Automatic sources dropoff on 2020-06-10 18:32:38.095721

The change is generated with prebuilt drop tool.

Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/java/awt/font/NumericShaper.java b/java/awt/font/NumericShaper.java
new file mode 100644
index 0000000..7e1980e
--- /dev/null
+++ b/java/awt/font/NumericShaper.java
@@ -0,0 +1,1525 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.awt.font;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.Set;
+
+/**
+ * The <code>NumericShaper</code> class is used to convert Latin-1 (European)
+ * digits to other Unicode decimal digits.  Users of this class will
+ * primarily be people who wish to present data using
+ * national digit shapes, but find it more convenient to represent the
+ * data internally using Latin-1 (European) digits.  This does not
+ * interpret the deprecated numeric shape selector character (U+206E).
+ * <p>
+ * Instances of <code>NumericShaper</code> are typically applied
+ * as attributes to text with the
+ * {@link TextAttribute#NUMERIC_SHAPING NUMERIC_SHAPING} attribute
+ * of the <code>TextAttribute</code> class.
+ * For example, this code snippet causes a <code>TextLayout</code> to
+ * shape European digits to Arabic in an Arabic context:<br>
+ * <blockquote><pre>
+ * Map map = new HashMap();
+ * map.put(TextAttribute.NUMERIC_SHAPING,
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC));
+ * FontRenderContext frc = ...;
+ * TextLayout layout = new TextLayout(text, map, frc);
+ * layout.draw(g2d, x, y);
+ * </pre></blockquote>
+ * <br>
+ * It is also possible to perform numeric shaping explicitly using instances
+ * of <code>NumericShaper</code>, as this code snippet demonstrates:<br>
+ * <blockquote><pre>
+ * char[] text = ...;
+ * // shape all EUROPEAN digits (except zero) to ARABIC digits
+ * NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
+ * shaper.shape(text, start, count);
+ *
+ * // shape European digits to ARABIC digits if preceding text is Arabic, or
+ * // shape European digits to TAMIL digits if preceding text is Tamil, or
+ * // leave European digits alone if there is no preceding text, or
+ * // preceding text is neither Arabic nor Tamil
+ * NumericShaper shaper =
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+ *                                         NumericShaper.TAMIL,
+ *                                       NumericShaper.EUROPEAN);
+ * shaper.shape(text, start, count);
+ * </pre></blockquote>
+ *
+ * <p><b>Bit mask- and enum-based Unicode ranges</b></p>
+ *
+ * <p>This class supports two different programming interfaces to
+ * represent Unicode ranges for script-specific digits: bit
+ * mask-based ones, such as {@link #ARABIC NumericShaper.ARABIC}, and
+ * enum-based ones, such as {@link NumericShaper.Range#ARABIC}.
+ * Multiple ranges can be specified by ORing bit mask-based constants,
+ * such as:
+ * <blockquote><pre>
+ * NumericShaper.ARABIC | NumericShaper.TAMIL
+ * </pre></blockquote>
+ * or creating a {@code Set} with the {@link NumericShaper.Range}
+ * constants, such as:
+ * <blockquote><pre>
+ * EnumSet.of(NumericShaper.Scirpt.ARABIC, NumericShaper.Range.TAMIL)
+ * </pre></blockquote>
+ * The enum-based ranges are a super set of the bit mask-based ones.
+ *
+ * <p>If the two interfaces are mixed (including serialization),
+ * Unicode range values are mapped to their counterparts where such
+ * mapping is possible, such as {@code NumericShaper.Range.ARABIC}
+ * from/to {@code NumericShaper.ARABIC}.  If any unmappable range
+ * values are specified, such as {@code NumericShaper.Range.BALINESE},
+ * those ranges are ignored.
+ *
+ * <p><b>Decimal Digits Precedence</b></p>
+ *
+ * <p>A Unicode range may have more than one set of decimal digits. If
+ * multiple decimal digits sets are specified for the same Unicode
+ * range, one of the sets will take precedence as follows.
+ *
+ * <table border=1 cellspacing=3 cellpadding=0 summary="NumericShaper constants precedence.">
+ *    <tr>
+ *       <th class="TableHeadingColor">Unicode Range</th>
+ *       <th class="TableHeadingColor"><code>NumericShaper</code> Constants</th>
+ *       <th class="TableHeadingColor">Precedence</th>
+ *    </tr>
+ *    <tr>
+ *       <td rowspan="2">Arabic</td>
+ *       <td>{@link NumericShaper#ARABIC NumericShaper.ARABIC}<br>
+ *           {@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}</td>
+ *       <td>{@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}</td>
+ *    </tr>
+ *    <tr>
+ *       <td>{@link NumericShaper.Range#ARABIC}<br>
+ *           {@link NumericShaper.Range#EASTERN_ARABIC}</td>
+ *       <td>{@link NumericShaper.Range#EASTERN_ARABIC}</td>
+ *    </tr>
+ *    <tr>
+ *       <td>Tai Tham</td>
+ *       <td>{@link NumericShaper.Range#TAI_THAM_HORA}<br>
+ *           {@link NumericShaper.Range#TAI_THAM_THAM}</td>
+ *       <td>{@link NumericShaper.Range#TAI_THAM_THAM}</td>
+ *    </tr>
+ * </table>
+ *
+ * @since 1.4
+ */
+
+public final class NumericShaper implements java.io.Serializable {
+    /**
+     * A {@code NumericShaper.Range} represents a Unicode range of a
+     * script having its own decimal digits. For example, the {@link
+     * NumericShaper.Range#THAI} range has the Thai digits, THAI DIGIT
+     * ZERO (U+0E50) to THAI DIGIT NINE (U+0E59).
+     *
+     * <p>The <code>Range</code> enum replaces the traditional bit
+     * mask-based values (e.g., {@link NumericShaper#ARABIC}), and
+     * supports more Unicode ranges than the bit mask-based ones. For
+     * example, the following code using the bit mask:
+     * <blockquote><pre>
+     * NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+     *                                     NumericShaper.TAMIL,
+     *                                   NumericShaper.EUROPEAN);
+     * </pre></blockquote>
+     * can be written using this enum as:
+     * <blockquote><pre>
+     * NumericShaper.getContextualShaper(EnumSet.of(
+     *                                     NumericShaper.Range.ARABIC,
+     *                                     NumericShaper.Range.TAMIL),
+     *                                   NumericShaper.Range.EUROPEAN);
+     * </pre></blockquote>
+     *
+     * @since 1.7
+     */
+    public static enum Range {
+        // The order of EUROPEAN to MOGOLIAN must be consistent
+        // with the bitmask-based constants.
+        /**
+         * The Latin (European) range with the Latin (ASCII) digits.
+         */
+        EUROPEAN        ('\u0030', '\u0000', '\u0300'),
+        /**
+         * The Arabic range with the Arabic-Indic digits.
+         */
+        ARABIC          ('\u0660', '\u0600', '\u0780'),
+        /**
+         * The Arabic range with the Eastern Arabic-Indic digits.
+         */
+        EASTERN_ARABIC  ('\u06f0', '\u0600', '\u0780'),
+        /**
+         * The Devanagari range with the Devanagari digits.
+         */
+        DEVANAGARI      ('\u0966', '\u0900', '\u0980'),
+        /**
+         * The Bengali range with the Bengali digits.
+         */
+        BENGALI         ('\u09e6', '\u0980', '\u0a00'),
+        /**
+         * The Gurmukhi range with the Gurmukhi digits.
+         */
+        GURMUKHI        ('\u0a66', '\u0a00', '\u0a80'),
+        /**
+         * The Gujarati range with the Gujarati digits.
+         */
+        GUJARATI        ('\u0ae6', '\u0b00', '\u0b80'),
+        /**
+         * The Oriya range with the Oriya digits.
+         */
+        ORIYA           ('\u0b66', '\u0b00', '\u0b80'),
+        /**
+         * The Tamil range with the Tamil digits.
+         */
+        TAMIL           ('\u0be6', '\u0b80', '\u0c00'),
+        /**
+         * The Telugu range with the Telugu digits.
+         */
+        TELUGU          ('\u0c66', '\u0c00', '\u0c80'),
+        /**
+         * The Kannada range with the Kannada digits.
+         */
+        KANNADA         ('\u0ce6', '\u0c80', '\u0d00'),
+        /**
+         * The Malayalam range with the Malayalam digits.
+         */
+        MALAYALAM       ('\u0d66', '\u0d00', '\u0d80'),
+        /**
+         * The Thai range with the Thai digits.
+         */
+        THAI            ('\u0e50', '\u0e00', '\u0e80'),
+        /**
+         * The Lao range with the Lao digits.
+         */
+        LAO             ('\u0ed0', '\u0e80', '\u0f00'),
+        /**
+         * The Tibetan range with the Tibetan digits.
+         */
+        TIBETAN         ('\u0f20', '\u0f00', '\u1000'),
+        /**
+         * The Myanmar range with the Myanmar digits.
+         */
+        MYANMAR         ('\u1040', '\u1000', '\u1080'),
+        /**
+         * The Ethiopic range with the Ethiopic digits. Ethiopic
+         * does not have a decimal digit 0 so Latin (European) 0 is
+         * used.
+         */
+        ETHIOPIC        ('\u1369', '\u1200', '\u1380') {
+            @Override
+            char getNumericBase() { return 1; }
+        },
+        /**
+         * The Khmer range with the Khmer digits.
+         */
+        KHMER           ('\u17e0', '\u1780', '\u1800'),
+        /**
+         * The Mongolian range with the Mongolian digits.
+         */
+        MONGOLIAN       ('\u1810', '\u1800', '\u1900'),
+        // The order of EUROPEAN to MOGOLIAN must be consistent
+        // with the bitmask-based constants.
+
+        /**
+         * The N'Ko range with the N'Ko digits.
+         */
+        NKO             ('\u07c0', '\u07c0', '\u0800'),
+        /**
+         * The Myanmar range with the Myanmar Shan digits.
+         */
+        MYANMAR_SHAN    ('\u1090', '\u1000', '\u10a0'),
+        /**
+         * The Limbu range with the Limbu digits.
+         */
+        LIMBU           ('\u1946', '\u1900', '\u1950'),
+        /**
+         * The New Tai Lue range with the New Tai Lue digits.
+         */
+        NEW_TAI_LUE     ('\u19d0', '\u1980', '\u19e0'),
+        /**
+         * The Balinese range with the Balinese digits.
+         */
+        BALINESE        ('\u1b50', '\u1b00', '\u1b80'),
+        /**
+         * The Sundanese range with the Sundanese digits.
+         */
+        SUNDANESE       ('\u1bb0', '\u1b80', '\u1bc0'),
+        /**
+         * The Lepcha range with the Lepcha digits.
+         */
+        LEPCHA          ('\u1c40', '\u1c00', '\u1c50'),
+        /**
+         * The Ol Chiki range with the Ol Chiki digits.
+         */
+        OL_CHIKI        ('\u1c50', '\u1c50', '\u1c80'),
+        /**
+         * The Vai range with the Vai digits.
+         */
+        VAI             ('\ua620', '\ua500', '\ua640'),
+        /**
+         * The Saurashtra range with the Saurashtra digits.
+         */
+        SAURASHTRA      ('\ua8d0', '\ua880', '\ua8e0'),
+        /**
+         * The Kayah Li range with the Kayah Li digits.
+         */
+        KAYAH_LI        ('\ua900', '\ua900', '\ua930'),
+        /**
+         * The Cham range with the Cham digits.
+         */
+        CHAM            ('\uaa50', '\uaa00', '\uaa60'),
+        /**
+         * The Tai Tham Hora range with the Tai Tham Hora digits.
+         */
+        TAI_THAM_HORA   ('\u1a80', '\u1a20', '\u1ab0'),
+        /**
+         * The Tai Tham Tham range with the Tai Tham Tham digits.
+         */
+        TAI_THAM_THAM   ('\u1a90', '\u1a20', '\u1ab0'),
+        /**
+         * The Javanese range with the Javanese digits.
+         */
+        JAVANESE        ('\ua9d0', '\ua980', '\ua9e0'),
+        /**
+         * The Meetei Mayek range with the Meetei Mayek digits.
+         */
+        MEETEI_MAYEK    ('\uabf0', '\uabc0', '\uac00');
+
+        private static int toRangeIndex(Range script) {
+            int index = script.ordinal();
+            return index < NUM_KEYS ? index : -1;
+        }
+
+        private static Range indexToRange(int index) {
+            return index < NUM_KEYS ? Range.values()[index] : null;
+        }
+
+        private static int toRangeMask(Set<Range> ranges) {
+            int m = 0;
+            for (Range range : ranges) {
+                int index = range.ordinal();
+                if (index < NUM_KEYS) {
+                    m |= 1 << index;
+                }
+            }
+            return m;
+        }
+
+        private static Set<Range> maskToRangeSet(int mask) {
+            Set<Range> set = EnumSet.noneOf(Range.class);
+            Range[] a = Range.values();
+            for (int i = 0; i < NUM_KEYS; i++) {
+                if ((mask & (1 << i)) != 0) {
+                    set.add(a[i]);
+                }
+            }
+            return set;
+        }
+
+        // base character of range digits
+        private final int base;
+        // Unicode range
+        private final int start, // inclusive
+                          end;   // exclusive
+
+        private Range(int base, int start, int end) {
+            this.base = base - ('0' + getNumericBase());
+            this.start = start;
+            this.end = end;
+        }
+
+        private int getDigitBase() {
+            return base;
+        }
+
+        char getNumericBase() {
+            return 0;
+        }
+
+        private boolean inRange(int c) {
+            return start <= c && c < end;
+        }
+    }
+
+    /** index of context for contextual shaping - values range from 0 to 18 */
+    private int key;
+
+    /** flag indicating whether to shape contextually (high bit) and which
+     *  digit ranges to shape (bits 0-18)
+     */
+    private int mask;
+
+    /**
+     * The context {@code Range} for contextual shaping or the {@code
+     * Range} for non-contextual shaping. {@code null} for the bit
+     * mask-based API.
+     *
+     * @since 1.7
+     */
+    private Range shapingRange;
+
+    /**
+     * {@code Set<Range>} indicating which Unicode ranges to
+     * shape. {@code null} for the bit mask-based API.
+     */
+    private transient Set<Range> rangeSet;
+
+    /**
+     * rangeSet.toArray() value. Sorted by Range.base when the number
+     * of elements is greater then BSEARCH_THRESHOLD.
+     */
+    private transient Range[] rangeArray;
+
+    /**
+     * If more than BSEARCH_THRESHOLD ranges are specified, binary search is used.
+     */
+    private static final int BSEARCH_THRESHOLD = 3;
+
+    private static final long serialVersionUID = -8022764705923730308L;
+
+    /** Identifies the Latin-1 (European) and extended range, and
+     *  Latin-1 (European) decimal base.
+     */
+    public static final int EUROPEAN = 1<<0;
+
+    /** Identifies the ARABIC range and decimal base. */
+    public static final int ARABIC = 1<<1;
+
+    /** Identifies the ARABIC range and ARABIC_EXTENDED decimal base. */
+    public static final int EASTERN_ARABIC = 1<<2;
+
+    /** Identifies the DEVANAGARI range and decimal base. */
+    public static final int DEVANAGARI = 1<<3;
+
+    /** Identifies the BENGALI range and decimal base. */
+    public static final int BENGALI = 1<<4;
+
+    /** Identifies the GURMUKHI range and decimal base. */
+    public static final int GURMUKHI = 1<<5;
+
+    /** Identifies the GUJARATI range and decimal base. */
+    public static final int GUJARATI = 1<<6;
+
+    /** Identifies the ORIYA range and decimal base. */
+    public static final int ORIYA = 1<<7;
+
+    /** Identifies the TAMIL range and decimal base. */
+    // TAMIL DIGIT ZERO was added in Unicode 4.1
+    public static final int TAMIL = 1<<8;
+
+    /** Identifies the TELUGU range and decimal base. */
+    public static final int TELUGU = 1<<9;
+
+    /** Identifies the KANNADA range and decimal base. */
+    public static final int KANNADA = 1<<10;
+
+    /** Identifies the MALAYALAM range and decimal base. */
+    public static final int MALAYALAM = 1<<11;
+
+    /** Identifies the THAI range and decimal base. */
+    public static final int THAI = 1<<12;
+
+    /** Identifies the LAO range and decimal base. */
+    public static final int LAO = 1<<13;
+
+    /** Identifies the TIBETAN range and decimal base. */
+    public static final int TIBETAN = 1<<14;
+
+    /** Identifies the MYANMAR range and decimal base. */
+    public static final int MYANMAR = 1<<15;
+
+    /** Identifies the ETHIOPIC range and decimal base. */
+    public static final int ETHIOPIC = 1<<16;
+
+    /** Identifies the KHMER range and decimal base. */
+    public static final int KHMER = 1<<17;
+
+    /** Identifies the MONGOLIAN range and decimal base. */
+    public static final int MONGOLIAN = 1<<18;
+
+    /** Identifies all ranges, for full contextual shaping.
+     *
+     * <p>This constant specifies all of the bit mask-based
+     * ranges. Use {@code EmunSet.allOf(NumericShaper.Range.class)} to
+     * specify all of the enum-based ranges.
+     */
+    public static final int ALL_RANGES = 0x0007ffff;
+
+    private static final int EUROPEAN_KEY = 0;
+    private static final int ARABIC_KEY = 1;
+    private static final int EASTERN_ARABIC_KEY = 2;
+    private static final int DEVANAGARI_KEY = 3;
+    private static final int BENGALI_KEY = 4;
+    private static final int GURMUKHI_KEY = 5;
+    private static final int GUJARATI_KEY = 6;
+    private static final int ORIYA_KEY = 7;
+    private static final int TAMIL_KEY = 8;
+    private static final int TELUGU_KEY = 9;
+    private static final int KANNADA_KEY = 10;
+    private static final int MALAYALAM_KEY = 11;
+    private static final int THAI_KEY = 12;
+    private static final int LAO_KEY = 13;
+    private static final int TIBETAN_KEY = 14;
+    private static final int MYANMAR_KEY = 15;
+    private static final int ETHIOPIC_KEY = 16;
+    private static final int KHMER_KEY = 17;
+    private static final int MONGOLIAN_KEY = 18;
+
+    private static final int NUM_KEYS = MONGOLIAN_KEY + 1; // fixed
+
+    private static final int CONTEXTUAL_MASK = 1<<31;
+
+    private static final char[] bases = {
+        '\u0030' - '\u0030', // EUROPEAN
+        '\u0660' - '\u0030', // ARABIC-INDIC
+        '\u06f0' - '\u0030', // EXTENDED ARABIC-INDIC (EASTERN_ARABIC)
+        '\u0966' - '\u0030', // DEVANAGARI
+        '\u09e6' - '\u0030', // BENGALI
+        '\u0a66' - '\u0030', // GURMUKHI
+        '\u0ae6' - '\u0030', // GUJARATI
+        '\u0b66' - '\u0030', // ORIYA
+        '\u0be6' - '\u0030', // TAMIL - zero was added in Unicode 4.1
+        '\u0c66' - '\u0030', // TELUGU
+        '\u0ce6' - '\u0030', // KANNADA
+        '\u0d66' - '\u0030', // MALAYALAM
+        '\u0e50' - '\u0030', // THAI
+        '\u0ed0' - '\u0030', // LAO
+        '\u0f20' - '\u0030', // TIBETAN
+        '\u1040' - '\u0030', // MYANMAR
+        '\u1369' - '\u0031', // ETHIOPIC - no zero
+        '\u17e0' - '\u0030', // KHMER
+        '\u1810' - '\u0030', // MONGOLIAN
+    };
+
+    // some ranges adjoin or overlap, rethink if we want to do a binary search on this
+
+    private static final char[] contexts = {
+        '\u0000', '\u0300', // 'EUROPEAN' (really latin-1 and extended)
+        '\u0600', '\u0780', // ARABIC
+        '\u0600', '\u0780', // EASTERN_ARABIC -- note overlap with arabic
+        '\u0900', '\u0980', // DEVANAGARI
+        '\u0980', '\u0a00', // BENGALI
+        '\u0a00', '\u0a80', // GURMUKHI
+        '\u0a80', '\u0b00', // GUJARATI
+        '\u0b00', '\u0b80', // ORIYA
+        '\u0b80', '\u0c00', // TAMIL
+        '\u0c00', '\u0c80', // TELUGU
+        '\u0c80', '\u0d00', // KANNADA
+        '\u0d00', '\u0d80', // MALAYALAM
+        '\u0e00', '\u0e80', // THAI
+        '\u0e80', '\u0f00', // LAO
+        '\u0f00', '\u1000', // TIBETAN
+        '\u1000', '\u1080', // MYANMAR
+        '\u1200', '\u1380', // ETHIOPIC - note missing zero
+        '\u1780', '\u1800', // KHMER
+        '\u1800', '\u1900', // MONGOLIAN
+        '\uffff',
+    };
+
+    // assume most characters are near each other so probing the cache is infrequent,
+    // and a linear probe is ok.
+
+    private static int ctCache = 0;
+    private static int ctCacheLimit = contexts.length - 2;
+
+    // warning, synchronize access to this as it modifies state
+    private static int getContextKey(char c) {
+        if (c < contexts[ctCache]) {
+            while (ctCache > 0 && c < contexts[ctCache]) --ctCache;
+        } else if (c >= contexts[ctCache + 1]) {
+            while (ctCache < ctCacheLimit && c >= contexts[ctCache + 1]) ++ctCache;
+        }
+
+        // if we're not in a known range, then return EUROPEAN as the range key
+        return (ctCache & 0x1) == 0 ? (ctCache / 2) : EUROPEAN_KEY;
+    }
+
+    // cache for the NumericShaper.Range version
+    private transient volatile Range currentRange = Range.EUROPEAN;
+
+    private Range rangeForCodePoint(final int codepoint) {
+        if (currentRange.inRange(codepoint)) {
+            return currentRange;
+        }
+
+        final Range[] ranges = rangeArray;
+        if (ranges.length > BSEARCH_THRESHOLD) {
+            int lo = 0;
+            int hi = ranges.length - 1;
+            while (lo <= hi) {
+                int mid = (lo + hi) / 2;
+                Range range = ranges[mid];
+                if (codepoint < range.start) {
+                    hi = mid - 1;
+                } else if (codepoint >= range.end) {
+                    lo = mid + 1;
+                } else {
+                    currentRange = range;
+                    return range;
+                }
+            }
+        } else {
+            for (int i = 0; i < ranges.length; i++) {
+                if (ranges[i].inRange(codepoint)) {
+                    return ranges[i];
+                }
+            }
+        }
+        return Range.EUROPEAN;
+    }
+
+    /*
+     * A range table of strong directional characters (types L, R, AL).
+     * Even (left) indexes are starts of ranges of non-strong-directional (or undefined)
+     * characters, odd (right) indexes are starts of ranges of strong directional
+     * characters.
+     */
+    private static int[] strongTable = {
+        0x0000, 0x0041,
+        0x005b, 0x0061,
+        0x007b, 0x00aa,
+        0x00ab, 0x00b5,
+        0x00b6, 0x00ba,
+        0x00bb, 0x00c0,
+        0x00d7, 0x00d8,
+        0x00f7, 0x00f8,
+        0x02b9, 0x02bb,
+        0x02c2, 0x02d0,
+        0x02d2, 0x02e0,
+        0x02e5, 0x02ee,
+        0x02ef, 0x0370,
+        0x0374, 0x0376,
+        0x037e, 0x0386,
+        0x0387, 0x0388,
+        0x03f6, 0x03f7,
+        0x0483, 0x048a,
+        0x058a, 0x05be,
+        0x05bf, 0x05c0,
+        0x05c1, 0x05c3,
+        0x05c4, 0x05c6,
+        0x05c7, 0x05d0,
+        0x0600, 0x0608,
+        0x0609, 0x060b,
+        0x060c, 0x060d,
+        0x060e, 0x061b,
+        0x064b, 0x066d,
+        0x0670, 0x0671,
+        0x06d6, 0x06e5,
+        0x06e7, 0x06ee,
+        0x06f0, 0x06fa,
+        0x0711, 0x0712,
+        0x0730, 0x074d,
+        0x07a6, 0x07b1,
+        0x07eb, 0x07f4,
+        0x07f6, 0x07fa,
+        0x0816, 0x081a,
+        0x081b, 0x0824,
+        0x0825, 0x0828,
+        0x0829, 0x0830,
+        0x0859, 0x085e,
+        0x08e4, 0x0903,
+        0x093a, 0x093b,
+        0x093c, 0x093d,
+        0x0941, 0x0949,
+        0x094d, 0x094e,
+        0x0951, 0x0958,
+        0x0962, 0x0964,
+        0x0981, 0x0982,
+        0x09bc, 0x09bd,
+        0x09c1, 0x09c7,
+        0x09cd, 0x09ce,
+        0x09e2, 0x09e6,
+        0x09f2, 0x09f4,
+        0x09fb, 0x0a03,
+        0x0a3c, 0x0a3e,
+        0x0a41, 0x0a59,
+        0x0a70, 0x0a72,
+        0x0a75, 0x0a83,
+        0x0abc, 0x0abd,
+        0x0ac1, 0x0ac9,
+        0x0acd, 0x0ad0,
+        0x0ae2, 0x0ae6,
+        0x0af1, 0x0b02,
+        0x0b3c, 0x0b3d,
+        0x0b3f, 0x0b40,
+        0x0b41, 0x0b47,
+        0x0b4d, 0x0b57,
+        0x0b62, 0x0b66,
+        0x0b82, 0x0b83,
+        0x0bc0, 0x0bc1,
+        0x0bcd, 0x0bd0,
+        0x0bf3, 0x0c01,
+        0x0c3e, 0x0c41,
+        0x0c46, 0x0c58,
+        0x0c62, 0x0c66,
+        0x0c78, 0x0c7f,
+        0x0cbc, 0x0cbd,
+        0x0ccc, 0x0cd5,
+        0x0ce2, 0x0ce6,
+        0x0d41, 0x0d46,
+        0x0d4d, 0x0d4e,
+        0x0d62, 0x0d66,
+        0x0dca, 0x0dcf,
+        0x0dd2, 0x0dd8,
+        0x0e31, 0x0e32,
+        0x0e34, 0x0e40,
+        0x0e47, 0x0e4f,
+        0x0eb1, 0x0eb2,
+        0x0eb4, 0x0ebd,
+        0x0ec8, 0x0ed0,
+        0x0f18, 0x0f1a,
+        0x0f35, 0x0f36,
+        0x0f37, 0x0f38,
+        0x0f39, 0x0f3e,
+        0x0f71, 0x0f7f,
+        0x0f80, 0x0f85,
+        0x0f86, 0x0f88,
+        0x0f8d, 0x0fbe,
+        0x0fc6, 0x0fc7,
+        0x102d, 0x1031,
+        0x1032, 0x1038,
+        0x1039, 0x103b,
+        0x103d, 0x103f,
+        0x1058, 0x105a,
+        0x105e, 0x1061,
+        0x1071, 0x1075,
+        0x1082, 0x1083,
+        0x1085, 0x1087,
+        0x108d, 0x108e,
+        0x109d, 0x109e,
+        0x135d, 0x1360,
+        0x1390, 0x13a0,
+        0x1400, 0x1401,
+        0x1680, 0x1681,
+        0x169b, 0x16a0,
+        0x1712, 0x1720,
+        0x1732, 0x1735,
+        0x1752, 0x1760,
+        0x1772, 0x1780,
+        0x17b4, 0x17b6,
+        0x17b7, 0x17be,
+        0x17c6, 0x17c7,
+        0x17c9, 0x17d4,
+        0x17db, 0x17dc,
+        0x17dd, 0x17e0,
+        0x17f0, 0x1810,
+        0x18a9, 0x18aa,
+        0x1920, 0x1923,
+        0x1927, 0x1929,
+        0x1932, 0x1933,
+        0x1939, 0x1946,
+        0x19de, 0x1a00,
+        0x1a17, 0x1a19,
+        0x1a56, 0x1a57,
+        0x1a58, 0x1a61,
+        0x1a62, 0x1a63,
+        0x1a65, 0x1a6d,
+        0x1a73, 0x1a80,
+        0x1b00, 0x1b04,
+        0x1b34, 0x1b35,
+        0x1b36, 0x1b3b,
+        0x1b3c, 0x1b3d,
+        0x1b42, 0x1b43,
+        0x1b6b, 0x1b74,
+        0x1b80, 0x1b82,
+        0x1ba2, 0x1ba6,
+        0x1ba8, 0x1baa,
+        0x1bab, 0x1bac,
+        0x1be6, 0x1be7,
+        0x1be8, 0x1bea,
+        0x1bed, 0x1bee,
+        0x1bef, 0x1bf2,
+        0x1c2c, 0x1c34,
+        0x1c36, 0x1c3b,
+        0x1cd0, 0x1cd3,
+        0x1cd4, 0x1ce1,
+        0x1ce2, 0x1ce9,
+        0x1ced, 0x1cee,
+        0x1cf4, 0x1cf5,
+        0x1dc0, 0x1e00,
+        0x1fbd, 0x1fbe,
+        0x1fbf, 0x1fc2,
+        0x1fcd, 0x1fd0,
+        0x1fdd, 0x1fe0,
+        0x1fed, 0x1ff2,
+        0x1ffd, 0x200e,
+        0x2010, 0x2071,
+        0x2074, 0x207f,
+        0x2080, 0x2090,
+        0x20a0, 0x2102,
+        0x2103, 0x2107,
+        0x2108, 0x210a,
+        0x2114, 0x2115,
+        0x2116, 0x2119,
+        0x211e, 0x2124,
+        0x2125, 0x2126,
+        0x2127, 0x2128,
+        0x2129, 0x212a,
+        0x212e, 0x212f,
+        0x213a, 0x213c,
+        0x2140, 0x2145,
+        0x214a, 0x214e,
+        0x2150, 0x2160,
+        0x2189, 0x2336,
+        0x237b, 0x2395,
+        0x2396, 0x249c,
+        0x24ea, 0x26ac,
+        0x26ad, 0x2800,
+        0x2900, 0x2c00,
+        0x2ce5, 0x2ceb,
+        0x2cef, 0x2cf2,
+        0x2cf9, 0x2d00,
+        0x2d7f, 0x2d80,
+        0x2de0, 0x3005,
+        0x3008, 0x3021,
+        0x302a, 0x3031,
+        0x3036, 0x3038,
+        0x303d, 0x3041,
+        0x3099, 0x309d,
+        0x30a0, 0x30a1,
+        0x30fb, 0x30fc,
+        0x31c0, 0x31f0,
+        0x321d, 0x3220,
+        0x3250, 0x3260,
+        0x327c, 0x327f,
+        0x32b1, 0x32c0,
+        0x32cc, 0x32d0,
+        0x3377, 0x337b,
+        0x33de, 0x33e0,
+        0x33ff, 0x3400,
+        0x4dc0, 0x4e00,
+        0xa490, 0xa4d0,
+        0xa60d, 0xa610,
+        0xa66f, 0xa680,
+        0xa69f, 0xa6a0,
+        0xa6f0, 0xa6f2,
+        0xa700, 0xa722,
+        0xa788, 0xa789,
+        0xa802, 0xa803,
+        0xa806, 0xa807,
+        0xa80b, 0xa80c,
+        0xa825, 0xa827,
+        0xa828, 0xa830,
+        0xa838, 0xa840,
+        0xa874, 0xa880,
+        0xa8c4, 0xa8ce,
+        0xa8e0, 0xa8f2,
+        0xa926, 0xa92e,
+        0xa947, 0xa952,
+        0xa980, 0xa983,
+        0xa9b3, 0xa9b4,
+        0xa9b6, 0xa9ba,
+        0xa9bc, 0xa9bd,
+        0xaa29, 0xaa2f,
+        0xaa31, 0xaa33,
+        0xaa35, 0xaa40,
+        0xaa43, 0xaa44,
+        0xaa4c, 0xaa4d,
+        0xaab0, 0xaab1,
+        0xaab2, 0xaab5,
+        0xaab7, 0xaab9,
+        0xaabe, 0xaac0,
+        0xaac1, 0xaac2,
+        0xaaec, 0xaaee,
+        0xaaf6, 0xab01,
+        0xabe5, 0xabe6,
+        0xabe8, 0xabe9,
+        0xabed, 0xabf0,
+        0xfb1e, 0xfb1f,
+        0xfb29, 0xfb2a,
+        0xfd3e, 0xfd50,
+        0xfdfd, 0xfe70,
+        0xfeff, 0xff21,
+        0xff3b, 0xff41,
+        0xff5b, 0xff66,
+        0xffe0, 0x10000,
+        0x10101, 0x10102,
+        0x10140, 0x101d0,
+        0x101fd, 0x10280,
+        0x1091f, 0x10920,
+        0x10a01, 0x10a10,
+        0x10a38, 0x10a40,
+        0x10b39, 0x10b40,
+        0x10e60, 0x11000,
+        0x11001, 0x11002,
+        0x11038, 0x11047,
+        0x11052, 0x11066,
+        0x11080, 0x11082,
+        0x110b3, 0x110b7,
+        0x110b9, 0x110bb,
+        0x11100, 0x11103,
+        0x11127, 0x1112c,
+        0x1112d, 0x11136,
+        0x11180, 0x11182,
+        0x111b6, 0x111bf,
+        0x116ab, 0x116ac,
+        0x116ad, 0x116ae,
+        0x116b0, 0x116b6,
+        0x116b7, 0x116c0,
+        0x16f8f, 0x16f93,
+        0x1d167, 0x1d16a,
+        0x1d173, 0x1d183,
+        0x1d185, 0x1d18c,
+        0x1d1aa, 0x1d1ae,
+        0x1d200, 0x1d360,
+        0x1d6db, 0x1d6dc,
+        0x1d715, 0x1d716,
+        0x1d74f, 0x1d750,
+        0x1d789, 0x1d78a,
+        0x1d7c3, 0x1d7c4,
+        0x1d7ce, 0x1ee00,
+        0x1eef0, 0x1f110,
+        0x1f16a, 0x1f170,
+        0x1f300, 0x1f48c,
+        0x1f48d, 0x1f524,
+        0x1f525, 0x20000,
+        0xe0001, 0xf0000,
+        0x10fffe, 0x10ffff // sentinel
+    };
+
+
+    // use a binary search with a cache
+
+    private transient volatile int stCache = 0;
+
+    private boolean isStrongDirectional(char c) {
+        int cachedIndex = stCache;
+        if (c < strongTable[cachedIndex]) {
+            cachedIndex = search(c, strongTable, 0, cachedIndex);
+        } else if (c >= strongTable[cachedIndex + 1]) {
+            cachedIndex = search(c, strongTable, cachedIndex + 1,
+                                 strongTable.length - cachedIndex - 1);
+        }
+        boolean val = (cachedIndex & 0x1) == 1;
+        stCache = cachedIndex;
+        return val;
+    }
+
+    private static int getKeyFromMask(int mask) {
+        int key = 0;
+        while (key < NUM_KEYS && ((mask & (1<<key)) == 0)) {
+            ++key;
+        }
+        if (key == NUM_KEYS || ((mask & ~(1<<key)) != 0)) {
+            throw new IllegalArgumentException("invalid shaper: " + Integer.toHexString(mask));
+        }
+        return key;
+    }
+
+    /**
+     * Returns a shaper for the provided unicode range.  All
+     * Latin-1 (EUROPEAN) digits are converted
+     * to the corresponding decimal unicode digits.
+     * @param singleRange the specified Unicode range
+     * @return a non-contextual numeric shaper
+     * @throws IllegalArgumentException if the range is not a single range
+     */
+    public static NumericShaper getShaper(int singleRange) {
+        int key = getKeyFromMask(singleRange);
+        return new NumericShaper(key, singleRange);
+    }
+
+    /**
+     * Returns a shaper for the provided Unicode
+     * range. All Latin-1 (EUROPEAN) digits are converted to the
+     * corresponding decimal digits of the specified Unicode range.
+     *
+     * @param singleRange the Unicode range given by a {@link
+     *                    NumericShaper.Range} constant.
+     * @return a non-contextual {@code NumericShaper}.
+     * @throws NullPointerException if {@code singleRange} is {@code null}
+     * @since 1.7
+     */
+    public static NumericShaper getShaper(Range singleRange) {
+        return new NumericShaper(singleRange, EnumSet.of(singleRange));
+    }
+
+    /**
+     * Returns a contextual shaper for the provided unicode range(s).
+     * Latin-1 (EUROPEAN) digits are converted to the decimal digits
+     * corresponding to the range of the preceding text, if the
+     * range is one of the provided ranges.  Multiple ranges are
+     * represented by or-ing the values together, such as,
+     * <code>NumericShaper.ARABIC | NumericShaper.THAI</code>.  The
+     * shaper assumes EUROPEAN as the starting context, that is, if
+     * EUROPEAN digits are encountered before any strong directional
+     * text in the string, the context is presumed to be EUROPEAN, and
+     * so the digits will not shape.
+     * @param ranges the specified Unicode ranges
+     * @return a shaper for the specified ranges
+     */
+    public static NumericShaper getContextualShaper(int ranges) {
+        ranges |= CONTEXTUAL_MASK;
+        return new NumericShaper(EUROPEAN_KEY, ranges);
+    }
+
+    /**
+     * Returns a contextual shaper for the provided Unicode
+     * range(s). The Latin-1 (EUROPEAN) digits are converted to the
+     * decimal digits corresponding to the range of the preceding
+     * text, if the range is one of the provided ranges.
+     *
+     * <p>The shaper assumes EUROPEAN as the starting context, that
+     * is, if EUROPEAN digits are encountered before any strong
+     * directional text in the string, the context is presumed to be
+     * EUROPEAN, and so the digits will not shape.
+     *
+     * @param ranges the specified Unicode ranges
+     * @return a contextual shaper for the specified ranges
+     * @throws NullPointerException if {@code ranges} is {@code null}.
+     * @since 1.7
+     */
+    public static NumericShaper getContextualShaper(Set<Range> ranges) {
+        NumericShaper shaper = new NumericShaper(Range.EUROPEAN, ranges);
+        shaper.mask = CONTEXTUAL_MASK;
+        return shaper;
+    }
+
+    /**
+     * Returns a contextual shaper for the provided unicode range(s).
+     * Latin-1 (EUROPEAN) digits will be converted to the decimal digits
+     * corresponding to the range of the preceding text, if the
+     * range is one of the provided ranges.  Multiple ranges are
+     * represented by or-ing the values together, for example,
+     * <code>NumericShaper.ARABIC | NumericShaper.THAI</code>.  The
+     * shaper uses defaultContext as the starting context.
+     * @param ranges the specified Unicode ranges
+     * @param defaultContext the starting context, such as
+     * <code>NumericShaper.EUROPEAN</code>
+     * @return a shaper for the specified Unicode ranges.
+     * @throws IllegalArgumentException if the specified
+     * <code>defaultContext</code> is not a single valid range.
+     */
+    public static NumericShaper getContextualShaper(int ranges, int defaultContext) {
+        int key = getKeyFromMask(defaultContext);
+        ranges |= CONTEXTUAL_MASK;
+        return new NumericShaper(key, ranges);
+    }
+
+    /**
+     * Returns a contextual shaper for the provided Unicode range(s).
+     * The Latin-1 (EUROPEAN) digits will be converted to the decimal
+     * digits corresponding to the range of the preceding text, if the
+     * range is one of the provided ranges. The shaper uses {@code
+     * defaultContext} as the starting context.
+     *
+     * @param ranges the specified Unicode ranges
+     * @param defaultContext the starting context, such as
+     *                       {@code NumericShaper.Range.EUROPEAN}
+     * @return a contextual shaper for the specified Unicode ranges.
+     * @throws NullPointerException
+     *         if {@code ranges} or {@code defaultContext} is {@code null}
+     * @since 1.7
+     */
+    public static NumericShaper getContextualShaper(Set<Range> ranges,
+                                                    Range defaultContext) {
+        if (defaultContext == null) {
+            throw new NullPointerException();
+        }
+        NumericShaper shaper = new NumericShaper(defaultContext, ranges);
+        shaper.mask = CONTEXTUAL_MASK;
+        return shaper;
+    }
+
+    /**
+     * Private constructor.
+     */
+    private NumericShaper(int key, int mask) {
+        this.key = key;
+        this.mask = mask;
+    }
+
+    private NumericShaper(Range defaultContext, Set<Range> ranges) {
+        shapingRange = defaultContext;
+        rangeSet = EnumSet.copyOf(ranges); // throws NPE if ranges is null.
+
+        // Give precedance to EASTERN_ARABIC if both ARABIC and
+        // EASTERN_ARABIC are specified.
+        if (rangeSet.contains(Range.EASTERN_ARABIC)
+            && rangeSet.contains(Range.ARABIC)) {
+            rangeSet.remove(Range.ARABIC);
+        }
+
+        // As well as the above case, give precedance to TAI_THAM_THAM if both
+        // TAI_THAM_HORA and TAI_THAM_THAM are specified.
+        if (rangeSet.contains(Range.TAI_THAM_THAM)
+            && rangeSet.contains(Range.TAI_THAM_HORA)) {
+            rangeSet.remove(Range.TAI_THAM_HORA);
+        }
+
+        rangeArray = rangeSet.toArray(new Range[rangeSet.size()]);
+        if (rangeArray.length > BSEARCH_THRESHOLD) {
+            // sort rangeArray for binary search
+            Arrays.sort(rangeArray,
+                        new Comparator<Range>() {
+                            public int compare(Range s1, Range s2) {
+                                return s1.base > s2.base ? 1 : s1.base == s2.base ? 0 : -1;
+                            }
+                        });
+        }
+    }
+
+    /**
+     * Converts the digits in the text that occur between start and
+     * start + count.
+     * @param text an array of characters to convert
+     * @param start the index into <code>text</code> to start
+     *        converting
+     * @param count the number of characters in <code>text</code>
+     *        to convert
+     * @throws IndexOutOfBoundsException if start or start + count is
+     *        out of bounds
+     * @throws NullPointerException if text is null
+     */
+    public void shape(char[] text, int start, int count) {
+        checkParams(text, start, count);
+        if (isContextual()) {
+            if (rangeSet == null) {
+                shapeContextually(text, start, count, key);
+            } else {
+                shapeContextually(text, start, count, shapingRange);
+            }
+        } else {
+            shapeNonContextually(text, start, count);
+        }
+    }
+
+    /**
+     * Converts the digits in the text that occur between start and
+     * start + count, using the provided context.
+     * Context is ignored if the shaper is not a contextual shaper.
+     * @param text an array of characters
+     * @param start the index into <code>text</code> to start
+     *        converting
+     * @param count the number of characters in <code>text</code>
+     *        to convert
+     * @param context the context to which to convert the
+     *        characters, such as <code>NumericShaper.EUROPEAN</code>
+     * @throws IndexOutOfBoundsException if start or start + count is
+     *        out of bounds
+     * @throws NullPointerException if text is null
+     * @throws IllegalArgumentException if this is a contextual shaper
+     * and the specified <code>context</code> is not a single valid
+     * range.
+     */
+    public void shape(char[] text, int start, int count, int context) {
+        checkParams(text, start, count);
+        if (isContextual()) {
+            int ctxKey = getKeyFromMask(context);
+            if (rangeSet == null) {
+                shapeContextually(text, start, count, ctxKey);
+            } else {
+                shapeContextually(text, start, count, Range.values()[ctxKey]);
+            }
+        } else {
+            shapeNonContextually(text, start, count);
+        }
+    }
+
+    /**
+     * Converts the digits in the text that occur between {@code
+     * start} and {@code start + count}, using the provided {@code
+     * context}. {@code Context} is ignored if the shaper is not a
+     * contextual shaper.
+     *
+     * @param text  a {@code char} array
+     * @param start the index into {@code text} to start converting
+     * @param count the number of {@code char}s in {@code text}
+     *              to convert
+     * @param context the context to which to convert the characters,
+     *                such as {@code NumericShaper.Range.EUROPEAN}
+     * @throws IndexOutOfBoundsException
+     *         if {@code start} or {@code start + count} is out of bounds
+     * @throws NullPointerException
+     *         if {@code text} or {@code context} is null
+     * @since 1.7
+     */
+    public void shape(char[] text, int start, int count, Range context) {
+        checkParams(text, start, count);
+        if (context == null) {
+            throw new NullPointerException("context is null");
+        }
+
+        if (isContextual()) {
+            if (rangeSet != null) {
+                shapeContextually(text, start, count, context);
+            } else {
+                int key = Range.toRangeIndex(context);
+                if (key >= 0) {
+                    shapeContextually(text, start, count, key);
+                } else {
+                    shapeContextually(text, start, count, shapingRange);
+                }
+            }
+        } else {
+            shapeNonContextually(text, start, count);
+        }
+    }
+
+    private void checkParams(char[] text, int start, int count) {
+        if (text == null) {
+            throw new NullPointerException("text is null");
+        }
+        if ((start < 0)
+            || (start > text.length)
+            || ((start + count) < 0)
+            || ((start + count) > text.length)) {
+            throw new IndexOutOfBoundsException(
+                "bad start or count for text of length " + text.length);
+        }
+    }
+
+    /**
+     * Returns a <code>boolean</code> indicating whether or not
+     * this shaper shapes contextually.
+     * @return <code>true</code> if this shaper is contextual;
+     *         <code>false</code> otherwise.
+     */
+    public boolean isContextual() {
+        return (mask & CONTEXTUAL_MASK) != 0;
+    }
+
+    /**
+     * Returns an <code>int</code> that ORs together the values for
+     * all the ranges that will be shaped.
+     * <p>
+     * For example, to check if a shaper shapes to Arabic, you would use the
+     * following:
+     * <blockquote>
+     *   {@code if ((shaper.getRanges() & shaper.ARABIC) != 0) &#123; ... }
+     * </blockquote>
+     *
+     * <p>Note that this method supports only the bit mask-based
+     * ranges. Call {@link #getRangeSet()} for the enum-based ranges.
+     *
+     * @return the values for all the ranges to be shaped.
+     */
+    public int getRanges() {
+        return mask & ~CONTEXTUAL_MASK;
+    }
+
+    /**
+     * Returns a {@code Set} representing all the Unicode ranges in
+     * this {@code NumericShaper} that will be shaped.
+     *
+     * @return all the Unicode ranges to be shaped.
+     * @since 1.7
+     */
+    public Set<Range> getRangeSet() {
+        if (rangeSet != null) {
+            return EnumSet.copyOf(rangeSet);
+        }
+        return Range.maskToRangeSet(mask);
+    }
+
+    /**
+     * Perform non-contextual shaping.
+     */
+    private void shapeNonContextually(char[] text, int start, int count) {
+        int base;
+        char minDigit = '0';
+        if (shapingRange != null) {
+            base = shapingRange.getDigitBase();
+            minDigit += shapingRange.getNumericBase();
+        } else {
+            base = bases[key];
+            if (key == ETHIOPIC_KEY) {
+                minDigit++; // Ethiopic doesn't use decimal zero
+            }
+        }
+        for (int i = start, e = start + count; i < e; ++i) {
+            char c = text[i];
+            if (c >= minDigit && c <= '\u0039') {
+                text[i] = (char)(c + base);
+            }
+        }
+    }
+
+    /**
+     * Perform contextual shaping.
+     * Synchronized to protect caches used in getContextKey.
+     */
+    private synchronized void shapeContextually(char[] text, int start, int count, int ctxKey) {
+
+        // if we don't support this context, then don't shape
+        if ((mask & (1<<ctxKey)) == 0) {
+            ctxKey = EUROPEAN_KEY;
+        }
+        int lastkey = ctxKey;
+
+        int base = bases[ctxKey];
+        char minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero
+
+        synchronized (NumericShaper.class) {
+            for (int i = start, e = start + count; i < e; ++i) {
+                char c = text[i];
+                if (c >= minDigit && c <= '\u0039') {
+                    text[i] = (char)(c + base);
+                }
+
+                if (isStrongDirectional(c)) {
+                    int newkey = getContextKey(c);
+                    if (newkey != lastkey) {
+                        lastkey = newkey;
+
+                        ctxKey = newkey;
+                        if (((mask & EASTERN_ARABIC) != 0) &&
+                             (ctxKey == ARABIC_KEY ||
+                              ctxKey == EASTERN_ARABIC_KEY)) {
+                            ctxKey = EASTERN_ARABIC_KEY;
+                        } else if (((mask & ARABIC) != 0) &&
+                             (ctxKey == ARABIC_KEY ||
+                              ctxKey == EASTERN_ARABIC_KEY)) {
+                            ctxKey = ARABIC_KEY;
+                        } else if ((mask & (1<<ctxKey)) == 0) {
+                            ctxKey = EUROPEAN_KEY;
+                        }
+
+                        base = bases[ctxKey];
+
+                        minDigit = ctxKey == ETHIOPIC_KEY ? '1' : '0'; // Ethiopic doesn't use decimal zero
+                    }
+                }
+            }
+        }
+    }
+
+    private void shapeContextually(char[] text, int start, int count, Range ctxKey) {
+        // if we don't support the specified context, then don't shape.
+        if (ctxKey == null || !rangeSet.contains(ctxKey)) {
+            ctxKey = Range.EUROPEAN;
+        }
+
+        Range lastKey = ctxKey;
+        int base = ctxKey.getDigitBase();
+        char minDigit = (char)('0' + ctxKey.getNumericBase());
+        final int end = start + count;
+        for (int i = start; i < end; ++i) {
+            char c = text[i];
+            if (c >= minDigit && c <= '9') {
+                text[i] = (char)(c + base);
+                continue;
+            }
+            if (isStrongDirectional(c)) {
+                ctxKey = rangeForCodePoint(c);
+                if (ctxKey != lastKey) {
+                    lastKey = ctxKey;
+                    base = ctxKey.getDigitBase();
+                    minDigit = (char)('0' + ctxKey.getNumericBase());
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a hash code for this shaper.
+     * @return this shaper's hash code.
+     * @see java.lang.Object#hashCode
+     */
+    public int hashCode() {
+        int hash = mask;
+        if (rangeSet != null) {
+            // Use the CONTEXTUAL_MASK bit only for the enum-based
+            // NumericShaper. A deserialized NumericShaper might have
+            // bit masks.
+            hash &= CONTEXTUAL_MASK;
+            hash ^= rangeSet.hashCode();
+        }
+        return hash;
+    }
+
+    /**
+     * Returns {@code true} if the specified object is an instance of
+     * <code>NumericShaper</code> and shapes identically to this one,
+     * regardless of the range representations, the bit mask or the
+     * enum. For example, the following code produces {@code "true"}.
+     * <blockquote><pre>
+     * NumericShaper ns1 = NumericShaper.getShaper(NumericShaper.ARABIC);
+     * NumericShaper ns2 = NumericShaper.getShaper(NumericShaper.Range.ARABIC);
+     * System.out.println(ns1.equals(ns2));
+     * </pre></blockquote>
+     *
+     * @param o the specified object to compare to this
+     *          <code>NumericShaper</code>
+     * @return <code>true</code> if <code>o</code> is an instance
+     *         of <code>NumericShaper</code> and shapes in the same way;
+     *         <code>false</code> otherwise.
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object o) {
+        if (o != null) {
+            try {
+                NumericShaper rhs = (NumericShaper)o;
+                if (rangeSet != null) {
+                    if (rhs.rangeSet != null) {
+                        return isContextual() == rhs.isContextual()
+                            && rangeSet.equals(rhs.rangeSet)
+                            && shapingRange == rhs.shapingRange;
+                    }
+                    return isContextual() == rhs.isContextual()
+                        && rangeSet.equals(Range.maskToRangeSet(rhs.mask))
+                        && shapingRange == Range.indexToRange(rhs.key);
+                } else if (rhs.rangeSet != null) {
+                    Set<Range> rset = Range.maskToRangeSet(mask);
+                    Range srange = Range.indexToRange(key);
+                    return isContextual() == rhs.isContextual()
+                        && rset.equals(rhs.rangeSet)
+                        && srange == rhs.shapingRange;
+                }
+                return rhs.mask == mask && rhs.key == key;
+            }
+            catch (ClassCastException e) {
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a <code>String</code> that describes this shaper. This method
+     * is used for debugging purposes only.
+     * @return a <code>String</code> describing this shaper.
+     */
+    public String toString() {
+        StringBuilder buf = new StringBuilder(super.toString());
+
+        buf.append("[contextual:").append(isContextual());
+
+        String[] keyNames = null;
+        if (isContextual()) {
+            buf.append(", context:");
+            buf.append(shapingRange == null ? Range.values()[key] : shapingRange);
+        }
+
+        if (rangeSet == null) {
+            buf.append(", range(s): ");
+            boolean first = true;
+            for (int i = 0; i < NUM_KEYS; ++i) {
+                if ((mask & (1 << i)) != 0) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        buf.append(", ");
+                    }
+                    buf.append(Range.values()[i]);
+                }
+            }
+        } else {
+            buf.append(", range set: ").append(rangeSet);
+        }
+        buf.append(']');
+
+        return buf.toString();
+    }
+
+    /**
+     * Returns the index of the high bit in value (assuming le, actually
+     * power of 2 >= value). value must be positive.
+     */
+    private static int getHighBit(int value) {
+        if (value <= 0) {
+            return -32;
+        }
+
+        int bit = 0;
+
+        if (value >= 1 << 16) {
+            value >>= 16;
+            bit += 16;
+        }
+
+        if (value >= 1 << 8) {
+            value >>= 8;
+            bit += 8;
+        }
+
+        if (value >= 1 << 4) {
+            value >>= 4;
+            bit += 4;
+        }
+
+        if (value >= 1 << 2) {
+            value >>= 2;
+            bit += 2;
+        }
+
+        if (value >= 1 << 1) {
+            bit += 1;
+        }
+
+        return bit;
+    }
+
+    /**
+     * fast binary search over subrange of array.
+     */
+    private static int search(int value, int[] array, int start, int length)
+    {
+        int power = 1 << getHighBit(length);
+        int extra = length - power;
+        int probe = power;
+        int index = start;
+
+        if (value >= array[index + extra]) {
+            index += extra;
+        }
+
+        while (probe > 1) {
+            probe >>= 1;
+
+            if (value >= array[index + probe]) {
+                index += probe;
+            }
+        }
+
+        return index;
+    }
+
+    /**
+     * Converts the {@code NumericShaper.Range} enum-based parameters,
+     * if any, to the bit mask-based counterparts and writes this
+     * object to the {@code stream}. Any enum constants that have no
+     * bit mask-based counterparts are ignored in the conversion.
+     *
+     * @param stream the output stream to write to
+     * @throws IOException if an I/O error occurs while writing to {@code stream}
+     * @since 1.7
+     */
+    private void writeObject(ObjectOutputStream stream) throws IOException {
+        if (shapingRange != null) {
+            int index = Range.toRangeIndex(shapingRange);
+            if (index >= 0) {
+                key = index;
+            }
+        }
+        if (rangeSet != null) {
+            mask |= Range.toRangeMask(rangeSet);
+        }
+        stream.defaultWriteObject();
+    }
+}
diff --git a/java/awt/font/TextAttribute.java b/java/awt/font/TextAttribute.java
new file mode 100644
index 0000000..af0dca3
--- /dev/null
+++ b/java/awt/font/TextAttribute.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - 1997, All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998, All Rights Reserved
+ *
+ * The original version of this source code and documentation is
+ * copyrighted and owned by Taligent, Inc., a wholly-owned subsidiary
+ * of IBM. These materials are provided under terms of a License
+ * Agreement between Taligent and Sun. This technology is protected
+ * by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.awt.font;
+
+import java.io.InvalidObjectException;
+import java.text.AttributedCharacterIterator.Attribute;
+import java.util.Map;
+import java.util.HashMap;
+
+// Android-removed: List of classes for use with attribute keys; Android doesn't have those.
+// Android-removed: "Summary of attributes" section. Android doesn't have the referenced classes.
+/**
+ * The <code>TextAttribute</code> class defines attribute keys and
+ * attribute values used for text rendering.
+ * <p>
+ * <code>TextAttribute</code> instances are used as attribute keys to
+ * identify attributes in classes handling text attributes. Other
+ * constants defined in this class can be used as attribute values.
+ * <p>
+ * For each text attribute, the documentation provides:
+ * <UL>
+ *   <LI>the type of its value,
+ *   <LI>the relevant predefined constants, if any
+ *   <LI>the default effect if the attribute is absent
+ *   <LI>the valid values if there are limitations
+ *   <LI>a description of the effect.
+ * </UL>
+ * <p>
+ * <H3>Values</H3>
+ * <UL>
+ *   <LI>The values of attributes must always be immutable.
+ *   <LI>Where value limitations are given, any value outside of that
+ *   set is reserved for future use; the value will be treated as
+ *   the default.
+ *   <LI>The value <code>null</code> is treated the same as the
+ *   default value and results in the default behavior.
+ *   <li>If the value is not of the proper type, the attribute
+ *   will be ignored.
+ *   <li>The identity of the value does not matter, only the actual
+ *   value.  For example, <code>TextAttribute.WEIGHT_BOLD</code> and
+ *   <code>new Float(2.0)</code>
+ *   indicate the same <code>WEIGHT</code>.
+ *   <li>Attribute values of type <code>Number</code> (used for
+ *   <code>WEIGHT</code>, <code>WIDTH</code>, <code>POSTURE</code>,
+ *   <code>SIZE</code>, <code>JUSTIFICATION</code>, and
+ *   <code>TRACKING</code>) can vary along their natural range and are
+ *   not restricted to the predefined constants.
+ *   <code>Number.floatValue()</code> is used to get the actual value
+ *   from the <code>Number</code>.
+ *   <li>The values for <code>WEIGHT</code>, <code>WIDTH</code>, and
+ *   <code>POSTURE</code> are interpolated by the system, which
+ *   can select the 'nearest available' font or use other techniques to
+ *   approximate the user's request.
+ *
+ * </UL>
+ *
+ */
+public final class TextAttribute extends Attribute {
+
+    // table of all instances in this class, used by readResolve
+    private static final Map<String, TextAttribute>
+            instanceMap = new HashMap<String, TextAttribute>(29);
+
+    /**
+     * Constructs a <code>TextAttribute</code> with the specified name.
+     * @param name the attribute name to assign to this
+     * <code>TextAttribute</code>
+     */
+    protected TextAttribute(String name) {
+        super(name);
+        if (this.getClass() == TextAttribute.class) {
+            instanceMap.put(name, this);
+        }
+    }
+
+    /**
+     * Resolves instances being deserialized to the predefined constants.
+     */
+    protected Object readResolve() throws InvalidObjectException {
+        if (this.getClass() != TextAttribute.class) {
+            throw new InvalidObjectException(
+                "subclass didn't correctly implement readResolve");
+        }
+
+        TextAttribute instance = instanceMap.get(getName());
+        if (instance != null) {
+            return instance;
+        } else {
+            throw new InvalidObjectException("unknown attribute name");
+        }
+    }
+
+    // Serialization compatibility with Java 2 platform v1.2.
+    // 1.2 will throw an InvalidObjectException if ever asked to
+    // deserialize INPUT_METHOD_UNDERLINE.
+    // This shouldn't happen in real life.
+    static final long serialVersionUID = 7744112784117861702L;
+
+    //
+    // For use with Font.
+    //
+
+    // Android-removed: Don't link to java.awt.Font class, it doesn't exist on Android.
+    /**
+     * Attribute key for the font name.  Values are instances of
+     * <b><code>String</code></b>.  The default value is
+     * <code>"Default"</code>, which causes the platform default font
+     * family to be used.
+     *
+     * <p> The <code>Font</code> class defines constants for the logical
+     * font names.
+     *
+     * <p>This defines the value passed as <code>name</code> to the
+     * <code>Font</code> constructor.  Both logical and physical
+     * font names are allowed. If a font with the requested name
+     * is not found, the default font is used.
+     *
+     * <p><em>Note:</em> This attribute is unfortunately misnamed, as
+     * it specifies the face name and not just the family.  Thus
+     * values such as "Lucida Sans Bold" will select that face if it
+     * exists.  Note, though, that if the requested face does not
+     * exist, the default will be used with <em>regular</em> weight.
+     * The "Bold" in the name is part of the face name, not a separate
+     * request that the font's weight be bold.</p>
+     */
+    public static final TextAttribute FAMILY =
+        new TextAttribute("family");
+
+    /**
+     * Attribute key for the weight of a font.  Values are instances
+     * of <b><code>Number</code></b>.  The default value is
+     * <code>WEIGHT_REGULAR</code>.
+     *
+     * <p>Several constant values are provided, see {@link
+     * #WEIGHT_EXTRA_LIGHT}, {@link #WEIGHT_LIGHT}, {@link
+     * #WEIGHT_DEMILIGHT}, {@link #WEIGHT_REGULAR}, {@link
+     * #WEIGHT_SEMIBOLD}, {@link #WEIGHT_MEDIUM}, {@link
+     * #WEIGHT_DEMIBOLD}, {@link #WEIGHT_BOLD}, {@link #WEIGHT_HEAVY},
+     * {@link #WEIGHT_EXTRABOLD}, and {@link #WEIGHT_ULTRABOLD}.  The
+     * value <code>WEIGHT_BOLD</code> corresponds to the
+     * style value <code>Font.BOLD</code> as passed to the
+     * <code>Font</code> constructor.
+     *
+     * <p>The value is roughly the ratio of the stem width to that of
+     * the regular weight.
+     *
+     * <p>The system can interpolate the provided value.
+     */
+    public static final TextAttribute WEIGHT =
+        new TextAttribute("weight");
+
+    /**
+     * The lightest predefined weight.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_EXTRA_LIGHT =
+        Float.valueOf(0.5f);
+
+    /**
+     * The standard light weight.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_LIGHT =
+        Float.valueOf(0.75f);
+
+    /**
+     * An intermediate weight between <code>WEIGHT_LIGHT</code> and
+     * <code>WEIGHT_STANDARD</code>.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_DEMILIGHT =
+        Float.valueOf(0.875f);
+
+    /**
+     * The standard weight. This is the default value for <code>WEIGHT</code>.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_REGULAR =
+        Float.valueOf(1.0f);
+
+    /**
+     * A moderately heavier weight than <code>WEIGHT_REGULAR</code>.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_SEMIBOLD =
+        Float.valueOf(1.25f);
+
+    /**
+     * An intermediate weight between <code>WEIGHT_REGULAR</code> and
+     * <code>WEIGHT_BOLD</code>.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_MEDIUM =
+        Float.valueOf(1.5f);
+
+    /**
+     * A moderately lighter weight than <code>WEIGHT_BOLD</code>.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_DEMIBOLD =
+        Float.valueOf(1.75f);
+
+    /**
+     * The standard bold weight.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_BOLD =
+        Float.valueOf(2.0f);
+
+    /**
+     * A moderately heavier weight than <code>WEIGHT_BOLD</code>.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_HEAVY =
+        Float.valueOf(2.25f);
+
+    /**
+     * An extra heavy weight.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_EXTRABOLD =
+        Float.valueOf(2.5f);
+
+    /**
+     * The heaviest predefined weight.
+     * @see #WEIGHT
+     */
+    public static final Float WEIGHT_ULTRABOLD =
+        Float.valueOf(2.75f);
+
+    /**
+     * Attribute key for the width of a font.  Values are instances of
+     * <b><code>Number</code></b>.  The default value is
+     * <code>WIDTH_REGULAR</code>.
+     *
+     * <p>Several constant values are provided, see {@link
+     * #WIDTH_CONDENSED}, {@link #WIDTH_SEMI_CONDENSED}, {@link
+     * #WIDTH_REGULAR}, {@link #WIDTH_SEMI_EXTENDED}, {@link
+     * #WIDTH_EXTENDED}.
+     *
+     * <p>The value is roughly the ratio of the advance width to that
+     * of the regular width.
+     *
+     * <p>The system can interpolate the provided value.
+     */
+    public static final TextAttribute WIDTH =
+        new TextAttribute("width");
+
+    /**
+     * The most condensed predefined width.
+     * @see #WIDTH
+     */
+    public static final Float WIDTH_CONDENSED =
+        Float.valueOf(0.75f);
+
+    /**
+     * A moderately condensed width.
+     * @see #WIDTH
+     */
+    public static final Float WIDTH_SEMI_CONDENSED =
+        Float.valueOf(0.875f);
+
+    /**
+     * The standard width. This is the default value for
+     * <code>WIDTH</code>.
+     * @see #WIDTH
+     */
+    public static final Float WIDTH_REGULAR =
+        Float.valueOf(1.0f);
+
+    /**
+     * A moderately extended width.
+     * @see #WIDTH
+     */
+    public static final Float WIDTH_SEMI_EXTENDED =
+        Float.valueOf(1.25f);
+
+    /**
+     * The most extended predefined width.
+     * @see #WIDTH
+     */
+    public static final Float WIDTH_EXTENDED =
+        Float.valueOf(1.5f);
+
+    // Android-removed: Don't link to java.awt.Font class, it doesn't exist on Android.
+    /**
+     * Attribute key for the posture of a font.  Values are instances
+     * of <b><code>Number</code></b>. The default value is
+     * <code>POSTURE_REGULAR</code>.
+     *
+     * <p>Two constant values are provided, {@link #POSTURE_REGULAR}
+     * and {@link #POSTURE_OBLIQUE}. The value
+     * <code>POSTURE_OBLIQUE</code> corresponds to the style value
+     * <code>Font.ITALIC</code> as passed to the <code>Font</code>
+     * constructor.
+     *
+     * <p>The value is roughly the slope of the stems of the font,
+     * expressed as the run over the rise.  Positive values lean right.
+     *
+     * <p>The system can interpolate the provided value.
+     *
+     * <p>This will affect the font's italic angle as returned by
+     * <code>Font.getItalicAngle</code>.
+     *
+     */
+    public static final TextAttribute POSTURE =
+        new TextAttribute("posture");
+
+    /**
+     * The standard posture, upright.  This is the default value for
+     * <code>POSTURE</code>.
+     * @see #POSTURE
+     */
+    public static final Float POSTURE_REGULAR =
+        Float.valueOf(0.0f);
+
+    /**
+     * The standard italic posture.
+     * @see #POSTURE
+     */
+    public static final Float POSTURE_OBLIQUE =
+        Float.valueOf(0.20f);
+
+    /**
+     * Attribute key for the font size.  Values are instances of
+     * <b><code>Number</code></b>.  The default value is 12pt.
+     *
+     * <p>This corresponds to the <code>size</code> parameter to the
+     * <code>Font</code> constructor.
+     *
+     * <p>Very large or small sizes will impact rendering performance,
+     * and the rendering system might not render text at these sizes.
+     * Negative sizes are illegal and result in the default size.
+     *
+     * <p>Note that the appearance and metrics of a 12pt font with a
+     * 2x transform might be different than that of a 24 point font
+     * with no transform.
+     */
+    public static final TextAttribute SIZE =
+        new TextAttribute("size");
+
+    // Android-removed: References to classes that don't exist on Android.
+    // These classes were AffineTransform, Font, and TransformAttribute.
+    /**
+     * Attribute key for the transform of a font.  Values are
+     * instances of <b><code>TransformAttribute</code></b>.  The
+     * default value is <code>TransformAttribute.IDENTITY</code>.
+     *
+     * <p>The primary intent is to support scaling and skewing, though
+     * other effects are possible.</p>
+     *
+     * <p>Some transforms will cause the baseline to be rotated and/or
+     * shifted.  The text and the baseline are transformed together so
+     * that the text follows the new baseline.  For example, with text
+     * on a horizontal baseline, the new baseline follows the
+     * direction of the unit x vector passed through the
+     * transform. Text metrics are measured against this new baseline.
+     * So, for example, with other things being equal, text rendered
+     * with a rotated TRANSFORM and an unrotated TRANSFORM will measure as
+     * having the same ascent, descent, and advance.</p>
+     */
+     public static final TextAttribute TRANSFORM =
+        new TextAttribute("transform");
+
+    /**
+     * Attribute key for superscripting and subscripting.  Values are
+     * instances of <b><code>Integer</code></b>.  The default value is
+     * 0, which means that no superscript or subscript is used.
+     *
+     * <p>Two constant values are provided, see {@link
+     * #SUPERSCRIPT_SUPER} and {@link #SUPERSCRIPT_SUB}.  These have
+     * the values 1 and -1 respectively.  Values of
+     * greater magnitude define greater levels of superscript or
+     * subscripting, for example, 2 corresponds to super-superscript,
+     * 3 to super-super-superscript, and similarly for negative values
+     * and subscript, up to a level of 7 (or -7).  Values beyond this
+     * range are reserved; behavior is platform-dependent.
+     *
+     * <p><code>SUPERSCRIPT</code> can
+     * impact the ascent and descent of a font.  The ascent
+     * and descent can never become negative, however.
+     */
+    public static final TextAttribute SUPERSCRIPT =
+        new TextAttribute("superscript");
+
+    /**
+     * Standard superscript.
+     * @see #SUPERSCRIPT
+     */
+    public static final Integer SUPERSCRIPT_SUPER =
+        Integer.valueOf(1);
+
+    /**
+     * Standard subscript.
+     * @see #SUPERSCRIPT
+     */
+    public static final Integer SUPERSCRIPT_SUB =
+        Integer.valueOf(-1);
+
+    // Android-removed: Don't link to java.awt.Font class, it doesn't exist on Android.
+    /**
+     * Attribute key used to provide the font to use to render text.
+     *
+     * The default
+     * value is null, indicating that normal resolution of a
+     * <code>Font</code> from attributes should be performed.
+     *
+     * <p><code>TextLayout</code> and
+     * <code>AttributedCharacterIterator</code> work in terms of
+     * <code>Maps</code> of <code>TextAttributes</code>.  Normally,
+     * all the attributes are examined and used to select and
+     * configure a <code>Font</code> instance.  If a <code>FONT</code>
+     * attribute is present, though, its associated <code>Font</code>
+     * will be used.  This provides a way for users to override the
+     * resolution of font attributes into a <code>Font</code>, or
+     * force use of a particular <code>Font</code> instance.  This
+     * also allows users to specify subclasses of <code>Font</code> in
+     * cases where a <code>Font</code> can be subclassed.
+     *
+     * <p><code>FONT</code> is used for special situations where
+     * clients already have a <code>Font</code> instance but still
+     * need to use <code>Map</code>-based APIs.  Typically, there will
+     * be no other attributes in the <code>Map</code> except the
+     * <code>FONT</code> attribute.  With <code>Map</code>-based APIs
+     * the common case is to specify all attributes individually, so
+     * <code>FONT</code> is not needed or desireable.
+     *
+     * <p>However, if both <code>FONT</code> and other attributes are
+     * present in the <code>Map</code>, the rendering system will
+     * merge the attributes defined in the <code>Font</code> with the
+     * additional attributes.  This merging process classifies
+     * <code>TextAttributes</code> into two groups.  One group, the
+     * 'primary' group, is considered fundamental to the selection and
+     * metric behavior of a font.  These attributes are
+     * <code>FAMILY</code>, <code>WEIGHT</code>, <code>WIDTH</code>,
+     * <code>POSTURE</code>, <code>SIZE</code>,
+     * <code>TRANSFORM</code>, <code>SUPERSCRIPT</code>, and
+     * <code>TRACKING</code>. The other group, the 'secondary' group,
+     * consists of all other defined attributes, with the exception of
+     * <code>FONT</code> itself.
+     *
+     * <p>To generate the new <code>Map</code>, first the
+     * <code>Font</code> is obtained from the <code>FONT</code>
+     * attribute, and <em>all</em> of its attributes extracted into a
+     * new <code>Map</code>.  Then only the <em>secondary</em>
+     * attributes from the original <code>Map</code> are added to
+     * those in the new <code>Map</code>.  Thus the values of primary
+     * attributes come solely from the <code>Font</code>, and the
+     * values of secondary attributes originate with the
+     * <code>Font</code> but can be overridden by other values in the
+     * <code>Map</code>.
+     */
+    public static final TextAttribute FONT =
+        new TextAttribute("font");
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see GraphicAttribute
+    /**
+     * Attribute key for a user-defined glyph to display in lieu
+     * of the font's standard glyph for a character.  Values are
+     * intances of GraphicAttribute.  The default value is null,
+     * indicating that the standard glyphs provided by the font
+     * should be used.
+     *
+     * <p>This attribute is used to reserve space for a graphic or
+     * other component embedded in a line of text.  It is required for
+     * correct positioning of 'inline' components within a line when
+     * bidirectional reordering (see {@link java.text.Bidi}) is
+     * performed.  Each character (Unicode code point) will be
+     * rendered using the provided GraphicAttribute. Typically, the
+     * characters to which this attribute is applied should be
+     * <code>&#92;uFFFC</code>.
+     *
+     * <p>The GraphicAttribute determines the logical and visual
+     * bounds of the text; the actual Font values are ignored.
+     */
+    public static final TextAttribute CHAR_REPLACEMENT =
+        new TextAttribute("char_replacement");
+
+    //
+    // Adornments added to text.
+    //
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see java.awt.Paint
+    /**
+     * Attribute key for the paint used to render the text.  Values are
+     * instances of <b><code>Paint</code></b>.  The default value is
+     * null, indicating that the <code>Paint</code> set on the
+     * <code>Graphics2D</code> at the time of rendering is used.
+     *
+     * <p>Glyphs will be rendered using this
+     * <code>Paint</code> regardless of the <code>Paint</code> value
+     * set on the <code>Graphics</code> (but see {@link #SWAP_COLORS}).
+     *
+     * @see #SWAP_COLORS
+     */
+    public static final TextAttribute FOREGROUND =
+        new TextAttribute("foreground");
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see java.awt.Paint
+    /**
+     * Attribute key for the paint used to render the background of
+     * the text.  Values are instances of <b><code>Paint</code></b>.
+     * The default value is null, indicating that the background
+     * should not be rendered.
+     *
+     * <p>The logical bounds of the text will be filled using this
+     * <code>Paint</code>, and then the text will be rendered on top
+     * of it (but see {@link #SWAP_COLORS}).
+     *
+     * <p>The visual bounds of the text is extended to include the
+     * logical bounds, if necessary.  The outline is not affected.
+     *
+     * @see #SWAP_COLORS
+     */
+    public static final TextAttribute BACKGROUND =
+        new TextAttribute("background");
+
+    /**
+     * Attribute key for underline.  Values are instances of
+     * <b><code>Integer</code></b>.  The default value is -1, which
+     * means no underline.
+     *
+     * <p>The constant value {@link #UNDERLINE_ON} is provided.
+     *
+     * <p>The underline affects both the visual bounds and the outline
+     * of the text.
+     */
+    public static final TextAttribute UNDERLINE =
+        new TextAttribute("underline");
+
+    /**
+     * Standard underline.
+     *
+     * @see #UNDERLINE
+     */
+    public static final Integer UNDERLINE_ON =
+        Integer.valueOf(0);
+
+    /**
+     * Attribute key for strikethrough.  Values are instances of
+     * <b><code>Boolean</code></b>.  The default value is
+     * <code>false</code>, which means no strikethrough.
+     *
+     * <p>The constant value {@link #STRIKETHROUGH_ON} is provided.
+     *
+     * <p>The strikethrough affects both the visual bounds and the
+     * outline of the text.
+     */
+    public static final TextAttribute STRIKETHROUGH =
+        new TextAttribute("strikethrough");
+
+    /**
+     * A single strikethrough.
+     *
+     * @see #STRIKETHROUGH
+     */
+    public static final Boolean STRIKETHROUGH_ON =
+        Boolean.TRUE;
+
+    //
+    // Attributes use to control layout of text on a line.
+    //
+
+    /**
+     * Attribute key for the run direction of the line.  Values are
+     * instances of <b><code>Boolean</code></b>.  The default value is
+     * null, which indicates that the standard Bidi algorithm for
+     * determining run direction should be used with the value {@link
+     * java.text.Bidi#DIRECTION_DEFAULT_LEFT_TO_RIGHT}.
+     *
+     * <p>The constants {@link #RUN_DIRECTION_RTL} and {@link
+     * #RUN_DIRECTION_LTR} are provided.
+     *
+     * <p>This determines the value passed to the {@link
+     * java.text.Bidi} constructor to select the primary direction of
+     * the text in the paragraph.
+     *
+     * <p><em>Note:</em> This attribute should have the same value for
+     * all the text in a paragraph, otherwise the behavior is
+     * undetermined.
+     *
+     * @see java.text.Bidi
+     */
+    public static final TextAttribute RUN_DIRECTION =
+        new TextAttribute("run_direction");
+
+    /**
+     * Left-to-right run direction.
+     * @see #RUN_DIRECTION
+     */
+    public static final Boolean RUN_DIRECTION_LTR =
+        Boolean.FALSE;
+
+    /**
+     * Right-to-left run direction.
+     * @see #RUN_DIRECTION
+     */
+    public static final Boolean RUN_DIRECTION_RTL =
+        Boolean.TRUE;
+
+    /**
+     * Attribute key for the embedding level of the text.  Values are
+     * instances of <b><code>Integer</code></b>.  The default value is
+     * <code>null</code>, indicating that the the Bidirectional
+     * algorithm should run without explicit embeddings.
+     *
+     * <p>Positive values 1 through 61 are <em>embedding</em> levels,
+     * negative values -1 through -61 are <em>override</em> levels.
+     * The value 0 means that the base line direction is used.  These
+     * levels are passed in the embedding levels array to the {@link
+     * java.text.Bidi} constructor.
+     *
+     * <p><em>Note:</em> When this attribute is present anywhere in
+     * a paragraph, then any Unicode bidi control characters (RLO,
+     * LRO, RLE, LRE, and PDF) in the paragraph are
+     * disregarded, and runs of text where this attribute is not
+     * present are treated as though it were present and had the value
+     * 0.
+     *
+     * @see java.text.Bidi
+     */
+    public static final TextAttribute BIDI_EMBEDDING =
+        new TextAttribute("bidi_embedding");
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see TextLayout#getJustifiedLayout
+    /**
+     * Attribute key for the justification of a paragraph.  Values are
+     * instances of <b><code>Number</code></b>.  The default value is
+     * 1, indicating that justification should use the full width
+     * provided.  Values are pinned to the range [0..1].
+     *
+     * <p>The constants {@link #JUSTIFICATION_FULL} and {@link
+     * #JUSTIFICATION_NONE} are provided.
+     *
+     * <p>Specifies the fraction of the extra space to use when
+     * justification is requested on a <code>TextLayout</code>. For
+     * example, if the line is 50 points wide and it is requested to
+     * justify to 70 points, a value of 0.75 will pad to use
+     * three-quarters of the remaining space, or 15 points, so that
+     * the resulting line will be 65 points in length.
+     *
+     * <p><em>Note:</em> This should have the same value for all the
+     * text in a paragraph, otherwise the behavior is undetermined.
+     */
+    public static final TextAttribute JUSTIFICATION =
+        new TextAttribute("justification");
+
+    /**
+     * Justify the line to the full requested width.  This is the
+     * default value for <code>JUSTIFICATION</code>.
+     * @see #JUSTIFICATION
+     */
+    public static final Float JUSTIFICATION_FULL =
+        Float.valueOf(1.0f);
+
+    /**
+     * Do not allow the line to be justified.
+     * @see #JUSTIFICATION
+     */
+    public static final Float JUSTIFICATION_NONE =
+        Float.valueOf(0.0f);
+
+    //
+    // For use by input method.
+    //
+
+    // Android-removed: References to java.awt.im.InputMethodHighlight (doesn't exist on Android).
+    /**
+     * Attribute key for input method highlight styles.
+     *
+     * The default value is <code>null</code>,
+     * which means that input method styles should not be applied
+     * before rendering.
+     *
+     * @see java.text.Annotation
+     */
+    public static final TextAttribute INPUT_METHOD_HIGHLIGHT =
+        new TextAttribute("input method highlight");
+
+    /**
+     * Attribute key for input method underlines.  Values
+     * are instances of <b><code>Integer</code></b>.  The default
+     * value is <code>-1</code>, which means no underline.
+     *
+     * <p>Several constant values are provided, see {@link
+     * #UNDERLINE_LOW_ONE_PIXEL}, {@link #UNDERLINE_LOW_TWO_PIXEL},
+     * {@link #UNDERLINE_LOW_DOTTED}, {@link #UNDERLINE_LOW_GRAY}, and
+     * {@link #UNDERLINE_LOW_DASHED}.
+     *
+     * <p>This may be used in conjunction with {@link #UNDERLINE} if
+     * desired.  The primary purpose is for use by input methods.
+     * Other use of these underlines for simple ornamentation might
+     * confuse users.
+     *
+     * <p>The input method underline affects both the visual bounds and
+     * the outline of the text.
+     *
+     * @since 1.3
+     */
+    public static final TextAttribute INPUT_METHOD_UNDERLINE =
+        new TextAttribute("input method underline");
+
+    /**
+     * Single pixel solid low underline.
+     * @see #INPUT_METHOD_UNDERLINE
+     * @since 1.3
+     */
+    public static final Integer UNDERLINE_LOW_ONE_PIXEL =
+        Integer.valueOf(1);
+
+    /**
+     * Double pixel solid low underline.
+     * @see #INPUT_METHOD_UNDERLINE
+     * @since 1.3
+     */
+    public static final Integer UNDERLINE_LOW_TWO_PIXEL =
+        Integer.valueOf(2);
+
+    /**
+     * Single pixel dotted low underline.
+     * @see #INPUT_METHOD_UNDERLINE
+     * @since 1.3
+     */
+    public static final Integer UNDERLINE_LOW_DOTTED =
+        Integer.valueOf(3);
+
+    /**
+     * Double pixel gray low underline.
+     * @see #INPUT_METHOD_UNDERLINE
+     * @since 1.3
+     */
+    public static final Integer UNDERLINE_LOW_GRAY =
+        Integer.valueOf(4);
+
+    /**
+     * Single pixel dashed low underline.
+     * @see #INPUT_METHOD_UNDERLINE
+     * @since 1.3
+     */
+    public static final Integer UNDERLINE_LOW_DASHED =
+        Integer.valueOf(5);
+
+    /**
+     * Attribute key for swapping foreground and background
+     * <code>Paints</code>.  Values are instances of
+     * <b><code>Boolean</code></b>.  The default value is
+     * <code>false</code>, which means do not swap colors.
+     *
+     * <p>The constant value {@link #SWAP_COLORS_ON} is defined.
+     *
+     * <p>If the {@link #FOREGROUND} attribute is set, its
+     * <code>Paint</code> will be used as the background, otherwise
+     * the <code>Paint</code> currently on the <code>Graphics</code>
+     * will be used.  If the {@link #BACKGROUND} attribute is set, its
+     * <code>Paint</code> will be used as the foreground, otherwise
+     * the system will find a contrasting color to the
+     * (resolved) background so that the text will be visible.
+     *
+     * @see #FOREGROUND
+     * @see #BACKGROUND
+     */
+    public static final TextAttribute SWAP_COLORS =
+        new TextAttribute("swap_colors");
+
+    /**
+     * Swap foreground and background.
+     * @see #SWAP_COLORS
+     * @since 1.3
+     */
+    public static final Boolean SWAP_COLORS_ON =
+        Boolean.TRUE;
+
+    /**
+     * Attribute key for converting ASCII decimal digits to other
+     * decimal ranges.  Values are instances of {@link NumericShaper}.
+     * The default is <code>null</code>, which means do not perform
+     * numeric shaping.
+     *
+     * <p>When a numeric shaper is defined, the text is first
+     * processed by the shaper before any other analysis of the text
+     * is performed.
+     *
+     * <p><em>Note:</em> This should have the same value for all the
+     * text in the paragraph, otherwise the behavior is undetermined.
+     *
+     * @see NumericShaper
+     * @since 1.4
+     */
+    public static final TextAttribute NUMERIC_SHAPING =
+        new TextAttribute("numeric_shaping");
+
+    /**
+     * Attribute key to request kerning. Values are instances of
+     * <b><code>Integer</code></b>.  The default value is
+     * <code>0</code>, which does not request kerning.
+     *
+     * <p>The constant value {@link #KERNING_ON} is provided.
+     *
+     * <p>The default advances of single characters are not
+     * appropriate for some character sequences, for example "To" or
+     * "AWAY".  Without kerning the adjacent characters appear to be
+     * separated by too much space.  Kerning causes selected sequences
+     * of characters to be spaced differently for a more pleasing
+     * visual appearance.
+     *
+     * @since 1.6
+     */
+    public static final TextAttribute KERNING =
+        new TextAttribute("kerning");
+
+    /**
+     * Request standard kerning.
+     * @see #KERNING
+     * @since 1.6
+     */
+    public static final Integer KERNING_ON =
+        Integer.valueOf(1);
+
+
+    /**
+     * Attribute key for enabling optional ligatures. Values are
+     * instances of <b><code>Integer</code></b>.  The default value is
+     * <code>0</code>, which means do not use optional ligatures.
+     *
+     * <p>The constant value {@link #LIGATURES_ON} is defined.
+     *
+     * <p>Ligatures required by the writing system are always enabled.
+     *
+     * @since 1.6
+     */
+    public static final TextAttribute LIGATURES =
+        new TextAttribute("ligatures");
+
+    /**
+     * Request standard optional ligatures.
+     * @see #LIGATURES
+     * @since 1.6
+     */
+    public static final Integer LIGATURES_ON =
+        Integer.valueOf(1);
+
+    /**
+     * Attribute key to control tracking.  Values are instances of
+     * <b><code>Number</code></b>.  The default value is
+     * <code>0</code>, which means no additional tracking.
+     *
+     * <p>The constant values {@link #TRACKING_TIGHT} and {@link
+     * #TRACKING_LOOSE} are provided.
+     *
+     * <p>The tracking value is multiplied by the font point size and
+     * passed through the font transform to determine an additional
+     * amount to add to the advance of each glyph cluster.  Positive
+     * tracking values will inhibit formation of optional ligatures.
+     * Tracking values are typically between <code>-0.1</code> and
+     * <code>0.3</code>; values outside this range are generally not
+     * desireable.
+     *
+     * @since 1.6
+     */
+    public static final TextAttribute TRACKING =
+        new TextAttribute("tracking");
+
+    /**
+     * Perform tight tracking.
+     * @see #TRACKING
+     * @since 1.6
+     */
+    public static final Float TRACKING_TIGHT =
+        Float.valueOf(-.04f);
+
+    /**
+     * Perform loose tracking.
+     * @see #TRACKING
+     * @since 1.6
+     */
+    public static final Float TRACKING_LOOSE =
+        Float.valueOf(.04f);
+}
diff --git a/java/beans/ChangeListenerMap.java b/java/beans/ChangeListenerMap.java
new file mode 100644
index 0000000..fa8be47
--- /dev/null
+++ b/java/beans/ChangeListenerMap.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.beans;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EventListener;
+import java.util.EventListenerProxy;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * This is an abstract class that provides base functionality
+ * for the {@link PropertyChangeSupport PropertyChangeSupport} class
+ * and the {@link VetoableChangeSupport VetoableChangeSupport} class.
+ *
+ * @see PropertyChangeListenerMap
+ * @see VetoableChangeListenerMap
+ *
+ * @author Sergey A. Malenkov
+ */
+abstract class ChangeListenerMap<L extends EventListener> {
+    private Map<String, L[]> map;
+
+    /**
+     * Creates an array of listeners.
+     * This method can be optimized by using
+     * the same instance of the empty array
+     * when {@code length} is equal to {@code 0}.
+     *
+     * @param length  the array length
+     * @return        an array with specified length
+     */
+    protected abstract L[] newArray(int length);
+
+    /**
+     * Creates a proxy listener for the specified property.
+     *
+     * @param name      the name of the property to listen on
+     * @param listener  the listener to process events
+     * @return          a proxy listener
+     */
+    protected abstract L newProxy(String name, L listener);
+
+    /**
+     * Adds a listener to the list of listeners for the specified property.
+     * This listener is called as many times as it was added.
+     *
+     * @param name      the name of the property to listen on
+     * @param listener  the listener to process events
+     */
+    public final synchronized void add(String name, L listener) {
+        if (this.map == null) {
+            this.map = new HashMap<>();
+        }
+        L[] array = this.map.get(name);
+        int size = (array != null)
+                ? array.length
+                : 0;
+
+        L[] clone = newArray(size + 1);
+        clone[size] = listener;
+        if (array != null) {
+            System.arraycopy(array, 0, clone, 0, size);
+        }
+        this.map.put(name, clone);
+    }
+
+    /**
+     * Removes a listener from the list of listeners for the specified property.
+     * If the listener was added more than once to the same event source,
+     * this listener will be notified one less time after being removed.
+     *
+     * @param name      the name of the property to listen on
+     * @param listener  the listener to process events
+     */
+    public final synchronized void remove(String name, L listener) {
+        if (this.map != null) {
+            L[] array = this.map.get(name);
+            if (array != null) {
+                for (int i = 0; i < array.length; i++) {
+                    if (listener.equals(array[i])) {
+                        int size = array.length - 1;
+                        if (size > 0) {
+                            L[] clone = newArray(size);
+                            System.arraycopy(array, 0, clone, 0, i);
+                            System.arraycopy(array, i + 1, clone, i, size - i);
+                            this.map.put(name, clone);
+                        }
+                        else {
+                            this.map.remove(name);
+                            if (this.map.isEmpty()) {
+                                this.map = null;
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the list of listeners for the specified property.
+     *
+     * @param name  the name of the property
+     * @return      the corresponding list of listeners
+     */
+    public final synchronized L[] get(String name) {
+        return (this.map != null)
+                ? this.map.get(name)
+                : null;
+    }
+
+    /**
+     * Sets new list of listeners for the specified property.
+     *
+     * @param name       the name of the property
+     * @param listeners  new list of listeners
+     */
+    public final void set(String name, L[] listeners) {
+        if (listeners != null) {
+            if (this.map == null) {
+                this.map = new HashMap<>();
+            }
+            this.map.put(name, listeners);
+        }
+        else if (this.map != null) {
+            this.map.remove(name);
+            if (this.map.isEmpty()) {
+                this.map = null;
+            }
+        }
+    }
+
+    /**
+     * Returns all listeners in the map.
+     *
+     * @return an array of all listeners
+     */
+    public final synchronized L[] getListeners() {
+        if (this.map == null) {
+            return newArray(0);
+        }
+        List<L> list = new ArrayList<>();
+
+        L[] listeners = this.map.get(null);
+        if (listeners != null) {
+            for (L listener : listeners) {
+                list.add(listener);
+            }
+        }
+        for (Entry<String, L[]> entry : this.map.entrySet()) {
+            String name = entry.getKey();
+            if (name != null) {
+                for (L listener : entry.getValue()) {
+                    list.add(newProxy(name, listener));
+                }
+            }
+        }
+        return list.toArray(newArray(list.size()));
+    }
+
+    /**
+     * Returns listeners that have been associated with the named property.
+     *
+     * @param name  the name of the property
+     * @return an array of listeners for the named property
+     */
+    public final L[] getListeners(String name) {
+        if (name != null) {
+            L[] listeners = get(name);
+            if (listeners != null) {
+                return listeners.clone();
+            }
+        }
+        return newArray(0);
+    }
+
+    /**
+     * Indicates whether the map contains
+     * at least one listener to be notified.
+     *
+     * @param name  the name of the property
+     * @return      {@code true} if at least one listener exists or
+     *              {@code false} otherwise
+     */
+    public final synchronized boolean hasListeners(String name) {
+        if (this.map == null) {
+            return false;
+        }
+        L[] array = this.map.get(null);
+        return (array != null) || ((name != null) && (null != this.map.get(name)));
+    }
+
+    /**
+     * Returns a set of entries from the map.
+     * Each entry is a pair consisted of the property name
+     * and the corresponding list of listeners.
+     *
+     * @return a set of entries from the map
+     */
+    public final Set<Entry<String, L[]>> getEntries() {
+        return (this.map != null)
+                ? this.map.entrySet()
+                : Collections.<Entry<String, L[]>>emptySet();
+    }
+
+    /**
+     * Extracts a real listener from the proxy listener.
+     * It is necessary because default proxy class is not serializable.
+     *
+     * @return a real listener
+     */
+    public abstract L extract(L listener);
+}
diff --git a/java/beans/IndexedPropertyChangeEvent.java b/java/beans/IndexedPropertyChangeEvent.java
new file mode 100644
index 0000000..4769c81
--- /dev/null
+++ b/java/beans/IndexedPropertyChangeEvent.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.beans;
+
+/**
+ * An "IndexedPropertyChange" event gets delivered whenever a component that
+ * conforms to the JavaBeans&trade; specification (a "bean") changes a bound
+ * indexed property. This class is an extension of <code>PropertyChangeEvent</code>
+ * but contains the index of the property that has changed.
+ * <P>
+ * Null values may be provided for the old and the new values if their
+ * true values are not known.
+ * <P>
+ * An event source may send a null object as the name to indicate that an
+ * arbitrary set of if its properties have changed.  In this case the
+ * old and new values should also be null.
+ *
+ * @since 1.5
+ * @author Mark Davidson
+ */
+public class IndexedPropertyChangeEvent extends PropertyChangeEvent {
+    private static final long serialVersionUID = -320227448495806870L;
+
+    private int index;
+
+    /**
+     * Constructs a new <code>IndexedPropertyChangeEvent</code> object.
+     *
+     * @param source  The bean that fired the event.
+     * @param propertyName  The programmatic name of the property that
+     *             was changed.
+     * @param oldValue      The old value of the property.
+     * @param newValue      The new value of the property.
+     * @param index index of the property element that was changed.
+     */
+    public IndexedPropertyChangeEvent(Object source, String propertyName,
+                                      Object oldValue, Object newValue,
+                                      int index) {
+        super (source, propertyName, oldValue, newValue);
+        this.index = index;
+    }
+
+    /**
+     * Gets the index of the property that was changed.
+     *
+     * @return The index specifying the property element that was
+     *         changed.
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    void appendTo(StringBuilder sb) {
+        sb.append("; index=").append(getIndex());
+    }
+}
diff --git a/java/beans/PropertyChangeEvent.java b/java/beans/PropertyChangeEvent.java
new file mode 100644
index 0000000..eeaa651
--- /dev/null
+++ b/java/beans/PropertyChangeEvent.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.beans;
+
+import java.util.EventObject;
+
+/**
+ * A "PropertyChange" event gets delivered whenever a bean changes a "bound"
+ * or "constrained" property.  A PropertyChangeEvent object is sent as an
+ * argument to the PropertyChangeListener and VetoableChangeListener methods.
+ * <P>
+ * Normally PropertyChangeEvents are accompanied by the name and the old
+ * and new value of the changed property.  If the new value is a primitive
+ * type (such as int or boolean) it must be wrapped as the
+ * corresponding java.lang.* Object type (such as Integer or Boolean).
+ * <P>
+ * Null values may be provided for the old and the new values if their
+ * true values are not known.
+ * <P>
+ * An event source may send a null object as the name to indicate that an
+ * arbitrary set of if its properties have changed.  In this case the
+ * old and new values should also be null.
+ */
+public class PropertyChangeEvent extends EventObject {
+    private static final long serialVersionUID = 7042693688939648123L;
+
+    /**
+     * Constructs a new {@code PropertyChangeEvent}.
+     *
+     * @param source        the bean that fired the event
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     *
+     * @throws IllegalArgumentException if {@code source} is {@code null}
+     */
+    public PropertyChangeEvent(Object source, String propertyName,
+                               Object oldValue, Object newValue) {
+        super(source);
+        this.propertyName = propertyName;
+        this.newValue = newValue;
+        this.oldValue = oldValue;
+    }
+
+    /**
+     * Gets the programmatic name of the property that was changed.
+     *
+     * @return  The programmatic name of the property that was changed.
+     *          May be null if multiple properties have changed.
+     */
+    public String getPropertyName() {
+        return propertyName;
+    }
+
+    /**
+     * Gets the new value for the property, expressed as an Object.
+     *
+     * @return  The new value for the property, expressed as an Object.
+     *          May be null if multiple properties have changed.
+     */
+    public Object getNewValue() {
+        return newValue;
+    }
+
+    /**
+     * Gets the old value for the property, expressed as an Object.
+     *
+     * @return  The old value for the property, expressed as an Object.
+     *          May be null if multiple properties have changed.
+     */
+    public Object getOldValue() {
+        return oldValue;
+    }
+
+    /**
+     * Sets the propagationId object for the event.
+     *
+     * @param propagationId  The propagationId object for the event.
+     */
+    public void setPropagationId(Object propagationId) {
+        this.propagationId = propagationId;
+    }
+
+    /**
+     * The "propagationId" field is reserved for future use.  In Beans 1.0
+     * the sole requirement is that if a listener catches a PropertyChangeEvent
+     * and then fires a PropertyChangeEvent of its own, then it should
+     * make sure that it propagates the propagationId field from its
+     * incoming event to its outgoing event.
+     *
+     * @return the propagationId object associated with a bound/constrained
+     *          property update.
+     */
+    public Object getPropagationId() {
+        return propagationId;
+    }
+
+    /**
+     * name of the property that changed.  May be null, if not known.
+     * @serial
+     */
+    private String propertyName;
+
+    /**
+     * New value for property.  May be null if not known.
+     * @serial
+     */
+    private Object newValue;
+
+    /**
+     * Previous value for property.  May be null if not known.
+     * @serial
+     */
+    private Object oldValue;
+
+    /**
+     * Propagation ID.  May be null.
+     * @serial
+     * @see #getPropagationId
+     */
+    private Object propagationId;
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return a string representation of the object
+     *
+     * @since 1.7
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder(getClass().getName());
+        sb.append("[propertyName=").append(getPropertyName());
+        appendTo(sb);
+        sb.append("; oldValue=").append(getOldValue());
+        sb.append("; newValue=").append(getNewValue());
+        sb.append("; propagationId=").append(getPropagationId());
+        sb.append("; source=").append(getSource());
+        return sb.append("]").toString();
+    }
+
+    void appendTo(StringBuilder sb) {
+    }
+}
diff --git a/java/beans/PropertyChangeListener.java b/java/beans/PropertyChangeListener.java
new file mode 100644
index 0000000..5b78d48
--- /dev/null
+++ b/java/beans/PropertyChangeListener.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.beans;
+
+/**
+ * A "PropertyChange" event gets fired whenever a bean changes a "bound"
+ * property.  You can register a PropertyChangeListener with a source
+ * bean so as to be notified of any bound property updates.
+ */
+
+public interface PropertyChangeListener extends java.util.EventListener {
+
+    /**
+     * This method gets called when a bound property is changed.
+     * @param evt A PropertyChangeEvent object describing the event source
+     *          and the property that has changed.
+     */
+
+    void propertyChange(PropertyChangeEvent evt);
+
+}
diff --git a/java/beans/PropertyChangeListenerProxy.java b/java/beans/PropertyChangeListenerProxy.java
new file mode 100644
index 0000000..e8fe197
--- /dev/null
+++ b/java/beans/PropertyChangeListenerProxy.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.beans;
+
+import java.util.EventListenerProxy;
+
+/**
+ * A class which extends the {@code EventListenerProxy}
+ * specifically for adding a {@code PropertyChangeListener}
+ * with a "bound" property.
+ * Instances of this class can be added
+ * as {@code PropertyChangeListener}s to a bean
+ * which supports firing property change events.
+ * <p>
+ * If the object has a {@code getPropertyChangeListeners} method
+ * then the array returned could be a mixture of {@code PropertyChangeListener}
+ * and {@code PropertyChangeListenerProxy} objects.
+ *
+ * @see java.util.EventListenerProxy
+ * @see PropertyChangeSupport#getPropertyChangeListeners
+ * @since 1.4
+ */
+public class PropertyChangeListenerProxy
+        extends EventListenerProxy<PropertyChangeListener>
+        implements PropertyChangeListener {
+
+    private final String propertyName;
+
+    /**
+     * Constructor which binds the {@code PropertyChangeListener}
+     * to a specific property.
+     *
+     * @param propertyName  the name of the property to listen on
+     * @param listener      the listener object
+     */
+    public PropertyChangeListenerProxy(String propertyName, PropertyChangeListener listener) {
+        super(listener);
+        this.propertyName = propertyName;
+    }
+
+    /**
+     * Forwards the property change event to the listener delegate.
+     *
+     * @param event  the property change event
+     */
+    public void propertyChange(PropertyChangeEvent event) {
+        getListener().propertyChange(event);
+    }
+
+    /**
+     * Returns the name of the named property associated with the listener.
+     *
+     * @return the name of the named property associated with the listener
+     */
+    public String getPropertyName() {
+        return this.propertyName;
+    }
+}
diff --git a/java/beans/PropertyChangeSupport.java b/java/beans/PropertyChangeSupport.java
new file mode 100644
index 0000000..b99f481
--- /dev/null
+++ b/java/beans/PropertyChangeSupport.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.beans;
+
+import java.io.Serializable;
+import java.io.ObjectStreamField;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Map.Entry;
+
+// Android-changed: Removed @see tag (target does not exist on Android):
+// @see VetoableChangeSupport
+/**
+ * This is a utility class that can be used by beans that support bound
+ * properties.  It manages a list of listeners and dispatches
+ * {@link PropertyChangeEvent}s to them.  You can use an instance of this class
+ * as a member field of your bean and delegate these types of work to it.
+ * The {@link PropertyChangeListener} can be registered for all properties
+ * or for a property specified by name.
+ * <p>
+ * Here is an example of {@code PropertyChangeSupport} usage that follows
+ * the rules and recommendations laid out in the JavaBeans&trade; specification:
+ * <pre>
+ * public class MyBean {
+ *     private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
+ *
+ *     public void addPropertyChangeListener(PropertyChangeListener listener) {
+ *         this.pcs.addPropertyChangeListener(listener);
+ *     }
+ *
+ *     public void removePropertyChangeListener(PropertyChangeListener listener) {
+ *         this.pcs.removePropertyChangeListener(listener);
+ *     }
+ *
+ *     private String value;
+ *
+ *     public String getValue() {
+ *         return this.value;
+ *     }
+ *
+ *     public void setValue(String newValue) {
+ *         String oldValue = this.value;
+ *         this.value = newValue;
+ *         this.pcs.firePropertyChange("value", oldValue, newValue);
+ *     }
+ *
+ *     [...]
+ * }
+ * </pre>
+ * <p>
+ * A {@code PropertyChangeSupport} instance is thread-safe.
+ * <p>
+ * This class is serializable.  When it is serialized it will save
+ * (and restore) any listeners that are themselves serializable.  Any
+ * non-serializable listeners will be skipped during serialization.
+ */
+public class PropertyChangeSupport implements Serializable {
+    private PropertyChangeListenerMap map = new PropertyChangeListenerMap();
+
+    /**
+     * Constructs a <code>PropertyChangeSupport</code> object.
+     *
+     * @param sourceBean  The bean to be given as the source for any events.
+     */
+    public PropertyChangeSupport(Object sourceBean) {
+        if (sourceBean == null) {
+            throw new NullPointerException();
+        }
+        source = sourceBean;
+    }
+
+    /**
+     * Add a PropertyChangeListener to the listener list.
+     * The listener is registered for all properties.
+     * The same listener object may be added more than once, and will be called
+     * as many times as it is added.
+     * If <code>listener</code> is null, no exception is thrown and no action
+     * is taken.
+     *
+     * @param listener  The PropertyChangeListener to be added
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        if (listener == null) {
+            return;
+        }
+        if (listener instanceof PropertyChangeListenerProxy) {
+            PropertyChangeListenerProxy proxy =
+                   (PropertyChangeListenerProxy)listener;
+            // Call two argument add method.
+            addPropertyChangeListener(proxy.getPropertyName(),
+                                      proxy.getListener());
+        } else {
+            this.map.add(null, listener);
+        }
+    }
+
+    /**
+     * Remove a PropertyChangeListener from the listener list.
+     * This removes a PropertyChangeListener that was registered
+     * for all properties.
+     * If <code>listener</code> was added more than once to the same event
+     * source, it will be notified one less time after being removed.
+     * If <code>listener</code> is null, or was never added, no exception is
+     * thrown and no action is taken.
+     *
+     * @param listener  The PropertyChangeListener to be removed
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        if (listener == null) {
+            return;
+        }
+        if (listener instanceof PropertyChangeListenerProxy) {
+            PropertyChangeListenerProxy proxy =
+                    (PropertyChangeListenerProxy)listener;
+            // Call two argument remove method.
+            removePropertyChangeListener(proxy.getPropertyName(),
+                                         proxy.getListener());
+        } else {
+            this.map.remove(null, listener);
+        }
+    }
+
+    /**
+     * Returns an array of all the listeners that were added to the
+     * PropertyChangeSupport object with addPropertyChangeListener().
+     * <p>
+     * If some listeners have been added with a named property, then
+     * the returned array will be a mixture of PropertyChangeListeners
+     * and <code>PropertyChangeListenerProxy</code>s. If the calling
+     * method is interested in distinguishing the listeners then it must
+     * test each element to see if it's a
+     * <code>PropertyChangeListenerProxy</code>, perform the cast, and examine
+     * the parameter.
+     *
+     * <pre>{@code
+     * PropertyChangeListener[] listeners = bean.getPropertyChangeListeners();
+     * for (int i = 0; i < listeners.length; i++) {
+     *   if (listeners[i] instanceof PropertyChangeListenerProxy) {
+     *     PropertyChangeListenerProxy proxy =
+     *                    (PropertyChangeListenerProxy)listeners[i];
+     *     if (proxy.getPropertyName().equals("foo")) {
+     *       // proxy is a PropertyChangeListener which was associated
+     *       // with the property named "foo"
+     *     }
+     *   }
+     * }
+     * }</pre>
+     *
+     * @see PropertyChangeListenerProxy
+     * @return all of the <code>PropertyChangeListeners</code> added or an
+     *         empty array if no listeners have been added
+     * @since 1.4
+     */
+    public PropertyChangeListener[] getPropertyChangeListeners() {
+        return this.map.getListeners();
+    }
+
+    /**
+     * Add a PropertyChangeListener for a specific property.  The listener
+     * will be invoked only when a call on firePropertyChange names that
+     * specific property.
+     * The same listener object may be added more than once.  For each
+     * property,  the listener will be invoked the number of times it was added
+     * for that property.
+     * If <code>propertyName</code> or <code>listener</code> is null, no
+     * exception is thrown and no action is taken.
+     *
+     * @param propertyName  The name of the property to listen on.
+     * @param listener  The PropertyChangeListener to be added
+     */
+    public void addPropertyChangeListener(
+                String propertyName,
+                PropertyChangeListener listener) {
+        if (listener == null || propertyName == null) {
+            return;
+        }
+        listener = this.map.extract(listener);
+        if (listener != null) {
+            this.map.add(propertyName, listener);
+        }
+    }
+
+    /**
+     * Remove a PropertyChangeListener for a specific property.
+     * If <code>listener</code> was added more than once to the same event
+     * source for the specified property, it will be notified one less time
+     * after being removed.
+     * If <code>propertyName</code> is null,  no exception is thrown and no
+     * action is taken.
+     * If <code>listener</code> is null, or was never added for the specified
+     * property, no exception is thrown and no action is taken.
+     *
+     * @param propertyName  The name of the property that was listened on.
+     * @param listener  The PropertyChangeListener to be removed
+     */
+    public void removePropertyChangeListener(
+                String propertyName,
+                PropertyChangeListener listener) {
+        if (listener == null || propertyName == null) {
+            return;
+        }
+        listener = this.map.extract(listener);
+        if (listener != null) {
+            this.map.remove(propertyName, listener);
+        }
+    }
+
+    /**
+     * Returns an array of all the listeners which have been associated
+     * with the named property.
+     *
+     * @param propertyName  The name of the property being listened to
+     * @return all of the <code>PropertyChangeListeners</code> associated with
+     *         the named property.  If no such listeners have been added,
+     *         or if <code>propertyName</code> is null, an empty array is
+     *         returned.
+     * @since 1.4
+     */
+    public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
+        return this.map.getListeners(propertyName);
+    }
+
+    /**
+     * Reports a bound property update to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if old and new values are equal and non-null.
+     * <p>
+     * This is merely a convenience wrapper around the more general
+     * {@link #firePropertyChange(PropertyChangeEvent)} method.
+     *
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     */
+    public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+        if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
+            firePropertyChange(new PropertyChangeEvent(this.source, propertyName, oldValue, newValue));
+        }
+    }
+
+    /**
+     * Reports an integer bound property update to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if old and new values are equal.
+     * <p>
+     * This is merely a convenience wrapper around the more general
+     * {@link #firePropertyChange(String, Object, Object)}  method.
+     *
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     */
+    public void firePropertyChange(String propertyName, int oldValue, int newValue) {
+        if (oldValue != newValue) {
+            firePropertyChange(propertyName, Integer.valueOf(oldValue), Integer.valueOf(newValue));
+        }
+    }
+
+    /**
+     * Reports a boolean bound property update to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if old and new values are equal.
+     * <p>
+     * This is merely a convenience wrapper around the more general
+     * {@link #firePropertyChange(String, Object, Object)}  method.
+     *
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     */
+    public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
+        if (oldValue != newValue) {
+            firePropertyChange(propertyName, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
+        }
+    }
+
+    /**
+     * Fires a property change event to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if the given event's old and new values are equal and non-null.
+     *
+     * @param event  the {@code PropertyChangeEvent} to be fired
+     */
+    public void firePropertyChange(PropertyChangeEvent event) {
+        Object oldValue = event.getOldValue();
+        Object newValue = event.getNewValue();
+        if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
+            String name = event.getPropertyName();
+
+            PropertyChangeListener[] common = this.map.get(null);
+            PropertyChangeListener[] named = (name != null)
+                        ? this.map.get(name)
+                        : null;
+
+            fire(common, event);
+            fire(named, event);
+        }
+    }
+
+    private static void fire(PropertyChangeListener[] listeners, PropertyChangeEvent event) {
+        if (listeners != null) {
+            for (PropertyChangeListener listener : listeners) {
+                listener.propertyChange(event);
+            }
+        }
+    }
+
+    /**
+     * Reports a bound indexed property update to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if old and new values are equal and non-null.
+     * <p>
+     * This is merely a convenience wrapper around the more general
+     * {@link #firePropertyChange(PropertyChangeEvent)} method.
+     *
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param index         the index of the property element that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     * @since 1.5
+     */
+    public void fireIndexedPropertyChange(String propertyName, int index, Object oldValue, Object newValue) {
+        if (oldValue == null || newValue == null || !oldValue.equals(newValue)) {
+            firePropertyChange(new IndexedPropertyChangeEvent(source, propertyName, oldValue, newValue, index));
+        }
+    }
+
+    /**
+     * Reports an integer bound indexed property update to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if old and new values are equal.
+     * <p>
+     * This is merely a convenience wrapper around the more general
+     * {@link #fireIndexedPropertyChange(String, int, Object, Object)} method.
+     *
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param index         the index of the property element that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     * @since 1.5
+     */
+    public void fireIndexedPropertyChange(String propertyName, int index, int oldValue, int newValue) {
+        if (oldValue != newValue) {
+            fireIndexedPropertyChange(propertyName, index, Integer.valueOf(oldValue), Integer.valueOf(newValue));
+        }
+    }
+
+    /**
+     * Reports a boolean bound indexed property update to listeners
+     * that have been registered to track updates of
+     * all properties or a property with the specified name.
+     * <p>
+     * No event is fired if old and new values are equal.
+     * <p>
+     * This is merely a convenience wrapper around the more general
+     * {@link #fireIndexedPropertyChange(String, int, Object, Object)} method.
+     *
+     * @param propertyName  the programmatic name of the property that was changed
+     * @param index         the index of the property element that was changed
+     * @param oldValue      the old value of the property
+     * @param newValue      the new value of the property
+     * @since 1.5
+     */
+    public void fireIndexedPropertyChange(String propertyName, int index, boolean oldValue, boolean newValue) {
+        if (oldValue != newValue) {
+            fireIndexedPropertyChange(propertyName, index, Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
+        }
+    }
+
+    /**
+     * Check if there are any listeners for a specific property, including
+     * those registered on all properties.  If <code>propertyName</code>
+     * is null, only check for listeners registered on all properties.
+     *
+     * @param propertyName  the property name.
+     * @return true if there are one or more listeners for the given property
+     */
+    public boolean hasListeners(String propertyName) {
+        return this.map.hasListeners(propertyName);
+    }
+
+    /**
+     * @serialData Null terminated list of <code>PropertyChangeListeners</code>.
+     * <p>
+     * At serialization time we skip non-serializable listeners and
+     * only serialize the serializable listeners.
+     */
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        Hashtable<String, PropertyChangeSupport> children = null;
+        PropertyChangeListener[] listeners = null;
+        synchronized (this.map) {
+            for (Entry<String, PropertyChangeListener[]> entry : this.map.getEntries()) {
+                String property = entry.getKey();
+                if (property == null) {
+                    listeners = entry.getValue();
+                } else {
+                    if (children == null) {
+                        children = new Hashtable<>();
+                    }
+                    PropertyChangeSupport pcs = new PropertyChangeSupport(this.source);
+                    pcs.map.set(null, entry.getValue());
+                    children.put(property, pcs);
+                }
+            }
+        }
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("children", children);
+        fields.put("source", this.source);
+        fields.put("propertyChangeSupportSerializedDataVersion", 2);
+        s.writeFields();
+
+        if (listeners != null) {
+            for (PropertyChangeListener l : listeners) {
+                if (l instanceof Serializable) {
+                    s.writeObject(l);
+                }
+            }
+        }
+        s.writeObject(null);
+    }
+
+    private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
+        this.map = new PropertyChangeListenerMap();
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        @SuppressWarnings("unchecked")
+        Hashtable<String, PropertyChangeSupport> children = (Hashtable<String, PropertyChangeSupport>) fields.get("children", null);
+        this.source = fields.get("source", null);
+        fields.get("propertyChangeSupportSerializedDataVersion", 2);
+
+        Object listenerOrNull;
+        while (null != (listenerOrNull = s.readObject())) {
+            this.map.add(null, (PropertyChangeListener)listenerOrNull);
+        }
+        if (children != null) {
+            for (Entry<String, PropertyChangeSupport> entry : children.entrySet()) {
+                for (PropertyChangeListener listener : entry.getValue().getPropertyChangeListeners()) {
+                    this.map.add(entry.getKey(), listener);
+                }
+            }
+        }
+    }
+
+    /**
+     * The object to be provided as the "source" for any generated events.
+     */
+    private Object source;
+
+    /**
+     * @serialField children                                   Hashtable
+     * @serialField source                                     Object
+     * @serialField propertyChangeSupportSerializedDataVersion int
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("children", Hashtable.class),
+            new ObjectStreamField("source", Object.class),
+            new ObjectStreamField("propertyChangeSupportSerializedDataVersion", Integer.TYPE)
+    };
+
+    /**
+     * Serialization version ID, so we're compatible with JDK 1.1
+     */
+    static final long serialVersionUID = 6401253773779951803L;
+
+    /**
+     * This is a {@link ChangeListenerMap ChangeListenerMap} implementation
+     * that works with {@link PropertyChangeListener PropertyChangeListener} objects.
+     */
+    private static final class PropertyChangeListenerMap extends ChangeListenerMap<PropertyChangeListener> {
+        private static final PropertyChangeListener[] EMPTY = {};
+
+        /**
+         * Creates an array of {@link PropertyChangeListener PropertyChangeListener} objects.
+         * This method uses the same instance of the empty array
+         * when {@code length} equals {@code 0}.
+         *
+         * @param length  the array length
+         * @return        an array with specified length
+         */
+        @Override
+        protected PropertyChangeListener[] newArray(int length) {
+            return (0 < length)
+                    ? new PropertyChangeListener[length]
+                    : EMPTY;
+        }
+
+        /**
+         * Creates a {@link PropertyChangeListenerProxy PropertyChangeListenerProxy}
+         * object for the specified property.
+         *
+         * @param name      the name of the property to listen on
+         * @param listener  the listener to process events
+         * @return          a {@code PropertyChangeListenerProxy} object
+         */
+        @Override
+        protected PropertyChangeListener newProxy(String name, PropertyChangeListener listener) {
+            return new PropertyChangeListenerProxy(name, listener);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public final PropertyChangeListener extract(PropertyChangeListener listener) {
+            while (listener instanceof PropertyChangeListenerProxy) {
+                listener = ((PropertyChangeListenerProxy) listener).getListener();
+            }
+            return listener;
+        }
+    }
+}
diff --git a/java/io/Bits.java b/java/io/Bits.java
new file mode 100644
index 0000000..5563e66
--- /dev/null
+++ b/java/io/Bits.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Utility methods for packing/unpacking primitive values in/out of byte arrays
+ * using big-endian byte ordering.
+ */
+class Bits {
+
+    /*
+     * Methods for unpacking primitive values from byte arrays starting at
+     * given offsets.
+     */
+
+    static boolean getBoolean(byte[] b, int off) {
+        return b[off] != 0;
+    }
+
+    static char getChar(byte[] b, int off) {
+        return (char) ((b[off + 1] & 0xFF) +
+                       (b[off] << 8));
+    }
+
+    static short getShort(byte[] b, int off) {
+        return (short) ((b[off + 1] & 0xFF) +
+                        (b[off] << 8));
+    }
+
+    static int getInt(byte[] b, int off) {
+        return ((b[off + 3] & 0xFF)      ) +
+               ((b[off + 2] & 0xFF) <<  8) +
+               ((b[off + 1] & 0xFF) << 16) +
+               ((b[off    ]       ) << 24);
+    }
+
+    static float getFloat(byte[] b, int off) {
+        return Float.intBitsToFloat(getInt(b, off));
+    }
+
+    static long getLong(byte[] b, int off) {
+        return ((b[off + 7] & 0xFFL)      ) +
+               ((b[off + 6] & 0xFFL) <<  8) +
+               ((b[off + 5] & 0xFFL) << 16) +
+               ((b[off + 4] & 0xFFL) << 24) +
+               ((b[off + 3] & 0xFFL) << 32) +
+               ((b[off + 2] & 0xFFL) << 40) +
+               ((b[off + 1] & 0xFFL) << 48) +
+               (((long) b[off])      << 56);
+    }
+
+    static double getDouble(byte[] b, int off) {
+        return Double.longBitsToDouble(getLong(b, off));
+    }
+
+    /*
+     * Methods for packing primitive values into byte arrays starting at given
+     * offsets.
+     */
+
+    static void putBoolean(byte[] b, int off, boolean val) {
+        b[off] = (byte) (val ? 1 : 0);
+    }
+
+    static void putChar(byte[] b, int off, char val) {
+        b[off + 1] = (byte) (val      );
+        b[off    ] = (byte) (val >>> 8);
+    }
+
+    static void putShort(byte[] b, int off, short val) {
+        b[off + 1] = (byte) (val      );
+        b[off    ] = (byte) (val >>> 8);
+    }
+
+    static void putInt(byte[] b, int off, int val) {
+        b[off + 3] = (byte) (val       );
+        b[off + 2] = (byte) (val >>>  8);
+        b[off + 1] = (byte) (val >>> 16);
+        b[off    ] = (byte) (val >>> 24);
+    }
+
+    static void putFloat(byte[] b, int off, float val) {
+        putInt(b, off,  Float.floatToIntBits(val));
+    }
+
+    static void putLong(byte[] b, int off, long val) {
+        b[off + 7] = (byte) (val       );
+        b[off + 6] = (byte) (val >>>  8);
+        b[off + 5] = (byte) (val >>> 16);
+        b[off + 4] = (byte) (val >>> 24);
+        b[off + 3] = (byte) (val >>> 32);
+        b[off + 2] = (byte) (val >>> 40);
+        b[off + 1] = (byte) (val >>> 48);
+        b[off    ] = (byte) (val >>> 56);
+    }
+
+    static void putDouble(byte[] b, int off, double val) {
+        putLong(b, off, Double.doubleToLongBits(val));
+    }
+}
diff --git a/java/io/BufferedInputStream.java b/java/io/BufferedInputStream.java
new file mode 100644
index 0000000..e39c20c
--- /dev/null
+++ b/java/io/BufferedInputStream.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/**
+ * A <code>BufferedInputStream</code> adds
+ * functionality to another input stream-namely,
+ * the ability to buffer the input and to
+ * support the <code>mark</code> and <code>reset</code>
+ * methods. When  the <code>BufferedInputStream</code>
+ * is created, an internal buffer array is
+ * created. As bytes  from the stream are read
+ * or skipped, the internal buffer is refilled
+ * as necessary  from the contained input stream,
+ * many bytes at a time. The <code>mark</code>
+ * operation  remembers a point in the input
+ * stream and the <code>reset</code> operation
+ * causes all the  bytes read since the most
+ * recent <code>mark</code> operation to be
+ * reread before new bytes are  taken from
+ * the contained input stream.
+ *
+ * @author  Arthur van Hoff
+ * @since   JDK1.0
+ */
+public
+class BufferedInputStream extends FilterInputStream {
+
+    // Android-changed: made final
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    // Android-changed: made final
+    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * The internal buffer array where the data is stored. When necessary,
+     * it may be replaced by another array of
+     * a different size.
+     */
+    protected volatile byte buf[];
+
+    /**
+     * Atomic updater to provide compareAndSet for buf. This is
+     * necessary because closes can be asynchronous. We use nullness
+     * of buf[] as primary indicator that this stream is closed. (The
+     * "in" field is also nulled out on close.)
+     */
+    private static final
+        AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
+        AtomicReferenceFieldUpdater.newUpdater
+        (BufferedInputStream.class,  byte[].class, "buf");
+
+    /**
+     * The index one greater than the index of the last valid byte in
+     * the buffer.
+     * This value is always
+     * in the range <code>0</code> through <code>buf.length</code>;
+     * elements <code>buf[0]</code>  through <code>buf[count-1]
+     * </code>contain buffered input data obtained
+     * from the underlying  input stream.
+     */
+    protected int count;
+
+    /**
+     * The current position in the buffer. This is the index of the next
+     * character to be read from the <code>buf</code> array.
+     * <p>
+     * This value is always in the range <code>0</code>
+     * through <code>count</code>. If it is less
+     * than <code>count</code>, then  <code>buf[pos]</code>
+     * is the next byte to be supplied as input;
+     * if it is equal to <code>count</code>, then
+     * the  next <code>read</code> or <code>skip</code>
+     * operation will require more bytes to be
+     * read from the contained  input stream.
+     *
+     * @see     java.io.BufferedInputStream#buf
+     */
+    protected int pos;
+
+    /**
+     * The value of the <code>pos</code> field at the time the last
+     * <code>mark</code> method was called.
+     * <p>
+     * This value is always
+     * in the range <code>-1</code> through <code>pos</code>.
+     * If there is no marked position in  the input
+     * stream, this field is <code>-1</code>. If
+     * there is a marked position in the input
+     * stream,  then <code>buf[markpos]</code>
+     * is the first byte to be supplied as input
+     * after a <code>reset</code> operation. If
+     * <code>markpos</code> is not <code>-1</code>,
+     * then all bytes from positions <code>buf[markpos]</code>
+     * through  <code>buf[pos-1]</code> must remain
+     * in the buffer array (though they may be
+     * moved to  another place in the buffer array,
+     * with suitable adjustments to the values
+     * of <code>count</code>,  <code>pos</code>,
+     * and <code>markpos</code>); they may not
+     * be discarded unless and until the difference
+     * between <code>pos</code> and <code>markpos</code>
+     * exceeds <code>marklimit</code>.
+     *
+     * @see     java.io.BufferedInputStream#mark(int)
+     * @see     java.io.BufferedInputStream#pos
+     */
+    protected int markpos = -1;
+
+    /**
+     * The maximum read ahead allowed after a call to the
+     * <code>mark</code> method before subsequent calls to the
+     * <code>reset</code> method fail.
+     * Whenever the difference between <code>pos</code>
+     * and <code>markpos</code> exceeds <code>marklimit</code>,
+     * then the  mark may be dropped by setting
+     * <code>markpos</code> to <code>-1</code>.
+     *
+     * @see     java.io.BufferedInputStream#mark(int)
+     * @see     java.io.BufferedInputStream#reset()
+     */
+    protected int marklimit;
+
+    /**
+     * Check to make sure that underlying input stream has not been
+     * nulled out due to close; if not return it;
+     */
+    private InputStream getInIfOpen() throws IOException {
+        InputStream input = in;
+        if (input == null)
+            throw new IOException("Stream closed");
+        return input;
+    }
+
+    /**
+     * Check to make sure that buffer has not been nulled out due to
+     * close; if not return it;
+     */
+    private byte[] getBufIfOpen() throws IOException {
+        byte[] buffer = buf;
+        if (buffer == null)
+            throw new IOException("Stream closed");
+        return buffer;
+    }
+
+    /**
+     * Creates a <code>BufferedInputStream</code>
+     * and saves its  argument, the input stream
+     * <code>in</code>, for later use. An internal
+     * buffer array is created and  stored in <code>buf</code>.
+     *
+     * @param   in   the underlying input stream.
+     */
+    public BufferedInputStream(InputStream in) {
+        this(in, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Creates a <code>BufferedInputStream</code>
+     * with the specified buffer size,
+     * and saves its  argument, the input stream
+     * <code>in</code>, for later use.  An internal
+     * buffer array of length  <code>size</code>
+     * is created and stored in <code>buf</code>.
+     *
+     * @param   in     the underlying input stream.
+     * @param   size   the buffer size.
+     * @exception IllegalArgumentException if {@code size <= 0}.
+     */
+    public BufferedInputStream(InputStream in, int size) {
+        super(in);
+        if (size <= 0) {
+            throw new IllegalArgumentException("Buffer size <= 0");
+        }
+        buf = new byte[size];
+    }
+
+    /**
+     * Fills the buffer with more data, taking into account
+     * shuffling and other tricks for dealing with marks.
+     * Assumes that it is being called by a synchronized method.
+     * This method also assumes that all data has already been read in,
+     * hence pos > count.
+     */
+    private void fill() throws IOException {
+        byte[] buffer = getBufIfOpen();
+        if (markpos < 0)
+            pos = 0;            /* no mark: throw away the buffer */
+        else if (pos >= buffer.length)  /* no room left in buffer */
+            if (markpos > 0) {  /* can throw away early part of the buffer */
+                int sz = pos - markpos;
+                System.arraycopy(buffer, markpos, buffer, 0, sz);
+                pos = sz;
+                markpos = 0;
+            } else if (buffer.length >= marklimit) {
+                markpos = -1;   /* buffer got too big, invalidate mark */
+                pos = 0;        /* drop buffer contents */
+            } else if (buffer.length >= MAX_BUFFER_SIZE) {
+                throw new OutOfMemoryError("Required array size too large");
+            } else {            /* grow buffer */
+                int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
+                        pos * 2 : MAX_BUFFER_SIZE;
+                if (nsz > marklimit)
+                    nsz = marklimit;
+                byte nbuf[] = new byte[nsz];
+                System.arraycopy(buffer, 0, nbuf, 0, pos);
+                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
+                    // Can't replace buf if there was an async close.
+                    // Note: This would need to be changed if fill()
+                    // is ever made accessible to multiple threads.
+                    // But for now, the only way CAS can fail is via close.
+                    // assert buf == null;
+                    throw new IOException("Stream closed");
+                }
+                buffer = nbuf;
+            }
+        count = pos;
+        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
+        if (n > 0)
+            count = n + pos;
+    }
+
+    /**
+     * See
+     * the general contract of the <code>read</code>
+     * method of <code>InputStream</code>.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if this input stream has been closed by
+     *                          invoking its {@link #close()} method,
+     *                          or an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public synchronized int read() throws IOException {
+        if (pos >= count) {
+            fill();
+            if (pos >= count)
+                return -1;
+        }
+        return getBufIfOpen()[pos++] & 0xff;
+    }
+
+    /**
+     * Read characters into a portion of an array, reading from the underlying
+     * stream at most once if necessary.
+     */
+    private int read1(byte[] b, int off, int len) throws IOException {
+        int avail = count - pos;
+        if (avail <= 0) {
+            /* If the requested length is at least as large as the buffer, and
+               if there is no mark/reset activity, do not bother to copy the
+               bytes into the local buffer.  In this way buffered streams will
+               cascade harmlessly. */
+            if (len >= getBufIfOpen().length && markpos < 0) {
+                return getInIfOpen().read(b, off, len);
+            }
+            fill();
+            avail = count - pos;
+            if (avail <= 0) return -1;
+        }
+        int cnt = (avail < len) ? avail : len;
+        System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
+        pos += cnt;
+        return cnt;
+    }
+
+    /**
+     * Reads bytes from this byte-input stream into the specified byte array,
+     * starting at the given offset.
+     *
+     * <p> This method implements the general contract of the corresponding
+     * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
+     * the <code>{@link InputStream}</code> class.  As an additional
+     * convenience, it attempts to read as many bytes as possible by repeatedly
+     * invoking the <code>read</code> method of the underlying stream.  This
+     * iterated <code>read</code> continues until one of the following
+     * conditions becomes true: <ul>
+     *
+     *   <li> The specified number of bytes have been read,
+     *
+     *   <li> The <code>read</code> method of the underlying stream returns
+     *   <code>-1</code>, indicating end-of-file, or
+     *
+     *   <li> The <code>available</code> method of the underlying stream
+     *   returns zero, indicating that further input requests would block.
+     *
+     * </ul> If the first <code>read</code> on the underlying stream returns
+     * <code>-1</code> to indicate end-of-file then this method returns
+     * <code>-1</code>.  Otherwise this method returns the number of bytes
+     * actually read.
+     *
+     * <p> Subclasses of this class are encouraged, but not required, to
+     * attempt to read as many bytes as possible in the same fashion.
+     *
+     * @param      b     destination buffer.
+     * @param      off   offset at which to start storing bytes.
+     * @param      len   maximum number of bytes to read.
+     * @return     the number of bytes read, or <code>-1</code> if the end of
+     *             the stream has been reached.
+     * @exception  IOException  if this input stream has been closed by
+     *                          invoking its {@link #close()} method,
+     *                          or an I/O error occurs.
+     */
+    public synchronized int read(byte b[], int off, int len)
+        throws IOException
+    {
+        getBufIfOpen(); // Check for closed stream
+        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int n = 0;
+        for (;;) {
+            int nread = read1(b, off + n, len - n);
+            if (nread <= 0)
+                return (n == 0) ? nread : n;
+            n += nread;
+            if (n >= len)
+                return n;
+            // if not closed but no bytes available, return
+            InputStream input = in;
+            if (input != null && input.available() <= 0)
+                return n;
+        }
+    }
+
+    /**
+     * See the general contract of the <code>skip</code>
+     * method of <code>InputStream</code>.
+     *
+     * @exception  IOException  if the stream does not support seek,
+     *                          or if this input stream has been closed by
+     *                          invoking its {@link #close()} method, or an
+     *                          I/O error occurs.
+     */
+    public synchronized long skip(long n) throws IOException {
+        getBufIfOpen(); // Check for closed stream
+        if (n <= 0) {
+            return 0;
+        }
+        long avail = count - pos;
+
+        if (avail <= 0) {
+            // If no mark position set then don't keep in buffer
+            if (markpos <0)
+                return getInIfOpen().skip(n);
+
+            // Fill in buffer to save bytes for reset
+            fill();
+            avail = count - pos;
+            if (avail <= 0)
+                return 0;
+        }
+
+        long skipped = (avail < n) ? avail : n;
+        pos += skipped;
+        return skipped;
+    }
+
+    /**
+     * Returns an estimate of the number of bytes that can be read (or
+     * skipped over) from this input stream without blocking by the next
+     * invocation of a method for this input stream. The next invocation might be
+     * the same thread or another thread.  A single read or skip of this
+     * many bytes will not block, but may read or skip fewer bytes.
+     * <p>
+     * This method returns the sum of the number of bytes remaining to be read in
+     * the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
+     * {@link java.io.FilterInputStream#in in}.available().
+     *
+     * @return     an estimate of the number of bytes that can be read (or skipped
+     *             over) from this input stream without blocking.
+     * @exception  IOException  if this input stream has been closed by
+     *                          invoking its {@link #close()} method,
+     *                          or an I/O error occurs.
+     */
+    public synchronized int available() throws IOException {
+        int n = count - pos;
+        int avail = getInIfOpen().available();
+        return n > (Integer.MAX_VALUE - avail)
+                    ? Integer.MAX_VALUE
+                    : n + avail;
+    }
+
+    /**
+     * See the general contract of the <code>mark</code>
+     * method of <code>InputStream</code>.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.BufferedInputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {
+        marklimit = readlimit;
+        markpos = pos;
+    }
+
+    /**
+     * See the general contract of the <code>reset</code>
+     * method of <code>InputStream</code>.
+     * <p>
+     * If <code>markpos</code> is <code>-1</code>
+     * (no mark has been set or the mark has been
+     * invalidated), an <code>IOException</code>
+     * is thrown. Otherwise, <code>pos</code> is
+     * set equal to <code>markpos</code>.
+     *
+     * @exception  IOException  if this stream has not been marked or,
+     *                  if the mark has been invalidated, or the stream
+     *                  has been closed by invoking its {@link #close()}
+     *                  method, or an I/O error occurs.
+     * @see        java.io.BufferedInputStream#mark(int)
+     */
+    public synchronized void reset() throws IOException {
+        getBufIfOpen(); // Cause exception if closed
+        if (markpos < 0)
+            throw new IOException("Resetting to invalid mark");
+        pos = markpos;
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code>
+     * and <code>reset</code> methods. The <code>markSupported</code>
+     * method of <code>BufferedInputStream</code> returns
+     * <code>true</code>.
+     *
+     * @return  a <code>boolean</code> indicating if this stream type supports
+     *          the <code>mark</code> and <code>reset</code> methods.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * Once the stream has been closed, further read(), available(), reset(),
+     * or skip() invocations will throw an IOException.
+     * Closing a previously closed stream has no effect.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close() throws IOException {
+        byte[] buffer;
+        while ( (buffer = buf) != null) {
+            if (bufUpdater.compareAndSet(this, buffer, null)) {
+                InputStream input = in;
+                in = null;
+                if (input != null)
+                    input.close();
+                return;
+            }
+            // Else retry in case a new buf was CASed in fill()
+        }
+    }
+}
diff --git a/java/io/BufferedOutputStream.java b/java/io/BufferedOutputStream.java
new file mode 100644
index 0000000..0579704
--- /dev/null
+++ b/java/io/BufferedOutputStream.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1994, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * The class implements a buffered output stream. By setting up such
+ * an output stream, an application can write bytes to the underlying
+ * output stream without necessarily causing a call to the underlying
+ * system for each byte written.
+ *
+ * @author  Arthur van Hoff
+ * @since   JDK1.0
+ */
+public
+class BufferedOutputStream extends FilterOutputStream {
+    /**
+     * The internal buffer where data is stored.
+     */
+    protected byte buf[];
+
+    /**
+     * The number of valid bytes in the buffer. This value is always
+     * in the range <tt>0</tt> through <tt>buf.length</tt>; elements
+     * <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid
+     * byte data.
+     */
+    protected int count;
+
+    /**
+     * Creates a new buffered output stream to write data to the
+     * specified underlying output stream.
+     *
+     * @param   out   the underlying output stream.
+     */
+    public BufferedOutputStream(OutputStream out) {
+        this(out, 8192);
+    }
+
+    /**
+     * Creates a new buffered output stream to write data to the
+     * specified underlying output stream with the specified buffer
+     * size.
+     *
+     * @param   out    the underlying output stream.
+     * @param   size   the buffer size.
+     * @exception IllegalArgumentException if size &lt;= 0.
+     */
+    public BufferedOutputStream(OutputStream out, int size) {
+        super(out);
+        if (size <= 0) {
+            throw new IllegalArgumentException("Buffer size <= 0");
+        }
+        buf = new byte[size];
+    }
+
+    /** Flush the internal buffer */
+    private void flushBuffer() throws IOException {
+        if (count > 0) {
+            out.write(buf, 0, count);
+            count = 0;
+        }
+    }
+
+    /**
+     * Writes the specified byte to this buffered output stream.
+     *
+     * @param      b   the byte to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public synchronized void write(int b) throws IOException {
+        if (count >= buf.length) {
+            flushBuffer();
+        }
+        buf[count++] = (byte)b;
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to this buffered output stream.
+     *
+     * <p> Ordinarily this method stores bytes from the given array into this
+     * stream's buffer, flushing the buffer to the underlying output stream as
+     * needed.  If the requested length is at least as large as this stream's
+     * buffer, however, then this method will flush the buffer and write the
+     * bytes directly to the underlying output stream.  Thus redundant
+     * <code>BufferedOutputStream</code>s will not copy data unnecessarily.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public synchronized void write(byte b[], int off, int len) throws IOException {
+        if (len >= buf.length) {
+            /* If the request length exceeds the size of the output buffer,
+               flush the output buffer and then write the data directly.
+               In this way buffered streams will cascade harmlessly. */
+            flushBuffer();
+            out.write(b, off, len);
+            return;
+        }
+        if (len > buf.length - count) {
+            flushBuffer();
+        }
+        System.arraycopy(b, off, buf, count, len);
+        count += len;
+    }
+
+    /**
+     * Flushes this buffered output stream. This forces any buffered
+     * output bytes to be written out to the underlying output stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public synchronized void flush() throws IOException {
+        flushBuffer();
+        out.flush();
+    }
+}
diff --git a/java/io/BufferedReader.java b/java/io/BufferedReader.java
new file mode 100644
index 0000000..fb814b1
--- /dev/null
+++ b/java/io/BufferedReader.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * Reads text from a character-input stream, buffering characters so as to
+ * provide for the efficient reading of characters, arrays, and lines.
+ *
+ * <p> The buffer size may be specified, or the default size may be used.  The
+ * default is large enough for most purposes.
+ *
+ * <p> In general, each read request made of a Reader causes a corresponding
+ * read request to be made of the underlying character or byte stream.  It is
+ * therefore advisable to wrap a BufferedReader around any Reader whose read()
+ * operations may be costly, such as FileReaders and InputStreamReaders.  For
+ * example,
+ *
+ * <pre>
+ * BufferedReader in
+ *   = new BufferedReader(new FileReader("foo.in"));
+ * </pre>
+ *
+ * will buffer the input from the specified file.  Without buffering, each
+ * invocation of read() or readLine() could cause bytes to be read from the
+ * file, converted into characters, and then returned, which can be very
+ * inefficient.
+ *
+ * <p> Programs that use DataInputStreams for textual input can be localized by
+ * replacing each DataInputStream with an appropriate BufferedReader.
+ *
+ * @see FileReader
+ * @see InputStreamReader
+ * @see java.nio.file.Files#newBufferedReader
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class BufferedReader extends Reader {
+
+    private Reader in;
+
+    private char cb[];
+    private int nChars, nextChar;
+
+    private static final int INVALIDATED = -2;
+    private static final int UNMARKED = -1;
+    private int markedChar = UNMARKED;
+    private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
+
+    /** If the next character is a line feed, skip it */
+    private boolean skipLF = false;
+
+    /** The skipLF flag when the mark was set */
+    private boolean markedSkipLF = false;
+
+    private static int defaultCharBufferSize = 8192;
+    private static int defaultExpectedLineLength = 80;
+
+    /**
+     * Creates a buffering character-input stream that uses an input buffer of
+     * the specified size.
+     *
+     * @param  in   A Reader
+     * @param  sz   Input-buffer size
+     *
+     * @exception  IllegalArgumentException  If {@code sz <= 0}
+     */
+    public BufferedReader(Reader in, int sz) {
+        super(in);
+        if (sz <= 0)
+            throw new IllegalArgumentException("Buffer size <= 0");
+        this.in = in;
+        cb = new char[sz];
+        nextChar = nChars = 0;
+    }
+
+    /**
+     * Creates a buffering character-input stream that uses a default-sized
+     * input buffer.
+     *
+     * @param  in   A Reader
+     */
+    public BufferedReader(Reader in) {
+        this(in, defaultCharBufferSize);
+    }
+
+    /** Checks to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (in == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Fills the input buffer, taking the mark into account if it is valid.
+     */
+    private void fill() throws IOException {
+        int dst;
+        if (markedChar <= UNMARKED) {
+            /* No mark */
+            dst = 0;
+        } else {
+            /* Marked */
+            int delta = nextChar - markedChar;
+            if (delta >= readAheadLimit) {
+                /* Gone past read-ahead limit: Invalidate mark */
+                markedChar = INVALIDATED;
+                readAheadLimit = 0;
+                dst = 0;
+            } else {
+                if (readAheadLimit <= cb.length) {
+                    /* Shuffle in the current buffer */
+                    System.arraycopy(cb, markedChar, cb, 0, delta);
+                    markedChar = 0;
+                    dst = delta;
+                } else {
+                    /* Reallocate buffer to accommodate read-ahead limit */
+                    //
+                    // Android-changed: Use the same strategy as BufferedInputStream,
+                    // i.e, double the size of the buffer on each fill. Do not directly
+                    // size the buffer to the readAheadLimit.
+                    //
+                    // char ncb[] = new char[readAheadLimit];
+                    int nlength = cb.length * 2;
+                    if (nlength > readAheadLimit) {
+                        nlength = readAheadLimit;
+                    }
+                    char ncb[] = new char[nlength];
+                    System.arraycopy(cb, markedChar, ncb, 0, delta);
+                    cb = ncb;
+                    markedChar = 0;
+                    dst = delta;
+                }
+                nextChar = nChars = delta;
+            }
+        }
+
+        int n;
+        do {
+            n = in.read(cb, dst, cb.length - dst);
+        } while (n == 0);
+        if (n > 0) {
+            nChars = dst + n;
+            nextChar = dst;
+        }
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @return The character read, as an integer in the range
+     *         0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
+     *         end of the stream has been reached
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            for (;;) {
+                if (nextChar >= nChars) {
+                    fill();
+                    if (nextChar >= nChars)
+                        return -1;
+                }
+                if (skipLF) {
+                    skipLF = false;
+                    if (cb[nextChar] == '\n') {
+                        nextChar++;
+                        continue;
+                    }
+                }
+                return cb[nextChar++];
+            }
+        }
+    }
+
+    /**
+     * Reads characters into a portion of an array, reading from the underlying
+     * stream if necessary.
+     */
+    private int read1(char[] cbuf, int off, int len) throws IOException {
+        if (nextChar >= nChars) {
+            /* If the requested length is at least as large as the buffer, and
+               if there is no mark/reset activity, and if line feeds are not
+               being skipped, do not bother to copy the characters into the
+               local buffer.  In this way buffered streams will cascade
+               harmlessly. */
+            if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
+                return in.read(cbuf, off, len);
+            }
+            fill();
+        }
+        if (nextChar >= nChars) return -1;
+        if (skipLF) {
+            skipLF = false;
+            if (cb[nextChar] == '\n') {
+                nextChar++;
+                if (nextChar >= nChars)
+                    fill();
+                if (nextChar >= nChars)
+                    return -1;
+            }
+        }
+        int n = Math.min(len, nChars - nextChar);
+        System.arraycopy(cb, nextChar, cbuf, off, n);
+        nextChar += n;
+        return n;
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * <p> This method implements the general contract of the corresponding
+     * <code>{@link Reader#read(char[], int, int) read}</code> method of the
+     * <code>{@link Reader}</code> class.  As an additional convenience, it
+     * attempts to read as many characters as possible by repeatedly invoking
+     * the <code>read</code> method of the underlying stream.  This iterated
+     * <code>read</code> continues until one of the following conditions becomes
+     * true: <ul>
+     *
+     *   <li> The specified number of characters have been read,
+     *
+     *   <li> The <code>read</code> method of the underlying stream returns
+     *   <code>-1</code>, indicating end-of-file, or
+     *
+     *   <li> The <code>ready</code> method of the underlying stream
+     *   returns <code>false</code>, indicating that further input requests
+     *   would block.
+     *
+     * </ul> If the first <code>read</code> on the underlying stream returns
+     * <code>-1</code> to indicate end-of-file then this method returns
+     * <code>-1</code>.  Otherwise this method returns the number of characters
+     * actually read.
+     *
+     * <p> Subclasses of this class are encouraged, but not required, to
+     * attempt to read as many characters as possible in the same fashion.
+     *
+     * <p> Ordinarily this method takes characters from this stream's character
+     * buffer, filling it from the underlying stream as necessary.  If,
+     * however, the buffer is empty, the mark is not valid, and the requested
+     * length is at least as large as the buffer, then this method will read
+     * characters directly from the underlying stream into the given array.
+     * Thus redundant <code>BufferedReader</code>s will not copy data
+     * unnecessarily.
+     *
+     * @param      cbuf  Destination buffer
+     * @param      off   Offset at which to start storing characters
+     * @param      len   Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                ((off + len) > cbuf.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return 0;
+            }
+
+            int n = read1(cbuf, off, len);
+            if (n <= 0) return n;
+            while ((n < len) && in.ready()) {
+                int n1 = read1(cbuf, off + n, len - n);
+                if (n1 <= 0) break;
+                n += n1;
+            }
+            return n;
+        }
+    }
+
+    /**
+     * Reads a line of text.  A line is considered to be terminated by any one
+     * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
+     * followed immediately by a linefeed.
+     *
+     * @param      ignoreLF  If true, the next '\n' will be skipped
+     *
+     * @return     A String containing the contents of the line, not including
+     *             any line-termination characters, or null if the end of the
+     *             stream has been reached
+     *
+     * @see        java.io.LineNumberReader#readLine()
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    String readLine(boolean ignoreLF) throws IOException {
+        StringBuffer s = null;
+        int startChar;
+
+        synchronized (lock) {
+            ensureOpen();
+            boolean omitLF = ignoreLF || skipLF;
+
+        bufferLoop:
+            for (;;) {
+
+                if (nextChar >= nChars)
+                    fill();
+                if (nextChar >= nChars) { /* EOF */
+                    if (s != null && s.length() > 0)
+                        return s.toString();
+                    else
+                        return null;
+                }
+                boolean eol = false;
+                char c = 0;
+                int i;
+
+                /* Skip a leftover '\n', if necessary */
+                if (omitLF && (cb[nextChar] == '\n'))
+                    nextChar++;
+                skipLF = false;
+                omitLF = false;
+
+            charLoop:
+                for (i = nextChar; i < nChars; i++) {
+                    c = cb[i];
+                    if ((c == '\n') || (c == '\r')) {
+                        eol = true;
+                        break charLoop;
+                    }
+                }
+
+                startChar = nextChar;
+                nextChar = i;
+
+                if (eol) {
+                    String str;
+                    if (s == null) {
+                        str = new String(cb, startChar, i - startChar);
+                    } else {
+                        s.append(cb, startChar, i - startChar);
+                        str = s.toString();
+                    }
+                    nextChar++;
+                    if (c == '\r') {
+                        skipLF = true;
+                    }
+                    return str;
+                }
+
+                if (s == null)
+                    s = new StringBuffer(defaultExpectedLineLength);
+                s.append(cb, startChar, i - startChar);
+            }
+        }
+    }
+
+    /**
+     * Reads a line of text.  A line is considered to be terminated by any one
+     * of a line feed ('\n'), a carriage return ('\r'), or a carriage return
+     * followed immediately by a linefeed.
+     *
+     * @return     A String containing the contents of the line, not including
+     *             any line-termination characters, or null if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     *
+     * @see java.nio.file.Files#readAllLines
+     */
+    public String readLine() throws IOException {
+        return readLine(false);
+    }
+
+    /**
+     * Skips characters.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    The number of characters actually skipped
+     *
+     * @exception  IllegalArgumentException  If <code>n</code> is negative.
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0L) {
+            throw new IllegalArgumentException("skip value is negative");
+        }
+        synchronized (lock) {
+            ensureOpen();
+            long r = n;
+            while (r > 0) {
+                if (nextChar >= nChars)
+                    fill();
+                if (nextChar >= nChars) /* EOF */
+                    break;
+                if (skipLF) {
+                    skipLF = false;
+                    if (cb[nextChar] == '\n') {
+                        nextChar++;
+                    }
+                }
+                long d = nChars - nextChar;
+                if (r <= d) {
+                    nextChar += r;
+                    r = 0;
+                    break;
+                }
+                else {
+                    r -= d;
+                    nextChar = nChars;
+                }
+            }
+            return n - r;
+        }
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.  A buffered character
+     * stream is ready if the buffer is not empty, or if the underlying
+     * character stream is ready.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+
+            /*
+             * If newline needs to be skipped and the next char to be read
+             * is a newline character, then just skip it right away.
+             */
+            if (skipLF) {
+                /* Note that in.ready() will return true if and only if the next
+                 * read on the stream will not block.
+                 */
+                if (nextChar >= nChars && in.ready()) {
+                    fill();
+                }
+                if (nextChar < nChars) {
+                    if (cb[nextChar] == '\n')
+                        nextChar++;
+                    skipLF = false;
+                }
+            }
+            return (nextChar < nChars) || in.ready();
+        }
+    }
+
+    /**
+     * Tells whether this stream supports the mark() operation, which it does.
+     */
+    public boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * Marks the present position in the stream.  Subsequent calls to reset()
+     * will attempt to reposition the stream to this point.
+     *
+     * @param readAheadLimit   Limit on the number of characters that may be
+     *                         read while still preserving the mark. An attempt
+     *                         to reset the stream after reading characters
+     *                         up to this limit or beyond may fail.
+     *                         A limit value larger than the size of the input
+     *                         buffer will cause a new buffer to be allocated
+     *                         whose size is no smaller than limit.
+     *                         Therefore large values should be used with care.
+     *
+     * @exception  IllegalArgumentException  If {@code readAheadLimit < 0}
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        if (readAheadLimit < 0) {
+            throw new IllegalArgumentException("Read-ahead limit < 0");
+        }
+        synchronized (lock) {
+            ensureOpen();
+            this.readAheadLimit = readAheadLimit;
+            markedChar = nextChar;
+            markedSkipLF = skipLF;
+        }
+    }
+
+    /**
+     * Resets the stream to the most recent mark.
+     *
+     * @exception  IOException  If the stream has never been marked,
+     *                          or if the mark has been invalidated
+     */
+    public void reset() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (markedChar < 0)
+                throw new IOException((markedChar == INVALIDATED)
+                                      ? "Mark invalid"
+                                      : "Stream not marked");
+            nextChar = markedChar;
+            skipLF = markedSkipLF;
+        }
+    }
+
+    public void close() throws IOException {
+        synchronized (lock) {
+            if (in == null)
+                return;
+            try {
+                in.close();
+            } finally {
+                in = null;
+                cb = null;
+            }
+        }
+    }
+
+    /**
+     * Returns a {@code Stream}, the elements of which are lines read from
+     * this {@code BufferedReader}.  The {@link Stream} is lazily populated,
+     * i.e., read only occurs during the
+     * <a href="../util/stream/package-summary.html#StreamOps">terminal
+     * stream operation</a>.
+     *
+     * <p> The reader must not be operated on during the execution of the
+     * terminal stream operation. Otherwise, the result of the terminal stream
+     * operation is undefined.
+     *
+     * <p> After execution of the terminal stream operation there are no
+     * guarantees that the reader will be at a specific position from which to
+     * read the next character or line.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the underlying
+     * {@code BufferedReader}, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the {@code Stream}
+     * method that caused the read to take place. This method will return a
+     * Stream if invoked on a BufferedReader that is closed. Any operation on
+     * that stream that requires reading from the BufferedReader after it is
+     * closed, will cause an UncheckedIOException to be thrown.
+     *
+     * @return a {@code Stream<String>} providing the lines of text
+     *         described by this {@code BufferedReader}
+     *
+     * @since 1.8
+     */
+    public Stream<String> lines() {
+        Iterator<String> iter = new Iterator<String>() {
+            String nextLine = null;
+
+            @Override
+            public boolean hasNext() {
+                if (nextLine != null) {
+                    return true;
+                } else {
+                    try {
+                        nextLine = readLine();
+                        return (nextLine != null);
+                    } catch (IOException e) {
+                        throw new UncheckedIOException(e);
+                    }
+                }
+            }
+
+            @Override
+            public String next() {
+                if (nextLine != null || hasNext()) {
+                    String line = nextLine;
+                    nextLine = null;
+                    return line;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+        };
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+    }
+}
diff --git a/java/io/BufferedWriter.java b/java/io/BufferedWriter.java
new file mode 100644
index 0000000..a5d810a
--- /dev/null
+++ b/java/io/BufferedWriter.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Writes text to a character-output stream, buffering characters so as to
+ * provide for the efficient writing of single characters, arrays, and strings.
+ *
+ * <p> The buffer size may be specified, or the default size may be accepted.
+ * The default is large enough for most purposes.
+ *
+ * <p> A newLine() method is provided, which uses the platform's own notion of
+ * line separator as defined by the system property <tt>line.separator</tt>.
+ * Not all platforms use the newline character ('\n') to terminate lines.
+ * Calling this method to terminate each output line is therefore preferred to
+ * writing a newline character directly.
+ *
+ * <p> In general, a Writer sends its output immediately to the underlying
+ * character or byte stream.  Unless prompt output is required, it is advisable
+ * to wrap a BufferedWriter around any Writer whose write() operations may be
+ * costly, such as FileWriters and OutputStreamWriters.  For example,
+ *
+ * <pre>
+ * PrintWriter out
+ *   = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
+ * </pre>
+ *
+ * will buffer the PrintWriter's output to the file.  Without buffering, each
+ * invocation of a print() method would cause characters to be converted into
+ * bytes that would then be written immediately to the file, which can be very
+ * inefficient.
+ *
+ * @see PrintWriter
+ * @see FileWriter
+ * @see OutputStreamWriter
+ * @see java.nio.file.Files#newBufferedWriter
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class BufferedWriter extends Writer {
+
+    private Writer out;
+
+    private char cb[];
+    private int nChars, nextChar;
+
+    private static int defaultCharBufferSize = 8192;
+
+    /**
+     * Line separator string.  This is the value of the line.separator
+     * property at the moment that the stream was created.
+     */
+    private String lineSeparator;
+
+    /**
+     * Creates a buffered character-output stream that uses a default-sized
+     * output buffer.
+     *
+     * @param  out  A Writer
+     */
+    public BufferedWriter(Writer out) {
+        this(out, defaultCharBufferSize);
+    }
+
+    /**
+     * Creates a new buffered character-output stream that uses an output
+     * buffer of the given size.
+     *
+     * @param  out  A Writer
+     * @param  sz   Output-buffer size, a positive integer
+     *
+     * @exception  IllegalArgumentException  If {@code sz <= 0}
+     */
+    public BufferedWriter(Writer out, int sz) {
+        super(out);
+        if (sz <= 0)
+            throw new IllegalArgumentException("Buffer size <= 0");
+        this.out = out;
+        cb = new char[sz];
+        nChars = sz;
+        nextChar = 0;
+
+        lineSeparator = java.security.AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction("line.separator"));
+    }
+
+    /** Checks to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (out == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Flushes the output buffer to the underlying character stream, without
+     * flushing the stream itself.  This method is non-private only so that it
+     * may be invoked by PrintStream.
+     */
+    void flushBuffer() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (nextChar == 0)
+                return;
+            out.write(cb, 0, nextChar);
+            nextChar = 0;
+        }
+    }
+
+    /**
+     * Writes a single character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(int c) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (nextChar >= nChars)
+                flushBuffer();
+            cb[nextChar++] = (char) c;
+        }
+    }
+
+    /**
+     * Our own little min method, to avoid loading java.lang.Math if we've run
+     * out of file descriptors and we're trying to print a stack trace.
+     */
+    private int min(int a, int b) {
+        if (a < b) return a;
+        return b;
+    }
+
+    /**
+     * Writes a portion of an array of characters.
+     *
+     * <p> Ordinarily this method stores characters from the given array into
+     * this stream's buffer, flushing the buffer to the underlying stream as
+     * needed.  If the requested length is at least as large as the buffer,
+     * however, then this method will flush the buffer and write the characters
+     * directly to the underlying stream.  Thus redundant
+     * <code>BufferedWriter</code>s will not copy data unnecessarily.
+     *
+     * @param  cbuf  A character array
+     * @param  off   Offset from which to start reading characters
+     * @param  len   Number of characters to write
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(char cbuf[], int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                ((off + len) > cbuf.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return;
+            }
+
+            if (len >= nChars) {
+                /* If the request length exceeds the size of the output buffer,
+                   flush the buffer and then write the data directly.  In this
+                   way buffered streams will cascade harmlessly. */
+                flushBuffer();
+                out.write(cbuf, off, len);
+                return;
+            }
+
+            int b = off, t = off + len;
+            while (b < t) {
+                int d = min(nChars - nextChar, t - b);
+                System.arraycopy(cbuf, b, cb, nextChar, d);
+                b += d;
+                nextChar += d;
+                if (nextChar >= nChars)
+                    flushBuffer();
+            }
+        }
+    }
+
+    /**
+     * Writes a portion of a String.
+     *
+     * <p> If the value of the <tt>len</tt> parameter is negative then no
+     * characters are written.  This is contrary to the specification of this
+     * method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
+     * superclass}, which requires that an {@link IndexOutOfBoundsException} be
+     * thrown.
+     *
+     * @param  s     String to be written
+     * @param  off   Offset from which to start reading characters
+     * @param  len   Number of characters to be written
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(String s, int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+
+            int b = off, t = off + len;
+            while (b < t) {
+                int d = min(nChars - nextChar, t - b);
+                s.getChars(b, b + d, cb, nextChar);
+                b += d;
+                nextChar += d;
+                if (nextChar >= nChars)
+                    flushBuffer();
+            }
+        }
+    }
+
+    /**
+     * Writes a line separator.  The line separator string is defined by the
+     * system property <tt>line.separator</tt>, and is not necessarily a single
+     * newline ('\n') character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void newLine() throws IOException {
+        write(lineSeparator);
+    }
+
+    /**
+     * Flushes the stream.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void flush() throws IOException {
+        synchronized (lock) {
+            flushBuffer();
+            out.flush();
+        }
+    }
+
+    @SuppressWarnings("try")
+    public void close() throws IOException {
+        synchronized (lock) {
+            if (out == null) {
+                return;
+            }
+            try (Writer w = out) {
+                flushBuffer();
+            } finally {
+                out = null;
+                cb = null;
+            }
+        }
+    }
+}
diff --git a/java/io/ByteArrayInputStream.java b/java/io/ByteArrayInputStream.java
new file mode 100644
index 0000000..d07f074
--- /dev/null
+++ b/java/io/ByteArrayInputStream.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A <code>ByteArrayInputStream</code> contains
+ * an internal buffer that contains bytes that
+ * may be read from the stream. An internal
+ * counter keeps track of the next byte to
+ * be supplied by the <code>read</code> method.
+ * <p>
+ * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.io.StringBufferInputStream
+ * @since   JDK1.0
+ */
+public
+class ByteArrayInputStream extends InputStream {
+
+    /**
+     * An array of bytes that was provided
+     * by the creator of the stream. Elements <code>buf[0]</code>
+     * through <code>buf[count-1]</code> are the
+     * only bytes that can ever be read from the
+     * stream;  element <code>buf[pos]</code> is
+     * the next byte to be read.
+     */
+    protected byte buf[];
+
+    /**
+     * The index of the next character to read from the input stream buffer.
+     * This value should always be nonnegative
+     * and not larger than the value of <code>count</code>.
+     * The next byte to be read from the input stream buffer
+     * will be <code>buf[pos]</code>.
+     */
+    protected int pos;
+
+    /**
+     * The currently marked position in the stream.
+     * ByteArrayInputStream objects are marked at position zero by
+     * default when constructed.  They may be marked at another
+     * position within the buffer by the <code>mark()</code> method.
+     * The current buffer position is set to this point by the
+     * <code>reset()</code> method.
+     * <p>
+     * If no mark has been set, then the value of mark is the offset
+     * passed to the constructor (or 0 if the offset was not supplied).
+     *
+     * @since   JDK1.1
+     */
+    protected int mark = 0;
+
+    /**
+     * The index one greater than the last valid character in the input
+     * stream buffer.
+     * This value should always be nonnegative
+     * and not larger than the length of <code>buf</code>.
+     * It  is one greater than the position of
+     * the last byte within <code>buf</code> that
+     * can ever be read  from the input stream buffer.
+     */
+    protected int count;
+
+    /**
+     * Creates a <code>ByteArrayInputStream</code>
+     * so that it  uses <code>buf</code> as its
+     * buffer array.
+     * The buffer array is not copied.
+     * The initial value of <code>pos</code>
+     * is <code>0</code> and the initial value
+     * of  <code>count</code> is the length of
+     * <code>buf</code>.
+     *
+     * @param   buf   the input buffer.
+     */
+    public ByteArrayInputStream(byte buf[]) {
+        this.buf = buf;
+        this.pos = 0;
+        this.count = buf.length;
+    }
+
+    /**
+     * Creates <code>ByteArrayInputStream</code>
+     * that uses <code>buf</code> as its
+     * buffer array. The initial value of <code>pos</code>
+     * is <code>offset</code> and the initial value
+     * of <code>count</code> is the minimum of <code>offset+length</code>
+     * and <code>buf.length</code>.
+     * The buffer array is not copied. The buffer's mark is
+     * set to the specified offset.
+     *
+     * @param   buf      the input buffer.
+     * @param   offset   the offset in the buffer of the first byte to read.
+     * @param   length   the maximum number of bytes to read from the buffer.
+     */
+    public ByteArrayInputStream(byte buf[], int offset, int length) {
+        this.buf = buf;
+        this.pos = offset;
+        this.count = Math.min(offset + length, buf.length);
+        this.mark = offset;
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The value
+     * byte is returned as an <code>int</code> in the range
+     * <code>0</code> to <code>255</code>. If no byte is available
+     * because the end of the stream has been reached, the value
+     * <code>-1</code> is returned.
+     * <p>
+     * This <code>read</code> method
+     * cannot block.
+     *
+     * @return  the next byte of data, or <code>-1</code> if the end of the
+     *          stream has been reached.
+     */
+    public synchronized int read() {
+        return (pos < count) ? (buf[pos++] & 0xff) : -1;
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data into an array of bytes
+     * from this input stream.
+     * If <code>pos</code> equals <code>count</code>,
+     * then <code>-1</code> is returned to indicate
+     * end of file. Otherwise, the  number <code>k</code>
+     * of bytes read is equal to the smaller of
+     * <code>len</code> and <code>count-pos</code>.
+     * If <code>k</code> is positive, then bytes
+     * <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
+     * are copied into <code>b[off]</code>  through
+     * <code>b[off+k-1]</code> in the manner performed
+     * by <code>System.arraycopy</code>. The
+     * value <code>k</code> is added into <code>pos</code>
+     * and <code>k</code> is returned.
+     * <p>
+     * This <code>read</code> method cannot block.
+     *
+     * @param   b     the buffer into which the data is read.
+     * @param   off   the start offset in the destination array <code>b</code>
+     * @param   len   the maximum number of bytes read.
+     * @return  the total number of bytes read into the buffer, or
+     *          <code>-1</code> if there is no more data because the end of
+     *          the stream has been reached.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     */
+    public synchronized int read(byte b[], int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        if (pos >= count) {
+            return -1;
+        }
+
+        int avail = count - pos;
+        if (len > avail) {
+            len = avail;
+        }
+        if (len <= 0) {
+            return 0;
+        }
+        System.arraycopy(buf, pos, b, off, len);
+        pos += len;
+        return len;
+    }
+
+    /**
+     * Skips <code>n</code> bytes of input from this input stream. Fewer
+     * bytes might be skipped if the end of the input stream is reached.
+     * The actual number <code>k</code>
+     * of bytes to be skipped is equal to the smaller
+     * of <code>n</code> and  <code>count-pos</code>.
+     * The value <code>k</code> is added into <code>pos</code>
+     * and <code>k</code> is returned.
+     *
+     * @param   n   the number of bytes to be skipped.
+     * @return  the actual number of bytes skipped.
+     */
+    public synchronized long skip(long n) {
+        long k = count - pos;
+        if (n < k) {
+            k = n < 0 ? 0 : n;
+        }
+
+        pos += k;
+        return k;
+    }
+
+    /**
+     * Returns the number of remaining bytes that can be read (or skipped over)
+     * from this input stream.
+     * <p>
+     * The value returned is <code>count&nbsp;- pos</code>,
+     * which is the number of bytes remaining to be read from the input buffer.
+     *
+     * @return  the number of remaining bytes that can be read (or skipped
+     *          over) from this input stream without blocking.
+     */
+    public synchronized int available() {
+        return count - pos;
+    }
+
+    /**
+     * Tests if this <code>InputStream</code> supports mark/reset. The
+     * <code>markSupported</code> method of <code>ByteArrayInputStream</code>
+     * always returns <code>true</code>.
+     *
+     * @since   JDK1.1
+     */
+    public boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * Set the current marked position in the stream.
+     * ByteArrayInputStream objects are marked at position zero by
+     * default when constructed.  They may be marked at another
+     * position within the buffer by this method.
+     * <p>
+     * If no mark has been set, then the value of the mark is the
+     * offset passed to the constructor (or 0 if the offset was not
+     * supplied).
+     *
+     * <p> Note: The <code>readAheadLimit</code> for this class
+     *  has no meaning.
+     *
+     * @since   JDK1.1
+     */
+    public void mark(int readAheadLimit) {
+        mark = pos;
+    }
+
+    /**
+     * Resets the buffer to the marked position.  The marked position
+     * is 0 unless another position was marked or an offset was specified
+     * in the constructor.
+     */
+    public synchronized void reset() {
+        pos = mark;
+    }
+
+    /**
+     * Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
+     * this class can be called after the stream has been closed without
+     * generating an <tt>IOException</tt>.
+     */
+    public void close() throws IOException {
+    }
+
+}
diff --git a/java/io/ByteArrayOutputStream.annotated.java b/java/io/ByteArrayOutputStream.annotated.java
new file mode 100644
index 0000000..3fdca11
--- /dev/null
+++ b/java/io/ByteArrayOutputStream.annotated.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ByteArrayOutputStream extends java.io.OutputStream {
+
+public ByteArrayOutputStream() { throw new RuntimeException("Stub!"); }
+
+public ByteArrayOutputStream(int size) { throw new RuntimeException("Stub!"); }
+
+public synchronized void write(int b) { throw new RuntimeException("Stub!"); }
+
+public synchronized void write(byte @libcore.util.NonNull [] b, int off, int len) { throw new RuntimeException("Stub!"); }
+
+public synchronized void writeTo(@libcore.util.NonNull java.io.OutputStream out) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void reset() { throw new RuntimeException("Stub!"); }
+
+public synchronized byte @libcore.util.NonNull [] toByteArray() { throw new RuntimeException("Stub!"); }
+
+public synchronized int size() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString(@libcore.util.NonNull java.lang.String charsetName) throws java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
[email protected] public synchronized java.lang.String toString(int hibyte) { throw new RuntimeException("Stub!"); }
+
+public void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+protected byte @libcore.util.NonNull [] buf;
+
+protected int count;
+}
diff --git a/java/io/ByteArrayOutputStream.java b/java/io/ByteArrayOutputStream.java
new file mode 100644
index 0000000..f1d429b
--- /dev/null
+++ b/java/io/ByteArrayOutputStream.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Arrays;
+
+/**
+ * This class implements an output stream in which the data is
+ * written into a byte array. The buffer automatically grows as data
+ * is written to it.
+ * The data can be retrieved using <code>toByteArray()</code> and
+ * <code>toString()</code>.
+ * <p>
+ * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+ * this class can be called after the stream has been closed without
+ * generating an <tt>IOException</tt>.
+ *
+ * @author  Arthur van Hoff
+ * @since   JDK1.0
+ */
+
+public class ByteArrayOutputStream extends OutputStream {
+
+    /**
+     * The buffer where data is stored.
+     */
+    protected byte buf[];
+
+    /**
+     * The number of valid bytes in the buffer.
+     */
+    protected int count;
+
+    /**
+     * Creates a new byte array output stream. The buffer capacity is
+     * initially 32 bytes, though its size increases if necessary.
+     */
+    public ByteArrayOutputStream() {
+        this(32);
+    }
+
+    /**
+     * Creates a new byte array output stream, with a buffer capacity of
+     * the specified size, in bytes.
+     *
+     * @param   size   the initial size.
+     * @exception  IllegalArgumentException if size is negative.
+     */
+    public ByteArrayOutputStream(int size) {
+        if (size < 0) {
+            throw new IllegalArgumentException("Negative initial size: "
+                                               + size);
+        }
+        buf = new byte[size];
+    }
+
+    /**
+     * Increases the capacity if necessary to ensure that it can hold
+     * at least the number of elements specified by the minimum
+     * capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     * @throws OutOfMemoryError if {@code minCapacity < 0}.  This is
+     * interpreted as a request for the unsatisfiably large capacity
+     * {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
+     */
+    private void ensureCapacity(int minCapacity) {
+        // overflow-conscious code
+        if (minCapacity - buf.length > 0)
+            grow(minCapacity);
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity to ensure that it can hold at least the
+     * number of elements specified by the minimum capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    private void grow(int minCapacity) {
+        // overflow-conscious code
+        int oldCapacity = buf.length;
+        int newCapacity = oldCapacity << 1;
+        if (newCapacity - minCapacity < 0)
+            newCapacity = minCapacity;
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        buf = Arrays.copyOf(buf, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Writes the specified byte to this byte array output stream.
+     *
+     * @param   b   the byte to be written.
+     */
+    public synchronized void write(int b) {
+        ensureCapacity(count + 1);
+        buf[count] = (byte) b;
+        count += 1;
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to this byte array output stream.
+     *
+     * @param   b     the data.
+     * @param   off   the start offset in the data.
+     * @param   len   the number of bytes to write.
+     */
+    public synchronized void write(byte b[], int off, int len) {
+        if ((off < 0) || (off > b.length) || (len < 0) ||
+            ((off + len) - b.length > 0)) {
+            throw new IndexOutOfBoundsException();
+        }
+        ensureCapacity(count + len);
+        System.arraycopy(b, off, buf, count, len);
+        count += len;
+    }
+
+    /**
+     * Writes the complete contents of this byte array output stream to
+     * the specified output stream argument, as if by calling the output
+     * stream's write method using <code>out.write(buf, 0, count)</code>.
+     *
+     * @param      out   the output stream to which to write the data.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public synchronized void writeTo(OutputStream out) throws IOException {
+        out.write(buf, 0, count);
+    }
+
+    /**
+     * Resets the <code>count</code> field of this byte array output
+     * stream to zero, so that all currently accumulated output in the
+     * output stream is discarded. The output stream can be used again,
+     * reusing the already allocated buffer space.
+     *
+     * @see     java.io.ByteArrayInputStream#count
+     */
+    public synchronized void reset() {
+        count = 0;
+    }
+
+    /**
+     * Creates a newly allocated byte array. Its size is the current
+     * size of this output stream and the valid contents of the buffer
+     * have been copied into it.
+     *
+     * @return  the current contents of this output stream, as a byte array.
+     * @see     java.io.ByteArrayOutputStream#size()
+     */
+    public synchronized byte toByteArray()[] {
+        return Arrays.copyOf(buf, count);
+    }
+
+    /**
+     * Returns the current size of the buffer.
+     *
+     * @return  the value of the <code>count</code> field, which is the number
+     *          of valid bytes in this output stream.
+     * @see     java.io.ByteArrayOutputStream#count
+     */
+    public synchronized int size() {
+        return count;
+    }
+
+    /**
+     * Converts the buffer's contents into a string decoding bytes using the
+     * platform's default character set. The length of the new <tt>String</tt>
+     * is a function of the character set, and hence may not be equal to the
+     * size of the buffer.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with the default replacement string for the platform's
+     * default character set. The {@linkplain java.nio.charset.CharsetDecoder}
+     * class should be used when more control over the decoding process is
+     * required.
+     *
+     * @return String decoded from the buffer's contents.
+     * @since  JDK1.1
+     */
+    public synchronized String toString() {
+        return new String(buf, 0, count);
+    }
+
+    /**
+     * Converts the buffer's contents into a string by decoding the bytes using
+     * the named {@link java.nio.charset.Charset charset}. The length of the new
+     * <tt>String</tt> is a function of the charset, and hence may not be equal
+     * to the length of the byte array.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with this charset's default replacement string. The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param      charsetName  the name of a supported
+     *             {@link java.nio.charset.Charset charset}
+     * @return     String decoded from the buffer's contents.
+     * @exception  UnsupportedEncodingException
+     *             If the named charset is not supported
+     * @since      JDK1.1
+     */
+    public synchronized String toString(String charsetName)
+        throws UnsupportedEncodingException
+    {
+        return new String(buf, 0, count, charsetName);
+    }
+
+    /**
+     * Creates a newly allocated string. Its size is the current size of
+     * the output stream and the valid contents of the buffer have been
+     * copied into it. Each character <i>c</i> in the resulting string is
+     * constructed from the corresponding element <i>b</i> in the byte
+     * array such that:
+     * <blockquote><pre>
+     *     c == (char)(((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
+     * </pre></blockquote>
+     *
+     * @deprecated This method does not properly convert bytes into characters.
+     * As of JDK&nbsp;1.1, the preferred way to do this is via the
+     * <code>toString(String enc)</code> method, which takes an encoding-name
+     * argument, or the <code>toString()</code> method, which uses the
+     * platform's default character encoding.
+     *
+     * @param      hibyte    the high byte of each resulting Unicode character.
+     * @return     the current contents of the output stream, as a string.
+     * @see        java.io.ByteArrayOutputStream#size()
+     * @see        java.io.ByteArrayOutputStream#toString(String)
+     * @see        java.io.ByteArrayOutputStream#toString()
+     */
+    @Deprecated
+    public synchronized String toString(int hibyte) {
+        return new String(buf, hibyte, 0, count);
+    }
+
+    /**
+     * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
+     * this class can be called after the stream has been closed without
+     * generating an <tt>IOException</tt>.
+     */
+    public void close() throws IOException {
+    }
+
+}
diff --git a/java/io/CharArrayReader.java b/java/io/CharArrayReader.java
new file mode 100644
index 0000000..4140976
--- /dev/null
+++ b/java/io/CharArrayReader.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class implements a character buffer that can be used as a
+ * character-input stream.
+ *
+ * @author      Herb Jellinek
+ * @since       JDK1.1
+ */
+public class CharArrayReader extends Reader {
+    /** The character buffer. */
+    protected char buf[];
+
+    /** The current buffer position. */
+    protected int pos;
+
+    /** The position of mark in buffer. */
+    protected int markedPos = 0;
+
+    /**
+     *  The index of the end of this buffer.  There is not valid
+     *  data at or beyond this index.
+     */
+    protected int count;
+
+    /**
+     * Creates a CharArrayReader from the specified array of chars.
+     * @param buf       Input buffer (not copied)
+     */
+    public CharArrayReader(char buf[]) {
+        this.buf = buf;
+        this.pos = 0;
+        this.count = buf.length;
+    }
+
+    /**
+     * Creates a CharArrayReader from the specified array of chars.
+     *
+     * <p> The resulting reader will start reading at the given
+     * <tt>offset</tt>.  The total number of <tt>char</tt> values that can be
+     * read from this reader will be either <tt>length</tt> or
+     * <tt>buf.length-offset</tt>, whichever is smaller.
+     *
+     * @throws IllegalArgumentException
+     *         If <tt>offset</tt> is negative or greater than
+     *         <tt>buf.length</tt>, or if <tt>length</tt> is negative, or if
+     *         the sum of these two values is negative.
+     *
+     * @param buf       Input buffer (not copied)
+     * @param offset    Offset of the first char to read
+     * @param length    Number of chars to read
+     */
+    public CharArrayReader(char buf[], int offset, int length) {
+        if ((offset < 0) || (offset > buf.length) || (length < 0) ||
+            ((offset + length) < 0)) {
+            throw new IllegalArgumentException();
+        }
+        this.buf = buf;
+        this.pos = offset;
+        this.count = Math.min(offset + length, buf.length);
+        this.markedPos = offset;
+    }
+
+    /** Checks to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (buf == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @exception   IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (pos >= count)
+                return -1;
+            else
+                return buf[pos++];
+        }
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     * @param b  Destination buffer
+     * @param off  Offset at which to start storing characters
+     * @param len   Maximum number of characters to read
+     * @return  The actual number of characters read, or -1 if
+     *          the end of the stream has been reached
+     *
+     * @exception   IOException  If an I/O error occurs
+     */
+    public int read(char b[], int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if ((off < 0) || (off > b.length) || (len < 0) ||
+                ((off + len) > b.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return 0;
+            }
+
+            if (pos >= count) {
+                return -1;
+            }
+            // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+            int avail = count - pos;
+            if (len > avail) {
+                len = avail;
+            }
+            // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+            if (len <= 0) {
+                return 0;
+            }
+            System.arraycopy(buf, pos, b, off, len);
+            pos += len;
+            return len;
+        }
+    }
+
+    /**
+     * Skips characters.  Returns the number of characters that were skipped.
+     *
+     * <p>The <code>n</code> parameter may be negative, even though the
+     * <code>skip</code> method of the {@link Reader} superclass throws
+     * an exception in this case. If <code>n</code> is negative, then
+     * this method does nothing and returns <code>0</code>.
+     *
+     * @param n The number of characters to skip
+     * @return       The number of characters actually skipped
+     * @exception  IOException If the stream is closed, or an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+            long avail = count - pos;
+            if (n > avail) {
+                n = avail;
+            }
+            // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+            if (n < 0) {
+                return 0;
+            }
+            pos += n;
+            return n;
+        }
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.  Character-array readers
+     * are always ready to be read.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            return (count - pos) > 0;
+        }
+    }
+
+    /**
+     * Tells whether this stream supports the mark() operation, which it does.
+     */
+    public boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * Marks the present position in the stream.  Subsequent calls to reset()
+     * will reposition the stream to this point.
+     *
+     * @param  readAheadLimit  Limit on the number of characters that may be
+     *                         read while still preserving the mark.  Because
+     *                         the stream's input comes from a character array,
+     *                         there is no actual limit; hence this argument is
+     *                         ignored.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            markedPos = pos;
+        }
+    }
+
+    /**
+     * Resets the stream to the most recent mark, or to the beginning if it has
+     * never been marked.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void reset() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            pos = markedPos;
+        }
+    }
+
+    /**
+     * Closes the stream and releases any system resources associated with
+     * it.  Once the stream has been closed, further read(), ready(),
+     * mark(), reset(), or skip() invocations will throw an IOException.
+     * Closing a previously closed stream has no effect.
+     */
+    public void close() {
+        buf = null;
+    }
+}
diff --git a/java/io/CharArrayWriter.java b/java/io/CharArrayWriter.java
new file mode 100644
index 0000000..56a5821
--- /dev/null
+++ b/java/io/CharArrayWriter.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Arrays;
+
+/**
+ * This class implements a character buffer that can be used as an Writer.
+ * The buffer automatically grows when data is written to the stream.  The data
+ * can be retrieved using toCharArray() and toString().
+ * <P>
+ * Note: Invoking close() on this class has no effect, and methods
+ * of this class can be called after the stream has closed
+ * without generating an IOException.
+ *
+ * @author      Herb Jellinek
+ * @since       JDK1.1
+ */
+public
+class CharArrayWriter extends Writer {
+    /**
+     * The buffer where data is stored.
+     */
+    protected char buf[];
+
+    /**
+     * The number of chars in the buffer.
+     */
+    protected int count;
+
+    /**
+     * Creates a new CharArrayWriter.
+     */
+    public CharArrayWriter() {
+        this(32);
+    }
+
+    /**
+     * Creates a new CharArrayWriter with the specified initial size.
+     *
+     * @param initialSize  an int specifying the initial buffer size.
+     * @exception IllegalArgumentException if initialSize is negative
+     */
+    public CharArrayWriter(int initialSize) {
+        if (initialSize < 0) {
+            throw new IllegalArgumentException("Negative initial size: "
+                                               + initialSize);
+        }
+        buf = new char[initialSize];
+    }
+
+    /**
+     * Writes a character to the buffer.
+     */
+    public void write(int c) {
+        synchronized (lock) {
+            int newcount = count + 1;
+            if (newcount > buf.length) {
+                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
+            }
+            buf[count] = (char)c;
+            count = newcount;
+        }
+    }
+
+    /**
+     * Writes characters to the buffer.
+     * @param c the data to be written
+     * @param off       the start offset in the data
+     * @param len       the number of chars that are written
+     */
+    public void write(char c[], int off, int len) {
+        if ((off < 0) || (off > c.length) || (len < 0) ||
+            ((off + len) > c.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        synchronized (lock) {
+            int newcount = count + len;
+            if (newcount > buf.length) {
+                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
+            }
+            System.arraycopy(c, off, buf, count, len);
+            count = newcount;
+        }
+    }
+
+    /**
+     * Write a portion of a string to the buffer.
+     * @param  str  String to be written from
+     * @param  off  Offset from which to start reading characters
+     * @param  len  Number of characters to be written
+     */
+    public void write(String str, int off, int len) {
+        synchronized (lock) {
+            int newcount = count + len;
+            if (newcount > buf.length) {
+                buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
+            }
+            str.getChars(off, off + len, buf, count);
+            count = newcount;
+        }
+    }
+
+    /**
+     * Writes the contents of the buffer to another character stream.
+     *
+     * @param out       the output stream to write to
+     * @throws IOException If an I/O error occurs.
+     */
+    public void writeTo(Writer out) throws IOException {
+        synchronized (lock) {
+            out.write(buf, 0, count);
+        }
+    }
+
+    /**
+     * Appends the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.toString()) </pre>
+     *
+     * <p> Depending on the specification of <tt>toString</tt> for the
+     * character sequence <tt>csq</tt>, the entire sequence may not be
+     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * character buffer will return a subsequence whose content depends upon
+     * the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this writer.
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public CharArrayWriter append(CharSequence csq) {
+        String s = (csq == null ? "null" : csq.toString());
+        write(s, 0, s.length());
+        return this;
+    }
+
+    /**
+     * Appends a subsequence of the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @param  start
+     *         The index of the first character in the subsequence
+     *
+     * @param  end
+     *         The index of the character following the last character in the
+     *         subsequence
+     *
+     * @return  This writer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @since  1.5
+     */
+    public CharArrayWriter append(CharSequence csq, int start, int end) {
+        String s = (csq == null ? "null" : csq).subSequence(start, end).toString();
+        write(s, 0, s.length());
+        return this;
+    }
+
+    /**
+     * Appends the specified character to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(c) </pre>
+     *
+     * @param  c
+     *         The 16-bit character to append
+     *
+     * @return  This writer
+     *
+     * @since 1.5
+     */
+    public CharArrayWriter append(char c) {
+        write(c);
+        return this;
+    }
+
+    /**
+     * Resets the buffer so that you can use it again without
+     * throwing away the already allocated buffer.
+     */
+    public void reset() {
+        count = 0;
+    }
+
+    /**
+     * Returns a copy of the input data.
+     *
+     * @return an array of chars copied from the input data.
+     */
+    public char toCharArray()[] {
+        synchronized (lock) {
+            return Arrays.copyOf(buf, count);
+        }
+    }
+
+    /**
+     * Returns the current size of the buffer.
+     *
+     * @return an int representing the current size of the buffer.
+     */
+    public int size() {
+        return count;
+    }
+
+    /**
+     * Converts input data to a string.
+     * @return the string.
+     */
+    public String toString() {
+        synchronized (lock) {
+            return new String(buf, 0, count);
+        }
+    }
+
+    /**
+     * Flush the stream.
+     */
+    public void flush() { }
+
+    /**
+     * Close the stream.  This method does not release the buffer, since its
+     * contents might still be required. Note: Invoking this method in this class
+     * will have no effect.
+     */
+    public void close() { }
+
+}
diff --git a/java/io/CharConversionException.java b/java/io/CharConversionException.java
new file mode 100644
index 0000000..ba79fe3
--- /dev/null
+++ b/java/io/CharConversionException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+/**
+ * Base class for character conversion exceptions.
+ *
+ * @author      Asmus Freytag
+ * @since       JDK1.1
+ */
+public class CharConversionException
+    extends java.io.IOException
+{
+    private static final long serialVersionUID = -8680016352018427031L;
+
+    /**
+     * This provides no detailed message.
+     */
+    public CharConversionException() {
+    }
+    /**
+     * This provides a detailed message.
+     *
+     * @param s the detailed message associated with the exception.
+     */
+    public CharConversionException(String s) {
+        super(s);
+    }
+}
diff --git a/java/io/Closeable.java b/java/io/Closeable.java
new file mode 100644
index 0000000..b4a1c81
--- /dev/null
+++ b/java/io/Closeable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.IOException;
+
+/**
+ * A {@code Closeable} is a source or destination of data that can be closed.
+ * The close method is invoked to release resources that the object is
+ * holding (such as open files).
+ *
+ * @since 1.5
+ */
+public interface Closeable extends AutoCloseable {
+
+    /**
+     * Closes this stream and releases any system resources associated
+     * with it. If the stream is already closed then invoking this
+     * method has no effect.
+     *
+     * <p> As noted in {@link AutoCloseable#close()}, cases where the
+     * close may fail require careful attention. It is strongly advised
+     * to relinquish the underlying resources and to internally
+     * <em>mark</em> the {@code Closeable} as closed, prior to throwing
+     * the {@code IOException}.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException;
+}
diff --git a/java/io/Console.java b/java/io/Console.java
new file mode 100644
index 0000000..b25759c
--- /dev/null
+++ b/java/io/Console.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.*;
+import java.nio.charset.Charset;
+import sun.nio.cs.StreamDecoder;
+import sun.nio.cs.StreamEncoder;
+
+/**
+ * Methods to access the character-based console device, if any, associated
+ * with the current Java virtual machine.
+ *
+ * <p> Whether a virtual machine has a console is dependent upon the
+ * underlying platform and also upon the manner in which the virtual
+ * machine is invoked.  If the virtual machine is started from an
+ * interactive command line without redirecting the standard input and
+ * output streams then its console will exist and will typically be
+ * connected to the keyboard and display from which the virtual machine
+ * was launched.  If the virtual machine is started automatically, for
+ * example by a background job scheduler, then it will typically not
+ * have a console.
+ * <p>
+ * If this virtual machine has a console then it is represented by a
+ * unique instance of this class which can be obtained by invoking the
+ * {@link java.lang.System#console()} method.  If no console device is
+ * available then an invocation of that method will return <tt>null</tt>.
+ * <p>
+ * Read and write operations are synchronized to guarantee the atomic
+ * completion of critical operations; therefore invoking methods
+ * {@link #readLine()}, {@link #readPassword()}, {@link #format format()},
+ * {@link #printf printf()} as well as the read, format and write operations
+ * on the objects returned by {@link #reader()} and {@link #writer()} may
+ * block in multithreaded scenarios.
+ * <p>
+ * Invoking <tt>close()</tt> on the objects returned by the {@link #reader()}
+ * and the {@link #writer()} will not close the underlying stream of those
+ * objects.
+ * <p>
+ * The console-read methods return <tt>null</tt> when the end of the
+ * console input stream is reached, for example by typing control-D on
+ * Unix or control-Z on Windows.  Subsequent read operations will succeed
+ * if additional characters are later entered on the console's input
+ * device.
+ * <p>
+ * Unless otherwise specified, passing a <tt>null</tt> argument to any method
+ * in this class will cause a {@link NullPointerException} to be thrown.
+ * <p>
+ * <b>Security note:</b>
+ * If an application needs to read a password or other secure data, it should
+ * use {@link #readPassword()} or {@link #readPassword(String, Object...)} and
+ * manually zero the returned character array after processing to minimize the
+ * lifetime of sensitive data in memory.
+ *
+ * <blockquote><pre>{@code
+ * Console cons;
+ * char[] passwd;
+ * if ((cons = System.console()) != null &&
+ *     (passwd = cons.readPassword("[%s]", "Password:")) != null) {
+ *     ...
+ *     java.util.Arrays.fill(passwd, ' ');
+ * }
+ * }</pre></blockquote>
+ *
+ * @author  Xueming Shen
+ * @since   1.6
+ */
+
+public final class Console implements Flushable
+{
+   /**
+    * Retrieves the unique {@link java.io.PrintWriter PrintWriter} object
+    * associated with this console.
+    *
+    * @return  The printwriter associated with this console
+    */
+    public PrintWriter writer() {
+        return pw;
+    }
+
+   /**
+    * Retrieves the unique {@link java.io.Reader Reader} object associated
+    * with this console.
+    * <p>
+    * This method is intended to be used by sophisticated applications, for
+    * example, a {@link java.util.Scanner} object which utilizes the rich
+    * parsing/scanning functionality provided by the <tt>Scanner</tt>:
+    * <blockquote><pre>
+    * Console con = System.console();
+    * if (con != null) {
+    *     Scanner sc = new Scanner(con.reader());
+    *     ...
+    * }
+    * </pre></blockquote>
+    * <p>
+    * For simple applications requiring only line-oriented reading, use
+    * <tt>{@link #readLine}</tt>.
+    * <p>
+    * The bulk read operations {@link java.io.Reader#read(char[]) read(char[]) },
+    * {@link java.io.Reader#read(char[], int, int) read(char[], int, int) } and
+    * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
+    * on the returned object will not read in characters beyond the line
+    * bound for each invocation, even if the destination buffer has space for
+    * more characters. The {@code Reader}'s {@code read} methods may block if a
+    * line bound has not been entered or reached on the console's input device.
+    * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
+    * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
+    * by a linefeed, or an end of stream.
+    *
+    * @return  The reader associated with this console
+    */
+    public Reader reader() {
+        return reader;
+    }
+
+   /**
+    * Writes a formatted string to this console's output stream using
+    * the specified format string and arguments.
+    *
+    * @param  fmt
+    *         A format string as described in <a
+    *         href="../util/Formatter.html#syntax">Format string syntax</a>
+    *
+    * @param  args
+    *         Arguments referenced by the format specifiers in the format
+    *         string.  If there are more arguments than format specifiers, the
+    *         extra arguments are ignored.  The number of arguments is
+    *         variable and may be zero.  The maximum number of arguments is
+    *         limited by the maximum dimension of a Java array as defined by
+    *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+    *         The behaviour on a
+    *         <tt>null</tt> argument depends on the <a
+    *         href="../util/Formatter.html#syntax">conversion</a>.
+    *
+    * @throws  IllegalFormatException
+    *          If a format string contains an illegal syntax, a format
+    *          specifier that is incompatible with the given arguments,
+    *          insufficient arguments given the format string, or other
+    *          illegal conditions.  For specification of all possible
+    *          formatting errors, see the <a
+    *          href="../util/Formatter.html#detail">Details</a> section
+    *          of the formatter class specification.
+    *
+    * @return  This console
+    */
+    public Console format(String fmt, Object ...args) {
+        formatter.format(fmt, args).flush();
+        return this;
+    }
+
+   /**
+    * A convenience method to write a formatted string to this console's
+    * output stream using the specified format string and arguments.
+    *
+    * <p> An invocation of this method of the form <tt>con.printf(format,
+    * args)</tt> behaves in exactly the same way as the invocation of
+    * <pre>con.format(format, args)</pre>.
+    *
+    * @param  format
+    *         A format string as described in <a
+    *         href="../util/Formatter.html#syntax">Format string syntax</a>.
+    *
+    * @param  args
+    *         Arguments referenced by the format specifiers in the format
+    *         string.  If there are more arguments than format specifiers, the
+    *         extra arguments are ignored.  The number of arguments is
+    *         variable and may be zero.  The maximum number of arguments is
+    *         limited by the maximum dimension of a Java array as defined by
+    *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+    *         The behaviour on a
+    *         <tt>null</tt> argument depends on the <a
+    *         href="../util/Formatter.html#syntax">conversion</a>.
+    *
+    * @throws  IllegalFormatException
+    *          If a format string contains an illegal syntax, a format
+    *          specifier that is incompatible with the given arguments,
+    *          insufficient arguments given the format string, or other
+    *          illegal conditions.  For specification of all possible
+    *          formatting errors, see the <a
+    *          href="../util/Formatter.html#detail">Details</a> section of the
+    *          formatter class specification.
+    *
+    * @return  This console
+    */
+    public Console printf(String format, Object ... args) {
+        return format(format, args);
+    }
+
+   /**
+    * Provides a formatted prompt, then reads a single line of text from the
+    * console.
+    *
+    * @param  fmt
+    *         A format string as described in <a
+    *         href="../util/Formatter.html#syntax">Format string syntax</a>.
+    *
+    * @param  args
+    *         Arguments referenced by the format specifiers in the format
+    *         string.  If there are more arguments than format specifiers, the
+    *         extra arguments are ignored.  The maximum number of arguments is
+    *         limited by the maximum dimension of a Java array as defined by
+    *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+    *
+    * @throws  IllegalFormatException
+    *          If a format string contains an illegal syntax, a format
+    *          specifier that is incompatible with the given arguments,
+    *          insufficient arguments given the format string, or other
+    *          illegal conditions.  For specification of all possible
+    *          formatting errors, see the <a
+    *          href="../util/Formatter.html#detail">Details</a> section
+    *          of the formatter class specification.
+    *
+    * @throws IOError
+    *         If an I/O error occurs.
+    *
+    * @return  A string containing the line read from the console, not
+    *          including any line-termination characters, or <tt>null</tt>
+    *          if an end of stream has been reached.
+    */
+    public String readLine(String fmt, Object ... args) {
+        String line = null;
+        synchronized (writeLock) {
+            synchronized(readLock) {
+                if (fmt.length() != 0)
+                    pw.format(fmt, args);
+                try {
+                    char[] ca = readline(false);
+                    if (ca != null)
+                        line = new String(ca);
+                } catch (IOException x) {
+                    throw new IOError(x);
+                }
+            }
+        }
+        return line;
+    }
+
+   /**
+    * Reads a single line of text from the console.
+    *
+    * @throws IOError
+    *         If an I/O error occurs.
+    *
+    * @return  A string containing the line read from the console, not
+    *          including any line-termination characters, or <tt>null</tt>
+    *          if an end of stream has been reached.
+    */
+    public String readLine() {
+        return readLine("");
+    }
+
+   /**
+    * Provides a formatted prompt, then reads a password or passphrase from
+    * the console with echoing disabled.
+    *
+    * @param  fmt
+    *         A format string as described in <a
+    *         href="../util/Formatter.html#syntax">Format string syntax</a>
+    *         for the prompt text.
+    *
+    * @param  args
+    *         Arguments referenced by the format specifiers in the format
+    *         string.  If there are more arguments than format specifiers, the
+    *         extra arguments are ignored.  The maximum number of arguments is
+    *         limited by the maximum dimension of a Java array as defined by
+    *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+    *
+    * @throws  IllegalFormatException
+    *          If a format string contains an illegal syntax, a format
+    *          specifier that is incompatible with the given arguments,
+    *          insufficient arguments given the format string, or other
+    *          illegal conditions.  For specification of all possible
+    *          formatting errors, see the <a
+    *          href="../util/Formatter.html#detail">Details</a>
+    *          section of the formatter class specification.
+    *
+    * @throws IOError
+    *         If an I/O error occurs.
+    *
+    * @return  A character array containing the password or passphrase read
+    *          from the console, not including any line-termination characters,
+    *          or <tt>null</tt> if an end of stream has been reached.
+    */
+    public char[] readPassword(String fmt, Object ... args) {
+        char[] passwd = null;
+        synchronized (writeLock) {
+            synchronized(readLock) {
+                try {
+                    echoOff = echo(false);
+                } catch (IOException x) {
+                    throw new IOError(x);
+                }
+                IOError ioe = null;
+                try {
+                    if (fmt.length() != 0)
+                        pw.format(fmt, args);
+                    passwd = readline(true);
+                } catch (IOException x) {
+                    ioe = new IOError(x);
+                } finally {
+                    try {
+                        echoOff = echo(true);
+                    } catch (IOException x) {
+                        if (ioe == null)
+                            ioe = new IOError(x);
+                        else
+                            ioe.addSuppressed(x);
+                    }
+                    if (ioe != null)
+                        throw ioe;
+                }
+                pw.println();
+            }
+        }
+        return passwd;
+    }
+
+   /**
+    * Reads a password or passphrase from the console with echoing disabled
+    *
+    * @throws IOError
+    *         If an I/O error occurs.
+    *
+    * @return  A character array containing the password or passphrase read
+    *          from the console, not including any line-termination characters,
+    *          or <tt>null</tt> if an end of stream has been reached.
+    */
+    public char[] readPassword() {
+        return readPassword("");
+    }
+
+    /**
+     * Flushes the console and forces any buffered output to be written
+     * immediately .
+     */
+    public void flush() {
+        pw.flush();
+    }
+
+    private Object readLock;
+    private Object writeLock;
+    private Reader reader;
+    private Writer out;
+    private PrintWriter pw;
+    private Formatter formatter;
+    private Charset cs;
+    private char[] rcb;
+    private static native String encoding();
+    private static native boolean echo(boolean on) throws IOException;
+    private static boolean echoOff;
+
+    private char[] readline(boolean zeroOut) throws IOException {
+        int len = reader.read(rcb, 0, rcb.length);
+        if (len < 0)
+            return null;  //EOL
+        if (rcb[len-1] == '\r')
+            len--;        //remove CR at end;
+        else if (rcb[len-1] == '\n') {
+            len--;        //remove LF at end;
+            if (len > 0 && rcb[len-1] == '\r')
+                len--;    //remove the CR, if there is one
+        }
+        char[] b = new char[len];
+        if (len > 0) {
+            System.arraycopy(rcb, 0, b, 0, len);
+            if (zeroOut) {
+                Arrays.fill(rcb, 0, len, ' ');
+            }
+        }
+        return b;
+    }
+
+    private char[] grow() {
+        assert Thread.holdsLock(readLock);
+        char[] t = new char[rcb.length * 2];
+        System.arraycopy(rcb, 0, t, 0, rcb.length);
+        rcb = t;
+        return rcb;
+    }
+
+    class LineReader extends Reader {
+        private Reader in;
+        private char[] cb;
+        private int nChars, nextChar;
+        boolean leftoverLF;
+        LineReader(Reader in) {
+            this.in = in;
+            cb = new char[1024];
+            nextChar = nChars = 0;
+            leftoverLF = false;
+        }
+        public void close () {}
+        public boolean ready() throws IOException {
+            //in.ready synchronizes on readLock already
+            return in.ready();
+        }
+
+        public int read(char cbuf[], int offset, int length)
+            throws IOException
+        {
+            int off = offset;
+            int end = offset + length;
+            if (offset < 0 || offset > cbuf.length || length < 0 ||
+                end < 0 || end > cbuf.length) {
+                throw new IndexOutOfBoundsException();
+            }
+            synchronized(readLock) {
+                boolean eof = false;
+                char c = 0;
+                for (;;) {
+                    if (nextChar >= nChars) {   //fill
+                        int n = 0;
+                        do {
+                            n = in.read(cb, 0, cb.length);
+                        } while (n == 0);
+                        if (n > 0) {
+                            nChars = n;
+                            nextChar = 0;
+                            if (n < cb.length &&
+                                cb[n-1] != '\n' && cb[n-1] != '\r') {
+                                /*
+                                 * we're in canonical mode so each "fill" should
+                                 * come back with an eol. if there no lf or nl at
+                                 * the end of returned bytes we reached an eof.
+                                 */
+                                eof = true;
+                            }
+                        } else { /*EOF*/
+                            if (off - offset == 0)
+                                return -1;
+                            return off - offset;
+                        }
+                    }
+                    if (leftoverLF && cbuf == rcb && cb[nextChar] == '\n') {
+                        /*
+                         * if invoked by our readline, skip the leftover, otherwise
+                         * return the LF.
+                         */
+                        nextChar++;
+                    }
+                    leftoverLF = false;
+                    while (nextChar < nChars) {
+                        c = cbuf[off++] = cb[nextChar];
+                        cb[nextChar++] = 0;
+                        if (c == '\n') {
+                            return off - offset;
+                        } else if (c == '\r') {
+                            if (off == end) {
+                                /* no space left even the next is LF, so return
+                                 * whatever we have if the invoker is not our
+                                 * readLine()
+                                 */
+                                if (cbuf == rcb) {
+                                    cbuf = grow();
+                                    end = cbuf.length;
+                                } else {
+                                    leftoverLF = true;
+                                    return off - offset;
+                                }
+                            }
+                            if (nextChar == nChars && in.ready()) {
+                                /*
+                                 * we have a CR and we reached the end of
+                                 * the read in buffer, fill to make sure we
+                                 * don't miss a LF, if there is one, it's possible
+                                 * that it got cut off during last round reading
+                                 * simply because the read in buffer was full.
+                                 */
+                                nChars = in.read(cb, 0, cb.length);
+                                nextChar = 0;
+                            }
+                            if (nextChar < nChars && cb[nextChar] == '\n') {
+                                cbuf[off++] = '\n';
+                                nextChar++;
+                            }
+                            return off - offset;
+                        } else if (off == end) {
+                           if (cbuf == rcb) {
+                                cbuf = grow();
+                                end = cbuf.length;
+                           } else {
+                               return off - offset;
+                           }
+                        }
+                    }
+                    if (eof)
+                        return off - offset;
+                }
+            }
+        }
+    }
+
+    // Android-removed: SharedSecrets setup and also the shutdown hook.
+    // The hook is a no-op (but causes trouble when it's turned on).
+
+    // Android-changed: Use @hide rather than sun.misc.SharedSecrets to expose console().
+    /** @hide */
+    public static Console console() {
+        if (istty()) {
+            if (cons == null)
+                cons = new Console();
+            return cons;
+        }
+        return null;
+    }
+    private static Console cons;
+    private native static boolean istty();
+    private Console() {
+    // BEGIN Android-changed: Support custom in/out streams for testing.
+      this(new FileInputStream(FileDescriptor.in), new FileOutputStream(FileDescriptor.out));
+    }
+
+    // Constructor for tests
+    private Console(InputStream inStream, OutputStream outStream) {
+    // END Android-changed: Support custom in/out streams for testing.
+        readLock = new Object();
+        writeLock = new Object();
+        String csname = encoding();
+        if (csname != null) {
+            try {
+                cs = Charset.forName(csname);
+            } catch (Exception x) {}
+        }
+        if (cs == null)
+            cs = Charset.defaultCharset();
+        out = StreamEncoder.forOutputStreamWriter(
+                  outStream,
+                  writeLock,
+                  cs);
+        pw = new PrintWriter(out, true) { public void close() {} };
+        formatter = new Formatter(out);
+        reader = new LineReader(StreamDecoder.forInputStreamReader(
+                     inStream,
+                     readLock,
+                     cs));
+        rcb = new char[1024];
+    }
+}
diff --git a/java/io/DataInput.java b/java/io/DataInput.java
new file mode 100644
index 0000000..3e0f0dd
--- /dev/null
+++ b/java/io/DataInput.java
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * The {@code DataInput} interface provides
+ * for reading bytes from a binary stream and
+ * reconstructing from them data in any of
+ * the Java primitive types. There is also
+ * a
+ * facility for reconstructing a {@code String}
+ * from data in
+ * <a href="#modified-utf-8">modified UTF-8</a>
+ * format.
+ * <p>
+ * It is generally true of all the reading
+ * routines in this interface that if end of
+ * file is reached before the desired number
+ * of bytes has been read, an {@code EOFException}
+ * (which is a kind of {@code IOException})
+ * is thrown. If any byte cannot be read for
+ * any reason other than end of file, an {@code IOException}
+ * other than {@code EOFException} is
+ * thrown. In particular, an {@code IOException}
+ * may be thrown if the input stream has been
+ * closed.
+ *
+ * <h3><a name="modified-utf-8">Modified UTF-8</a></h3>
+ * <p>
+ * Implementations of the DataInput and DataOutput interfaces represent
+ * Unicode strings in a format that is a slight modification of UTF-8.
+ * (For information regarding the standard UTF-8 format, see section
+ * <i>3.9 Unicode Encoding Forms</i> of <i>The Unicode Standard, Version
+ * 4.0</i>).
+ * Note that in the following table, the most significant bit appears in the
+ * far left-hand column.
+ *
+ * <blockquote>
+ *   <table border="1" cellspacing="0" cellpadding="8"
+ *          summary="Bit values and bytes">
+ *     <tr>
+ *       <th colspan="9"><span style="font-weight:normal">
+ *         All characters in the range {@code '\u005Cu0001'} to
+ *         {@code '\u005Cu007F'} are represented by a single byte:</span></th>
+ *     </tr>
+ *     <tr>
+ *       <td></td>
+ *       <th colspan="8" id="bit_a">Bit Values</th>
+ *     </tr>
+ *     <tr>
+ *       <th id="byte1_a">Byte 1</th>
+ *       <td><center>0</center>
+ *       <td colspan="7"><center>bits 6-0</center>
+ *     </tr>
+ *     <tr>
+ *       <th colspan="9"><span style="font-weight:normal">
+ *         The null character {@code '\u005Cu0000'} and characters
+ *         in the range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are
+ *         represented by a pair of bytes:</span></th>
+ *     </tr>
+ *     <tr>
+ *       <td></td>
+ *       <th colspan="8" id="bit_b">Bit Values</th>
+ *     </tr>
+ *     <tr>
+ *       <th id="byte1_b">Byte 1</th>
+ *       <td><center>1</center>
+ *       <td><center>1</center>
+ *       <td><center>0</center>
+ *       <td colspan="5"><center>bits 10-6</center>
+ *     </tr>
+ *     <tr>
+ *       <th id="byte2_a">Byte 2</th>
+ *       <td><center>1</center>
+ *       <td><center>0</center>
+ *       <td colspan="6"><center>bits 5-0</center>
+ *     </tr>
+ *     <tr>
+ *       <th colspan="9"><span style="font-weight:normal">
+ *         {@code char} values in the range {@code '\u005Cu0800'}
+ *         to {@code '\u005CuFFFF'} are represented by three bytes:</span></th>
+ *     </tr>
+ *     <tr>
+ *       <td></td>
+ *       <th colspan="8"id="bit_c">Bit Values</th>
+ *     </tr>
+ *     <tr>
+ *       <th id="byte1_c">Byte 1</th>
+ *       <td><center>1</center>
+ *       <td><center>1</center>
+ *       <td><center>1</center>
+ *       <td><center>0</center>
+ *       <td colspan="4"><center>bits 15-12</center>
+ *     </tr>
+ *     <tr>
+ *       <th id="byte2_b">Byte 2</th>
+ *       <td><center>1</center>
+ *       <td><center>0</center>
+ *       <td colspan="6"><center>bits 11-6</center>
+ *     </tr>
+ *     <tr>
+ *       <th id="byte3">Byte 3</th>
+ *       <td><center>1</center>
+ *       <td><center>0</center>
+ *       <td colspan="6"><center>bits 5-0</center>
+ *     </tr>
+ *   </table>
+ * </blockquote>
+ * <p>
+ * The differences between this format and the
+ * standard UTF-8 format are the following:
+ * <ul>
+ * <li>The null byte {@code '\u005Cu0000'} is encoded in 2-byte format
+ *     rather than 1-byte, so that the encoded strings never have
+ *     embedded nulls.
+ * <li>Only the 1-byte, 2-byte, and 3-byte formats are used.
+ * <li><a href="../lang/Character.html#unicode">Supplementary characters</a>
+ *     are represented in the form of surrogate pairs.
+ * </ul>
+ * @author  Frank Yellin
+ * @see     java.io.DataInputStream
+ * @see     java.io.DataOutput
+ * @since   JDK1.0
+ */
+public
+interface DataInput {
+    /**
+     * Reads some bytes from an input
+     * stream and stores them into the buffer
+     * array {@code b}. The number of bytes
+     * read is equal
+     * to the length of {@code b}.
+     * <p>
+     * This method blocks until one of the
+     * following conditions occurs:
+     * <ul>
+     * <li>{@code b.length}
+     * bytes of input data are available, in which
+     * case a normal return is made.
+     *
+     * <li>End of
+     * file is detected, in which case an {@code EOFException}
+     * is thrown.
+     *
+     * <li>An I/O error occurs, in
+     * which case an {@code IOException} other
+     * than {@code EOFException} is thrown.
+     * </ul>
+     * <p>
+     * If {@code b} is {@code null},
+     * a {@code NullPointerException} is thrown.
+     * If {@code b.length} is zero, then
+     * no bytes are read. Otherwise, the first
+     * byte read is stored into element {@code b[0]},
+     * the next one into {@code b[1]}, and
+     * so on.
+     * If an exception is thrown from
+     * this method, then it may be that some but
+     * not all bytes of {@code b} have been
+     * updated with data from the input stream.
+     *
+     * @param     b   the buffer into which the data is read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    void readFully(byte b[]) throws IOException;
+
+    /**
+     *
+     * Reads {@code len}
+     * bytes from
+     * an input stream.
+     * <p>
+     * This method
+     * blocks until one of the following conditions
+     * occurs:
+     * <ul>
+     * <li>{@code len} bytes
+     * of input data are available, in which case
+     * a normal return is made.
+     *
+     * <li>End of file
+     * is detected, in which case an {@code EOFException}
+     * is thrown.
+     *
+     * <li>An I/O error occurs, in
+     * which case an {@code IOException} other
+     * than {@code EOFException} is thrown.
+     * </ul>
+     * <p>
+     * If {@code b} is {@code null},
+     * a {@code NullPointerException} is thrown.
+     * If {@code off} is negative, or {@code len}
+     * is negative, or {@code off+len} is
+     * greater than the length of the array {@code b},
+     * then an {@code IndexOutOfBoundsException}
+     * is thrown.
+     * If {@code len} is zero,
+     * then no bytes are read. Otherwise, the first
+     * byte read is stored into element {@code b[off]},
+     * the next one into {@code b[off+1]},
+     * and so on. The number of bytes read is,
+     * at most, equal to {@code len}.
+     *
+     * @param     b   the buffer into which the data is read.
+     * @param off  an int specifying the offset into the data.
+     * @param len  an int specifying the number of bytes to read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    void readFully(byte b[], int off, int len) throws IOException;
+
+    /**
+     * Makes an attempt to skip over
+     * {@code n} bytes
+     * of data from the input
+     * stream, discarding the skipped bytes. However,
+     * it may skip
+     * over some smaller number of
+     * bytes, possibly zero. This may result from
+     * any of a
+     * number of conditions; reaching
+     * end of file before {@code n} bytes
+     * have been skipped is
+     * only one possibility.
+     * This method never throws an {@code EOFException}.
+     * The actual
+     * number of bytes skipped is returned.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the number of bytes actually skipped.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    int skipBytes(int n) throws IOException;
+
+    /**
+     * Reads one input byte and returns
+     * {@code true} if that byte is nonzero,
+     * {@code false} if that byte is zero.
+     * This method is suitable for reading
+     * the byte written by the {@code writeBoolean}
+     * method of interface {@code DataOutput}.
+     *
+     * @return     the {@code boolean} value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    boolean readBoolean() throws IOException;
+
+    /**
+     * Reads and returns one input byte.
+     * The byte is treated as a signed value in
+     * the range {@code -128} through {@code 127},
+     * inclusive.
+     * This method is suitable for
+     * reading the byte written by the {@code writeByte}
+     * method of interface {@code DataOutput}.
+     *
+     * @return     the 8-bit value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    byte readByte() throws IOException;
+
+    /**
+     * Reads one input byte, zero-extends
+     * it to type {@code int}, and returns
+     * the result, which is therefore in the range
+     * {@code 0}
+     * through {@code 255}.
+     * This method is suitable for reading
+     * the byte written by the {@code writeByte}
+     * method of interface {@code DataOutput}
+     * if the argument to {@code writeByte}
+     * was intended to be a value in the range
+     * {@code 0} through {@code 255}.
+     *
+     * @return     the unsigned 8-bit value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    int readUnsignedByte() throws IOException;
+
+    /**
+     * Reads two input bytes and returns
+     * a {@code short} value. Let {@code a}
+     * be the first byte read and {@code b}
+     * be the second byte. The value
+     * returned
+     * is:
+     * <pre>{@code (short)((a << 8) | (b & 0xff))
+     * }</pre>
+     * This method
+     * is suitable for reading the bytes written
+     * by the {@code writeShort} method of
+     * interface {@code DataOutput}.
+     *
+     * @return     the 16-bit value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    short readShort() throws IOException;
+
+    /**
+     * Reads two input bytes and returns
+     * an {@code int} value in the range {@code 0}
+     * through {@code 65535}. Let {@code a}
+     * be the first byte read and
+     * {@code b}
+     * be the second byte. The value returned is:
+     * <pre>{@code (((a & 0xff) << 8) | (b & 0xff))
+     * }</pre>
+     * This method is suitable for reading the bytes
+     * written by the {@code writeShort} method
+     * of interface {@code DataOutput}  if
+     * the argument to {@code writeShort}
+     * was intended to be a value in the range
+     * {@code 0} through {@code 65535}.
+     *
+     * @return     the unsigned 16-bit value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    int readUnsignedShort() throws IOException;
+
+    /**
+     * Reads two input bytes and returns a {@code char} value.
+     * Let {@code a}
+     * be the first byte read and {@code b}
+     * be the second byte. The value
+     * returned is:
+     * <pre>{@code (char)((a << 8) | (b & 0xff))
+     * }</pre>
+     * This method
+     * is suitable for reading bytes written by
+     * the {@code writeChar} method of interface
+     * {@code DataOutput}.
+     *
+     * @return     the {@code char} value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    char readChar() throws IOException;
+
+    /**
+     * Reads four input bytes and returns an
+     * {@code int} value. Let {@code a-d}
+     * be the first through fourth bytes read. The value returned is:
+     * <pre>{@code
+     * (((a & 0xff) << 24) | ((b & 0xff) << 16) |
+     *  ((c & 0xff) <<  8) | (d & 0xff))
+     * }</pre>
+     * This method is suitable
+     * for reading bytes written by the {@code writeInt}
+     * method of interface {@code DataOutput}.
+     *
+     * @return     the {@code int} value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    int readInt() throws IOException;
+
+    /**
+     * Reads eight input bytes and returns
+     * a {@code long} value. Let {@code a-h}
+     * be the first through eighth bytes read.
+     * The value returned is:
+     * <pre>{@code
+     * (((long)(a & 0xff) << 56) |
+     *  ((long)(b & 0xff) << 48) |
+     *  ((long)(c & 0xff) << 40) |
+     *  ((long)(d & 0xff) << 32) |
+     *  ((long)(e & 0xff) << 24) |
+     *  ((long)(f & 0xff) << 16) |
+     *  ((long)(g & 0xff) <<  8) |
+     *  ((long)(h & 0xff)))
+     * }</pre>
+     * <p>
+     * This method is suitable
+     * for reading bytes written by the {@code writeLong}
+     * method of interface {@code DataOutput}.
+     *
+     * @return     the {@code long} value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    long readLong() throws IOException;
+
+    /**
+     * Reads four input bytes and returns
+     * a {@code float} value. It does this
+     * by first constructing an {@code int}
+     * value in exactly the manner
+     * of the {@code readInt}
+     * method, then converting this {@code int}
+     * value to a {@code float} in
+     * exactly the manner of the method {@code Float.intBitsToFloat}.
+     * This method is suitable for reading
+     * bytes written by the {@code writeFloat}
+     * method of interface {@code DataOutput}.
+     *
+     * @return     the {@code float} value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    float readFloat() throws IOException;
+
+    /**
+     * Reads eight input bytes and returns
+     * a {@code double} value. It does this
+     * by first constructing a {@code long}
+     * value in exactly the manner
+     * of the {@code readLong}
+     * method, then converting this {@code long}
+     * value to a {@code double} in exactly
+     * the manner of the method {@code Double.longBitsToDouble}.
+     * This method is suitable for reading
+     * bytes written by the {@code writeDouble}
+     * method of interface {@code DataOutput}.
+     *
+     * @return     the {@code double} value read.
+     * @exception  EOFException  if this stream reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    double readDouble() throws IOException;
+
+    /**
+     * Reads the next line of text from the input stream.
+     * It reads successive bytes, converting
+     * each byte separately into a character,
+     * until it encounters a line terminator or
+     * end of
+     * file; the characters read are then
+     * returned as a {@code String}. Note
+     * that because this
+     * method processes bytes,
+     * it does not support input of the full Unicode
+     * character set.
+     * <p>
+     * If end of file is encountered
+     * before even one byte can be read, then {@code null}
+     * is returned. Otherwise, each byte that is
+     * read is converted to type {@code char}
+     * by zero-extension. If the character {@code '\n'}
+     * is encountered, it is discarded and reading
+     * ceases. If the character {@code '\r'}
+     * is encountered, it is discarded and, if
+     * the following byte converts &#32;to the
+     * character {@code '\n'}, then that is
+     * discarded also; reading then ceases. If
+     * end of file is encountered before either
+     * of the characters {@code '\n'} and
+     * {@code '\r'} is encountered, reading
+     * ceases. Once reading has ceased, a {@code String}
+     * is returned that contains all the characters
+     * read and not discarded, taken in order.
+     * Note that every character in this string
+     * will have a value less than {@code \u005Cu0100},
+     * that is, {@code (char)256}.
+     *
+     * @return the next line of text from the input stream,
+     *         or {@code null} if the end of file is
+     *         encountered before a byte can be read.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    String readLine() throws IOException;
+
+    /**
+     * Reads in a string that has been encoded using a
+     * <a href="#modified-utf-8">modified UTF-8</a>
+     * format.
+     * The general contract of {@code readUTF}
+     * is that it reads a representation of a Unicode
+     * character string encoded in modified
+     * UTF-8 format; this string of characters
+     * is then returned as a {@code String}.
+     * <p>
+     * First, two bytes are read and used to
+     * construct an unsigned 16-bit integer in
+     * exactly the manner of the {@code readUnsignedShort}
+     * method . This integer value is called the
+     * <i>UTF length</i> and specifies the number
+     * of additional bytes to be read. These bytes
+     * are then converted to characters by considering
+     * them in groups. The length of each group
+     * is computed from the value of the first
+     * byte of the group. The byte following a
+     * group, if any, is the first byte of the
+     * next group.
+     * <p>
+     * If the first byte of a group
+     * matches the bit pattern {@code 0xxxxxxx}
+     * (where {@code x} means "may be {@code 0}
+     * or {@code 1}"), then the group consists
+     * of just that byte. The byte is zero-extended
+     * to form a character.
+     * <p>
+     * If the first byte
+     * of a group matches the bit pattern {@code 110xxxxx},
+     * then the group consists of that byte {@code a}
+     * and a second byte {@code b}. If there
+     * is no byte {@code b} (because byte
+     * {@code a} was the last of the bytes
+     * to be read), or if byte {@code b} does
+     * not match the bit pattern {@code 10xxxxxx},
+     * then a {@code UTFDataFormatException}
+     * is thrown. Otherwise, the group is converted
+     * to the character:
+     * <pre>{@code (char)(((a & 0x1F) << 6) | (b & 0x3F))
+     * }</pre>
+     * If the first byte of a group
+     * matches the bit pattern {@code 1110xxxx},
+     * then the group consists of that byte {@code a}
+     * and two more bytes {@code b} and {@code c}.
+     * If there is no byte {@code c} (because
+     * byte {@code a} was one of the last
+     * two of the bytes to be read), or either
+     * byte {@code b} or byte {@code c}
+     * does not match the bit pattern {@code 10xxxxxx},
+     * then a {@code UTFDataFormatException}
+     * is thrown. Otherwise, the group is converted
+     * to the character:
+     * <pre>{@code
+     * (char)(((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F))
+     * }</pre>
+     * If the first byte of a group matches the
+     * pattern {@code 1111xxxx} or the pattern
+     * {@code 10xxxxxx}, then a {@code UTFDataFormatException}
+     * is thrown.
+     * <p>
+     * If end of file is encountered
+     * at any time during this entire process,
+     * then an {@code EOFException} is thrown.
+     * <p>
+     * After every group has been converted to
+     * a character by this process, the characters
+     * are gathered, in the same order in which
+     * their corresponding groups were read from
+     * the input stream, to form a {@code String},
+     * which is returned.
+     * <p>
+     * The {@code writeUTF}
+     * method of interface {@code DataOutput}
+     * may be used to write data that is suitable
+     * for reading by this method.
+     * @return     a Unicode string.
+     * @exception  EOFException            if this stream reaches the end
+     *               before reading all the bytes.
+     * @exception  IOException             if an I/O error occurs.
+     * @exception  UTFDataFormatException  if the bytes do not represent a
+     *               valid modified UTF-8 encoding of a string.
+     */
+    String readUTF() throws IOException;
+}
diff --git a/java/io/DataInputStream.java b/java/io/DataInputStream.java
new file mode 100644
index 0000000..19d4067
--- /dev/null
+++ b/java/io/DataInputStream.java
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.nio.ByteOrder;
+import libcore.io.Memory;
+
+/**
+ * A data input stream lets an application read primitive Java data
+ * types from an underlying input stream in a machine-independent
+ * way. An application uses a data output stream to write data that
+ * can later be read by a data input stream.
+ * <p>
+ * DataInputStream is not necessarily safe for multithreaded access.
+ * Thread safety is optional and is the responsibility of users of
+ * methods in this class.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.io.DataOutputStream
+ * @since   JDK1.0
+ */
+public
+class DataInputStream extends FilterInputStream implements DataInput {
+
+    /**
+     * Creates a DataInputStream that uses the specified
+     * underlying InputStream.
+     *
+     * @param  in   the specified input stream
+     */
+    public DataInputStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * working arrays initialized on demand by readUTF
+     */
+    private byte bytearr[] = new byte[80];
+    private char chararr[] = new char[80];
+
+    /**
+     * Reads some number of bytes from the contained input stream and
+     * stores them into the buffer array <code>b</code>. The number of
+     * bytes actually read is returned as an integer. This method blocks
+     * until input data is available, end of file is detected, or an
+     * exception is thrown.
+     *
+     * <p>If <code>b</code> is null, a <code>NullPointerException</code> is
+     * thrown. If the length of <code>b</code> is zero, then no bytes are
+     * read and <code>0</code> is returned; otherwise, there is an attempt
+     * to read at least one byte. If no byte is available because the
+     * stream is at end of file, the value <code>-1</code> is returned;
+     * otherwise, at least one byte is read and stored into <code>b</code>.
+     *
+     * <p>The first byte read is stored into element <code>b[0]</code>, the
+     * next one into <code>b[1]</code>, and so on. The number of bytes read
+     * is, at most, equal to the length of <code>b</code>. Let <code>k</code>
+     * be the number of bytes actually read; these bytes will be stored in
+     * elements <code>b[0]</code> through <code>b[k-1]</code>, leaving
+     * elements <code>b[k]</code> through <code>b[b.length-1]</code>
+     * unaffected.
+     *
+     * <p>The <code>read(b)</code> method has the same effect as:
+     * <blockquote><pre>
+     * read(b, 0, b.length)
+     * </pre></blockquote>
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end
+     *             of the stream has been reached.
+     * @exception  IOException if the first byte cannot be read for any reason
+     * other than end of file, the stream has been closed and the underlying
+     * input stream does not support reading after close, or another I/O
+     * error occurs.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.InputStream#read(byte[], int, int)
+     */
+    public final int read(byte b[]) throws IOException {
+        return in.read(b, 0, b.length);
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from the contained
+     * input stream into an array of bytes.  An attempt is made to read
+     * as many as <code>len</code> bytes, but a smaller number may be read,
+     * possibly zero. The number of bytes actually read is returned as an
+     * integer.
+     *
+     * <p> This method blocks until input data is available, end of file is
+     * detected, or an exception is thrown.
+     *
+     * <p> If <code>len</code> is zero, then no bytes are read and
+     * <code>0</code> is returned; otherwise, there is an attempt to read at
+     * least one byte. If no byte is available because the stream is at end of
+     * file, the value <code>-1</code> is returned; otherwise, at least one
+     * byte is read and stored into <code>b</code>.
+     *
+     * <p> The first byte read is stored into element <code>b[off]</code>, the
+     * next one into <code>b[off+1]</code>, and so on. The number of bytes read
+     * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
+     * bytes actually read; these bytes will be stored in elements
+     * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
+     * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
+     * <code>b[off+len-1]</code> unaffected.
+     *
+     * <p> In every case, elements <code>b[0]</code> through
+     * <code>b[off]</code> and elements <code>b[off+len]</code> through
+     * <code>b[b.length-1]</code> are unaffected.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param off the start offset in the destination array <code>b</code>
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end
+     *             of the stream has been reached.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception  IOException if the first byte cannot be read for any reason
+     * other than end of file, the stream has been closed and the underlying
+     * input stream does not support reading after close, or another I/O
+     * error occurs.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.InputStream#read(byte[], int, int)
+     */
+    public final int read(byte b[], int off, int len) throws IOException {
+        return in.read(b, off, len);
+    }
+
+    /**
+     * See the general contract of the <code>readFully</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @exception  EOFException  if this input stream reaches the end before
+     *             reading all the bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final void readFully(byte b[]) throws IOException {
+        readFully(b, 0, b.length);
+    }
+
+    /**
+     * See the general contract of the <code>readFully</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset of the data.
+     * @param      len   the number of bytes to read.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading all the bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final void readFully(byte b[], int off, int len) throws IOException {
+        if (len < 0)
+            throw new IndexOutOfBoundsException();
+        int n = 0;
+        while (n < len) {
+            int count = in.read(b, off + n, len - n);
+            if (count < 0)
+                throw new EOFException();
+            n += count;
+        }
+    }
+
+    /**
+     * See the general contract of the <code>skipBytes</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes for this operation are read from the contained
+     * input stream.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if the contained input stream does not support
+     *             seek, or the stream has been closed and
+     *             the contained input stream does not support
+     *             reading after close, or another I/O error occurs.
+     */
+    public final int skipBytes(int n) throws IOException {
+        int total = 0;
+        int cur = 0;
+
+        while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) {
+            total += cur;
+        }
+
+        return total;
+    }
+
+    /**
+     * See the general contract of the <code>readBoolean</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the <code>boolean</code> value read.
+     * @exception  EOFException  if this input stream has reached the end.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final boolean readBoolean() throws IOException {
+        int ch = in.read();
+        if (ch < 0)
+            throw new EOFException();
+        return (ch != 0);
+    }
+
+    /**
+     * See the general contract of the <code>readByte</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next byte of this input stream as a signed 8-bit
+     *             <code>byte</code>.
+     * @exception  EOFException  if this input stream has reached the end.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final byte readByte() throws IOException {
+        int ch = in.read();
+        if (ch < 0)
+            throw new EOFException();
+        return (byte)(ch);
+    }
+
+    /**
+     * See the general contract of the <code>readUnsignedByte</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next byte of this input stream, interpreted as an
+     *             unsigned 8-bit number.
+     * @exception  EOFException  if this input stream has reached the end.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see         java.io.FilterInputStream#in
+     */
+    public final int readUnsignedByte() throws IOException {
+        int ch = in.read();
+        if (ch < 0)
+            throw new EOFException();
+        return ch;
+    }
+
+    /**
+     * See the general contract of the <code>readShort</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next two bytes of this input stream, interpreted as a
+     *             signed 16-bit number.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading two bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final short readShort() throws IOException {
+        // b/30268192
+        // Android-changed: Use read(byte[], int, int) instead of read().
+        readFully(readBuffer, 0, 2);
+        return Memory.peekShort(readBuffer, 0, ByteOrder.BIG_ENDIAN);
+    }
+
+    /**
+     * See the general contract of the <code>readUnsignedShort</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next two bytes of this input stream, interpreted as an
+     *             unsigned 16-bit integer.
+     * @exception  EOFException  if this input stream reaches the end before
+     *             reading two bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final int readUnsignedShort() throws IOException {
+        // b/30268192
+        // Android-changed: Use read(byte[], int, int) instead of read().
+        readFully(readBuffer, 0, 2);
+        return Memory.peekShort(readBuffer, 0, ByteOrder.BIG_ENDIAN) & 0xffff;
+    }
+
+    /**
+     * See the general contract of the <code>readChar</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next two bytes of this input stream, interpreted as a
+     *             <code>char</code>.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading two bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final char readChar() throws IOException {
+        // b/30268192
+        // Android-changed: Use read(byte[], int, int) instead of read().
+        readFully(readBuffer, 0, 2);
+        return (char)Memory.peekShort(readBuffer, 0, ByteOrder.BIG_ENDIAN);
+    }
+
+    /**
+     * See the general contract of the <code>readInt</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next four bytes of this input stream, interpreted as an
+     *             <code>int</code>.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading four bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final int readInt() throws IOException {
+        // b/30268192
+        // Android-changed: Use read(byte[], int, int) instead of read().
+        readFully(readBuffer, 0, 4);
+        return Memory.peekInt(readBuffer, 0, ByteOrder.BIG_ENDIAN);
+    }
+
+    private byte readBuffer[] = new byte[8];
+
+    /**
+     * See the general contract of the <code>readLong</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next eight bytes of this input stream, interpreted as a
+     *             <code>long</code>.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading eight bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public final long readLong() throws IOException {
+        readFully(readBuffer, 0, 8);
+        return (((long)readBuffer[0] << 56) +
+                ((long)(readBuffer[1] & 255) << 48) +
+                ((long)(readBuffer[2] & 255) << 40) +
+                ((long)(readBuffer[3] & 255) << 32) +
+                ((long)(readBuffer[4] & 255) << 24) +
+                ((readBuffer[5] & 255) << 16) +
+                ((readBuffer[6] & 255) <<  8) +
+                ((readBuffer[7] & 255) <<  0));
+    }
+
+    /**
+     * See the general contract of the <code>readFloat</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next four bytes of this input stream, interpreted as a
+     *             <code>float</code>.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading four bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.DataInputStream#readInt()
+     * @see        java.lang.Float#intBitsToFloat(int)
+     */
+    public final float readFloat() throws IOException {
+        return Float.intBitsToFloat(readInt());
+    }
+
+    /**
+     * See the general contract of the <code>readDouble</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     the next eight bytes of this input stream, interpreted as a
+     *             <code>double</code>.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading eight bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @see        java.io.DataInputStream#readLong()
+     * @see        java.lang.Double#longBitsToDouble(long)
+     */
+    public final double readDouble() throws IOException {
+        return Double.longBitsToDouble(readLong());
+    }
+
+    private char lineBuffer[];
+
+    /**
+     * See the general contract of the <code>readLine</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @deprecated This method does not properly convert bytes to characters.
+     * As of JDK&nbsp;1.1, the preferred way to read lines of text is via the
+     * <code>BufferedReader.readLine()</code> method.  Programs that use the
+     * <code>DataInputStream</code> class to read lines can be converted to use
+     * the <code>BufferedReader</code> class by replacing code of the form:
+     * <blockquote><pre>
+     *     DataInputStream d =&nbsp;new&nbsp;DataInputStream(in);
+     * </pre></blockquote>
+     * with:
+     * <blockquote><pre>
+     *     BufferedReader d
+     *          =&nbsp;new&nbsp;BufferedReader(new&nbsp;InputStreamReader(in));
+     * </pre></blockquote>
+     *
+     * @return     the next line of text from this input stream.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.BufferedReader#readLine()
+     * @see        java.io.FilterInputStream#in
+     */
+    @Deprecated
+    public final String readLine() throws IOException {
+        char buf[] = lineBuffer;
+
+        if (buf == null) {
+            buf = lineBuffer = new char[128];
+        }
+
+        int room = buf.length;
+        int offset = 0;
+        int c;
+
+loop:   while (true) {
+            switch (c = in.read()) {
+              case -1:
+              case '\n':
+                break loop;
+
+              case '\r':
+                int c2 = in.read();
+                if ((c2 != '\n') && (c2 != -1)) {
+                    if (!(in instanceof PushbackInputStream)) {
+                        this.in = new PushbackInputStream(in);
+                    }
+                    ((PushbackInputStream)in).unread(c2);
+                }
+                break loop;
+
+              default:
+                if (--room < 0) {
+                    buf = new char[offset + 128];
+                    room = buf.length - offset - 1;
+                    System.arraycopy(lineBuffer, 0, buf, 0, offset);
+                    lineBuffer = buf;
+                }
+                buf[offset++] = (char) c;
+                break;
+            }
+        }
+        if ((c == -1) && (offset == 0)) {
+            return null;
+        }
+        return String.copyValueOf(buf, 0, offset);
+    }
+
+    /**
+     * See the general contract of the <code>readUTF</code>
+     * method of <code>DataInput</code>.
+     * <p>
+     * Bytes
+     * for this operation are read from the contained
+     * input stream.
+     *
+     * @return     a Unicode string.
+     * @exception  EOFException  if this input stream reaches the end before
+     *               reading all the bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @exception  UTFDataFormatException if the bytes do not represent a valid
+     *             modified UTF-8 encoding of a string.
+     * @see        java.io.DataInputStream#readUTF(java.io.DataInput)
+     */
+    public final String readUTF() throws IOException {
+        return readUTF(this);
+    }
+
+    /**
+     * Reads from the
+     * stream <code>in</code> a representation
+     * of a Unicode  character string encoded in
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a> format;
+     * this string of characters is then returned as a <code>String</code>.
+     * The details of the modified UTF-8 representation
+     * are  exactly the same as for the <code>readUTF</code>
+     * method of <code>DataInput</code>.
+     *
+     * @param      in   a data input stream.
+     * @return     a Unicode string.
+     * @exception  EOFException            if the input stream reaches the end
+     *               before all the bytes.
+     * @exception  IOException   the stream has been closed and the contained
+     *             input stream does not support reading after close, or
+     *             another I/O error occurs.
+     * @exception  UTFDataFormatException  if the bytes do not represent a
+     *               valid modified UTF-8 encoding of a Unicode string.
+     * @see        java.io.DataInputStream#readUnsignedShort()
+     */
+    public final static String readUTF(DataInput in) throws IOException {
+        int utflen = in.readUnsignedShort();
+        byte[] bytearr = null;
+        char[] chararr = null;
+        if (in instanceof DataInputStream) {
+            DataInputStream dis = (DataInputStream)in;
+            if (dis.bytearr.length < utflen){
+                dis.bytearr = new byte[utflen*2];
+                dis.chararr = new char[utflen*2];
+            }
+            chararr = dis.chararr;
+            bytearr = dis.bytearr;
+        } else {
+            bytearr = new byte[utflen];
+            chararr = new char[utflen];
+        }
+
+        int c, char2, char3;
+        int count = 0;
+        int chararr_count=0;
+
+        in.readFully(bytearr, 0, utflen);
+
+        while (count < utflen) {
+            c = (int) bytearr[count] & 0xff;
+            if (c > 127) break;
+            count++;
+            chararr[chararr_count++]=(char)c;
+        }
+
+        while (count < utflen) {
+            c = (int) bytearr[count] & 0xff;
+            switch (c >> 4) {
+                case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
+                    /* 0xxxxxxx*/
+                    count++;
+                    chararr[chararr_count++]=(char)c;
+                    break;
+                case 12: case 13:
+                    /* 110x xxxx   10xx xxxx*/
+                    count += 2;
+                    if (count > utflen)
+                        throw new UTFDataFormatException(
+                            "malformed input: partial character at end");
+                    char2 = (int) bytearr[count-1];
+                    if ((char2 & 0xC0) != 0x80)
+                        throw new UTFDataFormatException(
+                            "malformed input around byte " + count);
+                    chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
+                                                    (char2 & 0x3F));
+                    break;
+                case 14:
+                    /* 1110 xxxx  10xx xxxx  10xx xxxx */
+                    count += 3;
+                    if (count > utflen)
+                        throw new UTFDataFormatException(
+                            "malformed input: partial character at end");
+                    char2 = (int) bytearr[count-2];
+                    char3 = (int) bytearr[count-1];
+                    if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
+                        throw new UTFDataFormatException(
+                            "malformed input around byte " + (count-1));
+                    chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |
+                                                    ((char2 & 0x3F) << 6)  |
+                                                    ((char3 & 0x3F) << 0));
+                    break;
+                default:
+                    /* 10xx xxxx,  1111 xxxx */
+                    throw new UTFDataFormatException(
+                        "malformed input around byte " + count);
+            }
+        }
+        // The number of chars produced may be less than utflen
+        return new String(chararr, 0, chararr_count);
+    }
+}
diff --git a/java/io/DataOutput.java b/java/io/DataOutput.java
new file mode 100644
index 0000000..c6692a6
--- /dev/null
+++ b/java/io/DataOutput.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * The <code>DataOutput</code> interface provides
+ * for converting data from any of the Java
+ * primitive types to a series of bytes and
+ * writing these bytes to a binary stream.
+ * There is  also a facility for converting
+ * a <code>String</code> into
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format and writing the resulting series
+ * of bytes.
+ * <p>
+ * For all the methods in this interface that
+ * write bytes, it is generally true that if
+ * a byte cannot be written for any reason,
+ * an <code>IOException</code> is thrown.
+ *
+ * @author  Frank Yellin
+ * @see     java.io.DataInput
+ * @see     java.io.DataOutputStream
+ * @since   JDK1.0
+ */
+public
+interface DataOutput {
+    /**
+     * Writes to the output stream the eight
+     * low-order bits of the argument <code>b</code>.
+     * The 24 high-order  bits of <code>b</code>
+     * are ignored.
+     *
+     * @param      b   the byte to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void write(int b) throws IOException;
+
+    /**
+     * Writes to the output stream all the bytes in array <code>b</code>.
+     * If <code>b</code> is <code>null</code>,
+     * a <code>NullPointerException</code> is thrown.
+     * If <code>b.length</code> is zero, then
+     * no bytes are written. Otherwise, the byte
+     * <code>b[0]</code> is written first, then
+     * <code>b[1]</code>, and so on; the last byte
+     * written is <code>b[b.length-1]</code>.
+     *
+     * @param      b   the data.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void write(byte b[]) throws IOException;
+
+    /**
+     * Writes <code>len</code> bytes from array
+     * <code>b</code>, in order,  to
+     * the output stream.  If <code>b</code>
+     * is <code>null</code>, a <code>NullPointerException</code>
+     * is thrown.  If <code>off</code> is negative,
+     * or <code>len</code> is negative, or <code>off+len</code>
+     * is greater than the length of the array
+     * <code>b</code>, then an <code>IndexOutOfBoundsException</code>
+     * is thrown.  If <code>len</code> is zero,
+     * then no bytes are written. Otherwise, the
+     * byte <code>b[off]</code> is written first,
+     * then <code>b[off+1]</code>, and so on; the
+     * last byte written is <code>b[off+len-1]</code>.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void write(byte b[], int off, int len) throws IOException;
+
+    /**
+     * Writes a <code>boolean</code> value to this output stream.
+     * If the argument <code>v</code>
+     * is <code>true</code>, the value <code>(byte)1</code>
+     * is written; if <code>v</code> is <code>false</code>,
+     * the  value <code>(byte)0</code> is written.
+     * The byte written by this method may
+     * be read by the <code>readBoolean</code>
+     * method of interface <code>DataInput</code>,
+     * which will then return a <code>boolean</code>
+     * equal to <code>v</code>.
+     *
+     * @param      v   the boolean to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeBoolean(boolean v) throws IOException;
+
+    /**
+     * Writes to the output stream the eight low-
+     * order bits of the argument <code>v</code>.
+     * The 24 high-order bits of <code>v</code>
+     * are ignored. (This means  that <code>writeByte</code>
+     * does exactly the same thing as <code>write</code>
+     * for an integer argument.) The byte written
+     * by this method may be read by the <code>readByte</code>
+     * method of interface <code>DataInput</code>,
+     * which will then return a <code>byte</code>
+     * equal to <code>(byte)v</code>.
+     *
+     * @param      v   the byte value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeByte(int v) throws IOException;
+
+    /**
+     * Writes two bytes to the output
+     * stream to represent the value of the argument.
+     * The byte values to be written, in the  order
+     * shown, are:
+     * <pre>{@code
+     * (byte)(0xff & (v >> 8))
+     * (byte)(0xff & v)
+     * }</pre> <p>
+     * The bytes written by this method may be
+     * read by the <code>readShort</code> method
+     * of interface <code>DataInput</code> , which
+     * will then return a <code>short</code> equal
+     * to <code>(short)v</code>.
+     *
+     * @param      v   the <code>short</code> value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeShort(int v) throws IOException;
+
+    /**
+     * Writes a <code>char</code> value, which
+     * is comprised of two bytes, to the
+     * output stream.
+     * The byte values to be written, in the  order
+     * shown, are:
+     * <pre>{@code
+     * (byte)(0xff & (v >> 8))
+     * (byte)(0xff & v)
+     * }</pre><p>
+     * The bytes written by this method may be
+     * read by the <code>readChar</code> method
+     * of interface <code>DataInput</code> , which
+     * will then return a <code>char</code> equal
+     * to <code>(char)v</code>.
+     *
+     * @param      v   the <code>char</code> value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeChar(int v) throws IOException;
+
+    /**
+     * Writes an <code>int</code> value, which is
+     * comprised of four bytes, to the output stream.
+     * The byte values to be written, in the  order
+     * shown, are:
+     * <pre>{@code
+     * (byte)(0xff & (v >> 24))
+     * (byte)(0xff & (v >> 16))
+     * (byte)(0xff & (v >>  8))
+     * (byte)(0xff & v)
+     * }</pre><p>
+     * The bytes written by this method may be read
+     * by the <code>readInt</code> method of interface
+     * <code>DataInput</code> , which will then
+     * return an <code>int</code> equal to <code>v</code>.
+     *
+     * @param      v   the <code>int</code> value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeInt(int v) throws IOException;
+
+    /**
+     * Writes a <code>long</code> value, which is
+     * comprised of eight bytes, to the output stream.
+     * The byte values to be written, in the  order
+     * shown, are:
+     * <pre>{@code
+     * (byte)(0xff & (v >> 56))
+     * (byte)(0xff & (v >> 48))
+     * (byte)(0xff & (v >> 40))
+     * (byte)(0xff & (v >> 32))
+     * (byte)(0xff & (v >> 24))
+     * (byte)(0xff & (v >> 16))
+     * (byte)(0xff & (v >>  8))
+     * (byte)(0xff & v)
+     * }</pre><p>
+     * The bytes written by this method may be
+     * read by the <code>readLong</code> method
+     * of interface <code>DataInput</code> , which
+     * will then return a <code>long</code> equal
+     * to <code>v</code>.
+     *
+     * @param      v   the <code>long</code> value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeLong(long v) throws IOException;
+
+    /**
+     * Writes a <code>float</code> value,
+     * which is comprised of four bytes, to the output stream.
+     * It does this as if it first converts this
+     * <code>float</code> value to an <code>int</code>
+     * in exactly the manner of the <code>Float.floatToIntBits</code>
+     * method  and then writes the <code>int</code>
+     * value in exactly the manner of the  <code>writeInt</code>
+     * method.  The bytes written by this method
+     * may be read by the <code>readFloat</code>
+     * method of interface <code>DataInput</code>,
+     * which will then return a <code>float</code>
+     * equal to <code>v</code>.
+     *
+     * @param      v   the <code>float</code> value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeFloat(float v) throws IOException;
+
+    /**
+     * Writes a <code>double</code> value,
+     * which is comprised of eight bytes, to the output stream.
+     * It does this as if it first converts this
+     * <code>double</code> value to a <code>long</code>
+     * in exactly the manner of the <code>Double.doubleToLongBits</code>
+     * method  and then writes the <code>long</code>
+     * value in exactly the manner of the  <code>writeLong</code>
+     * method. The bytes written by this method
+     * may be read by the <code>readDouble</code>
+     * method of interface <code>DataInput</code>,
+     * which will then return a <code>double</code>
+     * equal to <code>v</code>.
+     *
+     * @param      v   the <code>double</code> value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeDouble(double v) throws IOException;
+
+    /**
+     * Writes a string to the output stream.
+     * For every character in the string
+     * <code>s</code>,  taken in order, one byte
+     * is written to the output stream.  If
+     * <code>s</code> is <code>null</code>, a <code>NullPointerException</code>
+     * is thrown.<p>  If <code>s.length</code>
+     * is zero, then no bytes are written. Otherwise,
+     * the character <code>s[0]</code> is written
+     * first, then <code>s[1]</code>, and so on;
+     * the last character written is <code>s[s.length-1]</code>.
+     * For each character, one byte is written,
+     * the low-order byte, in exactly the manner
+     * of the <code>writeByte</code> method . The
+     * high-order eight bits of each character
+     * in the string are ignored.
+     *
+     * @param      s   the string of bytes to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeBytes(String s) throws IOException;
+
+    /**
+     * Writes every character in the string <code>s</code>,
+     * to the output stream, in order,
+     * two bytes per character. If <code>s</code>
+     * is <code>null</code>, a <code>NullPointerException</code>
+     * is thrown.  If <code>s.length</code>
+     * is zero, then no characters are written.
+     * Otherwise, the character <code>s[0]</code>
+     * is written first, then <code>s[1]</code>,
+     * and so on; the last character written is
+     * <code>s[s.length-1]</code>. For each character,
+     * two bytes are actually written, high-order
+     * byte first, in exactly the manner of the
+     * <code>writeChar</code> method.
+     *
+     * @param      s   the string value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeChars(String s) throws IOException;
+
+    /**
+     * Writes two bytes of length information
+     * to the output stream, followed
+     * by the
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * representation
+     * of  every character in the string <code>s</code>.
+     * If <code>s</code> is <code>null</code>,
+     * a <code>NullPointerException</code> is thrown.
+     * Each character in the string <code>s</code>
+     * is converted to a group of one, two, or
+     * three bytes, depending on the value of the
+     * character.<p>
+     * If a character <code>c</code>
+     * is in the range <code>&#92;u0001</code> through
+     * <code>&#92;u007f</code>, it is represented
+     * by one byte:
+     * <pre>(byte)c </pre>  <p>
+     * If a character <code>c</code> is <code>&#92;u0000</code>
+     * or is in the range <code>&#92;u0080</code>
+     * through <code>&#92;u07ff</code>, then it is
+     * represented by two bytes, to be written
+     * in the order shown: <pre>{@code
+     * (byte)(0xc0 | (0x1f & (c >> 6)))
+     * (byte)(0x80 | (0x3f & c))
+     * }</pre> <p> If a character
+     * <code>c</code> is in the range <code>&#92;u0800</code>
+     * through <code>uffff</code>, then it is
+     * represented by three bytes, to be written
+     * in the order shown: <pre>{@code
+     * (byte)(0xe0 | (0x0f & (c >> 12)))
+     * (byte)(0x80 | (0x3f & (c >>  6)))
+     * (byte)(0x80 | (0x3f & c))
+     * }</pre>  <p> First,
+     * the total number of bytes needed to represent
+     * all the characters of <code>s</code> is
+     * calculated. If this number is larger than
+     * <code>65535</code>, then a <code>UTFDataFormatException</code>
+     * is thrown. Otherwise, this length is written
+     * to the output stream in exactly the manner
+     * of the <code>writeShort</code> method;
+     * after this, the one-, two-, or three-byte
+     * representation of each character in the
+     * string <code>s</code> is written.<p>  The
+     * bytes written by this method may be read
+     * by the <code>readUTF</code> method of interface
+     * <code>DataInput</code> , which will then
+     * return a <code>String</code> equal to <code>s</code>.
+     *
+     * @param      s   the string value to be written.
+     * @throws     IOException  if an I/O error occurs.
+     */
+    void writeUTF(String s) throws IOException;
+}
diff --git a/java/io/DataOutputStream.java b/java/io/DataOutputStream.java
new file mode 100644
index 0000000..99fafed
--- /dev/null
+++ b/java/io/DataOutputStream.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A data output stream lets an application write primitive Java data
+ * types to an output stream in a portable way. An application can
+ * then use a data input stream to read the data back in.
+ *
+ * @author  unascribed
+ * @see     java.io.DataInputStream
+ * @since   JDK1.0
+ */
+public
+class DataOutputStream extends FilterOutputStream implements DataOutput {
+    /**
+     * The number of bytes written to the data output stream so far.
+     * If this counter overflows, it will be wrapped to Integer.MAX_VALUE.
+     */
+    protected int written;
+
+    /**
+     * bytearr is initialized on demand by writeUTF
+     */
+    private byte[] bytearr = null;
+
+    /**
+     * Creates a new data output stream to write data to the specified
+     * underlying output stream. The counter <code>written</code> is
+     * set to zero.
+     *
+     * @param   out   the underlying output stream, to be saved for later
+     *                use.
+     * @see     java.io.FilterOutputStream#out
+     */
+    public DataOutputStream(OutputStream out) {
+        super(out);
+    }
+
+    /**
+     * Increases the written counter by the specified value
+     * until it reaches Integer.MAX_VALUE.
+     */
+    private void incCount(int value) {
+        int temp = written + value;
+        if (temp < 0) {
+            temp = Integer.MAX_VALUE;
+        }
+        written = temp;
+    }
+
+    /**
+     * Writes the specified byte (the low eight bits of the argument
+     * <code>b</code>) to the underlying output stream. If no exception
+     * is thrown, the counter <code>written</code> is incremented by
+     * <code>1</code>.
+     * <p>
+     * Implements the <code>write</code> method of <code>OutputStream</code>.
+     *
+     * @param      b   the <code>byte</code> to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public synchronized void write(int b) throws IOException {
+        out.write(b);
+        incCount(1);
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to the underlying output stream.
+     * If no exception is thrown, the counter <code>written</code> is
+     * incremented by <code>len</code>.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public synchronized void write(byte b[], int off, int len)
+        throws IOException
+    {
+        out.write(b, off, len);
+        incCount(len);
+    }
+
+    /**
+     * Flushes this data output stream. This forces any buffered output
+     * bytes to be written out to the stream.
+     * <p>
+     * The <code>flush</code> method of <code>DataOutputStream</code>
+     * calls the <code>flush</code> method of its underlying output stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     * @see        java.io.OutputStream#flush()
+     */
+    public void flush() throws IOException {
+        out.flush();
+    }
+
+    /**
+     * Writes a <code>boolean</code> to the underlying output stream as
+     * a 1-byte value. The value <code>true</code> is written out as the
+     * value <code>(byte)1</code>; the value <code>false</code> is
+     * written out as the value <code>(byte)0</code>. If no exception is
+     * thrown, the counter <code>written</code> is incremented by
+     * <code>1</code>.
+     *
+     * @param      v   a <code>boolean</code> value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeBoolean(boolean v) throws IOException {
+        out.write(v ? 1 : 0);
+        incCount(1);
+    }
+
+    /**
+     * Writes out a <code>byte</code> to the underlying output stream as
+     * a 1-byte value. If no exception is thrown, the counter
+     * <code>written</code> is incremented by <code>1</code>.
+     *
+     * @param      v   a <code>byte</code> value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeByte(int v) throws IOException {
+        out.write(v);
+        incCount(1);
+    }
+
+    /**
+     * Writes a <code>short</code> to the underlying output stream as two
+     * bytes, high byte first. If no exception is thrown, the counter
+     * <code>written</code> is incremented by <code>2</code>.
+     *
+     * @param      v   a <code>short</code> to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeShort(int v) throws IOException {
+        out.write((v >>> 8) & 0xFF);
+        out.write((v >>> 0) & 0xFF);
+        incCount(2);
+    }
+
+    /**
+     * Writes a <code>char</code> to the underlying output stream as a
+     * 2-byte value, high byte first. If no exception is thrown, the
+     * counter <code>written</code> is incremented by <code>2</code>.
+     *
+     * @param      v   a <code>char</code> value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeChar(int v) throws IOException {
+        out.write((v >>> 8) & 0xFF);
+        out.write((v >>> 0) & 0xFF);
+        incCount(2);
+    }
+
+    /**
+     * Writes an <code>int</code> to the underlying output stream as four
+     * bytes, high byte first. If no exception is thrown, the counter
+     * <code>written</code> is incremented by <code>4</code>.
+     *
+     * @param      v   an <code>int</code> to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeInt(int v) throws IOException {
+        out.write((v >>> 24) & 0xFF);
+        out.write((v >>> 16) & 0xFF);
+        out.write((v >>>  8) & 0xFF);
+        out.write((v >>>  0) & 0xFF);
+        incCount(4);
+    }
+
+    private byte writeBuffer[] = new byte[8];
+
+    /**
+     * Writes a <code>long</code> to the underlying output stream as eight
+     * bytes, high byte first. In no exception is thrown, the counter
+     * <code>written</code> is incremented by <code>8</code>.
+     *
+     * @param      v   a <code>long</code> to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeLong(long v) throws IOException {
+        writeBuffer[0] = (byte)(v >>> 56);
+        writeBuffer[1] = (byte)(v >>> 48);
+        writeBuffer[2] = (byte)(v >>> 40);
+        writeBuffer[3] = (byte)(v >>> 32);
+        writeBuffer[4] = (byte)(v >>> 24);
+        writeBuffer[5] = (byte)(v >>> 16);
+        writeBuffer[6] = (byte)(v >>>  8);
+        writeBuffer[7] = (byte)(v >>>  0);
+        out.write(writeBuffer, 0, 8);
+        incCount(8);
+    }
+
+    /**
+     * Converts the float argument to an <code>int</code> using the
+     * <code>floatToIntBits</code> method in class <code>Float</code>,
+     * and then writes that <code>int</code> value to the underlying
+     * output stream as a 4-byte quantity, high byte first. If no
+     * exception is thrown, the counter <code>written</code> is
+     * incremented by <code>4</code>.
+     *
+     * @param      v   a <code>float</code> value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     * @see        java.lang.Float#floatToIntBits(float)
+     */
+    public final void writeFloat(float v) throws IOException {
+        writeInt(Float.floatToIntBits(v));
+    }
+
+    /**
+     * Converts the double argument to a <code>long</code> using the
+     * <code>doubleToLongBits</code> method in class <code>Double</code>,
+     * and then writes that <code>long</code> value to the underlying
+     * output stream as an 8-byte quantity, high byte first. If no
+     * exception is thrown, the counter <code>written</code> is
+     * incremented by <code>8</code>.
+     *
+     * @param      v   a <code>double</code> value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     * @see        java.lang.Double#doubleToLongBits(double)
+     */
+    public final void writeDouble(double v) throws IOException {
+        writeLong(Double.doubleToLongBits(v));
+    }
+
+    /**
+     * Writes out the string to the underlying output stream as a
+     * sequence of bytes. Each character in the string is written out, in
+     * sequence, by discarding its high eight bits. If no exception is
+     * thrown, the counter <code>written</code> is incremented by the
+     * length of <code>s</code>.
+     *
+     * @param      s   a string of bytes to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeBytes(String s) throws IOException {
+        int len = s.length();
+        for (int i = 0 ; i < len ; i++) {
+            out.write((byte)s.charAt(i));
+        }
+        incCount(len);
+    }
+
+    /**
+     * Writes a string to the underlying output stream as a sequence of
+     * characters. Each character is written to the data output stream as
+     * if by the <code>writeChar</code> method. If no exception is
+     * thrown, the counter <code>written</code> is incremented by twice
+     * the length of <code>s</code>.
+     *
+     * @param      s   a <code>String</code> value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.DataOutputStream#writeChar(int)
+     * @see        java.io.FilterOutputStream#out
+     */
+    public final void writeChars(String s) throws IOException {
+        int len = s.length();
+        for (int i = 0 ; i < len ; i++) {
+            int v = s.charAt(i);
+            out.write((v >>> 8) & 0xFF);
+            out.write((v >>> 0) & 0xFF);
+        }
+        incCount(len * 2);
+    }
+
+    /**
+     * Writes a string to the underlying output stream using
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * encoding in a machine-independent manner.
+     * <p>
+     * First, two bytes are written to the output stream as if by the
+     * <code>writeShort</code> method giving the number of bytes to
+     * follow. This value is the number of bytes actually written out,
+     * not the length of the string. Following the length, each character
+     * of the string is output, in sequence, using the modified UTF-8 encoding
+     * for the character. If no exception is thrown, the counter
+     * <code>written</code> is incremented by the total number of
+     * bytes written to the output stream. This will be at least two
+     * plus the length of <code>str</code>, and at most two plus
+     * thrice the length of <code>str</code>.
+     *
+     * @param      str   a string to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeUTF(String str) throws IOException {
+        writeUTF(str, this);
+    }
+
+    /**
+     * Writes a string to the specified DataOutput using
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * encoding in a machine-independent manner.
+     * <p>
+     * First, two bytes are written to out as if by the <code>writeShort</code>
+     * method giving the number of bytes to follow. This value is the number of
+     * bytes actually written out, not the length of the string. Following the
+     * length, each character of the string is output, in sequence, using the
+     * modified UTF-8 encoding for the character. If no exception is thrown, the
+     * counter <code>written</code> is incremented by the total number of
+     * bytes written to the output stream. This will be at least two
+     * plus the length of <code>str</code>, and at most two plus
+     * thrice the length of <code>str</code>.
+     *
+     * @param      str   a string to be written.
+     * @param      out   destination to write to
+     * @return     The number of bytes written out.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    static int writeUTF(String str, DataOutput out) throws IOException {
+        int strlen = str.length();
+        int utflen = 0;
+        int c, count = 0;
+
+        /* use charAt instead of copying String to char array */
+        for (int i = 0; i < strlen; i++) {
+            c = str.charAt(i);
+            if ((c >= 0x0001) && (c <= 0x007F)) {
+                utflen++;
+            } else if (c > 0x07FF) {
+                utflen += 3;
+            } else {
+                utflen += 2;
+            }
+        }
+
+        if (utflen > 65535)
+            throw new UTFDataFormatException(
+                "encoded string too long: " + utflen + " bytes");
+
+        byte[] bytearr = null;
+        if (out instanceof DataOutputStream) {
+            DataOutputStream dos = (DataOutputStream)out;
+            if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
+                dos.bytearr = new byte[(utflen*2) + 2];
+            bytearr = dos.bytearr;
+        } else {
+            bytearr = new byte[utflen+2];
+        }
+
+        bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
+        bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
+
+        int i=0;
+        for (i=0; i<strlen; i++) {
+           c = str.charAt(i);
+           if (!((c >= 0x0001) && (c <= 0x007F))) break;
+           bytearr[count++] = (byte) c;
+        }
+
+        for (;i < strlen; i++){
+            c = str.charAt(i);
+            if ((c >= 0x0001) && (c <= 0x007F)) {
+                bytearr[count++] = (byte) c;
+
+            } else if (c > 0x07FF) {
+                bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+                bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
+                bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
+            } else {
+                bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
+                bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
+            }
+        }
+        out.write(bytearr, 0, utflen+2);
+        return utflen + 2;
+    }
+
+    /**
+     * Returns the current value of the counter <code>written</code>,
+     * the number of bytes written to this data output stream so far.
+     * If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
+     *
+     * @return  the value of the <code>written</code> field.
+     * @see     java.io.DataOutputStream#written
+     */
+    public final int size() {
+        return written;
+    }
+}
diff --git a/java/io/DefaultFileSystem.java b/java/io/DefaultFileSystem.java
new file mode 100644
index 0000000..8e8cf08
--- /dev/null
+++ b/java/io/DefaultFileSystem.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ *
+ * @since 1.8
+ */
+class DefaultFileSystem {
+
+    /**
+     * Return the FileSystem object for Unix-based platform.
+     */
+    public static FileSystem getFileSystem() {
+        return new UnixFileSystem();
+    }
+}
diff --git a/java/io/DeleteOnExitHook.java b/java/io/DeleteOnExitHook.java
new file mode 100644
index 0000000..e988f9b
--- /dev/null
+++ b/java/io/DeleteOnExitHook.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+import java.util.*;
+import java.io.File;
+
+/**
+ * This class holds a set of filenames to be deleted on VM exit through a shutdown hook.
+ * A set is used both to prevent double-insertion of the same file as well as offer
+ * quick removal.
+ */
+
+class DeleteOnExitHook {
+    private static LinkedHashSet<String> files = new LinkedHashSet<>();
+    static {
+        // BEGIN Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                runHooks();
+            }
+        });
+        // END Android-changed: Use Runtime.addShutdownHook() rather than SharedSecrets.
+    }
+
+    private DeleteOnExitHook() {}
+
+    static synchronized void add(String file) {
+        if(files == null) {
+            // DeleteOnExitHook is running. Too late to add a file
+            throw new IllegalStateException("Shutdown in progress");
+        }
+
+        files.add(file);
+    }
+
+    static void runHooks() {
+        LinkedHashSet<String> theFiles;
+
+        synchronized (DeleteOnExitHook.class) {
+            theFiles = files;
+            files = null;
+        }
+
+        ArrayList<String> toBeDeleted = new ArrayList<>(theFiles);
+
+        // reverse the list to maintain previous jdk deletion order.
+        // Last in first deleted.
+        Collections.reverse(toBeDeleted);
+        for (String filename : toBeDeleted) {
+            (new File(filename)).delete();
+        }
+    }
+}
diff --git a/java/io/EOFException.java b/java/io/EOFException.java
new file mode 100644
index 0000000..536669f
--- /dev/null
+++ b/java/io/EOFException.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that an end of file or end of stream has been reached
+ * unexpectedly during input.
+ * <p>
+ * This exception is mainly used by data input streams to signal end of
+ * stream. Note that many other input operations return a special value on
+ * end of stream rather than throwing an exception.
+ *
+ * @author  Frank Yellin
+ * @see     java.io.DataInputStream
+ * @see     java.io.IOException
+ * @since   JDK1.0
+ */
+public
+class EOFException extends IOException {
+    private static final long serialVersionUID = 6433858223774886977L;
+
+    /**
+     * Constructs an <code>EOFException</code> with <code>null</code>
+     * as its error detail message.
+     */
+    public EOFException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>EOFException</code> with the specified detail
+     * message. The string <code>s</code> may later be retrieved by the
+     * <code>{@link java.lang.Throwable#getMessage}</code> method of class
+     * <code>java.lang.Throwable</code>.
+     *
+     * @param   s   the detail message.
+     */
+    public EOFException(String s) {
+        super(s);
+    }
+}
diff --git a/java/io/ExpiringCache.java b/java/io/ExpiringCache.java
new file mode 100644
index 0000000..d0edb11
--- /dev/null
+++ b/java/io/ExpiringCache.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ */
+
+package java.io;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+class ExpiringCache {
+    private long millisUntilExpiration;
+    private Map<String,Entry> map;
+    // Clear out old entries every few queries
+    private int queryCount;
+    private int queryOverflow = 300;
+    private int MAX_ENTRIES = 200;
+
+    static class Entry {
+        private long   timestamp;
+        private String val;
+
+        Entry(long timestamp, String val) {
+            this.timestamp = timestamp;
+            this.val = val;
+        }
+
+        long   timestamp()                  { return timestamp;           }
+        void   setTimestamp(long timestamp) { this.timestamp = timestamp; }
+
+        String val()                        { return val;                 }
+        void   setVal(String val)           { this.val = val;             }
+    }
+
+    ExpiringCache() {
+        this(30000);
+    }
+
+    @SuppressWarnings("serial")
+    ExpiringCache(long millisUntilExpiration) {
+        this.millisUntilExpiration = millisUntilExpiration;
+        map = new LinkedHashMap<String,Entry>() {
+            // Android-changed: Qualified ExpiringCache.Entry to distinguish from Map.Entry.
+            // There seems to be a compiler difference between javac and jack here;
+            // Map.Entry<String,Entry> doesn't work on jack since the latter "Entry" gets
+            // interpreted as referring to Map.Entry rather than ExpiringCache.Entry.
+            // protected boolean removeEldestEntry(Map.Entry<String,Entry> eldest) {
+            protected boolean removeEldestEntry(Map.Entry<String,ExpiringCache.Entry> eldest) {
+              return size() > MAX_ENTRIES;
+            }
+          };
+    }
+
+    synchronized String get(String key) {
+        if (++queryCount >= queryOverflow) {
+            cleanup();
+        }
+        Entry entry = entryFor(key);
+        if (entry != null) {
+            return entry.val();
+        }
+        return null;
+    }
+
+    synchronized void put(String key, String val) {
+        if (++queryCount >= queryOverflow) {
+            cleanup();
+        }
+        Entry entry = entryFor(key);
+        if (entry != null) {
+            entry.setTimestamp(System.currentTimeMillis());
+            entry.setVal(val);
+        } else {
+            map.put(key, new Entry(System.currentTimeMillis(), val));
+        }
+    }
+
+    synchronized void clear() {
+        map.clear();
+    }
+
+    private Entry entryFor(String key) {
+        Entry entry = map.get(key);
+        if (entry != null) {
+            long delta = System.currentTimeMillis() - entry.timestamp();
+            if (delta < 0 || delta >= millisUntilExpiration) {
+                map.remove(key);
+                entry = null;
+            }
+        }
+        return entry;
+    }
+
+    private void cleanup() {
+        Set<String> keySet = map.keySet();
+        // Avoid ConcurrentModificationExceptions
+        String[] keys = new String[keySet.size()];
+        int i = 0;
+        for (String key: keySet) {
+            keys[i++] = key;
+        }
+        for (int j = 0; j < keys.length; j++) {
+            entryFor(keys[j]);
+        }
+        queryCount = 0;
+    }
+}
diff --git a/java/io/Externalizable.java b/java/io/Externalizable.java
new file mode 100644
index 0000000..f9e88fe
--- /dev/null
+++ b/java/io/Externalizable.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.ObjectOutput;
+import java.io.ObjectInput;
+
+/**
+ * Only the identity of the class of an Externalizable instance is
+ * written in the serialization stream and it is the responsibility
+ * of the class to save and restore the contents of its instances.
+ *
+ * The writeExternal and readExternal methods of the Externalizable
+ * interface are implemented by a class to give the class complete
+ * control over the format and contents of the stream for an object
+ * and its supertypes. These methods must explicitly
+ * coordinate with the supertype to save its state. These methods supersede
+ * customized implementations of writeObject and readObject methods.<br>
+ *
+ * Object Serialization uses the Serializable and Externalizable
+ * interfaces.  Object persistence mechanisms can use them as well.  Each
+ * object to be stored is tested for the Externalizable interface. If
+ * the object supports Externalizable, the writeExternal method is called. If the
+ * object does not support Externalizable and does implement
+ * Serializable, the object is saved using
+ * ObjectOutputStream. <br> When an Externalizable object is
+ * reconstructed, an instance is created using the public no-arg
+ * constructor, then the readExternal method called.  Serializable
+ * objects are restored by reading them from an ObjectInputStream.<br>
+ *
+ * An Externalizable instance can designate a substitution object via
+ * the writeReplace and readResolve methods documented in the Serializable
+ * interface.<br>
+ *
+ * @author  unascribed
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @see java.io.ObjectOutput
+ * @see java.io.ObjectInput
+ * @see java.io.Serializable
+ * @since   JDK1.1
+ */
+public interface Externalizable extends java.io.Serializable {
+    /**
+     * The object implements the writeExternal method to save its contents
+     * by calling the methods of DataOutput for its primitive values or
+     * calling the writeObject method of ObjectOutput for objects, strings,
+     * and arrays.
+     *
+     * @serialData Overriding methods should use this tag to describe
+     *             the data layout of this Externalizable object.
+     *             List the sequence of element types and, if possible,
+     *             relate the element to a public/protected field and/or
+     *             method of this Externalizable class.
+     *
+     * @param out the stream to write the object to
+     * @exception IOException Includes any I/O exceptions that may occur
+     */
+    void writeExternal(ObjectOutput out) throws IOException;
+
+    /**
+     * The object implements the readExternal method to restore its
+     * contents by calling the methods of DataInput for primitive
+     * types and readObject for objects, strings and arrays.  The
+     * readExternal method must read the values in the same sequence
+     * and with the same types as were written by writeExternal.
+     *
+     * @param in the stream to read data from in order to restore the object
+     * @exception IOException if I/O errors occur
+     * @exception ClassNotFoundException If the class for an object being
+     *              restored cannot be found.
+     */
+    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
+}
diff --git a/java/io/File.annotated.java b/java/io/File.annotated.java
new file mode 100644
index 0000000..497c434
--- /dev/null
+++ b/java/io/File.annotated.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+import java.nio.file.Path;
+import java.net.URI;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.FileSystems;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class File implements java.io.Serializable, java.lang.Comparable<java.io.File> {
+
+public File(@libcore.util.NonNull java.lang.String pathname) { throw new RuntimeException("Stub!"); }
+
+public File(@libcore.util.Nullable java.lang.String parent, @libcore.util.NonNull java.lang.String child) { throw new RuntimeException("Stub!"); }
+
+public File(@libcore.util.Nullable java.io.File parent, @libcore.util.NonNull java.lang.String child) { throw new RuntimeException("Stub!"); }
+
+public File(@libcore.util.NonNull java.net.URI uri) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getParent() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.File getParentFile() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getPath() { throw new RuntimeException("Stub!"); }
+
+public boolean isAbsolute() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getAbsolutePath() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.File getAbsoluteFile() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getCanonicalPath() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.File getCanonicalFile() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
[email protected] public java.net.URL toURL() throws java.net.MalformedURLException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.net.URI toURI() { throw new RuntimeException("Stub!"); }
+
+public boolean canRead() { throw new RuntimeException("Stub!"); }
+
+public boolean canWrite() { throw new RuntimeException("Stub!"); }
+
+public boolean exists() { throw new RuntimeException("Stub!"); }
+
+public boolean isDirectory() { throw new RuntimeException("Stub!"); }
+
+public boolean isFile() { throw new RuntimeException("Stub!"); }
+
+public boolean isHidden() { throw new RuntimeException("Stub!"); }
+
+public long lastModified() { throw new RuntimeException("Stub!"); }
+
+public long length() { throw new RuntimeException("Stub!"); }
+
+public boolean createNewFile() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public boolean delete() { throw new RuntimeException("Stub!"); }
+
+public void deleteOnExit() { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.Nullable [] list() { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.Nullable [] list(@libcore.util.Nullable java.io.FilenameFilter filter) { throw new RuntimeException("Stub!"); }
+
+public [email protected] File @libcore.util.Nullable [] listFiles() { throw new RuntimeException("Stub!"); }
+
+public [email protected] File @libcore.util.Nullable [] listFiles(@libcore.util.Nullable java.io.FilenameFilter filter) { throw new RuntimeException("Stub!"); }
+
+public [email protected] File @libcore.util.Nullable [] listFiles(@libcore.util.Nullable java.io.FileFilter filter) { throw new RuntimeException("Stub!"); }
+
+public boolean mkdir() { throw new RuntimeException("Stub!"); }
+
+public boolean mkdirs() { throw new RuntimeException("Stub!"); }
+
+public boolean renameTo(@libcore.util.NonNull java.io.File dest) { throw new RuntimeException("Stub!"); }
+
+public boolean setLastModified(long time) { throw new RuntimeException("Stub!"); }
+
+public boolean setReadOnly() { throw new RuntimeException("Stub!"); }
+
+public boolean setWritable(boolean writable, boolean ownerOnly) { throw new RuntimeException("Stub!"); }
+
+public boolean setWritable(boolean writable) { throw new RuntimeException("Stub!"); }
+
+public boolean setReadable(boolean readable, boolean ownerOnly) { throw new RuntimeException("Stub!"); }
+
+public boolean setReadable(boolean readable) { throw new RuntimeException("Stub!"); }
+
+public boolean setExecutable(boolean executable, boolean ownerOnly) { throw new RuntimeException("Stub!"); }
+
+public boolean setExecutable(boolean executable) { throw new RuntimeException("Stub!"); }
+
+public boolean canExecute() { throw new RuntimeException("Stub!"); }
+
+public static [email protected] File @libcore.util.NonNull [] listRoots() { throw new RuntimeException("Stub!"); }
+
+public long getTotalSpace() { throw new RuntimeException("Stub!"); }
+
+public long getFreeSpace() { throw new RuntimeException("Stub!"); }
+
+public long getUsableSpace() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.io.File createTempFile(@libcore.util.NonNull java.lang.String prefix, @libcore.util.Nullable java.lang.String suffix, @libcore.util.Nullable java.io.File directory) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.io.File createTempFile(@libcore.util.NonNull java.lang.String prefix, @libcore.util.Nullable java.lang.String suffix) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.io.File pathname) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.nio.file.Path toPath() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.lang.String pathSeparator;
+static { pathSeparator = null; }
+
+public static final char pathSeparatorChar;
+static { pathSeparatorChar = 0; }
+
[email protected] public static final java.lang.String separator;
+static { separator = null; }
+
+public static final char separatorChar;
+static { separatorChar = 0; }
+}
diff --git a/java/io/File.java b/java/io/File.java
new file mode 100644
index 0000000..98956ca
--- /dev/null
+++ b/java/io/File.java
@@ -0,0 +1,2235 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.net.URI;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.ArrayList;
+import java.security.AccessController;
+import java.nio.file.Path;
+import java.nio.file.FileSystems;
+import sun.security.action.GetPropertyAction;
+
+// Android-added: Info about UTF-8 usage in filenames.
+/**
+ * An abstract representation of file and directory pathnames.
+ *
+ * <p> User interfaces and operating systems use system-dependent <em>pathname
+ * strings</em> to name files and directories.  This class presents an
+ * abstract, system-independent view of hierarchical pathnames.  An
+ * <em>abstract pathname</em> has two components:
+ *
+ * <ol>
+ * <li> An optional system-dependent <em>prefix</em> string,
+ *      such as a disk-drive specifier, <code>"/"</code>&nbsp;for the UNIX root
+ *      directory, or <code>"\\\\"</code>&nbsp;for a Microsoft Windows UNC pathname, and
+ * <li> A sequence of zero or more string <em>names</em>.
+ * </ol>
+ *
+ * The first name in an abstract pathname may be a directory name or, in the
+ * case of Microsoft Windows UNC pathnames, a hostname.  Each subsequent name
+ * in an abstract pathname denotes a directory; the last name may denote
+ * either a directory or a file.  The <em>empty</em> abstract pathname has no
+ * prefix and an empty name sequence.
+ *
+ * <p> The conversion of a pathname string to or from an abstract pathname is
+ * inherently system-dependent.  When an abstract pathname is converted into a
+ * pathname string, each name is separated from the next by a single copy of
+ * the default <em>separator character</em>.  The default name-separator
+ * character is defined by the system property <code>file.separator</code>, and
+ * is made available in the public static fields <code>{@link
+ * #separator}</code> and <code>{@link #separatorChar}</code> of this class.
+ * When a pathname string is converted into an abstract pathname, the names
+ * within it may be separated by the default name-separator character or by any
+ * other name-separator character that is supported by the underlying system.
+ *
+ * <p> A pathname, whether abstract or in string form, may be either
+ * <em>absolute</em> or <em>relative</em>.  An absolute pathname is complete in
+ * that no other information is required in order to locate the file that it
+ * denotes.  A relative pathname, in contrast, must be interpreted in terms of
+ * information taken from some other pathname.  By default the classes in the
+ * <code>java.io</code> package always resolve relative pathnames against the
+ * current user directory.  This directory is named by the system property
+ * <code>user.dir</code>, and is typically the directory in which the Java
+ * virtual machine was invoked.
+ *
+ * <p> The <em>parent</em> of an abstract pathname may be obtained by invoking
+ * the {@link #getParent} method of this class and consists of the pathname's
+ * prefix and each name in the pathname's name sequence except for the last.
+ * Each directory's absolute pathname is an ancestor of any <tt>File</tt>
+ * object with an absolute abstract pathname which begins with the directory's
+ * absolute pathname.  For example, the directory denoted by the abstract
+ * pathname <tt>"/usr"</tt> is an ancestor of the directory denoted by the
+ * pathname <tt>"/usr/local/bin"</tt>.
+ *
+ * <p> The prefix concept is used to handle root directories on UNIX platforms,
+ * and drive specifiers, root directories and UNC pathnames on Microsoft Windows platforms,
+ * as follows:
+ *
+ * <ul>
+ *
+ * <li> For UNIX platforms, the prefix of an absolute pathname is always
+ * <code>"/"</code>.  Relative pathnames have no prefix.  The abstract pathname
+ * denoting the root directory has the prefix <code>"/"</code> and an empty
+ * name sequence.
+ *
+ * <li> For Microsoft Windows platforms, the prefix of a pathname that contains a drive
+ * specifier consists of the drive letter followed by <code>":"</code> and
+ * possibly followed by <code>"\\"</code> if the pathname is absolute.  The
+ * prefix of a UNC pathname is <code>"\\\\"</code>; the hostname and the share
+ * name are the first two names in the name sequence.  A relative pathname that
+ * does not specify a drive has no prefix.
+ *
+ * </ul>
+ *
+ * <p> Instances of this class may or may not denote an actual file-system
+ * object such as a file or a directory.  If it does denote such an object
+ * then that object resides in a <i>partition</i>.  A partition is an
+ * operating system-specific portion of storage for a file system.  A single
+ * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may
+ * contain multiple partitions.  The object, if any, will reside on the
+ * partition <a name="partName">named</a> by some ancestor of the absolute
+ * form of this pathname.
+ *
+ * <p> A file system may implement restrictions to certain operations on the
+ * actual file-system object, such as reading, writing, and executing.  These
+ * restrictions are collectively known as <i>access permissions</i>.  The file
+ * system may have multiple sets of access permissions on a single object.
+ * For example, one set may apply to the object's <i>owner</i>, and another
+ * may apply to all other users.  The access permissions on an object may
+ * cause some methods in this class to fail.
+ *
+ * <p> Instances of the <code>File</code> class are immutable; that is, once
+ * created, the abstract pathname represented by a <code>File</code> object
+ * will never change.
+ *
+ * <h3>Interoperability with {@code java.nio.file} package</h3>
+ *
+ * <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
+ * package defines interfaces and classes for the Java virtual machine to access
+ * files, file attributes, and file systems. This API may be used to overcome
+ * many of the limitations of the {@code java.io.File} class.
+ * The {@link #toPath toPath} method may be used to obtain a {@link
+ * Path} that uses the abstract path represented by a {@code File} object to
+ * locate a file. The resulting {@code Path} may be used with the {@link
+ * java.nio.file.Files} class to provide more efficient and extensive access to
+ * additional file operations, file attributes, and I/O exceptions to help
+ * diagnose errors when an operation on a file fails.
+ *
+ * <p>On Android strings are converted to UTF-8 byte sequences when sending filenames to
+ * the operating system, and byte sequences returned by the operating system (from the
+ * various {@code list} methods) are converted to strings by decoding them as UTF-8
+ * byte sequences.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+
+public class File
+    implements Serializable, Comparable<File>
+{
+
+    /**
+     * The FileSystem object representing the platform's local file system.
+     */
+    private static final FileSystem fs = DefaultFileSystem.getFileSystem();
+
+    /**
+     * This abstract pathname's normalized pathname string. A normalized
+     * pathname string uses the default name-separator character and does not
+     * contain any duplicate or redundant separators.
+     *
+     * @serial
+     */
+    private final String path;
+
+    /**
+     * Enum type that indicates the status of a file path.
+     */
+    private static enum PathStatus { INVALID, CHECKED };
+
+    /**
+     * The flag indicating whether the file path is invalid.
+     */
+    private transient PathStatus status = null;
+
+    /**
+     * Check if the file has an invalid path. Currently, the inspection of
+     * a file path is very limited, and it only covers Nul character check.
+     * Returning true means the path is definitely invalid/garbage. But
+     * returning false does not guarantee that the path is valid.
+     *
+     * @return true if the file path is invalid.
+     */
+    final boolean isInvalid() {
+        if (status == null) {
+            status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED
+                                                       : PathStatus.INVALID;
+        }
+        return status == PathStatus.INVALID;
+    }
+
+    /**
+     * The length of this abstract pathname's prefix, or zero if it has no
+     * prefix.
+     */
+    private final transient int prefixLength;
+
+    /**
+     * Returns the length of this abstract pathname's prefix.
+     * For use by FileSystem classes.
+     */
+    int getPrefixLength() {
+        return prefixLength;
+    }
+
+    /**
+     * The system-dependent default name-separator character.  This field is
+     * initialized to contain the first character of the value of the system
+     * property <code>file.separator</code>.  On UNIX systems the value of this
+     * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>.
+     *
+     * @see     java.lang.System#getProperty(java.lang.String)
+     */
+    public static final char separatorChar = fs.getSeparator();
+
+    /**
+     * The system-dependent default name-separator character, represented as a
+     * string for convenience.  This string contains a single character, namely
+     * <code>{@link #separatorChar}</code>.
+     */
+    public static final String separator = "" + separatorChar;
+
+    /**
+     * The system-dependent path-separator character.  This field is
+     * initialized to contain the first character of the value of the system
+     * property <code>path.separator</code>.  This character is used to
+     * separate filenames in a sequence of files given as a <em>path list</em>.
+     * On UNIX systems, this character is <code>':'</code>; on Microsoft Windows systems it
+     * is <code>';'</code>.
+     *
+     * @see     java.lang.System#getProperty(java.lang.String)
+     */
+    public static final char pathSeparatorChar = fs.getPathSeparator();
+
+    /**
+     * The system-dependent path-separator character, represented as a string
+     * for convenience.  This string contains a single character, namely
+     * <code>{@link #pathSeparatorChar}</code>.
+     */
+    public static final String pathSeparator = "" + pathSeparatorChar;
+
+
+    /* -- Constructors -- */
+
+    /**
+     * Internal constructor for already-normalized pathname strings.
+     */
+    private File(String pathname, int prefixLength) {
+        this.path = pathname;
+        this.prefixLength = prefixLength;
+    }
+
+    /**
+     * Internal constructor for already-normalized pathname strings.
+     * The parameter order is used to disambiguate this method from the
+     * public(File, String) constructor.
+     */
+    private File(String child, File parent) {
+        assert parent.path != null;
+        assert (!parent.path.equals(""));
+        this.path = fs.resolve(parent.path, child);
+        this.prefixLength = parent.prefixLength;
+    }
+
+    /**
+     * Creates a new <code>File</code> instance by converting the given
+     * pathname string into an abstract pathname.  If the given string is
+     * the empty string, then the result is the empty abstract pathname.
+     *
+     * @param   pathname  A pathname string
+     * @throws  NullPointerException
+     *          If the <code>pathname</code> argument is <code>null</code>
+     */
+    public File(String pathname) {
+        if (pathname == null) {
+            throw new NullPointerException();
+        }
+        this.path = fs.normalize(pathname);
+        this.prefixLength = fs.prefixLength(this.path);
+    }
+
+    /* Note: The two-argument File constructors do not interpret an empty
+       parent abstract pathname as the current user directory.  An empty parent
+       instead causes the child to be resolved against the system-dependent
+       directory defined by the FileSystem.getDefaultParent method.  On Unix
+       this default is "/", while on Microsoft Windows it is "\\".  This is required for
+       compatibility with the original behavior of this class. */
+
+    /**
+     * Creates a new <code>File</code> instance from a parent pathname string
+     * and a child pathname string.
+     *
+     * <p> If <code>parent</code> is <code>null</code> then the new
+     * <code>File</code> instance is created as if by invoking the
+     * single-argument <code>File</code> constructor on the given
+     * <code>child</code> pathname string.
+     *
+     * <p> Otherwise the <code>parent</code> pathname string is taken to denote
+     * a directory, and the <code>child</code> pathname string is taken to
+     * denote either a directory or a file.  If the <code>child</code> pathname
+     * string is absolute then it is converted into a relative pathname in a
+     * system-dependent way.  If <code>parent</code> is the empty string then
+     * the new <code>File</code> instance is created by converting
+     * <code>child</code> into an abstract pathname and resolving the result
+     * against a system-dependent default directory.  Otherwise each pathname
+     * string is converted into an abstract pathname and the child abstract
+     * pathname is resolved against the parent.
+     *
+     * @param   parent  The parent pathname string
+     * @param   child   The child pathname string
+     * @throws  NullPointerException
+     *          If <code>child</code> is <code>null</code>
+     */
+    public File(String parent, String child) {
+        if (child == null) {
+            throw new NullPointerException();
+        }
+        // BEGIN Android-changed: b/25859957, app-compat; don't substitute empty parent.
+        if (parent != null && !parent.isEmpty()) {
+            this.path = fs.resolve(fs.normalize(parent),
+                                   fs.normalize(child));
+        // END Android-changed: b/25859957, app-compat; don't substitute empty parent.
+        } else {
+            this.path = fs.normalize(child);
+        }
+        this.prefixLength = fs.prefixLength(this.path);
+    }
+
+    /**
+     * Creates a new <code>File</code> instance from a parent abstract
+     * pathname and a child pathname string.
+     *
+     * <p> If <code>parent</code> is <code>null</code> then the new
+     * <code>File</code> instance is created as if by invoking the
+     * single-argument <code>File</code> constructor on the given
+     * <code>child</code> pathname string.
+     *
+     * <p> Otherwise the <code>parent</code> abstract pathname is taken to
+     * denote a directory, and the <code>child</code> pathname string is taken
+     * to denote either a directory or a file.  If the <code>child</code>
+     * pathname string is absolute then it is converted into a relative
+     * pathname in a system-dependent way.  If <code>parent</code> is the empty
+     * abstract pathname then the new <code>File</code> instance is created by
+     * converting <code>child</code> into an abstract pathname and resolving
+     * the result against a system-dependent default directory.  Otherwise each
+     * pathname string is converted into an abstract pathname and the child
+     * abstract pathname is resolved against the parent.
+     *
+     * @param   parent  The parent abstract pathname
+     * @param   child   The child pathname string
+     * @throws  NullPointerException
+     *          If <code>child</code> is <code>null</code>
+     */
+    public File(File parent, String child) {
+        if (child == null) {
+            throw new NullPointerException();
+        }
+        if (parent != null) {
+            if (parent.path.equals("")) {
+                this.path = fs.resolve(fs.getDefaultParent(),
+                                       fs.normalize(child));
+            } else {
+                this.path = fs.resolve(parent.path,
+                                       fs.normalize(child));
+            }
+        } else {
+            this.path = fs.normalize(child);
+        }
+        this.prefixLength = fs.prefixLength(this.path);
+    }
+
+    /**
+     * Creates a new <tt>File</tt> instance by converting the given
+     * <tt>file:</tt> URI into an abstract pathname.
+     *
+     * <p> The exact form of a <tt>file:</tt> URI is system-dependent, hence
+     * the transformation performed by this constructor is also
+     * system-dependent.
+     *
+     * <p> For a given abstract pathname <i>f</i> it is guaranteed that
+     *
+     * <blockquote><tt>
+     * new File(</tt><i>&nbsp;f</i><tt>.{@link #toURI() toURI}()).equals(</tt><i>&nbsp;f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
+     * </tt></blockquote>
+     *
+     * so long as the original abstract pathname, the URI, and the new abstract
+     * pathname are all created in (possibly different invocations of) the same
+     * Java virtual machine.  This relationship typically does not hold,
+     * however, when a <tt>file:</tt> URI that is created in a virtual machine
+     * on one operating system is converted into an abstract pathname in a
+     * virtual machine on a different operating system.
+     *
+     * @param  uri
+     *         An absolute, hierarchical URI with a scheme equal to
+     *         <tt>"file"</tt>, a non-empty path component, and undefined
+     *         authority, query, and fragment components
+     *
+     * @throws  NullPointerException
+     *          If <tt>uri</tt> is <tt>null</tt>
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameter do not hold
+     *
+     * @see #toURI()
+     * @see java.net.URI
+     * @since 1.4
+     */
+    public File(URI uri) {
+
+        // Check our many preconditions
+        if (!uri.isAbsolute())
+            throw new IllegalArgumentException("URI is not absolute");
+        if (uri.isOpaque())
+            throw new IllegalArgumentException("URI is not hierarchical");
+        String scheme = uri.getScheme();
+        if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
+            throw new IllegalArgumentException("URI scheme is not \"file\"");
+        if (uri.getAuthority() != null)
+            throw new IllegalArgumentException("URI has an authority component");
+        if (uri.getFragment() != null)
+            throw new IllegalArgumentException("URI has a fragment component");
+        if (uri.getQuery() != null)
+            throw new IllegalArgumentException("URI has a query component");
+        String p = uri.getPath();
+        if (p.equals(""))
+            throw new IllegalArgumentException("URI path component is empty");
+
+        // Okay, now initialize
+        p = fs.fromURIPath(p);
+        if (File.separatorChar != '/')
+            p = p.replace('/', File.separatorChar);
+        this.path = fs.normalize(p);
+        this.prefixLength = fs.prefixLength(this.path);
+    }
+
+
+    /* -- Path-component accessors -- */
+
+    /**
+     * Returns the name of the file or directory denoted by this abstract
+     * pathname.  This is just the last name in the pathname's name
+     * sequence.  If the pathname's name sequence is empty, then the empty
+     * string is returned.
+     *
+     * @return  The name of the file or directory denoted by this abstract
+     *          pathname, or the empty string if this pathname's name sequence
+     *          is empty
+     */
+    public String getName() {
+        int index = path.lastIndexOf(separatorChar);
+        if (index < prefixLength) return path.substring(prefixLength);
+        return path.substring(index + 1);
+    }
+
+    /**
+     * Returns the pathname string of this abstract pathname's parent, or
+     * <code>null</code> if this pathname does not name a parent directory.
+     *
+     * <p> The <em>parent</em> of an abstract pathname consists of the
+     * pathname's prefix, if any, and each name in the pathname's name
+     * sequence except for the last.  If the name sequence is empty then
+     * the pathname does not name a parent directory.
+     *
+     * @return  The pathname string of the parent directory named by this
+     *          abstract pathname, or <code>null</code> if this pathname
+     *          does not name a parent
+     */
+    public String getParent() {
+        int index = path.lastIndexOf(separatorChar);
+        if (index < prefixLength) {
+            if ((prefixLength > 0) && (path.length() > prefixLength))
+                return path.substring(0, prefixLength);
+            return null;
+        }
+        return path.substring(0, index);
+    }
+
+    /**
+     * Returns the abstract pathname of this abstract pathname's parent,
+     * or <code>null</code> if this pathname does not name a parent
+     * directory.
+     *
+     * <p> The <em>parent</em> of an abstract pathname consists of the
+     * pathname's prefix, if any, and each name in the pathname's name
+     * sequence except for the last.  If the name sequence is empty then
+     * the pathname does not name a parent directory.
+     *
+     * @return  The abstract pathname of the parent directory named by this
+     *          abstract pathname, or <code>null</code> if this pathname
+     *          does not name a parent
+     *
+     * @since 1.2
+     */
+    public File getParentFile() {
+        String p = this.getParent();
+        if (p == null) return null;
+        return new File(p, this.prefixLength);
+    }
+
+    /**
+     * Converts this abstract pathname into a pathname string.  The resulting
+     * string uses the {@link #separator default name-separator character} to
+     * separate the names in the name sequence.
+     *
+     * @return  The string form of this abstract pathname
+     */
+    public String getPath() {
+        return path;
+    }
+
+
+    /* -- Path operations -- */
+
+    // Android-changed: Android-specific path information
+    /**
+     * Tests whether this abstract pathname is absolute.  The definition of
+     * absolute pathname is system dependent.  On Android, absolute paths start with
+     * the character '/'.
+     *
+     * @return  <code>true</code> if this abstract pathname is absolute,
+     *          <code>false</code> otherwise
+     */
+    public boolean isAbsolute() {
+        return fs.isAbsolute(this);
+    }
+
+    // Android-changed: Android-specific path information
+    /**
+     * Returns the absolute path of this file. An absolute path is a path that starts at a root
+     * of the file system. On Android, there is only one root: {@code /}.
+     *
+     * <p>A common use for absolute paths is when passing paths to a {@code Process} as
+     * command-line arguments, to remove the requirement implied by relative paths, that the
+     * child must have the same working directory as its parent.
+     *
+     * @return  The absolute pathname string denoting the same file or
+     *          directory as this abstract pathname
+     *
+     * @see     java.io.File#isAbsolute()
+     */
+    public String getAbsolutePath() {
+        return fs.resolve(this);
+    }
+
+    /**
+     * Returns the absolute form of this abstract pathname.  Equivalent to
+     * <code>new&nbsp;File(this.{@link #getAbsolutePath})</code>.
+     *
+     * @return  The absolute abstract pathname denoting the same file or
+     *          directory as this abstract pathname
+     *
+     * @throws  SecurityException
+     *          If a required system property value cannot be accessed.
+     *
+     * @since 1.2
+     */
+    public File getAbsoluteFile() {
+        String absPath = getAbsolutePath();
+        return new File(absPath, fs.prefixLength(absPath));
+    }
+
+    /**
+     * Returns the canonical pathname string of this abstract pathname.
+     *
+     * <p> A canonical pathname is both absolute and unique.  The precise
+     * definition of canonical form is system-dependent.  This method first
+     * converts this pathname to absolute form if necessary, as if by invoking the
+     * {@link #getAbsolutePath} method, and then maps it to its unique form in a
+     * system-dependent way.  This typically involves removing redundant names
+     * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving
+     * symbolic links (on UNIX platforms), and converting drive letters to a
+     * standard case (on Microsoft Windows platforms).
+     *
+     * <p> Every pathname that denotes an existing file or directory has a
+     * unique canonical form.  Every pathname that denotes a nonexistent file
+     * or directory also has a unique canonical form.  The canonical form of
+     * the pathname of a nonexistent file or directory may be different from
+     * the canonical form of the same pathname after the file or directory is
+     * created.  Similarly, the canonical form of the pathname of an existing
+     * file or directory may be different from the canonical form of the same
+     * pathname after the file or directory is deleted.
+     *
+     * @return  The canonical pathname string denoting the same file or
+     *          directory as this abstract pathname
+     *
+     * @throws  IOException
+     *          If an I/O error occurs, which is possible because the
+     *          construction of the canonical pathname may require
+     *          filesystem queries
+     *
+     * @throws  SecurityException
+     *          If a required system property value cannot be accessed, or
+     *          if a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead}</code> method denies
+     *          read access to the file
+     *
+     * @since   JDK1.1
+     * @see     Path#toRealPath
+     */
+    public String getCanonicalPath() throws IOException {
+        if (isInvalid()) {
+            throw new IOException("Invalid file path");
+        }
+        return fs.canonicalize(fs.resolve(this));
+    }
+
+    /**
+     * Returns the canonical form of this abstract pathname.  Equivalent to
+     * <code>new&nbsp;File(this.{@link #getCanonicalPath})</code>.
+     *
+     * @return  The canonical pathname string denoting the same file or
+     *          directory as this abstract pathname
+     *
+     * @throws  IOException
+     *          If an I/O error occurs, which is possible because the
+     *          construction of the canonical pathname may require
+     *          filesystem queries
+     *
+     * @throws  SecurityException
+     *          If a required system property value cannot be accessed, or
+     *          if a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead}</code> method denies
+     *          read access to the file
+     *
+     * @since 1.2
+     * @see     Path#toRealPath
+     */
+    public File getCanonicalFile() throws IOException {
+        String canonPath = getCanonicalPath();
+        return new File(canonPath, fs.prefixLength(canonPath));
+    }
+
+    private static String slashify(String path, boolean isDirectory) {
+        String p = path;
+        if (File.separatorChar != '/')
+            p = p.replace(File.separatorChar, '/');
+        if (!p.startsWith("/"))
+            p = "/" + p;
+        if (!p.endsWith("/") && isDirectory)
+            p = p + "/";
+        return p;
+    }
+
+    /**
+     * Converts this abstract pathname into a <code>file:</code> URL.  The
+     * exact form of the URL is system-dependent.  If it can be determined that
+     * the file denoted by this abstract pathname is a directory, then the
+     * resulting URL will end with a slash.
+     *
+     * @return  A URL object representing the equivalent file URL
+     *
+     * @throws  MalformedURLException
+     *          If the path cannot be parsed as a URL
+     *
+     * @see     #toURI()
+     * @see     java.net.URI
+     * @see     java.net.URI#toURL()
+     * @see     java.net.URL
+     * @since   1.2
+     *
+     * @deprecated This method does not automatically escape characters that
+     * are illegal in URLs.  It is recommended that new code convert an
+     * abstract pathname into a URL by first converting it into a URI, via the
+     * {@link #toURI() toURI} method, and then converting the URI into a URL
+     * via the {@link java.net.URI#toURL() URI.toURL} method.
+     */
+    @Deprecated
+    public URL toURL() throws MalformedURLException {
+        if (isInvalid()) {
+            throw new MalformedURLException("Invalid file path");
+        }
+        // Android-changed: Fix for new File("").toURL().
+        // return new URL("file", "", slashify(getAbsolutePath(), isDirectory()));
+        return new URL("file", "", slashify(getAbsolutePath(),
+                getAbsoluteFile().isDirectory()));
+    }
+
+    /**
+     * Constructs a <tt>file:</tt> URI that represents this abstract pathname.
+     *
+     * <p> The exact form of the URI is system-dependent.  If it can be
+     * determined that the file denoted by this abstract pathname is a
+     * directory, then the resulting URI will end with a slash.
+     *
+     * <p> For a given abstract pathname <i>f</i>, it is guaranteed that
+     *
+     * <blockquote><tt>
+     * new {@link #File(java.net.URI) File}(</tt><i>&nbsp;f</i><tt>.toURI()).equals(</tt><i>&nbsp;f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
+     * </tt></blockquote>
+     *
+     * so long as the original abstract pathname, the URI, and the new abstract
+     * pathname are all created in (possibly different invocations of) the same
+     * Java virtual machine.  Due to the system-dependent nature of abstract
+     * pathnames, however, this relationship typically does not hold when a
+     * <tt>file:</tt> URI that is created in a virtual machine on one operating
+     * system is converted into an abstract pathname in a virtual machine on a
+     * different operating system.
+     *
+     * <p> Note that when this abstract pathname represents a UNC pathname then
+     * all components of the UNC (including the server name component) are encoded
+     * in the {@code URI} path. The authority component is undefined, meaning
+     * that it is represented as {@code null}. The {@link Path} class defines the
+     * {@link Path#toUri toUri} method to encode the server name in the authority
+     * component of the resulting {@code URI}. The {@link #toPath toPath} method
+     * may be used to obtain a {@code Path} representing this abstract pathname.
+     *
+     * @return  An absolute, hierarchical URI with a scheme equal to
+     *          <tt>"file"</tt>, a path representing this abstract pathname,
+     *          and undefined authority, query, and fragment components
+     * @throws SecurityException If a required system property value cannot
+     * be accessed.
+     *
+     * @see #File(java.net.URI)
+     * @see java.net.URI
+     * @see java.net.URI#toURL()
+     * @since 1.4
+     */
+    public URI toURI() {
+        try {
+            File f = getAbsoluteFile();
+            String sp = slashify(f.getPath(), f.isDirectory());
+            if (sp.startsWith("//"))
+                sp = "//" + sp;
+            return new URI("file", null, sp, null);
+        } catch (URISyntaxException x) {
+            throw new Error(x);         // Can't happen
+        }
+    }
+
+
+    /* -- Attribute accessors -- */
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on android
+    /**
+     * Tests whether the application can read the file denoted by this
+     * abstract pathname.
+     *
+     * @return  <code>true</code> if and only if the file specified by this
+     *          abstract pathname exists <em>and</em> can be read by the
+     *          application; <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file
+     */
+    public boolean canRead() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.checkAccess(this, FileSystem.ACCESS_READ);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on android
+    /**
+     * Tests whether the application can modify the file denoted by this
+     * abstract pathname.
+     *
+     * @return  <code>true</code> if and only if the file system actually
+     *          contains a file denoted by this abstract pathname <em>and</em>
+     *          the application is allowed to write to the file;
+     *          <code>false</code> otherwise.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     */
+    public boolean canWrite() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.checkAccess(this, FileSystem.ACCESS_WRITE);
+    }
+
+    /**
+     * Tests whether the file or directory denoted by this abstract pathname
+     * exists.
+     *
+     * @return  <code>true</code> if and only if the file or directory denoted
+     *          by this abstract pathname exists; <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file or directory
+     */
+    public boolean exists() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+
+        // Android-changed: b/25878034 work around SELinux stat64 denial.
+        return fs.checkAccess(this, FileSystem.ACCESS_OK);
+    }
+
+    /**
+     * Tests whether the file denoted by this abstract pathname is a
+     * directory.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * that the file is not a directory, or where several attributes of the
+     * same file are required at the same time, then the {@link
+     * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+     * Files.readAttributes} method may be used.
+     *
+     * @return <code>true</code> if and only if the file denoted by this
+     *          abstract pathname exists <em>and</em> is a directory;
+     *          <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file
+     */
+    public boolean isDirectory() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return ((fs.getBooleanAttributes(this) & FileSystem.BA_DIRECTORY)
+                != 0);
+    }
+
+    /**
+     * Tests whether the file denoted by this abstract pathname is a normal
+     * file.  A file is <em>normal</em> if it is not a directory and, in
+     * addition, satisfies other system-dependent criteria.  Any non-directory
+     * file created by a Java application is guaranteed to be a normal file.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * that the file is not a normal file, or where several attributes of the
+     * same file are required at the same time, then the {@link
+     * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+     * Files.readAttributes} method may be used.
+     *
+     * @return  <code>true</code> if and only if the file denoted by this
+     *          abstract pathname exists <em>and</em> is a normal file;
+     *          <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file
+     */
+    public boolean isFile() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return ((fs.getBooleanAttributes(this) & FileSystem.BA_REGULAR) != 0);
+    }
+
+    /**
+     * Tests whether the file named by this abstract pathname is a hidden
+     * file.  The exact definition of <em>hidden</em> is system-dependent.  On
+     * UNIX systems, a file is considered to be hidden if its name begins with
+     * a period character (<code>'.'</code>).  On Microsoft Windows systems, a file is
+     * considered to be hidden if it has been marked as such in the filesystem.
+     *
+     * @return  <code>true</code> if and only if the file denoted by this
+     *          abstract pathname is hidden according to the conventions of the
+     *          underlying platform
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file
+     *
+     * @since 1.2
+     */
+    public boolean isHidden() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return ((fs.getBooleanAttributes(this) & FileSystem.BA_HIDDEN) != 0);
+    }
+
+    /**
+     * Returns the time that the file denoted by this abstract pathname was
+     * last modified.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * where {@code 0L} is returned, or where several attributes of the
+     * same file are required at the same time, or where the time of last
+     * access or the creation time are required, then the {@link
+     * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+     * Files.readAttributes} method may be used.
+     *
+     * @return  A <code>long</code> value representing the time the file was
+     *          last modified, measured in milliseconds since the epoch
+     *          (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the
+     *          file does not exist or if an I/O error occurs
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file
+     */
+    public long lastModified() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return 0L;
+        }
+        return fs.getLastModifiedTime(this);
+    }
+
+    /**
+     * Returns the length of the file denoted by this abstract pathname.
+     * The return value is unspecified if this pathname denotes a directory.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * that {@code 0L} is returned, or where several attributes of the same file
+     * are required at the same time, then the {@link
+     * java.nio.file.Files#readAttributes(Path,Class,LinkOption[])
+     * Files.readAttributes} method may be used.
+     *
+     * @return  The length, in bytes, of the file denoted by this abstract
+     *          pathname, or <code>0L</code> if the file does not exist.  Some
+     *          operating systems may return <code>0L</code> for pathnames
+     *          denoting system-dependent entities such as devices or pipes.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method denies read access to the file
+     */
+    public long length() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return 0L;
+        }
+        return fs.getLength(this);
+    }
+
+
+    /* -- File operations -- */
+
+    /**
+     * Atomically creates a new, empty file named by this abstract pathname if
+     * and only if a file with this name does not yet exist.  The check for the
+     * existence of the file and the creation of the file if it does not exist
+     * are a single operation that is atomic with respect to all other
+     * filesystem activities that might affect the file.
+     * <P>
+     * Note: this method should <i>not</i> be used for file-locking, as
+     * the resulting protocol cannot be made to work reliably. The
+     * {@link java.nio.channels.FileLock FileLock}
+     * facility should be used instead.
+     *
+     * @return  <code>true</code> if the named file does not exist and was
+     *          successfully created; <code>false</code> if the named file
+     *          already exists
+     *
+     * @throws  IOException
+     *          If an I/O error occurred
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     *
+     * @since 1.2
+     */
+    public boolean createNewFile() throws IOException {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) security.checkWrite(path);
+        if (isInvalid()) {
+            throw new IOException("Invalid file path");
+        }
+        return fs.createFileExclusively(path);
+    }
+
+    /**
+     * Deletes the file or directory denoted by this abstract pathname.  If
+     * this pathname denotes a directory, then the directory must be empty in
+     * order to be deleted.
+     *
+     * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+     * java.nio.file.Files#delete(Path) delete} method to throw an {@link IOException}
+     * when a file cannot be deleted. This is useful for error reporting and to
+     * diagnose why a file cannot be deleted.
+     *
+     * @return  <code>true</code> if and only if the file or directory is
+     *          successfully deleted; <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkDelete}</code> method denies
+     *          delete access to the file
+     */
+    public boolean delete() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkDelete(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.delete(this);
+    }
+
+    // Android-added: Additional information about Android behaviour.
+    /**
+     * Requests that the file or directory denoted by this abstract
+     * pathname be deleted when the virtual machine terminates.
+     * Files (or directories) are deleted in the reverse order that
+     * they are registered. Invoking this method to delete a file or
+     * directory that is already registered for deletion has no effect.
+     * Deletion will be attempted only for normal termination of the
+     * virtual machine, as defined by the Java Language Specification.
+     *
+     * <p> Once deletion has been requested, it is not possible to cancel the
+     * request.  This method should therefore be used with care.
+     *
+     * <P>
+     * Note: this method should <i>not</i> be used for file-locking, as
+     * the resulting protocol cannot be made to work reliably. The
+     * {@link java.nio.channels.FileLock FileLock}
+     * facility should be used instead.
+     *
+     * <p><i>Note that on Android, the application lifecycle does not include VM termination,
+     * so calling this method will not ensure that files are deleted</i>. Instead, you should
+     * use the most appropriate out of:
+     * <ul>
+     * <li>Use a {@code finally} clause to manually invoke {@link #delete}.
+     * <li>Maintain your own set of files to delete, and process it at an appropriate point
+     * in your application's lifecycle.
+     * <li>Use the Unix trick of deleting the file as soon as all readers and writers have
+     * opened it. No new readers/writers will be able to access the file, but all existing
+     * ones will still have access until the last one closes the file.
+     * </ul>
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkDelete}</code> method denies
+     *          delete access to the file
+     *
+     * @see #delete
+     *
+     * @since 1.2
+     */
+    public void deleteOnExit() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkDelete(path);
+        }
+        if (isInvalid()) {
+            return;
+        }
+        DeleteOnExitHook.add(path);
+    }
+
+    /**
+     * Returns an array of strings naming the files and directories in the
+     * directory denoted by this abstract pathname.
+     *
+     * <p> If this abstract pathname does not denote a directory, then this
+     * method returns {@code null}.  Otherwise an array of strings is
+     * returned, one for each file or directory in the directory.  Names
+     * denoting the directory itself and the directory's parent directory are
+     * not included in the result.  Each string is a file name rather than a
+     * complete path.
+     *
+     * <p> There is no guarantee that the name strings in the resulting array
+     * will appear in any specific order; they are not, in particular,
+     * guaranteed to appear in alphabetical order.
+     *
+     * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+     * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method to
+     * open a directory and iterate over the names of the files in the directory.
+     * This may use less resources when working with very large directories, and
+     * may be more responsive when working with remote directories.
+     *
+     * @return  An array of strings naming the files and directories in the
+     *          directory denoted by this abstract pathname.  The array will be
+     *          empty if the directory is empty.  Returns {@code null} if
+     *          this abstract pathname does not denote a directory, or if an
+     *          I/O error occurs.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its {@link
+     *          SecurityManager#checkRead(String)} method denies read access to
+     *          the directory
+     */
+    public String[] list() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(path);
+        }
+        if (isInvalid()) {
+            return null;
+        }
+        return fs.list(this);
+    }
+
+    /**
+     * Returns an array of strings naming the files and directories in the
+     * directory denoted by this abstract pathname that satisfy the specified
+     * filter.  The behavior of this method is the same as that of the
+     * {@link #list()} method, except that the strings in the returned array
+     * must satisfy the filter.  If the given {@code filter} is {@code null}
+     * then all names are accepted.  Otherwise, a name satisfies the filter if
+     * and only if the value {@code true} results when the {@link
+     * FilenameFilter#accept FilenameFilter.accept(File,&nbsp;String)} method
+     * of the filter is invoked on this abstract pathname and the name of a
+     * file or directory in the directory that it denotes.
+     *
+     * @param  filter
+     *         A filename filter
+     *
+     * @return  An array of strings naming the files and directories in the
+     *          directory denoted by this abstract pathname that were accepted
+     *          by the given {@code filter}.  The array will be empty if the
+     *          directory is empty or if no names were accepted by the filter.
+     *          Returns {@code null} if this abstract pathname does not denote
+     *          a directory, or if an I/O error occurs.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its {@link
+     *          SecurityManager#checkRead(String)} method denies read access to
+     *          the directory
+     *
+     * @see java.nio.file.Files#newDirectoryStream(Path,String)
+     */
+    public String[] list(FilenameFilter filter) {
+        String names[] = list();
+        if ((names == null) || (filter == null)) {
+            return names;
+        }
+        List<String> v = new ArrayList<>();
+        for (int i = 0 ; i < names.length ; i++) {
+            if (filter.accept(this, names[i])) {
+                v.add(names[i]);
+            }
+        }
+        return v.toArray(new String[v.size()]);
+    }
+
+    /**
+     * Returns an array of abstract pathnames denoting the files in the
+     * directory denoted by this abstract pathname.
+     *
+     * <p> If this abstract pathname does not denote a directory, then this
+     * method returns {@code null}.  Otherwise an array of {@code File} objects
+     * is returned, one for each file or directory in the directory.  Pathnames
+     * denoting the directory itself and the directory's parent directory are
+     * not included in the result.  Each resulting abstract pathname is
+     * constructed from this abstract pathname using the {@link #File(File,
+     * String) File(File,&nbsp;String)} constructor.  Therefore if this
+     * pathname is absolute then each resulting pathname is absolute; if this
+     * pathname is relative then each resulting pathname will be relative to
+     * the same directory.
+     *
+     * <p> There is no guarantee that the name strings in the resulting array
+     * will appear in any specific order; they are not, in particular,
+     * guaranteed to appear in alphabetical order.
+     *
+     * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+     * java.nio.file.Files#newDirectoryStream(Path) newDirectoryStream} method
+     * to open a directory and iterate over the names of the files in the
+     * directory. This may use less resources when working with very large
+     * directories.
+     *
+     * @return  An array of abstract pathnames denoting the files and
+     *          directories in the directory denoted by this abstract pathname.
+     *          The array will be empty if the directory is empty.  Returns
+     *          {@code null} if this abstract pathname does not denote a
+     *          directory, or if an I/O error occurs.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its {@link
+     *          SecurityManager#checkRead(String)} method denies read access to
+     *          the directory
+     *
+     * @since  1.2
+     */
+    public File[] listFiles() {
+        String[] ss = list();
+        if (ss == null) return null;
+        int n = ss.length;
+        File[] fs = new File[n];
+        for (int i = 0; i < n; i++) {
+            fs[i] = new File(ss[i], this);
+        }
+        return fs;
+    }
+
+    /**
+     * Returns an array of abstract pathnames denoting the files and
+     * directories in the directory denoted by this abstract pathname that
+     * satisfy the specified filter.  The behavior of this method is the same
+     * as that of the {@link #listFiles()} method, except that the pathnames in
+     * the returned array must satisfy the filter.  If the given {@code filter}
+     * is {@code null} then all pathnames are accepted.  Otherwise, a pathname
+     * satisfies the filter if and only if the value {@code true} results when
+     * the {@link FilenameFilter#accept
+     * FilenameFilter.accept(File,&nbsp;String)} method of the filter is
+     * invoked on this abstract pathname and the name of a file or directory in
+     * the directory that it denotes.
+     *
+     * @param  filter
+     *         A filename filter
+     *
+     * @return  An array of abstract pathnames denoting the files and
+     *          directories in the directory denoted by this abstract pathname.
+     *          The array will be empty if the directory is empty.  Returns
+     *          {@code null} if this abstract pathname does not denote a
+     *          directory, or if an I/O error occurs.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its {@link
+     *          SecurityManager#checkRead(String)} method denies read access to
+     *          the directory
+     *
+     * @since  1.2
+     * @see java.nio.file.Files#newDirectoryStream(Path,String)
+     */
+    public File[] listFiles(FilenameFilter filter) {
+        String ss[] = list();
+        if (ss == null) return null;
+        ArrayList<File> files = new ArrayList<>();
+        for (String s : ss)
+            if ((filter == null) || filter.accept(this, s))
+                files.add(new File(s, this));
+        return files.toArray(new File[files.size()]);
+    }
+
+    /**
+     * Returns an array of abstract pathnames denoting the files and
+     * directories in the directory denoted by this abstract pathname that
+     * satisfy the specified filter.  The behavior of this method is the same
+     * as that of the {@link #listFiles()} method, except that the pathnames in
+     * the returned array must satisfy the filter.  If the given {@code filter}
+     * is {@code null} then all pathnames are accepted.  Otherwise, a pathname
+     * satisfies the filter if and only if the value {@code true} results when
+     * the {@link FileFilter#accept FileFilter.accept(File)} method of the
+     * filter is invoked on the pathname.
+     *
+     * @param  filter
+     *         A file filter
+     *
+     * @return  An array of abstract pathnames denoting the files and
+     *          directories in the directory denoted by this abstract pathname.
+     *          The array will be empty if the directory is empty.  Returns
+     *          {@code null} if this abstract pathname does not denote a
+     *          directory, or if an I/O error occurs.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its {@link
+     *          SecurityManager#checkRead(String)} method denies read access to
+     *          the directory
+     *
+     * @since  1.2
+     * @see java.nio.file.Files#newDirectoryStream(Path,java.nio.file.DirectoryStream.Filter)
+     */
+    public File[] listFiles(FileFilter filter) {
+        String ss[] = list();
+        if (ss == null) return null;
+        ArrayList<File> files = new ArrayList<>();
+        for (String s : ss) {
+            File f = new File(s, this);
+            if ((filter == null) || filter.accept(f))
+                files.add(f);
+        }
+        return files.toArray(new File[files.size()]);
+    }
+
+    /**
+     * Creates the directory named by this abstract pathname.
+     *
+     * @return  <code>true</code> if and only if the directory was
+     *          created; <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method does not permit the named directory to be created
+     */
+    public boolean mkdir() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.createDirectory(this);
+    }
+
+    /**
+     * Creates the directory named by this abstract pathname, including any
+     * necessary but nonexistent parent directories.  Note that if this
+     * operation fails it may have succeeded in creating some of the necessary
+     * parent directories.
+     *
+     * @return  <code>true</code> if and only if the directory was created,
+     *          along with all necessary parent directories; <code>false</code>
+     *          otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
+     *          method does not permit verification of the existence of the
+     *          named directory and all necessary parent directories; or if
+     *          the <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method does not permit the named directory and all necessary
+     *          parent directories to be created
+     */
+    public boolean mkdirs() {
+        if (exists()) {
+            return false;
+        }
+        if (mkdir()) {
+            return true;
+        }
+        File canonFile = null;
+        try {
+            canonFile = getCanonicalFile();
+        } catch (IOException e) {
+            return false;
+        }
+
+        File parent = canonFile.getParentFile();
+        return (parent != null && (parent.mkdirs() || parent.exists()) &&
+                canonFile.mkdir());
+    }
+
+    // Android-changed: Replaced generic platform info with Android specific one.
+    /**
+     * Renames the file denoted by this abstract pathname.
+     *
+     * <p>Many failures are possible. Some of the more likely failures include:
+     * <ul>
+     * <li>Write permission is required on the directories containing both the source and
+     * destination paths.
+     * <li>Search permission is required for all parents of both paths.
+     * <li>Both paths be on the same mount point. On Android, applications are most likely to hit
+     * this restriction when attempting to copy between internal storage and an SD card.
+     * </ul>
+     *
+     * <p>The return value should always be checked to make sure
+     * that the rename operation was successful.
+     *
+     * <p> Note that the {@link java.nio.file.Files} class defines the {@link
+     * java.nio.file.Files#move move} method to move or rename a file in a
+     * platform independent manner.
+     *
+     * @param  dest  The new abstract pathname for the named file
+     *
+     * @return  <code>true</code> if and only if the renaming succeeded;
+     *          <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to either the old or new pathnames
+     *
+     * @throws  NullPointerException
+     *          If parameter <code>dest</code> is <code>null</code>
+     */
+    public boolean renameTo(File dest) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+            security.checkWrite(dest.path);
+        }
+        if (dest == null) {
+            throw new NullPointerException();
+        }
+        if (this.isInvalid() || dest.isInvalid()) {
+            return false;
+        }
+        return fs.rename(this, dest);
+    }
+
+    /**
+     * Sets the last-modified time of the file or directory named by this
+     * abstract pathname.
+     *
+     * <p> All platforms support file-modification times to the nearest second,
+     * but some provide more precision.  The argument will be truncated to fit
+     * the supported precision.  If the operation succeeds and no intervening
+     * operations on the file take place, then the next invocation of the
+     * <code>{@link #lastModified}</code> method will return the (possibly
+     * truncated) <code>time</code> argument that was passed to this method.
+     *
+     * @param  time  The new last-modified time, measured in milliseconds since
+     *               the epoch (00:00:00 GMT, January 1, 1970)
+     *
+     * @return <code>true</code> if and only if the operation succeeded;
+     *          <code>false</code> otherwise
+     *
+     * @throws  IllegalArgumentException  If the argument is negative
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the named file
+     *
+     * @since 1.2
+     */
+    public boolean setLastModified(long time) {
+        if (time < 0) throw new IllegalArgumentException("Negative time");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.setLastModifiedTime(this, time);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * Marks the file or directory named by this abstract pathname so that
+     * only read operations are allowed. After invoking this method the file
+     * or directory will not change until it is either deleted or marked
+     * to allow write access. Whether or not a read-only file or
+     * directory may be deleted depends upon the underlying system.
+     *
+     * @return <code>true</code> if and only if the operation succeeded;
+     *          <code>false</code> otherwise
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the named file
+     *
+     * @since 1.2
+     */
+    public boolean setReadOnly() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.setReadOnly(this);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * Sets the owner's or everybody's write permission for this abstract
+     * pathname.
+     *
+     * <p> The {@link java.nio.file.Files} class defines methods that operate on
+     * file attributes including file permissions. This may be used when finer
+     * manipulation of file permissions is required.
+     *
+     * @param   writable
+     *          If <code>true</code>, sets the access permission to allow write
+     *          operations; if <code>false</code> to disallow write operations
+     *
+     * @param   ownerOnly
+     *          If <code>true</code>, the write permission applies only to the
+     *          owner's write permission; otherwise, it applies to everybody.  If
+     *          the underlying file system can not distinguish the owner's write
+     *          permission from that of others, then the permission will apply to
+     *          everybody, regardless of this value.
+     *
+     * @return  <code>true</code> if and only if the operation succeeded. The
+     *          operation will fail if the user does not have permission to change
+     *          the access permissions of this abstract pathname.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the named file
+     *
+     * @since 1.6
+     */
+    public boolean setWritable(boolean writable, boolean ownerOnly) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * A convenience method to set the owner's write permission for this abstract
+     * pathname.
+     *
+     * <p> An invocation of this method of the form <tt>file.setWritable(arg)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     file.setWritable(arg, true) </pre>
+     *
+     * @param   writable
+     *          If <code>true</code>, sets the access permission to allow write
+     *          operations; if <code>false</code> to disallow write operations
+     *
+     * @return  <code>true</code> if and only if the operation succeeded.  The
+     *          operation will fail if the user does not have permission to
+     *          change the access permissions of this abstract pathname.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     *
+     * @since 1.6
+     */
+    public boolean setWritable(boolean writable) {
+        return setWritable(writable, true);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * Sets the owner's or everybody's read permission for this abstract
+     * pathname.
+     *
+     * <p> The {@link java.nio.file.Files} class defines methods that operate on
+     * file attributes including file permissions. This may be used when finer
+     * manipulation of file permissions is required.
+     *
+     * @param   readable
+     *          If <code>true</code>, sets the access permission to allow read
+     *          operations; if <code>false</code> to disallow read operations
+     *
+     * @param   ownerOnly
+     *          If <code>true</code>, the read permission applies only to the
+     *          owner's read permission; otherwise, it applies to everybody.  If
+     *          the underlying file system can not distinguish the owner's read
+     *          permission from that of others, then the permission will apply to
+     *          everybody, regardless of this value.
+     *
+     * @return  <code>true</code> if and only if the operation succeeded.  The
+     *          operation will fail if the user does not have permission to
+     *          change the access permissions of this abstract pathname.  If
+     *          <code>readable</code> is <code>false</code> and the underlying
+     *          file system does not implement a read permission, then the
+     *          operation will fail.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     *
+     * @since 1.6
+     */
+    public boolean setReadable(boolean readable, boolean ownerOnly) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * A convenience method to set the owner's read permission for this abstract
+     * pathname.
+     *
+     * <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     file.setReadable(arg, true) </pre>
+     *
+     * @param  readable
+     *          If <code>true</code>, sets the access permission to allow read
+     *          operations; if <code>false</code> to disallow read operations
+     *
+     * @return  <code>true</code> if and only if the operation succeeded.  The
+     *          operation will fail if the user does not have permission to
+     *          change the access permissions of this abstract pathname.  If
+     *          <code>readable</code> is <code>false</code> and the underlying
+     *          file system does not implement a read permission, then the
+     *          operation will fail.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     *
+     * @since 1.6
+     */
+    public boolean setReadable(boolean readable) {
+        return setReadable(readable, true);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * Sets the owner's or everybody's execute permission for this abstract
+     * pathname.
+     *
+     * <p> The {@link java.nio.file.Files} class defines methods that operate on
+     * file attributes including file permissions. This may be used when finer
+     * manipulation of file permissions is required.
+     *
+     * @param   executable
+     *          If <code>true</code>, sets the access permission to allow execute
+     *          operations; if <code>false</code> to disallow execute operations
+     *
+     * @param   ownerOnly
+     *          If <code>true</code>, the execute permission applies only to the
+     *          owner's execute permission; otherwise, it applies to everybody.
+     *          If the underlying file system can not distinguish the owner's
+     *          execute permission from that of others, then the permission will
+     *          apply to everybody, regardless of this value.
+     *
+     * @return  <code>true</code> if and only if the operation succeeded.  The
+     *          operation will fail if the user does not have permission to
+     *          change the access permissions of this abstract pathname.  If
+     *          <code>executable</code> is <code>false</code> and the underlying
+     *          file system does not implement an execute permission, then the
+     *          operation will fail.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     *
+     * @since 1.6
+     */
+    public boolean setExecutable(boolean executable, boolean ownerOnly) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * A convenience method to set the owner's execute permission for this
+     * abstract pathname.
+     *
+     * <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     file.setExecutable(arg, true) </pre>
+     *
+     * @param   executable
+     *          If <code>true</code>, sets the access permission to allow execute
+     *          operations; if <code>false</code> to disallow execute operations
+     *
+     * @return   <code>true</code> if and only if the operation succeeded.  The
+     *           operation will fail if the user does not have permission to
+     *           change the access permissions of this abstract pathname.  If
+     *           <code>executable</code> is <code>false</code> and the underlying
+     *           file system does not implement an execute permission, then the
+     *           operation will fail.
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method denies write access to the file
+     *
+     * @since 1.6
+     */
+    public boolean setExecutable(boolean executable) {
+        return setExecutable(executable, true);
+    }
+
+    // Android-changed. Removed javadoc comment about special privileges
+    // that doesn't make sense on Android.
+    /**
+     * Tests whether the application can execute the file denoted by this
+     * abstract pathname.
+     *
+     * @return  <code>true</code> if and only if the abstract pathname exists
+     *          <em>and</em> the application is allowed to execute the file
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkExec(java.lang.String)}</code>
+     *          method denies execute access to the file
+     *
+     * @since 1.6
+     */
+    public boolean canExecute() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkExec(path);
+        }
+        if (isInvalid()) {
+            return false;
+        }
+        return fs.checkAccess(this, FileSystem.ACCESS_EXECUTE);
+    }
+
+
+    /* -- Filesystem interface -- */
+
+    // Android-changed: Replaced generic platform info with Android specific one.
+    /**
+     * Returns the file system roots. On Android and other Unix systems, there is
+     * a single root, {@code /}.
+     */
+    public static File[] listRoots() {
+        return fs.listRoots();
+    }
+
+
+    /* -- Disk usage -- */
+
+    /**
+     * Returns the size of the partition <a href="#partName">named</a> by this
+     * abstract pathname.
+     *
+     * @return  The size, in bytes, of the partition or <tt>0L</tt> if this
+     *          abstract pathname does not name a partition
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String)} method denies
+     *          read access to the file named by this abstract pathname
+     *
+     * @since  1.6
+     */
+    public long getTotalSpace() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+            sm.checkRead(path);
+        }
+        if (isInvalid()) {
+            return 0L;
+        }
+        return fs.getSpace(this, FileSystem.SPACE_TOTAL);
+    }
+
+    /**
+     * Returns the number of unallocated bytes in the partition <a
+     * href="#partName">named</a> by this abstract path name.
+     *
+     * <p> The returned number of unallocated bytes is a hint, but not
+     * a guarantee, that it is possible to use most or any of these
+     * bytes.  The number of unallocated bytes is most likely to be
+     * accurate immediately after this call.  It is likely to be made
+     * inaccurate by any external I/O operations including those made
+     * on the system outside of this virtual machine.  This method
+     * makes no guarantee that write operations to this file system
+     * will succeed.
+     *
+     * @return  The number of unallocated bytes on the partition or <tt>0L</tt>
+     *          if the abstract pathname does not name a partition.  This
+     *          value will be less than or equal to the total file system size
+     *          returned by {@link #getTotalSpace}.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String)} method denies
+     *          read access to the file named by this abstract pathname
+     *
+     * @since  1.6
+     */
+    public long getFreeSpace() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+            sm.checkRead(path);
+        }
+        if (isInvalid()) {
+            return 0L;
+        }
+        return fs.getSpace(this, FileSystem.SPACE_FREE);
+    }
+
+    // Android-added: Replaced generic platform info with Android specific one.
+    /**
+     * Returns the number of bytes available to this virtual machine on the
+     * partition <a href="#partName">named</a> by this abstract pathname.  When
+     * possible, this method checks for write permissions and other operating
+     * system restrictions and will therefore usually provide a more accurate
+     * estimate of how much new data can actually be written than {@link
+     * #getFreeSpace}.
+     *
+     * <p> The returned number of available bytes is a hint, but not a
+     * guarantee, that it is possible to use most or any of these bytes.  The
+     * number of unallocated bytes is most likely to be accurate immediately
+     * after this call.  It is likely to be made inaccurate by any external
+     * I/O operations including those made on the system outside of this
+     * virtual machine.  This method makes no guarantee that write operations
+     * to this file system will succeed.
+     *
+     * <p> On Android (and other Unix-based systems), this method returns the number of free bytes
+     * available to non-root users, regardless of whether you're actually running as root,
+     * and regardless of any quota or other restrictions that might apply to the user.
+     * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
+     *
+     * @return  The number of available bytes on the partition or <tt>0L</tt>
+     *          if the abstract pathname does not name a partition.  On
+     *          systems where this information is not available, this method
+     *          will be equivalent to a call to {@link #getFreeSpace}.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String)} method denies
+     *          read access to the file named by this abstract pathname
+     *
+     * @since  1.6
+     */
+    public long getUsableSpace() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
+            sm.checkRead(path);
+        }
+        if (isInvalid()) {
+            return 0L;
+        }
+        return fs.getSpace(this, FileSystem.SPACE_USABLE);
+    }
+
+    /* -- Temporary files -- */
+
+    private static class TempDirectory {
+        private TempDirectory() { }
+
+        // Android-changed: Don't cache java.io.tmpdir value
+        // temporary directory location.
+        /*
+        private static final File tmpdir = new File(AccessController
+           .doPrivileged(new GetPropertyAction("java.io.tmpdir")));
+        static File location() {
+            return tmpdir;
+        }
+        */
+
+        // file name generation
+        // private static final SecureRandom random = new SecureRandom();
+        static File generateFile(String prefix, String suffix, File dir)
+            throws IOException
+        {
+            // Android-changed: Use Math.randomIntInternal. This (pseudo) random number
+            // is initialized post-fork
+
+            long n = Math.randomLongInternal();
+            if (n == Long.MIN_VALUE) {
+                n = 0;      // corner case
+            } else {
+                n = Math.abs(n);
+            }
+
+            // Android-changed: Reject invalid file prefixes
+            // Use only the file name from the supplied prefix
+            // prefix = (new File(prefix)).getName();
+
+            String name = prefix + Long.toString(n) + suffix;
+            File f = new File(dir, name);
+            if (!name.equals(f.getName()) || f.isInvalid()) {
+                if (System.getSecurityManager() != null)
+                    throw new IOException("Unable to create temporary file");
+                else
+                    throw new IOException("Unable to create temporary file, " + f);
+            }
+            return f;
+        }
+    }
+
+    /**
+     * <p> Creates a new empty file in the specified directory, using the
+     * given prefix and suffix strings to generate its name.  If this method
+     * returns successfully then it is guaranteed that:
+     *
+     * <ol>
+     * <li> The file denoted by the returned abstract pathname did not exist
+     *      before this method was invoked, and
+     * <li> Neither this method nor any of its variants will return the same
+     *      abstract pathname again in the current invocation of the virtual
+     *      machine.
+     * </ol>
+     *
+     * This method provides only part of a temporary-file facility.  To arrange
+     * for a file created by this method to be deleted automatically, use the
+     * <code>{@link #deleteOnExit}</code> method.
+     *
+     * <p> The <code>prefix</code> argument must be at least three characters
+     * long.  It is recommended that the prefix be a short, meaningful string
+     * such as <code>"hjb"</code> or <code>"mail"</code>.  The
+     * <code>suffix</code> argument may be <code>null</code>, in which case the
+     * suffix <code>".tmp"</code> will be used.
+     *
+     * <p> To create the new file, the prefix and the suffix may first be
+     * adjusted to fit the limitations of the underlying platform.  If the
+     * prefix is too long then it will be truncated, but its first three
+     * characters will always be preserved.  If the suffix is too long then it
+     * too will be truncated, but if it begins with a period character
+     * (<code>'.'</code>) then the period and the first three characters
+     * following it will always be preserved.  Once these adjustments have been
+     * made the name of the new file will be generated by concatenating the
+     * prefix, five or more internally-generated characters, and the suffix.
+     *
+     * <p> If the <code>directory</code> argument is <code>null</code> then the
+     * system-dependent default temporary-file directory will be used.  The
+     * default temporary-file directory is specified by the system property
+     * <code>java.io.tmpdir</code>.  On UNIX systems the default value of this
+     * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on
+     * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>.  A different
+     * value may be given to this system property when the Java virtual machine
+     * is invoked, but programmatic changes to this property are not guaranteed
+     * to have any effect upon the temporary directory used by this method.
+     *
+     * @param  prefix     The prefix string to be used in generating the file's
+     *                    name; must be at least three characters long
+     *
+     * @param  suffix     The suffix string to be used in generating the file's
+     *                    name; may be <code>null</code>, in which case the
+     *                    suffix <code>".tmp"</code> will be used
+     *
+     * @param  directory  The directory in which the file is to be created, or
+     *                    <code>null</code> if the default temporary-file
+     *                    directory is to be used
+     *
+     * @return  An abstract pathname denoting a newly-created empty file
+     *
+     * @throws  IllegalArgumentException
+     *          If the <code>prefix</code> argument contains fewer than three
+     *          characters
+     *
+     * @throws  IOException  If a file could not be created
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method does not allow a file to be created
+     *
+     * @since 1.2
+     */
+    public static File createTempFile(String prefix, String suffix,
+                                      File directory)
+        throws IOException
+    {
+        if (prefix.length() < 3)
+            throw new IllegalArgumentException("Prefix string too short");
+        if (suffix == null)
+            suffix = ".tmp";
+
+        // Android-changed: Handle java.io.tmpdir changes.
+        File tmpdir = (directory != null) ? directory
+                                          : new File(System.getProperty("java.io.tmpdir", "."));
+        //SecurityManager sm = System.getSecurityManager();
+        File f;
+        do {
+            f = TempDirectory.generateFile(prefix, suffix, tmpdir);
+
+            // Android-changed: sm is always null on Android.
+            /*
+            if (sm != null) {
+                try {
+                    sm.checkWrite(f.getPath());
+                } catch (SecurityException se) {
+                    // don't reveal temporary directory location
+                    if (directory == null)
+                        throw new SecurityException("Unable to create temporary file");
+                    throw se;
+                }
+            }
+            */
+        } while ((fs.getBooleanAttributes(f) & FileSystem.BA_EXISTS) != 0);
+
+        if (!fs.createFileExclusively(f.getPath()))
+            throw new IOException("Unable to create temporary file");
+
+        return f;
+    }
+
+    /**
+     * Creates an empty file in the default temporary-file directory, using
+     * the given prefix and suffix to generate its name. Invoking this method
+     * is equivalent to invoking <code>{@link #createTempFile(java.lang.String,
+     * java.lang.String, java.io.File)
+     * createTempFile(prefix,&nbsp;suffix,&nbsp;null)}</code>.
+     *
+     * <p> The {@link
+     * java.nio.file.Files#createTempFile(String,String,java.nio.file.attribute.FileAttribute[])
+     * Files.createTempFile} method provides an alternative method to create an
+     * empty file in the temporary-file directory. Files created by that method
+     * may have more restrictive access permissions to files created by this
+     * method and so may be more suited to security-sensitive applications.
+     *
+     * @param  prefix     The prefix string to be used in generating the file's
+     *                    name; must be at least three characters long
+     *
+     * @param  suffix     The suffix string to be used in generating the file's
+     *                    name; may be <code>null</code>, in which case the
+     *                    suffix <code>".tmp"</code> will be used
+     *
+     * @return  An abstract pathname denoting a newly-created empty file
+     *
+     * @throws  IllegalArgumentException
+     *          If the <code>prefix</code> argument contains fewer than three
+     *          characters
+     *
+     * @throws  IOException  If a file could not be created
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <code>{@link
+     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+     *          method does not allow a file to be created
+     *
+     * @since 1.2
+     * @see java.nio.file.Files#createTempDirectory(String,FileAttribute[])
+     */
+    public static File createTempFile(String prefix, String suffix)
+        throws IOException
+    {
+        return createTempFile(prefix, suffix, null);
+    }
+
+    /* -- Basic infrastructure -- */
+
+    /**
+     * Compares two abstract pathnames lexicographically.  The ordering
+     * defined by this method depends upon the underlying system.  On UNIX
+     * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
+     * systems it is not.
+     *
+     * @param   pathname  The abstract pathname to be compared to this abstract
+     *                    pathname
+     *
+     * @return  Zero if the argument is equal to this abstract pathname, a
+     *          value less than zero if this abstract pathname is
+     *          lexicographically less than the argument, or a value greater
+     *          than zero if this abstract pathname is lexicographically
+     *          greater than the argument
+     *
+     * @since   1.2
+     */
+    public int compareTo(File pathname) {
+        return fs.compare(this, pathname);
+    }
+
+    /**
+     * Tests this abstract pathname for equality with the given object.
+     * Returns <code>true</code> if and only if the argument is not
+     * <code>null</code> and is an abstract pathname that denotes the same file
+     * or directory as this abstract pathname.  Whether or not two abstract
+     * pathnames are equal depends upon the underlying system.  On UNIX
+     * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
+     * systems it is not.
+     *
+     * @param   obj   The object to be compared with this abstract pathname
+     *
+     * @return  <code>true</code> if and only if the objects are the same;
+     *          <code>false</code> otherwise
+     */
+    public boolean equals(Object obj) {
+        if ((obj != null) && (obj instanceof File)) {
+            return compareTo((File)obj) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * Computes a hash code for this abstract pathname.  Because equality of
+     * abstract pathnames is inherently system-dependent, so is the computation
+     * of their hash codes.  On UNIX systems, the hash code of an abstract
+     * pathname is equal to the exclusive <em>or</em> of the hash code
+     * of its pathname string and the decimal value
+     * <code>1234321</code>.  On Microsoft Windows systems, the hash
+     * code is equal to the exclusive <em>or</em> of the hash code of
+     * its pathname string converted to lower case and the decimal
+     * value <code>1234321</code>.  Locale is not taken into account on
+     * lowercasing the pathname string.
+     *
+     * @return  A hash code for this abstract pathname
+     */
+    public int hashCode() {
+        return fs.hashCode(this);
+    }
+
+    /**
+     * Returns the pathname string of this abstract pathname.  This is just the
+     * string returned by the <code>{@link #getPath}</code> method.
+     *
+     * @return  The string form of this abstract pathname
+     */
+    public String toString() {
+        return getPath();
+    }
+
+    /**
+     * WriteObject is called to save this filename.
+     * The separator character is saved also so it can be replaced
+     * in case the path is reconstituted on a different host type.
+     * <p>
+     * @serialData  Default fields followed by separator character.
+     */
+    private synchronized void writeObject(java.io.ObjectOutputStream s)
+        throws IOException
+    {
+        s.defaultWriteObject();
+        s.writeChar(separatorChar); // Add the separator character
+    }
+
+    /**
+     * readObject is called to restore this filename.
+     * The original separator character is read.  If it is different
+     * than the separator character on this system, then the old separator
+     * is replaced by the local separator.
+     */
+    private synchronized void readObject(java.io.ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+        ObjectInputStream.GetField fields = s.readFields();
+        String pathField = (String)fields.get("path", null);
+        char sep = s.readChar(); // read the previous separator char
+        if (sep != separatorChar)
+            pathField = pathField.replace(sep, separatorChar);
+        String path = fs.normalize(pathField);
+        UNSAFE.putObject(this, PATH_OFFSET, path);
+        UNSAFE.putIntVolatile(this, PREFIX_LENGTH_OFFSET, fs.prefixLength(path));
+    }
+
+    private static final long PATH_OFFSET;
+    private static final long PREFIX_LENGTH_OFFSET;
+    private static final sun.misc.Unsafe UNSAFE;
+    static {
+        try {
+            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            PATH_OFFSET = unsafe.objectFieldOffset(
+                    File.class.getDeclaredField("path"));
+            PREFIX_LENGTH_OFFSET = unsafe.objectFieldOffset(
+                    File.class.getDeclaredField("prefixLength"));
+            UNSAFE = unsafe;
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 301077366599181567L;
+
+    // -- Integration with java.nio.file --
+
+    private volatile transient Path filePath;
+
+    /**
+     * Returns a {@link Path java.nio.file.Path} object constructed from the
+     * this abstract path. The resulting {@code Path} is associated with the
+     * {@link java.nio.file.FileSystems#getDefault default-filesystem}.
+     *
+     * <p> The first invocation of this method works as if invoking it were
+     * equivalent to evaluating the expression:
+     * <blockquote><pre>
+     * {@link java.nio.file.FileSystems#getDefault FileSystems.getDefault}().{@link
+     * java.nio.file.FileSystem#getPath getPath}(this.{@link #getPath getPath}());
+     * </pre></blockquote>
+     * Subsequent invocations of this method return the same {@code Path}.
+     *
+     * <p> If this abstract pathname is the empty abstract pathname then this
+     * method returns a {@code Path} that may be used to access the current
+     * user directory.
+     *
+     * @return  a {@code Path} constructed from this abstract path
+     *
+     * @throws  java.nio.file.InvalidPathException
+     *          if a {@code Path} object cannot be constructed from the abstract
+     *          path (see {@link java.nio.file.FileSystem#getPath FileSystem.getPath})
+     *
+     * @since   1.7
+     * @see Path#toFile
+     */
+    public Path toPath() {
+        Path result = filePath;
+        if (result == null) {
+            synchronized (this) {
+                result = filePath;
+                if (result == null) {
+                    result = FileSystems.getDefault().getPath(path);
+                    filePath = result;
+                }
+            }
+        }
+        return result;
+    }
+}
diff --git a/java/io/FileDescriptor.annotated.java b/java/io/FileDescriptor.annotated.java
new file mode 100644
index 0000000..89006c1
--- /dev/null
+++ b/java/io/FileDescriptor.annotated.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class FileDescriptor {
+
+public FileDescriptor() { throw new RuntimeException("Stub!"); }
+
+public boolean valid() { throw new RuntimeException("Stub!"); }
+
+public native void sync() throws java.io.SyncFailedException;
+
[email protected]
+public int getInt$() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public void setInt$(int fd) { throw new RuntimeException("Stub!"); }
+
+public long getOwnerId$() { throw new RuntimeException("Stub!"); }
+
+public void setOwnerId$(long newOwnerId) { throw new RuntimeException("Stub!"); }
+
+public java.io.FileDescriptor release$() { throw new RuntimeException("Stub!"); }
+
+public boolean isSocket$() { throw new RuntimeException("Stub!"); }
+
+public static final long NO_OWNER = 0L; // 0x0L
+
+public static final java.io.FileDescriptor err;
+static { err = null; }
+
+public static final java.io.FileDescriptor in;
+static { in = null; }
+
+public static final java.io.FileDescriptor out;
+static { out = null; }
+}
+
diff --git a/java/io/FileDescriptor.java b/java/io/FileDescriptor.java
new file mode 100644
index 0000000..98db443
--- /dev/null
+++ b/java/io/FileDescriptor.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import static android.system.OsConstants.F_DUPFD_CLOEXEC;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Instances of the file descriptor class serve as an opaque handle
+ * to the underlying machine-specific structure representing an open
+ * file, an open socket, or another source or sink of bytes. The
+ * main practical use for a file descriptor is to create a
+ * <code>FileInputStream</code> or <code>FileOutputStream</code> to
+ * contain it.
+ * <p>
+ * Applications should not create their own file descriptors.
+ *
+ * @author  Pavani Diwanji
+ * @see     java.io.FileInputStream
+ * @see     java.io.FileOutputStream
+ * @since   JDK1.0
+ */
+public final class FileDescriptor {
+    // Android-changed: Removed parent reference counting. Creator is responsible for closing
+    // the file descriptor.
+
+    // Android-changed: Renamed fd to descriptor to avoid issues with JNI/reflection
+    // fetching the descriptor value.
+    private int descriptor;
+
+    // Android-added: Track fd owner to guard against accidental closure. http://b/110100358
+    // The owner on the libc side is an pointer-sized value that can be set to an arbitrary
+    // value (with 0 meaning 'unowned'). libcore chooses to use System.identityHashCode.
+    private long ownerId = NO_OWNER;
+
+    // Android-added: value of ownerId indicating that a FileDescriptor is unowned.
+    /** @hide */
+    public static final long NO_OWNER = 0L;
+
+    /**
+     * Constructs an (invalid) FileDescriptor
+     * object.
+     */
+    public /**/ FileDescriptor() {
+        descriptor = -1;
+    }
+
+    private /* */ FileDescriptor(int descriptor) {
+        this.descriptor = descriptor;
+    }
+
+    /**
+     * A handle to the standard input stream. Usually, this file
+     * descriptor is not used directly, but rather via the input stream
+     * known as <code>System.in</code>.
+     *
+     * @see     java.lang.System#in
+     */
+    public static final FileDescriptor in = new FileDescriptor(0);
+
+    /**
+     * A handle to the standard output stream. Usually, this file
+     * descriptor is not used directly, but rather via the output stream
+     * known as <code>System.out</code>.
+     * @see     java.lang.System#out
+     */
+    public static final FileDescriptor out = new FileDescriptor(1);
+
+    /**
+     * A handle to the standard error stream. Usually, this file
+     * descriptor is not used directly, but rather via the output stream
+     * known as <code>System.err</code>.
+     *
+     * @see     java.lang.System#err
+     */
+    public static final FileDescriptor err = new FileDescriptor(2);
+
+    /**
+     * Tests if this file descriptor object is valid.
+     *
+     * @return  <code>true</code> if the file descriptor object represents a
+     *          valid, open file, socket, or other active I/O connection;
+     *          <code>false</code> otherwise.
+     */
+    public boolean valid() {
+        return descriptor != -1;
+    }
+
+    /**
+     * Force all system buffers to synchronize with the underlying
+     * device.  This method returns after all modified data and
+     * attributes of this FileDescriptor have been written to the
+     * relevant device(s).  In particular, if this FileDescriptor
+     * refers to a physical storage medium, such as a file in a file
+     * system, sync will not return until all in-memory modified copies
+     * of buffers associated with this FileDescriptor have been
+     * written to the physical medium.
+     *
+     * sync is meant to be used by code that requires physical
+     * storage (such as a file) to be in a known state  For
+     * example, a class that provided a simple transaction facility
+     * might use sync to ensure that all changes to a file caused
+     * by a given transaction were recorded on a storage medium.
+     *
+     * sync only affects buffers downstream of this FileDescriptor.  If
+     * any in-memory buffering is being done by the application (for
+     * example, by a BufferedOutputStream object), those buffers must
+     * be flushed into the FileDescriptor (for example, by invoking
+     * OutputStream.flush) before that data will be affected by sync.
+     *
+     * @exception SyncFailedException
+     *        Thrown when the buffers cannot be flushed,
+     *        or because the system cannot guarantee that all the
+     *        buffers have been synchronized with physical media.
+     * @since     JDK1.1
+     */
+    public native void sync() throws SyncFailedException;
+
+    // Android-removed: initIDs not used to allow compile-time intialization
+    /* This routine initializes JNI field offsets for the class */
+    //private static native void initIDs();
+
+    // Android-added: Needed for framework to access descriptor value
+    /**
+     * Returns the int descriptor. It's highly unlikely you should be calling this. Please discuss
+     * your needs with a libcore maintainer before using this method.
+     * @hide internal use only
+     */
+    public final int getInt$() {
+        return descriptor;
+    }
+
+    // Android-added: Needed for framework to access descriptor value
+    /**
+     * Sets the int descriptor. It's highly unlikely you should be calling this. Please discuss
+     * your needs with a libcore maintainer before using this method.
+     * @hide internal use only
+     */
+    public final void setInt$(int fd) {
+        this.descriptor = fd;
+    }
+
+    // BEGIN Android-added: Method to clone standard file descriptors.
+    // Required as a consequence of RuntimeInit#redirectLogStreams. Cloning is used in
+    // ZygoteHooks.onEndPreload().
+    /**
+     * Clones the current native file descriptor and uses this for this FileDescriptor instance.
+     *
+     * This method does not close the current native file descriptor.
+     *
+     * @hide internal use only
+     */
+    public void cloneForFork() {
+        try {
+            int newDescriptor = Os.fcntlInt(this, F_DUPFD_CLOEXEC, 0);
+            this.descriptor = newDescriptor;
+        } catch (ErrnoException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    // END Android-added: Method to clone standard file descriptors.
+
+    // BEGIN Android-added: Methods to enable ownership enforcement of Unix file descriptors.
+    /**
+     * Returns the owner ID of this FileDescriptor. It's highly unlikely you should be calling this.
+     * Please discuss your needs with a libcore maintainer before using this method.
+     * @hide internal use only
+     */
+    public long getOwnerId$() {
+        return this.ownerId;
+    }
+
+    /**
+     * Sets the owner ID of this FileDescriptor. The owner ID does not need to be unique, but it is
+     * assumed that clashes are rare. See bionic/include/android/fdsan.h for more details.
+     *
+     * It's highly unlikely you should be calling this.
+     * Please discuss your needs with a libcore maintainer before using this method.
+     * @param owner the owner ID of the Object that is responsible for closing this FileDescriptor
+     * @hide internal use only
+     */
+    public void setOwnerId$(long newOwnerId) {
+        this.ownerId = newOwnerId;
+    }
+
+    /**
+     * Returns a copy of this FileDescriptor, and sets this to an invalid state.
+     * @hide internal use only
+     */
+    public FileDescriptor release$() {
+      FileDescriptor result = new FileDescriptor();
+      result.descriptor = this.descriptor;
+      result.ownerId = this.ownerId;
+      this.descriptor = -1;
+      this.ownerId = FileDescriptor.NO_OWNER;
+      return result;
+    }
+    // END Android-added: Methods to enable ownership enforcement of Unix file descriptors.
+
+    // Android-added: Needed for framework to test if it's a socket
+    /**
+     * @hide internal use only
+     */
+    public boolean isSocket$() {
+        return isSocket(descriptor);
+    }
+
+    private static native boolean isSocket(int descriptor);
+    // Set up JavaIOFileDescriptorAccess in SharedSecrets
+    static {
+        sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
+            new sun.misc.JavaIOFileDescriptorAccess() {
+                public void set(FileDescriptor obj, int fd) {
+                    obj.descriptor = fd;
+                }
+
+                public int get(FileDescriptor obj) {
+                    return obj.descriptor;
+                }
+
+                public void setHandle(FileDescriptor obj, long handle) {
+                    throw new UnsupportedOperationException();
+                }
+
+                public long getHandle(FileDescriptor obj) {
+                    throw new UnsupportedOperationException();
+                }
+            }
+        );
+    }
+// Android-removed: Removed method required for parents reference counting
+}
diff --git a/java/io/FileFilter.java b/java/io/FileFilter.java
new file mode 100644
index 0000000..f973d77
--- /dev/null
+++ b/java/io/FileFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A filter for abstract pathnames.
+ *
+ * <p> Instances of this interface may be passed to the <code>{@link
+ * File#listFiles(java.io.FileFilter) listFiles(FileFilter)}</code> method
+ * of the <code>{@link java.io.File}</code> class.
+ *
+ * @since 1.2
+ */
+@FunctionalInterface
+public interface FileFilter {
+
+    /**
+     * Tests whether or not the specified abstract pathname should be
+     * included in a pathname list.
+     *
+     * @param  pathname  The abstract pathname to be tested
+     * @return  <code>true</code> if and only if <code>pathname</code>
+     *          should be included
+     */
+    boolean accept(File pathname);
+}
diff --git a/java/io/FileInputStream.annotated.java b/java/io/FileInputStream.annotated.java
new file mode 100644
index 0000000..11013ac
--- /dev/null
+++ b/java/io/FileInputStream.annotated.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+import java.nio.channels.FileChannel;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class FileInputStream extends java.io.InputStream {
+
+public FileInputStream(java.lang.String name) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public FileInputStream(java.io.File file) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public FileInputStream(java.io.FileDescriptor fdObj) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public FileInputStream(java.io.FileDescriptor fdObj, boolean isFdOwner) { throw new RuntimeException("Stub!"); }
+
+public int read() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int read(byte[] b) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int read(byte[] b, int off, int len) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public long skip(long n) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public int available() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public final java.io.FileDescriptor getFD() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.FileChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+protected void finalize() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/io/FileInputStream.java b/java/io/FileInputStream.java
new file mode 100644
index 0000000..38230bb
--- /dev/null
+++ b/java/io/FileInputStream.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import static android.system.OsConstants.O_RDONLY;
+
+import java.nio.channels.FileChannel;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import sun.nio.ch.FileChannelImpl;
+import libcore.io.IoBridge;
+import libcore.io.IoTracker;
+import libcore.io.IoUtils;
+
+
+/**
+ * A <code>FileInputStream</code> obtains input bytes
+ * from a file in a file system. What files
+ * are  available depends on the host environment.
+ *
+ * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
+ * such as image data. For reading streams of characters, consider using
+ * <code>FileReader</code>.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.io.File
+ * @see     java.io.FileDescriptor
+ * @see     java.io.FileOutputStream
+ * @see     java.nio.file.Files#newInputStream
+ * @since   JDK1.0
+ */
+public
+class FileInputStream extends InputStream
+{
+    /* File Descriptor - handle to the open file */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final FileDescriptor fd;
+
+    /**
+     * The path of the referenced file
+     * (null if the stream is created with a file descriptor)
+     */
+    private final String path;
+
+    private FileChannel channel = null;
+
+    private final Object closeLock = new Object();
+    private volatile boolean closed = false;
+
+    // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor.
+    private final boolean isFdOwner;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    // Android-added: Tracking of unbuffered I/O.
+    private final IoTracker tracker = new IoTracker();
+
+    /**
+     * Creates a <code>FileInputStream</code> by
+     * opening a connection to an actual file,
+     * the file named by the path name <code>name</code>
+     * in the file system.  A new <code>FileDescriptor</code>
+     * object is created to represent this file
+     * connection.
+     * <p>
+     * First, if there is a security
+     * manager, its <code>checkRead</code> method
+     * is called with the <code>name</code> argument
+     * as its argument.
+     * <p>
+     * If the named file does not exist, is a directory rather than a regular
+     * file, or for some other reason cannot be opened for reading then a
+     * <code>FileNotFoundException</code> is thrown.
+     *
+     * @param      name   the system-dependent file name.
+     * @exception  FileNotFoundException  if the file does not exist,
+     *                   is a directory rather than a regular file,
+     *                   or for some other reason cannot be opened for
+     *                   reading.
+     * @exception  SecurityException      if a security manager exists and its
+     *               <code>checkRead</code> method denies read access
+     *               to the file.
+     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
+     */
+    public FileInputStream(String name) throws FileNotFoundException {
+        this(name != null ? new File(name) : null);
+    }
+
+    /**
+     * Creates a <code>FileInputStream</code> by
+     * opening a connection to an actual file,
+     * the file named by the <code>File</code>
+     * object <code>file</code> in the file system.
+     * A new <code>FileDescriptor</code> object
+     * is created to represent this file connection.
+     * <p>
+     * First, if there is a security manager,
+     * its <code>checkRead</code> method  is called
+     * with the path represented by the <code>file</code>
+     * argument as its argument.
+     * <p>
+     * If the named file does not exist, is a directory rather than a regular
+     * file, or for some other reason cannot be opened for reading then a
+     * <code>FileNotFoundException</code> is thrown.
+     *
+     * @param      file   the file to be opened for reading.
+     * @exception  FileNotFoundException  if the file does not exist,
+     *                   is a directory rather than a regular file,
+     *                   or for some other reason cannot be opened for
+     *                   reading.
+     * @exception  SecurityException      if a security manager exists and its
+     *               <code>checkRead</code> method denies read access to the file.
+     * @see        java.io.File#getPath()
+     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
+     */
+    public FileInputStream(File file) throws FileNotFoundException {
+        String name = (file != null ? file.getPath() : null);
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(name);
+        }
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        if (file.isInvalid()) {
+            throw new FileNotFoundException("Invalid file path");
+        }
+        // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+        // http://b/112107427
+        // fd = new FileDescriptor();
+        fd = IoBridge.open(name, O_RDONLY);
+        // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+        // Android-changed: Tracking mechanism for FileDescriptor sharing.
+        // fd.attach(this);
+        isFdOwner = true;
+
+        path = name;
+
+        // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+        // open(name);
+
+        // Android-added: File descriptor ownership tracking.
+        IoUtils.setFdOwner(this.fd, this);
+
+        // Android-added: CloseGuard support.
+        guard.open("close");
+    }
+
+    // Android-removed: Documentation around SecurityException. Not thrown on Android.
+    /**
+     * Creates a <code>FileInputStream</code> by using the file descriptor
+     * <code>fdObj</code>, which represents an existing connection to an
+     * actual file in the file system.
+     * <p>
+     * If there is a security manager, its <code>checkRead</code> method is
+     * called with the file descriptor <code>fdObj</code> as its argument to
+     * see if it's ok to read the file descriptor. If read access is denied
+     * to the file descriptor a <code>SecurityException</code> is thrown.
+     * <p>
+     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
+     * is thrown.
+     * <p>
+     * This constructor does not throw an exception if <code>fdObj</code>
+     * is {@link java.io.FileDescriptor#valid() invalid}.
+     * However, if the methods are invoked on the resulting stream to attempt
+     * I/O on the stream, an <code>IOException</code> is thrown.
+     *
+     * @param      fdObj   the file descriptor to be opened for reading.
+     */
+    public FileInputStream(FileDescriptor fdObj) {
+        // Android-changed: Delegate to added hidden constructor.
+        this(fdObj, false /* isFdOwner */);
+    }
+
+    // Android-added: Internal/hidden constructor for specifying FileDescriptor ownership.
+    // Android-removed: SecurityManager calls.
+    /** @hide */
+    public FileInputStream(FileDescriptor fdObj, boolean isFdOwner) {
+        if (fdObj == null) {
+            // Android-changed: Improved NullPointerException message.
+            throw new NullPointerException("fdObj == null");
+        }
+        fd = fdObj;
+        path = null;
+
+        // Android-changed: FileDescriptor ownership tracking mechanism.
+        /*
+        /*
+         * FileDescriptor is being shared by streams.
+         * Register this stream with FileDescriptor tracker.
+         *
+        fd.attach(this);
+        */
+        this.isFdOwner = isFdOwner;
+    }
+
+    // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+    // http://b/112107427
+    /*
+    /**
+     * Opens the specified file for reading.
+     * @param name the name of the file
+     *
+    private native void open0(String name) throws FileNotFoundException;
+
+    // wrap native call to allow instrumentation
+    /**
+     * Opens the specified file for reading.
+     * @param name the name of the file
+     *
+    private void open(String name) throws FileNotFoundException {
+        open0(name);
+    }
+    */
+    // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+    /**
+     * Reads a byte of data from this input stream. This method blocks
+     * if no input is yet available.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             file is reached.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int read() throws IOException {
+        // Android-changed: Read methods delegate to read(byte[], int, int) to share Android logic.
+        byte[] b = new byte[1];
+        return (read(b, 0, 1) != -1) ? b[0] & 0xff : -1;
+    }
+
+    // Android-removed: Read methods delegate to read(byte[], int, int) to share Android logic.
+    // private native int read0() throws IOException;
+
+    // Android-removed: Read methods delegate to read(byte[], int, int) to share Android logic.
+    /*
+    /**
+     * Reads a subarray as a sequence of bytes.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     *
+    private native int readBytes(byte b[], int off, int len) throws IOException;
+    */
+
+    /**
+     * Reads up to <code>b.length</code> bytes of data from this input
+     * stream into an array of bytes. This method blocks until some input
+     * is available.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the file has been reached.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int read(byte b[]) throws IOException {
+        // Android-changed: Read methods delegate to read(byte[], int, int) to share Android logic.
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this input stream
+     * into an array of bytes. If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in the destination array <code>b</code>
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the file has been reached.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        // Android-added: close() check before I/O.
+        if (closed && len > 0) {
+            throw new IOException("Stream Closed");
+        }
+
+        // Android-added: Tracking of unbuffered I/O.
+        tracker.trackIo(len);
+
+        // Android-changed: Use IoBridge instead of calling native method.
+        return IoBridge.read(fd, b, off, len);
+    }
+
+    /**
+     * Skips over and discards <code>n</code> bytes of data from the
+     * input stream.
+     *
+     * <p>The <code>skip</code> method may, for a variety of
+     * reasons, end up skipping over some smaller number of bytes,
+     * possibly <code>0</code>. If <code>n</code> is negative, the method
+     * will try to skip backwards. In case the backing file does not support
+     * backward skip at its current position, an <code>IOException</code> is
+     * thrown. The actual number of bytes skipped is returned. If it skips
+     * forwards, it returns a positive value. If it skips backwards, it
+     * returns a negative value.
+     *
+     * <p>This method may skip more bytes than what are remaining in the
+     * backing file. This produces no exception and the number of bytes skipped
+     * may include some number of bytes that were beyond the EOF of the
+     * backing file. Attempting to read from the stream after skipping past
+     * the end will result in -1 indicating the end of the file.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if n is negative, if the stream does not
+     *             support seek, or if an I/O error occurs.
+     */
+    // BEGIN Android-changed: skip(long) implementation changed from bare native.
+    public long skip(long n) throws IOException {
+        // Android-added: close() check before I/O.
+        if (closed) {
+            throw new IOException("Stream Closed");
+        }
+
+        try {
+            // Android-added: BlockGuard support.
+            BlockGuard.getThreadPolicy().onReadFromDisk();
+            return skip0(n);
+        } catch(UseManualSkipException e) {
+            return super.skip(n);
+        }
+    }
+
+    private native long skip0(long n) throws IOException, UseManualSkipException;
+
+    /*
+     * Used to force manual skip when FileInputStream operates on pipe
+     */
+    private static class UseManualSkipException extends Exception {
+    }
+    // END Android-changed: skip(long) implementation changed from bare native.
+
+    /**
+     * Returns an estimate of the number of remaining bytes that can be read (or
+     * skipped over) from this input stream without blocking by the next
+     * invocation of a method for this input stream. Returns 0 when the file
+     * position is beyond EOF. The next invocation might be the same thread
+     * or another thread. A single read or skip of this many bytes will not
+     * block, but may read or skip fewer bytes.
+     *
+     * <p> In some cases, a non-blocking read (or skip) may appear to be
+     * blocked when it is merely slow, for example when reading large
+     * files over slow networks.
+     *
+     * @return     an estimate of the number of remaining bytes that can be read
+     *             (or skipped over) from this input stream without blocking.
+     * @exception  IOException  if this file input stream has been closed by calling
+     *             {@code close} or an I/O error occurs.
+     */
+    // BEGIN Android-changed: available() implementation changed from bare native.
+    public int available() throws IOException {
+        // Android-added: close() check before I/O.
+        if (closed) {
+            throw new IOException("Stream Closed");
+        }
+
+        return available0();
+    }
+
+    private native int available0() throws IOException;
+    // END Android-changed: available() implementation changed from bare native.
+
+    /**
+     * Closes this file input stream and releases any system resources
+     * associated with the stream.
+     *
+     * <p> If this stream has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() throws IOException {
+        synchronized (closeLock) {
+            if (closed) {
+                return;
+            }
+            closed = true;
+        }
+
+        // Android-added: CloseGuard support.
+        guard.close();
+
+        if (channel != null) {
+           channel.close();
+        }
+
+        // BEGIN Android-changed: Close handling / notification of blocked threads.
+        if (isFdOwner) {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        }
+        // END Android-changed: Close handling / notification of blocked threads.
+    }
+
+    /**
+     * Returns the <code>FileDescriptor</code>
+     * object  that represents the connection to
+     * the actual file in the file system being
+     * used by this <code>FileInputStream</code>.
+     *
+     * @return     the file descriptor object associated with this stream.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FileDescriptor
+     */
+    public final FileDescriptor getFD() throws IOException {
+        if (fd != null) {
+            return fd;
+        }
+        throw new IOException();
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file input stream.
+     *
+     * <p> The initial {@link java.nio.channels.FileChannel#position()
+     * position} of the returned channel will be equal to the
+     * number of bytes read from the file so far.  Reading bytes from this
+     * stream will increment the channel's position.  Changing the channel's
+     * position, either explicitly or by reading, will change this stream's
+     * file position.
+     *
+     * @return  the file channel associated with this file input stream
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public FileChannel getChannel() {
+        synchronized (this) {
+            if (channel == null) {
+                channel = FileChannelImpl.open(fd, path, true, false, this);
+            }
+            return channel;
+        }
+    }
+
+    // BEGIN Android-removed: Unused code.
+    /*
+    private static native void initIDs();
+
+    private native void close0() throws IOException;
+
+    static {
+        initIDs();
+    }
+    */
+    // END Android-removed: Unused code.
+
+    /**
+     * Ensures that the <code>close</code> method of this file input stream is
+     * called when there are no more references to it.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FileInputStream#close()
+     */
+    protected void finalize() throws IOException {
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        if ((fd != null) &&  (fd != FileDescriptor.in)) {
+            // Android-removed: Obsoleted comment about shared FileDescriptor handling.
+            close();
+        }
+    }
+}
diff --git a/java/io/FileNotFoundException.java b/java/io/FileNotFoundException.java
new file mode 100644
index 0000000..278fa1d
--- /dev/null
+++ b/java/io/FileNotFoundException.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Signals that an attempt to open the file denoted by a specified pathname
+ * has failed.
+ *
+ * <p> This exception will be thrown by the {@link FileInputStream}, {@link
+ * FileOutputStream}, and {@link RandomAccessFile} constructors when a file
+ * with the specified pathname does not exist.  It will also be thrown by these
+ * constructors if the file does exist but for some reason is inaccessible, for
+ * example when an attempt is made to open a read-only file for writing.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+
+public class FileNotFoundException extends IOException {
+    private static final long serialVersionUID = -897856973823710492L;
+
+    /**
+     * Constructs a <code>FileNotFoundException</code> with
+     * <code>null</code> as its error detail message.
+     */
+    public FileNotFoundException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>FileNotFoundException</code> with the
+     * specified detail message. The string <code>s</code> can be
+     * retrieved later by the
+     * <code>{@link java.lang.Throwable#getMessage}</code>
+     * method of class <code>java.lang.Throwable</code>.
+     *
+     * @param   s   the detail message.
+     */
+    public FileNotFoundException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a <code>FileNotFoundException</code> with a detail message
+     * consisting of the given pathname string followed by the given reason
+     * string.  If the <code>reason</code> argument is <code>null</code> then
+     * it will be omitted.  This private constructor is invoked only by native
+     * I/O methods.
+     *
+     * @since 1.2
+     */
+    private FileNotFoundException(String path, String reason) {
+        super(path + ((reason == null)
+                      ? ""
+                      : " (" + reason + ")"));
+    }
+
+}
diff --git a/java/io/FileOutputStream.java b/java/io/FileOutputStream.java
new file mode 100644
index 0000000..d0d0d40
--- /dev/null
+++ b/java/io/FileOutputStream.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_CREAT;
+import static android.system.OsConstants.O_TRUNC;
+import static android.system.OsConstants.O_WRONLY;
+
+import java.nio.channels.FileChannel;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import sun.nio.ch.FileChannelImpl;
+import libcore.io.IoBridge;
+import libcore.io.IoTracker;
+import libcore.io.IoUtils;
+
+/**
+ * A file output stream is an output stream for writing data to a
+ * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
+ * a file is available or may be created depends upon the underlying
+ * platform.  Some platforms, in particular, allow a file to be opened
+ * for writing by only one <tt>FileOutputStream</tt> (or other
+ * file-writing object) at a time.  In such situations the constructors in
+ * this class will fail if the file involved is already open.
+ *
+ * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
+ * such as image data. For writing streams of characters, consider using
+ * <code>FileWriter</code>.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.io.File
+ * @see     java.io.FileDescriptor
+ * @see     java.io.FileInputStream
+ * @see     java.nio.file.Files#newOutputStream
+ * @since   JDK1.0
+ */
+public
+class FileOutputStream extends OutputStream
+{
+    /**
+     * The system dependent file descriptor.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final FileDescriptor fd;
+
+    /**
+     * True if the file is opened for append.
+     */
+    private final boolean append;
+
+    /**
+     * The associated channel, initialized lazily.
+     */
+    private FileChannel channel;
+
+    /**
+     * The path of the referenced file
+     * (null if the stream is created with a file descriptor)
+     */
+    private final String path;
+
+    private final Object closeLock = new Object();
+    private volatile boolean closed = false;
+
+    // Android-added: CloseGuard support: Log if the stream is not closed.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor.
+    private final boolean isFdOwner;
+
+    // Android-added: Tracking of unbuffered I/O.
+    private final IoTracker tracker = new IoTracker();
+
+    /**
+     * Creates a file output stream to write to the file with the
+     * specified name. A new <code>FileDescriptor</code> object is
+     * created to represent this file connection.
+     * <p>
+     * First, if there is a security manager, its <code>checkWrite</code>
+     * method is called with <code>name</code> as its argument.
+     * <p>
+     * If the file exists but is a directory rather than a regular file, does
+     * not exist but cannot be created, or cannot be opened for any other
+     * reason then a <code>FileNotFoundException</code> is thrown.
+     *
+     * @param      name   the system-dependent filename
+     * @exception  FileNotFoundException  if the file exists but is a directory
+     *                   rather than a regular file, does not exist but cannot
+     *                   be created, or cannot be opened for any other reason
+     * @exception  SecurityException  if a security manager exists and its
+     *               <code>checkWrite</code> method denies write access
+     *               to the file.
+     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
+     */
+    public FileOutputStream(String name) throws FileNotFoundException {
+        this(name != null ? new File(name) : null, false);
+    }
+
+    /**
+     * Creates a file output stream to write to the file with the specified
+     * name.  If the second argument is <code>true</code>, then
+     * bytes will be written to the end of the file rather than the beginning.
+     * A new <code>FileDescriptor</code> object is created to represent this
+     * file connection.
+     * <p>
+     * First, if there is a security manager, its <code>checkWrite</code>
+     * method is called with <code>name</code> as its argument.
+     * <p>
+     * If the file exists but is a directory rather than a regular file, does
+     * not exist but cannot be created, or cannot be opened for any other
+     * reason then a <code>FileNotFoundException</code> is thrown.
+     *
+     * @param     name        the system-dependent file name
+     * @param     append      if <code>true</code>, then bytes will be written
+     *                   to the end of the file rather than the beginning
+     * @exception  FileNotFoundException  if the file exists but is a directory
+     *                   rather than a regular file, does not exist but cannot
+     *                   be created, or cannot be opened for any other reason.
+     * @exception  SecurityException  if a security manager exists and its
+     *               <code>checkWrite</code> method denies write access
+     *               to the file.
+     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
+     * @since     JDK1.1
+     */
+    public FileOutputStream(String name, boolean append)
+        throws FileNotFoundException
+    {
+        this(name != null ? new File(name) : null, append);
+    }
+
+    /**
+     * Creates a file output stream to write to the file represented by
+     * the specified <code>File</code> object. A new
+     * <code>FileDescriptor</code> object is created to represent this
+     * file connection.
+     * <p>
+     * First, if there is a security manager, its <code>checkWrite</code>
+     * method is called with the path represented by the <code>file</code>
+     * argument as its argument.
+     * <p>
+     * If the file exists but is a directory rather than a regular file, does
+     * not exist but cannot be created, or cannot be opened for any other
+     * reason then a <code>FileNotFoundException</code> is thrown.
+     *
+     * @param      file               the file to be opened for writing.
+     * @exception  FileNotFoundException  if the file exists but is a directory
+     *                   rather than a regular file, does not exist but cannot
+     *                   be created, or cannot be opened for any other reason
+     * @exception  SecurityException  if a security manager exists and its
+     *               <code>checkWrite</code> method denies write access
+     *               to the file.
+     * @see        java.io.File#getPath()
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
+     */
+    public FileOutputStream(File file) throws FileNotFoundException {
+        this(file, false);
+    }
+
+    /**
+     * Creates a file output stream to write to the file represented by
+     * the specified <code>File</code> object. If the second argument is
+     * <code>true</code>, then bytes will be written to the end of the file
+     * rather than the beginning. A new <code>FileDescriptor</code> object is
+     * created to represent this file connection.
+     * <p>
+     * First, if there is a security manager, its <code>checkWrite</code>
+     * method is called with the path represented by the <code>file</code>
+     * argument as its argument.
+     * <p>
+     * If the file exists but is a directory rather than a regular file, does
+     * not exist but cannot be created, or cannot be opened for any other
+     * reason then a <code>FileNotFoundException</code> is thrown.
+     *
+     * @param      file               the file to be opened for writing.
+     * @param     append      if <code>true</code>, then bytes will be written
+     *                   to the end of the file rather than the beginning
+     * @exception  FileNotFoundException  if the file exists but is a directory
+     *                   rather than a regular file, does not exist but cannot
+     *                   be created, or cannot be opened for any other reason
+     * @exception  SecurityException  if a security manager exists and its
+     *               <code>checkWrite</code> method denies write access
+     *               to the file.
+     * @see        java.io.File#getPath()
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
+     * @since 1.4
+     */
+    public FileOutputStream(File file, boolean append)
+        throws FileNotFoundException
+    {
+        String name = (file != null ? file.getPath() : null);
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkWrite(name);
+        }
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        if (file.isInvalid()) {
+            throw new FileNotFoundException("Invalid file path");
+        }
+        // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+        // http://b/111268862
+        // this.fd = new FileDescriptor();
+        int flags = O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC);
+        this.fd = IoBridge.open(name, flags);
+        // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+        // Android-changed: Tracking mechanism for FileDescriptor sharing.
+        // fd.attach(this);
+        this.isFdOwner = true;
+
+        this.append = append;
+        this.path = name;
+
+        // Android-removed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+        // open(name, append);
+
+        // Android-added: File descriptor ownership tracking.
+        IoUtils.setFdOwner(this.fd, this);
+
+        // Android-added: CloseGuard support.
+        guard.open("close");
+    }
+
+    // Android-removed: Documentation around SecurityException. Not thrown on Android.
+    /**
+     * Creates a file output stream to write to the specified file
+     * descriptor, which represents an existing connection to an actual
+     * file in the file system.
+     * <p>
+     * First, if there is a security manager, its <code>checkWrite</code>
+     * method is called with the file descriptor <code>fdObj</code>
+     * argument as its argument.
+     * <p>
+     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
+     * is thrown.
+     * <p>
+     * This constructor does not throw an exception if <code>fdObj</code>
+     * is {@link java.io.FileDescriptor#valid() invalid}.
+     * However, if the methods are invoked on the resulting stream to attempt
+     * I/O on the stream, an <code>IOException</code> is thrown.
+     *
+     * @param      fdObj   the file descriptor to be opened for writing
+     */
+    public FileOutputStream(FileDescriptor fdObj) {
+        // Android-changed: Delegate to added hidden constructor.
+        this(fdObj, false /* isOwner */);
+    }
+
+    // Android-added: Internal/hidden constructor for specifying FileDescriptor ownership.
+    // Android-removed: SecurityManager calls.
+    /**
+     * Internal constructor for {@code FileOutputStream} objects where the file descriptor
+     * is owned by this tream.
+     *
+     * @hide
+     */
+    public FileOutputStream(FileDescriptor fdObj, boolean isFdOwner) {
+        if (fdObj == null) {
+            // Android-changed: Improved NullPointerException message.
+            throw new NullPointerException("fdObj == null");
+        }
+
+        this.fd = fdObj;
+        this.append = false;
+        this.path = null;
+
+        // Android-changed: FileDescriptor ownership tracking mechanism.
+        // fd.attach(this);
+        this.isFdOwner = isFdOwner;
+    }
+
+    // BEGIN Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+    // http://b/112107427
+    /*
+    /**
+     * Opens a file, with the specified name, for overwriting or appending.
+     * @param name name of file to be opened
+     * @param append whether the file is to be opened in append mode
+     *
+    private native void open0(String name, boolean append)
+        throws FileNotFoundException;
+
+    // wrap native call to allow instrumentation
+    /**
+     * Opens a file, with the specified name, for overwriting or appending.
+     * @param name name of file to be opened
+     * @param append whether the file is to be opened in append mode
+     *
+    private void open(String name, boolean append)
+        throws FileNotFoundException {
+        open0(name, append);
+    }
+    */
+    // END Android-changed: Open files using IoBridge to share BlockGuard & StrictMode logic.
+
+    // Android-removed: write(int, boolean), use IoBridge instead.
+    /*
+    /**
+     * Writes the specified byte to this file output stream.
+     *
+     * @param   b   the byte to be written.
+     * @param   append   {@code true} if the write operation first
+     *     advances the position to the end of file
+     *
+    private native void write(int b, boolean append) throws IOException;
+    */
+
+    /**
+     * Writes the specified byte to this file output stream. Implements
+     * the <code>write</code> method of <code>OutputStream</code>.
+     *
+     * @param      b   the byte to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(int b) throws IOException {
+        // Android-changed: Write methods delegate to write(byte[],int,int) to share Android logic.
+        write(new byte[] { (byte) b }, 0, 1);
+    }
+
+    // Android-removed: Write methods delegate to write(byte[],int,int) to share Android logic.
+    /*
+    /**
+     * Writes a sub array as a sequence of bytes.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @param append {@code true} to first advance the position to the
+     *     end of file
+     * @exception IOException If an I/O error has occurred.
+     *
+    private native void writeBytes(byte b[], int off, int len, boolean append)
+        throws IOException;
+    */
+
+    /**
+     * Writes <code>b.length</code> bytes from the specified byte array
+     * to this file output stream.
+     *
+     * @param      b   the data.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(byte b[]) throws IOException {
+        // Android-changed: Write methods delegate to write(byte[],int,int) to share Android logic.
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to this file output stream.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        // Android-added: close() check before I/O.
+        if (closed && len > 0) {
+            throw new IOException("Stream Closed");
+        }
+
+        // Android-added: Tracking of unbuffered I/O.
+        tracker.trackIo(len);
+
+        // Android-changed: Use IoBridge instead of calling native method.
+        IoBridge.write(fd, b, off, len);
+    }
+
+    /**
+     * Closes this file output stream and releases any system resources
+     * associated with this stream. This file output stream may no longer
+     * be used for writing bytes.
+     *
+     * <p> If this stream has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() throws IOException {
+        synchronized (closeLock) {
+            if (closed) {
+                return;
+            }
+            closed = true;
+        }
+
+        // Android-added: CloseGuard support.
+        guard.close();
+
+        if (channel != null) {
+            channel.close();
+        }
+
+        // BEGIN Android-changed: Close handling / notification of blocked threads.
+        if (isFdOwner) {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        }
+        // END Android-changed: Close handling / notification of blocked threads.
+    }
+
+    /**
+     * Returns the file descriptor associated with this stream.
+     *
+     * @return  the <code>FileDescriptor</code> object that represents
+     *          the connection to the file in the file system being used
+     *          by this <code>FileOutputStream</code> object.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FileDescriptor
+     */
+     // Android-added: @ReachabilitySensitive
+     @ReachabilitySensitive
+     public final FileDescriptor getFD()  throws IOException {
+        if (fd != null) {
+            return fd;
+        }
+        throw new IOException();
+     }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file output stream.
+     *
+     * <p> The initial {@link java.nio.channels.FileChannel#position()
+     * position} of the returned channel will be equal to the
+     * number of bytes written to the file so far unless this stream is in
+     * append mode, in which case it will be equal to the size of the file.
+     * Writing bytes to this stream will increment the channel's position
+     * accordingly.  Changing the channel's position, either explicitly or by
+     * writing, will change this stream's file position.
+     *
+     * @return  the file channel associated with this file output stream
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public FileChannel getChannel() {
+        synchronized (this) {
+            if (channel == null) {
+                channel = FileChannelImpl.open(fd, path, false, true, append, this);
+            }
+            return channel;
+        }
+    }
+
+    /**
+     * Cleans up the connection to the file, and ensures that the
+     * <code>close</code> method of this file output stream is
+     * called when there are no more references to this stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FileInputStream#close()
+     */
+    protected void finalize() throws IOException {
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        if (fd != null) {
+            if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
+                flush();
+            } else {
+                // Android-removed: Obsoleted comment about shared FileDescriptor handling.
+                close();
+            }
+        }
+    }
+
+    // BEGIN Android-removed: Unused code.
+    /*
+    private native void close0() throws IOException;
+
+    private static native void initIDs();
+
+    static {
+        initIDs();
+    }
+    */
+    // END Android-removed: Unused code.
+
+}
diff --git a/java/io/FilePermission.java b/java/io/FilePermission.java
new file mode 100644
index 0000000..bb69075
--- /dev/null
+++ b/java/io/FilePermission.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class FilePermission extends Permission implements Serializable {
+
+    public FilePermission(String path, String actions) { super(path); }
+
+    public boolean implies(Permission p) { return true; }
+    public String getActions() { return null; }
+}
diff --git a/java/io/FileReader.java b/java/io/FileReader.java
new file mode 100644
index 0000000..acc3a19
--- /dev/null
+++ b/java/io/FileReader.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Convenience class for reading character files.  The constructors of this
+ * class assume that the default character encoding and the default byte-buffer
+ * size are appropriate.  To specify these values yourself, construct an
+ * InputStreamReader on a FileInputStream.
+ *
+ * <p><code>FileReader</code> is meant for reading streams of characters.
+ * For reading streams of raw bytes, consider using a
+ * <code>FileInputStream</code>.
+ *
+ * @see InputStreamReader
+ * @see FileInputStream
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+public class FileReader extends InputStreamReader {
+
+   /**
+    * Creates a new <tt>FileReader</tt>, given the name of the
+    * file to read from.
+    *
+    * @param fileName the name of the file to read from
+    * @exception  FileNotFoundException  if the named file does not exist,
+    *                   is a directory rather than a regular file,
+    *                   or for some other reason cannot be opened for
+    *                   reading.
+    */
+    public FileReader(String fileName) throws FileNotFoundException {
+        super(new FileInputStream(fileName));
+    }
+
+   /**
+    * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
+    * to read from.
+    *
+    * @param file the <tt>File</tt> to read from
+    * @exception  FileNotFoundException  if the file does not exist,
+    *                   is a directory rather than a regular file,
+    *                   or for some other reason cannot be opened for
+    *                   reading.
+    */
+    public FileReader(File file) throws FileNotFoundException {
+        super(new FileInputStream(file));
+    }
+
+   /**
+    * Creates a new <tt>FileReader</tt>, given the
+    * <tt>FileDescriptor</tt> to read from.
+    *
+    * @param fd the FileDescriptor to read from
+    */
+    public FileReader(FileDescriptor fd) {
+        super(new FileInputStream(fd));
+    }
+
+}
diff --git a/java/io/FileSystem.java b/java/io/FileSystem.java
new file mode 100644
index 0000000..ffa640c
--- /dev/null
+++ b/java/io/FileSystem.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.lang.annotation.Native;
+
+/**
+ * Package-private abstract class for the local filesystem abstraction.
+ */
+
+abstract class FileSystem {
+
+    /* -- Normalization and construction -- */
+
+    /**
+     * Return the local filesystem's name-separator character.
+     */
+    public abstract char getSeparator();
+
+    /**
+     * Return the local filesystem's path-separator character.
+     */
+    public abstract char getPathSeparator();
+
+    /**
+     * Convert the given pathname string to normal form.  If the string is
+     * already in normal form then it is simply returned.
+     */
+    public abstract String normalize(String path);
+
+    /**
+     * Compute the length of this pathname string's prefix.  The pathname
+     * string must be in normal form.
+     */
+    public abstract int prefixLength(String path);
+
+    /**
+     * Resolve the child pathname string against the parent.
+     * Both strings must be in normal form, and the result
+     * will be in normal form.
+     */
+    public abstract String resolve(String parent, String child);
+
+    /**
+     * Return the parent pathname string to be used when the parent-directory
+     * argument in one of the two-argument File constructors is the empty
+     * pathname.
+     */
+    public abstract String getDefaultParent();
+
+    /**
+     * Post-process the given URI path string if necessary.  This is used on
+     * win32, e.g., to transform "/c:/foo" into "c:/foo".  The path string
+     * still has slash separators; code in the File class will translate them
+     * after this method returns.
+     */
+    public abstract String fromURIPath(String path);
+
+
+    /* -- Path operations -- */
+
+    /**
+     * Tell whether or not the given abstract pathname is absolute.
+     */
+    public abstract boolean isAbsolute(File f);
+
+    /**
+     * Resolve the given abstract pathname into absolute form.  Invoked by the
+     * getAbsolutePath and getCanonicalPath methods in the File class.
+     */
+    public abstract String resolve(File f);
+
+    public abstract String canonicalize(String path) throws IOException;
+
+
+    /* -- Attribute accessors -- */
+
+    /* Constants for simple boolean attributes */
+    @Native public static final int BA_EXISTS    = 0x01;
+    @Native public static final int BA_REGULAR   = 0x02;
+    @Native public static final int BA_DIRECTORY = 0x04;
+    @Native public static final int BA_HIDDEN    = 0x08;
+
+    /**
+     * Return the simple boolean attributes for the file or directory denoted
+     * by the given abstract pathname, or zero if it does not exist or some
+     * other I/O error occurs.
+     */
+    public abstract int getBooleanAttributes(File f);
+
+    @Native public static final int ACCESS_READ    = 0x04;
+    @Native public static final int ACCESS_WRITE   = 0x02;
+    @Native public static final int ACCESS_EXECUTE = 0x01;
+    // Android-added: b/25878034, to support File.exists() reimplementation.
+    public static final int ACCESS_OK      = 0x08;
+
+    /**
+     * Check whether the file or directory denoted by the given abstract
+     * pathname may be accessed by this process.  The second argument specifies
+     * which access, ACCESS_READ, ACCESS_WRITE or ACCESS_EXECUTE, to check.
+     * Return false if access is denied or an I/O error occurs
+     */
+    public abstract boolean checkAccess(File f, int access);
+    /**
+     * Set on or off the access permission (to owner only or to all) to the file
+     * or directory denoted by the given abstract pathname, based on the parameters
+     * enable, access and oweronly.
+     */
+    public abstract boolean setPermission(File f, int access, boolean enable, boolean owneronly);
+
+    /**
+     * Return the time at which the file or directory denoted by the given
+     * abstract pathname was last modified, or zero if it does not exist or
+     * some other I/O error occurs.
+     */
+    public abstract long getLastModifiedTime(File f);
+
+    /**
+     * Return the length in bytes of the file denoted by the given abstract
+     * pathname, or zero if it does not exist, is a directory, or some other
+     * I/O error occurs.
+     */
+    public abstract long getLength(File f);
+
+
+    /* -- File operations -- */
+
+    /**
+     * Create a new empty file with the given pathname.  Return
+     * <code>true</code> if the file was created and <code>false</code> if a
+     * file or directory with the given pathname already exists.  Throw an
+     * IOException if an I/O error occurs.
+     */
+    public abstract boolean createFileExclusively(String pathname)
+        throws IOException;
+
+    /**
+     * Delete the file or directory denoted by the given abstract pathname,
+     * returning <code>true</code> if and only if the operation succeeds.
+     */
+    public abstract boolean delete(File f);
+
+    /**
+     * List the elements of the directory denoted by the given abstract
+     * pathname.  Return an array of strings naming the elements of the
+     * directory if successful; otherwise, return <code>null</code>.
+     */
+    public abstract String[] list(File f);
+
+    /**
+     * Create a new directory denoted by the given abstract pathname,
+     * returning <code>true</code> if and only if the operation succeeds.
+     */
+    public abstract boolean createDirectory(File f);
+
+    /**
+     * Rename the file or directory denoted by the first abstract pathname to
+     * the second abstract pathname, returning <code>true</code> if and only if
+     * the operation succeeds.
+     */
+    public abstract boolean rename(File f1, File f2);
+
+    /**
+     * Set the last-modified time of the file or directory denoted by the
+     * given abstract pathname, returning <code>true</code> if and only if the
+     * operation succeeds.
+     */
+    public abstract boolean setLastModifiedTime(File f, long time);
+
+    /**
+     * Mark the file or directory denoted by the given abstract pathname as
+     * read-only, returning <code>true</code> if and only if the operation
+     * succeeds.
+     */
+    public abstract boolean setReadOnly(File f);
+
+
+    /* -- Filesystem interface -- */
+
+    /**
+     * List the available filesystem roots.
+     */
+    public abstract File[] listRoots();
+
+    /* -- Disk usage -- */
+    @Native public static final int SPACE_TOTAL  = 0;
+    @Native public static final int SPACE_FREE   = 1;
+    @Native public static final int SPACE_USABLE = 2;
+
+    public abstract long getSpace(File f, int t);
+
+    /* -- Basic infrastructure -- */
+
+    /**
+     * Compare two abstract pathnames lexicographically.
+     */
+    public abstract int compare(File f1, File f2);
+
+    /**
+     * Compute the hash code of an abstract pathname.
+     */
+    public abstract int hashCode(File f);
+
+    // Flags for enabling/disabling performance optimizations for file
+    // name canonicalization
+    // Android-changed: Disabled caches for security reasons (b/62301183)
+    //static boolean useCanonCaches      = true;
+    //static boolean useCanonPrefixCache = true;
+    static boolean useCanonCaches      = false;
+    static boolean useCanonPrefixCache = false;
+
+    private static boolean getBooleanProperty(String prop, boolean defaultVal) {
+        String val = System.getProperty(prop);
+        if (val == null) return defaultVal;
+        if (val.equalsIgnoreCase("true")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    static {
+        useCanonCaches      = getBooleanProperty("sun.io.useCanonCaches",
+                                                 useCanonCaches);
+        useCanonPrefixCache = getBooleanProperty("sun.io.useCanonPrefixCache",
+                                                 useCanonPrefixCache);
+    }
+}
diff --git a/java/io/FileWriter.java b/java/io/FileWriter.java
new file mode 100644
index 0000000..7475ea4
--- /dev/null
+++ b/java/io/FileWriter.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Convenience class for writing character files.  The constructors of this
+ * class assume that the default character encoding and the default byte-buffer
+ * size are acceptable.  To specify these values yourself, construct an
+ * OutputStreamWriter on a FileOutputStream.
+ *
+ * <p>Whether or not a file is available or may be created depends upon the
+ * underlying platform.  Some platforms, in particular, allow a file to be
+ * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
+ * object) at a time.  In such situations the constructors in this class
+ * will fail if the file involved is already open.
+ *
+ * <p><code>FileWriter</code> is meant for writing streams of characters.
+ * For writing streams of raw bytes, consider using a
+ * <code>FileOutputStream</code>.
+ *
+ * @see OutputStreamWriter
+ * @see FileOutputStream
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class FileWriter extends OutputStreamWriter {
+
+    /**
+     * Constructs a FileWriter object given a file name.
+     *
+     * @param fileName  String The system-dependent filename.
+     * @throws IOException  if the named file exists but is a directory rather
+     *                  than a regular file, does not exist but cannot be
+     *                  created, or cannot be opened for any other reason
+     */
+    public FileWriter(String fileName) throws IOException {
+        super(new FileOutputStream(fileName));
+    }
+
+    /**
+     * Constructs a FileWriter object given a file name with a boolean
+     * indicating whether or not to append the data written.
+     *
+     * @param fileName  String The system-dependent filename.
+     * @param append    boolean if <code>true</code>, then data will be written
+     *                  to the end of the file rather than the beginning.
+     * @throws IOException  if the named file exists but is a directory rather
+     *                  than a regular file, does not exist but cannot be
+     *                  created, or cannot be opened for any other reason
+     */
+    public FileWriter(String fileName, boolean append) throws IOException {
+        super(new FileOutputStream(fileName, append));
+    }
+
+    /**
+     * Constructs a FileWriter object given a File object.
+     *
+     * @param file  a File object to write to.
+     * @throws IOException  if the file exists but is a directory rather than
+     *                  a regular file, does not exist but cannot be created,
+     *                  or cannot be opened for any other reason
+     */
+    public FileWriter(File file) throws IOException {
+        super(new FileOutputStream(file));
+    }
+
+    /**
+     * Constructs a FileWriter object given a File object. If the second
+     * argument is <code>true</code>, then bytes will be written to the end
+     * of the file rather than the beginning.
+     *
+     * @param file  a File object to write to
+     * @param     append    if <code>true</code>, then bytes will be written
+     *                      to the end of the file rather than the beginning
+     * @throws IOException  if the file exists but is a directory rather than
+     *                  a regular file, does not exist but cannot be created,
+     *                  or cannot be opened for any other reason
+     * @since 1.4
+     */
+    public FileWriter(File file, boolean append) throws IOException {
+        super(new FileOutputStream(file, append));
+    }
+
+    /**
+     * Constructs a FileWriter object associated with a file descriptor.
+     *
+     * @param fd  FileDescriptor object to write to.
+     */
+    public FileWriter(FileDescriptor fd) {
+        super(new FileOutputStream(fd));
+    }
+
+}
diff --git a/java/io/FilenameFilter.java b/java/io/FilenameFilter.java
new file mode 100644
index 0000000..25d866b
--- /dev/null
+++ b/java/io/FilenameFilter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+// Android-changed: Removed @see tag (target does not exist on Android):
+// @see     java.awt.FileDialog#setFilenameFilter(java.io.FilenameFilter)
+/**
+ * Instances of classes that implement this interface are used to
+ * filter filenames. These instances are used to filter directory
+ * listings in the <code>list</code> method of class
+ * <code>File</code>, and by the Abstract Window Toolkit's file
+ * dialog component.
+ *
+ * @author  Arthur van Hoff
+ * @author  Jonathan Payne
+ * @see     java.io.File
+ * @see     java.io.File#list(java.io.FilenameFilter)
+ * @since   JDK1.0
+ */
+@FunctionalInterface
+public interface FilenameFilter {
+    /**
+     * Tests if a specified file should be included in a file list.
+     *
+     * @param   dir    the directory in which the file was found.
+     * @param   name   the name of the file.
+     * @return  <code>true</code> if and only if the name should be
+     * included in the file list; <code>false</code> otherwise.
+     */
+    boolean accept(File dir, String name);
+}
diff --git a/java/io/FilterInputStream.java b/java/io/FilterInputStream.java
new file mode 100644
index 0000000..10beaea
--- /dev/null
+++ b/java/io/FilterInputStream.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A <code>FilterInputStream</code> contains
+ * some other input stream, which it uses as
+ * its  basic source of data, possibly transforming
+ * the data along the way or providing  additional
+ * functionality. The class <code>FilterInputStream</code>
+ * itself simply overrides all  methods of
+ * <code>InputStream</code> with versions that
+ * pass all requests to the contained  input
+ * stream. Subclasses of <code>FilterInputStream</code>
+ * may further override some of  these methods
+ * and may also provide additional methods
+ * and fields.
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class FilterInputStream extends InputStream {
+    /**
+     * The input stream to be filtered.
+     */
+    protected volatile InputStream in;
+
+    /**
+     * Creates a <code>FilterInputStream</code>
+     * by assigning the  argument <code>in</code>
+     * to the field <code>this.in</code> so as
+     * to remember it for later use.
+     *
+     * @param   in   the underlying input stream, or <code>null</code> if
+     *          this instance is to be created without an underlying stream.
+     */
+    protected FilterInputStream(InputStream in) {
+        this.in = in;
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The value
+     * byte is returned as an <code>int</code> in the range
+     * <code>0</code> to <code>255</code>. If no byte is available
+     * because the end of the stream has been reached, the value
+     * <code>-1</code> is returned. This method blocks until input data
+     * is available, the end of the stream is detected, or an exception
+     * is thrown.
+     * <p>
+     * This method
+     * simply performs <code>in.read()</code> and returns the result.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public int read() throws IOException {
+        return in.read();
+    }
+
+    /**
+     * Reads up to <code>byte.length</code> bytes of data from this
+     * input stream into an array of bytes. This method blocks until some
+     * input is available.
+     * <p>
+     * This method simply performs the call
+     * <code>read(b, 0, b.length)</code> and returns
+     * the  result. It is important that it does
+     * <i>not</i> do <code>in.read(b)</code> instead;
+     * certain subclasses of  <code>FilterInputStream</code>
+     * depend on the implementation strategy actually
+     * used.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#read(byte[], int, int)
+     */
+    public int read(byte b[]) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this input stream
+     * into an array of bytes. If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * <p>
+     * This method simply performs <code>in.read(b, off, len)</code>
+     * and returns the result.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in the destination array <code>b</code>
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        return in.read(b, off, len);
+    }
+
+    /**
+     * Skips over and discards <code>n</code> bytes of data from the
+     * input stream. The <code>skip</code> method may, for a variety of
+     * reasons, end up skipping over some smaller number of bytes,
+     * possibly <code>0</code>. The actual number of bytes skipped is
+     * returned.
+     * <p>
+     * This method simply performs <code>in.skip(n)</code>.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if the stream does not support seek,
+     *                          or if some other I/O error occurs.
+     */
+    public long skip(long n) throws IOException {
+        return in.skip(n);
+    }
+
+    /**
+     * Returns an estimate of the number of bytes that can be read (or
+     * skipped over) from this input stream without blocking by the next
+     * caller of a method for this input stream. The next caller might be
+     * the same thread or another thread.  A single read or skip of this
+     * many bytes will not block, but may read or skip fewer bytes.
+     * <p>
+     * This method returns the result of {@link #in in}.available().
+     *
+     * @return     an estimate of the number of bytes that can be read (or skipped
+     *             over) from this input stream without blocking.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int available() throws IOException {
+        return in.available();
+    }
+
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * This
+     * method simply performs <code>in.close()</code>.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public void close() throws IOException {
+        in.close();
+    }
+
+    /**
+     * Marks the current position in this input stream. A subsequent
+     * call to the <code>reset</code> method repositions this stream at
+     * the last marked position so that subsequent reads re-read the same bytes.
+     * <p>
+     * The <code>readlimit</code> argument tells this input stream to
+     * allow that many bytes to be read before the mark position gets
+     * invalidated.
+     * <p>
+     * This method simply performs <code>in.mark(readlimit)</code>.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.FilterInputStream#in
+     * @see     java.io.FilterInputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {
+        in.mark(readlimit);
+    }
+
+    /**
+     * Repositions this stream to the position at the time the
+     * <code>mark</code> method was last called on this input stream.
+     * <p>
+     * This method
+     * simply performs <code>in.reset()</code>.
+     * <p>
+     * Stream marks are intended to be used in
+     * situations where you need to read ahead a little to see what's in
+     * the stream. Often this is most easily done by invoking some
+     * general parser. If the stream is of the type handled by the
+     * parse, it just chugs along happily. If the stream is not of
+     * that type, the parser should toss an exception when it fails.
+     * If this happens within readlimit bytes, it allows the outer
+     * code to reset the stream and try another parser.
+     *
+     * @exception  IOException  if the stream has not been marked or if the
+     *               mark has been invalidated.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.FilterInputStream#mark(int)
+     */
+    public synchronized void reset() throws IOException {
+        in.reset();
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code>
+     * and <code>reset</code> methods.
+     * This method
+     * simply performs <code>in.markSupported()</code>.
+     *
+     * @return  <code>true</code> if this stream type supports the
+     *          <code>mark</code> and <code>reset</code> method;
+     *          <code>false</code> otherwise.
+     * @see     java.io.FilterInputStream#in
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return in.markSupported();
+    }
+}
diff --git a/java/io/FilterOutputStream.java b/java/io/FilterOutputStream.java
new file mode 100644
index 0000000..89f5ef5
--- /dev/null
+++ b/java/io/FilterOutputStream.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class is the superclass of all classes that filter output
+ * streams. These streams sit on top of an already existing output
+ * stream (the <i>underlying</i> output stream) which it uses as its
+ * basic sink of data, but possibly transforming the data along the
+ * way or providing additional functionality.
+ * <p>
+ * The class <code>FilterOutputStream</code> itself simply overrides
+ * all methods of <code>OutputStream</code> with versions that pass
+ * all requests to the underlying output stream. Subclasses of
+ * <code>FilterOutputStream</code> may further override some of these
+ * methods as well as provide additional methods and fields.
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class FilterOutputStream extends OutputStream {
+    /**
+     * The underlying output stream to be filtered.
+     */
+    protected OutputStream out;
+
+    // Android-added: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+    /**
+     * Whether the stream is closed; implicitly initialized to false.
+     */
+    private boolean closed;
+
+    /**
+     * Creates an output stream filter built on top of the specified
+     * underlying output stream.
+     *
+     * @param   out   the underlying output stream to be assigned to
+     *                the field <tt>this.out</tt> for later use, or
+     *                <code>null</code> if this instance is to be
+     *                created without an underlying stream.
+     */
+    public FilterOutputStream(OutputStream out) {
+        this.out = out;
+    }
+
+    /**
+     * Writes the specified <code>byte</code> to this output stream.
+     * <p>
+     * The <code>write</code> method of <code>FilterOutputStream</code>
+     * calls the <code>write</code> method of its underlying output stream,
+     * that is, it performs <tt>out.write(b)</tt>.
+     * <p>
+     * Implements the abstract <tt>write</tt> method of <tt>OutputStream</tt>.
+     *
+     * @param      b   the <code>byte</code>.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(int b) throws IOException {
+        out.write(b);
+    }
+
+    /**
+     * Writes <code>b.length</code> bytes to this output stream.
+     * <p>
+     * The <code>write</code> method of <code>FilterOutputStream</code>
+     * calls its <code>write</code> method of three arguments with the
+     * arguments <code>b</code>, <code>0</code>, and
+     * <code>b.length</code>.
+     * <p>
+     * Note that this method does not call the one-argument
+     * <code>write</code> method of its underlying stream with the single
+     * argument <code>b</code>.
+     *
+     * @param      b   the data to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#write(byte[], int, int)
+     */
+    public void write(byte b[]) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified
+     * <code>byte</code> array starting at offset <code>off</code> to
+     * this output stream.
+     * <p>
+     * The <code>write</code> method of <code>FilterOutputStream</code>
+     * calls the <code>write</code> method of one argument on each
+     * <code>byte</code> to output.
+     * <p>
+     * Note that this method does not call the <code>write</code> method
+     * of its underlying input stream with the same arguments. Subclasses
+     * of <code>FilterOutputStream</code> should provide a more efficient
+     * implementation of this method.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#write(int)
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
+            throw new IndexOutOfBoundsException();
+
+        for (int i = 0 ; i < len ; i++) {
+            write(b[off + i]);
+        }
+    }
+
+    /**
+     * Flushes this output stream and forces any buffered output bytes
+     * to be written out to the stream.
+     * <p>
+     * The <code>flush</code> method of <code>FilterOutputStream</code>
+     * calls the <code>flush</code> method of its underlying output stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#out
+     */
+    public void flush() throws IOException {
+        out.flush();
+    }
+
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with the stream.
+     * <p>
+     * When not already closed, the {@code close} method of {@code
+     * FilterOutputStream} calls its {@code flush} method, and then
+     * calls the {@code close} method of its underlying output stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterOutputStream#flush()
+     * @see        java.io.FilterOutputStream#out
+     */
+    // BEGIN Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+    /*
+    @SuppressWarnings("try")
+    public void close() throws IOException {
+        try (OutputStream ostream = out) {
+            flush();
+        }
+    }
+    */
+    @Override
+    public void close() throws IOException {
+        if (closed) {
+            return;
+        }
+        closed = true;
+
+        Throwable flushException = null;
+        try {
+            flush();
+        } catch (Throwable e) {
+            flushException = e;
+            throw e;
+        } finally {
+            if (flushException == null) {
+                out.close();
+            } else {
+                try {
+                    out.close();
+                } catch (Throwable closeException) {
+                   // evaluate possible precedence of flushException over closeException
+                   if ((flushException instanceof ThreadDeath) &&
+                       !(closeException instanceof ThreadDeath)) {
+                       flushException.addSuppressed(closeException);
+                       throw (ThreadDeath) flushException;
+                   }
+
+                    if (flushException != closeException) {
+                        closeException.addSuppressed(flushException);
+                    }
+
+                    throw closeException;
+                }
+            }
+        }
+    }
+    // END Android-changed: Integrate OpenJDK 9 fix for double-close. http://b/122733269.
+}
diff --git a/java/io/FilterReader.java b/java/io/FilterReader.java
new file mode 100644
index 0000000..0826230
--- /dev/null
+++ b/java/io/FilterReader.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for reading filtered character streams.
+ * The abstract class <code>FilterReader</code> itself
+ * provides default methods that pass all requests to
+ * the contained stream. Subclasses of <code>FilterReader</code>
+ * should override some of these methods and may also provide
+ * additional methods and fields.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public abstract class FilterReader extends Reader {
+
+    /**
+     * The underlying character-input stream.
+     */
+    protected Reader in;
+
+    /**
+     * Creates a new filtered reader.
+     *
+     * @param in  a Reader object providing the underlying stream.
+     * @throws NullPointerException if <code>in</code> is <code>null</code>
+     */
+    protected FilterReader(Reader in) {
+        super(in);
+        this.in = in;
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        return in.read();
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        return in.read(cbuf, off, len);
+    }
+
+    /**
+     * Skips characters.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        return in.skip(n);
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+        return in.ready();
+    }
+
+    /**
+     * Tells whether this stream supports the mark() operation.
+     */
+    public boolean markSupported() {
+        return in.markSupported();
+    }
+
+    /**
+     * Marks the present position in the stream.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        in.mark(readAheadLimit);
+    }
+
+    /**
+     * Resets the stream.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void reset() throws IOException {
+        in.reset();
+    }
+
+    public void close() throws IOException {
+        in.close();
+    }
+
+}
diff --git a/java/io/FilterWriter.java b/java/io/FilterWriter.java
new file mode 100644
index 0000000..fb307d5
--- /dev/null
+++ b/java/io/FilterWriter.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for writing filtered character streams.
+ * The abstract class <code>FilterWriter</code> itself
+ * provides default methods that pass all requests to the
+ * contained stream. Subclasses of <code>FilterWriter</code>
+ * should override some of these methods and may also
+ * provide additional methods and fields.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public abstract class FilterWriter extends Writer {
+
+    /**
+     * The underlying character-output stream.
+     */
+    protected Writer out;
+
+    /**
+     * Create a new filtered writer.
+     *
+     * @param out  a Writer object to provide the underlying stream.
+     * @throws NullPointerException if <code>out</code> is <code>null</code>
+     */
+    protected FilterWriter(Writer out) {
+        super(out);
+        this.out = out;
+    }
+
+    /**
+     * Writes a single character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(int c) throws IOException {
+        out.write(c);
+    }
+
+    /**
+     * Writes a portion of an array of characters.
+     *
+     * @param  cbuf  Buffer of characters to be written
+     * @param  off   Offset from which to start reading characters
+     * @param  len   Number of characters to be written
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(char cbuf[], int off, int len) throws IOException {
+        out.write(cbuf, off, len);
+    }
+
+    /**
+     * Writes a portion of a string.
+     *
+     * @param  str  String to be written
+     * @param  off  Offset from which to start reading characters
+     * @param  len  Number of characters to be written
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(String str, int off, int len) throws IOException {
+        out.write(str, off, len);
+    }
+
+    /**
+     * Flushes the stream.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void flush() throws IOException {
+        out.flush();
+    }
+
+    public void close() throws IOException {
+        out.close();
+    }
+
+}
diff --git a/java/io/Flushable.java b/java/io/Flushable.java
new file mode 100644
index 0000000..fe90fbd
--- /dev/null
+++ b/java/io/Flushable.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.IOException;
+
+/**
+ * A <tt>Flushable</tt> is a destination of data that can be flushed.  The
+ * flush method is invoked to write any buffered output to the underlying
+ * stream.
+ *
+ * @since 1.5
+ */
+public interface Flushable {
+
+    /**
+     * Flushes this stream by writing any buffered output to the underlying
+     * stream.
+     *
+     * @throws IOException If an I/O error occurs
+     */
+    void flush() throws IOException;
+}
diff --git a/java/io/IOError.java b/java/io/IOError.java
new file mode 100644
index 0000000..f9626cd
--- /dev/null
+++ b/java/io/IOError.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when a serious I/O error has occurred.
+ *
+ * @author  Xueming Shen
+ * @since   1.6
+ */
+public class IOError extends Error {
+    /**
+     * Constructs a new instance of IOError with the specified cause. The
+     * IOError is created with the detail message of
+     * <tt>(cause==null ? null : cause.toString())</tt> (which typically
+     * contains the class and detail message of cause).
+     *
+     * @param  cause
+     *         The cause of this error, or <tt>null</tt> if the cause
+     *         is not known
+     */
+    public IOError(Throwable cause) {
+        super(cause);
+    }
+
+    private static final long serialVersionUID = 67100927991680413L;
+}
diff --git a/java/io/IOException.java b/java/io/IOException.java
new file mode 100644
index 0000000..745b579
--- /dev/null
+++ b/java/io/IOException.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that an I/O exception of some sort has occurred. This
+ * class is the general class of exceptions produced by failed or
+ * interrupted I/O operations.
+ *
+ * @author  unascribed
+ * @see     java.io.InputStream
+ * @see     java.io.OutputStream
+ * @since   JDK1.0
+ */
+public
+class IOException extends Exception {
+    static final long serialVersionUID = 7818375828146090155L;
+
+    /**
+     * Constructs an {@code IOException} with {@code null}
+     * as its error detail message.
+     */
+    public IOException() {
+        super();
+    }
+
+    /**
+     * Constructs an {@code IOException} with the specified detail message.
+     *
+     * @param message
+     *        The detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method)
+     */
+    public IOException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an {@code IOException} with the specified detail message
+     * and cause.
+     *
+     * <p> Note that the detail message associated with {@code cause} is
+     * <i>not</i> automatically incorporated into this exception's detail
+     * message.
+     *
+     * @param message
+     *        The detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method)
+     *
+     * @param cause
+     *        The cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A null value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     *
+     * @since 1.6
+     */
+    public IOException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an {@code IOException} with the specified cause and a
+     * detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of {@code cause}).
+     * This constructor is useful for IO exceptions that are little more
+     * than wrappers for other throwables.
+     *
+     * @param cause
+     *        The cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A null value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     *
+     * @since 1.6
+     */
+    public IOException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/io/InputStream.java b/java/io/InputStream.java
new file mode 100644
index 0000000..6c46a40
--- /dev/null
+++ b/java/io/InputStream.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This abstract class is the superclass of all classes representing
+ * an input stream of bytes.
+ *
+ * <p> Applications that need to define a subclass of <code>InputStream</code>
+ * must always provide a method that returns the next byte of input.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.io.BufferedInputStream
+ * @see     java.io.ByteArrayInputStream
+ * @see     java.io.DataInputStream
+ * @see     java.io.FilterInputStream
+ * @see     java.io.InputStream#read()
+ * @see     java.io.OutputStream
+ * @see     java.io.PushbackInputStream
+ * @since   JDK1.0
+ */
+public abstract class InputStream implements Closeable {
+
+    // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
+    // use when skipping.
+    private static final int MAX_SKIP_BUFFER_SIZE = 2048;
+
+    /**
+     * Reads the next byte of data from the input stream. The value byte is
+     * returned as an <code>int</code> in the range <code>0</code> to
+     * <code>255</code>. If no byte is available because the end of the stream
+     * has been reached, the value <code>-1</code> is returned. This method
+     * blocks until input data is available, the end of the stream is detected,
+     * or an exception is thrown.
+     *
+     * <p> A subclass must provide an implementation of this method.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public abstract int read() throws IOException;
+
+    /**
+     * Reads some number of bytes from the input stream and stores them into
+     * the buffer array <code>b</code>. The number of bytes actually read is
+     * returned as an integer.  This method blocks until input data is
+     * available, end of file is detected, or an exception is thrown.
+     *
+     * <p> If the length of <code>b</code> is zero, then no bytes are read and
+     * <code>0</code> is returned; otherwise, there is an attempt to read at
+     * least one byte. If no byte is available because the stream is at the
+     * end of the file, the value <code>-1</code> is returned; otherwise, at
+     * least one byte is read and stored into <code>b</code>.
+     *
+     * <p> The first byte read is stored into element <code>b[0]</code>, the
+     * next one into <code>b[1]</code>, and so on. The number of bytes read is,
+     * at most, equal to the length of <code>b</code>. Let <i>k</i> be the
+     * number of bytes actually read; these bytes will be stored in elements
+     * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>,
+     * leaving elements <code>b[</code><i>k</i><code>]</code> through
+     * <code>b[b.length-1]</code> unaffected.
+     *
+     * <p> The <code>read(b)</code> method for class <code>InputStream</code>
+     * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre>
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  IOException  If the first byte cannot be read for any reason
+     * other than the end of the file, if the input stream has been closed, or
+     * if some other I/O error occurs.
+     * @exception  NullPointerException  if <code>b</code> is <code>null</code>.
+     * @see        java.io.InputStream#read(byte[], int, int)
+     */
+    public int read(byte b[]) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from the input stream into
+     * an array of bytes.  An attempt is made to read as many as
+     * <code>len</code> bytes, but a smaller number may be read.
+     * The number of bytes actually read is returned as an integer.
+     *
+     * <p> This method blocks until input data is available, end of file is
+     * detected, or an exception is thrown.
+     *
+     * <p> If <code>len</code> is zero, then no bytes are read and
+     * <code>0</code> is returned; otherwise, there is an attempt to read at
+     * least one byte. If no byte is available because the stream is at end of
+     * file, the value <code>-1</code> is returned; otherwise, at least one
+     * byte is read and stored into <code>b</code>.
+     *
+     * <p> The first byte read is stored into element <code>b[off]</code>, the
+     * next one into <code>b[off+1]</code>, and so on. The number of bytes read
+     * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
+     * bytes actually read; these bytes will be stored in elements
+     * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
+     * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
+     * <code>b[off+len-1]</code> unaffected.
+     *
+     * <p> In every case, elements <code>b[0]</code> through
+     * <code>b[off]</code> and elements <code>b[off+len]</code> through
+     * <code>b[b.length-1]</code> are unaffected.
+     *
+     * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method
+     * for class <code>InputStream</code> simply calls the method
+     * <code>read()</code> repeatedly. If the first such call results in an
+     * <code>IOException</code>, that exception is returned from the call to
+     * the <code>read(b,</code> <code>off,</code> <code>len)</code> method.  If
+     * any subsequent call to <code>read()</code> results in a
+     * <code>IOException</code>, the exception is caught and treated as if it
+     * were end of file; the bytes read up to that point are stored into
+     * <code>b</code> and the number of bytes read before the exception
+     * occurred is returned. The default implementation of this method blocks
+     * until the requested amount of input data <code>len</code> has been read,
+     * end of file is detected, or an exception is thrown. Subclasses are encouraged
+     * to provide a more efficient implementation of this method.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in array <code>b</code>
+     *                   at which the data is written.
+     * @param      len   the maximum number of bytes to read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  IOException If the first byte cannot be read for any reason
+     * other than end of file, or if the input stream has been closed, or if
+     * some other I/O error occurs.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @see        java.io.InputStream#read()
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int c = read();
+        if (c == -1) {
+            return -1;
+        }
+        b[off] = (byte)c;
+
+        int i = 1;
+        try {
+            for (; i < len ; i++) {
+                c = read();
+                if (c == -1) {
+                    break;
+                }
+                b[off + i] = (byte)c;
+            }
+        } catch (IOException ee) {
+        }
+        return i;
+    }
+
+    /**
+     * Skips over and discards <code>n</code> bytes of data from this input
+     * stream. The <code>skip</code> method may, for a variety of reasons, end
+     * up skipping over some smaller number of bytes, possibly <code>0</code>.
+     * This may result from any of a number of conditions; reaching end of file
+     * before <code>n</code> bytes have been skipped is only one possibility.
+     * The actual number of bytes skipped is returned. If {@code n} is
+     * negative, the {@code skip} method for class {@code InputStream} always
+     * returns 0, and no bytes are skipped. Subclasses may handle the negative
+     * value differently.
+     *
+     * <p> The <code>skip</code> method of this class creates a
+     * byte array and then repeatedly reads into it until <code>n</code> bytes
+     * have been read or the end of the stream has been reached. Subclasses are
+     * encouraged to provide a more efficient implementation of this method.
+     * For instance, the implementation may depend on the ability to seek.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if the stream does not support seek,
+     *                          or if some other I/O error occurs.
+     */
+    public long skip(long n) throws IOException {
+
+        long remaining = n;
+        int nr;
+
+        if (n <= 0) {
+            return 0;
+        }
+
+        int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
+        byte[] skipBuffer = new byte[size];
+        while (remaining > 0) {
+            nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
+            if (nr < 0) {
+                break;
+            }
+            remaining -= nr;
+        }
+
+        return n - remaining;
+    }
+
+    /**
+     * Returns an estimate of the number of bytes that can be read (or
+     * skipped over) from this input stream without blocking by the next
+     * invocation of a method for this input stream. The next invocation
+     * might be the same thread or another thread.  A single read or skip of this
+     * many bytes will not block, but may read or skip fewer bytes.
+     *
+     * <p> Note that while some implementations of {@code InputStream} will return
+     * the total number of bytes in the stream, many will not.  It is
+     * never correct to use the return value of this method to allocate
+     * a buffer intended to hold all data in this stream.
+     *
+     * <p> A subclass' implementation of this method may choose to throw an
+     * {@link IOException} if this input stream has been closed by
+     * invoking the {@link #close()} method.
+     *
+     * <p> The {@code available} method for class {@code InputStream} always
+     * returns {@code 0}.
+     *
+     * <p> This method should be overridden by subclasses.
+     *
+     * @return     an estimate of the number of bytes that can be read (or skipped
+     *             over) from this input stream without blocking or {@code 0} when
+     *             it reaches the end of the input stream.
+     * @exception  IOException if an I/O error occurs.
+     */
+    public int available() throws IOException {
+        return 0;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     *
+     * <p> The <code>close</code> method of <code>InputStream</code> does
+     * nothing.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close() throws IOException {}
+
+    /**
+     * Marks the current position in this input stream. A subsequent call to
+     * the <code>reset</code> method repositions this stream at the last marked
+     * position so that subsequent reads re-read the same bytes.
+     *
+     * <p> The <code>readlimit</code> arguments tells this input stream to
+     * allow that many bytes to be read before the mark position gets
+     * invalidated.
+     *
+     * <p> The general contract of <code>mark</code> is that, if the method
+     * <code>markSupported</code> returns <code>true</code>, the stream somehow
+     * remembers all the bytes read after the call to <code>mark</code> and
+     * stands ready to supply those same bytes again if and whenever the method
+     * <code>reset</code> is called.  However, the stream is not required to
+     * remember any data at all if more than <code>readlimit</code> bytes are
+     * read from the stream before <code>reset</code> is called.
+     *
+     * <p> Marking a closed stream should not have any effect on the stream.
+     *
+     * <p> The <code>mark</code> method of <code>InputStream</code> does
+     * nothing.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.InputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {}
+
+    /**
+     * Repositions this stream to the position at the time the
+     * <code>mark</code> method was last called on this input stream.
+     *
+     * <p> The general contract of <code>reset</code> is:
+     *
+     * <ul>
+     * <li> If the method <code>markSupported</code> returns
+     * <code>true</code>, then:
+     *
+     *     <ul><li> If the method <code>mark</code> has not been called since
+     *     the stream was created, or the number of bytes read from the stream
+     *     since <code>mark</code> was last called is larger than the argument
+     *     to <code>mark</code> at that last call, then an
+     *     <code>IOException</code> might be thrown.
+     *
+     *     <li> If such an <code>IOException</code> is not thrown, then the
+     *     stream is reset to a state such that all the bytes read since the
+     *     most recent call to <code>mark</code> (or since the start of the
+     *     file, if <code>mark</code> has not been called) will be resupplied
+     *     to subsequent callers of the <code>read</code> method, followed by
+     *     any bytes that otherwise would have been the next input data as of
+     *     the time of the call to <code>reset</code>. </ul>
+     *
+     * <li> If the method <code>markSupported</code> returns
+     * <code>false</code>, then:
+     *
+     *     <ul><li> The call to <code>reset</code> may throw an
+     *     <code>IOException</code>.
+     *
+     *     <li> If an <code>IOException</code> is not thrown, then the stream
+     *     is reset to a fixed state that depends on the particular type of the
+     *     input stream and how it was created. The bytes that will be supplied
+     *     to subsequent callers of the <code>read</code> method depend on the
+     *     particular type of the input stream. </ul></ul>
+     *
+     * <p>The method <code>reset</code> for class <code>InputStream</code>
+     * does nothing except throw an <code>IOException</code>.
+     *
+     * @exception  IOException  if this stream has not been marked or if the
+     *               mark has been invalidated.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.IOException
+     */
+    public synchronized void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code> and
+     * <code>reset</code> methods. Whether or not <code>mark</code> and
+     * <code>reset</code> are supported is an invariant property of a
+     * particular input stream instance. The <code>markSupported</code> method
+     * of <code>InputStream</code> returns <code>false</code>.
+     *
+     * @return  <code>true</code> if this stream instance supports the mark
+     *          and reset methods; <code>false</code> otherwise.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+}
diff --git a/java/io/InputStreamReader.java b/java/io/InputStreamReader.java
new file mode 100644
index 0000000..e131dca
--- /dev/null
+++ b/java/io/InputStreamReader.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import sun.nio.cs.StreamDecoder;
+
+
+/**
+ * An InputStreamReader is a bridge from byte streams to character streams: It
+ * reads bytes and decodes them into characters using a specified {@link
+ * java.nio.charset.Charset charset}.  The charset that it uses
+ * may be specified by name or may be given explicitly, or the platform's
+ * default charset may be accepted.
+ *
+ * <p> Each invocation of one of an InputStreamReader's read() methods may
+ * cause one or more bytes to be read from the underlying byte-input stream.
+ * To enable the efficient conversion of bytes to characters, more bytes may
+ * be read ahead from the underlying stream than are necessary to satisfy the
+ * current read operation.
+ *
+ * <p> For top efficiency, consider wrapping an InputStreamReader within a
+ * BufferedReader.  For example:
+ *
+ * <pre>
+ * BufferedReader in
+ *   = new BufferedReader(new InputStreamReader(System.in));
+ * </pre>
+ *
+ * @see BufferedReader
+ * @see InputStream
+ * @see java.nio.charset.Charset
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class InputStreamReader extends Reader {
+
+    private final StreamDecoder sd;
+
+    /**
+     * Creates an InputStreamReader that uses the default charset.
+     *
+     * @param  in   An InputStream
+     */
+    public InputStreamReader(InputStream in) {
+        super(in);
+        try {
+            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
+        } catch (UnsupportedEncodingException e) {
+            // The default encoding should always be available
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * Creates an InputStreamReader that uses the named charset.
+     *
+     * @param  in
+     *         An InputStream
+     *
+     * @param  charsetName
+     *         The name of a supported
+     *         {@link java.nio.charset.Charset charset}
+     *
+     * @exception  UnsupportedEncodingException
+     *             If the named charset is not supported
+     */
+    public InputStreamReader(InputStream in, String charsetName)
+        throws UnsupportedEncodingException
+    {
+        super(in);
+        if (charsetName == null)
+            throw new NullPointerException("charsetName");
+        sd = StreamDecoder.forInputStreamReader(in, this, charsetName);
+    }
+
+    /**
+     * Creates an InputStreamReader that uses the given charset.
+     *
+     * @param  in       An InputStream
+     * @param  cs       A charset
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public InputStreamReader(InputStream in, Charset cs) {
+        super(in);
+        if (cs == null)
+            throw new NullPointerException("charset");
+        sd = StreamDecoder.forInputStreamReader(in, this, cs);
+    }
+
+    /**
+     * Creates an InputStreamReader that uses the given charset decoder.
+     *
+     * @param  in       An InputStream
+     * @param  dec      A charset decoder
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public InputStreamReader(InputStream in, CharsetDecoder dec) {
+        super(in);
+        if (dec == null)
+            throw new NullPointerException("charset decoder");
+        sd = StreamDecoder.forInputStreamReader(in, this, dec);
+    }
+
+    /**
+     * Returns the name of the character encoding being used by this stream.
+     *
+     * <p> If the encoding has an historical name then that name is returned;
+     * otherwise the encoding's canonical name is returned.
+     *
+     * <p> If this instance was created with the {@link
+     * #InputStreamReader(InputStream, String)} constructor then the returned
+     * name, being unique for the encoding, may differ from the name passed to
+     * the constructor. This method will return <code>null</code> if the
+     * stream has been closed.
+     * </p>
+     * @return The historical name of this encoding, or
+     *         <code>null</code> if the stream has been closed
+     *
+     * @see java.nio.charset.Charset
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public String getEncoding() {
+        return sd.getEncoding();
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @return The character read, or -1 if the end of the stream has been
+     *         reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        return sd.read();
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * @param      cbuf     Destination buffer
+     * @param      offset   Offset at which to start storing characters
+     * @param      length   Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char cbuf[], int offset, int length) throws IOException {
+        return sd.read(cbuf, offset, length);
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.  An InputStreamReader is
+     * ready if its input buffer is not empty, or if bytes are available to be
+     * read from the underlying byte stream.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+        return sd.ready();
+    }
+
+    public void close() throws IOException {
+        sd.close();
+    }
+}
diff --git a/java/io/InterruptedIOException.java b/java/io/InterruptedIOException.java
new file mode 100644
index 0000000..29b7c29
--- /dev/null
+++ b/java/io/InterruptedIOException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that an I/O operation has been interrupted. An
+ * <code>InterruptedIOException</code> is thrown to indicate that an
+ * input or output transfer has been terminated because the thread
+ * performing it was interrupted. The field {@link #bytesTransferred}
+ * indicates how many bytes were successfully transferred before
+ * the interruption occurred.
+ *
+ * @author  unascribed
+ * @see     java.io.InputStream
+ * @see     java.io.OutputStream
+ * @see     java.lang.Thread#interrupt()
+ * @since   JDK1.0
+ */
+public
+class InterruptedIOException extends IOException {
+    private static final long serialVersionUID = 4020568460727500567L;
+
+    /**
+     * Constructs an <code>InterruptedIOException</code> with
+     * <code>null</code> as its error detail message.
+     */
+    public InterruptedIOException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InterruptedIOException</code> with the
+     * specified detail message. The string <code>s</code> can be
+     * retrieved later by the
+     * <code>{@link java.lang.Throwable#getMessage}</code>
+     * method of class <code>java.lang.Throwable</code>.
+     *
+     * @param   s   the detail message.
+     */
+    public InterruptedIOException(String s) {
+        super(s);
+    }
+
+    /**
+     * Reports how many bytes had been transferred as part of the I/O
+     * operation before it was interrupted.
+     *
+     * @serial
+     */
+    public int bytesTransferred = 0;
+
+    // Android-added: Additional constructor for internal use.
+    /** @hide */
+    public InterruptedIOException(Throwable cause) {
+        super(cause);
+    }
+
+    // Android-added: Additional constructor for internal use.
+    /**
+     * Constructs a new instance with given detail message and cause.
+     *
+     * @hide internal use only
+     */
+    public InterruptedIOException(String detailMessage, Throwable cause) {
+        super(detailMessage, cause);
+    }
+}
diff --git a/java/io/InvalidClassException.java b/java/io/InvalidClassException.java
new file mode 100644
index 0000000..77f0a5a
--- /dev/null
+++ b/java/io/InvalidClassException.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when the Serialization runtime detects one of the following
+ * problems with a Class.
+ * <UL>
+ * <LI> The serial version of the class does not match that of the class
+ *      descriptor read from the stream
+ * <LI> The class contains unknown datatypes
+ * <LI> The class does not have an accessible no-arg constructor
+ * </UL>
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class InvalidClassException extends ObjectStreamException {
+
+    private static final long serialVersionUID = -4333316296251054416L;
+
+    /**
+     * Name of the invalid class.
+     *
+     * @serial Name of the invalid class.
+     */
+    public String classname;
+
+    /**
+     * Report an InvalidClassException for the reason specified.
+     *
+     * @param reason  String describing the reason for the exception.
+     */
+    public InvalidClassException(String reason) {
+        super(reason);
+    }
+
+    /**
+     * Constructs an InvalidClassException object.
+     *
+     * @param cname   a String naming the invalid class.
+     * @param reason  a String describing the reason for the exception.
+     */
+    public InvalidClassException(String cname, String reason) {
+        super(reason);
+        classname = cname;
+    }
+
+    /**
+     * Produce the message and include the classname, if present.
+     */
+    public String getMessage() {
+        if (classname == null)
+            return super.getMessage();
+        else
+            return classname + "; " + super.getMessage();
+    }
+}
diff --git a/java/io/InvalidObjectException.java b/java/io/InvalidObjectException.java
new file mode 100644
index 0000000..fbe1108
--- /dev/null
+++ b/java/io/InvalidObjectException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Indicates that one or more deserialized objects failed validation
+ * tests.  The argument should provide the reason for the failure.
+ *
+ * @see ObjectInputValidation
+ * @since JDK1.1
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class InvalidObjectException extends ObjectStreamException {
+
+    private static final long serialVersionUID = 3233174318281839583L;
+
+    /**
+     * Constructs an <code>InvalidObjectException</code>.
+     * @param reason Detailed message explaining the reason for the failure.
+     *
+     * @see ObjectInputValidation
+     */
+    public  InvalidObjectException(String reason) {
+        super(reason);
+    }
+}
diff --git a/java/io/LineNumberInputStream.java b/java/io/LineNumberInputStream.java
new file mode 100644
index 0000000..1f37a98
--- /dev/null
+++ b/java/io/LineNumberInputStream.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class is an input stream filter that provides the added
+ * functionality of keeping track of the current line number.
+ * <p>
+ * A line is a sequence of bytes ending with a carriage return
+ * character ({@code '\u005Cr'}), a newline character
+ * ({@code '\u005Cn'}), or a carriage return character followed
+ * immediately by a linefeed character. In all three cases, the line
+ * terminating character(s) are returned as a single newline character.
+ * <p>
+ * The line number begins at {@code 0}, and is incremented by
+ * {@code 1} when a {@code read} returns a newline character.
+ *
+ * @author     Arthur van Hoff
+ * @see        java.io.LineNumberReader
+ * @since      JDK1.0
+ * @deprecated This class incorrectly assumes that bytes adequately represent
+ *             characters.  As of JDK&nbsp;1.1, the preferred way to operate on
+ *             character streams is via the new character-stream classes, which
+ *             include a class for counting line numbers.
+ */
+@Deprecated
+public
+class LineNumberInputStream extends FilterInputStream {
+    int pushBack = -1;
+    int lineNumber;
+    int markLineNumber;
+    int markPushBack = -1;
+
+    /**
+     * Constructs a newline number input stream that reads its input
+     * from the specified input stream.
+     *
+     * @param      in   the underlying input stream.
+     */
+    public LineNumberInputStream(InputStream in) {
+        super(in);
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The value
+     * byte is returned as an {@code int} in the range
+     * {@code 0} to {@code 255}. If no byte is available
+     * because the end of the stream has been reached, the value
+     * {@code -1} is returned. This method blocks until input data
+     * is available, the end of the stream is detected, or an exception
+     * is thrown.
+     * <p>
+     * The {@code read} method of
+     * {@code LineNumberInputStream} calls the {@code read}
+     * method of the underlying input stream. It checks for carriage
+     * returns and newline characters in the input, and modifies the
+     * current line number as appropriate. A carriage-return character or
+     * a carriage return followed by a newline character are both
+     * converted into a single newline character.
+     *
+     * @return     the next byte of data, or {@code -1} if the end of this
+     *             stream is reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.LineNumberInputStream#getLineNumber()
+     */
+    @SuppressWarnings("fallthrough")
+    public int read() throws IOException {
+        int c = pushBack;
+
+        if (c != -1) {
+            pushBack = -1;
+        } else {
+            c = in.read();
+        }
+
+        switch (c) {
+          case '\r':
+            pushBack = in.read();
+            if (pushBack == '\n') {
+                pushBack = -1;
+            }
+          case '\n':
+            lineNumber++;
+            return '\n';
+        }
+        return c;
+    }
+
+    /**
+     * Reads up to {@code len} bytes of data from this input stream
+     * into an array of bytes. This method blocks until some input is available.
+     * <p>
+     * The {@code read} method of
+     * {@code LineNumberInputStream} repeatedly calls the
+     * {@code read} method of zero arguments to fill in the byte array.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset of the data.
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             {@code -1} if there is no more data because the end of
+     *             this stream has been reached.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.LineNumberInputStream#read()
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if ((off < 0) || (off > b.length) || (len < 0) ||
+                   ((off + len) > b.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int c = read();
+        if (c == -1) {
+            return -1;
+        }
+        b[off] = (byte)c;
+
+        int i = 1;
+        try {
+            for (; i < len ; i++) {
+                c = read();
+                if (c == -1) {
+                    break;
+                }
+                if (b != null) {
+                    b[off + i] = (byte)c;
+                }
+            }
+        } catch (IOException ee) {
+        }
+        return i;
+    }
+
+    /**
+     * Skips over and discards {@code n} bytes of data from this
+     * input stream. The {@code skip} method may, for a variety of
+     * reasons, end up skipping over some smaller number of bytes,
+     * possibly {@code 0}. The actual number of bytes skipped is
+     * returned.  If {@code n} is negative, no bytes are skipped.
+     * <p>
+     * The {@code skip} method of {@code LineNumberInputStream} creates
+     * a byte array and then repeatedly reads into it until
+     * {@code n} bytes have been read or the end of the stream has
+     * been reached.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public long skip(long n) throws IOException {
+        int chunk = 2048;
+        long remaining = n;
+        byte data[];
+        int nr;
+
+        if (n <= 0) {
+            return 0;
+        }
+
+        data = new byte[chunk];
+        while (remaining > 0) {
+            nr = read(data, 0, (int) Math.min(chunk, remaining));
+            if (nr < 0) {
+                break;
+            }
+            remaining -= nr;
+        }
+
+        return n - remaining;
+    }
+
+    /**
+     * Sets the line number to the specified argument.
+     *
+     * @param      lineNumber   the new line number.
+     * @see #getLineNumber
+     */
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    /**
+     * Returns the current line number.
+     *
+     * @return     the current line number.
+     * @see #setLineNumber
+     */
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+
+    /**
+     * Returns the number of bytes that can be read from this input
+     * stream without blocking.
+     * <p>
+     * Note that if the underlying input stream is able to supply
+     * <i>k</i> input characters without blocking, the
+     * {@code LineNumberInputStream} can guarantee only to provide
+     * <i>k</i>/2 characters without blocking, because the
+     * <i>k</i> characters from the underlying input stream might
+     * consist of <i>k</i>/2 pairs of {@code '\u005Cr'} and
+     * {@code '\u005Cn'}, which are converted to just
+     * <i>k</i>/2 {@code '\u005Cn'} characters.
+     *
+     * @return     the number of bytes that can be read from this input stream
+     *             without blocking.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     */
+    public int available() throws IOException {
+        return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
+    }
+
+    /**
+     * Marks the current position in this input stream. A subsequent
+     * call to the {@code reset} method repositions this stream at
+     * the last marked position so that subsequent reads re-read the same bytes.
+     * <p>
+     * The {@code mark} method of
+     * {@code LineNumberInputStream} remembers the current line
+     * number in a private variable, and then calls the {@code mark}
+     * method of the underlying input stream.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.FilterInputStream#in
+     * @see     java.io.LineNumberInputStream#reset()
+     */
+    public void mark(int readlimit) {
+        markLineNumber = lineNumber;
+        markPushBack   = pushBack;
+        in.mark(readlimit);
+    }
+
+    /**
+     * Repositions this stream to the position at the time the
+     * {@code mark} method was last called on this input stream.
+     * <p>
+     * The {@code reset} method of
+     * {@code LineNumberInputStream} resets the line number to be
+     * the line number at the time the {@code mark} method was
+     * called, and then calls the {@code reset} method of the
+     * underlying input stream.
+     * <p>
+     * Stream marks are intended to be used in
+     * situations where you need to read ahead a little to see what's in
+     * the stream. Often this is most easily done by invoking some
+     * general parser. If the stream is of the type handled by the
+     * parser, it just chugs along happily. If the stream is not of
+     * that type, the parser should toss an exception when it fails,
+     * which, if it happens within readlimit bytes, allows the outer
+     * code to reset the stream and try another parser.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.LineNumberInputStream#mark(int)
+     */
+    public void reset() throws IOException {
+        lineNumber = markLineNumber;
+        pushBack   = markPushBack;
+        in.reset();
+    }
+}
diff --git a/java/io/LineNumberReader.java b/java/io/LineNumberReader.java
new file mode 100644
index 0000000..29884fd
--- /dev/null
+++ b/java/io/LineNumberReader.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A buffered character-input stream that keeps track of line numbers.  This
+ * class defines methods {@link #setLineNumber(int)} and {@link
+ * #getLineNumber()} for setting and getting the current line number
+ * respectively.
+ *
+ * <p> By default, line numbering begins at 0. This number increments at every
+ * <a href="#lt">line terminator</a> as the data is read, and can be changed
+ * with a call to <tt>setLineNumber(int)</tt>.  Note however, that
+ * <tt>setLineNumber(int)</tt> does not actually change the current position in
+ * the stream; it only changes the value that will be returned by
+ * <tt>getLineNumber()</tt>.
+ *
+ * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
+ * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
+ * immediately by a linefeed.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class LineNumberReader extends BufferedReader {
+
+    /** The current line number */
+    private int lineNumber = 0;
+
+    /** The line number of the mark, if any */
+    private int markedLineNumber; // Defaults to 0
+
+    /** If the next character is a line feed, skip it */
+    private boolean skipLF;
+
+    /** The skipLF flag when the mark was set */
+    private boolean markedSkipLF;
+
+    /**
+     * Create a new line-numbering reader, using the default input-buffer
+     * size.
+     *
+     * @param  in
+     *         A Reader object to provide the underlying stream
+     */
+    public LineNumberReader(Reader in) {
+        super(in);
+    }
+
+    /**
+     * Create a new line-numbering reader, reading characters into a buffer of
+     * the given size.
+     *
+     * @param  in
+     *         A Reader object to provide the underlying stream
+     *
+     * @param  sz
+     *         An int specifying the size of the buffer
+     */
+    public LineNumberReader(Reader in, int sz) {
+        super(in, sz);
+    }
+
+    /**
+     * Set the current line number.
+     *
+     * @param  lineNumber
+     *         An int specifying the line number
+     *
+     * @see #getLineNumber
+     */
+    public void setLineNumber(int lineNumber) {
+        this.lineNumber = lineNumber;
+    }
+
+    /**
+     * Get the current line number.
+     *
+     * @return  The current line number
+     *
+     * @see #setLineNumber
+     */
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    /**
+     * Read a single character.  <a href="#lt">Line terminators</a> are
+     * compressed into single newline ('\n') characters.  Whenever a line
+     * terminator is read the current line number is incremented.
+     *
+     * @return  The character read, or -1 if the end of the stream has been
+     *          reached
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @SuppressWarnings("fallthrough")
+    public int read() throws IOException {
+        synchronized (lock) {
+            int c = super.read();
+            if (skipLF) {
+                if (c == '\n')
+                    c = super.read();
+                skipLF = false;
+            }
+            switch (c) {
+            case '\r':
+                skipLF = true;
+            case '\n':          /* Fall through */
+                lineNumber++;
+                return '\n';
+            }
+            return c;
+        }
+    }
+
+    /**
+     * Read characters into a portion of an array.  Whenever a <a
+     * href="#lt">line terminator</a> is read the current line number is
+     * incremented.
+     *
+     * @param  cbuf
+     *         Destination buffer
+     *
+     * @param  off
+     *         Offset at which to start storing characters
+     *
+     * @param  len
+     *         Maximum number of characters to read
+     *
+     * @return  The number of bytes read, or -1 if the end of the stream has
+     *          already been reached
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @SuppressWarnings("fallthrough")
+    public int read(char cbuf[], int off, int len) throws IOException {
+        synchronized (lock) {
+            int n = super.read(cbuf, off, len);
+
+            for (int i = off; i < off + n; i++) {
+                int c = cbuf[i];
+                if (skipLF) {
+                    skipLF = false;
+                    if (c == '\n')
+                        continue;
+                }
+                switch (c) {
+                case '\r':
+                    skipLF = true;
+                case '\n':      /* Fall through */
+                    lineNumber++;
+                    break;
+                }
+            }
+
+            return n;
+        }
+    }
+
+    /**
+     * Read a line of text.  Whenever a <a href="#lt">line terminator</a> is
+     * read the current line number is incremented.
+     *
+     * @return  A String containing the contents of the line, not including
+     *          any <a href="#lt">line termination characters</a>, or
+     *          <tt>null</tt> if the end of the stream has been reached
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public String readLine() throws IOException {
+        synchronized (lock) {
+            String l = super.readLine(skipLF);
+            skipLF = false;
+            if (l != null)
+                lineNumber++;
+            return l;
+        }
+    }
+
+    /** Maximum skip-buffer size */
+    private static final int maxSkipBufferSize = 8192;
+
+    /** Skip buffer, null until allocated */
+    private char skipBuffer[] = null;
+
+    /**
+     * Skip characters.
+     *
+     * @param  n
+     *         The number of characters to skip
+     *
+     * @return  The number of characters actually skipped
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  IllegalArgumentException
+     *          If <tt>n</tt> is negative
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0)
+            throw new IllegalArgumentException("skip() value is negative");
+        int nn = (int) Math.min(n, maxSkipBufferSize);
+        synchronized (lock) {
+            if ((skipBuffer == null) || (skipBuffer.length < nn))
+                skipBuffer = new char[nn];
+            long r = n;
+            while (r > 0) {
+                int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
+                if (nc == -1)
+                    break;
+                r -= nc;
+            }
+            return n - r;
+        }
+    }
+
+    /**
+     * Mark the present position in the stream.  Subsequent calls to reset()
+     * will attempt to reposition the stream to this point, and will also reset
+     * the line number appropriately.
+     *
+     * @param  readAheadLimit
+     *         Limit on the number of characters that may be read while still
+     *         preserving the mark.  After reading this many characters,
+     *         attempting to reset the stream may fail.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        synchronized (lock) {
+            super.mark(readAheadLimit);
+            markedLineNumber = lineNumber;
+            markedSkipLF     = skipLF;
+        }
+    }
+
+    /**
+     * Reset the stream to the most recent mark.
+     *
+     * @throws  IOException
+     *          If the stream has not been marked, or if the mark has been
+     *          invalidated
+     */
+    public void reset() throws IOException {
+        synchronized (lock) {
+            super.reset();
+            lineNumber = markedLineNumber;
+            skipLF     = markedSkipLF;
+        }
+    }
+
+}
diff --git a/java/io/NotActiveException.java b/java/io/NotActiveException.java
new file mode 100644
index 0000000..13291e6
--- /dev/null
+++ b/java/io/NotActiveException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when serialization or deserialization is not active.
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class NotActiveException extends ObjectStreamException {
+
+    private static final long serialVersionUID = -3893467273049808895L;
+
+    /**
+     * Constructor to create a new NotActiveException with the reason given.
+     *
+     * @param reason  a String describing the reason for the exception.
+     */
+    public NotActiveException(String reason) {
+        super(reason);
+    }
+
+    /**
+     * Constructor to create a new NotActiveException without a reason.
+     */
+    public NotActiveException() {
+        super();
+    }
+}
diff --git a/java/io/NotSerializableException.java b/java/io/NotSerializableException.java
new file mode 100644
index 0000000..70e4f57
--- /dev/null
+++ b/java/io/NotSerializableException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when an instance is required to have a Serializable interface.
+ * The serialization runtime or the class of the instance can throw
+ * this exception. The argument should be the name of the class.
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class NotSerializableException extends ObjectStreamException {
+
+    private static final long serialVersionUID = 2906642554793891381L;
+
+    /**
+     * Constructs a NotSerializableException object with message string.
+     *
+     * @param classname Class of the instance being serialized/deserialized.
+     */
+    public NotSerializableException(String classname) {
+        super(classname);
+    }
+
+    /**
+     *  Constructs a NotSerializableException object.
+     */
+    public NotSerializableException() {
+        super();
+    }
+}
diff --git a/java/io/ObjectInput.java b/java/io/ObjectInput.java
new file mode 100644
index 0000000..bc7c26b
--- /dev/null
+++ b/java/io/ObjectInput.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * ObjectInput extends the DataInput interface to include the reading of
+ * objects. DataInput includes methods for the input of primitive types,
+ * ObjectInput extends that interface to include objects, arrays, and Strings.
+ *
+ * @author  unascribed
+ * @see java.io.InputStream
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @since   JDK1.1
+ */
+public interface ObjectInput extends DataInput, AutoCloseable {
+    /**
+     * Read and return an object. The class that implements this interface
+     * defines where the object is "read" from.
+     *
+     * @return the object read from the stream
+     * @exception java.lang.ClassNotFoundException If the class of a serialized
+     *      object cannot be found.
+     * @exception IOException If any of the usual Input/Output
+     * related exceptions occur.
+     */
+    public Object readObject()
+        throws ClassNotFoundException, IOException;
+
+    /**
+     * Reads a byte of data. This method will block if no input is
+     * available.
+     * @return  the byte read, or -1 if the end of the
+     *          stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read() throws IOException;
+
+    /**
+     * Reads into an array of bytes.  This method will
+     * block until some input is available.
+     * @param b the buffer into which the data is read
+     * @return  the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read(byte b[]) throws IOException;
+
+    /**
+     * Reads into an array of bytes.  This method will
+     * block until some input is available.
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes read
+     * @return  the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read(byte b[], int off, int len) throws IOException;
+
+    /**
+     * Skips n bytes of input.
+     * @param n the number of bytes to be skipped
+     * @return  the actual number of bytes skipped.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public long skip(long n) throws IOException;
+
+    /**
+     * Returns the number of bytes that can be read
+     * without blocking.
+     * @return the number of available bytes.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int available() throws IOException;
+
+    /**
+     * Closes the input stream. Must be called
+     * to release any resources associated with
+     * the stream.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void close() throws IOException;
+}
diff --git a/java/io/ObjectInputStream.java b/java/io/ObjectInputStream.java
new file mode 100644
index 0000000..8369a59
--- /dev/null
+++ b/java/io/ObjectInputStream.java
@@ -0,0 +1,3716 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.ObjectStreamClass.WeakClassKey;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.Array;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import static java.io.ObjectStreamClass.processQueue;
+import sun.reflect.misc.ReflectUtil;
+import dalvik.system.VMStack;
+
+/**
+ * An ObjectInputStream deserializes primitive data and objects previously
+ * written using an ObjectOutputStream.
+ *
+ * <p>ObjectOutputStream and ObjectInputStream can provide an application with
+ * persistent storage for graphs of objects when used with a FileOutputStream
+ * and FileInputStream respectively.  ObjectInputStream is used to recover
+ * those objects previously serialized. Other uses include passing objects
+ * between hosts using a socket stream or for marshaling and unmarshaling
+ * arguments and parameters in a remote communication system.
+ *
+ * <p>ObjectInputStream ensures that the types of all objects in the graph
+ * created from the stream match the classes present in the Java Virtual
+ * Machine.  Classes are loaded as required using the standard mechanisms.
+ *
+ * <p>Only objects that support the java.io.Serializable or
+ * java.io.Externalizable interface can be read from streams.
+ *
+ * <p>The method <code>readObject</code> is used to read an object from the
+ * stream.  Java's safe casting should be used to get the desired type.  In
+ * Java, strings and arrays are objects and are treated as objects during
+ * serialization. When read they need to be cast to the expected type.
+ *
+ * <p>Primitive data types can be read from the stream using the appropriate
+ * method on DataInput.
+ *
+ * <p>The default deserialization mechanism for objects restores the contents
+ * of each field to the value and type it had when it was written.  Fields
+ * declared as transient or static are ignored by the deserialization process.
+ * References to other objects cause those objects to be read from the stream
+ * as necessary.  Graphs of objects are restored correctly using a reference
+ * sharing mechanism.  New objects are always allocated when deserializing,
+ * which prevents existing objects from being overwritten.
+ *
+ * <p>Reading an object is analogous to running the constructors of a new
+ * object.  Memory is allocated for the object and initialized to zero (NULL).
+ * No-arg constructors are invoked for the non-serializable classes and then
+ * the fields of the serializable classes are restored from the stream starting
+ * with the serializable class closest to java.lang.object and finishing with
+ * the object's most specific class.
+ *
+ * <p>For example to read from a stream as written by the example in
+ * ObjectOutputStream:
+ * <br>
+ * <pre>
+ *      FileInputStream fis = new FileInputStream("t.tmp");
+ *      ObjectInputStream ois = new ObjectInputStream(fis);
+ *
+ *      int i = ois.readInt();
+ *      String today = (String) ois.readObject();
+ *      Date date = (Date) ois.readObject();
+ *
+ *      ois.close();
+ * </pre>
+ *
+ * <p>Classes control how they are serialized by implementing either the
+ * java.io.Serializable or java.io.Externalizable interfaces.
+ *
+ * <p>Implementing the Serializable interface allows object serialization to
+ * save and restore the entire state of the object and it allows classes to
+ * evolve between the time the stream is written and the time it is read.  It
+ * automatically traverses references between objects, saving and restoring
+ * entire graphs.
+ *
+ * <p>Serializable classes that require special handling during the
+ * serialization and deserialization process should implement the following
+ * methods:
+ *
+ * <pre>
+ * private void writeObject(java.io.ObjectOutputStream stream)
+ *     throws IOException;
+ * private void readObject(java.io.ObjectInputStream stream)
+ *     throws IOException, ClassNotFoundException;
+ * private void readObjectNoData()
+ *     throws ObjectStreamException;
+ * </pre>
+ *
+ * <p>The readObject method is responsible for reading and restoring the state
+ * of the object for its particular class using data written to the stream by
+ * the corresponding writeObject method.  The method does not need to concern
+ * itself with the state belonging to its superclasses or subclasses.  State is
+ * restored by reading data from the ObjectInputStream for the individual
+ * fields and making assignments to the appropriate fields of the object.
+ * Reading primitive data types is supported by DataInput.
+ *
+ * <p>Any attempt to read object data which exceeds the boundaries of the
+ * custom data written by the corresponding writeObject method will cause an
+ * OptionalDataException to be thrown with an eof field value of true.
+ * Non-object reads which exceed the end of the allotted data will reflect the
+ * end of data in the same way that they would indicate the end of the stream:
+ * bytewise reads will return -1 as the byte read or number of bytes read, and
+ * primitive reads will throw EOFExceptions.  If there is no corresponding
+ * writeObject method, then the end of default serialized data marks the end of
+ * the allotted data.
+ *
+ * <p>Primitive and object read calls issued from within a readExternal method
+ * behave in the same manner--if the stream is already positioned at the end of
+ * data written by the corresponding writeExternal method, object reads will
+ * throw OptionalDataExceptions with eof set to true, bytewise reads will
+ * return -1, and primitive reads will throw EOFExceptions.  Note that this
+ * behavior does not hold for streams written with the old
+ * <code>ObjectStreamConstants.PROTOCOL_VERSION_1</code> protocol, in which the
+ * end of data written by writeExternal methods is not demarcated, and hence
+ * cannot be detected.
+ *
+ * <p>The readObjectNoData method is responsible for initializing the state of
+ * the object for its particular class in the event that the serialization
+ * stream does not list the given class as a superclass of the object being
+ * deserialized.  This may occur in cases where the receiving party uses a
+ * different version of the deserialized instance's class than the sending
+ * party, and the receiver's version extends classes that are not extended by
+ * the sender's version.  This may also occur if the serialization stream has
+ * been tampered; hence, readObjectNoData is useful for initializing
+ * deserialized objects properly despite a "hostile" or incomplete source
+ * stream.
+ *
+ * <p>Serialization does not read or assign values to the fields of any object
+ * that does not implement the java.io.Serializable interface.  Subclasses of
+ * Objects that are not serializable can be serializable. In this case the
+ * non-serializable class must have a no-arg constructor to allow its fields to
+ * be initialized.  In this case it is the responsibility of the subclass to
+ * save and restore the state of the non-serializable class. It is frequently
+ * the case that the fields of that class are accessible (public, package, or
+ * protected) or that there are get and set methods that can be used to restore
+ * the state.
+ *
+ * <p>Any exception that occurs while deserializing an object will be caught by
+ * the ObjectInputStream and abort the reading process.
+ *
+ * <p>Implementing the Externalizable interface allows the object to assume
+ * complete control over the contents and format of the object's serialized
+ * form.  The methods of the Externalizable interface, writeExternal and
+ * readExternal, are called to save and restore the objects state.  When
+ * implemented by a class they can write and read their own state using all of
+ * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
+ * the objects to handle any versioning that occurs.
+ *
+ * <p>Enum constants are deserialized differently than ordinary serializable or
+ * externalizable objects.  The serialized form of an enum constant consists
+ * solely of its name; field values of the constant are not transmitted.  To
+ * deserialize an enum constant, ObjectInputStream reads the constant name from
+ * the stream; the deserialized constant is then obtained by calling the static
+ * method <code>Enum.valueOf(Class, String)</code> with the enum constant's
+ * base type and the received constant name as arguments.  Like other
+ * serializable or externalizable objects, enum constants can function as the
+ * targets of back references appearing subsequently in the serialization
+ * stream.  The process by which enum constants are deserialized cannot be
+ * customized: any class-specific readObject, readObjectNoData, and readResolve
+ * methods defined by enum types are ignored during deserialization.
+ * Similarly, any serialPersistentFields or serialVersionUID field declarations
+ * are also ignored--all enum types have a fixed serialVersionUID of 0L.
+ *
+ * @author      Mike Warres
+ * @author      Roger Riggs
+ * @see java.io.DataInput
+ * @see java.io.ObjectOutputStream
+ * @see java.io.Serializable
+ * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
+ * @since   JDK1.1
+ */
+public class ObjectInputStream
+    extends InputStream implements ObjectInput, ObjectStreamConstants
+{
+    /** handle value representing null */
+    private static final int NULL_HANDLE = -1;
+
+    /** marker for unshared objects in internal handle table */
+    private static final Object unsharedMarker = new Object();
+
+    /** table mapping primitive type names to corresponding class objects */
+    private static final HashMap<String, Class<?>> primClasses
+        = new HashMap<>(8, 1.0F);
+    static {
+        primClasses.put("boolean", boolean.class);
+        primClasses.put("byte", byte.class);
+        primClasses.put("char", char.class);
+        primClasses.put("short", short.class);
+        primClasses.put("int", int.class);
+        primClasses.put("long", long.class);
+        primClasses.put("float", float.class);
+        primClasses.put("double", double.class);
+        primClasses.put("void", void.class);
+    }
+
+    private static class Caches {
+        /** cache of subclass security audit results */
+        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
+            new ConcurrentHashMap<>();
+
+        /** queue for WeakReferences to audited subclasses */
+        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
+            new ReferenceQueue<>();
+    }
+
+    // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+    /*
+    static {
+        /* Setup access so sun.misc can invoke package private functions. *
+        sun.misc.SharedSecrets.setJavaOISAccess(new JavaOISAccess() {
+            public void setObjectInputFilter(ObjectInputStream stream, ObjectInputFilter filter) {
+                stream.setInternalObjectInputFilter(filter);
+            }
+
+            public ObjectInputFilter getObjectInputFilter(ObjectInputStream stream) {
+                return stream.getInternalObjectInputFilter();
+            }
+        });
+    }
+
+    /*
+     * Separate class to defer initialization of logging until needed.
+     *
+    private static class Logging {
+
+        /*
+         * Logger for ObjectInputFilter results.
+         * Setup the filter logger if it is set to INFO or WARNING.
+         * (Assuming it will not change).
+         *
+        private static final PlatformLogger traceLogger;
+        private static final PlatformLogger infoLogger;
+        static {
+            PlatformLogger filterLog = PlatformLogger.getLogger("java.io.serialization");
+            infoLogger = (filterLog != null &&
+                filterLog.isLoggable(PlatformLogger.Level.INFO)) ? filterLog : null;
+            traceLogger = (filterLog != null &&
+                filterLog.isLoggable(PlatformLogger.Level.FINER)) ? filterLog : null;
+        }
+    }
+    */
+
+    /** filter stream for handling block data conversion */
+    private final BlockDataInputStream bin;
+    /** validation callback list */
+    private final ValidationList vlist;
+    /** recursion depth */
+    // Android-changed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+    // private long depth;
+    private int depth;
+    // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+    // /** Total number of references to any type of object, class, enum, proxy, etc. */
+    // private long totalObjectRefs;
+    /** whether stream is closed */
+    private boolean closed;
+
+    /** wire handle -> obj/exception map */
+    private final HandleTable handles;
+    /** scratch field for passing handle values up/down call stack */
+    private int passHandle = NULL_HANDLE;
+    /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
+    private boolean defaultDataEnd = false;
+
+    /** buffer for reading primitive field values */
+    private byte[] primVals;
+
+    /** if true, invoke readObjectOverride() instead of readObject() */
+    private final boolean enableOverride;
+    /** if true, invoke resolveObject() */
+    private boolean enableResolve;
+
+    /**
+     * Context during upcalls to class-defined readObject methods; holds
+     * object currently being deserialized and descriptor for current class.
+     * Null when not during readObject upcall.
+     */
+    private SerialCallbackContext curContext;
+
+    // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+    /**
+     * Filter of class descriptors and classes read from the stream;
+     * may be null.
+     *
+    private ObjectInputFilter serialFilter;
+    */
+
+    /**
+     * Creates an ObjectInputStream that reads from the specified InputStream.
+     * A serialization stream header is read from the stream and verified.
+     * This constructor will block until the corresponding ObjectOutputStream
+     * has written and flushed the header.
+     *
+     * <p>If a security manager is installed, this constructor will check for
+     * the "enableSubclassImplementation" SerializablePermission when invoked
+     * directly or indirectly by the constructor of a subclass which overrides
+     * the ObjectInputStream.readFields or ObjectInputStream.readUnshared
+     * methods.
+     *
+     * @param   in input stream to read from
+     * @throws  StreamCorruptedException if the stream header is incorrect
+     * @throws  IOException if an I/O error occurs while reading stream header
+     * @throws  SecurityException if untrusted subclass illegally overrides
+     *          security-sensitive methods
+     * @throws  NullPointerException if <code>in</code> is <code>null</code>
+     * @see     ObjectInputStream#ObjectInputStream()
+     * @see     ObjectInputStream#readFields()
+     * @see     ObjectOutputStream#ObjectOutputStream(OutputStream)
+     */
+    public ObjectInputStream(InputStream in) throws IOException {
+        verifySubclass();
+        bin = new BlockDataInputStream(in);
+        handles = new HandleTable(10);
+        vlist = new ValidationList();
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // serialFilter = ObjectInputFilter.Config.getSerialFilter();
+        enableOverride = false;
+        readStreamHeader();
+        bin.setBlockDataMode(true);
+    }
+
+    /**
+     * Provide a way for subclasses that are completely reimplementing
+     * ObjectInputStream to not have to allocate private data just used by this
+     * implementation of ObjectInputStream.
+     *
+     * <p>If there is a security manager installed, this method first calls the
+     * security manager's <code>checkPermission</code> method with the
+     * <code>SerializablePermission("enableSubclassImplementation")</code>
+     * permission to ensure it's ok to enable subclassing.
+     *
+     * @throws  SecurityException if a security manager exists and its
+     *          <code>checkPermission</code> method denies enabling
+     *          subclassing.
+     * @throws  IOException if an I/O error occurs while creating this stream
+     * @see SecurityManager#checkPermission
+     * @see java.io.SerializablePermission
+     */
+    protected ObjectInputStream() throws IOException, SecurityException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+        }
+        bin = null;
+        handles = null;
+        vlist = null;
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // serialFilter = ObjectInputFilter.Config.getSerialFilter();
+        enableOverride = true;
+    }
+
+    /**
+     * Read an object from the ObjectInputStream.  The class of the object, the
+     * signature of the class, and the values of the non-transient and
+     * non-static fields of the class and all of its supertypes are read.
+     * Default deserializing for a class can be overridden using the writeObject
+     * and readObject methods.  Objects referenced by this object are read
+     * transitively so that a complete equivalent graph of objects is
+     * reconstructed by readObject.
+     *
+     * <p>The root object is completely restored when all of its fields and the
+     * objects it references are completely restored.  At this point the object
+     * validation callbacks are executed in order based on their registered
+     * priorities. The callbacks are registered by objects (in the readObject
+     * special methods) as they are individually restored.
+     *
+     * <p>Exceptions are thrown for problems with the InputStream and for
+     * classes that should not be deserialized.  All exceptions are fatal to
+     * the InputStream and leave it in an indeterminate state; it is up to the
+     * caller to ignore or recover the stream state.
+     *
+     * @throws  ClassNotFoundException Class of a serialized object cannot be
+     *          found.
+     * @throws  InvalidClassException Something is wrong with a class used by
+     *          serialization.
+     * @throws  StreamCorruptedException Control information in the
+     *          stream is inconsistent.
+     * @throws  OptionalDataException Primitive data was found in the
+     *          stream instead of objects.
+     * @throws  IOException Any of the usual Input/Output related exceptions.
+     */
+    public final Object readObject()
+        throws IOException, ClassNotFoundException
+    {
+        if (enableOverride) {
+            return readObjectOverride();
+        }
+
+        // if nested read, passHandle contains handle of enclosing object
+        int outerHandle = passHandle;
+        try {
+            Object obj = readObject0(false);
+            handles.markDependency(outerHandle, passHandle);
+            ClassNotFoundException ex = handles.lookupException(passHandle);
+            if (ex != null) {
+                throw ex;
+            }
+            if (depth == 0) {
+                vlist.doCallbacks();
+            }
+            return obj;
+        } finally {
+            passHandle = outerHandle;
+            if (closed && depth == 0) {
+                clear();
+            }
+        }
+    }
+
+    /**
+     * This method is called by trusted subclasses of ObjectOutputStream that
+     * constructed ObjectOutputStream using the protected no-arg constructor.
+     * The subclass is expected to provide an override method with the modifier
+     * "final".
+     *
+     * @return  the Object read from the stream.
+     * @throws  ClassNotFoundException Class definition of a serialized object
+     *          cannot be found.
+     * @throws  OptionalDataException Primitive data was found in the stream
+     *          instead of objects.
+     * @throws  IOException if I/O errors occurred while reading from the
+     *          underlying stream
+     * @see #ObjectInputStream()
+     * @see #readObject()
+     * @since 1.2
+     */
+    protected Object readObjectOverride()
+        throws IOException, ClassNotFoundException
+    {
+        return null;
+    }
+
+    /**
+     * Reads an "unshared" object from the ObjectInputStream.  This method is
+     * identical to readObject, except that it prevents subsequent calls to
+     * readObject and readUnshared from returning additional references to the
+     * deserialized instance obtained via this call.  Specifically:
+     * <ul>
+     *   <li>If readUnshared is called to deserialize a back-reference (the
+     *       stream representation of an object which has been written
+     *       previously to the stream), an ObjectStreamException will be
+     *       thrown.
+     *
+     *   <li>If readUnshared returns successfully, then any subsequent attempts
+     *       to deserialize back-references to the stream handle deserialized
+     *       by readUnshared will cause an ObjectStreamException to be thrown.
+     * </ul>
+     * Deserializing an object via readUnshared invalidates the stream handle
+     * associated with the returned object.  Note that this in itself does not
+     * always guarantee that the reference returned by readUnshared is unique;
+     * the deserialized object may define a readResolve method which returns an
+     * object visible to other parties, or readUnshared may return a Class
+     * object or enum constant obtainable elsewhere in the stream or through
+     * external means. If the deserialized object defines a readResolve method
+     * and the invocation of that method returns an array, then readUnshared
+     * returns a shallow clone of that array; this guarantees that the returned
+     * array object is unique and cannot be obtained a second time from an
+     * invocation of readObject or readUnshared on the ObjectInputStream,
+     * even if the underlying data stream has been manipulated.
+     *
+     * <p>ObjectInputStream subclasses which override this method can only be
+     * constructed in security contexts possessing the
+     * "enableSubclassImplementation" SerializablePermission; any attempt to
+     * instantiate such a subclass without this permission will cause a
+     * SecurityException to be thrown.
+     *
+     * @return  reference to deserialized object
+     * @throws  ClassNotFoundException if class of an object to deserialize
+     *          cannot be found
+     * @throws  StreamCorruptedException if control information in the stream
+     *          is inconsistent
+     * @throws  ObjectStreamException if object to deserialize has already
+     *          appeared in stream
+     * @throws  OptionalDataException if primitive data is next in stream
+     * @throws  IOException if an I/O error occurs during deserialization
+     * @since   1.4
+     */
+    public Object readUnshared() throws IOException, ClassNotFoundException {
+        // if nested read, passHandle contains handle of enclosing object
+        int outerHandle = passHandle;
+        try {
+            Object obj = readObject0(true);
+            handles.markDependency(outerHandle, passHandle);
+            ClassNotFoundException ex = handles.lookupException(passHandle);
+            if (ex != null) {
+                throw ex;
+            }
+            if (depth == 0) {
+                vlist.doCallbacks();
+            }
+            return obj;
+        } finally {
+            passHandle = outerHandle;
+            if (closed && depth == 0) {
+                clear();
+            }
+        }
+    }
+
+    /**
+     * Read the non-static and non-transient fields of the current class from
+     * this stream.  This may only be called from the readObject method of the
+     * class being deserialized. It will throw the NotActiveException if it is
+     * called otherwise.
+     *
+     * @throws  ClassNotFoundException if the class of a serialized object
+     *          could not be found.
+     * @throws  IOException if an I/O error occurs.
+     * @throws  NotActiveException if the stream is not currently reading
+     *          objects.
+     */
+    public void defaultReadObject()
+        throws IOException, ClassNotFoundException
+    {
+        SerialCallbackContext ctx = curContext;
+        if (ctx == null) {
+            throw new NotActiveException("not in call to readObject");
+        }
+        Object curObj = ctx.getObj();
+        ObjectStreamClass curDesc = ctx.getDesc();
+        bin.setBlockDataMode(false);
+        defaultReadFields(curObj, curDesc);
+        bin.setBlockDataMode(true);
+        if (!curDesc.hasWriteObjectData()) {
+            /*
+             * Fix for 4360508: since stream does not contain terminating
+             * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
+             * knows to simulate end-of-custom-data behavior.
+             */
+            defaultDataEnd = true;
+        }
+        ClassNotFoundException ex = handles.lookupException(passHandle);
+        if (ex != null) {
+            throw ex;
+        }
+    }
+
+    /**
+     * Reads the persistent fields from the stream and makes them available by
+     * name.
+     *
+     * @return  the <code>GetField</code> object representing the persistent
+     *          fields of the object being deserialized
+     * @throws  ClassNotFoundException if the class of a serialized object
+     *          could not be found.
+     * @throws  IOException if an I/O error occurs.
+     * @throws  NotActiveException if the stream is not currently reading
+     *          objects.
+     * @since 1.2
+     */
+    public ObjectInputStream.GetField readFields()
+        throws IOException, ClassNotFoundException
+    {
+        SerialCallbackContext ctx = curContext;
+        if (ctx == null) {
+            throw new NotActiveException("not in call to readObject");
+        }
+        Object curObj = ctx.getObj();
+        ObjectStreamClass curDesc = ctx.getDesc();
+        bin.setBlockDataMode(false);
+        GetFieldImpl getField = new GetFieldImpl(curDesc);
+        getField.readFields();
+        bin.setBlockDataMode(true);
+        if (!curDesc.hasWriteObjectData()) {
+            /*
+             * Fix for 4360508: since stream does not contain terminating
+             * TC_ENDBLOCKDATA tag, set flag so that reading code elsewhere
+             * knows to simulate end-of-custom-data behavior.
+             */
+            defaultDataEnd = true;
+        }
+
+        return getField;
+    }
+
+    /**
+     * Register an object to be validated before the graph is returned.  While
+     * similar to resolveObject these validations are called after the entire
+     * graph has been reconstituted.  Typically, a readObject method will
+     * register the object with the stream so that when all of the objects are
+     * restored a final set of validations can be performed.
+     *
+     * @param   obj the object to receive the validation callback.
+     * @param   prio controls the order of callbacks;zero is a good default.
+     *          Use higher numbers to be called back earlier, lower numbers for
+     *          later callbacks. Within a priority, callbacks are processed in
+     *          no particular order.
+     * @throws  NotActiveException The stream is not currently reading objects
+     *          so it is invalid to register a callback.
+     * @throws  InvalidObjectException The validation object is null.
+     */
+    public void registerValidation(ObjectInputValidation obj, int prio)
+        throws NotActiveException, InvalidObjectException
+    {
+        if (depth == 0) {
+            throw new NotActiveException("stream inactive");
+        }
+        vlist.register(obj, prio);
+    }
+
+    /**
+     * Load the local class equivalent of the specified stream class
+     * description.  Subclasses may implement this method to allow classes to
+     * be fetched from an alternate source.
+     *
+     * <p>The corresponding method in <code>ObjectOutputStream</code> is
+     * <code>annotateClass</code>.  This method will be invoked only once for
+     * each unique class in the stream.  This method can be implemented by
+     * subclasses to use an alternate loading mechanism but must return a
+     * <code>Class</code> object. Once returned, if the class is not an array
+     * class, its serialVersionUID is compared to the serialVersionUID of the
+     * serialized class, and if there is a mismatch, the deserialization fails
+     * and an {@link InvalidClassException} is thrown.
+     *
+     * <p>The default implementation of this method in
+     * <code>ObjectInputStream</code> returns the result of calling
+     * <pre>
+     *     Class.forName(desc.getName(), false, loader)
+     * </pre>
+     * where <code>loader</code> is determined as follows: if there is a
+     * method on the current thread's stack whose declaring class was
+     * defined by a user-defined class loader (and was not a generated to
+     * implement reflective invocations), then <code>loader</code> is class
+     * loader corresponding to the closest such method to the currently
+     * executing frame; otherwise, <code>loader</code> is
+     * <code>null</code>. If this call results in a
+     * <code>ClassNotFoundException</code> and the name of the passed
+     * <code>ObjectStreamClass</code> instance is the Java language keyword
+     * for a primitive type or void, then the <code>Class</code> object
+     * representing that primitive type or void will be returned
+     * (e.g., an <code>ObjectStreamClass</code> with the name
+     * <code>"int"</code> will be resolved to <code>Integer.TYPE</code>).
+     * Otherwise, the <code>ClassNotFoundException</code> will be thrown to
+     * the caller of this method.
+     *
+     * @param   desc an instance of class <code>ObjectStreamClass</code>
+     * @return  a <code>Class</code> object corresponding to <code>desc</code>
+     * @throws  IOException any of the usual Input/Output exceptions.
+     * @throws  ClassNotFoundException if class of a serialized object cannot
+     *          be found.
+     */
+    protected Class<?> resolveClass(ObjectStreamClass desc)
+        throws IOException, ClassNotFoundException
+    {
+        String name = desc.getName();
+        try {
+            return Class.forName(name, false, latestUserDefinedLoader());
+        } catch (ClassNotFoundException ex) {
+            Class<?> cl = primClasses.get(name);
+            if (cl != null) {
+                return cl;
+            } else {
+                throw ex;
+            }
+        }
+    }
+
+    /**
+     * Returns a proxy class that implements the interfaces named in a proxy
+     * class descriptor; subclasses may implement this method to read custom
+     * data from the stream along with the descriptors for dynamic proxy
+     * classes, allowing them to use an alternate loading mechanism for the
+     * interfaces and the proxy class.
+     *
+     * <p>This method is called exactly once for each unique proxy class
+     * descriptor in the stream.
+     *
+     * <p>The corresponding method in <code>ObjectOutputStream</code> is
+     * <code>annotateProxyClass</code>.  For a given subclass of
+     * <code>ObjectInputStream</code> that overrides this method, the
+     * <code>annotateProxyClass</code> method in the corresponding subclass of
+     * <code>ObjectOutputStream</code> must write any data or objects read by
+     * this method.
+     *
+     * <p>The default implementation of this method in
+     * <code>ObjectInputStream</code> returns the result of calling
+     * <code>Proxy.getProxyClass</code> with the list of <code>Class</code>
+     * objects for the interfaces that are named in the <code>interfaces</code>
+     * parameter.  The <code>Class</code> object for each interface name
+     * <code>i</code> is the value returned by calling
+     * <pre>
+     *     Class.forName(i, false, loader)
+     * </pre>
+     * where <code>loader</code> is that of the first non-<code>null</code>
+     * class loader up the execution stack, or <code>null</code> if no
+     * non-<code>null</code> class loaders are on the stack (the same class
+     * loader choice used by the <code>resolveClass</code> method).  Unless any
+     * of the resolved interfaces are non-public, this same value of
+     * <code>loader</code> is also the class loader passed to
+     * <code>Proxy.getProxyClass</code>; if non-public interfaces are present,
+     * their class loader is passed instead (if more than one non-public
+     * interface class loader is encountered, an
+     * <code>IllegalAccessError</code> is thrown).
+     * If <code>Proxy.getProxyClass</code> throws an
+     * <code>IllegalArgumentException</code>, <code>resolveProxyClass</code>
+     * will throw a <code>ClassNotFoundException</code> containing the
+     * <code>IllegalArgumentException</code>.
+     *
+     * @param interfaces the list of interface names that were
+     *                deserialized in the proxy class descriptor
+     * @return  a proxy class for the specified interfaces
+     * @throws        IOException any exception thrown by the underlying
+     *                <code>InputStream</code>
+     * @throws        ClassNotFoundException if the proxy class or any of the
+     *                named interfaces could not be found
+     * @see ObjectOutputStream#annotateProxyClass(Class)
+     * @since 1.3
+     */
+    protected Class<?> resolveProxyClass(String[] interfaces)
+        throws IOException, ClassNotFoundException
+    {
+        ClassLoader latestLoader = latestUserDefinedLoader();
+        ClassLoader nonPublicLoader = null;
+        boolean hasNonPublicInterface = false;
+
+        // define proxy in class loader of non-public interface(s), if any
+        Class<?>[] classObjs = new Class<?>[interfaces.length];
+        for (int i = 0; i < interfaces.length; i++) {
+            Class<?> cl = Class.forName(interfaces[i], false, latestLoader);
+            if ((cl.getModifiers() & Modifier.PUBLIC) == 0) {
+                if (hasNonPublicInterface) {
+                    if (nonPublicLoader != cl.getClassLoader()) {
+                        throw new IllegalAccessError(
+                            "conflicting non-public interface class loaders");
+                    }
+                } else {
+                    nonPublicLoader = cl.getClassLoader();
+                    hasNonPublicInterface = true;
+                }
+            }
+            classObjs[i] = cl;
+        }
+        try {
+            return Proxy.getProxyClass(
+                hasNonPublicInterface ? nonPublicLoader : latestLoader,
+                classObjs);
+        } catch (IllegalArgumentException e) {
+            throw new ClassNotFoundException(null, e);
+        }
+    }
+
+    /**
+     * This method will allow trusted subclasses of ObjectInputStream to
+     * substitute one object for another during deserialization. Replacing
+     * objects is disabled until enableResolveObject is called. The
+     * enableResolveObject method checks that the stream requesting to resolve
+     * object can be trusted. Every reference to serializable objects is passed
+     * to resolveObject.  To insure that the private state of objects is not
+     * unintentionally exposed only trusted streams may use resolveObject.
+     *
+     * <p>This method is called after an object has been read but before it is
+     * returned from readObject.  The default resolveObject method just returns
+     * the same object.
+     *
+     * <p>When a subclass is replacing objects it must insure that the
+     * substituted object is compatible with every field where the reference
+     * will be stored.  Objects whose type is not a subclass of the type of the
+     * field or array element abort the serialization by raising an exception
+     * and the object is not be stored.
+     *
+     * <p>This method is called only once when each object is first
+     * encountered.  All subsequent references to the object will be redirected
+     * to the new object.
+     *
+     * @param   obj object to be substituted
+     * @return  the substituted object
+     * @throws  IOException Any of the usual Input/Output exceptions.
+     */
+    protected Object resolveObject(Object obj) throws IOException {
+        return obj;
+    }
+
+    /**
+     * Enable the stream to allow objects read from the stream to be replaced.
+     * When enabled, the resolveObject method is called for every object being
+     * deserialized.
+     *
+     * <p>If <i>enable</i> is true, and there is a security manager installed,
+     * this method first calls the security manager's
+     * <code>checkPermission</code> method with the
+     * <code>SerializablePermission("enableSubstitution")</code> permission to
+     * ensure it's ok to enable the stream to allow objects read from the
+     * stream to be replaced.
+     *
+     * @param   enable true for enabling use of <code>resolveObject</code> for
+     *          every object being deserialized
+     * @return  the previous setting before this method was invoked
+     * @throws  SecurityException if a security manager exists and its
+     *          <code>checkPermission</code> method denies enabling the stream
+     *          to allow objects read from the stream to be replaced.
+     * @see SecurityManager#checkPermission
+     * @see java.io.SerializablePermission
+     */
+    protected boolean enableResolveObject(boolean enable)
+        throws SecurityException
+    {
+        if (enable == enableResolve) {
+            return enable;
+        }
+        if (enable) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(SUBSTITUTION_PERMISSION);
+            }
+        }
+        enableResolve = enable;
+        return !enableResolve;
+    }
+
+    /**
+     * The readStreamHeader method is provided to allow subclasses to read and
+     * verify their own stream headers. It reads and verifies the magic number
+     * and version number.
+     *
+     * @throws  IOException if there are I/O errors while reading from the
+     *          underlying <code>InputStream</code>
+     * @throws  StreamCorruptedException if control information in the stream
+     *          is inconsistent
+     */
+    protected void readStreamHeader()
+        throws IOException, StreamCorruptedException
+    {
+        short s0 = bin.readShort();
+        short s1 = bin.readShort();
+        if (s0 != STREAM_MAGIC || s1 != STREAM_VERSION) {
+            throw new StreamCorruptedException(
+                String.format("invalid stream header: %04X%04X", s0, s1));
+        }
+    }
+
+    /**
+     * Read a class descriptor from the serialization stream.  This method is
+     * called when the ObjectInputStream expects a class descriptor as the next
+     * item in the serialization stream.  Subclasses of ObjectInputStream may
+     * override this method to read in class descriptors that have been written
+     * in non-standard formats (by subclasses of ObjectOutputStream which have
+     * overridden the <code>writeClassDescriptor</code> method).  By default,
+     * this method reads class descriptors according to the format defined in
+     * the Object Serialization specification.
+     *
+     * @return  the class descriptor read
+     * @throws  IOException If an I/O error has occurred.
+     * @throws  ClassNotFoundException If the Class of a serialized object used
+     *          in the class descriptor representation cannot be found
+     * @see java.io.ObjectOutputStream#writeClassDescriptor(java.io.ObjectStreamClass)
+     * @since 1.3
+     */
+    protected ObjectStreamClass readClassDescriptor()
+        throws IOException, ClassNotFoundException
+    {
+        ObjectStreamClass desc = new ObjectStreamClass();
+        desc.readNonProxy(this);
+        return desc;
+    }
+
+    /**
+     * Reads a byte of data. This method will block if no input is available.
+     *
+     * @return  the byte read, or -1 if the end of the stream is reached.
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public int read() throws IOException {
+        return bin.read();
+    }
+
+    /**
+     * Reads into an array of bytes.  This method will block until some input
+     * is available. Consider using java.io.DataInputStream.readFully to read
+     * exactly 'length' bytes.
+     *
+     * @param   buf the buffer into which the data is read
+     * @param   off the start offset of the data
+     * @param   len the maximum number of bytes read
+     * @return  the actual number of bytes read, -1 is returned when the end of
+     *          the stream is reached.
+     * @throws  IOException If an I/O error has occurred.
+     * @see java.io.DataInputStream#readFully(byte[],int,int)
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        if (buf == null) {
+            throw new NullPointerException();
+        }
+        int endoff = off + len;
+        if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        return bin.read(buf, off, len, false);
+    }
+
+    /**
+     * Returns the number of bytes that can be read without blocking.
+     *
+     * @return  the number of available bytes.
+     * @throws  IOException if there are I/O errors while reading from the
+     *          underlying <code>InputStream</code>
+     */
+    public int available() throws IOException {
+        return bin.available();
+    }
+
+    /**
+     * Closes the input stream. Must be called to release any resources
+     * associated with the stream.
+     *
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public void close() throws IOException {
+        /*
+         * Even if stream already closed, propagate redundant close to
+         * underlying stream to stay consistent with previous implementations.
+         */
+        closed = true;
+        if (depth == 0) {
+            clear();
+        }
+        bin.close();
+    }
+
+    /**
+     * Reads in a boolean.
+     *
+     * @return  the boolean read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public boolean readBoolean() throws IOException {
+        return bin.readBoolean();
+    }
+
+    /**
+     * Reads an 8 bit byte.
+     *
+     * @return  the 8 bit byte read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public byte readByte() throws IOException  {
+        return bin.readByte();
+    }
+
+    /**
+     * Reads an unsigned 8 bit byte.
+     *
+     * @return  the 8 bit byte read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public int readUnsignedByte()  throws IOException {
+        return bin.readUnsignedByte();
+    }
+
+    /**
+     * Reads a 16 bit char.
+     *
+     * @return  the 16 bit char read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public char readChar()  throws IOException {
+        return bin.readChar();
+    }
+
+    /**
+     * Reads a 16 bit short.
+     *
+     * @return  the 16 bit short read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public short readShort()  throws IOException {
+        return bin.readShort();
+    }
+
+    /**
+     * Reads an unsigned 16 bit short.
+     *
+     * @return  the 16 bit short read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public int readUnsignedShort() throws IOException {
+        return bin.readUnsignedShort();
+    }
+
+    /**
+     * Reads a 32 bit int.
+     *
+     * @return  the 32 bit integer read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public int readInt()  throws IOException {
+        return bin.readInt();
+    }
+
+    /**
+     * Reads a 64 bit long.
+     *
+     * @return  the read 64 bit long.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public long readLong()  throws IOException {
+        return bin.readLong();
+    }
+
+    /**
+     * Reads a 32 bit float.
+     *
+     * @return  the 32 bit float read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public float readFloat() throws IOException {
+        return bin.readFloat();
+    }
+
+    /**
+     * Reads a 64 bit double.
+     *
+     * @return  the 64 bit double read.
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public double readDouble() throws IOException {
+        return bin.readDouble();
+    }
+
+    /**
+     * Reads bytes, blocking until all bytes are read.
+     *
+     * @param   buf the buffer into which the data is read
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public void readFully(byte[] buf) throws IOException {
+        bin.readFully(buf, 0, buf.length, false);
+    }
+
+    /**
+     * Reads bytes, blocking until all bytes are read.
+     *
+     * @param   buf the buffer into which the data is read
+     * @param   off the start offset of the data
+     * @param   len the maximum number of bytes to read
+     * @throws  EOFException If end of file is reached.
+     * @throws  IOException If other I/O error has occurred.
+     */
+    public void readFully(byte[] buf, int off, int len) throws IOException {
+        int endoff = off + len;
+        if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        bin.readFully(buf, off, len, false);
+    }
+
+    /**
+     * Skips bytes.
+     *
+     * @param   len the number of bytes to be skipped
+     * @return  the actual number of bytes skipped.
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public int skipBytes(int len) throws IOException {
+        return bin.skipBytes(len);
+    }
+
+    /**
+     * Reads in a line that has been terminated by a \n, \r, \r\n or EOF.
+     *
+     * @return  a String copy of the line.
+     * @throws  IOException if there are I/O errors while reading from the
+     *          underlying <code>InputStream</code>
+     * @deprecated This method does not properly convert bytes to characters.
+     *          see DataInputStream for the details and alternatives.
+     */
+    @Deprecated
+    public String readLine() throws IOException {
+        return bin.readLine();
+    }
+
+    /**
+     * Reads a String in
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * format.
+     *
+     * @return  the String.
+     * @throws  IOException if there are I/O errors while reading from the
+     *          underlying <code>InputStream</code>
+     * @throws  UTFDataFormatException if read bytes do not represent a valid
+     *          modified UTF-8 encoding of a string
+     */
+    public String readUTF() throws IOException {
+        return bin.readUTF();
+    }
+
+    // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+    // Removed ObjectInputFilter related methods.
+
+    /**
+     * Provide access to the persistent fields read from the input stream.
+     */
+    public static abstract class GetField {
+
+        /**
+         * Get the ObjectStreamClass that describes the fields in the stream.
+         *
+         * @return  the descriptor class that describes the serializable fields
+         */
+        public abstract ObjectStreamClass getObjectStreamClass();
+
+        /**
+         * Return true if the named field is defaulted and has no value in this
+         * stream.
+         *
+         * @param  name the name of the field
+         * @return true, if and only if the named field is defaulted
+         * @throws IOException if there are I/O errors while reading from
+         *         the underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if <code>name</code> does not
+         *         correspond to a serializable field
+         */
+        public abstract boolean defaulted(String name) throws IOException;
+
+        /**
+         * Get the value of the named boolean field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>boolean</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract boolean get(String name, boolean val)
+            throws IOException;
+
+        /**
+         * Get the value of the named byte field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>byte</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract byte get(String name, byte val) throws IOException;
+
+        /**
+         * Get the value of the named char field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>char</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract char get(String name, char val) throws IOException;
+
+        /**
+         * Get the value of the named short field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>short</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract short get(String name, short val) throws IOException;
+
+        /**
+         * Get the value of the named int field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>int</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract int get(String name, int val) throws IOException;
+
+        /**
+         * Get the value of the named long field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>long</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract long get(String name, long val) throws IOException;
+
+        /**
+         * Get the value of the named float field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>float</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract float get(String name, float val) throws IOException;
+
+        /**
+         * Get the value of the named double field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>double</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract double get(String name, double val) throws IOException;
+
+        /**
+         * Get the value of the named Object field from the persistent field.
+         *
+         * @param  name the name of the field
+         * @param  val the default value to use if <code>name</code> does not
+         *         have a value
+         * @return the value of the named <code>Object</code> field
+         * @throws IOException if there are I/O errors while reading from the
+         *         underlying <code>InputStream</code>
+         * @throws IllegalArgumentException if type of <code>name</code> is
+         *         not serializable or if the field type is incorrect
+         */
+        public abstract Object get(String name, Object val) throws IOException;
+    }
+
+    /**
+     * Verifies that this (possibly subclass) instance can be constructed
+     * without violating security constraints: the subclass must not override
+     * security-sensitive non-final methods, or else the
+     * "enableSubclassImplementation" SerializablePermission is checked.
+     */
+    private void verifySubclass() {
+        Class<?> cl = getClass();
+        if (cl == ObjectInputStream.class) {
+            return;
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return;
+        }
+        processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
+        WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
+        Boolean result = Caches.subclassAudits.get(key);
+        if (result == null) {
+            result = Boolean.valueOf(auditSubclass(cl));
+            Caches.subclassAudits.putIfAbsent(key, result);
+        }
+        if (result.booleanValue()) {
+            return;
+        }
+        sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+    }
+
+    /**
+     * Performs reflective checks on given subclass to verify that it doesn't
+     * override security-sensitive non-final methods.  Returns true if subclass
+     * is "safe", false otherwise.
+     */
+    private static boolean auditSubclass(final Class<?> subcl) {
+        Boolean result = AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    for (Class<?> cl = subcl;
+                         cl != ObjectInputStream.class;
+                         cl = cl.getSuperclass())
+                    {
+                        try {
+                            cl.getDeclaredMethod(
+                                "readUnshared", (Class[]) null);
+                            return Boolean.FALSE;
+                        } catch (NoSuchMethodException ex) {
+                        }
+                        try {
+                            cl.getDeclaredMethod("readFields", (Class[]) null);
+                            return Boolean.FALSE;
+                        } catch (NoSuchMethodException ex) {
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            }
+        );
+        return result.booleanValue();
+    }
+
+    /**
+     * Clears internal data structures.
+     */
+    private void clear() {
+        handles.clear();
+        vlist.clear();
+    }
+
+    /**
+     * Underlying readObject implementation.
+     */
+    private Object readObject0(boolean unshared) throws IOException {
+        boolean oldMode = bin.getBlockDataMode();
+        if (oldMode) {
+            int remain = bin.currentBlockRemaining();
+            if (remain > 0) {
+                throw new OptionalDataException(remain);
+            } else if (defaultDataEnd) {
+                /*
+                 * Fix for 4360508: stream is currently at the end of a field
+                 * value block written via default serialization; since there
+                 * is no terminating TC_ENDBLOCKDATA tag, simulate
+                 * end-of-custom-data behavior explicitly.
+                 */
+                throw new OptionalDataException(true);
+            }
+            bin.setBlockDataMode(false);
+        }
+
+        byte tc;
+        while ((tc = bin.peekByte()) == TC_RESET) {
+            bin.readByte();
+            handleReset();
+        }
+
+        depth++;
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // totalObjectRefs++;
+        try {
+            switch (tc) {
+                case TC_NULL:
+                    return readNull();
+
+                case TC_REFERENCE:
+                    return readHandle(unshared);
+
+                case TC_CLASS:
+                    return readClass(unshared);
+
+                case TC_CLASSDESC:
+                case TC_PROXYCLASSDESC:
+                    return readClassDesc(unshared);
+
+                case TC_STRING:
+                case TC_LONGSTRING:
+                    return checkResolve(readString(unshared));
+
+                case TC_ARRAY:
+                    return checkResolve(readArray(unshared));
+
+                case TC_ENUM:
+                    return checkResolve(readEnum(unshared));
+
+                case TC_OBJECT:
+                    return checkResolve(readOrdinaryObject(unshared));
+
+                case TC_EXCEPTION:
+                    IOException ex = readFatalException();
+                    throw new WriteAbortedException("writing aborted", ex);
+
+                case TC_BLOCKDATA:
+                case TC_BLOCKDATALONG:
+                    if (oldMode) {
+                        bin.setBlockDataMode(true);
+                        bin.peek();             // force header read
+                        throw new OptionalDataException(
+                            bin.currentBlockRemaining());
+                    } else {
+                        throw new StreamCorruptedException(
+                            "unexpected block data");
+                    }
+
+                case TC_ENDBLOCKDATA:
+                    if (oldMode) {
+                        throw new OptionalDataException(true);
+                    } else {
+                        throw new StreamCorruptedException(
+                            "unexpected end of block data");
+                    }
+
+                default:
+                    throw new StreamCorruptedException(
+                        String.format("invalid type code: %02X", tc));
+            }
+        } finally {
+            depth--;
+            bin.setBlockDataMode(oldMode);
+        }
+    }
+
+    /**
+     * If resolveObject has been enabled and given object does not have an
+     * exception associated with it, calls resolveObject to determine
+     * replacement for object, and updates handle table accordingly.  Returns
+     * replacement object, or echoes provided object if no replacement
+     * occurred.  Expects that passHandle is set to given object's handle prior
+     * to calling this method.
+     */
+    private Object checkResolve(Object obj) throws IOException {
+        if (!enableResolve || handles.lookupException(passHandle) != null) {
+            return obj;
+        }
+        Object rep = resolveObject(obj);
+        if (rep != obj) {
+            // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+            /*
+            // The type of the original object has been filtered but resolveObject
+            // may have replaced it;  filter the replacement's type
+            if (rep != null) {
+                if (rep.getClass().isArray()) {
+                    filterCheck(rep.getClass(), Array.getLength(rep));
+                } else {
+                    filterCheck(rep.getClass(), -1);
+                }
+            }
+            */
+            handles.setObject(passHandle, rep);
+        }
+        return rep;
+    }
+
+    /**
+     * Reads string without allowing it to be replaced in stream.  Called from
+     * within ObjectStreamClass.read().
+     */
+    String readTypeString() throws IOException {
+        int oldHandle = passHandle;
+        try {
+            byte tc = bin.peekByte();
+            switch (tc) {
+                case TC_NULL:
+                    return (String) readNull();
+
+                case TC_REFERENCE:
+                    return (String) readHandle(false);
+
+                case TC_STRING:
+                case TC_LONGSTRING:
+                    return readString(false);
+
+                default:
+                    throw new StreamCorruptedException(
+                        String.format("invalid type code: %02X", tc));
+            }
+        } finally {
+            passHandle = oldHandle;
+        }
+    }
+
+    /**
+     * Reads in null code, sets passHandle to NULL_HANDLE and returns null.
+     */
+    private Object readNull() throws IOException {
+        if (bin.readByte() != TC_NULL) {
+            throw new InternalError();
+        }
+        passHandle = NULL_HANDLE;
+        return null;
+    }
+
+    /**
+     * Reads in object handle, sets passHandle to the read handle, and returns
+     * object associated with the handle.
+     */
+    private Object readHandle(boolean unshared) throws IOException {
+        if (bin.readByte() != TC_REFERENCE) {
+            throw new InternalError();
+        }
+        passHandle = bin.readInt() - baseWireHandle;
+        if (passHandle < 0 || passHandle >= handles.size()) {
+            throw new StreamCorruptedException(
+                String.format("invalid handle value: %08X", passHandle +
+                baseWireHandle));
+        }
+        if (unshared) {
+            // REMIND: what type of exception to throw here?
+            throw new InvalidObjectException(
+                "cannot read back reference as unshared");
+        }
+
+        Object obj = handles.lookupObject(passHandle);
+        if (obj == unsharedMarker) {
+            // REMIND: what type of exception to throw here?
+            throw new InvalidObjectException(
+                "cannot read back reference to unshared object");
+        }
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // filterCheck(null, -1);       // just a check for number of references, depth, no class
+        return obj;
+    }
+
+    /**
+     * Reads in and returns class object.  Sets passHandle to class object's
+     * assigned handle.  Returns null if class is unresolvable (in which case a
+     * ClassNotFoundException will be associated with the class' handle in the
+     * handle table).
+     */
+    private Class<?> readClass(boolean unshared) throws IOException {
+        if (bin.readByte() != TC_CLASS) {
+            throw new InternalError();
+        }
+        ObjectStreamClass desc = readClassDesc(false);
+        Class<?> cl = desc.forClass();
+        passHandle = handles.assign(unshared ? unsharedMarker : cl);
+
+        ClassNotFoundException resolveEx = desc.getResolveException();
+        if (resolveEx != null) {
+            handles.markException(passHandle, resolveEx);
+        }
+
+        handles.finish(passHandle);
+        return cl;
+    }
+
+    /**
+     * Reads in and returns (possibly null) class descriptor.  Sets passHandle
+     * to class descriptor's assigned handle.  If class descriptor cannot be
+     * resolved to a class in the local VM, a ClassNotFoundException is
+     * associated with the class descriptor's handle.
+     */
+    private ObjectStreamClass readClassDesc(boolean unshared)
+        throws IOException
+    {
+        byte tc = bin.peekByte();
+        ObjectStreamClass descriptor;
+        switch (tc) {
+            case TC_NULL:
+                descriptor = (ObjectStreamClass) readNull();
+                break;
+            case TC_REFERENCE:
+                descriptor = (ObjectStreamClass) readHandle(unshared);
+                break;
+            case TC_PROXYCLASSDESC:
+                descriptor = readProxyDesc(unshared);
+                break;
+            case TC_CLASSDESC:
+                descriptor = readNonProxyDesc(unshared);
+                break;
+            default:
+                throw new StreamCorruptedException(
+                    String.format("invalid type code: %02X", tc));
+        }
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // if (descriptor != null) {
+        //     validateDescriptor(descriptor);
+        // }
+        return descriptor;
+    }
+
+    private boolean isCustomSubclass() {
+        // Return true if this class is a custom subclass of ObjectInputStream
+        return getClass().getClassLoader()
+                    != ObjectInputStream.class.getClassLoader();
+    }
+
+    /**
+     * Reads in and returns class descriptor for a dynamic proxy class.  Sets
+     * passHandle to proxy class descriptor's assigned handle.  If proxy class
+     * descriptor cannot be resolved to a class in the local VM, a
+     * ClassNotFoundException is associated with the descriptor's handle.
+     */
+    private ObjectStreamClass readProxyDesc(boolean unshared)
+        throws IOException
+    {
+        if (bin.readByte() != TC_PROXYCLASSDESC) {
+            throw new InternalError();
+        }
+
+        ObjectStreamClass desc = new ObjectStreamClass();
+        int descHandle = handles.assign(unshared ? unsharedMarker : desc);
+        passHandle = NULL_HANDLE;
+
+        int numIfaces = bin.readInt();
+        String[] ifaces = new String[numIfaces];
+        for (int i = 0; i < numIfaces; i++) {
+            ifaces[i] = bin.readUTF();
+        }
+
+        Class<?> cl = null;
+        ClassNotFoundException resolveEx = null;
+        bin.setBlockDataMode(true);
+        try {
+            if ((cl = resolveProxyClass(ifaces)) == null) {
+                resolveEx = new ClassNotFoundException("null class");
+            } else if (!Proxy.isProxyClass(cl)) {
+                throw new InvalidClassException("Not a proxy");
+            } else {
+                // ReflectUtil.checkProxyPackageAccess makes a test
+                // equivalent to isCustomSubclass so there's no need
+                // to condition this call to isCustomSubclass == true here.
+                ReflectUtil.checkProxyPackageAccess(
+                        getClass().getClassLoader(),
+                        cl.getInterfaces());
+                // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+                // // Filter the interfaces
+                // for (Class<?> clazz : cl.getInterfaces()) {
+                //     filterCheck(clazz, -1);
+                // }
+            }
+        } catch (ClassNotFoundException ex) {
+            resolveEx = ex;
+        }
+        skipCustomData();
+
+        desc.initProxy(cl, resolveEx, readClassDesc(false));
+
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // // Call filterCheck on the definition
+        // filterCheck(desc.forClass(), -1);
+
+        handles.finish(descHandle);
+        passHandle = descHandle;
+        return desc;
+    }
+
+    /**
+     * Reads in and returns class descriptor for a class that is not a dynamic
+     * proxy class.  Sets passHandle to class descriptor's assigned handle.  If
+     * class descriptor cannot be resolved to a class in the local VM, a
+     * ClassNotFoundException is associated with the descriptor's handle.
+     */
+    private ObjectStreamClass readNonProxyDesc(boolean unshared)
+        throws IOException
+    {
+        if (bin.readByte() != TC_CLASSDESC) {
+            throw new InternalError();
+        }
+
+        ObjectStreamClass desc = new ObjectStreamClass();
+        int descHandle = handles.assign(unshared ? unsharedMarker : desc);
+        passHandle = NULL_HANDLE;
+
+        ObjectStreamClass readDesc = null;
+        try {
+            readDesc = readClassDescriptor();
+        } catch (ClassNotFoundException ex) {
+            throw (IOException) new InvalidClassException(
+                "failed to read class descriptor").initCause(ex);
+        }
+
+        Class<?> cl = null;
+        ClassNotFoundException resolveEx = null;
+        bin.setBlockDataMode(true);
+        final boolean checksRequired = isCustomSubclass();
+        try {
+            if ((cl = resolveClass(readDesc)) == null) {
+                resolveEx = new ClassNotFoundException("null class");
+            } else if (checksRequired) {
+                ReflectUtil.checkPackageAccess(cl);
+            }
+        } catch (ClassNotFoundException ex) {
+            resolveEx = ex;
+        }
+        skipCustomData();
+
+        desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
+
+        // Android-removed: ObjectInputFilter unsupported - removed filterCheck() call.
+        // // Call filterCheck on the definition
+        // filterCheck(desc.forClass(), -1);
+
+        handles.finish(descHandle);
+        passHandle = descHandle;
+
+        return desc;
+    }
+
+    /**
+     * Reads in and returns new string.  Sets passHandle to new string's
+     * assigned handle.
+     */
+    private String readString(boolean unshared) throws IOException {
+        String str;
+        byte tc = bin.readByte();
+        switch (tc) {
+            case TC_STRING:
+                str = bin.readUTF();
+                break;
+
+            case TC_LONGSTRING:
+                str = bin.readLongUTF();
+                break;
+
+            default:
+                throw new StreamCorruptedException(
+                    String.format("invalid type code: %02X", tc));
+        }
+        passHandle = handles.assign(unshared ? unsharedMarker : str);
+        handles.finish(passHandle);
+        return str;
+    }
+
+    /**
+     * Reads in and returns array object, or null if array class is
+     * unresolvable.  Sets passHandle to array's assigned handle.
+     */
+    private Object readArray(boolean unshared) throws IOException {
+        if (bin.readByte() != TC_ARRAY) {
+            throw new InternalError();
+        }
+
+        ObjectStreamClass desc = readClassDesc(false);
+        int len = bin.readInt();
+
+        // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+        // filterCheck(desc.forClass(), len);
+
+        Object array = null;
+        Class<?> cl, ccl = null;
+        if ((cl = desc.forClass()) != null) {
+            ccl = cl.getComponentType();
+            array = Array.newInstance(ccl, len);
+        }
+
+        int arrayHandle = handles.assign(unshared ? unsharedMarker : array);
+        ClassNotFoundException resolveEx = desc.getResolveException();
+        if (resolveEx != null) {
+            handles.markException(arrayHandle, resolveEx);
+        }
+
+        if (ccl == null) {
+            for (int i = 0; i < len; i++) {
+                readObject0(false);
+            }
+        } else if (ccl.isPrimitive()) {
+            if (ccl == Integer.TYPE) {
+                bin.readInts((int[]) array, 0, len);
+            } else if (ccl == Byte.TYPE) {
+                bin.readFully((byte[]) array, 0, len, true);
+            } else if (ccl == Long.TYPE) {
+                bin.readLongs((long[]) array, 0, len);
+            } else if (ccl == Float.TYPE) {
+                bin.readFloats((float[]) array, 0, len);
+            } else if (ccl == Double.TYPE) {
+                bin.readDoubles((double[]) array, 0, len);
+            } else if (ccl == Short.TYPE) {
+                bin.readShorts((short[]) array, 0, len);
+            } else if (ccl == Character.TYPE) {
+                bin.readChars((char[]) array, 0, len);
+            } else if (ccl == Boolean.TYPE) {
+                bin.readBooleans((boolean[]) array, 0, len);
+            } else {
+                throw new InternalError();
+            }
+        } else {
+            Object[] oa = (Object[]) array;
+            for (int i = 0; i < len; i++) {
+                oa[i] = readObject0(false);
+                handles.markDependency(arrayHandle, passHandle);
+            }
+        }
+
+        handles.finish(arrayHandle);
+        passHandle = arrayHandle;
+        return array;
+    }
+
+    /**
+     * Reads in and returns enum constant, or null if enum type is
+     * unresolvable.  Sets passHandle to enum constant's assigned handle.
+     */
+    private Enum<?> readEnum(boolean unshared) throws IOException {
+        if (bin.readByte() != TC_ENUM) {
+            throw new InternalError();
+        }
+
+        ObjectStreamClass desc = readClassDesc(false);
+        if (!desc.isEnum()) {
+            throw new InvalidClassException("non-enum class: " + desc);
+        }
+
+        int enumHandle = handles.assign(unshared ? unsharedMarker : null);
+        ClassNotFoundException resolveEx = desc.getResolveException();
+        if (resolveEx != null) {
+            handles.markException(enumHandle, resolveEx);
+        }
+
+        String name = readString(false);
+        Enum<?> result = null;
+        Class<?> cl = desc.forClass();
+        if (cl != null) {
+            try {
+                @SuppressWarnings("unchecked")
+                Enum<?> en = Enum.valueOf((Class)cl, name);
+                result = en;
+            } catch (IllegalArgumentException ex) {
+                throw (IOException) new InvalidObjectException(
+                    "enum constant " + name + " does not exist in " +
+                    cl).initCause(ex);
+            }
+            if (!unshared) {
+                handles.setObject(enumHandle, result);
+            }
+        }
+
+        handles.finish(enumHandle);
+        passHandle = enumHandle;
+        return result;
+    }
+
+    /**
+     * Reads and returns "ordinary" (i.e., not a String, Class,
+     * ObjectStreamClass, array, or enum constant) object, or null if object's
+     * class is unresolvable (in which case a ClassNotFoundException will be
+     * associated with object's handle).  Sets passHandle to object's assigned
+     * handle.
+     */
+    private Object readOrdinaryObject(boolean unshared)
+        throws IOException
+    {
+        if (bin.readByte() != TC_OBJECT) {
+            throw new InternalError();
+        }
+
+        ObjectStreamClass desc = readClassDesc(false);
+        desc.checkDeserialize();
+
+        Class<?> cl = desc.forClass();
+        if (cl == String.class || cl == Class.class
+                || cl == ObjectStreamClass.class) {
+            throw new InvalidClassException("invalid class descriptor");
+        }
+
+        Object obj;
+        try {
+            obj = desc.isInstantiable() ? desc.newInstance() : null;
+        } catch (Exception ex) {
+            throw (IOException) new InvalidClassException(
+                desc.forClass().getName(),
+                "unable to create instance").initCause(ex);
+        }
+
+        passHandle = handles.assign(unshared ? unsharedMarker : obj);
+        ClassNotFoundException resolveEx = desc.getResolveException();
+        if (resolveEx != null) {
+            handles.markException(passHandle, resolveEx);
+        }
+
+        if (desc.isExternalizable()) {
+            readExternalData((Externalizable) obj, desc);
+        } else {
+            readSerialData(obj, desc);
+        }
+
+        handles.finish(passHandle);
+
+        if (obj != null &&
+            handles.lookupException(passHandle) == null &&
+            desc.hasReadResolveMethod())
+        {
+            Object rep = desc.invokeReadResolve(obj);
+            if (unshared && rep.getClass().isArray()) {
+                rep = cloneArray(rep);
+            }
+            if (rep != obj) {
+                // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+                /*
+                // Filter the replacement object
+                if (rep != null) {
+                    if (rep.getClass().isArray()) {
+                        filterCheck(rep.getClass(), Array.getLength(rep));
+                    } else {
+                        filterCheck(rep.getClass(), -1);
+                    }
+                }
+                */
+                handles.setObject(passHandle, obj = rep);
+            }
+        }
+
+        return obj;
+    }
+
+    /**
+     * If obj is non-null, reads externalizable data by invoking readExternal()
+     * method of obj; otherwise, attempts to skip over externalizable data.
+     * Expects that passHandle is set to obj's handle before this method is
+     * called.
+     */
+    private void readExternalData(Externalizable obj, ObjectStreamClass desc)
+        throws IOException
+    {
+        SerialCallbackContext oldContext = curContext;
+        if (oldContext != null)
+            oldContext.check();
+        curContext = null;
+        try {
+            boolean blocked = desc.hasBlockExternalData();
+            if (blocked) {
+                bin.setBlockDataMode(true);
+            }
+            if (obj != null) {
+                try {
+                    obj.readExternal(this);
+                } catch (ClassNotFoundException ex) {
+                    /*
+                     * In most cases, the handle table has already propagated
+                     * a CNFException to passHandle at this point; this mark
+                     * call is included to address cases where the readExternal
+                     * method has cons'ed and thrown a new CNFException of its
+                     * own.
+                     */
+                     handles.markException(passHandle, ex);
+                }
+            }
+            if (blocked) {
+                skipCustomData();
+            }
+        } finally {
+            if (oldContext != null)
+                oldContext.check();
+            curContext = oldContext;
+        }
+        /*
+         * At this point, if the externalizable data was not written in
+         * block-data form and either the externalizable class doesn't exist
+         * locally (i.e., obj == null) or readExternal() just threw a
+         * CNFException, then the stream is probably in an inconsistent state,
+         * since some (or all) of the externalizable data may not have been
+         * consumed.  Since there's no "correct" action to take in this case,
+         * we mimic the behavior of past serialization implementations and
+         * blindly hope that the stream is in sync; if it isn't and additional
+         * externalizable data remains in the stream, a subsequent read will
+         * most likely throw a StreamCorruptedException.
+         */
+    }
+
+    /**
+     * Reads (or attempts to skip, if obj is null or is tagged with a
+     * ClassNotFoundException) instance data for each serializable class of
+     * object in stream, from superclass to subclass.  Expects that passHandle
+     * is set to obj's handle before this method is called.
+     */
+    private void readSerialData(Object obj, ObjectStreamClass desc)
+        throws IOException
+    {
+        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+        for (int i = 0; i < slots.length; i++) {
+            ObjectStreamClass slotDesc = slots[i].desc;
+
+            if (slots[i].hasData) {
+                if (obj == null || handles.lookupException(passHandle) != null) {
+                    defaultReadFields(null, slotDesc); // skip field values
+                } else if (slotDesc.hasReadObjectMethod()) {
+                    // BEGIN Android-changed: ThreadDeath cannot cause corruption on Android.
+                    // Android does not support Thread.stop() or Thread.stop(Throwable) so this
+                    // does not need to protect against state corruption that can occur when a
+                    // ThreadDeath Error is thrown in the middle of the finally block.
+                    SerialCallbackContext oldContext = curContext;
+                    if (oldContext != null)
+                        oldContext.check();
+                    try {
+                        curContext = new SerialCallbackContext(obj, slotDesc);
+
+                        bin.setBlockDataMode(true);
+                        slotDesc.invokeReadObject(obj, this);
+                    } catch (ClassNotFoundException ex) {
+                        /*
+                         * In most cases, the handle table has already
+                         * propagated a CNFException to passHandle at this
+                         * point; this mark call is included to address cases
+                         * where the custom readObject method has cons'ed and
+                         * thrown a new CNFException of its own.
+                         */
+                        handles.markException(passHandle, ex);
+                    } finally {
+                        curContext.setUsed();
+                        if (oldContext!= null)
+                            oldContext.check();
+                        curContext = oldContext;
+                        // END Android-changed: ThreadDeath cannot cause corruption on Android.
+                    }
+
+                    /*
+                     * defaultDataEnd may have been set indirectly by custom
+                     * readObject() method when calling defaultReadObject() or
+                     * readFields(); clear it to restore normal read behavior.
+                     */
+                    defaultDataEnd = false;
+                } else {
+                    defaultReadFields(obj, slotDesc);
+                    }
+
+                if (slotDesc.hasWriteObjectData()) {
+                    skipCustomData();
+                } else {
+                    bin.setBlockDataMode(false);
+                }
+            } else {
+                if (obj != null &&
+                    slotDesc.hasReadObjectNoDataMethod() &&
+                    handles.lookupException(passHandle) == null)
+                {
+                    slotDesc.invokeReadObjectNoData(obj);
+                }
+            }
+        }
+            }
+
+    /**
+     * Skips over all block data and objects until TC_ENDBLOCKDATA is
+     * encountered.
+     */
+    private void skipCustomData() throws IOException {
+        int oldHandle = passHandle;
+        for (;;) {
+            if (bin.getBlockDataMode()) {
+                bin.skipBlockData();
+                bin.setBlockDataMode(false);
+            }
+            switch (bin.peekByte()) {
+                case TC_BLOCKDATA:
+                case TC_BLOCKDATALONG:
+                    bin.setBlockDataMode(true);
+                    break;
+
+                case TC_ENDBLOCKDATA:
+                    bin.readByte();
+                    passHandle = oldHandle;
+                    return;
+
+                default:
+                    readObject0(false);
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Reads in values of serializable fields declared by given class
+     * descriptor.  If obj is non-null, sets field values in obj.  Expects that
+     * passHandle is set to obj's handle before this method is called.
+     */
+    private void defaultReadFields(Object obj, ObjectStreamClass desc)
+        throws IOException
+    {
+        Class<?> cl = desc.forClass();
+        if (cl != null && obj != null && !cl.isInstance(obj)) {
+            throw new ClassCastException();
+        }
+
+        int primDataSize = desc.getPrimDataSize();
+        if (primVals == null || primVals.length < primDataSize) {
+            primVals = new byte[primDataSize];
+        }
+            bin.readFully(primVals, 0, primDataSize, false);
+        if (obj != null) {
+            desc.setPrimFieldValues(obj, primVals);
+        }
+
+        int objHandle = passHandle;
+        ObjectStreamField[] fields = desc.getFields(false);
+        Object[] objVals = new Object[desc.getNumObjFields()];
+        int numPrimFields = fields.length - objVals.length;
+        for (int i = 0; i < objVals.length; i++) {
+            ObjectStreamField f = fields[numPrimFields + i];
+            objVals[i] = readObject0(f.isUnshared());
+            if (f.getField() != null) {
+                handles.markDependency(objHandle, passHandle);
+            }
+        }
+        if (obj != null) {
+            desc.setObjFieldValues(obj, objVals);
+        }
+        passHandle = objHandle;
+    }
+
+    /**
+     * Reads in and returns IOException that caused serialization to abort.
+     * All stream state is discarded prior to reading in fatal exception.  Sets
+     * passHandle to fatal exception's handle.
+     */
+    private IOException readFatalException() throws IOException {
+        if (bin.readByte() != TC_EXCEPTION) {
+            throw new InternalError();
+        }
+        clear();
+        // BEGIN Android-changed: Fix SerializationStressTest#test_2_writeReplace.
+        IOException e = (IOException) readObject0(false);
+        // If we want to continue reading from same stream after fatal exception, we
+        // need to clear internal data structures.
+        clear();
+        return e;
+        // END Android-changed: Fix SerializationStressTest#test_2_writeReplace.
+    }
+
+    /**
+     * If recursion depth is 0, clears internal data structures; otherwise,
+     * throws a StreamCorruptedException.  This method is called when a
+     * TC_RESET typecode is encountered.
+     */
+    private void handleReset() throws StreamCorruptedException {
+        if (depth > 0) {
+            throw new StreamCorruptedException(
+                "unexpected reset; recursion depth: " + depth);
+        }
+        clear();
+    }
+
+    /**
+     * Converts specified span of bytes into float values.
+     */
+    // REMIND: remove once hotspot inlines Float.intBitsToFloat
+    private static native void bytesToFloats(byte[] src, int srcpos,
+                                             float[] dst, int dstpos,
+                                             int nfloats);
+
+    /**
+     * Converts specified span of bytes into double values.
+     */
+    // REMIND: remove once hotspot inlines Double.longBitsToDouble
+    private static native void bytesToDoubles(byte[] src, int srcpos,
+                                              double[] dst, int dstpos,
+                                              int ndoubles);
+
+    /**
+     * Returns the first non-null class loader (not counting class loaders of
+     * generated reflection implementation classes) up the execution stack, or
+     * null if only code from the null class loader is on the stack.  This
+     * method is also called via reflection by the following RMI-IIOP class:
+     *
+     *     com.sun.corba.se.internal.util.JDKClassLoader
+     *
+     * This method should not be removed or its signature changed without
+     * corresponding modifications to the above class.
+     */
+    private static ClassLoader latestUserDefinedLoader() {
+        // Android-changed: Use VMStack on Android.
+        return VMStack.getClosestUserClassLoader();
+    }
+
+    /**
+     * Default GetField implementation.
+     */
+    private class GetFieldImpl extends GetField {
+
+        /** class descriptor describing serializable fields */
+        private final ObjectStreamClass desc;
+        /** primitive field values */
+        private final byte[] primVals;
+        /** object field values */
+        private final Object[] objVals;
+        /** object field value handles */
+        private final int[] objHandles;
+
+        /**
+         * Creates GetFieldImpl object for reading fields defined in given
+         * class descriptor.
+         */
+        GetFieldImpl(ObjectStreamClass desc) {
+            this.desc = desc;
+            primVals = new byte[desc.getPrimDataSize()];
+            objVals = new Object[desc.getNumObjFields()];
+            objHandles = new int[objVals.length];
+        }
+
+        public ObjectStreamClass getObjectStreamClass() {
+            return desc;
+        }
+
+        public boolean defaulted(String name) throws IOException {
+            return (getFieldOffset(name, null) < 0);
+        }
+
+        public boolean get(String name, boolean val) throws IOException {
+            int off = getFieldOffset(name, Boolean.TYPE);
+            return (off >= 0) ? Bits.getBoolean(primVals, off) : val;
+        }
+
+        public byte get(String name, byte val) throws IOException {
+            int off = getFieldOffset(name, Byte.TYPE);
+            return (off >= 0) ? primVals[off] : val;
+        }
+
+        public char get(String name, char val) throws IOException {
+            int off = getFieldOffset(name, Character.TYPE);
+            return (off >= 0) ? Bits.getChar(primVals, off) : val;
+        }
+
+        public short get(String name, short val) throws IOException {
+            int off = getFieldOffset(name, Short.TYPE);
+            return (off >= 0) ? Bits.getShort(primVals, off) : val;
+        }
+
+        public int get(String name, int val) throws IOException {
+            int off = getFieldOffset(name, Integer.TYPE);
+            return (off >= 0) ? Bits.getInt(primVals, off) : val;
+        }
+
+        public float get(String name, float val) throws IOException {
+            int off = getFieldOffset(name, Float.TYPE);
+            return (off >= 0) ? Bits.getFloat(primVals, off) : val;
+        }
+
+        public long get(String name, long val) throws IOException {
+            int off = getFieldOffset(name, Long.TYPE);
+            return (off >= 0) ? Bits.getLong(primVals, off) : val;
+        }
+
+        public double get(String name, double val) throws IOException {
+            int off = getFieldOffset(name, Double.TYPE);
+            return (off >= 0) ? Bits.getDouble(primVals, off) : val;
+        }
+
+        public Object get(String name, Object val) throws IOException {
+            int off = getFieldOffset(name, Object.class);
+            if (off >= 0) {
+                int objHandle = objHandles[off];
+                handles.markDependency(passHandle, objHandle);
+                return (handles.lookupException(objHandle) == null) ?
+                    objVals[off] : null;
+            } else {
+                return val;
+            }
+        }
+
+        /**
+         * Reads primitive and object field values from stream.
+         */
+        void readFields() throws IOException {
+            bin.readFully(primVals, 0, primVals.length, false);
+
+            int oldHandle = passHandle;
+            ObjectStreamField[] fields = desc.getFields(false);
+            int numPrimFields = fields.length - objVals.length;
+            for (int i = 0; i < objVals.length; i++) {
+                objVals[i] =
+                    readObject0(fields[numPrimFields + i].isUnshared());
+                objHandles[i] = passHandle;
+            }
+            passHandle = oldHandle;
+        }
+
+        /**
+         * Returns offset of field with given name and type.  A specified type
+         * of null matches all types, Object.class matches all non-primitive
+         * types, and any other non-null type matches assignable types only.
+         * If no matching field is found in the (incoming) class
+         * descriptor but a matching field is present in the associated local
+         * class descriptor, returns -1.  Throws IllegalArgumentException if
+         * neither incoming nor local class descriptor contains a match.
+         */
+        private int getFieldOffset(String name, Class<?> type) {
+            ObjectStreamField field = desc.getField(name, type);
+            if (field != null) {
+                return field.getOffset();
+            } else if (desc.getLocalDesc().getField(name, type) != null) {
+                return -1;
+            } else {
+                throw new IllegalArgumentException("no such field " + name +
+                                                   " with type " + type);
+            }
+        }
+    }
+
+    /**
+     * Prioritized list of callbacks to be performed once object graph has been
+     * completely deserialized.
+     */
+    private static class ValidationList {
+
+        private static class Callback {
+            final ObjectInputValidation obj;
+            final int priority;
+            Callback next;
+            final AccessControlContext acc;
+
+            Callback(ObjectInputValidation obj, int priority, Callback next,
+                AccessControlContext acc)
+            {
+                this.obj = obj;
+                this.priority = priority;
+                this.next = next;
+                this.acc = acc;
+            }
+        }
+
+        /** linked list of callbacks */
+        private Callback list;
+
+        /**
+         * Creates new (empty) ValidationList.
+         */
+        ValidationList() {
+        }
+
+        /**
+         * Registers callback.  Throws InvalidObjectException if callback
+         * object is null.
+         */
+        void register(ObjectInputValidation obj, int priority)
+            throws InvalidObjectException
+        {
+            if (obj == null) {
+                throw new InvalidObjectException("null callback");
+            }
+
+            Callback prev = null, cur = list;
+            while (cur != null && priority < cur.priority) {
+                prev = cur;
+                cur = cur.next;
+            }
+            AccessControlContext acc = AccessController.getContext();
+            if (prev != null) {
+                prev.next = new Callback(obj, priority, cur, acc);
+            } else {
+                list = new Callback(obj, priority, list, acc);
+            }
+        }
+
+        /**
+         * Invokes all registered callbacks and clears the callback list.
+         * Callbacks with higher priorities are called first; those with equal
+         * priorities may be called in any order.  If any of the callbacks
+         * throws an InvalidObjectException, the callback process is terminated
+         * and the exception propagated upwards.
+         */
+        void doCallbacks() throws InvalidObjectException {
+            try {
+                while (list != null) {
+                    AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<Void>()
+                    {
+                        public Void run() throws InvalidObjectException {
+                            list.obj.validateObject();
+                            return null;
+                        }
+                    }, list.acc);
+                    list = list.next;
+                }
+            } catch (PrivilegedActionException ex) {
+                list = null;
+                throw (InvalidObjectException) ex.getException();
+            }
+        }
+
+        /**
+         * Resets the callback list to its initial (empty) state.
+         */
+        public void clear() {
+            list = null;
+        }
+    }
+
+    // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
+    // Removed FilterValues class.
+
+    /**
+     * Input stream supporting single-byte peek operations.
+     */
+    private static class PeekInputStream extends InputStream {
+
+        /** underlying stream */
+        private final InputStream in;
+        /** peeked byte */
+        private int peekb = -1;
+        /** total bytes read from the stream */
+        private long totalBytesRead = 0;
+
+        /**
+         * Creates new PeekInputStream on top of given underlying stream.
+         */
+        PeekInputStream(InputStream in) {
+            this.in = in;
+        }
+
+        /**
+         * Peeks at next byte value in stream.  Similar to read(), except
+         * that it does not consume the read value.
+         */
+        int peek() throws IOException {
+            if (peekb >= 0) {
+                return peekb;
+            }
+            peekb = in.read();
+            totalBytesRead += peekb >= 0 ? 1 : 0;
+            return peekb;
+        }
+
+        public int read() throws IOException {
+            if (peekb >= 0) {
+                int v = peekb;
+                peekb = -1;
+                return v;
+            } else {
+                int nbytes = in.read();
+                totalBytesRead += nbytes >= 0 ? 1 : 0;
+                return nbytes;
+            }
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            int nbytes;
+            if (len == 0) {
+                return 0;
+            } else if (peekb < 0) {
+                nbytes = in.read(b, off, len);
+                totalBytesRead += nbytes >= 0 ? nbytes : 0;
+                return nbytes;
+            } else {
+                b[off++] = (byte) peekb;
+                len--;
+                peekb = -1;
+                nbytes = in.read(b, off, len);
+                totalBytesRead += nbytes >= 0 ? nbytes : 0;
+                return (nbytes >= 0) ? (nbytes + 1) : 1;
+            }
+        }
+
+        void readFully(byte[] b, int off, int len) throws IOException {
+            int n = 0;
+            while (n < len) {
+                int count = read(b, off + n, len - n);
+                if (count < 0) {
+                    throw new EOFException();
+                }
+                n += count;
+            }
+        }
+
+        public long skip(long n) throws IOException {
+            if (n <= 0) {
+                return 0;
+            }
+            int skipped = 0;
+            if (peekb >= 0) {
+                peekb = -1;
+                skipped++;
+                n--;
+            }
+            n = skipped + in.skip(n);
+            totalBytesRead += n;
+            return n;
+        }
+
+        public int available() throws IOException {
+            return in.available() + ((peekb >= 0) ? 1 : 0);
+        }
+
+        public void close() throws IOException {
+            in.close();
+        }
+
+        public long getBytesRead() {
+            return totalBytesRead;
+        }
+    }
+
+    /**
+     * Input stream with two modes: in default mode, inputs data written in the
+     * same format as DataOutputStream; in "block data" mode, inputs data
+     * bracketed by block data markers (see object serialization specification
+     * for details).  Buffering depends on block data mode: when in default
+     * mode, no data is buffered in advance; when in block data mode, all data
+     * for the current data block is read in at once (and buffered).
+     */
+    private class BlockDataInputStream
+        extends InputStream implements DataInput
+    {
+        /** maximum data block length */
+        private static final int MAX_BLOCK_SIZE = 1024;
+        /** maximum data block header length */
+        private static final int MAX_HEADER_SIZE = 5;
+        /** (tunable) length of char buffer (for reading strings) */
+        private static final int CHAR_BUF_SIZE = 256;
+        /** readBlockHeader() return value indicating header read may block */
+        private static final int HEADER_BLOCKED = -2;
+
+        /** buffer for reading general/block data */
+        private final byte[] buf = new byte[MAX_BLOCK_SIZE];
+        /** buffer for reading block data headers */
+        private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
+        /** char buffer for fast string reads */
+        private final char[] cbuf = new char[CHAR_BUF_SIZE];
+
+        /** block data mode */
+        private boolean blkmode = false;
+
+        // block data state fields; values meaningful only when blkmode true
+        /** current offset into buf */
+        private int pos = 0;
+        /** end offset of valid data in buf, or -1 if no more block data */
+        private int end = -1;
+        /** number of bytes in current block yet to be read from stream */
+        private int unread = 0;
+
+        /** underlying stream (wrapped in peekable filter stream) */
+        private final PeekInputStream in;
+        /** loopback stream (for data reads that span data blocks) */
+        private final DataInputStream din;
+
+        /**
+         * Creates new BlockDataInputStream on top of given underlying stream.
+         * Block data mode is turned off by default.
+         */
+        BlockDataInputStream(InputStream in) {
+            this.in = new PeekInputStream(in);
+            din = new DataInputStream(this);
+        }
+
+        /**
+         * Sets block data mode to the given mode (true == on, false == off)
+         * and returns the previous mode value.  If the new mode is the same as
+         * the old mode, no action is taken.  Throws IllegalStateException if
+         * block data mode is being switched from on to off while unconsumed
+         * block data is still present in the stream.
+         */
+        boolean setBlockDataMode(boolean newmode) throws IOException {
+            if (blkmode == newmode) {
+                return blkmode;
+            }
+            if (newmode) {
+                pos = 0;
+                end = 0;
+                unread = 0;
+            } else if (pos < end) {
+                throw new IllegalStateException("unread block data");
+            }
+            blkmode = newmode;
+            return !blkmode;
+        }
+
+        /**
+         * Returns true if the stream is currently in block data mode, false
+         * otherwise.
+         */
+        boolean getBlockDataMode() {
+            return blkmode;
+        }
+
+        /**
+         * If in block data mode, skips to the end of the current group of data
+         * blocks (but does not unset block data mode).  If not in block data
+         * mode, throws an IllegalStateException.
+         */
+        void skipBlockData() throws IOException {
+            if (!blkmode) {
+                throw new IllegalStateException("not in block data mode");
+            }
+            while (end >= 0) {
+                refill();
+            }
+        }
+
+        /**
+         * Attempts to read in the next block data header (if any).  If
+         * canBlock is false and a full header cannot be read without possibly
+         * blocking, returns HEADER_BLOCKED, else if the next element in the
+         * stream is a block data header, returns the block data length
+         * specified by the header, else returns -1.
+         */
+        private int readBlockHeader(boolean canBlock) throws IOException {
+            if (defaultDataEnd) {
+                /*
+                 * Fix for 4360508: stream is currently at the end of a field
+                 * value block written via default serialization; since there
+                 * is no terminating TC_ENDBLOCKDATA tag, simulate
+                 * end-of-custom-data behavior explicitly.
+                 */
+                return -1;
+            }
+            try {
+                for (;;) {
+                    int avail = canBlock ? Integer.MAX_VALUE : in.available();
+                    if (avail == 0) {
+                        return HEADER_BLOCKED;
+                    }
+
+                    int tc = in.peek();
+                    switch (tc) {
+                        case TC_BLOCKDATA:
+                            if (avail < 2) {
+                                return HEADER_BLOCKED;
+                            }
+                            in.readFully(hbuf, 0, 2);
+                            return hbuf[1] & 0xFF;
+
+                        case TC_BLOCKDATALONG:
+                            if (avail < 5) {
+                                return HEADER_BLOCKED;
+                            }
+                            in.readFully(hbuf, 0, 5);
+                            int len = Bits.getInt(hbuf, 1);
+                            if (len < 0) {
+                                throw new StreamCorruptedException(
+                                    "illegal block data header length: " +
+                                    len);
+                            }
+                            return len;
+
+                        /*
+                         * TC_RESETs may occur in between data blocks.
+                         * Unfortunately, this case must be parsed at a lower
+                         * level than other typecodes, since primitive data
+                         * reads may span data blocks separated by a TC_RESET.
+                         */
+                        case TC_RESET:
+                            in.read();
+                            handleReset();
+                            break;
+
+                        default:
+                            if (tc >= 0 && (tc < TC_BASE || tc > TC_MAX)) {
+                                throw new StreamCorruptedException(
+                                    String.format("invalid type code: %02X",
+                                    tc));
+                            }
+                            return -1;
+                    }
+                }
+            } catch (EOFException ex) {
+                throw new StreamCorruptedException(
+                    "unexpected EOF while reading block data header");
+            }
+        }
+
+        /**
+         * Refills internal buffer buf with block data.  Any data in buf at the
+         * time of the call is considered consumed.  Sets the pos, end, and
+         * unread fields to reflect the new amount of available block data; if
+         * the next element in the stream is not a data block, sets pos and
+         * unread to 0 and end to -1.
+         */
+        private void refill() throws IOException {
+            try {
+                do {
+                    pos = 0;
+                    if (unread > 0) {
+                        int n =
+                            in.read(buf, 0, Math.min(unread, MAX_BLOCK_SIZE));
+                        if (n >= 0) {
+                            end = n;
+                            unread -= n;
+                        } else {
+                            throw new StreamCorruptedException(
+                                "unexpected EOF in middle of data block");
+                        }
+                    } else {
+                        int n = readBlockHeader(true);
+                        if (n >= 0) {
+                            end = 0;
+                            unread = n;
+                        } else {
+                            end = -1;
+                            unread = 0;
+                        }
+                    }
+                } while (pos == end);
+            } catch (IOException ex) {
+                pos = 0;
+                end = -1;
+                unread = 0;
+                throw ex;
+            }
+        }
+
+        /**
+         * If in block data mode, returns the number of unconsumed bytes
+         * remaining in the current data block.  If not in block data mode,
+         * throws an IllegalStateException.
+         */
+        int currentBlockRemaining() {
+            if (blkmode) {
+                return (end >= 0) ? (end - pos) + unread : 0;
+            } else {
+                throw new IllegalStateException();
+            }
+        }
+
+        /**
+         * Peeks at (but does not consume) and returns the next byte value in
+         * the stream, or -1 if the end of the stream/block data (if in block
+         * data mode) has been reached.
+         */
+        int peek() throws IOException {
+            if (blkmode) {
+                if (pos == end) {
+                    refill();
+                }
+                return (end >= 0) ? (buf[pos] & 0xFF) : -1;
+            } else {
+                return in.peek();
+            }
+        }
+
+        /**
+         * Peeks at (but does not consume) and returns the next byte value in
+         * the stream, or throws EOFException if end of stream/block data has
+         * been reached.
+         */
+        byte peekByte() throws IOException {
+            int val = peek();
+            if (val < 0) {
+                throw new EOFException();
+            }
+            return (byte) val;
+        }
+
+
+        /* ----------------- generic input stream methods ------------------ */
+        /*
+         * The following methods are equivalent to their counterparts in
+         * InputStream, except that they interpret data block boundaries and
+         * read the requested data from within data blocks when in block data
+         * mode.
+         */
+
+        public int read() throws IOException {
+            if (blkmode) {
+                if (pos == end) {
+                    refill();
+                }
+                return (end >= 0) ? (buf[pos++] & 0xFF) : -1;
+            } else {
+                return in.read();
+            }
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            return read(b, off, len, false);
+        }
+
+        public long skip(long len) throws IOException {
+            long remain = len;
+            while (remain > 0) {
+                if (blkmode) {
+                    if (pos == end) {
+                        refill();
+                    }
+                    if (end < 0) {
+                        break;
+                    }
+                    int nread = (int) Math.min(remain, end - pos);
+                    remain -= nread;
+                    pos += nread;
+                } else {
+                    int nread = (int) Math.min(remain, MAX_BLOCK_SIZE);
+                    if ((nread = in.read(buf, 0, nread)) < 0) {
+                        break;
+                    }
+                    remain -= nread;
+                }
+            }
+            return len - remain;
+        }
+
+        public int available() throws IOException {
+            if (blkmode) {
+                if ((pos == end) && (unread == 0)) {
+                    int n;
+                    while ((n = readBlockHeader(false)) == 0) ;
+                    switch (n) {
+                        case HEADER_BLOCKED:
+                            break;
+
+                        case -1:
+                            pos = 0;
+                            end = -1;
+                            break;
+
+                        default:
+                            pos = 0;
+                            end = 0;
+                            unread = n;
+                            break;
+                    }
+                }
+                // avoid unnecessary call to in.available() if possible
+                int unreadAvail = (unread > 0) ?
+                    Math.min(in.available(), unread) : 0;
+                return (end >= 0) ? (end - pos) + unreadAvail : 0;
+            } else {
+                return in.available();
+            }
+        }
+
+        public void close() throws IOException {
+            if (blkmode) {
+                pos = 0;
+                end = -1;
+                unread = 0;
+            }
+            in.close();
+        }
+
+        /**
+         * Attempts to read len bytes into byte array b at offset off.  Returns
+         * the number of bytes read, or -1 if the end of stream/block data has
+         * been reached.  If copy is true, reads values into an intermediate
+         * buffer before copying them to b (to avoid exposing a reference to
+         * b).
+         */
+        int read(byte[] b, int off, int len, boolean copy) throws IOException {
+            if (len == 0) {
+                return 0;
+            } else if (blkmode) {
+                if (pos == end) {
+                    refill();
+                }
+                if (end < 0) {
+                    return -1;
+                }
+                int nread = Math.min(len, end - pos);
+                System.arraycopy(buf, pos, b, off, nread);
+                pos += nread;
+                return nread;
+            } else if (copy) {
+                int nread = in.read(buf, 0, Math.min(len, MAX_BLOCK_SIZE));
+                if (nread > 0) {
+                    System.arraycopy(buf, 0, b, off, nread);
+                }
+                return nread;
+            } else {
+                return in.read(b, off, len);
+            }
+        }
+
+        /* ----------------- primitive data input methods ------------------ */
+        /*
+         * The following methods are equivalent to their counterparts in
+         * DataInputStream, except that they interpret data block boundaries
+         * and read the requested data from within data blocks when in block
+         * data mode.
+         */
+
+        public void readFully(byte[] b) throws IOException {
+            readFully(b, 0, b.length, false);
+        }
+
+        public void readFully(byte[] b, int off, int len) throws IOException {
+            readFully(b, off, len, false);
+        }
+
+        public void readFully(byte[] b, int off, int len, boolean copy)
+            throws IOException
+        {
+            while (len > 0) {
+                int n = read(b, off, len, copy);
+                if (n < 0) {
+                    throw new EOFException();
+                }
+                off += n;
+                len -= n;
+            }
+        }
+
+        public int skipBytes(int n) throws IOException {
+            return din.skipBytes(n);
+        }
+
+        public boolean readBoolean() throws IOException {
+            int v = read();
+            if (v < 0) {
+                throw new EOFException();
+            }
+            return (v != 0);
+        }
+
+        public byte readByte() throws IOException {
+            int v = read();
+            if (v < 0) {
+                throw new EOFException();
+            }
+            return (byte) v;
+        }
+
+        public int readUnsignedByte() throws IOException {
+            int v = read();
+            if (v < 0) {
+                throw new EOFException();
+            }
+            return v;
+        }
+
+        public char readChar() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 2);
+            } else if (end - pos < 2) {
+                return din.readChar();
+            }
+            char v = Bits.getChar(buf, pos);
+            pos += 2;
+            return v;
+        }
+
+        public short readShort() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 2);
+            } else if (end - pos < 2) {
+                return din.readShort();
+            }
+            short v = Bits.getShort(buf, pos);
+            pos += 2;
+            return v;
+        }
+
+        public int readUnsignedShort() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 2);
+            } else if (end - pos < 2) {
+                return din.readUnsignedShort();
+            }
+            int v = Bits.getShort(buf, pos) & 0xFFFF;
+            pos += 2;
+            return v;
+        }
+
+        public int readInt() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 4);
+            } else if (end - pos < 4) {
+                return din.readInt();
+            }
+            int v = Bits.getInt(buf, pos);
+            pos += 4;
+            return v;
+        }
+
+        public float readFloat() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 4);
+            } else if (end - pos < 4) {
+                return din.readFloat();
+            }
+            float v = Bits.getFloat(buf, pos);
+            pos += 4;
+            return v;
+        }
+
+        public long readLong() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 8);
+            } else if (end - pos < 8) {
+                return din.readLong();
+            }
+            long v = Bits.getLong(buf, pos);
+            pos += 8;
+            return v;
+        }
+
+        public double readDouble() throws IOException {
+            if (!blkmode) {
+                pos = 0;
+                in.readFully(buf, 0, 8);
+            } else if (end - pos < 8) {
+                return din.readDouble();
+            }
+            double v = Bits.getDouble(buf, pos);
+            pos += 8;
+            return v;
+        }
+
+        public String readUTF() throws IOException {
+            return readUTFBody(readUnsignedShort());
+        }
+
+        @SuppressWarnings("deprecation")
+        public String readLine() throws IOException {
+            return din.readLine();      // deprecated, not worth optimizing
+        }
+
+        /* -------------- primitive data array input methods --------------- */
+        /*
+         * The following methods read in spans of primitive data values.
+         * Though equivalent to calling the corresponding primitive read
+         * methods repeatedly, these methods are optimized for reading groups
+         * of primitive data values more efficiently.
+         */
+
+        void readBooleans(boolean[] v, int off, int len) throws IOException {
+            int stop, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE);
+                    in.readFully(buf, 0, span);
+                    stop = off + span;
+                    pos = 0;
+                } else if (end - pos < 1) {
+                    v[off++] = din.readBoolean();
+                    continue;
+                } else {
+                    stop = Math.min(endoff, off + end - pos);
+                }
+
+                while (off < stop) {
+                    v[off++] = Bits.getBoolean(buf, pos++);
+                }
+            }
+        }
+
+        void readChars(char[] v, int off, int len) throws IOException {
+            int stop, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
+                    in.readFully(buf, 0, span << 1);
+                    stop = off + span;
+                    pos = 0;
+                } else if (end - pos < 2) {
+                    v[off++] = din.readChar();
+                    continue;
+                } else {
+                    stop = Math.min(endoff, off + ((end - pos) >> 1));
+                }
+
+                while (off < stop) {
+                    v[off++] = Bits.getChar(buf, pos);
+                    pos += 2;
+                }
+            }
+        }
+
+        void readShorts(short[] v, int off, int len) throws IOException {
+            int stop, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 1);
+                    in.readFully(buf, 0, span << 1);
+                    stop = off + span;
+                    pos = 0;
+                } else if (end - pos < 2) {
+                    v[off++] = din.readShort();
+                    continue;
+                } else {
+                    stop = Math.min(endoff, off + ((end - pos) >> 1));
+                }
+
+                while (off < stop) {
+                    v[off++] = Bits.getShort(buf, pos);
+                    pos += 2;
+                }
+            }
+        }
+
+        void readInts(int[] v, int off, int len) throws IOException {
+            int stop, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
+                    in.readFully(buf, 0, span << 2);
+                    stop = off + span;
+                    pos = 0;
+                } else if (end - pos < 4) {
+                    v[off++] = din.readInt();
+                    continue;
+                } else {
+                    stop = Math.min(endoff, off + ((end - pos) >> 2));
+                }
+
+                while (off < stop) {
+                    v[off++] = Bits.getInt(buf, pos);
+                    pos += 4;
+                }
+            }
+        }
+
+        void readFloats(float[] v, int off, int len) throws IOException {
+            int span, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 2);
+                    in.readFully(buf, 0, span << 2);
+                    pos = 0;
+                } else if (end - pos < 4) {
+                    v[off++] = din.readFloat();
+                    continue;
+                } else {
+                    span = Math.min(endoff - off, ((end - pos) >> 2));
+                }
+
+                bytesToFloats(buf, pos, v, off, span);
+                off += span;
+                pos += span << 2;
+            }
+        }
+
+        void readLongs(long[] v, int off, int len) throws IOException {
+            int stop, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    int span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
+                    in.readFully(buf, 0, span << 3);
+                    stop = off + span;
+                    pos = 0;
+                } else if (end - pos < 8) {
+                    v[off++] = din.readLong();
+                    continue;
+                } else {
+                    stop = Math.min(endoff, off + ((end - pos) >> 3));
+                }
+
+                while (off < stop) {
+                    v[off++] = Bits.getLong(buf, pos);
+                    pos += 8;
+                }
+            }
+        }
+
+        void readDoubles(double[] v, int off, int len) throws IOException {
+            int span, endoff = off + len;
+            while (off < endoff) {
+                if (!blkmode) {
+                    span = Math.min(endoff - off, MAX_BLOCK_SIZE >> 3);
+                    in.readFully(buf, 0, span << 3);
+                    pos = 0;
+                } else if (end - pos < 8) {
+                    v[off++] = din.readDouble();
+                    continue;
+                } else {
+                    span = Math.min(endoff - off, ((end - pos) >> 3));
+                }
+
+                bytesToDoubles(buf, pos, v, off, span);
+                off += span;
+                pos += span << 3;
+            }
+        }
+
+        /**
+         * Reads in string written in "long" UTF format.  "Long" UTF format is
+         * identical to standard UTF, except that it uses an 8 byte header
+         * (instead of the standard 2 bytes) to convey the UTF encoding length.
+         */
+        String readLongUTF() throws IOException {
+            return readUTFBody(readLong());
+        }
+
+        /**
+         * Reads in the "body" (i.e., the UTF representation minus the 2-byte
+         * or 8-byte length header) of a UTF encoding, which occupies the next
+         * utflen bytes.
+         */
+        private String readUTFBody(long utflen) throws IOException {
+            StringBuilder sbuf = new StringBuilder();
+            if (!blkmode) {
+                end = pos = 0;
+            }
+
+            while (utflen > 0) {
+                int avail = end - pos;
+                if (avail >= 3 || (long) avail == utflen) {
+                    utflen -= readUTFSpan(sbuf, utflen);
+                } else {
+                    if (blkmode) {
+                        // near block boundary, read one byte at a time
+                        utflen -= readUTFChar(sbuf, utflen);
+                    } else {
+                        // shift and refill buffer manually
+                        if (avail > 0) {
+                            System.arraycopy(buf, pos, buf, 0, avail);
+                        }
+                        pos = 0;
+                        end = (int) Math.min(MAX_BLOCK_SIZE, utflen);
+                        in.readFully(buf, avail, end - avail);
+                    }
+                }
+            }
+
+            return sbuf.toString();
+        }
+
+        /**
+         * Reads span of UTF-encoded characters out of internal buffer
+         * (starting at offset pos and ending at or before offset end),
+         * consuming no more than utflen bytes.  Appends read characters to
+         * sbuf.  Returns the number of bytes consumed.
+         */
+        private long readUTFSpan(StringBuilder sbuf, long utflen)
+            throws IOException
+        {
+            int cpos = 0;
+            int start = pos;
+            int avail = Math.min(end - pos, CHAR_BUF_SIZE);
+            // stop short of last char unless all of utf bytes in buffer
+            int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
+            boolean outOfBounds = false;
+
+            try {
+                while (pos < stop) {
+                    int b1, b2, b3;
+                    b1 = buf[pos++] & 0xFF;
+                    switch (b1 >> 4) {
+                        case 0:
+                        case 1:
+                        case 2:
+                        case 3:
+                        case 4:
+                        case 5:
+                        case 6:
+                        case 7:   // 1 byte format: 0xxxxxxx
+                            cbuf[cpos++] = (char) b1;
+                            break;
+
+                        case 12:
+                        case 13:  // 2 byte format: 110xxxxx 10xxxxxx
+                            b2 = buf[pos++];
+                            if ((b2 & 0xC0) != 0x80) {
+                                throw new UTFDataFormatException();
+                            }
+                            cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) |
+                                                   ((b2 & 0x3F) << 0));
+                            break;
+
+                        case 14:  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
+                            b3 = buf[pos + 1];
+                            b2 = buf[pos + 0];
+                            pos += 2;
+                            if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
+                                throw new UTFDataFormatException();
+                            }
+                            cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) |
+                                                   ((b2 & 0x3F) << 6) |
+                                                   ((b3 & 0x3F) << 0));
+                            break;
+
+                        default:  // 10xx xxxx, 1111 xxxx
+                            throw new UTFDataFormatException();
+                    }
+                }
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                outOfBounds = true;
+            } finally {
+                if (outOfBounds || (pos - start) > utflen) {
+                    /*
+                     * Fix for 4450867: if a malformed utf char causes the
+                     * conversion loop to scan past the expected end of the utf
+                     * string, only consume the expected number of utf bytes.
+                     */
+                    pos = start + (int) utflen;
+                    throw new UTFDataFormatException();
+                }
+            }
+
+            sbuf.append(cbuf, 0, cpos);
+            return pos - start;
+        }
+
+        /**
+         * Reads in single UTF-encoded character one byte at a time, appends
+         * the character to sbuf, and returns the number of bytes consumed.
+         * This method is used when reading in UTF strings written in block
+         * data mode to handle UTF-encoded characters which (potentially)
+         * straddle block-data boundaries.
+         */
+        private int readUTFChar(StringBuilder sbuf, long utflen)
+            throws IOException
+        {
+            int b1, b2, b3;
+            b1 = readByte() & 0xFF;
+            switch (b1 >> 4) {
+                case 0:
+                case 1:
+                case 2:
+                case 3:
+                case 4:
+                case 5:
+                case 6:
+                case 7:     // 1 byte format: 0xxxxxxx
+                    sbuf.append((char) b1);
+                    return 1;
+
+                case 12:
+                case 13:    // 2 byte format: 110xxxxx 10xxxxxx
+                    if (utflen < 2) {
+                        throw new UTFDataFormatException();
+                    }
+                    b2 = readByte();
+                    if ((b2 & 0xC0) != 0x80) {
+                        throw new UTFDataFormatException();
+                    }
+                    sbuf.append((char) (((b1 & 0x1F) << 6) |
+                                        ((b2 & 0x3F) << 0)));
+                    return 2;
+
+                case 14:    // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
+                    if (utflen < 3) {
+                        if (utflen == 2) {
+                            readByte();         // consume remaining byte
+                        }
+                        throw new UTFDataFormatException();
+                    }
+                    b2 = readByte();
+                    b3 = readByte();
+                    if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
+                        throw new UTFDataFormatException();
+                    }
+                    sbuf.append((char) (((b1 & 0x0F) << 12) |
+                                        ((b2 & 0x3F) << 6) |
+                                        ((b3 & 0x3F) << 0)));
+                    return 3;
+
+                default:   // 10xx xxxx, 1111 xxxx
+                    throw new UTFDataFormatException();
+            }
+        }
+
+        /**
+         * Returns the number of bytes read from the input stream.
+         * @return the number of bytes read from the input stream
+         */
+        long getBytesRead() {
+            return in.getBytesRead();
+        }
+    }
+
+    /**
+     * Unsynchronized table which tracks wire handle to object mappings, as
+     * well as ClassNotFoundExceptions associated with deserialized objects.
+     * This class implements an exception-propagation algorithm for
+     * determining which objects should have ClassNotFoundExceptions associated
+     * with them, taking into account cycles and discontinuities (e.g., skipped
+     * fields) in the object graph.
+     *
+     * <p>General use of the table is as follows: during deserialization, a
+     * given object is first assigned a handle by calling the assign method.
+     * This method leaves the assigned handle in an "open" state, wherein
+     * dependencies on the exception status of other handles can be registered
+     * by calling the markDependency method, or an exception can be directly
+     * associated with the handle by calling markException.  When a handle is
+     * tagged with an exception, the HandleTable assumes responsibility for
+     * propagating the exception to any other objects which depend
+     * (transitively) on the exception-tagged object.
+     *
+     * <p>Once all exception information/dependencies for the handle have been
+     * registered, the handle should be "closed" by calling the finish method
+     * on it.  The act of finishing a handle allows the exception propagation
+     * algorithm to aggressively prune dependency links, lessening the
+     * performance/memory impact of exception tracking.
+     *
+     * <p>Note that the exception propagation algorithm used depends on handles
+     * being assigned/finished in LIFO order; however, for simplicity as well
+     * as memory conservation, it does not enforce this constraint.
+     */
+    // REMIND: add full description of exception propagation algorithm?
+    private static class HandleTable {
+
+        /* status codes indicating whether object has associated exception */
+        private static final byte STATUS_OK = 1;
+        private static final byte STATUS_UNKNOWN = 2;
+        private static final byte STATUS_EXCEPTION = 3;
+
+        /** array mapping handle -> object status */
+        byte[] status;
+        /** array mapping handle -> object/exception (depending on status) */
+        Object[] entries;
+        /** array mapping handle -> list of dependent handles (if any) */
+        HandleList[] deps;
+        /** lowest unresolved dependency */
+        int lowDep = -1;
+        /** number of handles in table */
+        int size = 0;
+
+        /**
+         * Creates handle table with the given initial capacity.
+         */
+        HandleTable(int initialCapacity) {
+            status = new byte[initialCapacity];
+            entries = new Object[initialCapacity];
+            deps = new HandleList[initialCapacity];
+        }
+
+        /**
+         * Assigns next available handle to given object, and returns assigned
+         * handle.  Once object has been completely deserialized (and all
+         * dependencies on other objects identified), the handle should be
+         * "closed" by passing it to finish().
+         */
+        int assign(Object obj) {
+            if (size >= entries.length) {
+                grow();
+            }
+            status[size] = STATUS_UNKNOWN;
+            entries[size] = obj;
+            return size++;
+        }
+
+        /**
+         * Registers a dependency (in exception status) of one handle on
+         * another.  The dependent handle must be "open" (i.e., assigned, but
+         * not finished yet).  No action is taken if either dependent or target
+         * handle is NULL_HANDLE.
+         */
+        void markDependency(int dependent, int target) {
+            if (dependent == NULL_HANDLE || target == NULL_HANDLE) {
+                return;
+            }
+            switch (status[dependent]) {
+
+                case STATUS_UNKNOWN:
+                    switch (status[target]) {
+                        case STATUS_OK:
+                            // ignore dependencies on objs with no exception
+                            break;
+
+                        case STATUS_EXCEPTION:
+                            // eagerly propagate exception
+                            markException(dependent,
+                                (ClassNotFoundException) entries[target]);
+                            break;
+
+                        case STATUS_UNKNOWN:
+                            // add to dependency list of target
+                            if (deps[target] == null) {
+                                deps[target] = new HandleList();
+                            }
+                            deps[target].add(dependent);
+
+                            // remember lowest unresolved target seen
+                            if (lowDep < 0 || lowDep > target) {
+                                lowDep = target;
+                            }
+                            break;
+
+                        default:
+                            throw new InternalError();
+                    }
+                    break;
+
+                case STATUS_EXCEPTION:
+                    break;
+
+                default:
+                    throw new InternalError();
+            }
+        }
+
+        /**
+         * Associates a ClassNotFoundException (if one not already associated)
+         * with the currently active handle and propagates it to other
+         * referencing objects as appropriate.  The specified handle must be
+         * "open" (i.e., assigned, but not finished yet).
+         */
+        void markException(int handle, ClassNotFoundException ex) {
+            switch (status[handle]) {
+                case STATUS_UNKNOWN:
+                    status[handle] = STATUS_EXCEPTION;
+                    entries[handle] = ex;
+
+                    // propagate exception to dependents
+                    HandleList dlist = deps[handle];
+                    if (dlist != null) {
+                        int ndeps = dlist.size();
+                        for (int i = 0; i < ndeps; i++) {
+                            markException(dlist.get(i), ex);
+                        }
+                        deps[handle] = null;
+                    }
+                    break;
+
+                case STATUS_EXCEPTION:
+                    break;
+
+                default:
+                    throw new InternalError();
+            }
+        }
+
+        /**
+         * Marks given handle as finished, meaning that no new dependencies
+         * will be marked for handle.  Calls to the assign and finish methods
+         * must occur in LIFO order.
+         */
+        void finish(int handle) {
+            int end;
+            if (lowDep < 0) {
+                // no pending unknowns, only resolve current handle
+                end = handle + 1;
+            } else if (lowDep >= handle) {
+                // pending unknowns now clearable, resolve all upward handles
+                end = size;
+                lowDep = -1;
+            } else {
+                // unresolved backrefs present, can't resolve anything yet
+                return;
+            }
+
+            // change STATUS_UNKNOWN -> STATUS_OK in selected span of handles
+            for (int i = handle; i < end; i++) {
+                switch (status[i]) {
+                    case STATUS_UNKNOWN:
+                        status[i] = STATUS_OK;
+                        deps[i] = null;
+                        break;
+
+                    case STATUS_OK:
+                    case STATUS_EXCEPTION:
+                        break;
+
+                    default:
+                        throw new InternalError();
+                }
+            }
+        }
+
+        /**
+         * Assigns a new object to the given handle.  The object previously
+         * associated with the handle is forgotten.  This method has no effect
+         * if the given handle already has an exception associated with it.
+         * This method may be called at any time after the handle is assigned.
+         */
+        void setObject(int handle, Object obj) {
+            switch (status[handle]) {
+                case STATUS_UNKNOWN:
+                case STATUS_OK:
+                    entries[handle] = obj;
+                    break;
+
+                case STATUS_EXCEPTION:
+                    break;
+
+                default:
+                    throw new InternalError();
+            }
+        }
+
+        /**
+         * Looks up and returns object associated with the given handle.
+         * Returns null if the given handle is NULL_HANDLE, or if it has an
+         * associated ClassNotFoundException.
+         */
+        Object lookupObject(int handle) {
+            return (handle != NULL_HANDLE &&
+                    status[handle] != STATUS_EXCEPTION) ?
+                entries[handle] : null;
+        }
+
+        /**
+         * Looks up and returns ClassNotFoundException associated with the
+         * given handle.  Returns null if the given handle is NULL_HANDLE, or
+         * if there is no ClassNotFoundException associated with the handle.
+         */
+        ClassNotFoundException lookupException(int handle) {
+            return (handle != NULL_HANDLE &&
+                    status[handle] == STATUS_EXCEPTION) ?
+                (ClassNotFoundException) entries[handle] : null;
+        }
+
+        /**
+         * Resets table to its initial state.
+         */
+        void clear() {
+            Arrays.fill(status, 0, size, (byte) 0);
+            Arrays.fill(entries, 0, size, null);
+            Arrays.fill(deps, 0, size, null);
+            lowDep = -1;
+            size = 0;
+        }
+
+        /**
+         * Returns number of handles registered in table.
+         */
+        int size() {
+            return size;
+        }
+
+        /**
+         * Expands capacity of internal arrays.
+         */
+        private void grow() {
+            int newCapacity = (entries.length << 1) + 1;
+
+            byte[] newStatus = new byte[newCapacity];
+            Object[] newEntries = new Object[newCapacity];
+            HandleList[] newDeps = new HandleList[newCapacity];
+
+            System.arraycopy(status, 0, newStatus, 0, size);
+            System.arraycopy(entries, 0, newEntries, 0, size);
+            System.arraycopy(deps, 0, newDeps, 0, size);
+
+            status = newStatus;
+            entries = newEntries;
+            deps = newDeps;
+        }
+
+        /**
+         * Simple growable list of (integer) handles.
+         */
+        private static class HandleList {
+            private int[] list = new int[4];
+            private int size = 0;
+
+            public HandleList() {
+            }
+
+            public void add(int handle) {
+                if (size >= list.length) {
+                    int[] newList = new int[list.length << 1];
+                    System.arraycopy(list, 0, newList, 0, list.length);
+                    list = newList;
+                }
+                list[size++] = handle;
+            }
+
+            public int get(int index) {
+                if (index >= size) {
+                    throw new ArrayIndexOutOfBoundsException();
+                }
+                return list[index];
+            }
+
+            public int size() {
+                return size;
+            }
+        }
+    }
+
+    /**
+     * Method for cloning arrays in case of using unsharing reading
+     */
+    private static Object cloneArray(Object array) {
+        if (array instanceof Object[]) {
+            return ((Object[]) array).clone();
+        } else if (array instanceof boolean[]) {
+            return ((boolean[]) array).clone();
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array).clone();
+        } else if (array instanceof char[]) {
+            return ((char[]) array).clone();
+        } else if (array instanceof double[]) {
+            return ((double[]) array).clone();
+        } else if (array instanceof float[]) {
+            return ((float[]) array).clone();
+        } else if (array instanceof int[]) {
+            return ((int[]) array).clone();
+        } else if (array instanceof long[]) {
+            return ((long[]) array).clone();
+        } else if (array instanceof short[]) {
+            return ((short[]) array).clone();
+        } else {
+            throw new AssertionError();
+        }
+    }
+
+    // Android-removed: Logic related to ObjectStreamClassValidator, unused on Android
+    /*
+    private void validateDescriptor(ObjectStreamClass descriptor) {
+        ObjectStreamClassValidator validating = validator;
+        if (validating != null) {
+            validating.validateDescriptor(descriptor);
+        }
+    }
+
+    // controlled access to ObjectStreamClassValidator
+    private volatile ObjectStreamClassValidator validator;
+
+    private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) {
+        ois.validator = validator;
+    }
+    static {
+        SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator);
+    }
+    */
+}
diff --git a/java/io/ObjectInputValidation.java b/java/io/ObjectInputValidation.java
new file mode 100644
index 0000000..dc6f842
--- /dev/null
+++ b/java/io/ObjectInputValidation.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Callback interface to allow validation of objects within a graph.
+ * Allows an object to be called when a complete graph of objects has
+ * been deserialized.
+ *
+ * @author  unascribed
+ * @see     ObjectInputStream
+ * @see     ObjectInputStream#registerValidation(java.io.ObjectInputValidation, int)
+ * @since   JDK1.1
+ */
+public interface ObjectInputValidation {
+    /**
+     * Validates the object.
+     *
+     * @exception InvalidObjectException If the object cannot validate itself.
+     */
+    public void validateObject() throws InvalidObjectException;
+}
diff --git a/java/io/ObjectOutput.java b/java/io/ObjectOutput.java
new file mode 100644
index 0000000..7c2cbeb
--- /dev/null
+++ b/java/io/ObjectOutput.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * ObjectOutput extends the DataOutput interface to include writing of objects.
+ * DataOutput includes methods for output of primitive types, ObjectOutput
+ * extends that interface to include objects, arrays, and Strings.
+ *
+ * @author  unascribed
+ * @see java.io.InputStream
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @since   JDK1.1
+ */
+public interface ObjectOutput extends DataOutput, AutoCloseable {
+    /**
+     * Write an object to the underlying storage or stream.  The
+     * class that implements this interface defines how the object is
+     * written.
+     *
+     * @param obj the object to be written
+     * @exception IOException Any of the usual Input/Output related exceptions.
+     */
+    public void writeObject(Object obj)
+      throws IOException;
+
+    /**
+     * Writes a byte. This method will block until the byte is actually
+     * written.
+     * @param b the byte
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void write(int b) throws IOException;
+
+    /**
+     * Writes an array of bytes. This method will block until the bytes
+     * are actually written.
+     * @param b the data to be written
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void write(byte b[]) throws IOException;
+
+    /**
+     * Writes a sub array of bytes.
+     * @param b the data to be written
+     * @param off       the start offset in the data
+     * @param len       the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void write(byte b[], int off, int len) throws IOException;
+
+    /**
+     * Flushes the stream. This will write any buffered
+     * output bytes.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void flush() throws IOException;
+
+    /**
+     * Closes the stream. This method must be called
+     * to release any resources associated with the
+     * stream.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void close() throws IOException;
+}
diff --git a/java/io/ObjectOutputStream.java b/java/io/ObjectOutputStream.java
new file mode 100644
index 0000000..ccec944
--- /dev/null
+++ b/java/io/ObjectOutputStream.java
@@ -0,0 +1,2574 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.ObjectStreamClass.WeakClassKey;
+import java.lang.ref.ReferenceQueue;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import static java.io.ObjectStreamClass.processQueue;
+import java.io.SerialCallbackContext;
+import sun.reflect.misc.ReflectUtil;
+
+/**
+ * An ObjectOutputStream writes primitive data types and graphs of Java objects
+ * to an OutputStream.  The objects can be read (reconstituted) using an
+ * ObjectInputStream.  Persistent storage of objects can be accomplished by
+ * using a file for the stream.  If the stream is a network socket stream, the
+ * objects can be reconstituted on another host or in another process.
+ *
+ * <p>Only objects that support the java.io.Serializable interface can be
+ * written to streams.  The class of each serializable object is encoded
+ * including the class name and signature of the class, the values of the
+ * object's fields and arrays, and the closure of any other objects referenced
+ * from the initial objects.
+ *
+ * <p>The method writeObject is used to write an object to the stream.  Any
+ * object, including Strings and arrays, is written with writeObject. Multiple
+ * objects or primitives can be written to the stream.  The objects must be
+ * read back from the corresponding ObjectInputstream with the same types and
+ * in the same order as they were written.
+ *
+ * <p>Primitive data types can also be written to the stream using the
+ * appropriate methods from DataOutput. Strings can also be written using the
+ * writeUTF method.
+ *
+ * <p>The default serialization mechanism for an object writes the class of the
+ * object, the class signature, and the values of all non-transient and
+ * non-static fields.  References to other objects (except in transient or
+ * static fields) cause those objects to be written also. Multiple references
+ * to a single object are encoded using a reference sharing mechanism so that
+ * graphs of objects can be restored to the same shape as when the original was
+ * written.
+ *
+ * <p>For example to write an object that can be read by the example in
+ * ObjectInputStream:
+ * <br>
+ * <pre>
+ *      FileOutputStream fos = new FileOutputStream("t.tmp");
+ *      ObjectOutputStream oos = new ObjectOutputStream(fos);
+ *
+ *      oos.writeInt(12345);
+ *      oos.writeObject("Today");
+ *      oos.writeObject(new Date());
+ *
+ *      oos.close();
+ * </pre>
+ *
+ * <p>Classes that require special handling during the serialization and
+ * deserialization process must implement special methods with these exact
+ * signatures:
+ * <br>
+ * <pre>
+ * private void readObject(java.io.ObjectInputStream stream)
+ *     throws IOException, ClassNotFoundException;
+ * private void writeObject(java.io.ObjectOutputStream stream)
+ *     throws IOException
+ * private void readObjectNoData()
+ *     throws ObjectStreamException;
+ * </pre>
+ *
+ * <p>The writeObject method is responsible for writing the state of the object
+ * for its particular class so that the corresponding readObject method can
+ * restore it.  The method does not need to concern itself with the state
+ * belonging to the object's superclasses or subclasses.  State is saved by
+ * writing the individual fields to the ObjectOutputStream using the
+ * writeObject method or by using the methods for primitive data types
+ * supported by DataOutput.
+ *
+ * <p>Serialization does not write out the fields of any object that does not
+ * implement the java.io.Serializable interface.  Subclasses of Objects that
+ * are not serializable can be serializable. In this case the non-serializable
+ * class must have a no-arg constructor to allow its fields to be initialized.
+ * In this case it is the responsibility of the subclass to save and restore
+ * the state of the non-serializable class. It is frequently the case that the
+ * fields of that class are accessible (public, package, or protected) or that
+ * there are get and set methods that can be used to restore the state.
+ *
+ * <p>Serialization of an object can be prevented by implementing writeObject
+ * and readObject methods that throw the NotSerializableException.  The
+ * exception will be caught by the ObjectOutputStream and abort the
+ * serialization process.
+ *
+ * <p>Implementing the Externalizable interface allows the object to assume
+ * complete control over the contents and format of the object's serialized
+ * form.  The methods of the Externalizable interface, writeExternal and
+ * readExternal, are called to save and restore the objects state.  When
+ * implemented by a class they can write and read their own state using all of
+ * the methods of ObjectOutput and ObjectInput.  It is the responsibility of
+ * the objects to handle any versioning that occurs.
+ *
+ * <p>Enum constants are serialized differently than ordinary serializable or
+ * externalizable objects.  The serialized form of an enum constant consists
+ * solely of its name; field values of the constant are not transmitted.  To
+ * serialize an enum constant, ObjectOutputStream writes the string returned by
+ * the constant's name method.  Like other serializable or externalizable
+ * objects, enum constants can function as the targets of back references
+ * appearing subsequently in the serialization stream.  The process by which
+ * enum constants are serialized cannot be customized; any class-specific
+ * writeObject and writeReplace methods defined by enum types are ignored
+ * during serialization.  Similarly, any serialPersistentFields or
+ * serialVersionUID field declarations are also ignored--all enum types have a
+ * fixed serialVersionUID of 0L.
+ *
+ * <p>Primitive data, excluding serializable fields and externalizable data, is
+ * written to the ObjectOutputStream in block-data records. A block data record
+ * is composed of a header and data. The block data header consists of a marker
+ * and the number of bytes to follow the header.  Consecutive primitive data
+ * writes are merged into one block-data record.  The blocking factor used for
+ * a block-data record will be 1024 bytes.  Each block-data record will be
+ * filled up to 1024 bytes, or be written whenever there is a termination of
+ * block-data mode.  Calls to the ObjectOutputStream methods writeObject,
+ * defaultWriteObject and writeFields initially terminate any existing
+ * block-data record.
+ *
+ * @author      Mike Warres
+ * @author      Roger Riggs
+ * @see java.io.DataOutput
+ * @see java.io.ObjectInputStream
+ * @see java.io.Serializable
+ * @see java.io.Externalizable
+ * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
+ * @since       JDK1.1
+ */
+public class ObjectOutputStream
+    extends OutputStream implements ObjectOutput, ObjectStreamConstants
+{
+
+    private static class Caches {
+        /** cache of subclass security audit results */
+        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
+            new ConcurrentHashMap<>();
+
+        /** queue for WeakReferences to audited subclasses */
+        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
+            new ReferenceQueue<>();
+    }
+
+    /** filter stream for handling block data conversion */
+    private final BlockDataOutputStream bout;
+    /** obj -> wire handle map */
+    private final HandleTable handles;
+    /** obj -> replacement obj map */
+    private final ReplaceTable subs;
+    /** stream protocol version */
+    private int protocol = PROTOCOL_VERSION_2;
+    /** recursion depth */
+    private int depth;
+
+    /** buffer for writing primitive field values */
+    private byte[] primVals;
+
+    /** if true, invoke writeObjectOverride() instead of writeObject() */
+    private final boolean enableOverride;
+    /** if true, invoke replaceObject() */
+    private boolean enableReplace;
+
+    // values below valid only during upcalls to writeObject()/writeExternal()
+    /**
+     * Context during upcalls to class-defined writeObject methods; holds
+     * object currently being serialized and descriptor for current class.
+     * Null when not during writeObject upcall.
+     */
+    private SerialCallbackContext curContext;
+    /** current PutField object */
+    private PutFieldImpl curPut;
+
+    /** custom storage for debug trace info */
+    private final DebugTraceInfoStack debugInfoStack;
+
+    /**
+     * value of "sun.io.serialization.extendedDebugInfo" property,
+     * as true or false for extended information about exception's place
+     */
+    // BEGIN Android-changed: Do not support extendedDebugInfo on Android.
+    /*
+    private static final boolean extendedDebugInfo =
+        java.security.AccessController.doPrivileged(
+            new sun.security.action.GetBooleanAction(
+                "sun.io.serialization.extendedDebugInfo")).booleanValue();
+    */
+    private static final boolean extendedDebugInfo = false;
+    // END Android-changed: Do not support extendedDebugInfo on Android.
+
+    /**
+     * Creates an ObjectOutputStream that writes to the specified OutputStream.
+     * This constructor writes the serialization stream header to the
+     * underlying stream; callers may wish to flush the stream immediately to
+     * ensure that constructors for receiving ObjectInputStreams will not block
+     * when reading the header.
+     *
+     * <p>If a security manager is installed, this constructor will check for
+     * the "enableSubclassImplementation" SerializablePermission when invoked
+     * directly or indirectly by the constructor of a subclass which overrides
+     * the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
+     * methods.
+     *
+     * @param   out output stream to write to
+     * @throws  IOException if an I/O error occurs while writing stream header
+     * @throws  SecurityException if untrusted subclass illegally overrides
+     *          security-sensitive methods
+     * @throws  NullPointerException if <code>out</code> is <code>null</code>
+     * @since   1.4
+     * @see     ObjectOutputStream#ObjectOutputStream()
+     * @see     ObjectOutputStream#putFields()
+     * @see     ObjectInputStream#ObjectInputStream(InputStream)
+     */
+    public ObjectOutputStream(OutputStream out) throws IOException {
+        verifySubclass();
+        bout = new BlockDataOutputStream(out);
+        handles = new HandleTable(10, (float) 3.00);
+        subs = new ReplaceTable(10, (float) 3.00);
+        enableOverride = false;
+        writeStreamHeader();
+        bout.setBlockDataMode(true);
+        if (extendedDebugInfo) {
+            debugInfoStack = new DebugTraceInfoStack();
+        } else {
+            debugInfoStack = null;
+        }
+    }
+
+    /**
+     * Provide a way for subclasses that are completely reimplementing
+     * ObjectOutputStream to not have to allocate private data just used by
+     * this implementation of ObjectOutputStream.
+     *
+     * <p>If there is a security manager installed, this method first calls the
+     * security manager's <code>checkPermission</code> method with a
+     * <code>SerializablePermission("enableSubclassImplementation")</code>
+     * permission to ensure it's ok to enable subclassing.
+     *
+     * @throws  SecurityException if a security manager exists and its
+     *          <code>checkPermission</code> method denies enabling
+     *          subclassing.
+     * @throws  IOException if an I/O error occurs while creating this stream
+     * @see SecurityManager#checkPermission
+     * @see java.io.SerializablePermission
+     */
+    protected ObjectOutputStream() throws IOException, SecurityException {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+        }
+        bout = null;
+        handles = null;
+        subs = null;
+        enableOverride = true;
+        debugInfoStack = null;
+    }
+
+    /**
+     * Specify stream protocol version to use when writing the stream.
+     *
+     * <p>This routine provides a hook to enable the current version of
+     * Serialization to write in a format that is backwards compatible to a
+     * previous version of the stream format.
+     *
+     * <p>Every effort will be made to avoid introducing additional
+     * backwards incompatibilities; however, sometimes there is no
+     * other alternative.
+     *
+     * @param   version use ProtocolVersion from java.io.ObjectStreamConstants.
+     * @throws  IllegalStateException if called after any objects
+     *          have been serialized.
+     * @throws  IllegalArgumentException if invalid version is passed in.
+     * @throws  IOException if I/O errors occur
+     * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
+     * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_2
+     * @since   1.2
+     */
+    public void useProtocolVersion(int version) throws IOException {
+        if (handles.size() != 0) {
+            // REMIND: implement better check for pristine stream?
+            throw new IllegalStateException("stream non-empty");
+        }
+        switch (version) {
+            case PROTOCOL_VERSION_1:
+            case PROTOCOL_VERSION_2:
+                protocol = version;
+                break;
+
+            default:
+                throw new IllegalArgumentException(
+                    "unknown version: " + version);
+        }
+    }
+
+    /**
+     * Write the specified object to the ObjectOutputStream.  The class of the
+     * object, the signature of the class, and the values of the non-transient
+     * and non-static fields of the class and all of its supertypes are
+     * written.  Default serialization for a class can be overridden using the
+     * writeObject and the readObject methods.  Objects referenced by this
+     * object are written transitively so that a complete equivalent graph of
+     * objects can be reconstructed by an ObjectInputStream.
+     *
+     * <p>Exceptions are thrown for problems with the OutputStream and for
+     * classes that should not be serialized.  All exceptions are fatal to the
+     * OutputStream, which is left in an indeterminate state, and it is up to
+     * the caller to ignore or recover the stream state.
+     *
+     * @throws  InvalidClassException Something is wrong with a class used by
+     *          serialization.
+     * @throws  NotSerializableException Some object to be serialized does not
+     *          implement the java.io.Serializable interface.
+     * @throws  IOException Any exception thrown by the underlying
+     *          OutputStream.
+     */
+    public final void writeObject(Object obj) throws IOException {
+        if (enableOverride) {
+            writeObjectOverride(obj);
+            return;
+        }
+        try {
+            writeObject0(obj, false);
+        } catch (IOException ex) {
+            if (depth == 0) {
+                // BEGIN Android-changed: Ignore secondary exceptions during writeObject().
+                // writeFatalException(ex);
+                try {
+                    writeFatalException(ex);
+
+                } catch (IOException ex2) {
+                    // If writing the exception to the output stream causes another exception there
+                    // is no need to propagate the second exception or generate a third exception,
+                    // both of which might obscure details of the root cause.
+                }
+                // END Android-changed: Ignore secondary exceptions during writeObject().
+            }
+            throw ex;
+        }
+    }
+
+    /**
+     * Method used by subclasses to override the default writeObject method.
+     * This method is called by trusted subclasses of ObjectInputStream that
+     * constructed ObjectInputStream using the protected no-arg constructor.
+     * The subclass is expected to provide an override method with the modifier
+     * "final".
+     *
+     * @param   obj object to be written to the underlying stream
+     * @throws  IOException if there are I/O errors while writing to the
+     *          underlying stream
+     * @see #ObjectOutputStream()
+     * @see #writeObject(Object)
+     * @since 1.2
+     */
+    protected void writeObjectOverride(Object obj) throws IOException {
+        // BEGIN Android-added: Let writeObjectOverride throw IOException if !enableOverride.
+        if (!enableOverride) {
+            // Subclasses must override.
+            throw new IOException();
+        }
+        // END Android-added: Let writeObjectOverride throw IOException if !enableOverride.
+    }
+
+    /**
+     * Writes an "unshared" object to the ObjectOutputStream.  This method is
+     * identical to writeObject, except that it always writes the given object
+     * as a new, unique object in the stream (as opposed to a back-reference
+     * pointing to a previously serialized instance).  Specifically:
+     * <ul>
+     *   <li>An object written via writeUnshared is always serialized in the
+     *       same manner as a newly appearing object (an object that has not
+     *       been written to the stream yet), regardless of whether or not the
+     *       object has been written previously.
+     *
+     *   <li>If writeObject is used to write an object that has been previously
+     *       written with writeUnshared, the previous writeUnshared operation
+     *       is treated as if it were a write of a separate object.  In other
+     *       words, ObjectOutputStream will never generate back-references to
+     *       object data written by calls to writeUnshared.
+     * </ul>
+     * While writing an object via writeUnshared does not in itself guarantee a
+     * unique reference to the object when it is deserialized, it allows a
+     * single object to be defined multiple times in a stream, so that multiple
+     * calls to readUnshared by the receiver will not conflict.  Note that the
+     * rules described above only apply to the base-level object written with
+     * writeUnshared, and not to any transitively referenced sub-objects in the
+     * object graph to be serialized.
+     *
+     * <p>ObjectOutputStream subclasses which override this method can only be
+     * constructed in security contexts possessing the
+     * "enableSubclassImplementation" SerializablePermission; any attempt to
+     * instantiate such a subclass without this permission will cause a
+     * SecurityException to be thrown.
+     *
+     * @param   obj object to write to stream
+     * @throws  NotSerializableException if an object in the graph to be
+     *          serialized does not implement the Serializable interface
+     * @throws  InvalidClassException if a problem exists with the class of an
+     *          object to be serialized
+     * @throws  IOException if an I/O error occurs during serialization
+     * @since 1.4
+     */
+    public void writeUnshared(Object obj) throws IOException {
+        try {
+            writeObject0(obj, true);
+        } catch (IOException ex) {
+            if (depth == 0) {
+                writeFatalException(ex);
+            }
+            throw ex;
+        }
+    }
+
+    /**
+     * Write the non-static and non-transient fields of the current class to
+     * this stream.  This may only be called from the writeObject method of the
+     * class being serialized. It will throw the NotActiveException if it is
+     * called otherwise.
+     *
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          <code>OutputStream</code>
+     */
+    public void defaultWriteObject() throws IOException {
+        SerialCallbackContext ctx = curContext;
+        if (ctx == null) {
+            throw new NotActiveException("not in call to writeObject");
+        }
+        Object curObj = ctx.getObj();
+        ObjectStreamClass curDesc = ctx.getDesc();
+        bout.setBlockDataMode(false);
+        defaultWriteFields(curObj, curDesc);
+        bout.setBlockDataMode(true);
+    }
+
+    /**
+     * Retrieve the object used to buffer persistent fields to be written to
+     * the stream.  The fields will be written to the stream when writeFields
+     * method is called.
+     *
+     * @return  an instance of the class Putfield that holds the serializable
+     *          fields
+     * @throws  IOException if I/O errors occur
+     * @since 1.2
+     */
+    public ObjectOutputStream.PutField putFields() throws IOException {
+        if (curPut == null) {
+            SerialCallbackContext ctx = curContext;
+            if (ctx == null) {
+                throw new NotActiveException("not in call to writeObject");
+            }
+            Object curObj = ctx.getObj();
+            ObjectStreamClass curDesc = ctx.getDesc();
+            curPut = new PutFieldImpl(curDesc);
+        }
+        return curPut;
+    }
+
+    /**
+     * Write the buffered fields to the stream.
+     *
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     * @throws  NotActiveException Called when a classes writeObject method was
+     *          not called to write the state of the object.
+     * @since 1.2
+     */
+    public void writeFields() throws IOException {
+        if (curPut == null) {
+            throw new NotActiveException("no current PutField object");
+        }
+        bout.setBlockDataMode(false);
+        curPut.writeFields();
+        bout.setBlockDataMode(true);
+    }
+
+    /**
+     * Reset will disregard the state of any objects already written to the
+     * stream.  The state is reset to be the same as a new ObjectOutputStream.
+     * The current point in the stream is marked as reset so the corresponding
+     * ObjectInputStream will be reset at the same point.  Objects previously
+     * written to the stream will not be referred to as already being in the
+     * stream.  They will be written to the stream again.
+     *
+     * @throws  IOException if reset() is invoked while serializing an object.
+     */
+    public void reset() throws IOException {
+        if (depth != 0) {
+            throw new IOException("stream active");
+        }
+        bout.setBlockDataMode(false);
+        bout.writeByte(TC_RESET);
+        clear();
+        bout.setBlockDataMode(true);
+    }
+
+    /**
+     * Subclasses may implement this method to allow class data to be stored in
+     * the stream. By default this method does nothing.  The corresponding
+     * method in ObjectInputStream is resolveClass.  This method is called
+     * exactly once for each unique class in the stream.  The class name and
+     * signature will have already been written to the stream.  This method may
+     * make free use of the ObjectOutputStream to save any representation of
+     * the class it deems suitable (for example, the bytes of the class file).
+     * The resolveClass method in the corresponding subclass of
+     * ObjectInputStream must read and use any data or objects written by
+     * annotateClass.
+     *
+     * @param   cl the class to annotate custom data for
+     * @throws  IOException Any exception thrown by the underlying
+     *          OutputStream.
+     */
+    protected void annotateClass(Class<?> cl) throws IOException {
+    }
+
+    /**
+     * Subclasses may implement this method to store custom data in the stream
+     * along with descriptors for dynamic proxy classes.
+     *
+     * <p>This method is called exactly once for each unique proxy class
+     * descriptor in the stream.  The default implementation of this method in
+     * <code>ObjectOutputStream</code> does nothing.
+     *
+     * <p>The corresponding method in <code>ObjectInputStream</code> is
+     * <code>resolveProxyClass</code>.  For a given subclass of
+     * <code>ObjectOutputStream</code> that overrides this method, the
+     * <code>resolveProxyClass</code> method in the corresponding subclass of
+     * <code>ObjectInputStream</code> must read any data or objects written by
+     * <code>annotateProxyClass</code>.
+     *
+     * @param   cl the proxy class to annotate custom data for
+     * @throws  IOException any exception thrown by the underlying
+     *          <code>OutputStream</code>
+     * @see ObjectInputStream#resolveProxyClass(String[])
+     * @since   1.3
+     */
+    protected void annotateProxyClass(Class<?> cl) throws IOException {
+    }
+
+    /**
+     * This method will allow trusted subclasses of ObjectOutputStream to
+     * substitute one object for another during serialization. Replacing
+     * objects is disabled until enableReplaceObject is called. The
+     * enableReplaceObject method checks that the stream requesting to do
+     * replacement can be trusted.  The first occurrence of each object written
+     * into the serialization stream is passed to replaceObject.  Subsequent
+     * references to the object are replaced by the object returned by the
+     * original call to replaceObject.  To ensure that the private state of
+     * objects is not unintentionally exposed, only trusted streams may use
+     * replaceObject.
+     *
+     * <p>The ObjectOutputStream.writeObject method takes a parameter of type
+     * Object (as opposed to type Serializable) to allow for cases where
+     * non-serializable objects are replaced by serializable ones.
+     *
+     * <p>When a subclass is replacing objects it must insure that either a
+     * complementary substitution must be made during deserialization or that
+     * the substituted object is compatible with every field where the
+     * reference will be stored.  Objects whose type is not a subclass of the
+     * type of the field or array element abort the serialization by raising an
+     * exception and the object is not be stored.
+     *
+     * <p>This method is called only once when each object is first
+     * encountered.  All subsequent references to the object will be redirected
+     * to the new object. This method should return the object to be
+     * substituted or the original object.
+     *
+     * <p>Null can be returned as the object to be substituted, but may cause
+     * NullReferenceException in classes that contain references to the
+     * original object since they may be expecting an object instead of
+     * null.
+     *
+     * @param   obj the object to be replaced
+     * @return  the alternate object that replaced the specified one
+     * @throws  IOException Any exception thrown by the underlying
+     *          OutputStream.
+     */
+    protected Object replaceObject(Object obj) throws IOException {
+        return obj;
+    }
+
+    /**
+     * Enable the stream to do replacement of objects in the stream.  When
+     * enabled, the replaceObject method is called for every object being
+     * serialized.
+     *
+     * <p>If <code>enable</code> is true, and there is a security manager
+     * installed, this method first calls the security manager's
+     * <code>checkPermission</code> method with a
+     * <code>SerializablePermission("enableSubstitution")</code> permission to
+     * ensure it's ok to enable the stream to do replacement of objects in the
+     * stream.
+     *
+     * @param   enable boolean parameter to enable replacement of objects
+     * @return  the previous setting before this method was invoked
+     * @throws  SecurityException if a security manager exists and its
+     *          <code>checkPermission</code> method denies enabling the stream
+     *          to do replacement of objects in the stream.
+     * @see SecurityManager#checkPermission
+     * @see java.io.SerializablePermission
+     */
+    protected boolean enableReplaceObject(boolean enable)
+        throws SecurityException
+    {
+        if (enable == enableReplace) {
+            return enable;
+        }
+        if (enable) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(SUBSTITUTION_PERMISSION);
+            }
+        }
+        enableReplace = enable;
+        return !enableReplace;
+    }
+
+    /**
+     * The writeStreamHeader method is provided so subclasses can append or
+     * prepend their own header to the stream.  It writes the magic number and
+     * version to the stream.
+     *
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    protected void writeStreamHeader() throws IOException {
+        bout.writeShort(STREAM_MAGIC);
+        bout.writeShort(STREAM_VERSION);
+    }
+
+    /**
+     * Write the specified class descriptor to the ObjectOutputStream.  Class
+     * descriptors are used to identify the classes of objects written to the
+     * stream.  Subclasses of ObjectOutputStream may override this method to
+     * customize the way in which class descriptors are written to the
+     * serialization stream.  The corresponding method in ObjectInputStream,
+     * <code>readClassDescriptor</code>, should then be overridden to
+     * reconstitute the class descriptor from its custom stream representation.
+     * By default, this method writes class descriptors according to the format
+     * defined in the Object Serialization specification.
+     *
+     * <p>Note that this method will only be called if the ObjectOutputStream
+     * is not using the old serialization stream format (set by calling
+     * ObjectOutputStream's <code>useProtocolVersion</code> method).  If this
+     * serialization stream is using the old format
+     * (<code>PROTOCOL_VERSION_1</code>), the class descriptor will be written
+     * internally in a manner that cannot be overridden or customized.
+     *
+     * @param   desc class descriptor to write to the stream
+     * @throws  IOException If an I/O error has occurred.
+     * @see java.io.ObjectInputStream#readClassDescriptor()
+     * @see #useProtocolVersion(int)
+     * @see java.io.ObjectStreamConstants#PROTOCOL_VERSION_1
+     * @since 1.3
+     */
+    protected void writeClassDescriptor(ObjectStreamClass desc)
+        throws IOException
+    {
+        desc.writeNonProxy(this);
+    }
+
+    /**
+     * Writes a byte. This method will block until the byte is actually
+     * written.
+     *
+     * @param   val the byte to be written to the stream
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public void write(int val) throws IOException {
+        bout.write(val);
+    }
+
+    /**
+     * Writes an array of bytes. This method will block until the bytes are
+     * actually written.
+     *
+     * @param   buf the data to be written
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public void write(byte[] buf) throws IOException {
+        bout.write(buf, 0, buf.length, false);
+    }
+
+    /**
+     * Writes a sub array of bytes.
+     *
+     * @param   buf the data to be written
+     * @param   off the start offset in the data
+     * @param   len the number of bytes that are written
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public void write(byte[] buf, int off, int len) throws IOException {
+        if (buf == null) {
+            throw new NullPointerException();
+        }
+        int endoff = off + len;
+        if (off < 0 || len < 0 || endoff > buf.length || endoff < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        bout.write(buf, off, len, false);
+    }
+
+    /**
+     * Flushes the stream. This will write any buffered output bytes and flush
+     * through to the underlying stream.
+     *
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public void flush() throws IOException {
+        bout.flush();
+    }
+
+    /**
+     * Drain any buffered data in ObjectOutputStream.  Similar to flush but
+     * does not propagate the flush to the underlying stream.
+     *
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    protected void drain() throws IOException {
+        bout.drain();
+    }
+
+    /**
+     * Closes the stream. This method must be called to release any resources
+     * associated with the stream.
+     *
+     * @throws  IOException If an I/O error has occurred.
+     */
+    public void close() throws IOException {
+        flush();
+        // Android-removed:  Don't clear() during close(), keep the handle table. http://b/28159133
+        // clear();
+        bout.close();
+    }
+
+    /**
+     * Writes a boolean.
+     *
+     * @param   val the boolean to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeBoolean(boolean val) throws IOException {
+        bout.writeBoolean(val);
+    }
+
+    /**
+     * Writes an 8 bit byte.
+     *
+     * @param   val the byte value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeByte(int val) throws IOException  {
+        bout.writeByte(val);
+    }
+
+    /**
+     * Writes a 16 bit short.
+     *
+     * @param   val the short value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeShort(int val)  throws IOException {
+        bout.writeShort(val);
+    }
+
+    /**
+     * Writes a 16 bit char.
+     *
+     * @param   val the char value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeChar(int val)  throws IOException {
+        bout.writeChar(val);
+    }
+
+    /**
+     * Writes a 32 bit int.
+     *
+     * @param   val the integer value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeInt(int val)  throws IOException {
+        bout.writeInt(val);
+    }
+
+    /**
+     * Writes a 64 bit long.
+     *
+     * @param   val the long value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeLong(long val)  throws IOException {
+        bout.writeLong(val);
+    }
+
+    /**
+     * Writes a 32 bit float.
+     *
+     * @param   val the float value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeFloat(float val) throws IOException {
+        bout.writeFloat(val);
+    }
+
+    /**
+     * Writes a 64 bit double.
+     *
+     * @param   val the double value to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeDouble(double val) throws IOException {
+        bout.writeDouble(val);
+    }
+
+    /**
+     * Writes a String as a sequence of bytes.
+     *
+     * @param   str the String of bytes to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeBytes(String str) throws IOException {
+        bout.writeBytes(str);
+    }
+
+    /**
+     * Writes a String as a sequence of chars.
+     *
+     * @param   str the String of chars to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeChars(String str) throws IOException {
+        bout.writeChars(str);
+    }
+
+    /**
+     * Primitive data write of this String in
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * format.  Note that there is a
+     * significant difference between writing a String into the stream as
+     * primitive data or as an Object. A String instance written by writeObject
+     * is written into the stream as a String initially. Future writeObject()
+     * calls write references to the string into the stream.
+     *
+     * @param   str the String to be written
+     * @throws  IOException if I/O errors occur while writing to the underlying
+     *          stream
+     */
+    public void writeUTF(String str) throws IOException {
+        bout.writeUTF(str);
+    }
+
+    /**
+     * Provide programmatic access to the persistent fields to be written
+     * to ObjectOutput.
+     *
+     * @since 1.2
+     */
+    public static abstract class PutField {
+
+        /**
+         * Put the value of the named boolean field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>boolean</code>
+         */
+        public abstract void put(String name, boolean val);
+
+        /**
+         * Put the value of the named byte field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>byte</code>
+         */
+        public abstract void put(String name, byte val);
+
+        /**
+         * Put the value of the named char field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>char</code>
+         */
+        public abstract void put(String name, char val);
+
+        /**
+         * Put the value of the named short field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>short</code>
+         */
+        public abstract void put(String name, short val);
+
+        /**
+         * Put the value of the named int field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>int</code>
+         */
+        public abstract void put(String name, int val);
+
+        /**
+         * Put the value of the named long field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>long</code>
+         */
+        public abstract void put(String name, long val);
+
+        /**
+         * Put the value of the named float field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>float</code>
+         */
+        public abstract void put(String name, float val);
+
+        /**
+         * Put the value of the named double field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not
+         * <code>double</code>
+         */
+        public abstract void put(String name, double val);
+
+        /**
+         * Put the value of the named Object field into the persistent field.
+         *
+         * @param  name the name of the serializable field
+         * @param  val the value to assign to the field
+         *         (which may be <code>null</code>)
+         * @throws IllegalArgumentException if <code>name</code> does not
+         * match the name of a serializable field for the class whose fields
+         * are being written, or if the type of the named field is not a
+         * reference type
+         */
+        public abstract void put(String name, Object val);
+
+        /**
+         * Write the data and fields to the specified ObjectOutput stream,
+         * which must be the same stream that produced this
+         * <code>PutField</code> object.
+         *
+         * @param  out the stream to write the data and fields to
+         * @throws IOException if I/O errors occur while writing to the
+         *         underlying stream
+         * @throws IllegalArgumentException if the specified stream is not
+         *         the same stream that produced this <code>PutField</code>
+         *         object
+         * @deprecated This method does not write the values contained by this
+         *         <code>PutField</code> object in a proper format, and may
+         *         result in corruption of the serialization stream.  The
+         *         correct way to write <code>PutField</code> data is by
+         *         calling the {@link java.io.ObjectOutputStream#writeFields()}
+         *         method.
+         */
+        @Deprecated
+        public abstract void write(ObjectOutput out) throws IOException;
+    }
+
+
+    /**
+     * Returns protocol version in use.
+     */
+    int getProtocolVersion() {
+        return protocol;
+    }
+
+    /**
+     * Writes string without allowing it to be replaced in stream.  Used by
+     * ObjectStreamClass to write class descriptor type strings.
+     */
+    void writeTypeString(String str) throws IOException {
+        int handle;
+        if (str == null) {
+            writeNull();
+        } else if ((handle = handles.lookup(str)) != -1) {
+            writeHandle(handle);
+        } else {
+            writeString(str, false);
+        }
+    }
+
+    /**
+     * Verifies that this (possibly subclass) instance can be constructed
+     * without violating security constraints: the subclass must not override
+     * security-sensitive non-final methods, or else the
+     * "enableSubclassImplementation" SerializablePermission is checked.
+     */
+    private void verifySubclass() {
+        Class<?> cl = getClass();
+        if (cl == ObjectOutputStream.class) {
+            return;
+        }
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            return;
+        }
+        processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
+        WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
+        Boolean result = Caches.subclassAudits.get(key);
+        if (result == null) {
+            result = Boolean.valueOf(auditSubclass(cl));
+            Caches.subclassAudits.putIfAbsent(key, result);
+        }
+        if (result.booleanValue()) {
+            return;
+        }
+        sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+    }
+
+    /**
+     * Performs reflective checks on given subclass to verify that it doesn't
+     * override security-sensitive non-final methods.  Returns true if subclass
+     * is "safe", false otherwise.
+     */
+    private static boolean auditSubclass(final Class<?> subcl) {
+        Boolean result = AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    for (Class<?> cl = subcl;
+                         cl != ObjectOutputStream.class;
+                         cl = cl.getSuperclass())
+                    {
+                        try {
+                            cl.getDeclaredMethod(
+                                "writeUnshared", new Class<?>[] { Object.class });
+                            return Boolean.FALSE;
+                        } catch (NoSuchMethodException ex) {
+                        }
+                        try {
+                            cl.getDeclaredMethod("putFields", (Class<?>[]) null);
+                            return Boolean.FALSE;
+                        } catch (NoSuchMethodException ex) {
+                        }
+                    }
+                    return Boolean.TRUE;
+                }
+            }
+        );
+        return result.booleanValue();
+    }
+
+    /**
+     * Clears internal data structures.
+     */
+    private void clear() {
+        subs.clear();
+        handles.clear();
+    }
+
+    /**
+     * Underlying writeObject/writeUnshared implementation.
+     */
+    private void writeObject0(Object obj, boolean unshared)
+        throws IOException
+    {
+        boolean oldMode = bout.setBlockDataMode(false);
+        depth++;
+        try {
+            // handle previously written and non-replaceable objects
+            int h;
+            if ((obj = subs.lookup(obj)) == null) {
+                writeNull();
+                return;
+            } else if (!unshared && (h = handles.lookup(obj)) != -1) {
+                writeHandle(h);
+                return;
+            // BEGIN Android-changed:  Make Class and ObjectStreamClass replaceable.
+            /*
+            } else if (obj instanceof Class) {
+                writeClass((Class) obj, unshared);
+                return;
+            } else if (obj instanceof ObjectStreamClass) {
+                writeClassDesc((ObjectStreamClass) obj, unshared);
+                return;
+            */
+            // END Android-changed:  Make Class and ObjectStreamClass replaceable.
+            }
+
+            // check for replacement object
+            Object orig = obj;
+            Class<?> cl = obj.getClass();
+            ObjectStreamClass desc;
+
+            // BEGIN Android-changed: Make only one call to writeReplace.
+            /*
+            for (;;) {
+                // REMIND: skip this check for strings/arrays?
+                Class<?> repCl;
+                desc = ObjectStreamClass.lookup(cl, true);
+                if (!desc.hasWriteReplaceMethod() ||
+                    (obj = desc.invokeWriteReplace(obj)) == null ||
+                    (repCl = obj.getClass()) == cl)
+                {
+                    break;
+                }
+                cl = repCl;
+                desc = ObjectStreamClass.lookup(cl, true);
+                break;
+            }
+            */
+            // Do only one replace pass
+
+            Class repCl;
+            desc = ObjectStreamClass.lookup(cl, true);
+            if (desc.hasWriteReplaceMethod() &&
+                (obj = desc.invokeWriteReplace(obj)) != null &&
+                (repCl = obj.getClass()) != cl)
+            {
+                cl = repCl;
+                desc = ObjectStreamClass.lookup(cl, true);
+            }
+            // END Android-changed: Make only one call to writeReplace.
+
+            if (enableReplace) {
+                Object rep = replaceObject(obj);
+                if (rep != obj && rep != null) {
+                    cl = rep.getClass();
+                    desc = ObjectStreamClass.lookup(cl, true);
+                }
+                obj = rep;
+            }
+
+            // if object replaced, run through original checks a second time
+            if (obj != orig) {
+                subs.assign(orig, obj);
+                if (obj == null) {
+                    writeNull();
+                    return;
+                } else if (!unshared && (h = handles.lookup(obj)) != -1) {
+                    writeHandle(h);
+                    return;
+// BEGIN Android-changed:  Make Class and ObjectStreamClass replaceable.
+/*
+                } else if (obj instanceof Class) {
+                    writeClass((Class) obj, unshared);
+                    return;
+                } else if (obj instanceof ObjectStreamClass) {
+                    writeClassDesc((ObjectStreamClass) obj, unshared);
+                    return;
+*/
+// END Android-changed:  Make Class and ObjectStreamClass replaceable.
+                }
+            }
+
+            // remaining cases
+            // BEGIN Android-changed: Make Class and ObjectStreamClass replaceable.
+            if (obj instanceof Class) {
+                writeClass((Class) obj, unshared);
+            } else if (obj instanceof ObjectStreamClass) {
+                writeClassDesc((ObjectStreamClass) obj, unshared);
+            // END Android-changed:  Make Class and ObjectStreamClass replaceable.
+            } else if (obj instanceof String) {
+                writeString((String) obj, unshared);
+            } else if (cl.isArray()) {
+                writeArray(obj, desc, unshared);
+            } else if (obj instanceof Enum) {
+                writeEnum((Enum<?>) obj, desc, unshared);
+            } else if (obj instanceof Serializable) {
+                writeOrdinaryObject(obj, desc, unshared);
+            } else {
+                if (extendedDebugInfo) {
+                    throw new NotSerializableException(
+                        cl.getName() + "\n" + debugInfoStack.toString());
+                } else {
+                    throw new NotSerializableException(cl.getName());
+                }
+            }
+        } finally {
+            depth--;
+            bout.setBlockDataMode(oldMode);
+        }
+    }
+
+    /**
+     * Writes null code to stream.
+     */
+    private void writeNull() throws IOException {
+        bout.writeByte(TC_NULL);
+    }
+
+    /**
+     * Writes given object handle to stream.
+     */
+    private void writeHandle(int handle) throws IOException {
+        bout.writeByte(TC_REFERENCE);
+        bout.writeInt(baseWireHandle + handle);
+    }
+
+    /**
+     * Writes representation of given class to stream.
+     */
+    private void writeClass(Class<?> cl, boolean unshared) throws IOException {
+        bout.writeByte(TC_CLASS);
+        writeClassDesc(ObjectStreamClass.lookup(cl, true), false);
+        handles.assign(unshared ? null : cl);
+    }
+
+    /**
+     * Writes representation of given class descriptor to stream.
+     */
+    private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
+        throws IOException
+    {
+        int handle;
+        if (desc == null) {
+            writeNull();
+        } else if (!unshared && (handle = handles.lookup(desc)) != -1) {
+            writeHandle(handle);
+        } else if (desc.isProxy()) {
+            writeProxyDesc(desc, unshared);
+        } else {
+            writeNonProxyDesc(desc, unshared);
+        }
+    }
+
+    private boolean isCustomSubclass() {
+        // Return true if this class is a custom subclass of ObjectOutputStream
+        return getClass().getClassLoader()
+                   != ObjectOutputStream.class.getClassLoader();
+    }
+
+    /**
+     * Writes class descriptor representing a dynamic proxy class to stream.
+     */
+    private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
+        throws IOException
+    {
+        bout.writeByte(TC_PROXYCLASSDESC);
+        handles.assign(unshared ? null : desc);
+
+        Class<?> cl = desc.forClass();
+        Class<?>[] ifaces = cl.getInterfaces();
+        bout.writeInt(ifaces.length);
+        for (int i = 0; i < ifaces.length; i++) {
+            bout.writeUTF(ifaces[i].getName());
+        }
+
+        bout.setBlockDataMode(true);
+        if (cl != null && isCustomSubclass()) {
+            ReflectUtil.checkPackageAccess(cl);
+        }
+        annotateProxyClass(cl);
+        bout.setBlockDataMode(false);
+        bout.writeByte(TC_ENDBLOCKDATA);
+
+        writeClassDesc(desc.getSuperDesc(), false);
+    }
+
+    /**
+     * Writes class descriptor representing a standard (i.e., not a dynamic
+     * proxy) class to stream.
+     */
+    private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
+        throws IOException
+    {
+        bout.writeByte(TC_CLASSDESC);
+        handles.assign(unshared ? null : desc);
+
+        if (protocol == PROTOCOL_VERSION_1) {
+            // do not invoke class descriptor write hook with old protocol
+            desc.writeNonProxy(this);
+        } else {
+            writeClassDescriptor(desc);
+        }
+
+        Class<?> cl = desc.forClass();
+        bout.setBlockDataMode(true);
+        if (cl != null && isCustomSubclass()) {
+            ReflectUtil.checkPackageAccess(cl);
+        }
+        annotateClass(cl);
+        bout.setBlockDataMode(false);
+        bout.writeByte(TC_ENDBLOCKDATA);
+
+        writeClassDesc(desc.getSuperDesc(), false);
+    }
+
+    /**
+     * Writes given string to stream, using standard or long UTF format
+     * depending on string length.
+     */
+    private void writeString(String str, boolean unshared) throws IOException {
+        handles.assign(unshared ? null : str);
+        long utflen = bout.getUTFLength(str);
+        if (utflen <= 0xFFFF) {
+            bout.writeByte(TC_STRING);
+            bout.writeUTF(str, utflen);
+        } else {
+            bout.writeByte(TC_LONGSTRING);
+            bout.writeLongUTF(str, utflen);
+        }
+    }
+
+    /**
+     * Writes given array object to stream.
+     */
+    private void writeArray(Object array,
+                            ObjectStreamClass desc,
+                            boolean unshared)
+        throws IOException
+    {
+        bout.writeByte(TC_ARRAY);
+        writeClassDesc(desc, false);
+        handles.assign(unshared ? null : array);
+
+        Class<?> ccl = desc.forClass().getComponentType();
+        if (ccl.isPrimitive()) {
+            if (ccl == Integer.TYPE) {
+                int[] ia = (int[]) array;
+                bout.writeInt(ia.length);
+                bout.writeInts(ia, 0, ia.length);
+            } else if (ccl == Byte.TYPE) {
+                byte[] ba = (byte[]) array;
+                bout.writeInt(ba.length);
+                bout.write(ba, 0, ba.length, true);
+            } else if (ccl == Long.TYPE) {
+                long[] ja = (long[]) array;
+                bout.writeInt(ja.length);
+                bout.writeLongs(ja, 0, ja.length);
+            } else if (ccl == Float.TYPE) {
+                float[] fa = (float[]) array;
+                bout.writeInt(fa.length);
+                bout.writeFloats(fa, 0, fa.length);
+            } else if (ccl == Double.TYPE) {
+                double[] da = (double[]) array;
+                bout.writeInt(da.length);
+                bout.writeDoubles(da, 0, da.length);
+            } else if (ccl == Short.TYPE) {
+                short[] sa = (short[]) array;
+                bout.writeInt(sa.length);
+                bout.writeShorts(sa, 0, sa.length);
+            } else if (ccl == Character.TYPE) {
+                char[] ca = (char[]) array;
+                bout.writeInt(ca.length);
+                bout.writeChars(ca, 0, ca.length);
+            } else if (ccl == Boolean.TYPE) {
+                boolean[] za = (boolean[]) array;
+                bout.writeInt(za.length);
+                bout.writeBooleans(za, 0, za.length);
+            } else {
+                throw new InternalError();
+            }
+        } else {
+            Object[] objs = (Object[]) array;
+            int len = objs.length;
+            bout.writeInt(len);
+            if (extendedDebugInfo) {
+                debugInfoStack.push(
+                    "array (class \"" + array.getClass().getName() +
+                    "\", size: " + len  + ")");
+            }
+            try {
+                for (int i = 0; i < len; i++) {
+                    if (extendedDebugInfo) {
+                        debugInfoStack.push(
+                            "element of array (index: " + i + ")");
+                    }
+                    try {
+                        writeObject0(objs[i], false);
+                    } finally {
+                        if (extendedDebugInfo) {
+                            debugInfoStack.pop();
+                        }
+                    }
+                }
+            } finally {
+                if (extendedDebugInfo) {
+                    debugInfoStack.pop();
+                }
+            }
+        }
+    }
+
+    /**
+     * Writes given enum constant to stream.
+     */
+    private void writeEnum(Enum<?> en,
+                           ObjectStreamClass desc,
+                           boolean unshared)
+        throws IOException
+    {
+        bout.writeByte(TC_ENUM);
+        ObjectStreamClass sdesc = desc.getSuperDesc();
+        writeClassDesc((sdesc.forClass() == Enum.class) ? desc : sdesc, false);
+        handles.assign(unshared ? null : en);
+        writeString(en.name(), false);
+    }
+
+    /**
+     * Writes representation of a "ordinary" (i.e., not a String, Class,
+     * ObjectStreamClass, array, or enum constant) serializable object to the
+     * stream.
+     */
+    private void writeOrdinaryObject(Object obj,
+                                     ObjectStreamClass desc,
+                                     boolean unshared)
+        throws IOException
+    {
+        if (extendedDebugInfo) {
+            debugInfoStack.push(
+                (depth == 1 ? "root " : "") + "object (class \"" +
+                obj.getClass().getName() + "\", " + obj.toString() + ")");
+        }
+        try {
+            desc.checkSerialize();
+
+            bout.writeByte(TC_OBJECT);
+            writeClassDesc(desc, false);
+            handles.assign(unshared ? null : obj);
+            if (desc.isExternalizable() && !desc.isProxy()) {
+                writeExternalData((Externalizable) obj);
+            } else {
+                writeSerialData(obj, desc);
+            }
+        } finally {
+            if (extendedDebugInfo) {
+                debugInfoStack.pop();
+            }
+        }
+    }
+
+    /**
+     * Writes externalizable data of given object by invoking its
+     * writeExternal() method.
+     */
+    private void writeExternalData(Externalizable obj) throws IOException {
+        PutFieldImpl oldPut = curPut;
+        curPut = null;
+
+        if (extendedDebugInfo) {
+            debugInfoStack.push("writeExternal data");
+        }
+        SerialCallbackContext oldContext = curContext;
+        try {
+            curContext = null;
+            if (protocol == PROTOCOL_VERSION_1) {
+                obj.writeExternal(this);
+            } else {
+                bout.setBlockDataMode(true);
+                obj.writeExternal(this);
+                bout.setBlockDataMode(false);
+                bout.writeByte(TC_ENDBLOCKDATA);
+            }
+        } finally {
+            curContext = oldContext;
+            if (extendedDebugInfo) {
+                debugInfoStack.pop();
+            }
+        }
+
+        curPut = oldPut;
+    }
+
+    /**
+     * Writes instance data for each serializable class of given object, from
+     * superclass to subclass.
+     */
+    private void writeSerialData(Object obj, ObjectStreamClass desc)
+        throws IOException
+    {
+        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+        for (int i = 0; i < slots.length; i++) {
+            ObjectStreamClass slotDesc = slots[i].desc;
+            if (slotDesc.hasWriteObjectMethod()) {
+                PutFieldImpl oldPut = curPut;
+                curPut = null;
+                SerialCallbackContext oldContext = curContext;
+
+                if (extendedDebugInfo) {
+                    debugInfoStack.push(
+                        "custom writeObject data (class \"" +
+                        slotDesc.getName() + "\")");
+                }
+                try {
+                    curContext = new SerialCallbackContext(obj, slotDesc);
+                    bout.setBlockDataMode(true);
+                    slotDesc.invokeWriteObject(obj, this);
+                    bout.setBlockDataMode(false);
+                    bout.writeByte(TC_ENDBLOCKDATA);
+                } finally {
+                    curContext.setUsed();
+                    curContext = oldContext;
+                    if (extendedDebugInfo) {
+                        debugInfoStack.pop();
+                    }
+                }
+
+                curPut = oldPut;
+            } else {
+                defaultWriteFields(obj, slotDesc);
+            }
+        }
+    }
+
+    /**
+     * Fetches and writes values of serializable fields of given object to
+     * stream.  The given class descriptor specifies which field values to
+     * write, and in which order they should be written.
+     */
+    private void defaultWriteFields(Object obj, ObjectStreamClass desc)
+        throws IOException
+    {
+        Class<?> cl = desc.forClass();
+        if (cl != null && obj != null && !cl.isInstance(obj)) {
+            throw new ClassCastException();
+        }
+
+        desc.checkDefaultSerialize();
+
+        int primDataSize = desc.getPrimDataSize();
+        if (primVals == null || primVals.length < primDataSize) {
+            primVals = new byte[primDataSize];
+        }
+        desc.getPrimFieldValues(obj, primVals);
+        bout.write(primVals, 0, primDataSize, false);
+
+        ObjectStreamField[] fields = desc.getFields(false);
+        Object[] objVals = new Object[desc.getNumObjFields()];
+        int numPrimFields = fields.length - objVals.length;
+        desc.getObjFieldValues(obj, objVals);
+        for (int i = 0; i < objVals.length; i++) {
+            if (extendedDebugInfo) {
+                debugInfoStack.push(
+                    "field (class \"" + desc.getName() + "\", name: \"" +
+                    fields[numPrimFields + i].getName() + "\", type: \"" +
+                    fields[numPrimFields + i].getType() + "\")");
+            }
+            try {
+                writeObject0(objVals[i],
+                             fields[numPrimFields + i].isUnshared());
+            } finally {
+                if (extendedDebugInfo) {
+                    debugInfoStack.pop();
+                }
+            }
+        }
+    }
+
+    /**
+     * Attempts to write to stream fatal IOException that has caused
+     * serialization to abort.
+     */
+    private void writeFatalException(IOException ex) throws IOException {
+        /*
+         * Note: the serialization specification states that if a second
+         * IOException occurs while attempting to serialize the original fatal
+         * exception to the stream, then a StreamCorruptedException should be
+         * thrown (section 2.1).  However, due to a bug in previous
+         * implementations of serialization, StreamCorruptedExceptions were
+         * rarely (if ever) actually thrown--the "root" exceptions from
+         * underlying streams were thrown instead.  This historical behavior is
+         * followed here for consistency.
+         */
+        clear();
+        boolean oldMode = bout.setBlockDataMode(false);
+        try {
+            bout.writeByte(TC_EXCEPTION);
+            writeObject0(ex, false);
+            clear();
+        } finally {
+            bout.setBlockDataMode(oldMode);
+        }
+    }
+
+    /**
+     * Converts specified span of float values into byte values.
+     */
+    // REMIND: remove once hotspot inlines Float.floatToIntBits
+    private static native void floatsToBytes(float[] src, int srcpos,
+                                             byte[] dst, int dstpos,
+                                             int nfloats);
+
+    /**
+     * Converts specified span of double values into byte values.
+     */
+    // REMIND: remove once hotspot inlines Double.doubleToLongBits
+    private static native void doublesToBytes(double[] src, int srcpos,
+                                              byte[] dst, int dstpos,
+                                              int ndoubles);
+
+    /**
+     * Default PutField implementation.
+     */
+    private class PutFieldImpl extends PutField {
+
+        /** class descriptor describing serializable fields */
+        private final ObjectStreamClass desc;
+        /** primitive field values */
+        private final byte[] primVals;
+        /** object field values */
+        private final Object[] objVals;
+
+        /**
+         * Creates PutFieldImpl object for writing fields defined in given
+         * class descriptor.
+         */
+        PutFieldImpl(ObjectStreamClass desc) {
+            this.desc = desc;
+            primVals = new byte[desc.getPrimDataSize()];
+            objVals = new Object[desc.getNumObjFields()];
+        }
+
+        public void put(String name, boolean val) {
+            Bits.putBoolean(primVals, getFieldOffset(name, Boolean.TYPE), val);
+        }
+
+        public void put(String name, byte val) {
+            primVals[getFieldOffset(name, Byte.TYPE)] = val;
+        }
+
+        public void put(String name, char val) {
+            Bits.putChar(primVals, getFieldOffset(name, Character.TYPE), val);
+        }
+
+        public void put(String name, short val) {
+            Bits.putShort(primVals, getFieldOffset(name, Short.TYPE), val);
+        }
+
+        public void put(String name, int val) {
+            Bits.putInt(primVals, getFieldOffset(name, Integer.TYPE), val);
+        }
+
+        public void put(String name, float val) {
+            Bits.putFloat(primVals, getFieldOffset(name, Float.TYPE), val);
+        }
+
+        public void put(String name, long val) {
+            Bits.putLong(primVals, getFieldOffset(name, Long.TYPE), val);
+        }
+
+        public void put(String name, double val) {
+            Bits.putDouble(primVals, getFieldOffset(name, Double.TYPE), val);
+        }
+
+        public void put(String name, Object val) {
+            objVals[getFieldOffset(name, Object.class)] = val;
+        }
+
+        // deprecated in ObjectOutputStream.PutField
+        public void write(ObjectOutput out) throws IOException {
+            /*
+             * Applications should *not* use this method to write PutField
+             * data, as it will lead to stream corruption if the PutField
+             * object writes any primitive data (since block data mode is not
+             * unset/set properly, as is done in OOS.writeFields()).  This
+             * broken implementation is being retained solely for behavioral
+             * compatibility, in order to support applications which use
+             * OOS.PutField.write() for writing only non-primitive data.
+             *
+             * Serialization of unshared objects is not implemented here since
+             * it is not necessary for backwards compatibility; also, unshared
+             * semantics may not be supported by the given ObjectOutput
+             * instance.  Applications which write unshared objects using the
+             * PutField API must use OOS.writeFields().
+             */
+            if (ObjectOutputStream.this != out) {
+                throw new IllegalArgumentException("wrong stream");
+            }
+            out.write(primVals, 0, primVals.length);
+
+            ObjectStreamField[] fields = desc.getFields(false);
+            int numPrimFields = fields.length - objVals.length;
+            // REMIND: warn if numPrimFields > 0?
+            for (int i = 0; i < objVals.length; i++) {
+                if (fields[numPrimFields + i].isUnshared()) {
+                    throw new IOException("cannot write unshared object");
+                }
+                out.writeObject(objVals[i]);
+            }
+        }
+
+        /**
+         * Writes buffered primitive data and object fields to stream.
+         */
+        void writeFields() throws IOException {
+            bout.write(primVals, 0, primVals.length, false);
+
+            ObjectStreamField[] fields = desc.getFields(false);
+            int numPrimFields = fields.length - objVals.length;
+            for (int i = 0; i < objVals.length; i++) {
+                if (extendedDebugInfo) {
+                    debugInfoStack.push(
+                        "field (class \"" + desc.getName() + "\", name: \"" +
+                        fields[numPrimFields + i].getName() + "\", type: \"" +
+                        fields[numPrimFields + i].getType() + "\")");
+                }
+                try {
+                    writeObject0(objVals[i],
+                                 fields[numPrimFields + i].isUnshared());
+                } finally {
+                    if (extendedDebugInfo) {
+                        debugInfoStack.pop();
+                    }
+                }
+            }
+        }
+
+        /**
+         * Returns offset of field with given name and type.  A specified type
+         * of null matches all types, Object.class matches all non-primitive
+         * types, and any other non-null type matches assignable types only.
+         * Throws IllegalArgumentException if no matching field found.
+         */
+        private int getFieldOffset(String name, Class<?> type) {
+            ObjectStreamField field = desc.getField(name, type);
+            if (field == null) {
+                throw new IllegalArgumentException("no such field " + name +
+                                                   " with type " + type);
+            }
+            return field.getOffset();
+        }
+    }
+
+    /**
+     * Buffered output stream with two modes: in default mode, outputs data in
+     * same format as DataOutputStream; in "block data" mode, outputs data
+     * bracketed by block data markers (see object serialization specification
+     * for details).
+     */
+    private static class BlockDataOutputStream
+        extends OutputStream implements DataOutput
+    {
+        /** maximum data block length */
+        private static final int MAX_BLOCK_SIZE = 1024;
+        /** maximum data block header length */
+        private static final int MAX_HEADER_SIZE = 5;
+        /** (tunable) length of char buffer (for writing strings) */
+        private static final int CHAR_BUF_SIZE = 256;
+
+        /** buffer for writing general/block data */
+        private final byte[] buf = new byte[MAX_BLOCK_SIZE];
+        /** buffer for writing block data headers */
+        private final byte[] hbuf = new byte[MAX_HEADER_SIZE];
+        /** char buffer for fast string writes */
+        private final char[] cbuf = new char[CHAR_BUF_SIZE];
+
+        /** block data mode */
+        private boolean blkmode = false;
+        /** current offset into buf */
+        private int pos = 0;
+
+        /** underlying output stream */
+        private final OutputStream out;
+        /** loopback stream (for data writes that span data blocks) */
+        private final DataOutputStream dout;
+
+        // BEGIN Android-added: Warning if writing to a closed ObjectOutputStream.
+        /**
+         * Indicates that this stream was closed and that a warning must be logged once if an
+         * attempt is made to write to it and the underlying stream does not throw an exception.
+         *
+         * <p>This will be set back to false when a warning is logged to ensure that the log is not
+         * flooded with warnings.
+         *
+         * http://b/28159133
+         */
+        private boolean warnOnceWhenWriting;
+        // END Android-added: Warning if writing to a closed ObjectOutputStream.
+
+        /**
+         * Creates new BlockDataOutputStream on top of given underlying stream.
+         * Block data mode is turned off by default.
+         */
+        BlockDataOutputStream(OutputStream out) {
+            this.out = out;
+            dout = new DataOutputStream(this);
+        }
+
+        /**
+         * Sets block data mode to the given mode (true == on, false == off)
+         * and returns the previous mode value.  If the new mode is the same as
+         * the old mode, no action is taken.  If the new mode differs from the
+         * old mode, any buffered data is flushed before switching to the new
+         * mode.
+         */
+        boolean setBlockDataMode(boolean mode) throws IOException {
+            if (blkmode == mode) {
+                return blkmode;
+            }
+            drain();
+            blkmode = mode;
+            return !blkmode;
+        }
+
+        /**
+         * Returns true if the stream is currently in block data mode, false
+         * otherwise.
+         */
+        boolean getBlockDataMode() {
+            return blkmode;
+        }
+
+        // BEGIN Android-added: Warning about writing to closed ObjectOutputStream
+        /**
+         * Warns if the stream has been closed.
+         *
+         * <p>This is called after data has been written to the underlying stream in order to allow
+         * the underlying stream to detect and fail if an attempt is made to write to a closed
+         * stream. That ensures that this will only log a warning if the underlying stream does not
+         * so it will not log unnecessary warnings.
+         */
+        private void warnIfClosed() {
+            if (warnOnceWhenWriting) {
+                System.logW("The app is relying on undefined behavior. Attempting to write to a"
+                        + " closed ObjectOutputStream could produce corrupt output in a future"
+                        + " release of Android.", new IOException("Stream Closed"));
+                // Set back to false so no more messages are logged unless the stream is closed
+                // again.
+                warnOnceWhenWriting = false;
+            }
+        }
+        // END Android-added: Warning about writing to closed ObjectOutputStream
+
+        /* ----------------- generic output stream methods ----------------- */
+        /*
+         * The following methods are equivalent to their counterparts in
+         * OutputStream, except that they partition written data into data
+         * blocks when in block data mode.
+         */
+
+        public void write(int b) throws IOException {
+            if (pos >= MAX_BLOCK_SIZE) {
+                drain();
+            }
+            buf[pos++] = (byte) b;
+        }
+
+        public void write(byte[] b) throws IOException {
+            write(b, 0, b.length, false);
+        }
+
+        public void write(byte[] b, int off, int len) throws IOException {
+            write(b, off, len, false);
+        }
+
+        public void flush() throws IOException {
+            drain();
+            out.flush();
+        }
+
+        public void close() throws IOException {
+            flush();
+            out.close();
+            // Android-added: Warning about writing to closed ObjectOutputStream
+            warnOnceWhenWriting = true;
+        }
+
+        /**
+         * Writes specified span of byte values from given array.  If copy is
+         * true, copies the values to an intermediate buffer before writing
+         * them to underlying stream (to avoid exposing a reference to the
+         * original byte array).
+         */
+        void write(byte[] b, int off, int len, boolean copy)
+            throws IOException
+        {
+            if (!(copy || blkmode)) {           // write directly
+                drain();
+                out.write(b, off, len);
+                // Android-added: Warning about writing to closed ObjectOutputStream
+                warnIfClosed();
+                return;
+            }
+
+            while (len > 0) {
+                if (pos >= MAX_BLOCK_SIZE) {
+                    drain();
+                }
+                if (len >= MAX_BLOCK_SIZE && !copy && pos == 0) {
+                    // avoid unnecessary copy
+                    writeBlockHeader(MAX_BLOCK_SIZE);
+                    out.write(b, off, MAX_BLOCK_SIZE);
+                    off += MAX_BLOCK_SIZE;
+                    len -= MAX_BLOCK_SIZE;
+                } else {
+                    int wlen = Math.min(len, MAX_BLOCK_SIZE - pos);
+                    System.arraycopy(b, off, buf, pos, wlen);
+                    pos += wlen;
+                    off += wlen;
+                    len -= wlen;
+                }
+            }
+            // Android-added: Warning about writing to closed ObjectOutputStream
+            warnIfClosed();
+        }
+
+        /**
+         * Writes all buffered data from this stream to the underlying stream,
+         * but does not flush underlying stream.
+         */
+        void drain() throws IOException {
+            if (pos == 0) {
+                return;
+            }
+            if (blkmode) {
+                writeBlockHeader(pos);
+            }
+            out.write(buf, 0, pos);
+            pos = 0;
+            // Android-added: Warning about writing to closed ObjectOutputStream
+            warnIfClosed();
+        }
+
+        /**
+         * Writes block data header.  Data blocks shorter than 256 bytes are
+         * prefixed with a 2-byte header; all others start with a 5-byte
+         * header.
+         */
+        private void writeBlockHeader(int len) throws IOException {
+            if (len <= 0xFF) {
+                hbuf[0] = TC_BLOCKDATA;
+                hbuf[1] = (byte) len;
+                out.write(hbuf, 0, 2);
+            } else {
+                hbuf[0] = TC_BLOCKDATALONG;
+                Bits.putInt(hbuf, 1, len);
+                out.write(hbuf, 0, 5);
+            }
+            // Android-added: Warning about writing to closed ObjectOutputStream
+            warnIfClosed();
+        }
+
+
+        /* ----------------- primitive data output methods ----------------- */
+        /*
+         * The following methods are equivalent to their counterparts in
+         * DataOutputStream, except that they partition written data into data
+         * blocks when in block data mode.
+         */
+
+        public void writeBoolean(boolean v) throws IOException {
+            if (pos >= MAX_BLOCK_SIZE) {
+                drain();
+            }
+            Bits.putBoolean(buf, pos++, v);
+        }
+
+        public void writeByte(int v) throws IOException {
+            if (pos >= MAX_BLOCK_SIZE) {
+                drain();
+            }
+            buf[pos++] = (byte) v;
+        }
+
+        public void writeChar(int v) throws IOException {
+            if (pos + 2 <= MAX_BLOCK_SIZE) {
+                Bits.putChar(buf, pos, (char) v);
+                pos += 2;
+            } else {
+                dout.writeChar(v);
+            }
+        }
+
+        public void writeShort(int v) throws IOException {
+            if (pos + 2 <= MAX_BLOCK_SIZE) {
+                Bits.putShort(buf, pos, (short) v);
+                pos += 2;
+            } else {
+                dout.writeShort(v);
+            }
+        }
+
+        public void writeInt(int v) throws IOException {
+            if (pos + 4 <= MAX_BLOCK_SIZE) {
+                Bits.putInt(buf, pos, v);
+                pos += 4;
+            } else {
+                dout.writeInt(v);
+            }
+        }
+
+        public void writeFloat(float v) throws IOException {
+            if (pos + 4 <= MAX_BLOCK_SIZE) {
+                Bits.putFloat(buf, pos, v);
+                pos += 4;
+            } else {
+                dout.writeFloat(v);
+            }
+        }
+
+        public void writeLong(long v) throws IOException {
+            if (pos + 8 <= MAX_BLOCK_SIZE) {
+                Bits.putLong(buf, pos, v);
+                pos += 8;
+            } else {
+                dout.writeLong(v);
+            }
+        }
+
+        public void writeDouble(double v) throws IOException {
+            if (pos + 8 <= MAX_BLOCK_SIZE) {
+                Bits.putDouble(buf, pos, v);
+                pos += 8;
+            } else {
+                dout.writeDouble(v);
+            }
+        }
+
+        public void writeBytes(String s) throws IOException {
+            int endoff = s.length();
+            int cpos = 0;
+            int csize = 0;
+            for (int off = 0; off < endoff; ) {
+                if (cpos >= csize) {
+                    cpos = 0;
+                    csize = Math.min(endoff - off, CHAR_BUF_SIZE);
+                    s.getChars(off, off + csize, cbuf, 0);
+                }
+                if (pos >= MAX_BLOCK_SIZE) {
+                    drain();
+                }
+                int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos);
+                int stop = pos + n;
+                while (pos < stop) {
+                    buf[pos++] = (byte) cbuf[cpos++];
+                }
+                off += n;
+            }
+        }
+
+        public void writeChars(String s) throws IOException {
+            int endoff = s.length();
+            for (int off = 0; off < endoff; ) {
+                int csize = Math.min(endoff - off, CHAR_BUF_SIZE);
+                s.getChars(off, off + csize, cbuf, 0);
+                writeChars(cbuf, 0, csize);
+                off += csize;
+            }
+        }
+
+        public void writeUTF(String s) throws IOException {
+            writeUTF(s, getUTFLength(s));
+        }
+
+
+        /* -------------- primitive data array output methods -------------- */
+        /*
+         * The following methods write out spans of primitive data values.
+         * Though equivalent to calling the corresponding primitive write
+         * methods repeatedly, these methods are optimized for writing groups
+         * of primitive data values more efficiently.
+         */
+
+        void writeBooleans(boolean[] v, int off, int len) throws IOException {
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos >= MAX_BLOCK_SIZE) {
+                    drain();
+                }
+                int stop = Math.min(endoff, off + (MAX_BLOCK_SIZE - pos));
+                while (off < stop) {
+                    Bits.putBoolean(buf, pos++, v[off++]);
+                }
+            }
+        }
+
+        void writeChars(char[] v, int off, int len) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 2;
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos <= limit) {
+                    int avail = (MAX_BLOCK_SIZE - pos) >> 1;
+                    int stop = Math.min(endoff, off + avail);
+                    while (off < stop) {
+                        Bits.putChar(buf, pos, v[off++]);
+                        pos += 2;
+                    }
+                } else {
+                    dout.writeChar(v[off++]);
+                }
+            }
+        }
+
+        void writeShorts(short[] v, int off, int len) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 2;
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos <= limit) {
+                    int avail = (MAX_BLOCK_SIZE - pos) >> 1;
+                    int stop = Math.min(endoff, off + avail);
+                    while (off < stop) {
+                        Bits.putShort(buf, pos, v[off++]);
+                        pos += 2;
+                    }
+                } else {
+                    dout.writeShort(v[off++]);
+                }
+            }
+        }
+
+        void writeInts(int[] v, int off, int len) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 4;
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos <= limit) {
+                    int avail = (MAX_BLOCK_SIZE - pos) >> 2;
+                    int stop = Math.min(endoff, off + avail);
+                    while (off < stop) {
+                        Bits.putInt(buf, pos, v[off++]);
+                        pos += 4;
+                    }
+                } else {
+                    dout.writeInt(v[off++]);
+                }
+            }
+        }
+
+        void writeFloats(float[] v, int off, int len) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 4;
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos <= limit) {
+                    int avail = (MAX_BLOCK_SIZE - pos) >> 2;
+                    int chunklen = Math.min(endoff - off, avail);
+                    floatsToBytes(v, off, buf, pos, chunklen);
+                    off += chunklen;
+                    pos += chunklen << 2;
+                } else {
+                    dout.writeFloat(v[off++]);
+                }
+            }
+        }
+
+        void writeLongs(long[] v, int off, int len) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 8;
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos <= limit) {
+                    int avail = (MAX_BLOCK_SIZE - pos) >> 3;
+                    int stop = Math.min(endoff, off + avail);
+                    while (off < stop) {
+                        Bits.putLong(buf, pos, v[off++]);
+                        pos += 8;
+                    }
+                } else {
+                    dout.writeLong(v[off++]);
+                }
+            }
+        }
+
+        void writeDoubles(double[] v, int off, int len) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 8;
+            int endoff = off + len;
+            while (off < endoff) {
+                if (pos <= limit) {
+                    int avail = (MAX_BLOCK_SIZE - pos) >> 3;
+                    int chunklen = Math.min(endoff - off, avail);
+                    doublesToBytes(v, off, buf, pos, chunklen);
+                    off += chunklen;
+                    pos += chunklen << 3;
+                } else {
+                    dout.writeDouble(v[off++]);
+                }
+            }
+        }
+
+        /**
+         * Returns the length in bytes of the UTF encoding of the given string.
+         */
+        long getUTFLength(String s) {
+            int len = s.length();
+            long utflen = 0;
+            for (int off = 0; off < len; ) {
+                int csize = Math.min(len - off, CHAR_BUF_SIZE);
+                s.getChars(off, off + csize, cbuf, 0);
+                for (int cpos = 0; cpos < csize; cpos++) {
+                    char c = cbuf[cpos];
+                    if (c >= 0x0001 && c <= 0x007F) {
+                        utflen++;
+                    } else if (c > 0x07FF) {
+                        utflen += 3;
+                    } else {
+                        utflen += 2;
+                    }
+                }
+                off += csize;
+            }
+            return utflen;
+        }
+
+        /**
+         * Writes the given string in UTF format.  This method is used in
+         * situations where the UTF encoding length of the string is already
+         * known; specifying it explicitly avoids a prescan of the string to
+         * determine its UTF length.
+         */
+        void writeUTF(String s, long utflen) throws IOException {
+            if (utflen > 0xFFFFL) {
+                throw new UTFDataFormatException();
+            }
+            writeShort((int) utflen);
+            if (utflen == (long) s.length()) {
+                writeBytes(s);
+            } else {
+                writeUTFBody(s);
+            }
+        }
+
+        /**
+         * Writes given string in "long" UTF format.  "Long" UTF format is
+         * identical to standard UTF, except that it uses an 8 byte header
+         * (instead of the standard 2 bytes) to convey the UTF encoding length.
+         */
+        void writeLongUTF(String s) throws IOException {
+            writeLongUTF(s, getUTFLength(s));
+        }
+
+        /**
+         * Writes given string in "long" UTF format, where the UTF encoding
+         * length of the string is already known.
+         */
+        void writeLongUTF(String s, long utflen) throws IOException {
+            writeLong(utflen);
+            if (utflen == (long) s.length()) {
+                writeBytes(s);
+            } else {
+                writeUTFBody(s);
+            }
+        }
+
+        /**
+         * Writes the "body" (i.e., the UTF representation minus the 2-byte or
+         * 8-byte length header) of the UTF encoding for the given string.
+         */
+        private void writeUTFBody(String s) throws IOException {
+            int limit = MAX_BLOCK_SIZE - 3;
+            int len = s.length();
+            for (int off = 0; off < len; ) {
+                int csize = Math.min(len - off, CHAR_BUF_SIZE);
+                s.getChars(off, off + csize, cbuf, 0);
+                for (int cpos = 0; cpos < csize; cpos++) {
+                    char c = cbuf[cpos];
+                    if (pos <= limit) {
+                        if (c <= 0x007F && c != 0) {
+                            buf[pos++] = (byte) c;
+                        } else if (c > 0x07FF) {
+                            buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F));
+                            buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F));
+                            buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F));
+                            pos += 3;
+                        } else {
+                            buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F));
+                            buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F));
+                            pos += 2;
+                        }
+                    } else {    // write one byte at a time to normalize block
+                        if (c <= 0x007F && c != 0) {
+                            write(c);
+                        } else if (c > 0x07FF) {
+                            write(0xE0 | ((c >> 12) & 0x0F));
+                            write(0x80 | ((c >> 6) & 0x3F));
+                            write(0x80 | ((c >> 0) & 0x3F));
+                        } else {
+                            write(0xC0 | ((c >> 6) & 0x1F));
+                            write(0x80 | ((c >> 0) & 0x3F));
+                        }
+                    }
+                }
+                off += csize;
+            }
+        }
+    }
+
+    /**
+     * Lightweight identity hash table which maps objects to integer handles,
+     * assigned in ascending order.
+     */
+    private static class HandleTable {
+
+        /* number of mappings in table/next available handle */
+        private int size;
+        /* size threshold determining when to expand hash spine */
+        private int threshold;
+        /* factor for computing size threshold */
+        private final float loadFactor;
+        /* maps hash value -> candidate handle value */
+        private int[] spine;
+        /* maps handle value -> next candidate handle value */
+        private int[] next;
+        /* maps handle value -> associated object */
+        private Object[] objs;
+
+        /**
+         * Creates new HandleTable with given capacity and load factor.
+         */
+        HandleTable(int initialCapacity, float loadFactor) {
+            this.loadFactor = loadFactor;
+            spine = new int[initialCapacity];
+            next = new int[initialCapacity];
+            objs = new Object[initialCapacity];
+            threshold = (int) (initialCapacity * loadFactor);
+            clear();
+        }
+
+        /**
+         * Assigns next available handle to given object, and returns handle
+         * value.  Handles are assigned in ascending order starting at 0.
+         */
+        int assign(Object obj) {
+            if (size >= next.length) {
+                growEntries();
+            }
+            if (size >= threshold) {
+                growSpine();
+            }
+            insert(obj, size);
+            return size++;
+        }
+
+        /**
+         * Looks up and returns handle associated with given object, or -1 if
+         * no mapping found.
+         */
+        int lookup(Object obj) {
+            if (size == 0) {
+                return -1;
+            }
+            int index = hash(obj) % spine.length;
+            for (int i = spine[index]; i >= 0; i = next[i]) {
+                if (objs[i] == obj) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /**
+         * Resets table to its initial (empty) state.
+         */
+        void clear() {
+            Arrays.fill(spine, -1);
+            Arrays.fill(objs, 0, size, null);
+            size = 0;
+        }
+
+        /**
+         * Returns the number of mappings currently in table.
+         */
+        int size() {
+            return size;
+        }
+
+        /**
+         * Inserts mapping object -> handle mapping into table.  Assumes table
+         * is large enough to accommodate new mapping.
+         */
+        private void insert(Object obj, int handle) {
+            int index = hash(obj) % spine.length;
+            objs[handle] = obj;
+            next[handle] = spine[index];
+            spine[index] = handle;
+        }
+
+        /**
+         * Expands the hash "spine" -- equivalent to increasing the number of
+         * buckets in a conventional hash table.
+         */
+        private void growSpine() {
+            spine = new int[(spine.length << 1) + 1];
+            threshold = (int) (spine.length * loadFactor);
+            Arrays.fill(spine, -1);
+            for (int i = 0; i < size; i++) {
+                insert(objs[i], i);
+            }
+        }
+
+        /**
+         * Increases hash table capacity by lengthening entry arrays.
+         */
+        private void growEntries() {
+            int newLength = (next.length << 1) + 1;
+            int[] newNext = new int[newLength];
+            System.arraycopy(next, 0, newNext, 0, size);
+            next = newNext;
+
+            Object[] newObjs = new Object[newLength];
+            System.arraycopy(objs, 0, newObjs, 0, size);
+            objs = newObjs;
+        }
+
+        /**
+         * Returns hash value for given object.
+         */
+        private int hash(Object obj) {
+            return System.identityHashCode(obj) & 0x7FFFFFFF;
+        }
+    }
+
+    /**
+     * Lightweight identity hash table which maps objects to replacement
+     * objects.
+     */
+    private static class ReplaceTable {
+
+        /* maps object -> index */
+        private final HandleTable htab;
+        /* maps index -> replacement object */
+        private Object[] reps;
+
+        /**
+         * Creates new ReplaceTable with given capacity and load factor.
+         */
+        ReplaceTable(int initialCapacity, float loadFactor) {
+            htab = new HandleTable(initialCapacity, loadFactor);
+            reps = new Object[initialCapacity];
+        }
+
+        /**
+         * Enters mapping from object to replacement object.
+         */
+        void assign(Object obj, Object rep) {
+            int index = htab.assign(obj);
+            while (index >= reps.length) {
+                grow();
+            }
+            reps[index] = rep;
+        }
+
+        /**
+         * Looks up and returns replacement for given object.  If no
+         * replacement is found, returns the lookup object itself.
+         */
+        Object lookup(Object obj) {
+            int index = htab.lookup(obj);
+            return (index >= 0) ? reps[index] : obj;
+        }
+
+        /**
+         * Resets table to its initial (empty) state.
+         */
+        void clear() {
+            Arrays.fill(reps, 0, htab.size(), null);
+            htab.clear();
+        }
+
+        /**
+         * Returns the number of mappings currently in table.
+         */
+        int size() {
+            return htab.size();
+        }
+
+        /**
+         * Increases table capacity.
+         */
+        private void grow() {
+            Object[] newReps = new Object[(reps.length << 1) + 1];
+            System.arraycopy(reps, 0, newReps, 0, reps.length);
+            reps = newReps;
+        }
+    }
+
+    /**
+     * Stack to keep debug information about the state of the
+     * serialization process, for embedding in exception messages.
+     */
+    private static class DebugTraceInfoStack {
+        private final List<String> stack;
+
+        DebugTraceInfoStack() {
+            stack = new ArrayList<>();
+        }
+
+        /**
+         * Removes all of the elements from enclosed list.
+         */
+        void clear() {
+            stack.clear();
+        }
+
+        /**
+         * Removes the object at the top of enclosed list.
+         */
+        void pop() {
+            stack.remove(stack.size()-1);
+        }
+
+        /**
+         * Pushes a String onto the top of enclosed list.
+         */
+        void push(String entry) {
+            stack.add("\t- " + entry);
+        }
+
+        /**
+         * Returns a string representation of this object
+         */
+        public String toString() {
+            StringBuilder buffer = new StringBuilder();
+            if (!stack.isEmpty()) {
+                for(int i = stack.size(); i > 0; i-- ) {
+                    buffer.append(stack.get(i-1) + ((i != 1) ? "\n" : ""));
+                }
+            }
+            return buffer.toString();
+        }
+    }
+
+}
diff --git a/java/io/ObjectStreamClass.java b/java/io/ObjectStreamClass.java
new file mode 100644
index 0000000..a88ad63
--- /dev/null
+++ b/java/io/ObjectStreamClass.java
@@ -0,0 +1,2498 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.reflect.misc.ReflectUtil;
+import dalvik.system.VMRuntime;
+
+/**
+ * Serialization's descriptor for classes.  It contains the name and
+ * serialVersionUID of the class.  The ObjectStreamClass for a specific class
+ * loaded in this Java VM can be found/created using the lookup method.
+ *
+ * <p>The algorithm to compute the SerialVersionUID is described in
+ * <a href="../../../platform/serialization/spec/class.html#4100">Object
+ * Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
+ *
+ * @author      Mike Warres
+ * @author      Roger Riggs
+ * @see ObjectStreamField
+ * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
+ * @since   JDK1.1
+ */
+public class ObjectStreamClass implements Serializable {
+
+    /** serialPersistentFields value indicating no serializable fields */
+    public static final ObjectStreamField[] NO_FIELDS =
+        new ObjectStreamField[0];
+
+    private static final long serialVersionUID = -6120832682080437368L;
+    private static final ObjectStreamField[] serialPersistentFields =
+        NO_FIELDS;
+
+    // BEGIN Android-removed: ReflectionFactory not used on Android.
+    /*
+    /** reflection factory for obtaining serialization constructors *
+    private static final ReflectionFactory reflFactory =
+        AccessController.doPrivileged(
+            new ReflectionFactory.GetReflectionFactoryAction());
+    */
+    // END Android-removed: ReflectionFactory not used on Android.
+
+    private static class Caches {
+        /** cache mapping local classes -> descriptors */
+        static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
+            new ConcurrentHashMap<>();
+
+        /** cache mapping field group/local desc pairs -> field reflectors */
+        static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
+            new ConcurrentHashMap<>();
+
+        /** queue for WeakReferences to local classes */
+        private static final ReferenceQueue<Class<?>> localDescsQueue =
+            new ReferenceQueue<>();
+        /** queue for WeakReferences to field reflectors keys */
+        private static final ReferenceQueue<Class<?>> reflectorsQueue =
+            new ReferenceQueue<>();
+    }
+
+    /** class associated with this descriptor (if any) */
+    private Class<?> cl;
+    /** name of class represented by this descriptor */
+    private String name;
+    /** serialVersionUID of represented class (null if not computed yet) */
+    private volatile Long suid;
+
+    /** true if represents dynamic proxy class */
+    private boolean isProxy;
+    /** true if represents enum type */
+    private boolean isEnum;
+    /** true if represented class implements Serializable */
+    private boolean serializable;
+    /** true if represented class implements Externalizable */
+    private boolean externalizable;
+    /** true if desc has data written by class-defined writeObject method */
+    private boolean hasWriteObjectData;
+    /**
+     * true if desc has externalizable data written in block data format; this
+     * must be true by default to accommodate ObjectInputStream subclasses which
+     * override readClassDescriptor() to return class descriptors obtained from
+     * ObjectStreamClass.lookup() (see 4461737)
+     */
+    private boolean hasBlockExternalData = true;
+
+    /**
+     * Contains information about InvalidClassException instances to be thrown
+     * when attempting operations on an invalid class. Note that instances of
+     * this class are immutable and are potentially shared among
+     * ObjectStreamClass instances.
+     */
+    private static class ExceptionInfo {
+        private final String className;
+        private final String message;
+
+        ExceptionInfo(String cn, String msg) {
+            className = cn;
+            message = msg;
+        }
+
+        /**
+         * Returns (does not throw) an InvalidClassException instance created
+         * from the information in this object, suitable for being thrown by
+         * the caller.
+         */
+        InvalidClassException newInvalidClassException() {
+            return new InvalidClassException(className, message);
+        }
+    }
+
+    /** exception (if any) thrown while attempting to resolve class */
+    private ClassNotFoundException resolveEx;
+    /** exception (if any) to throw if non-enum deserialization attempted */
+    private ExceptionInfo deserializeEx;
+    /** exception (if any) to throw if non-enum serialization attempted */
+    private ExceptionInfo serializeEx;
+    /** exception (if any) to throw if default serialization attempted */
+    private ExceptionInfo defaultSerializeEx;
+
+    /** serializable fields */
+    private ObjectStreamField[] fields;
+    /** aggregate marshalled size of primitive fields */
+    private int primDataSize;
+    /** number of non-primitive fields */
+    private int numObjFields;
+    /** reflector for setting/getting serializable field values */
+    private FieldReflector fieldRefl;
+    /** data layout of serialized objects described by this class desc */
+    private volatile ClassDataSlot[] dataLayout;
+
+    /** serialization-appropriate constructor, or null if none */
+    private Constructor<?> cons;
+    /** class-defined writeObject method, or null if none */
+    private Method writeObjectMethod;
+    /** class-defined readObject method, or null if none */
+    private Method readObjectMethod;
+    /** class-defined readObjectNoData method, or null if none */
+    private Method readObjectNoDataMethod;
+    /** class-defined writeReplace method, or null if none */
+    private Method writeReplaceMethod;
+    /** class-defined readResolve method, or null if none */
+    private Method readResolveMethod;
+
+    /** local class descriptor for represented class (may point to self) */
+    private ObjectStreamClass localDesc;
+    /** superclass descriptor appearing in stream */
+    private ObjectStreamClass superDesc;
+
+    /** true if, and only if, the object has been correctly initialized */
+    private boolean initialized;
+
+    // BEGIN Android-removed: Initialization not required on Android.
+    /*
+    /**
+     * Initializes native code.
+     *
+    private static native void initNative();
+    static {
+        initNative();
+    }
+    */
+    // END Android-removed: Initialization not required on Android.
+
+    /**
+     * Find the descriptor for a class that can be serialized.  Creates an
+     * ObjectStreamClass instance if one does not exist yet for class. Null is
+     * returned if the specified class does not implement java.io.Serializable
+     * or java.io.Externalizable.
+     *
+     * @param   cl class for which to get the descriptor
+     * @return  the class descriptor for the specified class
+     */
+    public static ObjectStreamClass lookup(Class<?> cl) {
+        return lookup(cl, false);
+    }
+
+    /**
+     * Returns the descriptor for any class, regardless of whether it
+     * implements {@link Serializable}.
+     *
+     * @param        cl class for which to get the descriptor
+     * @return       the class descriptor for the specified class
+     * @since 1.6
+     */
+    public static ObjectStreamClass lookupAny(Class<?> cl) {
+        return lookup(cl, true);
+    }
+
+    /**
+     * Returns the name of the class described by this descriptor.
+     * This method returns the name of the class in the format that
+     * is used by the {@link Class#getName} method.
+     *
+     * @return a string representing the name of the class
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Return the serialVersionUID for this class.  The serialVersionUID
+     * defines a set of classes all with the same name that have evolved from a
+     * common root class and agree to be serialized and deserialized using a
+     * common format.  NonSerializable classes have a serialVersionUID of 0L.
+     *
+     * @return  the SUID of the class described by this descriptor
+     */
+    public long getSerialVersionUID() {
+        // REMIND: synchronize instead of relying on volatile?
+        if (suid == null) {
+            suid = AccessController.doPrivileged(
+                new PrivilegedAction<Long>() {
+                    public Long run() {
+                        return computeDefaultSUID(cl);
+                    }
+                }
+            );
+        }
+        return suid.longValue();
+    }
+
+    /**
+     * Return the class in the local VM that this version is mapped to.  Null
+     * is returned if there is no corresponding local class.
+     *
+     * @return  the <code>Class</code> instance that this descriptor represents
+     */
+    @CallerSensitive
+    public Class<?> forClass() {
+        if (cl == null) {
+            return null;
+        }
+        requireInitialized();
+        if (System.getSecurityManager() != null) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), cl.getClassLoader())) {
+                ReflectUtil.checkPackageAccess(cl);
+            }
+        }
+        return cl;
+    }
+
+    /**
+     * Return an array of the fields of this serializable class.
+     *
+     * @return  an array containing an element for each persistent field of
+     *          this class. Returns an array of length zero if there are no
+     *          fields.
+     * @since 1.2
+     */
+    public ObjectStreamField[] getFields() {
+        return getFields(true);
+    }
+
+    /**
+     * Get the field of this class by name.
+     *
+     * @param   name the name of the data field to look for
+     * @return  The ObjectStreamField object of the named field or null if
+     *          there is no such named field.
+     */
+    public ObjectStreamField getField(String name) {
+        return getField(name, null);
+    }
+
+    /**
+     * Return a string describing this ObjectStreamClass.
+     */
+    public String toString() {
+        return name + ": static final long serialVersionUID = " +
+            getSerialVersionUID() + "L;";
+    }
+
+    /**
+     * Looks up and returns class descriptor for given class, or null if class
+     * is non-serializable and "all" is set to false.
+     *
+     * @param   cl class to look up
+     * @param   all if true, return descriptors for all classes; if false, only
+     *          return descriptors for serializable classes
+     */
+    static ObjectStreamClass lookup(Class<?> cl, boolean all) {
+        if (!(all || Serializable.class.isAssignableFrom(cl))) {
+            return null;
+        }
+        processQueue(Caches.localDescsQueue, Caches.localDescs);
+        WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
+        Reference<?> ref = Caches.localDescs.get(key);
+        Object entry = null;
+        if (ref != null) {
+            entry = ref.get();
+        }
+        EntryFuture future = null;
+        if (entry == null) {
+            EntryFuture newEntry = new EntryFuture();
+            Reference<?> newRef = new SoftReference<>(newEntry);
+            do {
+                if (ref != null) {
+                    Caches.localDescs.remove(key, ref);
+                }
+                ref = Caches.localDescs.putIfAbsent(key, newRef);
+                if (ref != null) {
+                    entry = ref.get();
+                }
+            } while (ref != null && entry == null);
+            if (entry == null) {
+                future = newEntry;
+            }
+        }
+
+        if (entry instanceof ObjectStreamClass) {  // check common case first
+            return (ObjectStreamClass) entry;
+        }
+        if (entry instanceof EntryFuture) {
+            future = (EntryFuture) entry;
+            if (future.getOwner() == Thread.currentThread()) {
+                /*
+                 * Handle nested call situation described by 4803747: waiting
+                 * for future value to be set by a lookup() call further up the
+                 * stack will result in deadlock, so calculate and set the
+                 * future value here instead.
+                 */
+                entry = null;
+            } else {
+                entry = future.get();
+            }
+        }
+        if (entry == null) {
+            try {
+                entry = new ObjectStreamClass(cl);
+            } catch (Throwable th) {
+                entry = th;
+            }
+            if (future.set(entry)) {
+                Caches.localDescs.put(key, new SoftReference<Object>(entry));
+            } else {
+                // nested lookup call already set future
+                entry = future.get();
+            }
+        }
+
+        if (entry instanceof ObjectStreamClass) {
+            return (ObjectStreamClass) entry;
+        } else if (entry instanceof RuntimeException) {
+            throw (RuntimeException) entry;
+        } else if (entry instanceof Error) {
+            throw (Error) entry;
+        } else {
+            throw new InternalError("unexpected entry: " + entry);
+        }
+    }
+
+    /**
+     * Placeholder used in class descriptor and field reflector lookup tables
+     * for an entry in the process of being initialized.  (Internal) callers
+     * which receive an EntryFuture belonging to another thread as the result
+     * of a lookup should call the get() method of the EntryFuture; this will
+     * return the actual entry once it is ready for use and has been set().  To
+     * conserve objects, EntryFutures synchronize on themselves.
+     */
+    private static class EntryFuture {
+
+        private static final Object unset = new Object();
+        private final Thread owner = Thread.currentThread();
+        private Object entry = unset;
+
+        /**
+         * Attempts to set the value contained by this EntryFuture.  If the
+         * EntryFuture's value has not been set already, then the value is
+         * saved, any callers blocked in the get() method are notified, and
+         * true is returned.  If the value has already been set, then no saving
+         * or notification occurs, and false is returned.
+         */
+        synchronized boolean set(Object entry) {
+            if (this.entry != unset) {
+                return false;
+            }
+            this.entry = entry;
+            notifyAll();
+            return true;
+        }
+
+        /**
+         * Returns the value contained by this EntryFuture, blocking if
+         * necessary until a value is set.
+         */
+        synchronized Object get() {
+            boolean interrupted = false;
+            while (entry == unset) {
+                try {
+                    wait();
+                } catch (InterruptedException ex) {
+                    interrupted = true;
+                }
+            }
+            if (interrupted) {
+                AccessController.doPrivileged(
+                    new PrivilegedAction<Void>() {
+                        public Void run() {
+                            Thread.currentThread().interrupt();
+                            return null;
+                        }
+                    }
+                );
+            }
+            return entry;
+        }
+
+        /**
+         * Returns the thread that created this EntryFuture.
+         */
+        Thread getOwner() {
+            return owner;
+        }
+    }
+
+    /**
+     * Creates local class descriptor representing given class.
+     */
+    private ObjectStreamClass(final Class<?> cl) {
+        this.cl = cl;
+        name = cl.getName();
+        isProxy = Proxy.isProxyClass(cl);
+        isEnum = Enum.class.isAssignableFrom(cl);
+        serializable = Serializable.class.isAssignableFrom(cl);
+        externalizable = Externalizable.class.isAssignableFrom(cl);
+
+        Class<?> superCl = cl.getSuperclass();
+        superDesc = (superCl != null) ? lookup(superCl, false) : null;
+        localDesc = this;
+
+        if (serializable) {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    if (isEnum) {
+                        suid = Long.valueOf(0);
+                        fields = NO_FIELDS;
+                        return null;
+                    }
+                    if (cl.isArray()) {
+                        fields = NO_FIELDS;
+                        return null;
+                    }
+
+                    suid = getDeclaredSUID(cl);
+                    try {
+                        fields = getSerialFields(cl);
+                        computeFieldOffsets();
+                    } catch (InvalidClassException e) {
+                        serializeEx = deserializeEx =
+                            new ExceptionInfo(e.classname, e.getMessage());
+                        fields = NO_FIELDS;
+                    }
+
+                    if (externalizable) {
+                        cons = getExternalizableConstructor(cl);
+                    } else {
+                        cons = getSerializableConstructor(cl);
+                        writeObjectMethod = getPrivateMethod(cl, "writeObject",
+                            new Class<?>[] { ObjectOutputStream.class },
+                            Void.TYPE);
+                        readObjectMethod = getPrivateMethod(cl, "readObject",
+                            new Class<?>[] { ObjectInputStream.class },
+                            Void.TYPE);
+                        readObjectNoDataMethod = getPrivateMethod(
+                            cl, "readObjectNoData", null, Void.TYPE);
+                        hasWriteObjectData = (writeObjectMethod != null);
+                    }
+                    writeReplaceMethod = getInheritableMethod(
+                        cl, "writeReplace", null, Object.class);
+                    readResolveMethod = getInheritableMethod(
+                        cl, "readResolve", null, Object.class);
+                    return null;
+                }
+            });
+        } else {
+            suid = Long.valueOf(0);
+            fields = NO_FIELDS;
+        }
+
+        try {
+            fieldRefl = getReflector(fields, this);
+        } catch (InvalidClassException ex) {
+            // field mismatches impossible when matching local fields vs. self
+            throw new InternalError(ex);
+        }
+
+        if (deserializeEx == null) {
+            if (isEnum) {
+                deserializeEx = new ExceptionInfo(name, "enum type");
+            } else if (cons == null) {
+                deserializeEx = new ExceptionInfo(name, "no valid constructor");
+            }
+        }
+        for (int i = 0; i < fields.length; i++) {
+            if (fields[i].getField() == null) {
+                defaultSerializeEx = new ExceptionInfo(
+                    name, "unmatched serializable field(s) declared");
+            }
+        }
+        initialized = true;
+    }
+
+    /**
+     * Creates blank class descriptor which should be initialized via a
+     * subsequent call to initProxy(), initNonProxy() or readNonProxy().
+     */
+    ObjectStreamClass() {
+    }
+
+    /**
+     * Initializes class descriptor representing a proxy class.
+     */
+    void initProxy(Class<?> cl,
+                   ClassNotFoundException resolveEx,
+                   ObjectStreamClass superDesc)
+        throws InvalidClassException
+    {
+        ObjectStreamClass osc = null;
+        if (cl != null) {
+            osc = lookup(cl, true);
+            if (!osc.isProxy) {
+                throw new InvalidClassException(
+                    "cannot bind proxy descriptor to a non-proxy class");
+            }
+        }
+        this.cl = cl;
+        this.resolveEx = resolveEx;
+        this.superDesc = superDesc;
+        isProxy = true;
+        serializable = true;
+        suid = Long.valueOf(0);
+        fields = NO_FIELDS;
+        if (osc != null) {
+            localDesc = osc;
+            name = localDesc.name;
+            externalizable = localDesc.externalizable;
+            writeReplaceMethod = localDesc.writeReplaceMethod;
+            readResolveMethod = localDesc.readResolveMethod;
+            deserializeEx = localDesc.deserializeEx;
+            cons = localDesc.cons;
+        }
+        fieldRefl = getReflector(fields, localDesc);
+        initialized = true;
+    }
+
+    /**
+     * Initializes class descriptor representing a non-proxy class.
+     */
+    void initNonProxy(ObjectStreamClass model,
+                      Class<?> cl,
+                      ClassNotFoundException resolveEx,
+                      ObjectStreamClass superDesc)
+        throws InvalidClassException
+    {
+        long suid = Long.valueOf(model.getSerialVersionUID());
+        ObjectStreamClass osc = null;
+        if (cl != null) {
+            osc = lookup(cl, true);
+            if (osc.isProxy) {
+                throw new InvalidClassException(
+                        "cannot bind non-proxy descriptor to a proxy class");
+            }
+            if (model.isEnum != osc.isEnum) {
+                throw new InvalidClassException(model.isEnum ?
+                        "cannot bind enum descriptor to a non-enum class" :
+                        "cannot bind non-enum descriptor to an enum class");
+            }
+
+            if (model.serializable == osc.serializable &&
+                    !cl.isArray() &&
+                    suid != osc.getSerialVersionUID()) {
+                throw new InvalidClassException(osc.name,
+                        "local class incompatible: " +
+                                "stream classdesc serialVersionUID = " + suid +
+                                ", local class serialVersionUID = " +
+                                osc.getSerialVersionUID());
+            }
+
+            if (!classNamesEqual(model.name, osc.name)) {
+                throw new InvalidClassException(osc.name,
+                        "local class name incompatible with stream class " +
+                                "name \"" + model.name + "\"");
+            }
+
+            if (!model.isEnum) {
+                if ((model.serializable == osc.serializable) &&
+                        (model.externalizable != osc.externalizable)) {
+                    throw new InvalidClassException(osc.name,
+                            "Serializable incompatible with Externalizable");
+                }
+
+                if ((model.serializable != osc.serializable) ||
+                        (model.externalizable != osc.externalizable) ||
+                        !(model.serializable || model.externalizable)) {
+                    deserializeEx = new ExceptionInfo(
+                            osc.name, "class invalid for deserialization");
+                }
+            }
+        }
+
+        this.cl = cl;
+        this.resolveEx = resolveEx;
+        this.superDesc = superDesc;
+        name = model.name;
+        this.suid = suid;
+        isProxy = false;
+        isEnum = model.isEnum;
+        serializable = model.serializable;
+        externalizable = model.externalizable;
+        hasBlockExternalData = model.hasBlockExternalData;
+        hasWriteObjectData = model.hasWriteObjectData;
+        fields = model.fields;
+        primDataSize = model.primDataSize;
+        numObjFields = model.numObjFields;
+
+        if (osc != null) {
+            localDesc = osc;
+            writeObjectMethod = localDesc.writeObjectMethod;
+            readObjectMethod = localDesc.readObjectMethod;
+            readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
+            writeReplaceMethod = localDesc.writeReplaceMethod;
+            readResolveMethod = localDesc.readResolveMethod;
+            if (deserializeEx == null) {
+                deserializeEx = localDesc.deserializeEx;
+            }
+            cons = localDesc.cons;
+        }
+
+        fieldRefl = getReflector(fields, localDesc);
+        // reassign to matched fields so as to reflect local unshared settings
+        fields = fieldRefl.getFields();
+        initialized = true;
+    }
+
+    /**
+     * Reads non-proxy class descriptor information from given input stream.
+     * The resulting class descriptor is not fully functional; it can only be
+     * used as input to the ObjectInputStream.resolveClass() and
+     * ObjectStreamClass.initNonProxy() methods.
+     */
+    void readNonProxy(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        name = in.readUTF();
+        suid = Long.valueOf(in.readLong());
+        isProxy = false;
+
+        byte flags = in.readByte();
+        hasWriteObjectData =
+            ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
+        hasBlockExternalData =
+            ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
+        externalizable =
+            ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
+        boolean sflag =
+            ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
+        if (externalizable && sflag) {
+            throw new InvalidClassException(
+                name, "serializable and externalizable flags conflict");
+        }
+        serializable = externalizable || sflag;
+        isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
+        if (isEnum && suid.longValue() != 0L) {
+            throw new InvalidClassException(name,
+                "enum descriptor has non-zero serialVersionUID: " + suid);
+        }
+
+        int numFields = in.readShort();
+        if (isEnum && numFields != 0) {
+            throw new InvalidClassException(name,
+                "enum descriptor has non-zero field count: " + numFields);
+        }
+        fields = (numFields > 0) ?
+            new ObjectStreamField[numFields] : NO_FIELDS;
+        for (int i = 0; i < numFields; i++) {
+            char tcode = (char) in.readByte();
+            String fname = in.readUTF();
+            String signature = ((tcode == 'L') || (tcode == '[')) ?
+                in.readTypeString() : new String(new char[] { tcode });
+            try {
+                fields[i] = new ObjectStreamField(fname, signature, false);
+            } catch (RuntimeException e) {
+                throw (IOException) new InvalidClassException(name,
+                    "invalid descriptor for field " + fname).initCause(e);
+            }
+        }
+        computeFieldOffsets();
+    }
+
+    /**
+     * Writes non-proxy class descriptor information to given output stream.
+     */
+    void writeNonProxy(ObjectOutputStream out) throws IOException {
+        out.writeUTF(name);
+        out.writeLong(getSerialVersionUID());
+
+        byte flags = 0;
+        if (externalizable) {
+            flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
+            int protocol = out.getProtocolVersion();
+            if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
+                flags |= ObjectStreamConstants.SC_BLOCK_DATA;
+            }
+        } else if (serializable) {
+            flags |= ObjectStreamConstants.SC_SERIALIZABLE;
+        }
+        if (hasWriteObjectData) {
+            flags |= ObjectStreamConstants.SC_WRITE_METHOD;
+        }
+        if (isEnum) {
+            flags |= ObjectStreamConstants.SC_ENUM;
+        }
+        out.writeByte(flags);
+
+        out.writeShort(fields.length);
+        for (int i = 0; i < fields.length; i++) {
+            ObjectStreamField f = fields[i];
+            out.writeByte(f.getTypeCode());
+            out.writeUTF(f.getName());
+            if (!f.isPrimitive()) {
+                out.writeTypeString(f.getTypeString());
+            }
+        }
+    }
+
+    /**
+     * Returns ClassNotFoundException (if any) thrown while attempting to
+     * resolve local class corresponding to this class descriptor.
+     */
+    ClassNotFoundException getResolveException() {
+        return resolveEx;
+    }
+
+    /**
+     * Throws InternalError if not initialized.
+     */
+    private final void requireInitialized() {
+        if (!initialized)
+            throw new InternalError("Unexpected call when not initialized");
+    }
+
+    /**
+     * Throws an InvalidClassException if object instances referencing this
+     * class descriptor should not be allowed to deserialize.  This method does
+     * not apply to deserialization of enum constants.
+     */
+    void checkDeserialize() throws InvalidClassException {
+        requireInitialized();
+        if (deserializeEx != null) {
+            throw deserializeEx.newInvalidClassException();
+        }
+    }
+
+    /**
+     * Throws an InvalidClassException if objects whose class is represented by
+     * this descriptor should not be allowed to serialize.  This method does
+     * not apply to serialization of enum constants.
+     */
+    void checkSerialize() throws InvalidClassException {
+        requireInitialized();
+        if (serializeEx != null) {
+            throw serializeEx.newInvalidClassException();
+        }
+    }
+
+    /**
+     * Throws an InvalidClassException if objects whose class is represented by
+     * this descriptor should not be permitted to use default serialization
+     * (e.g., if the class declares serializable fields that do not correspond
+     * to actual fields, and hence must use the GetField API).  This method
+     * does not apply to deserialization of enum constants.
+     */
+    void checkDefaultSerialize() throws InvalidClassException {
+        requireInitialized();
+        if (defaultSerializeEx != null) {
+            throw defaultSerializeEx.newInvalidClassException();
+        }
+    }
+
+    /**
+     * Returns superclass descriptor.  Note that on the receiving side, the
+     * superclass descriptor may be bound to a class that is not a superclass
+     * of the subclass descriptor's bound class.
+     */
+    ObjectStreamClass getSuperDesc() {
+        requireInitialized();
+        return superDesc;
+    }
+
+    /**
+     * Returns the "local" class descriptor for the class associated with this
+     * class descriptor (i.e., the result of
+     * ObjectStreamClass.lookup(this.forClass())) or null if there is no class
+     * associated with this descriptor.
+     */
+    ObjectStreamClass getLocalDesc() {
+        requireInitialized();
+        return localDesc;
+    }
+
+    /**
+     * Returns arrays of ObjectStreamFields representing the serializable
+     * fields of the represented class.  If copy is true, a clone of this class
+     * descriptor's field array is returned, otherwise the array itself is
+     * returned.
+     */
+    ObjectStreamField[] getFields(boolean copy) {
+        return copy ? fields.clone() : fields;
+    }
+
+    /**
+     * Looks up a serializable field of the represented class by name and type.
+     * A specified type of null matches all types, Object.class matches all
+     * non-primitive types, and any other non-null type matches assignable
+     * types only.  Returns matching field, or null if no match found.
+     */
+    ObjectStreamField getField(String name, Class<?> type) {
+        for (int i = 0; i < fields.length; i++) {
+            ObjectStreamField f = fields[i];
+            if (f.getName().equals(name)) {
+                if (type == null ||
+                    (type == Object.class && !f.isPrimitive()))
+                {
+                    return f;
+                }
+                Class<?> ftype = f.getType();
+                if (ftype != null && type.isAssignableFrom(ftype)) {
+                    return f;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns true if class descriptor represents a dynamic proxy class, false
+     * otherwise.
+     */
+    boolean isProxy() {
+        requireInitialized();
+        return isProxy;
+    }
+
+    /**
+     * Returns true if class descriptor represents an enum type, false
+     * otherwise.
+     */
+    boolean isEnum() {
+        requireInitialized();
+        return isEnum;
+    }
+
+    /**
+     * Returns true if represented class implements Externalizable, false
+     * otherwise.
+     */
+    boolean isExternalizable() {
+        requireInitialized();
+        return externalizable;
+    }
+
+    /**
+     * Returns true if represented class implements Serializable, false
+     * otherwise.
+     */
+    boolean isSerializable() {
+        requireInitialized();
+        return serializable;
+    }
+
+    /**
+     * Returns true if class descriptor represents externalizable class that
+     * has written its data in 1.2 (block data) format, false otherwise.
+     */
+    boolean hasBlockExternalData() {
+        requireInitialized();
+        return hasBlockExternalData;
+    }
+
+    /**
+     * Returns true if class descriptor represents serializable (but not
+     * externalizable) class which has written its data via a custom
+     * writeObject() method, false otherwise.
+     */
+    boolean hasWriteObjectData() {
+        requireInitialized();
+        return hasWriteObjectData;
+    }
+
+    /**
+     * Returns true if represented class is serializable/externalizable and can
+     * be instantiated by the serialization runtime--i.e., if it is
+     * externalizable and defines a public no-arg constructor, or if it is
+     * non-externalizable and its first non-serializable superclass defines an
+     * accessible no-arg constructor.  Otherwise, returns false.
+     */
+    boolean isInstantiable() {
+        requireInitialized();
+        return (cons != null);
+    }
+
+    /**
+     * Returns true if represented class is serializable (but not
+     * externalizable) and defines a conformant writeObject method.  Otherwise,
+     * returns false.
+     */
+    boolean hasWriteObjectMethod() {
+        requireInitialized();
+        return (writeObjectMethod != null);
+    }
+
+    /**
+     * Returns true if represented class is serializable (but not
+     * externalizable) and defines a conformant readObject method.  Otherwise,
+     * returns false.
+     */
+    boolean hasReadObjectMethod() {
+        requireInitialized();
+        return (readObjectMethod != null);
+    }
+
+    /**
+     * Returns true if represented class is serializable (but not
+     * externalizable) and defines a conformant readObjectNoData method.
+     * Otherwise, returns false.
+     */
+    boolean hasReadObjectNoDataMethod() {
+        requireInitialized();
+        return (readObjectNoDataMethod != null);
+    }
+
+    /**
+     * Returns true if represented class is serializable or externalizable and
+     * defines a conformant writeReplace method.  Otherwise, returns false.
+     */
+    boolean hasWriteReplaceMethod() {
+        requireInitialized();
+        return (writeReplaceMethod != null);
+    }
+
+    /**
+     * Returns true if represented class is serializable or externalizable and
+     * defines a conformant readResolve method.  Otherwise, returns false.
+     */
+    boolean hasReadResolveMethod() {
+        requireInitialized();
+        return (readResolveMethod != null);
+    }
+
+    /**
+     * Creates a new instance of the represented class.  If the class is
+     * externalizable, invokes its public no-arg constructor; otherwise, if the
+     * class is serializable, invokes the no-arg constructor of the first
+     * non-serializable superclass.  Throws UnsupportedOperationException if
+     * this class descriptor is not associated with a class, if the associated
+     * class is non-serializable or if the appropriate no-arg constructor is
+     * inaccessible/unavailable.
+     */
+    Object newInstance()
+        throws InstantiationException, InvocationTargetException,
+               UnsupportedOperationException
+    {
+        requireInitialized();
+        if (cons != null) {
+            try {
+                return cons.newInstance();
+            } catch (IllegalAccessException ex) {
+                // should not occur, as access checks have been suppressed
+                throw new InternalError(ex);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Invokes the writeObject method of the represented serializable class.
+     * Throws UnsupportedOperationException if this class descriptor is not
+     * associated with a class, or if the class is externalizable,
+     * non-serializable or does not define writeObject.
+     */
+    void invokeWriteObject(Object obj, ObjectOutputStream out)
+        throws IOException, UnsupportedOperationException
+    {
+        requireInitialized();
+        if (writeObjectMethod != null) {
+            try {
+                writeObjectMethod.invoke(obj, new Object[]{ out });
+            } catch (InvocationTargetException ex) {
+                Throwable th = ex.getTargetException();
+                if (th instanceof IOException) {
+                    throw (IOException) th;
+                } else {
+                    throwMiscException(th);
+                }
+            } catch (IllegalAccessException ex) {
+                // should not occur, as access checks have been suppressed
+                throw new InternalError(ex);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Invokes the readObject method of the represented serializable class.
+     * Throws UnsupportedOperationException if this class descriptor is not
+     * associated with a class, or if the class is externalizable,
+     * non-serializable or does not define readObject.
+     */
+    void invokeReadObject(Object obj, ObjectInputStream in)
+        throws ClassNotFoundException, IOException,
+               UnsupportedOperationException
+    {
+        requireInitialized();
+        if (readObjectMethod != null) {
+            try {
+                readObjectMethod.invoke(obj, new Object[]{ in });
+            } catch (InvocationTargetException ex) {
+                Throwable th = ex.getTargetException();
+                if (th instanceof ClassNotFoundException) {
+                    throw (ClassNotFoundException) th;
+                } else if (th instanceof IOException) {
+                    throw (IOException) th;
+                } else {
+                    throwMiscException(th);
+                }
+            } catch (IllegalAccessException ex) {
+                // should not occur, as access checks have been suppressed
+                throw new InternalError(ex);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Invokes the readObjectNoData method of the represented serializable
+     * class.  Throws UnsupportedOperationException if this class descriptor is
+     * not associated with a class, or if the class is externalizable,
+     * non-serializable or does not define readObjectNoData.
+     */
+    void invokeReadObjectNoData(Object obj)
+        throws IOException, UnsupportedOperationException
+    {
+        requireInitialized();
+        if (readObjectNoDataMethod != null) {
+            try {
+                readObjectNoDataMethod.invoke(obj, (Object[]) null);
+            } catch (InvocationTargetException ex) {
+                Throwable th = ex.getTargetException();
+                if (th instanceof ObjectStreamException) {
+                    throw (ObjectStreamException) th;
+                } else {
+                    throwMiscException(th);
+                }
+            } catch (IllegalAccessException ex) {
+                // should not occur, as access checks have been suppressed
+                throw new InternalError(ex);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Invokes the writeReplace method of the represented serializable class and
+     * returns the result.  Throws UnsupportedOperationException if this class
+     * descriptor is not associated with a class, or if the class is
+     * non-serializable or does not define writeReplace.
+     */
+    Object invokeWriteReplace(Object obj)
+        throws IOException, UnsupportedOperationException
+    {
+        requireInitialized();
+        if (writeReplaceMethod != null) {
+            try {
+                return writeReplaceMethod.invoke(obj, (Object[]) null);
+            } catch (InvocationTargetException ex) {
+                Throwable th = ex.getTargetException();
+                if (th instanceof ObjectStreamException) {
+                    throw (ObjectStreamException) th;
+                } else {
+                    throwMiscException(th);
+                    throw new InternalError(th);  // never reached
+                }
+            } catch (IllegalAccessException ex) {
+                // should not occur, as access checks have been suppressed
+                throw new InternalError(ex);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Invokes the readResolve method of the represented serializable class and
+     * returns the result.  Throws UnsupportedOperationException if this class
+     * descriptor is not associated with a class, or if the class is
+     * non-serializable or does not define readResolve.
+     */
+    Object invokeReadResolve(Object obj)
+        throws IOException, UnsupportedOperationException
+    {
+        requireInitialized();
+        if (readResolveMethod != null) {
+            try {
+                return readResolveMethod.invoke(obj, (Object[]) null);
+            } catch (InvocationTargetException ex) {
+                Throwable th = ex.getTargetException();
+                if (th instanceof ObjectStreamException) {
+                    throw (ObjectStreamException) th;
+                } else {
+                    throwMiscException(th);
+                    throw new InternalError(th);  // never reached
+                }
+            } catch (IllegalAccessException ex) {
+                // should not occur, as access checks have been suppressed
+                throw new InternalError(ex);
+            }
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Class representing the portion of an object's serialized form allotted
+     * to data described by a given class descriptor.  If "hasData" is false,
+     * the object's serialized form does not contain data associated with the
+     * class descriptor.
+     */
+    static class ClassDataSlot {
+
+        /** class descriptor "occupying" this slot */
+        final ObjectStreamClass desc;
+        /** true if serialized form includes data for this slot's descriptor */
+        final boolean hasData;
+
+        ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
+            this.desc = desc;
+            this.hasData = hasData;
+        }
+    }
+
+    /**
+     * Returns array of ClassDataSlot instances representing the data layout
+     * (including superclass data) for serialized objects described by this
+     * class descriptor.  ClassDataSlots are ordered by inheritance with those
+     * containing "higher" superclasses appearing first.  The final
+     * ClassDataSlot contains a reference to this descriptor.
+     */
+    ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
+        // REMIND: synchronize instead of relying on volatile?
+        if (dataLayout == null) {
+            dataLayout = getClassDataLayout0();
+        }
+        return dataLayout;
+    }
+
+    private ClassDataSlot[] getClassDataLayout0()
+        throws InvalidClassException
+    {
+        ArrayList<ClassDataSlot> slots = new ArrayList<>();
+        Class<?> start = cl, end = cl;
+
+        // locate closest non-serializable superclass
+        while (end != null && Serializable.class.isAssignableFrom(end)) {
+            end = end.getSuperclass();
+        }
+
+        HashSet<String> oscNames = new HashSet<>(3);
+
+        for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
+            if (oscNames.contains(d.name)) {
+                throw new InvalidClassException("Circular reference.");
+            } else {
+                oscNames.add(d.name);
+            }
+
+            // search up inheritance hierarchy for class with matching name
+            String searchName = (d.cl != null) ? d.cl.getName() : d.name;
+            Class<?> match = null;
+            for (Class<?> c = start; c != end; c = c.getSuperclass()) {
+                if (searchName.equals(c.getName())) {
+                    match = c;
+                    break;
+                }
+            }
+
+            // add "no data" slot for each unmatched class below match
+            if (match != null) {
+                for (Class<?> c = start; c != match; c = c.getSuperclass()) {
+                    slots.add(new ClassDataSlot(
+                        ObjectStreamClass.lookup(c, true), false));
+                }
+                start = match.getSuperclass();
+            }
+
+            // record descriptor/class pairing
+            slots.add(new ClassDataSlot(d.getVariantFor(match), true));
+        }
+
+        // add "no data" slot for any leftover unmatched classes
+        for (Class<?> c = start; c != end; c = c.getSuperclass()) {
+            slots.add(new ClassDataSlot(
+                ObjectStreamClass.lookup(c, true), false));
+        }
+
+        // order slots from superclass -> subclass
+        Collections.reverse(slots);
+        return slots.toArray(new ClassDataSlot[slots.size()]);
+    }
+
+    /**
+     * Returns aggregate size (in bytes) of marshalled primitive field values
+     * for represented class.
+     */
+    int getPrimDataSize() {
+        return primDataSize;
+    }
+
+    /**
+     * Returns number of non-primitive serializable fields of represented
+     * class.
+     */
+    int getNumObjFields() {
+        return numObjFields;
+    }
+
+    /**
+     * Fetches the serializable primitive field values of object obj and
+     * marshals them into byte array buf starting at offset 0.  It is the
+     * responsibility of the caller to ensure that obj is of the proper type if
+     * non-null.
+     */
+    void getPrimFieldValues(Object obj, byte[] buf) {
+        fieldRefl.getPrimFieldValues(obj, buf);
+    }
+
+    /**
+     * Sets the serializable primitive fields of object obj using values
+     * unmarshalled from byte array buf starting at offset 0.  It is the
+     * responsibility of the caller to ensure that obj is of the proper type if
+     * non-null.
+     */
+    void setPrimFieldValues(Object obj, byte[] buf) {
+        fieldRefl.setPrimFieldValues(obj, buf);
+    }
+
+    /**
+     * Fetches the serializable object field values of object obj and stores
+     * them in array vals starting at offset 0.  It is the responsibility of
+     * the caller to ensure that obj is of the proper type if non-null.
+     */
+    void getObjFieldValues(Object obj, Object[] vals) {
+        fieldRefl.getObjFieldValues(obj, vals);
+    }
+
+    /**
+     * Sets the serializable object fields of object obj using values from
+     * array vals starting at offset 0.  It is the responsibility of the caller
+     * to ensure that obj is of the proper type if non-null.
+     */
+    void setObjFieldValues(Object obj, Object[] vals) {
+        fieldRefl.setObjFieldValues(obj, vals);
+    }
+
+    /**
+     * Calculates and sets serializable field offsets, as well as primitive
+     * data size and object field count totals.  Throws InvalidClassException
+     * if fields are illegally ordered.
+     */
+    private void computeFieldOffsets() throws InvalidClassException {
+        primDataSize = 0;
+        numObjFields = 0;
+        int firstObjIndex = -1;
+
+        for (int i = 0; i < fields.length; i++) {
+            ObjectStreamField f = fields[i];
+            switch (f.getTypeCode()) {
+                case 'Z':
+                case 'B':
+                    f.setOffset(primDataSize++);
+                    break;
+
+                case 'C':
+                case 'S':
+                    f.setOffset(primDataSize);
+                    primDataSize += 2;
+                    break;
+
+                case 'I':
+                case 'F':
+                    f.setOffset(primDataSize);
+                    primDataSize += 4;
+                    break;
+
+                case 'J':
+                case 'D':
+                    f.setOffset(primDataSize);
+                    primDataSize += 8;
+                    break;
+
+                case '[':
+                case 'L':
+                    f.setOffset(numObjFields++);
+                    if (firstObjIndex == -1) {
+                        firstObjIndex = i;
+                    }
+                    break;
+
+                default:
+                    throw new InternalError();
+            }
+        }
+        if (firstObjIndex != -1 &&
+            firstObjIndex + numObjFields != fields.length)
+        {
+            throw new InvalidClassException(name, "illegal field order");
+        }
+    }
+
+    /**
+     * If given class is the same as the class associated with this class
+     * descriptor, returns reference to this class descriptor.  Otherwise,
+     * returns variant of this class descriptor bound to given class.
+     */
+    private ObjectStreamClass getVariantFor(Class<?> cl)
+        throws InvalidClassException
+    {
+        if (this.cl == cl) {
+            return this;
+        }
+        ObjectStreamClass desc = new ObjectStreamClass();
+        if (isProxy) {
+            desc.initProxy(cl, null, superDesc);
+        } else {
+            desc.initNonProxy(this, cl, null, superDesc);
+        }
+        return desc;
+    }
+
+    /**
+     * Returns public no-arg constructor of given class, or null if none found.
+     * Access checks are disabled on the returned constructor (if any), since
+     * the defining class may still be non-public.
+     */
+    private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
+        try {
+            Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
+            cons.setAccessible(true);
+            return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
+                cons : null;
+        } catch (NoSuchMethodException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns subclass-accessible no-arg constructor of first non-serializable
+     * superclass, or null if none found.  Access checks are disabled on the
+     * returned constructor (if any).
+     */
+    private static Constructor<?> getSerializableConstructor(Class<?> cl) {
+        Class<?> initCl = cl;
+        while (Serializable.class.isAssignableFrom(initCl)) {
+            if ((initCl = initCl.getSuperclass()) == null) {
+                return null;
+            }
+        }
+        try {
+            Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
+            int mods = cons.getModifiers();
+            if ((mods & Modifier.PRIVATE) != 0 ||
+                ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
+                 !packageEquals(cl, initCl)))
+            {
+                return null;
+            }
+            // BEGIN Android-changed: Serialization constructor obtained differently
+            // cons = reflFactory.newConstructorForSerialization(cl, cons);
+            if (cons.getDeclaringClass() != cl) {
+                cons = cons.serializationCopy(cons.getDeclaringClass(), cl);
+            }
+            // END Android-changed: Serialization constructor obtained differently
+            cons.setAccessible(true);
+            return cons;
+        } catch (NoSuchMethodException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns non-static, non-abstract method with given signature provided it
+     * is defined by or accessible (via inheritance) by the given class, or
+     * null if no match found.  Access checks are disabled on the returned
+     * method (if any).
+     */
+    private static Method getInheritableMethod(Class<?> cl, String name,
+                                               Class<?>[] argTypes,
+                                               Class<?> returnType)
+    {
+        Method meth = null;
+        Class<?> defCl = cl;
+        while (defCl != null) {
+            try {
+                meth = defCl.getDeclaredMethod(name, argTypes);
+                break;
+            } catch (NoSuchMethodException ex) {
+                defCl = defCl.getSuperclass();
+            }
+        }
+
+        if ((meth == null) || (meth.getReturnType() != returnType)) {
+            return null;
+        }
+        meth.setAccessible(true);
+        int mods = meth.getModifiers();
+        if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
+            return null;
+        } else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
+            return meth;
+        } else if ((mods & Modifier.PRIVATE) != 0) {
+            return (cl == defCl) ? meth : null;
+        } else {
+            return packageEquals(cl, defCl) ? meth : null;
+        }
+    }
+
+    /**
+     * Returns non-static private method with given signature defined by given
+     * class, or null if none found.  Access checks are disabled on the
+     * returned method (if any).
+     */
+    private static Method getPrivateMethod(Class<?> cl, String name,
+                                           Class<?>[] argTypes,
+                                           Class<?> returnType)
+    {
+        try {
+            Method meth = cl.getDeclaredMethod(name, argTypes);
+            meth.setAccessible(true);
+            int mods = meth.getModifiers();
+            return ((meth.getReturnType() == returnType) &&
+                    ((mods & Modifier.STATIC) == 0) &&
+                    ((mods & Modifier.PRIVATE) != 0)) ? meth : null;
+        } catch (NoSuchMethodException ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns true if classes are defined in the same runtime package, false
+     * otherwise.
+     */
+    private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
+        return (cl1.getClassLoader() == cl2.getClassLoader() &&
+                getPackageName(cl1).equals(getPackageName(cl2)));
+    }
+
+    /**
+     * Returns package name of given class.
+     */
+    private static String getPackageName(Class<?> cl) {
+        String s = cl.getName();
+        int i = s.lastIndexOf('[');
+        if (i >= 0) {
+            s = s.substring(i + 2);
+        }
+        i = s.lastIndexOf('.');
+        return (i >= 0) ? s.substring(0, i) : "";
+    }
+
+    /**
+     * Compares class names for equality, ignoring package names.  Returns true
+     * if class names equal, false otherwise.
+     */
+    private static boolean classNamesEqual(String name1, String name2) {
+        name1 = name1.substring(name1.lastIndexOf('.') + 1);
+        name2 = name2.substring(name2.lastIndexOf('.') + 1);
+        return name1.equals(name2);
+    }
+
+    /**
+     * Returns JVM type signature for given class.
+     */
+    private static String getClassSignature(Class<?> cl) {
+        StringBuilder sbuf = new StringBuilder();
+        while (cl.isArray()) {
+            sbuf.append('[');
+            cl = cl.getComponentType();
+        }
+        if (cl.isPrimitive()) {
+            if (cl == Integer.TYPE) {
+                sbuf.append('I');
+            } else if (cl == Byte.TYPE) {
+                sbuf.append('B');
+            } else if (cl == Long.TYPE) {
+                sbuf.append('J');
+            } else if (cl == Float.TYPE) {
+                sbuf.append('F');
+            } else if (cl == Double.TYPE) {
+                sbuf.append('D');
+            } else if (cl == Short.TYPE) {
+                sbuf.append('S');
+            } else if (cl == Character.TYPE) {
+                sbuf.append('C');
+            } else if (cl == Boolean.TYPE) {
+                sbuf.append('Z');
+            } else if (cl == Void.TYPE) {
+                sbuf.append('V');
+            } else {
+                throw new InternalError();
+            }
+        } else {
+            sbuf.append('L' + cl.getName().replace('.', '/') + ';');
+        }
+        return sbuf.toString();
+    }
+
+    /**
+     * Returns JVM type signature for given list of parameters and return type.
+     */
+    private static String getMethodSignature(Class<?>[] paramTypes,
+                                             Class<?> retType)
+    {
+        StringBuilder sbuf = new StringBuilder();
+        sbuf.append('(');
+        for (int i = 0; i < paramTypes.length; i++) {
+            sbuf.append(getClassSignature(paramTypes[i]));
+        }
+        sbuf.append(')');
+        sbuf.append(getClassSignature(retType));
+        return sbuf.toString();
+    }
+
+    /**
+     * Convenience method for throwing an exception that is either a
+     * RuntimeException, Error, or of some unexpected type (in which case it is
+     * wrapped inside an IOException).
+     */
+    private static void throwMiscException(Throwable th) throws IOException {
+        if (th instanceof RuntimeException) {
+            throw (RuntimeException) th;
+        } else if (th instanceof Error) {
+            throw (Error) th;
+        } else {
+            IOException ex = new IOException("unexpected exception type");
+            ex.initCause(th);
+            throw ex;
+        }
+    }
+
+    /**
+     * Returns ObjectStreamField array describing the serializable fields of
+     * the given class.  Serializable fields backed by an actual field of the
+     * class are represented by ObjectStreamFields with corresponding non-null
+     * Field objects.  Throws InvalidClassException if the (explicitly
+     * declared) serializable fields are invalid.
+     */
+    private static ObjectStreamField[] getSerialFields(Class<?> cl)
+        throws InvalidClassException
+    {
+        ObjectStreamField[] fields;
+        if (Serializable.class.isAssignableFrom(cl) &&
+            !Externalizable.class.isAssignableFrom(cl) &&
+            !Proxy.isProxyClass(cl) &&
+            !cl.isInterface())
+        {
+            if ((fields = getDeclaredSerialFields(cl)) == null) {
+                fields = getDefaultSerialFields(cl);
+            }
+            Arrays.sort(fields);
+        } else {
+            fields = NO_FIELDS;
+        }
+        return fields;
+    }
+
+    /**
+     * Returns serializable fields of given class as defined explicitly by a
+     * "serialPersistentFields" field, or null if no appropriate
+     * "serialPersistentFields" field is defined.  Serializable fields backed
+     * by an actual field of the class are represented by ObjectStreamFields
+     * with corresponding non-null Field objects.  For compatibility with past
+     * releases, a "serialPersistentFields" field with a null value is
+     * considered equivalent to not declaring "serialPersistentFields".  Throws
+     * InvalidClassException if the declared serializable fields are
+     * invalid--e.g., if multiple fields share the same name.
+     */
+    private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
+        throws InvalidClassException
+    {
+        ObjectStreamField[] serialPersistentFields = null;
+        try {
+            Field f = cl.getDeclaredField("serialPersistentFields");
+            int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
+            if ((f.getModifiers() & mask) == mask) {
+                f.setAccessible(true);
+                serialPersistentFields = (ObjectStreamField[]) f.get(null);
+            }
+        } catch (Exception ex) {
+        }
+        if (serialPersistentFields == null) {
+            return null;
+        } else if (serialPersistentFields.length == 0) {
+            return NO_FIELDS;
+        }
+
+        ObjectStreamField[] boundFields =
+            new ObjectStreamField[serialPersistentFields.length];
+        Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
+
+        for (int i = 0; i < serialPersistentFields.length; i++) {
+            ObjectStreamField spf = serialPersistentFields[i];
+
+            String fname = spf.getName();
+            if (fieldNames.contains(fname)) {
+                throw new InvalidClassException(
+                    "multiple serializable fields named " + fname);
+            }
+            fieldNames.add(fname);
+
+            try {
+                Field f = cl.getDeclaredField(fname);
+                if ((f.getType() == spf.getType()) &&
+                    ((f.getModifiers() & Modifier.STATIC) == 0))
+                {
+                    boundFields[i] =
+                        new ObjectStreamField(f, spf.isUnshared(), true);
+                }
+            } catch (NoSuchFieldException ex) {
+            }
+            if (boundFields[i] == null) {
+                boundFields[i] = new ObjectStreamField(
+                    fname, spf.getType(), spf.isUnshared());
+            }
+        }
+        return boundFields;
+    }
+
+    /**
+     * Returns array of ObjectStreamFields corresponding to all non-static
+     * non-transient fields declared by given class.  Each ObjectStreamField
+     * contains a Field object for the field it represents.  If no default
+     * serializable fields exist, NO_FIELDS is returned.
+     */
+    private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
+        Field[] clFields = cl.getDeclaredFields();
+        ArrayList<ObjectStreamField> list = new ArrayList<>();
+        int mask = Modifier.STATIC | Modifier.TRANSIENT;
+
+        for (int i = 0; i < clFields.length; i++) {
+            if ((clFields[i].getModifiers() & mask) == 0) {
+                list.add(new ObjectStreamField(clFields[i], false, true));
+            }
+        }
+        int size = list.size();
+        return (size == 0) ? NO_FIELDS :
+            list.toArray(new ObjectStreamField[size]);
+    }
+
+    /**
+     * Returns explicit serial version UID value declared by given class, or
+     * null if none.
+     */
+    private static Long getDeclaredSUID(Class<?> cl) {
+        try {
+            Field f = cl.getDeclaredField("serialVersionUID");
+            int mask = Modifier.STATIC | Modifier.FINAL;
+            if ((f.getModifiers() & mask) == mask) {
+                f.setAccessible(true);
+                return Long.valueOf(f.getLong(null));
+            }
+        } catch (Exception ex) {
+        }
+        return null;
+    }
+
+    /**
+     * Computes the default serial version UID value for the given class.
+     */
+    private static long computeDefaultSUID(Class<?> cl) {
+        if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
+        {
+            return 0L;
+        }
+
+        try {
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            DataOutputStream dout = new DataOutputStream(bout);
+
+            dout.writeUTF(cl.getName());
+
+            int classMods = cl.getModifiers() &
+                (Modifier.PUBLIC | Modifier.FINAL |
+                 Modifier.INTERFACE | Modifier.ABSTRACT);
+
+            /*
+             * compensate for javac bug in which ABSTRACT bit was set for an
+             * interface only if the interface declared methods
+             */
+            Method[] methods = cl.getDeclaredMethods();
+            if ((classMods & Modifier.INTERFACE) != 0) {
+                classMods = (methods.length > 0) ?
+                    (classMods | Modifier.ABSTRACT) :
+                    (classMods & ~Modifier.ABSTRACT);
+            }
+            dout.writeInt(classMods);
+
+            if (!cl.isArray()) {
+                /*
+                 * compensate for change in 1.2FCS in which
+                 * Class.getInterfaces() was modified to return Cloneable and
+                 * Serializable for array classes.
+                 */
+                Class<?>[] interfaces = cl.getInterfaces();
+                String[] ifaceNames = new String[interfaces.length];
+                for (int i = 0; i < interfaces.length; i++) {
+                    ifaceNames[i] = interfaces[i].getName();
+                }
+                Arrays.sort(ifaceNames);
+                for (int i = 0; i < ifaceNames.length; i++) {
+                    dout.writeUTF(ifaceNames[i]);
+                }
+            }
+
+            Field[] fields = cl.getDeclaredFields();
+            MemberSignature[] fieldSigs = new MemberSignature[fields.length];
+            for (int i = 0; i < fields.length; i++) {
+                fieldSigs[i] = new MemberSignature(fields[i]);
+            }
+            Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
+                public int compare(MemberSignature ms1, MemberSignature ms2) {
+                    return ms1.name.compareTo(ms2.name);
+                }
+            });
+            for (int i = 0; i < fieldSigs.length; i++) {
+                MemberSignature sig = fieldSigs[i];
+                int mods = sig.member.getModifiers() &
+                    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
+                     Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
+                     Modifier.TRANSIENT);
+                if (((mods & Modifier.PRIVATE) == 0) ||
+                    ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
+                {
+                    dout.writeUTF(sig.name);
+                    dout.writeInt(mods);
+                    dout.writeUTF(sig.signature);
+                }
+            }
+
+            // BEGIN Android-changed: Fix/log clinit serialization workaround b/29064453
+            // Prior to SDK 24 hasStaticInitializer() would return true if the superclass had a
+            // static initializer, that was contrary to the specification. In SDK 24 the default
+            // behavior was corrected but the old behavior was preserved for apps that targeted 23
+            // or below in order to maintain backwards compatibility.
+            //
+            // if (hasStaticInitializer(cl)) {
+            boolean inheritStaticInitializer =
+                (VMRuntime.getRuntime().getTargetSdkVersion()
+                <= MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND);
+            boolean warnIncompatibleSUIDChange = false;
+            if (hasStaticInitializer(cl, inheritStaticInitializer)) {
+                // If a static initializer was found but the current class does not have one then
+                // the class's default SUID will change if the app targets SDK > 24 so send a
+                // warning.
+                if (inheritStaticInitializer && !hasStaticInitializer(cl, false)) {
+                    // Defer until hash has been calculated so the warning message can give precise
+                    // instructions to the developer on how to fix the problems.
+                    warnIncompatibleSUIDChange = true;
+                }
+                // END Android-changed: Fix/log clinit serialization workaround b/29064453
+                dout.writeUTF("<clinit>");
+                dout.writeInt(Modifier.STATIC);
+                dout.writeUTF("()V");
+            }
+
+            Constructor<?>[] cons = cl.getDeclaredConstructors();
+            MemberSignature[] consSigs = new MemberSignature[cons.length];
+            for (int i = 0; i < cons.length; i++) {
+                consSigs[i] = new MemberSignature(cons[i]);
+            }
+            Arrays.sort(consSigs, new Comparator<MemberSignature>() {
+                public int compare(MemberSignature ms1, MemberSignature ms2) {
+                    return ms1.signature.compareTo(ms2.signature);
+                }
+            });
+            for (int i = 0; i < consSigs.length; i++) {
+                MemberSignature sig = consSigs[i];
+                int mods = sig.member.getModifiers() &
+                    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
+                     Modifier.STATIC | Modifier.FINAL |
+                     Modifier.SYNCHRONIZED | Modifier.NATIVE |
+                     Modifier.ABSTRACT | Modifier.STRICT);
+                if ((mods & Modifier.PRIVATE) == 0) {
+                    dout.writeUTF("<init>");
+                    dout.writeInt(mods);
+                    dout.writeUTF(sig.signature.replace('/', '.'));
+                }
+            }
+
+            MemberSignature[] methSigs = new MemberSignature[methods.length];
+            for (int i = 0; i < methods.length; i++) {
+                methSigs[i] = new MemberSignature(methods[i]);
+            }
+            Arrays.sort(methSigs, new Comparator<MemberSignature>() {
+                public int compare(MemberSignature ms1, MemberSignature ms2) {
+                    int comp = ms1.name.compareTo(ms2.name);
+                    if (comp == 0) {
+                        comp = ms1.signature.compareTo(ms2.signature);
+                    }
+                    return comp;
+                }
+            });
+            for (int i = 0; i < methSigs.length; i++) {
+                MemberSignature sig = methSigs[i];
+                int mods = sig.member.getModifiers() &
+                    (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
+                     Modifier.STATIC | Modifier.FINAL |
+                     Modifier.SYNCHRONIZED | Modifier.NATIVE |
+                     Modifier.ABSTRACT | Modifier.STRICT);
+                if ((mods & Modifier.PRIVATE) == 0) {
+                    dout.writeUTF(sig.name);
+                    dout.writeInt(mods);
+                    dout.writeUTF(sig.signature.replace('/', '.'));
+                }
+            }
+
+            dout.flush();
+
+            MessageDigest md = MessageDigest.getInstance("SHA");
+            byte[] hashBytes = md.digest(bout.toByteArray());
+            long hash = 0;
+            for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
+                hash = (hash << 8) | (hashBytes[i] & 0xFF);
+            }
+            // BEGIN Android-added: Fix/log clinit serialization workaround b/29064453
+            // ObjectStreamClass instances are cached per Class and caches its default
+            // serialVersionUID so it will only log one message per class per app process
+            // irrespective of the number of times the class is serialized.
+            if (warnIncompatibleSUIDChange) {
+                suidCompatibilityListener.warnDefaultSUIDTargetVersionDependent(cl, hash);
+            }
+            // END Android-added: Fix/log clinit serialization workaround b/29064453
+            return hash;
+        } catch (IOException ex) {
+            throw new InternalError(ex);
+        } catch (NoSuchAlgorithmException ex) {
+            throw new SecurityException(ex.getMessage());
+        }
+    }
+
+    // BEGIN Android-changed: Fix/log clinit serialization workaround b/29064453
+    /**
+     * Created for testing as there is no nice way to detect when a message is logged.
+     *
+     * @hide
+     */
+    public interface DefaultSUIDCompatibilityListener {
+        /**
+         * Called when a class being serialized/deserialized relies on the default SUID computation
+         * (because it has no explicit {@code serialVersionUID} field) where that computation is
+         * dependent on the app's targetSdkVersion.
+         *
+         * @param clazz the clazz for which the default SUID is being computed.
+         * @param hash the computed value.
+         */
+        void warnDefaultSUIDTargetVersionDependent(Class<?> clazz, long hash);
+    }
+
+    /**
+     * Public and mutable for testing purposes.
+     *
+     * @hide
+     */
+    public static DefaultSUIDCompatibilityListener suidCompatibilityListener =
+        (clazz, hash) -> {
+            System.logW("Class " + clazz.getCanonicalName() + " relies on its default SUID which"
+                + " is dependent on the app's targetSdkVersion. To avoid problems during upgrade"
+                + " add the following to class " + clazz.getCanonicalName() + "\n"
+                + "    private static final long serialVersionUID = " + hash + "L;");
+        };
+
+    /** Max SDK target version for which we use buggy hasStaticInitializer implementation. */
+    static final int MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND = 23;
+
+    /**
+     * Returns true if the given class defines a static initializer method,
+     * false otherwise.
+     *
+     * @param inheritStaticInitializer if false then this method will return true iff the given
+     * class has its own static initializer, if true (used for backwards compatibility for apps
+     * that target SDK version <= {@link #MAX_SDK_TARGET_FOR_CLINIT_UIDGEN_WORKAROUND}) it will
+     * return true if the given class or any of its ancestor classes have a static initializer.
+     */
+    private native static boolean hasStaticInitializer(
+        Class<?> cl, boolean inheritStaticInitializer);
+    // END Android-changed: Fix/log clinit serialization workaround b/29064453
+
+    /**
+     * Class for computing and caching field/constructor/method signatures
+     * during serialVersionUID calculation.
+     */
+    private static class MemberSignature {
+
+        public final Member member;
+        public final String name;
+        public final String signature;
+
+        public MemberSignature(Field field) {
+            member = field;
+            name = field.getName();
+            signature = getClassSignature(field.getType());
+        }
+
+        public MemberSignature(Constructor<?> cons) {
+            member = cons;
+            name = cons.getName();
+            signature = getMethodSignature(
+                cons.getParameterTypes(), Void.TYPE);
+        }
+
+        public MemberSignature(Method meth) {
+            member = meth;
+            name = meth.getName();
+            signature = getMethodSignature(
+                meth.getParameterTypes(), meth.getReturnType());
+        }
+    }
+
+    /**
+     * Class for setting and retrieving serializable field values in batch.
+     */
+    // REMIND: dynamically generate these?
+    private static class FieldReflector {
+
+        /** handle for performing unsafe operations */
+        private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+        /** fields to operate on */
+        private final ObjectStreamField[] fields;
+        /** number of primitive fields */
+        private final int numPrimFields;
+        /** unsafe field keys for reading fields - may contain dupes */
+        private final long[] readKeys;
+        /** unsafe fields keys for writing fields - no dupes */
+        private final long[] writeKeys;
+        /** field data offsets */
+        private final int[] offsets;
+        /** field type codes */
+        private final char[] typeCodes;
+        /** field types */
+        private final Class<?>[] types;
+
+        /**
+         * Constructs FieldReflector capable of setting/getting values from the
+         * subset of fields whose ObjectStreamFields contain non-null
+         * reflective Field objects.  ObjectStreamFields with null Fields are
+         * treated as filler, for which get operations return default values
+         * and set operations discard given values.
+         */
+        FieldReflector(ObjectStreamField[] fields) {
+            this.fields = fields;
+            int nfields = fields.length;
+            readKeys = new long[nfields];
+            writeKeys = new long[nfields];
+            offsets = new int[nfields];
+            typeCodes = new char[nfields];
+            ArrayList<Class<?>> typeList = new ArrayList<>();
+            Set<Long> usedKeys = new HashSet<>();
+
+
+            for (int i = 0; i < nfields; i++) {
+                ObjectStreamField f = fields[i];
+                Field rf = f.getField();
+                long key = (rf != null) ?
+                    unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
+                readKeys[i] = key;
+                writeKeys[i] = usedKeys.add(key) ?
+                    key : Unsafe.INVALID_FIELD_OFFSET;
+                offsets[i] = f.getOffset();
+                typeCodes[i] = f.getTypeCode();
+                if (!f.isPrimitive()) {
+                    typeList.add((rf != null) ? rf.getType() : null);
+                }
+            }
+
+            types = typeList.toArray(new Class<?>[typeList.size()]);
+            numPrimFields = nfields - types.length;
+        }
+
+        /**
+         * Returns list of ObjectStreamFields representing fields operated on
+         * by this reflector.  The shared/unshared values and Field objects
+         * contained by ObjectStreamFields in the list reflect their bindings
+         * to locally defined serializable fields.
+         */
+        ObjectStreamField[] getFields() {
+            return fields;
+        }
+
+        /**
+         * Fetches the serializable primitive field values of object obj and
+         * marshals them into byte array buf starting at offset 0.  The caller
+         * is responsible for ensuring that obj is of the proper type.
+         */
+        void getPrimFieldValues(Object obj, byte[] buf) {
+            if (obj == null) {
+                throw new NullPointerException();
+            }
+            /* assuming checkDefaultSerialize() has been called on the class
+             * descriptor this FieldReflector was obtained from, no field keys
+             * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
+             */
+            for (int i = 0; i < numPrimFields; i++) {
+                long key = readKeys[i];
+                int off = offsets[i];
+                switch (typeCodes[i]) {
+                    case 'Z':
+                        Bits.putBoolean(buf, off, unsafe.getBoolean(obj, key));
+                        break;
+
+                    case 'B':
+                        buf[off] = unsafe.getByte(obj, key);
+                        break;
+
+                    case 'C':
+                        Bits.putChar(buf, off, unsafe.getChar(obj, key));
+                        break;
+
+                    case 'S':
+                        Bits.putShort(buf, off, unsafe.getShort(obj, key));
+                        break;
+
+                    case 'I':
+                        Bits.putInt(buf, off, unsafe.getInt(obj, key));
+                        break;
+
+                    case 'F':
+                        Bits.putFloat(buf, off, unsafe.getFloat(obj, key));
+                        break;
+
+                    case 'J':
+                        Bits.putLong(buf, off, unsafe.getLong(obj, key));
+                        break;
+
+                    case 'D':
+                        Bits.putDouble(buf, off, unsafe.getDouble(obj, key));
+                        break;
+
+                    default:
+                        throw new InternalError();
+                }
+            }
+        }
+
+        /**
+         * Sets the serializable primitive fields of object obj using values
+         * unmarshalled from byte array buf starting at offset 0.  The caller
+         * is responsible for ensuring that obj is of the proper type.
+         */
+        void setPrimFieldValues(Object obj, byte[] buf) {
+            if (obj == null) {
+                throw new NullPointerException();
+            }
+            for (int i = 0; i < numPrimFields; i++) {
+                long key = writeKeys[i];
+                if (key == Unsafe.INVALID_FIELD_OFFSET) {
+                    continue;           // discard value
+                }
+                int off = offsets[i];
+                switch (typeCodes[i]) {
+                    case 'Z':
+                        unsafe.putBoolean(obj, key, Bits.getBoolean(buf, off));
+                        break;
+
+                    case 'B':
+                        unsafe.putByte(obj, key, buf[off]);
+                        break;
+
+                    case 'C':
+                        unsafe.putChar(obj, key, Bits.getChar(buf, off));
+                        break;
+
+                    case 'S':
+                        unsafe.putShort(obj, key, Bits.getShort(buf, off));
+                        break;
+
+                    case 'I':
+                        unsafe.putInt(obj, key, Bits.getInt(buf, off));
+                        break;
+
+                    case 'F':
+                        unsafe.putFloat(obj, key, Bits.getFloat(buf, off));
+                        break;
+
+                    case 'J':
+                        unsafe.putLong(obj, key, Bits.getLong(buf, off));
+                        break;
+
+                    case 'D':
+                        unsafe.putDouble(obj, key, Bits.getDouble(buf, off));
+                        break;
+
+                    default:
+                        throw new InternalError();
+                }
+            }
+        }
+
+        /**
+         * Fetches the serializable object field values of object obj and
+         * stores them in array vals starting at offset 0.  The caller is
+         * responsible for ensuring that obj is of the proper type.
+         */
+        void getObjFieldValues(Object obj, Object[] vals) {
+            if (obj == null) {
+                throw new NullPointerException();
+            }
+            /* assuming checkDefaultSerialize() has been called on the class
+             * descriptor this FieldReflector was obtained from, no field keys
+             * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
+             */
+            for (int i = numPrimFields; i < fields.length; i++) {
+                switch (typeCodes[i]) {
+                    case 'L':
+                    case '[':
+                        vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]);
+                        break;
+
+                    default:
+                        throw new InternalError();
+                }
+            }
+        }
+
+        /**
+         * Sets the serializable object fields of object obj using values from
+         * array vals starting at offset 0.  The caller is responsible for
+         * ensuring that obj is of the proper type; however, attempts to set a
+         * field with a value of the wrong type will trigger an appropriate
+         * ClassCastException.
+         */
+        void setObjFieldValues(Object obj, Object[] vals) {
+            if (obj == null) {
+                throw new NullPointerException();
+            }
+            for (int i = numPrimFields; i < fields.length; i++) {
+                long key = writeKeys[i];
+                if (key == Unsafe.INVALID_FIELD_OFFSET) {
+                    continue;           // discard value
+                }
+                switch (typeCodes[i]) {
+                    case 'L':
+                    case '[':
+                        Object val = vals[offsets[i]];
+                        if (val != null &&
+                            !types[i - numPrimFields].isInstance(val))
+                        {
+                            Field f = fields[i].getField();
+                            throw new ClassCastException(
+                                "cannot assign instance of " +
+                                val.getClass().getName() + " to field " +
+                                f.getDeclaringClass().getName() + "." +
+                                f.getName() + " of type " +
+                                f.getType().getName() + " in instance of " +
+                                obj.getClass().getName());
+                        }
+                        unsafe.putObject(obj, key, val);
+                        break;
+
+                    default:
+                        throw new InternalError();
+                }
+            }
+        }
+    }
+
+    /**
+     * Matches given set of serializable fields with serializable fields
+     * described by the given local class descriptor, and returns a
+     * FieldReflector instance capable of setting/getting values from the
+     * subset of fields that match (non-matching fields are treated as filler,
+     * for which get operations return default values and set operations
+     * discard given values).  Throws InvalidClassException if unresolvable
+     * type conflicts exist between the two sets of fields.
+     */
+    private static FieldReflector getReflector(ObjectStreamField[] fields,
+                                               ObjectStreamClass localDesc)
+        throws InvalidClassException
+    {
+        // class irrelevant if no fields
+        Class<?> cl = (localDesc != null && fields.length > 0) ?
+            localDesc.cl : null;
+        processQueue(Caches.reflectorsQueue, Caches.reflectors);
+        FieldReflectorKey key = new FieldReflectorKey(cl, fields,
+                                                      Caches.reflectorsQueue);
+        Reference<?> ref = Caches.reflectors.get(key);
+        Object entry = null;
+        if (ref != null) {
+            entry = ref.get();
+        }
+        EntryFuture future = null;
+        if (entry == null) {
+            EntryFuture newEntry = new EntryFuture();
+            Reference<?> newRef = new SoftReference<>(newEntry);
+            do {
+                if (ref != null) {
+                    Caches.reflectors.remove(key, ref);
+                }
+                ref = Caches.reflectors.putIfAbsent(key, newRef);
+                if (ref != null) {
+                    entry = ref.get();
+                }
+            } while (ref != null && entry == null);
+            if (entry == null) {
+                future = newEntry;
+            }
+        }
+
+        if (entry instanceof FieldReflector) {  // check common case first
+            return (FieldReflector) entry;
+        } else if (entry instanceof EntryFuture) {
+            entry = ((EntryFuture) entry).get();
+        } else if (entry == null) {
+            try {
+                entry = new FieldReflector(matchFields(fields, localDesc));
+            } catch (Throwable th) {
+                entry = th;
+            }
+            future.set(entry);
+            Caches.reflectors.put(key, new SoftReference<Object>(entry));
+        }
+
+        if (entry instanceof FieldReflector) {
+            return (FieldReflector) entry;
+        } else if (entry instanceof InvalidClassException) {
+            throw (InvalidClassException) entry;
+        } else if (entry instanceof RuntimeException) {
+            throw (RuntimeException) entry;
+        } else if (entry instanceof Error) {
+            throw (Error) entry;
+        } else {
+            throw new InternalError("unexpected entry: " + entry);
+        }
+    }
+
+    /**
+     * FieldReflector cache lookup key.  Keys are considered equal if they
+     * refer to the same class and equivalent field formats.
+     */
+    private static class FieldReflectorKey extends WeakReference<Class<?>> {
+
+        private final String sigs;
+        private final int hash;
+        private final boolean nullClass;
+
+        FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
+                          ReferenceQueue<Class<?>> queue)
+        {
+            super(cl, queue);
+            nullClass = (cl == null);
+            StringBuilder sbuf = new StringBuilder();
+            for (int i = 0; i < fields.length; i++) {
+                ObjectStreamField f = fields[i];
+                sbuf.append(f.getName()).append(f.getSignature());
+            }
+            sigs = sbuf.toString();
+            hash = System.identityHashCode(cl) + sigs.hashCode();
+        }
+
+        public int hashCode() {
+            return hash;
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+
+            if (obj instanceof FieldReflectorKey) {
+                FieldReflectorKey other = (FieldReflectorKey) obj;
+                Class<?> referent;
+                return (nullClass ? other.nullClass
+                                  : ((referent = get()) != null) &&
+                                    (referent == other.get())) &&
+                    sigs.equals(other.sigs);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Matches given set of serializable fields with serializable fields
+     * obtained from the given local class descriptor (which contain bindings
+     * to reflective Field objects).  Returns list of ObjectStreamFields in
+     * which each ObjectStreamField whose signature matches that of a local
+     * field contains a Field object for that field; unmatched
+     * ObjectStreamFields contain null Field objects.  Shared/unshared settings
+     * of the returned ObjectStreamFields also reflect those of matched local
+     * ObjectStreamFields.  Throws InvalidClassException if unresolvable type
+     * conflicts exist between the two sets of fields.
+     */
+    private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
+                                                   ObjectStreamClass localDesc)
+        throws InvalidClassException
+    {
+        ObjectStreamField[] localFields = (localDesc != null) ?
+            localDesc.fields : NO_FIELDS;
+
+        /*
+         * Even if fields == localFields, we cannot simply return localFields
+         * here.  In previous implementations of serialization,
+         * ObjectStreamField.getType() returned Object.class if the
+         * ObjectStreamField represented a non-primitive field and belonged to
+         * a non-local class descriptor.  To preserve this (questionable)
+         * behavior, the ObjectStreamField instances returned by matchFields
+         * cannot report non-primitive types other than Object.class; hence
+         * localFields cannot be returned directly.
+         */
+
+        ObjectStreamField[] matches = new ObjectStreamField[fields.length];
+        for (int i = 0; i < fields.length; i++) {
+            ObjectStreamField f = fields[i], m = null;
+            for (int j = 0; j < localFields.length; j++) {
+                ObjectStreamField lf = localFields[j];
+                // Android-changed: We can have fields with a same name and a different type.
+                if (f.getName().equals(lf.getName()) &&
+                    f.getSignature().equals(lf.getSignature())) {
+                    if (lf.getField() != null) {
+                        m = new ObjectStreamField(
+                            lf.getField(), lf.isUnshared(), false);
+                    } else {
+                        m = new ObjectStreamField(
+                            lf.getName(), lf.getSignature(), lf.isUnshared());
+                    }
+                }
+            }
+            if (m == null) {
+                m = new ObjectStreamField(
+                    f.getName(), f.getSignature(), false);
+            }
+            m.setOffset(f.getOffset());
+            matches[i] = m;
+        }
+        return matches;
+    }
+    // BEGIN Android-added: Keep some private API for app compat. b/28283540.
+    // NOTE: The following couple of methods are left here because frameworks such as objenesis
+    // use them.
+    //
+    // **** THESE METHODS WILL BE REMOVED IN A FUTURE ANDROID RELEASE ****.
+    //
+    private static long getConstructorId(Class<?> clazz) {
+        final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+            System.logE("WARNING: ObjectStreamClass.getConstructorId(Class<?>) is private API and" +
+                        "will be removed in a future Android release.");
+            // NOTE: This method is a stub that returns a fixed value. It's meant to be used
+            // with newInstance(Class<?>, long) and our current implementation of that method ignores
+            // the "constructorId" argument. We return :
+            //
+            // oh one one eight nine nine nine
+            // eight eight one nine nine
+            // nine one one nine seven two five
+            // three
+            //
+            // in all cases.
+            return 1189998819991197253L;
+        }
+
+        throw new UnsupportedOperationException("ObjectStreamClass.getConstructorId(Class<?>) is " +
+                                                "not supported on SDK " + targetSdkVersion);
+    }
+    private static Object newInstance(Class<?> clazz, long constructorId) {
+        final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+            System.logE("WARNING: ObjectStreamClass.newInstance(Class<?>, long) is private API and" +
+                        "will be removed in a future Android release.");
+            return sun.misc.Unsafe.getUnsafe().allocateInstance(clazz);
+        }
+
+        throw new UnsupportedOperationException("ObjectStreamClass.newInstance(Class<?>, long) " +
+                                                "is not supported on SDK " + targetSdkVersion);
+    }
+    // END Android-added: Keep some private API for app compat. b/28283540.
+
+    /**
+     * Removes from the specified map any keys that have been enqueued
+     * on the specified reference queue.
+     */
+    static void processQueue(ReferenceQueue<Class<?>> queue,
+                             ConcurrentMap<? extends
+                             WeakReference<Class<?>>, ?> map)
+    {
+        Reference<? extends Class<?>> ref;
+        while((ref = queue.poll()) != null) {
+            map.remove(ref);
+        }
+    }
+
+    /**
+     *  Weak key for Class objects.
+     *
+     **/
+    static class WeakClassKey extends WeakReference<Class<?>> {
+        /**
+         * saved value of the referent's identity hash code, to maintain
+         * a consistent hash code after the referent has been cleared
+         */
+        private final int hash;
+
+        /**
+         * Create a new WeakClassKey to the given object, registered
+         * with a queue.
+         */
+        WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
+            super(cl, refQueue);
+            hash = System.identityHashCode(cl);
+        }
+
+        /**
+         * Returns the identity hash code of the original referent.
+         */
+        public int hashCode() {
+            return hash;
+        }
+
+        /**
+         * Returns true if the given object is this identical
+         * WeakClassKey instance, or, if this object's referent has not
+         * been cleared, if the given object is another WeakClassKey
+         * instance with the identical non-null referent as this one.
+         */
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+
+            if (obj instanceof WeakClassKey) {
+                Object referent = get();
+                return (referent != null) &&
+                       (referent == ((WeakClassKey) obj).get());
+            } else {
+                return false;
+            }
+        }
+    }
+}
diff --git a/java/io/ObjectStreamConstants.java b/java/io/ObjectStreamConstants.java
new file mode 100644
index 0000000..23f72b4
--- /dev/null
+++ b/java/io/ObjectStreamConstants.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Constants written into the Object Serialization Stream.
+ *
+ * @author  unascribed
+ * @since JDK 1.1
+ */
+public interface ObjectStreamConstants {
+
+    /**
+     * Magic number that is written to the stream header.
+     */
+    final static short STREAM_MAGIC = (short)0xaced;
+
+    /**
+     * Version number that is written to the stream header.
+     */
+    final static short STREAM_VERSION = 5;
+
+    /* Each item in the stream is preceded by a tag
+     */
+
+    /**
+     * First tag value.
+     */
+    final static byte TC_BASE = 0x70;
+
+    /**
+     * Null object reference.
+     */
+    final static byte TC_NULL =         (byte)0x70;
+
+    /**
+     * Reference to an object already written into the stream.
+     */
+    final static byte TC_REFERENCE =    (byte)0x71;
+
+    /**
+     * new Class Descriptor.
+     */
+    final static byte TC_CLASSDESC =    (byte)0x72;
+
+    /**
+     * new Object.
+     */
+    final static byte TC_OBJECT =       (byte)0x73;
+
+    /**
+     * new String.
+     */
+    final static byte TC_STRING =       (byte)0x74;
+
+    /**
+     * new Array.
+     */
+    final static byte TC_ARRAY =        (byte)0x75;
+
+    /**
+     * Reference to Class.
+     */
+    final static byte TC_CLASS =        (byte)0x76;
+
+    /**
+     * Block of optional data. Byte following tag indicates number
+     * of bytes in this block data.
+     */
+    final static byte TC_BLOCKDATA =    (byte)0x77;
+
+    /**
+     * End of optional block data blocks for an object.
+     */
+    final static byte TC_ENDBLOCKDATA = (byte)0x78;
+
+    /**
+     * Reset stream context. All handles written into stream are reset.
+     */
+    final static byte TC_RESET =        (byte)0x79;
+
+    /**
+     * long Block data. The long following the tag indicates the
+     * number of bytes in this block data.
+     */
+    final static byte TC_BLOCKDATALONG= (byte)0x7A;
+
+    /**
+     * Exception during write.
+     */
+    final static byte TC_EXCEPTION =    (byte)0x7B;
+
+    /**
+     * Long string.
+     */
+    final static byte TC_LONGSTRING =   (byte)0x7C;
+
+    /**
+     * new Proxy Class Descriptor.
+     */
+    final static byte TC_PROXYCLASSDESC =       (byte)0x7D;
+
+    /**
+     * new Enum constant.
+     * @since 1.5
+     */
+    final static byte TC_ENUM =         (byte)0x7E;
+
+    /**
+     * Last tag value.
+     */
+    final static byte TC_MAX =          (byte)0x7E;
+
+    /**
+     * First wire handle to be assigned.
+     */
+    final static int baseWireHandle = 0x7e0000;
+
+
+    /******************************************************/
+    /* Bit masks for ObjectStreamClass flag.*/
+
+    /**
+     * Bit mask for ObjectStreamClass flag. Indicates a Serializable class
+     * defines its own writeObject method.
+     */
+    final static byte SC_WRITE_METHOD = 0x01;
+
+    /**
+     * Bit mask for ObjectStreamClass flag. Indicates Externalizable data
+     * written in Block Data mode.
+     * Added for PROTOCOL_VERSION_2.
+     *
+     * @see #PROTOCOL_VERSION_2
+     * @since 1.2
+     */
+    final static byte SC_BLOCK_DATA = 0x08;
+
+    /**
+     * Bit mask for ObjectStreamClass flag. Indicates class is Serializable.
+     */
+    final static byte SC_SERIALIZABLE = 0x02;
+
+    /**
+     * Bit mask for ObjectStreamClass flag. Indicates class is Externalizable.
+     */
+    final static byte SC_EXTERNALIZABLE = 0x04;
+
+    /**
+     * Bit mask for ObjectStreamClass flag. Indicates class is an enum type.
+     * @since 1.5
+     */
+    final static byte SC_ENUM = 0x10;
+
+
+    /* *******************************************************************/
+    /* Security permissions */
+
+    /**
+     * Enable substitution of one object for another during
+     * serialization/deserialization.
+     *
+     * @see java.io.ObjectOutputStream#enableReplaceObject(boolean)
+     * @see java.io.ObjectInputStream#enableResolveObject(boolean)
+     * @since 1.2
+     */
+    final static SerializablePermission SUBSTITUTION_PERMISSION =
+                           new SerializablePermission("enableSubstitution");
+
+    /**
+     * Enable overriding of readObject and writeObject.
+     *
+     * @see java.io.ObjectOutputStream#writeObjectOverride(Object)
+     * @see java.io.ObjectInputStream#readObjectOverride()
+     * @since 1.2
+     */
+    final static SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
+                    new SerializablePermission("enableSubclassImplementation");
+   /**
+    * A Stream Protocol Version. <p>
+    *
+    * All externalizable data is written in JDK 1.1 external data
+    * format after calling this method. This version is needed to write
+    * streams containing Externalizable data that can be read by
+    * pre-JDK 1.1.6 JVMs.
+    *
+    * @see java.io.ObjectOutputStream#useProtocolVersion(int)
+    * @since 1.2
+    */
+    public final static int PROTOCOL_VERSION_1 = 1;
+
+
+   /**
+    * A Stream Protocol Version. <p>
+    *
+    * This protocol is written by JVM 1.2.
+    *
+    * Externalizable data is written in block data mode and is
+    * terminated with TC_ENDBLOCKDATA. Externalizable class descriptor
+    * flags has SC_BLOCK_DATA enabled. JVM 1.1.6 and greater can
+    * read this format change.
+    *
+    * Enables writing a nonSerializable class descriptor into the
+    * stream. The serialVersionUID of a nonSerializable class is
+    * set to 0L.
+    *
+    * @see java.io.ObjectOutputStream#useProtocolVersion(int)
+    * @see #SC_BLOCK_DATA
+    * @since 1.2
+    */
+    public final static int PROTOCOL_VERSION_2 = 2;
+}
diff --git a/java/io/ObjectStreamException.java b/java/io/ObjectStreamException.java
new file mode 100644
index 0000000..889cad3
--- /dev/null
+++ b/java/io/ObjectStreamException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Superclass of all exceptions specific to Object Stream classes.
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public abstract class ObjectStreamException extends IOException {
+
+    private static final long serialVersionUID = 7260898174833392607L;
+
+    /**
+     * Create an ObjectStreamException with the specified argument.
+     *
+     * @param classname the detailed message for the exception
+     */
+    protected ObjectStreamException(String classname) {
+        super(classname);
+    }
+
+    /**
+     * Create an ObjectStreamException.
+     */
+    protected ObjectStreamException() {
+        super();
+    }
+}
diff --git a/java/io/ObjectStreamField.java b/java/io/ObjectStreamField.java
new file mode 100644
index 0000000..d26535f
--- /dev/null
+++ b/java/io/ObjectStreamField.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.lang.reflect.Field;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.reflect.misc.ReflectUtil;
+
+/**
+ * A description of a Serializable field from a Serializable class.  An array
+ * of ObjectStreamFields is used to declare the Serializable fields of a class.
+ *
+ * @author      Mike Warres
+ * @author      Roger Riggs
+ * @see ObjectStreamClass
+ * @since 1.2
+ */
+public class ObjectStreamField
+    implements Comparable<Object>
+{
+
+    /** field name */
+    private final String name;
+    /** canonical JVM signature of field type */
+    private final String signature;
+    /** field type (Object.class if unknown non-primitive type) */
+    private final Class<?> type;
+    /** whether or not to (de)serialize field values as unshared */
+    private final boolean unshared;
+    /** corresponding reflective field object, if any */
+    private final Field field;
+    /** offset of field value in enclosing field group */
+    private int offset = 0;
+
+    /**
+     * Create a Serializable field with the specified type.  This field should
+     * be documented with a <code>serialField</code> tag.
+     *
+     * @param   name the name of the serializable field
+     * @param   type the <code>Class</code> object of the serializable field
+     */
+    public ObjectStreamField(String name, Class<?> type) {
+        this(name, type, false);
+    }
+
+    /**
+     * Creates an ObjectStreamField representing a serializable field with the
+     * given name and type.  If unshared is false, values of the represented
+     * field are serialized and deserialized in the default manner--if the
+     * field is non-primitive, object values are serialized and deserialized as
+     * if they had been written and read by calls to writeObject and
+     * readObject.  If unshared is true, values of the represented field are
+     * serialized and deserialized as if they had been written and read by
+     * calls to writeUnshared and readUnshared.
+     *
+     * @param   name field name
+     * @param   type field type
+     * @param   unshared if false, write/read field values in the same manner
+     *          as writeObject/readObject; if true, write/read in the same
+     *          manner as writeUnshared/readUnshared
+     * @since   1.4
+     */
+    public ObjectStreamField(String name, Class<?> type, boolean unshared) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        this.name = name;
+        this.type = type;
+        this.unshared = unshared;
+        signature = getClassSignature(type).intern();
+        field = null;
+    }
+
+    /**
+     * Creates an ObjectStreamField representing a field with the given name,
+     * signature and unshared setting.
+     */
+    ObjectStreamField(String name, String signature, boolean unshared) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        this.name = name;
+        this.signature = signature.intern();
+        this.unshared = unshared;
+        field = null;
+
+        switch (signature.charAt(0)) {
+            case 'Z': type = Boolean.TYPE; break;
+            case 'B': type = Byte.TYPE; break;
+            case 'C': type = Character.TYPE; break;
+            case 'S': type = Short.TYPE; break;
+            case 'I': type = Integer.TYPE; break;
+            case 'J': type = Long.TYPE; break;
+            case 'F': type = Float.TYPE; break;
+            case 'D': type = Double.TYPE; break;
+            case 'L':
+            case '[': type = Object.class; break;
+            default: throw new IllegalArgumentException("illegal signature");
+        }
+    }
+
+    /**
+     * Creates an ObjectStreamField representing the given field with the
+     * specified unshared setting.  For compatibility with the behavior of
+     * earlier serialization implementations, a "showType" parameter is
+     * necessary to govern whether or not a getType() call on this
+     * ObjectStreamField (if non-primitive) will return Object.class (as
+     * opposed to a more specific reference type).
+     */
+    ObjectStreamField(Field field, boolean unshared, boolean showType) {
+        this.field = field;
+        this.unshared = unshared;
+        name = field.getName();
+        Class<?> ftype = field.getType();
+        type = (showType || ftype.isPrimitive()) ? ftype : Object.class;
+        signature = getClassSignature(ftype).intern();
+    }
+
+    /**
+     * Get the name of this field.
+     *
+     * @return  a <code>String</code> representing the name of the serializable
+     *          field
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Get the type of the field.  If the type is non-primitive and this
+     * <code>ObjectStreamField</code> was obtained from a deserialized {@link
+     * ObjectStreamClass} instance, then <code>Object.class</code> is returned.
+     * Otherwise, the <code>Class</code> object for the type of the field is
+     * returned.
+     *
+     * @return  a <code>Class</code> object representing the type of the
+     *          serializable field
+     */
+    @CallerSensitive
+    public Class<?> getType() {
+        // BEGIN Android-removed: Security manager is always null on Android.
+        /*
+        if (System.getSecurityManager() != null) {
+            Class<?> caller = Reflection.getCallerClass();
+            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) {
+                ReflectUtil.checkPackageAccess(type);
+            }
+        }
+        */
+        // END Android-removed: Security manager is always null on Android.
+        return type;
+    }
+
+    /**
+     * Returns character encoding of field type.  The encoding is as follows:
+     * <blockquote><pre>
+     * B            byte
+     * C            char
+     * D            double
+     * F            float
+     * I            int
+     * J            long
+     * L            class or interface
+     * S            short
+     * Z            boolean
+     * [            array
+     * </pre></blockquote>
+     *
+     * @return  the typecode of the serializable field
+     */
+    // REMIND: deprecate?
+    public char getTypeCode() {
+        return signature.charAt(0);
+    }
+
+    /**
+     * Return the JVM type signature.
+     *
+     * @return  null if this field has a primitive type.
+     */
+    // REMIND: deprecate?
+    public String getTypeString() {
+        return isPrimitive() ? null : signature;
+    }
+
+    /**
+     * Offset of field within instance data.
+     *
+     * @return  the offset of this field
+     * @see #setOffset
+     */
+    // REMIND: deprecate?
+    public int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Offset within instance data.
+     *
+     * @param   offset the offset of the field
+     * @see #getOffset
+     */
+    // REMIND: deprecate?
+    protected void setOffset(int offset) {
+        this.offset = offset;
+    }
+
+    /**
+     * Return true if this field has a primitive type.
+     *
+     * @return  true if and only if this field corresponds to a primitive type
+     */
+    // REMIND: deprecate?
+    public boolean isPrimitive() {
+        char tcode = signature.charAt(0);
+        return ((tcode != 'L') && (tcode != '['));
+    }
+
+    /**
+     * Returns boolean value indicating whether or not the serializable field
+     * represented by this ObjectStreamField instance is unshared.
+     *
+     * @return {@code true} if this field is unshared
+     *
+     * @since 1.4
+     */
+    public boolean isUnshared() {
+        return unshared;
+    }
+
+    /**
+     * Compare this field with another <code>ObjectStreamField</code>.  Return
+     * -1 if this is smaller, 0 if equal, 1 if greater.  Types that are
+     * primitives are "smaller" than object types.  If equal, the field names
+     * are compared.
+     */
+    // REMIND: deprecate?
+    public int compareTo(Object obj) {
+        ObjectStreamField other = (ObjectStreamField) obj;
+        boolean isPrim = isPrimitive();
+        if (isPrim != other.isPrimitive()) {
+            return isPrim ? -1 : 1;
+        }
+        return name.compareTo(other.name);
+    }
+
+    /**
+     * Return a string that describes this field.
+     */
+    public String toString() {
+        return signature + ' ' + name;
+    }
+
+    /**
+     * Returns field represented by this ObjectStreamField, or null if
+     * ObjectStreamField is not associated with an actual field.
+     */
+    Field getField() {
+        return field;
+    }
+
+    /**
+     * Returns JVM type signature of field (similar to getTypeString, except
+     * that signature strings are returned for primitive fields as well).
+     */
+    String getSignature() {
+        return signature;
+    }
+
+    /**
+     * Returns JVM type signature for given class.
+     */
+    private static String getClassSignature(Class<?> cl) {
+        StringBuilder sbuf = new StringBuilder();
+        while (cl.isArray()) {
+            sbuf.append('[');
+            cl = cl.getComponentType();
+        }
+        if (cl.isPrimitive()) {
+            if (cl == Integer.TYPE) {
+                sbuf.append('I');
+            } else if (cl == Byte.TYPE) {
+                sbuf.append('B');
+            } else if (cl == Long.TYPE) {
+                sbuf.append('J');
+            } else if (cl == Float.TYPE) {
+                sbuf.append('F');
+            } else if (cl == Double.TYPE) {
+                sbuf.append('D');
+            } else if (cl == Short.TYPE) {
+                sbuf.append('S');
+            } else if (cl == Character.TYPE) {
+                sbuf.append('C');
+            } else if (cl == Boolean.TYPE) {
+                sbuf.append('Z');
+            } else if (cl == Void.TYPE) {
+                sbuf.append('V');
+            } else {
+                throw new InternalError();
+            }
+        } else {
+            sbuf.append('L' + cl.getName().replace('.', '/') + ';');
+        }
+        return sbuf.toString();
+    }
+}
diff --git a/java/io/OptionalDataException.java b/java/io/OptionalDataException.java
new file mode 100644
index 0000000..91283fd
--- /dev/null
+++ b/java/io/OptionalDataException.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+/**
+ * Exception indicating the failure of an object read operation due to
+ * unread primitive data, or the end of data belonging to a serialized
+ * object in the stream.  This exception may be thrown in two cases:
+ *
+ * <ul>
+ *   <li>An attempt was made to read an object when the next element in the
+ *       stream is primitive data.  In this case, the OptionalDataException's
+ *       length field is set to the number of bytes of primitive data
+ *       immediately readable from the stream, and the eof field is set to
+ *       false.
+ *
+ *   <li>An attempt was made to read past the end of data consumable by a
+ *       class-defined readObject or readExternal method.  In this case, the
+ *       OptionalDataException's eof field is set to true, and the length field
+ *       is set to 0.
+ * </ul>
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class OptionalDataException extends ObjectStreamException {
+
+    private static final long serialVersionUID = -8011121865681257820L;
+
+    /*
+     * Create an <code>OptionalDataException</code> with a length.
+     */
+    OptionalDataException(int len) {
+        eof = false;
+        length = len;
+    }
+
+    /*
+     * Create an <code>OptionalDataException</code> signifying no
+     * more primitive data is available.
+     */
+    OptionalDataException(boolean end) {
+        length = 0;
+        eof = end;
+    }
+
+    /**
+     * The number of bytes of primitive data available to be read
+     * in the current buffer.
+     *
+     * @serial
+     */
+    public int length;
+
+    /**
+     * True if there is no more data in the buffered part of the stream.
+     *
+     * @serial
+     */
+    public boolean eof;
+}
diff --git a/java/io/OutputStream.java b/java/io/OutputStream.java
new file mode 100644
index 0000000..c6dd7de
--- /dev/null
+++ b/java/io/OutputStream.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This abstract class is the superclass of all classes representing
+ * an output stream of bytes. An output stream accepts output bytes
+ * and sends them to some sink.
+ * <p>
+ * Applications that need to define a subclass of
+ * <code>OutputStream</code> must always provide at least a method
+ * that writes one byte of output.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.io.BufferedOutputStream
+ * @see     java.io.ByteArrayOutputStream
+ * @see     java.io.DataOutputStream
+ * @see     java.io.FilterOutputStream
+ * @see     java.io.InputStream
+ * @see     java.io.OutputStream#write(int)
+ * @since   JDK1.0
+ */
+public abstract class OutputStream implements Closeable, Flushable {
+    /**
+     * Writes the specified byte to this output stream. The general
+     * contract for <code>write</code> is that one byte is written
+     * to the output stream. The byte to be written is the eight
+     * low-order bits of the argument <code>b</code>. The 24
+     * high-order bits of <code>b</code> are ignored.
+     * <p>
+     * Subclasses of <code>OutputStream</code> must provide an
+     * implementation for this method.
+     *
+     * @param      b   the <code>byte</code>.
+     * @exception  IOException  if an I/O error occurs. In particular,
+     *             an <code>IOException</code> may be thrown if the
+     *             output stream has been closed.
+     */
+    public abstract void write(int b) throws IOException;
+
+    /**
+     * Writes <code>b.length</code> bytes from the specified byte array
+     * to this output stream. The general contract for <code>write(b)</code>
+     * is that it should have exactly the same effect as the call
+     * <code>write(b, 0, b.length)</code>.
+     *
+     * @param      b   the data.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.OutputStream#write(byte[], int, int)
+     */
+    public void write(byte b[]) throws IOException {
+        write(b, 0, b.length);
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to this output stream.
+     * The general contract for <code>write(b, off, len)</code> is that
+     * some of the bytes in the array <code>b</code> are written to the
+     * output stream in order; element <code>b[off]</code> is the first
+     * byte written and <code>b[off+len-1]</code> is the last byte written
+     * by this operation.
+     * <p>
+     * The <code>write</code> method of <code>OutputStream</code> calls
+     * the write method of one argument on each of the bytes to be
+     * written out. Subclasses are encouraged to override this method and
+     * provide a more efficient implementation.
+     * <p>
+     * If <code>b</code> is <code>null</code>, a
+     * <code>NullPointerException</code> is thrown.
+     * <p>
+     * If <code>off</code> is negative, or <code>len</code> is negative, or
+     * <code>off+len</code> is greater than the length of the array
+     * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs. In particular,
+     *             an <code>IOException</code> is thrown if the output
+     *             stream is closed.
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if ((off < 0) || (off > b.length) || (len < 0) ||
+                   ((off + len) > b.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        for (int i = 0 ; i < len ; i++) {
+            write(b[off + i]);
+        }
+    }
+
+    /**
+     * Flushes this output stream and forces any buffered output bytes
+     * to be written out. The general contract of <code>flush</code> is
+     * that calling it is an indication that, if any bytes previously
+     * written have been buffered by the implementation of the output
+     * stream, such bytes should immediately be written to their
+     * intended destination.
+     * <p>
+     * If the intended destination of this stream is an abstraction provided by
+     * the underlying operating system, for example a file, then flushing the
+     * stream guarantees only that bytes previously written to the stream are
+     * passed to the operating system for writing; it does not guarantee that
+     * they are actually written to a physical device such as a disk drive.
+     * <p>
+     * The <code>flush</code> method of <code>OutputStream</code> does nothing.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void flush() throws IOException {
+    }
+
+    /**
+     * Closes this output stream and releases any system resources
+     * associated with this stream. The general contract of <code>close</code>
+     * is that it closes the output stream. A closed stream cannot perform
+     * output operations and cannot be reopened.
+     * <p>
+     * The <code>close</code> method of <code>OutputStream</code> does nothing.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close() throws IOException {
+    }
+
+}
diff --git a/java/io/OutputStreamWriter.java b/java/io/OutputStreamWriter.java
new file mode 100644
index 0000000..5f7b9e3
--- /dev/null
+++ b/java/io/OutputStreamWriter.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import sun.nio.cs.StreamEncoder;
+
+
+/**
+ * An OutputStreamWriter is a bridge from character streams to byte streams:
+ * Characters written to it are encoded into bytes using a specified {@link
+ * java.nio.charset.Charset charset}.  The charset that it uses
+ * may be specified by name or may be given explicitly, or the platform's
+ * default charset may be accepted.
+ *
+ * <p> Each invocation of a write() method causes the encoding converter to be
+ * invoked on the given character(s).  The resulting bytes are accumulated in a
+ * buffer before being written to the underlying output stream.  The size of
+ * this buffer may be specified, but by default it is large enough for most
+ * purposes.  Note that the characters passed to the write() methods are not
+ * buffered.
+ *
+ * <p> For top efficiency, consider wrapping an OutputStreamWriter within a
+ * BufferedWriter so as to avoid frequent converter invocations.  For example:
+ *
+ * <pre>
+ * Writer out
+ *   = new BufferedWriter(new OutputStreamWriter(System.out));
+ * </pre>
+ *
+ * <p> A <i>surrogate pair</i> is a character represented by a sequence of two
+ * <tt>char</tt> values: A <i>high</i> surrogate in the range '&#92;uD800' to
+ * '&#92;uDBFF' followed by a <i>low</i> surrogate in the range '&#92;uDC00' to
+ * '&#92;uDFFF'.
+ *
+ * <p> A <i>malformed surrogate element</i> is a high surrogate that is not
+ * followed by a low surrogate or a low surrogate that is not preceded by a
+ * high surrogate.
+ *
+ * <p> This class always replaces malformed surrogate elements and unmappable
+ * character sequences with the charset's default <i>substitution sequence</i>.
+ * The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
+ * control over the encoding process is required.
+ *
+ * @see BufferedWriter
+ * @see OutputStream
+ * @see java.nio.charset.Charset
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class OutputStreamWriter extends Writer {
+
+    private final StreamEncoder se;
+
+    /**
+     * Creates an OutputStreamWriter that uses the named charset.
+     *
+     * @param  out
+     *         An OutputStream
+     *
+     * @param  charsetName
+     *         The name of a supported
+     *         {@link java.nio.charset.Charset charset}
+     *
+     * @exception  UnsupportedEncodingException
+     *             If the named encoding is not supported
+     */
+    public OutputStreamWriter(OutputStream out, String charsetName)
+        throws UnsupportedEncodingException
+    {
+        super(out);
+        if (charsetName == null)
+            throw new NullPointerException("charsetName");
+        se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
+    }
+
+    /**
+     * Creates an OutputStreamWriter that uses the default character encoding.
+     *
+     * @param  out  An OutputStream
+     */
+    public OutputStreamWriter(OutputStream out) {
+        super(out);
+        try {
+            se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
+        } catch (UnsupportedEncodingException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * Creates an OutputStreamWriter that uses the given charset.
+     *
+     * @param  out
+     *         An OutputStream
+     *
+     * @param  cs
+     *         A charset
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public OutputStreamWriter(OutputStream out, Charset cs) {
+        super(out);
+        if (cs == null)
+            throw new NullPointerException("charset");
+        se = StreamEncoder.forOutputStreamWriter(out, this, cs);
+    }
+
+    /**
+     * Creates an OutputStreamWriter that uses the given charset encoder.
+     *
+     * @param  out
+     *         An OutputStream
+     *
+     * @param  enc
+     *         A charset encoder
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {
+        super(out);
+        if (enc == null)
+            throw new NullPointerException("charset encoder");
+        se = StreamEncoder.forOutputStreamWriter(out, this, enc);
+    }
+
+    /**
+     * Returns the name of the character encoding being used by this stream.
+     *
+     * <p> If the encoding has an historical name then that name is returned;
+     * otherwise the encoding's canonical name is returned.
+     *
+     * <p> If this instance was created with the {@link
+     * #OutputStreamWriter(OutputStream, String)} constructor then the returned
+     * name, being unique for the encoding, may differ from the name passed to
+     * the constructor.  This method may return <tt>null</tt> if the stream has
+     * been closed. </p>
+     *
+     * @return The historical name of this encoding, or possibly
+     *         <code>null</code> if the stream has been closed
+     *
+     * @see java.nio.charset.Charset
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public String getEncoding() {
+        return se.getEncoding();
+    }
+
+    /**
+     * Flushes the output buffer to the underlying byte stream, without flushing
+     * the byte stream itself.  This method is non-private only so that it may
+     * be invoked by PrintStream.
+     */
+    void flushBuffer() throws IOException {
+        se.flushBuffer();
+    }
+
+    /**
+     * Writes a single character.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(int c) throws IOException {
+        se.write(c);
+    }
+
+    /**
+     * Writes a portion of an array of characters.
+     *
+     * @param  cbuf  Buffer of characters
+     * @param  off   Offset from which to start writing characters
+     * @param  len   Number of characters to write
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(char cbuf[], int off, int len) throws IOException {
+        se.write(cbuf, off, len);
+    }
+
+    /**
+     * Writes a portion of a string.
+     *
+     * @param  str  A String
+     * @param  off  Offset from which to start writing characters
+     * @param  len  Number of characters to write
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void write(String str, int off, int len) throws IOException {
+        se.write(str, off, len);
+    }
+
+    /**
+     * Flushes the stream.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void flush() throws IOException {
+        se.flush();
+    }
+
+    public void close() throws IOException {
+        se.close();
+    }
+}
diff --git a/java/io/PipedInputStream.java b/java/io/PipedInputStream.java
new file mode 100644
index 0000000..b79bcbd
--- /dev/null
+++ b/java/io/PipedInputStream.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import libcore.io.IoUtils;
+
+/**
+ * A piped input stream should be connected
+ * to a piped output stream; the piped  input
+ * stream then provides whatever data bytes
+ * are written to the piped output  stream.
+ * Typically, data is read from a <code>PipedInputStream</code>
+ * object by one thread  and data is written
+ * to the corresponding <code>PipedOutputStream</code>
+ * by some  other thread. Attempting to use
+ * both objects from a single thread is not
+ * recommended, as it may deadlock the thread.
+ * The piped input stream contains a buffer,
+ * decoupling read operations from write operations,
+ * within limits.
+ * A pipe is said to be <a name="BROKEN"> <i>broken</i> </a> if a
+ * thread that was providing data bytes to the connected
+ * piped output stream is no longer alive.
+ *
+ * @author  James Gosling
+ * @see     java.io.PipedOutputStream
+ * @since   JDK1.0
+ */
+public class PipedInputStream extends InputStream {
+    boolean closedByWriter = false;
+    volatile boolean closedByReader = false;
+    boolean connected = false;
+
+        /* REMIND: identification of the read and write sides needs to be
+           more sophisticated.  Either using thread groups (but what about
+           pipes within a thread?) or using finalization (but it may be a
+           long time until the next GC). */
+    Thread readSide;
+    Thread writeSide;
+
+    private static final int DEFAULT_PIPE_SIZE = 1024;
+
+    /**
+     * The default size of the pipe's circular input buffer.
+     * @since   JDK1.1
+     */
+    // This used to be a constant before the pipe size was allowed
+    // to change. This field will continue to be maintained
+    // for backward compatibility.
+    protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE;
+
+    /**
+     * The circular buffer into which incoming data is placed.
+     * @since   JDK1.1
+     */
+    protected byte buffer[];
+
+    /**
+     * The index of the position in the circular buffer at which the
+     * next byte of data will be stored when received from the connected
+     * piped output stream. <code>in&lt;0</code> implies the buffer is empty,
+     * <code>in==out</code> implies the buffer is full
+     * @since   JDK1.1
+     */
+    protected int in = -1;
+
+    /**
+     * The index of the position in the circular buffer at which the next
+     * byte of data will be read by this piped input stream.
+     * @since   JDK1.1
+     */
+    protected int out = 0;
+
+    /**
+     * Creates a <code>PipedInputStream</code> so
+     * that it is connected to the piped output
+     * stream <code>src</code>. Data bytes written
+     * to <code>src</code> will then be  available
+     * as input from this stream.
+     *
+     * @param      src   the stream to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public PipedInputStream(PipedOutputStream src) throws IOException {
+        this(src, DEFAULT_PIPE_SIZE);
+    }
+
+    /**
+     * Creates a <code>PipedInputStream</code> so that it is
+     * connected to the piped output stream
+     * <code>src</code> and uses the specified pipe size for
+     * the pipe's buffer.
+     * Data bytes written to <code>src</code> will then
+     * be available as input from this stream.
+     *
+     * @param      src   the stream to connect to.
+     * @param      pipeSize the size of the pipe's buffer.
+     * @exception  IOException  if an I/O error occurs.
+     * @exception  IllegalArgumentException if {@code pipeSize <= 0}.
+     * @since      1.6
+     */
+    public PipedInputStream(PipedOutputStream src, int pipeSize)
+            throws IOException {
+         initPipe(pipeSize);
+         connect(src);
+    }
+
+    /**
+     * Creates a <code>PipedInputStream</code> so
+     * that it is not yet {@linkplain #connect(java.io.PipedOutputStream)
+     * connected}.
+     * It must be {@linkplain java.io.PipedOutputStream#connect(
+     * java.io.PipedInputStream) connected} to a
+     * <code>PipedOutputStream</code> before being used.
+     */
+    public PipedInputStream() {
+        initPipe(DEFAULT_PIPE_SIZE);
+    }
+
+    /**
+     * Creates a <code>PipedInputStream</code> so that it is not yet
+     * {@linkplain #connect(java.io.PipedOutputStream) connected} and
+     * uses the specified pipe size for the pipe's buffer.
+     * It must be {@linkplain java.io.PipedOutputStream#connect(
+     * java.io.PipedInputStream)
+     * connected} to a <code>PipedOutputStream</code> before being used.
+     *
+     * @param      pipeSize the size of the pipe's buffer.
+     * @exception  IllegalArgumentException if {@code pipeSize <= 0}.
+     * @since      1.6
+     */
+    public PipedInputStream(int pipeSize) {
+        initPipe(pipeSize);
+    }
+
+    private void initPipe(int pipeSize) {
+         if (pipeSize <= 0) {
+            throw new IllegalArgumentException("Pipe Size <= 0");
+         }
+         buffer = new byte[pipeSize];
+    }
+
+    /**
+     * Causes this piped input stream to be connected
+     * to the piped  output stream <code>src</code>.
+     * If this object is already connected to some
+     * other piped output  stream, an <code>IOException</code>
+     * is thrown.
+     * <p>
+     * If <code>src</code> is an
+     * unconnected piped output stream and <code>snk</code>
+     * is an unconnected piped input stream, they
+     * may be connected by either the call:
+     *
+     * <pre><code>snk.connect(src)</code> </pre>
+     * <p>
+     * or the call:
+     *
+     * <pre><code>src.connect(snk)</code> </pre>
+     * <p>
+     * The two calls have the same effect.
+     *
+     * @param      src   The piped output stream to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void connect(PipedOutputStream src) throws IOException {
+        src.connect(this);
+    }
+
+    /**
+     * Receives a byte of data.  This method will block if no input is
+     * available.
+     * @param b the byte being received
+     * @exception IOException If the pipe is <a href="#BROKEN"> <code>broken</code></a>,
+     *          {@link #connect(java.io.PipedOutputStream) unconnected},
+     *          closed, or if an I/O error occurs.
+     * @since     JDK1.1
+     */
+    protected synchronized void receive(int b) throws IOException {
+        checkStateForReceive();
+        writeSide = Thread.currentThread();
+        if (in == out)
+            awaitSpace();
+        if (in < 0) {
+            in = 0;
+            out = 0;
+        }
+        buffer[in++] = (byte)(b & 0xFF);
+        if (in >= buffer.length) {
+            in = 0;
+        }
+    }
+
+    /**
+     * Receives data into an array of bytes.  This method will
+     * block until some input is available.
+     * @param b the buffer into which the data is received
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes received
+     * @exception IOException If the pipe is <a href="#BROKEN"> broken</a>,
+     *           {@link #connect(java.io.PipedOutputStream) unconnected},
+     *           closed,or if an I/O error occurs.
+     */
+    synchronized void receive(byte b[], int off, int len)  throws IOException {
+        checkStateForReceive();
+        writeSide = Thread.currentThread();
+        int bytesToTransfer = len;
+        while (bytesToTransfer > 0) {
+            if (in == out)
+                awaitSpace();
+            int nextTransferAmount = 0;
+            if (out < in) {
+                nextTransferAmount = buffer.length - in;
+            } else if (in < out) {
+                if (in == -1) {
+                    in = out = 0;
+                    nextTransferAmount = buffer.length - in;
+                } else {
+                    nextTransferAmount = out - in;
+                }
+            }
+            if (nextTransferAmount > bytesToTransfer)
+                nextTransferAmount = bytesToTransfer;
+            assert(nextTransferAmount > 0);
+            System.arraycopy(b, off, buffer, in, nextTransferAmount);
+            bytesToTransfer -= nextTransferAmount;
+            off += nextTransferAmount;
+            in += nextTransferAmount;
+            if (in >= buffer.length) {
+                in = 0;
+            }
+        }
+    }
+
+    private void checkStateForReceive() throws IOException {
+        if (!connected) {
+            throw new IOException("Pipe not connected");
+        } else if (closedByWriter || closedByReader) {
+            throw new IOException("Pipe closed");
+        } else if (readSide != null && !readSide.isAlive()) {
+            throw new IOException("Read end dead");
+        }
+    }
+
+    private void awaitSpace() throws IOException {
+        while (in == out) {
+            checkStateForReceive();
+
+            /* full: kick any waiting readers */
+            notifyAll();
+            try {
+                wait(1000);
+            } catch (InterruptedException ex) {
+                // Android-changed: re-set the thread's interrupt status
+                // throw new java.io.InterruptedIOException();
+                IoUtils.throwInterruptedIoException();
+            }
+        }
+    }
+
+    /**
+     * Notifies all waiting threads that the last byte of data has been
+     * received.
+     */
+    synchronized void receivedLast() {
+        closedByWriter = true;
+        notifyAll();
+    }
+
+    /**
+     * Reads the next byte of data from this piped input stream. The
+     * value byte is returned as an <code>int</code> in the range
+     * <code>0</code> to <code>255</code>.
+     * This method blocks until input data is available, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if the pipe is
+     *           {@link #connect(java.io.PipedOutputStream) unconnected},
+     *           <a href="#BROKEN"> <code>broken</code></a>, closed,
+     *           or if an I/O error occurs.
+     */
+    public synchronized int read()  throws IOException {
+        if (!connected) {
+            throw new IOException("Pipe not connected");
+        } else if (closedByReader) {
+            throw new IOException("Pipe closed");
+        } else if (writeSide != null && !writeSide.isAlive()
+                   && !closedByWriter && (in < 0)) {
+            throw new IOException("Write end dead");
+        }
+
+        readSide = Thread.currentThread();
+        int trials = 2;
+        while (in < 0) {
+            if (closedByWriter) {
+                /* closed by writer, return EOF */
+                return -1;
+            }
+            if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
+                throw new IOException("Pipe broken");
+            }
+            /* might be a writer waiting */
+            notifyAll();
+            try {
+                wait(1000);
+            } catch (InterruptedException ex) {
+                // Android-changed: re-set the thread's interrupt status
+                // throw new java.io.InterruptedIOException();
+                IoUtils.throwInterruptedIoException();
+            }
+        }
+        int ret = buffer[out++] & 0xFF;
+        if (out >= buffer.length) {
+            out = 0;
+        }
+        if (in == out) {
+            /* now empty */
+            in = -1;
+        }
+
+        return ret;
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this piped input
+     * stream into an array of bytes. Less than <code>len</code> bytes
+     * will be read if the end of the data stream is reached or if
+     * <code>len</code> exceeds the pipe's buffer size.
+     * If <code>len </code> is zero, then no bytes are read and 0 is returned;
+     * otherwise, the method blocks until at least 1 byte of input is
+     * available, end of the stream has been detected, or an exception is
+     * thrown.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in the destination array <code>b</code>
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception  IOException if the pipe is <a href="#BROKEN"> <code>broken</code></a>,
+     *           {@link #connect(java.io.PipedOutputStream) unconnected},
+     *           closed, or if an I/O error occurs.
+     */
+    public synchronized int read(byte b[], int off, int len)  throws IOException {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        /* possibly wait on the first character */
+        int c = read();
+        if (c < 0) {
+            return -1;
+        }
+        b[off] = (byte) c;
+        int rlen = 1;
+        while ((in >= 0) && (len > 1)) {
+
+            int available;
+
+            if (in > out) {
+                available = Math.min((buffer.length - out), (in - out));
+            } else {
+                available = buffer.length - out;
+            }
+
+            // A byte is read beforehand outside the loop
+            if (available > (len - 1)) {
+                available = len - 1;
+            }
+            System.arraycopy(buffer, out, b, off + rlen, available);
+            out += available;
+            rlen += available;
+            len -= available;
+
+            if (out >= buffer.length) {
+                out = 0;
+            }
+            if (in == out) {
+                /* now empty */
+                in = -1;
+            }
+        }
+        return rlen;
+    }
+
+    /**
+     * Returns the number of bytes that can be read from this input
+     * stream without blocking.
+     *
+     * @return the number of bytes that can be read from this input stream
+     *         without blocking, or {@code 0} if this input stream has been
+     *         closed by invoking its {@link #close()} method, or if the pipe
+     *         is {@link #connect(java.io.PipedOutputStream) unconnected}, or
+     *          <a href="#BROKEN"> <code>broken</code></a>.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @since   JDK1.0.2
+     */
+    public synchronized int available() throws IOException {
+        if(in < 0)
+            return 0;
+        else if(in == out)
+            return buffer.length;
+        else if (in > out)
+            return in - out;
+        else
+            return in + buffer.length - out;
+    }
+
+    /**
+     * Closes this piped input stream and releases any system resources
+     * associated with the stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close()  throws IOException {
+        closedByReader = true;
+        synchronized (this) {
+            in = -1;
+        }
+    }
+}
diff --git a/java/io/PipedOutputStream.java b/java/io/PipedOutputStream.java
new file mode 100644
index 0000000..feed73a
--- /dev/null
+++ b/java/io/PipedOutputStream.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.*;
+
+/**
+ * A piped output stream can be connected to a piped input stream
+ * to create a communications pipe. The piped output stream is the
+ * sending end of the pipe. Typically, data is written to a
+ * <code>PipedOutputStream</code> object by one thread and data is
+ * read from the connected <code>PipedInputStream</code> by some
+ * other thread. Attempting to use both objects from a single thread
+ * is not recommended as it may deadlock the thread.
+ * The pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a
+ * thread that was reading data bytes from the connected piped input
+ * stream is no longer alive.
+ *
+ * @author  James Gosling
+ * @see     java.io.PipedInputStream
+ * @since   JDK1.0
+ */
+public
+class PipedOutputStream extends OutputStream {
+
+        /* REMIND: identification of the read and write sides needs to be
+           more sophisticated.  Either using thread groups (but what about
+           pipes within a thread?) or using finalization (but it may be a
+           long time until the next GC). */
+    private PipedInputStream sink;
+
+    /**
+     * Creates a piped output stream connected to the specified piped
+     * input stream. Data bytes written to this stream will then be
+     * available as input from <code>snk</code>.
+     *
+     * @param      snk   The piped input stream to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public PipedOutputStream(PipedInputStream snk)  throws IOException {
+        connect(snk);
+    }
+
+    /**
+     * Creates a piped output stream that is not yet connected to a
+     * piped input stream. It must be connected to a piped input stream,
+     * either by the receiver or the sender, before being used.
+     *
+     * @see     java.io.PipedInputStream#connect(java.io.PipedOutputStream)
+     * @see     java.io.PipedOutputStream#connect(java.io.PipedInputStream)
+     */
+    public PipedOutputStream() {
+    }
+
+    /**
+     * Connects this piped output stream to a receiver. If this object
+     * is already connected to some other piped input stream, an
+     * <code>IOException</code> is thrown.
+     * <p>
+     * If <code>snk</code> is an unconnected piped input stream and
+     * <code>src</code> is an unconnected piped output stream, they may
+     * be connected by either the call:
+     * <blockquote><pre>
+     * src.connect(snk)</pre></blockquote>
+     * or the call:
+     * <blockquote><pre>
+     * snk.connect(src)</pre></blockquote>
+     * The two calls have the same effect.
+     *
+     * @param      snk   the piped input stream to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public synchronized void connect(PipedInputStream snk) throws IOException {
+        if (snk == null) {
+            throw new NullPointerException();
+        } else if (sink != null || snk.connected) {
+            throw new IOException("Already connected");
+        }
+        sink = snk;
+        snk.in = -1;
+        snk.out = 0;
+        snk.connected = true;
+    }
+
+    /**
+     * Writes the specified <code>byte</code> to the piped output stream.
+     * <p>
+     * Implements the <code>write</code> method of <code>OutputStream</code>.
+     *
+     * @param      b   the <code>byte</code> to be written.
+     * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
+     *          {@link #connect(java.io.PipedInputStream) unconnected},
+     *          closed, or if an I/O error occurs.
+     */
+    public void write(int b)  throws IOException {
+        if (sink == null) {
+            throw new IOException("Pipe not connected");
+        }
+        sink.receive(b);
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array
+     * starting at offset <code>off</code> to this piped output stream.
+     * This method blocks until all the bytes are written to the output
+     * stream.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
+     *          {@link #connect(java.io.PipedInputStream) unconnected},
+     *          closed, or if an I/O error occurs.
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        if (sink == null) {
+            throw new IOException("Pipe not connected");
+        } else if (b == null) {
+            throw new NullPointerException();
+        } else if ((off < 0) || (off > b.length) || (len < 0) ||
+                   ((off + len) > b.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        sink.receive(b, off, len);
+    }
+
+    /**
+     * Flushes this output stream and forces any buffered output bytes
+     * to be written out.
+     * This will notify any readers that bytes are waiting in the pipe.
+     *
+     * @exception IOException if an I/O error occurs.
+     */
+    public synchronized void flush() throws IOException {
+        if (sink != null) {
+            synchronized (sink) {
+                sink.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Closes this piped output stream and releases any system resources
+     * associated with this stream. This stream may no longer be used for
+     * writing bytes.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close()  throws IOException {
+        if (sink != null) {
+            sink.receivedLast();
+        }
+    }
+}
diff --git a/java/io/PipedReader.java b/java/io/PipedReader.java
new file mode 100644
index 0000000..d72e1e5
--- /dev/null
+++ b/java/io/PipedReader.java
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import libcore.io.IoUtils;
+
+/**
+ * Piped character-input streams.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class PipedReader extends Reader {
+    boolean closedByWriter = false;
+    boolean closedByReader = false;
+    boolean connected = false;
+
+    /* REMIND: identification of the read and write sides needs to be
+       more sophisticated.  Either using thread groups (but what about
+       pipes within a thread?) or using finalization (but it may be a
+       long time until the next GC). */
+    Thread readSide;
+    Thread writeSide;
+
+   /**
+    * The size of the pipe's circular input buffer.
+    */
+    private static final int DEFAULT_PIPE_SIZE = 1024;
+
+    /**
+     * The circular buffer into which incoming data is placed.
+     */
+    char buffer[];
+
+    /**
+     * The index of the position in the circular buffer at which the
+     * next character of data will be stored when received from the connected
+     * piped writer. <code>in&lt;0</code> implies the buffer is empty,
+     * <code>in==out</code> implies the buffer is full
+     */
+    int in = -1;
+
+    /**
+     * The index of the position in the circular buffer at which the next
+     * character of data will be read by this piped reader.
+     */
+    int out = 0;
+
+    /**
+     * Creates a <code>PipedReader</code> so
+     * that it is connected to the piped writer
+     * <code>src</code>. Data written to <code>src</code>
+     * will then be available as input from this stream.
+     *
+     * @param      src   the stream to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public PipedReader(PipedWriter src) throws IOException {
+        this(src, DEFAULT_PIPE_SIZE);
+    }
+
+    /**
+     * Creates a <code>PipedReader</code> so that it is connected
+     * to the piped writer <code>src</code> and uses the specified
+     * pipe size for the pipe's buffer. Data written to <code>src</code>
+     * will then be  available as input from this stream.
+
+     * @param      src       the stream to connect to.
+     * @param      pipeSize  the size of the pipe's buffer.
+     * @exception  IOException  if an I/O error occurs.
+     * @exception  IllegalArgumentException if {@code pipeSize <= 0}.
+     * @since      1.6
+     */
+    public PipedReader(PipedWriter src, int pipeSize) throws IOException {
+        initPipe(pipeSize);
+        connect(src);
+    }
+
+
+    /**
+     * Creates a <code>PipedReader</code> so
+     * that it is not yet {@linkplain #connect(java.io.PipedWriter)
+     * connected}. It must be {@linkplain java.io.PipedWriter#connect(
+     * java.io.PipedReader) connected} to a <code>PipedWriter</code>
+     * before being used.
+     */
+    public PipedReader() {
+        initPipe(DEFAULT_PIPE_SIZE);
+    }
+
+    /**
+     * Creates a <code>PipedReader</code> so that it is not yet
+     * {@link #connect(java.io.PipedWriter) connected} and uses
+     * the specified pipe size for the pipe's buffer.
+     * It must be  {@linkplain java.io.PipedWriter#connect(
+     * java.io.PipedReader) connected} to a <code>PipedWriter</code>
+     * before being used.
+     *
+     * @param   pipeSize the size of the pipe's buffer.
+     * @exception  IllegalArgumentException if {@code pipeSize <= 0}.
+     * @since      1.6
+     */
+    public PipedReader(int pipeSize) {
+        initPipe(pipeSize);
+    }
+
+    private void initPipe(int pipeSize) {
+        if (pipeSize <= 0) {
+            throw new IllegalArgumentException("Pipe size <= 0");
+        }
+        buffer = new char[pipeSize];
+    }
+
+    /**
+     * Causes this piped reader to be connected
+     * to the piped  writer <code>src</code>.
+     * If this object is already connected to some
+     * other piped writer, an <code>IOException</code>
+     * is thrown.
+     * <p>
+     * If <code>src</code> is an
+     * unconnected piped writer and <code>snk</code>
+     * is an unconnected piped reader, they
+     * may be connected by either the call:
+     *
+     * <pre><code>snk.connect(src)</code> </pre>
+     * <p>
+     * or the call:
+     *
+     * <pre><code>src.connect(snk)</code> </pre>
+     * <p>
+     * The two calls have the same effect.
+     *
+     * @param      src   The piped writer to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void connect(PipedWriter src) throws IOException {
+        src.connect(this);
+    }
+
+    /**
+     * Receives a char of data. This method will block if no input is
+     * available.
+     */
+    synchronized void receive(int c) throws IOException {
+        if (!connected) {
+            throw new IOException("Pipe not connected");
+        } else if (closedByWriter || closedByReader) {
+            throw new IOException("Pipe closed");
+        } else if (readSide != null && !readSide.isAlive()) {
+            throw new IOException("Read end dead");
+        }
+
+        writeSide = Thread.currentThread();
+        while (in == out) {
+            if ((readSide != null) && !readSide.isAlive()) {
+                throw new IOException("Pipe broken");
+            }
+            /* full: kick any waiting readers */
+            notifyAll();
+            try {
+                wait(1000);
+            } catch (InterruptedException ex) {
+                // Android-changed: re-set the thread's interrupt status
+                // throw new java.io.InterruptedIOException();
+                IoUtils.throwInterruptedIoException();
+            }
+        }
+        if (in < 0) {
+            in = 0;
+            out = 0;
+        }
+        buffer[in++] = (char) c;
+        if (in >= buffer.length) {
+            in = 0;
+        }
+    }
+
+    /**
+     * Receives data into an array of characters.  This method will
+     * block until some input is available.
+     */
+    synchronized void receive(char c[], int off, int len)  throws IOException {
+        while (--len >= 0) {
+            receive(c[off++]);
+        }
+    }
+
+    /**
+     * Notifies all waiting threads that the last character of data has been
+     * received.
+     */
+    synchronized void receivedLast() {
+        closedByWriter = true;
+        notifyAll();
+    }
+
+    /**
+     * Reads the next character of data from this piped stream.
+     * If no character is available because the end of the stream
+     * has been reached, the value <code>-1</code> is returned.
+     * This method blocks until input data is available, the end of
+     * the stream is detected, or an exception is thrown.
+     *
+     * @return     the next character of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if the pipe is
+     *          <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
+     *          {@link #connect(java.io.PipedWriter) unconnected}, closed,
+     *          or an I/O error occurs.
+     */
+    public synchronized int read()  throws IOException {
+        if (!connected) {
+            throw new IOException("Pipe not connected");
+        } else if (closedByReader) {
+            throw new IOException("Pipe closed");
+        } else if (writeSide != null && !writeSide.isAlive()
+                   && !closedByWriter && (in < 0)) {
+            throw new IOException("Write end dead");
+        }
+
+        readSide = Thread.currentThread();
+        int trials = 2;
+        while (in < 0) {
+            if (closedByWriter) {
+                /* closed by writer, return EOF */
+                return -1;
+            }
+            if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
+                throw new IOException("Pipe broken");
+            }
+            /* might be a writer waiting */
+            notifyAll();
+            try {
+                wait(1000);
+            } catch (InterruptedException ex) {
+              // Android-changed: re-set the thread's interrupt status
+              // throw new java.io.InterruptedIOException();
+              IoUtils.throwInterruptedIoException();
+            }
+        }
+        int ret = buffer[out++];
+        if (out >= buffer.length) {
+            out = 0;
+        }
+        if (in == out) {
+            /* now empty */
+            in = -1;
+        }
+        return ret;
+    }
+
+    /**
+     * Reads up to <code>len</code> characters of data from this piped
+     * stream into an array of characters. Less than <code>len</code> characters
+     * will be read if the end of the data stream is reached or if
+     * <code>len</code> exceeds the pipe's buffer size. This method
+     * blocks until at least one character of input is available.
+     *
+     * @param      cbuf     the buffer into which the data is read.
+     * @param      off   the start offset of the data.
+     * @param      len   the maximum number of characters read.
+     * @return     the total number of characters read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  IOException  if the pipe is
+     *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
+     *                  {@link #connect(java.io.PipedWriter) unconnected}, closed,
+     *                  or an I/O error occurs.
+     */
+    public synchronized int read(char cbuf[], int off, int len)  throws IOException {
+        if (!connected) {
+            throw new IOException("Pipe not connected");
+        } else if (closedByReader) {
+            throw new IOException("Pipe closed");
+        } else if (writeSide != null && !writeSide.isAlive()
+                   && !closedByWriter && (in < 0)) {
+            throw new IOException("Write end dead");
+        }
+
+        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+            ((off + len) > cbuf.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        /* possibly wait on the first character */
+        int c = read();
+        if (c < 0) {
+            return -1;
+        }
+        cbuf[off] =  (char)c;
+        int rlen = 1;
+        while ((in >= 0) && (--len > 0)) {
+            cbuf[off + rlen] = buffer[out++];
+            rlen++;
+            if (out >= buffer.length) {
+                out = 0;
+            }
+            if (in == out) {
+                /* now empty */
+                in = -1;
+            }
+        }
+        return rlen;
+    }
+
+    /**
+     * Tell whether this stream is ready to be read.  A piped character
+     * stream is ready if the circular buffer is not empty.
+     *
+     * @exception  IOException  if the pipe is
+     *                  <a href=PipedInputStream.html#BROKEN> <code>broken</code></a>,
+     *                  {@link #connect(java.io.PipedWriter) unconnected}, or closed.
+     */
+    public synchronized boolean ready() throws IOException {
+        if (!connected) {
+            throw new IOException("Pipe not connected");
+        } else if (closedByReader) {
+            throw new IOException("Pipe closed");
+        } else if (writeSide != null && !writeSide.isAlive()
+                   && !closedByWriter && (in < 0)) {
+            throw new IOException("Write end dead");
+        }
+        if (in < 0) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Closes this piped stream and releases any system resources
+     * associated with the stream.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close()  throws IOException {
+        in = -1;
+        closedByReader = true;
+    }
+}
diff --git a/java/io/PipedWriter.java b/java/io/PipedWriter.java
new file mode 100644
index 0000000..46e1455
--- /dev/null
+++ b/java/io/PipedWriter.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Piped character-output streams.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class PipedWriter extends Writer {
+
+    /* REMIND: identification of the read and write sides needs to be
+       more sophisticated.  Either using thread groups (but what about
+       pipes within a thread?) or using finalization (but it may be a
+       long time until the next GC). */
+    private PipedReader sink;
+
+    /* This flag records the open status of this particular writer. It
+     * is independent of the status flags defined in PipedReader. It is
+     * used to do a sanity check on connect.
+     */
+    private boolean closed = false;
+
+    /**
+     * Creates a piped writer connected to the specified piped
+     * reader. Data characters written to this stream will then be
+     * available as input from <code>snk</code>.
+     *
+     * @param      snk   The piped reader to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public PipedWriter(PipedReader snk)  throws IOException {
+        connect(snk);
+    }
+
+    /**
+     * Creates a piped writer that is not yet connected to a
+     * piped reader. It must be connected to a piped reader,
+     * either by the receiver or the sender, before being used.
+     *
+     * @see     java.io.PipedReader#connect(java.io.PipedWriter)
+     * @see     java.io.PipedWriter#connect(java.io.PipedReader)
+     */
+    public PipedWriter() {
+    }
+
+    /**
+     * Connects this piped writer to a receiver. If this object
+     * is already connected to some other piped reader, an
+     * <code>IOException</code> is thrown.
+     * <p>
+     * If <code>snk</code> is an unconnected piped reader and
+     * <code>src</code> is an unconnected piped writer, they may
+     * be connected by either the call:
+     * <blockquote><pre>
+     * src.connect(snk)</pre></blockquote>
+     * or the call:
+     * <blockquote><pre>
+     * snk.connect(src)</pre></blockquote>
+     * The two calls have the same effect.
+     *
+     * @param      snk   the piped reader to connect to.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public synchronized void connect(PipedReader snk) throws IOException {
+        if (snk == null) {
+            throw new NullPointerException();
+        } else if (sink != null || snk.connected) {
+            throw new IOException("Already connected");
+        } else if (snk.closedByReader || closed) {
+            throw new IOException("Pipe closed");
+        }
+
+        sink = snk;
+        snk.in = -1;
+        snk.out = 0;
+        snk.connected = true;
+    }
+
+    /**
+     * Writes the specified <code>char</code> to the piped output stream.
+     * If a thread was reading data characters from the connected piped input
+     * stream, but the thread is no longer alive, then an
+     * <code>IOException</code> is thrown.
+     * <p>
+     * Implements the <code>write</code> method of <code>Writer</code>.
+     *
+     * @param      c   the <code>char</code> to be written.
+     * @exception  IOException  if the pipe is
+     *          <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,
+     *          {@link #connect(java.io.PipedReader) unconnected}, closed
+     *          or an I/O error occurs.
+     */
+    public void write(int c)  throws IOException {
+        if (sink == null) {
+            throw new IOException("Pipe not connected");
+        }
+        sink.receive(c);
+    }
+
+    /**
+     * Writes <code>len</code> characters from the specified character array
+     * starting at offset <code>off</code> to this piped output stream.
+     * This method blocks until all the characters are written to the output
+     * stream.
+     * If a thread was reading data characters from the connected piped input
+     * stream, but the thread is no longer alive, then an
+     * <code>IOException</code> is thrown.
+     *
+     * @param      cbuf  the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of characters to write.
+     * @exception  IOException  if the pipe is
+     *          <a href=PipedOutputStream.html#BROKEN> <code>broken</code></a>,
+     *          {@link #connect(java.io.PipedReader) unconnected}, closed
+     *          or an I/O error occurs.
+     */
+    public void write(char cbuf[], int off, int len) throws IOException {
+        if (sink == null) {
+            throw new IOException("Pipe not connected");
+        } else if ((off | len | (off + len) | (cbuf.length - (off + len))) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        sink.receive(cbuf, off, len);
+    }
+
+    /**
+     * Flushes this output stream and forces any buffered output characters
+     * to be written out.
+     * This will notify any readers that characters are waiting in the pipe.
+     *
+     * @exception  IOException  if the pipe is closed, or an I/O error occurs.
+     */
+    public synchronized void flush() throws IOException {
+        if (sink != null) {
+            if (sink.closedByReader || closed) {
+                throw new IOException("Pipe closed");
+            }
+            synchronized (sink) {
+                sink.notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Closes this piped output stream and releases any system resources
+     * associated with this stream. This stream may no longer be used for
+     * writing characters.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close()  throws IOException {
+        closed = true;
+        if (sink != null) {
+            sink.receivedLast();
+        }
+    }
+}
diff --git a/java/io/PrintStream.java b/java/io/PrintStream.java
new file mode 100644
index 0000000..809d39b
--- /dev/null
+++ b/java/io/PrintStream.java
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Formatter;
+import java.util.Locale;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * A <code>PrintStream</code> adds functionality to another output stream,
+ * namely the ability to print representations of various data values
+ * conveniently.  Two other features are provided as well.  Unlike other output
+ * streams, a <code>PrintStream</code> never throws an
+ * <code>IOException</code>; instead, exceptional situations merely set an
+ * internal flag that can be tested via the <code>checkError</code> method.
+ * Optionally, a <code>PrintStream</code> can be created so as to flush
+ * automatically; this means that the <code>flush</code> method is
+ * automatically invoked after a byte array is written, one of the
+ * <code>println</code> methods is invoked, or a newline character or byte
+ * (<code>'\n'</code>) is written.
+ *
+ * <p> All characters printed by a <code>PrintStream</code> are converted into
+ * bytes using the platform's default character encoding.  The <code>{@link
+ * PrintWriter}</code> class should be used in situations that require writing
+ * characters rather than bytes.
+ *
+ * @author     Frank Yellin
+ * @author     Mark Reinhold
+ * @since      JDK1.0
+ */
+
+public class PrintStream extends FilterOutputStream
+    implements Appendable, Closeable
+{
+
+    private final boolean autoFlush;
+    private boolean trouble = false;
+    private Formatter formatter;
+
+    /**
+     * Track both the text- and character-output streams, so that their buffers
+     * can be flushed without flushing the entire stream.
+     */
+    private BufferedWriter textOut;
+    private OutputStreamWriter charOut;
+
+    // Android-added: Lazy initialization of charOut and textOut.
+    private Charset charset;
+
+    /**
+     * requireNonNull is explicitly declared here so as not to create an extra
+     * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
+     * early during system initialization.
+     */
+    private static <T> T requireNonNull(T obj, String message) {
+        if (obj == null)
+            throw new NullPointerException(message);
+        return obj;
+    }
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws UnsupportedEncodingException  if the charset is not supported
+     */
+    private static Charset toCharset(String csn)
+        throws UnsupportedEncodingException
+    {
+        requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            // UnsupportedEncodingException should be thrown
+            throw new UnsupportedEncodingException(csn);
+        }
+    }
+
+    /* Private constructors */
+    private PrintStream(boolean autoFlush, OutputStream out) {
+        super(out);
+        this.autoFlush = autoFlush;
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this);
+        // this.textOut = new BufferedWriter(charOut);
+    }
+
+    private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
+        super(out);
+        this.autoFlush = autoFlush;
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this, charset);
+        // this.textOut = new BufferedWriter(charOut);
+        this.charset = charset;
+    }
+
+    /* Variant of the private constructor so that the given charset name
+     * can be verified before evaluating the OutputStream argument. Used
+     * by constructors creating a FileOutputStream that also take a
+     * charset name.
+     */
+    private PrintStream(boolean autoFlush, Charset charset, OutputStream out)
+        throws UnsupportedEncodingException
+    {
+        this(autoFlush, out, charset);
+    }
+
+    /**
+     * Creates a new print stream.  This stream will not flush automatically.
+     *
+     * @param  out        The output stream to which values and objects will be
+     *                    printed
+     *
+     * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream)
+     */
+    public PrintStream(OutputStream out) {
+        this(out, false);
+    }
+
+    /**
+     * Creates a new print stream.
+     *
+     * @param  out        The output stream to which values and objects will be
+     *                    printed
+     * @param  autoFlush  A boolean; if true, the output buffer will be flushed
+     *                    whenever a byte array is written, one of the
+     *                    <code>println</code> methods is invoked, or a newline
+     *                    character or byte (<code>'\n'</code>) is written
+     *
+     * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
+     */
+    public PrintStream(OutputStream out, boolean autoFlush) {
+        this(autoFlush, requireNonNull(out, "Null output stream"));
+    }
+
+    /**
+     * Creates a new print stream.
+     *
+     * @param  out        The output stream to which values and objects will be
+     *                    printed
+     * @param  autoFlush  A boolean; if true, the output buffer will be flushed
+     *                    whenever a byte array is written, one of the
+     *                    <code>println</code> methods is invoked, or a newline
+     *                    character or byte (<code>'\n'</code>) is written
+     * @param  encoding   The name of a supported
+     *                    <a href="../lang/package-summary.html#charenc">
+     *                    character encoding</a>
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named encoding is not supported
+     *
+     * @since  1.4
+     */
+    public PrintStream(OutputStream out, boolean autoFlush, String encoding)
+        throws UnsupportedEncodingException
+    {
+        this(autoFlush,
+             requireNonNull(out, "Null output stream"),
+             toCharset(encoding));
+    }
+
+    /**
+     * Creates a new print stream, without automatic line flushing, with the
+     * specified file name.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}
+     * for this instance of the Java virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this print
+     *         stream.  If the file exists, then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @since  1.5
+     */
+    public PrintStream(String fileName) throws FileNotFoundException {
+        this(false, new FileOutputStream(fileName));
+    }
+
+    /**
+     * Creates a new print stream, without automatic line flushing, with the
+     * specified file name and charset.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this print
+     *         stream.  If the file exists, then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @since  1.5
+     */
+    public PrintStream(String fileName, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        // ensure charset is checked before the file is opened
+        this(false, toCharset(csn), new FileOutputStream(fileName));
+    }
+
+    /**
+     * Creates a new print stream, without automatic line flushing, with the
+     * specified file.  This convenience constructor creates the necessary
+     * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+     * which will encode characters using the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this print stream.  If the
+     *         file exists, then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())}
+     *          denies write access to the file
+     *
+     * @since  1.5
+     */
+    public PrintStream(File file) throws FileNotFoundException {
+        this(false, new FileOutputStream(file));
+    }
+
+    /**
+     * Creates a new print stream, without automatic line flushing, with the
+     * specified file and charset.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  file
+     *         The file to use as the destination of this print stream.  If the
+     *         file exists, then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())}
+     *          denies write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @since  1.5
+     */
+    public PrintStream(File file, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        // ensure charset is checked before the file is opened
+        this(false, toCharset(csn), new FileOutputStream(file));
+    }
+
+    /** Check to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (out == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Flushes the stream.  This is done by writing any buffered output bytes to
+     * the underlying output stream and then flushing that stream.
+     *
+     * @see        java.io.OutputStream#flush()
+     */
+    public void flush() {
+        synchronized (this) {
+            try {
+                ensureOpen();
+                out.flush();
+            }
+            catch (IOException x) {
+                trouble = true;
+            }
+        }
+    }
+
+    private boolean closing = false; /* To avoid recursive closing */
+
+    // BEGIN Android-added: Lazy initialization of charOut and textOut.
+    private BufferedWriter getTextOut() {
+        if (textOut == null) {
+            charOut = charset != null ? new OutputStreamWriter(this, charset) :
+                    new OutputStreamWriter(this);
+            textOut = new BufferedWriter(charOut);
+        }
+        return textOut;
+    }
+    // END Android-added: Lazy initialization of charOut and textOut.
+
+    /**
+     * Closes the stream.  This is done by flushing the stream and then closing
+     * the underlying output stream.
+     *
+     * @see        java.io.OutputStream#close()
+     */
+    public void close() {
+        synchronized (this) {
+            if (! closing) {
+                closing = true;
+                try {
+                    // BEGIN Android-changed: Lazy initialization of charOut and textOut.
+                    // textOut.close();
+                    if (textOut != null) {
+                        textOut.close();
+                    }
+                    // END Android-changed: Lazy initialization of charOut and textOut.
+                    out.close();
+                }
+                catch (IOException x) {
+                    trouble = true;
+                }
+                textOut = null;
+                charOut = null;
+                out = null;
+            }
+        }
+    }
+
+    /**
+     * Flushes the stream and checks its error state. The internal error state
+     * is set to <code>true</code> when the underlying output stream throws an
+     * <code>IOException</code> other than <code>InterruptedIOException</code>,
+     * and when the <code>setError</code> method is invoked.  If an operation
+     * on the underlying output stream throws an
+     * <code>InterruptedIOException</code>, then the <code>PrintStream</code>
+     * converts the exception back into an interrupt by doing:
+     * <pre>
+     *     Thread.currentThread().interrupt();
+     * </pre>
+     * or the equivalent.
+     *
+     * @return <code>true</code> if and only if this stream has encountered an
+     *         <code>IOException</code> other than
+     *         <code>InterruptedIOException</code>, or the
+     *         <code>setError</code> method has been invoked
+     */
+    public boolean checkError() {
+        if (out != null)
+            flush();
+        if (out instanceof java.io.PrintStream) {
+            PrintStream ps = (PrintStream) out;
+            return ps.checkError();
+        }
+        return trouble;
+    }
+
+    /**
+     * Sets the error state of the stream to <code>true</code>.
+     *
+     * <p> This method will cause subsequent invocations of {@link
+     * #checkError()} to return <tt>true</tt> until {@link
+     * #clearError()} is invoked.
+     *
+     * @since JDK1.1
+     */
+    protected void setError() {
+        trouble = true;
+    }
+
+    /**
+     * Clears the internal error state of this stream.
+     *
+     * <p> This method will cause subsequent invocations of {@link
+     * #checkError()} to return <tt>false</tt> until another write
+     * operation fails and invokes {@link #setError()}.
+     *
+     * @since 1.6
+     */
+    protected void clearError() {
+        trouble = false;
+    }
+
+    /*
+     * Exception-catching, synchronized output operations,
+     * which also implement the write() methods of OutputStream
+     */
+
+    /**
+     * Writes the specified byte to this stream.  If the byte is a newline and
+     * automatic flushing is enabled then the <code>flush</code> method will be
+     * invoked.
+     *
+     * <p> Note that the byte is written as given; to write a character that
+     * will be translated according to the platform's default character
+     * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+     * methods.
+     *
+     * @param  b  The byte to be written
+     * @see #print(char)
+     * @see #println(char)
+     */
+    public void write(int b) {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                out.write(b);
+                if ((b == '\n') && autoFlush)
+                    out.flush();
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /**
+     * Writes <code>len</code> bytes from the specified byte array starting at
+     * offset <code>off</code> to this stream.  If automatic flushing is
+     * enabled then the <code>flush</code> method will be invoked.
+     *
+     * <p> Note that the bytes will be written as given; to write characters
+     * that will be translated according to the platform's default character
+     * encoding, use the <code>print(char)</code> or <code>println(char)</code>
+     * methods.
+     *
+     * @param  buf   A byte array
+     * @param  off   Offset from which to start taking bytes
+     * @param  len   Number of bytes to write
+     */
+    public void write(byte buf[], int off, int len) {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                out.write(buf, off, len);
+                if (autoFlush)
+                    out.flush();
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /*
+     * The following private methods on the text- and character-output streams
+     * always flush the stream buffers, so that writes to the underlying byte
+     * stream occur as promptly as with the original PrintStream.
+     */
+
+    private void write(char buf[]) {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                // Android-added: Lazy initialization of charOut and textOut.
+                BufferedWriter textOut = getTextOut();
+                textOut.write(buf);
+                textOut.flushBuffer();
+                charOut.flushBuffer();
+                if (autoFlush) {
+                    for (int i = 0; i < buf.length; i++)
+                        if (buf[i] == '\n')
+                            out.flush();
+                }
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    private void write(String s) {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                // Android-added: Lazy initialization of charOut and textOut.
+                BufferedWriter textOut = getTextOut();
+                textOut.write(s);
+                textOut.flushBuffer();
+                charOut.flushBuffer();
+                if (autoFlush && (s.indexOf('\n') >= 0))
+                    out.flush();
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    private void newLine() {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                // Android-added: Lazy initialization of charOut and textOut.
+                BufferedWriter textOut = getTextOut();
+                textOut.newLine();
+                textOut.flushBuffer();
+                charOut.flushBuffer();
+                if (autoFlush)
+                    out.flush();
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /* Methods that do not terminate lines */
+
+    /**
+     * Prints a boolean value.  The string produced by <code>{@link
+     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      b   The <code>boolean</code> to be printed
+     */
+    public void print(boolean b) {
+        write(b ? "true" : "false");
+    }
+
+    /**
+     * Prints a character.  The character is translated into one or more bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      c   The <code>char</code> to be printed
+     */
+    public void print(char c) {
+        write(String.valueOf(c));
+    }
+
+    /**
+     * Prints an integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(int)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      i   The <code>int</code> to be printed
+     * @see        java.lang.Integer#toString(int)
+     */
+    public void print(int i) {
+        write(String.valueOf(i));
+    }
+
+    /**
+     * Prints a long integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(long)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      l   The <code>long</code> to be printed
+     * @see        java.lang.Long#toString(long)
+     */
+    public void print(long l) {
+        write(String.valueOf(l));
+    }
+
+    /**
+     * Prints a floating-point number.  The string produced by <code>{@link
+     * java.lang.String#valueOf(float)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      f   The <code>float</code> to be printed
+     * @see        java.lang.Float#toString(float)
+     */
+    public void print(float f) {
+        write(String.valueOf(f));
+    }
+
+    /**
+     * Prints a double-precision floating-point number.  The string produced by
+     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+     * bytes according to the platform's default character encoding, and these
+     * bytes are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      d   The <code>double</code> to be printed
+     * @see        java.lang.Double#toString(double)
+     */
+    public void print(double d) {
+        write(String.valueOf(d));
+    }
+
+    /**
+     * Prints an array of characters.  The characters are converted into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      s   The array of chars to be printed
+     *
+     * @throws  NullPointerException  If <code>s</code> is <code>null</code>
+     */
+    public void print(char s[]) {
+        write(s);
+    }
+
+    /**
+     * Prints a string.  If the argument is <code>null</code> then the string
+     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * converted into bytes according to the platform's default character
+     * encoding, and these bytes are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      s   The <code>String</code> to be printed
+     */
+    public void print(String s) {
+        if (s == null) {
+            s = "null";
+        }
+        write(s);
+    }
+
+    /**
+     * Prints an object.  The string produced by the <code>{@link
+     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      obj   The <code>Object</code> to be printed
+     * @see        java.lang.Object#toString()
+     */
+    public void print(Object obj) {
+        write(String.valueOf(obj));
+    }
+
+
+    /* Methods that do terminate lines */
+
+    /**
+     * Terminates the current line by writing the line separator string.  The
+     * line separator string is defined by the system property
+     * <code>line.separator</code>, and is not necessarily a single newline
+     * character (<code>'\n'</code>).
+     */
+    public void println() {
+        newLine();
+    }
+
+    /**
+     * Prints a boolean and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(boolean)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>boolean</code> to be printed
+     */
+    public void println(boolean x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints a character and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(char)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>char</code> to be printed.
+     */
+    public void println(char x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints an integer and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(int)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>int</code> to be printed.
+     */
+    public void println(int x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints a long and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(long)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  a The <code>long</code> to be printed.
+     */
+    public void println(long x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints a float and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(float)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>float</code> to be printed.
+     */
+    public void println(float x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints a double and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(double)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>double</code> to be printed.
+     */
+    public void println(double x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints an array of characters and then terminate the line.  This method
+     * behaves as though it invokes <code>{@link #print(char[])}</code> and
+     * then <code>{@link #println()}</code>.
+     *
+     * @param x  an array of chars to print.
+     */
+    public void println(char x[]) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints a String and then terminate the line.  This method behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>String</code> to be printed.
+     */
+    public void println(String x) {
+        synchronized (this) {
+            print(x);
+            newLine();
+        }
+    }
+
+    /**
+     * Prints an Object and then terminate the line.  This method calls
+     * at first String.valueOf(x) to get the printed object's string value,
+     * then behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>Object</code> to be printed.
+     */
+    public void println(Object x) {
+        String s = String.valueOf(x);
+        synchronized (this) {
+            print(s);
+            newLine();
+        }
+    }
+
+
+    /**
+     * A convenience method to write a formatted string to this output stream
+     * using the specified format string and arguments.
+     *
+     * <p> An invocation of this method of the form <tt>out.printf(format,
+     * args)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.format(format, args) </pre>
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This output stream
+     *
+     * @since  1.5
+     */
+    public PrintStream printf(String format, Object ... args) {
+        return format(format, args);
+    }
+
+    /**
+     * A convenience method to write a formatted string to this output stream
+     * using the specified format string and arguments.
+     *
+     * <p> An invocation of this method of the form <tt>out.printf(l, format,
+     * args)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.format(l, format, args) </pre>
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         is applied.
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This output stream
+     *
+     * @since  1.5
+     */
+    public PrintStream printf(Locale l, String format, Object ... args) {
+        return format(l, format, args);
+    }
+
+    /**
+     * Writes a formatted string to this output stream using the specified
+     * format string and arguments.
+     *
+     * <p> The locale always used is the one returned by {@link
+     * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
+     * previous invocations of other formatting methods on this object.
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This output stream
+     *
+     * @since  1.5
+     */
+    public PrintStream format(String format, Object ... args) {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                if ((formatter == null)
+                    || (formatter.locale() != Locale.getDefault()))
+                    formatter = new Formatter((Appendable) this);
+                formatter.format(Locale.getDefault(), format, args);
+            }
+        } catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        } catch (IOException x) {
+            trouble = true;
+        }
+        return this;
+    }
+
+    /**
+     * Writes a formatted string to this output stream using the specified
+     * format string and arguments.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         is applied.
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This output stream
+     *
+     * @since  1.5
+     */
+    public PrintStream format(Locale l, String format, Object ... args) {
+        try {
+            synchronized (this) {
+                ensureOpen();
+                if ((formatter == null)
+                    || (formatter.locale() != l))
+                    formatter = new Formatter(this, l);
+                formatter.format(l, format, args);
+            }
+        } catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        } catch (IOException x) {
+            trouble = true;
+        }
+        return this;
+    }
+
+    /**
+     * Appends the specified character sequence to this output stream.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.print(csq.toString()) </pre>
+     *
+     * <p> Depending on the specification of <tt>toString</tt> for the
+     * character sequence <tt>csq</tt>, the entire sequence may not be
+     * appended.  For instance, invoking then <tt>toString</tt> method of a
+     * character buffer will return a subsequence whose content depends upon
+     * the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this output stream.
+     *
+     * @return  This output stream
+     *
+     * @since  1.5
+     */
+    public PrintStream append(CharSequence csq) {
+        if (csq == null)
+            print("null");
+        else
+            print(csq.toString());
+        return this;
+    }
+
+    /**
+     * Appends a subsequence of the specified character sequence to this output
+     * stream.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.print(csq.subSequence(start, end).toString()) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @param  start
+     *         The index of the first character in the subsequence
+     *
+     * @param  end
+     *         The index of the character following the last character in the
+     *         subsequence
+     *
+     * @return  This output stream
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @since  1.5
+     */
+    public PrintStream append(CharSequence csq, int start, int end) {
+        CharSequence cs = (csq == null ? "null" : csq);
+        write(cs.subSequence(start, end).toString());
+        return this;
+    }
+
+    /**
+     * Appends the specified character to this output stream.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.print(c) </pre>
+     *
+     * @param  c
+     *         The 16-bit character to append
+     *
+     * @return  This output stream
+     *
+     * @since  1.5
+     */
+    public PrintStream append(char c) {
+        print(c);
+        return this;
+    }
+
+}
diff --git a/java/io/PrintWriter.annotated.java b/java/io/PrintWriter.annotated.java
new file mode 100644
index 0000000..531dfb0
--- /dev/null
+++ b/java/io/PrintWriter.annotated.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.io;
+
+import java.nio.charset.Charset;
+import java.util.Formatter;
+import java.util.Locale;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class PrintWriter extends java.io.Writer {
+
+public PrintWriter(@libcore.util.NonNull java.io.Writer out) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.Writer out, boolean autoFlush) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.OutputStream out) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.OutputStream out, boolean autoFlush) { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.lang.String fileName) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.lang.String fileName, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.File file) throws java.io.FileNotFoundException { throw new RuntimeException("Stub!"); }
+
+public PrintWriter(@libcore.util.NonNull java.io.File file, @libcore.util.NonNull java.lang.String csn) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public void flush() { throw new RuntimeException("Stub!"); }
+
+public void close() { throw new RuntimeException("Stub!"); }
+
+public boolean checkError() { throw new RuntimeException("Stub!"); }
+
+protected void setError() { throw new RuntimeException("Stub!"); }
+
+protected void clearError() { throw new RuntimeException("Stub!"); }
+
+public void write(int c) { throw new RuntimeException("Stub!"); }
+
+public void write(char[] buf, int off, int len) { throw new RuntimeException("Stub!"); }
+
+public void write(char[] buf) { throw new RuntimeException("Stub!"); }
+
+public void write(@libcore.util.NonNull java.lang.String s, int off, int len) { throw new RuntimeException("Stub!"); }
+
+public void write(@libcore.util.NonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
+
+public void print(boolean b) { throw new RuntimeException("Stub!"); }
+
+public void print(char c) { throw new RuntimeException("Stub!"); }
+
+public void print(int i) { throw new RuntimeException("Stub!"); }
+
+public void print(long l) { throw new RuntimeException("Stub!"); }
+
+public void print(float f) { throw new RuntimeException("Stub!"); }
+
+public void print(double d) { throw new RuntimeException("Stub!"); }
+
+public void print(char[] s) { throw new RuntimeException("Stub!"); }
+
+public void print(@libcore.util.Nullable java.lang.String s) { throw new RuntimeException("Stub!"); }
+
+public void print(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public void println() { throw new RuntimeException("Stub!"); }
+
+public void println(boolean x) { throw new RuntimeException("Stub!"); }
+
+public void println(char x) { throw new RuntimeException("Stub!"); }
+
+public void println(int x) { throw new RuntimeException("Stub!"); }
+
+public void println(long x) { throw new RuntimeException("Stub!"); }
+
+public void println(float x) { throw new RuntimeException("Stub!"); }
+
+public void println(double x) { throw new RuntimeException("Stub!"); }
+
+public void println(char[] x) { throw new RuntimeException("Stub!"); }
+
+public void println(@libcore.util.Nullable java.lang.String x) { throw new RuntimeException("Stub!"); }
+
+public void println(@libcore.util.Nullable java.lang.Object x) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter printf(@libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter printf(@libcore.util.Nullable java.util.Locale l, @libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter format(@libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter format(@libcore.util.Nullable java.util.Locale l, @libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter append(@libcore.util.Nullable java.lang.CharSequence csq) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter append(@libcore.util.Nullable java.lang.CharSequence csq, int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.io.PrintWriter append(char c) { throw new RuntimeException("Stub!"); }
+
+protected java.io.Writer out;
+}
diff --git a/java/io/PrintWriter.java b/java/io/PrintWriter.java
new file mode 100644
index 0000000..9287a19
--- /dev/null
+++ b/java/io/PrintWriter.java
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Objects;
+import java.util.Formatter;
+import java.util.Locale;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+/**
+ * Prints formatted representations of objects to a text-output stream.  This
+ * class implements all of the <tt>print</tt> methods found in {@link
+ * PrintStream}.  It does not contain methods for writing raw bytes, for which
+ * a program should use unencoded byte streams.
+ *
+ * <p> Unlike the {@link PrintStream} class, if automatic flushing is enabled
+ * it will be done only when one of the <tt>println</tt>, <tt>printf</tt>, or
+ * <tt>format</tt> methods is invoked, rather than whenever a newline character
+ * happens to be output.  These methods use the platform's own notion of line
+ * separator rather than the newline character.
+ *
+ * <p> Methods in this class never throw I/O exceptions, although some of its
+ * constructors may.  The client may inquire as to whether any errors have
+ * occurred by invoking {@link #checkError checkError()}.
+ *
+ * @author      Frank Yellin
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class PrintWriter extends Writer {
+
+    /**
+     * The underlying character-output stream of this
+     * <code>PrintWriter</code>.
+     *
+     * @since 1.2
+     */
+    protected Writer out;
+
+    private final boolean autoFlush;
+    private boolean trouble = false;
+    private Formatter formatter;
+    private PrintStream psOut = null;
+
+    /**
+     * Line separator string.  This is the value of the line.separator
+     * property at the moment that the stream was created.
+     */
+    private final String lineSeparator;
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws UnsupportedEncodingException  if the charset is not supported
+     */
+    private static Charset toCharset(String csn)
+        throws UnsupportedEncodingException
+    {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            // UnsupportedEncodingException should be thrown
+            throw new UnsupportedEncodingException(csn);
+        }
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing.
+     *
+     * @param  out        A character-output stream
+     */
+    public PrintWriter (Writer out) {
+        this(out, false);
+    }
+
+    /**
+     * Creates a new PrintWriter.
+     *
+     * @param  out        A character-output stream
+     * @param  autoFlush  A boolean; if true, the <tt>println</tt>,
+     *                    <tt>printf</tt>, or <tt>format</tt> methods will
+     *                    flush the output buffer
+     */
+    public PrintWriter(Writer out,
+                       boolean autoFlush) {
+        super(out);
+        this.out = out;
+        this.autoFlush = autoFlush;
+        lineSeparator = java.security.AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction("line.separator"));
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, from an
+     * existing OutputStream.  This convenience constructor creates the
+     * necessary intermediate OutputStreamWriter, which will convert characters
+     * into bytes using the default character encoding.
+     *
+     * @param  out        An output stream
+     *
+     * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
+     */
+    public PrintWriter(OutputStream out) {
+        this(out, false);
+    }
+
+    /**
+     * Creates a new PrintWriter from an existing OutputStream.  This
+     * convenience constructor creates the necessary intermediate
+     * OutputStreamWriter, which will convert characters into bytes using the
+     * default character encoding.
+     *
+     * @param  out        An output stream
+     * @param  autoFlush  A boolean; if true, the <tt>println</tt>,
+     *                    <tt>printf</tt>, or <tt>format</tt> methods will
+     *                    flush the output buffer
+     *
+     * @see java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
+     */
+    public PrintWriter(OutputStream out, boolean autoFlush) {
+        this(new BufferedWriter(new OutputStreamWriter(out)), autoFlush);
+
+        // save print stream for error propagation
+        if (out instanceof java.io.PrintStream) {
+            psOut = (PrintStream) out;
+        }
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, with the
+     * specified file name.  This convenience constructor creates the necessary
+     * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+     * which will encode characters using the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this writer.
+     *         If the file exists then it will be truncated to zero size;
+     *         otherwise, a new file will be created.  The output will be
+     *         written to the file and is buffered.
+     *
+     * @throws  FileNotFoundException
+     *          If the given string does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @since  1.5
+     */
+    public PrintWriter(String fileName) throws FileNotFoundException {
+        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
+             false);
+    }
+
+    /* Private constructor */
+    private PrintWriter(Charset charset, File file)
+        throws FileNotFoundException
+    {
+        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)),
+             false);
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, with the
+     * specified file name and charset.  This convenience constructor creates
+     * the necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this writer.
+     *         If the file exists then it will be truncated to zero size;
+     *         otherwise, a new file will be created.  The output will be
+     *         written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given string does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @since  1.5
+     */
+    public PrintWriter(String fileName, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), new File(fileName));
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, with the
+     * specified file.  This convenience constructor creates the necessary
+     * intermediate {@link java.io.OutputStreamWriter OutputStreamWriter},
+     * which will encode characters using the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this writer.  If the file
+     *         exists then it will be truncated to zero size; otherwise, a new
+     *         file will be created.  The output will be written to the file
+     *         and is buffered.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())}
+     *          denies write access to the file
+     *
+     * @since  1.5
+     */
+    public PrintWriter(File file) throws FileNotFoundException {
+        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
+             false);
+    }
+
+    /**
+     * Creates a new PrintWriter, without automatic line flushing, with the
+     * specified file and charset.  This convenience constructor creates the
+     * necessary intermediate {@link java.io.OutputStreamWriter
+     * OutputStreamWriter}, which will encode characters using the provided
+     * charset.
+     *
+     * @param  file
+     *         The file to use as the destination of this writer.  If the file
+     *         exists then it will be truncated to zero size; otherwise, a new
+     *         file will be created.  The output will be written to the file
+     *         and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())}
+     *          denies write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @since  1.5
+     */
+    public PrintWriter(File file, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), file);
+    }
+
+    /** Checks to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (out == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Flushes the stream.
+     * @see #checkError()
+     */
+    public void flush() {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                out.flush();
+            }
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /**
+     * Closes the stream and releases any system resources associated
+     * with it. Closing a previously closed stream has no effect.
+     *
+     * @see #checkError()
+     */
+    public void close() {
+        try {
+            synchronized (lock) {
+                if (out == null)
+                    return;
+                out.close();
+                out = null;
+            }
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /**
+     * Flushes the stream if it's not closed and checks its error state.
+     *
+     * @return <code>true</code> if the print stream has encountered an error,
+     *          either on the underlying output stream or during a format
+     *          conversion.
+     */
+    public boolean checkError() {
+        if (out != null) {
+            flush();
+        }
+        if (out instanceof java.io.PrintWriter) {
+            PrintWriter pw = (PrintWriter) out;
+            return pw.checkError();
+        } else if (psOut != null) {
+            return psOut.checkError();
+        }
+        return trouble;
+    }
+
+    /**
+     * Indicates that an error has occurred.
+     *
+     * <p> This method will cause subsequent invocations of {@link
+     * #checkError()} to return <tt>true</tt> until {@link
+     * #clearError()} is invoked.
+     */
+    protected void setError() {
+        trouble = true;
+    }
+
+    /**
+     * Clears the error state of this stream.
+     *
+     * <p> This method will cause subsequent invocations of {@link
+     * #checkError()} to return <tt>false</tt> until another write
+     * operation fails and invokes {@link #setError()}.
+     *
+     * @since 1.6
+     */
+    protected void clearError() {
+        trouble = false;
+    }
+
+    /*
+     * Exception-catching, synchronized output operations,
+     * which also implement the write() methods of Writer
+     */
+
+    /**
+     * Writes a single character.
+     * @param c int specifying a character to be written.
+     */
+    public void write(int c) {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                out.write(c);
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /**
+     * Writes A Portion of an array of characters.
+     * @param buf Array of characters
+     * @param off Offset from which to start writing characters
+     * @param len Number of characters to write
+     */
+    public void write(char buf[], int off, int len) {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                out.write(buf, off, len);
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /**
+     * Writes an array of characters.  This method cannot be inherited from the
+     * Writer class because it must suppress I/O exceptions.
+     * @param buf Array of characters to be written
+     */
+    public void write(char buf[]) {
+        write(buf, 0, buf.length);
+    }
+
+    /**
+     * Writes a portion of a string.
+     * @param s A String
+     * @param off Offset from which to start writing characters
+     * @param len Number of characters to write
+     */
+    public void write(String s, int off, int len) {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                out.write(s, off, len);
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /**
+     * Writes a string.  This method cannot be inherited from the Writer class
+     * because it must suppress I/O exceptions.
+     * @param s String to be written
+     */
+    public void write(String s) {
+        write(s, 0, s.length());
+    }
+
+    private void newLine() {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                out.write(lineSeparator);
+                if (autoFlush)
+                    out.flush();
+            }
+        }
+        catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        }
+        catch (IOException x) {
+            trouble = true;
+        }
+    }
+
+    /* Methods that do not terminate lines */
+
+    /**
+     * Prints a boolean value.  The string produced by <code>{@link
+     * java.lang.String#valueOf(boolean)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      b   The <code>boolean</code> to be printed
+     */
+    public void print(boolean b) {
+        write(b ? "true" : "false");
+    }
+
+    /**
+     * Prints a character.  The character is translated into one or more bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      c   The <code>char</code> to be printed
+     */
+    public void print(char c) {
+        write(c);
+    }
+
+    /**
+     * Prints an integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(int)}</code> is translated into bytes according
+     * to the platform's default character encoding, and these bytes are
+     * written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      i   The <code>int</code> to be printed
+     * @see        java.lang.Integer#toString(int)
+     */
+    public void print(int i) {
+        write(String.valueOf(i));
+    }
+
+    /**
+     * Prints a long integer.  The string produced by <code>{@link
+     * java.lang.String#valueOf(long)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      l   The <code>long</code> to be printed
+     * @see        java.lang.Long#toString(long)
+     */
+    public void print(long l) {
+        write(String.valueOf(l));
+    }
+
+    /**
+     * Prints a floating-point number.  The string produced by <code>{@link
+     * java.lang.String#valueOf(float)}</code> is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      f   The <code>float</code> to be printed
+     * @see        java.lang.Float#toString(float)
+     */
+    public void print(float f) {
+        write(String.valueOf(f));
+    }
+
+    /**
+     * Prints a double-precision floating-point number.  The string produced by
+     * <code>{@link java.lang.String#valueOf(double)}</code> is translated into
+     * bytes according to the platform's default character encoding, and these
+     * bytes are written in exactly the manner of the <code>{@link
+     * #write(int)}</code> method.
+     *
+     * @param      d   The <code>double</code> to be printed
+     * @see        java.lang.Double#toString(double)
+     */
+    public void print(double d) {
+        write(String.valueOf(d));
+    }
+
+    /**
+     * Prints an array of characters.  The characters are converted into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      s   The array of chars to be printed
+     *
+     * @throws  NullPointerException  If <code>s</code> is <code>null</code>
+     */
+    public void print(char s[]) {
+        write(s);
+    }
+
+    /**
+     * Prints a string.  If the argument is <code>null</code> then the string
+     * <code>"null"</code> is printed.  Otherwise, the string's characters are
+     * converted into bytes according to the platform's default character
+     * encoding, and these bytes are written in exactly the manner of the
+     * <code>{@link #write(int)}</code> method.
+     *
+     * @param      s   The <code>String</code> to be printed
+     */
+    public void print(String s) {
+        if (s == null) {
+            s = "null";
+        }
+        write(s);
+    }
+
+    /**
+     * Prints an object.  The string produced by the <code>{@link
+     * java.lang.String#valueOf(Object)}</code> method is translated into bytes
+     * according to the platform's default character encoding, and these bytes
+     * are written in exactly the manner of the <code>{@link #write(int)}</code>
+     * method.
+     *
+     * @param      obj   The <code>Object</code> to be printed
+     * @see        java.lang.Object#toString()
+     */
+    public void print(Object obj) {
+        write(String.valueOf(obj));
+    }
+
+    /* Methods that do terminate lines */
+
+    /**
+     * Terminates the current line by writing the line separator string.  The
+     * line separator string is defined by the system property
+     * <code>line.separator</code>, and is not necessarily a single newline
+     * character (<code>'\n'</code>).
+     */
+    public void println() {
+        newLine();
+    }
+
+    /**
+     * Prints a boolean value and then terminates the line.  This method behaves
+     * as though it invokes <code>{@link #print(boolean)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x the <code>boolean</code> value to be printed
+     */
+    public void println(boolean x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints a character and then terminates the line.  This method behaves as
+     * though it invokes <code>{@link #print(char)}</code> and then <code>{@link
+     * #println()}</code>.
+     *
+     * @param x the <code>char</code> value to be printed
+     */
+    public void println(char x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints an integer and then terminates the line.  This method behaves as
+     * though it invokes <code>{@link #print(int)}</code> and then <code>{@link
+     * #println()}</code>.
+     *
+     * @param x the <code>int</code> value to be printed
+     */
+    public void println(int x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints a long integer and then terminates the line.  This method behaves
+     * as though it invokes <code>{@link #print(long)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x the <code>long</code> value to be printed
+     */
+    public void println(long x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints a floating-point number and then terminates the line.  This method
+     * behaves as though it invokes <code>{@link #print(float)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x the <code>float</code> value to be printed
+     */
+    public void println(float x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints a double-precision floating-point number and then terminates the
+     * line.  This method behaves as though it invokes <code>{@link
+     * #print(double)}</code> and then <code>{@link #println()}</code>.
+     *
+     * @param x the <code>double</code> value to be printed
+     */
+    public void println(double x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints an array of characters and then terminates the line.  This method
+     * behaves as though it invokes <code>{@link #print(char[])}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x the array of <code>char</code> values to be printed
+     */
+    public void println(char x[]) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints a String and then terminates the line.  This method behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x the <code>String</code> value to be printed
+     */
+    public void println(String x) {
+        synchronized (lock) {
+            print(x);
+            println();
+        }
+    }
+
+    /**
+     * Prints an Object and then terminates the line.  This method calls
+     * at first String.valueOf(x) to get the printed object's string value,
+     * then behaves as
+     * though it invokes <code>{@link #print(String)}</code> and then
+     * <code>{@link #println()}</code>.
+     *
+     * @param x  The <code>Object</code> to be printed.
+     */
+    public void println(Object x) {
+        String s = String.valueOf(x);
+        synchronized (lock) {
+            print(s);
+            println();
+        }
+    }
+
+    /**
+     * A convenience method to write a formatted string to this writer using
+     * the specified format string and arguments.  If automatic flushing is
+     * enabled, calls to this method will flush the output buffer.
+     *
+     * <p> An invocation of this method of the form <tt>out.printf(format,
+     * args)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.format(format, args) </pre>
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public PrintWriter printf(String format, Object ... args) {
+        return format(format, args);
+    }
+
+    /**
+     * A convenience method to write a formatted string to this writer using
+     * the specified format string and arguments.  If automatic flushing is
+     * enabled, calls to this method will flush the output buffer.
+     *
+     * <p> An invocation of this method of the form <tt>out.printf(l, format,
+     * args)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.format(l, format, args) </pre>
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         is applied.
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public PrintWriter printf(Locale l, String format, Object ... args) {
+        return format(l, format, args);
+    }
+
+    /**
+     * Writes a formatted string to this writer using the specified format
+     * string and arguments.  If automatic flushing is enabled, calls to this
+     * method will flush the output buffer.
+     *
+     * <p> The locale always used is the one returned by {@link
+     * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
+     * previous invocations of other formatting methods on this object.
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          Formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public PrintWriter format(String format, Object ... args) {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                if ((formatter == null)
+                    || (formatter.locale() != Locale.getDefault()))
+                    formatter = new Formatter(this);
+                formatter.format(Locale.getDefault(), format, args);
+                if (autoFlush)
+                    out.flush();
+            }
+        } catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        } catch (IOException x) {
+            trouble = true;
+        }
+        return this;
+    }
+
+    /**
+     * Writes a formatted string to this writer using the specified format
+     * string and arguments.  If automatic flushing is enabled, calls to this
+     * method will flush the output buffer.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If <tt>l</tt> is <tt>null</tt> then no localization
+     *         is applied.
+     *
+     * @param  format
+     *         A format string as described in <a
+     *         href="../util/Formatter.html#syntax">Format string syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         <tt>null</tt> argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @throws  NullPointerException
+     *          If the <tt>format</tt> is <tt>null</tt>
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public PrintWriter format(Locale l, String format, Object ... args) {
+        try {
+            synchronized (lock) {
+                ensureOpen();
+                if ((formatter == null) || (formatter.locale() != l))
+                    formatter = new Formatter(this, l);
+                formatter.format(l, format, args);
+                if (autoFlush)
+                    out.flush();
+            }
+        } catch (InterruptedIOException x) {
+            Thread.currentThread().interrupt();
+        } catch (IOException x) {
+            trouble = true;
+        }
+        return this;
+    }
+
+    /**
+     * Appends the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.toString()) </pre>
+     *
+     * <p> Depending on the specification of <tt>toString</tt> for the
+     * character sequence <tt>csq</tt>, the entire sequence may not be
+     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * character buffer will return a subsequence whose content depends upon
+     * the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this writer.
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public PrintWriter append(CharSequence csq) {
+        if (csq == null)
+            write("null");
+        else
+            write(csq.toString());
+        return this;
+    }
+
+    /**
+     * Appends a subsequence of the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @param  start
+     *         The index of the first character in the subsequence
+     *
+     * @param  end
+     *         The index of the character following the last character in the
+     *         subsequence
+     *
+     * @return  This writer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @since  1.5
+     */
+    public PrintWriter append(CharSequence csq, int start, int end) {
+        CharSequence cs = (csq == null ? "null" : csq);
+        write(cs.subSequence(start, end).toString());
+        return this;
+    }
+
+    /**
+     * Appends the specified character to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(c) </pre>
+     *
+     * @param  c
+     *         The 16-bit character to append
+     *
+     * @return  This writer
+     *
+     * @since 1.5
+     */
+    public PrintWriter append(char c) {
+        write(c);
+        return this;
+    }
+}
diff --git a/java/io/PushbackInputStream.java b/java/io/PushbackInputStream.java
new file mode 100644
index 0000000..b44848d
--- /dev/null
+++ b/java/io/PushbackInputStream.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * A <code>PushbackInputStream</code> adds
+ * functionality to another input stream, namely
+ * the  ability to "push back" or "unread"
+ * one byte. This is useful in situations where
+ * it is  convenient for a fragment of code
+ * to read an indefinite number of data bytes
+ * that  are delimited by a particular byte
+ * value; after reading the terminating byte,
+ * the  code fragment can "unread" it, so that
+ * the next read operation on the input stream
+ * will reread the byte that was pushed back.
+ * For example, bytes representing the  characters
+ * constituting an identifier might be terminated
+ * by a byte representing an  operator character;
+ * a method whose job is to read just an identifier
+ * can read until it  sees the operator and
+ * then push the operator back to be re-read.
+ *
+ * @author  David Connelly
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class PushbackInputStream extends FilterInputStream {
+    /**
+     * The pushback buffer.
+     * @since   JDK1.1
+     */
+    protected byte[] buf;
+
+    /**
+     * The position within the pushback buffer from which the next byte will
+     * be read.  When the buffer is empty, <code>pos</code> is equal to
+     * <code>buf.length</code>; when the buffer is full, <code>pos</code> is
+     * equal to zero.
+     *
+     * @since   JDK1.1
+     */
+    protected int pos;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (in == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Creates a <code>PushbackInputStream</code>
+     * with a pushback buffer of the specified <code>size</code>,
+     * and saves its  argument, the input stream
+     * <code>in</code>, for later use. Initially,
+     * there is no pushed-back byte  (the field
+     * <code>pushBack</code> is initialized to
+     * <code>-1</code>).
+     *
+     * @param  in    the input stream from which bytes will be read.
+     * @param  size  the size of the pushback buffer.
+     * @exception IllegalArgumentException if {@code size <= 0}
+     * @since  JDK1.1
+     */
+    public PushbackInputStream(InputStream in, int size) {
+        super(in);
+        if (size <= 0) {
+            throw new IllegalArgumentException("size <= 0");
+        }
+        this.buf = new byte[size];
+        this.pos = size;
+    }
+
+    /**
+     * Creates a <code>PushbackInputStream</code>
+     * and saves its  argument, the input stream
+     * <code>in</code>, for later use. Initially,
+     * there is no pushed-back byte  (the field
+     * <code>pushBack</code> is initialized to
+     * <code>-1</code>).
+     *
+     * @param   in   the input stream from which bytes will be read.
+     */
+    public PushbackInputStream(InputStream in) {
+        this(in, 1);
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The value
+     * byte is returned as an <code>int</code> in the range
+     * <code>0</code> to <code>255</code>. If no byte is available
+     * because the end of the stream has been reached, the value
+     * <code>-1</code> is returned. This method blocks until input data
+     * is available, the end of the stream is detected, or an exception
+     * is thrown.
+     *
+     * <p> This method returns the most recently pushed-back byte, if there is
+     * one, and otherwise calls the <code>read</code> method of its underlying
+     * input stream and returns whatever value that method returns.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream has been reached.
+     * @exception  IOException  if this input stream has been closed by
+     *             invoking its {@link #close()} method,
+     *             or an I/O error occurs.
+     * @see        java.io.InputStream#read()
+     */
+    public int read() throws IOException {
+        ensureOpen();
+        if (pos < buf.length) {
+            return buf[pos++] & 0xff;
+        }
+        return super.read();
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this input stream into
+     * an array of bytes.  This method first reads any pushed-back bytes; after
+     * that, if fewer than <code>len</code> bytes have been read then it
+     * reads from the underlying input stream. If <code>len</code> is not zero, the method
+     * blocks until at least 1 byte of input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in the destination array <code>b</code>
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception  IOException  if this input stream has been closed by
+     *             invoking its {@link #close()} method,
+     *             or an I/O error occurs.
+     * @see        java.io.InputStream#read(byte[], int, int)
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        int avail = buf.length - pos;
+        if (avail > 0) {
+            if (len < avail) {
+                avail = len;
+            }
+            System.arraycopy(buf, pos, b, off, avail);
+            pos += avail;
+            off += avail;
+            len -= avail;
+        }
+        if (len > 0) {
+            len = super.read(b, off, len);
+            if (len == -1) {
+                return avail == 0 ? -1 : avail;
+            }
+            return avail + len;
+        }
+        return avail;
+    }
+
+    /**
+     * Pushes back a byte by copying it to the front of the pushback buffer.
+     * After this method returns, the next byte to be read will have the value
+     * <code>(byte)b</code>.
+     *
+     * @param      b   the <code>int</code> value whose low-order
+     *                  byte is to be pushed back.
+     * @exception IOException If there is not enough room in the pushback
+     *            buffer for the byte, or this input stream has been closed by
+     *            invoking its {@link #close()} method.
+     */
+    public void unread(int b) throws IOException {
+        ensureOpen();
+        if (pos == 0) {
+            throw new IOException("Push back buffer is full");
+        }
+        buf[--pos] = (byte)b;
+    }
+
+    /**
+     * Pushes back a portion of an array of bytes by copying it to the front
+     * of the pushback buffer.  After this method returns, the next byte to be
+     * read will have the value <code>b[off]</code>, the byte after that will
+     * have the value <code>b[off+1]</code>, and so forth.
+     *
+     * @param b the byte array to push back.
+     * @param off the start offset of the data.
+     * @param len the number of bytes to push back.
+     * @exception IOException If there is not enough room in the pushback
+     *            buffer for the specified number of bytes,
+     *            or this input stream has been closed by
+     *            invoking its {@link #close()} method.
+     * @since     JDK1.1
+     */
+    public void unread(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (len > pos) {
+            throw new IOException("Push back buffer is full");
+        }
+        pos -= len;
+        System.arraycopy(b, off, buf, pos, len);
+    }
+
+    /**
+     * Pushes back an array of bytes by copying it to the front of the
+     * pushback buffer.  After this method returns, the next byte to be read
+     * will have the value <code>b[0]</code>, the byte after that will have the
+     * value <code>b[1]</code>, and so forth.
+     *
+     * @param b the byte array to push back
+     * @exception IOException If there is not enough room in the pushback
+     *            buffer for the specified number of bytes,
+     *            or this input stream has been closed by
+     *            invoking its {@link #close()} method.
+     * @since     JDK1.1
+     */
+    public void unread(byte[] b) throws IOException {
+        unread(b, 0, b.length);
+    }
+
+    /**
+     * Returns an estimate of the number of bytes that can be read (or
+     * skipped over) from this input stream without blocking by the next
+     * invocation of a method for this input stream. The next invocation might be
+     * the same thread or another thread.  A single read or skip of this
+     * many bytes will not block, but may read or skip fewer bytes.
+     *
+     * <p> The method returns the sum of the number of bytes that have been
+     * pushed back and the value returned by {@link
+     * java.io.FilterInputStream#available available}.
+     *
+     * @return     the number of bytes that can be read (or skipped over) from
+     *             the input stream without blocking.
+     * @exception  IOException  if this input stream has been closed by
+     *             invoking its {@link #close()} method,
+     *             or an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.InputStream#available()
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        int n = buf.length - pos;
+        int avail = super.available();
+        return n > (Integer.MAX_VALUE - avail)
+                    ? Integer.MAX_VALUE
+                    : n + avail;
+    }
+
+    /**
+     * Skips over and discards <code>n</code> bytes of data from this
+     * input stream. The <code>skip</code> method may, for a variety of
+     * reasons, end up skipping over some smaller number of bytes,
+     * possibly zero.  If <code>n</code> is negative, no bytes are skipped.
+     *
+     * <p> The <code>skip</code> method of <code>PushbackInputStream</code>
+     * first skips over the bytes in the pushback buffer, if any.  It then
+     * calls the <code>skip</code> method of the underlying input stream if
+     * more bytes need to be skipped.  The actual number of bytes skipped
+     * is returned.
+     *
+     * @param      n  {@inheritDoc}
+     * @return     {@inheritDoc}
+     * @exception  IOException  if the stream does not support seek,
+     *            or the stream has been closed by
+     *            invoking its {@link #close()} method,
+     *            or an I/O error occurs.
+     * @see        java.io.FilterInputStream#in
+     * @see        java.io.InputStream#skip(long n)
+     * @since      1.2
+     */
+    public long skip(long n) throws IOException {
+        ensureOpen();
+        if (n <= 0) {
+            return 0;
+        }
+
+        long pskip = buf.length - pos;
+        if (pskip > 0) {
+            if (n < pskip) {
+                pskip = n;
+            }
+            pos += pskip;
+            n -= pskip;
+        }
+        if (n > 0) {
+            pskip += super.skip(n);
+        }
+        return pskip;
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code> and
+     * <code>reset</code> methods, which it does not.
+     *
+     * @return   <code>false</code>, since this class does not support the
+     *           <code>mark</code> and <code>reset</code> methods.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Marks the current position in this input stream.
+     *
+     * <p> The <code>mark</code> method of <code>PushbackInputStream</code>
+     * does nothing.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.InputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {
+    }
+
+    /**
+     * Repositions this stream to the position at the time the
+     * <code>mark</code> method was last called on this input stream.
+     *
+     * <p> The method <code>reset</code> for class
+     * <code>PushbackInputStream</code> does nothing except throw an
+     * <code>IOException</code>.
+     *
+     * @exception  IOException  if this method is invoked.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.IOException
+     */
+    public synchronized void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * Once the stream has been closed, further read(), unread(),
+     * available(), reset(), or skip() invocations will throw an IOException.
+     * Closing a previously closed stream has no effect.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public synchronized void close() throws IOException {
+        if (in == null)
+            return;
+        in.close();
+        in = null;
+        buf = null;
+    }
+}
diff --git a/java/io/PushbackReader.java b/java/io/PushbackReader.java
new file mode 100644
index 0000000..f918621
--- /dev/null
+++ b/java/io/PushbackReader.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A character-stream reader that allows characters to be pushed back into the
+ * stream.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class PushbackReader extends FilterReader {
+
+    /** Pushback buffer */
+    private char[] buf;
+
+    /** Current position in buffer */
+    private int pos;
+
+    /**
+     * Creates a new pushback reader with a pushback buffer of the given size.
+     *
+     * @param   in   The reader from which characters will be read
+     * @param   size The size of the pushback buffer
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public PushbackReader(Reader in, int size) {
+        super(in);
+        if (size <= 0) {
+            throw new IllegalArgumentException("size <= 0");
+        }
+        this.buf = new char[size];
+        this.pos = size;
+    }
+
+    /**
+     * Creates a new pushback reader with a one-character pushback buffer.
+     *
+     * @param   in  The reader from which characters will be read
+     */
+    public PushbackReader(Reader in) {
+        this(in, 1);
+    }
+
+    /** Checks to make sure that the stream has not been closed. */
+    private void ensureOpen() throws IOException {
+        if (buf == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @return     The character read, or -1 if the end of the stream has been
+     *             reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (pos < buf.length)
+                return buf[pos++];
+            else
+                return super.read();
+        }
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * @param      cbuf  Destination buffer
+     * @param      off   Offset at which to start writing characters
+     * @param      len   Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            try {
+                if (len <= 0) {
+                    if (len < 0) {
+                        throw new IndexOutOfBoundsException();
+                    } else if ((off < 0) || (off > cbuf.length)) {
+                        throw new IndexOutOfBoundsException();
+                    }
+                    return 0;
+                }
+                int avail = buf.length - pos;
+                if (avail > 0) {
+                    if (len < avail)
+                        avail = len;
+                    System.arraycopy(buf, pos, cbuf, off, avail);
+                    pos += avail;
+                    off += avail;
+                    len -= avail;
+                }
+                if (len > 0) {
+                    len = super.read(cbuf, off, len);
+                    if (len == -1) {
+                        return (avail == 0) ? -1 : avail;
+                    }
+                    return avail + len;
+                }
+                return avail;
+            } catch (ArrayIndexOutOfBoundsException e) {
+                throw new IndexOutOfBoundsException();
+            }
+        }
+    }
+
+    /**
+     * Pushes back a single character by copying it to the front of the
+     * pushback buffer. After this method returns, the next character to be read
+     * will have the value <code>(char)c</code>.
+     *
+     * @param  c  The int value representing a character to be pushed back
+     *
+     * @exception  IOException  If the pushback buffer is full,
+     *                          or if some other I/O error occurs
+     */
+    public void unread(int c) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (pos == 0)
+                throw new IOException("Pushback buffer overflow");
+            buf[--pos] = (char) c;
+        }
+    }
+
+    /**
+     * Pushes back a portion of an array of characters by copying it to the
+     * front of the pushback buffer.  After this method returns, the next
+     * character to be read will have the value <code>cbuf[off]</code>, the
+     * character after that will have the value <code>cbuf[off+1]</code>, and
+     * so forth.
+     *
+     * @param  cbuf  Character array
+     * @param  off   Offset of first character to push back
+     * @param  len   Number of characters to push back
+     *
+     * @exception  IOException  If there is insufficient room in the pushback
+     *                          buffer, or if some other I/O error occurs
+     */
+    public void unread(char cbuf[], int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (len > pos)
+                throw new IOException("Pushback buffer overflow");
+            pos -= len;
+            System.arraycopy(cbuf, off, buf, pos, len);
+        }
+    }
+
+    /**
+     * Pushes back an array of characters by copying it to the front of the
+     * pushback buffer.  After this method returns, the next character to be
+     * read will have the value <code>cbuf[0]</code>, the character after that
+     * will have the value <code>cbuf[1]</code>, and so forth.
+     *
+     * @param  cbuf  Character array to push back
+     *
+     * @exception  IOException  If there is insufficient room in the pushback
+     *                          buffer, or if some other I/O error occurs
+     */
+    public void unread(char cbuf[]) throws IOException {
+        unread(cbuf, 0, cbuf.length);
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            return (pos < buf.length) || super.ready();
+        }
+    }
+
+    /**
+     * Marks the present position in the stream. The <code>mark</code>
+     * for class <code>PushbackReader</code> always throws an exception.
+     *
+     * @exception  IOException  Always, since mark is not supported
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+
+    /**
+     * Resets the stream. The <code>reset</code> method of
+     * <code>PushbackReader</code> always throws an exception.
+     *
+     * @exception  IOException  Always, since reset is not supported
+     */
+    public void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+
+    /**
+     * Tells whether this stream supports the mark() operation, which it does
+     * not.
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Closes the stream and releases any system resources associated with
+     * it. Once the stream has been closed, further read(),
+     * unread(), ready(), or skip() invocations will throw an IOException.
+     * Closing a previously closed stream has no effect.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void close() throws IOException {
+        super.close();
+        buf = null;
+    }
+
+    /**
+     * Skips characters.  This method will block until some characters are
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    The number of characters actually skipped
+     *
+     * @exception  IllegalArgumentException  If <code>n</code> is negative.
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0L)
+            throw new IllegalArgumentException("skip value is negative");
+        synchronized (lock) {
+            ensureOpen();
+            int avail = buf.length - pos;
+            if (avail > 0) {
+                if (n <= avail) {
+                    pos += n;
+                    return n;
+                } else {
+                    pos = buf.length;
+                    n -= avail;
+                }
+            }
+            return avail + super.skip(n);
+        }
+    }
+}
diff --git a/java/io/RandomAccessFile.java b/java/io/RandomAccessFile.java
new file mode 100644
index 0000000..06683ad
--- /dev/null
+++ b/java/io/RandomAccessFile.java
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.nio.channels.FileChannel;
+import sun.nio.ch.FileChannelImpl;
+import android.system.Os;
+import android.system.ErrnoException;
+import dalvik.system.CloseGuard;
+import libcore.io.IoBridge;
+import libcore.io.IoTracker;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import static android.system.OsConstants.*;
+
+
+/**
+ * Instances of this class support both reading and writing to a
+ * random access file. A random access file behaves like a large
+ * array of bytes stored in the file system. There is a kind of cursor,
+ * or index into the implied array, called the <em>file pointer</em>;
+ * input operations read bytes starting at the file pointer and advance
+ * the file pointer past the bytes read. If the random access file is
+ * created in read/write mode, then output operations are also available;
+ * output operations write bytes starting at the file pointer and advance
+ * the file pointer past the bytes written. Output operations that write
+ * past the current end of the implied array cause the array to be
+ * extended. The file pointer can be read by the
+ * {@code getFilePointer} method and set by the {@code seek}
+ * method.
+ * <p>
+ * It is generally true of all the reading routines in this class that
+ * if end-of-file is reached before the desired number of bytes has been
+ * read, an {@code EOFException} (which is a kind of
+ * {@code IOException}) is thrown. If any byte cannot be read for
+ * any reason other than end-of-file, an {@code IOException} other
+ * than {@code EOFException} is thrown. In particular, an
+ * {@code IOException} may be thrown if the stream has been closed.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+
+public class RandomAccessFile implements DataOutput, DataInput, Closeable {
+
+    // BEGIN Android-added: CloseGuard and some helper fields for Android changes in this file.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+    private final byte[] scratch = new byte[8];
+
+    private static final int FLUSH_NONE = 0;
+    private static final int FLUSH_FSYNC = 1;
+    private static final int FLUSH_FDATASYNC = 2;
+    private int flushAfterWrite = FLUSH_NONE;
+
+    private int mode;
+    // END Android-added: CloseGuard and some helper fields for Android changes in this file.
+
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private FileDescriptor fd;
+    private FileChannel channel = null;
+    private boolean rw;
+
+    /**
+     * The path of the referenced file
+     * (null if the stream is created with a file descriptor)
+     */
+    private final String path;
+
+    private Object closeLock = new Object();
+    private volatile boolean closed = false;
+
+    // BEGIN Android-added: IoTracker.
+    /**
+     * A single tracker to track both read and write. The tracker resets when the operation
+     * performed is different from the operation last performed.
+     */
+    private final IoTracker ioTracker = new IoTracker();
+    // END Android-added: IoTracker.
+
+    /**
+     * Creates a random access file stream to read from, and optionally
+     * to write to, a file with the specified name. A new
+     * {@link FileDescriptor} object is created to represent the
+     * connection to the file.
+     *
+     * <p> The <tt>mode</tt> argument specifies the access mode with which the
+     * file is to be opened.  The permitted values and their meanings are as
+     * specified for the <a
+     * href="#mode"><tt>RandomAccessFile(File,String)</tt></a> constructor.
+     *
+     * <p>
+     * If there is a security manager, its {@code checkRead} method
+     * is called with the {@code name} argument
+     * as its argument to see if read access to the file is allowed.
+     * If the mode allows writing, the security manager's
+     * {@code checkWrite} method
+     * is also called with the {@code name} argument
+     * as its argument to see if write access to the file is allowed.
+     *
+     * @param      name   the system-dependent filename
+     * @param      mode   the access <a href="#mode">mode</a>
+     * @exception  IllegalArgumentException  if the mode argument is not equal
+     *               to one of <tt>"r"</tt>, <tt>"rw"</tt>, <tt>"rws"</tt>, or
+     *               <tt>"rwd"</tt>
+     * @exception FileNotFoundException
+     *            if the mode is <tt>"r"</tt> but the given string does not
+     *            denote an existing regular file, or if the mode begins with
+     *            <tt>"rw"</tt> but the given string does not denote an
+     *            existing, writable regular file and a new regular file of
+     *            that name cannot be created, or if some other error occurs
+     *            while opening or creating the file
+     * @exception  SecurityException         if a security manager exists and its
+     *               {@code checkRead} method denies read access to the file
+     *               or the mode is "rw" and the security manager's
+     *               {@code checkWrite} method denies write access to the file
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
+     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public RandomAccessFile(String name, String mode)
+        throws FileNotFoundException
+    {
+        this(name != null ? new File(name) : null, mode);
+    }
+
+    /**
+     * Creates a random access file stream to read from, and optionally to
+     * write to, the file specified by the {@link File} argument.  A new {@link
+     * FileDescriptor} object is created to represent this file connection.
+     *
+     * <p>The <a name="mode"><tt>mode</tt></a> argument specifies the access mode
+     * in which the file is to be opened.  The permitted values and their
+     * meanings are:
+     *
+     * <table summary="Access mode permitted values and meanings">
+     * <tr><th align="left">Value</th><th align="left">Meaning</th></tr>
+     * <tr><td valign="top"><tt>"r"</tt></td>
+     *     <td> Open for reading only.  Invoking any of the <tt>write</tt>
+     *     methods of the resulting object will cause an {@link
+     *     java.io.IOException} to be thrown. </td></tr>
+     * <tr><td valign="top"><tt>"rw"</tt></td>
+     *     <td> Open for reading and writing.  If the file does not already
+     *     exist then an attempt will be made to create it. </td></tr>
+     * <tr><td valign="top"><tt>"rws"</tt></td>
+     *     <td> Open for reading and writing, as with <tt>"rw"</tt>, and also
+     *     require that every update to the file's content or metadata be
+     *     written synchronously to the underlying storage device.  </td></tr>
+     * <tr><td valign="top"><tt>"rwd"&nbsp;&nbsp;</tt></td>
+     *     <td> Open for reading and writing, as with <tt>"rw"</tt>, and also
+     *     require that every update to the file's content be written
+     *     synchronously to the underlying storage device. </td></tr>
+     * </table>
+     *
+     * The <tt>"rws"</tt> and <tt>"rwd"</tt> modes work much like the {@link
+     * java.nio.channels.FileChannel#force(boolean) force(boolean)} method of
+     * the {@link java.nio.channels.FileChannel} class, passing arguments of
+     * <tt>true</tt> and <tt>false</tt>, respectively, except that they always
+     * apply to every I/O operation and are therefore often more efficient.  If
+     * the file resides on a local storage device then when an invocation of a
+     * method of this class returns it is guaranteed that all changes made to
+     * the file by that invocation will have been written to that device.  This
+     * is useful for ensuring that critical information is not lost in the
+     * event of a system crash.  If the file does not reside on a local device
+     * then no such guarantee is made.
+     *
+     * <p>The <tt>"rwd"</tt> mode can be used to reduce the number of I/O
+     * operations performed.  Using <tt>"rwd"</tt> only requires updates to the
+     * file's content to be written to storage; using <tt>"rws"</tt> requires
+     * updates to both the file's content and its metadata to be written, which
+     * generally requires at least one more low-level I/O operation.
+     *
+     * <p>If there is a security manager, its {@code checkRead} method is
+     * called with the pathname of the {@code file} argument as its
+     * argument to see if read access to the file is allowed.  If the mode
+     * allows writing, the security manager's {@code checkWrite} method is
+     * also called with the path argument to see if write access to the file is
+     * allowed.
+     *
+     * @param      file   the file object
+     * @param      mode   the access mode, as described
+     *                    <a href="#mode">above</a>
+     * @exception  IllegalArgumentException  if the mode argument is not equal
+     *               to one of <tt>"r"</tt>, <tt>"rw"</tt>, <tt>"rws"</tt>, or
+     *               <tt>"rwd"</tt>
+     * @exception FileNotFoundException
+     *            if the mode is <tt>"r"</tt> but the given file object does
+     *            not denote an existing regular file, or if the mode begins
+     *            with <tt>"rw"</tt> but the given file object does not denote
+     *            an existing, writable regular file and a new regular file of
+     *            that name cannot be created, or if some other error occurs
+     *            while opening or creating the file
+     * @exception  SecurityException         if a security manager exists and its
+     *               {@code checkRead} method denies read access to the file
+     *               or the mode is "rw" and the security manager's
+     *               {@code checkWrite} method denies write access to the file
+     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
+     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
+     * @see        java.nio.channels.FileChannel#force(boolean)
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public RandomAccessFile(File file, String mode)
+        throws FileNotFoundException
+    {
+        String name = (file != null ? file.getPath() : null);
+        int imode = -1;
+        if (mode.equals("r")) {
+            imode = O_RDONLY;
+        } else if (mode.startsWith("rw")) {
+            // Android-changed: Added. O_CREAT
+            // imode = O_RDWR;
+            imode = O_RDWR | O_CREAT;
+            rw = true;
+            if (mode.length() > 2) {
+                if (mode.equals("rws")) {
+                    // Android-changed: For performance reasons, use fsync after each write.
+                    // RandomAccessFile.write may result in multiple write syscalls,
+                    // O_SYNC/O_DSYNC flags will cause a blocking wait on each syscall. Replacing
+                    // them with single fsync/fdatasync call gives better performance with only
+                    // minor decrease in reliability.
+                    // imode |= O_SYNC;
+                    flushAfterWrite = FLUSH_FSYNC;
+                } else if (mode.equals("rwd")) {
+                    // Android-changed: For performance reasons, use fdatasync after each write.
+                    // imode |= O_DSYNC;
+                    flushAfterWrite = FLUSH_FDATASYNC;
+                } else {
+                    imode = -1;
+                }
+            }
+        }
+        if (imode < 0) {
+            throw new IllegalArgumentException("Illegal mode \"" + mode
+                                               + "\" must be one of "
+                                               + "\"r\", \"rw\", \"rws\","
+                                               + " or \"rwd\"");
+        }
+        // Android-removed: do not use legacy security code
+        /*
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkRead(name);
+            if (rw) {
+                security.checkWrite(name);
+            }
+        }
+        */
+        if (name == null) {
+            // Android-changed: different exception message in ctor when file == null.
+            // throw new NullPointerException();
+            throw new NullPointerException("file == null");
+        }
+        if (file.isInvalid()) {
+            throw new FileNotFoundException("Invalid file path");
+        }
+        this.path = name;
+        this.mode = imode;
+
+        // BEGIN Android-changed: Use IoBridge.open() instead of open.
+        fd = IoBridge.open(name, imode);
+        IoUtils.setFdOwner(fd, this);
+        maybeSync();
+        guard.open("close");
+        // END Android-changed: Use IoBridge.open() instead of open.
+    }
+
+    // BEGIN Android-added: Sync after rws/rwd write
+    private void maybeSync() {
+        if (flushAfterWrite == FLUSH_FSYNC) {
+            try {
+                fd.sync();
+            } catch (IOException e) {
+                // Ignored
+            }
+        } else if (flushAfterWrite == FLUSH_FDATASYNC) {
+            try {
+                Os.fdatasync(fd);
+            } catch (ErrnoException e) {
+                // Ignored
+            }
+        }
+    }
+    // END Android-added: Sync after rws/rwd write
+
+    /**
+     * Returns the opaque file descriptor object associated with this
+     * stream.
+     *
+     * @return     the file descriptor object associated with this stream.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.FileDescriptor
+     */
+    public final FileDescriptor getFD() throws IOException {
+        if (fd != null) {
+            return fd;
+        }
+        throw new IOException();
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file.
+     *
+     * <p> The {@link java.nio.channels.FileChannel#position()
+     * position} of the returned channel will always be equal to
+     * this object's file-pointer offset as returned by the {@link
+     * #getFilePointer getFilePointer} method.  Changing this object's
+     * file-pointer offset, whether explicitly or by reading or writing bytes,
+     * will change the position of the channel, and vice versa.  Changing the
+     * file's length via this object will change the length seen via the file
+     * channel, and vice versa.
+     *
+     * @return  the file channel associated with this file
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public final FileChannel getChannel() {
+        synchronized (this) {
+            if (channel == null) {
+                channel = FileChannelImpl.open(fd, path, true, rw, this);
+            }
+            return channel;
+        }
+    }
+
+    /**
+     * Reads a byte of data from this file. The byte is returned as an
+     * integer in the range 0 to 255 ({@code 0x00-0x0ff}). This
+     * method blocks if no input is yet available.
+     * <p>
+     * Although {@code RandomAccessFile} is not a subclass of
+     * {@code InputStream}, this method behaves in exactly the same
+     * way as the {@link InputStream#read()} method of
+     * {@code InputStream}.
+     *
+     * @return     the next byte of data, or {@code -1} if the end of the
+     *             file has been reached.
+     * @exception  IOException  if an I/O error occurs. Not thrown if
+     *                          end-of-file has been reached.
+     */
+    public int read() throws IOException {
+        // Android-changed: Implement on top of libcore os API.
+        // return read0();
+        return (read(scratch, 0, 1) != -1) ? scratch[0] & 0xff : -1;
+    }
+
+    /**
+     * Reads a sub array as a sequence of bytes.
+     * @param b the buffer into which the data is read.
+     * @param off the start offset of the data.
+     * @param len the number of bytes to read.
+     * @exception IOException If an I/O error has occurred.
+     */
+    private int readBytes(byte b[], int off, int len) throws IOException {
+        // Android-changed: Implement on top of libcore os API.
+        ioTracker.trackIo(len, IoTracker.Mode.READ);
+        return IoBridge.read(fd, b, off, len);
+    }
+
+    /**
+     * Reads up to {@code len} bytes of data from this file into an
+     * array of bytes. This method blocks until at least one byte of input
+     * is available.
+     * <p>
+     * Although {@code RandomAccessFile} is not a subclass of
+     * {@code InputStream}, this method behaves in exactly the
+     * same way as the {@link InputStream#read(byte[], int, int)} method of
+     * {@code InputStream}.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in array {@code b}
+     *                   at which the data is written.
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             {@code -1} if there is no more data because the end of
+     *             the file has been reached.
+     * @exception  IOException If the first byte cannot be read for any reason
+     * other than end of file, or if the random access file has been closed, or if
+     * some other I/O error occurs.
+     * @exception  NullPointerException If {@code b} is {@code null}.
+     * @exception  IndexOutOfBoundsException If {@code off} is negative,
+     * {@code len} is negative, or {@code len} is greater than
+     * {@code b.length - off}
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        return readBytes(b, off, len);
+    }
+
+    /**
+     * Reads up to {@code b.length} bytes of data from this file
+     * into an array of bytes. This method blocks until at least one byte
+     * of input is available.
+     * <p>
+     * Although {@code RandomAccessFile} is not a subclass of
+     * {@code InputStream}, this method behaves in exactly the
+     * same way as the {@link InputStream#read(byte[])} method of
+     * {@code InputStream}.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @return     the total number of bytes read into the buffer, or
+     *             {@code -1} if there is no more data because the end of
+     *             this file has been reached.
+     * @exception  IOException If the first byte cannot be read for any reason
+     * other than end of file, or if the random access file has been closed, or if
+     * some other I/O error occurs.
+     * @exception  NullPointerException If {@code b} is {@code null}.
+     */
+    public int read(byte b[]) throws IOException {
+        return readBytes(b, 0, b.length);
+    }
+
+    /**
+     * Reads {@code b.length} bytes from this file into the byte
+     * array, starting at the current file pointer. This method reads
+     * repeatedly from the file until the requested number of bytes are
+     * read. This method blocks until the requested number of bytes are
+     * read, the end of the stream is detected, or an exception is thrown.
+     *
+     * @param      b   the buffer into which the data is read.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final void readFully(byte b[]) throws IOException {
+        readFully(b, 0, b.length);
+    }
+
+    /**
+     * Reads exactly {@code len} bytes from this file into the byte
+     * array, starting at the current file pointer. This method reads
+     * repeatedly from the file until the requested number of bytes are
+     * read. This method blocks until the requested number of bytes are
+     * read, the end of the stream is detected, or an exception is thrown.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset of the data.
+     * @param      len   the number of bytes to read.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               all the bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final void readFully(byte b[], int off, int len) throws IOException {
+        int n = 0;
+        do {
+            int count = this.read(b, off + n, len - n);
+            if (count < 0)
+                throw new EOFException();
+            n += count;
+        } while (n < len);
+    }
+
+    /**
+     * Attempts to skip over {@code n} bytes of input discarding the
+     * skipped bytes.
+     * <p>
+     *
+     * This method may skip over some smaller number of bytes, possibly zero.
+     * This may result from any of a number of conditions; reaching end of
+     * file before {@code n} bytes have been skipped is only one
+     * possibility. This method never throws an {@code EOFException}.
+     * The actual number of bytes skipped is returned.  If {@code n}
+     * is negative, no bytes are skipped.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int skipBytes(int n) throws IOException {
+        long pos;
+        long len;
+        long newpos;
+
+        if (n <= 0) {
+            return 0;
+        }
+        pos = getFilePointer();
+        len = length();
+        newpos = pos + n;
+        if (newpos > len) {
+            newpos = len;
+        }
+        seek(newpos);
+
+        /* return the actual number of bytes skipped */
+        return (int) (newpos - pos);
+    }
+
+    // 'Write' primitives
+
+    /**
+     * Writes the specified byte to this file. The write starts at
+     * the current file pointer.
+     *
+     * @param      b   the {@code byte} to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(int b) throws IOException {
+        // BEGIN Android-changed: Implement on top of libcore os API.
+        // write0(b);
+        scratch[0] = (byte) (b & 0xff);
+        write(scratch, 0, 1);
+        // END Android-changed: Implement on top of libcore os API.
+    }
+
+    /**
+     * Writes a sub array as a sequence of bytes.
+     * @param b the data to be written
+
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     */
+    private void writeBytes(byte b[], int off, int len) throws IOException {
+        // BEGIN Android-changed: Implement on top of libcore os API.
+        ioTracker.trackIo(len, IoTracker.Mode.WRITE);
+        IoBridge.write(fd, b, off, len);
+        maybeSync();
+        // END Android-changed: Implement on top of libcore os API.
+    }
+
+    /**
+     * Writes {@code b.length} bytes from the specified byte array
+     * to this file, starting at the current file pointer.
+     *
+     * @param      b   the data.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(byte b[]) throws IOException {
+        writeBytes(b, 0, b.length);
+    }
+
+    /**
+     * Writes {@code len} bytes from the specified byte array
+     * starting at offset {@code off} to this file.
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        writeBytes(b, off, len);
+    }
+
+    // 'Random access' stuff
+
+    /**
+     * Returns the current offset in this file.
+     *
+     * @return     the offset from the beginning of the file, in bytes,
+     *             at which the next read or write occurs.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public long getFilePointer() throws IOException {
+        // BEGIN Android-changed: Implement on top of libcore os API.
+        try {
+            return Libcore.os.lseek(fd, 0L, SEEK_CUR);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsIOException();
+        }
+        // END Android-changed: Implement on top of libcore os API.
+    }
+
+    /**
+     * Sets the file-pointer offset, measured from the beginning of this
+     * file, at which the next read or write occurs.  The offset may be
+     * set beyond the end of the file. Setting the offset beyond the end
+     * of the file does not change the file length.  The file length will
+     * change only by writing after the offset has been set beyond the end
+     * of the file.
+     *
+     * @param      pos   the offset position, measured in bytes from the
+     *                   beginning of the file, at which to set the file
+     *                   pointer.
+     * @exception  IOException  if {@code pos} is less than
+     *                          {@code 0} or if an I/O error occurs.
+     */
+    public void seek(long pos) throws IOException {
+        if (pos < 0) {
+            // Android-changed: different exception message for seek(-1).
+            // throw new IOException("Negative seek offset");
+            throw new IOException("offset < 0: " + pos);
+        } else {
+            // BEGIN Android-changed: Implement on top of libcore os API.
+            // seek0(pos);
+            try {
+                Libcore.os.lseek(fd, pos, SEEK_SET);
+                ioTracker.reset();
+            } catch (ErrnoException errnoException) {
+                throw errnoException.rethrowAsIOException();
+            }
+            // END Android-changed: Implement on top of libcore os API.
+        }
+    }
+
+    /**
+     * Returns the length of this file.
+     *
+     * @return     the length of this file, measured in bytes.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public long length() throws IOException {
+        // BEGIN Android-changed: Implement on top of libcore os API.
+        try {
+            return Libcore.os.fstat(fd).st_size;
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsIOException();
+        }
+        // END Android-changed: Implement on top of libcore os API.
+    }
+
+    /**
+     * Sets the length of this file.
+     *
+     * <p> If the present length of the file as returned by the
+     * {@code length} method is greater than the {@code newLength}
+     * argument then the file will be truncated.  In this case, if the file
+     * offset as returned by the {@code getFilePointer} method is greater
+     * than {@code newLength} then after this method returns the offset
+     * will be equal to {@code newLength}.
+     *
+     * <p> If the present length of the file as returned by the
+     * {@code length} method is smaller than the {@code newLength}
+     * argument then the file will be extended.  In this case, the contents of
+     * the extended portion of the file are not defined.
+     *
+     * @param      newLength    The desired length of the file
+     * @exception  IOException  If an I/O error occurs
+     * @since      1.2
+     */
+    public void setLength(long newLength) throws IOException {
+        // BEGIN Android-changed: Implement on top of libcore os API.
+        if (newLength < 0) {
+            throw new IllegalArgumentException("newLength < 0");
+        }
+        try {
+            Libcore.os.ftruncate(fd, newLength);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsIOException();
+        }
+
+        long filePointer = getFilePointer();
+        if (filePointer > newLength) {
+            seek(newLength);
+        }
+        maybeSync();
+        // END Android-changed: Implement on top of libcore os API.
+    }
+
+
+    /**
+     * Closes this random access file stream and releases any system
+     * resources associated with the stream. A closed random access
+     * file cannot perform input or output operations and cannot be
+     * reopened.
+     *
+     * <p> If this file has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() throws IOException {
+        guard.close();
+        synchronized (closeLock) {
+            if (closed) {
+                return;
+            }
+            closed = true;
+        }
+
+        // BEGIN Android-changed: Implement on top of libcore os API.
+        if (channel != null && channel.isOpen()) {
+            channel.close();
+        }
+        IoBridge.closeAndSignalBlockedThreads(fd);
+        // END Android-changed: Implement on top of libcore os API.
+    }
+
+    //
+    //  Some "reading/writing Java data types" methods stolen from
+    //  DataInputStream and DataOutputStream.
+    //
+
+    /**
+     * Reads a {@code boolean} from this file. This method reads a
+     * single byte from the file, starting at the current file pointer.
+     * A value of {@code 0} represents
+     * {@code false}. Any other value represents {@code true}.
+     * This method blocks until the byte is read, the end of the stream
+     * is detected, or an exception is thrown.
+     *
+     * @return     the {@code boolean} value read.
+     * @exception  EOFException  if this file has reached the end.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final boolean readBoolean() throws IOException {
+        int ch = this.read();
+        if (ch < 0)
+            throw new EOFException();
+        return (ch != 0);
+    }
+
+    /**
+     * Reads a signed eight-bit value from this file. This method reads a
+     * byte from the file, starting from the current file pointer.
+     * If the byte read is {@code b}, where
+     * <code>0&nbsp;&lt;=&nbsp;b&nbsp;&lt;=&nbsp;255</code>,
+     * then the result is:
+     * <blockquote><pre>
+     *     (byte)(b)
+     * </pre></blockquote>
+     * <p>
+     * This method blocks until the byte is read, the end of the stream
+     * is detected, or an exception is thrown.
+     *
+     * @return     the next byte of this file as a signed eight-bit
+     *             {@code byte}.
+     * @exception  EOFException  if this file has reached the end.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final byte readByte() throws IOException {
+        int ch = this.read();
+        if (ch < 0)
+            throw new EOFException();
+        return (byte)(ch);
+    }
+
+    /**
+     * Reads an unsigned eight-bit number from this file. This method reads
+     * a byte from this file, starting at the current file pointer,
+     * and returns that byte.
+     * <p>
+     * This method blocks until the byte is read, the end of the stream
+     * is detected, or an exception is thrown.
+     *
+     * @return     the next byte of this file, interpreted as an unsigned
+     *             eight-bit number.
+     * @exception  EOFException  if this file has reached the end.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final int readUnsignedByte() throws IOException {
+        int ch = this.read();
+        if (ch < 0)
+            throw new EOFException();
+        return ch;
+    }
+
+    /**
+     * Reads a signed 16-bit number from this file. The method reads two
+     * bytes from this file, starting at the current file pointer.
+     * If the two bytes read, in order, are
+     * {@code b1} and {@code b2}, where each of the two values is
+     * between {@code 0} and {@code 255}, inclusive, then the
+     * result is equal to:
+     * <blockquote><pre>
+     *     (short)((b1 &lt;&lt; 8) | b2)
+     * </pre></blockquote>
+     * <p>
+     * This method blocks until the two bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next two bytes of this file, interpreted as a signed
+     *             16-bit number.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               two bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final short readShort() throws IOException {
+        int ch1 = this.read();
+        int ch2 = this.read();
+        if ((ch1 | ch2) < 0)
+            throw new EOFException();
+        return (short)((ch1 << 8) + (ch2 << 0));
+    }
+
+    /**
+     * Reads an unsigned 16-bit number from this file. This method reads
+     * two bytes from the file, starting at the current file pointer.
+     * If the bytes read, in order, are
+     * {@code b1} and {@code b2}, where
+     * <code>0&nbsp;&lt;=&nbsp;b1, b2&nbsp;&lt;=&nbsp;255</code>,
+     * then the result is equal to:
+     * <blockquote><pre>
+     *     (b1 &lt;&lt; 8) | b2
+     * </pre></blockquote>
+     * <p>
+     * This method blocks until the two bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next two bytes of this file, interpreted as an unsigned
+     *             16-bit integer.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               two bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final int readUnsignedShort() throws IOException {
+        int ch1 = this.read();
+        int ch2 = this.read();
+        if ((ch1 | ch2) < 0)
+            throw new EOFException();
+        return (ch1 << 8) + (ch2 << 0);
+    }
+
+    /**
+     * Reads a character from this file. This method reads two
+     * bytes from the file, starting at the current file pointer.
+     * If the bytes read, in order, are
+     * {@code b1} and {@code b2}, where
+     * <code>0&nbsp;&lt;=&nbsp;b1,&nbsp;b2&nbsp;&lt;=&nbsp;255</code>,
+     * then the result is equal to:
+     * <blockquote><pre>
+     *     (char)((b1 &lt;&lt; 8) | b2)
+     * </pre></blockquote>
+     * <p>
+     * This method blocks until the two bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next two bytes of this file, interpreted as a
+     *                  {@code char}.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               two bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final char readChar() throws IOException {
+        int ch1 = this.read();
+        int ch2 = this.read();
+        if ((ch1 | ch2) < 0)
+            throw new EOFException();
+        return (char)((ch1 << 8) + (ch2 << 0));
+    }
+
+    /**
+     * Reads a signed 32-bit integer from this file. This method reads 4
+     * bytes from the file, starting at the current file pointer.
+     * If the bytes read, in order, are {@code b1},
+     * {@code b2}, {@code b3}, and {@code b4}, where
+     * <code>0&nbsp;&lt;=&nbsp;b1, b2, b3, b4&nbsp;&lt;=&nbsp;255</code>,
+     * then the result is equal to:
+     * <blockquote><pre>
+     *     (b1 &lt;&lt; 24) | (b2 &lt;&lt; 16) + (b3 &lt;&lt; 8) + b4
+     * </pre></blockquote>
+     * <p>
+     * This method blocks until the four bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next four bytes of this file, interpreted as an
+     *             {@code int}.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               four bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final int readInt() throws IOException {
+        int ch1 = this.read();
+        int ch2 = this.read();
+        int ch3 = this.read();
+        int ch4 = this.read();
+        if ((ch1 | ch2 | ch3 | ch4) < 0)
+            throw new EOFException();
+        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
+    }
+
+    /**
+     * Reads a signed 64-bit integer from this file. This method reads eight
+     * bytes from the file, starting at the current file pointer.
+     * If the bytes read, in order, are
+     * {@code b1}, {@code b2}, {@code b3},
+     * {@code b4}, {@code b5}, {@code b6},
+     * {@code b7}, and {@code b8,} where:
+     * <blockquote><pre>
+     *     0 &lt;= b1, b2, b3, b4, b5, b6, b7, b8 &lt;=255,
+     * </pre></blockquote>
+     * <p>
+     * then the result is equal to:
+     * <blockquote><pre>
+     *     ((long)b1 &lt;&lt; 56) + ((long)b2 &lt;&lt; 48)
+     *     + ((long)b3 &lt;&lt; 40) + ((long)b4 &lt;&lt; 32)
+     *     + ((long)b5 &lt;&lt; 24) + ((long)b6 &lt;&lt; 16)
+     *     + ((long)b7 &lt;&lt; 8) + b8
+     * </pre></blockquote>
+     * <p>
+     * This method blocks until the eight bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next eight bytes of this file, interpreted as a
+     *             {@code long}.
+     * @exception  EOFException  if this file reaches the end before reading
+     *               eight bytes.
+     * @exception  IOException   if an I/O error occurs.
+     */
+    public final long readLong() throws IOException {
+        return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
+    }
+
+    /**
+     * Reads a {@code float} from this file. This method reads an
+     * {@code int} value, starting at the current file pointer,
+     * as if by the {@code readInt} method
+     * and then converts that {@code int} to a {@code float}
+     * using the {@code intBitsToFloat} method in class
+     * {@code Float}.
+     * <p>
+     * This method blocks until the four bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next four bytes of this file, interpreted as a
+     *             {@code float}.
+     * @exception  EOFException  if this file reaches the end before reading
+     *             four bytes.
+     * @exception  IOException   if an I/O error occurs.
+     * @see        java.io.RandomAccessFile#readInt()
+     * @see        java.lang.Float#intBitsToFloat(int)
+     */
+    public final float readFloat() throws IOException {
+        return Float.intBitsToFloat(readInt());
+    }
+
+    /**
+     * Reads a {@code double} from this file. This method reads a
+     * {@code long} value, starting at the current file pointer,
+     * as if by the {@code readLong} method
+     * and then converts that {@code long} to a {@code double}
+     * using the {@code longBitsToDouble} method in
+     * class {@code Double}.
+     * <p>
+     * This method blocks until the eight bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     the next eight bytes of this file, interpreted as a
+     *             {@code double}.
+     * @exception  EOFException  if this file reaches the end before reading
+     *             eight bytes.
+     * @exception  IOException   if an I/O error occurs.
+     * @see        java.io.RandomAccessFile#readLong()
+     * @see        java.lang.Double#longBitsToDouble(long)
+     */
+    public final double readDouble() throws IOException {
+        return Double.longBitsToDouble(readLong());
+    }
+
+    /**
+     * Reads the next line of text from this file.  This method successively
+     * reads bytes from the file, starting at the current file pointer,
+     * until it reaches a line terminator or the end
+     * of the file.  Each byte is converted into a character by taking the
+     * byte's value for the lower eight bits of the character and setting the
+     * high eight bits of the character to zero.  This method does not,
+     * therefore, support the full Unicode character set.
+     *
+     * <p> A line of text is terminated by a carriage-return character
+     * ({@code '\u005Cr'}), a newline character ({@code '\u005Cn'}), a
+     * carriage-return character immediately followed by a newline character,
+     * or the end of the file.  Line-terminating characters are discarded and
+     * are not included as part of the string returned.
+     *
+     * <p> This method blocks until a newline character is read, a carriage
+     * return and the byte following it are read (to see if it is a newline),
+     * the end of the file is reached, or an exception is thrown.
+     *
+     * @return     the next line of text from this file, or null if end
+     *             of file is encountered before even one byte is read.
+     * @exception  IOException  if an I/O error occurs.
+     */
+
+    public final String readLine() throws IOException {
+        StringBuffer input = new StringBuffer();
+        int c = -1;
+        boolean eol = false;
+
+        while (!eol) {
+            switch (c = read()) {
+            case -1:
+            case '\n':
+                eol = true;
+                break;
+            case '\r':
+                eol = true;
+                long cur = getFilePointer();
+                if ((read()) != '\n') {
+                    seek(cur);
+                }
+                break;
+            default:
+                input.append((char)c);
+                break;
+            }
+        }
+
+        if ((c == -1) && (input.length() == 0)) {
+            return null;
+        }
+        return input.toString();
+    }
+
+    /**
+     * Reads in a string from this file. The string has been encoded
+     * using a
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * format.
+     * <p>
+     * The first two bytes are read, starting from the current file
+     * pointer, as if by
+     * {@code readUnsignedShort}. This value gives the number of
+     * following bytes that are in the encoded string, not
+     * the length of the resulting string. The following bytes are then
+     * interpreted as bytes encoding characters in the modified UTF-8 format
+     * and are converted into characters.
+     * <p>
+     * This method blocks until all the bytes are read, the end of the
+     * stream is detected, or an exception is thrown.
+     *
+     * @return     a Unicode string.
+     * @exception  EOFException            if this file reaches the end before
+     *               reading all the bytes.
+     * @exception  IOException             if an I/O error occurs.
+     * @exception  UTFDataFormatException  if the bytes do not represent
+     *               valid modified UTF-8 encoding of a Unicode string.
+     * @see        java.io.RandomAccessFile#readUnsignedShort()
+     */
+    public final String readUTF() throws IOException {
+        return DataInputStream.readUTF(this);
+    }
+
+    /**
+     * Writes a {@code boolean} to the file as a one-byte value. The
+     * value {@code true} is written out as the value
+     * {@code (byte)1}; the value {@code false} is written out
+     * as the value {@code (byte)0}. The write starts at
+     * the current position of the file pointer.
+     *
+     * @param      v   a {@code boolean} value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeBoolean(boolean v) throws IOException {
+        write(v ? 1 : 0);
+        //written++;
+    }
+
+    /**
+     * Writes a {@code byte} to the file as a one-byte value. The
+     * write starts at the current position of the file pointer.
+     *
+     * @param      v   a {@code byte} value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeByte(int v) throws IOException {
+        write(v);
+        //written++;
+    }
+
+    /**
+     * Writes a {@code short} to the file as two bytes, high byte first.
+     * The write starts at the current position of the file pointer.
+     *
+     * @param      v   a {@code short} to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeShort(int v) throws IOException {
+        write((v >>> 8) & 0xFF);
+        write((v >>> 0) & 0xFF);
+        //written += 2;
+    }
+
+    /**
+     * Writes a {@code char} to the file as a two-byte value, high
+     * byte first. The write starts at the current position of the
+     * file pointer.
+     *
+     * @param      v   a {@code char} value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeChar(int v) throws IOException {
+        write((v >>> 8) & 0xFF);
+        write((v >>> 0) & 0xFF);
+        //written += 2;
+    }
+
+    /**
+     * Writes an {@code int} to the file as four bytes, high byte first.
+     * The write starts at the current position of the file pointer.
+     *
+     * @param      v   an {@code int} to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeInt(int v) throws IOException {
+        write((v >>> 24) & 0xFF);
+        write((v >>> 16) & 0xFF);
+        write((v >>>  8) & 0xFF);
+        write((v >>>  0) & 0xFF);
+        //written += 4;
+    }
+
+    /**
+     * Writes a {@code long} to the file as eight bytes, high byte first.
+     * The write starts at the current position of the file pointer.
+     *
+     * @param      v   a {@code long} to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeLong(long v) throws IOException {
+        write((int)(v >>> 56) & 0xFF);
+        write((int)(v >>> 48) & 0xFF);
+        write((int)(v >>> 40) & 0xFF);
+        write((int)(v >>> 32) & 0xFF);
+        write((int)(v >>> 24) & 0xFF);
+        write((int)(v >>> 16) & 0xFF);
+        write((int)(v >>>  8) & 0xFF);
+        write((int)(v >>>  0) & 0xFF);
+        //written += 8;
+    }
+
+    /**
+     * Converts the float argument to an {@code int} using the
+     * {@code floatToIntBits} method in class {@code Float},
+     * and then writes that {@code int} value to the file as a
+     * four-byte quantity, high byte first. The write starts at the
+     * current position of the file pointer.
+     *
+     * @param      v   a {@code float} value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.lang.Float#floatToIntBits(float)
+     */
+    public final void writeFloat(float v) throws IOException {
+        writeInt(Float.floatToIntBits(v));
+    }
+
+    /**
+     * Converts the double argument to a {@code long} using the
+     * {@code doubleToLongBits} method in class {@code Double},
+     * and then writes that {@code long} value to the file as an
+     * eight-byte quantity, high byte first. The write starts at the current
+     * position of the file pointer.
+     *
+     * @param      v   a {@code double} value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.lang.Double#doubleToLongBits(double)
+     */
+    public final void writeDouble(double v) throws IOException {
+        writeLong(Double.doubleToLongBits(v));
+    }
+
+    /**
+     * Writes the string to the file as a sequence of bytes. Each
+     * character in the string is written out, in sequence, by discarding
+     * its high eight bits. The write starts at the current position of
+     * the file pointer.
+     *
+     * @param      s   a string of bytes to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    @SuppressWarnings("deprecation")
+    public final void writeBytes(String s) throws IOException {
+        int len = s.length();
+        byte[] b = new byte[len];
+        s.getBytes(0, len, b, 0);
+        writeBytes(b, 0, len);
+    }
+
+    /**
+     * Writes a string to the file as a sequence of characters. Each
+     * character is written to the data output stream as if by the
+     * {@code writeChar} method. The write starts at the current
+     * position of the file pointer.
+     *
+     * @param      s   a {@code String} value to be written.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.RandomAccessFile#writeChar(int)
+     */
+    public final void writeChars(String s) throws IOException {
+        int clen = s.length();
+        int blen = 2*clen;
+        byte[] b = new byte[blen];
+        char[] c = new char[clen];
+        s.getChars(0, clen, c, 0);
+        for (int i = 0, j = 0; i < clen; i++) {
+            b[j++] = (byte)(c[i] >>> 8);
+            b[j++] = (byte)(c[i] >>> 0);
+        }
+        writeBytes(b, 0, blen);
+    }
+
+    /**
+     * Writes a string to the file using
+     * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+     * encoding in a machine-independent manner.
+     * <p>
+     * First, two bytes are written to the file, starting at the
+     * current file pointer, as if by the
+     * {@code writeShort} method giving the number of bytes to
+     * follow. This value is the number of bytes actually written out,
+     * not the length of the string. Following the length, each character
+     * of the string is output, in sequence, using the modified UTF-8 encoding
+     * for each character.
+     *
+     * @param      str   a string to be written.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public final void writeUTF(String str) throws IOException {
+        DataOutputStream.writeUTF(str, this);
+    }
+
+    // Android-added: use finalize() to detect if not close()d.
+    @Override protected void finalize() throws Throwable {
+        try {
+            if (guard != null) {
+                guard.warnIfOpen();
+            }
+            close();
+        } finally {
+            super.finalize();
+        }
+    }
+}
diff --git a/java/io/Reader.java b/java/io/Reader.java
new file mode 100644
index 0000000..1c9cca6
--- /dev/null
+++ b/java/io/Reader.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for reading character streams.  The only methods that a
+ * subclass must implement are read(char[], int, int) and close().  Most
+ * subclasses, however, will override some of the methods defined here in order
+ * to provide higher efficiency, additional functionality, or both.
+ *
+ *
+ * @see BufferedReader
+ * @see   LineNumberReader
+ * @see CharArrayReader
+ * @see InputStreamReader
+ * @see   FileReader
+ * @see FilterReader
+ * @see   PushbackReader
+ * @see PipedReader
+ * @see StringReader
+ * @see Writer
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public abstract class Reader implements Readable, Closeable {
+
+    /**
+     * The object used to synchronize operations on this stream.  For
+     * efficiency, a character-stream object may use an object other than
+     * itself to protect critical sections.  A subclass should therefore use
+     * the object in this field rather than <tt>this</tt> or a synchronized
+     * method.
+     */
+    protected Object lock;
+
+    /**
+     * Creates a new character-stream reader whose critical sections will
+     * synchronize on the reader itself.
+     */
+    protected Reader() {
+        this.lock = this;
+    }
+
+    /**
+     * Creates a new character-stream reader whose critical sections will
+     * synchronize on the given object.
+     *
+     * @param lock  The Object to synchronize on.
+     */
+    protected Reader(Object lock) {
+        if (lock == null) {
+            throw new NullPointerException();
+        }
+        this.lock = lock;
+    }
+
+    /**
+     * Attempts to read characters into the specified character buffer.
+     * The buffer is used as a repository of characters as-is: the only
+     * changes made are the results of a put operation. No flipping or
+     * rewinding of the buffer is performed.
+     *
+     * @param target the buffer to read characters into
+     * @return The number of characters added to the buffer, or
+     *         -1 if this source of characters is at its end
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if target is null
+     * @throws java.nio.ReadOnlyBufferException if target is a read only buffer
+     * @since 1.5
+     */
+    public int read(java.nio.CharBuffer target) throws IOException {
+        int len = target.remaining();
+        char[] cbuf = new char[len];
+        int n = read(cbuf, 0, len);
+        if (n > 0)
+            target.put(cbuf, 0, n);
+        return n;
+    }
+
+    /**
+     * Reads a single character.  This method will block until a character is
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * <p> Subclasses that intend to support efficient single-character input
+     * should override this method.
+     *
+     * @return     The character read, as an integer in the range 0 to 65535
+     *             (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has
+     *             been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        char cb[] = new char[1];
+        if (read(cb, 0, 1) == -1)
+            return -1;
+        else
+            return cb[0];
+    }
+
+    /**
+     * Reads characters into an array.  This method will block until some input
+     * is available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param       cbuf  Destination buffer
+     *
+     * @return      The number of characters read, or -1
+     *              if the end of the stream
+     *              has been reached
+     *
+     * @exception   IOException  If an I/O error occurs
+     */
+    public int read(char cbuf[]) throws IOException {
+        return read(cbuf, 0, cbuf.length);
+    }
+
+    /**
+     * Reads characters into a portion of an array.  This method will block
+     * until some input is available, an I/O error occurs, or the end of the
+     * stream is reached.
+     *
+     * @param      cbuf  Destination buffer
+     * @param      off   Offset at which to start storing characters
+     * @param      len   Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    abstract public int read(char cbuf[], int off, int len) throws IOException;
+
+    /** Maximum skip-buffer size */
+    private static final int maxSkipBufferSize = 8192;
+
+    /** Skip buffer, null until allocated */
+    private char skipBuffer[] = null;
+
+    /**
+     * Skips characters.  This method will block until some characters are
+     * available, an I/O error occurs, or the end of the stream is reached.
+     *
+     * @param  n  The number of characters to skip
+     *
+     * @return    The number of characters actually skipped
+     *
+     * @exception  IllegalArgumentException  If <code>n</code> is negative.
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0L)
+            throw new IllegalArgumentException("skip value is negative");
+        int nn = (int) Math.min(n, maxSkipBufferSize);
+        synchronized (lock) {
+            if ((skipBuffer == null) || (skipBuffer.length < nn))
+                skipBuffer = new char[nn];
+            long r = n;
+            while (r > 0) {
+                int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
+                if (nc == -1)
+                    break;
+                r -= nc;
+            }
+            return n - r;
+        }
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.
+     *
+     * @return True if the next read() is guaranteed not to block for input,
+     * false otherwise.  Note that returning false does not guarantee that the
+     * next read will block.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public boolean ready() throws IOException {
+        return false;
+    }
+
+    /**
+     * Tells whether this stream supports the mark() operation. The default
+     * implementation always returns false. Subclasses should override this
+     * method.
+     *
+     * @return true if and only if this stream supports the mark operation.
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Marks the present position in the stream.  Subsequent calls to reset()
+     * will attempt to reposition the stream to this point.  Not all
+     * character-input streams support the mark() operation.
+     *
+     * @param  readAheadLimit  Limit on the number of characters that may be
+     *                         read while still preserving the mark.  After
+     *                         reading this many characters, attempting to
+     *                         reset the stream may fail.
+     *
+     * @exception  IOException  If the stream does not support mark(),
+     *                          or if some other I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        throw new IOException("mark() not supported");
+    }
+
+    /**
+     * Resets the stream.  If the stream has been marked, then attempt to
+     * reposition it at the mark.  If the stream has not been marked, then
+     * attempt to reset it in some way appropriate to the particular stream,
+     * for example by repositioning it to its starting point.  Not all
+     * character-input streams support the reset() operation, and some support
+     * reset() without supporting mark().
+     *
+     * @exception  IOException  If the stream has not been marked,
+     *                          or if the mark has been invalidated,
+     *                          or if the stream does not support reset(),
+     *                          or if some other I/O error occurs
+     */
+    public void reset() throws IOException {
+        throw new IOException("reset() not supported");
+    }
+
+    /**
+     * Closes the stream and releases any system resources associated with
+     * it.  Once the stream has been closed, further read(), ready(),
+     * mark(), reset(), or skip() invocations will throw an IOException.
+     * Closing a previously closed stream has no effect.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+     abstract public void close() throws IOException;
+
+}
diff --git a/java/io/SequenceInputStream.java b/java/io/SequenceInputStream.java
new file mode 100644
index 0000000..01da7f6
--- /dev/null
+++ b/java/io/SequenceInputStream.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * A <code>SequenceInputStream</code> represents
+ * the logical concatenation of other input
+ * streams. It starts out with an ordered
+ * collection of input streams and reads from
+ * the first one until end of file is reached,
+ * whereupon it reads from the second one,
+ * and so on, until end of file is reached
+ * on the last of the contained input streams.
+ *
+ * @author  Author van Hoff
+ * @since   JDK1.0
+ */
+public
+class SequenceInputStream extends InputStream {
+    Enumeration<? extends InputStream> e;
+    InputStream in;
+
+    /**
+     * Initializes a newly created <code>SequenceInputStream</code>
+     * by remembering the argument, which must
+     * be an <code>Enumeration</code>  that produces
+     * objects whose run-time type is <code>InputStream</code>.
+     * The input streams that are  produced by
+     * the enumeration will be read, in order,
+     * to provide the bytes to be read  from this
+     * <code>SequenceInputStream</code>. After
+     * each input stream from the enumeration
+     * is exhausted, it is closed by calling its
+     * <code>close</code> method.
+     *
+     * @param   e   an enumeration of input streams.
+     * @see     java.util.Enumeration
+     */
+    public SequenceInputStream(Enumeration<? extends InputStream> e) {
+        this.e = e;
+        try {
+            nextStream();
+        } catch (IOException ex) {
+            // This should never happen
+            throw new Error("panic");
+        }
+    }
+
+    /**
+     * Initializes a newly
+     * created <code>SequenceInputStream</code>
+     * by remembering the two arguments, which
+     * will be read in order, first <code>s1</code>
+     * and then <code>s2</code>, to provide the
+     * bytes to be read from this <code>SequenceInputStream</code>.
+     *
+     * @param   s1   the first input stream to read.
+     * @param   s2   the second input stream to read.
+     */
+    public SequenceInputStream(InputStream s1, InputStream s2) {
+        Vector<InputStream> v = new Vector<>(2);
+
+        v.addElement(s1);
+        v.addElement(s2);
+        e = v.elements();
+        try {
+            nextStream();
+        } catch (IOException ex) {
+            // This should never happen
+            throw new Error("panic");
+        }
+    }
+
+    /**
+     *  Continues reading in the next stream if an EOF is reached.
+     */
+    final void nextStream() throws IOException {
+        if (in != null) {
+            in.close();
+        }
+
+        if (e.hasMoreElements()) {
+            in = (InputStream) e.nextElement();
+            if (in == null)
+                throw new NullPointerException();
+        }
+        else in = null;
+
+    }
+
+    /**
+     * Returns an estimate of the number of bytes that can be read (or
+     * skipped over) from the current underlying input stream without
+     * blocking by the next invocation of a method for the current
+     * underlying input stream. The next invocation might be
+     * the same thread or another thread.  A single read or skip of this
+     * many bytes will not block, but may read or skip fewer bytes.
+     * <p>
+     * This method simply calls {@code available} of the current underlying
+     * input stream and returns the result.
+     *
+     * @return an estimate of the number of bytes that can be read (or
+     *         skipped over) from the current underlying input stream
+     *         without blocking or {@code 0} if this input stream
+     *         has been closed by invoking its {@link #close()} method
+     * @exception  IOException  if an I/O error occurs.
+     *
+     * @since   JDK1.1
+     */
+    public int available() throws IOException {
+        if (in == null) {
+            return 0; // no way to signal EOF from available()
+        }
+        return in.available();
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The byte is
+     * returned as an <code>int</code> in the range <code>0</code> to
+     * <code>255</code>. If no byte is available because the end of the
+     * stream has been reached, the value <code>-1</code> is returned.
+     * This method blocks until input data is available, the end of the
+     * stream is detected, or an exception is thrown.
+     * <p>
+     * This method
+     * tries to read one character from the current substream. If it
+     * reaches the end of the stream, it calls the <code>close</code>
+     * method of the current substream and begins reading from the next
+     * substream.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int read() throws IOException {
+        while (in != null) {
+            int c = in.read();
+            if (c != -1) {
+                return c;
+            }
+            nextStream();
+        }
+        return -1;
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this input stream
+     * into an array of bytes.  If <code>len</code> is not zero, the method
+     * blocks until at least 1 byte of input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * <p>
+     * The <code>read</code> method of <code>SequenceInputStream</code>
+     * tries to read the data from the current substream. If it fails to
+     * read any characters because the substream has reached the end of
+     * the stream, it calls the <code>close</code> method of the current
+     * substream and begins reading from the next substream.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset in array <code>b</code>
+     *                   at which the data is written.
+     * @param      len   the maximum number of bytes read.
+     * @return     int   the number of bytes read.
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public int read(byte b[], int off, int len) throws IOException {
+        if (in == null) {
+            return -1;
+        } else if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+        do {
+            int n = in.read(b, off, len);
+            if (n > 0) {
+                return n;
+            }
+            nextStream();
+        } while (in != null);
+        return -1;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources
+     * associated with the stream.
+     * A closed <code>SequenceInputStream</code>
+     * cannot  perform input operations and cannot
+     * be reopened.
+     * <p>
+     * If this stream was created
+     * from an enumeration, all remaining elements
+     * are requested from the enumeration and closed
+     * before the <code>close</code> method returns.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     */
+    public void close() throws IOException {
+        do {
+            nextStream();
+        } while (in != null);
+    }
+}
diff --git a/java/io/SerialCallbackContext.java b/java/io/SerialCallbackContext.java
new file mode 100644
index 0000000..4009087
--- /dev/null
+++ b/java/io/SerialCallbackContext.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Context during upcalls from object stream to class-defined
+ * readObject/writeObject methods.
+ * Holds object currently being deserialized and descriptor for current class.
+ *
+ * This context keeps track of the thread it was constructed on, and allows
+ * only a single call of defaultReadObject, readFields, defaultWriteObject
+ * or writeFields which must be invoked on the same thread before the class's
+ * readObject/writeObject method has returned.
+ * If not set to the current thread, the getObj method throws NotActiveException.
+ */
+final class SerialCallbackContext {
+    private final Object obj;
+    private final ObjectStreamClass desc;
+    /**
+     * Thread this context is in use by.
+     * As this only works in one thread, we do not need to worry about thread-safety.
+     */
+    private Thread thread;
+
+    public SerialCallbackContext(Object obj, ObjectStreamClass desc) {
+        this.obj = obj;
+        this.desc = desc;
+        this.thread = Thread.currentThread();
+    }
+
+    public Object getObj() throws NotActiveException {
+        checkAndSetUsed();
+        return obj;
+    }
+
+    public ObjectStreamClass getDesc() {
+        return desc;
+    }
+
+    public void check() throws NotActiveException {
+        if (thread != null && thread != Thread.currentThread()) {
+            throw new NotActiveException(
+                "expected thread: " + thread + ", but got: " + Thread.currentThread());
+        }
+    }
+
+    private void checkAndSetUsed() throws NotActiveException {
+        if (thread != Thread.currentThread()) {
+             throw new NotActiveException(
+              "not in readObject invocation or fields already read");
+        }
+        thread = null;
+    }
+
+    public void setUsed() {
+        thread = null;
+    }
+}
diff --git a/java/io/Serializable.java b/java/io/Serializable.java
new file mode 100644
index 0000000..496aef7
--- /dev/null
+++ b/java/io/Serializable.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+// Android-added: Notes about serialVersionUID, using serialization judiciously, JSON.
+/**
+ * Serializability of a class is enabled by the class implementing the
+ * java.io.Serializable interface. Classes that do not implement this
+ * interface will not have any of their state serialized or
+ * deserialized.  All subtypes of a serializable class are themselves
+ * serializable.  The serialization interface has no methods or fields
+ * and serves only to identify the semantics of being serializable. <p>
+ *
+ * To allow subtypes of non-serializable classes to be serialized, the
+ * subtype may assume responsibility for saving and restoring the
+ * state of the supertype's public, protected, and (if accessible)
+ * package fields.  The subtype may assume this responsibility only if
+ * the class it extends has an accessible no-arg constructor to
+ * initialize the class's state.  It is an error to declare a class
+ * Serializable if this is not the case.  The error will be detected at
+ * runtime. <p>
+ *
+ * During deserialization, the fields of non-serializable classes will
+ * be initialized using the public or protected no-arg constructor of
+ * the class.  A no-arg constructor must be accessible to the subclass
+ * that is serializable.  The fields of serializable subclasses will
+ * be restored from the stream. <p>
+ *
+ * When traversing a graph, an object may be encountered that does not
+ * support the Serializable interface. In this case the
+ * NotSerializableException will be thrown and will identify the class
+ * of the non-serializable object. <p>
+ *
+ * Classes that require special handling during the serialization and
+ * deserialization process must implement special methods with these exact
+ * signatures:
+ *
+ * <PRE>
+ * private void writeObject(java.io.ObjectOutputStream out)
+ *     throws IOException
+ * private void readObject(java.io.ObjectInputStream in)
+ *     throws IOException, ClassNotFoundException;
+ * private void readObjectNoData()
+ *     throws ObjectStreamException;
+ * </PRE>
+ *
+ * <p>The writeObject method is responsible for writing the state of the
+ * object for its particular class so that the corresponding
+ * readObject method can restore it.  The default mechanism for saving
+ * the Object's fields can be invoked by calling
+ * out.defaultWriteObject. The method does not need to concern
+ * itself with the state belonging to its superclasses or subclasses.
+ * State is saved by writing the individual fields to the
+ * ObjectOutputStream using the writeObject method or by using the
+ * methods for primitive data types supported by DataOutput.
+ *
+ * <p>The readObject method is responsible for reading from the stream and
+ * restoring the classes fields. It may call in.defaultReadObject to invoke
+ * the default mechanism for restoring the object's non-static and
+ * non-transient fields.  The defaultReadObject method uses information in
+ * the stream to assign the fields of the object saved in the stream with the
+ * correspondingly named fields in the current object.  This handles the case
+ * when the class has evolved to add new fields. The method does not need to
+ * concern itself with the state belonging to its superclasses or subclasses.
+ * State is saved by writing the individual fields to the
+ * ObjectOutputStream using the writeObject method or by using the
+ * methods for primitive data types supported by DataOutput.
+ *
+ * <p>The readObjectNoData method is responsible for initializing the state of
+ * the object for its particular class in the event that the serialization
+ * stream does not list the given class as a superclass of the object being
+ * deserialized.  This may occur in cases where the receiving party uses a
+ * different version of the deserialized instance's class than the sending
+ * party, and the receiver's version extends classes that are not extended by
+ * the sender's version.  This may also occur if the serialization stream has
+ * been tampered; hence, readObjectNoData is useful for initializing
+ * deserialized objects properly despite a "hostile" or incomplete source
+ * stream.
+ *
+ * <p>Serializable classes that need to designate an alternative object to be
+ * used when writing an object to the stream should implement this
+ * special method with the exact signature:
+ *
+ * <PRE>
+ * ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
+ * </PRE><p>
+ *
+ * This writeReplace method is invoked by serialization if the method
+ * exists and it would be accessible from a method defined within the
+ * class of the object being serialized. Thus, the method can have private,
+ * protected and package-private access. Subclass access to this method
+ * follows java accessibility rules. <p>
+ *
+ * Classes that need to designate a replacement when an instance of it
+ * is read from the stream should implement this special method with the
+ * exact signature.
+ *
+ * <PRE>
+ * ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
+ * </PRE><p>
+ *
+ * This readResolve method follows the same invocation rules and
+ * accessibility rules as writeReplace.<p>
+ *
+ * The serialization runtime associates with each serializable class a version
+ * number, called a serialVersionUID, which is used during deserialization to
+ * verify that the sender and receiver of a serialized object have loaded
+ * classes for that object that are compatible with respect to serialization.
+ * If the receiver has loaded a class for the object that has a different
+ * serialVersionUID than that of the corresponding sender's class, then
+ * deserialization will result in an {@link InvalidClassException}.  A
+ * serializable class can declare its own serialVersionUID explicitly by
+ * declaring a field named <code>"serialVersionUID"</code> that must be static,
+ * final, and of type <code>long</code>:
+ *
+ * <PRE>
+ * ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
+ * </PRE>
+ *
+ * If a serializable class does not explicitly declare a serialVersionUID, then
+ * the serialization runtime will calculate a default serialVersionUID value
+ * for that class based on various aspects of the class, as described in the
+ * Java(TM) Object Serialization Specification.  However, it is <em>strongly
+ * recommended</em> that all serializable classes explicitly declare
+ * serialVersionUID values, since the default serialVersionUID computation is
+ * highly sensitive to class details that may vary depending on compiler
+ * implementations, and can thus result in unexpected
+ * <code>InvalidClassException</code>s during deserialization.  Therefore, to
+ * guarantee a consistent serialVersionUID value across different java compiler
+ * implementations, a serializable class must declare an explicit
+ * serialVersionUID value.  It is also strongly advised that explicit
+ * serialVersionUID declarations use the <code>private</code> modifier where
+ * possible, since such declarations apply only to the immediately declaring
+ * class--serialVersionUID fields are not useful as inherited members. Array
+ * classes cannot declare an explicit serialVersionUID, so they always have
+ * the default computed value, but the requirement for matching
+ * serialVersionUID values is waived for array classes.
+ *
+ * Android implementation of serialVersionUID computation will change slightly
+ * for some classes if you're targeting android N. In order to preserve compatibility,
+ * this change is only enabled is the application target SDK version is set to
+ * 24 or higher. It is highly recommended to use an explicit serialVersionUID
+ * field to avoid compatibility issues.
+ *
+ * <h3>Implement Serializable Judiciously</h3>
+ * Refer to <i>Effective Java</i>'s chapter on serialization for thorough
+ * coverage of the serialization API. The book explains how to use this
+ * interface without harming your application's maintainability.
+ *
+ * <h3>Recommended Alternatives</h3>
+ * <strong>JSON</strong> is concise, human-readable and efficient. Android
+ * includes both a {@link android.util.JsonReader streaming API} and a {@link
+ * org.json.JSONObject tree API} to read and write JSON. Use a binding library
+ * like <a href="http://code.google.com/p/google-gson/">GSON</a> to read and
+ * write Java objects directly.
+ *
+ * @author  unascribed
+ * @see java.io.ObjectOutputStream
+ * @see java.io.ObjectInputStream
+ * @see java.io.ObjectOutput
+ * @see java.io.ObjectInput
+ * @see java.io.Externalizable
+ * @since   JDK1.1
+ */
+public interface Serializable {
+}
diff --git a/java/io/SerializablePermission.java b/java/io/SerializablePermission.java
new file mode 100644
index 0000000..93bb4aa
--- /dev/null
+++ b/java/io/SerializablePermission.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.security.*;
+
+// Android-changed: Replaced with empty implementation and documented as legacy security code.
+/**
+ * This legacy security is not supported on Android. Do not use.
+ */
+public final class SerializablePermission extends BasicPermission {
+
+    public SerializablePermission(String name)
+    {
+        super("");
+    }
+
+    public SerializablePermission(String name, String actions)
+    {
+        super("", "");
+    }
+}
diff --git a/java/io/StreamCorruptedException.java b/java/io/StreamCorruptedException.java
new file mode 100644
index 0000000..57af82c
--- /dev/null
+++ b/java/io/StreamCorruptedException.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Thrown when control information that was read from an object stream
+ * violates internal consistency checks.
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class StreamCorruptedException extends ObjectStreamException {
+
+    private static final long serialVersionUID = 8983558202217591746L;
+
+    /**
+     * Create a StreamCorruptedException and list a reason why thrown.
+     *
+     * @param reason  String describing the reason for the exception.
+     */
+    public StreamCorruptedException(String reason) {
+        super(reason);
+    }
+
+    /**
+     * Create a StreamCorruptedException and list no reason why thrown.
+     */
+    public StreamCorruptedException() {
+        super();
+    }
+}
diff --git a/java/io/StreamTokenizer.java b/java/io/StreamTokenizer.java
new file mode 100644
index 0000000..3c7c7cc
--- /dev/null
+++ b/java/io/StreamTokenizer.java
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.util.Arrays;
+
+/**
+ * The {@code StreamTokenizer} class takes an input stream and
+ * parses it into "tokens", allowing the tokens to be
+ * read one at a time. The parsing process is controlled by a table
+ * and a number of flags that can be set to various states. The
+ * stream tokenizer can recognize identifiers, numbers, quoted
+ * strings, and various comment styles.
+ * <p>
+ * Each byte read from the input stream is regarded as a character
+ * in the range {@code '\u005Cu0000'} through {@code '\u005Cu00FF'}.
+ * The character value is used to look up five possible attributes of
+ * the character: <i>white space</i>, <i>alphabetic</i>,
+ * <i>numeric</i>, <i>string quote</i>, and <i>comment character</i>.
+ * Each character can have zero or more of these attributes.
+ * <p>
+ * In addition, an instance has four flags. These flags indicate:
+ * <ul>
+ * <li>Whether line terminators are to be returned as tokens or treated
+ *     as white space that merely separates tokens.
+ * <li>Whether C-style comments are to be recognized and skipped.
+ * <li>Whether C++-style comments are to be recognized and skipped.
+ * <li>Whether the characters of identifiers are converted to lowercase.
+ * </ul>
+ * <p>
+ * A typical application first constructs an instance of this class,
+ * sets up the syntax tables, and then repeatedly loops calling the
+ * {@code nextToken} method in each iteration of the loop until
+ * it returns the value {@code TT_EOF}.
+ *
+ * @author  James Gosling
+ * @see     java.io.StreamTokenizer#nextToken()
+ * @see     java.io.StreamTokenizer#TT_EOF
+ * @since   JDK1.0
+ */
+
+public class StreamTokenizer {
+
+    /* Only one of these will be non-null */
+    private Reader reader = null;
+    private InputStream input = null;
+
+    private char buf[] = new char[20];
+
+    /**
+     * The next character to be considered by the nextToken method.  May also
+     * be NEED_CHAR to indicate that a new character should be read, or SKIP_LF
+     * to indicate that a new character should be read and, if it is a '\n'
+     * character, it should be discarded and a second new character should be
+     * read.
+     */
+    private int peekc = NEED_CHAR;
+
+    private static final int NEED_CHAR = Integer.MAX_VALUE;
+    private static final int SKIP_LF = Integer.MAX_VALUE - 1;
+
+    private boolean pushedBack;
+    private boolean forceLower;
+    /** The line number of the last token read */
+    private int LINENO = 1;
+
+    private boolean eolIsSignificantP = false;
+    private boolean slashSlashCommentsP = false;
+    private boolean slashStarCommentsP = false;
+
+    private byte ctype[] = new byte[256];
+    private static final byte CT_WHITESPACE = 1;
+    private static final byte CT_DIGIT = 2;
+    private static final byte CT_ALPHA = 4;
+    private static final byte CT_QUOTE = 8;
+    private static final byte CT_COMMENT = 16;
+
+    /**
+     * After a call to the {@code nextToken} method, this field
+     * contains the type of the token just read. For a single character
+     * token, its value is the single character, converted to an integer.
+     * For a quoted string token, its value is the quote character.
+     * Otherwise, its value is one of the following:
+     * <ul>
+     * <li>{@code TT_WORD} indicates that the token is a word.
+     * <li>{@code TT_NUMBER} indicates that the token is a number.
+     * <li>{@code TT_EOL} indicates that the end of line has been read.
+     *     The field can only have this value if the
+     *     {@code eolIsSignificant} method has been called with the
+     *     argument {@code true}.
+     * <li>{@code TT_EOF} indicates that the end of the input stream
+     *     has been reached.
+     * </ul>
+     * <p>
+     * The initial value of this field is -4.
+     *
+     * @see     java.io.StreamTokenizer#eolIsSignificant(boolean)
+     * @see     java.io.StreamTokenizer#nextToken()
+     * @see     java.io.StreamTokenizer#quoteChar(int)
+     * @see     java.io.StreamTokenizer#TT_EOF
+     * @see     java.io.StreamTokenizer#TT_EOL
+     * @see     java.io.StreamTokenizer#TT_NUMBER
+     * @see     java.io.StreamTokenizer#TT_WORD
+     */
+    public int ttype = TT_NOTHING;
+
+    /**
+     * A constant indicating that the end of the stream has been read.
+     */
+    public static final int TT_EOF = -1;
+
+    /**
+     * A constant indicating that the end of the line has been read.
+     */
+    public static final int TT_EOL = '\n';
+
+    /**
+     * A constant indicating that a number token has been read.
+     */
+    public static final int TT_NUMBER = -2;
+
+    /**
+     * A constant indicating that a word token has been read.
+     */
+    public static final int TT_WORD = -3;
+
+    /* A constant indicating that no token has been read, used for
+     * initializing ttype.  FIXME This could be made public and
+     * made available as the part of the API in a future release.
+     */
+    private static final int TT_NOTHING = -4;
+
+    /**
+     * If the current token is a word token, this field contains a
+     * string giving the characters of the word token. When the current
+     * token is a quoted string token, this field contains the body of
+     * the string.
+     * <p>
+     * The current token is a word when the value of the
+     * {@code ttype} field is {@code TT_WORD}. The current token is
+     * a quoted string token when the value of the {@code ttype} field is
+     * a quote character.
+     * <p>
+     * The initial value of this field is null.
+     *
+     * @see     java.io.StreamTokenizer#quoteChar(int)
+     * @see     java.io.StreamTokenizer#TT_WORD
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public String sval;
+
+    /**
+     * If the current token is a number, this field contains the value
+     * of that number. The current token is a number when the value of
+     * the {@code ttype} field is {@code TT_NUMBER}.
+     * <p>
+     * The initial value of this field is 0.0.
+     *
+     * @see     java.io.StreamTokenizer#TT_NUMBER
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public double nval;
+
+    /** Private constructor that initializes everything except the streams. */
+    private StreamTokenizer() {
+        wordChars('a', 'z');
+        wordChars('A', 'Z');
+        wordChars(128 + 32, 255);
+        whitespaceChars(0, ' ');
+        commentChar('/');
+        quoteChar('"');
+        quoteChar('\'');
+        parseNumbers();
+    }
+
+    /**
+     * Creates a stream tokenizer that parses the specified input
+     * stream. The stream tokenizer is initialized to the following
+     * default state:
+     * <ul>
+     * <li>All byte values {@code 'A'} through {@code 'Z'},
+     *     {@code 'a'} through {@code 'z'}, and
+     *     {@code '\u005Cu00A0'} through {@code '\u005Cu00FF'} are
+     *     considered to be alphabetic.
+     * <li>All byte values {@code '\u005Cu0000'} through
+     *     {@code '\u005Cu0020'} are considered to be white space.
+     * <li>{@code '/'} is a comment character.
+     * <li>Single quote {@code '\u005C''} and double quote {@code '"'}
+     *     are string quote characters.
+     * <li>Numbers are parsed.
+     * <li>Ends of lines are treated as white space, not as separate tokens.
+     * <li>C-style and C++-style comments are not recognized.
+     * </ul>
+     *
+     * @deprecated As of JDK version 1.1, the preferred way to tokenize an
+     * input stream is to convert it into a character stream, for example:
+     * <blockquote><pre>
+     *   Reader r = new BufferedReader(new InputStreamReader(is));
+     *   StreamTokenizer st = new StreamTokenizer(r);
+     * </pre></blockquote>
+     *
+     * @param      is        an input stream.
+     * @see        java.io.BufferedReader
+     * @see        java.io.InputStreamReader
+     * @see        java.io.StreamTokenizer#StreamTokenizer(java.io.Reader)
+     */
+    @Deprecated
+    public StreamTokenizer(InputStream is) {
+        this();
+        if (is == null) {
+            throw new NullPointerException();
+        }
+        input = is;
+    }
+
+    /**
+     * Create a tokenizer that parses the given character stream.
+     *
+     * @param r  a Reader object providing the input stream.
+     * @since   JDK1.1
+     */
+    public StreamTokenizer(Reader r) {
+        this();
+        if (r == null) {
+            throw new NullPointerException();
+        }
+        reader = r;
+    }
+
+    /**
+     * Resets this tokenizer's syntax table so that all characters are
+     * "ordinary." See the {@code ordinaryChar} method
+     * for more information on a character being ordinary.
+     *
+     * @see     java.io.StreamTokenizer#ordinaryChar(int)
+     */
+    public void resetSyntax() {
+        for (int i = ctype.length; --i >= 0;)
+            ctype[i] = 0;
+    }
+
+    /**
+     * Specifies that all characters <i>c</i> in the range
+     * <code>low&nbsp;&lt;=&nbsp;<i>c</i>&nbsp;&lt;=&nbsp;high</code>
+     * are word constituents. A word token consists of a word constituent
+     * followed by zero or more word constituents or number constituents.
+     *
+     * @param   low   the low end of the range.
+     * @param   hi    the high end of the range.
+     */
+    public void wordChars(int low, int hi) {
+        if (low < 0)
+            low = 0;
+        if (hi >= ctype.length)
+            hi = ctype.length - 1;
+        while (low <= hi)
+            ctype[low++] |= CT_ALPHA;
+    }
+
+    /**
+     * Specifies that all characters <i>c</i> in the range
+     * <code>low&nbsp;&lt;=&nbsp;<i>c</i>&nbsp;&lt;=&nbsp;high</code>
+     * are white space characters. White space characters serve only to
+     * separate tokens in the input stream.
+     *
+     * <p>Any other attribute settings for the characters in the specified
+     * range are cleared.
+     *
+     * @param   low   the low end of the range.
+     * @param   hi    the high end of the range.
+     */
+    public void whitespaceChars(int low, int hi) {
+        if (low < 0)
+            low = 0;
+        if (hi >= ctype.length)
+            hi = ctype.length - 1;
+        while (low <= hi)
+            ctype[low++] = CT_WHITESPACE;
+    }
+
+    /**
+     * Specifies that all characters <i>c</i> in the range
+     * <code>low&nbsp;&lt;=&nbsp;<i>c</i>&nbsp;&lt;=&nbsp;high</code>
+     * are "ordinary" in this tokenizer. See the
+     * {@code ordinaryChar} method for more information on a
+     * character being ordinary.
+     *
+     * @param   low   the low end of the range.
+     * @param   hi    the high end of the range.
+     * @see     java.io.StreamTokenizer#ordinaryChar(int)
+     */
+    public void ordinaryChars(int low, int hi) {
+        if (low < 0)
+            low = 0;
+        if (hi >= ctype.length)
+            hi = ctype.length - 1;
+        while (low <= hi)
+            ctype[low++] = 0;
+    }
+
+    /**
+     * Specifies that the character argument is "ordinary"
+     * in this tokenizer. It removes any special significance the
+     * character has as a comment character, word component, string
+     * delimiter, white space, or number character. When such a character
+     * is encountered by the parser, the parser treats it as a
+     * single-character token and sets {@code ttype} field to the
+     * character value.
+     *
+     * <p>Making a line terminator character "ordinary" may interfere
+     * with the ability of a {@code StreamTokenizer} to count
+     * lines. The {@code lineno} method may no longer reflect
+     * the presence of such terminator characters in its line count.
+     *
+     * @param   ch   the character.
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public void ordinaryChar(int ch) {
+        if (ch >= 0 && ch < ctype.length)
+            ctype[ch] = 0;
+    }
+
+    /**
+     * Specified that the character argument starts a single-line
+     * comment. All characters from the comment character to the end of
+     * the line are ignored by this stream tokenizer.
+     *
+     * <p>Any other attribute settings for the specified character are cleared.
+     *
+     * @param   ch   the character.
+     */
+    public void commentChar(int ch) {
+        if (ch >= 0 && ch < ctype.length)
+            ctype[ch] = CT_COMMENT;
+    }
+
+    /**
+     * Specifies that matching pairs of this character delimit string
+     * constants in this tokenizer.
+     * <p>
+     * When the {@code nextToken} method encounters a string
+     * constant, the {@code ttype} field is set to the string
+     * delimiter and the {@code sval} field is set to the body of
+     * the string.
+     * <p>
+     * If a string quote character is encountered, then a string is
+     * recognized, consisting of all characters after (but not including)
+     * the string quote character, up to (but not including) the next
+     * occurrence of that same string quote character, or a line
+     * terminator, or end of file. The usual escape sequences such as
+     * {@code "\u005Cn"} and {@code "\u005Ct"} are recognized and
+     * converted to single characters as the string is parsed.
+     *
+     * <p>Any other attribute settings for the specified character are cleared.
+     *
+     * @param   ch   the character.
+     * @see     java.io.StreamTokenizer#nextToken()
+     * @see     java.io.StreamTokenizer#sval
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public void quoteChar(int ch) {
+        if (ch >= 0 && ch < ctype.length)
+            ctype[ch] = CT_QUOTE;
+    }
+
+    /**
+     * Specifies that numbers should be parsed by this tokenizer. The
+     * syntax table of this tokenizer is modified so that each of the twelve
+     * characters:
+     * <blockquote><pre>
+     *      0 1 2 3 4 5 6 7 8 9 . -
+     * </pre></blockquote>
+     * <p>
+     * has the "numeric" attribute.
+     * <p>
+     * When the parser encounters a word token that has the format of a
+     * double precision floating-point number, it treats the token as a
+     * number rather than a word, by setting the {@code ttype}
+     * field to the value {@code TT_NUMBER} and putting the numeric
+     * value of the token into the {@code nval} field.
+     *
+     * @see     java.io.StreamTokenizer#nval
+     * @see     java.io.StreamTokenizer#TT_NUMBER
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public void parseNumbers() {
+        for (int i = '0'; i <= '9'; i++)
+            ctype[i] |= CT_DIGIT;
+        ctype['.'] |= CT_DIGIT;
+        ctype['-'] |= CT_DIGIT;
+    }
+
+    /**
+     * Determines whether or not ends of line are treated as tokens.
+     * If the flag argument is true, this tokenizer treats end of lines
+     * as tokens; the {@code nextToken} method returns
+     * {@code TT_EOL} and also sets the {@code ttype} field to
+     * this value when an end of line is read.
+     * <p>
+     * A line is a sequence of characters ending with either a
+     * carriage-return character ({@code '\u005Cr'}) or a newline
+     * character ({@code '\u005Cn'}). In addition, a carriage-return
+     * character followed immediately by a newline character is treated
+     * as a single end-of-line token.
+     * <p>
+     * If the {@code flag} is false, end-of-line characters are
+     * treated as white space and serve only to separate tokens.
+     *
+     * @param   flag   {@code true} indicates that end-of-line characters
+     *                 are separate tokens; {@code false} indicates that
+     *                 end-of-line characters are white space.
+     * @see     java.io.StreamTokenizer#nextToken()
+     * @see     java.io.StreamTokenizer#ttype
+     * @see     java.io.StreamTokenizer#TT_EOL
+     */
+    public void eolIsSignificant(boolean flag) {
+        eolIsSignificantP = flag;
+    }
+
+    /**
+     * Determines whether or not the tokenizer recognizes C-style comments.
+     * If the flag argument is {@code true}, this stream tokenizer
+     * recognizes C-style comments. All text between successive
+     * occurrences of {@code /*} and <code>*&#47;</code> are discarded.
+     * <p>
+     * If the flag argument is {@code false}, then C-style comments
+     * are not treated specially.
+     *
+     * @param   flag   {@code true} indicates to recognize and ignore
+     *                 C-style comments.
+     */
+    public void slashStarComments(boolean flag) {
+        slashStarCommentsP = flag;
+    }
+
+    /**
+     * Determines whether or not the tokenizer recognizes C++-style comments.
+     * If the flag argument is {@code true}, this stream tokenizer
+     * recognizes C++-style comments. Any occurrence of two consecutive
+     * slash characters ({@code '/'}) is treated as the beginning of
+     * a comment that extends to the end of the line.
+     * <p>
+     * If the flag argument is {@code false}, then C++-style
+     * comments are not treated specially.
+     *
+     * @param   flag   {@code true} indicates to recognize and ignore
+     *                 C++-style comments.
+     */
+    public void slashSlashComments(boolean flag) {
+        slashSlashCommentsP = flag;
+    }
+
+    /**
+     * Determines whether or not word token are automatically lowercased.
+     * If the flag argument is {@code true}, then the value in the
+     * {@code sval} field is lowercased whenever a word token is
+     * returned (the {@code ttype} field has the
+     * value {@code TT_WORD} by the {@code nextToken} method
+     * of this tokenizer.
+     * <p>
+     * If the flag argument is {@code false}, then the
+     * {@code sval} field is not modified.
+     *
+     * @param   fl   {@code true} indicates that all word tokens should
+     *               be lowercased.
+     * @see     java.io.StreamTokenizer#nextToken()
+     * @see     java.io.StreamTokenizer#ttype
+     * @see     java.io.StreamTokenizer#TT_WORD
+     */
+    public void lowerCaseMode(boolean fl) {
+        forceLower = fl;
+    }
+
+    /** Read the next character */
+    private int read() throws IOException {
+        if (reader != null)
+            return reader.read();
+        else if (input != null)
+            return input.read();
+        else
+            throw new IllegalStateException();
+    }
+
+    /**
+     * Parses the next token from the input stream of this tokenizer.
+     * The type of the next token is returned in the {@code ttype}
+     * field. Additional information about the token may be in the
+     * {@code nval} field or the {@code sval} field of this
+     * tokenizer.
+     * <p>
+     * Typical clients of this
+     * class first set up the syntax tables and then sit in a loop
+     * calling nextToken to parse successive tokens until TT_EOF
+     * is returned.
+     *
+     * @return     the value of the {@code ttype} field.
+     * @exception  IOException  if an I/O error occurs.
+     * @see        java.io.StreamTokenizer#nval
+     * @see        java.io.StreamTokenizer#sval
+     * @see        java.io.StreamTokenizer#ttype
+     */
+    public int nextToken() throws IOException {
+        if (pushedBack) {
+            pushedBack = false;
+            return ttype;
+        }
+        byte ct[] = ctype;
+        sval = null;
+
+        int c = peekc;
+        if (c < 0)
+            c = NEED_CHAR;
+        if (c == SKIP_LF) {
+            c = read();
+            if (c < 0)
+                return ttype = TT_EOF;
+            if (c == '\n')
+                c = NEED_CHAR;
+        }
+        if (c == NEED_CHAR) {
+            c = read();
+            if (c < 0)
+                return ttype = TT_EOF;
+        }
+        ttype = c;              /* Just to be safe */
+
+        /* Set peekc so that the next invocation of nextToken will read
+         * another character unless peekc is reset in this invocation
+         */
+        peekc = NEED_CHAR;
+
+        int ctype = c < 256 ? ct[c] : CT_ALPHA;
+        while ((ctype & CT_WHITESPACE) != 0) {
+            if (c == '\r') {
+                LINENO++;
+                if (eolIsSignificantP) {
+                    peekc = SKIP_LF;
+                    return ttype = TT_EOL;
+                }
+                c = read();
+                if (c == '\n')
+                    c = read();
+            } else {
+                if (c == '\n') {
+                    LINENO++;
+                    if (eolIsSignificantP) {
+                        return ttype = TT_EOL;
+                    }
+                }
+                c = read();
+            }
+            if (c < 0)
+                return ttype = TT_EOF;
+            ctype = c < 256 ? ct[c] : CT_ALPHA;
+        }
+
+        if ((ctype & CT_DIGIT) != 0) {
+            boolean neg = false;
+            if (c == '-') {
+                c = read();
+                if (c != '.' && (c < '0' || c > '9')) {
+                    peekc = c;
+                    return ttype = '-';
+                }
+                neg = true;
+            }
+            double v = 0;
+            int decexp = 0;
+            int seendot = 0;
+            while (true) {
+                if (c == '.' && seendot == 0)
+                    seendot = 1;
+                else if ('0' <= c && c <= '9') {
+                    v = v * 10 + (c - '0');
+                    decexp += seendot;
+                } else
+                    break;
+                c = read();
+            }
+            peekc = c;
+            if (decexp != 0) {
+                double denom = 10;
+                decexp--;
+                while (decexp > 0) {
+                    denom *= 10;
+                    decexp--;
+                }
+                /* Do one division of a likely-to-be-more-accurate number */
+                v = v / denom;
+            }
+            nval = neg ? -v : v;
+            return ttype = TT_NUMBER;
+        }
+
+        if ((ctype & CT_ALPHA) != 0) {
+            int i = 0;
+            do {
+                if (i >= buf.length) {
+                    buf = Arrays.copyOf(buf, buf.length * 2);
+                }
+                buf[i++] = (char) c;
+                c = read();
+                ctype = c < 0 ? CT_WHITESPACE : c < 256 ? ct[c] : CT_ALPHA;
+            } while ((ctype & (CT_ALPHA | CT_DIGIT)) != 0);
+            peekc = c;
+            sval = String.copyValueOf(buf, 0, i);
+            if (forceLower)
+                sval = sval.toLowerCase();
+            return ttype = TT_WORD;
+        }
+
+        if ((ctype & CT_QUOTE) != 0) {
+            ttype = c;
+            int i = 0;
+            /* Invariants (because \Octal needs a lookahead):
+             *   (i)  c contains char value
+             *   (ii) d contains the lookahead
+             */
+            int d = read();
+            while (d >= 0 && d != ttype && d != '\n' && d != '\r') {
+                if (d == '\\') {
+                    c = read();
+                    int first = c;   /* To allow \377, but not \477 */
+                    if (c >= '0' && c <= '7') {
+                        c = c - '0';
+                        int c2 = read();
+                        if ('0' <= c2 && c2 <= '7') {
+                            c = (c << 3) + (c2 - '0');
+                            c2 = read();
+                            if ('0' <= c2 && c2 <= '7' && first <= '3') {
+                                c = (c << 3) + (c2 - '0');
+                                d = read();
+                            } else
+                                d = c2;
+                        } else
+                          d = c2;
+                    } else {
+                        switch (c) {
+                        case 'a':
+                            c = 0x7;
+                            break;
+                        case 'b':
+                            c = '\b';
+                            break;
+                        case 'f':
+                            c = 0xC;
+                            break;
+                        case 'n':
+                            c = '\n';
+                            break;
+                        case 'r':
+                            c = '\r';
+                            break;
+                        case 't':
+                            c = '\t';
+                            break;
+                        case 'v':
+                            c = 0xB;
+                            break;
+                        }
+                        d = read();
+                    }
+                } else {
+                    c = d;
+                    d = read();
+                }
+                if (i >= buf.length) {
+                    buf = Arrays.copyOf(buf, buf.length * 2);
+                }
+                buf[i++] = (char)c;
+            }
+
+            /* If we broke out of the loop because we found a matching quote
+             * character then arrange to read a new character next time
+             * around; otherwise, save the character.
+             */
+            peekc = (d == ttype) ? NEED_CHAR : d;
+
+            sval = String.copyValueOf(buf, 0, i);
+            return ttype;
+        }
+
+        if (c == '/' && (slashSlashCommentsP || slashStarCommentsP)) {
+            c = read();
+            if (c == '*' && slashStarCommentsP) {
+                int prevc = 0;
+                while ((c = read()) != '/' || prevc != '*') {
+                    if (c == '\r') {
+                        LINENO++;
+                        c = read();
+                        if (c == '\n') {
+                            c = read();
+                        }
+                    } else {
+                        if (c == '\n') {
+                            LINENO++;
+                            c = read();
+                        }
+                    }
+                    if (c < 0)
+                        return ttype = TT_EOF;
+                    prevc = c;
+                }
+                return nextToken();
+            } else if (c == '/' && slashSlashCommentsP) {
+                while ((c = read()) != '\n' && c != '\r' && c >= 0);
+                peekc = c;
+                return nextToken();
+            } else {
+                /* Now see if it is still a single line comment */
+                if ((ct['/'] & CT_COMMENT) != 0) {
+                    while ((c = read()) != '\n' && c != '\r' && c >= 0);
+                    peekc = c;
+                    return nextToken();
+                } else {
+                    peekc = c;
+                    return ttype = '/';
+                }
+            }
+        }
+
+        if ((ctype & CT_COMMENT) != 0) {
+            while ((c = read()) != '\n' && c != '\r' && c >= 0);
+            peekc = c;
+            return nextToken();
+        }
+
+        return ttype = c;
+    }
+
+    /**
+     * Causes the next call to the {@code nextToken} method of this
+     * tokenizer to return the current value in the {@code ttype}
+     * field, and not to modify the value in the {@code nval} or
+     * {@code sval} field.
+     *
+     * @see     java.io.StreamTokenizer#nextToken()
+     * @see     java.io.StreamTokenizer#nval
+     * @see     java.io.StreamTokenizer#sval
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public void pushBack() {
+        if (ttype != TT_NOTHING)   /* No-op if nextToken() not called */
+            pushedBack = true;
+    }
+
+    /**
+     * Return the current line number.
+     *
+     * @return  the current line number of this stream tokenizer.
+     */
+    public int lineno() {
+        return LINENO;
+    }
+
+    /**
+     * Returns the string representation of the current stream token and
+     * the line number it occurs on.
+     *
+     * <p>The precise string returned is unspecified, although the following
+     * example can be considered typical:
+     *
+     * <blockquote><pre>Token['a'], line 10</pre></blockquote>
+     *
+     * @return  a string representation of the token
+     * @see     java.io.StreamTokenizer#nval
+     * @see     java.io.StreamTokenizer#sval
+     * @see     java.io.StreamTokenizer#ttype
+     */
+    public String toString() {
+        String ret;
+        switch (ttype) {
+          case TT_EOF:
+            ret = "EOF";
+            break;
+          case TT_EOL:
+            ret = "EOL";
+            break;
+          case TT_WORD:
+            ret = sval;
+            break;
+          case TT_NUMBER:
+            ret = "n=" + nval;
+            break;
+          case TT_NOTHING:
+            ret = "NOTHING";
+            break;
+          default: {
+                /*
+                 * ttype is the first character of either a quoted string or
+                 * is an ordinary character. ttype can definitely not be less
+                 * than 0, since those are reserved values used in the previous
+                 * case statements
+                 */
+                if (ttype < 256 &&
+                    ((ctype[ttype] & CT_QUOTE) != 0)) {
+                    ret = sval;
+                    break;
+                }
+
+                char s[] = new char[3];
+                s[0] = s[2] = '\'';
+                s[1] = (char) ttype;
+                ret = new String(s);
+                break;
+            }
+        }
+        return "Token[" + ret + "], line " + LINENO;
+    }
+
+}
diff --git a/java/io/StringBufferInputStream.java b/java/io/StringBufferInputStream.java
new file mode 100644
index 0000000..90c5d4d
--- /dev/null
+++ b/java/io/StringBufferInputStream.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * This class allows an application to create an input stream in
+ * which the bytes read are supplied by the contents of a string.
+ * Applications can also read bytes from a byte array by using a
+ * <code>ByteArrayInputStream</code>.
+ * <p>
+ * Only the low eight bits of each character in the string are used by
+ * this class.
+ *
+ * @author     Arthur van Hoff
+ * @see        java.io.ByteArrayInputStream
+ * @see        java.io.StringReader
+ * @since      JDK1.0
+ * @deprecated This class does not properly convert characters into bytes.  As
+ *             of JDK&nbsp;1.1, the preferred way to create a stream from a
+ *             string is via the <code>StringReader</code> class.
+ */
+@Deprecated
+public
+class StringBufferInputStream extends InputStream {
+    /**
+     * The string from which bytes are read.
+     */
+    protected String buffer;
+
+    /**
+     * The index of the next character to read from the input stream buffer.
+     *
+     * @see        java.io.StringBufferInputStream#buffer
+     */
+    protected int pos;
+
+    /**
+     * The number of valid characters in the input stream buffer.
+     *
+     * @see        java.io.StringBufferInputStream#buffer
+     */
+    protected int count;
+
+    /**
+     * Creates a string input stream to read data from the specified string.
+     *
+     * @param      s   the underlying input buffer.
+     */
+    public StringBufferInputStream(String s) {
+        this.buffer = s;
+        count = s.length();
+    }
+
+    /**
+     * Reads the next byte of data from this input stream. The value
+     * byte is returned as an <code>int</code> in the range
+     * <code>0</code> to <code>255</code>. If no byte is available
+     * because the end of the stream has been reached, the value
+     * <code>-1</code> is returned.
+     * <p>
+     * The <code>read</code> method of
+     * <code>StringBufferInputStream</code> cannot block. It returns the
+     * low eight bits of the next character in this input stream's buffer.
+     *
+     * @return     the next byte of data, or <code>-1</code> if the end of the
+     *             stream is reached.
+     */
+    public synchronized int read() {
+        return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
+    }
+
+    /**
+     * Reads up to <code>len</code> bytes of data from this input stream
+     * into an array of bytes.
+     * <p>
+     * The <code>read</code> method of
+     * <code>StringBufferInputStream</code> cannot block. It copies the
+     * low eight bits from the characters in this input stream's buffer into
+     * the byte array argument.
+     *
+     * @param      b     the buffer into which the data is read.
+     * @param      off   the start offset of the data.
+     * @param      len   the maximum number of bytes read.
+     * @return     the total number of bytes read into the buffer, or
+     *             <code>-1</code> if there is no more data because the end of
+     *             the stream has been reached.
+     */
+    public synchronized int read(byte b[], int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        } else if ((off < 0) || (off > b.length) || (len < 0) ||
+                   ((off + len) > b.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (pos >= count) {
+            return -1;
+        }
+        // BEGIN Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+        int avail = count - pos;
+        if (len > avail) {
+            len = avail;
+        }
+        // END Android-changed: Backport of OpenJDK 9b132 fix to avoid integer overflow.
+        if (len <= 0) {
+            return 0;
+        }
+        String  s = buffer;
+        int cnt = len;
+        while (--cnt >= 0) {
+            b[off++] = (byte)s.charAt(pos++);
+        }
+
+        return len;
+    }
+
+    /**
+     * Skips <code>n</code> bytes of input from this input stream. Fewer
+     * bytes might be skipped if the end of the input stream is reached.
+     *
+     * @param      n   the number of bytes to be skipped.
+     * @return     the actual number of bytes skipped.
+     */
+    public synchronized long skip(long n) {
+        if (n < 0) {
+            return 0;
+        }
+        if (n > count - pos) {
+            n = count - pos;
+        }
+        pos += n;
+        return n;
+    }
+
+    /**
+     * Returns the number of bytes that can be read from the input
+     * stream without blocking.
+     *
+     * @return     the value of <code>count&nbsp;-&nbsp;pos</code>, which is the
+     *             number of bytes remaining to be read from the input buffer.
+     */
+    public synchronized int available() {
+        return count - pos;
+    }
+
+    /**
+     * Resets the input stream to begin reading from the first character
+     * of this input stream's underlying buffer.
+     */
+    public synchronized void reset() {
+        pos = 0;
+    }
+}
diff --git a/java/io/StringReader.java b/java/io/StringReader.java
new file mode 100644
index 0000000..ce9ff60
--- /dev/null
+++ b/java/io/StringReader.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A character stream whose source is a string.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class StringReader extends Reader {
+
+    private String str;
+    private int length;
+    private int next = 0;
+    private int mark = 0;
+
+    /**
+     * Creates a new string reader.
+     *
+     * @param s  String providing the character stream.
+     */
+    public StringReader(String s) {
+        this.str = s;
+        this.length = s.length();
+    }
+
+    /** Check to make sure that the stream has not been closed */
+    private void ensureOpen() throws IOException {
+        if (str == null)
+            throw new IOException("Stream closed");
+    }
+
+    /**
+     * Reads a single character.
+     *
+     * @return     The character read, or -1 if the end of the stream has been
+     *             reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (next >= length)
+                return -1;
+            return str.charAt(next++);
+        }
+    }
+
+    /**
+     * Reads characters into a portion of an array.
+     *
+     * @param      cbuf  Destination buffer
+     * @param      off   Offset at which to start writing characters
+     * @param      len   Maximum number of characters to read
+     *
+     * @return     The number of characters read, or -1 if the end of the
+     *             stream has been reached
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public int read(char cbuf[], int off, int len) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                ((off + len) > cbuf.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0) {
+                return 0;
+            }
+            if (next >= length)
+                return -1;
+            int n = Math.min(length - next, len);
+            str.getChars(next, next + n, cbuf, off);
+            next += n;
+            return n;
+        }
+    }
+
+    /**
+     * Skips the specified number of characters in the stream. Returns
+     * the number of characters that were skipped.
+     *
+     * <p>The <code>ns</code> parameter may be negative, even though the
+     * <code>skip</code> method of the {@link Reader} superclass throws
+     * an exception in this case. Negative values of <code>ns</code> cause the
+     * stream to skip backwards. Negative return values indicate a skip
+     * backwards. It is not possible to skip backwards past the beginning of
+     * the string.
+     *
+     * <p>If the entire string has been read or skipped, then this method has
+     * no effect and always returns 0.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public long skip(long ns) throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            if (next >= length)
+                return 0;
+            // Bound skip by beginning and end of the source
+            long n = Math.min(length - next, ns);
+            n = Math.max(-next, n);
+            next += n;
+            return n;
+        }
+    }
+
+    /**
+     * Tells whether this stream is ready to be read.
+     *
+     * @return True if the next read() is guaranteed not to block for input
+     *
+     * @exception  IOException  If the stream is closed
+     */
+    public boolean ready() throws IOException {
+        synchronized (lock) {
+        ensureOpen();
+        return true;
+        }
+    }
+
+    /**
+     * Tells whether this stream supports the mark() operation, which it does.
+     */
+    public boolean markSupported() {
+        return true;
+    }
+
+    /**
+     * Marks the present position in the stream.  Subsequent calls to reset()
+     * will reposition the stream to this point.
+     *
+     * @param  readAheadLimit  Limit on the number of characters that may be
+     *                         read while still preserving the mark.  Because
+     *                         the stream's input comes from a string, there
+     *                         is no actual limit, so this argument must not
+     *                         be negative, but is otherwise ignored.
+     *
+     * @exception  IllegalArgumentException  If {@code readAheadLimit < 0}
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void mark(int readAheadLimit) throws IOException {
+        if (readAheadLimit < 0){
+            throw new IllegalArgumentException("Read-ahead limit < 0");
+        }
+        synchronized (lock) {
+            ensureOpen();
+            mark = next;
+        }
+    }
+
+    /**
+     * Resets the stream to the most recent mark, or to the beginning of the
+     * string if it has never been marked.
+     *
+     * @exception  IOException  If an I/O error occurs
+     */
+    public void reset() throws IOException {
+        synchronized (lock) {
+            ensureOpen();
+            next = mark;
+        }
+    }
+
+    /**
+     * Closes the stream and releases any system resources associated with
+     * it. Once the stream has been closed, further read(),
+     * ready(), mark(), or reset() invocations will throw an IOException.
+     * Closing a previously closed stream has no effect.
+     */
+    public void close() {
+        str = null;
+    }
+}
diff --git a/java/io/StringWriter.java b/java/io/StringWriter.java
new file mode 100644
index 0000000..c4e5d40
--- /dev/null
+++ b/java/io/StringWriter.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * A character stream that collects its output in a string buffer, which can
+ * then be used to construct a string.
+ * <p>
+ * Closing a <tt>StringWriter</tt> has no effect. The methods in this class
+ * can be called after the stream has been closed without generating an
+ * <tt>IOException</tt>.
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public class StringWriter extends Writer {
+
+    private StringBuffer buf;
+
+    /**
+     * Create a new string writer using the default initial string-buffer
+     * size.
+     */
+    public StringWriter() {
+        buf = new StringBuffer();
+        lock = buf;
+    }
+
+    /**
+     * Create a new string writer using the specified initial string-buffer
+     * size.
+     *
+     * @param initialSize
+     *        The number of <tt>char</tt> values that will fit into this buffer
+     *        before it is automatically expanded
+     *
+     * @throws IllegalArgumentException
+     *         If <tt>initialSize</tt> is negative
+     */
+    public StringWriter(int initialSize) {
+        if (initialSize < 0) {
+            throw new IllegalArgumentException("Negative buffer size");
+        }
+        buf = new StringBuffer(initialSize);
+        lock = buf;
+    }
+
+    /**
+     * Write a single character.
+     */
+    public void write(int c) {
+        buf.append((char) c);
+    }
+
+    /**
+     * Write a portion of an array of characters.
+     *
+     * @param  cbuf  Array of characters
+     * @param  off   Offset from which to start writing characters
+     * @param  len   Number of characters to write
+     */
+    public void write(char cbuf[], int off, int len) {
+        if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+            ((off + len) > cbuf.length) || ((off + len) < 0)) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        buf.append(cbuf, off, len);
+    }
+
+    /**
+     * Write a string.
+     */
+    public void write(String str) {
+        buf.append(str);
+    }
+
+    /**
+     * Write a portion of a string.
+     *
+     * @param  str  String to be written
+     * @param  off  Offset from which to start writing characters
+     * @param  len  Number of characters to write
+     */
+    public void write(String str, int off, int len)  {
+        buf.append(str.substring(off, off + len));
+    }
+
+    /**
+     * Appends the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.toString()) </pre>
+     *
+     * <p> Depending on the specification of <tt>toString</tt> for the
+     * character sequence <tt>csq</tt>, the entire sequence may not be
+     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * character buffer will return a subsequence whose content depends upon
+     * the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this writer.
+     *
+     * @return  This writer
+     *
+     * @since  1.5
+     */
+    public StringWriter append(CharSequence csq) {
+        if (csq == null)
+            write("null");
+        else
+            write(csq.toString());
+        return this;
+    }
+
+    /**
+     * Appends a subsequence of the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @param  start
+     *         The index of the first character in the subsequence
+     *
+     * @param  end
+     *         The index of the character following the last character in the
+     *         subsequence
+     *
+     * @return  This writer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @since  1.5
+     */
+    public StringWriter append(CharSequence csq, int start, int end) {
+        CharSequence cs = (csq == null ? "null" : csq);
+        write(cs.subSequence(start, end).toString());
+        return this;
+    }
+
+    /**
+     * Appends the specified character to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(c) </pre>
+     *
+     * @param  c
+     *         The 16-bit character to append
+     *
+     * @return  This writer
+     *
+     * @since 1.5
+     */
+    public StringWriter append(char c) {
+        write(c);
+        return this;
+    }
+
+    /**
+     * Return the buffer's current value as a string.
+     */
+    public String toString() {
+        return buf.toString();
+    }
+
+    /**
+     * Return the string buffer itself.
+     *
+     * @return StringBuffer holding the current buffer value.
+     */
+    public StringBuffer getBuffer() {
+        return buf;
+    }
+
+    /**
+     * Flush the stream.
+     */
+    public void flush() {
+    }
+
+    /**
+     * Closing a <tt>StringWriter</tt> has no effect. The methods in this
+     * class can be called after the stream has been closed without generating
+     * an <tt>IOException</tt>.
+     */
+    public void close() throws IOException {
+    }
+
+}
diff --git a/java/io/SyncFailedException.java b/java/io/SyncFailedException.java
new file mode 100644
index 0000000..7e553a7
--- /dev/null
+++ b/java/io/SyncFailedException.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that a sync operation has failed.
+ *
+ * @author  Ken Arnold
+ * @see     java.io.FileDescriptor#sync
+ * @see     java.io.IOException
+ * @since   JDK1.1
+ */
+public class SyncFailedException extends IOException {
+    private static final long serialVersionUID = -2353342684412443330L;
+
+    /**
+     * Constructs an SyncFailedException with a detail message.
+     * A detail message is a String that describes this particular exception.
+     *
+     * @param desc  a String describing the exception.
+     */
+    public SyncFailedException(String desc) {
+        super(desc);
+    }
+}
diff --git a/java/io/UTFDataFormatException.java b/java/io/UTFDataFormatException.java
new file mode 100644
index 0000000..422d28b
--- /dev/null
+++ b/java/io/UTFDataFormatException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that a malformed string in
+ * <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
+ * format has been read in a data
+ * input stream or by any class that implements the data input
+ * interface.
+ * See the
+ * <a href="DataInput.html#modified-utf-8"><code>DataInput</code></a>
+ * class description for the format in
+ * which modified UTF-8 strings are read and written.
+ *
+ * @author  Frank Yellin
+ * @see     java.io.DataInput
+ * @see     java.io.DataInputStream#readUTF(java.io.DataInput)
+ * @see     java.io.IOException
+ * @since   JDK1.0
+ */
+public
+class UTFDataFormatException extends IOException {
+    private static final long serialVersionUID = 420743449228280612L;
+
+    /**
+     * Constructs a <code>UTFDataFormatException</code> with
+     * <code>null</code> as its error detail message.
+     */
+    public UTFDataFormatException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>UTFDataFormatException</code> with the
+     * specified detail message. The string <code>s</code> can be
+     * retrieved later by the
+     * <code>{@link java.lang.Throwable#getMessage}</code>
+     * method of class <code>java.lang.Throwable</code>.
+     *
+     * @param   s   the detail message.
+     */
+    public UTFDataFormatException(String s) {
+        super(s);
+    }
+}
diff --git a/java/io/UncheckedIOException.java b/java/io/UncheckedIOException.java
new file mode 100644
index 0000000..22c43e3
--- /dev/null
+++ b/java/io/UncheckedIOException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+import java.util.Objects;
+
+/**
+ * Wraps an {@link IOException} with an unchecked exception.
+ *
+ * @since   1.8
+ */
+public class UncheckedIOException extends RuntimeException {
+    private static final long serialVersionUID = -8134305061645241065L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   message
+     *          the detail message, can be null
+     * @param   cause
+     *          the {@code IOException}
+     *
+     * @throws  NullPointerException
+     *          if the cause is {@code null}
+     */
+    public UncheckedIOException(String message, IOException cause) {
+        super(message, Objects.requireNonNull(cause));
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   cause
+     *          the {@code IOException}
+     *
+     * @throws  NullPointerException
+     *          if the cause is {@code null}
+     */
+    public UncheckedIOException(IOException cause) {
+        super(Objects.requireNonNull(cause));
+    }
+
+    /**
+     * Returns the cause of this exception.
+     *
+     * @return  the {@code IOException} which is the cause of this exception.
+     */
+    @Override
+    public IOException getCause() {
+        return (IOException) super.getCause();
+    }
+
+    /**
+     * Called to read the object from a stream.
+     *
+     * @throws  InvalidObjectException
+     *          if the object is invalid or has a cause that is not
+     *          an {@code IOException}
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException
+    {
+        s.defaultReadObject();
+        Throwable cause = super.getCause();
+        if (!(cause instanceof IOException))
+            throw new InvalidObjectException("Cause must be an IOException");
+    }
+}
diff --git a/java/io/UnixFileSystem.java b/java/io/UnixFileSystem.java
new file mode 100644
index 0000000..e2aad21
--- /dev/null
+++ b/java/io/UnixFileSystem.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+import java.security.AccessController;
+
+import android.system.ErrnoException;
+import android.system.OsConstants;
+
+import dalvik.system.BlockGuard;
+
+import libcore.io.Libcore;
+
+import sun.security.action.GetPropertyAction;
+
+
+class UnixFileSystem extends FileSystem {
+
+    private final char slash;
+    private final char colon;
+    private final String javaHome;
+
+    public UnixFileSystem() {
+        slash = AccessController.doPrivileged(
+            new GetPropertyAction("file.separator")).charAt(0);
+        colon = AccessController.doPrivileged(
+            new GetPropertyAction("path.separator")).charAt(0);
+        javaHome = AccessController.doPrivileged(
+            new GetPropertyAction("java.home"));
+    }
+
+
+    /* -- Normalization and construction -- */
+
+    public char getSeparator() {
+        return slash;
+    }
+
+    public char getPathSeparator() {
+        return colon;
+    }
+
+    /*
+     * A normal Unix pathname does not contain consecutive slashes and does not end
+     * with a slash. The empty string and "/" are special cases that are also
+     * considered normal.
+     */
+    public String normalize(String pathname) {
+        int n = pathname.length();
+        char[] normalized = pathname.toCharArray();
+        int index = 0;
+        char prevChar = 0;
+        for (int i = 0; i < n; i++) {
+            char current = normalized[i];
+            // Remove duplicate slashes.
+            if (!(current == '/' && prevChar == '/')) {
+                normalized[index++] = current;
+            }
+
+            prevChar = current;
+        }
+
+        // Omit the trailing slash, except when pathname == "/".
+        if (prevChar == '/' && n > 1) {
+            index--;
+        }
+
+        return (index != n) ? new String(normalized, 0, index) : pathname;
+    }
+
+    public int prefixLength(String pathname) {
+        if (pathname.length() == 0) return 0;
+        return (pathname.charAt(0) == '/') ? 1 : 0;
+    }
+
+    // Invariant: Both |parent| and |child| are normalized paths.
+    public String resolve(String parent, String child) {
+        if (child.isEmpty() || child.equals("/")) {
+            return parent;
+        }
+
+        if (child.charAt(0) == '/') {
+            if (parent.equals("/")) return child;
+            return parent + child;
+        }
+
+        if (parent.equals("/")) return parent + child;
+        return parent + '/' + child;
+    }
+
+    public String getDefaultParent() {
+        return "/";
+    }
+
+    public String fromURIPath(String path) {
+        String p = path;
+        if (p.endsWith("/") && (p.length() > 1)) {
+            // "/foo/" --> "/foo", but "/" --> "/"
+            p = p.substring(0, p.length() - 1);
+        }
+        return p;
+    }
+
+
+    /* -- Path operations -- */
+
+    public boolean isAbsolute(File f) {
+        return (f.getPrefixLength() != 0);
+    }
+
+    public String resolve(File f) {
+        if (isAbsolute(f)) return f.getPath();
+        return resolve(System.getProperty("user.dir"), f.getPath());
+    }
+
+    // Caches for canonicalization results to improve startup performance.
+    // The first cache handles repeated canonicalizations of the same path
+    // name. The prefix cache handles repeated canonicalizations within the
+    // same directory, and must not create results differing from the true
+    // canonicalization algorithm in canonicalize_md.c. For this reason the
+    // prefix cache is conservative and is not used for complex path names.
+    private ExpiringCache cache = new ExpiringCache();
+    // On Unix symlinks can jump anywhere in the file system, so we only
+    // treat prefixes in java.home as trusted and cacheable in the
+    // canonicalization algorithm
+    private ExpiringCache javaHomePrefixCache = new ExpiringCache();
+
+    public String canonicalize(String path) throws IOException {
+        if (!useCanonCaches) {
+            return canonicalize0(path);
+        } else {
+            String res = cache.get(path);
+            if (res == null) {
+                String dir = null;
+                String resDir = null;
+                if (useCanonPrefixCache) {
+                    // Note that this can cause symlinks that should
+                    // be resolved to a destination directory to be
+                    // resolved to the directory they're contained in
+                    dir = parentOrNull(path);
+                    if (dir != null) {
+                        resDir = javaHomePrefixCache.get(dir);
+                        if (resDir != null) {
+                            // Hit only in prefix cache; full path is canonical
+                            String filename = path.substring(1 + dir.length());
+                            res = resDir + slash + filename;
+                            cache.put(dir + slash + filename, res);
+                        }
+                    }
+                }
+                if (res == null) {
+                    // BEGIN Android-added: BlockGuard support.
+                    BlockGuard.getThreadPolicy().onReadFromDisk();
+                    BlockGuard.getVmPolicy().onPathAccess(path);
+                    // END Android-added: BlockGuard support.
+                    res = canonicalize0(path);
+                    cache.put(path, res);
+                    if (useCanonPrefixCache &&
+                        dir != null && dir.startsWith(javaHome)) {
+                        resDir = parentOrNull(res);
+                        // Note that we don't allow a resolved symlink
+                        // to elsewhere in java.home to pollute the
+                        // prefix cache (java.home prefix cache could
+                        // just as easily be a set at this point)
+                        if (resDir != null && resDir.equals(dir)) {
+                            File f = new File(res);
+                            if (f.exists() && !f.isDirectory()) {
+                                javaHomePrefixCache.put(dir, resDir);
+                            }
+                        }
+                    }
+                }
+            }
+            return res;
+        }
+    }
+    private native String canonicalize0(String path) throws IOException;
+    // Best-effort attempt to get parent of this path; used for
+    // optimization of filename canonicalization. This must return null for
+    // any cases where the code in canonicalize_md.c would throw an
+    // exception or otherwise deal with non-simple pathnames like handling
+    // of "." and "..". It may conservatively return null in other
+    // situations as well. Returning null will cause the underlying
+    // (expensive) canonicalization routine to be called.
+    static String parentOrNull(String path) {
+        if (path == null) return null;
+        char sep = File.separatorChar;
+        int last = path.length() - 1;
+        int idx = last;
+        int adjacentDots = 0;
+        int nonDotCount = 0;
+        while (idx > 0) {
+            char c = path.charAt(idx);
+            if (c == '.') {
+                if (++adjacentDots >= 2) {
+                    // Punt on pathnames containing . and ..
+                    return null;
+                }
+            } else if (c == sep) {
+                if (adjacentDots == 1 && nonDotCount == 0) {
+                    // Punt on pathnames containing . and ..
+                    return null;
+                }
+                if (idx == 0 ||
+                    idx >= last - 1 ||
+                    path.charAt(idx - 1) == sep) {
+                    // Punt on pathnames containing adjacent slashes
+                    // toward the end
+                    return null;
+                }
+                return path.substring(0, idx);
+            } else {
+                ++nonDotCount;
+                adjacentDots = 0;
+            }
+            --idx;
+        }
+        return null;
+    }
+
+    /* -- Attribute accessors -- */
+
+    private native int getBooleanAttributes0(String abspath);
+
+    public int getBooleanAttributes(File f) {
+        // BEGIN Android-added: BlockGuard support.
+        BlockGuard.getThreadPolicy().onReadFromDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        // END Android-added: BlockGuard support.
+
+        int rv = getBooleanAttributes0(f.getPath());
+        String name = f.getName();
+        boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
+        return rv | (hidden ? BA_HIDDEN : 0);
+    }
+
+    // Android-changed: Access files through common interface.
+    public boolean checkAccess(File f, int access) {
+        final int mode;
+        switch (access) {
+            case FileSystem.ACCESS_OK:
+                mode = OsConstants.F_OK;
+                break;
+            case FileSystem.ACCESS_READ:
+                mode = OsConstants.R_OK;
+                break;
+            case FileSystem.ACCESS_WRITE:
+                mode = OsConstants.W_OK;
+                break;
+            case FileSystem.ACCESS_EXECUTE:
+                mode = OsConstants.X_OK;
+                break;
+            default:
+                throw new IllegalArgumentException("Bad access mode: " + access);
+        }
+
+        try {
+            return Libcore.os.access(f.getPath(), mode);
+        } catch (ErrnoException e) {
+            return false;
+        }
+    }
+
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public long getLastModifiedTime(File f) {
+        BlockGuard.getThreadPolicy().onReadFromDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        return getLastModifiedTime0(f);
+    }
+    private native long getLastModifiedTime0(File f);
+
+    // Android-changed: Access files through common interface.
+    public long getLength(File f) {
+        try {
+            return Libcore.os.stat(f.getPath()).st_size;
+        } catch (ErrnoException e) {
+            return 0;
+        }
+    }
+
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        return setPermission0(f, access, enable, owneronly);
+    }
+    private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
+
+    /* -- File operations -- */
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public boolean createFileExclusively(String path) throws IOException {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
+        BlockGuard.getVmPolicy().onPathAccess(path);
+        return createFileExclusively0(path);
+    }
+    private native boolean createFileExclusively0(String path) throws IOException;
+
+    public boolean delete(File f) {
+        // Keep canonicalization caches in sync after file deletion
+        // and renaming operations. Could be more clever than this
+        // (i.e., only remove/update affected entries) but probably
+        // not worth it since these entries expire after 30 seconds
+        // anyway.
+        cache.clear();
+        javaHomePrefixCache.clear();
+        // BEGIN Android-changed: Access files through common interface.
+        try {
+            Libcore.os.remove(f.getPath());
+            return true;
+        } catch (ErrnoException e) {
+            return false;
+        }
+        // END Android-changed: Access files through common interface.
+    }
+
+    // Android-removed: Access files through common interface.
+    // private native boolean delete0(File f);
+
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public String[] list(File f) {
+        BlockGuard.getThreadPolicy().onReadFromDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        return list0(f);
+    }
+    private native String[] list0(File f);
+
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public boolean createDirectory(File f) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        return createDirectory0(f);
+    }
+    private native boolean createDirectory0(File f);
+
+    public boolean rename(File f1, File f2) {
+        // Keep canonicalization caches in sync after file deletion
+        // and renaming operations. Could be more clever than this
+        // (i.e., only remove/update affected entries) but probably
+        // not worth it since these entries expire after 30 seconds
+        // anyway.
+        cache.clear();
+        javaHomePrefixCache.clear();
+        // BEGIN Android-changed: Access files through common interface.
+        try {
+            Libcore.os.rename(f1.getPath(), f2.getPath());
+            return true;
+        } catch (ErrnoException e) {
+            return false;
+        }
+        // END Android-changed: Access files through common interface.
+    }
+
+    // Android-removed: Access files through common interface.
+    // private native boolean rename0(File f1, File f2);
+
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public boolean setLastModifiedTime(File f, long time) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        return setLastModifiedTime0(f, time);
+    }
+    private native boolean setLastModifiedTime0(File f, long time);
+
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public boolean setReadOnly(File f) {
+        BlockGuard.getThreadPolicy().onWriteToDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+        return setReadOnly0(f);
+    }
+    private native boolean setReadOnly0(File f);
+
+
+    /* -- Filesystem interface -- */
+
+    public File[] listRoots() {
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkRead("/");
+            }
+            return new File[] { new File("/") };
+        } catch (SecurityException x) {
+            return new File[0];
+        }
+    }
+
+    /* -- Disk usage -- */
+    // Android-changed: Add method to intercept native method call; BlockGuard support.
+    public long getSpace(File f, int t) {
+        BlockGuard.getThreadPolicy().onReadFromDisk();
+        BlockGuard.getVmPolicy().onPathAccess(f.getPath());
+
+        return getSpace0(f, t);
+    }
+    private native long getSpace0(File f, int t);
+
+    /* -- Basic infrastructure -- */
+
+    public int compare(File f1, File f2) {
+        return f1.getPath().compareTo(f2.getPath());
+    }
+
+    public int hashCode(File f) {
+        return f.getPath().hashCode() ^ 1234321;
+    }
+
+
+    private static native void initIDs();
+
+    static {
+        initIDs();
+    }
+
+}
diff --git a/java/io/UnsupportedEncodingException.java b/java/io/UnsupportedEncodingException.java
new file mode 100644
index 0000000..b59f9c3
--- /dev/null
+++ b/java/io/UnsupportedEncodingException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.io;
+
+/**
+ * The Character Encoding is not supported.
+ *
+ * @author  Asmus Freytag
+ * @since   JDK1.1
+ */
+public class UnsupportedEncodingException
+    extends IOException
+{
+    private static final long serialVersionUID = -4274276298326136670L;
+
+    /**
+     * Constructs an UnsupportedEncodingException without a detail message.
+     */
+    public UnsupportedEncodingException() {
+        super();
+    }
+
+    /**
+     * Constructs an UnsupportedEncodingException with a detail message.
+     * @param s Describes the reason for the exception.
+     */
+    public UnsupportedEncodingException(String s) {
+        super(s);
+    }
+}
diff --git a/java/io/WriteAbortedException.java b/java/io/WriteAbortedException.java
new file mode 100644
index 0000000..c39950d
--- /dev/null
+++ b/java/io/WriteAbortedException.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+/**
+ * Signals that one of the ObjectStreamExceptions was thrown during a
+ * write operation.  Thrown during a read operation when one of the
+ * ObjectStreamExceptions was thrown during a write operation.  The
+ * exception that terminated the write can be found in the detail
+ * field. The stream is reset to it's initial state and all references
+ * to objects already deserialized are discarded.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to conform to
+ * the general purpose exception-chaining mechanism.  The "exception causing
+ * the abort" that is provided at construction time and
+ * accessed via the public {@link #detail} field is now known as the
+ * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
+ * method, as well as the aforementioned "legacy field."
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class WriteAbortedException extends ObjectStreamException {
+    private static final long serialVersionUID = -3326426625597282442L;
+
+    /**
+     * Exception that was caught while writing the ObjectStream.
+     *
+     * <p>This field predates the general-purpose exception chaining facility.
+     * The {@link Throwable#getCause()} method is now the preferred means of
+     * obtaining this information.
+     *
+     * @serial
+     */
+    public Exception detail;
+
+    /**
+     * Constructs a WriteAbortedException with a string describing
+     * the exception and the exception causing the abort.
+     * @param s   String describing the exception.
+     * @param ex  Exception causing the abort.
+     */
+    public WriteAbortedException(String s, Exception ex) {
+        super(s);
+        initCause(null);  // Disallow subsequent initCause
+        detail = ex;
+    }
+
+    /**
+     * Produce the message and include the message from the nested
+     * exception, if there is one.
+     */
+    public String getMessage() {
+        if (detail == null)
+            return super.getMessage();
+        else
+            return super.getMessage() + "; " + detail.toString();
+    }
+
+    /**
+     * Returns the exception that terminated the operation (the <i>cause</i>).
+     *
+     * @return  the exception that terminated the operation (the <i>cause</i>),
+     *          which may be null.
+     * @since   1.4
+     */
+    public Throwable getCause() {
+        return detail;
+    }
+}
diff --git a/java/io/Writer.java b/java/io/Writer.java
new file mode 100644
index 0000000..8747a13
--- /dev/null
+++ b/java/io/Writer.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.io;
+
+
+/**
+ * Abstract class for writing to character streams.  The only methods that a
+ * subclass must implement are write(char[], int, int), flush(), and close().
+ * Most subclasses, however, will override some of the methods defined here in
+ * order to provide higher efficiency, additional functionality, or both.
+ *
+ * @see Writer
+ * @see   BufferedWriter
+ * @see   CharArrayWriter
+ * @see   FilterWriter
+ * @see   OutputStreamWriter
+ * @see     FileWriter
+ * @see   PipedWriter
+ * @see   PrintWriter
+ * @see   StringWriter
+ * @see Reader
+ *
+ * @author      Mark Reinhold
+ * @since       JDK1.1
+ */
+
+public abstract class Writer implements Appendable, Closeable, Flushable {
+
+    /**
+     * Temporary buffer used to hold writes of strings and single characters
+     */
+    private char[] writeBuffer;
+
+    /**
+     * Size of writeBuffer, must be >= 1
+     */
+    private static final int WRITE_BUFFER_SIZE = 1024;
+
+    /**
+     * The object used to synchronize operations on this stream.  For
+     * efficiency, a character-stream object may use an object other than
+     * itself to protect critical sections.  A subclass should therefore use
+     * the object in this field rather than <tt>this</tt> or a synchronized
+     * method.
+     */
+    protected Object lock;
+
+    /**
+     * Creates a new character-stream writer whose critical sections will
+     * synchronize on the writer itself.
+     */
+    protected Writer() {
+        this.lock = this;
+    }
+
+    /**
+     * Creates a new character-stream writer whose critical sections will
+     * synchronize on the given object.
+     *
+     * @param  lock
+     *         Object to synchronize on
+     */
+    protected Writer(Object lock) {
+        if (lock == null) {
+            throw new NullPointerException();
+        }
+        this.lock = lock;
+    }
+
+    /**
+     * Writes a single character.  The character to be written is contained in
+     * the 16 low-order bits of the given integer value; the 16 high-order bits
+     * are ignored.
+     *
+     * <p> Subclasses that intend to support efficient single-character output
+     * should override this method.
+     *
+     * @param  c
+     *         int specifying a character to be written
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public void write(int c) throws IOException {
+        synchronized (lock) {
+            if (writeBuffer == null){
+                writeBuffer = new char[WRITE_BUFFER_SIZE];
+            }
+            writeBuffer[0] = (char) c;
+            write(writeBuffer, 0, 1);
+        }
+    }
+
+    /**
+     * Writes an array of characters.
+     *
+     * @param  cbuf
+     *         Array of characters to be written
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public void write(char cbuf[]) throws IOException {
+        write(cbuf, 0, cbuf.length);
+    }
+
+    /**
+     * Writes a portion of an array of characters.
+     *
+     * @param  cbuf
+     *         Array of characters
+     *
+     * @param  off
+     *         Offset from which to start writing characters
+     *
+     * @param  len
+     *         Number of characters to write
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    abstract public void write(char cbuf[], int off, int len) throws IOException;
+
+    /**
+     * Writes a string.
+     *
+     * @param  str
+     *         String to be written
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public void write(String str) throws IOException {
+        write(str, 0, str.length());
+    }
+
+    /**
+     * Writes a portion of a string.
+     *
+     * @param  str
+     *         A String
+     *
+     * @param  off
+     *         Offset from which to start writing characters
+     *
+     * @param  len
+     *         Number of characters to write
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>off</tt> is negative, or <tt>len</tt> is negative,
+     *          or <tt>off+len</tt> is negative or greater than the length
+     *          of the given string
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public void write(String str, int off, int len) throws IOException {
+        synchronized (lock) {
+            char cbuf[];
+            if (len <= WRITE_BUFFER_SIZE) {
+                if (writeBuffer == null) {
+                    writeBuffer = new char[WRITE_BUFFER_SIZE];
+                }
+                cbuf = writeBuffer;
+            } else {    // Don't permanently allocate very large buffers.
+                cbuf = new char[len];
+            }
+            str.getChars(off, (off + len), cbuf, 0);
+            write(cbuf, 0, len);
+        }
+    }
+
+    /**
+     * Appends the specified character sequence to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.toString()) </pre>
+     *
+     * <p> Depending on the specification of <tt>toString</tt> for the
+     * character sequence <tt>csq</tt>, the entire sequence may not be
+     * appended. For instance, invoking the <tt>toString</tt> method of a
+     * character buffer will return a subsequence whose content depends upon
+     * the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this writer.
+     *
+     * @return  This writer
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since  1.5
+     */
+    public Writer append(CharSequence csq) throws IOException {
+        if (csq == null)
+            write("null");
+        else
+            write(csq.toString());
+        return this;
+    }
+
+    /**
+     * Appends a subsequence of the specified character sequence to this writer.
+     * <tt>Appendable</tt>.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the
+     * same way as the invocation
+     *
+     * <pre>
+     *     out.write(csq.subSequence(start, end).toString()) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @param  start
+     *         The index of the first character in the subsequence
+     *
+     * @param  end
+     *         The index of the character following the last character in the
+     *         subsequence
+     *
+     * @return  This writer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since  1.5
+     */
+    public Writer append(CharSequence csq, int start, int end) throws IOException {
+        CharSequence cs = (csq == null ? "null" : csq);
+        write(cs.subSequence(start, end).toString());
+        return this;
+    }
+
+    /**
+     * Appends the specified character to this writer.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(c)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.write(c) </pre>
+     *
+     * @param  c
+     *         The 16-bit character to append
+     *
+     * @return  This writer
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.5
+     */
+    public Writer append(char c) throws IOException {
+        write(c);
+        return this;
+    }
+
+    /**
+     * Flushes the stream.  If the stream has saved any characters from the
+     * various write() methods in a buffer, write them immediately to their
+     * intended destination.  Then, if that destination is another character or
+     * byte stream, flush it.  Thus one flush() invocation will flush all the
+     * buffers in a chain of Writers and OutputStreams.
+     *
+     * <p> If the intended destination of this stream is an abstraction provided
+     * by the underlying operating system, for example a file, then flushing the
+     * stream guarantees only that bytes previously written to the stream are
+     * passed to the operating system for writing; it does not guarantee that
+     * they are actually written to a physical device such as a disk drive.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    abstract public void flush() throws IOException;
+
+    /**
+     * Closes the stream, flushing it first. Once the stream has been closed,
+     * further write() or flush() invocations will cause an IOException to be
+     * thrown. Closing a previously closed stream has no effect.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    abstract public void close() throws IOException;
+
+}
diff --git a/java/lang/AbstractMethodError.java b/java/lang/AbstractMethodError.java
new file mode 100644
index 0000000..e266107
--- /dev/null
+++ b/java/lang/AbstractMethodError.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application tries to call an abstract method.
+ * Normally, this error is caught by the compiler; this error can
+ * only occur at run time if the definition of some class has
+ * incompatibly changed since the currently executing method was last
+ * compiled.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class AbstractMethodError extends IncompatibleClassChangeError {
+    private static final long serialVersionUID = -1654391082989018462L;
+
+    /**
+     * Constructs an <code>AbstractMethodError</code> with no detail  message.
+     */
+    public AbstractMethodError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>AbstractMethodError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public AbstractMethodError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/AbstractStringBuilder.java b/java/lang/AbstractStringBuilder.java
new file mode 100644
index 0000000..4c31e23
--- /dev/null
+++ b/java/lang/AbstractStringBuilder.java
@@ -0,0 +1,1466 @@
+/*
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import sun.misc.FloatingDecimal;
+import java.util.Arrays;
+
+/**
+ * A mutable sequence of characters.
+ * <p>
+ * Implements a modifiable string. At any point in time it contains some
+ * particular sequence of characters, but the length and content of the
+ * sequence can be changed through certain method calls.
+ *
+ * <p>Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * @author      Michael McCloskey
+ * @author      Martin Buchholz
+ * @author      Ulf Zibis
+ * @since       1.5
+ */
+abstract class AbstractStringBuilder implements Appendable, CharSequence {
+    /**
+     * The value is used for character storage.
+     */
+    char[] value;
+
+    /**
+     * The count is the number of characters used.
+     */
+    int count;
+
+    /**
+     * This no-arg constructor is necessary for serialization of subclasses.
+     */
+    AbstractStringBuilder() {
+    }
+
+    /**
+     * Creates an AbstractStringBuilder of the specified capacity.
+     */
+    AbstractStringBuilder(int capacity) {
+        value = new char[capacity];
+    }
+
+    /**
+     * Returns the length (character count).
+     *
+     * @return  the length of the sequence of characters currently
+     *          represented by this object
+     */
+    @Override
+    public int length() {
+        return count;
+    }
+
+    /**
+     * Returns the current capacity. The capacity is the amount of storage
+     * available for newly inserted characters, beyond which an allocation
+     * will occur.
+     *
+     * @return  the current capacity
+     */
+    public int capacity() {
+        return value.length;
+    }
+
+    /**
+     * Ensures that the capacity is at least equal to the specified minimum.
+     * If the current capacity is less than the argument, then a new internal
+     * array is allocated with greater capacity. The new capacity is the
+     * larger of:
+     * <ul>
+     * <li>The {@code minimumCapacity} argument.
+     * <li>Twice the old capacity, plus {@code 2}.
+     * </ul>
+     * If the {@code minimumCapacity} argument is nonpositive, this
+     * method takes no action and simply returns.
+     * Note that subsequent operations on this object can reduce the
+     * actual capacity below that requested here.
+     *
+     * @param   minimumCapacity   the minimum desired capacity.
+     */
+    public void ensureCapacity(int minimumCapacity) {
+        if (minimumCapacity > 0)
+            ensureCapacityInternal(minimumCapacity);
+    }
+
+    /**
+     * For positive values of {@code minimumCapacity}, this method
+     * behaves like {@code ensureCapacity}, however it is never
+     * synchronized.
+     * If {@code minimumCapacity} is non positive due to numeric
+     * overflow, this method throws {@code OutOfMemoryError}.
+     */
+    private void ensureCapacityInternal(int minimumCapacity) {
+        // overflow-conscious code
+        if (minimumCapacity - value.length > 0) {
+            value = Arrays.copyOf(value,
+                    newCapacity(minimumCapacity));
+        }
+    }
+
+    /**
+     * The maximum size of array to allocate (unless necessary).
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Returns a capacity at least as large as the given minimum capacity.
+     * Returns the current capacity increased by the same amount + 2 if
+     * that suffices.
+     * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
+     * unless the given minimum capacity is greater than that.
+     *
+     * @param  minCapacity the desired minimum capacity
+     * @throws OutOfMemoryError if minCapacity is less than zero or
+     *         greater than Integer.MAX_VALUE
+     */
+    private int newCapacity(int minCapacity) {
+        // overflow-conscious code
+        int newCapacity = (value.length << 1) + 2;
+        if (newCapacity - minCapacity < 0) {
+            newCapacity = minCapacity;
+        }
+        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
+            ? hugeCapacity(minCapacity)
+            : newCapacity;
+    }
+
+    private int hugeCapacity(int minCapacity) {
+        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
+            throw new OutOfMemoryError();
+        }
+        return (minCapacity > MAX_ARRAY_SIZE)
+            ? minCapacity : MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Attempts to reduce storage used for the character sequence.
+     * If the buffer is larger than necessary to hold its current sequence of
+     * characters, then it may be resized to become more space efficient.
+     * Calling this method may, but is not required to, affect the value
+     * returned by a subsequent call to the {@link #capacity()} method.
+     */
+    public void trimToSize() {
+        if (count < value.length) {
+            value = Arrays.copyOf(value, count);
+        }
+    }
+
+    /**
+     * Sets the length of the character sequence.
+     * The sequence is changed to a new character sequence
+     * whose length is specified by the argument. For every nonnegative
+     * index <i>k</i> less than {@code newLength}, the character at
+     * index <i>k</i> in the new character sequence is the same as the
+     * character at index <i>k</i> in the old sequence if <i>k</i> is less
+     * than the length of the old character sequence; otherwise, it is the
+     * null character {@code '\u005Cu0000'}.
+     *
+     * In other words, if the {@code newLength} argument is less than
+     * the current length, the length is changed to the specified length.
+     * <p>
+     * If the {@code newLength} argument is greater than or equal
+     * to the current length, sufficient null characters
+     * ({@code '\u005Cu0000'}) are appended so that
+     * length becomes the {@code newLength} argument.
+     * <p>
+     * The {@code newLength} argument must be greater than or equal
+     * to {@code 0}.
+     *
+     * @param      newLength   the new length
+     * @throws     IndexOutOfBoundsException  if the
+     *               {@code newLength} argument is negative.
+     */
+    public void setLength(int newLength) {
+        if (newLength < 0)
+            throw new StringIndexOutOfBoundsException(newLength);
+        ensureCapacityInternal(newLength);
+
+        if (count < newLength) {
+            Arrays.fill(value, count, newLength, '\0');
+        }
+
+        count = newLength;
+    }
+
+    /**
+     * Returns the {@code char} value in this sequence at the specified index.
+     * The first {@code char} value is at index {@code 0}, the next at index
+     * {@code 1}, and so on, as in array indexing.
+     * <p>
+     * The index argument must be greater than or equal to
+     * {@code 0}, and less than the length of this sequence.
+     *
+     * <p>If the {@code char} value specified by the index is a
+     * <a href="Character.html#unicode">surrogate</a>, the surrogate
+     * value is returned.
+     *
+     * @param      index   the index of the desired {@code char} value.
+     * @return     the {@code char} value at the specified index.
+     * @throws     IndexOutOfBoundsException  if {@code index} is
+     *             negative or greater than or equal to {@code length()}.
+     */
+    @Override
+    public char charAt(int index) {
+        if ((index < 0) || (index >= count))
+            throw new StringIndexOutOfBoundsException(index);
+        return value[index];
+    }
+
+    /**
+     * Returns the character (Unicode code point) at the specified
+     * index. The index refers to {@code char} values
+     * (Unicode code units) and ranges from {@code 0} to
+     * {@link #length()}{@code  - 1}.
+     *
+     * <p> If the {@code char} value specified at the given index
+     * is in the high-surrogate range, the following index is less
+     * than the length of this sequence, and the
+     * {@code char} value at the following index is in the
+     * low-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at the given index is returned.
+     *
+     * @param      index the index to the {@code char} values
+     * @return     the code point value of the character at the
+     *             {@code index}
+     * @exception  IndexOutOfBoundsException  if the {@code index}
+     *             argument is negative or not less than the length of this
+     *             sequence.
+     */
+    public int codePointAt(int index) {
+        if ((index < 0) || (index >= count)) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        return Character.codePointAtImpl(value, index, count);
+    }
+
+    /**
+     * Returns the character (Unicode code point) before the specified
+     * index. The index refers to {@code char} values
+     * (Unicode code units) and ranges from {@code 1} to {@link
+     * #length()}.
+     *
+     * <p> If the {@code char} value at {@code (index - 1)}
+     * is in the low-surrogate range, {@code (index - 2)} is not
+     * negative, and the {@code char} value at {@code (index -
+     * 2)} is in the high-surrogate range, then the
+     * supplementary code point value of the surrogate pair is
+     * returned. If the {@code char} value at {@code index -
+     * 1} is an unpaired low-surrogate or a high-surrogate, the
+     * surrogate value is returned.
+     *
+     * @param     index the index following the code point that should be returned
+     * @return    the Unicode code point value before the given index.
+     * @exception IndexOutOfBoundsException if the {@code index}
+     *            argument is less than 1 or greater than the length
+     *            of this sequence.
+     */
+    public int codePointBefore(int index) {
+        int i = index - 1;
+        if ((i < 0) || (i >= count)) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        return Character.codePointBeforeImpl(value, index, 0);
+    }
+
+    /**
+     * Returns the number of Unicode code points in the specified text
+     * range of this sequence. The text range begins at the specified
+     * {@code beginIndex} and extends to the {@code char} at
+     * index {@code endIndex - 1}. Thus the length (in
+     * {@code char}s) of the text range is
+     * {@code endIndex-beginIndex}. Unpaired surrogates within
+     * this sequence count as one code point each.
+     *
+     * @param beginIndex the index to the first {@code char} of
+     * the text range.
+     * @param endIndex the index after the last {@code char} of
+     * the text range.
+     * @return the number of Unicode code points in the specified text
+     * range
+     * @exception IndexOutOfBoundsException if the
+     * {@code beginIndex} is negative, or {@code endIndex}
+     * is larger than the length of this sequence, or
+     * {@code beginIndex} is larger than {@code endIndex}.
+     */
+    public int codePointCount(int beginIndex, int endIndex) {
+        if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
+            throw new IndexOutOfBoundsException();
+        }
+        return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
+    }
+
+    /**
+     * Returns the index within this sequence that is offset from the
+     * given {@code index} by {@code codePointOffset} code
+     * points. Unpaired surrogates within the text range given by
+     * {@code index} and {@code codePointOffset} count as
+     * one code point each.
+     *
+     * @param index the index to be offset
+     * @param codePointOffset the offset in code points
+     * @return the index within this sequence
+     * @exception IndexOutOfBoundsException if {@code index}
+     *   is negative or larger then the length of this sequence,
+     *   or if {@code codePointOffset} is positive and the subsequence
+     *   starting with {@code index} has fewer than
+     *   {@code codePointOffset} code points,
+     *   or if {@code codePointOffset} is negative and the subsequence
+     *   before {@code index} has fewer than the absolute value of
+     *   {@code codePointOffset} code points.
+     */
+    public int offsetByCodePoints(int index, int codePointOffset) {
+        if (index < 0 || index > count) {
+            throw new IndexOutOfBoundsException();
+        }
+        return Character.offsetByCodePointsImpl(value, 0, count,
+                                                index, codePointOffset);
+    }
+
+    /**
+     * Characters are copied from this sequence into the
+     * destination character array {@code dst}. The first character to
+     * be copied is at index {@code srcBegin}; the last character to
+     * be copied is at index {@code srcEnd-1}. The total number of
+     * characters to be copied is {@code srcEnd-srcBegin}. The
+     * characters are copied into the subarray of {@code dst} starting
+     * at index {@code dstBegin} and ending at index:
+     * <pre>{@code
+     * dstbegin + (srcEnd-srcBegin) - 1
+     * }</pre>
+     *
+     * @param      srcBegin   start copying at this offset.
+     * @param      srcEnd     stop copying at this offset.
+     * @param      dst        the array to copy the data into.
+     * @param      dstBegin   offset into {@code dst}.
+     * @throws     IndexOutOfBoundsException  if any of the following is true:
+     *             <ul>
+     *             <li>{@code srcBegin} is negative
+     *             <li>{@code dstBegin} is negative
+     *             <li>the {@code srcBegin} argument is greater than
+     *             the {@code srcEnd} argument.
+     *             <li>{@code srcEnd} is greater than
+     *             {@code this.length()}.
+     *             <li>{@code dstBegin+srcEnd-srcBegin} is greater than
+     *             {@code dst.length}
+     *             </ul>
+     */
+    public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
+    {
+        if (srcBegin < 0)
+            throw new StringIndexOutOfBoundsException(srcBegin);
+        if ((srcEnd < 0) || (srcEnd > count))
+            throw new StringIndexOutOfBoundsException(srcEnd);
+        if (srcBegin > srcEnd)
+            throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
+        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
+    }
+
+    /**
+     * The character at the specified index is set to {@code ch}. This
+     * sequence is altered to represent a new character sequence that is
+     * identical to the old character sequence, except that it contains the
+     * character {@code ch} at position {@code index}.
+     * <p>
+     * The index argument must be greater than or equal to
+     * {@code 0}, and less than the length of this sequence.
+     *
+     * @param      index   the index of the character to modify.
+     * @param      ch      the new character.
+     * @throws     IndexOutOfBoundsException  if {@code index} is
+     *             negative or greater than or equal to {@code length()}.
+     */
+    public void setCharAt(int index, char ch) {
+        if ((index < 0) || (index >= count))
+            throw new StringIndexOutOfBoundsException(index);
+        value[index] = ch;
+    }
+
+    /**
+     * Appends the string representation of the {@code Object} argument.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(Object)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   obj   an {@code Object}.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(Object obj) {
+        return append(String.valueOf(obj));
+    }
+
+    /**
+     * Appends the specified string to this character sequence.
+     * <p>
+     * The characters of the {@code String} argument are appended, in
+     * order, increasing the length of this sequence by the length of the
+     * argument. If {@code str} is {@code null}, then the four
+     * characters {@code "null"} are appended.
+     * <p>
+     * Let <i>n</i> be the length of this character sequence just prior to
+     * execution of the {@code append} method. Then the character at
+     * index <i>k</i> in the new character sequence is equal to the character
+     * at index <i>k</i> in the old character sequence, if <i>k</i> is less
+     * than <i>n</i>; otherwise, it is equal to the character at index
+     * <i>k-n</i> in the argument {@code str}.
+     *
+     * @param   str   a string.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(String str) {
+        if (str == null)
+            return appendNull();
+        int len = str.length();
+        ensureCapacityInternal(count + len);
+        str.getChars(0, len, value, count);
+        count += len;
+        return this;
+    }
+
+    // Documentation in subclasses because of synchro difference
+    public AbstractStringBuilder append(StringBuffer sb) {
+        if (sb == null)
+            return appendNull();
+        int len = sb.length();
+        ensureCapacityInternal(count + len);
+        sb.getChars(0, len, value, count);
+        count += len;
+        return this;
+    }
+
+    /**
+     * @since 1.8
+     */
+    AbstractStringBuilder append(AbstractStringBuilder asb) {
+        if (asb == null)
+            return appendNull();
+        int len = asb.length();
+        ensureCapacityInternal(count + len);
+        asb.getChars(0, len, value, count);
+        count += len;
+        return this;
+    }
+
+    // Documentation in subclasses because of synchro difference
+    @Override
+    public AbstractStringBuilder append(CharSequence s) {
+        if (s == null)
+            return appendNull();
+        if (s instanceof String)
+            return this.append((String)s);
+        if (s instanceof AbstractStringBuilder)
+            return this.append((AbstractStringBuilder)s);
+
+        return this.append(s, 0, s.length());
+    }
+
+    private AbstractStringBuilder appendNull() {
+        int c = count;
+        ensureCapacityInternal(c + 4);
+        final char[] value = this.value;
+        value[c++] = 'n';
+        value[c++] = 'u';
+        value[c++] = 'l';
+        value[c++] = 'l';
+        count = c;
+        return this;
+    }
+
+    /**
+     * Appends a subsequence of the specified {@code CharSequence} to this
+     * sequence.
+     * <p>
+     * Characters of the argument {@code s}, starting at
+     * index {@code start}, are appended, in order, to the contents of
+     * this sequence up to the (exclusive) index {@code end}. The length
+     * of this sequence is increased by the value of {@code end - start}.
+     * <p>
+     * Let <i>n</i> be the length of this character sequence just prior to
+     * execution of the {@code append} method. Then the character at
+     * index <i>k</i> in this character sequence becomes equal to the
+     * character at index <i>k</i> in this sequence, if <i>k</i> is less than
+     * <i>n</i>; otherwise, it is equal to the character at index
+     * <i>k+start-n</i> in the argument {@code s}.
+     * <p>
+     * If {@code s} is {@code null}, then this method appends
+     * characters as if the s parameter was a sequence containing the four
+     * characters {@code "null"}.
+     *
+     * @param   s the sequence to append.
+     * @param   start   the starting index of the subsequence to be appended.
+     * @param   end     the end index of the subsequence to be appended.
+     * @return  a reference to this object.
+     * @throws     IndexOutOfBoundsException if
+     *             {@code start} is negative, or
+     *             {@code start} is greater than {@code end} or
+     *             {@code end} is greater than {@code s.length()}
+     */
+    @Override
+    public AbstractStringBuilder append(CharSequence s, int start, int end) {
+        if (s == null)
+            s = "null";
+        if ((start < 0) || (start > end) || (end > s.length()))
+            throw new IndexOutOfBoundsException(
+                "start " + start + ", end " + end + ", s.length() "
+                + s.length());
+        int len = end - start;
+        ensureCapacityInternal(count + len);
+        for (int i = start, j = count; i < end; i++, j++)
+            value[j] = s.charAt(i);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code char} array
+     * argument to this sequence.
+     * <p>
+     * The characters of the array argument are appended, in order, to
+     * the contents of this sequence. The length of this sequence
+     * increases by the length of the argument.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(char[])},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   str   the characters to be appended.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(char[] str) {
+        int len = str.length;
+        ensureCapacityInternal(count + len);
+        System.arraycopy(str, 0, value, count, len);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Appends the string representation of a subarray of the
+     * {@code char} array argument to this sequence.
+     * <p>
+     * Characters of the {@code char} array {@code str}, starting at
+     * index {@code offset}, are appended, in order, to the contents
+     * of this sequence. The length of this sequence increases
+     * by the value of {@code len}.
+     * <p>
+     * The overall effect is exactly as if the arguments were converted
+     * to a string by the method {@link String#valueOf(char[],int,int)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   str      the characters to be appended.
+     * @param   offset   the index of the first {@code char} to append.
+     * @param   len      the number of {@code char}s to append.
+     * @return  a reference to this object.
+     * @throws IndexOutOfBoundsException
+     *         if {@code offset < 0} or {@code len < 0}
+     *         or {@code offset+len > str.length}
+     */
+    public AbstractStringBuilder append(char str[], int offset, int len) {
+        if (len > 0)                // let arraycopy report AIOOBE for len < 0
+            ensureCapacityInternal(count + len);
+        System.arraycopy(str, offset, value, count, len);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code boolean}
+     * argument to the sequence.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(boolean)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   b   a {@code boolean}.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(boolean b) {
+        if (b) {
+            ensureCapacityInternal(count + 4);
+            value[count++] = 't';
+            value[count++] = 'r';
+            value[count++] = 'u';
+            value[count++] = 'e';
+        } else {
+            ensureCapacityInternal(count + 5);
+            value[count++] = 'f';
+            value[count++] = 'a';
+            value[count++] = 'l';
+            value[count++] = 's';
+            value[count++] = 'e';
+        }
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code char}
+     * argument to this sequence.
+     * <p>
+     * The argument is appended to the contents of this sequence.
+     * The length of this sequence increases by {@code 1}.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(char)},
+     * and the character in that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   c   a {@code char}.
+     * @return  a reference to this object.
+     */
+    @Override
+    public AbstractStringBuilder append(char c) {
+        ensureCapacityInternal(count + 1);
+        value[count++] = c;
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code int}
+     * argument to this sequence.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(int)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   i   an {@code int}.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(int i) {
+        if (i == Integer.MIN_VALUE) {
+            append("-2147483648");
+            return this;
+        }
+        int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
+                                     : Integer.stringSize(i);
+        int spaceNeeded = count + appendedLength;
+        ensureCapacityInternal(spaceNeeded);
+        Integer.getChars(i, spaceNeeded, value);
+        count = spaceNeeded;
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code long}
+     * argument to this sequence.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(long)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   l   a {@code long}.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(long l) {
+        if (l == Long.MIN_VALUE) {
+            append("-9223372036854775808");
+            return this;
+        }
+        int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
+                                     : Long.stringSize(l);
+        int spaceNeeded = count + appendedLength;
+        ensureCapacityInternal(spaceNeeded);
+        Long.getChars(l, spaceNeeded, value);
+        count = spaceNeeded;
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code float}
+     * argument to this sequence.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(float)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   f   a {@code float}.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(float f) {
+        FloatingDecimal.appendTo(f,this);
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code double}
+     * argument to this sequence.
+     * <p>
+     * The overall effect is exactly as if the argument were converted
+     * to a string by the method {@link String#valueOf(double)},
+     * and the characters of that string were then
+     * {@link #append(String) appended} to this character sequence.
+     *
+     * @param   d   a {@code double}.
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder append(double d) {
+        FloatingDecimal.appendTo(d,this);
+        return this;
+    }
+
+    /**
+     * Removes the characters in a substring of this sequence.
+     * The substring begins at the specified {@code start} and extends to
+     * the character at index {@code end - 1} or to the end of the
+     * sequence if no such character exists. If
+     * {@code start} is equal to {@code end}, no changes are made.
+     *
+     * @param      start  The beginning index, inclusive.
+     * @param      end    The ending index, exclusive.
+     * @return     This object.
+     * @throws     StringIndexOutOfBoundsException  if {@code start}
+     *             is negative, greater than {@code length()}, or
+     *             greater than {@code end}.
+     */
+    public AbstractStringBuilder delete(int start, int end) {
+        if (start < 0)
+            throw new StringIndexOutOfBoundsException(start);
+        if (end > count)
+            end = count;
+        if (start > end)
+            throw new StringIndexOutOfBoundsException();
+        int len = end - start;
+        if (len > 0) {
+            System.arraycopy(value, start+len, value, start, count-end);
+            count -= len;
+        }
+        return this;
+    }
+
+    /**
+     * Appends the string representation of the {@code codePoint}
+     * argument to this sequence.
+     *
+     * <p> The argument is appended to the contents of this sequence.
+     * The length of this sequence increases by
+     * {@link Character#charCount(int) Character.charCount(codePoint)}.
+     *
+     * <p> The overall effect is exactly as if the argument were
+     * converted to a {@code char} array by the method
+     * {@link Character#toChars(int)} and the character in that array
+     * were then {@link #append(char[]) appended} to this character
+     * sequence.
+     *
+     * @param   codePoint   a Unicode code point
+     * @return  a reference to this object.
+     * @exception IllegalArgumentException if the specified
+     * {@code codePoint} isn't a valid Unicode code point
+     */
+    public AbstractStringBuilder appendCodePoint(int codePoint) {
+        final int count = this.count;
+
+        if (Character.isBmpCodePoint(codePoint)) {
+            ensureCapacityInternal(count + 1);
+            value[count] = (char) codePoint;
+            this.count = count + 1;
+        } else if (Character.isValidCodePoint(codePoint)) {
+            ensureCapacityInternal(count + 2);
+            Character.toSurrogates(codePoint, value, count);
+            this.count = count + 2;
+        } else {
+            throw new IllegalArgumentException();
+        }
+        return this;
+    }
+
+    /**
+     * Removes the {@code char} at the specified position in this
+     * sequence. This sequence is shortened by one {@code char}.
+     *
+     * <p>Note: If the character at the given index is a supplementary
+     * character, this method does not remove the entire character. If
+     * correct handling of supplementary characters is required,
+     * determine the number of {@code char}s to remove by calling
+     * {@code Character.charCount(thisSequence.codePointAt(index))},
+     * where {@code thisSequence} is this sequence.
+     *
+     * @param       index  Index of {@code char} to remove
+     * @return      This object.
+     * @throws      StringIndexOutOfBoundsException  if the {@code index}
+     *              is negative or greater than or equal to
+     *              {@code length()}.
+     */
+    public AbstractStringBuilder deleteCharAt(int index) {
+        if ((index < 0) || (index >= count))
+            throw new StringIndexOutOfBoundsException(index);
+        System.arraycopy(value, index+1, value, index, count-index-1);
+        count--;
+        return this;
+    }
+
+    /**
+     * Replaces the characters in a substring of this sequence
+     * with characters in the specified {@code String}. The substring
+     * begins at the specified {@code start} and extends to the character
+     * at index {@code end - 1} or to the end of the
+     * sequence if no such character exists. First the
+     * characters in the substring are removed and then the specified
+     * {@code String} is inserted at {@code start}. (This
+     * sequence will be lengthened to accommodate the
+     * specified String if necessary.)
+     *
+     * @param      start    The beginning index, inclusive.
+     * @param      end      The ending index, exclusive.
+     * @param      str   String that will replace previous contents.
+     * @return     This object.
+     * @throws     StringIndexOutOfBoundsException  if {@code start}
+     *             is negative, greater than {@code length()}, or
+     *             greater than {@code end}.
+     */
+    public AbstractStringBuilder replace(int start, int end, String str) {
+        if (start < 0)
+            throw new StringIndexOutOfBoundsException(start);
+        if (start > count)
+            throw new StringIndexOutOfBoundsException("start > length()");
+        if (start > end)
+            throw new StringIndexOutOfBoundsException("start > end");
+
+        if (end > count)
+            end = count;
+        int len = str.length();
+        int newCount = count + len - (end - start);
+        ensureCapacityInternal(newCount);
+
+        System.arraycopy(value, end, value, start + len, count - end);
+        str.getChars(value, start);
+        count = newCount;
+        return this;
+    }
+
+    /**
+     * Returns a new {@code String} that contains a subsequence of
+     * characters currently contained in this character sequence. The
+     * substring begins at the specified index and extends to the end of
+     * this sequence.
+     *
+     * @param      start    The beginning index, inclusive.
+     * @return     The new string.
+     * @throws     StringIndexOutOfBoundsException  if {@code start} is
+     *             less than zero, or greater than the length of this object.
+     */
+    public String substring(int start) {
+        return substring(start, count);
+    }
+
+    /**
+     * Returns a new character sequence that is a subsequence of this sequence.
+     *
+     * <p> An invocation of this method of the form
+     *
+     * <pre>{@code
+     * sb.subSequence(begin,&nbsp;end)}</pre>
+     *
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>{@code
+     * sb.substring(begin,&nbsp;end)}</pre>
+     *
+     * This method is provided so that this class can
+     * implement the {@link CharSequence} interface.
+     *
+     * @param      start   the start index, inclusive.
+     * @param      end     the end index, exclusive.
+     * @return     the specified subsequence.
+     *
+     * @throws  IndexOutOfBoundsException
+     *          if {@code start} or {@code end} are negative,
+     *          if {@code end} is greater than {@code length()},
+     *          or if {@code start} is greater than {@code end}
+     * @spec JSR-51
+     */
+    @Override
+    public CharSequence subSequence(int start, int end) {
+        return substring(start, end);
+    }
+
+    /**
+     * Returns a new {@code String} that contains a subsequence of
+     * characters currently contained in this sequence. The
+     * substring begins at the specified {@code start} and
+     * extends to the character at index {@code end - 1}.
+     *
+     * @param      start    The beginning index, inclusive.
+     * @param      end      The ending index, exclusive.
+     * @return     The new string.
+     * @throws     StringIndexOutOfBoundsException  if {@code start}
+     *             or {@code end} are negative or greater than
+     *             {@code length()}, or {@code start} is
+     *             greater than {@code end}.
+     */
+    public String substring(int start, int end) {
+        if (start < 0)
+            throw new StringIndexOutOfBoundsException(start);
+        if (end > count)
+            throw new StringIndexOutOfBoundsException(end);
+        if (start > end)
+            throw new StringIndexOutOfBoundsException(end - start);
+        return new String(value, start, end - start);
+    }
+
+    /**
+     * Inserts the string representation of a subarray of the {@code str}
+     * array argument into this sequence. The subarray begins at the
+     * specified {@code offset} and extends {@code len} {@code char}s.
+     * The characters of the subarray are inserted into this sequence at
+     * the position indicated by {@code index}. The length of this
+     * sequence increases by {@code len} {@code char}s.
+     *
+     * @param      index    position at which to insert subarray.
+     * @param      str       A {@code char} array.
+     * @param      offset   the index of the first {@code char} in subarray to
+     *             be inserted.
+     * @param      len      the number of {@code char}s in the subarray to
+     *             be inserted.
+     * @return     This object
+     * @throws     StringIndexOutOfBoundsException  if {@code index}
+     *             is negative or greater than {@code length()}, or
+     *             {@code offset} or {@code len} are negative, or
+     *             {@code (offset+len)} is greater than
+     *             {@code str.length}.
+     */
+    public AbstractStringBuilder insert(int index, char[] str, int offset,
+                                        int len)
+    {
+        if ((index < 0) || (index > length()))
+            throw new StringIndexOutOfBoundsException(index);
+        if ((offset < 0) || (len < 0) || (offset > str.length - len))
+            throw new StringIndexOutOfBoundsException(
+                "offset " + offset + ", len " + len + ", str.length "
+                + str.length);
+        ensureCapacityInternal(count + len);
+        System.arraycopy(value, index, value, index + len, count - index);
+        System.arraycopy(str, offset, value, index, len);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Inserts the string representation of the {@code Object}
+     * argument into this character sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(Object)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      obj      an {@code Object}.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, Object obj) {
+        return insert(offset, String.valueOf(obj));
+    }
+
+    /**
+     * Inserts the string into this character sequence.
+     * <p>
+     * The characters of the {@code String} argument are inserted, in
+     * order, into this sequence at the indicated offset, moving up any
+     * characters originally above that position and increasing the length
+     * of this sequence by the length of the argument. If
+     * {@code str} is {@code null}, then the four characters
+     * {@code "null"} are inserted into this sequence.
+     * <p>
+     * The character at index <i>k</i> in the new character sequence is
+     * equal to:
+     * <ul>
+     * <li>the character at index <i>k</i> in the old character sequence, if
+     * <i>k</i> is less than {@code offset}
+     * <li>the character at index <i>k</i>{@code -offset} in the
+     * argument {@code str}, if <i>k</i> is not less than
+     * {@code offset} but is less than {@code offset+str.length()}
+     * <li>the character at index <i>k</i>{@code -str.length()} in the
+     * old character sequence, if <i>k</i> is not less than
+     * {@code offset+str.length()}
+     * </ul><p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      str      a string.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, String str) {
+        if ((offset < 0) || (offset > length()))
+            throw new StringIndexOutOfBoundsException(offset);
+        if (str == null)
+            str = "null";
+        int len = str.length();
+        ensureCapacityInternal(count + len);
+        System.arraycopy(value, offset, value, offset + len, count - offset);
+        str.getChars(value, offset);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Inserts the string representation of the {@code char} array
+     * argument into this sequence.
+     * <p>
+     * The characters of the array argument are inserted into the
+     * contents of this sequence at the position indicated by
+     * {@code offset}. The length of this sequence increases by
+     * the length of the argument.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(char[])},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      str      a character array.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, char[] str) {
+        if ((offset < 0) || (offset > length()))
+            throw new StringIndexOutOfBoundsException(offset);
+        int len = str.length;
+        ensureCapacityInternal(count + len);
+        System.arraycopy(value, offset, value, offset + len, count - offset);
+        System.arraycopy(str, 0, value, offset, len);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Inserts the specified {@code CharSequence} into this sequence.
+     * <p>
+     * The characters of the {@code CharSequence} argument are inserted,
+     * in order, into this sequence at the indicated offset, moving up
+     * any characters originally above that position and increasing the length
+     * of this sequence by the length of the argument s.
+     * <p>
+     * The result of this method is exactly the same as if it were an
+     * invocation of this object's
+     * {@link #insert(int,CharSequence,int,int) insert}(dstOffset, s, 0, s.length())
+     * method.
+     *
+     * <p>If {@code s} is {@code null}, then the four characters
+     * {@code "null"} are inserted into this sequence.
+     *
+     * @param      dstOffset   the offset.
+     * @param      s the sequence to be inserted
+     * @return     a reference to this object.
+     * @throws     IndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int dstOffset, CharSequence s) {
+        if (s == null)
+            s = "null";
+        if (s instanceof String)
+            return this.insert(dstOffset, (String)s);
+        return this.insert(dstOffset, s, 0, s.length());
+    }
+
+    /**
+     * Inserts a subsequence of the specified {@code CharSequence} into
+     * this sequence.
+     * <p>
+     * The subsequence of the argument {@code s} specified by
+     * {@code start} and {@code end} are inserted,
+     * in order, into this sequence at the specified destination offset, moving
+     * up any characters originally above that position. The length of this
+     * sequence is increased by {@code end - start}.
+     * <p>
+     * The character at index <i>k</i> in this sequence becomes equal to:
+     * <ul>
+     * <li>the character at index <i>k</i> in this sequence, if
+     * <i>k</i> is less than {@code dstOffset}
+     * <li>the character at index <i>k</i>{@code +start-dstOffset} in
+     * the argument {@code s}, if <i>k</i> is greater than or equal to
+     * {@code dstOffset} but is less than {@code dstOffset+end-start}
+     * <li>the character at index <i>k</i>{@code -(end-start)} in this
+     * sequence, if <i>k</i> is greater than or equal to
+     * {@code dstOffset+end-start}
+     * </ul><p>
+     * The {@code dstOffset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     * <p>The start argument must be nonnegative, and not greater than
+     * {@code end}.
+     * <p>The end argument must be greater than or equal to
+     * {@code start}, and less than or equal to the length of s.
+     *
+     * <p>If {@code s} is {@code null}, then this method inserts
+     * characters as if the s parameter was a sequence containing the four
+     * characters {@code "null"}.
+     *
+     * @param      dstOffset   the offset in this sequence.
+     * @param      s       the sequence to be inserted.
+     * @param      start   the starting index of the subsequence to be inserted.
+     * @param      end     the end index of the subsequence to be inserted.
+     * @return     a reference to this object.
+     * @throws     IndexOutOfBoundsException  if {@code dstOffset}
+     *             is negative or greater than {@code this.length()}, or
+     *              {@code start} or {@code end} are negative, or
+     *              {@code start} is greater than {@code end} or
+     *              {@code end} is greater than {@code s.length()}
+     */
+     public AbstractStringBuilder insert(int dstOffset, CharSequence s,
+                                         int start, int end) {
+        if (s == null)
+            s = "null";
+        if ((dstOffset < 0) || (dstOffset > this.length()))
+            throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
+        if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
+            throw new IndexOutOfBoundsException(
+                "start " + start + ", end " + end + ", s.length() "
+                + s.length());
+        int len = end - start;
+        ensureCapacityInternal(count + len);
+        System.arraycopy(value, dstOffset, value, dstOffset + len,
+                         count - dstOffset);
+        for (int i=start; i<end; i++)
+            value[dstOffset++] = s.charAt(i);
+        count += len;
+        return this;
+    }
+
+    /**
+     * Inserts the string representation of the {@code boolean}
+     * argument into this sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(boolean)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      b        a {@code boolean}.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, boolean b) {
+        return insert(offset, String.valueOf(b));
+    }
+
+    /**
+     * Inserts the string representation of the {@code char}
+     * argument into this sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(char)},
+     * and the character in that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      c        a {@code char}.
+     * @return     a reference to this object.
+     * @throws     IndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, char c) {
+        ensureCapacityInternal(count + 1);
+        System.arraycopy(value, offset, value, offset + 1, count - offset);
+        value[offset] = c;
+        count += 1;
+        return this;
+    }
+
+    /**
+     * Inserts the string representation of the second {@code int}
+     * argument into this sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(int)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      i        an {@code int}.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, int i) {
+        return insert(offset, String.valueOf(i));
+    }
+
+    /**
+     * Inserts the string representation of the {@code long}
+     * argument into this sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(long)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      l        a {@code long}.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, long l) {
+        return insert(offset, String.valueOf(l));
+    }
+
+    /**
+     * Inserts the string representation of the {@code float}
+     * argument into this sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(float)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      f        a {@code float}.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, float f) {
+        return insert(offset, String.valueOf(f));
+    }
+
+    /**
+     * Inserts the string representation of the {@code double}
+     * argument into this sequence.
+     * <p>
+     * The overall effect is exactly as if the second argument were
+     * converted to a string by the method {@link String#valueOf(double)},
+     * and the characters of that string were then
+     * {@link #insert(int,String) inserted} into this character
+     * sequence at the indicated offset.
+     * <p>
+     * The {@code offset} argument must be greater than or equal to
+     * {@code 0}, and less than or equal to the {@linkplain #length() length}
+     * of this sequence.
+     *
+     * @param      offset   the offset.
+     * @param      d        a {@code double}.
+     * @return     a reference to this object.
+     * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
+     */
+    public AbstractStringBuilder insert(int offset, double d) {
+        return insert(offset, String.valueOf(d));
+    }
+
+    /**
+     * Returns the index within this string of the first occurrence of the
+     * specified substring. The integer returned is the smallest value
+     * <i>k</i> such that:
+     * <pre>{@code
+     * this.toString().startsWith(str, <i>k</i>)
+     * }</pre>
+     * is {@code true}.
+     *
+     * @param   str   any string.
+     * @return  if the string argument occurs as a substring within this
+     *          object, then the index of the first character of the first
+     *          such substring is returned; if it does not occur as a
+     *          substring, {@code -1} is returned.
+     */
+    public int indexOf(String str) {
+        return indexOf(str, 0);
+    }
+
+    /**
+     * Returns the index within this string of the first occurrence of the
+     * specified substring, starting at the specified index.  The integer
+     * returned is the smallest value {@code k} for which:
+     * <pre>{@code
+     *     k >= Math.min(fromIndex, this.length()) &&
+     *                   this.toString().startsWith(str, k)
+     * }</pre>
+     * If no such value of <i>k</i> exists, then -1 is returned.
+     *
+     * @param   str         the substring for which to search.
+     * @param   fromIndex   the index from which to start the search.
+     * @return  the index within this string of the first occurrence of the
+     *          specified substring, starting at the specified index.
+     */
+    public int indexOf(String str, int fromIndex) {
+        return String.indexOf(value, 0, count, str, fromIndex);
+    }
+
+    /**
+     * Returns the index within this string of the rightmost occurrence
+     * of the specified substring.  The rightmost empty string "" is
+     * considered to occur at the index value {@code this.length()}.
+     * The returned index is the largest value <i>k</i> such that
+     * <pre>{@code
+     * this.toString().startsWith(str, k)
+     * }</pre>
+     * is true.
+     *
+     * @param   str   the substring to search for.
+     * @return  if the string argument occurs one or more times as a substring
+     *          within this object, then the index of the first character of
+     *          the last such substring is returned. If it does not occur as
+     *          a substring, {@code -1} is returned.
+     */
+    public int lastIndexOf(String str) {
+        return lastIndexOf(str, count);
+    }
+
+    /**
+     * Returns the index within this string of the last occurrence of the
+     * specified substring. The integer returned is the largest value <i>k</i>
+     * such that:
+     * <pre>{@code
+     *     k <= Math.min(fromIndex, this.length()) &&
+     *                   this.toString().startsWith(str, k)
+     * }</pre>
+     * If no such value of <i>k</i> exists, then -1 is returned.
+     *
+     * @param   str         the substring to search for.
+     * @param   fromIndex   the index to start the search from.
+     * @return  the index within this sequence of the last occurrence of the
+     *          specified substring.
+     */
+    public int lastIndexOf(String str, int fromIndex) {
+        return String.lastIndexOf(value, 0, count, str, fromIndex);
+    }
+
+    /**
+     * Causes this character sequence to be replaced by the reverse of
+     * the sequence. If there are any surrogate pairs included in the
+     * sequence, these are treated as single characters for the
+     * reverse operation. Thus, the order of the high-low surrogates
+     * is never reversed.
+     *
+     * Let <i>n</i> be the character length of this character sequence
+     * (not the length in {@code char} values) just prior to
+     * execution of the {@code reverse} method. Then the
+     * character at index <i>k</i> in the new character sequence is
+     * equal to the character at index <i>n-k-1</i> in the old
+     * character sequence.
+     *
+     * <p>Note that the reverse operation may result in producing
+     * surrogate pairs that were unpaired low-surrogates and
+     * high-surrogates before the operation. For example, reversing
+     * "\u005CuDC00\u005CuD800" produces "\u005CuD800\u005CuDC00" which is
+     * a valid surrogate pair.
+     *
+     * @return  a reference to this object.
+     */
+    public AbstractStringBuilder reverse() {
+        boolean hasSurrogates = false;
+        int n = count - 1;
+        for (int j = (n-1) >> 1; j >= 0; j--) {
+            int k = n - j;
+            char cj = value[j];
+            char ck = value[k];
+            value[j] = ck;
+            value[k] = cj;
+            if (Character.isSurrogate(cj) ||
+                Character.isSurrogate(ck)) {
+                hasSurrogates = true;
+            }
+        }
+        if (hasSurrogates) {
+            reverseAllValidSurrogatePairs();
+        }
+        return this;
+    }
+
+    /** Outlined helper method for reverse() */
+    private void reverseAllValidSurrogatePairs() {
+        for (int i = 0; i < count - 1; i++) {
+            char c2 = value[i];
+            if (Character.isLowSurrogate(c2)) {
+                char c1 = value[i + 1];
+                if (Character.isHighSurrogate(c1)) {
+                    value[i++] = c1;
+                    value[i] = c2;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a string representing the data in this sequence.
+     * A new {@code String} object is allocated and initialized to
+     * contain the character sequence currently represented by this
+     * object. This {@code String} is then returned. Subsequent
+     * changes to this sequence do not affect the contents of the
+     * {@code String}.
+     *
+     * @return  a string representation of this sequence of characters.
+     */
+    @Override
+    public abstract String toString();
+
+    /**
+     * Needed by {@code String} for the contentEquals method.
+     */
+    final char[] getValue() {
+        return value;
+    }
+
+}
diff --git a/java/lang/AndroidHardcodedSystemProperties.java b/java/lang/AndroidHardcodedSystemProperties.java
new file mode 100644
index 0000000..931994f
--- /dev/null
+++ b/java/lang/AndroidHardcodedSystemProperties.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.util.Properties;
+
+/**
+ * A class encoding all hardcoded system property values on Android. A compiler may
+ * take advantage of these properties. Changing them at load-time (-D) or runtime
+ * may not have any effect.
+ *
+ * @hide
+ */
+public final class AndroidHardcodedSystemProperties {
+
+    // This value is shared with sun.misc.Version. It is defined here so that the compiler
+    // can use it.
+    public final static String JAVA_VERSION = "0";
+
+    final static String[][] STATIC_PROPERTIES = {
+        // None of these four are meaningful on Android, but these keys are guaranteed
+        // to be present for System.getProperty. For java.class.version, we use the maximum
+        // class file version that dx currently supports.
+        { "java.class.version", "50.0" },
+        { "java.version", JAVA_VERSION },
+        { "java.compiler", "" },
+        { "java.ext.dirs", "" },
+
+        { "java.specification.name", "Dalvik Core Library" },
+        { "java.specification.vendor", "The Android Project" },
+        { "java.specification.version", "0.9" },
+
+        { "java.vendor", "The Android Project" },
+        { "java.vendor.url", "http://www.android.com/" },
+        { "java.vm.name", "Dalvik" },
+        { "java.vm.specification.name", "Dalvik Virtual Machine Specification" },
+        { "java.vm.specification.vendor", "The Android Project" },
+        { "java.vm.specification.version", "0.9" },
+        { "java.vm.vendor", "The Android Project" },
+
+        { "java.vm.vendor.url", "http://www.android.com/" },
+
+        { "java.net.preferIPv6Addresses", "false" },
+
+        { "file.encoding", "UTF-8" },
+
+        { "file.separator", "/" },
+        { "line.separator", "\n" },
+        { "path.separator", ":" },
+
+        // Turn off ICU debugging. This allows compile-time initialization of a range of
+        // classes. b/28039175
+        { "ICUDebug", null },
+
+        // Hardcode DecimalFormat parsing flag to be default. b/27265238
+        { "android.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", null },
+        // Hardcode MessagePattern apostrophe mode to be default. b/27265238
+        { "android.icu.text.MessagePattern.ApostropheMode", null },
+
+        // Hardcode "sun.io.useCanonCaches" to use the default (off). b/28174137, b/62301183
+        { "sun.io.useCanonCaches", null },
+        { "sun.io.useCanonPrefixCache", null },
+
+        // Hardcode some http properties to use the default. b/28174137
+        { "http.keepAlive", null },
+        { "http.keepAliveDuration", null },
+        { "http.maxConnections", null },
+
+        // Turn off javax.net debugging. This allows compile-time initialization of a range
+        // of classes. b/28174137
+        { "javax.net.debug", null },
+
+        // Hardcode default value for AVA. b/28174137
+        { "com.sun.security.preserveOldDCEncoding", null },
+
+        // Hardcode default value for LogManager. b/28174137
+        { "java.util.logging.manager", null },
+    };
+}
diff --git a/java/lang/Appendable.annotated.java b/java/lang/Appendable.annotated.java
new file mode 100644
index 0000000..0ef58db
--- /dev/null
+++ b/java/lang/Appendable.annotated.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Appendable {
+
[email protected] public java.lang.Appendable append(@libcore.util.Nullable java.lang.CharSequence csq) throws java.io.IOException;
+
[email protected] public java.lang.Appendable append(@libcore.util.Nullable java.lang.CharSequence csq, int start, int end) throws java.io.IOException;
+
[email protected] public java.lang.Appendable append(char c) throws java.io.IOException;
+}
+
diff --git a/java/lang/Appendable.java b/java/lang/Appendable.java
new file mode 100644
index 0000000..46fd78d
--- /dev/null
+++ b/java/lang/Appendable.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.IOException;
+
+/**
+ * An object to which <tt>char</tt> sequences and values can be appended.  The
+ * <tt>Appendable</tt> interface must be implemented by any class whose
+ * instances are intended to receive formatted output from a {@link
+ * java.util.Formatter}.
+ *
+ * <p> The characters to be appended should be valid Unicode characters as
+ * described in <a href="Character.html#unicode">Unicode Character
+ * Representation</a>.  Note that supplementary characters may be composed of
+ * multiple 16-bit <tt>char</tt> values.
+ *
+ * <p> Appendables are not necessarily safe for multithreaded access.  Thread
+ * safety is the responsibility of classes that extend and implement this
+ * interface.
+ *
+ * <p> Since this interface may be implemented by existing classes
+ * with different styles of error handling there is no guarantee that
+ * errors will be propagated to the invoker.
+ *
+ * @since 1.5
+ */
+public interface Appendable {
+
+    /**
+     * Appends the specified character sequence to this <tt>Appendable</tt>.
+     *
+     * <p> Depending on which class implements the character sequence
+     * <tt>csq</tt>, the entire sequence may not be appended.  For
+     * instance, if <tt>csq</tt> is a {@link java.nio.CharBuffer} then
+     * the subsequence to append is defined by the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this Appendable.
+     *
+     * @return  A reference to this <tt>Appendable</tt>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    Appendable append(CharSequence csq) throws IOException;
+
+    /**
+     * Appends a subsequence of the specified character sequence to this
+     * <tt>Appendable</tt>.
+     *
+     * <p> An invocation of this method of the form <tt>out.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in
+     * exactly the same way as the invocation
+     *
+     * <pre>
+     *     out.append(csq.subSequence(start, end)) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @param  start
+     *         The index of the first character in the subsequence
+     *
+     * @param  end
+     *         The index of the character following the last character in the
+     *         subsequence
+     *
+     * @return  A reference to this <tt>Appendable</tt>
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    Appendable append(CharSequence csq, int start, int end) throws IOException;
+
+    /**
+     * Appends the specified character to this <tt>Appendable</tt>.
+     *
+     * @param  c
+     *         The character to append
+     *
+     * @return  A reference to this <tt>Appendable</tt>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    Appendable append(char c) throws IOException;
+}
diff --git a/java/lang/ArithmeticException.java b/java/lang/ArithmeticException.java
new file mode 100644
index 0000000..af00777
--- /dev/null
+++ b/java/lang/ArithmeticException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an exceptional arithmetic condition has occurred. For
+ * example, an integer "divide by zero" throws an
+ * instance of this class.
+ *
+ * {@code ArithmeticException} objects may be constructed by the
+ * virtual machine as if {@linkplain Throwable#Throwable(String,
+ * Throwable, boolean, boolean) suppression were disabled and/or the
+ * stack trace was not writable}.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public class ArithmeticException extends RuntimeException {
+    private static final long serialVersionUID = 2256477558314496007L;
+
+    /**
+     * Constructs an {@code ArithmeticException} with no detail
+     * message.
+     */
+    public ArithmeticException() {
+        super();
+    }
+
+    /**
+     * Constructs an {@code ArithmeticException} with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public ArithmeticException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/ArrayIndexOutOfBoundsException.java b/java/lang/ArrayIndexOutOfBoundsException.java
new file mode 100644
index 0000000..d07a4b2
--- /dev/null
+++ b/java/lang/ArrayIndexOutOfBoundsException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an array has been accessed with an
+ * illegal index. The index is either negative or greater than or
+ * equal to the size of the array.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
+    private static final long serialVersionUID = -5116101128118950844L;
+
+    /**
+     * Constructs an <code>ArrayIndexOutOfBoundsException</code> with no
+     * detail message.
+     */
+    public ArrayIndexOutOfBoundsException() {
+        super();
+    }
+
+    /**
+     * Constructs a new <code>ArrayIndexOutOfBoundsException</code>
+     * class with an argument indicating the illegal index.
+     *
+     * @param   index   the illegal index.
+     */
+    public ArrayIndexOutOfBoundsException(int index) {
+        super("Array index out of range: " + index);
+    }
+
+    /**
+     * Constructs an <code>ArrayIndexOutOfBoundsException</code> class
+     * with the specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public ArrayIndexOutOfBoundsException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/ArrayStoreException.java b/java/lang/ArrayStoreException.java
new file mode 100644
index 0000000..5ea0aa9
--- /dev/null
+++ b/java/lang/ArrayStoreException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an attempt has been made to store the
+ * wrong type of object into an array of objects. For example, the
+ * following code generates an <code>ArrayStoreException</code>:
+ * <blockquote><pre>
+ *     Object x[] = new String[3];
+ *     x[0] = new Integer(0);
+ * </pre></blockquote>
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class ArrayStoreException extends RuntimeException {
+    private static final long serialVersionUID = -4522193890499838241L;
+
+    /**
+     * Constructs an <code>ArrayStoreException</code> with no detail message.
+     */
+    public ArrayStoreException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>ArrayStoreException</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public ArrayStoreException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/AssertionError.java b/java/lang/AssertionError.java
new file mode 100644
index 0000000..a560af5
--- /dev/null
+++ b/java/lang/AssertionError.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an assertion has failed.
+ *
+ * <p>The seven one-argument public constructors provided by this
+ * class ensure that the assertion error returned by the invocation:
+ * <pre>
+ *     new AssertionError(<i>expression</i>)
+ * </pre>
+ * has as its detail message the <i>string conversion</i> of
+ * <i>expression</i> (as defined in section 15.18.1.1 of
+ * <cite>The Java&trade; Language Specification</cite>),
+ * regardless of the type of <i>expression</i>.
+ *
+ * @since   1.4
+ */
+public class AssertionError extends Error {
+    private static final long serialVersionUID = -5013299493970297370L;
+
+    /**
+     * Constructs an AssertionError with no detail message.
+     */
+    public AssertionError() {
+    }
+
+    /**
+     * This internal constructor does no processing on its string argument,
+     * even if it is a null reference.  The public constructors will
+     * never call this constructor with a null argument.
+     */
+    private AssertionError(String detailMessage) {
+        super(detailMessage);
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified object, which is converted to a string as
+     * defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *<p>
+     * If the specified object is an instance of {@code Throwable}, it
+     * becomes the <i>cause</i> of the newly constructed assertion error.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     * @see   Throwable#getCause()
+     */
+    public AssertionError(Object detailMessage) {
+        this(String.valueOf(detailMessage));
+        if (detailMessage instanceof Throwable)
+            initCause((Throwable) detailMessage);
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified <code>boolean</code>, which is converted to
+     * a string as defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     */
+    public AssertionError(boolean detailMessage) {
+        this(String.valueOf(detailMessage));
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified <code>char</code>, which is converted to a
+     * string as defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     */
+    public AssertionError(char detailMessage) {
+        this(String.valueOf(detailMessage));
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified <code>int</code>, which is converted to a
+     * string as defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     */
+    public AssertionError(int detailMessage) {
+        this(String.valueOf(detailMessage));
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified <code>long</code>, which is converted to a
+     * string as defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     */
+    public AssertionError(long detailMessage) {
+        this(String.valueOf(detailMessage));
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified <code>float</code>, which is converted to a
+     * string as defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     */
+    public AssertionError(float detailMessage) {
+        this(String.valueOf(detailMessage));
+    }
+
+    /**
+     * Constructs an AssertionError with its detail message derived
+     * from the specified <code>double</code>, which is converted to a
+     * string as defined in section 15.18.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param detailMessage value to be used in constructing detail message
+     */
+    public AssertionError(double detailMessage) {
+        this(String.valueOf(detailMessage));
+    }
+
+    /**
+     * Constructs a new {@code AssertionError} with the specified
+     * detail message and cause.
+     *
+     * <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this error's detail message.
+     *
+     * @param  message the detail message, may be {@code null}
+     * @param  cause the cause, may be {@code null}
+     *
+     * @since 1.7
+     */
+    public AssertionError(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/java/lang/AutoCloseable.java b/java/lang/AutoCloseable.java
new file mode 100644
index 0000000..135d9fe
--- /dev/null
+++ b/java/lang/AutoCloseable.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * An object that may hold resources (such as file or socket handles)
+ * until it is closed. The {@link #close()} method of an {@code AutoCloseable}
+ * object is called automatically when exiting a {@code
+ * try}-with-resources block for which the object has been declared in
+ * the resource specification header. This construction ensures prompt
+ * release, avoiding resource exhaustion exceptions and errors that
+ * may otherwise occur.
+ *
+ * @apiNote
+ * <p>It is possible, and in fact common, for a base class to
+ * implement AutoCloseable even though not all of its subclasses or
+ * instances will hold releasable resources.  For code that must operate
+ * in complete generality, or when it is known that the {@code AutoCloseable}
+ * instance requires resource release, it is recommended to use {@code
+ * try}-with-resources constructions. However, when using facilities such as
+ * {@link java.util.stream.Stream} that support both I/O-based and
+ * non-I/O-based forms, {@code try}-with-resources blocks are in
+ * general unnecessary when using non-I/O-based forms.
+ *
+ * @author Josh Bloch
+ * @since 1.7
+ */
+public interface AutoCloseable {
+    /**
+     * Closes this resource, relinquishing any underlying resources.
+     * This method is invoked automatically on objects managed by the
+     * {@code try}-with-resources statement.
+     *
+     * <p>While this interface method is declared to throw {@code
+     * Exception}, implementers are <em>strongly</em> encouraged to
+     * declare concrete implementations of the {@code close} method to
+     * throw more specific exceptions, or to throw no exception at all
+     * if the close operation cannot fail.
+     *
+     * <p> Cases where the close operation may fail require careful
+     * attention by implementers. It is strongly advised to relinquish
+     * the underlying resources and to internally <em>mark</em> the
+     * resource as closed, prior to throwing the exception. The {@code
+     * close} method is unlikely to be invoked more than once and so
+     * this ensures that the resources are released in a timely manner.
+     * Furthermore it reduces problems that could arise when the resource
+     * wraps, or is wrapped, by another resource.
+     *
+     * <p><em>Implementers of this interface are also strongly advised
+     * to not have the {@code close} method throw {@link
+     * InterruptedException}.</em>
+     *
+     * This exception interacts with a thread's interrupted status,
+     * and runtime misbehavior is likely to occur if an {@code
+     * InterruptedException} is {@linkplain Throwable#addSuppressed
+     * suppressed}.
+     *
+     * More generally, if it would cause problems for an
+     * exception to be suppressed, the {@code AutoCloseable.close}
+     * method should not throw it.
+     *
+     * <p>Note that unlike the {@link java.io.Closeable#close close}
+     * method of {@link java.io.Closeable}, this {@code close} method
+     * is <em>not</em> required to be idempotent.  In other words,
+     * calling this {@code close} method more than once may have some
+     * visible side effect, unlike {@code Closeable.close} which is
+     * required to have no effect if called more than once.
+     *
+     * However, implementers of this interface are strongly encouraged
+     * to make their {@code close} methods idempotent.
+     *
+     * @throws Exception if this resource cannot be closed
+     */
+    void close() throws Exception;
+}
diff --git a/java/lang/Boolean.annotated.java b/java/lang/Boolean.annotated.java
new file mode 100644
index 0000000..8022814
--- /dev/null
+++ b/java/lang/Boolean.annotated.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Boolean implements java.io.Serializable, java.lang.Comparable<java.lang.Boolean> {
+
+public Boolean(boolean value) { throw new RuntimeException("Stub!"); }
+
+public Boolean(@libcore.util.Nullable java.lang.String s) { throw new RuntimeException("Stub!"); }
+
+public static boolean parseBoolean(@libcore.util.Nullable java.lang.String s) { throw new RuntimeException("Stub!"); }
+
+public boolean booleanValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Boolean valueOf(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Boolean valueOf(@libcore.util.Nullable java.lang.String s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(boolean value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static boolean getBoolean(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.lang.Boolean b) { throw new RuntimeException("Stub!"); }
+
+public static int compare(boolean x, boolean y) { throw new RuntimeException("Stub!"); }
+
+public static boolean logicalAnd(boolean a, boolean b) { throw new RuntimeException("Stub!"); }
+
+public static boolean logicalOr(boolean a, boolean b) { throw new RuntimeException("Stub!"); }
+
+public static boolean logicalXor(boolean a, boolean b) { throw new RuntimeException("Stub!"); }
+
+public static final java.lang.Boolean FALSE;
+static { FALSE = null; }
+
+public static final java.lang.Boolean TRUE;
+static { TRUE = null; }
+
+public static final java.lang.Class<java.lang.Boolean> TYPE;
+static { TYPE = null; }
+}
diff --git a/java/lang/Boolean.java b/java/lang/Boolean.java
new file mode 100644
index 0000000..a9293ba
--- /dev/null
+++ b/java/lang/Boolean.java
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * The Boolean class wraps a value of the primitive type
+ * {@code boolean} in an object. An object of type
+ * {@code Boolean} contains a single field whose type is
+ * {@code boolean}.
+ * <p>
+ * In addition, this class provides many methods for
+ * converting a {@code boolean} to a {@code String} and a
+ * {@code String} to a {@code boolean}, as well as other
+ * constants and methods useful when dealing with a
+ * {@code boolean}.
+ *
+ * @author  Arthur van Hoff
+ * @since   JDK1.0
+ */
+public final class Boolean implements java.io.Serializable,
+                                      Comparable<Boolean>
+{
+    /**
+     * The {@code Boolean} object corresponding to the primitive
+     * value {@code true}.
+     */
+    public static final Boolean TRUE = new Boolean(true);
+
+    /**
+     * The {@code Boolean} object corresponding to the primitive
+     * value {@code false}.
+     */
+    public static final Boolean FALSE = new Boolean(false);
+
+    /**
+     * The Class object representing the primitive type boolean.
+     *
+     * @since   JDK1.1
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");
+
+    /**
+     * The value of the Boolean.
+     *
+     * @serial
+     */
+    private final boolean value;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -3665804199014368530L;
+
+    /**
+     * Allocates a {@code Boolean} object representing the
+     * {@code value} argument.
+     *
+     * <p><b>Note: It is rarely appropriate to use this constructor.
+     * Unless a <i>new</i> instance is required, the static factory
+     * {@link #valueOf(boolean)} is generally a better choice. It is
+     * likely to yield significantly better space and time performance.</b>
+     *
+     * @param   value   the value of the {@code Boolean}.
+     */
+    public Boolean(boolean value) {
+        this.value = value;
+    }
+
+    /**
+     * Allocates a {@code Boolean} object representing the value
+     * {@code true} if the string argument is not {@code null}
+     * and is equal, ignoring case, to the string {@code "true"}.
+     * Otherwise, allocate a {@code Boolean} object representing the
+     * value {@code false}. Examples:<p>
+     * {@code new Boolean("True")} produces a {@code Boolean} object
+     * that represents {@code true}.<br>
+     * {@code new Boolean("yes")} produces a {@code Boolean} object
+     * that represents {@code false}.
+     *
+     * @param   s   the string to be converted to a {@code Boolean}.
+     */
+    public Boolean(String s) {
+        this(parseBoolean(s));
+    }
+
+    /**
+     * Parses the string argument as a boolean.  The {@code boolean}
+     * returned represents the value {@code true} if the string argument
+     * is not {@code null} and is equal, ignoring case, to the string
+     * {@code "true"}. <p>
+     * Example: {@code Boolean.parseBoolean("True")} returns {@code true}.<br>
+     * Example: {@code Boolean.parseBoolean("yes")} returns {@code false}.
+     *
+     * @param      s   the {@code String} containing the boolean
+     *                 representation to be parsed
+     * @return     the boolean represented by the string argument
+     * @since 1.5
+     */
+    public static boolean parseBoolean(String s) {
+        return ((s != null) && s.equalsIgnoreCase("true"));
+    }
+
+    /**
+     * Returns the value of this {@code Boolean} object as a boolean
+     * primitive.
+     *
+     * @return  the primitive {@code boolean} value of this object.
+     */
+    public boolean booleanValue() {
+        return value;
+    }
+
+    /**
+     * Returns a {@code Boolean} instance representing the specified
+     * {@code boolean} value.  If the specified {@code boolean} value
+     * is {@code true}, this method returns {@code Boolean.TRUE};
+     * if it is {@code false}, this method returns {@code Boolean.FALSE}.
+     * If a new {@code Boolean} instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Boolean(boolean)}, as this method is likely to yield
+     * significantly better space and time performance.
+     *
+     * @param  b a boolean value.
+     * @return a {@code Boolean} instance representing {@code b}.
+     * @since  1.4
+     */
+    public static Boolean valueOf(boolean b) {
+        return (b ? TRUE : FALSE);
+    }
+
+    /**
+     * Returns a {@code Boolean} with a value represented by the
+     * specified string.  The {@code Boolean} returned represents a
+     * true value if the string argument is not {@code null}
+     * and is equal, ignoring case, to the string {@code "true"}.
+     *
+     * @param   s   a string.
+     * @return  the {@code Boolean} value represented by the string.
+     */
+    public static Boolean valueOf(String s) {
+        return parseBoolean(s) ? TRUE : FALSE;
+    }
+
+    /**
+     * Returns a {@code String} object representing the specified
+     * boolean.  If the specified boolean is {@code true}, then
+     * the string {@code "true"} will be returned, otherwise the
+     * string {@code "false"} will be returned.
+     *
+     * @param b the boolean to be converted
+     * @return the string representation of the specified {@code boolean}
+     * @since 1.4
+     */
+    public static String toString(boolean b) {
+        return b ? "true" : "false";
+    }
+
+    /**
+     * Returns a {@code String} object representing this Boolean's
+     * value.  If this object represents the value {@code true},
+     * a string equal to {@code "true"} is returned. Otherwise, a
+     * string equal to {@code "false"} is returned.
+     *
+     * @return  a string representation of this object.
+     */
+    public String toString() {
+        return value ? "true" : "false";
+    }
+
+    /**
+     * Returns a hash code for this {@code Boolean} object.
+     *
+     * @return  the integer {@code 1231} if this object represents
+     * {@code true}; returns the integer {@code 1237} if this
+     * object represents {@code false}.
+     */
+    @Override
+    public int hashCode() {
+        return Boolean.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code boolean} value; compatible with
+     * {@code Boolean.hashCode()}.
+     *
+     * @param value the value to hash
+     * @return a hash code value for a {@code boolean} value.
+     * @since 1.8
+     */
+    public static int hashCode(boolean value) {
+        return value ? 1231 : 1237;
+    }
+
+   /**
+     * Returns {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Boolean} object that
+     * represents the same {@code boolean} value as this object.
+     *
+     * @param   obj   the object to compare with.
+     * @return  {@code true} if the Boolean objects represent the
+     *          same value; {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Boolean) {
+            return value == ((Boolean)obj).booleanValue();
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if and only if the system property
+     * named by the argument exists and is equal to the string
+     * {@code "true"}. (Beginning with version 1.0.2 of the
+     * Java<small><sup>TM</sup></small> platform, the test of
+     * this string is case insensitive.) A system property is accessible
+     * through {@code getProperty}, a method defined by the
+     * {@code System} class.
+     * <p>
+     * If there is no property with the specified name, or if the specified
+     * name is empty or null, then {@code false} is returned.
+     *
+     * @param   name   the system property name.
+     * @return  the {@code boolean} value of the system property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     java.lang.System#getProperty(java.lang.String)
+     * @see     java.lang.System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static boolean getBoolean(String name) {
+        boolean result = false;
+        try {
+            result = parseBoolean(System.getProperty(name));
+        } catch (IllegalArgumentException | NullPointerException e) {
+        }
+        return result;
+    }
+
+    /**
+     * Compares this {@code Boolean} instance with another.
+     *
+     * @param   b the {@code Boolean} instance to be compared
+     * @return  zero if this object represents the same boolean value as the
+     *          argument; a positive value if this object represents true
+     *          and the argument represents false; and a negative value if
+     *          this object represents false and the argument represents true
+     * @throws  NullPointerException if the argument is {@code null}
+     * @see     Comparable
+     * @since  1.5
+     */
+    public int compareTo(Boolean b) {
+        return compare(this.value, b.value);
+    }
+
+    /**
+     * Compares two {@code boolean} values.
+     * The value returned is identical to what would be returned by:
+     * <pre>
+     *    Boolean.valueOf(x).compareTo(Boolean.valueOf(y))
+     * </pre>
+     *
+     * @param  x the first {@code boolean} to compare
+     * @param  y the second {@code boolean} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code !x && y}; and
+     *         a value greater than {@code 0} if {@code x && !y}
+     * @since 1.7
+     */
+    public static int compare(boolean x, boolean y) {
+        return (x == y) ? 0 : (x ? 1 : -1);
+    }
+
+    /**
+     * Returns the result of applying the logical AND operator to the
+     * specified {@code boolean} operands.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the logical AND of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static boolean logicalAnd(boolean a, boolean b) {
+        return a && b;
+    }
+
+    /**
+     * Returns the result of applying the logical OR operator to the
+     * specified {@code boolean} operands.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the logical OR of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static boolean logicalOr(boolean a, boolean b) {
+        return a || b;
+    }
+
+    /**
+     * Returns the result of applying the logical XOR operator to the
+     * specified {@code boolean} operands.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return  the logical XOR of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static boolean logicalXor(boolean a, boolean b) {
+        return a ^ b;
+    }
+}
diff --git a/java/lang/BootstrapMethodError.java b/java/lang/BootstrapMethodError.java
new file mode 100644
index 0000000..a1509a0
--- /dev/null
+++ b/java/lang/BootstrapMethodError.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an {@code invokedynamic} instruction has
+ * failed to find its bootstrap method,
+ * or the bootstrap method has failed to provide a
+ * {@linkplain java.lang.invoke.CallSite call site} with a {@linkplain java.lang.invoke.CallSite#getTarget target}
+ * of the correct {@linkplain java.lang.invoke.MethodHandle#type method type}.
+ *
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class BootstrapMethodError extends LinkageError {
+    private static final long serialVersionUID = 292L;
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with no detail message.
+     */
+    public BootstrapMethodError() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public BootstrapMethodError(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with the specified
+     * detail message and cause.
+     *
+     * @param s the detail message.
+     * @param cause the cause, may be {@code null}.
+     */
+    public BootstrapMethodError(String s, Throwable cause) {
+        super(s, cause);
+    }
+
+    /**
+     * Constructs a {@code BootstrapMethodError} with the specified
+     * cause.
+     *
+     * @param cause the cause, may be {@code null}.
+     */
+    public BootstrapMethodError(Throwable cause) {
+        // cf. Throwable(Throwable cause) constructor.
+        super(cause == null ? null : cause.toString());
+        initCause(cause);
+    }
+}
diff --git a/java/lang/Byte.annotated.java b/java/lang/Byte.annotated.java
new file mode 100644
index 0000000..b64ca1e
--- /dev/null
+++ b/java/lang/Byte.annotated.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Byte extends java.lang.Number implements java.lang.Comparable<java.lang.Byte> {
+
+public Byte(byte value) { throw new RuntimeException("Stub!"); }
+
+public Byte(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(byte b) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Byte valueOf(byte b) { throw new RuntimeException("Stub!"); }
+
+public static byte parseByte(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static byte parseByte(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Byte valueOf(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Byte valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Byte decode(@libcore.util.NonNull java.lang.String nm) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public byte byteValue() { throw new RuntimeException("Stub!"); }
+
+public short shortValue() { throw new RuntimeException("Stub!"); }
+
+public int intValue() { throw new RuntimeException("Stub!"); }
+
+public long longValue() { throw new RuntimeException("Stub!"); }
+
+public float floatValue() { throw new RuntimeException("Stub!"); }
+
+public double doubleValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(byte value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.lang.Byte anotherByte) { throw new RuntimeException("Stub!"); }
+
+public static int compare(byte x, byte y) { throw new RuntimeException("Stub!"); }
+
+public static int toUnsignedInt(byte x) { throw new RuntimeException("Stub!"); }
+
+public static long toUnsignedLong(byte x) { throw new RuntimeException("Stub!"); }
+
+public static final int BYTES = 1; // 0x1
+
+public static final byte MAX_VALUE = 127; // 0x7f
+
+public static final byte MIN_VALUE = -128; // 0xffffff80
+
+public static final int SIZE = 8; // 0x8
+
+public static final java.lang.Class<java.lang.Byte> TYPE;
+static { TYPE = null; }
+}
+
diff --git a/java/lang/Byte.java b/java/lang/Byte.java
new file mode 100644
index 0000000..deb4ecb
--- /dev/null
+++ b/java/lang/Byte.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import libcore.util.HexEncoding;
+
+/**
+ *
+ * The {@code Byte} class wraps a value of primitive type {@code byte}
+ * in an object.  An object of type {@code Byte} contains a single
+ * field whose type is {@code byte}.
+ *
+ * <p>In addition, this class provides several methods for converting
+ * a {@code byte} to a {@code String} and a {@code String} to a {@code
+ * byte}, as well as other constants and methods useful when dealing
+ * with a {@code byte}.
+ *
+ * @author  Nakul Saraiya
+ * @author  Joseph D. Darcy
+ * @see     java.lang.Number
+ * @since   JDK1.1
+ */
+public final class Byte extends Number implements Comparable<Byte> {
+
+    /**
+     * A constant holding the minimum value a {@code byte} can
+     * have, -2<sup>7</sup>.
+     */
+    public static final byte   MIN_VALUE = -128;
+
+    /**
+     * A constant holding the maximum value a {@code byte} can
+     * have, 2<sup>7</sup>-1.
+     */
+    public static final byte   MAX_VALUE = 127;
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code byte}.
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Byte>     TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
+
+    /**
+     * Returns a new {@code String} object representing the
+     * specified {@code byte}. The radix is assumed to be 10.
+     *
+     * @param b the {@code byte} to be converted
+     * @return the string representation of the specified {@code byte}
+     * @see java.lang.Integer#toString(int)
+     */
+    public static String toString(byte b) {
+        return Integer.toString((int)b, 10);
+    }
+
+    private static class ByteCache {
+        private ByteCache(){}
+
+        static final Byte cache[] = new Byte[-(-128) + 127 + 1];
+
+        static {
+            for(int i = 0; i < cache.length; i++)
+                cache[i] = new Byte((byte)(i - 128));
+        }
+    }
+
+    /**
+     * Returns a {@code Byte} instance representing the specified
+     * {@code byte} value.
+     * If a new {@code Byte} instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Byte(byte)}, as this method is likely to yield
+     * significantly better space and time performance since
+     * all byte values are cached.
+     *
+     * @param  b a byte value.
+     * @return a {@code Byte} instance representing {@code b}.
+     * @since  1.5
+     */
+    public static Byte valueOf(byte b) {
+        final int offset = 128;
+        return ByteCache.cache[(int)b + offset];
+    }
+
+    /**
+     * Parses the string argument as a signed {@code byte} in the
+     * radix specified by the second argument. The characters in the
+     * string must all be digits, of the specified radix (as
+     * determined by whether {@link java.lang.Character#digit(char,
+     * int)} returns a nonnegative value) except that the first
+     * character may be an ASCII minus sign {@code '-'}
+     * ({@code '\u005Cu002D'}) to indicate a negative value or an
+     * ASCII plus sign {@code '+'} ({@code '\u005Cu002B'}) to
+     * indicate a positive value.  The resulting {@code byte} value is
+     * returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li> The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li> The radix is either smaller than {@link
+     * java.lang.Character#MIN_RADIX} or larger than {@link
+     * java.lang.Character#MAX_RADIX}.
+     *
+     * <li> Any character of the string is not a digit of the
+     * specified radix, except that the first character may be a minus
+     * sign {@code '-'} ({@code '\u005Cu002D'}) or plus sign
+     * {@code '+'} ({@code '\u005Cu002B'}) provided that the
+     * string is longer than length 1.
+     *
+     * <li> The value represented by the string is not a value of type
+     * {@code byte}.
+     * </ul>
+     *
+     * @param s         the {@code String} containing the
+     *                  {@code byte}
+     *                  representation to be parsed
+     * @param radix     the radix to be used while parsing {@code s}
+     * @return          the {@code byte} value represented by the string
+     *                   argument in the specified radix
+     * @throws          NumberFormatException If the string does
+     *                  not contain a parsable {@code byte}.
+     */
+    public static byte parseByte(String s, int radix)
+        throws NumberFormatException {
+        int i = Integer.parseInt(s, radix);
+        if (i < MIN_VALUE || i > MAX_VALUE)
+            throw new NumberFormatException(
+                "Value out of range. Value:\"" + s + "\" Radix:" + radix);
+        return (byte)i;
+    }
+
+    /**
+     * Parses the string argument as a signed decimal {@code
+     * byte}. The characters in the string must all be decimal digits,
+     * except that the first character may be an ASCII minus sign
+     * {@code '-'} ({@code '\u005Cu002D'}) to indicate a negative
+     * value or an ASCII plus sign {@code '+'}
+     * ({@code '\u005Cu002B'}) to indicate a positive value. The
+     * resulting {@code byte} value is returned, exactly as if the
+     * argument and the radix 10 were given as arguments to the {@link
+     * #parseByte(java.lang.String, int)} method.
+     *
+     * @param s         a {@code String} containing the
+     *                  {@code byte} representation to be parsed
+     * @return          the {@code byte} value represented by the
+     *                  argument in decimal
+     * @throws          NumberFormatException if the string does not
+     *                  contain a parsable {@code byte}.
+     */
+    public static byte parseByte(String s) throws NumberFormatException {
+        return parseByte(s, 10);
+    }
+
+    /**
+     * Returns a {@code Byte} object holding the value
+     * extracted from the specified {@code String} when parsed
+     * with the radix given by the second argument. The first argument
+     * is interpreted as representing a signed {@code byte} in
+     * the radix specified by the second argument, exactly as if the
+     * argument were given to the {@link #parseByte(java.lang.String,
+     * int)} method. The result is a {@code Byte} object that
+     * represents the {@code byte} value specified by the string.
+     *
+     * <p> In other words, this method returns a {@code Byte} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     * {@code new Byte(Byte.parseByte(s, radix))}
+     * </blockquote>
+     *
+     * @param s         the string to be parsed
+     * @param radix     the radix to be used in interpreting {@code s}
+     * @return          a {@code Byte} object holding the value
+     *                  represented by the string argument in the
+     *                  specified radix.
+     * @throws          NumberFormatException If the {@code String} does
+     *                  not contain a parsable {@code byte}.
+     */
+    public static Byte valueOf(String s, int radix)
+        throws NumberFormatException {
+        return valueOf(parseByte(s, radix));
+    }
+
+    /**
+     * Returns a {@code Byte} object holding the value
+     * given by the specified {@code String}. The argument is
+     * interpreted as representing a signed decimal {@code byte},
+     * exactly as if the argument were given to the {@link
+     * #parseByte(java.lang.String)} method. The result is a
+     * {@code Byte} object that represents the {@code byte}
+     * value specified by the string.
+     *
+     * <p> In other words, this method returns a {@code Byte} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     * {@code new Byte(Byte.parseByte(s))}
+     * </blockquote>
+     *
+     * @param s         the string to be parsed
+     * @return          a {@code Byte} object holding the value
+     *                  represented by the string argument
+     * @throws          NumberFormatException If the {@code String} does
+     *                  not contain a parsable {@code byte}.
+     */
+    public static Byte valueOf(String s) throws NumberFormatException {
+        return valueOf(s, 10);
+    }
+
+    /**
+     * Decodes a {@code String} into a {@code Byte}.
+     * Accepts decimal, hexadecimal, and octal numbers given by
+     * the following grammar:
+     *
+     * <blockquote>
+     * <dl>
+     * <dt><i>DecodableString:</i>
+     * <dd><i>Sign<sub>opt</sub> DecimalNumeral</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0x} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0X} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code #} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0} <i>OctalDigits</i>
+     *
+     * <dt><i>Sign:</i>
+     * <dd>{@code -}
+     * <dd>{@code +}
+     * </dl>
+     * </blockquote>
+     *
+     * <i>DecimalNumeral</i>, <i>HexDigits</i>, and <i>OctalDigits</i>
+     * are as defined in section 3.10.1 of
+     * <cite>The Java&trade; Language Specification</cite>,
+     * except that underscores are not accepted between digits.
+     *
+     * <p>The sequence of characters following an optional
+     * sign and/or radix specifier ("{@code 0x}", "{@code 0X}",
+     * "{@code #}", or leading zero) is parsed as by the {@code
+     * Byte.parseByte} method with the indicated radix (10, 16, or 8).
+     * This sequence of characters must represent a positive value or
+     * a {@link NumberFormatException} will be thrown.  The result is
+     * negated if first character of the specified {@code String} is
+     * the minus sign.  No whitespace characters are permitted in the
+     * {@code String}.
+     *
+     * @param     nm the {@code String} to decode.
+     * @return   a {@code Byte} object holding the {@code byte}
+     *          value represented by {@code nm}
+     * @throws  NumberFormatException  if the {@code String} does not
+     *            contain a parsable {@code byte}.
+     * @see java.lang.Byte#parseByte(java.lang.String, int)
+     */
+    public static Byte decode(String nm) throws NumberFormatException {
+        int i = Integer.decode(nm);
+        if (i < MIN_VALUE || i > MAX_VALUE)
+            throw new NumberFormatException(
+                    "Value " + i + " out of range from input " + nm);
+        return valueOf((byte)i);
+    }
+
+    /**
+     * The value of the {@code Byte}.
+     *
+     * @serial
+     */
+    private final byte value;
+
+    /**
+     * Constructs a newly allocated {@code Byte} object that
+     * represents the specified {@code byte} value.
+     *
+     * @param value     the value to be represented by the
+     *                  {@code Byte}.
+     */
+    public Byte(byte value) {
+        this.value = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Byte} object that
+     * represents the {@code byte} value indicated by the
+     * {@code String} parameter. The string is converted to a
+     * {@code byte} value in exactly the manner used by the
+     * {@code parseByte} method for radix 10.
+     *
+     * @param s         the {@code String} to be converted to a
+     *                  {@code Byte}
+     * @throws           NumberFormatException If the {@code String}
+     *                  does not contain a parsable {@code byte}.
+     * @see        java.lang.Byte#parseByte(java.lang.String, int)
+     */
+    public Byte(String s) throws NumberFormatException {
+        this.value = parseByte(s, 10);
+    }
+
+    /**
+     * Returns the value of this {@code Byte} as a
+     * {@code byte}.
+     */
+    public byte byteValue() {
+        return value;
+    }
+
+    /**
+     * Returns the value of this {@code Byte} as a {@code short} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public short shortValue() {
+        return (short)value;
+    }
+
+    /**
+     * Returns the value of this {@code Byte} as an {@code int} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public int intValue() {
+        return (int)value;
+    }
+
+    /**
+     * Returns the value of this {@code Byte} as a {@code long} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public long longValue() {
+        return (long)value;
+    }
+
+    /**
+     * Returns the value of this {@code Byte} as a {@code float} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)value;
+    }
+
+    /**
+     * Returns the value of this {@code Byte} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)value;
+    }
+
+    /**
+     * Returns a {@code String} object representing this
+     * {@code Byte}'s value.  The value is converted to signed
+     * decimal representation and returned as a string, exactly as if
+     * the {@code byte} value were given as an argument to the
+     * {@link java.lang.Byte#toString(byte)} method.
+     *
+     * @return  a string representation of the value of this object in
+     *          base&nbsp;10.
+     */
+    public String toString() {
+        return Integer.toString((int)value);
+    }
+
+    /**
+     * Returns a hash code for this {@code Byte}; equal to the result
+     * of invoking {@code intValue()}.
+     *
+     * @return a hash code value for this {@code Byte}
+     */
+    @Override
+    public int hashCode() {
+        return Byte.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code byte} value; compatible with
+     * {@code Byte.hashCode()}.
+     *
+     * @param value the value to hash
+     * @return a hash code value for a {@code byte} value.
+     * @since 1.8
+     */
+    public static int hashCode(byte value) {
+        return (int)value;
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is
+     * {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Byte} object that
+     * contains the same {@code byte} value as this object.
+     *
+     * @param obj       the object to compare with
+     * @return          {@code true} if the objects are the same;
+     *                  {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Byte) {
+            return value == ((Byte)obj).byteValue();
+        }
+        return false;
+    }
+
+    /**
+     * Compares two {@code Byte} objects numerically.
+     *
+     * @param   anotherByte   the {@code Byte} to be compared.
+     * @return  the value {@code 0} if this {@code Byte} is
+     *          equal to the argument {@code Byte}; a value less than
+     *          {@code 0} if this {@code Byte} is numerically less
+     *          than the argument {@code Byte}; and a value greater than
+     *           {@code 0} if this {@code Byte} is numerically
+     *           greater than the argument {@code Byte} (signed
+     *           comparison).
+     * @since   1.2
+     */
+    public int compareTo(Byte anotherByte) {
+        return compare(this.value, anotherByte.value);
+    }
+
+    /**
+     * Compares two {@code byte} values numerically.
+     * The value returned is identical to what would be returned by:
+     * <pre>
+     *    Byte.valueOf(x).compareTo(Byte.valueOf(y))
+     * </pre>
+     *
+     * @param  x the first {@code byte} to compare
+     * @param  y the second {@code byte} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 1.7
+     */
+    public static int compare(byte x, byte y) {
+        return x - y;
+    }
+
+    /**
+     * Converts the argument to an {@code int} by an unsigned
+     * conversion.  In an unsigned conversion to an {@code int}, the
+     * high-order 24 bits of the {@code int} are zero and the
+     * low-order 8 bits are equal to the bits of the {@code byte} argument.
+     *
+     * Consequently, zero and positive {@code byte} values are mapped
+     * to a numerically equal {@code int} value and negative {@code
+     * byte} values are mapped to an {@code int} value equal to the
+     * input plus 2<sup>8</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code int}
+     * @return the argument converted to {@code int} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static int toUnsignedInt(byte x) {
+        return ((int) x) & 0xff;
+    }
+
+    /**
+     * Converts the argument to a {@code long} by an unsigned
+     * conversion.  In an unsigned conversion to a {@code long}, the
+     * high-order 56 bits of the {@code long} are zero and the
+     * low-order 8 bits are equal to the bits of the {@code byte} argument.
+     *
+     * Consequently, zero and positive {@code byte} values are mapped
+     * to a numerically equal {@code long} value and negative {@code
+     * byte} values are mapped to a {@code long} value equal to the
+     * input plus 2<sup>8</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code long}
+     * @return the argument converted to {@code long} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static long toUnsignedLong(byte x) {
+        return ((long) x) & 0xffL;
+    }
+
+
+    /**
+     * The number of bits used to represent a {@code byte} value in two's
+     * complement binary form.
+     *
+     * @since 1.5
+     */
+    public static final int SIZE = 8;
+
+    /**
+     * The number of bytes used to represent a {@code byte} value in two's
+     * complement binary form.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /** use serialVersionUID from JDK 1.1. for interoperability */
+    private static final long serialVersionUID = -7183698231559129828L;
+
+    // BEGIN Android-added: toHexString() for internal use.
+    /**
+     * @hide
+     */
+    public static String toHexString(byte b, boolean upperCase) {
+        // This method currently retained because it is marked @UnsupportedAppUsage.
+        return HexEncoding.encodeToString(b, upperCase);
+    }
+    // END Android-added: toHexString() for internal use.
+}
diff --git a/java/lang/CaseMapper.java b/java/lang/CaseMapper.java
new file mode 100644
index 0000000..04eef09
--- /dev/null
+++ b/java/lang/CaseMapper.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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 android.icu.text.Transliterator;
+import com.android.icu.util.CaseMapperNative;
+import java.util.Locale;
+
+/**
+ * Performs case operations as described by http://unicode.org/reports/tr21/tr21-5.html.
+ */
+class CaseMapper {
+    private static final char[] upperValues = "SS\u0000\u02bcN\u0000J\u030c\u0000\u0399\u0308\u0301\u03a5\u0308\u0301\u0535\u0552\u0000H\u0331\u0000T\u0308\u0000W\u030a\u0000Y\u030a\u0000A\u02be\u0000\u03a5\u0313\u0000\u03a5\u0313\u0300\u03a5\u0313\u0301\u03a5\u0313\u0342\u1f08\u0399\u0000\u1f09\u0399\u0000\u1f0a\u0399\u0000\u1f0b\u0399\u0000\u1f0c\u0399\u0000\u1f0d\u0399\u0000\u1f0e\u0399\u0000\u1f0f\u0399\u0000\u1f08\u0399\u0000\u1f09\u0399\u0000\u1f0a\u0399\u0000\u1f0b\u0399\u0000\u1f0c\u0399\u0000\u1f0d\u0399\u0000\u1f0e\u0399\u0000\u1f0f\u0399\u0000\u1f28\u0399\u0000\u1f29\u0399\u0000\u1f2a\u0399\u0000\u1f2b\u0399\u0000\u1f2c\u0399\u0000\u1f2d\u0399\u0000\u1f2e\u0399\u0000\u1f2f\u0399\u0000\u1f28\u0399\u0000\u1f29\u0399\u0000\u1f2a\u0399\u0000\u1f2b\u0399\u0000\u1f2c\u0399\u0000\u1f2d\u0399\u0000\u1f2e\u0399\u0000\u1f2f\u0399\u0000\u1f68\u0399\u0000\u1f69\u0399\u0000\u1f6a\u0399\u0000\u1f6b\u0399\u0000\u1f6c\u0399\u0000\u1f6d\u0399\u0000\u1f6e\u0399\u0000\u1f6f\u0399\u0000\u1f68\u0399\u0000\u1f69\u0399\u0000\u1f6a\u0399\u0000\u1f6b\u0399\u0000\u1f6c\u0399\u0000\u1f6d\u0399\u0000\u1f6e\u0399\u0000\u1f6f\u0399\u0000\u1fba\u0399\u0000\u0391\u0399\u0000\u0386\u0399\u0000\u0391\u0342\u0000\u0391\u0342\u0399\u0391\u0399\u0000\u1fca\u0399\u0000\u0397\u0399\u0000\u0389\u0399\u0000\u0397\u0342\u0000\u0397\u0342\u0399\u0397\u0399\u0000\u0399\u0308\u0300\u0399\u0308\u0301\u0399\u0342\u0000\u0399\u0308\u0342\u03a5\u0308\u0300\u03a5\u0308\u0301\u03a1\u0313\u0000\u03a5\u0342\u0000\u03a5\u0308\u0342\u1ffa\u0399\u0000\u03a9\u0399\u0000\u038f\u0399\u0000\u03a9\u0342\u0000\u03a9\u0342\u0399\u03a9\u0399\u0000FF\u0000FI\u0000FL\u0000FFIFFLST\u0000ST\u0000\u0544\u0546\u0000\u0544\u0535\u0000\u0544\u053b\u0000\u054e\u0546\u0000\u0544\u053d\u0000".toCharArray();
+    private static final char[] upperValues2 = "\u000b\u0000\f\u0000\r\u0000\u000e\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>\u0000\u0000?@A\u0000BC\u0000\u0000\u0000\u0000D\u0000\u0000\u0000\u0000\u0000EFG\u0000HI\u0000\u0000\u0000\u0000J\u0000\u0000\u0000\u0000\u0000KL\u0000\u0000MN\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000OPQ\u0000RS\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000TUV\u0000WX\u0000\u0000\u0000\u0000Y".toCharArray();
+
+    private static final char LATIN_CAPITAL_I_WITH_DOT = '\u0130';
+    private static final char GREEK_CAPITAL_SIGMA = '\u03a3';
+    private static final char GREEK_SMALL_FINAL_SIGMA = '\u03c2';
+
+    /**
+     * Our current GC makes short-lived objects more expensive than we'd like. When that's fixed,
+     * this class should be changed so that you instantiate it with the String and its value,
+     * and count fields.
+     */
+    private CaseMapper() {
+    }
+
+    /**
+     * Implements String.toLowerCase. The original String instance is returned if nothing changes.
+     */
+    public static String toLowerCase(Locale locale, String s) {
+        // Punt hard cases to ICU4C.
+        // Note that Greek isn't a particularly hard case for toLowerCase, only toUpperCase.
+        String languageCode = locale.getLanguage();
+        if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
+            return CaseMapperNative.toLowerCase(s, locale);
+        }
+
+        char[] newValue = null;
+        for (int i = 0, end = s.length(); i < end; ++i) {
+            char ch = s.charAt(i);
+            char newCh;
+            if (ch == LATIN_CAPITAL_I_WITH_DOT || Character.isHighSurrogate(ch)) {
+                // Punt these hard cases.
+                return CaseMapperNative.toLowerCase(s, locale);
+            } else if (ch == GREEK_CAPITAL_SIGMA && isFinalSigma(s, i)) {
+                newCh = GREEK_SMALL_FINAL_SIGMA;
+            } else {
+                newCh = Character.toLowerCase(ch);
+            }
+            if (ch != newCh) {
+                if (newValue == null) {
+                    newValue = new char[end];
+                    s.getCharsNoCheck(0, end, newValue, 0);
+                }
+                newValue[i] = newCh;
+            }
+        }
+        return newValue != null ? new String(newValue) : s;
+    }
+
+    /**
+     * True if 'index' is preceded by a sequence consisting of a cased letter and a case-ignorable
+     * sequence, and 'index' is not followed by a sequence consisting of an ignorable sequence and
+     * then a cased letter.
+     */
+    private static boolean isFinalSigma(String s, int index) {
+        // TODO: we don't skip case-ignorable sequences like we should.
+        // TODO: we should add a more direct way to test for a cased letter.
+        if (index <= 0) {
+            return false;
+        }
+        char previous = s.charAt(index - 1);
+        if (!(Character.isLowerCase(previous) || Character.isUpperCase(previous) || Character.isTitleCase(previous))) {
+            return false;
+        }
+        if (index + 1 >= s.length()) {
+            return true;
+        }
+        char next = s.charAt(index + 1);
+        if (Character.isLowerCase(next) || Character.isUpperCase(next) || Character.isTitleCase(next)) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Return the index of the specified character into the upperValues table.
+     * The upperValues table contains three entries at each position. These
+     * three characters are the upper case conversion. If only two characters
+     * are used, the third character in the table is \u0000.
+     * @return the index into the upperValues table, or -1
+     */
+    private static int upperIndex(int ch) {
+        int index = -1;
+        if (ch >= 0xdf) {
+            if (ch <= 0x587) {
+                switch (ch) {
+                case 0xdf: return 0;
+                case 0x149: return 1;
+                case 0x1f0: return 2;
+                case 0x390: return 3;
+                case 0x3b0: return 4;
+                case 0x587: return 5;
+                }
+            } else if (ch >= 0x1e96) {
+                if (ch <= 0x1e9a) {
+                    index = 6 + ch - 0x1e96;
+                } else if (ch >= 0x1f50 && ch <= 0x1ffc) {
+                    index = upperValues2[ch - 0x1f50];
+                    if (index == 0) {
+                        index = -1;
+                    }
+                } else if (ch >= 0xfb00) {
+                    if (ch <= 0xfb06) {
+                        index = 90 + ch - 0xfb00;
+                    } else if (ch >= 0xfb13 && ch <= 0xfb17) {
+                        index = 97 + ch - 0xfb13;
+                    }
+                }
+            }
+        }
+        return index;
+    }
+
+    private static final ThreadLocal<Transliterator> EL_UPPER = new ThreadLocal<Transliterator>() {
+        @Override protected Transliterator initialValue() {
+            return Transliterator.getInstance("el-Upper");
+        }
+    };
+
+    public static String toUpperCase(Locale locale, String s, int count) {
+        String languageCode = locale.getLanguage();
+        if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
+            return CaseMapperNative.toUpperCase(s, locale);
+        }
+        if (languageCode.equals("el")) {
+            return EL_UPPER.get().transliterate(s);
+        }
+
+        char[] output = null;
+        int i = 0;
+        for (int o = 0; o < count; o++) {
+            char ch = s.charAt(o);
+            if (Character.isHighSurrogate(ch)) {
+                return CaseMapperNative.toUpperCase(s, locale);
+            }
+            int index = upperIndex(ch);
+            if (index == -1) {
+                if (output != null && i >= output.length) {
+                    char[] newoutput = new char[output.length + (count / 6) + 2];
+                    System.arraycopy(output, 0, newoutput, 0, output.length);
+                    output = newoutput;
+                }
+                char upch = Character.toUpperCase(ch);
+                if (output != null) {
+                    output[i++] = upch;
+                } else if (ch != upch) {
+                    output = new char[count];
+                    i = o;
+                    s.getCharsNoCheck(0, i, output, 0);
+                    output[i++] = upch;
+                }
+            } else {
+                int target = index * 3;
+                char val3 = upperValues[target + 2];
+                if (output == null) {
+                    output = new char[count + (count / 6) + 2];
+                    i = o;
+                    s.getCharsNoCheck(0, i, output, 0);
+                } else if (i + (val3 == 0 ? 1 : 2) >= output.length) {
+                    char[] newoutput = new char[output.length + (count / 6) + 3];
+                    System.arraycopy(output, 0, newoutput, 0, output.length);
+                    output = newoutput;
+                }
+
+                char val = upperValues[target];
+                output[i++] = val;
+                val = upperValues[target + 1];
+                output[i++] = val;
+                if (val3 != 0) {
+                    output[i++] = val3;
+                }
+            }
+        }
+        if (output == null) {
+            return s;
+        }
+        return output.length == i || output.length - i < 8 ? new String(0, i, output) : new String(output, 0, i);
+    }
+}
diff --git a/java/lang/CharSequence.annotated.java b/java/lang/CharSequence.annotated.java
new file mode 100644
index 0000000..e61d5d4
--- /dev/null
+++ b/java/lang/CharSequence.annotated.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.util.stream.IntStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface CharSequence {
+
+public int length();
+
+public char charAt(int index);
+
[email protected] public java.lang.CharSequence subSequence(int start, int end);
+
[email protected] public java.lang.String toString();
+
[email protected] public default java.util.stream.IntStream chars() { throw new RuntimeException("Stub!"); }
+
[email protected] public default java.util.stream.IntStream codePoints() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/CharSequence.java b/java/lang/CharSequence.java
new file mode 100644
index 0000000..4d9ab3f
--- /dev/null
+++ b/java/lang/CharSequence.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.util.NoSuchElementException;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.IntConsumer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A <tt>CharSequence</tt> is a readable sequence of <code>char</code> values. This
+ * interface provides uniform, read-only access to many different kinds of
+ * <code>char</code> sequences.
+ * A <code>char</code> value represents a character in the <i>Basic
+ * Multilingual Plane (BMP)</i> or a surrogate. Refer to <a
+ * href="Character.html#unicode">Unicode Character Representation</a> for details.
+ *
+ * <p> This interface does not refine the general contracts of the {@link
+ * java.lang.Object#equals(java.lang.Object) equals} and {@link
+ * java.lang.Object#hashCode() hashCode} methods.  The result of comparing two
+ * objects that implement <tt>CharSequence</tt> is therefore, in general,
+ * undefined.  Each object may be implemented by a different class, and there
+ * is no guarantee that each class will be capable of testing its instances
+ * for equality with those of the other.  It is therefore inappropriate to use
+ * arbitrary <tt>CharSequence</tt> instances as elements in a set or as keys in
+ * a map. </p>
+ *
+ * @author Mike McCloskey
+ * @since 1.4
+ * @spec JSR-51
+ */
+
+public interface CharSequence {
+
+    /**
+     * Returns the length of this character sequence.  The length is the number
+     * of 16-bit <code>char</code>s in the sequence.
+     *
+     * @return  the number of <code>char</code>s in this sequence
+     */
+    int length();
+
+    /**
+     * Returns the <code>char</code> value at the specified index.  An index ranges from zero
+     * to <tt>length() - 1</tt>.  The first <code>char</code> value of the sequence is at
+     * index zero, the next at index one, and so on, as for array
+     * indexing.
+     *
+     * <p>If the <code>char</code> value specified by the index is a
+     * <a href="{@docRoot}/java/lang/Character.html#unicode">surrogate</a>, the surrogate
+     * value is returned.
+     *
+     * @param   index   the index of the <code>char</code> value to be returned
+     *
+     * @return  the specified <code>char</code> value
+     *
+     * @throws  IndexOutOfBoundsException
+     *          if the <tt>index</tt> argument is negative or not less than
+     *          <tt>length()</tt>
+     */
+    char charAt(int index);
+
+    /**
+     * Returns a <code>CharSequence</code> that is a subsequence of this sequence.
+     * The subsequence starts with the <code>char</code> value at the specified index and
+     * ends with the <code>char</code> value at index <tt>end - 1</tt>.  The length
+     * (in <code>char</code>s) of the
+     * returned sequence is <tt>end - start</tt>, so if <tt>start == end</tt>
+     * then an empty sequence is returned.
+     *
+     * @param   start   the start index, inclusive
+     * @param   end     the end index, exclusive
+     *
+     * @return  the specified subsequence
+     *
+     * @throws  IndexOutOfBoundsException
+     *          if <tt>start</tt> or <tt>end</tt> are negative,
+     *          if <tt>end</tt> is greater than <tt>length()</tt>,
+     *          or if <tt>start</tt> is greater than <tt>end</tt>
+     */
+    CharSequence subSequence(int start, int end);
+
+    /**
+     * Returns a string containing the characters in this sequence in the same
+     * order as this sequence.  The length of the string will be the length of
+     * this sequence.
+     *
+     * @return  a string consisting of exactly this sequence of characters
+     */
+    public String toString();
+
+    /**
+     * Returns a stream of {@code int} zero-extending the {@code char} values
+     * from this sequence.  Any char which maps to a <a
+     * href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
+     * point</a> is passed through uninterpreted.
+     *
+     * <p>If the sequence is mutated while the stream is being read, the
+     * result is undefined.
+     *
+     * @return an IntStream of char values from this sequence
+     * @since 1.8
+     */
+    public default IntStream chars() {
+        class CharIterator implements PrimitiveIterator.OfInt {
+            int cur = 0;
+
+            public boolean hasNext() {
+                return cur < length();
+            }
+
+            public int nextInt() {
+                if (hasNext()) {
+                    return charAt(cur++);
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            @Override
+            public void forEachRemaining(IntConsumer block) {
+                for (; cur < length(); cur++) {
+                    block.accept(charAt(cur));
+                }
+            }
+        }
+
+        return StreamSupport.intStream(() ->
+                Spliterators.spliterator(
+                        new CharIterator(),
+                        length(),
+                        Spliterator.ORDERED),
+                Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
+                false);
+    }
+
+    /**
+     * Returns a stream of code point values from this sequence.  Any surrogate
+     * pairs encountered in the sequence are combined as if by {@linkplain
+     * Character#toCodePoint Character.toCodePoint} and the result is passed
+     * to the stream. Any other code units, including ordinary BMP characters,
+     * unpaired surrogates, and undefined code units, are zero-extended to
+     * {@code int} values which are then passed to the stream.
+     *
+     * <p>If the sequence is mutated while the stream is being read, the result
+     * is undefined.
+     *
+     * @return an IntStream of Unicode code points from this sequence
+     * @since 1.8
+     */
+    public default IntStream codePoints() {
+        class CodePointIterator implements PrimitiveIterator.OfInt {
+            int cur = 0;
+
+            @Override
+            public void forEachRemaining(IntConsumer block) {
+                final int length = length();
+                int i = cur;
+                try {
+                    while (i < length) {
+                        char c1 = charAt(i++);
+                        if (!Character.isHighSurrogate(c1) || i >= length) {
+                            block.accept(c1);
+                        } else {
+                            char c2 = charAt(i);
+                            if (Character.isLowSurrogate(c2)) {
+                                i++;
+                                block.accept(Character.toCodePoint(c1, c2));
+                            } else {
+                                block.accept(c1);
+                            }
+                        }
+                    }
+                } finally {
+                    cur = i;
+                }
+            }
+
+            public boolean hasNext() {
+                return cur < length();
+            }
+
+            public int nextInt() {
+                final int length = length();
+
+                if (cur >= length) {
+                    throw new NoSuchElementException();
+                }
+                char c1 = charAt(cur++);
+                if (Character.isHighSurrogate(c1) && cur < length) {
+                    char c2 = charAt(cur);
+                    if (Character.isLowSurrogate(c2)) {
+                        cur++;
+                        return Character.toCodePoint(c1, c2);
+                    }
+                }
+                return c1;
+            }
+        }
+
+        return StreamSupport.intStream(() ->
+                Spliterators.spliteratorUnknownSize(
+                        new CodePointIterator(),
+                        Spliterator.ORDERED),
+                Spliterator.ORDERED,
+                false);
+    }
+}
diff --git a/java/lang/Character.annotated.java b/java/lang/Character.annotated.java
new file mode 100644
index 0000000..d50474f
--- /dev/null
+++ b/java/lang/Character.annotated.java
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.util.Locale;
+import java.util.Map;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Character implements java.io.Serializable, java.lang.Comparable<java.lang.Character> {
+
+public Character(char value) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Character valueOf(char c) { throw new RuntimeException("Stub!"); }
+
+public char charValue() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(char value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(char c) { throw new RuntimeException("Stub!"); }
+
+public static boolean isValidCodePoint(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isBmpCodePoint(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isSupplementaryCodePoint(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isHighSurrogate(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLowSurrogate(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isSurrogate(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isSurrogatePair(char high, char low) { throw new RuntimeException("Stub!"); }
+
+public static int charCount(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static int toCodePoint(char high, char low) { throw new RuntimeException("Stub!"); }
+
+public static int codePointAt(@libcore.util.NonNull java.lang.CharSequence seq, int index) { throw new RuntimeException("Stub!"); }
+
+public static int codePointAt(char[] a, int index) { throw new RuntimeException("Stub!"); }
+
+public static int codePointAt(char[] a, int index, int limit) { throw new RuntimeException("Stub!"); }
+
+public static int codePointBefore(@libcore.util.NonNull java.lang.CharSequence seq, int index) { throw new RuntimeException("Stub!"); }
+
+public static int codePointBefore(char[] a, int index) { throw new RuntimeException("Stub!"); }
+
+public static int codePointBefore(char[] a, int index, int start) { throw new RuntimeException("Stub!"); }
+
+public static char highSurrogate(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static char lowSurrogate(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static int toChars(int codePoint, char[] dst, int dstIndex) { throw new RuntimeException("Stub!"); }
+
+public static char[] toChars(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static int codePointCount(@libcore.util.NonNull java.lang.CharSequence seq, int beginIndex, int endIndex) { throw new RuntimeException("Stub!"); }
+
+public static int codePointCount(char[] a, int offset, int count) { throw new RuntimeException("Stub!"); }
+
+public static int offsetByCodePoints(@libcore.util.NonNull java.lang.CharSequence seq, int index, int codePointOffset) { throw new RuntimeException("Stub!"); }
+
+public static int offsetByCodePoints(char[] a, int start, int count, int index, int codePointOffset) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLowerCase(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLowerCase(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isUpperCase(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isUpperCase(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isTitleCase(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isTitleCase(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isDigit(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isDigit(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isDefined(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isDefined(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLetter(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLetter(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLetterOrDigit(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isLetterOrDigit(int codePoint) { throw new RuntimeException("Stub!"); }
+
+@Deprecated public static boolean isJavaLetter(char ch) { throw new RuntimeException("Stub!"); }
+
+@Deprecated public static boolean isJavaLetterOrDigit(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isAlphabetic(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isIdeographic(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isJavaIdentifierStart(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isJavaIdentifierStart(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isJavaIdentifierPart(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isJavaIdentifierPart(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isUnicodeIdentifierStart(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isUnicodeIdentifierStart(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isUnicodeIdentifierPart(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isUnicodeIdentifierPart(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isIdentifierIgnorable(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isIdentifierIgnorable(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static char toLowerCase(char ch) { throw new RuntimeException("Stub!"); }
+
+public static int toLowerCase(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static char toUpperCase(char ch) { throw new RuntimeException("Stub!"); }
+
+public static int toUpperCase(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static char toTitleCase(char ch) { throw new RuntimeException("Stub!"); }
+
+public static int toTitleCase(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static int digit(char ch, int radix) { throw new RuntimeException("Stub!"); }
+
+public static int digit(int codePoint, int radix) { throw new RuntimeException("Stub!"); }
+
+public static int getNumericValue(char ch) { throw new RuntimeException("Stub!"); }
+
+public static int getNumericValue(int codePoint) { throw new RuntimeException("Stub!"); }
+
+@Deprecated public static boolean isSpace(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isSpaceChar(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isSpaceChar(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isWhitespace(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isWhitespace(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isISOControl(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isISOControl(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static int getType(char ch) { throw new RuntimeException("Stub!"); }
+
+public static int getType(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static char forDigit(int digit, int radix) { throw new RuntimeException("Stub!"); }
+
+public static byte getDirectionality(char ch) { throw new RuntimeException("Stub!"); }
+
+public static byte getDirectionality(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static boolean isMirrored(char ch) { throw new RuntimeException("Stub!"); }
+
+public static boolean isMirrored(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.lang.Character anotherCharacter) { throw new RuntimeException("Stub!"); }
+
+public static int compare(char x, char y) { throw new RuntimeException("Stub!"); }
+
+public static char reverseBytes(char ch) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String getName(int codePoint) { throw new RuntimeException("Stub!"); }
+
+public static final int BYTES = 2; // 0x2
+
+public static final byte COMBINING_SPACING_MARK = 8; // 0x8
+
+public static final byte CONNECTOR_PUNCTUATION = 23; // 0x17
+
+public static final byte CONTROL = 15; // 0xf
+
+public static final byte CURRENCY_SYMBOL = 26; // 0x1a
+
+public static final byte DASH_PUNCTUATION = 20; // 0x14
+
+public static final byte DECIMAL_DIGIT_NUMBER = 9; // 0x9
+
+public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6; // 0x6
+
+public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; // 0x9
+
+public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; // 0x7
+
+public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3; // 0x3
+
+public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; // 0x4
+
+public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; // 0x5
+
+public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0; // 0x0
+
+public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; // 0xe
+
+public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; // 0xf
+
+public static final byte DIRECTIONALITY_NONSPACING_MARK = 8; // 0x8
+
+public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13; // 0xd
+
+public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; // 0xa
+
+public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; // 0x12
+
+public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1; // 0x1
+
+public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; // 0x2
+
+public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; // 0x10
+
+public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; // 0x11
+
+public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; // 0xb
+
+public static final byte DIRECTIONALITY_UNDEFINED = -1; // 0xffffffff
+
+public static final byte DIRECTIONALITY_WHITESPACE = 12; // 0xc
+
+public static final byte ENCLOSING_MARK = 7; // 0x7
+
+public static final byte END_PUNCTUATION = 22; // 0x16
+
+public static final byte FINAL_QUOTE_PUNCTUATION = 30; // 0x1e
+
+public static final byte FORMAT = 16; // 0x10
+
+public static final byte INITIAL_QUOTE_PUNCTUATION = 29; // 0x1d
+
+public static final byte LETTER_NUMBER = 10; // 0xa
+
+public static final byte LINE_SEPARATOR = 13; // 0xd
+
+public static final byte LOWERCASE_LETTER = 2; // 0x2
+
+public static final byte MATH_SYMBOL = 25; // 0x19
+
+public static final int MAX_CODE_POINT = 1114111; // 0x10ffff
+
+public static final char MAX_HIGH_SURROGATE = 56319; // 0xdbff '\udbff'
+
+public static final char MAX_LOW_SURROGATE = 57343; // 0xdfff '\udfff'
+
+public static final int MAX_RADIX = 36; // 0x24
+
+public static final char MAX_SURROGATE = 57343; // 0xdfff '\udfff'
+
+public static final char MAX_VALUE = 65535; // 0xffff '\uffff'
+
+public static final int MIN_CODE_POINT = 0; // 0x0
+
+public static final char MIN_HIGH_SURROGATE = 55296; // 0xd800 '\ud800'
+
+public static final char MIN_LOW_SURROGATE = 56320; // 0xdc00 '\udc00'
+
+public static final int MIN_RADIX = 2; // 0x2
+
+public static final int MIN_SUPPLEMENTARY_CODE_POINT = 65536; // 0x10000
+
+public static final char MIN_SURROGATE = 55296; // 0xd800 '\ud800'
+
+public static final char MIN_VALUE = 0; // 0x0000 '\u0000'
+
+public static final byte MODIFIER_LETTER = 4; // 0x4
+
+public static final byte MODIFIER_SYMBOL = 27; // 0x1b
+
+public static final byte NON_SPACING_MARK = 6; // 0x6
+
+public static final byte OTHER_LETTER = 5; // 0x5
+
+public static final byte OTHER_NUMBER = 11; // 0xb
+
+public static final byte OTHER_PUNCTUATION = 24; // 0x18
+
+public static final byte OTHER_SYMBOL = 28; // 0x1c
+
+public static final byte PARAGRAPH_SEPARATOR = 14; // 0xe
+
+public static final byte PRIVATE_USE = 18; // 0x12
+
+public static final int SIZE = 16; // 0x10
+
+public static final byte SPACE_SEPARATOR = 12; // 0xc
+
+public static final byte START_PUNCTUATION = 21; // 0x15
+
+public static final byte SURROGATE = 19; // 0x13
+
+public static final byte TITLECASE_LETTER = 3; // 0x3
+
+public static final java.lang.Class<java.lang.Character> TYPE;
+static { TYPE = null; }
+
+public static final byte UNASSIGNED = 0; // 0x0
+
+public static final byte UPPERCASE_LETTER = 1; // 0x1
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class Subset {
+
+protected Subset(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public final boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public final int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static final class UnicodeBlock extends java.lang.Character.Subset {
+
+UnicodeBlock(java.lang.String idName) { super(null); throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Character.UnicodeBlock of(char c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Character.UnicodeBlock of(int codePoint) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Character.UnicodeBlock forName(@libcore.util.NonNull java.lang.String blockName) { throw new RuntimeException("Stub!"); }
+
+public static final java.lang.Character.UnicodeBlock AEGEAN_NUMBERS;
+static { AEGEAN_NUMBERS = null; }
+
+public static final java.lang.Character.UnicodeBlock ALCHEMICAL_SYMBOLS;
+static { ALCHEMICAL_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock ALPHABETIC_PRESENTATION_FORMS;
+static { ALPHABETIC_PRESENTATION_FORMS = null; }
+
+public static final java.lang.Character.UnicodeBlock ANCIENT_GREEK_MUSICAL_NOTATION;
+static { ANCIENT_GREEK_MUSICAL_NOTATION = null; }
+
+public static final java.lang.Character.UnicodeBlock ANCIENT_GREEK_NUMBERS;
+static { ANCIENT_GREEK_NUMBERS = null; }
+
+public static final java.lang.Character.UnicodeBlock ANCIENT_SYMBOLS;
+static { ANCIENT_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock ARABIC;
+static { ARABIC = null; }
+
+public static final java.lang.Character.UnicodeBlock ARABIC_EXTENDED_A;
+static { ARABIC_EXTENDED_A = null; }
+
+public static final java.lang.Character.UnicodeBlock ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS;
+static { ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock ARABIC_PRESENTATION_FORMS_A;
+static { ARABIC_PRESENTATION_FORMS_A = null; }
+
+public static final java.lang.Character.UnicodeBlock ARABIC_PRESENTATION_FORMS_B;
+static { ARABIC_PRESENTATION_FORMS_B = null; }
+
+public static final java.lang.Character.UnicodeBlock ARABIC_SUPPLEMENT;
+static { ARABIC_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock ARMENIAN;
+static { ARMENIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock ARROWS;
+static { ARROWS = null; }
+
+public static final java.lang.Character.UnicodeBlock AVESTAN;
+static { AVESTAN = null; }
+
+public static final java.lang.Character.UnicodeBlock BALINESE;
+static { BALINESE = null; }
+
+public static final java.lang.Character.UnicodeBlock BAMUM;
+static { BAMUM = null; }
+
+public static final java.lang.Character.UnicodeBlock BAMUM_SUPPLEMENT;
+static { BAMUM_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock BASIC_LATIN;
+static { BASIC_LATIN = null; }
+
+public static final java.lang.Character.UnicodeBlock BATAK;
+static { BATAK = null; }
+
+public static final java.lang.Character.UnicodeBlock BENGALI;
+static { BENGALI = null; }
+
+public static final java.lang.Character.UnicodeBlock BLOCK_ELEMENTS;
+static { BLOCK_ELEMENTS = null; }
+
+public static final java.lang.Character.UnicodeBlock BOPOMOFO;
+static { BOPOMOFO = null; }
+
+public static final java.lang.Character.UnicodeBlock BOPOMOFO_EXTENDED;
+static { BOPOMOFO_EXTENDED = null; }
+
+public static final java.lang.Character.UnicodeBlock BOX_DRAWING;
+static { BOX_DRAWING = null; }
+
+public static final java.lang.Character.UnicodeBlock BRAHMI;
+static { BRAHMI = null; }
+
+public static final java.lang.Character.UnicodeBlock BRAILLE_PATTERNS;
+static { BRAILLE_PATTERNS = null; }
+
+public static final java.lang.Character.UnicodeBlock BUGINESE;
+static { BUGINESE = null; }
+
+public static final java.lang.Character.UnicodeBlock BUHID;
+static { BUHID = null; }
+
+public static final java.lang.Character.UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS;
+static { BYZANTINE_MUSICAL_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock CARIAN;
+static { CARIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock CHAKMA;
+static { CHAKMA = null; }
+
+public static final java.lang.Character.UnicodeBlock CHAM;
+static { CHAM = null; }
+
+public static final java.lang.Character.UnicodeBlock CHEROKEE;
+static { CHEROKEE = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY;
+static { CJK_COMPATIBILITY = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY_FORMS;
+static { CJK_COMPATIBILITY_FORMS = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS;
+static { CJK_COMPATIBILITY_IDEOGRAPHS = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT;
+static { CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_RADICALS_SUPPLEMENT;
+static { CJK_RADICALS_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_STROKES;
+static { CJK_STROKES = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION;
+static { CJK_SYMBOLS_AND_PUNCTUATION = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS;
+static { CJK_UNIFIED_IDEOGRAPHS = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A;
+static { CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B;
+static { CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C;
+static { CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C = null; }
+
+public static final java.lang.Character.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D;
+static { CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D = null; }
+
+public static final java.lang.Character.UnicodeBlock COMBINING_DIACRITICAL_MARKS;
+static { COMBINING_DIACRITICAL_MARKS = null; }
+
+public static final java.lang.Character.UnicodeBlock COMBINING_DIACRITICAL_MARKS_SUPPLEMENT;
+static { COMBINING_DIACRITICAL_MARKS_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock COMBINING_HALF_MARKS;
+static { COMBINING_HALF_MARKS = null; }
+
+public static final java.lang.Character.UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS;
+static { COMBINING_MARKS_FOR_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock COMMON_INDIC_NUMBER_FORMS;
+static { COMMON_INDIC_NUMBER_FORMS = null; }
+
+public static final java.lang.Character.UnicodeBlock CONTROL_PICTURES;
+static { CONTROL_PICTURES = null; }
+
+public static final java.lang.Character.UnicodeBlock COPTIC;
+static { COPTIC = null; }
+
+public static final java.lang.Character.UnicodeBlock COUNTING_ROD_NUMERALS;
+static { COUNTING_ROD_NUMERALS = null; }
+
+public static final java.lang.Character.UnicodeBlock CUNEIFORM;
+static { CUNEIFORM = null; }
+
+public static final java.lang.Character.UnicodeBlock CUNEIFORM_NUMBERS_AND_PUNCTUATION;
+static { CUNEIFORM_NUMBERS_AND_PUNCTUATION = null; }
+
+public static final java.lang.Character.UnicodeBlock CURRENCY_SYMBOLS;
+static { CURRENCY_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock CYPRIOT_SYLLABARY;
+static { CYPRIOT_SYLLABARY = null; }
+
+public static final java.lang.Character.UnicodeBlock CYRILLIC;
+static { CYRILLIC = null; }
+
+public static final java.lang.Character.UnicodeBlock CYRILLIC_EXTENDED_A;
+static { CYRILLIC_EXTENDED_A = null; }
+
+public static final java.lang.Character.UnicodeBlock CYRILLIC_EXTENDED_B;
+static { CYRILLIC_EXTENDED_B = null; }
+
+public static final java.lang.Character.UnicodeBlock CYRILLIC_SUPPLEMENTARY;
+static { CYRILLIC_SUPPLEMENTARY = null; }
+
+public static final java.lang.Character.UnicodeBlock DESERET;
+static { DESERET = null; }
+
+public static final java.lang.Character.UnicodeBlock DEVANAGARI;
+static { DEVANAGARI = null; }
+
+public static final java.lang.Character.UnicodeBlock DEVANAGARI_EXTENDED;
+static { DEVANAGARI_EXTENDED = null; }
+
+public static final java.lang.Character.UnicodeBlock DINGBATS;
+static { DINGBATS = null; }
+
+public static final java.lang.Character.UnicodeBlock DOMINO_TILES;
+static { DOMINO_TILES = null; }
+
+public static final java.lang.Character.UnicodeBlock EGYPTIAN_HIEROGLYPHS;
+static { EGYPTIAN_HIEROGLYPHS = null; }
+
+public static final java.lang.Character.UnicodeBlock EMOTICONS;
+static { EMOTICONS = null; }
+
+public static final java.lang.Character.UnicodeBlock ENCLOSED_ALPHANUMERICS;
+static { ENCLOSED_ALPHANUMERICS = null; }
+
+public static final java.lang.Character.UnicodeBlock ENCLOSED_ALPHANUMERIC_SUPPLEMENT;
+static { ENCLOSED_ALPHANUMERIC_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS;
+static { ENCLOSED_CJK_LETTERS_AND_MONTHS = null; }
+
+public static final java.lang.Character.UnicodeBlock ENCLOSED_IDEOGRAPHIC_SUPPLEMENT;
+static { ENCLOSED_IDEOGRAPHIC_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock ETHIOPIC;
+static { ETHIOPIC = null; }
+
+public static final java.lang.Character.UnicodeBlock ETHIOPIC_EXTENDED;
+static { ETHIOPIC_EXTENDED = null; }
+
+public static final java.lang.Character.UnicodeBlock ETHIOPIC_EXTENDED_A;
+static { ETHIOPIC_EXTENDED_A = null; }
+
+public static final java.lang.Character.UnicodeBlock ETHIOPIC_SUPPLEMENT;
+static { ETHIOPIC_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock GENERAL_PUNCTUATION;
+static { GENERAL_PUNCTUATION = null; }
+
+public static final java.lang.Character.UnicodeBlock GEOMETRIC_SHAPES;
+static { GEOMETRIC_SHAPES = null; }
+
+public static final java.lang.Character.UnicodeBlock GEORGIAN;
+static { GEORGIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock GEORGIAN_SUPPLEMENT;
+static { GEORGIAN_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock GLAGOLITIC;
+static { GLAGOLITIC = null; }
+
+public static final java.lang.Character.UnicodeBlock GOTHIC;
+static { GOTHIC = null; }
+
+public static final java.lang.Character.UnicodeBlock GREEK;
+static { GREEK = null; }
+
+public static final java.lang.Character.UnicodeBlock GREEK_EXTENDED;
+static { GREEK_EXTENDED = null; }
+
+public static final java.lang.Character.UnicodeBlock GUJARATI;
+static { GUJARATI = null; }
+
+public static final java.lang.Character.UnicodeBlock GURMUKHI;
+static { GURMUKHI = null; }
+
+public static final java.lang.Character.UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS;
+static { HALFWIDTH_AND_FULLWIDTH_FORMS = null; }
+
+public static final java.lang.Character.UnicodeBlock HANGUL_COMPATIBILITY_JAMO;
+static { HANGUL_COMPATIBILITY_JAMO = null; }
+
+public static final java.lang.Character.UnicodeBlock HANGUL_JAMO;
+static { HANGUL_JAMO = null; }
+
+public static final java.lang.Character.UnicodeBlock HANGUL_JAMO_EXTENDED_A;
+static { HANGUL_JAMO_EXTENDED_A = null; }
+
+public static final java.lang.Character.UnicodeBlock HANGUL_JAMO_EXTENDED_B;
+static { HANGUL_JAMO_EXTENDED_B = null; }
+
+public static final java.lang.Character.UnicodeBlock HANGUL_SYLLABLES;
+static { HANGUL_SYLLABLES = null; }
+
+public static final java.lang.Character.UnicodeBlock HANUNOO;
+static { HANUNOO = null; }
+
+public static final java.lang.Character.UnicodeBlock HEBREW;
+static { HEBREW = null; }
+
+public static final java.lang.Character.UnicodeBlock HIGH_PRIVATE_USE_SURROGATES;
+static { HIGH_PRIVATE_USE_SURROGATES = null; }
+
+public static final java.lang.Character.UnicodeBlock HIGH_SURROGATES;
+static { HIGH_SURROGATES = null; }
+
+public static final java.lang.Character.UnicodeBlock HIRAGANA;
+static { HIRAGANA = null; }
+
+public static final java.lang.Character.UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS;
+static { IDEOGRAPHIC_DESCRIPTION_CHARACTERS = null; }
+
+public static final java.lang.Character.UnicodeBlock IMPERIAL_ARAMAIC;
+static { IMPERIAL_ARAMAIC = null; }
+
+public static final java.lang.Character.UnicodeBlock INSCRIPTIONAL_PAHLAVI;
+static { INSCRIPTIONAL_PAHLAVI = null; }
+
+public static final java.lang.Character.UnicodeBlock INSCRIPTIONAL_PARTHIAN;
+static { INSCRIPTIONAL_PARTHIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock IPA_EXTENSIONS;
+static { IPA_EXTENSIONS = null; }
+
+public static final java.lang.Character.UnicodeBlock JAVANESE;
+static { JAVANESE = null; }
+
+public static final java.lang.Character.UnicodeBlock KAITHI;
+static { KAITHI = null; }
+
+public static final java.lang.Character.UnicodeBlock KANA_SUPPLEMENT;
+static { KANA_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock KANBUN;
+static { KANBUN = null; }
+
+public static final java.lang.Character.UnicodeBlock KANGXI_RADICALS;
+static { KANGXI_RADICALS = null; }
+
+public static final java.lang.Character.UnicodeBlock KANNADA;
+static { KANNADA = null; }
+
+public static final java.lang.Character.UnicodeBlock KATAKANA;
+static { KATAKANA = null; }
+
+public static final java.lang.Character.UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS;
+static { KATAKANA_PHONETIC_EXTENSIONS = null; }
+
+public static final java.lang.Character.UnicodeBlock KAYAH_LI;
+static { KAYAH_LI = null; }
+
+public static final java.lang.Character.UnicodeBlock KHAROSHTHI;
+static { KHAROSHTHI = null; }
+
+public static final java.lang.Character.UnicodeBlock KHMER;
+static { KHMER = null; }
+
+public static final java.lang.Character.UnicodeBlock KHMER_SYMBOLS;
+static { KHMER_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock LAO;
+static { LAO = null; }
+
+public static final java.lang.Character.UnicodeBlock LATIN_1_SUPPLEMENT;
+static { LATIN_1_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_A;
+static { LATIN_EXTENDED_A = null; }
+
+public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_ADDITIONAL;
+static { LATIN_EXTENDED_ADDITIONAL = null; }
+
+public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_B;
+static { LATIN_EXTENDED_B = null; }
+
+public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_C;
+static { LATIN_EXTENDED_C = null; }
+
+public static final java.lang.Character.UnicodeBlock LATIN_EXTENDED_D;
+static { LATIN_EXTENDED_D = null; }
+
+public static final java.lang.Character.UnicodeBlock LEPCHA;
+static { LEPCHA = null; }
+
+public static final java.lang.Character.UnicodeBlock LETTERLIKE_SYMBOLS;
+static { LETTERLIKE_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock LIMBU;
+static { LIMBU = null; }
+
+public static final java.lang.Character.UnicodeBlock LINEAR_B_IDEOGRAMS;
+static { LINEAR_B_IDEOGRAMS = null; }
+
+public static final java.lang.Character.UnicodeBlock LINEAR_B_SYLLABARY;
+static { LINEAR_B_SYLLABARY = null; }
+
+public static final java.lang.Character.UnicodeBlock LISU;
+static { LISU = null; }
+
+public static final java.lang.Character.UnicodeBlock LOW_SURROGATES;
+static { LOW_SURROGATES = null; }
+
+public static final java.lang.Character.UnicodeBlock LYCIAN;
+static { LYCIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock LYDIAN;
+static { LYDIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock MAHJONG_TILES;
+static { MAHJONG_TILES = null; }
+
+public static final java.lang.Character.UnicodeBlock MALAYALAM;
+static { MALAYALAM = null; }
+
+public static final java.lang.Character.UnicodeBlock MANDAIC;
+static { MANDAIC = null; }
+
+public static final java.lang.Character.UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS;
+static { MATHEMATICAL_ALPHANUMERIC_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock MATHEMATICAL_OPERATORS;
+static { MATHEMATICAL_OPERATORS = null; }
+
+public static final java.lang.Character.UnicodeBlock MEETEI_MAYEK;
+static { MEETEI_MAYEK = null; }
+
+public static final java.lang.Character.UnicodeBlock MEETEI_MAYEK_EXTENSIONS;
+static { MEETEI_MAYEK_EXTENSIONS = null; }
+
+public static final java.lang.Character.UnicodeBlock MEROITIC_CURSIVE;
+static { MEROITIC_CURSIVE = null; }
+
+public static final java.lang.Character.UnicodeBlock MEROITIC_HIEROGLYPHS;
+static { MEROITIC_HIEROGLYPHS = null; }
+
+public static final java.lang.Character.UnicodeBlock MIAO;
+static { MIAO = null; }
+
+public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A;
+static { MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A = null; }
+
+public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B;
+static { MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B = null; }
+
+public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_SYMBOLS;
+static { MISCELLANEOUS_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS;
+static { MISCELLANEOUS_SYMBOLS_AND_ARROWS = null; }
+
+public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS;
+static { MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS = null; }
+
+public static final java.lang.Character.UnicodeBlock MISCELLANEOUS_TECHNICAL;
+static { MISCELLANEOUS_TECHNICAL = null; }
+
+public static final java.lang.Character.UnicodeBlock MODIFIER_TONE_LETTERS;
+static { MODIFIER_TONE_LETTERS = null; }
+
+public static final java.lang.Character.UnicodeBlock MONGOLIAN;
+static { MONGOLIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock MUSICAL_SYMBOLS;
+static { MUSICAL_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock MYANMAR;
+static { MYANMAR = null; }
+
+public static final java.lang.Character.UnicodeBlock MYANMAR_EXTENDED_A;
+static { MYANMAR_EXTENDED_A = null; }
+
+public static final java.lang.Character.UnicodeBlock NEW_TAI_LUE;
+static { NEW_TAI_LUE = null; }
+
+public static final java.lang.Character.UnicodeBlock NKO;
+static { NKO = null; }
+
+public static final java.lang.Character.UnicodeBlock NUMBER_FORMS;
+static { NUMBER_FORMS = null; }
+
+public static final java.lang.Character.UnicodeBlock OGHAM;
+static { OGHAM = null; }
+
+public static final java.lang.Character.UnicodeBlock OLD_ITALIC;
+static { OLD_ITALIC = null; }
+
+public static final java.lang.Character.UnicodeBlock OLD_PERSIAN;
+static { OLD_PERSIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock OLD_SOUTH_ARABIAN;
+static { OLD_SOUTH_ARABIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock OLD_TURKIC;
+static { OLD_TURKIC = null; }
+
+public static final java.lang.Character.UnicodeBlock OL_CHIKI;
+static { OL_CHIKI = null; }
+
+public static final java.lang.Character.UnicodeBlock OPTICAL_CHARACTER_RECOGNITION;
+static { OPTICAL_CHARACTER_RECOGNITION = null; }
+
+public static final java.lang.Character.UnicodeBlock ORIYA;
+static { ORIYA = null; }
+
+public static final java.lang.Character.UnicodeBlock OSMANYA;
+static { OSMANYA = null; }
+
+public static final java.lang.Character.UnicodeBlock PHAGS_PA;
+static { PHAGS_PA = null; }
+
+public static final java.lang.Character.UnicodeBlock PHAISTOS_DISC;
+static { PHAISTOS_DISC = null; }
+
+public static final java.lang.Character.UnicodeBlock PHOENICIAN;
+static { PHOENICIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock PHONETIC_EXTENSIONS;
+static { PHONETIC_EXTENSIONS = null; }
+
+public static final java.lang.Character.UnicodeBlock PHONETIC_EXTENSIONS_SUPPLEMENT;
+static { PHONETIC_EXTENSIONS_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock PLAYING_CARDS;
+static { PLAYING_CARDS = null; }
+
+public static final java.lang.Character.UnicodeBlock PRIVATE_USE_AREA;
+static { PRIVATE_USE_AREA = null; }
+
+public static final java.lang.Character.UnicodeBlock REJANG;
+static { REJANG = null; }
+
+public static final java.lang.Character.UnicodeBlock RUMI_NUMERAL_SYMBOLS;
+static { RUMI_NUMERAL_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock RUNIC;
+static { RUNIC = null; }
+
+public static final java.lang.Character.UnicodeBlock SAMARITAN;
+static { SAMARITAN = null; }
+
+public static final java.lang.Character.UnicodeBlock SAURASHTRA;
+static { SAURASHTRA = null; }
+
+public static final java.lang.Character.UnicodeBlock SHARADA;
+static { SHARADA = null; }
+
+public static final java.lang.Character.UnicodeBlock SHAVIAN;
+static { SHAVIAN = null; }
+
+public static final java.lang.Character.UnicodeBlock SINHALA;
+static { SINHALA = null; }
+
+public static final java.lang.Character.UnicodeBlock SMALL_FORM_VARIANTS;
+static { SMALL_FORM_VARIANTS = null; }
+
+public static final java.lang.Character.UnicodeBlock SORA_SOMPENG;
+static { SORA_SOMPENG = null; }
+
+public static final java.lang.Character.UnicodeBlock SPACING_MODIFIER_LETTERS;
+static { SPACING_MODIFIER_LETTERS = null; }
+
+public static final java.lang.Character.UnicodeBlock SPECIALS;
+static { SPECIALS = null; }
+
+public static final java.lang.Character.UnicodeBlock SUNDANESE;
+static { SUNDANESE = null; }
+
+public static final java.lang.Character.UnicodeBlock SUNDANESE_SUPPLEMENT;
+static { SUNDANESE_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS;
+static { SUPERSCRIPTS_AND_SUBSCRIPTS = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_ARROWS_A;
+static { SUPPLEMENTAL_ARROWS_A = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_ARROWS_B;
+static { SUPPLEMENTAL_ARROWS_B = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS;
+static { SUPPLEMENTAL_MATHEMATICAL_OPERATORS = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPPLEMENTAL_PUNCTUATION;
+static { SUPPLEMENTAL_PUNCTUATION = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A;
+static { SUPPLEMENTARY_PRIVATE_USE_AREA_A = null; }
+
+public static final java.lang.Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B;
+static { SUPPLEMENTARY_PRIVATE_USE_AREA_B = null; }
+
+@Deprecated public static final java.lang.Character.UnicodeBlock SURROGATES_AREA;
+static { SURROGATES_AREA = null; }
+
+public static final java.lang.Character.UnicodeBlock SYLOTI_NAGRI;
+static { SYLOTI_NAGRI = null; }
+
+public static final java.lang.Character.UnicodeBlock SYRIAC;
+static { SYRIAC = null; }
+
+public static final java.lang.Character.UnicodeBlock TAGALOG;
+static { TAGALOG = null; }
+
+public static final java.lang.Character.UnicodeBlock TAGBANWA;
+static { TAGBANWA = null; }
+
+public static final java.lang.Character.UnicodeBlock TAGS;
+static { TAGS = null; }
+
+public static final java.lang.Character.UnicodeBlock TAI_LE;
+static { TAI_LE = null; }
+
+public static final java.lang.Character.UnicodeBlock TAI_THAM;
+static { TAI_THAM = null; }
+
+public static final java.lang.Character.UnicodeBlock TAI_VIET;
+static { TAI_VIET = null; }
+
+public static final java.lang.Character.UnicodeBlock TAI_XUAN_JING_SYMBOLS;
+static { TAI_XUAN_JING_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock TAKRI;
+static { TAKRI = null; }
+
+public static final java.lang.Character.UnicodeBlock TAMIL;
+static { TAMIL = null; }
+
+public static final java.lang.Character.UnicodeBlock TELUGU;
+static { TELUGU = null; }
+
+public static final java.lang.Character.UnicodeBlock THAANA;
+static { THAANA = null; }
+
+public static final java.lang.Character.UnicodeBlock THAI;
+static { THAI = null; }
+
+public static final java.lang.Character.UnicodeBlock TIBETAN;
+static { TIBETAN = null; }
+
+public static final java.lang.Character.UnicodeBlock TIFINAGH;
+static { TIFINAGH = null; }
+
+public static final java.lang.Character.UnicodeBlock TRANSPORT_AND_MAP_SYMBOLS;
+static { TRANSPORT_AND_MAP_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock UGARITIC;
+static { UGARITIC = null; }
+
+public static final java.lang.Character.UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS;
+static { UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS = null; }
+
+public static final java.lang.Character.UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED;
+static { UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED = null; }
+
+public static final java.lang.Character.UnicodeBlock VAI;
+static { VAI = null; }
+
+public static final java.lang.Character.UnicodeBlock VARIATION_SELECTORS;
+static { VARIATION_SELECTORS = null; }
+
+public static final java.lang.Character.UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT;
+static { VARIATION_SELECTORS_SUPPLEMENT = null; }
+
+public static final java.lang.Character.UnicodeBlock VEDIC_EXTENSIONS;
+static { VEDIC_EXTENSIONS = null; }
+
+public static final java.lang.Character.UnicodeBlock VERTICAL_FORMS;
+static { VERTICAL_FORMS = null; }
+
+public static final java.lang.Character.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS;
+static { YIJING_HEXAGRAM_SYMBOLS = null; }
+
+public static final java.lang.Character.UnicodeBlock YI_RADICALS;
+static { YI_RADICALS = null; }
+
+public static final java.lang.Character.UnicodeBlock YI_SYLLABLES;
+static { YI_SYLLABLES = null; }
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static enum UnicodeScript {
+COMMON,
+LATIN,
+GREEK,
+CYRILLIC,
+ARMENIAN,
+HEBREW,
+ARABIC,
+SYRIAC,
+THAANA,
+DEVANAGARI,
+BENGALI,
+GURMUKHI,
+GUJARATI,
+ORIYA,
+TAMIL,
+TELUGU,
+KANNADA,
+MALAYALAM,
+SINHALA,
+THAI,
+LAO,
+TIBETAN,
+MYANMAR,
+GEORGIAN,
+HANGUL,
+ETHIOPIC,
+CHEROKEE,
+CANADIAN_ABORIGINAL,
+OGHAM,
+RUNIC,
+KHMER,
+MONGOLIAN,
+HIRAGANA,
+KATAKANA,
+BOPOMOFO,
+HAN,
+YI,
+OLD_ITALIC,
+GOTHIC,
+DESERET,
+INHERITED,
+TAGALOG,
+HANUNOO,
+BUHID,
+TAGBANWA,
+LIMBU,
+TAI_LE,
+LINEAR_B,
+UGARITIC,
+SHAVIAN,
+OSMANYA,
+CYPRIOT,
+BRAILLE,
+BUGINESE,
+COPTIC,
+NEW_TAI_LUE,
+GLAGOLITIC,
+TIFINAGH,
+SYLOTI_NAGRI,
+OLD_PERSIAN,
+KHAROSHTHI,
+BALINESE,
+CUNEIFORM,
+PHOENICIAN,
+PHAGS_PA,
+NKO,
+SUNDANESE,
+BATAK,
+LEPCHA,
+OL_CHIKI,
+VAI,
+SAURASHTRA,
+KAYAH_LI,
+REJANG,
+LYCIAN,
+CARIAN,
+LYDIAN,
+CHAM,
+TAI_THAM,
+TAI_VIET,
+AVESTAN,
+EGYPTIAN_HIEROGLYPHS,
+SAMARITAN,
+MANDAIC,
+LISU,
+BAMUM,
+JAVANESE,
+MEETEI_MAYEK,
+IMPERIAL_ARAMAIC,
+OLD_SOUTH_ARABIAN,
+INSCRIPTIONAL_PARTHIAN,
+INSCRIPTIONAL_PAHLAVI,
+OLD_TURKIC,
+BRAHMI,
+KAITHI,
+MEROITIC_HIEROGLYPHS,
+MEROITIC_CURSIVE,
+SORA_SOMPENG,
+CHAKMA,
+SHARADA,
+TAKRI,
+MIAO,
+UNKNOWN;
+
[email protected] public static java.lang.Character.UnicodeScript of(int codePoint) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Character.UnicodeScript forName(@libcore.util.NonNull java.lang.String scriptName) { throw new RuntimeException("Stub!"); }
+}
+
+}
+
diff --git a/java/lang/Character.java b/java/lang/Character.java
new file mode 100644
index 0000000..8b1635d
--- /dev/null
+++ b/java/lang/Character.java
@@ -0,0 +1,7659 @@
+/*
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+// Android-changed: Remove reference to a specific unicode standard version
+/**
+ * The {@code Character} class wraps a value of the primitive
+ * type {@code char} in an object. An object of type
+ * {@code Character} contains a single field whose type is
+ * {@code char}.
+ * <p>
+ * In addition, this class provides several methods for determining
+ * a character's category (lowercase letter, digit, etc.) and for converting
+ * characters from uppercase to lowercase and vice versa.
+ * <p>
+ * Character information is based on the Unicode Standard
+ * <p>
+ * The methods and data of class {@code Character} are defined by
+ * the information in the <i>UnicodeData</i> file that is part of the
+ * Unicode Character Database maintained by the Unicode
+ * Consortium. This file specifies various properties including name
+ * and general category for every defined Unicode code point or
+ * character range.
+ * <p>
+ * The file and its description are available from the Unicode Consortium at:
+ * <ul>
+ * <li><a href="http://www.unicode.org">http://www.unicode.org</a>
+ * </ul>
+ *
+ * <h3><a name="unicode">Unicode Character Representations</a></h3>
+ *
+ * <p>The {@code char} data type (and therefore the value that a
+ * {@code Character} object encapsulates) are based on the
+ * original Unicode specification, which defined characters as
+ * fixed-width 16-bit entities. The Unicode Standard has since been
+ * changed to allow for characters whose representation requires more
+ * than 16 bits.  The range of legal <em>code point</em>s is now
+ * U+0000 to U+10FFFF, known as <em>Unicode scalar value</em>.
+ * (Refer to the <a
+ * href="http://www.unicode.org/reports/tr27/#notation"><i>
+ * definition</i></a> of the U+<i>n</i> notation in the Unicode
+ * Standard.)
+ *
+ * <p><a name="BMP">The set of characters from U+0000 to U+FFFF</a> is
+ * sometimes referred to as the <em>Basic Multilingual Plane (BMP)</em>.
+ * <a name="supplementary">Characters</a> whose code points are greater
+ * than U+FFFF are called <em>supplementary character</em>s.  The Java
+ * platform uses the UTF-16 representation in {@code char} arrays and
+ * in the {@code String} and {@code StringBuffer} classes. In
+ * this representation, supplementary characters are represented as a pair
+ * of {@code char} values, the first from the <em>high-surrogates</em>
+ * range, (&#92;uD800-&#92;uDBFF), the second from the
+ * <em>low-surrogates</em> range (&#92;uDC00-&#92;uDFFF).
+ *
+ * <p>A {@code char} value, therefore, represents Basic
+ * Multilingual Plane (BMP) code points, including the surrogate
+ * code points, or code units of the UTF-16 encoding. An
+ * {@code int} value represents all Unicode code points,
+ * including supplementary code points. The lower (least significant)
+ * 21 bits of {@code int} are used to represent Unicode code
+ * points and the upper (most significant) 11 bits must be zero.
+ * Unless otherwise specified, the behavior with respect to
+ * supplementary characters and surrogate {@code char} values is
+ * as follows:
+ *
+ * <ul>
+ * <li>The methods that only accept a {@code char} value cannot support
+ * supplementary characters. They treat {@code char} values from the
+ * surrogate ranges as undefined characters. For example,
+ * {@code Character.isLetter('\u005CuD840')} returns {@code false}, even though
+ * this specific value if followed by any low-surrogate value in a string
+ * would represent a letter.
+ *
+ * <li>The methods that accept an {@code int} value support all
+ * Unicode characters, including supplementary characters. For
+ * example, {@code Character.isLetter(0x2F81A)} returns
+ * {@code true} because the code point value represents a letter
+ * (a CJK ideograph).
+ * </ul>
+ *
+ * <p>In the Java SE API documentation, <em>Unicode code point</em> is
+ * used for character values in the range between U+0000 and U+10FFFF,
+ * and <em>Unicode code unit</em> is used for 16-bit
+ * {@code char} values that are code units of the <em>UTF-16</em>
+ * encoding. For more information on Unicode terminology, refer to the
+ * <a href="http://www.unicode.org/glossary/">Unicode Glossary</a>.
+ *
+ * @author  Lee Boynton
+ * @author  Guy Steele
+ * @author  Akira Tanaka
+ * @author  Martin Buchholz
+ * @author  Ulf Zibis
+ * @since   1.0
+ */
+public final
+class Character implements java.io.Serializable, Comparable<Character> {
+    /**
+     * The minimum radix available for conversion to and from strings.
+     * The constant value of this field is the smallest value permitted
+     * for the radix argument in radix-conversion methods such as the
+     * {@code digit} method, the {@code forDigit} method, and the
+     * {@code toString} method of class {@code Integer}.
+     *
+     * @see     Character#digit(char, int)
+     * @see     Character#forDigit(int, int)
+     * @see     Integer#toString(int, int)
+     * @see     Integer#valueOf(String)
+     */
+    public static final int MIN_RADIX = 2;
+
+    /**
+     * The maximum radix available for conversion to and from strings.
+     * The constant value of this field is the largest value permitted
+     * for the radix argument in radix-conversion methods such as the
+     * {@code digit} method, the {@code forDigit} method, and the
+     * {@code toString} method of class {@code Integer}.
+     *
+     * @see     Character#digit(char, int)
+     * @see     Character#forDigit(int, int)
+     * @see     Integer#toString(int, int)
+     * @see     Integer#valueOf(String)
+     */
+    public static final int MAX_RADIX = 36;
+
+    /**
+     * The constant value of this field is the smallest value of type
+     * {@code char}, {@code '\u005Cu0000'}.
+     *
+     * @since   1.0.2
+     */
+    public static final char MIN_VALUE = '\u0000';
+
+    /**
+     * The constant value of this field is the largest value of type
+     * {@code char}, {@code '\u005CuFFFF'}.
+     *
+     * @since   1.0.2
+     */
+    public static final char MAX_VALUE = '\uFFFF';
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code char}.
+     *
+     * @since   1.1
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Character> TYPE = (Class<Character>) Class.getPrimitiveClass("char");
+
+    /*
+     * Normative general types
+     */
+
+    /*
+     * General character types
+     */
+
+    /**
+     * General category "Cn" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte UNASSIGNED = 0;
+
+    /**
+     * General category "Lu" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte UPPERCASE_LETTER = 1;
+
+    /**
+     * General category "Ll" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte LOWERCASE_LETTER = 2;
+
+    /**
+     * General category "Lt" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte TITLECASE_LETTER = 3;
+
+    /**
+     * General category "Lm" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte MODIFIER_LETTER = 4;
+
+    /**
+     * General category "Lo" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte OTHER_LETTER = 5;
+
+    /**
+     * General category "Mn" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte NON_SPACING_MARK = 6;
+
+    /**
+     * General category "Me" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte ENCLOSING_MARK = 7;
+
+    /**
+     * General category "Mc" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte COMBINING_SPACING_MARK = 8;
+
+    /**
+     * General category "Nd" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte DECIMAL_DIGIT_NUMBER        = 9;
+
+    /**
+     * General category "Nl" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte LETTER_NUMBER = 10;
+
+    /**
+     * General category "No" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte OTHER_NUMBER = 11;
+
+    /**
+     * General category "Zs" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte SPACE_SEPARATOR = 12;
+
+    /**
+     * General category "Zl" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte LINE_SEPARATOR = 13;
+
+    /**
+     * General category "Zp" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte PARAGRAPH_SEPARATOR = 14;
+
+    /**
+     * General category "Cc" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte CONTROL = 15;
+
+    /**
+     * General category "Cf" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte FORMAT = 16;
+
+    /**
+     * General category "Co" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte PRIVATE_USE = 18;
+
+    /**
+     * General category "Cs" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte SURROGATE = 19;
+
+    /**
+     * General category "Pd" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte DASH_PUNCTUATION = 20;
+
+    /**
+     * General category "Ps" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte START_PUNCTUATION = 21;
+
+    /**
+     * General category "Pe" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte END_PUNCTUATION = 22;
+
+    /**
+     * General category "Pc" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte CONNECTOR_PUNCTUATION = 23;
+
+    /**
+     * General category "Po" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte OTHER_PUNCTUATION = 24;
+
+    /**
+     * General category "Sm" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte MATH_SYMBOL = 25;
+
+    /**
+     * General category "Sc" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte CURRENCY_SYMBOL = 26;
+
+    /**
+     * General category "Sk" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte MODIFIER_SYMBOL = 27;
+
+    /**
+     * General category "So" in the Unicode specification.
+     * @since   1.1
+     */
+    public static final byte OTHER_SYMBOL = 28;
+
+    /**
+     * General category "Pi" in the Unicode specification.
+     * @since   1.4
+     */
+    public static final byte INITIAL_QUOTE_PUNCTUATION = 29;
+
+    /**
+     * General category "Pf" in the Unicode specification.
+     * @since   1.4
+     */
+    public static final byte FINAL_QUOTE_PUNCTUATION = 30;
+
+    /**
+     * Error flag. Use int (code point) to avoid confusion with U+FFFF.
+     */
+    static final int ERROR = 0xFFFFFFFF;
+
+
+    /**
+     * Undefined bidirectional character type. Undefined {@code char}
+     * values have undefined directionality in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_UNDEFINED = -1;
+
+    /**
+     * Strong bidirectional character type "L" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0;
+
+    /**
+     * Strong bidirectional character type "R" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1;
+
+    /**
+    * Strong bidirectional character type "AL" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2;
+
+    /**
+     * Weak bidirectional character type "EN" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3;
+
+    /**
+     * Weak bidirectional character type "ES" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4;
+
+    /**
+     * Weak bidirectional character type "ET" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5;
+
+    /**
+     * Weak bidirectional character type "AN" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6;
+
+    /**
+     * Weak bidirectional character type "CS" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7;
+
+    /**
+     * Weak bidirectional character type "NSM" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_NONSPACING_MARK = 8;
+
+    /**
+     * Weak bidirectional character type "BN" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9;
+
+    /**
+     * Neutral bidirectional character type "B" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10;
+
+    /**
+     * Neutral bidirectional character type "S" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11;
+
+    /**
+     * Neutral bidirectional character type "WS" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_WHITESPACE = 12;
+
+    /**
+     * Neutral bidirectional character type "ON" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13;
+
+    /**
+     * Strong bidirectional character type "LRE" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14;
+
+    /**
+     * Strong bidirectional character type "LRO" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15;
+
+    /**
+     * Strong bidirectional character type "RLE" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16;
+
+    /**
+     * Strong bidirectional character type "RLO" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17;
+
+    /**
+     * Weak bidirectional character type "PDF" in the Unicode specification.
+     * @since 1.4
+     */
+    public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18;
+
+    /**
+     * The minimum value of a
+     * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit">
+     * Unicode high-surrogate code unit</a>
+     * in the UTF-16 encoding, constant {@code '\u005CuD800'}.
+     * A high-surrogate is also known as a <i>leading-surrogate</i>.
+     *
+     * @since 1.5
+     */
+    public static final char MIN_HIGH_SURROGATE = '\uD800';
+
+    /**
+     * The maximum value of a
+     * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit">
+     * Unicode high-surrogate code unit</a>
+     * in the UTF-16 encoding, constant {@code '\u005CuDBFF'}.
+     * A high-surrogate is also known as a <i>leading-surrogate</i>.
+     *
+     * @since 1.5
+     */
+    public static final char MAX_HIGH_SURROGATE = '\uDBFF';
+
+    /**
+     * The minimum value of a
+     * <a href="http://www.unicode.org/glossary/#low_surrogate_code_unit">
+     * Unicode low-surrogate code unit</a>
+     * in the UTF-16 encoding, constant {@code '\u005CuDC00'}.
+     * A low-surrogate is also known as a <i>trailing-surrogate</i>.
+     *
+     * @since 1.5
+     */
+    public static final char MIN_LOW_SURROGATE  = '\uDC00';
+
+    /**
+     * The maximum value of a
+     * <a href="http://www.unicode.org/glossary/#low_surrogate_code_unit">
+     * Unicode low-surrogate code unit</a>
+     * in the UTF-16 encoding, constant {@code '\u005CuDFFF'}.
+     * A low-surrogate is also known as a <i>trailing-surrogate</i>.
+     *
+     * @since 1.5
+     */
+    public static final char MAX_LOW_SURROGATE  = '\uDFFF';
+
+    /**
+     * The minimum value of a Unicode surrogate code unit in the
+     * UTF-16 encoding, constant {@code '\u005CuD800'}.
+     *
+     * @since 1.5
+     */
+    public static final char MIN_SURROGATE = MIN_HIGH_SURROGATE;
+
+    /**
+     * The maximum value of a Unicode surrogate code unit in the
+     * UTF-16 encoding, constant {@code '\u005CuDFFF'}.
+     *
+     * @since 1.5
+     */
+    public static final char MAX_SURROGATE = MAX_LOW_SURROGATE;
+
+    /**
+     * The minimum value of a
+     * <a href="http://www.unicode.org/glossary/#supplementary_code_point">
+     * Unicode supplementary code point</a>, constant {@code U+10000}.
+     *
+     * @since 1.5
+     */
+    public static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x010000;
+
+    /**
+     * The minimum value of a
+     * <a href="http://www.unicode.org/glossary/#code_point">
+     * Unicode code point</a>, constant {@code U+0000}.
+     *
+     * @since 1.5
+     */
+    public static final int MIN_CODE_POINT = 0x000000;
+
+    /**
+     * The maximum value of a
+     * <a href="http://www.unicode.org/glossary/#code_point">
+     * Unicode code point</a>, constant {@code U+10FFFF}.
+     *
+     * @since 1.5
+     */
+    public static final int MAX_CODE_POINT = 0X10FFFF;
+
+    // BEGIN Android-added: Use ICU.
+    // The indices in int[] DIRECTIONALITY are based on icu4c's u_charDirection(),
+    // accessed via getDirectionalityImpl(), implemented in Character.cpp.
+    private static final byte[] DIRECTIONALITY = new byte[] {
+            DIRECTIONALITY_LEFT_TO_RIGHT, DIRECTIONALITY_RIGHT_TO_LEFT,
+            DIRECTIONALITY_EUROPEAN_NUMBER,
+            DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR,
+            DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR,
+            DIRECTIONALITY_ARABIC_NUMBER,
+            DIRECTIONALITY_COMMON_NUMBER_SEPARATOR,
+            DIRECTIONALITY_PARAGRAPH_SEPARATOR,
+            DIRECTIONALITY_SEGMENT_SEPARATOR, DIRECTIONALITY_WHITESPACE,
+            DIRECTIONALITY_OTHER_NEUTRALS,
+            DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING,
+            DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE,
+            DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC,
+            DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING,
+            DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE,
+            DIRECTIONALITY_POP_DIRECTIONAL_FORMAT,
+            DIRECTIONALITY_NONSPACING_MARK, DIRECTIONALITY_BOUNDARY_NEUTRAL };
+    // END Android-added: Use ICU.
+
+    /**
+     * Instances of this class represent particular subsets of the Unicode
+     * character set.  The only family of subsets defined in the
+     * {@code Character} class is {@link Character.UnicodeBlock}.
+     * Other portions of the Java API may define other subsets for their
+     * own purposes.
+     *
+     * @since 1.2
+     */
+    public static class Subset  {
+
+        private String name;
+
+        /**
+         * Constructs a new {@code Subset} instance.
+         *
+         * @param  name  The name of this subset
+         * @exception NullPointerException if name is {@code null}
+         */
+        protected Subset(String name) {
+            if (name == null) {
+                throw new NullPointerException("name");
+            }
+            this.name = name;
+        }
+
+        /**
+         * Compares two {@code Subset} objects for equality.
+         * This method returns {@code true} if and only if
+         * {@code this} and the argument refer to the same
+         * object; since this method is {@code final}, this
+         * guarantee holds for all subclasses.
+         */
+        public final boolean equals(Object obj) {
+            return (this == obj);
+        }
+
+        /**
+         * Returns the standard hash code as defined by the
+         * {@link Object#hashCode} method.  This method
+         * is {@code final} in order to ensure that the
+         * {@code equals} and {@code hashCode} methods will
+         * be consistent in all subclasses.
+         */
+        public final int hashCode() {
+            return super.hashCode();
+        }
+
+        /**
+         * Returns the name of this subset.
+         */
+        public final String toString() {
+            return name;
+        }
+    }
+
+    // See http://www.unicode.org/Public/UNIDATA/Blocks.txt
+    // for the latest specification of Unicode Blocks.
+
+    /**
+     * A family of character subsets representing the character blocks in the
+     * Unicode specification. Character blocks generally define characters
+     * used for a specific script or purpose. A character is contained by
+     * at most one Unicode block.
+     *
+     * @since 1.2
+     */
+    public static final class UnicodeBlock extends Subset {
+
+        private static Map<String, UnicodeBlock> map = new HashMap<>(256);
+
+        /**
+         * Creates a UnicodeBlock with the given identifier name.
+         * This name must be the same as the block identifier.
+         */
+        private UnicodeBlock(String idName) {
+            super(idName);
+            map.put(idName, this);
+        }
+
+        // BEGIN Android-added: ICU consistency: Don't map deprecated SURROGATES_AREA. b/26140229
+        // Add a (String, boolean) constructor for use by SURROGATES_AREA.
+        private UnicodeBlock(String idName, boolean isMap) {
+            super(idName);
+            if (isMap) {
+                map.put(idName, this);
+            }
+        }
+        // END Android-added: ICU consistency: Don't map deprecated SURROGATES_AREA. b/26140229
+
+        /**
+         * Creates a UnicodeBlock with the given identifier name and
+         * alias name.
+         */
+        private UnicodeBlock(String idName, String alias) {
+            this(idName);
+            map.put(alias, this);
+        }
+
+        /**
+         * Creates a UnicodeBlock with the given identifier name and
+         * alias names.
+         */
+        private UnicodeBlock(String idName, String... aliases) {
+            this(idName);
+            for (String alias : aliases)
+                map.put(alias, this);
+        }
+
+        /**
+         * Constant for the "Basic Latin" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock  BASIC_LATIN =
+            new UnicodeBlock("BASIC_LATIN",
+                             "BASIC LATIN",
+                             "BASICLATIN");
+
+        /**
+         * Constant for the "Latin-1 Supplement" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock LATIN_1_SUPPLEMENT =
+            new UnicodeBlock("LATIN_1_SUPPLEMENT",
+                             "LATIN-1 SUPPLEMENT",
+                             "LATIN-1SUPPLEMENT");
+
+        /**
+         * Constant for the "Latin Extended-A" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock LATIN_EXTENDED_A =
+            new UnicodeBlock("LATIN_EXTENDED_A",
+                             "LATIN EXTENDED-A",
+                             "LATINEXTENDED-A");
+
+        /**
+         * Constant for the "Latin Extended-B" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock LATIN_EXTENDED_B =
+            new UnicodeBlock("LATIN_EXTENDED_B",
+                             "LATIN EXTENDED-B",
+                             "LATINEXTENDED-B");
+
+        /**
+         * Constant for the "IPA Extensions" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock IPA_EXTENSIONS =
+            new UnicodeBlock("IPA_EXTENSIONS",
+                             "IPA EXTENSIONS",
+                             "IPAEXTENSIONS");
+
+        /**
+         * Constant for the "Spacing Modifier Letters" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock SPACING_MODIFIER_LETTERS =
+            new UnicodeBlock("SPACING_MODIFIER_LETTERS",
+                             "SPACING MODIFIER LETTERS",
+                             "SPACINGMODIFIERLETTERS");
+
+        /**
+         * Constant for the "Combining Diacritical Marks" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS =
+            new UnicodeBlock("COMBINING_DIACRITICAL_MARKS",
+                             "COMBINING DIACRITICAL MARKS",
+                             "COMBININGDIACRITICALMARKS");
+
+        /**
+         * Constant for the "Greek and Coptic" Unicode character block.
+         * <p>
+         * This block was previously known as the "Greek" block.
+         *
+         * @since 1.2
+         */
+        public static final UnicodeBlock GREEK =
+            new UnicodeBlock("GREEK",
+                             "GREEK AND COPTIC",
+                             "GREEKANDCOPTIC");
+
+        /**
+         * Constant for the "Cyrillic" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CYRILLIC =
+            new UnicodeBlock("CYRILLIC");
+
+        /**
+         * Constant for the "Armenian" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ARMENIAN =
+            new UnicodeBlock("ARMENIAN");
+
+        /**
+         * Constant for the "Hebrew" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock HEBREW =
+            new UnicodeBlock("HEBREW");
+
+        /**
+         * Constant for the "Arabic" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ARABIC =
+            new UnicodeBlock("ARABIC");
+
+        /**
+         * Constant for the "Devanagari" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock DEVANAGARI =
+            new UnicodeBlock("DEVANAGARI");
+
+        /**
+         * Constant for the "Bengali" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock BENGALI =
+            new UnicodeBlock("BENGALI");
+
+        /**
+         * Constant for the "Gurmukhi" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock GURMUKHI =
+            new UnicodeBlock("GURMUKHI");
+
+        /**
+         * Constant for the "Gujarati" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock GUJARATI =
+            new UnicodeBlock("GUJARATI");
+
+        /**
+         * Constant for the "Oriya" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ORIYA =
+            new UnicodeBlock("ORIYA");
+
+        /**
+         * Constant for the "Tamil" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock TAMIL =
+            new UnicodeBlock("TAMIL");
+
+        /**
+         * Constant for the "Telugu" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock TELUGU =
+            new UnicodeBlock("TELUGU");
+
+        /**
+         * Constant for the "Kannada" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock KANNADA =
+            new UnicodeBlock("KANNADA");
+
+        /**
+         * Constant for the "Malayalam" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock MALAYALAM =
+            new UnicodeBlock("MALAYALAM");
+
+        /**
+         * Constant for the "Thai" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock THAI =
+            new UnicodeBlock("THAI");
+
+        /**
+         * Constant for the "Lao" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock LAO =
+            new UnicodeBlock("LAO");
+
+        /**
+         * Constant for the "Tibetan" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock TIBETAN =
+            new UnicodeBlock("TIBETAN");
+
+        /**
+         * Constant for the "Georgian" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock GEORGIAN =
+            new UnicodeBlock("GEORGIAN");
+
+        /**
+         * Constant for the "Hangul Jamo" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock HANGUL_JAMO =
+            new UnicodeBlock("HANGUL_JAMO",
+                             "HANGUL JAMO",
+                             "HANGULJAMO");
+
+        /**
+         * Constant for the "Latin Extended Additional" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock LATIN_EXTENDED_ADDITIONAL =
+            new UnicodeBlock("LATIN_EXTENDED_ADDITIONAL",
+                             "LATIN EXTENDED ADDITIONAL",
+                             "LATINEXTENDEDADDITIONAL");
+
+        /**
+         * Constant for the "Greek Extended" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock GREEK_EXTENDED =
+            new UnicodeBlock("GREEK_EXTENDED",
+                             "GREEK EXTENDED",
+                             "GREEKEXTENDED");
+
+        /**
+         * Constant for the "General Punctuation" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock GENERAL_PUNCTUATION =
+            new UnicodeBlock("GENERAL_PUNCTUATION",
+                             "GENERAL PUNCTUATION",
+                             "GENERALPUNCTUATION");
+
+        /**
+         * Constant for the "Superscripts and Subscripts" Unicode character
+         * block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS =
+            new UnicodeBlock("SUPERSCRIPTS_AND_SUBSCRIPTS",
+                             "SUPERSCRIPTS AND SUBSCRIPTS",
+                             "SUPERSCRIPTSANDSUBSCRIPTS");
+
+        /**
+         * Constant for the "Currency Symbols" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CURRENCY_SYMBOLS =
+            new UnicodeBlock("CURRENCY_SYMBOLS",
+                             "CURRENCY SYMBOLS",
+                             "CURRENCYSYMBOLS");
+
+        /**
+         * Constant for the "Combining Diacritical Marks for Symbols" Unicode
+         * character block.
+         * <p>
+         * This block was previously known as "Combining Marks for Symbols".
+         * @since 1.2
+         */
+        public static final UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS =
+            new UnicodeBlock("COMBINING_MARKS_FOR_SYMBOLS",
+                             "COMBINING DIACRITICAL MARKS FOR SYMBOLS",
+                             "COMBININGDIACRITICALMARKSFORSYMBOLS",
+                             "COMBINING MARKS FOR SYMBOLS",
+                             "COMBININGMARKSFORSYMBOLS");
+
+        /**
+         * Constant for the "Letterlike Symbols" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock LETTERLIKE_SYMBOLS =
+            new UnicodeBlock("LETTERLIKE_SYMBOLS",
+                             "LETTERLIKE SYMBOLS",
+                             "LETTERLIKESYMBOLS");
+
+        /**
+         * Constant for the "Number Forms" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock NUMBER_FORMS =
+            new UnicodeBlock("NUMBER_FORMS",
+                             "NUMBER FORMS",
+                             "NUMBERFORMS");
+
+        /**
+         * Constant for the "Arrows" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ARROWS =
+            new UnicodeBlock("ARROWS");
+
+        /**
+         * Constant for the "Mathematical Operators" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock MATHEMATICAL_OPERATORS =
+            new UnicodeBlock("MATHEMATICAL_OPERATORS",
+                             "MATHEMATICAL OPERATORS",
+                             "MATHEMATICALOPERATORS");
+
+        /**
+         * Constant for the "Miscellaneous Technical" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock MISCELLANEOUS_TECHNICAL =
+            new UnicodeBlock("MISCELLANEOUS_TECHNICAL",
+                             "MISCELLANEOUS TECHNICAL",
+                             "MISCELLANEOUSTECHNICAL");
+
+        /**
+         * Constant for the "Control Pictures" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CONTROL_PICTURES =
+            new UnicodeBlock("CONTROL_PICTURES",
+                             "CONTROL PICTURES",
+                             "CONTROLPICTURES");
+
+        /**
+         * Constant for the "Optical Character Recognition" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock OPTICAL_CHARACTER_RECOGNITION =
+            new UnicodeBlock("OPTICAL_CHARACTER_RECOGNITION",
+                             "OPTICAL CHARACTER RECOGNITION",
+                             "OPTICALCHARACTERRECOGNITION");
+
+        /**
+         * Constant for the "Enclosed Alphanumerics" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ENCLOSED_ALPHANUMERICS =
+            new UnicodeBlock("ENCLOSED_ALPHANUMERICS",
+                             "ENCLOSED ALPHANUMERICS",
+                             "ENCLOSEDALPHANUMERICS");
+
+        /**
+         * Constant for the "Box Drawing" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock BOX_DRAWING =
+            new UnicodeBlock("BOX_DRAWING",
+                             "BOX DRAWING",
+                             "BOXDRAWING");
+
+        /**
+         * Constant for the "Block Elements" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock BLOCK_ELEMENTS =
+            new UnicodeBlock("BLOCK_ELEMENTS",
+                             "BLOCK ELEMENTS",
+                             "BLOCKELEMENTS");
+
+        /**
+         * Constant for the "Geometric Shapes" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock GEOMETRIC_SHAPES =
+            new UnicodeBlock("GEOMETRIC_SHAPES",
+                             "GEOMETRIC SHAPES",
+                             "GEOMETRICSHAPES");
+
+        /**
+         * Constant for the "Miscellaneous Symbols" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock MISCELLANEOUS_SYMBOLS =
+            new UnicodeBlock("MISCELLANEOUS_SYMBOLS",
+                             "MISCELLANEOUS SYMBOLS",
+                             "MISCELLANEOUSSYMBOLS");
+
+        /**
+         * Constant for the "Dingbats" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock DINGBATS =
+            new UnicodeBlock("DINGBATS");
+
+        /**
+         * Constant for the "CJK Symbols and Punctuation" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION =
+            new UnicodeBlock("CJK_SYMBOLS_AND_PUNCTUATION",
+                             "CJK SYMBOLS AND PUNCTUATION",
+                             "CJKSYMBOLSANDPUNCTUATION");
+
+        /**
+         * Constant for the "Hiragana" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock HIRAGANA =
+            new UnicodeBlock("HIRAGANA");
+
+        /**
+         * Constant for the "Katakana" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock KATAKANA =
+            new UnicodeBlock("KATAKANA");
+
+        /**
+         * Constant for the "Bopomofo" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock BOPOMOFO =
+            new UnicodeBlock("BOPOMOFO");
+
+        /**
+         * Constant for the "Hangul Compatibility Jamo" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock HANGUL_COMPATIBILITY_JAMO =
+            new UnicodeBlock("HANGUL_COMPATIBILITY_JAMO",
+                             "HANGUL COMPATIBILITY JAMO",
+                             "HANGULCOMPATIBILITYJAMO");
+
+        /**
+         * Constant for the "Kanbun" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock KANBUN =
+            new UnicodeBlock("KANBUN");
+
+        /**
+         * Constant for the "Enclosed CJK Letters and Months" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS =
+            new UnicodeBlock("ENCLOSED_CJK_LETTERS_AND_MONTHS",
+                             "ENCLOSED CJK LETTERS AND MONTHS",
+                             "ENCLOSEDCJKLETTERSANDMONTHS");
+
+        /**
+         * Constant for the "CJK Compatibility" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CJK_COMPATIBILITY =
+            new UnicodeBlock("CJK_COMPATIBILITY",
+                             "CJK COMPATIBILITY",
+                             "CJKCOMPATIBILITY");
+
+        /**
+         * Constant for the "CJK Unified Ideographs" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS =
+            new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS",
+                             "CJK UNIFIED IDEOGRAPHS",
+                             "CJKUNIFIEDIDEOGRAPHS");
+
+        /**
+         * Constant for the "Hangul Syllables" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock HANGUL_SYLLABLES =
+            new UnicodeBlock("HANGUL_SYLLABLES",
+                             "HANGUL SYLLABLES",
+                             "HANGULSYLLABLES");
+
+        /**
+         * Constant for the "Private Use Area" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock PRIVATE_USE_AREA =
+            new UnicodeBlock("PRIVATE_USE_AREA",
+                             "PRIVATE USE AREA",
+                             "PRIVATEUSEAREA");
+
+        /**
+         * Constant for the "CJK Compatibility Ideographs" Unicode character
+         * block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS =
+            new UnicodeBlock("CJK_COMPATIBILITY_IDEOGRAPHS",
+                             "CJK COMPATIBILITY IDEOGRAPHS",
+                             "CJKCOMPATIBILITYIDEOGRAPHS");
+
+        /**
+         * Constant for the "Alphabetic Presentation Forms" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ALPHABETIC_PRESENTATION_FORMS =
+            new UnicodeBlock("ALPHABETIC_PRESENTATION_FORMS",
+                             "ALPHABETIC PRESENTATION FORMS",
+                             "ALPHABETICPRESENTATIONFORMS");
+
+        /**
+         * Constant for the "Arabic Presentation Forms-A" Unicode character
+         * block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_A =
+            new UnicodeBlock("ARABIC_PRESENTATION_FORMS_A",
+                             "ARABIC PRESENTATION FORMS-A",
+                             "ARABICPRESENTATIONFORMS-A");
+
+        /**
+         * Constant for the "Combining Half Marks" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock COMBINING_HALF_MARKS =
+            new UnicodeBlock("COMBINING_HALF_MARKS",
+                             "COMBINING HALF MARKS",
+                             "COMBININGHALFMARKS");
+
+        /**
+         * Constant for the "CJK Compatibility Forms" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock CJK_COMPATIBILITY_FORMS =
+            new UnicodeBlock("CJK_COMPATIBILITY_FORMS",
+                             "CJK COMPATIBILITY FORMS",
+                             "CJKCOMPATIBILITYFORMS");
+
+        /**
+         * Constant for the "Small Form Variants" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock SMALL_FORM_VARIANTS =
+            new UnicodeBlock("SMALL_FORM_VARIANTS",
+                             "SMALL FORM VARIANTS",
+                             "SMALLFORMVARIANTS");
+
+        /**
+         * Constant for the "Arabic Presentation Forms-B" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_B =
+            new UnicodeBlock("ARABIC_PRESENTATION_FORMS_B",
+                             "ARABIC PRESENTATION FORMS-B",
+                             "ARABICPRESENTATIONFORMS-B");
+
+        /**
+         * Constant for the "Halfwidth and Fullwidth Forms" Unicode character
+         * block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS =
+            new UnicodeBlock("HALFWIDTH_AND_FULLWIDTH_FORMS",
+                             "HALFWIDTH AND FULLWIDTH FORMS",
+                             "HALFWIDTHANDFULLWIDTHFORMS");
+
+        /**
+         * Constant for the "Specials" Unicode character block.
+         * @since 1.2
+         */
+        public static final UnicodeBlock SPECIALS =
+            new UnicodeBlock("SPECIALS");
+
+        /**
+         * @deprecated As of J2SE 5, use {@link #HIGH_SURROGATES},
+         *             {@link #HIGH_PRIVATE_USE_SURROGATES}, and
+         *             {@link #LOW_SURROGATES}. These new constants match
+         *             the block definitions of the Unicode Standard.
+         *             The {@link #of(char)} and {@link #of(int)} methods
+         *             return the new constants, not SURROGATES_AREA.
+         */
+        @Deprecated
+        public static final UnicodeBlock SURROGATES_AREA =
+            // Android-changed: ICU consistency: Don't map deprecated SURROGATES_AREA. b/26140229
+            // new UnicodeBlock("SURROGATES_AREA");
+            new UnicodeBlock("SURROGATES_AREA", false);
+
+        /**
+         * Constant for the "Syriac" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock SYRIAC =
+            new UnicodeBlock("SYRIAC");
+
+        /**
+         * Constant for the "Thaana" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock THAANA =
+            new UnicodeBlock("THAANA");
+
+        /**
+         * Constant for the "Sinhala" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock SINHALA =
+            new UnicodeBlock("SINHALA");
+
+        /**
+         * Constant for the "Myanmar" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock MYANMAR =
+            new UnicodeBlock("MYANMAR");
+
+        /**
+         * Constant for the "Ethiopic" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock ETHIOPIC =
+            new UnicodeBlock("ETHIOPIC");
+
+        /**
+         * Constant for the "Cherokee" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock CHEROKEE =
+            new UnicodeBlock("CHEROKEE");
+
+        /**
+         * Constant for the "Unified Canadian Aboriginal Syllabics" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS =
+            new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS",
+                             "UNIFIED CANADIAN ABORIGINAL SYLLABICS",
+                             "UNIFIEDCANADIANABORIGINALSYLLABICS");
+
+        /**
+         * Constant for the "Ogham" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock OGHAM =
+            new UnicodeBlock("OGHAM");
+
+        /**
+         * Constant for the "Runic" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock RUNIC =
+            new UnicodeBlock("RUNIC");
+
+        /**
+         * Constant for the "Khmer" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock KHMER =
+            new UnicodeBlock("KHMER");
+
+        /**
+         * Constant for the "Mongolian" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock MONGOLIAN =
+            new UnicodeBlock("MONGOLIAN");
+
+        /**
+         * Constant for the "Braille Patterns" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock BRAILLE_PATTERNS =
+            new UnicodeBlock("BRAILLE_PATTERNS",
+                             "BRAILLE PATTERNS",
+                             "BRAILLEPATTERNS");
+
+        /**
+         * Constant for the "CJK Radicals Supplement" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock CJK_RADICALS_SUPPLEMENT =
+            new UnicodeBlock("CJK_RADICALS_SUPPLEMENT",
+                             "CJK RADICALS SUPPLEMENT",
+                             "CJKRADICALSSUPPLEMENT");
+
+        /**
+         * Constant for the "Kangxi Radicals" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock KANGXI_RADICALS =
+            new UnicodeBlock("KANGXI_RADICALS",
+                             "KANGXI RADICALS",
+                             "KANGXIRADICALS");
+
+        /**
+         * Constant for the "Ideographic Description Characters" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS =
+            new UnicodeBlock("IDEOGRAPHIC_DESCRIPTION_CHARACTERS",
+                             "IDEOGRAPHIC DESCRIPTION CHARACTERS",
+                             "IDEOGRAPHICDESCRIPTIONCHARACTERS");
+
+        /**
+         * Constant for the "Bopomofo Extended" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock BOPOMOFO_EXTENDED =
+            new UnicodeBlock("BOPOMOFO_EXTENDED",
+                             "BOPOMOFO EXTENDED",
+                             "BOPOMOFOEXTENDED");
+
+        /**
+         * Constant for the "CJK Unified Ideographs Extension A" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A =
+            new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A",
+                             "CJK UNIFIED IDEOGRAPHS EXTENSION A",
+                             "CJKUNIFIEDIDEOGRAPHSEXTENSIONA");
+
+        /**
+         * Constant for the "Yi Syllables" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock YI_SYLLABLES =
+            new UnicodeBlock("YI_SYLLABLES",
+                             "YI SYLLABLES",
+                             "YISYLLABLES");
+
+        /**
+         * Constant for the "Yi Radicals" Unicode character block.
+         * @since 1.4
+         */
+        public static final UnicodeBlock YI_RADICALS =
+            new UnicodeBlock("YI_RADICALS",
+                             "YI RADICALS",
+                             "YIRADICALS");
+
+        /**
+         * Constant for the "Cyrillic Supplementary" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock CYRILLIC_SUPPLEMENTARY =
+            new UnicodeBlock("CYRILLIC_SUPPLEMENTARY",
+                             "CYRILLIC SUPPLEMENTARY",
+                             "CYRILLICSUPPLEMENTARY",
+                             "CYRILLIC SUPPLEMENT",
+                             "CYRILLICSUPPLEMENT");
+
+        /**
+         * Constant for the "Tagalog" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock TAGALOG =
+            new UnicodeBlock("TAGALOG");
+
+        /**
+         * Constant for the "Hanunoo" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock HANUNOO =
+            new UnicodeBlock("HANUNOO");
+
+        /**
+         * Constant for the "Buhid" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock BUHID =
+            new UnicodeBlock("BUHID");
+
+        /**
+         * Constant for the "Tagbanwa" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock TAGBANWA =
+            new UnicodeBlock("TAGBANWA");
+
+        /**
+         * Constant for the "Limbu" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock LIMBU =
+            new UnicodeBlock("LIMBU");
+
+        /**
+         * Constant for the "Tai Le" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock TAI_LE =
+            new UnicodeBlock("TAI_LE",
+                             "TAI LE",
+                             "TAILE");
+
+        /**
+         * Constant for the "Khmer Symbols" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock KHMER_SYMBOLS =
+            new UnicodeBlock("KHMER_SYMBOLS",
+                             "KHMER SYMBOLS",
+                             "KHMERSYMBOLS");
+
+        /**
+         * Constant for the "Phonetic Extensions" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock PHONETIC_EXTENSIONS =
+            new UnicodeBlock("PHONETIC_EXTENSIONS",
+                             "PHONETIC EXTENSIONS",
+                             "PHONETICEXTENSIONS");
+
+        /**
+         * Constant for the "Miscellaneous Mathematical Symbols-A" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A =
+            new UnicodeBlock("MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A",
+                             "MISCELLANEOUS MATHEMATICAL SYMBOLS-A",
+                             "MISCELLANEOUSMATHEMATICALSYMBOLS-A");
+
+        /**
+         * Constant for the "Supplemental Arrows-A" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock SUPPLEMENTAL_ARROWS_A =
+            new UnicodeBlock("SUPPLEMENTAL_ARROWS_A",
+                             "SUPPLEMENTAL ARROWS-A",
+                             "SUPPLEMENTALARROWS-A");
+
+        /**
+         * Constant for the "Supplemental Arrows-B" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock SUPPLEMENTAL_ARROWS_B =
+            new UnicodeBlock("SUPPLEMENTAL_ARROWS_B",
+                             "SUPPLEMENTAL ARROWS-B",
+                             "SUPPLEMENTALARROWS-B");
+
+        /**
+         * Constant for the "Miscellaneous Mathematical Symbols-B" Unicode
+         * character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B =
+            new UnicodeBlock("MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B",
+                             "MISCELLANEOUS MATHEMATICAL SYMBOLS-B",
+                             "MISCELLANEOUSMATHEMATICALSYMBOLS-B");
+
+        /**
+         * Constant for the "Supplemental Mathematical Operators" Unicode
+         * character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS =
+            new UnicodeBlock("SUPPLEMENTAL_MATHEMATICAL_OPERATORS",
+                             "SUPPLEMENTAL MATHEMATICAL OPERATORS",
+                             "SUPPLEMENTALMATHEMATICALOPERATORS");
+
+        /**
+         * Constant for the "Miscellaneous Symbols and Arrows" Unicode character
+         * block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS =
+            new UnicodeBlock("MISCELLANEOUS_SYMBOLS_AND_ARROWS",
+                             "MISCELLANEOUS SYMBOLS AND ARROWS",
+                             "MISCELLANEOUSSYMBOLSANDARROWS");
+
+        /**
+         * Constant for the "Katakana Phonetic Extensions" Unicode character
+         * block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS =
+            new UnicodeBlock("KATAKANA_PHONETIC_EXTENSIONS",
+                             "KATAKANA PHONETIC EXTENSIONS",
+                             "KATAKANAPHONETICEXTENSIONS");
+
+        /**
+         * Constant for the "Yijing Hexagram Symbols" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock YIJING_HEXAGRAM_SYMBOLS =
+            new UnicodeBlock("YIJING_HEXAGRAM_SYMBOLS",
+                             "YIJING HEXAGRAM SYMBOLS",
+                             "YIJINGHEXAGRAMSYMBOLS");
+
+        /**
+         * Constant for the "Variation Selectors" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock VARIATION_SELECTORS =
+            new UnicodeBlock("VARIATION_SELECTORS",
+                             "VARIATION SELECTORS",
+                             "VARIATIONSELECTORS");
+
+        /**
+         * Constant for the "Linear B Syllabary" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock LINEAR_B_SYLLABARY =
+            new UnicodeBlock("LINEAR_B_SYLLABARY",
+                             "LINEAR B SYLLABARY",
+                             "LINEARBSYLLABARY");
+
+        /**
+         * Constant for the "Linear B Ideograms" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock LINEAR_B_IDEOGRAMS =
+            new UnicodeBlock("LINEAR_B_IDEOGRAMS",
+                             "LINEAR B IDEOGRAMS",
+                             "LINEARBIDEOGRAMS");
+
+        /**
+         * Constant for the "Aegean Numbers" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock AEGEAN_NUMBERS =
+            new UnicodeBlock("AEGEAN_NUMBERS",
+                             "AEGEAN NUMBERS",
+                             "AEGEANNUMBERS");
+
+        /**
+         * Constant for the "Old Italic" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock OLD_ITALIC =
+            new UnicodeBlock("OLD_ITALIC",
+                             "OLD ITALIC",
+                             "OLDITALIC");
+
+        /**
+         * Constant for the "Gothic" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock GOTHIC =
+            new UnicodeBlock("GOTHIC");
+
+        /**
+         * Constant for the "Ugaritic" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock UGARITIC =
+            new UnicodeBlock("UGARITIC");
+
+        /**
+         * Constant for the "Deseret" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock DESERET =
+            new UnicodeBlock("DESERET");
+
+        /**
+         * Constant for the "Shavian" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock SHAVIAN =
+            new UnicodeBlock("SHAVIAN");
+
+        /**
+         * Constant for the "Osmanya" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock OSMANYA =
+            new UnicodeBlock("OSMANYA");
+
+        /**
+         * Constant for the "Cypriot Syllabary" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock CYPRIOT_SYLLABARY =
+            new UnicodeBlock("CYPRIOT_SYLLABARY",
+                             "CYPRIOT SYLLABARY",
+                             "CYPRIOTSYLLABARY");
+
+        /**
+         * Constant for the "Byzantine Musical Symbols" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS =
+            new UnicodeBlock("BYZANTINE_MUSICAL_SYMBOLS",
+                             "BYZANTINE MUSICAL SYMBOLS",
+                             "BYZANTINEMUSICALSYMBOLS");
+
+        /**
+         * Constant for the "Musical Symbols" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock MUSICAL_SYMBOLS =
+            new UnicodeBlock("MUSICAL_SYMBOLS",
+                             "MUSICAL SYMBOLS",
+                             "MUSICALSYMBOLS");
+
+        /**
+         * Constant for the "Tai Xuan Jing Symbols" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock TAI_XUAN_JING_SYMBOLS =
+            new UnicodeBlock("TAI_XUAN_JING_SYMBOLS",
+                             "TAI XUAN JING SYMBOLS",
+                             "TAIXUANJINGSYMBOLS");
+
+        /**
+         * Constant for the "Mathematical Alphanumeric Symbols" Unicode
+         * character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS =
+            new UnicodeBlock("MATHEMATICAL_ALPHANUMERIC_SYMBOLS",
+                             "MATHEMATICAL ALPHANUMERIC SYMBOLS",
+                             "MATHEMATICALALPHANUMERICSYMBOLS");
+
+        /**
+         * Constant for the "CJK Unified Ideographs Extension B" Unicode
+         * character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B =
+            new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B",
+                             "CJK UNIFIED IDEOGRAPHS EXTENSION B",
+                             "CJKUNIFIEDIDEOGRAPHSEXTENSIONB");
+
+        /**
+         * Constant for the "CJK Compatibility Ideographs Supplement" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT =
+            new UnicodeBlock("CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT",
+                             "CJK COMPATIBILITY IDEOGRAPHS SUPPLEMENT",
+                             "CJKCOMPATIBILITYIDEOGRAPHSSUPPLEMENT");
+
+        /**
+         * Constant for the "Tags" Unicode character block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock TAGS =
+            new UnicodeBlock("TAGS");
+
+        /**
+         * Constant for the "Variation Selectors Supplement" Unicode character
+         * block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT =
+            new UnicodeBlock("VARIATION_SELECTORS_SUPPLEMENT",
+                             "VARIATION SELECTORS SUPPLEMENT",
+                             "VARIATIONSELECTORSSUPPLEMENT");
+
+        /**
+         * Constant for the "Supplementary Private Use Area-A" Unicode character
+         * block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A =
+            new UnicodeBlock("SUPPLEMENTARY_PRIVATE_USE_AREA_A",
+                             "SUPPLEMENTARY PRIVATE USE AREA-A",
+                             "SUPPLEMENTARYPRIVATEUSEAREA-A");
+
+        /**
+         * Constant for the "Supplementary Private Use Area-B" Unicode character
+         * block.
+         * @since 1.5
+         */
+        public static final UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B =
+            new UnicodeBlock("SUPPLEMENTARY_PRIVATE_USE_AREA_B",
+                             "SUPPLEMENTARY PRIVATE USE AREA-B",
+                             "SUPPLEMENTARYPRIVATEUSEAREA-B");
+
+        /**
+         * Constant for the "High Surrogates" Unicode character block.
+         * This block represents codepoint values in the high surrogate
+         * range: U+D800 through U+DB7F
+         *
+         * @since 1.5
+         */
+        public static final UnicodeBlock HIGH_SURROGATES =
+            new UnicodeBlock("HIGH_SURROGATES",
+                             "HIGH SURROGATES",
+                             "HIGHSURROGATES");
+
+        /**
+         * Constant for the "High Private Use Surrogates" Unicode character
+         * block.
+         * This block represents codepoint values in the private use high
+         * surrogate range: U+DB80 through U+DBFF
+         *
+         * @since 1.5
+         */
+        public static final UnicodeBlock HIGH_PRIVATE_USE_SURROGATES =
+            new UnicodeBlock("HIGH_PRIVATE_USE_SURROGATES",
+                             "HIGH PRIVATE USE SURROGATES",
+                             "HIGHPRIVATEUSESURROGATES");
+
+        /**
+         * Constant for the "Low Surrogates" Unicode character block.
+         * This block represents codepoint values in the low surrogate
+         * range: U+DC00 through U+DFFF
+         *
+         * @since 1.5
+         */
+        public static final UnicodeBlock LOW_SURROGATES =
+            new UnicodeBlock("LOW_SURROGATES",
+                             "LOW SURROGATES",
+                             "LOWSURROGATES");
+
+        /**
+         * Constant for the "Arabic Supplement" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ARABIC_SUPPLEMENT =
+            new UnicodeBlock("ARABIC_SUPPLEMENT",
+                             "ARABIC SUPPLEMENT",
+                             "ARABICSUPPLEMENT");
+
+        /**
+         * Constant for the "NKo" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock NKO =
+            new UnicodeBlock("NKO");
+
+        /**
+         * Constant for the "Samaritan" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock SAMARITAN =
+            new UnicodeBlock("SAMARITAN");
+
+        /**
+         * Constant for the "Mandaic" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock MANDAIC =
+            new UnicodeBlock("MANDAIC");
+
+        /**
+         * Constant for the "Ethiopic Supplement" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ETHIOPIC_SUPPLEMENT =
+            new UnicodeBlock("ETHIOPIC_SUPPLEMENT",
+                             "ETHIOPIC SUPPLEMENT",
+                             "ETHIOPICSUPPLEMENT");
+
+        /**
+         * Constant for the "Unified Canadian Aboriginal Syllabics Extended"
+         * Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED =
+            new UnicodeBlock("UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED",
+                             "UNIFIED CANADIAN ABORIGINAL SYLLABICS EXTENDED",
+                             "UNIFIEDCANADIANABORIGINALSYLLABICSEXTENDED");
+
+        /**
+         * Constant for the "New Tai Lue" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock NEW_TAI_LUE =
+            new UnicodeBlock("NEW_TAI_LUE",
+                             "NEW TAI LUE",
+                             "NEWTAILUE");
+
+        /**
+         * Constant for the "Buginese" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock BUGINESE =
+            new UnicodeBlock("BUGINESE");
+
+        /**
+         * Constant for the "Tai Tham" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock TAI_THAM =
+            new UnicodeBlock("TAI_THAM",
+                             "TAI THAM",
+                             "TAITHAM");
+
+        /**
+         * Constant for the "Balinese" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock BALINESE =
+            new UnicodeBlock("BALINESE");
+
+        /**
+         * Constant for the "Sundanese" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock SUNDANESE =
+            new UnicodeBlock("SUNDANESE");
+
+        /**
+         * Constant for the "Batak" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock BATAK =
+            new UnicodeBlock("BATAK");
+
+        /**
+         * Constant for the "Lepcha" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock LEPCHA =
+            new UnicodeBlock("LEPCHA");
+
+        /**
+         * Constant for the "Ol Chiki" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock OL_CHIKI =
+            new UnicodeBlock("OL_CHIKI",
+                             "OL CHIKI",
+                             "OLCHIKI");
+
+        /**
+         * Constant for the "Vedic Extensions" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock VEDIC_EXTENSIONS =
+            new UnicodeBlock("VEDIC_EXTENSIONS",
+                             "VEDIC EXTENSIONS",
+                             "VEDICEXTENSIONS");
+
+        /**
+         * Constant for the "Phonetic Extensions Supplement" Unicode character
+         * block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock PHONETIC_EXTENSIONS_SUPPLEMENT =
+            new UnicodeBlock("PHONETIC_EXTENSIONS_SUPPLEMENT",
+                             "PHONETIC EXTENSIONS SUPPLEMENT",
+                             "PHONETICEXTENSIONSSUPPLEMENT");
+
+        /**
+         * Constant for the "Combining Diacritical Marks Supplement" Unicode
+         * character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS_SUPPLEMENT =
+            new UnicodeBlock("COMBINING_DIACRITICAL_MARKS_SUPPLEMENT",
+                             "COMBINING DIACRITICAL MARKS SUPPLEMENT",
+                             "COMBININGDIACRITICALMARKSSUPPLEMENT");
+
+        /**
+         * Constant for the "Glagolitic" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock GLAGOLITIC =
+            new UnicodeBlock("GLAGOLITIC");
+
+        /**
+         * Constant for the "Latin Extended-C" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock LATIN_EXTENDED_C =
+            new UnicodeBlock("LATIN_EXTENDED_C",
+                             "LATIN EXTENDED-C",
+                             "LATINEXTENDED-C");
+
+        /**
+         * Constant for the "Coptic" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock COPTIC =
+            new UnicodeBlock("COPTIC");
+
+        /**
+         * Constant for the "Georgian Supplement" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock GEORGIAN_SUPPLEMENT =
+            new UnicodeBlock("GEORGIAN_SUPPLEMENT",
+                             "GEORGIAN SUPPLEMENT",
+                             "GEORGIANSUPPLEMENT");
+
+        /**
+         * Constant for the "Tifinagh" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock TIFINAGH =
+            new UnicodeBlock("TIFINAGH");
+
+        /**
+         * Constant for the "Ethiopic Extended" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ETHIOPIC_EXTENDED =
+            new UnicodeBlock("ETHIOPIC_EXTENDED",
+                             "ETHIOPIC EXTENDED",
+                             "ETHIOPICEXTENDED");
+
+        /**
+         * Constant for the "Cyrillic Extended-A" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CYRILLIC_EXTENDED_A =
+            new UnicodeBlock("CYRILLIC_EXTENDED_A",
+                             "CYRILLIC EXTENDED-A",
+                             "CYRILLICEXTENDED-A");
+
+        /**
+         * Constant for the "Supplemental Punctuation" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock SUPPLEMENTAL_PUNCTUATION =
+            new UnicodeBlock("SUPPLEMENTAL_PUNCTUATION",
+                             "SUPPLEMENTAL PUNCTUATION",
+                             "SUPPLEMENTALPUNCTUATION");
+
+        /**
+         * Constant for the "CJK Strokes" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CJK_STROKES =
+            new UnicodeBlock("CJK_STROKES",
+                             "CJK STROKES",
+                             "CJKSTROKES");
+
+        /**
+         * Constant for the "Lisu" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock LISU =
+            new UnicodeBlock("LISU");
+
+        /**
+         * Constant for the "Vai" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock VAI =
+            new UnicodeBlock("VAI");
+
+        /**
+         * Constant for the "Cyrillic Extended-B" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CYRILLIC_EXTENDED_B =
+            new UnicodeBlock("CYRILLIC_EXTENDED_B",
+                             "CYRILLIC EXTENDED-B",
+                             "CYRILLICEXTENDED-B");
+
+        /**
+         * Constant for the "Bamum" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock BAMUM =
+            new UnicodeBlock("BAMUM");
+
+        /**
+         * Constant for the "Modifier Tone Letters" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock MODIFIER_TONE_LETTERS =
+            new UnicodeBlock("MODIFIER_TONE_LETTERS",
+                             "MODIFIER TONE LETTERS",
+                             "MODIFIERTONELETTERS");
+
+        /**
+         * Constant for the "Latin Extended-D" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock LATIN_EXTENDED_D =
+            new UnicodeBlock("LATIN_EXTENDED_D",
+                             "LATIN EXTENDED-D",
+                             "LATINEXTENDED-D");
+
+        /**
+         * Constant for the "Syloti Nagri" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock SYLOTI_NAGRI =
+            new UnicodeBlock("SYLOTI_NAGRI",
+                             "SYLOTI NAGRI",
+                             "SYLOTINAGRI");
+
+        /**
+         * Constant for the "Common Indic Number Forms" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock COMMON_INDIC_NUMBER_FORMS =
+            new UnicodeBlock("COMMON_INDIC_NUMBER_FORMS",
+                             "COMMON INDIC NUMBER FORMS",
+                             "COMMONINDICNUMBERFORMS");
+
+        /**
+         * Constant for the "Phags-pa" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock PHAGS_PA =
+            new UnicodeBlock("PHAGS_PA",
+                             "PHAGS-PA");
+
+        /**
+         * Constant for the "Saurashtra" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock SAURASHTRA =
+            new UnicodeBlock("SAURASHTRA");
+
+        /**
+         * Constant for the "Devanagari Extended" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock DEVANAGARI_EXTENDED =
+            new UnicodeBlock("DEVANAGARI_EXTENDED",
+                             "DEVANAGARI EXTENDED",
+                             "DEVANAGARIEXTENDED");
+
+        /**
+         * Constant for the "Kayah Li" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock KAYAH_LI =
+            new UnicodeBlock("KAYAH_LI",
+                             "KAYAH LI",
+                             "KAYAHLI");
+
+        /**
+         * Constant for the "Rejang" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock REJANG =
+            new UnicodeBlock("REJANG");
+
+        /**
+         * Constant for the "Hangul Jamo Extended-A" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock HANGUL_JAMO_EXTENDED_A =
+            new UnicodeBlock("HANGUL_JAMO_EXTENDED_A",
+                             "HANGUL JAMO EXTENDED-A",
+                             "HANGULJAMOEXTENDED-A");
+
+        /**
+         * Constant for the "Javanese" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock JAVANESE =
+            new UnicodeBlock("JAVANESE");
+
+        /**
+         * Constant for the "Cham" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CHAM =
+            new UnicodeBlock("CHAM");
+
+        /**
+         * Constant for the "Myanmar Extended-A" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock MYANMAR_EXTENDED_A =
+            new UnicodeBlock("MYANMAR_EXTENDED_A",
+                             "MYANMAR EXTENDED-A",
+                             "MYANMAREXTENDED-A");
+
+        /**
+         * Constant for the "Tai Viet" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock TAI_VIET =
+            new UnicodeBlock("TAI_VIET",
+                             "TAI VIET",
+                             "TAIVIET");
+
+        /**
+         * Constant for the "Ethiopic Extended-A" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ETHIOPIC_EXTENDED_A =
+            new UnicodeBlock("ETHIOPIC_EXTENDED_A",
+                             "ETHIOPIC EXTENDED-A",
+                             "ETHIOPICEXTENDED-A");
+
+        /**
+         * Constant for the "Meetei Mayek" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock MEETEI_MAYEK =
+            new UnicodeBlock("MEETEI_MAYEK",
+                             "MEETEI MAYEK",
+                             "MEETEIMAYEK");
+
+        /**
+         * Constant for the "Hangul Jamo Extended-B" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock HANGUL_JAMO_EXTENDED_B =
+            new UnicodeBlock("HANGUL_JAMO_EXTENDED_B",
+                             "HANGUL JAMO EXTENDED-B",
+                             "HANGULJAMOEXTENDED-B");
+
+        /**
+         * Constant for the "Vertical Forms" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock VERTICAL_FORMS =
+            new UnicodeBlock("VERTICAL_FORMS",
+                             "VERTICAL FORMS",
+                             "VERTICALFORMS");
+
+        /**
+         * Constant for the "Ancient Greek Numbers" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ANCIENT_GREEK_NUMBERS =
+            new UnicodeBlock("ANCIENT_GREEK_NUMBERS",
+                             "ANCIENT GREEK NUMBERS",
+                             "ANCIENTGREEKNUMBERS");
+
+        /**
+         * Constant for the "Ancient Symbols" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ANCIENT_SYMBOLS =
+            new UnicodeBlock("ANCIENT_SYMBOLS",
+                             "ANCIENT SYMBOLS",
+                             "ANCIENTSYMBOLS");
+
+        /**
+         * Constant for the "Phaistos Disc" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock PHAISTOS_DISC =
+            new UnicodeBlock("PHAISTOS_DISC",
+                             "PHAISTOS DISC",
+                             "PHAISTOSDISC");
+
+        /**
+         * Constant for the "Lycian" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock LYCIAN =
+            new UnicodeBlock("LYCIAN");
+
+        /**
+         * Constant for the "Carian" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CARIAN =
+            new UnicodeBlock("CARIAN");
+
+        /**
+         * Constant for the "Old Persian" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock OLD_PERSIAN =
+            new UnicodeBlock("OLD_PERSIAN",
+                             "OLD PERSIAN",
+                             "OLDPERSIAN");
+
+        /**
+         * Constant for the "Imperial Aramaic" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock IMPERIAL_ARAMAIC =
+            new UnicodeBlock("IMPERIAL_ARAMAIC",
+                             "IMPERIAL ARAMAIC",
+                             "IMPERIALARAMAIC");
+
+        /**
+         * Constant for the "Phoenician" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock PHOENICIAN =
+            new UnicodeBlock("PHOENICIAN");
+
+        /**
+         * Constant for the "Lydian" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock LYDIAN =
+            new UnicodeBlock("LYDIAN");
+
+        /**
+         * Constant for the "Kharoshthi" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock KHAROSHTHI =
+            new UnicodeBlock("KHAROSHTHI");
+
+        /**
+         * Constant for the "Old South Arabian" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock OLD_SOUTH_ARABIAN =
+            new UnicodeBlock("OLD_SOUTH_ARABIAN",
+                             "OLD SOUTH ARABIAN",
+                             "OLDSOUTHARABIAN");
+
+        /**
+         * Constant for the "Avestan" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock AVESTAN =
+            new UnicodeBlock("AVESTAN");
+
+        /**
+         * Constant for the "Inscriptional Parthian" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock INSCRIPTIONAL_PARTHIAN =
+            new UnicodeBlock("INSCRIPTIONAL_PARTHIAN",
+                             "INSCRIPTIONAL PARTHIAN",
+                             "INSCRIPTIONALPARTHIAN");
+
+        /**
+         * Constant for the "Inscriptional Pahlavi" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock INSCRIPTIONAL_PAHLAVI =
+            new UnicodeBlock("INSCRIPTIONAL_PAHLAVI",
+                             "INSCRIPTIONAL PAHLAVI",
+                             "INSCRIPTIONALPAHLAVI");
+
+        /**
+         * Constant for the "Old Turkic" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock OLD_TURKIC =
+            new UnicodeBlock("OLD_TURKIC",
+                             "OLD TURKIC",
+                             "OLDTURKIC");
+
+        /**
+         * Constant for the "Rumi Numeral Symbols" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock RUMI_NUMERAL_SYMBOLS =
+            new UnicodeBlock("RUMI_NUMERAL_SYMBOLS",
+                             "RUMI NUMERAL SYMBOLS",
+                             "RUMINUMERALSYMBOLS");
+
+        /**
+         * Constant for the "Brahmi" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock BRAHMI =
+            new UnicodeBlock("BRAHMI");
+
+        /**
+         * Constant for the "Kaithi" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock KAITHI =
+            new UnicodeBlock("KAITHI");
+
+        /**
+         * Constant for the "Cuneiform" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CUNEIFORM =
+            new UnicodeBlock("CUNEIFORM");
+
+        /**
+         * Constant for the "Cuneiform Numbers and Punctuation" Unicode
+         * character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CUNEIFORM_NUMBERS_AND_PUNCTUATION =
+            new UnicodeBlock("CUNEIFORM_NUMBERS_AND_PUNCTUATION",
+                             "CUNEIFORM NUMBERS AND PUNCTUATION",
+                             "CUNEIFORMNUMBERSANDPUNCTUATION");
+
+        /**
+         * Constant for the "Egyptian Hieroglyphs" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock EGYPTIAN_HIEROGLYPHS =
+            new UnicodeBlock("EGYPTIAN_HIEROGLYPHS",
+                             "EGYPTIAN HIEROGLYPHS",
+                             "EGYPTIANHIEROGLYPHS");
+
+        /**
+         * Constant for the "Bamum Supplement" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock BAMUM_SUPPLEMENT =
+            new UnicodeBlock("BAMUM_SUPPLEMENT",
+                             "BAMUM SUPPLEMENT",
+                             "BAMUMSUPPLEMENT");
+
+        /**
+         * Constant for the "Kana Supplement" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock KANA_SUPPLEMENT =
+            new UnicodeBlock("KANA_SUPPLEMENT",
+                             "KANA SUPPLEMENT",
+                             "KANASUPPLEMENT");
+
+        /**
+         * Constant for the "Ancient Greek Musical Notation" Unicode character
+         * block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ANCIENT_GREEK_MUSICAL_NOTATION =
+            new UnicodeBlock("ANCIENT_GREEK_MUSICAL_NOTATION",
+                             "ANCIENT GREEK MUSICAL NOTATION",
+                             "ANCIENTGREEKMUSICALNOTATION");
+
+        /**
+         * Constant for the "Counting Rod Numerals" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock COUNTING_ROD_NUMERALS =
+            new UnicodeBlock("COUNTING_ROD_NUMERALS",
+                             "COUNTING ROD NUMERALS",
+                             "COUNTINGRODNUMERALS");
+
+        /**
+         * Constant for the "Mahjong Tiles" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock MAHJONG_TILES =
+            new UnicodeBlock("MAHJONG_TILES",
+                             "MAHJONG TILES",
+                             "MAHJONGTILES");
+
+        /**
+         * Constant for the "Domino Tiles" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock DOMINO_TILES =
+            new UnicodeBlock("DOMINO_TILES",
+                             "DOMINO TILES",
+                             "DOMINOTILES");
+
+        /**
+         * Constant for the "Playing Cards" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock PLAYING_CARDS =
+            new UnicodeBlock("PLAYING_CARDS",
+                             "PLAYING CARDS",
+                             "PLAYINGCARDS");
+
+        /**
+         * Constant for the "Enclosed Alphanumeric Supplement" Unicode character
+         * block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ENCLOSED_ALPHANUMERIC_SUPPLEMENT =
+            new UnicodeBlock("ENCLOSED_ALPHANUMERIC_SUPPLEMENT",
+                             "ENCLOSED ALPHANUMERIC SUPPLEMENT",
+                             "ENCLOSEDALPHANUMERICSUPPLEMENT");
+
+        /**
+         * Constant for the "Enclosed Ideographic Supplement" Unicode character
+         * block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ENCLOSED_IDEOGRAPHIC_SUPPLEMENT =
+            new UnicodeBlock("ENCLOSED_IDEOGRAPHIC_SUPPLEMENT",
+                             "ENCLOSED IDEOGRAPHIC SUPPLEMENT",
+                             "ENCLOSEDIDEOGRAPHICSUPPLEMENT");
+
+        /**
+         * Constant for the "Miscellaneous Symbols And Pictographs" Unicode
+         * character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS =
+            new UnicodeBlock("MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS",
+                             "MISCELLANEOUS SYMBOLS AND PICTOGRAPHS",
+                             "MISCELLANEOUSSYMBOLSANDPICTOGRAPHS");
+
+        /**
+         * Constant for the "Emoticons" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock EMOTICONS =
+            new UnicodeBlock("EMOTICONS");
+
+        /**
+         * Constant for the "Transport And Map Symbols" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock TRANSPORT_AND_MAP_SYMBOLS =
+            new UnicodeBlock("TRANSPORT_AND_MAP_SYMBOLS",
+                             "TRANSPORT AND MAP SYMBOLS",
+                             "TRANSPORTANDMAPSYMBOLS");
+
+        /**
+         * Constant for the "Alchemical Symbols" Unicode character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock ALCHEMICAL_SYMBOLS =
+            new UnicodeBlock("ALCHEMICAL_SYMBOLS",
+                             "ALCHEMICAL SYMBOLS",
+                             "ALCHEMICALSYMBOLS");
+
+        /**
+         * Constant for the "CJK Unified Ideographs Extension C" Unicode
+         * character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C =
+            new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C",
+                             "CJK UNIFIED IDEOGRAPHS EXTENSION C",
+                             "CJKUNIFIEDIDEOGRAPHSEXTENSIONC");
+
+        /**
+         * Constant for the "CJK Unified Ideographs Extension D" Unicode
+         * character block.
+         * @since 1.7
+         */
+        public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D =
+            new UnicodeBlock("CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D",
+                             "CJK UNIFIED IDEOGRAPHS EXTENSION D",
+                             "CJKUNIFIEDIDEOGRAPHSEXTENSIOND");
+
+        /**
+         * Constant for the "Arabic Extended-A" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock ARABIC_EXTENDED_A =
+            new UnicodeBlock("ARABIC_EXTENDED_A",
+                             "ARABIC EXTENDED-A",
+                             "ARABICEXTENDED-A");
+
+        /**
+         * Constant for the "Sundanese Supplement" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock SUNDANESE_SUPPLEMENT =
+            new UnicodeBlock("SUNDANESE_SUPPLEMENT",
+                             "SUNDANESE SUPPLEMENT",
+                             "SUNDANESESUPPLEMENT");
+
+        /**
+         * Constant for the "Meetei Mayek Extensions" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock MEETEI_MAYEK_EXTENSIONS =
+            new UnicodeBlock("MEETEI_MAYEK_EXTENSIONS",
+                             "MEETEI MAYEK EXTENSIONS",
+                             "MEETEIMAYEKEXTENSIONS");
+
+        /**
+         * Constant for the "Meroitic Hieroglyphs" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock MEROITIC_HIEROGLYPHS =
+            new UnicodeBlock("MEROITIC_HIEROGLYPHS",
+                             "MEROITIC HIEROGLYPHS",
+                             "MEROITICHIEROGLYPHS");
+
+        /**
+         * Constant for the "Meroitic Cursive" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock MEROITIC_CURSIVE =
+            new UnicodeBlock("MEROITIC_CURSIVE",
+                             "MEROITIC CURSIVE",
+                             "MEROITICCURSIVE");
+
+        /**
+         * Constant for the "Sora Sompeng" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock SORA_SOMPENG =
+            new UnicodeBlock("SORA_SOMPENG",
+                             "SORA SOMPENG",
+                             "SORASOMPENG");
+
+        /**
+         * Constant for the "Chakma" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock CHAKMA =
+            new UnicodeBlock("CHAKMA");
+
+        /**
+         * Constant for the "Sharada" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock SHARADA =
+            new UnicodeBlock("SHARADA");
+
+        /**
+         * Constant for the "Takri" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock TAKRI =
+            new UnicodeBlock("TAKRI");
+
+        /**
+         * Constant for the "Miao" Unicode character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock MIAO =
+            new UnicodeBlock("MIAO");
+
+        /**
+         * Constant for the "Arabic Mathematical Alphabetic Symbols" Unicode
+         * character block.
+         * @since 1.8
+         */
+        public static final UnicodeBlock ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS =
+            new UnicodeBlock("ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS",
+                             "ARABIC MATHEMATICAL ALPHABETIC SYMBOLS",
+                             "ARABICMATHEMATICALALPHABETICSYMBOLS");
+
+        private static final int blockStarts[] = {
+            0x0000,   // 0000..007F; Basic Latin
+            0x0080,   // 0080..00FF; Latin-1 Supplement
+            0x0100,   // 0100..017F; Latin Extended-A
+            0x0180,   // 0180..024F; Latin Extended-B
+            0x0250,   // 0250..02AF; IPA Extensions
+            0x02B0,   // 02B0..02FF; Spacing Modifier Letters
+            0x0300,   // 0300..036F; Combining Diacritical Marks
+            0x0370,   // 0370..03FF; Greek and Coptic
+            0x0400,   // 0400..04FF; Cyrillic
+            0x0500,   // 0500..052F; Cyrillic Supplement
+            0x0530,   // 0530..058F; Armenian
+            0x0590,   // 0590..05FF; Hebrew
+            0x0600,   // 0600..06FF; Arabic
+            0x0700,   // 0700..074F; Syriac
+            0x0750,   // 0750..077F; Arabic Supplement
+            0x0780,   // 0780..07BF; Thaana
+            0x07C0,   // 07C0..07FF; NKo
+            0x0800,   // 0800..083F; Samaritan
+            0x0840,   // 0840..085F; Mandaic
+            0x0860,   //             unassigned
+            0x08A0,   // 08A0..08FF; Arabic Extended-A
+            0x0900,   // 0900..097F; Devanagari
+            0x0980,   // 0980..09FF; Bengali
+            0x0A00,   // 0A00..0A7F; Gurmukhi
+            0x0A80,   // 0A80..0AFF; Gujarati
+            0x0B00,   // 0B00..0B7F; Oriya
+            0x0B80,   // 0B80..0BFF; Tamil
+            0x0C00,   // 0C00..0C7F; Telugu
+            0x0C80,   // 0C80..0CFF; Kannada
+            0x0D00,   // 0D00..0D7F; Malayalam
+            0x0D80,   // 0D80..0DFF; Sinhala
+            0x0E00,   // 0E00..0E7F; Thai
+            0x0E80,   // 0E80..0EFF; Lao
+            0x0F00,   // 0F00..0FFF; Tibetan
+            0x1000,   // 1000..109F; Myanmar
+            0x10A0,   // 10A0..10FF; Georgian
+            0x1100,   // 1100..11FF; Hangul Jamo
+            0x1200,   // 1200..137F; Ethiopic
+            0x1380,   // 1380..139F; Ethiopic Supplement
+            0x13A0,   // 13A0..13FF; Cherokee
+            0x1400,   // 1400..167F; Unified Canadian Aboriginal Syllabics
+            0x1680,   // 1680..169F; Ogham
+            0x16A0,   // 16A0..16FF; Runic
+            0x1700,   // 1700..171F; Tagalog
+            0x1720,   // 1720..173F; Hanunoo
+            0x1740,   // 1740..175F; Buhid
+            0x1760,   // 1760..177F; Tagbanwa
+            0x1780,   // 1780..17FF; Khmer
+            0x1800,   // 1800..18AF; Mongolian
+            0x18B0,   // 18B0..18FF; Unified Canadian Aboriginal Syllabics Extended
+            0x1900,   // 1900..194F; Limbu
+            0x1950,   // 1950..197F; Tai Le
+            0x1980,   // 1980..19DF; New Tai Lue
+            0x19E0,   // 19E0..19FF; Khmer Symbols
+            0x1A00,   // 1A00..1A1F; Buginese
+            0x1A20,   // 1A20..1AAF; Tai Tham
+            0x1AB0,   //             unassigned
+            0x1B00,   // 1B00..1B7F; Balinese
+            0x1B80,   // 1B80..1BBF; Sundanese
+            0x1BC0,   // 1BC0..1BFF; Batak
+            0x1C00,   // 1C00..1C4F; Lepcha
+            0x1C50,   // 1C50..1C7F; Ol Chiki
+            0x1C80,   //             unassigned
+            0x1CC0,   // 1CC0..1CCF; Sundanese Supplement
+            0x1CD0,   // 1CD0..1CFF; Vedic Extensions
+            0x1D00,   // 1D00..1D7F; Phonetic Extensions
+            0x1D80,   // 1D80..1DBF; Phonetic Extensions Supplement
+            0x1DC0,   // 1DC0..1DFF; Combining Diacritical Marks Supplement
+            0x1E00,   // 1E00..1EFF; Latin Extended Additional
+            0x1F00,   // 1F00..1FFF; Greek Extended
+            0x2000,   // 2000..206F; General Punctuation
+            0x2070,   // 2070..209F; Superscripts and Subscripts
+            0x20A0,   // 20A0..20CF; Currency Symbols
+            0x20D0,   // 20D0..20FF; Combining Diacritical Marks for Symbols
+            0x2100,   // 2100..214F; Letterlike Symbols
+            0x2150,   // 2150..218F; Number Forms
+            0x2190,   // 2190..21FF; Arrows
+            0x2200,   // 2200..22FF; Mathematical Operators
+            0x2300,   // 2300..23FF; Miscellaneous Technical
+            0x2400,   // 2400..243F; Control Pictures
+            0x2440,   // 2440..245F; Optical Character Recognition
+            0x2460,   // 2460..24FF; Enclosed Alphanumerics
+            0x2500,   // 2500..257F; Box Drawing
+            0x2580,   // 2580..259F; Block Elements
+            0x25A0,   // 25A0..25FF; Geometric Shapes
+            0x2600,   // 2600..26FF; Miscellaneous Symbols
+            0x2700,   // 2700..27BF; Dingbats
+            0x27C0,   // 27C0..27EF; Miscellaneous Mathematical Symbols-A
+            0x27F0,   // 27F0..27FF; Supplemental Arrows-A
+            0x2800,   // 2800..28FF; Braille Patterns
+            0x2900,   // 2900..297F; Supplemental Arrows-B
+            0x2980,   // 2980..29FF; Miscellaneous Mathematical Symbols-B
+            0x2A00,   // 2A00..2AFF; Supplemental Mathematical Operators
+            0x2B00,   // 2B00..2BFF; Miscellaneous Symbols and Arrows
+            0x2C00,   // 2C00..2C5F; Glagolitic
+            0x2C60,   // 2C60..2C7F; Latin Extended-C
+            0x2C80,   // 2C80..2CFF; Coptic
+            0x2D00,   // 2D00..2D2F; Georgian Supplement
+            0x2D30,   // 2D30..2D7F; Tifinagh
+            0x2D80,   // 2D80..2DDF; Ethiopic Extended
+            0x2DE0,   // 2DE0..2DFF; Cyrillic Extended-A
+            0x2E00,   // 2E00..2E7F; Supplemental Punctuation
+            0x2E80,   // 2E80..2EFF; CJK Radicals Supplement
+            0x2F00,   // 2F00..2FDF; Kangxi Radicals
+            0x2FE0,   //             unassigned
+            0x2FF0,   // 2FF0..2FFF; Ideographic Description Characters
+            0x3000,   // 3000..303F; CJK Symbols and Punctuation
+            0x3040,   // 3040..309F; Hiragana
+            0x30A0,   // 30A0..30FF; Katakana
+            0x3100,   // 3100..312F; Bopomofo
+            0x3130,   // 3130..318F; Hangul Compatibility Jamo
+            0x3190,   // 3190..319F; Kanbun
+            0x31A0,   // 31A0..31BF; Bopomofo Extended
+            0x31C0,   // 31C0..31EF; CJK Strokes
+            0x31F0,   // 31F0..31FF; Katakana Phonetic Extensions
+            0x3200,   // 3200..32FF; Enclosed CJK Letters and Months
+            0x3300,   // 3300..33FF; CJK Compatibility
+            0x3400,   // 3400..4DBF; CJK Unified Ideographs Extension A
+            0x4DC0,   // 4DC0..4DFF; Yijing Hexagram Symbols
+            0x4E00,   // 4E00..9FFF; CJK Unified Ideographs
+            0xA000,   // A000..A48F; Yi Syllables
+            0xA490,   // A490..A4CF; Yi Radicals
+            0xA4D0,   // A4D0..A4FF; Lisu
+            0xA500,   // A500..A63F; Vai
+            0xA640,   // A640..A69F; Cyrillic Extended-B
+            0xA6A0,   // A6A0..A6FF; Bamum
+            0xA700,   // A700..A71F; Modifier Tone Letters
+            0xA720,   // A720..A7FF; Latin Extended-D
+            0xA800,   // A800..A82F; Syloti Nagri
+            0xA830,   // A830..A83F; Common Indic Number Forms
+            0xA840,   // A840..A87F; Phags-pa
+            0xA880,   // A880..A8DF; Saurashtra
+            0xA8E0,   // A8E0..A8FF; Devanagari Extended
+            0xA900,   // A900..A92F; Kayah Li
+            0xA930,   // A930..A95F; Rejang
+            0xA960,   // A960..A97F; Hangul Jamo Extended-A
+            0xA980,   // A980..A9DF; Javanese
+            0xA9E0,   //             unassigned
+            0xAA00,   // AA00..AA5F; Cham
+            0xAA60,   // AA60..AA7F; Myanmar Extended-A
+            0xAA80,   // AA80..AADF; Tai Viet
+            0xAAE0,   // AAE0..AAFF; Meetei Mayek Extensions
+            0xAB00,   // AB00..AB2F; Ethiopic Extended-A
+            0xAB30,   //             unassigned
+            0xABC0,   // ABC0..ABFF; Meetei Mayek
+            0xAC00,   // AC00..D7AF; Hangul Syllables
+            0xD7B0,   // D7B0..D7FF; Hangul Jamo Extended-B
+            0xD800,   // D800..DB7F; High Surrogates
+            0xDB80,   // DB80..DBFF; High Private Use Surrogates
+            0xDC00,   // DC00..DFFF; Low Surrogates
+            0xE000,   // E000..F8FF; Private Use Area
+            0xF900,   // F900..FAFF; CJK Compatibility Ideographs
+            0xFB00,   // FB00..FB4F; Alphabetic Presentation Forms
+            0xFB50,   // FB50..FDFF; Arabic Presentation Forms-A
+            0xFE00,   // FE00..FE0F; Variation Selectors
+            0xFE10,   // FE10..FE1F; Vertical Forms
+            0xFE20,   // FE20..FE2F; Combining Half Marks
+            0xFE30,   // FE30..FE4F; CJK Compatibility Forms
+            0xFE50,   // FE50..FE6F; Small Form Variants
+            0xFE70,   // FE70..FEFF; Arabic Presentation Forms-B
+            0xFF00,   // FF00..FFEF; Halfwidth and Fullwidth Forms
+            0xFFF0,   // FFF0..FFFF; Specials
+            0x10000,  // 10000..1007F; Linear B Syllabary
+            0x10080,  // 10080..100FF; Linear B Ideograms
+            0x10100,  // 10100..1013F; Aegean Numbers
+            0x10140,  // 10140..1018F; Ancient Greek Numbers
+            0x10190,  // 10190..101CF; Ancient Symbols
+            0x101D0,  // 101D0..101FF; Phaistos Disc
+            0x10200,  //               unassigned
+            0x10280,  // 10280..1029F; Lycian
+            0x102A0,  // 102A0..102DF; Carian
+            0x102E0,  //               unassigned
+            0x10300,  // 10300..1032F; Old Italic
+            0x10330,  // 10330..1034F; Gothic
+            0x10350,  //               unassigned
+            0x10380,  // 10380..1039F; Ugaritic
+            0x103A0,  // 103A0..103DF; Old Persian
+            0x103E0,  //               unassigned
+            0x10400,  // 10400..1044F; Deseret
+            0x10450,  // 10450..1047F; Shavian
+            0x10480,  // 10480..104AF; Osmanya
+            0x104B0,  //               unassigned
+            0x10800,  // 10800..1083F; Cypriot Syllabary
+            0x10840,  // 10840..1085F; Imperial Aramaic
+            0x10860,  //               unassigned
+            0x10900,  // 10900..1091F; Phoenician
+            0x10920,  // 10920..1093F; Lydian
+            0x10940,  //               unassigned
+            0x10980,  // 10980..1099F; Meroitic Hieroglyphs
+            0x109A0,  // 109A0..109FF; Meroitic Cursive
+            0x10A00,  // 10A00..10A5F; Kharoshthi
+            0x10A60,  // 10A60..10A7F; Old South Arabian
+            0x10A80,  //               unassigned
+            0x10B00,  // 10B00..10B3F; Avestan
+            0x10B40,  // 10B40..10B5F; Inscriptional Parthian
+            0x10B60,  // 10B60..10B7F; Inscriptional Pahlavi
+            0x10B80,  //               unassigned
+            0x10C00,  // 10C00..10C4F; Old Turkic
+            0x10C50,  //               unassigned
+            0x10E60,  // 10E60..10E7F; Rumi Numeral Symbols
+            0x10E80,  //               unassigned
+            0x11000,  // 11000..1107F; Brahmi
+            0x11080,  // 11080..110CF; Kaithi
+            0x110D0,  // 110D0..110FF; Sora Sompeng
+            0x11100,  // 11100..1114F; Chakma
+            0x11150,  //               unassigned
+            0x11180,  // 11180..111DF; Sharada
+            0x111E0,  //               unassigned
+            0x11680,  // 11680..116CF; Takri
+            0x116D0,  //               unassigned
+            0x12000,  // 12000..123FF; Cuneiform
+            0x12400,  // 12400..1247F; Cuneiform Numbers and Punctuation
+            0x12480,  //               unassigned
+            0x13000,  // 13000..1342F; Egyptian Hieroglyphs
+            0x13430,  //               unassigned
+            0x16800,  // 16800..16A3F; Bamum Supplement
+            0x16A40,  //               unassigned
+            0x16F00,  // 16F00..16F9F; Miao
+            0x16FA0,  //               unassigned
+            0x1B000,  // 1B000..1B0FF; Kana Supplement
+            0x1B100,  //               unassigned
+            0x1D000,  // 1D000..1D0FF; Byzantine Musical Symbols
+            0x1D100,  // 1D100..1D1FF; Musical Symbols
+            0x1D200,  // 1D200..1D24F; Ancient Greek Musical Notation
+            0x1D250,  //               unassigned
+            0x1D300,  // 1D300..1D35F; Tai Xuan Jing Symbols
+            0x1D360,  // 1D360..1D37F; Counting Rod Numerals
+            0x1D380,  //               unassigned
+            0x1D400,  // 1D400..1D7FF; Mathematical Alphanumeric Symbols
+            0x1D800,  //               unassigned
+            0x1EE00,  // 1EE00..1EEFF; Arabic Mathematical Alphabetic Symbols
+            0x1EF00,  //               unassigned
+            0x1F000,  // 1F000..1F02F; Mahjong Tiles
+            0x1F030,  // 1F030..1F09F; Domino Tiles
+            0x1F0A0,  // 1F0A0..1F0FF; Playing Cards
+            0x1F100,  // 1F100..1F1FF; Enclosed Alphanumeric Supplement
+            0x1F200,  // 1F200..1F2FF; Enclosed Ideographic Supplement
+            0x1F300,  // 1F300..1F5FF; Miscellaneous Symbols And Pictographs
+            0x1F600,  // 1F600..1F64F; Emoticons
+            0x1F650,  //               unassigned
+            0x1F680,  // 1F680..1F6FF; Transport And Map Symbols
+            0x1F700,  // 1F700..1F77F; Alchemical Symbols
+            0x1F780,  //               unassigned
+            0x20000,  // 20000..2A6DF; CJK Unified Ideographs Extension B
+            0x2A6E0,  //               unassigned
+            0x2A700,  // 2A700..2B73F; CJK Unified Ideographs Extension C
+            0x2B740,  // 2B740..2B81F; CJK Unified Ideographs Extension D
+            0x2B820,  //               unassigned
+            0x2F800,  // 2F800..2FA1F; CJK Compatibility Ideographs Supplement
+            0x2FA20,  //               unassigned
+            0xE0000,  // E0000..E007F; Tags
+            0xE0080,  //               unassigned
+            0xE0100,  // E0100..E01EF; Variation Selectors Supplement
+            0xE01F0,  //               unassigned
+            0xF0000,  // F0000..FFFFF; Supplementary Private Use Area-A
+            0x100000  // 100000..10FFFF; Supplementary Private Use Area-B
+        };
+
+        private static final UnicodeBlock[] blocks = {
+            BASIC_LATIN,
+            LATIN_1_SUPPLEMENT,
+            LATIN_EXTENDED_A,
+            LATIN_EXTENDED_B,
+            IPA_EXTENSIONS,
+            SPACING_MODIFIER_LETTERS,
+            COMBINING_DIACRITICAL_MARKS,
+            GREEK,
+            CYRILLIC,
+            CYRILLIC_SUPPLEMENTARY,
+            ARMENIAN,
+            HEBREW,
+            ARABIC,
+            SYRIAC,
+            ARABIC_SUPPLEMENT,
+            THAANA,
+            NKO,
+            SAMARITAN,
+            MANDAIC,
+            null,
+            ARABIC_EXTENDED_A,
+            DEVANAGARI,
+            BENGALI,
+            GURMUKHI,
+            GUJARATI,
+            ORIYA,
+            TAMIL,
+            TELUGU,
+            KANNADA,
+            MALAYALAM,
+            SINHALA,
+            THAI,
+            LAO,
+            TIBETAN,
+            MYANMAR,
+            GEORGIAN,
+            HANGUL_JAMO,
+            ETHIOPIC,
+            ETHIOPIC_SUPPLEMENT,
+            CHEROKEE,
+            UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS,
+            OGHAM,
+            RUNIC,
+            TAGALOG,
+            HANUNOO,
+            BUHID,
+            TAGBANWA,
+            KHMER,
+            MONGOLIAN,
+            UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED,
+            LIMBU,
+            TAI_LE,
+            NEW_TAI_LUE,
+            KHMER_SYMBOLS,
+            BUGINESE,
+            TAI_THAM,
+            null,
+            BALINESE,
+            SUNDANESE,
+            BATAK,
+            LEPCHA,
+            OL_CHIKI,
+            null,
+            SUNDANESE_SUPPLEMENT,
+            VEDIC_EXTENSIONS,
+            PHONETIC_EXTENSIONS,
+            PHONETIC_EXTENSIONS_SUPPLEMENT,
+            COMBINING_DIACRITICAL_MARKS_SUPPLEMENT,
+            LATIN_EXTENDED_ADDITIONAL,
+            GREEK_EXTENDED,
+            GENERAL_PUNCTUATION,
+            SUPERSCRIPTS_AND_SUBSCRIPTS,
+            CURRENCY_SYMBOLS,
+            COMBINING_MARKS_FOR_SYMBOLS,
+            LETTERLIKE_SYMBOLS,
+            NUMBER_FORMS,
+            ARROWS,
+            MATHEMATICAL_OPERATORS,
+            MISCELLANEOUS_TECHNICAL,
+            CONTROL_PICTURES,
+            OPTICAL_CHARACTER_RECOGNITION,
+            ENCLOSED_ALPHANUMERICS,
+            BOX_DRAWING,
+            BLOCK_ELEMENTS,
+            GEOMETRIC_SHAPES,
+            MISCELLANEOUS_SYMBOLS,
+            DINGBATS,
+            MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A,
+            SUPPLEMENTAL_ARROWS_A,
+            BRAILLE_PATTERNS,
+            SUPPLEMENTAL_ARROWS_B,
+            MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B,
+            SUPPLEMENTAL_MATHEMATICAL_OPERATORS,
+            MISCELLANEOUS_SYMBOLS_AND_ARROWS,
+            GLAGOLITIC,
+            LATIN_EXTENDED_C,
+            COPTIC,
+            GEORGIAN_SUPPLEMENT,
+            TIFINAGH,
+            ETHIOPIC_EXTENDED,
+            CYRILLIC_EXTENDED_A,
+            SUPPLEMENTAL_PUNCTUATION,
+            CJK_RADICALS_SUPPLEMENT,
+            KANGXI_RADICALS,
+            null,
+            IDEOGRAPHIC_DESCRIPTION_CHARACTERS,
+            CJK_SYMBOLS_AND_PUNCTUATION,
+            HIRAGANA,
+            KATAKANA,
+            BOPOMOFO,
+            HANGUL_COMPATIBILITY_JAMO,
+            KANBUN,
+            BOPOMOFO_EXTENDED,
+            CJK_STROKES,
+            KATAKANA_PHONETIC_EXTENSIONS,
+            ENCLOSED_CJK_LETTERS_AND_MONTHS,
+            CJK_COMPATIBILITY,
+            CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A,
+            YIJING_HEXAGRAM_SYMBOLS,
+            CJK_UNIFIED_IDEOGRAPHS,
+            YI_SYLLABLES,
+            YI_RADICALS,
+            LISU,
+            VAI,
+            CYRILLIC_EXTENDED_B,
+            BAMUM,
+            MODIFIER_TONE_LETTERS,
+            LATIN_EXTENDED_D,
+            SYLOTI_NAGRI,
+            COMMON_INDIC_NUMBER_FORMS,
+            PHAGS_PA,
+            SAURASHTRA,
+            DEVANAGARI_EXTENDED,
+            KAYAH_LI,
+            REJANG,
+            HANGUL_JAMO_EXTENDED_A,
+            JAVANESE,
+            null,
+            CHAM,
+            MYANMAR_EXTENDED_A,
+            TAI_VIET,
+            MEETEI_MAYEK_EXTENSIONS,
+            ETHIOPIC_EXTENDED_A,
+            null,
+            MEETEI_MAYEK,
+            HANGUL_SYLLABLES,
+            HANGUL_JAMO_EXTENDED_B,
+            HIGH_SURROGATES,
+            HIGH_PRIVATE_USE_SURROGATES,
+            LOW_SURROGATES,
+            PRIVATE_USE_AREA,
+            CJK_COMPATIBILITY_IDEOGRAPHS,
+            ALPHABETIC_PRESENTATION_FORMS,
+            ARABIC_PRESENTATION_FORMS_A,
+            VARIATION_SELECTORS,
+            VERTICAL_FORMS,
+            COMBINING_HALF_MARKS,
+            CJK_COMPATIBILITY_FORMS,
+            SMALL_FORM_VARIANTS,
+            ARABIC_PRESENTATION_FORMS_B,
+            HALFWIDTH_AND_FULLWIDTH_FORMS,
+            SPECIALS,
+            LINEAR_B_SYLLABARY,
+            LINEAR_B_IDEOGRAMS,
+            AEGEAN_NUMBERS,
+            ANCIENT_GREEK_NUMBERS,
+            ANCIENT_SYMBOLS,
+            PHAISTOS_DISC,
+            null,
+            LYCIAN,
+            CARIAN,
+            null,
+            OLD_ITALIC,
+            GOTHIC,
+            null,
+            UGARITIC,
+            OLD_PERSIAN,
+            null,
+            DESERET,
+            SHAVIAN,
+            OSMANYA,
+            null,
+            CYPRIOT_SYLLABARY,
+            IMPERIAL_ARAMAIC,
+            null,
+            PHOENICIAN,
+            LYDIAN,
+            null,
+            MEROITIC_HIEROGLYPHS,
+            MEROITIC_CURSIVE,
+            KHAROSHTHI,
+            OLD_SOUTH_ARABIAN,
+            null,
+            AVESTAN,
+            INSCRIPTIONAL_PARTHIAN,
+            INSCRIPTIONAL_PAHLAVI,
+            null,
+            OLD_TURKIC,
+            null,
+            RUMI_NUMERAL_SYMBOLS,
+            null,
+            BRAHMI,
+            KAITHI,
+            SORA_SOMPENG,
+            CHAKMA,
+            null,
+            SHARADA,
+            null,
+            TAKRI,
+            null,
+            CUNEIFORM,
+            CUNEIFORM_NUMBERS_AND_PUNCTUATION,
+            null,
+            EGYPTIAN_HIEROGLYPHS,
+            null,
+            BAMUM_SUPPLEMENT,
+            null,
+            MIAO,
+            null,
+            KANA_SUPPLEMENT,
+            null,
+            BYZANTINE_MUSICAL_SYMBOLS,
+            MUSICAL_SYMBOLS,
+            ANCIENT_GREEK_MUSICAL_NOTATION,
+            null,
+            TAI_XUAN_JING_SYMBOLS,
+            COUNTING_ROD_NUMERALS,
+            null,
+            MATHEMATICAL_ALPHANUMERIC_SYMBOLS,
+            null,
+            ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
+            null,
+            MAHJONG_TILES,
+            DOMINO_TILES,
+            PLAYING_CARDS,
+            ENCLOSED_ALPHANUMERIC_SUPPLEMENT,
+            ENCLOSED_IDEOGRAPHIC_SUPPLEMENT,
+            MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS,
+            EMOTICONS,
+            null,
+            TRANSPORT_AND_MAP_SYMBOLS,
+            ALCHEMICAL_SYMBOLS,
+            null,
+            CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B,
+            null,
+            CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C,
+            CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D,
+            null,
+            CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT,
+            null,
+            TAGS,
+            null,
+            VARIATION_SELECTORS_SUPPLEMENT,
+            null,
+            SUPPLEMENTARY_PRIVATE_USE_AREA_A,
+            SUPPLEMENTARY_PRIVATE_USE_AREA_B
+        };
+
+
+        /**
+         * Returns the object representing the Unicode block containing the
+         * given character, or {@code null} if the character is not a
+         * member of a defined block.
+         *
+         * <p><b>Note:</b> This method cannot handle
+         * <a href="Character.html#supplementary"> supplementary
+         * characters</a>.  To support all Unicode characters, including
+         * supplementary characters, use the {@link #of(int)} method.
+         *
+         * @param   c  The character in question
+         * @return  The {@code UnicodeBlock} instance representing the
+         *          Unicode block of which this character is a member, or
+         *          {@code null} if the character is not a member of any
+         *          Unicode block
+         */
+        public static UnicodeBlock of(char c) {
+            return of((int)c);
+        }
+
+        /**
+         * Returns the object representing the Unicode block
+         * containing the given character (Unicode code point), or
+         * {@code null} if the character is not a member of a
+         * defined block.
+         *
+         * @param   codePoint the character (Unicode code point) in question.
+         * @return  The {@code UnicodeBlock} instance representing the
+         *          Unicode block of which this character is a member, or
+         *          {@code null} if the character is not a member of any
+         *          Unicode block
+         * @exception IllegalArgumentException if the specified
+         * {@code codePoint} is an invalid Unicode code point.
+         * @see Character#isValidCodePoint(int)
+         * @since   1.5
+         */
+        public static UnicodeBlock of(int codePoint) {
+            if (!isValidCodePoint(codePoint)) {
+                throw new IllegalArgumentException();
+            }
+
+            int top, bottom, current;
+            bottom = 0;
+            top = blockStarts.length;
+            current = top/2;
+
+            // invariant: top > current >= bottom && codePoint >= unicodeBlockStarts[bottom]
+            while (top - bottom > 1) {
+                if (codePoint >= blockStarts[current]) {
+                    bottom = current;
+                } else {
+                    top = current;
+                }
+                current = (top + bottom) / 2;
+            }
+            return blocks[current];
+        }
+
+        /**
+         * Returns the UnicodeBlock with the given name. Block
+         * names are determined by The Unicode Standard. The file
+         * Blocks-&lt;version&gt;.txt defines blocks for a particular
+         * version of the standard. The {@link Character} class specifies
+         * the version of the standard that it supports.
+         * <p>
+         * This method accepts block names in the following forms:
+         * <ol>
+         * <li> Canonical block names as defined by the Unicode Standard.
+         * For example, the standard defines a "Basic Latin" block. Therefore, this
+         * method accepts "Basic Latin" as a valid block name. The documentation of
+         * each UnicodeBlock provides the canonical name.
+         * <li>Canonical block names with all spaces removed. For example, "BasicLatin"
+         * is a valid block name for the "Basic Latin" block.
+         * <li>The text representation of each constant UnicodeBlock identifier.
+         * For example, this method will return the {@link #BASIC_LATIN} block if
+         * provided with the "BASIC_LATIN" name. This form replaces all spaces and
+         * hyphens in the canonical name with underscores.
+         * </ol>
+         * Finally, character case is ignored for all of the valid block name forms.
+         * For example, "BASIC_LATIN" and "basic_latin" are both valid block names.
+         * The en_US locale's case mapping rules are used to provide case-insensitive
+         * string comparisons for block name validation.
+         * <p>
+         * If the Unicode Standard changes block names, both the previous and
+         * current names will be accepted.
+         *
+         * @param blockName A {@code UnicodeBlock} name.
+         * @return The {@code UnicodeBlock} instance identified
+         *         by {@code blockName}
+         * @throws IllegalArgumentException if {@code blockName} is an
+         *         invalid name
+         * @throws NullPointerException if {@code blockName} is null
+         * @since 1.5
+         */
+        public static final UnicodeBlock forName(String blockName) {
+            UnicodeBlock block = map.get(blockName.toUpperCase(Locale.US));
+            if (block == null) {
+                throw new IllegalArgumentException();
+            }
+            return block;
+        }
+    }
+
+
+    /**
+     * A family of character subsets representing the character scripts
+     * defined in the <a href="http://www.unicode.org/reports/tr24/">
+     * <i>Unicode Standard Annex #24: Script Names</i></a>. Every Unicode
+     * character is assigned to a single Unicode script, either a specific
+     * script, such as {@link Character.UnicodeScript#LATIN Latin}, or
+     * one of the following three special values,
+     * {@link Character.UnicodeScript#INHERITED Inherited},
+     * {@link Character.UnicodeScript#COMMON Common} or
+     * {@link Character.UnicodeScript#UNKNOWN Unknown}.
+     *
+     * @since 1.7
+     */
+    public static enum UnicodeScript {
+        /**
+         * Unicode script "Common".
+         */
+        COMMON,
+
+        /**
+         * Unicode script "Latin".
+         */
+        LATIN,
+
+        /**
+         * Unicode script "Greek".
+         */
+        GREEK,
+
+        /**
+         * Unicode script "Cyrillic".
+         */
+        CYRILLIC,
+
+        /**
+         * Unicode script "Armenian".
+         */
+        ARMENIAN,
+
+        /**
+         * Unicode script "Hebrew".
+         */
+        HEBREW,
+
+        /**
+         * Unicode script "Arabic".
+         */
+        ARABIC,
+
+        /**
+         * Unicode script "Syriac".
+         */
+        SYRIAC,
+
+        /**
+         * Unicode script "Thaana".
+         */
+        THAANA,
+
+        /**
+         * Unicode script "Devanagari".
+         */
+        DEVANAGARI,
+
+        /**
+         * Unicode script "Bengali".
+         */
+        BENGALI,
+
+        /**
+         * Unicode script "Gurmukhi".
+         */
+        GURMUKHI,
+
+        /**
+         * Unicode script "Gujarati".
+         */
+        GUJARATI,
+
+        /**
+         * Unicode script "Oriya".
+         */
+        ORIYA,
+
+        /**
+         * Unicode script "Tamil".
+         */
+        TAMIL,
+
+        /**
+         * Unicode script "Telugu".
+         */
+        TELUGU,
+
+        /**
+         * Unicode script "Kannada".
+         */
+        KANNADA,
+
+        /**
+         * Unicode script "Malayalam".
+         */
+        MALAYALAM,
+
+        /**
+         * Unicode script "Sinhala".
+         */
+        SINHALA,
+
+        /**
+         * Unicode script "Thai".
+         */
+        THAI,
+
+        /**
+         * Unicode script "Lao".
+         */
+        LAO,
+
+        /**
+         * Unicode script "Tibetan".
+         */
+        TIBETAN,
+
+        /**
+         * Unicode script "Myanmar".
+         */
+        MYANMAR,
+
+        /**
+         * Unicode script "Georgian".
+         */
+        GEORGIAN,
+
+        /**
+         * Unicode script "Hangul".
+         */
+        HANGUL,
+
+        /**
+         * Unicode script "Ethiopic".
+         */
+        ETHIOPIC,
+
+        /**
+         * Unicode script "Cherokee".
+         */
+        CHEROKEE,
+
+        /**
+         * Unicode script "Canadian_Aboriginal".
+         */
+        CANADIAN_ABORIGINAL,
+
+        /**
+         * Unicode script "Ogham".
+         */
+        OGHAM,
+
+        /**
+         * Unicode script "Runic".
+         */
+        RUNIC,
+
+        /**
+         * Unicode script "Khmer".
+         */
+        KHMER,
+
+        /**
+         * Unicode script "Mongolian".
+         */
+        MONGOLIAN,
+
+        /**
+         * Unicode script "Hiragana".
+         */
+        HIRAGANA,
+
+        /**
+         * Unicode script "Katakana".
+         */
+        KATAKANA,
+
+        /**
+         * Unicode script "Bopomofo".
+         */
+        BOPOMOFO,
+
+        /**
+         * Unicode script "Han".
+         */
+        HAN,
+
+        /**
+         * Unicode script "Yi".
+         */
+        YI,
+
+        /**
+         * Unicode script "Old_Italic".
+         */
+        OLD_ITALIC,
+
+        /**
+         * Unicode script "Gothic".
+         */
+        GOTHIC,
+
+        /**
+         * Unicode script "Deseret".
+         */
+        DESERET,
+
+        /**
+         * Unicode script "Inherited".
+         */
+        INHERITED,
+
+        /**
+         * Unicode script "Tagalog".
+         */
+        TAGALOG,
+
+        /**
+         * Unicode script "Hanunoo".
+         */
+        HANUNOO,
+
+        /**
+         * Unicode script "Buhid".
+         */
+        BUHID,
+
+        /**
+         * Unicode script "Tagbanwa".
+         */
+        TAGBANWA,
+
+        /**
+         * Unicode script "Limbu".
+         */
+        LIMBU,
+
+        /**
+         * Unicode script "Tai_Le".
+         */
+        TAI_LE,
+
+        /**
+         * Unicode script "Linear_B".
+         */
+        LINEAR_B,
+
+        /**
+         * Unicode script "Ugaritic".
+         */
+        UGARITIC,
+
+        /**
+         * Unicode script "Shavian".
+         */
+        SHAVIAN,
+
+        /**
+         * Unicode script "Osmanya".
+         */
+        OSMANYA,
+
+        /**
+         * Unicode script "Cypriot".
+         */
+        CYPRIOT,
+
+        /**
+         * Unicode script "Braille".
+         */
+        BRAILLE,
+
+        /**
+         * Unicode script "Buginese".
+         */
+        BUGINESE,
+
+        /**
+         * Unicode script "Coptic".
+         */
+        COPTIC,
+
+        /**
+         * Unicode script "New_Tai_Lue".
+         */
+        NEW_TAI_LUE,
+
+        /**
+         * Unicode script "Glagolitic".
+         */
+        GLAGOLITIC,
+
+        /**
+         * Unicode script "Tifinagh".
+         */
+        TIFINAGH,
+
+        /**
+         * Unicode script "Syloti_Nagri".
+         */
+        SYLOTI_NAGRI,
+
+        /**
+         * Unicode script "Old_Persian".
+         */
+        OLD_PERSIAN,
+
+        /**
+         * Unicode script "Kharoshthi".
+         */
+        KHAROSHTHI,
+
+        /**
+         * Unicode script "Balinese".
+         */
+        BALINESE,
+
+        /**
+         * Unicode script "Cuneiform".
+         */
+        CUNEIFORM,
+
+        /**
+         * Unicode script "Phoenician".
+         */
+        PHOENICIAN,
+
+        /**
+         * Unicode script "Phags_Pa".
+         */
+        PHAGS_PA,
+
+        /**
+         * Unicode script "Nko".
+         */
+        NKO,
+
+        /**
+         * Unicode script "Sundanese".
+         */
+        SUNDANESE,
+
+        /**
+         * Unicode script "Batak".
+         */
+        BATAK,
+
+        /**
+         * Unicode script "Lepcha".
+         */
+        LEPCHA,
+
+        /**
+         * Unicode script "Ol_Chiki".
+         */
+        OL_CHIKI,
+
+        /**
+         * Unicode script "Vai".
+         */
+        VAI,
+
+        /**
+         * Unicode script "Saurashtra".
+         */
+        SAURASHTRA,
+
+        /**
+         * Unicode script "Kayah_Li".
+         */
+        KAYAH_LI,
+
+        /**
+         * Unicode script "Rejang".
+         */
+        REJANG,
+
+        /**
+         * Unicode script "Lycian".
+         */
+        LYCIAN,
+
+        /**
+         * Unicode script "Carian".
+         */
+        CARIAN,
+
+        /**
+         * Unicode script "Lydian".
+         */
+        LYDIAN,
+
+        /**
+         * Unicode script "Cham".
+         */
+        CHAM,
+
+        /**
+         * Unicode script "Tai_Tham".
+         */
+        TAI_THAM,
+
+        /**
+         * Unicode script "Tai_Viet".
+         */
+        TAI_VIET,
+
+        /**
+         * Unicode script "Avestan".
+         */
+        AVESTAN,
+
+        /**
+         * Unicode script "Egyptian_Hieroglyphs".
+         */
+        EGYPTIAN_HIEROGLYPHS,
+
+        /**
+         * Unicode script "Samaritan".
+         */
+        SAMARITAN,
+
+        /**
+         * Unicode script "Mandaic".
+         */
+        MANDAIC,
+
+        /**
+         * Unicode script "Lisu".
+         */
+        LISU,
+
+        /**
+         * Unicode script "Bamum".
+         */
+        BAMUM,
+
+        /**
+         * Unicode script "Javanese".
+         */
+        JAVANESE,
+
+        /**
+         * Unicode script "Meetei_Mayek".
+         */
+        MEETEI_MAYEK,
+
+        /**
+         * Unicode script "Imperial_Aramaic".
+         */
+        IMPERIAL_ARAMAIC,
+
+        /**
+         * Unicode script "Old_South_Arabian".
+         */
+        OLD_SOUTH_ARABIAN,
+
+        /**
+         * Unicode script "Inscriptional_Parthian".
+         */
+        INSCRIPTIONAL_PARTHIAN,
+
+        /**
+         * Unicode script "Inscriptional_Pahlavi".
+         */
+        INSCRIPTIONAL_PAHLAVI,
+
+        /**
+         * Unicode script "Old_Turkic".
+         */
+        OLD_TURKIC,
+
+        /**
+         * Unicode script "Brahmi".
+         */
+        BRAHMI,
+
+        /**
+         * Unicode script "Kaithi".
+         */
+        KAITHI,
+
+        /**
+         * Unicode script "Meroitic Hieroglyphs".
+         */
+        MEROITIC_HIEROGLYPHS,
+
+        /**
+         * Unicode script "Meroitic Cursive".
+         */
+        MEROITIC_CURSIVE,
+
+        /**
+         * Unicode script "Sora Sompeng".
+         */
+        SORA_SOMPENG,
+
+        /**
+         * Unicode script "Chakma".
+         */
+        CHAKMA,
+
+        /**
+         * Unicode script "Sharada".
+         */
+        SHARADA,
+
+        /**
+         * Unicode script "Takri".
+         */
+        TAKRI,
+
+        /**
+         * Unicode script "Miao".
+         */
+        MIAO,
+
+        /**
+         * Unicode script "Unknown".
+         */
+        UNKNOWN;
+
+        private static final int[] scriptStarts = {
+            0x0000,   // 0000..0040; COMMON
+            0x0041,   // 0041..005A; LATIN
+            0x005B,   // 005B..0060; COMMON
+            0x0061,   // 0061..007A; LATIN
+            0x007B,   // 007B..00A9; COMMON
+            0x00AA,   // 00AA..00AA; LATIN
+            0x00AB,   // 00AB..00B9; COMMON
+            0x00BA,   // 00BA..00BA; LATIN
+            0x00BB,   // 00BB..00BF; COMMON
+            0x00C0,   // 00C0..00D6; LATIN
+            0x00D7,   // 00D7..00D7; COMMON
+            0x00D8,   // 00D8..00F6; LATIN
+            0x00F7,   // 00F7..00F7; COMMON
+            0x00F8,   // 00F8..02B8; LATIN
+            0x02B9,   // 02B9..02DF; COMMON
+            0x02E0,   // 02E0..02E4; LATIN
+            0x02E5,   // 02E5..02E9; COMMON
+            0x02EA,   // 02EA..02EB; BOPOMOFO
+            0x02EC,   // 02EC..02FF; COMMON
+            0x0300,   // 0300..036F; INHERITED
+            0x0370,   // 0370..0373; GREEK
+            0x0374,   // 0374..0374; COMMON
+            0x0375,   // 0375..037D; GREEK
+            0x037E,   // 037E..0383; COMMON
+            0x0384,   // 0384..0384; GREEK
+            0x0385,   // 0385..0385; COMMON
+            0x0386,   // 0386..0386; GREEK
+            0x0387,   // 0387..0387; COMMON
+            0x0388,   // 0388..03E1; GREEK
+            0x03E2,   // 03E2..03EF; COPTIC
+            0x03F0,   // 03F0..03FF; GREEK
+            0x0400,   // 0400..0484; CYRILLIC
+            0x0485,   // 0485..0486; INHERITED
+            0x0487,   // 0487..0530; CYRILLIC
+            0x0531,   // 0531..0588; ARMENIAN
+            0x0589,   // 0589..0589; COMMON
+            0x058A,   // 058A..0590; ARMENIAN
+            0x0591,   // 0591..05FF; HEBREW
+            0x0600,   // 0600..060B; ARABIC
+            0x060C,   // 060C..060C; COMMON
+            0x060D,   // 060D..061A; ARABIC
+            0x061B,   // 061B..061D; COMMON
+            0x061E,   // 061E..061E; ARABIC
+            0x061F,   // 061F..061F; COMMON
+            0x0620,   // 0620..063F; ARABIC
+            0x0640,   // 0640..0640; COMMON
+            0x0641,   // 0641..064A; ARABIC
+            0x064B,   // 064B..0655; INHERITED
+            0x0656,   // 0656..065F; ARABIC
+            0x0660,   // 0660..0669; COMMON
+            0x066A,   // 066A..066F; ARABIC
+            0x0670,   // 0670..0670; INHERITED
+            0x0671,   // 0671..06DC; ARABIC
+            0x06DD,   // 06DD..06DD; COMMON
+            0x06DE,   // 06DE..06FF; ARABIC
+            0x0700,   // 0700..074F; SYRIAC
+            0x0750,   // 0750..077F; ARABIC
+            0x0780,   // 0780..07BF; THAANA
+            0x07C0,   // 07C0..07FF; NKO
+            0x0800,   // 0800..083F; SAMARITAN
+            0x0840,   // 0840..089F; MANDAIC
+            0x08A0,   // 08A0..08FF; ARABIC
+            0x0900,   // 0900..0950; DEVANAGARI
+            0x0951,   // 0951..0952; INHERITED
+            0x0953,   // 0953..0963; DEVANAGARI
+            0x0964,   // 0964..0965; COMMON
+            0x0966,   // 0966..0980; DEVANAGARI
+            0x0981,   // 0981..0A00; BENGALI
+            0x0A01,   // 0A01..0A80; GURMUKHI
+            0x0A81,   // 0A81..0B00; GUJARATI
+            0x0B01,   // 0B01..0B81; ORIYA
+            0x0B82,   // 0B82..0C00; TAMIL
+            0x0C01,   // 0C01..0C81; TELUGU
+            0x0C82,   // 0C82..0CF0; KANNADA
+            0x0D02,   // 0D02..0D81; MALAYALAM
+            0x0D82,   // 0D82..0E00; SINHALA
+            0x0E01,   // 0E01..0E3E; THAI
+            0x0E3F,   // 0E3F..0E3F; COMMON
+            0x0E40,   // 0E40..0E80; THAI
+            0x0E81,   // 0E81..0EFF; LAO
+            0x0F00,   // 0F00..0FD4; TIBETAN
+            0x0FD5,   // 0FD5..0FD8; COMMON
+            0x0FD9,   // 0FD9..0FFF; TIBETAN
+            0x1000,   // 1000..109F; MYANMAR
+            0x10A0,   // 10A0..10FA; GEORGIAN
+            0x10FB,   // 10FB..10FB; COMMON
+            0x10FC,   // 10FC..10FF; GEORGIAN
+            0x1100,   // 1100..11FF; HANGUL
+            0x1200,   // 1200..139F; ETHIOPIC
+            0x13A0,   // 13A0..13FF; CHEROKEE
+            0x1400,   // 1400..167F; CANADIAN_ABORIGINAL
+            0x1680,   // 1680..169F; OGHAM
+            0x16A0,   // 16A0..16EA; RUNIC
+            0x16EB,   // 16EB..16ED; COMMON
+            0x16EE,   // 16EE..16FF; RUNIC
+            0x1700,   // 1700..171F; TAGALOG
+            0x1720,   // 1720..1734; HANUNOO
+            0x1735,   // 1735..173F; COMMON
+            0x1740,   // 1740..175F; BUHID
+            0x1760,   // 1760..177F; TAGBANWA
+            0x1780,   // 1780..17FF; KHMER
+            0x1800,   // 1800..1801; MONGOLIAN
+            0x1802,   // 1802..1803; COMMON
+            0x1804,   // 1804..1804; MONGOLIAN
+            0x1805,   // 1805..1805; COMMON
+            0x1806,   // 1806..18AF; MONGOLIAN
+            0x18B0,   // 18B0..18FF; CANADIAN_ABORIGINAL
+            0x1900,   // 1900..194F; LIMBU
+            0x1950,   // 1950..197F; TAI_LE
+            0x1980,   // 1980..19DF; NEW_TAI_LUE
+            0x19E0,   // 19E0..19FF; KHMER
+            0x1A00,   // 1A00..1A1F; BUGINESE
+            0x1A20,   // 1A20..1AFF; TAI_THAM
+            0x1B00,   // 1B00..1B7F; BALINESE
+            0x1B80,   // 1B80..1BBF; SUNDANESE
+            0x1BC0,   // 1BC0..1BFF; BATAK
+            0x1C00,   // 1C00..1C4F; LEPCHA
+            0x1C50,   // 1C50..1CBF; OL_CHIKI
+            0x1CC0,   // 1CC0..1CCF; SUNDANESE
+            0x1CD0,   // 1CD0..1CD2; INHERITED
+            0x1CD3,   // 1CD3..1CD3; COMMON
+            0x1CD4,   // 1CD4..1CE0; INHERITED
+            0x1CE1,   // 1CE1..1CE1; COMMON
+            0x1CE2,   // 1CE2..1CE8; INHERITED
+            0x1CE9,   // 1CE9..1CEC; COMMON
+            0x1CED,   // 1CED..1CED; INHERITED
+            0x1CEE,   // 1CEE..1CF3; COMMON
+            0x1CF4,   // 1CF4..1CF4; INHERITED
+            0x1CF5,   // 1CF5..1CFF; COMMON
+            0x1D00,   // 1D00..1D25; LATIN
+            0x1D26,   // 1D26..1D2A; GREEK
+            0x1D2B,   // 1D2B..1D2B; CYRILLIC
+            0x1D2C,   // 1D2C..1D5C; LATIN
+            0x1D5D,   // 1D5D..1D61; GREEK
+            0x1D62,   // 1D62..1D65; LATIN
+            0x1D66,   // 1D66..1D6A; GREEK
+            0x1D6B,   // 1D6B..1D77; LATIN
+            0x1D78,   // 1D78..1D78; CYRILLIC
+            0x1D79,   // 1D79..1DBE; LATIN
+            0x1DBF,   // 1DBF..1DBF; GREEK
+            0x1DC0,   // 1DC0..1DFF; INHERITED
+            0x1E00,   // 1E00..1EFF; LATIN
+            0x1F00,   // 1F00..1FFF; GREEK
+            0x2000,   // 2000..200B; COMMON
+            0x200C,   // 200C..200D; INHERITED
+            0x200E,   // 200E..2070; COMMON
+            0x2071,   // 2071..2073; LATIN
+            0x2074,   // 2074..207E; COMMON
+            0x207F,   // 207F..207F; LATIN
+            0x2080,   // 2080..208F; COMMON
+            0x2090,   // 2090..209F; LATIN
+            0x20A0,   // 20A0..20CF; COMMON
+            0x20D0,   // 20D0..20FF; INHERITED
+            0x2100,   // 2100..2125; COMMON
+            0x2126,   // 2126..2126; GREEK
+            0x2127,   // 2127..2129; COMMON
+            0x212A,   // 212A..212B; LATIN
+            0x212C,   // 212C..2131; COMMON
+            0x2132,   // 2132..2132; LATIN
+            0x2133,   // 2133..214D; COMMON
+            0x214E,   // 214E..214E; LATIN
+            0x214F,   // 214F..215F; COMMON
+            0x2160,   // 2160..2188; LATIN
+            0x2189,   // 2189..27FF; COMMON
+            0x2800,   // 2800..28FF; BRAILLE
+            0x2900,   // 2900..2BFF; COMMON
+            0x2C00,   // 2C00..2C5F; GLAGOLITIC
+            0x2C60,   // 2C60..2C7F; LATIN
+            0x2C80,   // 2C80..2CFF; COPTIC
+            0x2D00,   // 2D00..2D2F; GEORGIAN
+            0x2D30,   // 2D30..2D7F; TIFINAGH
+            0x2D80,   // 2D80..2DDF; ETHIOPIC
+            0x2DE0,   // 2DE0..2DFF; CYRILLIC
+            0x2E00,   // 2E00..2E7F; COMMON
+            0x2E80,   // 2E80..2FEF; HAN
+            0x2FF0,   // 2FF0..3004; COMMON
+            0x3005,   // 3005..3005; HAN
+            0x3006,   // 3006..3006; COMMON
+            0x3007,   // 3007..3007; HAN
+            0x3008,   // 3008..3020; COMMON
+            0x3021,   // 3021..3029; HAN
+            0x302A,   // 302A..302D; INHERITED
+            0x302E,   // 302E..302F; HANGUL
+            0x3030,   // 3030..3037; COMMON
+            0x3038,   // 3038..303B; HAN
+            0x303C,   // 303C..3040; COMMON
+            0x3041,   // 3041..3098; HIRAGANA
+            0x3099,   // 3099..309A; INHERITED
+            0x309B,   // 309B..309C; COMMON
+            0x309D,   // 309D..309F; HIRAGANA
+            0x30A0,   // 30A0..30A0; COMMON
+            0x30A1,   // 30A1..30FA; KATAKANA
+            0x30FB,   // 30FB..30FC; COMMON
+            0x30FD,   // 30FD..3104; KATAKANA
+            0x3105,   // 3105..3130; BOPOMOFO
+            0x3131,   // 3131..318F; HANGUL
+            0x3190,   // 3190..319F; COMMON
+            0x31A0,   // 31A0..31BF; BOPOMOFO
+            0x31C0,   // 31C0..31EF; COMMON
+            0x31F0,   // 31F0..31FF; KATAKANA
+            0x3200,   // 3200..321F; HANGUL
+            0x3220,   // 3220..325F; COMMON
+            0x3260,   // 3260..327E; HANGUL
+            0x327F,   // 327F..32CF; COMMON
+            0x32D0,   // 32D0..3357; KATAKANA
+            0x3358,   // 3358..33FF; COMMON
+            0x3400,   // 3400..4DBF; HAN
+            0x4DC0,   // 4DC0..4DFF; COMMON
+            0x4E00,   // 4E00..9FFF; HAN
+            0xA000,   // A000..A4CF; YI
+            0xA4D0,   // A4D0..A4FF; LISU
+            0xA500,   // A500..A63F; VAI
+            0xA640,   // A640..A69F; CYRILLIC
+            0xA6A0,   // A6A0..A6FF; BAMUM
+            0xA700,   // A700..A721; COMMON
+            0xA722,   // A722..A787; LATIN
+            0xA788,   // A788..A78A; COMMON
+            0xA78B,   // A78B..A7FF; LATIN
+            0xA800,   // A800..A82F; SYLOTI_NAGRI
+            0xA830,   // A830..A83F; COMMON
+            0xA840,   // A840..A87F; PHAGS_PA
+            0xA880,   // A880..A8DF; SAURASHTRA
+            0xA8E0,   // A8E0..A8FF; DEVANAGARI
+            0xA900,   // A900..A92F; KAYAH_LI
+            0xA930,   // A930..A95F; REJANG
+            0xA960,   // A960..A97F; HANGUL
+            0xA980,   // A980..A9FF; JAVANESE
+            0xAA00,   // AA00..AA5F; CHAM
+            0xAA60,   // AA60..AA7F; MYANMAR
+            0xAA80,   // AA80..AADF; TAI_VIET
+            0xAAE0,   // AAE0..AB00; MEETEI_MAYEK
+            0xAB01,   // AB01..ABBF; ETHIOPIC
+            0xABC0,   // ABC0..ABFF; MEETEI_MAYEK
+            0xAC00,   // AC00..D7FB; HANGUL
+            0xD7FC,   // D7FC..F8FF; UNKNOWN
+            0xF900,   // F900..FAFF; HAN
+            0xFB00,   // FB00..FB12; LATIN
+            0xFB13,   // FB13..FB1C; ARMENIAN
+            0xFB1D,   // FB1D..FB4F; HEBREW
+            0xFB50,   // FB50..FD3D; ARABIC
+            0xFD3E,   // FD3E..FD4F; COMMON
+            0xFD50,   // FD50..FDFC; ARABIC
+            0xFDFD,   // FDFD..FDFF; COMMON
+            0xFE00,   // FE00..FE0F; INHERITED
+            0xFE10,   // FE10..FE1F; COMMON
+            0xFE20,   // FE20..FE2F; INHERITED
+            0xFE30,   // FE30..FE6F; COMMON
+            0xFE70,   // FE70..FEFE; ARABIC
+            0xFEFF,   // FEFF..FF20; COMMON
+            0xFF21,   // FF21..FF3A; LATIN
+            0xFF3B,   // FF3B..FF40; COMMON
+            0xFF41,   // FF41..FF5A; LATIN
+            0xFF5B,   // FF5B..FF65; COMMON
+            0xFF66,   // FF66..FF6F; KATAKANA
+            0xFF70,   // FF70..FF70; COMMON
+            0xFF71,   // FF71..FF9D; KATAKANA
+            0xFF9E,   // FF9E..FF9F; COMMON
+            0xFFA0,   // FFA0..FFDF; HANGUL
+            0xFFE0,   // FFE0..FFFF; COMMON
+            0x10000,  // 10000..100FF; LINEAR_B
+            0x10100,  // 10100..1013F; COMMON
+            0x10140,  // 10140..1018F; GREEK
+            0x10190,  // 10190..101FC; COMMON
+            0x101FD,  // 101FD..1027F; INHERITED
+            0x10280,  // 10280..1029F; LYCIAN
+            0x102A0,  // 102A0..102FF; CARIAN
+            0x10300,  // 10300..1032F; OLD_ITALIC
+            0x10330,  // 10330..1037F; GOTHIC
+            0x10380,  // 10380..1039F; UGARITIC
+            0x103A0,  // 103A0..103FF; OLD_PERSIAN
+            0x10400,  // 10400..1044F; DESERET
+            0x10450,  // 10450..1047F; SHAVIAN
+            0x10480,  // 10480..107FF; OSMANYA
+            0x10800,  // 10800..1083F; CYPRIOT
+            0x10840,  // 10840..108FF; IMPERIAL_ARAMAIC
+            0x10900,  // 10900..1091F; PHOENICIAN
+            0x10920,  // 10920..1097F; LYDIAN
+            0x10980,  // 10980..1099F; MEROITIC_HIEROGLYPHS
+            0x109A0,  // 109A0..109FF; MEROITIC_CURSIVE
+            0x10A00,  // 10A00..10A5F; KHAROSHTHI
+            0x10A60,  // 10A60..10AFF; OLD_SOUTH_ARABIAN
+            0x10B00,  // 10B00..10B3F; AVESTAN
+            0x10B40,  // 10B40..10B5F; INSCRIPTIONAL_PARTHIAN
+            0x10B60,  // 10B60..10BFF; INSCRIPTIONAL_PAHLAVI
+            0x10C00,  // 10C00..10E5F; OLD_TURKIC
+            0x10E60,  // 10E60..10FFF; ARABIC
+            0x11000,  // 11000..1107F; BRAHMI
+            0x11080,  // 11080..110CF; KAITHI
+            0x110D0,  // 110D0..110FF; SORA_SOMPENG
+            0x11100,  // 11100..1117F; CHAKMA
+            0x11180,  // 11180..1167F; SHARADA
+            0x11680,  // 11680..116CF; TAKRI
+            0x12000,  // 12000..12FFF; CUNEIFORM
+            0x13000,  // 13000..167FF; EGYPTIAN_HIEROGLYPHS
+            0x16800,  // 16800..16A38; BAMUM
+            0x16F00,  // 16F00..16F9F; MIAO
+            0x1B000,  // 1B000..1B000; KATAKANA
+            0x1B001,  // 1B001..1CFFF; HIRAGANA
+            0x1D000,  // 1D000..1D166; COMMON
+            0x1D167,  // 1D167..1D169; INHERITED
+            0x1D16A,  // 1D16A..1D17A; COMMON
+            0x1D17B,  // 1D17B..1D182; INHERITED
+            0x1D183,  // 1D183..1D184; COMMON
+            0x1D185,  // 1D185..1D18B; INHERITED
+            0x1D18C,  // 1D18C..1D1A9; COMMON
+            0x1D1AA,  // 1D1AA..1D1AD; INHERITED
+            0x1D1AE,  // 1D1AE..1D1FF; COMMON
+            0x1D200,  // 1D200..1D2FF; GREEK
+            0x1D300,  // 1D300..1EDFF; COMMON
+            0x1EE00,  // 1EE00..1EFFF; ARABIC
+            0x1F000,  // 1F000..1F1FF; COMMON
+            0x1F200,  // 1F200..1F200; HIRAGANA
+            0x1F201,  // 1F210..1FFFF; COMMON
+            0x20000,  // 20000..E0000; HAN
+            0xE0001,  // E0001..E00FF; COMMON
+            0xE0100,  // E0100..E01EF; INHERITED
+            0xE01F0   // E01F0..10FFFF; UNKNOWN
+
+        };
+
+        private static final UnicodeScript[] scripts = {
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            BOPOMOFO,
+            COMMON,
+            INHERITED,
+            GREEK,
+            COMMON,
+            GREEK,
+            COMMON,
+            GREEK,
+            COMMON,
+            GREEK,
+            COMMON,
+            GREEK,
+            COPTIC,
+            GREEK,
+            CYRILLIC,
+            INHERITED,
+            CYRILLIC,
+            ARMENIAN,
+            COMMON,
+            ARMENIAN,
+            HEBREW,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            INHERITED,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            INHERITED,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            SYRIAC,
+            ARABIC,
+            THAANA,
+            NKO,
+            SAMARITAN,
+            MANDAIC,
+            ARABIC,
+            DEVANAGARI,
+            INHERITED,
+            DEVANAGARI,
+            COMMON,
+            DEVANAGARI,
+            BENGALI,
+            GURMUKHI,
+            GUJARATI,
+            ORIYA,
+            TAMIL,
+            TELUGU,
+            KANNADA,
+            MALAYALAM,
+            SINHALA,
+            THAI,
+            COMMON,
+            THAI,
+            LAO,
+            TIBETAN,
+            COMMON,
+            TIBETAN,
+            MYANMAR,
+            GEORGIAN,
+            COMMON,
+            GEORGIAN,
+            HANGUL,
+            ETHIOPIC,
+            CHEROKEE,
+            CANADIAN_ABORIGINAL,
+            OGHAM,
+            RUNIC,
+            COMMON,
+            RUNIC,
+            TAGALOG,
+            HANUNOO,
+            COMMON,
+            BUHID,
+            TAGBANWA,
+            KHMER,
+            MONGOLIAN,
+            COMMON,
+            MONGOLIAN,
+            COMMON,
+            MONGOLIAN,
+            CANADIAN_ABORIGINAL,
+            LIMBU,
+            TAI_LE,
+            NEW_TAI_LUE,
+            KHMER,
+            BUGINESE,
+            TAI_THAM,
+            BALINESE,
+            SUNDANESE,
+            BATAK,
+            LEPCHA,
+            OL_CHIKI,
+            SUNDANESE,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            LATIN,
+            GREEK,
+            CYRILLIC,
+            LATIN,
+            GREEK,
+            LATIN,
+            GREEK,
+            LATIN,
+            CYRILLIC,
+            LATIN,
+            GREEK,
+            INHERITED,
+            LATIN,
+            GREEK,
+            COMMON,
+            INHERITED,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            INHERITED,
+            COMMON,
+            GREEK,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            BRAILLE,
+            COMMON,
+            GLAGOLITIC,
+            LATIN,
+            COPTIC,
+            GEORGIAN,
+            TIFINAGH,
+            ETHIOPIC,
+            CYRILLIC,
+            COMMON,
+            HAN,
+            COMMON,
+            HAN,
+            COMMON,
+            HAN,
+            COMMON,
+            HAN,
+            INHERITED,
+            HANGUL,
+            COMMON,
+            HAN,
+            COMMON,
+            HIRAGANA,
+            INHERITED,
+            COMMON,
+            HIRAGANA,
+            COMMON,
+            KATAKANA,
+            COMMON,
+            KATAKANA,
+            BOPOMOFO,
+            HANGUL,
+            COMMON,
+            BOPOMOFO,
+            COMMON,
+            KATAKANA,
+            HANGUL,
+            COMMON,
+            HANGUL,
+            COMMON,
+            KATAKANA,
+            COMMON,
+            HAN,
+            COMMON,
+            HAN,
+            YI,
+            LISU,
+            VAI,
+            CYRILLIC,
+            BAMUM,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            SYLOTI_NAGRI,
+            COMMON,
+            PHAGS_PA,
+            SAURASHTRA,
+            DEVANAGARI,
+            KAYAH_LI,
+            REJANG,
+            HANGUL,
+            JAVANESE,
+            CHAM,
+            MYANMAR,
+            TAI_VIET,
+            MEETEI_MAYEK,
+            ETHIOPIC,
+            MEETEI_MAYEK,
+            HANGUL,
+            UNKNOWN     ,
+            HAN,
+            LATIN,
+            ARMENIAN,
+            HEBREW,
+            ARABIC,
+            COMMON,
+            ARABIC,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            ARABIC,
+            COMMON,
+            LATIN,
+            COMMON,
+            LATIN,
+            COMMON,
+            KATAKANA,
+            COMMON,
+            KATAKANA,
+            COMMON,
+            HANGUL,
+            COMMON,
+            LINEAR_B,
+            COMMON,
+            GREEK,
+            COMMON,
+            INHERITED,
+            LYCIAN,
+            CARIAN,
+            OLD_ITALIC,
+            GOTHIC,
+            UGARITIC,
+            OLD_PERSIAN,
+            DESERET,
+            SHAVIAN,
+            OSMANYA,
+            CYPRIOT,
+            IMPERIAL_ARAMAIC,
+            PHOENICIAN,
+            LYDIAN,
+            MEROITIC_HIEROGLYPHS,
+            MEROITIC_CURSIVE,
+            KHAROSHTHI,
+            OLD_SOUTH_ARABIAN,
+            AVESTAN,
+            INSCRIPTIONAL_PARTHIAN,
+            INSCRIPTIONAL_PAHLAVI,
+            OLD_TURKIC,
+            ARABIC,
+            BRAHMI,
+            KAITHI,
+            SORA_SOMPENG,
+            CHAKMA,
+            SHARADA,
+            TAKRI,
+            CUNEIFORM,
+            EGYPTIAN_HIEROGLYPHS,
+            BAMUM,
+            MIAO,
+            KATAKANA,
+            HIRAGANA,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            INHERITED,
+            COMMON,
+            GREEK,
+            COMMON,
+            ARABIC,
+            COMMON,
+            HIRAGANA,
+            COMMON,
+            HAN,
+            COMMON,
+            INHERITED,
+            UNKNOWN
+        };
+
+        private static HashMap<String, Character.UnicodeScript> aliases;
+        static {
+            aliases = new HashMap<>(128);
+            aliases.put("ARAB", ARABIC);
+            aliases.put("ARMI", IMPERIAL_ARAMAIC);
+            aliases.put("ARMN", ARMENIAN);
+            aliases.put("AVST", AVESTAN);
+            aliases.put("BALI", BALINESE);
+            aliases.put("BAMU", BAMUM);
+            aliases.put("BATK", BATAK);
+            aliases.put("BENG", BENGALI);
+            aliases.put("BOPO", BOPOMOFO);
+            aliases.put("BRAI", BRAILLE);
+            aliases.put("BRAH", BRAHMI);
+            aliases.put("BUGI", BUGINESE);
+            aliases.put("BUHD", BUHID);
+            aliases.put("CAKM", CHAKMA);
+            aliases.put("CANS", CANADIAN_ABORIGINAL);
+            aliases.put("CARI", CARIAN);
+            aliases.put("CHAM", CHAM);
+            aliases.put("CHER", CHEROKEE);
+            aliases.put("COPT", COPTIC);
+            aliases.put("CPRT", CYPRIOT);
+            aliases.put("CYRL", CYRILLIC);
+            aliases.put("DEVA", DEVANAGARI);
+            aliases.put("DSRT", DESERET);
+            aliases.put("EGYP", EGYPTIAN_HIEROGLYPHS);
+            aliases.put("ETHI", ETHIOPIC);
+            aliases.put("GEOR", GEORGIAN);
+            aliases.put("GLAG", GLAGOLITIC);
+            aliases.put("GOTH", GOTHIC);
+            aliases.put("GREK", GREEK);
+            aliases.put("GUJR", GUJARATI);
+            aliases.put("GURU", GURMUKHI);
+            aliases.put("HANG", HANGUL);
+            aliases.put("HANI", HAN);
+            aliases.put("HANO", HANUNOO);
+            aliases.put("HEBR", HEBREW);
+            aliases.put("HIRA", HIRAGANA);
+            // it appears we don't have the KATAKANA_OR_HIRAGANA
+            //aliases.put("HRKT", KATAKANA_OR_HIRAGANA);
+            aliases.put("ITAL", OLD_ITALIC);
+            aliases.put("JAVA", JAVANESE);
+            aliases.put("KALI", KAYAH_LI);
+            aliases.put("KANA", KATAKANA);
+            aliases.put("KHAR", KHAROSHTHI);
+            aliases.put("KHMR", KHMER);
+            aliases.put("KNDA", KANNADA);
+            aliases.put("KTHI", KAITHI);
+            aliases.put("LANA", TAI_THAM);
+            aliases.put("LAOO", LAO);
+            aliases.put("LATN", LATIN);
+            aliases.put("LEPC", LEPCHA);
+            aliases.put("LIMB", LIMBU);
+            aliases.put("LINB", LINEAR_B);
+            aliases.put("LISU", LISU);
+            aliases.put("LYCI", LYCIAN);
+            aliases.put("LYDI", LYDIAN);
+            aliases.put("MAND", MANDAIC);
+            aliases.put("MERC", MEROITIC_CURSIVE);
+            aliases.put("MERO", MEROITIC_HIEROGLYPHS);
+            aliases.put("MLYM", MALAYALAM);
+            aliases.put("MONG", MONGOLIAN);
+            aliases.put("MTEI", MEETEI_MAYEK);
+            aliases.put("MYMR", MYANMAR);
+            aliases.put("NKOO", NKO);
+            aliases.put("OGAM", OGHAM);
+            aliases.put("OLCK", OL_CHIKI);
+            aliases.put("ORKH", OLD_TURKIC);
+            aliases.put("ORYA", ORIYA);
+            aliases.put("OSMA", OSMANYA);
+            aliases.put("PHAG", PHAGS_PA);
+            aliases.put("PLRD", MIAO);
+            aliases.put("PHLI", INSCRIPTIONAL_PAHLAVI);
+            aliases.put("PHNX", PHOENICIAN);
+            aliases.put("PRTI", INSCRIPTIONAL_PARTHIAN);
+            aliases.put("RJNG", REJANG);
+            aliases.put("RUNR", RUNIC);
+            aliases.put("SAMR", SAMARITAN);
+            aliases.put("SARB", OLD_SOUTH_ARABIAN);
+            aliases.put("SAUR", SAURASHTRA);
+            aliases.put("SHAW", SHAVIAN);
+            aliases.put("SHRD", SHARADA);
+            aliases.put("SINH", SINHALA);
+            aliases.put("SORA", SORA_SOMPENG);
+            aliases.put("SUND", SUNDANESE);
+            aliases.put("SYLO", SYLOTI_NAGRI);
+            aliases.put("SYRC", SYRIAC);
+            aliases.put("TAGB", TAGBANWA);
+            aliases.put("TALE", TAI_LE);
+            aliases.put("TAKR", TAKRI);
+            aliases.put("TALU", NEW_TAI_LUE);
+            aliases.put("TAML", TAMIL);
+            aliases.put("TAVT", TAI_VIET);
+            aliases.put("TELU", TELUGU);
+            aliases.put("TFNG", TIFINAGH);
+            aliases.put("TGLG", TAGALOG);
+            aliases.put("THAA", THAANA);
+            aliases.put("THAI", THAI);
+            aliases.put("TIBT", TIBETAN);
+            aliases.put("UGAR", UGARITIC);
+            aliases.put("VAII", VAI);
+            aliases.put("XPEO", OLD_PERSIAN);
+            aliases.put("XSUX", CUNEIFORM);
+            aliases.put("YIII", YI);
+            aliases.put("ZINH", INHERITED);
+            aliases.put("ZYYY", COMMON);
+            aliases.put("ZZZZ", UNKNOWN);
+        }
+
+        /**
+         * Returns the enum constant representing the Unicode script of which
+         * the given character (Unicode code point) is assigned to.
+         *
+         * @param   codePoint the character (Unicode code point) in question.
+         * @return  The {@code UnicodeScript} constant representing the
+         *          Unicode script of which this character is assigned to.
+         *
+         * @exception IllegalArgumentException if the specified
+         * {@code codePoint} is an invalid Unicode code point.
+         * @see Character#isValidCodePoint(int)
+         *
+         */
+        public static UnicodeScript of(int codePoint) {
+            if (!isValidCodePoint(codePoint))
+                throw new IllegalArgumentException();
+            int type = getType(codePoint);
+            // leave SURROGATE and PRIVATE_USE for table lookup
+            if (type == UNASSIGNED)
+                return UNKNOWN;
+            int index = Arrays.binarySearch(scriptStarts, codePoint);
+            if (index < 0)
+                index = -index - 2;
+            return scripts[index];
+        }
+
+        /**
+         * Returns the UnicodeScript constant with the given Unicode script
+         * name or the script name alias. Script names and their aliases are
+         * determined by The Unicode Standard. The files Scripts&lt;version&gt;.txt
+         * and PropertyValueAliases&lt;version&gt;.txt define script names
+         * and the script name aliases for a particular version of the
+         * standard. The {@link Character} class specifies the version of
+         * the standard that it supports.
+         * <p>
+         * Character case is ignored for all of the valid script names.
+         * The en_US locale's case mapping rules are used to provide
+         * case-insensitive string comparisons for script name validation.
+         * <p>
+         *
+         * @param scriptName A {@code UnicodeScript} name.
+         * @return The {@code UnicodeScript} constant identified
+         *         by {@code scriptName}
+         * @throws IllegalArgumentException if {@code scriptName} is an
+         *         invalid name
+         * @throws NullPointerException if {@code scriptName} is null
+         */
+        public static final UnicodeScript forName(String scriptName) {
+            scriptName = scriptName.toUpperCase(Locale.ENGLISH);
+                                 //.replace(' ', '_'));
+            UnicodeScript sc = aliases.get(scriptName);
+            if (sc != null)
+                return sc;
+            return valueOf(scriptName);
+        }
+    }
+
+    /**
+     * The value of the {@code Character}.
+     *
+     * @serial
+     */
+    private final char value;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 3786198910865385080L;
+
+    /**
+     * Constructs a newly allocated {@code Character} object that
+     * represents the specified {@code char} value.
+     *
+     * @param  value   the value to be represented by the
+     *                  {@code Character} object.
+     */
+    public Character(char value) {
+        this.value = value;
+    }
+
+    private static class CharacterCache {
+        private CharacterCache(){}
+
+        static final Character cache[] = new Character[127 + 1];
+
+        static {
+            for (int i = 0; i < cache.length; i++)
+                cache[i] = new Character((char)i);
+        }
+    }
+
+    /**
+     * Returns a <tt>Character</tt> instance representing the specified
+     * <tt>char</tt> value.
+     * If a new <tt>Character</tt> instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Character(char)}, as this method is likely to yield
+     * significantly better space and time performance by caching
+     * frequently requested values.
+     *
+     * This method will always cache values in the range {@code
+     * '\u005Cu0000'} to {@code '\u005Cu007F'}, inclusive, and may
+     * cache other values outside of this range.
+     *
+     * @param  c a char value.
+     * @return a <tt>Character</tt> instance representing <tt>c</tt>.
+     * @since  1.5
+     */
+    public static Character valueOf(char c) {
+        if (c <= 127) { // must cache
+            return CharacterCache.cache[(int)c];
+        }
+        return new Character(c);
+    }
+
+    /**
+     * Returns the value of this {@code Character} object.
+     * @return  the primitive {@code char} value represented by
+     *          this object.
+     */
+    public char charValue() {
+        return value;
+    }
+
+    /**
+     * Returns a hash code for this {@code Character}; equal to the result
+     * of invoking {@code charValue()}.
+     *
+     * @return a hash code value for this {@code Character}
+     */
+    @Override
+    public int hashCode() {
+        return Character.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code char} value; compatible with
+     * {@code Character.hashCode()}.
+     *
+     * @since 1.8
+     *
+     * @param value The {@code char} for which to return a hash code.
+     * @return a hash code value for a {@code char} value.
+     */
+    public static int hashCode(char value) {
+        return (int)value;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Character} object that
+     * represents the same {@code char} value as this object.
+     *
+     * @param   obj   the object to compare with.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Character) {
+            return value == ((Character)obj).charValue();
+        }
+        return false;
+    }
+
+    /**
+     * Returns a {@code String} object representing this
+     * {@code Character}'s value.  The result is a string of
+     * length 1 whose sole component is the primitive
+     * {@code char} value represented by this
+     * {@code Character} object.
+     *
+     * @return  a string representation of this object.
+     */
+    public String toString() {
+        char buf[] = {value};
+        return String.valueOf(buf);
+    }
+
+    /**
+     * Returns a {@code String} object representing the
+     * specified {@code char}.  The result is a string of length
+     * 1 consisting solely of the specified {@code char}.
+     *
+     * @param c the {@code char} to be converted
+     * @return the string representation of the specified {@code char}
+     * @since 1.4
+     */
+    public static String toString(char c) {
+        return String.valueOf(c);
+    }
+
+    /**
+     * Determines whether the specified code point is a valid
+     * <a href="http://www.unicode.org/glossary/#code_point">
+     * Unicode code point value</a>.
+     *
+     * @param  codePoint the Unicode code point to be tested
+     * @return {@code true} if the specified code point value is between
+     *         {@link #MIN_CODE_POINT} and
+     *         {@link #MAX_CODE_POINT} inclusive;
+     *         {@code false} otherwise.
+     * @since  1.5
+     */
+    public static boolean isValidCodePoint(int codePoint) {
+        // Optimized form of:
+        //     codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT
+        int plane = codePoint >>> 16;
+        return plane < ((MAX_CODE_POINT + 1) >>> 16);
+    }
+
+    /**
+     * Determines whether the specified character (Unicode code point)
+     * is in the <a href="#BMP">Basic Multilingual Plane (BMP)</a>.
+     * Such code points can be represented using a single {@code char}.
+     *
+     * @param  codePoint the character (Unicode code point) to be tested
+     * @return {@code true} if the specified code point is between
+     *         {@link #MIN_VALUE} and {@link #MAX_VALUE} inclusive;
+     *         {@code false} otherwise.
+     * @since  1.7
+     */
+    public static boolean isBmpCodePoint(int codePoint) {
+        return codePoint >>> 16 == 0;
+        // Optimized form of:
+        //     codePoint >= MIN_VALUE && codePoint <= MAX_VALUE
+        // We consistently use logical shift (>>>) to facilitate
+        // additional runtime optimizations.
+    }
+
+    /**
+     * Determines whether the specified character (Unicode code point)
+     * is in the <a href="#supplementary">supplementary character</a> range.
+     *
+     * @param  codePoint the character (Unicode code point) to be tested
+     * @return {@code true} if the specified code point is between
+     *         {@link #MIN_SUPPLEMENTARY_CODE_POINT} and
+     *         {@link #MAX_CODE_POINT} inclusive;
+     *         {@code false} otherwise.
+     * @since  1.5
+     */
+    public static boolean isSupplementaryCodePoint(int codePoint) {
+        return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT
+            && codePoint <  MAX_CODE_POINT + 1;
+    }
+
+    /**
+     * Determines if the given {@code char} value is a
+     * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit">
+     * Unicode high-surrogate code unit</a>
+     * (also known as <i>leading-surrogate code unit</i>).
+     *
+     * <p>Such values do not represent characters by themselves,
+     * but are used in the representation of
+     * <a href="#supplementary">supplementary characters</a>
+     * in the UTF-16 encoding.
+     *
+     * @param  ch the {@code char} value to be tested.
+     * @return {@code true} if the {@code char} value is between
+     *         {@link #MIN_HIGH_SURROGATE} and
+     *         {@link #MAX_HIGH_SURROGATE} inclusive;
+     *         {@code false} otherwise.
+     * @see    Character#isLowSurrogate(char)
+     * @see    Character.UnicodeBlock#of(int)
+     * @since  1.5
+     */
+    public static boolean isHighSurrogate(char ch) {
+        // Help VM constant-fold; MAX_HIGH_SURROGATE + 1 == MIN_LOW_SURROGATE
+        return ch >= MIN_HIGH_SURROGATE && ch < (MAX_HIGH_SURROGATE + 1);
+    }
+
+    /**
+     * Determines if the given {@code char} value is a
+     * <a href="http://www.unicode.org/glossary/#low_surrogate_code_unit">
+     * Unicode low-surrogate code unit</a>
+     * (also known as <i>trailing-surrogate code unit</i>).
+     *
+     * <p>Such values do not represent characters by themselves,
+     * but are used in the representation of
+     * <a href="#supplementary">supplementary characters</a>
+     * in the UTF-16 encoding.
+     *
+     * @param  ch the {@code char} value to be tested.
+     * @return {@code true} if the {@code char} value is between
+     *         {@link #MIN_LOW_SURROGATE} and
+     *         {@link #MAX_LOW_SURROGATE} inclusive;
+     *         {@code false} otherwise.
+     * @see    Character#isHighSurrogate(char)
+     * @since  1.5
+     */
+    public static boolean isLowSurrogate(char ch) {
+        return ch >= MIN_LOW_SURROGATE && ch < (MAX_LOW_SURROGATE + 1);
+    }
+
+    /**
+     * Determines if the given {@code char} value is a Unicode
+     * <i>surrogate code unit</i>.
+     *
+     * <p>Such values do not represent characters by themselves,
+     * but are used in the representation of
+     * <a href="#supplementary">supplementary characters</a>
+     * in the UTF-16 encoding.
+     *
+     * <p>A char value is a surrogate code unit if and only if it is either
+     * a {@linkplain #isLowSurrogate(char) low-surrogate code unit} or
+     * a {@linkplain #isHighSurrogate(char) high-surrogate code unit}.
+     *
+     * @param  ch the {@code char} value to be tested.
+     * @return {@code true} if the {@code char} value is between
+     *         {@link #MIN_SURROGATE} and
+     *         {@link #MAX_SURROGATE} inclusive;
+     *         {@code false} otherwise.
+     * @since  1.7
+     */
+    public static boolean isSurrogate(char ch) {
+        return ch >= MIN_SURROGATE && ch < (MAX_SURROGATE + 1);
+    }
+
+    /**
+     * Determines whether the specified pair of {@code char}
+     * values is a valid
+     * <a href="http://www.unicode.org/glossary/#surrogate_pair">
+     * Unicode surrogate pair</a>.
+
+     * <p>This method is equivalent to the expression:
+     * <blockquote><pre>{@code
+     * isHighSurrogate(high) && isLowSurrogate(low)
+     * }</pre></blockquote>
+     *
+     * @param  high the high-surrogate code value to be tested
+     * @param  low the low-surrogate code value to be tested
+     * @return {@code true} if the specified high and
+     * low-surrogate code values represent a valid surrogate pair;
+     * {@code false} otherwise.
+     * @since  1.5
+     */
+    public static boolean isSurrogatePair(char high, char low) {
+        return isHighSurrogate(high) && isLowSurrogate(low);
+    }
+
+    /**
+     * Determines the number of {@code char} values needed to
+     * represent the specified character (Unicode code point). If the
+     * specified character is equal to or greater than 0x10000, then
+     * the method returns 2. Otherwise, the method returns 1.
+     *
+     * <p>This method doesn't validate the specified character to be a
+     * valid Unicode code point. The caller must validate the
+     * character value using {@link #isValidCodePoint(int) isValidCodePoint}
+     * if necessary.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  2 if the character is a valid supplementary character; 1 otherwise.
+     * @see     Character#isSupplementaryCodePoint(int)
+     * @since   1.5
+     */
+    public static int charCount(int codePoint) {
+        return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT ? 2 : 1;
+    }
+
+    /**
+     * Converts the specified surrogate pair to its supplementary code
+     * point value. This method does not validate the specified
+     * surrogate pair. The caller must validate it using {@link
+     * #isSurrogatePair(char, char) isSurrogatePair} if necessary.
+     *
+     * @param  high the high-surrogate code unit
+     * @param  low the low-surrogate code unit
+     * @return the supplementary code point composed from the
+     *         specified surrogate pair.
+     * @since  1.5
+     */
+    public static int toCodePoint(char high, char low) {
+        // Optimized form of:
+        // return ((high - MIN_HIGH_SURROGATE) << 10)
+        //         + (low - MIN_LOW_SURROGATE)
+        //         + MIN_SUPPLEMENTARY_CODE_POINT;
+        return ((high << 10) + low) + (MIN_SUPPLEMENTARY_CODE_POINT
+                                       - (MIN_HIGH_SURROGATE << 10)
+                                       - MIN_LOW_SURROGATE);
+    }
+
+    /**
+     * Returns the code point at the given index of the
+     * {@code CharSequence}. If the {@code char} value at
+     * the given index in the {@code CharSequence} is in the
+     * high-surrogate range, the following index is less than the
+     * length of the {@code CharSequence}, and the
+     * {@code char} value at the following index is in the
+     * low-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at the given index is returned.
+     *
+     * @param seq a sequence of {@code char} values (Unicode code
+     * units)
+     * @param index the index to the {@code char} values (Unicode
+     * code units) in {@code seq} to be converted
+     * @return the Unicode code point at the given index
+     * @exception NullPointerException if {@code seq} is null.
+     * @exception IndexOutOfBoundsException if the value
+     * {@code index} is negative or not less than
+     * {@link CharSequence#length() seq.length()}.
+     * @since  1.5
+     */
+    public static int codePointAt(CharSequence seq, int index) {
+        char c1 = seq.charAt(index);
+        if (isHighSurrogate(c1) && ++index < seq.length()) {
+            char c2 = seq.charAt(index);
+            if (isLowSurrogate(c2)) {
+                return toCodePoint(c1, c2);
+            }
+        }
+        return c1;
+    }
+
+    /**
+     * Returns the code point at the given index of the
+     * {@code char} array. If the {@code char} value at
+     * the given index in the {@code char} array is in the
+     * high-surrogate range, the following index is less than the
+     * length of the {@code char} array, and the
+     * {@code char} value at the following index is in the
+     * low-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at the given index is returned.
+     *
+     * @param a the {@code char} array
+     * @param index the index to the {@code char} values (Unicode
+     * code units) in the {@code char} array to be converted
+     * @return the Unicode code point at the given index
+     * @exception NullPointerException if {@code a} is null.
+     * @exception IndexOutOfBoundsException if the value
+     * {@code index} is negative or not less than
+     * the length of the {@code char} array.
+     * @since  1.5
+     */
+    public static int codePointAt(char[] a, int index) {
+        return codePointAtImpl(a, index, a.length);
+    }
+
+    /**
+     * Returns the code point at the given index of the
+     * {@code char} array, where only array elements with
+     * {@code index} less than {@code limit} can be used. If
+     * the {@code char} value at the given index in the
+     * {@code char} array is in the high-surrogate range, the
+     * following index is less than the {@code limit}, and the
+     * {@code char} value at the following index is in the
+     * low-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at the given index is returned.
+     *
+     * @param a the {@code char} array
+     * @param index the index to the {@code char} values (Unicode
+     * code units) in the {@code char} array to be converted
+     * @param limit the index after the last array element that
+     * can be used in the {@code char} array
+     * @return the Unicode code point at the given index
+     * @exception NullPointerException if {@code a} is null.
+     * @exception IndexOutOfBoundsException if the {@code index}
+     * argument is negative or not less than the {@code limit}
+     * argument, or if the {@code limit} argument is negative or
+     * greater than the length of the {@code char} array.
+     * @since  1.5
+     */
+    public static int codePointAt(char[] a, int index, int limit) {
+        if (index >= limit || limit < 0 || limit > a.length) {
+            throw new IndexOutOfBoundsException();
+        }
+        return codePointAtImpl(a, index, limit);
+    }
+
+    // throws ArrayIndexOutOfBoundsException if index out of bounds
+    static int codePointAtImpl(char[] a, int index, int limit) {
+        char c1 = a[index];
+        if (isHighSurrogate(c1) && ++index < limit) {
+            char c2 = a[index];
+            if (isLowSurrogate(c2)) {
+                return toCodePoint(c1, c2);
+            }
+        }
+        return c1;
+    }
+
+    /**
+     * Returns the code point preceding the given index of the
+     * {@code CharSequence}. If the {@code char} value at
+     * {@code (index - 1)} in the {@code CharSequence} is in
+     * the low-surrogate range, {@code (index - 2)} is not
+     * negative, and the {@code char} value at {@code (index - 2)}
+     * in the {@code CharSequence} is in the
+     * high-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at {@code (index - 1)} is
+     * returned.
+     *
+     * @param seq the {@code CharSequence} instance
+     * @param index the index following the code point that should be returned
+     * @return the Unicode code point value before the given index.
+     * @exception NullPointerException if {@code seq} is null.
+     * @exception IndexOutOfBoundsException if the {@code index}
+     * argument is less than 1 or greater than {@link
+     * CharSequence#length() seq.length()}.
+     * @since  1.5
+     */
+    public static int codePointBefore(CharSequence seq, int index) {
+        char c2 = seq.charAt(--index);
+        if (isLowSurrogate(c2) && index > 0) {
+            char c1 = seq.charAt(--index);
+            if (isHighSurrogate(c1)) {
+                return toCodePoint(c1, c2);
+            }
+        }
+        return c2;
+    }
+
+    /**
+     * Returns the code point preceding the given index of the
+     * {@code char} array. If the {@code char} value at
+     * {@code (index - 1)} in the {@code char} array is in
+     * the low-surrogate range, {@code (index - 2)} is not
+     * negative, and the {@code char} value at {@code (index - 2)}
+     * in the {@code char} array is in the
+     * high-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at {@code (index - 1)} is
+     * returned.
+     *
+     * @param a the {@code char} array
+     * @param index the index following the code point that should be returned
+     * @return the Unicode code point value before the given index.
+     * @exception NullPointerException if {@code a} is null.
+     * @exception IndexOutOfBoundsException if the {@code index}
+     * argument is less than 1 or greater than the length of the
+     * {@code char} array
+     * @since  1.5
+     */
+    public static int codePointBefore(char[] a, int index) {
+        return codePointBeforeImpl(a, index, 0);
+    }
+
+    /**
+     * Returns the code point preceding the given index of the
+     * {@code char} array, where only array elements with
+     * {@code index} greater than or equal to {@code start}
+     * can be used. If the {@code char} value at {@code (index - 1)}
+     * in the {@code char} array is in the
+     * low-surrogate range, {@code (index - 2)} is not less than
+     * {@code start}, and the {@code char} value at
+     * {@code (index - 2)} in the {@code char} array is in
+     * the high-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at {@code (index - 1)} is
+     * returned.
+     *
+     * @param a the {@code char} array
+     * @param index the index following the code point that should be returned
+     * @param start the index of the first array element in the
+     * {@code char} array
+     * @return the Unicode code point value before the given index.
+     * @exception NullPointerException if {@code a} is null.
+     * @exception IndexOutOfBoundsException if the {@code index}
+     * argument is not greater than the {@code start} argument or
+     * is greater than the length of the {@code char} array, or
+     * if the {@code start} argument is negative or not less than
+     * the length of the {@code char} array.
+     * @since  1.5
+     */
+    public static int codePointBefore(char[] a, int index, int start) {
+        if (index <= start || start < 0 || start >= a.length) {
+            throw new IndexOutOfBoundsException();
+        }
+        return codePointBeforeImpl(a, index, start);
+    }
+
+    // throws ArrayIndexOutOfBoundsException if index-1 out of bounds
+    static int codePointBeforeImpl(char[] a, int index, int start) {
+        char c2 = a[--index];
+        if (isLowSurrogate(c2) && index > start) {
+            char c1 = a[--index];
+            if (isHighSurrogate(c1)) {
+                return toCodePoint(c1, c2);
+            }
+        }
+        return c2;
+    }
+
+    /**
+     * Returns the leading surrogate (a
+     * <a href="http://www.unicode.org/glossary/#high_surrogate_code_unit">
+     * high surrogate code unit</a>) of the
+     * <a href="http://www.unicode.org/glossary/#surrogate_pair">
+     * surrogate pair</a>
+     * representing the specified supplementary character (Unicode
+     * code point) in the UTF-16 encoding.  If the specified character
+     * is not a
+     * <a href="Character.html#supplementary">supplementary character</a>,
+     * an unspecified {@code char} is returned.
+     *
+     * <p>If
+     * {@link #isSupplementaryCodePoint isSupplementaryCodePoint(x)}
+     * is {@code true}, then
+     * {@link #isHighSurrogate isHighSurrogate}{@code (highSurrogate(x))} and
+     * {@link #toCodePoint toCodePoint}{@code (highSurrogate(x), }{@link #lowSurrogate lowSurrogate}{@code (x)) == x}
+     * are also always {@code true}.
+     *
+     * @param   codePoint a supplementary character (Unicode code point)
+     * @return  the leading surrogate code unit used to represent the
+     *          character in the UTF-16 encoding
+     * @since   1.7
+     */
+    public static char highSurrogate(int codePoint) {
+        return (char) ((codePoint >>> 10)
+            + (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10)));
+    }
+
+    /**
+     * Returns the trailing surrogate (a
+     * <a href="http://www.unicode.org/glossary/#low_surrogate_code_unit">
+     * low surrogate code unit</a>) of the
+     * <a href="http://www.unicode.org/glossary/#surrogate_pair">
+     * surrogate pair</a>
+     * representing the specified supplementary character (Unicode
+     * code point) in the UTF-16 encoding.  If the specified character
+     * is not a
+     * <a href="Character.html#supplementary">supplementary character</a>,
+     * an unspecified {@code char} is returned.
+     *
+     * <p>If
+     * {@link #isSupplementaryCodePoint isSupplementaryCodePoint(x)}
+     * is {@code true}, then
+     * {@link #isLowSurrogate isLowSurrogate}{@code (lowSurrogate(x))} and
+     * {@link #toCodePoint toCodePoint}{@code (}{@link #highSurrogate highSurrogate}{@code (x), lowSurrogate(x)) == x}
+     * are also always {@code true}.
+     *
+     * @param   codePoint a supplementary character (Unicode code point)
+     * @return  the trailing surrogate code unit used to represent the
+     *          character in the UTF-16 encoding
+     * @since   1.7
+     */
+    public static char lowSurrogate(int codePoint) {
+        return (char) ((codePoint & 0x3ff) + MIN_LOW_SURROGATE);
+    }
+
+    /**
+     * Converts the specified character (Unicode code point) to its
+     * UTF-16 representation. If the specified code point is a BMP
+     * (Basic Multilingual Plane or Plane 0) value, the same value is
+     * stored in {@code dst[dstIndex]}, and 1 is returned. If the
+     * specified code point is a supplementary character, its
+     * surrogate values are stored in {@code dst[dstIndex]}
+     * (high-surrogate) and {@code dst[dstIndex+1]}
+     * (low-surrogate), and 2 is returned.
+     *
+     * @param  codePoint the character (Unicode code point) to be converted.
+     * @param  dst an array of {@code char} in which the
+     * {@code codePoint}'s UTF-16 value is stored.
+     * @param dstIndex the start index into the {@code dst}
+     * array where the converted value is stored.
+     * @return 1 if the code point is a BMP code point, 2 if the
+     * code point is a supplementary code point.
+     * @exception IllegalArgumentException if the specified
+     * {@code codePoint} is not a valid Unicode code point.
+     * @exception NullPointerException if the specified {@code dst} is null.
+     * @exception IndexOutOfBoundsException if {@code dstIndex}
+     * is negative or not less than {@code dst.length}, or if
+     * {@code dst} at {@code dstIndex} doesn't have enough
+     * array element(s) to store the resulting {@code char}
+     * value(s). (If {@code dstIndex} is equal to
+     * {@code dst.length-1} and the specified
+     * {@code codePoint} is a supplementary character, the
+     * high-surrogate value is not stored in
+     * {@code dst[dstIndex]}.)
+     * @since  1.5
+     */
+    public static int toChars(int codePoint, char[] dst, int dstIndex) {
+        if (isBmpCodePoint(codePoint)) {
+            dst[dstIndex] = (char) codePoint;
+            return 1;
+        } else if (isValidCodePoint(codePoint)) {
+            toSurrogates(codePoint, dst, dstIndex);
+            return 2;
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Converts the specified character (Unicode code point) to its
+     * UTF-16 representation stored in a {@code char} array. If
+     * the specified code point is a BMP (Basic Multilingual Plane or
+     * Plane 0) value, the resulting {@code char} array has
+     * the same value as {@code codePoint}. If the specified code
+     * point is a supplementary code point, the resulting
+     * {@code char} array has the corresponding surrogate pair.
+     *
+     * @param  codePoint a Unicode code point
+     * @return a {@code char} array having
+     *         {@code codePoint}'s UTF-16 representation.
+     * @exception IllegalArgumentException if the specified
+     * {@code codePoint} is not a valid Unicode code point.
+     * @since  1.5
+     */
+    public static char[] toChars(int codePoint) {
+        if (isBmpCodePoint(codePoint)) {
+            return new char[] { (char) codePoint };
+        } else if (isValidCodePoint(codePoint)) {
+            char[] result = new char[2];
+            toSurrogates(codePoint, result, 0);
+            return result;
+        } else {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    static void toSurrogates(int codePoint, char[] dst, int index) {
+        // We write elements "backwards" to guarantee all-or-nothing
+        dst[index+1] = lowSurrogate(codePoint);
+        dst[index] = highSurrogate(codePoint);
+    }
+
+    /**
+     * Returns the number of Unicode code points in the text range of
+     * the specified char sequence. The text range begins at the
+     * specified {@code beginIndex} and extends to the
+     * {@code char} at index {@code endIndex - 1}. Thus the
+     * length (in {@code char}s) of the text range is
+     * {@code endIndex-beginIndex}. Unpaired surrogates within
+     * the text range count as one code point each.
+     *
+     * @param seq the char sequence
+     * @param beginIndex the index to the first {@code char} of
+     * the text range.
+     * @param endIndex the index after the last {@code char} of
+     * the text range.
+     * @return the number of Unicode code points in the specified text
+     * range
+     * @exception NullPointerException if {@code seq} is null.
+     * @exception IndexOutOfBoundsException if the
+     * {@code beginIndex} is negative, or {@code endIndex}
+     * is larger than the length of the given sequence, or
+     * {@code beginIndex} is larger than {@code endIndex}.
+     * @since  1.5
+     */
+    public static int codePointCount(CharSequence seq, int beginIndex, int endIndex) {
+        int length = seq.length();
+        if (beginIndex < 0 || endIndex > length || beginIndex > endIndex) {
+            throw new IndexOutOfBoundsException();
+        }
+        int n = endIndex - beginIndex;
+        for (int i = beginIndex; i < endIndex; ) {
+            if (isHighSurrogate(seq.charAt(i++)) && i < endIndex &&
+                isLowSurrogate(seq.charAt(i))) {
+                n--;
+                i++;
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Returns the number of Unicode code points in a subarray of the
+     * {@code char} array argument. The {@code offset}
+     * argument is the index of the first {@code char} of the
+     * subarray and the {@code count} argument specifies the
+     * length of the subarray in {@code char}s. Unpaired
+     * surrogates within the subarray count as one code point each.
+     *
+     * @param a the {@code char} array
+     * @param offset the index of the first {@code char} in the
+     * given {@code char} array
+     * @param count the length of the subarray in {@code char}s
+     * @return the number of Unicode code points in the specified subarray
+     * @exception NullPointerException if {@code a} is null.
+     * @exception IndexOutOfBoundsException if {@code offset} or
+     * {@code count} is negative, or if {@code offset +
+     * count} is larger than the length of the given array.
+     * @since  1.5
+     */
+    public static int codePointCount(char[] a, int offset, int count) {
+        if (count > a.length - offset || offset < 0 || count < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        return codePointCountImpl(a, offset, count);
+    }
+
+    static int codePointCountImpl(char[] a, int offset, int count) {
+        int endIndex = offset + count;
+        int n = count;
+        for (int i = offset; i < endIndex; ) {
+            if (isHighSurrogate(a[i++]) && i < endIndex &&
+                isLowSurrogate(a[i])) {
+                n--;
+                i++;
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Returns the index within the given char sequence that is offset
+     * from the given {@code index} by {@code codePointOffset}
+     * code points. Unpaired surrogates within the text range given by
+     * {@code index} and {@code codePointOffset} count as
+     * one code point each.
+     *
+     * @param seq the char sequence
+     * @param index the index to be offset
+     * @param codePointOffset the offset in code points
+     * @return the index within the char sequence
+     * @exception NullPointerException if {@code seq} is null.
+     * @exception IndexOutOfBoundsException if {@code index}
+     *   is negative or larger then the length of the char sequence,
+     *   or if {@code codePointOffset} is positive and the
+     *   subsequence starting with {@code index} has fewer than
+     *   {@code codePointOffset} code points, or if
+     *   {@code codePointOffset} is negative and the subsequence
+     *   before {@code index} has fewer than the absolute value
+     *   of {@code codePointOffset} code points.
+     * @since 1.5
+     */
+    public static int offsetByCodePoints(CharSequence seq, int index,
+                                         int codePointOffset) {
+        int length = seq.length();
+        if (index < 0 || index > length) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        int x = index;
+        if (codePointOffset >= 0) {
+            int i;
+            for (i = 0; x < length && i < codePointOffset; i++) {
+                if (isHighSurrogate(seq.charAt(x++)) && x < length &&
+                    isLowSurrogate(seq.charAt(x))) {
+                    x++;
+                }
+            }
+            if (i < codePointOffset) {
+                throw new IndexOutOfBoundsException();
+            }
+        } else {
+            int i;
+            for (i = codePointOffset; x > 0 && i < 0; i++) {
+                if (isLowSurrogate(seq.charAt(--x)) && x > 0 &&
+                    isHighSurrogate(seq.charAt(x-1))) {
+                    x--;
+                }
+            }
+            if (i < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+        }
+        return x;
+    }
+
+    /**
+     * Returns the index within the given {@code char} subarray
+     * that is offset from the given {@code index} by
+     * {@code codePointOffset} code points. The
+     * {@code start} and {@code count} arguments specify a
+     * subarray of the {@code char} array. Unpaired surrogates
+     * within the text range given by {@code index} and
+     * {@code codePointOffset} count as one code point each.
+     *
+     * @param a the {@code char} array
+     * @param start the index of the first {@code char} of the
+     * subarray
+     * @param count the length of the subarray in {@code char}s
+     * @param index the index to be offset
+     * @param codePointOffset the offset in code points
+     * @return the index within the subarray
+     * @exception NullPointerException if {@code a} is null.
+     * @exception IndexOutOfBoundsException
+     *   if {@code start} or {@code count} is negative,
+     *   or if {@code start + count} is larger than the length of
+     *   the given array,
+     *   or if {@code index} is less than {@code start} or
+     *   larger then {@code start + count},
+     *   or if {@code codePointOffset} is positive and the text range
+     *   starting with {@code index} and ending with {@code start + count - 1}
+     *   has fewer than {@code codePointOffset} code
+     *   points,
+     *   or if {@code codePointOffset} is negative and the text range
+     *   starting with {@code start} and ending with {@code index - 1}
+     *   has fewer than the absolute value of
+     *   {@code codePointOffset} code points.
+     * @since 1.5
+     */
+    public static int offsetByCodePoints(char[] a, int start, int count,
+                                         int index, int codePointOffset) {
+        if (count > a.length-start || start < 0 || count < 0
+            || index < start || index > start+count) {
+            throw new IndexOutOfBoundsException();
+        }
+        return offsetByCodePointsImpl(a, start, count, index, codePointOffset);
+    }
+
+    static int offsetByCodePointsImpl(char[]a, int start, int count,
+                                      int index, int codePointOffset) {
+        int x = index;
+        if (codePointOffset >= 0) {
+            int limit = start + count;
+            int i;
+            for (i = 0; x < limit && i < codePointOffset; i++) {
+                if (isHighSurrogate(a[x++]) && x < limit &&
+                    isLowSurrogate(a[x])) {
+                    x++;
+                }
+            }
+            if (i < codePointOffset) {
+                throw new IndexOutOfBoundsException();
+            }
+        } else {
+            int i;
+            for (i = codePointOffset; x > start && i < 0; i++) {
+                if (isLowSurrogate(a[--x]) && x > start &&
+                    isHighSurrogate(a[x-1])) {
+                    x--;
+                }
+            }
+            if (i < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+        }
+        return x;
+    }
+
+    /**
+     * Determines if the specified character is a lowercase character.
+     * <p>
+     * A character is lowercase if its general category type, provided
+     * by {@code Character.getType(ch)}, is
+     * {@code LOWERCASE_LETTER}, or it has contributory property
+     * Other_Lowercase as defined by the Unicode Standard.
+     * <p>
+     * The following are examples of lowercase characters:
+     * <blockquote><pre>
+     * a b c d e f g h i j k l m n o p q r s t u v w x y z
+     * '&#92;u00DF' '&#92;u00E0' '&#92;u00E1' '&#92;u00E2' '&#92;u00E3' '&#92;u00E4' '&#92;u00E5' '&#92;u00E6'
+     * '&#92;u00E7' '&#92;u00E8' '&#92;u00E9' '&#92;u00EA' '&#92;u00EB' '&#92;u00EC' '&#92;u00ED' '&#92;u00EE'
+     * '&#92;u00EF' '&#92;u00F0' '&#92;u00F1' '&#92;u00F2' '&#92;u00F3' '&#92;u00F4' '&#92;u00F5' '&#92;u00F6'
+     * '&#92;u00F8' '&#92;u00F9' '&#92;u00FA' '&#92;u00FB' '&#92;u00FC' '&#92;u00FD' '&#92;u00FE' '&#92;u00FF'
+     * </pre></blockquote>
+     * <p> Many other Unicode characters are lowercase too.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isLowerCase(int)} method.
+     *
+     * @param   ch   the character to be tested.
+     * @return  {@code true} if the character is lowercase;
+     *          {@code false} otherwise.
+     * @see     Character#isLowerCase(char)
+     * @see     Character#isTitleCase(char)
+     * @see     Character#toLowerCase(char)
+     * @see     Character#getType(char)
+     */
+    public static boolean isLowerCase(char ch) {
+        return isLowerCase((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is a
+     * lowercase character.
+     * <p>
+     * A character is lowercase if its general category type, provided
+     * by {@link Character#getType getType(codePoint)}, is
+     * {@code LOWERCASE_LETTER}, or it has contributory property
+     * Other_Lowercase as defined by the Unicode Standard.
+     * <p>
+     * The following are examples of lowercase characters:
+     * <blockquote><pre>
+     * a b c d e f g h i j k l m n o p q r s t u v w x y z
+     * '&#92;u00DF' '&#92;u00E0' '&#92;u00E1' '&#92;u00E2' '&#92;u00E3' '&#92;u00E4' '&#92;u00E5' '&#92;u00E6'
+     * '&#92;u00E7' '&#92;u00E8' '&#92;u00E9' '&#92;u00EA' '&#92;u00EB' '&#92;u00EC' '&#92;u00ED' '&#92;u00EE'
+     * '&#92;u00EF' '&#92;u00F0' '&#92;u00F1' '&#92;u00F2' '&#92;u00F3' '&#92;u00F4' '&#92;u00F5' '&#92;u00F6'
+     * '&#92;u00F8' '&#92;u00F9' '&#92;u00FA' '&#92;u00FB' '&#92;u00FC' '&#92;u00FD' '&#92;u00FE' '&#92;u00FF'
+     * </pre></blockquote>
+     * <p> Many other Unicode characters are lowercase too.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is lowercase;
+     *          {@code false} otherwise.
+     * @see     Character#isLowerCase(int)
+     * @see     Character#isTitleCase(int)
+     * @see     Character#toLowerCase(int)
+     * @see     Character#getType(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isLowerCase(int codePoint) {
+        return getType(codePoint) == Character.LOWERCASE_LETTER ||
+               CharacterData.of(codePoint).isOtherLowercase(codePoint);
+    }
+    */
+    public static boolean isLowerCase(int codePoint) {
+        return isLowerCaseImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isLowerCaseImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is an uppercase character.
+     * <p>
+     * A character is uppercase if its general category type, provided by
+     * {@code Character.getType(ch)}, is {@code UPPERCASE_LETTER}.
+     * or it has contributory property Other_Uppercase as defined by the Unicode Standard.
+     * <p>
+     * The following are examples of uppercase characters:
+     * <blockquote><pre>
+     * A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+     * '&#92;u00C0' '&#92;u00C1' '&#92;u00C2' '&#92;u00C3' '&#92;u00C4' '&#92;u00C5' '&#92;u00C6' '&#92;u00C7'
+     * '&#92;u00C8' '&#92;u00C9' '&#92;u00CA' '&#92;u00CB' '&#92;u00CC' '&#92;u00CD' '&#92;u00CE' '&#92;u00CF'
+     * '&#92;u00D0' '&#92;u00D1' '&#92;u00D2' '&#92;u00D3' '&#92;u00D4' '&#92;u00D5' '&#92;u00D6' '&#92;u00D8'
+     * '&#92;u00D9' '&#92;u00DA' '&#92;u00DB' '&#92;u00DC' '&#92;u00DD' '&#92;u00DE'
+     * </pre></blockquote>
+     * <p> Many other Unicode characters are uppercase too.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isUpperCase(int)} method.
+     *
+     * @param   ch   the character to be tested.
+     * @return  {@code true} if the character is uppercase;
+     *          {@code false} otherwise.
+     * @see     Character#isLowerCase(char)
+     * @see     Character#isTitleCase(char)
+     * @see     Character#toUpperCase(char)
+     * @see     Character#getType(char)
+     * @since   1.0
+     */
+    public static boolean isUpperCase(char ch) {
+        return isUpperCase((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is an uppercase character.
+     * <p>
+     * A character is uppercase if its general category type, provided by
+     * {@link Character#getType(int) getType(codePoint)}, is {@code UPPERCASE_LETTER},
+     * or it has contributory property Other_Uppercase as defined by the Unicode Standard.
+     * <p>
+     * The following are examples of uppercase characters:
+     * <blockquote><pre>
+     * A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
+     * '&#92;u00C0' '&#92;u00C1' '&#92;u00C2' '&#92;u00C3' '&#92;u00C4' '&#92;u00C5' '&#92;u00C6' '&#92;u00C7'
+     * '&#92;u00C8' '&#92;u00C9' '&#92;u00CA' '&#92;u00CB' '&#92;u00CC' '&#92;u00CD' '&#92;u00CE' '&#92;u00CF'
+     * '&#92;u00D0' '&#92;u00D1' '&#92;u00D2' '&#92;u00D3' '&#92;u00D4' '&#92;u00D5' '&#92;u00D6' '&#92;u00D8'
+     * '&#92;u00D9' '&#92;u00DA' '&#92;u00DB' '&#92;u00DC' '&#92;u00DD' '&#92;u00DE'
+     * </pre></blockquote>
+     * <p> Many other Unicode characters are uppercase too.<p>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is uppercase;
+     *          {@code false} otherwise.
+     * @see     Character#isLowerCase(int)
+     * @see     Character#isTitleCase(int)
+     * @see     Character#toUpperCase(int)
+     * @see     Character#getType(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isUpperCase(int codePoint) {
+        return getType(codePoint) == Character.UPPERCASE_LETTER ||
+               CharacterData.of(codePoint).isOtherUppercase(codePoint);
+    }
+    */
+    public static boolean isUpperCase(int codePoint) {
+        return isUpperCaseImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isUpperCaseImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is a titlecase character.
+     * <p>
+     * A character is a titlecase character if its general
+     * category type, provided by {@code Character.getType(ch)},
+     * is {@code TITLECASE_LETTER}.
+     * <p>
+     * Some characters look like pairs of Latin letters. For example, there
+     * is an uppercase letter that looks like "LJ" and has a corresponding
+     * lowercase letter that looks like "lj". A third form, which looks like "Lj",
+     * is the appropriate form to use when rendering a word in lowercase
+     * with initial capitals, as for a book title.
+     * <p>
+     * These are some of the Unicode characters for which this method returns
+     * {@code true}:
+     * <ul>
+     * <li>{@code LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON}
+     * <li>{@code LATIN CAPITAL LETTER L WITH SMALL LETTER J}
+     * <li>{@code LATIN CAPITAL LETTER N WITH SMALL LETTER J}
+     * <li>{@code LATIN CAPITAL LETTER D WITH SMALL LETTER Z}
+     * </ul>
+     * <p> Many other Unicode characters are titlecase too.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isTitleCase(int)} method.
+     *
+     * @param   ch   the character to be tested.
+     * @return  {@code true} if the character is titlecase;
+     *          {@code false} otherwise.
+     * @see     Character#isLowerCase(char)
+     * @see     Character#isUpperCase(char)
+     * @see     Character#toTitleCase(char)
+     * @see     Character#getType(char)
+     * @since   1.0.2
+     */
+    public static boolean isTitleCase(char ch) {
+        return isTitleCase((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is a titlecase character.
+     * <p>
+     * A character is a titlecase character if its general
+     * category type, provided by {@link Character#getType(int) getType(codePoint)},
+     * is {@code TITLECASE_LETTER}.
+     * <p>
+     * Some characters look like pairs of Latin letters. For example, there
+     * is an uppercase letter that looks like "LJ" and has a corresponding
+     * lowercase letter that looks like "lj". A third form, which looks like "Lj",
+     * is the appropriate form to use when rendering a word in lowercase
+     * with initial capitals, as for a book title.
+     * <p>
+     * These are some of the Unicode characters for which this method returns
+     * {@code true}:
+     * <ul>
+     * <li>{@code LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON}
+     * <li>{@code LATIN CAPITAL LETTER L WITH SMALL LETTER J}
+     * <li>{@code LATIN CAPITAL LETTER N WITH SMALL LETTER J}
+     * <li>{@code LATIN CAPITAL LETTER D WITH SMALL LETTER Z}
+     * </ul>
+     * <p> Many other Unicode characters are titlecase too.<p>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is titlecase;
+     *          {@code false} otherwise.
+     * @see     Character#isLowerCase(int)
+     * @see     Character#isUpperCase(int)
+     * @see     Character#toTitleCase(int)
+     * @see     Character#getType(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isTitleCase(int codePoint) {
+        return getType(codePoint) == Character.TITLECASE_LETTER;
+    }
+    */
+    public static boolean isTitleCase(int codePoint) {
+        return isTitleCaseImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isTitleCaseImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is a digit.
+     * <p>
+     * A character is a digit if its general category type, provided
+     * by {@code Character.getType(ch)}, is
+     * {@code DECIMAL_DIGIT_NUMBER}.
+     * <p>
+     * Some Unicode character ranges that contain digits:
+     * <ul>
+     * <li>{@code '\u005Cu0030'} through {@code '\u005Cu0039'},
+     *     ISO-LATIN-1 digits ({@code '0'} through {@code '9'})
+     * <li>{@code '\u005Cu0660'} through {@code '\u005Cu0669'},
+     *     Arabic-Indic digits
+     * <li>{@code '\u005Cu06F0'} through {@code '\u005Cu06F9'},
+     *     Extended Arabic-Indic digits
+     * <li>{@code '\u005Cu0966'} through {@code '\u005Cu096F'},
+     *     Devanagari digits
+     * <li>{@code '\u005CuFF10'} through {@code '\u005CuFF19'},
+     *     Fullwidth digits
+     * </ul>
+     *
+     * Many other character ranges contain digits as well.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isDigit(int)} method.
+     *
+     * @param   ch   the character to be tested.
+     * @return  {@code true} if the character is a digit;
+     *          {@code false} otherwise.
+     * @see     Character#digit(char, int)
+     * @see     Character#forDigit(int, int)
+     * @see     Character#getType(char)
+     */
+    public static boolean isDigit(char ch) {
+        return isDigit((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is a digit.
+     * <p>
+     * A character is a digit if its general category type, provided
+     * by {@link Character#getType(int) getType(codePoint)}, is
+     * {@code DECIMAL_DIGIT_NUMBER}.
+     * <p>
+     * Some Unicode character ranges that contain digits:
+     * <ul>
+     * <li>{@code '\u005Cu0030'} through {@code '\u005Cu0039'},
+     *     ISO-LATIN-1 digits ({@code '0'} through {@code '9'})
+     * <li>{@code '\u005Cu0660'} through {@code '\u005Cu0669'},
+     *     Arabic-Indic digits
+     * <li>{@code '\u005Cu06F0'} through {@code '\u005Cu06F9'},
+     *     Extended Arabic-Indic digits
+     * <li>{@code '\u005Cu0966'} through {@code '\u005Cu096F'},
+     *     Devanagari digits
+     * <li>{@code '\u005CuFF10'} through {@code '\u005CuFF19'},
+     *     Fullwidth digits
+     * </ul>
+     *
+     * Many other character ranges contain digits as well.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is a digit;
+     *          {@code false} otherwise.
+     * @see     Character#forDigit(int, int)
+     * @see     Character#getType(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isDigit(int codePoint) {
+        return getType(codePoint) == Character.DECIMAL_DIGIT_NUMBER;
+    }
+    */
+    public static boolean isDigit(int codePoint) {
+        return isDigitImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isDigitImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if a character is defined in Unicode.
+     * <p>
+     * A character is defined if at least one of the following is true:
+     * <ul>
+     * <li>It has an entry in the UnicodeData file.
+     * <li>It has a value in a range defined by the UnicodeData file.
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isDefined(int)} method.
+     *
+     * @param   ch   the character to be tested
+     * @return  {@code true} if the character has a defined meaning
+     *          in Unicode; {@code false} otherwise.
+     * @see     Character#isDigit(char)
+     * @see     Character#isLetter(char)
+     * @see     Character#isLetterOrDigit(char)
+     * @see     Character#isLowerCase(char)
+     * @see     Character#isTitleCase(char)
+     * @see     Character#isUpperCase(char)
+     * @since   1.0.2
+     */
+    public static boolean isDefined(char ch) {
+        return isDefined((int)ch);
+    }
+
+    /**
+     * Determines if a character (Unicode code point) is defined in Unicode.
+     * <p>
+     * A character is defined if at least one of the following is true:
+     * <ul>
+     * <li>It has an entry in the UnicodeData file.
+     * <li>It has a value in a range defined by the UnicodeData file.
+     * </ul>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character has a defined meaning
+     *          in Unicode; {@code false} otherwise.
+     * @see     Character#isDigit(int)
+     * @see     Character#isLetter(int)
+     * @see     Character#isLetterOrDigit(int)
+     * @see     Character#isLowerCase(int)
+     * @see     Character#isTitleCase(int)
+     * @see     Character#isUpperCase(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isDefined(int codePoint) {
+        return getType(codePoint) != Character.UNASSIGNED;
+    }
+    */
+    public static boolean isDefined(int codePoint) {
+        return isDefinedImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isDefinedImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is a letter.
+     * <p>
+     * A character is considered to be a letter if its general
+     * category type, provided by {@code Character.getType(ch)},
+     * is any of the following:
+     * <ul>
+     * <li> {@code UPPERCASE_LETTER}
+     * <li> {@code LOWERCASE_LETTER}
+     * <li> {@code TITLECASE_LETTER}
+     * <li> {@code MODIFIER_LETTER}
+     * <li> {@code OTHER_LETTER}
+     * </ul>
+     *
+     * Not all letters have case. Many characters are
+     * letters but are neither uppercase nor lowercase nor titlecase.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isLetter(int)} method.
+     *
+     * @param   ch   the character to be tested.
+     * @return  {@code true} if the character is a letter;
+     *          {@code false} otherwise.
+     * @see     Character#isDigit(char)
+     * @see     Character#isJavaIdentifierStart(char)
+     * @see     Character#isJavaLetter(char)
+     * @see     Character#isJavaLetterOrDigit(char)
+     * @see     Character#isLetterOrDigit(char)
+     * @see     Character#isLowerCase(char)
+     * @see     Character#isTitleCase(char)
+     * @see     Character#isUnicodeIdentifierStart(char)
+     * @see     Character#isUpperCase(char)
+     */
+    public static boolean isLetter(char ch) {
+        return isLetter((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is a letter.
+     * <p>
+     * A character is considered to be a letter if its general
+     * category type, provided by {@link Character#getType(int) getType(codePoint)},
+     * is any of the following:
+     * <ul>
+     * <li> {@code UPPERCASE_LETTER}
+     * <li> {@code LOWERCASE_LETTER}
+     * <li> {@code TITLECASE_LETTER}
+     * <li> {@code MODIFIER_LETTER}
+     * <li> {@code OTHER_LETTER}
+     * </ul>
+     *
+     * Not all letters have case. Many characters are
+     * letters but are neither uppercase nor lowercase nor titlecase.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is a letter;
+     *          {@code false} otherwise.
+     * @see     Character#isDigit(int)
+     * @see     Character#isJavaIdentifierStart(int)
+     * @see     Character#isLetterOrDigit(int)
+     * @see     Character#isLowerCase(int)
+     * @see     Character#isTitleCase(int)
+     * @see     Character#isUnicodeIdentifierStart(int)
+     * @see     Character#isUpperCase(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isLetter(int codePoint) {
+        return ((((1 << Character.UPPERCASE_LETTER) |
+            (1 << Character.LOWERCASE_LETTER) |
+            (1 << Character.TITLECASE_LETTER) |
+            (1 << Character.MODIFIER_LETTER) |
+            (1 << Character.OTHER_LETTER)) >> getType(codePoint)) & 1)
+            != 0;
+    }
+    */
+    public static boolean isLetter(int codePoint) {
+        return isLetterImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isLetterImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is a letter or digit.
+     * <p>
+     * A character is considered to be a letter or digit if either
+     * {@code Character.isLetter(char ch)} or
+     * {@code Character.isDigit(char ch)} returns
+     * {@code true} for the character.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isLetterOrDigit(int)} method.
+     *
+     * @param   ch   the character to be tested.
+     * @return  {@code true} if the character is a letter or digit;
+     *          {@code false} otherwise.
+     * @see     Character#isDigit(char)
+     * @see     Character#isJavaIdentifierPart(char)
+     * @see     Character#isJavaLetter(char)
+     * @see     Character#isJavaLetterOrDigit(char)
+     * @see     Character#isLetter(char)
+     * @see     Character#isUnicodeIdentifierPart(char)
+     * @since   1.0.2
+     */
+    public static boolean isLetterOrDigit(char ch) {
+        return isLetterOrDigit((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is a letter or digit.
+     * <p>
+     * A character is considered to be a letter or digit if either
+     * {@link #isLetter(int) isLetter(codePoint)} or
+     * {@link #isDigit(int) isDigit(codePoint)} returns
+     * {@code true} for the character.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is a letter or digit;
+     *          {@code false} otherwise.
+     * @see     Character#isDigit(int)
+     * @see     Character#isJavaIdentifierPart(int)
+     * @see     Character#isLetter(int)
+     * @see     Character#isUnicodeIdentifierPart(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isLetterOrDigit(int codePoint) {
+        return ((((1 << Character.UPPERCASE_LETTER) |
+            (1 << Character.LOWERCASE_LETTER) |
+            (1 << Character.TITLECASE_LETTER) |
+            (1 << Character.MODIFIER_LETTER) |
+            (1 << Character.OTHER_LETTER) |
+            (1 << Character.DECIMAL_DIGIT_NUMBER)) >> getType(codePoint)) & 1)
+            != 0;
+    }
+    */
+    public static boolean isLetterOrDigit(int codePoint) {
+        return isLetterOrDigitImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isLetterOrDigitImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is permissible as the first
+     * character in a Java identifier.
+     * <p>
+     * A character may start a Java identifier if and only if
+     * one of the following is true:
+     * <ul>
+     * <li> {@link #isLetter(char) isLetter(ch)} returns {@code true}
+     * <li> {@link #getType(char) getType(ch)} returns {@code LETTER_NUMBER}
+     * <li> {@code ch} is a currency symbol (such as {@code '$'})
+     * <li> {@code ch} is a connecting punctuation character (such as {@code '_'}).
+     * </ul>
+     *
+     * @param   ch the character to be tested.
+     * @return  {@code true} if the character may start a Java
+     *          identifier; {@code false} otherwise.
+     * @see     Character#isJavaLetterOrDigit(char)
+     * @see     Character#isJavaIdentifierStart(char)
+     * @see     Character#isJavaIdentifierPart(char)
+     * @see     Character#isLetter(char)
+     * @see     Character#isLetterOrDigit(char)
+     * @see     Character#isUnicodeIdentifierStart(char)
+     * @since   1.02
+     * @deprecated Replaced by isJavaIdentifierStart(char).
+     */
+    @Deprecated
+    public static boolean isJavaLetter(char ch) {
+        return isJavaIdentifierStart(ch);
+    }
+
+    /**
+     * Determines if the specified character may be part of a Java
+     * identifier as other than the first character.
+     * <p>
+     * A character may be part of a Java identifier if and only if any
+     * of the following are true:
+     * <ul>
+     * <li>  it is a letter
+     * <li>  it is a currency symbol (such as {@code '$'})
+     * <li>  it is a connecting punctuation character (such as {@code '_'})
+     * <li>  it is a digit
+     * <li>  it is a numeric letter (such as a Roman numeral character)
+     * <li>  it is a combining mark
+     * <li>  it is a non-spacing mark
+     * <li> {@code isIdentifierIgnorable} returns
+     * {@code true} for the character.
+     * </ul>
+     *
+     * @param   ch the character to be tested.
+     * @return  {@code true} if the character may be part of a
+     *          Java identifier; {@code false} otherwise.
+     * @see     Character#isJavaLetter(char)
+     * @see     Character#isJavaIdentifierStart(char)
+     * @see     Character#isJavaIdentifierPart(char)
+     * @see     Character#isLetter(char)
+     * @see     Character#isLetterOrDigit(char)
+     * @see     Character#isUnicodeIdentifierPart(char)
+     * @see     Character#isIdentifierIgnorable(char)
+     * @since   1.02
+     * @deprecated Replaced by isJavaIdentifierPart(char).
+     */
+    @Deprecated
+    public static boolean isJavaLetterOrDigit(char ch) {
+        return isJavaIdentifierPart(ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is an alphabet.
+     * <p>
+     * A character is considered to be alphabetic if its general category type,
+     * provided by {@link Character#getType(int) getType(codePoint)}, is any of
+     * the following:
+     * <ul>
+     * <li> <code>UPPERCASE_LETTER</code>
+     * <li> <code>LOWERCASE_LETTER</code>
+     * <li> <code>TITLECASE_LETTER</code>
+     * <li> <code>MODIFIER_LETTER</code>
+     * <li> <code>OTHER_LETTER</code>
+     * <li> <code>LETTER_NUMBER</code>
+     * </ul>
+     * or it has contributory property Other_Alphabetic as defined by the
+     * Unicode Standard.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  <code>true</code> if the character is a Unicode alphabet
+     *          character, <code>false</code> otherwise.
+     * @since   1.7
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isAlphabetic(int codePoint) {
+        return (((((1 << Character.UPPERCASE_LETTER) |
+            (1 << Character.LOWERCASE_LETTER) |
+            (1 << Character.TITLECASE_LETTER) |
+            (1 << Character.MODIFIER_LETTER) |
+            (1 << Character.OTHER_LETTER) |
+            (1 << Character.LETTER_NUMBER)) >> getType(codePoint)) & 1) != 0) ||
+            CharacterData.of(codePoint).isOtherAlphabetic(codePoint);
+    }
+    */
+    public static boolean isAlphabetic(int codePoint) {
+        return isAlphabeticImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isAlphabeticImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character (Unicode code point) is a CJKV
+     * (Chinese, Japanese, Korean and Vietnamese) ideograph, as defined by
+     * the Unicode Standard.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  <code>true</code> if the character is a Unicode ideograph
+     *          character, <code>false</code> otherwise.
+     * @since   1.7
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isIdeographic(int codePoint) {
+        return CharacterData.of(codePoint).isIdeographic(codePoint);
+    }
+    */
+    public static boolean isIdeographic(int codePoint) {
+        return isIdeographicImpl(codePoint);
+    }
+    @FastNative
+    static native boolean isIdeographicImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see     javax.lang.model.SourceVersion#isIdentifier(CharSequence)
+    /**
+     * Determines if the specified character is
+     * permissible as the first character in a Java identifier.
+     * <p>
+     * A character may start a Java identifier if and only if
+     * one of the following conditions is true:
+     * <ul>
+     * <li> {@link #isLetter(char) isLetter(ch)} returns {@code true}
+     * <li> {@link #getType(char) getType(ch)} returns {@code LETTER_NUMBER}
+     * <li> {@code ch} is a currency symbol (such as {@code '$'})
+     * <li> {@code ch} is a connecting punctuation character (such as {@code '_'}).
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isJavaIdentifierStart(int)} method.
+     *
+     * @param   ch the character to be tested.
+     * @return  {@code true} if the character may start a Java identifier;
+     *          {@code false} otherwise.
+     * @see     Character#isJavaIdentifierPart(char)
+     * @see     Character#isLetter(char)
+     * @see     Character#isUnicodeIdentifierStart(char)
+     * @since   1.1
+     */
+    public static boolean isJavaIdentifierStart(char ch) {
+        return isJavaIdentifierStart((int)ch);
+    }
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see     javax.lang.model.SourceVersion#isIdentifier(CharSequence)
+    /**
+     * Determines if the character (Unicode code point) is
+     * permissible as the first character in a Java identifier.
+     * <p>
+     * A character may start a Java identifier if and only if
+     * one of the following conditions is true:
+     * <ul>
+     * <li> {@link #isLetter(int) isLetter(codePoint)}
+     *      returns {@code true}
+     * <li> {@link #getType(int) getType(codePoint)}
+     *      returns {@code LETTER_NUMBER}
+     * <li> the referenced character is a currency symbol (such as {@code '$'})
+     * <li> the referenced character is a connecting punctuation character
+     *      (such as {@code '_'}).
+     * </ul>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character may start a Java identifier;
+     *          {@code false} otherwise.
+     * @see     Character#isJavaIdentifierPart(int)
+     * @see     Character#isLetter(int)
+     * @see     Character#isUnicodeIdentifierStart(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Use ICU.
+    /*
+    public static boolean isJavaIdentifierStart(int codePoint) {
+        return CharacterData.of(codePoint).isJavaIdentifierStart(codePoint);
+    }
+    */
+    public static boolean isJavaIdentifierStart(int codePoint) {
+        // Use precomputed bitmasks to optimize the ASCII range.
+        if (codePoint < 64) {
+            return (codePoint == '$'); // There's only one character in this range.
+        } else if (codePoint < 128) {
+            return (0x7fffffe87fffffeL & (1L << (codePoint - 64))) != 0;
+        }
+        return ((1 << getType(codePoint))
+                & ((1 << UPPERCASE_LETTER)
+                   | (1 << LOWERCASE_LETTER)
+                   | (1  << TITLECASE_LETTER)
+                   | (1  << MODIFIER_LETTER)
+                   | (1  << OTHER_LETTER)
+                   | (1  << CURRENCY_SYMBOL)
+                   | (1  << CONNECTOR_PUNCTUATION)
+                   | (1  << LETTER_NUMBER))) != 0;
+    }
+    // END Android-changed: Use ICU.
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see     javax.lang.model.SourceVersion#isIdentifier(CharSequence)
+    /**
+     * Determines if the specified character may be part of a Java
+     * identifier as other than the first character.
+     * <p>
+     * A character may be part of a Java identifier if any of the following
+     * are true:
+     * <ul>
+     * <li>  it is a letter
+     * <li>  it is a currency symbol (such as {@code '$'})
+     * <li>  it is a connecting punctuation character (such as {@code '_'})
+     * <li>  it is a digit
+     * <li>  it is a numeric letter (such as a Roman numeral character)
+     * <li>  it is a combining mark
+     * <li>  it is a non-spacing mark
+     * <li> {@code isIdentifierIgnorable} returns
+     * {@code true} for the character
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isJavaIdentifierPart(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return {@code true} if the character may be part of a
+     *          Java identifier; {@code false} otherwise.
+     * @see     Character#isIdentifierIgnorable(char)
+     * @see     Character#isJavaIdentifierStart(char)
+     * @see     Character#isLetterOrDigit(char)
+     * @see     Character#isUnicodeIdentifierPart(char)
+     * @since   1.1
+     */
+    public static boolean isJavaIdentifierPart(char ch) {
+        return isJavaIdentifierPart((int)ch);
+    }
+
+    // Android-changed: Removed @see tag (target does not exist on Android):
+    // @see     javax.lang.model.SourceVersion#isIdentifier(CharSequence)
+    /**
+     * Determines if the character (Unicode code point) may be part of a Java
+     * identifier as other than the first character.
+     * <p>
+     * A character may be part of a Java identifier if any of the following
+     * are true:
+     * <ul>
+     * <li>  it is a letter
+     * <li>  it is a currency symbol (such as {@code '$'})
+     * <li>  it is a connecting punctuation character (such as {@code '_'})
+     * <li>  it is a digit
+     * <li>  it is a numeric letter (such as a Roman numeral character)
+     * <li>  it is a combining mark
+     * <li>  it is a non-spacing mark
+     * <li> {@link #isIdentifierIgnorable(int)
+     * isIdentifierIgnorable(codePoint)} returns {@code true} for
+     * the character
+     * </ul>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return {@code true} if the character may be part of a
+     *          Java identifier; {@code false} otherwise.
+     * @see     Character#isIdentifierIgnorable(int)
+     * @see     Character#isJavaIdentifierStart(int)
+     * @see     Character#isLetterOrDigit(int)
+     * @see     Character#isUnicodeIdentifierPart(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Use ICU.
+    /*
+    public static boolean isJavaIdentifierPart(int codePoint) {
+        return CharacterData.of(codePoint).isJavaIdentifierPart(codePoint);
+    }
+    */
+    public static boolean isJavaIdentifierPart(int codePoint) {
+        // Use precomputed bitmasks to optimize the ASCII range.
+        if (codePoint < 64) {
+            return (0x3ff00100fffc1ffL & (1L << codePoint)) != 0;
+        } else if (codePoint < 128) {
+            return (0x87fffffe87fffffeL & (1L << (codePoint - 64))) != 0;
+        }
+        return ((1 << getType(codePoint))
+                & ((1 << UPPERCASE_LETTER)
+                   | (1 << LOWERCASE_LETTER)
+                   | (1 << TITLECASE_LETTER)
+                   | (1 << MODIFIER_LETTER)
+                   | (1 << OTHER_LETTER)
+                   | (1 << CURRENCY_SYMBOL)
+                   | (1 << CONNECTOR_PUNCTUATION)
+                   | (1 << DECIMAL_DIGIT_NUMBER)
+                   | (1 << LETTER_NUMBER)
+                   | (1 << FORMAT)
+                   | (1 << COMBINING_SPACING_MARK)
+                   | (1 << NON_SPACING_MARK))) != 0
+                || (codePoint >= 0 && codePoint <= 8) || (codePoint >= 0xe && codePoint <= 0x1b)
+                || (codePoint >= 0x7f && codePoint <= 0x9f);
+    }
+    // END Android-changed: Use ICU.
+
+    /**
+     * Determines if the specified character is permissible as the
+     * first character in a Unicode identifier.
+     * <p>
+     * A character may start a Unicode identifier if and only if
+     * one of the following conditions is true:
+     * <ul>
+     * <li> {@link #isLetter(char) isLetter(ch)} returns {@code true}
+     * <li> {@link #getType(char) getType(ch)} returns
+     *      {@code LETTER_NUMBER}.
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isUnicodeIdentifierStart(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return  {@code true} if the character may start a Unicode
+     *          identifier; {@code false} otherwise.
+     * @see     Character#isJavaIdentifierStart(char)
+     * @see     Character#isLetter(char)
+     * @see     Character#isUnicodeIdentifierPart(char)
+     * @since   1.1
+     */
+    public static boolean isUnicodeIdentifierStart(char ch) {
+        return isUnicodeIdentifierStart((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is permissible as the
+     * first character in a Unicode identifier.
+     * <p>
+     * A character may start a Unicode identifier if and only if
+     * one of the following conditions is true:
+     * <ul>
+     * <li> {@link #isLetter(int) isLetter(codePoint)}
+     *      returns {@code true}
+     * <li> {@link #getType(int) getType(codePoint)}
+     *      returns {@code LETTER_NUMBER}.
+     * </ul>
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character may start a Unicode
+     *          identifier; {@code false} otherwise.
+     * @see     Character#isJavaIdentifierStart(int)
+     * @see     Character#isLetter(int)
+     * @see     Character#isUnicodeIdentifierPart(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isUnicodeIdentifierStart(int codePoint) {
+        return CharacterData.of(codePoint).isUnicodeIdentifierStart(codePoint);
+    }
+    */
+    public static boolean isUnicodeIdentifierStart(int codePoint) {
+        return isUnicodeIdentifierStartImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isUnicodeIdentifierStartImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character may be part of a Unicode
+     * identifier as other than the first character.
+     * <p>
+     * A character may be part of a Unicode identifier if and only if
+     * one of the following statements is true:
+     * <ul>
+     * <li>  it is a letter
+     * <li>  it is a connecting punctuation character (such as {@code '_'})
+     * <li>  it is a digit
+     * <li>  it is a numeric letter (such as a Roman numeral character)
+     * <li>  it is a combining mark
+     * <li>  it is a non-spacing mark
+     * <li> {@code isIdentifierIgnorable} returns
+     * {@code true} for this character.
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isUnicodeIdentifierPart(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return  {@code true} if the character may be part of a
+     *          Unicode identifier; {@code false} otherwise.
+     * @see     Character#isIdentifierIgnorable(char)
+     * @see     Character#isJavaIdentifierPart(char)
+     * @see     Character#isLetterOrDigit(char)
+     * @see     Character#isUnicodeIdentifierStart(char)
+     * @since   1.1
+     */
+    public static boolean isUnicodeIdentifierPart(char ch) {
+        return isUnicodeIdentifierPart((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) may be part of a Unicode
+     * identifier as other than the first character.
+     * <p>
+     * A character may be part of a Unicode identifier if and only if
+     * one of the following statements is true:
+     * <ul>
+     * <li>  it is a letter
+     * <li>  it is a connecting punctuation character (such as {@code '_'})
+     * <li>  it is a digit
+     * <li>  it is a numeric letter (such as a Roman numeral character)
+     * <li>  it is a combining mark
+     * <li>  it is a non-spacing mark
+     * <li> {@code isIdentifierIgnorable} returns
+     * {@code true} for this character.
+     * </ul>
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character may be part of a
+     *          Unicode identifier; {@code false} otherwise.
+     * @see     Character#isIdentifierIgnorable(int)
+     * @see     Character#isJavaIdentifierPart(int)
+     * @see     Character#isLetterOrDigit(int)
+     * @see     Character#isUnicodeIdentifierStart(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isUnicodeIdentifierPart(int codePoint) {
+        return CharacterData.of(codePoint).isUnicodeIdentifierPart(codePoint);
+    }
+    */
+    public static boolean isUnicodeIdentifierPart(int codePoint) {
+        return isUnicodeIdentifierPartImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isUnicodeIdentifierPartImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character should be regarded as
+     * an ignorable character in a Java identifier or a Unicode identifier.
+     * <p>
+     * The following Unicode characters are ignorable in a Java identifier
+     * or a Unicode identifier:
+     * <ul>
+     * <li>ISO control characters that are not whitespace
+     * <ul>
+     * <li>{@code '\u005Cu0000'} through {@code '\u005Cu0008'}
+     * <li>{@code '\u005Cu000E'} through {@code '\u005Cu001B'}
+     * <li>{@code '\u005Cu007F'} through {@code '\u005Cu009F'}
+     * </ul>
+     *
+     * <li>all characters that have the {@code FORMAT} general
+     * category value
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isIdentifierIgnorable(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return  {@code true} if the character is an ignorable control
+     *          character that may be part of a Java or Unicode identifier;
+     *           {@code false} otherwise.
+     * @see     Character#isJavaIdentifierPart(char)
+     * @see     Character#isUnicodeIdentifierPart(char)
+     * @since   1.1
+     */
+    public static boolean isIdentifierIgnorable(char ch) {
+        return isIdentifierIgnorable((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) should be regarded as
+     * an ignorable character in a Java identifier or a Unicode identifier.
+     * <p>
+     * The following Unicode characters are ignorable in a Java identifier
+     * or a Unicode identifier:
+     * <ul>
+     * <li>ISO control characters that are not whitespace
+     * <ul>
+     * <li>{@code '\u005Cu0000'} through {@code '\u005Cu0008'}
+     * <li>{@code '\u005Cu000E'} through {@code '\u005Cu001B'}
+     * <li>{@code '\u005Cu007F'} through {@code '\u005Cu009F'}
+     * </ul>
+     *
+     * <li>all characters that have the {@code FORMAT} general
+     * category value
+     * </ul>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is an ignorable control
+     *          character that may be part of a Java or Unicode identifier;
+     *          {@code false} otherwise.
+     * @see     Character#isJavaIdentifierPart(int)
+     * @see     Character#isUnicodeIdentifierPart(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isIdentifierIgnorable(int codePoint) {
+        return CharacterData.of(codePoint).isIdentifierIgnorable(codePoint);
+    }
+    */
+    public static boolean isIdentifierIgnorable(int codePoint) {
+        return isIdentifierIgnorableImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isIdentifierIgnorableImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Converts the character argument to lowercase using case
+     * mapping information from the UnicodeData file.
+     * <p>
+     * Note that
+     * {@code Character.isLowerCase(Character.toLowerCase(ch))}
+     * does not always return {@code true} for some ranges of
+     * characters, particularly those that are symbols or ideographs.
+     *
+     * <p>In general, {@link String#toLowerCase()} should be used to map
+     * characters to lowercase. {@code String} case mapping methods
+     * have several benefits over {@code Character} case mapping methods.
+     * {@code String} case mapping methods can perform locale-sensitive
+     * mappings, context-sensitive mappings, and 1:M character mappings, whereas
+     * the {@code Character} case mapping methods cannot.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #toLowerCase(int)} method.
+     *
+     * @param   ch   the character to be converted.
+     * @return  the lowercase equivalent of the character, if any;
+     *          otherwise, the character itself.
+     * @see     Character#isLowerCase(char)
+     * @see     String#toLowerCase()
+     */
+    public static char toLowerCase(char ch) {
+        return (char)toLowerCase((int)ch);
+    }
+
+    /**
+     * Converts the character (Unicode code point) argument to
+     * lowercase using case mapping information from the UnicodeData
+     * file.
+     *
+     * <p> Note that
+     * {@code Character.isLowerCase(Character.toLowerCase(codePoint))}
+     * does not always return {@code true} for some ranges of
+     * characters, particularly those that are symbols or ideographs.
+     *
+     * <p>In general, {@link String#toLowerCase()} should be used to map
+     * characters to lowercase. {@code String} case mapping methods
+     * have several benefits over {@code Character} case mapping methods.
+     * {@code String} case mapping methods can perform locale-sensitive
+     * mappings, context-sensitive mappings, and 1:M character mappings, whereas
+     * the {@code Character} case mapping methods cannot.
+     *
+     * @param   codePoint   the character (Unicode code point) to be converted.
+     * @return  the lowercase equivalent of the character (Unicode code
+     *          point), if any; otherwise, the character itself.
+     * @see     Character#isLowerCase(int)
+     * @see     String#toLowerCase()
+     *
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static int toLowerCase(int codePoint) {
+        return CharacterData.of(codePoint).toLowerCase(codePoint);
+    }
+    */
+    public static int toLowerCase(int codePoint) {
+        if (codePoint >= 'A' && codePoint <= 'Z') {
+            return codePoint + ('a' - 'A');
+        }
+
+        // All ASCII codepoints except the ones above remain unchanged.
+        if (codePoint < 0x80) {
+            return codePoint;
+        }
+
+        return toLowerCaseImpl(codePoint);
+    }
+
+    @FastNative
+    static native int toLowerCaseImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Converts the character argument to uppercase using case mapping
+     * information from the UnicodeData file.
+     * <p>
+     * Note that
+     * {@code Character.isUpperCase(Character.toUpperCase(ch))}
+     * does not always return {@code true} for some ranges of
+     * characters, particularly those that are symbols or ideographs.
+     *
+     * <p>In general, {@link String#toUpperCase()} should be used to map
+     * characters to uppercase. {@code String} case mapping methods
+     * have several benefits over {@code Character} case mapping methods.
+     * {@code String} case mapping methods can perform locale-sensitive
+     * mappings, context-sensitive mappings, and 1:M character mappings, whereas
+     * the {@code Character} case mapping methods cannot.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #toUpperCase(int)} method.
+     *
+     * @param   ch   the character to be converted.
+     * @return  the uppercase equivalent of the character, if any;
+     *          otherwise, the character itself.
+     * @see     Character#isUpperCase(char)
+     * @see     String#toUpperCase()
+     */
+    public static char toUpperCase(char ch) {
+        return (char)toUpperCase((int)ch);
+    }
+
+    /**
+     * Converts the character (Unicode code point) argument to
+     * uppercase using case mapping information from the UnicodeData
+     * file.
+     *
+     * <p>Note that
+     * {@code Character.isUpperCase(Character.toUpperCase(codePoint))}
+     * does not always return {@code true} for some ranges of
+     * characters, particularly those that are symbols or ideographs.
+     *
+     * <p>In general, {@link String#toUpperCase()} should be used to map
+     * characters to uppercase. {@code String} case mapping methods
+     * have several benefits over {@code Character} case mapping methods.
+     * {@code String} case mapping methods can perform locale-sensitive
+     * mappings, context-sensitive mappings, and 1:M character mappings, whereas
+     * the {@code Character} case mapping methods cannot.
+     *
+     * @param   codePoint   the character (Unicode code point) to be converted.
+     * @return  the uppercase equivalent of the character, if any;
+     *          otherwise, the character itself.
+     * @see     Character#isUpperCase(int)
+     * @see     String#toUpperCase()
+     *
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static int toUpperCase(int codePoint) {
+        return CharacterData.of(codePoint).toUpperCase(codePoint);
+    }
+    */
+    public static int toUpperCase(int codePoint) {
+        if (codePoint >= 'a' && codePoint <= 'z') {
+            return codePoint - ('a' - 'A');
+        }
+
+        // All ASCII codepoints except the ones above remain unchanged.
+        if (codePoint < 0x80) {
+            return codePoint;
+        }
+
+        return toUpperCaseImpl(codePoint);
+    }
+
+    @FastNative
+    static native int toUpperCaseImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Converts the character argument to titlecase using case mapping
+     * information from the UnicodeData file. If a character has no
+     * explicit titlecase mapping and is not itself a titlecase char
+     * according to UnicodeData, then the uppercase mapping is
+     * returned as an equivalent titlecase mapping. If the
+     * {@code char} argument is already a titlecase
+     * {@code char}, the same {@code char} value will be
+     * returned.
+     * <p>
+     * Note that
+     * {@code Character.isTitleCase(Character.toTitleCase(ch))}
+     * does not always return {@code true} for some ranges of
+     * characters.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #toTitleCase(int)} method.
+     *
+     * @param   ch   the character to be converted.
+     * @return  the titlecase equivalent of the character, if any;
+     *          otherwise, the character itself.
+     * @see     Character#isTitleCase(char)
+     * @see     Character#toLowerCase(char)
+     * @see     Character#toUpperCase(char)
+     * @since   1.0.2
+     */
+    public static char toTitleCase(char ch) {
+        return (char)toTitleCase((int)ch);
+    }
+
+    /**
+     * Converts the character (Unicode code point) argument to titlecase using case mapping
+     * information from the UnicodeData file. If a character has no
+     * explicit titlecase mapping and is not itself a titlecase char
+     * according to UnicodeData, then the uppercase mapping is
+     * returned as an equivalent titlecase mapping. If the
+     * character argument is already a titlecase
+     * character, the same character value will be
+     * returned.
+     *
+     * <p>Note that
+     * {@code Character.isTitleCase(Character.toTitleCase(codePoint))}
+     * does not always return {@code true} for some ranges of
+     * characters.
+     *
+     * @param   codePoint   the character (Unicode code point) to be converted.
+     * @return  the titlecase equivalent of the character, if any;
+     *          otherwise, the character itself.
+     * @see     Character#isTitleCase(int)
+     * @see     Character#toLowerCase(int)
+     * @see     Character#toUpperCase(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static int toTitleCase(int codePoint) {
+        return CharacterData.of(codePoint).toTitleCase(codePoint);
+    }
+    */
+    public static int toTitleCase(int codePoint) {
+        return toTitleCaseImpl(codePoint);
+    }
+
+    @FastNative
+    static native int toTitleCaseImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Returns the numeric value of the character {@code ch} in the
+     * specified radix.
+     * <p>
+     * If the radix is not in the range {@code MIN_RADIX} &le;
+     * {@code radix} &le; {@code MAX_RADIX} or if the
+     * value of {@code ch} is not a valid digit in the specified
+     * radix, {@code -1} is returned. A character is a valid digit
+     * if at least one of the following is true:
+     * <ul>
+     * <li>The method {@code isDigit} is {@code true} of the character
+     *     and the Unicode decimal digit value of the character (or its
+     *     single-character decomposition) is less than the specified radix.
+     *     In this case the decimal digit value is returned.
+     * <li>The character is one of the uppercase Latin letters
+     *     {@code 'A'} through {@code 'Z'} and its code is less than
+     *     {@code radix + 'A' - 10}.
+     *     In this case, {@code ch - 'A' + 10}
+     *     is returned.
+     * <li>The character is one of the lowercase Latin letters
+     *     {@code 'a'} through {@code 'z'} and its code is less than
+     *     {@code radix + 'a' - 10}.
+     *     In this case, {@code ch - 'a' + 10}
+     *     is returned.
+     * <li>The character is one of the fullwidth uppercase Latin letters A
+     *     ({@code '\u005CuFF21'}) through Z ({@code '\u005CuFF3A'})
+     *     and its code is less than
+     *     {@code radix + '\u005CuFF21' - 10}.
+     *     In this case, {@code ch - '\u005CuFF21' + 10}
+     *     is returned.
+     * <li>The character is one of the fullwidth lowercase Latin letters a
+     *     ({@code '\u005CuFF41'}) through z ({@code '\u005CuFF5A'})
+     *     and its code is less than
+     *     {@code radix + '\u005CuFF41' - 10}.
+     *     In this case, {@code ch - '\u005CuFF41' + 10}
+     *     is returned.
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #digit(int, int)} method.
+     *
+     * @param   ch      the character to be converted.
+     * @param   radix   the radix.
+     * @return  the numeric value represented by the character in the
+     *          specified radix.
+     * @see     Character#forDigit(int, int)
+     * @see     Character#isDigit(char)
+     */
+    public static int digit(char ch, int radix) {
+        return digit((int)ch, radix);
+    }
+
+    /**
+     * Returns the numeric value of the specified character (Unicode
+     * code point) in the specified radix.
+     *
+     * <p>If the radix is not in the range {@code MIN_RADIX} &le;
+     * {@code radix} &le; {@code MAX_RADIX} or if the
+     * character is not a valid digit in the specified
+     * radix, {@code -1} is returned. A character is a valid digit
+     * if at least one of the following is true:
+     * <ul>
+     * <li>The method {@link #isDigit(int) isDigit(codePoint)} is {@code true} of the character
+     *     and the Unicode decimal digit value of the character (or its
+     *     single-character decomposition) is less than the specified radix.
+     *     In this case the decimal digit value is returned.
+     * <li>The character is one of the uppercase Latin letters
+     *     {@code 'A'} through {@code 'Z'} and its code is less than
+     *     {@code radix + 'A' - 10}.
+     *     In this case, {@code codePoint - 'A' + 10}
+     *     is returned.
+     * <li>The character is one of the lowercase Latin letters
+     *     {@code 'a'} through {@code 'z'} and its code is less than
+     *     {@code radix + 'a' - 10}.
+     *     In this case, {@code codePoint - 'a' + 10}
+     *     is returned.
+     * <li>The character is one of the fullwidth uppercase Latin letters A
+     *     ({@code '\u005CuFF21'}) through Z ({@code '\u005CuFF3A'})
+     *     and its code is less than
+     *     {@code radix + '\u005CuFF21' - 10}.
+     *     In this case,
+     *     {@code codePoint - '\u005CuFF21' + 10}
+     *     is returned.
+     * <li>The character is one of the fullwidth lowercase Latin letters a
+     *     ({@code '\u005CuFF41'}) through z ({@code '\u005CuFF5A'})
+     *     and its code is less than
+     *     {@code radix + '\u005CuFF41'- 10}.
+     *     In this case,
+     *     {@code codePoint - '\u005CuFF41' + 10}
+     *     is returned.
+     * </ul>
+     *
+     * @param   codePoint the character (Unicode code point) to be converted.
+     * @param   radix   the radix.
+     * @return  the numeric value represented by the character in the
+     *          specified radix.
+     * @see     Character#forDigit(int, int)
+     * @see     Character#isDigit(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static int digit(int codePoint, int radix) {
+        return CharacterData.of(codePoint).digit(codePoint, radix);
+    }
+    */
+    public static int digit(int codePoint, int radix) {
+        if (radix < MIN_RADIX || radix > MAX_RADIX) {
+            return -1;
+        }
+        if (codePoint < 128) {
+            // Optimized for ASCII
+            int result = -1;
+            if ('0' <= codePoint && codePoint <= '9') {
+                result = codePoint - '0';
+            } else if ('a' <= codePoint && codePoint <= 'z') {
+                result = 10 + (codePoint - 'a');
+            } else if ('A' <= codePoint && codePoint <= 'Z') {
+                result = 10 + (codePoint - 'A');
+            }
+            return result < radix ? result : -1;
+        }
+        return digitImpl(codePoint, radix);
+    }
+
+    @FastNative
+    native static int digitImpl(int codePoint, int radix);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Returns the {@code int} value that the specified Unicode
+     * character represents. For example, the character
+     * {@code '\u005Cu216C'} (the roman numeral fifty) will return
+     * an int with a value of 50.
+     * <p>
+     * The letters A-Z in their uppercase ({@code '\u005Cu0041'} through
+     * {@code '\u005Cu005A'}), lowercase
+     * ({@code '\u005Cu0061'} through {@code '\u005Cu007A'}), and
+     * full width variant ({@code '\u005CuFF21'} through
+     * {@code '\u005CuFF3A'} and {@code '\u005CuFF41'} through
+     * {@code '\u005CuFF5A'}) forms have numeric values from 10
+     * through 35. This is independent of the Unicode specification,
+     * which does not assign numeric values to these {@code char}
+     * values.
+     * <p>
+     * If the character does not have a numeric value, then -1 is returned.
+     * If the character has a numeric value that cannot be represented as a
+     * nonnegative integer (for example, a fractional value), then -2
+     * is returned.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #getNumericValue(int)} method.
+     *
+     * @param   ch      the character to be converted.
+     * @return  the numeric value of the character, as a nonnegative {@code int}
+     *           value; -2 if the character has a numeric value that is not a
+     *          nonnegative integer; -1 if the character has no numeric value.
+     * @see     Character#forDigit(int, int)
+     * @see     Character#isDigit(char)
+     * @since   1.1
+     */
+    public static int getNumericValue(char ch) {
+        return getNumericValue((int)ch);
+    }
+
+    /**
+     * Returns the {@code int} value that the specified
+     * character (Unicode code point) represents. For example, the character
+     * {@code '\u005Cu216C'} (the Roman numeral fifty) will return
+     * an {@code int} with a value of 50.
+     * <p>
+     * The letters A-Z in their uppercase ({@code '\u005Cu0041'} through
+     * {@code '\u005Cu005A'}), lowercase
+     * ({@code '\u005Cu0061'} through {@code '\u005Cu007A'}), and
+     * full width variant ({@code '\u005CuFF21'} through
+     * {@code '\u005CuFF3A'} and {@code '\u005CuFF41'} through
+     * {@code '\u005CuFF5A'}) forms have numeric values from 10
+     * through 35. This is independent of the Unicode specification,
+     * which does not assign numeric values to these {@code char}
+     * values.
+     * <p>
+     * If the character does not have a numeric value, then -1 is returned.
+     * If the character has a numeric value that cannot be represented as a
+     * nonnegative integer (for example, a fractional value), then -2
+     * is returned.
+     *
+     * @param   codePoint the character (Unicode code point) to be converted.
+     * @return  the numeric value of the character, as a nonnegative {@code int}
+     *          value; -2 if the character has a numeric value that is not a
+     *          nonnegative integer; -1 if the character has no numeric value.
+     * @see     Character#forDigit(int, int)
+     * @see     Character#isDigit(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static int getNumericValue(int codePoint) {
+        return CharacterData.of(codePoint).getNumericValue(codePoint);
+    }
+    */
+    public static int getNumericValue(int codePoint) {
+        // This is both an optimization and papers over differences between Java and ICU.
+        if (codePoint < 128) {
+            if (codePoint >= '0' && codePoint <= '9') {
+                return codePoint - '0';
+            }
+            if (codePoint >= 'a' && codePoint <= 'z') {
+                return codePoint - ('a' - 10);
+            }
+            if (codePoint >= 'A' && codePoint <= 'Z') {
+                return codePoint - ('A' - 10);
+            }
+            return -1;
+        }
+        // Full-width uppercase A-Z.
+        if (codePoint >= 0xff21 && codePoint <= 0xff3a) {
+            return codePoint - 0xff17;
+        }
+        // Full-width lowercase a-z.
+        if (codePoint >= 0xff41 && codePoint <= 0xff5a) {
+            return codePoint - 0xff37;
+        }
+        return getNumericValueImpl(codePoint);
+    }
+
+    @FastNative
+    native static int getNumericValueImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is ISO-LATIN-1 white space.
+     * This method returns {@code true} for the following five
+     * characters only:
+     * <table summary="truechars">
+     * <tr><td>{@code '\t'}</td>            <td>{@code U+0009}</td>
+     *     <td>{@code HORIZONTAL TABULATION}</td></tr>
+     * <tr><td>{@code '\n'}</td>            <td>{@code U+000A}</td>
+     *     <td>{@code NEW LINE}</td></tr>
+     * <tr><td>{@code '\f'}</td>            <td>{@code U+000C}</td>
+     *     <td>{@code FORM FEED}</td></tr>
+     * <tr><td>{@code '\r'}</td>            <td>{@code U+000D}</td>
+     *     <td>{@code CARRIAGE RETURN}</td></tr>
+     * <tr><td>{@code ' '}</td>             <td>{@code U+0020}</td>
+     *     <td>{@code SPACE}</td></tr>
+     * </table>
+     *
+     * @param      ch   the character to be tested.
+     * @return     {@code true} if the character is ISO-LATIN-1 white
+     *             space; {@code false} otherwise.
+     * @see        Character#isSpaceChar(char)
+     * @see        Character#isWhitespace(char)
+     * @deprecated Replaced by isWhitespace(char).
+     */
+    @Deprecated
+    public static boolean isSpace(char ch) {
+        return (ch <= 0x0020) &&
+            (((((1L << 0x0009) |
+            (1L << 0x000A) |
+            (1L << 0x000C) |
+            (1L << 0x000D) |
+            (1L << 0x0020)) >> ch) & 1L) != 0);
+    }
+
+
+    /**
+     * Determines if the specified character is a Unicode space character.
+     * A character is considered to be a space character if and only if
+     * it is specified to be a space character by the Unicode Standard. This
+     * method returns true if the character's general category type is any of
+     * the following:
+     * <ul>
+     * <li> {@code SPACE_SEPARATOR}
+     * <li> {@code LINE_SEPARATOR}
+     * <li> {@code PARAGRAPH_SEPARATOR}
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isSpaceChar(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return  {@code true} if the character is a space character;
+     *          {@code false} otherwise.
+     * @see     Character#isWhitespace(char)
+     * @since   1.1
+     */
+    public static boolean isSpaceChar(char ch) {
+        return isSpaceChar((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is a
+     * Unicode space character.  A character is considered to be a
+     * space character if and only if it is specified to be a space
+     * character by the Unicode Standard. This method returns true if
+     * the character's general category type is any of the following:
+     *
+     * <ul>
+     * <li> {@link #SPACE_SEPARATOR}
+     * <li> {@link #LINE_SEPARATOR}
+     * <li> {@link #PARAGRAPH_SEPARATOR}
+     * </ul>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is a space character;
+     *          {@code false} otherwise.
+     * @see     Character#isWhitespace(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isSpaceChar(int codePoint) {
+        return ((((1 << Character.SPACE_SEPARATOR) |
+                  (1 << Character.LINE_SEPARATOR) |
+                  (1 << Character.PARAGRAPH_SEPARATOR)) >> getType(codePoint)) & 1)
+            != 0;
+    }
+    */
+    public static boolean isSpaceChar(int codePoint) {
+        // We don't just call into icu4c because of the JNI overhead. Ideally we'd fix that.
+        // SPACE or NO-BREAK SPACE?
+        if (codePoint == 0x20 || codePoint == 0xa0) {
+            return true;
+        }
+        if (codePoint < 0x1000) {
+            return false;
+        }
+        // OGHAM SPACE MARK or MONGOLIAN VOWEL SEPARATOR?
+        if (codePoint == 0x1680 || codePoint == 0x180e) {
+            return true;
+        }
+        if (codePoint < 0x2000) {
+            return false;
+        }
+        if (codePoint <= 0xffff) {
+            // Other whitespace from General Punctuation...
+            return codePoint <= 0x200a || codePoint == 0x2028 || codePoint == 0x2029 || codePoint == 0x202f || codePoint == 0x205f ||
+                codePoint == 0x3000; // ...or CJK Symbols and Punctuation?
+        }
+        // Let icu4c worry about non-BMP code points.
+        return isSpaceCharImpl(codePoint);
+    }
+
+    @FastNative
+    static native boolean isSpaceCharImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is white space according to Java.
+     * A character is a Java whitespace character if and only if it satisfies
+     * one of the following criteria:
+     * <ul>
+     * <li> It is a Unicode space character ({@code SPACE_SEPARATOR},
+     *      {@code LINE_SEPARATOR}, or {@code PARAGRAPH_SEPARATOR})
+     *      but is not also a non-breaking space ({@code '\u005Cu00A0'},
+     *      {@code '\u005Cu2007'}, {@code '\u005Cu202F'}).
+     * <li> It is {@code '\u005Ct'}, U+0009 HORIZONTAL TABULATION.
+     * <li> It is {@code '\u005Cn'}, U+000A LINE FEED.
+     * <li> It is {@code '\u005Cu000B'}, U+000B VERTICAL TABULATION.
+     * <li> It is {@code '\u005Cf'}, U+000C FORM FEED.
+     * <li> It is {@code '\u005Cr'}, U+000D CARRIAGE RETURN.
+     * <li> It is {@code '\u005Cu001C'}, U+001C FILE SEPARATOR.
+     * <li> It is {@code '\u005Cu001D'}, U+001D GROUP SEPARATOR.
+     * <li> It is {@code '\u005Cu001E'}, U+001E RECORD SEPARATOR.
+     * <li> It is {@code '\u005Cu001F'}, U+001F UNIT SEPARATOR.
+     * </ul>
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isWhitespace(int)} method.
+     *
+     * @param   ch the character to be tested.
+     * @return  {@code true} if the character is a Java whitespace
+     *          character; {@code false} otherwise.
+     * @see     Character#isSpaceChar(char)
+     * @since   1.1
+     */
+    public static boolean isWhitespace(char ch) {
+        return isWhitespace((int)ch);
+    }
+
+    /**
+     * Determines if the specified character (Unicode code point) is
+     * white space according to Java.  A character is a Java
+     * whitespace character if and only if it satisfies one of the
+     * following criteria:
+     * <ul>
+     * <li> It is a Unicode space character ({@link #SPACE_SEPARATOR},
+     *      {@link #LINE_SEPARATOR}, or {@link #PARAGRAPH_SEPARATOR})
+     *      but is not also a non-breaking space ({@code '\u005Cu00A0'},
+     *      {@code '\u005Cu2007'}, {@code '\u005Cu202F'}).
+     * <li> It is {@code '\u005Ct'}, U+0009 HORIZONTAL TABULATION.
+     * <li> It is {@code '\u005Cn'}, U+000A LINE FEED.
+     * <li> It is {@code '\u005Cu000B'}, U+000B VERTICAL TABULATION.
+     * <li> It is {@code '\u005Cf'}, U+000C FORM FEED.
+     * <li> It is {@code '\u005Cr'}, U+000D CARRIAGE RETURN.
+     * <li> It is {@code '\u005Cu001C'}, U+001C FILE SEPARATOR.
+     * <li> It is {@code '\u005Cu001D'}, U+001D GROUP SEPARATOR.
+     * <li> It is {@code '\u005Cu001E'}, U+001E RECORD SEPARATOR.
+     * <li> It is {@code '\u005Cu001F'}, U+001F UNIT SEPARATOR.
+     * </ul>
+     * <p>
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is a Java whitespace
+     *          character; {@code false} otherwise.
+     * @see     Character#isSpaceChar(int)
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isWhitespace(int codePoint) {
+        return CharacterData.of(codePoint).isWhitespace(codePoint);
+    }
+    */
+    public static boolean isWhitespace(int codePoint) {
+        // We don't just call into icu4c because of the JNI overhead. Ideally we'd fix that.
+        // Any ASCII whitespace character?
+        if ((codePoint >= 0x1c && codePoint <= 0x20) || (codePoint >= 0x09 && codePoint <= 0x0d)) {
+            return true;
+        }
+        if (codePoint < 0x1000) {
+            return false;
+        }
+        // OGHAM SPACE MARK or MONGOLIAN VOWEL SEPARATOR?
+        if (codePoint == 0x1680 || codePoint == 0x180e) {
+            return true;
+        }
+        if (codePoint < 0x2000) {
+            return false;
+        }
+        // Exclude General Punctuation's non-breaking spaces (which includes FIGURE SPACE).
+        if (codePoint == 0x2007 || codePoint == 0x202f) {
+            return false;
+        }
+        if (codePoint <= 0xffff) {
+            // Other whitespace from General Punctuation...
+            return codePoint <= 0x200a || codePoint == 0x2028 || codePoint == 0x2029 || codePoint == 0x205f ||
+                codePoint == 0x3000; // ...or CJK Symbols and Punctuation?
+        }
+        // Let icu4c worry about non-BMP code points.
+        return isWhitespaceImpl(codePoint);
+    }
+
+    @FastNative
+    native static boolean isWhitespaceImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines if the specified character is an ISO control
+     * character.  A character is considered to be an ISO control
+     * character if its code is in the range {@code '\u005Cu0000'}
+     * through {@code '\u005Cu001F'} or in the range
+     * {@code '\u005Cu007F'} through {@code '\u005Cu009F'}.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isISOControl(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return  {@code true} if the character is an ISO control character;
+     *          {@code false} otherwise.
+     *
+     * @see     Character#isSpaceChar(char)
+     * @see     Character#isWhitespace(char)
+     * @since   1.1
+     */
+    public static boolean isISOControl(char ch) {
+        return isISOControl((int)ch);
+    }
+
+    /**
+     * Determines if the referenced character (Unicode code point) is an ISO control
+     * character.  A character is considered to be an ISO control
+     * character if its code is in the range {@code '\u005Cu0000'}
+     * through {@code '\u005Cu001F'} or in the range
+     * {@code '\u005Cu007F'} through {@code '\u005Cu009F'}.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is an ISO control character;
+     *          {@code false} otherwise.
+     * @see     Character#isSpaceChar(int)
+     * @see     Character#isWhitespace(int)
+     * @since   1.5
+     */
+    public static boolean isISOControl(int codePoint) {
+        // Optimized form of:
+        //     (codePoint >= 0x00 && codePoint <= 0x1F) ||
+        //     (codePoint >= 0x7F && codePoint <= 0x9F);
+        return codePoint <= 0x9F &&
+            (codePoint >= 0x7F || (codePoint >>> 5 == 0));
+    }
+
+    /**
+     * Returns a value indicating a character's general category.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #getType(int)} method.
+     *
+     * @param   ch      the character to be tested.
+     * @return  a value of type {@code int} representing the
+     *          character's general category.
+     * @see     Character#COMBINING_SPACING_MARK
+     * @see     Character#CONNECTOR_PUNCTUATION
+     * @see     Character#CONTROL
+     * @see     Character#CURRENCY_SYMBOL
+     * @see     Character#DASH_PUNCTUATION
+     * @see     Character#DECIMAL_DIGIT_NUMBER
+     * @see     Character#ENCLOSING_MARK
+     * @see     Character#END_PUNCTUATION
+     * @see     Character#FINAL_QUOTE_PUNCTUATION
+     * @see     Character#FORMAT
+     * @see     Character#INITIAL_QUOTE_PUNCTUATION
+     * @see     Character#LETTER_NUMBER
+     * @see     Character#LINE_SEPARATOR
+     * @see     Character#LOWERCASE_LETTER
+     * @see     Character#MATH_SYMBOL
+     * @see     Character#MODIFIER_LETTER
+     * @see     Character#MODIFIER_SYMBOL
+     * @see     Character#NON_SPACING_MARK
+     * @see     Character#OTHER_LETTER
+     * @see     Character#OTHER_NUMBER
+     * @see     Character#OTHER_PUNCTUATION
+     * @see     Character#OTHER_SYMBOL
+     * @see     Character#PARAGRAPH_SEPARATOR
+     * @see     Character#PRIVATE_USE
+     * @see     Character#SPACE_SEPARATOR
+     * @see     Character#START_PUNCTUATION
+     * @see     Character#SURROGATE
+     * @see     Character#TITLECASE_LETTER
+     * @see     Character#UNASSIGNED
+     * @see     Character#UPPERCASE_LETTER
+     * @since   1.1
+     */
+    public static int getType(char ch) {
+        return getType((int)ch);
+    }
+
+    /**
+     * Returns a value indicating a character's general category.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  a value of type {@code int} representing the
+     *          character's general category.
+     * @see     Character#COMBINING_SPACING_MARK COMBINING_SPACING_MARK
+     * @see     Character#CONNECTOR_PUNCTUATION CONNECTOR_PUNCTUATION
+     * @see     Character#CONTROL CONTROL
+     * @see     Character#CURRENCY_SYMBOL CURRENCY_SYMBOL
+     * @see     Character#DASH_PUNCTUATION DASH_PUNCTUATION
+     * @see     Character#DECIMAL_DIGIT_NUMBER DECIMAL_DIGIT_NUMBER
+     * @see     Character#ENCLOSING_MARK ENCLOSING_MARK
+     * @see     Character#END_PUNCTUATION END_PUNCTUATION
+     * @see     Character#FINAL_QUOTE_PUNCTUATION FINAL_QUOTE_PUNCTUATION
+     * @see     Character#FORMAT FORMAT
+     * @see     Character#INITIAL_QUOTE_PUNCTUATION INITIAL_QUOTE_PUNCTUATION
+     * @see     Character#LETTER_NUMBER LETTER_NUMBER
+     * @see     Character#LINE_SEPARATOR LINE_SEPARATOR
+     * @see     Character#LOWERCASE_LETTER LOWERCASE_LETTER
+     * @see     Character#MATH_SYMBOL MATH_SYMBOL
+     * @see     Character#MODIFIER_LETTER MODIFIER_LETTER
+     * @see     Character#MODIFIER_SYMBOL MODIFIER_SYMBOL
+     * @see     Character#NON_SPACING_MARK NON_SPACING_MARK
+     * @see     Character#OTHER_LETTER OTHER_LETTER
+     * @see     Character#OTHER_NUMBER OTHER_NUMBER
+     * @see     Character#OTHER_PUNCTUATION OTHER_PUNCTUATION
+     * @see     Character#OTHER_SYMBOL OTHER_SYMBOL
+     * @see     Character#PARAGRAPH_SEPARATOR PARAGRAPH_SEPARATOR
+     * @see     Character#PRIVATE_USE PRIVATE_USE
+     * @see     Character#SPACE_SEPARATOR SPACE_SEPARATOR
+     * @see     Character#START_PUNCTUATION START_PUNCTUATION
+     * @see     Character#SURROGATE SURROGATE
+     * @see     Character#TITLECASE_LETTER TITLECASE_LETTER
+     * @see     Character#UNASSIGNED UNASSIGNED
+     * @see     Character#UPPERCASE_LETTER UPPERCASE_LETTER
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static int getType(int codePoint) {
+        return CharacterData.of(codePoint).getType(codePoint);
+    }
+    */
+    public static int getType(int codePoint) {
+        int type = getTypeImpl(codePoint);
+        // The type values returned by ICU are not RI-compatible. The RI skips the value 17.
+        if (type <= Character.FORMAT) {
+            return type;
+        }
+        return (type + 1);
+    }
+
+    @FastNative
+    static native int getTypeImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines the character representation for a specific digit in
+     * the specified radix. If the value of {@code radix} is not a
+     * valid radix, or the value of {@code digit} is not a valid
+     * digit in the specified radix, the null character
+     * ({@code '\u005Cu0000'}) is returned.
+     * <p>
+     * The {@code radix} argument is valid if it is greater than or
+     * equal to {@code MIN_RADIX} and less than or equal to
+     * {@code MAX_RADIX}. The {@code digit} argument is valid if
+     * {@code 0 <= digit < radix}.
+     * <p>
+     * If the digit is less than 10, then
+     * {@code '0' + digit} is returned. Otherwise, the value
+     * {@code 'a' + digit - 10} is returned.
+     *
+     * @param   digit   the number to convert to a character.
+     * @param   radix   the radix.
+     * @return  the {@code char} representation of the specified digit
+     *          in the specified radix.
+     * @see     Character#MIN_RADIX
+     * @see     Character#MAX_RADIX
+     * @see     Character#digit(char, int)
+     */
+    public static char forDigit(int digit, int radix) {
+        if ((digit >= radix) || (digit < 0)) {
+            return '\0';
+        }
+        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX)) {
+            return '\0';
+        }
+        if (digit < 10) {
+            return (char)('0' + digit);
+        }
+        return (char)('a' - 10 + digit);
+    }
+
+    /**
+     * Returns the Unicode directionality property for the given
+     * character.  Character directionality is used to calculate the
+     * visual ordering of text. The directionality value of undefined
+     * {@code char} values is {@code DIRECTIONALITY_UNDEFINED}.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #getDirectionality(int)} method.
+     *
+     * @param  ch {@code char} for which the directionality property
+     *            is requested.
+     * @return the directionality property of the {@code char} value.
+     *
+     * @see Character#DIRECTIONALITY_UNDEFINED
+     * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC
+     * @see Character#DIRECTIONALITY_EUROPEAN_NUMBER
+     * @see Character#DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR
+     * @see Character#DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR
+     * @see Character#DIRECTIONALITY_ARABIC_NUMBER
+     * @see Character#DIRECTIONALITY_COMMON_NUMBER_SEPARATOR
+     * @see Character#DIRECTIONALITY_NONSPACING_MARK
+     * @see Character#DIRECTIONALITY_BOUNDARY_NEUTRAL
+     * @see Character#DIRECTIONALITY_PARAGRAPH_SEPARATOR
+     * @see Character#DIRECTIONALITY_SEGMENT_SEPARATOR
+     * @see Character#DIRECTIONALITY_WHITESPACE
+     * @see Character#DIRECTIONALITY_OTHER_NEUTRALS
+     * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING
+     * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE
+     * @see Character#DIRECTIONALITY_POP_DIRECTIONAL_FORMAT
+     * @since 1.4
+     */
+    public static byte getDirectionality(char ch) {
+        return getDirectionality((int)ch);
+    }
+
+    /**
+     * Returns the Unicode directionality property for the given
+     * character (Unicode code point).  Character directionality is
+     * used to calculate the visual ordering of text. The
+     * directionality value of undefined character is {@link
+     * #DIRECTIONALITY_UNDEFINED}.
+     *
+     * @param   codePoint the character (Unicode code point) for which
+     *          the directionality property is requested.
+     * @return the directionality property of the character.
+     *
+     * @see Character#DIRECTIONALITY_UNDEFINED DIRECTIONALITY_UNDEFINED
+     * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT DIRECTIONALITY_LEFT_TO_RIGHT
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT DIRECTIONALITY_RIGHT_TO_LEFT
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC
+     * @see Character#DIRECTIONALITY_EUROPEAN_NUMBER DIRECTIONALITY_EUROPEAN_NUMBER
+     * @see Character#DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR
+     * @see Character#DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR
+     * @see Character#DIRECTIONALITY_ARABIC_NUMBER DIRECTIONALITY_ARABIC_NUMBER
+     * @see Character#DIRECTIONALITY_COMMON_NUMBER_SEPARATOR DIRECTIONALITY_COMMON_NUMBER_SEPARATOR
+     * @see Character#DIRECTIONALITY_NONSPACING_MARK DIRECTIONALITY_NONSPACING_MARK
+     * @see Character#DIRECTIONALITY_BOUNDARY_NEUTRAL DIRECTIONALITY_BOUNDARY_NEUTRAL
+     * @see Character#DIRECTIONALITY_PARAGRAPH_SEPARATOR DIRECTIONALITY_PARAGRAPH_SEPARATOR
+     * @see Character#DIRECTIONALITY_SEGMENT_SEPARATOR DIRECTIONALITY_SEGMENT_SEPARATOR
+     * @see Character#DIRECTIONALITY_WHITESPACE DIRECTIONALITY_WHITESPACE
+     * @see Character#DIRECTIONALITY_OTHER_NEUTRALS DIRECTIONALITY_OTHER_NEUTRALS
+     * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING
+     * @see Character#DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING
+     * @see Character#DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE
+     * @see Character#DIRECTIONALITY_POP_DIRECTIONAL_FORMAT DIRECTIONALITY_POP_DIRECTIONAL_FORMAT
+     * @since    1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static byte getDirectionality(int codePoint) {
+        return CharacterData.of(codePoint).getDirectionality(codePoint);
+    }
+    */
+    public static byte getDirectionality(int codePoint) {
+        if (getType(codePoint) == Character.UNASSIGNED) {
+            return Character.DIRECTIONALITY_UNDEFINED;
+        }
+
+        byte directionality = getDirectionalityImpl(codePoint);
+        if (directionality >= 0 && directionality < DIRECTIONALITY.length) {
+            return DIRECTIONALITY[directionality];
+        }
+        return Character.DIRECTIONALITY_UNDEFINED;
+    }
+
+    @FastNative
+    native static byte getDirectionalityImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Determines whether the character is mirrored according to the
+     * Unicode specification.  Mirrored characters should have their
+     * glyphs horizontally mirrored when displayed in text that is
+     * right-to-left.  For example, {@code '\u005Cu0028'} LEFT
+     * PARENTHESIS is semantically defined to be an <i>opening
+     * parenthesis</i>.  This will appear as a "(" in text that is
+     * left-to-right but as a ")" in text that is right-to-left.
+     *
+     * <p><b>Note:</b> This method cannot handle <a
+     * href="#supplementary"> supplementary characters</a>. To support
+     * all Unicode characters, including supplementary characters, use
+     * the {@link #isMirrored(int)} method.
+     *
+     * @param  ch {@code char} for which the mirrored property is requested
+     * @return {@code true} if the char is mirrored, {@code false}
+     *         if the {@code char} is not mirrored or is not defined.
+     * @since 1.4
+     */
+    public static boolean isMirrored(char ch) {
+        return isMirrored((int)ch);
+    }
+
+    /**
+     * Determines whether the specified character (Unicode code point)
+     * is mirrored according to the Unicode specification.  Mirrored
+     * characters should have their glyphs horizontally mirrored when
+     * displayed in text that is right-to-left.  For example,
+     * {@code '\u005Cu0028'} LEFT PARENTHESIS is semantically
+     * defined to be an <i>opening parenthesis</i>.  This will appear
+     * as a "(" in text that is left-to-right but as a ")" in text
+     * that is right-to-left.
+     *
+     * @param   codePoint the character (Unicode code point) to be tested.
+     * @return  {@code true} if the character is mirrored, {@code false}
+     *          if the character is not mirrored or is not defined.
+     * @since   1.5
+     */
+    // BEGIN Android-changed: Reimplement methods natively on top of ICU4C.
+    /*
+    public static boolean isMirrored(int codePoint) {
+        return CharacterData.of(codePoint).isMirrored(codePoint);
+    }
+    */
+    public static boolean isMirrored(int codePoint) {
+        return isMirroredImpl(codePoint);
+    }
+
+    @FastNative
+    native static boolean isMirroredImpl(int codePoint);
+    // END Android-changed: Reimplement methods natively on top of ICU4C.
+
+    /**
+     * Compares two {@code Character} objects numerically.
+     *
+     * @param   anotherCharacter   the {@code Character} to be compared.
+
+     * @return  the value {@code 0} if the argument {@code Character}
+     *          is equal to this {@code Character}; a value less than
+     *          {@code 0} if this {@code Character} is numerically less
+     *          than the {@code Character} argument; and a value greater than
+     *          {@code 0} if this {@code Character} is numerically greater
+     *          than the {@code Character} argument (unsigned comparison).
+     *          Note that this is strictly a numerical comparison; it is not
+     *          locale-dependent.
+     * @since   1.2
+     */
+    public int compareTo(Character anotherCharacter) {
+        return compare(this.value, anotherCharacter.value);
+    }
+
+    /**
+     * Compares two {@code char} values numerically.
+     * The value returned is identical to what would be returned by:
+     * <pre>
+     *    Character.valueOf(x).compareTo(Character.valueOf(y))
+     * </pre>
+     *
+     * @param  x the first {@code char} to compare
+     * @param  y the second {@code char} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 1.7
+     */
+    public static int compare(char x, char y) {
+        return x - y;
+    }
+
+    // BEGIN Android-removed: Use ICU.
+    /**
+     * Converts the character (Unicode code point) argument to uppercase using
+     * information from the UnicodeData file.
+     * <p>
+     *
+     * @param   codePoint   the character (Unicode code point) to be converted.
+     * @return  either the uppercase equivalent of the character, if
+     *          any, or an error flag ({@code Character.ERROR})
+     *          that indicates that a 1:M {@code char} mapping exists.
+     * @see     Character#isLowerCase(char)
+     * @see     Character#isUpperCase(char)
+     * @see     Character#toLowerCase(char)
+     * @see     Character#toTitleCase(char)
+     * @since 1.4
+     *
+    static int toUpperCaseEx(int codePoint) {
+        assert isValidCodePoint(codePoint);
+        return CharacterData.of(codePoint).toUpperCaseEx(codePoint);
+    }
+
+    /**
+     * Converts the character (Unicode code point) argument to uppercase using case
+     * mapping information from the SpecialCasing file in the Unicode
+     * specification. If a character has no explicit uppercase
+     * mapping, then the {@code char} itself is returned in the
+     * {@code char[]}.
+     *
+     * @param   codePoint   the character (Unicode code point) to be converted.
+     * @return a {@code char[]} with the uppercased character.
+     * @since 1.4
+     *
+    static char[] toUpperCaseCharArray(int codePoint) {
+        // As of Unicode 6.0, 1:M uppercasings only happen in the BMP.
+        assert isBmpCodePoint(codePoint);
+        return CharacterData.of(codePoint).toUpperCaseCharArray(codePoint);
+    }
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * The number of bits used to represent a <tt>char</tt> value in unsigned
+     * binary form, constant {@code 16}.
+     *
+     * @since 1.5
+     */
+    public static final int SIZE = 16;
+
+    /**
+     * The number of bytes used to represent a {@code char} value in unsigned
+     * binary form.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /**
+     * Returns the value obtained by reversing the order of the bytes in the
+     * specified <tt>char</tt> value.
+     *
+     * @param ch The {@code char} of which to reverse the byte order.
+     * @return the value obtained by reversing (or, equivalently, swapping)
+     *     the bytes in the specified <tt>char</tt> value.
+     * @since 1.5
+     */
+    public static char reverseBytes(char ch) {
+        return (char) (((ch & 0xFF00) >> 8) | (ch << 8));
+    }
+
+    /**
+     * Returns the Unicode name of the specified character
+     * {@code codePoint}, or null if the code point is
+     * {@link #UNASSIGNED unassigned}.
+     * <p>
+     * Note: if the specified character is not assigned a name by
+     * the <i>UnicodeData</i> file (part of the Unicode Character
+     * Database maintained by the Unicode Consortium), the returned
+     * name is the same as the result of expression.
+     *
+     * <blockquote>{@code
+     *     Character.UnicodeBlock.of(codePoint).toString().replace('_', ' ')
+     *     + " "
+     *     + Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH);
+     *
+     * }</blockquote>
+     *
+     * @param  codePoint the character (Unicode code point)
+     *
+     * @return the Unicode name of the specified character, or null if
+     *         the code point is unassigned.
+     *
+     * @exception IllegalArgumentException if the specified
+     *            {@code codePoint} is not a valid Unicode
+     *            code point.
+     *
+     * @since 1.7
+     */
+    public static String getName(int codePoint) {
+        if (!isValidCodePoint(codePoint)) {
+            throw new IllegalArgumentException();
+        }
+        // Android-changed: Use ICU.
+        // String name = CharacterName.get(codePoint);
+        String name = getNameImpl(codePoint);
+        if (name != null)
+            return name;
+        if (getType(codePoint) == UNASSIGNED)
+            return null;
+        UnicodeBlock block = UnicodeBlock.of(codePoint);
+        if (block != null)
+            return block.toString().replace('_', ' ') + " "
+                   + Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH);
+        // should never come here
+        return Integer.toHexString(codePoint).toUpperCase(Locale.ENGLISH);
+    }
+
+    // Android-added: Use ICU.
+    // Implement getNameImpl() natively.
+    private static native String getNameImpl(int codePoint);
+}
diff --git a/java/lang/Class.annotated.java b/java/lang/Class.annotated.java
new file mode 100644
index 0000000..fd80abb
--- /dev/null
+++ b/java/lang/Class.annotated.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Type;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.TypeVariable;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.io.InputStream;
+import java.util.HashMap;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Class<T> implements java.io.Serializable, java.lang.reflect.GenericDeclaration, java.lang.reflect.Type, java.lang.reflect.AnnotatedElement {
+
+Class() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toGenericString() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.Class<?> forName(java.lang.String className) throws java.lang.ClassNotFoundException { throw new RuntimeException("Stub!"); }
+
+public static java.lang.Class<?> forName(java.lang.String name, boolean initialize, java.lang.ClassLoader loader) throws java.lang.ClassNotFoundException { throw new RuntimeException("Stub!"); }
+
+public native T newInstance() throws java.lang.IllegalAccessException, java.lang.InstantiationException;
+
+public boolean isInstance(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public boolean isAssignableFrom(java.lang.Class<?> cls) { throw new RuntimeException("Stub!"); }
+
+public boolean isInterface() { throw new RuntimeException("Stub!"); }
+
+public boolean isArray() { throw new RuntimeException("Stub!"); }
+
+public boolean isPrimitive() { throw new RuntimeException("Stub!"); }
+
+public boolean isFinalizable() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnnotation() { throw new RuntimeException("Stub!"); }
+
+public boolean isSynthetic() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.ClassLoader getClassLoader() { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.reflect.TypeVariable<java.lang.Class<T>>[] getTypeParameters() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<? super T> getSuperclass() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Type getGenericSuperclass() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Package getPackage() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.lang.String getPackageName$() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?>[] getInterfaces() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Type[] getGenericInterfaces() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?> getComponentType() { throw new RuntimeException("Stub!"); }
+
+public int getModifiers() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object[] getSigners() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Method getEnclosingMethod() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Constructor<?> getEnclosingConstructor() { throw new RuntimeException("Stub!"); }
+
+public native java.lang.Class<?> getDeclaringClass();
+
+public native java.lang.Class<?> getEnclosingClass();
+
+public java.lang.String getSimpleName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getTypeName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getCanonicalName() { throw new RuntimeException("Stub!"); }
+
+public native boolean isAnonymousClass();
+
+public boolean isLocalClass() { throw new RuntimeException("Stub!"); }
+
+public boolean isMemberClass() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Class<?>[] getClasses() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Field[] getFields() throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Method[] getMethods() throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Constructor<?>[] getConstructors() throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Field getField(java.lang.String name) throws java.lang.NoSuchFieldException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Method getMethod(java.lang.String name, java.lang.Class<?>... parameterTypes) throws java.lang.NoSuchMethodException, java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Constructor<T> getConstructor(java.lang.Class<?>... parameterTypes) throws java.lang.NoSuchMethodException, java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public native java.lang.Class<?>[] getDeclaredClasses();
+
+public native java.lang.reflect.Field[] getDeclaredFields();
+
[email protected]
+public native java.lang.reflect.Field[] getDeclaredFieldsUnchecked(boolean publicOnly);
+
+public java.lang.reflect.Method[] getDeclaredMethods() throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public native java.lang.reflect.Method[] getDeclaredMethodsUnchecked(boolean publicOnly);
+
+public java.lang.reflect.Constructor<?>[] getDeclaredConstructors() throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public native java.lang.reflect.Field getDeclaredField(java.lang.String name) throws java.lang.NoSuchFieldException;
+
+public java.lang.reflect.Method getDeclaredMethod(java.lang.String name, java.lang.Class<?>... parameterTypes) throws java.lang.NoSuchMethodException, java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Method getInstanceMethod(java.lang.String name, java.lang.Class<?>[] parameterTypes) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Constructor<T> getDeclaredConstructor(java.lang.Class<?>... parameterTypes) throws java.lang.NoSuchMethodException, java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public java.io.InputStream getResourceAsStream(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public java.net.URL getResource(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public java.security.ProtectionDomain getProtectionDomain() { throw new RuntimeException("Stub!"); }
+
+public boolean desiredAssertionStatus() { throw new RuntimeException("Stub!"); }
+
+public boolean isEnum() { throw new RuntimeException("Stub!"); }
+
+public T[] getEnumConstants() { throw new RuntimeException("Stub!"); }
+
+public T[] getEnumConstantsShared() { throw new RuntimeException("Stub!"); }
+
+public T cast(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public <U> java.lang.Class<? extends U> asSubclass(java.lang.Class<U> clazz) { throw new RuntimeException("Stub!"); }
+
+public <A extends java.lang.annotation.Annotation> A getAnnotation(java.lang.Class<A> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <A extends java.lang.annotation.Annotation> A[] getAnnotationsByType(java.lang.Class<A> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public java.lang.annotation.Annotation[] getAnnotations() { throw new RuntimeException("Stub!"); }
+
+public native <A extends java.lang.annotation.Annotation> A getDeclaredAnnotation(java.lang.Class<A> annotationClass);
+
+public native java.lang.annotation.Annotation[] getDeclaredAnnotations();
+
+public boolean isProxy() { throw new RuntimeException("Stub!"); }
+
+public int getAccessFlags() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/lang/Class.java b/java/lang/Class.java
new file mode 100644
index 0000000..f792248
--- /dev/null
+++ b/java/lang/Class.java
@@ -0,0 +1,2675 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.InternalNames;
+import libcore.reflect.Types;
+import libcore.util.BasicLruCache;
+import libcore.util.CollectionUtils;
+import libcore.util.EmptyArray;
+
+import dalvik.system.ClassExt;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * Instances of the class {@code Class} represent classes and
+ * interfaces in a running Java application.  An enum is a kind of
+ * class and an annotation is a kind of interface.  Every array also
+ * belongs to a class that is reflected as a {@code Class} object
+ * that is shared by all arrays with the same element type and number
+ * of dimensions.  The primitive Java types ({@code boolean},
+ * {@code byte}, {@code char}, {@code short},
+ * {@code int}, {@code long}, {@code float}, and
+ * {@code double}), and the keyword {@code void} are also
+ * represented as {@code Class} objects.
+ *
+ * <p> {@code Class} has no public constructor. Instead {@code Class}
+ * objects are constructed automatically by the Java Virtual Machine as classes
+ * are loaded and by calls to the {@code defineClass} method in the class
+ * loader.
+ *
+ * <p> The following example uses a {@code Class} object to print the
+ * class name of an object:
+ *
+ * <blockquote><pre>
+ *     void printClassName(Object obj) {
+ *         System.out.println("The class of " + obj +
+ *                            " is " + obj.getClass().getName());
+ *     }
+ * </pre></blockquote>
+ *
+ * <p> It is also possible to get the {@code Class} object for a named
+ * type (or for void) using a class literal.  See Section 15.8.2 of
+ * <cite>The Java&trade; Language Specification</cite>.
+ * For example:
+ *
+ * <blockquote>
+ *     {@code System.out.println("The name of class Foo is: "+Foo.class.getName());}
+ * </blockquote>
+ *
+ * @param <T> the type of the class modeled by this {@code Class}
+ * object.  For example, the type of {@code String.class} is {@code
+ * Class<String>}.  Use {@code Class<?>} if the class being modeled is
+ * unknown.
+ *
+ * @author  unascribed
+ * @see     java.lang.ClassLoader#defineClass(byte[], int, int)
+ * @since   JDK1.0
+ */
+public final class Class<T> implements java.io.Serializable,
+                              GenericDeclaration,
+                              Type,
+                              AnnotatedElement {
+    private static final int ANNOTATION= 0x00002000;
+    private static final int ENUM      = 0x00004000;
+    private static final int SYNTHETIC = 0x00001000;
+    private static final int FINALIZABLE = 0x80000000;
+
+    /** defining class loader, or null for the "bootstrap" system loader. */
+    private transient ClassLoader classLoader;
+
+    /**
+     * For array classes, the component class object for instanceof/checkcast (for String[][][],
+     * this will be String[][]). null for non-array classes.
+     */
+    private transient Class<?> componentType;
+
+    /**
+     * DexCache of resolved constant pool entries. Will be null for certain runtime-generated classes
+     * e.g. arrays and primitive classes.
+     */
+    private transient Object dexCache;
+
+    /**
+     * Extra data that only some classes possess. This is allocated lazily as needed.
+     */
+    private transient ClassExt extData;
+
+    /**
+     * The interface table (iftable_) contains pairs of a interface class and an array of the
+     * interface methods. There is one pair per interface supported by this class.  That
+     * means one pair for each interface we support directly, indirectly via superclass, or
+     * indirectly via a superinterface.  This will be null if neither we nor our superclass
+     * implement any interfaces.
+     *
+     * Why we need this: given "class Foo implements Face", declare "Face faceObj = new Foo()".
+     * Invoke faceObj.blah(), where "blah" is part of the Face interface.  We can't easily use a
+     * single vtable.
+     *
+     * For every interface a concrete class implements, we create an array of the concrete vtable_
+     * methods for the methods in the interface.
+     */
+    private transient Object[] ifTable;
+
+    /** Lazily computed name of this class; always prefer calling getName(). */
+    private transient String name;
+
+    /** The superclass, or null if this is java.lang.Object, an interface or primitive type. */
+    private transient Class<? super T> superClass;
+
+    /**
+     * Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass
+     * is copied in, and virtual methods from our class either replace those from the super or are
+     * appended. For abstract classes, methods may be created in the vtable that aren't in
+     * virtual_ methods_ for miranda methods.
+     */
+    private transient Object vtable;
+
+    /**
+     * Instance fields. These describe the layout of the contents of an Object. Note that only the
+     * fields directly declared by this class are listed in iFields; fields declared by a
+     * superclass are listed in the superclass's Class.iFields.
+     *
+     * All instance fields that refer to objects are guaranteed to be at the beginning of the field
+     * list.  {@link Class#numReferenceInstanceFields} specifies the number of reference fields.
+     */
+    private transient long iFields;
+
+    /** All methods with this class as the base for virtual dispatch. */
+    private transient long methods;
+
+    /** Static fields */
+    private transient long sFields;
+
+    /** access flags; low 16 bits are defined by VM spec */
+    private transient int accessFlags;
+
+    /** Class flags to help the GC with object scanning. */
+    private transient int classFlags;
+
+    /**
+     * Total size of the Class instance; used when allocating storage on GC heap.
+     * See also {@link Class#objectSize}.
+     */
+    private transient int classSize;
+
+    /**
+     * tid used to check for recursive static initializer invocation.
+     */
+    private transient int clinitThreadId;
+
+    /**
+     * Class def index from dex file. An index of 65535 indicates that there is no class definition,
+     * for example for an array type.
+     * TODO: really 16bits as type indices are 16bit.
+     */
+    private transient int dexClassDefIndex;
+
+    /**
+     * Class type index from dex file, lazily computed. An index of 65535 indicates that the type
+     * index isn't known. Volatile to avoid double-checked locking bugs.
+     * TODO: really 16bits as type indices are 16bit.
+     */
+    private transient volatile int dexTypeIndex;
+
+    /** Number of instance fields that are object references. */
+    private transient int numReferenceInstanceFields;
+
+    /** Number of static fields that are object references. */
+    private transient int numReferenceStaticFields;
+
+    /**
+     * Total object size; used when allocating storage on GC heap. For interfaces and abstract
+     * classes this will be zero. See also {@link Class#classSize}.
+     */
+    private transient int objectSize;
+
+    /**
+     * Aligned object size for allocation fast path. The value is max int if the object is
+     * uninitialized or finalizable, otherwise the aligned object size.
+     */
+    private transient int objectSizeAllocFastPath;
+
+    /**
+     * The lower 16 bits is the primitive type value, or 0 if not a primitive type; set for
+     * generated primitive classes.
+     */
+    private transient int primitiveType;
+
+    /** Bitmap of offsets of iFields. */
+    private transient int referenceInstanceOffsets;
+
+    /** State of class initialization */
+    private transient int status;
+
+    /** Offset of the first virtual method copied from an interface in the methods array. */
+    private transient short copiedMethodsOffset;
+
+    /** Offset of the first virtual method defined in this class in the methods array. */
+    private transient short virtualMethodsOffset;
+
+    /*
+     * Private constructor. Only the Java Virtual Machine creates Class objects.
+     * This constructor is not used and prevents the default constructor being
+     * generated.
+     */
+    private Class() {}
+
+
+    /**
+     * Converts the object to a string. The string representation is the
+     * string "class" or "interface", followed by a space, and then by the
+     * fully qualified name of the class in the format returned by
+     * {@code getName}.  If this {@code Class} object represents a
+     * primitive type, this method returns the name of the primitive type.  If
+     * this {@code Class} object represents void this method returns
+     * "void".
+     *
+     * @return a string representation of this class object.
+     */
+    public String toString() {
+        return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+            + getName();
+    }
+
+    /**
+     * Returns a string describing this {@code Class}, including
+     * information about modifiers and type parameters.
+     *
+     * The string is formatted as a list of type modifiers, if any,
+     * followed by the kind of type (empty string for primitive types
+     * and {@code class}, {@code enum}, {@code interface}, or
+     * <code>&#64;</code>{@code interface}, as appropriate), followed
+     * by the type's name, followed by an angle-bracketed
+     * comma-separated list of the type's type parameters, if any.
+     *
+     * A space is used to separate modifiers from one another and to
+     * separate any modifiers from the kind of type. The modifiers
+     * occur in canonical order. If there are no type parameters, the
+     * type parameter list is elided.
+     *
+     * <p>Note that since information about the runtime representation
+     * of a type is being generated, modifiers not present on the
+     * originating source code or illegal on the originating source
+     * code may be present.
+     *
+     * @return a string describing this {@code Class}, including
+     * information about modifiers and type parameters
+     *
+     * @since 1.8
+     */
+    public String toGenericString() {
+        if (isPrimitive()) {
+            return toString();
+        } else {
+            StringBuilder sb = new StringBuilder();
+
+            // Class modifiers are a superset of interface modifiers
+            int modifiers = getModifiers() & Modifier.classModifiers();
+            if (modifiers != 0) {
+                sb.append(Modifier.toString(modifiers));
+                sb.append(' ');
+            }
+
+            if (isAnnotation()) {
+                sb.append('@');
+            }
+            if (isInterface()) { // Note: all annotation types are interfaces
+                sb.append("interface");
+            } else {
+                if (isEnum())
+                    sb.append("enum");
+                else
+                    sb.append("class");
+            }
+            sb.append(' ');
+            sb.append(getName());
+
+            TypeVariable<?>[] typeparms = getTypeParameters();
+            if (typeparms.length > 0) {
+                boolean first = true;
+                sb.append('<');
+                for(TypeVariable<?> typeparm: typeparms) {
+                    if (!first)
+                        sb.append(',');
+                    sb.append(typeparm.getTypeName());
+                    first = false;
+                }
+                sb.append('>');
+            }
+
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Returns the {@code Class} object associated with the class or
+     * interface with the given string name.  Invoking this method is
+     * equivalent to:
+     *
+     * <blockquote>
+     *  {@code Class.forName(className, true, currentLoader)}
+     * </blockquote>
+     *
+     * where {@code currentLoader} denotes the defining class loader of
+     * the current class.
+     *
+     * <p> For example, the following code fragment returns the
+     * runtime {@code Class} descriptor for the class named
+     * {@code java.lang.Thread}:
+     *
+     * <blockquote>
+     *   {@code Class t = Class.forName("java.lang.Thread")}
+     * </blockquote>
+     * <p>
+     * A call to {@code forName("X")} causes the class named
+     * {@code X} to be initialized.
+     *
+     * @param      className   the fully qualified name of the desired class.
+     * @return     the {@code Class} object for the class with the
+     *             specified name.
+     * @exception LinkageError if the linkage fails
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *            by this method fails
+     * @exception ClassNotFoundException if the class cannot be located
+     */
+    @CallerSensitive
+    public static Class<?> forName(String className)
+                throws ClassNotFoundException {
+        Class<?> caller = Reflection.getCallerClass();
+        return forName(className, true, ClassLoader.getClassLoader(caller));
+    }
+
+
+    /**
+     * Returns the {@code Class} object associated with the class or
+     * interface with the given string name, using the given class loader.
+     * Given the fully qualified name for a class or interface (in the same
+     * format returned by {@code getName}) this method attempts to
+     * locate, load, and link the class or interface.  The specified class
+     * loader is used to load the class or interface.  If the parameter
+     * {@code loader} is null, the class is loaded through the bootstrap
+     * class loader.  The class is initialized only if the
+     * {@code initialize} parameter is {@code true} and if it has
+     * not been initialized earlier.
+     *
+     * <p> If {@code name} denotes a primitive type or void, an attempt
+     * will be made to locate a user-defined class in the unnamed package whose
+     * name is {@code name}. Therefore, this method cannot be used to
+     * obtain any of the {@code Class} objects representing primitive
+     * types or void.
+     *
+     * <p> If {@code name} denotes an array class, the component type of
+     * the array class is loaded but not initialized.
+     *
+     * <p> For example, in an instance method the expression:
+     *
+     * <blockquote>
+     *  {@code Class.forName("Foo")}
+     * </blockquote>
+     *
+     * is equivalent to:
+     *
+     * <blockquote>
+     *  {@code Class.forName("Foo", true, this.getClass().getClassLoader())}
+     * </blockquote>
+     *
+     * Note that this method throws errors related to loading, linking or
+     * initializing as specified in Sections 12.2, 12.3 and 12.4 of <em>The
+     * Java Language Specification</em>.
+     * Note that this method does not check whether the requested class
+     * is accessible to its caller.
+     *
+     * <p> If the {@code loader} is {@code null}, and a security
+     * manager is present, and the caller's class loader is not null, then this
+     * method calls the security manager's {@code checkPermission} method
+     * with a {@code RuntimePermission("getClassLoader")} permission to
+     * ensure it's ok to access the bootstrap class loader.
+     *
+     * @param name       fully qualified name of the desired class
+     * @param initialize if {@code true} the class will be initialized.
+     *                   See Section 12.4 of <em>The Java Language Specification</em>.
+     * @param loader     class loader from which the class must be loaded
+     * @return           class object representing the desired class
+     *
+     * @exception LinkageError if the linkage fails
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *            by this method fails
+     * @exception ClassNotFoundException if the class cannot be located by
+     *            the specified class loader
+     *
+     * @see       java.lang.Class#forName(String)
+     * @see       java.lang.ClassLoader
+     * @since     1.2
+     */
+    @CallerSensitive
+    public static Class<?> forName(String name, boolean initialize,
+                                   ClassLoader loader)
+        throws ClassNotFoundException
+    {
+        if (loader == null) {
+            loader = BootClassLoader.getInstance();
+        }
+        Class<?> result;
+        try {
+            result = classForName(name, initialize, loader);
+        } catch (ClassNotFoundException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof LinkageError) {
+                throw (LinkageError) cause;
+            }
+            throw e;
+        }
+        return result;
+    }
+
+    /** Called after security checks have been made. */
+    @FastNative
+    static native Class<?> classForName(String className, boolean shouldInitialize,
+            ClassLoader classLoader) throws ClassNotFoundException;
+
+    /**
+     * Creates a new instance of the class represented by this {@code Class}
+     * object.  The class is instantiated as if by a {@code new}
+     * expression with an empty argument list.  The class is initialized if it
+     * has not already been initialized.
+     *
+     * <p>Note that this method propagates any exception thrown by the
+     * nullary constructor, including a checked exception.  Use of
+     * this method effectively bypasses the compile-time exception
+     * checking that would otherwise be performed by the compiler.
+     * The {@link
+     * java.lang.reflect.Constructor#newInstance(java.lang.Object...)
+     * Constructor.newInstance} method avoids this problem by wrapping
+     * any exception thrown by the constructor in a (checked) {@link
+     * java.lang.reflect.InvocationTargetException}.
+     *
+     * @return  a newly allocated instance of the class represented by this
+     *          object.
+     * @throws  IllegalAccessException  if the class or its nullary
+     *          constructor is not accessible.
+     * @throws  InstantiationException
+     *          if this {@code Class} represents an abstract class,
+     *          an interface, an array class, a primitive type, or void;
+     *          or if the class has no nullary constructor;
+     *          or if the instantiation fails for some other reason.
+     * @throws  ExceptionInInitializerError if the initialization
+     *          provoked by this method fails.
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and
+     *          the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class.
+     */
+    @FastNative
+    public native T newInstance() throws InstantiationException, IllegalAccessException;
+
+    /**
+     * Determines if the specified {@code Object} is assignment-compatible
+     * with the object represented by this {@code Class}.  This method is
+     * the dynamic equivalent of the Java language {@code instanceof}
+     * operator. The method returns {@code true} if the specified
+     * {@code Object} argument is non-null and can be cast to the
+     * reference type represented by this {@code Class} object without
+     * raising a {@code ClassCastException.} It returns {@code false}
+     * otherwise.
+     *
+     * <p> Specifically, if this {@code Class} object represents a
+     * declared class, this method returns {@code true} if the specified
+     * {@code Object} argument is an instance of the represented class (or
+     * of any of its subclasses); it returns {@code false} otherwise. If
+     * this {@code Class} object represents an array class, this method
+     * returns {@code true} if the specified {@code Object} argument
+     * can be converted to an object of the array class by an identity
+     * conversion or by a widening reference conversion; it returns
+     * {@code false} otherwise. If this {@code Class} object
+     * represents an interface, this method returns {@code true} if the
+     * class or any superclass of the specified {@code Object} argument
+     * implements this interface; it returns {@code false} otherwise. If
+     * this {@code Class} object represents a primitive type, this method
+     * returns {@code false}.
+     *
+     * @param   obj the object to check
+     * @return  true if {@code obj} is an instance of this class
+     *
+     * @since JDK1.1
+     */
+    public boolean isInstance(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        return isAssignableFrom(obj.getClass());
+    }
+
+
+    /**
+     * Determines if the class or interface represented by this
+     * {@code Class} object is either the same as, or is a superclass or
+     * superinterface of, the class or interface represented by the specified
+     * {@code Class} parameter. It returns {@code true} if so;
+     * otherwise it returns {@code false}. If this {@code Class}
+     * object represents a primitive type, this method returns
+     * {@code true} if the specified {@code Class} parameter is
+     * exactly this {@code Class} object; otherwise it returns
+     * {@code false}.
+     *
+     * <p> Specifically, this method tests whether the type represented by the
+     * specified {@code Class} parameter can be converted to the type
+     * represented by this {@code Class} object via an identity conversion
+     * or via a widening reference conversion. See <em>The Java Language
+     * Specification</em>, sections 5.1.1 and 5.1.4 , for details.
+     *
+     * @param cls the {@code Class} object to be checked
+     * @return the {@code boolean} value indicating whether objects of the
+     * type {@code cls} can be assigned to objects of this class
+     * @exception NullPointerException if the specified Class parameter is
+     *            null.
+     * @since JDK1.1
+     */
+    public boolean isAssignableFrom(Class<?> cls) {
+        if (this == cls) {
+            return true;  // Can always assign to things of the same type.
+        } else if (this == Object.class) {
+            return !cls.isPrimitive();  // Can assign any reference to java.lang.Object.
+        } else if (isArray()) {
+            return cls.isArray() && componentType.isAssignableFrom(cls.componentType);
+        } else if (isInterface()) {
+            // Search iftable which has a flattened and uniqued list of interfaces.
+            Object[] iftable = cls.ifTable;
+            if (iftable != null) {
+                for (int i = 0; i < iftable.length; i += 2) {
+                    if (iftable[i] == this) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        } else {
+            if (!cls.isInterface()) {
+                for (cls = cls.superClass; cls != null; cls = cls.superClass) {
+                    if (cls == this) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Determines if the specified {@code Class} object represents an
+     * interface type.
+     *
+     * @return  {@code true} if this object represents an interface;
+     *          {@code false} otherwise.
+     */
+    public boolean isInterface() {
+        return (accessFlags & Modifier.INTERFACE) != 0;
+    }
+
+    /**
+     * Determines if this {@code Class} object represents an array class.
+     *
+     * @return  {@code true} if this object represents an array class;
+     *          {@code false} otherwise.
+     * @since   JDK1.1
+     */
+    public boolean isArray() {
+        return getComponentType() != null;
+    }
+
+    /**
+     * Determines if the specified {@code Class} object represents a
+     * primitive type.
+     *
+     * <p> There are nine predefined {@code Class} objects to represent
+     * the eight primitive types and void.  These are created by the Java
+     * Virtual Machine, and have the same names as the primitive types that
+     * they represent, namely {@code boolean}, {@code byte},
+     * {@code char}, {@code short}, {@code int},
+     * {@code long}, {@code float}, and {@code double}.
+     *
+     * <p> These objects may only be accessed via the following public static
+     * final variables, and are the only {@code Class} objects for which
+     * this method returns {@code true}.
+     *
+     * @return true if and only if this class represents a primitive type
+     *
+     * @see     java.lang.Boolean#TYPE
+     * @see     java.lang.Character#TYPE
+     * @see     java.lang.Byte#TYPE
+     * @see     java.lang.Short#TYPE
+     * @see     java.lang.Integer#TYPE
+     * @see     java.lang.Long#TYPE
+     * @see     java.lang.Float#TYPE
+     * @see     java.lang.Double#TYPE
+     * @see     java.lang.Void#TYPE
+     * @since JDK1.1
+     */
+    public boolean isPrimitive() {
+      return (primitiveType & 0xFFFF) != 0;
+    }
+
+    /**
+     * Indicates whether this {@code Class} or its parents override finalize.
+     *
+     * @return {@code true} if and if this class or its parents override
+     *         finalize;
+     *
+     * @hide
+     */
+    public boolean isFinalizable() {
+        return (getModifiers() & FINALIZABLE) != 0;
+    }
+
+    /**
+     * Returns true if this {@code Class} object represents an annotation
+     * type.  Note that if this method returns true, {@link #isInterface()}
+     * would also return true, as all annotation types are also interfaces.
+     *
+     * @return {@code true} if this class object represents an annotation
+     *      type; {@code false} otherwise
+     * @since 1.5
+     */
+    public boolean isAnnotation() {
+        return (getModifiers() & ANNOTATION) != 0;
+    }
+
+    /**
+     * Returns {@code true} if this class is a synthetic class;
+     * returns {@code false} otherwise.
+     * @return {@code true} if and only if this class is a synthetic class as
+     *         defined by the Java Language Specification.
+     * @jls 13.1 The Form of a Binary
+     * @since 1.5
+     */
+    public boolean isSynthetic() {
+        return (getModifiers() & SYNTHETIC) != 0;
+    }
+
+    /**
+     * Returns the  name of the entity (class, interface, array class,
+     * primitive type, or void) represented by this {@code Class} object,
+     * as a {@code String}.
+     *
+     * <p> If this class object represents a reference type that is not an
+     * array type then the binary name of the class is returned, as specified
+     * by
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * <p> If this class object represents a primitive type or void, then the
+     * name returned is a {@code String} equal to the Java language
+     * keyword corresponding to the primitive type or void.
+     *
+     * <p> If this class object represents a class of arrays, then the internal
+     * form of the name consists of the name of the element type preceded by
+     * one or more '{@code [}' characters representing the depth of the array
+     * nesting.  The encoding of element type names is as follows:
+     *
+     * <blockquote><table summary="Element types and encodings">
+     * <tr><th> Element Type <th> &nbsp;&nbsp;&nbsp; <th> Encoding
+     * <tr><td> boolean      <td> &nbsp;&nbsp;&nbsp; <td align=center> Z
+     * <tr><td> byte         <td> &nbsp;&nbsp;&nbsp; <td align=center> B
+     * <tr><td> char         <td> &nbsp;&nbsp;&nbsp; <td align=center> C
+     * <tr><td> class or interface
+     *                       <td> &nbsp;&nbsp;&nbsp; <td align=center> L<i>classname</i>;
+     * <tr><td> double       <td> &nbsp;&nbsp;&nbsp; <td align=center> D
+     * <tr><td> float        <td> &nbsp;&nbsp;&nbsp; <td align=center> F
+     * <tr><td> int          <td> &nbsp;&nbsp;&nbsp; <td align=center> I
+     * <tr><td> long         <td> &nbsp;&nbsp;&nbsp; <td align=center> J
+     * <tr><td> short        <td> &nbsp;&nbsp;&nbsp; <td align=center> S
+     * </table></blockquote>
+     *
+     * <p> The class or interface name <i>classname</i> is the binary name of
+     * the class specified above.
+     *
+     * <p> Examples:
+     * <blockquote><pre>
+     * String.class.getName()
+     *     returns "java.lang.String"
+     * byte.class.getName()
+     *     returns "byte"
+     * (new Object[3]).getClass().getName()
+     *     returns "[Ljava.lang.Object;"
+     * (new int[3][4][5][6][7][8][9]).getClass().getName()
+     *     returns "[[[[[[[I"
+     * </pre></blockquote>
+     *
+     * @return  the name of the class or interface
+     *          represented by this object.
+     */
+    public String getName() {
+        String name = this.name;
+        if (name == null)
+            this.name = name = getNameNative();
+        return name;
+    }
+
+    @FastNative
+    private native String getNameNative();
+
+    /**
+     * Returns the class loader for the class.  Some implementations may use
+     * null to represent the bootstrap class loader. This method will return
+     * null in such implementations if this class was loaded by the bootstrap
+     * class loader.
+     *
+     * <p> If a security manager is present, and the caller's class loader is
+     * not null and the caller's class loader is not the same as or an ancestor of
+     * the class loader for the class whose class loader is requested, then
+     * this method calls the security manager's {@code checkPermission}
+     * method with a {@code RuntimePermission("getClassLoader")}
+     * permission to ensure it's ok to access the class loader for the class.
+     *
+     * <p>If this object
+     * represents a primitive type or void, null is returned.
+     *
+     * @return  the class loader that loaded the class or interface
+     *          represented by this object.
+     * @throws SecurityException
+     *    if a security manager exists and its
+     *    {@code checkPermission} method denies
+     *    access to the class loader for the class.
+     * @see java.lang.ClassLoader
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     */
+    public ClassLoader getClassLoader() {
+        if (isPrimitive()) {
+            return null;
+        }
+        // Android-note: The RI returns null in the case where Android returns BootClassLoader.
+        // Noted in http://b/111850480#comment3
+        return (classLoader == null) ? BootClassLoader.getInstance() : classLoader;
+    }
+
+    /**
+     * Returns an array of {@code TypeVariable} objects that represent the
+     * type variables declared by the generic declaration represented by this
+     * {@code GenericDeclaration} object, in declaration order.  Returns an
+     * array of length 0 if the underlying generic declaration declares no type
+     * variables.
+     *
+     * @return an array of {@code TypeVariable} objects that represent
+     *     the type variables declared by this generic declaration
+     * @throws java.lang.reflect.GenericSignatureFormatError if the generic
+     *     signature of this generic declaration does not conform to
+     *     the format specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @since 1.5
+     */
+    @Override
+    public synchronized TypeVariable<Class<T>>[] getTypeParameters() {
+        String annotationSignature = getSignatureAttribute();
+        if (annotationSignature == null) {
+            return EmptyArray.TYPE_VARIABLE;
+        }
+        GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+        parser.parseForClass(this, annotationSignature);
+        return parser.formalTypeParameters;
+    }
+
+
+    /**
+     * Returns the {@code Class} representing the superclass of the entity
+     * (class, interface, primitive type or void) represented by this
+     * {@code Class}.  If this {@code Class} represents either the
+     * {@code Object} class, an interface, a primitive type, or void, then
+     * null is returned.  If this object represents an array class then the
+     * {@code Class} object representing the {@code Object} class is
+     * returned.
+     *
+     * @return the superclass of the class represented by this object.
+     */
+    public Class<? super T> getSuperclass() {
+        // For interfaces superClass is Object (which agrees with the JNI spec)
+        // but not with the expected behavior here.
+        if (isInterface()) {
+            return null;
+        } else {
+            return superClass;
+        }
+    }
+
+    /**
+     * Returns the {@code Type} representing the direct superclass of
+     * the entity (class, interface, primitive type or void) represented by
+     * this {@code Class}.
+     *
+     * <p>If the superclass is a parameterized type, the {@code Type}
+     * object returned must accurately reflect the actual type
+     * parameters used in the source code. The parameterized type
+     * representing the superclass is created if it had not been
+     * created before. See the declaration of {@link
+     * java.lang.reflect.ParameterizedType ParameterizedType} for the
+     * semantics of the creation process for parameterized types.  If
+     * this {@code Class} represents either the {@code Object}
+     * class, an interface, a primitive type, or void, then null is
+     * returned.  If this object represents an array class then the
+     * {@code Class} object representing the {@code Object} class is
+     * returned.
+     *
+     * @throws java.lang.reflect.GenericSignatureFormatError if the generic
+     *     class signature does not conform to the format specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if the generic superclass
+     *     refers to a non-existent type declaration
+     * @throws java.lang.reflect.MalformedParameterizedTypeException if the
+     *     generic superclass refers to a parameterized type that cannot be
+     *     instantiated  for any reason
+     * @return the superclass of the class represented by this object
+     * @since 1.5
+     */
+    public Type getGenericSuperclass() {
+        Type genericSuperclass = getSuperclass();
+        // This method is specified to return null for all cases where getSuperclass
+        // returns null, i.e, for primitives, interfaces, void and java.lang.Object.
+        if (genericSuperclass == null) {
+            return null;
+        }
+
+        String annotationSignature = getSignatureAttribute();
+        if (annotationSignature != null) {
+            GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+            parser.parseForClass(this, annotationSignature);
+            genericSuperclass = parser.superclassType;
+        }
+        return Types.getType(genericSuperclass);
+    }
+
+    /**
+     * Gets the package for this class.  The class loader of this class is used
+     * to find the package.  If the class was loaded by the bootstrap class
+     * loader the set of packages loaded from CLASSPATH is searched to find the
+     * package of the class. Null is returned if no package object was created
+     * by the class loader of this class.
+     *
+     * <p> Packages have attributes for versions and specifications only if the
+     * information was defined in the manifests that accompany the classes, and
+     * if the class loader created the package instance with the attributes
+     * from the manifest.
+     *
+     * @return the package of the class, or null if no package
+     *         information is available from the archive or codebase.
+     */
+    public Package getPackage() {
+        ClassLoader loader = getClassLoader();
+        if (loader != null) {
+            String packageName = getPackageName$();
+            return packageName != null ? loader.getPackage(packageName) : null;
+        }
+        return null;
+    }
+
+    /**
+     * Returns the package name of this class. This returns null for classes in
+     * the default package.
+     *
+     * @hide
+     */
+    public String getPackageName$() {
+        String name = getName();
+        int last = name.lastIndexOf('.');
+        return last == -1 ? null : name.substring(0, last);
+    }
+
+
+    /**
+     * Determines the interfaces implemented by the class or interface
+     * represented by this object.
+     *
+     * <p> If this object represents a class, the return value is an array
+     * containing objects representing all interfaces implemented by the
+     * class. The order of the interface objects in the array corresponds to
+     * the order of the interface names in the {@code implements} clause
+     * of the declaration of the class represented by this object. For
+     * example, given the declaration:
+     * <blockquote>
+     * {@code class Shimmer implements FloorWax, DessertTopping { ... }}
+     * </blockquote>
+     * suppose the value of {@code s} is an instance of
+     * {@code Shimmer}; the value of the expression:
+     * <blockquote>
+     * {@code s.getClass().getInterfaces()[0]}
+     * </blockquote>
+     * is the {@code Class} object that represents interface
+     * {@code FloorWax}; and the value of:
+     * <blockquote>
+     * {@code s.getClass().getInterfaces()[1]}
+     * </blockquote>
+     * is the {@code Class} object that represents interface
+     * {@code DessertTopping}.
+     *
+     * <p> If this object represents an interface, the array contains objects
+     * representing all interfaces extended by the interface. The order of the
+     * interface objects in the array corresponds to the order of the interface
+     * names in the {@code extends} clause of the declaration of the
+     * interface represented by this object.
+     *
+     * <p> If this object represents a class or interface that implements no
+     * interfaces, the method returns an array of length 0.
+     *
+     * <p> If this object represents a primitive type or void, the method
+     * returns an array of length 0.
+     *
+     * <p> If this {@code Class} object represents an array type, the
+     * interfaces {@code Cloneable} and {@code java.io.Serializable} are
+     * returned in that order.
+     *
+     * @return an array of interfaces implemented by this class.
+     */
+    public Class<?>[] getInterfaces() {
+        if (isArray()) {
+            return new Class<?>[] { Cloneable.class, Serializable.class };
+        }
+
+        final Class<?>[] ifaces = getInterfacesInternal();
+        if (ifaces == null) {
+            return EmptyArray.CLASS;
+        }
+
+        return ifaces;
+    }
+
+    @FastNative
+    private native Class<?>[] getInterfacesInternal();
+
+
+    /**
+     * Returns the {@code Type}s representing the interfaces
+     * directly implemented by the class or interface represented by
+     * this object.
+     *
+     * <p>If a superinterface is a parameterized type, the
+     * {@code Type} object returned for it must accurately reflect
+     * the actual type parameters used in the source code. The
+     * parameterized type representing each superinterface is created
+     * if it had not been created before. See the declaration of
+     * {@link java.lang.reflect.ParameterizedType ParameterizedType}
+     * for the semantics of the creation process for parameterized
+     * types.
+     *
+     * <p> If this object represents a class, the return value is an
+     * array containing objects representing all interfaces
+     * implemented by the class. The order of the interface objects in
+     * the array corresponds to the order of the interface names in
+     * the {@code implements} clause of the declaration of the class
+     * represented by this object.  In the case of an array class, the
+     * interfaces {@code Cloneable} and {@code Serializable} are
+     * returned in that order.
+     *
+     * <p>If this object represents an interface, the array contains
+     * objects representing all interfaces directly extended by the
+     * interface.  The order of the interface objects in the array
+     * corresponds to the order of the interface names in the
+     * {@code extends} clause of the declaration of the interface
+     * represented by this object.
+     *
+     * <p>If this object represents a class or interface that
+     * implements no interfaces, the method returns an array of length
+     * 0.
+     *
+     * <p>If this object represents a primitive type or void, the
+     * method returns an array of length 0.
+     *
+     * @throws java.lang.reflect.GenericSignatureFormatError
+     *     if the generic class signature does not conform to the format
+     *     specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if any of the generic
+     *     superinterfaces refers to a non-existent type declaration
+     * @throws java.lang.reflect.MalformedParameterizedTypeException
+     *     if any of the generic superinterfaces refer to a parameterized
+     *     type that cannot be instantiated for any reason
+     * @return an array of interfaces implemented by this class
+     * @since 1.5
+     */
+    public Type[] getGenericInterfaces() {
+        Type[] result;
+        synchronized (Caches.genericInterfaces) {
+            result = Caches.genericInterfaces.get(this);
+            if (result == null) {
+                String annotationSignature = getSignatureAttribute();
+                if (annotationSignature == null) {
+                    result = getInterfaces();
+                } else {
+                    GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+                    parser.parseForClass(this, annotationSignature);
+                    result = Types.getTypeArray(parser.interfaceTypes, false);
+                }
+                Caches.genericInterfaces.put(this, result);
+            }
+        }
+        return (result.length == 0) ? result : result.clone();
+    }
+
+
+    /**
+     * Returns the {@code Class} representing the component type of an
+     * array.  If this class does not represent an array class this method
+     * returns null.
+     *
+     * @return the {@code Class} representing the component type of this
+     * class if this class is an array
+     * @see     java.lang.reflect.Array
+     * @since JDK1.1
+     */
+    public Class<?> getComponentType() {
+      return componentType;
+    }
+
+    /**
+     * Returns the Java language modifiers for this class or interface, encoded
+     * in an integer. The modifiers consist of the Java Virtual Machine's
+     * constants for {@code public}, {@code protected},
+     * {@code private}, {@code final}, {@code static},
+     * {@code abstract} and {@code interface}; they should be decoded
+     * using the methods of class {@code Modifier}.
+     *
+     * <p> If the underlying class is an array class, then its
+     * {@code public}, {@code private} and {@code protected}
+     * modifiers are the same as those of its component type.  If this
+     * {@code Class} represents a primitive type or void, its
+     * {@code public} modifier is always {@code true}, and its
+     * {@code protected} and {@code private} modifiers are always
+     * {@code false}. If this object represents an array class, a
+     * primitive type or void, then its {@code final} modifier is always
+     * {@code true} and its interface modifier is always
+     * {@code false}. The values of its other modifiers are not determined
+     * by this specification.
+     *
+     * <p> The modifier encodings are defined in <em>The Java Virtual Machine
+     * Specification</em>, table 4.1.
+     *
+     * @return the {@code int} representing the modifiers for this class
+     * @see     java.lang.reflect.Modifier
+     * @since JDK1.1
+     */
+    public int getModifiers() {
+        // Array classes inherit modifiers from their component types, but in the case of arrays
+        // of an inner class, the class file may contain "fake" access flags because it's not valid
+        // for a top-level class to private, say. The real access flags are stored in the InnerClass
+        // attribute, so we need to make sure we drill down to the inner class: the accessFlags
+        // field is not the value we want to return, and the synthesized array class does not itself
+        // have an InnerClass attribute. https://code.google.com/p/android/issues/detail?id=56267
+        if (isArray()) {
+            int componentModifiers = getComponentType().getModifiers();
+            if ((componentModifiers & Modifier.INTERFACE) != 0) {
+                componentModifiers &= ~(Modifier.INTERFACE | Modifier.STATIC);
+            }
+            return Modifier.ABSTRACT | Modifier.FINAL | componentModifiers;
+        }
+        int JAVA_FLAGS_MASK = 0xffff;
+        int modifiers = this.getInnerClassFlags(accessFlags & JAVA_FLAGS_MASK);
+        return modifiers & JAVA_FLAGS_MASK;
+    }
+
+    /**
+     * Gets the signers of this class.
+     *
+     * @return  the signers of this class, or null if there are no signers.  In
+     *          particular, this method returns null if this object represents
+     *          a primitive type or void.
+     * @since   JDK1.1
+     */
+    public Object[] getSigners() {
+        return null;
+    }
+
+    @FastNative
+    private native Method getEnclosingMethodNative();
+
+    /**
+     * If this {@code Class} object represents a local or anonymous
+     * class within a method, returns a {@link
+     * java.lang.reflect.Method Method} object representing the
+     * immediately enclosing method of the underlying class. Returns
+     * {@code null} otherwise.
+     *
+     * In particular, this method returns {@code null} if the underlying
+     * class is a local or anonymous class immediately enclosed by a type
+     * declaration, instance initializer or static initializer.
+     *
+     * @return the immediately enclosing method of the underlying class, if
+     *     that class is a local or anonymous class; otherwise {@code null}.
+     * @since 1.5
+     */
+    // Android-changed: Removed SecurityException
+    public Method getEnclosingMethod() {
+        if (classNameImpliesTopLevel()) {
+            return null;
+        }
+        return getEnclosingMethodNative();
+    }
+
+    /**
+     * If this {@code Class} object represents a local or anonymous
+     * class within a constructor, returns a {@link
+     * java.lang.reflect.Constructor Constructor} object representing
+     * the immediately enclosing constructor of the underlying
+     * class. Returns {@code null} otherwise.  In particular, this
+     * method returns {@code null} if the underlying class is a local
+     * or anonymous class immediately enclosed by a type declaration,
+     * instance initializer or static initializer.
+     *
+     * @return the immediately enclosing constructor of the underlying class, if
+     *     that class is a local or anonymous class; otherwise {@code null}.
+     * @since 1.5
+     */
+    // Android-changed: Removed SecurityException
+    public Constructor<?> getEnclosingConstructor() {
+        if (classNameImpliesTopLevel()) {
+            return null;
+        }
+        return getEnclosingConstructorNative();
+    }
+
+    @FastNative
+    private native Constructor<?> getEnclosingConstructorNative();
+
+    private boolean classNameImpliesTopLevel() {
+        return !getName().contains("$");
+    }
+
+
+    /**
+     * If the class or interface represented by this {@code Class} object
+     * is a member of another class, returns the {@code Class} object
+     * representing the class in which it was declared.  This method returns
+     * null if this class or interface is not a member of any other class.  If
+     * this {@code Class} object represents an array class, a primitive
+     * type, or void,then this method returns null.
+     *
+     * @return the declaring class for this class
+     * @since JDK1.1
+     */
+    // Android-changed: Removed SecurityException
+    @FastNative
+    public native Class<?> getDeclaringClass();
+
+    /**
+     * Returns the immediately enclosing class of the underlying
+     * class.  If the underlying class is a top level class this
+     * method returns {@code null}.
+     * @return the immediately enclosing class of the underlying class
+     * @since 1.5
+     */
+    // Android-changed: Removed SecurityException
+    @FastNative
+    public native Class<?> getEnclosingClass();
+
+    /**
+     * Returns the simple name of the underlying class as given in the
+     * source code. Returns an empty string if the underlying class is
+     * anonymous.
+     *
+     * <p>The simple name of an array is the simple name of the
+     * component type with "[]" appended.  In particular the simple
+     * name of an array whose component type is anonymous is "[]".
+     *
+     * @return the simple name of the underlying class
+     * @since 1.5
+     */
+    public String getSimpleName() {
+        if (isArray())
+            return getComponentType().getSimpleName()+"[]";
+
+        if (isAnonymousClass()) {
+            return "";
+        }
+
+        if (isMemberClass() || isLocalClass()) {
+            // Note that we obtain this information from getInnerClassName(), which uses
+            // dex system annotations to obtain the name. It is possible for this information
+            // to disagree with the actual enclosing class name. For example, if dex
+            // manipulation tools have renamed the enclosing class without adjusting
+            // the system annotation to match. See http://b/28800927.
+            return getInnerClassName();
+        }
+
+        String simpleName = getName();
+        final int dot = simpleName.lastIndexOf(".");
+        if (dot > 0) {
+            return simpleName.substring(simpleName.lastIndexOf(".")+1); // strip the package name
+        }
+
+        return simpleName;
+    }
+
+    /**
+     * Return an informative string for the name of this type.
+     *
+     * @return an informative string for the name of this type
+     * @since 1.8
+     */
+    public String getTypeName() {
+        if (isArray()) {
+            try {
+                Class<?> cl = this;
+                int dimensions = 0;
+                while (cl.isArray()) {
+                    dimensions++;
+                    cl = cl.getComponentType();
+                }
+                StringBuilder sb = new StringBuilder();
+                sb.append(cl.getName());
+                for (int i = 0; i < dimensions; i++) {
+                    sb.append("[]");
+                }
+                return sb.toString();
+            } catch (Throwable e) { /*FALLTHRU*/ }
+        }
+        return getName();
+    }
+
+    /**
+     * Returns the canonical name of the underlying class as
+     * defined by the Java Language Specification.  Returns null if
+     * the underlying class does not have a canonical name (i.e., if
+     * it is a local or anonymous class or an array whose component
+     * type does not have a canonical name).
+     * @return the canonical name of the underlying class if it exists, and
+     * {@code null} otherwise.
+     * @since 1.5
+     */
+    public String getCanonicalName() {
+        if (isArray()) {
+            String canonicalName = getComponentType().getCanonicalName();
+            if (canonicalName != null)
+                return canonicalName + "[]";
+            else
+                return null;
+        }
+        if (isLocalOrAnonymousClass())
+            return null;
+        Class<?> enclosingClass = getEnclosingClass();
+        if (enclosingClass == null) { // top level class
+            return getName();
+        } else {
+            String enclosingName = enclosingClass.getCanonicalName();
+            if (enclosingName == null)
+                return null;
+            return enclosingName + "." + getSimpleName();
+        }
+    }
+
+    /**
+     * Returns {@code true} if and only if the underlying class
+     * is an anonymous class.
+     *
+     * @return {@code true} if and only if this class is an anonymous class.
+     * @since 1.5
+     */
+    @FastNative
+    public native boolean isAnonymousClass();
+
+    /**
+     * Returns {@code true} if and only if the underlying class
+     * is a local class.
+     *
+     * @return {@code true} if and only if this class is a local class.
+     * @since 1.5
+     */
+    public boolean isLocalClass() {
+        return (getEnclosingMethod() != null || getEnclosingConstructor() != null)
+                && !isAnonymousClass();
+    }
+
+    /**
+     * Returns {@code true} if and only if the underlying class
+     * is a member class.
+     *
+     * @return {@code true} if and only if this class is a member class.
+     * @since 1.5
+     */
+    public boolean isMemberClass() {
+        return getDeclaringClass() != null;
+    }
+
+    /**
+     * Returns {@code true} if this is a local class or an anonymous
+     * class.  Returns {@code false} otherwise.
+     */
+    private boolean isLocalOrAnonymousClass() {
+        // JVM Spec 4.8.6: A class must have an EnclosingMethod
+        // attribute if and only if it is a local class or an
+        // anonymous class.
+        return isLocalClass() || isAnonymousClass();
+    }
+
+    /**
+     * Returns an array containing {@code Class} objects representing all
+     * the public classes and interfaces that are members of the class
+     * represented by this {@code Class} object.  This includes public
+     * class and interface members inherited from superclasses and public class
+     * and interface members declared by the class.  This method returns an
+     * array of length 0 if this {@code Class} object has no public member
+     * classes or interfaces.  This method also returns an array of length 0 if
+     * this {@code Class} object represents a primitive type, an array
+     * class, or void.
+     *
+     * @return the array of {@code Class} objects representing the public
+     *         members of this class
+     *
+     * @since JDK1.1
+     */
+    @CallerSensitive
+    public Class<?>[] getClasses() {
+        List<Class<?>> result = new ArrayList<Class<?>>();
+        for (Class<?> c = this; c != null; c = c.superClass) {
+            for (Class<?> member : c.getDeclaredClasses()) {
+                if (Modifier.isPublic(member.getModifiers())) {
+                    result.add(member);
+                }
+            }
+        }
+        return result.toArray(new Class[result.size()]);
+    }
+
+
+    /**
+     * Returns an array containing {@code Field} objects reflecting all
+     * the accessible public fields of the class or interface represented by
+     * this {@code Class} object.
+     *
+     * <p> If this {@code Class} object represents a class or interface with no
+     * no accessible public fields, then this method returns an array of length
+     * 0.
+     *
+     * <p> If this {@code Class} object represents a class, then this method
+     * returns the public fields of the class and of all its superclasses.
+     *
+     * <p> If this {@code Class} object represents an interface, then this
+     * method returns the fields of the interface and of all its
+     * superinterfaces.
+     *
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then this method returns an array of length 0.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
+     *
+     * @return the array of {@code Field} objects representing the
+     *         public fields
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and
+     *         the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class.
+     *
+     * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
+     */
+    @CallerSensitive
+    public Field[] getFields() throws SecurityException {
+        List<Field> fields = new ArrayList<Field>();
+        getPublicFieldsRecursive(fields);
+        return fields.toArray(new Field[fields.size()]);
+    }
+
+    /**
+     * Populates {@code result} with public fields defined by this class, its
+     * superclasses, and all implemented interfaces.
+     */
+    private void getPublicFieldsRecursive(List<Field> result) {
+        // search superclasses
+        for (Class<?> c = this; c != null; c = c.superClass) {
+            Collections.addAll(result, c.getPublicDeclaredFields());
+        }
+
+        // search iftable which has a flattened and uniqued list of interfaces
+        Object[] iftable = ifTable;
+        if (iftable != null) {
+            for (int i = 0; i < iftable.length; i += 2) {
+                Collections.addAll(result, ((Class<?>) iftable[i]).getPublicDeclaredFields());
+            }
+        }
+    }
+
+    /**
+     * Returns an array containing {@code Method} objects reflecting all the
+     * public methods of the class or interface represented by this {@code
+     * Class} object, including those declared by the class or interface and
+     * those inherited from superclasses and superinterfaces.
+     *
+     * <p> If this {@code Class} object represents a type that has multiple
+     * public methods with the same name and parameter types, but different
+     * return types, then the returned array has a {@code Method} object for
+     * each such method.
+     *
+     * <p> If this {@code Class} object represents a type with a class
+     * initialization method {@code <clinit>}, then the returned array does
+     * <em>not</em> have a corresponding {@code Method} object.
+     *
+     * <p> If this {@code Class} object represents an array type, then the
+     * returned array has a {@code Method} object for each of the public
+     * methods inherited by the array type from {@code Object}. It does not
+     * contain a {@code Method} object for {@code clone()}.
+     *
+     * <p> If this {@code Class} object represents an interface then the
+     * returned array does not contain any implicitly declared methods from
+     * {@code Object}. Therefore, if no methods are explicitly declared in
+     * this interface or any of its superinterfaces then the returned array
+     * has length 0. (Note that a {@code Class} object which represents a class
+     * always has public methods, inherited from {@code Object}.)
+     *
+     * <p> If this {@code Class} object represents a primitive type or void,
+     * then the returned array has length 0.
+     *
+     * <p> Static methods declared in superinterfaces of the class or interface
+     * represented by this {@code Class} object are not considered members of
+     * the class or interface.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
+     *
+     * @return the array of {@code Method} objects representing the
+     *         public methods of this class
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and
+     *         the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class.
+     *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
+     * @since JDK1.1
+     */
+    @CallerSensitive
+    public Method[] getMethods() throws SecurityException {
+        List<Method> methods = new ArrayList<Method>();
+        getPublicMethodsInternal(methods);
+        /*
+         * Remove duplicate methods defined by superclasses and
+         * interfaces, preferring to keep methods declared by derived
+         * types.
+         */
+        CollectionUtils.removeDuplicates(methods, Method.ORDER_BY_SIGNATURE);
+        return methods.toArray(new Method[methods.size()]);
+    }
+
+    /**
+     * Populates {@code result} with public methods defined by this class, its
+     * superclasses, and all implemented interfaces, including overridden methods.
+     */
+    private void getPublicMethodsInternal(List<Method> result) {
+        Collections.addAll(result, getDeclaredMethodsUnchecked(true));
+        if (!isInterface()) {
+            // Search superclasses, for interfaces don't search java.lang.Object.
+            for (Class<?> c = superClass; c != null; c = c.superClass) {
+                Collections.addAll(result, c.getDeclaredMethodsUnchecked(true));
+            }
+        }
+        // Search iftable which has a flattened and uniqued list of interfaces.
+        Object[] iftable = ifTable;
+        if (iftable != null) {
+            for (int i = 0; i < iftable.length; i += 2) {
+                Class<?> ifc = (Class<?>) iftable[i];
+                Collections.addAll(result, ifc.getDeclaredMethodsUnchecked(true));
+            }
+        }
+    }
+
+    /**
+     * Returns an array containing {@code Constructor} objects reflecting
+     * all the public constructors of the class represented by this
+     * {@code Class} object.  An array of length 0 is returned if the
+     * class has no public constructors, or if the class is an array class, or
+     * if the class reflects a primitive type or void.
+     *
+     * Note that while this method returns an array of {@code
+     * Constructor<T>} objects (that is an array of constructors from
+     * this class), the return type of this method is {@code
+     * Constructor<?>[]} and <em>not</em> {@code Constructor<T>[]} as
+     * might be expected.  This less informative return type is
+     * necessary since after being returned from this method, the
+     * array could be modified to hold {@code Constructor} objects for
+     * different classes, which would violate the type guarantees of
+     * {@code Constructor<T>[]}.
+     *
+     * @return the array of {@code Constructor} objects representing the
+     *         public constructors of this class
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and
+     *         the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class.
+     *
+     * @since JDK1.1
+     */
+    @CallerSensitive
+    public Constructor<?>[] getConstructors() throws SecurityException {
+        return getDeclaredConstructorsInternal(true);
+    }
+
+
+    /**
+     * Returns a {@code Field} object that reflects the specified public member
+     * field of the class or interface represented by this {@code Class}
+     * object. The {@code name} parameter is a {@code String} specifying the
+     * simple name of the desired field.
+     *
+     * <p> The field to be reflected is determined by the algorithm that
+     * follows.  Let C be the class or interface represented by this object:
+     *
+     * <OL>
+     * <LI> If C declares a public field with the name specified, that is the
+     *      field to be reflected.</LI>
+     * <LI> If no field was found in step 1 above, this algorithm is applied
+     *      recursively to each direct superinterface of C. The direct
+     *      superinterfaces are searched in the order they were declared.</LI>
+     * <LI> If no field was found in steps 1 and 2 above, and C has a
+     *      superclass S, then this algorithm is invoked recursively upon S.
+     *      If C has no superclass, then a {@code NoSuchFieldException}
+     *      is thrown.</LI>
+     * </OL>
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code length} field of the array type.
+     *
+     * @param name the field name
+     * @return the {@code Field} object of this class specified by
+     *         {@code name}
+     * @throws NoSuchFieldException if a field with the specified name is
+     *         not found.
+     * @throws NullPointerException if {@code name} is {@code null}
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and
+     *         the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class.
+     *
+     * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
+     */
+    // Android-changed: Removed SecurityException
+    public Field getField(String name)
+        throws NoSuchFieldException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        Field result = getPublicFieldRecursive(name);
+        if (result == null) {
+            throw new NoSuchFieldException(name);
+        }
+        return result;
+    }
+
+    /**
+     * The native implementation of the {@code getField} method.
+     *
+     * @throws NullPointerException
+     *            if name is null.
+     * @see #getField(String)
+     */
+    @FastNative
+    private native Field getPublicFieldRecursive(String name);
+
+    /**
+     * Returns a {@code Method} object that reflects the specified public
+     * member method of the class or interface represented by this
+     * {@code Class} object. The {@code name} parameter is a
+     * {@code String} specifying the simple name of the desired method. The
+     * {@code parameterTypes} parameter is an array of {@code Class}
+     * objects that identify the method's formal parameter types, in declared
+     * order. If {@code parameterTypes} is {@code null}, it is
+     * treated as if it were an empty array.
+     *
+     * <p> If the {@code name} is "{@code <init>}" or "{@code <clinit>}" a
+     * {@code NoSuchMethodException} is raised. Otherwise, the method to
+     * be reflected is determined by the algorithm that follows.  Let C be the
+     * class or interface represented by this object:
+     * <OL>
+     * <LI> C is searched for a <I>matching method</I>, as defined below. If a
+     *      matching method is found, it is reflected.</LI>
+     * <LI> If no matching method is found by step 1 then:
+     *   <OL TYPE="a">
+     *   <LI> If C is a class other than {@code Object}, then this algorithm is
+     *        invoked recursively on the superclass of C.</LI>
+     *   <LI> If C is the class {@code Object}, or if C is an interface, then
+     *        the superinterfaces of C (if any) are searched for a matching
+     *        method. If any such method is found, it is reflected.</LI>
+     *   </OL></LI>
+     * </OL>
+     *
+     * <p> To find a matching method in a class or interface C:&nbsp; If C
+     * declares exactly one public method with the specified name and exactly
+     * the same formal parameter types, that is the method reflected. If more
+     * than one such method is found in C, and one of these methods has a
+     * return type that is more specific than any of the others, that method is
+     * reflected; otherwise one of the methods is chosen arbitrarily.
+     *
+     * <p>Note that there may be more than one matching method in a
+     * class because while the Java language forbids a class to
+     * declare multiple methods with the same signature but different
+     * return types, the Java virtual machine does not.  This
+     * increased flexibility in the virtual machine can be used to
+     * implement various language features.  For example, covariant
+     * returns can be implemented with {@linkplain
+     * java.lang.reflect.Method#isBridge bridge methods}; the bridge
+     * method and the method being overridden would have the same
+     * signature but different return types.
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code clone()} method.
+     *
+     * <p> Static methods declared in superinterfaces of the class or interface
+     * represented by this {@code Class} object are not considered members of
+     * the class or interface.
+     *
+     * @param name the name of the method
+     * @param parameterTypes the list of parameters
+     * @return the {@code Method} object that matches the specified
+     *         {@code name} and {@code parameterTypes}
+     * @throws NoSuchMethodException if a matching method is not found
+     *         or if the name is "&lt;init&gt;"or "&lt;clinit&gt;".
+     * @throws NullPointerException if {@code name} is {@code null}
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and
+     *         the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class.
+     *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
+     * @since JDK1.1
+     */
+    @CallerSensitive
+    public Method getMethod(String name, Class<?>... parameterTypes)
+        throws NoSuchMethodException, SecurityException {
+        return getMethod(name, parameterTypes, true);
+    }
+
+
+    /**
+     * Returns a {@code Constructor} object that reflects the specified
+     * public constructor of the class represented by this {@code Class}
+     * object. The {@code parameterTypes} parameter is an array of
+     * {@code Class} objects that identify the constructor's formal
+     * parameter types, in declared order.
+     *
+     * If this {@code Class} object represents an inner class
+     * declared in a non-static context, the formal parameter types
+     * include the explicit enclosing instance as the first parameter.
+     *
+     * <p> The constructor to reflect is the public constructor of the class
+     * represented by this {@code Class} object whose formal parameter
+     * types match those specified by {@code parameterTypes}.
+     *
+     * @param parameterTypes the parameter array
+     * @return the {@code Constructor} object of the public constructor that
+     *         matches the specified {@code parameterTypes}
+     * @throws NoSuchMethodException if a matching method is not found.
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and
+     *         the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class.
+     *
+     * @since JDK1.1
+     */
+    public Constructor<T> getConstructor(Class<?>... parameterTypes)
+        throws NoSuchMethodException, SecurityException {
+        return getConstructor0(parameterTypes, Member.PUBLIC);
+    }
+
+
+    /**
+     * Returns an array of {@code Class} objects reflecting all the
+     * classes and interfaces declared as members of the class represented by
+     * this {@code Class} object. This includes public, protected, default
+     * (package) access, and private classes and interfaces declared by the
+     * class, but excludes inherited classes and interfaces.  This method
+     * returns an array of length 0 if the class declares no classes or
+     * interfaces as members, or if this {@code Class} object represents a
+     * primitive type, an array class, or void.
+     *
+     * @return the array of {@code Class} objects representing all the
+     *         declared members of this class
+     * @throws SecurityException
+     *         If a security manager, <i>s</i>, is present and any of the
+     *         following conditions is met:
+     *
+     *         <ul>
+     *
+     *         <li> the caller's class loader is not the same as the
+     *         class loader of this class and invocation of
+     *         {@link SecurityManager#checkPermission
+     *         s.checkPermission} method with
+     *         {@code RuntimePermission("accessDeclaredMembers")}
+     *         denies access to the declared classes within this class
+     *
+     *         <li> the caller's class loader is not the same as or an
+     *         ancestor of the class loader for the current class and
+     *         invocation of {@link SecurityManager#checkPackageAccess
+     *         s.checkPackageAccess()} denies access to the package
+     *         of this class
+     *
+     *         </ul>
+     *
+     * @since JDK1.1
+     */
+    // Android-changed: Removed SecurityException
+    @FastNative
+    public native Class<?>[] getDeclaredClasses();
+
+    /**
+     * Returns an array of {@code Field} objects reflecting all the fields
+     * declared by the class or interface represented by this
+     * {@code Class} object. This includes public, protected, default
+     * (package) access, and private fields, but excludes inherited fields.
+     *
+     * <p> If this {@code Class} object represents a class or interface with no
+     * declared fields, then this method returns an array of length 0.
+     *
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then this method returns an array of length 0.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
+     *
+     * @return  the array of {@code Field} objects representing all the
+     *          declared fields of this class
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared fields within this class
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
+     */
+    // Android-changed: Removed SecurityException
+    @FastNative
+    public native Field[] getDeclaredFields();
+
+    /**
+     * Populates a list of fields without performing any security or type
+     * resolution checks first. If no fields exist, the list is not modified.
+     *
+     * @param publicOnly Whether to return only public fields.
+     * @hide
+     */
+    @FastNative
+    public native Field[] getDeclaredFieldsUnchecked(boolean publicOnly);
+
+    /**
+     *
+     * Returns an array containing {@code Method} objects reflecting all the
+     * declared methods of the class or interface represented by this {@code
+     * Class} object, including public, protected, default (package)
+     * access, and private methods, but excluding inherited methods.
+     *
+     * <p> If this {@code Class} object represents a type that has multiple
+     * declared methods with the same name and parameter types, but different
+     * return types, then the returned array has a {@code Method} object for
+     * each such method.
+     *
+     * <p> If this {@code Class} object represents a type that has a class
+     * initialization method {@code <clinit>}, then the returned array does
+     * <em>not</em> have a corresponding {@code Method} object.
+     *
+     * <p> If this {@code Class} object represents a class or interface with no
+     * declared methods, then the returned array has length 0.
+     *
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then the returned array has length 0.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
+     *
+     * @return  the array of {@code Method} objects representing all the
+     *          declared methods of this class
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared methods within this class
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
+     * @since JDK1.1
+     */
+    public Method[] getDeclaredMethods() throws SecurityException {
+        Method[] result = getDeclaredMethodsUnchecked(false);
+        for (Method m : result) {
+            // Throw NoClassDefFoundError if types cannot be resolved.
+            m.getReturnType();
+            m.getParameterTypes();
+        }
+        return result;
+    }
+
+    /**
+     * Populates a list of methods without performing any security or type
+     * resolution checks first. If no methods exist, the list is not modified.
+     *
+     * @param publicOnly Whether to return only public methods.
+     * @hide
+     */
+    @FastNative
+    public native Method[] getDeclaredMethodsUnchecked(boolean publicOnly);
+
+    /**
+     * Returns an array of {@code Constructor} objects reflecting all the
+     * constructors declared by the class represented by this
+     * {@code Class} object. These are public, protected, default
+     * (package) access, and private constructors.  The elements in the array
+     * returned are not sorted and are not in any particular order.  If the
+     * class has a default constructor, it is included in the returned array.
+     * This method returns an array of length 0 if this {@code Class}
+     * object represents an interface, a primitive type, an array class, or
+     * void.
+     *
+     * <p> See <em>The Java Language Specification</em>, section 8.2.
+     *
+     * @return  the array of {@code Constructor} objects representing all the
+     *          declared constructors of this class
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared constructors within this class
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @since JDK1.1
+     */
+    public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
+        return getDeclaredConstructorsInternal(false);
+    }
+
+
+    /**
+     * Returns the constructor with the given parameters if it is defined by this class;
+     * {@code null} otherwise. This may return a non-public member.
+     */
+    @FastNative
+    private native Constructor<?>[] getDeclaredConstructorsInternal(boolean publicOnly);
+
+    /**
+     * Returns a {@code Field} object that reflects the specified declared
+     * field of the class or interface represented by this {@code Class}
+     * object. The {@code name} parameter is a {@code String} that specifies
+     * the simple name of the desired field.
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code length} field of the array type.
+     *
+     * @param name the name of the field
+     * @return  the {@code Field} object for the specified field in this
+     *          class
+     * @throws  NoSuchFieldException if a field with the specified name is
+     *          not found.
+     * @throws  NullPointerException if {@code name} is {@code null}
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared field
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
+     */
+    // Android-changed: Removed SecurityException
+    @FastNative
+    public native Field getDeclaredField(String name) throws NoSuchFieldException;
+
+    /**
+     * Returns the subset of getDeclaredFields which are public.
+     */
+    @FastNative
+    private native Field[] getPublicDeclaredFields();
+
+    /**
+     * Returns a {@code Method} object that reflects the specified
+     * declared method of the class or interface represented by this
+     * {@code Class} object. The {@code name} parameter is a
+     * {@code String} that specifies the simple name of the desired
+     * method, and the {@code parameterTypes} parameter is an array of
+     * {@code Class} objects that identify the method's formal parameter
+     * types, in declared order.  If more than one method with the same
+     * parameter types is declared in a class, and one of these methods has a
+     * return type that is more specific than any of the others, that method is
+     * returned; otherwise one of the methods is chosen arbitrarily.  If the
+     * name is "&lt;init&gt;"or "&lt;clinit&gt;" a {@code NoSuchMethodException}
+     * is raised.
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code clone()} method.
+     *
+     * @param name the name of the method
+     * @param parameterTypes the parameter array
+     * @return  the {@code Method} object for the method of this class
+     *          matching the specified name and parameters
+     * @throws  NoSuchMethodException if a matching method is not found.
+     * @throws  NullPointerException if {@code name} is {@code null}
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared method
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
+     * @since JDK1.1
+     */
+    @CallerSensitive
+    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
+        throws NoSuchMethodException, SecurityException {
+        return getMethod(name, parameterTypes, false);
+    }
+
+    private Method getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods)
+            throws NoSuchMethodException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        if (parameterTypes == null) {
+            parameterTypes = EmptyArray.CLASS;
+        }
+        for (Class<?> c : parameterTypes) {
+            if (c == null) {
+                throw new NoSuchMethodException("parameter type is null");
+            }
+        }
+        Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes)
+                                               : getDeclaredMethodInternal(name, parameterTypes);
+        // Fail if we didn't find the method or it was expected to be public.
+        if (result == null ||
+            (recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) {
+            throw new NoSuchMethodException(getName() + "." + name + " "
+                    + Arrays.toString(parameterTypes));
+        }
+        return result;
+    }
+    private Method getPublicMethodRecursive(String name, Class<?>[] parameterTypes) {
+        // search superclasses
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            Method result = c.getDeclaredMethodInternal(name, parameterTypes);
+            if (result != null && Modifier.isPublic(result.getAccessFlags())) {
+                return result;
+            }
+        }
+
+        return findInterfaceMethod(name, parameterTypes);
+    }
+
+    /**
+     * Returns an instance method that's defined on this class or any super classes, regardless
+     * of its access flags. Constructors are excluded.
+     *
+     * This function does not perform access checks and its semantics don't match any dex byte code
+     * instruction or public reflection API. This is used by {@code MethodHandles.findVirtual}
+     * which will perform access checks on the returned method.
+     *
+     * @hide
+     */
+    public Method getInstanceMethod(String name, Class<?>[] parameterTypes)
+            throws NoSuchMethodException, IllegalAccessException {
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            Method result = c.getDeclaredMethodInternal(name, parameterTypes);
+            if (result != null && !Modifier.isStatic(result.getModifiers())) {
+                return result;
+            }
+        }
+
+        return findInterfaceMethod(name, parameterTypes);
+    }
+
+    private Method findInterfaceMethod(String name, Class<?>[] parameterTypes) {
+        Object[] iftable = ifTable;
+        if (iftable != null) {
+            // Search backwards so more specific interfaces are searched first. This ensures that
+            // the method we return is not overridden by one of it's subtypes that this class also
+            // implements.
+            for (int i = iftable.length - 2; i >= 0; i -= 2) {
+                Class<?> ifc = (Class<?>) iftable[i];
+                Method result = ifc.getPublicMethodRecursive(name, parameterTypes);
+                if (result != null && Modifier.isPublic(result.getAccessFlags())) {
+                    return result;
+                }
+            }
+        }
+
+        return null;
+    }
+
+
+    /**
+     * Returns a {@code Constructor} object that reflects the specified
+     * constructor of the class or interface represented by this
+     * {@code Class} object.  The {@code parameterTypes} parameter is
+     * an array of {@code Class} objects that identify the constructor's
+     * formal parameter types, in declared order.
+     *
+     * If this {@code Class} object represents an inner class
+     * declared in a non-static context, the formal parameter types
+     * include the explicit enclosing instance as the first parameter.
+     *
+     * @param parameterTypes the parameter array
+     * @return  The {@code Constructor} object for the constructor with the
+     *          specified parameter list
+     * @throws  NoSuchMethodException if a matching method is not found.
+     * @throws  SecurityException
+     *          If a security manager, <i>s</i>, is present and any of the
+     *          following conditions is met:
+     *
+     *          <ul>
+     *
+     *          <li> the caller's class loader is not the same as the
+     *          class loader of this class and invocation of
+     *          {@link SecurityManager#checkPermission
+     *          s.checkPermission} method with
+     *          {@code RuntimePermission("accessDeclaredMembers")}
+     *          denies access to the declared constructor
+     *
+     *          <li> the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the current class and
+     *          invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the package
+     *          of this class
+     *
+     *          </ul>
+     *
+     * @since JDK1.1
+     */
+    @CallerSensitive
+    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
+        throws NoSuchMethodException, SecurityException {
+        return getConstructor0(parameterTypes, Member.DECLARED);
+    }
+
+    /**
+     * Finds a resource with a given name.  The rules for searching resources
+     * associated with a given class are implemented by the defining
+     * {@linkplain ClassLoader class loader} of the class.  This method
+     * delegates to this object's class loader.  If this object was loaded by
+     * the bootstrap class loader, the method delegates to {@link
+     * ClassLoader#getSystemResourceAsStream}.
+     *
+     * <p> Before delegation, an absolute resource name is constructed from the
+     * given resource name using this algorithm:
+     *
+     * <ul>
+     *
+     * <li> If the {@code name} begins with a {@code '/'}
+     * (<tt>'&#92;u002f'</tt>), then the absolute name of the resource is the
+     * portion of the {@code name} following the {@code '/'}.
+     *
+     * <li> Otherwise, the absolute name is of the following form:
+     *
+     * <blockquote>
+     *   {@code modified_package_name/name}
+     * </blockquote>
+     *
+     * <p> Where the {@code modified_package_name} is the package name of this
+     * object with {@code '/'} substituted for {@code '.'}
+     * (<tt>'&#92;u002e'</tt>).
+     *
+     * </ul>
+     *
+     * @param  name name of the desired resource
+     * @return      A {@link java.io.InputStream} object or {@code null} if
+     *              no resource with this name is found
+     * @throws  NullPointerException If {@code name} is {@code null}
+     * @since  JDK1.1
+     */
+     public InputStream getResourceAsStream(String name) {
+        name = resolveName(name);
+        ClassLoader cl = getClassLoader();
+        if (cl==null) {
+            // A system class.
+            return ClassLoader.getSystemResourceAsStream(name);
+        }
+        return cl.getResourceAsStream(name);
+    }
+
+    /**
+     * Finds a resource with a given name.  The rules for searching resources
+     * associated with a given class are implemented by the defining
+     * {@linkplain ClassLoader class loader} of the class.  This method
+     * delegates to this object's class loader.  If this object was loaded by
+     * the bootstrap class loader, the method delegates to {@link
+     * ClassLoader#getSystemResource}.
+     *
+     * <p> Before delegation, an absolute resource name is constructed from the
+     * given resource name using this algorithm:
+     *
+     * <ul>
+     *
+     * <li> If the {@code name} begins with a {@code '/'}
+     * (<tt>'&#92;u002f'</tt>), then the absolute name of the resource is the
+     * portion of the {@code name} following the {@code '/'}.
+     *
+     * <li> Otherwise, the absolute name is of the following form:
+     *
+     * <blockquote>
+     *   {@code modified_package_name/name}
+     * </blockquote>
+     *
+     * <p> Where the {@code modified_package_name} is the package name of this
+     * object with {@code '/'} substituted for {@code '.'}
+     * (<tt>'&#92;u002e'</tt>).
+     *
+     * </ul>
+     *
+     * @param  name name of the desired resource
+     * @return      A  {@link java.net.URL} object or {@code null} if no
+     *              resource with this name is found
+     * @since  JDK1.1
+     */
+    public java.net.URL getResource(String name) {
+        name = resolveName(name);
+        ClassLoader cl = getClassLoader();
+        if (cl==null) {
+            // A system class.
+            return ClassLoader.getSystemResource(name);
+        }
+        return cl.getResource(name);
+    }
+
+    /**
+     * Returns the {@code ProtectionDomain} of this class.  If there is a
+     * security manager installed, this method first calls the security
+     * manager's {@code checkPermission} method with a
+     * {@code RuntimePermission("getProtectionDomain")} permission to
+     * ensure it's ok to get the
+     * {@code ProtectionDomain}.
+     *
+     * @return the ProtectionDomain of this class
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        getting the ProtectionDomain.
+     *
+     * @see java.security.ProtectionDomain
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     * @since 1.2
+     */
+    public java.security.ProtectionDomain getProtectionDomain() {
+        return null;
+    }
+
+    /*
+     * Return the runtime's Class object for the named
+     * primitive type.
+     */
+    @FastNative
+    static native Class<?> getPrimitiveClass(String name);
+
+    /**
+     * Add a package name prefix if the name is not absolute Remove leading "/"
+     * if name is absolute
+     */
+    private String resolveName(String name) {
+        if (name == null) {
+            return name;
+        }
+        if (!name.startsWith("/")) {
+            Class<?> c = this;
+            while (c.isArray()) {
+                c = c.getComponentType();
+            }
+            String baseName = c.getName();
+            int index = baseName.lastIndexOf('.');
+            if (index != -1) {
+                name = baseName.substring(0, index).replace('.', '/')
+                    +"/"+name;
+            }
+        } else {
+            name = name.substring(1);
+        }
+        return name;
+    }
+
+    private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
+                                        int which) throws NoSuchMethodException
+    {
+        if (parameterTypes == null) {
+            parameterTypes = EmptyArray.CLASS;
+        }
+        for (Class<?> c : parameterTypes) {
+            if (c == null) {
+                throw new NoSuchMethodException("parameter type is null");
+            }
+        }
+        Constructor<T> result = getDeclaredConstructorInternal(parameterTypes);
+        if (result == null || which == Member.PUBLIC && !Modifier.isPublic(result.getAccessFlags())) {
+            throw new NoSuchMethodException(getName() + ".<init> "
+                    + Arrays.toString(parameterTypes));
+        }
+        return result;
+    }
+
+    /** use serialVersionUID from JDK 1.1 for interoperability */
+    private static final long serialVersionUID = 3206093459760846163L;
+
+
+    /**
+     * Returns the constructor with the given parameters if it is defined by this class;
+     * {@code null} otherwise. This may return a non-public member.
+     *
+     * @param args the types of the parameters to the constructor.
+     */
+    @FastNative
+    private native Constructor<T> getDeclaredConstructorInternal(Class<?>[] args);
+
+    /**
+     * Returns the assertion status that would be assigned to this
+     * class if it were to be initialized at the time this method is invoked.
+     * If this class has had its assertion status set, the most recent
+     * setting will be returned; otherwise, if any package default assertion
+     * status pertains to this class, the most recent setting for the most
+     * specific pertinent package default assertion status is returned;
+     * otherwise, if this class is not a system class (i.e., it has a
+     * class loader) its class loader's default assertion status is returned;
+     * otherwise, the system class default assertion status is returned.
+     * <p>
+     * Few programmers will have any need for this method; it is provided
+     * for the benefit of the JRE itself.  (It allows a class to determine at
+     * the time that it is initialized whether assertions should be enabled.)
+     * Note that this method is not guaranteed to return the actual
+     * assertion status that was (or will be) associated with the specified
+     * class when it was (or will be) initialized.
+     *
+     * @return the desired assertion status of the specified class.
+     * @see    java.lang.ClassLoader#setClassAssertionStatus
+     * @see    java.lang.ClassLoader#setPackageAssertionStatus
+     * @see    java.lang.ClassLoader#setDefaultAssertionStatus
+     * @since  1.4
+     */
+    public boolean desiredAssertionStatus() {
+        return false;
+    }
+
+    /**
+     * Returns the simple name of a member or local class, or {@code null} otherwise.
+     */
+    @FastNative
+    private native String getInnerClassName();
+
+    @FastNative
+    private native int getInnerClassFlags(int defaultValue);
+
+    /**
+     * Returns true if and only if this class was declared as an enum in the
+     * source code.
+     *
+     * @return true if and only if this class was declared as an enum in the
+     *     source code
+     * @since 1.5
+     */
+    public boolean isEnum() {
+        // An enum must both directly extend java.lang.Enum and have
+        // the ENUM bit set; classes for specialized enum constants
+        // don't do the former.
+        return (this.getModifiers() & ENUM) != 0 &&
+        this.getSuperclass() == java.lang.Enum.class;
+    }
+
+    /**
+     * Returns the elements of this enum class or null if this
+     * Class object does not represent an enum type.
+     *
+     * @return an array containing the values comprising the enum class
+     *     represented by this Class object in the order they're
+     *     declared, or null if this Class object does not
+     *     represent an enum type
+     * @since 1.5
+     */
+    public T[] getEnumConstants() {
+        T[] values = getEnumConstantsShared();
+        return (values != null) ? values.clone() : null;
+    }
+
+    // Android-changed: Made public/hidden instead of using sun.misc.SharedSecrets.
+    /**
+     * Returns the elements of this enum class or null if this
+     * Class object does not represent an enum type;
+     * identical to getEnumConstants except that the result is
+     * uncloned, cached, and shared by all callers.
+     * @hide
+     */
+    public T[] getEnumConstantsShared() {
+        if (!isEnum()) return null;
+        return (T[]) Enum.getSharedConstants((Class) this);
+    }
+
+    /**
+     * Casts an object to the class or interface represented
+     * by this {@code Class} object.
+     *
+     * @param obj the object to be cast
+     * @return the object after casting, or null if obj is null
+     *
+     * @throws ClassCastException if the object is not
+     * null and is not assignable to the type T.
+     *
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public T cast(Object obj) {
+        if (obj != null && !isInstance(obj))
+            throw new ClassCastException(cannotCastMsg(obj));
+        return (T) obj;
+    }
+
+    private String cannotCastMsg(Object obj) {
+        return "Cannot cast " + obj.getClass().getName() + " to " + getName();
+    }
+
+    /**
+     * Casts this {@code Class} object to represent a subclass of the class
+     * represented by the specified class object.  Checks that the cast
+     * is valid, and throws a {@code ClassCastException} if it is not.  If
+     * this method succeeds, it always returns a reference to this class object.
+     *
+     * <p>This method is useful when a client needs to "narrow" the type of
+     * a {@code Class} object to pass it to an API that restricts the
+     * {@code Class} objects that it is willing to accept.  A cast would
+     * generate a compile-time warning, as the correctness of the cast
+     * could not be checked at runtime (because generic types are implemented
+     * by erasure).
+     *
+     * @param <U> the type to cast this class object to
+     * @param clazz the class of the type to cast this class object to
+     * @return this {@code Class} object, cast to represent a subclass of
+     *    the specified class object.
+     * @throws ClassCastException if this {@code Class} object does not
+     *    represent a subclass of the specified class (here "subclass" includes
+     *    the class itself).
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public <U> Class<? extends U> asSubclass(Class<U> clazz) {
+        if (clazz.isAssignableFrom(this))
+            return (Class<? extends U>) this;
+        else
+            throw new ClassCastException(this.toString() +
+                " cannot be cast to " + clazz.getName());
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+
+        A annotation = getDeclaredAnnotation(annotationClass);
+        if (annotation != null) {
+            return annotation;
+        }
+
+        if (annotationClass.isDeclaredAnnotationPresent(Inherited.class)) {
+            for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+                annotation = sup.getDeclaredAnnotation(annotationClass);
+                if (annotation != null) {
+                    return annotation;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+        if (annotationClass == null) {
+            throw new NullPointerException("annotationClass == null");
+        }
+
+        if (isDeclaredAnnotationPresent(annotationClass)) {
+            return true;
+        }
+
+        if (annotationClass.isDeclaredAnnotationPresent(Inherited.class)) {
+            for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+                if (sup.isDeclaredAnnotationPresent(annotationClass)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) {
+      // Find any associated annotations [directly or repeatably (indirectly) present on this].
+      A[] annotations = GenericDeclaration.super.getAnnotationsByType(annotationClass);
+
+      if (annotations.length != 0) {
+        return annotations;
+      }
+
+      // Nothing was found, attempt looking for associated annotations recursively up to the root
+      // class if and only if:
+      // * The annotation class was marked with @Inherited.
+      //
+      // Inherited annotations are not coalesced into a single set: the first declaration found is
+      // returned.
+
+      if (annotationClass.isDeclaredAnnotationPresent(Inherited.class)) {
+        Class<?> superClass = getSuperclass();  // Returns null if klass's base is Object.
+
+        if (superClass != null) {
+          return superClass.getAnnotationsByType(annotationClass);
+        }
+      }
+
+      // Annotated was not marked with @Inherited, or no superclass.
+      return (A[]) Array.newInstance(annotationClass, 0);  // Safe by construction.
+    }
+
+    /**
+     * @since 1.5
+     */
+    @Override
+    public Annotation[] getAnnotations() {
+        /*
+         * We need to get the annotations declared on this class, plus the
+         * annotations from superclasses that have the "@Inherited" annotation
+         * set.  We create a temporary map to use while we accumulate the
+         * annotations and convert it to an array at the end.
+         *
+         * It's possible to have duplicates when annotations are inherited.
+         * We use a Map to filter those out.
+         *
+         * HashMap might be overkill here.
+         */
+        HashMap<Class<?>, Annotation> map = new HashMap<Class<?>, Annotation>();
+        for (Annotation declaredAnnotation : getDeclaredAnnotations()) {
+            map.put(declaredAnnotation.annotationType(), declaredAnnotation);
+        }
+        for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+            for (Annotation declaredAnnotation : sup.getDeclaredAnnotations()) {
+                Class<? extends Annotation> clazz = declaredAnnotation.annotationType();
+                if (!map.containsKey(clazz) && clazz.isDeclaredAnnotationPresent(Inherited.class)) {
+                    map.put(clazz, declaredAnnotation);
+                }
+            }
+        }
+
+        /* Convert annotation values from HashMap to array. */
+        Collection<Annotation> coll = map.values();
+        return coll.toArray(new Annotation[coll.size()]);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    @FastNative
+    public native <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass);
+
+    /**
+     * @since 1.5
+     */
+    @Override
+    @FastNative
+    public native Annotation[] getDeclaredAnnotations();
+
+    /**
+     * Returns true if the annotation exists.
+     */
+    @FastNative
+    private native boolean isDeclaredAnnotationPresent(Class<? extends Annotation> annotationClass);
+
+    private String getSignatureAttribute() {
+        String[] annotation = getSignatureAnnotation();
+        if (annotation == null) {
+            return null;
+        }
+        StringBuilder result = new StringBuilder();
+        for (String s : annotation) {
+            result.append(s);
+        }
+        return result.toString();
+    }
+
+    @FastNative
+    private native String[] getSignatureAnnotation();
+
+    /**
+     * Is this a runtime created proxy class?
+     *
+     * @hide
+     */
+    public boolean isProxy() {
+        return (accessFlags & 0x00040000) != 0;
+    }
+
+    /**
+     * @hide
+     */
+    public int getAccessFlags() {
+        return accessFlags;
+    }
+
+
+    /**
+     * Returns the method if it is defined by this class; {@code null} otherwise. This may return a
+     * non-public member.
+     *
+     * @param name the method name
+     * @param args the method's parameter types
+     */
+    @FastNative
+    private native Method getDeclaredMethodInternal(String name, Class<?>[] args);
+
+    private static class Caches {
+        /**
+         * Cache to avoid frequent recalculation of generic interfaces, which is generally uncommon.
+         * Sized sufficient to allow ConcurrentHashMapTest to run without recalculating its generic
+         * interfaces (required to avoid time outs). Validated by running reflection heavy code
+         * such as applications using Guice-like frameworks.
+         */
+        private static final BasicLruCache<Class, Type[]> genericInterfaces
+            = new BasicLruCache<Class, Type[]>(8);
+    }
+}
diff --git a/java/lang/ClassCastException.java b/java/lang/ClassCastException.java
new file mode 100644
index 0000000..e4ca76c
--- /dev/null
+++ b/java/lang/ClassCastException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that the code has attempted to cast an object
+ * to a subclass of which it is not an instance. For example, the
+ * following code generates a <code>ClassCastException</code>:
+ * <blockquote><pre>
+ *     Object x = new Integer(0);
+ *     System.out.println((String)x);
+ * </pre></blockquote>
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class ClassCastException extends RuntimeException {
+    private static final long serialVersionUID = -9223365651070458532L;
+
+    /**
+     * Constructs a <code>ClassCastException</code> with no detail message.
+     */
+    public ClassCastException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>ClassCastException</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public ClassCastException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/ClassCircularityError.java b/java/lang/ClassCircularityError.java
new file mode 100644
index 0000000..64e5361
--- /dev/null
+++ b/java/lang/ClassCircularityError.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when the Java Virtual Machine detects a circularity in the
+ * superclass hierarchy of a class being loaded.
+ *
+ * @author     unascribed
+ * @since      JDK1.0
+ */
+public class ClassCircularityError extends LinkageError {
+    private static final long serialVersionUID = 1054362542914539689L;
+
+    /**
+     * Constructs a {@code ClassCircularityError} with no detail message.
+     */
+    public ClassCircularityError() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code ClassCircularityError} with the specified detail
+     * message.
+     *
+     * @param  s
+     *         The detail message
+     */
+    public ClassCircularityError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/ClassFormatError.java b/java/lang/ClassFormatError.java
new file mode 100644
index 0000000..2dc81db
--- /dev/null
+++ b/java/lang/ClassFormatError.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when the Java Virtual Machine attempts to read a class
+ * file and determines that the file is malformed or otherwise cannot
+ * be interpreted as a class file.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class ClassFormatError extends LinkageError {
+    private static final long serialVersionUID = -8420114879011949195L;
+
+    /**
+     * Constructs a <code>ClassFormatError</code> with no detail message.
+     */
+    public ClassFormatError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>ClassFormatError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public ClassFormatError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/ClassLoader.java b/java/lang/ClassLoader.java
new file mode 100644
index 0000000..0a8b08a
--- /dev/null
+++ b/java/lang/ClassLoader.java
@@ -0,0 +1,1428 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.CodeSource;
+import java.security.Policy;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.Stack;
+import java.util.Map;
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import dalvik.system.PathClassLoader;
+import java.util.List;
+import sun.misc.CompoundEnumeration;
+import sun.misc.Resource;
+import sun.misc.URLClassPath;
+import sun.misc.VM;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
+
+/**
+ * A class loader is an object that is responsible for loading classes. The
+ * class <tt>ClassLoader</tt> is an abstract class.  Given the <a
+ * href="#name">binary name</a> of a class, a class loader should attempt to
+ * locate or generate data that constitutes a definition for the class.  A
+ * typical strategy is to transform the name into a file name and then read a
+ * "class file" of that name from a file system.
+ *
+ * <p> Every {@link Class <tt>Class</tt>} object contains a {@link
+ * Class#getClassLoader() reference} to the <tt>ClassLoader</tt> that defined
+ * it.
+ *
+ * <p> <tt>Class</tt> objects for array classes are not created by class
+ * loaders, but are created automatically as required by the Java runtime.
+ * The class loader for an array class, as returned by {@link
+ * Class#getClassLoader()} is the same as the class loader for its element
+ * type; if the element type is a primitive type, then the array class has no
+ * class loader.
+ *
+ * <p> Applications implement subclasses of <tt>ClassLoader</tt> in order to
+ * extend the manner in which the Java virtual machine dynamically loads
+ * classes.
+ *
+ * <p> Class loaders may typically be used by security managers to indicate
+ * security domains.
+ *
+ * <p> The <tt>ClassLoader</tt> class uses a delegation model to search for
+ * classes and resources.  Each instance of <tt>ClassLoader</tt> has an
+ * associated parent class loader.  When requested to find a class or
+ * resource, a <tt>ClassLoader</tt> instance will delegate the search for the
+ * class or resource to its parent class loader before attempting to find the
+ * class or resource itself.  The virtual machine's built-in class loader,
+ * called the "bootstrap class loader", does not itself have a parent but may
+ * serve as the parent of a <tt>ClassLoader</tt> instance.
+ *
+ * <p> Class loaders that support concurrent loading of classes are known as
+ * <em>parallel capable</em> class loaders and are required to register
+ * themselves at their class initialization time by invoking the
+ * {@link
+ * #registerAsParallelCapable <tt>ClassLoader.registerAsParallelCapable</tt>}
+ * method. Note that the <tt>ClassLoader</tt> class is registered as parallel
+ * capable by default. However, its subclasses still need to register themselves
+ * if they are parallel capable. <br>
+ * In environments in which the delegation model is not strictly
+ * hierarchical, class loaders need to be parallel capable, otherwise class
+ * loading can lead to deadlocks because the loader lock is held for the
+ * duration of the class loading process (see {@link #loadClass
+ * <tt>loadClass</tt>} methods).
+ *
+ * <p> Normally, the Java virtual machine loads classes from the local file
+ * system in a platform-dependent manner.  For example, on UNIX systems, the
+ * virtual machine loads classes from the directory defined by the
+ * <tt>CLASSPATH</tt> environment variable.
+ *
+ * <p> However, some classes may not originate from a file; they may originate
+ * from other sources, such as the network, or they could be constructed by an
+ * application.  The method {@link #defineClass(String, byte[], int, int)
+ * <tt>defineClass</tt>} converts an array of bytes into an instance of class
+ * <tt>Class</tt>. Instances of this newly defined class can be created using
+ * {@link Class#newInstance <tt>Class.newInstance</tt>}.
+ *
+ * <p> The methods and constructors of objects created by a class loader may
+ * reference other classes.  To determine the class(es) referred to, the Java
+ * virtual machine invokes the {@link #loadClass <tt>loadClass</tt>} method of
+ * the class loader that originally created the class.
+ *
+ * <p> For example, an application could create a network class loader to
+ * download class files from a server.  Sample code might look like:
+ *
+ * <blockquote><pre>
+ *   ClassLoader loader&nbsp;= new NetworkClassLoader(host,&nbsp;port);
+ *   Object main&nbsp;= loader.loadClass("Main", true).newInstance();
+ *       &nbsp;.&nbsp;.&nbsp;.
+ * </pre></blockquote>
+ *
+ * <p> The network class loader subclass must define the methods {@link
+ * #findClass <tt>findClass</tt>} and <tt>loadClassData</tt> to load a class
+ * from the network.  Once it has downloaded the bytes that make up the class,
+ * it should use the method {@link #defineClass <tt>defineClass</tt>} to
+ * create a class instance.  A sample implementation is:
+ *
+ * <blockquote><pre>
+ *     class NetworkClassLoader extends ClassLoader {
+ *         String host;
+ *         int port;
+ *
+ *         public Class findClass(String name) {
+ *             byte[] b = loadClassData(name);
+ *             return defineClass(name, b, 0, b.length);
+ *         }
+ *
+ *         private byte[] loadClassData(String name) {
+ *             // load the class data from the connection
+ *             &nbsp;.&nbsp;.&nbsp;.
+ *         }
+ *     }
+ * </pre></blockquote>
+ *
+ * <h3> <a name="name">Binary names</a> </h3>
+ *
+ * <p> Any class name provided as a {@link String} parameter to methods in
+ * <tt>ClassLoader</tt> must be a binary name as defined by
+ * <cite>The Java&trade; Language Specification</cite>.
+ *
+ * <p> Examples of valid class names include:
+ * <blockquote><pre>
+ *   "java.lang.String"
+ *   "javax.swing.JSpinner$DefaultEditor"
+ *   "java.security.KeyStore$Builder$FileBuilder$1"
+ *   "java.net.URLClassLoader$3$1"
+ * </pre></blockquote>
+ *
+ * @see      #resolveClass(Class)
+ * @since 1.0
+ */
+public abstract class ClassLoader {
+
+    static private class SystemClassLoader {
+        public static ClassLoader loader = ClassLoader.createSystemClassLoader();
+    }
+
+    /**
+     * To avoid unloading individual classes, {@link java.lang.reflect.Proxy}
+     * only generates one class for each set of interfaces. This maps sets of
+     * interfaces to the proxy class that implements all of them. It is declared
+     * here so that these generated classes can be unloaded with their class
+     * loader.
+     *
+     * @hide
+     */
+    public final Map<List<Class<?>>, Class<?>> proxyCache =
+            new HashMap<List<Class<?>>, Class<?>>();
+
+    // The parent class loader for delegation
+    // Note: VM hardcoded the offset of this field, thus all new fields
+    // must be added *after* it.
+    private final ClassLoader parent;
+
+    /**
+     * Encapsulates the set of parallel capable loader types.
+     */
+    private static ClassLoader createSystemClassLoader() {
+        String classPath = System.getProperty("java.class.path", ".");
+        String librarySearchPath = System.getProperty("java.library.path", "");
+
+        // String[] paths = classPath.split(":");
+        // URL[] urls = new URL[paths.length];
+        // for (int i = 0; i < paths.length; i++) {
+        // try {
+        // urls[i] = new URL("file://" + paths[i]);
+        // }
+        // catch (Exception ex) {
+        // ex.printStackTrace();
+        // }
+        // }
+        //
+        // return new java.net.URLClassLoader(urls, null);
+
+        // TODO Make this a java.net.URLClassLoader once we have those?
+        return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance());
+    }
+
+    // The packages defined in this class loader.  Each package name is mapped
+    // to its corresponding Package object.
+    // @GuardedBy("itself")
+    private final HashMap<String, Package> packages = new HashMap<>();
+
+    /**
+     * Pointer to the allocator used by the runtime to allocate metadata such
+     * as ArtFields and ArtMethods.
+     */
+    private transient long allocator;
+
+    /**
+     * Pointer to the class table, only used from within the runtime.
+     */
+    private transient long classTable;
+
+    private static Void checkCreateClassLoader() {
+        return null;
+    }
+
+    private ClassLoader(Void unused, ClassLoader parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Creates a new class loader using the specified parent class loader for
+     * delegation.
+     *
+     * <p> If there is a security manager, its {@link
+     * SecurityManager#checkCreateClassLoader()
+     * <tt>checkCreateClassLoader</tt>} method is invoked.  This may result in
+     * a security exception.  </p>
+     *
+     * @param  parent
+     *         The parent class loader
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          <tt>checkCreateClassLoader</tt> method doesn't allow creation
+     *          of a new class loader.
+     *
+     * @since  1.2
+     */
+    protected ClassLoader(ClassLoader parent) {
+        this(checkCreateClassLoader(), parent);
+    }
+
+    /**
+     * Creates a new class loader using the <tt>ClassLoader</tt> returned by
+     * the method {@link #getSystemClassLoader()
+     * <tt>getSystemClassLoader()</tt>} as the parent class loader.
+     *
+     * <p> If there is a security manager, its {@link
+     * SecurityManager#checkCreateClassLoader()
+     * <tt>checkCreateClassLoader</tt>} method is invoked.  This may result in
+     * a security exception.  </p>
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          <tt>checkCreateClassLoader</tt> method doesn't allow creation
+     *          of a new class loader.
+     */
+    protected ClassLoader() {
+        this(checkCreateClassLoader(), getSystemClassLoader());
+    }
+
+    // -- Class --
+
+    /**
+     * Loads the class with the specified <a href="#name">binary name</a>.
+     * This method searches for classes in the same manner as the {@link
+     * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
+     * machine to resolve class references.  Invoking this method is equivalent
+     * to invoking {@link #loadClass(String, boolean) <tt>loadClass(name,
+     * false)</tt>}.
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return  The resulting <tt>Class</tt> object
+     *
+     * @throws  ClassNotFoundException
+     *          If the class was not found
+     */
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        return loadClass(name, false);
+    }
+
+    /**
+     * Loads the class with the specified <a href="#name">binary name</a>.  The
+     * default implementation of this method searches for classes in the
+     * following order:
+     *
+     * <ol>
+     *
+     *   <li><p> Invoke {@link #findLoadedClass(String)} to check if the class
+     *   has already been loaded.  </p></li>
+     *
+     *   <li><p> Invoke the {@link #loadClass(String) <tt>loadClass</tt>} method
+     *   on the parent class loader.  If the parent is <tt>null</tt> the class
+     *   loader built-in to the virtual machine is used, instead.  </p></li>
+     *
+     *   <li><p> Invoke the {@link #findClass(String)} method to find the
+     *   class.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> If the class was found using the above steps, and the
+     * <tt>resolve</tt> flag is true, this method will then invoke the {@link
+     * #resolveClass(Class)} method on the resulting <tt>Class</tt> object.
+     *
+     * <p> Subclasses of <tt>ClassLoader</tt> are encouraged to override {@link
+     * #findClass(String)}, rather than this method.  </p>
+     *
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @param  resolve
+     *         If <tt>true</tt> then resolve the class
+     *
+     * @return  The resulting <tt>Class</tt> object
+     *
+     * @throws  ClassNotFoundException
+     *          If the class could not be found
+     */
+    // Android-removed: Remove references to getClassLoadingLock
+    //                   Remove perf counters.
+    //
+    // <p> Unless overridden, this method synchronizes on the result of
+    // {@link #getClassLoadingLock <tt>getClassLoadingLock</tt>} method
+    // during the entire class loading process.
+    protected Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+            // First, check if the class has already been loaded
+            Class<?> c = findLoadedClass(name);
+            if (c == null) {
+                try {
+                    if (parent != null) {
+                        c = parent.loadClass(name, false);
+                    } else {
+                        c = findBootstrapClassOrNull(name);
+                    }
+                } catch (ClassNotFoundException e) {
+                    // ClassNotFoundException thrown if class not found
+                    // from the non-null parent class loader
+                }
+
+                if (c == null) {
+                    // If still not found, then invoke findClass in order
+                    // to find the class.
+                    c = findClass(name);
+                }
+            }
+            return c;
+    }
+
+
+    /**
+     * Finds the class with the specified <a href="#name">binary name</a>.
+     * This method should be overridden by class loader implementations that
+     * follow the delegation model for loading classes, and will be invoked by
+     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
+     * parent class loader for the requested class.  The default implementation
+     * throws a <tt>ClassNotFoundException</tt>.
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return  The resulting <tt>Class</tt> object
+     *
+     * @throws  ClassNotFoundException
+     *          If the class could not be found
+     *
+     * @since  1.2
+     */
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        throw new ClassNotFoundException(name);
+    }
+
+    /**
+     * Converts an array of bytes into an instance of class <tt>Class</tt>.
+     * Before the <tt>Class</tt> can be used it must be resolved.  This method
+     * is deprecated in favor of the version that takes a <a
+     * href="#name">binary name</a> as its first argument, and is more secure.
+     *
+     * @param  b
+     *         The bytes that make up the class data.  The bytes in positions
+     *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
+     *         of a valid class file as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @param  off
+     *         The start offset in <tt>b</tt> of the class data
+     *
+     * @param  len
+     *         The length of the class data
+     *
+     * @return  The <tt>Class</tt> object that was created from the specified
+     *          class data
+     *
+     * @throws  ClassFormatError
+     *          If the data did not contain a valid class
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
+     *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
+     *
+     * @throws  SecurityException
+     *          If an attempt is made to add this class to a package that
+     *          contains classes that were signed by a different set of
+     *          certificates than this class, or if an attempt is made
+     *          to define a class in a package with a fully-qualified name
+     *          that starts with "{@code java.}".
+     *
+     * @see  #loadClass(String, boolean)
+     * @see  #resolveClass(Class)
+     *
+     * @deprecated  Replaced by {@link #defineClass(String, byte[], int, int)
+     * defineClass(String, byte[], int, int)}
+     */
+    @Deprecated
+    protected final Class<?> defineClass(byte[] b, int off, int len)
+        throws ClassFormatError
+    {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+    /**
+     * Converts an array of bytes into an instance of class <tt>Class</tt>.
+     * Before the <tt>Class</tt> can be used it must be resolved.
+     *
+     * <p> This method assigns a default {@link java.security.ProtectionDomain
+     * <tt>ProtectionDomain</tt>} to the newly defined class.  The
+     * <tt>ProtectionDomain</tt> is effectively granted the same set of
+     * permissions returned when {@link
+     * java.security.Policy#getPermissions(java.security.CodeSource)
+     * <tt>Policy.getPolicy().getPermissions(new CodeSource(null, null))</tt>}
+     * is invoked.  The default domain is created on the first invocation of
+     * {@link #defineClass(String, byte[], int, int) <tt>defineClass</tt>},
+     * and re-used on subsequent invocations.
+     *
+     * <p> To assign a specific <tt>ProtectionDomain</tt> to the class, use
+     * the {@link #defineClass(String, byte[], int, int,
+     * java.security.ProtectionDomain) <tt>defineClass</tt>} method that takes a
+     * <tt>ProtectionDomain</tt> as one of its arguments.  </p>
+     *
+     * @param  name
+     *         The expected <a href="#name">binary name</a> of the class, or
+     *         <tt>null</tt> if not known
+     *
+     * @param  b
+     *         The bytes that make up the class data.  The bytes in positions
+     *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
+     *         of a valid class file as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @param  off
+     *         The start offset in <tt>b</tt> of the class data
+     *
+     * @param  len
+     *         The length of the class data
+     *
+     * @return  The <tt>Class</tt> object that was created from the specified
+     *          class data.
+     *
+     * @throws  ClassFormatError
+     *          If the data did not contain a valid class
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
+     *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
+     *
+     * @throws  SecurityException
+     *          If an attempt is made to add this class to a package that
+     *          contains classes that were signed by a different set of
+     *          certificates than this class (which is unsigned), or if
+     *          <tt>name</tt> begins with "<tt>java.</tt>".
+     *
+     * @see  #loadClass(String, boolean)
+     * @see  #resolveClass(Class)
+     * @see  java.security.CodeSource
+     * @see  java.security.SecureClassLoader
+     *
+     * @since  1.1
+     */
+    protected final Class<?> defineClass(String name, byte[] b, int off, int len)
+        throws ClassFormatError
+    {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+
+    /**
+     * Converts an array of bytes into an instance of class <tt>Class</tt>,
+     * with an optional <tt>ProtectionDomain</tt>.  If the domain is
+     * <tt>null</tt>, then a default domain will be assigned to the class as
+     * specified in the documentation for {@link #defineClass(String, byte[],
+     * int, int)}.  Before the class can be used it must be resolved.
+     *
+     * <p> The first class defined in a package determines the exact set of
+     * certificates that all subsequent classes defined in that package must
+     * contain.  The set of certificates for a class is obtained from the
+     * {@link java.security.CodeSource <tt>CodeSource</tt>} within the
+     * <tt>ProtectionDomain</tt> of the class.  Any classes added to that
+     * package must contain the same set of certificates or a
+     * <tt>SecurityException</tt> will be thrown.  Note that if
+     * <tt>name</tt> is <tt>null</tt>, this check is not performed.
+     * You should always pass in the <a href="#name">binary name</a> of the
+     * class you are defining as well as the bytes.  This ensures that the
+     * class you are defining is indeed the class you think it is.
+     *
+     * <p> The specified <tt>name</tt> cannot begin with "<tt>java.</tt>", since
+     * all classes in the "<tt>java.*</tt> packages can only be defined by the
+     * bootstrap class loader.  If <tt>name</tt> is not <tt>null</tt>, it
+     * must be equal to the <a href="#name">binary name</a> of the class
+     * specified by the byte array "<tt>b</tt>", otherwise a {@link
+     * NoClassDefFoundError <tt>NoClassDefFoundError</tt>} will be thrown. </p>
+     *
+     * @param  name
+     *         The expected <a href="#name">binary name</a> of the class, or
+     *         <tt>null</tt> if not known
+     *
+     * @param  b
+     *         The bytes that make up the class data. The bytes in positions
+     *         <tt>off</tt> through <tt>off+len-1</tt> should have the format
+     *         of a valid class file as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @param  off
+     *         The start offset in <tt>b</tt> of the class data
+     *
+     * @param  len
+     *         The length of the class data
+     *
+     * @param  protectionDomain
+     *         The ProtectionDomain of the class
+     *
+     * @return  The <tt>Class</tt> object created from the data,
+     *          and optional <tt>ProtectionDomain</tt>.
+     *
+     * @throws  ClassFormatError
+     *          If the data did not contain a valid class
+     *
+     * @throws  NoClassDefFoundError
+     *          If <tt>name</tt> is not equal to the <a href="#name">binary
+     *          name</a> of the class specified by <tt>b</tt>
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
+     *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
+     *
+     * @throws  SecurityException
+     *          If an attempt is made to add this class to a package that
+     *          contains classes that were signed by a different set of
+     *          certificates than this class, or if <tt>name</tt> begins with
+     *          "<tt>java.</tt>".
+     */
+    // Android-changed: Remove <tt> from link for NoClassDefFoundError
+    protected final Class<?> defineClass(String name, byte[] b, int off, int len,
+                                         ProtectionDomain protectionDomain)
+        throws ClassFormatError
+    {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+    /**
+     * Converts a {@link java.nio.ByteBuffer <tt>ByteBuffer</tt>}
+     * into an instance of class <tt>Class</tt>,
+     * with an optional <tt>ProtectionDomain</tt>.  If the domain is
+     * <tt>null</tt>, then a default domain will be assigned to the class as
+     * specified in the documentation for {@link #defineClass(String, byte[],
+     * int, int)}.  Before the class can be used it must be resolved.
+     *
+     * <p>The rules about the first class defined in a package determining the
+     * set of certificates for the package, and the restrictions on class names
+     * are identical to those specified in the documentation for {@link
+     * #defineClass(String, byte[], int, int, ProtectionDomain)}.
+     *
+     * <p> An invocation of this method of the form
+     * <i>cl</i><tt>.defineClass(</tt><i>name</i><tt>,</tt>
+     * <i>bBuffer</i><tt>,</tt> <i>pd</i><tt>)</tt> yields exactly the same
+     * result as the statements
+     *
+     *<p> <tt>
+     * ...<br>
+     * byte[] temp = new byte[bBuffer.{@link
+     * java.nio.ByteBuffer#remaining remaining}()];<br>
+     *     bBuffer.{@link java.nio.ByteBuffer#get(byte[])
+     * get}(temp);<br>
+     *     return {@link #defineClass(String, byte[], int, int, ProtectionDomain)
+     * cl.defineClass}(name, temp, 0,
+     * temp.length, pd);<br>
+     * </tt></p>
+     *
+     * @param  name
+     *         The expected <a href="#name">binary name</a>. of the class, or
+     *         <tt>null</tt> if not known
+     *
+     * @param  b
+     *         The bytes that make up the class data. The bytes from positions
+     *         <tt>b.position()</tt> through <tt>b.position() + b.limit() -1
+     *         </tt> should have the format of a valid class file as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @param  protectionDomain
+     *         The ProtectionDomain of the class, or <tt>null</tt>.
+     *
+     * @return  The <tt>Class</tt> object created from the data,
+     *          and optional <tt>ProtectionDomain</tt>.
+     *
+     * @throws  ClassFormatError
+     *          If the data did not contain a valid class.
+     *
+     * @throws  NoClassDefFoundError
+     *          If <tt>name</tt> is not equal to the <a href="#name">binary
+     *          name</a> of the class specified by <tt>b</tt>
+     *
+     * @throws  SecurityException
+     *          If an attempt is made to add this class to a package that
+     *          contains classes that were signed by a different set of
+     *          certificates than this class, or if <tt>name</tt> begins with
+     *          "<tt>java.</tt>".
+     *
+     * @see      #defineClass(String, byte[], int, int, ProtectionDomain)
+     *
+     * @since  1.5
+     */
+    protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
+                                         ProtectionDomain protectionDomain)
+        throws ClassFormatError
+    {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+    /**
+     * Links the specified class.  This (misleadingly named) method may be
+     * used by a class loader to link a class.  If the class <tt>c</tt> has
+     * already been linked, then this method simply returns. Otherwise, the
+     * class is linked as described in the "Execution" chapter of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @param  c
+     *         The class to link
+     *
+     * @throws  NullPointerException
+     *          If <tt>c</tt> is <tt>null</tt>.
+     *
+     * @see  #defineClass(String, byte[], int, int)
+     */
+    protected final void resolveClass(Class<?> c) {
+    }
+
+    /**
+     * Finds a class with the specified <a href="#name">binary name</a>,
+     * loading it if necessary.
+     *
+     * <p> This method loads the class through the system class loader (see
+     * {@link #getSystemClassLoader()}).  The <tt>Class</tt> object returned
+     * might have more than one <tt>ClassLoader</tt> associated with it.
+     * Subclasses of <tt>ClassLoader</tt> need not usually invoke this method,
+     * because most class loaders need to override just {@link
+     * #findClass(String)}.  </p>
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return  The <tt>Class</tt> object for the specified <tt>name</tt>
+     *
+     * @throws  ClassNotFoundException
+     *          If the class could not be found
+     *
+     * @see  #ClassLoader(ClassLoader)
+     * @see  #getParent()
+     */
+    protected final Class<?> findSystemClass(String name)
+        throws ClassNotFoundException
+    {
+        return Class.forName(name, false, getSystemClassLoader());
+    }
+
+    /**
+     * Returns a class loaded by the bootstrap class loader;
+     * or return null if not found.
+     */
+    private Class<?> findBootstrapClassOrNull(String name)
+    {
+        return null;
+    }
+
+    /**
+     * Returns the class with the given <a href="#name">binary name</a> if this
+     * loader has been recorded by the Java virtual machine as an initiating
+     * loader of a class with that <a href="#name">binary name</a>.  Otherwise
+     * <tt>null</tt> is returned.
+     *
+     * @param  name
+     *         The <a href="#name">binary name</a> of the class
+     *
+     * @return  The <tt>Class</tt> object, or <tt>null</tt> if the class has
+     *          not been loaded
+     *
+     * @since  1.1
+     */
+    protected final Class<?> findLoadedClass(String name) {
+        ClassLoader loader;
+        if (this == BootClassLoader.getInstance())
+            loader = null;
+        else
+            loader = this;
+        return VMClassLoader.findLoadedClass(loader, name);
+    }
+
+    /**
+     * Sets the signers of a class.  This should be invoked after defining a
+     * class.
+     *
+     * @param  c
+     *         The <tt>Class</tt> object
+     *
+     * @param  signers
+     *         The signers for the class
+     *
+     * @since  1.1
+     */
+    protected final void setSigners(Class<?> c, Object[] signers) {
+    }
+
+
+    // -- Resource --
+
+    /**
+     * Finds the resource with the given name.  A resource is some data
+     * (images, audio, text, etc) that can be accessed by class code in a way
+     * that is independent of the location of the code.
+     *
+     * <p> The name of a resource is a '<tt>/</tt>'-separated path name that
+     * identifies the resource.
+     *
+     * <p> This method will first search the parent class loader for the
+     * resource; if the parent is <tt>null</tt> the path of the class loader
+     * built-in to the virtual machine is searched.  That failing, this method
+     * will invoke {@link #findResource(String)} to find the resource.  </p>
+     *
+     * @apiNote When overriding this method it is recommended that an
+     * implementation ensures that any delegation is consistent with the {@link
+     * #getResources(java.lang.String) getResources(String)} method.
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  A <tt>URL</tt> object for reading the resource, or
+     *          <tt>null</tt> if the resource could not be found or the invoker
+     *          doesn't have adequate  privileges to get the resource.
+     *
+     * @since  1.1
+     */
+    public URL getResource(String name) {
+        URL url;
+        if (parent != null) {
+            url = parent.getResource(name);
+        } else {
+            url = getBootstrapResource(name);
+        }
+        if (url == null) {
+            url = findResource(name);
+        }
+        return url;
+    }
+
+    /**
+     * Finds all the resources with the given name. A resource is some data
+     * (images, audio, text, etc) that can be accessed by class code in a way
+     * that is independent of the location of the code.
+     *
+     * <p>The name of a resource is a <tt>/</tt>-separated path name that
+     * identifies the resource.
+     *
+     * <p> The search order is described in the documentation for {@link
+     * #getResource(String)}.  </p>
+     *
+     * @apiNote When overriding this method it is recommended that an
+     * implementation ensures that any delegation is consistent with the {@link
+     * #getResource(java.lang.String) getResource(String)} method. This should
+     * ensure that the first element returned by the Enumeration's
+     * {@code nextElement} method is the same resource that the
+     * {@code getResource(String)} method would return.
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
+     *          the resource.  If no resources could  be found, the enumeration
+     *          will be empty.  Resources that the class loader doesn't have
+     *          access to will not be in the enumeration.
+     *
+     * @throws  IOException
+     *          If I/O errors occur
+     *
+     * @see  #findResources(String)
+     *
+     * @since  1.2
+     */
+    public Enumeration<URL> getResources(String name) throws IOException {
+        @SuppressWarnings("unchecked")
+        Enumeration<URL>[] tmp = (Enumeration<URL>[]) new Enumeration<?>[2];
+        if (parent != null) {
+            tmp[0] = parent.getResources(name);
+        } else {
+            tmp[0] = getBootstrapResources(name);
+        }
+        tmp[1] = findResources(name);
+
+        return new CompoundEnumeration<>(tmp);
+    }
+
+    /**
+     * Finds the resource with the given name. Class loader implementations
+     * should override this method to specify where to find resources.
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  A <tt>URL</tt> object for reading the resource, or
+     *          <tt>null</tt> if the resource could not be found
+     *
+     * @since  1.2
+     */
+    protected URL findResource(String name) {
+        return null;
+    }
+
+    /**
+     * Returns an enumeration of {@link java.net.URL <tt>URL</tt>} objects
+     * representing all the resources with the given name. Class loader
+     * implementations should override this method to specify where to load
+     * resources from.
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An enumeration of {@link java.net.URL <tt>URL</tt>} objects for
+     *          the resources
+     *
+     * @throws  IOException
+     *          If I/O errors occur
+     *
+     * @since  1.2
+     */
+    protected Enumeration<URL> findResources(String name) throws IOException {
+        return java.util.Collections.emptyEnumeration();
+    }
+
+    /**
+     * Registers the caller as parallel capable.
+     * The registration succeeds if and only if all of the following
+     * conditions are met:
+     * <ol>
+     * <li> no instance of the caller has been created</li>
+     * <li> all of the super classes (except class Object) of the caller are
+     * registered as parallel capable</li>
+     * </ol>
+     * <p>Note that once a class loader is registered as parallel capable, there
+     * is no way to change it back.</p>
+     *
+     * @return  true if the caller is successfully registered as
+     *          parallel capable and false if otherwise.
+     *
+     * @since   1.7
+     */
+    @CallerSensitive
+    protected static boolean registerAsParallelCapable() {
+        return true;
+    }
+
+    /**
+     * Find a resource of the specified name from the search path used to load
+     * classes.  This method locates the resource through the system class
+     * loader (see {@link #getSystemClassLoader()}).
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  A {@link java.net.URL <tt>URL</tt>} object for reading the
+     *          resource, or <tt>null</tt> if the resource could not be found
+     *
+     * @since  1.1
+     */
+    public static URL getSystemResource(String name) {
+        ClassLoader system = getSystemClassLoader();
+        if (system == null) {
+            return getBootstrapResource(name);
+        }
+        return system.getResource(name);
+    }
+
+    /**
+     * Finds all resources of the specified name from the search path used to
+     * load classes.  The resources thus found are returned as an
+     * {@link java.util.Enumeration <tt>Enumeration</tt>} of {@link
+     * java.net.URL <tt>URL</tt>} objects.
+     *
+     * <p> The search order is described in the documentation for {@link
+     * #getSystemResource(String)}.  </p>
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An enumeration of resource {@link java.net.URL <tt>URL</tt>}
+     *          objects
+     *
+     * @throws  IOException
+     *          If I/O errors occur
+
+     * @since  1.2
+     */
+    public static Enumeration<URL> getSystemResources(String name)
+        throws IOException
+    {
+        ClassLoader system = getSystemClassLoader();
+        if (system == null) {
+            return getBootstrapResources(name);
+        }
+        return system.getResources(name);
+    }
+
+    /**
+     * Find resources from the VM's built-in classloader.
+     */
+    private static URL getBootstrapResource(String name) {
+        return null;
+    }
+
+    /**
+     * Find resources from the VM's built-in classloader.
+     */
+    private static Enumeration<URL> getBootstrapResources(String name)
+        throws IOException
+    {
+        return null;
+    }
+
+
+
+    /**
+     * Returns an input stream for reading the specified resource.
+     *
+     * <p> The search order is described in the documentation for {@link
+     * #getResource(String)}.  </p>
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An input stream for reading the resource, or <tt>null</tt>
+     *          if the resource could not be found
+     *
+     * @since  1.1
+     */
+    public InputStream getResourceAsStream(String name) {
+        URL url = getResource(name);
+        try {
+            return url != null ? url.openStream() : null;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Open for reading, a resource of the specified name from the search path
+     * used to load classes.  This method locates the resource through the
+     * system class loader (see {@link #getSystemClassLoader()}).
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An input stream for reading the resource, or <tt>null</tt>
+     *          if the resource could not be found
+     *
+     * @since  1.1
+     */
+    public static InputStream getSystemResourceAsStream(String name) {
+        URL url = getSystemResource(name);
+        try {
+            return url != null ? url.openStream() : null;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+
+    // -- Hierarchy --
+
+    /**
+     * Returns the parent class loader for delegation. Some implementations may
+     * use <tt>null</tt> to represent the bootstrap class loader. This method
+     * will return <tt>null</tt> in such implementations if this class loader's
+     * parent is the bootstrap class loader.
+     *
+     * <p> If a security manager is present, and the invoker's class loader is
+     * not <tt>null</tt> and is not an ancestor of this class loader, then this
+     * method invokes the security manager's {@link
+     * SecurityManager#checkPermission(java.security.Permission)
+     * <tt>checkPermission</tt>} method with a {@link
+     * RuntimePermission#RuntimePermission(String)
+     * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
+     * access to the parent class loader is permitted.  If not, a
+     * <tt>SecurityException</tt> will be thrown.  </p>
+     *
+     * @return  The parent <tt>ClassLoader</tt>
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <tt>checkPermission</tt>
+     *          method doesn't allow access to this class loader's parent class
+     *          loader.
+     *
+     * @since  1.2
+     */
+    @CallerSensitive
+    public final ClassLoader getParent() {
+        return parent;
+    }
+
+    // Android-changed: Removed "java.system.class.loader" paragraph.
+    /**
+     * Returns the system class loader for delegation.  This is the default
+     * delegation parent for new <tt>ClassLoader</tt> instances, and is
+     * typically the class loader used to start the application.
+     *
+     * <p> This method is first invoked early in the runtime's startup
+     * sequence, at which point it creates the system class loader and sets it
+     * as the context class loader of the invoking <tt>Thread</tt>.
+     *
+     * <p> The default system class loader is an implementation-dependent
+     * instance of this class.
+     *
+     * <p> If a security manager is present, and the invoker's class loader is
+     * not <tt>null</tt> and the invoker's class loader is not the same as or
+     * an ancestor of the system class loader, then this method invokes the
+     * security manager's {@link
+     * SecurityManager#checkPermission(java.security.Permission)
+     * <tt>checkPermission</tt>} method with a {@link
+     * RuntimePermission#RuntimePermission(String)
+     * <tt>RuntimePermission("getClassLoader")</tt>} permission to verify
+     * access to the system class loader.  If not, a
+     * <tt>SecurityException</tt> will be thrown.  </p>
+     *
+     * @return  The system <tt>ClassLoader</tt> for delegation, or
+     *          <tt>null</tt> if none
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its <tt>checkPermission</tt>
+     *          method doesn't allow access to the system class loader.
+     *
+     * @throws  IllegalStateException
+     *          If invoked recursively during the construction of the class
+     *          loader specified by the "<tt>java.system.class.loader</tt>"
+     *          property.
+     *
+     * @throws  Error
+     *          If the system property "<tt>java.system.class.loader</tt>"
+     *          is defined but the named class could not be loaded, the
+     *          provider class does not define the required constructor, or an
+     *          exception is thrown by that constructor when it is invoked. The
+     *          underlying cause of the error can be retrieved via the
+     *          {@link Throwable#getCause()} method.
+     *
+     * @revised  1.4
+     */
+    @CallerSensitive
+    public static ClassLoader getSystemClassLoader() {
+        return SystemClassLoader.loader;
+    }
+
+    // Returns the class's class loader, or null if none.
+    static ClassLoader getClassLoader(Class<?> caller) {
+        // This can be null if the VM is requesting it
+        if (caller == null) {
+            return null;
+        }
+        // Android-changed: Use Class.getClassLoader(); there is no Class.getClassLoader0().
+        // // Circumvent security check since this is package-private
+        // return caller.getClassLoader0();
+        return caller.getClassLoader();
+    }
+
+    // -- Package --
+
+    /**
+     * Defines a package by name in this <tt>ClassLoader</tt>.  This allows
+     * class loaders to define the packages for their classes. Packages must
+     * be created before the class is defined, and package names must be
+     * unique within a class loader and cannot be redefined or changed once
+     * created.
+     *
+     * @param  name
+     *         The package name
+     *
+     * @param  specTitle
+     *         The specification title
+     *
+     * @param  specVersion
+     *         The specification version
+     *
+     * @param  specVendor
+     *         The specification vendor
+     *
+     * @param  implTitle
+     *         The implementation title
+     *
+     * @param  implVersion
+     *         The implementation version
+     *
+     * @param  implVendor
+     *         The implementation vendor
+     *
+     * @param  sealBase
+     *         If not <tt>null</tt>, then this package is sealed with
+     *         respect to the given code source {@link java.net.URL
+     *         <tt>URL</tt>}  object.  Otherwise, the package is not sealed.
+     *
+     * @return  The newly defined <tt>Package</tt> object
+     *
+     * @throws  IllegalArgumentException
+     *          If package name duplicates an existing package either in this
+     *          class loader or one of its ancestors
+     *
+     * @since  1.2
+     */
+    protected Package definePackage(String name, String specTitle,
+                                    String specVersion, String specVendor,
+                                    String implTitle, String implVersion,
+                                    String implVendor, URL sealBase)
+        throws IllegalArgumentException
+    {
+        synchronized (packages) {
+            Package pkg = packages.get(name);
+            if (pkg != null) {
+                throw new IllegalArgumentException(name);
+            }
+            pkg = new Package(name, specTitle, specVersion, specVendor,
+                              implTitle, implVersion, implVendor,
+                              sealBase, this);
+            packages.put(name, pkg);
+            return pkg;
+        }
+    }
+
+    /**
+     * Returns a <tt>Package</tt> that has been defined by this class loader
+     * or any of its ancestors.
+     *
+     * @param  name
+     *         The package name
+     *
+     * @return  The <tt>Package</tt> corresponding to the given name, or
+     *          <tt>null</tt> if not found
+     *
+     * @since  1.2
+     */
+    protected Package getPackage(String name) {
+        Package pkg;
+        synchronized (packages) {
+            pkg = packages.get(name);
+        }
+        return pkg;
+    }
+
+    /**
+     * Returns all of the <tt>Packages</tt> defined by this class loader and
+     * its ancestors.
+     *
+     * @return  The array of <tt>Package</tt> objects defined by this
+     *          <tt>ClassLoader</tt>
+     *
+     * @since  1.2
+     */
+    protected Package[] getPackages() {
+        Map<String, Package> map;
+        synchronized (packages) {
+            map = new HashMap<>(packages);
+        }
+        Package[] pkgs;
+        return map.values().toArray(new Package[map.size()]);
+    }
+
+
+    // -- Native library access --
+
+    /**
+     * Returns the absolute path name of a native library.  The VM invokes this
+     * method to locate the native libraries that belong to classes loaded with
+     * this class loader. If this method returns <tt>null</tt>, the VM
+     * searches the library along the path specified as the
+     * "<tt>java.library.path</tt>" property.
+     *
+     * @param  libname
+     *         The library name
+     *
+     * @return  The absolute path of the native library
+     *
+     * @see  System#loadLibrary(String)
+     * @see  System#mapLibraryName(String)
+     *
+     * @since  1.2
+     */
+    protected String findLibrary(String libname) {
+        return null;
+    }
+
+    /**
+     * Sets the default assertion status for this class loader.  This setting
+     * determines whether classes loaded by this class loader and initialized
+     * in the future will have assertions enabled or disabled by default.
+     * This setting may be overridden on a per-package or per-class basis by
+     * invoking {@link #setPackageAssertionStatus(String, boolean)} or {@link
+     * #setClassAssertionStatus(String, boolean)}.
+     *
+     * @param  enabled
+     *         <tt>true</tt> if classes loaded by this class loader will
+     *         henceforth have assertions enabled by default, <tt>false</tt>
+     *         if they will have assertions disabled by default.
+     *
+     * @since  1.4
+     */
+    public void setDefaultAssertionStatus(boolean enabled) {
+    }
+
+    /**
+     * Sets the package default assertion status for the named package.  The
+     * package default assertion status determines the assertion status for
+     * classes initialized in the future that belong to the named package or
+     * any of its "subpackages".
+     *
+     * <p> A subpackage of a package named p is any package whose name begins
+     * with "<tt>p.</tt>".  For example, <tt>javax.swing.text</tt> is a
+     * subpackage of <tt>javax.swing</tt>, and both <tt>java.util</tt> and
+     * <tt>java.lang.reflect</tt> are subpackages of <tt>java</tt>.
+     *
+     * <p> In the event that multiple package defaults apply to a given class,
+     * the package default pertaining to the most specific package takes
+     * precedence over the others.  For example, if <tt>javax.lang</tt> and
+     * <tt>javax.lang.reflect</tt> both have package defaults associated with
+     * them, the latter package default applies to classes in
+     * <tt>javax.lang.reflect</tt>.
+     *
+     * <p> Package defaults take precedence over the class loader's default
+     * assertion status, and may be overridden on a per-class basis by invoking
+     * {@link #setClassAssertionStatus(String, boolean)}.  </p>
+     *
+     * @param  packageName
+     *         The name of the package whose package default assertion status
+     *         is to be set. A <tt>null</tt> value indicates the unnamed
+     *         package that is "current"
+     *         (see section 7.4.2 of
+     *         <cite>The Java&trade; Language Specification</cite>.)
+     *
+     * @param  enabled
+     *         <tt>true</tt> if classes loaded by this classloader and
+     *         belonging to the named package or any of its subpackages will
+     *         have assertions enabled by default, <tt>false</tt> if they will
+     *         have assertions disabled by default.
+     *
+     * @since  1.4
+     */
+    public void setPackageAssertionStatus(String packageName,
+                                          boolean enabled) {
+    }
+
+    /**
+     * Sets the desired assertion status for the named top-level class in this
+     * class loader and any nested classes contained therein.  This setting
+     * takes precedence over the class loader's default assertion status, and
+     * over any applicable per-package default.  This method has no effect if
+     * the named class has already been initialized.  (Once a class is
+     * initialized, its assertion status cannot change.)
+     *
+     * <p> If the named class is not a top-level class, this invocation will
+     * have no effect on the actual assertion status of any class. </p>
+     *
+     * @param  className
+     *         The fully qualified class name of the top-level class whose
+     *         assertion status is to be set.
+     *
+     * @param  enabled
+     *         <tt>true</tt> if the named class is to have assertions
+     *         enabled when (and if) it is initialized, <tt>false</tt> if the
+     *         class is to have assertions disabled.
+     *
+     * @since  1.4
+     */
+    public void setClassAssertionStatus(String className, boolean enabled) {
+    }
+
+    /**
+     * Sets the default assertion status for this class loader to
+     * <tt>false</tt> and discards any package defaults or class assertion
+     * status settings associated with the class loader.  This method is
+     * provided so that class loaders can be made to ignore any command line or
+     * persistent assertion status settings and "start with a clean slate."
+     *
+     * @since  1.4
+     */
+    public void clearAssertionStatus() {
+        /*
+         * Whether or not "Java assertion maps" are initialized, set
+         * them to empty maps, effectively ignoring any present settings.
+         */
+    }
+}
+
+
+class BootClassLoader extends ClassLoader {
+
+    private static BootClassLoader instance;
+
+    @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
+    public static synchronized BootClassLoader getInstance() {
+        if (instance == null) {
+            instance = new BootClassLoader();
+        }
+
+        return instance;
+    }
+
+    public BootClassLoader() {
+        super(null);
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        return Class.classForName(name, false, null);
+    }
+
+    @Override
+    protected URL findResource(String name) {
+        return VMClassLoader.getResource(name);
+    }
+
+    @SuppressWarnings("unused")
+    @Override
+    protected Enumeration<URL> findResources(String resName) throws IOException {
+        return Collections.enumeration(VMClassLoader.getResources(resName));
+    }
+
+    /**
+     * Returns package information for the given package. Unfortunately, the
+     * Android BootClassLoader doesn't really have this information, and as a
+     * non-secure ClassLoader, it isn't even required to, according to the spec.
+     * Yet, we want to provide it, in order to make all those hopeful callers of
+     * {@code myClass.getPackage().getName()} happy. Thus we construct a Package
+     * object the first time it is being requested and fill most of the fields
+     * with dummy values. The Package object is then put into the ClassLoader's
+     * Package cache, so we see the same one next time. We don't create Package
+     * objects for null arguments or for the default package.
+     * <p>
+     * There a limited chance that we end up with multiple Package objects
+     * representing the same package: It can happen when when a package is
+     * scattered across different JAR files being loaded by different
+     * ClassLoaders. Rather unlikely, and given that this whole thing is more or
+     * less a workaround, probably not worth the effort.
+     */
+    @Override
+    protected Package getPackage(String name) {
+        if (name != null && !name.isEmpty()) {
+            synchronized (this) {
+                Package pack = super.getPackage(name);
+
+                if (pack == null) {
+                    pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0",
+                            "Unknown", null);
+                }
+
+                return pack;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public URL getResource(String resName) {
+        return findResource(resName);
+    }
+
+    @Override
+    protected Class<?> loadClass(String className, boolean resolve)
+           throws ClassNotFoundException {
+        Class<?> clazz = findLoadedClass(className);
+
+        if (clazz == null) {
+            clazz = findClass(className);
+        }
+
+        return clazz;
+    }
+
+    @Override
+    public Enumeration<URL> getResources(String resName) throws IOException {
+        return findResources(resName);
+    }
+}
diff --git a/java/lang/ClassNotFoundException.java b/java/lang/ClassNotFoundException.java
new file mode 100644
index 0000000..1211e9f
--- /dev/null
+++ b/java/lang/ClassNotFoundException.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application tries to load in a class through its
+ * string name using:
+ * <ul>
+ * <li>The <code>forName</code> method in class <code>Class</code>.
+ * <li>The <code>findSystemClass</code> method in class
+ *     <code>ClassLoader</code> .
+ * <li>The <code>loadClass</code> method in class <code>ClassLoader</code>.
+ * </ul>
+ * <p>
+ * but no definition for the class with the specified name could be found.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to conform to
+ * the general purpose exception-chaining mechanism.  The "optional exception
+ * that was raised while loading the class" that may be provided at
+ * construction time and accessed via the {@link #getException()} method is
+ * now known as the <i>cause</i>, and may be accessed via the {@link
+ * Throwable#getCause()} method, as well as the aforementioned "legacy method."
+ *
+ * @author  unascribed
+ * @see     java.lang.Class#forName(java.lang.String)
+ * @see     java.lang.ClassLoader#findSystemClass(java.lang.String)
+ * @see     java.lang.ClassLoader#loadClass(java.lang.String, boolean)
+ * @since   JDK1.0
+ */
+public class ClassNotFoundException extends ReflectiveOperationException {
+    /**
+     * use serialVersionUID from JDK 1.1.X for interoperability
+     */
+     private static final long serialVersionUID = 9176873029745254542L;
+
+    /**
+     * This field holds the exception ex if the
+     * ClassNotFoundException(String s, Throwable ex) constructor was
+     * used to instantiate the object
+     * @serial
+     * @since 1.2
+     */
+    private Throwable ex;
+
+    /**
+     * Constructs a <code>ClassNotFoundException</code> with no detail message.
+     */
+    public ClassNotFoundException() {
+        super((Throwable)null);  // Disallow initCause
+    }
+
+    /**
+     * Constructs a <code>ClassNotFoundException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public ClassNotFoundException(String s) {
+        super(s, null);  //  Disallow initCause
+    }
+
+    /**
+     * Constructs a <code>ClassNotFoundException</code> with the
+     * specified detail message and optional exception that was
+     * raised while loading the class.
+     *
+     * @param s the detail message
+     * @param ex the exception that was raised while loading the class
+     * @since 1.2
+     */
+    public ClassNotFoundException(String s, Throwable ex) {
+        super(s, null);  //  Disallow initCause
+        this.ex = ex;
+    }
+
+    /**
+     * Returns the exception that was raised if an error occurred while
+     * attempting to load the class. Otherwise, returns <tt>null</tt>.
+     *
+     * <p>This method predates the general-purpose exception chaining facility.
+     * The {@link Throwable#getCause()} method is now the preferred means of
+     * obtaining this information.
+     *
+     * @return the <code>Exception</code> that was raised while loading a class
+     * @since 1.2
+     */
+    public Throwable getException() {
+        return ex;
+    }
+
+    /**
+     * Returns the cause of this exception (the exception that was raised
+     * if an error occurred while attempting to load the class; otherwise
+     * <tt>null</tt>).
+     *
+     * @return  the cause of this exception.
+     * @since   1.4
+     */
+    public Throwable getCause() {
+        return ex;
+    }
+}
diff --git a/java/lang/CloneNotSupportedException.java b/java/lang/CloneNotSupportedException.java
new file mode 100644
index 0000000..e43901c
--- /dev/null
+++ b/java/lang/CloneNotSupportedException.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that the <code>clone</code> method in class
+ * <code>Object</code> has been called to clone an object, but that
+ * the object's class does not implement the <code>Cloneable</code>
+ * interface.
+ * <p>
+ * Applications that override the <code>clone</code> method can also
+ * throw this exception to indicate that an object could not or
+ * should not be cloned.
+ *
+ * @author  unascribed
+ * @see     java.lang.Cloneable
+ * @see     java.lang.Object#clone()
+ * @since   JDK1.0
+ */
+
+public
+class CloneNotSupportedException extends Exception {
+    private static final long serialVersionUID = 5195511250079656443L;
+
+    /**
+     * Constructs a <code>CloneNotSupportedException</code> with no
+     * detail message.
+     */
+    public CloneNotSupportedException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>CloneNotSupportedException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public CloneNotSupportedException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/Cloneable.java b/java/lang/Cloneable.java
new file mode 100644
index 0000000..14cf2a9
--- /dev/null
+++ b/java/lang/Cloneable.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * A class implements the <code>Cloneable</code> interface to
+ * indicate to the {@link java.lang.Object#clone()} method that it
+ * is legal for that method to make a
+ * field-for-field copy of instances of that class.
+ * <p>
+ * Invoking Object's clone method on an instance that does not implement the
+ * <code>Cloneable</code> interface results in the exception
+ * <code>CloneNotSupportedException</code> being thrown.
+ * <p>
+ * By convention, classes that implement this interface should override
+ * <tt>Object.clone</tt> (which is protected) with a public method.
+ * See {@link java.lang.Object#clone()} for details on overriding this
+ * method.
+ * <p>
+ * Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
+ * Therefore, it is not possible to clone an object merely by virtue of the
+ * fact that it implements this interface.  Even if the clone method is invoked
+ * reflectively, there is no guarantee that it will succeed.
+ *
+ * @author  unascribed
+ * @see     java.lang.CloneNotSupportedException
+ * @see     java.lang.Object#clone()
+ * @since   JDK1.0
+ */
+public interface Cloneable {
+}
diff --git a/java/lang/Comparable.java b/java/lang/Comparable.java
new file mode 100644
index 0000000..a88cf16
--- /dev/null
+++ b/java/lang/Comparable.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+import java.util.*;
+
+/**
+ * This interface imposes a total ordering on the objects of each class that
+ * implements it.  This ordering is referred to as the class's <i>natural
+ * ordering</i>, and the class's <tt>compareTo</tt> method is referred to as
+ * its <i>natural comparison method</i>.<p>
+ *
+ * Lists (and arrays) of objects that implement this interface can be sorted
+ * automatically by {@link Collections#sort(List) Collections.sort} (and
+ * {@link Arrays#sort(Object[]) Arrays.sort}).  Objects that implement this
+ * interface can be used as keys in a {@linkplain SortedMap sorted map} or as
+ * elements in a {@linkplain SortedSet sorted set}, without the need to
+ * specify a {@linkplain Comparator comparator}.<p>
+ *
+ * The natural ordering for a class <tt>C</tt> is said to be <i>consistent
+ * with equals</i> if and only if <tt>e1.compareTo(e2) == 0</tt> has
+ * the same boolean value as <tt>e1.equals(e2)</tt> for every
+ * <tt>e1</tt> and <tt>e2</tt> of class <tt>C</tt>.  Note that <tt>null</tt>
+ * is not an instance of any class, and <tt>e.compareTo(null)</tt> should
+ * throw a <tt>NullPointerException</tt> even though <tt>e.equals(null)</tt>
+ * returns <tt>false</tt>.<p>
+ *
+ * It is strongly recommended (though not required) that natural orderings be
+ * consistent with equals.  This is so because sorted sets (and sorted maps)
+ * without explicit comparators behave "strangely" when they are used with
+ * elements (or keys) whose natural ordering is inconsistent with equals.  In
+ * particular, such a sorted set (or sorted map) violates the general contract
+ * for set (or map), which is defined in terms of the <tt>equals</tt>
+ * method.<p>
+ *
+ * For example, if one adds two keys <tt>a</tt> and <tt>b</tt> such that
+ * {@code (!a.equals(b) && a.compareTo(b) == 0)} to a sorted
+ * set that does not use an explicit comparator, the second <tt>add</tt>
+ * operation returns false (and the size of the sorted set does not increase)
+ * because <tt>a</tt> and <tt>b</tt> are equivalent from the sorted set's
+ * perspective.<p>
+ *
+ * Virtually all Java core classes that implement <tt>Comparable</tt> have natural
+ * orderings that are consistent with equals.  One exception is
+ * <tt>java.math.BigDecimal</tt>, whose natural ordering equates
+ * <tt>BigDecimal</tt> objects with equal values and different precisions
+ * (such as 4.0 and 4.00).<p>
+ *
+ * For the mathematically inclined, the <i>relation</i> that defines
+ * the natural ordering on a given class C is:<pre>
+ *       {(x, y) such that x.compareTo(y) &lt;= 0}.
+ * </pre> The <i>quotient</i> for this total order is: <pre>
+ *       {(x, y) such that x.compareTo(y) == 0}.
+ * </pre>
+ *
+ * It follows immediately from the contract for <tt>compareTo</tt> that the
+ * quotient is an <i>equivalence relation</i> on <tt>C</tt>, and that the
+ * natural ordering is a <i>total order</i> on <tt>C</tt>.  When we say that a
+ * class's natural ordering is <i>consistent with equals</i>, we mean that the
+ * quotient for the natural ordering is the equivalence relation defined by
+ * the class's {@link Object#equals(Object) equals(Object)} method:<pre>
+ *     {(x, y) such that x.equals(y)}. </pre><p>
+ *
+ * This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <T> the type of objects that this object may be compared to
+ *
+ * @author  Josh Bloch
+ * @see java.util.Comparator
+ * @since 1.2
+ */
+public interface Comparable<T> {
+    /**
+     * Compares this object with the specified object for order.  Returns a
+     * negative integer, zero, or a positive integer as this object is less
+     * than, equal to, or greater than the specified object.
+     *
+     * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
+     * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
+     * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
+     * <tt>y.compareTo(x)</tt> throws an exception.)
+     *
+     * <p>The implementor must also ensure that the relation is transitive:
+     * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
+     * <tt>x.compareTo(z)&gt;0</tt>.
+     *
+     * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
+     * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
+     * all <tt>z</tt>.
+     *
+     * <p>It is strongly recommended, but <i>not</i> strictly required that
+     * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
+     * class that implements the <tt>Comparable</tt> interface and violates
+     * this condition should clearly indicate this fact.  The recommended
+     * language is "Note: this class has a natural ordering that is
+     * inconsistent with equals."
+     *
+     * <p>In the foregoing description, the notation
+     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
+     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
+     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
+     * <i>expression</i> is negative, zero or positive.
+     *
+     * @param   o the object to be compared.
+     * @return  a negative integer, zero, or a positive integer as this object
+     *          is less than, equal to, or greater than the specified object.
+     *
+     * @throws NullPointerException if the specified object is null
+     * @throws ClassCastException if the specified object's type prevents it
+     *         from being compared to this object.
+     */
+    public int compareTo(T o);
+}
diff --git a/java/lang/Compiler.java b/java/lang/Compiler.java
new file mode 100644
index 0000000..def9a83
--- /dev/null
+++ b/java/lang/Compiler.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Does nothing on Android.
+ */
+public final class Compiler  {
+    /**
+     * Prevent this class from being instantiated.
+     */
+    private Compiler() {}               // don't make instances
+
+    /**
+     * Compiles the specified class using the JIT compiler and indicates if
+     * compilation has been successful. Does nothing and returns false on
+     * Android.
+     *
+     * @param classToCompile
+     *            java.lang.Class the class to JIT compile
+     * @return {@code true} if the compilation has been successful;
+     *         {@code false} if it has failed or if there is no JIT compiler
+     *         available.
+     */
+    public static boolean compileClass(Class<?> classToCompile) {
+        return false;
+    }
+
+    /**
+     * Compiles all classes whose name matches the specified name using the JIT
+     * compiler and indicates if compilation has been successful. Does nothing
+     * and returns false on Android.
+     *
+     * @param nameRoot
+     *            the string to match class names with.
+     * @return {@code true} if the compilation has been successful;
+     *         {@code false} if it has failed or if there is no JIT compiler
+     *         available.
+     */
+    public static boolean compileClasses(String nameRoot) {
+        return false;
+    }
+
+    /**
+     * Executes an operation according to the specified command object. This
+     * method is the low-level interface to the JIT compiler. It may return any
+     * object or {@code null} if no JIT compiler is available. Returns null
+     * on Android, whether or not the system has a JIT.
+     *
+     * @param cmd
+     *            the command object for the JIT compiler.
+     * @return the result of executing command or {@code null}.
+     */
+    public static Object command(Object cmd) {
+        return null;
+    }
+
+    /**
+     * Enables the JIT compiler. Does nothing on Android.
+     */
+    public static void enable() {
+
+    }
+
+    /**
+     * Disables the JIT compiler. Does nothing on Android.
+     */
+    public static void disable() {
+
+    }
+}
diff --git a/java/lang/Daemons.java b/java/lang/Daemons.java
new file mode 100644
index 0000000..568614f
--- /dev/null
+++ b/java/lang/Daemons.java
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 android.compat.annotation.UnsupportedAppUsage;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.lang.ref.FinalizerReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import libcore.util.EmptyArray;
+
+import dalvik.system.VMRuntime;
+import dalvik.system.VMDebug;
+
+/**
+ * Calls Object.finalize() on objects in the finalizer reference queue. The VM
+ * will abort if any finalize() call takes more than the maximum finalize time
+ * to complete.
+ *
+ * @hide
+ */
+public final class Daemons {
+    private static final int NANOS_PER_MILLI = 1000 * 1000;
+
+    // This used to be final. IT IS NOW ONLY WRITTEN. We now update it when we look at the command
+    // line argument, for the benefit of mis-behaved apps that might read it.  SLATED FOR REMOVAL.
+    // There is no reason to use this: Finalizers should not rely on the value. If a finalizer takes
+    // appreciable time, the work should be done elsewhere.  Based on disassembly of Daemons.class,
+    // the value is effectively inlined, so changing the field never did have an effect.
+    // DO NOT USE. FOR ANYTHING. THIS WILL BE REMOVED SHORTLY.
+    @UnsupportedAppUsage
+    private static long MAX_FINALIZE_NANOS = 10L * 1000 * NANOS_PER_MILLI;
+
+    private static final Daemon[] DAEMONS = new Daemon[] {
+            HeapTaskDaemon.INSTANCE,
+            ReferenceQueueDaemon.INSTANCE,
+            FinalizerDaemon.INSTANCE,
+            FinalizerWatchdogDaemon.INSTANCE,
+    };
+    private static final CountDownLatch POST_ZYGOTE_START_LATCH = new CountDownLatch(DAEMONS.length);
+    private static final CountDownLatch PRE_ZYGOTE_START_LATCH = new CountDownLatch(DAEMONS.length);
+
+    private static boolean postZygoteFork = false;
+
+    @UnsupportedAppUsage
+    public static void start() {
+        for (Daemon daemon : DAEMONS) {
+            daemon.start();
+        }
+    }
+
+    public static void startPostZygoteFork() {
+        postZygoteFork = true;
+        for (Daemon daemon : DAEMONS) {
+            daemon.startPostZygoteFork();
+        }
+    }
+
+    @UnsupportedAppUsage
+    public static void stop() {
+        for (Daemon daemon : DAEMONS) {
+            daemon.stop();
+        }
+    }
+
+    private static void waitForDaemonStart() throws Exception {
+        if (postZygoteFork) {
+            POST_ZYGOTE_START_LATCH.await();
+        } else {
+            PRE_ZYGOTE_START_LATCH.await();
+        }
+    }
+
+    /**
+     * A background task that provides runtime support to the application.
+     * Daemons can be stopped and started, but only so that the zygote can be a
+     * single-threaded process when it forks.
+     */
+    private static abstract class Daemon implements Runnable {
+        @UnsupportedAppUsage
+        private Thread thread;
+        private String name;
+        private boolean postZygoteFork;
+
+        protected Daemon(String name) {
+            this.name = name;
+        }
+
+        @UnsupportedAppUsage
+        public synchronized void start() {
+            startInternal();
+        }
+
+        public synchronized void startPostZygoteFork() {
+            postZygoteFork = true;
+            startInternal();
+        }
+
+        public void startInternal() {
+            if (thread != null) {
+                throw new IllegalStateException("already running");
+            }
+            thread = new Thread(ThreadGroup.systemThreadGroup, this, name);
+            thread.setDaemon(true);
+            thread.setSystemDaemon(true);
+            thread.start();
+        }
+
+        public final void run() {
+            if (postZygoteFork) {
+                // We don't set the priority before the Thread.start() call above because
+                // Thread.start() will call SetNativePriority and overwrite the desired native
+                // priority. We (may) use a native priority that doesn't have a corresponding
+                // java.lang.Thread-level priority (native priorities are more coarse-grained.)
+                VMRuntime.getRuntime().setSystemDaemonThreadPriority();
+                POST_ZYGOTE_START_LATCH.countDown();
+            } else {
+                PRE_ZYGOTE_START_LATCH.countDown();
+            }
+            runInternal();
+        }
+
+        public abstract void runInternal();
+
+        /**
+         * Returns true while the current thread should continue to run; false
+         * when it should return.
+         */
+        @UnsupportedAppUsage
+        protected synchronized boolean isRunning() {
+            return thread != null;
+        }
+
+        public synchronized void interrupt() {
+            interrupt(thread);
+        }
+
+        public synchronized void interrupt(Thread thread) {
+            if (thread == null) {
+                throw new IllegalStateException("not running");
+            }
+            thread.interrupt();
+        }
+
+        /**
+         * Waits for the runtime thread to stop. This interrupts the thread
+         * currently running the runnable and then waits for it to exit.
+         */
+        @UnsupportedAppUsage
+        public void stop() {
+            Thread threadToStop;
+            synchronized (this) {
+                threadToStop = thread;
+                thread = null;
+            }
+            if (threadToStop == null) {
+                throw new IllegalStateException("not running");
+            }
+            interrupt(threadToStop);
+            while (true) {
+                try {
+                    threadToStop.join();
+                    return;
+                } catch (InterruptedException ignored) {
+                } catch (OutOfMemoryError ignored) {
+                    // An OOME may be thrown if allocating the InterruptedException failed.
+                }
+            }
+        }
+
+        /**
+         * Returns the current stack trace of the thread, or an empty stack trace
+         * if the thread is not currently running.
+         */
+        public synchronized StackTraceElement[] getStackTrace() {
+            return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT;
+        }
+    }
+
+    /**
+     * This heap management thread moves elements from the garbage collector's
+     * pending list to the managed reference queue.
+     */
+    private static class ReferenceQueueDaemon extends Daemon {
+        @UnsupportedAppUsage
+        private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon();
+
+        ReferenceQueueDaemon() {
+            super("ReferenceQueueDaemon");
+        }
+
+        @Override public void runInternal() {
+            while (isRunning()) {
+                Reference<?> list;
+                try {
+                    synchronized (ReferenceQueue.class) {
+                        while (ReferenceQueue.unenqueued == null) {
+                            ReferenceQueue.class.wait();
+                        }
+                        list = ReferenceQueue.unenqueued;
+                        ReferenceQueue.unenqueued = null;
+                    }
+                } catch (InterruptedException e) {
+                    continue;
+                } catch (OutOfMemoryError e) {
+                    continue;
+                }
+                ReferenceQueue.enqueuePending(list);
+            }
+        }
+    }
+
+    private static class FinalizerDaemon extends Daemon {
+        @UnsupportedAppUsage
+        private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
+        private final ReferenceQueue<Object> queue = FinalizerReference.queue;
+        private final AtomicInteger progressCounter = new AtomicInteger(0);
+        // Object (not reference!) being finalized. Accesses may race!
+        @UnsupportedAppUsage
+        private Object finalizingObject = null;
+
+        FinalizerDaemon() {
+            super("FinalizerDaemon");
+        }
+
+        @Override public void runInternal() {
+            // This loop may be performance critical, since we need to keep up with mutator
+            // generation of finalizable objects.
+            // We minimize the amount of work we do per finalizable object. For example, we avoid
+            // reading the current time here, since that involves a kernel call per object.  We
+            // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A
+            // non-volatile store to communicate the current finalizable object, e.g. for
+            // reporting, and a release store (lazySet) to a counter.
+            // We do stop the  FinalizerWatchDogDaemon if we have nothing to do for a
+            // potentially extended period.  This prevents the device from waking up regularly
+            // during idle times.
+
+            // Local copy of progressCounter; saves a fence per increment on ARM and MIPS.
+            int localProgressCounter = progressCounter.get();
+
+            while (isRunning()) {
+                try {
+                    // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication
+                    // when busy.
+                    FinalizerReference<?> finalizingReference = (FinalizerReference<?>)queue.poll();
+                    if (finalizingReference != null) {
+                        finalizingObject = finalizingReference.get();
+                        progressCounter.lazySet(++localProgressCounter);
+                    } else {
+                        finalizingObject = null;
+                        progressCounter.lazySet(++localProgressCounter);
+                        // Slow path; block.
+                        FinalizerWatchdogDaemon.INSTANCE.goToSleep();
+                        finalizingReference = (FinalizerReference<?>)queue.remove();
+                        finalizingObject = finalizingReference.get();
+                        progressCounter.set(++localProgressCounter);
+                        FinalizerWatchdogDaemon.INSTANCE.wakeUp();
+                    }
+                    doFinalize(finalizingReference);
+                } catch (InterruptedException ignored) {
+                } catch (OutOfMemoryError ignored) {
+                }
+            }
+        }
+
+        @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
+        private void doFinalize(FinalizerReference<?> reference) {
+            FinalizerReference.remove(reference);
+            Object object = reference.get();
+            reference.clear();
+            try {
+                object.finalize();
+            } catch (Throwable ex) {
+                // The RI silently swallows these, but Android has always logged.
+                System.logE("Uncaught exception thrown by finalizer", ex);
+            } finally {
+                // Done finalizing, stop holding the object as live.
+                finalizingObject = null;
+            }
+        }
+    }
+
+    /**
+     * The watchdog exits the VM if the finalizer ever gets stuck. We consider
+     * the finalizer to be stuck if it spends more than MAX_FINALIZATION_MILLIS
+     * on one instance.
+     */
+    private static class FinalizerWatchdogDaemon extends Daemon {
+        @UnsupportedAppUsage
+        private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon();
+
+        private boolean needToWork = true;  // Only accessed in synchronized methods.
+
+        private long finalizerTimeoutMs = 0;  // Lazily initialized.
+
+        FinalizerWatchdogDaemon() {
+            super("FinalizerWatchdogDaemon");
+        }
+
+        @Override public void runInternal() {
+            while (isRunning()) {
+                if (!sleepUntilNeeded()) {
+                    // We have been interrupted, need to see if this daemon has been stopped.
+                    continue;
+                }
+                final Object finalizing = waitForFinalization();
+                if (finalizing != null && !VMDebug.isDebuggerConnected()) {
+                    finalizerTimedOut(finalizing);
+                    break;
+                }
+            }
+        }
+
+        /**
+         * Wait until something is ready to be finalized.
+         * Return false if we have been interrupted
+         * See also http://code.google.com/p/android/issues/detail?id=22778.
+         */
+        private synchronized boolean sleepUntilNeeded() {
+            while (!needToWork) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                    // Daemon.stop may have interrupted us.
+                    return false;
+                } catch (OutOfMemoryError e) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Notify daemon that it's OK to sleep until notified that something is ready to be
+         * finalized.
+         */
+        private synchronized void goToSleep() {
+            needToWork = false;
+        }
+
+        /**
+         * Notify daemon that there is something ready to be finalized.
+         */
+        private synchronized void wakeUp() {
+            needToWork = true;
+            notify();
+        }
+
+        private synchronized boolean getNeedToWork() {
+            return needToWork;
+        }
+
+        /**
+         * Sleep for the given number of milliseconds.
+         * @return false if we were interrupted.
+         */
+        private boolean sleepForMillis(long durationMillis) {
+            long startMillis = System.currentTimeMillis();
+            while (true) {
+                long elapsedMillis = System.currentTimeMillis() - startMillis;
+                long sleepMillis = durationMillis - elapsedMillis;
+                if (sleepMillis <= 0) {
+                    return true;
+                }
+                try {
+                    Thread.sleep(sleepMillis);
+                } catch (InterruptedException e) {
+                    if (!isRunning()) {
+                        return false;
+                    }
+                } catch (OutOfMemoryError ignored) {
+                    if (!isRunning()) {
+                        return false;
+                    }
+                }
+            }
+        }
+
+
+        /**
+         * Return an object that took too long to finalize or return null.
+         * Wait VMRuntime.getFinalizerTimeoutMs.  If the FinalizerDaemon took essentially the
+         * whole time processing a single reference, return that reference.  Otherwise return
+         * null.  Only called from a single thread.
+         */
+        private Object waitForFinalization() {
+            if (finalizerTimeoutMs == 0) {
+                finalizerTimeoutMs = VMRuntime.getRuntime().getFinalizerTimeoutMs();
+                // Temporary app backward compatibility. Remove eventually.
+                MAX_FINALIZE_NANOS = NANOS_PER_MILLI * finalizerTimeoutMs;
+            }
+            long startCount = FinalizerDaemon.INSTANCE.progressCounter.get();
+            // Avoid remembering object being finalized, so as not to keep it alive.
+            if (!sleepForMillis(finalizerTimeoutMs)) {
+                // Don't report possibly spurious timeout if we are interrupted.
+                return null;
+            }
+            if (getNeedToWork() && FinalizerDaemon.INSTANCE.progressCounter.get() == startCount) {
+                // We assume that only remove() and doFinalize() may take time comparable to
+                // the finalizer timeout.
+                // We observed neither the effect of the gotoSleep() nor the increment preceding a
+                // later wakeUp. Any remove() call by the FinalizerDaemon during our sleep
+                // interval must have been followed by a wakeUp call before we checked needToWork.
+                // But then we would have seen the counter increment.  Thus there cannot have
+                // been such a remove() call.
+                // The FinalizerDaemon must not have progressed (from either the beginning or the
+                // last progressCounter increment) to either the next increment or gotoSleep()
+                // call.  Thus we must have taken essentially the whole finalizerTimeoutMs in a
+                // single doFinalize() call.  Thus it's OK to time out.  finalizingObject was set
+                // just before the counter increment, which preceded the doFinalize call.  Thus we
+                // are guaranteed to get the correct finalizing value below, unless doFinalize()
+                // just finished as we were timing out, in which case we may get null or a later
+                // one.  In this last case, we are very likely to discard it below.
+                Object finalizing = FinalizerDaemon.INSTANCE.finalizingObject;
+                sleepForMillis(500);
+                // Recheck to make it even less likely we report the wrong finalizing object in
+                // the case which a very slow finalization just finished as we were timing out.
+                if (getNeedToWork()
+                        && FinalizerDaemon.INSTANCE.progressCounter.get() == startCount) {
+                    return finalizing;
+                }
+            }
+            return null;
+        }
+
+        private static void finalizerTimedOut(Object object) {
+            // The current object has exceeded the finalization deadline; abort!
+            String message = object.getClass().getName() + ".finalize() timed out after "
+                    + VMRuntime.getRuntime().getFinalizerTimeoutMs() / 1000 + " seconds";
+            Exception syntheticException = new TimeoutException(message);
+            // We use the stack from where finalize() was running to show where it was stuck.
+            syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
+
+            // Send SIGQUIT to get native stack traces.
+            try {
+                Os.kill(Os.getpid(), OsConstants.SIGQUIT);
+                // Sleep a few seconds to let the stack traces print.
+                Thread.sleep(5000);
+            } catch (Exception e) {
+                System.logE("failed to send SIGQUIT", e);
+            } catch (OutOfMemoryError ignored) {
+                // May occur while trying to allocate the exception.
+            }
+
+            // Ideally, we'd want to do this if this Thread had no handler to dispatch to.
+            // Unfortunately, it's extremely to messy to query whether a given Thread has *some*
+            // handler to dispatch to, either via a handler set on itself, via its ThreadGroup
+            // object or via the defaultUncaughtExceptionHandler.
+            //
+            // As an approximation, we log by hand an exit if there's no pre-exception handler nor
+            // a default uncaught exception handler.
+            //
+            // Note that this condition will only ever be hit by ART host tests and standalone
+            // dalvikvm invocations. All zygote forked process *will* have a pre-handler set
+            // in RuntimeInit and they cannot subsequently override it.
+            if (Thread.getUncaughtExceptionPreHandler() == null &&
+                    Thread.getDefaultUncaughtExceptionHandler() == null) {
+                // If we have no handler, log and exit.
+                System.logE(message, syntheticException);
+                System.exit(2);
+            }
+
+            // Otherwise call the handler to do crash reporting.
+            // We don't just throw because we're not the thread that
+            // timed out; we're the thread that detected it.
+            Thread.currentThread().dispatchUncaughtException(syntheticException);
+        }
+    }
+
+    // Adds a heap trim task to the heap event processor, not called from java. Left for
+    // compatibility purposes due to reflection.
+    @UnsupportedAppUsage
+    public static void requestHeapTrim() {
+        VMRuntime.getRuntime().requestHeapTrim();
+    }
+
+    // Adds a concurrent GC request task ot the heap event processor, not called from java. Left
+    // for compatibility purposes due to reflection.
+    public static void requestGC() {
+        VMRuntime.getRuntime().requestConcurrentGC();
+    }
+
+    private static class HeapTaskDaemon extends Daemon {
+        private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon();
+
+        HeapTaskDaemon() {
+            super("HeapTaskDaemon");
+        }
+
+        // Overrides the Daemon.interupt method which is called from Daemons.stop.
+        public synchronized void interrupt(Thread thread) {
+            VMRuntime.getRuntime().stopHeapTaskProcessor();
+        }
+
+        @Override public void runInternal() {
+            synchronized (this) {
+                if (isRunning()) {
+                  // Needs to be synchronized or else we there is a race condition where we start
+                  // the thread, call stopHeapTaskProcessor before we start the heap task
+                  // processor, resulting in a deadlock since startHeapTaskProcessor restarts it
+                  // while the other thread is waiting in Daemons.stop().
+                  VMRuntime.getRuntime().startHeapTaskProcessor();
+                }
+            }
+            // This runs tasks until we are stopped and there is no more pending task.
+            VMRuntime.getRuntime().runHeapTasks();
+        }
+    }
+}
diff --git a/java/lang/Deprecated.java b/java/lang/Deprecated.java
new file mode 100644
index 0000000..58a0691
--- /dev/null
+++ b/java/lang/Deprecated.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+/**
+ * A program element annotated &#64;Deprecated is one that programmers
+ * are discouraged from using, typically because it is dangerous,
+ * or because a better alternative exists.  Compilers warn when a
+ * deprecated program element is used or overridden in non-deprecated code.
+ *
+ * @author  Neal Gafter
+ * @since 1.5
+ * @jls 9.6.3.6 @Deprecated
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
+public @interface Deprecated {
+}
diff --git a/java/lang/DexCache.java b/java/lang/DexCache.java
new file mode 100644
index 0000000..e35a69d
--- /dev/null
+++ b/java/lang/DexCache.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * 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 android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * A dex cache holds resolved copies of strings, fields, methods, and classes from the dexfile.
+ */
+final class DexCache {
+    /** The classloader this dex cache is for. */
+    private ClassLoader classLoader;
+
+    /** The location of the associated dex file. */
+    private String location;
+
+    /** Holds C pointer to dexFile. */
+    @UnsupportedAppUsage
+    private long dexFile;
+
+    /**
+     * References to pre resolved strings.
+     */
+    private long preResolvedStrings;
+
+    /**
+     * References to CallSite (C array pointer) as they become resolved following
+     * interpreter semantics.
+     */
+    private long resolvedCallSites;
+
+    /**
+     * References to fields (C array pointer) as they become resolved following
+     * interpreter semantics. May refer to fields defined in other dex files.
+     */
+    private long resolvedFields;
+
+    /**
+     * References to MethodType (C array pointer) as they become resolved following
+     * interpreter semantics.
+     */
+    private long resolvedMethodTypes;
+
+    /**
+     * References to methods (C array pointer) as they become resolved following
+     * interpreter semantics. May refer to methods defined in other dex files.
+     */
+    private long resolvedMethods;
+
+    /**
+     * References to types (C array pointer) as they become resolved following
+     * interpreter semantics. May refer to types defined in other dex files.
+     */
+    private long resolvedTypes;
+
+    /**
+     * References to strings (C array pointer) as they become resolved following
+     * interpreter semantics. All strings are interned.
+     */
+    private long strings;
+
+    /**
+     * The number of elements in the native pre resolved strings array.
+     */
+    private int numPreResolvedStrings;
+
+    /**
+     * The number of elements in the native call sites array.
+     */
+    private int numResolvedCallSites;
+
+    /**
+     * The number of elements in the native resolvedFields array.
+     */
+    private int numResolvedFields;
+
+    /**
+     * The number of elements in the native method types array.
+     */
+    private int numResolvedMethodTypes;
+
+    /**
+     * The number of elements in the native resolvedMethods array.
+     */
+    private int numResolvedMethods;
+
+    /**
+     * The number of elements in the native resolvedTypes array.
+     */
+    private int numResolvedTypes;
+
+    /**
+     * The number of elements in the native strings array.
+     */
+    private int numStrings;
+
+    // Only created by the VM.
+    private DexCache() {}
+}
diff --git a/java/lang/Double.annotated.java b/java/lang/Double.annotated.java
new file mode 100644
index 0000000..8f565fc
--- /dev/null
+++ b/java/lang/Double.annotated.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Double extends java.lang.Number implements java.lang.Comparable<java.lang.Double> {
+
+public Double(double value) { throw new RuntimeException("Stub!"); }
+
+public Double(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(double d) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toHexString(double d) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Double valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Double valueOf(double d) { throw new RuntimeException("Stub!"); }
+
+public static double parseDouble(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static boolean isNaN(double v) { throw new RuntimeException("Stub!"); }
+
+public static boolean isInfinite(double v) { throw new RuntimeException("Stub!"); }
+
+public static boolean isFinite(double d) { throw new RuntimeException("Stub!"); }
+
+public boolean isNaN() { throw new RuntimeException("Stub!"); }
+
+public boolean isInfinite() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public byte byteValue() { throw new RuntimeException("Stub!"); }
+
+public short shortValue() { throw new RuntimeException("Stub!"); }
+
+public int intValue() { throw new RuntimeException("Stub!"); }
+
+public long longValue() { throw new RuntimeException("Stub!"); }
+
+public float floatValue() { throw new RuntimeException("Stub!"); }
+
+public double doubleValue() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(double value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static long doubleToLongBits(double value) { throw new RuntimeException("Stub!"); }
+
+public static native long doubleToRawLongBits(double value);
+
+public static native double longBitsToDouble(long bits);
+
+public int compareTo(@libcore.util.NonNull java.lang.Double anotherDouble) { throw new RuntimeException("Stub!"); }
+
+public static int compare(double d1, double d2) { throw new RuntimeException("Stub!"); }
+
+public static double sum(double a, double b) { throw new RuntimeException("Stub!"); }
+
+public static double max(double a, double b) { throw new RuntimeException("Stub!"); }
+
+public static double min(double a, double b) { throw new RuntimeException("Stub!"); }
+
+public static final int BYTES = 8; // 0x8
+
+public static final int MAX_EXPONENT = 1023; // 0x3ff
+
+public static final double MAX_VALUE = 1.7976931348623157E308;
+
+public static final int MIN_EXPONENT = -1022; // 0xfffffc02
+
+public static final double MIN_NORMAL = 2.2250738585072014E-308;
+
+public static final double MIN_VALUE = 4.9E-324;
+
+public static final double NEGATIVE_INFINITY = (-1.0/0.0);
+
+public static final double NaN = (0.0/0.0);
+
+public static final double POSITIVE_INFINITY = (1.0/0.0);
+
+public static final int SIZE = 64; // 0x40
+
+public static final java.lang.Class<java.lang.Double> TYPE;
+static { TYPE = null; }
+}
+
diff --git a/java/lang/Double.java b/java/lang/Double.java
new file mode 100644
index 0000000..690ca6a
--- /dev/null
+++ b/java/lang/Double.java
@@ -0,0 +1,1058 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import sun.misc.FloatingDecimal;
+import sun.misc.FpUtils;
+import sun.misc.DoubleConsts;
+
+/**
+ * The {@code Double} class wraps a value of the primitive type
+ * {@code double} in an object. An object of type
+ * {@code Double} contains a single field whose type is
+ * {@code double}.
+ *
+ * <p>In addition, this class provides several methods for converting a
+ * {@code double} to a {@code String} and a
+ * {@code String} to a {@code double}, as well as other
+ * constants and methods useful when dealing with a
+ * {@code double}.
+ *
+ * @author  Lee Boynton
+ * @author  Arthur van Hoff
+ * @author  Joseph D. Darcy
+ * @since JDK1.0
+ */
+public final class Double extends Number implements Comparable<Double> {
+    /**
+     * A constant holding the positive infinity of type
+     * {@code double}. It is equal to the value returned by
+     * {@code Double.longBitsToDouble(0x7ff0000000000000L)}.
+     */
+    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
+
+    /**
+     * A constant holding the negative infinity of type
+     * {@code double}. It is equal to the value returned by
+     * {@code Double.longBitsToDouble(0xfff0000000000000L)}.
+     */
+    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
+
+    /**
+     * A constant holding a Not-a-Number (NaN) value of type
+     * {@code double}. It is equivalent to the value returned by
+     * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
+     */
+    public static final double NaN = 0.0d / 0.0;
+
+    /**
+     * A constant holding the largest positive finite value of type
+     * {@code double},
+     * (2-2<sup>-52</sup>)&middot;2<sup>1023</sup>.  It is equal to
+     * the hexadecimal floating-point literal
+     * {@code 0x1.fffffffffffffP+1023} and also equal to
+     * {@code Double.longBitsToDouble(0x7fefffffffffffffL)}.
+     */
+    public static final double MAX_VALUE = 0x1.fffffffffffffP+1023; // 1.7976931348623157e+308
+
+    /**
+     * A constant holding the smallest positive normal value of type
+     * {@code double}, 2<sup>-1022</sup>.  It is equal to the
+     * hexadecimal floating-point literal {@code 0x1.0p-1022} and also
+     * equal to {@code Double.longBitsToDouble(0x0010000000000000L)}.
+     *
+     * @since 1.6
+     */
+    public static final double MIN_NORMAL = 0x1.0p-1022; // 2.2250738585072014E-308
+
+    /**
+     * A constant holding the smallest positive nonzero value of type
+     * {@code double}, 2<sup>-1074</sup>. It is equal to the
+     * hexadecimal floating-point literal
+     * {@code 0x0.0000000000001P-1022} and also equal to
+     * {@code Double.longBitsToDouble(0x1L)}.
+     */
+    public static final double MIN_VALUE = 0x0.0000000000001P-1022; // 4.9e-324
+
+    /**
+     * Maximum exponent a finite {@code double} variable may have.
+     * It is equal to the value returned by
+     * {@code Math.getExponent(Double.MAX_VALUE)}.
+     *
+     * @since 1.6
+     */
+    public static final int MAX_EXPONENT = 1023;
+
+    /**
+     * Minimum exponent a normalized {@code double} variable may
+     * have.  It is equal to the value returned by
+     * {@code Math.getExponent(Double.MIN_NORMAL)}.
+     *
+     * @since 1.6
+     */
+    public static final int MIN_EXPONENT = -1022;
+
+    /**
+     * The number of bits used to represent a {@code double} value.
+     *
+     * @since 1.5
+     */
+    public static final int SIZE = 64;
+
+    /**
+     * The number of bytes used to represent a {@code double} value.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code double}.
+     *
+     * @since JDK1.1
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Double>   TYPE = (Class<Double>) Class.getPrimitiveClass("double");
+
+    /**
+     * Returns a string representation of the {@code double}
+     * argument. All characters mentioned below are ASCII characters.
+     * <ul>
+     * <li>If the argument is NaN, the result is the string
+     *     "{@code NaN}".
+     * <li>Otherwise, the result is a string that represents the sign and
+     * magnitude (absolute value) of the argument. If the sign is negative,
+     * the first character of the result is '{@code -}'
+     * ({@code '\u005Cu002D'}); if the sign is positive, no sign character
+     * appears in the result. As for the magnitude <i>m</i>:
+     * <ul>
+     * <li>If <i>m</i> is infinity, it is represented by the characters
+     * {@code "Infinity"}; thus, positive infinity produces the result
+     * {@code "Infinity"} and negative infinity produces the result
+     * {@code "-Infinity"}.
+     *
+     * <li>If <i>m</i> is zero, it is represented by the characters
+     * {@code "0.0"}; thus, negative zero produces the result
+     * {@code "-0.0"} and positive zero produces the result
+     * {@code "0.0"}.
+     *
+     * <li>If <i>m</i> is greater than or equal to 10<sup>-3</sup> but less
+     * than 10<sup>7</sup>, then it is represented as the integer part of
+     * <i>m</i>, in decimal form with no leading zeroes, followed by
+     * '{@code .}' ({@code '\u005Cu002E'}), followed by one or
+     * more decimal digits representing the fractional part of <i>m</i>.
+     *
+     * <li>If <i>m</i> is less than 10<sup>-3</sup> or greater than or
+     * equal to 10<sup>7</sup>, then it is represented in so-called
+     * "computerized scientific notation." Let <i>n</i> be the unique
+     * integer such that 10<sup><i>n</i></sup> &le; <i>m</i> {@literal <}
+     * 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+     * mathematically exact quotient of <i>m</i> and
+     * 10<sup><i>n</i></sup> so that 1 &le; <i>a</i> {@literal <} 10. The
+     * magnitude is then represented as the integer part of <i>a</i>,
+     * as a single decimal digit, followed by '{@code .}'
+     * ({@code '\u005Cu002E'}), followed by decimal digits
+     * representing the fractional part of <i>a</i>, followed by the
+     * letter '{@code E}' ({@code '\u005Cu0045'}), followed
+     * by a representation of <i>n</i> as a decimal integer, as
+     * produced by the method {@link Integer#toString(int)}.
+     * </ul>
+     * </ul>
+     * How many digits must be printed for the fractional part of
+     * <i>m</i> or <i>a</i>? There must be at least one digit to represent
+     * the fractional part, and beyond that as many, but only as many, more
+     * digits as are needed to uniquely distinguish the argument value from
+     * adjacent values of type {@code double}. That is, suppose that
+     * <i>x</i> is the exact mathematical value represented by the decimal
+     * representation produced by this method for a finite nonzero argument
+     * <i>d</i>. Then <i>d</i> must be the {@code double} value nearest
+     * to <i>x</i>; or if two {@code double} values are equally close
+     * to <i>x</i>, then <i>d</i> must be one of them and the least
+     * significant bit of the significand of <i>d</i> must be {@code 0}.
+     *
+     * <p>To create localized string representations of a floating-point
+     * value, use subclasses of {@link java.text.NumberFormat}.
+     *
+     * @param   d   the {@code double} to be converted.
+     * @return a string representation of the argument.
+     */
+    public static String toString(double d) {
+        return FloatingDecimal.toJavaFormatString(d);
+    }
+
+    /**
+     * Returns a hexadecimal string representation of the
+     * {@code double} argument. All characters mentioned below
+     * are ASCII characters.
+     *
+     * <ul>
+     * <li>If the argument is NaN, the result is the string
+     *     "{@code NaN}".
+     * <li>Otherwise, the result is a string that represents the sign
+     * and magnitude of the argument. If the sign is negative, the
+     * first character of the result is '{@code -}'
+     * ({@code '\u005Cu002D'}); if the sign is positive, no sign
+     * character appears in the result. As for the magnitude <i>m</i>:
+     *
+     * <ul>
+     * <li>If <i>m</i> is infinity, it is represented by the string
+     * {@code "Infinity"}; thus, positive infinity produces the
+     * result {@code "Infinity"} and negative infinity produces
+     * the result {@code "-Infinity"}.
+     *
+     * <li>If <i>m</i> is zero, it is represented by the string
+     * {@code "0x0.0p0"}; thus, negative zero produces the result
+     * {@code "-0x0.0p0"} and positive zero produces the result
+     * {@code "0x0.0p0"}.
+     *
+     * <li>If <i>m</i> is a {@code double} value with a
+     * normalized representation, substrings are used to represent the
+     * significand and exponent fields.  The significand is
+     * represented by the characters {@code "0x1."}
+     * followed by a lowercase hexadecimal representation of the rest
+     * of the significand as a fraction.  Trailing zeros in the
+     * hexadecimal representation are removed unless all the digits
+     * are zero, in which case a single zero is used. Next, the
+     * exponent is represented by {@code "p"} followed
+     * by a decimal string of the unbiased exponent as if produced by
+     * a call to {@link Integer#toString(int) Integer.toString} on the
+     * exponent value.
+     *
+     * <li>If <i>m</i> is a {@code double} value with a subnormal
+     * representation, the significand is represented by the
+     * characters {@code "0x0."} followed by a
+     * hexadecimal representation of the rest of the significand as a
+     * fraction.  Trailing zeros in the hexadecimal representation are
+     * removed. Next, the exponent is represented by
+     * {@code "p-1022"}.  Note that there must be at
+     * least one nonzero digit in a subnormal significand.
+     *
+     * </ul>
+     *
+     * </ul>
+     *
+     * <table border>
+     * <caption>Examples</caption>
+     * <tr><th>Floating-point Value</th><th>Hexadecimal String</th>
+     * <tr><td>{@code 1.0}</td> <td>{@code 0x1.0p0}</td>
+     * <tr><td>{@code -1.0}</td>        <td>{@code -0x1.0p0}</td>
+     * <tr><td>{@code 2.0}</td> <td>{@code 0x1.0p1}</td>
+     * <tr><td>{@code 3.0}</td> <td>{@code 0x1.8p1}</td>
+     * <tr><td>{@code 0.5}</td> <td>{@code 0x1.0p-1}</td>
+     * <tr><td>{@code 0.25}</td>        <td>{@code 0x1.0p-2}</td>
+     * <tr><td>{@code Double.MAX_VALUE}</td>
+     *     <td>{@code 0x1.fffffffffffffp1023}</td>
+     * <tr><td>{@code Minimum Normal Value}</td>
+     *     <td>{@code 0x1.0p-1022}</td>
+     * <tr><td>{@code Maximum Subnormal Value}</td>
+     *     <td>{@code 0x0.fffffffffffffp-1022}</td>
+     * <tr><td>{@code Double.MIN_VALUE}</td>
+     *     <td>{@code 0x0.0000000000001p-1022}</td>
+     * </table>
+     * @param   d   the {@code double} to be converted.
+     * @return a hex string representation of the argument.
+     * @since 1.5
+     * @author Joseph D. Darcy
+     */
+    public static String toHexString(double d) {
+        /*
+         * Modeled after the "a" conversion specifier in C99, section
+         * 7.19.6.1; however, the output of this method is more
+         * tightly specified.
+         */
+        if (!isFinite(d) )
+            // For infinity and NaN, use the decimal output.
+            return Double.toString(d);
+        else {
+            // Initialized to maximum size of output.
+            StringBuilder answer = new StringBuilder(24);
+
+            if (Math.copySign(1.0, d) == -1.0)    // value is negative,
+                answer.append("-");                  // so append sign info
+
+            answer.append("0x");
+
+            d = Math.abs(d);
+
+            if(d == 0.0) {
+                answer.append("0.0p0");
+            } else {
+                boolean subnormal = (d < DoubleConsts.MIN_NORMAL);
+
+                // Isolate significand bits and OR in a high-order bit
+                // so that the string representation has a known
+                // length.
+                long signifBits = (Double.doubleToLongBits(d)
+                                   & DoubleConsts.SIGNIF_BIT_MASK) |
+                    0x1000000000000000L;
+
+                // Subnormal values have a 0 implicit bit; normal
+                // values have a 1 implicit bit.
+                answer.append(subnormal ? "0." : "1.");
+
+                // Isolate the low-order 13 digits of the hex
+                // representation.  If all the digits are zero,
+                // replace with a single 0; otherwise, remove all
+                // trailing zeros.
+                String signif = Long.toHexString(signifBits).substring(3,16);
+                answer.append(signif.equals("0000000000000") ? // 13 zeros
+                              "0":
+                              signif.replaceFirst("0{1,12}$", ""));
+
+                answer.append('p');
+                // If the value is subnormal, use the E_min exponent
+                // value for double; otherwise, extract and report d's
+                // exponent (the representation of a subnormal uses
+                // E_min -1).
+                answer.append(subnormal ?
+                              DoubleConsts.MIN_EXPONENT:
+                              Math.getExponent(d));
+            }
+            return answer.toString();
+        }
+    }
+
+    /**
+     * Returns a {@code Double} object holding the
+     * {@code double} value represented by the argument string
+     * {@code s}.
+     *
+     * <p>If {@code s} is {@code null}, then a
+     * {@code NullPointerException} is thrown.
+     *
+     * <p>Leading and trailing whitespace characters in {@code s}
+     * are ignored.  Whitespace is removed as if by the {@link
+     * String#trim} method; that is, both ASCII space and control
+     * characters are removed. The rest of {@code s} should
+     * constitute a <i>FloatValue</i> as described by the lexical
+     * syntax rules:
+     *
+     * <blockquote>
+     * <dl>
+     * <dt><i>FloatValue:</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code NaN}
+     * <dd><i>Sign<sub>opt</sub></i> {@code Infinity}
+     * <dd><i>Sign<sub>opt</sub> FloatingPointLiteral</i>
+     * <dd><i>Sign<sub>opt</sub> HexFloatingPointLiteral</i>
+     * <dd><i>SignedInteger</i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>HexFloatingPointLiteral</i>:
+     * <dd> <i>HexSignificand BinaryExponent FloatTypeSuffix<sub>opt</sub></i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>HexSignificand:</i>
+     * <dd><i>HexNumeral</i>
+     * <dd><i>HexNumeral</i> {@code .}
+     * <dd>{@code 0x} <i>HexDigits<sub>opt</sub>
+     *     </i>{@code .}<i> HexDigits</i>
+     * <dd>{@code 0X}<i> HexDigits<sub>opt</sub>
+     *     </i>{@code .} <i>HexDigits</i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>BinaryExponent:</i>
+     * <dd><i>BinaryExponentIndicator SignedInteger</i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>BinaryExponentIndicator:</i>
+     * <dd>{@code p}
+     * <dd>{@code P}
+     * </dl>
+     *
+     * </blockquote>
+     *
+     * where <i>Sign</i>, <i>FloatingPointLiteral</i>,
+     * <i>HexNumeral</i>, <i>HexDigits</i>, <i>SignedInteger</i> and
+     * <i>FloatTypeSuffix</i> are as defined in the lexical structure
+     * sections of
+     * <cite>The Java&trade; Language Specification</cite>,
+     * except that underscores are not accepted between digits.
+     * If {@code s} does not have the form of
+     * a <i>FloatValue</i>, then a {@code NumberFormatException}
+     * is thrown. Otherwise, {@code s} is regarded as
+     * representing an exact decimal value in the usual
+     * "computerized scientific notation" or as an exact
+     * hexadecimal value; this exact numerical value is then
+     * conceptually converted to an "infinitely precise"
+     * binary value that is then rounded to type {@code double}
+     * by the usual round-to-nearest rule of IEEE 754 floating-point
+     * arithmetic, which includes preserving the sign of a zero
+     * value.
+     *
+     * Note that the round-to-nearest rule also implies overflow and
+     * underflow behaviour; if the exact value of {@code s} is large
+     * enough in magnitude (greater than or equal to ({@link
+     * #MAX_VALUE} + {@link Math#ulp(double) ulp(MAX_VALUE)}/2),
+     * rounding to {@code double} will result in an infinity and if the
+     * exact value of {@code s} is small enough in magnitude (less
+     * than or equal to {@link #MIN_VALUE}/2), rounding to float will
+     * result in a zero.
+     *
+     * Finally, after rounding a {@code Double} object representing
+     * this {@code double} value is returned.
+     *
+     * <p> To interpret localized string representations of a
+     * floating-point value, use subclasses of {@link
+     * java.text.NumberFormat}.
+     *
+     * <p>Note that trailing format specifiers, specifiers that
+     * determine the type of a floating-point literal
+     * ({@code 1.0f} is a {@code float} value;
+     * {@code 1.0d} is a {@code double} value), do
+     * <em>not</em> influence the results of this method.  In other
+     * words, the numerical value of the input string is converted
+     * directly to the target floating-point type.  The two-step
+     * sequence of conversions, string to {@code float} followed
+     * by {@code float} to {@code double}, is <em>not</em>
+     * equivalent to converting a string directly to
+     * {@code double}. For example, the {@code float}
+     * literal {@code 0.1f} is equal to the {@code double}
+     * value {@code 0.10000000149011612}; the {@code float}
+     * literal {@code 0.1f} represents a different numerical
+     * value than the {@code double} literal
+     * {@code 0.1}. (The numerical value 0.1 cannot be exactly
+     * represented in a binary floating-point number.)
+     *
+     * <p>To avoid calling this method on an invalid string and having
+     * a {@code NumberFormatException} be thrown, the regular
+     * expression below can be used to screen the input string:
+     *
+     * <pre>{@code
+     *  final String Digits     = "(\\p{Digit}+)";
+     *  final String HexDigits  = "(\\p{XDigit}+)";
+     *  // an exponent is 'e' or 'E' followed by an optionally
+     *  // signed decimal integer.
+     *  final String Exp        = "[eE][+-]?"+Digits;
+     *  final String fpRegex    =
+     *      ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
+     *       "[+-]?(" + // Optional sign character
+     *       "NaN|" +           // "NaN" string
+     *       "Infinity|" +      // "Infinity" string
+     *
+     *       // A decimal floating-point string representing a finite positive
+     *       // number without a leading sign has at most five basic pieces:
+     *       // Digits . Digits ExponentPart FloatTypeSuffix
+     *       //
+     *       // Since this method allows integer-only strings as input
+     *       // in addition to strings of floating-point literals, the
+     *       // two sub-patterns below are simplifications of the grammar
+     *       // productions from section 3.10.2 of
+     *       // The Java Language Specification.
+     *
+     *       // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
+     *       "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
+     *
+     *       // . Digits ExponentPart_opt FloatTypeSuffix_opt
+     *       "(\\.("+Digits+")("+Exp+")?)|"+
+     *
+     *       // Hexadecimal strings
+     *       "((" +
+     *        // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
+     *        "(0[xX]" + HexDigits + "(\\.)?)|" +
+     *
+     *        // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
+     *        "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
+     *
+     *        ")[pP][+-]?" + Digits + "))" +
+     *       "[fFdD]?))" +
+     *       "[\\x00-\\x20]*");// Optional trailing "whitespace"
+     *
+     *  if (Pattern.matches(fpRegex, myString))
+     *      Double.valueOf(myString); // Will not throw NumberFormatException
+     *  else {
+     *      // Perform suitable alternative action
+     *  }
+     * }</pre>
+     *
+     * @param      s   the string to be parsed.
+     * @return     a {@code Double} object holding the value
+     *             represented by the {@code String} argument.
+     * @throws     NumberFormatException  if the string does not contain a
+     *             parsable number.
+     */
+    public static Double valueOf(String s) throws NumberFormatException {
+        return new Double(parseDouble(s));
+    }
+
+    /**
+     * Returns a {@code Double} instance representing the specified
+     * {@code double} value.
+     * If a new {@code Double} instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Double(double)}, as this method is likely to yield
+     * significantly better space and time performance by caching
+     * frequently requested values.
+     *
+     * @param  d a double value.
+     * @return a {@code Double} instance representing {@code d}.
+     * @since  1.5
+     */
+    public static Double valueOf(double d) {
+        return new Double(d);
+    }
+
+    /**
+     * Returns a new {@code double} initialized to the value
+     * represented by the specified {@code String}, as performed
+     * by the {@code valueOf} method of class
+     * {@code Double}.
+     *
+     * @param  s   the string to be parsed.
+     * @return the {@code double} value represented by the string
+     *         argument.
+     * @throws NullPointerException  if the string is null
+     * @throws NumberFormatException if the string does not contain
+     *         a parsable {@code double}.
+     * @see    java.lang.Double#valueOf(String)
+     * @since 1.2
+     */
+    public static double parseDouble(String s) throws NumberFormatException {
+        return FloatingDecimal.parseDouble(s);
+    }
+
+    /**
+     * Returns {@code true} if the specified number is a
+     * Not-a-Number (NaN) value, {@code false} otherwise.
+     *
+     * @param   v   the value to be tested.
+     * @return  {@code true} if the value of the argument is NaN;
+     *          {@code false} otherwise.
+     */
+    public static boolean isNaN(double v) {
+        return (v != v);
+    }
+
+    /**
+     * Returns {@code true} if the specified number is infinitely
+     * large in magnitude, {@code false} otherwise.
+     *
+     * @param   v   the value to be tested.
+     * @return  {@code true} if the value of the argument is positive
+     *          infinity or negative infinity; {@code false} otherwise.
+     */
+    public static boolean isInfinite(double v) {
+        return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
+    }
+
+    /**
+     * Returns {@code true} if the argument is a finite floating-point
+     * value; returns {@code false} otherwise (for NaN and infinity
+     * arguments).
+     *
+     * @param d the {@code double} value to be tested
+     * @return {@code true} if the argument is a finite
+     * floating-point value, {@code false} otherwise.
+     * @since 1.8
+     */
+    public static boolean isFinite(double d) {
+        return Math.abs(d) <= DoubleConsts.MAX_VALUE;
+    }
+
+    /**
+     * The value of the Double.
+     *
+     * @serial
+     */
+    private final double value;
+
+    /**
+     * Constructs a newly allocated {@code Double} object that
+     * represents the primitive {@code double} argument.
+     *
+     * @param   value   the value to be represented by the {@code Double}.
+     */
+    public Double(double value) {
+        this.value = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Double} object that
+     * represents the floating-point value of type {@code double}
+     * represented by the string. The string is converted to a
+     * {@code double} value as if by the {@code valueOf} method.
+     *
+     * @param  s  a string to be converted to a {@code Double}.
+     * @throws    NumberFormatException  if the string does not contain a
+     *            parsable number.
+     * @see       java.lang.Double#valueOf(java.lang.String)
+     */
+    public Double(String s) throws NumberFormatException {
+        value = parseDouble(s);
+    }
+
+    /**
+     * Returns {@code true} if this {@code Double} value is
+     * a Not-a-Number (NaN), {@code false} otherwise.
+     *
+     * @return  {@code true} if the value represented by this object is
+     *          NaN; {@code false} otherwise.
+     */
+    public boolean isNaN() {
+        return isNaN(value);
+    }
+
+    /**
+     * Returns {@code true} if this {@code Double} value is
+     * infinitely large in magnitude, {@code false} otherwise.
+     *
+     * @return  {@code true} if the value represented by this object is
+     *          positive infinity or negative infinity;
+     *          {@code false} otherwise.
+     */
+    public boolean isInfinite() {
+        return isInfinite(value);
+    }
+
+    /**
+     * Returns a string representation of this {@code Double} object.
+     * The primitive {@code double} value represented by this
+     * object is converted to a string exactly as if by the method
+     * {@code toString} of one argument.
+     *
+     * @return  a {@code String} representation of this object.
+     * @see java.lang.Double#toString(double)
+     */
+    public String toString() {
+        return toString(value);
+    }
+
+    /**
+     * Returns the value of this {@code Double} as a {@code byte}
+     * after a narrowing primitive conversion.
+     *
+     * @return  the {@code double} value represented by this object
+     *          converted to type {@code byte}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     * @since JDK1.1
+     */
+    public byte byteValue() {
+        return (byte)value;
+    }
+
+    /**
+     * Returns the value of this {@code Double} as a {@code short}
+     * after a narrowing primitive conversion.
+     *
+     * @return  the {@code double} value represented by this object
+     *          converted to type {@code short}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     * @since JDK1.1
+     */
+    public short shortValue() {
+        return (short)value;
+    }
+
+    /**
+     * Returns the value of this {@code Double} as an {@code int}
+     * after a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     *
+     * @return  the {@code double} value represented by this object
+     *          converted to type {@code int}
+     */
+    public int intValue() {
+        return (int)value;
+    }
+
+    /**
+     * Returns the value of this {@code Double} as a {@code long}
+     * after a narrowing primitive conversion.
+     *
+     * @return  the {@code double} value represented by this object
+     *          converted to type {@code long}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public long longValue() {
+        return (long)value;
+    }
+
+    /**
+     * Returns the value of this {@code Double} as a {@code float}
+     * after a narrowing primitive conversion.
+     *
+     * @return  the {@code double} value represented by this object
+     *          converted to type {@code float}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     * @since JDK1.0
+     */
+    public float floatValue() {
+        return (float)value;
+    }
+
+    /**
+     * Returns the {@code double} value of this {@code Double} object.
+     *
+     * @return the {@code double} value represented by this object
+     */
+    public double doubleValue() {
+        return value;
+    }
+
+    /**
+     * Returns a hash code for this {@code Double} object. The
+     * result is the exclusive OR of the two halves of the
+     * {@code long} integer bit representation, exactly as
+     * produced by the method {@link #doubleToLongBits(double)}, of
+     * the primitive {@code double} value represented by this
+     * {@code Double} object. That is, the hash code is the value
+     * of the expression:
+     *
+     * <blockquote>
+     *  {@code (int)(v^(v>>>32))}
+     * </blockquote>
+     *
+     * where {@code v} is defined by:
+     *
+     * <blockquote>
+     *  {@code long v = Double.doubleToLongBits(this.doubleValue());}
+     * </blockquote>
+     *
+     * @return  a {@code hash code} value for this object.
+     */
+    @Override
+    public int hashCode() {
+        return Double.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code double} value; compatible with
+     * {@code Double.hashCode()}.
+     *
+     * @param value the value to hash
+     * @return a hash code value for a {@code double} value.
+     * @since 1.8
+     */
+    public static int hashCode(double value) {
+        long bits = doubleToLongBits(value);
+        return (int)(bits ^ (bits >>> 32));
+    }
+
+    /**
+     * Compares this object against the specified object.  The result
+     * is {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Double} object that
+     * represents a {@code double} that has the same value as the
+     * {@code double} represented by this object. For this
+     * purpose, two {@code double} values are considered to be
+     * the same if and only if the method {@link
+     * #doubleToLongBits(double)} returns the identical
+     * {@code long} value when applied to each.
+     *
+     * <p>Note that in most cases, for two instances of class
+     * {@code Double}, {@code d1} and {@code d2}, the
+     * value of {@code d1.equals(d2)} is {@code true} if and
+     * only if
+     *
+     * <blockquote>
+     *  {@code d1.doubleValue() == d2.doubleValue()}
+     * </blockquote>
+     *
+     * <p>also has the value {@code true}. However, there are two
+     * exceptions:
+     * <ul>
+     * <li>If {@code d1} and {@code d2} both represent
+     *     {@code Double.NaN}, then the {@code equals} method
+     *     returns {@code true}, even though
+     *     {@code Double.NaN==Double.NaN} has the value
+     *     {@code false}.
+     * <li>If {@code d1} represents {@code +0.0} while
+     *     {@code d2} represents {@code -0.0}, or vice versa,
+     *     the {@code equal} test has the value {@code false},
+     *     even though {@code +0.0==-0.0} has the value {@code true}.
+     * </ul>
+     * This definition allows hash tables to operate properly.
+     * @param   obj   the object to compare with.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see java.lang.Double#doubleToLongBits(double)
+     */
+    public boolean equals(Object obj) {
+        return (obj instanceof Double)
+               && (doubleToLongBits(((Double)obj).value) ==
+                      doubleToLongBits(value));
+    }
+
+    /**
+     * Returns a representation of the specified floating-point value
+     * according to the IEEE 754 floating-point "double
+     * format" bit layout.
+     *
+     * <p>Bit 63 (the bit that is selected by the mask
+     * {@code 0x8000000000000000L}) represents the sign of the
+     * floating-point number. Bits
+     * 62-52 (the bits that are selected by the mask
+     * {@code 0x7ff0000000000000L}) represent the exponent. Bits 51-0
+     * (the bits that are selected by the mask
+     * {@code 0x000fffffffffffffL}) represent the significand
+     * (sometimes called the mantissa) of the floating-point number.
+     *
+     * <p>If the argument is positive infinity, the result is
+     * {@code 0x7ff0000000000000L}.
+     *
+     * <p>If the argument is negative infinity, the result is
+     * {@code 0xfff0000000000000L}.
+     *
+     * <p>If the argument is NaN, the result is
+     * {@code 0x7ff8000000000000L}.
+     *
+     * <p>In all cases, the result is a {@code long} integer that, when
+     * given to the {@link #longBitsToDouble(long)} method, will produce a
+     * floating-point value the same as the argument to
+     * {@code doubleToLongBits} (except all NaN values are
+     * collapsed to a single "canonical" NaN value).
+     *
+     * @param   value   a {@code double} precision floating-point number.
+     * @return the bits that represent the floating-point number.
+     */
+    public static long doubleToLongBits(double value) {
+        long result = doubleToRawLongBits(value);
+        // Check for NaN based on values of bit fields, maximum
+        // exponent and nonzero significand.
+        if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
+              DoubleConsts.EXP_BIT_MASK) &&
+             (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
+            result = 0x7ff8000000000000L;
+        return result;
+    }
+
+    /**
+     * Returns a representation of the specified floating-point value
+     * according to the IEEE 754 floating-point "double
+     * format" bit layout, preserving Not-a-Number (NaN) values.
+     *
+     * <p>Bit 63 (the bit that is selected by the mask
+     * {@code 0x8000000000000000L}) represents the sign of the
+     * floating-point number. Bits
+     * 62-52 (the bits that are selected by the mask
+     * {@code 0x7ff0000000000000L}) represent the exponent. Bits 51-0
+     * (the bits that are selected by the mask
+     * {@code 0x000fffffffffffffL}) represent the significand
+     * (sometimes called the mantissa) of the floating-point number.
+     *
+     * <p>If the argument is positive infinity, the result is
+     * {@code 0x7ff0000000000000L}.
+     *
+     * <p>If the argument is negative infinity, the result is
+     * {@code 0xfff0000000000000L}.
+     *
+     * <p>If the argument is NaN, the result is the {@code long}
+     * integer representing the actual NaN value.  Unlike the
+     * {@code doubleToLongBits} method,
+     * {@code doubleToRawLongBits} does not collapse all the bit
+     * patterns encoding a NaN to a single "canonical" NaN
+     * value.
+     *
+     * <p>In all cases, the result is a {@code long} integer that,
+     * when given to the {@link #longBitsToDouble(long)} method, will
+     * produce a floating-point value the same as the argument to
+     * {@code doubleToRawLongBits}.
+     *
+     * @param   value   a {@code double} precision floating-point number.
+     * @return the bits that represent the floating-point number.
+     * @since 1.3
+     */
+    public static native long doubleToRawLongBits(double value);
+
+    /**
+     * Returns the {@code double} value corresponding to a given
+     * bit representation.
+     * The argument is considered to be a representation of a
+     * floating-point value according to the IEEE 754 floating-point
+     * "double format" bit layout.
+     *
+     * <p>If the argument is {@code 0x7ff0000000000000L}, the result
+     * is positive infinity.
+     *
+     * <p>If the argument is {@code 0xfff0000000000000L}, the result
+     * is negative infinity.
+     *
+     * <p>If the argument is any value in the range
+     * {@code 0x7ff0000000000001L} through
+     * {@code 0x7fffffffffffffffL} or in the range
+     * {@code 0xfff0000000000001L} through
+     * {@code 0xffffffffffffffffL}, the result is a NaN.  No IEEE
+     * 754 floating-point operation provided by Java can distinguish
+     * between two NaN values of the same type with different bit
+     * patterns.  Distinct values of NaN are only distinguishable by
+     * use of the {@code Double.doubleToRawLongBits} method.
+     *
+     * <p>In all other cases, let <i>s</i>, <i>e</i>, and <i>m</i> be three
+     * values that can be computed from the argument:
+     *
+     * <blockquote><pre>{@code
+     * int s = ((bits >> 63) == 0) ? 1 : -1;
+     * int e = (int)((bits >> 52) & 0x7ffL);
+     * long m = (e == 0) ?
+     *                 (bits & 0xfffffffffffffL) << 1 :
+     *                 (bits & 0xfffffffffffffL) | 0x10000000000000L;
+     * }</pre></blockquote>
+     *
+     * Then the floating-point result equals the value of the mathematical
+     * expression <i>s</i>&middot;<i>m</i>&middot;2<sup><i>e</i>-1075</sup>.
+     *
+     * <p>Note that this method may not be able to return a
+     * {@code double} NaN with exactly same bit pattern as the
+     * {@code long} argument.  IEEE 754 distinguishes between two
+     * kinds of NaNs, quiet NaNs and <i>signaling NaNs</i>.  The
+     * differences between the two kinds of NaN are generally not
+     * visible in Java.  Arithmetic operations on signaling NaNs turn
+     * them into quiet NaNs with a different, but often similar, bit
+     * pattern.  However, on some processors merely copying a
+     * signaling NaN also performs that conversion.  In particular,
+     * copying a signaling NaN to return it to the calling method
+     * may perform this conversion.  So {@code longBitsToDouble}
+     * may not be able to return a {@code double} with a
+     * signaling NaN bit pattern.  Consequently, for some
+     * {@code long} values,
+     * {@code doubleToRawLongBits(longBitsToDouble(start))} may
+     * <i>not</i> equal {@code start}.  Moreover, which
+     * particular bit patterns represent signaling NaNs is platform
+     * dependent; although all NaN bit patterns, quiet or signaling,
+     * must be in the NaN range identified above.
+     *
+     * @param   bits   any {@code long} integer.
+     * @return  the {@code double} floating-point value with the same
+     *          bit pattern.
+     */
+    public static native double longBitsToDouble(long bits);
+
+    /**
+     * Compares two {@code Double} objects numerically.  There
+     * are two ways in which comparisons performed by this method
+     * differ from those performed by the Java language numerical
+     * comparison operators ({@code <, <=, ==, >=, >})
+     * when applied to primitive {@code double} values:
+     * <ul><li>
+     *          {@code Double.NaN} is considered by this method
+     *          to be equal to itself and greater than all other
+     *          {@code double} values (including
+     *          {@code Double.POSITIVE_INFINITY}).
+     * <li>
+     *          {@code 0.0d} is considered by this method to be greater
+     *          than {@code -0.0d}.
+     * </ul>
+     * This ensures that the <i>natural ordering</i> of
+     * {@code Double} objects imposed by this method is <i>consistent
+     * with equals</i>.
+     *
+     * @param   anotherDouble   the {@code Double} to be compared.
+     * @return  the value {@code 0} if {@code anotherDouble} is
+     *          numerically equal to this {@code Double}; a value
+     *          less than {@code 0} if this {@code Double}
+     *          is numerically less than {@code anotherDouble};
+     *          and a value greater than {@code 0} if this
+     *          {@code Double} is numerically greater than
+     *          {@code anotherDouble}.
+     *
+     * @since   1.2
+     */
+    public int compareTo(Double anotherDouble) {
+        return Double.compare(value, anotherDouble.value);
+    }
+
+    /**
+     * Compares the two specified {@code double} values. The sign
+     * of the integer value returned is the same as that of the
+     * integer that would be returned by the call:
+     * <pre>
+     *    new Double(d1).compareTo(new Double(d2))
+     * </pre>
+     *
+     * @param   d1        the first {@code double} to compare
+     * @param   d2        the second {@code double} to compare
+     * @return  the value {@code 0} if {@code d1} is
+     *          numerically equal to {@code d2}; a value less than
+     *          {@code 0} if {@code d1} is numerically less than
+     *          {@code d2}; and a value greater than {@code 0}
+     *          if {@code d1} is numerically greater than
+     *          {@code d2}.
+     * @since 1.4
+     */
+    public static int compare(double d1, double d2) {
+        if (d1 < d2)
+            return -1;           // Neither val is NaN, thisVal is smaller
+        if (d1 > d2)
+            return 1;            // Neither val is NaN, thisVal is larger
+
+        // Cannot use doubleToRawLongBits because of possibility of NaNs.
+        long thisBits    = Double.doubleToLongBits(d1);
+        long anotherBits = Double.doubleToLongBits(d2);
+
+        return (thisBits == anotherBits ?  0 : // Values are equal
+                (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
+                 1));                          // (0.0, -0.0) or (NaN, !NaN)
+    }
+
+    /**
+     * Adds two {@code double} values together as per the + operator.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the sum of {@code a} and {@code b}
+     * @jls 4.2.4 Floating-Point Operations
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static double sum(double a, double b) {
+        return a + b;
+    }
+
+    /**
+     * Returns the greater of two {@code double} values
+     * as if by calling {@link Math#max(double, double) Math.max}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the greater of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static double max(double a, double b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code double} values
+     * as if by calling {@link Math#min(double, double) Math.min}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the smaller of {@code a} and {@code b}.
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static double min(double a, double b) {
+        return Math.min(a, b);
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -9172774392245257468L;
+}
diff --git a/java/lang/Enum.annotated.java b/java/lang/Enum.annotated.java
new file mode 100644
index 0000000..b49785e
--- /dev/null
+++ b/java/lang/Enum.annotated.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Enum<E extends java.lang.Enum<E>> implements java.lang.Comparable<E>, java.io.Serializable {
+
+protected Enum(@libcore.util.NonNull java.lang.String name, int ordinal) { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String name() { throw new RuntimeException("Stub!"); }
+
+public final int ordinal() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public final boolean equals(@libcore.util.Nullable java.lang.Object other) { throw new RuntimeException("Stub!"); }
+
+public final int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] protected final java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
+public final int compareTo(@libcore.util.NullFromTypeParam E o) { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.Class<E> getDeclaringClass() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T extends java.lang.Enum<T>> T valueOf(@libcore.util.NonNull java.lang.Class<T> enumType, @libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+protected final void finalize() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/Enum.java b/java/lang/Enum.java
new file mode 100644
index 0000000..988c133
--- /dev/null
+++ b/java/lang/Enum.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.Serializable;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Objects;
+import libcore.util.BasicLruCache;
+import libcore.util.EmptyArray;
+
+/**
+ * This is the common base class of all Java language enumeration types.
+ *
+ * More information about enums, including descriptions of the
+ * implicitly declared methods synthesized by the compiler, can be
+ * found in section 8.9 of
+ * <cite>The Java&trade; Language Specification</cite>.
+ *
+ * <p> Note that when using an enumeration type as the type of a set
+ * or as the type of the keys in a map, specialized and efficient
+ * {@linkplain java.util.EnumSet set} and {@linkplain
+ * java.util.EnumMap map} implementations are available.
+ *
+ * @param <E> The enum type subclass
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Class#getEnumConstants()
+ * @see     java.util.EnumSet
+ * @see     java.util.EnumMap
+ * @since   1.5
+ */
+public abstract class Enum<E extends Enum<E>>
+        implements Comparable<E>, Serializable {
+    /**
+     * The name of this enum constant, as declared in the enum declaration.
+     * Most programmers should use the {@link #toString} method rather than
+     * accessing this field.
+     */
+    private final String name;
+
+    /**
+     * Returns the name of this enum constant, exactly as declared in its
+     * enum declaration.
+     *
+     * <b>Most programmers should use the {@link #toString} method in
+     * preference to this one, as the toString method may return
+     * a more user-friendly name.</b>  This method is designed primarily for
+     * use in specialized situations where correctness depends on getting the
+     * exact name, which will not vary from release to release.
+     *
+     * @return the name of this enum constant
+     */
+    public final String name() {
+        return name;
+    }
+
+    /**
+     * The ordinal of this enumeration constant (its position
+     * in the enum declaration, where the initial constant is assigned
+     * an ordinal of zero).
+     *
+     * Most programmers will have no use for this field.  It is designed
+     * for use by sophisticated enum-based data structures, such as
+     * {@link java.util.EnumSet} and {@link java.util.EnumMap}.
+     */
+    private final int ordinal;
+
+    /**
+     * Returns the ordinal of this enumeration constant (its position
+     * in its enum declaration, where the initial constant is assigned
+     * an ordinal of zero).
+     *
+     * Most programmers will have no use for this method.  It is
+     * designed for use by sophisticated enum-based data structures, such
+     * as {@link java.util.EnumSet} and {@link java.util.EnumMap}.
+     *
+     * @return the ordinal of this enumeration constant
+     */
+    public final int ordinal() {
+        return ordinal;
+    }
+
+    /**
+     * Sole constructor.  Programmers cannot invoke this constructor.
+     * It is for use by code emitted by the compiler in response to
+     * enum type declarations.
+     *
+     * @param name - The name of this enum constant, which is the identifier
+     *               used to declare it.
+     * @param ordinal - The ordinal of this enumeration constant (its position
+     *         in the enum declaration, where the initial constant is assigned
+     *         an ordinal of zero).
+     */
+    protected Enum(String name, int ordinal) {
+        this.name = name;
+        this.ordinal = ordinal;
+    }
+
+    /**
+     * Returns the name of this enum constant, as contained in the
+     * declaration.  This method may be overridden, though it typically
+     * isn't necessary or desirable.  An enum type should override this
+     * method when a more "programmer-friendly" string form exists.
+     *
+     * @return the name of this enum constant
+     */
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * Returns true if the specified object is equal to this
+     * enum constant.
+     *
+     * @param other the object to be compared for equality with this object.
+     * @return  true if the specified object is equal to this
+     *          enum constant.
+     */
+    public final boolean equals(Object other) {
+        return this==other;
+    }
+
+    /**
+     * Returns a hash code for this enum constant.
+     *
+     * @return a hash code for this enum constant.
+     */
+    public final int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * Throws CloneNotSupportedException.  This guarantees that enums
+     * are never cloned, which is necessary to preserve their "singleton"
+     * status.
+     *
+     * @return (never returns)
+     */
+    protected final Object clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    /**
+     * Compares this enum with the specified object for order.  Returns a
+     * negative integer, zero, or a positive integer as this object is less
+     * than, equal to, or greater than the specified object.
+     *
+     * Enum constants are only comparable to other enum constants of the
+     * same enum type.  The natural order implemented by this
+     * method is the order in which the constants are declared.
+     */
+    public final int compareTo(E o) {
+        Enum<?> other = (Enum<?>)o;
+        Enum<E> self = this;
+        if (self.getClass() != other.getClass() && // optimization
+            self.getDeclaringClass() != other.getDeclaringClass())
+            throw new ClassCastException();
+        return self.ordinal - other.ordinal;
+    }
+
+    /**
+     * Returns the Class object corresponding to this enum constant's
+     * enum type.  Two enum constants e1 and  e2 are of the
+     * same enum type if and only if
+     *   e1.getDeclaringClass() == e2.getDeclaringClass().
+     * (The value returned by this method may differ from the one returned
+     * by the {@link Object#getClass} method for enum constants with
+     * constant-specific class bodies.)
+     *
+     * @return the Class object corresponding to this enum constant's
+     *     enum type
+     */
+    @SuppressWarnings("unchecked")
+    public final Class<E> getDeclaringClass() {
+        Class<?> clazz = getClass();
+        Class<?> zuper = clazz.getSuperclass();
+        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
+    }
+
+    /**
+     * Returns the enum constant of the specified enum type with the
+     * specified name.  The name must match exactly an identifier used
+     * to declare an enum constant in this type.  (Extraneous whitespace
+     * characters are not permitted.)
+     *
+     * <p>Note that for a particular enum type {@code T}, the
+     * implicitly declared {@code public static T valueOf(String)}
+     * method on that enum may be used instead of this method to map
+     * from a name to the corresponding enum constant.  All the
+     * constants of an enum type can be obtained by calling the
+     * implicit {@code public static T[] values()} method of that
+     * type.
+     *
+     * @param <T> The enum type whose constant is to be returned
+     * @param enumType the {@code Class} object of the enum type from which
+     *      to return a constant
+     * @param name the name of the constant to return
+     * @return the enum constant of the specified enum type with the
+     *      specified name
+     * @throws IllegalArgumentException if the specified enum type has
+     *         no constant with the specified name, or the specified
+     *         class object does not represent an enum type
+     * @throws NullPointerException if {@code enumType} or {@code name}
+     *         is null
+     * @since 1.5
+     */
+    // BEGIN Android-changed: Use a static BasicLruCache mapping Enum class -> Enum instance array.
+    // This change was made to fix a performance regression. See b/4087759 and b/109791362 for more
+    // background information.
+    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
+                                                String name) {
+        Objects.requireNonNull(enumType, "enumType == null");
+        Objects.requireNonNull(enumType, "name == null");
+        T[] values = getSharedConstants(enumType);
+        if (values == null) {
+            throw new IllegalArgumentException(enumType.toString() + " is not an enum type.");
+        }
+
+        // Iterate backwards through the array to retain historic Android behavior in the
+        // unexpected / likely invalid case where there are multiple values with the same name.
+        for (int i = values.length - 1; i >= 0; --i) {
+            T value = values[i];
+            if (name.equals(value.name())) {
+                return value;
+            }
+        }
+        throw new IllegalArgumentException(
+                "No enum constant " + enumType.getCanonicalName() + "." + name);
+    }
+
+    private static Object[] enumValues(Class<? extends Enum> clazz) {
+        if (!clazz.isEnum()) {
+            // Either clazz is Enum.class itself, or it is not an enum class and the method was
+            // called unsafely e.g. using an unchecked cast or via reflection.
+            return null;
+        }
+        try {
+            Method valueMethod = clazz.getDeclaredMethod("values");
+            return (Object[]) valueMethod.invoke(null);
+        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static final BasicLruCache<Class<? extends Enum>, Object[]> sharedConstantsCache
+            = new BasicLruCache<Class<? extends Enum>, Object[]>(64) {
+        @Override protected Object[] create(Class<? extends Enum> enumType) {
+            return enumValues(enumType);
+        }
+    };
+
+    /**
+     * Returns a shared, mutable array containing the constants of this enum. It
+     * is an error to modify the returned array.
+     *
+     * @hide
+     */
+    @SuppressWarnings("unchecked") // the cache always returns the type matching enumType
+    public static <T extends Enum<T>> T[] getSharedConstants(Class<T> enumType) {
+        return (T[]) sharedConstantsCache.get(enumType);
+    }
+    // END Android-changed: Use a static BasicLruCache mapping Enum class -> Enum instance array.
+
+    /**
+     * enum classes cannot have finalize methods.
+     */
+    protected final void finalize() { }
+
+    /**
+     * prevent default deserialization
+     */
+    private void readObject(ObjectInputStream in) throws IOException,
+        ClassNotFoundException {
+        throw new InvalidObjectException("can't deserialize enum");
+    }
+
+    private void readObjectNoData() throws ObjectStreamException {
+        throw new InvalidObjectException("can't deserialize enum");
+    }
+}
diff --git a/java/lang/EnumConstantNotPresentException.java b/java/lang/EnumConstantNotPresentException.java
new file mode 100644
index 0000000..1773160
--- /dev/null
+++ b/java/lang/EnumConstantNotPresentException.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application tries to access an enum constant by name
+ * and the enum type contains no constant with the specified name.
+ * This exception can be thrown by the {@linkplain
+ * java.lang.reflect.AnnotatedElement API used to read annotations
+ * reflectively}.
+ *
+ * @author  Josh Bloch
+ * @see     java.lang.reflect.AnnotatedElement
+ * @since   1.5
+ */
+@SuppressWarnings("rawtypes") /* rawtypes are part of the public api */
+public class EnumConstantNotPresentException extends RuntimeException {
+    private static final long serialVersionUID = -6046998521960521108L;
+
+    /**
+     * The type of the missing enum constant.
+     */
+    private Class<? extends Enum> enumType;
+
+    /**
+     * The name of the missing enum constant.
+     */
+    private String constantName;
+
+    /**
+     * Constructs an <tt>EnumConstantNotPresentException</tt> for the
+     * specified constant.
+     *
+     * @param enumType the type of the missing enum constant
+     * @param constantName the name of the missing enum constant
+     */
+    public EnumConstantNotPresentException(Class<? extends Enum> enumType,
+                                           String constantName) {
+        super(enumType.getName() + "." + constantName);
+        this.enumType = enumType;
+        this.constantName  = constantName;
+    }
+
+    /**
+     * Returns the type of the missing enum constant.
+     *
+     * @return the type of the missing enum constant
+     */
+    public Class<? extends Enum> enumType() { return enumType; }
+
+    /**
+     * Returns the name of the missing enum constant.
+     *
+     * @return the name of the missing enum constant
+     */
+    public String constantName() { return constantName; }
+}
diff --git a/java/lang/Error.java b/java/lang/Error.java
new file mode 100644
index 0000000..d18c15f
--- /dev/null
+++ b/java/lang/Error.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * An {@code Error} is a subclass of {@code Throwable}
+ * that indicates serious problems that a reasonable application
+ * should not try to catch. Most such errors are abnormal conditions.
+ * The {@code ThreadDeath} error, though a "normal" condition,
+ * is also a subclass of {@code Error} because most applications
+ * should not try to catch it.
+ * <p>
+ * A method is not required to declare in its {@code throws}
+ * clause any subclasses of {@code Error} that might be thrown
+ * during the execution of the method but not caught, since these
+ * errors are abnormal conditions that should never occur.
+ *
+ * That is, {@code Error} and its subclasses are regarded as unchecked
+ * exceptions for the purposes of compile-time checking of exceptions.
+ *
+ * @author  Frank Yellin
+ * @see     java.lang.ThreadDeath
+ * @jls 11.2 Compile-Time Checking of Exceptions
+ * @since   JDK1.0
+ */
+public class Error extends Throwable {
+    static final long serialVersionUID = 4980196508277280342L;
+
+    /**
+     * Constructs a new error with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public Error() {
+        super();
+    }
+
+    /**
+     * Constructs a new error with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param   message   the detail message. The detail message is saved for
+     *          later retrieval by the {@link #getMessage()} method.
+     */
+    public Error(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new error with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this error's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public Error(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new error with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}).
+     * This constructor is useful for errors that are little more than
+     * wrappers for other throwables.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public Error(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new error with the specified detail message,
+     * cause, suppression enabled or disabled, and writable stack
+     * trace enabled or disabled.
+     *
+     * @param  message the detail message.
+     * @param cause the cause.  (A {@code null} value is permitted,
+     * and indicates that the cause is nonexistent or unknown.)
+     * @param enableSuppression whether or not suppression is enabled
+     *                          or disabled
+     * @param writableStackTrace whether or not the stack trace should
+     *                           be writable
+     *
+     * @since 1.7
+     */
+    protected Error(String message, Throwable cause,
+                    boolean enableSuppression,
+                    boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/java/lang/Exception.java b/java/lang/Exception.java
new file mode 100644
index 0000000..0bcbf9c
--- /dev/null
+++ b/java/lang/Exception.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * The class {@code Exception} and its subclasses are a form of
+ * {@code Throwable} that indicates conditions that a reasonable
+ * application might want to catch.
+ *
+ * <p>The class {@code Exception} and any subclasses that are not also
+ * subclasses of {@link RuntimeException} are <em>checked
+ * exceptions</em>.  Checked exceptions need to be declared in a
+ * method or constructor's {@code throws} clause if they can be thrown
+ * by the execution of the method or constructor and propagate outside
+ * the method or constructor boundary.
+ *
+ * @author  Frank Yellin
+ * @see     java.lang.Error
+ * @jls 11.2 Compile-Time Checking of Exceptions
+ * @since   JDK1.0
+ */
+public class Exception extends Throwable {
+    static final long serialVersionUID = -3387516993124229948L;
+
+    /**
+     * Constructs a new exception with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     */
+    public Exception() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * @param   message   the detail message. The detail message is saved for
+     *          later retrieval by the {@link #getMessage()} method.
+     */
+    public Exception(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public Exception(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public Exception(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message,
+     * cause, suppression enabled or disabled, and writable stack
+     * trace enabled or disabled.
+     *
+     * @param  message the detail message.
+     * @param cause the cause.  (A {@code null} value is permitted,
+     * and indicates that the cause is nonexistent or unknown.)
+     * @param enableSuppression whether or not suppression is enabled
+     *                          or disabled
+     * @param writableStackTrace whether or not the stack trace should
+     *                           be writable
+     * @since 1.7
+     */
+    protected Exception(String message, Throwable cause,
+                        boolean enableSuppression,
+                        boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/java/lang/ExceptionInInitializerError.java b/java/lang/ExceptionInInitializerError.java
new file mode 100644
index 0000000..0259766
--- /dev/null
+++ b/java/lang/ExceptionInInitializerError.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Signals that an unexpected exception has occurred in a static initializer.
+ * An <code>ExceptionInInitializerError</code> is thrown to indicate that an
+ * exception occurred during evaluation of a static initializer or the
+ * initializer for a static variable.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to conform to
+ * the general purpose exception-chaining mechanism.  The "saved throwable
+ * object" that may be provided at construction time and accessed via
+ * the {@link #getException()} method is now known as the <i>cause</i>,
+ * and may be accessed via the {@link Throwable#getCause()} method, as well
+ * as the aforementioned "legacy method."
+ *
+ * @author  Frank Yellin
+ * @since   JDK1.1
+ */
+public class ExceptionInInitializerError extends LinkageError {
+    /**
+     * Use serialVersionUID from JDK 1.1.X for interoperability
+     */
+    private static final long serialVersionUID = 1521711792217232256L;
+
+    /**
+     * This field holds the exception if the
+     * ExceptionInInitializerError(Throwable thrown) constructor was
+     * used to instantiate the object
+     *
+     * @serial
+     *
+     */
+    private Throwable exception;
+
+    /**
+     * Constructs an <code>ExceptionInInitializerError</code> with
+     * <code>null</code> as its detail message string and with no saved
+     * throwable object.
+     * A detail message is a String that describes this particular exception.
+     */
+    public ExceptionInInitializerError() {
+        initCause(null);  // Disallow subsequent initCause
+    }
+
+    /**
+     * Constructs a new <code>ExceptionInInitializerError</code> class by
+     * saving a reference to the <code>Throwable</code> object thrown for
+     * later retrieval by the {@link #getException()} method. The detail
+     * message string is set to <code>null</code>.
+     *
+     * @param thrown The exception thrown
+     */
+    public ExceptionInInitializerError(Throwable thrown) {
+        initCause(null);  // Disallow subsequent initCause
+        this.exception = thrown;
+    }
+
+    /**
+     * Constructs an ExceptionInInitializerError with the specified detail
+     * message string.  A detail message is a String that describes this
+     * particular exception. The detail message string is saved for later
+     * retrieval by the {@link Throwable#getMessage()} method. There is no
+     * saved throwable object.
+     *
+     *
+     * @param s the detail message
+     */
+    public ExceptionInInitializerError(String s) {
+        super(s);
+        initCause(null);  // Disallow subsequent initCause
+    }
+
+    /**
+     * Returns the exception that occurred during a static initialization that
+     * caused this error to be created.
+     *
+     * <p>This method predates the general-purpose exception chaining facility.
+     * The {@link Throwable#getCause()} method is now the preferred means of
+     * obtaining this information.
+     *
+     * @return the saved throwable object of this
+     *         <code>ExceptionInInitializerError</code>, or <code>null</code>
+     *         if this <code>ExceptionInInitializerError</code> has no saved
+     *         throwable object.
+     */
+    public Throwable getException() {
+        return exception;
+    }
+
+    /**
+     * Returns the cause of this error (the exception that occurred
+     * during a static initialization that caused this error to be created).
+     *
+     * @return  the cause of this error or <code>null</code> if the
+     *          cause is nonexistent or unknown.
+     * @since   1.4
+     */
+    public Throwable getCause() {
+        return exception;
+    }
+}
diff --git a/java/lang/FindBugsSuppressWarnings.java b/java/lang/FindBugsSuppressWarnings.java
new file mode 100644
index 0000000..ac753bd
--- /dev/null
+++ b/java/lang/FindBugsSuppressWarnings.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 static java.lang.annotation.ElementType.CONSTRUCTOR;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.ElementType.TYPE;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.CLASS;
+import java.lang.annotation.Target;
+
+/**
+ * Suppress FindBugs warnings on the annotated element. FindBugs will recognize
+ * any annotation that has class retention and whose name ends with
+ * "SuppressWarnings".
+ *
+ * @hide
+ */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(CLASS)
+public @interface FindBugsSuppressWarnings {
+
+    /**
+     * The <a href="http://findbugs.sourceforge.net/bugDescriptions.html">FindBugs
+     * Patterns</a> to suppress, such as {@code SE_TRANSIENT_FIELD_NOT_RESTORED}
+     * or {@code Se}. Full, upper case names are preferred.
+     */
+    String[] value();
+}
diff --git a/java/lang/Float.annotated.java b/java/lang/Float.annotated.java
new file mode 100644
index 0000000..a459ec1
--- /dev/null
+++ b/java/lang/Float.annotated.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Float extends java.lang.Number implements java.lang.Comparable<java.lang.Float> {
+
+public Float(float value) { throw new RuntimeException("Stub!"); }
+
+public Float(double value) { throw new RuntimeException("Stub!"); }
+
+public Float(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toHexString(float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Float valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Float valueOf(float f) { throw new RuntimeException("Stub!"); }
+
+public static float parseFloat(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static boolean isNaN(float v) { throw new RuntimeException("Stub!"); }
+
+public static boolean isInfinite(float v) { throw new RuntimeException("Stub!"); }
+
+public static boolean isFinite(float f) { throw new RuntimeException("Stub!"); }
+
+public boolean isNaN() { throw new RuntimeException("Stub!"); }
+
+public boolean isInfinite() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public byte byteValue() { throw new RuntimeException("Stub!"); }
+
+public short shortValue() { throw new RuntimeException("Stub!"); }
+
+public int intValue() { throw new RuntimeException("Stub!"); }
+
+public long longValue() { throw new RuntimeException("Stub!"); }
+
+public float floatValue() { throw new RuntimeException("Stub!"); }
+
+public double doubleValue() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(float value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static int floatToIntBits(float value) { throw new RuntimeException("Stub!"); }
+
+public static native int floatToRawIntBits(float value);
+
+public static native float intBitsToFloat(int bits);
+
+public int compareTo(@libcore.util.NonNull java.lang.Float anotherFloat) { throw new RuntimeException("Stub!"); }
+
+public static int compare(float f1, float f2) { throw new RuntimeException("Stub!"); }
+
+public static float sum(float a, float b) { throw new RuntimeException("Stub!"); }
+
+public static float max(float a, float b) { throw new RuntimeException("Stub!"); }
+
+public static float min(float a, float b) { throw new RuntimeException("Stub!"); }
+
+public static final int BYTES = 4; // 0x4
+
+public static final int MAX_EXPONENT = 127; // 0x7f
+
+public static final float MAX_VALUE = 3.4028235E38f;
+
+public static final int MIN_EXPONENT = -126; // 0xffffff82
+
+public static final float MIN_NORMAL = 1.17549435E-38f;
+
+public static final float MIN_VALUE = 1.4E-45f;
+
+public static final float NEGATIVE_INFINITY = (-1.0f/0.0f);
+
+public static final float NaN = (0.0f/0.0f);
+
+public static final float POSITIVE_INFINITY = (1.0f/0.0f);
+
+public static final int SIZE = 32; // 0x20
+
+public static final java.lang.Class<java.lang.Float> TYPE;
+static { TYPE = null; }
+}
+
diff --git a/java/lang/Float.java b/java/lang/Float.java
new file mode 100644
index 0000000..5cc28f9
--- /dev/null
+++ b/java/lang/Float.java
@@ -0,0 +1,965 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import sun.misc.FloatingDecimal;
+import sun.misc.FloatConsts;
+import sun.misc.DoubleConsts;
+
+/**
+ * The {@code Float} class wraps a value of primitive type
+ * {@code float} in an object. An object of type
+ * {@code Float} contains a single field whose type is
+ * {@code float}.
+ *
+ * <p>In addition, this class provides several methods for converting a
+ * {@code float} to a {@code String} and a
+ * {@code String} to a {@code float}, as well as other
+ * constants and methods useful when dealing with a
+ * {@code float}.
+ *
+ * @author  Lee Boynton
+ * @author  Arthur van Hoff
+ * @author  Joseph D. Darcy
+ * @since JDK1.0
+ */
+public final class Float extends Number implements Comparable<Float> {
+    /**
+     * A constant holding the positive infinity of type
+     * {@code float}. It is equal to the value returned by
+     * {@code Float.intBitsToFloat(0x7f800000)}.
+     */
+    public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
+
+    /**
+     * A constant holding the negative infinity of type
+     * {@code float}. It is equal to the value returned by
+     * {@code Float.intBitsToFloat(0xff800000)}.
+     */
+    public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
+
+    /**
+     * A constant holding a Not-a-Number (NaN) value of type
+     * {@code float}.  It is equivalent to the value returned by
+     * {@code Float.intBitsToFloat(0x7fc00000)}.
+     */
+    public static final float NaN = 0.0f / 0.0f;
+
+    /**
+     * A constant holding the largest positive finite value of type
+     * {@code float}, (2-2<sup>-23</sup>)&middot;2<sup>127</sup>.
+     * It is equal to the hexadecimal floating-point literal
+     * {@code 0x1.fffffeP+127f} and also equal to
+     * {@code Float.intBitsToFloat(0x7f7fffff)}.
+     */
+    public static final float MAX_VALUE = 0x1.fffffeP+127f; // 3.4028235e+38f
+
+    /**
+     * A constant holding the smallest positive normal value of type
+     * {@code float}, 2<sup>-126</sup>.  It is equal to the
+     * hexadecimal floating-point literal {@code 0x1.0p-126f} and also
+     * equal to {@code Float.intBitsToFloat(0x00800000)}.
+     *
+     * @since 1.6
+     */
+    public static final float MIN_NORMAL = 0x1.0p-126f; // 1.17549435E-38f
+
+    /**
+     * A constant holding the smallest positive nonzero value of type
+     * {@code float}, 2<sup>-149</sup>. It is equal to the
+     * hexadecimal floating-point literal {@code 0x0.000002P-126f}
+     * and also equal to {@code Float.intBitsToFloat(0x1)}.
+     */
+    public static final float MIN_VALUE = 0x0.000002P-126f; // 1.4e-45f
+
+    /**
+     * Maximum exponent a finite {@code float} variable may have.  It
+     * is equal to the value returned by {@code
+     * Math.getExponent(Float.MAX_VALUE)}.
+     *
+     * @since 1.6
+     */
+    public static final int MAX_EXPONENT = 127;
+
+    /**
+     * Minimum exponent a normalized {@code float} variable may have.
+     * It is equal to the value returned by {@code
+     * Math.getExponent(Float.MIN_NORMAL)}.
+     *
+     * @since 1.6
+     */
+    public static final int MIN_EXPONENT = -126;
+
+    /**
+     * The number of bits used to represent a {@code float} value.
+     *
+     * @since 1.5
+     */
+    public static final int SIZE = 32;
+
+    /**
+     * The number of bytes used to represent a {@code float} value.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code float}.
+     *
+     * @since JDK1.1
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Float> TYPE = (Class<Float>) Class.getPrimitiveClass("float");
+
+    /**
+     * Returns a string representation of the {@code float}
+     * argument. All characters mentioned below are ASCII characters.
+     * <ul>
+     * <li>If the argument is NaN, the result is the string
+     * "{@code NaN}".
+     * <li>Otherwise, the result is a string that represents the sign and
+     *     magnitude (absolute value) of the argument. If the sign is
+     *     negative, the first character of the result is
+     *     '{@code -}' ({@code '\u005Cu002D'}); if the sign is
+     *     positive, no sign character appears in the result. As for
+     *     the magnitude <i>m</i>:
+     * <ul>
+     * <li>If <i>m</i> is infinity, it is represented by the characters
+     *     {@code "Infinity"}; thus, positive infinity produces
+     *     the result {@code "Infinity"} and negative infinity
+     *     produces the result {@code "-Infinity"}.
+     * <li>If <i>m</i> is zero, it is represented by the characters
+     *     {@code "0.0"}; thus, negative zero produces the result
+     *     {@code "-0.0"} and positive zero produces the result
+     *     {@code "0.0"}.
+     * <li> If <i>m</i> is greater than or equal to 10<sup>-3</sup> but
+     *      less than 10<sup>7</sup>, then it is represented as the
+     *      integer part of <i>m</i>, in decimal form with no leading
+     *      zeroes, followed by '{@code .}'
+     *      ({@code '\u005Cu002E'}), followed by one or more
+     *      decimal digits representing the fractional part of
+     *      <i>m</i>.
+     * <li> If <i>m</i> is less than 10<sup>-3</sup> or greater than or
+     *      equal to 10<sup>7</sup>, then it is represented in
+     *      so-called "computerized scientific notation." Let <i>n</i>
+     *      be the unique integer such that 10<sup><i>n</i> </sup>&le;
+     *      <i>m</i> {@literal <} 10<sup><i>n</i>+1</sup>; then let <i>a</i>
+     *      be the mathematically exact quotient of <i>m</i> and
+     *      10<sup><i>n</i></sup> so that 1 &le; <i>a</i> {@literal <} 10.
+     *      The magnitude is then represented as the integer part of
+     *      <i>a</i>, as a single decimal digit, followed by
+     *      '{@code .}' ({@code '\u005Cu002E'}), followed by
+     *      decimal digits representing the fractional part of
+     *      <i>a</i>, followed by the letter '{@code E}'
+     *      ({@code '\u005Cu0045'}), followed by a representation
+     *      of <i>n</i> as a decimal integer, as produced by the
+     *      method {@link java.lang.Integer#toString(int)}.
+     *
+     * </ul>
+     * </ul>
+     * How many digits must be printed for the fractional part of
+     * <i>m</i> or <i>a</i>? There must be at least one digit
+     * to represent the fractional part, and beyond that as many, but
+     * only as many, more digits as are needed to uniquely distinguish
+     * the argument value from adjacent values of type
+     * {@code float}. That is, suppose that <i>x</i> is the
+     * exact mathematical value represented by the decimal
+     * representation produced by this method for a finite nonzero
+     * argument <i>f</i>. Then <i>f</i> must be the {@code float}
+     * value nearest to <i>x</i>; or, if two {@code float} values are
+     * equally close to <i>x</i>, then <i>f</i> must be one of
+     * them and the least significant bit of the significand of
+     * <i>f</i> must be {@code 0}.
+     *
+     * <p>To create localized string representations of a floating-point
+     * value, use subclasses of {@link java.text.NumberFormat}.
+     *
+     * @param   f   the float to be converted.
+     * @return a string representation of the argument.
+     */
+    public static String toString(float f) {
+        return FloatingDecimal.toJavaFormatString(f);
+    }
+
+    /**
+     * Returns a hexadecimal string representation of the
+     * {@code float} argument. All characters mentioned below are
+     * ASCII characters.
+     *
+     * <ul>
+     * <li>If the argument is NaN, the result is the string
+     *     "{@code NaN}".
+     * <li>Otherwise, the result is a string that represents the sign and
+     * magnitude (absolute value) of the argument. If the sign is negative,
+     * the first character of the result is '{@code -}'
+     * ({@code '\u005Cu002D'}); if the sign is positive, no sign character
+     * appears in the result. As for the magnitude <i>m</i>:
+     *
+     * <ul>
+     * <li>If <i>m</i> is infinity, it is represented by the string
+     * {@code "Infinity"}; thus, positive infinity produces the
+     * result {@code "Infinity"} and negative infinity produces
+     * the result {@code "-Infinity"}.
+     *
+     * <li>If <i>m</i> is zero, it is represented by the string
+     * {@code "0x0.0p0"}; thus, negative zero produces the result
+     * {@code "-0x0.0p0"} and positive zero produces the result
+     * {@code "0x0.0p0"}.
+     *
+     * <li>If <i>m</i> is a {@code float} value with a
+     * normalized representation, substrings are used to represent the
+     * significand and exponent fields.  The significand is
+     * represented by the characters {@code "0x1."}
+     * followed by a lowercase hexadecimal representation of the rest
+     * of the significand as a fraction.  Trailing zeros in the
+     * hexadecimal representation are removed unless all the digits
+     * are zero, in which case a single zero is used. Next, the
+     * exponent is represented by {@code "p"} followed
+     * by a decimal string of the unbiased exponent as if produced by
+     * a call to {@link Integer#toString(int) Integer.toString} on the
+     * exponent value.
+     *
+     * <li>If <i>m</i> is a {@code float} value with a subnormal
+     * representation, the significand is represented by the
+     * characters {@code "0x0."} followed by a
+     * hexadecimal representation of the rest of the significand as a
+     * fraction.  Trailing zeros in the hexadecimal representation are
+     * removed. Next, the exponent is represented by
+     * {@code "p-126"}.  Note that there must be at
+     * least one nonzero digit in a subnormal significand.
+     *
+     * </ul>
+     *
+     * </ul>
+     *
+     * <table border>
+     * <caption>Examples</caption>
+     * <tr><th>Floating-point Value</th><th>Hexadecimal String</th>
+     * <tr><td>{@code 1.0}</td> <td>{@code 0x1.0p0}</td>
+     * <tr><td>{@code -1.0}</td>        <td>{@code -0x1.0p0}</td>
+     * <tr><td>{@code 2.0}</td> <td>{@code 0x1.0p1}</td>
+     * <tr><td>{@code 3.0}</td> <td>{@code 0x1.8p1}</td>
+     * <tr><td>{@code 0.5}</td> <td>{@code 0x1.0p-1}</td>
+     * <tr><td>{@code 0.25}</td>        <td>{@code 0x1.0p-2}</td>
+     * <tr><td>{@code Float.MAX_VALUE}</td>
+     *     <td>{@code 0x1.fffffep127}</td>
+     * <tr><td>{@code Minimum Normal Value}</td>
+     *     <td>{@code 0x1.0p-126}</td>
+     * <tr><td>{@code Maximum Subnormal Value}</td>
+     *     <td>{@code 0x0.fffffep-126}</td>
+     * <tr><td>{@code Float.MIN_VALUE}</td>
+     *     <td>{@code 0x0.000002p-126}</td>
+     * </table>
+     * @param   f   the {@code float} to be converted.
+     * @return a hex string representation of the argument.
+     * @since 1.5
+     * @author Joseph D. Darcy
+     */
+    public static String toHexString(float f) {
+        if (Math.abs(f) < FloatConsts.MIN_NORMAL
+            &&  f != 0.0f ) {// float subnormal
+            // Adjust exponent to create subnormal double, then
+            // replace subnormal double exponent with subnormal float
+            // exponent
+            String s = Double.toHexString(Math.scalb((double)f,
+                                                     /* -1022+126 */
+                                                     DoubleConsts.MIN_EXPONENT-
+                                                     FloatConsts.MIN_EXPONENT));
+            return s.replaceFirst("p-1022$", "p-126");
+        }
+        else // double string will be the same as float string
+            return Double.toHexString(f);
+    }
+
+    /**
+     * Returns a {@code Float} object holding the
+     * {@code float} value represented by the argument string
+     * {@code s}.
+     *
+     * <p>If {@code s} is {@code null}, then a
+     * {@code NullPointerException} is thrown.
+     *
+     * <p>Leading and trailing whitespace characters in {@code s}
+     * are ignored.  Whitespace is removed as if by the {@link
+     * String#trim} method; that is, both ASCII space and control
+     * characters are removed. The rest of {@code s} should
+     * constitute a <i>FloatValue</i> as described by the lexical
+     * syntax rules:
+     *
+     * <blockquote>
+     * <dl>
+     * <dt><i>FloatValue:</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code NaN}
+     * <dd><i>Sign<sub>opt</sub></i> {@code Infinity}
+     * <dd><i>Sign<sub>opt</sub> FloatingPointLiteral</i>
+     * <dd><i>Sign<sub>opt</sub> HexFloatingPointLiteral</i>
+     * <dd><i>SignedInteger</i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>HexFloatingPointLiteral</i>:
+     * <dd> <i>HexSignificand BinaryExponent FloatTypeSuffix<sub>opt</sub></i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>HexSignificand:</i>
+     * <dd><i>HexNumeral</i>
+     * <dd><i>HexNumeral</i> {@code .}
+     * <dd>{@code 0x} <i>HexDigits<sub>opt</sub>
+     *     </i>{@code .}<i> HexDigits</i>
+     * <dd>{@code 0X}<i> HexDigits<sub>opt</sub>
+     *     </i>{@code .} <i>HexDigits</i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>BinaryExponent:</i>
+     * <dd><i>BinaryExponentIndicator SignedInteger</i>
+     * </dl>
+     *
+     * <dl>
+     * <dt><i>BinaryExponentIndicator:</i>
+     * <dd>{@code p}
+     * <dd>{@code P}
+     * </dl>
+     *
+     * </blockquote>
+     *
+     * where <i>Sign</i>, <i>FloatingPointLiteral</i>,
+     * <i>HexNumeral</i>, <i>HexDigits</i>, <i>SignedInteger</i> and
+     * <i>FloatTypeSuffix</i> are as defined in the lexical structure
+     * sections of
+     * <cite>The Java&trade; Language Specification</cite>,
+     * except that underscores are not accepted between digits.
+     * If {@code s} does not have the form of
+     * a <i>FloatValue</i>, then a {@code NumberFormatException}
+     * is thrown. Otherwise, {@code s} is regarded as
+     * representing an exact decimal value in the usual
+     * "computerized scientific notation" or as an exact
+     * hexadecimal value; this exact numerical value is then
+     * conceptually converted to an "infinitely precise"
+     * binary value that is then rounded to type {@code float}
+     * by the usual round-to-nearest rule of IEEE 754 floating-point
+     * arithmetic, which includes preserving the sign of a zero
+     * value.
+     *
+     * Note that the round-to-nearest rule also implies overflow and
+     * underflow behaviour; if the exact value of {@code s} is large
+     * enough in magnitude (greater than or equal to ({@link
+     * #MAX_VALUE} + {@link Math#ulp(float) ulp(MAX_VALUE)}/2),
+     * rounding to {@code float} will result in an infinity and if the
+     * exact value of {@code s} is small enough in magnitude (less
+     * than or equal to {@link #MIN_VALUE}/2), rounding to float will
+     * result in a zero.
+     *
+     * Finally, after rounding a {@code Float} object representing
+     * this {@code float} value is returned.
+     *
+     * <p>To interpret localized string representations of a
+     * floating-point value, use subclasses of {@link
+     * java.text.NumberFormat}.
+     *
+     * <p>Note that trailing format specifiers, specifiers that
+     * determine the type of a floating-point literal
+     * ({@code 1.0f} is a {@code float} value;
+     * {@code 1.0d} is a {@code double} value), do
+     * <em>not</em> influence the results of this method.  In other
+     * words, the numerical value of the input string is converted
+     * directly to the target floating-point type.  In general, the
+     * two-step sequence of conversions, string to {@code double}
+     * followed by {@code double} to {@code float}, is
+     * <em>not</em> equivalent to converting a string directly to
+     * {@code float}.  For example, if first converted to an
+     * intermediate {@code double} and then to
+     * {@code float}, the string<br>
+     * {@code "1.00000017881393421514957253748434595763683319091796875001d"}<br>
+     * results in the {@code float} value
+     * {@code 1.0000002f}; if the string is converted directly to
+     * {@code float}, <code>1.000000<b>1</b>f</code> results.
+     *
+     * <p>To avoid calling this method on an invalid string and having
+     * a {@code NumberFormatException} be thrown, the documentation
+     * for {@link Double#valueOf Double.valueOf} lists a regular
+     * expression which can be used to screen the input.
+     *
+     * @param   s   the string to be parsed.
+     * @return  a {@code Float} object holding the value
+     *          represented by the {@code String} argument.
+     * @throws  NumberFormatException  if the string does not contain a
+     *          parsable number.
+     */
+    public static Float valueOf(String s) throws NumberFormatException {
+        return new Float(parseFloat(s));
+    }
+
+    /**
+     * Returns a {@code Float} instance representing the specified
+     * {@code float} value.
+     * If a new {@code Float} instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Float(float)}, as this method is likely to yield
+     * significantly better space and time performance by caching
+     * frequently requested values.
+     *
+     * @param  f a float value.
+     * @return a {@code Float} instance representing {@code f}.
+     * @since  1.5
+     */
+    public static Float valueOf(float f) {
+        return new Float(f);
+    }
+
+    /**
+     * Returns a new {@code float} initialized to the value
+     * represented by the specified {@code String}, as performed
+     * by the {@code valueOf} method of class {@code Float}.
+     *
+     * @param  s the string to be parsed.
+     * @return the {@code float} value represented by the string
+     *         argument.
+     * @throws NullPointerException  if the string is null
+     * @throws NumberFormatException if the string does not contain a
+     *               parsable {@code float}.
+     * @see    java.lang.Float#valueOf(String)
+     * @since 1.2
+     */
+    public static float parseFloat(String s) throws NumberFormatException {
+        return FloatingDecimal.parseFloat(s);
+    }
+
+    /**
+     * Returns {@code true} if the specified number is a
+     * Not-a-Number (NaN) value, {@code false} otherwise.
+     *
+     * @param   v   the value to be tested.
+     * @return  {@code true} if the argument is NaN;
+     *          {@code false} otherwise.
+     */
+    public static boolean isNaN(float v) {
+        return (v != v);
+    }
+
+    /**
+     * Returns {@code true} if the specified number is infinitely
+     * large in magnitude, {@code false} otherwise.
+     *
+     * @param   v   the value to be tested.
+     * @return  {@code true} if the argument is positive infinity or
+     *          negative infinity; {@code false} otherwise.
+     */
+    public static boolean isInfinite(float v) {
+        return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
+    }
+
+
+    /**
+     * Returns {@code true} if the argument is a finite floating-point
+     * value; returns {@code false} otherwise (for NaN and infinity
+     * arguments).
+     *
+     * @param f the {@code float} value to be tested
+     * @return {@code true} if the argument is a finite
+     * floating-point value, {@code false} otherwise.
+     * @since 1.8
+     */
+     public static boolean isFinite(float f) {
+        return Math.abs(f) <= FloatConsts.MAX_VALUE;
+    }
+
+    /**
+     * The value of the Float.
+     *
+     * @serial
+     */
+    private final float value;
+
+    /**
+     * Constructs a newly allocated {@code Float} object that
+     * represents the primitive {@code float} argument.
+     *
+     * @param   value   the value to be represented by the {@code Float}.
+     */
+    public Float(float value) {
+        this.value = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Float} object that
+     * represents the argument converted to type {@code float}.
+     *
+     * @param   value   the value to be represented by the {@code Float}.
+     */
+    public Float(double value) {
+        this.value = (float)value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Float} object that
+     * represents the floating-point value of type {@code float}
+     * represented by the string. The string is converted to a
+     * {@code float} value as if by the {@code valueOf} method.
+     *
+     * @param      s   a string to be converted to a {@code Float}.
+     * @throws  NumberFormatException  if the string does not contain a
+     *               parsable number.
+     * @see        java.lang.Float#valueOf(java.lang.String)
+     */
+    public Float(String s) throws NumberFormatException {
+        value = parseFloat(s);
+    }
+
+    /**
+     * Returns {@code true} if this {@code Float} value is a
+     * Not-a-Number (NaN), {@code false} otherwise.
+     *
+     * @return  {@code true} if the value represented by this object is
+     *          NaN; {@code false} otherwise.
+     */
+    public boolean isNaN() {
+        return isNaN(value);
+    }
+
+    /**
+     * Returns {@code true} if this {@code Float} value is
+     * infinitely large in magnitude, {@code false} otherwise.
+     *
+     * @return  {@code true} if the value represented by this object is
+     *          positive infinity or negative infinity;
+     *          {@code false} otherwise.
+     */
+    public boolean isInfinite() {
+        return isInfinite(value);
+    }
+
+    /**
+     * Returns a string representation of this {@code Float} object.
+     * The primitive {@code float} value represented by this object
+     * is converted to a {@code String} exactly as if by the method
+     * {@code toString} of one argument.
+     *
+     * @return  a {@code String} representation of this object.
+     * @see java.lang.Float#toString(float)
+     */
+    public String toString() {
+        return Float.toString(value);
+    }
+
+    /**
+     * Returns the value of this {@code Float} as a {@code byte} after
+     * a narrowing primitive conversion.
+     *
+     * @return  the {@code float} value represented by this object
+     *          converted to type {@code byte}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public byte byteValue() {
+        return (byte)value;
+    }
+
+    /**
+     * Returns the value of this {@code Float} as a {@code short}
+     * after a narrowing primitive conversion.
+     *
+     * @return  the {@code float} value represented by this object
+     *          converted to type {@code short}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     * @since JDK1.1
+     */
+    public short shortValue() {
+        return (short)value;
+    }
+
+    /**
+     * Returns the value of this {@code Float} as an {@code int} after
+     * a narrowing primitive conversion.
+     *
+     * @return  the {@code float} value represented by this object
+     *          converted to type {@code int}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public int intValue() {
+        return (int)value;
+    }
+
+    /**
+     * Returns value of this {@code Float} as a {@code long} after a
+     * narrowing primitive conversion.
+     *
+     * @return  the {@code float} value represented by this object
+     *          converted to type {@code long}
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public long longValue() {
+        return (long)value;
+    }
+
+    /**
+     * Returns the {@code float} value of this {@code Float} object.
+     *
+     * @return the {@code float} value represented by this object
+     */
+    public float floatValue() {
+        return value;
+    }
+
+    /**
+     * Returns the value of this {@code Float} as a {@code double}
+     * after a widening primitive conversion.
+     *
+     * @return the {@code float} value represented by this
+     *         object converted to type {@code double}
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)value;
+    }
+
+    /**
+     * Returns a hash code for this {@code Float} object. The
+     * result is the integer bit representation, exactly as produced
+     * by the method {@link #floatToIntBits(float)}, of the primitive
+     * {@code float} value represented by this {@code Float}
+     * object.
+     *
+     * @return a hash code value for this object.
+     */
+    @Override
+    public int hashCode() {
+        return Float.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code float} value; compatible with
+     * {@code Float.hashCode()}.
+     *
+     * @param value the value to hash
+     * @return a hash code value for a {@code float} value.
+     * @since 1.8
+     */
+    public static int hashCode(float value) {
+        return floatToIntBits(value);
+    }
+
+    /**
+
+     * Compares this object against the specified object.  The result
+     * is {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Float} object that
+     * represents a {@code float} with the same value as the
+     * {@code float} represented by this object. For this
+     * purpose, two {@code float} values are considered to be the
+     * same if and only if the method {@link #floatToIntBits(float)}
+     * returns the identical {@code int} value when applied to
+     * each.
+     *
+     * <p>Note that in most cases, for two instances of class
+     * {@code Float}, {@code f1} and {@code f2}, the value
+     * of {@code f1.equals(f2)} is {@code true} if and only if
+     *
+     * <blockquote><pre>
+     *   f1.floatValue() == f2.floatValue()
+     * </pre></blockquote>
+     *
+     * <p>also has the value {@code true}. However, there are two exceptions:
+     * <ul>
+     * <li>If {@code f1} and {@code f2} both represent
+     *     {@code Float.NaN}, then the {@code equals} method returns
+     *     {@code true}, even though {@code Float.NaN==Float.NaN}
+     *     has the value {@code false}.
+     * <li>If {@code f1} represents {@code +0.0f} while
+     *     {@code f2} represents {@code -0.0f}, or vice
+     *     versa, the {@code equal} test has the value
+     *     {@code false}, even though {@code 0.0f==-0.0f}
+     *     has the value {@code true}.
+     * </ul>
+     *
+     * This definition allows hash tables to operate properly.
+     *
+     * @param obj the object to be compared
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see java.lang.Float#floatToIntBits(float)
+     */
+    public boolean equals(Object obj) {
+        return (obj instanceof Float)
+               && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
+    }
+
+    /**
+     * Returns a representation of the specified floating-point value
+     * according to the IEEE 754 floating-point "single format" bit
+     * layout.
+     *
+     * <p>Bit 31 (the bit that is selected by the mask
+     * {@code 0x80000000}) represents the sign of the floating-point
+     * number.
+     * Bits 30-23 (the bits that are selected by the mask
+     * {@code 0x7f800000}) represent the exponent.
+     * Bits 22-0 (the bits that are selected by the mask
+     * {@code 0x007fffff}) represent the significand (sometimes called
+     * the mantissa) of the floating-point number.
+     *
+     * <p>If the argument is positive infinity, the result is
+     * {@code 0x7f800000}.
+     *
+     * <p>If the argument is negative infinity, the result is
+     * {@code 0xff800000}.
+     *
+     * <p>If the argument is NaN, the result is {@code 0x7fc00000}.
+     *
+     * <p>In all cases, the result is an integer that, when given to the
+     * {@link #intBitsToFloat(int)} method, will produce a floating-point
+     * value the same as the argument to {@code floatToIntBits}
+     * (except all NaN values are collapsed to a single
+     * "canonical" NaN value).
+     *
+     * @param   value   a floating-point number.
+     * @return the bits that represent the floating-point number.
+     */
+    public static int floatToIntBits(float value) {
+        int result = floatToRawIntBits(value);
+        // Check for NaN based on values of bit fields, maximum
+        // exponent and nonzero significand.
+        if ( ((result & FloatConsts.EXP_BIT_MASK) ==
+              FloatConsts.EXP_BIT_MASK) &&
+             (result & FloatConsts.SIGNIF_BIT_MASK) != 0)
+            result = 0x7fc00000;
+        return result;
+    }
+
+    /**
+     * Returns a representation of the specified floating-point value
+     * according to the IEEE 754 floating-point "single format" bit
+     * layout, preserving Not-a-Number (NaN) values.
+     *
+     * <p>Bit 31 (the bit that is selected by the mask
+     * {@code 0x80000000}) represents the sign of the floating-point
+     * number.
+     * Bits 30-23 (the bits that are selected by the mask
+     * {@code 0x7f800000}) represent the exponent.
+     * Bits 22-0 (the bits that are selected by the mask
+     * {@code 0x007fffff}) represent the significand (sometimes called
+     * the mantissa) of the floating-point number.
+     *
+     * <p>If the argument is positive infinity, the result is
+     * {@code 0x7f800000}.
+     *
+     * <p>If the argument is negative infinity, the result is
+     * {@code 0xff800000}.
+     *
+     * <p>If the argument is NaN, the result is the integer representing
+     * the actual NaN value.  Unlike the {@code floatToIntBits}
+     * method, {@code floatToRawIntBits} does not collapse all the
+     * bit patterns encoding a NaN to a single "canonical"
+     * NaN value.
+     *
+     * <p>In all cases, the result is an integer that, when given to the
+     * {@link #intBitsToFloat(int)} method, will produce a
+     * floating-point value the same as the argument to
+     * {@code floatToRawIntBits}.
+     *
+     * @param   value   a floating-point number.
+     * @return the bits that represent the floating-point number.
+     * @since 1.3
+     */
+    public static native int floatToRawIntBits(float value);
+
+    /**
+     * Returns the {@code float} value corresponding to a given
+     * bit representation.
+     * The argument is considered to be a representation of a
+     * floating-point value according to the IEEE 754 floating-point
+     * "single format" bit layout.
+     *
+     * <p>If the argument is {@code 0x7f800000}, the result is positive
+     * infinity.
+     *
+     * <p>If the argument is {@code 0xff800000}, the result is negative
+     * infinity.
+     *
+     * <p>If the argument is any value in the range
+     * {@code 0x7f800001} through {@code 0x7fffffff} or in
+     * the range {@code 0xff800001} through
+     * {@code 0xffffffff}, the result is a NaN.  No IEEE 754
+     * floating-point operation provided by Java can distinguish
+     * between two NaN values of the same type with different bit
+     * patterns.  Distinct values of NaN are only distinguishable by
+     * use of the {@code Float.floatToRawIntBits} method.
+     *
+     * <p>In all other cases, let <i>s</i>, <i>e</i>, and <i>m</i> be three
+     * values that can be computed from the argument:
+     *
+     * <blockquote><pre>{@code
+     * int s = ((bits >> 31) == 0) ? 1 : -1;
+     * int e = ((bits >> 23) & 0xff);
+     * int m = (e == 0) ?
+     *                 (bits & 0x7fffff) << 1 :
+     *                 (bits & 0x7fffff) | 0x800000;
+     * }</pre></blockquote>
+     *
+     * Then the floating-point result equals the value of the mathematical
+     * expression <i>s</i>&middot;<i>m</i>&middot;2<sup><i>e</i>-150</sup>.
+     *
+     * <p>Note that this method may not be able to return a
+     * {@code float} NaN with exactly same bit pattern as the
+     * {@code int} argument.  IEEE 754 distinguishes between two
+     * kinds of NaNs, quiet NaNs and <i>signaling NaNs</i>.  The
+     * differences between the two kinds of NaN are generally not
+     * visible in Java.  Arithmetic operations on signaling NaNs turn
+     * them into quiet NaNs with a different, but often similar, bit
+     * pattern.  However, on some processors merely copying a
+     * signaling NaN also performs that conversion.  In particular,
+     * copying a signaling NaN to return it to the calling method may
+     * perform this conversion.  So {@code intBitsToFloat} may
+     * not be able to return a {@code float} with a signaling NaN
+     * bit pattern.  Consequently, for some {@code int} values,
+     * {@code floatToRawIntBits(intBitsToFloat(start))} may
+     * <i>not</i> equal {@code start}.  Moreover, which
+     * particular bit patterns represent signaling NaNs is platform
+     * dependent; although all NaN bit patterns, quiet or signaling,
+     * must be in the NaN range identified above.
+     *
+     * @param   bits   an integer.
+     * @return  the {@code float} floating-point value with the same bit
+     *          pattern.
+     */
+    public static native float intBitsToFloat(int bits);
+
+    /**
+     * Compares two {@code Float} objects numerically.  There are
+     * two ways in which comparisons performed by this method differ
+     * from those performed by the Java language numerical comparison
+     * operators ({@code <, <=, ==, >=, >}) when
+     * applied to primitive {@code float} values:
+     *
+     * <ul><li>
+     *          {@code Float.NaN} is considered by this method to
+     *          be equal to itself and greater than all other
+     *          {@code float} values
+     *          (including {@code Float.POSITIVE_INFINITY}).
+     * <li>
+     *          {@code 0.0f} is considered by this method to be greater
+     *          than {@code -0.0f}.
+     * </ul>
+     *
+     * This ensures that the <i>natural ordering</i> of {@code Float}
+     * objects imposed by this method is <i>consistent with equals</i>.
+     *
+     * @param   anotherFloat   the {@code Float} to be compared.
+     * @return  the value {@code 0} if {@code anotherFloat} is
+     *          numerically equal to this {@code Float}; a value
+     *          less than {@code 0} if this {@code Float}
+     *          is numerically less than {@code anotherFloat};
+     *          and a value greater than {@code 0} if this
+     *          {@code Float} is numerically greater than
+     *          {@code anotherFloat}.
+     *
+     * @since   1.2
+     * @see Comparable#compareTo(Object)
+     */
+    public int compareTo(Float anotherFloat) {
+        return Float.compare(value, anotherFloat.value);
+    }
+
+    /**
+     * Compares the two specified {@code float} values. The sign
+     * of the integer value returned is the same as that of the
+     * integer that would be returned by the call:
+     * <pre>
+     *    new Float(f1).compareTo(new Float(f2))
+     * </pre>
+     *
+     * @param   f1        the first {@code float} to compare.
+     * @param   f2        the second {@code float} to compare.
+     * @return  the value {@code 0} if {@code f1} is
+     *          numerically equal to {@code f2}; a value less than
+     *          {@code 0} if {@code f1} is numerically less than
+     *          {@code f2}; and a value greater than {@code 0}
+     *          if {@code f1} is numerically greater than
+     *          {@code f2}.
+     * @since 1.4
+     */
+    public static int compare(float f1, float f2) {
+        if (f1 < f2)
+            return -1;           // Neither val is NaN, thisVal is smaller
+        if (f1 > f2)
+            return 1;            // Neither val is NaN, thisVal is larger
+
+        // Cannot use floatToRawIntBits because of possibility of NaNs.
+        int thisBits    = Float.floatToIntBits(f1);
+        int anotherBits = Float.floatToIntBits(f2);
+
+        return (thisBits == anotherBits ?  0 : // Values are equal
+                (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
+                 1));                          // (0.0, -0.0) or (NaN, !NaN)
+    }
+
+    /**
+     * Adds two {@code float} values together as per the + operator.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the sum of {@code a} and {@code b}
+     * @jls 4.2.4 Floating-Point Operations
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static float sum(float a, float b) {
+        return a + b;
+    }
+
+    /**
+     * Returns the greater of two {@code float} values
+     * as if by calling {@link Math#max(float, float) Math.max}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the greater of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static float max(float a, float b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code float} values
+     * as if by calling {@link Math#min(float, float) Math.min}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the smaller of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static float min(float a, float b) {
+        return Math.min(a, b);
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -2671257302660747028L;
+}
diff --git a/java/lang/FunctionalInterface.java b/java/lang/FunctionalInterface.java
new file mode 100644
index 0000000..a93ed51
--- /dev/null
+++ b/java/lang/FunctionalInterface.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.*;
+
+/**
+ * An informative annotation type used to indicate that an interface
+ * type declaration is intended to be a <i>functional interface</i> as
+ * defined by the Java Language Specification.
+ *
+ * Conceptually, a functional interface has exactly one abstract
+ * method.  Since {@linkplain java.lang.reflect.Method#isDefault()
+ * default methods} have an implementation, they are not abstract.  If
+ * an interface declares an abstract method overriding one of the
+ * public methods of {@code java.lang.Object}, that also does
+ * <em>not</em> count toward the interface's abstract method count
+ * since any implementation of the interface will have an
+ * implementation from {@code java.lang.Object} or elsewhere.
+ *
+ * <p>Note that instances of functional interfaces can be created with
+ * lambda expressions, method references, or constructor references.
+ *
+ * <p>If a type is annotated with this annotation type, compilers are
+ * required to generate an error message unless:
+ *
+ * <ul>
+ * <li> The type is an interface type and not an annotation type, enum, or class.
+ * <li> The annotated type satisfies the requirements of a functional interface.
+ * </ul>
+ *
+ * <p>However, the compiler will treat any interface meeting the
+ * definition of a functional interface as a functional interface
+ * regardless of whether or not a {@code FunctionalInterface}
+ * annotation is present on the interface declaration.
+ *
+ * @jls 4.3.2. The Class Object
+ * @jls 9.8 Functional Interfaces
+ * @jls 9.4.3 Interface Method Body
+ * @since 1.8
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface FunctionalInterface {}
diff --git a/java/lang/IllegalAccessError.java b/java/lang/IllegalAccessError.java
new file mode 100644
index 0000000..ce045cd
--- /dev/null
+++ b/java/lang/IllegalAccessError.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if an application attempts to access or modify a field, or
+ * to call a method that it does not have access to.
+ * <p>
+ * Normally, this error is caught by the compiler; this error can
+ * only occur at run time if the definition of a class has
+ * incompatibly changed.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public class IllegalAccessError extends IncompatibleClassChangeError {
+    private static final long serialVersionUID = -8988904074992417891L;
+
+    /**
+     * Constructs an <code>IllegalAccessError</code> with no detail message.
+     */
+    public IllegalAccessError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IllegalAccessError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IllegalAccessError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/IllegalAccessException.java b/java/lang/IllegalAccessException.java
new file mode 100644
index 0000000..c7b1df8
--- /dev/null
+++ b/java/lang/IllegalAccessException.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * An IllegalAccessException is thrown when an application tries
+ * to reflectively create an instance (other than an array),
+ * set or get a field, or invoke a method, but the currently
+ * executing method does not have access to the definition of
+ * the specified class, field, method or constructor.
+ *
+ * @author  unascribed
+ * @see     Class#newInstance()
+ * @see     java.lang.reflect.Field#set(Object, Object)
+ * @see     java.lang.reflect.Field#setBoolean(Object, boolean)
+ * @see     java.lang.reflect.Field#setByte(Object, byte)
+ * @see     java.lang.reflect.Field#setShort(Object, short)
+ * @see     java.lang.reflect.Field#setChar(Object, char)
+ * @see     java.lang.reflect.Field#setInt(Object, int)
+ * @see     java.lang.reflect.Field#setLong(Object, long)
+ * @see     java.lang.reflect.Field#setFloat(Object, float)
+ * @see     java.lang.reflect.Field#setDouble(Object, double)
+ * @see     java.lang.reflect.Field#get(Object)
+ * @see     java.lang.reflect.Field#getBoolean(Object)
+ * @see     java.lang.reflect.Field#getByte(Object)
+ * @see     java.lang.reflect.Field#getShort(Object)
+ * @see     java.lang.reflect.Field#getChar(Object)
+ * @see     java.lang.reflect.Field#getInt(Object)
+ * @see     java.lang.reflect.Field#getLong(Object)
+ * @see     java.lang.reflect.Field#getFloat(Object)
+ * @see     java.lang.reflect.Field#getDouble(Object)
+ * @see     java.lang.reflect.Method#invoke(Object, Object[])
+ * @see     java.lang.reflect.Constructor#newInstance(Object[])
+ * @since   JDK1.0
+ */
+public class IllegalAccessException extends ReflectiveOperationException {
+    private static final long serialVersionUID = 6616958222490762034L;
+
+    /**
+     * Constructs an <code>IllegalAccessException</code> without a
+     * detail message.
+     */
+    public IllegalAccessException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IllegalAccessException</code> with a detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IllegalAccessException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/IllegalArgumentException.java b/java/lang/IllegalArgumentException.java
new file mode 100644
index 0000000..c29a9d5
--- /dev/null
+++ b/java/lang/IllegalArgumentException.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that a method has been passed an illegal or
+ * inappropriate argument.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class IllegalArgumentException extends RuntimeException {
+    /**
+     * Constructs an <code>IllegalArgumentException</code> with no
+     * detail message.
+     */
+    public IllegalArgumentException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IllegalArgumentException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IllegalArgumentException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * <p>Note that the detail message associated with <code>cause</code> is
+     * <i>not</i> automatically incorporated in this exception's detail
+     * message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link Throwable#getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A <tt>null</tt> value
+     *         is permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since 1.5
+     */
+    public IllegalArgumentException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.5
+     */
+    public IllegalArgumentException(Throwable cause) {
+        super(cause);
+    }
+
+    private static final long serialVersionUID = -5365630128856068164L;
+}
diff --git a/java/lang/IllegalMonitorStateException.java b/java/lang/IllegalMonitorStateException.java
new file mode 100644
index 0000000..3985066
--- /dev/null
+++ b/java/lang/IllegalMonitorStateException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that a thread has attempted to wait on an
+ * object's monitor or to notify other threads waiting on an object's
+ * monitor without owning the specified monitor.
+ *
+ * @author  unascribed
+ * @see     java.lang.Object#notify()
+ * @see     java.lang.Object#notifyAll()
+ * @see     java.lang.Object#wait()
+ * @see     java.lang.Object#wait(long)
+ * @see     java.lang.Object#wait(long, int)
+ * @since   JDK1.0
+ */
+public
+class IllegalMonitorStateException extends RuntimeException {
+    private static final long serialVersionUID = 3713306369498869069L;
+
+    /**
+     * Constructs an <code>IllegalMonitorStateException</code> with no
+     * detail message.
+     */
+    public IllegalMonitorStateException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IllegalMonitorStateException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IllegalMonitorStateException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/IllegalStateException.java b/java/lang/IllegalStateException.java
new file mode 100644
index 0000000..9c0c06a
--- /dev/null
+++ b/java/lang/IllegalStateException.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Signals that a method has been invoked at an illegal or
+ * inappropriate time.  In other words, the Java environment or
+ * Java application is not in an appropriate state for the requested
+ * operation.
+ *
+ * @author  Jonni Kanerva
+ * @since   JDK1.1
+ */
+public
+class IllegalStateException extends RuntimeException {
+    /**
+     * Constructs an IllegalStateException with no detail message.
+     * A detail message is a String that describes this particular exception.
+     */
+    public IllegalStateException() {
+        super();
+    }
+
+    /**
+     * Constructs an IllegalStateException with the specified detail
+     * message.  A detail message is a String that describes this particular
+     * exception.
+     *
+     * @param s the String that contains a detailed message
+     */
+    public IllegalStateException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * <p>Note that the detail message associated with <code>cause</code> is
+     * <i>not</i> automatically incorporated in this exception's detail
+     * message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link Throwable#getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A <tt>null</tt> value
+     *         is permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since 1.5
+     */
+    public IllegalStateException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.5
+     */
+    public IllegalStateException(Throwable cause) {
+        super(cause);
+    }
+
+    static final long serialVersionUID = -1848914673093119416L;
+}
diff --git a/java/lang/IllegalThreadStateException.java b/java/lang/IllegalThreadStateException.java
new file mode 100644
index 0000000..c59ab59
--- /dev/null
+++ b/java/lang/IllegalThreadStateException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that a thread is not in an appropriate state
+ * for the requested operation. See, for example, the
+ * <code>suspend</code> and <code>resume</code> methods in class
+ * <code>Thread</code>.
+ *
+ * @author  unascribed
+ * @see     java.lang.Thread#resume()
+ * @see     java.lang.Thread#suspend()
+ * @since   JDK1.0
+ */
+public class IllegalThreadStateException extends IllegalArgumentException {
+    private static final long serialVersionUID = -7626246362397460174L;
+
+    /**
+     * Constructs an <code>IllegalThreadStateException</code> with no
+     * detail message.
+     */
+    public IllegalThreadStateException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IllegalThreadStateException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IllegalThreadStateException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/IncompatibleClassChangeError.java b/java/lang/IncompatibleClassChangeError.java
new file mode 100644
index 0000000..edffaee
--- /dev/null
+++ b/java/lang/IncompatibleClassChangeError.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an incompatible class change has occurred to some class
+ * definition. The definition of some class, on which the currently
+ * executing method depends, has since changed.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class IncompatibleClassChangeError extends LinkageError {
+    private static final long serialVersionUID = -4914975503642802119L;
+
+    /**
+     * Constructs an <code>IncompatibleClassChangeError</code> with no
+     * detail message.
+     */
+    public IncompatibleClassChangeError () {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IncompatibleClassChangeError</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IncompatibleClassChangeError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/IndexOutOfBoundsException.java b/java/lang/IndexOutOfBoundsException.java
new file mode 100644
index 0000000..4dc7948
--- /dev/null
+++ b/java/lang/IndexOutOfBoundsException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an index of some sort (such as to an array, to a
+ * string, or to a vector) is out of range.
+ * <p>
+ * Applications can subclass this class to indicate similar exceptions.
+ *
+ * @author  Frank Yellin
+ * @since   JDK1.0
+ */
+public
+class IndexOutOfBoundsException extends RuntimeException {
+    private static final long serialVersionUID = 234122996006267687L;
+
+    /**
+     * Constructs an <code>IndexOutOfBoundsException</code> with no
+     * detail message.
+     */
+    public IndexOutOfBoundsException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>IndexOutOfBoundsException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public IndexOutOfBoundsException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/InheritableThreadLocal.java b/java/lang/InheritableThreadLocal.java
new file mode 100644
index 0000000..935c5f1
--- /dev/null
+++ b/java/lang/InheritableThreadLocal.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+import java.lang.ref.*;
+
+/**
+ * This class extends <tt>ThreadLocal</tt> to provide inheritance of values
+ * from parent thread to child thread: when a child thread is created, the
+ * child receives initial values for all inheritable thread-local variables
+ * for which the parent has values.  Normally the child's values will be
+ * identical to the parent's; however, the child's value can be made an
+ * arbitrary function of the parent's by overriding the <tt>childValue</tt>
+ * method in this class.
+ *
+ * <p>Inheritable thread-local variables are used in preference to
+ * ordinary thread-local variables when the per-thread-attribute being
+ * maintained in the variable (e.g., User ID, Transaction ID) must be
+ * automatically transmitted to any child threads that are created.
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @see     ThreadLocal
+ * @since   1.2
+ */
+
+public class InheritableThreadLocal<T> extends ThreadLocal<T> {
+    /**
+     * Computes the child's initial value for this inheritable thread-local
+     * variable as a function of the parent's value at the time the child
+     * thread is created.  This method is called from within the parent
+     * thread before the child is started.
+     * <p>
+     * This method merely returns its input argument, and should be overridden
+     * if a different behavior is desired.
+     *
+     * @param parentValue the parent thread's value
+     * @return the child thread's initial value
+     */
+    protected T childValue(T parentValue) {
+        return parentValue;
+    }
+
+    /**
+     * Get the map associated with a ThreadLocal.
+     *
+     * @param t the current thread
+     */
+    ThreadLocalMap getMap(Thread t) {
+       return t.inheritableThreadLocals;
+    }
+
+    /**
+     * Create the map associated with a ThreadLocal.
+     *
+     * @param t the current thread
+     * @param firstValue value for the initial entry of the table.
+     */
+    void createMap(Thread t, T firstValue) {
+        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
+    }
+}
diff --git a/java/lang/InstantiationError.java b/java/lang/InstantiationError.java
new file mode 100644
index 0000000..89c10b3
--- /dev/null
+++ b/java/lang/InstantiationError.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application tries to use the Java <code>new</code>
+ * construct to instantiate an abstract class or an interface.
+ * <p>
+ * Normally, this error is caught by the compiler; this error can
+ * only occur at run time if the definition of a class has
+ * incompatibly changed.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+
+
+public
+class InstantiationError extends IncompatibleClassChangeError {
+    private static final long serialVersionUID = -4885810657349421204L;
+
+    /**
+     * Constructs an <code>InstantiationError</code> with no detail  message.
+     */
+    public InstantiationError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InstantiationError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public InstantiationError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/InstantiationException.java b/java/lang/InstantiationException.java
new file mode 100644
index 0000000..afeeb17
--- /dev/null
+++ b/java/lang/InstantiationException.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application tries to create an instance of a class
+ * using the {@code newInstance} method in class
+ * {@code Class}, but the specified class object cannot be
+ * instantiated.  The instantiation can fail for a variety of
+ * reasons including but not limited to:
+ *
+ * <ul>
+ * <li> the class object represents an abstract class, an interface,
+ *      an array class, a primitive type, or {@code void}
+ * <li> the class has no nullary constructor
+ *</ul>
+ *
+ * @author  unascribed
+ * @see     java.lang.Class#newInstance()
+ * @since   JDK1.0
+ */
+public
+class InstantiationException extends ReflectiveOperationException {
+    private static final long serialVersionUID = -8441929162975509110L;
+
+    /**
+     * Constructs an {@code InstantiationException} with no detail message.
+     */
+    public InstantiationException() {
+        super();
+    }
+
+    /**
+     * Constructs an {@code InstantiationException} with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public InstantiationException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/Integer.annotated.java b/java/lang/Integer.annotated.java
new file mode 100644
index 0000000..d3f6753
--- /dev/null
+++ b/java/lang/Integer.annotated.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Integer extends java.lang.Number implements java.lang.Comparable<java.lang.Integer> {
+
+public Integer(int value) { throw new RuntimeException("Stub!"); }
+
+public Integer(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(int i, int radix) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toUnsignedString(int i, int radix) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toHexString(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toOctalString(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toBinaryString(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toUnsignedString(int i) { throw new RuntimeException("Stub!"); }
+
+public static int parseInt(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static int parseInt(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static int parseUnsignedInt(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static int parseUnsignedInt(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer valueOf(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer valueOf(int i) { throw new RuntimeException("Stub!"); }
+
+public byte byteValue() { throw new RuntimeException("Stub!"); }
+
+public short shortValue() { throw new RuntimeException("Stub!"); }
+
+public int intValue() { throw new RuntimeException("Stub!"); }
+
+public long longValue() { throw new RuntimeException("Stub!"); }
+
+public float floatValue() { throw new RuntimeException("Stub!"); }
+
+public double doubleValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(int value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer getInteger(@libcore.util.NonNull java.lang.String nm) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer getInteger(@libcore.util.NonNull java.lang.String nm, int val) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer getInteger(@libcore.util.NonNull java.lang.String nm, @libcore.util.Nullable java.lang.Integer val) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Integer decode(@libcore.util.NonNull java.lang.String nm) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.lang.Integer anotherInteger) { throw new RuntimeException("Stub!"); }
+
+public static int compare(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static long toUnsignedLong(int x) { throw new RuntimeException("Stub!"); }
+
+public static int divideUnsigned(int dividend, int divisor) { throw new RuntimeException("Stub!"); }
+
+public static int remainderUnsigned(int dividend, int divisor) { throw new RuntimeException("Stub!"); }
+
+public static int highestOneBit(int i) { throw new RuntimeException("Stub!"); }
+
+public static int lowestOneBit(int i) { throw new RuntimeException("Stub!"); }
+
+public static int numberOfLeadingZeros(int i) { throw new RuntimeException("Stub!"); }
+
+public static int numberOfTrailingZeros(int i) { throw new RuntimeException("Stub!"); }
+
+public static int bitCount(int i) { throw new RuntimeException("Stub!"); }
+
+public static int rotateLeft(int i, int distance) { throw new RuntimeException("Stub!"); }
+
+public static int rotateRight(int i, int distance) { throw new RuntimeException("Stub!"); }
+
+public static int reverse(int i) { throw new RuntimeException("Stub!"); }
+
+public static int signum(int i) { throw new RuntimeException("Stub!"); }
+
+public static int reverseBytes(int i) { throw new RuntimeException("Stub!"); }
+
+public static int sum(int a, int b) { throw new RuntimeException("Stub!"); }
+
+public static int max(int a, int b) { throw new RuntimeException("Stub!"); }
+
+public static int min(int a, int b) { throw new RuntimeException("Stub!"); }
+
+public static final int BYTES = 4; // 0x4
+
+public static final int MAX_VALUE = 2147483647; // 0x7fffffff
+
+public static final int MIN_VALUE = -2147483648; // 0x80000000
+
+public static final int SIZE = 32; // 0x20
+
+public static final java.lang.Class<java.lang.Integer> TYPE;
+static { TYPE = null; }
+}
+
diff --git a/java/lang/Integer.java b/java/lang/Integer.java
new file mode 100644
index 0000000..93ae24c
--- /dev/null
+++ b/java/lang/Integer.java
@@ -0,0 +1,1630 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.Native;
+
+/**
+ * The {@code Integer} class wraps a value of the primitive type
+ * {@code int} in an object. An object of type {@code Integer}
+ * contains a single field whose type is {@code int}.
+ *
+ * <p>In addition, this class provides several methods for converting
+ * an {@code int} to a {@code String} and a {@code String} to an
+ * {@code int}, as well as other constants and methods useful when
+ * dealing with an {@code int}.
+ *
+ * <p>Implementation note: The implementations of the "bit twiddling"
+ * methods (such as {@link #highestOneBit(int) highestOneBit} and
+ * {@link #numberOfTrailingZeros(int) numberOfTrailingZeros}) are
+ * based on material from Henry S. Warren, Jr.'s <i>Hacker's
+ * Delight</i>, (Addison Wesley, 2002).
+ *
+ * @author  Lee Boynton
+ * @author  Arthur van Hoff
+ * @author  Josh Bloch
+ * @author  Joseph D. Darcy
+ * @since JDK1.0
+ */
+public final class Integer extends Number implements Comparable<Integer> {
+    /**
+     * A constant holding the minimum value an {@code int} can
+     * have, -2<sup>31</sup>.
+     */
+    @Native public static final int   MIN_VALUE = 0x80000000;
+
+    /**
+     * A constant holding the maximum value an {@code int} can
+     * have, 2<sup>31</sup>-1.
+     */
+    @Native public static final int   MAX_VALUE = 0x7fffffff;
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code int}.
+     *
+     * @since   JDK1.1
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
+
+    /**
+     * All possible chars for representing a number as a String
+     */
+    final static char[] digits = {
+        '0' , '1' , '2' , '3' , '4' , '5' ,
+        '6' , '7' , '8' , '9' , 'a' , 'b' ,
+        'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
+        'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
+        'o' , 'p' , 'q' , 'r' , 's' , 't' ,
+        'u' , 'v' , 'w' , 'x' , 'y' , 'z'
+    };
+
+    /**
+     * Returns a string representation of the first argument in the
+     * radix specified by the second argument.
+     *
+     * <p>If the radix is smaller than {@code Character.MIN_RADIX}
+     * or larger than {@code Character.MAX_RADIX}, then the radix
+     * {@code 10} is used instead.
+     *
+     * <p>If the first argument is negative, the first element of the
+     * result is the ASCII minus character {@code '-'}
+     * ({@code '\u005Cu002D'}). If the first argument is not
+     * negative, no sign character appears in the result.
+     *
+     * <p>The remaining characters of the result represent the magnitude
+     * of the first argument. If the magnitude is zero, it is
+     * represented by a single zero character {@code '0'}
+     * ({@code '\u005Cu0030'}); otherwise, the first character of
+     * the representation of the magnitude will not be the zero
+     * character.  The following ASCII characters are used as digits:
+     *
+     * <blockquote>
+     *   {@code 0123456789abcdefghijklmnopqrstuvwxyz}
+     * </blockquote>
+     *
+     * These are {@code '\u005Cu0030'} through
+     * {@code '\u005Cu0039'} and {@code '\u005Cu0061'} through
+     * {@code '\u005Cu007A'}. If {@code radix} is
+     * <var>N</var>, then the first <var>N</var> of these characters
+     * are used as radix-<var>N</var> digits in the order shown. Thus,
+     * the digits for hexadecimal (radix 16) are
+     * {@code 0123456789abcdef}. If uppercase letters are
+     * desired, the {@link java.lang.String#toUpperCase()} method may
+     * be called on the result:
+     *
+     * <blockquote>
+     *  {@code Integer.toString(n, 16).toUpperCase()}
+     * </blockquote>
+     *
+     * @param   i       an integer to be converted to a string.
+     * @param   radix   the radix to use in the string representation.
+     * @return  a string representation of the argument in the specified radix.
+     * @see     java.lang.Character#MAX_RADIX
+     * @see     java.lang.Character#MIN_RADIX
+     */
+    public static String toString(int i, int radix) {
+        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
+            radix = 10;
+
+        /* Use the faster version */
+        if (radix == 10) {
+            return toString(i);
+        }
+
+        char buf[] = new char[33];
+        boolean negative = (i < 0);
+        int charPos = 32;
+
+        if (!negative) {
+            i = -i;
+        }
+
+        while (i <= -radix) {
+            buf[charPos--] = digits[-(i % radix)];
+            i = i / radix;
+        }
+        buf[charPos] = digits[-i];
+
+        if (negative) {
+            buf[--charPos] = '-';
+        }
+
+        return new String(buf, charPos, (33 - charPos));
+    }
+
+    /**
+     * Returns a string representation of the first argument as an
+     * unsigned integer value in the radix specified by the second
+     * argument.
+     *
+     * <p>If the radix is smaller than {@code Character.MIN_RADIX}
+     * or larger than {@code Character.MAX_RADIX}, then the radix
+     * {@code 10} is used instead.
+     *
+     * <p>Note that since the first argument is treated as an unsigned
+     * value, no leading sign character is printed.
+     *
+     * <p>If the magnitude is zero, it is represented by a single zero
+     * character {@code '0'} ({@code '\u005Cu0030'}); otherwise,
+     * the first character of the representation of the magnitude will
+     * not be the zero character.
+     *
+     * <p>The behavior of radixes and the characters used as digits
+     * are the same as {@link #toString(int, int) toString}.
+     *
+     * @param   i       an integer to be converted to an unsigned string.
+     * @param   radix   the radix to use in the string representation.
+     * @return  an unsigned string representation of the argument in the specified radix.
+     * @see     #toString(int, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(int i, int radix) {
+        return Long.toUnsignedString(toUnsignedLong(i), radix);
+    }
+
+    /**
+     * Returns a string representation of the integer argument as an
+     * unsigned integer in base&nbsp;16.
+     *
+     * <p>The unsigned integer value is the argument plus 2<sup>32</sup>
+     * if the argument is negative; otherwise, it is equal to the
+     * argument.  This value is converted to a string of ASCII digits
+     * in hexadecimal (base&nbsp;16) with no extra leading
+     * {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Integer#parseUnsignedInt(String, int)
+     * Integer.parseUnsignedInt(s, 16)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} ({@code '\u005Cu0030'});
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as hexadecimal digits:
+     *
+     * <blockquote>
+     *  {@code 0123456789abcdef}
+     * </blockquote>
+     *
+     * These are the characters {@code '\u005Cu0030'} through
+     * {@code '\u005Cu0039'} and {@code '\u005Cu0061'} through
+     * {@code '\u005Cu0066'}. If uppercase letters are
+     * desired, the {@link java.lang.String#toUpperCase()} method may
+     * be called on the result:
+     *
+     * <blockquote>
+     *  {@code Integer.toHexString(n).toUpperCase()}
+     * </blockquote>
+     *
+     * @param   i   an integer to be converted to a string.
+     * @return  the string representation of the unsigned integer value
+     *          represented by the argument in hexadecimal (base&nbsp;16).
+     * @see #parseUnsignedInt(String, int)
+     * @see #toUnsignedString(int, int)
+     * @since   JDK1.0.2
+     */
+    public static String toHexString(int i) {
+        return toUnsignedString0(i, 4);
+    }
+
+    /**
+     * Returns a string representation of the integer argument as an
+     * unsigned integer in base&nbsp;8.
+     *
+     * <p>The unsigned integer value is the argument plus 2<sup>32</sup>
+     * if the argument is negative; otherwise, it is equal to the
+     * argument.  This value is converted to a string of ASCII digits
+     * in octal (base&nbsp;8) with no extra leading {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Integer#parseUnsignedInt(String, int)
+     * Integer.parseUnsignedInt(s, 8)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} ({@code '\u005Cu0030'});
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as octal digits:
+     *
+     * <blockquote>
+     * {@code 01234567}
+     * </blockquote>
+     *
+     * These are the characters {@code '\u005Cu0030'} through
+     * {@code '\u005Cu0037'}.
+     *
+     * @param   i   an integer to be converted to a string.
+     * @return  the string representation of the unsigned integer value
+     *          represented by the argument in octal (base&nbsp;8).
+     * @see #parseUnsignedInt(String, int)
+     * @see #toUnsignedString(int, int)
+     * @since   JDK1.0.2
+     */
+    public static String toOctalString(int i) {
+        return toUnsignedString0(i, 3);
+    }
+
+    /**
+     * Returns a string representation of the integer argument as an
+     * unsigned integer in base&nbsp;2.
+     *
+     * <p>The unsigned integer value is the argument plus 2<sup>32</sup>
+     * if the argument is negative; otherwise it is equal to the
+     * argument.  This value is converted to a string of ASCII digits
+     * in binary (base&nbsp;2) with no extra leading {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Integer#parseUnsignedInt(String, int)
+     * Integer.parseUnsignedInt(s, 2)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} ({@code '\u005Cu0030'});
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * characters {@code '0'} ({@code '\u005Cu0030'}) and {@code
+     * '1'} ({@code '\u005Cu0031'}) are used as binary digits.
+     *
+     * @param   i   an integer to be converted to a string.
+     * @return  the string representation of the unsigned integer value
+     *          represented by the argument in binary (base&nbsp;2).
+     * @see #parseUnsignedInt(String, int)
+     * @see #toUnsignedString(int, int)
+     * @since   JDK1.0.2
+     */
+    public static String toBinaryString(int i) {
+        return toUnsignedString0(i, 1);
+    }
+
+    /**
+     * Convert the integer to an unsigned number.
+     */
+    private static String toUnsignedString0(int val, int shift) {
+        // assert shift > 0 && shift <=5 : "Illegal shift value";
+        int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
+        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
+        char[] buf = new char[chars];
+
+        formatUnsignedInt(val, shift, buf, 0, chars);
+
+        // Android-changed: Use regular constructor instead of one which takes over "buf".
+        // return new String(buf, true);
+        return new String(buf);
+    }
+
+    /**
+     * Format a long (treated as unsigned) into a character buffer.
+     * @param val the unsigned int to format
+     * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
+     * @param buf the character buffer to write to
+     * @param offset the offset in the destination buffer to start at
+     * @param len the number of characters to write
+     * @return the lowest character  location used
+     */
+     static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
+        int charPos = len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            buf[offset + --charPos] = Integer.digits[val & mask];
+            val >>>= shift;
+        } while (val != 0 && charPos > 0);
+
+        return charPos;
+    }
+
+    // BEGIN Android-changed: Cache the toString() result for small values.
+    private static final String[] SMALL_NEG_VALUES  = new String[100];
+    private static final String[] SMALL_NONNEG_VALUES = new String[100];
+    // END Android-changed: Cache the toString() result for small values.
+
+    final static char [] DigitTens = {
+        '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
+        '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
+        '2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
+        '3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
+        '4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
+        '5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
+        '6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
+        '7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
+        '8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
+        '9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
+        } ;
+
+    final static char [] DigitOnes = {
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+        } ;
+
+        // I use the "invariant division by multiplication" trick to
+        // accelerate Integer.toString.  In particular we want to
+        // avoid division by 10.
+        //
+        // The "trick" has roughly the same performance characteristics
+        // as the "classic" Integer.toString code on a non-JIT VM.
+        // The trick avoids .rem and .div calls but has a longer code
+        // path and is thus dominated by dispatch overhead.  In the
+        // JIT case the dispatch overhead doesn't exist and the
+        // "trick" is considerably faster than the classic code.
+        //
+        // TODO-FIXME: convert (x * 52429) into the equiv shift-add
+        // sequence.
+        //
+        // RE:  Division by Invariant Integers using Multiplication
+        //      T Gralund, P Montgomery
+        //      ACM PLDI 1994
+        //
+
+    /**
+     * Returns a {@code String} object representing the
+     * specified integer. The argument is converted to signed decimal
+     * representation and returned as a string, exactly as if the
+     * argument and radix 10 were given as arguments to the {@link
+     * #toString(int, int)} method.
+     *
+     * @param   i   an integer to be converted.
+     * @return  a string representation of the argument in base&nbsp;10.
+     */
+    public static String toString(int i) {
+        if (i == Integer.MIN_VALUE)
+            return "-2147483648";
+
+        // BEGIN Android-changed: Cache the String for small values.
+        // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
+        boolean negative = i < 0;
+        boolean small = negative ? i > -100 : i < 100;
+        if (small) {
+            final String[] smallValues = negative ? SMALL_NEG_VALUES : SMALL_NONNEG_VALUES;
+
+            if (negative) {
+                i = -i;
+                if (smallValues[i] == null) {
+                    smallValues[i] =
+                        i < 10 ? new String(new char[]{'-', DigitOnes[i]})
+                               : new String(new char[]{'-', DigitTens[i], DigitOnes[i]});
+                }
+            } else {
+                if (smallValues[i] == null) {
+                    smallValues[i] =
+                        i < 10 ? new String(new char[]{DigitOnes[i]})
+                               : new String(new char[]{DigitTens[i], DigitOnes[i]});
+                }
+            }
+            return smallValues[i];
+        }
+        int size = negative ? stringSize(-i) + 1 : stringSize(i);
+        // END Android-changed: Cache the String for small values.
+        char[] buf = new char[size];
+        getChars(i, size, buf);
+        // Android-changed: Use regular constructor instead of one which takes over "buf".
+        // return new String(buf, true);
+        return new String(buf);
+    }
+
+    /**
+     * Returns a string representation of the argument as an unsigned
+     * decimal value.
+     *
+     * The argument is converted to unsigned decimal representation
+     * and returned as a string exactly as if the argument and radix
+     * 10 were given as arguments to the {@link #toUnsignedString(int,
+     * int)} method.
+     *
+     * @param   i  an integer to be converted to an unsigned string.
+     * @return  an unsigned string representation of the argument.
+     * @see     #toUnsignedString(int, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(int i) {
+        return Long.toString(toUnsignedLong(i));
+    }
+
+    /**
+     * Places characters representing the integer i into the
+     * character array buf. The characters are placed into
+     * the buffer backwards starting with the least significant
+     * digit at the specified index (exclusive), and working
+     * backwards from there.
+     *
+     * Will fail if i == Integer.MIN_VALUE
+     */
+    static void getChars(int i, int index, char[] buf) {
+        int q, r;
+        int charPos = index;
+        char sign = 0;
+
+        if (i < 0) {
+            sign = '-';
+            i = -i;
+        }
+
+        // Generate two digits per iteration
+        while (i >= 65536) {
+            q = i / 100;
+        // really: r = i - (q * 100);
+            r = i - ((q << 6) + (q << 5) + (q << 2));
+            i = q;
+            buf [--charPos] = DigitOnes[r];
+            buf [--charPos] = DigitTens[r];
+        }
+
+        // Fall thru to fast mode for smaller numbers
+        // assert(i <= 65536, i);
+        for (;;) {
+            q = (i * 52429) >>> (16+3);
+            r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
+            buf [--charPos] = digits [r];
+            i = q;
+            if (i == 0) break;
+        }
+        if (sign != 0) {
+            buf [--charPos] = sign;
+        }
+    }
+
+    final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
+                                      99999999, 999999999, Integer.MAX_VALUE };
+
+    // Requires positive x
+    static int stringSize(int x) {
+        for (int i=0; ; i++)
+            if (x <= sizeTable[i])
+                return i+1;
+    }
+
+    /**
+     * Parses the string argument as a signed integer in the radix
+     * specified by the second argument. The characters in the string
+     * must all be digits of the specified radix (as determined by
+     * whether {@link java.lang.Character#digit(char, int)} returns a
+     * nonnegative value), except that the first character may be an
+     * ASCII minus sign {@code '-'} ({@code '\u005Cu002D'}) to
+     * indicate a negative value or an ASCII plus sign {@code '+'}
+     * ({@code '\u005Cu002B'}) to indicate a positive value. The
+     * resulting integer value is returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li>The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li>The radix is either smaller than
+     * {@link java.lang.Character#MIN_RADIX} or
+     * larger than {@link java.lang.Character#MAX_RADIX}.
+     *
+     * <li>Any character of the string is not a digit of the specified
+     * radix, except that the first character may be a minus sign
+     * {@code '-'} ({@code '\u005Cu002D'}) or plus sign
+     * {@code '+'} ({@code '\u005Cu002B'}) provided that the
+     * string is longer than length 1.
+     *
+     * <li>The value represented by the string is not a value of type
+     * {@code int}.
+     * </ul>
+     *
+     * <p>Examples:
+     * <blockquote><pre>
+     * parseInt("0", 10) returns 0
+     * parseInt("473", 10) returns 473
+     * parseInt("+42", 10) returns 42
+     * parseInt("-0", 10) returns 0
+     * parseInt("-FF", 16) returns -255
+     * parseInt("1100110", 2) returns 102
+     * parseInt("2147483647", 10) returns 2147483647
+     * parseInt("-2147483648", 10) returns -2147483648
+     * parseInt("2147483648", 10) throws a NumberFormatException
+     * parseInt("99", 8) throws a NumberFormatException
+     * parseInt("Kona", 10) throws a NumberFormatException
+     * parseInt("Kona", 27) returns 411787
+     * </pre></blockquote>
+     *
+     * @param      s   the {@code String} containing the integer
+     *                  representation to be parsed
+     * @param      radix   the radix to be used while parsing {@code s}.
+     * @return     the integer represented by the string argument in the
+     *             specified radix.
+     * @exception  NumberFormatException if the {@code String}
+     *             does not contain a parsable {@code int}.
+     */
+    public static int parseInt(String s, int radix)
+                throws NumberFormatException
+    {
+        /*
+         * WARNING: This method may be invoked early during VM initialization
+         * before IntegerCache is initialized. Care must be taken to not use
+         * the valueOf method.
+         */
+
+        if (s == null) {
+            // Android-changed: Improve exception message for parseInt.
+            throw new NumberFormatException("s == null");
+        }
+
+        if (radix < Character.MIN_RADIX) {
+            throw new NumberFormatException("radix " + radix +
+                                            " less than Character.MIN_RADIX");
+        }
+
+        if (radix > Character.MAX_RADIX) {
+            throw new NumberFormatException("radix " + radix +
+                                            " greater than Character.MAX_RADIX");
+        }
+
+        int result = 0;
+        boolean negative = false;
+        int i = 0, len = s.length();
+        int limit = -Integer.MAX_VALUE;
+        int multmin;
+        int digit;
+
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar < '0') { // Possible leading "+" or "-"
+                if (firstChar == '-') {
+                    negative = true;
+                    limit = Integer.MIN_VALUE;
+                } else if (firstChar != '+')
+                    throw NumberFormatException.forInputString(s);
+
+                if (len == 1) // Cannot have lone "+" or "-"
+                    throw NumberFormatException.forInputString(s);
+                i++;
+            }
+            multmin = limit / radix;
+            while (i < len) {
+                // Accumulating negatively avoids surprises near MAX_VALUE
+                digit = Character.digit(s.charAt(i++),radix);
+                if (digit < 0) {
+                    throw NumberFormatException.forInputString(s);
+                }
+                if (result < multmin) {
+                    throw NumberFormatException.forInputString(s);
+                }
+                result *= radix;
+                if (result < limit + digit) {
+                    throw NumberFormatException.forInputString(s);
+                }
+                result -= digit;
+            }
+        } else {
+            throw NumberFormatException.forInputString(s);
+        }
+        return negative ? result : -result;
+    }
+
+    /**
+     * Parses the string argument as a signed decimal integer. The
+     * characters in the string must all be decimal digits, except
+     * that the first character may be an ASCII minus sign {@code '-'}
+     * ({@code '\u005Cu002D'}) to indicate a negative value or an
+     * ASCII plus sign {@code '+'} ({@code '\u005Cu002B'}) to
+     * indicate a positive value. The resulting integer value is
+     * returned, exactly as if the argument and the radix 10 were
+     * given as arguments to the {@link #parseInt(java.lang.String,
+     * int)} method.
+     *
+     * @param s    a {@code String} containing the {@code int}
+     *             representation to be parsed
+     * @return     the integer value represented by the argument in decimal.
+     * @exception  NumberFormatException  if the string does not contain a
+     *               parsable integer.
+     */
+    public static int parseInt(String s) throws NumberFormatException {
+        return parseInt(s,10);
+    }
+
+    /**
+     * Parses the string argument as an unsigned integer in the radix
+     * specified by the second argument.  An unsigned integer maps the
+     * values usually associated with negative numbers to positive
+     * numbers larger than {@code MAX_VALUE}.
+     *
+     * The characters in the string must all be digits of the
+     * specified radix (as determined by whether {@link
+     * java.lang.Character#digit(char, int)} returns a nonnegative
+     * value), except that the first character may be an ASCII plus
+     * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting
+     * integer value is returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li>The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li>The radix is either smaller than
+     * {@link java.lang.Character#MIN_RADIX} or
+     * larger than {@link java.lang.Character#MAX_RADIX}.
+     *
+     * <li>Any character of the string is not a digit of the specified
+     * radix, except that the first character may be a plus sign
+     * {@code '+'} ({@code '\u005Cu002B'}) provided that the
+     * string is longer than length 1.
+     *
+     * <li>The value represented by the string is larger than the
+     * largest unsigned {@code int}, 2<sup>32</sup>-1.
+     *
+     * </ul>
+     *
+     *
+     * @param      s   the {@code String} containing the unsigned integer
+     *                  representation to be parsed
+     * @param      radix   the radix to be used while parsing {@code s}.
+     * @return     the integer represented by the string argument in the
+     *             specified radix.
+     * @throws     NumberFormatException if the {@code String}
+     *             does not contain a parsable {@code int}.
+     * @since 1.8
+     */
+    public static int parseUnsignedInt(String s, int radix)
+                throws NumberFormatException {
+        if (s == null)  {
+            throw new NumberFormatException("null");
+        }
+
+        int len = s.length();
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar == '-') {
+                throw new
+                    NumberFormatException(String.format("Illegal leading minus sign " +
+                                                       "on unsigned string %s.", s));
+            } else {
+                if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
+                    (radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
+                    return parseInt(s, radix);
+                } else {
+                    long ell = Long.parseLong(s, radix);
+                    if ((ell & 0xffff_ffff_0000_0000L) == 0) {
+                        return (int) ell;
+                    } else {
+                        throw new
+                            NumberFormatException(String.format("String value %s exceeds " +
+                                                                "range of unsigned int.", s));
+                    }
+                }
+            }
+        } else {
+            throw NumberFormatException.forInputString(s);
+        }
+    }
+
+    /**
+     * Parses the string argument as an unsigned decimal integer. The
+     * characters in the string must all be decimal digits, except
+     * that the first character may be an an ASCII plus sign {@code
+     * '+'} ({@code '\u005Cu002B'}). The resulting integer value
+     * is returned, exactly as if the argument and the radix 10 were
+     * given as arguments to the {@link
+     * #parseUnsignedInt(java.lang.String, int)} method.
+     *
+     * @param s   a {@code String} containing the unsigned {@code int}
+     *            representation to be parsed
+     * @return    the unsigned integer value represented by the argument in decimal.
+     * @throws    NumberFormatException  if the string does not contain a
+     *            parsable unsigned integer.
+     * @since 1.8
+     */
+    public static int parseUnsignedInt(String s) throws NumberFormatException {
+        return parseUnsignedInt(s, 10);
+    }
+
+    /**
+     * Returns an {@code Integer} object holding the value
+     * extracted from the specified {@code String} when parsed
+     * with the radix given by the second argument. The first argument
+     * is interpreted as representing a signed integer in the radix
+     * specified by the second argument, exactly as if the arguments
+     * were given to the {@link #parseInt(java.lang.String, int)}
+     * method. The result is an {@code Integer} object that
+     * represents the integer value specified by the string.
+     *
+     * <p>In other words, this method returns an {@code Integer}
+     * object equal to the value of:
+     *
+     * <blockquote>
+     *  {@code new Integer(Integer.parseInt(s, radix))}
+     * </blockquote>
+     *
+     * @param      s   the string to be parsed.
+     * @param      radix the radix to be used in interpreting {@code s}
+     * @return     an {@code Integer} object holding the value
+     *             represented by the string argument in the specified
+     *             radix.
+     * @exception NumberFormatException if the {@code String}
+     *            does not contain a parsable {@code int}.
+     */
+    public static Integer valueOf(String s, int radix) throws NumberFormatException {
+        return Integer.valueOf(parseInt(s,radix));
+    }
+
+    /**
+     * Returns an {@code Integer} object holding the
+     * value of the specified {@code String}. The argument is
+     * interpreted as representing a signed decimal integer, exactly
+     * as if the argument were given to the {@link
+     * #parseInt(java.lang.String)} method. The result is an
+     * {@code Integer} object that represents the integer value
+     * specified by the string.
+     *
+     * <p>In other words, this method returns an {@code Integer}
+     * object equal to the value of:
+     *
+     * <blockquote>
+     *  {@code new Integer(Integer.parseInt(s))}
+     * </blockquote>
+     *
+     * @param      s   the string to be parsed.
+     * @return     an {@code Integer} object holding the value
+     *             represented by the string argument.
+     * @exception  NumberFormatException  if the string cannot be parsed
+     *             as an integer.
+     */
+    public static Integer valueOf(String s) throws NumberFormatException {
+        return Integer.valueOf(parseInt(s, 10));
+    }
+
+    /**
+     * Cache to support the object identity semantics of autoboxing for values between
+     * -128 and 127 (inclusive) as required by JLS.
+     *
+     * The cache is initialized on first usage.  The size of the cache
+     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
+     * During VM initialization, java.lang.Integer.IntegerCache.high property
+     * may be set and saved in the private system properties in the
+     * sun.misc.VM class.
+     */
+
+    private static class IntegerCache {
+        static final int low = -128;
+        static final int high;
+        static final Integer cache[];
+
+        static {
+            // high value may be configured by property
+            int h = 127;
+            String integerCacheHighPropValue =
+                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
+            if (integerCacheHighPropValue != null) {
+                try {
+                    int i = parseInt(integerCacheHighPropValue);
+                    i = Math.max(i, 127);
+                    // Maximum array size is Integer.MAX_VALUE
+                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
+                } catch( NumberFormatException nfe) {
+                    // If the property cannot be parsed into an int, ignore it.
+                }
+            }
+            high = h;
+
+            cache = new Integer[(high - low) + 1];
+            int j = low;
+            for(int k = 0; k < cache.length; k++)
+                cache[k] = new Integer(j++);
+
+            // range [-128, 127] must be interned (JLS7 5.1.7)
+            assert IntegerCache.high >= 127;
+        }
+
+        private IntegerCache() {}
+    }
+
+    /**
+     * Returns an {@code Integer} instance representing the specified
+     * {@code int} value.  If a new {@code Integer} instance is not
+     * required, this method should generally be used in preference to
+     * the constructor {@link #Integer(int)}, as this method is likely
+     * to yield significantly better space and time performance by
+     * caching frequently requested values.
+     *
+     * This method will always cache values in the range -128 to 127,
+     * inclusive, and may cache other values outside of this range.
+     *
+     * @param  i an {@code int} value.
+     * @return an {@code Integer} instance representing {@code i}.
+     * @since  1.5
+     */
+    public static Integer valueOf(int i) {
+        if (i >= IntegerCache.low && i <= IntegerCache.high)
+            return IntegerCache.cache[i + (-IntegerCache.low)];
+        return new Integer(i);
+    }
+
+    /**
+     * The value of the {@code Integer}.
+     *
+     * @serial
+     */
+    private final int value;
+
+    /**
+     * Constructs a newly allocated {@code Integer} object that
+     * represents the specified {@code int} value.
+     *
+     * @param   value   the value to be represented by the
+     *                  {@code Integer} object.
+     */
+    public Integer(int value) {
+        this.value = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Integer} object that
+     * represents the {@code int} value indicated by the
+     * {@code String} parameter. The string is converted to an
+     * {@code int} value in exactly the manner used by the
+     * {@code parseInt} method for radix 10.
+     *
+     * @param      s   the {@code String} to be converted to an
+     *                 {@code Integer}.
+     * @exception  NumberFormatException  if the {@code String} does not
+     *               contain a parsable integer.
+     * @see        java.lang.Integer#parseInt(java.lang.String, int)
+     */
+    public Integer(String s) throws NumberFormatException {
+        this.value = parseInt(s, 10);
+    }
+
+    /**
+     * Returns the value of this {@code Integer} as a {@code byte}
+     * after a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public byte byteValue() {
+        return (byte)value;
+    }
+
+    /**
+     * Returns the value of this {@code Integer} as a {@code short}
+     * after a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public short shortValue() {
+        return (short)value;
+    }
+
+    /**
+     * Returns the value of this {@code Integer} as an
+     * {@code int}.
+     */
+    public int intValue() {
+        return value;
+    }
+
+    /**
+     * Returns the value of this {@code Integer} as a {@code long}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     * @see Integer#toUnsignedLong(int)
+     */
+    public long longValue() {
+        return (long)value;
+    }
+
+    /**
+     * Returns the value of this {@code Integer} as a {@code float}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)value;
+    }
+
+    /**
+     * Returns the value of this {@code Integer} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)value;
+    }
+
+    /**
+     * Returns a {@code String} object representing this
+     * {@code Integer}'s value. The value is converted to signed
+     * decimal representation and returned as a string, exactly as if
+     * the integer value were given as an argument to the {@link
+     * java.lang.Integer#toString(int)} method.
+     *
+     * @return  a string representation of the value of this object in
+     *          base&nbsp;10.
+     */
+    public String toString() {
+        return toString(value);
+    }
+
+    /**
+     * Returns a hash code for this {@code Integer}.
+     *
+     * @return  a hash code value for this object, equal to the
+     *          primitive {@code int} value represented by this
+     *          {@code Integer} object.
+     */
+    @Override
+    public int hashCode() {
+        return Integer.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code int} value; compatible with
+     * {@code Integer.hashCode()}.
+     *
+     * @param value the value to hash
+     * @since 1.8
+     *
+     * @return a hash code value for a {@code int} value.
+     */
+    public static int hashCode(int value) {
+        return value;
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is
+     * {@code true} if and only if the argument is not
+     * {@code null} and is an {@code Integer} object that
+     * contains the same {@code int} value as this object.
+     *
+     * @param   obj   the object to compare with.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Integer) {
+            return value == ((Integer)obj).intValue();
+        }
+        return false;
+    }
+
+    /**
+     * Determines the integer value of the system property with the
+     * specified name.
+     *
+     * <p>The first argument is treated as the name of a system
+     * property.  System properties are accessible through the {@link
+     * java.lang.System#getProperty(java.lang.String)} method. The
+     * string value of this property is then interpreted as an integer
+     * value using the grammar supported by {@link Integer#decode decode} and
+     * an {@code Integer} object representing this value is returned.
+     *
+     * <p>If there is no property with the specified name, if the
+     * specified name is empty or {@code null}, or if the property
+     * does not have the correct numeric format, then {@code null} is
+     * returned.
+     *
+     * <p>In other words, this method returns an {@code Integer}
+     * object equal to the value of:
+     *
+     * <blockquote>
+     *  {@code getInteger(nm, null)}
+     * </blockquote>
+     *
+     * @param   nm   property name.
+     * @return  the {@code Integer} value of the property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     java.lang.System#getProperty(java.lang.String)
+     * @see     java.lang.System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static Integer getInteger(String nm) {
+        return getInteger(nm, null);
+    }
+
+    /**
+     * Determines the integer value of the system property with the
+     * specified name.
+     *
+     * <p>The first argument is treated as the name of a system
+     * property.  System properties are accessible through the {@link
+     * java.lang.System#getProperty(java.lang.String)} method. The
+     * string value of this property is then interpreted as an integer
+     * value using the grammar supported by {@link Integer#decode decode} and
+     * an {@code Integer} object representing this value is returned.
+     *
+     * <p>The second argument is the default value. An {@code Integer} object
+     * that represents the value of the second argument is returned if there
+     * is no property of the specified name, if the property does not have
+     * the correct numeric format, or if the specified name is empty or
+     * {@code null}.
+     *
+     * <p>In other words, this method returns an {@code Integer} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     *  {@code getInteger(nm, new Integer(val))}
+     * </blockquote>
+     *
+     * but in practice it may be implemented in a manner such as:
+     *
+     * <blockquote><pre>
+     * Integer result = getInteger(nm, null);
+     * return (result == null) ? new Integer(val) : result;
+     * </pre></blockquote>
+     *
+     * to avoid the unnecessary allocation of an {@code Integer}
+     * object when the default value is not needed.
+     *
+     * @param   nm   property name.
+     * @param   val   default value.
+     * @return  the {@code Integer} value of the property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     java.lang.System#getProperty(java.lang.String)
+     * @see     java.lang.System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static Integer getInteger(String nm, int val) {
+        Integer result = getInteger(nm, null);
+        return (result == null) ? Integer.valueOf(val) : result;
+    }
+
+    /**
+     * Returns the integer value of the system property with the
+     * specified name.  The first argument is treated as the name of a
+     * system property.  System properties are accessible through the
+     * {@link java.lang.System#getProperty(java.lang.String)} method.
+     * The string value of this property is then interpreted as an
+     * integer value, as per the {@link Integer#decode decode} method,
+     * and an {@code Integer} object representing this value is
+     * returned; in summary:
+     *
+     * <ul><li>If the property value begins with the two ASCII characters
+     *         {@code 0x} or the ASCII character {@code #}, not
+     *      followed by a minus sign, then the rest of it is parsed as a
+     *      hexadecimal integer exactly as by the method
+     *      {@link #valueOf(java.lang.String, int)} with radix 16.
+     * <li>If the property value begins with the ASCII character
+     *     {@code 0} followed by another character, it is parsed as an
+     *     octal integer exactly as by the method
+     *     {@link #valueOf(java.lang.String, int)} with radix 8.
+     * <li>Otherwise, the property value is parsed as a decimal integer
+     * exactly as by the method {@link #valueOf(java.lang.String, int)}
+     * with radix 10.
+     * </ul>
+     *
+     * <p>The second argument is the default value. The default value is
+     * returned if there is no property of the specified name, if the
+     * property does not have the correct numeric format, or if the
+     * specified name is empty or {@code null}.
+     *
+     * @param   nm   property name.
+     * @param   val   default value.
+     * @return  the {@code Integer} value of the property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     System#getProperty(java.lang.String)
+     * @see     System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static Integer getInteger(String nm, Integer val) {
+        String v = null;
+        try {
+            v = System.getProperty(nm);
+        } catch (IllegalArgumentException | NullPointerException e) {
+        }
+        if (v != null) {
+            try {
+                return Integer.decode(v);
+            } catch (NumberFormatException e) {
+            }
+        }
+        return val;
+    }
+
+    /**
+     * Decodes a {@code String} into an {@code Integer}.
+     * Accepts decimal, hexadecimal, and octal numbers given
+     * by the following grammar:
+     *
+     * <blockquote>
+     * <dl>
+     * <dt><i>DecodableString:</i>
+     * <dd><i>Sign<sub>opt</sub> DecimalNumeral</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0x} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0X} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code #} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0} <i>OctalDigits</i>
+     *
+     * <dt><i>Sign:</i>
+     * <dd>{@code -}
+     * <dd>{@code +}
+     * </dl>
+     * </blockquote>
+     *
+     * <i>DecimalNumeral</i>, <i>HexDigits</i>, and <i>OctalDigits</i>
+     * are as defined in section 3.10.1 of
+     * <cite>The Java&trade; Language Specification</cite>,
+     * except that underscores are not accepted between digits.
+     *
+     * <p>The sequence of characters following an optional
+     * sign and/or radix specifier ("{@code 0x}", "{@code 0X}",
+     * "{@code #}", or leading zero) is parsed as by the {@code
+     * Integer.parseInt} method with the indicated radix (10, 16, or
+     * 8).  This sequence of characters must represent a positive
+     * value or a {@link NumberFormatException} will be thrown.  The
+     * result is negated if first character of the specified {@code
+     * String} is the minus sign.  No whitespace characters are
+     * permitted in the {@code String}.
+     *
+     * @param     nm the {@code String} to decode.
+     * @return    an {@code Integer} object holding the {@code int}
+     *             value represented by {@code nm}
+     * @exception NumberFormatException  if the {@code String} does not
+     *            contain a parsable integer.
+     * @see java.lang.Integer#parseInt(java.lang.String, int)
+     */
+    public static Integer decode(String nm) throws NumberFormatException {
+        int radix = 10;
+        int index = 0;
+        boolean negative = false;
+        Integer result;
+
+        if (nm.length() == 0)
+            throw new NumberFormatException("Zero length string");
+        char firstChar = nm.charAt(0);
+        // Handle sign, if present
+        if (firstChar == '-') {
+            negative = true;
+            index++;
+        } else if (firstChar == '+')
+            index++;
+
+        // Handle radix specifier, if present
+        if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
+            index += 2;
+            radix = 16;
+        }
+        else if (nm.startsWith("#", index)) {
+            index ++;
+            radix = 16;
+        }
+        else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
+            index ++;
+            radix = 8;
+        }
+
+        if (nm.startsWith("-", index) || nm.startsWith("+", index))
+            throw new NumberFormatException("Sign character in wrong position");
+
+        try {
+            result = Integer.valueOf(nm.substring(index), radix);
+            result = negative ? Integer.valueOf(-result.intValue()) : result;
+        } catch (NumberFormatException e) {
+            // If number is Integer.MIN_VALUE, we'll end up here. The next line
+            // handles this case, and causes any genuine format error to be
+            // rethrown.
+            String constant = negative ? ("-" + nm.substring(index))
+                                       : nm.substring(index);
+            result = Integer.valueOf(constant, radix);
+        }
+        return result;
+    }
+
+    /**
+     * Compares two {@code Integer} objects numerically.
+     *
+     * @param   anotherInteger   the {@code Integer} to be compared.
+     * @return  the value {@code 0} if this {@code Integer} is
+     *          equal to the argument {@code Integer}; a value less than
+     *          {@code 0} if this {@code Integer} is numerically less
+     *          than the argument {@code Integer}; and a value greater
+     *          than {@code 0} if this {@code Integer} is numerically
+     *           greater than the argument {@code Integer} (signed
+     *           comparison).
+     * @since   1.2
+     */
+    public int compareTo(Integer anotherInteger) {
+        return compare(this.value, anotherInteger.value);
+    }
+
+    /**
+     * Compares two {@code int} values numerically.
+     * The value returned is identical to what would be returned by:
+     * <pre>
+     *    Integer.valueOf(x).compareTo(Integer.valueOf(y))
+     * </pre>
+     *
+     * @param  x the first {@code int} to compare
+     * @param  y the second {@code int} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 1.7
+     */
+    public static int compare(int x, int y) {
+        return (x < y) ? -1 : ((x == y) ? 0 : 1);
+    }
+
+    /**
+     * Compares two {@code int} values numerically treating the values
+     * as unsigned.
+     *
+     * @param  x the first {@code int} to compare
+     * @param  y the second {@code int} to compare
+     * @return the value {@code 0} if {@code x == y}; a value less
+     *         than {@code 0} if {@code x < y} as unsigned values; and
+     *         a value greater than {@code 0} if {@code x > y} as
+     *         unsigned values
+     * @since 1.8
+     */
+    public static int compareUnsigned(int x, int y) {
+        return compare(x + MIN_VALUE, y + MIN_VALUE);
+    }
+
+    /**
+     * Converts the argument to a {@code long} by an unsigned
+     * conversion.  In an unsigned conversion to a {@code long}, the
+     * high-order 32 bits of the {@code long} are zero and the
+     * low-order 32 bits are equal to the bits of the integer
+     * argument.
+     *
+     * Consequently, zero and positive {@code int} values are mapped
+     * to a numerically equal {@code long} value and negative {@code
+     * int} values are mapped to a {@code long} value equal to the
+     * input plus 2<sup>32</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code long}
+     * @return the argument converted to {@code long} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static long toUnsignedLong(int x) {
+        return ((long) x) & 0xffffffffL;
+    }
+
+    /**
+     * Returns the unsigned quotient of dividing the first argument by
+     * the second where each argument and the result is interpreted as
+     * an unsigned value.
+     *
+     * <p>Note that in two's complement arithmetic, the three other
+     * basic arithmetic operations of add, subtract, and multiply are
+     * bit-wise identical if the two operands are regarded as both
+     * being signed or both being unsigned.  Therefore separate {@code
+     * addUnsigned}, etc. methods are not provided.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned quotient of the first argument divided by
+     * the second argument
+     * @see #remainderUnsigned
+     * @since 1.8
+     */
+    public static int divideUnsigned(int dividend, int divisor) {
+        // In lieu of tricky code, for now just use long arithmetic.
+        return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
+    }
+
+    /**
+     * Returns the unsigned remainder from dividing the first argument
+     * by the second where each argument and the result is interpreted
+     * as an unsigned value.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned remainder of the first argument divided by
+     * the second argument
+     * @see #divideUnsigned
+     * @since 1.8
+     */
+    public static int remainderUnsigned(int dividend, int divisor) {
+        // In lieu of tricky code, for now just use long arithmetic.
+        return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
+    }
+
+
+    // Bit twiddling
+
+    /**
+     * The number of bits used to represent an {@code int} value in two's
+     * complement binary form.
+     *
+     * @since 1.5
+     */
+    @Native public static final int SIZE = 32;
+
+    /**
+     * The number of bytes used to represent a {@code int} value in two's
+     * complement binary form.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /**
+     * Returns an {@code int} value with at most a single one-bit, in the
+     * position of the highest-order ("leftmost") one-bit in the specified
+     * {@code int} value.  Returns zero if the specified value has no
+     * one-bits in its two's complement binary representation, that is, if it
+     * is equal to zero.
+     *
+     * @param i the value whose highest one bit is to be computed
+     * @return an {@code int} value with a single one-bit, in the position
+     *     of the highest-order one-bit in the specified value, or zero if
+     *     the specified value is itself equal to zero.
+     * @since 1.5
+     */
+    public static int highestOneBit(int i) {
+        // HD, Figure 3-1
+        i |= (i >>  1);
+        i |= (i >>  2);
+        i |= (i >>  4);
+        i |= (i >>  8);
+        i |= (i >> 16);
+        return i - (i >>> 1);
+    }
+
+    /**
+     * Returns an {@code int} value with at most a single one-bit, in the
+     * position of the lowest-order ("rightmost") one-bit in the specified
+     * {@code int} value.  Returns zero if the specified value has no
+     * one-bits in its two's complement binary representation, that is, if it
+     * is equal to zero.
+     *
+     * @param i the value whose lowest one bit is to be computed
+     * @return an {@code int} value with a single one-bit, in the position
+     *     of the lowest-order one-bit in the specified value, or zero if
+     *     the specified value is itself equal to zero.
+     * @since 1.5
+     */
+    public static int lowestOneBit(int i) {
+        // HD, Section 2-1
+        return i & -i;
+    }
+
+    /**
+     * Returns the number of zero bits preceding the highest-order
+     * ("leftmost") one-bit in the two's complement binary representation
+     * of the specified {@code int} value.  Returns 32 if the
+     * specified value has no one-bits in its two's complement representation,
+     * in other words if it is equal to zero.
+     *
+     * <p>Note that this method is closely related to the logarithm base 2.
+     * For all positive {@code int} values x:
+     * <ul>
+     * <li>floor(log<sub>2</sub>(x)) = {@code 31 - numberOfLeadingZeros(x)}
+     * <li>ceil(log<sub>2</sub>(x)) = {@code 32 - numberOfLeadingZeros(x - 1)}
+     * </ul>
+     *
+     * @param i the value whose number of leading zeros is to be computed
+     * @return the number of zero bits preceding the highest-order
+     *     ("leftmost") one-bit in the two's complement binary representation
+     *     of the specified {@code int} value, or 32 if the value
+     *     is equal to zero.
+     * @since 1.5
+     */
+    public static int numberOfLeadingZeros(int i) {
+        // HD, Figure 5-6
+        if (i == 0)
+            return 32;
+        int n = 1;
+        if (i >>> 16 == 0) { n += 16; i <<= 16; }
+        if (i >>> 24 == 0) { n +=  8; i <<=  8; }
+        if (i >>> 28 == 0) { n +=  4; i <<=  4; }
+        if (i >>> 30 == 0) { n +=  2; i <<=  2; }
+        n -= i >>> 31;
+        return n;
+    }
+
+    /**
+     * Returns the number of zero bits following the lowest-order ("rightmost")
+     * one-bit in the two's complement binary representation of the specified
+     * {@code int} value.  Returns 32 if the specified value has no
+     * one-bits in its two's complement representation, in other words if it is
+     * equal to zero.
+     *
+     * @param i the value whose number of trailing zeros is to be computed
+     * @return the number of zero bits following the lowest-order ("rightmost")
+     *     one-bit in the two's complement binary representation of the
+     *     specified {@code int} value, or 32 if the value is equal
+     *     to zero.
+     * @since 1.5
+     */
+    public static int numberOfTrailingZeros(int i) {
+        // HD, Figure 5-14
+        int y;
+        if (i == 0) return 32;
+        int n = 31;
+        y = i <<16; if (y != 0) { n = n -16; i = y; }
+        y = i << 8; if (y != 0) { n = n - 8; i = y; }
+        y = i << 4; if (y != 0) { n = n - 4; i = y; }
+        y = i << 2; if (y != 0) { n = n - 2; i = y; }
+        return n - ((i << 1) >>> 31);
+    }
+
+    /**
+     * Returns the number of one-bits in the two's complement binary
+     * representation of the specified {@code int} value.  This function is
+     * sometimes referred to as the <i>population count</i>.
+     *
+     * @param i the value whose bits are to be counted
+     * @return the number of one-bits in the two's complement binary
+     *     representation of the specified {@code int} value.
+     * @since 1.5
+     */
+    public static int bitCount(int i) {
+        // HD, Figure 5-2
+        i = i - ((i >>> 1) & 0x55555555);
+        i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
+        i = (i + (i >>> 4)) & 0x0f0f0f0f;
+        i = i + (i >>> 8);
+        i = i + (i >>> 16);
+        return i & 0x3f;
+    }
+
+    /**
+     * Returns the value obtained by rotating the two's complement binary
+     * representation of the specified {@code int} value left by the
+     * specified number of bits.  (Bits shifted out of the left hand, or
+     * high-order, side reenter on the right, or low-order.)
+     *
+     * <p>Note that left rotation with a negative distance is equivalent to
+     * right rotation: {@code rotateLeft(val, -distance) == rotateRight(val,
+     * distance)}.  Note also that rotation by any multiple of 32 is a
+     * no-op, so all but the last five bits of the rotation distance can be
+     * ignored, even if the distance is negative: {@code rotateLeft(val,
+     * distance) == rotateLeft(val, distance & 0x1F)}.
+     *
+     * @param i the value whose bits are to be rotated left
+     * @param distance the number of bit positions to rotate left
+     * @return the value obtained by rotating the two's complement binary
+     *     representation of the specified {@code int} value left by the
+     *     specified number of bits.
+     * @since 1.5
+     */
+    public static int rotateLeft(int i, int distance) {
+        return (i << distance) | (i >>> -distance);
+    }
+
+    /**
+     * Returns the value obtained by rotating the two's complement binary
+     * representation of the specified {@code int} value right by the
+     * specified number of bits.  (Bits shifted out of the right hand, or
+     * low-order, side reenter on the left, or high-order.)
+     *
+     * <p>Note that right rotation with a negative distance is equivalent to
+     * left rotation: {@code rotateRight(val, -distance) == rotateLeft(val,
+     * distance)}.  Note also that rotation by any multiple of 32 is a
+     * no-op, so all but the last five bits of the rotation distance can be
+     * ignored, even if the distance is negative: {@code rotateRight(val,
+     * distance) == rotateRight(val, distance & 0x1F)}.
+     *
+     * @param i the value whose bits are to be rotated right
+     * @param distance the number of bit positions to rotate right
+     * @return the value obtained by rotating the two's complement binary
+     *     representation of the specified {@code int} value right by the
+     *     specified number of bits.
+     * @since 1.5
+     */
+    public static int rotateRight(int i, int distance) {
+        return (i >>> distance) | (i << -distance);
+    }
+
+    /**
+     * Returns the value obtained by reversing the order of the bits in the
+     * two's complement binary representation of the specified {@code int}
+     * value.
+     *
+     * @param i the value to be reversed
+     * @return the value obtained by reversing order of the bits in the
+     *     specified {@code int} value.
+     * @since 1.5
+     */
+    public static int reverse(int i) {
+        // HD, Figure 7-1
+        i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
+        i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
+        i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
+        i = (i << 24) | ((i & 0xff00) << 8) |
+            ((i >>> 8) & 0xff00) | (i >>> 24);
+        return i;
+    }
+
+    /**
+     * Returns the signum function of the specified {@code int} value.  (The
+     * return value is -1 if the specified value is negative; 0 if the
+     * specified value is zero; and 1 if the specified value is positive.)
+     *
+     * @param i the value whose signum is to be computed
+     * @return the signum function of the specified {@code int} value.
+     * @since 1.5
+     */
+    public static int signum(int i) {
+        // HD, Section 2-7
+        return (i >> 31) | (-i >>> 31);
+    }
+
+    /**
+     * Returns the value obtained by reversing the order of the bytes in the
+     * two's complement representation of the specified {@code int} value.
+     *
+     * @param i the value whose bytes are to be reversed
+     * @return the value obtained by reversing the bytes in the specified
+     *     {@code int} value.
+     * @since 1.5
+     */
+    public static int reverseBytes(int i) {
+        return ((i >>> 24)           ) |
+               ((i >>   8) &   0xFF00) |
+               ((i <<   8) & 0xFF0000) |
+               ((i << 24));
+    }
+
+    /**
+     * Adds two integers together as per the + operator.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the sum of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static int sum(int a, int b) {
+        return a + b;
+    }
+
+    /**
+     * Returns the greater of two {@code int} values
+     * as if by calling {@link Math#max(int, int) Math.max}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the greater of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static int max(int a, int b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code int} values
+     * as if by calling {@link Math#min(int, int) Math.min}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the smaller of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static int min(int a, int b) {
+        return Math.min(a, b);
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    @Native private static final long serialVersionUID = 1360826667806852920L;
+}
diff --git a/java/lang/InternalError.java b/java/lang/InternalError.java
new file mode 100644
index 0000000..8d33821
--- /dev/null
+++ b/java/lang/InternalError.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate some unexpected internal error has occurred in
+ * the Java Virtual Machine.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public class InternalError extends VirtualMachineError {
+    private static final long serialVersionUID = -9062593416125562365L;
+
+    /**
+     * Constructs an <code>InternalError</code> with no detail message.
+     */
+    public InternalError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InternalError</code> with the specified
+     * detail message.
+     *
+     * @param   message   the detail message.
+     */
+    public InternalError(String message) {
+        super(message);
+    }
+
+
+    /**
+     * Constructs an {@code InternalError} with the specified detail
+     * message and cause.  <p>Note that the detail message associated
+     * with {@code cause} is <i>not</i> automatically incorporated in
+     * this error's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.8
+     */
+    public InternalError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an {@code InternalError} with the specified cause
+     * and a detail message of {@code (cause==null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.8
+     */
+    public InternalError(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/java/lang/InterruptedException.java b/java/lang/InterruptedException.java
new file mode 100644
index 0000000..27bc5a8
--- /dev/null
+++ b/java/lang/InterruptedException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when a thread is waiting, sleeping, or otherwise occupied,
+ * and the thread is interrupted, either before or during the activity.
+ * Occasionally a method may wish to test whether the current
+ * thread has been interrupted, and if so, to immediately throw
+ * this exception.  The following code can be used to achieve
+ * this effect:
+ * <pre>
+ *  if (Thread.interrupted())  // Clears interrupted status!
+ *      throw new InterruptedException();
+ * </pre>
+ *
+ * @author  Frank Yellin
+ * @see     java.lang.Object#wait()
+ * @see     java.lang.Object#wait(long)
+ * @see     java.lang.Object#wait(long, int)
+ * @see     java.lang.Thread#sleep(long)
+ * @see     java.lang.Thread#interrupt()
+ * @see     java.lang.Thread#interrupted()
+ * @since   JDK1.0
+ */
+public
+class InterruptedException extends Exception {
+    private static final long serialVersionUID = 6700697376100628473L;
+
+    /**
+     * Constructs an <code>InterruptedException</code> with no detail  message.
+     */
+    public InterruptedException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InterruptedException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public InterruptedException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/Iterable.annotated.java b/java/lang/Iterable.annotated.java
new file mode 100644
index 0000000..8986b35
--- /dev/null
+++ b/java/lang/Iterable.annotated.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import libcore.util.NonNull;
+import libcore.util.NullFromTypeParam;
+
+public interface Iterable<T> {
+
+  public @NonNull Iterator<@NullFromTypeParam T> iterator();
+  public default void forEach(@NonNull Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+  @NonNull public default Spliterator<T> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/Iterable.java b/java/lang/Iterable.java
new file mode 100644
index 0000000..eed3938
--- /dev/null
+++ b/java/lang/Iterable.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+
+/**
+ * Implementing this interface allows an object to be the target of
+ * the "for-each loop" statement. See
+ * <strong>
+ * <a href="{@docRoot}/../technotes/guides/language/foreach.html">For-each Loop</a>
+ * </strong>
+ *
+ * @param <T> the type of elements returned by the iterator
+ *
+ * @since 1.5
+ * @jls 14.14.2 The enhanced for statement
+ */
+public interface Iterable<T> {
+    /**
+     * Returns an iterator over elements of type {@code T}.
+     *
+     * @return an Iterator.
+     */
+    Iterator<T> iterator();
+
+    /**
+     * Performs the given action for each element of the {@code Iterable}
+     * until all elements have been processed or the action throws an
+     * exception.  Unless otherwise specified by the implementing class,
+     * actions are performed in the order of iteration (if an iteration order
+     * is specified).  Exceptions thrown by the action are relayed to the
+     * caller.
+     *
+     * @implSpec
+     * <p>The default implementation behaves as if:
+     * <pre>{@code
+     *     for (T t : this)
+     *         action.accept(t);
+     * }</pre>
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     * @since 1.8
+     */
+    default void forEach(Consumer<? super T> action) {
+        Objects.requireNonNull(action);
+        for (T t : this) {
+            action.accept(t);
+        }
+    }
+
+    /**
+     * Creates a {@link Spliterator} over the elements described by this
+     * {@code Iterable}.
+     *
+     * @implSpec
+     * The default implementation creates an
+     * <em><a href="Spliterator.html#binding">early-binding</a></em>
+     * spliterator from the iterable's {@code Iterator}.  The spliterator
+     * inherits the <em>fail-fast</em> properties of the iterable's iterator.
+     *
+     * @implNote
+     * The default implementation should usually be overridden.  The
+     * spliterator returned by the default implementation has poor splitting
+     * capabilities, is unsized, and does not report any spliterator
+     * characteristics. Implementing classes can nearly always provide a
+     * better implementation.
+     *
+     * @return a {@code Spliterator} over the elements described by this
+     * {@code Iterable}.
+     * @since 1.8
+     */
+    default Spliterator<T> spliterator() {
+        return Spliterators.spliteratorUnknownSize(iterator(), 0);
+    }
+}
diff --git a/java/lang/LinkageError.java b/java/lang/LinkageError.java
new file mode 100644
index 0000000..6b5f060
--- /dev/null
+++ b/java/lang/LinkageError.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Subclasses of {@code LinkageError} indicate that a class has
+ * some dependency on another class; however, the latter class has
+ * incompatibly changed after the compilation of the former class.
+ *
+ *
+ * @author  Frank Yellin
+ * @since   JDK1.0
+ */
+public
+class LinkageError extends Error {
+    private static final long serialVersionUID = 3579600108157160122L;
+
+    /**
+     * Constructs a {@code LinkageError} with no detail message.
+     */
+    public LinkageError() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code LinkageError} with the specified detail
+     * message.
+     *
+     * @param   s   the detail message.
+     */
+    public LinkageError(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a {@code LinkageError} with the specified detail
+     * message and cause.
+     *
+     * @param s     the detail message.
+     * @param cause the cause, may be {@code null}
+     * @since 1.7
+     */
+    public LinkageError(String s, Throwable cause) {
+        super(s, cause);
+    }
+}
diff --git a/java/lang/Long.annotated.java b/java/lang/Long.annotated.java
new file mode 100644
index 0000000..b077ef5
--- /dev/null
+++ b/java/lang/Long.annotated.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.math.*;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Long extends java.lang.Number implements java.lang.Comparable<java.lang.Long> {
+
+public Long(long value) { throw new RuntimeException("Stub!"); }
+
+public Long(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(long i, int radix) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toUnsignedString(long i, int radix) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toHexString(long i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toOctalString(long i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toBinaryString(long i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(long i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toUnsignedString(long i) { throw new RuntimeException("Stub!"); }
+
+public static long parseLong(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static long parseLong(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static long parseUnsignedLong(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public static long parseUnsignedLong(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long valueOf(@libcore.util.NonNull java.lang.String s, int radix) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long valueOf(@libcore.util.NonNull java.lang.String s) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long valueOf(long l) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long decode(@libcore.util.NonNull java.lang.String nm) throws java.lang.NumberFormatException { throw new RuntimeException("Stub!"); }
+
+public byte byteValue() { throw new RuntimeException("Stub!"); }
+
+public short shortValue() { throw new RuntimeException("Stub!"); }
+
+public int intValue() { throw new RuntimeException("Stub!"); }
+
+public long longValue() { throw new RuntimeException("Stub!"); }
+
+public float floatValue() { throw new RuntimeException("Stub!"); }
+
+public double doubleValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(long value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long getLong(@libcore.util.NonNull java.lang.String nm) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long getLong(@libcore.util.NonNull java.lang.String nm, long val) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Long getLong(@libcore.util.NonNull java.lang.String nm, @libcore.util.Nullable java.lang.Long val) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.lang.Long anotherLong) { throw new RuntimeException("Stub!"); }
+
+public static int compare(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static int compareUnsigned(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static long divideUnsigned(long dividend, long divisor) { throw new RuntimeException("Stub!"); }
+
+public static long remainderUnsigned(long dividend, long divisor) { throw new RuntimeException("Stub!"); }
+
+public static long highestOneBit(long i) { throw new RuntimeException("Stub!"); }
+
+public static long lowestOneBit(long i) { throw new RuntimeException("Stub!"); }
+
+public static int numberOfLeadingZeros(long i) { throw new RuntimeException("Stub!"); }
+
+public static int numberOfTrailingZeros(long i) { throw new RuntimeException("Stub!"); }
+
+public static int bitCount(long i) { throw new RuntimeException("Stub!"); }
+
+public static long rotateLeft(long i, int distance) { throw new RuntimeException("Stub!"); }
+
+public static long rotateRight(long i, int distance) { throw new RuntimeException("Stub!"); }
+
+public static long reverse(long i) { throw new RuntimeException("Stub!"); }
+
+public static int signum(long i) { throw new RuntimeException("Stub!"); }
+
+public static long reverseBytes(long i) { throw new RuntimeException("Stub!"); }
+
+public static long sum(long a, long b) { throw new RuntimeException("Stub!"); }
+
+public static long max(long a, long b) { throw new RuntimeException("Stub!"); }
+
+public static long min(long a, long b) { throw new RuntimeException("Stub!"); }
+
+public static final int BYTES = 8; // 0x8
+
+public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL
+
+public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L
+
+public static final int SIZE = 64; // 0x40
+
+public static final java.lang.Class<java.lang.Long> TYPE;
+static { TYPE = null; }
+}
+
diff --git a/java/lang/Long.java b/java/lang/Long.java
new file mode 100644
index 0000000..0047125
--- /dev/null
+++ b/java/lang/Long.java
@@ -0,0 +1,1625 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.Native;
+import java.math.*;
+
+
+/**
+ * The {@code Long} class wraps a value of the primitive type {@code
+ * long} in an object. An object of type {@code Long} contains a
+ * single field whose type is {@code long}.
+ *
+ * <p> In addition, this class provides several methods for converting
+ * a {@code long} to a {@code String} and a {@code String} to a {@code
+ * long}, as well as other constants and methods useful when dealing
+ * with a {@code long}.
+ *
+ * <p>Implementation note: The implementations of the "bit twiddling"
+ * methods (such as {@link #highestOneBit(long) highestOneBit} and
+ * {@link #numberOfTrailingZeros(long) numberOfTrailingZeros}) are
+ * based on material from Henry S. Warren, Jr.'s <i>Hacker's
+ * Delight</i>, (Addison Wesley, 2002).
+ *
+ * @author  Lee Boynton
+ * @author  Arthur van Hoff
+ * @author  Josh Bloch
+ * @author  Joseph D. Darcy
+ * @since   JDK1.0
+ */
+public final class Long extends Number implements Comparable<Long> {
+    /**
+     * A constant holding the minimum value a {@code long} can
+     * have, -2<sup>63</sup>.
+     */
+    @Native public static final long MIN_VALUE = 0x8000000000000000L;
+
+    /**
+     * A constant holding the maximum value a {@code long} can
+     * have, 2<sup>63</sup>-1.
+     */
+    @Native public static final long MAX_VALUE = 0x7fffffffffffffffL;
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code long}.
+     *
+     * @since   JDK1.1
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Long>     TYPE = (Class<Long>) Class.getPrimitiveClass("long");
+
+    /**
+     * Returns a string representation of the first argument in the
+     * radix specified by the second argument.
+     *
+     * <p>If the radix is smaller than {@code Character.MIN_RADIX}
+     * or larger than {@code Character.MAX_RADIX}, then the radix
+     * {@code 10} is used instead.
+     *
+     * <p>If the first argument is negative, the first element of the
+     * result is the ASCII minus sign {@code '-'}
+     * ({@code '\u005Cu002d'}). If the first argument is not
+     * negative, no sign character appears in the result.
+     *
+     * <p>The remaining characters of the result represent the magnitude
+     * of the first argument. If the magnitude is zero, it is
+     * represented by a single zero character {@code '0'}
+     * ({@code '\u005Cu0030'}); otherwise, the first character of
+     * the representation of the magnitude will not be the zero
+     * character.  The following ASCII characters are used as digits:
+     *
+     * <blockquote>
+     *   {@code 0123456789abcdefghijklmnopqrstuvwxyz}
+     * </blockquote>
+     *
+     * These are {@code '\u005Cu0030'} through
+     * {@code '\u005Cu0039'} and {@code '\u005Cu0061'} through
+     * {@code '\u005Cu007a'}. If {@code radix} is
+     * <var>N</var>, then the first <var>N</var> of these characters
+     * are used as radix-<var>N</var> digits in the order shown. Thus,
+     * the digits for hexadecimal (radix 16) are
+     * {@code 0123456789abcdef}. If uppercase letters are
+     * desired, the {@link java.lang.String#toUpperCase()} method may
+     * be called on the result:
+     *
+     * <blockquote>
+     *  {@code Long.toString(n, 16).toUpperCase()}
+     * </blockquote>
+     *
+     * @param   i       a {@code long} to be converted to a string.
+     * @param   radix   the radix to use in the string representation.
+     * @return  a string representation of the argument in the specified radix.
+     * @see     java.lang.Character#MAX_RADIX
+     * @see     java.lang.Character#MIN_RADIX
+     */
+    public static String toString(long i, int radix) {
+        if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
+            radix = 10;
+        if (radix == 10)
+            return toString(i);
+        char[] buf = new char[65];
+        int charPos = 64;
+        boolean negative = (i < 0);
+
+        if (!negative) {
+            i = -i;
+        }
+
+        while (i <= -radix) {
+            buf[charPos--] = Integer.digits[(int)(-(i % radix))];
+            i = i / radix;
+        }
+        buf[charPos] = Integer.digits[(int)(-i)];
+
+        if (negative) {
+            buf[--charPos] = '-';
+        }
+
+        return new String(buf, charPos, (65 - charPos));
+    }
+
+    /**
+     * Returns a string representation of the first argument as an
+     * unsigned integer value in the radix specified by the second
+     * argument.
+     *
+     * <p>If the radix is smaller than {@code Character.MIN_RADIX}
+     * or larger than {@code Character.MAX_RADIX}, then the radix
+     * {@code 10} is used instead.
+     *
+     * <p>Note that since the first argument is treated as an unsigned
+     * value, no leading sign character is printed.
+     *
+     * <p>If the magnitude is zero, it is represented by a single zero
+     * character {@code '0'} ({@code '\u005Cu0030'}); otherwise,
+     * the first character of the representation of the magnitude will
+     * not be the zero character.
+     *
+     * <p>The behavior of radixes and the characters used as digits
+     * are the same as {@link #toString(long, int) toString}.
+     *
+     * @param   i       an integer to be converted to an unsigned string.
+     * @param   radix   the radix to use in the string representation.
+     * @return  an unsigned string representation of the argument in the specified radix.
+     * @see     #toString(long, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(long i, int radix) {
+        if (i >= 0)
+            return toString(i, radix);
+        else {
+            switch (radix) {
+            case 2:
+                return toBinaryString(i);
+
+            case 4:
+                return toUnsignedString0(i, 2);
+
+            case 8:
+                return toOctalString(i);
+
+            case 10:
+                /*
+                 * We can get the effect of an unsigned division by 10
+                 * on a long value by first shifting right, yielding a
+                 * positive value, and then dividing by 5.  This
+                 * allows the last digit and preceding digits to be
+                 * isolated more quickly than by an initial conversion
+                 * to BigInteger.
+                 */
+                long quot = (i >>> 1) / 5;
+                long rem = i - quot * 10;
+                return toString(quot) + rem;
+
+            case 16:
+                return toHexString(i);
+
+            case 32:
+                return toUnsignedString0(i, 5);
+
+            default:
+                return toUnsignedBigInteger(i).toString(radix);
+            }
+        }
+    }
+
+    /**
+     * Return a BigInteger equal to the unsigned value of the
+     * argument.
+     */
+    private static BigInteger toUnsignedBigInteger(long i) {
+        if (i >= 0L)
+            return BigInteger.valueOf(i);
+        else {
+            int upper = (int) (i >>> 32);
+            int lower = (int) i;
+
+            // return (upper << 32) + lower
+            return (BigInteger.valueOf(Integer.toUnsignedLong(upper))).shiftLeft(32).
+                add(BigInteger.valueOf(Integer.toUnsignedLong(lower)));
+        }
+    }
+
+    /**
+     * Returns a string representation of the {@code long}
+     * argument as an unsigned integer in base&nbsp;16.
+     *
+     * <p>The unsigned {@code long} value is the argument plus
+     * 2<sup>64</sup> if the argument is negative; otherwise, it is
+     * equal to the argument.  This value is converted to a string of
+     * ASCII digits in hexadecimal (base&nbsp;16) with no extra
+     * leading {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s,
+     * 16)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} ({@code '\u005Cu0030'});
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as hexadecimal digits:
+     *
+     * <blockquote>
+     *  {@code 0123456789abcdef}
+     * </blockquote>
+     *
+     * These are the characters {@code '\u005Cu0030'} through
+     * {@code '\u005Cu0039'} and  {@code '\u005Cu0061'} through
+     * {@code '\u005Cu0066'}.  If uppercase letters are desired,
+     * the {@link java.lang.String#toUpperCase()} method may be called
+     * on the result:
+     *
+     * <blockquote>
+     *  {@code Long.toHexString(n).toUpperCase()}
+     * </blockquote>
+     *
+     * @param   i   a {@code long} to be converted to a string.
+     * @return  the string representation of the unsigned {@code long}
+     *          value represented by the argument in hexadecimal
+     *          (base&nbsp;16).
+     * @see #parseUnsignedLong(String, int)
+     * @see #toUnsignedString(long, int)
+     * @since   JDK 1.0.2
+     */
+    public static String toHexString(long i) {
+        return toUnsignedString0(i, 4);
+    }
+
+    /**
+     * Returns a string representation of the {@code long}
+     * argument as an unsigned integer in base&nbsp;8.
+     *
+     * <p>The unsigned {@code long} value is the argument plus
+     * 2<sup>64</sup> if the argument is negative; otherwise, it is
+     * equal to the argument.  This value is converted to a string of
+     * ASCII digits in octal (base&nbsp;8) with no extra leading
+     * {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s,
+     * 8)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} ({@code '\u005Cu0030'});
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * following characters are used as octal digits:
+     *
+     * <blockquote>
+     *  {@code 01234567}
+     * </blockquote>
+     *
+     * These are the characters {@code '\u005Cu0030'} through
+     * {@code '\u005Cu0037'}.
+     *
+     * @param   i   a {@code long} to be converted to a string.
+     * @return  the string representation of the unsigned {@code long}
+     *          value represented by the argument in octal (base&nbsp;8).
+     * @see #parseUnsignedLong(String, int)
+     * @see #toUnsignedString(long, int)
+     * @since   JDK 1.0.2
+     */
+    public static String toOctalString(long i) {
+        return toUnsignedString0(i, 3);
+    }
+
+    /**
+     * Returns a string representation of the {@code long}
+     * argument as an unsigned integer in base&nbsp;2.
+     *
+     * <p>The unsigned {@code long} value is the argument plus
+     * 2<sup>64</sup> if the argument is negative; otherwise, it is
+     * equal to the argument.  This value is converted to a string of
+     * ASCII digits in binary (base&nbsp;2) with no extra leading
+     * {@code 0}s.
+     *
+     * <p>The value of the argument can be recovered from the returned
+     * string {@code s} by calling {@link
+     * Long#parseUnsignedLong(String, int) Long.parseUnsignedLong(s,
+     * 2)}.
+     *
+     * <p>If the unsigned magnitude is zero, it is represented by a
+     * single zero character {@code '0'} ({@code '\u005Cu0030'});
+     * otherwise, the first character of the representation of the
+     * unsigned magnitude will not be the zero character. The
+     * characters {@code '0'} ({@code '\u005Cu0030'}) and {@code
+     * '1'} ({@code '\u005Cu0031'}) are used as binary digits.
+     *
+     * @param   i   a {@code long} to be converted to a string.
+     * @return  the string representation of the unsigned {@code long}
+     *          value represented by the argument in binary (base&nbsp;2).
+     * @see #parseUnsignedLong(String, int)
+     * @see #toUnsignedString(long, int)
+     * @since   JDK 1.0.2
+     */
+    public static String toBinaryString(long i) {
+        return toUnsignedString0(i, 1);
+    }
+
+    /**
+     * Format a long (treated as unsigned) into a String.
+     * @param val the value to format
+     * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
+     */
+    static String toUnsignedString0(long val, int shift) {
+        // assert shift > 0 && shift <=5 : "Illegal shift value";
+        int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
+        int chars = Math.max(((mag + (shift - 1)) / shift), 1);
+        char[] buf = new char[chars];
+
+        formatUnsignedLong(val, shift, buf, 0, chars);
+        // Android-changed: Use regular constructor instead of one which takes over "buf".
+        // return new String(buf, true);
+        return new String(buf);
+    }
+
+    /**
+     * Format a long (treated as unsigned) into a character buffer.
+     * @param val the unsigned long to format
+     * @param shift the log2 of the base to format in (4 for hex, 3 for octal, 1 for binary)
+     * @param buf the character buffer to write to
+     * @param offset the offset in the destination buffer to start at
+     * @param len the number of characters to write
+     * @return the lowest character location used
+     */
+     static int formatUnsignedLong(long val, int shift, char[] buf, int offset, int len) {
+        int charPos = len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            buf[offset + --charPos] = Integer.digits[((int) val) & mask];
+            val >>>= shift;
+        } while (val != 0 && charPos > 0);
+
+        return charPos;
+    }
+
+    /**
+     * Returns a {@code String} object representing the specified
+     * {@code long}.  The argument is converted to signed decimal
+     * representation and returned as a string, exactly as if the
+     * argument and the radix 10 were given as arguments to the {@link
+     * #toString(long, int)} method.
+     *
+     * @param   i   a {@code long} to be converted.
+     * @return  a string representation of the argument in base&nbsp;10.
+     */
+    public static String toString(long i) {
+        if (i == Long.MIN_VALUE)
+            return "-9223372036854775808";
+        int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
+        char[] buf = new char[size];
+        getChars(i, size, buf);
+        // Android-changed: Use regular constructor instead of one which takes over "buf".
+        // return new String(buf, true);
+        return new String(buf);
+    }
+
+    /**
+     * Returns a string representation of the argument as an unsigned
+     * decimal value.
+     *
+     * The argument is converted to unsigned decimal representation
+     * and returned as a string exactly as if the argument and radix
+     * 10 were given as arguments to the {@link #toUnsignedString(long,
+     * int)} method.
+     *
+     * @param   i  an integer to be converted to an unsigned string.
+     * @return  an unsigned string representation of the argument.
+     * @see     #toUnsignedString(long, int)
+     * @since 1.8
+     */
+    public static String toUnsignedString(long i) {
+        return toUnsignedString(i, 10);
+    }
+
+    /**
+     * Places characters representing the integer i into the
+     * character array buf. The characters are placed into
+     * the buffer backwards starting with the least significant
+     * digit at the specified index (exclusive), and working
+     * backwards from there.
+     *
+     * Will fail if i == Long.MIN_VALUE
+     */
+    static void getChars(long i, int index, char[] buf) {
+        long q;
+        int r;
+        int charPos = index;
+        char sign = 0;
+
+        if (i < 0) {
+            sign = '-';
+            i = -i;
+        }
+
+        // Get 2 digits/iteration using longs until quotient fits into an int
+        while (i > Integer.MAX_VALUE) {
+            q = i / 100;
+            // really: r = i - (q * 100);
+            r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
+            i = q;
+            buf[--charPos] = Integer.DigitOnes[r];
+            buf[--charPos] = Integer.DigitTens[r];
+        }
+
+        // Get 2 digits/iteration using ints
+        int q2;
+        int i2 = (int)i;
+        while (i2 >= 65536) {
+            q2 = i2 / 100;
+            // really: r = i2 - (q * 100);
+            r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
+            i2 = q2;
+            buf[--charPos] = Integer.DigitOnes[r];
+            buf[--charPos] = Integer.DigitTens[r];
+        }
+
+        // Fall thru to fast mode for smaller numbers
+        // assert(i2 <= 65536, i2);
+        for (;;) {
+            q2 = (i2 * 52429) >>> (16+3);
+            r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
+            buf[--charPos] = Integer.digits[r];
+            i2 = q2;
+            if (i2 == 0) break;
+        }
+        if (sign != 0) {
+            buf[--charPos] = sign;
+        }
+    }
+
+    // Requires positive x
+    static int stringSize(long x) {
+        long p = 10;
+        for (int i=1; i<19; i++) {
+            if (x < p)
+                return i;
+            p = 10*p;
+        }
+        return 19;
+    }
+
+    /**
+     * Parses the string argument as a signed {@code long} in the
+     * radix specified by the second argument. The characters in the
+     * string must all be digits of the specified radix (as determined
+     * by whether {@link java.lang.Character#digit(char, int)} returns
+     * a nonnegative value), except that the first character may be an
+     * ASCII minus sign {@code '-'} ({@code '\u005Cu002D'}) to
+     * indicate a negative value or an ASCII plus sign {@code '+'}
+     * ({@code '\u005Cu002B'}) to indicate a positive value. The
+     * resulting {@code long} value is returned.
+     *
+     * <p>Note that neither the character {@code L}
+     * ({@code '\u005Cu004C'}) nor {@code l}
+     * ({@code '\u005Cu006C'}) is permitted to appear at the end
+     * of the string as a type indicator, as would be permitted in
+     * Java programming language source code - except that either
+     * {@code L} or {@code l} may appear as a digit for a
+     * radix greater than or equal to 22.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     *
+     * <li>The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li>The {@code radix} is either smaller than {@link
+     * java.lang.Character#MIN_RADIX} or larger than {@link
+     * java.lang.Character#MAX_RADIX}.
+     *
+     * <li>Any character of the string is not a digit of the specified
+     * radix, except that the first character may be a minus sign
+     * {@code '-'} ({@code '\u005Cu002d'}) or plus sign {@code
+     * '+'} ({@code '\u005Cu002B'}) provided that the string is
+     * longer than length 1.
+     *
+     * <li>The value represented by the string is not a value of type
+     *      {@code long}.
+     * </ul>
+     *
+     * <p>Examples:
+     * <blockquote><pre>
+     * parseLong("0", 10) returns 0L
+     * parseLong("473", 10) returns 473L
+     * parseLong("+42", 10) returns 42L
+     * parseLong("-0", 10) returns 0L
+     * parseLong("-FF", 16) returns -255L
+     * parseLong("1100110", 2) returns 102L
+     * parseLong("99", 8) throws a NumberFormatException
+     * parseLong("Hazelnut", 10) throws a NumberFormatException
+     * parseLong("Hazelnut", 36) returns 1356099454469L
+     * </pre></blockquote>
+     *
+     * @param      s       the {@code String} containing the
+     *                     {@code long} representation to be parsed.
+     * @param      radix   the radix to be used while parsing {@code s}.
+     * @return     the {@code long} represented by the string argument in
+     *             the specified radix.
+     * @throws     NumberFormatException  if the string does not contain a
+     *             parsable {@code long}.
+     */
+    public static long parseLong(String s, int radix)
+              throws NumberFormatException
+    {
+        if (s == null) {
+            throw new NumberFormatException("null");
+        }
+
+        if (radix < Character.MIN_RADIX) {
+            throw new NumberFormatException("radix " + radix +
+                                            " less than Character.MIN_RADIX");
+        }
+        if (radix > Character.MAX_RADIX) {
+            throw new NumberFormatException("radix " + radix +
+                                            " greater than Character.MAX_RADIX");
+        }
+
+        long result = 0;
+        boolean negative = false;
+        int i = 0, len = s.length();
+        long limit = -Long.MAX_VALUE;
+        long multmin;
+        int digit;
+
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar < '0') { // Possible leading "+" or "-"
+                if (firstChar == '-') {
+                    negative = true;
+                    limit = Long.MIN_VALUE;
+                } else if (firstChar != '+')
+                    throw NumberFormatException.forInputString(s);
+
+                if (len == 1) // Cannot have lone "+" or "-"
+                    throw NumberFormatException.forInputString(s);
+                i++;
+            }
+            multmin = limit / radix;
+            while (i < len) {
+                // Accumulating negatively avoids surprises near MAX_VALUE
+                digit = Character.digit(s.charAt(i++),radix);
+                if (digit < 0) {
+                    throw NumberFormatException.forInputString(s);
+                }
+                if (result < multmin) {
+                    throw NumberFormatException.forInputString(s);
+                }
+                result *= radix;
+                if (result < limit + digit) {
+                    throw NumberFormatException.forInputString(s);
+                }
+                result -= digit;
+            }
+        } else {
+            throw NumberFormatException.forInputString(s);
+        }
+        return negative ? result : -result;
+    }
+
+    /**
+     * Parses the string argument as a signed decimal {@code long}.
+     * The characters in the string must all be decimal digits, except
+     * that the first character may be an ASCII minus sign {@code '-'}
+     * ({@code \u005Cu002D'}) to indicate a negative value or an
+     * ASCII plus sign {@code '+'} ({@code '\u005Cu002B'}) to
+     * indicate a positive value. The resulting {@code long} value is
+     * returned, exactly as if the argument and the radix {@code 10}
+     * were given as arguments to the {@link
+     * #parseLong(java.lang.String, int)} method.
+     *
+     * <p>Note that neither the character {@code L}
+     * ({@code '\u005Cu004C'}) nor {@code l}
+     * ({@code '\u005Cu006C'}) is permitted to appear at the end
+     * of the string as a type indicator, as would be permitted in
+     * Java programming language source code.
+     *
+     * @param      s   a {@code String} containing the {@code long}
+     *             representation to be parsed
+     * @return     the {@code long} represented by the argument in
+     *             decimal.
+     * @throws     NumberFormatException  if the string does not contain a
+     *             parsable {@code long}.
+     */
+    public static long parseLong(String s) throws NumberFormatException {
+        return parseLong(s, 10);
+    }
+
+    /**
+     * Parses the string argument as an unsigned {@code long} in the
+     * radix specified by the second argument.  An unsigned integer
+     * maps the values usually associated with negative numbers to
+     * positive numbers larger than {@code MAX_VALUE}.
+     *
+     * The characters in the string must all be digits of the
+     * specified radix (as determined by whether {@link
+     * java.lang.Character#digit(char, int)} returns a nonnegative
+     * value), except that the first character may be an ASCII plus
+     * sign {@code '+'} ({@code '\u005Cu002B'}). The resulting
+     * integer value is returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li>The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li>The radix is either smaller than
+     * {@link java.lang.Character#MIN_RADIX} or
+     * larger than {@link java.lang.Character#MAX_RADIX}.
+     *
+     * <li>Any character of the string is not a digit of the specified
+     * radix, except that the first character may be a plus sign
+     * {@code '+'} ({@code '\u005Cu002B'}) provided that the
+     * string is longer than length 1.
+     *
+     * <li>The value represented by the string is larger than the
+     * largest unsigned {@code long}, 2<sup>64</sup>-1.
+     *
+     * </ul>
+     *
+     *
+     * @param      s   the {@code String} containing the unsigned integer
+     *                  representation to be parsed
+     * @param      radix   the radix to be used while parsing {@code s}.
+     * @return     the unsigned {@code long} represented by the string
+     *             argument in the specified radix.
+     * @throws     NumberFormatException if the {@code String}
+     *             does not contain a parsable {@code long}.
+     * @since 1.8
+     */
+    public static long parseUnsignedLong(String s, int radix)
+                throws NumberFormatException {
+        if (s == null)  {
+            throw new NumberFormatException("null");
+        }
+
+        int len = s.length();
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar == '-') {
+                throw new
+                    NumberFormatException(String.format("Illegal leading minus sign " +
+                                                       "on unsigned string %s.", s));
+            } else {
+                if (len <= 12 || // Long.MAX_VALUE in Character.MAX_RADIX is 13 digits
+                    (radix == 10 && len <= 18) ) { // Long.MAX_VALUE in base 10 is 19 digits
+                    return parseLong(s, radix);
+                }
+
+                // No need for range checks on len due to testing above.
+                long first = parseLong(s.substring(0, len - 1), radix);
+                int second = Character.digit(s.charAt(len - 1), radix);
+                if (second < 0) {
+                    throw new NumberFormatException("Bad digit at end of " + s);
+                }
+                long result = first * radix + second;
+                if (compareUnsigned(result, first) < 0) {
+                    /*
+                     * The maximum unsigned value, (2^64)-1, takes at
+                     * most one more digit to represent than the
+                     * maximum signed value, (2^63)-1.  Therefore,
+                     * parsing (len - 1) digits will be appropriately
+                     * in-range of the signed parsing.  In other
+                     * words, if parsing (len -1) digits overflows
+                     * signed parsing, parsing len digits will
+                     * certainly overflow unsigned parsing.
+                     *
+                     * The compareUnsigned check above catches
+                     * situations where an unsigned overflow occurs
+                     * incorporating the contribution of the final
+                     * digit.
+                     */
+                    throw new NumberFormatException(String.format("String value %s exceeds " +
+                                                                  "range of unsigned long.", s));
+                }
+                return result;
+            }
+        } else {
+            throw NumberFormatException.forInputString(s);
+        }
+    }
+
+    /**
+     * Parses the string argument as an unsigned decimal {@code long}. The
+     * characters in the string must all be decimal digits, except
+     * that the first character may be an an ASCII plus sign {@code
+     * '+'} ({@code '\u005Cu002B'}). The resulting integer value
+     * is returned, exactly as if the argument and the radix 10 were
+     * given as arguments to the {@link
+     * #parseUnsignedLong(java.lang.String, int)} method.
+     *
+     * @param s   a {@code String} containing the unsigned {@code long}
+     *            representation to be parsed
+     * @return    the unsigned {@code long} value represented by the decimal string argument
+     * @throws    NumberFormatException  if the string does not contain a
+     *            parsable unsigned integer.
+     * @since 1.8
+     */
+    public static long parseUnsignedLong(String s) throws NumberFormatException {
+        return parseUnsignedLong(s, 10);
+    }
+
+    /**
+     * Returns a {@code Long} object holding the value
+     * extracted from the specified {@code String} when parsed
+     * with the radix given by the second argument.  The first
+     * argument is interpreted as representing a signed
+     * {@code long} in the radix specified by the second
+     * argument, exactly as if the arguments were given to the {@link
+     * #parseLong(java.lang.String, int)} method. The result is a
+     * {@code Long} object that represents the {@code long}
+     * value specified by the string.
+     *
+     * <p>In other words, this method returns a {@code Long} object equal
+     * to the value of:
+     *
+     * <blockquote>
+     *  {@code new Long(Long.parseLong(s, radix))}
+     * </blockquote>
+     *
+     * @param      s       the string to be parsed
+     * @param      radix   the radix to be used in interpreting {@code s}
+     * @return     a {@code Long} object holding the value
+     *             represented by the string argument in the specified
+     *             radix.
+     * @throws     NumberFormatException  If the {@code String} does not
+     *             contain a parsable {@code long}.
+     */
+    public static Long valueOf(String s, int radix) throws NumberFormatException {
+        return Long.valueOf(parseLong(s, radix));
+    }
+
+    /**
+     * Returns a {@code Long} object holding the value
+     * of the specified {@code String}. The argument is
+     * interpreted as representing a signed decimal {@code long},
+     * exactly as if the argument were given to the {@link
+     * #parseLong(java.lang.String)} method. The result is a
+     * {@code Long} object that represents the integer value
+     * specified by the string.
+     *
+     * <p>In other words, this method returns a {@code Long} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     *  {@code new Long(Long.parseLong(s))}
+     * </blockquote>
+     *
+     * @param      s   the string to be parsed.
+     * @return     a {@code Long} object holding the value
+     *             represented by the string argument.
+     * @throws     NumberFormatException  If the string cannot be parsed
+     *             as a {@code long}.
+     */
+    public static Long valueOf(String s) throws NumberFormatException
+    {
+        return Long.valueOf(parseLong(s, 10));
+    }
+
+    private static class LongCache {
+        private LongCache(){}
+
+        static final Long cache[] = new Long[-(-128) + 127 + 1];
+
+        static {
+            for(int i = 0; i < cache.length; i++)
+                cache[i] = new Long(i - 128);
+        }
+    }
+
+    /**
+     * Returns a {@code Long} instance representing the specified
+     * {@code long} value.
+     * If a new {@code Long} instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Long(long)}, as this method is likely to yield
+     * significantly better space and time performance by caching
+     * frequently requested values.
+     *
+     * Note that unlike the {@linkplain Integer#valueOf(int)
+     * corresponding method} in the {@code Integer} class, this method
+     * is <em>not</em> required to cache values within a particular
+     * range.
+     *
+     * @param  l a long value.
+     * @return a {@code Long} instance representing {@code l}.
+     * @since  1.5
+     */
+    public static Long valueOf(long l) {
+        final int offset = 128;
+        if (l >= -128 && l <= 127) { // will cache
+            return LongCache.cache[(int)l + offset];
+        }
+        return new Long(l);
+    }
+
+    /**
+     * Decodes a {@code String} into a {@code Long}.
+     * Accepts decimal, hexadecimal, and octal numbers given by the
+     * following grammar:
+     *
+     * <blockquote>
+     * <dl>
+     * <dt><i>DecodableString:</i>
+     * <dd><i>Sign<sub>opt</sub> DecimalNumeral</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0x} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0X} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code #} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0} <i>OctalDigits</i>
+     *
+     * <dt><i>Sign:</i>
+     * <dd>{@code -}
+     * <dd>{@code +}
+     * </dl>
+     * </blockquote>
+     *
+     * <i>DecimalNumeral</i>, <i>HexDigits</i>, and <i>OctalDigits</i>
+     * are as defined in section 3.10.1 of
+     * <cite>The Java&trade; Language Specification</cite>,
+     * except that underscores are not accepted between digits.
+     *
+     * <p>The sequence of characters following an optional
+     * sign and/or radix specifier ("{@code 0x}", "{@code 0X}",
+     * "{@code #}", or leading zero) is parsed as by the {@code
+     * Long.parseLong} method with the indicated radix (10, 16, or 8).
+     * This sequence of characters must represent a positive value or
+     * a {@link NumberFormatException} will be thrown.  The result is
+     * negated if first character of the specified {@code String} is
+     * the minus sign.  No whitespace characters are permitted in the
+     * {@code String}.
+     *
+     * @param     nm the {@code String} to decode.
+     * @return    a {@code Long} object holding the {@code long}
+     *            value represented by {@code nm}
+     * @throws    NumberFormatException  if the {@code String} does not
+     *            contain a parsable {@code long}.
+     * @see java.lang.Long#parseLong(String, int)
+     * @since 1.2
+     */
+    public static Long decode(String nm) throws NumberFormatException {
+        int radix = 10;
+        int index = 0;
+        boolean negative = false;
+        Long result;
+
+        if (nm.length() == 0)
+            throw new NumberFormatException("Zero length string");
+        char firstChar = nm.charAt(0);
+        // Handle sign, if present
+        if (firstChar == '-') {
+            negative = true;
+            index++;
+        } else if (firstChar == '+')
+            index++;
+
+        // Handle radix specifier, if present
+        if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
+            index += 2;
+            radix = 16;
+        }
+        else if (nm.startsWith("#", index)) {
+            index ++;
+            radix = 16;
+        }
+        else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
+            index ++;
+            radix = 8;
+        }
+
+        if (nm.startsWith("-", index) || nm.startsWith("+", index))
+            throw new NumberFormatException("Sign character in wrong position");
+
+        try {
+            result = Long.valueOf(nm.substring(index), radix);
+            result = negative ? Long.valueOf(-result.longValue()) : result;
+        } catch (NumberFormatException e) {
+            // If number is Long.MIN_VALUE, we'll end up here. The next line
+            // handles this case, and causes any genuine format error to be
+            // rethrown.
+            String constant = negative ? ("-" + nm.substring(index))
+                                       : nm.substring(index);
+            result = Long.valueOf(constant, radix);
+        }
+        return result;
+    }
+
+    /**
+     * The value of the {@code Long}.
+     *
+     * @serial
+     */
+    private final long value;
+
+    /**
+     * Constructs a newly allocated {@code Long} object that
+     * represents the specified {@code long} argument.
+     *
+     * @param   value   the value to be represented by the
+     *          {@code Long} object.
+     */
+    public Long(long value) {
+        this.value = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Long} object that
+     * represents the {@code long} value indicated by the
+     * {@code String} parameter. The string is converted to a
+     * {@code long} value in exactly the manner used by the
+     * {@code parseLong} method for radix 10.
+     *
+     * @param      s   the {@code String} to be converted to a
+     *             {@code Long}.
+     * @throws     NumberFormatException  if the {@code String} does not
+     *             contain a parsable {@code long}.
+     * @see        java.lang.Long#parseLong(java.lang.String, int)
+     */
+    public Long(String s) throws NumberFormatException {
+        this.value = parseLong(s, 10);
+    }
+
+    /**
+     * Returns the value of this {@code Long} as a {@code byte} after
+     * a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public byte byteValue() {
+        return (byte)value;
+    }
+
+    /**
+     * Returns the value of this {@code Long} as a {@code short} after
+     * a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public short shortValue() {
+        return (short)value;
+    }
+
+    /**
+     * Returns the value of this {@code Long} as an {@code int} after
+     * a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public int intValue() {
+        return (int)value;
+    }
+
+    /**
+     * Returns the value of this {@code Long} as a
+     * {@code long} value.
+     */
+    public long longValue() {
+        return value;
+    }
+
+    /**
+     * Returns the value of this {@code Long} as a {@code float} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)value;
+    }
+
+    /**
+     * Returns the value of this {@code Long} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)value;
+    }
+
+    /**
+     * Returns a {@code String} object representing this
+     * {@code Long}'s value.  The value is converted to signed
+     * decimal representation and returned as a string, exactly as if
+     * the {@code long} value were given as an argument to the
+     * {@link java.lang.Long#toString(long)} method.
+     *
+     * @return  a string representation of the value of this object in
+     *          base&nbsp;10.
+     */
+    public String toString() {
+        return toString(value);
+    }
+
+    /**
+     * Returns a hash code for this {@code Long}. The result is
+     * the exclusive OR of the two halves of the primitive
+     * {@code long} value held by this {@code Long}
+     * object. That is, the hashcode is the value of the expression:
+     *
+     * <blockquote>
+     *  {@code (int)(this.longValue()^(this.longValue()>>>32))}
+     * </blockquote>
+     *
+     * @return  a hash code value for this object.
+     */
+    @Override
+    public int hashCode() {
+        return Long.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code long} value; compatible with
+     * {@code Long.hashCode()}.
+     *
+     * @param value the value to hash
+     * @return a hash code value for a {@code long} value.
+     * @since 1.8
+     */
+    public static int hashCode(long value) {
+        return (int)(value ^ (value >>> 32));
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is
+     * {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Long} object that
+     * contains the same {@code long} value as this object.
+     *
+     * @param   obj   the object to compare with.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Long) {
+            return value == ((Long)obj).longValue();
+        }
+        return false;
+    }
+
+    /**
+     * Determines the {@code long} value of the system property
+     * with the specified name.
+     *
+     * <p>The first argument is treated as the name of a system
+     * property.  System properties are accessible through the {@link
+     * java.lang.System#getProperty(java.lang.String)} method. The
+     * string value of this property is then interpreted as a {@code
+     * long} value using the grammar supported by {@link Long#decode decode}
+     * and a {@code Long} object representing this value is returned.
+     *
+     * <p>If there is no property with the specified name, if the
+     * specified name is empty or {@code null}, or if the property
+     * does not have the correct numeric format, then {@code null} is
+     * returned.
+     *
+     * <p>In other words, this method returns a {@code Long} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     *  {@code getLong(nm, null)}
+     * </blockquote>
+     *
+     * @param   nm   property name.
+     * @return  the {@code Long} value of the property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     java.lang.System#getProperty(java.lang.String)
+     * @see     java.lang.System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static Long getLong(String nm) {
+        return getLong(nm, null);
+    }
+
+    /**
+     * Determines the {@code long} value of the system property
+     * with the specified name.
+     *
+     * <p>The first argument is treated as the name of a system
+     * property.  System properties are accessible through the {@link
+     * java.lang.System#getProperty(java.lang.String)} method. The
+     * string value of this property is then interpreted as a {@code
+     * long} value using the grammar supported by {@link Long#decode decode}
+     * and a {@code Long} object representing this value is returned.
+     *
+     * <p>The second argument is the default value. A {@code Long} object
+     * that represents the value of the second argument is returned if there
+     * is no property of the specified name, if the property does not have
+     * the correct numeric format, or if the specified name is empty or null.
+     *
+     * <p>In other words, this method returns a {@code Long} object equal
+     * to the value of:
+     *
+     * <blockquote>
+     *  {@code getLong(nm, new Long(val))}
+     * </blockquote>
+     *
+     * but in practice it may be implemented in a manner such as:
+     *
+     * <blockquote><pre>
+     * Long result = getLong(nm, null);
+     * return (result == null) ? new Long(val) : result;
+     * </pre></blockquote>
+     *
+     * to avoid the unnecessary allocation of a {@code Long} object when
+     * the default value is not needed.
+     *
+     * @param   nm    property name.
+     * @param   val   default value.
+     * @return  the {@code Long} value of the property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     java.lang.System#getProperty(java.lang.String)
+     * @see     java.lang.System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static Long getLong(String nm, long val) {
+        Long result = Long.getLong(nm, null);
+        return (result == null) ? Long.valueOf(val) : result;
+    }
+
+    /**
+     * Returns the {@code long} value of the system property with
+     * the specified name.  The first argument is treated as the name
+     * of a system property.  System properties are accessible through
+     * the {@link java.lang.System#getProperty(java.lang.String)}
+     * method. The string value of this property is then interpreted
+     * as a {@code long} value, as per the
+     * {@link Long#decode decode} method, and a {@code Long} object
+     * representing this value is returned; in summary:
+     *
+     * <ul>
+     * <li>If the property value begins with the two ASCII characters
+     * {@code 0x} or the ASCII character {@code #}, not followed by
+     * a minus sign, then the rest of it is parsed as a hexadecimal integer
+     * exactly as for the method {@link #valueOf(java.lang.String, int)}
+     * with radix 16.
+     * <li>If the property value begins with the ASCII character
+     * {@code 0} followed by another character, it is parsed as
+     * an octal integer exactly as by the method {@link
+     * #valueOf(java.lang.String, int)} with radix 8.
+     * <li>Otherwise the property value is parsed as a decimal
+     * integer exactly as by the method
+     * {@link #valueOf(java.lang.String, int)} with radix 10.
+     * </ul>
+     *
+     * <p>Note that, in every case, neither {@code L}
+     * ({@code '\u005Cu004C'}) nor {@code l}
+     * ({@code '\u005Cu006C'}) is permitted to appear at the end
+     * of the property value as a type indicator, as would be
+     * permitted in Java programming language source code.
+     *
+     * <p>The second argument is the default value. The default value is
+     * returned if there is no property of the specified name, if the
+     * property does not have the correct numeric format, or if the
+     * specified name is empty or {@code null}.
+     *
+     * @param   nm   property name.
+     * @param   val   default value.
+     * @return  the {@code Long} value of the property.
+     * @throws  SecurityException for the same reasons as
+     *          {@link System#getProperty(String) System.getProperty}
+     * @see     System#getProperty(java.lang.String)
+     * @see     System#getProperty(java.lang.String, java.lang.String)
+     */
+    public static Long getLong(String nm, Long val) {
+        String v = null;
+        try {
+            v = System.getProperty(nm);
+        } catch (IllegalArgumentException | NullPointerException e) {
+        }
+        if (v != null) {
+            try {
+                return Long.decode(v);
+            } catch (NumberFormatException e) {
+            }
+        }
+        return val;
+    }
+
+    /**
+     * Compares two {@code Long} objects numerically.
+     *
+     * @param   anotherLong   the {@code Long} to be compared.
+     * @return  the value {@code 0} if this {@code Long} is
+     *          equal to the argument {@code Long}; a value less than
+     *          {@code 0} if this {@code Long} is numerically less
+     *          than the argument {@code Long}; and a value greater
+     *          than {@code 0} if this {@code Long} is numerically
+     *           greater than the argument {@code Long} (signed
+     *           comparison).
+     * @since   1.2
+     */
+    public int compareTo(Long anotherLong) {
+        return compare(this.value, anotherLong.value);
+    }
+
+    /**
+     * Compares two {@code long} values numerically.
+     * The value returned is identical to what would be returned by:
+     * <pre>
+     *    Long.valueOf(x).compareTo(Long.valueOf(y))
+     * </pre>
+     *
+     * @param  x the first {@code long} to compare
+     * @param  y the second {@code long} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 1.7
+     */
+    public static int compare(long x, long y) {
+        return (x < y) ? -1 : ((x == y) ? 0 : 1);
+    }
+
+    /**
+     * Compares two {@code long} values numerically treating the values
+     * as unsigned.
+     *
+     * @param  x the first {@code long} to compare
+     * @param  y the second {@code long} to compare
+     * @return the value {@code 0} if {@code x == y}; a value less
+     *         than {@code 0} if {@code x < y} as unsigned values; and
+     *         a value greater than {@code 0} if {@code x > y} as
+     *         unsigned values
+     * @since 1.8
+     */
+    public static int compareUnsigned(long x, long y) {
+        return compare(x + MIN_VALUE, y + MIN_VALUE);
+    }
+
+
+    /**
+     * Returns the unsigned quotient of dividing the first argument by
+     * the second where each argument and the result is interpreted as
+     * an unsigned value.
+     *
+     * <p>Note that in two's complement arithmetic, the three other
+     * basic arithmetic operations of add, subtract, and multiply are
+     * bit-wise identical if the two operands are regarded as both
+     * being signed or both being unsigned.  Therefore separate {@code
+     * addUnsigned}, etc. methods are not provided.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned quotient of the first argument divided by
+     * the second argument
+     * @see #remainderUnsigned
+     * @since 1.8
+     */
+    public static long divideUnsigned(long dividend, long divisor) {
+        if (divisor < 0L) { // signed comparison
+            // Answer must be 0 or 1 depending on relative magnitude
+            // of dividend and divisor.
+            return (compareUnsigned(dividend, divisor)) < 0 ? 0L :1L;
+        }
+
+        if (dividend > 0) //  Both inputs non-negative
+            return dividend/divisor;
+        else {
+            /*
+             * For simple code, leveraging BigInteger.  Longer and faster
+             * code written directly in terms of operations on longs is
+             * possible; see "Hacker's Delight" for divide and remainder
+             * algorithms.
+             */
+            return toUnsignedBigInteger(dividend).
+                divide(toUnsignedBigInteger(divisor)).longValue();
+        }
+    }
+
+    /**
+     * Returns the unsigned remainder from dividing the first argument
+     * by the second where each argument and the result is interpreted
+     * as an unsigned value.
+     *
+     * @param dividend the value to be divided
+     * @param divisor the value doing the dividing
+     * @return the unsigned remainder of the first argument divided by
+     * the second argument
+     * @see #divideUnsigned
+     * @since 1.8
+     */
+    public static long remainderUnsigned(long dividend, long divisor) {
+        if (dividend > 0 && divisor > 0) { // signed comparisons
+            return dividend % divisor;
+        } else {
+            if (compareUnsigned(dividend, divisor) < 0) // Avoid explicit check for 0 divisor
+                return dividend;
+            else
+                return toUnsignedBigInteger(dividend).
+                    remainder(toUnsignedBigInteger(divisor)).longValue();
+        }
+    }
+
+    // Bit Twiddling
+
+    /**
+     * The number of bits used to represent a {@code long} value in two's
+     * complement binary form.
+     *
+     * @since 1.5
+     */
+    @Native public static final int SIZE = 64;
+
+    /**
+     * The number of bytes used to represent a {@code long} value in two's
+     * complement binary form.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /**
+     * Returns a {@code long} value with at most a single one-bit, in the
+     * position of the highest-order ("leftmost") one-bit in the specified
+     * {@code long} value.  Returns zero if the specified value has no
+     * one-bits in its two's complement binary representation, that is, if it
+     * is equal to zero.
+     *
+     * @param i the value whose highest one bit is to be computed
+     * @return a {@code long} value with a single one-bit, in the position
+     *     of the highest-order one-bit in the specified value, or zero if
+     *     the specified value is itself equal to zero.
+     * @since 1.5
+     */
+    public static long highestOneBit(long i) {
+        // HD, Figure 3-1
+        i |= (i >>  1);
+        i |= (i >>  2);
+        i |= (i >>  4);
+        i |= (i >>  8);
+        i |= (i >> 16);
+        i |= (i >> 32);
+        return i - (i >>> 1);
+    }
+
+    /**
+     * Returns a {@code long} value with at most a single one-bit, in the
+     * position of the lowest-order ("rightmost") one-bit in the specified
+     * {@code long} value.  Returns zero if the specified value has no
+     * one-bits in its two's complement binary representation, that is, if it
+     * is equal to zero.
+     *
+     * @param i the value whose lowest one bit is to be computed
+     * @return a {@code long} value with a single one-bit, in the position
+     *     of the lowest-order one-bit in the specified value, or zero if
+     *     the specified value is itself equal to zero.
+     * @since 1.5
+     */
+    public static long lowestOneBit(long i) {
+        // HD, Section 2-1
+        return i & -i;
+    }
+
+    /**
+     * Returns the number of zero bits preceding the highest-order
+     * ("leftmost") one-bit in the two's complement binary representation
+     * of the specified {@code long} value.  Returns 64 if the
+     * specified value has no one-bits in its two's complement representation,
+     * in other words if it is equal to zero.
+     *
+     * <p>Note that this method is closely related to the logarithm base 2.
+     * For all positive {@code long} values x:
+     * <ul>
+     * <li>floor(log<sub>2</sub>(x)) = {@code 63 - numberOfLeadingZeros(x)}
+     * <li>ceil(log<sub>2</sub>(x)) = {@code 64 - numberOfLeadingZeros(x - 1)}
+     * </ul>
+     *
+     * @param i the value whose number of leading zeros is to be computed
+     * @return the number of zero bits preceding the highest-order
+     *     ("leftmost") one-bit in the two's complement binary representation
+     *     of the specified {@code long} value, or 64 if the value
+     *     is equal to zero.
+     * @since 1.5
+     */
+    public static int numberOfLeadingZeros(long i) {
+        // HD, Figure 5-6
+         if (i == 0)
+            return 64;
+        int n = 1;
+        int x = (int)(i >>> 32);
+        if (x == 0) { n += 32; x = (int)i; }
+        if (x >>> 16 == 0) { n += 16; x <<= 16; }
+        if (x >>> 24 == 0) { n +=  8; x <<=  8; }
+        if (x >>> 28 == 0) { n +=  4; x <<=  4; }
+        if (x >>> 30 == 0) { n +=  2; x <<=  2; }
+        n -= x >>> 31;
+        return n;
+    }
+
+    /**
+     * Returns the number of zero bits following the lowest-order ("rightmost")
+     * one-bit in the two's complement binary representation of the specified
+     * {@code long} value.  Returns 64 if the specified value has no
+     * one-bits in its two's complement representation, in other words if it is
+     * equal to zero.
+     *
+     * @param i the value whose number of trailing zeros is to be computed
+     * @return the number of zero bits following the lowest-order ("rightmost")
+     *     one-bit in the two's complement binary representation of the
+     *     specified {@code long} value, or 64 if the value is equal
+     *     to zero.
+     * @since 1.5
+     */
+    public static int numberOfTrailingZeros(long i) {
+        // HD, Figure 5-14
+        int x, y;
+        if (i == 0) return 64;
+        int n = 63;
+        y = (int)i; if (y != 0) { n = n -32; x = y; } else x = (int)(i>>>32);
+        y = x <<16; if (y != 0) { n = n -16; x = y; }
+        y = x << 8; if (y != 0) { n = n - 8; x = y; }
+        y = x << 4; if (y != 0) { n = n - 4; x = y; }
+        y = x << 2; if (y != 0) { n = n - 2; x = y; }
+        return n - ((x << 1) >>> 31);
+    }
+
+    /**
+     * Returns the number of one-bits in the two's complement binary
+     * representation of the specified {@code long} value.  This function is
+     * sometimes referred to as the <i>population count</i>.
+     *
+     * @param i the value whose bits are to be counted
+     * @return the number of one-bits in the two's complement binary
+     *     representation of the specified {@code long} value.
+     * @since 1.5
+     */
+     public static int bitCount(long i) {
+        // HD, Figure 5-14
+        i = i - ((i >>> 1) & 0x5555555555555555L);
+        i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
+        i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
+        i = i + (i >>> 8);
+        i = i + (i >>> 16);
+        i = i + (i >>> 32);
+        return (int)i & 0x7f;
+     }
+
+    /**
+     * Returns the value obtained by rotating the two's complement binary
+     * representation of the specified {@code long} value left by the
+     * specified number of bits.  (Bits shifted out of the left hand, or
+     * high-order, side reenter on the right, or low-order.)
+     *
+     * <p>Note that left rotation with a negative distance is equivalent to
+     * right rotation: {@code rotateLeft(val, -distance) == rotateRight(val,
+     * distance)}.  Note also that rotation by any multiple of 64 is a
+     * no-op, so all but the last six bits of the rotation distance can be
+     * ignored, even if the distance is negative: {@code rotateLeft(val,
+     * distance) == rotateLeft(val, distance & 0x3F)}.
+     *
+     * @param i the value whose bits are to be rotated left
+     * @param distance the number of bit positions to rotate left
+     * @return the value obtained by rotating the two's complement binary
+     *     representation of the specified {@code long} value left by the
+     *     specified number of bits.
+     * @since 1.5
+     */
+    public static long rotateLeft(long i, int distance) {
+        return (i << distance) | (i >>> -distance);
+    }
+
+    /**
+     * Returns the value obtained by rotating the two's complement binary
+     * representation of the specified {@code long} value right by the
+     * specified number of bits.  (Bits shifted out of the right hand, or
+     * low-order, side reenter on the left, or high-order.)
+     *
+     * <p>Note that right rotation with a negative distance is equivalent to
+     * left rotation: {@code rotateRight(val, -distance) == rotateLeft(val,
+     * distance)}.  Note also that rotation by any multiple of 64 is a
+     * no-op, so all but the last six bits of the rotation distance can be
+     * ignored, even if the distance is negative: {@code rotateRight(val,
+     * distance) == rotateRight(val, distance & 0x3F)}.
+     *
+     * @param i the value whose bits are to be rotated right
+     * @param distance the number of bit positions to rotate right
+     * @return the value obtained by rotating the two's complement binary
+     *     representation of the specified {@code long} value right by the
+     *     specified number of bits.
+     * @since 1.5
+     */
+    public static long rotateRight(long i, int distance) {
+        return (i >>> distance) | (i << -distance);
+    }
+
+    /**
+     * Returns the value obtained by reversing the order of the bits in the
+     * two's complement binary representation of the specified {@code long}
+     * value.
+     *
+     * @param i the value to be reversed
+     * @return the value obtained by reversing order of the bits in the
+     *     specified {@code long} value.
+     * @since 1.5
+     */
+    public static long reverse(long i) {
+        // HD, Figure 7-1
+        i = (i & 0x5555555555555555L) << 1 | (i >>> 1) & 0x5555555555555555L;
+        i = (i & 0x3333333333333333L) << 2 | (i >>> 2) & 0x3333333333333333L;
+        i = (i & 0x0f0f0f0f0f0f0f0fL) << 4 | (i >>> 4) & 0x0f0f0f0f0f0f0f0fL;
+        i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
+        i = (i << 48) | ((i & 0xffff0000L) << 16) |
+            ((i >>> 16) & 0xffff0000L) | (i >>> 48);
+        return i;
+    }
+
+    /**
+     * Returns the signum function of the specified {@code long} value.  (The
+     * return value is -1 if the specified value is negative; 0 if the
+     * specified value is zero; and 1 if the specified value is positive.)
+     *
+     * @param i the value whose signum is to be computed
+     * @return the signum function of the specified {@code long} value.
+     * @since 1.5
+     */
+    public static int signum(long i) {
+        // HD, Section 2-7
+        return (int) ((i >> 63) | (-i >>> 63));
+    }
+
+    /**
+     * Returns the value obtained by reversing the order of the bytes in the
+     * two's complement representation of the specified {@code long} value.
+     *
+     * @param i the value whose bytes are to be reversed
+     * @return the value obtained by reversing the bytes in the specified
+     *     {@code long} value.
+     * @since 1.5
+     */
+    public static long reverseBytes(long i) {
+        i = (i & 0x00ff00ff00ff00ffL) << 8 | (i >>> 8) & 0x00ff00ff00ff00ffL;
+        return (i << 48) | ((i & 0xffff0000L) << 16) |
+            ((i >>> 16) & 0xffff0000L) | (i >>> 48);
+    }
+
+    /**
+     * Adds two {@code long} values together as per the + operator.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the sum of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static long sum(long a, long b) {
+        return a + b;
+    }
+
+    /**
+     * Returns the greater of two {@code long} values
+     * as if by calling {@link Math#max(long, long) Math.max}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the greater of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static long max(long a, long b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code long} values
+     * as if by calling {@link Math#min(long, long) Math.min}.
+     *
+     * @param a the first operand
+     * @param b the second operand
+     * @return the smaller of {@code a} and {@code b}
+     * @see java.util.function.BinaryOperator
+     * @since 1.8
+     */
+    public static long min(long a, long b) {
+        return Math.min(a, b);
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    @Native private static final long serialVersionUID = 4290774380558885855L;
+}
diff --git a/java/lang/Math.annotated.java b/java/lang/Math.annotated.java
new file mode 100644
index 0000000..46fae4e
--- /dev/null
+++ b/java/lang/Math.annotated.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.util.Random;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Math {
+
+Math() { throw new RuntimeException("Stub!"); }
+
+public static native double sin(double a);
+
+public static native double cos(double a);
+
+public static native double tan(double a);
+
+public static native double asin(double a);
+
+public static native double acos(double a);
+
+public static native double atan(double a);
+
+public static double toRadians(double angdeg) { throw new RuntimeException("Stub!"); }
+
+public static double toDegrees(double angrad) { throw new RuntimeException("Stub!"); }
+
+public static native double exp(double a);
+
+public static native double log(double a);
+
+public static native double log10(double a);
+
+public static native double sqrt(double a);
+
+public static native double cbrt(double a);
+
+public static native double IEEEremainder(double f1, double f2);
+
+public static native double ceil(double a);
+
+public static native double floor(double a);
+
+public static native double rint(double a);
+
+public static native double atan2(double y, double x);
+
+public static native double pow(double a, double b);
+
+public static int round(float a) { throw new RuntimeException("Stub!"); }
+
+public static long round(double a) { throw new RuntimeException("Stub!"); }
+
+public static double random() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static long randomLongInternal() { throw new RuntimeException("Stub!"); }
+
+public static int addExact(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static long addExact(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static int subtractExact(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static long subtractExact(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static int multiplyExact(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static long multiplyExact(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static int incrementExact(int a) { throw new RuntimeException("Stub!"); }
+
+public static long incrementExact(long a) { throw new RuntimeException("Stub!"); }
+
+public static int decrementExact(int a) { throw new RuntimeException("Stub!"); }
+
+public static long decrementExact(long a) { throw new RuntimeException("Stub!"); }
+
+public static int negateExact(int a) { throw new RuntimeException("Stub!"); }
+
+public static long negateExact(long a) { throw new RuntimeException("Stub!"); }
+
+public static int toIntExact(long value) { throw new RuntimeException("Stub!"); }
+
+public static int floorDiv(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static long floorDiv(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static int floorMod(int x, int y) { throw new RuntimeException("Stub!"); }
+
+public static long floorMod(long x, long y) { throw new RuntimeException("Stub!"); }
+
+public static int abs(int a) { throw new RuntimeException("Stub!"); }
+
+public static long abs(long a) { throw new RuntimeException("Stub!"); }
+
+public static float abs(float a) { throw new RuntimeException("Stub!"); }
+
+public static double abs(double a) { throw new RuntimeException("Stub!"); }
+
+public static int max(int a, int b) { throw new RuntimeException("Stub!"); }
+
+public static long max(long a, long b) { throw new RuntimeException("Stub!"); }
+
+public static float max(float a, float b) { throw new RuntimeException("Stub!"); }
+
+public static double max(double a, double b) { throw new RuntimeException("Stub!"); }
+
+public static int min(int a, int b) { throw new RuntimeException("Stub!"); }
+
+public static long min(long a, long b) { throw new RuntimeException("Stub!"); }
+
+public static float min(float a, float b) { throw new RuntimeException("Stub!"); }
+
+public static double min(double a, double b) { throw new RuntimeException("Stub!"); }
+
+public static double ulp(double d) { throw new RuntimeException("Stub!"); }
+
+public static float ulp(float f) { throw new RuntimeException("Stub!"); }
+
+public static double signum(double d) { throw new RuntimeException("Stub!"); }
+
+public static float signum(float f) { throw new RuntimeException("Stub!"); }
+
+public static native double sinh(double x);
+
+public static native double cosh(double x);
+
+public static native double tanh(double x);
+
+public static native double hypot(double x, double y);
+
+public static native double expm1(double x);
+
+public static native double log1p(double x);
+
+public static double copySign(double magnitude, double sign) { throw new RuntimeException("Stub!"); }
+
+public static float copySign(float magnitude, float sign) { throw new RuntimeException("Stub!"); }
+
+public static int getExponent(float f) { throw new RuntimeException("Stub!"); }
+
+public static int getExponent(double d) { throw new RuntimeException("Stub!"); }
+
+public static double nextAfter(double start, double direction) { throw new RuntimeException("Stub!"); }
+
+public static float nextAfter(float start, double direction) { throw new RuntimeException("Stub!"); }
+
+public static double nextUp(double d) { throw new RuntimeException("Stub!"); }
+
+public static float nextUp(float f) { throw new RuntimeException("Stub!"); }
+
+public static double nextDown(double d) { throw new RuntimeException("Stub!"); }
+
+public static float nextDown(float f) { throw new RuntimeException("Stub!"); }
+
+public static double scalb(double d, int scaleFactor) { throw new RuntimeException("Stub!"); }
+
+public static float scalb(float f, int scaleFactor) { throw new RuntimeException("Stub!"); }
+
+public static final double E = 2.718281828459045;
+
+public static final double PI = 3.141592653589793;
+}
+
diff --git a/java/lang/Math.java b/java/lang/Math.java
new file mode 100644
index 0000000..17cbf6d
--- /dev/null
+++ b/java/lang/Math.java
@@ -0,0 +1,2397 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+import dalvik.annotation.optimization.CriticalNative;
+import java.util.Random;
+
+import sun.misc.FloatConsts;
+import sun.misc.DoubleConsts;
+
+// Android-note: Document that the results from Math are based on libm's behavior.
+// For performance, Android implements many of the methods in this class in terms of the underlying
+// OS's libm functions. libm has well-defined behavior for special cases. Where known these are
+// marked with the tag above and the documentation has been modified as needed.
+/**
+ * The class {@code Math} contains methods for performing basic
+ * numeric operations such as the elementary exponential, logarithm,
+ * square root, and trigonometric functions.
+ *
+ * <p>Unlike some of the numeric methods of class
+ * {@code StrictMath}, all implementations of the equivalent
+ * functions of class {@code Math} are not defined to return the
+ * bit-for-bit same results.  This relaxation permits
+ * better-performing implementations where strict reproducibility is
+ * not required.
+ *
+ * <p>By default many of the {@code Math} methods simply call
+ * the equivalent method in {@code StrictMath} for their
+ * implementation.  Code generators are encouraged to use
+ * platform-specific native libraries or microprocessor instructions,
+ * where available, to provide higher-performance implementations of
+ * {@code Math} methods.  Such higher-performance
+ * implementations still must conform to the specification for
+ * {@code Math}.
+ *
+ * <p>The quality of implementation specifications concern two
+ * properties, accuracy of the returned result and monotonicity of the
+ * method.  Accuracy of the floating-point {@code Math} methods is
+ * measured in terms of <i>ulps</i>, units in the last place.  For a
+ * given floating-point format, an {@linkplain #ulp(double) ulp} of a
+ * specific real number value is the distance between the two
+ * floating-point values bracketing that numerical value.  When
+ * discussing the accuracy of a method as a whole rather than at a
+ * specific argument, the number of ulps cited is for the worst-case
+ * error at any argument.  If a method always has an error less than
+ * 0.5 ulps, the method always returns the floating-point number
+ * nearest the exact result; such a method is <i>correctly
+ * rounded</i>.  A correctly rounded method is generally the best a
+ * floating-point approximation can be; however, it is impractical for
+ * many floating-point methods to be correctly rounded.  Instead, for
+ * the {@code Math} class, a larger error bound of 1 or 2 ulps is
+ * allowed for certain methods.  Informally, with a 1 ulp error bound,
+ * when the exact result is a representable number, the exact result
+ * should be returned as the computed result; otherwise, either of the
+ * two floating-point values which bracket the exact result may be
+ * returned.  For exact results large in magnitude, one of the
+ * endpoints of the bracket may be infinite.  Besides accuracy at
+ * individual arguments, maintaining proper relations between the
+ * method at different arguments is also important.  Therefore, most
+ * methods with more than 0.5 ulp errors are required to be
+ * <i>semi-monotonic</i>: whenever the mathematical function is
+ * non-decreasing, so is the floating-point approximation, likewise,
+ * whenever the mathematical function is non-increasing, so is the
+ * floating-point approximation.  Not all approximations that have 1
+ * ulp accuracy will automatically meet the monotonicity requirements.
+ *
+ * <p>
+ * The platform uses signed two's complement integer arithmetic with
+ * int and long primitive types.  The developer should choose
+ * the primitive type to ensure that arithmetic operations consistently
+ * produce correct results, which in some cases means the operations
+ * will not overflow the range of values of the computation.
+ * The best practice is to choose the primitive type and algorithm to avoid
+ * overflow. In cases where the size is {@code int} or {@code long} and
+ * overflow errors need to be detected, the methods {@code addExact},
+ * {@code subtractExact}, {@code multiplyExact}, and {@code toIntExact}
+ * throw an {@code ArithmeticException} when the results overflow.
+ * For other arithmetic operations such as divide, absolute value,
+ * increment, decrement, and negation overflow occurs only with
+ * a specific minimum or maximum value and should be checked against
+ * the minimum or maximum as appropriate.
+ *
+ * @author  unascribed
+ * @author  Joseph D. Darcy
+ * @since   JDK1.0
+ */
+
+public final class Math {
+
+    // Android-changed: Numerous methods in this class are re-implemented in native for performance.
+    // Those methods are also annotated @CriticalNative.
+
+    /**
+     * Don't let anyone instantiate this class.
+     */
+    private Math() {}
+
+    /**
+     * The {@code double} value that is closer than any other to
+     * <i>e</i>, the base of the natural logarithms.
+     */
+    public static final double E = 2.7182818284590452354;
+
+    /**
+     * The {@code double} value that is closer than any other to
+     * <i>pi</i>, the ratio of the circumference of a circle to its
+     * diameter.
+     */
+    public static final double PI = 3.14159265358979323846;
+
+    /**
+     * Returns the trigonometric sine of an angle.  Special cases:
+     * <ul><li>If the argument is NaN or an infinity, then the
+     * result is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   an angle, in radians.
+     * @return  the sine of the argument.
+     */
+    @CriticalNative
+    public static native double sin(double a);
+
+    /**
+     * Returns the trigonometric cosine of an angle. Special cases:
+     * <ul><li>If the argument is NaN or an infinity, then the
+     * result is NaN.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   an angle, in radians.
+     * @return  the cosine of the argument.
+     */
+    @CriticalNative
+    public static native double cos(double a);
+
+    /**
+     * Returns the trigonometric tangent of an angle.  Special cases:
+     * <ul><li>If the argument is NaN or an infinity, then the result
+     * is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   an angle, in radians.
+     * @return  the tangent of the argument.
+     */
+    @CriticalNative
+    public static native double tan(double a);
+
+    /**
+     * Returns the arc sine of a value; the returned angle is in the
+     * range -<i>pi</i>/2 through <i>pi</i>/2.  Special cases:
+     * <ul><li>If the argument is NaN or its absolute value is greater
+     * than 1, then the result is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   the value whose arc sine is to be returned.
+     * @return  the arc sine of the argument.
+     */
+    @CriticalNative
+    public static native double asin(double a);
+
+    /**
+     * Returns the arc cosine of a value; the returned angle is in the
+     * range 0.0 through <i>pi</i>.  Special case:
+     * <ul><li>If the argument is NaN or its absolute value is greater
+     * than 1, then the result is NaN.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   the value whose arc cosine is to be returned.
+     * @return  the arc cosine of the argument.
+     */
+    @CriticalNative
+    public static native double acos(double a);
+
+    /**
+     * Returns the arc tangent of a value; the returned angle is in the
+     * range -<i>pi</i>/2 through <i>pi</i>/2.  Special cases:
+     * <ul><li>If the argument is NaN, then the result is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   the value whose arc tangent is to be returned.
+     * @return  the arc tangent of the argument.
+     */
+    @CriticalNative
+    public static native double atan(double a);
+
+    /**
+     * Converts an angle measured in degrees to an approximately
+     * equivalent angle measured in radians.  The conversion from
+     * degrees to radians is generally inexact.
+     *
+     * @param   angdeg   an angle, in degrees
+     * @return  the measurement of the angle {@code angdeg}
+     *          in radians.
+     * @since   1.2
+     */
+    public static double toRadians(double angdeg) {
+        return angdeg / 180.0 * PI;
+    }
+
+    /**
+     * Converts an angle measured in radians to an approximately
+     * equivalent angle measured in degrees.  The conversion from
+     * radians to degrees is generally inexact; users should
+     * <i>not</i> expect {@code cos(toRadians(90.0))} to exactly
+     * equal {@code 0.0}.
+     *
+     * @param   angrad   an angle, in radians
+     * @return  the measurement of the angle {@code angrad}
+     *          in degrees.
+     * @since   1.2
+     */
+    public static double toDegrees(double angrad) {
+        return angrad * 180.0 / PI;
+    }
+
+    /**
+     * Returns Euler's number <i>e</i> raised to the power of a
+     * {@code double} value.  Special cases:
+     * <ul><li>If the argument is NaN, the result is NaN.
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     * <li>If the argument is negative infinity, then the result is
+     * positive zero.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   the exponent to raise <i>e</i> to.
+     * @return  the value <i>e</i><sup>{@code a}</sup>,
+     *          where <i>e</i> is the base of the natural logarithms.
+     */
+    @CriticalNative
+    public static native double exp(double a);
+
+    /**
+     * Returns the natural logarithm (base <i>e</i>) of a {@code double}
+     * value.  Special cases:
+     * <ul><li>If the argument is NaN or less than zero, then the result
+     * is NaN.
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     * <li>If the argument is positive zero or negative zero, then the
+     * result is negative infinity.</ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   a value
+     * @return  the value ln&nbsp;{@code a}, the natural logarithm of
+     *          {@code a}.
+     */
+    @CriticalNative
+    public static native double log(double a);
+
+    /**
+     * Returns the base 10 logarithm of a {@code double} value.
+     * Special cases:
+     *
+     * <ul><li>If the argument is NaN or less than zero, then the result
+     * is NaN.
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     * <li>If the argument is positive zero or negative zero, then the
+     * result is negative infinity.
+     * <li> If the argument is equal to 10<sup><i>n</i></sup> for
+     * integer <i>n</i>, then the result is <i>n</i>.
+     * </ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   a value
+     * @return  the base 10 logarithm of  {@code a}.
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double log10(double a);
+
+    /**
+     * Returns the correctly rounded positive square root of a
+     * {@code double} value.
+     * Special cases:
+     * <ul><li>If the argument is NaN or less than zero, then the result
+     * is NaN.
+     * <li>If the argument is positive infinity, then the result is positive
+     * infinity.
+     * <li>If the argument is positive zero or negative zero, then the
+     * result is the same as the argument.</ul>
+     * Otherwise, the result is the {@code double} value closest to
+     * the true mathematical square root of the argument value.
+     *
+     * @param   a   a value.
+     * @return  the positive square root of {@code a}.
+     *          If the argument is NaN or less than zero, the result is NaN.
+     */
+    @CriticalNative
+    public static native double sqrt(double a);
+
+
+    /**
+     * Returns the cube root of a {@code double} value.  For
+     * positive finite {@code x}, {@code cbrt(-x) ==
+     * -cbrt(x)}; that is, the cube root of a negative value is
+     * the negative of the cube root of that value's magnitude.
+     *
+     * Special cases:
+     *
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is infinite, then the result is an infinity
+     * with the same sign as the argument.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     *
+     * @param   a   a value.
+     * @return  the cube root of {@code a}.
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double cbrt(double a);
+
+    /**
+     * Computes the remainder operation on two arguments as prescribed
+     * by the IEEE 754 standard.
+     * The remainder value is mathematically equal to
+     * <code>f1&nbsp;-&nbsp;f2</code>&nbsp;&times;&nbsp;<i>n</i>,
+     * where <i>n</i> is the mathematical integer closest to the exact
+     * mathematical value of the quotient {@code f1/f2}, and if two
+     * mathematical integers are equally close to {@code f1/f2},
+     * then <i>n</i> is the integer that is even. If the remainder is
+     * zero, its sign is the same as the sign of the first argument.
+     * Special cases:
+     * <ul><li>If either argument is NaN, or the first argument is infinite,
+     * or the second argument is positive zero or negative zero, then the
+     * result is NaN.
+     * <li>If the first argument is finite and the second argument is
+     * infinite, then the result is the same as the first argument.</ul>
+     *
+     * @param   f1   the dividend.
+     * @param   f2   the divisor.
+     * @return  the remainder when {@code f1} is divided by
+     *          {@code f2}.
+     */
+    @CriticalNative
+    public static native double IEEEremainder(double f1, double f2);
+
+    /**
+     * Returns the smallest (closest to negative infinity)
+     * {@code double} value that is greater than or equal to the
+     * argument and is equal to a mathematical integer. Special cases:
+     * <ul><li>If the argument value is already equal to a
+     * mathematical integer, then the result is the same as the
+     * argument.  <li>If the argument is NaN or an infinity or
+     * positive zero or negative zero, then the result is the same as
+     * the argument.  <li>If the argument value is less than zero but
+     * greater than -1.0, then the result is negative zero.</ul> Note
+     * that the value of {@code Math.ceil(x)} is exactly the
+     * value of {@code -Math.floor(-x)}.
+     *
+     *
+     * @param   a   a value.
+     * @return  the smallest (closest to negative infinity)
+     *          floating-point value that is greater than or equal to
+     *          the argument and is equal to a mathematical integer.
+     */
+    @CriticalNative
+    public static native double ceil(double a);
+
+    /**
+     * Returns the largest (closest to positive infinity)
+     * {@code double} value that is less than or equal to the
+     * argument and is equal to a mathematical integer. Special cases:
+     * <ul><li>If the argument value is already equal to a
+     * mathematical integer, then the result is the same as the
+     * argument.  <li>If the argument is NaN or an infinity or
+     * positive zero or negative zero, then the result is the same as
+     * the argument.</ul>
+     *
+     * @param   a   a value.
+     * @return  the largest (closest to positive infinity)
+     *          floating-point value that less than or equal to the argument
+     *          and is equal to a mathematical integer.
+     */
+    @CriticalNative
+    public static native double floor(double a);
+
+    /**
+     * Returns the {@code double} value that is closest in value
+     * to the argument and is equal to a mathematical integer. If two
+     * {@code double} values that are mathematical integers are
+     * equally close, the result is the integer value that is
+     * even. Special cases:
+     * <ul><li>If the argument value is already equal to a mathematical
+     * integer, then the result is the same as the argument.
+     * <li>If the argument is NaN or an infinity or positive zero or negative
+     * zero, then the result is the same as the argument.</ul>
+     *
+     * @param   a   a {@code double} value.
+     * @return  the closest floating-point value to {@code a} that is
+     *          equal to a mathematical integer.
+     */
+    @CriticalNative
+    public static native double rint(double a);
+
+    /**
+     * Returns the angle <i>theta</i> from the conversion of rectangular
+     * coordinates ({@code x},&nbsp;{@code y}) to polar
+     * coordinates (r,&nbsp;<i>theta</i>).
+     * This method computes the phase <i>theta</i> by computing an arc tangent
+     * of {@code y/x} in the range of -<i>pi</i> to <i>pi</i>. Special
+     * cases:
+     * <ul><li>If either argument is NaN, then the result is NaN.
+     * <li>If the first argument is positive zero and the second argument
+     * is positive, or the first argument is positive and finite and the
+     * second argument is positive infinity, then the result is positive
+     * zero.
+     * <li>If the first argument is negative zero and the second argument
+     * is positive, or the first argument is negative and finite and the
+     * second argument is positive infinity, then the result is negative zero.
+     * <li>If the first argument is positive zero and the second argument
+     * is negative, or the first argument is positive and finite and the
+     * second argument is negative infinity, then the result is the
+     * {@code double} value closest to <i>pi</i>.
+     * <li>If the first argument is negative zero and the second argument
+     * is negative, or the first argument is negative and finite and the
+     * second argument is negative infinity, then the result is the
+     * {@code double} value closest to -<i>pi</i>.
+     * <li>If the first argument is positive and the second argument is
+     * positive zero or negative zero, or the first argument is positive
+     * infinity and the second argument is finite, then the result is the
+     * {@code double} value closest to <i>pi</i>/2.
+     * <li>If the first argument is negative and the second argument is
+     * positive zero or negative zero, or the first argument is negative
+     * infinity and the second argument is finite, then the result is the
+     * {@code double} value closest to -<i>pi</i>/2.
+     * <li>If both arguments are positive infinity, then the result is the
+     * {@code double} value closest to <i>pi</i>/4.
+     * <li>If the first argument is positive infinity and the second argument
+     * is negative infinity, then the result is the {@code double}
+     * value closest to 3*<i>pi</i>/4.
+     * <li>If the first argument is negative infinity and the second argument
+     * is positive infinity, then the result is the {@code double} value
+     * closest to -<i>pi</i>/4.
+     * <li>If both arguments are negative infinity, then the result is the
+     * {@code double} value closest to -3*<i>pi</i>/4.</ul>
+     *
+     * <p>The computed result must be within 2 ulps of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   y   the ordinate coordinate
+     * @param   x   the abscissa coordinate
+     * @return  the <i>theta</i> component of the point
+     *          (<i>r</i>,&nbsp;<i>theta</i>)
+     *          in polar coordinates that corresponds to the point
+     *          (<i>x</i>,&nbsp;<i>y</i>) in Cartesian coordinates.
+     */
+    @CriticalNative
+    public static native double atan2(double y, double x);
+
+    // Android-changed: Document that the results from Math are based on libm's behavior.
+    // The cases known to differ with libm's pow():
+    //   If the first argument is 1.0 then result is always 1.0 (not NaN).
+    //   If the first argument is -1.0 and the second argument is infinite, the result is 1.0 (not
+    //   NaN).
+    /**
+     * Returns the value of the first argument raised to the power of the
+     * second argument. Special cases:
+     *
+     * <ul><li>If the second argument is positive or negative zero, then the
+     * result is 1.0.
+     * <li>If the second argument is 1.0, then the result is the same as the
+     * first argument.
+     * <li>If the first argument is 1.0, then the result is 1.0.
+     * <li>If the second argument is NaN, then the result is NaN except where the first argument is
+     * 1.0.
+     * <li>If the first argument is NaN and the second argument is nonzero,
+     * then the result is NaN.
+     *
+     * <li>If
+     * <ul>
+     * <li>the absolute value of the first argument is greater than 1
+     * and the second argument is positive infinity, or
+     * <li>the absolute value of the first argument is less than 1 and
+     * the second argument is negative infinity,
+     * </ul>
+     * then the result is positive infinity.
+     *
+     * <li>If
+     * <ul>
+     * <li>the absolute value of the first argument is greater than 1 and
+     * the second argument is negative infinity, or
+     * <li>the absolute value of the
+     * first argument is less than 1 and the second argument is positive
+     * infinity,
+     * </ul>
+     * then the result is positive zero.
+     *
+     * <li>If the absolute value of the first argument equals 1 and the
+     * second argument is infinite, then the result is 1.0.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is positive zero and the second argument
+     * is greater than zero, or
+     * <li>the first argument is positive infinity and the second
+     * argument is less than zero,
+     * </ul>
+     * then the result is positive zero.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is positive zero and the second argument
+     * is less than zero, or
+     * <li>the first argument is positive infinity and the second
+     * argument is greater than zero,
+     * </ul>
+     * then the result is positive infinity.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is greater than zero but not a finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is less than zero but not a finite odd integer,
+     * </ul>
+     * then the result is positive zero.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is a positive finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is a negative finite odd integer,
+     * </ul>
+     * then the result is negative zero.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is less than zero but not a finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is greater than zero but not a finite odd integer,
+     * </ul>
+     * then the result is positive infinity.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is a negative finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is a positive finite odd integer,
+     * </ul>
+     * then the result is negative infinity.
+     *
+     * <li>If the first argument is finite and less than zero
+     * <ul>
+     * <li> if the second argument is a finite even integer, the
+     * result is equal to the result of raising the absolute value of
+     * the first argument to the power of the second argument
+     *
+     * <li>if the second argument is a finite odd integer, the result
+     * is equal to the negative of the result of raising the absolute
+     * value of the first argument to the power of the second
+     * argument
+     *
+     * <li>if the second argument is finite and not an integer, then
+     * the result is NaN.
+     * </ul>
+     *
+     * <li>If both arguments are integers, then the result is exactly equal
+     * to the mathematical result of raising the first argument to the power
+     * of the second argument if that result can in fact be represented
+     * exactly as a {@code double} value.</ul>
+     *
+     * <p>(In the foregoing descriptions, a floating-point value is
+     * considered to be an integer if and only if it is finite and a
+     * fixed point of the method {@link #ceil ceil} or,
+     * equivalently, a fixed point of the method {@link #floor
+     * floor}. A value is a fixed point of a one-argument
+     * method if and only if the result of applying the method to the
+     * value is equal to the value.)
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   a   the base.
+     * @param   b   the exponent.
+     * @return  the value {@code a}<sup>{@code b}</sup>.
+     */
+    @CriticalNative
+    public static native double pow(double a, double b);
+
+    /**
+     * Returns the closest {@code int} to the argument, with ties
+     * rounding to positive infinity.
+     *
+     * <p>
+     * Special cases:
+     * <ul><li>If the argument is NaN, the result is 0.
+     * <li>If the argument is negative infinity or any value less than or
+     * equal to the value of {@code Integer.MIN_VALUE}, the result is
+     * equal to the value of {@code Integer.MIN_VALUE}.
+     * <li>If the argument is positive infinity or any value greater than or
+     * equal to the value of {@code Integer.MAX_VALUE}, the result is
+     * equal to the value of {@code Integer.MAX_VALUE}.</ul>
+     *
+     * @param   a   a floating-point value to be rounded to an integer.
+     * @return  the value of the argument rounded to the nearest
+     *          {@code int} value.
+     * @see     java.lang.Integer#MAX_VALUE
+     * @see     java.lang.Integer#MIN_VALUE
+     */
+    public static int round(float a) {
+        int intBits = Float.floatToRawIntBits(a);
+        int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK)
+                >> (FloatConsts.SIGNIFICAND_WIDTH - 1);
+        int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2
+                + FloatConsts.EXP_BIAS) - biasedExp;
+        if ((shift & -32) == 0) { // shift >= 0 && shift < 32
+            // a is a finite number such that pow(2,-32) <= ulp(a) < 1
+            int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK)
+                    | (FloatConsts.SIGNIF_BIT_MASK + 1));
+            if (intBits < 0) {
+                r = -r;
+            }
+            // In the comments below each Java expression evaluates to the value
+            // the corresponding mathematical expression:
+            // (r) evaluates to a / ulp(a)
+            // (r >> shift) evaluates to floor(a * 2)
+            // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
+            // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
+            return ((r >> shift) + 1) >> 1;
+        } else {
+            // a is either
+            // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2
+            // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
+            // - an infinity or NaN
+            return (int) a;
+        }
+    }
+
+    /**
+     * Returns the closest {@code long} to the argument, with ties
+     * rounding to positive infinity.
+     *
+     * <p>Special cases:
+     * <ul><li>If the argument is NaN, the result is 0.
+     * <li>If the argument is negative infinity or any value less than or
+     * equal to the value of {@code Long.MIN_VALUE}, the result is
+     * equal to the value of {@code Long.MIN_VALUE}.
+     * <li>If the argument is positive infinity or any value greater than or
+     * equal to the value of {@code Long.MAX_VALUE}, the result is
+     * equal to the value of {@code Long.MAX_VALUE}.</ul>
+     *
+     * @param   a   a floating-point value to be rounded to a
+     *          {@code long}.
+     * @return  the value of the argument rounded to the nearest
+     *          {@code long} value.
+     * @see     java.lang.Long#MAX_VALUE
+     * @see     java.lang.Long#MIN_VALUE
+     */
+    public static long round(double a) {
+        long longBits = Double.doubleToRawLongBits(a);
+        long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK)
+                >> (DoubleConsts.SIGNIFICAND_WIDTH - 1);
+        long shift = (DoubleConsts.SIGNIFICAND_WIDTH - 2
+                + DoubleConsts.EXP_BIAS) - biasedExp;
+        if ((shift & -64) == 0) { // shift >= 0 && shift < 64
+            // a is a finite number such that pow(2,-64) <= ulp(a) < 1
+            long r = ((longBits & DoubleConsts.SIGNIF_BIT_MASK)
+                    | (DoubleConsts.SIGNIF_BIT_MASK + 1));
+            if (longBits < 0) {
+                r = -r;
+            }
+            // In the comments below each Java expression evaluates to the value
+            // the corresponding mathematical expression:
+            // (r) evaluates to a / ulp(a)
+            // (r >> shift) evaluates to floor(a * 2)
+            // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
+            // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
+            return ((r >> shift) + 1) >> 1;
+        } else {
+            // a is either
+            // - a finite number with abs(a) < exp(2,DoubleConsts.SIGNIFICAND_WIDTH-64) < 1/2
+            // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
+            // - an infinity or NaN
+            return (long) a;
+        }
+    }
+
+    private static final class RandomNumberGeneratorHolder {
+        static final Random randomNumberGenerator = new Random();
+    }
+
+    /**
+     * Returns a {@code double} value with a positive sign, greater
+     * than or equal to {@code 0.0} and less than {@code 1.0}.
+     * Returned values are chosen pseudorandomly with (approximately)
+     * uniform distribution from that range.
+     *
+     * <p>When this method is first called, it creates a single new
+     * pseudorandom-number generator, exactly as if by the expression
+     *
+     * <blockquote>{@code new java.util.Random()}</blockquote>
+     *
+     * This new pseudorandom-number generator is used thereafter for
+     * all calls to this method and is used nowhere else.
+     *
+     * <p>This method is properly synchronized to allow correct use by
+     * more than one thread. However, if many threads need to generate
+     * pseudorandom numbers at a great rate, it may reduce contention
+     * for each thread to have its own pseudorandom-number generator.
+     *
+     * @return  a pseudorandom {@code double} greater than or equal
+     * to {@code 0.0} and less than {@code 1.0}.
+     * @see Random#nextDouble()
+     */
+    public static double random() {
+        return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
+    }
+
+    // Android-added: setRandomSeedInternal(long), called after zygote forks.
+    // This allows different processes to have different random seeds.
+    /**
+     * Set the seed for the pseudo random generator used by {@link #random()}
+     * and {@link #randomIntInternal()}.
+     *
+     * @hide for internal use only.
+     */
+    public static void setRandomSeedInternal(long seed) {
+        RandomNumberGeneratorHolder.randomNumberGenerator.setSeed(seed);
+    }
+
+    // Android-added: randomIntInternal() method: like random() but for int.
+    /**
+     * @hide for internal use only.
+     */
+    public static int randomIntInternal() {
+        return RandomNumberGeneratorHolder.randomNumberGenerator.nextInt();
+    }
+
+    // Android-added: randomLongInternal() method: like random() but for long.
+    /**
+     * @hide for internal use only.
+     */
+    public static long randomLongInternal() {
+        return RandomNumberGeneratorHolder.randomNumberGenerator.nextLong();
+    }
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    public static int addExact(int x, int y) {
+        int r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    public static long addExact(long x, long y) {
+        long r = x + y;
+        // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+        if (((x ^ r) & (y ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the difference of the arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value to subtract from the first
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    public static int subtractExact(int x, int y) {
+        int r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        if (((x ^ y) & (x ^ r)) < 0) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the difference of the arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value to subtract from the first
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    public static long subtractExact(long x, long y) {
+        long r = x - y;
+        // HD 2-12 Overflow iff the arguments have different signs and
+        // the sign of the result is different than the sign of x
+        if (((x ^ y) & (x ^ r)) < 0) {
+            throw new ArithmeticException("long overflow");
+        }
+        return r;
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    public static int multiplyExact(int x, int y) {
+        long r = (long)x * (long)y;
+        if ((int)r != r) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return (int)r;
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    public static long multiplyExact(long x, long y) {
+        long r = x * y;
+        long ax = Math.abs(x);
+        long ay = Math.abs(y);
+        if (((ax | ay) >>> 31 != 0)) {
+            // Some bits greater than 2^31 that might cause overflow
+            // Check the result using the divide operator
+            // and check for the special case of Long.MIN_VALUE * -1
+           if (((y != 0) && (r / y != x)) ||
+               (x == Long.MIN_VALUE && y == -1)) {
+                throw new ArithmeticException("long overflow");
+            }
+        }
+        return r;
+    }
+
+    /**
+     * Returns the argument incremented by one, throwing an exception if the
+     * result overflows an {@code int}.
+     *
+     * @param a the value to increment
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    public static int incrementExact(int a) {
+        if (a == Integer.MAX_VALUE) {
+            throw new ArithmeticException("integer overflow");
+        }
+
+        return a + 1;
+    }
+
+    /**
+     * Returns the argument incremented by one, throwing an exception if the
+     * result overflows a {@code long}.
+     *
+     * @param a the value to increment
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    public static long incrementExact(long a) {
+        if (a == Long.MAX_VALUE) {
+            throw new ArithmeticException("long overflow");
+        }
+
+        return a + 1L;
+    }
+
+    /**
+     * Returns the argument decremented by one, throwing an exception if the
+     * result overflows an {@code int}.
+     *
+     * @param a the value to decrement
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    public static int decrementExact(int a) {
+        if (a == Integer.MIN_VALUE) {
+            throw new ArithmeticException("integer overflow");
+        }
+
+        return a - 1;
+    }
+
+    /**
+     * Returns the argument decremented by one, throwing an exception if the
+     * result overflows a {@code long}.
+     *
+     * @param a the value to decrement
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    public static long decrementExact(long a) {
+        if (a == Long.MIN_VALUE) {
+            throw new ArithmeticException("long overflow");
+        }
+
+        return a - 1L;
+    }
+
+    /**
+     * Returns the negation of the argument, throwing an exception if the
+     * result overflows an {@code int}.
+     *
+     * @param a the value to negate
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @since 1.8
+     */
+    public static int negateExact(int a) {
+        if (a == Integer.MIN_VALUE) {
+            throw new ArithmeticException("integer overflow");
+        }
+
+        return -a;
+    }
+
+    /**
+     * Returns the negation of the argument, throwing an exception if the
+     * result overflows a {@code long}.
+     *
+     * @param a the value to negate
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @since 1.8
+     */
+    public static long negateExact(long a) {
+        if (a == Long.MIN_VALUE) {
+            throw new ArithmeticException("long overflow");
+        }
+
+        return -a;
+    }
+
+    /**
+     * Returns the value of the {@code long} argument;
+     * throwing an exception if the value overflows an {@code int}.
+     *
+     * @param value the long value
+     * @return the argument as an int
+     * @throws ArithmeticException if the {@code argument} overflows an int
+     * @since 1.8
+     */
+    public static int toIntExact(long value) {
+        if ((int)value != value) {
+            throw new ArithmeticException("integer overflow");
+        }
+        return (int)value;
+    }
+
+    /**
+     * Returns the largest (closest to positive infinity)
+     * {@code int} value that is less than or equal to the algebraic quotient.
+     * There is one special case, if the dividend is the
+     * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1},
+     * then integer overflow occurs and
+     * the result is equal to the {@code Integer.MIN_VALUE}.
+     * <p>
+     * Normal integer division operates under the round to zero rounding mode
+     * (truncation).  This operation instead acts under the round toward
+     * negative infinity (floor) rounding mode.
+     * The floor rounding mode gives different results than truncation
+     * when the exact result is negative.
+     * <ul>
+     *   <li>If the signs of the arguments are the same, the results of
+     *       {@code floorDiv} and the {@code /} operator are the same.  <br>
+     *       For example, {@code floorDiv(4, 3) == 1} and {@code (4 / 3) == 1}.</li>
+     *   <li>If the signs of the arguments are different,  the quotient is negative and
+     *       {@code floorDiv} returns the integer less than or equal to the quotient
+     *       and the {@code /} operator returns the integer closest to zero.<br>
+     *       For example, {@code floorDiv(-4, 3) == -2},
+     *       whereas {@code (-4 / 3) == -1}.
+     *   </li>
+     * </ul>
+     * <p>
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the largest (closest to positive infinity)
+     * {@code int} value that is less than or equal to the algebraic quotient.
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see #floorMod(int, int)
+     * @see #floor(double)
+     * @since 1.8
+     */
+    public static int floorDiv(int x, int y) {
+        int r = x / y;
+        // if the signs are different and modulo not zero, round down
+        if ((x ^ y) < 0 && (r * y != x)) {
+            r--;
+        }
+        return r;
+    }
+
+    /**
+     * Returns the largest (closest to positive infinity)
+     * {@code long} value that is less than or equal to the algebraic quotient.
+     * There is one special case, if the dividend is the
+     * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
+     * then integer overflow occurs and
+     * the result is equal to the {@code Long.MIN_VALUE}.
+     * <p>
+     * Normal integer division operates under the round to zero rounding mode
+     * (truncation).  This operation instead acts under the round toward
+     * negative infinity (floor) rounding mode.
+     * The floor rounding mode gives different results than truncation
+     * when the exact result is negative.
+     * <p>
+     * For examples, see {@link #floorDiv(int, int)}.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the largest (closest to positive infinity)
+     * {@code long} value that is less than or equal to the algebraic quotient.
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see #floorMod(long, long)
+     * @see #floor(double)
+     * @since 1.8
+     */
+    public static long floorDiv(long x, long y) {
+        long r = x / y;
+        // if the signs are different and modulo not zero, round down
+        if ((x ^ y) < 0 && (r * y != x)) {
+            r--;
+        }
+        return r;
+    }
+
+    /**
+     * Returns the floor modulus of the {@code int} arguments.
+     * <p>
+     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+     * has the same sign as the divisor {@code y}, and
+     * is in the range of {@code -abs(y) < r < +abs(y)}.
+     *
+     * <p>
+     * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+     * <ul>
+     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+     * </ul>
+     * <p>
+     * The difference in values between {@code floorMod} and
+     * the {@code %} operator is due to the difference between
+     * {@code floorDiv} that returns the integer less than or equal to the quotient
+     * and the {@code /} operator that returns the integer closest to zero.
+     * <p>
+     * Examples:
+     * <ul>
+     *   <li>If the signs of the arguments are the same, the results
+     *       of {@code floorMod} and the {@code %} operator are the same.  <br>
+     *       <ul>
+     *       <li>{@code floorMod(4, 3) == 1}; &nbsp; and {@code (4 % 3) == 1}</li>
+     *       </ul>
+     *   <li>If the signs of the arguments are different, the results differ from the {@code %} operator.<br>
+     *      <ul>
+     *      <li>{@code floorMod(+4, -3) == -2}; &nbsp; and {@code (+4 % -3) == +1} </li>
+     *      <li>{@code floorMod(-4, +3) == +2}; &nbsp; and {@code (-4 % +3) == -1} </li>
+     *      <li>{@code floorMod(-4, -3) == -1}; &nbsp; and {@code (-4 % -3) == -1 } </li>
+     *      </ul>
+     *   </li>
+     * </ul>
+     * <p>
+     * If the signs of arguments are unknown and a positive modulus
+     * is needed it can be computed as {@code (floorMod(x, y) + abs(y)) % abs(y)}.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see #floorDiv(int, int)
+     * @since 1.8
+     */
+    public static int floorMod(int x, int y) {
+        int r = x - floorDiv(x, y) * y;
+        return r;
+    }
+
+    /**
+     * Returns the floor modulus of the {@code long} arguments.
+     * <p>
+     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+     * has the same sign as the divisor {@code y}, and
+     * is in the range of {@code -abs(y) < r < +abs(y)}.
+     *
+     * <p>
+     * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+     * <ul>
+     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+     * </ul>
+     * <p>
+     * For examples, see {@link #floorMod(int, int)}.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see #floorDiv(long, long)
+     * @since 1.8
+     */
+    public static long floorMod(long x, long y) {
+        return x - floorDiv(x, y) * y;
+    }
+
+    /**
+     * Returns the absolute value of an {@code int} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     *
+     * <p>Note that if the argument is equal to the value of
+     * {@link Integer#MIN_VALUE}, the most negative representable
+     * {@code int} value, the result is that same value, which is
+     * negative.
+     *
+     * @param   a   the argument whose absolute value is to be determined
+     * @return  the absolute value of the argument.
+     */
+    public static int abs(int a) {
+        return (a < 0) ? -a : a;
+    }
+
+    /**
+     * Returns the absolute value of a {@code long} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     *
+     * <p>Note that if the argument is equal to the value of
+     * {@link Long#MIN_VALUE}, the most negative representable
+     * {@code long} value, the result is that same value, which
+     * is negative.
+     *
+     * @param   a   the argument whose absolute value is to be determined
+     * @return  the absolute value of the argument.
+     */
+    public static long abs(long a) {
+        return (a < 0) ? -a : a;
+    }
+
+    /**
+     * Returns the absolute value of a {@code float} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     * Special cases:
+     * <ul><li>If the argument is positive zero or negative zero, the
+     * result is positive zero.
+     * <li>If the argument is infinite, the result is positive infinity.
+     * <li>If the argument is NaN, the result is NaN.</ul>
+     * In other words, the result is the same as the value of the expression:
+     * <p>{@code Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))}
+     *
+     * @param   a   the argument whose absolute value is to be determined
+     * @return  the absolute value of the argument.
+     */
+    public static float abs(float a) {
+        // Android-changed: Implementation modified to exactly match ART intrinsics behavior.
+        // Note, as a "quality of implementation", rather than pure "spec compliance",
+        // we require that Math.abs() clears the sign bit (but changes nothing else)
+        // for all numbers, including NaN (signaling NaN may become quiet though).
+        // http://b/30758343
+        return Float.intBitsToFloat(0x7fffffff & Float.floatToRawIntBits(a));
+    }
+
+    /**
+     * Returns the absolute value of a {@code double} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     * Special cases:
+     * <ul><li>If the argument is positive zero or negative zero, the result
+     * is positive zero.
+     * <li>If the argument is infinite, the result is positive infinity.
+     * <li>If the argument is NaN, the result is NaN.</ul>
+     * In other words, the result is the same as the value of the expression:
+     * <p>{@code Double.longBitsToDouble((Double.doubleToLongBits(a)<<1)>>>1)}
+     *
+     * @param   a   the argument whose absolute value is to be determined
+     * @return  the absolute value of the argument.
+     */
+    public static double abs(double a) {
+        // Android-changed: Implementation modified to exactly match ART intrinsics behavior.
+        // Note, as a "quality of implementation", rather than pure "spec compliance",
+        // we require that Math.abs() clears the sign bit (but changes nothing else)
+        // for all numbers, including NaN (signaling NaN may become quiet though).
+        // http://b/30758343
+        return Double.longBitsToDouble(0x7fffffffffffffffL & Double.doubleToRawLongBits(a));
+    }
+
+    /**
+     * Returns the greater of two {@code int} values. That is, the
+     * result is the argument closer to the value of
+     * {@link Integer#MAX_VALUE}. If the arguments have the same value,
+     * the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static int max(int a, int b) {
+        return (a >= b) ? a : b;
+    }
+
+    /**
+     * Returns the greater of two {@code long} values. That is, the
+     * result is the argument closer to the value of
+     * {@link Long#MAX_VALUE}. If the arguments have the same value,
+     * the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static long max(long a, long b) {
+        return (a >= b) ? a : b;
+    }
+
+    // Use raw bit-wise conversions on guaranteed non-NaN arguments.
+    private static long negativeZeroFloatBits  = Float.floatToRawIntBits(-0.0f);
+    private static long negativeZeroDoubleBits = Double.doubleToRawLongBits(-0.0d);
+
+    /**
+     * Returns the greater of two {@code float} values.  That is,
+     * the result is the argument closer to positive infinity. If the
+     * arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero. If one
+     * argument is positive zero and the other negative zero, the
+     * result is positive zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static float max(float a, float b) {
+        if (a != a)
+            return a;   // a is NaN
+        if ((a == 0.0f) &&
+            (b == 0.0f) &&
+            (Float.floatToRawIntBits(a) == negativeZeroFloatBits)) {
+            // Raw conversion ok since NaN can't map to -0.0.
+            return b;
+        }
+        return (a >= b) ? a : b;
+    }
+
+    /**
+     * Returns the greater of two {@code double} values.  That
+     * is, the result is the argument closer to positive infinity. If
+     * the arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero. If one
+     * argument is positive zero and the other negative zero, the
+     * result is positive zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static double max(double a, double b) {
+        if (a != a)
+            return a;   // a is NaN
+        if ((a == 0.0d) &&
+            (b == 0.0d) &&
+            (Double.doubleToRawLongBits(a) == negativeZeroDoubleBits)) {
+            // Raw conversion ok since NaN can't map to -0.0.
+            return b;
+        }
+        return (a >= b) ? a : b;
+    }
+
+    /**
+     * Returns the smaller of two {@code int} values. That is,
+     * the result the argument closer to the value of
+     * {@link Integer#MIN_VALUE}.  If the arguments have the same
+     * value, the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static int min(int a, int b) {
+        return (a <= b) ? a : b;
+    }
+
+    /**
+     * Returns the smaller of two {@code long} values. That is,
+     * the result is the argument closer to the value of
+     * {@link Long#MIN_VALUE}. If the arguments have the same
+     * value, the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static long min(long a, long b) {
+        return (a <= b) ? a : b;
+    }
+
+    /**
+     * Returns the smaller of two {@code float} values.  That is,
+     * the result is the value closer to negative infinity. If the
+     * arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero.  If
+     * one argument is positive zero and the other is negative zero,
+     * the result is negative zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static float min(float a, float b) {
+        if (a != a)
+            return a;   // a is NaN
+        if ((a == 0.0f) &&
+            (b == 0.0f) &&
+            (Float.floatToRawIntBits(b) == negativeZeroFloatBits)) {
+            // Raw conversion ok since NaN can't map to -0.0.
+            return b;
+        }
+        return (a <= b) ? a : b;
+    }
+
+    /**
+     * Returns the smaller of two {@code double} values.  That
+     * is, the result is the value closer to negative infinity. If the
+     * arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero. If one
+     * argument is positive zero and the other is negative zero, the
+     * result is negative zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static double min(double a, double b) {
+        if (a != a)
+            return a;   // a is NaN
+        if ((a == 0.0d) &&
+            (b == 0.0d) &&
+            (Double.doubleToRawLongBits(b) == negativeZeroDoubleBits)) {
+            // Raw conversion ok since NaN can't map to -0.0.
+            return b;
+        }
+        return (a <= b) ? a : b;
+    }
+
+    /**
+     * Returns the size of an ulp of the argument.  An ulp, unit in
+     * the last place, of a {@code double} value is the positive
+     * distance between this floating-point value and the {@code
+     * double} value next larger in magnitude.  Note that for non-NaN
+     * <i>x</i>, <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive or negative infinity, then the
+     * result is positive infinity.
+     * <li> If the argument is positive or negative zero, then the result is
+     * {@code Double.MIN_VALUE}.
+     * <li> If the argument is &plusmn;{@code Double.MAX_VALUE}, then
+     * the result is equal to 2<sup>971</sup>.
+     * </ul>
+     *
+     * @param d the floating-point value whose ulp is to be returned
+     * @return the size of an ulp of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static double ulp(double d) {
+        int exp = getExponent(d);
+
+        switch(exp) {
+        case DoubleConsts.MAX_EXPONENT+1:       // NaN or infinity
+            return Math.abs(d);
+
+        case DoubleConsts.MIN_EXPONENT-1:       // zero or subnormal
+            return Double.MIN_VALUE;
+
+        default:
+            assert exp <= DoubleConsts.MAX_EXPONENT && exp >= DoubleConsts.MIN_EXPONENT;
+
+            // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
+            exp = exp - (DoubleConsts.SIGNIFICAND_WIDTH-1);
+            if (exp >= DoubleConsts.MIN_EXPONENT) {
+                return powerOfTwoD(exp);
+            }
+            else {
+                // return a subnormal result; left shift integer
+                // representation of Double.MIN_VALUE appropriate
+                // number of positions
+                return Double.longBitsToDouble(1L <<
+                (exp - (DoubleConsts.MIN_EXPONENT - (DoubleConsts.SIGNIFICAND_WIDTH-1)) ));
+            }
+        }
+    }
+
+    /**
+     * Returns the size of an ulp of the argument.  An ulp, unit in
+     * the last place, of a {@code float} value is the positive
+     * distance between this floating-point value and the {@code
+     * float} value next larger in magnitude.  Note that for non-NaN
+     * <i>x</i>, <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive or negative infinity, then the
+     * result is positive infinity.
+     * <li> If the argument is positive or negative zero, then the result is
+     * {@code Float.MIN_VALUE}.
+     * <li> If the argument is &plusmn;{@code Float.MAX_VALUE}, then
+     * the result is equal to 2<sup>104</sup>.
+     * </ul>
+     *
+     * @param f the floating-point value whose ulp is to be returned
+     * @return the size of an ulp of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static float ulp(float f) {
+        int exp = getExponent(f);
+
+        switch(exp) {
+        case FloatConsts.MAX_EXPONENT+1:        // NaN or infinity
+            return Math.abs(f);
+
+        case FloatConsts.MIN_EXPONENT-1:        // zero or subnormal
+            return FloatConsts.MIN_VALUE;
+
+        default:
+            assert exp <= FloatConsts.MAX_EXPONENT && exp >= FloatConsts.MIN_EXPONENT;
+
+            // ulp(x) is usually 2^(SIGNIFICAND_WIDTH-1)*(2^ilogb(x))
+            exp = exp - (FloatConsts.SIGNIFICAND_WIDTH-1);
+            if (exp >= FloatConsts.MIN_EXPONENT) {
+                return powerOfTwoF(exp);
+            }
+            else {
+                // return a subnormal result; left shift integer
+                // representation of FloatConsts.MIN_VALUE appropriate
+                // number of positions
+                return Float.intBitsToFloat(1 <<
+                (exp - (FloatConsts.MIN_EXPONENT - (FloatConsts.SIGNIFICAND_WIDTH-1)) ));
+            }
+        }
+    }
+
+    /**
+     * Returns the signum function of the argument; zero if the argument
+     * is zero, 1.0 if the argument is greater than zero, -1.0 if the
+     * argument is less than zero.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive zero or negative zero, then the
+     *      result is the same as the argument.
+     * </ul>
+     *
+     * @param d the floating-point value whose signum is to be returned
+     * @return the signum function of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static double signum(double d) {
+        return (d == 0.0 || Double.isNaN(d))?d:copySign(1.0, d);
+    }
+
+    /**
+     * Returns the signum function of the argument; zero if the argument
+     * is zero, 1.0f if the argument is greater than zero, -1.0f if the
+     * argument is less than zero.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive zero or negative zero, then the
+     *      result is the same as the argument.
+     * </ul>
+     *
+     * @param f the floating-point value whose signum is to be returned
+     * @return the signum function of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static float signum(float f) {
+        return (f == 0.0f || Float.isNaN(f))?f:copySign(1.0f, f);
+    }
+
+    /**
+     * Returns the hyperbolic sine of a {@code double} value.
+     * The hyperbolic sine of <i>x</i> is defined to be
+     * (<i>e<sup>x</sup>&nbsp;-&nbsp;e<sup>-x</sup></i>)/2
+     * where <i>e</i> is {@linkplain Math#E Euler's number}.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is infinite, then the result is an infinity
+     * with the same sign as the argument.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 2.5 ulps of the exact result.
+     *
+     * @param   x The number whose hyperbolic sine is to be returned.
+     * @return  The hyperbolic sine of {@code x}.
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double sinh(double x);
+
+    /**
+     * Returns the hyperbolic cosine of a {@code double} value.
+     * The hyperbolic cosine of <i>x</i> is defined to be
+     * (<i>e<sup>x</sup>&nbsp;+&nbsp;e<sup>-x</sup></i>)/2
+     * where <i>e</i> is {@linkplain Math#E Euler's number}.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is infinite, then the result is positive
+     * infinity.
+     *
+     * <li>If the argument is zero, then the result is {@code 1.0}.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 2.5 ulps of the exact result.
+     *
+     * @param   x The number whose hyperbolic cosine is to be returned.
+     * @return  The hyperbolic cosine of {@code x}.
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double cosh(double x);
+
+    /**
+     * Returns the hyperbolic tangent of a {@code double} value.
+     * The hyperbolic tangent of <i>x</i> is defined to be
+     * (<i>e<sup>x</sup>&nbsp;-&nbsp;e<sup>-x</sup></i>)/(<i>e<sup>x</sup>&nbsp;+&nbsp;e<sup>-x</sup></i>),
+     * in other words, {@linkplain Math#sinh
+     * sinh(<i>x</i>)}/{@linkplain Math#cosh cosh(<i>x</i>)}.  Note
+     * that the absolute value of the exact tanh is always less than
+     * 1.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * <li>If the argument is positive infinity, then the result is
+     * {@code +1.0}.
+     *
+     * <li>If the argument is negative infinity, then the result is
+     * {@code -1.0}.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 2.5 ulps of the exact result.
+     * The result of {@code tanh} for any finite input must have
+     * an absolute value less than or equal to 1.  Note that once the
+     * exact result of tanh is within 1/2 of an ulp of the limit value
+     * of &plusmn;1, correctly signed &plusmn;{@code 1.0} should
+     * be returned.
+     *
+     * @param   x The number whose hyperbolic tangent is to be returned.
+     * @return  The hyperbolic tangent of {@code x}.
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double tanh(double x);
+
+    /**
+     * Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
+     * without intermediate overflow or underflow.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li> If either argument is infinite, then the result
+     * is positive infinity.
+     *
+     * <li> If either argument is NaN and neither argument is infinite,
+     * then the result is NaN.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact
+     * result.  If one parameter is held constant, the results must be
+     * semi-monotonic in the other parameter.
+     *
+     * @param x a value
+     * @param y a value
+     * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
+     * without intermediate overflow or underflow
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double hypot(double x, double y);
+
+    /**
+     * Returns <i>e</i><sup>x</sup>&nbsp;-1.  Note that for values of
+     * <i>x</i> near 0, the exact sum of
+     * {@code expm1(x)}&nbsp;+&nbsp;1 is much closer to the true
+     * result of <i>e</i><sup>x</sup> than {@code exp(x)}.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li>If the argument is NaN, the result is NaN.
+     *
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     *
+     * <li>If the argument is negative infinity, then the result is
+     * -1.0.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.  The result of
+     * {@code expm1} for any finite input must be greater than or
+     * equal to {@code -1.0}.  Note that once the exact result of
+     * <i>e</i><sup>{@code x}</sup>&nbsp;-&nbsp;1 is within 1/2
+     * ulp of the limit value -1, {@code -1.0} should be
+     * returned.
+     *
+     * @param   x   the exponent to raise <i>e</i> to in the computation of
+     *              <i>e</i><sup>{@code x}</sup>&nbsp;-1.
+     * @return  the value <i>e</i><sup>{@code x}</sup>&nbsp;-&nbsp;1.
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double expm1(double x);
+
+    /**
+     * Returns the natural logarithm of the sum of the argument and 1.
+     * Note that for small values {@code x}, the result of
+     * {@code log1p(x)} is much closer to the true result of ln(1
+     * + {@code x}) than the floating-point evaluation of
+     * {@code log(1.0+x)}.
+     *
+     * <p>Special cases:
+     *
+     * <ul>
+     *
+     * <li>If the argument is NaN or less than -1, then the result is
+     * NaN.
+     *
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     *
+     * <li>If the argument is negative one, then the result is
+     * negative infinity.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * <p>The computed result must be within 1 ulp of the exact result.
+     * Results must be semi-monotonic.
+     *
+     * @param   x   a value
+     * @return the value ln({@code x}&nbsp;+&nbsp;1), the natural
+     * log of {@code x}&nbsp;+&nbsp;1
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native double log1p(double x);
+
+    /**
+     * Returns the first floating-point argument with the sign of the
+     * second floating-point argument.  Note that unlike the {@link
+     * StrictMath#copySign(double, double) StrictMath.copySign}
+     * method, this method does not require NaN {@code sign}
+     * arguments to be treated as positive values; implementations are
+     * permitted to treat some NaN arguments as positive and other NaN
+     * arguments as negative to allow greater performance.
+     *
+     * @param magnitude  the parameter providing the magnitude of the result
+     * @param sign   the parameter providing the sign of the result
+     * @return a value with the magnitude of {@code magnitude}
+     * and the sign of {@code sign}.
+     * @since 1.6
+     */
+    public static double copySign(double magnitude, double sign) {
+        return Double.longBitsToDouble((Double.doubleToRawLongBits(sign) &
+                                        (DoubleConsts.SIGN_BIT_MASK)) |
+                                       (Double.doubleToRawLongBits(magnitude) &
+                                        (DoubleConsts.EXP_BIT_MASK |
+                                         DoubleConsts.SIGNIF_BIT_MASK)));
+    }
+
+    /**
+     * Returns the first floating-point argument with the sign of the
+     * second floating-point argument.  Note that unlike the {@link
+     * StrictMath#copySign(float, float) StrictMath.copySign}
+     * method, this method does not require NaN {@code sign}
+     * arguments to be treated as positive values; implementations are
+     * permitted to treat some NaN arguments as positive and other NaN
+     * arguments as negative to allow greater performance.
+     *
+     * @param magnitude  the parameter providing the magnitude of the result
+     * @param sign   the parameter providing the sign of the result
+     * @return a value with the magnitude of {@code magnitude}
+     * and the sign of {@code sign}.
+     * @since 1.6
+     */
+    public static float copySign(float magnitude, float sign) {
+        return Float.intBitsToFloat((Float.floatToRawIntBits(sign) &
+                                     (FloatConsts.SIGN_BIT_MASK)) |
+                                    (Float.floatToRawIntBits(magnitude) &
+                                     (FloatConsts.EXP_BIT_MASK |
+                                      FloatConsts.SIGNIF_BIT_MASK)));
+    }
+
+    /**
+     * Returns the unbiased exponent used in the representation of a
+     * {@code float}.  Special cases:
+     *
+     * <ul>
+     * <li>If the argument is NaN or infinite, then the result is
+     * {@link Float#MAX_EXPONENT} + 1.
+     * <li>If the argument is zero or subnormal, then the result is
+     * {@link Float#MIN_EXPONENT} -1.
+     * </ul>
+     * @param f a {@code float} value
+     * @return the unbiased exponent of the argument
+     * @since 1.6
+     */
+    public static int getExponent(float f) {
+        /*
+         * Bitwise convert f to integer, mask out exponent bits, shift
+         * to the right and then subtract out float's bias adjust to
+         * get true exponent value
+         */
+        return ((Float.floatToRawIntBits(f) & FloatConsts.EXP_BIT_MASK) >>
+                (FloatConsts.SIGNIFICAND_WIDTH - 1)) - FloatConsts.EXP_BIAS;
+    }
+
+    /**
+     * Returns the unbiased exponent used in the representation of a
+     * {@code double}.  Special cases:
+     *
+     * <ul>
+     * <li>If the argument is NaN or infinite, then the result is
+     * {@link Double#MAX_EXPONENT} + 1.
+     * <li>If the argument is zero or subnormal, then the result is
+     * {@link Double#MIN_EXPONENT} -1.
+     * </ul>
+     * @param d a {@code double} value
+     * @return the unbiased exponent of the argument
+     * @since 1.6
+     */
+    public static int getExponent(double d) {
+        /*
+         * Bitwise convert d to long, mask out exponent bits, shift
+         * to the right and then subtract out double's bias adjust to
+         * get true exponent value.
+         */
+        return (int)(((Double.doubleToRawLongBits(d) & DoubleConsts.EXP_BIT_MASK) >>
+                      (DoubleConsts.SIGNIFICAND_WIDTH - 1)) - DoubleConsts.EXP_BIAS);
+    }
+
+    /**
+     * Returns the floating-point number adjacent to the first
+     * argument in the direction of the second argument.  If both
+     * arguments compare as equal the second argument is returned.
+     *
+     * <p>
+     * Special cases:
+     * <ul>
+     * <li> If either argument is a NaN, then NaN is returned.
+     *
+     * <li> If both arguments are signed zeros, {@code direction}
+     * is returned unchanged (as implied by the requirement of
+     * returning the second argument if the arguments compare as
+     * equal).
+     *
+     * <li> If {@code start} is
+     * &plusmn;{@link Double#MIN_VALUE} and {@code direction}
+     * has a value such that the result should have a smaller
+     * magnitude, then a zero with the same sign as {@code start}
+     * is returned.
+     *
+     * <li> If {@code start} is infinite and
+     * {@code direction} has a value such that the result should
+     * have a smaller magnitude, {@link Double#MAX_VALUE} with the
+     * same sign as {@code start} is returned.
+     *
+     * <li> If {@code start} is equal to &plusmn;
+     * {@link Double#MAX_VALUE} and {@code direction} has a
+     * value such that the result should have a larger magnitude, an
+     * infinity with same sign as {@code start} is returned.
+     * </ul>
+     *
+     * @param start  starting floating-point value
+     * @param direction value indicating which of
+     * {@code start}'s neighbors or {@code start} should
+     * be returned
+     * @return The floating-point number adjacent to {@code start} in the
+     * direction of {@code direction}.
+     * @since 1.6
+     */
+    public static double nextAfter(double start, double direction) {
+        /*
+         * The cases:
+         *
+         * nextAfter(+infinity, 0)  == MAX_VALUE
+         * nextAfter(+infinity, +infinity)  == +infinity
+         * nextAfter(-infinity, 0)  == -MAX_VALUE
+         * nextAfter(-infinity, -infinity)  == -infinity
+         *
+         * are naturally handled without any additional testing
+         */
+
+        // First check for NaN values
+        if (Double.isNaN(start) || Double.isNaN(direction)) {
+            // return a NaN derived from the input NaN(s)
+            return start + direction;
+        } else if (start == direction) {
+            return direction;
+        } else {        // start > direction or start < direction
+            // Add +0.0 to get rid of a -0.0 (+0.0 + -0.0 => +0.0)
+            // then bitwise convert start to integer.
+            long transducer = Double.doubleToRawLongBits(start + 0.0d);
+
+            /*
+             * IEEE 754 floating-point numbers are lexicographically
+             * ordered if treated as signed- magnitude integers .
+             * Since Java's integers are two's complement,
+             * incrementing" the two's complement representation of a
+             * logically negative floating-point value *decrements*
+             * the signed-magnitude representation. Therefore, when
+             * the integer representation of a floating-point values
+             * is less than zero, the adjustment to the representation
+             * is in the opposite direction than would be expected at
+             * first .
+             */
+            if (direction > start) { // Calculate next greater value
+                transducer = transducer + (transducer >= 0L ? 1L:-1L);
+            } else  { // Calculate next lesser value
+                assert direction < start;
+                if (transducer > 0L)
+                    --transducer;
+                else
+                    if (transducer < 0L )
+                        ++transducer;
+                    /*
+                     * transducer==0, the result is -MIN_VALUE
+                     *
+                     * The transition from zero (implicitly
+                     * positive) to the smallest negative
+                     * signed magnitude value must be done
+                     * explicitly.
+                     */
+                    else
+                        transducer = DoubleConsts.SIGN_BIT_MASK | 1L;
+            }
+
+            return Double.longBitsToDouble(transducer);
+        }
+    }
+
+    /**
+     * Returns the floating-point number adjacent to the first
+     * argument in the direction of the second argument.  If both
+     * arguments compare as equal a value equivalent to the second argument
+     * is returned.
+     *
+     * <p>
+     * Special cases:
+     * <ul>
+     * <li> If either argument is a NaN, then NaN is returned.
+     *
+     * <li> If both arguments are signed zeros, a value equivalent
+     * to {@code direction} is returned.
+     *
+     * <li> If {@code start} is
+     * &plusmn;{@link Float#MIN_VALUE} and {@code direction}
+     * has a value such that the result should have a smaller
+     * magnitude, then a zero with the same sign as {@code start}
+     * is returned.
+     *
+     * <li> If {@code start} is infinite and
+     * {@code direction} has a value such that the result should
+     * have a smaller magnitude, {@link Float#MAX_VALUE} with the
+     * same sign as {@code start} is returned.
+     *
+     * <li> If {@code start} is equal to &plusmn;
+     * {@link Float#MAX_VALUE} and {@code direction} has a
+     * value such that the result should have a larger magnitude, an
+     * infinity with same sign as {@code start} is returned.
+     * </ul>
+     *
+     * @param start  starting floating-point value
+     * @param direction value indicating which of
+     * {@code start}'s neighbors or {@code start} should
+     * be returned
+     * @return The floating-point number adjacent to {@code start} in the
+     * direction of {@code direction}.
+     * @since 1.6
+     */
+    public static float nextAfter(float start, double direction) {
+        /*
+         * The cases:
+         *
+         * nextAfter(+infinity, 0)  == MAX_VALUE
+         * nextAfter(+infinity, +infinity)  == +infinity
+         * nextAfter(-infinity, 0)  == -MAX_VALUE
+         * nextAfter(-infinity, -infinity)  == -infinity
+         *
+         * are naturally handled without any additional testing
+         */
+
+        // First check for NaN values
+        if (Float.isNaN(start) || Double.isNaN(direction)) {
+            // return a NaN derived from the input NaN(s)
+            return start + (float)direction;
+        } else if (start == direction) {
+            return (float)direction;
+        } else {        // start > direction or start < direction
+            // Add +0.0 to get rid of a -0.0 (+0.0 + -0.0 => +0.0)
+            // then bitwise convert start to integer.
+            int transducer = Float.floatToRawIntBits(start + 0.0f);
+
+            /*
+             * IEEE 754 floating-point numbers are lexicographically
+             * ordered if treated as signed- magnitude integers .
+             * Since Java's integers are two's complement,
+             * incrementing" the two's complement representation of a
+             * logically negative floating-point value *decrements*
+             * the signed-magnitude representation. Therefore, when
+             * the integer representation of a floating-point values
+             * is less than zero, the adjustment to the representation
+             * is in the opposite direction than would be expected at
+             * first.
+             */
+            if (direction > start) {// Calculate next greater value
+                transducer = transducer + (transducer >= 0 ? 1:-1);
+            } else  { // Calculate next lesser value
+                assert direction < start;
+                if (transducer > 0)
+                    --transducer;
+                else
+                    if (transducer < 0 )
+                        ++transducer;
+                    /*
+                     * transducer==0, the result is -MIN_VALUE
+                     *
+                     * The transition from zero (implicitly
+                     * positive) to the smallest negative
+                     * signed magnitude value must be done
+                     * explicitly.
+                     */
+                    else
+                        transducer = FloatConsts.SIGN_BIT_MASK | 1;
+            }
+
+            return Float.intBitsToFloat(transducer);
+        }
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code d} in
+     * the direction of positive infinity.  This method is
+     * semantically equivalent to {@code nextAfter(d,
+     * Double.POSITIVE_INFINITY)}; however, a {@code nextUp}
+     * implementation may run faster than its equivalent
+     * {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is positive infinity, the result is
+     * positive infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@link Double#MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param d starting floating-point value
+     * @return The adjacent floating-point value closer to positive
+     * infinity.
+     * @since 1.6
+     */
+    public static double nextUp(double d) {
+        if( Double.isNaN(d) || d == Double.POSITIVE_INFINITY)
+            return d;
+        else {
+            d += 0.0d;
+            return Double.longBitsToDouble(Double.doubleToRawLongBits(d) +
+                                           ((d >= 0.0d)?+1L:-1L));
+        }
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code f} in
+     * the direction of positive infinity.  This method is
+     * semantically equivalent to {@code nextAfter(f,
+     * Float.POSITIVE_INFINITY)}; however, a {@code nextUp}
+     * implementation may run faster than its equivalent
+     * {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is positive infinity, the result is
+     * positive infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@link Float#MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param f starting floating-point value
+     * @return The adjacent floating-point value closer to positive
+     * infinity.
+     * @since 1.6
+     */
+    public static float nextUp(float f) {
+        if( Float.isNaN(f) || f == FloatConsts.POSITIVE_INFINITY)
+            return f;
+        else {
+            f += 0.0f;
+            return Float.intBitsToFloat(Float.floatToRawIntBits(f) +
+                                        ((f >= 0.0f)?+1:-1));
+        }
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code d} in
+     * the direction of negative infinity.  This method is
+     * semantically equivalent to {@code nextAfter(d,
+     * Double.NEGATIVE_INFINITY)}; however, a
+     * {@code nextDown} implementation may run faster than its
+     * equivalent {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is negative infinity, the result is
+     * negative infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@code -Double.MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param d  starting floating-point value
+     * @return The adjacent floating-point value closer to negative
+     * infinity.
+     * @since 1.8
+     */
+    public static double nextDown(double d) {
+        if (Double.isNaN(d) || d == Double.NEGATIVE_INFINITY)
+            return d;
+        else {
+            if (d == 0.0)
+                return -Double.MIN_VALUE;
+            else
+                return Double.longBitsToDouble(Double.doubleToRawLongBits(d) +
+                                               ((d > 0.0d)?-1L:+1L));
+        }
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code f} in
+     * the direction of negative infinity.  This method is
+     * semantically equivalent to {@code nextAfter(f,
+     * Float.NEGATIVE_INFINITY)}; however, a
+     * {@code nextDown} implementation may run faster than its
+     * equivalent {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is negative infinity, the result is
+     * negative infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@code -Float.MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param f  starting floating-point value
+     * @return The adjacent floating-point value closer to negative
+     * infinity.
+     * @since 1.8
+     */
+    public static float nextDown(float f) {
+        if (Float.isNaN(f) || f == Float.NEGATIVE_INFINITY)
+            return f;
+        else {
+            if (f == 0.0f)
+                return -Float.MIN_VALUE;
+            else
+                return Float.intBitsToFloat(Float.floatToRawIntBits(f) +
+                                            ((f > 0.0f)?-1:+1));
+        }
+    }
+
+    /**
+     * Returns {@code d} &times;
+     * 2<sup>{@code scaleFactor}</sup> rounded as if performed
+     * by a single correctly rounded floating-point multiply to a
+     * member of the double value set.  See the Java
+     * Language Specification for a discussion of floating-point
+     * value sets.  If the exponent of the result is between {@link
+     * Double#MIN_EXPONENT} and {@link Double#MAX_EXPONENT}, the
+     * answer is calculated exactly.  If the exponent of the result
+     * would be larger than {@code Double.MAX_EXPONENT}, an
+     * infinity is returned.  Note that if the result is subnormal,
+     * precision may be lost; that is, when {@code scalb(x, n)}
+     * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal
+     * <i>x</i>.  When the result is non-NaN, the result has the same
+     * sign as {@code d}.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li> If the first argument is NaN, NaN is returned.
+     * <li> If the first argument is infinite, then an infinity of the
+     * same sign is returned.
+     * <li> If the first argument is zero, then a zero of the same
+     * sign is returned.
+     * </ul>
+     *
+     * @param d number to be scaled by a power of two.
+     * @param scaleFactor power of 2 used to scale {@code d}
+     * @return {@code d} &times; 2<sup>{@code scaleFactor}</sup>
+     * @since 1.6
+     */
+    public static double scalb(double d, int scaleFactor) {
+        /*
+         * This method does not need to be declared strictfp to
+         * compute the same correct result on all platforms.  When
+         * scaling up, it does not matter what order the
+         * multiply-store operations are done; the result will be
+         * finite or overflow regardless of the operation ordering.
+         * However, to get the correct result when scaling down, a
+         * particular ordering must be used.
+         *
+         * When scaling down, the multiply-store operations are
+         * sequenced so that it is not possible for two consecutive
+         * multiply-stores to return subnormal results.  If one
+         * multiply-store result is subnormal, the next multiply will
+         * round it away to zero.  This is done by first multiplying
+         * by 2 ^ (scaleFactor % n) and then multiplying several
+         * times by by 2^n as needed where n is the exponent of number
+         * that is a covenient power of two.  In this way, at most one
+         * real rounding error occurs.  If the double value set is
+         * being used exclusively, the rounding will occur on a
+         * multiply.  If the double-extended-exponent value set is
+         * being used, the products will (perhaps) be exact but the
+         * stores to d are guaranteed to round to the double value
+         * set.
+         *
+         * It is _not_ a valid implementation to first multiply d by
+         * 2^MIN_EXPONENT and then by 2 ^ (scaleFactor %
+         * MIN_EXPONENT) since even in a strictfp program double
+         * rounding on underflow could occur; e.g. if the scaleFactor
+         * argument was (MIN_EXPONENT - n) and the exponent of d was a
+         * little less than -(MIN_EXPONENT - n), meaning the final
+         * result would be subnormal.
+         *
+         * Since exact reproducibility of this method can be achieved
+         * without any undue performance burden, there is no
+         * compelling reason to allow double rounding on underflow in
+         * scalb.
+         */
+
+        // magnitude of a power of two so large that scaling a finite
+        // nonzero value by it would be guaranteed to over or
+        // underflow; due to rounding, scaling down takes takes an
+        // additional power of two which is reflected here
+        final int MAX_SCALE = DoubleConsts.MAX_EXPONENT + -DoubleConsts.MIN_EXPONENT +
+                              DoubleConsts.SIGNIFICAND_WIDTH + 1;
+        int exp_adjust = 0;
+        int scale_increment = 0;
+        double exp_delta = Double.NaN;
+
+        // Make sure scaling factor is in a reasonable range
+
+        if(scaleFactor < 0) {
+            scaleFactor = Math.max(scaleFactor, -MAX_SCALE);
+            scale_increment = -512;
+            exp_delta = twoToTheDoubleScaleDown;
+        }
+        else {
+            scaleFactor = Math.min(scaleFactor, MAX_SCALE);
+            scale_increment = 512;
+            exp_delta = twoToTheDoubleScaleUp;
+        }
+
+        // Calculate (scaleFactor % +/-512), 512 = 2^9, using
+        // technique from "Hacker's Delight" section 10-2.
+        int t = (scaleFactor >> 9-1) >>> 32 - 9;
+        exp_adjust = ((scaleFactor + t) & (512 -1)) - t;
+
+        d *= powerOfTwoD(exp_adjust);
+        scaleFactor -= exp_adjust;
+
+        while(scaleFactor != 0) {
+            d *= exp_delta;
+            scaleFactor -= scale_increment;
+        }
+        return d;
+    }
+
+    /**
+     * Returns {@code f} &times;
+     * 2<sup>{@code scaleFactor}</sup> rounded as if performed
+     * by a single correctly rounded floating-point multiply to a
+     * member of the float value set.  See the Java
+     * Language Specification for a discussion of floating-point
+     * value sets.  If the exponent of the result is between {@link
+     * Float#MIN_EXPONENT} and {@link Float#MAX_EXPONENT}, the
+     * answer is calculated exactly.  If the exponent of the result
+     * would be larger than {@code Float.MAX_EXPONENT}, an
+     * infinity is returned.  Note that if the result is subnormal,
+     * precision may be lost; that is, when {@code scalb(x, n)}
+     * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal
+     * <i>x</i>.  When the result is non-NaN, the result has the same
+     * sign as {@code f}.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li> If the first argument is NaN, NaN is returned.
+     * <li> If the first argument is infinite, then an infinity of the
+     * same sign is returned.
+     * <li> If the first argument is zero, then a zero of the same
+     * sign is returned.
+     * </ul>
+     *
+     * @param f number to be scaled by a power of two.
+     * @param scaleFactor power of 2 used to scale {@code f}
+     * @return {@code f} &times; 2<sup>{@code scaleFactor}</sup>
+     * @since 1.6
+     */
+    public static float scalb(float f, int scaleFactor) {
+        // magnitude of a power of two so large that scaling a finite
+        // nonzero value by it would be guaranteed to over or
+        // underflow; due to rounding, scaling down takes takes an
+        // additional power of two which is reflected here
+        final int MAX_SCALE = FloatConsts.MAX_EXPONENT + -FloatConsts.MIN_EXPONENT +
+                              FloatConsts.SIGNIFICAND_WIDTH + 1;
+
+        // Make sure scaling factor is in a reasonable range
+        scaleFactor = Math.max(Math.min(scaleFactor, MAX_SCALE), -MAX_SCALE);
+
+        /*
+         * Since + MAX_SCALE for float fits well within the double
+         * exponent range and + float -> double conversion is exact
+         * the multiplication below will be exact. Therefore, the
+         * rounding that occurs when the double product is cast to
+         * float will be the correctly rounded float result.  Since
+         * all operations other than the final multiply will be exact,
+         * it is not necessary to declare this method strictfp.
+         */
+        return (float)((double)f*powerOfTwoD(scaleFactor));
+    }
+
+    // Constants used in scalb
+    static double twoToTheDoubleScaleUp = powerOfTwoD(512);
+    static double twoToTheDoubleScaleDown = powerOfTwoD(-512);
+
+    /**
+     * Returns a floating-point power of two in the normal range.
+     */
+    static double powerOfTwoD(int n) {
+        assert(n >= DoubleConsts.MIN_EXPONENT && n <= DoubleConsts.MAX_EXPONENT);
+        return Double.longBitsToDouble((((long)n + (long)DoubleConsts.EXP_BIAS) <<
+                                        (DoubleConsts.SIGNIFICAND_WIDTH-1))
+                                       & DoubleConsts.EXP_BIT_MASK);
+    }
+
+    /**
+     * Returns a floating-point power of two in the normal range.
+     */
+    static float powerOfTwoF(int n) {
+        assert(n >= FloatConsts.MIN_EXPONENT && n <= FloatConsts.MAX_EXPONENT);
+        return Float.intBitsToFloat(((n + FloatConsts.EXP_BIAS) <<
+                                     (FloatConsts.SIGNIFICAND_WIDTH-1))
+                                    & FloatConsts.EXP_BIT_MASK);
+    }
+}
diff --git a/java/lang/NegativeArraySizeException.java b/java/lang/NegativeArraySizeException.java
new file mode 100644
index 0000000..a90c815
--- /dev/null
+++ b/java/lang/NegativeArraySizeException.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if an application tries to create an array with negative size.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class NegativeArraySizeException extends RuntimeException {
+    private static final long serialVersionUID = -8960118058596991861L;
+
+    /**
+     * Constructs a <code>NegativeArraySizeException</code> with no
+     * detail message.
+     */
+    public NegativeArraySizeException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NegativeArraySizeException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public NegativeArraySizeException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/NoClassDefFoundError.java b/java/lang/NoClassDefFoundError.java
new file mode 100644
index 0000000..e4f764f
--- /dev/null
+++ b/java/lang/NoClassDefFoundError.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if the Java Virtual Machine or a <code>ClassLoader</code> instance
+ * tries to load in the definition of a class (as part of a normal method call
+ * or as part of creating a new instance using the <code>new</code> expression)
+ * and no definition of the class could be found.
+ * <p>
+ * The searched-for class definition existed when the currently
+ * executing class was compiled, but the definition can no longer be
+ * found.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class NoClassDefFoundError extends LinkageError {
+    private static final long serialVersionUID = 9095859863287012458L;
+
+    /**
+     * Constructs a <code>NoClassDefFoundError</code> with no detail message.
+     */
+    public NoClassDefFoundError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NoClassDefFoundError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public NoClassDefFoundError(String s) {
+        super(s);
+    }
+
+    // Android-added: A new constructor for use by the Android runtime.
+    /**
+     * Constructs a new {@code NoClassDefFoundError} with the current stack
+     * trace, the specified detail message and the specified cause. Used
+     * internally by the Android runtime.
+     *
+     * @param detailMessage
+     *            the detail message for this error.
+     * @param throwable
+     *            the cause of this error.
+     */
+    private NoClassDefFoundError(String detailMessage, Throwable throwable) {
+        super(detailMessage, throwable);
+    }
+}
diff --git a/java/lang/NoSuchFieldError.java b/java/lang/NoSuchFieldError.java
new file mode 100644
index 0000000..735adbb
--- /dev/null
+++ b/java/lang/NoSuchFieldError.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if an application tries to access or modify a specified
+ * field of an object, and that object no longer has that field.
+ * <p>
+ * Normally, this error is caught by the compiler; this error can
+ * only occur at run time if the definition of a class has
+ * incompatibly changed.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class NoSuchFieldError extends IncompatibleClassChangeError {
+    private static final long serialVersionUID = -3456430195886129035L;
+
+    /**
+     * Constructs a <code>NoSuchFieldError</code> with no detail message.
+     */
+    public NoSuchFieldError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NoSuchFieldError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public NoSuchFieldError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/NoSuchFieldException.java b/java/lang/NoSuchFieldException.java
new file mode 100644
index 0000000..0058264
--- /dev/null
+++ b/java/lang/NoSuchFieldException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Signals that the class doesn't have a field of a specified name.
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public class NoSuchFieldException extends ReflectiveOperationException {
+    private static final long serialVersionUID = -6143714805279938260L;
+
+    /**
+     * Constructor.
+     */
+    public NoSuchFieldException() {
+        super();
+    }
+
+    /**
+     * Constructor with a detail message.
+     *
+     * @param s the detail message
+     */
+    public NoSuchFieldException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/NoSuchMethodError.java b/java/lang/NoSuchMethodError.java
new file mode 100644
index 0000000..248de62
--- /dev/null
+++ b/java/lang/NoSuchMethodError.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if an application tries to call a specified method of a
+ * class (either static or instance), and that class no longer has a
+ * definition of that method.
+ * <p>
+ * Normally, this error is caught by the compiler; this error can
+ * only occur at run time if the definition of a class has
+ * incompatibly changed.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class NoSuchMethodError extends IncompatibleClassChangeError {
+    private static final long serialVersionUID = -3765521442372831335L;
+
+    /**
+     * Constructs a <code>NoSuchMethodError</code> with no detail message.
+     */
+    public NoSuchMethodError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NoSuchMethodError</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public NoSuchMethodError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/NoSuchMethodException.java b/java/lang/NoSuchMethodException.java
new file mode 100644
index 0000000..701437c
--- /dev/null
+++ b/java/lang/NoSuchMethodException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when a particular method cannot be found.
+ *
+ * @author     unascribed
+ * @since      JDK1.0
+ */
+public
+class NoSuchMethodException extends ReflectiveOperationException {
+    private static final long serialVersionUID = 5034388446362600923L;
+
+    /**
+     * Constructs a <code>NoSuchMethodException</code> without a detail message.
+     */
+    public NoSuchMethodException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NoSuchMethodException</code> with a detail message.
+     *
+     * @param      s   the detail message.
+     */
+    public NoSuchMethodException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/NullPointerException.java b/java/lang/NullPointerException.java
new file mode 100644
index 0000000..5b87ec4
--- /dev/null
+++ b/java/lang/NullPointerException.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application attempts to use {@code null} in a
+ * case where an object is required. These include:
+ * <ul>
+ * <li>Calling the instance method of a {@code null} object.
+ * <li>Accessing or modifying the field of a {@code null} object.
+ * <li>Taking the length of {@code null} as if it were an array.
+ * <li>Accessing or modifying the slots of {@code null} as if it
+ *     were an array.
+ * <li>Throwing {@code null} as if it were a {@code Throwable}
+ *     value.
+ * </ul>
+ * <p>
+ * Applications should throw instances of this class to indicate
+ * other illegal uses of the {@code null} object.
+ *
+ * {@code NullPointerException} objects may be constructed by the
+ * virtual machine as if {@linkplain Throwable#Throwable(String,
+ * Throwable, boolean, boolean) suppression were disabled and/or the
+ * stack trace was not writable}.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class NullPointerException extends RuntimeException {
+    private static final long serialVersionUID = 5162710183389028792L;
+
+    /**
+     * Constructs a {@code NullPointerException} with no detail message.
+     */
+    public NullPointerException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code NullPointerException} with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public NullPointerException(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/Number.java b/java/lang/Number.java
new file mode 100644
index 0000000..d901609
--- /dev/null
+++ b/java/lang/Number.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * The abstract class {@code Number} is the superclass of platform
+ * classes representing numeric values that are convertible to the
+ * primitive types {@code byte}, {@code double}, {@code float}, {@code
+ * int}, {@code long}, and {@code short}.
+ *
+ * The specific semantics of the conversion from the numeric value of
+ * a particular {@code Number} implementation to a given primitive
+ * type is defined by the {@code Number} implementation in question.
+ *
+ * For platform classes, the conversion is often analogous to a
+ * narrowing primitive conversion or a widening primitive conversion
+ * as defining in <cite>The Java&trade; Language Specification</cite>
+ * for converting between primitive types.  Therefore, conversions may
+ * lose information about the overall magnitude of a numeric value, may
+ * lose precision, and may even return a result of a different sign
+ * than the input.
+ *
+ * See the documentation of a given {@code Number} implementation for
+ * conversion details.
+ *
+ * @author      Lee Boynton
+ * @author      Arthur van Hoff
+ * @jls 5.1.2 Widening Primitive Conversions
+ * @jls 5.1.3 Narrowing Primitive Conversions
+ * @since   JDK1.0
+ */
+public abstract class Number implements java.io.Serializable {
+    /**
+     * Returns the value of the specified number as an {@code int},
+     * which may involve rounding or truncation.
+     *
+     * @return  the numeric value represented by this object after conversion
+     *          to type {@code int}.
+     */
+    public abstract int intValue();
+
+    /**
+     * Returns the value of the specified number as a {@code long},
+     * which may involve rounding or truncation.
+     *
+     * @return  the numeric value represented by this object after conversion
+     *          to type {@code long}.
+     */
+    public abstract long longValue();
+
+    /**
+     * Returns the value of the specified number as a {@code float},
+     * which may involve rounding.
+     *
+     * @return  the numeric value represented by this object after conversion
+     *          to type {@code float}.
+     */
+    public abstract float floatValue();
+
+    /**
+     * Returns the value of the specified number as a {@code double},
+     * which may involve rounding.
+     *
+     * @return  the numeric value represented by this object after conversion
+     *          to type {@code double}.
+     */
+    public abstract double doubleValue();
+
+    /**
+     * Returns the value of the specified number as a {@code byte},
+     * which may involve rounding or truncation.
+     *
+     * <p>This implementation returns the result of {@link #intValue} cast
+     * to a {@code byte}.
+     *
+     * @return  the numeric value represented by this object after conversion
+     *          to type {@code byte}.
+     * @since   JDK1.1
+     */
+    public byte byteValue() {
+        return (byte)intValue();
+    }
+
+    /**
+     * Returns the value of the specified number as a {@code short},
+     * which may involve rounding or truncation.
+     *
+     * <p>This implementation returns the result of {@link #intValue} cast
+     * to a {@code short}.
+     *
+     * @return  the numeric value represented by this object after conversion
+     *          to type {@code short}.
+     * @since   JDK1.1
+     */
+    public short shortValue() {
+        return (short)intValue();
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -8742448824652078965L;
+}
diff --git a/java/lang/NumberFormatException.java b/java/lang/NumberFormatException.java
new file mode 100644
index 0000000..ea1ec9f
--- /dev/null
+++ b/java/lang/NumberFormatException.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that the application has attempted to convert
+ * a string to one of the numeric types, but that the string does not
+ * have the appropriate format.
+ *
+ * @author  unascribed
+ * @see     java.lang.Integer#parseInt(String)
+ * @since   JDK1.0
+ */
+public
+class NumberFormatException extends IllegalArgumentException {
+    static final long serialVersionUID = -2848938806368998894L;
+
+    /**
+     * Constructs a <code>NumberFormatException</code> with no detail message.
+     */
+    public NumberFormatException () {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NumberFormatException</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public NumberFormatException (String s) {
+        super (s);
+    }
+
+    /**
+     * Factory method for making a <code>NumberFormatException</code>
+     * given the specified input which caused the error.
+     *
+     * @param   s   the input causing the error
+     */
+    static NumberFormatException forInputString(String s) {
+        return new NumberFormatException("For input string: \"" + s + "\"");
+    }
+}
diff --git a/java/lang/Object.annotated.java b/java/lang/Object.annotated.java
new file mode 100644
index 0000000..45939e8
--- /dev/null
+++ b/java/lang/Object.annotated.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Object {
+
+public Object() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.Class<?> getClass() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] protected java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public final native void notify();
+
+public final native void notifyAll();
+
+public final void wait(long timeout) throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public final native void wait(long timeout, int nanos) throws java.lang.InterruptedException;
+
+public final void wait() throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+protected void finalize() throws java.lang.Throwable { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/Object.java b/java/lang/Object.java
new file mode 100644
index 0000000..d307144
--- /dev/null
+++ b/java/lang/Object.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * Class {@code Object} is the root of the class hierarchy.
+ * Every class has {@code Object} as a superclass. All objects,
+ * including arrays, implement the methods of this class.
+ *
+ * @author  unascribed
+ * @see     java.lang.Class
+ * @since   JDK1.0
+ */
+public class Object {
+
+    // Android-removed: registerNatives() not used on Android
+    // private static native void registerNatives();
+    // static {
+    //     registerNatives();
+    // }
+
+    // Android-added: Use Android specific fields for Class and monitor.
+    private transient Class<?> shadow$_klass_;
+    private transient int shadow$_monitor_;
+
+    /**
+     * Returns the runtime class of this {@code Object}. The returned
+     * {@code Class} object is the object that is locked by {@code
+     * static synchronized} methods of the represented class.
+     *
+     * <p><b>The actual result type is {@code Class<? extends |X|>}
+     * where {@code |X|} is the erasure of the static type of the
+     * expression on which {@code getClass} is called.</b> For
+     * example, no cast is required in this code fragment:</p>
+     *
+     * <p>
+     * {@code Number n = 0;                             }<br>
+     * {@code Class<? extends Number> c = n.getClass(); }
+     * </p>
+     *
+     * @return The {@code Class} object that represents the runtime
+     *         class of this object.
+     * @jls 15.8.2 Class Literals
+     */
+    // Android-changed: Use Android specific fields for Class and monitor.
+    // public final native Class<?> getClass();
+    public final Class<?> getClass() {
+      return shadow$_klass_;
+    }
+
+    /**
+     * Returns a hash code value for the object. This method is
+     * supported for the benefit of hash tables such as those provided by
+     * {@link java.util.HashMap}.
+     * <p>
+     * The general contract of {@code hashCode} is:
+     * <ul>
+     * <li>Whenever it is invoked on the same object more than once during
+     *     an execution of a Java application, the {@code hashCode} method
+     *     must consistently return the same integer, provided no information
+     *     used in {@code equals} comparisons on the object is modified.
+     *     This integer need not remain consistent from one execution of an
+     *     application to another execution of the same application.
+     * <li>If two objects are equal according to the {@code equals(Object)}
+     *     method, then calling the {@code hashCode} method on each of
+     *     the two objects must produce the same integer result.
+     * <li>It is <em>not</em> required that if two objects are unequal
+     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
+     *     method, then calling the {@code hashCode} method on each of the
+     *     two objects must produce distinct integer results.  However, the
+     *     programmer should be aware that producing distinct integer results
+     *     for unequal objects may improve the performance of hash tables.
+     * </ul>
+     * <p>
+     * As much as is reasonably practical, the hashCode method defined by
+     * class {@code Object} does return distinct integers for distinct
+     * objects. (This is typically implemented by converting the internal
+     * address of the object into an integer, but this implementation
+     * technique is not required by the
+     * Java&trade; programming language.)
+     *
+     * @return  a hash code value for this object.
+     * @see     java.lang.Object#equals(java.lang.Object)
+     * @see     java.lang.System#identityHashCode
+     */
+    // BEGIN Android-changed: Added a local helper for identityHashCode.
+    // public native int hashCode();
+    public int hashCode() {
+        return identityHashCode(this);
+    }
+
+    // Package-private to be used by j.l.System. We do the implementation here
+    // to avoid Object.hashCode doing a clinit check on j.l.System, and also
+    // to avoid leaking shadow$_monitor_ outside of this class.
+    /* package-private */ static int identityHashCode(Object obj) {
+        int lockWord = obj.shadow$_monitor_;
+        final int lockWordStateMask = 0xC0000000;  // Top 2 bits.
+        final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).
+        final int lockWordHashMask = 0x0FFFFFFF;  // Low 28 bits.
+        if ((lockWord & lockWordStateMask) == lockWordStateHash) {
+            return lockWord & lockWordHashMask;
+        }
+        return identityHashCodeNative(obj);
+    }
+
+    /**
+     * Return the identity hash code when the information in the monitor field
+     * is not sufficient.
+     */
+    @FastNative
+    private static native int identityHashCodeNative(Object obj);
+    // END Android-changed: Added a local helper for identityHashCode.
+
+    /**
+     * Indicates whether some other object is "equal to" this one.
+     * <p>
+     * The {@code equals} method implements an equivalence relation
+     * on non-null object references:
+     * <ul>
+     * <li>It is <i>reflexive</i>: for any non-null reference value
+     *     {@code x}, {@code x.equals(x)} should return
+     *     {@code true}.
+     * <li>It is <i>symmetric</i>: for any non-null reference values
+     *     {@code x} and {@code y}, {@code x.equals(y)}
+     *     should return {@code true} if and only if
+     *     {@code y.equals(x)} returns {@code true}.
+     * <li>It is <i>transitive</i>: for any non-null reference values
+     *     {@code x}, {@code y}, and {@code z}, if
+     *     {@code x.equals(y)} returns {@code true} and
+     *     {@code y.equals(z)} returns {@code true}, then
+     *     {@code x.equals(z)} should return {@code true}.
+     * <li>It is <i>consistent</i>: for any non-null reference values
+     *     {@code x} and {@code y}, multiple invocations of
+     *     {@code x.equals(y)} consistently return {@code true}
+     *     or consistently return {@code false}, provided no
+     *     information used in {@code equals} comparisons on the
+     *     objects is modified.
+     * <li>For any non-null reference value {@code x},
+     *     {@code x.equals(null)} should return {@code false}.
+     * </ul>
+     * <p>
+     * The {@code equals} method for class {@code Object} implements
+     * the most discriminating possible equivalence relation on objects;
+     * that is, for any non-null reference values {@code x} and
+     * {@code y}, this method returns {@code true} if and only
+     * if {@code x} and {@code y} refer to the same object
+     * ({@code x == y} has the value {@code true}).
+     * <p>
+     * Note that it is generally necessary to override the {@code hashCode}
+     * method whenever this method is overridden, so as to maintain the
+     * general contract for the {@code hashCode} method, which states
+     * that equal objects must have equal hash codes.
+     *
+     * @param   obj   the reference object with which to compare.
+     * @return  {@code true} if this object is the same as the obj
+     *          argument; {@code false} otherwise.
+     * @see     #hashCode()
+     * @see     java.util.HashMap
+     */
+    public boolean equals(Object obj) {
+        return (this == obj);
+    }
+
+    /**
+     * Creates and returns a copy of this object.  The precise meaning
+     * of "copy" may depend on the class of the object. The general
+     * intent is that, for any object {@code x}, the expression:
+     * <blockquote>
+     * <pre>
+     * x.clone() != x</pre></blockquote>
+     * will be true, and that the expression:
+     * <blockquote>
+     * <pre>
+     * x.clone().getClass() == x.getClass()</pre></blockquote>
+     * will be {@code true}, but these are not absolute requirements.
+     * While it is typically the case that:
+     * <blockquote>
+     * <pre>
+     * x.clone().equals(x)</pre></blockquote>
+     * will be {@code true}, this is not an absolute requirement.
+     * <p>
+     * By convention, the returned object should be obtained by calling
+     * {@code super.clone}.  If a class and all of its superclasses (except
+     * {@code Object}) obey this convention, it will be the case that
+     * {@code x.clone().getClass() == x.getClass()}.
+     * <p>
+     * By convention, the object returned by this method should be independent
+     * of this object (which is being cloned).  To achieve this independence,
+     * it may be necessary to modify one or more fields of the object returned
+     * by {@code super.clone} before returning it.  Typically, this means
+     * copying any mutable objects that comprise the internal "deep structure"
+     * of the object being cloned and replacing the references to these
+     * objects with references to the copies.  If a class contains only
+     * primitive fields or references to immutable objects, then it is usually
+     * the case that no fields in the object returned by {@code super.clone}
+     * need to be modified.
+     * <p>
+     * The method {@code clone} for class {@code Object} performs a
+     * specific cloning operation. First, if the class of this object does
+     * not implement the interface {@code Cloneable}, then a
+     * {@code CloneNotSupportedException} is thrown. Note that all arrays
+     * are considered to implement the interface {@code Cloneable} and that
+     * the return type of the {@code clone} method of an array type {@code T[]}
+     * is {@code T[]} where T is any reference or primitive type.
+     * Otherwise, this method creates a new instance of the class of this
+     * object and initializes all its fields with exactly the contents of
+     * the corresponding fields of this object, as if by assignment; the
+     * contents of the fields are not themselves cloned. Thus, this method
+     * performs a "shallow copy" of this object, not a "deep copy" operation.
+     * <p>
+     * The class {@code Object} does not itself implement the interface
+     * {@code Cloneable}, so calling the {@code clone} method on an object
+     * whose class is {@code Object} will result in throwing an
+     * exception at run time.
+     *
+     * @return     a clone of this instance.
+     * @throws  CloneNotSupportedException  if the object's class does not
+     *               support the {@code Cloneable} interface. Subclasses
+     *               that override the {@code clone} method can also
+     *               throw this exception to indicate that an instance cannot
+     *               be cloned.
+     * @see java.lang.Cloneable
+     */
+    // BEGIN Android-changed: Use native local helper for clone()
+    // Checks whether cloning is allowed before calling native local helper.
+    // protected native Object clone() throws CloneNotSupportedException;
+    protected Object clone() throws CloneNotSupportedException {
+        if (!(this instanceof Cloneable)) {
+            throw new CloneNotSupportedException("Class " + getClass().getName() +
+                                                 " doesn't implement Cloneable");
+        }
+
+        return internalClone();
+    }
+
+    /*
+     * Native helper method for cloning.
+     */
+    @FastNative
+    private native Object internalClone();
+    // END Android-changed: Use native local helper for clone()
+
+    /**
+     * Returns a string representation of the object. In general, the
+     * {@code toString} method returns a string that
+     * "textually represents" this object. The result should
+     * be a concise but informative representation that is easy for a
+     * person to read.
+     * It is recommended that all subclasses override this method.
+     * <p>
+     * The {@code toString} method for class {@code Object}
+     * returns a string consisting of the name of the class of which the
+     * object is an instance, the at-sign character `{@code @}', and
+     * the unsigned hexadecimal representation of the hash code of the
+     * object. In other words, this method returns a string equal to the
+     * value of:
+     * <blockquote>
+     * <pre>
+     * getClass().getName() + '@' + Integer.toHexString(hashCode())
+     * </pre></blockquote>
+     *
+     * @return  a string representation of the object.
+     */
+    public String toString() {
+        return getClass().getName() + "@" + Integer.toHexString(hashCode());
+    }
+
+    /**
+     * Wakes up a single thread that is waiting on this object's
+     * monitor. If any threads are waiting on this object, one of them
+     * is chosen to be awakened. The choice is arbitrary and occurs at
+     * the discretion of the implementation. A thread waits on an object's
+     * monitor by calling one of the {@code wait} methods.
+     * <p>
+     * The awakened thread will not be able to proceed until the current
+     * thread relinquishes the lock on this object. The awakened thread will
+     * compete in the usual manner with any other threads that might be
+     * actively competing to synchronize on this object; for example, the
+     * awakened thread enjoys no reliable privilege or disadvantage in being
+     * the next thread to lock this object.
+     * <p>
+     * This method should only be called by a thread that is the owner
+     * of this object's monitor. A thread becomes the owner of the
+     * object's monitor in one of three ways:
+     * <ul>
+     * <li>By executing a synchronized instance method of that object.
+     * <li>By executing the body of a {@code synchronized} statement
+     *     that synchronizes on the object.
+     * <li>For objects of type {@code Class,} by executing a
+     *     synchronized static method of that class.
+     * </ul>
+     * <p>
+     * Only one thread at a time can own an object's monitor.
+     *
+     * @throws  IllegalMonitorStateException  if the current thread is not
+     *               the owner of this object's monitor.
+     * @see        java.lang.Object#notifyAll()
+     * @see        java.lang.Object#wait()
+     */
+    @FastNative
+    public final native void notify();
+
+    /**
+     * Wakes up all threads that are waiting on this object's monitor. A
+     * thread waits on an object's monitor by calling one of the
+     * {@code wait} methods.
+     * <p>
+     * The awakened threads will not be able to proceed until the current
+     * thread relinquishes the lock on this object. The awakened threads
+     * will compete in the usual manner with any other threads that might
+     * be actively competing to synchronize on this object; for example,
+     * the awakened threads enjoy no reliable privilege or disadvantage in
+     * being the next thread to lock this object.
+     * <p>
+     * This method should only be called by a thread that is the owner
+     * of this object's monitor. See the {@code notify} method for a
+     * description of the ways in which a thread can become the owner of
+     * a monitor.
+     *
+     * @throws  IllegalMonitorStateException  if the current thread is not
+     *               the owner of this object's monitor.
+     * @see        java.lang.Object#notify()
+     * @see        java.lang.Object#wait()
+     */
+    @FastNative
+    public final native void notifyAll();
+
+    /**
+     * Causes the current thread to wait until either another thread invokes the
+     * {@link java.lang.Object#notify()} method or the
+     * {@link java.lang.Object#notifyAll()} method for this object, or a
+     * specified amount of time has elapsed.
+     * <p>
+     * The current thread must own this object's monitor.
+     * <p>
+     * This method causes the current thread (call it <var>T</var>) to
+     * place itself in the wait set for this object and then to relinquish
+     * any and all synchronization claims on this object. Thread <var>T</var>
+     * becomes disabled for thread scheduling purposes and lies dormant
+     * until one of four things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@code notify} method for this
+     * object and thread <var>T</var> happens to be arbitrarily chosen as
+     * the thread to be awakened.
+     * <li>Some other thread invokes the {@code notifyAll} method for this
+     * object.
+     * <li>Some other thread {@linkplain Thread#interrupt() interrupts}
+     * thread <var>T</var>.
+     * <li>The specified amount of real time has elapsed, more or less.  If
+     * {@code timeout} is zero, however, then real time is not taken into
+     * consideration and the thread simply waits until notified.
+     * </ul>
+     * The thread <var>T</var> is then removed from the wait set for this
+     * object and re-enabled for thread scheduling. It then competes in the
+     * usual manner with other threads for the right to synchronize on the
+     * object; once it has gained control of the object, all its
+     * synchronization claims on the object are restored to the status quo
+     * ante - that is, to the situation as of the time that the {@code wait}
+     * method was invoked. Thread <var>T</var> then returns from the
+     * invocation of the {@code wait} method. Thus, on return from the
+     * {@code wait} method, the synchronization state of the object and of
+     * thread {@code T} is exactly as it was when the {@code wait} method
+     * was invoked.
+     * <p>
+     * A thread can also wake up without being notified, interrupted, or
+     * timing out, a so-called <i>spurious wakeup</i>.  While this will rarely
+     * occur in practice, applications must guard against it by testing for
+     * the condition that should have caused the thread to be awakened, and
+     * continuing to wait if the condition is not satisfied.  In other words,
+     * waits should always occur in loops, like this one:
+     * <pre>
+     *     synchronized (obj) {
+     *         while (&lt;condition does not hold&gt;)
+     *             obj.wait(timeout);
+     *         ... // Perform action appropriate to condition
+     *     }
+     * </pre>
+     * (For more information on this topic, see Section 3.2.3 in Doug Lea's
+     * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
+     * 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
+     * Language Guide" (Addison-Wesley, 2001).
+     *
+     * <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
+     * interrupted} by any thread before or while it is waiting, then an
+     * {@code InterruptedException} is thrown.  This exception is not
+     * thrown until the lock status of this object has been restored as
+     * described above.
+     *
+     * <p>
+     * Note that the {@code wait} method, as it places the current thread
+     * into the wait set for this object, unlocks only this object; any
+     * other objects on which the current thread may be synchronized remain
+     * locked while the thread waits.
+     * <p>
+     * This method should only be called by a thread that is the owner
+     * of this object's monitor. See the {@code notify} method for a
+     * description of the ways in which a thread can become the owner of
+     * a monitor.
+     *
+     * @param      timeout   the maximum time to wait in milliseconds.
+     * @throws  IllegalArgumentException      if the value of timeout is
+     *               negative.
+     * @throws  IllegalMonitorStateException  if the current thread is not
+     *               the owner of the object's monitor.
+     * @throws  InterruptedException if any thread interrupted the
+     *             current thread before or while the current thread
+     *             was waiting for a notification.  The <i>interrupted
+     *             status</i> of the current thread is cleared when
+     *             this exception is thrown.
+     * @see        java.lang.Object#notify()
+     * @see        java.lang.Object#notifyAll()
+     */
+    // Android-changed: Implement wait(long) non-natively.
+    // public final native void wait(long timeout) throws InterruptedException;
+    public final void wait(long timeout) throws InterruptedException {
+        wait(timeout, 0);
+    }
+
+    /**
+     * Causes the current thread to wait until another thread invokes the
+     * {@link java.lang.Object#notify()} method or the
+     * {@link java.lang.Object#notifyAll()} method for this object, or
+     * some other thread interrupts the current thread, or a certain
+     * amount of real time has elapsed.
+     * <p>
+     * This method is similar to the {@code wait} method of one
+     * argument, but it allows finer control over the amount of time to
+     * wait for a notification before giving up. The amount of real time,
+     * measured in nanoseconds, is given by:
+     * <blockquote>
+     * <pre>
+     * 1000000*timeout+nanos</pre></blockquote>
+     * <p>
+     * In all other respects, this method does the same thing as the
+     * method {@link #wait(long)} of one argument. In particular,
+     * {@code wait(0, 0)} means the same thing as {@code wait(0)}.
+     * <p>
+     * The current thread must own this object's monitor. The thread
+     * releases ownership of this monitor and waits until either of the
+     * following two conditions has occurred:
+     * <ul>
+     * <li>Another thread notifies threads waiting on this object's monitor
+     *     to wake up either through a call to the {@code notify} method
+     *     or the {@code notifyAll} method.
+     * <li>The timeout period, specified by {@code timeout}
+     *     milliseconds plus {@code nanos} nanoseconds arguments, has
+     *     elapsed.
+     * </ul>
+     * <p>
+     * The thread then waits until it can re-obtain ownership of the
+     * monitor and resumes execution.
+     * <p>
+     * As in the one argument version, interrupts and spurious wakeups are
+     * possible, and this method should always be used in a loop:
+     * <pre>
+     *     synchronized (obj) {
+     *         while (&lt;condition does not hold&gt;)
+     *             obj.wait(timeout, nanos);
+     *         ... // Perform action appropriate to condition
+     *     }
+     * </pre>
+     * This method should only be called by a thread that is the owner
+     * of this object's monitor. See the {@code notify} method for a
+     * description of the ways in which a thread can become the owner of
+     * a monitor.
+     *
+     * @param      timeout   the maximum time to wait in milliseconds.
+     * @param      nanos      additional time, in nanoseconds range
+     *                       0-999999.
+     * @throws  IllegalArgumentException      if the value of timeout is
+     *                      negative or the value of nanos is
+     *                      not in the range 0-999999.
+     * @throws  IllegalMonitorStateException  if the current thread is not
+     *               the owner of this object's monitor.
+     * @throws  InterruptedException if any thread interrupted the
+     *             current thread before or while the current thread
+     *             was waiting for a notification.  The <i>interrupted
+     *             status</i> of the current thread is cleared when
+     *             this exception is thrown.
+     */
+    // Android-changed: Implement wait(long, int) natively.
+    /*
+    public final void wait(long timeout, int nanos) throws InterruptedException {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout value is negative");
+        }
+
+        if (nanos < 0 || nanos > 999999) {
+            throw new IllegalArgumentException(
+                                "nanosecond timeout value out of range");
+        }
+
+        if (nanos > 0) {
+            timeout++;
+        }
+
+        wait(timeout);
+    }
+    */
+    @FastNative
+    public final native void wait(long timeout, int nanos) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until another thread invokes the
+     * {@link java.lang.Object#notify()} method or the
+     * {@link java.lang.Object#notifyAll()} method for this object.
+     * In other words, this method behaves exactly as if it simply
+     * performs the call {@code wait(0)}.
+     * <p>
+     * The current thread must own this object's monitor. The thread
+     * releases ownership of this monitor and waits until another thread
+     * notifies threads waiting on this object's monitor to wake up
+     * either through a call to the {@code notify} method or the
+     * {@code notifyAll} method. The thread then waits until it can
+     * re-obtain ownership of the monitor and resumes execution.
+     * <p>
+     * As in the one argument version, interrupts and spurious wakeups are
+     * possible, and this method should always be used in a loop:
+     * <pre>
+     *     synchronized (obj) {
+     *         while (&lt;condition does not hold&gt;)
+     *             obj.wait();
+     *         ... // Perform action appropriate to condition
+     *     }
+     * </pre>
+     * This method should only be called by a thread that is the owner
+     * of this object's monitor. See the {@code notify} method for a
+     * description of the ways in which a thread can become the owner of
+     * a monitor.
+     *
+     * @throws  IllegalMonitorStateException  if the current thread is not
+     *               the owner of the object's monitor.
+     * @throws  InterruptedException if any thread interrupted the
+     *             current thread before or while the current thread
+     *             was waiting for a notification.  The <i>interrupted
+     *             status</i> of the current thread is cleared when
+     *             this exception is thrown.
+     * @see        java.lang.Object#notify()
+     * @see        java.lang.Object#notifyAll()
+     */
+    public final void wait() throws InterruptedException {
+        wait(0);
+    }
+
+    /**
+     * Called by the garbage collector on an object when garbage collection
+     * determines that there are no more references to the object.
+     * A subclass overrides the {@code finalize} method to dispose of
+     * system resources or to perform other cleanup.
+     * <p>
+     * The general contract of {@code finalize} is that it is invoked
+     * if and when the Java&trade; virtual
+     * machine has determined that there is no longer any
+     * means by which this object can be accessed by any thread that has
+     * not yet died, except as a result of an action taken by the
+     * finalization of some other object or class which is ready to be
+     * finalized. The {@code finalize} method may take any action, including
+     * making this object available again to other threads; the usual purpose
+     * of {@code finalize}, however, is to perform cleanup actions before
+     * the object is irrevocably discarded. For example, the finalize method
+     * for an object that represents an input/output connection might perform
+     * explicit I/O transactions to break the connection before the object is
+     * permanently discarded.
+     * <p>
+     * The {@code finalize} method of class {@code Object} performs no
+     * special action; it simply returns normally. Subclasses of
+     * {@code Object} may override this definition.
+     * <p>
+     * The Java programming language does not guarantee which thread will
+     * invoke the {@code finalize} method for any given object. It is
+     * guaranteed, however, that the thread that invokes finalize will not
+     * be holding any user-visible synchronization locks when finalize is
+     * invoked. If an uncaught exception is thrown by the finalize method,
+     * the exception is ignored and finalization of that object terminates.
+     * <p>
+     * After the {@code finalize} method has been invoked for an object, no
+     * further action is taken until the Java virtual machine has again
+     * determined that there is no longer any means by which this object can
+     * be accessed by any thread that has not yet died, including possible
+     * actions by other objects or classes which are ready to be finalized,
+     * at which point the object may be discarded.
+     * <p>
+     * The {@code finalize} method is never invoked more than once by a Java
+     * virtual machine for any given object.
+     * <p>
+     * Any exception thrown by the {@code finalize} method causes
+     * the finalization of this object to be halted, but is otherwise
+     * ignored.
+     *
+     * @throws Throwable the {@code Exception} raised by this method
+     * @see java.lang.ref.WeakReference
+     * @see java.lang.ref.PhantomReference
+     * @jls 12.6 Finalization of Class Instances
+     */
+    protected void finalize() throws Throwable { }
+}
diff --git a/java/lang/OutOfMemoryError.java b/java/lang/OutOfMemoryError.java
new file mode 100644
index 0000000..0f9df4e
--- /dev/null
+++ b/java/lang/OutOfMemoryError.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when the Java Virtual Machine cannot allocate an object
+ * because it is out of memory, and no more memory could be made
+ * available by the garbage collector.
+ *
+ * {@code OutOfMemoryError} objects may be constructed by the virtual
+ * machine as if {@linkplain Throwable#Throwable(String, Throwable,
+ * boolean, boolean) suppression were disabled and/or the stack trace was not
+ * writable}.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public class OutOfMemoryError extends VirtualMachineError {
+    private static final long serialVersionUID = 8228564086184010517L;
+
+    /**
+     * Constructs an {@code OutOfMemoryError} with no detail message.
+     */
+    public OutOfMemoryError() {
+        super();
+    }
+
+    /**
+     * Constructs an {@code OutOfMemoryError} with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public OutOfMemoryError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/Override.java b/java/lang/Override.java
new file mode 100644
index 0000000..bf77344
--- /dev/null
+++ b/java/lang/Override.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.*;
+
+/**
+ * Indicates that a method declaration is intended to override a
+ * method declaration in a supertype. If a method is annotated with
+ * this annotation type compilers are required to generate an error
+ * message unless at least one of the following conditions hold:
+ *
+ * <ul><li>
+ * The method does override or implement a method declared in a
+ * supertype.
+ * </li><li>
+ * The method has a signature that is override-equivalent to that of
+ * any public method declared in {@linkplain Object}.
+ * </li></ul>
+ *
+ * @author  Peter von der Ah&eacute;
+ * @author  Joshua Bloch
+ * @jls 9.6.1.4 @Override
+ * @since 1.5
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Override {
+}
diff --git a/java/lang/Package.java b/java/lang/Package.java
new file mode 100644
index 0000000..b6a37fd
--- /dev/null
+++ b/java/lang/Package.java
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.reflect.AnnotatedElement;
+import java.io.InputStream;
+import java.util.Enumeration;
+
+import java.util.StringTokenizer;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.net.MalformedURLException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import sun.net.www.ParseUtil;
+import sun.reflect.CallerSensitive;
+import dalvik.system.VMRuntime;
+import sun.reflect.Reflection;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * {@code Package} objects contain version information
+ * about the implementation and specification of a Java package.
+ * This versioning information is retrieved and made available
+ * by the {@link ClassLoader} instance that
+ * loaded the class(es).  Typically, it is stored in the manifest that is
+ * distributed with the classes.
+ *
+ * <p>The set of classes that make up the package may implement a
+ * particular specification and if so the specification title, version number,
+ * and vendor strings identify that specification.
+ * An application can ask if the package is
+ * compatible with a particular version, see the {@link
+ * #isCompatibleWith isCompatibleWith}
+ * method for details.
+ *
+ * <p>Specification version numbers use a syntax that consists of nonnegative
+ * decimal integers separated by periods ".", for example "2.0" or
+ * "1.2.3.4.5.6.7".  This allows an extensible number to be used to represent
+ * major, minor, micro, etc. versions.  The version specification is described
+ * by the following formal grammar:
+ * <blockquote>
+ * <dl>
+ * <dt><i>SpecificationVersion:</i>
+ * <dd><i>Digits RefinedVersion<sub>opt</sub></i>
+
+ * <dt><i>RefinedVersion:</i>
+ * <dd>{@code .} <i>Digits</i>
+ * <dd>{@code .} <i>Digits RefinedVersion</i>
+ *
+ * <dt><i>Digits:</i>
+ * <dd><i>Digit</i>
+ * <dd><i>Digits</i>
+ *
+ * <dt><i>Digit:</i>
+ * <dd>any character for which {@link Character#isDigit} returns {@code true},
+ * e.g. 0, 1, 2, ...
+ * </dl>
+ * </blockquote>
+ *
+ * <p>The implementation title, version, and vendor strings identify an
+ * implementation and are made available conveniently to enable accurate
+ * reporting of the packages involved when a problem occurs. The contents
+ * all three implementation strings are vendor specific. The
+ * implementation version strings have no specified syntax and should
+ * only be compared for equality with desired version identifiers.
+ *
+ * <p>Within each {@code ClassLoader} instance all classes from the same
+ * java package have the same Package object.  The static methods allow a package
+ * to be found by name or the set of all packages known to the current class
+ * loader to be found.
+ *
+ * @see ClassLoader#definePackage
+ */
+public class Package implements java.lang.reflect.AnnotatedElement {
+    /**
+     * Return the name of this package.
+     *
+     * @return  The fully-qualified name of this package as defined in section 6.5.3 of
+     *          <cite>The Java&trade; Language Specification</cite>,
+     *          for example, {@code java.lang}
+     */
+    public String getName() {
+        return pkgName;
+    }
+
+
+    /**
+     * Return the title of the specification that this package implements.
+     * @return the specification title, null is returned if it is not known.
+     */
+    public String getSpecificationTitle() {
+        return specTitle;
+    }
+
+    /**
+     * Returns the version number of the specification
+     * that this package implements.
+     * This version string must be a sequence of nonnegative decimal
+     * integers separated by "."'s and may have leading zeros.
+     * When version strings are compared the most significant
+     * numbers are compared.
+     * @return the specification version, null is returned if it is not known.
+     */
+    public String getSpecificationVersion() {
+        return specVersion;
+    }
+
+    /**
+     * Return the name of the organization, vendor,
+     * or company that owns and maintains the specification
+     * of the classes that implement this package.
+     * @return the specification vendor, null is returned if it is not known.
+     */
+    public String getSpecificationVendor() {
+        return specVendor;
+    }
+
+    /**
+     * Return the title of this package.
+     * @return the title of the implementation, null is returned if it is not known.
+     */
+    public String getImplementationTitle() {
+        return implTitle;
+    }
+
+    /**
+     * Return the version of this implementation. It consists of any string
+     * assigned by the vendor of this implementation and does
+     * not have any particular syntax specified or expected by the Java
+     * runtime. It may be compared for equality with other
+     * package version strings used for this implementation
+     * by this vendor for this package.
+     * @return the version of the implementation, null is returned if it is not known.
+     */
+    public String getImplementationVersion() {
+        return implVersion;
+    }
+
+    /**
+     * Returns the name of the organization,
+     * vendor or company that provided this implementation.
+     * @return the vendor that implemented this package..
+     */
+    public String getImplementationVendor() {
+        return implVendor;
+    }
+
+    /**
+     * Returns true if this package is sealed.
+     *
+     * @return true if the package is sealed, false otherwise
+     */
+    public boolean isSealed() {
+        return sealBase != null;
+    }
+
+    /**
+     * Returns true if this package is sealed with respect to the specified
+     * code source url.
+     *
+     * @param url the code source url
+     * @return true if this package is sealed with respect to url
+     */
+    public boolean isSealed(URL url) {
+        return url.equals(sealBase);
+    }
+
+    /**
+     * Compare this package's specification version with a
+     * desired version. It returns true if
+     * this packages specification version number is greater than or equal
+     * to the desired version number. <p>
+     *
+     * Version numbers are compared by sequentially comparing corresponding
+     * components of the desired and specification strings.
+     * Each component is converted as a decimal integer and the values
+     * compared.
+     * If the specification value is greater than the desired
+     * value true is returned. If the value is less false is returned.
+     * If the values are equal the period is skipped and the next pair of
+     * components is compared.
+     *
+     * @param desired the version string of the desired version.
+     * @return true if this package's version number is greater
+     *          than or equal to the desired version number
+     *
+     * @exception NumberFormatException if the desired or current version
+     *          is not of the correct dotted form.
+     */
+    public boolean isCompatibleWith(String desired)
+        throws NumberFormatException
+    {
+        if (specVersion == null || specVersion.length() < 1) {
+            throw new NumberFormatException("Empty version string");
+        }
+
+        String [] sa = specVersion.split("\\.", -1);
+        int [] si = new int[sa.length];
+        for (int i = 0; i < sa.length; i++) {
+            si[i] = Integer.parseInt(sa[i]);
+            if (si[i] < 0)
+                throw NumberFormatException.forInputString("" + si[i]);
+        }
+
+        String [] da = desired.split("\\.", -1);
+        int [] di = new int[da.length];
+        for (int i = 0; i < da.length; i++) {
+            di[i] = Integer.parseInt(da[i]);
+            if (di[i] < 0)
+                throw NumberFormatException.forInputString("" + di[i]);
+        }
+
+        int len = Math.max(di.length, si.length);
+        for (int i = 0; i < len; i++) {
+            int d = (i < di.length ? di[i] : 0);
+            int s = (i < si.length ? si[i] : 0);
+            if (s < d)
+                return false;
+            if (s > d)
+                return true;
+        }
+        return true;
+    }
+
+    /**
+     * Find a package by name in the callers {@code ClassLoader} instance.
+     * The callers {@code ClassLoader} instance is used to find the package
+     * instance corresponding to the named class. If the callers
+     * {@code ClassLoader} instance is null then the set of packages loaded
+     * by the system {@code ClassLoader} instance is searched to find the
+     * named package. <p>
+     *
+     * Packages have attributes for versions and specifications only if the class
+     * loader created the package instance with the appropriate attributes. Typically,
+     * those attributes are defined in the manifests that accompany the classes.
+     *
+     * @param name a package name, for example, java.lang.
+     * @return the package of the requested name. It may be null if no package
+     *          information is available from the archive or codebase.
+     */
+    @CallerSensitive
+    public static Package getPackage(String name) {
+        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
+        if (l != null) {
+            return l.getPackage(name);
+        } else {
+            return getSystemPackage(name);
+        }
+    }
+
+    /**
+     * Get all the packages currently known for the caller's {@code ClassLoader}
+     * instance.  Those packages correspond to classes loaded via or accessible by
+     * name to that {@code ClassLoader} instance.  If the caller's
+     * {@code ClassLoader} instance is the bootstrap {@code ClassLoader}
+     * instance, which may be represented by {@code null} in some implementations,
+     * only packages corresponding to classes loaded by the bootstrap
+     * {@code ClassLoader} instance will be returned.
+     *
+     * @return a new array of packages known to the callers {@code ClassLoader}
+     * instance.  An zero length array is returned if none are known.
+     */
+    @CallerSensitive
+    public static Package[] getPackages() {
+        ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass());
+        if (l != null) {
+            return l.getPackages();
+        } else {
+            return getSystemPackages();
+        }
+    }
+
+    /**
+     * Get the package for the specified class.
+     * The class's class loader is used to find the package instance
+     * corresponding to the specified class. If the class loader
+     * is the bootstrap class loader, which may be represented by
+     * {@code null} in some implementations, then the set of packages
+     * loaded by the bootstrap class loader is searched to find the package.
+     * <p>
+     * Packages have attributes for versions and specifications only
+     * if the class loader created the package
+     * instance with the appropriate attributes. Typically those
+     * attributes are defined in the manifests that accompany
+     * the classes.
+     *
+     * @param c the class to get the package of.
+     * @return the package of the class. It may be null if no package
+     *          information is available from the archive or codebase.  */
+    static Package getPackage(Class<?> c) {
+        String name = c.getName();
+        int i = name.lastIndexOf('.');
+        if (i != -1) {
+            name = name.substring(0, i);
+            ClassLoader cl = c.getClassLoader();
+            if (cl != null) {
+                return cl.getPackage(name);
+            } else {
+                return getSystemPackage(name);
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Return the hash code computed from the package name.
+     * @return the hash code computed from the package name.
+     */
+    public int hashCode(){
+        return pkgName.hashCode();
+    }
+
+    /**
+     * Returns the string representation of this Package.
+     * Its value is the string "package " and the package name.
+     * If the package title is defined it is appended.
+     * If the package version is defined it is appended.
+     * @return the string representation of the package.
+     */
+    public String toString() {
+        // BEGIN Android-added: Backwards compatibility fix for target API <= 24.
+        // Several apps try to parse the output of toString(). This is a really
+        // bad idea - especially when there's a Package.getName() function as well as a
+        // Class.getName() function that can be used instead.
+        // Starting from the API level 25 the proper output is generated.
+        final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+            return "package " + pkgName;
+        }
+        // END Android-added: Backwards compatibility fix for target API <= 24.
+
+        String spec = specTitle;
+        String ver =  specVersion;
+        if (spec != null && spec.length() > 0)
+            spec = ", " + spec;
+        else
+            spec = "";
+        if (ver != null && ver.length() > 0)
+            ver = ", version " + ver;
+        else
+            ver = "";
+        return "package " + pkgName + spec + ver;
+    }
+
+    private Class<?> getPackageInfo() {
+        if (packageInfo == null) {
+            try {
+                packageInfo = Class.forName(pkgName + ".package-info", false, loader);
+            } catch (ClassNotFoundException ex) {
+                // store a proxy for the package info that has no annotations
+                class PackageInfoProxy {}
+                packageInfo = PackageInfoProxy.class;
+            }
+        }
+        return packageInfo;
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
+        return getPackageInfo().getAnnotation(annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+        return AnnotatedElement.super.isAnnotationPresent(annotationClass);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public  <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) {
+        return getPackageInfo().getAnnotationsByType(annotationClass);
+    }
+
+    /**
+     * @since 1.5
+     */
+    public Annotation[] getAnnotations() {
+        return getPackageInfo().getAnnotations();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
+        return getPackageInfo().getDeclaredAnnotation(annotationClass);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) {
+        return getPackageInfo().getDeclaredAnnotationsByType(annotationClass);
+    }
+
+    /**
+     * @since 1.5
+     */
+    public Annotation[] getDeclaredAnnotations()  {
+        return getPackageInfo().getDeclaredAnnotations();
+    }
+
+    /**
+     * Construct a package instance with the specified version
+     * information.
+     * @param name the name of the package
+     * @param spectitle the title of the specification
+     * @param specversion the version of the specification
+     * @param specvendor the organization that maintains the specification
+     * @param impltitle the title of the implementation
+     * @param implversion the version of the implementation
+     * @param implvendor the organization that maintains the implementation
+     */
+    Package(String name,
+            String spectitle, String specversion, String specvendor,
+            String impltitle, String implversion, String implvendor,
+            URL sealbase, ClassLoader loader)
+    {
+        pkgName = name;
+        implTitle = impltitle;
+        implVersion = implversion;
+        implVendor = implvendor;
+        specTitle = spectitle;
+        specVersion = specversion;
+        specVendor = specvendor;
+        sealBase = sealbase;
+        this.loader = loader;
+    }
+
+    /*
+     * Construct a package using the attributes from the specified manifest.
+     *
+     * @param name the package name
+     * @param man the optional manifest for the package
+     * @param url the optional code source url for the package
+     */
+    private Package(String name, Manifest man, URL url, ClassLoader loader) {
+        String path = name.replace('.', '/').concat("/");
+        String sealed = null;
+        String specTitle= null;
+        String specVersion= null;
+        String specVendor= null;
+        String implTitle= null;
+        String implVersion= null;
+        String implVendor= null;
+        URL sealBase= null;
+        Attributes attr = man.getAttributes(path);
+        if (attr != null) {
+            specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
+            specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+            specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
+            implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
+            implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+            implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+            sealed      = attr.getValue(Name.SEALED);
+        }
+        attr = man.getMainAttributes();
+        if (attr != null) {
+            if (specTitle == null) {
+                specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
+            }
+            if (specVersion == null) {
+                specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+            }
+            if (specVendor == null) {
+                specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
+            }
+            if (implTitle == null) {
+                implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
+            }
+            if (implVersion == null) {
+                implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+            }
+            if (implVendor == null) {
+                implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+            }
+            if (sealed == null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        if ("true".equalsIgnoreCase(sealed)) {
+            sealBase = url;
+        }
+        pkgName = name;
+        this.specTitle = specTitle;
+        this.specVersion = specVersion;
+        this.specVendor = specVendor;
+        this.implTitle = implTitle;
+        this.implVersion = implVersion;
+        this.implVendor = implVendor;
+        this.sealBase = sealBase;
+        this.loader = loader;
+    }
+
+    /*
+     * Returns the loaded system package for the specified name.
+     */
+    static Package getSystemPackage(String name) {
+        synchronized (pkgs) {
+            Package pkg = pkgs.get(name);
+            if (pkg == null) {
+                name = name.replace('.', '/').concat("/");
+                String fn = getSystemPackage0(name);
+                if (fn != null) {
+                    pkg = defineSystemPackage(name, fn);
+                }
+            }
+            return pkg;
+        }
+    }
+
+    /*
+     * Return an array of loaded system packages.
+     */
+    static Package[] getSystemPackages() {
+        // First, update the system package map with new package names
+        String[] names = getSystemPackages0();
+        synchronized (pkgs) {
+            for (int i = 0; i < names.length; i++) {
+                defineSystemPackage(names[i], getSystemPackage0(names[i]));
+            }
+            return pkgs.values().toArray(new Package[pkgs.size()]);
+        }
+    }
+
+    private static Package defineSystemPackage(final String iname,
+                                               final String fn)
+    {
+        return AccessController.doPrivileged(new PrivilegedAction<Package>() {
+            public Package run() {
+                String name = iname;
+                // Get the cached code source url for the file name
+                URL url = urls.get(fn);
+                if (url == null) {
+                    // URL not found, so create one
+                    File file = new File(fn);
+                    try {
+                        url = ParseUtil.fileToEncodedURL(file);
+                    } catch (MalformedURLException e) {
+                    }
+                    if (url != null) {
+                        urls.put(fn, url);
+                        // If loading a JAR file, then also cache the manifest
+                        if (file.isFile()) {
+                            mans.put(fn, loadManifest(fn));
+                        }
+                    }
+                }
+                // Convert to "."-separated package name
+                name = name.substring(0, name.length() - 1).replace('/', '.');
+                Package pkg;
+                Manifest man = mans.get(fn);
+                if (man != null) {
+                    pkg = new Package(name, man, url, null);
+                } else {
+                    pkg = new Package(name, null, null, null,
+                                      null, null, null, null, null);
+                }
+                pkgs.put(name, pkg);
+                return pkg;
+            }
+        });
+    }
+
+    /*
+     * Returns the Manifest for the specified JAR file name.
+     */
+    private static Manifest loadManifest(String fn) {
+        try (FileInputStream fis = new FileInputStream(fn);
+             JarInputStream jis = new JarInputStream(fis, false))
+        {
+            return jis.getManifest();
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+    // The map of loaded system packages
+    private static Map<String, Package> pkgs = new HashMap<>(31);
+
+    // Maps each directory or zip file name to its corresponding url
+    private static Map<String, URL> urls = new HashMap<>(10);
+
+    // Maps each code source url for a jar file to its manifest
+    private static Map<String, Manifest> mans = new HashMap<>(10);
+
+    private static native String getSystemPackage0(String name);
+    private static native String[] getSystemPackages0();
+
+    /*
+     * Private storage for the package name and attributes.
+     */
+    private final String pkgName;
+    private final String specTitle;
+    private final String specVersion;
+    private final String specVendor;
+    private final String implTitle;
+    private final String implVersion;
+    private final String implVendor;
+    private final URL sealBase;
+    private transient final ClassLoader loader;
+    private transient Class<?> packageInfo;
+}
diff --git a/java/lang/Process.java b/java/lang/Process.java
new file mode 100644
index 0000000..4e94538
--- /dev/null
+++ b/java/lang/Process.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * The {@link ProcessBuilder#start()} and
+ * {@link Runtime#exec(String[],String[],File) Runtime.exec}
+ * methods create a native process and return an instance of a
+ * subclass of {@code Process} that can be used to control the process
+ * and obtain information about it.  The class {@code Process}
+ * provides methods for performing input from the process, performing
+ * output to the process, waiting for the process to complete,
+ * checking the exit status of the process, and destroying (killing)
+ * the process.
+ *
+ * <p>The methods that create processes may not work well for special
+ * processes on certain native platforms, such as native windowing
+ * processes, daemon processes, Win16/DOS processes on Microsoft
+ * Windows, or shell scripts.
+ *
+ * <p>By default, the created subprocess does not have its own terminal
+ * or console.  All its standard I/O (i.e. stdin, stdout, stderr)
+ * operations will be redirected to the parent process, where they can
+ * be accessed via the streams obtained using the methods
+ * {@link #getOutputStream()},
+ * {@link #getInputStream()}, and
+ * {@link #getErrorStream()}.
+ * The parent process uses these streams to feed input to and get output
+ * from the subprocess.  Because some native platforms only provide
+ * limited buffer size for standard input and output streams, failure
+ * to promptly write the input stream or read the output stream of
+ * the subprocess may cause the subprocess to block, or even deadlock.
+ *
+ * <p>Where desired, <a href="ProcessBuilder.html#redirect-input">
+ * subprocess I/O can also be redirected</a>
+ * using methods of the {@link ProcessBuilder} class.
+ *
+ * <p>The subprocess is not killed when there are no more references to
+ * the {@code Process} object, but rather the subprocess
+ * continues executing asynchronously.
+ *
+ * <p>There is no requirement that a process represented by a {@code
+ * Process} object execute asynchronously or concurrently with respect
+ * to the Java process that owns the {@code Process} object.
+ *
+ * <p>As of 1.5, {@link ProcessBuilder#start()} is the preferred way
+ * to create a {@code Process}.
+ *
+ * @since   JDK1.0
+ */
+public abstract class Process {
+    /**
+     * Returns the output stream connected to the normal input of the
+     * subprocess.  Output to the stream is piped into the standard
+     * input of the process represented by this {@code Process} object.
+     *
+     * <p>If the standard input of the subprocess has been redirected using
+     * {@link ProcessBuilder#redirectInput(Redirect)
+     * ProcessBuilder.redirectInput}
+     * then this method will return a
+     * <a href="ProcessBuilder.html#redirect-input">null output stream</a>.
+     *
+     * <p>Implementation note: It is a good idea for the returned
+     * output stream to be buffered.
+     *
+     * @return the output stream connected to the normal input of the
+     *         subprocess
+     */
+    public abstract OutputStream getOutputStream();
+
+    /**
+     * Returns the input stream connected to the normal output of the
+     * subprocess.  The stream obtains data piped from the standard
+     * output of the process represented by this {@code Process} object.
+     *
+     * <p>If the standard output of the subprocess has been redirected using
+     * {@link ProcessBuilder#redirectOutput(Redirect)
+     * ProcessBuilder.redirectOutput}
+     * then this method will return a
+     * <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
+     *
+     * <p>Otherwise, if the standard error of the subprocess has been
+     * redirected using
+     * {@link ProcessBuilder#redirectErrorStream(boolean)
+     * ProcessBuilder.redirectErrorStream}
+     * then the input stream returned by this method will receive the
+     * merged standard output and the standard error of the subprocess.
+     *
+     * <p>Implementation note: It is a good idea for the returned
+     * input stream to be buffered.
+     *
+     * @return the input stream connected to the normal output of the
+     *         subprocess
+     */
+    public abstract InputStream getInputStream();
+
+    /**
+     * Returns the input stream connected to the error output of the
+     * subprocess.  The stream obtains data piped from the error output
+     * of the process represented by this {@code Process} object.
+     *
+     * <p>If the standard error of the subprocess has been redirected using
+     * {@link ProcessBuilder#redirectError(Redirect)
+     * ProcessBuilder.redirectError} or
+     * {@link ProcessBuilder#redirectErrorStream(boolean)
+     * ProcessBuilder.redirectErrorStream}
+     * then this method will return a
+     * <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
+     *
+     * <p>Implementation note: It is a good idea for the returned
+     * input stream to be buffered.
+     *
+     * @return the input stream connected to the error output of
+     *         the subprocess
+     */
+    public abstract InputStream getErrorStream();
+
+    /**
+     * Causes the current thread to wait, if necessary, until the
+     * process represented by this {@code Process} object has
+     * terminated.  This method returns immediately if the subprocess
+     * has already terminated.  If the subprocess has not yet
+     * terminated, the calling thread will be blocked until the
+     * subprocess exits.
+     *
+     * @return the exit value of the subprocess represented by this
+     *         {@code Process} object.  By convention, the value
+     *         {@code 0} indicates normal termination.
+     * @throws InterruptedException if the current thread is
+     *         {@linkplain Thread#interrupt() interrupted} by another
+     *         thread while it is waiting, then the wait is ended and
+     *         an {@link InterruptedException} is thrown.
+     */
+    public abstract int waitFor() throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait, if necessary, until the
+     * subprocess represented by this {@code Process} object has
+     * terminated, or the specified waiting time elapses.
+     *
+     * <p>If the subprocess has already terminated then this method returns
+     * immediately with the value {@code true}.  If the process has not
+     * terminated and the timeout value is less than, or equal to, zero, then
+     * this method returns immediately with the value {@code false}.
+     *
+     * <p>The default implementation of this methods polls the {@code exitValue}
+     * to check if the process has terminated. Concrete implementations of this
+     * class are strongly encouraged to override this method with a more
+     * efficient implementation.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if the subprocess has exited and {@code false} if
+     *         the waiting time elapsed before the subprocess has exited.
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting.
+     * @throws NullPointerException if unit is null
+     * @since 1.8
+     */
+    public boolean waitFor(long timeout, TimeUnit unit)
+        throws InterruptedException
+    {
+        long startTime = System.nanoTime();
+        long rem = unit.toNanos(timeout);
+
+        do {
+            try {
+                exitValue();
+                return true;
+            } catch(IllegalThreadStateException ex) {
+                if (rem > 0)
+                    Thread.sleep(
+                        Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));
+            }
+            rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);
+        } while (rem > 0);
+        return false;
+    }
+
+    /**
+     * Returns the exit value for the subprocess.
+     *
+     * @return the exit value of the subprocess represented by this
+     *         {@code Process} object.  By convention, the value
+     *         {@code 0} indicates normal termination.
+     * @throws IllegalThreadStateException if the subprocess represented
+     *         by this {@code Process} object has not yet terminated
+     */
+    public abstract int exitValue();
+
+    /**
+     * Kills the subprocess. Whether the subprocess represented by this
+     * {@code Process} object is forcibly terminated or not is
+     * implementation dependent.
+     */
+    public abstract void destroy();
+
+    /**
+     * Kills the subprocess. The subprocess represented by this
+     * {@code Process} object is forcibly terminated.
+     *
+     * <p>The default implementation of this method invokes {@link #destroy}
+     * and so may not forcibly terminate the process. Concrete implementations
+     * of this class are strongly encouraged to override this method with a
+     * compliant implementation.  Invoking this method on {@code Process}
+     * objects returned by {@link ProcessBuilder#start} and
+     * {@link Runtime#exec} will forcibly terminate the process.
+     *
+     * <p>Note: The subprocess may not terminate immediately.
+     * i.e. {@code isAlive()} may return true for a brief period
+     * after {@code destroyForcibly()} is called. This method
+     * may be chained to {@code waitFor()} if needed.
+     *
+     * @return the {@code Process} object representing the
+     *         subprocess to be forcibly destroyed.
+     * @since 1.8
+     */
+    public Process destroyForcibly() {
+        destroy();
+        return this;
+    }
+
+    /**
+     * Tests whether the subprocess represented by this {@code Process} is
+     * alive.
+     *
+     * @return {@code true} if the subprocess represented by this
+     *         {@code Process} object has not yet terminated.
+     * @since 1.8
+     */
+    public boolean isAlive() {
+        try {
+            exitValue();
+            return false;
+        } catch(IllegalThreadStateException e) {
+            return true;
+        }
+    }
+}
diff --git a/java/lang/ProcessBuilder.java b/java/lang/ProcessBuilder.java
new file mode 100644
index 0000000..fc58abc
--- /dev/null
+++ b/java/lang/ProcessBuilder.java
@@ -0,0 +1,1055 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class is used to create operating system processes.
+ *
+ * <p>Each {@code ProcessBuilder} instance manages a collection
+ * of process attributes.  The {@link #start()} method creates a new
+ * {@link Process} instance with those attributes.  The {@link
+ * #start()} method can be invoked repeatedly from the same instance
+ * to create new subprocesses with identical or related attributes.
+ *
+ * <p>Each process builder manages these process attributes:
+ *
+ * <ul>
+ *
+ * <li>a <i>command</i>, a list of strings which signifies the
+ * external program file to be invoked and its arguments, if any.
+ * Which string lists represent a valid operating system command is
+ * system-dependent.  For example, it is common for each conceptual
+ * argument to be an element in this list, but there are operating
+ * systems where programs are expected to tokenize command line
+ * strings themselves - on such a system a Java implementation might
+ * require commands to contain exactly two elements.
+ *
+ * <li>an <i>environment</i>, which is a system-dependent mapping from
+ * <i>variables</i> to <i>values</i>.  The initial value is a copy of
+ * the environment of the current process (see {@link System#getenv()}).
+ *
+ * <li>a <i>working directory</i>.  The default value is the current
+ * working directory of the current process, usually the directory
+ * named by the system property {@code user.dir}.
+ *
+ * <li><a name="redirect-input">a source of <i>standard input</i></a>.
+ * By default, the subprocess reads input from a pipe.  Java code
+ * can access this pipe via the output stream returned by
+ * {@link Process#getOutputStream()}.  However, standard input may
+ * be redirected to another source using
+ * {@link #redirectInput(Redirect) redirectInput}.
+ * In this case, {@link Process#getOutputStream()} will return a
+ * <i>null output stream</i>, for which:
+ *
+ * <ul>
+ * <li>the {@link OutputStream#write(int) write} methods always
+ * throw {@code IOException}
+ * <li>the {@link OutputStream#close() close} method does nothing
+ * </ul>
+ *
+ * <li><a name="redirect-output">a destination for <i>standard output</i>
+ * and <i>standard error</i></a>.  By default, the subprocess writes standard
+ * output and standard error to pipes.  Java code can access these pipes
+ * via the input streams returned by {@link Process#getInputStream()} and
+ * {@link Process#getErrorStream()}.  However, standard output and
+ * standard error may be redirected to other destinations using
+ * {@link #redirectOutput(Redirect) redirectOutput} and
+ * {@link #redirectError(Redirect) redirectError}.
+ * In this case, {@link Process#getInputStream()} and/or
+ * {@link Process#getErrorStream()} will return a <i>null input
+ * stream</i>, for which:
+ *
+ * <ul>
+ * <li>the {@link InputStream#read() read} methods always return
+ * {@code -1}
+ * <li>the {@link InputStream#available() available} method always returns
+ * {@code 0}
+ * <li>the {@link InputStream#close() close} method does nothing
+ * </ul>
+ *
+ * <li>a <i>redirectErrorStream</i> property.  Initially, this property
+ * is {@code false}, meaning that the standard output and error
+ * output of a subprocess are sent to two separate streams, which can
+ * be accessed using the {@link Process#getInputStream()} and {@link
+ * Process#getErrorStream()} methods.
+ *
+ * <p>If the value is set to {@code true}, then:
+ *
+ * <ul>
+ * <li>standard error is merged with the standard output and always sent
+ * to the same destination (this makes it easier to correlate error
+ * messages with the corresponding output)
+ * <li>the common destination of standard error and standard output can be
+ * redirected using
+ * {@link #redirectOutput(Redirect) redirectOutput}
+ * <li>any redirection set by the
+ * {@link #redirectError(Redirect) redirectError}
+ * method is ignored when creating a subprocess
+ * <li>the stream returned from {@link Process#getErrorStream()} will
+ * always be a <a href="#redirect-output">null input stream</a>
+ * </ul>
+ *
+ * </ul>
+ *
+ * <p>Modifying a process builder's attributes will affect processes
+ * subsequently started by that object's {@link #start()} method, but
+ * will never affect previously started processes or the Java process
+ * itself.
+ *
+ * <p>Most error checking is performed by the {@link #start()} method.
+ * It is possible to modify the state of an object so that {@link
+ * #start()} will fail.  For example, setting the command attribute to
+ * an empty list will not throw an exception unless {@link #start()}
+ * is invoked.
+ *
+ * <p><strong>Note that this class is not synchronized.</strong>
+ * If multiple threads access a {@code ProcessBuilder} instance
+ * concurrently, and at least one of the threads modifies one of the
+ * attributes structurally, it <i>must</i> be synchronized externally.
+ *
+ * <p>Starting a new process which uses the default working directory
+ * and environment is easy:
+ *
+ * <pre> {@code
+ * Process p = new ProcessBuilder("myCommand", "myArg").start();
+ * }</pre>
+ *
+ * <p>Here is an example that starts a process with a modified working
+ * directory and environment, and redirects standard output and error
+ * to be appended to a log file:
+ *
+ * <pre> {@code
+ * ProcessBuilder pb =
+ *   new ProcessBuilder("myCommand", "myArg1", "myArg2");
+ * Map<String, String> env = pb.environment();
+ * env.put("VAR1", "myValue");
+ * env.remove("OTHERVAR");
+ * env.put("VAR2", env.get("VAR1") + "suffix");
+ * pb.directory(new File("myDir"));
+ * File log = new File("log");
+ * pb.redirectErrorStream(true);
+ * pb.redirectOutput(Redirect.appendTo(log));
+ * Process p = pb.start();
+ * assert pb.redirectInput() == Redirect.PIPE;
+ * assert pb.redirectOutput().file() == log;
+ * assert p.getInputStream().read() == -1;
+ * }</pre>
+ *
+ * <p>To start a process with an explicit set of environment
+ * variables, first call {@link java.util.Map#clear() Map.clear()}
+ * before adding environment variables.
+ *
+ * @author Martin Buchholz
+ * @since 1.5
+ */
+
+public final class ProcessBuilder
+{
+    private List<String> command;
+    private File directory;
+    private Map<String,String> environment;
+    private boolean redirectErrorStream;
+    private Redirect[] redirects;
+
+    /**
+     * Constructs a process builder with the specified operating
+     * system program and arguments.  This constructor does <i>not</i>
+     * make a copy of the {@code command} list.  Subsequent
+     * updates to the list will be reflected in the state of the
+     * process builder.  It is not checked whether
+     * {@code command} corresponds to a valid operating system
+     * command.
+     *
+     * @param  command the list containing the program and its arguments
+     * @throws NullPointerException if the argument is null
+     */
+    public ProcessBuilder(List<String> command) {
+        if (command == null)
+            throw new NullPointerException();
+        this.command = command;
+    }
+
+    /**
+     * Constructs a process builder with the specified operating
+     * system program and arguments.  This is a convenience
+     * constructor that sets the process builder's command to a string
+     * list containing the same strings as the {@code command}
+     * array, in the same order.  It is not checked whether
+     * {@code command} corresponds to a valid operating system
+     * command.
+     *
+     * @param command a string array containing the program and its arguments
+     */
+    public ProcessBuilder(String... command) {
+        this.command = new ArrayList<>(command.length);
+        for (String arg : command)
+            this.command.add(arg);
+    }
+
+    /**
+     * Sets this process builder's operating system program and
+     * arguments.  This method does <i>not</i> make a copy of the
+     * {@code command} list.  Subsequent updates to the list will
+     * be reflected in the state of the process builder.  It is not
+     * checked whether {@code command} corresponds to a valid
+     * operating system command.
+     *
+     * @param  command the list containing the program and its arguments
+     * @return this process builder
+     *
+     * @throws NullPointerException if the argument is null
+     */
+    public ProcessBuilder command(List<String> command) {
+        if (command == null)
+            throw new NullPointerException();
+        this.command = command;
+        return this;
+    }
+
+    /**
+     * Sets this process builder's operating system program and
+     * arguments.  This is a convenience method that sets the command
+     * to a string list containing the same strings as the
+     * {@code command} array, in the same order.  It is not
+     * checked whether {@code command} corresponds to a valid
+     * operating system command.
+     *
+     * @param  command a string array containing the program and its arguments
+     * @return this process builder
+     */
+    public ProcessBuilder command(String... command) {
+        this.command = new ArrayList<>(command.length);
+        for (String arg : command)
+            this.command.add(arg);
+        return this;
+    }
+
+    /**
+     * Returns this process builder's operating system program and
+     * arguments.  The returned list is <i>not</i> a copy.  Subsequent
+     * updates to the list will be reflected in the state of this
+     * process builder.
+     *
+     * @return this process builder's program and its arguments
+     */
+    public List<String> command() {
+        return command;
+    }
+
+    /**
+     * Returns a string map view of this process builder's environment.
+     *
+     * Whenever a process builder is created, the environment is
+     * initialized to a copy of the current process environment (see
+     * {@link System#getenv()}).  Subprocesses subsequently started by
+     * this object's {@link #start()} method will use this map as
+     * their environment.
+     *
+     * <p>The returned object may be modified using ordinary {@link
+     * java.util.Map Map} operations.  These modifications will be
+     * visible to subprocesses started via the {@link #start()}
+     * method.  Two {@code ProcessBuilder} instances always
+     * contain independent process environments, so changes to the
+     * returned map will never be reflected in any other
+     * {@code ProcessBuilder} instance or the values returned by
+     * {@link System#getenv System.getenv}.
+     *
+     * <p>If the system does not support environment variables, an
+     * empty map is returned.
+     *
+     * <p>The returned map does not permit null keys or values.
+     * Attempting to insert or query the presence of a null key or
+     * value will throw a {@link NullPointerException}.
+     * Attempting to query the presence of a key or value which is not
+     * of type {@link String} will throw a {@link ClassCastException}.
+     *
+     * <p>The behavior of the returned map is system-dependent.  A
+     * system may not allow modifications to environment variables or
+     * may forbid certain variable names or values.  For this reason,
+     * attempts to modify the map may fail with
+     * {@link UnsupportedOperationException} or
+     * {@link IllegalArgumentException}
+     * if the modification is not permitted by the operating system.
+     *
+     * <p>Since the external format of environment variable names and
+     * values is system-dependent, there may not be a one-to-one
+     * mapping between them and Java's Unicode strings.  Nevertheless,
+     * the map is implemented in such a way that environment variables
+     * which are not modified by Java code will have an unmodified
+     * native representation in the subprocess.
+     *
+     * <p>The returned map and its collection views may not obey the
+     * general contract of the {@link Object#equals} and
+     * {@link Object#hashCode} methods.
+     *
+     * <p>The returned map is typically case-sensitive on all platforms.
+     *
+     * <p>If a security manager exists, its
+     * {@link SecurityManager#checkPermission checkPermission} method
+     * is called with a
+     * {@link RuntimePermission}{@code ("getenv.*")} permission.
+     * This may result in a {@link SecurityException} being thrown.
+     *
+     * <p>When passing information to a Java subprocess,
+     * <a href=System.html#EnvironmentVSSystemProperties>system properties</a>
+     * are generally preferred over environment variables.
+     *
+     * @return this process builder's environment
+     *
+     * @throws SecurityException
+     *         if a security manager exists and its
+     *         {@link SecurityManager#checkPermission checkPermission}
+     *         method doesn't allow access to the process environment
+     *
+     * @see    Runtime#exec(String[],String[],java.io.File)
+     * @see    System#getenv()
+     */
+    public Map<String,String> environment() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(new RuntimePermission("getenv.*"));
+
+        if (environment == null)
+            environment = ProcessEnvironment.environment();
+
+        assert environment != null;
+
+        return environment;
+    }
+
+    // Only for use by Runtime.exec(...envp...)
+    ProcessBuilder environment(String[] envp) {
+        assert environment == null;
+        if (envp != null) {
+            environment = ProcessEnvironment.emptyEnvironment(envp.length);
+            assert environment != null;
+
+            for (String envstring : envp) {
+                // Before 1.5, we blindly passed invalid envstrings
+                // to the child process.
+                // We would like to throw an exception, but do not,
+                // for compatibility with old broken code.
+
+                // Silently discard any trailing junk.
+                if (envstring.indexOf((int) '\u0000') != -1)
+                    envstring = envstring.replaceFirst("\u0000.*", "");
+
+                int eqlsign =
+                    envstring.indexOf('=', ProcessEnvironment.MIN_NAME_LENGTH);
+                // Silently ignore envstrings lacking the required `='.
+                if (eqlsign != -1)
+                    environment.put(envstring.substring(0,eqlsign),
+                                    envstring.substring(eqlsign+1));
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Returns this process builder's working directory.
+     *
+     * Subprocesses subsequently started by this object's {@link
+     * #start()} method will use this as their working directory.
+     * The returned value may be {@code null} -- this means to use
+     * the working directory of the current Java process, usually the
+     * directory named by the system property {@code user.dir},
+     * as the working directory of the child process.
+     *
+     * @return this process builder's working directory
+     */
+    public File directory() {
+        return directory;
+    }
+
+    /**
+     * Sets this process builder's working directory.
+     *
+     * Subprocesses subsequently started by this object's {@link
+     * #start()} method will use this as their working directory.
+     * The argument may be {@code null} -- this means to use the
+     * working directory of the current Java process, usually the
+     * directory named by the system property {@code user.dir},
+     * as the working directory of the child process.
+     *
+     * @param  directory the new working directory
+     * @return this process builder
+     */
+    public ProcessBuilder directory(File directory) {
+        this.directory = directory;
+        return this;
+    }
+
+    // ---------------- I/O Redirection ----------------
+
+    /**
+     * Implements a <a href="#redirect-output">null input stream</a>.
+     */
+    static class NullInputStream extends InputStream {
+        static final NullInputStream INSTANCE = new NullInputStream();
+        private NullInputStream() {}
+        public int read()      { return -1; }
+        public int available() { return 0; }
+    }
+
+    /**
+     * Implements a <a href="#redirect-input">null output stream</a>.
+     */
+    static class NullOutputStream extends OutputStream {
+        static final NullOutputStream INSTANCE = new NullOutputStream();
+        private NullOutputStream() {}
+        public void write(int b) throws IOException {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Represents a source of subprocess input or a destination of
+     * subprocess output.
+     *
+     * Each {@code Redirect} instance is one of the following:
+     *
+     * <ul>
+     * <li>the special value {@link #PIPE Redirect.PIPE}
+     * <li>the special value {@link #INHERIT Redirect.INHERIT}
+     * <li>a redirection to read from a file, created by an invocation of
+     *     {@link Redirect#from Redirect.from(File)}
+     * <li>a redirection to write to a file,  created by an invocation of
+     *     {@link Redirect#to Redirect.to(File)}
+     * <li>a redirection to append to a file, created by an invocation of
+     *     {@link Redirect#appendTo Redirect.appendTo(File)}
+     * </ul>
+     *
+     * <p>Each of the above categories has an associated unique
+     * {@link Type Type}.
+     *
+     * @since 1.7
+     */
+    public static abstract class Redirect {
+        /**
+         * The type of a {@link Redirect}.
+         */
+        public enum Type {
+            /**
+             * The type of {@link Redirect#PIPE Redirect.PIPE}.
+             */
+            PIPE,
+
+            /**
+             * The type of {@link Redirect#INHERIT Redirect.INHERIT}.
+             */
+            INHERIT,
+
+            /**
+             * The type of redirects returned from
+             * {@link Redirect#from Redirect.from(File)}.
+             */
+            READ,
+
+            /**
+             * The type of redirects returned from
+             * {@link Redirect#to Redirect.to(File)}.
+             */
+            WRITE,
+
+            /**
+             * The type of redirects returned from
+             * {@link Redirect#appendTo Redirect.appendTo(File)}.
+             */
+            APPEND
+        };
+
+        /**
+         * Returns the type of this {@code Redirect}.
+         * @return the type of this {@code Redirect}
+         */
+        public abstract Type type();
+
+        /**
+         * Indicates that subprocess I/O will be connected to the
+         * current Java process over a pipe.
+         *
+         * This is the default handling of subprocess standard I/O.
+         *
+         * <p>It will always be true that
+         *  <pre> {@code
+         * Redirect.PIPE.file() == null &&
+         * Redirect.PIPE.type() == Redirect.Type.PIPE
+         * }</pre>
+         */
+        public static final Redirect PIPE = new Redirect() {
+                public Type type() { return Type.PIPE; }
+                public String toString() { return type().toString(); }};
+
+        /**
+         * Indicates that subprocess I/O source or destination will be the
+         * same as those of the current process.  This is the normal
+         * behavior of most operating system command interpreters (shells).
+         *
+         * <p>It will always be true that
+         *  <pre> {@code
+         * Redirect.INHERIT.file() == null &&
+         * Redirect.INHERIT.type() == Redirect.Type.INHERIT
+         * }</pre>
+         */
+        public static final Redirect INHERIT = new Redirect() {
+                public Type type() { return Type.INHERIT; }
+                public String toString() { return type().toString(); }};
+
+        /**
+         * Returns the {@link File} source or destination associated
+         * with this redirect, or {@code null} if there is no such file.
+         *
+         * @return the file associated with this redirect,
+         *         or {@code null} if there is no such file
+         */
+        public File file() { return null; }
+
+        /**
+         * When redirected to a destination file, indicates if the output
+         * is to be written to the end of the file.
+         */
+        boolean append() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Returns a redirect to read from the specified file.
+         *
+         * <p>It will always be true that
+         *  <pre> {@code
+         * Redirect.from(file).file() == file &&
+         * Redirect.from(file).type() == Redirect.Type.READ
+         * }</pre>
+         *
+         * @param file The {@code File} for the {@code Redirect}.
+         * @throws NullPointerException if the specified file is null
+         * @return a redirect to read from the specified file
+         */
+        public static Redirect from(final File file) {
+            if (file == null)
+                throw new NullPointerException();
+            return new Redirect() {
+                    public Type type() { return Type.READ; }
+                    public File file() { return file; }
+                    public String toString() {
+                        return "redirect to read from file \"" + file + "\"";
+                    }
+                };
+        }
+
+        /**
+         * Returns a redirect to write to the specified file.
+         * If the specified file exists when the subprocess is started,
+         * its previous contents will be discarded.
+         *
+         * <p>It will always be true that
+         *  <pre> {@code
+         * Redirect.to(file).file() == file &&
+         * Redirect.to(file).type() == Redirect.Type.WRITE
+         * }</pre>
+         *
+         * @param file The {@code File} for the {@code Redirect}.
+         * @throws NullPointerException if the specified file is null
+         * @return a redirect to write to the specified file
+         */
+        public static Redirect to(final File file) {
+            if (file == null)
+                throw new NullPointerException();
+            return new Redirect() {
+                    public Type type() { return Type.WRITE; }
+                    public File file() { return file; }
+                    public String toString() {
+                        return "redirect to write to file \"" + file + "\"";
+                    }
+                    boolean append() { return false; }
+                };
+        }
+
+        /**
+         * Returns a redirect to append to the specified file.
+         * Each write operation first advances the position to the
+         * end of the file and then writes the requested data.
+         * Whether the advancement of the position and the writing
+         * of the data are done in a single atomic operation is
+         * system-dependent and therefore unspecified.
+         *
+         * <p>It will always be true that
+         *  <pre> {@code
+         * Redirect.appendTo(file).file() == file &&
+         * Redirect.appendTo(file).type() == Redirect.Type.APPEND
+         * }</pre>
+         *
+         * @param file The {@code File} for the {@code Redirect}.
+         * @throws NullPointerException if the specified file is null
+         * @return a redirect to append to the specified file
+         */
+        public static Redirect appendTo(final File file) {
+            if (file == null)
+                throw new NullPointerException();
+            return new Redirect() {
+                    public Type type() { return Type.APPEND; }
+                    public File file() { return file; }
+                    public String toString() {
+                        return "redirect to append to file \"" + file + "\"";
+                    }
+                    boolean append() { return true; }
+                };
+        }
+
+        /**
+         * Compares the specified object with this {@code Redirect} for
+         * equality.  Returns {@code true} if and only if the two
+         * objects are identical or both objects are {@code Redirect}
+         * instances of the same type associated with non-null equal
+         * {@code File} instances.
+         */
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+            if (! (obj instanceof Redirect))
+                return false;
+            Redirect r = (Redirect) obj;
+            if (r.type() != this.type())
+                return false;
+            assert this.file() != null;
+            return this.file().equals(r.file());
+        }
+
+        /**
+         * Returns a hash code value for this {@code Redirect}.
+         * @return a hash code value for this {@code Redirect}
+         */
+        public int hashCode() {
+            File file = file();
+            if (file == null)
+                return super.hashCode();
+            else
+                return file.hashCode();
+        }
+
+        /**
+         * No public constructors.  Clients must use predefined
+         * static {@code Redirect} instances or factory methods.
+         */
+        private Redirect() {}
+    }
+
+    private Redirect[] redirects() {
+        if (redirects == null)
+            redirects = new Redirect[] {
+                Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
+            };
+        return redirects;
+    }
+
+    /**
+     * Sets this process builder's standard input source.
+     *
+     * Subprocesses subsequently started by this object's {@link #start()}
+     * method obtain their standard input from this source.
+     *
+     * <p>If the source is {@link Redirect#PIPE Redirect.PIPE}
+     * (the initial value), then the standard input of a
+     * subprocess can be written to using the output stream
+     * returned by {@link Process#getOutputStream()}.
+     * If the source is set to any other value, then
+     * {@link Process#getOutputStream()} will return a
+     * <a href="#redirect-input">null output stream</a>.
+     *
+     * @param  source the new standard input source
+     * @return this process builder
+     * @throws IllegalArgumentException
+     *         if the redirect does not correspond to a valid source
+     *         of data, that is, has type
+     *         {@link Redirect.Type#WRITE WRITE} or
+     *         {@link Redirect.Type#APPEND APPEND}
+     * @since  1.7
+     */
+    public ProcessBuilder redirectInput(Redirect source) {
+        if (source.type() == Redirect.Type.WRITE ||
+            source.type() == Redirect.Type.APPEND)
+            throw new IllegalArgumentException(
+                "Redirect invalid for reading: " + source);
+        redirects()[0] = source;
+        return this;
+    }
+
+    /**
+     * Sets this process builder's standard output destination.
+     *
+     * Subprocesses subsequently started by this object's {@link #start()}
+     * method send their standard output to this destination.
+     *
+     * <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
+     * (the initial value), then the standard output of a subprocess
+     * can be read using the input stream returned by {@link
+     * Process#getInputStream()}.
+     * If the destination is set to any other value, then
+     * {@link Process#getInputStream()} will return a
+     * <a href="#redirect-output">null input stream</a>.
+     *
+     * @param  destination the new standard output destination
+     * @return this process builder
+     * @throws IllegalArgumentException
+     *         if the redirect does not correspond to a valid
+     *         destination of data, that is, has type
+     *         {@link Redirect.Type#READ READ}
+     * @since  1.7
+     */
+    public ProcessBuilder redirectOutput(Redirect destination) {
+        if (destination.type() == Redirect.Type.READ)
+            throw new IllegalArgumentException(
+                "Redirect invalid for writing: " + destination);
+        redirects()[1] = destination;
+        return this;
+    }
+
+    /**
+     * Sets this process builder's standard error destination.
+     *
+     * Subprocesses subsequently started by this object's {@link #start()}
+     * method send their standard error to this destination.
+     *
+     * <p>If the destination is {@link Redirect#PIPE Redirect.PIPE}
+     * (the initial value), then the error output of a subprocess
+     * can be read using the input stream returned by {@link
+     * Process#getErrorStream()}.
+     * If the destination is set to any other value, then
+     * {@link Process#getErrorStream()} will return a
+     * <a href="#redirect-output">null input stream</a>.
+     *
+     * <p>If the {@link #redirectErrorStream redirectErrorStream}
+     * attribute has been set {@code true}, then the redirection set
+     * by this method has no effect.
+     *
+     * @param  destination the new standard error destination
+     * @return this process builder
+     * @throws IllegalArgumentException
+     *         if the redirect does not correspond to a valid
+     *         destination of data, that is, has type
+     *         {@link Redirect.Type#READ READ}
+     * @since  1.7
+     */
+    public ProcessBuilder redirectError(Redirect destination) {
+        if (destination.type() == Redirect.Type.READ)
+            throw new IllegalArgumentException(
+                "Redirect invalid for writing: " + destination);
+        redirects()[2] = destination;
+        return this;
+    }
+
+    /**
+     * Sets this process builder's standard input source to a file.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * {@code redirectInput(file)}
+     * behaves in exactly the same way as the invocation
+     * {@link #redirectInput(Redirect) redirectInput}
+     * {@code (Redirect.from(file))}.
+     *
+     * @param  file the new standard input source
+     * @return this process builder
+     * @since  1.7
+     */
+    public ProcessBuilder redirectInput(File file) {
+        return redirectInput(Redirect.from(file));
+    }
+
+    /**
+     * Sets this process builder's standard output destination to a file.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * {@code redirectOutput(file)}
+     * behaves in exactly the same way as the invocation
+     * {@link #redirectOutput(Redirect) redirectOutput}
+     * {@code (Redirect.to(file))}.
+     *
+     * @param  file the new standard output destination
+     * @return this process builder
+     * @since  1.7
+     */
+    public ProcessBuilder redirectOutput(File file) {
+        return redirectOutput(Redirect.to(file));
+    }
+
+    /**
+     * Sets this process builder's standard error destination to a file.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * {@code redirectError(file)}
+     * behaves in exactly the same way as the invocation
+     * {@link #redirectError(Redirect) redirectError}
+     * {@code (Redirect.to(file))}.
+     *
+     * @param  file the new standard error destination
+     * @return this process builder
+     * @since  1.7
+     */
+    public ProcessBuilder redirectError(File file) {
+        return redirectError(Redirect.to(file));
+    }
+
+    /**
+     * Returns this process builder's standard input source.
+     *
+     * Subprocesses subsequently started by this object's {@link #start()}
+     * method obtain their standard input from this source.
+     * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
+     *
+     * @return this process builder's standard input source
+     * @since  1.7
+     */
+    public Redirect redirectInput() {
+        return (redirects == null) ? Redirect.PIPE : redirects[0];
+    }
+
+    /**
+     * Returns this process builder's standard output destination.
+     *
+     * Subprocesses subsequently started by this object's {@link #start()}
+     * method redirect their standard output to this destination.
+     * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
+     *
+     * @return this process builder's standard output destination
+     * @since  1.7
+     */
+    public Redirect redirectOutput() {
+        return (redirects == null) ? Redirect.PIPE : redirects[1];
+    }
+
+    /**
+     * Returns this process builder's standard error destination.
+     *
+     * Subprocesses subsequently started by this object's {@link #start()}
+     * method redirect their standard error to this destination.
+     * The initial value is {@link Redirect#PIPE Redirect.PIPE}.
+     *
+     * @return this process builder's standard error destination
+     * @since  1.7
+     */
+    public Redirect redirectError() {
+        return (redirects == null) ? Redirect.PIPE : redirects[2];
+    }
+
+    /**
+     * Sets the source and destination for subprocess standard I/O
+     * to be the same as those of the current Java process.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     *  <pre> {@code
+     * pb.inheritIO()
+     * }</pre>
+     * behaves in exactly the same way as the invocation
+     *  <pre> {@code
+     * pb.redirectInput(Redirect.INHERIT)
+     *   .redirectOutput(Redirect.INHERIT)
+     *   .redirectError(Redirect.INHERIT)
+     * }</pre>
+     *
+     * This gives behavior equivalent to most operating system
+     * command interpreters, or the standard C library function
+     * {@code system()}.
+     *
+     * @return this process builder
+     * @since  1.7
+     */
+    public ProcessBuilder inheritIO() {
+        Arrays.fill(redirects(), Redirect.INHERIT);
+        return this;
+    }
+
+    /**
+     * Tells whether this process builder merges standard error and
+     * standard output.
+     *
+     * <p>If this property is {@code true}, then any error output
+     * generated by subprocesses subsequently started by this object's
+     * {@link #start()} method will be merged with the standard
+     * output, so that both can be read using the
+     * {@link Process#getInputStream()} method.  This makes it easier
+     * to correlate error messages with the corresponding output.
+     * The initial value is {@code false}.
+     *
+     * @return this process builder's {@code redirectErrorStream} property
+     */
+    public boolean redirectErrorStream() {
+        return redirectErrorStream;
+    }
+
+    /**
+     * Sets this process builder's {@code redirectErrorStream} property.
+     *
+     * <p>If this property is {@code true}, then any error output
+     * generated by subprocesses subsequently started by this object's
+     * {@link #start()} method will be merged with the standard
+     * output, so that both can be read using the
+     * {@link Process#getInputStream()} method.  This makes it easier
+     * to correlate error messages with the corresponding output.
+     * The initial value is {@code false}.
+     *
+     * @param  redirectErrorStream the new property value
+     * @return this process builder
+     */
+    public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
+        this.redirectErrorStream = redirectErrorStream;
+        return this;
+    }
+
+    /**
+     * Starts a new process using the attributes of this process builder.
+     *
+     * <p>The new process will
+     * invoke the command and arguments given by {@link #command()},
+     * in a working directory as given by {@link #directory()},
+     * with a process environment as given by {@link #environment()}.
+     *
+     * <p>This method checks that the command is a valid operating
+     * system command.  Which commands are valid is system-dependent,
+     * but at the very least the command must be a non-empty list of
+     * non-null strings.
+     *
+     * <p>A minimal set of system dependent environment variables may
+     * be required to start a process on some operating systems.
+     * As a result, the subprocess may inherit additional environment variable
+     * settings beyond those in the process builder's {@link #environment()}.
+     *
+     * <p>If there is a security manager, its
+     * {@link SecurityManager#checkExec checkExec}
+     * method is called with the first component of this object's
+     * {@code command} array as its argument. This may result in
+     * a {@link SecurityException} being thrown.
+     *
+     * <p>Starting an operating system process is highly system-dependent.
+     * Among the many things that can go wrong are:
+     * <ul>
+     * <li>The operating system program file was not found.
+     * <li>Access to the program file was denied.
+     * <li>The working directory does not exist.
+     * </ul>
+     *
+     * <p>In such cases an exception will be thrown.  The exact nature
+     * of the exception is system-dependent, but it will always be a
+     * subclass of {@link IOException}.
+     *
+     * <p>Subsequent modifications to this process builder will not
+     * affect the returned {@link Process}.
+     *
+     * @return a new {@link Process} object for managing the subprocess
+     *
+     * @throws NullPointerException
+     *         if an element of the command list is null
+     *
+     * @throws IndexOutOfBoundsException
+     *         if the command is an empty list (has size {@code 0})
+     *
+     * @throws SecurityException
+     *         if a security manager exists and
+     *         <ul>
+     *
+     *         <li>its
+     *         {@link SecurityManager#checkExec checkExec}
+     *         method doesn't allow creation of the subprocess, or
+     *
+     *         <li>the standard input to the subprocess was
+     *         {@linkplain #redirectInput redirected from a file}
+     *         and the security manager's
+     *         {@link SecurityManager#checkRead checkRead} method
+     *         denies read access to the file, or
+     *
+     *         <li>the standard output or standard error of the
+     *         subprocess was
+     *         {@linkplain #redirectOutput redirected to a file}
+     *         and the security manager's
+     *         {@link SecurityManager#checkWrite checkWrite} method
+     *         denies write access to the file
+     *
+     *         </ul>
+     *
+     * @throws IOException if an I/O error occurs
+     *
+     * @see Runtime#exec(String[], String[], java.io.File)
+     */
+    public Process start() throws IOException {
+        // Must convert to array first -- a malicious user-supplied
+        // list might try to circumvent the security check.
+        String[] cmdarray = command.toArray(new String[command.size()]);
+        cmdarray = cmdarray.clone();
+
+        for (String arg : cmdarray)
+            if (arg == null)
+                throw new NullPointerException();
+        // Throws IndexOutOfBoundsException if command is empty
+        String prog = cmdarray[0];
+
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkExec(prog);
+
+        String dir = directory == null ? null : directory.toString();
+
+        for (int i = 1; i < cmdarray.length; i++) {
+            if (cmdarray[i].indexOf('\u0000') >= 0) {
+                throw new IOException("invalid null character in command");
+            }
+        }
+
+        try {
+            return ProcessImpl.start(cmdarray,
+                                     environment,
+                                     dir,
+                                     redirects,
+                                     redirectErrorStream);
+        } catch (IOException | IllegalArgumentException e) {
+            String exceptionInfo = ": " + e.getMessage();
+            Throwable cause = e;
+            if ((e instanceof IOException) && security != null) {
+                // Can not disclose the fail reason for read-protected files.
+                try {
+                    security.checkRead(prog);
+                } catch (SecurityException se) {
+                    exceptionInfo = "";
+                    cause = se;
+                }
+            }
+            // It's much easier for us to create a high-quality error
+            // message than the low-level C code which found the problem.
+            throw new IOException(
+                "Cannot run program \"" + prog + "\""
+                + (dir == null ? "" : " (in directory \"" + dir + "\")")
+                + exceptionInfo,
+                cause);
+        }
+    }
+}
diff --git a/java/lang/ProcessEnvironment.java b/java/lang/ProcessEnvironment.java
new file mode 100644
index 0000000..08d260c
--- /dev/null
+++ b/java/lang/ProcessEnvironment.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* We use APIs that access the standard Unix environ array, which
+ * is defined by UNIX98 to look like:
+ *
+ *    char **environ;
+ *
+ * These are unsorted, case-sensitive, null-terminated arrays of bytes
+ * of the form FOO=BAR\000 which are usually encoded in the user's
+ * default encoding (file.encoding is an excellent choice for
+ * encoding/decoding these).  However, even though the user cannot
+ * directly access the underlying byte representation, we take pains
+ * to pass on the child the exact byte representation we inherit from
+ * the parent process for any environment name or value not created by
+ * Javaland.  So we keep track of all the byte representations.
+ *
+ * Internally, we define the types Variable and Value that exhibit
+ * String/byteArray duality.  The internal representation of the
+ * environment then looks like a Map<Variable,Value>.  But we don't
+ * expose this to the user -- we only provide a Map<String,String>
+ * view, although we could also provide a Map<byte[],byte[]> view.
+ *
+ * The non-private methods in this class are not for general use even
+ * within this package.  Instead, they are the system-dependent parts
+ * of the system-independent method of the same name.  Don't even
+ * think of using this class unless your method's name appears below.
+ *
+ * @author  Martin Buchholz
+ * @since   1.5
+ */
+
+package java.lang;
+
+import java.io.*;
+import java.util.*;
+
+
+final class ProcessEnvironment
+{
+    private static final HashMap<Variable,Value> theEnvironment;
+    private static final Map<String,String> theUnmodifiableEnvironment;
+    static final int MIN_NAME_LENGTH = 0;
+
+    static {
+        // We cache the C environment.  This means that subsequent calls
+        // to putenv/setenv from C will not be visible from Java code.
+        byte[][] environ = environ();
+        theEnvironment = new HashMap<>(environ.length/2 + 3);
+        // Read environment variables back to front,
+        // so that earlier variables override later ones.
+        for (int i = environ.length-1; i > 0; i-=2)
+            theEnvironment.put(Variable.valueOf(environ[i-1]),
+                               Value.valueOf(environ[i]));
+
+        theUnmodifiableEnvironment
+            = Collections.unmodifiableMap
+            (new StringEnvironment(theEnvironment));
+    }
+
+    /* Only for use by System.getenv(String) */
+    static String getenv(String name) {
+        return theUnmodifiableEnvironment.get(name);
+    }
+
+    /* Only for use by System.getenv() */
+    static Map<String,String> getenv() {
+        return theUnmodifiableEnvironment;
+    }
+
+    /* Only for use by ProcessBuilder.environment() */
+    @SuppressWarnings("unchecked")
+    static Map<String,String> environment() {
+        return new StringEnvironment
+            ((Map<Variable,Value>)(theEnvironment.clone()));
+    }
+
+    /* Only for use by Runtime.exec(...String[]envp...) */
+    static Map<String,String> emptyEnvironment(int capacity) {
+        return new StringEnvironment(new HashMap<Variable,Value>(capacity));
+    }
+
+    private static native byte[][] environ();
+
+    // This class is not instantiable.
+    private ProcessEnvironment() {}
+
+    // Check that name is suitable for insertion into Environment map
+    private static void validateVariable(String name) {
+        if (name.indexOf('=')      != -1 ||
+            name.indexOf('\u0000') != -1)
+            throw new IllegalArgumentException
+                ("Invalid environment variable name: \"" + name + "\"");
+    }
+
+    // Check that value is suitable for insertion into Environment map
+    private static void validateValue(String value) {
+        if (value.indexOf('\u0000') != -1)
+            throw new IllegalArgumentException
+                ("Invalid environment variable value: \"" + value + "\"");
+    }
+
+    // A class hiding the byteArray-String duality of
+    // text data on Unixoid operating systems.
+    private static abstract class ExternalData {
+        protected final String str;
+        protected final byte[] bytes;
+
+        protected ExternalData(String str, byte[] bytes) {
+            this.str = str;
+            this.bytes = bytes;
+        }
+
+        public byte[] getBytes() {
+            return bytes;
+        }
+
+        public String toString() {
+            return str;
+        }
+
+        public boolean equals(Object o) {
+            return o instanceof ExternalData
+                && arrayEquals(getBytes(), ((ExternalData) o).getBytes());
+        }
+
+        public int hashCode() {
+            return arrayHash(getBytes());
+        }
+    }
+
+    private static class Variable
+        extends ExternalData implements Comparable<Variable>
+    {
+        protected Variable(String str, byte[] bytes) {
+            super(str, bytes);
+        }
+
+        public static Variable valueOfQueryOnly(Object str) {
+            return valueOfQueryOnly((String) str);
+        }
+
+        public static Variable valueOfQueryOnly(String str) {
+            return new Variable(str, str.getBytes());
+        }
+
+        public static Variable valueOf(String str) {
+            validateVariable(str);
+            return valueOfQueryOnly(str);
+        }
+
+        public static Variable valueOf(byte[] bytes) {
+            return new Variable(new String(bytes), bytes);
+        }
+
+        public int compareTo(Variable variable) {
+            return arrayCompare(getBytes(), variable.getBytes());
+        }
+
+        public boolean equals(Object o) {
+            return o instanceof Variable && super.equals(o);
+        }
+    }
+
+    private static class Value
+        extends ExternalData implements Comparable<Value>
+    {
+        protected Value(String str, byte[] bytes) {
+            super(str, bytes);
+        }
+
+        public static Value valueOfQueryOnly(Object str) {
+            return valueOfQueryOnly((String) str);
+        }
+
+        public static Value valueOfQueryOnly(String str) {
+            return new Value(str, str.getBytes());
+        }
+
+        public static Value valueOf(String str) {
+            validateValue(str);
+            return valueOfQueryOnly(str);
+        }
+
+        public static Value valueOf(byte[] bytes) {
+            return new Value(new String(bytes), bytes);
+        }
+
+        public int compareTo(Value value) {
+            return arrayCompare(getBytes(), value.getBytes());
+        }
+
+        public boolean equals(Object o) {
+            return o instanceof Value && super.equals(o);
+        }
+    }
+
+    // This implements the String map view the user sees.
+    private static class StringEnvironment
+        extends AbstractMap<String,String>
+    {
+        private Map<Variable,Value> m;
+        private static String toString(Value v) {
+            return v == null ? null : v.toString();
+        }
+        public StringEnvironment(Map<Variable,Value> m) {this.m = m;}
+        public int size()        {return m.size();}
+        public boolean isEmpty() {return m.isEmpty();}
+        public void clear()      {       m.clear();}
+        public boolean containsKey(Object key) {
+            return m.containsKey(Variable.valueOfQueryOnly(key));
+        }
+        public boolean containsValue(Object value) {
+            return m.containsValue(Value.valueOfQueryOnly(value));
+        }
+        public String get(Object key) {
+            return toString(m.get(Variable.valueOfQueryOnly(key)));
+        }
+        public String put(String key, String value) {
+            return toString(m.put(Variable.valueOf(key),
+                                  Value.valueOf(value)));
+        }
+        public String remove(Object key) {
+            return toString(m.remove(Variable.valueOfQueryOnly(key)));
+        }
+        public Set<String> keySet() {
+            return new StringKeySet(m.keySet());
+        }
+        public Set<Map.Entry<String,String>> entrySet() {
+            return new StringEntrySet(m.entrySet());
+        }
+        public Collection<String> values() {
+            return new StringValues(m.values());
+        }
+
+        // It is technically feasible to provide a byte-oriented view
+        // as follows:
+        //      public Map<byte[],byte[]> asByteArrayMap() {
+        //          return new ByteArrayEnvironment(m);
+        //      }
+
+
+        // Convert to Unix style environ as a monolithic byte array
+        // inspired by the Windows Environment Block, except we work
+        // exclusively with bytes instead of chars, and we need only
+        // one trailing NUL on Unix.
+        // This keeps the JNI as simple and efficient as possible.
+        public byte[] toEnvironmentBlock(int[]envc) {
+            int count = m.size() * 2; // For added '=' and NUL
+            for (Map.Entry<Variable,Value> entry : m.entrySet()) {
+                count += entry.getKey().getBytes().length;
+                count += entry.getValue().getBytes().length;
+            }
+
+            byte[] block = new byte[count];
+
+            int i = 0;
+            for (Map.Entry<Variable,Value> entry : m.entrySet()) {
+                byte[] key   = entry.getKey  ().getBytes();
+                byte[] value = entry.getValue().getBytes();
+                System.arraycopy(key, 0, block, i, key.length);
+                i+=key.length;
+                block[i++] = (byte) '=';
+                System.arraycopy(value, 0, block, i, value.length);
+                i+=value.length + 1;
+                // No need to write NUL byte explicitly
+                //block[i++] = (byte) '\u0000';
+            }
+            envc[0] = m.size();
+            return block;
+        }
+    }
+
+    static byte[] toEnvironmentBlock(Map<String,String> map, int[]envc) {
+        return map == null ? null :
+            ((StringEnvironment)map).toEnvironmentBlock(envc);
+    }
+
+
+    private static class StringEntry
+        implements Map.Entry<String,String>
+    {
+        private final Map.Entry<Variable,Value> e;
+        public StringEntry(Map.Entry<Variable,Value> e) {this.e = e;}
+        public String getKey()   {return e.getKey().toString();}
+        public String getValue() {return e.getValue().toString();}
+        public String setValue(String newValue) {
+            return e.setValue(Value.valueOf(newValue)).toString();
+        }
+        public String toString() {return getKey() + "=" + getValue();}
+        public boolean equals(Object o) {
+            return o instanceof StringEntry
+                && e.equals(((StringEntry)o).e);
+        }
+        public int hashCode()    {return e.hashCode();}
+    }
+
+    private static class StringEntrySet
+        extends AbstractSet<Map.Entry<String,String>>
+    {
+        private final Set<Map.Entry<Variable,Value>> s;
+        public StringEntrySet(Set<Map.Entry<Variable,Value>> s) {this.s = s;}
+        public int size()        {return s.size();}
+        public boolean isEmpty() {return s.isEmpty();}
+        public void clear()      {       s.clear();}
+        public Iterator<Map.Entry<String,String>> iterator() {
+            return new Iterator<Map.Entry<String,String>>() {
+                Iterator<Map.Entry<Variable,Value>> i = s.iterator();
+                public boolean hasNext() {return i.hasNext();}
+                public Map.Entry<String,String> next() {
+                    return new StringEntry(i.next());
+                }
+                public void remove() {i.remove();}
+            };
+        }
+        private static Map.Entry<Variable,Value> vvEntry(final Object o) {
+            if (o instanceof StringEntry)
+                return ((StringEntry)o).e;
+            return new Map.Entry<Variable,Value>() {
+                public Variable getKey() {
+                    return Variable.valueOfQueryOnly(((Map.Entry)o).getKey());
+                }
+                public Value getValue() {
+                    return Value.valueOfQueryOnly(((Map.Entry)o).getValue());
+                }
+                public Value setValue(Value value) {
+                    throw new UnsupportedOperationException();
+                }
+            };
+        }
+        public boolean contains(Object o) { return s.contains(vvEntry(o)); }
+        public boolean remove(Object o)   { return s.remove(vvEntry(o)); }
+        public boolean equals(Object o) {
+            return o instanceof StringEntrySet
+                && s.equals(((StringEntrySet) o).s);
+        }
+        public int hashCode() {return s.hashCode();}
+    }
+
+    private static class StringValues
+          extends AbstractCollection<String>
+    {
+        private final Collection<Value> c;
+        public StringValues(Collection<Value> c) {this.c = c;}
+        public int size()        {return c.size();}
+        public boolean isEmpty() {return c.isEmpty();}
+        public void clear()      {       c.clear();}
+        public Iterator<String> iterator() {
+            return new Iterator<String>() {
+                Iterator<Value> i = c.iterator();
+                public boolean hasNext() {return i.hasNext();}
+                public String next()     {return i.next().toString();}
+                public void remove()     {i.remove();}
+            };
+        }
+        public boolean contains(Object o) {
+            return c.contains(Value.valueOfQueryOnly(o));
+        }
+        public boolean remove(Object o) {
+            return c.remove(Value.valueOfQueryOnly(o));
+        }
+        public boolean equals(Object o) {
+            return o instanceof StringValues
+                && c.equals(((StringValues)o).c);
+        }
+        public int hashCode() {return c.hashCode();}
+    }
+
+    private static class StringKeySet extends AbstractSet<String> {
+        private final Set<Variable> s;
+        public StringKeySet(Set<Variable> s) {this.s = s;}
+        public int size()        {return s.size();}
+        public boolean isEmpty() {return s.isEmpty();}
+        public void clear()      {       s.clear();}
+        public Iterator<String> iterator() {
+            return new Iterator<String>() {
+                Iterator<Variable> i = s.iterator();
+                public boolean hasNext() {return i.hasNext();}
+                public String next()     {return i.next().toString();}
+                public void remove()     {       i.remove();}
+            };
+        }
+        public boolean contains(Object o) {
+            return s.contains(Variable.valueOfQueryOnly(o));
+        }
+        public boolean remove(Object o) {
+            return s.remove(Variable.valueOfQueryOnly(o));
+        }
+    }
+
+    // Replace with general purpose method someday
+    private static int arrayCompare(byte[]x, byte[] y) {
+        int min = x.length < y.length ? x.length : y.length;
+        for (int i = 0; i < min; i++)
+            if (x[i] != y[i])
+                return x[i] - y[i];
+        return x.length - y.length;
+    }
+
+    // Replace with general purpose method someday
+    private static boolean arrayEquals(byte[] x, byte[] y) {
+        if (x.length != y.length)
+            return false;
+        for (int i = 0; i < x.length; i++)
+            if (x[i] != y[i])
+                return false;
+        return true;
+    }
+
+    // Replace with general purpose method someday
+    private static int arrayHash(byte[] x) {
+        int hash = 0;
+        for (int i = 0; i < x.length; i++)
+            hash = 31 * hash + x[i];
+        return hash;
+    }
+
+}
diff --git a/java/lang/ProcessImpl.java b/java/lang/ProcessImpl.java
new file mode 100644
index 0000000..39ea145
--- /dev/null
+++ b/java/lang/ProcessImpl.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.lang.ProcessBuilder.Redirect;
+import java.lang.ProcessBuilder.Redirect;
+
+/**
+ * This class is for the exclusive use of ProcessBuilder.start() to
+ * create new processes.
+ *
+ * @author Martin Buchholz
+ * @since   1.5
+ */
+final class ProcessImpl {
+    // Android-changed: Use FileDescriptor.getInt$() instead of fdAccess.get(...).
+    // private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
+    //     = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
+
+    private ProcessImpl() {}    // Not instantiable
+
+    private static byte[] toCString(String s) {
+        if (s == null)
+            return null;
+        byte[] bytes = s.getBytes();
+        byte[] result = new byte[bytes.length + 1];
+        System.arraycopy(bytes, 0,
+                         result, 0,
+                         bytes.length);
+        result[result.length-1] = (byte)0;
+        return result;
+    }
+
+    // Only for use by ProcessBuilder.start()
+    static Process start(String[] cmdarray,
+                         java.util.Map<String,String> environment,
+                         String dir,
+                         ProcessBuilder.Redirect[] redirects,
+                         boolean redirectErrorStream)
+        throws IOException
+    {
+        assert cmdarray != null && cmdarray.length > 0;
+
+        // Convert arguments to a contiguous block; it's easier to do
+        // memory management in Java than in C.
+        byte[][] args = new byte[cmdarray.length-1][];
+        int size = args.length; // For added NUL bytes
+        for (int i = 0; i < args.length; i++) {
+            args[i] = cmdarray[i+1].getBytes();
+            size += args[i].length;
+        }
+        byte[] argBlock = new byte[size];
+        int i = 0;
+        for (byte[] arg : args) {
+            System.arraycopy(arg, 0, argBlock, i, arg.length);
+            i += arg.length + 1;
+            // No need to write NUL bytes explicitly
+        }
+
+        int[] envc = new int[1];
+        byte[] envBlock = ProcessEnvironment.toEnvironmentBlock(environment, envc);
+
+        int[] std_fds;
+
+        FileInputStream  f0 = null;
+        FileOutputStream f1 = null;
+        FileOutputStream f2 = null;
+
+        try {
+            if (redirects == null) {
+                std_fds = new int[] { -1, -1, -1 };
+            } else {
+                std_fds = new int[3];
+
+                if (redirects[0] == Redirect.PIPE)
+                    std_fds[0] = -1;
+                else if (redirects[0] == Redirect.INHERIT)
+                    std_fds[0] = 0;
+                else {
+                    f0 = new FileInputStream(redirects[0].file());
+                    // Android-changed: Use FileDescriptor.getInt$() instead of fdAccess.get(...).
+                    // std_fds[0] = fdAccess.get(f0.getFD());
+                    std_fds[0] = f0.getFD().getInt$();
+                }
+
+                if (redirects[1] == Redirect.PIPE)
+                    std_fds[1] = -1;
+                else if (redirects[1] == Redirect.INHERIT)
+                    std_fds[1] = 1;
+                else {
+                    f1 = new FileOutputStream(redirects[1].file(),
+                                              redirects[1].append());
+                    // Android-changed: Use FileDescriptor.getInt$() instead of fdAccess.get(...).
+                    // std_fds[1] = fdAccess.get(f1.getFD());
+                    std_fds[1] = f1.getFD().getInt$();
+                }
+
+                if (redirects[2] == Redirect.PIPE)
+                    std_fds[2] = -1;
+                else if (redirects[2] == Redirect.INHERIT)
+                    std_fds[2] = 2;
+                else {
+                    f2 = new FileOutputStream(redirects[2].file(),
+                                              redirects[2].append());
+                    // Android-changed: Use FileDescriptor.getInt$() instead of fdAccess.get(...).
+                    // std_fds[2] = fdAccess.get(f2.getFD());
+                    std_fds[2] = f2.getFD().getInt$();
+                }
+            }
+
+        return new UNIXProcess
+            (toCString(cmdarray[0]),
+             argBlock, args.length,
+             envBlock, envc[0],
+             toCString(dir),
+                 std_fds,
+             redirectErrorStream);
+        } finally {
+            // In theory, close() can throw IOException
+            // (although it is rather unlikely to happen here)
+            try { if (f0 != null) f0.close(); }
+            finally {
+                try { if (f1 != null) f1.close(); }
+                finally { if (f2 != null) f2.close(); }
+            }
+        }
+    }
+}
diff --git a/java/lang/Readable.java b/java/lang/Readable.java
new file mode 100644
index 0000000..c7a3d1a
--- /dev/null
+++ b/java/lang/Readable.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.IOException;
+
+/**
+ * A <tt>Readable</tt> is a source of characters. Characters from
+ * a <tt>Readable</tt> are made available to callers of the read
+ * method via a {@link java.nio.CharBuffer CharBuffer}.
+ *
+ * @since 1.5
+ */
+public interface Readable {
+
+    /**
+     * Attempts to read characters into the specified character buffer.
+     * The buffer is used as a repository of characters as-is: the only
+     * changes made are the results of a put operation. No flipping or
+     * rewinding of the buffer is performed.
+     *
+     * @param cb the buffer to read characters into
+     * @return The number of {@code char} values added to the buffer,
+     *                 or -1 if this source of characters is at its end
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if cb is null
+     * @throws java.nio.ReadOnlyBufferException if cb is a read only buffer
+     */
+    public int read(java.nio.CharBuffer cb) throws IOException;
+}
diff --git a/java/lang/ReflectiveOperationException.java b/java/lang/ReflectiveOperationException.java
new file mode 100644
index 0000000..a140478
--- /dev/null
+++ b/java/lang/ReflectiveOperationException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Common superclass of exceptions thrown by reflective operations in
+ * core reflection.
+ *
+ * @see LinkageError
+ * @since 1.7
+ */
+public class ReflectiveOperationException extends Exception {
+    static final long serialVersionUID = 123456789L;
+
+    /**
+     * Constructs a new exception with {@code null} as its detail
+     * message.  The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause}.
+     */
+    public ReflectiveOperationException() {
+        super();
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause}.
+     *
+     * @param   message   the detail message. The detail message is saved for
+     *          later retrieval by the {@link #getMessage()} method.
+     */
+    public ReflectiveOperationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message
+     * and cause.
+     *
+     * <p>Note that the detail message associated with
+     * {@code cause} is <em>not</em> automatically incorporated in
+     * this exception's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     */
+    public ReflectiveOperationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     */
+    public ReflectiveOperationException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/lang/Runnable.java b/java/lang/Runnable.java
new file mode 100644
index 0000000..b9f1df7
--- /dev/null
+++ b/java/lang/Runnable.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * The <code>Runnable</code> interface should be implemented by any
+ * class whose instances are intended to be executed by a thread. The
+ * class must define a method of no arguments called <code>run</code>.
+ * <p>
+ * This interface is designed to provide a common protocol for objects that
+ * wish to execute code while they are active. For example,
+ * <code>Runnable</code> is implemented by class <code>Thread</code>.
+ * Being active simply means that a thread has been started and has not
+ * yet been stopped.
+ * <p>
+ * In addition, <code>Runnable</code> provides the means for a class to be
+ * active while not subclassing <code>Thread</code>. A class that implements
+ * <code>Runnable</code> can run without subclassing <code>Thread</code>
+ * by instantiating a <code>Thread</code> instance and passing itself in
+ * as the target.  In most cases, the <code>Runnable</code> interface should
+ * be used if you are only planning to override the <code>run()</code>
+ * method and no other <code>Thread</code> methods.
+ * This is important because classes should not be subclassed
+ * unless the programmer intends on modifying or enhancing the fundamental
+ * behavior of the class.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.lang.Thread
+ * @see     java.util.concurrent.Callable
+ * @since   JDK1.0
+ */
+@FunctionalInterface
+public interface Runnable {
+    /**
+     * When an object implementing interface <code>Runnable</code> is used
+     * to create a thread, starting the thread causes the object's
+     * <code>run</code> method to be called in that separately executing
+     * thread.
+     * <p>
+     * The general contract of the method <code>run</code> is that it may
+     * take any action whatsoever.
+     *
+     * @see     java.lang.Thread#run()
+     */
+    public abstract void run();
+}
diff --git a/java/lang/Runtime.java b/java/lang/Runtime.java
new file mode 100644
index 0000000..f5c52e7
--- /dev/null
+++ b/java/lang/Runtime.java
@@ -0,0 +1,1191 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+import java.io.*;
+import java.util.StringTokenizer;
+
+import dalvik.system.BlockGuard;
+import sun.reflect.CallerSensitive;
+import java.lang.ref.FinalizerReference;
+import java.util.ArrayList;
+import java.util.List;
+import dalvik.system.DelegateLastClassLoader;
+import dalvik.system.PathClassLoader;
+import dalvik.system.VMDebug;
+import dalvik.system.VMRuntime;
+import sun.reflect.Reflection;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.util.EmptyArray;
+import static android.system.OsConstants._SC_NPROCESSORS_CONF;
+
+/**
+ * Every Java application has a single instance of class
+ * <code>Runtime</code> that allows the application to interface with
+ * the environment in which the application is running. The current
+ * runtime can be obtained from the <code>getRuntime</code> method.
+ * <p>
+ * An application cannot create its own instance of this class.
+ *
+ * @author  unascribed
+ * @see     java.lang.Runtime#getRuntime()
+ * @since   JDK1.0
+ */
+
+public class Runtime {
+    private static Runtime currentRuntime = new Runtime();
+
+    /**
+     * Holds the list of threads to run when the VM terminates
+     */
+    private List<Thread> shutdownHooks = new ArrayList<Thread>();
+
+    /**
+     * Reflects whether finalization should be run for all objects
+     * when the VM terminates.
+     */
+    private static boolean finalizeOnExit;
+
+    /**
+     * Reflects whether we are already shutting down the VM.
+     */
+    private boolean shuttingDown;
+
+    /**
+     * Reflects whether we are tracing method calls.
+     */
+    private boolean tracingMethods;
+
+    private static native void nativeExit(int code);
+
+    /**
+     * Returns the runtime object associated with the current Java application.
+     * Most of the methods of class <code>Runtime</code> are instance
+     * methods and must be invoked with respect to the current runtime object.
+     *
+     * @return  the <code>Runtime</code> object associated with the current
+     *          Java application.
+     */
+    public static Runtime getRuntime() {
+        return currentRuntime;
+    }
+
+    /** Don't let anyone else instantiate this class */
+    private Runtime() {}
+
+    /**
+     * Terminates the currently running Java virtual machine by initiating its
+     * shutdown sequence.  This method never returns normally.  The argument
+     * serves as a status code; by convention, a nonzero status code indicates
+     * abnormal termination.
+     *
+     * <p> The virtual machine's shutdown sequence consists of two phases.  In
+     * the first phase all registered {@link #addShutdownHook shutdown hooks},
+     * if any, are started in some unspecified order and allowed to run
+     * concurrently until they finish.  In the second phase all uninvoked
+     * finalizers are run if {@link #runFinalizersOnExit finalization-on-exit}
+     * has been enabled.  Once this is done the virtual machine {@link #halt
+     * halts}.
+     *
+     * <p> If this method is invoked after the virtual machine has begun its
+     * shutdown sequence then if shutdown hooks are being run this method will
+     * block indefinitely.  If shutdown hooks have already been run and on-exit
+     * finalization has been enabled then this method halts the virtual machine
+     * with the given status code if the status is nonzero; otherwise, it
+     * blocks indefinitely.
+     *
+     * <p> The <tt>{@link System#exit(int) System.exit}</tt> method is the
+     * conventional and convenient means of invoking this method. <p>
+     *
+     * @param  status
+     *         Termination status.  By convention, a nonzero status code
+     *         indicates abnormal termination.
+     *
+     * @throws SecurityException
+     *         If a security manager is present and its <tt>{@link
+     *         SecurityManager#checkExit checkExit}</tt> method does not permit
+     *         exiting with the specified status
+     *
+     * @see java.lang.SecurityException
+     * @see java.lang.SecurityManager#checkExit(int)
+     * @see #addShutdownHook
+     * @see #removeShutdownHook
+     * @see #runFinalizersOnExit
+     * @see #halt(int)
+     */
+    public void exit(int status) {
+        // Make sure we don't try this several times
+        synchronized(this) {
+            if (!shuttingDown) {
+                shuttingDown = true;
+
+                Thread[] hooks;
+                synchronized (shutdownHooks) {
+                    // create a copy of the hooks
+                    hooks = new Thread[shutdownHooks.size()];
+                    shutdownHooks.toArray(hooks);
+                }
+
+                // Start all shutdown hooks concurrently
+                for (Thread hook : hooks) {
+                    hook.start();
+                }
+
+                // Wait for all shutdown hooks to finish
+                for (Thread hook : hooks) {
+                    try {
+                        hook.join();
+                    } catch (InterruptedException ex) {
+                        // Ignore, since we are at VM shutdown.
+                    }
+                }
+
+                // Ensure finalization on exit, if requested
+                if (finalizeOnExit) {
+                    runFinalization();
+                }
+
+                // Get out of here finally...
+                nativeExit(status);
+            }
+        }
+    }
+
+    /**
+     * Registers a new virtual-machine shutdown hook.
+     *
+     * <p> The Java virtual machine <i>shuts down</i> in response to two kinds
+     * of events:
+     *
+     *   <ul>
+     *
+     *   <li> The program <i>exits</i> normally, when the last non-daemon
+     *   thread exits or when the <tt>{@link #exit exit}</tt> (equivalently,
+     *   {@link System#exit(int) System.exit}) method is invoked, or
+     *
+     *   <li> The virtual machine is <i>terminated</i> in response to a
+     *   user interrupt, such as typing <tt>^C</tt>, or a system-wide event,
+     *   such as user logoff or system shutdown.
+     *
+     *   </ul>
+     *
+     * <p> A <i>shutdown hook</i> is simply an initialized but unstarted
+     * thread.  When the virtual machine begins its shutdown sequence it will
+     * start all registered shutdown hooks in some unspecified order and let
+     * them run concurrently.  When all the hooks have finished it will then
+     * run all uninvoked finalizers if finalization-on-exit has been enabled.
+     * Finally, the virtual machine will halt.  Note that daemon threads will
+     * continue to run during the shutdown sequence, as will non-daemon threads
+     * if shutdown was initiated by invoking the <tt>{@link #exit exit}</tt>
+     * method.
+     *
+     * <p> Once the shutdown sequence has begun it can be stopped only by
+     * invoking the <tt>{@link #halt halt}</tt> method, which forcibly
+     * terminates the virtual machine.
+     *
+     * <p> Once the shutdown sequence has begun it is impossible to register a
+     * new shutdown hook or de-register a previously-registered hook.
+     * Attempting either of these operations will cause an
+     * <tt>{@link IllegalStateException}</tt> to be thrown.
+     *
+     * <p> Shutdown hooks run at a delicate time in the life cycle of a virtual
+     * machine and should therefore be coded defensively.  They should, in
+     * particular, be written to be thread-safe and to avoid deadlocks insofar
+     * as possible.  They should also not rely blindly upon services that may
+     * have registered their own shutdown hooks and therefore may themselves in
+     * the process of shutting down.  Attempts to use other thread-based
+     * services such as the AWT event-dispatch thread, for example, may lead to
+     * deadlocks.
+     *
+     * <p> Shutdown hooks should also finish their work quickly.  When a
+     * program invokes <tt>{@link #exit exit}</tt> the expectation is
+     * that the virtual machine will promptly shut down and exit.  When the
+     * virtual machine is terminated due to user logoff or system shutdown the
+     * underlying operating system may only allow a fixed amount of time in
+     * which to shut down and exit.  It is therefore inadvisable to attempt any
+     * user interaction or to perform a long-running computation in a shutdown
+     * hook.
+     *
+     * <p> Uncaught exceptions are handled in shutdown hooks just as in any
+     * other thread, by invoking the <tt>{@link ThreadGroup#uncaughtException
+     * uncaughtException}</tt> method of the thread's <tt>{@link
+     * ThreadGroup}</tt> object.  The default implementation of this method
+     * prints the exception's stack trace to <tt>{@link System#err}</tt> and
+     * terminates the thread; it does not cause the virtual machine to exit or
+     * halt.
+     *
+     * <p> In rare circumstances the virtual machine may <i>abort</i>, that is,
+     * stop running without shutting down cleanly.  This occurs when the
+     * virtual machine is terminated externally, for example with the
+     * <tt>SIGKILL</tt> signal on Unix or the <tt>TerminateProcess</tt> call on
+     * Microsoft Windows.  The virtual machine may also abort if a native
+     * method goes awry by, for example, corrupting internal data structures or
+     * attempting to access nonexistent memory.  If the virtual machine aborts
+     * then no guarantee can be made about whether or not any shutdown hooks
+     * will be run. <p>
+     *
+     * @param   hook
+     *          An initialized but unstarted <tt>{@link Thread}</tt> object
+     *
+     * @throws  IllegalArgumentException
+     *          If the specified hook has already been registered,
+     *          or if it can be determined that the hook is already running or
+     *          has already been run
+     *
+     * @throws  IllegalStateException
+     *          If the virtual machine is already in the process
+     *          of shutting down
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and it denies
+     *          <tt>{@link RuntimePermission}("shutdownHooks")</tt>
+     *
+     * @see #removeShutdownHook
+     * @see #halt(int)
+     * @see #exit(int)
+     * @since 1.3
+     */
+    public void addShutdownHook(Thread hook) {
+        // Sanity checks
+        if (hook == null) {
+            throw new NullPointerException("hook == null");
+        }
+
+        if (shuttingDown) {
+            throw new IllegalStateException("VM already shutting down");
+        }
+
+        if (hook.started) {
+            throw new IllegalArgumentException("Hook has already been started");
+        }
+
+        synchronized (shutdownHooks) {
+            if (shutdownHooks.contains(hook)) {
+                throw new IllegalArgumentException("Hook already registered.");
+            }
+
+            shutdownHooks.add(hook);
+        }
+    }
+
+    /**
+     * De-registers a previously-registered virtual-machine shutdown hook. <p>
+     *
+     * @param hook the hook to remove
+     * @return <tt>true</tt> if the specified hook had previously been
+     * registered and was successfully de-registered, <tt>false</tt>
+     * otherwise.
+     *
+     * @throws  IllegalStateException
+     *          If the virtual machine is already in the process of shutting
+     *          down
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and it denies
+     *          <tt>{@link RuntimePermission}("shutdownHooks")</tt>
+     *
+     * @see #addShutdownHook
+     * @see #exit(int)
+     * @since 1.3
+     */
+    public boolean removeShutdownHook(Thread hook) {
+        // Sanity checks
+        if (hook == null) {
+            throw new NullPointerException("hook == null");
+        }
+
+        if (shuttingDown) {
+            throw new IllegalStateException("VM already shutting down");
+        }
+
+        synchronized (shutdownHooks) {
+            return shutdownHooks.remove(hook);
+        }
+    }
+
+    /**
+     * Forcibly terminates the currently running Java virtual machine.  This
+     * method never returns normally.
+     *
+     * <p> This method should be used with extreme caution.  Unlike the
+     * <tt>{@link #exit exit}</tt> method, this method does not cause shutdown
+     * hooks to be started and does not run uninvoked finalizers if
+     * finalization-on-exit has been enabled.  If the shutdown sequence has
+     * already been initiated then this method does not wait for any running
+     * shutdown hooks or finalizers to finish their work. <p>
+     *
+     * @param  status
+     *         Termination status.  By convention, a nonzero status code
+     *         indicates abnormal termination.  If the <tt>{@link Runtime#exit
+     *         exit}</tt> (equivalently, <tt>{@link System#exit(int)
+     *         System.exit}</tt>) method has already been invoked then this
+     *         status code will override the status code passed to that method.
+     *
+     * @throws SecurityException
+     *         If a security manager is present and its <tt>{@link
+     *         SecurityManager#checkExit checkExit}</tt> method does not permit
+     *         an exit with the specified status
+     *
+     * @see #exit
+     * @see #addShutdownHook
+     * @see #removeShutdownHook
+     * @since 1.3
+     */
+    public void halt(int status) {
+        nativeExit(status);
+    }
+
+    /**
+     * Enable or disable finalization on exit; doing so specifies that the
+     * finalizers of all objects that have finalizers that have not yet been
+     * automatically invoked are to be run before the Java runtime exits.
+     * By default, finalization on exit is disabled.
+     *
+     * <p>If there is a security manager,
+     * its <code>checkExit</code> method is first called
+     * with 0 as its argument to ensure the exit is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param value true to enable finalization on exit, false to disable
+     * @deprecated  This method is inherently unsafe.  It may result in
+     *      finalizers being called on live objects while other threads are
+     *      concurrently manipulating those objects, resulting in erratic
+     *      behavior or deadlock.
+     *
+     * @throws  SecurityException
+     *        if a security manager exists and its <code>checkExit</code>
+     *        method doesn't allow the exit.
+     *
+     * @see     java.lang.Runtime#exit(int)
+     * @see     java.lang.Runtime#gc()
+     * @see     java.lang.SecurityManager#checkExit(int)
+     * @since   JDK1.1
+     */
+    @Deprecated
+    public static void runFinalizersOnExit(boolean value) {
+        finalizeOnExit = value;
+    }
+
+    /**
+     * Executes the specified string command in a separate process.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * <tt>exec(command)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>{@link #exec(String, String[], File) exec}(command, null, null)</tt>.
+     *
+     * @param   command   a specified system command.
+     *
+     * @return  A new {@link Process} object for managing the subprocess
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          {@link SecurityManager#checkExec checkExec}
+     *          method doesn't allow creation of the subprocess
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  NullPointerException
+     *          If <code>command</code> is <code>null</code>
+     *
+     * @throws  IllegalArgumentException
+     *          If <code>command</code> is empty
+     *
+     * @see     #exec(String[], String[], File)
+     * @see     ProcessBuilder
+     */
+    public Process exec(String command) throws IOException {
+        return exec(command, null, null);
+    }
+
+    /**
+     * Executes the specified string command in a separate process with the
+     * specified environment.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * <tt>exec(command, envp)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>{@link #exec(String, String[], File) exec}(command, envp, null)</tt>.
+     *
+     * @param   command   a specified system command.
+     *
+     * @param   envp      array of strings, each element of which
+     *                    has environment variable settings in the format
+     *                    <i>name</i>=<i>value</i>, or
+     *                    <tt>null</tt> if the subprocess should inherit
+     *                    the environment of the current process.
+     *
+     * @return  A new {@link Process} object for managing the subprocess
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          {@link SecurityManager#checkExec checkExec}
+     *          method doesn't allow creation of the subprocess
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  NullPointerException
+     *          If <code>command</code> is <code>null</code>,
+     *          or one of the elements of <code>envp</code> is <code>null</code>
+     *
+     * @throws  IllegalArgumentException
+     *          If <code>command</code> is empty
+     *
+     * @see     #exec(String[], String[], File)
+     * @see     ProcessBuilder
+     */
+    public Process exec(String command, String[] envp) throws IOException {
+        return exec(command, envp, null);
+    }
+
+    /**
+     * Executes the specified string command in a separate process with the
+     * specified environment and working directory.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * <tt>exec(command, envp, dir)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>{@link #exec(String[], String[], File) exec}(cmdarray, envp, dir)</tt>,
+     * where <code>cmdarray</code> is an array of all the tokens in
+     * <code>command</code>.
+     *
+     * <p>More precisely, the <code>command</code> string is broken
+     * into tokens using a {@link StringTokenizer} created by the call
+     * <code>new {@link StringTokenizer}(command)</code> with no
+     * further modification of the character categories.  The tokens
+     * produced by the tokenizer are then placed in the new string
+     * array <code>cmdarray</code>, in the same order.
+     *
+     * @param   command   a specified system command.
+     *
+     * @param   envp      array of strings, each element of which
+     *                    has environment variable settings in the format
+     *                    <i>name</i>=<i>value</i>, or
+     *                    <tt>null</tt> if the subprocess should inherit
+     *                    the environment of the current process.
+     *
+     * @param   dir       the working directory of the subprocess, or
+     *                    <tt>null</tt> if the subprocess should inherit
+     *                    the working directory of the current process.
+     *
+     * @return  A new {@link Process} object for managing the subprocess
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          {@link SecurityManager#checkExec checkExec}
+     *          method doesn't allow creation of the subprocess
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  NullPointerException
+     *          If <code>command</code> is <code>null</code>,
+     *          or one of the elements of <code>envp</code> is <code>null</code>
+     *
+     * @throws  IllegalArgumentException
+     *          If <code>command</code> is empty
+     *
+     * @see     ProcessBuilder
+     * @since 1.3
+     */
+    public Process exec(String command, String[] envp, File dir)
+        throws IOException {
+        if (command.length() == 0)
+            throw new IllegalArgumentException("Empty command");
+
+        StringTokenizer st = new StringTokenizer(command);
+        String[] cmdarray = new String[st.countTokens()];
+        for (int i = 0; st.hasMoreTokens(); i++)
+            cmdarray[i] = st.nextToken();
+        return exec(cmdarray, envp, dir);
+    }
+
+    /**
+     * Executes the specified command and arguments in a separate process.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * <tt>exec(cmdarray)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>{@link #exec(String[], String[], File) exec}(cmdarray, null, null)</tt>.
+     *
+     * @param   cmdarray  array containing the command to call and
+     *                    its arguments.
+     *
+     * @return  A new {@link Process} object for managing the subprocess
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          {@link SecurityManager#checkExec checkExec}
+     *          method doesn't allow creation of the subprocess
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  NullPointerException
+     *          If <code>cmdarray</code> is <code>null</code>,
+     *          or one of the elements of <code>cmdarray</code> is <code>null</code>
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <code>cmdarray</code> is an empty array
+     *          (has length <code>0</code>)
+     *
+     * @see     ProcessBuilder
+     */
+    public Process exec(String cmdarray[]) throws IOException {
+        return exec(cmdarray, null, null);
+    }
+
+    /**
+     * Executes the specified command and arguments in a separate process
+     * with the specified environment.
+     *
+     * <p>This is a convenience method.  An invocation of the form
+     * <tt>exec(cmdarray, envp)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>{@link #exec(String[], String[], File) exec}(cmdarray, envp, null)</tt>.
+     *
+     * @param   cmdarray  array containing the command to call and
+     *                    its arguments.
+     *
+     * @param   envp      array of strings, each element of which
+     *                    has environment variable settings in the format
+     *                    <i>name</i>=<i>value</i>, or
+     *                    <tt>null</tt> if the subprocess should inherit
+     *                    the environment of the current process.
+     *
+     * @return  A new {@link Process} object for managing the subprocess
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          {@link SecurityManager#checkExec checkExec}
+     *          method doesn't allow creation of the subprocess
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  NullPointerException
+     *          If <code>cmdarray</code> is <code>null</code>,
+     *          or one of the elements of <code>cmdarray</code> is <code>null</code>,
+     *          or one of the elements of <code>envp</code> is <code>null</code>
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <code>cmdarray</code> is an empty array
+     *          (has length <code>0</code>)
+     *
+     * @see     ProcessBuilder
+     */
+    public Process exec(String[] cmdarray, String[] envp) throws IOException {
+        return exec(cmdarray, envp, null);
+    }
+
+
+    /**
+     * Executes the specified command and arguments in a separate process with
+     * the specified environment and working directory.
+     *
+     * <p>Given an array of strings <code>cmdarray</code>, representing the
+     * tokens of a command line, and an array of strings <code>envp</code>,
+     * representing "environment" variable settings, this method creates
+     * a new process in which to execute the specified command.
+     *
+     * <p>This method checks that <code>cmdarray</code> is a valid operating
+     * system command.  Which commands are valid is system-dependent,
+     * but at the very least the command must be a non-empty list of
+     * non-null strings.
+     *
+     * <p>If <tt>envp</tt> is <tt>null</tt>, the subprocess inherits the
+     * environment settings of the current process.
+     *
+     * <p>A minimal set of system dependent environment variables may
+     * be required to start a process on some operating systems.
+     * As a result, the subprocess may inherit additional environment variable
+     * settings beyond those in the specified environment.
+     *
+     * <p>{@link ProcessBuilder#start()} is now the preferred way to
+     * start a process with a modified environment.
+     *
+     * <p>The working directory of the new subprocess is specified by <tt>dir</tt>.
+     * If <tt>dir</tt> is <tt>null</tt>, the subprocess inherits the
+     * current working directory of the current process.
+     *
+     * <p>If a security manager exists, its
+     * {@link SecurityManager#checkExec checkExec}
+     * method is invoked with the first component of the array
+     * <code>cmdarray</code> as its argument. This may result in a
+     * {@link SecurityException} being thrown.
+     *
+     * <p>Starting an operating system process is highly system-dependent.
+     * Among the many things that can go wrong are:
+     * <ul>
+     * <li>The operating system program file was not found.
+     * <li>Access to the program file was denied.
+     * <li>The working directory does not exist.
+     * </ul>
+     *
+     * <p>In such cases an exception will be thrown.  The exact nature
+     * of the exception is system-dependent, but it will always be a
+     * subclass of {@link IOException}.
+     *
+     *
+     * @param   cmdarray  array containing the command to call and
+     *                    its arguments.
+     *
+     * @param   envp      array of strings, each element of which
+     *                    has environment variable settings in the format
+     *                    <i>name</i>=<i>value</i>, or
+     *                    <tt>null</tt> if the subprocess should inherit
+     *                    the environment of the current process.
+     *
+     * @param   dir       the working directory of the subprocess, or
+     *                    <tt>null</tt> if the subprocess should inherit
+     *                    the working directory of the current process.
+     *
+     * @return  A new {@link Process} object for managing the subprocess
+     *
+     * @throws  SecurityException
+     *          If a security manager exists and its
+     *          {@link SecurityManager#checkExec checkExec}
+     *          method doesn't allow creation of the subprocess
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  NullPointerException
+     *          If <code>cmdarray</code> is <code>null</code>,
+     *          or one of the elements of <code>cmdarray</code> is <code>null</code>,
+     *          or one of the elements of <code>envp</code> is <code>null</code>
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <code>cmdarray</code> is an empty array
+     *          (has length <code>0</code>)
+     *
+     * @see     ProcessBuilder
+     * @since 1.3
+     */
+    public Process exec(String[] cmdarray, String[] envp, File dir)
+        throws IOException {
+        return new ProcessBuilder(cmdarray)
+            .environment(envp)
+            .directory(dir)
+            .start();
+    }
+
+    /**
+     * Returns the number of processors available to the Java virtual machine.
+     *
+     * <p> This value may change during a particular invocation of the virtual
+     * machine.  Applications that are sensitive to the number of available
+     * processors should therefore occasionally poll this property and adjust
+     * their resource usage appropriately. </p>
+     *
+     * @return  the maximum number of processors available to the virtual
+     *          machine; never smaller than one
+     * @since 1.4
+     */
+    public int availableProcessors() {
+        return (int) Libcore.os.sysconf(_SC_NPROCESSORS_CONF);
+    }
+
+    /**
+     * Returns the amount of free memory in the Java Virtual Machine.
+     * Calling the
+     * <code>gc</code> method may result in increasing the value returned
+     * by <code>freeMemory.</code>
+     *
+     * @return  an approximation to the total amount of memory currently
+     *          available for future allocated objects, measured in bytes.
+     */
+    @FastNative
+    public native long freeMemory();
+
+    /**
+     * Returns the total amount of memory in the Java virtual machine.
+     * The value returned by this method may vary over time, depending on
+     * the host environment.
+     * <p>
+     * Note that the amount of memory required to hold an object of any
+     * given type may be implementation-dependent.
+     *
+     * @return  the total amount of memory currently available for current
+     *          and future objects, measured in bytes.
+     */
+    @FastNative
+    public native long totalMemory();
+
+    /**
+     * Returns the maximum amount of memory that the Java virtual machine will
+     * attempt to use.  If there is no inherent limit then the value {@link
+     * java.lang.Long#MAX_VALUE} will be returned.
+     *
+     * @return  the maximum amount of memory that the virtual machine will
+     *          attempt to use, measured in bytes
+     * @since 1.4
+     */
+    @FastNative
+    public native long maxMemory();
+
+    /**
+     * Runs the garbage collector.
+     * Calling this method suggests that the Java virtual machine expend
+     * effort toward recycling unused objects in order to make the memory
+     * they currently occupy available for quick reuse. When control
+     * returns from the method call, the virtual machine has made
+     * its best effort to recycle all discarded objects.
+     * <p>
+     * The name <code>gc</code> stands for "garbage
+     * collector". The virtual machine performs this recycling
+     * process automatically as needed, in a separate thread, even if the
+     * <code>gc</code> method is not invoked explicitly.
+     * <p>
+     * The method {@link System#gc()} is the conventional and convenient
+     * means of invoking this method.
+     */
+    // Android-changed: Added BlockGuard check to gc()
+    // public native void gc();
+    public void gc() {
+        BlockGuard.getThreadPolicy().onExplicitGc();
+        nativeGc();
+    }
+
+    private native void nativeGc();
+
+    /* Wormhole for calling java.lang.ref.Finalizer.runFinalization */
+    private static native void runFinalization0();
+
+    /**
+     * Runs the finalization methods of any objects pending finalization.
+     * Calling this method suggests that the Java virtual machine expend
+     * effort toward running the <code>finalize</code> methods of objects
+     * that have been found to be discarded but whose <code>finalize</code>
+     * methods have not yet been run. When control returns from the
+     * method call, the virtual machine has made a best effort to
+     * complete all outstanding finalizations.
+     * <p>
+     * The virtual machine performs the finalization process
+     * automatically as needed, in a separate thread, if the
+     * <code>runFinalization</code> method is not invoked explicitly.
+     * <p>
+     * The method {@link System#runFinalization()} is the conventional
+     * and convenient means of invoking this method.
+     *
+     * @see     java.lang.Object#finalize()
+     */
+    public void runFinalization() {
+        VMRuntime.runFinalization(0);
+    }
+
+    /**
+     * Enables/Disables tracing of instructions.
+     * If the <code>boolean</code> argument is <code>true</code>, this
+     * method suggests that the Java virtual machine emit debugging
+     * information for each instruction in the virtual machine as it
+     * is executed. The format of this information, and the file or other
+     * output stream to which it is emitted, depends on the host environment.
+     * The virtual machine may ignore this request if it does not support
+     * this feature. The destination of the trace output is system
+     * dependent.
+     * <p>
+     * If the <code>boolean</code> argument is <code>false</code>, this
+     * method causes the virtual machine to stop performing the
+     * detailed instruction trace it is performing.
+     *
+     * @param   on   <code>true</code> to enable instruction tracing;
+     *               <code>false</code> to disable this feature.
+     */
+    public void traceInstructions(boolean on) {
+    }
+
+    /**
+     * Enables/Disables tracing of method calls.
+     * If the <code>boolean</code> argument is <code>true</code>, this
+     * method suggests that the Java virtual machine emit debugging
+     * information for each method in the virtual machine as it is
+     * called. The format of this information, and the file or other output
+     * stream to which it is emitted, depends on the host environment. The
+     * virtual machine may ignore this request if it does not support
+     * this feature.
+     * <p>
+     * Calling this method with argument false suggests that the
+     * virtual machine cease emitting per-call debugging information.
+     * <p>
+     * Calling this method on Android Lollipop or later (API level >= 21)
+     * with {@code true} argument will cause it to throw an
+     * {@code UnsupportedOperationException}.
+     *
+     * @param   on   <code>true</code> to enable instruction tracing;
+     *               <code>false</code> to disable this feature.
+     */
+    public void traceMethodCalls(boolean on) {
+        if (on != tracingMethods) {
+            if (on) {
+                VMDebug.startMethodTracing();
+            } else {
+                VMDebug.stopMethodTracing();
+            }
+            tracingMethods = on;
+        }
+    }
+
+    /**
+     * Loads the native library specified by the filename argument.  The filename
+     * argument must be an absolute path name.
+     * (for example
+     * <code>Runtime.getRuntime().load("/home/avh/lib/libX11.so");</code>).
+     *
+     * If the filename argument, when stripped of any platform-specific library
+     * prefix, path, and file extension, indicates a library whose name is,
+     * for example, L, and a native library called L is statically linked
+     * with the VM, then the JNI_OnLoad_L function exported by the library
+     * is invoked rather than attempting to load a dynamic library.
+     * A filename matching the argument does not have to exist in the file
+     * system. See the JNI Specification for more details.
+     *
+     * Otherwise, the filename argument is mapped to a native library image in
+     * an implementation-dependent manner.
+     * <p>
+     * First, if there is a security manager, its <code>checkLink</code>
+     * method is called with the <code>filename</code> as its argument.
+     * This may result in a security exception.
+     * <p>
+     * This is similar to the method {@link #loadLibrary(String)}, but it
+     * accepts a general file name as an argument rather than just a library
+     * name, allowing any file of native code to be loaded.
+     * <p>
+     * The method {@link System#load(String)} is the conventional and
+     * convenient means of invoking this method.
+     *
+     * @param      filename   the file to load.
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkLink</code> method doesn't allow
+     *             loading of the specified dynamic library
+     * @exception  UnsatisfiedLinkError  if either the filename is not an
+     *             absolute path name, the native library is not statically
+     *             linked with the VM, or the library cannot be mapped to
+     *             a native library image by the host system.
+     * @exception  NullPointerException if <code>filename</code> is
+     *             <code>null</code>
+     * @see        java.lang.Runtime#getRuntime()
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
+     */
+    @CallerSensitive
+    public void load(String filename) {
+        load0(Reflection.getCallerClass(), filename);
+    }
+
+    /** Check target sdk, if it's higher than N, we throw an UnsupportedOperationException */
+    private void checkTargetSdkVersionForLoad(String methodName) {
+        final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 24) {
+            throw new UnsupportedOperationException(methodName + " is not supported on SDK " +
+                                                    targetSdkVersion);
+        }
+    }
+
+    // Fixes b/25859957 regression. Depending on private methods is bad, mkay.
+    void load(String absolutePath, ClassLoader loader) {
+        checkTargetSdkVersionForLoad("java.lang.Runtime#load(String, ClassLoader)");
+
+        java.lang.System.logE("java.lang.Runtime#load(String, ClassLoader)" +
+                              " is private and will be removed in a future Android release");
+        if (absolutePath == null) {
+            throw new NullPointerException("absolutePath == null");
+        }
+        String error = nativeLoad(absolutePath, loader);
+        if (error != null) {
+            throw new UnsatisfiedLinkError(error);
+        }
+    }
+
+    synchronized void load0(Class<?> fromClass, String filename) {
+        if (!(new File(filename).isAbsolute())) {
+            throw new UnsatisfiedLinkError(
+                "Expecting an absolute path of the library: " + filename);
+        }
+        if (filename == null) {
+            throw new NullPointerException("filename == null");
+        }
+        String error = nativeLoad(filename, fromClass.getClassLoader());
+        if (error != null) {
+            throw new UnsatisfiedLinkError(error);
+        }
+    }
+
+    /**
+     * Loads the native library specified by the <code>libname</code>
+     * argument.  The <code>libname</code> argument must not contain any platform
+     * specific prefix, file extension or path. If a native library
+     * called <code>libname</code> is statically linked with the VM, then the
+     * JNI_OnLoad_<code>libname</code> function exported by the library is invoked.
+     * See the JNI Specification for more details.
+     *
+     * Otherwise, the libname argument is loaded from a system library
+     * location and mapped to a native library image in an implementation-
+     * dependent manner.
+     * <p>
+     * First, if there is a security manager, its <code>checkLink</code>
+     * method is called with the <code>libname</code> as its argument.
+     * This may result in a security exception.
+     * <p>
+     * The method {@link System#loadLibrary(String)} is the conventional
+     * and convenient means of invoking this method. If native
+     * methods are to be used in the implementation of a class, a standard
+     * strategy is to put the native code in a library file (call it
+     * <code>LibFile</code>) and then to put a static initializer:
+     * <blockquote><pre>
+     * static { System.loadLibrary("LibFile"); }
+     * </pre></blockquote>
+     * within the class declaration. When the class is loaded and
+     * initialized, the necessary native code implementation for the native
+     * methods will then be loaded as well.
+     * <p>
+     * If this method is called more than once with the same library
+     * name, the second and subsequent calls are ignored.
+     *
+     * @param      libname   the name of the library.
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkLink</code> method doesn't allow
+     *             loading of the specified dynamic library
+     * @exception  UnsatisfiedLinkError if either the libname argument
+     *             contains a file path, the native library is not statically
+     *             linked with the VM,  or the library cannot be mapped to a
+     *             native library image by the host system.
+     * @exception  NullPointerException if <code>libname</code> is
+     *             <code>null</code>
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
+     */
+    @CallerSensitive
+    public void loadLibrary(String libname) {
+        loadLibrary0(Reflection.getCallerClass(), libname);
+    }
+
+    // BEGIN Android-changed: Different implementation of loadLibrary0(Class, String).
+    /*
+    synchronized void loadLibrary0(Class<?> fromClass, String libname) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkLink(libname);
+        }
+        if (libname.indexOf((int)File.separatorChar) != -1) {
+            throw new UnsatisfiedLinkError(
+    "Directory separator should not appear in library name: " + libname);
+        }
+        ClassLoader.loadLibrary(fromClass, libname, false);
+    }
+    */
+    void loadLibrary0(Class<?> fromClass, String libname) {
+        ClassLoader classLoader = ClassLoader.getClassLoader(fromClass);
+        loadLibrary0(classLoader, fromClass, libname);
+    }
+
+    /**
+     * Temporarily preserved for backward compatibility. Applications call this
+     * method using reflection.
+     *
+     * **** THIS METHOD WILL BE REMOVED IN A FUTURE ANDROID VERSION ****
+     *
+     * http://b/26217329
+     *
+     * @hide
+     */
+    public void loadLibrary(String libname, ClassLoader classLoader) {
+        checkTargetSdkVersionForLoad("java.lang.Runtime#loadLibrary(String, ClassLoader)");
+        java.lang.System.logE("java.lang.Runtime#loadLibrary(String, ClassLoader)" +
+                              " is private and will be removed in a future Android release");
+        // Pass null for callerClass, we don't know it at this point. Passing null preserved
+        // the behavior when we used to not pass the class.
+        loadLibrary0(classLoader, null, libname);
+    }
+
+    // This overload exists for @UnsupportedAppUsage
+    void loadLibrary0(ClassLoader loader, String libname) {
+        // Pass null for callerClass, we don't know it at this point. Passing null preserved
+        // the behavior when we used to not pass the class.
+        loadLibrary0(loader, null, libname);
+    }
+    
+    /**
+     * Loads the shared library {@code libname} in the context of {@code loader} and
+     * {@code callerClass}.
+     *
+     * @param      loader    the class loader that initiated the loading. Used by the
+     *                       underlying linker to determine linker namespace. A {@code null}
+     *                       value represents the boot class loader.
+     * @param      fromClass the class that initiated the loading. Used when loader is
+     *                       {@code null} and ignored in all other cases. When used, it 
+     *                       determines the linker namespace from the class's .dex location.
+     *                       {@code null} indicates the default namespace for the boot 
+     *                       class loader.
+     * @param      libname   the name of the library.
+     */
+    private synchronized void loadLibrary0(ClassLoader loader, Class<?> callerClass, String libname) {
+        if (libname.indexOf((int)File.separatorChar) != -1) {
+            throw new UnsatisfiedLinkError(
+    "Directory separator should not appear in library name: " + libname);
+        }
+        String libraryName = libname;
+        // Android-note: BootClassLoader doesn't implement findLibrary(). http://b/111850480
+        // Android's class.getClassLoader() can return BootClassLoader where the RI would
+        // have returned null; therefore we treat BootClassLoader the same as null here.
+        if (loader != null && !(loader instanceof BootClassLoader)) {
+            String filename = loader.findLibrary(libraryName);
+            if (filename == null &&
+                    (loader.getClass() == PathClassLoader.class ||
+                     loader.getClass() == DelegateLastClassLoader.class)) {
+                // Don't give up even if we failed to find the library in the native lib paths.
+                // The underlying dynamic linker might be able to find the lib in one of the linker
+                // namespaces associated with the current linker namespace. In order to give the
+                // dynamic linker a chance, proceed to load the library with its soname, which
+                // is the fileName.
+                // Note that we do this only for PathClassLoader  and DelegateLastClassLoader to
+                // minimize the scope of this behavioral change as much as possible, which might
+                // cause problem like b/143649498. These two class loaders are the only
+                // platform-provided class loaders that can load apps. See the classLoader attribute
+                // of the application tag in app manifest.
+                filename = System.mapLibraryName(libraryName);
+            }
+            if (filename == null) {
+                // It's not necessarily true that the ClassLoader used
+                // System.mapLibraryName, but the default setup does, and it's
+                // misleading to say we didn't find "libMyLibrary.so" when we
+                // actually searched for "liblibMyLibrary.so.so".
+                throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
+                                               System.mapLibraryName(libraryName) + "\"");
+            }
+            String error = nativeLoad(filename, loader);
+            if (error != null) {
+                throw new UnsatisfiedLinkError(error);
+            }
+            return;
+        }
+
+        // We know some apps use mLibPaths directly, potentially assuming it's not null.
+        // Initialize it here to make sure apps see a non-null value.
+        getLibPaths();
+        String filename = System.mapLibraryName(libraryName);
+        String error = nativeLoad(filename, loader, callerClass);
+        if (error != null) {
+            throw new UnsatisfiedLinkError(error);
+        }
+    }
+
+    private volatile String[] mLibPaths = null;
+
+    private String[] getLibPaths() {
+        if (mLibPaths == null) {
+            synchronized(this) {
+                if (mLibPaths == null) {
+                    mLibPaths = initLibPaths();
+                }
+            }
+        }
+        return mLibPaths;
+    }
+
+    private static String[] initLibPaths() {
+        String javaLibraryPath = System.getProperty("java.library.path");
+        if (javaLibraryPath == null) {
+            return EmptyArray.STRING;
+        }
+        String[] paths = javaLibraryPath.split(":");
+        // Add a '/' to the end of each directory so we don't have to do it every time.
+        for (int i = 0; i < paths.length; ++i) {
+            if (!paths[i].endsWith("/")) {
+                paths[i] += "/";
+            }
+        }
+        return paths;
+    }
+
+    private static String nativeLoad(String filename, ClassLoader loader) {
+        return nativeLoad(filename, loader, null);
+    }
+
+    private static native String nativeLoad(String filename, ClassLoader loader, Class<?> caller);
+    // END Android-changed: Different implementation of loadLibrary0(Class, String).
+
+    /**
+     * Creates a localized version of an input stream. This method takes
+     * an <code>InputStream</code> and returns an <code>InputStream</code>
+     * equivalent to the argument in all respects except that it is
+     * localized: as characters in the local character set are read from
+     * the stream, they are automatically converted from the local
+     * character set to Unicode.
+     * <p>
+     * If the argument is already a localized stream, it may be returned
+     * as the result.
+     *
+     * @param      in InputStream to localize
+     * @return     a localized input stream
+     * @see        java.io.InputStream
+     * @see        java.io.BufferedReader#BufferedReader(java.io.Reader)
+     * @see        java.io.InputStreamReader#InputStreamReader(java.io.InputStream)
+     * @deprecated As of JDK&nbsp;1.1, the preferred way to translate a byte
+     * stream in the local encoding into a character stream in Unicode is via
+     * the <code>InputStreamReader</code> and <code>BufferedReader</code>
+     * classes.
+     */
+    @Deprecated
+    public InputStream getLocalizedInputStream(InputStream in) {
+        return in;
+    }
+
+    /**
+     * Creates a localized version of an output stream. This method
+     * takes an <code>OutputStream</code> and returns an
+     * <code>OutputStream</code> equivalent to the argument in all respects
+     * except that it is localized: as Unicode characters are written to
+     * the stream, they are automatically converted to the local
+     * character set.
+     * <p>
+     * If the argument is already a localized stream, it may be returned
+     * as the result.
+     *
+     * @deprecated As of JDK&nbsp;1.1, the preferred way to translate a
+     * Unicode character stream into a byte stream in the local encoding is via
+     * the <code>OutputStreamWriter</code>, <code>BufferedWriter</code>, and
+     * <code>PrintWriter</code> classes.
+     *
+     * @param      out OutputStream to localize
+     * @return     a localized output stream
+     * @see        java.io.OutputStream
+     * @see        java.io.BufferedWriter#BufferedWriter(java.io.Writer)
+     * @see        java.io.OutputStreamWriter#OutputStreamWriter(java.io.OutputStream)
+     * @see        java.io.PrintWriter#PrintWriter(java.io.OutputStream)
+     */
+    @Deprecated
+    public OutputStream getLocalizedOutputStream(OutputStream out) {
+        return out;
+    }
+
+}
diff --git a/java/lang/RuntimeException.java b/java/lang/RuntimeException.java
new file mode 100644
index 0000000..c9731e8
--- /dev/null
+++ b/java/lang/RuntimeException.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * {@code RuntimeException} is the superclass of those
+ * exceptions that can be thrown during the normal operation of the
+ * Java Virtual Machine.
+ *
+ * <p>{@code RuntimeException} and its subclasses are <em>unchecked
+ * exceptions</em>.  Unchecked exceptions do <em>not</em> need to be
+ * declared in a method or constructor's {@code throws} clause if they
+ * can be thrown by the execution of the method or constructor and
+ * propagate outside the method or constructor boundary.
+ *
+ * @author  Frank Yellin
+ * @jls 11.2 Compile-Time Checking of Exceptions
+ * @since   JDK1.0
+ */
+public class RuntimeException extends Exception {
+    static final long serialVersionUID = -7034897190745766939L;
+
+    /** Constructs a new runtime exception with {@code null} as its
+     * detail message.  The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause}.
+     */
+    public RuntimeException() {
+        super();
+    }
+
+    /** Constructs a new runtime exception with the specified detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     *
+     * @param   message   the detail message. The detail message is saved for
+     *          later retrieval by the {@link #getMessage()} method.
+     */
+    public RuntimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new runtime exception with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this runtime exception's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public RuntimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /** Constructs a new runtime exception with the specified cause and a
+     * detail message of <tt>(cause==null ? null : cause.toString())</tt>
+     * (which typically contains the class and detail message of
+     * <tt>cause</tt>).  This constructor is useful for runtime exceptions
+     * that are little more than wrappers for other throwables.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public RuntimeException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new runtime exception with the specified detail
+     * message, cause, suppression enabled or disabled, and writable
+     * stack trace enabled or disabled.
+     *
+     * @param  message the detail message.
+     * @param cause the cause.  (A {@code null} value is permitted,
+     * and indicates that the cause is nonexistent or unknown.)
+     * @param enableSuppression whether or not suppression is enabled
+     *                          or disabled
+     * @param writableStackTrace whether or not the stack trace should
+     *                           be writable
+     *
+     * @since 1.7
+     */
+    protected RuntimeException(String message, Throwable cause,
+                               boolean enableSuppression,
+                               boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/java/lang/RuntimePermission.java b/java/lang/RuntimePermission.java
new file mode 100644
index 0000000..2d05ba1
--- /dev/null
+++ b/java/lang/RuntimePermission.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class RuntimePermission extends BasicPermission {
+
+    private static final long serialVersionUID = 7399184964622342223L;
+
+    public RuntimePermission(String name)
+    {
+        super(name);
+    }
+
+    public RuntimePermission(String name, String actions)
+    {
+        super(name, actions);
+    }
+}
diff --git a/java/lang/SafeVarargs.java b/java/lang/SafeVarargs.java
new file mode 100644
index 0000000..6fcd48e
--- /dev/null
+++ b/java/lang/SafeVarargs.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.*;
+
+/**
+ * A programmer assertion that the body of the annotated method or
+ * constructor does not perform potentially unsafe operations on its
+ * varargs parameter.  Applying this annotation to a method or
+ * constructor suppresses unchecked warnings about a
+ * <i>non-reifiable</i> variable arity (vararg) type and suppresses
+ * unchecked warnings about parameterized array creation at call
+ * sites.
+ *
+ * <p> In addition to the usage restrictions imposed by its {@link
+ * Target @Target} meta-annotation, compilers are required to implement
+ * additional usage restrictions on this annotation type; it is a
+ * compile-time error if a method or constructor declaration is
+ * annotated with a {@code @SafeVarargs} annotation, and either:
+ * <ul>
+ * <li>  the declaration is a fixed arity method or constructor
+ *
+ * <li> the declaration is a variable arity method that is neither
+ * {@code static} nor {@code final}.
+ *
+ * </ul>
+ *
+ * <p> Compilers are encouraged to issue warnings when this annotation
+ * type is applied to a method or constructor declaration where:
+ *
+ * <ul>
+ *
+ * <li> The variable arity parameter has a reifiable element type,
+ * which includes primitive types, {@code Object}, and {@code String}.
+ * (The unchecked warnings this annotation type suppresses already do
+ * not occur for a reifiable element type.)
+ *
+ * <li> The body of the method or constructor declaration performs
+ * potentially unsafe operations, such as an assignment to an element
+ * of the variable arity parameter's array that generates an unchecked
+ * warning.  Some unsafe operations do not trigger an unchecked
+ * warning.  For example, the aliasing in
+ *
+ * <blockquote><pre>
+ * &#64;SafeVarargs // Not actually safe!
+ * static void m(List&lt;String&gt;... stringLists) {
+ *   Object[] array = stringLists;
+ *   List&lt;Integer&gt; tmpList = Arrays.asList(42);
+ *   array[0] = tmpList; // Semantically invalid, but compiles without warnings
+ *   String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
+ * }
+ * </pre></blockquote>
+ *
+ * leads to a {@code ClassCastException} at runtime.
+ *
+ * <p>Future versions of the platform may mandate compiler errors for
+ * such unsafe operations.
+ *
+ * </ul>
+ *
+ * @since 1.7
+ * @jls 4.7 Reifiable Types
+ * @jls 8.4.1 Formal Parameters
+ * @jls 9.6.3.7 @SafeVarargs
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
+public @interface SafeVarargs {}
diff --git a/java/lang/SecurityException.java b/java/lang/SecurityException.java
new file mode 100644
index 0000000..7e07178
--- /dev/null
+++ b/java/lang/SecurityException.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+/**
+ * Thrown by the security manager to indicate a security violation.
+ *
+ * @author  unascribed
+ * @see     java.lang.SecurityManager
+ * @since   JDK1.0
+ */
+public class SecurityException extends RuntimeException {
+
+    private static final long serialVersionUID = 6878364983674394167L;
+
+    /**
+     * Constructs a <code>SecurityException</code> with no detail  message.
+     */
+    public SecurityException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>SecurityException</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public SecurityException(String s) {
+        super(s);
+    }
+
+    /**
+     * Creates a <code>SecurityException</code> with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A <tt>null</tt> value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public SecurityException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a <code>SecurityException</code> with the specified cause
+     * and a detail message of <tt>(cause==null ? null : cause.toString())</tt>
+     * (which typically contains the class and detail message of
+     * <tt>cause</tt>).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A <tt>null</tt> value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public SecurityException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/lang/SecurityManager.java b/java/lang/SecurityManager.java
new file mode 100644
index 0000000..b7053e0
--- /dev/null
+++ b/java/lang/SecurityManager.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.security.*;
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// SecurityManager can only check access by Java code, so it can be bypassed by using
+// native code.  Applications should rely on Android permissions, process separation,
+// other other methods for security purposes.
+/**
+ * Legacy security code; do not use.
+ *
+ * <p>Security managers do <i>not</i> provide a secure environment for
+ * executing untrusted code and are unsupported on Android. Untrusted code
+ * cannot be safely isolated within a single VM on Android. Application
+ * developers can assume that there's no SecurityManager installed,
+ * i.e. {@link java.lang.System#getSecurityManager()} will return null.
+ */
+public
+class SecurityManager {
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected boolean inCheck;
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    public boolean getInCheck() {
+        return inCheck;
+    }
+
+    public SecurityManager() {
+
+    }
+
+    protected Class[] getClassContext() {
+        return null;
+    }
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected ClassLoader currentClassLoader()
+    {
+        return null;
+    }
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected Class<?> currentLoadedClass() {
+        return null;
+    }
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected int classDepth(String name) {
+        return -1;
+    }
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected int classLoaderDepth()
+    {
+        return -1;
+    }
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected boolean inClass(String name) {
+        return false;
+    }
+
+    /**
+     * @deprecated Use {@link #checkPermission} instead.
+     */
+    @Deprecated
+    protected boolean inClassLoader() {
+        return false;
+    }
+
+    public Object getSecurityContext() {
+        return null;
+    }
+
+    public void checkPermission(Permission perm) {
+
+    }
+
+    public void checkPermission(Permission perm, Object context) {
+
+    }
+
+    public void checkCreateClassLoader() {
+
+    }
+
+    public void checkAccess(Thread t) { }
+
+    public void checkAccess(ThreadGroup g) { }
+
+    public void checkExit(int status) { }
+
+    public void checkExec(String cmd) { }
+
+    public void checkLink(String lib) { }
+
+    public void checkRead(FileDescriptor fd) { }
+
+    public void checkRead(String file) { }
+
+    public void checkRead(String file, Object context) { }
+
+    public void checkWrite(FileDescriptor fd) { }
+
+    public void checkWrite(String file) { }
+
+    public void checkDelete(String file) { }
+
+    public void checkConnect(String host, int port) { }
+
+    public void checkConnect(String host, int port, Object context) { }
+
+    public void checkListen(int port) { }
+
+    public void checkAccept(String host, int port) { }
+
+    public void checkMulticast(InetAddress maddr) { }
+
+    /**
+     * @deprecated use {@link #checkMulticast(java.net.InetAddress)} instead.
+     */
+    @Deprecated
+    public void checkMulticast(InetAddress maddr, byte ttl) { }
+
+    public void checkPropertiesAccess() { }
+
+    public void checkPropertyAccess(String key) { }
+
+    public boolean checkTopLevelWindow(Object window) {
+        return true;
+    }
+
+    public void checkPrintJobAccess() { }
+
+    public void checkSystemClipboardAccess() { }
+
+    public void checkAwtEventQueueAccess() { }
+
+    public void checkPackageAccess(String pkg) { }
+
+    public void checkPackageDefinition(String pkg) { }
+
+    public void checkSetFactory() { }
+
+    public void checkMemberAccess(Class<?> clazz, int which) { }
+
+    public void checkSecurityAccess(String target) { }
+
+    /**
+     * Returns the current thread's thread group.
+     */
+    public ThreadGroup getThreadGroup() {
+        return Thread.currentThread().getThreadGroup();
+    }
+
+}
diff --git a/java/lang/Short.java b/java/lang/Short.java
new file mode 100644
index 0000000..9fb3913
--- /dev/null
+++ b/java/lang/Short.java
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * The {@code Short} class wraps a value of primitive type {@code
+ * short} in an object.  An object of type {@code Short} contains a
+ * single field whose type is {@code short}.
+ *
+ * <p>In addition, this class provides several methods for converting
+ * a {@code short} to a {@code String} and a {@code String} to a
+ * {@code short}, as well as other constants and methods useful when
+ * dealing with a {@code short}.
+ *
+ * @author  Nakul Saraiya
+ * @author  Joseph D. Darcy
+ * @see     java.lang.Number
+ * @since   JDK1.1
+ */
+public final class Short extends Number implements Comparable<Short> {
+
+    /**
+     * A constant holding the minimum value a {@code short} can
+     * have, -2<sup>15</sup>.
+     */
+    public static final short   MIN_VALUE = -32768;
+
+    /**
+     * A constant holding the maximum value a {@code short} can
+     * have, 2<sup>15</sup>-1.
+     */
+    public static final short   MAX_VALUE = 32767;
+
+    /**
+     * The {@code Class} instance representing the primitive type
+     * {@code short}.
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Short>    TYPE = (Class<Short>) Class.getPrimitiveClass("short");
+
+    /**
+     * Returns a new {@code String} object representing the
+     * specified {@code short}. The radix is assumed to be 10.
+     *
+     * @param s the {@code short} to be converted
+     * @return the string representation of the specified {@code short}
+     * @see java.lang.Integer#toString(int)
+     */
+    public static String toString(short s) {
+        return Integer.toString((int)s, 10);
+    }
+
+    /**
+     * Parses the string argument as a signed {@code short} in the
+     * radix specified by the second argument. The characters in the
+     * string must all be digits, of the specified radix (as
+     * determined by whether {@link java.lang.Character#digit(char,
+     * int)} returns a nonnegative value) except that the first
+     * character may be an ASCII minus sign {@code '-'}
+     * ({@code '\u005Cu002D'}) to indicate a negative value or an
+     * ASCII plus sign {@code '+'} ({@code '\u005Cu002B'}) to
+     * indicate a positive value.  The resulting {@code short} value
+     * is returned.
+     *
+     * <p>An exception of type {@code NumberFormatException} is
+     * thrown if any of the following situations occurs:
+     * <ul>
+     * <li> The first argument is {@code null} or is a string of
+     * length zero.
+     *
+     * <li> The radix is either smaller than {@link
+     * java.lang.Character#MIN_RADIX} or larger than {@link
+     * java.lang.Character#MAX_RADIX}.
+     *
+     * <li> Any character of the string is not a digit of the
+     * specified radix, except that the first character may be a minus
+     * sign {@code '-'} ({@code '\u005Cu002D'}) or plus sign
+     * {@code '+'} ({@code '\u005Cu002B'}) provided that the
+     * string is longer than length 1.
+     *
+     * <li> The value represented by the string is not a value of type
+     * {@code short}.
+     * </ul>
+     *
+     * @param s         the {@code String} containing the
+     *                  {@code short} representation to be parsed
+     * @param radix     the radix to be used while parsing {@code s}
+     * @return          the {@code short} represented by the string
+     *                  argument in the specified radix.
+     * @throws          NumberFormatException If the {@code String}
+     *                  does not contain a parsable {@code short}.
+     */
+    public static short parseShort(String s, int radix)
+        throws NumberFormatException {
+        int i = Integer.parseInt(s, radix);
+        if (i < MIN_VALUE || i > MAX_VALUE)
+            throw new NumberFormatException(
+                "Value out of range. Value:\"" + s + "\" Radix:" + radix);
+        return (short)i;
+    }
+
+    /**
+     * Parses the string argument as a signed decimal {@code
+     * short}. The characters in the string must all be decimal
+     * digits, except that the first character may be an ASCII minus
+     * sign {@code '-'} ({@code '\u005Cu002D'}) to indicate a
+     * negative value or an ASCII plus sign {@code '+'}
+     * ({@code '\u005Cu002B'}) to indicate a positive value.  The
+     * resulting {@code short} value is returned, exactly as if the
+     * argument and the radix 10 were given as arguments to the {@link
+     * #parseShort(java.lang.String, int)} method.
+     *
+     * @param s a {@code String} containing the {@code short}
+     *          representation to be parsed
+     * @return  the {@code short} value represented by the
+     *          argument in decimal.
+     * @throws  NumberFormatException If the string does not
+     *          contain a parsable {@code short}.
+     */
+    public static short parseShort(String s) throws NumberFormatException {
+        return parseShort(s, 10);
+    }
+
+    /**
+     * Returns a {@code Short} object holding the value
+     * extracted from the specified {@code String} when parsed
+     * with the radix given by the second argument. The first argument
+     * is interpreted as representing a signed {@code short} in
+     * the radix specified by the second argument, exactly as if the
+     * argument were given to the {@link #parseShort(java.lang.String,
+     * int)} method. The result is a {@code Short} object that
+     * represents the {@code short} value specified by the string.
+     *
+     * <p>In other words, this method returns a {@code Short} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     *  {@code new Short(Short.parseShort(s, radix))}
+     * </blockquote>
+     *
+     * @param s         the string to be parsed
+     * @param radix     the radix to be used in interpreting {@code s}
+     * @return          a {@code Short} object holding the value
+     *                  represented by the string argument in the
+     *                  specified radix.
+     * @throws          NumberFormatException If the {@code String} does
+     *                  not contain a parsable {@code short}.
+     */
+    public static Short valueOf(String s, int radix)
+        throws NumberFormatException {
+        return valueOf(parseShort(s, radix));
+    }
+
+    /**
+     * Returns a {@code Short} object holding the
+     * value given by the specified {@code String}. The argument
+     * is interpreted as representing a signed decimal
+     * {@code short}, exactly as if the argument were given to
+     * the {@link #parseShort(java.lang.String)} method. The result is
+     * a {@code Short} object that represents the
+     * {@code short} value specified by the string.
+     *
+     * <p>In other words, this method returns a {@code Short} object
+     * equal to the value of:
+     *
+     * <blockquote>
+     *  {@code new Short(Short.parseShort(s))}
+     * </blockquote>
+     *
+     * @param s the string to be parsed
+     * @return  a {@code Short} object holding the value
+     *          represented by the string argument
+     * @throws  NumberFormatException If the {@code String} does
+     *          not contain a parsable {@code short}.
+     */
+    public static Short valueOf(String s) throws NumberFormatException {
+        return valueOf(s, 10);
+    }
+
+    private static class ShortCache {
+        private ShortCache(){}
+
+        static final Short cache[] = new Short[-(-128) + 127 + 1];
+
+        static {
+            for(int i = 0; i < cache.length; i++)
+                cache[i] = new Short((short)(i - 128));
+        }
+    }
+
+    /**
+     * Returns a {@code Short} instance representing the specified
+     * {@code short} value.
+     * If a new {@code Short} instance is not required, this method
+     * should generally be used in preference to the constructor
+     * {@link #Short(short)}, as this method is likely to yield
+     * significantly better space and time performance by caching
+     * frequently requested values.
+     *
+     * This method will always cache values in the range -128 to 127,
+     * inclusive, and may cache other values outside of this range.
+     *
+     * @param  s a short value.
+     * @return a {@code Short} instance representing {@code s}.
+     * @since  1.5
+     */
+    public static Short valueOf(short s) {
+        final int offset = 128;
+        int sAsInt = s;
+        if (sAsInt >= -128 && sAsInt <= 127) { // must cache
+            return ShortCache.cache[sAsInt + offset];
+        }
+        return new Short(s);
+    }
+
+    /**
+     * Decodes a {@code String} into a {@code Short}.
+     * Accepts decimal, hexadecimal, and octal numbers given by
+     * the following grammar:
+     *
+     * <blockquote>
+     * <dl>
+     * <dt><i>DecodableString:</i>
+     * <dd><i>Sign<sub>opt</sub> DecimalNumeral</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0x} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0X} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code #} <i>HexDigits</i>
+     * <dd><i>Sign<sub>opt</sub></i> {@code 0} <i>OctalDigits</i>
+     *
+     * <dt><i>Sign:</i>
+     * <dd>{@code -}
+     * <dd>{@code +}
+     * </dl>
+     * </blockquote>
+     *
+     * <i>DecimalNumeral</i>, <i>HexDigits</i>, and <i>OctalDigits</i>
+     * are as defined in section 3.10.1 of
+     * <cite>The Java&trade; Language Specification</cite>,
+     * except that underscores are not accepted between digits.
+     *
+     * <p>The sequence of characters following an optional
+     * sign and/or radix specifier ("{@code 0x}", "{@code 0X}",
+     * "{@code #}", or leading zero) is parsed as by the {@code
+     * Short.parseShort} method with the indicated radix (10, 16, or
+     * 8).  This sequence of characters must represent a positive
+     * value or a {@link NumberFormatException} will be thrown.  The
+     * result is negated if first character of the specified {@code
+     * String} is the minus sign.  No whitespace characters are
+     * permitted in the {@code String}.
+     *
+     * @param     nm the {@code String} to decode.
+     * @return    a {@code Short} object holding the {@code short}
+     *            value represented by {@code nm}
+     * @throws    NumberFormatException  if the {@code String} does not
+     *            contain a parsable {@code short}.
+     * @see java.lang.Short#parseShort(java.lang.String, int)
+     */
+    public static Short decode(String nm) throws NumberFormatException {
+        int i = Integer.decode(nm);
+        if (i < MIN_VALUE || i > MAX_VALUE)
+            throw new NumberFormatException(
+                    "Value " + i + " out of range from input " + nm);
+        return valueOf((short)i);
+    }
+
+    /**
+     * The value of the {@code Short}.
+     *
+     * @serial
+     */
+    private final short value;
+
+    /**
+     * Constructs a newly allocated {@code Short} object that
+     * represents the specified {@code short} value.
+     *
+     * @param value     the value to be represented by the
+     *                  {@code Short}.
+     */
+    public Short(short value) {
+        this.value = value;
+    }
+
+    /**
+     * Constructs a newly allocated {@code Short} object that
+     * represents the {@code short} value indicated by the
+     * {@code String} parameter. The string is converted to a
+     * {@code short} value in exactly the manner used by the
+     * {@code parseShort} method for radix 10.
+     *
+     * @param s the {@code String} to be converted to a
+     *          {@code Short}
+     * @throws  NumberFormatException If the {@code String}
+     *          does not contain a parsable {@code short}.
+     * @see     java.lang.Short#parseShort(java.lang.String, int)
+     */
+    public Short(String s) throws NumberFormatException {
+        this.value = parseShort(s, 10);
+    }
+
+    /**
+     * Returns the value of this {@code Short} as a {@code byte} after
+     * a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public byte byteValue() {
+        return (byte)value;
+    }
+
+    /**
+     * Returns the value of this {@code Short} as a
+     * {@code short}.
+     */
+    public short shortValue() {
+        return value;
+    }
+
+    /**
+     * Returns the value of this {@code Short} as an {@code int} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public int intValue() {
+        return (int)value;
+    }
+
+    /**
+     * Returns the value of this {@code Short} as a {@code long} after
+     * a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public long longValue() {
+        return (long)value;
+    }
+
+    /**
+     * Returns the value of this {@code Short} as a {@code float}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)value;
+    }
+
+    /**
+     * Returns the value of this {@code Short} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)value;
+    }
+
+    /**
+     * Returns a {@code String} object representing this
+     * {@code Short}'s value.  The value is converted to signed
+     * decimal representation and returned as a string, exactly as if
+     * the {@code short} value were given as an argument to the
+     * {@link java.lang.Short#toString(short)} method.
+     *
+     * @return  a string representation of the value of this object in
+     *          base&nbsp;10.
+     */
+    public String toString() {
+        return Integer.toString((int)value);
+    }
+
+    /**
+     * Returns a hash code for this {@code Short}; equal to the result
+     * of invoking {@code intValue()}.
+     *
+     * @return a hash code value for this {@code Short}
+     */
+    @Override
+    public int hashCode() {
+        return Short.hashCode(value);
+    }
+
+    /**
+     * Returns a hash code for a {@code short} value; compatible with
+     * {@code Short.hashCode()}.
+     *
+     * @param value the value to hash
+     * @return a hash code value for a {@code short} value.
+     * @since 1.8
+     */
+    public static int hashCode(short value) {
+        return (int)value;
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is
+     * {@code true} if and only if the argument is not
+     * {@code null} and is a {@code Short} object that
+     * contains the same {@code short} value as this object.
+     *
+     * @param obj       the object to compare with
+     * @return          {@code true} if the objects are the same;
+     *                  {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj instanceof Short) {
+            return value == ((Short)obj).shortValue();
+        }
+        return false;
+    }
+
+    /**
+     * Compares two {@code Short} objects numerically.
+     *
+     * @param   anotherShort   the {@code Short} to be compared.
+     * @return  the value {@code 0} if this {@code Short} is
+     *          equal to the argument {@code Short}; a value less than
+     *          {@code 0} if this {@code Short} is numerically less
+     *          than the argument {@code Short}; and a value greater than
+     *           {@code 0} if this {@code Short} is numerically
+     *           greater than the argument {@code Short} (signed
+     *           comparison).
+     * @since   1.2
+     */
+    public int compareTo(Short anotherShort) {
+        return compare(this.value, anotherShort.value);
+    }
+
+    /**
+     * Compares two {@code short} values numerically.
+     * The value returned is identical to what would be returned by:
+     * <pre>
+     *    Short.valueOf(x).compareTo(Short.valueOf(y))
+     * </pre>
+     *
+     * @param  x the first {@code short} to compare
+     * @param  y the second {@code short} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 1.7
+     */
+    public static int compare(short x, short y) {
+        return x - y;
+    }
+
+    /**
+     * The number of bits used to represent a {@code short} value in two's
+     * complement binary form.
+     * @since 1.5
+     */
+    public static final int SIZE = 16;
+
+    /**
+     * The number of bytes used to represent a {@code short} value in two's
+     * complement binary form.
+     *
+     * @since 1.8
+     */
+    public static final int BYTES = SIZE / Byte.SIZE;
+
+    /**
+     * Returns the value obtained by reversing the order of the bytes in the
+     * two's complement representation of the specified {@code short} value.
+     *
+     * @param i the value whose bytes are to be reversed
+     * @return the value obtained by reversing (or, equivalently, swapping)
+     *     the bytes in the specified {@code short} value.
+     * @since 1.5
+     */
+    public static short reverseBytes(short i) {
+        return (short) (((i & 0xFF00) >> 8) | (i << 8));
+    }
+
+
+    /**
+     * Converts the argument to an {@code int} by an unsigned
+     * conversion.  In an unsigned conversion to an {@code int}, the
+     * high-order 16 bits of the {@code int} are zero and the
+     * low-order 16 bits are equal to the bits of the {@code short} argument.
+     *
+     * Consequently, zero and positive {@code short} values are mapped
+     * to a numerically equal {@code int} value and negative {@code
+     * short} values are mapped to an {@code int} value equal to the
+     * input plus 2<sup>16</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code int}
+     * @return the argument converted to {@code int} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static int toUnsignedInt(short x) {
+        return ((int) x) & 0xffff;
+    }
+
+    /**
+     * Converts the argument to a {@code long} by an unsigned
+     * conversion.  In an unsigned conversion to a {@code long}, the
+     * high-order 48 bits of the {@code long} are zero and the
+     * low-order 16 bits are equal to the bits of the {@code short} argument.
+     *
+     * Consequently, zero and positive {@code short} values are mapped
+     * to a numerically equal {@code long} value and negative {@code
+     * short} values are mapped to a {@code long} value equal to the
+     * input plus 2<sup>16</sup>.
+     *
+     * @param  x the value to convert to an unsigned {@code long}
+     * @return the argument converted to {@code long} by an unsigned
+     *         conversion
+     * @since 1.8
+     */
+    public static long toUnsignedLong(short x) {
+        return ((long) x) & 0xffffL;
+    }
+
+    /** use serialVersionUID from JDK 1.1. for interoperability */
+    private static final long serialVersionUID = 7515723908773894738L;
+}
diff --git a/java/lang/StackOverflowError.java b/java/lang/StackOverflowError.java
new file mode 100644
index 0000000..73fd8c1
--- /dev/null
+++ b/java/lang/StackOverflowError.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when a stack overflow occurs because an application
+ * recurses too deeply.
+ *
+ * @author unascribed
+ * @since   JDK1.0
+ */
+public
+class StackOverflowError extends VirtualMachineError {
+    private static final long serialVersionUID = 8609175038441759607L;
+
+    /**
+     * Constructs a <code>StackOverflowError</code> with no detail message.
+     */
+    public StackOverflowError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>StackOverflowError</code> with the specified
+     * detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public StackOverflowError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/StackTraceElement.java b/java/lang/StackTraceElement.java
new file mode 100644
index 0000000..e3dad88
--- /dev/null
+++ b/java/lang/StackTraceElement.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.util.Objects;
+
+/**
+ * An element in a stack trace, as returned by {@link
+ * Throwable#getStackTrace()}.  Each element represents a single stack frame.
+ * All stack frames except for the one at the top of the stack represent
+ * a method invocation.  The frame at the top of the stack represents the
+ * execution point at which the stack trace was generated.  Typically,
+ * this is the point at which the throwable corresponding to the stack trace
+ * was created.
+ *
+ * @since  1.4
+ * @author Josh Bloch
+ */
+public final class StackTraceElement implements java.io.Serializable {
+    // Normally initialized by VM (public constructor added in 1.5)
+    private String declaringClass;
+    private String methodName;
+    private String fileName;
+    private int    lineNumber;
+
+    /**
+     * Creates a stack trace element representing the specified execution
+     * point.
+     *
+     * @param declaringClass the fully qualified name of the class containing
+     *        the execution point represented by the stack trace element
+     * @param methodName the name of the method containing the execution point
+     *        represented by the stack trace element
+     * @param fileName the name of the file containing the execution point
+     *         represented by the stack trace element, or {@code null} if
+     *         this information is unavailable
+     * @param lineNumber the line number of the source line containing the
+     *         execution point represented by this stack trace element, or
+     *         a negative number if this information is unavailable. A value
+     *         of -2 indicates that the method containing the execution point
+     *         is a native method
+     * @throws NullPointerException if {@code declaringClass} or
+     *         {@code methodName} is null
+     * @since 1.5
+     */
+    public StackTraceElement(String declaringClass, String methodName,
+                             String fileName, int lineNumber) {
+        this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null");
+        this.methodName     = Objects.requireNonNull(methodName, "Method name is null");
+        this.fileName       = fileName;
+        this.lineNumber     = lineNumber;
+    }
+
+    /**
+     * Returns the name of the source file containing the execution point
+     * represented by this stack trace element.  Generally, this corresponds
+     * to the {@code SourceFile} attribute of the relevant {@code class}
+     * file (as per <i>The Java Virtual Machine Specification</i>, Section
+     * 4.7.7).  In some systems, the name may refer to some source code unit
+     * other than a file, such as an entry in source repository.
+     *
+     * @return the name of the file containing the execution point
+     *         represented by this stack trace element, or {@code null} if
+     *         this information is unavailable.
+     */
+    public String getFileName() {
+        return fileName;
+    }
+
+    /**
+     * Returns the line number of the source line containing the execution
+     * point represented by this stack trace element.  Generally, this is
+     * derived from the {@code LineNumberTable} attribute of the relevant
+     * {@code class} file (as per <i>The Java Virtual Machine
+     * Specification</i>, Section 4.7.8).
+     *
+     * @return the line number of the source line containing the execution
+     *         point represented by this stack trace element, or a negative
+     *         number if this information is unavailable.
+     */
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    /**
+     * Returns the fully qualified name of the class containing the
+     * execution point represented by this stack trace element.
+     *
+     * @return the fully qualified name of the {@code Class} containing
+     *         the execution point represented by this stack trace element.
+     */
+    public String getClassName() {
+        return declaringClass;
+    }
+
+    /**
+     * Returns the name of the method containing the execution point
+     * represented by this stack trace element.  If the execution point is
+     * contained in an instance or class initializer, this method will return
+     * the appropriate <i>special method name</i>, {@code <init>} or
+     * {@code <clinit>}, as per Section 3.9 of <i>The Java Virtual
+     * Machine Specification</i>.
+     *
+     * @return the name of the method containing the execution point
+     *         represented by this stack trace element.
+     */
+    public String getMethodName() {
+        return methodName;
+    }
+
+    /**
+     * Returns true if the method containing the execution point
+     * represented by this stack trace element is a native method.
+     *
+     * @return {@code true} if the method containing the execution point
+     *         represented by this stack trace element is a native method.
+     */
+    public boolean isNativeMethod() {
+        return lineNumber == -2;
+    }
+
+    /**
+     * Returns a string representation of this stack trace element.  The
+     * format of this string depends on the implementation, but the following
+     * examples may be regarded as typical:
+     * <ul>
+     * <li>
+     *   {@code "MyClass.mash(MyClass.java:9)"} - Here, {@code "MyClass"}
+     *   is the <i>fully-qualified name</i> of the class containing the
+     *   execution point represented by this stack trace element,
+     *   {@code "mash"} is the name of the method containing the execution
+     *   point, {@code "MyClass.java"} is the source file containing the
+     *   execution point, and {@code "9"} is the line number of the source
+     *   line containing the execution point.
+     * <li>
+     *   {@code "MyClass.mash(MyClass.java)"} - As above, but the line
+     *   number is unavailable.
+     * <li>
+     *   {@code "MyClass.mash(Unknown Source)"} - As above, but neither
+     *   the file name nor the line  number are available.
+     * <li>
+     *   {@code "MyClass.mash(Native Method)"} - As above, but neither
+     *   the file name nor the line  number are available, and the method
+     *   containing the execution point is known to be a native method.
+     * </ul>
+     * @see    Throwable#printStackTrace()
+     */
+    public String toString() {
+        // BEGIN Android-changed: Fall back Unknown Source:<dex_pc> for unknown lineNumber.
+        // http://b/30183883
+        // The only behavior change is that "Unknown Source" is followed by a number
+        // (the value of the dex program counter, dex_pc), which never occurs on the
+        // RI. This value isn't a line number, but can be useful for debugging and
+        // avoids the need to ship line number information along with the dex code to
+        // get an accurate stack trace.
+        // Formatting it in this way might be more digestible to automated tools that
+        // are not specifically written to expect this behavior.
+        /*
+        return getClassName() + "." + methodName +
+            (isNativeMethod() ? "(Native Method)" :
+             (fileName != null && lineNumber >= 0 ?
+              "(" + fileName + ":" + lineNumber + ")" :
+              (fileName != null ?  "("+fileName+")" : "(Unknown Source)")));
+        */
+        StringBuilder result = new StringBuilder();
+        result.append(getClassName()).append(".").append(methodName);
+        if (isNativeMethod()) {
+            result.append("(Native Method)");
+        } else if (fileName != null) {
+            if (lineNumber >= 0) {
+                result.append("(").append(fileName).append(":").append(lineNumber).append(")");
+            } else {
+                result.append("(").append(fileName).append(")");
+            }
+        } else {
+            if (lineNumber >= 0) {
+                // The line number is actually the dex pc.
+                result.append("(Unknown Source:").append(lineNumber).append(")");
+            } else {
+                result.append("(Unknown Source)");
+            }
+        }
+        return result.toString();
+        // END Android-changed: Fall back Unknown Source:<dex_pc> for unknown lineNumber.
+    }
+
+    /**
+     * Returns true if the specified object is another
+     * {@code StackTraceElement} instance representing the same execution
+     * point as this instance.  Two stack trace elements {@code a} and
+     * {@code b} are equal if and only if:
+     * <pre>{@code
+     *     equals(a.getFileName(), b.getFileName()) &&
+     *     a.getLineNumber() == b.getLineNumber()) &&
+     *     equals(a.getClassName(), b.getClassName()) &&
+     *     equals(a.getMethodName(), b.getMethodName())
+     * }</pre>
+     * where {@code equals} has the semantics of {@link
+     * java.util.Objects#equals(Object, Object) Objects.equals}.
+     *
+     * @param  obj the object to be compared with this stack trace element.
+     * @return true if the specified object is another
+     *         {@code StackTraceElement} instance representing the same
+     *         execution point as this instance.
+     */
+    public boolean equals(Object obj) {
+        if (obj==this)
+            return true;
+        if (!(obj instanceof StackTraceElement))
+            return false;
+        StackTraceElement e = (StackTraceElement)obj;
+        return e.declaringClass.equals(declaringClass) &&
+            e.lineNumber == lineNumber &&
+            Objects.equals(methodName, e.methodName) &&
+            Objects.equals(fileName, e.fileName);
+    }
+
+    /**
+     * Returns a hash code value for this stack trace element.
+     */
+    public int hashCode() {
+        int result = 31*declaringClass.hashCode() + methodName.hashCode();
+        result = 31*result + Objects.hashCode(fileName);
+        result = 31*result + lineNumber;
+        return result;
+    }
+
+    private static final long serialVersionUID = 6992337162326171013L;
+}
diff --git a/java/lang/StrictMath.java b/java/lang/StrictMath.java
new file mode 100644
index 0000000..ae4af2b
--- /dev/null
+++ b/java/lang/StrictMath.java
@@ -0,0 +1,1710 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+import java.util.Random;
+import sun.misc.DoubleConsts;
+
+/**
+ * The class {@code StrictMath} contains methods for performing basic
+ * numeric operations such as the elementary exponential, logarithm,
+ * square root, and trigonometric functions.
+ *
+ * <p>To help ensure portability of Java programs, the definitions of
+ * some of the numeric functions in this package require that they
+ * produce the same results as certain published algorithms. These
+ * algorithms are available from the well-known network library
+ * {@code netlib} as the package "Freely Distributable Math
+ * Library," <a
+ * href="ftp://ftp.netlib.org/fdlibm.tar">{@code fdlibm}</a>. These
+ * algorithms, which are written in the C programming language, are
+ * then to be understood as executed with all floating-point
+ * operations following the rules of Java floating-point arithmetic.
+ *
+ * <p>The Java math library is defined with respect to
+ * {@code fdlibm} version 5.3. Where {@code fdlibm} provides
+ * more than one definition for a function (such as
+ * {@code acos}), use the "IEEE 754 core function" version
+ * (residing in a file whose name begins with the letter
+ * {@code e}).  The methods which require {@code fdlibm}
+ * semantics are {@code sin}, {@code cos}, {@code tan},
+ * {@code asin}, {@code acos}, {@code atan},
+ * {@code exp}, {@code log}, {@code log10},
+ * {@code cbrt}, {@code atan2}, {@code pow},
+ * {@code sinh}, {@code cosh}, {@code tanh},
+ * {@code hypot}, {@code expm1}, and {@code log1p}.
+ *
+ * <p>
+ * The platform uses signed two's complement integer arithmetic with
+ * int and long primitive types.  The developer should choose
+ * the primitive type to ensure that arithmetic operations consistently
+ * produce correct results, which in some cases means the operations
+ * will not overflow the range of values of the computation.
+ * The best practice is to choose the primitive type and algorithm to avoid
+ * overflow. In cases where the size is {@code int} or {@code long} and
+ * overflow errors need to be detected, the methods {@code addExact},
+ * {@code subtractExact}, {@code multiplyExact}, and {@code toIntExact}
+ * throw an {@code ArithmeticException} when the results overflow.
+ * For other arithmetic operations such as divide, absolute value,
+ * increment, decrement, and negation overflow occurs only with
+ * a specific minimum or maximum value and should be checked against
+ * the minimum or maximum as appropriate.
+ *
+ * @author  unascribed
+ * @author  Joseph D. Darcy
+ * @since   1.3
+ */
+
+public final class StrictMath {
+
+    /**
+     * Don't let anyone instantiate this class.
+     */
+    private StrictMath() {}
+
+    /**
+     * The {@code double} value that is closer than any other to
+     * <i>e</i>, the base of the natural logarithms.
+     */
+    public static final double E = 2.7182818284590452354;
+
+    /**
+     * The {@code double} value that is closer than any other to
+     * <i>pi</i>, the ratio of the circumference of a circle to its
+     * diameter.
+     */
+    public static final double PI = 3.14159265358979323846;
+
+    /**
+     * Returns the trigonometric sine of an angle. Special cases:
+     * <ul><li>If the argument is NaN or an infinity, then the
+     * result is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * @param   a   an angle, in radians.
+     * @return  the sine of the argument.
+     */
+    public static native double sin(double a);
+
+    /**
+     * Returns the trigonometric cosine of an angle. Special cases:
+     * <ul><li>If the argument is NaN or an infinity, then the
+     * result is NaN.</ul>
+     *
+     * @param   a   an angle, in radians.
+     * @return  the cosine of the argument.
+     */
+    public static native double cos(double a);
+
+    /**
+     * Returns the trigonometric tangent of an angle. Special cases:
+     * <ul><li>If the argument is NaN or an infinity, then the result
+     * is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * @param   a   an angle, in radians.
+     * @return  the tangent of the argument.
+     */
+    public static native double tan(double a);
+
+    /**
+     * Returns the arc sine of a value; the returned angle is in the
+     * range -<i>pi</i>/2 through <i>pi</i>/2.  Special cases:
+     * <ul><li>If the argument is NaN or its absolute value is greater
+     * than 1, then the result is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * @param   a   the value whose arc sine is to be returned.
+     * @return  the arc sine of the argument.
+     */
+    public static native double asin(double a);
+
+    /**
+     * Returns the arc cosine of a value; the returned angle is in the
+     * range 0.0 through <i>pi</i>.  Special case:
+     * <ul><li>If the argument is NaN or its absolute value is greater
+     * than 1, then the result is NaN.</ul>
+     *
+     * @param   a   the value whose arc cosine is to be returned.
+     * @return  the arc cosine of the argument.
+     */
+    public static native double acos(double a);
+
+    /**
+     * Returns the arc tangent of a value; the returned angle is in the
+     * range -<i>pi</i>/2 through <i>pi</i>/2.  Special cases:
+     * <ul><li>If the argument is NaN, then the result is NaN.
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.</ul>
+     *
+     * @param   a   the value whose arc tangent is to be returned.
+     * @return  the arc tangent of the argument.
+     */
+    public static native double atan(double a);
+
+    /**
+     * Converts an angle measured in degrees to an approximately
+     * equivalent angle measured in radians.  The conversion from
+     * degrees to radians is generally inexact.
+     *
+     * @param   angdeg   an angle, in degrees
+     * @return  the measurement of the angle {@code angdeg}
+     *          in radians.
+     */
+    public static strictfp double toRadians(double angdeg) {
+        // Do not delegate to Math.toRadians(angdeg) because
+        // this method has the strictfp modifier.
+        return angdeg / 180.0 * PI;
+    }
+
+    /**
+     * Converts an angle measured in radians to an approximately
+     * equivalent angle measured in degrees.  The conversion from
+     * radians to degrees is generally inexact; users should
+     * <i>not</i> expect {@code cos(toRadians(90.0))} to exactly
+     * equal {@code 0.0}.
+     *
+     * @param   angrad   an angle, in radians
+     * @return  the measurement of the angle {@code angrad}
+     *          in degrees.
+     */
+    public static strictfp double toDegrees(double angrad) {
+        // Do not delegate to Math.toDegrees(angrad) because
+        // this method has the strictfp modifier.
+        return angrad * 180.0 / PI;
+    }
+
+    /**
+     * Returns Euler's number <i>e</i> raised to the power of a
+     * {@code double} value. Special cases:
+     * <ul><li>If the argument is NaN, the result is NaN.
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     * <li>If the argument is negative infinity, then the result is
+     * positive zero.</ul>
+     *
+     * @param   a   the exponent to raise <i>e</i> to.
+     * @return  the value <i>e</i><sup>{@code a}</sup>,
+     *          where <i>e</i> is the base of the natural logarithms.
+     */
+    public static native double exp(double a);
+
+    /**
+     * Returns the natural logarithm (base <i>e</i>) of a {@code double}
+     * value. Special cases:
+     * <ul><li>If the argument is NaN or less than zero, then the result
+     * is NaN.
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     * <li>If the argument is positive zero or negative zero, then the
+     * result is negative infinity.</ul>
+     *
+     * @param   a   a value
+     * @return  the value ln&nbsp;{@code a}, the natural logarithm of
+     *          {@code a}.
+     */
+    public static native double log(double a);
+
+
+    /**
+     * Returns the base 10 logarithm of a {@code double} value.
+     * Special cases:
+     *
+     * <ul><li>If the argument is NaN or less than zero, then the result
+     * is NaN.
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     * <li>If the argument is positive zero or negative zero, then the
+     * result is negative infinity.
+     * <li> If the argument is equal to 10<sup><i>n</i></sup> for
+     * integer <i>n</i>, then the result is <i>n</i>.
+     * </ul>
+     *
+     * @param   a   a value
+     * @return  the base 10 logarithm of  {@code a}.
+     * @since 1.5
+     */
+    public static native double log10(double a);
+
+    /**
+     * Returns the correctly rounded positive square root of a
+     * {@code double} value.
+     * Special cases:
+     * <ul><li>If the argument is NaN or less than zero, then the result
+     * is NaN.
+     * <li>If the argument is positive infinity, then the result is positive
+     * infinity.
+     * <li>If the argument is positive zero or negative zero, then the
+     * result is the same as the argument.</ul>
+     * Otherwise, the result is the {@code double} value closest to
+     * the true mathematical square root of the argument value.
+     *
+     * @param   a   a value.
+     * @return  the positive square root of {@code a}.
+     */
+    public static native double sqrt(double a);
+
+    /**
+     * Returns the cube root of a {@code double} value.  For
+     * positive finite {@code x}, {@code cbrt(-x) ==
+     * -cbrt(x)}; that is, the cube root of a negative value is
+     * the negative of the cube root of that value's magnitude.
+     * Special cases:
+     *
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is infinite, then the result is an infinity
+     * with the same sign as the argument.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * @param   a   a value.
+     * @return  the cube root of {@code a}.
+     * @since 1.5
+     */
+    public static native double cbrt(double a);
+
+    /**
+     * Computes the remainder operation on two arguments as prescribed
+     * by the IEEE 754 standard.
+     * The remainder value is mathematically equal to
+     * <code>f1&nbsp;-&nbsp;f2</code>&nbsp;&times;&nbsp;<i>n</i>,
+     * where <i>n</i> is the mathematical integer closest to the exact
+     * mathematical value of the quotient {@code f1/f2}, and if two
+     * mathematical integers are equally close to {@code f1/f2},
+     * then <i>n</i> is the integer that is even. If the remainder is
+     * zero, its sign is the same as the sign of the first argument.
+     * Special cases:
+     * <ul><li>If either argument is NaN, or the first argument is infinite,
+     * or the second argument is positive zero or negative zero, then the
+     * result is NaN.
+     * <li>If the first argument is finite and the second argument is
+     * infinite, then the result is the same as the first argument.</ul>
+     *
+     * @param   f1   the dividend.
+     * @param   f2   the divisor.
+     * @return  the remainder when {@code f1} is divided by
+     *          {@code f2}.
+     */
+    public static native double IEEEremainder(double f1, double f2);
+
+    /**
+     * Returns the smallest (closest to negative infinity)
+     * {@code double} value that is greater than or equal to the
+     * argument and is equal to a mathematical integer. Special cases:
+     * <ul><li>If the argument value is already equal to a
+     * mathematical integer, then the result is the same as the
+     * argument.  <li>If the argument is NaN or an infinity or
+     * positive zero or negative zero, then the result is the same as
+     * the argument.  <li>If the argument value is less than zero but
+     * greater than -1.0, then the result is negative zero.</ul> Note
+     * that the value of {@code StrictMath.ceil(x)} is exactly the
+     * value of {@code -StrictMath.floor(-x)}.
+     *
+     * @param   a   a value.
+     * @return  the smallest (closest to negative infinity)
+     *          floating-point value that is greater than or equal to
+     *          the argument and is equal to a mathematical integer.
+     */
+    public static double ceil(double a) {
+        return floorOrCeil(a, -0.0, 1.0, 1.0);
+    }
+
+    /**
+     * Returns the largest (closest to positive infinity)
+     * {@code double} value that is less than or equal to the
+     * argument and is equal to a mathematical integer. Special cases:
+     * <ul><li>If the argument value is already equal to a
+     * mathematical integer, then the result is the same as the
+     * argument.  <li>If the argument is NaN or an infinity or
+     * positive zero or negative zero, then the result is the same as
+     * the argument.</ul>
+     *
+     * @param   a   a value.
+     * @return  the largest (closest to positive infinity)
+     *          floating-point value that less than or equal to the argument
+     *          and is equal to a mathematical integer.
+     */
+    public static double floor(double a) {
+        return floorOrCeil(a, -1.0, 0.0, -1.0);
+    }
+
+    /**
+     * Internal method to share logic between floor and ceil.
+     *
+     * @param a the value to be floored or ceiled
+     * @param negativeBoundary result for values in (-1, 0)
+     * @param positiveBoundary result for values in (0, 1)
+     * @param increment value to add when the argument is non-integral
+     */
+    private static double floorOrCeil(double a,
+                                      double negativeBoundary,
+                                      double positiveBoundary,
+                                      double sign) {
+        int exponent = Math.getExponent(a);
+
+        if (exponent < 0) {
+            /*
+             * Absolute value of argument is less than 1.
+             * floorOrceil(-0.0) => -0.0
+             * floorOrceil(+0.0) => +0.0
+             */
+            return ((a == 0.0) ? a :
+                    ( (a < 0.0) ?  negativeBoundary : positiveBoundary) );
+        } else if (exponent >= 52) {
+            /*
+             * Infinity, NaN, or a value so large it must be integral.
+             */
+            return a;
+        }
+        // Else the argument is either an integral value already XOR it
+        // has to be rounded to one.
+        assert exponent >= 0 && exponent <= 51;
+
+        long doppel = Double.doubleToRawLongBits(a);
+        long mask   = DoubleConsts.SIGNIF_BIT_MASK >> exponent;
+
+        if ( (mask & doppel) == 0L )
+            return a; // integral value
+        else {
+            double result = Double.longBitsToDouble(doppel & (~mask));
+            if (sign*a > 0.0)
+                result = result + sign;
+            return result;
+        }
+    }
+
+    /**
+     * Returns the {@code double} value that is closest in value
+     * to the argument and is equal to a mathematical integer. If two
+     * {@code double} values that are mathematical integers are
+     * equally close to the value of the argument, the result is the
+     * integer value that is even. Special cases:
+     * <ul><li>If the argument value is already equal to a mathematical
+     * integer, then the result is the same as the argument.
+     * <li>If the argument is NaN or an infinity or positive zero or negative
+     * zero, then the result is the same as the argument.</ul>
+     *
+     * @param   a   a value.
+     * @return  the closest floating-point value to {@code a} that is
+     *          equal to a mathematical integer.
+     * @author Joseph D. Darcy
+     */
+    public static double rint(double a) {
+        /*
+         * If the absolute value of a is not less than 2^52, it
+         * is either a finite integer (the double format does not have
+         * enough significand bits for a number that large to have any
+         * fractional portion), an infinity, or a NaN.  In any of
+         * these cases, rint of the argument is the argument.
+         *
+         * Otherwise, the sum (twoToThe52 + a ) will properly round
+         * away any fractional portion of a since ulp(twoToThe52) ==
+         * 1.0; subtracting out twoToThe52 from this sum will then be
+         * exact and leave the rounded integer portion of a.
+         *
+         * This method does *not* need to be declared strictfp to get
+         * fully reproducible results.  Whether or not a method is
+         * declared strictfp can only make a difference in the
+         * returned result if some operation would overflow or
+         * underflow with strictfp semantics.  The operation
+         * (twoToThe52 + a ) cannot overflow since large values of a
+         * are screened out; the add cannot underflow since twoToThe52
+         * is too large.  The subtraction ((twoToThe52 + a ) -
+         * twoToThe52) will be exact as discussed above and thus
+         * cannot overflow or meaningfully underflow.  Finally, the
+         * last multiply in the return statement is by plus or minus
+         * 1.0, which is exact too.
+         */
+        double twoToThe52 = (double)(1L << 52); // 2^52
+        double sign = Math.copySign(1.0, a); // preserve sign info
+        a = Math.abs(a);
+
+        if (a < twoToThe52) { // E_min <= ilogb(a) <= 51
+            a = ((twoToThe52 + a ) - twoToThe52);
+        }
+
+        return sign * a; // restore original sign
+    }
+
+    /**
+     * Returns the angle <i>theta</i> from the conversion of rectangular
+     * coordinates ({@code x},&nbsp;{@code y}) to polar
+     * coordinates (r,&nbsp;<i>theta</i>).
+     * This method computes the phase <i>theta</i> by computing an arc tangent
+     * of {@code y/x} in the range of -<i>pi</i> to <i>pi</i>. Special
+     * cases:
+     * <ul><li>If either argument is NaN, then the result is NaN.
+     * <li>If the first argument is positive zero and the second argument
+     * is positive, or the first argument is positive and finite and the
+     * second argument is positive infinity, then the result is positive
+     * zero.
+     * <li>If the first argument is negative zero and the second argument
+     * is positive, or the first argument is negative and finite and the
+     * second argument is positive infinity, then the result is negative zero.
+     * <li>If the first argument is positive zero and the second argument
+     * is negative, or the first argument is positive and finite and the
+     * second argument is negative infinity, then the result is the
+     * {@code double} value closest to <i>pi</i>.
+     * <li>If the first argument is negative zero and the second argument
+     * is negative, or the first argument is negative and finite and the
+     * second argument is negative infinity, then the result is the
+     * {@code double} value closest to -<i>pi</i>.
+     * <li>If the first argument is positive and the second argument is
+     * positive zero or negative zero, or the first argument is positive
+     * infinity and the second argument is finite, then the result is the
+     * {@code double} value closest to <i>pi</i>/2.
+     * <li>If the first argument is negative and the second argument is
+     * positive zero or negative zero, or the first argument is negative
+     * infinity and the second argument is finite, then the result is the
+     * {@code double} value closest to -<i>pi</i>/2.
+     * <li>If both arguments are positive infinity, then the result is the
+     * {@code double} value closest to <i>pi</i>/4.
+     * <li>If the first argument is positive infinity and the second argument
+     * is negative infinity, then the result is the {@code double}
+     * value closest to 3*<i>pi</i>/4.
+     * <li>If the first argument is negative infinity and the second argument
+     * is positive infinity, then the result is the {@code double} value
+     * closest to -<i>pi</i>/4.
+     * <li>If both arguments are negative infinity, then the result is the
+     * {@code double} value closest to -3*<i>pi</i>/4.</ul>
+     *
+     * @param   y   the ordinate coordinate
+     * @param   x   the abscissa coordinate
+     * @return  the <i>theta</i> component of the point
+     *          (<i>r</i>,&nbsp;<i>theta</i>)
+     *          in polar coordinates that corresponds to the point
+     *          (<i>x</i>,&nbsp;<i>y</i>) in Cartesian coordinates.
+     */
+    public static native double atan2(double y, double x);
+
+
+    /**
+     * Returns the value of the first argument raised to the power of the
+     * second argument. Special cases:
+     *
+     * <ul><li>If the second argument is positive or negative zero, then the
+     * result is 1.0.
+     * <li>If the second argument is 1.0, then the result is the same as the
+     * first argument.
+     * <li>If the second argument is NaN, then the result is NaN.
+     * <li>If the first argument is NaN and the second argument is nonzero,
+     * then the result is NaN.
+     *
+     * <li>If
+     * <ul>
+     * <li>the absolute value of the first argument is greater than 1
+     * and the second argument is positive infinity, or
+     * <li>the absolute value of the first argument is less than 1 and
+     * the second argument is negative infinity,
+     * </ul>
+     * then the result is positive infinity.
+     *
+     * <li>If
+     * <ul>
+     * <li>the absolute value of the first argument is greater than 1 and
+     * the second argument is negative infinity, or
+     * <li>the absolute value of the
+     * first argument is less than 1 and the second argument is positive
+     * infinity,
+     * </ul>
+     * then the result is positive zero.
+     *
+     * <li>If the absolute value of the first argument equals 1 and the
+     * second argument is infinite, then the result is NaN.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is positive zero and the second argument
+     * is greater than zero, or
+     * <li>the first argument is positive infinity and the second
+     * argument is less than zero,
+     * </ul>
+     * then the result is positive zero.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is positive zero and the second argument
+     * is less than zero, or
+     * <li>the first argument is positive infinity and the second
+     * argument is greater than zero,
+     * </ul>
+     * then the result is positive infinity.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is greater than zero but not a finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is less than zero but not a finite odd integer,
+     * </ul>
+     * then the result is positive zero.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is a positive finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is a negative finite odd integer,
+     * </ul>
+     * then the result is negative zero.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is less than zero but not a finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is greater than zero but not a finite odd integer,
+     * </ul>
+     * then the result is positive infinity.
+     *
+     * <li>If
+     * <ul>
+     * <li>the first argument is negative zero and the second argument
+     * is a negative finite odd integer, or
+     * <li>the first argument is negative infinity and the second
+     * argument is a positive finite odd integer,
+     * </ul>
+     * then the result is negative infinity.
+     *
+     * <li>If the first argument is finite and less than zero
+     * <ul>
+     * <li> if the second argument is a finite even integer, the
+     * result is equal to the result of raising the absolute value of
+     * the first argument to the power of the second argument
+     *
+     * <li>if the second argument is a finite odd integer, the result
+     * is equal to the negative of the result of raising the absolute
+     * value of the first argument to the power of the second
+     * argument
+     *
+     * <li>if the second argument is finite and not an integer, then
+     * the result is NaN.
+     * </ul>
+     *
+     * <li>If both arguments are integers, then the result is exactly equal
+     * to the mathematical result of raising the first argument to the power
+     * of the second argument if that result can in fact be represented
+     * exactly as a {@code double} value.</ul>
+     *
+     * <p>(In the foregoing descriptions, a floating-point value is
+     * considered to be an integer if and only if it is finite and a
+     * fixed point of the method {@link #ceil ceil} or,
+     * equivalently, a fixed point of the method {@link #floor
+     * floor}. A value is a fixed point of a one-argument
+     * method if and only if the result of applying the method to the
+     * value is equal to the value.)
+     *
+     * @param   a   base.
+     * @param   b   the exponent.
+     * @return  the value {@code a}<sup>{@code b}</sup>.
+     */
+    public static native double pow(double a, double b);
+
+    /**
+     * Returns the closest {@code int} to the argument, with ties
+     * rounding to positive infinity.
+     *
+     * <p>Special cases:
+     * <ul><li>If the argument is NaN, the result is 0.
+     * <li>If the argument is negative infinity or any value less than or
+     * equal to the value of {@code Integer.MIN_VALUE}, the result is
+     * equal to the value of {@code Integer.MIN_VALUE}.
+     * <li>If the argument is positive infinity or any value greater than or
+     * equal to the value of {@code Integer.MAX_VALUE}, the result is
+     * equal to the value of {@code Integer.MAX_VALUE}.</ul>
+     *
+     * @param   a   a floating-point value to be rounded to an integer.
+     * @return  the value of the argument rounded to the nearest
+     *          {@code int} value.
+     * @see     java.lang.Integer#MAX_VALUE
+     * @see     java.lang.Integer#MIN_VALUE
+     */
+    public static int round(float a) {
+        return Math.round(a);
+    }
+
+    /**
+     * Returns the closest {@code long} to the argument, with ties
+     * rounding to positive infinity.
+     *
+     * <p>Special cases:
+     * <ul><li>If the argument is NaN, the result is 0.
+     * <li>If the argument is negative infinity or any value less than or
+     * equal to the value of {@code Long.MIN_VALUE}, the result is
+     * equal to the value of {@code Long.MIN_VALUE}.
+     * <li>If the argument is positive infinity or any value greater than or
+     * equal to the value of {@code Long.MAX_VALUE}, the result is
+     * equal to the value of {@code Long.MAX_VALUE}.</ul>
+     *
+     * @param   a  a floating-point value to be rounded to a
+     *          {@code long}.
+     * @return  the value of the argument rounded to the nearest
+     *          {@code long} value.
+     * @see     java.lang.Long#MAX_VALUE
+     * @see     java.lang.Long#MIN_VALUE
+     */
+    public static long round(double a) {
+        return Math.round(a);
+    }
+
+    private static final class RandomNumberGeneratorHolder {
+        static final Random randomNumberGenerator = new Random();
+    }
+
+    /**
+     * Returns a {@code double} value with a positive sign, greater
+     * than or equal to {@code 0.0} and less than {@code 1.0}.
+     * Returned values are chosen pseudorandomly with (approximately)
+     * uniform distribution from that range.
+     *
+     * <p>When this method is first called, it creates a single new
+     * pseudorandom-number generator, exactly as if by the expression
+     *
+     * <blockquote>{@code new java.util.Random()}</blockquote>
+     *
+     * This new pseudorandom-number generator is used thereafter for
+     * all calls to this method and is used nowhere else.
+     *
+     * <p>This method is properly synchronized to allow correct use by
+     * more than one thread. However, if many threads need to generate
+     * pseudorandom numbers at a great rate, it may reduce contention
+     * for each thread to have its own pseudorandom-number generator.
+     *
+     * @return  a pseudorandom {@code double} greater than or equal
+     * to {@code 0.0} and less than {@code 1.0}.
+     * @see Random#nextDouble()
+     */
+    public static double random() {
+        return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
+    }
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @see Math#addExact(int,int)
+     * @since 1.8
+     */
+    public static int addExact(int x, int y) {
+        return Math.addExact(x, y);
+    }
+
+    /**
+     * Returns the sum of its arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @see Math#addExact(long,long)
+     * @since 1.8
+     */
+    public static long addExact(long x, long y) {
+        return Math.addExact(x, y);
+    }
+
+    /**
+     * Returns the difference of the arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value to subtract from the first
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @see Math#subtractExact(int,int)
+     * @since 1.8
+     */
+    public static int subtractExact(int x, int y) {
+        return Math.subtractExact(x, y);
+    }
+
+    /**
+     * Returns the difference of the arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value to subtract from the first
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @see Math#subtractExact(long,long)
+     * @since 1.8
+     */
+    public static long subtractExact(long x, long y) {
+        return Math.subtractExact(x, y);
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows an {@code int}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows an int
+     * @see Math#multiplyExact(int,int)
+     * @since 1.8
+     */
+    public static int multiplyExact(int x, int y) {
+        return Math.multiplyExact(x, y);
+    }
+
+    /**
+     * Returns the product of the arguments,
+     * throwing an exception if the result overflows a {@code long}.
+     *
+     * @param x the first value
+     * @param y the second value
+     * @return the result
+     * @throws ArithmeticException if the result overflows a long
+     * @see Math#multiplyExact(long,long)
+     * @since 1.8
+     */
+    public static long multiplyExact(long x, long y) {
+        return Math.multiplyExact(x, y);
+    }
+
+    /**
+     * Returns the value of the {@code long} argument;
+     * throwing an exception if the value overflows an {@code int}.
+     *
+     * @param value the long value
+     * @return the argument as an int
+     * @throws ArithmeticException if the {@code argument} overflows an int
+     * @see Math#toIntExact(long)
+     * @since 1.8
+     */
+    public static int toIntExact(long value) {
+        return Math.toIntExact(value);
+    }
+
+    /**
+     * Returns the largest (closest to positive infinity)
+     * {@code int} value that is less than or equal to the algebraic quotient.
+     * There is one special case, if the dividend is the
+     * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1},
+     * then integer overflow occurs and
+     * the result is equal to the {@code Integer.MIN_VALUE}.
+     * <p>
+     * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and
+     * a comparison to the integer division {@code /} operator.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the largest (closest to positive infinity)
+     * {@code int} value that is less than or equal to the algebraic quotient.
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see Math#floorDiv(int, int)
+     * @see Math#floor(double)
+     * @since 1.8
+     */
+    public static int floorDiv(int x, int y) {
+        return Math.floorDiv(x, y);
+    }
+
+    /**
+     * Returns the largest (closest to positive infinity)
+     * {@code long} value that is less than or equal to the algebraic quotient.
+     * There is one special case, if the dividend is the
+     * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
+     * then integer overflow occurs and
+     * the result is equal to the {@code Long.MIN_VALUE}.
+     * <p>
+     * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and
+     * a comparison to the integer division {@code /} operator.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the largest (closest to positive infinity)
+     * {@code long} value that is less than or equal to the algebraic quotient.
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see Math#floorDiv(long, long)
+     * @see Math#floor(double)
+     * @since 1.8
+     */
+    public static long floorDiv(long x, long y) {
+        return Math.floorDiv(x, y);
+    }
+
+    /**
+     * Returns the floor modulus of the {@code int} arguments.
+     * <p>
+     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+     * has the same sign as the divisor {@code y}, and
+     * is in the range of {@code -abs(y) < r < +abs(y)}.
+     * <p>
+     * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+     * <ul>
+     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+     * </ul>
+     * <p>
+     * See {@link Math#floorMod(int, int) Math.floorMod} for examples and
+     * a comparison to the {@code %} operator.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see Math#floorMod(int, int)
+     * @see StrictMath#floorDiv(int, int)
+     * @since 1.8
+     */
+    public static int floorMod(int x, int y) {
+        return Math.floorMod(x , y);
+    }
+    /**
+     * Returns the floor modulus of the {@code long} arguments.
+     * <p>
+     * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+     * has the same sign as the divisor {@code y}, and
+     * is in the range of {@code -abs(y) < r < +abs(y)}.
+     * <p>
+     * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+     * <ul>
+     *   <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+     * </ul>
+     * <p>
+     * See {@link Math#floorMod(int, int) Math.floorMod} for examples and
+     * a comparison to the {@code %} operator.
+     *
+     * @param x the dividend
+     * @param y the divisor
+     * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+     * @throws ArithmeticException if the divisor {@code y} is zero
+     * @see Math#floorMod(long, long)
+     * @see StrictMath#floorDiv(long, long)
+     * @since 1.8
+     */
+    public static long floorMod(long x, long y) {
+        return Math.floorMod(x, y);
+    }
+
+    /**
+     * Returns the absolute value of an {@code int} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     *
+     * <p>Note that if the argument is equal to the value of
+     * {@link Integer#MIN_VALUE}, the most negative representable
+     * {@code int} value, the result is that same value, which is
+     * negative.
+     *
+     * @param   a   the  argument whose absolute value is to be determined.
+     * @return  the absolute value of the argument.
+     */
+    public static int abs(int a) {
+        return Math.abs(a);
+    }
+
+    /**
+     * Returns the absolute value of a {@code long} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     *
+     * <p>Note that if the argument is equal to the value of
+     * {@link Long#MIN_VALUE}, the most negative representable
+     * {@code long} value, the result is that same value, which
+     * is negative.
+     *
+     * @param   a   the  argument whose absolute value is to be determined.
+     * @return  the absolute value of the argument.
+     */
+    public static long abs(long a) {
+        return Math.abs(a);
+    }
+
+    /**
+     * Returns the absolute value of a {@code float} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     * Special cases:
+     * <ul><li>If the argument is positive zero or negative zero, the
+     * result is positive zero.
+     * <li>If the argument is infinite, the result is positive infinity.
+     * <li>If the argument is NaN, the result is NaN.</ul>
+     * In other words, the result is the same as the value of the expression:
+     * <p>{@code Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))}
+     *
+     * @param   a   the argument whose absolute value is to be determined
+     * @return  the absolute value of the argument.
+     */
+    public static float abs(float a) {
+        return Math.abs(a);
+    }
+
+    /**
+     * Returns the absolute value of a {@code double} value.
+     * If the argument is not negative, the argument is returned.
+     * If the argument is negative, the negation of the argument is returned.
+     * Special cases:
+     * <ul><li>If the argument is positive zero or negative zero, the result
+     * is positive zero.
+     * <li>If the argument is infinite, the result is positive infinity.
+     * <li>If the argument is NaN, the result is NaN.</ul>
+     * In other words, the result is the same as the value of the expression:
+     * <p>{@code Double.longBitsToDouble((Double.doubleToLongBits(a)<<1)>>>1)}
+     *
+     * @param   a   the argument whose absolute value is to be determined
+     * @return  the absolute value of the argument.
+     */
+    public static double abs(double a) {
+        return Math.abs(a);
+    }
+
+    /**
+     * Returns the greater of two {@code int} values. That is, the
+     * result is the argument closer to the value of
+     * {@link Integer#MAX_VALUE}. If the arguments have the same value,
+     * the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static int max(int a, int b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the greater of two {@code long} values. That is, the
+     * result is the argument closer to the value of
+     * {@link Long#MAX_VALUE}. If the arguments have the same value,
+     * the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+        */
+    public static long max(long a, long b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the greater of two {@code float} values.  That is,
+     * the result is the argument closer to positive infinity. If the
+     * arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero. If one
+     * argument is positive zero and the other negative zero, the
+     * result is positive zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static float max(float a, float b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the greater of two {@code double} values.  That
+     * is, the result is the argument closer to positive infinity. If
+     * the arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero. If one
+     * argument is positive zero and the other negative zero, the
+     * result is positive zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the larger of {@code a} and {@code b}.
+     */
+    public static double max(double a, double b) {
+        return Math.max(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code int} values. That is,
+     * the result the argument closer to the value of
+     * {@link Integer#MIN_VALUE}.  If the arguments have the same
+     * value, the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static int min(int a, int b) {
+        return Math.min(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code long} values. That is,
+     * the result is the argument closer to the value of
+     * {@link Long#MIN_VALUE}. If the arguments have the same
+     * value, the result is that same value.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static long min(long a, long b) {
+        return Math.min(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code float} values.  That is,
+     * the result is the value closer to negative infinity. If the
+     * arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero.  If
+     * one argument is positive zero and the other is negative zero,
+     * the result is negative zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b.}
+     */
+    public static float min(float a, float b) {
+        return Math.min(a, b);
+    }
+
+    /**
+     * Returns the smaller of two {@code double} values.  That
+     * is, the result is the value closer to negative infinity. If the
+     * arguments have the same value, the result is that same
+     * value. If either value is NaN, then the result is NaN.  Unlike
+     * the numerical comparison operators, this method considers
+     * negative zero to be strictly smaller than positive zero. If one
+     * argument is positive zero and the other is negative zero, the
+     * result is negative zero.
+     *
+     * @param   a   an argument.
+     * @param   b   another argument.
+     * @return  the smaller of {@code a} and {@code b}.
+     */
+    public static double min(double a, double b) {
+        return Math.min(a, b);
+    }
+
+    /**
+     * Returns the size of an ulp of the argument.  An ulp, unit in
+     * the last place, of a {@code double} value is the positive
+     * distance between this floating-point value and the {@code
+     * double} value next larger in magnitude.  Note that for non-NaN
+     * <i>x</i>, <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive or negative infinity, then the
+     * result is positive infinity.
+     * <li> If the argument is positive or negative zero, then the result is
+     * {@code Double.MIN_VALUE}.
+     * <li> If the argument is &plusmn;{@code Double.MAX_VALUE}, then
+     * the result is equal to 2<sup>971</sup>.
+     * </ul>
+     *
+     * @param d the floating-point value whose ulp is to be returned
+     * @return the size of an ulp of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static double ulp(double d) {
+        return Math.ulp(d);
+    }
+
+    /**
+     * Returns the size of an ulp of the argument.  An ulp, unit in
+     * the last place, of a {@code float} value is the positive
+     * distance between this floating-point value and the {@code
+     * float} value next larger in magnitude.  Note that for non-NaN
+     * <i>x</i>, <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive or negative infinity, then the
+     * result is positive infinity.
+     * <li> If the argument is positive or negative zero, then the result is
+     * {@code Float.MIN_VALUE}.
+     * <li> If the argument is &plusmn;{@code Float.MAX_VALUE}, then
+     * the result is equal to 2<sup>104</sup>.
+     * </ul>
+     *
+     * @param f the floating-point value whose ulp is to be returned
+     * @return the size of an ulp of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static float ulp(float f) {
+        return Math.ulp(f);
+    }
+
+    /**
+     * Returns the signum function of the argument; zero if the argument
+     * is zero, 1.0 if the argument is greater than zero, -1.0 if the
+     * argument is less than zero.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive zero or negative zero, then the
+     *      result is the same as the argument.
+     * </ul>
+     *
+     * @param d the floating-point value whose signum is to be returned
+     * @return the signum function of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static double signum(double d) {
+        return Math.signum(d);
+    }
+
+    /**
+     * Returns the signum function of the argument; zero if the argument
+     * is zero, 1.0f if the argument is greater than zero, -1.0f if the
+     * argument is less than zero.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, then the result is NaN.
+     * <li> If the argument is positive zero or negative zero, then the
+     *      result is the same as the argument.
+     * </ul>
+     *
+     * @param f the floating-point value whose signum is to be returned
+     * @return the signum function of the argument
+     * @author Joseph D. Darcy
+     * @since 1.5
+     */
+    public static float signum(float f) {
+        return Math.signum(f);
+    }
+
+    /**
+     * Returns the hyperbolic sine of a {@code double} value.
+     * The hyperbolic sine of <i>x</i> is defined to be
+     * (<i>e<sup>x</sup>&nbsp;-&nbsp;e<sup>-x</sup></i>)/2
+     * where <i>e</i> is {@linkplain Math#E Euler's number}.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is infinite, then the result is an infinity
+     * with the same sign as the argument.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * @param   x The number whose hyperbolic sine is to be returned.
+     * @return  The hyperbolic sine of {@code x}.
+     * @since 1.5
+     */
+    public static native double sinh(double x);
+
+    /**
+     * Returns the hyperbolic cosine of a {@code double} value.
+     * The hyperbolic cosine of <i>x</i> is defined to be
+     * (<i>e<sup>x</sup>&nbsp;+&nbsp;e<sup>-x</sup></i>)/2
+     * where <i>e</i> is {@linkplain Math#E Euler's number}.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is infinite, then the result is positive
+     * infinity.
+     *
+     * <li>If the argument is zero, then the result is {@code 1.0}.
+     *
+     * </ul>
+     *
+     * @param   x The number whose hyperbolic cosine is to be returned.
+     * @return  The hyperbolic cosine of {@code x}.
+     * @since 1.5
+     */
+    public static native double cosh(double x);
+
+    /**
+     * Returns the hyperbolic tangent of a {@code double} value.
+     * The hyperbolic tangent of <i>x</i> is defined to be
+     * (<i>e<sup>x</sup>&nbsp;-&nbsp;e<sup>-x</sup></i>)/(<i>e<sup>x</sup>&nbsp;+&nbsp;e<sup>-x</sup></i>),
+     * in other words, {@linkplain Math#sinh
+     * sinh(<i>x</i>)}/{@linkplain Math#cosh cosh(<i>x</i>)}.  Note
+     * that the absolute value of the exact tanh is always less than
+     * 1.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN, then the result is NaN.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * <li>If the argument is positive infinity, then the result is
+     * {@code +1.0}.
+     *
+     * <li>If the argument is negative infinity, then the result is
+     * {@code -1.0}.
+     *
+     * </ul>
+     *
+     * @param   x The number whose hyperbolic tangent is to be returned.
+     * @return  The hyperbolic tangent of {@code x}.
+     * @since 1.5
+     */
+    public static native double tanh(double x);
+
+    /**
+     * Returns sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
+     * without intermediate overflow or underflow.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li> If either argument is infinite, then the result
+     * is positive infinity.
+     *
+     * <li> If either argument is NaN and neither argument is infinite,
+     * then the result is NaN.
+     *
+     * </ul>
+     *
+     * @param x a value
+     * @param y a value
+     * @return sqrt(<i>x</i><sup>2</sup>&nbsp;+<i>y</i><sup>2</sup>)
+     * without intermediate overflow or underflow
+     * @since 1.5
+     */
+    public static native double hypot(double x, double y);
+
+    /**
+     * Returns <i>e</i><sup>x</sup>&nbsp;-1.  Note that for values of
+     * <i>x</i> near 0, the exact sum of
+     * {@code expm1(x)}&nbsp;+&nbsp;1 is much closer to the true
+     * result of <i>e</i><sup>x</sup> than {@code exp(x)}.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li>If the argument is NaN, the result is NaN.
+     *
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     *
+     * <li>If the argument is negative infinity, then the result is
+     * -1.0.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * @param   x   the exponent to raise <i>e</i> to in the computation of
+     *              <i>e</i><sup>{@code x}</sup>&nbsp;-1.
+     * @return  the value <i>e</i><sup>{@code x}</sup>&nbsp;-&nbsp;1.
+     * @since 1.5
+     */
+    public static native double expm1(double x);
+
+    /**
+     * Returns the natural logarithm of the sum of the argument and 1.
+     * Note that for small values {@code x}, the result of
+     * {@code log1p(x)} is much closer to the true result of ln(1
+     * + {@code x}) than the floating-point evaluation of
+     * {@code log(1.0+x)}.
+     *
+     * <p>Special cases:
+     * <ul>
+     *
+     * <li>If the argument is NaN or less than -1, then the result is
+     * NaN.
+     *
+     * <li>If the argument is positive infinity, then the result is
+     * positive infinity.
+     *
+     * <li>If the argument is negative one, then the result is
+     * negative infinity.
+     *
+     * <li>If the argument is zero, then the result is a zero with the
+     * same sign as the argument.
+     *
+     * </ul>
+     *
+     * @param   x   a value
+     * @return the value ln({@code x}&nbsp;+&nbsp;1), the natural
+     * log of {@code x}&nbsp;+&nbsp;1
+     * @since 1.5
+     */
+    public static native double log1p(double x);
+
+    /**
+     * Returns the first floating-point argument with the sign of the
+     * second floating-point argument.  For this method, a NaN
+     * {@code sign} argument is always treated as if it were
+     * positive.
+     *
+     * @param magnitude  the parameter providing the magnitude of the result
+     * @param sign   the parameter providing the sign of the result
+     * @return a value with the magnitude of {@code magnitude}
+     * and the sign of {@code sign}.
+     * @since 1.6
+     */
+    public static double copySign(double magnitude, double sign) {
+        return Math.copySign(magnitude, (Double.isNaN(sign)?1.0d:sign));
+    }
+
+    /**
+     * Returns the first floating-point argument with the sign of the
+     * second floating-point argument.  For this method, a NaN
+     * {@code sign} argument is always treated as if it were
+     * positive.
+     *
+     * @param magnitude  the parameter providing the magnitude of the result
+     * @param sign   the parameter providing the sign of the result
+     * @return a value with the magnitude of {@code magnitude}
+     * and the sign of {@code sign}.
+     * @since 1.6
+     */
+    public static float copySign(float magnitude, float sign) {
+        return Math.copySign(magnitude, (Float.isNaN(sign)?1.0f:sign));
+    }
+    /**
+     * Returns the unbiased exponent used in the representation of a
+     * {@code float}.  Special cases:
+     *
+     * <ul>
+     * <li>If the argument is NaN or infinite, then the result is
+     * {@link Float#MAX_EXPONENT} + 1.
+     * <li>If the argument is zero or subnormal, then the result is
+     * {@link Float#MIN_EXPONENT} -1.
+     * </ul>
+     * @param f a {@code float} value
+     * @return the unbiased exponent of the argument
+     * @since 1.6
+     */
+    public static int getExponent(float f) {
+        return Math.getExponent(f);
+    }
+
+    /**
+     * Returns the unbiased exponent used in the representation of a
+     * {@code double}.  Special cases:
+     *
+     * <ul>
+     * <li>If the argument is NaN or infinite, then the result is
+     * {@link Double#MAX_EXPONENT} + 1.
+     * <li>If the argument is zero or subnormal, then the result is
+     * {@link Double#MIN_EXPONENT} -1.
+     * </ul>
+     * @param d a {@code double} value
+     * @return the unbiased exponent of the argument
+     * @since 1.6
+     */
+    public static int getExponent(double d) {
+        return Math.getExponent(d);
+    }
+
+    /**
+     * Returns the floating-point number adjacent to the first
+     * argument in the direction of the second argument.  If both
+     * arguments compare as equal the second argument is returned.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li> If either argument is a NaN, then NaN is returned.
+     *
+     * <li> If both arguments are signed zeros, {@code direction}
+     * is returned unchanged (as implied by the requirement of
+     * returning the second argument if the arguments compare as
+     * equal).
+     *
+     * <li> If {@code start} is
+     * &plusmn;{@link Double#MIN_VALUE} and {@code direction}
+     * has a value such that the result should have a smaller
+     * magnitude, then a zero with the same sign as {@code start}
+     * is returned.
+     *
+     * <li> If {@code start} is infinite and
+     * {@code direction} has a value such that the result should
+     * have a smaller magnitude, {@link Double#MAX_VALUE} with the
+     * same sign as {@code start} is returned.
+     *
+     * <li> If {@code start} is equal to &plusmn;
+     * {@link Double#MAX_VALUE} and {@code direction} has a
+     * value such that the result should have a larger magnitude, an
+     * infinity with same sign as {@code start} is returned.
+     * </ul>
+     *
+     * @param start  starting floating-point value
+     * @param direction value indicating which of
+     * {@code start}'s neighbors or {@code start} should
+     * be returned
+     * @return The floating-point number adjacent to {@code start} in the
+     * direction of {@code direction}.
+     * @since 1.6
+     */
+    public static double nextAfter(double start, double direction) {
+        return Math.nextAfter(start, direction);
+    }
+
+    /**
+     * Returns the floating-point number adjacent to the first
+     * argument in the direction of the second argument.  If both
+     * arguments compare as equal a value equivalent to the second argument
+     * is returned.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li> If either argument is a NaN, then NaN is returned.
+     *
+     * <li> If both arguments are signed zeros, a value equivalent
+     * to {@code direction} is returned.
+     *
+     * <li> If {@code start} is
+     * &plusmn;{@link Float#MIN_VALUE} and {@code direction}
+     * has a value such that the result should have a smaller
+     * magnitude, then a zero with the same sign as {@code start}
+     * is returned.
+     *
+     * <li> If {@code start} is infinite and
+     * {@code direction} has a value such that the result should
+     * have a smaller magnitude, {@link Float#MAX_VALUE} with the
+     * same sign as {@code start} is returned.
+     *
+     * <li> If {@code start} is equal to &plusmn;
+     * {@link Float#MAX_VALUE} and {@code direction} has a
+     * value such that the result should have a larger magnitude, an
+     * infinity with same sign as {@code start} is returned.
+     * </ul>
+     *
+     * @param start  starting floating-point value
+     * @param direction value indicating which of
+     * {@code start}'s neighbors or {@code start} should
+     * be returned
+     * @return The floating-point number adjacent to {@code start} in the
+     * direction of {@code direction}.
+     * @since 1.6
+     */
+    public static float nextAfter(float start, double direction) {
+        return Math.nextAfter(start, direction);
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code d} in
+     * the direction of positive infinity.  This method is
+     * semantically equivalent to {@code nextAfter(d,
+     * Double.POSITIVE_INFINITY)}; however, a {@code nextUp}
+     * implementation may run faster than its equivalent
+     * {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is positive infinity, the result is
+     * positive infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@link Double#MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param d starting floating-point value
+     * @return The adjacent floating-point value closer to positive
+     * infinity.
+     * @since 1.6
+     */
+    public static double nextUp(double d) {
+        return Math.nextUp(d);
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code f} in
+     * the direction of positive infinity.  This method is
+     * semantically equivalent to {@code nextAfter(f,
+     * Float.POSITIVE_INFINITY)}; however, a {@code nextUp}
+     * implementation may run faster than its equivalent
+     * {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is positive infinity, the result is
+     * positive infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@link Float#MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param f starting floating-point value
+     * @return The adjacent floating-point value closer to positive
+     * infinity.
+     * @since 1.6
+     */
+    public static float nextUp(float f) {
+        return Math.nextUp(f);
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code d} in
+     * the direction of negative infinity.  This method is
+     * semantically equivalent to {@code nextAfter(d,
+     * Double.NEGATIVE_INFINITY)}; however, a
+     * {@code nextDown} implementation may run faster than its
+     * equivalent {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is negative infinity, the result is
+     * negative infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@code -Double.MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param d  starting floating-point value
+     * @return The adjacent floating-point value closer to negative
+     * infinity.
+     * @since 1.8
+     */
+    public static double nextDown(double d) {
+        return Math.nextDown(d);
+    }
+
+    /**
+     * Returns the floating-point value adjacent to {@code f} in
+     * the direction of negative infinity.  This method is
+     * semantically equivalent to {@code nextAfter(f,
+     * Float.NEGATIVE_INFINITY)}; however, a
+     * {@code nextDown} implementation may run faster than its
+     * equivalent {@code nextAfter} call.
+     *
+     * <p>Special Cases:
+     * <ul>
+     * <li> If the argument is NaN, the result is NaN.
+     *
+     * <li> If the argument is negative infinity, the result is
+     * negative infinity.
+     *
+     * <li> If the argument is zero, the result is
+     * {@code -Float.MIN_VALUE}
+     *
+     * </ul>
+     *
+     * @param f  starting floating-point value
+     * @return The adjacent floating-point value closer to negative
+     * infinity.
+     * @since 1.8
+     */
+    public static float nextDown(float f) {
+        return Math.nextDown(f);
+    }
+
+    /**
+     * Returns {@code d} &times;
+     * 2<sup>{@code scaleFactor}</sup> rounded as if performed
+     * by a single correctly rounded floating-point multiply to a
+     * member of the double value set.  See the Java
+     * Language Specification for a discussion of floating-point
+     * value sets.  If the exponent of the result is between {@link
+     * Double#MIN_EXPONENT} and {@link Double#MAX_EXPONENT}, the
+     * answer is calculated exactly.  If the exponent of the result
+     * would be larger than {@code Double.MAX_EXPONENT}, an
+     * infinity is returned.  Note that if the result is subnormal,
+     * precision may be lost; that is, when {@code scalb(x, n)}
+     * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal
+     * <i>x</i>.  When the result is non-NaN, the result has the same
+     * sign as {@code d}.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li> If the first argument is NaN, NaN is returned.
+     * <li> If the first argument is infinite, then an infinity of the
+     * same sign is returned.
+     * <li> If the first argument is zero, then a zero of the same
+     * sign is returned.
+     * </ul>
+     *
+     * @param d number to be scaled by a power of two.
+     * @param scaleFactor power of 2 used to scale {@code d}
+     * @return {@code d} &times; 2<sup>{@code scaleFactor}</sup>
+     * @since 1.6
+     */
+    public static double scalb(double d, int scaleFactor) {
+        return Math.scalb(d, scaleFactor);
+    }
+
+    /**
+     * Returns {@code f} &times;
+     * 2<sup>{@code scaleFactor}</sup> rounded as if performed
+     * by a single correctly rounded floating-point multiply to a
+     * member of the float value set.  See the Java
+     * Language Specification for a discussion of floating-point
+     * value sets.  If the exponent of the result is between {@link
+     * Float#MIN_EXPONENT} and {@link Float#MAX_EXPONENT}, the
+     * answer is calculated exactly.  If the exponent of the result
+     * would be larger than {@code Float.MAX_EXPONENT}, an
+     * infinity is returned.  Note that if the result is subnormal,
+     * precision may be lost; that is, when {@code scalb(x, n)}
+     * is subnormal, {@code scalb(scalb(x, n), -n)} may not equal
+     * <i>x</i>.  When the result is non-NaN, the result has the same
+     * sign as {@code f}.
+     *
+     * <p>Special cases:
+     * <ul>
+     * <li> If the first argument is NaN, NaN is returned.
+     * <li> If the first argument is infinite, then an infinity of the
+     * same sign is returned.
+     * <li> If the first argument is zero, then a zero of the same
+     * sign is returned.
+     * </ul>
+     *
+     * @param f number to be scaled by a power of two.
+     * @param scaleFactor power of 2 used to scale {@code f}
+     * @return {@code f} &times; 2<sup>{@code scaleFactor}</sup>
+     * @since 1.6
+     */
+    public static float scalb(float f, int scaleFactor) {
+        return Math.scalb(f, scaleFactor);
+    }
+}
diff --git a/java/lang/String.annotated.java b/java/lang/String.annotated.java
new file mode 100644
index 0000000..a8cf1de
--- /dev/null
+++ b/java/lang/String.annotated.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.nio.charset.Charset;
+import java.io.UnsupportedEncodingException;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.StringJoiner;
+import java.util.Locale;
+import java.util.Formatter;
+import java.util.Comparator;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class String implements java.io.Serializable, java.lang.Comparable<java.lang.String>, java.lang.CharSequence {
+
+public String() { throw new RuntimeException("Stub!"); }
+
+public String(@libcore.util.NonNull java.lang.String original) { throw new RuntimeException("Stub!"); }
+
+public String(char[] value) { throw new RuntimeException("Stub!"); }
+
+public String(char[] value, int offset, int count) { throw new RuntimeException("Stub!"); }
+
+public String(int[] codePoints, int offset, int count) { throw new RuntimeException("Stub!"); }
+
+@Deprecated public String(byte[] ascii, int hibyte, int offset, int count) { throw new RuntimeException("Stub!"); }
+
+@Deprecated public String(byte[] ascii, int hibyte) { throw new RuntimeException("Stub!"); }
+
+public String(byte[] bytes, int offset, int length, @libcore.util.NonNull java.lang.String charsetName) throws java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public String(byte[] bytes, int offset, int length, @libcore.util.NonNull java.nio.charset.Charset charset) { throw new RuntimeException("Stub!"); }
+
+public String(byte[] bytes, @libcore.util.NonNull java.lang.String charsetName) throws java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public String(byte[] bytes, @libcore.util.NonNull java.nio.charset.Charset charset) { throw new RuntimeException("Stub!"); }
+
+public String(byte[] bytes, int offset, int length) { throw new RuntimeException("Stub!"); }
+
+public String(byte[] bytes) { throw new RuntimeException("Stub!"); }
+
+public String(@libcore.util.NonNull java.lang.StringBuffer buffer) { throw new RuntimeException("Stub!"); }
+
+public String(@libcore.util.NonNull java.lang.StringBuilder builder) { throw new RuntimeException("Stub!"); }
+
+public int length() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public native char charAt(int index);
+
+public int codePointAt(int index) { throw new RuntimeException("Stub!"); }
+
+public int codePointBefore(int index) { throw new RuntimeException("Stub!"); }
+
+public int codePointCount(int beginIndex, int endIndex) { throw new RuntimeException("Stub!"); }
+
+public int offsetByCodePoints(int index, int codePointOffset) { throw new RuntimeException("Stub!"); }
+
+public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { throw new RuntimeException("Stub!"); }
+
+@Deprecated public void getBytes(int srcBegin, int srcEnd, byte[] dst, int dstBegin) { throw new RuntimeException("Stub!"); }
+
+public byte[] getBytes(@libcore.util.NonNull java.lang.String charsetName) throws java.io.UnsupportedEncodingException { throw new RuntimeException("Stub!"); }
+
+public byte[] getBytes(@libcore.util.NonNull java.nio.charset.Charset charset) { throw new RuntimeException("Stub!"); }
+
+public byte[] getBytes() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object anObject) { throw new RuntimeException("Stub!"); }
+
+public boolean contentEquals(@libcore.util.NonNull java.lang.StringBuffer sb) { throw new RuntimeException("Stub!"); }
+
+public boolean contentEquals(@libcore.util.NonNull java.lang.CharSequence cs) { throw new RuntimeException("Stub!"); }
+
+public boolean equalsIgnoreCase(@libcore.util.Nullable java.lang.String anotherString) { throw new RuntimeException("Stub!"); }
+
+public native int compareTo(@libcore.util.NonNull java.lang.String anotherString);
+
+public int compareToIgnoreCase(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public boolean regionMatches(int toffset, @libcore.util.NonNull java.lang.String other, int ooffset, int len) { throw new RuntimeException("Stub!"); }
+
+public boolean regionMatches(boolean ignoreCase, int toffset, @libcore.util.NonNull java.lang.String other, int ooffset, int len) { throw new RuntimeException("Stub!"); }
+
+public boolean startsWith(@libcore.util.NonNull java.lang.String prefix, int toffset) { throw new RuntimeException("Stub!"); }
+
+public boolean startsWith(@libcore.util.NonNull java.lang.String prefix) { throw new RuntimeException("Stub!"); }
+
+public boolean endsWith(@libcore.util.NonNull java.lang.String suffix) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public int indexOf(int ch) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(int ch, int fromIndex) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(int ch) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(int ch, int fromIndex) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.NonNull java.lang.String str, int fromIndex) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.NonNull java.lang.String str, int fromIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String substring(int beginIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String substring(int beginIndex, int endIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.CharSequence subSequence(int beginIndex, int endIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public native java.lang.String concat(@libcore.util.NonNull java.lang.String str);
+
[email protected] public java.lang.String replace(char oldChar, char newChar) { throw new RuntimeException("Stub!"); }
+
+public boolean matches(@libcore.util.NonNull java.lang.String regex) { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.NonNull java.lang.CharSequence s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replaceFirst(@libcore.util.NonNull java.lang.String regex, @libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replaceAll(@libcore.util.NonNull java.lang.String regex, @libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replace(@libcore.util.NonNull java.lang.CharSequence target, @libcore.util.NonNull java.lang.CharSequence replacement) { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.NonNull [] split(@libcore.util.NonNull java.lang.String regex, int limit) { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.NonNull [] split(@libcore.util.NonNull java.lang.String regex) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String join(@libcore.util.NonNull java.lang.CharSequence delimiter, [email protected] CharSequence @libcore.util.Nullable ... elements) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String join(@libcore.util.NonNull java.lang.CharSequence delimiter, @libcore.util.NonNull java.lang.Iterable<? extends @libcore.util.Nullable java.lang.CharSequence> elements) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toLowerCase(@libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toLowerCase() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toUpperCase(@libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toUpperCase() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String trim() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public native char[] toCharArray();
+
[email protected] public static java.lang.String format(@libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String format(@libcore.util.NonNull java.util.Locale l, @libcore.util.NonNull java.lang.String format, [email protected] Object @libcore.util.NonNull ... args) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(char[] data) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(char[] data, int offset, int count) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String copyValueOf(char[] data, int offset, int count) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String copyValueOf(char[] data) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(char c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(long l) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String valueOf(double d) { throw new RuntimeException("Stub!"); }
+
[email protected] public native java.lang.String intern();
+
+public static final java.util.Comparator<java.lang.String> CASE_INSENSITIVE_ORDER;
+static { CASE_INSENSITIVE_ORDER = null; }
+}
diff --git a/java/lang/String.java b/java/lang/String.java
new file mode 100644
index 0000000..2ba7b1f
--- /dev/null
+++ b/java/lang/String.java
@@ -0,0 +1,3104 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+import java.io.ObjectStreamField;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.ByteBuffer;
+import java.util.Comparator;
+import java.util.Formatter;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.StringJoiner;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import libcore.util.CharsetUtils;
+
+/**
+ * The {@code String} class represents character strings. All
+ * string literals in Java programs, such as {@code "abc"}, are
+ * implemented as instances of this class.
+ * <p>
+ * Strings are constant; their values cannot be changed after they
+ * are created. String buffers support mutable strings.
+ * Because String objects are immutable they can be shared. For example:
+ * <blockquote><pre>
+ *     String str = "abc";
+ * </pre></blockquote><p>
+ * is equivalent to:
+ * <blockquote><pre>
+ *     char data[] = {'a', 'b', 'c'};
+ *     String str = new String(data);
+ * </pre></blockquote><p>
+ * Here are some more examples of how strings can be used:
+ * <blockquote><pre>
+ *     System.out.println("abc");
+ *     String cde = "cde";
+ *     System.out.println("abc" + cde);
+ *     String c = "abc".substring(2,3);
+ *     String d = cde.substring(1, 2);
+ * </pre></blockquote>
+ * <p>
+ * The class {@code String} includes methods for examining
+ * individual characters of the sequence, for comparing strings, for
+ * searching strings, for extracting substrings, and for creating a
+ * copy of a string with all characters translated to uppercase or to
+ * lowercase. Case mapping is based on the Unicode Standard version
+ * specified by the {@link java.lang.Character Character} class.
+ * <p>
+ * The Java language provides special support for the string
+ * concatenation operator (&nbsp;+&nbsp;), and for conversion of
+ * other objects to strings. String concatenation is implemented
+ * through the {@code StringBuilder}(or {@code StringBuffer})
+ * class and its {@code append} method.
+ * String conversions are implemented through the method
+ * {@code toString}, defined by {@code Object} and
+ * inherited by all classes in Java. For additional information on
+ * string concatenation and conversion, see Gosling, Joy, and Steele,
+ * <i>The Java Language Specification</i>.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * <p>A {@code String} represents a string in the UTF-16 format
+ * in which <em>supplementary characters</em> are represented by <em>surrogate
+ * pairs</em> (see the section <a href="Character.html#unicode">Unicode
+ * Character Representations</a> in the {@code Character} class for
+ * more information).
+ * Index values refer to {@code char} code units, so a supplementary
+ * character uses two positions in a {@code String}.
+ * <p>The {@code String} class provides methods for dealing with
+ * Unicode code points (i.e., characters), in addition to those for
+ * dealing with Unicode code units (i.e., {@code char} values).
+ *
+ * @author  Lee Boynton
+ * @author  Arthur van Hoff
+ * @author  Martin Buchholz
+ * @author  Ulf Zibis
+ * @see     java.lang.Object#toString()
+ * @see     java.lang.StringBuffer
+ * @see     java.lang.StringBuilder
+ * @see     java.nio.charset.Charset
+ * @since   JDK1.0
+ */
+
+public final class String
+    implements java.io.Serializable, Comparable<String>, CharSequence {
+
+    // BEGIN Android-changed: The character data is managed by the runtime.
+    // We only keep track of the length here and compression here. This has several consequences
+    // throughout this class:
+    //  - References to value[i] are replaced by charAt(i).
+    //  - References to value.length are replaced by calls to length().
+    //  - Sometimes the result of length() is assigned to a local variable to avoid repeated calls.
+    //  - We skip several attempts at optimization where the values field was assigned to a local
+    //    variable to avoid the getfield opcode.
+    // These changes are not all marked individually.
+    //
+    // private final char value[];
+    //
+    // If STRING_COMPRESSION_ENABLED, count stores the length shifted one bit to the left with the
+    // lowest bit used to indicate whether or not the bytes are compressed (see GetFlaggedCount in
+    // the native code).
+    private final int count;
+    // END Android-changed: The character data is managed by the runtime.
+
+    // Android-changed: We make use of new StringIndexOutOfBoundsException constructor signatures.
+    // These improve some error messages. These changes are not all marked individually.
+
+    /** Cache the hash code for the string */
+    private int hash; // Default to 0
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -6849794470754667710L;
+
+    /**
+     * Class String is special cased within the Serialization Stream Protocol.
+     *
+     * A String instance is written into an ObjectOutputStream according to
+     * <a href="{@docRoot}/../platform/serialization/spec/output.html">
+     * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
+     */
+    private static final ObjectStreamField[] serialPersistentFields =
+        new ObjectStreamField[0];
+
+    /**
+     * Initializes a newly created {@code String} object so that it represents
+     * an empty character sequence.  Note that use of this constructor is
+     * unnecessary since Strings are immutable.
+     */
+    public String() {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Initializes a newly created {@code String} object so that it represents
+     * the same sequence of characters as the argument; in other words, the
+     * newly created string is a copy of the argument string. Unless an
+     * explicit copy of {@code original} is needed, use of this constructor is
+     * unnecessary since Strings are immutable.
+     *
+     * @param  original
+     *         A {@code String}
+     */
+    public String(String original) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new {@code String} so that it represents the sequence of
+     * characters currently contained in the character array argument. The
+     * contents of the character array are copied; subsequent modification of
+     * the character array does not affect the newly created string.
+     *
+     * @param  value
+     *         The initial value of the string
+     */
+    public String(char value[]) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new {@code String} that contains characters from a subarray
+     * of the character array argument. The {@code offset} argument is the
+     * index of the first character of the subarray and the {@code count}
+     * argument specifies the length of the subarray. The contents of the
+     * subarray are copied; subsequent modification of the character array does
+     * not affect the newly created string.
+     *
+     * @param  value
+     *         Array that is the source of characters
+     *
+     * @param  offset
+     *         The initial offset
+     *
+     * @param  count
+     *         The length
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the {@code offset} and {@code count} arguments index
+     *          characters outside the bounds of the {@code value} array
+     */
+    public String(char value[], int offset, int count) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new {@code String} that contains characters from a subarray
+     * of the <a href="Character.html#unicode">Unicode code point</a> array
+     * argument.  The {@code offset} argument is the index of the first code
+     * point of the subarray and the {@code count} argument specifies the
+     * length of the subarray.  The contents of the subarray are converted to
+     * {@code char}s; subsequent modification of the {@code int} array does not
+     * affect the newly created string.
+     *
+     * @param  codePoints
+     *         Array that is the source of Unicode code points
+     *
+     * @param  offset
+     *         The initial offset
+     *
+     * @param  count
+     *         The length
+     *
+     * @throws  IllegalArgumentException
+     *          If any invalid Unicode code point is found in {@code
+     *          codePoints}
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the {@code offset} and {@code count} arguments index
+     *          characters outside the bounds of the {@code codePoints} array
+     *
+     * @since  1.5
+     */
+    public String(int[] codePoints, int offset, int count) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new {@code String} constructed from a subarray of an array
+     * of 8-bit integer values.
+     *
+     * <p> The {@code offset} argument is the index of the first byte of the
+     * subarray, and the {@code count} argument specifies the length of the
+     * subarray.
+     *
+     * <p> Each {@code byte} in the subarray is converted to a {@code char} as
+     * specified in the method above.
+     *
+     * @deprecated This method does not properly convert bytes into characters.
+     * As of JDK&nbsp;1.1, the preferred way to do this is via the
+     * {@code String} constructors that take a {@link
+     * java.nio.charset.Charset}, charset name, or that use the platform's
+     * default charset.
+     *
+     * @param  ascii
+     *         The bytes to be converted to characters
+     *
+     * @param  hibyte
+     *         The top 8 bits of each 16-bit Unicode code unit
+     *
+     * @param  offset
+     *         The initial offset
+     * @param  count
+     *         The length
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the {@code offset} or {@code count} argument is invalid
+     *
+     * @see  #String(byte[], int)
+     * @see  #String(byte[], int, int, java.lang.String)
+     * @see  #String(byte[], int, int, java.nio.charset.Charset)
+     * @see  #String(byte[], int, int)
+     * @see  #String(byte[], java.lang.String)
+     * @see  #String(byte[], java.nio.charset.Charset)
+     * @see  #String(byte[])
+     */
+    @Deprecated
+    public String(byte ascii[], int hibyte, int offset, int count) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new {@code String} containing characters constructed from
+     * an array of 8-bit integer values. Each character <i>c</i>in the
+     * resulting string is constructed from the corresponding component
+     * <i>b</i> in the byte array such that:
+     *
+     * <blockquote><pre>
+     *     <b><i>c</i></b> == (char)(((hibyte &amp; 0xff) &lt;&lt; 8)
+     *                         | (<b><i>b</i></b> &amp; 0xff))
+     * </pre></blockquote>
+     *
+     * @deprecated  This method does not properly convert bytes into
+     * characters.  As of JDK&nbsp;1.1, the preferred way to do this is via the
+     * {@code String} constructors that take a {@link
+     * java.nio.charset.Charset}, charset name, or that use the platform's
+     * default charset.
+     *
+     * @param  ascii
+     *         The bytes to be converted to characters
+     *
+     * @param  hibyte
+     *         The top 8 bits of each 16-bit Unicode code unit
+     *
+     * @see  #String(byte[], int, int, java.lang.String)
+     * @see  #String(byte[], int, int, java.nio.charset.Charset)
+     * @see  #String(byte[], int, int)
+     * @see  #String(byte[], java.lang.String)
+     * @see  #String(byte[], java.nio.charset.Charset)
+     * @see  #String(byte[])
+     */
+    @Deprecated
+    public String(byte ascii[], int hibyte) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Constructs a new {@code String} by decoding the specified subarray of
+     * bytes using the specified charset.  The length of the new {@code String}
+     * is a function of the charset, and hence may not be equal to the length
+     * of the subarray.
+     *
+     * <p> The behavior of this constructor when the given bytes are not valid
+     * in the given charset is unspecified.  The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param  bytes
+     *         The bytes to be decoded into characters
+     *
+     * @param  offset
+     *         The index of the first byte to decode
+     *
+     * @param  length
+     *         The number of bytes to decode
+
+     * @param  charsetName
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the {@code offset} and {@code length} arguments index
+     *          characters outside the bounds of the {@code bytes} array
+     *
+     * @since  JDK1.1
+     */
+    public String(byte bytes[], int offset, int length, String charsetName)
+            throws UnsupportedEncodingException {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Constructs a new {@code String} by decoding the specified subarray of
+     * bytes using the specified {@linkplain java.nio.charset.Charset charset}.
+     * The length of the new {@code String} is a function of the charset, and
+     * hence may not be equal to the length of the subarray.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with this charset's default replacement string.  The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param  bytes
+     *         The bytes to be decoded into characters
+     *
+     * @param  offset
+     *         The index of the first byte to decode
+     *
+     * @param  length
+     *         The number of bytes to decode
+     *
+     * @param  charset
+     *         The {@linkplain java.nio.charset.Charset charset} to be used to
+     *         decode the {@code bytes}
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the {@code offset} and {@code length} arguments index
+     *          characters outside the bounds of the {@code bytes} array
+     *
+     * @since  1.6
+     */
+    public String(byte bytes[], int offset, int length, Charset charset) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Constructs a new {@code String} by decoding the specified array of bytes
+     * using the specified {@linkplain java.nio.charset.Charset charset}.  The
+     * length of the new {@code String} is a function of the charset, and hence
+     * may not be equal to the length of the byte array.
+     *
+     * <p> The behavior of this constructor when the given bytes are not valid
+     * in the given charset is unspecified.  The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param  bytes
+     *         The bytes to be decoded into characters
+     *
+     * @param  charsetName
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @since  JDK1.1
+     */
+    public String(byte bytes[], String charsetName)
+            throws UnsupportedEncodingException {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Constructs a new {@code String} by decoding the specified array of
+     * bytes using the specified {@linkplain java.nio.charset.Charset charset}.
+     * The length of the new {@code String} is a function of the charset, and
+     * hence may not be equal to the length of the byte array.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with this charset's default replacement string.  The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param  bytes
+     *         The bytes to be decoded into characters
+     *
+     * @param  charset
+     *         The {@linkplain java.nio.charset.Charset charset} to be used to
+     *         decode the {@code bytes}
+     *
+     * @since  1.6
+     */
+    public String(byte bytes[], Charset charset) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Constructs a new {@code String} by decoding the specified subarray of
+     * bytes using the platform's default charset.  The length of the new
+     * {@code String} is a function of the charset, and hence may not be equal
+     * to the length of the subarray.
+     *
+     * <p> The behavior of this constructor when the given bytes are not valid
+     * in the default charset is unspecified.  The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param  bytes
+     *         The bytes to be decoded into characters
+     *
+     * @param  offset
+     *         The index of the first byte to decode
+     *
+     * @param  length
+     *         The number of bytes to decode
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the {@code offset} and the {@code length} arguments index
+     *          characters outside the bounds of the {@code bytes} array
+     *
+     * @since  JDK1.1
+     */
+    public String(byte bytes[], int offset, int length) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Constructs a new {@code String} by decoding the specified array of bytes
+     * using the platform's default charset.  The length of the new {@code
+     * String} is a function of the charset, and hence may not be equal to the
+     * length of the byte array.
+     *
+     * <p> The behavior of this constructor when the given bytes are not valid
+     * in the default charset is unspecified.  The {@link
+     * java.nio.charset.CharsetDecoder} class should be used when more control
+     * over the decoding process is required.
+     *
+     * @param  bytes
+     *         The bytes to be decoded into characters
+     *
+     * @since  JDK1.1
+     */
+    public String(byte bytes[]) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new string that contains the sequence of characters
+     * currently contained in the string buffer argument. The contents of the
+     * string buffer are copied; subsequent modification of the string buffer
+     * does not affect the newly created string.
+     *
+     * @param  buffer
+     *         A {@code StringBuffer}
+     */
+    public String(StringBuffer buffer) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    /**
+     * Allocates a new string that contains the sequence of characters
+     * currently contained in the string builder argument. The contents of the
+     * string builder are copied; subsequent modification of the string builder
+     * does not affect the newly created string.
+     *
+     * <p> This constructor is provided to ease migration to {@code
+     * StringBuilder}. Obtaining a string from a string builder via the {@code
+     * toString} method is likely to run faster and is generally preferred.
+     *
+     * @param   builder
+     *          A {@code StringBuilder}
+     *
+     * @since  1.5
+     */
+    public String(StringBuilder builder) {
+        // Android-changed: Constructor unsupported as all calls are intercepted by the runtime.
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+
+    // Android-removed: Unused package-private constructor String(char[] value, boolean share).
+
+    // BEGIN Android-added: Constructor for internal use.
+    // Not implemented in java as all calls are intercepted by the runtime.
+    /**
+     * Package private constructor
+     *
+     * @deprecated Use {@link #String(char[],int,int)} instead.
+     */
+    @Deprecated
+    String(int offset, int count, char[] value) {
+        throw new UnsupportedOperationException("Use StringFactory instead.");
+    }
+    // END Android-added: Constructor for internal use.
+
+    /**
+     * Returns the length of this string.
+     * The length is equal to the number of <a href="Character.html#unicode">Unicode
+     * code units</a> in the string.
+     *
+     * @return  the length of the sequence of characters represented by this
+     *          object.
+     */
+    public int length() {
+        // BEGIN Android-changed: Get length from count field rather than value array (see above).
+        // return value.length;
+        final boolean STRING_COMPRESSION_ENABLED = true;
+        if (STRING_COMPRESSION_ENABLED) {
+            // For the compression purposes (save the characters as 8-bit if all characters
+            // are ASCII), the least significant bit of "count" is used as the compression flag.
+            return (count >>> 1);
+        } else {
+            return count;
+        }
+        // END Android-changed: Get length from count field rather than value array (see above).
+    }
+
+    /**
+     * Returns {@code true} if, and only if, {@link #length()} is {@code 0}.
+     *
+     * @return {@code true} if {@link #length()} is {@code 0}, otherwise
+     * {@code false}
+     *
+     * @since 1.6
+     */
+    public boolean isEmpty() {
+        // Android-changed: Get length from count field rather than value array (see above).
+        // Empty string has {@code count == 0} with or without string compression enabled.
+        // return value.length == 0;
+        return count == 0;
+    }
+
+    /**
+     * Returns the {@code char} value at the
+     * specified index. An index ranges from {@code 0} to
+     * {@code length() - 1}. The first {@code char} value of the sequence
+     * is at index {@code 0}, the next at index {@code 1},
+     * and so on, as for array indexing.
+     *
+     * <p>If the {@code char} value specified by the index is a
+     * <a href="Character.html#unicode">surrogate</a>, the surrogate
+     * value is returned.
+     *
+     * @param      index   the index of the {@code char} value.
+     * @return     the {@code char} value at the specified index of this string.
+     *             The first {@code char} value is at index {@code 0}.
+     * @exception  IndexOutOfBoundsException  if the {@code index}
+     *             argument is negative or not less than the length of this
+     *             string.
+     */
+    // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    @FastNative
+    public native char charAt(int index);
+    // END Android-changed: Replace with implementation in runtime to access chars (see above).
+
+    /**
+     * Returns the character (Unicode code point) at the specified
+     * index. The index refers to {@code char} values
+     * (Unicode code units) and ranges from {@code 0} to
+     * {@link #length()}{@code  - 1}.
+     *
+     * <p> If the {@code char} value specified at the given index
+     * is in the high-surrogate range, the following index is less
+     * than the length of this {@code String}, and the
+     * {@code char} value at the following index is in the
+     * low-surrogate range, then the supplementary code point
+     * corresponding to this surrogate pair is returned. Otherwise,
+     * the {@code char} value at the given index is returned.
+     *
+     * @param      index the index to the {@code char} values
+     * @return     the code point value of the character at the
+     *             {@code index}
+     * @exception  IndexOutOfBoundsException  if the {@code index}
+     *             argument is negative or not less than the length of this
+     *             string.
+     * @since      1.5
+     */
+    public int codePointAt(int index) {
+        if ((index < 0) || (index >= length())) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        // Android-changed: Skip codePointAtImpl optimization that needs access to java chars.
+        return Character.codePointAt(this, index);
+    }
+
+    /**
+     * Returns the character (Unicode code point) before the specified
+     * index. The index refers to {@code char} values
+     * (Unicode code units) and ranges from {@code 1} to {@link
+     * CharSequence#length() length}.
+     *
+     * <p> If the {@code char} value at {@code (index - 1)}
+     * is in the low-surrogate range, {@code (index - 2)} is not
+     * negative, and the {@code char} value at {@code (index -
+     * 2)} is in the high-surrogate range, then the
+     * supplementary code point value of the surrogate pair is
+     * returned. If the {@code char} value at {@code index -
+     * 1} is an unpaired low-surrogate or a high-surrogate, the
+     * surrogate value is returned.
+     *
+     * @param     index the index following the code point that should be returned
+     * @return    the Unicode code point value before the given index.
+     * @exception IndexOutOfBoundsException if the {@code index}
+     *            argument is less than 1 or greater than the length
+     *            of this string.
+     * @since     1.5
+     */
+    public int codePointBefore(int index) {
+        int i = index - 1;
+        if ((i < 0) || (i >= length())) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        // Android-changed: Skip codePointBeforeImpl optimization that needs access to java chars.
+        return Character.codePointBefore(this, index);
+    }
+
+    /**
+     * Returns the number of Unicode code points in the specified text
+     * range of this {@code String}. The text range begins at the
+     * specified {@code beginIndex} and extends to the
+     * {@code char} at index {@code endIndex - 1}. Thus the
+     * length (in {@code char}s) of the text range is
+     * {@code endIndex-beginIndex}. Unpaired surrogates within
+     * the text range count as one code point each.
+     *
+     * @param beginIndex the index to the first {@code char} of
+     * the text range.
+     * @param endIndex the index after the last {@code char} of
+     * the text range.
+     * @return the number of Unicode code points in the specified text
+     * range
+     * @exception IndexOutOfBoundsException if the
+     * {@code beginIndex} is negative, or {@code endIndex}
+     * is larger than the length of this {@code String}, or
+     * {@code beginIndex} is larger than {@code endIndex}.
+     * @since  1.5
+     */
+    public int codePointCount(int beginIndex, int endIndex) {
+        if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
+            throw new IndexOutOfBoundsException();
+        }
+        // Android-changed: Skip codePointCountImpl optimization that needs access to java chars.
+        return Character.codePointCount(this, beginIndex, endIndex);
+    }
+
+    /**
+     * Returns the index within this {@code String} that is
+     * offset from the given {@code index} by
+     * {@code codePointOffset} code points. Unpaired surrogates
+     * within the text range given by {@code index} and
+     * {@code codePointOffset} count as one code point each.
+     *
+     * @param index the index to be offset
+     * @param codePointOffset the offset in code points
+     * @return the index within this {@code String}
+     * @exception IndexOutOfBoundsException if {@code index}
+     *   is negative or larger then the length of this
+     *   {@code String}, or if {@code codePointOffset} is positive
+     *   and the substring starting with {@code index} has fewer
+     *   than {@code codePointOffset} code points,
+     *   or if {@code codePointOffset} is negative and the substring
+     *   before {@code index} has fewer than the absolute value
+     *   of {@code codePointOffset} code points.
+     * @since 1.5
+     */
+    public int offsetByCodePoints(int index, int codePointOffset) {
+        if (index < 0 || index > length()) {
+            throw new IndexOutOfBoundsException();
+        }
+        // Android-changed: Skip offsetByCodePointsImpl optimization that needs access to java chars
+        return Character.offsetByCodePoints(this, index, codePointOffset);
+    }
+
+    /**
+     * Copy characters from this string into dst starting at dstBegin.
+     * This method doesn't perform any range checking.
+     */
+    void getChars(char dst[], int dstBegin) {
+        // Android-changed: Replace arraycopy with native call since chars are managed by runtime.
+        getCharsNoCheck(0, length(), dst, dstBegin);
+    }
+
+    /**
+     * Copies characters from this string into the destination character
+     * array.
+     * <p>
+     * The first character to be copied is at index {@code srcBegin};
+     * the last character to be copied is at index {@code srcEnd-1}
+     * (thus the total number of characters to be copied is
+     * {@code srcEnd-srcBegin}). The characters are copied into the
+     * subarray of {@code dst} starting at index {@code dstBegin}
+     * and ending at index:
+     * <blockquote><pre>
+     *     dstBegin + (srcEnd-srcBegin) - 1
+     * </pre></blockquote>
+     *
+     * @param      srcBegin   index of the first character in the string
+     *                        to copy.
+     * @param      srcEnd     index after the last character in the string
+     *                        to copy.
+     * @param      dst        the destination array.
+     * @param      dstBegin   the start offset in the destination array.
+     * @exception IndexOutOfBoundsException If any of the following
+     *            is true:
+     *            <ul><li>{@code srcBegin} is negative.
+     *            <li>{@code srcBegin} is greater than {@code srcEnd}
+     *            <li>{@code srcEnd} is greater than the length of this
+     *                string
+     *            <li>{@code dstBegin} is negative
+     *            <li>{@code dstBegin+(srcEnd-srcBegin)} is larger than
+     *                {@code dst.length}</ul>
+     */
+    public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
+        // BEGIN Android-changed: Implement in terms of length() and native getCharsNoCheck method.
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+
+        if (srcBegin < 0) {
+            throw new StringIndexOutOfBoundsException(this, srcBegin);
+        }
+        if (srcEnd > length()) {
+            throw new StringIndexOutOfBoundsException(this, srcEnd);
+        }
+
+        int n = srcEnd - srcBegin;
+        if (srcEnd < srcBegin) {
+            throw new StringIndexOutOfBoundsException(this, srcBegin, n);
+        }
+
+        if (dstBegin < 0) {
+            throw new ArrayIndexOutOfBoundsException("dstBegin < 0. dstBegin=" + dstBegin);
+        }
+        // dstBegin can be equal to dst.length, but only in the case where zero chars are to be
+        // copied.
+        if (dstBegin > dst.length) {
+            throw new ArrayIndexOutOfBoundsException(
+                    "dstBegin > dst.length. dstBegin=" + dstBegin + ", dst.length=" + dst.length);
+        }
+        if (n > dst.length - dstBegin) {
+            throw new ArrayIndexOutOfBoundsException(
+                    "n > dst.length - dstBegin. n=" + n + ", dst.length=" + dst.length
+                            + "dstBegin=" + dstBegin);
+        }
+
+        getCharsNoCheck(srcBegin, srcEnd, dst, dstBegin);
+        // END Android-changed: Implement in terms of length() and native getCharsNoCheck method.
+    }
+
+    // BEGIN Android-added: Native method to access char storage managed by runtime.
+    /**
+     * getChars without bounds checks, for use by other classes
+     * within the java.lang package only.  The caller is responsible for
+     * ensuring that start >= 0 && start <= end && end <= count.
+     */
+    @FastNative
+    native void getCharsNoCheck(int start, int end, char[] buffer, int index);
+    // END Android-added: Native method to access char storage managed by runtime.
+
+    /**
+     * Copies characters from this string into the destination byte array. Each
+     * byte receives the 8 low-order bits of the corresponding character. The
+     * eight high-order bits of each character are not copied and do not
+     * participate in the transfer in any way.
+     *
+     * <p> The first character to be copied is at index {@code srcBegin}; the
+     * last character to be copied is at index {@code srcEnd-1}.  The total
+     * number of characters to be copied is {@code srcEnd-srcBegin}. The
+     * characters, converted to bytes, are copied into the subarray of {@code
+     * dst} starting at index {@code dstBegin} and ending at index:
+     *
+     * <blockquote><pre>
+     *     dstBegin + (srcEnd-srcBegin) - 1
+     * </pre></blockquote>
+     *
+     * @deprecated  This method does not properly convert characters into
+     * bytes.  As of JDK&nbsp;1.1, the preferred way to do this is via the
+     * {@link #getBytes()} method, which uses the platform's default charset.
+     *
+     * @param  srcBegin
+     *         Index of the first character in the string to copy
+     *
+     * @param  srcEnd
+     *         Index after the last character in the string to copy
+     *
+     * @param  dst
+     *         The destination array
+     *
+     * @param  dstBegin
+     *         The start offset in the destination array
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If any of the following is true:
+     *          <ul>
+     *            <li> {@code srcBegin} is negative
+     *            <li> {@code srcBegin} is greater than {@code srcEnd}
+     *            <li> {@code srcEnd} is greater than the length of this String
+     *            <li> {@code dstBegin} is negative
+     *            <li> {@code dstBegin+(srcEnd-srcBegin)} is larger than {@code
+     *                 dst.length}
+     *          </ul>
+     */
+    @Deprecated
+    public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
+        if (srcBegin < 0) {
+            throw new StringIndexOutOfBoundsException(this, srcBegin);
+        }
+        if (srcEnd > length()) {
+            throw new StringIndexOutOfBoundsException(this, srcEnd);
+        }
+        if (srcBegin > srcEnd) {
+            throw new StringIndexOutOfBoundsException(this, srcEnd - srcBegin);
+        }
+
+        int j = dstBegin;
+        int n = srcEnd;
+        int i = srcBegin;
+
+        while (i < n) {
+            dst[j++] = (byte)charAt(i++);
+        }
+    }
+
+    /**
+     * Encodes this {@code String} into a sequence of bytes using the named
+     * charset, storing the result into a new byte array.
+     *
+     * <p> The behavior of this method when this string cannot be encoded in
+     * the given charset is unspecified.  The {@link
+     * java.nio.charset.CharsetEncoder} class should be used when more control
+     * over the encoding process is required.
+     *
+     * @param  charsetName
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @return  The resultant byte array
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     *
+     * @since  JDK1.1
+     */
+    public byte[] getBytes(String charsetName)
+            throws UnsupportedEncodingException {
+        if (charsetName == null) throw new NullPointerException();
+        // Android-changed: Skip StringCoding optimization that needs access to java chars.
+        // return StringCoding.encode(charsetName, value, 0, value.length);
+        return getBytes(Charset.forNameUEE(charsetName));
+    }
+
+    /**
+     * Encodes this {@code String} into a sequence of bytes using the given
+     * {@linkplain java.nio.charset.Charset charset}, storing the result into a
+     * new byte array.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with this charset's default replacement byte array.  The
+     * {@link java.nio.charset.CharsetEncoder} class should be used when more
+     * control over the encoding process is required.
+     *
+     * @param  charset
+     *         The {@linkplain java.nio.charset.Charset} to be used to encode
+     *         the {@code String}
+     *
+     * @return  The resultant byte array
+     *
+     * @since  1.6
+     */
+    public byte[] getBytes(Charset charset) {
+        // BEGIN Android-changed: Skip StringCoding optimization that needs access to java chars.
+        // if (charset == null) throw new NullPointerException();
+        // return StringCoding.encode(charset, value, 0, value.length);
+        if (charset == null) {
+            throw new NullPointerException("charset == null");
+        }
+
+        final int len = length();
+        final String name = charset.name();
+        if ("UTF-8".equals(name)) {
+            return CharsetUtils.toUtf8Bytes(this, 0, len);
+        } else if ("ISO-8859-1".equals(name)) {
+            return CharsetUtils.toIsoLatin1Bytes(this, 0, len);
+        } else if ("US-ASCII".equals(name)) {
+            return CharsetUtils.toAsciiBytes(this, 0, len);
+        } else if ("UTF-16BE".equals(name)) {
+            return CharsetUtils.toBigEndianUtf16Bytes(this, 0, len);
+        }
+
+        ByteBuffer buffer = charset.encode(this);
+        byte[] bytes = new byte[buffer.limit()];
+        buffer.get(bytes);
+        return bytes;
+        // END Android-changed: Skip StringCoding optimization that needs access to java chars.
+    }
+
+    /**
+     * Encodes this {@code String} into a sequence of bytes using the
+     * platform's default charset, storing the result into a new byte array.
+     *
+     * <p> The behavior of this method when this string cannot be encoded in
+     * the default charset is unspecified.  The {@link
+     * java.nio.charset.CharsetEncoder} class should be used when more control
+     * over the encoding process is required.
+     *
+     * @return  The resultant byte array
+     *
+     * @since      JDK1.1
+     */
+    public byte[] getBytes() {
+        // Android-changed: Skip StringCoding optimization that needs access to java chars.
+        // return StringCoding.encode(value, 0, value.length);
+        return getBytes(Charset.defaultCharset());
+    }
+
+    /**
+     * Compares this string to the specified object.  The result is {@code
+     * true} if and only if the argument is not {@code null} and is a {@code
+     * String} object that represents the same sequence of characters as this
+     * object.
+     *
+     * @param  anObject
+     *         The object to compare this {@code String} against
+     *
+     * @return  {@code true} if the given object represents a {@code String}
+     *          equivalent to this string, {@code false} otherwise
+     *
+     * @see  #compareTo(String)
+     * @see  #equalsIgnoreCase(String)
+     */
+    public boolean equals(Object anObject) {
+        if (this == anObject) {
+            return true;
+        }
+        if (anObject instanceof String) {
+            String anotherString = (String)anObject;
+            int n = length();
+            if (n == anotherString.length()) {
+                int i = 0;
+                while (n-- != 0) {
+                    if (charAt(i) != anotherString.charAt(i))
+                            return false;
+                    i++;
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Compares this string to the specified {@code StringBuffer}.  The result
+     * is {@code true} if and only if this {@code String} represents the same
+     * sequence of characters as the specified {@code StringBuffer}. This method
+     * synchronizes on the {@code StringBuffer}.
+     *
+     * @param  sb
+     *         The {@code StringBuffer} to compare this {@code String} against
+     *
+     * @return  {@code true} if this {@code String} represents the same
+     *          sequence of characters as the specified {@code StringBuffer},
+     *          {@code false} otherwise
+     *
+     * @since  1.4
+     */
+    public boolean contentEquals(StringBuffer sb) {
+        return contentEquals((CharSequence)sb);
+    }
+
+    private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
+        char v2[] = sb.getValue();
+        int n = length();
+        if (n != sb.length()) {
+            return false;
+        }
+        for (int i = 0; i < n; i++) {
+            if (charAt(i) != v2[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Compares this string to the specified {@code CharSequence}.  The
+     * result is {@code true} if and only if this {@code String} represents the
+     * same sequence of char values as the specified sequence. Note that if the
+     * {@code CharSequence} is a {@code StringBuffer} then the method
+     * synchronizes on it.
+     *
+     * @param  cs
+     *         The sequence to compare this {@code String} against
+     *
+     * @return  {@code true} if this {@code String} represents the same
+     *          sequence of char values as the specified sequence, {@code
+     *          false} otherwise
+     *
+     * @since  1.5
+     */
+    public boolean contentEquals(CharSequence cs) {
+        // Argument is a StringBuffer, StringBuilder
+        if (cs instanceof AbstractStringBuilder) {
+            if (cs instanceof StringBuffer) {
+                synchronized(cs) {
+                   return nonSyncContentEquals((AbstractStringBuilder)cs);
+                }
+            } else {
+                return nonSyncContentEquals((AbstractStringBuilder)cs);
+            }
+        }
+        // Argument is a String
+        if (cs instanceof String) {
+            return equals(cs);
+        }
+        // Argument is a generic CharSequence
+        int n = length();
+        if (n != cs.length()) {
+            return false;
+        }
+        for (int i = 0; i < n; i++) {
+            if (charAt(i) != cs.charAt(i)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Compares this {@code String} to another {@code String}, ignoring case
+     * considerations.  Two strings are considered equal ignoring case if they
+     * are of the same length and corresponding characters in the two strings
+     * are equal ignoring case.
+     *
+     * <p> Two characters {@code c1} and {@code c2} are considered the same
+     * ignoring case if at least one of the following is true:
+     * <ul>
+     *   <li> The two characters are the same (as compared by the
+     *        {@code ==} operator)
+     *   <li> Applying the method {@link
+     *        java.lang.Character#toUpperCase(char)} to each character
+     *        produces the same result
+     *   <li> Applying the method {@link
+     *        java.lang.Character#toLowerCase(char)} to each character
+     *        produces the same result
+     * </ul>
+     *
+     * @param  anotherString
+     *         The {@code String} to compare this {@code String} against
+     *
+     * @return  {@code true} if the argument is not {@code null} and it
+     *          represents an equivalent {@code String} ignoring case; {@code
+     *          false} otherwise
+     *
+     * @see  #equals(Object)
+     */
+    public boolean equalsIgnoreCase(String anotherString) {
+        final int len = length();
+        return (this == anotherString) ? true
+                : (anotherString != null)
+                && (anotherString.length() == len)
+                && regionMatches(true, 0, anotherString, 0, len);
+    }
+
+    /**
+     * Compares two strings lexicographically.
+     * The comparison is based on the Unicode value of each character in
+     * the strings. The character sequence represented by this
+     * {@code String} object is compared lexicographically to the
+     * character sequence represented by the argument string. The result is
+     * a negative integer if this {@code String} object
+     * lexicographically precedes the argument string. The result is a
+     * positive integer if this {@code String} object lexicographically
+     * follows the argument string. The result is zero if the strings
+     * are equal; {@code compareTo} returns {@code 0} exactly when
+     * the {@link #equals(Object)} method would return {@code true}.
+     * <p>
+     * This is the definition of lexicographic ordering. If two strings are
+     * different, then either they have different characters at some index
+     * that is a valid index for both strings, or their lengths are different,
+     * or both. If they have different characters at one or more index
+     * positions, let <i>k</i> be the smallest such index; then the string
+     * whose character at position <i>k</i> has the smaller value, as
+     * determined by using the &lt; operator, lexicographically precedes the
+     * other string. In this case, {@code compareTo} returns the
+     * difference of the two character values at position {@code k} in
+     * the two string -- that is, the value:
+     * <blockquote><pre>
+     * this.charAt(k)-anotherString.charAt(k)
+     * </pre></blockquote>
+     * If there is no index position at which they differ, then the shorter
+     * string lexicographically precedes the longer string. In this case,
+     * {@code compareTo} returns the difference of the lengths of the
+     * strings -- that is, the value:
+     * <blockquote><pre>
+     * this.length()-anotherString.length()
+     * </pre></blockquote>
+     *
+     * @param   anotherString   the {@code String} to be compared.
+     * @return  the value {@code 0} if the argument string is equal to
+     *          this string; a value less than {@code 0} if this string
+     *          is lexicographically less than the string argument; and a
+     *          value greater than {@code 0} if this string is
+     *          lexicographically greater than the string argument.
+     */
+    // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    @FastNative
+    public native int compareTo(String anotherString);
+    // END Android-changed: Replace with implementation in runtime to access chars (see above).
+
+    /**
+     * A Comparator that orders {@code String} objects as by
+     * {@code compareToIgnoreCase}. This comparator is serializable.
+     * <p>
+     * Note that this Comparator does <em>not</em> take locale into account,
+     * and will result in an unsatisfactory ordering for certain locales.
+     * The java.text package provides <em>Collators</em> to allow
+     * locale-sensitive ordering.
+     *
+     * @see     java.text.Collator#compare(String, String)
+     * @since   1.2
+     */
+    public static final Comparator<String> CASE_INSENSITIVE_ORDER
+                                         = new CaseInsensitiveComparator();
+    private static class CaseInsensitiveComparator
+            implements Comparator<String>, java.io.Serializable {
+        // use serialVersionUID from JDK 1.2.2 for interoperability
+        private static final long serialVersionUID = 8575799808933029326L;
+
+        public int compare(String s1, String s2) {
+            int n1 = s1.length();
+            int n2 = s2.length();
+            int min = Math.min(n1, n2);
+            for (int i = 0; i < min; i++) {
+                char c1 = s1.charAt(i);
+                char c2 = s2.charAt(i);
+                if (c1 != c2) {
+                    c1 = Character.toUpperCase(c1);
+                    c2 = Character.toUpperCase(c2);
+                    if (c1 != c2) {
+                        c1 = Character.toLowerCase(c1);
+                        c2 = Character.toLowerCase(c2);
+                        if (c1 != c2) {
+                            // No overflow because of numeric promotion
+                            return c1 - c2;
+                        }
+                    }
+                }
+            }
+            return n1 - n2;
+        }
+
+        /** Replaces the de-serialized object. */
+        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
+    }
+
+    /**
+     * Compares two strings lexicographically, ignoring case
+     * differences. This method returns an integer whose sign is that of
+     * calling {@code compareTo} with normalized versions of the strings
+     * where case differences have been eliminated by calling
+     * {@code Character.toLowerCase(Character.toUpperCase(character))} on
+     * each character.
+     * <p>
+     * Note that this method does <em>not</em> take locale into account,
+     * and will result in an unsatisfactory ordering for certain locales.
+     * The java.text package provides <em>collators</em> to allow
+     * locale-sensitive ordering.
+     *
+     * @param   str   the {@code String} to be compared.
+     * @return  a negative integer, zero, or a positive integer as the
+     *          specified String is greater than, equal to, or less
+     *          than this String, ignoring case considerations.
+     * @see     java.text.Collator#compare(String, String)
+     * @since   1.2
+     */
+    public int compareToIgnoreCase(String str) {
+        return CASE_INSENSITIVE_ORDER.compare(this, str);
+    }
+
+    /**
+     * Tests if two string regions are equal.
+     * <p>
+     * A substring of this {@code String} object is compared to a substring
+     * of the argument other. The result is true if these substrings
+     * represent identical character sequences. The substring of this
+     * {@code String} object to be compared begins at index {@code toffset}
+     * and has length {@code len}. The substring of other to be compared
+     * begins at index {@code ooffset} and has length {@code len}. The
+     * result is {@code false} if and only if at least one of the following
+     * is true:
+     * <ul><li>{@code toffset} is negative.
+     * <li>{@code ooffset} is negative.
+     * <li>{@code toffset+len} is greater than the length of this
+     * {@code String} object.
+     * <li>{@code ooffset+len} is greater than the length of the other
+     * argument.
+     * <li>There is some nonnegative integer <i>k</i> less than {@code len}
+     * such that:
+     * {@code this.charAt(toffset + }<i>k</i>{@code ) != other.charAt(ooffset + }
+     * <i>k</i>{@code )}
+     * </ul>
+     *
+     * @param   toffset   the starting offset of the subregion in this string.
+     * @param   other     the string argument.
+     * @param   ooffset   the starting offset of the subregion in the string
+     *                    argument.
+     * @param   len       the number of characters to compare.
+     * @return  {@code true} if the specified subregion of this string
+     *          exactly matches the specified subregion of the string argument;
+     *          {@code false} otherwise.
+     */
+    public boolean regionMatches(int toffset, String other, int ooffset,
+            int len) {
+        int to = toffset;
+        int po = ooffset;
+        // Note: toffset, ooffset, or len might be near -1>>>1.
+        if ((ooffset < 0) || (toffset < 0)
+                || (toffset > (long)length() - len)
+                || (ooffset > (long)other.length() - len)) {
+            return false;
+        }
+        while (len-- > 0) {
+            if (charAt(to++) != other.charAt(po++)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Tests if two string regions are equal.
+     * <p>
+     * A substring of this {@code String} object is compared to a substring
+     * of the argument {@code other}. The result is {@code true} if these
+     * substrings represent character sequences that are the same, ignoring
+     * case if and only if {@code ignoreCase} is true. The substring of
+     * this {@code String} object to be compared begins at index
+     * {@code toffset} and has length {@code len}. The substring of
+     * {@code other} to be compared begins at index {@code ooffset} and
+     * has length {@code len}. The result is {@code false} if and only if
+     * at least one of the following is true:
+     * <ul><li>{@code toffset} is negative.
+     * <li>{@code ooffset} is negative.
+     * <li>{@code toffset+len} is greater than the length of this
+     * {@code String} object.
+     * <li>{@code ooffset+len} is greater than the length of the other
+     * argument.
+     * <li>{@code ignoreCase} is {@code false} and there is some nonnegative
+     * integer <i>k</i> less than {@code len} such that:
+     * <blockquote><pre>
+     * this.charAt(toffset+k) != other.charAt(ooffset+k)
+     * </pre></blockquote>
+     * <li>{@code ignoreCase} is {@code true} and there is some nonnegative
+     * integer <i>k</i> less than {@code len} such that:
+     * <blockquote><pre>
+     * Character.toLowerCase(this.charAt(toffset+k)) !=
+     Character.toLowerCase(other.charAt(ooffset+k))
+     * </pre></blockquote>
+     * and:
+     * <blockquote><pre>
+     * Character.toUpperCase(this.charAt(toffset+k)) !=
+     *         Character.toUpperCase(other.charAt(ooffset+k))
+     * </pre></blockquote>
+     * </ul>
+     *
+     * @param   ignoreCase   if {@code true}, ignore case when comparing
+     *                       characters.
+     * @param   toffset      the starting offset of the subregion in this
+     *                       string.
+     * @param   other        the string argument.
+     * @param   ooffset      the starting offset of the subregion in the string
+     *                       argument.
+     * @param   len          the number of characters to compare.
+     * @return  {@code true} if the specified subregion of this string
+     *          matches the specified subregion of the string argument;
+     *          {@code false} otherwise. Whether the matching is exact
+     *          or case insensitive depends on the {@code ignoreCase}
+     *          argument.
+     */
+    public boolean regionMatches(boolean ignoreCase, int toffset,
+            String other, int ooffset, int len) {
+        int to = toffset;
+        int po = ooffset;
+        // Note: toffset, ooffset, or len might be near -1>>>1.
+        if ((ooffset < 0) || (toffset < 0)
+                || (toffset > (long)length() - len)
+                || (ooffset > (long)other.length() - len)) {
+            return false;
+        }
+        while (len-- > 0) {
+            char c1 = charAt(to++);
+            char c2 = other.charAt(po++);
+            if (c1 == c2) {
+                continue;
+            }
+            if (ignoreCase) {
+                // If characters don't match but case may be ignored,
+                // try converting both characters to uppercase.
+                // If the results match, then the comparison scan should
+                // continue.
+                char u1 = Character.toUpperCase(c1);
+                char u2 = Character.toUpperCase(c2);
+                if (u1 == u2) {
+                    continue;
+                }
+                // Unfortunately, conversion to uppercase does not work properly
+                // for the Georgian alphabet, which has strange rules about case
+                // conversion.  So we need to make one last check before
+                // exiting.
+                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
+                    continue;
+                }
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Tests if the substring of this string beginning at the
+     * specified index starts with the specified prefix.
+     *
+     * @param   prefix    the prefix.
+     * @param   toffset   where to begin looking in this string.
+     * @return  {@code true} if the character sequence represented by the
+     *          argument is a prefix of the substring of this object starting
+     *          at index {@code toffset}; {@code false} otherwise.
+     *          The result is {@code false} if {@code toffset} is
+     *          negative or greater than the length of this
+     *          {@code String} object; otherwise the result is the same
+     *          as the result of the expression
+     *          <pre>
+     *          this.substring(toffset).startsWith(prefix)
+     *          </pre>
+     */
+    public boolean startsWith(String prefix, int toffset) {
+        int to = toffset;
+        int po = 0;
+        int pc = prefix.length();
+        // Note: toffset might be near -1>>>1.
+        if ((toffset < 0) || (toffset > length() - pc)) {
+            return false;
+        }
+        while (--pc >= 0) {
+            if (charAt(to++) != prefix.charAt(po++)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Tests if this string starts with the specified prefix.
+     *
+     * @param   prefix   the prefix.
+     * @return  {@code true} if the character sequence represented by the
+     *          argument is a prefix of the character sequence represented by
+     *          this string; {@code false} otherwise.
+     *          Note also that {@code true} will be returned if the
+     *          argument is an empty string or is equal to this
+     *          {@code String} object as determined by the
+     *          {@link #equals(Object)} method.
+     * @since   1. 0
+     */
+    public boolean startsWith(String prefix) {
+        return startsWith(prefix, 0);
+    }
+
+    /**
+     * Tests if this string ends with the specified suffix.
+     *
+     * @param   suffix   the suffix.
+     * @return  {@code true} if the character sequence represented by the
+     *          argument is a suffix of the character sequence represented by
+     *          this object; {@code false} otherwise. Note that the
+     *          result will be {@code true} if the argument is the
+     *          empty string or is equal to this {@code String} object
+     *          as determined by the {@link #equals(Object)} method.
+     */
+    public boolean endsWith(String suffix) {
+        return startsWith(suffix, length() - suffix.length());
+    }
+
+    /**
+     * Returns a hash code for this string. The hash code for a
+     * {@code String} object is computed as
+     * <blockquote><pre>
+     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
+     * </pre></blockquote>
+     * using {@code int} arithmetic, where {@code s[i]} is the
+     * <i>i</i>th character of the string, {@code n} is the length of
+     * the string, and {@code ^} indicates exponentiation.
+     * (The hash value of the empty string is zero.)
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        int h = hash;
+        final int len = length();
+        if (h == 0 && len > 0) {
+            for (int i = 0; i < len; i++) {
+                h = 31 * h + charAt(i);
+            }
+            hash = h;
+        }
+        return h;
+    }
+
+    /**
+     * Returns the index within this string of the first occurrence of
+     * the specified character. If a character with value
+     * {@code ch} occurs in the character sequence represented by
+     * this {@code String} object, then the index (in Unicode
+     * code units) of the first such occurrence is returned. For
+     * values of {@code ch} in the range from 0 to 0xFFFF
+     * (inclusive), this is the smallest value <i>k</i> such that:
+     * <blockquote><pre>
+     * this.charAt(<i>k</i>) == ch
+     * </pre></blockquote>
+     * is true. For other values of {@code ch}, it is the
+     * smallest value <i>k</i> such that:
+     * <blockquote><pre>
+     * this.codePointAt(<i>k</i>) == ch
+     * </pre></blockquote>
+     * is true. In either case, if no such character occurs in this
+     * string, then {@code -1} is returned.
+     *
+     * @param   ch   a character (Unicode code point).
+     * @return  the index of the first occurrence of the character in the
+     *          character sequence represented by this object, or
+     *          {@code -1} if the character does not occur.
+     */
+    public int indexOf(int ch) {
+        return indexOf(ch, 0);
+    }
+
+    /**
+     * Returns the index within this string of the first occurrence of the
+     * specified character, starting the search at the specified index.
+     * <p>
+     * If a character with value {@code ch} occurs in the
+     * character sequence represented by this {@code String}
+     * object at an index no smaller than {@code fromIndex}, then
+     * the index of the first such occurrence is returned. For values
+     * of {@code ch} in the range from 0 to 0xFFFF (inclusive),
+     * this is the smallest value <i>k</i> such that:
+     * <blockquote><pre>
+     * (this.charAt(<i>k</i>) == ch) {@code &&} (<i>k</i> &gt;= fromIndex)
+     * </pre></blockquote>
+     * is true. For other values of {@code ch}, it is the
+     * smallest value <i>k</i> such that:
+     * <blockquote><pre>
+     * (this.codePointAt(<i>k</i>) == ch) {@code &&} (<i>k</i> &gt;= fromIndex)
+     * </pre></blockquote>
+     * is true. In either case, if no such character occurs in this
+     * string at or after position {@code fromIndex}, then
+     * {@code -1} is returned.
+     *
+     * <p>
+     * There is no restriction on the value of {@code fromIndex}. If it
+     * is negative, it has the same effect as if it were zero: this entire
+     * string may be searched. If it is greater than the length of this
+     * string, it has the same effect as if it were equal to the length of
+     * this string: {@code -1} is returned.
+     *
+     * <p>All indices are specified in {@code char} values
+     * (Unicode code units).
+     *
+     * @param   ch          a character (Unicode code point).
+     * @param   fromIndex   the index to start the search from.
+     * @return  the index of the first occurrence of the character in the
+     *          character sequence represented by this object that is greater
+     *          than or equal to {@code fromIndex}, or {@code -1}
+     *          if the character does not occur.
+     */
+    public int indexOf(int ch, int fromIndex) {
+        final int max = length();
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        } else if (fromIndex >= max) {
+            // Note: fromIndex might be near -1>>>1.
+            return -1;
+        }
+
+        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            // handle most cases here (ch is a BMP code point or a
+            // negative value (invalid code point))
+            for (int i = fromIndex; i < max; i++) {
+                if (charAt(i) == ch) {
+                    return i;
+                }
+            }
+            return -1;
+        } else {
+            return indexOfSupplementary(ch, fromIndex);
+        }
+    }
+
+    /**
+     * Handles (rare) calls of indexOf with a supplementary character.
+     */
+    private int indexOfSupplementary(int ch, int fromIndex) {
+        if (Character.isValidCodePoint(ch)) {
+            final char hi = Character.highSurrogate(ch);
+            final char lo = Character.lowSurrogate(ch);
+            final int max = length() - 1;
+            for (int i = fromIndex; i < max; i++) {
+                if (charAt(i) == hi && charAt(i + 1) == lo) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index within this string of the last occurrence of
+     * the specified character. For values of {@code ch} in the
+     * range from 0 to 0xFFFF (inclusive), the index (in Unicode code
+     * units) returned is the largest value <i>k</i> such that:
+     * <blockquote><pre>
+     * this.charAt(<i>k</i>) == ch
+     * </pre></blockquote>
+     * is true. For other values of {@code ch}, it is the
+     * largest value <i>k</i> such that:
+     * <blockquote><pre>
+     * this.codePointAt(<i>k</i>) == ch
+     * </pre></blockquote>
+     * is true.  In either case, if no such character occurs in this
+     * string, then {@code -1} is returned.  The
+     * {@code String} is searched backwards starting at the last
+     * character.
+     *
+     * @param   ch   a character (Unicode code point).
+     * @return  the index of the last occurrence of the character in the
+     *          character sequence represented by this object, or
+     *          {@code -1} if the character does not occur.
+     */
+    public int lastIndexOf(int ch) {
+        return lastIndexOf(ch, length() - 1);
+    }
+
+    /**
+     * Returns the index within this string of the last occurrence of
+     * the specified character, searching backward starting at the
+     * specified index. For values of {@code ch} in the range
+     * from 0 to 0xFFFF (inclusive), the index returned is the largest
+     * value <i>k</i> such that:
+     * <blockquote><pre>
+     * (this.charAt(<i>k</i>) == ch) {@code &&} (<i>k</i> &lt;= fromIndex)
+     * </pre></blockquote>
+     * is true. For other values of {@code ch}, it is the
+     * largest value <i>k</i> such that:
+     * <blockquote><pre>
+     * (this.codePointAt(<i>k</i>) == ch) {@code &&} (<i>k</i> &lt;= fromIndex)
+     * </pre></blockquote>
+     * is true. In either case, if no such character occurs in this
+     * string at or before position {@code fromIndex}, then
+     * {@code -1} is returned.
+     *
+     * <p>All indices are specified in {@code char} values
+     * (Unicode code units).
+     *
+     * @param   ch          a character (Unicode code point).
+     * @param   fromIndex   the index to start the search from. There is no
+     *          restriction on the value of {@code fromIndex}. If it is
+     *          greater than or equal to the length of this string, it has
+     *          the same effect as if it were equal to one less than the
+     *          length of this string: this entire string may be searched.
+     *          If it is negative, it has the same effect as if it were -1:
+     *          -1 is returned.
+     * @return  the index of the last occurrence of the character in the
+     *          character sequence represented by this object that is less
+     *          than or equal to {@code fromIndex}, or {@code -1}
+     *          if the character does not occur before that point.
+     */
+    public int lastIndexOf(int ch, int fromIndex) {
+        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            // handle most cases here (ch is a BMP code point or a
+            // negative value (invalid code point))
+            int i = Math.min(fromIndex, length() - 1);
+            for (; i >= 0; i--) {
+                if (charAt(i) == ch) {
+                    return i;
+                }
+            }
+            return -1;
+        } else {
+            return lastIndexOfSupplementary(ch, fromIndex);
+        }
+    }
+
+    /**
+     * Handles (rare) calls of lastIndexOf with a supplementary character.
+     */
+    private int lastIndexOfSupplementary(int ch, int fromIndex) {
+        if (Character.isValidCodePoint(ch)) {
+            char hi = Character.highSurrogate(ch);
+            char lo = Character.lowSurrogate(ch);
+            int i = Math.min(fromIndex, length() - 2);
+            for (; i >= 0; i--) {
+                if (charAt(i) == hi && charAt(i + 1) == lo) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index within this string of the first occurrence of the
+     * specified substring.
+     *
+     * <p>The returned index is the smallest value <i>k</i> for which:
+     * <blockquote><pre>
+     * this.startsWith(str, <i>k</i>)
+     * </pre></blockquote>
+     * If no such value of <i>k</i> exists, then {@code -1} is returned.
+     *
+     * @param   str   the substring to search for.
+     * @return  the index of the first occurrence of the specified substring,
+     *          or {@code -1} if there is no such occurrence.
+     */
+    public int indexOf(String str) {
+        return indexOf(str, 0);
+    }
+
+    /**
+     * Returns the index within this string of the first occurrence of the
+     * specified substring, starting at the specified index.
+     *
+     * <p>The returned index is the smallest value <i>k</i> for which:
+     * <blockquote><pre>
+     * <i>k</i> &gt;= fromIndex {@code &&} this.startsWith(str, <i>k</i>)
+     * </pre></blockquote>
+     * If no such value of <i>k</i> exists, then {@code -1} is returned.
+     *
+     * @param   str         the substring to search for.
+     * @param   fromIndex   the index from which to start the search.
+     * @return  the index of the first occurrence of the specified substring,
+     *          starting at the specified index,
+     *          or {@code -1} if there is no such occurrence.
+     */
+    public int indexOf(String str, int fromIndex) {
+        // Android-changed: Delegate to the static indexOf method below.
+        return indexOf(this, str, fromIndex);
+    }
+
+    // BEGIN Android-added: Private static indexOf method that takes String parameters.
+    // The use of length(), charAt(), etc. makes it more efficient for compressed strings.
+    /**
+     * The source is the string being searched, and the target is the string being searched for.
+     *
+     * @param   source       the characters being searched.
+     * @param   target       the characters being searched for.
+     * @param   fromIndex    the index to begin searching from.
+     */
+    private static int indexOf(String source, String target, int fromIndex) {
+        final int sourceLength = source.length();
+        final int targetLength = target.length();
+        if (fromIndex >= sourceLength) {
+            return (targetLength == 0 ? sourceLength : -1);
+        }
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        }
+        if (targetLength == 0) {
+            return fromIndex;
+        }
+
+        char first = target.charAt(0);
+        int max = (sourceLength - targetLength);
+
+        for (int i = fromIndex; i <= max; i++) {
+            /* Look for first character. */
+            if (source.charAt(i)!= first) {
+                while (++i <= max && source.charAt(i) != first);
+            }
+
+            /* Found first character, now look at the rest of v2 */
+            if (i <= max) {
+                int j = i + 1;
+                int end = j + targetLength - 1;
+                for (int k = 1; j < end && source.charAt(j)
+                         == target.charAt(k); j++, k++);
+
+                if (j == end) {
+                    /* Found whole string. */
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+    // END Android-added: Private static indexOf method that takes String parameters.
+
+    /**
+     * Code shared by String and AbstractStringBuilder to do searches. The
+     * source is the character array being searched, and the target
+     * is the string being searched for.
+     *
+     * @param   source       the characters being searched.
+     * @param   sourceOffset offset of the source string.
+     * @param   sourceCount  count of the source string.
+     * @param   target       the characters being searched for.
+     * @param   fromIndex    the index to begin searching from.
+     */
+    static int indexOf(char[] source, int sourceOffset, int sourceCount,
+            String target, int fromIndex) {
+        return indexOf(source, sourceOffset, sourceCount,
+                       target.toCharArray(), 0, target.length(),
+                       fromIndex);
+    }
+
+    /**
+     * Code shared by String and StringBuffer to do searches. The
+     * source is the character array being searched, and the target
+     * is the string being searched for.
+     *
+     * @param   source       the characters being searched.
+     * @param   sourceOffset offset of the source string.
+     * @param   sourceCount  count of the source string.
+     * @param   target       the characters being searched for.
+     * @param   targetOffset offset of the target string.
+     * @param   targetCount  count of the target string.
+     * @param   fromIndex    the index to begin searching from.
+     */
+    static int indexOf(char[] source, int sourceOffset, int sourceCount,
+            char[] target, int targetOffset, int targetCount,
+            int fromIndex) {
+        if (fromIndex >= sourceCount) {
+            return (targetCount == 0 ? sourceCount : -1);
+        }
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        }
+        if (targetCount == 0) {
+            return fromIndex;
+        }
+
+        char first = target[targetOffset];
+        int max = sourceOffset + (sourceCount - targetCount);
+
+        for (int i = sourceOffset + fromIndex; i <= max; i++) {
+            /* Look for first character. */
+            if (source[i] != first) {
+                while (++i <= max && source[i] != first);
+            }
+
+            /* Found first character, now look at the rest of v2 */
+            if (i <= max) {
+                int j = i + 1;
+                int end = j + targetCount - 1;
+                for (int k = targetOffset + 1; j < end && source[j]
+                        == target[k]; j++, k++);
+
+                if (j == end) {
+                    /* Found whole string. */
+                    return i - sourceOffset;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index within this string of the last occurrence of the
+     * specified substring.  The last occurrence of the empty string ""
+     * is considered to occur at the index value {@code this.length()}.
+     *
+     * <p>The returned index is the largest value <i>k</i> for which:
+     * <blockquote><pre>
+     * this.startsWith(str, <i>k</i>)
+     * </pre></blockquote>
+     * If no such value of <i>k</i> exists, then {@code -1} is returned.
+     *
+     * @param   str   the substring to search for.
+     * @return  the index of the last occurrence of the specified substring,
+     *          or {@code -1} if there is no such occurrence.
+     */
+    public int lastIndexOf(String str) {
+        return lastIndexOf(str, length());
+    }
+
+    /**
+     * Returns the index within this string of the last occurrence of the
+     * specified substring, searching backward starting at the specified index.
+     *
+     * <p>The returned index is the largest value <i>k</i> for which:
+     * <blockquote><pre>
+     * <i>k</i> {@code <=} fromIndex {@code &&} this.startsWith(str, <i>k</i>)
+     * </pre></blockquote>
+     * If no such value of <i>k</i> exists, then {@code -1} is returned.
+     *
+     * @param   str         the substring to search for.
+     * @param   fromIndex   the index to start the search from.
+     * @return  the index of the last occurrence of the specified substring,
+     *          searching backward from the specified index,
+     *          or {@code -1} if there is no such occurrence.
+     */
+    public int lastIndexOf(String str, int fromIndex) {
+        // Android-changed: Change parameters to static lastIndexOf to match new signature below.
+        return lastIndexOf(this, str, fromIndex);
+    }
+
+    // BEGIN Android-added: Private static lastIndexOf method that takes String parameters.
+    // The use of length(), charAt(), etc. makes it more efficient for compressed strings.
+    /**
+     * The source is the string being searched, and the target is the string being searched for.
+     *
+     * @param   source       the characters being searched.
+     * @param   target       the characters being searched for.
+     * @param   fromIndex    the index to begin searching from.
+     */
+    private static int lastIndexOf(String source, String target, int fromIndex) {
+        /*
+         * Check arguments; return immediately where possible. For
+         * consistency, don't check for null str.
+         */
+        final int sourceLength = source.length();
+        final int targetLength = target.length();
+        int rightIndex = sourceLength - targetLength;
+        if (fromIndex < 0) {
+            return -1;
+        }
+        if (fromIndex > rightIndex) {
+            fromIndex = rightIndex;
+        }
+        /* Empty string always matches. */
+        if (targetLength == 0) {
+            return fromIndex;
+        }
+
+        int strLastIndex = targetLength - 1;
+        char strLastChar = target.charAt(strLastIndex);
+        int min = targetLength - 1;
+        int i = min + fromIndex;
+
+        startSearchForLastChar:
+        while (true) {
+            while (i >= min && source.charAt(i) != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - (targetLength - 1);
+            int k = strLastIndex - 1;
+
+            while (j > start) {
+                if (source.charAt(j--) != target.charAt(k--)) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start + 1;
+        }
+    }
+    // END Android-added: Private static lastIndexOf method that takes String parameters.
+
+    /**
+     * Code shared by String and AbstractStringBuilder to do searches. The
+     * source is the character array being searched, and the target
+     * is the string being searched for.
+     *
+     * @param   source       the characters being searched.
+     * @param   sourceOffset offset of the source string.
+     * @param   sourceCount  count of the source string.
+     * @param   target       the characters being searched for.
+     * @param   fromIndex    the index to begin searching from.
+     */
+    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
+            String target, int fromIndex) {
+        return lastIndexOf(source, sourceOffset, sourceCount,
+                       target.toCharArray(), 0, target.length(),
+                       fromIndex);
+    }
+
+    /**
+     * Code shared by String and StringBuffer to do searches. The
+     * source is the character array being searched, and the target
+     * is the string being searched for.
+     *
+     * @param   source       the characters being searched.
+     * @param   sourceOffset offset of the source string.
+     * @param   sourceCount  count of the source string.
+     * @param   target       the characters being searched for.
+     * @param   targetOffset offset of the target string.
+     * @param   targetCount  count of the target string.
+     * @param   fromIndex    the index to begin searching from.
+     */
+    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
+            char[] target, int targetOffset, int targetCount,
+            int fromIndex) {
+        /*
+         * Check arguments; return immediately where possible. For
+         * consistency, don't check for null str.
+         */
+        int rightIndex = sourceCount - targetCount;
+        if (fromIndex < 0) {
+            return -1;
+        }
+        if (fromIndex > rightIndex) {
+            fromIndex = rightIndex;
+        }
+        /* Empty string always matches. */
+        if (targetCount == 0) {
+            return fromIndex;
+        }
+
+        int strLastIndex = targetOffset + targetCount - 1;
+        char strLastChar = target[strLastIndex];
+        int min = sourceOffset + targetCount - 1;
+        int i = min + fromIndex;
+
+    startSearchForLastChar:
+        while (true) {
+            while (i >= min && source[i] != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - (targetCount - 1);
+            int k = strLastIndex - 1;
+
+            while (j > start) {
+                if (source[j--] != target[k--]) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start - sourceOffset + 1;
+        }
+    }
+
+    /**
+     * Returns a string that is a substring of this string. The
+     * substring begins with the character at the specified index and
+     * extends to the end of this string. <p>
+     * Examples:
+     * <blockquote><pre>
+     * "unhappy".substring(2) returns "happy"
+     * "Harbison".substring(3) returns "bison"
+     * "emptiness".substring(9) returns "" (an empty string)
+     * </pre></blockquote>
+     *
+     * @param      beginIndex   the beginning index, inclusive.
+     * @return     the specified substring.
+     * @exception  IndexOutOfBoundsException  if
+     *             {@code beginIndex} is negative or larger than the
+     *             length of this {@code String} object.
+     */
+    public String substring(int beginIndex) {
+        if (beginIndex < 0) {
+            throw new StringIndexOutOfBoundsException(this, beginIndex);
+        }
+        int subLen = length() - beginIndex;
+        if (subLen < 0) {
+            throw new StringIndexOutOfBoundsException(this, beginIndex);
+        }
+        // Android-changed: Use native fastSubstring instead of String constructor.
+        return (beginIndex == 0) ? this : fastSubstring(beginIndex, subLen);
+    }
+
+    /**
+     * Returns a string that is a substring of this string. The
+     * substring begins at the specified {@code beginIndex} and
+     * extends to the character at index {@code endIndex - 1}.
+     * Thus the length of the substring is {@code endIndex-beginIndex}.
+     * <p>
+     * Examples:
+     * <blockquote><pre>
+     * "hamburger".substring(4, 8) returns "urge"
+     * "smiles".substring(1, 5) returns "mile"
+     * </pre></blockquote>
+     *
+     * @param      beginIndex   the beginning index, inclusive.
+     * @param      endIndex     the ending index, exclusive.
+     * @return     the specified substring.
+     * @exception  IndexOutOfBoundsException  if the
+     *             {@code beginIndex} is negative, or
+     *             {@code endIndex} is larger than the length of
+     *             this {@code String} object, or
+     *             {@code beginIndex} is larger than
+     *             {@code endIndex}.
+     */
+    public String substring(int beginIndex, int endIndex) {
+        if (beginIndex < 0) {
+            throw new StringIndexOutOfBoundsException(this, beginIndex);
+        }
+        if (endIndex > length()) {
+            throw new StringIndexOutOfBoundsException(this, endIndex);
+        }
+        int subLen = endIndex - beginIndex;
+        if (subLen < 0) {
+            throw new StringIndexOutOfBoundsException(subLen);
+        }
+
+        // Android-changed: Use native fastSubstring instead of String constructor.
+        return ((beginIndex == 0) && (endIndex == length())) ? this
+                : fastSubstring(beginIndex, subLen);
+    }
+
+    // BEGIN Android-added: Native method to access char storage managed by runtime.
+    @FastNative
+    private native String fastSubstring(int start, int length);
+    // END Android-added: Native method to access char storage managed by runtime.
+
+    /**
+     * Returns a character sequence that is a subsequence of this sequence.
+     *
+     * <p> An invocation of this method of the form
+     *
+     * <blockquote><pre>
+     * str.subSequence(begin,&nbsp;end)</pre></blockquote>
+     *
+     * behaves in exactly the same way as the invocation
+     *
+     * <blockquote><pre>
+     * str.substring(begin,&nbsp;end)</pre></blockquote>
+     *
+     * @apiNote
+     * This method is defined so that the {@code String} class can implement
+     * the {@link CharSequence} interface.
+     *
+     * @param   beginIndex   the begin index, inclusive.
+     * @param   endIndex     the end index, exclusive.
+     * @return  the specified subsequence.
+     *
+     * @throws  IndexOutOfBoundsException
+     *          if {@code beginIndex} or {@code endIndex} is negative,
+     *          if {@code endIndex} is greater than {@code length()},
+     *          or if {@code beginIndex} is greater than {@code endIndex}
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public CharSequence subSequence(int beginIndex, int endIndex) {
+        return this.substring(beginIndex, endIndex);
+    }
+
+    /**
+     * Concatenates the specified string to the end of this string.
+     * <p>
+     * If the length of the argument string is {@code 0}, then this
+     * {@code String} object is returned. Otherwise, a
+     * {@code String} object is returned that represents a character
+     * sequence that is the concatenation of the character sequence
+     * represented by this {@code String} object and the character
+     * sequence represented by the argument string.<p>
+     * Examples:
+     * <blockquote><pre>
+     * "cares".concat("s") returns "caress"
+     * "to".concat("get").concat("her") returns "together"
+     * </pre></blockquote>
+     *
+     * @param   str   the {@code String} that is concatenated to the end
+     *                of this {@code String}.
+     * @return  a string that represents the concatenation of this object's
+     *          characters followed by the string argument's characters.
+     */
+    // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    @FastNative
+    public native String concat(String str);
+    // END Android-changed: Replace with implementation in runtime to access chars (see above).
+
+    /**
+     * Returns a string resulting from replacing all occurrences of
+     * {@code oldChar} in this string with {@code newChar}.
+     * <p>
+     * If the character {@code oldChar} does not occur in the
+     * character sequence represented by this {@code String} object,
+     * then a reference to this {@code String} object is returned.
+     * Otherwise, a {@code String} object is returned that
+     * represents a character sequence identical to the character sequence
+     * represented by this {@code String} object, except that every
+     * occurrence of {@code oldChar} is replaced by an occurrence
+     * of {@code newChar}.
+     * <p>
+     * Examples:
+     * <blockquote><pre>
+     * "mesquite in your cellar".replace('e', 'o')
+     *         returns "mosquito in your collar"
+     * "the war of baronets".replace('r', 'y')
+     *         returns "the way of bayonets"
+     * "sparring with a purple porpoise".replace('p', 't')
+     *         returns "starring with a turtle tortoise"
+     * "JonL".replace('q', 'x') returns "JonL" (no change)
+     * </pre></blockquote>
+     *
+     * @param   oldChar   the old character.
+     * @param   newChar   the new character.
+     * @return  a string derived from this string by replacing every
+     *          occurrence of {@code oldChar} with {@code newChar}.
+     */
+    public String replace(char oldChar, char newChar) {
+        // BEGIN Android-changed: Replace with implementation using native doReplace method.
+        if (oldChar != newChar) {
+            final int len = length();
+            for (int i = 0; i < len; ++i) {
+                if (charAt(i) == oldChar) {
+                    return doReplace(oldChar, newChar);
+                }
+            }
+        }
+        // END Android-changed: Replace with implementation using native doReplace method.
+        return this;
+    }
+
+    // BEGIN Android-added: Native method to access char storage managed by runtime.
+    // Implementation of replace(char oldChar, char newChar) called when we found a match.
+    @FastNative
+    private native String doReplace(char oldChar, char newChar);
+    // END Android-added: Native method to access char storage managed by runtime.
+
+    /**
+     * Tells whether or not this string matches the given <a
+     * href="../util/regex/Pattern.html#sum">regular expression</a>.
+     *
+     * <p> An invocation of this method of the form
+     * <i>str</i>{@code .matches(}<i>regex</i>{@code )} yields exactly the
+     * same result as the expression
+     *
+     * <blockquote>
+     * {@link java.util.regex.Pattern}.{@link java.util.regex.Pattern#matches(String,CharSequence)
+     * matches(<i>regex</i>, <i>str</i>)}
+     * </blockquote>
+     *
+     * @param   regex
+     *          the regular expression to which this string is to be matched
+     *
+     * @return  {@code true} if, and only if, this string matches the
+     *          given regular expression
+     *
+     * @throws  PatternSyntaxException
+     *          if the regular expression's syntax is invalid
+     *
+     * @see java.util.regex.Pattern
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public boolean matches(String regex) {
+        return Pattern.matches(regex, this);
+    }
+
+    /**
+     * Returns true if and only if this string contains the specified
+     * sequence of char values.
+     *
+     * @param s the sequence to search for
+     * @return true if this string contains {@code s}, false otherwise
+     * @since 1.5
+     */
+    public boolean contains(CharSequence s) {
+        return indexOf(s.toString()) > -1;
+    }
+
+    /**
+     * Replaces the first substring of this string that matches the given <a
+     * href="../util/regex/Pattern.html#sum">regular expression</a> with the
+     * given replacement.
+     *
+     * <p> An invocation of this method of the form
+     * <i>str</i>{@code .replaceFirst(}<i>regex</i>{@code ,} <i>repl</i>{@code )}
+     * yields exactly the same result as the expression
+     *
+     * <blockquote>
+     * <code>
+     * {@link java.util.regex.Pattern}.{@link
+     * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
+     * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(<i>str</i>).{@link
+     * java.util.regex.Matcher#replaceFirst replaceFirst}(<i>repl</i>)
+     * </code>
+     * </blockquote>
+     *
+     *<p>
+     * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
+     * replacement string may cause the results to be different than if it were
+     * being treated as a literal replacement string; see
+     * {@link java.util.regex.Matcher#replaceFirst}.
+     * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
+     * meaning of these characters, if desired.
+     *
+     * @param   regex
+     *          the regular expression to which this string is to be matched
+     * @param   replacement
+     *          the string to be substituted for the first match
+     *
+     * @return  The resulting {@code String}
+     *
+     * @throws  PatternSyntaxException
+     *          if the regular expression's syntax is invalid
+     *
+     * @see java.util.regex.Pattern
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public String replaceFirst(String regex, String replacement) {
+        return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
+    }
+
+    /**
+     * Replaces each substring of this string that matches the given <a
+     * href="../util/regex/Pattern.html#sum">regular expression</a> with the
+     * given replacement.
+     *
+     * <p> An invocation of this method of the form
+     * <i>str</i>{@code .replaceAll(}<i>regex</i>{@code ,} <i>repl</i>{@code )}
+     * yields exactly the same result as the expression
+     *
+     * <blockquote>
+     * <code>
+     * {@link java.util.regex.Pattern}.{@link
+     * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
+     * java.util.regex.Pattern#matcher(java.lang.CharSequence) matcher}(<i>str</i>).{@link
+     * java.util.regex.Matcher#replaceAll replaceAll}(<i>repl</i>)
+     * </code>
+     * </blockquote>
+     *
+     *<p>
+     * Note that backslashes ({@code \}) and dollar signs ({@code $}) in the
+     * replacement string may cause the results to be different than if it were
+     * being treated as a literal replacement string; see
+     * {@link java.util.regex.Matcher#replaceAll Matcher.replaceAll}.
+     * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
+     * meaning of these characters, if desired.
+     *
+     * @param   regex
+     *          the regular expression to which this string is to be matched
+     * @param   replacement
+     *          the string to be substituted for each match
+     *
+     * @return  The resulting {@code String}
+     *
+     * @throws  PatternSyntaxException
+     *          if the regular expression's syntax is invalid
+     *
+     * @see java.util.regex.Pattern
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public String replaceAll(String regex, String replacement) {
+        return Pattern.compile(regex).matcher(this).replaceAll(replacement);
+    }
+
+    /**
+     * Replaces each substring of this string that matches the literal target
+     * sequence with the specified literal replacement sequence. The
+     * replacement proceeds from the beginning of the string to the end, for
+     * example, replacing "aa" with "b" in the string "aaa" will result in
+     * "ba" rather than "ab".
+     *
+     * @param  target The sequence of char values to be replaced
+     * @param  replacement The replacement sequence of char values
+     * @return  The resulting string
+     * @since 1.5
+     */
+    public String replace(CharSequence target, CharSequence replacement) {
+        // BEGIN Android-changed: Replace regex-based implementation with a bespoke one.
+        if (target == null) {
+            throw new NullPointerException("target == null");
+        }
+
+        if (replacement == null) {
+            throw new NullPointerException("replacement == null");
+        }
+
+        String replacementStr = replacement.toString();
+        String targetStr = target.toString();
+
+        // Special case when target == "". This is a pretty nonsensical transformation and nobody
+        // should be hitting this.
+        //
+        // See commit 870b23b3febc85 and http://code.google.com/p/android/issues/detail?id=8807
+        // An empty target is inserted at the start of the string, the end of the string and
+        // between all characters.
+        final int len = length();
+        if (targetStr.isEmpty()) {
+            // Note that overallocates by |replacement.size()| if |this| is the empty string, but
+            // that should be a rare case within an already nonsensical case.
+            StringBuilder sb = new StringBuilder(replacementStr.length() * (len + 2) + len);
+            sb.append(replacementStr);
+            for (int i = 0; i < len; ++i) {
+                sb.append(charAt(i));
+                sb.append(replacementStr);
+            }
+
+            return sb.toString();
+        }
+
+        // This is the "regular" case.
+        int lastMatch = 0;
+        StringBuilder sb = null;
+        for (;;) {
+            int currentMatch = indexOf(this, targetStr, lastMatch);
+            if (currentMatch == -1) {
+                break;
+            }
+
+            if (sb == null) {
+                sb = new StringBuilder(len);
+            }
+
+            sb.append(this, lastMatch, currentMatch);
+            sb.append(replacementStr);
+            lastMatch = currentMatch + targetStr.length();
+        }
+
+        if (sb != null) {
+            sb.append(this, lastMatch, len);
+            return sb.toString();
+        } else {
+            return this;
+        }
+        // END Android-changed: Replace regex-based implementation with a bespoke one.
+    }
+
+    /**
+     * Splits this string around matches of the given
+     * <a href="../util/regex/Pattern.html#sum">regular expression</a>.
+     *
+     * <p> The array returned by this method contains each substring of this
+     * string that is terminated by another substring that matches the given
+     * expression or is terminated by the end of the string.  The substrings in
+     * the array are in the order in which they occur in this string.  If the
+     * expression does not match any part of the input then the resulting array
+     * has just one element, namely this string.
+     *
+     * <p> When there is a positive-width match at the beginning of this
+     * string then an empty leading substring is included at the beginning
+     * of the resulting array. A zero-width match at the beginning however
+     * never produces such empty leading substring.
+     *
+     * <p> The {@code limit} parameter controls the number of times the
+     * pattern is applied and therefore affects the length of the resulting
+     * array.  If the limit <i>n</i> is greater than zero then the pattern
+     * will be applied at most <i>n</i>&nbsp;-&nbsp;1 times, the array's
+     * length will be no greater than <i>n</i>, and the array's last entry
+     * will contain all input beyond the last matched delimiter.  If <i>n</i>
+     * is non-positive then the pattern will be applied as many times as
+     * possible and the array can have any length.  If <i>n</i> is zero then
+     * the pattern will be applied as many times as possible, the array can
+     * have any length, and trailing empty strings will be discarded.
+     *
+     * <p> The string {@code "boo:and:foo"}, for example, yields the
+     * following results with these parameters:
+     *
+     * <blockquote><table cellpadding=1 cellspacing=0 summary="Split example showing regex, limit, and result">
+     * <tr>
+     *     <th>Regex</th>
+     *     <th>Limit</th>
+     *     <th>Result</th>
+     * </tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>2</td>
+     *     <td>{@code { "boo", "and:foo" }}</td></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>5</td>
+     *     <td>{@code { "boo", "and", "foo" }}</td></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>-2</td>
+     *     <td>{@code { "boo", "and", "foo" }}</td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>5</td>
+     *     <td>{@code { "b", "", ":and:f", "", "" }}</td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>-2</td>
+     *     <td>{@code { "b", "", ":and:f", "", "" }}</td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>0</td>
+     *     <td>{@code { "b", "", ":and:f" }}</td></tr>
+     * </table></blockquote>
+     *
+     * <p> An invocation of this method of the form
+     * <i>str.</i>{@code split(}<i>regex</i>{@code ,}&nbsp;<i>n</i>{@code )}
+     * yields the same result as the expression
+     *
+     * <blockquote>
+     * <code>
+     * {@link java.util.regex.Pattern}.{@link
+     * java.util.regex.Pattern#compile compile}(<i>regex</i>).{@link
+     * java.util.regex.Pattern#split(java.lang.CharSequence,int) split}(<i>str</i>,&nbsp;<i>n</i>)
+     * </code>
+     * </blockquote>
+     *
+     *
+     * @param  regex
+     *         the delimiting regular expression
+     *
+     * @param  limit
+     *         the result threshold, as described above
+     *
+     * @return  the array of strings computed by splitting this string
+     *          around matches of the given regular expression
+     *
+     * @throws  PatternSyntaxException
+     *          if the regular expression's syntax is invalid
+     *
+     * @see java.util.regex.Pattern
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public String[] split(String regex, int limit) {
+        // BEGIN Android-changed: Replace custom fast-path with use of new Pattern.fastSplit method.
+        // Try fast splitting without allocating Pattern object
+        String[] fast = Pattern.fastSplit(regex, this, limit);
+        if (fast != null) {
+            return fast;
+        }
+        // END Android-changed: Replace custom fast-path with use of new Pattern.fastSplit method.
+        return Pattern.compile(regex).split(this, limit);
+    }
+
+    /**
+     * Splits this string around matches of the given <a
+     * href="../util/regex/Pattern.html#sum">regular expression</a>.
+     *
+     * <p> This method works as if by invoking the two-argument {@link
+     * #split(String, int) split} method with the given expression and a limit
+     * argument of zero.  Trailing empty strings are therefore not included in
+     * the resulting array.
+     *
+     * <p> The string {@code "boo:and:foo"}, for example, yields the following
+     * results with these expressions:
+     *
+     * <blockquote><table cellpadding=1 cellspacing=0 summary="Split examples showing regex and result">
+     * <tr>
+     *  <th>Regex</th>
+     *  <th>Result</th>
+     * </tr>
+     * <tr><td align=center>:</td>
+     *     <td>{@code { "boo", "and", "foo" }}</td></tr>
+     * <tr><td align=center>o</td>
+     *     <td>{@code { "b", "", ":and:f" }}</td></tr>
+     * </table></blockquote>
+     *
+     *
+     * @param  regex
+     *         the delimiting regular expression
+     *
+     * @return  the array of strings computed by splitting this string
+     *          around matches of the given regular expression
+     *
+     * @throws  PatternSyntaxException
+     *          if the regular expression's syntax is invalid
+     *
+     * @see java.util.regex.Pattern
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public String[] split(String regex) {
+        return split(regex, 0);
+    }
+
+    /**
+     * Returns a new String composed of copies of the
+     * {@code CharSequence elements} joined together with a copy of
+     * the specified {@code delimiter}.
+     *
+     * <blockquote>For example,
+     * <pre>{@code
+     *     String message = String.join("-", "Java", "is", "cool");
+     *     // message returned is: "Java-is-cool"
+     * }</pre></blockquote>
+     *
+     * Note that if an element is null, then {@code "null"} is added.
+     *
+     * @param  delimiter the delimiter that separates each element
+     * @param  elements the elements to join together.
+     *
+     * @return a new {@code String} that is composed of the {@code elements}
+     *         separated by the {@code delimiter}
+     *
+     * @throws NullPointerException If {@code delimiter} or {@code elements}
+     *         is {@code null}
+     *
+     * @see java.util.StringJoiner
+     * @since 1.8
+     */
+    public static String join(CharSequence delimiter, CharSequence... elements) {
+        Objects.requireNonNull(delimiter);
+        Objects.requireNonNull(elements);
+        // Number of elements not likely worth Arrays.stream overhead.
+        StringJoiner joiner = new StringJoiner(delimiter);
+        for (CharSequence cs: elements) {
+            joiner.add(cs);
+        }
+        return joiner.toString();
+    }
+
+    /**
+     * Returns a new {@code String} composed of copies of the
+     * {@code CharSequence elements} joined together with a copy of the
+     * specified {@code delimiter}.
+     *
+     * <blockquote>For example,
+     * <pre>{@code
+     *     List<String> strings = new LinkedList<>();
+     *     strings.add("Java");strings.add("is");
+     *     strings.add("cool");
+     *     String message = String.join(" ", strings);
+     *     //message returned is: "Java is cool"
+     *
+     *     Set<String> strings = new LinkedHashSet<>();
+     *     strings.add("Java"); strings.add("is");
+     *     strings.add("very"); strings.add("cool");
+     *     String message = String.join("-", strings);
+     *     //message returned is: "Java-is-very-cool"
+     * }</pre></blockquote>
+     *
+     * Note that if an individual element is {@code null}, then {@code "null"} is added.
+     *
+     * @param  delimiter a sequence of characters that is used to separate each
+     *         of the {@code elements} in the resulting {@code String}
+     * @param  elements an {@code Iterable} that will have its {@code elements}
+     *         joined together.
+     *
+     * @return a new {@code String} that is composed from the {@code elements}
+     *         argument
+     *
+     * @throws NullPointerException If {@code delimiter} or {@code elements}
+     *         is {@code null}
+     *
+     * @see    #join(CharSequence,CharSequence...)
+     * @see    java.util.StringJoiner
+     * @since 1.8
+     */
+    public static String join(CharSequence delimiter,
+            Iterable<? extends CharSequence> elements) {
+        Objects.requireNonNull(delimiter);
+        Objects.requireNonNull(elements);
+        StringJoiner joiner = new StringJoiner(delimiter);
+        for (CharSequence cs: elements) {
+            joiner.add(cs);
+        }
+        return joiner.toString();
+    }
+
+    /**
+     * Converts all of the characters in this {@code String} to lower
+     * case using the rules of the given {@code Locale}.  Case mapping is based
+     * on the Unicode Standard version specified by the {@link java.lang.Character Character}
+     * class. Since case mappings are not always 1:1 char mappings, the resulting
+     * {@code String} may be a different length than the original {@code String}.
+     * <p>
+     * Examples of lowercase  mappings are in the following table:
+     * <table border="1" summary="Lowercase mapping examples showing language code of locale, upper case, lower case, and description">
+     * <tr>
+     *   <th>Language Code of Locale</th>
+     *   <th>Upper Case</th>
+     *   <th>Lower Case</th>
+     *   <th>Description</th>
+     * </tr>
+     * <tr>
+     *   <td>tr (Turkish)</td>
+     *   <td>&#92;u0130</td>
+     *   <td>&#92;u0069</td>
+     *   <td>capital letter I with dot above -&gt; small letter i</td>
+     * </tr>
+     * <tr>
+     *   <td>tr (Turkish)</td>
+     *   <td>&#92;u0049</td>
+     *   <td>&#92;u0131</td>
+     *   <td>capital letter I -&gt; small letter dotless i </td>
+     * </tr>
+     * <tr>
+     *   <td>(all)</td>
+     *   <td>French Fries</td>
+     *   <td>french fries</td>
+     *   <td>lowercased all chars in String</td>
+     * </tr>
+     * <tr>
+     *   <td>(all)</td>
+     *   <td><img src="doc-files/capiota.gif" alt="capiota"><img src="doc-files/capchi.gif" alt="capchi">
+     *       <img src="doc-files/captheta.gif" alt="captheta"><img src="doc-files/capupsil.gif" alt="capupsil">
+     *       <img src="doc-files/capsigma.gif" alt="capsigma"></td>
+     *   <td><img src="doc-files/iota.gif" alt="iota"><img src="doc-files/chi.gif" alt="chi">
+     *       <img src="doc-files/theta.gif" alt="theta"><img src="doc-files/upsilon.gif" alt="upsilon">
+     *       <img src="doc-files/sigma1.gif" alt="sigma"></td>
+     *   <td>lowercased all chars in String</td>
+     * </tr>
+     * </table>
+     *
+     * @param locale use the case transformation rules for this locale
+     * @return the {@code String}, converted to lowercase.
+     * @see     java.lang.String#toLowerCase()
+     * @see     java.lang.String#toUpperCase()
+     * @see     java.lang.String#toUpperCase(Locale)
+     * @since   1.1
+     */
+    public String toLowerCase(Locale locale) {
+        // Android-changed: Replace custom code with call to new CaseMapper class.
+        return CaseMapper.toLowerCase(locale, this);
+    }
+
+    /**
+     * Converts all of the characters in this {@code String} to lower
+     * case using the rules of the default locale. This is equivalent to calling
+     * {@code toLowerCase(Locale.getDefault())}.
+     * <p>
+     * <b>Note:</b> This method is locale sensitive, and may produce unexpected
+     * results if used for strings that are intended to be interpreted locale
+     * independently.
+     * Examples are programming language identifiers, protocol keys, and HTML
+     * tags.
+     * For instance, {@code "TITLE".toLowerCase()} in a Turkish locale
+     * returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
+     * LATIN SMALL LETTER DOTLESS I character.
+     * To obtain correct results for locale insensitive strings, use
+     * {@code toLowerCase(Locale.ROOT)}.
+     * <p>
+     * @return  the {@code String}, converted to lowercase.
+     * @see     java.lang.String#toLowerCase(Locale)
+     */
+    public String toLowerCase() {
+        return toLowerCase(Locale.getDefault());
+    }
+
+    /**
+     * Converts all of the characters in this {@code String} to upper
+     * case using the rules of the given {@code Locale}. Case mapping is based
+     * on the Unicode Standard version specified by the {@link java.lang.Character Character}
+     * class. Since case mappings are not always 1:1 char mappings, the resulting
+     * {@code String} may be a different length than the original {@code String}.
+     * <p>
+     * Examples of locale-sensitive and 1:M case mappings are in the following table.
+     *
+     * <table border="1" summary="Examples of locale-sensitive and 1:M case mappings. Shows Language code of locale, lower case, upper case, and description.">
+     * <tr>
+     *   <th>Language Code of Locale</th>
+     *   <th>Lower Case</th>
+     *   <th>Upper Case</th>
+     *   <th>Description</th>
+     * </tr>
+     * <tr>
+     *   <td>tr (Turkish)</td>
+     *   <td>&#92;u0069</td>
+     *   <td>&#92;u0130</td>
+     *   <td>small letter i -&gt; capital letter I with dot above</td>
+     * </tr>
+     * <tr>
+     *   <td>tr (Turkish)</td>
+     *   <td>&#92;u0131</td>
+     *   <td>&#92;u0049</td>
+     *   <td>small letter dotless i -&gt; capital letter I</td>
+     * </tr>
+     * <tr>
+     *   <td>(all)</td>
+     *   <td>&#92;u00df</td>
+     *   <td>&#92;u0053 &#92;u0053</td>
+     *   <td>small letter sharp s -&gt; two letters: SS</td>
+     * </tr>
+     * <tr>
+     *   <td>(all)</td>
+     *   <td>Fahrvergn&uuml;gen</td>
+     *   <td>FAHRVERGN&Uuml;GEN</td>
+     *   <td></td>
+     * </tr>
+     * </table>
+     * @param locale use the case transformation rules for this locale
+     * @return the {@code String}, converted to uppercase.
+     * @see     java.lang.String#toUpperCase()
+     * @see     java.lang.String#toLowerCase()
+     * @see     java.lang.String#toLowerCase(Locale)
+     * @since   1.1
+     */
+    public String toUpperCase(Locale locale) {
+        // Android-changed: Replace custom code with call to new CaseMapper class.
+        return CaseMapper.toUpperCase(locale, this, length());
+    }
+
+    /**
+     * Converts all of the characters in this {@code String} to upper
+     * case using the rules of the default locale. This method is equivalent to
+     * {@code toUpperCase(Locale.getDefault())}.
+     * <p>
+     * <b>Note:</b> This method is locale sensitive, and may produce unexpected
+     * results if used for strings that are intended to be interpreted locale
+     * independently.
+     * Examples are programming language identifiers, protocol keys, and HTML
+     * tags.
+     * For instance, {@code "title".toUpperCase()} in a Turkish locale
+     * returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
+     * LATIN CAPITAL LETTER I WITH DOT ABOVE character.
+     * To obtain correct results for locale insensitive strings, use
+     * {@code toUpperCase(Locale.ROOT)}.
+     * <p>
+     * @return  the {@code String}, converted to uppercase.
+     * @see     java.lang.String#toUpperCase(Locale)
+     */
+    public String toUpperCase() {
+        return toUpperCase(Locale.getDefault());
+    }
+
+    /**
+     * Returns a string whose value is this string, with any leading and trailing
+     * whitespace removed.
+     * <p>
+     * If this {@code String} object represents an empty character
+     * sequence, or the first and last characters of character sequence
+     * represented by this {@code String} object both have codes
+     * greater than {@code '\u005Cu0020'} (the space character), then a
+     * reference to this {@code String} object is returned.
+     * <p>
+     * Otherwise, if there is no character with a code greater than
+     * {@code '\u005Cu0020'} in the string, then a
+     * {@code String} object representing an empty string is
+     * returned.
+     * <p>
+     * Otherwise, let <i>k</i> be the index of the first character in the
+     * string whose code is greater than {@code '\u005Cu0020'}, and let
+     * <i>m</i> be the index of the last character in the string whose code
+     * is greater than {@code '\u005Cu0020'}. A {@code String}
+     * object is returned, representing the substring of this string that
+     * begins with the character at index <i>k</i> and ends with the
+     * character at index <i>m</i>-that is, the result of
+     * {@code this.substring(k, m + 1)}.
+     * <p>
+     * This method may be used to trim whitespace (as defined above) from
+     * the beginning and end of a string.
+     *
+     * @return  A string whose value is this string, with any leading and trailing white
+     *          space removed, or this string if it has no leading or
+     *          trailing white space.
+     */
+    public String trim() {
+        int len = length();
+        int st = 0;
+
+        while ((st < len) && (charAt(st) <= ' ')) {
+            st++;
+        }
+        while ((st < len) && (charAt(len - 1) <= ' ')) {
+            len--;
+        }
+        return ((st > 0) || (len < length())) ? substring(st, len) : this;
+    }
+
+    /**
+     * This object (which is already a string!) is itself returned.
+     *
+     * @return  the string itself.
+     */
+    public String toString() {
+        return this;
+    }
+
+    /**
+     * Converts this string to a new character array.
+     *
+     * @return  a newly allocated character array whose length is the length
+     *          of this string and whose contents are initialized to contain
+     *          the character sequence represented by this string.
+     */
+    // BEGIN Android-changed: Replace with implementation in runtime to access chars (see above).
+    @FastNative
+    public native char[] toCharArray();
+    // END Android-changed: Replace with implementation in runtime to access chars (see above).
+
+
+    /**
+     * Returns a formatted string using the specified format string and
+     * arguments.
+     *
+     * <p> The locale always used is the one returned by {@link
+     * java.util.Locale#getDefault() Locale.getDefault()}.
+     *
+     * @param  format
+     *         A <a href="../util/Formatter.html#syntax">format string</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         {@code null} argument depends on the <a
+     *         href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     *
+     * @return  A formatted string
+     *
+     * @see  java.util.Formatter
+     * @since  1.5
+     */
+    public static String format(String format, Object... args) {
+        return new Formatter().format(format, args).toString();
+    }
+
+    /**
+     * Returns a formatted string using the specified locale, format string,
+     * and arguments.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @param  format
+     *         A <a href="../util/Formatter.html#syntax">format string</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The number of arguments is
+     *         variable and may be zero.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *         The behaviour on a
+     *         {@code null} argument depends on the
+     *         <a href="../util/Formatter.html#syntax">conversion</a>.
+     *
+     * @throws  java.util.IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification
+     *
+     * @return  A formatted string
+     *
+     * @see  java.util.Formatter
+     * @since  1.5
+     */
+    public static String format(Locale l, String format, Object... args) {
+        return new Formatter(l).format(format, args).toString();
+    }
+
+    /**
+     * Returns the string representation of the {@code Object} argument.
+     *
+     * @param   obj   an {@code Object}.
+     * @return  if the argument is {@code null}, then a string equal to
+     *          {@code "null"}; otherwise, the value of
+     *          {@code obj.toString()} is returned.
+     * @see     java.lang.Object#toString()
+     */
+    public static String valueOf(Object obj) {
+        return (obj == null) ? "null" : obj.toString();
+    }
+
+    /**
+     * Returns the string representation of the {@code char} array
+     * argument. The contents of the character array are copied; subsequent
+     * modification of the character array does not affect the returned
+     * string.
+     *
+     * @param   data     the character array.
+     * @return  a {@code String} that contains the characters of the
+     *          character array.
+     */
+    public static String valueOf(char data[]) {
+        return new String(data);
+    }
+
+    /**
+     * Returns the string representation of a specific subarray of the
+     * {@code char} array argument.
+     * <p>
+     * The {@code offset} argument is the index of the first
+     * character of the subarray. The {@code count} argument
+     * specifies the length of the subarray. The contents of the subarray
+     * are copied; subsequent modification of the character array does not
+     * affect the returned string.
+     *
+     * @param   data     the character array.
+     * @param   offset   initial offset of the subarray.
+     * @param   count    length of the subarray.
+     * @return  a {@code String} that contains the characters of the
+     *          specified subarray of the character array.
+     * @exception IndexOutOfBoundsException if {@code offset} is
+     *          negative, or {@code count} is negative, or
+     *          {@code offset+count} is larger than
+     *          {@code data.length}.
+     */
+    public static String valueOf(char data[], int offset, int count) {
+        return new String(data, offset, count);
+    }
+
+    /**
+     * Equivalent to {@link #valueOf(char[], int, int)}.
+     *
+     * @param   data     the character array.
+     * @param   offset   initial offset of the subarray.
+     * @param   count    length of the subarray.
+     * @return  a {@code String} that contains the characters of the
+     *          specified subarray of the character array.
+     * @exception IndexOutOfBoundsException if {@code offset} is
+     *          negative, or {@code count} is negative, or
+     *          {@code offset+count} is larger than
+     *          {@code data.length}.
+     */
+    public static String copyValueOf(char data[], int offset, int count) {
+        return new String(data, offset, count);
+    }
+
+    /**
+     * Equivalent to {@link #valueOf(char[])}.
+     *
+     * @param   data   the character array.
+     * @return  a {@code String} that contains the characters of the
+     *          character array.
+     */
+    public static String copyValueOf(char data[]) {
+        return new String(data);
+    }
+
+    /**
+     * Returns the string representation of the {@code boolean} argument.
+     *
+     * @param   b   a {@code boolean}.
+     * @return  if the argument is {@code true}, a string equal to
+     *          {@code "true"} is returned; otherwise, a string equal to
+     *          {@code "false"} is returned.
+     */
+    public static String valueOf(boolean b) {
+        return b ? "true" : "false";
+    }
+
+    /**
+     * Returns the string representation of the {@code char}
+     * argument.
+     *
+     * @param   c   a {@code char}.
+     * @return  a string of length {@code 1} containing
+     *          as its single character the argument {@code c}.
+     */
+    public static String valueOf(char c) {
+        // Android-changed: Replace constructor call with call to StringFactory class.
+        // There is currently no String(char[], boolean) on Android to call. http://b/79902155
+        // char data[] = {c};
+        // return new String(data, true);
+        return StringFactory.newStringFromChars(0, 1, new char[] { c });
+    }
+
+    /**
+     * Returns the string representation of the {@code int} argument.
+     * <p>
+     * The representation is exactly the one returned by the
+     * {@code Integer.toString} method of one argument.
+     *
+     * @param   i   an {@code int}.
+     * @return  a string representation of the {@code int} argument.
+     * @see     java.lang.Integer#toString(int, int)
+     */
+    public static String valueOf(int i) {
+        return Integer.toString(i);
+    }
+
+    /**
+     * Returns the string representation of the {@code long} argument.
+     * <p>
+     * The representation is exactly the one returned by the
+     * {@code Long.toString} method of one argument.
+     *
+     * @param   l   a {@code long}.
+     * @return  a string representation of the {@code long} argument.
+     * @see     java.lang.Long#toString(long)
+     */
+    public static String valueOf(long l) {
+        return Long.toString(l);
+    }
+
+    /**
+     * Returns the string representation of the {@code float} argument.
+     * <p>
+     * The representation is exactly the one returned by the
+     * {@code Float.toString} method of one argument.
+     *
+     * @param   f   a {@code float}.
+     * @return  a string representation of the {@code float} argument.
+     * @see     java.lang.Float#toString(float)
+     */
+    public static String valueOf(float f) {
+        return Float.toString(f);
+    }
+
+    /**
+     * Returns the string representation of the {@code double} argument.
+     * <p>
+     * The representation is exactly the one returned by the
+     * {@code Double.toString} method of one argument.
+     *
+     * @param   d   a {@code double}.
+     * @return  a  string representation of the {@code double} argument.
+     * @see     java.lang.Double#toString(double)
+     */
+    public static String valueOf(double d) {
+        return Double.toString(d);
+    }
+
+    /**
+     * Returns a canonical representation for the string object.
+     * <p>
+     * A pool of strings, initially empty, is maintained privately by the
+     * class {@code String}.
+     * <p>
+     * When the intern method is invoked, if the pool already contains a
+     * string equal to this {@code String} object as determined by
+     * the {@link #equals(Object)} method, then the string from the pool is
+     * returned. Otherwise, this {@code String} object is added to the
+     * pool and a reference to this {@code String} object is returned.
+     * <p>
+     * It follows that for any two strings {@code s} and {@code t},
+     * {@code s.intern() == t.intern()} is {@code true}
+     * if and only if {@code s.equals(t)} is {@code true}.
+     * <p>
+     * All literal strings and string-valued constant expressions are
+     * interned. String literals are defined in section 3.10.5 of the
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * @return  a string that has the same contents as this string, but is
+     *          guaranteed to be from a pool of unique strings.
+     */
+    // BEGIN Android-changed: Annotate native method as @FastNative.
+    @FastNative
+    // END Android-changed: Annotate native method as @FastNative.
+    public native String intern();
+}
diff --git a/java/lang/StringBuffer.annotated.java b/java/lang/StringBuffer.annotated.java
new file mode 100644
index 0000000..4baff67
--- /dev/null
+++ b/java/lang/StringBuffer.annotated.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class StringBuffer implements java.lang.Appendable, java.lang.CharSequence, java.io.Serializable {
+
+public StringBuffer() { throw new RuntimeException("Stub!"); }
+
+public StringBuffer(int capacity) { throw new RuntimeException("Stub!"); }
+
+public StringBuffer(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public StringBuffer(@libcore.util.NonNull java.lang.CharSequence seq) { throw new RuntimeException("Stub!"); }
+
+public synchronized int length() { throw new RuntimeException("Stub!"); }
+
+public synchronized int capacity() { throw new RuntimeException("Stub!"); }
+
+public synchronized void ensureCapacity(int minimumCapacity) { throw new RuntimeException("Stub!"); }
+
+public synchronized void trimToSize() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setLength(int newLength) { throw new RuntimeException("Stub!"); }
+
+public synchronized char charAt(int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized int codePointAt(int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized int codePointBefore(int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized int codePointCount(int beginIndex, int endIndex) { throw new RuntimeException("Stub!"); }
+
+public synchronized int offsetByCodePoints(int index, int codePointOffset) { throw new RuntimeException("Stub!"); }
+
+public synchronized void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { throw new RuntimeException("Stub!"); }
+
+public synchronized void setCharAt(int index, char ch) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(@libcore.util.Nullable java.lang.String str) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(@libcore.util.Nullable java.lang.StringBuffer sb) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(@libcore.util.Nullable java.lang.CharSequence s) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(@libcore.util.Nullable java.lang.CharSequence s, int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(char[] str) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(char[] str, int offset, int len) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(char c) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer appendCodePoint(int codePoint) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(long lng) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer append(double d) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer delete(int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer deleteCharAt(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer replace(int start, int end, @libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String substring(int start) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.CharSequence subSequence(int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String substring(int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer insert(int index, char[] str, int offset, int len) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer insert(int offset, @libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer insert(int offset, @libcore.util.Nullable java.lang.String str) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer insert(int offset, char[] str) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer insert(int dstOffset, @libcore.util.Nullable java.lang.CharSequence s) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer insert(int dstOffset, @libcore.util.Nullable java.lang.CharSequence s, int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer insert(int offset, boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer insert(int offset, char c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer insert(int offset, int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer insert(int offset, long l) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer insert(int offset, float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer insert(int offset, double d) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public synchronized int indexOf(@libcore.util.NonNull java.lang.String str, int fromIndex) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public synchronized int lastIndexOf(@libcore.util.NonNull java.lang.String str, int fromIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.StringBuffer reverse() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/lang/StringBuffer.java b/java/lang/StringBuffer.java
new file mode 100644
index 0000000..6781f11
--- /dev/null
+++ b/java/lang/StringBuffer.java
@@ -0,0 +1,715 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.util.Arrays;
+
+/**
+ * A thread-safe, mutable sequence of characters.
+ * A string buffer is like a {@link String}, but can be modified. At any
+ * point in time it contains some particular sequence of characters, but
+ * the length and content of the sequence can be changed through certain
+ * method calls.
+ * <p>
+ * String buffers are safe for use by multiple threads. The methods
+ * are synchronized where necessary so that all the operations on any
+ * particular instance behave as if they occur in some serial order
+ * that is consistent with the order of the method calls made by each of
+ * the individual threads involved.
+ * <p>
+ * The principal operations on a {@code StringBuffer} are the
+ * {@code append} and {@code insert} methods, which are
+ * overloaded so as to accept data of any type. Each effectively
+ * converts a given datum to a string and then appends or inserts the
+ * characters of that string to the string buffer. The
+ * {@code append} method always adds these characters at the end
+ * of the buffer; the {@code insert} method adds the characters at
+ * a specified point.
+ * <p>
+ * For example, if {@code z} refers to a string buffer object
+ * whose current contents are {@code "start"}, then
+ * the method call {@code z.append("le")} would cause the string
+ * buffer to contain {@code "startle"}, whereas
+ * {@code z.insert(4, "le")} would alter the string buffer to
+ * contain {@code "starlet"}.
+ * <p>
+ * In general, if sb refers to an instance of a {@code StringBuffer},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
+ * <p>
+ * Whenever an operation occurs involving a source sequence (such as
+ * appending or inserting from a source sequence), this class synchronizes
+ * only on the string buffer performing the operation, not on the source.
+ * Note that while {@code StringBuffer} is designed to be safe to use
+ * concurrently from multiple threads, if the constructor or the
+ * {@code append} or {@code insert} operation is passed a source sequence
+ * that is shared across threads, the calling code must ensure
+ * that the operation has a consistent and unchanging view of the source
+ * sequence for the duration of the operation.
+ * This could be satisfied by the caller holding a lock during the
+ * operation's call, by using an immutable source sequence, or by not
+ * sharing the source sequence across threads.
+ * <p>
+ * Every string buffer has a capacity. As long as the length of the
+ * character sequence contained in the string buffer does not exceed
+ * the capacity, it is not necessary to allocate a new internal
+ * buffer array. If the internal buffer overflows, it is
+ * automatically made larger.
+ * <p>
+ * Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ * <p>
+ * As of  release JDK 5, this class has been supplemented with an equivalent
+ * class designed for use by a single thread, {@link StringBuilder}.  The
+ * {@code StringBuilder} class should generally be used in preference to
+ * this one, as it supports all of the same operations but it is faster, as
+ * it performs no synchronization.
+ *
+ * @author      Arthur van Hoff
+ * @see     java.lang.StringBuilder
+ * @see     java.lang.String
+ * @since   JDK1.0
+ */
+ public final class StringBuffer
+    extends AbstractStringBuilder
+    implements java.io.Serializable, CharSequence
+{
+
+    /**
+     * A cache of the last value returned by toString. Cleared
+     * whenever the StringBuffer is modified.
+     */
+    private transient char[] toStringCache;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    static final long serialVersionUID = 3388685877147921107L;
+
+    /**
+     * Constructs a string buffer with no characters in it and an
+     * initial capacity of 16 characters.
+     */
+    public StringBuffer() {
+        super(16);
+    }
+
+    /**
+     * Constructs a string buffer with no characters in it and
+     * the specified initial capacity.
+     *
+     * @param      capacity  the initial capacity.
+     * @exception  NegativeArraySizeException  if the {@code capacity}
+     *               argument is less than {@code 0}.
+     */
+    public StringBuffer(int capacity) {
+        super(capacity);
+    }
+
+    /**
+     * Constructs a string buffer initialized to the contents of the
+     * specified string. The initial capacity of the string buffer is
+     * {@code 16} plus the length of the string argument.
+     *
+     * @param   str   the initial contents of the buffer.
+     */
+    public StringBuffer(String str) {
+        super(str.length() + 16);
+        append(str);
+    }
+
+    /**
+     * Constructs a string buffer that contains the same characters
+     * as the specified {@code CharSequence}. The initial capacity of
+     * the string buffer is {@code 16} plus the length of the
+     * {@code CharSequence} argument.
+     * <p>
+     * If the length of the specified {@code CharSequence} is
+     * less than or equal to zero, then an empty buffer of capacity
+     * {@code 16} is returned.
+     *
+     * @param      seq   the sequence to copy.
+     * @since 1.5
+     */
+    public StringBuffer(CharSequence seq) {
+        this(seq.length() + 16);
+        append(seq);
+    }
+
+    @Override
+    public synchronized int length() {
+        return count;
+    }
+
+    @Override
+    public synchronized int capacity() {
+        return value.length;
+    }
+
+
+    @Override
+    public synchronized void ensureCapacity(int minimumCapacity) {
+        super.ensureCapacity(minimumCapacity);
+    }
+
+    /**
+     * @since      1.5
+     */
+    @Override
+    public synchronized void trimToSize() {
+        super.trimToSize();
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @see        #length()
+     */
+    @Override
+    public synchronized void setLength(int newLength) {
+        toStringCache = null;
+        super.setLength(newLength);
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @see        #length()
+     */
+    @Override
+    public synchronized char charAt(int index) {
+        if ((index < 0) || (index >= count))
+            throw new StringIndexOutOfBoundsException(index);
+        return value[index];
+    }
+
+    /**
+     * @since      1.5
+     */
+    @Override
+    public synchronized int codePointAt(int index) {
+        return super.codePointAt(index);
+    }
+
+    /**
+     * @since     1.5
+     */
+    @Override
+    public synchronized int codePointBefore(int index) {
+        return super.codePointBefore(index);
+    }
+
+    /**
+     * @since     1.5
+     */
+    @Override
+    public synchronized int codePointCount(int beginIndex, int endIndex) {
+        return super.codePointCount(beginIndex, endIndex);
+    }
+
+    /**
+     * @since     1.5
+     */
+    @Override
+    public synchronized int offsetByCodePoints(int index, int codePointOffset) {
+        return super.offsetByCodePoints(index, codePointOffset);
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
+                                      int dstBegin)
+    {
+        super.getChars(srcBegin, srcEnd, dst, dstBegin);
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @see        #length()
+     */
+    @Override
+    public synchronized void setCharAt(int index, char ch) {
+        if ((index < 0) || (index >= count))
+            throw new StringIndexOutOfBoundsException(index);
+        toStringCache = null;
+        value[index] = ch;
+    }
+
+    @Override
+    public synchronized StringBuffer append(Object obj) {
+        toStringCache = null;
+        super.append(String.valueOf(obj));
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(String str) {
+        toStringCache = null;
+        super.append(str);
+        return this;
+    }
+
+    /**
+     * Appends the specified {@code StringBuffer} to this sequence.
+     * <p>
+     * The characters of the {@code StringBuffer} argument are appended,
+     * in order, to the contents of this {@code StringBuffer}, increasing the
+     * length of this {@code StringBuffer} by the length of the argument.
+     * If {@code sb} is {@code null}, then the four characters
+     * {@code "null"} are appended to this {@code StringBuffer}.
+     * <p>
+     * Let <i>n</i> be the length of the old character sequence, the one
+     * contained in the {@code StringBuffer} just prior to execution of the
+     * {@code append} method. Then the character at index <i>k</i> in
+     * the new character sequence is equal to the character at index <i>k</i>
+     * in the old character sequence, if <i>k</i> is less than <i>n</i>;
+     * otherwise, it is equal to the character at index <i>k-n</i> in the
+     * argument {@code sb}.
+     * <p>
+     * This method synchronizes on {@code this}, the destination
+     * object, but does not synchronize on the source ({@code sb}).
+     *
+     * @param   sb   the {@code StringBuffer} to append.
+     * @return  a reference to this object.
+     * @since 1.4
+     */
+    public synchronized StringBuffer append(StringBuffer sb) {
+        toStringCache = null;
+        super.append(sb);
+        return this;
+    }
+
+    /**
+     * @since 1.8
+     */
+    @Override
+    synchronized StringBuffer append(AbstractStringBuilder asb) {
+        toStringCache = null;
+        super.append(asb);
+        return this;
+    }
+
+    /**
+     * Appends the specified {@code CharSequence} to this
+     * sequence.
+     * <p>
+     * The characters of the {@code CharSequence} argument are appended,
+     * in order, increasing the length of this sequence by the length of the
+     * argument.
+     *
+     * <p>The result of this method is exactly the same as if it were an
+     * invocation of this.append(s, 0, s.length());
+     *
+     * <p>This method synchronizes on {@code this}, the destination
+     * object, but does not synchronize on the source ({@code s}).
+     *
+     * <p>If {@code s} is {@code null}, then the four characters
+     * {@code "null"} are appended.
+     *
+     * @param   s the {@code CharSequence} to append.
+     * @return  a reference to this object.
+     * @since 1.5
+     */
+    @Override
+    public synchronized StringBuffer append(CharSequence s) {
+        toStringCache = null;
+        super.append(s);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @since      1.5
+     */
+    @Override
+    public synchronized StringBuffer append(CharSequence s, int start, int end)
+    {
+        toStringCache = null;
+        super.append(s, start, end);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(char[] str) {
+        toStringCache = null;
+        super.append(str);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public synchronized StringBuffer append(char[] str, int offset, int len) {
+        toStringCache = null;
+        super.append(str, offset, len);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(boolean b) {
+        toStringCache = null;
+        super.append(b);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(char c) {
+        toStringCache = null;
+        super.append(c);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(int i) {
+        toStringCache = null;
+        super.append(i);
+        return this;
+    }
+
+    /**
+     * @since 1.5
+     */
+    @Override
+    public synchronized StringBuffer appendCodePoint(int codePoint) {
+        toStringCache = null;
+        super.appendCodePoint(codePoint);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(long lng) {
+        toStringCache = null;
+        super.append(lng);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(float f) {
+        toStringCache = null;
+        super.append(f);
+        return this;
+    }
+
+    @Override
+    public synchronized StringBuffer append(double d) {
+        toStringCache = null;
+        super.append(d);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     * @since      1.2
+     */
+    @Override
+    public synchronized StringBuffer delete(int start, int end) {
+        toStringCache = null;
+        super.delete(start, end);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     * @since      1.2
+     */
+    @Override
+    public synchronized StringBuffer deleteCharAt(int index) {
+        toStringCache = null;
+        super.deleteCharAt(index);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     * @since      1.2
+     */
+    @Override
+    public synchronized StringBuffer replace(int start, int end, String str) {
+        toStringCache = null;
+        super.replace(start, end, str);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     * @since      1.2
+     */
+    @Override
+    public synchronized String substring(int start) {
+        return substring(start, count);
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @since      1.4
+     */
+    @Override
+    public synchronized CharSequence subSequence(int start, int end) {
+        return super.substring(start, end);
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     * @since      1.2
+     */
+    @Override
+    public synchronized String substring(int start, int end) {
+        return super.substring(start, end);
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     * @since      1.2
+     */
+    @Override
+    public synchronized StringBuffer insert(int index, char[] str, int offset,
+                                            int len)
+    {
+        toStringCache = null;
+        super.insert(index, str, offset, len);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public synchronized StringBuffer insert(int offset, Object obj) {
+        toStringCache = null;
+        super.insert(offset, String.valueOf(obj));
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public synchronized StringBuffer insert(int offset, String str) {
+        toStringCache = null;
+        super.insert(offset, str);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public synchronized StringBuffer insert(int offset, char[] str) {
+        toStringCache = null;
+        super.insert(offset, str);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @since      1.5
+     */
+    @Override
+    public StringBuffer insert(int dstOffset, CharSequence s) {
+        // Note, synchronization achieved via invocations of other StringBuffer methods
+        // after narrowing of s to specific type
+        // Ditto for toStringCache clearing
+        super.insert(dstOffset, s);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @since      1.5
+     */
+    @Override
+    public synchronized StringBuffer insert(int dstOffset, CharSequence s,
+            int start, int end)
+    {
+        toStringCache = null;
+        super.insert(dstOffset, s, start, end);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public  StringBuffer insert(int offset, boolean b) {
+        // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+        // after conversion of b to String by super class method
+        // Ditto for toStringCache clearing
+        super.insert(offset, b);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public synchronized StringBuffer insert(int offset, char c) {
+        toStringCache = null;
+        super.insert(offset, c);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuffer insert(int offset, int i) {
+        // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+        // after conversion of i to String by super class method
+        // Ditto for toStringCache clearing
+        super.insert(offset, i);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuffer insert(int offset, long l) {
+        // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+        // after conversion of l to String by super class method
+        // Ditto for toStringCache clearing
+        super.insert(offset, l);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuffer insert(int offset, float f) {
+        // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+        // after conversion of f to String by super class method
+        // Ditto for toStringCache clearing
+        super.insert(offset, f);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuffer insert(int offset, double d) {
+        // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
+        // after conversion of d to String by super class method
+        // Ditto for toStringCache clearing
+        super.insert(offset, d);
+        return this;
+    }
+
+    /**
+     * @since      1.4
+     */
+    @Override
+    public int indexOf(String str) {
+        // Note, synchronization achieved via invocations of other StringBuffer methods
+        return super.indexOf(str);
+    }
+
+    /**
+     * @since      1.4
+     */
+    @Override
+    public synchronized int indexOf(String str, int fromIndex) {
+        return super.indexOf(str, fromIndex);
+    }
+
+    /**
+     * @since      1.4
+     */
+    @Override
+    public int lastIndexOf(String str) {
+        // Note, synchronization achieved via invocations of other StringBuffer methods
+        return lastIndexOf(str, count);
+    }
+
+    /**
+     * @since      1.4
+     */
+    @Override
+    public synchronized int lastIndexOf(String str, int fromIndex) {
+        return super.lastIndexOf(str, fromIndex);
+    }
+
+    /**
+     * @since   JDK1.0.2
+     */
+    @Override
+    public synchronized StringBuffer reverse() {
+        toStringCache = null;
+        super.reverse();
+        return this;
+    }
+
+    @Override
+    public synchronized String toString() {
+        if (toStringCache == null) {
+            toStringCache = Arrays.copyOfRange(value, 0, count);
+        }
+        return new String(toStringCache, 0, count);
+    }
+
+    /**
+     * Serializable fields for StringBuffer.
+     *
+     * @serialField value  char[]
+     *              The backing character array of this StringBuffer.
+     * @serialField count int
+     *              The number of characters in this StringBuffer.
+     * @serialField shared  boolean
+     *              A flag indicating whether the backing array is shared.
+     *              The value is ignored upon deserialization.
+     */
+    private static final java.io.ObjectStreamField[] serialPersistentFields =
+    {
+        new java.io.ObjectStreamField("value", char[].class),
+        new java.io.ObjectStreamField("count", Integer.TYPE),
+        new java.io.ObjectStreamField("shared", Boolean.TYPE),
+    };
+
+    /**
+     * readObject is called to restore the state of the StringBuffer from
+     * a stream.
+     */
+    private synchronized void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        java.io.ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("value", value);
+        fields.put("count", count);
+        fields.put("shared", false);
+        s.writeFields();
+    }
+
+    /**
+     * readObject is called to restore the state of the StringBuffer from
+     * a stream.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        java.io.ObjectInputStream.GetField fields = s.readFields();
+        value = (char[])fields.get("value", null);
+        count = fields.get("count", 0);
+    }
+}
diff --git a/java/lang/StringBuilder.annotated.java b/java/lang/StringBuilder.annotated.java
new file mode 100644
index 0000000..6fdde8a
--- /dev/null
+++ b/java/lang/StringBuilder.annotated.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class StringBuilder implements java.lang.Appendable, java.lang.CharSequence, java.io.Serializable {
+
+public StringBuilder() { throw new RuntimeException("Stub!"); }
+
+public StringBuilder(int capacity) { throw new RuntimeException("Stub!"); }
+
+public StringBuilder(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public StringBuilder(@libcore.util.NonNull java.lang.CharSequence seq) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(@libcore.util.Nullable java.lang.String str) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(@libcore.util.Nullable java.lang.StringBuffer sb) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(@libcore.util.Nullable java.lang.CharSequence s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(@libcore.util.Nullable java.lang.CharSequence s, int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(char[] str) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(char[] str, int offset, int len) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(char c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(long lng) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder append(double d) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder appendCodePoint(int codePoint) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder delete(int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder deleteCharAt(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder replace(int start, int end, @libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int index, char[] str, int offset, int len) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, @libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, @libcore.util.Nullable java.lang.String str) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, char[] str) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int dstOffset, @libcore.util.Nullable java.lang.CharSequence s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int dstOffset, @libcore.util.Nullable java.lang.CharSequence s, int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, char c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, int i) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, long l) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, float f) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder insert(int offset, double d) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.NonNull java.lang.String str, int fromIndex) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.NonNull java.lang.String str) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.NonNull java.lang.String str, int fromIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuilder reverse() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public void trimToSize() { throw new RuntimeException("Stub!"); }
+
+public int codePointAt(int index) { throw new RuntimeException("Stub!"); }
+
+public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { throw new RuntimeException("Stub!"); }
+
+public int length() { throw new RuntimeException("Stub!"); }
+
+public void setCharAt(int index, char ch) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.CharSequence subSequence(int start, int end) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String substring(int start) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String substring(int start, int end) { throw new RuntimeException("Stub!"); }
+
+public int capacity() { throw new RuntimeException("Stub!"); }
+
+public void setLength(int newLength) { throw new RuntimeException("Stub!"); }
+
+public void ensureCapacity(int minimumCapacity) { throw new RuntimeException("Stub!"); }
+
+public int codePointBefore(int index) { throw new RuntimeException("Stub!"); }
+
+public char charAt(int index) { throw new RuntimeException("Stub!"); }
+
+public int codePointCount(int beginIndex, int endIndex) { throw new RuntimeException("Stub!"); }
+
+public int offsetByCodePoints(int index, int codePointOffset) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/lang/StringBuilder.java b/java/lang/StringBuilder.java
new file mode 100644
index 0000000..325c9c5
--- /dev/null
+++ b/java/lang/StringBuilder.java
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+
+/**
+ * A mutable sequence of characters.  This class provides an API compatible
+ * with {@code StringBuffer}, but with no guarantee of synchronization.
+ * This class is designed for use as a drop-in replacement for
+ * {@code StringBuffer} in places where the string buffer was being
+ * used by a single thread (as is generally the case).   Where possible,
+ * it is recommended that this class be used in preference to
+ * {@code StringBuffer} as it will be faster under most implementations.
+ *
+ * <p>The principal operations on a {@code StringBuilder} are the
+ * {@code append} and {@code insert} methods, which are
+ * overloaded so as to accept data of any type. Each effectively
+ * converts a given datum to a string and then appends or inserts the
+ * characters of that string to the string builder. The
+ * {@code append} method always adds these characters at the end
+ * of the builder; the {@code insert} method adds the characters at
+ * a specified point.
+ * <p>
+ * For example, if {@code z} refers to a string builder object
+ * whose current contents are "{@code start}", then
+ * the method call {@code z.append("le")} would cause the string
+ * builder to contain "{@code startle}", whereas
+ * {@code z.insert(4, "le")} would alter the string builder to
+ * contain "{@code starlet}".
+ * <p>
+ * In general, if sb refers to an instance of a {@code StringBuilder},
+ * then {@code sb.append(x)} has the same effect as
+ * {@code sb.insert(sb.length(), x)}.
+ * <p>
+ * Every string builder has a capacity. As long as the length of the
+ * character sequence contained in the string builder does not exceed
+ * the capacity, it is not necessary to allocate a new internal
+ * buffer. If the internal buffer overflows, it is automatically made larger.
+ *
+ * <p>Instances of {@code StringBuilder} are not safe for
+ * use by multiple threads. If such synchronization is required then it is
+ * recommended that {@link java.lang.StringBuffer} be used.
+ *
+ * <p>Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * @author      Michael McCloskey
+ * @see         java.lang.StringBuffer
+ * @see         java.lang.String
+ * @since       1.5
+ */
+public final class StringBuilder
+    extends AbstractStringBuilder
+    implements java.io.Serializable, CharSequence
+{
+
+    /** use serialVersionUID for interoperability */
+    static final long serialVersionUID = 4383685877147921099L;
+
+    /**
+     * Constructs a string builder with no characters in it and an
+     * initial capacity of 16 characters.
+     */
+    public StringBuilder() {
+        super(16);
+    }
+
+    /**
+     * Constructs a string builder with no characters in it and an
+     * initial capacity specified by the {@code capacity} argument.
+     *
+     * @param      capacity  the initial capacity.
+     * @throws     NegativeArraySizeException  if the {@code capacity}
+     *               argument is less than {@code 0}.
+     */
+    public StringBuilder(int capacity) {
+        super(capacity);
+    }
+
+    /**
+     * Constructs a string builder initialized to the contents of the
+     * specified string. The initial capacity of the string builder is
+     * {@code 16} plus the length of the string argument.
+     *
+     * @param   str   the initial contents of the buffer.
+     */
+    public StringBuilder(String str) {
+        super(str.length() + 16);
+        append(str);
+    }
+
+    /**
+     * Constructs a string builder that contains the same characters
+     * as the specified {@code CharSequence}. The initial capacity of
+     * the string builder is {@code 16} plus the length of the
+     * {@code CharSequence} argument.
+     *
+     * @param      seq   the sequence to copy.
+     */
+    public StringBuilder(CharSequence seq) {
+        this(seq.length() + 16);
+        append(seq);
+    }
+
+    @Override
+    public StringBuilder append(Object obj) {
+        return append(String.valueOf(obj));
+    }
+
+    @Override
+    public StringBuilder append(String str) {
+        super.append(str);
+        return this;
+    }
+
+    /**
+     * Appends the specified {@code StringBuffer} to this sequence.
+     * <p>
+     * The characters of the {@code StringBuffer} argument are appended,
+     * in order, to this sequence, increasing the
+     * length of this sequence by the length of the argument.
+     * If {@code sb} is {@code null}, then the four characters
+     * {@code "null"} are appended to this sequence.
+     * <p>
+     * Let <i>n</i> be the length of this character sequence just prior to
+     * execution of the {@code append} method. Then the character at index
+     * <i>k</i> in the new character sequence is equal to the character at
+     * index <i>k</i> in the old character sequence, if <i>k</i> is less than
+     * <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i>
+     * in the argument {@code sb}.
+     *
+     * @param   sb   the {@code StringBuffer} to append.
+     * @return  a reference to this object.
+     */
+    public StringBuilder append(StringBuffer sb) {
+        super.append(sb);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(CharSequence s) {
+        super.append(s);
+        return this;
+    }
+
+    /**
+     * @throws     IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder append(CharSequence s, int start, int end) {
+        super.append(s, start, end);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(char[] str) {
+        super.append(str);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder append(char[] str, int offset, int len) {
+        super.append(str, offset, len);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(boolean b) {
+        super.append(b);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(char c) {
+        super.append(c);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(int i) {
+        super.append(i);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(long lng) {
+        super.append(lng);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(float f) {
+        super.append(f);
+        return this;
+    }
+
+    @Override
+    public StringBuilder append(double d) {
+        super.append(d);
+        return this;
+    }
+
+    /**
+     * @since 1.5
+     */
+    @Override
+    public StringBuilder appendCodePoint(int codePoint) {
+        super.appendCodePoint(codePoint);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder delete(int start, int end) {
+        super.delete(start, end);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder deleteCharAt(int index) {
+        super.deleteCharAt(index);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder replace(int start, int end, String str) {
+        super.replace(start, end, str);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int index, char[] str, int offset,
+                                int len)
+    {
+        super.insert(index, str, offset, len);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, Object obj) {
+            super.insert(offset, obj);
+            return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, String str) {
+        super.insert(offset, str);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, char[] str) {
+        super.insert(offset, str);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int dstOffset, CharSequence s) {
+            super.insert(dstOffset, s);
+            return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int dstOffset, CharSequence s,
+                                int start, int end)
+    {
+        super.insert(dstOffset, s, start, end);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, boolean b) {
+        super.insert(offset, b);
+        return this;
+    }
+
+    /**
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, char c) {
+        super.insert(offset, c);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, int i) {
+        super.insert(offset, i);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, long l) {
+        super.insert(offset, l);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, float f) {
+        super.insert(offset, f);
+        return this;
+    }
+
+    /**
+     * @throws StringIndexOutOfBoundsException {@inheritDoc}
+     */
+    @Override
+    public StringBuilder insert(int offset, double d) {
+        super.insert(offset, d);
+        return this;
+    }
+
+    @Override
+    public int indexOf(String str) {
+        return super.indexOf(str);
+    }
+
+    @Override
+    public int indexOf(String str, int fromIndex) {
+        return super.indexOf(str, fromIndex);
+    }
+
+    @Override
+    public int lastIndexOf(String str) {
+        return super.lastIndexOf(str);
+    }
+
+    @Override
+    public int lastIndexOf(String str, int fromIndex) {
+        return super.lastIndexOf(str, fromIndex);
+    }
+
+    @Override
+    public StringBuilder reverse() {
+        super.reverse();
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        // BEGIN Android-added: Return a constant "" for an empty buffer to keep historic behavior.
+        if (count == 0) {
+            return "";
+        }
+        // END Android-added: Return a constant "" for an empty buffer to keep historic behavior.
+        // Create a copy, don't share the array
+        return new String(value, 0, count);
+    }
+
+    /**
+     * Save the state of the {@code StringBuilder} instance to a stream
+     * (that is, serialize it).
+     *
+     * @serialData the number of characters currently stored in the string
+     *             builder ({@code int}), followed by the characters in the
+     *             string builder ({@code char[]}).   The length of the
+     *             {@code char} array may be greater than the number of
+     *             characters currently stored in the string builder, in which
+     *             case extra characters are ignored.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        s.writeInt(count);
+        s.writeObject(value);
+    }
+
+    /**
+     * readObject is called to restore the state of the StringBuffer from
+     * a stream.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        count = s.readInt();
+        value = (char[]) s.readObject();
+    }
+
+}
diff --git a/java/lang/StringFactory.java b/java/lang/StringFactory.java
new file mode 100644
index 0000000..6ef664b
--- /dev/null
+++ b/java/lang/StringFactory.java
@@ -0,0 +1,296 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Comparator;
+import libcore.util.CharsetUtils;
+import libcore.util.EmptyArray;
+
+/**
+ * Class used to generate strings instead of calling String.&lt;init&gt;.
+ *
+ * @hide
+ */
+public final class StringFactory {
+
+    // TODO: Remove once native methods are in place.
+    private static final char REPLACEMENT_CHAR = (char) 0xfffd;
+
+    public static String newEmptyString() {
+        return newStringFromChars(EmptyArray.CHAR, 0, 0);
+    }
+
+    public static String newStringFromBytes(byte[] data) {
+        return newStringFromBytes(data, 0, data.length);
+    }
+
+    public static String newStringFromBytes(byte[] data, int high) {
+        return newStringFromBytes(data, high, 0, data.length);
+    }
+
+    public static String newStringFromBytes(byte[] data, int offset, int byteCount) {
+        return newStringFromBytes(data, offset, byteCount, Charset.defaultCharset());
+    }
+
+    @FastNative
+    public static native String newStringFromBytes(byte[] data, int high, int offset, int byteCount);
+
+    public static String newStringFromBytes(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException {
+        return newStringFromBytes(data, offset, byteCount, Charset.forNameUEE(charsetName));
+    }
+
+    public static String newStringFromBytes(byte[] data, String charsetName) throws UnsupportedEncodingException {
+        return newStringFromBytes(data, 0, data.length, Charset.forNameUEE(charsetName));
+    }
+
+    private static final int[] TABLE_UTF8_NEEDED = new int[] {
+    //      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+            0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xc0 - 0xcf
+            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xd0 - 0xdf
+            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xe0 - 0xef
+            3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xf0 - 0xff
+    };
+
+    // TODO: Implement this method natively.
+    public static String newStringFromBytes(byte[] data, int offset, int byteCount, Charset charset) {
+        if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
+            throw new StringIndexOutOfBoundsException(data.length, offset, byteCount);
+        }
+
+        char[] value;
+        int length;
+
+        // We inline UTF-8, ISO-8859-1, and US-ASCII decoders for speed.
+        String canonicalCharsetName = charset.name();
+        if (canonicalCharsetName.equals("UTF-8")) {
+            /*
+            This code converts a UTF-8 byte sequence to a Java String (UTF-16).
+            It implements the W3C recommended UTF-8 decoder.
+            https://www.w3.org/TR/encoding/#utf-8-decoder
+
+            Unicode 3.2 Well-Formed UTF-8 Byte Sequences
+            Code Points        First  Second Third Fourth
+            U+0000..U+007F     00..7F
+            U+0080..U+07FF     C2..DF 80..BF
+            U+0800..U+0FFF     E0     A0..BF 80..BF
+            U+1000..U+CFFF     E1..EC 80..BF 80..BF
+            U+D000..U+D7FF     ED     80..9F 80..BF
+            U+E000..U+FFFF     EE..EF 80..BF 80..BF
+            U+10000..U+3FFFF   F0     90..BF 80..BF 80..BF
+            U+40000..U+FFFFF   F1..F3 80..BF 80..BF 80..BF
+            U+100000..U+10FFFF F4     80..8F 80..BF 80..BF
+
+            Please refer to Unicode as the authority.
+            p.126 Table 3-7 in http://www.unicode.org/versions/Unicode10.0.0/ch03.pdf
+
+            Handling Malformed Input
+            The maximal subpart should be replaced by a single U+FFFD. Maximal subpart is
+            the longest code unit subsequence starting at an unconvertible offset that is either
+            1) the initial subsequence of a well-formed code unit sequence, or
+            2) a subsequence of length one:
+            One U+FFFD should be emitted for every sequence of bytes that is an incomplete prefix
+            of a valid sequence, and with the conversion to restart after the incomplete sequence.
+
+            For example, in byte sequence "41 C0 AF 41 F4 80 80 41", the maximal subparts are
+            "C0", "AF", and "F4 80 80". "F4 80 80" can be the initial subsequence of "F4 80 80 80",
+            but "C0" can't be the initial subsequence of any well-formed code unit sequence.
+            Thus, the output should be "A\ufffd\ufffdA\ufffdA".
+
+            Please refer to section "Best Practices for Using U+FFFD." in
+            http://www.unicode.org/versions/Unicode10.0.0/ch03.pdf
+            */
+            byte[] d = data;
+            char[] v = new char[byteCount];
+
+            int idx = offset;
+            int last = offset + byteCount;
+            int s = 0;
+
+            int codePoint = 0;
+            int utf8BytesSeen = 0;
+            int utf8BytesNeeded = 0;
+            int lowerBound = 0x80;
+            int upperBound = 0xbf;
+
+            while (idx < last) {
+                int b = d[idx++] & 0xff;
+                if (utf8BytesNeeded == 0) {
+                    if ((b & 0x80) == 0) { // ASCII char. 0xxxxxxx
+                        v[s++] = (char) b;
+                        continue;
+                    }
+
+                    if ((b & 0x40) == 0) { // 10xxxxxx is illegal as first byte
+                        v[s++] = REPLACEMENT_CHAR;
+                        continue;
+                    }
+
+                    // 11xxxxxx
+                    int tableLookupIndex = b & 0x3f;
+                    utf8BytesNeeded = TABLE_UTF8_NEEDED[tableLookupIndex];
+                    if (utf8BytesNeeded == 0) {
+                        v[s++] = REPLACEMENT_CHAR;
+                        continue;
+                    }
+
+                    // utf8BytesNeeded
+                    // 1: b & 0x1f
+                    // 2: b & 0x0f
+                    // 3: b & 0x07
+                    codePoint = b & (0x3f >> utf8BytesNeeded);
+                    if (b == 0xe0) {
+                        lowerBound = 0xa0;
+                    } else if (b == 0xed) {
+                        upperBound = 0x9f;
+                    } else if (b == 0xf0) {
+                        lowerBound = 0x90;
+                    } else if (b == 0xf4) {
+                        upperBound = 0x8f;
+                    }
+                } else {
+                    if (b < lowerBound || b > upperBound) {
+                        // The bytes seen are ill-formed. Substitute them with U+FFFD
+                        v[s++] = REPLACEMENT_CHAR;
+                        codePoint = 0;
+                        utf8BytesNeeded = 0;
+                        utf8BytesSeen = 0;
+                        lowerBound = 0x80;
+                        upperBound = 0xbf;
+                        /*
+                         * According to the Unicode Standard,
+                         * "a UTF-8 conversion process is required to never consume well-formed
+                         * subsequences as part of its error handling for ill-formed subsequences"
+                         * The current byte could be part of well-formed subsequences. Reduce the
+                         * index by 1 to parse it in next loop.
+                         */
+                        idx--;
+                        continue;
+                    }
+
+                    lowerBound = 0x80;
+                    upperBound = 0xbf;
+                    codePoint = (codePoint << 6) | (b & 0x3f);
+                    utf8BytesSeen++;
+                    if (utf8BytesNeeded != utf8BytesSeen) {
+                        continue;
+                    }
+
+                    // Encode chars from U+10000 up as surrogate pairs
+                    if (codePoint < 0x10000) {
+                        v[s++] = (char) codePoint;
+                    } else {
+                        v[s++] = (char) ((codePoint >> 10) + 0xd7c0);
+                        v[s++] = (char) ((codePoint & 0x3ff) + 0xdc00);
+                    }
+
+                    utf8BytesSeen = 0;
+                    utf8BytesNeeded = 0;
+                    codePoint = 0;
+                }
+            }
+
+            // The bytes seen are ill-formed. Substitute them by U+FFFD
+            if (utf8BytesNeeded != 0) {
+                v[s++] = REPLACEMENT_CHAR;
+            }
+
+            if (s == byteCount) {
+                // We guessed right, so we can use our temporary array as-is.
+                value = v;
+                length = s;
+            } else {
+                // Our temporary array was too big, so reallocate and copy.
+                value = new char[s];
+                length = s;
+                System.arraycopy(v, 0, value, 0, s);
+            }
+        } else if (canonicalCharsetName.equals("ISO-8859-1")) {
+            value = new char[byteCount];
+            length = byteCount;
+            CharsetUtils.isoLatin1BytesToChars(data, offset, byteCount, value);
+        } else if (canonicalCharsetName.equals("US-ASCII")) {
+            value = new char[byteCount];
+            length = byteCount;
+            CharsetUtils.asciiBytesToChars(data, offset, byteCount, value);
+        } else {
+            CharBuffer cb = charset.decode(ByteBuffer.wrap(data, offset, byteCount));
+            length = cb.length();
+            // The call to newStringFromChars below will copy length bytes out of value, so it does
+            // not matter that cb.array().length may be > cb.length() or that a Charset could keep a
+            // reference to the CharBuffer it returns and later mutate it.
+            value = cb.array();
+        }
+        return newStringFromChars(value, 0, length);
+    }
+
+    public static String newStringFromBytes(byte[] data, Charset charset) {
+        return newStringFromBytes(data, 0, data.length, charset);
+    }
+
+    public static String newStringFromChars(char[] data) {
+        return newStringFromChars(data, 0, data.length);
+    }
+
+    public static String newStringFromChars(char[] data, int offset, int charCount) {
+        if ((offset | charCount) < 0 || charCount > data.length - offset) {
+            throw new StringIndexOutOfBoundsException(data.length, offset, charCount);
+        }
+        return newStringFromChars(offset, charCount, data);
+    }
+
+    // The char array passed as {@code java_data} must not be a null reference.
+    @FastNative
+    static native String newStringFromChars(int offset, int charCount, char[] data);
+
+    @FastNative
+    public static native String newStringFromString(String toCopy);
+
+    public static String newStringFromStringBuffer(StringBuffer stringBuffer) {
+        synchronized (stringBuffer) {
+            return newStringFromChars(stringBuffer.getValue(), 0, stringBuffer.length());
+        }
+    }
+
+    // TODO: Implement this method natively.
+    public static String newStringFromCodePoints(int[] codePoints, int offset, int count) {
+        if (codePoints == null) {
+            throw new NullPointerException("codePoints == null");
+        }
+        if ((offset | count) < 0 || count > codePoints.length - offset) {
+            throw new StringIndexOutOfBoundsException(codePoints.length, offset, count);
+        }
+        char[] value = new char[count * 2];
+        int end = offset + count;
+        int length = 0;
+        for (int i = offset; i < end; i++) {
+            length += Character.toChars(codePoints[i], value, length);
+        }
+        return newStringFromChars(value, 0, length);
+    }
+
+    public static String newStringFromStringBuilder(StringBuilder stringBuilder) {
+        return newStringFromChars(stringBuilder.getValue(), 0, stringBuilder.length());
+    }
+}
diff --git a/java/lang/StringIndexOutOfBoundsException.java b/java/lang/StringIndexOutOfBoundsException.java
new file mode 100644
index 0000000..a40bd29
--- /dev/null
+++ b/java/lang/StringIndexOutOfBoundsException.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown by {@code String} methods to indicate that an index
+ * is either negative or greater than the size of the string.  For
+ * some methods such as the charAt method, this exception also is
+ * thrown when the index is equal to the size of the string.
+ *
+ * @author  unascribed
+ * @see     java.lang.String#charAt(int)
+ * @since   JDK1.0
+ */
+public
+class StringIndexOutOfBoundsException extends IndexOutOfBoundsException {
+    private static final long serialVersionUID = -6762910422159637258L;
+
+    /**
+     * Constructs a {@code StringIndexOutOfBoundsException} with no
+     * detail message.
+     *
+     * @since   JDK1.0.
+     */
+    public StringIndexOutOfBoundsException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code StringIndexOutOfBoundsException} with
+     * the specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public StringIndexOutOfBoundsException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a new {@code StringIndexOutOfBoundsException}
+     * class with an argument indicating the illegal index.
+     *
+     * @param   index   the illegal index.
+     */
+    public StringIndexOutOfBoundsException(int index) {
+        super("String index out of range: " + index);
+    }
+
+    // BEGIN Android-added: Additional constructors for internal use.
+    /**
+     * Used internally for consistent high-quality error reporting.
+     * @hide
+     */
+    StringIndexOutOfBoundsException(String s, int index) {
+        this(s.length(), index);
+    }
+
+    /**
+     * Used internally for consistent high-quality error reporting.
+     * @hide
+     */
+    StringIndexOutOfBoundsException(int sourceLength, int index) {
+        super("length=" + sourceLength + "; index=" + index);
+    }
+
+    /**
+     * Used internally for consistent high-quality error reporting.
+     * @hide
+     */
+    StringIndexOutOfBoundsException(String s, int offset, int count) {
+        this(s.length(), offset, count);
+    }
+
+    /**
+     * Used internally for consistent high-quality error reporting.
+     * @hide
+     */
+    StringIndexOutOfBoundsException(int sourceLength, int offset,
+            int count) {
+        super("length=" + sourceLength + "; regionStart=" + offset
+                + "; regionLength=" + count);
+    }
+    // END Android-added: Additional constructors for internal use.
+}
diff --git a/java/lang/SuppressWarnings.java b/java/lang/SuppressWarnings.java
new file mode 100644
index 0000000..d315ddb
--- /dev/null
+++ b/java/lang/SuppressWarnings.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+/**
+ * Indicates that the named compiler warnings should be suppressed in the
+ * annotated element (and in all program elements contained in the annotated
+ * element).  Note that the set of warnings suppressed in a given element is
+ * a superset of the warnings suppressed in all containing elements.  For
+ * example, if you annotate a class to suppress one warning and annotate a
+ * method to suppress another, both warnings will be suppressed in the method.
+ *
+ * <p>As a matter of style, programmers should always use this annotation
+ * on the most deeply nested element where it is effective.  If you want to
+ * suppress a warning in a particular method, you should annotate that
+ * method rather than its class.
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @jls 4.8 Raw Types
+ * @jls 4.12.2 Variables of Reference Type
+ * @jls 5.1.9 Unchecked Conversion
+ * @jls 5.5.2 Checked Casts and Unchecked Casts
+ * @jls 9.6.3.5 @SuppressWarnings
+ */
+@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface SuppressWarnings {
+    /**
+     * The set of warnings that are to be suppressed by the compiler in the
+     * annotated element.  Duplicate names are permitted.  The second and
+     * successive occurrences of a name are ignored.  The presence of
+     * unrecognized warning names is <i>not</i> an error: Compilers must
+     * ignore any warning names they do not recognize.  They are, however,
+     * free to emit a warning if an annotation contains an unrecognized
+     * warning name.
+     *
+     * <p> The string {@code "unchecked"} is used to suppress
+     * unchecked warnings. Compiler vendors should document the
+     * additional warning names they support in conjunction with this
+     * annotation type. They are encouraged to cooperate to ensure
+     * that the same names work across multiple compilers.
+     * @return the set of warnings to be suppressed
+     */
+    String[] value();
+}
diff --git a/java/lang/System.annotated.java b/java/lang/System.annotated.java
new file mode 100644
index 0000000..918b3da
--- /dev/null
+++ b/java/lang/System.annotated.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.*;
+import java.nio.channels.spi.SelectorProvider;
+import java.nio.channels.Channel;
+import java.util.Properties;
+import java.util.PropertyPermission;
+import java.util.Map;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class System {
+
+System() { throw new RuntimeException("Stub!"); }
+
+public static void setIn(java.io.InputStream in) { throw new RuntimeException("Stub!"); }
+
+public static void setOut(java.io.PrintStream out) { throw new RuntimeException("Stub!"); }
+
+public static void setErr(java.io.PrintStream err) { throw new RuntimeException("Stub!"); }
+
+public static java.io.Console console() { throw new RuntimeException("Stub!"); }
+
+public static java.nio.channels.Channel inheritedChannel() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public static void setSecurityManager(java.lang.SecurityManager s) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.SecurityManager getSecurityManager() { throw new RuntimeException("Stub!"); }
+
+public static native long currentTimeMillis();
+
+public static native long nanoTime();
+
+public static native void arraycopy(java.lang.Object src, int srcPos, java.lang.Object dest, int destPos, int length);
+
+public static int identityHashCode(java.lang.Object x) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Properties getProperties() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String lineSeparator() { throw new RuntimeException("Stub!"); }
+
+public static void setProperties(java.util.Properties props) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String getProperty(java.lang.String key) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String getProperty(java.lang.String key, java.lang.String def) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String setProperty(java.lang.String key, java.lang.String value) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String clearProperty(java.lang.String key) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String getenv(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Map<java.lang.String,java.lang.String> getenv() { throw new RuntimeException("Stub!"); }
+
+public static void exit(int status) { throw new RuntimeException("Stub!"); }
+
+public static void gc() { throw new RuntimeException("Stub!"); }
+
+public static void runFinalization() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public static void runFinalizersOnExit(boolean value) { throw new RuntimeException("Stub!"); }
+
+public static void load(java.lang.String filename) { throw new RuntimeException("Stub!"); }
+
+public static void loadLibrary(java.lang.String libname) { throw new RuntimeException("Stub!"); }
+
+public static native java.lang.String mapLibraryName(java.lang.String libname);
+
+public static final java.io.PrintStream err;
+static { err = null; }
+
+public static final java.io.InputStream in;
+static { in = null; }
+
+public static final java.io.PrintStream out;
+static { out = null; }
+
[email protected]
+public static void logE(String message, Throwable th) { throw new RuntimeException("Stub!"); }
+
+}
+
diff --git a/java/lang/System.java b/java/lang/System.java
new file mode 100644
index 0000000..352d9ec
--- /dev/null
+++ b/java/lang/System.java
@@ -0,0 +1,1774 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang;
+
+import com.android.icu.util.Icu4cMetadata;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+import android.system.ErrnoException;
+import android.system.StructPasswd;
+import android.system.StructUtsname;
+import dalvik.system.VMRuntime;
+import java.io.*;
+import java.nio.channels.Channel;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.PropertyPermission;
+import libcore.io.Libcore;
+import libcore.timezone.TimeZoneDataFiles;
+
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
+/**
+ * The <code>System</code> class contains several useful class fields
+ * and methods. It cannot be instantiated.
+ *
+ * <p>Among the facilities provided by the <code>System</code> class
+ * are standard input, standard output, and error output streams;
+ * access to externally defined properties and environment
+ * variables; a means of loading files and libraries; and a utility
+ * method for quickly copying a portion of an array.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public final class System {
+    /** Don't let anyone instantiate this class */
+    private System() {
+    }
+
+    /**
+     * The "standard" input stream. This stream is already
+     * open and ready to supply input data. Typically this stream
+     * corresponds to keyboard input or another input source specified by
+     * the host environment or user.
+     */
+    public final static InputStream in;
+
+    /**
+     * The "standard" output stream. This stream is already
+     * open and ready to accept output data. Typically this stream
+     * corresponds to display output or another output destination
+     * specified by the host environment or user.
+     * <p>
+     * For simple stand-alone Java applications, a typical way to write
+     * a line of output data is:
+     * <blockquote><pre>
+     *     System.out.println(data)
+     * </pre></blockquote>
+     * <p>
+     * See the <code>println</code> methods in class <code>PrintStream</code>.
+     *
+     * @see     java.io.PrintStream#println()
+     * @see     java.io.PrintStream#println(boolean)
+     * @see     java.io.PrintStream#println(char)
+     * @see     java.io.PrintStream#println(char[])
+     * @see     java.io.PrintStream#println(double)
+     * @see     java.io.PrintStream#println(float)
+     * @see     java.io.PrintStream#println(int)
+     * @see     java.io.PrintStream#println(long)
+     * @see     java.io.PrintStream#println(java.lang.Object)
+     * @see     java.io.PrintStream#println(java.lang.String)
+     */
+    public final static PrintStream out;
+
+    /**
+     * The "standard" error output stream. This stream is already
+     * open and ready to accept output data.
+     * <p>
+     * Typically this stream corresponds to display output or another
+     * output destination specified by the host environment or user. By
+     * convention, this output stream is used to display error messages
+     * or other information that should come to the immediate attention
+     * of a user even if the principal output stream, the value of the
+     * variable <code>out</code>, has been redirected to a file or other
+     * destination that is typically not continuously monitored.
+     */
+    public final static PrintStream err;
+
+    /**
+     * Dedicated lock for GC / Finalization logic.
+     */
+    private static final Object LOCK = new Object();
+
+    /**
+     * Whether or not we need to do a GC before running the finalizers.
+     */
+    private static boolean runGC;
+
+    /**
+     * If we just ran finalization, we might want to do a GC to free the finalized objects.
+     * This lets us do gc/runFinlization/gc sequences but prevents back to back System.gc().
+     */
+    private static boolean justRanFinalization;
+
+    /**
+     * Reassigns the "standard" input stream.
+     *
+     * <p>First, if there is a security manager, its <code>checkPermission</code>
+     * method is called with a <code>RuntimePermission("setIO")</code> permission
+     *  to see if it's ok to reassign the "standard" input stream.
+     * <p>
+     *
+     * @param in the new standard input stream.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <code>checkPermission</code> method doesn't allow
+     *        reassigning of the standard input stream.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     *
+     * @since   JDK1.1
+     */
+    public static void setIn(InputStream in) {
+        setIn0(in);
+    }
+
+    /**
+     * Reassigns the "standard" output stream.
+     *
+     * <p>First, if there is a security manager, its <code>checkPermission</code>
+     * method is called with a <code>RuntimePermission("setIO")</code> permission
+     *  to see if it's ok to reassign the "standard" output stream.
+     *
+     * @param out the new standard output stream
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <code>checkPermission</code> method doesn't allow
+     *        reassigning of the standard output stream.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     *
+     * @since   JDK1.1
+     */
+    public static void setOut(PrintStream out) {
+        setOut0(out);
+    }
+
+    /**
+     * Reassigns the "standard" error output stream.
+     *
+     * <p>First, if there is a security manager, its <code>checkPermission</code>
+     * method is called with a <code>RuntimePermission("setIO")</code> permission
+     *  to see if it's ok to reassign the "standard" error output stream.
+     *
+     * @param err the new standard error output stream.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <code>checkPermission</code> method doesn't allow
+     *        reassigning of the standard error output stream.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     *
+     * @since   JDK1.1
+     */
+    public static void setErr(PrintStream err) {
+        setErr0(err);
+    }
+
+    private static volatile Console cons = null;
+    /**
+     * Returns the unique {@link java.io.Console Console} object associated
+     * with the current Java virtual machine, if any.
+     *
+     * @return  The system console, if any, otherwise <tt>null</tt>.
+     *
+     * @since   1.6
+     */
+     public static Console console() {
+         // Android-changed: Added proper double checked locking for cons access
+         if (cons == null) {
+             synchronized (System.class) {
+                 if (cons == null) {
+                     cons = Console.console();
+                 }
+             }
+         }
+         return cons;
+     }
+
+    /**
+     * Returns the channel inherited from the entity that created this
+     * Java virtual machine.
+     *
+     * <p> This method returns the channel obtained by invoking the
+     * {@link java.nio.channels.spi.SelectorProvider#inheritedChannel
+     * inheritedChannel} method of the system-wide default
+     * {@link java.nio.channels.spi.SelectorProvider} object. </p>
+     *
+     * <p> In addition to the network-oriented channels described in
+     * {@link java.nio.channels.spi.SelectorProvider#inheritedChannel
+     * inheritedChannel}, this method may return other kinds of
+     * channels in the future.
+     *
+     * @return  The inherited channel, if any, otherwise <tt>null</tt>.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and it does not
+     *          permit access to the channel.
+     *
+     * @since 1.5
+     */
+    public static Channel inheritedChannel() throws IOException {
+        return SelectorProvider.provider().inheritedChannel();
+    }
+
+    private static native void setIn0(InputStream in);
+    private static native void setOut0(PrintStream out);
+    private static native void setErr0(PrintStream err);
+
+    /**
+     * Throws {@code SecurityException} (except in case {@code sm == null}).
+     *
+     * <p>Security managers do <i>not</i> provide a secure environment for
+     * executing untrusted code and are unsupported on Android. Untrusted code
+     * cannot be safely isolated within a single VM on Android, so this method
+     * <i>always</i> throws a {@code SecurityException} when passed a non-null SecurityManager
+     *
+     * @param s a security manager
+     * @throws SecurityException always, unless {@code sm == null}
+     */
+    public static
+    void setSecurityManager(final SecurityManager s) {
+        if (s != null) {
+            throw new SecurityException();
+        }
+    }
+
+    /**
+     * Always returns {@code null} in Android
+     *
+     * @return  {@code null} in Android
+     */
+    public static SecurityManager getSecurityManager() {
+        // No-op on android.
+        return null;
+    }
+
+    /**
+     * Returns the current time in milliseconds.  Note that
+     * while the unit of time of the return value is a millisecond,
+     * the granularity of the value depends on the underlying
+     * operating system and may be larger.  For example, many
+     * operating systems measure time in units of tens of
+     * milliseconds.
+     *
+     * <p> See the description of the class <code>Date</code> for
+     * a discussion of slight discrepancies that may arise between
+     * "computer time" and coordinated universal time (UTC).
+     *
+     * @return  the difference, measured in milliseconds, between
+     *          the current time and midnight, January 1, 1970 UTC.
+     * @see     java.util.Date
+     */
+    @CriticalNative
+    public static native long currentTimeMillis();
+
+    /**
+     * Returns the current value of the running Java Virtual Machine's
+     * high-resolution time source, in nanoseconds.
+     *
+     * <p>This method can only be used to measure elapsed time and is
+     * not related to any other notion of system or wall-clock time.
+     * The value returned represents nanoseconds since some fixed but
+     * arbitrary <i>origin</i> time (perhaps in the future, so values
+     * may be negative).  The same origin is used by all invocations of
+     * this method in an instance of a Java virtual machine; other
+     * virtual machine instances are likely to use a different origin.
+     *
+     * <p>This method provides nanosecond precision, but not necessarily
+     * nanosecond resolution (that is, how frequently the value changes)
+     * - no guarantees are made except that the resolution is at least as
+     * good as that of {@link #currentTimeMillis()}.
+     *
+     * <p>Differences in successive calls that span greater than
+     * approximately 292 years (2<sup>63</sup> nanoseconds) will not
+     * correctly compute elapsed time due to numerical overflow.
+     *
+     * <p>The values returned by this method become meaningful only when
+     * the difference between two such values, obtained within the same
+     * instance of a Java virtual machine, is computed.
+     *
+     * <p> For example, to measure how long some code takes to execute:
+     *  <pre> {@code
+     * long startTime = System.nanoTime();
+     * // ... the code being measured ...
+     * long estimatedTime = System.nanoTime() - startTime;}</pre>
+     *
+     * <p>To compare two nanoTime values
+     *  <pre> {@code
+     * long t0 = System.nanoTime();
+     * ...
+     * long t1 = System.nanoTime();}</pre>
+     *
+     * one should use {@code t1 - t0 < 0}, not {@code t1 < t0},
+     * because of the possibility of numerical overflow.
+     *
+     * @return the current value of the running Java Virtual Machine's
+     *         high-resolution time source, in nanoseconds
+     * @since 1.5
+     */
+    @CriticalNative
+    public static native long nanoTime();
+
+    /**
+     * Copies an array from the specified source array, beginning at the
+     * specified position, to the specified position of the destination array.
+     * A subsequence of array components are copied from the source
+     * array referenced by <code>src</code> to the destination array
+     * referenced by <code>dest</code>. The number of components copied is
+     * equal to the <code>length</code> argument. The components at
+     * positions <code>srcPos</code> through
+     * <code>srcPos+length-1</code> in the source array are copied into
+     * positions <code>destPos</code> through
+     * <code>destPos+length-1</code>, respectively, of the destination
+     * array.
+     * <p>
+     * If the <code>src</code> and <code>dest</code> arguments refer to the
+     * same array object, then the copying is performed as if the
+     * components at positions <code>srcPos</code> through
+     * <code>srcPos+length-1</code> were first copied to a temporary
+     * array with <code>length</code> components and then the contents of
+     * the temporary array were copied into positions
+     * <code>destPos</code> through <code>destPos+length-1</code> of the
+     * destination array.
+     * <p>
+     * If <code>dest</code> is <code>null</code>, then a
+     * <code>NullPointerException</code> is thrown.
+     * <p>
+     * If <code>src</code> is <code>null</code>, then a
+     * <code>NullPointerException</code> is thrown and the destination
+     * array is not modified.
+     * <p>
+     * Otherwise, if any of the following is true, an
+     * <code>ArrayStoreException</code> is thrown and the destination is
+     * not modified:
+     * <ul>
+     * <li>The <code>src</code> argument refers to an object that is not an
+     *     array.
+     * <li>The <code>dest</code> argument refers to an object that is not an
+     *     array.
+     * <li>The <code>src</code> argument and <code>dest</code> argument refer
+     *     to arrays whose component types are different primitive types.
+     * <li>The <code>src</code> argument refers to an array with a primitive
+     *    component type and the <code>dest</code> argument refers to an array
+     *     with a reference component type.
+     * <li>The <code>src</code> argument refers to an array with a reference
+     *    component type and the <code>dest</code> argument refers to an array
+     *     with a primitive component type.
+     * </ul>
+     * <p>
+     * Otherwise, if any of the following is true, an
+     * <code>IndexOutOfBoundsException</code> is
+     * thrown and the destination is not modified:
+     * <ul>
+     * <li>The <code>srcPos</code> argument is negative.
+     * <li>The <code>destPos</code> argument is negative.
+     * <li>The <code>length</code> argument is negative.
+     * <li><code>srcPos+length</code> is greater than
+     *     <code>src.length</code>, the length of the source array.
+     * <li><code>destPos+length</code> is greater than
+     *     <code>dest.length</code>, the length of the destination array.
+     * </ul>
+     * <p>
+     * Otherwise, if any actual component of the source array from
+     * position <code>srcPos</code> through
+     * <code>srcPos+length-1</code> cannot be converted to the component
+     * type of the destination array by assignment conversion, an
+     * <code>ArrayStoreException</code> is thrown. In this case, let
+     * <b><i>k</i></b> be the smallest nonnegative integer less than
+     * length such that <code>src[srcPos+</code><i>k</i><code>]</code>
+     * cannot be converted to the component type of the destination
+     * array; when the exception is thrown, source array components from
+     * positions <code>srcPos</code> through
+     * <code>srcPos+</code><i>k</i><code>-1</code>
+     * will already have been copied to destination array positions
+     * <code>destPos</code> through
+     * <code>destPos+</code><i>k</I><code>-1</code> and no other
+     * positions of the destination array will have been modified.
+     * (Because of the restrictions already itemized, this
+     * paragraph effectively applies only to the situation where both
+     * arrays have component types that are reference types.)
+     *
+     * @param      src      the source array.
+     * @param      srcPos   starting position in the source array.
+     * @param      dest     the destination array.
+     * @param      destPos  starting position in the destination data.
+     * @param      length   the number of array elements to be copied.
+     * @exception  IndexOutOfBoundsException  if copying would cause
+     *               access of data outside array bounds.
+     * @exception  ArrayStoreException  if an element in the <code>src</code>
+     *               array could not be stored into the <code>dest</code> array
+     *               because of a type mismatch.
+     * @exception  NullPointerException if either <code>src</code> or
+     *               <code>dest</code> is <code>null</code>.
+     */
+    @FastNative
+    public static native void arraycopy(Object src,  int  srcPos,
+                                        Object dest, int destPos,
+                                        int length);
+
+
+    // BEGIN Android-changed
+    /**
+     * The char array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_CHAR_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The char[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_CHAR_ARRAY_THRESHOLD) {
+            // Copy char by char for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for longer arrays.
+            arraycopyCharUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The char[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyCharUnchecked(char[] src, int srcPos,
+        char[] dst, int dstPos, int length);
+
+    /**
+     * The byte array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_BYTE_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The byte[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_BYTE_ARRAY_THRESHOLD) {
+            // Copy byte by byte for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for longer arrays.
+            arraycopyByteUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The byte[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyByteUnchecked(byte[] src, int srcPos,
+        byte[] dst, int dstPos, int length);
+
+    /**
+     * The short array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_SHORT_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The short[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_SHORT_ARRAY_THRESHOLD) {
+            // Copy short by short for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for longer arrays.
+            arraycopyShortUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The short[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyShortUnchecked(short[] src, int srcPos,
+        short[] dst, int dstPos, int length);
+
+    /**
+     * The short array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_INT_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The int[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_INT_ARRAY_THRESHOLD) {
+            // Copy int by int for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for longer arrays.
+            arraycopyIntUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The int[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyIntUnchecked(int[] src, int srcPos,
+        int[] dst, int dstPos, int length);
+
+    /**
+     * The short array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_LONG_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The long[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_LONG_ARRAY_THRESHOLD) {
+            // Copy long by long for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for longer arrays.
+            arraycopyLongUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The long[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyLongUnchecked(long[] src, int srcPos,
+        long[] dst, int dstPos, int length);
+
+    /**
+     * The short array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_FLOAT_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The float[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_FLOAT_ARRAY_THRESHOLD) {
+            // Copy float by float for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for floater arrays.
+            arraycopyFloatUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The float[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyFloatUnchecked(float[] src, int srcPos,
+        float[] dst, int dstPos, int length);
+
+    /**
+     * The short array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_DOUBLE_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The double[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_DOUBLE_ARRAY_THRESHOLD) {
+            // Copy double by double for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for floater arrays.
+            arraycopyDoubleUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The double[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyDoubleUnchecked(double[] src, int srcPos,
+        double[] dst, int dstPos, int length);
+
+    /**
+     * The short array length threshold below which to use a Java
+     * (non-native) version of arraycopy() instead of the native
+     * version. See b/7103825.
+     */
+    private static final int ARRAYCOPY_SHORT_BOOLEAN_ARRAY_THRESHOLD = 32;
+
+    /**
+     * The boolean[] specialized version of arraycopy().
+     * Note: This method is required for runtime ART compiler optimizations.
+     * Do not remove or change the signature.
+     */
+    @SuppressWarnings("unused")
+    private static void arraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) {
+        if (src == null) {
+            throw new NullPointerException("src == null");
+        }
+        if (dst == null) {
+            throw new NullPointerException("dst == null");
+        }
+        if (srcPos < 0 || dstPos < 0 || length < 0 ||
+            srcPos > src.length - length || dstPos > dst.length - length) {
+            throw new ArrayIndexOutOfBoundsException(
+                "src.length=" + src.length + " srcPos=" + srcPos +
+                " dst.length=" + dst.length + " dstPos=" + dstPos + " length=" + length);
+        }
+        if (length <= ARRAYCOPY_SHORT_BOOLEAN_ARRAY_THRESHOLD) {
+            // Copy boolean by boolean for shorter arrays.
+            if (src == dst && srcPos < dstPos && dstPos < srcPos + length) {
+                // Copy backward (to avoid overwriting elements before
+                // they are copied in case of an overlap on the same
+                // array.)
+                for (int i = length - 1; i >= 0; --i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            } else {
+                // Copy forward.
+                for (int i = 0; i < length; ++i) {
+                    dst[dstPos + i] = src[srcPos + i];
+                }
+            }
+        } else {
+            // Call the native version for floater arrays.
+            arraycopyBooleanUnchecked(src, srcPos, dst, dstPos, length);
+        }
+    }
+
+    /**
+     * The boolean[] specialized, unchecked, native version of
+     * arraycopy(). This assumes error checking has been done.
+     */
+    @FastNative
+    private static native void arraycopyBooleanUnchecked(boolean[] src, int srcPos,
+        boolean[] dst, int dstPos, int length);
+    // END Android-changed
+
+    /**
+     * Returns the same hash code for the given object as
+     * would be returned by the default method hashCode(),
+     * whether or not the given object's class overrides
+     * hashCode().
+     * The hash code for the null reference is zero.
+     *
+     * @param x object for which the hashCode is to be calculated
+     * @return  the hashCode
+     * @since   JDK1.1
+     */
+    public static int identityHashCode(Object x) {
+        if (x == null) {
+            return 0;
+        }
+        return Object.identityHashCode(x);
+    }
+
+    /**
+     * System properties. The following properties are guaranteed to be defined:
+     * <dl>
+     * <dt>java.version         <dd>Java version number
+     * <dt>java.vendor          <dd>Java vendor specific string
+     * <dt>java.vendor.url      <dd>Java vendor URL
+     * <dt>java.home            <dd>Java installation directory
+     * <dt>java.class.version   <dd>Java class version number
+     * <dt>java.class.path      <dd>Java classpath
+     * <dt>os.name              <dd>Operating System Name
+     * <dt>os.arch              <dd>Operating System Architecture
+     * <dt>os.version           <dd>Operating System Version
+     * <dt>file.separator       <dd>File separator ("/" on Unix)
+     * <dt>path.separator       <dd>Path separator (":" on Unix)
+     * <dt>line.separator       <dd>Line separator ("\n" on Unix)
+     * <dt>user.name            <dd>User account name
+     * <dt>user.home            <dd>User home directory
+     * <dt>user.dir             <dd>User's current working directory
+     * </dl>
+     */
+
+    private static Properties props;
+    private static Properties unchangeableProps;
+
+    private static native String[] specialProperties();
+
+    static final class PropertiesWithNonOverrideableDefaults extends Properties {
+        PropertiesWithNonOverrideableDefaults(Properties defaults) {
+            super(defaults);
+        }
+
+        @Override
+        public Object put(Object key, Object value) {
+            if (defaults.containsKey(key)) {
+                logE("Ignoring attempt to set property \"" + key +
+                        "\" to value \"" + value + "\".");
+                return defaults.get(key);
+            }
+
+            return super.put(key, value);
+        }
+
+        @Override
+        public Object remove(Object key) {
+            if (defaults.containsKey(key)) {
+                logE("Ignoring attempt to remove property \"" + key + "\".");
+                return null;
+            }
+
+            return super.remove(key);
+        }
+    }
+
+    private static void parsePropertyAssignments(Properties p, String[] assignments) {
+        for (String assignment : assignments) {
+            int split = assignment.indexOf('=');
+            String key = assignment.substring(0, split);
+            String value = assignment.substring(split + 1);
+            p.put(key, value);
+        }
+    }
+
+    private static Properties initUnchangeableSystemProperties() {
+        VMRuntime runtime = VMRuntime.getRuntime();
+        Properties p = new Properties();
+
+        // Set non-static properties.
+        p.put("java.boot.class.path", runtime.bootClassPath());
+        p.put("java.class.path", runtime.classPath());
+
+        // TODO: does this make any sense? Should we just leave java.home unset?
+        String javaHome = getenv("JAVA_HOME");
+        if (javaHome == null) {
+            javaHome = "/system";
+        }
+        p.put("java.home", javaHome);
+
+        p.put("java.vm.version", runtime.vmVersion());
+
+        try {
+            StructPasswd passwd = Libcore.os.getpwuid(Libcore.os.getuid());
+            p.put("user.name", passwd.pw_name);
+        } catch (ErrnoException exception) {
+            throw new AssertionError(exception);
+        }
+
+        StructUtsname info = Libcore.os.uname();
+        p.put("os.arch", info.machine);
+        // os.name was previously hardcoded to "Linux", but was reverted due to support
+        // for Fuchsia. b/121268567 shows initialization regressions.
+        p.put("os.name", info.sysname);
+        p.put("os.version", info.release);
+
+        // Android-added: Undocumented properties that exist only on Android.
+        p.put("android.icu.library.version", Icu4cMetadata.getIcuVersion());
+        p.put("android.icu.unicode.version", Icu4cMetadata.getUnicodeVersion());
+        p.put("android.icu.cldr.version", Icu4cMetadata.getCldrVersion());
+
+        // Property override for ICU4J : this is the location of the ICU4C data. This
+        // is prioritized over the properties in ICUConfig.properties. The issue with using
+        // that is that it doesn't play well with jarjar and it needs complicated build rules
+        // to change its default value.
+        String icuDataPath = TimeZoneDataFiles.generateIcuDataPath();
+        p.put("android.icu.impl.ICUBinary.dataPath", icuDataPath);
+
+        parsePropertyAssignments(p, specialProperties());
+
+        // Override built-in properties with settings from the command line.
+        // Note: it is not possible to override hardcoded values.
+        parsePropertyAssignments(p, runtime.properties());
+
+
+        // Set static hardcoded properties.
+        // These come last, as they must be guaranteed to agree with what a backend compiler
+        // may assume when compiling the boot image on Android.
+        for (String[] pair : AndroidHardcodedSystemProperties.STATIC_PROPERTIES) {
+            if (p.containsKey(pair[0])) {
+                logE("Ignoring command line argument: -D" + pair[0]);
+            }
+            if (pair[1] == null) {
+                p.remove(pair[0]);
+            } else {
+                p.put(pair[0], pair[1]);
+            }
+        }
+
+        return p;
+    }
+
+    private static Properties initProperties() {
+        Properties p = new PropertiesWithNonOverrideableDefaults(unchangeableProps);
+        setDefaultChangeableProperties(p);
+        return p;
+    }
+
+    private static Properties setDefaultChangeableProperties(Properties p) {
+        // On Android, each app gets its own temporary directory.
+        // (See android.app.ActivityThread.) This is just a fallback default,
+        // useful only on the host.
+        // We check first if the property has not been set already: note that it
+        // can only be set from the command line through the '-Djava.io.tmpdir=' option.
+        if (!unchangeableProps.containsKey("java.io.tmpdir")) {
+            p.put("java.io.tmpdir", "/tmp");
+        }
+
+        // Android has always had an empty "user.home" (see docs for getProperty).
+        // This is not useful for normal android apps which need to use android specific
+        // APIs such as {@code Context.getFilesDir} and {@code Context.getCacheDir} but
+        // we make it changeable for backward compatibility, so that they can change it
+        // to a writeable location if required.
+        // We check first if the property has not been set already: note that it
+        // can only be set from the command line through the '-Duser.home=' option.
+        if (!unchangeableProps.containsKey("user.home")) {
+            p.put("user.home", "");
+        }
+
+        return p;
+    }
+
+    /**
+     * Inits an unchangeable system property with the given value.
+     *
+     * This is called from native code when the environment needs to change under native
+     * bridge emulation.
+     *
+     * @hide also visible for tests.
+     */
+    public static void setUnchangeableSystemProperty(String key, String value) {
+        checkKey(key);
+        unchangeableProps.put(key, value);
+    }
+
+    private static void addLegacyLocaleSystemProperties() {
+        final String locale = getProperty("user.locale", "");
+        if (!locale.isEmpty()) {
+            Locale l = Locale.forLanguageTag(locale);
+            setUnchangeableSystemProperty("user.language", l.getLanguage());
+            setUnchangeableSystemProperty("user.region", l.getCountry());
+            setUnchangeableSystemProperty("user.variant", l.getVariant());
+        } else {
+            // If "user.locale" isn't set we fall back to our old defaults of
+            // language="en" and region="US" (if unset) and don't attempt to set it.
+            // The Locale class will fall back to using user.language and
+            // user.region if unset.
+            final String language = getProperty("user.language", "");
+            final String region = getProperty("user.region", "");
+
+            if (language.isEmpty()) {
+                setUnchangeableSystemProperty("user.language", "en");
+            }
+
+            if (region.isEmpty()) {
+                setUnchangeableSystemProperty("user.region", "US");
+            }
+        }
+    }
+
+    /**
+     * Determines the current system properties.
+     *
+     *
+     * <p>The following properties are always provided by the Dalvik VM:</p>
+     * <p><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+     * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+     *     <td><b>Name</b></td>        <td><b>Meaning</b></td>                    <td><b>Example</b></td></tr>
+     * <tr><td>file.separator</td>     <td>{@link java.io.File#separator}</td>    <td>{@code /}</td></tr>
+     *
+     * <tr><td>java.class.path</td>    <td>System class path</td>                 <td>{@code .}</td></tr>
+     * <tr><td>java.class.version</td> <td>(Not useful on Android)</td>           <td>{@code 50.0}</td></tr>
+     * <tr><td>java.compiler</td>      <td>(Not useful on Android)</td>           <td>Empty</td></tr>
+     * <tr><td>java.ext.dirs</td>      <td>(Not useful on Android)</td>           <td>Empty</td></tr>
+     * <tr><td>java.home</td>          <td>Location of the VM on the file system</td> <td>{@code /system}</td></tr>
+     * <tr><td>java.io.tmpdir</td>     <td>See {@link java.io.File#createTempFile}</td> <td>{@code /sdcard}</td></tr>
+     * <tr><td>java.library.path</td>  <td>Search path for JNI libraries</td>     <td>{@code /vendor/lib:/system/lib}</td></tr>
+     * <tr><td>java.vendor</td>        <td>Human-readable VM vendor</td>          <td>{@code The Android Project}</td></tr>
+     * <tr><td>java.vendor.url</td>    <td>URL for VM vendor's web site</td>      <td>{@code http://www.android.com/}</td></tr>
+     * <tr><td>java.version</td>       <td>(Not useful on Android)</td>           <td>{@code 0}</td></tr>
+     *
+     * <tr><td>java.specification.version</td>    <td>VM libraries version</td>        <td>{@code 0.9}</td></tr>
+     * <tr><td>java.specification.vendor</td>     <td>VM libraries vendor</td>         <td>{@code The Android Project}</td></tr>
+     * <tr><td>java.specification.name</td>       <td>VM libraries name</td>           <td>{@code Dalvik Core Library}</td></tr>
+     * <tr><td>java.vm.version</td>               <td>VM implementation version</td>   <td>{@code 1.2.0}</td></tr>
+     * <tr><td>java.vm.vendor</td>                <td>VM implementation vendor</td>    <td>{@code The Android Project}</td></tr>
+     * <tr><td>java.vm.name</td>                  <td>VM implementation name</td>      <td>{@code Dalvik}</td></tr>
+     * <tr><td>java.vm.specification.version</td> <td>VM specification version</td>    <td>{@code 0.9}</td></tr>
+     * <tr><td>java.vm.specification.vendor</td>  <td>VM specification vendor</td>     <td>{@code The Android Project}</td></tr>
+     * <tr><td>java.vm.specification.name</td>    <td>VM specification name</td>       <td>{@code Dalvik Virtual Machine Specification}</td></tr>
+     *
+     * <tr><td>line.separator</td>     <td>The system line separator</td>         <td>{@code \n}</td></tr>
+     *
+     * <tr><td>os.arch</td>            <td>OS architecture</td>                   <td>{@code armv7l}</td></tr>
+     * <tr><td>os.name</td>            <td>OS (kernel) name</td>                  <td>{@code Linux}</td></tr>
+     * <tr><td>os.version</td>         <td>OS (kernel) version</td>               <td>{@code 2.6.32.9-g103d848}</td></tr>
+     *
+     * <tr><td>path.separator</td>     <td>See {@link java.io.File#pathSeparator}</td> <td>{@code :}</td></tr>
+     *
+     * <tr><td>user.dir</td>           <td>Base of non-absolute paths</td>        <td>{@code /}</td></tr>
+     * <tr><td>user.home</td>          <td>(Not useful on Android)</td>           <td>Empty</td></tr>
+     * <tr><td>user.name</td>          <td>(Not useful on Android)</td>           <td>Empty</td></tr>
+     *
+     * </table>
+     * <p>
+     * Multiple paths in a system property value are separated by the path
+     * separator character of the platform.
+     * <p>
+     * Note that even if the security manager does not permit the
+     * <code>getProperties</code> operation, it may choose to permit the
+     * {@link #getProperty(String)} operation.
+     *
+     * @return     the system properties
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkPropertiesAccess</code> method doesn't allow access
+     *              to the system properties.
+     * @see        #setProperties
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkPropertiesAccess()
+     * @see        java.util.Properties
+     */
+    public static Properties getProperties() {
+        SecurityManager sm = getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertiesAccess();
+        }
+
+        return props;
+    }
+
+    /**
+     * Returns the system-dependent line separator string.  It always
+     * returns the same value - the initial value of the {@linkplain
+     * #getProperty(String) system property} {@code line.separator}.
+     *
+     * <p>On UNIX systems, it returns {@code "\n"}; on Microsoft
+     * Windows systems it returns {@code "\r\n"}.
+     *
+     * @return the system-dependent line separator string
+     * @since 1.7
+     */
+    public static String lineSeparator() {
+        return lineSeparator;
+    }
+
+    private static String lineSeparator;
+
+
+    // Comment replaced with android one.
+    /**
+     * Attempts to set all system properties. Copies all properties from
+     * {@code p} and discards system properties that are read only and cannot
+     * be modified. See {@link #getProperty} for a list of such properties.
+     */
+    public static void setProperties(Properties props) {
+        Properties baseProperties = new PropertiesWithNonOverrideableDefaults(unchangeableProps);
+        if (props != null) {
+            baseProperties.putAll(props);
+        } else {
+            setDefaultChangeableProperties(baseProperties);
+        }
+
+        System.props = baseProperties;
+    }
+
+    /**
+     * Gets the system property indicated by the specified key.
+     * <p>
+     * First, if there is a security manager, its
+     * <code>checkPropertyAccess</code> method is called with the key as
+     * its argument. This may result in a SecurityException.
+     * <p>
+     * If there is no current set of system properties, a set of system
+     * properties is first created and initialized in the same manner as
+     * for the <code>getProperties</code> method.
+     *
+     * @param      key   the name of the system property.
+     * @return     the string value of the system property,
+     *             or <code>null</code> if there is no property with that key.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *              access to the specified system property.
+     * @exception  NullPointerException if <code>key</code> is
+     *             <code>null</code>.
+     * @exception  IllegalArgumentException if <code>key</code> is empty.
+     * @see        #setProperty
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
+     * @see        java.lang.System#getProperties()
+     */
+    public static String getProperty(String key) {
+        checkKey(key);
+        SecurityManager sm = getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertyAccess(key);
+        }
+
+        return props.getProperty(key);
+    }
+
+    /**
+     * Gets the system property indicated by the specified key.
+     * <p>
+     * First, if there is a security manager, its
+     * <code>checkPropertyAccess</code> method is called with the
+     * <code>key</code> as its argument.
+     * <p>
+     * If there is no current set of system properties, a set of system
+     * properties is first created and initialized in the same manner as
+     * for the <code>getProperties</code> method.
+     *
+     * @param      key   the name of the system property.
+     * @param      def   a default value.
+     * @return     the string value of the system property,
+     *             or the default value if there is no property with that key.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *             access to the specified system property.
+     * @exception  NullPointerException if <code>key</code> is
+     *             <code>null</code>.
+     * @exception  IllegalArgumentException if <code>key</code> is empty.
+     * @see        #setProperty
+     * @see        java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
+     * @see        java.lang.System#getProperties()
+     */
+    public static String getProperty(String key, String def) {
+        checkKey(key);
+        SecurityManager sm = getSecurityManager();
+        if (sm != null) {
+            sm.checkPropertyAccess(key);
+        }
+
+        return props.getProperty(key, def);
+    }
+
+    /**
+     * Sets the system property indicated by the specified key.
+     * <p>
+     * First, if a security manager exists, its
+     * <code>SecurityManager.checkPermission</code> method
+     * is called with a <code>PropertyPermission(key, "write")</code>
+     * permission. This may result in a SecurityException being thrown.
+     * If no exception is thrown, the specified property is set to the given
+     * value.
+     * <p>
+     *
+     * @param      key   the name of the system property.
+     * @param      value the value of the system property.
+     * @return     the previous value of the system property,
+     *             or <code>null</code> if it did not have one.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkPermission</code> method doesn't allow
+     *             setting of the specified property.
+     * @exception  NullPointerException if <code>key</code> or
+     *             <code>value</code> is <code>null</code>.
+     * @exception  IllegalArgumentException if <code>key</code> is empty.
+     * @see        #getProperty
+     * @see        java.lang.System#getProperty(java.lang.String)
+     * @see        java.lang.System#getProperty(java.lang.String, java.lang.String)
+     * @see        java.util.PropertyPermission
+     * @see        SecurityManager#checkPermission
+     * @since      1.2
+     */
+    public static String setProperty(String key, String value) {
+        checkKey(key);
+        SecurityManager sm = getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new PropertyPermission(key,
+                SecurityConstants.PROPERTY_WRITE_ACTION));
+        }
+
+        return (String) props.setProperty(key, value);
+    }
+
+    /**
+     * Removes the system property indicated by the specified key.
+     * <p>
+     * First, if a security manager exists, its
+     * <code>SecurityManager.checkPermission</code> method
+     * is called with a <code>PropertyPermission(key, "write")</code>
+     * permission. This may result in a SecurityException being thrown.
+     * If no exception is thrown, the specified property is removed.
+     * <p>
+     *
+     * @param      key   the name of the system property to be removed.
+     * @return     the previous string value of the system property,
+     *             or <code>null</code> if there was no property with that key.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkPropertyAccess</code> method doesn't allow
+     *              access to the specified system property.
+     * @exception  NullPointerException if <code>key</code> is
+     *             <code>null</code>.
+     * @exception  IllegalArgumentException if <code>key</code> is empty.
+     * @see        #getProperty
+     * @see        #setProperty
+     * @see        java.util.Properties
+     * @see        java.lang.SecurityException
+     * @see        java.lang.SecurityManager#checkPropertiesAccess()
+     * @since 1.5
+     */
+    public static String clearProperty(String key) {
+        checkKey(key);
+        SecurityManager sm = getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new PropertyPermission(key, "write"));
+        }
+
+        return (String) props.remove(key);
+    }
+
+    private static void checkKey(String key) {
+        if (key == null) {
+            throw new NullPointerException("key can't be null");
+        }
+        if (key.equals("")) {
+            throw new IllegalArgumentException("key can't be empty");
+        }
+    }
+
+    /**
+     * Gets the value of the specified environment variable. An
+     * environment variable is a system-dependent external named
+     * value.
+     *
+     * <p>If a security manager exists, its
+     * {@link SecurityManager#checkPermission checkPermission}
+     * method is called with a
+     * <code>{@link RuntimePermission}("getenv."+name)</code>
+     * permission.  This may result in a {@link SecurityException}
+     * being thrown.  If no exception is thrown the value of the
+     * variable <code>name</code> is returned.
+     *
+     * <p><a name="EnvironmentVSSystemProperties"><i>System
+     * properties</i> and <i>environment variables</i></a> are both
+     * conceptually mappings between names and values.  Both
+     * mechanisms can be used to pass user-defined information to a
+     * Java process.  Environment variables have a more global effect,
+     * because they are visible to all descendants of the process
+     * which defines them, not just the immediate Java subprocess.
+     * They can have subtly different semantics, such as case
+     * insensitivity, on different operating systems.  For these
+     * reasons, environment variables are more likely to have
+     * unintended side effects.  It is best to use system properties
+     * where possible.  Environment variables should be used when a
+     * global effect is desired, or when an external system interface
+     * requires an environment variable (such as <code>PATH</code>).
+     *
+     * <p>On UNIX systems the alphabetic case of <code>name</code> is
+     * typically significant, while on Microsoft Windows systems it is
+     * typically not.  For example, the expression
+     * <code>System.getenv("FOO").equals(System.getenv("foo"))</code>
+     * is likely to be true on Microsoft Windows.
+     *
+     * @param  name the name of the environment variable
+     * @return the string value of the variable, or <code>null</code>
+     *         if the variable is not defined in the system environment
+     * @throws NullPointerException if <code>name</code> is <code>null</code>
+     * @throws SecurityException
+     *         if a security manager exists and its
+     *         {@link SecurityManager#checkPermission checkPermission}
+     *         method doesn't allow access to the environment variable
+     *         <code>name</code>
+     * @see    #getenv()
+     * @see    ProcessBuilder#environment()
+     */
+    public static String getenv(String name) {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+
+        return Libcore.os.getenv(name);
+    }
+
+
+    /**
+     * Returns an unmodifiable string map view of the current system environment.
+     * The environment is a system-dependent mapping from names to
+     * values which is passed from parent to child processes.
+     *
+     * <p>If the system does not support environment variables, an
+     * empty map is returned.
+     *
+     * <p>The returned map will never contain null keys or values.
+     * Attempting to query the presence of a null key or value will
+     * throw a {@link NullPointerException}.  Attempting to query
+     * the presence of a key or value which is not of type
+     * {@link String} will throw a {@link ClassCastException}.
+     *
+     * <p>The returned map and its collection views may not obey the
+     * general contract of the {@link Object#equals} and
+     * {@link Object#hashCode} methods.
+     *
+     * <p>The returned map is typically case-sensitive on all platforms.
+     *
+     * <p>If a security manager exists, its
+     * {@link SecurityManager#checkPermission checkPermission}
+     * method is called with a
+     * <code>{@link RuntimePermission}("getenv.*")</code>
+     * permission.  This may result in a {@link SecurityException} being
+     * thrown.
+     *
+     * <p>When passing information to a Java subprocess,
+     * <a href=#EnvironmentVSSystemProperties>system properties</a>
+     * are generally preferred over environment variables.
+     *
+     * @return the environment as a map of variable names to values
+     * @throws SecurityException
+     *         if a security manager exists and its
+     *         {@link SecurityManager#checkPermission checkPermission}
+     *         method doesn't allow access to the process environment
+     * @see    #getenv(String)
+     * @see    ProcessBuilder#environment()
+     * @since  1.5
+     */
+    public static java.util.Map<String,String> getenv() {
+        SecurityManager sm = getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("getenv.*"));
+        }
+
+        return ProcessEnvironment.getenv();
+    }
+
+    /**
+     * Terminates the currently running Java Virtual Machine. The
+     * argument serves as a status code; by convention, a nonzero status
+     * code indicates abnormal termination.
+     * <p>
+     * This method calls the <code>exit</code> method in class
+     * <code>Runtime</code>. This method never returns normally.
+     * <p>
+     * The call <code>System.exit(n)</code> is effectively equivalent to
+     * the call:
+     * <blockquote><pre>
+     * Runtime.getRuntime().exit(n)
+     * </pre></blockquote>
+     *
+     * @param      status   exit status.
+     * @throws  SecurityException
+     *        if a security manager exists and its <code>checkExit</code>
+     *        method doesn't allow exit with the specified status.
+     * @see        java.lang.Runtime#exit(int)
+     */
+    public static void exit(int status) {
+        Runtime.getRuntime().exit(status);
+    }
+
+    /**
+     * Runs the garbage collector.
+     * <p>
+     * Calling the <code>gc</code> method suggests that the Java Virtual
+     * Machine expend effort toward recycling unused objects in order to
+     * make the memory they currently occupy available for quick reuse.
+     * When control returns from the method call, the Java Virtual
+     * Machine has made a best effort to reclaim space from all discarded
+     * objects.
+     * <p>
+     * The call <code>System.gc()</code> is effectively equivalent to the
+     * call:
+     * <blockquote><pre>
+     * Runtime.getRuntime().gc()
+     * </pre></blockquote>
+     *
+     * @see     java.lang.Runtime#gc()
+     */
+    public static void gc() {
+        boolean shouldRunGC;
+        synchronized (LOCK) {
+            shouldRunGC = justRanFinalization;
+            if (shouldRunGC) {
+                justRanFinalization = false;
+            } else {
+                runGC = true;
+            }
+        }
+        if (shouldRunGC) {
+            Runtime.getRuntime().gc();
+        }
+    }
+
+    /**
+     * Runs the finalization methods of any objects pending finalization.
+     * <p>
+     * Calling this method suggests that the Java Virtual Machine expend
+     * effort toward running the <code>finalize</code> methods of objects
+     * that have been found to be discarded but whose <code>finalize</code>
+     * methods have not yet been run. When control returns from the
+     * method call, the Java Virtual Machine has made a best effort to
+     * complete all outstanding finalizations.
+     * <p>
+     * The call <code>System.runFinalization()</code> is effectively
+     * equivalent to the call:
+     * <blockquote><pre>
+     * Runtime.getRuntime().runFinalization()
+     * </pre></blockquote>
+     *
+     * @see     java.lang.Runtime#runFinalization()
+     */
+    public static void runFinalization() {
+        boolean shouldRunGC;
+        synchronized (LOCK) {
+            shouldRunGC = runGC;
+            runGC = false;
+        }
+        if (shouldRunGC) {
+            Runtime.getRuntime().gc();
+        }
+        Runtime.getRuntime().runFinalization();
+        synchronized (LOCK) {
+            justRanFinalization = true;
+        }
+    }
+
+    /**
+     * Enable or disable finalization on exit; doing so specifies that the
+     * finalizers of all objects that have finalizers that have not yet been
+     * automatically invoked are to be run before the Java runtime exits.
+     * By default, finalization on exit is disabled.
+     *
+     * <p>If there is a security manager,
+     * its <code>checkExit</code> method is first called
+     * with 0 as its argument to ensure the exit is allowed.
+     * This could result in a SecurityException.
+     *
+     * @deprecated  This method is inherently unsafe.  It may result in
+     *      finalizers being called on live objects while other threads are
+     *      concurrently manipulating those objects, resulting in erratic
+     *      behavior or deadlock.
+     * @param value indicating enabling or disabling of finalization
+     * @throws  SecurityException
+     *        if a security manager exists and its <code>checkExit</code>
+     *        method doesn't allow the exit.
+     *
+     * @see     java.lang.Runtime#exit(int)
+     * @see     java.lang.Runtime#gc()
+     * @see     java.lang.SecurityManager#checkExit(int)
+     * @since   JDK1.1
+     */
+    @Deprecated
+    public static void runFinalizersOnExit(boolean value) {
+        Runtime.runFinalizersOnExit(value);
+    }
+
+    /**
+     * Loads the native library specified by the filename argument.  The filename
+     * argument must be an absolute path name.
+     *
+     * If the filename argument, when stripped of any platform-specific library
+     * prefix, path, and file extension, indicates a library whose name is,
+     * for example, L, and a native library called L is statically linked
+     * with the VM, then the JNI_OnLoad_L function exported by the library
+     * is invoked rather than attempting to load a dynamic library.
+     * A filename matching the argument does not have to exist in the
+     * file system.
+     * See the JNI Specification for more details.
+     *
+     * Otherwise, the filename argument is mapped to a native library image in
+     * an implementation-dependent manner.
+     *
+     * <p>
+     * The call <code>System.load(name)</code> is effectively equivalent
+     * to the call:
+     * <blockquote><pre>
+     * Runtime.getRuntime().load(name)
+     * </pre></blockquote>
+     *
+     * @param      filename   the file to load.
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkLink</code> method doesn't allow
+     *             loading of the specified dynamic library
+     * @exception  UnsatisfiedLinkError  if either the filename is not an
+     *             absolute path name, the native library is not statically
+     *             linked with the VM, or the library cannot be mapped to
+     *             a native library image by the host system.
+     * @exception  NullPointerException if <code>filename</code> is
+     *             <code>null</code>
+     * @see        java.lang.Runtime#load(java.lang.String)
+     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
+     */
+    @CallerSensitive
+    public static void load(String filename) {
+        Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
+    }
+
+    /**
+     * Loads the native library specified by the <code>libname</code>
+     * argument.  The <code>libname</code> argument must not contain any platform
+     * specific prefix, file extension or path. If a native library
+     * called <code>libname</code> is statically linked with the VM, then the
+     * JNI_OnLoad_<code>libname</code> function exported by the library is invoked.
+     * See the JNI Specification for more details.
+     *
+     * Otherwise, the libname argument is loaded from a system library
+     * location and mapped to a native library image in an implementation-
+     * dependent manner.
+     * <p>
+     * The call <code>System.loadLibrary(name)</code> is effectively
+     * equivalent to the call
+     * <blockquote><pre>
+     * Runtime.getRuntime().loadLibrary(name)
+     * </pre></blockquote>
+     *
+     * @param      libname   the name of the library.
+     * @exception  SecurityException  if a security manager exists and its
+     *             <code>checkLink</code> method doesn't allow
+     *             loading of the specified dynamic library
+     * @exception  UnsatisfiedLinkError if either the libname argument
+     *             contains a file path, the native library is not statically
+     *             linked with the VM,  or the library cannot be mapped to a
+     *             native library image by the host system.
+     * @exception  NullPointerException if <code>libname</code> is
+     *             <code>null</code>
+     * @see        java.lang.Runtime#loadLibrary(java.lang.String)
+     * @see        java.lang.SecurityManager#checkLink(java.lang.String)
+     */
+    @CallerSensitive
+    public static void loadLibrary(String libname) {
+        Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
+    }
+
+    /**
+     * Maps a library name into a platform-specific string representing
+     * a native library.
+     *
+     * @param      libname the name of the library.
+     * @return     a platform-dependent native library name.
+     * @exception  NullPointerException if <code>libname</code> is
+     *             <code>null</code>
+     * @see        java.lang.System#loadLibrary(java.lang.String)
+     * @see        java.lang.ClassLoader#findLibrary(java.lang.String)
+     * @since      1.2
+     */
+    public static native String mapLibraryName(String libname);
+
+    /**
+     * Create PrintStream for stdout/err based on encoding.
+     */
+    private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
+       if (enc != null) {
+            try {
+                return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
+            } catch (UnsupportedEncodingException uee) {}
+        }
+        return new PrintStream(new BufferedOutputStream(fos, 128), true);
+    }
+
+
+    /**
+     * Initialize the system class.  Called after thread initialization.
+     */
+    static {
+        unchangeableProps = initUnchangeableSystemProperties();
+        props = initProperties();
+        addLegacyLocaleSystemProperties();
+        sun.misc.Version.initSystemProperties();
+
+        // TODO: Confirm that this isn't something super important.
+        // sun.misc.VM.saveAndRemoveProperties(props);
+
+        lineSeparator = props.getProperty("line.separator");
+
+        FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
+        FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
+        FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
+        // BEGIN Android-changed: lower buffer size.
+        // in = new BufferedInputStream(fdIn);
+        in = new BufferedInputStream(fdIn, 128);
+        // END Android-changed: lower buffer size.
+        out = newPrintStream(fdOut, props.getProperty("sun.stdout.encoding"));
+        err = newPrintStream(fdErr, props.getProperty("sun.stderr.encoding"));
+
+        // Initialize any miscellenous operating system settings that need to be
+        // set for the class libraries. Currently this is no-op everywhere except
+        // for Windows where the process-wide error mode is set before the java.io
+        // classes are used.
+        sun.misc.VM.initializeOSEnvironment();
+
+        // Subsystems that are invoked during initialization can invoke
+        // sun.misc.VM.isBooted() in order to avoid doing things that should
+        // wait until the application class loader has been set up.
+        // IMPORTANT: Ensure that this remains the last initialization action!
+        sun.misc.VM.booted();
+    }
+
+    /**
+     * @hide internal use only
+     */
+    public static void logE(String message) {
+        log('E', message, null);
+    }
+
+    /**
+     * @hide internal use only
+     */
+    public static void logE(String message, Throwable th) {
+        log('E', message, th);
+    }
+
+    /**
+     * @hide internal use only
+     */
+    public static void logI(String message) {
+        log('I', message, null);
+    }
+
+    /**
+     * @hide internal use only
+     */
+    public static void logI(String message, Throwable th) {
+        log('I', message, th);
+    }
+
+    /**
+     * @hide internal use only
+     */
+    public static void logW(String message) {
+        log('W', message, null);
+    }
+
+    /**
+     * @hide internal use only
+     */
+    public static void logW(String message, Throwable th) {
+        log('W', message, th);
+    }
+
+    private static native void log(char type, String message, Throwable th);
+}
diff --git a/java/lang/Thread.annotated.java b/java/lang/Thread.annotated.java
new file mode 100644
index 0000000..2499518
--- /dev/null
+++ b/java/lang/Thread.annotated.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.util.Map;
+import java.util.concurrent.locks.LockSupport;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Thread implements java.lang.Runnable {
+
+public Thread() { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.Runnable target) { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.ThreadGroup group, java.lang.Runnable target) { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.ThreadGroup group, java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.Runnable target, java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.ThreadGroup group, java.lang.Runnable target, java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public Thread(java.lang.ThreadGroup group, java.lang.Runnable target, java.lang.String name, long stackSize) { throw new RuntimeException("Stub!"); }
+
+public static native java.lang.Thread currentThread();
+
+public static native void yield();
+
+public static void sleep(long millis) throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public static void sleep(long millis, int nanos) throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+protected java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
+public synchronized void start() { throw new RuntimeException("Stub!"); }
+
+public void run() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public final void stop() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public final synchronized void stop(java.lang.Throwable obj) { throw new RuntimeException("Stub!"); }
+
+public void interrupt() { throw new RuntimeException("Stub!"); }
+
+public static native boolean interrupted();
+
+public native boolean isInterrupted();
+
+@Deprecated
+public void destroy() { throw new RuntimeException("Stub!"); }
+
+public final boolean isAlive() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public final void suspend() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public final void resume() { throw new RuntimeException("Stub!"); }
+
+public final void setPriority(int newPriority) { throw new RuntimeException("Stub!"); }
+
+public final int getPriority() { throw new RuntimeException("Stub!"); }
+
+public final synchronized void setName(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.ThreadGroup getThreadGroup() { throw new RuntimeException("Stub!"); }
+
+public static int activeCount() { throw new RuntimeException("Stub!"); }
+
+public static int enumerate(java.lang.Thread[] tarray) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public int countStackFrames() { throw new RuntimeException("Stub!"); }
+
+public final void join(long millis) throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public final void join(long millis, int nanos) throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public final void join() throws java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public static void dumpStack() { throw new RuntimeException("Stub!"); }
+
+public final void setDaemon(boolean on) { throw new RuntimeException("Stub!"); }
+
+public final boolean isDaemon() { throw new RuntimeException("Stub!"); }
+
+public final void checkAccess() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public java.lang.ClassLoader getContextClassLoader() { throw new RuntimeException("Stub!"); }
+
+public void setContextClassLoader(java.lang.ClassLoader cl) { throw new RuntimeException("Stub!"); }
+
+public static native boolean holdsLock(java.lang.Object obj);
+
+public java.lang.StackTraceElement[] getStackTrace() { throw new RuntimeException("Stub!"); }
+
+public static java.util.Map<java.lang.Thread,java.lang.StackTraceElement[]> getAllStackTraces() { throw new RuntimeException("Stub!"); }
+
+public long getId() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Thread.State getState() { throw new RuntimeException("Stub!"); }
+
+public static void setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler eh) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static UncaughtExceptionHandler getUncaughtExceptionPreHandler() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() { throw new RuntimeException("Stub!"); }
+
+public void setUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler eh) { throw new RuntimeException("Stub!"); }
+
+public static final int MAX_PRIORITY = 10; // 0xa
+
+public static final int MIN_PRIORITY = 1; // 0x1
+
+public static final int NORM_PRIORITY = 5; // 0x5
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static enum State {
+NEW,
+RUNNABLE,
+BLOCKED,
+WAITING,
+TIMED_WAITING,
+TERMINATED;
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
[email protected]
+public static interface UncaughtExceptionHandler {
+
+public void uncaughtException(java.lang.Thread t, java.lang.Throwable e);
+}
+
+}
+
diff --git a/java/lang/Thread.java b/java/lang/Thread.java
new file mode 100644
index 0000000..699a1ac
--- /dev/null
+++ b/java/lang/Thread.java
@@ -0,0 +1,2353 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import dalvik.annotation.optimization.FastNative;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import java.security.PrivilegedAction;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.LockSupport;
+import sun.nio.ch.Interruptible;
+import sun.reflect.CallerSensitive;
+import dalvik.system.RuntimeHooks;
+import dalvik.system.ThreadPrioritySetter;
+import dalvik.system.VMStack;
+import libcore.util.EmptyArray;
+
+
+/**
+ * A <i>thread</i> is a thread of execution in a program. The Java
+ * Virtual Machine allows an application to have multiple threads of
+ * execution running concurrently.
+ * <p>
+ * Every thread has a priority. Threads with higher priority are
+ * executed in preference to threads with lower priority. Each thread
+ * may or may not also be marked as a daemon. When code running in
+ * some thread creates a new <code>Thread</code> object, the new
+ * thread has its priority initially set equal to the priority of the
+ * creating thread, and is a daemon thread if and only if the
+ * creating thread is a daemon.
+ * <p>
+ * When a Java Virtual Machine starts up, there is usually a single
+ * non-daemon thread (which typically calls the method named
+ * <code>main</code> of some designated class). The Java Virtual
+ * Machine continues to execute threads until either of the following
+ * occurs:
+ * <ul>
+ * <li>The <code>exit</code> method of class <code>Runtime</code> has been
+ *     called and the security manager has permitted the exit operation
+ *     to take place.
+ * <li>All threads that are not daemon threads have died, either by
+ *     returning from the call to the <code>run</code> method or by
+ *     throwing an exception that propagates beyond the <code>run</code>
+ *     method.
+ * </ul>
+ * <p>
+ * There are two ways to create a new thread of execution. One is to
+ * declare a class to be a subclass of <code>Thread</code>. This
+ * subclass should override the <code>run</code> method of class
+ * <code>Thread</code>. An instance of the subclass can then be
+ * allocated and started. For example, a thread that computes primes
+ * larger than a stated value could be written as follows:
+ * <hr><blockquote><pre>
+ *     class PrimeThread extends Thread {
+ *         long minPrime;
+ *         PrimeThread(long minPrime) {
+ *             this.minPrime = minPrime;
+ *         }
+ *
+ *         public void run() {
+ *             // compute primes larger than minPrime
+ *             &nbsp;.&nbsp;.&nbsp;.
+ *         }
+ *     }
+ * </pre></blockquote><hr>
+ * <p>
+ * The following code would then create a thread and start it running:
+ * <blockquote><pre>
+ *     PrimeThread p = new PrimeThread(143);
+ *     p.start();
+ * </pre></blockquote>
+ * <p>
+ * The other way to create a thread is to declare a class that
+ * implements the <code>Runnable</code> interface. That class then
+ * implements the <code>run</code> method. An instance of the class can
+ * then be allocated, passed as an argument when creating
+ * <code>Thread</code>, and started. The same example in this other
+ * style looks like the following:
+ * <hr><blockquote><pre>
+ *     class PrimeRun implements Runnable {
+ *         long minPrime;
+ *         PrimeRun(long minPrime) {
+ *             this.minPrime = minPrime;
+ *         }
+ *
+ *         public void run() {
+ *             // compute primes larger than minPrime
+ *             &nbsp;.&nbsp;.&nbsp;.
+ *         }
+ *     }
+ * </pre></blockquote><hr>
+ * <p>
+ * The following code would then create a thread and start it running:
+ * <blockquote><pre>
+ *     PrimeRun p = new PrimeRun(143);
+ *     new Thread(p).start();
+ * </pre></blockquote>
+ * <p>
+ * Every thread has a name for identification purposes. More than
+ * one thread may have the same name. If a name is not specified when
+ * a thread is created, a new name is generated for it.
+ * <p>
+ * Unless otherwise noted, passing a {@code null} argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * @author  unascribed
+ * @see     Runnable
+ * @see     Runtime#exit(int)
+ * @see     #run()
+ * @see     #stop()
+ * @since   JDK1.0
+ */
+public
+class Thread implements Runnable {
+    // Android-removed: registerNatives() not used on Android.
+    /*
+    /* Make sure registerNatives is the first thing <clinit> does. *
+    private static native void registerNatives();
+    static {
+        registerNatives();
+    }
+    */
+
+    // BEGIN Android-added: Android specific fields lock, nativePeer.
+    /**
+     * The synchronization object responsible for this thread's join/sleep/park operations.
+     */
+    private final Object lock = new Object();
+
+    /**
+     * Reference to the native thread object.
+     *
+     * <p>Is 0 if the native thread has not yet been created/started, or has been destroyed.
+     */
+    private volatile long nativePeer;
+    // END Android-added: Android specific fields lock, nativePeer.
+
+    private volatile String name;
+    private int            priority;
+    private Thread         threadQ;
+    private long           eetop;
+
+    /* Whether or not to single_step this thread. */
+    private boolean     single_step;
+
+    /* Whether or not the thread is a daemon thread. */
+    private boolean     daemon = false;
+
+    /* JVM state */
+    private boolean     stillborn = false;
+
+    /* What will be run. */
+    private Runnable target;
+
+    /* The group of this thread */
+    private ThreadGroup group;
+
+    /* The context ClassLoader for this thread */
+    private ClassLoader contextClassLoader;
+
+    /* The inherited AccessControlContext of this thread */
+    private AccessControlContext inheritedAccessControlContext;
+
+    /* For autonumbering anonymous threads. */
+    private static int threadInitNumber;
+    private static synchronized int nextThreadNum() {
+        return threadInitNumber++;
+    }
+
+    /* ThreadLocal values pertaining to this thread. This map is maintained
+     * by the ThreadLocal class. */
+    ThreadLocal.ThreadLocalMap threadLocals = null;
+
+    /*
+     * InheritableThreadLocal values pertaining to this thread. This map is
+     * maintained by the InheritableThreadLocal class.
+     */
+    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
+
+    /*
+     * The requested stack size for this thread, or 0 if the creator did
+     * not specify a stack size.  It is up to the VM to do whatever it
+     * likes with this number; some VMs will ignore it.
+     */
+    private long stackSize;
+
+    // BEGIN Android-changed: Keep track of whether this thread was unparked while not alive.
+    /*
+    /*
+     * JVM-private state that persists after native thread termination.
+     *
+    private long nativeParkEventPointer;
+    */
+    /**
+     * Indicates whether this thread was unpark()ed while not alive, in which case start()ing
+     * it should leave it in unparked state. This field is read and written by native code in
+     * the runtime, guarded by thread_list_lock. See http://b/28845097#comment49
+     */
+    private boolean unparkedBeforeStart;
+    // END Android-changed: Keep track of whether this thread was unparked while not alive.
+
+    /*
+     * Thread ID
+     */
+    private long tid;
+
+    /* For generating thread ID */
+    private static long threadSeqNumber;
+
+
+    // Android-added: The concept of "system-daemon" threads. See java.lang.Daemons.
+    /** True if this thread is managed by {@link Daemons}. */
+    private boolean systemDaemon = false;
+
+    /* Java thread status for tools,
+     * initialized to indicate thread 'not yet started'
+     */
+
+    // BEGIN Android-changed: Replace unused threadStatus field with started field.
+    // Upstream this is modified by the native code and read in the start() and getState() methods
+    // but in Android it is unused. The threadStatus is essentially an internal representation of
+    // the Thread.State enum. Android uses two sources for that information, the native thread
+    // state and the started field. The reason two sources are needed is because the native thread
+    // is created when the thread is started and destroyed when the thread is stopped. That means
+    // that the native thread state does not exist before the Thread has started (in State.NEW) or
+    // after it has been stopped (in State.TERMINATED). In that case (i.e. when the nativePeer = 0)
+    // the started field differentiates between the two states, i.e. if started = false then the
+    // thread is in State.NEW and if started = true then the thread is in State.TERMINATED.
+    // private volatile int threadStatus = 0;
+    /**
+     * True if the the Thread has been started, even it has since been stopped.
+     */
+    boolean started = false;
+    // END Android-changed: Replace unused threadStatus field with started field.
+
+
+    private static synchronized long nextThreadID() {
+        return ++threadSeqNumber;
+    }
+
+    /**
+     * The argument supplied to the current call to
+     * java.util.concurrent.locks.LockSupport.park.
+     * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
+     * Accessed using java.util.concurrent.locks.LockSupport.getBlocker
+     */
+    volatile Object parkBlocker;
+
+    /* The object in which this thread is blocked in an interruptible I/O
+     * operation, if any.  The blocker's interrupt method should be invoked
+     * after setting this thread's interrupt status.
+     */
+    private volatile Interruptible blocker;
+    private final Object blockerLock = new Object();
+
+    // Android-changed: Make blockedOn() @hide public, for internal use.
+    // Changed comment to reflect usage on Android
+    /* Set the blocker field; used by java.nio.channels.spi.AbstractInterruptibleChannel
+     */
+    /** @hide */
+    public void blockedOn(Interruptible b) {
+        synchronized (blockerLock) {
+            blocker = b;
+        }
+    }
+
+    /**
+     * The minimum priority that a thread can have.
+     */
+    public final static int MIN_PRIORITY = 1;
+
+   /**
+     * The default priority that is assigned to a thread.
+     */
+    public final static int NORM_PRIORITY = 5;
+
+    /**
+     * The maximum priority that a thread can have.
+     */
+    public final static int MAX_PRIORITY = 10;
+
+    /**
+     * Returns a reference to the currently executing thread object.
+     *
+     * @return  the currently executing thread.
+     */
+    @FastNative
+    public static native Thread currentThread();
+
+    /**
+     * A hint to the scheduler that the current thread is willing to yield
+     * its current use of a processor. The scheduler is free to ignore this
+     * hint.
+     *
+     * <p> Yield is a heuristic attempt to improve relative progression
+     * between threads that would otherwise over-utilise a CPU. Its use
+     * should be combined with detailed profiling and benchmarking to
+     * ensure that it actually has the desired effect.
+     *
+     * <p> It is rarely appropriate to use this method. It may be useful
+     * for debugging or testing purposes, where it may help to reproduce
+     * bugs due to race conditions. It may also be useful when designing
+     * concurrency control constructs such as the ones in the
+     * {@link java.util.concurrent.locks} package.
+     */
+    public static native void yield();
+
+    /**
+     * Causes the currently executing thread to sleep (temporarily cease
+     * execution) for the specified number of milliseconds, subject to
+     * the precision and accuracy of system timers and schedulers. The thread
+     * does not lose ownership of any monitors.
+     *
+     * @param  millis
+     *         the length of time to sleep in milliseconds
+     *
+     * @throws  IllegalArgumentException
+     *          if the value of {@code millis} is negative
+     *
+     * @throws  InterruptedException
+     *          if any thread has interrupted the current thread. The
+     *          <i>interrupted status</i> of the current thread is
+     *          cleared when this exception is thrown.
+     */
+    // BEGIN Android-changed: Implement sleep() methods using a shared native implementation.
+    public static void sleep(long millis) throws InterruptedException {
+        sleep(millis, 0);
+    }
+
+    @FastNative
+    private static native void sleep(Object lock, long millis, int nanos)
+        throws InterruptedException;
+    // END Android-changed: Implement sleep() methods using a shared native implementation.
+
+    /**
+     * Causes the currently executing thread to sleep (temporarily cease
+     * execution) for the specified number of milliseconds plus the specified
+     * number of nanoseconds, subject to the precision and accuracy of system
+     * timers and schedulers. The thread does not lose ownership of any
+     * monitors.
+     *
+     * @param  millis
+     *         the length of time to sleep in milliseconds
+     *
+     * @param  nanos
+     *         {@code 0-999999} additional nanoseconds to sleep
+     *
+     * @throws  IllegalArgumentException
+     *          if the value of {@code millis} is negative, or the value of
+     *          {@code nanos} is not in the range {@code 0-999999}
+     *
+     * @throws  InterruptedException
+     *          if any thread has interrupted the current thread. The
+     *          <i>interrupted status</i> of the current thread is
+     *          cleared when this exception is thrown.
+     */
+    public static void sleep(long millis, int nanos)
+    throws InterruptedException {
+        // BEGIN Android-changed: Improve exception messages.
+        /*
+        if (millis < 0) {
+            throw new IllegalArgumentException("timeout value is negative");
+        }
+
+        if (nanos < 0 || nanos > 999999) {
+            throw new IllegalArgumentException(
+                                "nanosecond timeout value out of range");
+        }
+        */
+        if (millis < 0) {
+            throw new IllegalArgumentException("millis < 0: " + millis);
+        }
+        if (nanos < 0) {
+            throw new IllegalArgumentException("nanos < 0: " + nanos);
+        }
+        if (nanos > 999999) {
+            throw new IllegalArgumentException("nanos > 999999: " + nanos);
+        }
+        // END Android-changed: Improve exception messages.
+
+        // BEGIN Android-changed: Implement sleep() methods using a shared native implementation.
+        // Attempt nanosecond rather than millisecond accuracy for sleep();
+        // RI code rounds to the nearest millisecond.
+        /*
+        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
+            millis++;
+        }
+
+        sleep(millis);
+        */
+        // The JLS 3rd edition, section 17.9 says: "...sleep for zero
+        // time...need not have observable effects."
+        if (millis == 0 && nanos == 0) {
+            // ...but we still have to handle being interrupted.
+            if (Thread.interrupted()) {
+              throw new InterruptedException();
+            }
+            return;
+        }
+
+        final int nanosPerMilli = 1000000;
+        long start = System.nanoTime();
+        long duration = (millis * nanosPerMilli) + nanos;
+
+        Object lock = currentThread().lock;
+
+        // The native sleep(...) method actually performs a special type of wait, which may return
+        // early, so loop until sleep duration passes.
+        synchronized (lock) {
+            while (true) {
+                sleep(lock, millis, nanos);
+
+                long now = System.nanoTime();
+                long elapsed = now - start;
+
+                if (elapsed >= duration) {
+                    break;
+                }
+
+                duration -= elapsed;
+                start = now;
+                millis = duration / nanosPerMilli;
+                nanos = (int) (duration % nanosPerMilli);
+            }
+        }
+        // END Android-changed: Implement sleep() methods using a shared native implementation.
+    }
+
+    /**
+     * Initializes a Thread with the current AccessControlContext.
+     * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext)
+     */
+    private void init(ThreadGroup g, Runnable target, String name,
+                      long stackSize) {
+        init(g, target, name, stackSize, null);
+    }
+
+    /**
+     * Initializes a Thread.
+     *
+     * @param g the Thread group
+     * @param target the object whose run() method gets called
+     * @param name the name of the new Thread
+     * @param stackSize the desired stack size for the new thread, or
+     *        zero to indicate that this parameter is to be ignored.
+     * @param acc the AccessControlContext to inherit, or
+     *            AccessController.getContext() if null
+     */
+    private void init(ThreadGroup g, Runnable target, String name,
+                      long stackSize, AccessControlContext acc) {
+        if (name == null) {
+            throw new NullPointerException("name cannot be null");
+        }
+
+        this.name = name;
+
+        Thread parent = currentThread();
+        // Android-removed: SecurityManager stubbed out on Android
+        // SecurityManager security = System.getSecurityManager();
+        if (g == null) {
+            // Android-changed: SecurityManager stubbed out on Android
+            /*
+            /* Determine if it's an applet or not *
+
+            /* If there is a security manager, ask the security manager
+               what to do. *
+            if (security != null) {
+                g = security.getThreadGroup();
+            }
+
+            /* If the security doesn't have a strong opinion of the matter
+               use the parent thread group. *
+            if (g == null) {
+            */
+                g = parent.getThreadGroup();
+            // }
+        }
+
+        // Android-removed: SecurityManager stubbed out on Android
+        /*
+        /* checkAccess regardless of whether or not threadgroup is
+           explicitly passed in. *
+        g.checkAccess();
+
+        /*
+         * Do we have the required permissions?
+         *
+        if (security != null) {
+            if (isCCLOverridden(getClass())) {
+                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
+            }
+        }
+        */
+
+        g.addUnstarted();
+
+        this.group = g;
+        this.daemon = parent.isDaemon();
+        this.priority = parent.getPriority();
+        // Android-changed: Moved into init2(Thread) helper method.
+        /*
+        if (security == null || isCCLOverridden(parent.getClass()))
+            this.contextClassLoader = parent.getContextClassLoader();
+        else
+            this.contextClassLoader = parent.contextClassLoader;
+        this.inheritedAccessControlContext =
+                acc != null ? acc : AccessController.getContext();
+        */
+        this.target = target;
+        // Android-removed: The priority parameter is unchecked on Android.
+        // It is unclear why this is not being done (b/80180276).
+        // setPriority(priority);
+        // Android-changed: Moved into init2(Thread) helper method.
+        // if (parent.inheritableThreadLocals != null)
+        //     this.inheritableThreadLocals =
+        //         ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
+        init2(parent);
+
+        /* Stash the specified stack size in case the VM cares */
+        this.stackSize = stackSize;
+
+        /* Set thread ID */
+        tid = nextThreadID();
+    }
+
+    /**
+     * Throws CloneNotSupportedException as a Thread can not be meaningfully
+     * cloned. Construct a new Thread instead.
+     *
+     * @throws  CloneNotSupportedException
+     *          always
+     */
+    @Override
+    protected Object clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    /**
+     * Allocates a new {@code Thread} object. This constructor has the same
+     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+     * {@code (null, null, gname)}, where {@code gname} is a newly generated
+     * name. Automatically generated names are of the form
+     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
+     */
+    public Thread() {
+        init(null, null, "Thread-" + nextThreadNum(), 0);
+    }
+
+    /**
+     * Allocates a new {@code Thread} object. This constructor has the same
+     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+     * {@code (null, target, gname)}, where {@code gname} is a newly generated
+     * name. Automatically generated names are of the form
+     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
+     *
+     * @param  target
+     *         the object whose {@code run} method is invoked when this thread
+     *         is started. If {@code null}, this classes {@code run} method does
+     *         nothing.
+     */
+    public Thread(Runnable target) {
+        init(null, target, "Thread-" + nextThreadNum(), 0);
+    }
+
+    /**
+     * Creates a new Thread that inherits the given AccessControlContext.
+     * This is not a public constructor.
+     */
+    Thread(Runnable target, AccessControlContext acc) {
+        init(null, target, "Thread-" + nextThreadNum(), 0, acc);
+    }
+
+    /**
+     * Allocates a new {@code Thread} object. This constructor has the same
+     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+     * {@code (group, target, gname)} ,where {@code gname} is a newly generated
+     * name. Automatically generated names are of the form
+     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
+     *
+     * @param  group
+     *         the thread group. If {@code null} and there is a security
+     *         manager, the group is determined by {@linkplain
+     *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+     *         If there is not a security manager or {@code
+     *         SecurityManager.getThreadGroup()} returns {@code null}, the group
+     *         is set to the current thread's thread group.
+     *
+     * @param  target
+     *         the object whose {@code run} method is invoked when this thread
+     *         is started. If {@code null}, this thread's run method is invoked.
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot create a thread in the specified
+     *          thread group
+     */
+    public Thread(ThreadGroup group, Runnable target) {
+        init(group, target, "Thread-" + nextThreadNum(), 0);
+    }
+
+    /**
+     * Allocates a new {@code Thread} object. This constructor has the same
+     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+     * {@code (null, null, name)}.
+     *
+     * @param   name
+     *          the name of the new thread
+     */
+    public Thread(String name) {
+        init(null, null, name, 0);
+    }
+
+    /**
+     * Allocates a new {@code Thread} object. This constructor has the same
+     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+     * {@code (group, null, name)}.
+     *
+     * @param  group
+     *         the thread group. If {@code null} and there is a security
+     *         manager, the group is determined by {@linkplain
+     *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+     *         If there is not a security manager or {@code
+     *         SecurityManager.getThreadGroup()} returns {@code null}, the group
+     *         is set to the current thread's thread group.
+     *
+     * @param  name
+     *         the name of the new thread
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot create a thread in the specified
+     *          thread group
+     */
+    public Thread(ThreadGroup group, String name) {
+        init(group, null, name, 0);
+    }
+
+    // BEGIN Android-added: Private constructor - used by the runtime.
+    /** @hide */
+    Thread(ThreadGroup group, String name, int priority, boolean daemon) {
+        this.group = group;
+        this.group.addUnstarted();
+        // Must be tolerant of threads without a name.
+        if (name == null) {
+            name = "Thread-" + nextThreadNum();
+        }
+
+        // NOTE: Resist the temptation to call setName() here. This constructor is only called
+        // by the runtime to construct peers for threads that have attached via JNI and it's
+        // undesirable to clobber their natively set name.
+        this.name = name;
+
+        this.priority = priority;
+        this.daemon = daemon;
+        init2(currentThread());
+        tid = nextThreadID();
+    }
+
+    // Android-added: Helper method for previous constructor and init(...) method.
+    private void init2(Thread parent) {
+        this.contextClassLoader = parent.getContextClassLoader();
+        this.inheritedAccessControlContext = AccessController.getContext();
+        if (parent.inheritableThreadLocals != null) {
+            this.inheritableThreadLocals = ThreadLocal.createInheritedMap(
+                    parent.inheritableThreadLocals);
+        }
+    }
+    // END Android-added: Private constructor - used by the runtime.
+
+
+    /**
+     * Allocates a new {@code Thread} object. This constructor has the same
+     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
+     * {@code (null, target, name)}.
+     *
+     * @param  target
+     *         the object whose {@code run} method is invoked when this thread
+     *         is started. If {@code null}, this thread's run method is invoked.
+     *
+     * @param  name
+     *         the name of the new thread
+     */
+    public Thread(Runnable target, String name) {
+        init(null, target, name, 0);
+    }
+
+    /**
+     * Allocates a new {@code Thread} object so that it has {@code target}
+     * as its run object, has the specified {@code name} as its name,
+     * and belongs to the thread group referred to by {@code group}.
+     *
+     * <p>If there is a security manager, its
+     * {@link SecurityManager#checkAccess(ThreadGroup) checkAccess}
+     * method is invoked with the ThreadGroup as its argument.
+     *
+     * <p>In addition, its {@code checkPermission} method is invoked with
+     * the {@code RuntimePermission("enableContextClassLoaderOverride")}
+     * permission when invoked directly or indirectly by the constructor
+     * of a subclass which overrides the {@code getContextClassLoader}
+     * or {@code setContextClassLoader} methods.
+     *
+     * <p>The priority of the newly created thread is set equal to the
+     * priority of the thread creating it, that is, the currently running
+     * thread. The method {@linkplain #setPriority setPriority} may be
+     * used to change the priority to a new value.
+     *
+     * <p>The newly created thread is initially marked as being a daemon
+     * thread if and only if the thread creating it is currently marked
+     * as a daemon thread. The method {@linkplain #setDaemon setDaemon}
+     * may be used to change whether or not a thread is a daemon.
+     *
+     * @param  group
+     *         the thread group. If {@code null} and there is a security
+     *         manager, the group is determined by {@linkplain
+     *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+     *         If there is not a security manager or {@code
+     *         SecurityManager.getThreadGroup()} returns {@code null}, the group
+     *         is set to the current thread's thread group.
+     *
+     * @param  target
+     *         the object whose {@code run} method is invoked when this thread
+     *         is started. If {@code null}, this thread's run method is invoked.
+     *
+     * @param  name
+     *         the name of the new thread
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot create a thread in the specified
+     *          thread group or cannot override the context class loader methods.
+     */
+    public Thread(ThreadGroup group, Runnable target, String name) {
+        init(group, target, name, 0);
+    }
+
+    /**
+     * Allocates a new {@code Thread} object so that it has {@code target}
+     * as its run object, has the specified {@code name} as its name,
+     * and belongs to the thread group referred to by {@code group}, and has
+     * the specified <i>stack size</i>.
+     *
+     * <p>This constructor is identical to {@link
+     * #Thread(ThreadGroup,Runnable,String)} with the exception of the fact
+     * that it allows the thread stack size to be specified.  The stack size
+     * is the approximate number of bytes of address space that the virtual
+     * machine is to allocate for this thread's stack.  <b>The effect of the
+     * {@code stackSize} parameter, if any, is highly platform dependent.</b>
+     *
+     * <p>On some platforms, specifying a higher value for the
+     * {@code stackSize} parameter may allow a thread to achieve greater
+     * recursion depth before throwing a {@link StackOverflowError}.
+     * Similarly, specifying a lower value may allow a greater number of
+     * threads to exist concurrently without throwing an {@link
+     * OutOfMemoryError} (or other internal error).  The details of
+     * the relationship between the value of the <tt>stackSize</tt> parameter
+     * and the maximum recursion depth and concurrency level are
+     * platform-dependent.  <b>On some platforms, the value of the
+     * {@code stackSize} parameter may have no effect whatsoever.</b>
+     *
+     * <p>The virtual machine is free to treat the {@code stackSize}
+     * parameter as a suggestion.  If the specified value is unreasonably low
+     * for the platform, the virtual machine may instead use some
+     * platform-specific minimum value; if the specified value is unreasonably
+     * high, the virtual machine may instead use some platform-specific
+     * maximum.  Likewise, the virtual machine is free to round the specified
+     * value up or down as it sees fit (or to ignore it completely).
+     *
+     * <p>Specifying a value of zero for the {@code stackSize} parameter will
+     * cause this constructor to behave exactly like the
+     * {@code Thread(ThreadGroup, Runnable, String)} constructor.
+     *
+     * <p><i>Due to the platform-dependent nature of the behavior of this
+     * constructor, extreme care should be exercised in its use.
+     * The thread stack size necessary to perform a given computation will
+     * likely vary from one JRE implementation to another.  In light of this
+     * variation, careful tuning of the stack size parameter may be required,
+     * and the tuning may need to be repeated for each JRE implementation on
+     * which an application is to run.</i>
+     *
+     * <p>Implementation note: Java platform implementers are encouraged to
+     * document their implementation's behavior with respect to the
+     * {@code stackSize} parameter.
+     *
+     *
+     * @param  group
+     *         the thread group. If {@code null} and there is a security
+     *         manager, the group is determined by {@linkplain
+     *         SecurityManager#getThreadGroup SecurityManager.getThreadGroup()}.
+     *         If there is not a security manager or {@code
+     *         SecurityManager.getThreadGroup()} returns {@code null}, the group
+     *         is set to the current thread's thread group.
+     *
+     * @param  target
+     *         the object whose {@code run} method is invoked when this thread
+     *         is started. If {@code null}, this thread's run method is invoked.
+     *
+     * @param  name
+     *         the name of the new thread
+     *
+     * @param  stackSize
+     *         the desired stack size for the new thread, or zero to indicate
+     *         that this parameter is to be ignored.
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot create a thread in the specified
+     *          thread group
+     *
+     * @since 1.4
+     */
+    public Thread(ThreadGroup group, Runnable target, String name,
+                  long stackSize) {
+        init(group, target, name, stackSize);
+    }
+
+    /**
+     * Causes this thread to begin execution; the Java Virtual Machine
+     * calls the <code>run</code> method of this thread.
+     * <p>
+     * The result is that two threads are running concurrently: the
+     * current thread (which returns from the call to the
+     * <code>start</code> method) and the other thread (which executes its
+     * <code>run</code> method).
+     * <p>
+     * It is never legal to start a thread more than once.
+     * In particular, a thread may not be restarted once it has completed
+     * execution.
+     *
+     * @exception  IllegalThreadStateException  if the thread was already
+     *               started.
+     * @see        #run()
+     * @see        #stop()
+     */
+    public synchronized void start() {
+        /**
+         * This method is not invoked for the main method thread or "system"
+         * group threads created/set up by the VM. Any new functionality added
+         * to this method in the future may have to also be added to the VM.
+         *
+         * A zero status value corresponds to state "NEW".
+         */
+        // Android-changed: Replace unused threadStatus field with started field.
+        // The threadStatus field is unused on Android.
+        if (started)
+            throw new IllegalThreadStateException();
+
+        /* Notify the group that this thread is about to be started
+         * so that it can be added to the group's list of threads
+         * and the group's unstarted count can be decremented. */
+        group.add(this);
+
+        // Android-changed: Use field instead of local variable.
+        // It is necessary to remember the state of this across calls to this method so that it
+        // can throw an IllegalThreadStateException if this method is called on an already
+        // started thread.
+        started = false;
+        try {
+            // Android-changed: Use Android specific nativeCreate() method to create/start thread.
+            // start0();
+            nativeCreate(this, stackSize, daemon);
+            started = true;
+        } finally {
+            try {
+                if (!started) {
+                    group.threadStartFailed(this);
+                }
+            } catch (Throwable ignore) {
+                /* do nothing. If start0 threw a Throwable then
+                  it will be passed up the call stack */
+            }
+        }
+    }
+
+    // Android-changed: Use Android specific nativeCreate() method to create/start thread.
+    // The upstream native method start0() only takes a reference to this object and so must obtain
+    // the stack size and daemon status directly from the field whereas Android supplies the values
+    // explicitly on the method call.
+    // private native void start0();
+    private native static void nativeCreate(Thread t, long stackSize, boolean daemon);
+
+    /**
+     * If this thread was constructed using a separate
+     * <code>Runnable</code> run object, then that
+     * <code>Runnable</code> object's <code>run</code> method is called;
+     * otherwise, this method does nothing and returns.
+     * <p>
+     * Subclasses of <code>Thread</code> should override this method.
+     *
+     * @see     #start()
+     * @see     #stop()
+     * @see     #Thread(ThreadGroup, Runnable, String)
+     */
+    @Override
+    public void run() {
+        if (target != null) {
+            target.run();
+        }
+    }
+
+    /**
+     * This method is called by the system to give a Thread
+     * a chance to clean up before it actually exits.
+     */
+    private void exit() {
+        if (group != null) {
+            group.threadTerminated(this);
+            group = null;
+        }
+        /* Aggressively null out all reference fields: see bug 4006245 */
+        target = null;
+        /* Speed the release of some of these resources */
+        threadLocals = null;
+        inheritableThreadLocals = null;
+        inheritedAccessControlContext = null;
+        blocker = null;
+        uncaughtExceptionHandler = null;
+    }
+
+    // Android-changed: Throws UnsupportedOperationException.
+    /**
+     * Throws {@code UnsupportedOperationException}.
+     *
+     * @deprecated This method was originally designed to force a thread to stop
+     *       and throw a {@code ThreadDeath} as an exception. It was inherently unsafe.
+     *       Stopping a thread with
+     *       Thread.stop causes it to unlock all of the monitors that it
+     *       has locked (as a natural consequence of the unchecked
+     *       <code>ThreadDeath</code> exception propagating up the stack).  If
+     *       any of the objects previously protected by these monitors were in
+     *       an inconsistent state, the damaged objects become visible to
+     *       other threads, potentially resulting in arbitrary behavior.  Many
+     *       uses of <code>stop</code> should be replaced by code that simply
+     *       modifies some variable to indicate that the target thread should
+     *       stop running.  The target thread should check this variable
+     *       regularly, and return from its run method in an orderly fashion
+     *       if the variable indicates that it is to stop running.  If the
+     *       target thread waits for long periods (on a condition variable,
+     *       for example), the <code>interrupt</code> method should be used to
+     *       interrupt the wait.
+     *       For more information, see
+     *       <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *       are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
+     */
+    @Deprecated
+    public final void stop() {
+        /*
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            checkAccess();
+            if (this != Thread.currentThread()) {
+                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
+            }
+        }
+        // A zero status value corresponds to "NEW", it can't change to
+        // not-NEW because we hold the lock.
+        if (threadStatus != 0) {
+            resume(); // Wake up thread if it was suspended; no-op otherwise
+        }
+
+        // The VM can handle all thread states
+        stop0(new ThreadDeath());
+        */
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.
+     *
+     * @param obj ignored
+     *
+     * @deprecated This method was originally designed to force a thread to stop
+     *        and throw a given {@code Throwable} as an exception. It was
+     *        inherently unsafe (see {@link #stop()} for details), and furthermore
+     *        could be used to generate exceptions that the target thread was
+     *        not prepared to handle.
+     *        For more information, see
+     *        <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *        are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
+     */
+    @Deprecated
+    public final synchronized void stop(Throwable obj) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Interrupts this thread.
+     *
+     * <p> Unless the current thread is interrupting itself, which is
+     * always permitted, the {@link #checkAccess() checkAccess} method
+     * of this thread is invoked, which may cause a {@link
+     * SecurityException} to be thrown.
+     *
+     * <p> If this thread is blocked in an invocation of the {@link
+     * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
+     * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
+     * class, or of the {@link #join()}, {@link #join(long)}, {@link
+     * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
+     * methods of this class, then its interrupt status will be cleared and it
+     * will receive an {@link InterruptedException}.
+     *
+     * <p> If this thread is blocked in an I/O operation upon an {@link
+     * java.nio.channels.InterruptibleChannel InterruptibleChannel}
+     * then the channel will be closed, the thread's interrupt
+     * status will be set, and the thread will receive a {@link
+     * java.nio.channels.ClosedByInterruptException}.
+     *
+     * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
+     * then the thread's interrupt status will be set and it will return
+     * immediately from the selection operation, possibly with a non-zero
+     * value, just as if the selector's {@link
+     * java.nio.channels.Selector#wakeup wakeup} method were invoked.
+     *
+     * <p> If none of the previous conditions hold then this thread's interrupt
+     * status will be set. </p>
+     *
+     * <p> Interrupting a thread that is not alive need not have any effect.
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot modify this thread
+     *
+     * @revised 6.0
+     * @spec JSR-51
+     */
+    public void interrupt() {
+        if (this != Thread.currentThread())
+            checkAccess();
+
+        synchronized (blockerLock) {
+            Interruptible b = blocker;
+            if (b != null) {
+                interrupt0();           // Just to set the interrupt flag
+                b.interrupt(this);
+                return;
+            }
+        }
+        interrupt0();
+    }
+
+    /**
+     * Tests whether the current thread has been interrupted.  The
+     * <i>interrupted status</i> of the thread is cleared by this method.  In
+     * other words, if this method were to be called twice in succession, the
+     * second call would return false (unless the current thread were
+     * interrupted again, after the first call had cleared its interrupted
+     * status and before the second call had examined it).
+     *
+     * <p>A thread interruption ignored because a thread was not alive
+     * at the time of the interrupt will be reflected by this method
+     * returning false.
+     *
+     * @return  <code>true</code> if the current thread has been interrupted;
+     *          <code>false</code> otherwise.
+     * @see #isInterrupted()
+     * @revised 6.0
+     */
+    // Android-changed: Use native interrupted()/isInterrupted() methods.
+    // Upstream has one native method for both these methods that takes a boolean parameter that
+    // determines whether the interrupted status of the thread should be cleared after reading
+    // it. While that approach does allow code reuse it is less efficient/more complex than having
+    // a native implementation of each method because:
+    // * The pure Java interrupted() method requires two native calls, one to get the current
+    //   thread and one to get its interrupted status.
+    // * Updating the interrupted flag is more complex than simply reading it. Knowing that only
+    //   the current thread can clear the interrupted status makes the code simpler as it does not
+    //   need to be concerned about multiple threads trying to clear the status simultaneously.
+    // public static boolean interrupted() {
+    //     return currentThread().isInterrupted(true);
+    // }
+    @FastNative
+    public static native boolean interrupted();
+
+    /**
+     * Tests whether this thread has been interrupted.  The <i>interrupted
+     * status</i> of the thread is unaffected by this method.
+     *
+     * <p>A thread interruption ignored because a thread was not alive
+     * at the time of the interrupt will be reflected by this method
+     * returning false.
+     *
+     * @return  <code>true</code> if this thread has been interrupted;
+     *          <code>false</code> otherwise.
+     * @see     #interrupted()
+     * @revised 6.0
+     */
+    // Android-changed: Use native interrupted()/isInterrupted() methods.
+    // public boolean isInterrupted() {
+    //     return isInterrupted(false);
+    // }
+    @FastNative
+    public native boolean isInterrupted();
+
+    // Android-removed: Use native interrupted()/isInterrupted() methods.
+    /*
+    /**
+     * Tests if some Thread has been interrupted.  The interrupted state
+     * is reset or not based on the value of ClearInterrupted that is
+     * passed.
+     *
+    private native boolean isInterrupted(boolean ClearInterrupted);
+    */
+
+    // BEGIN Android-changed: Throw UnsupportedOperationException instead of NoSuchMethodError.
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @deprecated This method was originally designed to destroy this
+     *     thread without any cleanup. Any monitors it held would have
+     *     remained locked. However, the method was never implemented.
+     *     If if were to be implemented, it would be deadlock-prone in
+     *     much the manner of {@link #suspend}. If the target thread held
+     *     a lock protecting a critical system resource when it was
+     *     destroyed, no thread could ever access this resource again.
+     *     If another thread ever attempted to lock this resource, deadlock
+     *     would result. Such deadlocks typically manifest themselves as
+     *     "frozen" processes. For more information, see
+     *     <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
+     *     Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
+     * @throws UnsupportedOperationException always
+     */
+    @Deprecated
+    public void destroy() {
+        throw new UnsupportedOperationException();
+    }
+    // END Android-changed: Throw UnsupportedOperationException instead of NoSuchMethodError.
+
+    /**
+     * Tests if this thread is alive. A thread is alive if it has
+     * been started and has not yet died.
+     *
+     * @return  <code>true</code> if this thread is alive;
+     *          <code>false</code> otherwise.
+     */
+    // Android-changed: Provide pure Java implementation of isAlive().
+    public final boolean isAlive() {
+        return nativePeer != 0;
+    }
+
+    // Android-changed: Updated JavaDoc as it always throws an UnsupportedOperationException.
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @deprecated   This method was designed to suspend the Thread but it was
+     *   inherently deadlock-prone.  If the target thread holds a lock on the
+     *   monitor protecting a critical system resource when it is suspended, no
+     *   thread can access this resource until the target thread is resumed. If
+     *   the thread that would resume the target thread attempts to lock this
+     *   monitor prior to calling <code>resume</code>, deadlock results.  Such
+     *   deadlocks typically manifest themselves as "frozen" processes.
+     *   For more information, see
+     *   <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *   are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
+     * @throws UnsupportedOperationException always
+     */
+    @Deprecated
+    public final void suspend() {
+        // Android-changed: Unsupported on Android.
+        // checkAccess();
+        // suspend0();
+
+        throw new UnsupportedOperationException();
+    }
+
+    // Android-changed: Updated JavaDoc as it always throws an UnsupportedOperationException.
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @deprecated This method exists solely for use with {@link #suspend},
+     *     which has been deprecated because it is deadlock-prone.
+     *     For more information, see
+     *     <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
+     *     are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
+     * @throws UnsupportedOperationException always
+     */
+    @Deprecated
+    public final void resume() {
+        // Android-changed: Unsupported on Android.
+        // checkAccess();
+        // resume0();
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Changes the priority of this thread.
+     * <p>
+     * First the <code>checkAccess</code> method of this thread is called
+     * with no arguments. This may result in throwing a
+     * <code>SecurityException</code>.
+     * <p>
+     * Otherwise, the priority of this thread is set to the smaller of
+     * the specified <code>newPriority</code> and the maximum permitted
+     * priority of the thread's thread group.
+     *
+     * @param newPriority priority to set this thread to
+     * @exception  IllegalArgumentException  If the priority is not in the
+     *               range <code>MIN_PRIORITY</code> to
+     *               <code>MAX_PRIORITY</code>.
+     * @exception  SecurityException  if the current thread cannot modify
+     *               this thread.
+     * @see        #getPriority
+     * @see        #checkAccess()
+     * @see        #getThreadGroup()
+     * @see        #MAX_PRIORITY
+     * @see        #MIN_PRIORITY
+     * @see        ThreadGroup#getMaxPriority()
+     */
+    public final void setPriority(int newPriority) {
+        ThreadGroup g;
+        checkAccess();
+        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
+            // Android-changed: Improve exception message when the new priority is out of bounds.
+            throw new IllegalArgumentException("Priority out of range: " + newPriority);
+        }
+        if((g = getThreadGroup()) != null) {
+            if (newPriority > g.getMaxPriority()) {
+                newPriority = g.getMaxPriority();
+            }
+            // Android-changed: Avoid native call if Thread is not yet started.
+            // setPriority0(priority = newPriority);
+            synchronized(this) {
+                this.priority = newPriority;
+                if (isAlive()) {
+                    // BEGIN Android-added: Customize behavior of Thread.setPriority().
+                    // http://b/139521784
+                    // setPriority0(newPriority);
+                    ThreadPrioritySetter threadPrioritySetter =
+                        RuntimeHooks.getThreadPrioritySetter();
+                    int nativeTid = this.getNativeTid();
+                    if (threadPrioritySetter != null && nativeTid != 0) {
+                        threadPrioritySetter.setPriority(nativeTid, newPriority);
+                    } else {
+                        setPriority0(newPriority);
+                    }
+                    // END Android-added: Customize behavior of Thread.setPriority().
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns this thread's priority.
+     *
+     * @return  this thread's priority.
+     * @see     #setPriority
+     */
+    public final int getPriority() {
+        return priority;
+    }
+
+    /**
+     * Changes the name of this thread to be equal to the argument
+     * <code>name</code>.
+     * <p>
+     * First the <code>checkAccess</code> method of this thread is called
+     * with no arguments. This may result in throwing a
+     * <code>SecurityException</code>.
+     *
+     * @param      name   the new name for this thread.
+     * @exception  SecurityException  if the current thread cannot modify this
+     *               thread.
+     * @see        #getName
+     * @see        #checkAccess()
+     */
+    public final synchronized void setName(String name) {
+        checkAccess();
+        if (name == null) {
+            throw new NullPointerException("name cannot be null");
+        }
+
+        this.name = name;
+        // Android-changed: Use isAlive() not threadStatus to check whether Thread has started.
+        // The threadStatus field is not used in Android.
+        // if (threadStatus != 0) {
+        if (isAlive()) {
+            setNativeName(name);
+        }
+    }
+
+    /**
+     * Returns this thread's name.
+     *
+     * @return  this thread's name.
+     * @see     #setName(String)
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the thread group to which this thread belongs.
+     * This method returns null if this thread has died
+     * (been stopped).
+     *
+     * @return  this thread's thread group.
+     */
+    public final ThreadGroup getThreadGroup() {
+        // BEGIN Android-added: Work around exit() not being called.
+        // Android runtime does not call exit() when a Thread exits so the group field is not
+        // set to null so it needs to pretend as if it did. If we are not going to call exit()
+        // then this should probably just check isAlive() here rather than getState() as the
+        // latter requires a native call.
+        if (getState() == Thread.State.TERMINATED) {
+            return null;
+        }
+        // END Android-added: Work around exit() not being called.
+        return group;
+    }
+
+    /**
+     * Returns an estimate of the number of active threads in the current
+     * thread's {@linkplain java.lang.ThreadGroup thread group} and its
+     * subgroups. Recursively iterates over all subgroups in the current
+     * thread's thread group.
+     *
+     * <p> The value returned is only an estimate because the number of
+     * threads may change dynamically while this method traverses internal
+     * data structures, and might be affected by the presence of certain
+     * system threads. This method is intended primarily for debugging
+     * and monitoring purposes.
+     *
+     * @return  an estimate of the number of active threads in the current
+     *          thread's thread group and in any other thread group that
+     *          has the current thread's thread group as an ancestor
+     */
+    public static int activeCount() {
+        return currentThread().getThreadGroup().activeCount();
+    }
+
+    /**
+     * Copies into the specified array every active thread in the current
+     * thread's thread group and its subgroups. This method simply
+     * invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
+     * method of the current thread's thread group.
+     *
+     * <p> An application might use the {@linkplain #activeCount activeCount}
+     * method to get an estimate of how big the array should be, however
+     * <i>if the array is too short to hold all the threads, the extra threads
+     * are silently ignored.</i>  If it is critical to obtain every active
+     * thread in the current thread's thread group and its subgroups, the
+     * invoker should verify that the returned int value is strictly less
+     * than the length of {@code tarray}.
+     *
+     * <p> Due to the inherent race condition in this method, it is recommended
+     * that the method only be used for debugging and monitoring purposes.
+     *
+     * @param  tarray
+     *         an array into which to put the list of threads
+     *
+     * @return  the number of threads put into the array
+     *
+     * @throws  SecurityException
+     *          if {@link java.lang.ThreadGroup#checkAccess} determines that
+     *          the current thread cannot access its thread group
+     */
+    public static int enumerate(Thread tarray[]) {
+        return currentThread().getThreadGroup().enumerate(tarray);
+    }
+
+    /**
+     * Counts the number of stack frames in this thread. The thread must
+     * be suspended.
+     *
+     * @return     the number of stack frames in this thread.
+     * @exception  IllegalThreadStateException  if this thread is not
+     *             suspended.
+     * @deprecated The definition of this call depends on {@link #suspend},
+     *             which is deprecated.  Further, the results of this call
+     *             were never well-defined.
+     */
+    @Deprecated
+    // Android-changed: Provide non-native implementation of countStackFrames().
+    // public native int countStackFrames();
+    public int countStackFrames() {
+        return getStackTrace().length;
+    }
+
+    /**
+     * Waits at most {@code millis} milliseconds for this thread to
+     * die. A timeout of {@code 0} means to wait forever.
+     *
+     * <p> This implementation uses a loop of {@code this.wait} calls
+     * conditioned on {@code this.isAlive}. As a thread terminates the
+     * {@code this.notifyAll} method is invoked. It is recommended that
+     * applications not use {@code wait}, {@code notify}, or
+     * {@code notifyAll} on {@code Thread} instances.
+     *
+     * @param  millis
+     *         the time to wait in milliseconds
+     *
+     * @throws  IllegalArgumentException
+     *          if the value of {@code millis} is negative
+     *
+     * @throws  InterruptedException
+     *          if any thread has interrupted the current thread. The
+     *          <i>interrupted status</i> of the current thread is
+     *          cleared when this exception is thrown.
+     */
+    // BEGIN Android-changed: Synchronize on separate lock object not this Thread.
+    // public final synchronized void join(long millis)
+    public final void join(long millis)
+    throws InterruptedException {
+        synchronized(lock) {
+        long base = System.currentTimeMillis();
+        long now = 0;
+
+        if (millis < 0) {
+            throw new IllegalArgumentException("timeout value is negative");
+        }
+
+        if (millis == 0) {
+            while (isAlive()) {
+                lock.wait(0);
+            }
+        } else {
+            while (isAlive()) {
+                long delay = millis - now;
+                if (delay <= 0) {
+                    break;
+                }
+                lock.wait(delay);
+                now = System.currentTimeMillis() - base;
+            }
+        }
+        }
+    }
+    // END Android-changed: Synchronize on separate lock object not this Thread.
+
+    /**
+     * Waits at most {@code millis} milliseconds plus
+     * {@code nanos} nanoseconds for this thread to die.
+     *
+     * <p> This implementation uses a loop of {@code this.wait} calls
+     * conditioned on {@code this.isAlive}. As a thread terminates the
+     * {@code this.notifyAll} method is invoked. It is recommended that
+     * applications not use {@code wait}, {@code notify}, or
+     * {@code notifyAll} on {@code Thread} instances.
+     *
+     * @param  millis
+     *         the time to wait in milliseconds
+     *
+     * @param  nanos
+     *         {@code 0-999999} additional nanoseconds to wait
+     *
+     * @throws  IllegalArgumentException
+     *          if the value of {@code millis} is negative, or the value
+     *          of {@code nanos} is not in the range {@code 0-999999}
+     *
+     * @throws  InterruptedException
+     *          if any thread has interrupted the current thread. The
+     *          <i>interrupted status</i> of the current thread is
+     *          cleared when this exception is thrown.
+     */
+    // BEGIN Android-changed: Synchronize on separate lock object not this Thread.
+    // public final synchronized void join(long millis, int nanos)
+    public final void join(long millis, int nanos)
+    throws InterruptedException {
+
+        synchronized(lock) {
+        if (millis < 0) {
+            throw new IllegalArgumentException("timeout value is negative");
+        }
+
+        if (nanos < 0 || nanos > 999999) {
+            throw new IllegalArgumentException(
+                                "nanosecond timeout value out of range");
+        }
+
+        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
+            millis++;
+        }
+
+        join(millis);
+        }
+    }
+    // END Android-changed: Synchronize on separate lock object not this Thread.
+
+    /**
+     * Waits for this thread to die.
+     *
+     * <p> An invocation of this method behaves in exactly the same
+     * way as the invocation
+     *
+     * <blockquote>
+     * {@linkplain #join(long) join}{@code (0)}
+     * </blockquote>
+     *
+     * @throws  InterruptedException
+     *          if any thread has interrupted the current thread. The
+     *          <i>interrupted status</i> of the current thread is
+     *          cleared when this exception is thrown.
+     */
+    public final void join() throws InterruptedException {
+        join(0);
+    }
+
+    /**
+     * Prints a stack trace of the current thread to the standard error stream.
+     * This method is used only for debugging.
+     *
+     * @see     Throwable#printStackTrace()
+     */
+    public static void dumpStack() {
+        new Exception("Stack trace").printStackTrace();
+    }
+
+    /**
+     * Marks this thread as either a {@linkplain #isDaemon daemon} thread
+     * or a user thread. The Java Virtual Machine exits when the only
+     * threads running are all daemon threads.
+     *
+     * <p> This method must be invoked before the thread is started.
+     *
+     * @param  on
+     *         if {@code true}, marks this thread as a daemon thread
+     *
+     * @throws  IllegalThreadStateException
+     *          if this thread is {@linkplain #isAlive alive}
+     *
+     * @throws  SecurityException
+     *          if {@link #checkAccess} determines that the current
+     *          thread cannot modify this thread
+     */
+    public final void setDaemon(boolean on) {
+        checkAccess();
+        if (isAlive()) {
+            throw new IllegalThreadStateException();
+        }
+        daemon = on;
+    }
+
+    /**
+     * Tests if this thread is a daemon thread.
+     *
+     * @return  <code>true</code> if this thread is a daemon thread;
+     *          <code>false</code> otherwise.
+     * @see     #setDaemon(boolean)
+     */
+    public final boolean isDaemon() {
+        return daemon;
+    }
+
+    /**
+     * Determines if the currently running thread has permission to
+     * modify this thread.
+     * <p>
+     * If there is a security manager, its <code>checkAccess</code> method
+     * is called with this thread as its argument. This may result in
+     * throwing a <code>SecurityException</code>.
+     *
+     * @exception  SecurityException  if the current thread is not allowed to
+     *               access this thread.
+     * @see        SecurityManager#checkAccess(Thread)
+     */
+    public final void checkAccess() {
+        // Android-removed: SecurityManager stubbed out on Android
+        // SecurityManager security = System.getSecurityManager();
+        // if (security != null) {
+        //     security.checkAccess(this);
+        // }
+    }
+
+    /**
+     * Returns a string representation of this thread, including the
+     * thread's name, priority, and thread group.
+     *
+     * @return  a string representation of this thread.
+     */
+    public String toString() {
+        ThreadGroup group = getThreadGroup();
+        if (group != null) {
+            return "Thread[" + getName() + "," + getPriority() + "," +
+                           group.getName() + "]";
+        } else {
+            return "Thread[" + getName() + "," + getPriority() + "," +
+                            "" + "]";
+        }
+    }
+
+    /**
+     * Returns the context ClassLoader for this Thread. The context
+     * ClassLoader is provided by the creator of the thread for use
+     * by code running in this thread when loading classes and resources.
+     * If not {@linkplain #setContextClassLoader set}, the default is the
+     * ClassLoader context of the parent Thread. The context ClassLoader of the
+     * primordial thread is typically set to the class loader used to load the
+     * application.
+     *
+     * <p>If a security manager is present, and the invoker's class loader is not
+     * {@code null} and is not the same as or an ancestor of the context class
+     * loader, then this method invokes the security manager's {@link
+     * SecurityManager#checkPermission(java.security.Permission) checkPermission}
+     * method with a {@link RuntimePermission RuntimePermission}{@code
+     * ("getClassLoader")} permission to verify that retrieval of the context
+     * class loader is permitted.
+     *
+     * @return  the context ClassLoader for this Thread, or {@code null}
+     *          indicating the system class loader (or, failing that, the
+     *          bootstrap class loader)
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot get the context ClassLoader
+     *
+     * @since 1.2
+     */
+    @CallerSensitive
+    public ClassLoader getContextClassLoader() {
+        // Android-removed: SecurityManager stubbed out on Android
+        /*
+        if (contextClassLoader == null)
+            return null;
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            ClassLoader.checkClassLoaderPermission(contextClassLoader,
+                                                   Reflection.getCallerClass());
+        }
+        */
+        return contextClassLoader;
+    }
+
+    /**
+     * Sets the context ClassLoader for this Thread. The context
+     * ClassLoader can be set when a thread is created, and allows
+     * the creator of the thread to provide the appropriate class loader,
+     * through {@code getContextClassLoader}, to code running in the thread
+     * when loading classes and resources.
+     *
+     * <p>If a security manager is present, its {@link
+     * SecurityManager#checkPermission(java.security.Permission) checkPermission}
+     * method is invoked with a {@link RuntimePermission RuntimePermission}{@code
+     * ("setContextClassLoader")} permission to see if setting the context
+     * ClassLoader is permitted.
+     *
+     * @param  cl
+     *         the context ClassLoader for this Thread, or null  indicating the
+     *         system class loader (or, failing that, the bootstrap class loader)
+     *
+     * @throws  SecurityException
+     *          if the current thread cannot set the context ClassLoader
+     *
+     * @since 1.2
+     */
+    public void setContextClassLoader(ClassLoader cl) {
+        // Android-removed: SecurityManager stubbed out on Android
+        // SecurityManager sm = System.getSecurityManager();
+        // if (sm != null) {
+        //     sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+        // }
+        contextClassLoader = cl;
+    }
+
+    /**
+     * Returns <tt>true</tt> if and only if the current thread holds the
+     * monitor lock on the specified object.
+     *
+     * <p>This method is designed to allow a program to assert that
+     * the current thread already holds a specified lock:
+     * <pre>
+     *     assert Thread.holdsLock(obj);
+     * </pre>
+     *
+     * @param  obj the object on which to test lock ownership
+     * @throws NullPointerException if obj is <tt>null</tt>
+     * @return <tt>true</tt> if the current thread holds the monitor lock on
+     *         the specified object.
+     * @since 1.4
+     */
+    public static native boolean holdsLock(Object obj);
+
+    private static final StackTraceElement[] EMPTY_STACK_TRACE
+        = new StackTraceElement[0];
+
+    /**
+     * Returns an array of stack trace elements representing the stack dump
+     * of this thread.  This method will return a zero-length array if
+     * this thread has not started, has started but has not yet been
+     * scheduled to run by the system, or has terminated.
+     * If the returned array is of non-zero length then the first element of
+     * the array represents the top of the stack, which is the most recent
+     * method invocation in the sequence.  The last element of the array
+     * represents the bottom of the stack, which is the least recent method
+     * invocation in the sequence.
+     *
+     * <p>If there is a security manager, and this thread is not
+     * the current thread, then the security manager's
+     * <tt>checkPermission</tt> method is called with a
+     * <tt>RuntimePermission("getStackTrace")</tt> permission
+     * to see if it's ok to get the stack trace.
+     *
+     * <p>Some virtual machines may, under some circumstances, omit one
+     * or more stack frames from the stack trace.  In the extreme case,
+     * a virtual machine that has no stack trace information concerning
+     * this thread is permitted to return a zero-length array from this
+     * method.
+     *
+     * @return an array of <tt>StackTraceElement</tt>,
+     * each represents one stack frame.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <tt>checkPermission</tt> method doesn't allow
+     *        getting the stack trace of thread.
+     * @see SecurityManager#checkPermission
+     * @see RuntimePermission
+     * @see Throwable#getStackTrace
+     *
+     * @since 1.5
+     */
+    public StackTraceElement[] getStackTrace() {
+        // Android-changed: Use native VMStack to get stack trace.
+        StackTraceElement ste[] = VMStack.getThreadStackTrace(this);
+        return ste != null ? ste : EmptyArray.STACK_TRACE_ELEMENT;
+    }
+
+    /**
+     * Returns a map of stack traces for all live threads.
+     * The map keys are threads and each map value is an array of
+     * <tt>StackTraceElement</tt> that represents the stack dump
+     * of the corresponding <tt>Thread</tt>.
+     * The returned stack traces are in the format specified for
+     * the {@link #getStackTrace getStackTrace} method.
+     *
+     * <p>The threads may be executing while this method is called.
+     * The stack trace of each thread only represents a snapshot and
+     * each stack trace may be obtained at different time.  A zero-length
+     * array will be returned in the map value if the virtual machine has
+     * no stack trace information about a thread.
+     *
+     * <p>If there is a security manager, then the security manager's
+     * <tt>checkPermission</tt> method is called with a
+     * <tt>RuntimePermission("getStackTrace")</tt> permission as well as
+     * <tt>RuntimePermission("modifyThreadGroup")</tt> permission
+     * to see if it is ok to get the stack trace of all threads.
+     *
+     * @return a <tt>Map</tt> from <tt>Thread</tt> to an array of
+     * <tt>StackTraceElement</tt> that represents the stack trace of
+     * the corresponding thread.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <tt>checkPermission</tt> method doesn't allow
+     *        getting the stack trace of thread.
+     * @see #getStackTrace
+     * @see SecurityManager#checkPermission
+     * @see RuntimePermission
+     * @see Throwable#getStackTrace
+     *
+     * @since 1.5
+     */
+    public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
+        // Android-removed: SecurityManager stubbed out on Android
+        /*
+        // check for getStackTrace permission
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(
+                SecurityConstants.GET_STACK_TRACE_PERMISSION);
+            security.checkPermission(
+                SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
+        }
+        */
+
+        // Get a snapshot of the list of all threads
+        // BEGIN Android-changed: Use ThreadGroup and getStackTrace() instead of native methods.
+        // Allocate a bit more space than needed, in case new ones are just being created.
+        /*
+        Thread[] threads = getThreads();
+        StackTraceElement[][] traces = dumpThreads(threads);
+        Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
+        for (int i = 0; i < threads.length; i++) {
+            StackTraceElement[] stackTrace = traces[i];
+            if (stackTrace != null) {
+                m.put(threads[i], stackTrace);
+            }
+            // else terminated so we don't put it in the map
+        }
+        */
+        int count = ThreadGroup.systemThreadGroup.activeCount();
+        Thread[] threads = new Thread[count + count / 2];
+
+        // Enumerate the threads.
+        count = ThreadGroup.systemThreadGroup.enumerate(threads);
+
+        // Collect the stacktraces
+        Map<Thread, StackTraceElement[]> m = new HashMap<Thread, StackTraceElement[]>();
+        for (int i = 0; i < count; i++) {
+            StackTraceElement[] stackTrace = threads[i].getStackTrace();
+            m.put(threads[i], stackTrace);
+        }
+        // END Android-changed: Use ThreadGroup and getStackTrace() instead of native methods.
+        return m;
+    }
+
+
+    private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
+                    new RuntimePermission("enableContextClassLoaderOverride");
+
+    /** cache of subclass security audit results */
+    /* Replace with ConcurrentReferenceHashMap when/if it appears in a future
+     * release */
+    private static class Caches {
+        /** cache of subclass security audit results */
+        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
+            new ConcurrentHashMap<>();
+
+        /** queue for WeakReferences to audited subclasses */
+        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
+            new ReferenceQueue<>();
+    }
+
+    /**
+     * Verifies that this (possibly subclass) instance can be constructed
+     * without violating security constraints: the subclass must not override
+     * security-sensitive non-final methods, or else the
+     * "enableContextClassLoaderOverride" RuntimePermission is checked.
+     */
+    private static boolean isCCLOverridden(Class<?> cl) {
+        if (cl == Thread.class)
+            return false;
+
+        processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
+        WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
+        Boolean result = Caches.subclassAudits.get(key);
+        if (result == null) {
+            result = Boolean.valueOf(auditSubclass(cl));
+            Caches.subclassAudits.putIfAbsent(key, result);
+        }
+
+        return result.booleanValue();
+    }
+
+    /**
+     * Performs reflective checks on given subclass to verify that it doesn't
+     * override security-sensitive non-final methods.  Returns true if the
+     * subclass overrides any of the methods, false otherwise.
+     */
+    private static boolean auditSubclass(final Class<?> subcl) {
+        Boolean result = AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    for (Class<?> cl = subcl;
+                         cl != Thread.class;
+                         cl = cl.getSuperclass())
+                    {
+                        try {
+                            cl.getDeclaredMethod("getContextClassLoader", new Class<?>[0]);
+                            return Boolean.TRUE;
+                        } catch (NoSuchMethodException ex) {
+                        }
+                        try {
+                            Class<?>[] params = {ClassLoader.class};
+                            cl.getDeclaredMethod("setContextClassLoader", params);
+                            return Boolean.TRUE;
+                        } catch (NoSuchMethodException ex) {
+                        }
+                    }
+                    return Boolean.FALSE;
+                }
+            }
+        );
+        return result.booleanValue();
+    }
+
+    // Android-removed: Native methods that are unused on Android.
+    // private native static StackTraceElement[][] dumpThreads(Thread[] threads);
+    // private native static Thread[] getThreads();
+
+    /**
+     * Returns the identifier of this Thread.  The thread ID is a positive
+     * <tt>long</tt> number generated when this thread was created.
+     * The thread ID is unique and remains unchanged during its lifetime.
+     * When a thread is terminated, this thread ID may be reused.
+     *
+     * @return this thread's ID.
+     * @since 1.5
+     */
+    public long getId() {
+        return tid;
+    }
+
+    /**
+     * A thread state.  A thread can be in one of the following states:
+     * <ul>
+     * <li>{@link #NEW}<br>
+     *     A thread that has not yet started is in this state.
+     *     </li>
+     * <li>{@link #RUNNABLE}<br>
+     *     A thread executing in the Java virtual machine is in this state.
+     *     </li>
+     * <li>{@link #BLOCKED}<br>
+     *     A thread that is blocked waiting for a monitor lock
+     *     is in this state.
+     *     </li>
+     * <li>{@link #WAITING}<br>
+     *     A thread that is waiting indefinitely for another thread to
+     *     perform a particular action is in this state.
+     *     </li>
+     * <li>{@link #TIMED_WAITING}<br>
+     *     A thread that is waiting for another thread to perform an action
+     *     for up to a specified waiting time is in this state.
+     *     </li>
+     * <li>{@link #TERMINATED}<br>
+     *     A thread that has exited is in this state.
+     *     </li>
+     * </ul>
+     *
+     * <p>
+     * A thread can be in only one state at a given point in time.
+     * These states are virtual machine states which do not reflect
+     * any operating system thread states.
+     *
+     * @since   1.5
+     * @see #getState
+     */
+    public enum State {
+        /**
+         * Thread state for a thread which has not yet started.
+         */
+        NEW,
+
+        /**
+         * Thread state for a runnable thread.  A thread in the runnable
+         * state is executing in the Java virtual machine but it may
+         * be waiting for other resources from the operating system
+         * such as processor.
+         */
+        RUNNABLE,
+
+        /**
+         * Thread state for a thread blocked waiting for a monitor lock.
+         * A thread in the blocked state is waiting for a monitor lock
+         * to enter a synchronized block/method or
+         * reenter a synchronized block/method after calling
+         * {@link Object#wait() Object.wait}.
+         */
+        BLOCKED,
+
+        /**
+         * Thread state for a waiting thread.
+         * A thread is in the waiting state due to calling one of the
+         * following methods:
+         * <ul>
+         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
+         *   <li>{@link #join() Thread.join} with no timeout</li>
+         *   <li>{@link LockSupport#park() LockSupport.park}</li>
+         * </ul>
+         *
+         * <p>A thread in the waiting state is waiting for another thread to
+         * perform a particular action.
+         *
+         * For example, a thread that has called <tt>Object.wait()</tt>
+         * on an object is waiting for another thread to call
+         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
+         * that object. A thread that has called <tt>Thread.join()</tt>
+         * is waiting for a specified thread to terminate.
+         */
+        WAITING,
+
+        /**
+         * Thread state for a waiting thread with a specified waiting time.
+         * A thread is in the timed waiting state due to calling one of
+         * the following methods with a specified positive waiting time:
+         * <ul>
+         *   <li>{@link #sleep Thread.sleep}</li>
+         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
+         *   <li>{@link #join(long) Thread.join} with timeout</li>
+         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
+         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
+         * </ul>
+         */
+        TIMED_WAITING,
+
+        /**
+         * Thread state for a terminated thread.
+         * The thread has completed execution.
+         */
+        TERMINATED;
+    }
+
+    /**
+     * Returns the state of this thread.
+     * This method is designed for use in monitoring of the system state,
+     * not for synchronization control.
+     *
+     * @return this thread's state.
+     * @since 1.5
+     */
+    public State getState() {
+        // get current thread state
+        // Android-changed: Replace unused threadStatus field with started field.
+        // Use Android specific nativeGetStatus() method. See comment on started field for more
+        // information.
+        // return sun.misc.VM.toThreadState(threadStatus);
+        return State.values()[nativeGetStatus(started)];
+    }
+
+    // Added in JSR-166
+
+    /**
+     * Interface for handlers invoked when a <tt>Thread</tt> abruptly
+     * terminates due to an uncaught exception.
+     * <p>When a thread is about to terminate due to an uncaught exception
+     * the Java Virtual Machine will query the thread for its
+     * <tt>UncaughtExceptionHandler</tt> using
+     * {@link #getUncaughtExceptionHandler} and will invoke the handler's
+     * <tt>uncaughtException</tt> method, passing the thread and the
+     * exception as arguments.
+     * If a thread has not had its <tt>UncaughtExceptionHandler</tt>
+     * explicitly set, then its <tt>ThreadGroup</tt> object acts as its
+     * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
+     * has no
+     * special requirements for dealing with the exception, it can forward
+     * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
+     * default uncaught exception handler}.
+     *
+     * @see #setDefaultUncaughtExceptionHandler
+     * @see #setUncaughtExceptionHandler
+     * @see ThreadGroup#uncaughtException
+     * @since 1.5
+     */
+    @FunctionalInterface
+    public interface UncaughtExceptionHandler {
+        /**
+         * Method invoked when the given thread terminates due to the
+         * given uncaught exception.
+         * <p>Any exception thrown by this method will be ignored by the
+         * Java Virtual Machine.
+         * @param t the thread
+         * @param e the exception
+         */
+        void uncaughtException(Thread t, Throwable e);
+    }
+
+    // null unless explicitly set
+    private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
+
+    // null unless explicitly set
+    private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
+
+    /**
+     * Set the default handler invoked when a thread abruptly terminates
+     * due to an uncaught exception, and no other handler has been defined
+     * for that thread.
+     *
+     * <p>Uncaught exception handling is controlled first by the thread, then
+     * by the thread's {@link ThreadGroup} object and finally by the default
+     * uncaught exception handler. If the thread does not have an explicit
+     * uncaught exception handler set, and the thread's thread group
+     * (including parent thread groups)  does not specialize its
+     * <tt>uncaughtException</tt> method, then the default handler's
+     * <tt>uncaughtException</tt> method will be invoked.
+     * <p>By setting the default uncaught exception handler, an application
+     * can change the way in which uncaught exceptions are handled (such as
+     * logging to a specific device, or file) for those threads that would
+     * already accept whatever &quot;default&quot; behavior the system
+     * provided.
+     *
+     * <p>Note that the default uncaught exception handler should not usually
+     * defer to the thread's <tt>ThreadGroup</tt> object, as that could cause
+     * infinite recursion.
+     *
+     * @param eh the object to use as the default uncaught exception handler.
+     * If <tt>null</tt> then there is no default handler.
+     *
+     * @throws SecurityException if a security manager is present and it
+     *         denies <tt>{@link RuntimePermission}
+     *         (&quot;setDefaultUncaughtExceptionHandler&quot;)</tt>
+     *
+     * @see #setUncaughtExceptionHandler
+     * @see #getUncaughtExceptionHandler
+     * @see ThreadGroup#uncaughtException
+     * @since 1.5
+     */
+    public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
+        // Android-removed: SecurityManager stubbed out on Android
+        /*
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(
+                new RuntimePermission("setDefaultUncaughtExceptionHandler")
+                    );
+        }
+        */
+
+         defaultUncaughtExceptionHandler = eh;
+     }
+
+    /**
+     * Returns the default handler invoked when a thread abruptly terminates
+     * due to an uncaught exception. If the returned value is <tt>null</tt>,
+     * there is no default.
+     * @since 1.5
+     * @see #setDefaultUncaughtExceptionHandler
+     * @return the default uncaught exception handler for all threads
+     */
+    public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
+        return defaultUncaughtExceptionHandler;
+    }
+
+    // BEGIN Android-added: The concept of an uncaughtExceptionPreHandler for use by platform.
+    // See http://b/29624607 for background information.
+    // null unless explicitly set
+    private static volatile UncaughtExceptionHandler uncaughtExceptionPreHandler;
+
+    /**
+     * Sets an {@link UncaughtExceptionHandler} that will be called before any
+     * returned by {@link #getUncaughtExceptionHandler()}. To allow the standard
+     * handlers to run, this handler should never terminate this process. Any
+     * throwables thrown by the handler will be ignored by
+     * {@link #dispatchUncaughtException(Throwable)}.
+     *
+     * @hide used when configuring the runtime for exception logging; see
+     *     {@link dalvik.system.RuntimeHooks} b/29624607
+     */
+    public static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) {
+        uncaughtExceptionPreHandler = eh;
+    }
+
+    /** @hide */
+    public static UncaughtExceptionHandler getUncaughtExceptionPreHandler() {
+        return uncaughtExceptionPreHandler;
+    }
+    // END Android-added: The concept of an uncaughtExceptionPreHandler for use by platform.
+
+    /**
+     * Returns the handler invoked when this thread abruptly terminates
+     * due to an uncaught exception. If this thread has not had an
+     * uncaught exception handler explicitly set then this thread's
+     * <tt>ThreadGroup</tt> object is returned, unless this thread
+     * has terminated, in which case <tt>null</tt> is returned.
+     * @since 1.5
+     * @return the uncaught exception handler for this thread
+     */
+    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+        return uncaughtExceptionHandler != null ?
+            uncaughtExceptionHandler : group;
+    }
+
+    /**
+     * Set the handler invoked when this thread abruptly terminates
+     * due to an uncaught exception.
+     * <p>A thread can take full control of how it responds to uncaught
+     * exceptions by having its uncaught exception handler explicitly set.
+     * If no such handler is set then the thread's <tt>ThreadGroup</tt>
+     * object acts as its handler.
+     * @param eh the object to use as this thread's uncaught exception
+     * handler. If <tt>null</tt> then this thread has no explicit handler.
+     * @throws  SecurityException  if the current thread is not allowed to
+     *          modify this thread.
+     * @see #setDefaultUncaughtExceptionHandler
+     * @see ThreadGroup#uncaughtException
+     * @since 1.5
+     */
+    public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
+        checkAccess();
+        uncaughtExceptionHandler = eh;
+    }
+
+    /**
+     * Dispatch an uncaught exception to the handler. This method is
+     * intended to be called only by the runtime and by tests.
+     *
+     * @hide
+     */
+    // Android-changed: Make dispatchUncaughtException() public, for use by tests.
+    public final void dispatchUncaughtException(Throwable e) {
+        // BEGIN Android-added: uncaughtExceptionPreHandler for use by platform.
+        Thread.UncaughtExceptionHandler initialUeh =
+                Thread.getUncaughtExceptionPreHandler();
+        if (initialUeh != null) {
+            try {
+                initialUeh.uncaughtException(this, e);
+            } catch (RuntimeException | Error ignored) {
+                // Throwables thrown by the initial handler are ignored
+            }
+        }
+        // END Android-added: uncaughtExceptionPreHandler for use by platform.
+        getUncaughtExceptionHandler().uncaughtException(this, e);
+    }
+
+    // BEGIN Android-added: The concept of "system-daemon" threads. See java.lang.Daemons.
+    /**
+     * Marks this thread as either a special runtime-managed ("system daemon")
+     * thread or a normal (i.e. app code created) daemon thread.)
+     *
+     * <p>System daemon threads get special handling when starting up in some
+     * cases.
+     *
+     * <p>This method must be invoked before the thread is started.
+     *
+     * <p>This method must only be invoked on Thread instances that have already
+     * had {@code setDaemon(true)} called on them.
+     *
+     * <p>Package-private since only {@link java.lang.Daemons} needs to call
+     * this.
+     *
+     * @param  on if {@code true}, marks this thread as a system daemon thread
+     *
+     * @throws  IllegalThreadStateException
+     *          if this thread is {@linkplain #isAlive alive} or not a
+     *          {@linkplain #isDaemon daemon}
+     *
+     * @throws  SecurityException
+     *          if {@link #checkAccess} determines that the current
+     *          thread cannot modify this thread
+     *
+     * @hide For use by Daemons.java only.
+     */
+    final void setSystemDaemon(boolean on) {
+        checkAccess();
+        if (isAlive() || !isDaemon()) {
+            throw new IllegalThreadStateException();
+        }
+        systemDaemon = on;
+    }
+    // END Android-added: The concept of "system-daemon" threads. See java.lang.Daemons.
+
+    /**
+     * Removes from the specified map any keys that have been enqueued
+     * on the specified reference queue.
+     */
+    static void processQueue(ReferenceQueue<Class<?>> queue,
+                             ConcurrentMap<? extends
+                             WeakReference<Class<?>>, ?> map)
+    {
+        Reference<? extends Class<?>> ref;
+        while((ref = queue.poll()) != null) {
+            map.remove(ref);
+        }
+    }
+
+    /**
+     *  Weak key for Class objects.
+     **/
+    static class WeakClassKey extends WeakReference<Class<?>> {
+        /**
+         * saved value of the referent's identity hash code, to maintain
+         * a consistent hash code after the referent has been cleared
+         */
+        private final int hash;
+
+        /**
+         * Create a new WeakClassKey to the given object, registered
+         * with a queue.
+         */
+        WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
+            super(cl, refQueue);
+            hash = System.identityHashCode(cl);
+        }
+
+        /**
+         * Returns the identity hash code of the original referent.
+         */
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        /**
+         * Returns true if the given object is this identical
+         * WeakClassKey instance, or, if this object's referent has not
+         * been cleared, if the given object is another WeakClassKey
+         * instance with the identical non-null referent as this one.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this)
+                return true;
+
+            if (obj instanceof WeakClassKey) {
+                Object referent = get();
+                return (referent != null) &&
+                       (referent == ((WeakClassKey) obj).get());
+            } else {
+                return false;
+            }
+        }
+    }
+
+
+    // The following three initially uninitialized fields are exclusively
+    // managed by class java.util.concurrent.ThreadLocalRandom. These
+    // fields are used to build the high-performance PRNGs in the
+    // concurrent code, and we can not risk accidental false sharing.
+    // Hence, the fields are isolated with @Contended.
+
+    // BEGIN Android-changed: @sun.misc.Contended is not supported on Android.
+    /** The current seed for a ThreadLocalRandom */
+    // @sun.misc.Contended("tlr")
+    long threadLocalRandomSeed;
+
+    /** Probe hash value; nonzero if threadLocalRandomSeed initialized */
+    // @sun.misc.Contended("tlr")
+    int threadLocalRandomProbe;
+
+    /** Secondary seed isolated from public ThreadLocalRandom sequence */
+    //  @sun.misc.Contended("tlr")
+    int threadLocalRandomSecondarySeed;
+    // END Android-changed: @sun.misc.Contended is not supported on Android.
+
+    /* Some private helper methods */
+    private native void setPriority0(int newPriority);
+
+    // BEGIN Android-removed: Native methods that are unused on Android.
+    /*
+    private native void stop0(Object o);
+    private native void suspend0();
+    private native void resume0();
+    */
+    // END Android-removed: Native methods that are unused on Android.
+
+    @FastNative
+    private native void interrupt0();
+    private native void setNativeName(String name);
+
+    // Android-added: Android specific nativeGetStatus() method.
+    private native int nativeGetStatus(boolean hasBeenStarted);
+
+    // BEGIN Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
+    /**
+     * Returns the thread ID of the underlying native thread -- which is different from
+     * the {@link #getId() managed thread ID} -- or 0 if the native thread is not
+     * started or has stopped.
+     */
+    @FastNative
+    private native int getNativeTid();
+    // END Android-added: Customize behavior of Thread.setPriority(). http://b/139521784
+}
diff --git a/java/lang/ThreadDeath.java b/java/lang/ThreadDeath.java
new file mode 100644
index 0000000..79e8bb5
--- /dev/null
+++ b/java/lang/ThreadDeath.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * An instance of {@code ThreadDeath} is thrown in the victim thread
+ * when the (deprecated) {@link Thread#stop()} method is invoked.
+ *
+ * <p>An application should catch instances of this class only if it
+ * must clean up after being terminated asynchronously.  If
+ * {@code ThreadDeath} is caught by a method, it is important that it
+ * be rethrown so that the thread actually dies.
+ *
+ * <p>The {@linkplain ThreadGroup#uncaughtException top-level error
+ * handler} does not print out a message if {@code ThreadDeath} is
+ * never caught.
+ *
+ * <p>The class {@code ThreadDeath} is specifically a subclass of
+ * {@code Error} rather than {@code Exception}, even though it is a
+ * "normal occurrence", because many applications catch all
+ * occurrences of {@code Exception} and then discard the exception.
+ *
+ * @since   JDK1.0
+ */
+
+public class ThreadDeath extends Error {
+    private static final long serialVersionUID = -4417128565033088268L;
+}
diff --git a/java/lang/ThreadGroup.java b/java/lang/ThreadGroup.java
new file mode 100644
index 0000000..292b536
--- /dev/null
+++ b/java/lang/ThreadGroup.java
@@ -0,0 +1,1110 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import sun.misc.VM;
+
+/**
+ * A thread group represents a set of threads. In addition, a thread
+ * group can also include other thread groups. The thread groups form
+ * a tree in which every thread group except the initial thread group
+ * has a parent.
+ * <p>
+ * A thread is allowed to access information about its own thread
+ * group, but not to access information about its thread group's
+ * parent thread group or any other thread groups.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+/* The locking strategy for this code is to try to lock only one level of the
+ * tree wherever possible, but otherwise to lock from the bottom up.
+ * That is, from child thread groups to parents.
+ * This has the advantage of limiting the number of locks that need to be held
+ * and in particular avoids having to grab the lock for the root thread group,
+ * (or a global lock) which would be a source of contention on a
+ * multi-processor system with many thread groups.
+ * This policy often leads to taking a snapshot of the state of a thread group
+ * and working off of that snapshot, rather than holding the thread group locked
+ * while we work on the children.
+ */
+public
+class ThreadGroup implements Thread.UncaughtExceptionHandler {
+    /* the runtime uses these directly; do not rename */
+    static final ThreadGroup systemThreadGroup = new ThreadGroup();
+
+    static final ThreadGroup mainThreadGroup = new ThreadGroup(systemThreadGroup, "main");
+
+    private final ThreadGroup parent;
+    String name;
+    int maxPriority;
+    boolean destroyed;
+    boolean daemon;
+    boolean vmAllowSuspension;
+
+    int nUnstartedThreads = 0;
+    int nthreads;
+    Thread threads[];
+
+    int ngroups;
+    ThreadGroup groups[];
+
+    /**
+     * Creates an empty Thread group that is not in any Thread group.
+     * This method is used to create the system Thread group.
+     */
+    private ThreadGroup() {     // called from C code
+        this.name = "system";
+        this.maxPriority = Thread.MAX_PRIORITY;
+        this.parent = null;
+    }
+
+    /**
+     * Constructs a new thread group. The parent of this new group is
+     * the thread group of the currently running thread.
+     * <p>
+     * The <code>checkAccess</code> method of the parent thread group is
+     * called with no arguments; this may result in a security exception.
+     *
+     * @param   name   the name of the new thread group.
+     * @exception  SecurityException  if the current thread cannot create a
+     *               thread in the specified thread group.
+     * @see     java.lang.ThreadGroup#checkAccess()
+     * @since   JDK1.0
+     */
+    public ThreadGroup(String name) {
+        this(Thread.currentThread().getThreadGroup(), name);
+    }
+
+    /**
+     * Creates a new thread group. The parent of this new group is the
+     * specified thread group.
+     * <p>
+     * The <code>checkAccess</code> method of the parent thread group is
+     * called with no arguments; this may result in a security exception.
+     *
+     * @param     parent   the parent thread group.
+     * @param     name     the name of the new thread group.
+     * @exception  NullPointerException  if the thread group argument is
+     *               <code>null</code>.
+     * @exception  SecurityException  if the current thread cannot create a
+     *               thread in the specified thread group.
+     * @see     java.lang.SecurityException
+     * @see     java.lang.ThreadGroup#checkAccess()
+     * @since   JDK1.0
+     */
+    public ThreadGroup(ThreadGroup parent, String name) {
+        this(checkParentAccess(parent), parent, name);
+    }
+
+    private ThreadGroup(Void unused, ThreadGroup parent, String name) {
+        this.name = name;
+        this.maxPriority = parent.maxPriority;
+        this.daemon = parent.daemon;
+        this.vmAllowSuspension = parent.vmAllowSuspension;
+        this.parent = parent;
+        parent.add(this);
+    }
+
+    /*
+     * @throws  NullPointerException  if the parent argument is {@code null}
+     * @throws  SecurityException     if the current thread cannot create a
+     *                                thread in the specified thread group.
+     */
+    private static Void checkParentAccess(ThreadGroup parent) {
+        parent.checkAccess();
+        return null;
+    }
+
+    /**
+     * Returns the name of this thread group.
+     *
+     * @return  the name of this thread group.
+     * @since   JDK1.0
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the parent of this thread group.
+     * <p>
+     * First, if the parent is not <code>null</code>, the
+     * <code>checkAccess</code> method of the parent thread group is
+     * called with no arguments; this may result in a security exception.
+     *
+     * @return  the parent of this thread group. The top-level thread group
+     *          is the only thread group whose parent is <code>null</code>.
+     * @exception  SecurityException  if the current thread cannot modify
+     *               this thread group.
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @see        java.lang.SecurityException
+     * @see        java.lang.RuntimePermission
+     * @since   JDK1.0
+     */
+    public final ThreadGroup getParent() {
+        if (parent != null)
+            parent.checkAccess();
+        return parent;
+    }
+
+    /**
+     * Returns the maximum priority of this thread group. Threads that are
+     * part of this group cannot have a higher priority than the maximum
+     * priority.
+     *
+     * @return  the maximum priority that a thread in this thread group
+     *          can have.
+     * @see     #setMaxPriority
+     * @since   JDK1.0
+     */
+    public final int getMaxPriority() {
+        return maxPriority;
+    }
+
+    /**
+     * Tests if this thread group is a daemon thread group. A
+     * daemon thread group is automatically destroyed when its last
+     * thread is stopped or its last thread group is destroyed.
+     *
+     * @return  <code>true</code> if this thread group is a daemon thread group;
+     *          <code>false</code> otherwise.
+     * @since   JDK1.0
+     */
+    public final boolean isDaemon() {
+        return daemon;
+    }
+
+    /**
+     * Tests if this thread group has been destroyed.
+     *
+     * @return  true if this object is destroyed
+     * @since   JDK1.1
+     */
+    public synchronized boolean isDestroyed() {
+        return destroyed;
+    }
+
+    /**
+     * Changes the daemon status of this thread group.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     * <p>
+     * A daemon thread group is automatically destroyed when its last
+     * thread is stopped or its last thread group is destroyed.
+     *
+     * @param      daemon   if <code>true</code>, marks this thread group as
+     *                      a daemon thread group; otherwise, marks this
+     *                      thread group as normal.
+     * @exception  SecurityException  if the current thread cannot modify
+     *               this thread group.
+     * @see        java.lang.SecurityException
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      JDK1.0
+     */
+    public final void setDaemon(boolean daemon) {
+        checkAccess();
+        this.daemon = daemon;
+    }
+
+    /**
+     * Sets the maximum priority of the group. Threads in the thread
+     * group that already have a higher priority are not affected.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     * <p>
+     * If the <code>pri</code> argument is less than
+     * {@link Thread#MIN_PRIORITY} or greater than
+     * {@link Thread#MAX_PRIORITY}, it is clamped to those values.
+     * <p>
+     * Otherwise, the priority of this ThreadGroup object is set to the
+     * smaller of the specified <code>pri</code> and the maximum permitted
+     * priority of the parent of this thread group. (If this thread group
+     * is the system thread group, which has no parent, then its maximum
+     * priority is simply set to <code>pri</code>.) Then this method is
+     * called recursively, with <code>pri</code> as its argument, for
+     * every thread group that belongs to this thread group.
+     *
+     * @param      pri   the new priority of the thread group.
+     * @exception  SecurityException  if the current thread cannot modify
+     *               this thread group.
+     * @see        #getMaxPriority
+     * @see        java.lang.SecurityException
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      JDK1.0
+     */
+    public final void setMaxPriority(int pri) {
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            checkAccess();
+            // BEGIN Android-changed: Clamp to the range [MIN_PRIORITY, MAX_PRIORITY].
+            // This preserves backward compatibility with previous versions of Android.
+            // if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
+            //     return;
+            // }
+            if (pri < Thread.MIN_PRIORITY) {
+                pri = Thread.MIN_PRIORITY;
+            }
+            if (pri > Thread.MAX_PRIORITY) {
+                pri = Thread.MAX_PRIORITY;
+            }
+            // END Android-changed: Clamp to the range [MIN_PRIORITY, MAX_PRIORITY].
+
+            maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+            groupsSnapshot[i].setMaxPriority(pri);
+        }
+    }
+
+    /**
+     * Tests if this thread group is either the thread group
+     * argument or one of its ancestor thread groups.
+     *
+     * @param   g   a thread group.
+     * @return  <code>true</code> if this thread group is the thread group
+     *          argument or one of its ancestor thread groups;
+     *          <code>false</code> otherwise.
+     * @since   JDK1.0
+     */
+    public final boolean parentOf(ThreadGroup g) {
+        for (; g != null ; g = g.parent) {
+            if (g == this) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines if the currently running thread has permission to
+     * modify this thread group.
+     * <p>
+     * If there is a security manager, its <code>checkAccess</code> method
+     * is called with this thread group as its argument. This may result
+     * in throwing a <code>SecurityException</code>.
+     *
+     * @exception  SecurityException  if the current thread is not allowed to
+     *               access this thread group.
+     * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
+     * @since      JDK1.0
+     */
+    public final void checkAccess() {
+        // Android-removed: SecurityManager stubbed out on Android.
+        // SecurityManager security = System.getSecurityManager();
+        // if (security != null) {
+        //     security.checkAccess(this);
+        // }
+    }
+
+    /**
+     * Returns an estimate of the number of active threads in this thread
+     * group and its subgroups. Recursively iterates over all subgroups in
+     * this thread group.
+     *
+     * <p> The value returned is only an estimate because the number of
+     * threads may change dynamically while this method traverses internal
+     * data structures, and might be affected by the presence of certain
+     * system threads. This method is intended primarily for debugging
+     * and monitoring purposes.
+     *
+     * @return  an estimate of the number of active threads in this thread
+     *          group and in any other thread group that has this thread
+     *          group as an ancestor
+     *
+     * @since   JDK1.0
+     */
+    public int activeCount() {
+        int result;
+        // Snapshot sub-group data so we don't hold this lock
+        // while our children are computing.
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            if (destroyed) {
+                return 0;
+            }
+            result = nthreads;
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+            result += groupsSnapshot[i].activeCount();
+        }
+        return result;
+    }
+
+    /**
+     * Copies into the specified array every active thread in this
+     * thread group and its subgroups.
+     *
+     * <p> An invocation of this method behaves in exactly the same
+     * way as the invocation
+     *
+     * <blockquote>
+     * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)}
+     * </blockquote>
+     *
+     * @param  list
+     *         an array into which to put the list of threads
+     *
+     * @return  the number of threads put into the array
+     *
+     * @throws  SecurityException
+     *          if {@linkplain #checkAccess checkAccess} determines that
+     *          the current thread cannot access this thread group
+     *
+     * @since   JDK1.0
+     */
+    public int enumerate(Thread list[]) {
+        checkAccess();
+        return enumerate(list, 0, true);
+    }
+
+    /**
+     * Copies into the specified array every active thread in this
+     * thread group. If {@code recurse} is {@code true},
+     * this method recursively enumerates all subgroups of this
+     * thread group and references to every active thread in these
+     * subgroups are also included. If the array is too short to
+     * hold all the threads, the extra threads are silently ignored.
+     *
+     * <p> An application might use the {@linkplain #activeCount activeCount}
+     * method to get an estimate of how big the array should be, however
+     * <i>if the array is too short to hold all the threads, the extra threads
+     * are silently ignored.</i>  If it is critical to obtain every active
+     * thread in this thread group, the caller should verify that the returned
+     * int value is strictly less than the length of {@code list}.
+     *
+     * <p> Due to the inherent race condition in this method, it is recommended
+     * that the method only be used for debugging and monitoring purposes.
+     *
+     * @param  list
+     *         an array into which to put the list of threads
+     *
+     * @param  recurse
+     *         if {@code true}, recursively enumerate all subgroups of this
+     *         thread group
+     *
+     * @return  the number of threads put into the array
+     *
+     * @throws  SecurityException
+     *          if {@linkplain #checkAccess checkAccess} determines that
+     *          the current thread cannot access this thread group
+     *
+     * @since   JDK1.0
+     */
+    public int enumerate(Thread list[], boolean recurse) {
+        checkAccess();
+        return enumerate(list, 0, recurse);
+    }
+
+    private int enumerate(Thread list[], int n, boolean recurse) {
+        int ngroupsSnapshot = 0;
+        ThreadGroup[] groupsSnapshot = null;
+        synchronized (this) {
+            if (destroyed) {
+                return 0;
+            }
+            int nt = nthreads;
+            if (nt > list.length - n) {
+                nt = list.length - n;
+            }
+            for (int i = 0; i < nt; i++) {
+                if (threads[i].isAlive()) {
+                    list[n++] = threads[i];
+                }
+            }
+            if (recurse) {
+                ngroupsSnapshot = ngroups;
+                if (groups != null) {
+                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+                } else {
+                    groupsSnapshot = null;
+                }
+            }
+        }
+        if (recurse) {
+            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+                n = groupsSnapshot[i].enumerate(list, n, true);
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Returns an estimate of the number of active groups in this
+     * thread group and its subgroups. Recursively iterates over
+     * all subgroups in this thread group.
+     *
+     * <p> The value returned is only an estimate because the number of
+     * thread groups may change dynamically while this method traverses
+     * internal data structures. This method is intended primarily for
+     * debugging and monitoring purposes.
+     *
+     * @return  the number of active thread groups with this thread group as
+     *          an ancestor
+     *
+     * @since   JDK1.0
+     */
+    public int activeGroupCount() {
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            if (destroyed) {
+                return 0;
+            }
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+        }
+        int n = ngroupsSnapshot;
+        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+            n += groupsSnapshot[i].activeGroupCount();
+        }
+        return n;
+    }
+
+    /**
+     * Copies into the specified array references to every active
+     * subgroup in this thread group and its subgroups.
+     *
+     * <p> An invocation of this method behaves in exactly the same
+     * way as the invocation
+     *
+     * <blockquote>
+     * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)}
+     * </blockquote>
+     *
+     * @param  list
+     *         an array into which to put the list of thread groups
+     *
+     * @return  the number of thread groups put into the array
+     *
+     * @throws  SecurityException
+     *          if {@linkplain #checkAccess checkAccess} determines that
+     *          the current thread cannot access this thread group
+     *
+     * @since   JDK1.0
+     */
+    public int enumerate(ThreadGroup list[]) {
+        checkAccess();
+        return enumerate(list, 0, true);
+    }
+
+    /**
+     * Copies into the specified array references to every active
+     * subgroup in this thread group. If {@code recurse} is
+     * {@code true}, this method recursively enumerates all subgroups of this
+     * thread group and references to every active thread group in these
+     * subgroups are also included.
+     *
+     * <p> An application might use the
+     * {@linkplain #activeGroupCount activeGroupCount} method to
+     * get an estimate of how big the array should be, however <i>if the
+     * array is too short to hold all the thread groups, the extra thread
+     * groups are silently ignored.</i>  If it is critical to obtain every
+     * active subgroup in this thread group, the caller should verify that
+     * the returned int value is strictly less than the length of
+     * {@code list}.
+     *
+     * <p> Due to the inherent race condition in this method, it is recommended
+     * that the method only be used for debugging and monitoring purposes.
+     *
+     * @param  list
+     *         an array into which to put the list of thread groups
+     *
+     * @param  recurse
+     *         if {@code true}, recursively enumerate all subgroups
+     *
+     * @return  the number of thread groups put into the array
+     *
+     * @throws  SecurityException
+     *          if {@linkplain #checkAccess checkAccess} determines that
+     *          the current thread cannot access this thread group
+     *
+     * @since   JDK1.0
+     */
+    public int enumerate(ThreadGroup list[], boolean recurse) {
+        checkAccess();
+        return enumerate(list, 0, recurse);
+    }
+
+    private int enumerate(ThreadGroup list[], int n, boolean recurse) {
+        int ngroupsSnapshot = 0;
+        ThreadGroup[] groupsSnapshot = null;
+        synchronized (this) {
+            if (destroyed) {
+                return 0;
+            }
+            int ng = ngroups;
+            if (ng > list.length - n) {
+                ng = list.length - n;
+            }
+            if (ng > 0) {
+                System.arraycopy(groups, 0, list, n, ng);
+                n += ng;
+            }
+            if (recurse) {
+                ngroupsSnapshot = ngroups;
+                if (groups != null) {
+                    groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+                } else {
+                    groupsSnapshot = null;
+                }
+            }
+        }
+        if (recurse) {
+            for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+                n = groupsSnapshot[i].enumerate(list, n, true);
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Stops all threads in this thread group.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     * <p>
+     * This method then calls the <code>stop</code> method on all the
+     * threads in this thread group and in all of its subgroups.
+     *
+     * @exception  SecurityException  if the current thread is not allowed
+     *               to access this thread group or any of the threads in
+     *               the thread group.
+     * @see        java.lang.SecurityException
+     * @see        java.lang.Thread#stop()
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      JDK1.0
+     * @deprecated    This method is inherently unsafe.  See
+     *     {@link Thread#stop} for details.
+     */
+    @Deprecated
+    public final void stop() {
+        if (stopOrSuspend(false))
+            Thread.currentThread().stop();
+    }
+
+    /**
+     * Interrupts all threads in this thread group.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     * <p>
+     * This method then calls the <code>interrupt</code> method on all the
+     * threads in this thread group and in all of its subgroups.
+     *
+     * @exception  SecurityException  if the current thread is not allowed
+     *               to access this thread group or any of the threads in
+     *               the thread group.
+     * @see        java.lang.Thread#interrupt()
+     * @see        java.lang.SecurityException
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      1.2
+     */
+    public final void interrupt() {
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            checkAccess();
+            for (int i = 0 ; i < nthreads ; i++) {
+                threads[i].interrupt();
+            }
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+            groupsSnapshot[i].interrupt();
+        }
+    }
+
+    /**
+     * Suspends all threads in this thread group.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     * <p>
+     * This method then calls the <code>suspend</code> method on all the
+     * threads in this thread group and in all of its subgroups.
+     *
+     * @exception  SecurityException  if the current thread is not allowed
+     *               to access this thread group or any of the threads in
+     *               the thread group.
+     * @see        java.lang.Thread#suspend()
+     * @see        java.lang.SecurityException
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      JDK1.0
+     * @deprecated    This method is inherently deadlock-prone.  See
+     *     {@link Thread#suspend} for details.
+     */
+    @Deprecated
+    @SuppressWarnings("deprecation")
+    public final void suspend() {
+        if (stopOrSuspend(true))
+            Thread.currentThread().suspend();
+    }
+
+    /**
+     * Helper method: recursively stops or suspends (as directed by the
+     * boolean argument) all of the threads in this thread group and its
+     * subgroups, except the current thread.  This method returns true
+     * if (and only if) the current thread is found to be in this thread
+     * group or one of its subgroups.
+     */
+    @SuppressWarnings("deprecation")
+    private boolean stopOrSuspend(boolean suspend) {
+        boolean suicide = false;
+        Thread us = Thread.currentThread();
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot = null;
+        synchronized (this) {
+            checkAccess();
+            for (int i = 0 ; i < nthreads ; i++) {
+                if (threads[i]==us)
+                    suicide = true;
+                else if (suspend)
+                    threads[i].suspend();
+                else
+                    threads[i].stop();
+            }
+
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i++)
+            suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
+
+        return suicide;
+    }
+
+    /**
+     * Resumes all threads in this thread group.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     * <p>
+     * This method then calls the <code>resume</code> method on all the
+     * threads in this thread group and in all of its sub groups.
+     *
+     * @exception  SecurityException  if the current thread is not allowed to
+     *               access this thread group or any of the threads in the
+     *               thread group.
+     * @see        java.lang.SecurityException
+     * @see        java.lang.Thread#resume()
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      JDK1.0
+     * @deprecated    This method is used solely in conjunction with
+     *      <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
+     *       both of which have been deprecated, as they are inherently
+     *       deadlock-prone.  See {@link Thread#suspend} for details.
+     */
+    @Deprecated
+    @SuppressWarnings("deprecation")
+    public final void resume() {
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            checkAccess();
+            for (int i = 0 ; i < nthreads ; i++) {
+                threads[i].resume();
+            }
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+            groupsSnapshot[i].resume();
+        }
+    }
+
+    /**
+     * Destroys this thread group and all of its subgroups. This thread
+     * group must be empty, indicating that all threads that had been in
+     * this thread group have since stopped.
+     * <p>
+     * First, the <code>checkAccess</code> method of this thread group is
+     * called with no arguments; this may result in a security exception.
+     *
+     * @exception  IllegalThreadStateException  if the thread group is not
+     *               empty or if the thread group has already been destroyed.
+     * @exception  SecurityException  if the current thread cannot modify this
+     *               thread group.
+     * @see        java.lang.ThreadGroup#checkAccess()
+     * @since      JDK1.0
+     */
+    public final void destroy() {
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            checkAccess();
+            if (destroyed || (nthreads > 0)) {
+                throw new IllegalThreadStateException();
+            }
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+            if (parent != null) {
+                destroyed = true;
+                ngroups = 0;
+                groups = null;
+                nthreads = 0;
+                threads = null;
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
+            groupsSnapshot[i].destroy();
+        }
+        if (parent != null) {
+            parent.remove(this);
+        }
+    }
+
+    /**
+     * Adds the specified Thread group to this group.
+     * @param g the specified Thread group to be added
+     * @exception IllegalThreadStateException If the Thread group has been destroyed.
+     */
+    private final void add(ThreadGroup g){
+        synchronized (this) {
+            if (destroyed) {
+                throw new IllegalThreadStateException();
+            }
+            if (groups == null) {
+                groups = new ThreadGroup[4];
+            } else if (ngroups == groups.length) {
+                groups = Arrays.copyOf(groups, ngroups * 2);
+            }
+            groups[ngroups] = g;
+
+            // This is done last so it doesn't matter in case the
+            // thread is killed
+            ngroups++;
+        }
+    }
+
+    /**
+     * Removes the specified Thread group from this group.
+     * @param g the Thread group to be removed
+     * @return if this Thread has already been destroyed.
+     */
+    private void remove(ThreadGroup g) {
+        synchronized (this) {
+            if (destroyed) {
+                return;
+            }
+            for (int i = 0 ; i < ngroups ; i++) {
+                if (groups[i] == g) {
+                    ngroups -= 1;
+                    System.arraycopy(groups, i + 1, groups, i, ngroups - i);
+                    // Zap dangling reference to the dead group so that
+                    // the garbage collector will collect it.
+                    groups[ngroups] = null;
+                    break;
+                }
+            }
+            if (nthreads == 0) {
+                notifyAll();
+            }
+            if (daemon && (nthreads == 0) &&
+                (nUnstartedThreads == 0) && (ngroups == 0))
+            {
+                destroy();
+            }
+        }
+    }
+
+
+    /**
+     * Increments the count of unstarted threads in the thread group.
+     * Unstarted threads are not added to the thread group so that they
+     * can be collected if they are never started, but they must be
+     * counted so that daemon thread groups with unstarted threads in
+     * them are not destroyed.
+     */
+    void addUnstarted() {
+        synchronized(this) {
+            if (destroyed) {
+                throw new IllegalThreadStateException();
+            }
+            nUnstartedThreads++;
+        }
+    }
+
+    /**
+     * Adds the specified thread to this thread group.
+     *
+     * <p> Note: This method is called from both library code
+     * and the Virtual Machine. It is called from VM to add
+     * certain system threads to the system thread group.
+     *
+     * @param  t
+     *         the Thread to be added
+     *
+     * @throws  IllegalThreadStateException
+     *          if the Thread group has been destroyed
+     */
+    void add(Thread t) {
+        synchronized (this) {
+            if (destroyed) {
+                throw new IllegalThreadStateException();
+            }
+            if (threads == null) {
+                threads = new Thread[4];
+            } else if (nthreads == threads.length) {
+                threads = Arrays.copyOf(threads, nthreads * 2);
+            }
+            threads[nthreads] = t;
+
+            // This is done last so it doesn't matter in case the
+            // thread is killed
+            nthreads++;
+
+            // The thread is now a fully fledged member of the group, even
+            // though it may, or may not, have been started yet. It will prevent
+            // the group from being destroyed so the unstarted Threads count is
+            // decremented.
+            nUnstartedThreads--;
+        }
+    }
+
+    /**
+     * Notifies the group that the thread {@code t} has failed
+     * an attempt to start.
+     *
+     * <p> The state of this thread group is rolled back as if the
+     * attempt to start the thread has never occurred. The thread is again
+     * considered an unstarted member of the thread group, and a subsequent
+     * attempt to start the thread is permitted.
+     *
+     * @param  t
+     *         the Thread whose start method was invoked
+     */
+    void threadStartFailed(Thread t) {
+        synchronized(this) {
+            remove(t);
+            nUnstartedThreads++;
+        }
+    }
+
+    /**
+     * Notifies the group that the thread {@code t} has terminated.
+     *
+     * <p> Destroy the group if all of the following conditions are
+     * true: this is a daemon thread group; there are no more alive
+     * or unstarted threads in the group; there are no subgroups in
+     * this thread group.
+     *
+     * @param  t
+     *         the Thread that has terminated
+     */
+    void threadTerminated(Thread t) {
+        synchronized (this) {
+            remove(t);
+
+            if (nthreads == 0) {
+                notifyAll();
+            }
+            if (daemon && (nthreads == 0) &&
+                (nUnstartedThreads == 0) && (ngroups == 0))
+            {
+                destroy();
+            }
+        }
+    }
+
+    /**
+     * Removes the specified Thread from this group. Invoking this method
+     * on a thread group that has been destroyed has no effect.
+     *
+     * @param  t
+     *         the Thread to be removed
+     */
+    private void remove(Thread t) {
+        synchronized (this) {
+            if (destroyed) {
+                return;
+            }
+            for (int i = 0 ; i < nthreads ; i++) {
+                if (threads[i] == t) {
+                    System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
+                    // Zap dangling reference to the dead thread so that
+                    // the garbage collector will collect it.
+                    threads[nthreads] = null;
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Prints information about this thread group to the standard
+     * output. This method is useful only for debugging.
+     *
+     * @since   JDK1.0
+     */
+    public void list() {
+        list(System.out, 0);
+    }
+    void list(PrintStream out, int indent) {
+        int ngroupsSnapshot;
+        ThreadGroup[] groupsSnapshot;
+        synchronized (this) {
+            for (int j = 0 ; j < indent ; j++) {
+                out.print(" ");
+            }
+            out.println(this);
+            indent += 4;
+            for (int i = 0 ; i < nthreads ; i++) {
+                for (int j = 0 ; j < indent ; j++) {
+                    out.print(" ");
+                }
+                out.println(threads[i]);
+            }
+            ngroupsSnapshot = ngroups;
+            if (groups != null) {
+                groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
+            } else {
+                groupsSnapshot = null;
+            }
+        }
+        for (int i = 0 ; i < ngroupsSnapshot ; i++) {
+            groupsSnapshot[i].list(out, indent);
+        }
+    }
+
+    /**
+     * Called by the Java Virtual Machine when a thread in this
+     * thread group stops because of an uncaught exception, and the thread
+     * does not have a specific {@link Thread.UncaughtExceptionHandler}
+     * installed.
+     * <p>
+     * The <code>uncaughtException</code> method of
+     * <code>ThreadGroup</code> does the following:
+     * <ul>
+     * <li>If this thread group has a parent thread group, the
+     *     <code>uncaughtException</code> method of that parent is called
+     *     with the same two arguments.
+     * <li>Otherwise, this method checks to see if there is a
+     *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
+     *     uncaught exception handler} installed, and if so, its
+     *     <code>uncaughtException</code> method is called with the same
+     *     two arguments.
+     * <li>Otherwise, this method determines if the <code>Throwable</code>
+     *     argument is an instance of {@link ThreadDeath}. If so, nothing
+     *     special is done. Otherwise, a message containing the
+     *     thread's name, as returned from the thread's {@link
+     *     Thread#getName getName} method, and a stack backtrace,
+     *     using the <code>Throwable</code>'s {@link
+     *     Throwable#printStackTrace printStackTrace} method, is
+     *     printed to the {@linkplain System#err standard error stream}.
+     * </ul>
+     * <p>
+     * Applications can override this method in subclasses of
+     * <code>ThreadGroup</code> to provide alternative handling of
+     * uncaught exceptions.
+     *
+     * @param   t   the thread that is about to exit.
+     * @param   e   the uncaught exception.
+     * @since   JDK1.0
+     */
+    public void uncaughtException(Thread t, Throwable e) {
+        if (parent != null) {
+            parent.uncaughtException(t, e);
+        } else {
+            Thread.UncaughtExceptionHandler ueh =
+                Thread.getDefaultUncaughtExceptionHandler();
+            if (ueh != null) {
+                ueh.uncaughtException(t, e);
+            } else if (!(e instanceof ThreadDeath)) {
+                System.err.print("Exception in thread \""
+                                 + t.getName() + "\" ");
+                e.printStackTrace(System.err);
+            }
+        }
+    }
+
+    /**
+     * Used by VM to control lowmem implicit suspension.
+     *
+     * @param b boolean to allow or disallow suspension
+     * @return true on success
+     * @since   JDK1.1
+     * @deprecated The definition of this call depends on {@link #suspend},
+     *             which is deprecated.  Further, the behavior of this call
+     *             was never specified.
+     */
+    @Deprecated
+    public boolean allowThreadSuspension(boolean b) {
+        this.vmAllowSuspension = b;
+        if (!b) {
+            VM.unsuspendSomeThreads();
+        }
+        return true;
+    }
+
+    /**
+     * Returns a string representation of this Thread group.
+     *
+     * @return  a string representation of this thread group.
+     * @since   JDK1.0
+     */
+    public String toString() {
+        return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
+    }
+}
diff --git a/java/lang/ThreadLocal.annotated.java b/java/lang/ThreadLocal.annotated.java
new file mode 100644
index 0000000..b8cf527
--- /dev/null
+++ b/java/lang/ThreadLocal.annotated.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.lang.ref.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ThreadLocal<T> {
+
+public ThreadLocal() { throw new RuntimeException("Stub!"); }
+
[email protected] protected T initialValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <S> java.lang.ThreadLocal<S> withInitial(@libcore.util.NonNull java.util.function.Supplier<? extends S> supplier) { throw new RuntimeException("Stub!"); }
+
[email protected] public T get() { throw new RuntimeException("Stub!"); }
+
+public void set(@libcore.util.NullFromTypeParam T value) { throw new RuntimeException("Stub!"); }
+
+public void remove() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/ThreadLocal.java b/java/lang/ThreadLocal.java
new file mode 100644
index 0000000..c29ce7e
--- /dev/null
+++ b/java/lang/ThreadLocal.java
@@ -0,0 +1,722 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+import java.lang.ref.*;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+/**
+ * This class provides thread-local variables.  These variables differ from
+ * their normal counterparts in that each thread that accesses one (via its
+ * {@code get} or {@code set} method) has its own, independently initialized
+ * copy of the variable.  {@code ThreadLocal} instances are typically private
+ * static fields in classes that wish to associate state with a thread (e.g.,
+ * a user ID or Transaction ID).
+ *
+ * <p>For example, the class below generates unique identifiers local to each
+ * thread.
+ * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
+ * and remains unchanged on subsequent calls.
+ * <pre>
+ * import java.util.concurrent.atomic.AtomicInteger;
+ *
+ * public class ThreadId {
+ *     // Atomic integer containing the next thread ID to be assigned
+ *     private static final AtomicInteger nextId = new AtomicInteger(0);
+ *
+ *     // Thread local variable containing each thread's ID
+ *     private static final ThreadLocal&lt;Integer&gt; threadId =
+ *         new ThreadLocal&lt;Integer&gt;() {
+ *             &#64;Override protected Integer initialValue() {
+ *                 return nextId.getAndIncrement();
+ *         }
+ *     };
+ *
+ *     // Returns the current thread's unique ID, assigning it if necessary
+ *     public static int get() {
+ *         return threadId.get();
+ *     }
+ * }
+ * </pre>
+ * <p>Each thread holds an implicit reference to its copy of a thread-local
+ * variable as long as the thread is alive and the {@code ThreadLocal}
+ * instance is accessible; after a thread goes away, all of its copies of
+ * thread-local instances are subject to garbage collection (unless other
+ * references to these copies exist).
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @since   1.2
+ */
+public class ThreadLocal<T> {
+    /**
+     * ThreadLocals rely on per-thread linear-probe hash maps attached
+     * to each thread (Thread.threadLocals and
+     * inheritableThreadLocals).  The ThreadLocal objects act as keys,
+     * searched via threadLocalHashCode.  This is a custom hash code
+     * (useful only within ThreadLocalMaps) that eliminates collisions
+     * in the common case where consecutively constructed ThreadLocals
+     * are used by the same threads, while remaining well-behaved in
+     * less common cases.
+     */
+    private final int threadLocalHashCode = nextHashCode();
+
+    /**
+     * The next hash code to be given out. Updated atomically. Starts at
+     * zero.
+     */
+    private static AtomicInteger nextHashCode =
+        new AtomicInteger();
+
+    /**
+     * The difference between successively generated hash codes - turns
+     * implicit sequential thread-local IDs into near-optimally spread
+     * multiplicative hash values for power-of-two-sized tables.
+     */
+    private static final int HASH_INCREMENT = 0x61c88647;
+
+    /**
+     * Returns the next hash code.
+     */
+    private static int nextHashCode() {
+        return nextHashCode.getAndAdd(HASH_INCREMENT);
+    }
+
+    /**
+     * Returns the current thread's "initial value" for this
+     * thread-local variable.  This method will be invoked the first
+     * time a thread accesses the variable with the {@link #get}
+     * method, unless the thread previously invoked the {@link #set}
+     * method, in which case the {@code initialValue} method will not
+     * be invoked for the thread.  Normally, this method is invoked at
+     * most once per thread, but it may be invoked again in case of
+     * subsequent invocations of {@link #remove} followed by {@link #get}.
+     *
+     * <p>This implementation simply returns {@code null}; if the
+     * programmer desires thread-local variables to have an initial
+     * value other than {@code null}, {@code ThreadLocal} must be
+     * subclassed, and this method overridden.  Typically, an
+     * anonymous inner class will be used.
+     *
+     * @return the initial value for this thread-local
+     */
+    protected T initialValue() {
+        return null;
+    }
+
+    /**
+     * Creates a thread local variable. The initial value of the variable is
+     * determined by invoking the {@code get} method on the {@code Supplier}.
+     *
+     * @param <S> the type of the thread local's value
+     * @param supplier the supplier to be used to determine the initial value
+     * @return a new thread local variable
+     * @throws NullPointerException if the specified supplier is null
+     * @since 1.8
+     */
+    public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
+        return new SuppliedThreadLocal<>(supplier);
+    }
+
+    /**
+     * Creates a thread local variable.
+     * @see #withInitial(java.util.function.Supplier)
+     */
+    public ThreadLocal() {
+    }
+
+    /**
+     * Returns the value in the current thread's copy of this
+     * thread-local variable.  If the variable has no value for the
+     * current thread, it is first initialized to the value returned
+     * by an invocation of the {@link #initialValue} method.
+     *
+     * @return the current thread's value of this thread-local
+     */
+    public T get() {
+        Thread t = Thread.currentThread();
+        ThreadLocalMap map = getMap(t);
+        if (map != null) {
+            ThreadLocalMap.Entry e = map.getEntry(this);
+            if (e != null) {
+                @SuppressWarnings("unchecked")
+                T result = (T)e.value;
+                return result;
+            }
+        }
+        return setInitialValue();
+    }
+
+    /**
+     * Variant of set() to establish initialValue. Used instead
+     * of set() in case user has overridden the set() method.
+     *
+     * @return the initial value
+     */
+    private T setInitialValue() {
+        T value = initialValue();
+        Thread t = Thread.currentThread();
+        ThreadLocalMap map = getMap(t);
+        if (map != null)
+            map.set(this, value);
+        else
+            createMap(t, value);
+        return value;
+    }
+
+    /**
+     * Sets the current thread's copy of this thread-local variable
+     * to the specified value.  Most subclasses will have no need to
+     * override this method, relying solely on the {@link #initialValue}
+     * method to set the values of thread-locals.
+     *
+     * @param value the value to be stored in the current thread's copy of
+     *        this thread-local.
+     */
+    public void set(T value) {
+        Thread t = Thread.currentThread();
+        ThreadLocalMap map = getMap(t);
+        if (map != null)
+            map.set(this, value);
+        else
+            createMap(t, value);
+    }
+
+    /**
+     * Removes the current thread's value for this thread-local
+     * variable.  If this thread-local variable is subsequently
+     * {@linkplain #get read} by the current thread, its value will be
+     * reinitialized by invoking its {@link #initialValue} method,
+     * unless its value is {@linkplain #set set} by the current thread
+     * in the interim.  This may result in multiple invocations of the
+     * {@code initialValue} method in the current thread.
+     *
+     * @since 1.5
+     */
+     public void remove() {
+         ThreadLocalMap m = getMap(Thread.currentThread());
+         if (m != null)
+             m.remove(this);
+     }
+
+    /**
+     * Get the map associated with a ThreadLocal. Overridden in
+     * InheritableThreadLocal.
+     *
+     * @param  t the current thread
+     * @return the map
+     */
+    ThreadLocalMap getMap(Thread t) {
+        return t.threadLocals;
+    }
+
+    /**
+     * Create the map associated with a ThreadLocal. Overridden in
+     * InheritableThreadLocal.
+     *
+     * @param t the current thread
+     * @param firstValue value for the initial entry of the map
+     */
+    void createMap(Thread t, T firstValue) {
+        t.threadLocals = new ThreadLocalMap(this, firstValue);
+    }
+
+    /**
+     * Factory method to create map of inherited thread locals.
+     * Designed to be called only from Thread constructor.
+     *
+     * @param  parentMap the map associated with parent thread
+     * @return a map containing the parent's inheritable bindings
+     */
+    static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
+        return new ThreadLocalMap(parentMap);
+    }
+
+    /**
+     * Method childValue is visibly defined in subclass
+     * InheritableThreadLocal, but is internally defined here for the
+     * sake of providing createInheritedMap factory method without
+     * needing to subclass the map class in InheritableThreadLocal.
+     * This technique is preferable to the alternative of embedding
+     * instanceof tests in methods.
+     */
+    T childValue(T parentValue) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * An extension of ThreadLocal that obtains its initial value from
+     * the specified {@code Supplier}.
+     */
+    static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {
+
+        private final Supplier<? extends T> supplier;
+
+        SuppliedThreadLocal(Supplier<? extends T> supplier) {
+            this.supplier = Objects.requireNonNull(supplier);
+        }
+
+        @Override
+        protected T initialValue() {
+            return supplier.get();
+        }
+    }
+
+    /**
+     * ThreadLocalMap is a customized hash map suitable only for
+     * maintaining thread local values. No operations are exported
+     * outside of the ThreadLocal class. The class is package private to
+     * allow declaration of fields in class Thread.  To help deal with
+     * very large and long-lived usages, the hash table entries use
+     * WeakReferences for keys. However, since reference queues are not
+     * used, stale entries are guaranteed to be removed only when
+     * the table starts running out of space.
+     */
+    static class ThreadLocalMap {
+
+        /**
+         * The entries in this hash map extend WeakReference, using
+         * its main ref field as the key (which is always a
+         * ThreadLocal object).  Note that null keys (i.e. entry.get()
+         * == null) mean that the key is no longer referenced, so the
+         * entry can be expunged from table.  Such entries are referred to
+         * as "stale entries" in the code that follows.
+         */
+        static class Entry extends WeakReference<ThreadLocal<?>> {
+            /** The value associated with this ThreadLocal. */
+            Object value;
+
+            Entry(ThreadLocal<?> k, Object v) {
+                super(k);
+                value = v;
+            }
+        }
+
+        /**
+         * The initial capacity -- MUST be a power of two.
+         */
+        private static final int INITIAL_CAPACITY = 16;
+
+        /**
+         * The table, resized as necessary.
+         * table.length MUST always be a power of two.
+         */
+        private Entry[] table;
+
+        /**
+         * The number of entries in the table.
+         */
+        private int size = 0;
+
+        /**
+         * The next size value at which to resize.
+         */
+        private int threshold; // Default to 0
+
+        /**
+         * Set the resize threshold to maintain at worst a 2/3 load factor.
+         */
+        private void setThreshold(int len) {
+            threshold = len * 2 / 3;
+        }
+
+        /**
+         * Increment i modulo len.
+         */
+        private static int nextIndex(int i, int len) {
+            return ((i + 1 < len) ? i + 1 : 0);
+        }
+
+        /**
+         * Decrement i modulo len.
+         */
+        private static int prevIndex(int i, int len) {
+            return ((i - 1 >= 0) ? i - 1 : len - 1);
+        }
+
+        /**
+         * Construct a new map initially containing (firstKey, firstValue).
+         * ThreadLocalMaps are constructed lazily, so we only create
+         * one when we have at least one entry to put in it.
+         */
+        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
+            table = new Entry[INITIAL_CAPACITY];
+            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
+            table[i] = new Entry(firstKey, firstValue);
+            size = 1;
+            setThreshold(INITIAL_CAPACITY);
+        }
+
+        /**
+         * Construct a new map including all Inheritable ThreadLocals
+         * from given parent map. Called only by createInheritedMap.
+         *
+         * @param parentMap the map associated with parent thread.
+         */
+        private ThreadLocalMap(ThreadLocalMap parentMap) {
+            Entry[] parentTable = parentMap.table;
+            int len = parentTable.length;
+            setThreshold(len);
+            table = new Entry[len];
+
+            for (int j = 0; j < len; j++) {
+                Entry e = parentTable[j];
+                if (e != null) {
+                    @SuppressWarnings("unchecked")
+                    ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
+                    if (key != null) {
+                        Object value = key.childValue(e.value);
+                        Entry c = new Entry(key, value);
+                        int h = key.threadLocalHashCode & (len - 1);
+                        while (table[h] != null)
+                            h = nextIndex(h, len);
+                        table[h] = c;
+                        size++;
+                    }
+                }
+            }
+        }
+
+        /**
+         * Get the entry associated with key.  This method
+         * itself handles only the fast path: a direct hit of existing
+         * key. It otherwise relays to getEntryAfterMiss.  This is
+         * designed to maximize performance for direct hits, in part
+         * by making this method readily inlinable.
+         *
+         * @param  key the thread local object
+         * @return the entry associated with key, or null if no such
+         */
+        private Entry getEntry(ThreadLocal<?> key) {
+            int i = key.threadLocalHashCode & (table.length - 1);
+            Entry e = table[i];
+            if (e != null && e.get() == key)
+                return e;
+            else
+                return getEntryAfterMiss(key, i, e);
+        }
+
+        /**
+         * Version of getEntry method for use when key is not found in
+         * its direct hash slot.
+         *
+         * @param  key the thread local object
+         * @param  i the table index for key's hash code
+         * @param  e the entry at table[i]
+         * @return the entry associated with key, or null if no such
+         */
+        private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
+            Entry[] tab = table;
+            int len = tab.length;
+
+            while (e != null) {
+                ThreadLocal<?> k = e.get();
+                if (k == key)
+                    return e;
+                if (k == null)
+                    expungeStaleEntry(i);
+                else
+                    i = nextIndex(i, len);
+                e = tab[i];
+            }
+            return null;
+        }
+
+        /**
+         * Set the value associated with key.
+         *
+         * @param key the thread local object
+         * @param value the value to be set
+         */
+        private void set(ThreadLocal<?> key, Object value) {
+
+            // We don't use a fast path as with get() because it is at
+            // least as common to use set() to create new entries as
+            // it is to replace existing ones, in which case, a fast
+            // path would fail more often than not.
+
+            Entry[] tab = table;
+            int len = tab.length;
+            int i = key.threadLocalHashCode & (len-1);
+
+            for (Entry e = tab[i];
+                 e != null;
+                 e = tab[i = nextIndex(i, len)]) {
+                ThreadLocal<?> k = e.get();
+
+                if (k == key) {
+                    e.value = value;
+                    return;
+                }
+
+                if (k == null) {
+                    replaceStaleEntry(key, value, i);
+                    return;
+                }
+            }
+
+            tab[i] = new Entry(key, value);
+            int sz = ++size;
+            if (!cleanSomeSlots(i, sz) && sz >= threshold)
+                rehash();
+        }
+
+        /**
+         * Remove the entry for key.
+         */
+        private void remove(ThreadLocal<?> key) {
+            Entry[] tab = table;
+            int len = tab.length;
+            int i = key.threadLocalHashCode & (len-1);
+            for (Entry e = tab[i];
+                 e != null;
+                 e = tab[i = nextIndex(i, len)]) {
+                if (e.get() == key) {
+                    e.clear();
+                    expungeStaleEntry(i);
+                    return;
+                }
+            }
+        }
+
+        /**
+         * Replace a stale entry encountered during a set operation
+         * with an entry for the specified key.  The value passed in
+         * the value parameter is stored in the entry, whether or not
+         * an entry already exists for the specified key.
+         *
+         * As a side effect, this method expunges all stale entries in the
+         * "run" containing the stale entry.  (A run is a sequence of entries
+         * between two null slots.)
+         *
+         * @param  key the key
+         * @param  value the value to be associated with key
+         * @param  staleSlot index of the first stale entry encountered while
+         *         searching for key.
+         */
+        private void replaceStaleEntry(ThreadLocal<?> key, Object value,
+                                       int staleSlot) {
+            Entry[] tab = table;
+            int len = tab.length;
+            Entry e;
+
+            // Back up to check for prior stale entry in current run.
+            // We clean out whole runs at a time to avoid continual
+            // incremental rehashing due to garbage collector freeing
+            // up refs in bunches (i.e., whenever the collector runs).
+            int slotToExpunge = staleSlot;
+            for (int i = prevIndex(staleSlot, len);
+                 (e = tab[i]) != null;
+                 i = prevIndex(i, len))
+                if (e.get() == null)
+                    slotToExpunge = i;
+
+            // Find either the key or trailing null slot of run, whichever
+            // occurs first
+            for (int i = nextIndex(staleSlot, len);
+                 (e = tab[i]) != null;
+                 i = nextIndex(i, len)) {
+                ThreadLocal<?> k = e.get();
+
+                // If we find key, then we need to swap it
+                // with the stale entry to maintain hash table order.
+                // The newly stale slot, or any other stale slot
+                // encountered above it, can then be sent to expungeStaleEntry
+                // to remove or rehash all of the other entries in run.
+                if (k == key) {
+                    e.value = value;
+
+                    tab[i] = tab[staleSlot];
+                    tab[staleSlot] = e;
+
+                    // Start expunge at preceding stale entry if it exists
+                    if (slotToExpunge == staleSlot)
+                        slotToExpunge = i;
+                    cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
+                    return;
+                }
+
+                // If we didn't find stale entry on backward scan, the
+                // first stale entry seen while scanning for key is the
+                // first still present in the run.
+                if (k == null && slotToExpunge == staleSlot)
+                    slotToExpunge = i;
+            }
+
+            // If key not found, put new entry in stale slot
+            tab[staleSlot].value = null;
+            tab[staleSlot] = new Entry(key, value);
+
+            // If there are any other stale entries in run, expunge them
+            if (slotToExpunge != staleSlot)
+                cleanSomeSlots(expungeStaleEntry(slotToExpunge), len);
+        }
+
+        /**
+         * Expunge a stale entry by rehashing any possibly colliding entries
+         * lying between staleSlot and the next null slot.  This also expunges
+         * any other stale entries encountered before the trailing null.  See
+         * Knuth, Section 6.4
+         *
+         * @param staleSlot index of slot known to have null key
+         * @return the index of the next null slot after staleSlot
+         * (all between staleSlot and this slot will have been checked
+         * for expunging).
+         */
+        private int expungeStaleEntry(int staleSlot) {
+            Entry[] tab = table;
+            int len = tab.length;
+
+            // expunge entry at staleSlot
+            tab[staleSlot].value = null;
+            tab[staleSlot] = null;
+            size--;
+
+            // Rehash until we encounter null
+            Entry e;
+            int i;
+            for (i = nextIndex(staleSlot, len);
+                 (e = tab[i]) != null;
+                 i = nextIndex(i, len)) {
+                ThreadLocal<?> k = e.get();
+                if (k == null) {
+                    e.value = null;
+                    tab[i] = null;
+                    size--;
+                } else {
+                    int h = k.threadLocalHashCode & (len - 1);
+                    if (h != i) {
+                        tab[i] = null;
+
+                        // Unlike Knuth 6.4 Algorithm R, we must scan until
+                        // null because multiple entries could have been stale.
+                        while (tab[h] != null)
+                            h = nextIndex(h, len);
+                        tab[h] = e;
+                    }
+                }
+            }
+            return i;
+        }
+
+        /**
+         * Heuristically scan some cells looking for stale entries.
+         * This is invoked when either a new element is added, or
+         * another stale one has been expunged. It performs a
+         * logarithmic number of scans, as a balance between no
+         * scanning (fast but retains garbage) and a number of scans
+         * proportional to number of elements, that would find all
+         * garbage but would cause some insertions to take O(n) time.
+         *
+         * @param i a position known NOT to hold a stale entry. The
+         * scan starts at the element after i.
+         *
+         * @param n scan control: {@code log2(n)} cells are scanned,
+         * unless a stale entry is found, in which case
+         * {@code log2(table.length)-1} additional cells are scanned.
+         * When called from insertions, this parameter is the number
+         * of elements, but when from replaceStaleEntry, it is the
+         * table length. (Note: all this could be changed to be either
+         * more or less aggressive by weighting n instead of just
+         * using straight log n. But this version is simple, fast, and
+         * seems to work well.)
+         *
+         * @return true if any stale entries have been removed.
+         */
+        private boolean cleanSomeSlots(int i, int n) {
+            boolean removed = false;
+            Entry[] tab = table;
+            int len = tab.length;
+            do {
+                i = nextIndex(i, len);
+                Entry e = tab[i];
+                if (e != null && e.get() == null) {
+                    n = len;
+                    removed = true;
+                    i = expungeStaleEntry(i);
+                }
+            } while ( (n >>>= 1) != 0);
+            return removed;
+        }
+
+        /**
+         * Re-pack and/or re-size the table. First scan the entire
+         * table removing stale entries. If this doesn't sufficiently
+         * shrink the size of the table, double the table size.
+         */
+        private void rehash() {
+            expungeStaleEntries();
+
+            // Use lower threshold for doubling to avoid hysteresis
+            if (size >= threshold - threshold / 4)
+                resize();
+        }
+
+        /**
+         * Double the capacity of the table.
+         */
+        private void resize() {
+            Entry[] oldTab = table;
+            int oldLen = oldTab.length;
+            int newLen = oldLen * 2;
+            Entry[] newTab = new Entry[newLen];
+            int count = 0;
+
+            for (int j = 0; j < oldLen; ++j) {
+                Entry e = oldTab[j];
+                if (e != null) {
+                    ThreadLocal<?> k = e.get();
+                    if (k == null) {
+                        e.value = null; // Help the GC
+                    } else {
+                        int h = k.threadLocalHashCode & (newLen - 1);
+                        while (newTab[h] != null)
+                            h = nextIndex(h, newLen);
+                        newTab[h] = e;
+                        count++;
+                    }
+                }
+            }
+
+            setThreshold(newLen);
+            size = count;
+            table = newTab;
+        }
+
+        /**
+         * Expunge all stale entries in the table.
+         */
+        private void expungeStaleEntries() {
+            Entry[] tab = table;
+            int len = tab.length;
+            for (int j = 0; j < len; j++) {
+                Entry e = tab[j];
+                if (e != null && e.get() == null)
+                    expungeStaleEntry(j);
+            }
+        }
+    }
+}
diff --git a/java/lang/Throwable.annotated.java b/java/lang/Throwable.annotated.java
new file mode 100644
index 0000000..f6cef0c
--- /dev/null
+++ b/java/lang/Throwable.annotated.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang;
+
+import java.io.*;
+import java.util.*;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Throwable implements java.io.Serializable {
+
+public Throwable() { throw new RuntimeException("Stub!"); }
+
+public Throwable(@libcore.util.Nullable java.lang.String message) { throw new RuntimeException("Stub!"); }
+
+public Throwable(@libcore.util.Nullable java.lang.String message, @libcore.util.Nullable java.lang.Throwable cause) { throw new RuntimeException("Stub!"); }
+
+public Throwable(@libcore.util.Nullable java.lang.Throwable cause) { throw new RuntimeException("Stub!"); }
+
+protected Throwable(@libcore.util.Nullable java.lang.String message, @libcore.util.Nullable java.lang.Throwable cause, boolean enableSuppression, boolean writableStackTrace) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getMessage() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getLocalizedMessage() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.Throwable getCause() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.Throwable initCause(@libcore.util.Nullable java.lang.Throwable cause) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public void printStackTrace() { throw new RuntimeException("Stub!"); }
+
+public void printStackTrace(@libcore.util.NonNull java.io.PrintStream s) { throw new RuntimeException("Stub!"); }
+
+public void printStackTrace(@libcore.util.NonNull java.io.PrintWriter s) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.Throwable fillInStackTrace() { throw new RuntimeException("Stub!"); }
+
+public [email protected] StackTraceElement @libcore.util.NonNull [] getStackTrace() { throw new RuntimeException("Stub!"); }
+
+public void setStackTrace([email protected] StackTraceElement @libcore.util.NonNull [] stackTrace) { throw new RuntimeException("Stub!"); }
+
+public final synchronized void addSuppressed(@libcore.util.NonNull java.lang.Throwable exception) { throw new RuntimeException("Stub!"); }
+
+public final synchronized [email protected] Throwable @libcore.util.NonNull [] getSuppressed() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/Throwable.java b/java/lang/Throwable.java
new file mode 100644
index 0000000..5a3f8a8
--- /dev/null
+++ b/java/lang/Throwable.java
@@ -0,0 +1,1134 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+import dalvik.annotation.optimization.FastNative;
+import  java.io.*;
+import  java.util.*;
+
+/**
+ * The {@code Throwable} class is the superclass of all errors and
+ * exceptions in the Java language. Only objects that are instances of this
+ * class (or one of its subclasses) are thrown by the Java Virtual Machine or
+ * can be thrown by the Java {@code throw} statement. Similarly, only
+ * this class or one of its subclasses can be the argument type in a
+ * {@code catch} clause.
+ *
+ * For the purposes of compile-time checking of exceptions, {@code
+ * Throwable} and any subclass of {@code Throwable} that is not also a
+ * subclass of either {@link RuntimeException} or {@link Error} are
+ * regarded as checked exceptions.
+ *
+ * <p>Instances of two subclasses, {@link java.lang.Error} and
+ * {@link java.lang.Exception}, are conventionally used to indicate
+ * that exceptional situations have occurred. Typically, these instances
+ * are freshly created in the context of the exceptional situation so
+ * as to include relevant information (such as stack trace data).
+ *
+ * <p>A throwable contains a snapshot of the execution stack of its
+ * thread at the time it was created. It can also contain a message
+ * string that gives more information about the error. Over time, a
+ * throwable can {@linkplain Throwable#addSuppressed suppress} other
+ * throwables from being propagated.  Finally, the throwable can also
+ * contain a <i>cause</i>: another throwable that caused this
+ * throwable to be constructed.  The recording of this causal information
+ * is referred to as the <i>chained exception</i> facility, as the
+ * cause can, itself, have a cause, and so on, leading to a "chain" of
+ * exceptions, each caused by another.
+ *
+ * <p>One reason that a throwable may have a cause is that the class that
+ * throws it is built atop a lower layered abstraction, and an operation on
+ * the upper layer fails due to a failure in the lower layer.  It would be bad
+ * design to let the throwable thrown by the lower layer propagate outward, as
+ * it is generally unrelated to the abstraction provided by the upper layer.
+ * Further, doing so would tie the API of the upper layer to the details of
+ * its implementation, assuming the lower layer's exception was a checked
+ * exception.  Throwing a "wrapped exception" (i.e., an exception containing a
+ * cause) allows the upper layer to communicate the details of the failure to
+ * its caller without incurring either of these shortcomings.  It preserves
+ * the flexibility to change the implementation of the upper layer without
+ * changing its API (in particular, the set of exceptions thrown by its
+ * methods).
+ *
+ * <p>A second reason that a throwable may have a cause is that the method
+ * that throws it must conform to a general-purpose interface that does not
+ * permit the method to throw the cause directly.  For example, suppose
+ * a persistent collection conforms to the {@link java.util.Collection
+ * Collection} interface, and that its persistence is implemented atop
+ * {@code java.io}.  Suppose the internals of the {@code add} method
+ * can throw an {@link java.io.IOException IOException}.  The implementation
+ * can communicate the details of the {@code IOException} to its caller
+ * while conforming to the {@code Collection} interface by wrapping the
+ * {@code IOException} in an appropriate unchecked exception.  (The
+ * specification for the persistent collection should indicate that it is
+ * capable of throwing such exceptions.)
+ *
+ * <p>A cause can be associated with a throwable in two ways: via a
+ * constructor that takes the cause as an argument, or via the
+ * {@link #initCause(Throwable)} method.  New throwable classes that
+ * wish to allow causes to be associated with them should provide constructors
+ * that take a cause and delegate (perhaps indirectly) to one of the
+ * {@code Throwable} constructors that takes a cause.
+ *
+ * Because the {@code initCause} method is public, it allows a cause to be
+ * associated with any throwable, even a "legacy throwable" whose
+ * implementation predates the addition of the exception chaining mechanism to
+ * {@code Throwable}.
+ *
+ * <p>By convention, class {@code Throwable} and its subclasses have two
+ * constructors, one that takes no arguments and one that takes a
+ * {@code String} argument that can be used to produce a detail message.
+ * Further, those subclasses that might likely have a cause associated with
+ * them should have two more constructors, one that takes a
+ * {@code Throwable} (the cause), and one that takes a
+ * {@code String} (the detail message) and a {@code Throwable} (the
+ * cause).
+ *
+ * @author  unascribed
+ * @author  Josh Bloch (Added exception chaining and programmatic access to
+ *          stack trace in 1.4.)
+ * @jls 11.2 Compile-Time Checking of Exceptions
+ * @since JDK1.0
+ */
+public class Throwable implements Serializable {
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -3042686055658047285L;
+
+    /**
+     * Native code saves some indication of the stack backtrace in this slot.
+     */
+    private transient Object backtrace;
+
+    /**
+     * Specific details about the Throwable.  For example, for
+     * {@code FileNotFoundException}, this contains the name of
+     * the file that could not be found.
+     *
+     * @serial
+     */
+    private String detailMessage;
+
+
+    /**
+     * Holder class to defer initializing sentinel objects only used
+     * for serialization.
+     */
+    private static class SentinelHolder {
+        /**
+         * {@linkplain #setStackTrace(StackTraceElement[]) Setting the
+         * stack trace} to a one-element array containing this sentinel
+         * value indicates future attempts to set the stack trace will be
+         * ignored.  The sentinal is equal to the result of calling:<br>
+         * {@code new StackTraceElement("", "", null, Integer.MIN_VALUE)}
+         */
+        public static final StackTraceElement STACK_TRACE_ELEMENT_SENTINEL =
+            new StackTraceElement("", "", null, Integer.MIN_VALUE);
+
+        /**
+         * Sentinel value used in the serial form to indicate an immutable
+         * stack trace.
+         */
+        public static final StackTraceElement[] STACK_TRACE_SENTINEL =
+            new StackTraceElement[] {STACK_TRACE_ELEMENT_SENTINEL};
+    }
+
+    // Android-removed: Use libcore.util.EmptyArray for the empty stack trace
+    // Adding the constant UNASSIGNED_STACK breaks serialization of some subclasses
+    // /**
+    //  * A shared value for an empty stack.
+    //  */
+    // private static final StackTraceElement[] UNASSIGNED_STACK = new StackTraceElement[0];
+
+    /*
+     * To allow Throwable objects to be made immutable and safely
+     * reused by the JVM, such as OutOfMemoryErrors, fields of
+     * Throwable that are writable in response to user actions, cause,
+     * stackTrace, and suppressedExceptions obey the following
+     * protocol:
+     *
+     * 1) The fields are initialized to a non-null sentinel value
+     * which indicates the value has logically not been set.
+     *
+     * 2) Writing a null to the field indicates further writes
+     * are forbidden
+     *
+     * 3) The sentinel value may be replaced with another non-null
+     * value.
+     *
+     * For example, implementations of the HotSpot JVM have
+     * preallocated OutOfMemoryError objects to provide for better
+     * diagnosability of that situation.  These objects are created
+     * without calling the constructor for that class and the fields
+     * in question are initialized to null.  To support this
+     * capability, any new fields added to Throwable that require
+     * being initialized to a non-null value require a coordinated JVM
+     * change.
+     */
+
+    /**
+     * The throwable that caused this throwable to get thrown, or null if this
+     * throwable was not caused by another throwable, or if the causative
+     * throwable is unknown.  If this field is equal to this throwable itself,
+     * it indicates that the cause of this throwable has not yet been
+     * initialized.
+     *
+     * @serial
+     * @since 1.4
+     */
+    private Throwable cause = this;
+
+    /**
+     * The stack trace, as returned by {@link #getStackTrace()}.
+     *
+     * The field is initialized to a zero-length array.  A {@code
+     * null} value of this field indicates subsequent calls to {@link
+     * #setStackTrace(StackTraceElement[])} and {@link
+     * #fillInStackTrace()} will be be no-ops.
+     *
+     * @serial
+     * @since 1.4
+     */
+    // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+    // private StackTraceElement[] stackTrace = UNASSIGNED_STACK;
+    private StackTraceElement[] stackTrace = libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
+
+    // Android-removed: Use empty collection in place of SUPPRESSED_SENTINEL
+    // Adding this constant breaks serialization of some subclasses
+    /*
+    // Setting this static field introduces an acceptable
+    // initialization dependency on a few java.util classes.
+    private static final List<Throwable> SUPPRESSED_SENTINEL =
+        Collections.unmodifiableList(new ArrayList<Throwable>(0));
+    */
+
+    /**
+     * The list of suppressed exceptions, as returned by {@link
+     * #getSuppressed()}.  The list is initialized to a zero-element
+     * unmodifiable sentinel list.  When a serialized Throwable is
+     * read in, if the {@code suppressedExceptions} field points to a
+     * zero-element list, the field is reset to the sentinel value.
+     *
+     * @serial
+     * @since 1.7
+     */
+    // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+    // private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;
+    private List<Throwable> suppressedExceptions = Collections.emptyList();
+
+    /** Message for trying to suppress a null exception. */
+    private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
+
+    /** Message for trying to suppress oneself. */
+    private static final String SELF_SUPPRESSION_MESSAGE = "Self-suppression not permitted";
+
+    /** Caption  for labeling causative exception stack traces */
+    private static final String CAUSE_CAPTION = "Caused by: ";
+
+    /** Caption for labeling suppressed exception stack traces */
+    private static final String SUPPRESSED_CAPTION = "Suppressed: ";
+
+    /**
+     * Constructs a new throwable with {@code null} as its detail message.
+     * The cause is not initialized, and may subsequently be initialized by a
+     * call to {@link #initCause}.
+     *
+     * <p>The {@link #fillInStackTrace()} method is called to initialize
+     * the stack trace data in the newly created throwable.
+     */
+    public Throwable() {
+        fillInStackTrace();
+    }
+
+    /**
+     * Constructs a new throwable with the specified detail message.  The
+     * cause is not initialized, and may subsequently be initialized by
+     * a call to {@link #initCause}.
+     *
+     * <p>The {@link #fillInStackTrace()} method is called to initialize
+     * the stack trace data in the newly created throwable.
+     *
+     * @param   message   the detail message. The detail message is saved for
+     *          later retrieval by the {@link #getMessage()} method.
+     */
+    public Throwable(String message) {
+        fillInStackTrace();
+        detailMessage = message;
+    }
+
+    /**
+     * Constructs a new throwable with the specified detail message and
+     * cause.  <p>Note that the detail message associated with
+     * {@code cause} is <i>not</i> automatically incorporated in
+     * this throwable's detail message.
+     *
+     * <p>The {@link #fillInStackTrace()} method is called to initialize
+     * the stack trace data in the newly created throwable.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public Throwable(String message, Throwable cause) {
+        fillInStackTrace();
+        detailMessage = message;
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs a new throwable with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}).
+     * This constructor is useful for throwables that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * <p>The {@link #fillInStackTrace()} method is called to initialize
+     * the stack trace data in the newly created throwable.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.4
+     */
+    public Throwable(Throwable cause) {
+        fillInStackTrace();
+        detailMessage = (cause==null ? null : cause.toString());
+        this.cause = cause;
+    }
+
+    /**
+     * Constructs a new throwable with the specified detail message,
+     * cause, {@linkplain #addSuppressed suppression} enabled or
+     * disabled, and writable stack trace enabled or disabled.  If
+     * suppression is disabled, {@link #getSuppressed} for this object
+     * will return a zero-length array and calls to {@link
+     * #addSuppressed} that would otherwise append an exception to the
+     * suppressed list will have no effect.  If the writable stack
+     * trace is false, this constructor will not call {@link
+     * #fillInStackTrace()}, a {@code null} will be written to the
+     * {@code stackTrace} field, and subsequent calls to {@code
+     * fillInStackTrace} and {@link
+     * #setStackTrace(StackTraceElement[])} will not set the stack
+     * trace.  If the writable stack trace is false, {@link
+     * #getStackTrace} will return a zero length array.
+     *
+     * <p>Note that the other constructors of {@code Throwable} treat
+     * suppression as being enabled and the stack trace as being
+     * writable.  Subclasses of {@code Throwable} should document any
+     * conditions under which suppression is disabled and document
+     * conditions under which the stack trace is not writable.
+     * Disabling of suppression should only occur in exceptional
+     * circumstances where special requirements exist, such as a
+     * virtual machine reusing exception objects under low-memory
+     * situations.  Circumstances where a given exception object is
+     * repeatedly caught and rethrown, such as to implement control
+     * flow between two sub-systems, is another situation where
+     * immutable throwable objects would be appropriate.
+     *
+     * @param  message the detail message.
+     * @param cause the cause.  (A {@code null} value is permitted,
+     * and indicates that the cause is nonexistent or unknown.)
+     * @param enableSuppression whether or not suppression is enabled or disabled
+     * @param writableStackTrace whether or not the stack trace should be
+     *                           writable
+     *
+     * @see OutOfMemoryError
+     * @see NullPointerException
+     * @see ArithmeticException
+     * @since 1.7
+     */
+    protected Throwable(String message, Throwable cause,
+                        boolean enableSuppression,
+                        boolean writableStackTrace) {
+        if (writableStackTrace) {
+            fillInStackTrace();
+        } else {
+            stackTrace = null;
+        }
+        detailMessage = message;
+        this.cause = cause;
+        if (!enableSuppression)
+            suppressedExceptions = null;
+    }
+
+    /**
+     * Returns the detail message string of this throwable.
+     *
+     * @return  the detail message string of this {@code Throwable} instance
+     *          (which may be {@code null}).
+     */
+    public String getMessage() {
+        return detailMessage;
+    }
+
+    /**
+     * Creates a localized description of this throwable.
+     * Subclasses may override this method in order to produce a
+     * locale-specific message.  For subclasses that do not override this
+     * method, the default implementation returns the same result as
+     * {@code getMessage()}.
+     *
+     * @return  The localized description of this throwable.
+     * @since   JDK1.1
+     */
+    public String getLocalizedMessage() {
+        return getMessage();
+    }
+
+    /**
+     * Returns the cause of this throwable or {@code null} if the
+     * cause is nonexistent or unknown.  (The cause is the throwable that
+     * caused this throwable to get thrown.)
+     *
+     * <p>This implementation returns the cause that was supplied via one of
+     * the constructors requiring a {@code Throwable}, or that was set after
+     * creation with the {@link #initCause(Throwable)} method.  While it is
+     * typically unnecessary to override this method, a subclass can override
+     * it to return a cause set by some other means.  This is appropriate for
+     * a "legacy chained throwable" that predates the addition of chained
+     * exceptions to {@code Throwable}.  Note that it is <i>not</i>
+     * necessary to override any of the {@code PrintStackTrace} methods,
+     * all of which invoke the {@code getCause} method to determine the
+     * cause of a throwable.
+     *
+     * @return  the cause of this throwable or {@code null} if the
+     *          cause is nonexistent or unknown.
+     * @since 1.4
+     */
+    public synchronized Throwable getCause() {
+        return (cause==this ? null : cause);
+    }
+
+    /**
+     * Initializes the <i>cause</i> of this throwable to the specified value.
+     * (The cause is the throwable that caused this throwable to get thrown.)
+     *
+     * <p>This method can be called at most once.  It is generally called from
+     * within the constructor, or immediately after creating the
+     * throwable.  If this throwable was created
+     * with {@link #Throwable(Throwable)} or
+     * {@link #Throwable(String,Throwable)}, this method cannot be called
+     * even once.
+     *
+     * <p>An example of using this method on a legacy throwable type
+     * without other support for setting the cause is:
+     *
+     * <pre>
+     * try {
+     *     lowLevelOp();
+     * } catch (LowLevelException le) {
+     *     throw (HighLevelException)
+     *           new HighLevelException().initCause(le); // Legacy constructor
+     * }
+     * </pre>
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @return  a reference to this {@code Throwable} instance.
+     * @throws IllegalArgumentException if {@code cause} is this
+     *         throwable.  (A throwable cannot be its own cause.)
+     * @throws IllegalStateException if this throwable was
+     *         created with {@link #Throwable(Throwable)} or
+     *         {@link #Throwable(String,Throwable)}, or this method has already
+     *         been called on this throwable.
+     * @since  1.4
+     */
+    public synchronized Throwable initCause(Throwable cause) {
+        if (this.cause != this)
+            throw new IllegalStateException("Can't overwrite cause with " +
+                                            Objects.toString(cause, "a null"), this);
+        if (cause == this)
+            throw new IllegalArgumentException("Self-causation not permitted", this);
+        this.cause = cause;
+        return this;
+    }
+
+    /**
+     * Returns a short description of this throwable.
+     * The result is the concatenation of:
+     * <ul>
+     * <li> the {@linkplain Class#getName() name} of the class of this object
+     * <li> ": " (a colon and a space)
+     * <li> the result of invoking this object's {@link #getLocalizedMessage}
+     *      method
+     * </ul>
+     * If {@code getLocalizedMessage} returns {@code null}, then just
+     * the class name is returned.
+     *
+     * @return a string representation of this throwable.
+     */
+    public String toString() {
+        String s = getClass().getName();
+        String message = getLocalizedMessage();
+        return (message != null) ? (s + ": " + message) : s;
+    }
+
+    /**
+     * Prints this throwable and its backtrace to the
+     * standard error stream. This method prints a stack trace for this
+     * {@code Throwable} object on the error output stream that is
+     * the value of the field {@code System.err}. The first line of
+     * output contains the result of the {@link #toString()} method for
+     * this object.  Remaining lines represent data previously recorded by
+     * the method {@link #fillInStackTrace()}. The format of this
+     * information depends on the implementation, but the following
+     * example may be regarded as typical:
+     * <blockquote><pre>
+     * java.lang.NullPointerException
+     *         at MyClass.mash(MyClass.java:9)
+     *         at MyClass.crunch(MyClass.java:6)
+     *         at MyClass.main(MyClass.java:3)
+     * </pre></blockquote>
+     * This example was produced by running the program:
+     * <pre>
+     * class MyClass {
+     *     public static void main(String[] args) {
+     *         crunch(null);
+     *     }
+     *     static void crunch(int[] a) {
+     *         mash(a);
+     *     }
+     *     static void mash(int[] b) {
+     *         System.out.println(b[0]);
+     *     }
+     * }
+     * </pre>
+     * The backtrace for a throwable with an initialized, non-null cause
+     * should generally include the backtrace for the cause.  The format
+     * of this information depends on the implementation, but the following
+     * example may be regarded as typical:
+     * <pre>
+     * HighLevelException: MidLevelException: LowLevelException
+     *         at Junk.a(Junk.java:13)
+     *         at Junk.main(Junk.java:4)
+     * Caused by: MidLevelException: LowLevelException
+     *         at Junk.c(Junk.java:23)
+     *         at Junk.b(Junk.java:17)
+     *         at Junk.a(Junk.java:11)
+     *         ... 1 more
+     * Caused by: LowLevelException
+     *         at Junk.e(Junk.java:30)
+     *         at Junk.d(Junk.java:27)
+     *         at Junk.c(Junk.java:21)
+     *         ... 3 more
+     * </pre>
+     * Note the presence of lines containing the characters {@code "..."}.
+     * These lines indicate that the remainder of the stack trace for this
+     * exception matches the indicated number of frames from the bottom of the
+     * stack trace of the exception that was caused by this exception (the
+     * "enclosing" exception).  This shorthand can greatly reduce the length
+     * of the output in the common case where a wrapped exception is thrown
+     * from same method as the "causative exception" is caught.  The above
+     * example was produced by running the program:
+     * <pre>
+     * public class Junk {
+     *     public static void main(String args[]) {
+     *         try {
+     *             a();
+     *         } catch(HighLevelException e) {
+     *             e.printStackTrace();
+     *         }
+     *     }
+     *     static void a() throws HighLevelException {
+     *         try {
+     *             b();
+     *         } catch(MidLevelException e) {
+     *             throw new HighLevelException(e);
+     *         }
+     *     }
+     *     static void b() throws MidLevelException {
+     *         c();
+     *     }
+     *     static void c() throws MidLevelException {
+     *         try {
+     *             d();
+     *         } catch(LowLevelException e) {
+     *             throw new MidLevelException(e);
+     *         }
+     *     }
+     *     static void d() throws LowLevelException {
+     *        e();
+     *     }
+     *     static void e() throws LowLevelException {
+     *         throw new LowLevelException();
+     *     }
+     * }
+     *
+     * class HighLevelException extends Exception {
+     *     HighLevelException(Throwable cause) { super(cause); }
+     * }
+     *
+     * class MidLevelException extends Exception {
+     *     MidLevelException(Throwable cause)  { super(cause); }
+     * }
+     *
+     * class LowLevelException extends Exception {
+     * }
+     * </pre>
+     * As of release 7, the platform supports the notion of
+     * <i>suppressed exceptions</i> (in conjunction with the {@code
+     * try}-with-resources statement). Any exceptions that were
+     * suppressed in order to deliver an exception are printed out
+     * beneath the stack trace.  The format of this information
+     * depends on the implementation, but the following example may be
+     * regarded as typical:
+     *
+     * <pre>
+     * Exception in thread "main" java.lang.Exception: Something happened
+     *  at Foo.bar(Foo.java:10)
+     *  at Foo.main(Foo.java:5)
+     *  Suppressed: Resource$CloseFailException: Resource ID = 0
+     *          at Resource.close(Resource.java:26)
+     *          at Foo.bar(Foo.java:9)
+     *          ... 1 more
+     * </pre>
+     * Note that the "... n more" notation is used on suppressed exceptions
+     * just at it is used on causes. Unlike causes, suppressed exceptions are
+     * indented beyond their "containing exceptions."
+     *
+     * <p>An exception can have both a cause and one or more suppressed
+     * exceptions:
+     * <pre>
+     * Exception in thread "main" java.lang.Exception: Main block
+     *  at Foo3.main(Foo3.java:7)
+     *  Suppressed: Resource$CloseFailException: Resource ID = 2
+     *          at Resource.close(Resource.java:26)
+     *          at Foo3.main(Foo3.java:5)
+     *  Suppressed: Resource$CloseFailException: Resource ID = 1
+     *          at Resource.close(Resource.java:26)
+     *          at Foo3.main(Foo3.java:5)
+     * Caused by: java.lang.Exception: I did it
+     *  at Foo3.main(Foo3.java:8)
+     * </pre>
+     * Likewise, a suppressed exception can have a cause:
+     * <pre>
+     * Exception in thread "main" java.lang.Exception: Main block
+     *  at Foo4.main(Foo4.java:6)
+     *  Suppressed: Resource2$CloseFailException: Resource ID = 1
+     *          at Resource2.close(Resource2.java:20)
+     *          at Foo4.main(Foo4.java:5)
+     *  Caused by: java.lang.Exception: Rats, you caught me
+     *          at Resource2$CloseFailException.&lt;init&gt;(Resource2.java:45)
+     *          ... 2 more
+     * </pre>
+     */
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+
+    /**
+     * Prints this throwable and its backtrace to the specified print stream.
+     *
+     * @param s {@code PrintStream} to use for output
+     */
+    public void printStackTrace(PrintStream s) {
+        printStackTrace(new WrappedPrintStream(s));
+    }
+
+    private void printStackTrace(PrintStreamOrWriter s) {
+        // Guard against malicious overrides of Throwable.equals by
+        // using a Set with identity equality semantics.
+        Set<Throwable> dejaVu =
+            Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
+        dejaVu.add(this);
+
+        synchronized (s.lock()) {
+            // Print our stack trace
+            s.println(this);
+            StackTraceElement[] trace = getOurStackTrace();
+            for (StackTraceElement traceElement : trace)
+                s.println("\tat " + traceElement);
+
+            // Print suppressed exceptions, if any
+            for (Throwable se : getSuppressed())
+                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
+
+            // Print cause, if any
+            Throwable ourCause = getCause();
+            if (ourCause != null)
+                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
+        }
+    }
+
+    /**
+     * Print our stack trace as an enclosed exception for the specified
+     * stack trace.
+     */
+    private void printEnclosedStackTrace(PrintStreamOrWriter s,
+                                         StackTraceElement[] enclosingTrace,
+                                         String caption,
+                                         String prefix,
+                                         Set<Throwable> dejaVu) {
+        // Android-removed: Use of assert keyword which breaks serialization of some subclasses
+        // (Using assert adds a static field that determines whether assertions are enabled.)
+        // assert Thread.holdsLock(s.lock());
+        if (dejaVu.contains(this)) {
+            s.println("\t[CIRCULAR REFERENCE:" + this + "]");
+        } else {
+            dejaVu.add(this);
+            // Compute number of frames in common between this and enclosing trace
+            StackTraceElement[] trace = getOurStackTrace();
+            int m = trace.length - 1;
+            int n = enclosingTrace.length - 1;
+            while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
+                m--; n--;
+            }
+            int framesInCommon = trace.length - 1 - m;
+
+            // Print our stack trace
+            s.println(prefix + caption + this);
+            for (int i = 0; i <= m; i++)
+                s.println(prefix + "\tat " + trace[i]);
+            if (framesInCommon != 0)
+                s.println(prefix + "\t... " + framesInCommon + " more");
+
+            // Print suppressed exceptions, if any
+            for (Throwable se : getSuppressed())
+                se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
+                                           prefix +"\t", dejaVu);
+
+            // Print cause, if any
+            Throwable ourCause = getCause();
+            if (ourCause != null)
+                ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
+        }
+    }
+
+    /**
+     * Prints this throwable and its backtrace to the specified
+     * print writer.
+     *
+     * @param s {@code PrintWriter} to use for output
+     * @since   JDK1.1
+     */
+    public void printStackTrace(PrintWriter s) {
+        printStackTrace(new WrappedPrintWriter(s));
+    }
+
+    /**
+     * Wrapper class for PrintStream and PrintWriter to enable a single
+     * implementation of printStackTrace.
+     */
+    private abstract static class PrintStreamOrWriter {
+        /** Returns the object to be locked when using this StreamOrWriter */
+        abstract Object lock();
+
+        /** Prints the specified string as a line on this StreamOrWriter */
+        abstract void println(Object o);
+    }
+
+    private static class WrappedPrintStream extends PrintStreamOrWriter {
+        private final PrintStream printStream;
+
+        WrappedPrintStream(PrintStream printStream) {
+            this.printStream = printStream;
+        }
+
+        Object lock() {
+            return printStream;
+        }
+
+        void println(Object o) {
+            printStream.println(o);
+        }
+    }
+
+    private static class WrappedPrintWriter extends PrintStreamOrWriter {
+        private final PrintWriter printWriter;
+
+        WrappedPrintWriter(PrintWriter printWriter) {
+            this.printWriter = printWriter;
+        }
+
+        Object lock() {
+            return printWriter;
+        }
+
+        void println(Object o) {
+            printWriter.println(o);
+        }
+    }
+
+    /**
+     * Fills in the execution stack trace. This method records within this
+     * {@code Throwable} object information about the current state of
+     * the stack frames for the current thread.
+     *
+     * <p>If the stack trace of this {@code Throwable} {@linkplain
+     * Throwable#Throwable(String, Throwable, boolean, boolean) is not
+     * writable}, calling this method has no effect.
+     *
+     * @return  a reference to this {@code Throwable} instance.
+     * @see     java.lang.Throwable#printStackTrace()
+     */
+    public synchronized Throwable fillInStackTrace() {
+        if (stackTrace != null ||
+            backtrace != null /* Out of protocol state */ ) {
+            // Android-changed: Use Android-specific nativeFillInStackTrace
+            // fillInStackTrace(0);
+            backtrace = nativeFillInStackTrace();
+            // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+            // stackTrace = UNASSIGNED_STACK;
+            stackTrace = libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
+        }
+        return this;
+    }
+
+    // Android-changed: Use Android-specific nativeFillInStackTrace
+    // private native Throwable fillInStackTrace(int dummy);
+    @FastNative
+    private static native Object nativeFillInStackTrace();
+
+    /**
+     * Provides programmatic access to the stack trace information printed by
+     * {@link #printStackTrace()}.  Returns an array of stack trace elements,
+     * each representing one stack frame.  The zeroth element of the array
+     * (assuming the array's length is non-zero) represents the top of the
+     * stack, which is the last method invocation in the sequence.  Typically,
+     * this is the point at which this throwable was created and thrown.
+     * The last element of the array (assuming the array's length is non-zero)
+     * represents the bottom of the stack, which is the first method invocation
+     * in the sequence.
+     *
+     * <p>Some virtual machines may, under some circumstances, omit one
+     * or more stack frames from the stack trace.  In the extreme case,
+     * a virtual machine that has no stack trace information concerning
+     * this throwable is permitted to return a zero-length array from this
+     * method.  Generally speaking, the array returned by this method will
+     * contain one element for every frame that would be printed by
+     * {@code printStackTrace}.  Writes to the returned array do not
+     * affect future calls to this method.
+     *
+     * @return an array of stack trace elements representing the stack trace
+     *         pertaining to this throwable.
+     * @since  1.4
+     */
+    public StackTraceElement[] getStackTrace() {
+        return getOurStackTrace().clone();
+    }
+
+    private synchronized StackTraceElement[] getOurStackTrace() {
+        // Initialize stack trace field with information from
+        // backtrace if this is the first call to this method
+        // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+        // if (stackTrace == UNASSIGNED_STACK ||
+        if (stackTrace == libcore.util.EmptyArray.STACK_TRACE_ELEMENT ||
+            (stackTrace == null && backtrace != null) /* Out of protocol state */) {
+            // BEGIN Android-changed: Use Android-specific nativeGetStackTrace
+            // int depth = getStackTraceDepth();
+            // stackTrace = new StackTraceElement[depth];
+            // for (int i=0; i < depth; i++)
+            //     stackTrace[i] = getStackTraceElement(i);
+            stackTrace = nativeGetStackTrace(backtrace);
+            backtrace = null;
+            if (stackTrace == null) {
+                return libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
+            }
+            // END Android-changed: Use Android-specific nativeGetStackTrace
+        } else if (stackTrace == null) {
+            // Android-changed: Use libcore.util.EmptyArray for the empty stack trace
+            // return UNASSIGNED_STACK;
+            return libcore.util.EmptyArray.STACK_TRACE_ELEMENT;
+        }
+        return stackTrace;
+    }
+
+    /**
+     * Sets the stack trace elements that will be returned by
+     * {@link #getStackTrace()} and printed by {@link #printStackTrace()}
+     * and related methods.
+     *
+     * This method, which is designed for use by RPC frameworks and other
+     * advanced systems, allows the client to override the default
+     * stack trace that is either generated by {@link #fillInStackTrace()}
+     * when a throwable is constructed or deserialized when a throwable is
+     * read from a serialization stream.
+     *
+     * <p>If the stack trace of this {@code Throwable} {@linkplain
+     * Throwable#Throwable(String, Throwable, boolean, boolean) is not
+     * writable}, calling this method has no effect other than
+     * validating its argument.
+     *
+     * @param   stackTrace the stack trace elements to be associated with
+     * this {@code Throwable}.  The specified array is copied by this
+     * call; changes in the specified array after the method invocation
+     * returns will have no affect on this {@code Throwable}'s stack
+     * trace.
+     *
+     * @throws NullPointerException if {@code stackTrace} is
+     *         {@code null} or if any of the elements of
+     *         {@code stackTrace} are {@code null}
+     *
+     * @since  1.4
+     */
+    public void setStackTrace(StackTraceElement[] stackTrace) {
+        // Validate argument
+        StackTraceElement[] defensiveCopy = stackTrace.clone();
+        for (int i = 0; i < defensiveCopy.length; i++) {
+            if (defensiveCopy[i] == null)
+                throw new NullPointerException("stackTrace[" + i + "]");
+        }
+
+        synchronized (this) {
+            if (this.stackTrace == null && // Immutable stack
+                backtrace == null) // Test for out of protocol state
+                return;
+            this.stackTrace = defensiveCopy;
+        }
+    }
+
+    // Android-removed: Unused native method getStackTraceDepth()
+    // /**
+    //  * Returns the number of elements in the stack trace (or 0 if the stack
+    //  * trace is unavailable).
+    //  *
+    //  * package-protection for use by SharedSecrets.
+    //  */
+    // native int getStackTraceDepth();
+
+    /**
+     * Returns the specified element of the stack trace.
+     *
+     * package-protection for use by SharedSecrets.
+     *
+     * @param index index of the element to return.
+     * @throws IndexOutOfBoundsException if {@code index < 0 ||
+     *         index >= getStackTraceDepth() }
+     */
+    // Android-changed: Use Android-specific nativeGetStackTrace
+    // native StackTraceElement getStackTraceElement(int index);
+    @FastNative
+    private static native StackTraceElement[] nativeGetStackTrace(Object stackState);
+
+
+    /**
+     * Reads a {@code Throwable} from a stream, enforcing
+     * well-formedness constraints on fields.  Null entries and
+     * self-pointers are not allowed in the list of {@code
+     * suppressedExceptions}.  Null entries are not allowed for stack
+     * trace elements.  A null stack trace in the serial form results
+     * in a zero-length stack element array. A single-element stack
+     * trace whose entry is equal to {@code new StackTraceElement("",
+     * "", null, Integer.MIN_VALUE)} results in a {@code null} {@code
+     * stackTrace} field.
+     *
+     * Note that there are no constraints on the value the {@code
+     * cause} field can hold; both {@code null} and {@code this} are
+     * valid values for the field.
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+        s.defaultReadObject();     // read in all fields
+        if (suppressedExceptions != null) {
+            List<Throwable> suppressed = null;
+            if (suppressedExceptions.isEmpty()) {
+                // Use the sentinel for a zero-length list
+                // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+                // suppressed = SUPPRESSED_SENTINEL;
+                suppressed = Collections.emptyList();
+            } else { // Copy Throwables to new list
+                suppressed = new ArrayList<>(1);
+                for (Throwable t : suppressedExceptions) {
+                    // Enforce constraints on suppressed exceptions in
+                    // case of corrupt or malicious stream.
+                    if (t == null)
+                        throw new NullPointerException(NULL_CAUSE_MESSAGE);
+                    if (t == this)
+                        throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
+                    suppressed.add(t);
+                }
+            }
+            suppressedExceptions = suppressed;
+        } // else a null suppressedExceptions field remains null
+
+        /*
+         * For zero-length stack traces, use a clone of
+         * UNASSIGNED_STACK rather than UNASSIGNED_STACK itself to
+         * allow identity comparison against UNASSIGNED_STACK in
+         * getOurStackTrace.  The identity of UNASSIGNED_STACK in
+         * stackTrace indicates to the getOurStackTrace method that
+         * the stackTrace needs to be constructed from the information
+         * in backtrace.
+         */
+        if (stackTrace != null) {
+            if (stackTrace.length == 0) {
+                // Android-removed: clone() call not needed because of libcore.util.EmptyArray usage
+                // stackTrace = UNASSIGNED_STACK.clone();
+            }  else if (stackTrace.length == 1 &&
+                        // Check for the marker of an immutable stack trace
+                        SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(stackTrace[0])) {
+                stackTrace = null;
+            } else { // Verify stack trace elements are non-null.
+                for(StackTraceElement ste : stackTrace) {
+                    if (ste == null)
+                        throw new NullPointerException("null StackTraceElement in serial stream. ");
+                }
+            }
+        } else {
+            // A null stackTrace field in the serial form can result
+            // from an exception serialized without that field in
+            // older JDK releases; treat such exceptions as having
+            // empty stack traces.
+            // Android-changed: Directly create empty array instead of cloning UNASSIGNED_STACK
+            // stackTrace = UNASSIGNED_STACK.clone();
+            stackTrace = new StackTraceElement[0];
+        }
+    }
+
+    /**
+     * Write a {@code Throwable} object to a stream.
+     *
+     * A {@code null} stack trace field is represented in the serial
+     * form as a one-element array whose element is equal to {@code
+     * new StackTraceElement("", "", null, Integer.MIN_VALUE)}.
+     */
+    private synchronized void writeObject(ObjectOutputStream s)
+        throws IOException {
+        // Ensure that the stackTrace field is initialized to a
+        // non-null value, if appropriate.  As of JDK 7, a null stack
+        // trace field is a valid value indicating the stack trace
+        // should not be set.
+        getOurStackTrace();
+
+        StackTraceElement[] oldStackTrace = stackTrace;
+        try {
+            if (stackTrace == null)
+                stackTrace = SentinelHolder.STACK_TRACE_SENTINEL;
+            s.defaultWriteObject();
+        } finally {
+            stackTrace = oldStackTrace;
+        }
+    }
+
+    /**
+     * Appends the specified exception to the exceptions that were
+     * suppressed in order to deliver this exception. This method is
+     * thread-safe and typically called (automatically and implicitly)
+     * by the {@code try}-with-resources statement.
+     *
+     * <p>The suppression behavior is enabled <em>unless</em> disabled
+     * {@linkplain #Throwable(String, Throwable, boolean, boolean) via
+     * a constructor}.  When suppression is disabled, this method does
+     * nothing other than to validate its argument.
+     *
+     * <p>Note that when one exception {@linkplain
+     * #initCause(Throwable) causes} another exception, the first
+     * exception is usually caught and then the second exception is
+     * thrown in response.  In other words, there is a causal
+     * connection between the two exceptions.
+     *
+     * In contrast, there are situations where two independent
+     * exceptions can be thrown in sibling code blocks, in particular
+     * in the {@code try} block of a {@code try}-with-resources
+     * statement and the compiler-generated {@code finally} block
+     * which closes the resource.
+     *
+     * In these situations, only one of the thrown exceptions can be
+     * propagated.  In the {@code try}-with-resources statement, when
+     * there are two such exceptions, the exception originating from
+     * the {@code try} block is propagated and the exception from the
+     * {@code finally} block is added to the list of exceptions
+     * suppressed by the exception from the {@code try} block.  As an
+     * exception unwinds the stack, it can accumulate multiple
+     * suppressed exceptions.
+     *
+     * <p>An exception may have suppressed exceptions while also being
+     * caused by another exception.  Whether or not an exception has a
+     * cause is semantically known at the time of its creation, unlike
+     * whether or not an exception will suppress other exceptions
+     * which is typically only determined after an exception is
+     * thrown.
+     *
+     * <p>Note that programmer written code is also able to take
+     * advantage of calling this method in situations where there are
+     * multiple sibling exceptions and only one can be propagated.
+     *
+     * @param exception the exception to be added to the list of
+     *        suppressed exceptions
+     * @throws IllegalArgumentException if {@code exception} is this
+     *         throwable; a throwable cannot suppress itself.
+     * @throws NullPointerException if {@code exception} is {@code null}
+     * @since 1.7
+     */
+    public final synchronized void addSuppressed(Throwable exception) {
+        if (exception == this)
+            throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception);
+
+        if (exception == null)
+            throw new NullPointerException(NULL_CAUSE_MESSAGE);
+
+        if (suppressedExceptions == null) // Suppressed exceptions not recorded
+            return;
+
+        // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+        // if (suppressedExceptions == SUPPRESSED_SENTINEL)
+        if (suppressedExceptions.isEmpty())
+            suppressedExceptions = new ArrayList<>(1);
+
+        suppressedExceptions.add(exception);
+    }
+
+    // Android-changed: Lazily initialize EMPTY_THROWABLE_ARRAY
+    // private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
+    private static Throwable[] EMPTY_THROWABLE_ARRAY;
+
+    /**
+     * Returns an array containing all of the exceptions that were
+     * suppressed, typically by the {@code try}-with-resources
+     * statement, in order to deliver this exception.
+     *
+     * If no exceptions were suppressed or {@linkplain
+     * #Throwable(String, Throwable, boolean, boolean) suppression is
+     * disabled}, an empty array is returned.  This method is
+     * thread-safe.  Writes to the returned array do not affect future
+     * calls to this method.
+     *
+     * @return an array containing all of the exceptions that were
+     *         suppressed to deliver this exception.
+     * @since 1.7
+     */
+    public final synchronized Throwable[] getSuppressed() {
+        // Android-added: Lazily initialize EMPTY_THROWABLE_ARRAY
+        if (EMPTY_THROWABLE_ARRAY == null) {
+            EMPTY_THROWABLE_ARRAY = new Throwable[0];
+        }
+
+        // Android-changed: Use empty collection in place of SUPPRESSED_SENTINEL
+        // if (suppressedExceptions == SUPPRESSED_SENTINEL ||
+        //    suppressedExceptions == null)
+        if (suppressedExceptions == null || suppressedExceptions.isEmpty())
+            return EMPTY_THROWABLE_ARRAY;
+        else
+            return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
+    }
+}
diff --git a/java/lang/TypeNotPresentException.java b/java/lang/TypeNotPresentException.java
new file mode 100644
index 0000000..65a0207
--- /dev/null
+++ b/java/lang/TypeNotPresentException.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an application tries to access a type using a string
+ * representing the type's name, but no definition for the type with
+ * the specified name can be found.   This exception differs from
+ * {@link ClassNotFoundException} in that <tt>ClassNotFoundException</tt> is a
+ * checked exception, whereas this exception is unchecked.
+ *
+ * <p>Note that this exception may be used when undefined type variables
+ * are accessed as well as when types (e.g., classes, interfaces or
+ * annotation types) are loaded.
+ * In particular, this exception can be thrown by the {@linkplain
+ * java.lang.reflect.AnnotatedElement API used to read annotations
+ * reflectively}.
+ *
+ * @author  Josh Bloch
+ * @see     java.lang.reflect.AnnotatedElement
+ * @since 1.5
+ */
+public class TypeNotPresentException extends RuntimeException {
+    private static final long serialVersionUID = -5101214195716534496L;
+
+    private String typeName;
+
+    /**
+     * Constructs a <tt>TypeNotPresentException</tt> for the named type
+     * with the specified cause.
+     *
+     * @param typeName the fully qualified name of the unavailable type
+     * @param cause the exception that was thrown when the system attempted to
+     *    load the named type, or <tt>null</tt> if unavailable or inapplicable
+     */
+    public TypeNotPresentException(String typeName, Throwable cause) {
+        super("Type " + typeName + " not present", cause);
+        this.typeName = typeName;
+    }
+
+    /**
+     * Returns the fully qualified name of the unavailable type.
+     *
+     * @return the fully qualified name of the unavailable type
+     */
+    public String typeName() { return typeName;}
+}
diff --git a/java/lang/UNIXProcess.java b/java/lang/UNIXProcess.java
new file mode 100644
index 0000000..40fd8bb
--- /dev/null
+++ b/java/lang/UNIXProcess.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadFactory;
+import java.security.AccessController;
+import static java.security.AccessController.doPrivileged;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * java.lang.Process subclass in the UNIX environment.
+ *
+ * @author Mario Wolczko and Ross Knippel.
+ * @author Konstantin Kladko (ported to Linux)
+ * @author Martin Buchholz
+ */
+final class UNIXProcess extends Process {
+    private final int pid;
+    private int exitcode;
+    private boolean hasExited;
+
+    private /* final */ OutputStream stdin;
+    private /* final */ InputStream  stdout;
+    private /* final */ InputStream  stderr;
+
+    /* this is for the reaping thread */
+    private native int waitForProcessExit(int pid);
+
+    /**
+     * Create a process using fork(2) and exec(2).
+     *
+     * @param fds an array of three file descriptors.
+     *        Indexes 0, 1, and 2 correspond to standard input,
+     *        standard output and standard error, respectively.  On
+     *        input, a value of -1 means to create a pipe to connect
+     *        child and parent processes.  On output, a value which
+     *        is not -1 is the parent pipe fd corresponding to the
+     *        pipe which has been created.  An element of this array
+     *        is -1 on input if and only if it is <em>not</em> -1 on
+     *        output.
+     * @return the pid of the subprocess
+     */
+    private native int forkAndExec(byte[] prog,
+                                   byte[] argBlock, int argc,
+                                   byte[] envBlock, int envc,
+                                   byte[] dir,
+                                   int[] fds,
+                                   boolean redirectErrorStream)
+        throws IOException;
+
+    /**
+     * The thread factory used to create "process reaper" daemon threads.
+     */
+    private static class ProcessReaperThreadFactory implements ThreadFactory {
+        private final static ThreadGroup group = getRootThreadGroup();
+
+        private static ThreadGroup getRootThreadGroup() {
+            return doPrivileged(new PrivilegedAction<ThreadGroup> () {
+                public ThreadGroup run() {
+                    ThreadGroup root = Thread.currentThread().getThreadGroup();
+                    while (root.getParent() != null)
+                        root = root.getParent();
+                    return root;
+                }});
+        }
+
+        public Thread newThread(Runnable grimReaper) {
+            // Our thread stack requirement is quite modest.
+            Thread t = new Thread(group, grimReaper, "process reaper", 32768);
+            t.setDaemon(true);
+            // A small attempt (probably futile) to avoid priority inversion
+            t.setPriority(Thread.MAX_PRIORITY);
+            return t;
+        }
+    }
+
+    /**
+     * The thread pool of "process reaper" daemon threads.
+     */
+    private static final Executor processReaperExecutor =
+        doPrivileged(new PrivilegedAction<Executor>() {
+            public Executor run() {
+                return Executors.newCachedThreadPool
+                    (new ProcessReaperThreadFactory());
+            }});
+
+    UNIXProcess(final byte[] prog,
+                final byte[] argBlock, final int argc,
+                final byte[] envBlock, final int envc,
+                final byte[] dir,
+                final int[] fds,
+                final boolean redirectErrorStream)
+            throws IOException {
+
+        pid = forkAndExec(prog,
+                          argBlock, argc,
+                          envBlock, envc,
+                          dir,
+                          fds,
+                          redirectErrorStream);
+
+        try {
+            doPrivileged(new PrivilegedExceptionAction<Void>() {
+                public Void run() throws IOException {
+                    initStreams(fds);
+                    return null;
+                }});
+        } catch (PrivilegedActionException ex) {
+            throw (IOException) ex.getException();
+        }
+    }
+
+    static FileDescriptor newFileDescriptor(int fd) {
+        FileDescriptor fileDescriptor = new FileDescriptor();
+        fileDescriptor.setInt$(fd);
+        return fileDescriptor;
+    }
+
+    void initStreams(int[] fds) throws IOException {
+        stdin = (fds[0] == -1) ?
+            ProcessBuilder.NullOutputStream.INSTANCE :
+            new ProcessPipeOutputStream(fds[0]);
+
+        stdout = (fds[1] == -1) ?
+            ProcessBuilder.NullInputStream.INSTANCE :
+            new ProcessPipeInputStream(fds[1]);
+
+        stderr = (fds[2] == -1) ?
+            ProcessBuilder.NullInputStream.INSTANCE :
+            new ProcessPipeInputStream(fds[2]);
+
+        processReaperExecutor.execute(new Runnable() {
+            public void run() {
+                int exitcode = waitForProcessExit(pid);
+                UNIXProcess.this.processExited(exitcode);
+            }});
+    }
+
+    void processExited(int exitcode) {
+        synchronized (this) {
+            this.exitcode = exitcode;
+            hasExited = true;
+            notifyAll();
+        }
+
+        if (stdout instanceof ProcessPipeInputStream)
+            ((ProcessPipeInputStream) stdout).processExited();
+
+        if (stderr instanceof ProcessPipeInputStream)
+            ((ProcessPipeInputStream) stderr).processExited();
+
+        if (stdin instanceof ProcessPipeOutputStream)
+            ((ProcessPipeOutputStream) stdin).processExited();
+    }
+
+    public OutputStream getOutputStream() {
+        return stdin;
+    }
+
+    public InputStream getInputStream() {
+        return stdout;
+    }
+
+    public InputStream getErrorStream() {
+        return stderr;
+    }
+
+    public synchronized int waitFor() throws InterruptedException {
+        while (!hasExited) {
+            wait();
+        }
+        return exitcode;
+    }
+
+    public synchronized int exitValue() {
+        if (!hasExited) {
+            throw new IllegalThreadStateException("process hasn't exited");
+        }
+        return exitcode;
+    }
+
+    private static native void destroyProcess(int pid);
+    public void destroy() {
+        // There is a risk that pid will be recycled, causing us to
+        // kill the wrong process!  So we only terminate processes
+        // that appear to still be running.  Even with this check,
+        // there is an unavoidable race condition here, but the window
+        // is very small, and OSes try hard to not recycle pids too
+        // soon, so this is quite safe.
+        synchronized (this) {
+            if (!hasExited)
+                destroyProcess(pid);
+        }
+        try { stdin.close();  } catch (IOException ignored) {}
+        try { stdout.close(); } catch (IOException ignored) {}
+        try { stderr.close(); } catch (IOException ignored) {}
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("Process[pid=");
+        sb.append(pid);
+        if (hasExited) {
+            sb.append(" ,hasExited=true, exitcode=");
+            sb.append(exitcode);
+            sb.append("]");
+        } else {
+            sb.append(", hasExited=false]");
+        }
+
+        return sb.toString();
+    }
+
+    /* This routine initializes JNI field offsets for the class */
+    private static native void initIDs();
+
+    static {
+        initIDs();
+    }
+
+    /**
+     * A buffered input stream for a subprocess pipe file descriptor
+     * that allows the underlying file descriptor to be reclaimed when
+     * the process exits, via the processExited hook.
+     *
+     * This is tricky because we do not want the user-level InputStream to be
+     * closed until the user invokes close(), and we need to continue to be
+     * able to read any buffered data lingering in the OS pipe buffer.
+     */
+    static class ProcessPipeInputStream extends BufferedInputStream {
+        ProcessPipeInputStream(int fd) {
+            super(new FileInputStream(newFileDescriptor(fd), true /* isFdOwner */));
+        }
+
+        private static byte[] drainInputStream(InputStream in)
+                throws IOException {
+            if (in == null) return null;
+            int n = 0;
+            int j;
+            byte[] a = null;
+            while ((j = in.available()) > 0) {
+                a = (a == null) ? new byte[j] : Arrays.copyOf(a, n + j);
+                n += in.read(a, n, j);
+            }
+            return (a == null || n == a.length) ? a : Arrays.copyOf(a, n);
+        }
+
+        /** Called by the process reaper thread when the process exits. */
+        synchronized void processExited() {
+            // Most BufferedInputStream methods are synchronized, but close()
+            // is not, and so we have to handle concurrent racing close().
+            try {
+                InputStream in = this.in;
+                if (in != null) {
+                    byte[] stragglers = drainInputStream(in);
+                    in.close();
+                    this.in = (stragglers == null) ?
+                        ProcessBuilder.NullInputStream.INSTANCE :
+                        new ByteArrayInputStream(stragglers);
+                    if (buf == null) // asynchronous close()?
+                        this.in = null;
+                }
+            } catch (IOException ignored) {
+                // probably an asynchronous close().
+            }
+        }
+    }
+
+    /**
+     * A buffered output stream for a subprocess pipe file descriptor
+     * that allows the underlying file descriptor to be reclaimed when
+     * the process exits, via the processExited hook.
+     */
+    static class ProcessPipeOutputStream extends BufferedOutputStream {
+        ProcessPipeOutputStream(int fd) {
+            super(new FileOutputStream(newFileDescriptor(fd), true /* isFdOwner */));
+        }
+
+        /** Called by the process reaper thread when the process exits. */
+        synchronized void processExited() {
+            OutputStream out = this.out;
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException ignored) {
+                    // We know of no reason to get an IOException, but if
+                    // we do, there's nothing else to do but carry on.
+                }
+                this.out = ProcessBuilder.NullOutputStream.INSTANCE;
+            }
+        }
+    }
+}
diff --git a/java/lang/UnknownError.java b/java/lang/UnknownError.java
new file mode 100644
index 0000000..0706f81
--- /dev/null
+++ b/java/lang/UnknownError.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when an unknown but serious exception has occurred in the
+ * Java Virtual Machine.
+ *
+ * @author unascribed
+ * @since   JDK1.0
+ */
+public
+class UnknownError extends VirtualMachineError {
+    private static final long serialVersionUID = 2524784860676771849L;
+
+    /**
+     * Constructs an <code>UnknownError</code> with no detail message.
+     */
+    public UnknownError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>UnknownError</code> with the specified detail
+     * message.
+     *
+     * @param   s   the detail message.
+     */
+    public UnknownError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/UnsatisfiedLinkError.java b/java/lang/UnsatisfiedLinkError.java
new file mode 100644
index 0000000..32a8ba8
--- /dev/null
+++ b/java/lang/UnsatisfiedLinkError.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown if the Java Virtual Machine cannot find an appropriate
+ * native-language definition of a method declared <code>native</code>.
+ *
+ * @author unascribed
+ * @see     java.lang.Runtime
+ * @since   JDK1.0
+ */
+public
+class UnsatisfiedLinkError extends LinkageError {
+    private static final long serialVersionUID = -4019343241616879428L;
+
+    /**
+     * Constructs an <code>UnsatisfiedLinkError</code> with no detail message.
+     */
+    public UnsatisfiedLinkError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>UnsatisfiedLinkError</code> with the
+     * specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public UnsatisfiedLinkError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/UnsupportedClassVersionError.java b/java/lang/UnsupportedClassVersionError.java
new file mode 100644
index 0000000..aed4d04
--- /dev/null
+++ b/java/lang/UnsupportedClassVersionError.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when the Java Virtual Machine attempts to read a class
+ * file and determines that the major and minor version numbers
+ * in the file are not supported.
+ *
+ * @since   1.2
+ */
+public
+class UnsupportedClassVersionError extends ClassFormatError {
+    private static final long serialVersionUID = -7123279212883497373L;
+
+    /**
+     * Constructs a <code>UnsupportedClassVersionError</code>
+     * with no detail message.
+     */
+    public UnsupportedClassVersionError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>UnsupportedClassVersionError</code> with
+     * the specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public UnsupportedClassVersionError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/UnsupportedOperationException.java b/java/lang/UnsupportedOperationException.java
new file mode 100644
index 0000000..fcb355c
--- /dev/null
+++ b/java/lang/UnsupportedOperationException.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that the requested operation is not supported.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @since   1.2
+ */
+public class UnsupportedOperationException extends RuntimeException {
+    /**
+     * Constructs an UnsupportedOperationException with no detail message.
+     */
+    public UnsupportedOperationException() {
+    }
+
+    /**
+     * Constructs an UnsupportedOperationException with the specified
+     * detail message.
+     *
+     * @param message the detail message
+     */
+    public UnsupportedOperationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * <p>Note that the detail message associated with <code>cause</code> is
+     * <i>not</i> automatically incorporated in this exception's detail
+     * message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link Throwable#getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A <tt>null</tt> value
+     *         is permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since 1.5
+     */
+    public UnsupportedOperationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of <tt>(cause==null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     * This constructor is useful for exceptions that are little more than
+     * wrappers for other throwables (for example, {@link
+     * java.security.PrivilegedActionException}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A <tt>null</tt> value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.5
+     */
+    public UnsupportedOperationException(Throwable cause) {
+        super(cause);
+    }
+
+    static final long serialVersionUID = -1242599979055084673L;
+}
diff --git a/java/lang/VMClassLoader.java b/java/lang/VMClassLoader.java
new file mode 100644
index 0000000..d44f888
--- /dev/null
+++ b/java/lang/VMClassLoader.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * 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 dalvik.annotation.optimization.FastNative;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.util.ArrayList;
+import java.util.List;
+import libcore.io.ClassPathURLStreamHandler;
+
+class VMClassLoader {
+
+    private static final ClassPathURLStreamHandler[] bootClassPathUrlHandlers;
+    static {
+        bootClassPathUrlHandlers = createBootClassPathUrlHandlers();
+    }
+
+    /**
+     * Creates an array of ClassPathURLStreamHandler objects for handling resource loading from
+     * the boot classpath.
+     */
+    private static ClassPathURLStreamHandler[] createBootClassPathUrlHandlers() {
+        String[] bootClassPathEntries = getBootClassPathEntries();
+        ArrayList<URLStreamHandler> urlStreamHandlers =
+                new ArrayList<URLStreamHandler>(bootClassPathEntries.length);
+        for (String bootClassPathEntry : bootClassPathEntries) {
+            try {
+                String entryUri = new File(bootClassPathEntry).toURI().toString();
+
+                // We assume all entries are zip or jar files.
+                URLStreamHandler urlStreamHandler =
+                        new ClassPathURLStreamHandler(bootClassPathEntry);
+                urlStreamHandlers.add(urlStreamHandler);
+            } catch (IOException e) {
+                // Skip it
+                System.logE("Unable to open boot classpath entry: " + bootClassPathEntry, e);
+            }
+        }
+        return urlStreamHandlers.toArray(new ClassPathURLStreamHandler[urlStreamHandlers.size()]);
+    }
+
+    /**
+     * Get a resource from a file in the bootstrap class path.
+     *
+     * We assume that the bootclasspath can't change once the VM has started.
+     * This assumption seems to be supported by the spec.
+     */
+    static URL getResource(String name) {
+        for (ClassPathURLStreamHandler urlHandler : bootClassPathUrlHandlers) {
+            URL url = urlHandler.getEntryUrlOrNull(name);
+            if (url != null) {
+                return url;
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Get an enumeration with all matching resources.
+     */
+    static List<URL> getResources(String name) {
+        ArrayList<URL> list = new ArrayList<URL>();
+        for (ClassPathURLStreamHandler urlHandler : bootClassPathUrlHandlers) {
+            URL url = urlHandler.getEntryUrlOrNull(name);
+            if (url != null) {
+                list.add(url);
+            }
+        }
+        return list;
+    }
+
+    @FastNative
+    native static Class findLoadedClass(ClassLoader cl, String name);
+
+    /**
+     * Boot class path manipulation, for getResources().
+     */
+    native private static String[] getBootClassPathEntries();
+
+}
diff --git a/java/lang/VerifyError.java b/java/lang/VerifyError.java
new file mode 100644
index 0000000..9ca9f90
--- /dev/null
+++ b/java/lang/VerifyError.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown when the "verifier" detects that a class file,
+ * though well formed, contains some sort of internal inconsistency
+ * or security problem.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public
+class VerifyError extends LinkageError {
+    private static final long serialVersionUID = 7001962396098498785L;
+
+    /**
+     * Constructs an <code>VerifyError</code> with no detail message.
+     */
+    public VerifyError() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>VerifyError</code> with the specified detail message.
+     *
+     * @param   s   the detail message.
+     */
+    public VerifyError(String s) {
+        super(s);
+    }
+}
diff --git a/java/lang/VirtualMachineError.java b/java/lang/VirtualMachineError.java
new file mode 100644
index 0000000..c0a2a92
--- /dev/null
+++ b/java/lang/VirtualMachineError.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that the Java Virtual Machine is broken or has
+ * run out of resources necessary for it to continue operating.
+ *
+ *
+ * @author  Frank Yellin
+ * @since   JDK1.0
+ */
+abstract public class VirtualMachineError extends Error {
+    private static final long serialVersionUID = 4161983926571568670L;
+
+    /**
+     * Constructs a <code>VirtualMachineError</code> with no detail message.
+     */
+    public VirtualMachineError() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>VirtualMachineError</code> with the specified
+     * detail message.
+     *
+     * @param   message   the detail message.
+     */
+    public VirtualMachineError(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code VirtualMachineError} with the specified
+     * detail message and cause.  <p>Note that the detail message
+     * associated with {@code cause} is <i>not</i> automatically
+     * incorporated in this error's detail message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link #getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.8
+     */
+    public VirtualMachineError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an a {@code VirtualMachineError} with the specified
+     * cause and a detail message of {@code (cause==null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.8
+     */
+    public VirtualMachineError(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/lang/Void.java b/java/lang/Void.java
new file mode 100644
index 0000000..96dbe6d
--- /dev/null
+++ b/java/lang/Void.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * The {@code Void} class is an uninstantiable placeholder class to hold a
+ * reference to the {@code Class} object representing the Java keyword
+ * void.
+ *
+ * @author  unascribed
+ * @since   JDK1.1
+ */
+public final
+class Void {
+
+    /**
+     * The {@code Class} object representing the pseudo-type corresponding to
+     * the keyword {@code void}.
+     */
+    @SuppressWarnings("unchecked")
+    public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void");
+
+    /*
+     * The Void class cannot be instantiated.
+     */
+    private Void() {}
+}
diff --git a/java/lang/annotation/Annotation.java b/java/lang/annotation/Annotation.java
new file mode 100644
index 0000000..7de6746
--- /dev/null
+++ b/java/lang/annotation/Annotation.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * The common interface extended by all annotation types.  Note that an
+ * interface that manually extends this one does <i>not</i> define
+ * an annotation type.  Also note that this interface does not itself
+ * define an annotation type.
+ *
+ * More information about annotation types can be found in section 9.6 of
+ * <cite>The Java&trade; Language Specification</cite>.
+ *
+ * The {@link java.lang.reflect.AnnotatedElement} interface discusses
+ * compatibility concerns when evolving an annotation type from being
+ * non-repeatable to being repeatable.
+ *
+ * @author  Josh Bloch
+ * @since   1.5
+ */
+public interface Annotation {
+    /**
+     * Returns true if the specified object represents an annotation
+     * that is logically equivalent to this one.  In other words,
+     * returns true if the specified object is an instance of the same
+     * annotation type as this instance, all of whose members are equal
+     * to the corresponding member of this annotation, as defined below:
+     * <ul>
+     *    <li>Two corresponding primitive typed members whose values are
+     *    <tt>x</tt> and <tt>y</tt> are considered equal if <tt>x == y</tt>,
+     *    unless their type is <tt>float</tt> or <tt>double</tt>.
+     *
+     *    <li>Two corresponding <tt>float</tt> members whose values
+     *    are <tt>x</tt> and <tt>y</tt> are considered equal if
+     *    <tt>Float.valueOf(x).equals(Float.valueOf(y))</tt>.
+     *    (Unlike the <tt>==</tt> operator, NaN is considered equal
+     *    to itself, and <tt>0.0f</tt> unequal to <tt>-0.0f</tt>.)
+     *
+     *    <li>Two corresponding <tt>double</tt> members whose values
+     *    are <tt>x</tt> and <tt>y</tt> are considered equal if
+     *    <tt>Double.valueOf(x).equals(Double.valueOf(y))</tt>.
+     *    (Unlike the <tt>==</tt> operator, NaN is considered equal
+     *    to itself, and <tt>0.0</tt> unequal to <tt>-0.0</tt>.)
+     *
+     *    <li>Two corresponding <tt>String</tt>, <tt>Class</tt>, enum, or
+     *    annotation typed members whose values are <tt>x</tt> and <tt>y</tt>
+     *    are considered equal if <tt>x.equals(y)</tt>.  (Note that this
+     *    definition is recursive for annotation typed members.)
+     *
+     *    <li>Two corresponding array typed members <tt>x</tt> and <tt>y</tt>
+     *    are considered equal if <tt>Arrays.equals(x, y)</tt>, for the
+     *    appropriate overloading of {@link java.util.Arrays#equals}.
+     * </ul>
+     *
+     * @return true if the specified object represents an annotation
+     *     that is logically equivalent to this one, otherwise false
+     */
+    boolean equals(Object obj);
+
+    /**
+     * Returns the hash code of this annotation, as defined below:
+     *
+     * <p>The hash code of an annotation is the sum of the hash codes
+     * of its members (including those with default values), as defined
+     * below:
+     *
+     * The hash code of an annotation member is (127 times the hash code
+     * of the member-name as computed by {@link String#hashCode()}) XOR
+     * the hash code of the member-value, as defined below:
+     *
+     * <p>The hash code of a member-value depends on its type:
+     * <ul>
+     * <li>The hash code of a primitive value <tt><i>v</i></tt> is equal to
+     *     <tt><i>WrapperType</i>.valueOf(<i>v</i>).hashCode()</tt>, where
+     *     <tt><i>WrapperType</i></tt> is the wrapper type corresponding
+     *     to the primitive type of <tt><i>v</i></tt> ({@link Byte},
+     *     {@link Character}, {@link Double}, {@link Float}, {@link Integer},
+     *     {@link Long}, {@link Short}, or {@link Boolean}).
+     *
+     * <li>The hash code of a string, enum, class, or annotation member-value
+     I     <tt><i>v</i></tt> is computed as by calling
+     *     <tt><i>v</i>.hashCode()</tt>.  (In the case of annotation
+     *     member values, this is a recursive definition.)
+     *
+     * <li>The hash code of an array member-value is computed by calling
+     *     the appropriate overloading of
+     *     {@link java.util.Arrays#hashCode(long[]) Arrays.hashCode}
+     *     on the value.  (There is one overloading for each primitive
+     *     type, and one for object reference types.)
+     * </ul>
+     *
+     * @return the hash code of this annotation
+     */
+    int hashCode();
+
+    /**
+     * Returns a string representation of this annotation.  The details
+     * of the representation are implementation-dependent, but the following
+     * may be regarded as typical:
+     * <pre>
+     *   &#064;com.acme.util.Name(first=Alfred, middle=E., last=Neuman)
+     * </pre>
+     *
+     * @return a string representation of this annotation
+     */
+    String toString();
+
+    /**
+     * Returns the annotation type of this annotation.
+     * @return the annotation type of this annotation
+     */
+    Class<? extends Annotation> annotationType();
+}
diff --git a/java/lang/annotation/AnnotationFormatError.java b/java/lang/annotation/AnnotationFormatError.java
new file mode 100644
index 0000000..f02104f
--- /dev/null
+++ b/java/lang/annotation/AnnotationFormatError.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2004, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Thrown when the annotation parser attempts to read an annotation
+ * from a class file and determines that the annotation is malformed.
+ * This error can be thrown by the {@linkplain
+ * java.lang.reflect.AnnotatedElement API used to read annotations
+ * reflectively}.
+ *
+ * @author  Josh Bloch
+ * @see     java.lang.reflect.AnnotatedElement
+ * @since   1.5
+ */
+public class AnnotationFormatError extends Error {
+    private static final long serialVersionUID = -4256701562333669892L;
+
+    /**
+     * Constructs a new <tt>AnnotationFormatError</tt> with the specified
+     * detail message.
+     *
+     * @param   message   the detail message.
+     */
+    public AnnotationFormatError(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new <tt>AnnotationFormatError</tt> with the specified
+     * detail message and cause.  Note that the detail message associated
+     * with <code>cause</code> is <i>not</i> automatically incorporated in
+     * this error's detail message.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (A <tt>null</tt> value is permitted, and
+     *     indicates that the cause is nonexistent or unknown.)
+     */
+    public AnnotationFormatError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+
+    /**
+     * Constructs a new <tt>AnnotationFormatError</tt> with the specified
+     * cause and a detail message of
+     * <tt>(cause == null ? null : cause.toString())</tt> (which
+     * typically contains the class and detail message of <tt>cause</tt>).
+     *
+     * @param  cause the cause (A <tt>null</tt> value is permitted, and
+     *     indicates that the cause is nonexistent or unknown.)
+     */
+    public AnnotationFormatError(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/lang/annotation/AnnotationTypeMismatchException.java b/java/lang/annotation/AnnotationTypeMismatchException.java
new file mode 100644
index 0000000..88e2712
--- /dev/null
+++ b/java/lang/annotation/AnnotationTypeMismatchException.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+import java.lang.reflect.Method;
+
+/**
+ * Thrown to indicate that a program has attempted to access an element of
+ * an annotation whose type has changed after the annotation was compiled
+ * (or serialized).
+ * This exception can be thrown by the {@linkplain
+ * java.lang.reflect.AnnotatedElement API used to read annotations
+ * reflectively}.
+ *
+ * @author  Josh Bloch
+ * @see     java.lang.reflect.AnnotatedElement
+ * @since 1.5
+ */
+public class AnnotationTypeMismatchException extends RuntimeException {
+    private static final long serialVersionUID = 8125925355765570191L;
+
+    /**
+     * The <tt>Method</tt> object for the annotation element.
+     */
+    private final Method element;
+
+    /**
+     * The (erroneous) type of data found in the annotation.  This string
+     * may, but is not required to, contain the value as well.  The exact
+     * format of the string is unspecified.
+     */
+    private final String foundType;
+
+    /**
+     * Constructs an AnnotationTypeMismatchException for the specified
+     * annotation type element and found data type.
+     *
+     * @param element the <tt>Method</tt> object for the annotation element
+     * @param foundType the (erroneous) type of data found in the annotation.
+     *        This string may, but is not required to, contain the value
+     *        as well.  The exact format of the string is unspecified.
+     */
+    public AnnotationTypeMismatchException(Method element, String foundType) {
+        super("Incorrectly typed data found for annotation element " + element
+              + " (Found data of type " + foundType + ")");
+        this.element = element;
+        this.foundType = foundType;
+    }
+
+    /**
+     * Returns the <tt>Method</tt> object for the incorrectly typed element.
+     *
+     * @return the <tt>Method</tt> object for the incorrectly typed element
+     */
+    public Method element() {
+        return this.element;
+    }
+
+    /**
+     * Returns the type of data found in the incorrectly typed element.
+     * The returned string may, but is not required to, contain the value
+     * as well.  The exact format of the string is unspecified.
+     *
+     * @return the type of data found in the incorrectly typed element
+     */
+    public String foundType() {
+        return this.foundType;
+    }
+}
diff --git a/java/lang/annotation/Documented.java b/java/lang/annotation/Documented.java
new file mode 100644
index 0000000..348a312
--- /dev/null
+++ b/java/lang/annotation/Documented.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Indicates that annotations with a type are to be documented by javadoc
+ * and similar tools by default.  This type should be used to annotate the
+ * declarations of types whose annotations affect the use of annotated
+ * elements by their clients.  If a type declaration is annotated with
+ * Documented, its annotations become part of the public API
+ * of the annotated elements.
+ *
+ * @author  Joshua Bloch
+ * @since 1.5
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Documented {
+}
diff --git a/java/lang/annotation/ElementType.java b/java/lang/annotation/ElementType.java
new file mode 100644
index 0000000..4590f39
--- /dev/null
+++ b/java/lang/annotation/ElementType.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * The constants of this enumerated type provide a simple classification of the
+ * syntactic locations where annotations may appear in a Java program. These
+ * constants are used in {@link Target java.lang.annotation.Target}
+ * meta-annotations to specify where it is legal to write annotations of a
+ * given type.
+ *
+ * <p>The syntactic locations where annotations may appear are split into
+ * <em>declaration contexts</em> , where annotations apply to declarations, and
+ * <em>type contexts</em> , where annotations apply to types used in
+ * declarations and expressions.
+ *
+ * <p>The constants {@link #ANNOTATION_TYPE} , {@link #CONSTRUCTOR} , {@link
+ * #FIELD} , {@link #LOCAL_VARIABLE} , {@link #METHOD} , {@link #PACKAGE} ,
+ * {@link #PARAMETER} , {@link #TYPE} , and {@link #TYPE_PARAMETER} correspond
+ * to the declaration contexts in JLS 9.6.4.1.
+ *
+ * <p>For example, an annotation whose type is meta-annotated with
+ * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a
+ * field declaration.
+ *
+ * <p>The constant {@link #TYPE_USE} corresponds to the 15 type contexts in JLS
+ * 4.11, as well as to two declaration contexts: type declarations (including
+ * annotation type declarations) and type parameter declarations.
+ *
+ * <p>For example, an annotation whose type is meta-annotated with
+ * {@code @Target(ElementType.TYPE_USE)} may be written on the type of a field
+ * (or within the type of the field, if it is a nested, parameterized, or array
+ * type), and may also appear as a modifier for, say, a class declaration.
+ *
+ * <p>The {@code TYPE_USE} constant includes type declarations and type
+ * parameter declarations as a convenience for designers of type checkers which
+ * give semantics to annotation types. For example, if the annotation type
+ * {@code NonNull} is meta-annotated with
+ * {@code @Target(ElementType.TYPE_USE)}, then {@code @NonNull}
+ * {@code class C {...}} could be treated by a type checker as indicating that
+ * all variables of class {@code C} are non-null, while still allowing
+ * variables of other classes to be non-null or not non-null based on whether
+ * {@code @NonNull} appears at the variable's declaration.
+ *
+ * @author  Joshua Bloch
+ * @since 1.5
+ * @jls 9.6.4.1 @Target
+ * @jls 4.1 The Kinds of Types and Values
+ */
+public enum ElementType {
+    /** Class, interface (including annotation type), or enum declaration */
+    TYPE,
+
+    /** Field declaration (includes enum constants) */
+    FIELD,
+
+    /** Method declaration */
+    METHOD,
+
+    /** Formal parameter declaration */
+    PARAMETER,
+
+    /** Constructor declaration */
+    CONSTRUCTOR,
+
+    /** Local variable declaration */
+    LOCAL_VARIABLE,
+
+    /** Annotation type declaration */
+    ANNOTATION_TYPE,
+
+    /** Package declaration */
+    PACKAGE,
+
+    /**
+     * Type parameter declaration
+     *
+     * @since 1.8
+     */
+    TYPE_PARAMETER,
+
+    /**
+     * Use of a type
+     *
+     * @since 1.8
+     */
+    TYPE_USE
+}
diff --git a/java/lang/annotation/IncompleteAnnotationException.java b/java/lang/annotation/IncompleteAnnotationException.java
new file mode 100644
index 0000000..241b21a
--- /dev/null
+++ b/java/lang/annotation/IncompleteAnnotationException.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Thrown to indicate that a program has attempted to access an element of
+ * an annotation type that was added to the annotation type definition after
+ * the annotation was compiled (or serialized).  This exception will not be
+ * thrown if the new element has a default value.
+ * This exception can be thrown by the {@linkplain
+ * java.lang.reflect.AnnotatedElement API used to read annotations
+ * reflectively}.
+ *
+ * @author  Josh Bloch
+ * @see     java.lang.reflect.AnnotatedElement
+ * @since 1.5
+ */
+public class IncompleteAnnotationException extends RuntimeException {
+    private static final long serialVersionUID = 8445097402741811912L;
+
+    private Class<? extends Annotation> annotationType;
+    private String elementName;
+
+    /**
+     * Constructs an IncompleteAnnotationException to indicate that
+     * the named element was missing from the specified annotation type.
+     *
+     * @param annotationType the Class object for the annotation type
+     * @param elementName the name of the missing element
+     * @throws NullPointerException if either parameter is {@code null}
+     */
+    public IncompleteAnnotationException(
+            Class<? extends Annotation> annotationType,
+            String elementName) {
+        super(annotationType.getName() + " missing element " +
+              elementName.toString());
+
+        this.annotationType = annotationType;
+        this.elementName = elementName;
+    }
+
+    /**
+     * Returns the Class object for the annotation type with the
+     * missing element.
+     *
+     * @return the Class object for the annotation type with the
+     *     missing element
+     */
+    public Class<? extends Annotation> annotationType() {
+        return annotationType;
+    }
+
+    /**
+     * Returns the name of the missing element.
+     *
+     * @return the name of the missing element
+     */
+    public String elementName() {
+        return elementName;
+    }
+}
diff --git a/java/lang/annotation/Inherited.java b/java/lang/annotation/Inherited.java
new file mode 100644
index 0000000..83391e2
--- /dev/null
+++ b/java/lang/annotation/Inherited.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Indicates that an annotation type is automatically inherited.  If
+ * an Inherited meta-annotation is present on an annotation type
+ * declaration, and the user queries the annotation type on a class
+ * declaration, and the class declaration has no annotation for this type,
+ * then the class's superclass will automatically be queried for the
+ * annotation type.  This process will be repeated until an annotation for this
+ * type is found, or the top of the class hierarchy (Object)
+ * is reached.  If no superclass has an annotation for this type, then
+ * the query will indicate that the class in question has no such annotation.
+ *
+ * <p>Note that this meta-annotation type has no effect if the annotated
+ * type is used to annotate anything other than a class.  Note also
+ * that this meta-annotation only causes annotations to be inherited
+ * from superclasses; annotations on implemented interfaces have no
+ * effect.
+ *
+ * @author  Joshua Bloch
+ * @since 1.5
+ * @jls 9.6.3.3 @Inherited
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Inherited {
+}
diff --git a/java/lang/annotation/Native.java b/java/lang/annotation/Native.java
new file mode 100644
index 0000000..861c1ff
--- /dev/null
+++ b/java/lang/annotation/Native.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+
+/**
+ * Indicates that a field defining a constant value may be referenced
+ * from native code.
+ *
+ * The annotation may be used as a hint by tools that generate native
+ * header files to determine whether a header file is required, and
+ * if so, what declarations it should contain.
+ *
+ * @since 1.8
+ */
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.SOURCE)
+public @interface Native {
+}
diff --git a/java/lang/annotation/Repeatable.java b/java/lang/annotation/Repeatable.java
new file mode 100644
index 0000000..7a2daa8
--- /dev/null
+++ b/java/lang/annotation/Repeatable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * The annotation type {@code java.lang.annotation.Repeatable} is
+ * used to indicate that the annotation type whose declaration it
+ * (meta-)annotates is <em>repeatable</em>. The value of
+ * {@code @Repeatable} indicates the <em>containing annotation
+ * type</em> for the repeatable annotation type.
+ *
+ * @since 1.8
+ * @jls 9.6 Annotation Types
+ * @jls 9.7 Annotations
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Repeatable {
+    /**
+     * Indicates the <em>containing annotation type</em> for the
+     * repeatable annotation type.
+     * @return the containing annotation type
+     */
+    Class<? extends Annotation> value();
+}
diff --git a/java/lang/annotation/Retention.java b/java/lang/annotation/Retention.java
new file mode 100644
index 0000000..5efa43f
--- /dev/null
+++ b/java/lang/annotation/Retention.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Indicates how long annotations with the annotated type are to
+ * be retained.  If no Retention annotation is present on
+ * an annotation type declaration, the retention policy defaults to
+ * {@code RetentionPolicy.CLASS}.
+ *
+ * <p>A Retention meta-annotation has effect only if the
+ * meta-annotated type is used directly for annotation.  It has no
+ * effect if the meta-annotated type is used as a member type in
+ * another annotation type.
+ *
+ * @author  Joshua Bloch
+ * @since 1.5
+ * @jls 9.6.3.2 @Retention
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Retention {
+    /**
+     * Returns the retention policy.
+     * @return the retention policy
+     */
+    RetentionPolicy value();
+}
diff --git a/java/lang/annotation/RetentionPolicy.java b/java/lang/annotation/RetentionPolicy.java
new file mode 100644
index 0000000..82aa198
--- /dev/null
+++ b/java/lang/annotation/RetentionPolicy.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Annotation retention policy.  The constants of this enumerated type
+ * describe the various policies for retaining annotations.  They are used
+ * in conjunction with the {@link Retention} meta-annotation type to specify
+ * how long annotations are to be retained.
+ *
+ * @author  Joshua Bloch
+ * @since 1.5
+ */
+public enum RetentionPolicy {
+    /**
+     * Annotations are to be discarded by the compiler.
+     */
+    SOURCE,
+
+    /**
+     * Annotations are to be recorded in the class file by the compiler
+     * but need not be retained by the VM at run time.  This is the default
+     * behavior.
+     */
+    CLASS,
+
+    /**
+     * Annotations are to be recorded in the class file by the compiler and
+     * retained by the VM at run time, so they may be read reflectively.
+     *
+     * @see java.lang.reflect.AnnotatedElement
+     */
+    RUNTIME
+}
diff --git a/java/lang/annotation/Target.java b/java/lang/annotation/Target.java
new file mode 100644
index 0000000..1ad4056
--- /dev/null
+++ b/java/lang/annotation/Target.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.annotation;
+
+/**
+ * Indicates the contexts in which an annotation type is applicable. The
+ * declaration contexts and type contexts in which an annotation type may be
+ * applicable are specified in JLS 9.6.4.1, and denoted in source code by enum
+ * constants of {@link ElementType java.lang.annotation.ElementType}.
+ *
+ * <p>If an {@code @Target} meta-annotation is not present on an annotation type
+ * {@code T} , then an annotation of type {@code T} may be written as a
+ * modifier for any declaration except a type parameter declaration.
+ *
+ * <p>If an {@code @Target} meta-annotation is present, the compiler will enforce
+ * the usage restrictions indicated by {@code ElementType}
+ * enum constants, in line with JLS 9.7.4.
+ *
+ * <p>For example, this {@code @Target} meta-annotation indicates that the
+ * declared type is itself a meta-annotation type.  It can only be used on
+ * annotation type declarations:
+ * <pre>
+ *    &#064;Target(ElementType.ANNOTATION_TYPE)
+ *    public &#064;interface MetaAnnotationType {
+ *        ...
+ *    }
+ * </pre>
+ *
+ * <p>This {@code @Target} meta-annotation indicates that the declared type is
+ * intended solely for use as a member type in complex annotation type
+ * declarations.  It cannot be used to annotate anything directly:
+ * <pre>
+ *    &#064;Target({})
+ *    public &#064;interface MemberType {
+ *        ...
+ *    }
+ * </pre>
+ *
+ * <p>It is a compile-time error for a single {@code ElementType} constant to
+ * appear more than once in an {@code @Target} annotation.  For example, the
+ * following {@code @Target} meta-annotation is illegal:
+ * <pre>
+ *    &#064;Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
+ *    public &#064;interface Bogus {
+ *        ...
+ *    }
+ * </pre>
+ *
+ * @since 1.5
+ * @jls 9.6.4.1 @Target
+ * @jls 9.7.4 Where Annotations May Appear
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+public @interface Target {
+    /**
+     * Returns an array of the kinds of elements an annotation type
+     * can be applied to.
+     * @return an array of the kinds of elements an annotation type
+     * can be applied to
+     */
+    ElementType[] value();
+}
diff --git a/java/lang/annotation/package-info.java b/java/lang/annotation/package-info.java
new file mode 100644
index 0000000..b2b7ec6
--- /dev/null
+++ b/java/lang/annotation/package-info.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides library support for the Java programming language
+ * annotation facility.
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ */
+package java.lang.annotation;
diff --git a/java/lang/invoke/ArrayElementVarHandle.java b/java/lang/invoke/ArrayElementVarHandle.java
new file mode 100644
index 0000000..e315ba7
--- /dev/null
+++ b/java/lang/invoke/ArrayElementVarHandle.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.invoke;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * A VarHandle to access array elements.
+ * @hide
+ */
+final class ArrayElementVarHandle extends VarHandle {
+    private ArrayElementVarHandle(Class<?> arrayClass) {
+        super(arrayClass.getComponentType(), arrayClass, false /* isFinal */,
+              arrayClass, int.class);
+    }
+
+    static ArrayElementVarHandle create(Class<?> arrayClass) {
+        return new ArrayElementVarHandle(arrayClass);
+    }
+}
diff --git a/java/lang/invoke/ByteArrayViewVarHandle.java b/java/lang/invoke/ByteArrayViewVarHandle.java
new file mode 100644
index 0000000..abdb1cb
--- /dev/null
+++ b/java/lang/invoke/ByteArrayViewVarHandle.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.invoke;
+
+import java.nio.ByteOrder;
+
+/**
+ * A VarHandle to access byte array elements as an array of primitive types.
+ * @hide
+ */
+final class ByteArrayViewVarHandle extends VarHandle {
+    private boolean nativeByteOrder;
+
+    private ByteArrayViewVarHandle(Class<?> arrayClass, ByteOrder byteOrder) {
+        super(arrayClass.getComponentType(), byte[].class, false /* isFinal */,
+              byte[].class, int.class);
+        this.nativeByteOrder = byteOrder.equals(ByteOrder.nativeOrder());
+    }
+
+    static ByteArrayViewVarHandle create(Class<?> arrayClass, ByteOrder byteOrder) {
+        return new ByteArrayViewVarHandle(arrayClass, byteOrder);
+    }
+}
diff --git a/java/lang/invoke/ByteBufferViewVarHandle.java b/java/lang/invoke/ByteBufferViewVarHandle.java
new file mode 100644
index 0000000..75fcbab
--- /dev/null
+++ b/java/lang/invoke/ByteBufferViewVarHandle.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.invoke;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A VarHandle to access byte array elements as an array of primitive types.
+ * @hide
+ */
+final class ByteBufferViewVarHandle extends VarHandle {
+    private boolean nativeByteOrder;
+
+    private ByteBufferViewVarHandle(Class<?> arrayClass, ByteOrder byteOrder) {
+        super(arrayClass.getComponentType(), byte[].class, false /* isFinal */,
+              ByteBuffer.class, int.class);
+        this.nativeByteOrder = byteOrder.equals(ByteOrder.nativeOrder());
+    }
+
+    static ByteBufferViewVarHandle create(Class<?> arrayClass, ByteOrder byteOrder) {
+        return new ByteBufferViewVarHandle(arrayClass, byteOrder);
+    }
+}
diff --git a/java/lang/invoke/CallSite.java b/java/lang/invoke/CallSite.java
new file mode 100644
index 0000000..85b4bb9
--- /dev/null
+++ b/java/lang/invoke/CallSite.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: Not using Empty
+//import sun.invoke.empty.Empty;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * A {@code CallSite} is a holder for a variable {@link MethodHandle},
+ * which is called its {@code target}.
+ * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
+ * all calls to the site's current target.
+ * A {@code CallSite} may be associated with several {@code invokedynamic}
+ * instructions, or it may be "free floating", associated with none.
+ * In any case, it may be invoked through an associated method handle
+ * called its {@linkplain #dynamicInvoker dynamic invoker}.
+ * <p>
+ * {@code CallSite} is an abstract class which does not allow
+ * direct subclassing by users.  It has three immediate,
+ * concrete subclasses that may be either instantiated or subclassed.
+ * <ul>
+ * <li>If a mutable target is not required, an {@code invokedynamic} instruction
+ * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
+ * <li>If a mutable target is required which has volatile variable semantics,
+ * because updates to the target must be immediately and reliably witnessed by other threads,
+ * a {@linkplain VolatileCallSite volatile call site} may be used.
+ * <li>Otherwise, if a mutable target is required,
+ * a {@linkplain MutableCallSite mutable call site} may be used.
+ * </ul>
+ * <p>
+ * A non-constant call site may be <em>relinked</em> by changing its target.
+ * The new target must have the same {@linkplain MethodHandle#type() type}
+ * as the previous target.
+ * Thus, though a call site can be relinked to a series of
+ * successive targets, it cannot change its type.
+ * <p>
+ * Here is a sample use of call sites and bootstrap methods which links every
+ * dynamic call site to print its arguments:
+<blockquote><pre>{@code
+static void test() throws Throwable {
+    // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
+    InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
+}
+private static void printArgs(Object... args) {
+  System.out.println(java.util.Arrays.deepToString(args));
+}
+private static final MethodHandle printArgs;
+static {
+  MethodHandles.Lookup lookup = MethodHandles.lookup();
+  Class thisClass = lookup.lookupClass();  // (who am I?)
+  printArgs = lookup.findStatic(thisClass,
+      "printArgs", MethodType.methodType(void.class, Object[].class));
+}
+private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
+  // ignore caller and name, but match the type:
+  return new ConstantCallSite(printArgs.asType(type));
+}
+}</pre></blockquote>
+ * @author John Rose, JSR 292 EG
+ */
+abstract
+public class CallSite {
+    // Android-changed: not used.
+    // static { MethodHandleImpl.initStatics(); }
+
+    // The actual payload of this call site:
+    /*package-private*/
+    MethodHandle target;    // Note: This field is known to the JVM.  Do not change.
+
+    /**
+     * Make a blank call site object with the given method type.
+     * An initial target method is supplied which will throw
+     * an {@link IllegalStateException} if called.
+     * <p>
+     * Before this {@code CallSite} object is returned from a bootstrap method,
+     * it is usually provided with a more useful target method,
+     * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+     * @throws NullPointerException if the proposed type is null
+     */
+    /*package-private*/
+    CallSite(MethodType type) {
+        // Android-changed: No cache for these so create uninitializedCallSite target here using
+        // method handle transformations to create a method handle that has the expected method
+        // type but throws an IllegalStateException.
+        // target = makeUninitializedCallSite(type);
+        this.target = MethodHandles.throwException(type.returnType(), IllegalStateException.class);
+        this.target = MethodHandles.insertArguments(
+            this.target, 0, new IllegalStateException("uninitialized call site"));
+        if (type.parameterCount() > 0) {
+            this.target = MethodHandles.dropArguments(this.target, 0, type.ptypes());
+        }
+
+        // Android-changed: Using initializer method for GET_TARGET
+        // rather than complex static initializer.
+        initializeGetTarget();
+    }
+
+    /**
+     * Make a call site object equipped with an initial target method handle.
+     * @param target the method handle which will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    /*package-private*/
+    CallSite(MethodHandle target) {
+        target.type();  // null check
+        this.target = target;
+
+        // Android-changed: Using initializer method for GET_TARGET
+        // rather than complex static initializer.
+        initializeGetTarget();
+    }
+
+    /**
+     * Make a call site object equipped with an initial target method handle.
+     * @param targetType the desired type of the call site
+     * @param createTargetHook a hook which will bind the call site to the target method handle
+     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+     *         or if the target returned by the hook is not of the given {@code targetType}
+     * @throws NullPointerException if the hook returns a null value
+     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+     * @throws Throwable anything else thrown by the hook function
+     */
+    /*package-private*/
+    CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+        this(targetType);
+        ConstantCallSite selfCCS = (ConstantCallSite) this;
+        MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
+        checkTargetChange(this.target, boundTarget);
+        this.target = boundTarget;
+
+        // Android-changed: Using initializer method for GET_TARGET
+        // rather than complex static initializer.
+        initializeGetTarget();
+    }
+
+    /**
+     * Returns the type of this call site's target.
+     * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
+     * The {@code setTarget} method enforces this invariant by refusing any new target that does
+     * not have the previous target's type.
+     * @return the type of the current target, which is also the type of any future target
+     */
+    public MethodType type() {
+        // warning:  do not call getTarget here, because CCS.getTarget can throw IllegalStateException
+        return target.type();
+    }
+
+    /**
+     * Returns the target method of the call site, according to the
+     * behavior defined by this call site's specific class.
+     * The immediate subclasses of {@code CallSite} document the
+     * class-specific behaviors of this method.
+     *
+     * @return the current linkage state of the call site, its target method handle
+     * @see ConstantCallSite
+     * @see VolatileCallSite
+     * @see #setTarget
+     * @see ConstantCallSite#getTarget
+     * @see MutableCallSite#getTarget
+     * @see VolatileCallSite#getTarget
+     */
+    public abstract MethodHandle getTarget();
+
+    /**
+     * Updates the target method of this call site, according to the
+     * behavior defined by this call site's specific class.
+     * The immediate subclasses of {@code CallSite} document the
+     * class-specific behaviors of this method.
+     * <p>
+     * The type of the new target must be {@linkplain MethodType#equals equal to}
+     * the type of the old target.
+     *
+     * @param newTarget the new target
+     * @throws NullPointerException if the proposed new target is null
+     * @throws WrongMethodTypeException if the proposed new target
+     *         has a method type that differs from the previous target
+     * @see CallSite#getTarget
+     * @see ConstantCallSite#setTarget
+     * @see MutableCallSite#setTarget
+     * @see VolatileCallSite#setTarget
+     */
+    public abstract void setTarget(MethodHandle newTarget);
+
+    void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
+        MethodType oldType = oldTarget.type();
+        MethodType newType = newTarget.type();  // null check!
+        if (!newType.equals(oldType))
+            throw wrongTargetType(newTarget, oldType);
+    }
+
+    private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
+        return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
+    }
+
+    /**
+     * Produces a method handle equivalent to an invokedynamic instruction
+     * which has been linked to this call site.
+     * <p>
+     * This method is equivalent to the following code:
+     * <blockquote><pre>{@code
+     * MethodHandle getTarget, invoker, result;
+     * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
+     * invoker = MethodHandles.exactInvoker(this.type());
+     * result = MethodHandles.foldArguments(invoker, getTarget)
+     * }</pre></blockquote>
+     *
+     * @return a method handle which always invokes this call site's current target
+     */
+    public abstract MethodHandle dynamicInvoker();
+
+    /*non-public*/ MethodHandle makeDynamicInvoker() {
+        // Android-changed: Use bindTo() rather than bindArgumentL() (not implemented).
+        MethodHandle getTarget = GET_TARGET.bindTo(this);
+        MethodHandle invoker = MethodHandles.exactInvoker(this.type());
+        return MethodHandles.foldArguments(invoker, getTarget);
+    }
+
+    // Android-changed: no longer final. GET_TARGET assigned in initializeGetTarget().
+    private static MethodHandle GET_TARGET = null;
+
+    private void initializeGetTarget() {
+        // Android-changed: moved from static initializer for
+        // GET_TARGET to avoid issues with running early. Called from
+        // constructors. CallSite creation is not performance critical.
+        synchronized (CallSite.class) {
+            if (GET_TARGET == null) {
+                try {
+                    GET_TARGET = IMPL_LOOKUP.
+                            findVirtual(CallSite.class, "getTarget",
+                                        MethodType.methodType(MethodHandle.class));
+                } catch (ReflectiveOperationException e) {
+                    throw new InternalError(e);
+                }
+            }
+        }
+    }
+
+    // Android-changed: not used.
+    // /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
+    // /*package-private*/
+    // static Empty uninitializedCallSite() {
+    //     throw new IllegalStateException("uninitialized call site");
+    // }
+
+    // unsafe stuff:
+    private static final long TARGET_OFFSET;
+    static {
+        try {
+            TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
+        } catch (Exception ex) { throw new Error(ex); }
+    }
+
+    /*package-private*/
+    void setTargetNormal(MethodHandle newTarget) {
+        // Android-changed: Set value directly.
+        // MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
+        target = newTarget;
+    }
+    /*package-private*/
+    MethodHandle getTargetVolatile() {
+        return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
+    }
+    /*package-private*/
+    void setTargetVolatile(MethodHandle newTarget) {
+        // Android-changed: Set value directly.
+        // MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
+        UNSAFE.putObjectVolatile(this, TARGET_OFFSET, newTarget);
+    }
+
+    // Android-changed: not used.
+    // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
+    // static CallSite makeSite(MethodHandle bootstrapMethod,
+    //                          // Callee information:
+    //                          String name, MethodType type,
+    //                          // Extra arguments for BSM, if any:
+    //                          Object info,
+    //                          // Caller information:
+    //                          Class<?> callerClass) {
+    //     MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
+    //     CallSite site;
+    //     try {
+    //         Object binding;
+    //         info = maybeReBox(info);
+    //         if (info == null) {
+    //             binding = bootstrapMethod.invoke(caller, name, type);
+    //         } else if (!info.getClass().isArray()) {
+    //             binding = bootstrapMethod.invoke(caller, name, type, info);
+    //         } else {
+    //             Object[] argv = (Object[]) info;
+    //             maybeReBoxElements(argv);
+    //             switch (argv.length) {
+    //             case 0:
+    //                 binding = bootstrapMethod.invoke(caller, name, type);
+    //                 break;
+    //             case 1:
+    //                 binding = bootstrapMethod.invoke(caller, name, type,
+    //                                                  argv[0]);
+    //                 break;
+    //             case 2:
+    //                 binding = bootstrapMethod.invoke(caller, name, type,
+    //                                                  argv[0], argv[1]);
+    //                 break;
+    //             case 3:
+    //                 binding = bootstrapMethod.invoke(caller, name, type,
+    //                                                  argv[0], argv[1], argv[2]);
+    //                 break;
+    //             case 4:
+    //                 binding = bootstrapMethod.invoke(caller, name, type,
+    //                                                  argv[0], argv[1], argv[2], argv[3]);
+    //                 break;
+    //             case 5:
+    //                 binding = bootstrapMethod.invoke(caller, name, type,
+    //                                                  argv[0], argv[1], argv[2], argv[3], argv[4]);
+    //                 break;
+    //             case 6:
+    //                 binding = bootstrapMethod.invoke(caller, name, type,
+    //                                                  argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+    //                 break;
+    //             default:
+    //                 final int NON_SPREAD_ARG_COUNT = 3;  // (caller, name, type)
+    //                 if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
+    //                     throw new BootstrapMethodError("too many bootstrap method arguments");
+    //                 MethodType bsmType = bootstrapMethod.type();
+    //                 MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
+    //                 MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
+    //                 MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
+    //                 binding = spreader.invokeExact(typedBSM, (Object)caller, (Object)name, (Object)type, argv);
+    //             }
+    //         }
+    //         //System.out.println("BSM for "+name+type+" => "+binding);
+    //         if (binding instanceof CallSite) {
+    //             site = (CallSite) binding;
+    //         }  else {
+    //             throw new ClassCastException("bootstrap method failed to produce a CallSite");
+    //         }
+    //         if (!site.getTarget().type().equals(type))
+    //             throw wrongTargetType(site.getTarget(), type);
+    //     } catch (Throwable ex) {
+    //         BootstrapMethodError bex;
+    //         if (ex instanceof BootstrapMethodError)
+    //             bex = (BootstrapMethodError) ex;
+    //         else
+    //             bex = new BootstrapMethodError("call site initialization exception", ex);
+    //         throw bex;
+    //     }
+    //     return site;
+    // }
+
+    // private static Object maybeReBox(Object x) {
+    //     if (x instanceof Integer) {
+    //         int xi = (int) x;
+    //         if (xi == (byte) xi)
+    //             x = xi;  // must rebox; see JLS 5.1.7
+    //     }
+    //     return x;
+    // }
+    // private static void maybeReBoxElements(Object[] xa) {
+    //     for (int i = 0; i < xa.length; i++) {
+    //         xa[i] = maybeReBox(xa[i]);
+    //     }
+    // }
+}
diff --git a/java/lang/invoke/ConstantCallSite.java b/java/lang/invoke/ConstantCallSite.java
new file mode 100644
index 0000000..f27d0e7
--- /dev/null
+++ b/java/lang/invoke/ConstantCallSite.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
+ * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
+ * bound to the call site's target.
+ * @author John Rose, JSR 292 EG
+ */
+public class ConstantCallSite extends CallSite {
+    private final boolean isFrozen;
+
+    /**
+     * Creates a call site with a permanent target.
+     * @param target the target to be permanently associated with this call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public ConstantCallSite(MethodHandle target) {
+        super(target);
+        isFrozen = true;
+    }
+
+    /**
+     * Creates a call site with a permanent target, possibly bound to the call site itself.
+     * <p>
+     * During construction of the call site, the {@code createTargetHook} is invoked to
+     * produce the actual target, as if by a call of the form
+     * {@code (MethodHandle) createTargetHook.invoke(this)}.
+     * <p>
+     * Note that user code cannot perform such an action directly in a subclass constructor,
+     * since the target must be fixed before the {@code ConstantCallSite} constructor returns.
+     * <p>
+     * The hook is said to bind the call site to a target method handle,
+     * and a typical action would be {@code someTarget.bindTo(this)}.
+     * However, the hook is free to take any action whatever,
+     * including ignoring the call site and returning a constant target.
+     * <p>
+     * The result returned by the hook must be a method handle of exactly
+     * the same type as the call site.
+     * <p>
+     * While the hook is being called, the new {@code ConstantCallSite}
+     * object is in a partially constructed state.
+     * In this state,
+     * a call to {@code getTarget}, or any other attempt to use the target,
+     * will result in an {@code IllegalStateException}.
+     * It is legal at all times to obtain the call site's type using the {@code type} method.
+     *
+     * @param targetType the type of the method handle to be permanently associated with this call site
+     * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
+     * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+     *         or if the target returned by the hook is not of the given {@code targetType}
+     * @throws NullPointerException if the hook returns a null value
+     * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+     * @throws Throwable anything else thrown by the hook function
+     */
+    protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+        super(targetType, createTargetHook);
+        isFrozen = true;
+    }
+
+    /**
+     * Returns the target method of the call site, which behaves
+     * like a {@code final} field of the {@code ConstantCallSite}.
+     * That is, the target is always the original value passed
+     * to the constructor call which created this instance.
+     *
+     * @return the immutable linkage state of this call site, a constant method handle
+     * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+     */
+    @Override public final MethodHandle getTarget() {
+        if (!isFrozen)  throw new IllegalStateException();
+        return target;
+    }
+
+    /**
+     * Always throws an {@link UnsupportedOperationException}.
+     * This kind of call site cannot change its target.
+     * @param ignore a new target proposed for the call site, which is ignored
+     * @throws UnsupportedOperationException because this kind of call site cannot change its target
+     */
+    @Override public final void setTarget(MethodHandle ignore) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns this call site's permanent target.
+     * Since that target will never change, this is a correct implementation
+     * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
+     * @return the immutable linkage state of this call site, a constant method handle
+     * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+     */
+    @Override
+    public final MethodHandle dynamicInvoker() {
+        return getTarget();
+    }
+}
diff --git a/java/lang/invoke/FieldVarHandle.java b/java/lang/invoke/FieldVarHandle.java
new file mode 100644
index 0000000..0921040
--- /dev/null
+++ b/java/lang/invoke/FieldVarHandle.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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.invoke;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * A VarHandle that's associated with an ArtField.
+ * @hide
+ */
+final class FieldVarHandle extends VarHandle {
+    private final long artField;
+
+    private FieldVarHandle(Field field, Class<?> declaringClass) {
+        super(field.getType(), Modifier.isFinal(field.getModifiers()), declaringClass);
+        artField = field.getArtField();
+    }
+
+    private FieldVarHandle(Field field) {
+        super(field.getType(), Modifier.isFinal(field.getModifiers()));
+        artField = field.getArtField();
+    }
+
+    static FieldVarHandle create(Field field) {
+        if (Modifier.isStatic(field.getModifiers())) {
+            return new FieldVarHandle(field);
+        } else {
+            return new FieldVarHandle(field, field.getDeclaringClass());
+        }
+    }
+}
diff --git a/java/lang/invoke/LambdaConversionException.java b/java/lang/invoke/LambdaConversionException.java
new file mode 100644
index 0000000..e1123da
--- /dev/null
+++ b/java/lang/invoke/LambdaConversionException.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * LambdaConversionException
+ */
+public class LambdaConversionException extends Exception {
+    private static final long serialVersionUID = 292L + 8L;
+
+    /**
+     * Constructs a {@code LambdaConversionException}.
+     */
+    public LambdaConversionException() {
+    }
+
+    /**
+     * Constructs a {@code LambdaConversionException} with a message.
+     * @param message the detail message
+     */
+    public LambdaConversionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code LambdaConversionException} with a message and cause.
+     * @param message the detail message
+     * @param cause the cause
+     */
+    public LambdaConversionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code LambdaConversionException} with a cause.
+     * @param cause the cause
+     */
+    public LambdaConversionException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a {@code LambdaConversionException} with a message,
+     * cause, and other settings.
+     * @param message the detail message
+     * @param cause the cause
+     * @param enableSuppression whether or not suppressed exceptions are enabled
+     * @param writableStackTrace whether or not the stack trace is writable
+     */
+    public LambdaConversionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/java/lang/invoke/LambdaMetafactory.java b/java/lang/invoke/LambdaMetafactory.java
new file mode 100644
index 0000000..e1ce46f
--- /dev/null
+++ b/java/lang/invoke/LambdaMetafactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+public class LambdaMetafactory {
+
+    public static final int FLAG_SERIALIZABLE = 1 << 0;
+
+    public static final int FLAG_MARKERS = 1 << 1;
+
+    public static final int FLAG_BRIDGES = 1 << 2;
+
+    public static CallSite metafactory(MethodHandles.Lookup caller,
+                                       String invokedName,
+                                       MethodType invokedType,
+                                       MethodType samMethodType,
+                                       MethodHandle implMethod,
+                                       MethodType instantiatedMethodType)
+            throws LambdaConversionException { return null; }
+
+    public static CallSite altMetafactory(MethodHandles.Lookup caller,
+                                          String invokedName,
+                                          MethodType invokedType,
+                                          Object... args)
+            throws LambdaConversionException { return null; }
+}
diff --git a/java/lang/invoke/MethodHandle.java b/java/lang/invoke/MethodHandle.java
new file mode 100644
index 0000000..87911c2
--- /dev/null
+++ b/java/lang/invoke/MethodHandle.java
@@ -0,0 +1,1646 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+
+import dalvik.system.EmulatedStackFrame;
+
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A method handle is a typed, directly executable reference to an underlying method,
+ * constructor, field, or similar low-level operation, with optional
+ * transformations of arguments or return values.
+ * These transformations are quite general, and include such patterns as
+ * {@linkplain #asType conversion},
+ * {@linkplain #bindTo insertion},
+ * {@linkplain java.lang.invoke.MethodHandles#dropArguments deletion},
+ * and {@linkplain java.lang.invoke.MethodHandles#filterArguments substitution}.
+ *
+ * <h1>Method handle contents</h1>
+ * Method handles are dynamically and strongly typed according to their parameter and return types.
+ * They are not distinguished by the name or the defining class of their underlying methods.
+ * A method handle must be invoked using a symbolic type descriptor which matches
+ * the method handle's own {@linkplain #type type descriptor}.
+ * <p>
+ * Every method handle reports its type descriptor via the {@link #type type} accessor.
+ * This type descriptor is a {@link java.lang.invoke.MethodType MethodType} object,
+ * whose structure is a series of classes, one of which is
+ * the return type of the method (or {@code void.class} if none).
+ * <p>
+ * A method handle's type controls the types of invocations it accepts,
+ * and the kinds of transformations that apply to it.
+ * <p>
+ * A method handle contains a pair of special invoker methods
+ * called {@link #invokeExact invokeExact} and {@link #invoke invoke}.
+ * Both invoker methods provide direct access to the method handle's
+ * underlying method, constructor, field, or other operation,
+ * as modified by transformations of arguments and return values.
+ * Both invokers accept calls which exactly match the method handle's own type.
+ * The plain, inexact invoker also accepts a range of other call types.
+ * <p>
+ * Method handles are immutable and have no visible state.
+ * Of course, they can be bound to underlying methods or data which exhibit state.
+ * With respect to the Java Memory Model, any method handle will behave
+ * as if all of its (internal) fields are final variables.  This means that any method
+ * handle made visible to the application will always be fully formed.
+ * This is true even if the method handle is published through a shared
+ * variable in a data race.
+ * <p>
+ * Method handles cannot be subclassed by the user.
+ * Implementations may (or may not) create internal subclasses of {@code MethodHandle}
+ * which may be visible via the {@link java.lang.Object#getClass Object.getClass}
+ * operation.  The programmer should not draw conclusions about a method handle
+ * from its specific class, as the method handle class hierarchy (if any)
+ * may change from time to time or across implementations from different vendors.
+ *
+ * <h1>Method handle compilation</h1>
+ * A Java method call expression naming {@code invokeExact} or {@code invoke}
+ * can invoke a method handle from Java source code.
+ * From the viewpoint of source code, these methods can take any arguments
+ * and their result can be cast to any return type.
+ * Formally this is accomplished by giving the invoker methods
+ * {@code Object} return types and variable arity {@code Object} arguments,
+ * but they have an additional quality called <em>signature polymorphism</em>
+ * which connects this freedom of invocation directly to the JVM execution stack.
+ * <p>
+ * As is usual with virtual methods, source-level calls to {@code invokeExact}
+ * and {@code invoke} compile to an {@code invokevirtual} instruction.
+ * More unusually, the compiler must record the actual argument types,
+ * and may not perform method invocation conversions on the arguments.
+ * Instead, it must push them on the stack according to their own unconverted types.
+ * The method handle object itself is pushed on the stack before the arguments.
+ * The compiler then calls the method handle with a symbolic type descriptor which
+ * describes the argument and return types.
+ * <p>
+ * To issue a complete symbolic type descriptor, the compiler must also determine
+ * the return type.  This is based on a cast on the method invocation expression,
+ * if there is one, or else {@code Object} if the invocation is an expression
+ * or else {@code void} if the invocation is a statement.
+ * The cast may be to a primitive type (but not {@code void}).
+ * <p>
+ * As a corner case, an uncasted {@code null} argument is given
+ * a symbolic type descriptor of {@code java.lang.Void}.
+ * The ambiguity with the type {@code Void} is harmless, since there are no references of type
+ * {@code Void} except the null reference.
+ *
+ * <h1>Method handle invocation</h1>
+ * The first time a {@code invokevirtual} instruction is executed
+ * it is linked, by symbolically resolving the names in the instruction
+ * and verifying that the method call is statically legal.
+ * This is true of calls to {@code invokeExact} and {@code invoke}.
+ * In this case, the symbolic type descriptor emitted by the compiler is checked for
+ * correct syntax and names it contains are resolved.
+ * Thus, an {@code invokevirtual} instruction which invokes
+ * a method handle will always link, as long
+ * as the symbolic type descriptor is syntactically well-formed
+ * and the types exist.
+ * <p>
+ * When the {@code invokevirtual} is executed after linking,
+ * the receiving method handle's type is first checked by the JVM
+ * to ensure that it matches the symbolic type descriptor.
+ * If the type match fails, it means that the method which the
+ * caller is invoking is not present on the individual
+ * method handle being invoked.
+ * <p>
+ * In the case of {@code invokeExact}, the type descriptor of the invocation
+ * (after resolving symbolic type names) must exactly match the method type
+ * of the receiving method handle.
+ * In the case of plain, inexact {@code invoke}, the resolved type descriptor
+ * must be a valid argument to the receiver's {@link #asType asType} method.
+ * Thus, plain {@code invoke} is more permissive than {@code invokeExact}.
+ * <p>
+ * After type matching, a call to {@code invokeExact} directly
+ * and immediately invoke the method handle's underlying method
+ * (or other behavior, as the case may be).
+ * <p>
+ * A call to plain {@code invoke} works the same as a call to
+ * {@code invokeExact}, if the symbolic type descriptor specified by the caller
+ * exactly matches the method handle's own type.
+ * If there is a type mismatch, {@code invoke} attempts
+ * to adjust the type of the receiving method handle,
+ * as if by a call to {@link #asType asType},
+ * to obtain an exactly invokable method handle {@code M2}.
+ * This allows a more powerful negotiation of method type
+ * between caller and callee.
+ * <p>
+ * (<em>Note:</em> The adjusted method handle {@code M2} is not directly observable,
+ * and implementations are therefore not required to materialize it.)
+ *
+ * <h1>Invocation checking</h1>
+ * In typical programs, method handle type matching will usually succeed.
+ * But if a match fails, the JVM will throw a {@link WrongMethodTypeException},
+ * either directly (in the case of {@code invokeExact}) or indirectly as if
+ * by a failed call to {@code asType} (in the case of {@code invoke}).
+ * <p>
+ * Thus, a method type mismatch which might show up as a linkage error
+ * in a statically typed program can show up as
+ * a dynamic {@code WrongMethodTypeException}
+ * in a program which uses method handles.
+ * <p>
+ * Because method types contain "live" {@code Class} objects,
+ * method type matching takes into account both types names and class loaders.
+ * Thus, even if a method handle {@code M} is created in one
+ * class loader {@code L1} and used in another {@code L2},
+ * method handle calls are type-safe, because the caller's symbolic type
+ * descriptor, as resolved in {@code L2},
+ * is matched against the original callee method's symbolic type descriptor,
+ * as resolved in {@code L1}.
+ * The resolution in {@code L1} happens when {@code M} is created
+ * and its type is assigned, while the resolution in {@code L2} happens
+ * when the {@code invokevirtual} instruction is linked.
+ * <p>
+ * Apart from the checking of type descriptors,
+ * a method handle's capability to call its underlying method is unrestricted.
+ * If a method handle is formed on a non-public method by a class
+ * that has access to that method, the resulting handle can be used
+ * in any place by any caller who receives a reference to it.
+ * <p>
+ * Unlike with the Core Reflection API, where access is checked every time
+ * a reflective method is invoked,
+ * method handle access checking is performed
+ * <a href="MethodHandles.Lookup.html#access">when the method handle is created</a>.
+ * In the case of {@code ldc} (see below), access checking is performed as part of linking
+ * the constant pool entry underlying the constant method handle.
+ * <p>
+ * Thus, handles to non-public methods, or to methods in non-public classes,
+ * should generally be kept secret.
+ * They should not be passed to untrusted code unless their use from
+ * the untrusted code would be harmless.
+ *
+ * <h1>Method handle creation</h1>
+ * Java code can create a method handle that directly accesses
+ * any method, constructor, or field that is accessible to that code.
+ * This is done via a reflective, capability-based API called
+ * {@link java.lang.invoke.MethodHandles.Lookup MethodHandles.Lookup}
+ * For example, a static method handle can be obtained
+ * from {@link java.lang.invoke.MethodHandles.Lookup#findStatic Lookup.findStatic}.
+ * There are also conversion methods from Core Reflection API objects,
+ * such as {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * <p>
+ * Like classes and strings, method handles that correspond to accessible
+ * fields, methods, and constructors can also be represented directly
+ * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
+ * A new type of constant pool entry, {@code CONSTANT_MethodHandle},
+ * refers directly to an associated {@code CONSTANT_Methodref},
+ * {@code CONSTANT_InterfaceMethodref}, or {@code CONSTANT_Fieldref}
+ * constant pool entry.
+ * (For full details on method handle constants,
+ * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
+ * <p>
+ * Method handles produced by lookups or constant loads from methods or
+ * constructors with the variable arity modifier bit ({@code 0x0080})
+ * have a corresponding variable arity, as if they were defined with
+ * the help of {@link #asVarargsCollector asVarargsCollector}.
+ * <p>
+ * A method reference may refer either to a static or non-static method.
+ * In the non-static case, the method handle type includes an explicit
+ * receiver argument, prepended before any other arguments.
+ * In the method handle's type, the initial receiver argument is typed
+ * according to the class under which the method was initially requested.
+ * (E.g., if a non-static method handle is obtained via {@code ldc},
+ * the type of the receiver is the class named in the constant pool entry.)
+ * <p>
+ * Method handle constants are subject to the same link-time access checks
+ * their corresponding bytecode instructions, and the {@code ldc} instruction
+ * will throw corresponding linkage errors if the bytecode behaviors would
+ * throw such errors.
+ * <p>
+ * As a corollary of this, access to protected members is restricted
+ * to receivers only of the accessing class, or one of its subclasses,
+ * and the accessing class must in turn be a subclass (or package sibling)
+ * of the protected member's defining class.
+ * If a method reference refers to a protected non-static method or field
+ * of a class outside the current package, the receiver argument will
+ * be narrowed to the type of the accessing class.
+ * <p>
+ * When a method handle to a virtual method is invoked, the method is
+ * always looked up in the receiver (that is, the first argument).
+ * <p>
+ * A non-virtual method handle to a specific virtual method implementation
+ * can also be created.  These do not perform virtual lookup based on
+ * receiver type.  Such a method handle simulates the effect of
+ * an {@code invokespecial} instruction to the same method.
+ *
+ * <h1>Usage examples</h1>
+ * Here are some examples of usage:
+ * <blockquote><pre>{@code
+Object x, y; String s; int i;
+MethodType mt; MethodHandle mh;
+MethodHandles.Lookup lookup = MethodHandles.lookup();
+// mt is (char,char)String
+mt = MethodType.methodType(String.class, char.class, char.class);
+mh = lookup.findVirtual(String.class, "replace", mt);
+s = (String) mh.invokeExact("daddy",'d','n');
+// invokeExact(Ljava/lang/String;CC)Ljava/lang/String;
+assertEquals(s, "nanny");
+// weakly typed invocation (using MHs.invoke)
+s = (String) mh.invokeWithArguments("sappy", 'p', 'v');
+assertEquals(s, "savvy");
+// mt is (Object[])List
+mt = MethodType.methodType(java.util.List.class, Object[].class);
+mh = lookup.findStatic(java.util.Arrays.class, "asList", mt);
+assert(mh.isVarargsCollector());
+x = mh.invoke("one", "two");
+// invoke(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;
+assertEquals(x, java.util.Arrays.asList("one","two"));
+// mt is (Object,Object,Object)Object
+mt = MethodType.genericMethodType(3);
+mh = mh.asType(mt);
+x = mh.invokeExact((Object)1, (Object)2, (Object)3);
+// invokeExact(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
+assertEquals(x, java.util.Arrays.asList(1,2,3));
+// mt is ()int
+mt = MethodType.methodType(int.class);
+mh = lookup.findVirtual(java.util.List.class, "size", mt);
+i = (int) mh.invokeExact(java.util.Arrays.asList(1,2,3));
+// invokeExact(Ljava/util/List;)I
+assert(i == 3);
+mt = MethodType.methodType(void.class, String.class);
+mh = lookup.findVirtual(java.io.PrintStream.class, "println", mt);
+mh.invokeExact(System.out, "Hello, world.");
+// invokeExact(Ljava/io/PrintStream;Ljava/lang/String;)V
+ * }</pre></blockquote>
+ * Each of the above calls to {@code invokeExact} or plain {@code invoke}
+ * generates a single invokevirtual instruction with
+ * the symbolic type descriptor indicated in the following comment.
+ * In these examples, the helper method {@code assertEquals} is assumed to
+ * be a method which calls {@link java.util.Objects#equals(Object,Object) Objects.equals}
+ * on its arguments, and asserts that the result is true.
+ *
+ * <h1>Exceptions</h1>
+ * The methods {@code invokeExact} and {@code invoke} are declared
+ * to throw {@link java.lang.Throwable Throwable},
+ * which is to say that there is no static restriction on what a method handle
+ * can throw.  Since the JVM does not distinguish between checked
+ * and unchecked exceptions (other than by their class, of course),
+ * there is no particular effect on bytecode shape from ascribing
+ * checked exceptions to method handle invocations.  But in Java source
+ * code, methods which perform method handle calls must either explicitly
+ * throw {@code Throwable}, or else must catch all
+ * throwables locally, rethrowing only those which are legal in the context,
+ * and wrapping ones which are illegal.
+ *
+ * <h1><a name="sigpoly"></a>Signature polymorphism</h1>
+ * The unusual compilation and linkage behavior of
+ * {@code invokeExact} and plain {@code invoke}
+ * is referenced by the term <em>signature polymorphism</em>.
+ * As defined in the Java Language Specification,
+ * a signature polymorphic method is one which can operate with
+ * any of a wide range of call signatures and return types.
+ * <p>
+ * In source code, a call to a signature polymorphic method will
+ * compile, regardless of the requested symbolic type descriptor.
+ * As usual, the Java compiler emits an {@code invokevirtual}
+ * instruction with the given symbolic type descriptor against the named method.
+ * The unusual part is that the symbolic type descriptor is derived from
+ * the actual argument and return types, not from the method declaration.
+ * <p>
+ * When the JVM processes bytecode containing signature polymorphic calls,
+ * it will successfully link any such call, regardless of its symbolic type descriptor.
+ * (In order to retain type safety, the JVM will guard such calls with suitable
+ * dynamic type checks, as described elsewhere.)
+ * <p>
+ * Bytecode generators, including the compiler back end, are required to emit
+ * untransformed symbolic type descriptors for these methods.
+ * Tools which determine symbolic linkage are required to accept such
+ * untransformed descriptors, without reporting linkage errors.
+ *
+ * <h1>Interoperation between method handles and the Core Reflection API</h1>
+ * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup Lookup} API,
+ * any class member represented by a Core Reflection API object
+ * can be converted to a behaviorally equivalent method handle.
+ * For example, a reflective {@link java.lang.reflect.Method Method} can
+ * be converted to a method handle using
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * The resulting method handles generally provide more direct and efficient
+ * access to the underlying class members.
+ * <p>
+ * As a special case,
+ * when the Core Reflection API is used to view the signature polymorphic
+ * methods {@code invokeExact} or plain {@code invoke} in this class,
+ * they appear as ordinary non-polymorphic methods.
+ * Their reflective appearance, as viewed by
+ * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
+ * is unaffected by their special status in this API.
+ * For example, {@link java.lang.reflect.Method#getModifiers Method.getModifiers}
+ * will report exactly those modifier bits required for any similarly
+ * declared method, including in this case {@code native} and {@code varargs} bits.
+ * <p>
+ * As with any reflected method, these methods (when reflected) may be
+ * invoked via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.
+ * However, such reflective calls do not result in method handle invocations.
+ * Such a call, if passed the required argument
+ * (a single one, of type {@code Object[]}), will ignore the argument and
+ * will throw an {@code UnsupportedOperationException}.
+ * <p>
+ * Since {@code invokevirtual} instructions can natively
+ * invoke method handles under any symbolic type descriptor, this reflective view conflicts
+ * with the normal presentation of these methods via bytecodes.
+ * Thus, these two native methods, when reflectively viewed by
+ * {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
+ * <p>
+ * In order to obtain an invoker method for a particular type descriptor,
+ * use {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker},
+ * or {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}.
+ * The {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
+ * API is also able to return a method handle
+ * to call {@code invokeExact} or plain {@code invoke},
+ * for any specified type descriptor .
+ *
+ * <h1>Interoperation between method handles and Java generics</h1>
+ * A method handle can be obtained on a method, constructor, or field
+ * which is declared with Java generic types.
+ * As with the Core Reflection API, the type of the method handle
+ * will constructed from the erasure of the source-level type.
+ * When a method handle is invoked, the types of its arguments
+ * or the return value cast type may be generic types or type instances.
+ * If this occurs, the compiler will replace those
+ * types by their erasures when it constructs the symbolic type descriptor
+ * for the {@code invokevirtual} instruction.
+ * <p>
+ * Method handles do not represent
+ * their function-like types in terms of Java parameterized (generic) types,
+ * because there are three mismatches between function-like types and parameterized
+ * Java types.
+ * <ul>
+ * <li>Method types range over all possible arities,
+ * from no arguments to up to the  <a href="MethodHandle.html#maxarity">maximum number</a> of allowed arguments.
+ * Generics are not variadic, and so cannot represent this.</li>
+ * <li>Method types can specify arguments of primitive types,
+ * which Java generic types cannot range over.</li>
+ * <li>Higher order functions over method handles (combinators) are
+ * often generic across a wide range of function types, including
+ * those of multiple arities.  It is impossible to represent such
+ * genericity with a Java type parameter.</li>
+ * </ul>
+ *
+ * <h1><a name="maxarity"></a>Arity limits</h1>
+ * The JVM imposes on all methods and constructors of any kind an absolute
+ * limit of 255 stacked arguments.  This limit can appear more restrictive
+ * in certain cases:
+ * <ul>
+ * <li>A {@code long} or {@code double} argument counts (for purposes of arity limits) as two argument slots.
+ * <li>A non-static method consumes an extra argument for the object on which the method is called.
+ * <li>A constructor consumes an extra argument for the object which is being constructed.
+ * <li>Since a method handle&rsquo;s {@code invoke} method (or other signature-polymorphic method) is non-virtual,
+ *     it consumes an extra argument for the method handle itself, in addition to any non-virtual receiver object.
+ * </ul>
+ * These limits imply that certain method handles cannot be created, solely because of the JVM limit on stacked arguments.
+ * For example, if a static JVM method accepts exactly 255 arguments, a method handle cannot be created for it.
+ * Attempts to create method handles with impossible method types lead to an {@link IllegalArgumentException}.
+ * In particular, a method handle&rsquo;s type must not have an arity of the exact maximum 255.
+ *
+ * @see MethodType
+ * @see MethodHandles
+ * @author John Rose, JSR 292 EG
+ */
+public abstract class MethodHandle {
+    // Android-removed: MethodHandleImpl.initStatics() unused on Android.
+    // static { MethodHandleImpl.initStatics(); }
+
+    /**
+     * Internal marker interface which distinguishes (to the Java compiler)
+     * those methods which are <a href="MethodHandle.html#sigpoly">signature polymorphic</a>.
+     *
+     * @hide
+     */
+    @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD})
+    @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+    // Android-changed: Made public @hide as otherwise it breaks the stubs generation.
+    // @interface PolymorphicSignature { }
+    public @interface PolymorphicSignature { }
+
+    // Android-added: Comment to differentiate between type and nominalType.
+    /**
+     * The type of this method handle, this corresponds to the exact type of the method
+     * being invoked.
+     * 
+     * @see #nominalType
+     */
+    private final MethodType type;
+    // Android-removed: LambdaForm and customizationCount unused on Android.
+    // They will be substituted with appropriate implementation / delegate classes.
+    /*
+    /*private* final LambdaForm form;
+    // form is not private so that invokers can easily fetch it
+    /*private* MethodHandle asTypeCache;
+    // asTypeCache is not private so that invokers can easily fetch it
+    /*non-public* byte customizationCount;
+    // customizationCount should be accessible from invokers
+    */
+
+    // BEGIN Android-added: Android specific implementation.
+    // The MethodHandle functionality is tightly coupled with internal details of the runtime and
+    // so Android has a completely different implementation compared to the RI.
+    /**
+     * The nominal type of this method handle, will be non-null if a method handle declares
+     * a different type from its "real" type, which is either the type of the method being invoked
+     * or the type of the emulated stackframe expected by an underyling adapter.
+     */
+    private MethodType nominalType;
+
+    /**
+     * The spread invoker associated with this type with zero trailing arguments.
+     * This is used to speed up invokeWithArguments.
+     */
+    private MethodHandle cachedSpreadInvoker;
+
+    /**
+     * The INVOKE* constants and SGET/SPUT and IGET/IPUT constants specify the behaviour of this
+     * method handle with respect to the ArtField* or the ArtMethod* that it operates on. These
+     * behaviours are equivalent to the dex bytecode behaviour on the respective method_id or
+     * field_id in the equivalent instruction.
+     *
+     * INVOKE_TRANSFORM is a special type of handle which doesn't encode any dex bytecode behaviour,
+     * instead it transforms the list of input arguments or performs other higher order operations
+     * before (optionally) delegating to another method handle.
+     *
+     * INVOKE_CALLSITE_TRANSFORM is a variation on INVOKE_TRANSFORM where the method type of
+     * a MethodHandle dynamically varies based on the callsite. This is used by
+     * the VarargsCollector implementation which places any number of trailing arguments
+     * into an array before invoking an arity method. The "any number of trailing arguments" means
+     * it would otherwise generate WrongMethodTypeExceptions as the callsite method type and
+     * VarargsCollector method type appear incompatible.
+     */
+
+    /** @hide */ public static final int INVOKE_VIRTUAL = 0;
+    /** @hide */ public static final int INVOKE_SUPER = 1;
+    /** @hide */ public static final int INVOKE_DIRECT = 2;
+    /** @hide */ public static final int INVOKE_STATIC = 3;
+    /** @hide */ public static final int INVOKE_INTERFACE = 4;
+    /** @hide */ public static final int INVOKE_TRANSFORM = 5;
+    /** @hide */ public static final int INVOKE_CALLSITE_TRANSFORM = 6;
+    /** @hide */ public static final int INVOKE_VAR_HANDLE = 7;
+    /** @hide */ public static final int INVOKE_VAR_HANDLE_EXACT = 8;
+    /** @hide */ public static final int IGET = 9;
+    /** @hide */ public static final int IPUT = 10;
+    /** @hide */ public static final int SGET = 11;
+    /** @hide */ public static final int SPUT = 12;
+
+    // The kind of this method handle (used by the runtime). This is one of the INVOKE_*
+    // constants or SGET/SPUT, IGET/IPUT.
+    /** @hide */ protected final int handleKind;
+
+    // The ArtMethod* or ArtField* associated with this method handle (used by the runtime).
+    /** @hide */ protected final long artFieldOrMethod;
+
+    /** @hide */
+    protected MethodHandle(long artFieldOrMethod, int handleKind, MethodType type) {
+        this.artFieldOrMethod = artFieldOrMethod;
+        this.handleKind = handleKind;
+        this.type = type;
+    }
+    // END Android-added: Android specific implementation.
+
+    /**
+     * Reports the type of this method handle.
+     * Every invocation of this method handle via {@code invokeExact} must exactly match this type.
+     * @return the method handle type
+     */
+    public MethodType type() {
+        // Android-added: Added nominalType field.
+        if (nominalType != null) {
+            return nominalType;
+        }
+
+        return type;
+    }
+
+    // BEGIN Android-removed: LambdaForm unsupported on Android.
+    /*
+    /**
+     * Package-private constructor for the method handle implementation hierarchy.
+     * Method handle inheritance will be contained completely within
+     * the {@code java.lang.invoke} package.
+     *
+    // @param type type (permanently assigned) of the new method handle
+    /*non-public* MethodHandle(MethodType type, LambdaForm form) {
+        type.getClass();  // explicit NPE
+        form.getClass();  // explicit NPE
+        this.type = type;
+        this.form = form.uncustomize();
+
+        this.form.prepare();  // TO DO:  Try to delay this step until just before invocation.
+    }
+    */
+    // END Android-removed: LambdaForm unsupported on Android.
+
+    /**
+     * Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
+     * The symbolic type descriptor at the call site of {@code invokeExact} must
+     * exactly match this method handle's {@link #type type}.
+     * No conversions are allowed on arguments or return values.
+     * <p>
+     * When this method is observed via the Core Reflection API,
+     * it will appear as a single native method, taking an object array and returning an object.
+     * If this native method is invoked directly via
+     * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
+     * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
+     * it will throw an {@code UnsupportedOperationException}.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     * @throws WrongMethodTypeException if the target's type is not identical with the caller's symbolic type descriptor
+     * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
+     */
+    public final native @PolymorphicSignature Object invokeExact(Object... args) throws Throwable;
+
+    /**
+     * Invokes the method handle, allowing any caller type descriptor,
+     * and optionally performing conversions on arguments and return values.
+     * <p>
+     * If the call site's symbolic type descriptor exactly matches this method handle's {@link #type type},
+     * the call proceeds as if by {@link #invokeExact invokeExact}.
+     * <p>
+     * Otherwise, the call proceeds as if this method handle were first
+     * adjusted by calling {@link #asType asType} to adjust this method handle
+     * to the required type, and then the call proceeds as if by
+     * {@link #invokeExact invokeExact} on the adjusted method handle.
+     * <p>
+     * There is no guarantee that the {@code asType} call is actually made.
+     * If the JVM can predict the results of making the call, it may perform
+     * adaptations directly on the caller's arguments,
+     * and call the target method handle according to its own exact type.
+     * <p>
+     * The resolved type descriptor at the call site of {@code invoke} must
+     * be a valid argument to the receivers {@code asType} method.
+     * In particular, the caller must specify the same argument arity
+     * as the callee's type,
+     * if the callee is not a {@linkplain #asVarargsCollector variable arity collector}.
+     * <p>
+     * When this method is observed via the Core Reflection API,
+     * it will appear as a single native method, taking an object array and returning an object.
+     * If this native method is invoked directly via
+     * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}, via JNI,
+     * or indirectly via {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect},
+     * it will throw an {@code UnsupportedOperationException}.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     * @throws WrongMethodTypeException if the target's type cannot be adjusted to the caller's symbolic type descriptor
+     * @throws ClassCastException if the target's type can be adjusted to the caller, but a reference cast fails
+     * @throws Throwable anything thrown by the underlying method propagates unchanged through the method handle call
+     */
+    public final native @PolymorphicSignature Object invoke(Object... args) throws Throwable;
+
+    // BEGIN Android-removed: RI implementation unused on Android.
+    /*
+    /**
+     * Private method for trusted invocation of a method handle respecting simplified signatures.
+     * Type mismatches will not throw {@code WrongMethodTypeException}, but could crash the JVM.
+     * <p>
+     * The caller signature is restricted to the following basic types:
+     * Object, int, long, float, double, and void return.
+     * <p>
+     * The caller is responsible for maintaining type correctness by ensuring
+     * that the each outgoing argument value is a member of the range of the corresponding
+     * callee argument type.
+     * (The caller should therefore issue appropriate casts and integer narrowing
+     * operations on outgoing argument values.)
+     * The caller can assume that the incoming result value is part of the range
+     * of the callee's return type.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     *
+    /*non-public* final native @PolymorphicSignature Object invokeBasic(Object... args) throws Throwable;
+
+    /**
+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeVirtual}.
+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
+     * The trailing (not leading) argument must be a MemberName.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     *
+    /*non-public* static native @PolymorphicSignature Object linkToVirtual(Object... args) throws Throwable;
+
+    /**
+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeStatic}.
+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
+     * The trailing (not leading) argument must be a MemberName.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     *
+    /*non-public* static native @PolymorphicSignature Object linkToStatic(Object... args) throws Throwable;
+
+    /**
+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeSpecial}.
+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
+     * The trailing (not leading) argument must be a MemberName.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     *
+    /*non-public* static native @PolymorphicSignature Object linkToSpecial(Object... args) throws Throwable;
+
+    /**
+     * Private method for trusted invocation of a MemberName of kind {@code REF_invokeInterface}.
+     * The caller signature is restricted to basic types as with {@code invokeBasic}.
+     * The trailing (not leading) argument must be a MemberName.
+     * @param args the signature-polymorphic parameter list, statically represented using varargs
+     * @return the signature-polymorphic result, statically represented using {@code Object}
+     *
+    /*non-public* static native @PolymorphicSignature Object linkToInterface(Object... args) throws Throwable;
+    */
+    // END Android-removed: RI implementation unused on Android.
+
+    /**
+     * Performs a variable arity invocation, passing the arguments in the given list
+     * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
+     * which mentions only the type {@code Object}, and whose arity is the length
+     * of the argument list.
+     * <p>
+     * Specifically, execution proceeds as if by the following steps,
+     * although the methods are not guaranteed to be called if the JVM
+     * can predict their effects.
+     * <ul>
+     * <li>Determine the length of the argument array as {@code N}.
+     *     For a null reference, {@code N=0}. </li>
+     * <li>Determine the general type {@code TN} of {@code N} arguments as
+     *     as {@code TN=MethodType.genericMethodType(N)}.</li>
+     * <li>Force the original target method handle {@code MH0} to the
+     *     required type, as {@code MH1 = MH0.asType(TN)}. </li>
+     * <li>Spread the array into {@code N} separate arguments {@code A0, ...}. </li>
+     * <li>Invoke the type-adjusted method handle on the unpacked arguments:
+     *     MH1.invokeExact(A0, ...). </li>
+     * <li>Take the return value as an {@code Object} reference. </li>
+     * </ul>
+     * <p>
+     * Because of the action of the {@code asType} step, the following argument
+     * conversions are applied as necessary:
+     * <ul>
+     * <li>reference casting
+     * <li>unboxing
+     * <li>widening primitive conversions
+     * </ul>
+     * <p>
+     * The result returned by the call is boxed if it is a primitive,
+     * or forced to null if the return type is void.
+     * <p>
+     * This call is equivalent to the following code:
+     * <blockquote><pre>{@code
+     * MethodHandle invoker = MethodHandles.spreadInvoker(this.type(), 0);
+     * Object result = invoker.invokeExact(this, arguments);
+     * }</pre></blockquote>
+     * <p>
+     * Unlike the signature polymorphic methods {@code invokeExact} and {@code invoke},
+     * {@code invokeWithArguments} can be accessed normally via the Core Reflection API and JNI.
+     * It can therefore be used as a bridge between native or reflective code and method handles.
+     *
+     * @param arguments the arguments to pass to the target
+     * @return the result returned by the target
+     * @throws ClassCastException if an argument cannot be converted by reference casting
+     * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
+     * @throws Throwable anything thrown by the target method invocation
+     * @see MethodHandles#spreadInvoker
+     */
+    public Object invokeWithArguments(Object... arguments) throws Throwable {
+        // BEGIN Android-changed: Android specific implementation.
+        // MethodType invocationType = MethodType.genericMethodType(arguments == null ? 0 : arguments.length);
+        // return invocationType.invokers().spreadInvoker(0).invokeExact(asType(invocationType), arguments);
+        MethodHandle invoker = null;
+        synchronized (this) {
+            if (cachedSpreadInvoker == null) {
+                cachedSpreadInvoker = MethodHandles.spreadInvoker(this.type(), 0);
+            }
+
+            invoker = cachedSpreadInvoker;
+        }
+
+        return invoker.invoke(this, arguments);
+        // END Android-changed: Android specific implementation.
+    }
+
+    /**
+     * Performs a variable arity invocation, passing the arguments in the given array
+     * to the method handle, as if via an inexact {@link #invoke invoke} from a call site
+     * which mentions only the type {@code Object}, and whose arity is the length
+     * of the argument array.
+     * <p>
+     * This method is also equivalent to the following code:
+     * <blockquote><pre>{@code
+     *   invokeWithArguments(arguments.toArray()
+     * }</pre></blockquote>
+     *
+     * @param arguments the arguments to pass to the target
+     * @return the result returned by the target
+     * @throws NullPointerException if {@code arguments} is a null reference
+     * @throws ClassCastException if an argument cannot be converted by reference casting
+     * @throws WrongMethodTypeException if the target's type cannot be adjusted to take the given number of {@code Object} arguments
+     * @throws Throwable anything thrown by the target method invocation
+     */
+    public Object invokeWithArguments(java.util.List<?> arguments) throws Throwable {
+        return invokeWithArguments(arguments.toArray());
+    }
+
+    /**
+     * Produces an adapter method handle which adapts the type of the
+     * current method handle to a new type.
+     * The resulting method handle is guaranteed to report a type
+     * which is equal to the desired new type.
+     * <p>
+     * If the original type and new type are equal, returns {@code this}.
+     * <p>
+     * The new method handle, when invoked, will perform the following
+     * steps:
+     * <ul>
+     * <li>Convert the incoming argument list to match the original
+     *     method handle's argument list.
+     * <li>Invoke the original method handle on the converted argument list.
+     * <li>Convert any result returned by the original method handle
+     *     to the return type of new method handle.
+     * </ul>
+     * <p>
+     * This method provides the crucial behavioral difference between
+     * {@link #invokeExact invokeExact} and plain, inexact {@link #invoke invoke}.
+     * The two methods
+     * perform the same steps when the caller's type descriptor exactly m atches
+     * the callee's, but when the types differ, plain {@link #invoke invoke}
+     * also calls {@code asType} (or some internal equivalent) in order
+     * to match up the caller's and callee's types.
+     * <p>
+     * If the current method is a variable arity method handle
+     * argument list conversion may involve the conversion and collection
+     * of several arguments into an array, as
+     * {@linkplain #asVarargsCollector described elsewhere}.
+     * In every other case, all conversions are applied <em>pairwise</em>,
+     * which means that each argument or return value is converted to
+     * exactly one argument or return value (or no return value).
+     * The applied conversions are defined by consulting the
+     * the corresponding component types of the old and new
+     * method handle types.
+     * <p>
+     * Let <em>T0</em> and <em>T1</em> be corresponding new and old parameter types,
+     * or old and new return types.  Specifically, for some valid index {@code i}, let
+     * <em>T0</em>{@code =newType.parameterType(i)} and <em>T1</em>{@code =this.type().parameterType(i)}.
+     * Or else, going the other way for return values, let
+     * <em>T0</em>{@code =this.type().returnType()} and <em>T1</em>{@code =newType.returnType()}.
+     * If the types are the same, the new method handle makes no change
+     * to the corresponding argument or return value (if any).
+     * Otherwise, one of the following conversions is applied
+     * if possible:
+     * <ul>
+     * <li>If <em>T0</em> and <em>T1</em> are references, then a cast to <em>T1</em> is applied.
+     *     (The types do not need to be related in any particular way.
+     *     This is because a dynamic value of null can convert to any reference type.)
+     * <li>If <em>T0</em> and <em>T1</em> are primitives, then a Java method invocation
+     *     conversion (JLS 5.3) is applied, if one exists.
+     *     (Specifically, <em>T0</em> must convert to <em>T1</em> by a widening primitive conversion.)
+     * <li>If <em>T0</em> is a primitive and <em>T1</em> a reference,
+     *     a Java casting conversion (JLS 5.5) is applied if one exists.
+     *     (Specifically, the value is boxed from <em>T0</em> to its wrapper class,
+     *     which is then widened as needed to <em>T1</em>.)
+     * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+     *     conversion will be applied at runtime, possibly followed
+     *     by a Java method invocation conversion (JLS 5.3)
+     *     on the primitive value.  (These are the primitive widening conversions.)
+     *     <em>T0</em> must be a wrapper class or a supertype of one.
+     *     (In the case where <em>T0</em> is Object, these are the conversions
+     *     allowed by {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}.)
+     *     The unboxing conversion must have a possibility of success, which means that
+     *     if <em>T0</em> is not itself a wrapper class, there must exist at least one
+     *     wrapper class <em>TW</em> which is a subtype of <em>T0</em> and whose unboxed
+     *     primitive value can be widened to <em>T1</em>.
+     * <li>If the return type <em>T1</em> is marked as void, any returned value is discarded
+     * <li>If the return type <em>T0</em> is void and <em>T1</em> a reference, a null value is introduced.
+     * <li>If the return type <em>T0</em> is void and <em>T1</em> a primitive,
+     *     a zero value is introduced.
+     * </ul>
+     * (<em>Note:</em> Both <em>T0</em> and <em>T1</em> may be regarded as static types,
+     * because neither corresponds specifically to the <em>dynamic type</em> of any
+     * actual argument or return value.)
+     * <p>
+     * The method handle conversion cannot be made if any one of the required
+     * pairwise conversions cannot be made.
+     * <p>
+     * At runtime, the conversions applied to reference arguments
+     * or return values may require additional runtime checks which can fail.
+     * An unboxing operation may fail because the original reference is null,
+     * causing a {@link java.lang.NullPointerException NullPointerException}.
+     * An unboxing operation or a reference cast may also fail on a reference
+     * to an object of the wrong type,
+     * causing a {@link java.lang.ClassCastException ClassCastException}.
+     * Although an unboxing operation may accept several kinds of wrappers,
+     * if none are available, a {@code ClassCastException} will be thrown.
+     *
+     * @param newType the expected type of the new method handle
+     * @return a method handle which delegates to {@code this} after performing
+     *           any necessary argument conversions, and arranges for any
+     *           necessary return value conversions
+     * @throws NullPointerException if {@code newType} is a null reference
+     * @throws WrongMethodTypeException if the conversion cannot be made
+     * @see MethodHandles#explicitCastArguments
+     */
+    public MethodHandle asType(MethodType newType) {
+        // Fast path alternative to a heavyweight {@code asType} call.
+        // Return 'this' if the conversion will be a no-op.
+        if (newType == type) {
+            return this;
+        }
+        // Android-removed: Type conversion memoizing is unsupported on Android.
+        /*
+        // Return 'this.asTypeCache' if the conversion is already memoized.
+        MethodHandle atc = asTypeCached(newType);
+        if (atc != null) {
+            return atc;
+        }
+        */
+        return asTypeUncached(newType);
+    }
+
+    // Android-removed: Type conversion memoizing is unsupported on Android.
+    /*
+    private MethodHandle asTypeCached(MethodType newType) {
+        MethodHandle atc = asTypeCache;
+        if (atc != null && newType == atc.type) {
+            return atc;
+        }
+        return null;
+    }
+    */
+
+    /** Override this to change asType behavior. */
+    /*non-public*/ MethodHandle asTypeUncached(MethodType newType) {
+        if (!type.isConvertibleTo(newType))
+            throw new WrongMethodTypeException("cannot convert "+this+" to "+newType);
+        // BEGIN Android-changed: Android specific implementation.
+        // return asTypeCache = MethodHandleImpl.makePairwiseConvert(this, newType, true);
+        MethodHandle mh = duplicate();
+        mh.nominalType = newType;
+        return mh;
+        // END Android-changed: Android specific implementation.
+    }
+
+    /**
+     * Makes an <em>array-spreading</em> method handle, which accepts a trailing array argument
+     * and spreads its elements as positional arguments.
+     * The new method handle adapts, as its <i>target</i>,
+     * the current method handle.  The type of the adapter will be
+     * the same as the type of the target, except that the final
+     * {@code arrayLength} parameters of the target's type are replaced
+     * by a single array parameter of type {@code arrayType}.
+     * <p>
+     * If the array element type differs from any of the corresponding
+     * argument types on the original target,
+     * the original target is adapted to take the array elements directly,
+     * as if by a call to {@link #asType asType}.
+     * <p>
+     * When called, the adapter replaces a trailing array argument
+     * by the array's elements, each as its own argument to the target.
+     * (The order of the arguments is preserved.)
+     * They are converted pairwise by casting and/or unboxing
+     * to the types of the trailing parameters of the target.
+     * Finally the target is called.
+     * What the target eventually returns is returned unchanged by the adapter.
+     * <p>
+     * Before calling the target, the adapter verifies that the array
+     * contains exactly enough elements to provide a correct argument count
+     * to the target method handle.
+     * (The array may also be null when zero elements are required.)
+     * <p>
+     * If, when the adapter is called, the supplied array argument does
+     * not have the correct number of elements, the adapter will throw
+     * an {@link IllegalArgumentException} instead of invoking the target.
+     * <p>
+     * Here are some simple examples of array-spreading method handles:
+     * <blockquote><pre>{@code
+MethodHandle equals = publicLookup()
+  .findVirtual(String.class, "equals", methodType(boolean.class, Object.class));
+assert( (boolean) equals.invokeExact("me", (Object)"me"));
+assert(!(boolean) equals.invokeExact("me", (Object)"thee"));
+// spread both arguments from a 2-array:
+MethodHandle eq2 = equals.asSpreader(Object[].class, 2);
+assert( (boolean) eq2.invokeExact(new Object[]{ "me", "me" }));
+assert(!(boolean) eq2.invokeExact(new Object[]{ "me", "thee" }));
+// try to spread from anything but a 2-array:
+for (int n = 0; n <= 10; n++) {
+  Object[] badArityArgs = (n == 2 ? null : new Object[n]);
+  try { assert((boolean) eq2.invokeExact(badArityArgs) && false); }
+  catch (IllegalArgumentException ex) { } // OK
+}
+// spread both arguments from a String array:
+MethodHandle eq2s = equals.asSpreader(String[].class, 2);
+assert( (boolean) eq2s.invokeExact(new String[]{ "me", "me" }));
+assert(!(boolean) eq2s.invokeExact(new String[]{ "me", "thee" }));
+// spread second arguments from a 1-array:
+MethodHandle eq1 = equals.asSpreader(Object[].class, 1);
+assert( (boolean) eq1.invokeExact("me", new Object[]{ "me" }));
+assert(!(boolean) eq1.invokeExact("me", new Object[]{ "thee" }));
+// spread no arguments from a 0-array or null:
+MethodHandle eq0 = equals.asSpreader(Object[].class, 0);
+assert( (boolean) eq0.invokeExact("me", (Object)"me", new Object[0]));
+assert(!(boolean) eq0.invokeExact("me", (Object)"thee", (Object[])null));
+// asSpreader and asCollector are approximate inverses:
+for (int n = 0; n <= 2; n++) {
+    for (Class<?> a : new Class<?>[]{Object[].class, String[].class, CharSequence[].class}) {
+        MethodHandle equals2 = equals.asSpreader(a, n).asCollector(a, n);
+        assert( (boolean) equals2.invokeWithArguments("me", "me"));
+        assert(!(boolean) equals2.invokeWithArguments("me", "thee"));
+    }
+}
+MethodHandle caToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, char[].class));
+assertEquals("[A, B, C]", (String) caToString.invokeExact("ABC".toCharArray()));
+MethodHandle caString3 = caToString.asCollector(char[].class, 3);
+assertEquals("[A, B, C]", (String) caString3.invokeExact('A', 'B', 'C'));
+MethodHandle caToString2 = caString3.asSpreader(char[].class, 2);
+assertEquals("[A, B, C]", (String) caToString2.invokeExact('A', "BC".toCharArray()));
+     * }</pre></blockquote>
+     * @param arrayType usually {@code Object[]}, the type of the array argument from which to extract the spread arguments
+     * @param arrayLength the number of arguments to spread from an incoming array argument
+     * @return a new method handle which spreads its final array argument,
+     *         before calling the original method handle
+     * @throws NullPointerException if {@code arrayType} is a null reference
+     * @throws IllegalArgumentException if {@code arrayType} is not an array type,
+     *         or if target does not have at least
+     *         {@code arrayLength} parameter types,
+     *         or if {@code arrayLength} is negative,
+     *         or if the resulting method handle's type would have
+     *         <a href="MethodHandle.html#maxarity">too many parameters</a>
+     * @throws WrongMethodTypeException if the implied {@code asType} call fails
+     * @see #asCollector
+     */
+    public MethodHandle asSpreader(Class<?> arrayType, int arrayLength) {
+        MethodType postSpreadType = asSpreaderChecks(arrayType, arrayLength);
+        // BEGIN Android-changed: Android specific implementation.
+        /*
+        int arity = type().parameterCount();
+        int spreadArgPos = arity - arrayLength;
+        MethodHandle afterSpread = this.asType(postSpreadType);
+        BoundMethodHandle mh = afterSpread.rebind();
+        LambdaForm lform = mh.editor().spreadArgumentsForm(1 + spreadArgPos, arrayType, arrayLength);
+        MethodType preSpreadType = postSpreadType.replaceParameterTypes(spreadArgPos, arity, arrayType);
+        return mh.copyWith(preSpreadType, lform);
+        */
+        final int targetParamCount = postSpreadType.parameterCount();
+        MethodType dropArrayArgs = postSpreadType.dropParameterTypes(
+                (targetParamCount - arrayLength), targetParamCount);
+        MethodType adapterType = dropArrayArgs.appendParameterTypes(arrayType);
+
+        return new Transformers.Spreader(this, adapterType, arrayLength);
+        // END Android-changed: Android specific implementation.
+    }
+
+    /**
+     * See if {@code asSpreader} can be validly called with the given arguments.
+     * Return the type of the method handle call after spreading but before conversions.
+     */
+    private MethodType asSpreaderChecks(Class<?> arrayType, int arrayLength) {
+        spreadArrayChecks(arrayType, arrayLength);
+        int nargs = type().parameterCount();
+        if (nargs < arrayLength || arrayLength < 0)
+            throw newIllegalArgumentException("bad spread array length");
+        Class<?> arrayElement = arrayType.getComponentType();
+        MethodType mtype = type();
+        boolean match = true, fail = false;
+        for (int i = nargs - arrayLength; i < nargs; i++) {
+            Class<?> ptype = mtype.parameterType(i);
+            if (ptype != arrayElement) {
+                match = false;
+                if (!MethodType.canConvert(arrayElement, ptype)) {
+                    fail = true;
+                    break;
+                }
+            }
+        }
+        if (match)  return mtype;
+        MethodType needType = mtype.asSpreaderType(arrayType, arrayLength);
+        if (!fail)  return needType;
+        // elicit an error:
+        this.asType(needType);
+        throw newInternalError("should not return", null);
+    }
+
+    private void spreadArrayChecks(Class<?> arrayType, int arrayLength) {
+        Class<?> arrayElement = arrayType.getComponentType();
+        if (arrayElement == null)
+            throw newIllegalArgumentException("not an array type", arrayType);
+        if ((arrayLength & 0x7F) != arrayLength) {
+            if ((arrayLength & 0xFF) != arrayLength)
+                throw newIllegalArgumentException("array length is not legal", arrayLength);
+            assert(arrayLength >= 128);
+            if (arrayElement == long.class ||
+                arrayElement == double.class)
+                throw newIllegalArgumentException("array length is not legal for long[] or double[]", arrayLength);
+        }
+    }
+
+    /**
+     * Makes an <em>array-collecting</em> method handle, which accepts a given number of trailing
+     * positional arguments and collects them into an array argument.
+     * The new method handle adapts, as its <i>target</i>,
+     * the current method handle.  The type of the adapter will be
+     * the same as the type of the target, except that a single trailing
+     * parameter (usually of type {@code arrayType}) is replaced by
+     * {@code arrayLength} parameters whose type is element type of {@code arrayType}.
+     * <p>
+     * If the array type differs from the final argument type on the original target,
+     * the original target is adapted to take the array type directly,
+     * as if by a call to {@link #asType asType}.
+     * <p>
+     * When called, the adapter replaces its trailing {@code arrayLength}
+     * arguments by a single new array of type {@code arrayType}, whose elements
+     * comprise (in order) the replaced arguments.
+     * Finally the target is called.
+     * What the target eventually returns is returned unchanged by the adapter.
+     * <p>
+     * (The array may also be a shared constant when {@code arrayLength} is zero.)
+     * <p>
+     * (<em>Note:</em> The {@code arrayType} is often identical to the last
+     * parameter type of the original target.
+     * It is an explicit argument for symmetry with {@code asSpreader}, and also
+     * to allow the target to use a simple {@code Object} as its last parameter type.)
+     * <p>
+     * In order to create a collecting adapter which is not restricted to a particular
+     * number of collected arguments, use {@link #asVarargsCollector asVarargsCollector} instead.
+     * <p>
+     * Here are some examples of array-collecting method handles:
+     * <blockquote><pre>{@code
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+assertEquals("[won]",   (String) deepToString.invokeExact(new Object[]{"won"}));
+MethodHandle ts1 = deepToString.asCollector(Object[].class, 1);
+assertEquals(methodType(String.class, Object.class), ts1.type());
+//assertEquals("[won]", (String) ts1.invokeExact(         new Object[]{"won"})); //FAIL
+assertEquals("[[won]]", (String) ts1.invokeExact((Object) new Object[]{"won"}));
+// arrayType can be a subtype of Object[]
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals(methodType(String.class, String.class, String.class), ts2.type());
+assertEquals("[two, too]", (String) ts2.invokeExact("two", "too"));
+MethodHandle ts0 = deepToString.asCollector(Object[].class, 0);
+assertEquals("[]", (String) ts0.invokeExact());
+// collectors can be nested, Lisp-style
+MethodHandle ts22 = deepToString.asCollector(Object[].class, 3).asCollector(String[].class, 2);
+assertEquals("[A, B, [C, D]]", ((String) ts22.invokeExact((Object)'A', (Object)"B", "C", "D")));
+// arrayType can be any primitive array type
+MethodHandle bytesToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, byte[].class))
+  .asCollector(byte[].class, 3);
+assertEquals("[1, 2, 3]", (String) bytesToString.invokeExact((byte)1, (byte)2, (byte)3));
+MethodHandle longsToString = publicLookup()
+  .findStatic(Arrays.class, "toString", methodType(String.class, long[].class))
+  .asCollector(long[].class, 1);
+assertEquals("[123]", (String) longsToString.invokeExact((long)123));
+     * }</pre></blockquote>
+     * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+     * @param arrayLength the number of arguments to collect into a new array argument
+     * @return a new method handle which collects some trailing argument
+     *         into an array, before calling the original method handle
+     * @throws NullPointerException if {@code arrayType} is a null reference
+     * @throws IllegalArgumentException if {@code arrayType} is not an array type
+     *         or {@code arrayType} is not assignable to this method handle's trailing parameter type,
+     *         or {@code arrayLength} is not a legal array size,
+     *         or the resulting method handle's type would have
+     *         <a href="MethodHandle.html#maxarity">too many parameters</a>
+     * @throws WrongMethodTypeException if the implied {@code asType} call fails
+     * @see #asSpreader
+     * @see #asVarargsCollector
+     */
+    public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
+        asCollectorChecks(arrayType, arrayLength);
+        // BEGIN Android-changed: Android specific implementation.
+        /*
+        int collectArgPos = type().parameterCount() - 1;
+        BoundMethodHandle mh = rebind();
+        MethodType resultType = type().asCollectorType(arrayType, arrayLength);
+        MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
+        LambdaForm lform = mh.editor().collectArgumentArrayForm(1 + collectArgPos, newArray);
+        if (lform != null) {
+            return mh.copyWith(resultType, lform);
+        }
+        lform = mh.editor().collectArgumentsForm(1 + collectArgPos, newArray.type().basicType());
+        return mh.copyWithExtendL(resultType, lform, newArray);
+        */
+        return new Transformers.Collector(this, arrayType, arrayLength);
+        // END Android-changed: Android specific implementation.
+    }
+
+    /**
+     * See if {@code asCollector} can be validly called with the given arguments.
+     * Return false if the last parameter is not an exact match to arrayType.
+     */
+    /*non-public*/ boolean asCollectorChecks(Class<?> arrayType, int arrayLength) {
+        spreadArrayChecks(arrayType, arrayLength);
+        int nargs = type().parameterCount();
+        if (nargs != 0) {
+            Class<?> lastParam = type().parameterType(nargs-1);
+            if (lastParam == arrayType)  return true;
+            if (lastParam.isAssignableFrom(arrayType))  return false;
+        }
+        throw newIllegalArgumentException("array type not assignable to trailing argument", this, arrayType);
+    }
+
+    /**
+     * Makes a <em>variable arity</em> adapter which is able to accept
+     * any number of trailing positional arguments and collect them
+     * into an array argument.
+     * <p>
+     * The type and behavior of the adapter will be the same as
+     * the type and behavior of the target, except that certain
+     * {@code invoke} and {@code asType} requests can lead to
+     * trailing positional arguments being collected into target's
+     * trailing parameter.
+     * Also, the last parameter type of the adapter will be
+     * {@code arrayType}, even if the target has a different
+     * last parameter type.
+     * <p>
+     * This transformation may return {@code this} if the method handle is
+     * already of variable arity and its trailing parameter type
+     * is identical to {@code arrayType}.
+     * <p>
+     * When called with {@link #invokeExact invokeExact}, the adapter invokes
+     * the target with no argument changes.
+     * (<em>Note:</em> This behavior is different from a
+     * {@linkplain #asCollector fixed arity collector},
+     * since it accepts a whole array of indeterminate length,
+     * rather than a fixed number of arguments.)
+     * <p>
+     * When called with plain, inexact {@link #invoke invoke}, if the caller
+     * type is the same as the adapter, the adapter invokes the target as with
+     * {@code invokeExact}.
+     * (This is the normal behavior for {@code invoke} when types match.)
+     * <p>
+     * Otherwise, if the caller and adapter arity are the same, and the
+     * trailing parameter type of the caller is a reference type identical to
+     * or assignable to the trailing parameter type of the adapter,
+     * the arguments and return values are converted pairwise,
+     * as if by {@link #asType asType} on a fixed arity
+     * method handle.
+     * <p>
+     * Otherwise, the arities differ, or the adapter's trailing parameter
+     * type is not assignable from the corresponding caller type.
+     * In this case, the adapter replaces all trailing arguments from
+     * the original trailing argument position onward, by
+     * a new array of type {@code arrayType}, whose elements
+     * comprise (in order) the replaced arguments.
+     * <p>
+     * The caller type must provides as least enough arguments,
+     * and of the correct type, to satisfy the target's requirement for
+     * positional arguments before the trailing array argument.
+     * Thus, the caller must supply, at a minimum, {@code N-1} arguments,
+     * where {@code N} is the arity of the target.
+     * Also, there must exist conversions from the incoming arguments
+     * to the target's arguments.
+     * As with other uses of plain {@code invoke}, if these basic
+     * requirements are not fulfilled, a {@code WrongMethodTypeException}
+     * may be thrown.
+     * <p>
+     * In all cases, what the target eventually returns is returned unchanged by the adapter.
+     * <p>
+     * In the final case, it is exactly as if the target method handle were
+     * temporarily adapted with a {@linkplain #asCollector fixed arity collector}
+     * to the arity required by the caller type.
+     * (As with {@code asCollector}, if the array length is zero,
+     * a shared constant may be used instead of a new array.
+     * If the implied call to {@code asCollector} would throw
+     * an {@code IllegalArgumentException} or {@code WrongMethodTypeException},
+     * the call to the variable arity adapter must throw
+     * {@code WrongMethodTypeException}.)
+     * <p>
+     * The behavior of {@link #asType asType} is also specialized for
+     * variable arity adapters, to maintain the invariant that
+     * plain, inexact {@code invoke} is always equivalent to an {@code asType}
+     * call to adjust the target type, followed by {@code invokeExact}.
+     * Therefore, a variable arity adapter responds
+     * to an {@code asType} request by building a fixed arity collector,
+     * if and only if the adapter and requested type differ either
+     * in arity or trailing argument type.
+     * The resulting fixed arity collector has its type further adjusted
+     * (if necessary) to the requested type by pairwise conversion,
+     * as if by another application of {@code asType}.
+     * <p>
+     * When a method handle is obtained by executing an {@code ldc} instruction
+     * of a {@code CONSTANT_MethodHandle} constant, and the target method is marked
+     * as a variable arity method (with the modifier bit {@code 0x0080}),
+     * the method handle will accept multiple arities, as if the method handle
+     * constant were created by means of a call to {@code asVarargsCollector}.
+     * <p>
+     * In order to create a collecting adapter which collects a predetermined
+     * number of arguments, and whose type reflects this predetermined number,
+     * use {@link #asCollector asCollector} instead.
+     * <p>
+     * No method handle transformations produce new method handles with
+     * variable arity, unless they are documented as doing so.
+     * Therefore, besides {@code asVarargsCollector},
+     * all methods in {@code MethodHandle} and {@code MethodHandles}
+     * will return a method handle with fixed arity,
+     * except in the cases where they are specified to return their original
+     * operand (e.g., {@code asType} of the method handle's own type).
+     * <p>
+     * Calling {@code asVarargsCollector} on a method handle which is already
+     * of variable arity will produce a method handle with the same type and behavior.
+     * It may (or may not) return the original variable arity method handle.
+     * <p>
+     * Here is an example, of a list-making variable arity method handle:
+     * <blockquote><pre>{@code
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+MethodHandle ts1 = deepToString.asVarargsCollector(Object[].class);
+assertEquals("[won]",   (String) ts1.invokeExact(    new Object[]{"won"}));
+assertEquals("[won]",   (String) ts1.invoke(         new Object[]{"won"}));
+assertEquals("[won]",   (String) ts1.invoke(                      "won" ));
+assertEquals("[[won]]", (String) ts1.invoke((Object) new Object[]{"won"}));
+// findStatic of Arrays.asList(...) produces a variable arity method handle:
+MethodHandle asList = publicLookup()
+  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class));
+assertEquals(methodType(List.class, Object[].class), asList.type());
+assert(asList.isVarargsCollector());
+assertEquals("[]", asList.invoke().toString());
+assertEquals("[1]", asList.invoke(1).toString());
+assertEquals("[two, too]", asList.invoke("two", "too").toString());
+String[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asList.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asList.invoke((Object[])argv).toString());
+List ls = (List) asList.invoke((Object)argv);
+assertEquals(1, ls.size());
+assertEquals("[three, thee, tee]", Arrays.toString((Object[])ls.get(0)));
+     * }</pre></blockquote>
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * These rules are designed as a dynamically-typed variation
+     * of the Java rules for variable arity methods.
+     * In both cases, callers to a variable arity method or method handle
+     * can either pass zero or more positional arguments, or else pass
+     * pre-collected arrays of any length.  Users should be aware of the
+     * special role of the final argument, and of the effect of a
+     * type match on that final argument, which determines whether
+     * or not a single trailing argument is interpreted as a whole
+     * array or a single element of an array to be collected.
+     * Note that the dynamic type of the trailing argument has no
+     * effect on this decision, only a comparison between the symbolic
+     * type descriptor of the call site and the type descriptor of the method handle.)
+     *
+     * @param arrayType often {@code Object[]}, the type of the array argument which will collect the arguments
+     * @return a new method handle which can collect any number of trailing arguments
+     *         into an array, before calling the original method handle
+     * @throws NullPointerException if {@code arrayType} is a null reference
+     * @throws IllegalArgumentException if {@code arrayType} is not an array type
+     *         or {@code arrayType} is not assignable to this method handle's trailing parameter type
+     * @see #asCollector
+     * @see #isVarargsCollector
+     * @see #asFixedArity
+     */
+    public MethodHandle asVarargsCollector(Class<?> arrayType) {
+        arrayType.getClass(); // explicit NPE
+        boolean lastMatch = asCollectorChecks(arrayType, 0);
+        if (isVarargsCollector() && lastMatch)
+            return this;
+        // Android-changed: Android specific implementation.
+        // return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+        return new Transformers.VarargsCollector(this);
+    }
+
+    /**
+     * Determines if this method handle
+     * supports {@linkplain #asVarargsCollector variable arity} calls.
+     * Such method handles arise from the following sources:
+     * <ul>
+     * <li>a call to {@linkplain #asVarargsCollector asVarargsCollector}
+     * <li>a call to a {@linkplain java.lang.invoke.MethodHandles.Lookup lookup method}
+     *     which resolves to a variable arity Java method or constructor
+     * <li>an {@code ldc} instruction of a {@code CONSTANT_MethodHandle}
+     *     which resolves to a variable arity Java method or constructor
+     * </ul>
+     * @return true if this method handle accepts more than one arity of plain, inexact {@code invoke} calls
+     * @see #asVarargsCollector
+     * @see #asFixedArity
+     */
+    public boolean isVarargsCollector() {
+        return false;
+    }
+
+    /**
+     * Makes a <em>fixed arity</em> method handle which is otherwise
+     * equivalent to the current method handle.
+     * <p>
+     * If the current method handle is not of
+     * {@linkplain #asVarargsCollector variable arity},
+     * the current method handle is returned.
+     * This is true even if the current method handle
+     * could not be a valid input to {@code asVarargsCollector}.
+     * <p>
+     * Otherwise, the resulting fixed-arity method handle has the same
+     * type and behavior of the current method handle,
+     * except that {@link #isVarargsCollector isVarargsCollector}
+     * will be false.
+     * The fixed-arity method handle may (or may not) be the
+     * a previous argument to {@code asVarargsCollector}.
+     * <p>
+     * Here is an example, of a list-making variable arity method handle:
+     * <blockquote><pre>{@code
+MethodHandle asListVar = publicLookup()
+  .findStatic(Arrays.class, "asList", methodType(List.class, Object[].class))
+  .asVarargsCollector(Object[].class);
+MethodHandle asListFix = asListVar.asFixedArity();
+assertEquals("[1]", asListVar.invoke(1).toString());
+Exception caught = null;
+try { asListFix.invoke((Object)1); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof ClassCastException);
+assertEquals("[two, too]", asListVar.invoke("two", "too").toString());
+try { asListFix.invoke("two", "too"); }
+catch (Exception ex) { caught = ex; }
+assert(caught instanceof WrongMethodTypeException);
+Object[] argv = { "three", "thee", "tee" };
+assertEquals("[three, thee, tee]", asListVar.invoke(argv).toString());
+assertEquals("[three, thee, tee]", asListFix.invoke(argv).toString());
+assertEquals(1, ((List) asListVar.invoke((Object)argv)).size());
+assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
+     * }</pre></blockquote>
+     *
+     * @return a new method handle which accepts only a fixed number of arguments
+     * @see #asVarargsCollector
+     * @see #isVarargsCollector
+     */
+    public MethodHandle asFixedArity() {
+        // BEGIN Android-changed: Android specific implementation.
+        // assert(!isVarargsCollector());
+        // return this;
+
+        MethodHandle mh = this;
+        if (mh.isVarargsCollector()) {
+            mh = ((Transformers.VarargsCollector) mh).asFixedArity();
+        }
+        assert(!mh.isVarargsCollector());
+        return mh;
+        // END Android-changed: Android specific implementation.
+    }
+
+    /**
+     * Binds a value {@code x} to the first argument of a method handle, without invoking it.
+     * The new method handle adapts, as its <i>target</i>,
+     * the current method handle by binding it to the given argument.
+     * The type of the bound handle will be
+     * the same as the type of the target, except that a single leading
+     * reference parameter will be omitted.
+     * <p>
+     * When called, the bound handle inserts the given value {@code x}
+     * as a new leading argument to the target.  The other arguments are
+     * also passed unchanged.
+     * What the target eventually returns is returned unchanged by the bound handle.
+     * <p>
+     * The reference {@code x} must be convertible to the first parameter
+     * type of the target.
+     * <p>
+     * (<em>Note:</em>  Because method handles are immutable, the target method handle
+     * retains its original type and behavior.)
+     * @param x  the value to bind to the first argument of the target
+     * @return a new method handle which prepends the given value to the incoming
+     *         argument list, before calling the original method handle
+     * @throws IllegalArgumentException if the target does not have a
+     *         leading parameter type that is a reference type
+     * @throws ClassCastException if {@code x} cannot be converted
+     *         to the leading parameter type of the target
+     * @see MethodHandles#insertArguments
+     */
+    public MethodHandle bindTo(Object x) {
+        x = type.leadingReferenceParameter().cast(x);  // throw CCE if needed
+        // Android-changed: Android specific implementation.
+        // return bindArgumentL(0, x);
+        return new Transformers.BindTo(this, x);
+    }
+
+    /**
+     * Returns a string representation of the method handle,
+     * starting with the string {@code "MethodHandle"} and
+     * ending with the string representation of the method handle's type.
+     * In other words, this method returns a string equal to the value of:
+     * <blockquote><pre>{@code
+     * "MethodHandle" + type().toString()
+     * }</pre></blockquote>
+     * <p>
+     * (<em>Note:</em>  Future releases of this API may add further information
+     * to the string representation.
+     * Therefore, the present syntax should not be parsed by applications.)
+     *
+     * @return a string representation of the method handle
+     */
+    @Override
+    public String toString() {
+        // Android-removed: Debugging support unused on Android.
+        // if (DEBUG_METHOD_HANDLE_NAMES)  return "MethodHandle"+debugString();
+        return standardString();
+    }
+    String standardString() {
+        return "MethodHandle"+type;
+    }
+
+    // BEGIN Android-removed: Debugging support unused on Android.
+    /*
+    /** Return a string with a several lines describing the method handle structure.
+     *  This string would be suitable for display in an IDE debugger.
+     *
+    String debugString() {
+        return type+" : "+internalForm()+internalProperties();
+    }
+    */
+    // END Android-removed: Debugging support unused on Android.
+
+    // BEGIN Android-added: Android specific implementation.
+    /** @hide */
+    public int getHandleKind() {
+        return handleKind;
+    }
+
+    /** @hide */
+    protected void transform(EmulatedStackFrame arguments) throws Throwable {
+        throw new AssertionError("MethodHandle.transform should never be called.");
+    }
+
+    /**
+     * Creates a copy of this method handle, copying all relevant data.
+     *
+     * @hide
+     */
+    protected MethodHandle duplicate() {
+        try {
+            return (MethodHandle) this.clone();
+        } catch (CloneNotSupportedException cnse) {
+            throw new AssertionError("Subclass of Transformer is not cloneable");
+        }
+    }
+
+    /**
+     * This is the entry point for all transform calls, and dispatches to the protected
+     * transform method. This layer of indirection exists purely for convenience, because
+     * we can invoke-direct on a fixed ArtMethod for all transform variants.
+     *
+     * NOTE: If this extra layer of indirection proves to be a problem, we can get rid
+     * of this layer of indirection at the cost of some additional ugliness.
+     */
+    private void transformInternal(EmulatedStackFrame arguments) throws Throwable {
+        transform(arguments);
+    }
+    // END Android-added: Android specific implementation.
+
+    // BEGIN Android-removed: RI implementation unused on Android.
+    /*
+    //// Implementation methods.
+    //// Sub-classes can override these default implementations.
+    //// All these methods assume arguments are already validated.
+
+    // Other transforms to do:  convert, explicitCast, permute, drop, filter, fold, GWT, catch
+
+    BoundMethodHandle bindArgumentL(int pos, Object value) {
+        return rebind().bindArgumentL(pos, value);
+    }
+
+    /*non-public*
+    MethodHandle setVarargs(MemberName member) throws IllegalAccessException {
+        if (!member.isVarargs())  return this;
+        Class<?> arrayType = type().lastParameterType();
+        if (arrayType.isArray()) {
+            return MethodHandleImpl.makeVarargsCollector(this, arrayType);
+        }
+        throw member.makeAccessException("cannot make variable arity", null);
+    }
+
+    /*non-public*
+    MethodHandle viewAsType(MethodType newType, boolean strict) {
+        // No actual conversions, just a new view of the same method.
+        // Note that this operation must not produce a DirectMethodHandle,
+        // because retyped DMHs, like any transformed MHs,
+        // cannot be cracked into MethodHandleInfo.
+        assert viewAsTypeChecks(newType, strict);
+        BoundMethodHandle mh = rebind();
+        assert(!((MethodHandle)mh instanceof DirectMethodHandle));
+        return mh.copyWith(newType, mh.form);
+    }
+
+    /*non-public*
+    boolean viewAsTypeChecks(MethodType newType, boolean strict) {
+        if (strict) {
+            assert(type().isViewableAs(newType, true))
+                : Arrays.asList(this, newType);
+        } else {
+            assert(type().basicType().isViewableAs(newType.basicType(), true))
+                : Arrays.asList(this, newType);
+        }
+        return true;
+    }
+
+    // Decoding
+
+    /*non-public*
+    LambdaForm internalForm() {
+        return form;
+    }
+
+    /*non-public*
+    MemberName internalMemberName() {
+        return null;  // DMH returns DMH.member
+    }
+
+    /*non-public*
+    Class<?> internalCallerClass() {
+        return null;  // caller-bound MH for @CallerSensitive method returns caller
+    }
+
+    /*non-public*
+    MethodHandleImpl.Intrinsic intrinsicName() {
+        // no special intrinsic meaning to most MHs
+        return MethodHandleImpl.Intrinsic.NONE;
+    }
+
+    /*non-public*
+    MethodHandle withInternalMemberName(MemberName member, boolean isInvokeSpecial) {
+        if (member != null) {
+            return MethodHandleImpl.makeWrappedMember(this, member, isInvokeSpecial);
+        } else if (internalMemberName() == null) {
+            // The required internaMemberName is null, and this MH (like most) doesn't have one.
+            return this;
+        } else {
+            // The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
+            MethodHandle result = rebind();
+            assert (result.internalMemberName() == null);
+            return result;
+        }
+    }
+
+    /*non-public*
+    boolean isInvokeSpecial() {
+        return false;  // DMH.Special returns true
+    }
+
+    /*non-public*
+    Object internalValues() {
+        return null;
+    }
+
+    /*non-public*
+    Object internalProperties() {
+        // Override to something to follow this.form, like "\n& FOO=bar"
+        return "";
+    }
+
+    //// Method handle implementation methods.
+    //// Sub-classes can override these default implementations.
+    //// All these methods assume arguments are already validated.
+
+    /*non-public*
+    abstract MethodHandle copyWith(MethodType mt, LambdaForm lf);
+
+    /** Require this method handle to be a BMH, or else replace it with a "wrapper" BMH.
+     *  Many transforms are implemented only for BMHs.
+     *  @return a behaviorally equivalent BMH
+     *
+    abstract BoundMethodHandle rebind();
+
+    /**
+     * Replace the old lambda form of this method handle with a new one.
+     * The new one must be functionally equivalent to the old one.
+     * Threads may continue running the old form indefinitely,
+     * but it is likely that the new one will be preferred for new executions.
+     * Use with discretion.
+     *
+    /*non-public*
+    void updateForm(LambdaForm newForm) {
+        assert(newForm.customized == null || newForm.customized == this);
+        if (form == newForm)  return;
+        newForm.prepare();  // as in MethodHandle.<init>
+        UNSAFE.putObject(this, FORM_OFFSET, newForm);
+        UNSAFE.fullFence();
+    }
+
+    /** Craft a LambdaForm customized for this particular MethodHandle *
+    /*non-public*
+    void customize() {
+        if (form.customized == null) {
+            LambdaForm newForm = form.customize(this);
+            updateForm(newForm);
+        } else {
+            assert(form.customized == this);
+        }
+    }
+
+    private static final long FORM_OFFSET;
+    static {
+        try {
+            FORM_OFFSET = UNSAFE.objectFieldOffset(MethodHandle.class.getDeclaredField("form"));
+        } catch (ReflectiveOperationException ex) {
+            throw newInternalError(ex);
+        }
+    }
+    */
+    // END Android-removed: RI implementation unused on Android.
+}
diff --git a/java/lang/invoke/MethodHandleImpl.java b/java/lang/invoke/MethodHandleImpl.java
new file mode 100644
index 0000000..6514cb6
--- /dev/null
+++ b/java/lang/invoke/MethodHandleImpl.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  The Android Open Source
+ * Project designates this particular file as subject to the "Classpath"
+ * exception as provided by The Android Open Source Project in the LICENSE
+ * file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+// Android-changed: Android specific implementation.
+// The whole class was implemented from scratch for the Android runtime based
+// on the specification of the MethodHandle class.
+// The code does not originate from upstream OpenJDK.
+/**
+ * A method handle that's directly associated with an ArtField or an ArtMethod and
+ * specifies no additional transformations.
+ *
+ * @hide
+ */
+public class MethodHandleImpl extends MethodHandle implements Cloneable {
+    private HandleInfo info;
+
+    MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
+        super(artFieldOrMethod, handleKind, type);
+    }
+
+    @Override
+    public Object clone() throws CloneNotSupportedException {
+        return super.clone();
+    }
+
+    MethodHandleInfo reveal() {
+        if (info == null) {
+            final Member member = getMemberInternal();
+            info = new HandleInfo(member, this);
+        }
+
+        return info;
+    }
+
+    /**
+     * Materialize a member from this method handle's ArtField or ArtMethod pointer.
+     */
+    public native Member getMemberInternal();
+
+    /**
+     * Implementation of {@code MethodHandleInfo} in terms of the handle being cracked
+     * and its corresponding {@code java.lang.reflect.Member}.
+     */
+    static class HandleInfo implements MethodHandleInfo {
+        private final Member member;
+        private final MethodHandle handle;
+
+        HandleInfo(Member member, MethodHandle handle) {
+            this.member = member;
+            this.handle = handle;
+        }
+
+        @Override
+        public int getReferenceKind() {
+            switch (handle.getHandleKind()) {
+                case INVOKE_VIRTUAL: {
+                    if (member.getDeclaringClass().isInterface()) {
+                        return REF_invokeInterface;
+                    } else {
+                        return REF_invokeVirtual;
+                    }
+                }
+
+                case INVOKE_DIRECT: {
+                    if (member instanceof Constructor) {
+                        return REF_newInvokeSpecial;
+                    } else {
+                        return REF_invokeSpecial;
+                    }
+                }
+
+                case INVOKE_SUPER:
+                    return MethodHandleInfo.REF_invokeSpecial;
+                case INVOKE_STATIC:
+                    return MethodHandleInfo.REF_invokeStatic;
+                case IGET:
+                    return MethodHandleInfo.REF_getField;
+                case IPUT:
+                    return MethodHandleInfo.REF_putField;
+                case SGET:
+                    return MethodHandleInfo.REF_getStatic;
+                case SPUT:
+                    return MethodHandleInfo.REF_putStatic;
+                default:
+                    throw new AssertionError("Unexpected handle kind: " + handle.getHandleKind());
+            }
+        }
+
+        @Override
+        public Class<?> getDeclaringClass() {
+            return member.getDeclaringClass();
+        }
+
+        @Override
+        public String getName() {
+            if (member instanceof Constructor) {
+                return "<init>";
+            }
+
+            return member.getName();
+        }
+
+        @Override
+        public MethodType getMethodType() {
+            // The "nominal" type of a cracked method handle is the same as the type
+            // of the handle itself, except in the cases enumerated below.
+            MethodType handleType = handle.type();
+
+            boolean omitLeadingParam = false;
+
+            // For constructs, the return type is always void.class, and not the type of
+            // the object returned. We also need to omit the leading reference, which is
+            // nominally the type of the object being constructed.
+            if (member instanceof Constructor) {
+                handleType = handleType.changeReturnType(void.class);
+                omitLeadingParam = true;
+            }
+
+            // For instance field gets/puts and instance method gets/puts, we omit the
+            // leading reference parameter to |this|.
+            switch (handle.getHandleKind()) {
+                case IGET:
+                case IPUT:
+                case INVOKE_INTERFACE:
+                case INVOKE_DIRECT:
+                case INVOKE_VIRTUAL:
+                case INVOKE_SUPER:
+                    omitLeadingParam = true;
+            }
+
+            return omitLeadingParam ? handleType.dropParameterTypes(0, 1) : handleType;
+        }
+
+        @Override
+        public <T extends Member> T reflectAs(Class<T> expected, MethodHandles.Lookup lookup) {
+            try {
+                lookup.checkAccess(member.getDeclaringClass(), member.getDeclaringClass(),
+                        member.getModifiers(), member.getName());
+            } catch (IllegalAccessException exception) {
+                throw new IllegalArgumentException("Unable to access member.", exception);
+            }
+
+            return (T) member;
+        }
+
+        @Override
+        public int getModifiers() {
+            return member.getModifiers();
+        }
+    }
+}
diff --git a/java/lang/invoke/MethodHandleInfo.java b/java/lang/invoke/MethodHandleInfo.java
new file mode 100644
index 0000000..356768d
--- /dev/null
+++ b/java/lang/invoke/MethodHandleInfo.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A symbolic reference obtained by cracking a direct method handle
+ * into its consitutent symbolic parts.
+ * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
+ * <h1><a name="directmh"></a>Direct Method Handles</h1>
+ * A <em>direct method handle</em> represents a method, constructor, or field without
+ * any intervening argument bindings or other transformations.
+ * The method, constructor, or field referred to by a direct method handle is called
+ * its <em>underlying member</em>.
+ * Direct method handles may be obtained in any of these ways:
+ * <ul>
+ * <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
+ *     (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
+ * <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
+ *     such as {@link Lookup#findVirtual Lookup.findVirtual},
+ *     to resolve a symbolic reference into a method handle.
+ *     A symbolic reference consists of a class, name string, and type.
+ * <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
+ *     or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
+ *     to convert a {@link Method} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
+ *     to convert a {@link Constructor} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
+ *     or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
+ *     to convert a {@link Field} into a method handle.
+ * </ul>
+ *
+ * <h1>Restrictions on Cracking</h1>
+ * Given a suitable {@code Lookup} object, it is possible to crack any direct method handle
+ * to recover a symbolic reference for the underlying method, constructor, or field.
+ * Cracking must be done via a {@code Lookup} object equivalent to that which created
+ * the target method handle, or which has enough access permissions to recreate
+ * an equivalent method handle.
+ * <p>
+ * If the underlying method is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>,
+ * the direct method handle will have been "bound" to a particular caller class, the
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
+ * of the lookup object used to create it.
+ * Cracking this method handle with a different lookup class will fail
+ * even if the underlying method is public (like {@code Class.forName}).
+ * <p>
+ * The requirement of lookup object matching provides a "fast fail" behavior
+ * for programs which may otherwise trust erroneous revelation of a method
+ * handle with symbolic information (or caller binding) from an unexpected scope.
+ * Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
+ *
+ * <h1><a name="refkinds"></a>Reference kinds</h1>
+ * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
+ * correspond to all major use cases for methods, constructors, and fields.
+ * These use cases may be distinguished using small integers as follows:
+ * <table border=1 cellpadding=5 summary="reference kinds">
+ * <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
+ * <tr>
+ *     <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
+ *     <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
+ *     <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
+ *     <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
+ *     <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * </table>
+ * @since 1.8
+ */
+public
+interface MethodHandleInfo {
+    /**
+     * A direct method handle reference kind,
+     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+     */
+    public static final int
+        REF_getField                = Constants.REF_getField,
+        REF_getStatic               = Constants.REF_getStatic,
+        REF_putField                = Constants.REF_putField,
+        REF_putStatic               = Constants.REF_putStatic,
+        REF_invokeVirtual           = Constants.REF_invokeVirtual,
+        REF_invokeStatic            = Constants.REF_invokeStatic,
+        REF_invokeSpecial           = Constants.REF_invokeSpecial,
+        REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
+        REF_invokeInterface         = Constants.REF_invokeInterface;
+
+    /**
+     * Returns the reference kind of the cracked method handle, which in turn
+     * determines whether the method handle's underlying member was a constructor, method, or field.
+     * See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
+     * @return the integer code for the kind of reference used to access the underlying member
+     */
+    public int getReferenceKind();
+
+    /**
+     * Returns the class in which the cracked method handle's underlying member was defined.
+     * @return the declaring class of the underlying member
+     */
+    public Class<?> getDeclaringClass();
+
+    /**
+     * Returns the name of the cracked method handle's underlying member.
+     * This is {@code "<init>"} if the underlying member was a constructor,
+     * else it is a simple method name or field name.
+     * @return the simple name of the underlying member
+     */
+    public String getName();
+
+    /**
+     * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
+     * If the reference is to a constructor, the return type will be {@code void}.
+     * If it is to a non-static method, the method type will not mention the {@code this} parameter.
+     * If it is to a field and the requested access is to read the field,
+     * the method type will have no parameters and return the field type.
+     * If it is to a field and the requested access is to write the field,
+     * the method type will have one parameter of the field type and return {@code void}.
+     * <p>
+     * Note that original direct method handle may include a leading {@code this} parameter,
+     * or (in the case of a constructor) will replace the {@code void} return type
+     * with the constructed class.
+     * The nominal type does not include any {@code this} parameter,
+     * and (in the case of a constructor) will return {@code void}.
+     * @return the type of the underlying member, expressed as a method type
+     */
+    public MethodType getMethodType();
+
+    // Utility methods.
+    // NOTE: class/name/type and reference kind constitute a symbolic reference
+    // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
+
+    /**
+     * Reflects the underlying member as a method, constructor, or field object.
+     * If the underlying member is public, it is reflected as if by
+     * {@code getMethod}, {@code getConstructor}, or {@code getField}.
+     * Otherwise, it is reflected as if by
+     * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
+     * The underlying member must be accessible to the given lookup object.
+     * @param <T> the desired type of the result, either {@link Member} or a subtype
+     * @param expected a class object representing the desired result type {@code T}
+     * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
+     * @return a reference to the method, constructor, or field object
+     * @exception ClassCastException if the member is not of the expected type
+     * @exception NullPointerException if either argument is {@code null}
+     * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
+     */
+    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
+
+    /**
+     * Returns the access modifiers of the underlying member.
+     * @return the Java language modifiers for underlying member,
+     *         or -1 if the member cannot be accessed
+     * @see Modifier
+     * @see #reflectAs
+     */
+    public int getModifiers();
+
+    /**
+     * Determines if the underlying member was a variable arity method or constructor.
+     * Such members are represented by method handles that are varargs collectors.
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
+     * }</pre>
+     *
+     *
+     * @return {@code true} if and only if the underlying member was declared with variable arity.
+     */
+    // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
+    public default boolean isVarArgs()  {
+        // fields are never varargs:
+        if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
+            return false;
+        // not in the public API: Modifier.VARARGS
+        final int ACC_VARARGS = 0x00000080;  // from JVMS 4.6 (Table 4.20)
+        assert(ACC_VARARGS == Modifier.TRANSIENT);
+        return Modifier.isTransient(getModifiers());
+    }
+
+    /**
+     * Returns the descriptive name of the given reference kind,
+     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+     * The conventional prefix "REF_" is omitted.
+     * @param referenceKind an integer code for a kind of reference used to access a class member
+     * @return a mixed-case string such as {@code "getField"}
+     * @exception IllegalArgumentException if the argument is not a valid
+     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+     */
+    public static String referenceKindToString(int referenceKind) {
+        if (!MethodHandleNatives.refKindIsValid(referenceKind))
+            throw newIllegalArgumentException("invalid reference kind", referenceKind);
+        return MethodHandleNatives.refKindName((byte)referenceKind);
+    }
+
+    /**
+     * Returns a string representation for a {@code MethodHandleInfo},
+     * given the four parts of its symbolic reference.
+     * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
+     * {@linkplain #referenceKindToString reference kind string} for {@code kind},
+     * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
+     * {@code N} is the {@code name}, and
+     * {@code MT} is the {@code type}.
+     * These four values may be obtained from the
+     * {@linkplain #getReferenceKind reference kind},
+     * {@linkplain #getDeclaringClass declaring class},
+     * {@linkplain #getName member name},
+     * and {@linkplain #getMethodType method type}
+     * of a {@code MethodHandleInfo} object.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
+     * }</pre>
+     *
+     * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
+     * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
+     * @param name the {@linkplain #getName member name} part of the symbolic reference
+     * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
+     * @return a string of the form {@code "RK C.N:MT"}
+     * @exception IllegalArgumentException if the first argument is not a valid
+     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+     * @exception NullPointerException if any reference argument is {@code null}
+     */
+    public static String toString(int kind, Class<?> defc, String name, MethodType type) {
+        Objects.requireNonNull(name); Objects.requireNonNull(type);
+        return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
+    }
+
+    // BEGIN Android-added: refKind...() methods needed for API compatibility with 26.
+    // These methods were accidentally added into the public API in API level. They are now
+    // deprecated as a prelude to being removed from the public API.
+    /**
+     * @deprecated This internal method was accidentally added to API 26 and must not be used. No
+     *             replacement is available but it is possible to replicate using information from
+     *             the <a href="MethodHandleInfo.html#refkinds">table above</a>, e.g.
+     *             {@code refKind >= 1 && refKind <= 9}. There are no guarantees that this logic
+     *             will work if future versions extend the table.
+     */
+    @Deprecated
+    static boolean refKindIsValid(int refKind) {
+        return MethodHandleNatives.refKindIsValid(refKind);
+    }
+
+    /**
+     * @deprecated This internal method was accidentally added to API 26 and must not be used. No
+     *             replacement is available but it is possible to replicate using information from
+     *             the <a href="MethodHandleInfo.html#refkinds">table above</a>, e.g.
+     *             {@code refKind >= 1 && refKind <= 4}.  There are no guarantees that this logic
+     *             will work if future versions extend the table.
+     */
+    @Deprecated
+    static boolean refKindIsField(int refKind) {
+        return MethodHandleNatives.refKindIsField((byte) refKind);
+    }
+
+    /**
+     * @deprecated This internal method was accidentally added to API 26 and must not be used. Use
+     *             {@link MethodHandleInfo#referenceKindToString(int)} instead.
+     */
+    @Deprecated
+    static String refKindName(int refKind) {
+        return MethodHandleNatives.refKindName((byte) refKind);
+    }
+    // END Android-added: refKind...() methods needed for API compatibility with 26.
+}
diff --git a/java/lang/invoke/MethodHandleNatives.java b/java/lang/invoke/MethodHandleNatives.java
new file mode 100644
index 0000000..87f95ff
--- /dev/null
+++ b/java/lang/invoke/MethodHandleNatives.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
+
+/**
+ * The JVM interface for the method handles package is all here.
+ * This is an interface internal and private to an implementation of JSR 292.
+ * <em>This class is not part of the JSR 292 standard.</em>
+ * @author jrose
+ */
+class MethodHandleNatives {
+
+    // BEGIN Android-removed: Unused implementation code.
+    /*
+    private MethodHandleNatives() { } // static only
+
+    /// MemberName support
+
+    static native void init(MemberName self, Object ref);
+    static native void expand(MemberName self);
+    static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError, ClassNotFoundException;
+    static native int getMembers(Class<?> defc, String matchName, String matchSig,
+            int matchFlags, Class<?> caller, int skip, MemberName[] results);
+
+    /// Field layout queries parallel to sun.misc.Unsafe:
+    static native long objectFieldOffset(MemberName self);  // e.g., returns vmindex
+    static native long staticFieldOffset(MemberName self);  // e.g., returns vmindex
+    static native Object staticFieldBase(MemberName self);  // e.g., returns clazz
+    static native Object getMemberVMInfo(MemberName self);  // returns {vmindex,vmtarget}
+
+    /// MethodHandle support
+
+    /** Fetch MH-related JVM parameter.
+     *  which=0 retrieves MethodHandlePushLimit
+     *  which=1 retrieves stack slot push size (in address units)
+     *
+    static native int getConstant(int which);
+
+    static final boolean COUNT_GWT;
+
+    /// CallSite support
+
+    /** Tell the JVM that we need to change the target of a CallSite. *
+    static native void setCallSiteTargetNormal(CallSite site, MethodHandle target);
+    static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target);
+
+    private static native void registerNatives();
+    static {
+        registerNatives();
+        COUNT_GWT                   = getConstant(Constants.GC_COUNT_GWT) != 0;
+
+        // The JVM calls MethodHandleNatives.<clinit>.  Cascade the <clinit> calls as needed:
+        MethodHandleImpl.initStatics();
+    }
+    */
+    // END Android-removed: Unused implementation code.
+
+    // All compile-time constants go here.
+    // There is an opportunity to check them against the JVM's idea of them.
+    static class Constants {
+        Constants() { } // static only
+        // BEGIN Android-removed: Unused implementation code.
+        /*
+        // MethodHandleImpl
+        static final int // for getConstant
+                GC_COUNT_GWT = 4,
+                GC_LAMBDA_SUPPORT = 5;
+
+        // MemberName
+        // The JVM uses values of -2 and above for vtable indexes.
+        // Field values are simple positive offsets.
+        // Ref: src/share/vm/oops/methodOop.hpp
+        // This value is negative enough to avoid such numbers,
+        // but not too negative.
+        static final int
+                MN_IS_METHOD           = 0x00010000, // method (not constructor)
+                MN_IS_CONSTRUCTOR      = 0x00020000, // constructor
+                MN_IS_FIELD            = 0x00040000, // field
+                MN_IS_TYPE             = 0x00080000, // nested type
+                MN_CALLER_SENSITIVE    = 0x00100000, // @CallerSensitive annotation detected
+                MN_REFERENCE_KIND_SHIFT = 24, // refKind
+                MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
+                // The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
+                MN_SEARCH_SUPERCLASSES = 0x00100000,
+                MN_SEARCH_INTERFACES   = 0x00200000;
+
+        /**
+         * Basic types as encoded in the JVM.  These code values are not
+         * intended for use outside this class.  They are used as part of
+         * a private interface between the JVM and this class.
+         *
+        static final int
+            T_BOOLEAN  =  4,
+            T_CHAR     =  5,
+            T_FLOAT    =  6,
+            T_DOUBLE   =  7,
+            T_BYTE     =  8,
+            T_SHORT    =  9,
+            T_INT      = 10,
+            T_LONG     = 11,
+            T_OBJECT   = 12,
+            //T_ARRAY    = 13
+            T_VOID     = 14,
+            //T_ADDRESS  = 15
+            T_ILLEGAL  = 99;
+
+        /**
+         * Constant pool entry types.
+         *
+        static final byte
+            CONSTANT_Utf8                = 1,
+            CONSTANT_Integer             = 3,
+            CONSTANT_Float               = 4,
+            CONSTANT_Long                = 5,
+            CONSTANT_Double              = 6,
+            CONSTANT_Class               = 7,
+            CONSTANT_String              = 8,
+            CONSTANT_Fieldref            = 9,
+            CONSTANT_Methodref           = 10,
+            CONSTANT_InterfaceMethodref  = 11,
+            CONSTANT_NameAndType         = 12,
+            CONSTANT_MethodHandle        = 15,  // JSR 292
+            CONSTANT_MethodType          = 16,  // JSR 292
+            CONSTANT_InvokeDynamic       = 18,
+            CONSTANT_LIMIT               = 19;   // Limit to tags found in classfiles
+
+        /**
+         * Access modifier flags.
+         *
+        static final char
+            ACC_PUBLIC                 = 0x0001,
+            ACC_PRIVATE                = 0x0002,
+            ACC_PROTECTED              = 0x0004,
+            ACC_STATIC                 = 0x0008,
+            ACC_FINAL                  = 0x0010,
+            ACC_SYNCHRONIZED           = 0x0020,
+            ACC_VOLATILE               = 0x0040,
+            ACC_TRANSIENT              = 0x0080,
+            ACC_NATIVE                 = 0x0100,
+            ACC_INTERFACE              = 0x0200,
+            ACC_ABSTRACT               = 0x0400,
+            ACC_STRICT                 = 0x0800,
+            ACC_SYNTHETIC              = 0x1000,
+            ACC_ANNOTATION             = 0x2000,
+            ACC_ENUM                   = 0x4000,
+            // aliases:
+            ACC_SUPER                  = ACC_SYNCHRONIZED,
+            ACC_BRIDGE                 = ACC_VOLATILE,
+            ACC_VARARGS                = ACC_TRANSIENT;
+        */
+        // END Android-removed: Unused implementation code.
+
+        /**
+         * Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
+         */
+        static final byte
+            REF_NONE                    = 0,  // null value
+            REF_getField                = 1,
+            REF_getStatic               = 2,
+            REF_putField                = 3,
+            REF_putStatic               = 4,
+            REF_invokeVirtual           = 5,
+            REF_invokeStatic            = 6,
+            REF_invokeSpecial           = 7,
+            REF_newInvokeSpecial        = 8,
+            REF_invokeInterface         = 9,
+            REF_LIMIT                  = 10;
+    }
+
+    static boolean refKindIsValid(int refKind) {
+        return (refKind > REF_NONE && refKind < REF_LIMIT);
+    }
+    static boolean refKindIsField(byte refKind) {
+        assert(refKindIsValid(refKind));
+        return (refKind <= REF_putStatic);
+    }
+    // BEGIN Android-removed: Unused implementation code.
+    /*
+    static boolean refKindIsGetter(byte refKind) {
+        assert(refKindIsValid(refKind));
+        return (refKind <= REF_getStatic);
+    }
+    static boolean refKindIsSetter(byte refKind) {
+        return refKindIsField(refKind) && !refKindIsGetter(refKind);
+    }
+    static boolean refKindIsMethod(byte refKind) {
+        return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
+    }
+    static boolean refKindIsConstructor(byte refKind) {
+        return (refKind == REF_newInvokeSpecial);
+    }
+    static boolean refKindHasReceiver(byte refKind) {
+        assert(refKindIsValid(refKind));
+        return (refKind & 1) != 0;
+    }
+    static boolean refKindIsStatic(byte refKind) {
+        return !refKindHasReceiver(refKind) && (refKind != REF_newInvokeSpecial);
+    }
+    static boolean refKindDoesDispatch(byte refKind) {
+        assert(refKindIsValid(refKind));
+        return (refKind == REF_invokeVirtual ||
+                refKind == REF_invokeInterface);
+    }
+    static {
+        final int HR_MASK = ((1 << REF_getField) |
+                             (1 << REF_putField) |
+                             (1 << REF_invokeVirtual) |
+                             (1 << REF_invokeSpecial) |
+                             (1 << REF_invokeInterface)
+                            );
+        for (byte refKind = REF_NONE+1; refKind < REF_LIMIT; refKind++) {
+            assert(refKindHasReceiver(refKind) == (((1<<refKind) & HR_MASK) != 0)) : refKind;
+        }
+    }
+    */
+    // END Android-removed: Unused implementation code.
+    static String refKindName(byte refKind) {
+        assert(refKindIsValid(refKind));
+        switch (refKind) {
+        case REF_getField:          return "getField";
+        case REF_getStatic:         return "getStatic";
+        case REF_putField:          return "putField";
+        case REF_putStatic:         return "putStatic";
+        case REF_invokeVirtual:     return "invokeVirtual";
+        case REF_invokeStatic:      return "invokeStatic";
+        case REF_invokeSpecial:     return "invokeSpecial";
+        case REF_newInvokeSpecial:  return "newInvokeSpecial";
+        case REF_invokeInterface:   return "invokeInterface";
+        default:                    return "REF_???";
+        }
+    }
+    // BEGIN Android-removed: Unused implementation code.
+    /*
+    private static native int getNamedCon(int which, Object[] name);
+    static boolean verifyConstants() {
+        Object[] box = { null };
+        for (int i = 0; ; i++) {
+            box[0] = null;
+            int vmval = getNamedCon(i, box);
+            if (box[0] == null)  break;
+            String name = (String) box[0];
+            try {
+                Field con = Constants.class.getDeclaredField(name);
+                int jval = con.getInt(null);
+                if (jval == vmval)  continue;
+                String err = (name+": JVM has "+vmval+" while Java has "+jval);
+                if (name.equals("CONV_OP_LIMIT")) {
+                    System.err.println("warning: "+err);
+                    continue;
+                }
+                throw new InternalError(err);
+            } catch (NoSuchFieldException | IllegalAccessException ex) {
+                String err = (name+": JVM has "+vmval+" which Java does not define");
+                // ignore exotic ops the JVM cares about; we just wont issue them
+                //System.err.println("warning: "+err);
+                continue;
+            }
+        }
+        return true;
+    }
+    static {
+        assert(verifyConstants());
+    }
+
+    // Up-calls from the JVM.
+    // These must NOT be public.
+
+    /**
+     * The JVM is linking an invokedynamic instruction.  Create a reified call site for it.
+     *
+    static MemberName linkCallSite(Object callerObj,
+                                   Object bootstrapMethodObj,
+                                   Object nameObj, Object typeObj,
+                                   Object staticArguments,
+                                   Object[] appendixResult) {
+        MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj;
+        Class<?> caller = (Class<?>)callerObj;
+        String name = nameObj.toString().intern();
+        MethodType type = (MethodType)typeObj;
+        if (!TRACE_METHOD_LINKAGE)
+            return linkCallSiteImpl(caller, bootstrapMethod, name, type,
+                                    staticArguments, appendixResult);
+        return linkCallSiteTracing(caller, bootstrapMethod, name, type,
+                                   staticArguments, appendixResult);
+    }
+    static MemberName linkCallSiteImpl(Class<?> caller,
+                                       MethodHandle bootstrapMethod,
+                                       String name, MethodType type,
+                                       Object staticArguments,
+                                       Object[] appendixResult) {
+        CallSite callSite = CallSite.makeSite(bootstrapMethod,
+                                              name,
+                                              type,
+                                              staticArguments,
+                                              caller);
+        if (callSite instanceof ConstantCallSite) {
+            appendixResult[0] = callSite.dynamicInvoker();
+            return Invokers.linkToTargetMethod(type);
+        } else {
+            appendixResult[0] = callSite;
+            return Invokers.linkToCallSiteMethod(type);
+        }
+    }
+    // Tracing logic:
+    static MemberName linkCallSiteTracing(Class<?> caller,
+                                          MethodHandle bootstrapMethod,
+                                          String name, MethodType type,
+                                          Object staticArguments,
+                                          Object[] appendixResult) {
+        Object bsmReference = bootstrapMethod.internalMemberName();
+        if (bsmReference == null)  bsmReference = bootstrapMethod;
+        Object staticArglist = (staticArguments instanceof Object[] ?
+                                java.util.Arrays.asList((Object[]) staticArguments) :
+                                staticArguments);
+        System.out.println("linkCallSite "+caller.getName()+" "+
+                           bsmReference+" "+
+                           name+type+"/"+staticArglist);
+        try {
+            MemberName res = linkCallSiteImpl(caller, bootstrapMethod, name, type,
+                                              staticArguments, appendixResult);
+            System.out.println("linkCallSite => "+res+" + "+appendixResult[0]);
+            return res;
+        } catch (Throwable ex) {
+            System.out.println("linkCallSite => throw "+ex);
+            throw ex;
+        }
+    }
+
+    /**
+     * The JVM wants a pointer to a MethodType.  Oblige it by finding or creating one.
+     *
+    static MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes) {
+        return MethodType.makeImpl(rtype, ptypes, true);
+    }
+
+    /**
+     * The JVM wants to link a call site that requires a dynamic type check.
+     * Name is a type-checking invoker, invokeExact or invoke.
+     * Return a JVM method (MemberName) to handle the invoking.
+     * The method assumes the following arguments on the stack:
+     * 0: the method handle being invoked
+     * 1-N: the arguments to the method handle invocation
+     * N+1: an optional, implicitly added argument (typically the given MethodType)
+     * <p>
+     * The nominal method at such a call site is an instance of
+     * a signature-polymorphic method (see @PolymorphicSignature).
+     * Such method instances are user-visible entities which are
+     * "split" from the generic placeholder method in {@code MethodHandle}.
+     * (Note that the placeholder method is not identical with any of
+     * its instances.  If invoked reflectively, is guaranteed to throw an
+     * {@code UnsupportedOperationException}.)
+     * If the signature-polymorphic method instance is ever reified,
+     * it appears as a "copy" of the original placeholder
+     * (a native final member of {@code MethodHandle}) except
+     * that its type descriptor has shape required by the instance,
+     * and the method instance is <em>not</em> varargs.
+     * The method instance is also marked synthetic, since the
+     * method (by definition) does not appear in Java source code.
+     * <p>
+     * The JVM is allowed to reify this method as instance metadata.
+     * For example, {@code invokeBasic} is always reified.
+     * But the JVM may instead call {@code linkMethod}.
+     * If the result is an * ordered pair of a {@code (method, appendix)},
+     * the method gets all the arguments (0..N inclusive)
+     * plus the appendix (N+1), and uses the appendix to complete the call.
+     * In this way, one reusable method (called a "linker method")
+     * can perform the function of any number of polymorphic instance
+     * methods.
+     * <p>
+     * Linker methods are allowed to be weakly typed, with any or
+     * all references rewritten to {@code Object} and any primitives
+     * (except {@code long}/{@code float}/{@code double})
+     * rewritten to {@code int}.
+     * A linker method is trusted to return a strongly typed result,
+     * according to the specific method type descriptor of the
+     * signature-polymorphic instance it is emulating.
+     * This can involve (as necessary) a dynamic check using
+     * data extracted from the appendix argument.
+     * <p>
+     * The JVM does not inspect the appendix, other than to pass
+     * it verbatim to the linker method at every call.
+     * This means that the JDK runtime has wide latitude
+     * for choosing the shape of each linker method and its
+     * corresponding appendix.
+     * Linker methods should be generated from {@code LambdaForm}s
+     * so that they do not become visible on stack traces.
+     * <p>
+     * The {@code linkMethod} call is free to omit the appendix
+     * (returning null) and instead emulate the required function
+     * completely in the linker method.
+     * As a corner case, if N==255, no appendix is possible.
+     * In this case, the method returned must be custom-generated to
+     * to perform any needed type checking.
+     * <p>
+     * If the JVM does not reify a method at a call site, but instead
+     * calls {@code linkMethod}, the corresponding call represented
+     * in the bytecodes may mention a valid method which is not
+     * representable with a {@code MemberName}.
+     * Therefore, use cases for {@code linkMethod} tend to correspond to
+     * special cases in reflective code such as {@code findVirtual}
+     * or {@code revealDirect}.
+     *
+    static MemberName linkMethod(Class<?> callerClass, int refKind,
+                                 Class<?> defc, String name, Object type,
+                                 Object[] appendixResult) {
+        if (!TRACE_METHOD_LINKAGE)
+            return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
+        return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult);
+    }
+    static MemberName linkMethodImpl(Class<?> callerClass, int refKind,
+                                     Class<?> defc, String name, Object type,
+                                     Object[] appendixResult) {
+        try {
+            if (defc == MethodHandle.class && refKind == REF_invokeVirtual) {
+                return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult);
+            }
+        } catch (Throwable ex) {
+            if (ex instanceof LinkageError)
+                throw (LinkageError) ex;
+            else
+                throw new LinkageError(ex.getMessage(), ex);
+        }
+        throw new LinkageError("no such method "+defc.getName()+"."+name+type);
+    }
+    private static MethodType fixMethodType(Class<?> callerClass, Object type) {
+        if (type instanceof MethodType)
+            return (MethodType) type;
+        else
+            return MethodType.fromMethodDescriptorString((String)type, callerClass.getClassLoader());
+    }
+    // Tracing logic:
+    static MemberName linkMethodTracing(Class<?> callerClass, int refKind,
+                                        Class<?> defc, String name, Object type,
+                                        Object[] appendixResult) {
+        System.out.println("linkMethod "+defc.getName()+"."+
+                           name+type+"/"+Integer.toHexString(refKind));
+        try {
+            MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult);
+            System.out.println("linkMethod => "+res+" + "+appendixResult[0]);
+            return res;
+        } catch (Throwable ex) {
+            System.out.println("linkMethod => throw "+ex);
+            throw ex;
+        }
+    }
+
+
+    /**
+     * The JVM is resolving a CONSTANT_MethodHandle CP entry.  And it wants our help.
+     * It will make an up-call to this method.  (Do not change the name or signature.)
+     * The type argument is a Class for field requests and a MethodType for non-fields.
+     * <p>
+     * Recent versions of the JVM may also pass a resolved MemberName for the type.
+     * In that case, the name is ignored and may be null.
+     *
+    static MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind,
+                                                 Class<?> defc, String name, Object type) {
+        try {
+            Lookup lookup = IMPL_LOOKUP.in(callerClass);
+            assert(refKindIsValid(refKind));
+            return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type);
+        } catch (IllegalAccessException ex) {
+            Throwable cause = ex.getCause();
+            if (cause instanceof AbstractMethodError) {
+                throw (AbstractMethodError) cause;
+            } else {
+                Error err = new IllegalAccessError(ex.getMessage());
+                throw initCauseFrom(err, ex);
+            }
+        } catch (NoSuchMethodException ex) {
+            Error err = new NoSuchMethodError(ex.getMessage());
+            throw initCauseFrom(err, ex);
+        } catch (NoSuchFieldException ex) {
+            Error err = new NoSuchFieldError(ex.getMessage());
+            throw initCauseFrom(err, ex);
+        } catch (ReflectiveOperationException ex) {
+            Error err = new IncompatibleClassChangeError();
+            throw initCauseFrom(err, ex);
+        }
+    }
+
+    /**
+     * Use best possible cause for err.initCause(), substituting the
+     * cause for err itself if the cause has the same (or better) type.
+     *
+    static private Error initCauseFrom(Error err, Exception ex) {
+        Throwable th = ex.getCause();
+        if (err.getClass().isInstance(th))
+           return (Error) th;
+        err.initCause(th == null ? ex : th);
+        return err;
+    }
+
+    /**
+     * Is this method a caller-sensitive method?
+     * I.e., does it call Reflection.getCallerClass or a similer method
+     * to ask about the identity of its caller?
+     *
+    static boolean isCallerSensitive(MemberName mem) {
+        if (!mem.isInvocable())  return false;  // fields are not caller sensitive
+
+        return mem.isCallerSensitive() || canBeCalledVirtual(mem);
+    }
+
+    static boolean canBeCalledVirtual(MemberName mem) {
+        assert(mem.isInvocable());
+        Class<?> defc = mem.getDeclaringClass();
+        switch (mem.getName()) {
+        case "checkMemberAccess":
+            return canBeCalledVirtual(mem, java.lang.SecurityManager.class);
+        case "getContextClassLoader":
+            return canBeCalledVirtual(mem, java.lang.Thread.class);
+        }
+        return false;
+    }
+
+    static boolean canBeCalledVirtual(MemberName symbolicRef, Class<?> definingClass) {
+        Class<?> symbolicRefClass = symbolicRef.getDeclaringClass();
+        if (symbolicRefClass == definingClass)  return true;
+        if (symbolicRef.isStatic() || symbolicRef.isPrivate())  return false;
+        return (definingClass.isAssignableFrom(symbolicRefClass) ||  // Msym overrides Mdef
+                symbolicRefClass.isInterface());                     // Mdef implements Msym
+    }
+    */
+    // END Android-removed: Unused implementation code.
+}
diff --git a/java/lang/invoke/MethodHandleStatics.java b/java/lang/invoke/MethodHandleStatics.java
new file mode 100644
index 0000000..90265cc
--- /dev/null
+++ b/java/lang/invoke/MethodHandleStatics.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.misc.Unsafe;
+
+/**
+ * This class consists exclusively of static names internal to the
+ * method handle implementation.
+ * Usage:  {@code import static java.lang.invoke.MethodHandleStatics.*}
+ * @author John Rose, JSR 292 EG
+ */
+/*non-public*/ class MethodHandleStatics {
+
+    private MethodHandleStatics() { }  // do not instantiate
+
+    static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
+    // Android-changed: Remove debugging related static fields.
+    // They are unused and have no equivalent on Android.
+    /*
+    static final boolean DEBUG_METHOD_HANDLE_NAMES;
+    static final boolean DUMP_CLASS_FILES;
+    static final boolean TRACE_INTERPRETER;
+    static final boolean TRACE_METHOD_LINKAGE;
+    static final int COMPILE_THRESHOLD;
+    static final int DONT_INLINE_THRESHOLD;
+    static final int PROFILE_LEVEL;
+    static final boolean PROFILE_GWT;
+    static final int CUSTOMIZE_THRESHOLD;
+
+    static {
+        final Object[] values = new Object[9];
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+                    values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
+                    values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
+                    values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
+                    values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0);
+                    values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
+                    values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
+                    values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true"));
+                    values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127);
+                    return null;
+                }
+            });
+        DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0];
+        DUMP_CLASS_FILES          = (Boolean) values[1];
+        TRACE_INTERPRETER         = (Boolean) values[2];
+        TRACE_METHOD_LINKAGE      = (Boolean) values[3];
+        COMPILE_THRESHOLD         = (Integer) values[4];
+        DONT_INLINE_THRESHOLD     = (Integer) values[5];
+        PROFILE_LEVEL             = (Integer) values[6];
+        PROFILE_GWT               = (Boolean) values[7];
+        CUSTOMIZE_THRESHOLD       = (Integer) values[8];
+
+        if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) {
+            throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range");
+        }
+    }
+
+    /** Tell if any of the debugging switches are turned on.
+     *  If this is the case, it is reasonable to perform extra checks or save extra information.
+     *
+    /*non-public* static boolean debugEnabled() {
+        return (DEBUG_METHOD_HANDLE_NAMES |
+                DUMP_CLASS_FILES |
+                TRACE_INTERPRETER |
+                TRACE_METHOD_LINKAGE);
+    }
+    */
+
+    // Android-removed: Methods operating on MethodHandles that are currently unused on Android.
+    /*
+    /*non-public* static String getNameString(MethodHandle target, MethodType type) {
+        if (type == null)
+            type = target.type();
+        MemberName name = null;
+        if (target != null)
+            name = target.internalMemberName();
+        if (name == null)
+            return "invoke" + type;
+        return name.getName() + type;
+    }
+
+    /*non-public* static String getNameString(MethodHandle target, MethodHandle typeHolder) {
+        return getNameString(target, typeHolder == null ? (MethodType) null : typeHolder.type());
+    }
+
+    /*non-public* static String getNameString(MethodHandle target) {
+        return getNameString(target, (MethodType) null);
+    }
+
+    /*non-public* static String addTypeString(Object obj, MethodHandle target) {
+        String str = String.valueOf(obj);
+        if (target == null)  return str;
+        int paren = str.indexOf('(');
+        if (paren >= 0) str = str.substring(0, paren);
+        return str + target.type();
+    }
+    */
+
+    // handy shared exception makers (they simplify the common case code)
+    /*non-public*/ static InternalError newInternalError(String message) {
+        return new InternalError(message);
+    }
+    /*non-public*/ static InternalError newInternalError(String message, Throwable cause) {
+        return new InternalError(message, cause);
+    }
+    /*non-public*/ static InternalError newInternalError(Throwable cause) {
+        return new InternalError(cause);
+    }
+    /*non-public*/ static RuntimeException newIllegalStateException(String message) {
+        return new IllegalStateException(message);
+    }
+    /*non-public*/ static RuntimeException newIllegalStateException(String message, Object obj) {
+        return new IllegalStateException(message(message, obj));
+    }
+    /*non-public*/ static RuntimeException newIllegalArgumentException(String message) {
+        return new IllegalArgumentException(message);
+    }
+    /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj) {
+        return new IllegalArgumentException(message(message, obj));
+    }
+    /*non-public*/ static RuntimeException newIllegalArgumentException(String message, Object obj, Object obj2) {
+        return new IllegalArgumentException(message(message, obj, obj2));
+    }
+    /** Propagate unchecked exceptions and errors, but wrap anything checked and throw that instead. */
+    /*non-public*/ static Error uncaughtException(Throwable ex) {
+        if (ex instanceof Error)  throw (Error) ex;
+        if (ex instanceof RuntimeException)  throw (RuntimeException) ex;
+        throw newInternalError("uncaught exception", ex);
+    }
+    static Error NYI() {
+        throw new AssertionError("NYI");
+    }
+    private static String message(String message, Object obj) {
+        if (obj != null)  message = message + ": " + obj;
+        return message;
+    }
+    private static String message(String message, Object obj, Object obj2) {
+        if (obj != null || obj2 != null)  message = message + ": " + obj + ", " + obj2;
+        return message;
+    }
+}
diff --git a/java/lang/invoke/MethodHandles.java b/java/lang/invoke/MethodHandles.java
new file mode 100644
index 0000000..1188ac6
--- /dev/null
+++ b/java/lang/invoke/MethodHandles.java
@@ -0,0 +1,3521 @@
+/*
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.nio.ByteOrder;
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+
+import sun.invoke.util.VerifyAccess;
+import sun.invoke.util.Wrapper;
+import sun.reflect.Reflection;
+
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * This class consists exclusively of static methods that operate on or return
+ * method handles. They fall into several categories:
+ * <ul>
+ * <li>Lookup methods which help create method handles for methods and fields.
+ * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
+ * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
+ * </ul>
+ * <p>
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class MethodHandles {
+
+    private MethodHandles() { }  // do not instantiate
+
+    // Android-changed: We do not use MemberName / MethodHandleImpl.
+    //
+    // private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
+    // static { MethodHandleImpl.initStatics(); }
+    // See IMPL_LOOKUP below.
+
+    //// Method handle creation from ordinary methods.
+
+    /**
+     * Returns a {@link Lookup lookup object} with
+     * full capabilities to emulate all supported bytecode behaviors of the caller.
+     * These capabilities include <a href="MethodHandles.Lookup.html#privacc">private access</a> to the caller.
+     * Factory methods on the lookup object can create
+     * <a href="MethodHandleInfo.html#directmh">direct method handles</a>
+     * for any member that the caller has access to via bytecodes,
+     * including protected and private fields and methods.
+     * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
+     * Do not store it in place where untrusted code can access it.
+     * <p>
+     * This method is caller sensitive, which means that it may return different
+     * values to different callers.
+     * <p>
+     * For any given caller class {@code C}, the lookup object returned by this call
+     * has equivalent capabilities to any lookup object
+     * supplied by the JVM to the bootstrap method of an
+     * <a href="package-summary.html#indyinsn">invokedynamic instruction</a>
+     * executing in the same caller class {@code C}.
+     * @return a lookup object for the caller of this method, with private access
+     */
+    // Android-changed: Remove caller sensitive.
+    // @CallerSensitive
+    public static Lookup lookup() {
+        return new Lookup(Reflection.getCallerClass());
+    }
+
+    /**
+     * Returns a {@link Lookup lookup object} which is trusted minimally.
+     * It can only be used to create method handles to
+     * publicly accessible fields and methods.
+     * <p>
+     * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+     * of this lookup object will be {@link java.lang.Object}.
+     *
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * The lookup class can be changed to any other class {@code C} using an expression of the form
+     * {@link Lookup#in publicLookup().in(C.class)}.
+     * Since all classes have equal access to public names,
+     * such a change would confer no new access rights.
+     * A public lookup object is always subject to
+     * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
+     * Also, it cannot access
+     * <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
+     * @return a lookup object which is trusted minimally
+     */
+    public static Lookup publicLookup() {
+        return Lookup.PUBLIC_LOOKUP;
+    }
+
+    /**
+     * Performs an unchecked "crack" of a
+     * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
+     * The result is as if the user had obtained a lookup object capable enough
+     * to crack the target method handle, called
+     * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
+     * on the target to obtain its symbolic reference, and then called
+     * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
+     * to resolve the symbolic reference to a member.
+     * <p>
+     * If there is a security manager, its {@code checkPermission} method
+     * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
+     * @param <T> the desired type of the result, either {@link Member} or a subtype
+     * @param target a direct method handle to crack into symbolic reference components
+     * @param expected a class object representing the desired result type {@code T}
+     * @return a reference to the method, constructor, or field object
+     * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
+     * @exception NullPointerException if either argument is {@code null}
+     * @exception IllegalArgumentException if the target is not a direct method handle
+     * @exception ClassCastException if the member is not of the expected type
+     * @since 1.8
+     */
+    public static <T extends Member> T
+    reflectAs(Class<T> expected, MethodHandle target) {
+        MethodHandleImpl directTarget = getMethodHandleImpl(target);
+        // Given that this is specified to be an "unchecked" crack, we can directly allocate
+        // a member from the underlying ArtField / Method and bypass all associated access checks.
+        return expected.cast(directTarget.getMemberInternal());
+    }
+
+    /**
+     * A <em>lookup object</em> is a factory for creating method handles,
+     * when the creation requires access checking.
+     * Method handles do not perform
+     * access checks when they are called, but rather when they are created.
+     * Therefore, method handle access
+     * restrictions must be enforced when a method handle is created.
+     * The caller class against which those restrictions are enforced
+     * is known as the {@linkplain #lookupClass lookup class}.
+     * <p>
+     * A lookup class which needs to create method handles will call
+     * {@link #lookup MethodHandles.lookup} to create a factory for itself.
+     * When the {@code Lookup} factory object is created, the identity of the lookup class is
+     * determined, and securely stored in the {@code Lookup} object.
+     * The lookup class (or its delegates) may then use factory methods
+     * on the {@code Lookup} object to create method handles for access-checked members.
+     * This includes all methods, constructors, and fields which are allowed to the lookup class,
+     * even private ones.
+     *
+     * <h1><a name="lookups"></a>Lookup Factory Methods</h1>
+     * The factory methods on a {@code Lookup} object correspond to all major
+     * use cases for methods, constructors, and fields.
+     * Each method handle created by a factory method is the functional
+     * equivalent of a particular <em>bytecode behavior</em>.
+     * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
+     * Here is a summary of the correspondence between these factory methods and
+     * the behavior the resulting method handles:
+     * <table border=1 cellpadding=5 summary="lookup method behaviors">
+     * <tr>
+     *     <th><a name="equiv"></a>lookup expression</th>
+     *     <th>member</th>
+     *     <th>bytecode behavior</th>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
+     *     <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td>
+     *     <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td>
+     *     <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td>
+     *     <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td>
+     *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td>
+     *     <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td>
+     *     <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td>
+     *     <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td>
+     *     <td>({@code static})?<br>{@code FT f;}</td><td>{@code (FT) aField.get(thisOrNull);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td>
+     *     <td>({@code static})?<br>{@code FT f;}</td><td>{@code aField.set(thisOrNull, arg);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
+     *     <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td>
+     *     <td>{@code C(A*);}</td><td>{@code (C) aConstructor.newInstance(arg*);}</td>
+     * </tr>
+     * <tr>
+     *     <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
+     *     <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
+     * </tr>
+     * </table>
+     *
+     * Here, the type {@code C} is the class or interface being searched for a member,
+     * documented as a parameter named {@code refc} in the lookup methods.
+     * The method type {@code MT} is composed from the return type {@code T}
+     * and the sequence of argument types {@code A*}.
+     * The constructor also has a sequence of argument types {@code A*} and
+     * is deemed to return the newly-created object of type {@code C}.
+     * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}.
+     * The formal parameter {@code this} stands for the self-reference of type {@code C};
+     * if it is present, it is always the leading argument to the method handle invocation.
+     * (In the case of some {@code protected} members, {@code this} may be
+     * restricted in type to the lookup class; see below.)
+     * The name {@code arg} stands for all the other method handle arguments.
+     * In the code examples for the Core Reflection API, the name {@code thisOrNull}
+     * stands for a null reference if the accessed method or field is static,
+     * and {@code this} otherwise.
+     * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
+     * for reflective objects corresponding to the given members.
+     * <p>
+     * In cases where the given member is of variable arity (i.e., a method or constructor)
+     * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
+     * In all other cases, the returned method handle will be of fixed arity.
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * The equivalence between looked-up method handles and underlying
+     * class members and bytecode behaviors
+     * can break down in a few ways:
+     * <ul style="font-size:smaller;">
+     * <li>If {@code C} is not symbolically accessible from the lookup class's loader,
+     * the lookup can still succeed, even when there is no equivalent
+     * Java expression or bytecoded constant.
+     * <li>Likewise, if {@code T} or {@code MT}
+     * is not symbolically accessible from the lookup class's loader,
+     * the lookup can still succeed.
+     * For example, lookups for {@code MethodHandle.invokeExact} and
+     * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
+     * <li>If there is a security manager installed, it can forbid the lookup
+     * on various grounds (<a href="MethodHandles.Lookup.html#secmgr">see below</a>).
+     * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
+     * constant is not subject to security manager checks.
+     * <li>If the looked-up method has a
+     * <a href="MethodHandle.html#maxarity">very large arity</a>,
+     * the method handle creation may fail, due to the method handle
+     * type having too many parameters.
+     * </ul>
+     *
+     * <h1><a name="access"></a>Access checking</h1>
+     * Access checks are applied in the factory methods of {@code Lookup},
+     * when a method handle is created.
+     * This is a key difference from the Core Reflection API, since
+     * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+     * performs access checking against every caller, on every call.
+     * <p>
+     * All access checks start from a {@code Lookup} object, which
+     * compares its recorded lookup class against all requests to
+     * create method handles.
+     * A single {@code Lookup} object can be used to create any number
+     * of access-checked method handles, all checked against a single
+     * lookup class.
+     * <p>
+     * A {@code Lookup} object can be shared with other trusted code,
+     * such as a metaobject protocol.
+     * A shared {@code Lookup} object delegates the capability
+     * to create method handles on private members of the lookup class.
+     * Even if privileged code uses the {@code Lookup} object,
+     * the access checking is confined to the privileges of the
+     * original lookup class.
+     * <p>
+     * A lookup can fail, because
+     * the containing class is not accessible to the lookup class, or
+     * because the desired class member is missing, or because the
+     * desired class member is not accessible to the lookup class, or
+     * because the lookup object is not trusted enough to access the member.
+     * In any of these cases, a {@code ReflectiveOperationException} will be
+     * thrown from the attempted lookup.  The exact class will be one of
+     * the following:
+     * <ul>
+     * <li>NoSuchMethodException &mdash; if a method is requested but does not exist
+     * <li>NoSuchFieldException &mdash; if a field is requested but does not exist
+     * <li>IllegalAccessException &mdash; if the member exists but an access check fails
+     * </ul>
+     * <p>
+     * In general, the conditions under which a method handle may be
+     * looked up for a method {@code M} are no more restrictive than the conditions
+     * under which the lookup class could have compiled, verified, and resolved a call to {@code M}.
+     * Where the JVM would raise exceptions like {@code NoSuchMethodError},
+     * a method handle lookup will generally raise a corresponding
+     * checked exception, such as {@code NoSuchMethodException}.
+     * And the effect of invoking the method handle resulting from the lookup
+     * is <a href="MethodHandles.Lookup.html#equiv">exactly equivalent</a>
+     * to executing the compiled, verified, and resolved call to {@code M}.
+     * The same point is true of fields and constructors.
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * Access checks only apply to named and reflected methods,
+     * constructors, and fields.
+     * Other method handle creation methods, such as
+     * {@link MethodHandle#asType MethodHandle.asType},
+     * do not require any access checks, and are used
+     * independently of any {@code Lookup} object.
+     * <p>
+     * If the desired member is {@code protected}, the usual JVM rules apply,
+     * including the requirement that the lookup class must be either be in the
+     * same package as the desired member, or must inherit that member.
+     * (See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.)
+     * In addition, if the desired member is a non-static field or method
+     * in a different package, the resulting method handle may only be applied
+     * to objects of the lookup class or one of its subclasses.
+     * This requirement is enforced by narrowing the type of the leading
+     * {@code this} parameter from {@code C}
+     * (which will necessarily be a superclass of the lookup class)
+     * to the lookup class itself.
+     * <p>
+     * The JVM imposes a similar requirement on {@code invokespecial} instruction,
+     * that the receiver argument must match both the resolved method <em>and</em>
+     * the current class.  Again, this requirement is enforced by narrowing the
+     * type of the leading parameter to the resulting method handle.
+     * (See the Java Virtual Machine Specification, section 4.10.1.9.)
+     * <p>
+     * The JVM represents constructors and static initializer blocks as internal methods
+     * with special names ({@code "<init>"} and {@code "<clinit>"}).
+     * The internal syntax of invocation instructions allows them to refer to such internal
+     * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
+     * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
+     * <p>
+     * In some cases, access between nested classes is obtained by the Java compiler by creating
+     * an wrapper method to access a private method of another class
+     * in the same top-level declaration.
+     * For example, a nested class {@code C.D}
+     * can access private members within other related classes such as
+     * {@code C}, {@code C.D.E}, or {@code C.B},
+     * but the Java compiler may need to generate wrapper methods in
+     * those related classes.  In such cases, a {@code Lookup} object on
+     * {@code C.E} would be unable to those private members.
+     * A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
+     * which can transform a lookup on {@code C.E} into one on any of those other
+     * classes, without special elevation of privilege.
+     * <p>
+     * The accesses permitted to a given lookup object may be limited,
+     * according to its set of {@link #lookupModes lookupModes},
+     * to a subset of members normally accessible to the lookup class.
+     * For example, the {@link #publicLookup publicLookup}
+     * method produces a lookup object which is only allowed to access
+     * public members in public classes.
+     * The caller sensitive method {@link #lookup lookup}
+     * produces a lookup object with full capabilities relative to
+     * its caller class, to emulate all supported bytecode behaviors.
+     * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object
+     * with fewer access modes than the original lookup object.
+     *
+     * <p style="font-size:smaller;">
+     * <a name="privacc"></a>
+     * <em>Discussion of private access:</em>
+     * We say that a lookup has <em>private access</em>
+     * if its {@linkplain #lookupModes lookup modes}
+     * include the possibility of accessing {@code private} members.
+     * As documented in the relevant methods elsewhere,
+     * only lookups with private access possess the following capabilities:
+     * <ul style="font-size:smaller;">
+     * <li>access private fields, methods, and constructors of the lookup class
+     * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
+     *     such as {@code Class.forName}
+     * <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
+     * <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
+     *     for classes accessible to the lookup class
+     * <li>create {@link Lookup#in delegated lookup objects} which have private access to other classes
+     *     within the same package member
+     * </ul>
+     * <p style="font-size:smaller;">
+     * Each of these permissions is a consequence of the fact that a lookup object
+     * with private access can be securely traced back to an originating class,
+     * whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
+     * can be reliably determined and emulated by method handles.
+     *
+     * <h1><a name="secmgr"></a>Security manager interactions</h1>
+     * Although bytecode instructions can only refer to classes in
+     * a related class loader, this API can search for methods in any
+     * class, as long as a reference to its {@code Class} object is
+     * available.  Such cross-loader references are also possible with the
+     * Core Reflection API, and are impossible to bytecode instructions
+     * such as {@code invokestatic} or {@code getfield}.
+     * There is a {@linkplain java.lang.SecurityManager security manager API}
+     * to allow applications to check such cross-loader references.
+     * These checks apply to both the {@code MethodHandles.Lookup} API
+     * and the Core Reflection API
+     * (as found on {@link java.lang.Class Class}).
+     * <p>
+     * If a security manager is present, member lookups are subject to
+     * additional checks.
+     * From one to three calls are made to the security manager.
+     * Any of these calls can refuse access by throwing a
+     * {@link java.lang.SecurityException SecurityException}.
+     * Define {@code smgr} as the security manager,
+     * {@code lookc} as the lookup class of the current lookup object,
+     * {@code refc} as the containing class in which the member
+     * is being sought, and {@code defc} as the class in which the
+     * member is actually defined.
+     * The value {@code lookc} is defined as <em>not present</em>
+     * if the current lookup object does not have
+     * <a href="MethodHandles.Lookup.html#privacc">private access</a>.
+     * The calls are made according to the following rules:
+     * <ul>
+     * <li><b>Step 1:</b>
+     *     If {@code lookc} is not present, or if its class loader is not
+     *     the same as or an ancestor of the class loader of {@code refc},
+     *     then {@link SecurityManager#checkPackageAccess
+     *     smgr.checkPackageAccess(refcPkg)} is called,
+     *     where {@code refcPkg} is the package of {@code refc}.
+     * <li><b>Step 2:</b>
+     *     If the retrieved member is not public and
+     *     {@code lookc} is not present, then
+     *     {@link SecurityManager#checkPermission smgr.checkPermission}
+     *     with {@code RuntimePermission("accessDeclaredMembers")} is called.
+     * <li><b>Step 3:</b>
+     *     If the retrieved member is not public,
+     *     and if {@code lookc} is not present,
+     *     and if {@code defc} and {@code refc} are different,
+     *     then {@link SecurityManager#checkPackageAccess
+     *     smgr.checkPackageAccess(defcPkg)} is called,
+     *     where {@code defcPkg} is the package of {@code defc}.
+     * </ul>
+     * Security checks are performed after other access checks have passed.
+     * Therefore, the above rules presuppose a member that is public,
+     * or else that is being accessed from a lookup class that has
+     * rights to access the member.
+     *
+     * <h1><a name="callsens"></a>Caller sensitive methods</h1>
+     * A small number of Java methods have a special property called caller sensitivity.
+     * A <em>caller-sensitive</em> method can behave differently depending on the
+     * identity of its immediate caller.
+     * <p>
+     * If a method handle for a caller-sensitive method is requested,
+     * the general rules for <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> apply,
+     * but they take account of the lookup class in a special way.
+     * The resulting method handle behaves as if it were called
+     * from an instruction contained in the lookup class,
+     * so that the caller-sensitive method detects the lookup class.
+     * (By contrast, the invoker of the method handle is disregarded.)
+     * Thus, in the case of caller-sensitive methods,
+     * different lookup classes may give rise to
+     * differently behaving method handles.
+     * <p>
+     * In cases where the lookup object is
+     * {@link #publicLookup publicLookup()},
+     * or some other lookup object without
+     * <a href="MethodHandles.Lookup.html#privacc">private access</a>,
+     * the lookup class is disregarded.
+     * In such cases, no caller-sensitive method handle can be created,
+     * access is forbidden, and the lookup fails with an
+     * {@code IllegalAccessException}.
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * For example, the caller-sensitive method
+     * {@link java.lang.Class#forName(String) Class.forName(x)}
+     * can return varying classes or throw varying exceptions,
+     * depending on the class loader of the class that calls it.
+     * A public lookup of {@code Class.forName} will fail, because
+     * there is no reasonable way to determine its bytecode behavior.
+     * <p style="font-size:smaller;">
+     * If an application caches method handles for broad sharing,
+     * it should use {@code publicLookup()} to create them.
+     * If there is a lookup of {@code Class.forName}, it will fail,
+     * and the application must take appropriate action in that case.
+     * It may be that a later lookup, perhaps during the invocation of a
+     * bootstrap method, can incorporate the specific identity
+     * of the caller, making the method accessible.
+     * <p style="font-size:smaller;">
+     * The function {@code MethodHandles.lookup} is caller sensitive
+     * so that there can be a secure foundation for lookups.
+     * Nearly all other methods in the JSR 292 API rely on lookup
+     * objects to check access requests.
+     */
+    // Android-changed: Change link targets from MethodHandles#[public]Lookup to
+    // #[public]Lookup to work around complaints from javadoc.
+    public static final
+    class Lookup {
+        /** The class on behalf of whom the lookup is being performed. */
+        /* @NonNull */ private final Class<?> lookupClass;
+
+        /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
+        private final int allowedModes;
+
+        /** A single-bit mask representing {@code public} access,
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value, {@code 0x01}, happens to be the same as the value of the
+         *  {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
+         */
+        public static final int PUBLIC = Modifier.PUBLIC;
+
+        /** A single-bit mask representing {@code private} access,
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value, {@code 0x02}, happens to be the same as the value of the
+         *  {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
+         */
+        public static final int PRIVATE = Modifier.PRIVATE;
+
+        /** A single-bit mask representing {@code protected} access,
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value, {@code 0x04}, happens to be the same as the value of the
+         *  {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
+         */
+        public static final int PROTECTED = Modifier.PROTECTED;
+
+        /** A single-bit mask representing {@code package} access (default access),
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value is {@code 0x08}, which does not correspond meaningfully to
+         *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+         */
+        public static final int PACKAGE = Modifier.STATIC;
+
+        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+
+        // Android-note: Android has no notion of a trusted lookup. If required, such lookups
+        // are performed by the runtime. As a result, we always use lookupClass, which will always
+        // be non-null in our implementation.
+        //
+        // private static final int TRUSTED   = -1;
+
+        private static int fixmods(int mods) {
+            mods &= (ALL_MODES - PACKAGE);
+            return (mods != 0) ? mods : PACKAGE;
+        }
+
+        /** Tells which class is performing the lookup.  It is this class against
+         *  which checks are performed for visibility and access permissions.
+         *  <p>
+         *  The class implies a maximum level of access permission,
+         *  but the permissions may be additionally limited by the bitmask
+         *  {@link #lookupModes lookupModes}, which controls whether non-public members
+         *  can be accessed.
+         *  @return the lookup class, on behalf of which this lookup object finds members
+         */
+        public Class<?> lookupClass() {
+            return lookupClass;
+        }
+
+        /** Tells which access-protection classes of members this lookup object can produce.
+         *  The result is a bit-mask of the bits
+         *  {@linkplain #PUBLIC PUBLIC (0x01)},
+         *  {@linkplain #PRIVATE PRIVATE (0x02)},
+         *  {@linkplain #PROTECTED PROTECTED (0x04)},
+         *  and {@linkplain #PACKAGE PACKAGE (0x08)}.
+         *  <p>
+         *  A freshly-created lookup object
+         *  on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
+         *  has all possible bits set, since the caller class can access all its own members.
+         *  A lookup object on a new lookup class
+         *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
+         *  may have some mode bits set to zero.
+         *  The purpose of this is to restrict access via the new lookup object,
+         *  so that it can access only names which can be reached by the original
+         *  lookup object, and also by the new lookup class.
+         *  @return the lookup modes, which limit the kinds of access performed by this lookup object
+         */
+        public int lookupModes() {
+            return allowedModes & ALL_MODES;
+        }
+
+        /** Embody the current class (the lookupClass) as a lookup class
+         * for method handle creation.
+         * Must be called by from a method in this package,
+         * which in turn is called by a method not in this package.
+         */
+        Lookup(Class<?> lookupClass) {
+            this(lookupClass, ALL_MODES);
+            // make sure we haven't accidentally picked up a privileged class:
+            checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
+        }
+
+        private Lookup(Class<?> lookupClass, int allowedModes) {
+            this.lookupClass = lookupClass;
+            this.allowedModes = allowedModes;
+        }
+
+        /**
+         * Creates a lookup on the specified new lookup class.
+         * The resulting object will report the specified
+         * class as its own {@link #lookupClass lookupClass}.
+         * <p>
+         * However, the resulting {@code Lookup} object is guaranteed
+         * to have no more access capabilities than the original.
+         * In particular, access capabilities can be lost as follows:<ul>
+         * <li>If the new lookup class differs from the old one,
+         * protected members will not be accessible by virtue of inheritance.
+         * (Protected members may continue to be accessible because of package sharing.)
+         * <li>If the new lookup class is in a different package
+         * than the old one, protected and default (package) members will not be accessible.
+         * <li>If the new lookup class is not within the same package member
+         * as the old one, private members will not be accessible.
+         * <li>If the new lookup class is not accessible to the old lookup class,
+         * then no members, not even public members, will be accessible.
+         * (In all other cases, public members will continue to be accessible.)
+         * </ul>
+         *
+         * @param requestedLookupClass the desired lookup class for the new lookup object
+         * @return a lookup object which reports the desired lookup class
+         * @throws NullPointerException if the argument is null
+         */
+        public Lookup in(Class<?> requestedLookupClass) {
+            requestedLookupClass.getClass();  // null check
+            // Android-changed: There's no notion of a trusted lookup.
+            // if (allowedModes == TRUSTED)  // IMPL_LOOKUP can make any lookup at all
+            //    return new Lookup(requestedLookupClass, ALL_MODES);
+
+            if (requestedLookupClass == this.lookupClass)
+                return this;  // keep same capabilities
+            int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+            if ((newModes & PACKAGE) != 0
+                && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
+                newModes &= ~(PACKAGE|PRIVATE);
+            }
+            // Allow nestmate lookups to be created without special privilege:
+            if ((newModes & PRIVATE) != 0
+                && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
+                newModes &= ~PRIVATE;
+            }
+            if ((newModes & PUBLIC) != 0
+                && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
+                // The requested class it not accessible from the lookup class.
+                // No permissions.
+                newModes = 0;
+            }
+            checkUnprivilegedlookupClass(requestedLookupClass, newModes);
+            return new Lookup(requestedLookupClass, newModes);
+        }
+
+        // Make sure outer class is initialized first.
+        //
+        // Android-changed: Removed unnecessary reference to IMPL_NAMES.
+        // static { IMPL_NAMES.getClass(); }
+
+        /** Version of lookup which is trusted minimally.
+         *  It can only be used to create method handles to
+         *  publicly accessible members.
+         */
+        static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
+
+        /** Package-private version of lookup which is trusted. */
+        static final Lookup IMPL_LOOKUP = new Lookup(Object.class, ALL_MODES);
+
+        private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
+            String name = lookupClass.getName();
+            if (name.startsWith("java.lang.invoke."))
+                throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
+
+            // For caller-sensitive MethodHandles.lookup()
+            // disallow lookup more restricted packages
+            //
+            // Android-changed: The bootstrap classloader isn't null.
+            if (allowedModes == ALL_MODES &&
+                    lookupClass.getClassLoader() == Object.class.getClassLoader()) {
+                if (name.startsWith("java.") ||
+                        (name.startsWith("sun.")
+                                && !name.startsWith("sun.invoke.")
+                                && !name.equals("sun.reflect.ReflectionFactory"))) {
+                    throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
+                }
+            }
+        }
+
+        /**
+         * Displays the name of the class from which lookups are to be made.
+         * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
+         * If there are restrictions on the access permitted to this lookup,
+         * this is indicated by adding a suffix to the class name, consisting
+         * of a slash and a keyword.  The keyword represents the strongest
+         * allowed access, and is chosen as follows:
+         * <ul>
+         * <li>If no access is allowed, the suffix is "/noaccess".
+         * <li>If only public access is allowed, the suffix is "/public".
+         * <li>If only public and package access are allowed, the suffix is "/package".
+         * <li>If only public, package, and private access are allowed, the suffix is "/private".
+         * </ul>
+         * If none of the above cases apply, it is the case that full
+         * access (public, package, private, and protected) is allowed.
+         * In this case, no suffix is added.
+         * This is true only of an object obtained originally from
+         * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
+         * Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in}
+         * always have restricted access, and will display a suffix.
+         * <p>
+         * (It may seem strange that protected access should be
+         * stronger than private access.  Viewed independently from
+         * package access, protected access is the first to be lost,
+         * because it requires a direct subclass relationship between
+         * caller and callee.)
+         * @see #in
+         */
+        @Override
+        public String toString() {
+            String cname = lookupClass.getName();
+            switch (allowedModes) {
+            case 0:  // no privileges
+                return cname + "/noaccess";
+            case PUBLIC:
+                return cname + "/public";
+            case PUBLIC|PACKAGE:
+                return cname + "/package";
+            case ALL_MODES & ~PROTECTED:
+                return cname + "/private";
+            case ALL_MODES:
+                return cname;
+            // Android-changed: No support for TRUSTED callers.
+            // case TRUSTED:
+            //    return "/trusted";  // internal only; not exported
+            default:  // Should not happen, but it's a bitfield...
+                cname = cname + "/" + Integer.toHexString(allowedModes);
+                assert(false) : cname;
+                return cname;
+            }
+        }
+
+        /**
+         * Produces a method handle for a static method.
+         * The type of the method handle will be that of the method.
+         * (Since static methods do not take receivers, there is no
+         * additional receiver argument inserted into the method handle type,
+         * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
+         * The method and all its argument types must be accessible to the lookup object.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the method's variable arity modifier bit ({@code 0x0080}) is set.
+         * <p>
+         * If the returned method handle is invoked, the method's class will
+         * be initialized, if it has not already been initialized.
+         * <p><b>Example:</b>
+         * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
+  "asList", methodType(List.class, Object[].class));
+assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
+         * }</pre></blockquote>
+         * @param refc the class from which the method is accessed
+         * @param name the name of the method
+         * @param type the type of the method
+         * @return the desired method handle
+         * @throws NoSuchMethodException if the method does not exist
+         * @throws IllegalAccessException if access checking fails,
+         *                                or if the method is not {@code static},
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public
+        MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            Method method = refc.getDeclaredMethod(name, type.ptypes());
+            final int modifiers = method.getModifiers();
+            if (!Modifier.isStatic(modifiers)) {
+                throw new IllegalAccessException("Method" + method + " is not static");
+            }
+            checkReturnType(method, type);
+            checkAccess(refc, method.getDeclaringClass(), modifiers, method.getName());
+            return createMethodHandle(method, MethodHandle.INVOKE_STATIC, type);
+        }
+
+        private MethodHandle findVirtualForMH(String name, MethodType type) {
+            // these names require special lookups because of the implicit MethodType argument
+            if ("invoke".equals(name))
+                return invoker(type);
+            if ("invokeExact".equals(name))
+                return exactInvoker(type);
+            return null;
+        }
+
+        private MethodHandle findVirtualForVH(String name, MethodType type) {
+            VarHandle.AccessMode accessMode;
+            try {
+                accessMode = VarHandle.AccessMode.valueFromMethodName(name);
+            } catch (IllegalArgumentException e) {
+                return null;
+            }
+            return varHandleInvoker(accessMode, type);
+        }
+
+        private static MethodHandle createMethodHandle(Method method, int handleKind,
+                                                       MethodType methodType) {
+            MethodHandle mh = new MethodHandleImpl(method.getArtMethod(), handleKind, methodType);
+            if (method.isVarArgs()) {
+                return new Transformers.VarargsCollector(mh);
+            } else {
+                return mh;
+            }
+        }
+
+        /**
+         * Produces a method handle for a virtual method.
+         * The type of the method handle will be that of the method,
+         * with the receiver type (usually {@code refc}) prepended.
+         * The method and all its argument types must be accessible to the lookup object.
+         * <p>
+         * When called, the handle will treat the first argument as a receiver
+         * and dispatch on the receiver's type to determine which method
+         * implementation to enter.
+         * (The dispatching action is identical with that performed by an
+         * {@code invokevirtual} or {@code invokeinterface} instruction.)
+         * <p>
+         * The first argument will be of type {@code refc} if the lookup
+         * class has full privileges to access the member.  Otherwise
+         * the member must be {@code protected} and the first argument
+         * will be restricted in type to the lookup class.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the method's variable arity modifier bit ({@code 0x0080}) is set.
+         * <p>
+         * Because of the general <a href="MethodHandles.Lookup.html#equiv">equivalence</a> between {@code invokevirtual}
+         * instructions and method handles produced by {@code findVirtual},
+         * if the class is {@code MethodHandle} and the name string is
+         * {@code invokeExact} or {@code invoke}, the resulting
+         * method handle is equivalent to one produced by
+         * {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
+         * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
+         * with the same {@code type} argument.
+         *
+         * <b>Example:</b>
+         * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_concat = publicLookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
+  "hashCode", methodType(int.class));
+MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
+  "hashCode", methodType(int.class));
+assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
+assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
+assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
+// interface method:
+MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
+  "subSequence", methodType(CharSequence.class, int.class, int.class));
+assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
+// constructor "internal method" must be accessed differently:
+MethodType MT_newString = methodType(void.class); //()V for new String()
+try { assertEquals("impossible", lookup()
+        .findVirtual(String.class, "<init>", MT_newString));
+ } catch (NoSuchMethodException ex) { } // OK
+MethodHandle MH_newString = publicLookup()
+  .findConstructor(String.class, MT_newString);
+assertEquals("", (String) MH_newString.invokeExact());
+         * }</pre></blockquote>
+         *
+         * @param refc the class or interface from which the method is accessed
+         * @param name the name of the method
+         * @param type the type of the method, with the receiver argument omitted
+         * @return the desired method handle
+         * @throws NoSuchMethodException if the method does not exist
+         * @throws IllegalAccessException if access checking fails,
+         *                                or if the method is {@code static}
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            // Special case : when we're looking up a virtual method on the MethodHandles class
+            // itself, we can return one of our specialized invokers.
+            if (refc == MethodHandle.class) {
+                MethodHandle mh = findVirtualForMH(name, type);
+                if (mh != null) {
+                    return mh;
+                }
+            } else if (refc == VarHandle.class) {
+                // Returns an non-exact invoker.
+                MethodHandle mh = findVirtualForVH(name, type);
+                if (mh != null) {
+                    return mh;
+                }
+            }
+
+            Method method = refc.getInstanceMethod(name, type.ptypes());
+            if (method == null) {
+                // This is pretty ugly and a consequence of the MethodHandles API. We have to throw
+                // an IAE and not an NSME if the method exists but is static (even though the RI's
+                // IAE has a message that says "no such method"). We confine the ugliness and
+                // slowness to the failure case, and allow getInstanceMethod to remain fairly
+                // general.
+                try {
+                    Method m = refc.getDeclaredMethod(name, type.ptypes());
+                    if (Modifier.isStatic(m.getModifiers())) {
+                        throw new IllegalAccessException("Method" + m + " is static");
+                    }
+                } catch (NoSuchMethodException ignored) {
+                }
+
+                throw new NoSuchMethodException(name + " "  + Arrays.toString(type.ptypes()));
+            }
+            checkReturnType(method, type);
+
+            // We have a valid method, perform access checks.
+            checkAccess(refc, method.getDeclaringClass(), method.getModifiers(), method.getName());
+
+            // Insert the leading reference parameter.
+            MethodType handleType = type.insertParameterTypes(0, refc);
+            return createMethodHandle(method, MethodHandle.INVOKE_VIRTUAL, handleType);
+        }
+
+        /**
+         * Produces a method handle which creates an object and initializes it, using
+         * the constructor of the specified type.
+         * The parameter types of the method handle will be those of the constructor,
+         * while the return type will be a reference to the constructor's class.
+         * The constructor and all its argument types must be accessible to the lookup object.
+         * <p>
+         * The requested type must have a return type of {@code void}.
+         * (This is consistent with the JVM's treatment of constructor type descriptors.)
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+         * <p>
+         * If the returned method handle is invoked, the constructor's class will
+         * be initialized, if it has not already been initialized.
+         * <p><b>Example:</b>
+         * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_newArrayList = publicLookup().findConstructor(
+  ArrayList.class, methodType(void.class, Collection.class));
+Collection orig = Arrays.asList("x", "y");
+Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
+assert(orig != copy);
+assertEquals(orig, copy);
+// a variable-arity constructor:
+MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
+  ProcessBuilder.class, methodType(void.class, String[].class));
+ProcessBuilder pb = (ProcessBuilder)
+  MH_newProcessBuilder.invoke("x", "y", "z");
+assertEquals("[x, y, z]", pb.command().toString());
+         * }</pre></blockquote>
+         * @param refc the class or interface from which the method is accessed
+         * @param type the type of the method, with the receiver argument omitted, and a void return type
+         * @return the desired method handle
+         * @throws NoSuchMethodException if the constructor does not exist
+         * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            if (refc.isArray()) {
+                throw new NoSuchMethodException("no constructor for array class: " + refc.getName());
+            }
+            // The queried |type| is (PT1,PT2,..)V
+            Constructor constructor = refc.getDeclaredConstructor(type.ptypes());
+            if (constructor == null) {
+                throw new NoSuchMethodException(
+                    "No constructor for " + constructor.getDeclaringClass() + " matching " + type);
+            }
+            checkAccess(refc, constructor.getDeclaringClass(), constructor.getModifiers(),
+                    constructor.getName());
+
+            return createMethodHandleForConstructor(constructor);
+        }
+
+        private MethodHandle createMethodHandleForConstructor(Constructor constructor) {
+            Class<?> refc = constructor.getDeclaringClass();
+            MethodType constructorType =
+                    MethodType.methodType(refc, constructor.getParameterTypes());
+            MethodHandle mh;
+            if (refc == String.class) {
+                // String constructors have optimized StringFactory methods
+                // that matches returned type. These factory methods combine the
+                // memory allocation and initialization calls for String objects.
+                mh = new MethodHandleImpl(constructor.getArtMethod(), MethodHandle.INVOKE_DIRECT,
+                                          constructorType);
+            } else {
+                // Constructors for all other classes use a Construct transformer to perform
+                // their memory allocation and call to <init>.
+                MethodType initType = initMethodType(constructorType);
+                MethodHandle initHandle = new MethodHandleImpl(
+                    constructor.getArtMethod(), MethodHandle.INVOKE_DIRECT, initType);
+                mh = new Transformers.Construct(initHandle, constructorType);
+            }
+
+            if (constructor.isVarArgs()) {
+                mh = new Transformers.VarargsCollector(mh);
+            }
+            return mh;
+        }
+
+        private static MethodType initMethodType(MethodType constructorType) {
+            // Returns a MethodType appropriate for class <init>
+            // methods. Constructor MethodTypes have the form
+            // (PT1,PT2,...)C and class <init> MethodTypes have the
+            // form (C,PT1,PT2,...)V.
+            assert constructorType.rtype() != void.class;
+
+            // Insert constructorType C as the first parameter type in
+            // the MethodType for <init>.
+            Class<?> [] initPtypes = new Class<?> [constructorType.ptypes().length + 1];
+            initPtypes[0] = constructorType.rtype();
+            System.arraycopy(constructorType.ptypes(), 0, initPtypes, 1,
+                             constructorType.ptypes().length);
+
+            // Set the return type for the <init> MethodType to be void.
+            return MethodType.methodType(void.class, initPtypes);
+        }
+
+        /**
+         * Produces an early-bound method handle for a virtual method.
+         * It will bypass checks for overriding methods on the receiver,
+         * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
+         * instruction from within the explicitly specified {@code specialCaller}.
+         * The type of the method handle will be that of the method,
+         * with a suitably restricted receiver type prepended.
+         * (The receiver type will be {@code specialCaller} or a subtype.)
+         * The method and all its argument types must be accessible
+         * to the lookup object.
+         * <p>
+         * Before method resolution,
+         * if the explicitly specified caller class is not identical with the
+         * lookup class, or if this lookup object does not have
+         * <a href="MethodHandles.Lookup.html#privacc">private access</a>
+         * privileges, the access fails.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the method's variable arity modifier bit ({@code 0x0080}) is set.
+         * <p style="font-size:smaller;">
+         * <em>(Note:  JVM internal methods named {@code "<init>"} are not visible to this API,
+         * even though the {@code invokespecial} instruction can refer to them
+         * in special circumstances.  Use {@link #findConstructor findConstructor}
+         * to access instance initialization methods in a safe manner.)</em>
+         * <p><b>Example:</b>
+         * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+static class Listie extends ArrayList {
+  public String toString() { return "[wee Listie]"; }
+  static Lookup lookup() { return MethodHandles.lookup(); }
+}
+...
+// no access to constructor via invokeSpecial:
+MethodHandle MH_newListie = Listie.lookup()
+  .findConstructor(Listie.class, methodType(void.class));
+Listie l = (Listie) MH_newListie.invokeExact();
+try { assertEquals("impossible", Listie.lookup().findSpecial(
+        Listie.class, "<init>", methodType(void.class), Listie.class));
+ } catch (NoSuchMethodException ex) { } // OK
+// access to super and self methods via invokeSpecial:
+MethodHandle MH_super = Listie.lookup().findSpecial(
+  ArrayList.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_this = Listie.lookup().findSpecial(
+  Listie.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_duper = Listie.lookup().findSpecial(
+  Object.class, "toString" , methodType(String.class), Listie.class);
+assertEquals("[]", (String) MH_super.invokeExact(l));
+assertEquals(""+l, (String) MH_this.invokeExact(l));
+assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
+try { assertEquals("inaccessible", Listie.lookup().findSpecial(
+        String.class, "toString", methodType(String.class), Listie.class));
+ } catch (IllegalAccessException ex) { } // OK
+Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
+assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
+         * }</pre></blockquote>
+         *
+         * @param refc the class or interface from which the method is accessed
+         * @param name the name of the method (which must not be "&lt;init&gt;")
+         * @param type the type of the method, with the receiver argument omitted
+         * @param specialCaller the proposed calling class to perform the {@code invokespecial}
+         * @return the desired method handle
+         * @throws NoSuchMethodException if the method does not exist
+         * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
+                                        Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
+            if (specialCaller == null) {
+                throw new NullPointerException("specialCaller == null");
+            }
+
+            if (type == null) {
+                throw new NullPointerException("type == null");
+            }
+
+            if (name == null) {
+                throw new NullPointerException("name == null");
+            }
+
+            if (refc == null) {
+                throw new NullPointerException("ref == null");
+            }
+
+            // Make sure that the special caller is identical to the lookup class or that we have
+            // private access.
+            // Android-changed: Also allow access to any interface methods.
+            checkSpecialCaller(specialCaller, refc);
+
+            // Even though constructors are invoked using a "special" invoke, handles to them can't
+            // be created using findSpecial. Callers must use findConstructor instead. Similarly,
+            // there is no path for calling static class initializers.
+            if (name.startsWith("<")) {
+                throw new NoSuchMethodException(name + " is not a valid method name.");
+            }
+
+            Method method = refc.getDeclaredMethod(name, type.ptypes());
+            checkReturnType(method, type);
+            return findSpecial(method, type, refc, specialCaller);
+        }
+
+        private MethodHandle findSpecial(Method method, MethodType type,
+                                         Class<?> refc, Class<?> specialCaller)
+                throws IllegalAccessException {
+            if (Modifier.isStatic(method.getModifiers())) {
+                throw new IllegalAccessException("expected a non-static method:" + method);
+            }
+
+            if (Modifier.isPrivate(method.getModifiers())) {
+                // Since this is a private method, we'll need to also make sure that the
+                // lookup class is the same as the refering class. We've already checked that
+                // the specialCaller is the same as the special lookup class, both of these must
+                // be the same as the declaring class(*) in order to access the private method.
+                //
+                // (*) Well, this isn't true for nested classes but OpenJDK doesn't support those
+                // either.
+                if (refc != lookupClass()) {
+                    throw new IllegalAccessException("no private access for invokespecial : "
+                            + refc + ", from" + this);
+                }
+
+                // This is a private method, so there's nothing special to do.
+                MethodType handleType = type.insertParameterTypes(0, refc);
+                return createMethodHandle(method, MethodHandle.INVOKE_DIRECT, handleType);
+            }
+
+            // This is a public, protected or package-private method, which means we're expecting
+            // invoke-super semantics. We'll have to restrict the receiver type appropriately on the
+            // handle once we check that there really is a "super" relationship between them.
+            if (!method.getDeclaringClass().isAssignableFrom(specialCaller)) {
+                throw new IllegalAccessException(refc + "is not assignable from " + specialCaller);
+            }
+
+            // Note that we restrict the receiver to "specialCaller" instances.
+            MethodType handleType = type.insertParameterTypes(0, specialCaller);
+            return createMethodHandle(method, MethodHandle.INVOKE_SUPER, handleType);
+        }
+
+        /**
+         * Produces a method handle giving read access to a non-static field.
+         * The type of the method handle will have a return type of the field's
+         * value type.
+         * The method handle's single argument will be the instance containing
+         * the field.
+         * Access checking is performed immediately on behalf of the lookup class.
+         * @param refc the class or interface from which the method is accessed
+         * @param name the field's name
+         * @param type the field's type
+         * @return a method handle which can load values from the field
+         * @throws NoSuchFieldException if the field does not exist
+         * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            return findAccessor(refc, name, type, MethodHandle.IGET);
+        }
+
+        private MethodHandle findAccessor(Class<?> refc, String name, Class<?> type, int kind)
+            throws NoSuchFieldException, IllegalAccessException {
+            final Field field = findFieldOfType(refc, name, type);
+            return findAccessor(field, refc, type, kind, true /* performAccessChecks */);
+        }
+
+        private MethodHandle findAccessor(Field field, Class<?> refc, Class<?> type, int kind,
+                                          boolean performAccessChecks)
+                throws IllegalAccessException {
+            final boolean isSetterKind = kind == MethodHandle.IPUT || kind == MethodHandle.SPUT;
+            final boolean isStaticKind = kind == MethodHandle.SGET || kind == MethodHandle.SPUT;
+            commonFieldChecks(field, refc, type, isStaticKind, performAccessChecks);
+            if (performAccessChecks) {
+                final int modifiers = field.getModifiers();
+                if (isSetterKind && Modifier.isFinal(modifiers)) {
+                    throw new IllegalAccessException("Field " + field + " is final");
+                }
+            }
+
+            final MethodType methodType;
+            switch (kind) {
+                case MethodHandle.SGET:
+                    methodType = MethodType.methodType(type);
+                    break;
+                case MethodHandle.SPUT:
+                    methodType = MethodType.methodType(void.class, type);
+                    break;
+                case MethodHandle.IGET:
+                    methodType = MethodType.methodType(type, refc);
+                    break;
+                case MethodHandle.IPUT:
+                    methodType = MethodType.methodType(void.class, refc, type);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid kind " + kind);
+            }
+            return new MethodHandleImpl(field.getArtField(), kind, methodType);
+        }
+
+        /**
+         * Produces a method handle giving write access to a non-static field.
+         * The type of the method handle will have a void return type.
+         * The method handle will take two arguments, the instance containing
+         * the field, and the value to be stored.
+         * The second argument will be of the field's value type.
+         * Access checking is performed immediately on behalf of the lookup class.
+         * @param refc the class or interface from which the method is accessed
+         * @param name the field's name
+         * @param type the field's type
+         * @return a method handle which can store values into the field
+         * @throws NoSuchFieldException if the field does not exist
+         * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            return findAccessor(refc, name, type, MethodHandle.IPUT);
+        }
+
+        // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory method.
+        /**
+         * Produces a VarHandle giving access to a non-static field {@code name}
+         * of type {@code type} declared in a class of type {@code recv}.
+         * The VarHandle's variable type is {@code type} and it has one
+         * coordinate type, {@code recv}.
+         * <p>
+         * Access checking is performed immediately on behalf of the lookup
+         * class.
+         * <p>
+         * Certain access modes of the returned VarHandle are unsupported under
+         * the following conditions:
+         * <ul>
+         * <li>if the field is declared {@code final}, then the write, atomic
+         *     update, numeric atomic update, and bitwise atomic update access
+         *     modes are unsupported.
+         * <li>if the field type is anything other than {@code byte},
+         *     {@code short}, {@code char}, {@code int}, {@code long},
+         *     {@code float}, or {@code double} then numeric atomic update
+         *     access modes are unsupported.
+         * <li>if the field type is anything other than {@code boolean},
+         *     {@code byte}, {@code short}, {@code char}, {@code int} or
+         *     {@code long} then bitwise atomic update access modes are
+         *     unsupported.
+         * </ul>
+         * <p>
+         * If the field is declared {@code volatile} then the returned VarHandle
+         * will override access to the field (effectively ignore the
+         * {@code volatile} declaration) in accordance to its specified
+         * access modes.
+         * <p>
+         * If the field type is {@code float} or {@code double} then numeric
+         * and atomic update access modes compare values using their bitwise
+         * representation (see {@link Float#floatToRawIntBits} and
+         * {@link Double#doubleToRawLongBits}, respectively).
+         * @apiNote
+         * Bitwise comparison of {@code float} values or {@code double} values,
+         * as performed by the numeric and atomic update access modes, differ
+         * from the primitive {@code ==} operator and the {@link Float#equals}
+         * and {@link Double#equals} methods, specifically with respect to
+         * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+         * Care should be taken when performing a compare and set or a compare
+         * and exchange operation with such values since the operation may
+         * unexpectedly fail.
+         * There are many possible NaN values that are considered to be
+         * {@code NaN} in Java, although no IEEE 754 floating-point operation
+         * provided by Java can distinguish between them.  Operation failure can
+         * occur if the expected or witness value is a NaN value and it is
+         * transformed (perhaps in a platform specific manner) into another NaN
+         * value, and thus has a different bitwise representation (see
+         * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+         * details).
+         * The values {@code -0.0} and {@code +0.0} have different bitwise
+         * representations but are considered equal when using the primitive
+         * {@code ==} operator.  Operation failure can occur if, for example, a
+         * numeric algorithm computes an expected value to be say {@code -0.0}
+         * and previously computed the witness value to be say {@code +0.0}.
+         * @param recv the receiver class, of type {@code R}, that declares the
+         * non-static field
+         * @param name the field's name
+         * @param type the field's type, of type {@code T}
+         * @return a VarHandle giving access to non-static fields.
+         * @throws NoSuchFieldException if the field does not exist
+         * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         * @since 9
+         * @hide
+         */
+        public VarHandle findVarHandle(Class<?> recv, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            final Field field = findFieldOfType(recv, name, type);
+            final boolean isStatic = false;
+            final boolean performAccessChecks = true;
+            commonFieldChecks(field, recv, type, isStatic, performAccessChecks);
+            return FieldVarHandle.create(field);
+        }
+        // END Android-changed: OpenJDK 9+181 VarHandle API factory method.
+
+        // BEGIN Android-added: Common field resolution and access check methods.
+        private Field findFieldOfType(final Class<?> refc, String name, Class<?> type)
+                throws NoSuchFieldException {
+            Field field = null;
+
+            // Search refc and super classes for the field.
+            for (Class<?> cls = refc; cls != null; cls = cls.getSuperclass()) {
+                try {
+                    field = cls.getDeclaredField(name);
+                    break;
+                } catch (NoSuchFieldException e) {
+                }
+            }
+
+            if (field == null) {
+                // Force failure citing refc.
+                field = refc.getDeclaredField(name);
+            }
+
+            final Class<?> fieldType = field.getType();
+            if (fieldType != type) {
+                throw new NoSuchFieldException(name);
+            }
+            return field;
+        }
+
+        private void commonFieldChecks(Field field, Class<?> refc, Class<?> type,
+                                       boolean isStatic, boolean performAccessChecks)
+                throws IllegalAccessException {
+            final int modifiers = field.getModifiers();
+            if (performAccessChecks) {
+                checkAccess(refc, field.getDeclaringClass(), modifiers, field.getName());
+            }
+            if (Modifier.isStatic(modifiers) != isStatic) {
+                String reason = "Field " + field + " is " +
+                        (isStatic ? "not " : "") + "static";
+                throw new IllegalAccessException(reason);
+            }
+        }
+        // END Android-added: Common field resolution and access check methods.
+
+        /**
+         * Produces a method handle giving read access to a static field.
+         * The type of the method handle will have a return type of the field's
+         * value type.
+         * The method handle will take no arguments.
+         * Access checking is performed immediately on behalf of the lookup class.
+         * <p>
+         * If the returned method handle is invoked, the field's class will
+         * be initialized, if it has not already been initialized.
+         * @param refc the class or interface from which the method is accessed
+         * @param name the field's name
+         * @param type the field's type
+         * @return a method handle which can load values from the field
+         * @throws NoSuchFieldException if the field does not exist
+         * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            return findAccessor(refc, name, type, MethodHandle.SGET);
+        }
+
+        /**
+         * Produces a method handle giving write access to a static field.
+         * The type of the method handle will have a void return type.
+         * The method handle will take a single
+         * argument, of the field's value type, the value to be stored.
+         * Access checking is performed immediately on behalf of the lookup class.
+         * <p>
+         * If the returned method handle is invoked, the field's class will
+         * be initialized, if it has not already been initialized.
+         * @param refc the class or interface from which the method is accessed
+         * @param name the field's name
+         * @param type the field's type
+         * @return a method handle which can store values into the field
+         * @throws NoSuchFieldException if the field does not exist
+         * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            return findAccessor(refc, name, type, MethodHandle.SPUT);
+        }
+
+        // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory method.
+        /**
+         * Produces a VarHandle giving access to a static field {@code name} of
+         * type {@code type} declared in a class of type {@code decl}.
+         * The VarHandle's variable type is {@code type} and it has no
+         * coordinate types.
+         * <p>
+         * Access checking is performed immediately on behalf of the lookup
+         * class.
+         * <p>
+         * If the returned VarHandle is operated on, the declaring class will be
+         * initialized, if it has not already been initialized.
+         * <p>
+         * Certain access modes of the returned VarHandle are unsupported under
+         * the following conditions:
+         * <ul>
+         * <li>if the field is declared {@code final}, then the write, atomic
+         *     update, numeric atomic update, and bitwise atomic update access
+         *     modes are unsupported.
+         * <li>if the field type is anything other than {@code byte},
+         *     {@code short}, {@code char}, {@code int}, {@code long},
+         *     {@code float}, or {@code double}, then numeric atomic update
+         *     access modes are unsupported.
+         * <li>if the field type is anything other than {@code boolean},
+         *     {@code byte}, {@code short}, {@code char}, {@code int} or
+         *     {@code long} then bitwise atomic update access modes are
+         *     unsupported.
+         * </ul>
+         * <p>
+         * If the field is declared {@code volatile} then the returned VarHandle
+         * will override access to the field (effectively ignore the
+         * {@code volatile} declaration) in accordance to its specified
+         * access modes.
+         * <p>
+         * If the field type is {@code float} or {@code double} then numeric
+         * and atomic update access modes compare values using their bitwise
+         * representation (see {@link Float#floatToRawIntBits} and
+         * {@link Double#doubleToRawLongBits}, respectively).
+         * @apiNote
+         * Bitwise comparison of {@code float} values or {@code double} values,
+         * as performed by the numeric and atomic update access modes, differ
+         * from the primitive {@code ==} operator and the {@link Float#equals}
+         * and {@link Double#equals} methods, specifically with respect to
+         * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+         * Care should be taken when performing a compare and set or a compare
+         * and exchange operation with such values since the operation may
+         * unexpectedly fail.
+         * There are many possible NaN values that are considered to be
+         * {@code NaN} in Java, although no IEEE 754 floating-point operation
+         * provided by Java can distinguish between them.  Operation failure can
+         * occur if the expected or witness value is a NaN value and it is
+         * transformed (perhaps in a platform specific manner) into another NaN
+         * value, and thus has a different bitwise representation (see
+         * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+         * details).
+         * The values {@code -0.0} and {@code +0.0} have different bitwise
+         * representations but are considered equal when using the primitive
+         * {@code ==} operator.  Operation failure can occur if, for example, a
+         * numeric algorithm computes an expected value to be say {@code -0.0}
+         * and previously computed the witness value to be say {@code +0.0}.
+         * @param decl the class that declares the static field
+         * @param name the field's name
+         * @param type the field's type, of type {@code T}
+         * @return a VarHandle giving access to a static field
+         * @throws NoSuchFieldException if the field does not exist
+         * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         * @since 9
+         * @hide
+         */
+        public VarHandle findStaticVarHandle(Class<?> decl, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            final Field field = findFieldOfType(decl, name, type);
+            final boolean isStatic = true;
+            final boolean performAccessChecks = true;
+            commonFieldChecks(field, decl, type, isStatic, performAccessChecks);
+            return FieldVarHandle.create(field);
+        }
+        // END Android-changed: OpenJDK 9+181 VarHandle API factory method.
+
+        /**
+         * Produces an early-bound method handle for a non-static method.
+         * The receiver must have a supertype {@code defc} in which a method
+         * of the given name and type is accessible to the lookup class.
+         * The method and all its argument types must be accessible to the lookup object.
+         * The type of the method handle will be that of the method,
+         * without any insertion of an additional receiver parameter.
+         * The given receiver will be bound into the method handle,
+         * so that every call to the method handle will invoke the
+         * requested method on the given receiver.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the method's variable arity modifier bit ({@code 0x0080}) is set
+         * <em>and</em> the trailing array argument is not the only argument.
+         * (If the trailing array argument is the only argument,
+         * the given receiver value will be bound to it.)
+         * <p>
+         * This is equivalent to the following code:
+         * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle mh0 = lookup().findVirtual(defc, name, type);
+MethodHandle mh1 = mh0.bindTo(receiver);
+MethodType mt1 = mh1.type();
+if (mh0.isVarargsCollector())
+  mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
+return mh1;
+         * }</pre></blockquote>
+         * where {@code defc} is either {@code receiver.getClass()} or a super
+         * type of that class, in which the requested method is accessible
+         * to the lookup class.
+         * (Note that {@code bindTo} does not preserve variable arity.)
+         * @param receiver the object from which the method is accessed
+         * @param name the name of the method
+         * @param type the type of the method, with the receiver argument omitted
+         * @return the desired method handle
+         * @throws NoSuchMethodException if the method does not exist
+         * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws NullPointerException if any argument is null
+         * @see MethodHandle#bindTo
+         * @see #findVirtual
+         */
+        public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            MethodHandle handle = findVirtual(receiver.getClass(), name, type);
+            MethodHandle adapter = handle.bindTo(receiver);
+            MethodType adapterType = adapter.type();
+            if (handle.isVarargsCollector()) {
+                adapter = adapter.asVarargsCollector(
+                        adapterType.parameterType(adapterType.parameterCount() - 1));
+            }
+
+            return adapter;
+        }
+
+        /**
+         * Makes a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
+         * to <i>m</i>, if the lookup class has permission.
+         * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
+         * If <i>m</i> is virtual, overriding is respected on every call.
+         * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
+         * The type of the method handle will be that of the method,
+         * with the receiver type prepended (but only if it is non-static).
+         * If the method's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the method's variable arity modifier bit ({@code 0x0080}) is set.
+         * <p>
+         * If <i>m</i> is static, and
+         * if the returned method handle is invoked, the method's class will
+         * be initialized, if it has not already been initialized.
+         * @param m the reflected method
+         * @return a method handle which can invoke the reflected method
+         * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @throws NullPointerException if the argument is null
+         */
+        public MethodHandle unreflect(Method m) throws IllegalAccessException {
+            if (m == null) {
+                throw new NullPointerException("m == null");
+            }
+
+            MethodType methodType = MethodType.methodType(m.getReturnType(),
+                    m.getParameterTypes());
+
+            // We should only perform access checks if setAccessible hasn't been called yet.
+            if (!m.isAccessible()) {
+                checkAccess(m.getDeclaringClass(), m.getDeclaringClass(), m.getModifiers(),
+                        m.getName());
+            }
+
+            if (Modifier.isStatic(m.getModifiers())) {
+                return createMethodHandle(m, MethodHandle.INVOKE_STATIC, methodType);
+            } else {
+                methodType = methodType.insertParameterTypes(0, m.getDeclaringClass());
+                return createMethodHandle(m, MethodHandle.INVOKE_VIRTUAL, methodType);
+            }
+        }
+
+        /**
+         * Produces a method handle for a reflected method.
+         * It will bypass checks for overriding methods on the receiver,
+         * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
+         * instruction from within the explicitly specified {@code specialCaller}.
+         * The type of the method handle will be that of the method,
+         * with a suitably restricted receiver type prepended.
+         * (The receiver type will be {@code specialCaller} or a subtype.)
+         * If the method's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class,
+         * as if {@code invokespecial} instruction were being linked.
+         * <p>
+         * Before method resolution,
+         * if the explicitly specified caller class is not identical with the
+         * lookup class, or if this lookup object does not have
+         * <a href="MethodHandles.Lookup.html#privacc">private access</a>
+         * privileges, the access fails.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the method's variable arity modifier bit ({@code 0x0080}) is set.
+         * @param m the reflected method
+         * @param specialCaller the class nominally calling the method
+         * @return a method handle which can invoke the reflected method
+         * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @throws NullPointerException if any argument is null
+         */
+        public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
+            if (m == null) {
+                throw new NullPointerException("m == null");
+            }
+
+            if (specialCaller == null) {
+                throw new NullPointerException("specialCaller == null");
+            }
+
+            if (!m.isAccessible()) {
+                // Android-changed: Match Java language 9 behavior where unreflectSpecial continues
+                // to require exact caller lookupClass match.
+                checkSpecialCaller(specialCaller, null);
+            }
+
+            final MethodType methodType = MethodType.methodType(m.getReturnType(),
+                    m.getParameterTypes());
+            return findSpecial(m, methodType, m.getDeclaringClass() /* refc */, specialCaller);
+        }
+
+        /**
+         * Produces a method handle for a reflected constructor.
+         * The type of the method handle will be that of the constructor,
+         * with the return type changed to the declaring class.
+         * The method handle will perform a {@code newInstance} operation,
+         * creating a new instance of the constructor's class on the
+         * arguments passed to the method handle.
+         * <p>
+         * If the constructor's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * <p>
+         * The returned method handle will have
+         * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+         * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+         * <p>
+         * If the returned method handle is invoked, the constructor's class will
+         * be initialized, if it has not already been initialized.
+         * @param c the reflected constructor
+         * @return a method handle which can invoke the reflected constructor
+         * @throws IllegalAccessException if access checking fails
+         *                                or if the method's variable arity modifier bit
+         *                                is set and {@code asVarargsCollector} fails
+         * @throws NullPointerException if the argument is null
+         */
+        public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
+            if (c == null) {
+                throw new NullPointerException("c == null");
+            }
+
+            if (!c.isAccessible()) {
+                checkAccess(c.getDeclaringClass(), c.getDeclaringClass(), c.getModifiers(),
+                        c.getName());
+            }
+
+            return createMethodHandleForConstructor(c);
+        }
+
+        /**
+         * Produces a method handle giving read access to a reflected field.
+         * The type of the method handle will have a return type of the field's
+         * value type.
+         * If the field is static, the method handle will take no arguments.
+         * Otherwise, its single argument will be the instance containing
+         * the field.
+         * If the field's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * <p>
+         * If the field is static, and
+         * if the returned method handle is invoked, the field's class will
+         * be initialized, if it has not already been initialized.
+         * @param f the reflected field
+         * @return a method handle which can load values from the reflected field
+         * @throws IllegalAccessException if access checking fails
+         * @throws NullPointerException if the argument is null
+         */
+        public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
+            return findAccessor(f, f.getDeclaringClass(), f.getType(),
+                    Modifier.isStatic(f.getModifiers()) ? MethodHandle.SGET : MethodHandle.IGET,
+                    !f.isAccessible() /* performAccessChecks */);
+        }
+
+        /**
+         * Produces a method handle giving write access to a reflected field.
+         * The type of the method handle will have a void return type.
+         * If the field is static, the method handle will take a single
+         * argument, of the field's value type, the value to be stored.
+         * Otherwise, the two arguments will be the instance containing
+         * the field, and the value to be stored.
+         * If the field's {@code accessible} flag is not set,
+         * access checking is performed immediately on behalf of the lookup class.
+         * <p>
+         * If the field is static, and
+         * if the returned method handle is invoked, the field's class will
+         * be initialized, if it has not already been initialized.
+         * @param f the reflected field
+         * @return a method handle which can store values into the reflected field
+         * @throws IllegalAccessException if access checking fails
+         * @throws NullPointerException if the argument is null
+         */
+        public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
+            return findAccessor(f, f.getDeclaringClass(), f.getType(),
+                    Modifier.isStatic(f.getModifiers()) ? MethodHandle.SPUT : MethodHandle.IPUT,
+                    !f.isAccessible() /* performAccessChecks */);
+        }
+
+        // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory method.
+        /**
+         * Produces a VarHandle giving access to a reflected field {@code f}
+         * of type {@code T} declared in a class of type {@code R}.
+         * The VarHandle's variable type is {@code T}.
+         * If the field is non-static the VarHandle has one coordinate type,
+         * {@code R}.  Otherwise, the field is static, and the VarHandle has no
+         * coordinate types.
+         * <p>
+         * Access checking is performed immediately on behalf of the lookup
+         * class, regardless of the value of the field's {@code accessible}
+         * flag.
+         * <p>
+         * If the field is static, and if the returned VarHandle is operated
+         * on, the field's declaring class will be initialized, if it has not
+         * already been initialized.
+         * <p>
+         * Certain access modes of the returned VarHandle are unsupported under
+         * the following conditions:
+         * <ul>
+         * <li>if the field is declared {@code final}, then the write, atomic
+         *     update, numeric atomic update, and bitwise atomic update access
+         *     modes are unsupported.
+         * <li>if the field type is anything other than {@code byte},
+         *     {@code short}, {@code char}, {@code int}, {@code long},
+         *     {@code float}, or {@code double} then numeric atomic update
+         *     access modes are unsupported.
+         * <li>if the field type is anything other than {@code boolean},
+         *     {@code byte}, {@code short}, {@code char}, {@code int} or
+         *     {@code long} then bitwise atomic update access modes are
+         *     unsupported.
+         * </ul>
+         * <p>
+         * If the field is declared {@code volatile} then the returned VarHandle
+         * will override access to the field (effectively ignore the
+         * {@code volatile} declaration) in accordance to its specified
+         * access modes.
+         * <p>
+         * If the field type is {@code float} or {@code double} then numeric
+         * and atomic update access modes compare values using their bitwise
+         * representation (see {@link Float#floatToRawIntBits} and
+         * {@link Double#doubleToRawLongBits}, respectively).
+         * @apiNote
+         * Bitwise comparison of {@code float} values or {@code double} values,
+         * as performed by the numeric and atomic update access modes, differ
+         * from the primitive {@code ==} operator and the {@link Float#equals}
+         * and {@link Double#equals} methods, specifically with respect to
+         * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+         * Care should be taken when performing a compare and set or a compare
+         * and exchange operation with such values since the operation may
+         * unexpectedly fail.
+         * There are many possible NaN values that are considered to be
+         * {@code NaN} in Java, although no IEEE 754 floating-point operation
+         * provided by Java can distinguish between them.  Operation failure can
+         * occur if the expected or witness value is a NaN value and it is
+         * transformed (perhaps in a platform specific manner) into another NaN
+         * value, and thus has a different bitwise representation (see
+         * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+         * details).
+         * The values {@code -0.0} and {@code +0.0} have different bitwise
+         * representations but are considered equal when using the primitive
+         * {@code ==} operator.  Operation failure can occur if, for example, a
+         * numeric algorithm computes an expected value to be say {@code -0.0}
+         * and previously computed the witness value to be say {@code +0.0}.
+         * @param f the reflected field, with a field of type {@code T}, and
+         * a declaring class of type {@code R}
+         * @return a VarHandle giving access to non-static fields or a static
+         * field
+         * @throws IllegalAccessException if access checking fails
+         * @throws NullPointerException if the argument is null
+         * @since 9
+         * @hide
+         */
+        public VarHandle unreflectVarHandle(Field f) throws IllegalAccessException {
+            final boolean isStatic = Modifier.isStatic(f.getModifiers());
+            final boolean performAccessChecks = true;
+            commonFieldChecks(f, f.getDeclaringClass(), f.getType(), isStatic, performAccessChecks);
+            return FieldVarHandle.create(f);
+        }
+        // END Android-changed: OpenJDK 9+181 VarHandle API factory method.
+
+        /**
+         * Cracks a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
+         * created by this lookup object or a similar one.
+         * Security and access checks are performed to ensure that this lookup object
+         * is capable of reproducing the target method handle.
+         * This means that the cracking may fail if target is a direct method handle
+         * but was created by an unrelated lookup object.
+         * This can happen if the method handle is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>
+         * and was created by a lookup object for a different class.
+         * @param target a direct method handle to crack into symbolic reference components
+         * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+         * @exception NullPointerException if the target is {@code null}
+         * @see MethodHandleInfo
+         * @since 1.8
+         */
+        public MethodHandleInfo revealDirect(MethodHandle target) {
+            MethodHandleImpl directTarget = getMethodHandleImpl(target);
+            MethodHandleInfo info = directTarget.reveal();
+
+            try {
+                checkAccess(lookupClass(), info.getDeclaringClass(), info.getModifiers(),
+                        info.getName());
+            } catch (IllegalAccessException exception) {
+                throw new IllegalArgumentException("Unable to access memeber.", exception);
+            }
+
+            return info;
+        }
+
+        private boolean hasPrivateAccess() {
+            return (allowedModes & PRIVATE) != 0;
+        }
+
+        /** Check public/protected/private bits on the symbolic reference class and its member. */
+        void checkAccess(Class<?> refc, Class<?> defc, int mods, String methName)
+                throws IllegalAccessException {
+            int allowedModes = this.allowedModes;
+
+            if (Modifier.isProtected(mods) &&
+                    defc == Object.class &&
+                    "clone".equals(methName) &&
+                    refc.isArray()) {
+                // The JVM does this hack also.
+                // (See ClassVerifier::verify_invoke_instructions
+                // and LinkResolver::check_method_accessability.)
+                // Because the JVM does not allow separate methods on array types,
+                // there is no separate method for int[].clone.
+                // All arrays simply inherit Object.clone.
+                // But for access checking logic, we make Object.clone
+                // (normally protected) appear to be public.
+                // Later on, when the DirectMethodHandle is created,
+                // its leading argument will be restricted to the
+                // requested array type.
+                // N.B. The return type is not adjusted, because
+                // that is *not* the bytecode behavior.
+                mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
+            }
+
+            if (Modifier.isProtected(mods) && Modifier.isConstructor(mods)) {
+                // cannot "new" a protected ctor in a different package
+                mods ^= Modifier.PROTECTED;
+            }
+
+            if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
+                return;  // common case
+            int requestedModes = fixmods(mods);  // adjust 0 => PACKAGE
+            if ((requestedModes & allowedModes) != 0) {
+                if (VerifyAccess.isMemberAccessible(refc, defc, mods, lookupClass(), allowedModes))
+                    return;
+            } else {
+                // Protected members can also be checked as if they were package-private.
+                if ((requestedModes & PROTECTED) != 0 && (allowedModes & PACKAGE) != 0
+                        && VerifyAccess.isSamePackage(defc, lookupClass()))
+                    return;
+            }
+
+            throwMakeAccessException(accessFailedMessage(refc, defc, mods), this);
+        }
+
+        String accessFailedMessage(Class<?> refc, Class<?> defc, int mods) {
+            // check the class first:
+            boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
+                    (defc == refc ||
+                            Modifier.isPublic(refc.getModifiers())));
+            if (!classOK && (allowedModes & PACKAGE) != 0) {
+                classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
+                        (defc == refc ||
+                                VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
+            }
+            if (!classOK)
+                return "class is not public";
+            if (Modifier.isPublic(mods))
+                return "access to public member failed";  // (how?)
+            if (Modifier.isPrivate(mods))
+                return "member is private";
+            if (Modifier.isProtected(mods))
+                return "member is protected";
+            return "member is private to package";
+        }
+
+        // Android-changed: checkSpecialCaller assumes that ALLOW_NESTMATE_ACCESS = false,
+        // as in upstream OpenJDK.
+        //
+        // private static final boolean ALLOW_NESTMATE_ACCESS = false;
+
+        // Android-changed: Match java language 9 behavior allowing special access if the reflected
+        // class (called 'refc', the class from which the method is being accessed) is an interface
+        // and is implemented by the caller.
+        private void checkSpecialCaller(Class<?> specialCaller, Class<?> refc) throws IllegalAccessException {
+            // Android-changed: No support for TRUSTED lookups. Also construct the
+            // IllegalAccessException by hand because the upstream code implicitly assumes
+            // that the lookupClass == specialCaller.
+            //
+            // if (allowedModes == TRUSTED)  return;
+            boolean isInterfaceLookup = (refc != null &&
+                                         refc.isInterface() &&
+                                         refc.isAssignableFrom(specialCaller));
+            if (!hasPrivateAccess() || (specialCaller != lookupClass() && !isInterfaceLookup)) {
+                throw new IllegalAccessException("no private access for invokespecial : "
+                        + specialCaller + ", from" + this);
+            }
+        }
+
+        private void throwMakeAccessException(String message, Object from) throws
+                IllegalAccessException{
+            message = message + ": "+ toString();
+            if (from != null)  message += ", from " + from;
+            throw new IllegalAccessException(message);
+        }
+
+        private void checkReturnType(Method method, MethodType methodType)
+                throws NoSuchMethodException {
+            if (method.getReturnType() != methodType.rtype()) {
+                throw new NoSuchMethodException(method.getName() + methodType);
+            }
+        }
+    }
+
+    /**
+     * "Cracks" {@code target} to reveal the underlying {@code MethodHandleImpl}.
+     */
+    private static MethodHandleImpl getMethodHandleImpl(MethodHandle target) {
+        // Special case : We implement handles to constructors as transformers,
+        // so we must extract the underlying handle from the transformer.
+        if (target instanceof Transformers.Construct) {
+            target = ((Transformers.Construct) target).getConstructorHandle();
+        }
+
+        // Special case: Var-args methods are also implemented as Transformers,
+        // so we should get the underlying handle in that case as well.
+        if (target instanceof Transformers.VarargsCollector) {
+            target = target.asFixedArity();
+        }
+
+        if (target instanceof MethodHandleImpl) {
+            return (MethodHandleImpl) target;
+        }
+
+        throw new IllegalArgumentException(target + " is not a direct handle");
+    }
+
+    // BEGIN Android-added: method to check if a class is an array.
+    private static void checkClassIsArray(Class<?> c) {
+        if (!c.isArray()) {
+            throw new IllegalArgumentException("Not an array type: " + c);
+        }
+    }
+
+    private static void checkTypeIsViewable(Class<?> componentType) {
+        if (componentType == short.class ||
+            componentType == char.class ||
+            componentType == int.class ||
+            componentType == long.class ||
+            componentType == float.class ||
+            componentType == double.class) {
+            return;
+        }
+        throw new UnsupportedOperationException("Component type not supported: " + componentType);
+    }
+    // END Android-added: method to check if a class is an array.
+
+    /**
+     * Produces a method handle giving read access to elements of an array.
+     * The type of the method handle will have a return type of the array's
+     * element type.  Its first argument will be the array type,
+     * and the second will be {@code int}.
+     * @param arrayClass an array type
+     * @return a method handle which can load values from the given array type
+     * @throws NullPointerException if the argument is null
+     * @throws  IllegalArgumentException if arrayClass is not an array type
+     */
+    public static
+    MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
+        checkClassIsArray(arrayClass);
+        final Class<?> componentType = arrayClass.getComponentType();
+        if (componentType.isPrimitive()) {
+            try {
+                return Lookup.PUBLIC_LOOKUP.findStatic(MethodHandles.class,
+                        "arrayElementGetter",
+                        MethodType.methodType(componentType, arrayClass, int.class));
+            } catch (NoSuchMethodException | IllegalAccessException exception) {
+                throw new AssertionError(exception);
+            }
+        }
+
+        return new Transformers.ReferenceArrayElementGetter(arrayClass);
+    }
+
+    /** @hide */ public static byte arrayElementGetter(byte[] array, int i) { return array[i]; }
+    /** @hide */ public static boolean arrayElementGetter(boolean[] array, int i) { return array[i]; }
+    /** @hide */ public static char arrayElementGetter(char[] array, int i) { return array[i]; }
+    /** @hide */ public static short arrayElementGetter(short[] array, int i) { return array[i]; }
+    /** @hide */ public static int arrayElementGetter(int[] array, int i) { return array[i]; }
+    /** @hide */ public static long arrayElementGetter(long[] array, int i) { return array[i]; }
+    /** @hide */ public static float arrayElementGetter(float[] array, int i) { return array[i]; }
+    /** @hide */ public static double arrayElementGetter(double[] array, int i) { return array[i]; }
+
+    /**
+     * Produces a method handle giving write access to elements of an array.
+     * The type of the method handle will have a void return type.
+     * Its last argument will be the array's element type.
+     * The first and second arguments will be the array type and int.
+     * @param arrayClass the class of an array
+     * @return a method handle which can store values into the array type
+     * @throws NullPointerException if the argument is null
+     * @throws IllegalArgumentException if arrayClass is not an array type
+     */
+    public static
+    MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
+        checkClassIsArray(arrayClass);
+        final Class<?> componentType = arrayClass.getComponentType();
+        if (componentType.isPrimitive()) {
+            try {
+                return Lookup.PUBLIC_LOOKUP.findStatic(MethodHandles.class,
+                        "arrayElementSetter",
+                        MethodType.methodType(void.class, arrayClass, int.class, componentType));
+            } catch (NoSuchMethodException | IllegalAccessException exception) {
+                throw new AssertionError(exception);
+            }
+        }
+
+        return new Transformers.ReferenceArrayElementSetter(arrayClass);
+    }
+
+    /** @hide */
+    public static void arrayElementSetter(byte[] array, int i, byte val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(boolean[] array, int i, boolean val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(char[] array, int i, char val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(short[] array, int i, short val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(int[] array, int i, int val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(long[] array, int i, long val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(float[] array, int i, float val) { array[i] = val; }
+    /** @hide */
+    public static void arrayElementSetter(double[] array, int i, double val) { array[i] = val; }
+
+    // BEGIN Android-changed: OpenJDK 9+181 VarHandle API factory methods.
+    /**
+     * Produces a VarHandle giving access to elements of an array of type
+     * {@code arrayClass}.  The VarHandle's variable type is the component type
+     * of {@code arrayClass} and the list of coordinate types is
+     * {@code (arrayClass, int)}, where the {@code int} coordinate type
+     * corresponds to an argument that is an index into an array.
+     * <p>
+     * Certain access modes of the returned VarHandle are unsupported under
+     * the following conditions:
+     * <ul>
+     * <li>if the component type is anything other than {@code byte},
+     *     {@code short}, {@code char}, {@code int}, {@code long},
+     *     {@code float}, or {@code double} then numeric atomic update access
+     *     modes are unsupported.
+     * <li>if the field type is anything other than {@code boolean},
+     *     {@code byte}, {@code short}, {@code char}, {@code int} or
+     *     {@code long} then bitwise atomic update access modes are
+     *     unsupported.
+     * </ul>
+     * <p>
+     * If the component type is {@code float} or {@code double} then numeric
+     * and atomic update access modes compare values using their bitwise
+     * representation (see {@link Float#floatToRawIntBits} and
+     * {@link Double#doubleToRawLongBits}, respectively).
+     * @apiNote
+     * Bitwise comparison of {@code float} values or {@code double} values,
+     * as performed by the numeric and atomic update access modes, differ
+     * from the primitive {@code ==} operator and the {@link Float#equals}
+     * and {@link Double#equals} methods, specifically with respect to
+     * comparing NaN values or comparing {@code -0.0} with {@code +0.0}.
+     * Care should be taken when performing a compare and set or a compare
+     * and exchange operation with such values since the operation may
+     * unexpectedly fail.
+     * There are many possible NaN values that are considered to be
+     * {@code NaN} in Java, although no IEEE 754 floating-point operation
+     * provided by Java can distinguish between them.  Operation failure can
+     * occur if the expected or witness value is a NaN value and it is
+     * transformed (perhaps in a platform specific manner) into another NaN
+     * value, and thus has a different bitwise representation (see
+     * {@link Float#intBitsToFloat} or {@link Double#longBitsToDouble} for more
+     * details).
+     * The values {@code -0.0} and {@code +0.0} have different bitwise
+     * representations but are considered equal when using the primitive
+     * {@code ==} operator.  Operation failure can occur if, for example, a
+     * numeric algorithm computes an expected value to be say {@code -0.0}
+     * and previously computed the witness value to be say {@code +0.0}.
+     * @param arrayClass the class of an array, of type {@code T[]}
+     * @return a VarHandle giving access to elements of an array
+     * @throws NullPointerException if the arrayClass is null
+     * @throws IllegalArgumentException if arrayClass is not an array type
+     * @since 9
+     * @hide
+     */
+    public static
+    VarHandle arrayElementVarHandle(Class<?> arrayClass) throws IllegalArgumentException {
+        checkClassIsArray(arrayClass);
+        return ArrayElementVarHandle.create(arrayClass);
+    }
+
+    /**
+     * Produces a VarHandle giving access to elements of a {@code byte[]} array
+     * viewed as if it were a different primitive array type, such as
+     * {@code int[]} or {@code long[]}.
+     * The VarHandle's variable type is the component type of
+     * {@code viewArrayClass} and the list of coordinate types is
+     * {@code (byte[], int)}, where the {@code int} coordinate type
+     * corresponds to an argument that is an index into a {@code byte[]} array.
+     * The returned VarHandle accesses bytes at an index in a {@code byte[]}
+     * array, composing bytes to or from a value of the component type of
+     * {@code viewArrayClass} according to the given endianness.
+     * <p>
+     * The supported component types (variables types) are {@code short},
+     * {@code char}, {@code int}, {@code long}, {@code float} and
+     * {@code double}.
+     * <p>
+     * Access of bytes at a given index will result in an
+     * {@code IndexOutOfBoundsException} if the index is less than {@code 0}
+     * or greater than the {@code byte[]} array length minus the size (in bytes)
+     * of {@code T}.
+     * <p>
+     * Access of bytes at an index may be aligned or misaligned for {@code T},
+     * with respect to the underlying memory address, {@code A} say, associated
+     * with the array and index.
+     * If access is misaligned then access for anything other than the
+     * {@code get} and {@code set} access modes will result in an
+     * {@code IllegalStateException}.  In such cases atomic access is only
+     * guaranteed with respect to the largest power of two that divides the GCD
+     * of {@code A} and the size (in bytes) of {@code T}.
+     * If access is aligned then following access modes are supported and are
+     * guaranteed to support atomic access:
+     * <ul>
+     * <li>read write access modes for all {@code T}, with the exception of
+     *     access modes {@code get} and {@code set} for {@code long} and
+     *     {@code double} on 32-bit platforms.
+     * <li>atomic update access modes for {@code int}, {@code long},
+     *     {@code float} or {@code double}.
+     *     (Future major platform releases of the JDK may support additional
+     *     types for certain currently unsupported access modes.)
+     * <li>numeric atomic update access modes for {@code int} and {@code long}.
+     *     (Future major platform releases of the JDK may support additional
+     *     numeric types for certain currently unsupported access modes.)
+     * <li>bitwise atomic update access modes for {@code int} and {@code long}.
+     *     (Future major platform releases of the JDK may support additional
+     *     numeric types for certain currently unsupported access modes.)
+     * </ul>
+     * <p>
+     * Misaligned access, and therefore atomicity guarantees, may be determined
+     * for {@code byte[]} arrays without operating on a specific array.  Given
+     * an {@code index}, {@code T} and it's corresponding boxed type,
+     * {@code T_BOX}, misalignment may be determined as follows:
+     * <pre>{@code
+     * int sizeOfT = T_BOX.BYTES;  // size in bytes of T
+     * int misalignedAtZeroIndex = ByteBuffer.wrap(new byte[0]).
+     *     alignmentOffset(0, sizeOfT);
+     * int misalignedAtIndex = (misalignedAtZeroIndex + index) % sizeOfT;
+     * boolean isMisaligned = misalignedAtIndex != 0;
+     * }</pre>
+     * <p>
+     * If the variable type is {@code float} or {@code double} then atomic
+     * update access modes compare values using their bitwise representation
+     * (see {@link Float#floatToRawIntBits} and
+     * {@link Double#doubleToRawLongBits}, respectively).
+     * @param viewArrayClass the view array class, with a component type of
+     * type {@code T}
+     * @param byteOrder the endianness of the view array elements, as
+     * stored in the underlying {@code byte} array
+     * @return a VarHandle giving access to elements of a {@code byte[]} array
+     * viewed as if elements corresponding to the components type of the view
+     * array class
+     * @throws NullPointerException if viewArrayClass or byteOrder is null
+     * @throws IllegalArgumentException if viewArrayClass is not an array type
+     * @throws UnsupportedOperationException if the component type of
+     * viewArrayClass is not supported as a variable type
+     * @since 9
+     * @hide
+     */
+    public static
+    VarHandle byteArrayViewVarHandle(Class<?> viewArrayClass,
+                                     ByteOrder byteOrder) throws IllegalArgumentException {
+        checkClassIsArray(viewArrayClass);
+        checkTypeIsViewable(viewArrayClass.getComponentType());
+        return ByteArrayViewVarHandle.create(viewArrayClass, byteOrder);
+    }
+
+    /**
+     * Produces a VarHandle giving access to elements of a {@code ByteBuffer}
+     * viewed as if it were an array of elements of a different primitive
+     * component type to that of {@code byte}, such as {@code int[]} or
+     * {@code long[]}.
+     * The VarHandle's variable type is the component type of
+     * {@code viewArrayClass} and the list of coordinate types is
+     * {@code (ByteBuffer, int)}, where the {@code int} coordinate type
+     * corresponds to an argument that is an index into a {@code byte[]} array.
+     * The returned VarHandle accesses bytes at an index in a
+     * {@code ByteBuffer}, composing bytes to or from a value of the component
+     * type of {@code viewArrayClass} according to the given endianness.
+     * <p>
+     * The supported component types (variables types) are {@code short},
+     * {@code char}, {@code int}, {@code long}, {@code float} and
+     * {@code double}.
+     * <p>
+     * Access will result in a {@code ReadOnlyBufferException} for anything
+     * other than the read access modes if the {@code ByteBuffer} is read-only.
+     * <p>
+     * Access of bytes at a given index will result in an
+     * {@code IndexOutOfBoundsException} if the index is less than {@code 0}
+     * or greater than the {@code ByteBuffer} limit minus the size (in bytes) of
+     * {@code T}.
+     * <p>
+     * Access of bytes at an index may be aligned or misaligned for {@code T},
+     * with respect to the underlying memory address, {@code A} say, associated
+     * with the {@code ByteBuffer} and index.
+     * If access is misaligned then access for anything other than the
+     * {@code get} and {@code set} access modes will result in an
+     * {@code IllegalStateException}.  In such cases atomic access is only
+     * guaranteed with respect to the largest power of two that divides the GCD
+     * of {@code A} and the size (in bytes) of {@code T}.
+     * If access is aligned then following access modes are supported and are
+     * guaranteed to support atomic access:
+     * <ul>
+     * <li>read write access modes for all {@code T}, with the exception of
+     *     access modes {@code get} and {@code set} for {@code long} and
+     *     {@code double} on 32-bit platforms.
+     * <li>atomic update access modes for {@code int}, {@code long},
+     *     {@code float} or {@code double}.
+     *     (Future major platform releases of the JDK may support additional
+     *     types for certain currently unsupported access modes.)
+     * <li>numeric atomic update access modes for {@code int} and {@code long}.
+     *     (Future major platform releases of the JDK may support additional
+     *     numeric types for certain currently unsupported access modes.)
+     * <li>bitwise atomic update access modes for {@code int} and {@code long}.
+     *     (Future major platform releases of the JDK may support additional
+     *     numeric types for certain currently unsupported access modes.)
+     * </ul>
+     * <p>
+     * Misaligned access, and therefore atomicity guarantees, may be determined
+     * for a {@code ByteBuffer}, {@code bb} (direct or otherwise), an
+     * {@code index}, {@code T} and it's corresponding boxed type,
+     * {@code T_BOX}, as follows:
+     * <pre>{@code
+     * int sizeOfT = T_BOX.BYTES;  // size in bytes of T
+     * ByteBuffer bb = ...
+     * int misalignedAtIndex = bb.alignmentOffset(index, sizeOfT);
+     * boolean isMisaligned = misalignedAtIndex != 0;
+     * }</pre>
+     * <p>
+     * If the variable type is {@code float} or {@code double} then atomic
+     * update access modes compare values using their bitwise representation
+     * (see {@link Float#floatToRawIntBits} and
+     * {@link Double#doubleToRawLongBits}, respectively).
+     * @param viewArrayClass the view array class, with a component type of
+     * type {@code T}
+     * @param byteOrder the endianness of the view array elements, as
+     * stored in the underlying {@code ByteBuffer} (Note this overrides the
+     * endianness of a {@code ByteBuffer})
+     * @return a VarHandle giving access to elements of a {@code ByteBuffer}
+     * viewed as if elements corresponding to the components type of the view
+     * array class
+     * @throws NullPointerException if viewArrayClass or byteOrder is null
+     * @throws IllegalArgumentException if viewArrayClass is not an array type
+     * @throws UnsupportedOperationException if the component type of
+     * viewArrayClass is not supported as a variable type
+     * @since 9
+     * @hide
+     */
+    public static
+    VarHandle byteBufferViewVarHandle(Class<?> viewArrayClass,
+                                      ByteOrder byteOrder) throws IllegalArgumentException {
+        checkClassIsArray(viewArrayClass);
+        checkTypeIsViewable(viewArrayClass.getComponentType());
+        return ByteBufferViewVarHandle.create(viewArrayClass, byteOrder);
+    }
+    // END Android-changed: OpenJDK 9+181 VarHandle API factory methods.
+
+    /// method handle invocation (reflective style)
+
+    /**
+     * Produces a method handle which will invoke any method handle of the
+     * given {@code type}, with a given number of trailing arguments replaced by
+     * a single trailing {@code Object[]} array.
+     * The resulting invoker will be a method handle with the following
+     * arguments:
+     * <ul>
+     * <li>a single {@code MethodHandle} target
+     * <li>zero or more leading values (counted by {@code leadingArgCount})
+     * <li>an {@code Object[]} array containing trailing arguments
+     * </ul>
+     * <p>
+     * The invoker will invoke its target like a call to {@link MethodHandle#invoke invoke} with
+     * the indicated {@code type}.
+     * That is, if the target is exactly of the given {@code type}, it will behave
+     * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
+     * is used to convert the target to the required {@code type}.
+     * <p>
+     * The type of the returned invoker will not be the given {@code type}, but rather
+     * will have all parameters except the first {@code leadingArgCount}
+     * replaced by a single array of type {@code Object[]}, which will be
+     * the final parameter.
+     * <p>
+     * Before invoking its target, the invoker will spread the final array, apply
+     * reference casts as necessary, and unbox and widen primitive arguments.
+     * If, when the invoker is called, the supplied array argument does
+     * not have the correct number of elements, the invoker will throw
+     * an {@link IllegalArgumentException} instead of invoking the target.
+     * <p>
+     * This method is equivalent to the following code (though it may be more efficient):
+     * <blockquote><pre>{@code
+MethodHandle invoker = MethodHandles.invoker(type);
+int spreadArgCount = type.parameterCount() - leadingArgCount;
+invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+return invoker;
+     * }</pre></blockquote>
+     * This method throws no reflective or security exceptions.
+     * @param type the desired target type
+     * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
+     * @return a method handle suitable for invoking any method handle of the given type
+     * @throws NullPointerException if {@code type} is null
+     * @throws IllegalArgumentException if {@code leadingArgCount} is not in
+     *                  the range from 0 to {@code type.parameterCount()} inclusive,
+     *                  or if the resulting method handle's type would have
+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
+     */
+    static public
+    MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
+        if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
+            throw newIllegalArgumentException("bad argument count", leadingArgCount);
+
+        MethodHandle invoker = MethodHandles.invoker(type);
+        int spreadArgCount = type.parameterCount() - leadingArgCount;
+        invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+        return invoker;
+    }
+
+    /**
+     * Produces a special <em>invoker method handle</em> which can be used to
+     * invoke any method handle of the given type, as if by {@link MethodHandle#invokeExact invokeExact}.
+     * The resulting invoker will have a type which is
+     * exactly equal to the desired type, except that it will accept
+     * an additional leading argument of type {@code MethodHandle}.
+     * <p>
+     * This method is equivalent to the following code (though it may be more efficient):
+     * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)}
+     *
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * Invoker method handles can be useful when working with variable method handles
+     * of unknown types.
+     * For example, to emulate an {@code invokeExact} call to a variable method
+     * handle {@code M}, extract its type {@code T},
+     * look up the invoker method {@code X} for {@code T},
+     * and call the invoker method, as {@code X.invoke(T, A...)}.
+     * (It would not work to call {@code X.invokeExact}, since the type {@code T}
+     * is unknown.)
+     * If spreading, collecting, or other argument transformations are required,
+     * they can be applied once to the invoker {@code X} and reused on many {@code M}
+     * method handle values, as long as they are compatible with the type of {@code X}.
+     * <p style="font-size:smaller;">
+     * <em>(Note:  The invoker method is not available via the Core Reflection API.
+     * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+     * on the declared {@code invokeExact} or {@code invoke} method will raise an
+     * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+     * <p>
+     * This method throws no reflective or security exceptions.
+     * @param type the desired target type
+     * @return a method handle suitable for invoking any method handle of the given type
+     * @throws IllegalArgumentException if the resulting method handle's type would have
+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
+     */
+    static public
+    MethodHandle exactInvoker(MethodType type) {
+        return new Transformers.Invoker(type, true /* isExactInvoker */);
+    }
+
+    /**
+     * Produces a special <em>invoker method handle</em> which can be used to
+     * invoke any method handle compatible with the given type, as if by {@link MethodHandle#invoke invoke}.
+     * The resulting invoker will have a type which is
+     * exactly equal to the desired type, except that it will accept
+     * an additional leading argument of type {@code MethodHandle}.
+     * <p>
+     * Before invoking its target, if the target differs from the expected type,
+     * the invoker will apply reference casts as
+     * necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}.
+     * Similarly, the return value will be converted as necessary.
+     * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
+     * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
+     * <p>
+     * This method is equivalent to the following code (though it may be more efficient):
+     * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)}
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * A {@linkplain MethodType#genericMethodType general method type} is one which
+     * mentions only {@code Object} arguments and return values.
+     * An invoker for such a type is capable of calling any method handle
+     * of the same arity as the general type.
+     * <p style="font-size:smaller;">
+     * <em>(Note:  The invoker method is not available via the Core Reflection API.
+     * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+     * on the declared {@code invokeExact} or {@code invoke} method will raise an
+     * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+     * <p>
+     * This method throws no reflective or security exceptions.
+     * @param type the desired target type
+     * @return a method handle suitable for invoking any method handle convertible to the given type
+     * @throws IllegalArgumentException if the resulting method handle's type would have
+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
+     */
+    static public
+    MethodHandle invoker(MethodType type) {
+        return new Transformers.Invoker(type, false /* isExactInvoker */);
+    }
+
+    // BEGIN Android-added: resolver for VarHandle accessor methods.
+    static private MethodHandle methodHandleForVarHandleAccessor(VarHandle.AccessMode accessMode,
+                                                                 MethodType type,
+                                                                 boolean isExactInvoker) {
+        Class<?> refc = VarHandle.class;
+        Method method;
+        try {
+            method = refc.getDeclaredMethod(accessMode.methodName(), Object[].class);
+        } catch (NoSuchMethodException e) {
+            throw new InternalError("No method for AccessMode " + accessMode, e);
+        }
+        MethodType methodType = type.insertParameterTypes(0, VarHandle.class);
+        int kind = isExactInvoker ? MethodHandle.INVOKE_VAR_HANDLE_EXACT
+                                  : MethodHandle.INVOKE_VAR_HANDLE;
+        return new MethodHandleImpl(method.getArtMethod(), kind, methodType);
+    }
+    // END Android-added: resolver for VarHandle accessor methods.
+
+    /**
+     * Produces a special <em>invoker method handle</em> which can be used to
+     * invoke a signature-polymorphic access mode method on any VarHandle whose
+     * associated access mode type is compatible with the given type.
+     * The resulting invoker will have a type which is exactly equal to the
+     * desired given type, except that it will accept an additional leading
+     * argument of type {@code VarHandle}.
+     *
+     * @param accessMode the VarHandle access mode
+     * @param type the desired target type
+     * @return a method handle suitable for invoking an access mode method of
+     *         any VarHandle whose access mode type is of the given type.
+     * @since 9
+     * @hide
+     */
+    static public
+    MethodHandle varHandleExactInvoker(VarHandle.AccessMode accessMode, MethodType type) {
+        return methodHandleForVarHandleAccessor(accessMode, type, true /* isExactInvoker */);
+    }
+
+    /**
+     * Produces a special <em>invoker method handle</em> which can be used to
+     * invoke a signature-polymorphic access mode method on any VarHandle whose
+     * associated access mode type is compatible with the given type.
+     * The resulting invoker will have a type which is exactly equal to the
+     * desired given type, except that it will accept an additional leading
+     * argument of type {@code VarHandle}.
+     * <p>
+     * Before invoking its target, if the access mode type differs from the
+     * desired given type, the invoker will apply reference casts as necessary
+     * and box, unbox, or widen primitive values, as if by
+     * {@link MethodHandle#asType asType}.  Similarly, the return value will be
+     * converted as necessary.
+     * <p>
+     * This method is equivalent to the following code (though it may be more
+     * efficient): {@code publicLookup().findVirtual(VarHandle.class, accessMode.name(), type)}
+     *
+     * @param accessMode the VarHandle access mode
+     * @param type the desired target type
+     * @return a method handle suitable for invoking an access mode method of
+     *         any VarHandle whose access mode type is convertible to the given
+     *         type.
+     * @since 9
+     * @hide
+     */
+    static public
+    MethodHandle varHandleInvoker(VarHandle.AccessMode accessMode, MethodType type) {
+        return methodHandleForVarHandleAccessor(accessMode, type, false /* isExactInvoker */);
+    }
+
+    // Android-changed: Basic invokers are not supported.
+    //
+    // static /*non-public*/
+    // MethodHandle basicInvoker(MethodType type) {
+    //     return type.invokers().basicInvoker();
+    // }
+
+     /// method handle modification (creation from other method handles)
+
+    /**
+     * Produces a method handle which adapts the type of the
+     * given method handle to a new type by pairwise argument and return type conversion.
+     * The original type and new type must have the same number of arguments.
+     * The resulting method handle is guaranteed to report a type
+     * which is equal to the desired new type.
+     * <p>
+     * If the original type and new type are equal, returns target.
+     * <p>
+     * The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType},
+     * and some additional conversions are also applied if those conversions fail.
+     * Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied
+     * if possible, before or instead of any conversions done by {@code asType}:
+     * <ul>
+     * <li>If <em>T0</em> and <em>T1</em> are references, and <em>T1</em> is an interface type,
+     *     then the value of type <em>T0</em> is passed as a <em>T1</em> without a cast.
+     *     (This treatment of interfaces follows the usage of the bytecode verifier.)
+     * <li>If <em>T0</em> is boolean and <em>T1</em> is another primitive,
+     *     the boolean is converted to a byte value, 1 for true, 0 for false.
+     *     (This treatment follows the usage of the bytecode verifier.)
+     * <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive,
+     *     <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5),
+     *     and the low order bit of the result is tested, as if by {@code (x & 1) != 0}.
+     * <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean,
+     *     then a Java casting conversion (JLS 5.5) is applied.
+     *     (Specifically, <em>T0</em> will convert to <em>T1</em> by
+     *     widening and/or narrowing.)
+     * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+     *     conversion will be applied at runtime, possibly followed
+     *     by a Java casting conversion (JLS 5.5) on the primitive value,
+     *     possibly followed by a conversion from byte to boolean by testing
+     *     the low-order bit.
+     * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive,
+     *     and if the reference is null at runtime, a zero value is introduced.
+     * </ul>
+     * @param target the method handle to invoke after arguments are retyped
+     * @param newType the expected type of the new method handle
+     * @return a method handle which delegates to the target after performing
+     *           any necessary argument conversions, and arranges for any
+     *           necessary return value conversions
+     * @throws NullPointerException if either argument is null
+     * @throws WrongMethodTypeException if the conversion cannot be made
+     * @see MethodHandle#asType
+     */
+    public static
+    MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
+        explicitCastArgumentsChecks(target, newType);
+        // use the asTypeCache when possible:
+        MethodType oldType = target.type();
+        if (oldType == newType) return target;
+        if (oldType.explicitCastEquivalentToAsType(newType)) {
+            if (Transformers.Transformer.class.isAssignableFrom(target.getClass())) {
+                // The StackFrameReader and StackFrameWriter used to perform transforms on
+                // EmulatedStackFrames (in Transformers.java) do not how to perform asType()
+                // conversions, but we know here that an explicit cast transform is the same as
+                // having called asType() on the method handle.
+                return new Transformers.ExplicitCastArguments(target.asFixedArity(), newType);
+            } else {
+                // Runtime will perform asType() conversion during invocation.
+                return target.asFixedArity().asType(newType);
+            }
+        }
+        return new Transformers.ExplicitCastArguments(target, newType);
+    }
+
+    private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) {
+        if (target.type().parameterCount() != newType.parameterCount()) {
+            throw new WrongMethodTypeException("cannot explicitly cast " + target +
+                                               " to " + newType);
+        }
+    }
+
+    /**
+     * Produces a method handle which adapts the calling sequence of the
+     * given method handle to a new type, by reordering the arguments.
+     * The resulting method handle is guaranteed to report a type
+     * which is equal to the desired new type.
+     * <p>
+     * The given array controls the reordering.
+     * Call {@code #I} the number of incoming parameters (the value
+     * {@code newType.parameterCount()}, and call {@code #O} the number
+     * of outgoing parameters (the value {@code target.type().parameterCount()}).
+     * Then the length of the reordering array must be {@code #O},
+     * and each element must be a non-negative number less than {@code #I}.
+     * For every {@code N} less than {@code #O}, the {@code N}-th
+     * outgoing argument will be taken from the {@code I}-th incoming
+     * argument, where {@code I} is {@code reorder[N]}.
+     * <p>
+     * No argument or return value conversions are applied.
+     * The type of each incoming argument, as determined by {@code newType},
+     * must be identical to the type of the corresponding outgoing parameter
+     * or parameters in the target method handle.
+     * The return type of {@code newType} must be identical to the return
+     * type of the original target.
+     * <p>
+     * The reordering array need not specify an actual permutation.
+     * An incoming argument will be duplicated if its index appears
+     * more than once in the array, and an incoming argument will be dropped
+     * if its index does not appear in the array.
+     * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
+     * incoming arguments which are not mentioned in the reordering array
+     * are may be any type, as determined only by {@code newType}.
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodType intfn1 = methodType(int.class, int.class);
+MethodType intfn2 = methodType(int.class, int.class, int.class);
+MethodHandle sub = ... (int x, int y) -> (x-y) ...;
+assert(sub.type().equals(intfn2));
+MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
+assert((int)rsub.invokeExact(1, 100) == 99);
+MethodHandle add = ... (int x, int y) -> (x+y) ...;
+assert(add.type().equals(intfn2));
+MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
+assert(twice.type().equals(intfn1));
+assert((int)twice.invokeExact(21) == 42);
+     * }</pre></blockquote>
+     * @param target the method handle to invoke after arguments are reordered
+     * @param newType the expected type of the new method handle
+     * @param reorder an index array which controls the reordering
+     * @return a method handle which delegates to the target after it
+     *           drops unused arguments and moves and/or duplicates the other arguments
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if the index array length is not equal to
+     *                  the arity of the target, or if any index array element
+     *                  not a valid index for a parameter of {@code newType},
+     *                  or if two corresponding parameter types in
+     *                  {@code target.type()} and {@code newType} are not identical,
+     */
+    public static
+    MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
+        reorder = reorder.clone();  // get a private copy
+        MethodType oldType = target.type();
+        permuteArgumentChecks(reorder, newType, oldType);
+
+        return new Transformers.PermuteArguments(newType, target, reorder);
+    }
+
+    // Android-changed: findFirstDupOrDrop is unused and removed.
+    // private static int findFirstDupOrDrop(int[] reorder, int newArity);
+
+    private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) {
+        if (newType.returnType() != oldType.returnType())
+            throw newIllegalArgumentException("return types do not match",
+                    oldType, newType);
+        if (reorder.length == oldType.parameterCount()) {
+            int limit = newType.parameterCount();
+            boolean bad = false;
+            for (int j = 0; j < reorder.length; j++) {
+                int i = reorder[j];
+                if (i < 0 || i >= limit) {
+                    bad = true; break;
+                }
+                Class<?> src = newType.parameterType(i);
+                Class<?> dst = oldType.parameterType(j);
+                if (src != dst)
+                    throw newIllegalArgumentException("parameter types do not match after reorder",
+                            oldType, newType);
+            }
+            if (!bad)  return true;
+        }
+        throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
+    }
+
+    /**
+     * Produces a method handle of the requested return type which returns the given
+     * constant value every time it is invoked.
+     * <p>
+     * Before the method handle is returned, the passed-in value is converted to the requested type.
+     * If the requested type is primitive, widening primitive conversions are attempted,
+     * else reference conversions are attempted.
+     * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
+     * @param type the return type of the desired method handle
+     * @param value the value to return
+     * @return a method handle of the given return type and no arguments, which always returns the given value
+     * @throws NullPointerException if the {@code type} argument is null
+     * @throws ClassCastException if the value cannot be converted to the required return type
+     * @throws IllegalArgumentException if the given type is {@code void.class}
+     */
+    public static
+    MethodHandle constant(Class<?> type, Object value) {
+        if (type.isPrimitive()) {
+            if (type == void.class)
+                throw newIllegalArgumentException("void type");
+            Wrapper w = Wrapper.forPrimitiveType(type);
+            value = w.convert(value, type);
+        }
+
+        return new Transformers.Constant(type, value);
+    }
+
+    /**
+     * Produces a method handle which returns its sole argument when invoked.
+     * @param type the type of the sole parameter and return value of the desired method handle
+     * @return a unary method handle which accepts and returns the given type
+     * @throws NullPointerException if the argument is null
+     * @throws IllegalArgumentException if the given type is {@code void.class}
+     */
+    public static
+    MethodHandle identity(Class<?> type) {
+        if (type == null) {
+            throw new NullPointerException("type == null");
+        }
+
+        if (type.isPrimitive()) {
+            try {
+                return Lookup.PUBLIC_LOOKUP.findStatic(MethodHandles.class, "identity",
+                        MethodType.methodType(type, type));
+            } catch (NoSuchMethodException | IllegalAccessException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        return new Transformers.ReferenceIdentity(type);
+    }
+
+    /** @hide */ public static byte identity(byte val) { return val; }
+    /** @hide */ public static boolean identity(boolean val) { return val; }
+    /** @hide */ public static char identity(char val) { return val; }
+    /** @hide */ public static short identity(short val) { return val; }
+    /** @hide */ public static int identity(int val) { return val; }
+    /** @hide */ public static long identity(long val) { return val; }
+    /** @hide */ public static float identity(float val) { return val; }
+    /** @hide */ public static double identity(double val) { return val; }
+
+    /**
+     * Provides a target method handle with one or more <em>bound arguments</em>
+     * in advance of the method handle's invocation.
+     * The formal parameters to the target corresponding to the bound
+     * arguments are called <em>bound parameters</em>.
+     * Returns a new method handle which saves away the bound arguments.
+     * When it is invoked, it receives arguments for any non-bound parameters,
+     * binds the saved arguments to their corresponding parameters,
+     * and calls the original target.
+     * <p>
+     * The type of the new method handle will drop the types for the bound
+     * parameters from the original target type, since the new method handle
+     * will no longer require those arguments to be supplied by its callers.
+     * <p>
+     * Each given argument object must match the corresponding bound parameter type.
+     * If a bound parameter type is a primitive, the argument object
+     * must be a wrapper, and will be unboxed to produce the primitive value.
+     * <p>
+     * The {@code pos} argument selects which parameters are to be bound.
+     * It may range between zero and <i>N-L</i> (inclusively),
+     * where <i>N</i> is the arity of the target method handle
+     * and <i>L</i> is the length of the values array.
+     * @param target the method handle to invoke after the argument is inserted
+     * @param pos where to insert the argument (zero for the first)
+     * @param values the series of arguments to insert
+     * @return a method handle which inserts an additional argument,
+     *         before calling the original method handle
+     * @throws NullPointerException if the target or the {@code values} array is null
+     * @see MethodHandle#bindTo
+     */
+    public static
+    MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
+        int insCount = values.length;
+        Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
+        if (insCount == 0)  {
+            return target;
+        }
+
+        // Throw ClassCastExceptions early if we can't cast any of the provided values
+        // to the required type.
+        for (int i = 0; i < insCount; i++) {
+            final Class<?> ptype = ptypes[pos + i];
+            if (!ptype.isPrimitive()) {
+                ptypes[pos + i].cast(values[i]);
+            } else {
+                // Will throw a ClassCastException if something terrible happens.
+                values[i] = Wrapper.forPrimitiveType(ptype).convert(values[i], ptype);
+            }
+        }
+
+        return new Transformers.InsertArguments(target, pos, values);
+    }
+
+    // Android-changed: insertArgumentPrimitive is unused.
+    //
+    // private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
+    //                                                          Class<?> ptype, Object value) {
+    //     Wrapper w = Wrapper.forPrimitiveType(ptype);
+    //     // perform unboxing and/or primitive conversion
+    //     value = w.convert(value, ptype);
+    //     switch (w) {
+    //     case INT:     return result.bindArgumentI(pos, (int)value);
+    //     case LONG:    return result.bindArgumentJ(pos, (long)value);
+    //     case FLOAT:   return result.bindArgumentF(pos, (float)value);
+    //     case DOUBLE:  return result.bindArgumentD(pos, (double)value);
+    //     default:      return result.bindArgumentI(pos, ValueConversions.widenSubword(value));
+    //     }
+    // }
+
+    private static Class<?>[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException {
+        MethodType oldType = target.type();
+        int outargs = oldType.parameterCount();
+        int inargs  = outargs - insCount;
+        if (inargs < 0)
+            throw newIllegalArgumentException("too many values to insert");
+        if (pos < 0 || pos > inargs)
+            throw newIllegalArgumentException("no argument type to append");
+        return oldType.ptypes();
+    }
+
+    /**
+     * Produces a method handle which will discard some dummy arguments
+     * before calling some other specified <i>target</i> method handle.
+     * The type of the new method handle will be the same as the target's type,
+     * except it will also include the dummy argument types,
+     * at some given position.
+     * <p>
+     * The {@code pos} argument may range between zero and <i>N</i>,
+     * where <i>N</i> is the arity of the target.
+     * If {@code pos} is zero, the dummy arguments will precede
+     * the target's real arguments; if {@code pos} is <i>N</i>
+     * they will come after.
+     * <p>
+     * <b>Example:</b>
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
+MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
+assertEquals(bigType, d0.type());
+assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
+     * }</pre></blockquote>
+     * <p>
+     * This method is also equivalent to the following code:
+     * <blockquote><pre>
+     * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))}
+     * </pre></blockquote>
+     * @param target the method handle to invoke after the arguments are dropped
+     * @param valueTypes the type(s) of the argument(s) to drop
+     * @param pos position of first argument to drop (zero for the leftmost)
+     * @return a method handle which drops arguments of the given types,
+     *         before calling the original method handle
+     * @throws NullPointerException if the target is null,
+     *                              or if the {@code valueTypes} list or any of its elements is null
+     * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+     *                  or if {@code pos} is negative or greater than the arity of the target,
+     *                  or if the new method handle's type would have too many parameters
+     */
+    public static
+    MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
+        valueTypes = copyTypes(valueTypes);
+        MethodType oldType = target.type();  // get NPE
+        int dropped = dropArgumentChecks(oldType, pos, valueTypes);
+
+        MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
+        if (dropped == 0) {
+            return target;
+        }
+
+        return new Transformers.DropArguments(newType, target, pos, valueTypes.size());
+    }
+
+    private static List<Class<?>> copyTypes(List<Class<?>> types) {
+        Object[] a = types.toArray();
+        return Arrays.asList(Arrays.copyOf(a, a.length, Class[].class));
+    }
+
+    private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
+        int dropped = valueTypes.size();
+        MethodType.checkSlotCount(dropped);
+        int outargs = oldType.parameterCount();
+        int inargs  = outargs + dropped;
+        if (pos < 0 || pos > outargs)
+            throw newIllegalArgumentException("no argument type to remove"
+                    + Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
+                    );
+        return dropped;
+    }
+
+    /**
+     * Produces a method handle which will discard some dummy arguments
+     * before calling some other specified <i>target</i> method handle.
+     * The type of the new method handle will be the same as the target's type,
+     * except it will also include the dummy argument types,
+     * at some given position.
+     * <p>
+     * The {@code pos} argument may range between zero and <i>N</i>,
+     * where <i>N</i> is the arity of the target.
+     * If {@code pos} is zero, the dummy arguments will precede
+     * the target's real arguments; if {@code pos} is <i>N</i>
+     * they will come after.
+     * <p>
+     * <b>Example:</b>
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+     * }</pre></blockquote>
+     * <p>
+     * This method is also equivalent to the following code:
+     * <blockquote><pre>
+     * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
+     * </pre></blockquote>
+     * @param target the method handle to invoke after the arguments are dropped
+     * @param valueTypes the type(s) of the argument(s) to drop
+     * @param pos position of first argument to drop (zero for the leftmost)
+     * @return a method handle which drops arguments of the given types,
+     *         before calling the original method handle
+     * @throws NullPointerException if the target is null,
+     *                              or if the {@code valueTypes} array or any of its elements is null
+     * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+     *                  or if {@code pos} is negative or greater than the arity of the target,
+     *                  or if the new method handle's type would have
+     *                  <a href="MethodHandle.html#maxarity">too many parameters</a>
+     */
+    public static
+    MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
+        return dropArguments(target, pos, Arrays.asList(valueTypes));
+    }
+
+    /**
+     * Adapts a target method handle by pre-processing
+     * one or more of its arguments, each with its own unary filter function,
+     * and then calling the target with each pre-processed argument
+     * replaced by the result of its corresponding filter function.
+     * <p>
+     * The pre-processing is performed by one or more method handles,
+     * specified in the elements of the {@code filters} array.
+     * The first element of the filter array corresponds to the {@code pos}
+     * argument of the target, and so on in sequence.
+     * <p>
+     * Null arguments in the array are treated as identity functions,
+     * and the corresponding arguments left unchanged.
+     * (If there are no non-null elements in the array, the original target is returned.)
+     * Each filter is applied to the corresponding argument of the adapter.
+     * <p>
+     * If a filter {@code F} applies to the {@code N}th argument of
+     * the target, then {@code F} must be a method handle which
+     * takes exactly one argument.  The type of {@code F}'s sole argument
+     * replaces the corresponding argument type of the target
+     * in the resulting adapted method handle.
+     * The return type of {@code F} must be identical to the corresponding
+     * parameter type of the target.
+     * <p>
+     * It is an error if there are elements of {@code filters}
+     * (null or not)
+     * which do not correspond to argument positions in the target.
+     * <p><b>Example:</b>
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle upcase = lookup().findVirtual(String.class,
+  "toUpperCase", methodType(String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle f0 = filterArguments(cat, 0, upcase);
+assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
+MethodHandle f1 = filterArguments(cat, 1, upcase);
+assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
+MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
+assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
+     * }</pre></blockquote>
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>{@code
+     * V target(P... p, A[i]... a[i], B... b);
+     * A[i] filter[i](V[i]);
+     * T adapter(P... p, V[i]... v[i], B... b) {
+     *   return target(p..., f[i](v[i])..., b...);
+     * }
+     * }</pre></blockquote>
+     *
+     * @param target the method handle to invoke after arguments are filtered
+     * @param pos the position of the first argument to filter
+     * @param filters method handles to call initially on filtered arguments
+     * @return method handle which incorporates the specified argument filtering logic
+     * @throws NullPointerException if the target is null
+     *                              or if the {@code filters} array is null
+     * @throws IllegalArgumentException if a non-null element of {@code filters}
+     *          does not match a corresponding argument type of target as described above,
+     *          or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
+     *          or if the resulting method handle's type would have
+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
+     */
+    public static
+    MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
+        filterArgumentsCheckArity(target, pos, filters);
+
+        for (int i = 0; i < filters.length; ++i) {
+            filterArgumentChecks(target, i + pos, filters[i]);
+        }
+
+        return new Transformers.FilterArguments(target, pos, filters);
+    }
+
+    private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
+        MethodType targetType = target.type();
+        int maxPos = targetType.parameterCount();
+        if (pos + filters.length > maxPos)
+            throw newIllegalArgumentException("too many filters");
+    }
+
+    private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
+        MethodType targetType = target.type();
+        MethodType filterType = filter.type();
+        if (filterType.parameterCount() != 1
+            || filterType.returnType() != targetType.parameterType(pos))
+            throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+    }
+
+    /**
+     * Adapts a target method handle by pre-processing
+     * a sub-sequence of its arguments with a filter (another method handle).
+     * The pre-processed arguments are replaced by the result (if any) of the
+     * filter function.
+     * The target is then called on the modified (usually shortened) argument list.
+     * <p>
+     * If the filter returns a value, the target must accept that value as
+     * its argument in position {@code pos}, preceded and/or followed by
+     * any arguments not passed to the filter.
+     * If the filter returns void, the target must accept all arguments
+     * not passed to the filter.
+     * No arguments are reordered, and a result returned from the filter
+     * replaces (in order) the whole subsequence of arguments originally
+     * passed to the adapter.
+     * <p>
+     * The argument types (if any) of the filter
+     * replace zero or one argument types of the target, at position {@code pos},
+     * in the resulting adapted method handle.
+     * The return type of the filter (if any) must be identical to the
+     * argument type of the target at position {@code pos}, and that target argument
+     * is supplied by the return value of the filter.
+     * <p>
+     * In all cases, {@code pos} must be greater than or equal to zero, and
+     * {@code pos} must also be less than or equal to the target's arity.
+     * <p><b>Example:</b>
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle deepToString = publicLookup()
+  .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+
+MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
+assertEquals("[strange]", (String) ts1.invokeExact("strange"));
+
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
+
+MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
+MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
+assertEquals("[top, [up, down], strange]",
+             (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
+assertEquals("[top, [up, down], [strange]]",
+             (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
+assertEquals("[top, [[up, down, strange], charm], bottom]",
+             (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
+     * }</pre></blockquote>
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>{@code
+     * T target(A...,V,C...);
+     * V filter(B...);
+     * T adapter(A... a,B... b,C... c) {
+     *   V v = filter(b...);
+     *   return target(a...,v,c...);
+     * }
+     * // and if the filter has no arguments:
+     * T target2(A...,V,C...);
+     * V filter2();
+     * T adapter2(A... a,C... c) {
+     *   V v = filter2();
+     *   return target2(a...,v,c...);
+     * }
+     * // and if the filter has a void return:
+     * T target3(A...,C...);
+     * void filter3(B...);
+     * void adapter3(A... a,B... b,C... c) {
+     *   filter3(b...);
+     *   return target3(a...,c...);
+     * }
+     * }</pre></blockquote>
+     * <p>
+     * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
+     * one which first "folds" the affected arguments, and then drops them, in separate
+     * steps as follows:
+     * <blockquote><pre>{@code
+     * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
+     * mh = MethodHandles.foldArguments(mh, coll); //step 1
+     * }</pre></blockquote>
+     * If the target method handle consumes no arguments besides than the result
+     * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
+     * is equivalent to {@code filterReturnValue(coll, mh)}.
+     * If the filter method handle {@code coll} consumes one argument and produces
+     * a non-void result, then {@code collectArguments(mh, N, coll)}
+     * is equivalent to {@code filterArguments(mh, N, coll)}.
+     * Other equivalences are possible but would require argument permutation.
+     *
+     * @param target the method handle to invoke after filtering the subsequence of arguments
+     * @param pos the position of the first adapter argument to pass to the filter,
+     *            and/or the target argument which receives the result of the filter
+     * @param filter method handle to call on the subsequence of arguments
+     * @return method handle which incorporates the specified argument subsequence filtering logic
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if the return type of {@code filter}
+     *          is non-void and is not the same as the {@code pos} argument of the target,
+     *          or if {@code pos} is not between 0 and the target's arity, inclusive,
+     *          or if the resulting method handle's type would have
+     *          <a href="MethodHandle.html#maxarity">too many parameters</a>
+     * @see MethodHandles#foldArguments
+     * @see MethodHandles#filterArguments
+     * @see MethodHandles#filterReturnValue
+     */
+    public static
+    MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
+        MethodType newType = collectArgumentsChecks(target, pos, filter);
+        return new Transformers.CollectArguments(target, filter, pos, newType);
+    }
+
+    private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
+        MethodType targetType = target.type();
+        MethodType filterType = filter.type();
+        Class<?> rtype = filterType.returnType();
+        List<Class<?>> filterArgs = filterType.parameterList();
+        if (rtype == void.class) {
+            return targetType.insertParameterTypes(pos, filterArgs);
+        }
+        if (rtype != targetType.parameterType(pos)) {
+            throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+        }
+        return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
+    }
+
+    /**
+     * Adapts a target method handle by post-processing
+     * its return value (if any) with a filter (another method handle).
+     * The result of the filter is returned from the adapter.
+     * <p>
+     * If the target returns a value, the filter must accept that value as
+     * its only argument.
+     * If the target returns void, the filter must accept no arguments.
+     * <p>
+     * The return type of the filter
+     * replaces the return type of the target
+     * in the resulting adapted method handle.
+     * The argument type of the filter (if any) must be identical to the
+     * return type of the target.
+     * <p><b>Example:</b>
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle length = lookup().findVirtual(String.class,
+  "length", methodType(int.class));
+System.out.println((String) cat.invokeExact("x", "y")); // xy
+MethodHandle f0 = filterReturnValue(cat, length);
+System.out.println((int) f0.invokeExact("x", "y")); // 2
+     * }</pre></blockquote>
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>{@code
+     * V target(A...);
+     * T filter(V);
+     * T adapter(A... a) {
+     *   V v = target(a...);
+     *   return filter(v);
+     * }
+     * // and if the target has a void return:
+     * void target2(A...);
+     * T filter2();
+     * T adapter2(A... a) {
+     *   target2(a...);
+     *   return filter2();
+     * }
+     * // and if the filter has a void return:
+     * V target3(A...);
+     * void filter3(V);
+     * void adapter3(A... a) {
+     *   V v = target3(a...);
+     *   filter3(v);
+     * }
+     * }</pre></blockquote>
+     * @param target the method handle to invoke before filtering the return value
+     * @param filter method handle to call on the return value
+     * @return method handle which incorporates the specified return value filtering logic
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if the argument list of {@code filter}
+     *          does not match the return type of target as described above
+     */
+    public static
+    MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
+        MethodType targetType = target.type();
+        MethodType filterType = filter.type();
+        filterReturnValueChecks(targetType, filterType);
+
+        return new Transformers.FilterReturnValue(target, filter);
+    }
+
+    private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
+        Class<?> rtype = targetType.returnType();
+        int filterValues = filterType.parameterCount();
+        if (filterValues == 0
+                ? (rtype != void.class)
+                : (rtype != filterType.parameterType(0) || filterValues != 1))
+            throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+    }
+
+    /**
+     * Adapts a target method handle by pre-processing
+     * some of its arguments, and then calling the target with
+     * the result of the pre-processing, inserted into the original
+     * sequence of arguments.
+     * <p>
+     * The pre-processing is performed by {@code combiner}, a second method handle.
+     * Of the arguments passed to the adapter, the first {@code N} arguments
+     * are copied to the combiner, which is then called.
+     * (Here, {@code N} is defined as the parameter count of the combiner.)
+     * After this, control passes to the target, with any result
+     * from the combiner inserted before the original {@code N} incoming
+     * arguments.
+     * <p>
+     * If the combiner returns a value, the first parameter type of the target
+     * must be identical with the return type of the combiner, and the next
+     * {@code N} parameter types of the target must exactly match the parameters
+     * of the combiner.
+     * <p>
+     * If the combiner has a void return, no result will be inserted,
+     * and the first {@code N} parameter types of the target
+     * must exactly match the parameters of the combiner.
+     * <p>
+     * The resulting adapter is the same type as the target, except that the
+     * first parameter type is dropped,
+     * if it corresponds to the result of the combiner.
+     * <p>
+     * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments
+     * that either the combiner or the target does not wish to receive.
+     * If some of the incoming arguments are destined only for the combiner,
+     * consider using {@link MethodHandle#asCollector asCollector} instead, since those
+     * arguments will not need to be live on the stack on entry to the
+     * target.)
+     * <p><b>Example:</b>
+     * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+  "println", methodType(void.class, String.class))
+    .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, trace);
+// also prints "boo":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+     * }</pre></blockquote>
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>{@code
+     * // there are N arguments in A...
+     * T target(V, A[N]..., B...);
+     * V combiner(A...);
+     * T adapter(A... a, B... b) {
+     *   V v = combiner(a...);
+     *   return target(v, a..., b...);
+     * }
+     * // and if the combiner has a void return:
+     * T target2(A[N]..., B...);
+     * void combiner2(A...);
+     * T adapter2(A... a, B... b) {
+     *   combiner2(a...);
+     *   return target2(a..., b...);
+     * }
+     * }</pre></blockquote>
+     * @param target the method handle to invoke after arguments are combined
+     * @param combiner method handle to call initially on the incoming arguments
+     * @return method handle which incorporates the specified argument folding logic
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if {@code combiner}'s return type
+     *          is non-void and not the same as the first argument type of
+     *          the target, or if the initial {@code N} argument types
+     *          of the target
+     *          (skipping one matching the {@code combiner}'s return type)
+     *          are not identical with the argument types of {@code combiner}
+     */
+    public static
+    MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
+        int foldPos = 0;
+        MethodType targetType = target.type();
+        MethodType combinerType = combiner.type();
+        Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
+
+        return new Transformers.FoldArguments(target, combiner);
+    }
+
+    private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
+        int foldArgs   = combinerType.parameterCount();
+        Class<?> rtype = combinerType.returnType();
+        int foldVals = rtype == void.class ? 0 : 1;
+        int afterInsertPos = foldPos + foldVals;
+        boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
+        if (ok && !(combinerType.parameterList()
+                    .equals(targetType.parameterList().subList(afterInsertPos,
+                                                               afterInsertPos + foldArgs))))
+            ok = false;
+        if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
+            ok = false;
+        if (!ok)
+            throw misMatchedTypes("target and combiner types", targetType, combinerType);
+        return rtype;
+    }
+
+    /**
+     * Makes a method handle which adapts a target method handle,
+     * by guarding it with a test, a boolean-valued method handle.
+     * If the guard fails, a fallback handle is called instead.
+     * All three method handles must have the same corresponding
+     * argument and return types, except that the return type
+     * of the test must be boolean, and the test is allowed
+     * to have fewer arguments than the other two method handles.
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>{@code
+     * boolean test(A...);
+     * T target(A...,B...);
+     * T fallback(A...,B...);
+     * T adapter(A... a,B... b) {
+     *   if (test(a...))
+     *     return target(a..., b...);
+     *   else
+     *     return fallback(a..., b...);
+     * }
+     * }</pre></blockquote>
+     * Note that the test arguments ({@code a...} in the pseudocode) cannot
+     * be modified by execution of the test, and so are passed unchanged
+     * from the caller to the target or fallback as appropriate.
+     * @param test method handle used for test, must return boolean
+     * @param target method handle to call if test passes
+     * @param fallback method handle to call if test fails
+     * @return method handle which incorporates the specified if/then/else logic
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if {@code test} does not return boolean,
+     *          or if all three method types do not match (with the return
+     *          type of {@code test} changed to match that of the target).
+     */
+    public static
+    MethodHandle guardWithTest(MethodHandle test,
+                               MethodHandle target,
+                               MethodHandle fallback) {
+        MethodType gtype = test.type();
+        MethodType ttype = target.type();
+        MethodType ftype = fallback.type();
+        if (!ttype.equals(ftype))
+            throw misMatchedTypes("target and fallback types", ttype, ftype);
+        if (gtype.returnType() != boolean.class)
+            throw newIllegalArgumentException("guard type is not a predicate "+gtype);
+        List<Class<?>> targs = ttype.parameterList();
+        List<Class<?>> gargs = gtype.parameterList();
+        if (!targs.equals(gargs)) {
+            int gpc = gargs.size(), tpc = targs.size();
+            if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
+                throw misMatchedTypes("target and test types", ttype, gtype);
+            test = dropArguments(test, gpc, targs.subList(gpc, tpc));
+            gtype = test.type();
+        }
+
+        return new Transformers.GuardWithTest(test, target, fallback);
+    }
+
+    static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
+        return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
+    }
+
+    /**
+     * Makes a method handle which adapts a target method handle,
+     * by running it inside an exception handler.
+     * If the target returns normally, the adapter returns that value.
+     * If an exception matching the specified type is thrown, the fallback
+     * handle is called instead on the exception, plus the original arguments.
+     * <p>
+     * The target and handler must have the same corresponding
+     * argument and return types, except that handler may omit trailing arguments
+     * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
+     * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
+     * <p> Here is pseudocode for the resulting adapter:
+     * <blockquote><pre>{@code
+     * T target(A..., B...);
+     * T handler(ExType, A...);
+     * T adapter(A... a, B... b) {
+     *   try {
+     *     return target(a..., b...);
+     *   } catch (ExType ex) {
+     *     return handler(ex, a...);
+     *   }
+     * }
+     * }</pre></blockquote>
+     * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+     * be modified by execution of the target, and so are passed unchanged
+     * from the caller to the handler, if the handler is invoked.
+     * <p>
+     * The target and handler must return the same type, even if the handler
+     * always throws.  (This might happen, for instance, because the handler
+     * is simulating a {@code finally} clause).
+     * To create such a throwing handler, compose the handler creation logic
+     * with {@link #throwException throwException},
+     * in order to create a method handle of the correct return type.
+     * @param target method handle to call
+     * @param exType the type of exception which the handler will catch
+     * @param handler method handle to call if a matching exception is thrown
+     * @return method handle which incorporates the specified try/catch logic
+     * @throws NullPointerException if any argument is null
+     * @throws IllegalArgumentException if {@code handler} does not accept
+     *          the given exception type, or if the method handle types do
+     *          not match in their return types and their
+     *          corresponding parameters
+     */
+    public static
+    MethodHandle catchException(MethodHandle target,
+                                Class<? extends Throwable> exType,
+                                MethodHandle handler) {
+        MethodType ttype = target.type();
+        MethodType htype = handler.type();
+        if (htype.parameterCount() < 1 ||
+            !htype.parameterType(0).isAssignableFrom(exType))
+            throw newIllegalArgumentException("handler does not accept exception type "+exType);
+        if (htype.returnType() != ttype.returnType())
+            throw misMatchedTypes("target and handler return types", ttype, htype);
+        List<Class<?>> targs = ttype.parameterList();
+        List<Class<?>> hargs = htype.parameterList();
+        hargs = hargs.subList(1, hargs.size());  // omit leading parameter from handler
+        if (!targs.equals(hargs)) {
+            int hpc = hargs.size(), tpc = targs.size();
+            if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
+                throw misMatchedTypes("target and handler types", ttype, htype);
+        }
+
+        return new Transformers.CatchException(target, handler, exType);
+    }
+
+    /**
+     * Produces a method handle which will throw exceptions of the given {@code exType}.
+     * The method handle will accept a single argument of {@code exType},
+     * and immediately throw it as an exception.
+     * The method type will nominally specify a return of {@code returnType}.
+     * The return type may be anything convenient:  It doesn't matter to the
+     * method handle's behavior, since it will never return normally.
+     * @param returnType the return type of the desired method handle
+     * @param exType the parameter type of the desired method handle
+     * @return method handle which can throw the given exceptions
+     * @throws NullPointerException if either argument is null
+     */
+    public static
+    MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
+        if (!Throwable.class.isAssignableFrom(exType))
+            throw new ClassCastException(exType.getName());
+
+        return new Transformers.AlwaysThrow(returnType, exType);
+    }
+}
diff --git a/java/lang/invoke/MethodType.java b/java/lang/invoke/MethodType.java
new file mode 100644
index 0000000..4652c93
--- /dev/null
+++ b/java/lang/invoke/MethodType.java
@@ -0,0 +1,1328 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+import java.lang.ref.WeakReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+import sun.invoke.util.BytecodeDescriptor;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * A method type represents the arguments and return type accepted and
+ * returned by a method handle, or the arguments and return type passed
+ * and expected  by a method handle caller.  Method types must be properly
+ * matched between a method handle and all its callers,
+ * and the JVM's operations enforce this matching at, specifically
+ * during calls to {@link MethodHandle#invokeExact MethodHandle.invokeExact}
+ * and {@link MethodHandle#invoke MethodHandle.invoke}, and during execution
+ * of {@code invokedynamic} instructions.
+ * <p>
+ * The structure is a return type accompanied by any number of parameter types.
+ * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
+ * (For ease of exposition, we treat {@code void} as if it were a type.
+ * In fact, it denotes the absence of a return type.)
+ * <p>
+ * All instances of {@code MethodType} are immutable.
+ * Two instances are completely interchangeable if they compare equal.
+ * Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
+ * <p>
+ * This type can be created only by factory methods.
+ * All factory methods may cache values, though caching is not guaranteed.
+ * Some factory methods are static, while others are virtual methods which
+ * modify precursor method types, e.g., by changing a selected parameter.
+ * <p>
+ * Factory methods which operate on groups of parameter types
+ * are systematically presented in two versions, so that both Java arrays and
+ * Java lists can be used to work with groups of parameter types.
+ * The query methods {@code parameterArray} and {@code parameterList}
+ * also provide a choice between arrays and lists.
+ * <p>
+ * {@code MethodType} objects are sometimes derived from bytecode instructions
+ * such as {@code invokedynamic}, specifically from the type descriptor strings associated
+ * with the instructions in a class file's constant pool.
+ * <p>
+ * Like classes and strings, method types can also be represented directly
+ * in a class file's constant pool as constants.
+ * A method type may be loaded by an {@code ldc} instruction which refers
+ * to a suitable {@code CONSTANT_MethodType} constant pool entry.
+ * The entry refers to a {@code CONSTANT_Utf8} spelling for the descriptor string.
+ * (For full details on method type constants,
+ * see sections 4.4.8 and 5.4.3.5 of the Java Virtual Machine Specification.)
+ * <p>
+ * When the JVM materializes a {@code MethodType} from a descriptor string,
+ * all classes named in the descriptor must be accessible, and will be loaded.
+ * (But the classes need not be initialized, as is the case with a {@code CONSTANT_Class}.)
+ * This loading may occur at any time before the {@code MethodType} object is first derived.
+ * @author John Rose, JSR 292 EG
+ */
+public final
+class MethodType implements java.io.Serializable {
+    private static final long serialVersionUID = 292L;  // {rtype, {ptype...}}
+
+    // The rtype and ptypes fields define the structural identity of the method type:
+    private final Class<?>   rtype;
+    private final Class<?>[] ptypes;
+
+    // The remaining fields are caches of various sorts:
+    private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
+    private @Stable MethodType wrapAlt;  // alternative wrapped/unwrapped version
+    // Android-removed: Cache of higher order adapters.
+    // We're not dynamically generating any adapters at this point.
+    // private @Stable Invokers invokers;   // cache of handy higher-order adapters
+    private @Stable String methodDescriptor;  // cache for toMethodDescriptorString
+
+    /**
+     * Check the given parameters for validity and store them into the final fields.
+     */
+    private MethodType(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+        checkRtype(rtype);
+        checkPtypes(ptypes);
+        this.rtype = rtype;
+        // defensively copy the array passed in by the user
+        this.ptypes = trusted ? ptypes : Arrays.copyOf(ptypes, ptypes.length);
+    }
+
+    /**
+     * Construct a temporary unchecked instance of MethodType for use only as a key to the intern table.
+     * Does not check the given parameters for validity, and must be discarded after it is used as a searching key.
+     * The parameters are reversed for this constructor, so that is is not accidentally used.
+     */
+    private MethodType(Class<?>[] ptypes, Class<?> rtype) {
+        this.rtype = rtype;
+        this.ptypes = ptypes;
+    }
+
+    /*trusted*/ MethodTypeForm form() { return form; }
+    // Android-changed: Make rtype()/ptypes() public @hide for implementation use.
+    // /*trusted*/ Class<?> rtype() { return rtype; }
+    // /*trusted*/ Class<?>[] ptypes() { return ptypes; }
+    /*trusted*/ /** @hide */ public Class<?> rtype() { return rtype; }
+    /*trusted*/ /** @hide */ public Class<?>[] ptypes() { return ptypes; }
+
+    // Android-removed: Implementation methods unused on Android.
+    // void setForm(MethodTypeForm f) { form = f; }
+
+    /** This number, mandated by the JVM spec as 255,
+     *  is the maximum number of <em>slots</em>
+     *  that any Java method can receive in its argument list.
+     *  It limits both JVM signatures and method type objects.
+     *  The longest possible invocation will look like
+     *  {@code staticMethod(arg1, arg2, ..., arg255)} or
+     *  {@code x.virtualMethod(arg1, arg2, ..., arg254)}.
+     */
+    /*non-public*/ static final int MAX_JVM_ARITY = 255;  // this is mandated by the JVM spec.
+
+    /** This number is the maximum arity of a method handle, 254.
+     *  It is derived from the absolute JVM-imposed arity by subtracting one,
+     *  which is the slot occupied by the method handle itself at the
+     *  beginning of the argument list used to invoke the method handle.
+     *  The longest possible invocation will look like
+     *  {@code mh.invoke(arg1, arg2, ..., arg254)}.
+     */
+    // Issue:  Should we allow MH.invokeWithArguments to go to the full 255?
+    /*non-public*/ static final int MAX_MH_ARITY = MAX_JVM_ARITY-1;  // deduct one for mh receiver
+
+    /** This number is the maximum arity of a method handle invoker, 253.
+     *  It is derived from the absolute JVM-imposed arity by subtracting two,
+     *  which are the slots occupied by invoke method handle, and the
+     *  target method handle, which are both at the beginning of the argument
+     *  list used to invoke the target method handle.
+     *  The longest possible invocation will look like
+     *  {@code invokermh.invoke(targetmh, arg1, arg2, ..., arg253)}.
+     */
+    /*non-public*/ static final int MAX_MH_INVOKER_ARITY = MAX_MH_ARITY-1;  // deduct one more for invoker
+
+    private static void checkRtype(Class<?> rtype) {
+        Objects.requireNonNull(rtype);
+    }
+    private static void checkPtype(Class<?> ptype) {
+        Objects.requireNonNull(ptype);
+        if (ptype == void.class)
+            throw newIllegalArgumentException("parameter type cannot be void");
+    }
+    /** Return number of extra slots (count of long/double args). */
+    private static int checkPtypes(Class<?>[] ptypes) {
+        int slots = 0;
+        for (Class<?> ptype : ptypes) {
+            checkPtype(ptype);
+            if (ptype == double.class || ptype == long.class) {
+                slots++;
+            }
+        }
+        checkSlotCount(ptypes.length + slots);
+        return slots;
+    }
+    static void checkSlotCount(int count) {
+        assert((MAX_JVM_ARITY & (MAX_JVM_ARITY+1)) == 0);
+        // MAX_JVM_ARITY must be power of 2 minus 1 for following code trick to work:
+        if ((count & MAX_JVM_ARITY) != count)
+            throw newIllegalArgumentException("bad parameter count "+count);
+    }
+    private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
+        if (num instanceof Integer)  num = "bad index: "+num;
+        return new IndexOutOfBoundsException(num.toString());
+    }
+
+    static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
+
+    static final Class<?>[] NO_PTYPES = {};
+
+    /**
+     * Finds or creates an instance of the given method type.
+     * @param rtype  the return type
+     * @param ptypes the parameter types
+     * @return a method type with the given components
+     * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
+     * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
+     */
+    public static
+    MethodType methodType(Class<?> rtype, Class<?>[] ptypes) {
+        return makeImpl(rtype, ptypes, false);
+    }
+
+    /**
+     * Finds or creates a method type with the given components.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param rtype  the return type
+     * @param ptypes the parameter types
+     * @return a method type with the given components
+     * @throws NullPointerException if {@code rtype} or {@code ptypes} or any element of {@code ptypes} is null
+     * @throws IllegalArgumentException if any element of {@code ptypes} is {@code void.class}
+     */
+    public static
+    MethodType methodType(Class<?> rtype, List<Class<?>> ptypes) {
+        boolean notrust = false;  // random List impl. could return evil ptypes array
+        return makeImpl(rtype, listToArray(ptypes), notrust);
+    }
+
+    private static Class<?>[] listToArray(List<Class<?>> ptypes) {
+        // sanity check the size before the toArray call, since size might be huge
+        checkSlotCount(ptypes.size());
+        return ptypes.toArray(NO_PTYPES);
+    }
+
+    /**
+     * Finds or creates a method type with the given components.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * The leading parameter type is prepended to the remaining array.
+     * @param rtype  the return type
+     * @param ptype0 the first parameter type
+     * @param ptypes the remaining parameter types
+     * @return a method type with the given components
+     * @throws NullPointerException if {@code rtype} or {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is null
+     * @throws IllegalArgumentException if {@code ptype0} or {@code ptypes} or any element of {@code ptypes} is {@code void.class}
+     */
+    public static
+    MethodType methodType(Class<?> rtype, Class<?> ptype0, Class<?>... ptypes) {
+        Class<?>[] ptypes1 = new Class<?>[1+ptypes.length];
+        ptypes1[0] = ptype0;
+        System.arraycopy(ptypes, 0, ptypes1, 1, ptypes.length);
+        return makeImpl(rtype, ptypes1, true);
+    }
+
+    /**
+     * Finds or creates a method type with the given components.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * The resulting method has no parameter types.
+     * @param rtype  the return type
+     * @return a method type with the given return value
+     * @throws NullPointerException if {@code rtype} is null
+     */
+    public static
+    MethodType methodType(Class<?> rtype) {
+        return makeImpl(rtype, NO_PTYPES, true);
+    }
+
+    /**
+     * Finds or creates a method type with the given components.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * The resulting method has the single given parameter type.
+     * @param rtype  the return type
+     * @param ptype0 the parameter type
+     * @return a method type with the given return value and parameter type
+     * @throws NullPointerException if {@code rtype} or {@code ptype0} is null
+     * @throws IllegalArgumentException if {@code ptype0} is {@code void.class}
+     */
+    public static
+    MethodType methodType(Class<?> rtype, Class<?> ptype0) {
+        return makeImpl(rtype, new Class<?>[]{ ptype0 }, true);
+    }
+
+    /**
+     * Finds or creates a method type with the given components.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * The resulting method has the same parameter types as {@code ptypes},
+     * and the specified return type.
+     * @param rtype  the return type
+     * @param ptypes the method type which supplies the parameter types
+     * @return a method type with the given components
+     * @throws NullPointerException if {@code rtype} or {@code ptypes} is null
+     */
+    public static
+    MethodType methodType(Class<?> rtype, MethodType ptypes) {
+        return makeImpl(rtype, ptypes.ptypes, true);
+    }
+
+    /**
+     * Sole factory method to find or create an interned method type.
+     * @param rtype desired return type
+     * @param ptypes desired parameter types
+     * @param trusted whether the ptypes can be used without cloning
+     * @return the unique method type of the desired structure
+     */
+    /*trusted*/ static
+    MethodType makeImpl(Class<?> rtype, Class<?>[] ptypes, boolean trusted) {
+        MethodType mt = internTable.get(new MethodType(ptypes, rtype));
+        if (mt != null)
+            return mt;
+        if (ptypes.length == 0) {
+            ptypes = NO_PTYPES; trusted = true;
+        }
+        mt = new MethodType(rtype, ptypes, trusted);
+        // promote the object to the Real Thing, and reprobe
+        mt.form = MethodTypeForm.findForm(mt);
+        return internTable.add(mt);
+    }
+    private static final MethodType[] objectOnlyTypes = new MethodType[20];
+
+    /**
+     * Finds or creates a method type whose components are {@code Object} with an optional trailing {@code Object[]} array.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * All parameters and the return type will be {@code Object},
+     * except the final array parameter if any, which will be {@code Object[]}.
+     * @param objectArgCount number of parameters (excluding the final array parameter if any)
+     * @param finalArray whether there will be a trailing array parameter, of type {@code Object[]}
+     * @return a generally applicable method type, for all calls of the given fixed argument count and a collected array of further arguments
+     * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255 (or 254, if {@code finalArray} is true)
+     * @see #genericMethodType(int)
+     */
+    public static
+    MethodType genericMethodType(int objectArgCount, boolean finalArray) {
+        MethodType mt;
+        checkSlotCount(objectArgCount);
+        int ivarargs = (!finalArray ? 0 : 1);
+        int ootIndex = objectArgCount*2 + ivarargs;
+        if (ootIndex < objectOnlyTypes.length) {
+            mt = objectOnlyTypes[ootIndex];
+            if (mt != null)  return mt;
+        }
+        Class<?>[] ptypes = new Class<?>[objectArgCount + ivarargs];
+        Arrays.fill(ptypes, Object.class);
+        if (ivarargs != 0)  ptypes[objectArgCount] = Object[].class;
+        mt = makeImpl(Object.class, ptypes, true);
+        if (ootIndex < objectOnlyTypes.length) {
+            objectOnlyTypes[ootIndex] = mt;     // cache it here also!
+        }
+        return mt;
+    }
+
+    /**
+     * Finds or creates a method type whose components are all {@code Object}.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * All parameters and the return type will be Object.
+     * @param objectArgCount number of parameters
+     * @return a generally applicable method type, for all calls of the given argument count
+     * @throws IllegalArgumentException if {@code objectArgCount} is negative or greater than 255
+     * @see #genericMethodType(int, boolean)
+     */
+    public static
+    MethodType genericMethodType(int objectArgCount) {
+        return genericMethodType(objectArgCount, false);
+    }
+
+    /**
+     * Finds or creates a method type with a single different parameter type.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param num    the index (zero-based) of the parameter type to change
+     * @param nptype a new parameter type to replace the old one with
+     * @return the same type, except with the selected parameter changed
+     * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
+     * @throws IllegalArgumentException if {@code nptype} is {@code void.class}
+     * @throws NullPointerException if {@code nptype} is null
+     */
+    public MethodType changeParameterType(int num, Class<?> nptype) {
+        if (parameterType(num) == nptype)  return this;
+        checkPtype(nptype);
+        Class<?>[] nptypes = ptypes.clone();
+        nptypes[num] = nptype;
+        return makeImpl(rtype, nptypes, true);
+    }
+
+    /**
+     * Finds or creates a method type with additional parameter types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param num    the position (zero-based) of the inserted parameter type(s)
+     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
+     * @return the same type, except with the selected parameter(s) inserted
+     * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
+     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+     *                                  or if the resulting method type would have more than 255 parameter slots
+     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+     */
+    public MethodType insertParameterTypes(int num, Class<?>... ptypesToInsert) {
+        int len = ptypes.length;
+        if (num < 0 || num > len)
+            throw newIndexOutOfBoundsException(num);
+        int ins = checkPtypes(ptypesToInsert);
+        checkSlotCount(parameterSlotCount() + ptypesToInsert.length + ins);
+        int ilen = ptypesToInsert.length;
+        if (ilen == 0)  return this;
+        Class<?>[] nptypes = Arrays.copyOfRange(ptypes, 0, len+ilen);
+        System.arraycopy(nptypes, num, nptypes, num+ilen, len-num);
+        System.arraycopy(ptypesToInsert, 0, nptypes, num, ilen);
+        return makeImpl(rtype, nptypes, true);
+    }
+
+    /**
+     * Finds or creates a method type with additional parameter types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
+     * @return the same type, except with the selected parameter(s) appended
+     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+     *                                  or if the resulting method type would have more than 255 parameter slots
+     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+     */
+    public MethodType appendParameterTypes(Class<?>... ptypesToInsert) {
+        return insertParameterTypes(parameterCount(), ptypesToInsert);
+    }
+
+    /**
+     * Finds or creates a method type with additional parameter types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param num    the position (zero-based) of the inserted parameter type(s)
+     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
+     * @return the same type, except with the selected parameter(s) inserted
+     * @throws IndexOutOfBoundsException if {@code num} is negative or greater than {@code parameterCount()}
+     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+     *                                  or if the resulting method type would have more than 255 parameter slots
+     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+     */
+    public MethodType insertParameterTypes(int num, List<Class<?>> ptypesToInsert) {
+        return insertParameterTypes(num, listToArray(ptypesToInsert));
+    }
+
+    /**
+     * Finds or creates a method type with additional parameter types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param ptypesToInsert zero or more new parameter types to insert after the end of the parameter list
+     * @return the same type, except with the selected parameter(s) appended
+     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+     *                                  or if the resulting method type would have more than 255 parameter slots
+     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+     */
+    public MethodType appendParameterTypes(List<Class<?>> ptypesToInsert) {
+        return insertParameterTypes(parameterCount(), ptypesToInsert);
+    }
+
+     /**
+     * Finds or creates a method type with modified parameter types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param start  the position (zero-based) of the first replaced parameter type(s)
+     * @param end    the position (zero-based) after the last replaced parameter type(s)
+     * @param ptypesToInsert zero or more new parameter types to insert into the parameter list
+     * @return the same type, except with the selected parameter(s) replaced
+     * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
+     *                                  or if {@code end} is negative or greater than {@code parameterCount()}
+     *                                  or if {@code start} is greater than {@code end}
+     * @throws IllegalArgumentException if any element of {@code ptypesToInsert} is {@code void.class}
+     *                                  or if the resulting method type would have more than 255 parameter slots
+     * @throws NullPointerException if {@code ptypesToInsert} or any of its elements is null
+     */
+    /*non-public*/ MethodType replaceParameterTypes(int start, int end, Class<?>... ptypesToInsert) {
+        if (start == end)
+            return insertParameterTypes(start, ptypesToInsert);
+        int len = ptypes.length;
+        if (!(0 <= start && start <= end && end <= len))
+            throw newIndexOutOfBoundsException("start="+start+" end="+end);
+        int ilen = ptypesToInsert.length;
+        if (ilen == 0)
+            return dropParameterTypes(start, end);
+        return dropParameterTypes(start, end).insertParameterTypes(start, ptypesToInsert);
+    }
+
+    /** Replace the last arrayLength parameter types with the component type of arrayType.
+     * @param arrayType any array type
+     * @param arrayLength the number of parameter types to change
+     * @return the resulting type
+     */
+    /*non-public*/ MethodType asSpreaderType(Class<?> arrayType, int arrayLength) {
+        assert(parameterCount() >= arrayLength);
+        int spreadPos = ptypes.length - arrayLength;
+        if (arrayLength == 0)  return this;  // nothing to change
+        if (arrayType == Object[].class) {
+            if (isGeneric())  return this;  // nothing to change
+            if (spreadPos == 0) {
+                // no leading arguments to preserve; go generic
+                MethodType res = genericMethodType(arrayLength);
+                if (rtype != Object.class) {
+                    res = res.changeReturnType(rtype);
+                }
+                return res;
+            }
+        }
+        Class<?> elemType = arrayType.getComponentType();
+        assert(elemType != null);
+        for (int i = spreadPos; i < ptypes.length; i++) {
+            if (ptypes[i] != elemType) {
+                Class<?>[] fixedPtypes = ptypes.clone();
+                Arrays.fill(fixedPtypes, i, ptypes.length, elemType);
+                return methodType(rtype, fixedPtypes);
+            }
+        }
+        return this;  // arguments check out; no change
+    }
+
+    /** Return the leading parameter type, which must exist and be a reference.
+     *  @return the leading parameter type, after error checks
+     */
+    /*non-public*/ Class<?> leadingReferenceParameter() {
+        Class<?> ptype;
+        if (ptypes.length == 0 ||
+            (ptype = ptypes[0]).isPrimitive())
+            throw newIllegalArgumentException("no leading reference parameter");
+        return ptype;
+    }
+
+    /** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
+     * @param arrayType any array type
+     * @param arrayLength the number of parameter types to insert
+     * @return the resulting type
+     */
+    /*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
+        assert(parameterCount() >= 1);
+        assert(lastParameterType().isAssignableFrom(arrayType));
+        MethodType res;
+        if (arrayType == Object[].class) {
+            res = genericMethodType(arrayLength);
+            if (rtype != Object.class) {
+                res = res.changeReturnType(rtype);
+            }
+        } else {
+            Class<?> elemType = arrayType.getComponentType();
+            assert(elemType != null);
+            res = methodType(rtype, Collections.nCopies(arrayLength, elemType));
+        }
+        if (ptypes.length == 1) {
+            return res;
+        } else {
+            return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
+        }
+    }
+
+    /**
+     * Finds or creates a method type with some parameter types omitted.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param start  the index (zero-based) of the first parameter type to remove
+     * @param end    the index (greater than {@code start}) of the first parameter type after not to remove
+     * @return the same type, except with the selected parameter(s) removed
+     * @throws IndexOutOfBoundsException if {@code start} is negative or greater than {@code parameterCount()}
+     *                                  or if {@code end} is negative or greater than {@code parameterCount()}
+     *                                  or if {@code start} is greater than {@code end}
+     */
+    public MethodType dropParameterTypes(int start, int end) {
+        int len = ptypes.length;
+        if (!(0 <= start && start <= end && end <= len))
+            throw newIndexOutOfBoundsException("start="+start+" end="+end);
+        if (start == end)  return this;
+        Class<?>[] nptypes;
+        if (start == 0) {
+            if (end == len) {
+                // drop all parameters
+                nptypes = NO_PTYPES;
+            } else {
+                // drop initial parameter(s)
+                nptypes = Arrays.copyOfRange(ptypes, end, len);
+            }
+        } else {
+            if (end == len) {
+                // drop trailing parameter(s)
+                nptypes = Arrays.copyOfRange(ptypes, 0, start);
+            } else {
+                int tail = len - end;
+                nptypes = Arrays.copyOfRange(ptypes, 0, start + tail);
+                System.arraycopy(ptypes, end, nptypes, start, tail);
+            }
+        }
+        return makeImpl(rtype, nptypes, true);
+    }
+
+    /**
+     * Finds or creates a method type with a different return type.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * @param nrtype a return parameter type to replace the old one with
+     * @return the same type, except with the return type change
+     * @throws NullPointerException if {@code nrtype} is null
+     */
+    public MethodType changeReturnType(Class<?> nrtype) {
+        if (returnType() == nrtype)  return this;
+        return makeImpl(nrtype, ptypes, true);
+    }
+
+    /**
+     * Reports if this type contains a primitive argument or return value.
+     * The return type {@code void} counts as a primitive.
+     * @return true if any of the types are primitives
+     */
+    public boolean hasPrimitives() {
+        return form.hasPrimitives();
+    }
+
+    /**
+     * Reports if this type contains a wrapper argument or return value.
+     * Wrappers are types which box primitive values, such as {@link Integer}.
+     * The reference type {@code java.lang.Void} counts as a wrapper,
+     * if it occurs as a return type.
+     * @return true if any of the types are wrappers
+     */
+    public boolean hasWrappers() {
+        return unwrap() != this;
+    }
+
+    /**
+     * Erases all reference types to {@code Object}.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * All primitive types (including {@code void}) will remain unchanged.
+     * @return a version of the original type with all reference types replaced
+     */
+    public MethodType erase() {
+        return form.erasedType();
+    }
+
+    // BEGIN Android-removed: Implementation methods unused on Android.
+    /*
+    /**
+     * Erases all reference types to {@code Object}, and all subword types to {@code int}.
+     * This is the reduced type polymorphism used by private methods
+     * such as {@link MethodHandle#invokeBasic invokeBasic}.
+     * @return a version of the original type with all reference and subword types replaced
+     *
+    /*non-public* MethodType basicType() {
+        return form.basicType();
+    }
+
+    /**
+     * @return a version of the original type with MethodHandle prepended as the first argument
+     *
+    /*non-public* MethodType invokerType() {
+        return insertParameterTypes(0, MethodHandle.class);
+    }
+    */
+    // END Android-removed: Implementation methods unused on Android.
+
+    /**
+     * Converts all types, both reference and primitive, to {@code Object}.
+     * Convenience method for {@link #genericMethodType(int) genericMethodType}.
+     * The expression {@code type.wrap().erase()} produces the same value
+     * as {@code type.generic()}.
+     * @return a version of the original type with all types replaced
+     */
+    public MethodType generic() {
+        return genericMethodType(parameterCount());
+    }
+
+    /*non-public*/ boolean isGeneric() {
+        return this == erase() && !hasPrimitives();
+    }
+
+    /**
+     * Converts all primitive types to their corresponding wrapper types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * All reference types (including wrapper types) will remain unchanged.
+     * A {@code void} return type is changed to the type {@code java.lang.Void}.
+     * The expression {@code type.wrap().erase()} produces the same value
+     * as {@code type.generic()}.
+     * @return a version of the original type with all primitive types replaced
+     */
+    public MethodType wrap() {
+        return hasPrimitives() ? wrapWithPrims(this) : this;
+    }
+
+    /**
+     * Converts all wrapper types to their corresponding primitive types.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * All primitive types (including {@code void}) will remain unchanged.
+     * A return type of {@code java.lang.Void} is changed to {@code void}.
+     * @return a version of the original type with all wrapper types replaced
+     */
+    public MethodType unwrap() {
+        MethodType noprims = !hasPrimitives() ? this : wrapWithPrims(this);
+        return unwrapWithNoPrims(noprims);
+    }
+
+    private static MethodType wrapWithPrims(MethodType pt) {
+        assert(pt.hasPrimitives());
+        MethodType wt = pt.wrapAlt;
+        if (wt == null) {
+            // fill in lazily
+            wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
+            assert(wt != null);
+            pt.wrapAlt = wt;
+        }
+        return wt;
+    }
+
+    private static MethodType unwrapWithNoPrims(MethodType wt) {
+        assert(!wt.hasPrimitives());
+        MethodType uwt = wt.wrapAlt;
+        if (uwt == null) {
+            // fill in lazily
+            uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
+            if (uwt == null)
+                uwt = wt;    // type has no wrappers or prims at all
+            wt.wrapAlt = uwt;
+        }
+        return uwt;
+    }
+
+    /**
+     * Returns the parameter type at the specified index, within this method type.
+     * @param num the index (zero-based) of the desired parameter type
+     * @return the selected parameter type
+     * @throws IndexOutOfBoundsException if {@code num} is not a valid index into {@code parameterArray()}
+     */
+    public Class<?> parameterType(int num) {
+        return ptypes[num];
+    }
+    /**
+     * Returns the number of parameter types in this method type.
+     * @return the number of parameter types
+     */
+    public int parameterCount() {
+        return ptypes.length;
+    }
+    /**
+     * Returns the return type of this method type.
+     * @return the return type
+     */
+    public Class<?> returnType() {
+        return rtype;
+    }
+
+    /**
+     * Presents the parameter types as a list (a convenience method).
+     * The list will be immutable.
+     * @return the parameter types (as an immutable list)
+     */
+    public List<Class<?>> parameterList() {
+        return Collections.unmodifiableList(Arrays.asList(ptypes.clone()));
+    }
+
+    /*non-public*/ Class<?> lastParameterType() {
+        int len = ptypes.length;
+        return len == 0 ? void.class : ptypes[len-1];
+    }
+
+    /**
+     * Presents the parameter types as an array (a convenience method).
+     * Changes to the array will not result in changes to the type.
+     * @return the parameter types (as a fresh copy if necessary)
+     */
+    public Class<?>[] parameterArray() {
+        return ptypes.clone();
+    }
+
+    /**
+     * Compares the specified object with this type for equality.
+     * That is, it returns <tt>true</tt> if and only if the specified object
+     * is also a method type with exactly the same parameters and return type.
+     * @param x object to compare
+     * @see Object#equals(Object)
+     */
+    @Override
+    public boolean equals(Object x) {
+        return this == x || x instanceof MethodType && equals((MethodType)x);
+    }
+
+    private boolean equals(MethodType that) {
+        return this.rtype == that.rtype
+            && Arrays.equals(this.ptypes, that.ptypes);
+    }
+
+    /**
+     * Returns the hash code value for this method type.
+     * It is defined to be the same as the hashcode of a List
+     * whose elements are the return type followed by the
+     * parameter types.
+     * @return the hash code value for this method type
+     * @see Object#hashCode()
+     * @see #equals(Object)
+     * @see List#hashCode()
+     */
+    @Override
+    public int hashCode() {
+      int hashCode = 31 + rtype.hashCode();
+      for (Class<?> ptype : ptypes)
+          hashCode = 31*hashCode + ptype.hashCode();
+      return hashCode;
+    }
+
+    /**
+     * Returns a string representation of the method type,
+     * of the form {@code "(PT0,PT1...)RT"}.
+     * The string representation of a method type is a
+     * parenthesis enclosed, comma separated list of type names,
+     * followed immediately by the return type.
+     * <p>
+     * Each type is represented by its
+     * {@link java.lang.Class#getSimpleName simple name}.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("(");
+        for (int i = 0; i < ptypes.length; i++) {
+            if (i > 0)  sb.append(",");
+            sb.append(ptypes[i].getSimpleName());
+        }
+        sb.append(")");
+        sb.append(rtype.getSimpleName());
+        return sb.toString();
+    }
+
+    // BEGIN Android-removed: Implementation methods unused on Android.
+    /*
+    /** True if the old return type can always be viewed (w/o casting) under new return type,
+     *  and the new parameters can be viewed (w/o casting) under the old parameter types.
+     *
+    /*non-public*
+    boolean isViewableAs(MethodType newType, boolean keepInterfaces) {
+        if (!VerifyType.isNullConversion(returnType(), newType.returnType(), keepInterfaces))
+            return false;
+        return parametersAreViewableAs(newType, keepInterfaces);
+    }
+    /** True if the new parameters can be viewed (w/o casting) under the old parameter types. *
+    /*non-public*
+    boolean parametersAreViewableAs(MethodType newType, boolean keepInterfaces) {
+        if (form == newType.form && form.erasedType == this)
+            return true;  // my reference parameters are all Object
+        if (ptypes == newType.ptypes)
+            return true;
+        int argc = parameterCount();
+        if (argc != newType.parameterCount())
+            return false;
+        for (int i = 0; i < argc; i++) {
+            if (!VerifyType.isNullConversion(newType.parameterType(i), parameterType(i), keepInterfaces))
+                return false;
+        }
+        return true;
+    }
+    */
+    // END Android-removed: Implementation methods unused on Android.
+
+    /*non-public*/
+    boolean isConvertibleTo(MethodType newType) {
+        MethodTypeForm oldForm = this.form();
+        MethodTypeForm newForm = newType.form();
+        if (oldForm == newForm)
+            // same parameter count, same primitive/object mix
+            return true;
+        if (!canConvert(returnType(), newType.returnType()))
+            return false;
+        Class<?>[] srcTypes = newType.ptypes;
+        Class<?>[] dstTypes = ptypes;
+        if (srcTypes == dstTypes)
+            return true;
+        int argc;
+        if ((argc = srcTypes.length) != dstTypes.length)
+            return false;
+        if (argc <= 1) {
+            if (argc == 1 && !canConvert(srcTypes[0], dstTypes[0]))
+                return false;
+            return true;
+        }
+        if ((oldForm.primitiveParameterCount() == 0 && oldForm.erasedType == this) ||
+            (newForm.primitiveParameterCount() == 0 && newForm.erasedType == newType)) {
+            // Somewhat complicated test to avoid a loop of 2 or more trips.
+            // If either type has only Object parameters, we know we can convert.
+            assert(canConvertParameters(srcTypes, dstTypes));
+            return true;
+        }
+        return canConvertParameters(srcTypes, dstTypes);
+    }
+
+    /** Returns true if MHs.explicitCastArguments produces the same result as MH.asType.
+     *  If the type conversion is impossible for either, the result should be false.
+     */
+    /*non-public*/
+    boolean explicitCastEquivalentToAsType(MethodType newType) {
+        if (this == newType)  return true;
+        if (!explicitCastEquivalentToAsType(rtype, newType.rtype)) {
+            return false;
+        }
+        Class<?>[] srcTypes = newType.ptypes;
+        Class<?>[] dstTypes = ptypes;
+        if (dstTypes == srcTypes) {
+            return true;
+        }
+        assert(dstTypes.length == srcTypes.length);
+        for (int i = 0; i < dstTypes.length; i++) {
+            if (!explicitCastEquivalentToAsType(srcTypes[i], dstTypes[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /** Reports true if the src can be converted to the dst, by both asType and MHs.eCE,
+     *  and with the same effect.
+     *  MHs.eCA has the following "upgrades" to MH.asType:
+     *  1. interfaces are unchecked (that is, treated as if aliased to Object)
+     *     Therefore, {@code Object->CharSequence} is possible in both cases but has different semantics
+     *  2a. the full matrix of primitive-to-primitive conversions is supported
+     *      Narrowing like {@code long->byte} and basic-typing like {@code boolean->int}
+     *      are not supported by asType, but anything supported by asType is equivalent
+     *      with MHs.eCE.
+     *  2b. conversion of void->primitive means explicit cast has to insert zero/false/null.
+     *  3a. unboxing conversions can be followed by the full matrix of primitive conversions
+     *  3b. unboxing of null is permitted (creates a zero primitive value)
+     * Other than interfaces, reference-to-reference conversions are the same.
+     * Boxing primitives to references is the same for both operators.
+     */
+    private static boolean explicitCastEquivalentToAsType(Class<?> src, Class<?> dst) {
+        if (src == dst || dst == Object.class || dst == void.class)  return true;
+        if (src.isPrimitive()) {
+            // Could be a prim/prim conversion, where casting is a strict superset.
+            // Or a boxing conversion, which is always to an exact wrapper class.
+            return canConvert(src, dst);
+        } else if (dst.isPrimitive()) {
+            // Unboxing behavior is different between MHs.eCA & MH.asType (see 3b).
+            return false;
+        } else {
+            // R->R always works, but we have to avoid a check-cast to an interface.
+            return !dst.isInterface() || dst.isAssignableFrom(src);
+        }
+    }
+
+    private boolean canConvertParameters(Class<?>[] srcTypes, Class<?>[] dstTypes) {
+        for (int i = 0; i < srcTypes.length; i++) {
+            if (!canConvert(srcTypes[i], dstTypes[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*non-public*/
+    static boolean canConvert(Class<?> src, Class<?> dst) {
+        // short-circuit a few cases:
+        if (src == dst || src == Object.class || dst == Object.class)  return true;
+        // the remainder of this logic is documented in MethodHandle.asType
+        if (src.isPrimitive()) {
+            // can force void to an explicit null, a la reflect.Method.invoke
+            // can also force void to a primitive zero, by analogy
+            if (src == void.class)  return true;  //or !dst.isPrimitive()?
+            Wrapper sw = Wrapper.forPrimitiveType(src);
+            if (dst.isPrimitive()) {
+                // P->P must widen
+                return Wrapper.forPrimitiveType(dst).isConvertibleFrom(sw);
+            } else {
+                // P->R must box and widen
+                return dst.isAssignableFrom(sw.wrapperType());
+            }
+        } else if (dst.isPrimitive()) {
+            // any value can be dropped
+            if (dst == void.class)  return true;
+            Wrapper dw = Wrapper.forPrimitiveType(dst);
+            // R->P must be able to unbox (from a dynamically chosen type) and widen
+            // For example:
+            //   Byte/Number/Comparable/Object -> dw:Byte -> byte.
+            //   Character/Comparable/Object -> dw:Character -> char
+            //   Boolean/Comparable/Object -> dw:Boolean -> boolean
+            // This means that dw must be cast-compatible with src.
+            if (src.isAssignableFrom(dw.wrapperType())) {
+                return true;
+            }
+            // The above does not work if the source reference is strongly typed
+            // to a wrapper whose primitive must be widened.  For example:
+            //   Byte -> unbox:byte -> short/int/long/float/double
+            //   Character -> unbox:char -> int/long/float/double
+            if (Wrapper.isWrapperType(src) &&
+                dw.isConvertibleFrom(Wrapper.forWrapperType(src))) {
+                // can unbox from src and then widen to dst
+                return true;
+            }
+            // We have already covered cases which arise due to runtime unboxing
+            // of a reference type which covers several wrapper types:
+            //   Object -> cast:Integer -> unbox:int -> long/float/double
+            //   Serializable -> cast:Byte -> unbox:byte -> byte/short/int/long/float/double
+            // An marginal case is Number -> dw:Character -> char, which would be OK if there were a
+            // subclass of Number which wraps a value that can convert to char.
+            // Since there is none, we don't need an extra check here to cover char or boolean.
+            return false;
+        } else {
+            // R->R always works, since null is always valid dynamically
+            return true;
+        }
+    }
+
+    /// Queries which have to do with the bytecode architecture
+
+    /** Reports the number of JVM stack slots required to invoke a method
+     * of this type.  Note that (for historical reasons) the JVM requires
+     * a second stack slot to pass long and double arguments.
+     * So this method returns {@link #parameterCount() parameterCount} plus the
+     * number of long and double parameters (if any).
+     * <p>
+     * This method is included for the benefit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @return the number of JVM stack slots for this type's parameters
+     */
+    /*non-public*/ int parameterSlotCount() {
+        return form.parameterSlotCount();
+    }
+
+    // BEGIN Android-removed: Cache of higher order adapters.
+    /*
+    /*non-public* Invokers invokers() {
+        Invokers inv = invokers;
+        if (inv != null)  return inv;
+        invokers = inv = new Invokers(this);
+        return inv;
+    }
+    */
+    // END Android-removed: Cache of higher order adapters.
+
+    // BEGIN Android-removed: Implementation methods unused on Android.
+    /*
+    /** Reports the number of JVM stack slots which carry all parameters including and after
+     * the given position, which must be in the range of 0 to
+     * {@code parameterCount} inclusive.  Successive parameters are
+     * more shallowly stacked, and parameters are indexed in the bytecodes
+     * according to their trailing edge.  Thus, to obtain the depth
+     * in the outgoing call stack of parameter {@code N}, obtain
+     * the {@code parameterSlotDepth} of its trailing edge
+     * at position {@code N+1}.
+     * <p>
+     * Parameters of type {@code long} and {@code double} occupy
+     * two stack slots (for historical reasons) and all others occupy one.
+     * Therefore, the number returned is the number of arguments
+     * <em>including</em> and <em>after</em> the given parameter,
+     * <em>plus</em> the number of long or double arguments
+     * at or after after the argument for the given parameter.
+     * <p>
+     * This method is included for the benefit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @param num an index (zero-based, inclusive) within the parameter types
+     * @return the index of the (shallowest) JVM stack slot transmitting the
+     *         given parameter
+     * @throws IllegalArgumentException if {@code num} is negative or greater than {@code parameterCount()}
+     *
+    /*non-public* int parameterSlotDepth(int num) {
+        if (num < 0 || num > ptypes.length)
+            parameterType(num);  // force a range check
+        return form.parameterToArgSlot(num-1);
+    }
+
+    /** Reports the number of JVM stack slots required to receive a return value
+     * from a method of this type.
+     * If the {@link #returnType() return type} is void, it will be zero,
+     * else if the return type is long or double, it will be two, else one.
+     * <p>
+     * This method is included for the benefit of applications that must
+     * generate bytecodes that process method handles and invokedynamic.
+     * @return the number of JVM stack slots (0, 1, or 2) for this type's return value
+     * Will be removed for PFD.
+     *
+    /*non-public* int returnSlotCount() {
+        return form.returnSlotCount();
+    }
+    */
+    // END Android-removed: Implementation methods unused on Android.
+
+    /**
+     * Finds or creates an instance of a method type, given the spelling of its bytecode descriptor.
+     * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
+     * Any class or interface name embedded in the descriptor string
+     * will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
+     * on the given loader (or if it is null, on the system class loader).
+     * <p>
+     * Note that it is possible to encounter method types which cannot be
+     * constructed by this method, because their component types are
+     * not all reachable from a common class loader.
+     * <p>
+     * This method is included for the benefit of applications that must
+     * generate bytecodes that process method handles and {@code invokedynamic}.
+     * @param descriptor a bytecode-level type descriptor string "(T...)T"
+     * @param loader the class loader in which to look up the types
+     * @return a method type matching the bytecode-level type descriptor
+     * @throws NullPointerException if the string is null
+     * @throws IllegalArgumentException if the string is not well-formed
+     * @throws TypeNotPresentException if a named type cannot be found
+     */
+    public static MethodType fromMethodDescriptorString(String descriptor, ClassLoader loader)
+        throws IllegalArgumentException, TypeNotPresentException
+    {
+        if (!descriptor.startsWith("(") ||  // also generates NPE if needed
+            descriptor.indexOf(')') < 0 ||
+            descriptor.indexOf('.') >= 0)
+            throw newIllegalArgumentException("not a method descriptor: "+descriptor);
+        List<Class<?>> types = BytecodeDescriptor.parseMethod(descriptor, loader);
+        Class<?> rtype = types.remove(types.size() - 1);
+        checkSlotCount(types.size());
+        Class<?>[] ptypes = listToArray(types);
+        return makeImpl(rtype, ptypes, true);
+    }
+
+    /**
+     * Produces a bytecode descriptor representation of the method type.
+     * <p>
+     * Note that this is not a strict inverse of {@link #fromMethodDescriptorString fromMethodDescriptorString}.
+     * Two distinct classes which share a common name but have different class loaders
+     * will appear identical when viewed within descriptor strings.
+     * <p>
+     * This method is included for the benefit of applications that must
+     * generate bytecodes that process method handles and {@code invokedynamic}.
+     * {@link #fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) fromMethodDescriptorString},
+     * because the latter requires a suitable class loader argument.
+     * @return the bytecode type descriptor representation
+     */
+    public String toMethodDescriptorString() {
+        String desc = methodDescriptor;
+        if (desc == null) {
+            desc = BytecodeDescriptor.unparse(this);
+            methodDescriptor = desc;
+        }
+        return desc;
+    }
+
+    /*non-public*/ static String toFieldDescriptorString(Class<?> cls) {
+        return BytecodeDescriptor.unparse(cls);
+    }
+
+    /// Serialization.
+
+    /**
+     * There are no serializable fields for {@code MethodType}.
+     */
+    private static final java.io.ObjectStreamField[] serialPersistentFields = { };
+
+    /**
+     * Save the {@code MethodType} instance to a stream.
+     *
+     * @serialData
+     * For portability, the serialized format does not refer to named fields.
+     * Instead, the return type and parameter type arrays are written directly
+     * from the {@code writeObject} method, using two calls to {@code s.writeObject}
+     * as follows:
+     * <blockquote><pre>{@code
+s.writeObject(this.returnType());
+s.writeObject(this.parameterArray());
+     * }</pre></blockquote>
+     * <p>
+     * The deserialized field values are checked as if they were
+     * provided to the factory method {@link #methodType(Class,Class[]) methodType}.
+     * For example, null values, or {@code void} parameter types,
+     * will lead to exceptions during deserialization.
+     * @param s the stream to write the object to
+     * @throws java.io.IOException if there is a problem writing the object
+     */
+    private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+        s.defaultWriteObject();  // requires serialPersistentFields to be an empty array
+        s.writeObject(returnType());
+        s.writeObject(parameterArray());
+    }
+
+    /**
+     * Reconstitute the {@code MethodType} instance from a stream (that is,
+     * deserialize it).
+     * This instance is a scratch object with bogus final fields.
+     * It provides the parameters to the factory method called by
+     * {@link #readResolve readResolve}.
+     * After that call it is discarded.
+     * @param s the stream to read the object from
+     * @throws java.io.IOException if there is a problem reading the object
+     * @throws ClassNotFoundException if one of the component classes cannot be resolved
+     * @see #MethodType()
+     * @see #readResolve
+     * @see #writeObject
+     */
+    private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();  // requires serialPersistentFields to be an empty array
+
+        Class<?>   returnType     = (Class<?>)   s.readObject();
+        Class<?>[] parameterArray = (Class<?>[]) s.readObject();
+
+        // Probably this object will never escape, but let's check
+        // the field values now, just to be sure.
+        checkRtype(returnType);
+        checkPtypes(parameterArray);
+
+        parameterArray = parameterArray.clone();  // make sure it is unshared
+        MethodType_init(returnType, parameterArray);
+    }
+
+    /**
+     * For serialization only.
+     * Sets the final fields to null, pending {@code Unsafe.putObject}.
+     */
+    private MethodType() {
+        this.rtype = null;
+        this.ptypes = null;
+    }
+    private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
+        // In order to communicate these values to readResolve, we must
+        // store them into the implementation-specific final fields.
+        checkRtype(rtype);
+        checkPtypes(ptypes);
+        UNSAFE.putObject(this, rtypeOffset, rtype);
+        UNSAFE.putObject(this, ptypesOffset, ptypes);
+    }
+
+    // Support for resetting final fields while deserializing
+    private static final long rtypeOffset, ptypesOffset;
+    static {
+        try {
+            rtypeOffset = UNSAFE.objectFieldOffset
+                (MethodType.class.getDeclaredField("rtype"));
+            ptypesOffset = UNSAFE.objectFieldOffset
+                (MethodType.class.getDeclaredField("ptypes"));
+        } catch (Exception ex) {
+            throw new Error(ex);
+        }
+    }
+
+    /**
+     * Resolves and initializes a {@code MethodType} object
+     * after serialization.
+     * @return the fully initialized {@code MethodType} object
+     */
+    private Object readResolve() {
+        // Do not use a trusted path for deserialization:
+        //return makeImpl(rtype, ptypes, true);
+        // Verify all operands, and make sure ptypes is unshared:
+        return methodType(rtype, ptypes);
+    }
+
+    /**
+     * Simple implementation of weak concurrent intern set.
+     *
+     * @param <T> interned type
+     */
+    private static class ConcurrentWeakInternSet<T> {
+
+        private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map;
+        private final ReferenceQueue<T> stale;
+
+        public ConcurrentWeakInternSet() {
+            this.map = new ConcurrentHashMap<>();
+            this.stale = new ReferenceQueue<>();
+        }
+
+        /**
+         * Get the existing interned element.
+         * This method returns null if no element is interned.
+         *
+         * @param elem element to look up
+         * @return the interned element
+         */
+        public T get(T elem) {
+            if (elem == null) throw new NullPointerException();
+            expungeStaleElements();
+
+            WeakEntry<T> value = map.get(new WeakEntry<>(elem));
+            if (value != null) {
+                T res = value.get();
+                if (res != null) {
+                    return res;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Interns the element.
+         * Always returns non-null element, matching the one in the intern set.
+         * Under the race against another add(), it can return <i>different</i>
+         * element, if another thread beats us to interning it.
+         *
+         * @param elem element to add
+         * @return element that was actually added
+         */
+        public T add(T elem) {
+            if (elem == null) throw new NullPointerException();
+
+            // Playing double race here, and so spinloop is required.
+            // First race is with two concurrent updaters.
+            // Second race is with GC purging weak ref under our feet.
+            // Hopefully, we almost always end up with a single pass.
+            T interned;
+            WeakEntry<T> e = new WeakEntry<>(elem, stale);
+            do {
+                expungeStaleElements();
+                WeakEntry<T> exist = map.putIfAbsent(e, e);
+                interned = (exist == null) ? elem : exist.get();
+            } while (interned == null);
+            return interned;
+        }
+
+        private void expungeStaleElements() {
+            Reference<? extends T> reference;
+            while ((reference = stale.poll()) != null) {
+                map.remove(reference);
+            }
+        }
+
+        private static class WeakEntry<T> extends WeakReference<T> {
+
+            public final int hashcode;
+
+            public WeakEntry(T key, ReferenceQueue<T> queue) {
+                super(key, queue);
+                hashcode = key.hashCode();
+            }
+
+            public WeakEntry(T key) {
+                super(key);
+                hashcode = key.hashCode();
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                if (obj instanceof WeakEntry) {
+                    Object that = ((WeakEntry) obj).get();
+                    Object mine = get();
+                    return (that == null || mine == null) ? (this == obj) : mine.equals(that);
+                }
+                return false;
+            }
+
+            @Override
+            public int hashCode() {
+                return hashcode;
+            }
+
+        }
+    }
+
+}
diff --git a/java/lang/invoke/MethodTypeForm.java b/java/lang/invoke/MethodTypeForm.java
new file mode 100644
index 0000000..6f6c2a8
--- /dev/null
+++ b/java/lang/invoke/MethodTypeForm.java
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+import java.lang.ref.SoftReference;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * Shared information for a group of method types, which differ
+ * only by reference types, and therefore share a common erasure
+ * and wrapping.
+ * <p>
+ * For an empirical discussion of the structure of method types,
+ * see <a href="http://groups.google.com/group/jvm-languages/browse_thread/thread/ac9308ae74da9b7e/">
+ * the thread "Avoiding Boxing" on jvm-languages</a>.
+ * There are approximately 2000 distinct erased method types in the JDK.
+ * There are a little over 10 times that number of unerased types.
+ * No more than half of these are likely to be loaded at once.
+ * @author John Rose
+ */
+final class MethodTypeForm {
+    final int[] argToSlotTable, slotToArgTable;
+    final long argCounts;               // packed slot & value counts
+    final long primCounts;              // packed prim & double counts
+    final MethodType erasedType;        // the canonical erasure
+    final MethodType basicType;         // the canonical erasure, with primitives simplified
+
+    // BEGIN Android-removed: Cached adaptors / lambda forms.
+    // The upstream caching mechanism will not work on Android because of fundamental differences
+    // in the Android runtime/implementation of MethodHandle. LambdaForm is not supported on
+    // Android for similar reasons.
+    /*
+    // Cached adapter information:
+    @Stable final SoftReference<MethodHandle>[] methodHandles;
+    // Indexes into methodHandles:
+    static final int
+            MH_BASIC_INV      =  0,  // cached instance of MH.invokeBasic
+            MH_NF_INV         =  1,  // cached helper for LF.NamedFunction
+            MH_UNINIT_CS      =  2,  // uninitialized call site
+            MH_LIMIT          =  3;
+
+    // Cached lambda form information, for basic types only:
+    final @Stable SoftReference<LambdaForm>[] lambdaForms;
+    // Indexes into lambdaForms:
+    static final int
+            LF_INVVIRTUAL              =  0,  // DMH invokeVirtual
+            LF_INVSTATIC               =  1,
+            LF_INVSPECIAL              =  2,
+            LF_NEWINVSPECIAL           =  3,
+            LF_INVINTERFACE            =  4,
+            LF_INVSTATIC_INIT          =  5,  // DMH invokeStatic with <clinit> barrier
+            LF_INTERPRET               =  6,  // LF interpreter
+            LF_REBIND                  =  7,  // BoundMethodHandle
+            LF_DELEGATE                =  8,  // DelegatingMethodHandle
+            LF_DELEGATE_BLOCK_INLINING =  9,  // Counting DelegatingMethodHandle w/ @DontInline
+            LF_EX_LINKER               = 10,  // invokeExact_MT (for invokehandle)
+            LF_EX_INVOKER              = 11,  // MHs.invokeExact
+            LF_GEN_LINKER              = 12,  // generic invoke_MT (for invokehandle)
+            LF_GEN_INVOKER             = 13,  // generic MHs.invoke
+            LF_CS_LINKER               = 14,  // linkToCallSite_CS
+            LF_MH_LINKER               = 15,  // linkToCallSite_MH
+            LF_GWC                     = 16,  // guardWithCatch (catchException)
+            LF_GWT                     = 17,  // guardWithTest
+            LF_LIMIT                   = 18;
+    */
+    // END Android-removed: Cached adaptors / lambda forms.
+
+    /** Return the type corresponding uniquely (1-1) to this MT-form.
+     *  It might have any primitive returns or arguments, but will have no references except Object.
+     */
+    public MethodType erasedType() {
+        return erasedType;
+    }
+
+    /** Return the basic type derived from the erased type of this MT-form.
+     *  A basic type is erased (all references Object) and also has all primitive
+     *  types (except int, long, float, double, void) normalized to int.
+     *  Such basic types correspond to low-level JVM calling sequences.
+     */
+    public MethodType basicType() {
+        return basicType;
+    }
+
+    private boolean assertIsBasicType() {
+        // primitives must be flattened also
+        assert(erasedType == basicType)
+                : "erasedType: " + erasedType + " != basicType: " + basicType;
+        return true;
+    }
+
+    // BEGIN Android-removed: Cached adaptors / lambda forms.
+    /*
+    public MethodHandle cachedMethodHandle(int which) {
+        assert(assertIsBasicType());
+        SoftReference<MethodHandle> entry = methodHandles[which];
+        return (entry != null) ? entry.get() : null;
+    }
+
+    synchronized public MethodHandle setCachedMethodHandle(int which, MethodHandle mh) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        SoftReference<MethodHandle> entry = methodHandles[which];
+        if (entry != null) {
+            MethodHandle prev = entry.get();
+            if (prev != null) {
+                return prev;
+            }
+        }
+        methodHandles[which] = new SoftReference<>(mh);
+        return mh;
+    }
+
+    public LambdaForm cachedLambdaForm(int which) {
+        assert(assertIsBasicType());
+        SoftReference<LambdaForm> entry = lambdaForms[which];
+        return (entry != null) ? entry.get() : null;
+    }
+
+    synchronized public LambdaForm setCachedLambdaForm(int which, LambdaForm form) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        SoftReference<LambdaForm> entry = lambdaForms[which];
+        if (entry != null) {
+            LambdaForm prev = entry.get();
+            if (prev != null) {
+                return prev;
+            }
+        }
+        lambdaForms[which] = new SoftReference<>(form);
+        return form;
+    }
+    */
+    // END Android-removed: Cached adaptors / lambda forms.
+
+    /**
+     * Build an MTF for a given type, which must have all references erased to Object.
+     * This MTF will stand for that type and all un-erased variations.
+     * Eagerly compute some basic properties of the type, common to all variations.
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected MethodTypeForm(MethodType erasedType) {
+        this.erasedType = erasedType;
+
+        Class<?>[] ptypes = erasedType.ptypes();
+        int ptypeCount = ptypes.length;
+        int pslotCount = ptypeCount;            // temp. estimate
+        int rtypeCount = 1;                     // temp. estimate
+        int rslotCount = 1;                     // temp. estimate
+
+        int[] argToSlotTab = null, slotToArgTab = null;
+
+        // Walk the argument types, looking for primitives.
+        int pac = 0, lac = 0, prc = 0, lrc = 0;
+        Class<?>[] epts = ptypes;
+        Class<?>[] bpts = epts;
+        for (int i = 0; i < epts.length; i++) {
+            Class<?> pt = epts[i];
+            if (pt != Object.class) {
+                ++pac;
+                Wrapper w = Wrapper.forPrimitiveType(pt);
+                if (w.isDoubleWord())  ++lac;
+                if (w.isSubwordOrInt() && pt != int.class) {
+                    if (bpts == epts)
+                        bpts = bpts.clone();
+                    bpts[i] = int.class;
+                }
+            }
+        }
+        pslotCount += lac;                  // #slots = #args + #longs
+        Class<?> rt = erasedType.returnType();
+        Class<?> bt = rt;
+        if (rt != Object.class) {
+            ++prc;          // even void.class counts as a prim here
+            Wrapper w = Wrapper.forPrimitiveType(rt);
+            if (w.isDoubleWord())  ++lrc;
+            if (w.isSubwordOrInt() && rt != int.class)
+                bt = int.class;
+            // adjust #slots, #args
+            if (rt == void.class)
+                rtypeCount = rslotCount = 0;
+            else
+                rslotCount += lrc;
+        }
+        if (epts == bpts && bt == rt) {
+            this.basicType = erasedType;
+        } else {
+            this.basicType = MethodType.makeImpl(bt, bpts, true);
+            // fill in rest of data from the basic type:
+            MethodTypeForm that = this.basicType.form();
+            assert(this != that);
+            this.primCounts = that.primCounts;
+            this.argCounts = that.argCounts;
+            this.argToSlotTable = that.argToSlotTable;
+            this.slotToArgTable = that.slotToArgTable;
+            // Android-removed: Cached adaptors / lambda forms.
+            // this.methodHandles = null;
+            // this.lambdaForms = null;
+            return;
+        }
+        if (lac != 0) {
+            int slot = ptypeCount + lac;
+            slotToArgTab = new int[slot+1];
+            argToSlotTab = new int[1+ptypeCount];
+            argToSlotTab[0] = slot;  // argument "-1" is past end of slots
+            for (int i = 0; i < epts.length; i++) {
+                Class<?> pt = epts[i];
+                Wrapper w = Wrapper.forBasicType(pt);
+                if (w.isDoubleWord())  --slot;
+                --slot;
+                slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+                argToSlotTab[1+i]  = slot;
+            }
+            assert(slot == 0);  // filled the table
+        } else if (pac != 0) {
+            // have primitives but no long primitives; share slot counts with generic
+            assert(ptypeCount == pslotCount);
+            MethodTypeForm that = MethodType.genericMethodType(ptypeCount).form();
+            assert(this != that);
+            slotToArgTab = that.slotToArgTable;
+            argToSlotTab = that.argToSlotTable;
+        } else {
+            int slot = ptypeCount; // first arg is deepest in stack
+            slotToArgTab = new int[slot+1];
+            argToSlotTab = new int[1+ptypeCount];
+            argToSlotTab[0] = slot;  // argument "-1" is past end of slots
+            for (int i = 0; i < ptypeCount; i++) {
+                --slot;
+                slotToArgTab[slot] = i+1; // "+1" see argSlotToParameter note
+                argToSlotTab[1+i]  = slot;
+            }
+        }
+        this.primCounts = pack(lrc, prc, lac, pac);
+        this.argCounts = pack(rslotCount, rtypeCount, pslotCount, ptypeCount);
+        this.argToSlotTable = argToSlotTab;
+        this.slotToArgTable = slotToArgTab;
+
+        if (pslotCount >= 256)  throw newIllegalArgumentException("too many arguments");
+
+        // Initialize caches, but only for basic types
+        assert(basicType == erasedType);
+        // Android-removed: Cached adaptors / lambda forms.
+        // this.lambdaForms   = new SoftReference[LF_LIMIT];
+        // this.methodHandles = new SoftReference[MH_LIMIT];
+    }
+
+    private static long pack(int a, int b, int c, int d) {
+        assert(((a|b|c|d) & ~0xFFFF) == 0);
+        long hw = ((a << 16) | b), lw = ((c << 16) | d);
+        return (hw << 32) | lw;
+    }
+    private static char unpack(long packed, int word) { // word==0 => return a, ==3 => return d
+        assert(word <= 3);
+        return (char)(packed >> ((3-word) * 16));
+    }
+
+    public int parameterCount() {                      // # outgoing values
+        return unpack(argCounts, 3);
+    }
+    public int parameterSlotCount() {                  // # outgoing interpreter slots
+        return unpack(argCounts, 2);
+    }
+    public int returnCount() {                         // = 0 (V), or 1
+        return unpack(argCounts, 1);
+    }
+    public int returnSlotCount() {                     // = 0 (V), 2 (J/D), or 1
+        return unpack(argCounts, 0);
+    }
+    public int primitiveParameterCount() {
+        return unpack(primCounts, 3);
+    }
+    public int longPrimitiveParameterCount() {
+        return unpack(primCounts, 2);
+    }
+    public int primitiveReturnCount() {                // = 0 (obj), or 1
+        return unpack(primCounts, 1);
+    }
+    public int longPrimitiveReturnCount() {            // = 1 (J/D), or 0
+        return unpack(primCounts, 0);
+    }
+    public boolean hasPrimitives() {
+        return primCounts != 0;
+    }
+    public boolean hasNonVoidPrimitives() {
+        if (primCounts == 0)  return false;
+        if (primitiveParameterCount() != 0)  return true;
+        return (primitiveReturnCount() != 0 && returnCount() != 0);
+    }
+    public boolean hasLongPrimitives() {
+        return (longPrimitiveParameterCount() | longPrimitiveReturnCount()) != 0;
+    }
+    public int parameterToArgSlot(int i) {
+        return argToSlotTable[1+i];
+    }
+    public int argSlotToParameter(int argSlot) {
+        // Note:  Empty slots are represented by zero in this table.
+        // Valid arguments slots contain incremented entries, so as to be non-zero.
+        // We return -1 the caller to mean an empty slot.
+        return slotToArgTable[argSlot] - 1;
+    }
+
+    static MethodTypeForm findForm(MethodType mt) {
+        MethodType erased = canonicalize(mt, ERASE, ERASE);
+        if (erased == null) {
+            // It is already erased.  Make a new MethodTypeForm.
+            return new MethodTypeForm(mt);
+        } else {
+            // Share the MethodTypeForm with the erased version.
+            return erased.form();
+        }
+    }
+
+    /** Codes for {@link #canonicalize(java.lang.Class, int)}.
+     * ERASE means change every reference to {@code Object}.
+     * WRAP means convert primitives (including {@code void} to their
+     * corresponding wrapper types.  UNWRAP means the reverse of WRAP.
+     * INTS means convert all non-void primitive types to int or long,
+     * according to size.  LONGS means convert all non-void primitives
+     * to long, regardless of size.  RAW_RETURN means convert a type
+     * (assumed to be a return type) to int if it is smaller than an int,
+     * or if it is void.
+     */
+    public static final int NO_CHANGE = 0, ERASE = 1, WRAP = 2, UNWRAP = 3, INTS = 4, LONGS = 5, RAW_RETURN = 6;
+
+    /** Canonicalize the types in the given method type.
+     * If any types change, intern the new type, and return it.
+     * Otherwise return null.
+     */
+    public static MethodType canonicalize(MethodType mt, int howRet, int howArgs) {
+        Class<?>[] ptypes = mt.ptypes();
+        Class<?>[] ptc = MethodTypeForm.canonicalizeAll(ptypes, howArgs);
+        Class<?> rtype = mt.returnType();
+        Class<?> rtc = MethodTypeForm.canonicalize(rtype, howRet);
+        if (ptc == null && rtc == null) {
+            // It is already canonical.
+            return null;
+        }
+        // Find the erased version of the method type:
+        if (rtc == null)  rtc = rtype;
+        if (ptc == null)  ptc = ptypes;
+        return MethodType.makeImpl(rtc, ptc, true);
+    }
+
+    /** Canonicalize the given return or param type.
+     *  Return null if the type is already canonicalized.
+     */
+    static Class<?> canonicalize(Class<?> t, int how) {
+        Class<?> ct;
+        if (t == Object.class) {
+            // no change, ever
+        } else if (!t.isPrimitive()) {
+            switch (how) {
+                case UNWRAP:
+                    ct = Wrapper.asPrimitiveType(t);
+                    if (ct != t)  return ct;
+                    break;
+                case RAW_RETURN:
+                case ERASE:
+                    return Object.class;
+            }
+        } else if (t == void.class) {
+            // no change, usually
+            switch (how) {
+                case RAW_RETURN:
+                    return int.class;
+                case WRAP:
+                    return Void.class;
+            }
+        } else {
+            // non-void primitive
+            switch (how) {
+                case WRAP:
+                    return Wrapper.asWrapperType(t);
+                case INTS:
+                    if (t == int.class || t == long.class)
+                        return null;  // no change
+                    if (t == double.class)
+                        return long.class;
+                    return int.class;
+                case LONGS:
+                    if (t == long.class)
+                        return null;  // no change
+                    return long.class;
+                case RAW_RETURN:
+                    if (t == int.class || t == long.class ||
+                        t == float.class || t == double.class)
+                        return null;  // no change
+                    // everything else returns as an int
+                    return int.class;
+            }
+        }
+        // no change; return null to signify
+        return null;
+    }
+
+    /** Canonicalize each param type in the given array.
+     *  Return null if all types are already canonicalized.
+     */
+    static Class<?>[] canonicalizeAll(Class<?>[] ts, int how) {
+        Class<?>[] cs = null;
+        for (int imax = ts.length, i = 0; i < imax; i++) {
+            Class<?> c = canonicalize(ts[i], how);
+            if (c == void.class)
+                c = null;  // a Void parameter was unwrapped to void; ignore
+            if (c != null) {
+                if (cs == null)
+                    cs = ts.clone();
+                cs[i] = c;
+            }
+        }
+        return cs;
+    }
+
+    @Override
+    public String toString() {
+        return "Form"+erasedType;
+    }
+}
diff --git a/java/lang/invoke/MutableCallSite.java b/java/lang/invoke/MutableCallSite.java
new file mode 100644
index 0000000..305579f
--- /dev/null
+++ b/java/lang/invoke/MutableCallSite.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: removed references to MutableCallSite.syncAll().
+/**
+ * A {@code MutableCallSite} is a {@link CallSite} whose target variable
+ * behaves like an ordinary field.
+ * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
+ * all calls to the site's current target.
+ * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
+ * also delegates each call to the site's current target.
+ * <p>
+ * Here is an example of a mutable call site which introduces a
+ * state variable into a method handle chain.
+ * <!-- JavaDocExamplesTest.testMutableCallSite -->
+ * <blockquote><pre>{@code
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str1 = MethodType.methodType(String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+    .findVirtual(String.class, "toUpperCase", MT_str1);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+ * }</pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>{@code
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+  "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+ * }</pre></blockquote>
+ * <p>
+ * <em>Non-synchronization of target values:</em>
+ * A write to a mutable call site's target does not force other threads
+ * to become aware of the updated value.  Threads which do not perform
+ * suitable synchronization actions relative to the updated call site
+ * may cache the old target value and delay their use of the new target
+ * value indefinitely.
+ * (This is a normal consequence of the Java Memory Model as applied
+ * to object fields.)
+ * <p>
+ * For target values which will be frequently updated, consider using
+ * a {@linkplain VolatileCallSite volatile call site} instead.
+ * @author John Rose, JSR 292 EG
+ */
+public class MutableCallSite extends CallSite {
+    /**
+     * Creates a blank call site object with the given method type.
+     * The initial target is set to a method handle of the given type
+     * which will throw an {@link IllegalStateException} if called.
+     * <p>
+     * The type of the call site is permanently set to the given type.
+     * <p>
+     * Before this {@code CallSite} object is returned from a bootstrap method,
+     * or invoked in some other manner,
+     * it is usually provided with a more useful target method,
+     * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+     * @param type the method type that this call site will have
+     * @throws NullPointerException if the proposed type is null
+     */
+    public MutableCallSite(MethodType type) {
+        super(type);
+    }
+
+    /**
+     * Creates a call site object with an initial target method handle.
+     * The type of the call site is permanently set to the initial target's type.
+     * @param target the method handle that will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public MutableCallSite(MethodHandle target) {
+        super(target);
+    }
+
+    /**
+     * Returns the target method of the call site, which behaves
+     * like a normal field of the {@code MutableCallSite}.
+     * <p>
+     * The interactions of {@code getTarget} with memory are the same
+     * as of a read from an ordinary variable, such as an array element or a
+     * non-volatile, non-final field.
+     * <p>
+     * In particular, the current thread may choose to reuse the result
+     * of a previous read of the target from memory, and may fail to see
+     * a recent update to the target by another thread.
+     *
+     * @return the linkage state of this call site, a method handle which can change over time
+     * @see #setTarget
+     */
+    @Override public final MethodHandle getTarget() {
+        return target;
+    }
+
+    /**
+     * Updates the target method of this call site, as a normal variable.
+     * The type of the new target must agree with the type of the old target.
+     * <p>
+     * The interactions with memory are the same
+     * as of a write to an ordinary variable, such as an array element or a
+     * non-volatile, non-final field.
+     * <p>
+     * In particular, unrelated threads may fail to see the updated target
+     * until they perform a read from memory.
+     * Stronger guarantees can be created by putting appropriate operations
+     * into the bootstrap method and/or the target methods used
+     * at any given call site.
+     *
+     * @param newTarget the new target
+     * @throws NullPointerException if the proposed new target is null
+     * @throws WrongMethodTypeException if the proposed new target
+     *         has a method type that differs from the previous target
+     * @see #getTarget
+     */
+    @Override public void setTarget(MethodHandle newTarget) {
+        checkTargetChange(this.target, newTarget);
+        setTargetNormal(newTarget);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final MethodHandle dynamicInvoker() {
+        return makeDynamicInvoker();
+    }
+
+    // BEGIN Android-removed: syncAll() implementation is incomplete.
+    /**
+     * Performs a synchronization operation on each call site in the given array,
+     * forcing all other threads to throw away any cached values previously
+     * loaded from the target of any of the call sites.
+     * <p>
+     * This operation does not reverse any calls that have already started
+     * on an old target value.
+     * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
+     * <p>
+     * The overall effect is to force all future readers of each call site's target
+     * to accept the most recently stored value.
+     * ("Most recently" is reckoned relative to the {@code syncAll} itself.)
+     * Conversely, the {@code syncAll} call may block until all readers have
+     * (somehow) decached all previous versions of each call site's target.
+     * <p>
+     * To avoid race conditions, calls to {@code setTarget} and {@code syncAll}
+     * should generally be performed under some sort of mutual exclusion.
+     * Note that reader threads may observe an updated target as early
+     * as the {@code setTarget} call that install the value
+     * (and before the {@code syncAll} that confirms the value).
+     * On the other hand, reader threads may observe previous versions of
+     * the target until the {@code syncAll} call returns
+     * (and after the {@code setTarget} that attempts to convey the updated version).
+     * <p>
+     * This operation is likely to be expensive and should be used sparingly.
+     * If possible, it should be buffered for batch processing on sets of call sites.
+     * <p>
+     * If {@code sites} contains a null element,
+     * a {@code NullPointerException} will be raised.
+     * In this case, some non-null elements in the array may be
+     * processed before the method returns abnormally.
+     * Which elements these are (if any) is implementation-dependent.
+     *
+     * <h1>Java Memory Model details</h1>
+     * In terms of the Java Memory Model, this operation performs a synchronization
+     * action which is comparable in effect to the writing of a volatile variable
+     * by the current thread, and an eventual volatile read by every other thread
+     * that may access one of the affected call sites.
+     * <p>
+     * The following effects are apparent, for each individual call site {@code S}:
+     * <ul>
+     * <li>A new volatile variable {@code V} is created, and written by the current thread.
+     *     As defined by the JMM, this write is a global synchronization event.
+     * <li>As is normal with thread-local ordering of write events,
+     *     every action already performed by the current thread is
+     *     taken to happen before the volatile write to {@code V}.
+     *     (In some implementations, this means that the current thread
+     *     performs a global release operation.)
+     * <li>Specifically, the write to the current target of {@code S} is
+     *     taken to happen before the volatile write to {@code V}.
+     * <li>The volatile write to {@code V} is placed
+     *     (in an implementation specific manner)
+     *     in the global synchronization order.
+     * <li>Consider an arbitrary thread {@code T} (other than the current thread).
+     *     If {@code T} executes a synchronization action {@code A}
+     *     after the volatile write to {@code V} (in the global synchronization order),
+     *     it is therefore required to see either the current target
+     *     of {@code S}, or a later write to that target,
+     *     if it executes a read on the target of {@code S}.
+     *     (This constraint is called "synchronization-order consistency".)
+     * <li>The JMM specifically allows optimizing compilers to elide
+     *     reads or writes of variables that are known to be useless.
+     *     Such elided reads and writes have no effect on the happens-before
+     *     relation.  Regardless of this fact, the volatile {@code V}
+     *     will not be elided, even though its written value is
+     *     indeterminate and its read value is not used.
+     * </ul>
+     * Because of the last point, the implementation behaves as if a
+     * volatile read of {@code V} were performed by {@code T}
+     * immediately after its action {@code A}.  In the local ordering
+     * of actions in {@code T}, this read happens before any future
+     * read of the target of {@code S}.  It is as if the
+     * implementation arbitrarily picked a read of {@code S}'s target
+     * by {@code T}, and forced a read of {@code V} to precede it,
+     * thereby ensuring communication of the new target value.
+     * <p>
+     * As long as the constraints of the Java Memory Model are obeyed,
+     * implementations may delay the completion of a {@code syncAll}
+     * operation while other threads ({@code T} above) continue to
+     * use previous values of {@code S}'s target.
+     * However, implementations are (as always) encouraged to avoid
+     * livelock, and to eventually require all threads to take account
+     * of the updated target.
+     *
+     * <p style="font-size:smaller;">
+     * <em>Discussion:</em>
+     * For performance reasons, {@code syncAll} is not a virtual method
+     * on a single call site, but rather applies to a set of call sites.
+     * Some implementations may incur a large fixed overhead cost
+     * for processing one or more synchronization operations,
+     * but a small incremental cost for each additional call site.
+     * In any case, this operation is likely to be costly, since
+     * other threads may have to be somehow interrupted
+     * in order to make them notice the updated target value.
+     * However, it may be observed that a single call to synchronize
+     * several sites has the same formal effect as many calls,
+     * each on just one of the sites.
+     *
+     * <p style="font-size:smaller;">
+     * <em>Implementation Note:</em>
+     * Simple implementations of {@code MutableCallSite} may use
+     * a volatile variable for the target of a mutable call site.
+     * In such an implementation, the {@code syncAll} method can be a no-op,
+     * and yet it will conform to the JMM behavior documented above.
+     *
+     * @param sites an array of call sites to be synchronized
+     * @throws NullPointerException if the {@code sites} array reference is null
+     *                              or the array contains a null
+     *
+    public static void syncAll(MutableCallSite[] sites) {
+        if (sites.length == 0)  return;
+        STORE_BARRIER.lazySet(0);
+        for (int i = 0; i < sites.length; i++) {
+            sites[i].getClass();  // trigger NPE on first null
+        }
+        // FIXME: NYI
+    }
+    private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+    */
+    // END Android-removed: syncAll() implementation is incomplete.
+}
diff --git a/java/lang/invoke/SerializedLambda.java b/java/lang/invoke/SerializedLambda.java
new file mode 100644
index 0000000..55ec670
--- /dev/null
+++ b/java/lang/invoke/SerializedLambda.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.io.Serializable;
+
+public final class SerializedLambda implements Serializable {
+
+    public SerializedLambda(Class<?> capturingClass,
+                            String functionalInterfaceClass,
+                            String functionalInterfaceMethodName,
+                            String functionalInterfaceMethodSignature,
+                            int implMethodKind,
+                            String implClass,
+                            String implMethodName,
+                            String implMethodSignature,
+                            String instantiatedMethodType,
+                            Object[] capturedArgs) { }
+
+    public String getCapturingClass() { return null; }
+
+    public String getFunctionalInterfaceClass() {
+        return null;
+    }
+
+    public String getFunctionalInterfaceMethodName() {
+        return null;
+    }
+
+    public String getFunctionalInterfaceMethodSignature() { return null; }
+
+    public String getImplClass() {
+        return null;
+    }
+
+    public String getImplMethodName() {
+        return null;
+    }
+
+    public String getImplMethodSignature() {
+        return null;
+    }
+
+    public int getImplMethodKind() {
+        return 0;
+    }
+
+    public final String getInstantiatedMethodType() {
+        return null;
+    }
+
+    public int getCapturedArgCount() {
+        return 0;
+    }
+
+    public Object getCapturedArg(int i) {
+        return null;
+    }
+
+}
diff --git a/java/lang/invoke/Stable.java b/java/lang/invoke/Stable.java
new file mode 100644
index 0000000..a0a413e
--- /dev/null
+++ b/java/lang/invoke/Stable.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.annotation.*;
+
+/**
+ * A field may be annotated as stable if all of its component variables
+ * changes value at most once.
+ * A field's value counts as its component value.
+ * If the field is typed as an array, then all the non-null components
+ * of the array, of depth up to the rank of the field's array type,
+ * also count as component values.
+ * By extension, any variable (either array or field) which has annotated
+ * as stable is called a stable variable, and its non-null or non-zero
+ * value is called a stable value.
+ * <p>
+ * Since all fields begin with a default value of null for references
+ * (resp., zero for primitives), it follows that this annotation indicates
+ * that the first non-null (resp., non-zero) value stored in the field
+ * will never be changed.
+ * <p>
+ * If the field is not of an array type, there are no array elements,
+ * then the value indicated as stable is simply the value of the field.
+ * If the dynamic type of the field value is an array but the static type
+ * is not, the components of the array are <em>not</em> regarded as stable.
+ * <p>
+ * If the field is an array type, then both the field value and
+ * all the components of the field value (if the field value is non-null)
+ * are indicated to be stable.
+ * If the field type is an array type with rank {@code N > 1},
+ * then each component of the field value (if the field value is non-null),
+ * is regarded as a stable array of rank {@code N-1}.
+ * <p>
+ * Fields which are declared {@code final} may also be annotated as stable.
+ * Since final fields already behave as stable values, such an annotation
+ * indicates no additional information, unless the type of the field is
+ * an array type.
+ * <p>
+ * It is (currently) undefined what happens if a field annotated as stable
+ * is given a third value.  In practice, if the JVM relies on this annotation
+ * to promote a field reference to a constant, it may be that the Java memory
+ * model would appear to be broken, if such a constant (the second value of the field)
+ * is used as the value of the field even after the field value has changed.
+ */
+/* package-private */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@interface Stable {
+}
diff --git a/java/lang/invoke/Transformers.java b/java/lang/invoke/Transformers.java
new file mode 100644
index 0000000..15546a8
--- /dev/null
+++ b/java/lang/invoke/Transformers.java
@@ -0,0 +1,2307 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  The Android Open Source
+ * Project designates this particular file as subject to the "Classpath"
+ * exception as provided by The Android Open Source Project in the LICENSE
+ * file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package java.lang.invoke;
+
+import dalvik.system.EmulatedStackFrame;
+import dalvik.system.EmulatedStackFrame.Range;
+import dalvik.system.EmulatedStackFrame.StackFrameAccessor;
+import dalvik.system.EmulatedStackFrame.StackFrameReader;
+import dalvik.system.EmulatedStackFrame.StackFrameWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import sun.invoke.util.Wrapper;
+import sun.misc.Unsafe;
+import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext;
+
+/**
+ * @hide Public for testing only.
+ */
+public class Transformers {
+    private Transformers() {}
+
+    static {
+        try {
+            TRANSFORM_INTERNAL = MethodHandle.class.getDeclaredMethod("transformInternal",
+                    EmulatedStackFrame.class);
+        } catch (NoSuchMethodException nsme) {
+            throw new AssertionError();
+        }
+    }
+
+    /**
+     * Method reference to the private {@code MethodHandle.transformInternal} method. This is
+     * cached here because it's the point of entry for all transformers.
+     */
+    private static final Method TRANSFORM_INTERNAL;
+
+    /** @hide */
+    public static abstract class Transformer extends MethodHandle implements Cloneable {
+        protected Transformer(MethodType type) {
+            super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type);
+        }
+
+        protected Transformer(MethodType type, int invokeKind) {
+            super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type);
+        }
+
+        @Override
+        public Object clone() throws CloneNotSupportedException {
+            return super.clone();
+        }
+    }
+
+    /**
+     * A method handle that always throws an exception of a specified type.
+     *
+     * The handle declares a nominal return type, which is immaterial to the execution
+     * of the handle because it never returns.
+     *
+     * @hide
+     */
+    public static class AlwaysThrow extends Transformer {
+        private final Class<? extends Throwable> exceptionType;
+
+        public AlwaysThrow(Class<?> nominalReturnType, Class<? extends  Throwable> exType) {
+            super(MethodType.methodType(nominalReturnType, exType));
+            this.exceptionType = exType;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            throw emulatedStackFrame.getReference(0, exceptionType);
+        }
+    }
+
+    /**
+     * Implements {@code MethodHandles.dropArguments}.
+     */
+    public static class DropArguments extends Transformer {
+        private final MethodHandle delegate;
+
+        private final EmulatedStackFrame.Range range1;
+
+        /**
+         * Note that {@code range2} will be null if the arguments that are being dropped
+         * are the last {@code n}.
+         */
+        /* @Nullable */ private final EmulatedStackFrame.Range range2;
+
+        public DropArguments(MethodType type, MethodHandle delegate,
+                             int startPos, int numDropped) {
+            super(type);
+
+            this.delegate = delegate;
+
+            // We pre-calculate the ranges of values we have to copy through to the delegate
+            // handle at the time of instantiation so that the actual invoke is performant.
+            this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos);
+            final int numArgs = type.ptypes().length;
+            if (startPos + numDropped < numArgs) {
+                this.range2 = EmulatedStackFrame.Range.of(type, startPos + numDropped, numArgs);
+            } else {
+                this.range2 = null;
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type());
+
+            emulatedStackFrame.copyRangeTo(calleeFrame, range1,
+                    0 /* referencesStart */, 0 /* stackFrameStart */);
+
+            if (range2 != null) {
+                final int referencesStart = range1.numReferences;
+                final int stackFrameStart = range1.numBytes;
+
+                emulatedStackFrame.copyRangeTo(calleeFrame, range2,
+                        referencesStart, stackFrameStart);
+            }
+
+            delegate.invoke(calleeFrame);
+            calleeFrame.copyReturnValueTo(emulatedStackFrame);
+        }
+    }
+
+    /**
+     * Implements {@code MethodHandles.catchException}.
+     */
+    public static class CatchException extends Transformer {
+        private final MethodHandle target;
+        private final MethodHandle handler;
+        private final Class<?> exType;
+
+        private final EmulatedStackFrame.Range handlerArgsRange;
+
+        public CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) {
+            super(target.type());
+
+            this.target = target;
+            this.handler = handler;
+            this.exType = exType;
+
+            // We only copy the first "count" args, dropping others if required. Note that
+            // we subtract one because the first handler arg is the exception thrown by the
+            // target.
+            handlerArgsRange = EmulatedStackFrame.Range.of(target.type(), 0,
+                    (handler.type().parameterCount() - 1));
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            try {
+                target.invoke(emulatedStackFrame);
+            } catch (Throwable th) {
+                if (th.getClass() == exType) {
+                    // We've gotten an exception of the appropriate type, so we need to call
+                    // the handler. Create a new frame of the appropriate size.
+                    EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type());
+
+                    // The first argument to the handler is the actual exception.
+                    fallback.setReference(0, th);
+
+                    // We then copy other arguments that need to be passed through to the handler.
+                    // Note that we might drop arguments at the end, if needed. Note that
+                    // referencesStart == 1 because the first argument is the exception type.
+                    emulatedStackFrame.copyRangeTo(fallback, handlerArgsRange,
+                            1 /* referencesStart */, 0 /* stackFrameStart */);
+
+                    // Perform the invoke and return the appropriate value.
+                    handler.invoke(fallback);
+                    fallback.copyReturnValueTo(emulatedStackFrame);
+                } else {
+                    // The exception is not of the expected type, we throw it.
+                    throw th;
+                }
+            }
+        }
+    }
+
+    /**
+     * Implements {@code MethodHandles.GuardWithTest}.
+     */
+    public static class GuardWithTest extends Transformer {
+        private final MethodHandle test;
+        private final MethodHandle target;
+        private final MethodHandle fallback;
+
+        private final EmulatedStackFrame.Range testArgsRange;
+
+        public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
+            super(target.type());
+
+            this.test = test;
+            this.target = target;
+            this.fallback = fallback;
+
+            // The test method might have a subset of the arguments of the handle / target.
+            testArgsRange = EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount());
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type());
+            emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0);
+
+            // We know that the return value for test is going to be boolean.class, so we don't have
+            // to do the copyReturnValue dance.
+            final boolean value = (boolean) test.invoke(testFrame);
+            if (value) {
+                target.invoke(emulatedStackFrame);
+            } else {
+                fallback.invoke(emulatedStackFrame);
+            }
+        }
+    }
+
+    /**
+     * Implementation of MethodHandles.arrayElementGetter for reference types.
+     */
+    public static class ReferenceArrayElementGetter extends Transformer {
+        private final Class<?> arrayClass;
+
+        public ReferenceArrayElementGetter(Class<?> arrayClass) {
+            super(MethodType.methodType(arrayClass.getComponentType(),
+                    new Class<?>[]{arrayClass, int.class}));
+            this.arrayClass = arrayClass;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(emulatedStackFrame);
+
+            // Read the array object and the index from the stack frame.
+            final Object[] array = (Object[]) reader.nextReference(arrayClass);
+            final int index = reader.nextInt();
+
+            // Write the array element back to the stack frame.
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(emulatedStackFrame);
+            writer.makeReturnValueAccessor();
+            writer.putNextReference(array[index], arrayClass.getComponentType());
+        }
+    }
+
+    /**
+     * Implementation of MethodHandles.arrayElementSetter for reference types.
+     */
+    public static class ReferenceArrayElementSetter extends Transformer {
+        private final Class<?> arrayClass;
+
+        public ReferenceArrayElementSetter(Class<?> arrayClass) {
+            super(MethodType.methodType(void.class,
+                    new Class<?>[] { arrayClass, int.class, arrayClass.getComponentType() }));
+            this.arrayClass = arrayClass;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(emulatedStackFrame);
+
+            // Read the array object, index and the value to write from the stack frame.
+            final Object[] array = (Object[]) reader.nextReference(arrayClass);
+            final int index = reader.nextInt();
+            final Object value = reader.nextReference(arrayClass.getComponentType());
+
+            array[index] = value;
+        }
+    }
+
+    /**
+     * Implementation of MethodHandles.identity() for reference types.
+     */
+    public static class ReferenceIdentity extends Transformer {
+        private final Class<?> type;
+
+        public ReferenceIdentity(Class<?> type) {
+            super(MethodType.methodType(type, type));
+            this.type = type;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(emulatedStackFrame);
+
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(emulatedStackFrame);
+            writer.makeReturnValueAccessor();
+            writer.putNextReference(reader.nextReference(type), type);
+        }
+    }
+
+    /**
+     * Implementation of MethodHandles.constant.
+     */
+    public static class Constant extends Transformer {
+        private final Class<?> type;
+
+        // NOTE: This implementation turned out to be more awkward than expected becuase
+        // of the type system. We could simplify this considerably at the cost of making
+        // the emulated stack frame API uglier or by transitioning into JNI.
+        //
+        // We could consider implementing this in terms of bind() once that's implemented.
+        // This would then just become : MethodHandles.identity(type).bind(value).
+        private int asInt;
+        private long asLong;
+        private float asFloat;
+        private double asDouble;
+        private Object asReference;
+
+        private char typeChar;
+
+        public Constant(Class<?> type, Object value) {
+            super(MethodType.methodType(type));
+            this.type = type;
+
+            if (!type.isPrimitive()) {
+                asReference = value;
+                typeChar = 'L';
+            } else if (type == int.class) {
+                asInt = (int) value;
+                typeChar = 'I';
+            } else if (type == char.class) {
+                asInt = (int) (char) value;
+                typeChar = 'C';
+            } else if (type == short.class) {
+                asInt = (int) (short) value;
+                typeChar = 'S';
+            } else if (type == byte.class) {
+                asInt = (int) (byte) value;
+                typeChar = 'B';
+            } else if (type == boolean.class) {
+                asInt = ((boolean) value) ? 1 : 0;
+                typeChar = 'Z';
+            } else if (type == long.class) {
+                asLong = (long) value;
+                typeChar = 'J';
+            } else if (type == float.class) {
+                asFloat = (float) value;
+                typeChar = 'F';
+            } else if (type == double.class) {
+                asDouble = (double) value;
+                typeChar = 'D';
+            } else {
+                throw new AssertionError("unknown type: " + typeChar);
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(emulatedStackFrame);
+            writer.makeReturnValueAccessor();
+
+            switch (typeChar) {
+                case 'L' : { writer.putNextReference(asReference, type); break; }
+                case 'I' : { writer.putNextInt(asInt); break; }
+                case 'C' : { writer.putNextChar((char) asInt); break; }
+                case 'S' : { writer.putNextShort((short) asInt); break; }
+                case 'B' : { writer.putNextByte((byte) asInt); break; }
+                case 'Z' : { writer.putNextBoolean(asInt == 1); break; }
+                case 'J' : { writer.putNextLong(asLong); break; }
+                case 'F' : { writer.putNextFloat(asFloat); break; }
+                case 'D' : { writer.putNextDouble(asDouble); break; }
+                default:
+                    throw new AssertionError("Unexpected typeChar: " + typeChar);
+            }
+        }
+    }
+
+    /*package*/ static class Construct extends Transformer {
+        private final MethodHandle constructorHandle;
+        private final EmulatedStackFrame.Range callerRange;
+
+        /*package*/ Construct(MethodHandle constructorHandle, MethodType returnedType) {
+            super(returnedType);
+            this.constructorHandle = constructorHandle;
+            this.callerRange = EmulatedStackFrame.Range.all(type());
+        }
+
+        MethodHandle getConstructorHandle() {
+            return constructorHandle;
+        }
+
+        private static boolean isAbstract(Class<?> klass) {
+            return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
+        }
+
+        private static void checkInstantiable(Class<?> klass) throws InstantiationException {
+            if (isAbstract(klass)) {
+                String s = klass.isInterface() ? "interface " : "abstract class ";
+                throw new InstantiationException("Can't instantiate " + s + klass);
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final Class<?> receiverType = constructorHandle.type().parameterType(0);
+            checkInstantiable(receiverType);
+
+            // Allocate memory for receiver.
+            Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType);
+
+            // The MethodHandle type for the caller has the form of
+            // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of
+            // the form {rtype=void,ptypes=T,A1...An}. So the frame for
+            // the constructor needs to have a slot with the receiver
+            // in position 0.
+            EmulatedStackFrame constructorFrame =
+                    EmulatedStackFrame.create(constructorHandle.type());
+            constructorFrame.setReference(0, receiver);
+            emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0);
+            constructorHandle.invoke(constructorFrame);
+
+            // Set return result for caller.
+            emulatedStackFrame.setReturnValueTo(receiver);
+        }
+    }
+
+    /**
+     * Implements MethodHandle.bindTo.
+     *
+     * @hide
+     */
+    public static class BindTo extends Transformer {
+        private final MethodHandle delegate;
+        private final Object receiver;
+
+        private final EmulatedStackFrame.Range range;
+
+        public BindTo(MethodHandle delegate, Object receiver) {
+            super(delegate.type().dropParameterTypes(0, 1));
+
+            this.delegate = delegate;
+            this.receiver = receiver;
+
+            this.range = EmulatedStackFrame.Range.all(this.type());
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            // Create a new emulated stack frame with the full type (including the leading
+            // receiver reference).
+            EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type());
+
+            // The first reference argument must be the receiver.
+            stackFrame.setReference(0, receiver);
+            // Copy all other arguments.
+            emulatedStackFrame.copyRangeTo(stackFrame, range,
+                    1 /* referencesStart */, 0 /* stackFrameStart */);
+
+            // Perform the invoke.
+            delegate.invoke(stackFrame);
+            stackFrame.copyReturnValueTo(emulatedStackFrame);
+        }
+    }
+
+    /**
+     * Implements MethodHandle.filterReturnValue.
+     */
+    public static class FilterReturnValue extends Transformer {
+        private final MethodHandle target;
+        private final MethodHandle filter;
+
+        private final EmulatedStackFrame.Range allArgs;
+
+        public FilterReturnValue(MethodHandle target, MethodHandle filter) {
+            super(MethodType.methodType(filter.type().rtype(), target.type().ptypes()));
+
+            this.target = target;
+            this.filter = filter;
+
+            allArgs = EmulatedStackFrame.Range.all(type());
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            // Create a new frame with the target's type and copy all arguments over.
+            // This frame differs in return type with |emulatedStackFrame| but will have
+            // the same parameter shapes.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+            emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0);
+            target.invoke(targetFrame);
+
+            // Perform the invoke.
+            final StackFrameReader returnValueReader = new StackFrameReader();
+            returnValueReader.attach(targetFrame);
+            returnValueReader.makeReturnValueAccessor();
+
+            // Create an emulated frame for the filter and copy all its arguments across.
+            EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
+            final StackFrameWriter filterWriter = new StackFrameWriter();
+            filterWriter.attach(filterFrame);
+
+            final Class<?> returnType = target.type().rtype();
+            if (!returnType.isPrimitive()) {
+                filterWriter.putNextReference(returnValueReader.nextReference(returnType),
+                        returnType);
+            } else if (returnType == boolean.class) {
+                filterWriter.putNextBoolean(returnValueReader.nextBoolean());
+            } else if (returnType == byte.class) {
+                filterWriter.putNextByte(returnValueReader.nextByte());
+            } else if (returnType == char.class) {
+                filterWriter.putNextChar(returnValueReader.nextChar());
+            } else if (returnType == short.class) {
+                filterWriter.putNextShort(returnValueReader.nextShort());
+            } else if (returnType == int.class) {
+                filterWriter.putNextInt(returnValueReader.nextInt());
+            } else if (returnType == long.class) {
+                filterWriter.putNextLong(returnValueReader.nextLong());
+            } else if (returnType == float.class) {
+                filterWriter.putNextFloat(returnValueReader.nextFloat());
+            } else if (returnType == double.class) {
+                filterWriter.putNextDouble(returnValueReader.nextDouble());
+            }
+
+            // Invoke the filter and copy its return value back to the original frame.
+            filter.invoke(filterFrame);
+            filterFrame.copyReturnValueTo(emulatedStackFrame);
+        }
+    }
+
+    /*
+     * Implements MethodHandles.permuteArguments.
+     *
+     * @hide
+     */
+    public static class PermuteArguments extends Transformer {
+        private final MethodHandle target;
+        private final int[] reorder;
+
+        public PermuteArguments(MethodType type, MethodHandle target, int[] reorder) {
+            super(type);
+
+            this.target = target;
+            this.reorder = reorder;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(emulatedStackFrame);
+
+            // In the interests of simplicity, we box / unbox arguments while performing
+            // the permutation. We first iterate through the incoming stack frame and box
+            // each argument. We then unbox and write out the argument to the target frame
+            // according to the specified reordering.
+            Object[] arguments = new Object[reorder.length];
+            final Class<?>[] ptypes = type().ptypes();
+            for (int i = 0; i < ptypes.length; ++i) {
+                final Class<?> ptype = ptypes[i];
+                if (!ptype.isPrimitive()) {
+                    arguments[i] = reader.nextReference(ptype);
+                } else if (ptype == boolean.class) {
+                    arguments[i] = reader.nextBoolean();
+                } else if (ptype == byte.class) {
+                    arguments[i] = reader.nextByte();
+                } else if (ptype == char.class) {
+                    arguments[i] = reader.nextChar();
+                } else if (ptype == short.class) {
+                    arguments[i] = reader.nextShort();
+                } else if (ptype == int.class) {
+                    arguments[i] = reader.nextInt();
+                } else if (ptype == long.class) {
+                    arguments[i] = reader.nextLong();
+                } else if (ptype == float.class) {
+                    arguments[i] = reader.nextFloat();
+                } else if (ptype == double.class) {
+                    arguments[i] = reader.nextDouble();
+                } else {
+                    throw new AssertionError("Unexpected type: " + ptype);
+                }
+            }
+
+            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(calleeFrame);
+
+            for (int i = 0; i < ptypes.length; ++i) {
+                int idx = reorder[i];
+                final Class<?> ptype = ptypes[idx];
+                final Object argument = arguments[idx];
+
+                if (!ptype.isPrimitive()) {
+                    writer.putNextReference(argument, ptype);
+                } else if (ptype == boolean.class) {
+                    writer.putNextBoolean((boolean) argument);
+                } else if (ptype == byte.class) {
+                    writer.putNextByte((byte) argument);
+                } else if (ptype == char.class) {
+                    writer.putNextChar((char) argument);
+                } else if (ptype == short.class) {
+                    writer.putNextShort((short) argument);
+                } else if (ptype == int.class) {
+                    writer.putNextInt((int) argument);
+                } else if (ptype == long.class) {
+                    writer.putNextLong((long) argument);
+                } else if (ptype == float.class) {
+                    writer.putNextFloat((float) argument);
+                } else if (ptype == double.class) {
+                    writer.putNextDouble((double) argument);
+                } else {
+                    throw new AssertionError("Unexpected type: " + ptype);
+                }
+            }
+
+            target.invoke(calleeFrame);
+            calleeFrame.copyReturnValueTo(emulatedStackFrame);
+        }
+    }
+
+    /**
+     * Converts methods with a trailing array argument to variable arity
+     * methods. So (A,B,C[])R can be invoked with any number of convertible
+     * arguments after B, e.g. (A,B)R or (A, B, C0)R or (A, B, C0...Cn)R.
+     *
+     * @hide
+     */
+    /*package*/ static class VarargsCollector extends Transformer {
+        final MethodHandle target;
+
+        /*package*/ VarargsCollector(MethodHandle target) {
+            super(target.type(), MethodHandle.INVOKE_CALLSITE_TRANSFORM);
+            if (!lastParameterTypeIsAnArray(target.type().ptypes())) {
+                throw new IllegalArgumentException("target does not have array as last parameter");
+            }
+            this.target = target;
+        }
+
+        private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) {
+            if (parameterTypes.length == 0) return false;
+            return parameterTypes[parameterTypes.length - 1].isArray();
+        }
+
+        @Override
+        public boolean isVarargsCollector() { return true; }
+
+        @Override
+        public MethodHandle asFixedArity() { return target; }
+
+        @Override
+        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+            MethodType callerFrameType = callerFrame.getMethodType();
+            Class<?>[] callerPTypes = callerFrameType.ptypes();
+            Class<?>[] targetPTypes = type().ptypes();
+
+            int lastTargetIndex = targetPTypes.length - 1;
+            if (callerPTypes.length == targetPTypes.length &&
+                targetPTypes[lastTargetIndex].isAssignableFrom(callerPTypes[lastTargetIndex])) {
+                // Caller frame matches target frame in the arity array parameter. Invoke
+                // immediately, and let the invoke() dispatch perform any necessary conversions
+                // on the other parameters present.
+                target.invoke(callerFrame);
+                return;
+            }
+
+            if (callerPTypes.length < targetPTypes.length - 1) {
+                // Too few arguments to be compatible with variable arity invocation.
+                throwWrongMethodTypeException(callerFrameType, type());
+            }
+
+            if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) {
+                // Incompatible return type.
+                throwWrongMethodTypeException(callerFrameType, type());
+            }
+
+            Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType();
+            if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) {
+                // Wrong types to be compatible with variable arity invocation.
+                throwWrongMethodTypeException(callerFrameType, type());
+            }
+
+            // Allocate targetFrame.
+            MethodType targetFrameType = makeTargetFrameType(callerFrameType, type());
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType);
+            prepareFrame(callerFrame, targetFrame);
+
+            // Invoke target.
+            target.invoke(targetFrame);
+
+            // Copy return value to the caller's frame.
+            targetFrame.copyReturnValueTo(callerFrame);
+        }
+
+        private static void throwWrongMethodTypeException(MethodType from, MethodType to) {
+            throw new WrongMethodTypeException("Cannot convert " + from + " to " + to);
+        }
+
+        private static boolean arityArgumentsConvertible(Class<?>[] ptypes, int arityStart,
+                                                         Class<?> elementType) {
+            if (ptypes.length - 1 == arityStart) {
+                if (ptypes[arityStart].isArray() &&
+                    ptypes[arityStart].getComponentType() == elementType) {
+                    // The last ptype is in the same position as the arity
+                    // array and has the same type.
+                    return true;
+                }
+            }
+
+            for (int i = arityStart; i < ptypes.length; ++i) {
+                if (!MethodType.canConvert(ptypes[i], elementType)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static Object referenceArray(StackFrameReader reader, Class<?>[] ptypes,
+                                             Class<?> elementType, int offset, int length) {
+            Object arityArray = Array.newInstance(elementType, length);
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                Object o = null;
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { o = reader.nextReference(argumentType); break; }
+                    case 'I': { o = reader.nextInt(); break; }
+                    case 'J': { o = reader.nextLong(); break; }
+                    case 'B': { o = reader.nextByte(); break; }
+                    case 'S': { o = reader.nextShort(); break; }
+                    case 'C': { o = reader.nextChar(); break; }
+                    case 'Z': { o = reader.nextBoolean(); break; }
+                    case 'F': { o = reader.nextFloat(); break; }
+                    case 'D': { o = reader.nextDouble(); break; }
+                }
+                Array.set(arityArray, i, elementType.cast(o));
+            }
+            return arityArray;
+        }
+
+        private static Object intArray(StackFrameReader reader, Class<?> ptypes[],
+                                       int offset, int length) {
+            int[] arityArray = new int[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'I': { arityArray[i] = reader.nextInt(); break; }
+                    case 'S': { arityArray[i] = reader.nextShort(); break; }
+                    case 'B': { arityArray[i] = reader.nextByte(); break; }
+                    default: {
+                        arityArray[i] = (Integer) reader.nextReference(argumentType);
+                        break;
+                    }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object longArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            long[] arityArray = new long[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'J': { arityArray[i] = reader.nextLong(); break; }
+                    case 'I': { arityArray[i] = reader.nextInt(); break; }
+                    case 'S': { arityArray[i] = reader.nextShort(); break; }
+                    case 'B': { arityArray[i] = reader.nextByte(); break; }
+                    default: { arityArray[i] = (Long) reader.nextReference(argumentType); break; }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object byteArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            byte[] arityArray = new byte[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'B': { arityArray[i] = reader.nextByte(); break; }
+                    default: { arityArray[i] = (Byte) reader.nextReference(argumentType); break; }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object shortArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            short[] arityArray = new short[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'S': { arityArray[i] = reader.nextShort(); break; }
+                    case 'B': { arityArray[i] = reader.nextByte(); break; }
+                    default: { arityArray[i] = (Short) reader.nextReference(argumentType); break; }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object charArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            char[] arityArray = new char[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'C': { arityArray[i] = reader.nextChar(); break; }
+                    default: {
+                        arityArray[i] = (Character) reader.nextReference(argumentType);
+                        break;
+                    }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object booleanArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            boolean[] arityArray = new boolean[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'Z': { arityArray[i] = reader.nextBoolean(); break; }
+                    default:
+                        arityArray[i] = (Boolean) reader.nextReference(argumentType);
+                        break;
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object floatArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            float[] arityArray = new float[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'F': { arityArray[i] = reader.nextFloat(); break; }
+                    case 'J': { arityArray[i] = reader.nextLong(); break; }
+                    case 'I': { arityArray[i] = reader.nextInt(); break; }
+                    case 'S': { arityArray[i] = reader.nextShort(); break; }
+                    case 'B': { arityArray[i] = reader.nextByte(); break; }
+                    default: {
+                        arityArray[i] = (Float) reader.nextReference(argumentType);
+                        break;
+                    }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object doubleArray(StackFrameReader reader, Class<?> ptypes[],
+                                        int offset, int length) {
+            double[] arityArray = new double[length];
+            for (int i = 0; i < length; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'D': { arityArray[i] = reader.nextDouble(); break; }
+                    case 'F': { arityArray[i] = reader.nextFloat(); break; }
+                    case 'J': { arityArray[i] = reader.nextLong(); break; }
+                    case 'I': { arityArray[i] = reader.nextInt(); break; }
+                    case 'S': { arityArray[i] = reader.nextShort(); break; }
+                    case 'B': { arityArray[i] = reader.nextByte(); break; }
+                    default: {
+                        arityArray[i] = (Double) reader.nextReference(argumentType);
+                        break;
+                    }
+                }
+            }
+            return arityArray;
+        }
+
+        private static Object makeArityArray(MethodType callerFrameType,
+                                             StackFrameReader callerFrameReader,
+                                             int indexOfArityArray,
+                                             Class<?> arityArrayType) {
+            int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray;
+            Class<?> elementType = arityArrayType.getComponentType();
+            Class<?>[] callerPTypes = callerFrameType.ptypes();
+
+            char elementBasicType = Wrapper.basicTypeChar(elementType);
+            switch (elementBasicType) {
+                case 'L': return referenceArray(callerFrameReader, callerPTypes, elementType,
+                                                indexOfArityArray, arityArrayLength);
+                case 'I': return intArray(callerFrameReader, callerPTypes,
+                                          indexOfArityArray, arityArrayLength);
+                case 'J': return longArray(callerFrameReader, callerPTypes,
+                                           indexOfArityArray, arityArrayLength);
+                case 'B': return byteArray(callerFrameReader, callerPTypes,
+                                           indexOfArityArray, arityArrayLength);
+                case 'S': return shortArray(callerFrameReader, callerPTypes,
+                                            indexOfArityArray, arityArrayLength);
+                case 'C': return charArray(callerFrameReader, callerPTypes,
+                                           indexOfArityArray, arityArrayLength);
+                case 'Z': return booleanArray(callerFrameReader, callerPTypes,
+                                              indexOfArityArray, arityArrayLength);
+                case 'F': return floatArray(callerFrameReader, callerPTypes,
+                                            indexOfArityArray, arityArrayLength);
+                case 'D': return doubleArray(callerFrameReader, callerPTypes,
+                                             indexOfArityArray, arityArrayLength);
+            }
+            throw new InternalError("Unexpected type: " + elementType);
+        }
+
+        public static Object collectArguments(char basicComponentType, Class<?> componentType,
+                                              StackFrameReader reader, Class<?>[] types,
+                                              int startIdx, int length) {
+            switch (basicComponentType) {
+                case 'L': return referenceArray(reader, types, componentType, startIdx, length);
+                case 'I': return intArray(reader, types, startIdx, length);
+                case 'J': return longArray(reader, types, startIdx, length);
+                case 'B': return byteArray(reader, types, startIdx, length);
+                case 'S': return shortArray(reader, types, startIdx, length);
+                case 'C': return charArray(reader, types, startIdx, length);
+                case 'Z': return booleanArray(reader, types, startIdx, length);
+                case 'F': return floatArray(reader, types, startIdx, length);
+                case 'D': return doubleArray(reader, types, startIdx, length);
+            }
+            throw new InternalError("Unexpected type: " + basicComponentType);
+        }
+
+        private static void copyParameter(StackFrameReader reader, StackFrameWriter writer,
+                                          Class<?> ptype) {
+            switch (Wrapper.basicTypeChar(ptype)) {
+                case 'L': { writer.putNextReference(reader.nextReference(ptype), ptype); break; }
+                case 'I': { writer.putNextInt(reader.nextInt()); break; }
+                case 'J': { writer.putNextLong(reader.nextLong()); break; }
+                case 'B': { writer.putNextByte(reader.nextByte()); break; }
+                case 'S': { writer.putNextShort(reader.nextShort()); break; }
+                case 'C': { writer.putNextChar(reader.nextChar()); break; }
+                case 'Z': { writer.putNextBoolean(reader.nextBoolean()); break; }
+                case 'F': { writer.putNextFloat(reader.nextFloat()); break; }
+                case 'D': { writer.putNextDouble(reader.nextDouble()); break; }
+                default: throw new InternalError("Unexpected type: " + ptype);
+            }
+        }
+
+        private static void prepareFrame(EmulatedStackFrame callerFrame,
+                                         EmulatedStackFrame targetFrame) {
+            StackFrameWriter targetWriter = new StackFrameWriter();
+            targetWriter.attach(targetFrame);
+            StackFrameReader callerReader = new StackFrameReader();
+            callerReader.attach(callerFrame);
+
+            // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array.
+            MethodType targetMethodType = targetFrame.getMethodType();
+            int indexOfArityArray = targetMethodType.ptypes().length - 1;
+            for (int i = 0; i < indexOfArityArray; ++i) {
+                Class<?> ptype = targetMethodType.ptypes()[i];
+                copyParameter(callerReader, targetWriter, ptype);
+            }
+
+            // Add arity array as last parameter in |targetFrame|.
+            Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray];
+            Object arityArray = makeArityArray(callerFrame.getMethodType(), callerReader,
+                                               indexOfArityArray, arityArrayType);
+            targetWriter.putNextReference(arityArray, arityArrayType);
+        }
+
+        /**
+         * Computes the frame type to invoke the target method handle with. This
+         * is the same as the caller frame type, but with the trailing argument
+         * being the array type that is the trailing argument in the target method
+         * handle.
+         *
+         * Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC
+         * then the constructed type is (C0, C1, T2[])RC.
+         */
+        private static MethodType makeTargetFrameType(MethodType callerType,
+                                                      MethodType targetType) {
+            final int ptypesLength = targetType.ptypes().length;
+            final Class<?>[] ptypes = new Class<?>[ptypesLength];
+            // Copy types from caller types to new methodType.
+            System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1);
+            // Set the last element in the type array to be the
+            // varargs array of the target.
+            ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1];
+            return MethodType.methodType(callerType.rtype(), ptypes);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.invoker & MethodHandles.exactInvoker.
+     */
+    static class Invoker extends Transformer {
+        private final MethodType targetType;
+        private final boolean isExactInvoker;
+        private final EmulatedStackFrame.Range copyRange;
+
+        Invoker(MethodType targetType, boolean isExactInvoker) {
+            super(targetType.insertParameterTypes(0, MethodHandle.class));
+            this.targetType = targetType;
+            this.isExactInvoker = isExactInvoker;
+            copyRange = EmulatedStackFrame.Range.of(type(), 1, type().parameterCount());
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
+            // We need to artifically throw a WrongMethodTypeException here because we
+            // can't call invokeExact on the target inside the transformer.
+            if (isExactInvoker) {
+                // TODO: We should do the comparison by hand if this new type creation
+                // on every invoke proves too expensive.
+                MethodType callType = emulatedStackFrame.getCallsiteType().dropParameterTypes(0, 1);
+                if (!targetType.equals(callType)) {
+                    throw new WrongMethodTypeException("Wrong type, Expected: " + targetType
+                            + " was: " + callType);
+                }
+            }
+
+            // The first argument to the stack frame is the handle that needs to be invoked.
+            MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class);
+
+            // All other arguments must be copied to the target frame.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType);
+            emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
+
+            // Finally, invoke the handle and copy the return value.
+            target.invoke(targetFrame);
+            targetFrame.copyReturnValueTo(emulatedStackFrame);
+        }
+    }
+
+    /**
+     * Implements MethodHandle.asSpreader / MethodHandles.spreadInvoker.
+     */
+    static class Spreader extends Transformer {
+        /** The method handle we're delegating to. */
+        private final MethodHandle target;
+
+        /**
+         * The offset of the trailing array argument in the list of arguments to
+         * this transformer. The array argument is always the last argument.
+         */
+        private final int arrayOffset;
+
+        /**
+         * The type char of the component type of the array.
+         */
+        private final char arrayTypeChar;
+
+        /**
+         * The number of input arguments that will be present in the array. In other words,
+         * this is the expected array length.
+         */
+        private final int numArrayArgs;
+
+        /**
+         * Range of arguments to copy verbatim from the input frame, This will cover all
+         * arguments that aren't a part of the trailing array.
+         */
+        private final Range copyRange;
+
+        Spreader(MethodHandle target, MethodType spreaderType, int numArrayArgs) {
+            super(spreaderType);
+            this.target = target;
+            // Copy all arguments except the last argument (which is the trailing array argument
+            // that needs to be spread).
+            arrayOffset = spreaderType.parameterCount() - 1;
+
+            // Get and cache the component type of the input array.
+            final Class<?> componentType = spreaderType.ptypes()[arrayOffset].getComponentType();
+            if (componentType == null) {
+                throw new AssertionError("Trailing argument must be an array.");
+            }
+            arrayTypeChar = Wrapper.basicTypeChar(componentType);
+
+            this.numArrayArgs = numArrayArgs;
+            // Copy all args except for the last argument.
+            this.copyRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset);
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+            // Create a new stack frame for the callee.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+            // Copy all arguments except for the trailing array argument.
+            callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
+
+            // Attach the writer, prepare to spread the trailing array arguments into
+            // the callee frame.
+            StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(targetFrame,
+                    arrayOffset,
+                    copyRange.numReferences,
+                    copyRange.numBytes);
+
+            // Get the array reference and check that its length is as expected.
+            Object arrayObj = callerFrame.getReference(
+                    copyRange.numReferences, this.type().ptypes()[arrayOffset]);
+            final int arrayLength = Array.getLength(arrayObj);
+            if (arrayLength != numArrayArgs) {
+                throw new IllegalArgumentException("Invalid array length: " + arrayLength);
+            }
+
+            final MethodType type = target.type();
+            switch (arrayTypeChar) {
+                case 'L':
+                    spreadArray((Object[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'I':
+                    spreadArray((int[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'J':
+                    spreadArray((long[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'B':
+                    spreadArray((byte[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'S':
+                    spreadArray((short[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'C':
+                    spreadArray((char[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'Z':
+                    spreadArray((boolean[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'F':
+                    spreadArray((float[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+                case 'D':
+                    spreadArray((double[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
+                    break;
+
+            }
+
+            target.invoke(targetFrame);
+            targetFrame.copyReturnValueTo(callerFrame);
+        }
+
+        public static void spreadArray(Object[] array, StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                Object o = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(o, argumentType); break; }
+                    case 'I': { writer.putNextInt((int) o); break; }
+                    case 'J': { writer.putNextLong((long) o); break; }
+                    case 'B': { writer.putNextByte((byte) o); break; }
+                    case 'S': { writer.putNextShort((short) o); break; }
+                    case 'C': { writer.putNextChar((char) o); break; }
+                    case 'Z': { writer.putNextBoolean((boolean) o); break; }
+                    case 'F': { writer.putNextFloat((float) o); break; }
+                    case 'D': { writer.putNextDouble((double) o); break; }
+                }
+            }
+        }
+
+        public static void spreadArray(int[] array, StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                int j = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(j, argumentType); break; }
+                    case 'I': { writer.putNextInt(j); break; }
+                    case 'J': { writer.putNextLong(j); break; }
+                    case 'F': { writer.putNextFloat(j); break; }
+                    case 'D': { writer.putNextDouble(j); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(long[] array, StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                long l = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(l, argumentType); break; }
+                    case 'J': { writer.putNextLong(l); break; }
+                    case 'F': { writer.putNextFloat((float) l); break; }
+                    case 'D': { writer.putNextDouble((double) l); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(byte[] array,
+                                       StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                byte b = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(b, argumentType); break; }
+                    case 'I': { writer.putNextInt(b); break; }
+                    case 'J': { writer.putNextLong(b); break; }
+                    case 'B': { writer.putNextByte(b); break; }
+                    case 'S': { writer.putNextShort(b); break; }
+                    case 'F': { writer.putNextFloat(b); break; }
+                    case 'D': { writer.putNextDouble(b); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(short[] array,
+                                       StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                short s = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(s, argumentType); break; }
+                    case 'I': { writer.putNextInt(s); break; }
+                    case 'J': { writer.putNextLong(s); break; }
+                    case 'S': { writer.putNextShort(s); break; }
+                    case 'F': { writer.putNextFloat(s); break; }
+                    case 'D': { writer.putNextDouble(s); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(char[] array,
+                                       StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                char c = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(c, argumentType); break; }
+                    case 'I': { writer.putNextInt(c); break; }
+                    case 'J': { writer.putNextLong(c); break; }
+                    case 'C': { writer.putNextChar(c); break; }
+                    case 'F': { writer.putNextFloat(c); break; }
+                    case 'D': { writer.putNextDouble(c); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(boolean[] array,
+                                       StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                boolean z = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(z, argumentType); break; }
+                    case 'Z': { writer.putNextBoolean(z); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(double[] array,
+                                       StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                double d = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(d, argumentType); break; }
+                    case 'D': { writer.putNextDouble(d); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+
+        public static void spreadArray(float[] array, StackFrameWriter writer, MethodType type,
+                                       int numArgs, int offset) {
+            final Class<?>[] ptypes = type.ptypes();
+            for (int i = 0; i < numArgs; ++i) {
+                Class<?> argumentType = ptypes[i + offset];
+                float f = array[i];
+                switch (Wrapper.basicTypeChar(argumentType)) {
+                    case 'L': { writer.putNextReference(f, argumentType); break; }
+                    case 'D': { writer.putNextDouble((double) f); break; }
+                    case 'F': { writer.putNextFloat(f); break; }
+                    default : { throw new AssertionError(); }
+                }
+            }
+        }
+    }
+
+    /**
+     * Implements MethodHandle.asCollector.
+     */
+    static class Collector extends Transformer {
+        private final MethodHandle target;
+
+        /**
+         * The offset of the trailing array argument in the list of arguments to
+         * this transformer. The array argument is always the last argument.
+         */
+        private final int arrayOffset;
+
+        /**
+         * The number of input arguments that will be present in the array. In other words,
+         * this is the expected array length.
+         */
+        private final int numArrayArgs;
+
+        /**
+         * The type char of the component type of the array.
+         */
+        private final char arrayTypeChar;
+
+        /**
+         * Range of arguments to copy verbatim from the input frame, This will cover all
+         * arguments that aren't a part of the trailing array.
+         */
+        private final Range copyRange;
+
+        Collector(MethodHandle delegate, Class<?> arrayType, int length) {
+            super(delegate.type().asCollectorType(arrayType, length));
+
+            target = delegate;
+            // Copy all arguments except the last argument (which is the trailing array argument
+            // that needs to be spread).
+            arrayOffset = delegate.type().parameterCount() - 1;
+            arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType());
+            numArrayArgs = length;
+
+            // Copy all args except for the last argument.
+            copyRange = EmulatedStackFrame.Range.of(delegate.type(), 0, arrayOffset);
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+            // Create a new stack frame for the callee.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+            // Copy all arguments except for the trailing array argument.
+            callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
+
+            // Attach the writer, prepare to spread the trailing array arguments into
+            // the callee frame.
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(targetFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(callerFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
+
+            switch (arrayTypeChar) {
+                case 'L': {
+                    // Reference arrays are the only case where the component type of the
+                    // array we construct might differ from the type of the reference we read
+                    // from the stack frame.
+                    final Class<?> targetType = target.type().ptypes()[arrayOffset];
+                    final Class<?> targetComponentType = targetType.getComponentType();
+                    final Class<?> adapterComponentType = type().lastParameterType();
+
+                    Object[] arr = (Object[]) Array.newInstance(targetComponentType, numArrayArgs);
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        arr[i] = reader.nextReference(adapterComponentType);
+                    }
+
+                    writer.putNextReference(arr, targetType);
+                    break;
+                }
+                case 'I': {
+                    int[] array = new int[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextInt();
+                    }
+                    writer.putNextReference(array, int[].class);
+                    break;
+                }
+                case 'J': {
+                    long[] array = new long[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextLong();
+                    }
+                    writer.putNextReference(array, long[].class);
+                    break;
+                }
+                case 'B': {
+                    byte[] array = new byte[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextByte();
+                    }
+                    writer.putNextReference(array, byte[].class);
+                    break;
+                }
+                case 'S': {
+                    short[] array = new short[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextShort();
+                    }
+                    writer.putNextReference(array, short[].class);
+                    break;
+                }
+                case 'C': {
+                    char[] array = new char[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextChar();
+                    }
+                    writer.putNextReference(array, char[].class);
+                    break;
+                }
+                case 'Z': {
+                    boolean[] array = new boolean[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextBoolean();
+                    }
+                    writer.putNextReference(array, boolean[].class);
+                    break;
+                }
+                case 'F': {
+                    float[] array = new float[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextFloat();
+                    }
+                    writer.putNextReference(array, float[].class);
+                    break;
+                }
+                case 'D': {
+                    double[] array = new double[numArrayArgs];
+                    for (int i = 0; i < numArrayArgs; ++i) {
+                        array[i] = reader.nextDouble();
+                    }
+                    writer.putNextReference(array, double[].class);
+                    break;
+                }
+            }
+
+            target.invoke(targetFrame);
+            targetFrame.copyReturnValueTo(callerFrame);
+        }
+    }
+
+    /*
+     * Implements MethodHandles.filterArguments.
+     */
+    static class FilterArguments extends Transformer {
+        /** The target handle. */
+        private final MethodHandle target;
+        /** Index of the first argument to filter */
+        private final int pos;
+        /** The list of filters to apply */
+        private final MethodHandle[] filters;
+
+        FilterArguments(MethodHandle target, int pos, MethodHandle[] filters) {
+            super(deriveType(target, pos, filters));
+
+            this.target = target;
+            this.pos = pos;
+            this.filters = filters;
+
+        }
+
+        private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
+            final Class<?>[] filterArgs = new Class<?>[filters.length];
+            for (int i = 0; i < filters.length; ++i) {
+                filterArgs[i] = filters[i].type().parameterType(0);
+            }
+
+            return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs);
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(stackFrame);
+
+            EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(transformedFrame);
+
+            final Class<?>[] ptypes = target.type().ptypes();
+            for (int i = 0; i < ptypes.length; ++i) {
+                // Check whether the current argument has a filter associated with it.
+                // If it has no filter, no further action need be taken.
+                final Class<?> ptype = ptypes[i];
+                final MethodHandle filter;
+                if (i < pos) {
+                    filter = null;
+                } else if (i >= pos + filters.length) {
+                    filter = null;
+                } else {
+                    filter = filters[i - pos];
+                }
+
+                if (filter != null) {
+                    // Note that filter.type() must be (ptype)ptype - this is checked before
+                    // this transformer is created.
+                    EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
+
+                    //  Copy the next argument from the stack frame to the filter frame.
+                    final StackFrameWriter filterWriter = new StackFrameWriter();
+                    filterWriter.attach(filterFrame);
+                    copyNext(reader, filterWriter, filter.type().ptypes()[0]);
+
+                    filter.invoke(filterFrame);
+
+                    // Copy the argument back from the filter frame to the stack frame.
+                    final StackFrameReader filterReader = new StackFrameReader();
+                    filterReader.attach(filterFrame);
+                    filterReader.makeReturnValueAccessor();
+                    copyNext(filterReader, writer, ptype);
+                } else {
+                    // There's no filter associated with this frame, just copy the next argument
+                    // over.
+                    copyNext(reader, writer, ptype);
+                }
+            }
+
+            target.invoke(transformedFrame);
+            transformedFrame.copyReturnValueTo(stackFrame);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.collectArguments.
+     */
+    static class CollectArguments extends Transformer {
+        private final MethodHandle target;
+        private final MethodHandle collector;
+        private final int pos;
+
+        /** The range of input arguments we copy to the collector. */
+        private final Range collectorRange;
+
+        /**
+         * The first range of arguments we copy to the target. These are arguments
+         * in the range [0, pos). Note that arg[pos] is the return value of the filter.
+         */
+        private final Range range1;
+
+        /**
+         * The second range of arguments we copy to the target. These are arguments in the range
+         * (pos, N], where N is the number of target arguments.
+         */
+        private final Range range2;
+
+        private final int referencesOffset;
+        private final int stackFrameOffset;
+
+        CollectArguments(MethodHandle target, MethodHandle collector, int pos,
+                         MethodType adapterType) {
+            super(adapterType);
+
+            this.target = target;
+            this.collector = collector;
+            this.pos = pos;
+
+            final int numFilterArgs = collector.type().parameterCount();
+            final int numAdapterArgs = type().parameterCount();
+            collectorRange = Range.of(type(), pos, pos + numFilterArgs);
+
+            range1 = Range.of(type(), 0, pos);
+            if (pos + numFilterArgs < numAdapterArgs) {
+                this.range2 = Range.of(type(), pos + numFilterArgs, numAdapterArgs);
+            } else {
+                this.range2 = null;
+            }
+
+            // Calculate the number of primitive bytes (or references) we copy to the
+            // target frame based on the return value of the combiner.
+            final Class<?> collectorRType = collector.type().rtype();
+            if (collectorRType == void.class) {
+                stackFrameOffset = 0;
+                referencesOffset = 0;
+            } else if (collectorRType.isPrimitive()) {
+                stackFrameOffset = EmulatedStackFrame.getSize(collectorRType);
+                referencesOffset = 0;
+            } else {
+                stackFrameOffset = 0;
+                referencesOffset = 1;
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            // First invoke the collector.
+            EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type());
+            stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0);
+            collector.invoke(filterFrame);
+
+            // Start constructing the target frame.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+            stackFrame.copyRangeTo(targetFrame, range1, 0, 0);
+
+            // If one of these offsets is not zero, we have a return value to copy.
+            if (referencesOffset != 0 || stackFrameOffset != 0) {
+                final StackFrameReader reader = new StackFrameReader();
+                reader.attach(filterFrame).makeReturnValueAccessor();
+                final StackFrameWriter writer = new StackFrameWriter();
+                writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
+                copyNext(reader, writer, target.type().ptypes()[0]);
+            }
+
+            if (range2 != null) {
+                stackFrame.copyRangeTo(targetFrame, range2,
+                        range1.numReferences + referencesOffset,
+                        range2.numBytes + stackFrameOffset);
+            }
+
+            target.invoke(targetFrame);
+            targetFrame.copyReturnValueTo(stackFrame);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.foldArguments.
+     */
+    static class FoldArguments extends Transformer {
+        private final MethodHandle target;
+        private final MethodHandle combiner;
+
+        private final Range combinerArgs;
+        private final Range targetArgs;
+
+        private final int referencesOffset;
+        private final int stackFrameOffset;
+
+        FoldArguments(MethodHandle target, MethodHandle combiner) {
+            super(deriveType(target, combiner));
+
+            this.target = target;
+            this.combiner = combiner;
+
+            combinerArgs = Range.all(combiner.type());
+            targetArgs = Range.all(type());
+
+            final Class<?> combinerRType = combiner.type().rtype();
+            if (combinerRType == void.class) {
+                stackFrameOffset = 0;
+                referencesOffset = 0;
+            } else if (combinerRType.isPrimitive()) {
+                stackFrameOffset = EmulatedStackFrame.getSize(combinerRType);
+                referencesOffset = 0;
+            } else {
+                stackFrameOffset = 0;
+                referencesOffset = 1;
+            }
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            // First construct the combiner frame and invoke it.
+            EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type());
+            stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0);
+            combiner.invoke(combinerFrame);
+
+            // Create the stack frame for the target.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+            // If one of these offsets is not zero, we have a return value to copy.
+            if (referencesOffset != 0 || stackFrameOffset != 0) {
+                final StackFrameReader reader = new StackFrameReader();
+                reader.attach(combinerFrame).makeReturnValueAccessor();
+                final StackFrameWriter writer = new StackFrameWriter();
+                writer.attach(targetFrame);
+                copyNext(reader, writer, target.type().ptypes()[0]);
+            }
+
+            stackFrame.copyRangeTo(targetFrame, targetArgs, referencesOffset, stackFrameOffset);
+            target.invoke(targetFrame);
+
+            targetFrame.copyReturnValueTo(stackFrame);
+        }
+
+        private static MethodType deriveType(MethodHandle target, MethodHandle combiner) {
+            if (combiner.type().rtype() == void.class) {
+                return target.type();
+            }
+
+            return target.type().dropParameterTypes(0, 1);
+        }
+    }
+
+    /**
+     * Implements MethodHandles.insertArguments.
+     */
+    static class InsertArguments extends Transformer {
+        private final MethodHandle target;
+        private final int pos;
+        private final Object[] values;
+
+        private final Range range1;
+        private final Range range2;
+
+        InsertArguments(MethodHandle target, int pos, Object[] values) {
+            super(target.type().dropParameterTypes(pos, pos + values.length));
+            this.target = target;
+            this.pos = pos;
+            this.values = values;
+
+            final MethodType type = type();
+            range1 = EmulatedStackFrame.Range.of(type, 0, pos);
+            range2 = Range.of(type, pos, type.parameterCount());
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
+            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
+
+            // Copy all arguments before |pos|.
+            stackFrame.copyRangeTo(calleeFrame, range1, 0, 0);
+
+            // Attach a stack frame writer so that we can copy the next |values.length|
+            // arguments.
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
+
+            // Copy all the arguments supplied in |values|.
+            int referencesCopied = 0;
+            int bytesCopied = 0;
+            final Class<?>[] ptypes = target.type().ptypes();
+            for (int i = 0; i < values.length; ++i) {
+                final Class<?> ptype = ptypes[i + pos];
+                if (ptype.isPrimitive()) {
+                    if (ptype == boolean.class) {
+                        writer.putNextBoolean((boolean) values[i]);
+                    } else if (ptype == byte.class) {
+                        writer.putNextByte((byte) values[i]);
+                    } else if (ptype == char.class) {
+                        writer.putNextChar((char) values[i]);
+                    } else if (ptype == short.class) {
+                        writer.putNextShort((short) values[i]);
+                    } else if (ptype == int.class) {
+                        writer.putNextInt((int) values[i]);
+                    } else if (ptype == long.class) {
+                        writer.putNextLong((long) values[i]);
+                    } else if (ptype == float.class) {
+                        writer.putNextFloat((float) values[i]);
+                    } else if (ptype == double.class) {
+                        writer.putNextDouble((double) values[i]);
+                    }
+
+                    bytesCopied += EmulatedStackFrame.getSize(ptype);
+                } else {
+                    writer.putNextReference(values[i], ptype);
+                    referencesCopied++;
+                }
+            }
+
+            // Copy all remaining arguments.
+            if (range2 != null) {
+                stackFrame.copyRangeTo(calleeFrame, range2,
+                        range1.numReferences + referencesCopied,
+                        range1.numBytes + bytesCopied);
+            }
+
+            target.invoke(calleeFrame);
+            calleeFrame.copyReturnValueTo(stackFrame);
+        }
+    }
+
+
+    /**
+     * Implements {@link java.lang.invokeMethodHandles#explicitCastArguments()}.
+     */
+    public static class ExplicitCastArguments extends Transformer {
+        private final MethodHandle target;
+
+        public ExplicitCastArguments(MethodHandle target, MethodType type) {
+            super(type);
+            this.target = target;
+        }
+
+        @Override
+        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
+            // Create a new stack frame for the target.
+            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
+
+            explicitCastArguments(callerFrame, targetFrame);
+            target.invoke(targetFrame);
+            explicitCastReturnValue(callerFrame, targetFrame);
+        }
+
+        private void explicitCastArguments(final EmulatedStackFrame callerFrame,
+                                           final EmulatedStackFrame targetFrame) {
+            final StackFrameReader reader = new StackFrameReader();
+            reader.attach(callerFrame);
+            final StackFrameWriter writer = new StackFrameWriter();
+            writer.attach(targetFrame);
+
+            final Class<?>[] fromTypes = type().ptypes();
+            final Class<?>[] toTypes = target.type().ptypes();
+            for (int i = 0; i < fromTypes.length; ++i) {
+                explicitCast(reader, fromTypes[i], writer, toTypes[i]);
+            }
+        }
+
+        private void explicitCastReturnValue(final EmulatedStackFrame callerFrame,
+                                             final EmulatedStackFrame targetFrame) {
+            Class<?> from = target.type().rtype();
+            Class<?> to = type().rtype();
+            if (to != void.class) {
+                final StackFrameWriter writer = new StackFrameWriter();
+                writer.attach(callerFrame);
+                writer.makeReturnValueAccessor();
+                if (from == void.class) {
+                    if (to.isPrimitive()) {
+                        unboxNull(writer, to);
+                    } else {
+                        writer.putNextReference(null, to);
+                    }
+                } else {
+                    final StackFrameReader reader = new StackFrameReader();
+                    reader.attach(targetFrame);
+                    reader.makeReturnValueAccessor();
+                    explicitCast(reader, target.type().rtype(), writer, type().rtype());
+                }
+            }
+        }
+
+        private static void throwUnexpectedType(final Class<?> unexpectedType) {
+            throw new InternalError("Unexpected type: " + unexpectedType);
+        }
+
+        @SuppressWarnings("unchecked")
+        private static void badCast(final Class<?> from, final Class<?> to) {
+            throw new ClassCastException("Cannot cast " + from.getName() + " to " + to.getName());
+        }
+
+        /**
+         * Converts byte value to boolean according to
+         * {@link java.lang.invoke.MethodHandles#explicitCast()}
+         */
+        private static boolean toBoolean(byte value) {
+            return (value & 1) == 1;
+        }
+
+        private static byte readPrimitiveAsByte(final StackFrameReader reader,
+                                                final Class<?> from) {
+            if (from == byte.class) {
+                return (byte) reader.nextByte();
+            } else if (from == char.class) {
+                return (byte) reader.nextChar();
+            } else if (from == short.class) {
+                return (byte) reader.nextShort();
+            } else if (from == int.class) {
+                return (byte) reader.nextInt();
+            } else if (from == long.class) {
+                return (byte) reader.nextLong();
+            } else if (from == float.class) {
+                return (byte) reader.nextFloat();
+            } else if (from == double.class) {
+                return (byte) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? (byte) 1 : (byte) 0;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static char readPrimitiveAsChar(final StackFrameReader reader,
+                                                final Class<?> from) {
+            if (from == byte.class) {
+                return (char) reader.nextByte();
+            } else if (from == char.class) {
+                return (char) reader.nextChar();
+            } else if (from == short.class) {
+                return (char) reader.nextShort();
+            } else if (from == int.class) {
+                return (char) reader.nextInt();
+            } else if (from == long.class) {
+                return (char) reader.nextLong();
+            } else if (from == float.class) {
+                return (char) reader.nextFloat();
+            } else if (from == double.class) {
+                return (char) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? (char) 1 : (char) 0;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static short readPrimitiveAsShort(final StackFrameReader reader,
+                                                  final Class<?> from) {
+            if (from == byte.class) {
+                return (short) reader.nextByte();
+            } else if (from == char.class) {
+                return (short) reader.nextChar();
+            } else if (from == short.class) {
+                return (short) reader.nextShort();
+            } else if (from == int.class) {
+                return (short) reader.nextInt();
+            } else if (from == long.class) {
+                return (short) reader.nextLong();
+            } else if (from == float.class) {
+                return (short) reader.nextFloat();
+            } else if (from == double.class) {
+                return (short) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? (short) 1 : (short) 0;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static int readPrimitiveAsInt(final StackFrameReader reader,
+                                              final Class<?> from) {
+            if (from == byte.class) {
+                return (int) reader.nextByte();
+            } else if (from == char.class) {
+                return (int) reader.nextChar();
+            } else if (from == short.class) {
+                return (int) reader.nextShort();
+            } else if (from == int.class) {
+                return (int) reader.nextInt();
+            } else if (from == long.class) {
+                return (int) reader.nextLong();
+            } else if (from == float.class) {
+                return (int) reader.nextFloat();
+            } else if (from == double.class) {
+                return (int) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1 : 0;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static long readPrimitiveAsLong(final StackFrameReader reader,
+                                                final Class<?> from) {
+            if (from == byte.class) {
+                return (long) reader.nextByte();
+            } else if (from == char.class) {
+                return (long) reader.nextChar();
+            } else if (from == short.class) {
+                return (long) reader.nextShort();
+            } else if (from == int.class) {
+                return (long) reader.nextInt();
+            } else if (from == long.class) {
+                return (long) reader.nextLong();
+            } else if (from == float.class) {
+                return (long) reader.nextFloat();
+            } else if (from == double.class) {
+                return (long) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1L : 0L;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static float readPrimitiveAsFloat(final StackFrameReader reader,
+                                                  final Class<?> from) {
+            if (from == byte.class) {
+                return (float) reader.nextByte();
+            } else if (from == char.class) {
+                return (float) reader.nextChar();
+            } else if (from == short.class) {
+                return (float) reader.nextShort();
+            } else if (from == int.class) {
+                return (float) reader.nextInt();
+            } else if (from == long.class) {
+                return (float) reader.nextLong();
+            } else if (from == float.class) {
+                return (float) reader.nextFloat();
+            } else if (from == double.class) {
+                return (float) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1.0f : 0.0f;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static double readPrimitiveAsDouble(final StackFrameReader reader,
+                                                    final Class<?> from) {
+            if (from == byte.class) {
+                return (double) reader.nextByte();
+            } else if (from == char.class) {
+                return (double) reader.nextChar();
+            } else if (from == short.class) {
+                return (double) reader.nextShort();
+            } else if (from == int.class) {
+                return (double) reader.nextInt();
+            } else if (from == long.class) {
+                return (double) reader.nextLong();
+            } else if (from == float.class) {
+                return (double) reader.nextFloat();
+            } else if (from == double.class) {
+                return (double) reader.nextDouble();
+            } else if (from == boolean.class) {
+                return reader.nextBoolean() ? 1.0 : 0.0;
+            } else {
+                throwUnexpectedType(from);
+                return 0;
+            }
+        }
+
+        private static void explicitCastPrimitives(final StackFrameReader reader,
+                                                   final Class<?> from,
+                                                   final StackFrameWriter writer,
+                                                   final Class<?> to) {
+            if (to == byte.class) {
+                byte value = readPrimitiveAsByte(reader, from);
+                writer.putNextByte(value);
+            } else if (to == char.class) {
+                char value = readPrimitiveAsChar(reader, from);
+                writer.putNextChar(value);
+            } else if (to == short.class) {
+                short value = readPrimitiveAsShort(reader, from);
+                writer.putNextShort(value);
+            } else if (to == int.class) {
+                int value = readPrimitiveAsInt(reader, from);
+                writer.putNextInt(value);
+            } else if (to == long.class) {
+                long value = readPrimitiveAsLong(reader, from);
+                writer.putNextLong(value);
+            } else if (to == float.class) {
+                float value = readPrimitiveAsFloat(reader, from);
+                writer.putNextFloat(value);
+            } else if (to == double.class) {
+                double value = readPrimitiveAsDouble(reader, from);
+                writer.putNextDouble(value);
+            } else if (to == boolean.class) {
+                byte byteValue = readPrimitiveAsByte(reader, from);
+                writer.putNextBoolean(toBoolean(byteValue));
+            } else {
+                throwUnexpectedType(to);
+            }
+        }
+
+        private static void unboxNull(final StackFrameWriter writer, final Class<?> to) {
+            if (to == boolean.class) {
+                writer.putNextBoolean(false);
+            } else if (to == byte.class) {
+                writer.putNextByte((byte) 0);
+            } else if (to == char.class) {
+                writer.putNextChar((char) 0);
+            } else if (to == short.class) {
+                writer.putNextShort((short) 0);
+            } else if (to == int.class) {
+                writer.putNextInt((int) 0);
+            } else if (to == long.class) {
+                writer.putNextLong((long) 0);
+            } else if (to == float.class) {
+                writer.putNextFloat((float) 0);
+            } else if (to == double.class) {
+                writer.putNextDouble((double) 0);
+            } else {
+                throwUnexpectedType(to);
+            }
+        }
+
+        private static void unboxNonNull(final Object ref, final Class<?> from,
+                                         final StackFrameWriter writer, final Class<?> to) {
+            if (from == Boolean.class) {
+                boolean z = (boolean) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean(z);
+                } else if (to == byte.class) {
+                    writer.putNextByte(z ? (byte) 1 : (byte) 0);
+                } else if (to == short.class) {
+                    writer.putNextShort(z ? (short) 1 : (short) 0);
+                } else if (to == char.class) {
+                    writer.putNextChar(z ? (char) 1 : (char) 0);
+                } else if (to == int.class) {
+                    writer.putNextInt(z ? 1 : 0);
+                } else if (to == long.class) {
+                    writer.putNextLong(z ? 1l : 0l);
+                } else if (to == float.class) {
+                    writer.putNextFloat(z ? 1.0f : 0.0f);
+                } else if (to == double.class) {
+                    writer.putNextDouble(z ? 1.0 : 0.0);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Byte.class) {
+                byte b = (byte) ref;
+                if (to == byte.class) {
+                    writer.putNextByte(b);
+                } else if (to == boolean.class) {
+                    writer.putNextBoolean(toBoolean(b));
+                } else if (to == short.class) {
+                    writer.putNextShort((short) b);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) b);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) b);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) b);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) b);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) b);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Short.class) {
+                short s = (short) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((s & 1) == 1);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) s);
+                } else if (to == short.class) {
+                    writer.putNextShort(s);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) s);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) s);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) s);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) s);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) s);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Character.class) {
+                char c = (char) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((c & (char) 1) == (char) 1);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) c);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) c);
+                } else if (to == char.class) {
+                    writer.putNextChar(c);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) c);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) c);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) c);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) c);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Integer.class) {
+                int i = (int) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((i & 1) == 1);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) i);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) i);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) i);
+                } else if (to == int.class) {
+                    writer.putNextInt(i);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) i);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) i);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) i);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Long.class) {
+                long j = (long) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean((j & 1l) == 1l);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) j);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) j);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) j);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) j);
+                } else if (to == long.class) {
+                    writer.putNextLong(j);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) j);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) j);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Float.class) {
+                float f = (float) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean(((byte) f & 1) != 0);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) f);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) f);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) f);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) f);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) f);
+                } else if (to == float.class) {
+                    writer.putNextFloat(f);
+                } else if (to == double.class) {
+                    writer.putNextDouble((double) f);
+                } else {
+                    badCast(from, to);
+                }
+            } else if (from == Double.class) {
+                double d = (double) ref;
+                if (to == boolean.class) {
+                    writer.putNextBoolean(((byte) d & 1) != 0);
+                } else if (to == byte.class) {
+                    writer.putNextByte((byte) d);
+                } else if (to == short.class) {
+                    writer.putNextShort((short) d);
+                } else if (to == char.class) {
+                    writer.putNextChar((char) d);
+                } else if (to == int.class) {
+                    writer.putNextInt((int) d);
+                } else if (to == long.class) {
+                    writer.putNextLong((long) d);
+                } else if (to == float.class) {
+                    writer.putNextFloat((float) d);
+                } else if (to == double.class) {
+                    writer.putNextDouble(d);
+                } else {
+                    badCast(from, to);
+                }
+            } else {
+                badCast(from, to);
+            }
+        }
+
+        private static void unbox(final Object ref, final Class<?> from,
+                                  final StackFrameWriter writer, final Class<?> to) {
+            if (ref == null) {
+                unboxNull(writer, to);
+            } else {
+                unboxNonNull(ref, from, writer, to);
+            }
+        }
+
+        private static void box(final StackFrameReader reader, final Class<?> from,
+                                final StackFrameWriter writer, final Class<?> to) {
+            Object boxed = null;
+            if (from == boolean.class) {
+                boxed = Boolean.valueOf(reader.nextBoolean());
+            } else if (from == byte.class) {
+                boxed = Byte.valueOf(reader.nextByte());
+            } else if (from == char.class) {
+                boxed = Character.valueOf(reader.nextChar());
+            } else if (from == short.class) {
+                boxed = Short.valueOf(reader.nextShort());
+            } else if (from == int.class) {
+                boxed = Integer.valueOf(reader.nextInt());
+            } else if (from == long.class) {
+                boxed = Long.valueOf(reader.nextLong());
+            } else if (from == float.class) {
+                boxed = Float.valueOf(reader.nextFloat());
+            } else if (from == double.class) {
+                boxed = Double.valueOf(reader.nextDouble());
+            } else {
+                throwUnexpectedType(from);
+            }
+            writer.putNextReference(to.cast(boxed), to);
+        }
+
+        private static void explicitCast(final StackFrameReader reader, final Class<?> from,
+                                         final StackFrameWriter writer, final Class<?> to) {
+            if (from.equals(to)) {
+                StackFrameAccessor.copyNext(reader, writer, from);
+                return;
+            }
+
+            if (from.isPrimitive()) {
+                if (to.isPrimitive()) {
+                    // |from| and |to| are primitive types.
+                    explicitCastPrimitives(reader, from, writer, to);
+                } else {
+                    // |from| is a primitive type, |to| is a reference type.
+                    box(reader, from, writer, to);
+                }
+            } else {
+                // |from| is a reference type.
+                Object ref = reader.nextReference(from);
+                if (to.isPrimitive()) {
+                    // |from| is a reference type, |to| is a primitive type,
+                    unbox(ref, from, writer, to);
+                } else if (to.isInterface()) {
+                    // Pass from without a cast according to description for
+                    // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
+                    writer.putNextReference(ref, to);
+                } else {
+                    // |to| and from |from| are reference types, perform class cast check.
+                    writer.putNextReference(to.cast(ref), to);
+                }
+            }
+        }
+    }
+}
diff --git a/java/lang/invoke/VarHandle.java b/java/lang/invoke/VarHandle.java
new file mode 100644
index 0000000..7b5ac00
--- /dev/null
+++ b/java/lang/invoke/VarHandle.java
@@ -0,0 +1,2386 @@
+/*
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import dalvik.system.VMRuntime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A VarHandle is a dynamically strongly typed reference to a variable, or to a
+ * parametrically-defined family of variables, including static fields,
+ * non-static fields, array elements, or components of an off-heap data
+ * structure.  Access to such variables is supported under various
+ * <em>access modes</em>, including plain read/write access, volatile
+ * read/write access, and compare-and-swap.
+ *
+ * <p>VarHandles are immutable and have no visible state.  VarHandles cannot be
+ * subclassed by the user.
+ *
+ * <p>A VarHandle has:
+ * <ul>
+ * <li>a {@link #varType variable type} T, the type of every variable referenced
+ * by this VarHandle; and
+ * <li>a list of {@link #coordinateTypes coordinate types}
+ * {@code CT1, CT2, ..., CTn}, the types of <em>coordinate expressions</em> that
+ * jointly locate a variable referenced by this VarHandle.
+ * </ul>
+ * Variable and coordinate types may be primitive or reference, and are
+ * represented by {@code Class} objects.  The list of coordinate types may be
+ * empty.
+ *
+ * <p>Factory methods that produce or {@link java.lang.invoke.MethodHandles.Lookup
+ * lookup} VarHandle instances document the supported variable type and the list
+ * of coordinate types.
+ *
+ * <p>Each access mode is associated with one <em>access mode method</em>, a
+ * <a href="MethodHandle.html#sigpoly">signature polymorphic</a> method named
+ * for the access mode.  When an access mode method is invoked on a VarHandle
+ * instance, the initial arguments to the invocation are coordinate expressions
+ * that indicate in precisely which object the variable is to be accessed.
+ * Trailing arguments to the invocation represent values of importance to the
+ * access mode.  For example, the various compare-and-set or compare-and-exchange
+ * access modes require two trailing arguments for the variable's expected value
+ * and new value.
+ *
+ * <p>The arity and types of arguments to the invocation of an access mode
+ * method are not checked statically.  Instead, each access mode method
+ * specifies an {@link #accessModeType(AccessMode) access mode type},
+ * represented as an instance of {@link MethodType}, that serves as a kind of
+ * method signature against which the arguments are checked dynamically.  An
+ * access mode type gives formal parameter types in terms of the coordinate
+ * types of a VarHandle instance and the types for values of importance to the
+ * access mode.  An access mode type also gives a return type, often in terms of
+ * the variable type of a VarHandle instance.  When an access mode method is
+ * invoked on a VarHandle instance, the symbolic type descriptor at the
+ * call site, the run time types of arguments to the invocation, and the run
+ * time type of the return value, must <a href="#invoke">match</a> the types
+ * given in the access mode type.  A runtime exception will be thrown if the
+ * match fails.
+ *
+ * For example, the access mode method {@link #compareAndSet} specifies that if
+ * its receiver is a VarHandle instance with coordinate types
+ * {@code CT1, ..., CTn} and variable type {@code T}, then its access mode type
+ * is {@code (CT1 c1, ..., CTn cn, T expectedValue, T newValue)boolean}.
+ * Suppose that a VarHandle instance can access array elements, and that its
+ * coordinate types are {@code String[]} and {@code int} while its variable type
+ * is {@code String}.  The access mode type for {@code compareAndSet} on this
+ * VarHandle instance would be
+ * {@code (String[] c1, int c2, String expectedValue, String newValue)boolean}.
+ * Such a VarHandle instance may produced by the
+ * {@link MethodHandles#arrayElementVarHandle(Class) array factory method} and
+ * access array elements as follows:
+ * <pre> {@code
+ * String[] sa = ...
+ * VarHandle avh = MethodHandles.arrayElementVarHandle(String[].class);
+ * boolean r = avh.compareAndSet(sa, 10, "expected", "new");
+ * }</pre>
+ *
+ * <p>Access modes control atomicity and consistency properties.
+ * <em>Plain</em> read ({@code get}) and write ({@code set})
+ * accesses are guaranteed to be bitwise atomic only for references
+ * and for primitive values of at most 32 bits, and impose no observable
+ * ordering constraints with respect to threads other than the
+ * executing thread. <em>Opaque</em> operations are bitwise atomic and
+ * coherently ordered with respect to accesses to the same variable.
+ * In addition to obeying Opaque properties, <em>Acquire</em> mode
+ * reads and their subsequent accesses are ordered after matching
+ * <em>Release</em> mode writes and their previous accesses.  In
+ * addition to obeying Acquire and Release properties, all
+ * <em>Volatile</em> operations are totally ordered with respect to
+ * each other.
+ *
+ * <p>Access modes are grouped into the following categories:
+ * <ul>
+ * <li>read access modes that get the value of a variable under specified
+ * memory ordering effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #get get},
+ * {@link #getVolatile getVolatile},
+ * {@link #getAcquire getAcquire},
+ * {@link #getOpaque getOpaque}.
+ * <li>write access modes that set the value of a variable under specified
+ * memory ordering effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #set set},
+ * {@link #setVolatile setVolatile},
+ * {@link #setRelease setRelease},
+ * {@link #setOpaque setOpaque}.
+ * <li>atomic update access modes that, for example, atomically compare and set
+ * the value of a variable under specified memory ordering effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #compareAndSet compareAndSet},
+ * {@link #weakCompareAndSetPlain weakCompareAndSetPlain},
+ * {@link #weakCompareAndSet weakCompareAndSet},
+ * {@link #weakCompareAndSetAcquire weakCompareAndSetAcquire},
+ * {@link #weakCompareAndSetRelease weakCompareAndSetRelease},
+ * {@link #compareAndExchangeAcquire compareAndExchangeAcquire},
+ * {@link #compareAndExchange compareAndExchange},
+ * {@link #compareAndExchangeRelease compareAndExchangeRelease},
+ * {@link #getAndSet getAndSet},
+ * {@link #getAndSetAcquire getAndSetAcquire},
+ * {@link #getAndSetRelease getAndSetRelease}.
+ * <li>numeric atomic update access modes that, for example, atomically get and
+ * set with addition the value of a variable under specified memory ordering
+ * effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #getAndAdd getAndAdd},
+ * {@link #getAndAddAcquire getAndAddAcquire},
+ * {@link #getAndAddRelease getAndAddRelease},
+ * <li>bitwise atomic update access modes that, for example, atomically get and
+ * bitwise OR the value of a variable under specified memory ordering
+ * effects.
+ * The set of corresponding access mode methods belonging to this group
+ * consists of the methods
+ * {@link #getAndBitwiseOr getAndBitwiseOr},
+ * {@link #getAndBitwiseOrAcquire getAndBitwiseOrAcquire},
+ * {@link #getAndBitwiseOrRelease getAndBitwiseOrRelease},
+ * {@link #getAndBitwiseAnd getAndBitwiseAnd},
+ * {@link #getAndBitwiseAndAcquire getAndBitwiseAndAcquire},
+ * {@link #getAndBitwiseAndRelease getAndBitwiseAndRelease},
+ * {@link #getAndBitwiseXor getAndBitwiseXor},
+ * {@link #getAndBitwiseXorAcquire getAndBitwiseXorAcquire},
+ * {@link #getAndBitwiseXorRelease getAndBitwiseXorRelease}.
+ * </ul>
+ *
+ * <p>Factory methods that produce or {@link java.lang.invoke.MethodHandles.Lookup
+ * lookup} VarHandle instances document the set of access modes that are
+ * supported, which may also include documenting restrictions based on the
+ * variable type and whether a variable is read-only.  If an access mode is not
+ * supported then the corresponding access mode method will on invocation throw
+ * an {@code UnsupportedOperationException}.  Factory methods should document
+ * any additional undeclared exceptions that may be thrown by access mode
+ * methods.
+ * The {@link #get get} access mode is supported for all
+ * VarHandle instances and the corresponding method never throws
+ * {@code UnsupportedOperationException}.
+ * If a VarHandle references a read-only variable (for example a {@code final}
+ * field) then write, atomic update, numeric atomic update, and bitwise atomic
+ * update access modes are not supported and corresponding methods throw
+ * {@code UnsupportedOperationException}.
+ * Read/write access modes (if supported), with the exception of
+ * {@code get} and {@code set}, provide atomic access for
+ * reference types and all primitive types.
+ * Unless stated otherwise in the documentation of a factory method, the access
+ * modes {@code get} and {@code set} (if supported) provide atomic access for
+ * reference types and all primitives types, with the exception of {@code long}
+ * and {@code double} on 32-bit platforms.
+ *
+ * <p>Access modes will override any memory ordering effects specified at
+ * the declaration site of a variable.  For example, a VarHandle accessing a
+ * a field using the {@code get} access mode will access the field as
+ * specified <em>by its access mode</em> even if that field is declared
+ * {@code volatile}.  When mixed access is performed extreme care should be
+ * taken since the Java Memory Model may permit surprising results.
+ *
+ * <p>In addition to supporting access to variables under various access modes,
+ * a set of static methods, referred to as memory fence methods, is also
+ * provided for fine-grained control of memory ordering.
+ *
+ * The Java Language Specification permits other threads to observe operations
+ * as if they were executed in orders different than are apparent in program
+ * source code, subject to constraints arising, for example, from the use of
+ * locks, {@code volatile} fields or VarHandles.  The static methods,
+ * {@link #fullFence fullFence}, {@link #acquireFence acquireFence},
+ * {@link #releaseFence releaseFence}, {@link #loadLoadFence loadLoadFence} and
+ * {@link #storeStoreFence storeStoreFence}, can also be used to impose
+ * constraints.  Their specifications, as is the case for certain access modes,
+ * are phrased in terms of the lack of "reorderings" -- observable ordering
+ * effects that might otherwise occur if the fence was not present.  More
+ * precise phrasing of the specification of access mode methods and memory fence
+ * methods may accompany future updates of the Java Language Specification.
+ *
+ * <h1>Compiling invocation of access mode methods</h1>
+ * A Java method call expression naming an access mode method can invoke a
+ * VarHandle from Java source code.  From the viewpoint of source code, these
+ * methods can take any arguments and their polymorphic result (if expressed)
+ * can be cast to any return type.  Formally this is accomplished by giving the
+ * access mode methods variable arity {@code Object} arguments and
+ * {@code Object} return types (if the return type is polymorphic), but they
+ * have an additional quality called <em>signature polymorphism</em> which
+ * connects this freedom of invocation directly to the JVM execution stack.
+ * <p>
+ * As is usual with virtual methods, source-level calls to access mode methods
+ * compile to an {@code invokevirtual} instruction.  More unusually, the
+ * compiler must record the actual argument types, and may not perform method
+ * invocation conversions on the arguments.  Instead, it must generate
+ * instructions to push them on the stack according to their own unconverted
+ * types.  The VarHandle object itself will be pushed on the stack before the
+ * arguments.  The compiler then generates an {@code invokevirtual} instruction
+ * that invokes the access mode method with a symbolic type descriptor which
+ * describes the argument and return types.
+ * <p>
+ * To issue a complete symbolic type descriptor, the compiler must also
+ * determine the return type (if polymorphic).  This is based on a cast on the
+ * method invocation expression, if there is one, or else {@code Object} if the
+ * invocation is an expression, or else {@code void} if the invocation is a
+ * statement.  The cast may be to a primitive type (but not {@code void}).
+ * <p>
+ * As a corner case, an uncasted {@code null} argument is given a symbolic type
+ * descriptor of {@code java.lang.Void}.  The ambiguity with the type
+ * {@code Void} is harmless, since there are no references of type {@code Void}
+ * except the null reference.
+ *
+ *
+ * <h1><a id="invoke">Performing invocation of access mode methods</a></h1>
+ * The first time an {@code invokevirtual} instruction is executed it is linked
+ * by symbolically resolving the names in the instruction and verifying that
+ * the method call is statically legal.  This also holds for calls to access mode
+ * methods.  In this case, the symbolic type descriptor emitted by the compiler
+ * is checked for correct syntax, and names it contains are resolved.  Thus, an
+ * {@code invokevirtual} instruction which invokes an access mode method will
+ * always link, as long as the symbolic type descriptor is syntactically
+ * well-formed and the types exist.
+ * <p>
+ * When the {@code invokevirtual} is executed after linking, the receiving
+ * VarHandle's access mode type is first checked by the JVM to ensure that it
+ * matches the symbolic type descriptor.  If the type
+ * match fails, it means that the access mode method which the caller is
+ * invoking is not present on the individual VarHandle being invoked.
+ *
+ * <p>
+ * Invocation of an access mode method behaves as if an invocation of
+ * {@link MethodHandle#invoke}, where the receiving method handle accepts the
+ * VarHandle instance as the leading argument.  More specifically, the
+ * following, where {@code {access-mode}} corresponds to the access mode method
+ * name:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * R r = (R) vh.{access-mode}(p1, p2, ..., pN);
+ * }</pre>
+ * behaves as if:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
+ * MethodHandle mh = MethodHandles.varHandleExactInvoker(
+ *                       am,
+ *                       vh.accessModeType(am));
+ *
+ * R r = (R) mh.invoke(vh, p1, p2, ..., pN)
+ * }</pre>
+ * (modulo access mode methods do not declare throwing of {@code Throwable}).
+ * This is equivalent to:
+ * <pre> {@code
+ * MethodHandle mh = MethodHandles.lookup().findVirtual(
+ *                       VarHandle.class,
+ *                       "{access-mode}",
+ *                       MethodType.methodType(R, p1, p2, ..., pN));
+ *
+ * R r = (R) mh.invokeExact(vh, p1, p2, ..., pN)
+ * }</pre>
+ * where the desired method type is the symbolic type descriptor and a
+ * {@link MethodHandle#invokeExact} is performed, since before invocation of the
+ * target, the handle will apply reference casts as necessary and box, unbox, or
+ * widen primitive values, as if by {@link MethodHandle#asType asType} (see also
+ * {@link MethodHandles#varHandleInvoker}).
+ *
+ * More concisely, such behaviour is equivalent to:
+ * <pre> {@code
+ * VarHandle vh = ..
+ * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
+ * MethodHandle mh = vh.toMethodHandle(am);
+ *
+ * R r = (R) mh.invoke(p1, p2, ..., pN)
+ * }</pre>
+ * Where, in this case, the method handle is bound to the VarHandle instance.
+ *
+ *
+ * <h1>Invocation checking</h1>
+ * In typical programs, VarHandle access mode type matching will usually
+ * succeed.  But if a match fails, the JVM will throw a
+ * {@link WrongMethodTypeException}.
+ * <p>
+ * Thus, an access mode type mismatch which might show up as a linkage error
+ * in a statically typed program can show up as a dynamic
+ * {@code WrongMethodTypeException} in a program which uses VarHandles.
+ * <p>
+ * Because access mode types contain "live" {@code Class} objects, method type
+ * matching takes into account both type names and class loaders.
+ * Thus, even if a VarHandle {@code VH} is created in one class loader
+ * {@code L1} and used in another {@code L2}, VarHandle access mode method
+ * calls are type-safe, because the caller's symbolic type descriptor, as
+ * resolved in {@code L2}, is matched against the original callee method's
+ * symbolic type descriptor, as resolved in {@code L1}.  The resolution in
+ * {@code L1} happens when {@code VH} is created and its access mode types are
+ * assigned, while the resolution in {@code L2} happens when the
+ * {@code invokevirtual} instruction is linked.
+ * <p>
+ * Apart from type descriptor checks, a VarHandles's capability to
+ * access it's variables is unrestricted.
+ * If a VarHandle is formed on a non-public variable by a class that has access
+ * to that variable, the resulting VarHandle can be used in any place by any
+ * caller who receives a reference to it.
+ * <p>
+ * Unlike with the Core Reflection API, where access is checked every time a
+ * reflective method is invoked, VarHandle access checking is performed
+ * <a href="MethodHandles.Lookup.html#access">when the VarHandle is
+ * created</a>.
+ * Thus, VarHandles to non-public variables, or to variables in non-public
+ * classes, should generally be kept secret.  They should not be passed to
+ * untrusted code unless their use from the untrusted code would be harmless.
+ *
+ *
+ * <h1>VarHandle creation</h1>
+ * Java code can create a VarHandle that directly accesses any field that is
+ * accessible to that code.  This is done via a reflective, capability-based
+ * API called {@link java.lang.invoke.MethodHandles.Lookup
+ * MethodHandles.Lookup}.
+ * For example, a VarHandle for a non-static field can be obtained
+ * from {@link java.lang.invoke.MethodHandles.Lookup#findVarHandle
+ * Lookup.findVarHandle}.
+ * There is also a conversion method from Core Reflection API objects,
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflectVarHandle
+ * Lookup.unreflectVarHandle}.
+ * <p>
+ * Access to protected field members is restricted to receivers only of the
+ * accessing class, or one of its subclasses, and the accessing class must in
+ * turn be a subclass (or package sibling) of the protected member's defining
+ * class.  If a VarHandle refers to a protected non-static field of a declaring
+ * class outside the current package, the receiver argument will be narrowed to
+ * the type of the accessing class.
+ *
+ * <h1>Interoperation between VarHandles and the Core Reflection API</h1>
+ * Using factory methods in the {@link java.lang.invoke.MethodHandles.Lookup
+ * Lookup} API, any field represented by a Core Reflection API object
+ * can be converted to a behaviorally equivalent VarHandle.
+ * For example, a reflective {@link java.lang.reflect.Field Field} can
+ * be converted to a VarHandle using
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflectVarHandle
+ * Lookup.unreflectVarHandle}.
+ * The resulting VarHandles generally provide more direct and efficient
+ * access to the underlying fields.
+ * <p>
+ * As a special case, when the Core Reflection API is used to view the
+ * signature polymorphic access mode methods in this class, they appear as
+ * ordinary non-polymorphic methods.  Their reflective appearance, as viewed by
+ * {@link java.lang.Class#getDeclaredMethod Class.getDeclaredMethod},
+ * is unaffected by their special status in this API.
+ * For example, {@link java.lang.reflect.Method#getModifiers
+ * Method.getModifiers}
+ * will report exactly those modifier bits required for any similarly
+ * declared method, including in this case {@code native} and {@code varargs}
+ * bits.
+ * <p>
+ * As with any reflected method, these methods (when reflected) may be invoked
+ * directly via {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke},
+ * via JNI, or indirectly via
+ * {@link java.lang.invoke.MethodHandles.Lookup#unreflect Lookup.unreflect}.
+ * However, such reflective calls do not result in access mode method
+ * invocations.  Such a call, if passed the required argument (a single one, of
+ * type {@code Object[]}), will ignore the argument and will throw an
+ * {@code UnsupportedOperationException}.
+ * <p>
+ * Since {@code invokevirtual} instructions can natively invoke VarHandle
+ * access mode methods under any symbolic type descriptor, this reflective view
+ * conflicts with the normal presentation of these methods via bytecodes.
+ * Thus, these native methods, when reflectively viewed by
+ * {@code Class.getDeclaredMethod}, may be regarded as placeholders only.
+ * <p>
+ * In order to obtain an invoker method for a particular access mode type,
+ * use {@link java.lang.invoke.MethodHandles#varHandleExactInvoker} or
+ * {@link java.lang.invoke.MethodHandles#varHandleInvoker}.  The
+ * {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual}
+ * API is also able to return a method handle to call an access mode method for
+ * any specified access mode type and is equivalent in behaviour to
+ * {@link java.lang.invoke.MethodHandles#varHandleInvoker}.
+ *
+ * <h1>Interoperation between VarHandles and Java generics</h1>
+ * A VarHandle can be obtained for a variable, such as a a field, which is
+ * declared with Java generic types.  As with the Core Reflection API, the
+ * VarHandle's variable type will be constructed from the erasure of the
+ * source-level type.  When a VarHandle access mode method is invoked, the
+ * types
+ * of its arguments or the return value cast type may be generic types or type
+ * instances.  If this occurs, the compiler will replace those types by their
+ * erasures when it constructs the symbolic type descriptor for the
+ * {@code invokevirtual} instruction.
+ *
+ * @see MethodHandle
+ * @see MethodHandles
+ * @see MethodType
+ * @since 9
+ * @hide
+ */
+public abstract class VarHandle {
+    // Android-added: Using sun.misc.Unsafe for fence implementation.
+    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
+
+    // BEGIN Android-removed: No VarForm in Android implementation.
+    /*
+    final VarForm vform;
+
+    VarHandle(VarForm vform) {
+        this.vform = vform;
+    }
+    */
+    // END Android-removed: No VarForm in Android implementation.
+
+    // BEGIN Android-added: fields for common metadata.
+    /** The target type for accesses. */
+    private final Class<?> varType;
+
+    /** This VarHandle's first coordinate, or null if this VarHandle has no coordinates. */
+    private final Class<?> coordinateType0;
+
+    /** This VarHandle's second coordinate, or null if this VarHandle has less than two
+     * coordinates. */
+    private final Class<?> coordinateType1;
+
+    /** BitMask of supported access mode indexed by AccessMode.ordinal(). */
+    private final int accessModesBitMask;
+    // END Android-added: fields for common metadata.
+
+    // Plain accessors
+
+    /**
+     * Returns the value of a variable, with memory semantics of reading as
+     * if the variable was declared non-{@code volatile}.  Commonly referred to
+     * as plain read access.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code get}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET)} on this VarHandle.
+     *
+     * <p>This access mode is supported by all VarHandle instances and never
+     * throws {@code UnsupportedOperationException}.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the value of the
+     * variable
+     * , statically represented using {@code Object}.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object get(Object... args);
+
+    /**
+     * Sets the value of a variable to the {@code newValue}, with memory
+     * semantics of setting as if the variable was declared non-{@code volatile}
+     * and non-{@code final}.  Commonly referred to as plain write access.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}
+     *
+     * <p>The symbolic type descriptor at the call site of {@code set}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.SET)} on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    void set(Object... args);
+
+
+    // Volatile accessors
+
+    /**
+     * Returns the value of a variable, with memory semantics of reading as if
+     * the variable was declared {@code volatile}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getVolatile}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_VOLATILE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the value of the
+     * variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getVolatile(Object... args);
+
+    /**
+     * Sets the value of a variable to the {@code newValue}, with memory
+     * semantics of setting as if the variable was declared {@code volatile}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code setVolatile}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.SET_VOLATILE)} on this
+     * VarHandle.
+     *
+     * @apiNote
+     * Ignoring the many semantic differences from C and C++, this method has
+     * memory ordering effects compatible with {@code memory_order_seq_cst}.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    void setVolatile(Object... args);
+
+
+    /**
+     * Returns the value of a variable, accessed in program order, but with no
+     * assurance of memory ordering effects with respect to other threads.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getOpaque}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_OPAQUE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the value of the
+     * variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getOpaque(Object... args);
+
+    /**
+     * Sets the value of a variable to the {@code newValue}, in program order,
+     * but with no assurance of memory ordering effects with respect to other
+     * threads.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code setOpaque}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.SET_OPAQUE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    void setOpaque(Object... args);
+
+
+    // Lazy accessors
+
+    /**
+     * Returns the value of a variable, and ensures that subsequent loads and
+     * stores are not reordered before this access.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_ACQUIRE)} on this
+     * VarHandle.
+     *
+     * @apiNote
+     * Ignoring the many semantic differences from C and C++, this method has
+     * memory ordering effects compatible with {@code memory_order_acquire}
+     * ordering.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the value of the
+     * variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAcquire(Object... args);
+
+    /**
+     * Sets the value of a variable to the {@code newValue}, and ensures that
+     * prior loads and stores are not reordered after this access.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)void}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code setRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.SET_RELEASE)} on this
+     * VarHandle.
+     *
+     * @apiNote
+     * Ignoring the many semantic differences from C and C++, this method has
+     * memory ordering effects compatible with {@code memory_order_release}
+     * ordering.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    void setRelease(Object... args);
+
+
+    // Compare and set accessors
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #setVolatile} if the variable's current value,
+     * referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * compareAndSet} must match the access mode type that is the result of
+     * calling {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_SET)} on
+     * this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return {@code true} if successful, otherwise {@code false} if the
+     * witness value was not the same as the {@code expectedValue}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    boolean compareAndSet(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #setVolatile} if the variable's current value,
+     * referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * compareAndExchange}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the witness value, which
+     * will be the same as the {@code expectedValue} if successful
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type is not
+     * compatible with the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type is compatible with the
+     * caller's symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object compareAndExchange(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #set} if the variable's current value,
+     * referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * compareAndExchangeAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)} on
+     * this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the witness value, which
+     * will be the same as the {@code expectedValue} if successful
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #set(Object...)
+     * @see #getAcquire(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object compareAndExchangeAcquire(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #setRelease} if the variable's current value,
+     * referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * compareAndExchangeRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the witness value, which
+     * will be the same as the {@code expectedValue} if successful
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setRelease(Object...)
+     * @see #get(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object compareAndExchangeRelease(Object... args);
+
+    // Weak (spurious failures allowed)
+
+    /**
+     * Possibly atomically sets the value of a variable to the {@code newValue}
+     * with the semantics of {@link #set} if the variable's current value,
+     * referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>This operation may fail spuriously (typically, due to memory
+     * contention) even if the witness value does match the expected value.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * weakCompareAndSetPlain} must match the access mode type that is the result of
+     * calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_PLAIN)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return {@code true} if successful, otherwise {@code false} if the
+     * witness value was not the same as the {@code expectedValue} or if this
+     * operation spuriously failed.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #set(Object...)
+     * @see #get(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    boolean weakCompareAndSetPlain(Object... args);
+
+    /**
+     * Possibly atomically sets the value of a variable to the {@code newValue}
+     * with the memory semantics of {@link #setVolatile} if the variable's
+     * current value, referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>This operation may fail spuriously (typically, due to memory
+     * contention) even if the witness value does match the expected value.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * weakCompareAndSet} must match the access mode type that is the
+     * result of calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return {@code true} if successful, otherwise {@code false} if the
+     * witness value was not the same as the {@code expectedValue} or if this
+     * operation spuriously failed.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    boolean weakCompareAndSet(Object... args);
+
+    /**
+     * Possibly atomically sets the value of a variable to the {@code newValue}
+     * with the semantics of {@link #set} if the variable's current value,
+     * referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>This operation may fail spuriously (typically, due to memory
+     * contention) even if the witness value does match the expected value.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * weakCompareAndSetAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return {@code true} if successful, otherwise {@code false} if the
+     * witness value was not the same as the {@code expectedValue} or if this
+     * operation spuriously failed.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #set(Object...)
+     * @see #getAcquire(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    boolean weakCompareAndSetAcquire(Object... args);
+
+    /**
+     * Possibly atomically sets the value of a variable to the {@code newValue}
+     * with the semantics of {@link #setRelease} if the variable's current
+     * value, referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>This operation may fail spuriously (typically, due to memory
+     * contention) even if the witness value does match the expected value.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)boolean}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * weakCompareAndSetRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return {@code true} if successful, otherwise {@code false} if the
+     * witness value was not the same as the {@code expectedValue} or if this
+     * operation spuriously failed.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setRelease(Object...)
+     * @see #get(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    boolean weakCompareAndSetRelease(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #setVolatile} and returns the variable's
+     * previous value, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndSet}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndSet(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #set} and returns the variable's
+     * previous value, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndSetAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET_ACQUIRE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndSetAcquire(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the {@code newValue} with the
+     * memory semantics of {@link #setRelease} and returns the variable's
+     * previous value, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T newValue)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndSetRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET_RELEASE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T newValue)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndSetRelease(Object... args);
+
+    // Primitive adders
+    // Throw UnsupportedOperationException for refs
+
+    /**
+     * Atomically adds the {@code value} to the current value of a variable with
+     * the memory semantics of {@link #setVolatile}, and returns the variable's
+     * previous value, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T value)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndAdd}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T value)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndAdd(Object... args);
+
+    /**
+     * Atomically adds the {@code value} to the current value of a variable with
+     * the memory semantics of {@link #set}, and returns the variable's
+     * previous value, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T value)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndAddAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD_ACQUIRE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T value)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndAddAcquire(Object... args);
+
+    /**
+     * Atomically adds the {@code value} to the current value of a variable with
+     * the memory semantics of {@link #setRelease}, and returns the variable's
+     * previous value, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T value)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndAddRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD_RELEASE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T value)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndAddRelease(Object... args);
+
+
+    // Bitwise operations
+    // Throw UnsupportedOperationException for refs
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise OR between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #setVolatile} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical OR is performed instead of a bitwise OR.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseOr}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_OR)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseOr(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise OR between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #set} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical OR is performed instead of a bitwise OR.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseOrAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_OR_ACQUIRE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #set(Object...)
+     * @see #getAcquire(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseOrAcquire(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise OR between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #setRelease} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical OR is performed instead of a bitwise OR.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseOrRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_OR_RELEASE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setRelease(Object...)
+     * @see #get(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseOrRelease(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise AND between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #setVolatile} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical AND is performed instead of a bitwise AND.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseAnd}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_AND)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseAnd(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise AND between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #set} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical AND is performed instead of a bitwise AND.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseAndAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_AND_ACQUIRE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #set(Object...)
+     * @see #getAcquire(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseAndAcquire(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise AND between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #setRelease} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical AND is performed instead of a bitwise AND.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseAndRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_AND_RELEASE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setRelease(Object...)
+     * @see #get(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseAndRelease(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise XOR between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #setVolatile} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical XOR is performed instead of a bitwise XOR.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseXor}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_XOR)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseXor(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise XOR between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #set} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #getAcquire}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical XOR is performed instead of a bitwise XOR.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseXorAcquire}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_XOR_ACQUIRE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #set(Object...)
+     * @see #getAcquire(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseXorAcquire(Object... args);
+
+    /**
+     * Atomically sets the value of a variable to the result of
+     * bitwise XOR between the variable's current value and the {@code mask}
+     * with the memory semantics of {@link #setRelease} and returns the
+     * variable's previous value, as accessed with the memory semantics of
+     * {@link #get}.
+     *
+     * <p>If the variable type is the non-integral {@code boolean} type then a
+     * logical XOR is performed instead of a bitwise XOR.
+     *
+     * <p>The method signature is of the form {@code (CT1 ct1, ..., CTn ctn, T mask)T}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code getAndBitwiseXorRelease}
+     * must match the access mode type that is the result of calling
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_BITWISE_XOR_RELEASE)} on this
+     * VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT1 ct1, ..., CTn ctn, T mask)}
+     * , statically represented using varargs.
+     * @return the signature-polymorphic result that is the previous value of
+     * the variable
+     * , statically represented using {@code Object}.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type does not
+     * match the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type matches the caller's
+     * symbolic type descriptor, but a reference cast fails.
+     * @see #setRelease(Object...)
+     * @see #get(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    // Android-removed: unsupported annotation.
+    // @HotSpotIntrinsicCandidate
+    Object getAndBitwiseXorRelease(Object... args);
+
+
+    // Android-changed: remove unused return type in AccessType constructor.
+    enum AccessType {
+        GET,
+        SET,
+        COMPARE_AND_SWAP,
+        COMPARE_AND_EXCHANGE,
+        GET_AND_UPDATE,
+        // Android-added: Finer grained access types.
+        // These are used to help categorize the access modes that a VarHandle supports.
+        GET_AND_UPDATE_BITWISE,
+        GET_AND_UPDATE_NUMERIC;
+
+        MethodType accessModeType(Class<?> receiver, Class<?> value,
+                                  Class<?>... intermediate) {
+            Class<?>[] ps;
+            int i;
+            switch (this) {
+                case GET:
+                    ps = allocateParameters(0, receiver, intermediate);
+                    fillParameters(ps, receiver, intermediate);
+                    return MethodType.methodType(value, ps);
+                case SET:
+                    ps = allocateParameters(1, receiver, intermediate);
+                    i = fillParameters(ps, receiver, intermediate);
+                    ps[i] = value;
+                    return MethodType.methodType(void.class, ps);
+                case COMPARE_AND_SWAP:
+                    ps = allocateParameters(2, receiver, intermediate);
+                    i = fillParameters(ps, receiver, intermediate);
+                    ps[i++] = value;
+                    ps[i] = value;
+                    return MethodType.methodType(boolean.class, ps);
+                case COMPARE_AND_EXCHANGE:
+                    ps = allocateParameters(2, receiver, intermediate);
+                    i = fillParameters(ps, receiver, intermediate);
+                    ps[i++] = value;
+                    ps[i] = value;
+                    return MethodType.methodType(value, ps);
+                case GET_AND_UPDATE:
+                case GET_AND_UPDATE_BITWISE:
+                case GET_AND_UPDATE_NUMERIC:
+                    ps = allocateParameters(1, receiver, intermediate);
+                    i = fillParameters(ps, receiver, intermediate);
+                    ps[i] = value;
+                    return MethodType.methodType(value, ps);
+                default:
+                    throw new InternalError("Unknown AccessType");
+            }
+        }
+
+        private static Class<?>[] allocateParameters(int values,
+                                                     Class<?> receiver, Class<?>... intermediate) {
+            int size = ((receiver != null) ? 1 : 0) + intermediate.length + values;
+            return new Class<?>[size];
+        }
+
+        private static int fillParameters(Class<?>[] ps,
+                                          Class<?> receiver, Class<?>... intermediate) {
+            int i = 0;
+            if (receiver != null)
+                ps[i++] = receiver;
+            for (int j = 0; j < intermediate.length; j++)
+                ps[i++] = intermediate[j];
+            return i;
+        }
+    }
+
+    /**
+     * The set of access modes that specify how a variable, referenced by a
+     * VarHandle, is accessed.
+     */
+    public enum AccessMode {
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#get VarHandle.get}
+         */
+        GET("get", AccessType.GET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#set VarHandle.set}
+         */
+        SET("set", AccessType.SET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getVolatile VarHandle.getVolatile}
+         */
+        GET_VOLATILE("getVolatile", AccessType.GET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#setVolatile VarHandle.setVolatile}
+         */
+        SET_VOLATILE("setVolatile", AccessType.SET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAcquire VarHandle.getAcquire}
+         */
+        GET_ACQUIRE("getAcquire", AccessType.GET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#setRelease VarHandle.setRelease}
+         */
+        SET_RELEASE("setRelease", AccessType.SET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getOpaque VarHandle.getOpaque}
+         */
+        GET_OPAQUE("getOpaque", AccessType.GET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#setOpaque VarHandle.setOpaque}
+         */
+        SET_OPAQUE("setOpaque", AccessType.SET),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#compareAndSet VarHandle.compareAndSet}
+         */
+        COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#compareAndExchange VarHandle.compareAndExchange}
+         */
+        COMPARE_AND_EXCHANGE("compareAndExchange", AccessType.COMPARE_AND_EXCHANGE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#compareAndExchangeAcquire VarHandle.compareAndExchangeAcquire}
+         */
+        COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#compareAndExchangeRelease VarHandle.compareAndExchangeRelease}
+         */
+        COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#weakCompareAndSetPlain VarHandle.weakCompareAndSetPlain}
+         */
+        WEAK_COMPARE_AND_SET_PLAIN("weakCompareAndSetPlain", AccessType.COMPARE_AND_SWAP),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#weakCompareAndSet VarHandle.weakCompareAndSet}
+         */
+        WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#weakCompareAndSetAcquire VarHandle.weakCompareAndSetAcquire}
+         */
+        WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#weakCompareAndSetRelease VarHandle.weakCompareAndSetRelease}
+         */
+        WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndSet VarHandle.getAndSet}
+         */
+        GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndSetAcquire VarHandle.getAndSetAcquire}
+         */
+        GET_AND_SET_ACQUIRE("getAndSetAcquire", AccessType.GET_AND_UPDATE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndSetRelease VarHandle.getAndSetRelease}
+         */
+        GET_AND_SET_RELEASE("getAndSetRelease", AccessType.GET_AND_UPDATE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndAdd VarHandle.getAndAdd}
+         */
+        GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE_NUMERIC),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndAddAcquire VarHandle.getAndAddAcquire}
+         */
+        GET_AND_ADD_ACQUIRE("getAndAddAcquire", AccessType.GET_AND_UPDATE_NUMERIC),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndAddRelease VarHandle.getAndAddRelease}
+         */
+        GET_AND_ADD_RELEASE("getAndAddRelease", AccessType.GET_AND_UPDATE_NUMERIC),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseOr VarHandle.getAndBitwiseOr}
+         */
+        GET_AND_BITWISE_OR("getAndBitwiseOr", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseOrRelease VarHandle.getAndBitwiseOrRelease}
+         */
+        GET_AND_BITWISE_OR_RELEASE("getAndBitwiseOrRelease", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseOrAcquire VarHandle.getAndBitwiseOrAcquire}
+         */
+        GET_AND_BITWISE_OR_ACQUIRE("getAndBitwiseOrAcquire", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseAnd VarHandle.getAndBitwiseAnd}
+         */
+        GET_AND_BITWISE_AND("getAndBitwiseAnd", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseAndRelease VarHandle.getAndBitwiseAndRelease}
+         */
+        GET_AND_BITWISE_AND_RELEASE("getAndBitwiseAndRelease", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseAndAcquire VarHandle.getAndBitwiseAndAcquire}
+         */
+        GET_AND_BITWISE_AND_ACQUIRE("getAndBitwiseAndAcquire", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseXor VarHandle.getAndBitwiseXor}
+         */
+        GET_AND_BITWISE_XOR("getAndBitwiseXor", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseXorRelease VarHandle.getAndBitwiseXorRelease}
+         */
+        GET_AND_BITWISE_XOR_RELEASE("getAndBitwiseXorRelease", AccessType.GET_AND_UPDATE_BITWISE),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#getAndBitwiseXorAcquire VarHandle.getAndBitwiseXorAcquire}
+         */
+        GET_AND_BITWISE_XOR_ACQUIRE("getAndBitwiseXorAcquire", AccessType.GET_AND_UPDATE_BITWISE),
+        ;
+
+        static final Map<String, AccessMode> methodNameToAccessMode;
+        static {
+            // Initial capacity of # values is sufficient to avoid resizes
+            // for the smallest table size (32)
+            methodNameToAccessMode = new HashMap<>(AccessMode.values().length);
+            for (AccessMode am : AccessMode.values()) {
+                methodNameToAccessMode.put(am.methodName, am);
+            }
+        }
+
+        final String methodName;
+        final AccessType at;
+
+        AccessMode(final String methodName, AccessType at) {
+            this.methodName = methodName;
+            this.at = at;
+        }
+
+        /**
+         * Returns the {@code VarHandle} signature-polymorphic method name
+         * associated with this {@code AccessMode} value.
+         *
+         * @return the signature-polymorphic method name
+         * @see #valueFromMethodName
+         */
+        public String methodName() {
+            return methodName;
+        }
+
+        /**
+         * Returns the {@code AccessMode} value associated with the specified
+         * {@code VarHandle} signature-polymorphic method name.
+         *
+         * @param methodName the signature-polymorphic method name
+         * @return the {@code AccessMode} value
+         * @throws IllegalArgumentException if there is no {@code AccessMode}
+         *         value associated with method name (indicating the method
+         *         name does not correspond to a {@code VarHandle}
+         *         signature-polymorphic method name).
+         * @see #methodName
+         */
+        public static AccessMode valueFromMethodName(String methodName) {
+            AccessMode am = methodNameToAccessMode.get(methodName);
+            if (am != null) return am;
+            throw new IllegalArgumentException("No AccessMode value for method name " + methodName);
+        }
+
+        // BEGIN Android-removed: MemberName and VarForm are not used in the Android implementation.
+        /*
+        @ForceInline
+        static MemberName getMemberName(int ordinal, VarForm vform) {
+            return vform.memberName_table[ordinal];
+        }
+        */
+        // END Android-removed: MemberName and VarForm are not used in the Android implementation.
+    }
+
+    // BEGIN Android-removed: AccessDescriptor not used in Android implementation.
+    /*
+    static final class AccessDescriptor {
+        final MethodType symbolicMethodTypeErased;
+        final MethodType symbolicMethodTypeInvoker;
+        final Class<?> returnType;
+        final int type;
+        final int mode;
+
+        public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) {
+            this.symbolicMethodTypeErased = symbolicMethodType.erase();
+            this.symbolicMethodTypeInvoker = symbolicMethodType.insertParameterTypes(0, VarHandle.class);
+            this.returnType = symbolicMethodType.returnType();
+            this.type = type;
+            this.mode = mode;
+        }
+    }
+    */
+    // END Android-removed: AccessDescriptor not used in Android implementation.
+
+    /**
+     * Returns the variable type of variables referenced by this VarHandle.
+     *
+     * @return the variable type of variables referenced by this VarHandle
+     */
+    public final Class<?> varType() {
+        // Android-removed: existing implementation.
+        // MethodType typeSet = accessModeType(AccessMode.SET);
+        // return typeSet.parameterType(typeSet.parameterCount() - 1)
+        // Android-added: return instance field.
+        return varType;
+    }
+
+    /**
+     * Returns the coordinate types for this VarHandle.
+     *
+     * @return the coordinate types for this VarHandle. The returned
+     * list is unmodifiable
+     */
+    public final List<Class<?>> coordinateTypes() {
+        // Android-removed: existing implementation.
+        // MethodType typeGet = accessModeType(AccessMode.GET);
+        // return typeGet.parameterList();
+        // Android-added: Android specific implementation.
+        if (coordinateType0 == null) {
+            return Collections.EMPTY_LIST;
+        } else if (coordinateType1 == null) {
+            return Collections.singletonList(coordinateType0);
+        } else {
+            return Collections.unmodifiableList(Arrays.asList(coordinateType0, coordinateType1));
+        }
+    }
+
+    /**
+     * Obtains the access mode type for this VarHandle and a given access mode.
+     *
+     * <p>The access mode type's parameter types will consist of a prefix that
+     * is the coordinate types of this VarHandle followed by further
+     * types as defined by the access mode method.
+     * The access mode type's return type is defined by the return type of the
+     * access mode method.
+     *
+     * @param accessMode the access mode, corresponding to the
+     * signature-polymorphic method of the same name
+     * @return the access mode type for the given access mode
+     */
+    public final MethodType accessModeType(AccessMode accessMode) {
+        // BEGIN Android-removed: Relies on internal class that is not part of the
+        // Android implementation.
+        /*
+        TypesAndInvokers tis = getTypesAndInvokers();
+        MethodType mt = tis.methodType_table[accessMode.at.ordinal()];
+        if (mt == null) {
+            mt = tis.methodType_table[accessMode.at.ordinal()] =
+                    accessModeTypeUncached(accessMode);
+        }
+        return mt;
+        */
+        // END Android-removed: Relies on internal class that is not part of the
+        // Android implementation.
+        // Android-added: alternative implementation.
+        if (coordinateType1 == null) {
+            // accessModeType() treats the first argument as the
+            // receiver and adapts accordingly if it is null.
+            return accessMode.at.accessModeType(coordinateType0, varType);
+        } else {
+            return accessMode.at.accessModeType(coordinateType0, varType, coordinateType1);
+        }
+    }
+
+    // Android-removed: Not part of the Android implementation.
+    // abstract MethodType accessModeTypeUncached(AccessMode accessMode);
+
+    /**
+     * Returns {@code true} if the given access mode is supported, otherwise
+     * {@code false}.
+     *
+     * <p>The return of a {@code false} value for a given access mode indicates
+     * that an {@code UnsupportedOperationException} is thrown on invocation
+     * of the corresponding access mode method.
+     *
+     * @param accessMode the access mode, corresponding to the
+     * signature-polymorphic method of the same name
+     * @return {@code true} if the given access mode is supported, otherwise
+     * {@code false}.
+     */
+    public final boolean isAccessModeSupported(AccessMode accessMode) {
+        // Android-removed: Refers to unused field vform.
+        // return AccessMode.getMemberName(accessMode.ordinal(), vform) != null;
+        // Android-added: use accessModesBitsMask field.
+        final int testBit = 1 << accessMode.ordinal();
+        return (accessModesBitMask & testBit) == testBit;
+    }
+
+    /**
+     * Obtains a method handle bound to this VarHandle and the given access
+     * mode.
+     *
+     * @apiNote This method, for a VarHandle {@code vh} and access mode
+     * {@code {access-mode}}, returns a method handle that is equivalent to
+     * method handle {@code bmh} in the following code (though it may be more
+     * efficient):
+     * <pre>{@code
+     * MethodHandle mh = MethodHandles.varHandleExactInvoker(
+     *                       vh.accessModeType(VarHandle.AccessMode.{access-mode}));
+     *
+     * MethodHandle bmh = mh.bindTo(vh);
+     * }</pre>
+     *
+     * @param accessMode the access mode, corresponding to the
+     * signature-polymorphic method of the same name
+     * @return a method handle bound to this VarHandle and the given access mode
+     */
+    public final MethodHandle toMethodHandle(AccessMode accessMode) {
+        // BEGIN Android-removed: no vform field in Android implementation.
+        /*
+        MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
+        if (mn != null) {
+            MethodHandle mh = getMethodHandle(accessMode.ordinal());
+            return mh.bindTo(this);
+        }
+        else {
+            // Ensure an UnsupportedOperationException is thrown
+            return MethodHandles.varHandleInvoker(accessMode, accessModeType(accessMode)).
+                    bindTo(this);
+        }
+        */
+        // END Android-removed: no vform field in Android implementation.
+
+        // Android-added: basic implementation following description in javadoc for this method.
+        MethodType type = accessModeType(accessMode);
+        return MethodHandles.varHandleExactInvoker(accessMode, type).bindTo(this);
+    }
+
+    // BEGIN Android-removed: Not used in Android implementation.
+    /*
+    @Stable
+    TypesAndInvokers typesAndInvokers;
+
+    static class TypesAndInvokers {
+        final @Stable
+        MethodType[] methodType_table =
+                new MethodType[VarHandle.AccessType.values().length];
+
+        final @Stable
+        MethodHandle[] methodHandle_table =
+                new MethodHandle[AccessMode.values().length];
+    }
+
+    @ForceInline
+    private final TypesAndInvokers getTypesAndInvokers() {
+        TypesAndInvokers tis = typesAndInvokers;
+        if (tis == null) {
+            tis = typesAndInvokers = new TypesAndInvokers();
+        }
+        return tis;
+    }
+
+    @ForceInline
+    final MethodHandle getMethodHandle(int mode) {
+        TypesAndInvokers tis = getTypesAndInvokers();
+        MethodHandle mh = tis.methodHandle_table[mode];
+        if (mh == null) {
+            mh = tis.methodHandle_table[mode] = getMethodHandleUncached(mode);
+        }
+        return mh;
+    }
+    private final MethodHandle getMethodHandleUncached(int mode) {
+        MethodType mt = accessModeType(AccessMode.values()[mode]).
+                insertParameterTypes(0, VarHandle.class);
+        MemberName mn = vform.getMemberName(mode);
+        DirectMethodHandle dmh = DirectMethodHandle.make(mn);
+        // Such a method handle must not be publically exposed directly
+        // otherwise it can be cracked, it must be transformed or rebound
+        // before exposure
+        MethodHandle mh = dmh.copyWith(mt, dmh.form);
+        assert mh.type().erase() == mn.getMethodType().erase();
+        return mh;
+    }
+    */
+    // END Android-removed: Not used in Android implementation.
+
+    // BEGIN Android-removed: No VarForm in Android implementation.
+    /*non-public*/
+    /*
+    final void updateVarForm(VarForm newVForm) {
+        if (vform == newVForm) return;
+        UNSAFE.putObject(this, VFORM_OFFSET, newVForm);
+        UNSAFE.fullFence();
+    }
+
+    static final BiFunction<String, List<Integer>, ArrayIndexOutOfBoundsException>
+            AIOOBE_SUPPLIER = Preconditions.outOfBoundsExceptionFormatter(
+            new Function<String, ArrayIndexOutOfBoundsException>() {
+                @Override
+                public ArrayIndexOutOfBoundsException apply(String s) {
+                    return new ArrayIndexOutOfBoundsException(s);
+                }
+            });
+
+    private static final long VFORM_OFFSET;
+
+    static {
+        try {
+            VFORM_OFFSET = UNSAFE.objectFieldOffset(VarHandle.class.getDeclaredField("vform"));
+        }
+        catch (ReflectiveOperationException e) {
+            throw newInternalError(e);
+        }
+
+        // The VarHandleGuards must be initialized to ensure correct
+        // compilation of the guard methods
+        UNSAFE.ensureClassInitialized(VarHandleGuards.class);
+    }
+    */
+    // END Android-removed: No VarForm in Android implementation.
+
+    // Fence methods
+
+    /**
+     * Ensures that loads and stores before the fence will not be reordered
+     * with
+     * loads and stores after the fence.
+     *
+     * @apiNote Ignoring the many semantic differences from C and C++, this
+     * method has memory ordering effects compatible with
+     * {@code atomic_thread_fence(memory_order_seq_cst)}
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    // @ForceInline
+    public static void fullFence() {
+        UNSAFE.fullFence();
+    }
+
+    /**
+     * Ensures that loads before the fence will not be reordered with loads and
+     * stores after the fence.
+     *
+     * @apiNote Ignoring the many semantic differences from C and C++, this
+     * method has memory ordering effects compatible with
+     * {@code atomic_thread_fence(memory_order_acquire)}
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    // @ForceInline
+    public static void acquireFence() {
+        UNSAFE.loadFence();
+    }
+
+    /**
+     * Ensures that loads and stores before the fence will not be
+     * reordered with stores after the fence.
+     *
+     * @apiNote Ignoring the many semantic differences from C and C++, this
+     * method has memory ordering effects compatible with
+     * {@code atomic_thread_fence(memory_order_release)}
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    // @ForceInline
+    public static void releaseFence() {
+        UNSAFE.storeFence();
+    }
+
+    /**
+     * Ensures that loads before the fence will not be reordered with
+     * loads after the fence.
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    // @ForceInline
+    public static void loadLoadFence() {
+        // Android-changed: Not using UNSAFE.loadLoadFence() as not present on Android.
+        // NB The compiler recognizes all the fences here as intrinsics.
+        UNSAFE.loadFence();
+    }
+
+    /**
+     * Ensures that stores before the fence will not be reordered with
+     * stores after the fence.
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    // @ForceInline
+    public static void storeStoreFence() {
+        // Android-changed: Not using UNSAFE.storeStoreFence() as not present on Android.
+        // NB The compiler recognizes all the fences here as intrinsics.
+        UNSAFE.storeFence();
+    }
+
+    // BEGIN Android-added: package private constructors.
+    /**
+     * Constructor for VarHandle with no coordinates.
+     *
+     * @param varType the variable type of variables to be referenced
+     * @param isFinal whether the target variables are final (non-modifiable)
+     * @hide
+     */
+    VarHandle(Class<?> varType, boolean isFinal) {
+        this.varType = Objects.requireNonNull(varType);
+        this.coordinateType0 = null;
+        this.coordinateType1 = null;
+        this.accessModesBitMask = alignedAccessModesBitMask(varType, isFinal);
+    }
+
+    /**
+     * Constructor for VarHandle with one coordinate.
+     *
+     * @param varType the variable type of variables to be referenced
+     * @param isFinal  whether the target variables are final (non-modifiable)
+     * @param coordinateType the coordinate
+     * @hide
+     */
+    VarHandle(Class<?> varType, boolean isFinal, Class<?> coordinateType) {
+        this.varType = Objects.requireNonNull(varType);
+        this.coordinateType0 = Objects.requireNonNull(coordinateType);
+        this.coordinateType1 = null;
+        this.accessModesBitMask = alignedAccessModesBitMask(varType, isFinal);
+    }
+
+    /**
+     * Constructor for VarHandle with two coordinates.
+     *
+     * @param varType the variable type of variables to be referenced
+     * @param backingArrayType the type of the array accesses will be performed on
+     * @param isFinal whether the target variables are final (non-modifiable)
+     * @param coordinateType0 the first coordinate
+     * @param coordinateType1 the second coordinate
+     * @hide
+     */
+    VarHandle(Class<?> varType, Class<?> backingArrayType,  boolean isFinal,
+              Class<?> coordinateType0, Class<?> coordinateType1) {
+        this.varType = Objects.requireNonNull(varType);
+        this.coordinateType0 = Objects.requireNonNull(coordinateType0);
+        this.coordinateType1 = Objects.requireNonNull(coordinateType1);
+        Objects.requireNonNull(backingArrayType);
+        Class<?> backingArrayComponentType = backingArrayType.getComponentType();
+        if (backingArrayComponentType != varType && backingArrayComponentType != byte.class) {
+            throw new InternalError("Unsupported backingArrayType: " + backingArrayType);
+        }
+
+        if (backingArrayType.getComponentType() == varType) {
+            this.accessModesBitMask = alignedAccessModesBitMask(varType, isFinal);
+        } else {
+            this.accessModesBitMask = unalignedAccessModesBitMask(varType);
+        }
+    }
+    // END Android-added: package private constructors.
+
+    // BEGIN Android-added: helper state for VarHandle properties.
+
+    /** BitMask of access modes that do not change the memory referenced by a VarHandle.
+     * An example being a read of a variable with volatile ordering effects. */
+    private final static int READ_ACCESS_MODES_BIT_MASK;
+
+    /** BitMask of access modes that write to the memory referenced by
+     * a VarHandle.  This does not include any compare and update
+     * access modes, nor any bitwise or numeric access modes. An
+     * example being a write to variable with release ordering
+     * effects.
+     */
+    private final static int WRITE_ACCESS_MODES_BIT_MASK;
+
+    /** BitMask of access modes that are applicable to types
+     * supporting for atomic updates.  This includes access modes that
+     * both read and write a variable such as compare-and-set.
+     */
+    private final static int ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+
+    /** BitMask of access modes that are applicable to types
+     * supporting numeric atomic update operations. */
+    private final static int NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+
+    /** BitMask of access modes that are applicable to types
+     * supporting bitwise atomic update operations. */
+    private final static int BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+
+    /** BitMask of all access modes. */
+    private final static int ALL_MODES_BIT_MASK;
+
+    static {
+        // Check we're not about to overflow the storage of the
+        // bitmasks here and in the accessModesBitMask field.
+        if (AccessMode.values().length > Integer.SIZE) {
+            throw new InternalError("accessModes overflow");
+        }
+
+        // Access modes bit mask declarations and initialization order
+        // follows the presentation order in JEP193.
+        READ_ACCESS_MODES_BIT_MASK = accessTypesToBitMask(EnumSet.of(AccessType.GET));
+
+        WRITE_ACCESS_MODES_BIT_MASK = accessTypesToBitMask(EnumSet.of(AccessType.SET));
+
+        ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK =
+                accessTypesToBitMask(EnumSet.of(AccessType.COMPARE_AND_EXCHANGE,
+                                                AccessType.COMPARE_AND_SWAP,
+                                                AccessType.GET_AND_UPDATE));
+
+        NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK =
+                accessTypesToBitMask(EnumSet.of(AccessType.GET_AND_UPDATE_NUMERIC));
+
+        BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK =
+                accessTypesToBitMask(EnumSet.of(AccessType.GET_AND_UPDATE_BITWISE));
+
+        ALL_MODES_BIT_MASK = (READ_ACCESS_MODES_BIT_MASK |
+                              WRITE_ACCESS_MODES_BIT_MASK |
+                              ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK |
+                              NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK |
+                              BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK);
+    }
+
+    static int accessTypesToBitMask(final EnumSet<AccessType> accessTypes) {
+        int m = 0;
+        for (AccessMode accessMode : AccessMode.values()) {
+            if (accessTypes.contains(accessMode.at)) {
+                m |= 1 << accessMode.ordinal();
+            }
+        }
+        return m;
+    }
+
+    static int alignedAccessModesBitMask(Class<?> varType, boolean isFinal) {
+        // For aligned accesses, the supported access modes are described in:
+        // @see java.lang.invoke.MethodHandles.Lookup#findVarHandle
+        int bitMask = ALL_MODES_BIT_MASK;
+
+        // If the field is declared final, keep only the read access modes.
+        if (isFinal) {
+            bitMask &= READ_ACCESS_MODES_BIT_MASK;
+        }
+
+        // If the field is anything other than byte, short, char, int,
+        // long, float, double then remove the numeric atomic update
+        // access modes.
+        if (varType != byte.class && varType != short.class && varType != char.class &&
+            varType != int.class && varType != long.class
+            && varType != float.class && varType != double.class) {
+            bitMask &= ~NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+        }
+
+        // If the field is not integral, remove the bitwise atomic update access modes.
+        if (varType != boolean.class && varType != byte.class && varType != short.class &&
+            varType != char.class && varType != int.class && varType != long.class) {
+            bitMask &= ~BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+        }
+        return bitMask;
+    }
+
+    static int unalignedAccessModesBitMask(Class<?> varType) {
+        // The VarHandle refers to a view of byte array or a
+        // view of a byte buffer.  The corresponding accesses
+        // maybe unaligned so the access modes are more
+        // restrictive than field or array element accesses.
+        //
+        // The supported access modes are described in:
+        // @see java.lang.invoke.MethodHandles#byteArrayViewVarHandle
+
+        // Read/write access modes supported for all types including
+        // long and double on 32-bit platforms (though these accesses
+        // may not be atomic).
+        int bitMask = READ_ACCESS_MODES_BIT_MASK | WRITE_ACCESS_MODES_BIT_MASK;
+
+        // int, long, float, double support atomic update modes per documentation.
+        if (varType == int.class || varType == long.class ||
+            varType == float.class || varType == double.class) {
+            bitMask |= ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+        }
+
+        // int and long support numeric updates per documentation.
+        if (varType == int.class || varType == long.class) {
+            bitMask |= NUMERIC_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+        }
+
+        // int and long support bitwise updates per documentation.
+        if (varType == int.class || varType == long.class) {
+            bitMask |= BITWISE_ATOMIC_UPDATE_ACCESS_MODES_BIT_MASK;
+        }
+        return bitMask;
+    }
+    // END Android-added: helper state for VarHandle properties.
+}
diff --git a/java/lang/invoke/VolatileCallSite.java b/java/lang/invoke/VolatileCallSite.java
new file mode 100644
index 0000000..47d2689
--- /dev/null
+++ b/java/lang/invoke/VolatileCallSite.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: Removed references to MutableCallSite.syncAll().
+/**
+ * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
+ * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
+ * to its call site target immediately, even if the update occurs in another thread.
+ * There may be a performance penalty for such tight coupling between threads.
+ * <p>
+ * In other respects, a {@code VolatileCallSite} is interchangeable
+ * with {@code MutableCallSite}.
+ * @see MutableCallSite
+ * @author John Rose, JSR 292 EG
+ */
+public class VolatileCallSite extends CallSite {
+    /**
+     * Creates a call site with a volatile binding to its target.
+     * The initial target is set to a method handle
+     * of the given type which will throw an {@code IllegalStateException} if called.
+     * @param type the method type that this call site will have
+     * @throws NullPointerException if the proposed type is null
+     */
+    public VolatileCallSite(MethodType type) {
+        super(type);
+    }
+
+    /**
+     * Creates a call site with a volatile binding to its target.
+     * The target is set to the given value.
+     * @param target the method handle that will be the initial target of the call site
+     * @throws NullPointerException if the proposed target is null
+     */
+    public VolatileCallSite(MethodHandle target) {
+        super(target);
+    }
+
+    /**
+     * Returns the target method of the call site, which behaves
+     * like a {@code volatile} field of the {@code VolatileCallSite}.
+     * <p>
+     * The interactions of {@code getTarget} with memory are the same
+     * as of a read from a {@code volatile} field.
+     * <p>
+     * In particular, the current thread is required to issue a fresh
+     * read of the target from memory, and must not fail to see
+     * a recent update to the target by another thread.
+     *
+     * @return the linkage state of this call site, a method handle which can change over time
+     * @see #setTarget
+     */
+    @Override public final MethodHandle getTarget() {
+        return getTargetVolatile();
+    }
+
+    /**
+     * Updates the target method of this call site, as a volatile variable.
+     * The type of the new target must agree with the type of the old target.
+     * <p>
+     * The interactions with memory are the same as of a write to a volatile field.
+     * In particular, any threads is guaranteed to see the updated target
+     * the next time it calls {@code getTarget}.
+     * @param newTarget the new target
+     * @throws NullPointerException if the proposed new target is null
+     * @throws WrongMethodTypeException if the proposed new target
+     *         has a method type that differs from the previous target
+     * @see #getTarget
+     */
+    @Override public void setTarget(MethodHandle newTarget) {
+        checkTargetChange(getTargetVolatile(), newTarget);
+        setTargetVolatile(newTarget);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final MethodHandle dynamicInvoker() {
+        return makeDynamicInvoker();
+    }
+}
diff --git a/java/lang/invoke/WrongMethodTypeException.java b/java/lang/invoke/WrongMethodTypeException.java
new file mode 100644
index 0000000..d55e3cd
--- /dev/null
+++ b/java/lang/invoke/WrongMethodTypeException.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * Thrown to indicate that code has attempted to call a method handle
+ * via the wrong method type.  As with the bytecode representation of
+ * normal Java method calls, method handle calls are strongly typed
+ * to a specific type descriptor associated with a call site.
+ * <p>
+ * This exception may also be thrown when two method handles are
+ * composed, and the system detects that their types cannot be
+ * matched up correctly.  This amounts to an early evaluation
+ * of the type mismatch, at method handle construction time,
+ * instead of when the mismatched method handle is called.
+ *
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class WrongMethodTypeException extends RuntimeException {
+    private static final long serialVersionUID = 292L;
+
+    /**
+     * Constructs a {@code WrongMethodTypeException} with no detail message.
+     */
+    public WrongMethodTypeException() {
+        super();
+    }
+
+    /**
+     * Constructs a {@code WrongMethodTypeException} with the specified
+     * detail message.
+     *
+     * @param s the detail message.
+     */
+    public WrongMethodTypeException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a {@code WrongMethodTypeException} with the specified
+     * detail message and cause.
+     *
+     * @param s the detail message.
+     * @param cause the cause of the exception, or null.
+     */
+    //FIXME: make this public in MR1
+    /*non-public*/ WrongMethodTypeException(String s, Throwable cause) {
+        super(s, cause);
+    }
+
+    /**
+     * Constructs a {@code WrongMethodTypeException} with the specified
+     * cause.
+     *
+     * @param cause the cause of the exception, or null.
+     */
+    //FIXME: make this public in MR1
+    /*non-public*/ WrongMethodTypeException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/lang/package-info.java b/java/lang/package-info.java
new file mode 100644
index 0000000..aa7a79d
--- /dev/null
+++ b/java/lang/package-info.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides classes that are fundamental to the design of the Java
+ * programming language. The most important classes are {@code
+ * Object}, which is the root of the class hierarchy, and {@code
+ * Class}, instances of which represent classes at run time.
+ *
+ * <p>Frequently it is necessary to represent a value of primitive
+ * type as if it were an object. The wrapper classes {@code Boolean},
+ * {@code Character}, {@code Integer}, {@code Long}, {@code Float},
+ * and {@code Double} serve this purpose.  An object of type {@code
+ * Double}, for example, contains a field whose type is double,
+ * representing that value in such a way that a reference to it can be
+ * stored in a variable of reference type.  These classes also provide
+ * a number of methods for converting among primitive values, as well
+ * as supporting such standard methods as equals and hashCode.  The
+ * {@code Void} class is a non-instantiable class that holds a
+ * reference to a {@code Class} object representing the type void.
+ *
+ * <p>The class {@code Math} provides commonly used mathematical
+ * functions such as sine, cosine, and square root. The classes {@code
+ * String}, {@code StringBuffer}, and {@code StringBuilder} similarly
+ * provide commonly used operations on character strings.
+ *
+ * <p>Classes {@code ClassLoader}, {@code Process}, {@code
+ * ProcessBuilder}, {@code Runtime}, {@code SecurityManager}, and
+ * {@code System} provide "system operations" that manage the dynamic
+ * loading of classes, creation of external processes, host
+ * environment inquiries such as the time of day, and enforcement of
+ * security policies.
+ *
+ * <p>Class {@code Throwable} encompasses objects that may be thrown
+ * by the {@code throw} statement. Subclasses of {@code Throwable}
+ * represent errors and exceptions.
+ *
+ * <a name="charenc"></a>
+ * <h3>Character Encodings</h3>
+ *
+ * The specification of the {@link java.nio.charset.Charset
+ * java.nio.charset.Charset} class describes the naming conventions
+ * for character encodings as well as the set of standard encodings
+ * that must be supported by every implementation of the Java
+ * platform.
+ *
+ * @since JDK1.0
+ */
+package java.lang;
diff --git a/java/lang/ref/FinalizerReference.java b/java/lang/ref/FinalizerReference.java
new file mode 100644
index 0000000..037af4a
--- /dev/null
+++ b/java/lang/ref/FinalizerReference.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * @hide
+ */
+public final class FinalizerReference<T> extends Reference<T> {
+    // This queue contains those objects eligible for finalization.
+    @UnsupportedAppUsage
+    public static final ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
+
+    // Guards the list (not the queue).
+    private static final Object LIST_LOCK = new Object();
+
+    // This list contains a FinalizerReference for every finalizable object in the heap.
+    // Objects in this list may or may not be eligible for finalization yet.
+    @UnsupportedAppUsage
+    private static FinalizerReference<?> head = null;
+
+    // The links used to construct the list.
+    private FinalizerReference<?> prev;
+    @UnsupportedAppUsage
+    private FinalizerReference<?> next;
+
+    // When the GC wants something finalized, it moves it from the 'referent' field to
+    // the 'zombie' field instead.
+    private T zombie;
+
+    public FinalizerReference(T r, ReferenceQueue<? super T> q) {
+        super(r, q);
+    }
+
+    @Override public T get() {
+        return zombie;
+    }
+
+    @Override public void clear() {
+        zombie = null;
+    }
+
+    @UnsupportedAppUsage
+    public static void add(Object referent) {
+        FinalizerReference<?> reference = new FinalizerReference<Object>(referent, queue);
+        synchronized (LIST_LOCK) {
+            reference.prev = null;
+            reference.next = head;
+            if (head != null) {
+                head.prev = reference;
+            }
+            head = reference;
+        }
+    }
+
+    @UnsupportedAppUsage
+    public static void remove(FinalizerReference<?> reference) {
+        synchronized (LIST_LOCK) {
+            FinalizerReference<?> next = reference.next;
+            FinalizerReference<?> prev = reference.prev;
+            reference.next = null;
+            reference.prev = null;
+            if (prev != null) {
+                prev.next = next;
+            } else {
+                head = next;
+            }
+            if (next != null) {
+                next.prev = prev;
+            }
+        }
+    }
+
+    /**
+     * Waits for all currently-enqueued references to be finalized.
+     */
+    public static void finalizeAllEnqueued(long timeout) throws InterruptedException {
+        // Alloate a new sentinel, this creates a FinalizerReference.
+        Sentinel sentinel;
+        // Keep looping until we safely enqueue our sentinel FinalizerReference.
+        // This is done to prevent races where the GC updates the pendingNext
+        // before we get the chance.
+        do {
+            sentinel = new Sentinel();
+        } while (!enqueueSentinelReference(sentinel));
+        sentinel.awaitFinalization(timeout);
+    }
+
+    private static boolean enqueueSentinelReference(Sentinel sentinel) {
+        synchronized (LIST_LOCK) {
+            // When a finalizable object is allocated, a FinalizerReference is added to the list.
+            // We search the list for that FinalizerReference (it should be at or near the head),
+            // and then put it on the queue so that it can be finalized.
+            for (FinalizerReference<?> r = head; r != null; r = r.next) {
+                // Use getReferent() instead of directly accessing the referent field not to race
+                // with GC reference processing. Can't use get() either because it's overridden to
+                // return the zombie.
+                if (r.getReferent() == sentinel) {
+                    FinalizerReference<Sentinel> sentinelReference = (FinalizerReference<Sentinel>) r;
+                    sentinelReference.clearReferent();
+                    sentinelReference.zombie = sentinel;
+                    // Make a single element list, then enqueue the reference on the daemon unenqueued
+                    // list. This is required instead of enqueuing directly on the finalizer queue
+                    // since there could be recently freed objects in the unqueued list which are not
+                    // yet on the finalizer queue. This could cause the sentinel to run before the
+                    // objects are finalized. b/17381967
+                    // Make circular list if unenqueued goes through native so that we can prevent
+                    // races where the GC updates the pendingNext before we do. If it is non null, then
+                    // we update the pending next to make a circular list while holding a lock.
+                    // b/17462553
+                    if (!sentinelReference.makeCircularListIfUnenqueued()) {
+                        return false;
+                    }
+                    ReferenceQueue.add(sentinelReference);
+                    return true;
+                }
+            }
+        }
+        // We just created a finalizable object and still hold a reference to it.
+        // It must be on the list.
+        throw new AssertionError("newly-created live Sentinel not on list!");
+    }
+
+    @FastNative
+    private final native T getReferent();
+    @FastNative
+    private native boolean makeCircularListIfUnenqueued();
+
+    /**
+     * A marker object that we can immediately enqueue. When this object's
+     * finalize() method is called, we know all previously-enqueued finalizable
+     * references have been finalized.
+     */
+    private static class Sentinel {
+        boolean finalized = false;
+
+        @Override protected synchronized void finalize() throws Throwable {
+            if (finalized) {
+                throw new AssertionError();
+            }
+            finalized = true;
+            notifyAll();
+        }
+
+        synchronized void awaitFinalization(long timeout) throws InterruptedException {
+            final long startTime = System.nanoTime();
+            final long endTime = startTime + timeout;
+            while (!finalized) {
+                // 0 signifies no timeout.
+                if (timeout != 0) {
+                    final long currentTime = System.nanoTime();
+                    if (currentTime >= endTime) {
+                        break;
+                    } else {
+                        final long deltaTime = endTime - currentTime;
+                        wait(deltaTime / 1000000, (int)(deltaTime % 1000000));
+                    }
+                } else {
+                    wait();
+                }
+            }
+        }
+    }
+}
diff --git a/java/lang/ref/PhantomReference.java b/java/lang/ref/PhantomReference.java
new file mode 100644
index 0000000..1c1364a
--- /dev/null
+++ b/java/lang/ref/PhantomReference.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.ref;
+
+
+/**
+ * Phantom reference objects, which are enqueued after the collector
+ * determines that their referents may otherwise be reclaimed.  Phantom
+ * references are most often used for scheduling pre-mortem cleanup actions in
+ * a more flexible way than is possible with the Java finalization mechanism.
+ *
+ * <p> If the garbage collector determines at a certain point in time that the
+ * referent of a phantom reference is <a
+ * href="package-summary.html#reachability">phantom reachable</a>, then at that
+ * time or at some later time it will enqueue the reference.
+ *
+ * <p> In order to ensure that a reclaimable object remains so, the referent of
+ * a phantom reference may not be retrieved: The <code>get</code> method of a
+ * phantom reference always returns <code>null</code>.
+ *
+ * <p> Unlike soft and weak references, phantom references are not
+ * automatically cleared by the garbage collector as they are enqueued.  An
+ * object that is reachable via phantom references will remain so until all
+ * such references are cleared or themselves become unreachable.
+ *
+ * @author   Mark Reinhold
+ * @since    1.2
+ */
+
+public class PhantomReference<T> extends Reference<T> {
+
+    /**
+     * Returns this reference object's referent.  Because the referent of a
+     * phantom reference is always inaccessible, this method always returns
+     * <code>null</code>.
+     *
+     * @return  <code>null</code>
+     */
+    public T get() {
+        return null;
+    }
+
+    /**
+     * Creates a new phantom reference that refers to the given object and
+     * is registered with the given queue.
+     *
+     * <p> It is possible to create a phantom reference with a <tt>null</tt>
+     * queue, but such a reference is completely useless: Its <tt>get</tt>
+     * method will always return null and, since it does not have a queue, it
+     * will never be enqueued.
+     *
+     * @param referent the object the new phantom reference will refer to
+     * @param q the queue with which the reference is to be registered,
+     *          or <tt>null</tt> if registration is not required
+     */
+    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
+        super(referent, q);
+    }
+
+}
diff --git a/java/lang/ref/Reference.java b/java/lang/ref/Reference.java
new file mode 100644
index 0000000..e5126b5
--- /dev/null
+++ b/java/lang/ref/Reference.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.ref;
+
+import dalvik.annotation.optimization.FastNative;
+
+
+/**
+ * Abstract base class for reference objects.  This class defines the
+ * operations common to all reference objects.  Because reference objects are
+ * implemented in close cooperation with the garbage collector, this class may
+ * not be subclassed directly.
+ *
+ * @author   Mark Reinhold
+ * @since    1.2
+ */
+
+public abstract class Reference<T> {
+    // BEGIN Android-changed: Reimplemented to accommodate a different GC and compiler.
+    // ClassLinker knows about the fields of this class.
+
+    /**
+     * Forces JNI path.
+     * If GC is not in progress (ie: not going through slow path), the referent
+     * can be quickly returned through intrinsic without passing through JNI.
+     * This flag forces the JNI path so that it can be tested and benchmarked.
+     */
+    private static boolean disableIntrinsic = false;
+
+    /**
+     * Slow path flag for the reference processor.
+     * Used by the reference processor to determine whether or not the referent
+     * can be immediately returned. Because the referent might get swept during
+     * GC, the slow path, which passes through JNI, must be taken.
+     */
+    private static boolean slowPathEnabled = false;
+
+    // Treated specially by GC. ART's ClassLinker::LinkFields() knows this is the
+    // alphabetically last non-static field.
+    volatile T referent;
+
+    final ReferenceQueue<? super T> queue;
+
+    /*
+     * This field forms a singly-linked list of reference objects that have
+     * been enqueued. The queueNext field is non-null if and only if this
+     * reference has been enqueued. After this reference has been enqueued and
+     * before it has been removed from its queue, the queueNext field points
+     * to the next reference on the queue. The last reference on a queue
+     * points to itself. Once this reference has been removed from the
+     * reference queue, the queueNext field points to the
+     * ReferenceQueue.sQueueNextUnenqueued sentinel reference object for the
+     * rest of this reference's lifetime.
+     * <p>
+     * Access to the queueNext field is guarded by synchronization on a lock
+     * internal to 'queue'.
+     */
+    Reference queueNext;
+
+    /**
+     * The pendingNext field is initially set by the GC. After the GC forms a
+     * complete circularly linked list, the list is handed off to the
+     * ReferenceQueueDaemon using the ReferenceQueue.class lock. The
+     * ReferenceQueueDaemon can then read the pendingNext fields without
+     * additional synchronization.
+     */
+    Reference<?> pendingNext;
+
+    /* -- Referent accessor and setters -- */
+
+    /**
+     * Returns this reference object's referent.  If this reference object has
+     * been cleared, either by the program or by the garbage collector, then
+     * this method returns <code>null</code>.
+     *
+     * @return   The object to which this reference refers, or
+     *           <code>null</code> if this reference object has been cleared
+     */
+    public T get() {
+        return getReferent();
+    }
+
+    @FastNative
+    private final native T getReferent();
+
+    /**
+     * Clears this reference object.  Invoking this method will not cause this
+     * object to be enqueued.
+     *
+     * <p> This method is invoked only by Java code; when the garbage collector
+     * clears references it does so directly, without invoking this method.
+     */
+    public void clear() {
+        clearReferent();
+    }
+
+    // Direct access to the referent is prohibited, clearReferent blocks and set
+    // the referent to null when it is safe to do so.
+    @FastNative
+    native void clearReferent();
+
+    /* -- Queue operations -- */
+
+    /**
+     * Tells whether or not this reference object has been enqueued, either by
+     * the program or by the garbage collector.  If this reference object was
+     * not registered with a queue when it was created, then this method will
+     * always return <code>false</code>.
+     *
+     * @return   <code>true</code> if and only if this reference object has
+     *           been enqueued
+     */
+    public boolean isEnqueued() {
+        // Contrary to what the documentation says, this method returns false
+        // after this reference object has been removed from its queue
+        // (b/26647823). ReferenceQueue.isEnqueued preserves this historically
+        // incorrect behavior.
+        return queue != null && queue.isEnqueued(this);
+    }
+
+    /**
+     * Adds this reference object to the queue with which it is registered,
+     * if any.
+     *
+     * <p> This method is invoked only by Java code; when the garbage collector
+     * enqueues references it does so directly, without invoking this method.
+     *
+     * @return   <code>true</code> if this reference object was successfully
+     *           enqueued; <code>false</code> if it was already enqueued or if
+     *           it was not registered with a queue when it was created
+     */
+    public boolean enqueue() {
+       return queue != null && queue.enqueue(this);
+    }
+
+    /* -- Constructors -- */
+
+    Reference(T referent) {
+        this(referent, null);
+    }
+
+    Reference(T referent, ReferenceQueue<? super T> queue) {
+        this.referent = referent;
+        this.queue = queue;
+    }
+    // END Android-changed: Reimplemented to accommodate a different GC and compiler.
+
+    // BEGIN Android-added: reachabilityFence() from upstream OpenJDK9+181.
+    // The actual implementation differs from OpenJDK9.
+    /**
+     * Ensures that the object referenced by the given reference remains
+     * <a href="package-summary.html#reachability"><em>strongly reachable</em></a>,
+     * regardless of any prior actions of the program that might otherwise cause
+     * the object to become unreachable; thus, the referenced object is not
+     * reclaimable by garbage collection at least until after the invocation of
+     * this method.  Invocation of this method does not itself initiate garbage
+     * collection or finalization.
+     *
+     * <p> This method establishes an ordering for
+     * <a href="package-summary.html#reachability"><em>strong reachability</em></a>
+     * with respect to garbage collection.  It controls relations that are
+     * otherwise only implicit in a program -- the reachability conditions
+     * triggering garbage collection.  This method is designed for use in
+     * uncommon situations of premature finalization where using
+     * {@code synchronized} blocks or methods, or using other synchronization
+     * facilities are not possible or do not provide the desired control.  This
+     * method is applicable only when reclamation may have visible effects,
+     * which is possible for objects with finalizers (See
+     * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.6">
+     * Section 12.6 17 of <cite>The Java&trade; Language Specification</cite></a>)
+     * that are implemented in ways that rely on ordering control for correctness.
+     *
+     * @apiNote
+     * Finalization may occur whenever the virtual machine detects that no
+     * reference to an object will ever be stored in the heap: The garbage
+     * collector may reclaim an object even if the fields of that object are
+     * still in use, so long as the object has otherwise become unreachable.
+     * This may have surprising and undesirable effects in cases such as the
+     * following example in which the bookkeeping associated with a class is
+     * managed through array indices.  Here, method {@code action} uses a
+     * {@code reachabilityFence} to ensure that the {@code Resource} object is
+     * not reclaimed before bookkeeping on an associated
+     * {@code ExternalResource} has been performed; in particular here, to
+     * ensure that the array slot holding the {@code ExternalResource} is not
+     * nulled out in method {@link Object#finalize}, which may otherwise run
+     * concurrently.
+     *
+     * <pre> {@code
+     * class Resource {
+     *   private static ExternalResource[] externalResourceArray = ...
+     *
+     *   int myIndex;
+     *   Resource(...) {
+     *     myIndex = ...
+     *     externalResourceArray[myIndex] = ...;
+     *     ...
+     *   }
+     *   protected void finalize() {
+     *     externalResourceArray[myIndex] = null;
+     *     ...
+     *   }
+     *   public void action() {
+     *     try {
+     *       // ...
+     *       int i = myIndex;
+     *       Resource.update(externalResourceArray[i]);
+     *     } finally {
+     *       Reference.reachabilityFence(this);
+     *     }
+     *   }
+     *   private static void update(ExternalResource ext) {
+     *     ext.status = ...;
+     *   }
+     * }}</pre>
+     *
+     * Here, the invocation of {@code reachabilityFence} is nonintuitively
+     * placed <em>after</em> the call to {@code update}, to ensure that the
+     * array slot is not nulled out by {@link Object#finalize} before the
+     * update, even if the call to {@code action} was the last use of this
+     * object.  This might be the case if, for example a usage in a user program
+     * had the form {@code new Resource().action();} which retains no other
+     * reference to this {@code Resource}.  While probably overkill here,
+     * {@code reachabilityFence} is placed in a {@code finally} block to ensure
+     * that it is invoked across all paths in the method.  In a method with more
+     * complex control paths, you might need further precautions to ensure that
+     * {@code reachabilityFence} is encountered along all of them.
+     *
+     * <p> It is sometimes possible to better encapsulate use of
+     * {@code reachabilityFence}.  Continuing the above example, if it were
+     * acceptable for the call to method {@code update} to proceed even if the
+     * finalizer had already executed (nulling out slot), then you could
+     * localize use of {@code reachabilityFence}:
+     *
+     * <pre> {@code
+     * public void action2() {
+     *   // ...
+     *   Resource.update(getExternalResource());
+     * }
+     * private ExternalResource getExternalResource() {
+     *   ExternalResource ext = externalResourceArray[myIndex];
+     *   Reference.reachabilityFence(this);
+     *   return ext;
+     * }}</pre>
+     *
+     * <p> Method {@code reachabilityFence} is not required in constructions
+     * that themselves ensure reachability.  For example, because objects that
+     * are locked cannot, in general, be reclaimed, it would suffice if all
+     * accesses of the object, in all methods of class {@code Resource}
+     * (including {@code finalize}) were enclosed in {@code synchronized (this)}
+     * blocks.  (Further, such blocks must not include infinite loops, or
+     * themselves be unreachable, which fall into the corner case exceptions to
+     * the "in general" disclaimer.)  However, method {@code reachabilityFence}
+     * remains a better option in cases where this approach is not as efficient,
+     * desirable, or possible; for example because it would encounter deadlock.
+     *
+     * @param ref the reference. If {@code null}, this method has no effect.
+     * @since 9
+     */
+    // @DontInline
+    public static void reachabilityFence(Object ref) {
+        // This code is usually replaced by much faster intrinsic implementations.
+        // It will be executed for tests run with the access checks interpreter in
+        // ART, e.g. with --verify-soft-fail.  Since this is a volatile store, it
+        // cannot easily be moved up past prior accesses, even if this method is
+        // inlined.
+        SinkHolder.sink = ref;
+        // Leaving SinkHolder set to ref is unpleasant, since it keeps ref live
+        // until the next reachabilityFence call. This causes e.g. 036-finalizer
+        // to fail. Clear it again in a way that's unlikely to be optimizable.
+        // The fact that finalize_count is volatile makes it hard to move the test up.
+        if (SinkHolder.finalize_count == 0) {
+            SinkHolder.sink = null;
+        }
+    }
+
+    private static class SinkHolder {
+        static volatile Object sink;
+
+        // Ensure that sink looks live to even a reasonably clever compiler.
+        private static volatile int finalize_count = 0;
+
+        private static Object sinkUser = new Object() {
+            protected void finalize() {
+                if (sink == null && finalize_count > 0) {
+                    throw new AssertionError("Can't get here");
+                }
+                finalize_count++;
+            }
+        };
+    }
+    // END Android-added: reachabilityFence() from upstream OpenJDK9+181.
+}
diff --git a/java/lang/ref/ReferenceQueue.java b/java/lang/ref/ReferenceQueue.java
new file mode 100644
index 0000000..72e55c1
--- /dev/null
+++ b/java/lang/ref/ReferenceQueue.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.ref;
+
+import sun.misc.Cleaner;
+
+/**
+ * Reference queues, to which registered reference objects are appended by the
+ * garbage collector after the appropriate reachability changes are detected.
+ *
+ * @author   Mark Reinhold
+ * @since    1.2
+ */
+// BEGIN Android-changed: Reimplemented to accomodate a different GC and compiler.
+
+public class ReferenceQueue<T> {
+
+    // Reference.queueNext will be set to sQueueNextUnenqueued to indicate
+    // when a reference has been enqueued and removed from its queue.
+    private static final Reference sQueueNextUnenqueued = new PhantomReference(null, null);
+
+    // NOTE: This implementation of ReferenceQueue is FIFO (queue-like) whereas
+    // the OpenJdk implementation is LIFO (stack-like).
+    private Reference<? extends T> head = null;
+    private Reference<? extends T> tail = null;
+
+    private final Object lock = new Object();
+
+    /**
+     * Constructs a new reference-object queue.
+     */
+    public ReferenceQueue() { }
+
+    /**
+     * Enqueue the given reference onto this queue.
+     * The caller is responsible for ensuring the lock is held on this queue,
+     * and for calling notifyAll on this queue after the reference has been
+     * enqueued. Returns true if the reference was enqueued successfully,
+     * false if the reference had already been enqueued.
+     * @GuardedBy("lock")
+     */
+    private boolean enqueueLocked(Reference<? extends T> r) {
+        // Verify the reference has not already been enqueued.
+        if (r.queueNext != null) {
+            return false;
+        }
+
+        if (r instanceof Cleaner) {
+            // If this reference is a Cleaner, then simply invoke the clean method instead
+            // of enqueueing it in the queue. Cleaners are associated with dummy queues that
+            // are never polled and objects are never enqueued on them.
+            Cleaner cl = (sun.misc.Cleaner) r;
+            cl.clean();
+
+            // Update queueNext to indicate that the reference has been
+            // enqueued, but is now removed from the queue.
+            r.queueNext = sQueueNextUnenqueued;
+            return true;
+        }
+
+        if (tail == null) {
+            head = r;
+        } else {
+            tail.queueNext = r;
+        }
+        tail = r;
+        tail.queueNext = r;
+        return true;
+    }
+
+    /**
+     * Test if the given reference object has been enqueued but not yet
+     * removed from the queue, assuming this is the reference object's queue.
+     */
+    boolean isEnqueued(Reference<? extends T> reference) {
+        synchronized (lock) {
+            return reference.queueNext != null && reference.queueNext != sQueueNextUnenqueued;
+        }
+    }
+
+    /**
+     * Enqueue the reference object on the receiver.
+     *
+     * @param reference
+     *            reference object to be enqueued.
+     * @return true if the reference was enqueued.
+     */
+    boolean enqueue(Reference<? extends T> reference) {
+        synchronized (lock) {
+            if (enqueueLocked(reference)) {
+                lock.notifyAll();
+                return true;
+            }
+            return false;
+        }
+    }
+
+    // @GuardedBy("lock")
+    private Reference<? extends T> reallyPollLocked() {
+        if (head != null) {
+            Reference<? extends T> r = head;
+            if (head == tail) {
+                tail = null;
+                head = null;
+            } else {
+                head = head.queueNext;
+            }
+
+            // Update queueNext to indicate that the reference has been
+            // enqueued, but is now removed from the queue.
+            r.queueNext = sQueueNextUnenqueued;
+            return r;
+        }
+
+        return null;
+    }
+
+    /**
+     * Polls this queue to see if a reference object is available.  If one is
+     * available without further delay then it is removed from the queue and
+     * returned.  Otherwise this method immediately returns <tt>null</tt>.
+     *
+     * @return  A reference object, if one was immediately available,
+     *          otherwise <code>null</code>
+     */
+    public Reference<? extends T> poll() {
+        synchronized (lock) {
+            if (head == null)
+                return null;
+
+            return reallyPollLocked();
+        }
+    }
+
+    /**
+     * Removes the next reference object in this queue, blocking until either
+     * one becomes available or the given timeout period expires.
+     *
+     * <p> This method does not offer real-time guarantees: It schedules the
+     * timeout as if by invoking the {@link Object#wait(long)} method.
+     *
+     * @param  timeout  If positive, block for up to <code>timeout</code>
+     *                  milliseconds while waiting for a reference to be
+     *                  added to this queue.  If zero, block indefinitely.
+     *
+     * @return  A reference object, if one was available within the specified
+     *          timeout period, otherwise <code>null</code>
+     *
+     * @throws  IllegalArgumentException
+     *          If the value of the timeout argument is negative
+     *
+     * @throws  InterruptedException
+     *          If the timeout wait is interrupted
+     */
+    public Reference<? extends T> remove(long timeout)
+        throws IllegalArgumentException, InterruptedException
+    {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("Negative timeout value");
+        }
+        synchronized (lock) {
+            Reference<? extends T> r = reallyPollLocked();
+            if (r != null) return r;
+            long start = (timeout == 0) ? 0 : System.nanoTime();
+            for (;;) {
+                lock.wait(timeout);
+                r = reallyPollLocked();
+                if (r != null) return r;
+                if (timeout != 0) {
+                    long end = System.nanoTime();
+                    timeout -= (end - start) / 1000_000;
+                    if (timeout <= 0) return null;
+                    start = end;
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes the next reference object in this queue, blocking until one
+     * becomes available.
+     *
+     * @return A reference object, blocking until one becomes available
+     * @throws  InterruptedException  If the wait is interrupted
+     */
+    public Reference<? extends T> remove() throws InterruptedException {
+        return remove(0);
+    }
+
+    /**
+     * Enqueue the given list of currently pending (unenqueued) references.
+     *
+     * @hide
+     */
+    public static void enqueuePending(Reference<?> list) {
+        Reference<?> start = list;
+        do {
+            ReferenceQueue queue = list.queue;
+            if (queue == null) {
+                Reference<?> next = list.pendingNext;
+
+                // Make pendingNext a self-loop to preserve the invariant that
+                // once enqueued, pendingNext is non-null -- without leaking
+                // the object pendingNext was previously pointing to.
+                list.pendingNext = list;
+                list = next;
+            } else {
+                // To improve performance, we try to avoid repeated
+                // synchronization on the same queue by batching enqueue of
+                // consecutive references in the list that have the same
+                // queue.
+                synchronized (queue.lock) {
+                    do {
+                        Reference<?> next = list.pendingNext;
+
+                        // Make pendingNext a self-loop to preserve the
+                        // invariant that once enqueued, pendingNext is
+                        // non-null -- without leaking the object pendingNext
+                        // was previously pointing to.
+                        list.pendingNext = list;
+                        queue.enqueueLocked(list);
+                        list = next;
+                    } while (list != start && list.queue == queue);
+                    queue.lock.notifyAll();
+                }
+            }
+        } while (list != start);
+    }
+
+    /**
+     * List of references that the GC says need to be enqueued.
+     * Protected by ReferenceQueue.class lock.
+     * @hide
+     */
+    public static Reference<?> unenqueued = null;
+
+    static void add(Reference<?> list) {
+        synchronized (ReferenceQueue.class) {
+            if (unenqueued == null) {
+                unenqueued = list;
+            } else {
+                // Find the last element in unenqueued.
+                Reference<?> last = unenqueued;
+                while (last.pendingNext != unenqueued) {
+                  last = last.pendingNext;
+                }
+                // Add our list to the end. Update the pendingNext to point back to enqueued.
+                last.pendingNext = list;
+                last = list;
+                while (last.pendingNext != list) {
+                    last = last.pendingNext;
+                }
+                last.pendingNext = unenqueued;
+            }
+            ReferenceQueue.class.notifyAll();
+        }
+    }
+}
+// END Android-changed: Reimplemented to accomodate a different GC and compiler.
diff --git a/java/lang/ref/SoftReference.java b/java/lang/ref/SoftReference.java
new file mode 100644
index 0000000..272d1bd
--- /dev/null
+++ b/java/lang/ref/SoftReference.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.ref;
+
+// Android-changed: Javadoc change to recommend against using SoftReferences for caches.
+/**
+ * Soft reference objects, which are cleared at the discretion of the garbage
+ * collector in response to memory demand.
+ *
+ * <p> Suppose that the garbage collector determines at a certain point in time
+ * that an object is <a href="package-summary.html#reachability">softly
+ * reachable</a>.  At that time it may choose to clear atomically all soft
+ * references to that object and all soft references to any other
+ * softly-reachable objects from which that object is reachable through a chain
+ * of strong references.  At the same time or at some later time it will
+ * enqueue those newly-cleared soft references that are registered with
+ * reference queues.
+ *
+ * <p> All soft references to softly-reachable objects are guaranteed to have
+ * been cleared before the virtual machine throws an
+ * <code>OutOfMemoryError</code>.  Otherwise no constraints are placed upon the
+ * time at which a soft reference will be cleared or the order in which a set
+ * of such references to different objects will be cleared.  Virtual machine
+ * implementations are, however, encouraged to bias against clearing
+ * recently-created or recently-used soft references.
+ *
+ * <h3>Avoid Soft References for Caching</h3>
+ * In practice, soft references are inefficient for caching. The runtime doesn't
+ * have enough information on which references to clear and which to keep. Most
+ * fatally, it doesn't know what to do when given the choice between clearing a
+ * soft reference and growing the heap.
+ *
+ * <p>The lack of information on the value to your application of each reference
+ * limits the usefulness of soft references. References that are cleared too
+ * early cause unnecessary work; those that are cleared too late waste memory.
+ *
+ * <p>Most applications should use an {@code android.util.LruCache} instead of
+ * soft references. LruCache has an effective eviction policy and lets the user
+ * tune how much memory is allotted.
+ *
+ * @author   Mark Reinhold
+ * @since    1.2
+ */
+
+public class SoftReference<T> extends Reference<T> {
+
+    /**
+     * Timestamp clock, updated by the garbage collector
+     */
+    static private long clock;
+
+    /**
+     * Timestamp updated by each invocation of the get method.  The VM may use
+     * this field when selecting soft references to be cleared, but it is not
+     * required to do so.
+     */
+    private long timestamp;
+
+    /**
+     * Creates a new soft reference that refers to the given object.  The new
+     * reference is not registered with any queue.
+     *
+     * @param referent object the new soft reference will refer to
+     */
+    public SoftReference(T referent) {
+        super(referent);
+        this.timestamp = clock;
+    }
+
+    /**
+     * Creates a new soft reference that refers to the given object and is
+     * registered with the given queue.
+     *
+     * @param referent object the new soft reference will refer to
+     * @param q the queue with which the reference is to be registered,
+     *          or <tt>null</tt> if registration is not required
+     *
+     */
+    public SoftReference(T referent, ReferenceQueue<? super T> q) {
+        super(referent, q);
+        this.timestamp = clock;
+    }
+
+    /**
+     * Returns this reference object's referent.  If this reference object has
+     * been cleared, either by the program or by the garbage collector, then
+     * this method returns <code>null</code>.
+     *
+     * @return   The object to which this reference refers, or
+     *           <code>null</code> if this reference object has been cleared
+     */
+    public T get() {
+        T o = super.get();
+        if (o != null && this.timestamp != clock)
+            this.timestamp = clock;
+        return o;
+    }
+
+}
diff --git a/java/lang/ref/WeakReference.java b/java/lang/ref/WeakReference.java
new file mode 100644
index 0000000..025949a
--- /dev/null
+++ b/java/lang/ref/WeakReference.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.ref;
+
+
+/**
+ * Weak reference objects, which do not prevent their referents from being
+ * made finalizable, finalized, and then reclaimed.  Weak references are most
+ * often used to implement canonicalizing mappings.
+ *
+ * <p> Suppose that the garbage collector determines at a certain point in time
+ * that an object is <a href="package-summary.html#reachability">weakly
+ * reachable</a>.  At that time it will atomically clear all weak references to
+ * that object and all weak references to any other weakly-reachable objects
+ * from which that object is reachable through a chain of strong and soft
+ * references.  At the same time it will declare all of the formerly
+ * weakly-reachable objects to be finalizable.  At the same time or at some
+ * later time it will enqueue those newly-cleared weak references that are
+ * registered with reference queues.
+ *
+ * @author   Mark Reinhold
+ * @since    1.2
+ */
+
+public class WeakReference<T> extends Reference<T> {
+
+    /**
+     * Creates a new weak reference that refers to the given object.  The new
+     * reference is not registered with any queue.
+     *
+     * @param referent object the new weak reference will refer to
+     */
+    public WeakReference(T referent) {
+        super(referent);
+    }
+
+    /**
+     * Creates a new weak reference that refers to the given object and is
+     * registered with the given queue.
+     *
+     * @param referent object the new weak reference will refer to
+     * @param q the queue with which the reference is to be registered,
+     *          or <tt>null</tt> if registration is not required
+     */
+    public WeakReference(T referent, ReferenceQueue<? super T> q) {
+        super(referent, q);
+    }
+
+}
diff --git a/java/lang/ref/package-info.java b/java/lang/ref/package-info.java
new file mode 100644
index 0000000..cc7f9ef
--- /dev/null
+++ b/java/lang/ref/package-info.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/**
+ * Provides reference-object classes, which support a limited degree of
+ * interaction with the garbage collector.  A program may use a reference object
+ * to maintain a reference to some other object in such a way that the latter
+ * object may still be reclaimed by the collector.  A program may also arrange to
+ * be notified some time after the collector has determined that the reachability
+ * of a given object has changed.
+ *
+ *
+ * <h2>Package Specification</h2>
+ *
+ * A <em>reference object</em> encapsulates a reference to some other object so
+ * that the reference itself may be examined and manipulated like any other
+ * object.  Three types of reference objects are provided, each weaker than the
+ * last: <em>soft</em>, <em>weak</em>, and <em>phantom</em>.  Each type
+ * corresponds to a different level of reachability, as defined below.  Soft
+ * references are for implementing memory-sensitive caches, weak references are
+ * for implementing canonicalizing mappings that do not prevent their keys (or
+ * values) from being reclaimed, and phantom references are for scheduling
+ * pre-mortem cleanup actions in a more flexible way than is possible with the
+ * Java finalization mechanism.
+ *
+ * <p> Each reference-object type is implemented by a subclass of the abstract
+ * base <code>{@link java.lang.ref.Reference}</code> class.  An instance of one of
+ * these subclasses encapsulates a single reference to a particular object, called
+ * the <em>referent</em>.  Every reference object provides methods for getting and
+ * clearing the reference.  Aside from the clearing operation reference objects
+ * are otherwise immutable, so no <code>set</code> operation is provided.  A
+ * program may further subclass these subclasses, adding whatever fields and
+ * methods are required for its purposes, or it may use these subclasses without
+ * change.
+ *
+ *
+ * <h3>Notification</h3>
+ *
+ * A program may request to be notified of changes in an object's reachability by
+ * <em>registering</em> an appropriate reference object with a <em>reference
+ * queue</em> at the time the reference object is created.  Some time after the
+ * garbage collector determines that the reachability of the referent has changed
+ * to the value corresponding to the type of the reference, it will add the
+ * reference to the associated queue.  At this point, the reference is considered
+ * to be <em>enqueued</em>.  The program may remove references from a queue either
+ * by polling or by blocking until a reference becomes available.  Reference
+ * queues are implemented by the <code>{@link java.lang.ref.ReferenceQueue}</code>
+ * class.
+ *
+ * <p> The relationship between a registered reference object and its queue is
+ * one-sided.  That is, a queue does not keep track of the references that are
+ * registered with it.  If a registered reference becomes unreachable itself, then
+ * it will never be enqueued.  It is the responsibility of the program using
+ * reference objects to ensure that the objects remain reachable for as long as
+ * the program is interested in their referents.
+ *
+ * <p> While some programs will choose to dedicate a thread to removing reference
+ * objects from one or more queues and processing them, this is by no means
+ * necessary.  A tactic that often works well is to examine a reference queue in
+ * the course of performing some other fairly-frequent action.  For example, a
+ * hashtable that uses weak references to implement weak keys could poll its
+ * reference queue each time the table is accessed.  This is how the <code>{@link
+ * java.util.WeakHashMap}</code> class works.  Because the <code>{@link
+ * java.lang.ref.ReferenceQueue#poll ReferenceQueue.poll}</code> method simply
+ * checks an internal data structure, this check will add little overhead to the
+ * hashtable access methods.
+ *
+ *
+ * <h3>Automatically-cleared references</h3>
+ *
+ * Soft and weak references are automatically cleared by the collector before
+ * being added to the queues with which they are registered, if any.  Therefore
+ * soft and weak references need not be registered with a queue in order to be
+ * useful, while phantom references do.  An object that is reachable via phantom
+ * references will remain so until all such references are cleared or themselves
+ * become unreachable.
+ *
+ *
+ * <a name="reachability"></a>
+ * <h3>Reachability</h3>
+ *
+ * Going from strongest to weakest, the different levels of reachability reflect
+ * the life cycle of an object.  They are operationally defined as follows:
+ *
+ * <ul>
+ *
+ * <li> An object is <em>strongly reachable</em> if it can be reached by some
+ * thread without traversing any reference objects.  A newly-created object is
+ * strongly reachable by the thread that created it.
+ *
+ * <li> An object is <em>softly reachable</em> if it is not strongly reachable but
+ * can be reached by traversing a soft reference.
+ *
+ * <li> An object is <em>weakly reachable</em> if it is neither strongly nor
+ * softly reachable but can be reached by traversing a weak reference.  When the
+ * weak references to a weakly-reachable object are cleared, the object becomes
+ * eligible for finalization.
+ *
+ * <li> An object is <em>phantom reachable</em> if it is neither strongly, softly,
+ * nor weakly reachable, it has been finalized, and some phantom reference refers
+ * to it.
+ *
+ * <li> Finally, an object is <em>unreachable</em>, and therefore eligible for
+ * reclamation, when it is not reachable in any of the above ways.
+ *
+ * </ul>
+ *
+ *
+ * @author	  Mark Reinhold
+ * @since	  1.2
+ */
+package java.lang.ref;
diff --git a/java/lang/reflect/AccessibleObject.annotated.java b/java/lang/reflect/AccessibleObject.annotated.java
new file mode 100644
index 0000000..f601635
--- /dev/null
+++ b/java/lang/reflect/AccessibleObject.annotated.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class AccessibleObject implements java.lang.reflect.AnnotatedElement {
+
+protected AccessibleObject() { throw new RuntimeException("Stub!"); }
+
+public static void setAccessible(java.lang.reflect.AccessibleObject[] array, boolean flag) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public void setAccessible(boolean flag) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public boolean isAccessible() { throw new RuntimeException("Stub!"); }
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public boolean isAnnotationPresent(@libcore.util.NonNull java.lang.Class<? extends java.lang.annotation.Annotation> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Annotation @libcore.util.NonNull [] getAnnotations() { throw new RuntimeException("Stub!"); }
+
[email protected] public <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Annotation @libcore.util.NonNull [] getDeclaredAnnotations() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/reflect/AccessibleObject.java b/java/lang/reflect/AccessibleObject.java
new file mode 100644
index 0000000..18442fa
--- /dev/null
+++ b/java/lang/reflect/AccessibleObject.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import java.lang.annotation.Annotation;
+
+/**
+ * The AccessibleObject class is the base class for Field, Method and
+ * Constructor objects.  It provides the ability to flag a reflected
+ * object as suppressing default Java language access control checks
+ * when it is used.  The access checks--for public, default (package)
+ * access, protected, and private members--are performed when Fields,
+ * Methods or Constructors are used to set or get fields, to invoke
+ * methods, or to create and initialize new instances of classes,
+ * respectively.
+ *
+ * <p>Setting the {@code accessible} flag in a reflected object
+ * permits sophisticated applications with sufficient privilege, such
+ * as Java Object Serialization or other persistence mechanisms, to
+ * manipulate objects in a manner that would normally be prohibited.
+ *
+ * <p>By default, a reflected object is <em>not</em> accessible.
+ *
+ * @see Field
+ * @see Method
+ * @see Constructor
+ * @see ReflectPermission
+ *
+ * @since 1.2
+ */
+public class AccessibleObject implements AnnotatedElement {
+
+    // Android-removed: Code associated with SecurityManager calls.
+    /*
+    /**
+     * The Permission object that is used to check whether a client
+     * has sufficient privilege to defeat Java language access
+     * control checks.
+     *
+    static final private java.security.Permission ACCESS_PERMISSION =
+        new ReflectPermission("suppressAccessChecks");
+    */
+
+    /**
+     * Convenience method to set the {@code accessible} flag for an
+     * array of objects with a single security check (for efficiency).
+     *
+     * <p>First, if there is a security manager, its
+     * {@code checkPermission} method is called with a
+     * {@code ReflectPermission("suppressAccessChecks")} permission.
+     *
+     * <p>A {@code SecurityException} is raised if {@code flag} is
+     * {@code true} but accessibility of any of the elements of the input
+     * {@code array} may not be changed (for example, if the element
+     * object is a {@link Constructor} object for the class {@link
+     * java.lang.Class}).  In the event of such a SecurityException, the
+     * accessibility of objects is set to {@code flag} for array elements
+     * upto (and excluding) the element for which the exception occurred; the
+     * accessibility of elements beyond (and including) the element for which
+     * the exception occurred is unchanged.
+     *
+     * @param array the array of AccessibleObjects
+     * @param flag  the new value for the {@code accessible} flag
+     *              in each object
+     * @throws SecurityException if the request is denied.
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     */
+    public static void setAccessible(AccessibleObject[] array, boolean flag)
+        throws SecurityException {
+        // Android-removed: SecurityManager calls.
+        // SecurityManager sm = System.getSecurityManager();
+        // if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+        for (int i = 0; i < array.length; i++) {
+            setAccessible0(array[i], flag);
+        }
+    }
+
+    /**
+     * Set the {@code accessible} flag for this object to
+     * the indicated boolean value.  A value of {@code true} indicates that
+     * the reflected object should suppress Java language access
+     * checking when it is used.  A value of {@code false} indicates
+     * that the reflected object should enforce Java language access checks.
+     *
+     * <p>First, if there is a security manager, its
+     * {@code checkPermission} method is called with a
+     * {@code ReflectPermission("suppressAccessChecks")} permission.
+     *
+     * <p>A {@code SecurityException} is raised if {@code flag} is
+     * {@code true} but accessibility of this object may not be changed
+     * (for example, if this element object is a {@link Constructor} object for
+     * the class {@link java.lang.Class}).
+     *
+     * <p>A {@code SecurityException} is raised if this object is a {@link
+     * java.lang.reflect.Constructor} object for the class
+     * {@code java.lang.Class}, and {@code flag} is true.
+     *
+     * @param flag the new value for the {@code accessible} flag
+     * @throws SecurityException if the request is denied.
+     * @see SecurityManager#checkPermission
+     * @see java.lang.RuntimePermission
+     */
+    public void setAccessible(boolean flag) throws SecurityException {
+        // Android-removed: SecurityManager calls.
+        // SecurityManager sm = System.getSecurityManager();
+        // if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
+        setAccessible0(this, flag);
+    }
+
+    /* Check that you aren't exposing java.lang.Class.<init> or sensitive
+       fields in java.lang.Class. */
+    private static void setAccessible0(AccessibleObject obj, boolean flag)
+        throws SecurityException
+    {
+        if (obj instanceof Constructor && flag == true) {
+            Constructor<?> c = (Constructor<?>)obj;
+            // BEGIN Android-changed: Disallow making Method & Field constructors accessible.
+            // if (c.getDeclaringClass() == Class.class) {
+            //     throw new SecurityException("Cannot make a java.lang.Class" +
+            //                                 " constructor accessible");
+            // }
+
+            Class<?> clazz = c.getDeclaringClass();
+            if (c.getDeclaringClass() == Class.class) {
+                throw new SecurityException("Can not make a java.lang.Class" +
+                                            " constructor accessible");
+            } else if (clazz == Method.class) {
+                throw new SecurityException("Can not make a java.lang.reflect.Method" +
+                                            " constructor accessible");
+            } else if (clazz == Field.class) {
+                throw new SecurityException("Can not make a java.lang.reflect.Field" +
+                                            " constructor accessible");
+            }
+            // END Android-changed: Disallow making Method & Field constructors accessible.
+        }
+        obj.override = flag;
+    }
+
+    /**
+     * Get the value of the {@code accessible} flag for this object.
+     *
+     * @return the value of the object's {@code accessible} flag
+     */
+    public boolean isAccessible() {
+        return override;
+    }
+
+    /**
+     * Constructor: only used by the Java Virtual Machine.
+     */
+    protected AccessibleObject() {}
+
+    // Indicates whether language-level access checks are overridden
+    // by this object. Initializes to "false". This field is used by
+    // Field, Method, and Constructor.
+    //
+    // NOTE: for security purposes, this field must not be visible
+    // outside this package.
+    boolean override;
+
+    // Android-removed: reflectionFactory: it is not used on Android.
+    /*
+    // Reflection factory used by subclasses for creating field,
+    // method, and constructor accessors. Note that this is called
+    // very early in the bootstrapping process.
+    static final ReflectionFactory reflectionFactory =
+        AccessController.doPrivileged(
+            new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());
+    */
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        throw new AssertionError("All subclasses should override this method");
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+        return AnnotatedElement.super.isAnnotationPresent(annotationClass);
+    }
+
+   /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+        throw new AssertionError("All subclasses should override this method");
+    }
+
+    /**
+     * @since 1.5
+     */
+    public Annotation[] getAnnotations() {
+        return getDeclaredAnnotations();
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
+        // Only annotations on classes are inherited, for all other
+        // objects getDeclaredAnnotation is the same as
+        // getAnnotation.
+        return getAnnotation(annotationClass);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
+        // Only annotations on classes are inherited, for all other
+        // objects getDeclaredAnnotationsByType is the same as
+        // getAnnotationsByType.
+        return getAnnotationsByType(annotationClass);
+    }
+
+    /**
+     * @since 1.5
+     */
+    public Annotation[] getDeclaredAnnotations()  {
+        throw new AssertionError("All subclasses should override this method");
+    }
+
+    // BEGIN Android-removed: Shared access checking logic: Not used on Android.
+    /*
+    // For non-public members or members in package-private classes,
+    // it is necessary to perform somewhat expensive security checks.
+    // If the security check succeeds for a given class, it will
+    // always succeed (it is not affected by the granting or revoking
+    // of permissions); we speed up the check in the common case by
+    // remembering the last Class for which the check succeeded.
+    //
+    // The simple security check for Constructor is to see if
+    // the caller has already been seen, verified, and cached.
+    // (See also Class.newInstance(), which uses a similar method.)
+    //
+    // A more complicated security check cache is needed for Method and Field
+    // The cache can be either null (empty cache), a 2-array of {caller,target},
+    // or a caller (with target implicitly equal to this.clazz).
+    // In the 2-array case, the target is always different from the clazz.
+    volatile Object securityCheckCache;
+
+    void checkAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers)
+        throws IllegalAccessException
+    {
+        if (caller == clazz) {  // quick check
+            return;             // ACCESS IS OK
+        }
+        Object cache = securityCheckCache;  // read volatile
+        Class<?> targetClass = clazz;
+        if (obj != null
+            && Modifier.isProtected(modifiers)
+            && ((targetClass = obj.getClass()) != clazz)) {
+            // Must match a 2-list of { caller, targetClass }.
+            if (cache instanceof Class[]) {
+                Class<?>[] cache2 = (Class<?>[]) cache;
+                if (cache2[1] == targetClass &&
+                    cache2[0] == caller) {
+                    return;     // ACCESS IS OK
+                }
+                // (Test cache[1] first since range check for [1]
+                // subsumes range check for [0].)
+            }
+        } else if (cache == caller) {
+            // Non-protected case (or obj.class == this.clazz).
+            return;             // ACCESS IS OK
+        }
+
+        // If no return, fall through to the slow path.
+        slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);
+    }
+
+    // Keep all this slow stuff out of line:
+    void slowCheckMemberAccess(Class<?> caller, Class<?> clazz, Object obj, int modifiers,
+                               Class<?> targetClass)
+        throws IllegalAccessException
+    {
+        Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
+
+        // Success: Update the cache.
+        Object cache = ((targetClass == clazz)
+                        ? caller
+                        : new Class<?>[] { caller, targetClass });
+
+        // Note:  The two cache elements are not volatile,
+        // but they are effectively final.  The Java memory model
+        // guarantees that the initializing stores for the cache
+        // elements will occur before the volatile write.
+        securityCheckCache = cache;         // write volatile
+    }
+    */
+    // END Android-removed: Shared access checking logic: Not used on Android.
+}
diff --git a/java/lang/reflect/AnnotatedElement.annotated.java b/java/lang/reflect/AnnotatedElement.annotated.java
new file mode 100644
index 0000000..97cb3a2
--- /dev/null
+++ b/java/lang/reflect/AnnotatedElement.annotated.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+import java.lang.annotation.AnnotationFormatError;
+import java.lang.annotation.Annotation;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface AnnotatedElement {
+
+public default boolean isAnnotationPresent(@libcore.util.NonNull java.lang.Class<? extends java.lang.annotation.Annotation> annotationClass) { throw new RuntimeException("Stub!"); }
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass);
+
+public [email protected] Annotation @libcore.util.NonNull [] getAnnotations();
+
+public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
[email protected] public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Annotation @libcore.util.NonNull [] getDeclaredAnnotations();
+}
diff --git a/java/lang/reflect/AnnotatedElement.java b/java/lang/reflect/AnnotatedElement.java
new file mode 100644
index 0000000..7bb2a60
--- /dev/null
+++ b/java/lang/reflect/AnnotatedElement.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.AnnotationFormatError;
+import java.util.Objects;
+import libcore.reflect.AnnotatedElements;
+
+// Android-changed: Removed some references to bytecode spec below that do not
+// apply to DEX and added a note about annotation ordering.
+/**
+ * Represents an annotated element of the program currently running in this
+ * VM.  This interface allows annotations to be read reflectively.  All
+ * annotations returned by methods in this interface are immutable and
+ * serializable. The arrays returned by methods of this interface may be modified
+ * by callers without affecting the arrays returned to other callers.
+ *
+ * <p>Android note: methods that return multiple annotations of different types such as
+ * {@link #getAnnotations()} and {@link #getDeclaredAnnotations()} can be affected
+ * by the explicit character-code ordering of annotations types specified by the DEX format.
+ * Annotations of different types on a single element are not guaranteed to be returned in the order
+ * they are declared in source.
+ *
+ * <p>The {@link #getAnnotationsByType(Class)} and {@link
+ * #getDeclaredAnnotationsByType(Class)} methods support multiple
+ * annotations of the same type on an element. If the argument to
+ * either method is a repeatable annotation type (JLS 9.6), then the
+ * method will "look through" a container annotation (JLS 9.7), if
+ * present, and return any annotations inside the container. Container
+ * annotations may be generated at compile-time to wrap multiple
+ * annotations of the argument type.
+ *
+ * <p>The terms <em>directly present</em>, <em>indirectly present</em>,
+ * <em>present</em>, and <em>associated</em> are used throughout this
+ * interface to describe precisely which annotations are returned by
+ * methods:
+ *
+ * <ul>
+ *
+ * <li> An annotation <i>A</i> is <em>directly present</em> on an
+ * element <i>E</i> if <i>E</i> is annotated by <i>A</i> in the original source.
+ *
+ * <li>An annotation <i>A</i> is <em>indirectly present</em> on an
+ * element <i>E</i> if <i>E</i> is annotated by a container annotation
+ * of <i>A</i>.
+ *
+ * <li>An annotation <i>A</i> is present on an element <i>E</i> if either:
+ *
+ * <ul>
+ *
+ * <li><i>A</i> is directly present on <i>E</i>; or
+ *
+ * <li>No annotation of <i>A</i> 's type is directly present on
+ * <i>E</i>, and <i>E</i> is a class, and <i>A</i> 's type is
+ * inheritable, and <i>A</i> is present on the superclass of <i>E</i>.
+ *
+ * </ul>
+ *
+ * <li>An annotation <i>A</i> is <em>associated</em> with an element <i>E</i>
+ * if either:
+ *
+ * <ul>
+ *
+ * <li><i>A</i> is directly or indirectly present on <i>E</i>; or
+ *
+ * <li>No annotation of <i>A</i> 's type is directly or indirectly
+ * present on <i>E</i>, and <i>E</i> is a class, and <i>A</i>'s type
+ * is inheritable, and <i>A</i> is associated with the superclass of
+ * <i>E</i>.
+ *
+ * </ul>
+ *
+ * </ul>
+ *
+ * <p>The table below summarizes which kind of annotation presence
+ * different methods in this interface examine.
+ *
+ * <table border>
+ * <caption>Overview of kind of presence detected by different AnnotatedElement methods</caption>
+ * <tr><th colspan=2></th><th colspan=4>Kind of Presence</th>
+ * <tr><th colspan=2>Method</th><th>Directly Present</th><th>Indirectly Present</th><th>Present</th><th>Associated</th>
+ * <tr><td align=right>{@code T}</td><td>{@link #getAnnotation(Class) getAnnotation(Class&lt;T&gt;)}
+ * <td></td><td></td><td>X</td><td></td>
+ * </tr>
+ * <tr><td align=right>{@code Annotation[]}</td><td>{@link #getAnnotations getAnnotations()}
+ * <td></td><td></td><td>X</td><td></td>
+ * </tr>
+ * <tr><td align=right>{@code T[]}</td><td>{@link #getAnnotationsByType(Class) getAnnotationsByType(Class&lt;T&gt;)}
+ * <td></td><td></td><td></td><td>X</td>
+ * </tr>
+ * <tr><td align=right>{@code T}</td><td>{@link #getDeclaredAnnotation(Class) getDeclaredAnnotation(Class&lt;T&gt;)}
+ * <td>X</td><td></td><td></td><td></td>
+ * </tr>
+ * <tr><td align=right>{@code Annotation[]}</td><td>{@link #getDeclaredAnnotations getDeclaredAnnotations()}
+ * <td>X</td><td></td><td></td><td></td>
+ * </tr>
+ * <tr><td align=right>{@code T[]}</td><td>{@link #getDeclaredAnnotationsByType(Class) getDeclaredAnnotationsByType(Class&lt;T&gt;)}
+ * <td>X</td><td>X</td><td></td><td></td>
+ * </tr>
+ * </table>
+ *
+ * <p>For an invocation of {@code get[Declared]AnnotationsByType( Class <
+ * T >)}, the order of annotations which are directly or indirectly
+ * present on an element <i>E</i> is computed as if indirectly present
+ * annotations on <i>E</i> are directly present on <i>E</i> in place
+ * of their container annotation, in the order in which they appear in
+ * the value element of the container annotation.
+ *
+ * <p>There are several compatibility concerns to keep in mind if an
+ * annotation type <i>T</i> is originally <em>not</em> repeatable and
+ * later modified to be repeatable.
+ *
+ * The containing annotation type for <i>T</i> is <i>TC</i>.
+ *
+ * <ul>
+ *
+ * <li>Modifying <i>T</i> to be repeatable is source and binary
+ * compatible with existing uses of <i>T</i> and with existing uses
+ * of <i>TC</i>.
+ *
+ * That is, for source compatibility, source code with annotations of
+ * type <i>T</i> or of type <i>TC</i> will still compile. For binary
+ * compatibility, class files with annotations of type <i>T</i> or of
+ * type <i>TC</i> (or with other kinds of uses of type <i>T</i> or of
+ * type <i>TC</i>) will link against the modified version of <i>T</i>
+ * if they linked against the earlier version.
+ *
+ * (An annotation type <i>TC</i> may informally serve as an acting
+ * containing annotation type before <i>T</i> is modified to be
+ * formally repeatable. Alternatively, when <i>T</i> is made
+ * repeatable, <i>TC</i> can be introduced as a new type.)
+ *
+ * <li>If an annotation type <i>TC</i> is present on an element, and
+ * <i>T</i> is modified to be repeatable with <i>TC</i> as its
+ * containing annotation type then:
+ *
+ * <ul>
+ *
+ * <li>The change to <i>T</i> is behaviorally compatible with respect
+ * to the {@code get[Declared]Annotation(Class<T>)} (called with an
+ * argument of <i>T</i> or <i>TC</i>) and {@code
+ * get[Declared]Annotations()} methods because the results of the
+ * methods will not change due to <i>TC</i> becoming the containing
+ * annotation type for <i>T</i>.
+ *
+ * <li>The change to <i>T</i> changes the results of the {@code
+ * get[Declared]AnnotationsByType(Class<T>)} methods called with an
+ * argument of <i>T</i>, because those methods will now recognize an
+ * annotation of type <i>TC</i> as a container annotation for <i>T</i>
+ * and will "look through" it to expose annotations of type <i>T</i>.
+ *
+ * </ul>
+ *
+ * <li>If an annotation of type <i>T</i> is present on an
+ * element and <i>T</i> is made repeatable and more annotations of
+ * type <i>T</i> are added to the element:
+ *
+ * <ul>
+ *
+ * <li> The addition of the annotations of type <i>T</i> is both
+ * source compatible and binary compatible.
+ *
+ * <li>The addition of the annotations of type <i>T</i> changes the results
+ * of the {@code get[Declared]Annotation(Class<T>)} methods and {@code
+ * get[Declared]Annotations()} methods, because those methods will now
+ * only see a container annotation on the element and not see an
+ * annotation of type <i>T</i>.
+ *
+ * <li>The addition of the annotations of type <i>T</i> changes the
+ * results of the {@code get[Declared]AnnotationsByType(Class<T>)}
+ * methods, because their results will expose the additional
+ * annotations of type <i>T</i> whereas previously they exposed only a
+ * single annotation of type <i>T</i>.
+ *
+ * </ul>
+ *
+ * </ul>
+ *
+ * <p>If an annotation returned by a method in this interface contains
+ * (directly or indirectly) a {@link Class}-valued member referring to
+ * a class that is not accessible in this VM, attempting to read the class
+ * by calling the relevant Class-returning method on the returned annotation
+ * will result in a {@link TypeNotPresentException}.
+ *
+ * <p>Similarly, attempting to read an enum-valued member will result in
+ * a {@link EnumConstantNotPresentException} if the enum constant in the
+ * annotation is no longer present in the enum type.
+ *
+ * <p>If an annotation type <i>T</i> is (meta-)annotated with an
+ * {@code @Repeatable} annotation whose value element indicates a type
+ * <i>TC</i>, but <i>TC</i> does not declare a {@code value()} method
+ * with a return type of <i>T</i>{@code []}, then an exception of type
+ * {@link java.lang.annotation.AnnotationFormatError} is thrown.
+ *
+ * <p>Finally, attempting to read a member whose definition has evolved
+ * incompatibly will result in a {@link
+ * java.lang.annotation.AnnotationTypeMismatchException} or an
+ * {@link java.lang.annotation.IncompleteAnnotationException}.
+ *
+ * @see java.lang.EnumConstantNotPresentException
+ * @see java.lang.TypeNotPresentException
+ * @see AnnotationFormatError
+ * @see java.lang.annotation.AnnotationTypeMismatchException
+ * @see java.lang.annotation.IncompleteAnnotationException
+ * @since 1.5
+ * @author Josh Bloch
+ */
+public interface AnnotatedElement {
+    /**
+     * Returns true if an annotation for the specified type
+     * is <em>present</em> on this element, else false.  This method
+     * is designed primarily for convenient access to marker annotations.
+     *
+     * <p>The truth value returned by this method is equivalent to:
+     * {@code getAnnotation(annotationClass) != null}
+     *
+     * <p>The body of the default method is specified to be the code
+     * above.
+     *
+     * @param annotationClass the Class object corresponding to the
+     *        annotation type
+     * @return true if an annotation for the specified annotation
+     *     type is present on this element, else false
+     * @throws NullPointerException if the given annotation class is null
+     * @since 1.5
+     */
+    default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+        return getAnnotation(annotationClass) != null;
+    }
+
+   /**
+     * Returns this element's annotation for the specified type if
+     * such an annotation is <em>present</em>, else null.
+     *
+     * @param <T> the type of the annotation to query for and return if present
+     * @param annotationClass the Class object corresponding to the
+     *        annotation type
+     * @return this element's annotation for the specified annotation type if
+     *     present on this element, else null
+     * @throws NullPointerException if the given annotation class is null
+     * @since 1.5
+     */
+    <T extends Annotation> T getAnnotation(Class<T> annotationClass);
+
+    /**
+     * Returns annotations that are <em>present</em> on this element.
+     *
+     * If there are no annotations <em>present</em> on this element, the return
+     * value is an array of length 0.
+     *
+     * The caller of this method is free to modify the returned array; it will
+     * have no effect on the arrays returned to other callers.
+     *
+     * @return annotations present on this element
+     * @since 1.5
+     */
+    Annotation[] getAnnotations();
+
+    /**
+     * Returns annotations that are <em>associated</em> with this element.
+     *
+     * If there are no annotations <em>associated</em> with this element, the return
+     * value is an array of length 0.
+     *
+     * The difference between this method and {@link #getAnnotation(Class)}
+     * is that this method detects if its argument is a <em>repeatable
+     * annotation type</em> (JLS 9.6), and if so, attempts to find one or
+     * more annotations of that type by "looking through" a container
+     * annotation.
+     *
+     * The caller of this method is free to modify the returned array; it will
+     * have no effect on the arrays returned to other callers.
+     *
+     * @implSpec The default implementation first calls {@link
+     * #getDeclaredAnnotationsByType(Class)} passing {@code
+     * annotationClass} as the argument. If the returned array has
+     * length greater than zero, the array is returned. If the returned
+     * array is zero-length and this {@code AnnotatedElement} is a
+     * class and the argument type is an inheritable annotation type,
+     * and the superclass of this {@code AnnotatedElement} is non-null,
+     * then the returned result is the result of calling {@link
+     * #getAnnotationsByType(Class)} on the superclass with {@code
+     * annotationClass} as the argument. Otherwise, a zero-length
+     * array is returned.
+     *
+     * @param <T> the type of the annotation to query for and return if present
+     * @param annotationClass the Class object corresponding to the
+     *        annotation type
+     * @return all this element's annotations for the specified annotation type if
+     *     associated with this element, else an array of length zero
+     * @throws NullPointerException if the given annotation class is null
+     * @since 1.8
+     */
+    default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+        // Android-changed: Altered method implementation for getAnnotationsByType(Class).
+        // Android's annotation code is customized because of the use of the DEX format on Android
+        // and code sharing with the runtime.
+        // This method does not handle inherited annotations and is intended for use for
+        // {@code Method}, {@code Field}, {@code Package}. The {@link Class#getAnnotationsByType}
+        // is implemented explicitly. Therefore this implementation does not fulfill the documented
+        // default implementation for {@link AnnotatedElement#getAnnotationsByType(Class)} but in an
+        // undetectable way because Class is final.
+        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
+    }
+
+    /**
+     * Returns this element's annotation for the specified type if
+     * such an annotation is <em>directly present</em>, else null.
+     *
+     * This method ignores inherited annotations. (Returns null if no
+     * annotations are directly present on this element.)
+     *
+     * @implSpec The default implementation first performs a null check
+     * and then loops over the results of {@link
+     * #getDeclaredAnnotations} returning the first annotation whose
+     * annotation type matches the argument type.
+     *
+     * @param <T> the type of the annotation to query for and return if directly present
+     * @param annotationClass the Class object corresponding to the
+     *        annotation type
+     * @return this element's annotation for the specified annotation type if
+     *     directly present on this element, else null
+     * @throws NullPointerException if the given annotation class is null
+     * @since 1.8
+     */
+    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+        // Loop over all directly-present annotations looking for a matching one
+        for (Annotation annotation : getDeclaredAnnotations()) {
+            if (annotationClass.equals(annotation.annotationType())) {
+                // More robust to do a dynamic cast at runtime instead
+                // of compile-time only.
+                return annotationClass.cast(annotation);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns this element's annotation(s) for the specified type if
+     * such annotations are either <em>directly present</em> or
+     * <em>indirectly present</em>. This method ignores inherited
+     * annotations.
+     *
+     * If there are no specified annotations directly or indirectly
+     * present on this element, the return value is an array of length
+     * 0.
+     *
+     * The difference between this method and {@link
+     * #getDeclaredAnnotation(Class)} is that this method detects if its
+     * argument is a <em>repeatable annotation type</em> (JLS 9.6), and if so,
+     * attempts to find one or more annotations of that type by "looking
+     * through" a container annotation if one is present.
+     *
+     * The caller of this method is free to modify the returned array; it will
+     * have no effect on the arrays returned to other callers.
+     *
+     * @implSpec The default implementation may call {@link
+     * #getDeclaredAnnotation(Class)} one or more times to find a
+     * directly present annotation and, if the annotation type is
+     * repeatable, to find a container annotation. If annotations of
+     * the annotation type {@code annotationClass} are found to be both
+     * directly and indirectly present, then {@link
+     * #getDeclaredAnnotations()} will get called to determine the
+     * order of the elements in the returned array.
+     *
+     * <p>Alternatively, the default implementation may call {@link
+     * #getDeclaredAnnotations()} a single time and the returned array
+     * examined for both directly and indirectly present
+     * annotations. The results of calling {@link
+     * #getDeclaredAnnotations()} are assumed to be consistent with the
+     * results of calling {@link #getDeclaredAnnotation(Class)}.
+     *
+     * @param <T> the type of the annotation to query for and return
+     * if directly or indirectly present
+     * @param annotationClass the Class object corresponding to the
+     *        annotation type
+     * @return all this element's annotations for the specified annotation type if
+     *     directly or indirectly present on this element, else an array of length zero
+     * @throws NullPointerException if the given annotation class is null
+     * @since 1.8
+     */
+    default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
+        // Android-changed: Altered method implementation for getAnnotationsByType(Class).
+        // Android's annotation code is customized because of the use of the DEX format on Android
+        // and code sharing with the runtime.
+        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
+    }
+
+    /**
+     * Returns annotations that are <em>directly present</em> on this element.
+     * This method ignores inherited annotations.
+     *
+     * If there are no annotations <em>directly present</em> on this element,
+     * the return value is an array of length 0.
+     *
+     * The caller of this method is free to modify the returned array; it will
+     * have no effect on the arrays returned to other callers.
+     *
+     * @return annotations directly present on this element
+     * @since 1.5
+     */
+    Annotation[] getDeclaredAnnotations();
+}
diff --git a/java/lang/reflect/Array.annotated.java b/java/lang/reflect/Array.annotated.java
new file mode 100644
index 0000000..f0fba5c
--- /dev/null
+++ b/java/lang/reflect/Array.annotated.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Array {
+
+Array() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Object newInstance(@libcore.util.NonNull java.lang.Class<?> componentType, int length) throws java.lang.NegativeArraySizeException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Object newInstance(@libcore.util.NonNull java.lang.Class<?> componentType, int... dimensions) throws java.lang.IllegalArgumentException, java.lang.NegativeArraySizeException { throw new RuntimeException("Stub!"); }
+
+public static int getLength(@libcore.util.NonNull java.lang.Object array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Object get(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static boolean getBoolean(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static byte getByte(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static char getChar(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static short getShort(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static int getInt(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static long getLong(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static float getFloat(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static double getDouble(@libcore.util.NonNull java.lang.Object array, int index) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void set(@libcore.util.NonNull java.lang.Object array, int index, @libcore.util.Nullable java.lang.Object value) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setBoolean(@libcore.util.NonNull java.lang.Object array, int index, boolean z) { throw new RuntimeException("Stub!"); }
+
+public static void setByte(@libcore.util.NonNull java.lang.Object array, int index, byte b) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setChar(@libcore.util.NonNull java.lang.Object array, int index, char c) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setShort(@libcore.util.NonNull java.lang.Object array, int index, short s) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setInt(@libcore.util.NonNull java.lang.Object array, int index, int i) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setLong(@libcore.util.NonNull java.lang.Object array, int index, long l) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setFloat(@libcore.util.NonNull java.lang.Object array, int index, float f) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static void setDouble(@libcore.util.NonNull java.lang.Object array, int index, double d) throws java.lang.ArrayIndexOutOfBoundsException, java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/reflect/Array.java b/java/lang/reflect/Array.java
new file mode 100644
index 0000000..95a8091
--- /dev/null
+++ b/java/lang/reflect/Array.java
@@ -0,0 +1,840 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import dalvik.annotation.optimization.FastNative;
+
+/**
+ * The {@code Array} class provides static methods to dynamically create and
+ * access Java arrays.
+ *
+ * <p>{@code Array} permits widening conversions to occur during a get or set
+ * operation, but throws an {@code IllegalArgumentException} if a narrowing
+ * conversion would occur.
+ *
+ * @author Nakul Saraiya
+ */
+public final
+class Array {
+
+    /**
+     * Constructor.  Class Array is not instantiable.
+     */
+    private Array() {}
+
+    /**
+     * Creates a new array with the specified component type and
+     * length.
+     * Invoking this method is equivalent to creating an array
+     * as follows:
+     * <blockquote>
+     * <pre>
+     * int[] x = {length};
+     * Array.newInstance(componentType, x);
+     * </pre>
+     * </blockquote>
+     *
+     * <p>The number of dimensions of the new array must not
+     * exceed 255.
+     *
+     * @param componentType the {@code Class} object representing the
+     * component type of the new array
+     * @param length the length of the new array
+     * @return the new array
+     * @exception NullPointerException if the specified
+     * {@code componentType} parameter is null
+     * @exception IllegalArgumentException if componentType is {@link
+     * Void#TYPE} or if the number of dimensions of the requested array
+     * instance exceed 255.
+     * @exception NegativeArraySizeException if the specified {@code length}
+     * is negative
+     */
+    public static Object newInstance(Class<?> componentType, int length)
+        throws NegativeArraySizeException {
+        return newArray(componentType, length);
+    }
+
+    /**
+     * Creates a new array
+     * with the specified component type and dimensions.
+     * If {@code componentType}
+     * represents a non-array class or interface, the new array
+     * has {@code dimensions.length} dimensions and
+     * {@code componentType} as its component type. If
+     * {@code componentType} represents an array class, the
+     * number of dimensions of the new array is equal to the sum
+     * of {@code dimensions.length} and the number of
+     * dimensions of {@code componentType}. In this case, the
+     * component type of the new array is the component type of
+     * {@code componentType}.
+     *
+     * <p>The number of dimensions of the new array must not
+     * exceed 255.
+     *
+     * @param componentType the {@code Class} object representing the component
+     * type of the new array
+     * @param dimensions an array of {@code int} representing the dimensions of
+     * the new array
+     * @return the new array
+     * @exception NullPointerException if the specified
+     * {@code componentType} argument is null
+     * @exception IllegalArgumentException if the specified {@code dimensions}
+     * argument is a zero-dimensional array, if componentType is {@link
+     * Void#TYPE}, or if the number of dimensions of the requested array
+     * instance exceed 255.
+     * @exception NegativeArraySizeException if any of the components in
+     * the specified {@code dimensions} argument is negative.
+     */
+    public static Object newInstance(Class<?> componentType, int... dimensions)
+        throws IllegalArgumentException, NegativeArraySizeException {
+        // Android-changed: New implementation of newInstance(Class, int...)
+        if (dimensions.length <= 0 || dimensions.length > 255) {
+            throw new IllegalArgumentException("Bad number of dimensions: " + dimensions.length);
+        }
+        if (componentType == void.class) {
+            throw new IllegalArgumentException("Can't allocate an array of void");
+        }
+        if (componentType == null) {
+            throw new NullPointerException("componentType == null");
+        }
+        return createMultiArray(componentType, dimensions);
+    }
+
+    /**
+     * Returns the length of the specified array object, as an {@code int}.
+     *
+     * @param array the array
+     * @return the length of the array
+     * @exception IllegalArgumentException if the object argument is not
+     * an array
+     */
+    // Android-changed: Non-native implementation of getLength(Object)
+    // Android-changed: Removal of explicit throws IllegalArgumentException from method signature.
+    public static int getLength(Object array)
+        /* throws IllegalArgumentException */ {
+        if (array instanceof Object[]) {
+            return ((Object[]) array).length;
+        } else if (array instanceof boolean[]) {
+            return ((boolean[]) array).length;
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array).length;
+        } else if (array instanceof char[]) {
+            return ((char[]) array).length;
+        } else if (array instanceof double[]) {
+            return ((double[]) array).length;
+        } else if (array instanceof float[]) {
+            return ((float[]) array).length;
+        } else if (array instanceof int[]) {
+            return ((int[]) array).length;
+        } else if (array instanceof long[]) {
+            return ((long[]) array).length;
+        } else if (array instanceof short[]) {
+            return ((short[]) array).length;
+        }
+        throw badArray(array);
+      }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object.  The value is automatically wrapped in an object
+     * if it has a primitive type.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the (possibly wrapped) value of the indexed component in
+     * the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     */
+    // Android-changed: Non-native implementation of get(Object, int)
+    public static Object get(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof Object[]) {
+            return ((Object[]) array)[index];
+        }
+        if (array instanceof boolean[]) {
+            return ((boolean[]) array)[index] ? Boolean.TRUE : Boolean.FALSE;
+        }
+        if (array instanceof byte[]) {
+            return Byte.valueOf(((byte[]) array)[index]);
+        }
+        if (array instanceof char[]) {
+            return Character.valueOf(((char[]) array)[index]);
+        }
+        if (array instanceof short[]) {
+            return Short.valueOf(((short[]) array)[index]);
+        }
+        if (array instanceof int[]) {
+            return Integer.valueOf(((int[]) array)[index]);
+        }
+        if (array instanceof long[]) {
+            return Long.valueOf(((long[]) array)[index]);
+        }
+        if (array instanceof float[]) {
+            return new Float(((float[]) array)[index]);
+        }
+        if (array instanceof double[]) {
+            return new Double(((double[]) array)[index]);
+        }
+        if (array == null) {
+            throw new NullPointerException("array == null");
+        }
+        throw notAnArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code boolean}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getBoolean(Object, int)
+    public static boolean getBoolean(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof boolean[]) {
+            return ((boolean[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code byte}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getByte(Object, int)
+    public static byte getByte(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof byte[]) {
+            return ((byte[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code char}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getChar(Object, int)
+    public static char getChar(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof char[]) {
+            return ((char[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code short}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getShort(Object, int)
+    public static short getShort(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof short[]) {
+            return ((short[]) array)[index];
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as an {@code int}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getInt(Object, int)
+    public static int getInt(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof int[]) {
+            return ((int[]) array)[index];
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array)[index];
+        } else if (array instanceof char[]) {
+            return ((char[]) array)[index];
+        } else if (array instanceof short[]) {
+            return ((short[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code long}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getLong(Object, int)
+    public static long getLong(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof long[]) {
+            return ((long[]) array)[index];
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array)[index];
+        } else if (array instanceof char[]) {
+            return ((char[]) array)[index];
+        } else if (array instanceof int[]) {
+            return ((int[]) array)[index];
+        } else if (array instanceof short[]) {
+            return ((short[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code float}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getFloat(Object, int)
+    public static float getFloat(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof float[]) {
+            return ((float[]) array)[index];
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array)[index];
+        } else if (array instanceof char[]) {
+            return ((char[]) array)[index];
+        } else if (array instanceof int[]) {
+            return ((int[]) array)[index];
+        } else if (array instanceof long[]) {
+            return ((long[]) array)[index];
+        } else if (array instanceof short[]) {
+            return ((short[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Returns the value of the indexed component in the specified
+     * array object, as a {@code double}.
+     *
+     * @param array the array
+     * @param index the index
+     * @return the value of the indexed component in the specified array
+     * @exception NullPointerException If the specified object is null
+     * @exception IllegalArgumentException If the specified object is not
+     * an array, or if the indexed element cannot be converted to the
+     * return type by an identity or widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to the
+     * length of the specified array
+     * @see Array#get
+     */
+    // Android-changed: Non-native implementation of getDouble(Object, int)
+    public static double getDouble(Object array, int index)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof double[]) {
+            return ((double[]) array)[index];
+        } else if (array instanceof byte[]) {
+            return ((byte[]) array)[index];
+        } else if (array instanceof char[]) {
+            return ((char[]) array)[index];
+        } else if (array instanceof float[]) {
+            return ((float[]) array)[index];
+        } else if (array instanceof int[]) {
+            return ((int[]) array)[index];
+        } else if (array instanceof long[]) {
+            return ((long[]) array)[index];
+        } else if (array instanceof short[]) {
+            return ((short[]) array)[index];
+        }
+        throw badArray(array);
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified new value.  The new value is first
+     * automatically unwrapped if the array has a primitive component
+     * type.
+     * @param array the array
+     * @param index the index into the array
+     * @param value the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the array component type is primitive and
+     * an unwrapping conversion fails
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     */
+    // Android-changed: Non-native implementation of set(Object, int, Object)
+    public static void set(Object array, int index, Object value)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (!array.getClass().isArray()) {
+            throw notAnArray(array);
+        }
+
+        if (array instanceof Object[]) {
+            if (value != null && !array.getClass().getComponentType().isInstance(value)) {
+                throw incompatibleType(array);
+            }
+            ((Object[]) array)[index] = value;
+        } else {
+            if (value == null) {
+                throw new IllegalArgumentException("Primitive array can't take null values.");
+            }
+            if (value instanceof Boolean) {
+                setBoolean(array, index, ((Boolean) value).booleanValue());
+            } else if (value instanceof Byte) {
+                setByte(array, index, ((Byte) value).byteValue());
+            } else if (value instanceof Character) {
+                setChar(array, index, ((Character) value).charValue());
+            } else if (value instanceof Short) {
+                setShort(array, index, ((Short) value).shortValue());
+            } else if (value instanceof Integer) {
+                setInt(array, index, ((Integer) value).intValue());
+            } else if (value instanceof Long) {
+                setLong(array, index, ((Long) value).longValue());
+            } else if (value instanceof Float) {
+                setFloat(array, index, ((Float) value).floatValue());
+            } else if (value instanceof Double) {
+                setDouble(array, index, ((Double) value).doubleValue());
+            }
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code boolean} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param z the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setBoolean(Object, int, boolean)
+    // Android-changed: Removal of explicit runtime exceptions throws clause
+    public static void setBoolean(Object array, int index, boolean z)
+        /* throws IllegalArgumentException, ArrayIndexOutOfBoundsException */ {
+        if (array instanceof boolean[]) {
+            ((boolean[]) array)[index] = z;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code byte} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param b the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setByte(Object, int, byte)
+    public static void setByte(Object array, int index, byte b)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof byte[]) {
+            ((byte[]) array)[index] = b;
+        } else if (array instanceof double[]) {
+            ((double[]) array)[index] = b;
+        } else if (array instanceof float[]) {
+            ((float[]) array)[index] = b;
+        } else if (array instanceof int[]) {
+            ((int[]) array)[index] = b;
+        } else if (array instanceof long[]) {
+            ((long[]) array)[index] = b;
+        } else if (array instanceof short[]) {
+            ((short[]) array)[index] = b;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code char} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param c the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setChar(Object, int, char)
+    public static void setChar(Object array, int index, char c)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof char[]) {
+            ((char[]) array)[index] = c;
+        } else if (array instanceof double[]) {
+            ((double[]) array)[index] = c;
+        } else if (array instanceof float[]) {
+            ((float[]) array)[index] = c;
+        } else if (array instanceof int[]) {
+            ((int[]) array)[index] = c;
+        } else if (array instanceof long[]) {
+            ((long[]) array)[index] = c;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code short} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param s the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setShort(Object, int, short)
+    public static void setShort(Object array, int index, short s)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof short[]) {
+            ((short[]) array)[index] = s;
+        } else if (array instanceof double[]) {
+            ((double[]) array)[index] = s;
+        } else if (array instanceof float[]) {
+            ((float[]) array)[index] = s;
+        } else if (array instanceof int[]) {
+            ((int[]) array)[index] = s;
+        } else if (array instanceof long[]) {
+            ((long[]) array)[index] = s;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code int} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param i the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setInt(Object, int, int)
+    public static void setInt(Object array, int index, int i)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof int[]) {
+            ((int[]) array)[index] = i;
+        } else if (array instanceof double[]) {
+            ((double[]) array)[index] = i;
+        } else if (array instanceof float[]) {
+            ((float[]) array)[index] = i;
+        } else if (array instanceof long[]) {
+            ((long[]) array)[index] = i;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code long} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param l the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setBoolean(Object, int, long)
+    public static void setLong(Object array, int index, long l)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof long[]) {
+            ((long[]) array)[index] = l;
+        } else if (array instanceof double[]) {
+            ((double[]) array)[index] = l;
+        } else if (array instanceof float[]) {
+            ((float[]) array)[index] = l;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code float} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param f the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    public static void setFloat(Object array, int index, float f)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof float[]) {
+            ((float[]) array)[index] = f;
+        } else if (array instanceof double[]) {
+            ((double[]) array)[index] = f;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /**
+     * Sets the value of the indexed component of the specified array
+     * object to the specified {@code double} value.
+     * @param array the array
+     * @param index the index into the array
+     * @param d the new value of the indexed component
+     * @exception NullPointerException If the specified object argument
+     * is null
+     * @exception IllegalArgumentException If the specified object argument
+     * is not an array, or if the specified value cannot be converted
+     * to the underlying array's component type by an identity or a
+     * primitive widening conversion
+     * @exception ArrayIndexOutOfBoundsException If the specified {@code index}
+     * argument is negative, or if it is greater than or equal to
+     * the length of the specified array
+     * @see Array#set
+     */
+    // Android-changed: Non-native implementation of setDouble(Object, int, double)
+    public static void setDouble(Object array, int index, double d)
+        throws IllegalArgumentException, ArrayIndexOutOfBoundsException {
+        if (array instanceof double[]) {
+            ((double[]) array)[index] = d;
+        } else {
+            throw badArray(array);
+        }
+    }
+
+    /*
+     * Private
+     */
+
+    // Android-added: Added javadocs for newArray(Class, int)
+    /**
+     * Returns a new array of the specified component type and length.
+     * Equivalent to {@code new componentType[size]}.
+     *
+     * @throws NullPointerException
+     *             if the component type is null
+     * @throws NegativeArraySizeException
+     *             if {@code size < 0}
+     */
+    // Android-changed: Non-native implementation of newArray(Class, int)
+    private static Object newArray(Class<?> componentType, int length)
+        throws NegativeArraySizeException {
+        if (!componentType.isPrimitive()) {
+            return createObjectArray(componentType, length);
+        } else if (componentType == char.class) {
+            return new char[length];
+        } else if (componentType == int.class) {
+            return new int[length];
+        } else if (componentType == byte.class) {
+            return new byte[length];
+        } else if (componentType == boolean.class) {
+            return new boolean[length];
+        } else if (componentType == short.class) {
+            return new short[length];
+        } else if (componentType == long.class) {
+            return new long[length];
+        } else if (componentType == float.class) {
+            return new float[length];
+        } else if (componentType == double.class) {
+            return new double[length];
+        } else if (componentType == void.class) {
+            throw new IllegalArgumentException("Can't allocate an array of void");
+        }
+        throw new AssertionError();
+    }
+
+    // Android-removed: multiNewArray(Class, int[]) method. createMultiArray used instead.
+    /*
+    private static native Object multiNewArray(Class<?> componentType,
+        int[] dimensions)
+        throws IllegalArgumentException, NegativeArraySizeException;
+    */
+
+    // Android-added: createMultiArray(Class, int[]) method. Used instead of multiNewArray
+    /*
+     * Create a multi-dimensional array of objects with the specified type.
+     */
+    @FastNative
+    private static native Object createMultiArray(Class<?> componentType, int[] dimensions)
+            throws NegativeArraySizeException;
+
+    // BEGIN Android-added: Helper methods to support custom method implementations.
+    /*
+     * Create a one-dimensional array of objects with the specified type.
+     */
+    @FastNative
+    private static native Object createObjectArray(Class<?> componentType, int length)
+            throws NegativeArraySizeException;
+
+    private static IllegalArgumentException notAnArray(Object o) {
+        throw new IllegalArgumentException("Not an array: " + o.getClass());
+    }
+
+    private static IllegalArgumentException incompatibleType(Object o) {
+        throw new IllegalArgumentException("Array has incompatible type: " + o.getClass());
+    }
+
+    private static RuntimeException badArray(Object array) {
+        if (array == null) {
+            throw new NullPointerException("array == null");
+        } else if (!array.getClass().isArray()) {
+            throw notAnArray(array);
+        } else {
+            throw incompatibleType(array);
+        }
+    }
+    // END Android-added: Helper methods to support custom method implementations.
+}
diff --git a/java/lang/reflect/Constructor.annotated.java b/java/lang/reflect/Constructor.annotated.java
new file mode 100644
index 0000000..58bd810
--- /dev/null
+++ b/java/lang/reflect/Constructor.annotated.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Constructor<T> extends java.lang.reflect.Executable {
+
+Constructor() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<T> getDeclaringClass() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public int getModifiers() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Class<?> @libcore.util.NonNull [] getParameterTypes() { throw new RuntimeException("Stub!"); }
+
+public int getParameterCount() { throw new RuntimeException("Stub!"); }
+
+public java.lang.reflect.Type[] getGenericParameterTypes() { throw new RuntimeException("Stub!"); }
+
+public native java.lang.Class<?>[] getExceptionTypes();
+
+public java.lang.reflect.Type[] getGenericExceptionTypes() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toGenericString() { throw new RuntimeException("Stub!"); }
+
[email protected] public T newInstance(java.lang.Object... initargs) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException { throw new RuntimeException("Stub!"); }
+
+public boolean isVarArgs() { throw new RuntimeException("Stub!"); }
+
+public boolean isSynthetic() { throw new RuntimeException("Stub!"); }
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public java.lang.annotation.Annotation[] getDeclaredAnnotations() { throw new RuntimeException("Stub!"); }
+
+public java.lang.annotation.Annotation[][] getParameterAnnotations() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/reflect/Constructor.java b/java/lang/reflect/Constructor.java
new file mode 100644
index 0000000..cf6b29f
--- /dev/null
+++ b/java/lang/reflect/Constructor.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import dalvik.annotation.optimization.FastNative;
+import libcore.util.EmptyArray;
+
+import sun.reflect.CallerSensitive;
+import java.lang.annotation.Annotation;
+import java.util.Comparator;
+
+/**
+ * {@code Constructor} provides information about, and access to, a single
+ * constructor for a class.
+ *
+ * <p>{@code Constructor} permits widening conversions to occur when matching the
+ * actual parameters to newInstance() with the underlying
+ * constructor's formal parameters, but throws an
+ * {@code IllegalArgumentException} if a narrowing conversion would occur.
+ *
+ * @param <T> the class in which the constructor is declared
+ *
+ * @see Member
+ * @see java.lang.Class
+ * @see java.lang.Class#getConstructors()
+ * @see java.lang.Class#getConstructor(Class[])
+ * @see java.lang.Class#getDeclaredConstructors()
+ *
+ * @author      Kenneth Russell
+ * @author      Nakul Saraiya
+ */
+public final class Constructor<T> extends Executable {
+    // Android-changed: Extensive modifications made throughout the class for ART.
+    // Android-changed: Many fields and methods removed / modified.
+    // Android-removed: Type annotations runtime code. Not supported on Android.
+    // Android-removed: Declared vs actual parameter annotation indexes handling.
+
+    private static final Comparator<Method> ORDER_BY_SIGNATURE = null; // Unused; must match Method.
+
+    private final Class<?> serializationClass;
+    private final Class<?> serializationCtor;
+
+    private Constructor() {
+      this(null, null);
+    }
+
+    private Constructor(Class<?> serializationCtor,
+        Class<?> serializationClass) {
+        this.serializationCtor = serializationCtor;
+        this.serializationClass = serializationClass;
+    }
+
+    /**
+     * @hide
+     */
+    public Constructor<T> serializationCopy(Class<?> ctor, Class<?> cl) {
+        return new Constructor<T>(ctor, cl);
+    }
+
+    @Override
+    boolean hasGenericInformation() {
+        // Android-changed: hasGenericInformation() implemented using Executable.
+        return super.hasGenericInformationInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    // Android-changed: getDeclaringClass() implemented using Executable.
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public Class<T> getDeclaringClass() {
+        return (Class<T>) super.getDeclaringClassInternal();
+    }
+
+    /**
+     * Returns the name of this constructor, as a string.  This is
+     * the binary name of the constructor's declaring class.
+     */
+    @Override
+    public String getName() {
+        return getDeclaringClass().getName();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getModifiers() {
+        // Android-changed: getModifiers() implemented using Executable.
+        return super.getModifiersInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws GenericSignatureFormatError {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public TypeVariable<Constructor<T>>[] getTypeParameters() {
+        // Android-changed: getTypeParameters() partly implemented using Executable.
+        GenericInfo info = getMethodOrConstructorGenericInfoInternal();
+        return (TypeVariable<Constructor<T>>[]) info.formalTypeParameters.clone();
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<?>[] getParameterTypes() {
+        // Android-changed: getParameterTypes() partly implemented using Executable.
+        Class<?>[] paramTypes = super.getParameterTypesInternal();
+        if (paramTypes == null) {
+            return EmptyArray.CLASS;
+        }
+
+        return paramTypes;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.8
+     */
+    public int getParameterCount() {
+        // Android-changed: getParameterCount() implemented using Executable.
+        return super.getParameterCountInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws GenericSignatureFormatError {@inheritDoc}
+     * @throws TypeNotPresentException {@inheritDoc}
+     * @throws MalformedParameterizedTypeException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public Type[] getGenericParameterTypes() {
+        return super.getGenericParameterTypes();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    // Android-changed: getExceptionTypes() implemented in native code.
+    @FastNative
+    public native Class<?>[] getExceptionTypes();
+
+    /**
+     * {@inheritDoc}
+     * @throws GenericSignatureFormatError {@inheritDoc}
+     * @throws TypeNotPresentException {@inheritDoc}
+     * @throws MalformedParameterizedTypeException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public Type[] getGenericExceptionTypes() {
+        return super.getGenericExceptionTypes();
+    }
+
+    /**
+     * Compares this {@code Constructor} against the specified object.
+     * Returns true if the objects are the same.  Two {@code Constructor} objects are
+     * the same if they were declared by the same class and have the
+     * same formal parameter types.
+     */
+    public boolean equals(Object obj) {
+        if (obj != null && obj instanceof Constructor) {
+            Constructor<?> other = (Constructor<?>)obj;
+            if (getDeclaringClass() == other.getDeclaringClass()) {
+                // Android-changed: Use getParameterTypes() instead of deleted parameterTypes field
+                return equalParamTypes(getParameterTypes(), other.getParameterTypes());
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hashcode for this {@code Constructor}. The hashcode is
+     * the same as the hashcode for the underlying constructor's
+     * declaring class name.
+     */
+    public int hashCode() {
+        return getDeclaringClass().getName().hashCode();
+    }
+
+    /**
+     * Returns a string describing this {@code Constructor}.  The string is
+     * formatted as the constructor access modifiers, if any,
+     * followed by the fully-qualified name of the declaring class,
+     * followed by a parenthesized, comma-separated list of the
+     * constructor's formal parameter types.  For example:
+     * <pre>
+     *    public java.util.Hashtable(int,float)
+     * </pre>
+     *
+     * <p>The only possible modifiers for constructors are the access
+     * modifiers {@code public}, {@code protected} or
+     * {@code private}.  Only one of these may appear, or none if the
+     * constructor has default (package) access.
+     *
+     * @return a string describing this {@code Constructor}
+     * @jls 8.8.3. Constructor Modifiers
+     */
+    public String toString() {
+        // Android-changed: Use getParameterTypes() / getExceptionTypes() instead of deleted fields
+        return sharedToString(Modifier.constructorModifiers(),
+                              false,
+                              getParameterTypes(),
+                              getExceptionTypes());
+    }
+
+    @Override
+    void specificToStringHeader(StringBuilder sb) {
+        sb.append(getDeclaringClass().getTypeName());
+    }
+
+    /**
+     * Returns a string describing this {@code Constructor},
+     * including type parameters.  The string is formatted as the
+     * constructor access modifiers, if any, followed by an
+     * angle-bracketed comma separated list of the constructor's type
+     * parameters, if any, followed by the fully-qualified name of the
+     * declaring class, followed by a parenthesized, comma-separated
+     * list of the constructor's generic formal parameter types.
+     *
+     * If this constructor was declared to take a variable number of
+     * arguments, instead of denoting the last parameter as
+     * "<tt><i>Type</i>[]</tt>", it is denoted as
+     * "<tt><i>Type</i>...</tt>".
+     *
+     * A space is used to separate access modifiers from one another
+     * and from the type parameters or return type.  If there are no
+     * type parameters, the type parameter list is elided; if the type
+     * parameter list is present, a space separates the list from the
+     * class name.  If the constructor is declared to throw
+     * exceptions, the parameter list is followed by a space, followed
+     * by the word "{@code throws}" followed by a
+     * comma-separated list of the thrown exception types.
+     *
+     * <p>The only possible modifiers for constructors are the access
+     * modifiers {@code public}, {@code protected} or
+     * {@code private}.  Only one of these may appear, or none if the
+     * constructor has default (package) access.
+     *
+     * @return a string describing this {@code Constructor},
+     * include type parameters
+     *
+     * @since 1.5
+     * @jls 8.8.3. Constructor Modifiers
+     */
+    @Override
+    public String toGenericString() {
+        return sharedToGenericString(Modifier.constructorModifiers(), false);
+    }
+
+    @Override
+    void specificToGenericStringHeader(StringBuilder sb) {
+        specificToStringHeader(sb);
+    }
+
+    /**
+     * Uses the constructor represented by this {@code Constructor} object to
+     * create and initialize a new instance of the constructor's
+     * declaring class, with the specified initialization parameters.
+     * Individual parameters are automatically unwrapped to match
+     * primitive formal parameters, and both primitive and reference
+     * parameters are subject to method invocation conversions as necessary.
+     *
+     * <p>If the number of formal parameters required by the underlying constructor
+     * is 0, the supplied {@code initargs} array may be of length 0 or null.
+     *
+     * <p>If the constructor's declaring class is an inner class in a
+     * non-static context, the first argument to the constructor needs
+     * to be the enclosing instance; see section 15.9.3 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     *
+     * <p>If the required access and argument checks succeed and the
+     * instantiation will proceed, the constructor's declaring class
+     * is initialized if it has not already been initialized.
+     *
+     * <p>If the constructor completes normally, returns the newly
+     * created and initialized instance.
+     *
+     * @param initargs array of objects to be passed as arguments to
+     * the constructor call; values of primitive types are wrapped in
+     * a wrapper object of the appropriate type (e.g. a {@code float}
+     * in a {@link java.lang.Float Float})
+     *
+     * @return a new object created by calling the constructor
+     * this object represents
+     *
+     * @exception IllegalAccessException    if this {@code Constructor} object
+     *              is enforcing Java language access control and the underlying
+     *              constructor is inaccessible.
+     * @exception IllegalArgumentException  if the number of actual
+     *              and formal parameters differ; if an unwrapping
+     *              conversion for primitive arguments fails; or if,
+     *              after possible unwrapping, a parameter value
+     *              cannot be converted to the corresponding formal
+     *              parameter type by a method invocation conversion; if
+     *              this constructor pertains to an enum type.
+     * @exception InstantiationException    if the class that declares the
+     *              underlying constructor represents an abstract class.
+     * @exception InvocationTargetException if the underlying constructor
+     *              throws an exception.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     */
+    // BEGIN Android-changed: newInstance(Object...) implemented differently.
+    @CallerSensitive
+    public T newInstance(Object ... initargs)
+        throws InstantiationException, IllegalAccessException,
+               IllegalArgumentException, InvocationTargetException
+    {
+        if (serializationClass == null) {
+            return newInstance0(initargs);
+        } else {
+            return (T) newInstanceFromSerialization(serializationCtor, serializationClass);
+        }
+    }
+
+    @FastNative
+    private static native Object newInstanceFromSerialization(Class<?> ctorClass, Class<?> allocClass)
+        throws InstantiationException, IllegalArgumentException, InvocationTargetException;
+
+    @FastNative
+    private native T newInstance0(Object... args) throws InstantiationException,
+            IllegalAccessException, IllegalArgumentException, InvocationTargetException;
+    // END Android-changed: newInstance(Object...) implemented differently.
+
+    /**
+     * {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public boolean isVarArgs() {
+        return super.isVarArgs();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @jls 13.1 The Form of a Binary
+     * @since 1.5
+     */
+    @Override
+    public boolean isSynthetic() {
+        return super.isSynthetic();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException  {@inheritDoc}
+     * @since 1.5
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        return super.getAnnotation(annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.5
+     */
+    public Annotation[] getDeclaredAnnotations()  {
+        return super.getDeclaredAnnotations();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public Annotation[][] getParameterAnnotations() {
+        // Android-changed: getParameterAnnotations() implemented using Executable.
+        return super.getParameterAnnotationsInternal();
+    }
+}
diff --git a/java/lang/reflect/Executable.annotated.java b/java/lang/reflect/Executable.annotated.java
new file mode 100644
index 0000000..d964aad
--- /dev/null
+++ b/java/lang/reflect/Executable.annotated.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+import java.lang.annotation.Annotation;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Executable extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member, java.lang.reflect.GenericDeclaration {
+
+Executable() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.lang.Class<?> getDeclaringClass();
+
[email protected] public abstract java.lang.String getName();
+
+public abstract int getModifiers();
+
+public abstract [email protected] TypeVariable<?> @libcore.util.NonNull [] getTypeParameters();
+
+public abstract [email protected] Class<?> @libcore.util.NonNull [] getParameterTypes();
+
+public int getParameterCount() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Type @libcore.util.NonNull [] getGenericParameterTypes() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Parameter @libcore.util.NonNull [] getParameters() { throw new RuntimeException("Stub!"); }
+
+public abstract [email protected] Class<?> @libcore.util.NonNull [] getExceptionTypes();
+
+public [email protected] Type @libcore.util.NonNull [] getGenericExceptionTypes() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.lang.String toGenericString();
+
+public boolean isVarArgs() { throw new RuntimeException("Stub!"); }
+
+public boolean isSynthetic() { throw new RuntimeException("Stub!"); }
+
+public abstract [email protected] Annotation @libcore.util.NonNull [] @libcore.util.NonNull [] getParameterAnnotations();
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Annotation @libcore.util.NonNull [] getDeclaredAnnotations() { throw new RuntimeException("Stub!"); }
+
+public final boolean isAnnotationPresent(@libcore.util.NonNull java.lang.Class<? extends java.lang.annotation.Annotation> annotationType) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/reflect/Executable.java b/java/lang/reflect/Executable.java
new file mode 100644
index 0000000..6782d00
--- /dev/null
+++ b/java/lang/reflect/Executable.java
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import dalvik.annotation.optimization.FastNative;
+
+import java.lang.annotation.Annotation;
+import java.util.Objects;
+import libcore.reflect.AnnotatedElements;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.ListOfTypes;
+import libcore.reflect.Types;
+import libcore.util.EmptyArray;
+
+/**
+ * A shared superclass for the common functionality of {@link Method}
+ * and {@link Constructor}.
+ *
+ * @since 1.8
+ */
+public abstract class Executable extends AccessibleObject
+    implements Member, GenericDeclaration {
+
+    // Android-changed: Extensive modifications made throughout the class for ART.
+    // Android-removed: Declared vs actual parameter annotation indexes handling.
+    // Android-removed: Type annotations runtime code. Not supported on Android.
+
+    /*
+     * Only grant package-visibility to the constructor.
+     */
+    Executable() {}
+
+    /**
+     * Does the Executable have generic information.
+     */
+    abstract boolean hasGenericInformation();
+
+    boolean equalParamTypes(Class<?>[] params1, Class<?>[] params2) {
+        /* Avoid unnecessary cloning */
+        if (params1.length == params2.length) {
+            for (int i = 0; i < params1.length; i++) {
+                if (params1[i] != params2[i])
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    void separateWithCommas(Class<?>[] types, StringBuilder sb) {
+        for (int j = 0; j < types.length; j++) {
+            sb.append(types[j].getTypeName());
+            if (j < (types.length - 1))
+                sb.append(",");
+        }
+
+    }
+
+    void printModifiersIfNonzero(StringBuilder sb, int mask, boolean isDefault) {
+        int mod = getModifiers() & mask;
+
+        if (mod != 0 && !isDefault) {
+            sb.append(Modifier.toString(mod)).append(' ');
+        } else {
+            int access_mod = mod & Modifier.ACCESS_MODIFIERS;
+            if (access_mod != 0)
+                sb.append(Modifier.toString(access_mod)).append(' ');
+            if (isDefault)
+                sb.append("default ");
+            mod = (mod & ~Modifier.ACCESS_MODIFIERS);
+            if (mod != 0)
+                sb.append(Modifier.toString(mod)).append(' ');
+        }
+    }
+
+    String sharedToString(int modifierMask,
+                          boolean isDefault,
+                          Class<?>[] parameterTypes,
+                          Class<?>[] exceptionTypes) {
+        try {
+            StringBuilder sb = new StringBuilder();
+
+            printModifiersIfNonzero(sb, modifierMask, isDefault);
+            specificToStringHeader(sb);
+
+            sb.append('(');
+            separateWithCommas(parameterTypes, sb);
+            sb.append(')');
+            if (exceptionTypes.length > 0) {
+                sb.append(" throws ");
+                separateWithCommas(exceptionTypes, sb);
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            return "<" + e + ">";
+        }
+    }
+
+    /**
+     * Generate toString header information specific to a method or
+     * constructor.
+     */
+    abstract void specificToStringHeader(StringBuilder sb);
+
+    String sharedToGenericString(int modifierMask, boolean isDefault) {
+        try {
+            StringBuilder sb = new StringBuilder();
+
+            printModifiersIfNonzero(sb, modifierMask, isDefault);
+
+            TypeVariable<?>[] typeparms = getTypeParameters();
+            if (typeparms.length > 0) {
+                boolean first = true;
+                sb.append('<');
+                for(TypeVariable<?> typeparm: typeparms) {
+                    if (!first)
+                        sb.append(',');
+                    // Class objects can't occur here; no need to test
+                    // and call Class.getName().
+                    sb.append(typeparm.toString());
+                    first = false;
+                }
+                sb.append("> ");
+            }
+
+            specificToGenericStringHeader(sb);
+
+            sb.append('(');
+            Type[] params = getGenericParameterTypes();
+            for (int j = 0; j < params.length; j++) {
+                String param = params[j].getTypeName();
+                if (isVarArgs() && (j == params.length - 1)) // replace T[] with T...
+                    param = param.replaceFirst("\\[\\]$", "...");
+                sb.append(param);
+                if (j < (params.length - 1))
+                    sb.append(',');
+            }
+            sb.append(')');
+            Type[] exceptions = getGenericExceptionTypes();
+            if (exceptions.length > 0) {
+                sb.append(" throws ");
+                for (int k = 0; k < exceptions.length; k++) {
+                    sb.append((exceptions[k] instanceof Class)?
+                              ((Class)exceptions[k]).getName():
+                              exceptions[k].toString());
+                    if (k < (exceptions.length - 1))
+                        sb.append(',');
+                }
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            return "<" + e + ">";
+        }
+    }
+
+    /**
+     * Generate toGenericString header information specific to a
+     * method or constructor.
+     */
+    abstract void specificToGenericStringHeader(StringBuilder sb);
+
+    /**
+     * Returns the {@code Class} object representing the class or interface
+     * that declares the executable represented by this object.
+     */
+    public abstract Class<?> getDeclaringClass();
+
+    /**
+     * Returns the name of the executable represented by this object.
+     */
+    public abstract String getName();
+
+    /**
+     * Returns the Java language {@linkplain Modifier modifiers} for
+     * the executable represented by this object.
+     */
+    public abstract int getModifiers();
+
+    /**
+     * Returns an array of {@code TypeVariable} objects that represent the
+     * type variables declared by the generic declaration represented by this
+     * {@code GenericDeclaration} object, in declaration order.  Returns an
+     * array of length 0 if the underlying generic declaration declares no type
+     * variables.
+     *
+     * @return an array of {@code TypeVariable} objects that represent
+     *     the type variables declared by this generic declaration
+     * @throws GenericSignatureFormatError if the generic
+     *     signature of this generic declaration does not conform to
+     *     the format specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     */
+    public abstract TypeVariable<?>[] getTypeParameters();
+
+    /**
+     * Returns an array of {@code Class} objects that represent the formal
+     * parameter types, in declaration order, of the executable
+     * represented by this object.  Returns an array of length
+     * 0 if the underlying executable takes no parameters.
+     *
+     * @return the parameter types for the executable this object
+     * represents
+     */
+    public abstract Class<?>[] getParameterTypes();
+
+    /**
+     * Returns the number of formal parameters (whether explicitly
+     * declared or implicitly declared or neither) for the executable
+     * represented by this object.
+     *
+     * @return The number of formal parameters for the executable this
+     * object represents
+     */
+    public int getParameterCount() {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Returns an array of {@code Type} objects that represent the formal
+     * parameter types, in declaration order, of the executable represented by
+     * this object. Returns an array of length 0 if the
+     * underlying executable takes no parameters.
+     *
+     * <p>If a formal parameter type is a parameterized type,
+     * the {@code Type} object returned for it must accurately reflect
+     * the actual type parameters used in the source code.
+     *
+     * <p>If a formal parameter type is a type variable or a parameterized
+     * type, it is created. Otherwise, it is resolved.
+     *
+     * @return an array of {@code Type}s that represent the formal
+     *     parameter types of the underlying executable, in declaration order
+     * @throws GenericSignatureFormatError
+     *     if the generic method signature does not conform to the format
+     *     specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if any of the parameter
+     *     types of the underlying executable refers to a non-existent type
+     *     declaration
+     * @throws MalformedParameterizedTypeException if any of
+     *     the underlying executable's parameter types refer to a parameterized
+     *     type that cannot be instantiated for any reason
+     */
+    public Type[] getGenericParameterTypes() {
+        // Android-changed: getGenericParameterTypes() implementation for use with ART.
+        return Types.getTypeArray(
+                getMethodOrConstructorGenericInfoInternal().genericParameterTypes, false);
+    }
+
+    /**
+     * Behaves like {@code getGenericParameterTypes}, but returns type
+     * information for all parameters, including synthetic parameters.
+     */
+    Type[] getAllGenericParameterTypes() {
+        final boolean genericInfo = hasGenericInformation();
+
+        // Easy case: we don't have generic parameter information.  In
+        // this case, we just return the result of
+        // getParameterTypes().
+        if (!genericInfo) {
+            return getParameterTypes();
+        } else {
+            final boolean realParamData = hasRealParameterData();
+            final Type[] genericParamTypes = getGenericParameterTypes();
+            final Type[] nonGenericParamTypes = getParameterTypes();
+            final Type[] out = new Type[nonGenericParamTypes.length];
+            final Parameter[] params = getParameters();
+            int fromidx = 0;
+            // If we have real parameter data, then we use the
+            // synthetic and mandate flags to our advantage.
+            if (realParamData) {
+                for (int i = 0; i < out.length; i++) {
+                    final Parameter param = params[i];
+                    if (param.isSynthetic() || param.isImplicit()) {
+                        // If we hit a synthetic or mandated parameter,
+                        // use the non generic parameter info.
+                        out[i] = nonGenericParamTypes[i];
+                    } else {
+                        // Otherwise, use the generic parameter info.
+                        out[i] = genericParamTypes[fromidx];
+                        fromidx++;
+                    }
+                }
+            } else {
+                // Otherwise, use the non-generic parameter data.
+                // Without method parameter reflection data, we have
+                // no way to figure out which parameters are
+                // synthetic/mandated, thus, no way to match up the
+                // indexes.
+                return genericParamTypes.length == nonGenericParamTypes.length ?
+                    genericParamTypes : nonGenericParamTypes;
+            }
+            return out;
+        }
+    }
+
+    /**
+     * Returns an array of {@code Parameter} objects that represent
+     * all the parameters to the underlying executable represented by
+     * this object.  Returns an array of length 0 if the executable
+     * has no parameters.
+     *
+     * <p>The parameters of the underlying executable do not necessarily
+     * have unique names, or names that are legal identifiers in the
+     * Java programming language (JLS 3.8).
+     *
+     * @throws MalformedParametersException if the class file contains
+     * a MethodParameters attribute that is improperly formatted.
+     * @return an array of {@code Parameter} objects representing all
+     * the parameters to the executable this object represents.
+     */
+    public Parameter[] getParameters() {
+        // TODO: This may eventually need to be guarded by security
+        // mechanisms similar to those in Field, Method, etc.
+        //
+        // Need to copy the cached array to prevent users from messing
+        // with it.  Since parameters are immutable, we can
+        // shallow-copy.
+        return privateGetParameters().clone();
+    }
+
+    private Parameter[] synthesizeAllParams() {
+        final int realparams = getParameterCount();
+        final Parameter[] out = new Parameter[realparams];
+        for (int i = 0; i < realparams; i++)
+            // TODO: is there a way to synthetically derive the
+            // modifiers?  Probably not in the general case, since
+            // we'd have no way of knowing about them, but there
+            // may be specific cases.
+            out[i] = new Parameter("arg" + i, 0, this, i);
+        return out;
+    }
+
+    private void verifyParameters(final Parameter[] parameters) {
+        final int mask = Modifier.FINAL | Modifier.SYNTHETIC | Modifier.MANDATED;
+
+        if (getParameterTypes().length != parameters.length)
+            throw new MalformedParametersException("Wrong number of parameters in MethodParameters attribute");
+
+        for (Parameter parameter : parameters) {
+            final String name = parameter.getRealName();
+            final int mods = parameter.getModifiers();
+
+            if (name != null) {
+                if (name.isEmpty() || name.indexOf('.') != -1 ||
+                    name.indexOf(';') != -1 || name.indexOf('[') != -1 ||
+                    name.indexOf('/') != -1) {
+                    throw new MalformedParametersException("Invalid parameter name \"" + name + "\"");
+                }
+            }
+
+            if (mods != (mods & mask)) {
+                throw new MalformedParametersException("Invalid parameter modifiers");
+            }
+        }
+    }
+
+    private Parameter[] privateGetParameters() {
+        // Use tmp to avoid multiple writes to a volatile.
+        Parameter[] tmp = parameters;
+
+        if (tmp == null) {
+
+            // Otherwise, go to the JVM to get them
+            try {
+                tmp = getParameters0();
+            } catch(IllegalArgumentException e) {
+                // Rethrow ClassFormatErrors
+                // Android-changed: Exception changed to be more descriptive.
+                MalformedParametersException e2 =
+                        new MalformedParametersException(
+                                "Invalid parameter metadata in class file");
+                e2.initCause(e);
+                throw e2;
+            }
+
+            // If we get back nothing, then synthesize parameters
+            if (tmp == null) {
+                hasRealParameterData = false;
+                tmp = synthesizeAllParams();
+            } else {
+                hasRealParameterData = true;
+                verifyParameters(tmp);
+            }
+
+            parameters = tmp;
+        }
+
+        return tmp;
+    }
+
+    boolean hasRealParameterData() {
+        // If this somehow gets called before parameters gets
+        // initialized, force it into existence.
+        if (parameters == null) {
+            privateGetParameters();
+        }
+        return hasRealParameterData;
+    }
+
+    private transient volatile boolean hasRealParameterData;
+    private transient volatile Parameter[] parameters;
+
+    // Android-changed: Added @FastNative to getParameters0()
+    @FastNative
+    private native Parameter[] getParameters0();
+
+    /**
+     * Returns an array of {@code Class} objects that represent the
+     * types of exceptions declared to be thrown by the underlying
+     * executable represented by this object.  Returns an array of
+     * length 0 if the executable declares no exceptions in its {@code
+     * throws} clause.
+     *
+     * @return the exception types declared as being thrown by the
+     * executable this object represents
+     */
+    public abstract Class<?>[] getExceptionTypes();
+
+    /**
+     * Returns an array of {@code Type} objects that represent the
+     * exceptions declared to be thrown by this executable object.
+     * Returns an array of length 0 if the underlying executable declares
+     * no exceptions in its {@code throws} clause.
+     *
+     * <p>If an exception type is a type variable or a parameterized
+     * type, it is created. Otherwise, it is resolved.
+     *
+     * @return an array of Types that represent the exception types
+     *     thrown by the underlying executable
+     * @throws GenericSignatureFormatError
+     *     if the generic method signature does not conform to the format
+     *     specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if the underlying executable's
+     *     {@code throws} clause refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if
+     *     the underlying executable's {@code throws} clause refers to a
+     *     parameterized type that cannot be instantiated for any reason
+     */
+    public Type[] getGenericExceptionTypes() {
+        // Android-changed: getGenericExceptionTypes() implementation for use with ART.
+        return Types.getTypeArray(
+                getMethodOrConstructorGenericInfoInternal().genericExceptionTypes, false);
+    }
+
+    /**
+     * Returns a string describing this {@code Executable}, including
+     * any type parameters.
+     * @return a string describing this {@code Executable}, including
+     * any type parameters
+     */
+    public abstract String toGenericString();
+
+    /**
+     * Returns {@code true} if this executable was declared to take a
+     * variable number of arguments; returns {@code false} otherwise.
+     *
+     * @return {@code true} if an only if this executable was declared
+     * to take a variable number of arguments.
+     */
+    public boolean isVarArgs()  {
+        // Android-changed: isVarArgs() made slightly more efficient.
+        return (accessFlags & Modifier.VARARGS) != 0;
+    }
+
+    /**
+     * Returns {@code true} if this executable is a synthetic
+     * construct; returns {@code false} otherwise.
+     *
+     * @return true if and only if this executable is a synthetic
+     * construct as defined by
+     * <cite>The Java&trade; Language Specification</cite>.
+     * @jls 13.1 The Form of a Binary
+     */
+    public boolean isSynthetic() {
+        // Android-changed: isSynthetic() made slightly more efficient.
+        return (accessFlags & Modifier.SYNTHETIC) != 0;
+    }
+
+    /**
+     * Returns an array of arrays of {@code Annotation}s that
+     * represent the annotations on the formal parameters, in
+     * declaration order, of the {@code Executable} represented by
+     * this object.  Synthetic and mandated parameters (see
+     * explanation below), such as the outer "this" parameter to an
+     * inner class constructor will be represented in the returned
+     * array.  If the executable has no parameters (meaning no formal,
+     * no synthetic, and no mandated parameters), a zero-length array
+     * will be returned.  If the {@code Executable} has one or more
+     * parameters, a nested array of length zero is returned for each
+     * parameter with no annotations. The annotation objects contained
+     * in the returned arrays are serializable.  The caller of this
+     * method is free to modify the returned arrays; it will have no
+     * effect on the arrays returned to other callers.
+     *
+     * A compiler may add extra parameters that are implicitly
+     * declared in source ("mandated"), as well as parameters that
+     * are neither implicitly nor explicitly declared in source
+     * ("synthetic") to the parameter list for a method.  See {@link
+     * java.lang.reflect.Parameter} for more information.
+     *
+     * @see java.lang.reflect.Parameter
+     * @see java.lang.reflect.Parameter#getAnnotations
+     * @return an array of arrays that represent the annotations on
+     *    the formal and implicit parameters, in declaration order, of
+     *    the executable represented by this object
+     */
+    public abstract Annotation[][] getParameterAnnotations();
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException  {@inheritDoc}
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+        // Android-changed: Implemented getAnnotation(Class) natively.
+        return getAnnotationNative(annotationClass);
+    }
+
+    // Android-changed: Implemented getAnnotation(Class) natively.
+    @FastNative
+    private native <T extends Annotation> T getAnnotationNative(Class<T> annotationClass);
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+        // Android-changed: getAnnotationsByType(Class), Android uses AnnotatedElements instead.
+        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Annotation[] getDeclaredAnnotations()  {
+        // Android-changed: Implemented getDeclaredAnnotations() natively.
+        return getDeclaredAnnotationsNative();
+    }
+
+    // Android-added: Implemented getDeclaredAnnotations() natively.
+    @FastNative
+    private native Annotation[] getDeclaredAnnotationsNative();
+
+    // BEGIN Android-added: Additional ART-related fields and logic.
+    // This code is shared for Method and Constructor.
+
+    /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
+    @SuppressWarnings("unused") // set by runtime
+    private int accessFlags;
+
+    /**
+     * The ArtMethod associated with this Executable, required for dispatching due to entrypoints
+     * Classloader is held live by the declaring class.
+     */
+    @SuppressWarnings("unused") // set by runtime
+    private long artMethod;
+
+    /** Executable's declaring class */
+    @SuppressWarnings("unused") // set by runtime
+    private Class<?> declaringClass;
+
+    /**
+     * Overriden method's declaring class (same as declaringClass unless declaringClass is a proxy
+     * class).
+     */
+    @SuppressWarnings("unused") // set by runtime
+    private Class<?> declaringClassOfOverriddenMethod;
+
+    /** The method index of this method within its defining dex file */
+    @SuppressWarnings("unused") // set by runtime
+    private int dexMethodIndex;
+
+    /**
+     * We insert native method stubs for abstract methods so we don't have to
+     * check the access flags at the time of the method call.  This results in
+     * "native abstract" methods, which can't exist.  If we see the "abstract"
+     * flag set, clear the "native" flag.
+     *
+     * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
+     * position, because the callers of this function are trying to convey
+     * the "traditional" meaning of the flags to their callers.
+     */
+    private static int fixMethodFlags(int flags) {
+        if ((flags & Modifier.ABSTRACT) != 0) {
+            flags &= ~Modifier.NATIVE;
+        }
+        flags &= ~Modifier.SYNCHRONIZED;
+        int ACC_DECLARED_SYNCHRONIZED = 0x00020000;
+        if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
+            flags |= Modifier.SYNCHRONIZED;
+        }
+        return flags & 0xffff;  // mask out bits not used by Java
+    }
+
+    final int getModifiersInternal() {
+        return fixMethodFlags(accessFlags);
+    }
+
+    final Class<?> getDeclaringClassInternal() {
+        return declaringClass;
+    }
+
+    /**
+     * Returns an array of {@code Class} objects associated with the parameter types of this
+     * Executable. If the Executable was declared with no parameters, {@code null} will be
+     * returned.
+     *
+     * @return the parameter types, or {@code null} if no parameters were declared.
+     */
+    @FastNative
+    final native Class<?>[] getParameterTypesInternal();
+
+    @FastNative
+    final native int getParameterCountInternal();
+
+    // Android provides a more efficient implementation of this method for Executable than the one
+    // implemented in AnnotatedElement.
+    @Override
+    public final boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        Objects.requireNonNull(annotationType);
+        return isAnnotationPresentNative(annotationType);
+    }
+    @FastNative
+    private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
+
+    final Annotation[][] getParameterAnnotationsInternal() {
+        Annotation[][] parameterAnnotations = getParameterAnnotationsNative();
+        if (parameterAnnotations == null) {
+            parameterAnnotations = new Annotation[getParameterTypes().length][0];
+        }
+        return parameterAnnotations;
+    }
+    @FastNative
+    private native Annotation[][] getParameterAnnotationsNative();
+
+    /**
+     * @hide - exposed for use by {@link Class}.
+     */
+    public final int getAccessFlags() {
+        return accessFlags;
+    }
+
+    /**
+     * @hide - exposed for use by {@code java.lang.invoke.*}.
+     */
+    public final long getArtMethod() {
+        return artMethod;
+    }
+
+    static final class GenericInfo {
+        final ListOfTypes genericExceptionTypes;
+        final ListOfTypes genericParameterTypes;
+        final Type genericReturnType;
+        final TypeVariable<?>[] formalTypeParameters;
+
+        GenericInfo(ListOfTypes exceptions, ListOfTypes parameters, Type ret,
+                TypeVariable<?>[] formal) {
+            genericExceptionTypes = exceptions;
+            genericParameterTypes = parameters;
+            genericReturnType = ret;
+            formalTypeParameters = formal;
+        }
+    }
+
+    final boolean hasGenericInformationInternal() {
+        return getSignatureAnnotation() != null;
+    }
+
+    /**
+     * Returns generic information associated with this method/constructor member.
+     */
+    final GenericInfo getMethodOrConstructorGenericInfoInternal() {
+        String signatureAttribute = getSignatureAttribute();
+        Class<?>[] exceptionTypes = this.getExceptionTypes();
+        GenericSignatureParser parser =
+                new GenericSignatureParser(this.getDeclaringClass().getClassLoader());
+        if (this instanceof Method) {
+            parser.parseForMethod(this, signatureAttribute, exceptionTypes);
+        } else {
+            parser.parseForConstructor(this, signatureAttribute, exceptionTypes);
+        }
+        return new GenericInfo(parser.exceptionTypes, parser.parameterTypes,
+                parser.returnType, parser.formalTypeParameters);
+    }
+
+    private String getSignatureAttribute() {
+        String[] annotation = getSignatureAnnotation();
+        if (annotation == null) {
+            return null;
+        }
+        StringBuilder result = new StringBuilder();
+        for (String s : annotation) {
+            result.append(s);
+        }
+        return result.toString();
+    }
+    @FastNative
+    private native String[] getSignatureAnnotation();
+
+    final boolean equalNameAndParametersInternal(Method m) {
+        return getName().equals(m.getName()) && (compareMethodParametersInternal(m) == 0);
+    }
+
+    @FastNative
+    native int compareMethodParametersInternal(Method meth);
+
+    @FastNative
+    final native String getMethodNameInternal();
+
+    @FastNative
+    final native Class<?> getMethodReturnTypeInternal();
+
+    /** A cheap implementation for {@link Method#isDefault()}. */
+    final boolean isDefaultMethodInternal() {
+        return (accessFlags & Modifier.DEFAULT) != 0;
+    }
+
+    /** A cheap implementation for {@link Method#isBridge()}. */
+    final boolean isBridgeMethodInternal() {
+        return (accessFlags & Modifier.BRIDGE) != 0;
+    }
+    // END Android-added: Additional ART-related fields and logic.
+
+}
diff --git a/java/lang/reflect/Field.annotated.java b/java/lang/reflect/Field.annotated.java
new file mode 100644
index 0000000..8a26ce3
--- /dev/null
+++ b/java/lang/reflect/Field.annotated.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Field extends java.lang.reflect.AccessibleObject implements java.lang.reflect.Member {
+
+Field() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<?> getDeclaringClass() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public int getModifiers() { throw new RuntimeException("Stub!"); }
+
+public boolean isEnumConstant() { throw new RuntimeException("Stub!"); }
+
+public boolean isSynthetic() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<?> getType() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.reflect.Type getGenericType() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toGenericString() { throw new RuntimeException("Stub!"); }
+
[email protected] public native java.lang.Object get(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native boolean getBoolean(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native byte getByte(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native char getChar(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native short getShort(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native int getInt(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native long getLong(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native float getFloat(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native double getDouble(@libcore.util.Nullable java.lang.Object obj) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void set(@libcore.util.Nullable java.lang.Object obj, @libcore.util.Nullable java.lang.Object value) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setBoolean(@libcore.util.Nullable java.lang.Object obj, boolean z) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setByte(@libcore.util.Nullable java.lang.Object obj, byte b) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setChar(@libcore.util.Nullable java.lang.Object obj, char c) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setShort(@libcore.util.Nullable java.lang.Object obj, short s) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setInt(@libcore.util.Nullable java.lang.Object obj, int i) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setLong(@libcore.util.Nullable java.lang.Object obj, long l) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setFloat(@libcore.util.Nullable java.lang.Object obj, float f) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
+public native void setDouble(@libcore.util.Nullable java.lang.Object obj, double d) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException;
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public boolean isAnnotationPresent(@libcore.util.NonNull java.lang.Class<? extends java.lang.annotation.Annotation> annotationType) { throw new RuntimeException("Stub!"); }
+
+public native java.lang.annotation.Annotation[] getDeclaredAnnotations();
+}
diff --git a/java/lang/reflect/Field.java b/java/lang/reflect/Field.java
new file mode 100644
index 0000000..ca5857a
--- /dev/null
+++ b/java/lang/reflect/Field.java
@@ -0,0 +1,950 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import dalvik.annotation.optimization.FastNative;
+import sun.reflect.CallerSensitive;
+import java.lang.annotation.Annotation;
+import java.util.Objects;
+import libcore.reflect.AnnotatedElements;
+import libcore.reflect.GenericSignatureParser;
+
+
+/**
+ * A {@code Field} provides information about, and dynamic access to, a
+ * single field of a class or an interface.  The reflected field may
+ * be a class (static) field or an instance field.
+ *
+ * <p>A {@code Field} permits widening conversions to occur during a get or
+ * set access operation, but throws an {@code IllegalArgumentException} if a
+ * narrowing conversion would occur.
+ *
+ * @see Member
+ * @see java.lang.Class
+ * @see java.lang.Class#getFields()
+ * @see java.lang.Class#getField(String)
+ * @see java.lang.Class#getDeclaredFields()
+ * @see java.lang.Class#getDeclaredField(String)
+ *
+ * @author Kenneth Russell
+ * @author Nakul Saraiya
+ */
+public final
+class Field extends AccessibleObject implements Member {
+    // Android-changed: Extensive modifications made throughout the class for ART.
+    // Android-changed: Many fields and methods removed / modified.
+    // Android-removed: Type annotations runtime code. Not supported on Android.
+
+    private int accessFlags;
+    private Class<?> declaringClass;
+    private int artFieldIndex;
+    private int offset;
+    private Class<?> type;
+
+    private Field() {
+    }
+
+    /**
+     * Returns the {@code Class} object representing the class or interface
+     * that declares the field represented by this {@code Field} object.
+     */
+    public Class<?> getDeclaringClass() {
+        // Android-changed: Adjust code for different field names.
+        return declaringClass;
+    }
+
+    /**
+     * Returns the name of the field represented by this {@code Field} object.
+     */
+    public String getName() {
+        // Android-changed: getName() implemented differently.
+        if (declaringClass.isProxy()) {
+            // Proxy classes have 1 synthesized static field with no valid dex index.
+            if ((getModifiers() & Modifier.STATIC) == 0) {
+                throw new AssertionError("Invalid modifiers for proxy field: " + getModifiers());
+            }
+            // Only 2 fields are present on proxy classes.
+            switch (artFieldIndex) {
+                case 0: return "interfaces";
+                case 1: return "throws";
+                default: throw new AssertionError("Invalid index for proxy: " + artFieldIndex);
+            }
+        }
+
+        return getNameInternal();
+    }
+
+    // Android-added: getName() implemented differently.
+    @FastNative
+    private native String getNameInternal();
+
+    /**
+     * Returns the Java language modifiers for the field represented
+     * by this {@code Field} object, as an integer. The {@code Modifier} class should
+     * be used to decode the modifiers.
+     *
+     * @see Modifier
+     */
+    public int getModifiers() {
+        // Android-changed: Adjust getModifiers() implementation to mask extra bits used on Android.
+        return accessFlags & 0xffff;  // mask out bits not used by Java
+    }
+
+    /**
+     * Returns {@code true} if this field represents an element of
+     * an enumerated type; returns {@code false} otherwise.
+     *
+     * @return {@code true} if and only if this field represents an element of
+     * an enumerated type.
+     * @since 1.5
+     */
+    public boolean isEnumConstant() {
+        return (getModifiers() & Modifier.ENUM) != 0;
+    }
+
+    /**
+     * Returns {@code true} if this field is a synthetic
+     * field; returns {@code false} otherwise.
+     *
+     * @return true if and only if this field is a synthetic
+     * field as defined by the Java Language Specification.
+     * @since 1.5
+     */
+    public boolean isSynthetic() {
+        return Modifier.isSynthetic(getModifiers());
+    }
+
+    /**
+     * Returns a {@code Class} object that identifies the
+     * declared type for the field represented by this
+     * {@code Field} object.
+     *
+     * @return a {@code Class} object identifying the declared
+     * type of the field represented by this object
+     */
+    public Class<?> getType() {
+        return type;
+    }
+
+    /**
+     * Returns a {@code Type} object that represents the declared type for
+     * the field represented by this {@code Field} object.
+     *
+     * <p>If the {@code Type} is a parameterized type, the
+     * {@code Type} object returned must accurately reflect the
+     * actual type parameters used in the source code.
+     *
+     * <p>If the type of the underlying field is a type variable or a
+     * parameterized type, it is created. Otherwise, it is resolved.
+     *
+     * @return a {@code Type} object that represents the declared type for
+     *     the field represented by this {@code Field} object
+     * @throws GenericSignatureFormatError if the generic field
+     *     signature does not conform to the format specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if the generic type
+     *     signature of the underlying field refers to a non-existent
+     *     type declaration
+     * @throws MalformedParameterizedTypeException if the generic
+     *     signature of the underlying field refers to a parameterized type
+     *     that cannot be instantiated for any reason
+     * @since 1.5
+     */
+    public Type getGenericType() {
+        // Android-changed: getGenericType() implemented differently.
+        String signatureAttribute = getSignatureAttribute();
+        ClassLoader cl = declaringClass.getClassLoader();
+        GenericSignatureParser parser = new GenericSignatureParser(cl);
+        parser.parseForField(declaringClass, signatureAttribute);
+        Type genericType = parser.fieldType;
+        if (genericType == null) {
+            genericType = getType();
+        }
+        return genericType;
+    }
+
+    // BEGIN Android-added: getGenericType() implemented differently.
+    private String getSignatureAttribute() {
+        String[] annotation = getSignatureAnnotation();
+        if (annotation == null) {
+            return null;
+        }
+        StringBuilder result = new StringBuilder();
+        for (String s : annotation) {
+            result.append(s);
+        }
+        return result.toString();
+    }
+    @FastNative
+    private native String[] getSignatureAnnotation();
+    // END Android-added: getGenericType() implemented differently.
+
+
+    /**
+     * Compares this {@code Field} against the specified object.  Returns
+     * true if the objects are the same.  Two {@code Field} objects are the same if
+     * they were declared by the same class and have the same name
+     * and type.
+     */
+    public boolean equals(Object obj) {
+        if (obj != null && obj instanceof Field) {
+            Field other = (Field)obj;
+            return (getDeclaringClass() == other.getDeclaringClass())
+                && (getName() == other.getName())
+                && (getType() == other.getType());
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hashcode for this {@code Field}.  This is computed as the
+     * exclusive-or of the hashcodes for the underlying field's
+     * declaring class name and its name.
+     */
+    public int hashCode() {
+        return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
+    }
+
+    /**
+     * Returns a string describing this {@code Field}.  The format is
+     * the access modifiers for the field, if any, followed
+     * by the field type, followed by a space, followed by
+     * the fully-qualified name of the class declaring the field,
+     * followed by a period, followed by the name of the field.
+     * For example:
+     * <pre>
+     *    public static final int java.lang.Thread.MIN_PRIORITY
+     *    private int java.io.FileDescriptor.fd
+     * </pre>
+     *
+     * <p>The modifiers are placed in canonical order as specified by
+     * "The Java Language Specification".  This is {@code public},
+     * {@code protected} or {@code private} first, and then other
+     * modifiers in the following order: {@code static}, {@code final},
+     * {@code transient}, {@code volatile}.
+     *
+     * @return a string describing this {@code Field}
+     * @jls 8.3.1 Field Modifiers
+     */
+    public String toString() {
+        int mod = getModifiers();
+        return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
+            + getType().getTypeName() + " "
+            + getDeclaringClass().getTypeName() + "."
+            + getName());
+    }
+
+    /**
+     * Returns a string describing this {@code Field}, including
+     * its generic type.  The format is the access modifiers for the
+     * field, if any, followed by the generic field type, followed by
+     * a space, followed by the fully-qualified name of the class
+     * declaring the field, followed by a period, followed by the name
+     * of the field.
+     *
+     * <p>The modifiers are placed in canonical order as specified by
+     * "The Java Language Specification".  This is {@code public},
+     * {@code protected} or {@code private} first, and then other
+     * modifiers in the following order: {@code static}, {@code final},
+     * {@code transient}, {@code volatile}.
+     *
+     * @return a string describing this {@code Field}, including
+     * its generic type
+     *
+     * @since 1.5
+     * @jls 8.3.1 Field Modifiers
+     */
+    public String toGenericString() {
+        int mod = getModifiers();
+        Type fieldType = getGenericType();
+        return (((mod == 0) ? "" : (Modifier.toString(mod) + " "))
+            + fieldType.getTypeName() + " "
+            + getDeclaringClass().getTypeName() + "."
+            + getName());
+    }
+
+    /**
+     * Returns the value of the field represented by this {@code Field}, on
+     * the specified object. The value is automatically wrapped in an
+     * object if it has a primitive type.
+     *
+     * <p>The underlying field's value is obtained as follows:
+     *
+     * <p>If the underlying field is a static field, the {@code obj} argument
+     * is ignored; it may be null.
+     *
+     * <p>Otherwise, the underlying field is an instance field.  If the
+     * specified {@code obj} argument is null, the method throws a
+     * {@code NullPointerException}. If the specified object is not an
+     * instance of the class or interface declaring the underlying
+     * field, the method throws an {@code IllegalArgumentException}.
+     *
+     * <p>If this {@code Field} object is enforcing Java language access control, and
+     * the underlying field is inaccessible, the method throws an
+     * {@code IllegalAccessException}.
+     * If the underlying field is static, the class that declared the
+     * field is initialized if it has not already been initialized.
+     *
+     * <p>Otherwise, the value is retrieved from the underlying instance
+     * or static field.  If the field has a primitive type, the value
+     * is wrapped in an object before being returned, otherwise it is
+     * returned as is.
+     *
+     * <p>If the field is hidden in the type of {@code obj},
+     * the field's value is obtained according to the preceding rules.
+     *
+     * @param obj object from which the represented field's value is
+     * to be extracted
+     * @return the value of the represented field in object
+     * {@code obj}; primitive values are wrapped in an appropriate
+     * object before being returned
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof).
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native Object get(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance {@code boolean} field.
+     *
+     * @param obj the object to extract the {@code boolean} value
+     * from
+     * @return the value of the {@code boolean} field
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code boolean} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native boolean getBoolean(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance {@code byte} field.
+     *
+     * @param obj the object to extract the {@code byte} value
+     * from
+     * @return the value of the {@code byte} field
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code byte} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native byte getByte(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance field of type
+     * {@code char} or of another primitive type convertible to
+     * type {@code char} via a widening conversion.
+     *
+     * @param obj the object to extract the {@code char} value
+     * from
+     * @return the value of the field converted to type {@code char}
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code char} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native char getChar(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance field of type
+     * {@code short} or of another primitive type convertible to
+     * type {@code short} via a widening conversion.
+     *
+     * @param obj the object to extract the {@code short} value
+     * from
+     * @return the value of the field converted to type {@code short}
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code short} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native short getShort(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance field of type
+     * {@code int} or of another primitive type convertible to
+     * type {@code int} via a widening conversion.
+     *
+     * @param obj the object to extract the {@code int} value
+     * from
+     * @return the value of the field converted to type {@code int}
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code int} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native int getInt(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance field of type
+     * {@code long} or of another primitive type convertible to
+     * type {@code long} via a widening conversion.
+     *
+     * @param obj the object to extract the {@code long} value
+     * from
+     * @return the value of the field converted to type {@code long}
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code long} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native long getLong(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance field of type
+     * {@code float} or of another primitive type convertible to
+     * type {@code float} via a widening conversion.
+     *
+     * @param obj the object to extract the {@code float} value
+     * from
+     * @return the value of the field converted to type {@code float}
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code float} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native float getFloat(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Gets the value of a static or instance field of type
+     * {@code double} or of another primitive type convertible to
+     * type {@code double} via a widening conversion.
+     *
+     * @param obj the object to extract the {@code double} value
+     * from
+     * @return the value of the field converted to type {@code double}
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is inaccessible.
+     * @exception IllegalArgumentException  if the specified object is not
+     *              an instance of the class or interface declaring the
+     *              underlying field (or a subclass or implementor
+     *              thereof), or if the field value cannot be
+     *              converted to the type {@code double} by a
+     *              widening conversion.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#get
+     */
+    @CallerSensitive
+    // Android-changed: get*(Object) implemented natively.
+    @FastNative
+    public native double getDouble(Object obj)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the field represented by this {@code Field} object on the
+     * specified object argument to the specified new value. The new
+     * value is automatically unwrapped if the underlying field has a
+     * primitive type.
+     *
+     * <p>The operation proceeds as follows:
+     *
+     * <p>If the underlying field is static, the {@code obj} argument is
+     * ignored; it may be null.
+     *
+     * <p>Otherwise the underlying field is an instance field.  If the
+     * specified object argument is null, the method throws a
+     * {@code NullPointerException}.  If the specified object argument is not
+     * an instance of the class or interface declaring the underlying
+     * field, the method throws an {@code IllegalArgumentException}.
+     *
+     * <p>If this {@code Field} object is enforcing Java language access control, and
+     * the underlying field is inaccessible, the method throws an
+     * {@code IllegalAccessException}.
+     *
+     * <p>If the underlying field is final, the method throws an
+     * {@code IllegalAccessException} unless {@code setAccessible(true)}
+     * has succeeded for this {@code Field} object
+     * and the field is non-static. Setting a final field in this way
+     * is meaningful only during deserialization or reconstruction of
+     * instances of classes with blank final fields, before they are
+     * made available for access by other parts of a program. Use in
+     * any other context may have unpredictable effects, including cases
+     * in which other parts of a program continue to use the original
+     * value of this field.
+     *
+     * <p>If the underlying field is of a primitive type, an unwrapping
+     * conversion is attempted to convert the new value to a value of
+     * a primitive type.  If this attempt fails, the method throws an
+     * {@code IllegalArgumentException}.
+     *
+     * <p>If, after possible unwrapping, the new value cannot be
+     * converted to the type of the underlying field by an identity or
+     * widening conversion, the method throws an
+     * {@code IllegalArgumentException}.
+     *
+     * <p>If the underlying field is static, the class that declared the
+     * field is initialized if it has not already been initialized.
+     *
+     * <p>The field is set to the possibly unwrapped and widened new value.
+     *
+     * <p>If the field is hidden in the type of {@code obj},
+     * the field's value is set according to the preceding rules.
+     *
+     * @param obj the object whose field should be modified
+     * @param value the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void set(Object obj, Object value)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code boolean} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, zObj)},
+     * where {@code zObj} is a {@code Boolean} object and
+     * {@code zObj.booleanValue() == z}.
+     *
+     * @param obj the object whose field should be modified
+     * @param z   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setBoolean(Object obj, boolean z)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code byte} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, bObj)},
+     * where {@code bObj} is a {@code Byte} object and
+     * {@code bObj.byteValue() == b}.
+     *
+     * @param obj the object whose field should be modified
+     * @param b   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setByte(Object obj, byte b)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code char} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, cObj)},
+     * where {@code cObj} is a {@code Character} object and
+     * {@code cObj.charValue() == c}.
+     *
+     * @param obj the object whose field should be modified
+     * @param c   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setChar(Object obj, char c)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code short} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, sObj)},
+     * where {@code sObj} is a {@code Short} object and
+     * {@code sObj.shortValue() == s}.
+     *
+     * @param obj the object whose field should be modified
+     * @param s   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setShort(Object obj, short s)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as an {@code int} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, iObj)},
+     * where {@code iObj} is a {@code Integer} object and
+     * {@code iObj.intValue() == i}.
+     *
+     * @param obj the object whose field should be modified
+     * @param i   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setInt(Object obj, int i)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code long} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, lObj)},
+     * where {@code lObj} is a {@code Long} object and
+     * {@code lObj.longValue() == l}.
+     *
+     * @param obj the object whose field should be modified
+     * @param l   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setLong(Object obj, long l)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code float} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, fObj)},
+     * where {@code fObj} is a {@code Float} object and
+     * {@code fObj.floatValue() == f}.
+     *
+     * @param obj the object whose field should be modified
+     * @param f   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setFloat(Object obj, float f)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * Sets the value of a field as a {@code double} on the specified object.
+     * This method is equivalent to
+     * {@code set(obj, dObj)},
+     * where {@code dObj} is a {@code Double} object and
+     * {@code dObj.doubleValue() == d}.
+     *
+     * @param obj the object whose field should be modified
+     * @param d   the new value for the field of {@code obj}
+     * being modified
+     *
+     * @exception IllegalAccessException    if this {@code Field} object
+     *              is enforcing Java language access control and the underlying
+     *              field is either inaccessible or final.
+     * @exception IllegalArgumentException  if the specified object is not an
+     *              instance of the class or interface declaring the underlying
+     *              field (or a subclass or implementor thereof),
+     *              or if an unwrapping conversion fails.
+     * @exception NullPointerException      if the specified object is null
+     *              and the field is an instance field.
+     * @exception ExceptionInInitializerError if the initialization provoked
+     *              by this method fails.
+     * @see       Field#set
+     */
+    @CallerSensitive
+    // Android-changed: set*(Object, ...) implemented natively.
+    @FastNative
+    public native void setDouble(Object obj, double d)
+        throws IllegalArgumentException, IllegalAccessException;
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.5
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+        // Android-changed: getAnnotation(Class) implemented differently.
+        return getAnnotationNative(annotationClass);
+    }
+    // Android-added: getAnnotation(Class) implemented differently.
+    @FastNative
+    private native <A extends Annotation> A getAnnotationNative(Class<A> annotationType);
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+        // Android-added: getAnnotationsByType(Class) implemented differently.
+        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
+    }
+
+    // BEGIN Android-added: isAnnotationPresent(Class) overridden in Field.
+    @Override
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return isAnnotationPresentNative(annotationType);
+    }
+    @FastNative
+    private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
+    // END Android-added: isAnnotationPresent(Class) overridden in Field.
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    @FastNative
+    public native Annotation[] getDeclaredAnnotations();
+
+    // BEGIN Android-added: Methods for use by Android-specific code.
+    /**
+     * Returns the offset of the field within an instance, or for static fields, the class.
+     *
+     * @hide
+     */
+    public int getOffset() {
+        return offset;
+    }
+
+    /**
+     * @hide - export for use by {@code java.lang.invoke.*}
+     */
+    @FastNative
+    public native long getArtField();
+    // END Android-added: Methods for use by Android-specific code.
+}
diff --git a/java/lang/reflect/GenericArrayType.annotated.java b/java/lang/reflect/GenericArrayType.annotated.java
new file mode 100644
index 0000000..c173408
--- /dev/null
+++ b/java/lang/reflect/GenericArrayType.annotated.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface GenericArrayType extends java.lang.reflect.Type {
+
[email protected] public java.lang.reflect.Type getGenericComponentType();
+}
+
diff --git a/java/lang/reflect/GenericArrayType.java b/java/lang/reflect/GenericArrayType.java
new file mode 100644
index 0000000..c45399e
--- /dev/null
+++ b/java/lang/reflect/GenericArrayType.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * {@code GenericArrayType} represents an array type whose component
+ * type is either a parameterized type or a type variable.
+ * @since 1.5
+ */
+public interface GenericArrayType extends Type {
+    /**
+     * Returns a {@code Type} object representing the component type
+     * of this array. This method creates the component type of the
+     * array.  See the declaration of {@link
+     * java.lang.reflect.ParameterizedType ParameterizedType} for the
+     * semantics of the creation process for parameterized types and
+     * see {@link java.lang.reflect.TypeVariable TypeVariable} for the
+     * creation process for type variables.
+     *
+     * @return  a {@code Type} object representing the component type
+     *     of this array
+     * @throws TypeNotPresentException if the underlying array type's
+     *     component type refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if  the
+     *     underlying array type's component type refers to a
+     *     parameterized type that cannot be instantiated for any reason
+     */
+    Type getGenericComponentType();
+}
diff --git a/java/lang/reflect/GenericDeclaration.annotated.java b/java/lang/reflect/GenericDeclaration.annotated.java
new file mode 100644
index 0000000..3614d84
--- /dev/null
+++ b/java/lang/reflect/GenericDeclaration.annotated.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface GenericDeclaration extends java.lang.reflect.AnnotatedElement {
+
[email protected] public java.lang.reflect.TypeVariable<?>[] getTypeParameters();
+}
+
diff --git a/java/lang/reflect/GenericDeclaration.java b/java/lang/reflect/GenericDeclaration.java
new file mode 100644
index 0000000..042e359
--- /dev/null
+++ b/java/lang/reflect/GenericDeclaration.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * A common interface for all entities that declare type variables.
+ *
+ * @since 1.5
+ */
+public interface GenericDeclaration extends AnnotatedElement {
+    /**
+     * Returns an array of {@code TypeVariable} objects that
+     * represent the type variables declared by the generic
+     * declaration represented by this {@code GenericDeclaration}
+     * object, in declaration order.  Returns an array of length 0 if
+     * the underlying generic declaration declares no type variables.
+     *
+     * @return an array of {@code TypeVariable} objects that represent
+     *     the type variables declared by this generic declaration
+     * @throws GenericSignatureFormatError if the generic
+     *     signature of this generic declaration does not conform to
+     *     the format specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     */
+    public TypeVariable<?>[] getTypeParameters();
+}
diff --git a/java/lang/reflect/GenericSignatureFormatError.java b/java/lang/reflect/GenericSignatureFormatError.java
new file mode 100644
index 0000000..3fd70d3
--- /dev/null
+++ b/java/lang/reflect/GenericSignatureFormatError.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+
+/**
+ * Thrown when a syntactically malformed signature attribute is
+ * encountered by a reflective method that needs to interpret the
+ * generic signature information for a type, method or constructor.
+ *
+ * @since 1.5
+ */
+public class GenericSignatureFormatError extends ClassFormatError {
+    private static final long serialVersionUID = 6709919147137911034L;
+
+    /**
+     * Constructs a new {@code GenericSignatureFormatError}.
+     *
+     */
+    public GenericSignatureFormatError() {
+        super();
+    }
+
+    /**
+     * Constructs a new {@code GenericSignatureFormatError} with the
+     * specified message.
+     *
+     * @param message the detail message, may be {@code null}
+     */
+    public GenericSignatureFormatError(String message) {
+        super(message);
+    }
+}
diff --git a/java/lang/reflect/InvocationHandler.java b/java/lang/reflect/InvocationHandler.java
new file mode 100644
index 0000000..c35e460
--- /dev/null
+++ b/java/lang/reflect/InvocationHandler.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * {@code InvocationHandler} is the interface implemented by
+ * the <i>invocation handler</i> of a proxy instance.
+ *
+ * <p>Each proxy instance has an associated invocation handler.
+ * When a method is invoked on a proxy instance, the method
+ * invocation is encoded and dispatched to the {@code invoke}
+ * method of its invocation handler.
+ *
+ * @author      Peter Jones
+ * @see         Proxy
+ * @since       1.3
+ */
+public interface InvocationHandler {
+
+    /**
+     * Processes a method invocation on a proxy instance and returns
+     * the result.  This method will be invoked on an invocation handler
+     * when a method is invoked on a proxy instance that it is
+     * associated with.
+     *
+     * @param   proxy the proxy instance that the method was invoked on
+     *
+     * @param   method the {@code Method} instance corresponding to
+     * the interface method invoked on the proxy instance.  The declaring
+     * class of the {@code Method} object will be the interface that
+     * the method was declared in, which may be a superinterface of the
+     * proxy interface that the proxy class inherits the method through.
+     *
+     * @param   args an array of objects containing the values of the
+     * arguments passed in the method invocation on the proxy instance,
+     * or {@code null} if interface method takes no arguments.
+     * Arguments of primitive types are wrapped in instances of the
+     * appropriate primitive wrapper class, such as
+     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
+     *
+     * @return  the value to return from the method invocation on the
+     * proxy instance.  If the declared return type of the interface
+     * method is a primitive type, then the value returned by
+     * this method must be an instance of the corresponding primitive
+     * wrapper class; otherwise, it must be a type assignable to the
+     * declared return type.  If the value returned by this method is
+     * {@code null} and the interface method's return type is
+     * primitive, then a {@code NullPointerException} will be
+     * thrown by the method invocation on the proxy instance.  If the
+     * value returned by this method is otherwise not compatible with
+     * the interface method's declared return type as described above,
+     * a {@code ClassCastException} will be thrown by the method
+     * invocation on the proxy instance.
+     *
+     * @throws  Throwable the exception to throw from the method
+     * invocation on the proxy instance.  The exception's type must be
+     * assignable either to any of the exception types declared in the
+     * {@code throws} clause of the interface method or to the
+     * unchecked exception types {@code java.lang.RuntimeException}
+     * or {@code java.lang.Error}.  If a checked exception is
+     * thrown by this method that is not assignable to any of the
+     * exception types declared in the {@code throws} clause of
+     * the interface method, then an
+     * {@link UndeclaredThrowableException} containing the
+     * exception that was thrown by this method will be thrown by the
+     * method invocation on the proxy instance.
+     *
+     * @see     UndeclaredThrowableException
+     */
+    public Object invoke(Object proxy, Method method, Object[] args)
+        throws Throwable;
+}
diff --git a/java/lang/reflect/InvocationTargetException.java b/java/lang/reflect/InvocationTargetException.java
new file mode 100644
index 0000000..360d0ba
--- /dev/null
+++ b/java/lang/reflect/InvocationTargetException.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * InvocationTargetException is a checked exception that wraps
+ * an exception thrown by an invoked method or constructor.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to conform to
+ * the general purpose exception-chaining mechanism.  The "target exception"
+ * that is provided at construction time and accessed via the
+ * {@link #getTargetException()} method is now known as the <i>cause</i>,
+ * and may be accessed via the {@link Throwable#getCause()} method,
+ * as well as the aforementioned "legacy method."
+ *
+ * @see Method
+ * @see Constructor
+ */
+public class InvocationTargetException extends ReflectiveOperationException {
+    /**
+     * Use serialVersionUID from JDK 1.1.X for interoperability
+     */
+    private static final long serialVersionUID = 4085088731926701167L;
+
+     /**
+     * This field holds the target if the
+     * InvocationTargetException(Throwable target) constructor was
+     * used to instantiate the object
+     *
+     * @serial
+     *
+     */
+    private Throwable target;
+
+    /**
+     * Constructs an {@code InvocationTargetException} with
+     * {@code null} as the target exception.
+     */
+    protected InvocationTargetException() {
+        super((Throwable)null);  // Disallow initCause
+    }
+
+    /**
+     * Constructs a InvocationTargetException with a target exception.
+     *
+     * @param target the target exception
+     */
+    public InvocationTargetException(Throwable target) {
+        super((Throwable)null);  // Disallow initCause
+        this.target = target;
+    }
+
+    /**
+     * Constructs a InvocationTargetException with a target exception
+     * and a detail message.
+     *
+     * @param target the target exception
+     * @param s      the detail message
+     */
+    public InvocationTargetException(Throwable target, String s) {
+        super(s, null);  // Disallow initCause
+        this.target = target;
+    }
+
+    /**
+     * Get the thrown target exception.
+     *
+     * <p>This method predates the general-purpose exception chaining facility.
+     * The {@link Throwable#getCause()} method is now the preferred means of
+     * obtaining this information.
+     *
+     * @return the thrown target exception (cause of this exception).
+     */
+    public Throwable getTargetException() {
+        return target;
+    }
+
+    /**
+     * Returns the cause of this exception (the thrown target exception,
+     * which may be {@code null}).
+     *
+     * @return  the cause of this exception.
+     * @since   1.4
+     */
+    public Throwable getCause() {
+        return target;
+    }
+}
diff --git a/java/lang/reflect/MalformedParameterizedTypeException.java b/java/lang/reflect/MalformedParameterizedTypeException.java
new file mode 100644
index 0000000..a9efc55
--- /dev/null
+++ b/java/lang/reflect/MalformedParameterizedTypeException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+/**
+ * Thrown when a semantically malformed parameterized type is
+ * encountered by a reflective method that needs to instantiate it.
+ * For example, if the number of type arguments to a parameterized type
+ * is wrong.
+ *
+ * @since 1.5
+ */
+public class MalformedParameterizedTypeException extends RuntimeException {
+    private static final long serialVersionUID = -5696557788586220964L;
+}
diff --git a/java/lang/reflect/MalformedParametersException.java b/java/lang/reflect/MalformedParametersException.java
new file mode 100644
index 0000000..7479624
--- /dev/null
+++ b/java/lang/reflect/MalformedParametersException.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Thrown when {@link java.lang.reflect.Executable#getParameters the
+ * java.lang.reflect package} attempts to read method parameters from
+ * a class file and determines that one or more parameters are
+ * malformed.
+ *
+ * <p>The following is a list of conditions under which this exception
+ * can be thrown:
+ * <ul>
+ * <li> The number of parameters (parameter_count) is wrong for the method
+ * <li> A constant pool index is out of bounds.
+ * <li> A constant pool index does not refer to a UTF-8 entry
+ * <li> A parameter's name is "", or contains an illegal character
+ * <li> The flags field contains an illegal flag (something other than
+ *     FINAL, SYNTHETIC, or MANDATED)
+ * </ul>
+ *
+ * See {@link java.lang.reflect.Executable#getParameters} for more
+ * information.
+ *
+ * @see java.lang.reflect.Executable#getParameters
+ * @since 1.8
+ */
+public class MalformedParametersException extends RuntimeException {
+
+    /**
+     * Version for serialization.
+     */
+    private static final long serialVersionUID = 20130919L;
+
+    /**
+     * Create a {@code MalformedParametersException} with an empty
+     * reason.
+     */
+    public MalformedParametersException() {}
+
+    /**
+     * Create a {@code MalformedParametersException}.
+     *
+     * @param reason The reason for the exception.
+     */
+    public MalformedParametersException(String reason) {
+        super(reason);
+    }
+}
diff --git a/java/lang/reflect/Member.annotated.java b/java/lang/reflect/Member.annotated.java
new file mode 100644
index 0000000..0552ce2
--- /dev/null
+++ b/java/lang/reflect/Member.annotated.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Member {
+
[email protected] public java.lang.Class<?> getDeclaringClass();
+
[email protected] public java.lang.String getName();
+
+public int getModifiers();
+
+public boolean isSynthetic();
+
+public static final int DECLARED = 1; // 0x1
+
+public static final int PUBLIC = 0; // 0x0
+}
+
diff --git a/java/lang/reflect/Member.java b/java/lang/reflect/Member.java
new file mode 100644
index 0000000..2241d45
--- /dev/null
+++ b/java/lang/reflect/Member.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Member is an interface that reflects identifying information about
+ * a single member (a field or a method) or a constructor.
+ *
+ * @see java.lang.Class
+ * @see Field
+ * @see Method
+ * @see Constructor
+ *
+ * @author Nakul Saraiya
+ */
+public
+interface Member {
+
+    /**
+     * Identifies the set of all public members of a class or interface,
+     * including inherited members.
+     */
+    public static final int PUBLIC = 0;
+
+    /**
+     * Identifies the set of declared members of a class or interface.
+     * Inherited members are not included.
+     */
+    public static final int DECLARED = 1;
+
+    /**
+     * Returns the Class object representing the class or interface
+     * that declares the member or constructor represented by this Member.
+     *
+     * @return an object representing the declaring class of the
+     * underlying member
+     */
+    public Class<?> getDeclaringClass();
+
+    /**
+     * Returns the simple name of the underlying member or constructor
+     * represented by this Member.
+     *
+     * @return the simple name of the underlying member
+     */
+    public String getName();
+
+    /**
+     * Returns the Java language modifiers for the member or
+     * constructor represented by this Member, as an integer.  The
+     * Modifier class should be used to decode the modifiers in
+     * the integer.
+     *
+     * @return the Java language modifiers for the underlying member
+     * @see Modifier
+     */
+    public int getModifiers();
+
+    /**
+     * Returns {@code true} if this member was introduced by
+     * the compiler; returns {@code false} otherwise.
+     *
+     * @return true if and only if this member was introduced by
+     * the compiler.
+     * @jls 13.1 The Form of a Binary
+     * @since 1.5
+     */
+    public boolean isSynthetic();
+}
diff --git a/java/lang/reflect/Method.annotated.java b/java/lang/reflect/Method.annotated.java
new file mode 100644
index 0000000..004a5ed
--- /dev/null
+++ b/java/lang/reflect/Method.annotated.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Method extends java.lang.reflect.Executable {
+
+Method() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<?> getDeclaringClass() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public int getModifiers() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<?> getReturnType() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.reflect.Type getGenericReturnType() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<?>[] getParameterTypes() { throw new RuntimeException("Stub!"); }
+
+public int getParameterCount() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.reflect.Type[] getGenericParameterTypes() { throw new RuntimeException("Stub!"); }
+
[email protected] public native java.lang.Class<?>[] getExceptionTypes();
+
[email protected] public java.lang.reflect.Type[] getGenericExceptionTypes() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toGenericString() { throw new RuntimeException("Stub!"); }
+
[email protected] public native java.lang.Object invoke(@libcore.util.Nullable java.lang.Object obj, [email protected] Object @libcore.util.Nullable ... args) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+
+public boolean isBridge() { throw new RuntimeException("Stub!"); }
+
+public boolean isVarArgs() { throw new RuntimeException("Stub!"); }
+
+public boolean isSynthetic() { throw new RuntimeException("Stub!"); }
+
+public boolean isDefault() { throw new RuntimeException("Stub!"); }
+
[email protected] public native java.lang.Object getDefaultValue();
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.annotation.Annotation[] getDeclaredAnnotations() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.annotation.Annotation[][] getParameterAnnotations() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/reflect/Method.java b/java/lang/reflect/Method.java
new file mode 100644
index 0000000..3da75c5
--- /dev/null
+++ b/java/lang/reflect/Method.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import sun.reflect.CallerSensitive;
+import dalvik.annotation.optimization.FastNative;
+import java.lang.annotation.Annotation;
+import java.util.Comparator;
+import libcore.reflect.Types;
+import libcore.util.EmptyArray;
+
+/**
+ * A {@code Method} provides information about, and access to, a single method
+ * on a class or interface.  The reflected method may be a class method
+ * or an instance method (including an abstract method).
+ *
+ * <p>A {@code Method} permits widening conversions to occur when matching the
+ * actual parameters to invoke with the underlying method's formal
+ * parameters, but it throws an {@code IllegalArgumentException} if a
+ * narrowing conversion would occur.
+ *
+ * @see Member
+ * @see java.lang.Class
+ * @see java.lang.Class#getMethods()
+ * @see java.lang.Class#getMethod(String, Class[])
+ * @see java.lang.Class#getDeclaredMethods()
+ * @see java.lang.Class#getDeclaredMethod(String, Class[])
+ *
+ * @author Kenneth Russell
+ * @author Nakul Saraiya
+ */
+public final class Method extends Executable  {
+    // Android-changed: Extensive modifications made throughout the class for ART.
+    // Android-changed: Many fields and methods removed / modified.
+    // Android-removed: Type annotations runtime code. Not supported on Android.
+    // Android-removed: Declared vs actual parameter annotation indexes handling.
+
+    /**
+     * Orders methods by their name, parameters and return type.
+     *
+     * @hide
+     */
+    public static final Comparator<Method> ORDER_BY_SIGNATURE = new Comparator<Method>() {
+        @Override public int compare(Method a, Method b) {
+            if (a == b) {
+                return 0;
+            }
+            int comparison = a.getName().compareTo(b.getName());
+            if (comparison == 0) {
+                comparison = a.compareMethodParametersInternal(b);
+                if (comparison == 0) {
+                    // This is necessary for methods that have covariant return types.
+                    Class<?> aReturnType = a.getReturnType();
+                    Class<?> bReturnType = b.getReturnType();
+                    if (aReturnType == bReturnType) {
+                        comparison = 0;
+                    } else {
+                        comparison = aReturnType.getName().compareTo(bReturnType.getName());
+                    }
+                }
+            }
+            return comparison;
+        }
+    };
+
+    private Method() {
+    }
+
+    @Override
+    boolean hasGenericInformation() {
+        // Android-changed: hasGenericInformation() implemented using Executable.
+        return super.hasGenericInformationInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<?> getDeclaringClass() {
+        // Android-changed: getDeclaringClass() implemented using Executable.
+        return super.getDeclaringClassInternal();
+    }
+
+    /**
+     * Returns the name of the method represented by this {@code Method}
+     * object, as a {@code String}.
+     */
+    @Override
+    public String getName() {
+        // Android-changed: getName() implemented using Executable.
+        return getMethodNameInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int getModifiers() {
+        // Android-changed: getModifiers() implemented using Executable.
+        return super.getModifiersInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws GenericSignatureFormatError {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public TypeVariable<Method>[] getTypeParameters() {
+        // Android-changed: getTypeParameters() partly implemented using Executable.
+        GenericInfo info = getMethodOrConstructorGenericInfoInternal();
+        return (TypeVariable<Method>[]) info.formalTypeParameters.clone();
+    }
+
+    /**
+     * Returns a {@code Class} object that represents the formal return type
+     * of the method represented by this {@code Method} object.
+     *
+     * @return the return type for the method this object represents
+     */
+    public Class<?> getReturnType() {
+        // Android-changed: getReturnType() implemented using Executable.
+        return getMethodReturnTypeInternal();
+    }
+
+    /**
+     * Returns a {@code Type} object that represents the formal return
+     * type of the method represented by this {@code Method} object.
+     *
+     * <p>If the return type is a parameterized type,
+     * the {@code Type} object returned must accurately reflect
+     * the actual type parameters used in the source code.
+     *
+     * <p>If the return type is a type variable or a parameterized type, it
+     * is created. Otherwise, it is resolved.
+     *
+     * @return  a {@code Type} object that represents the formal return
+     *     type of the underlying  method
+     * @throws GenericSignatureFormatError
+     *     if the generic method signature does not conform to the format
+     *     specified in
+     *     <cite>The Java&trade; Virtual Machine Specification</cite>
+     * @throws TypeNotPresentException if the underlying method's
+     *     return type refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if the
+     *     underlying method's return typed refers to a parameterized
+     *     type that cannot be instantiated for any reason
+     * @since 1.5
+     */
+    public Type getGenericReturnType() {
+        // Android-changed: getGenericReturnType() partly implemented using Executable.
+      return Types.getType(getMethodOrConstructorGenericInfoInternal().genericReturnType);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<?>[] getParameterTypes() {
+        // Android-changed: getParameterTypes() partly implemented using Executable.
+        Class<?>[] paramTypes = super.getParameterTypesInternal();
+        if (paramTypes == null) {
+            return EmptyArray.CLASS;
+        }
+
+        return paramTypes;
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.8
+     */
+    public int getParameterCount() {
+        // Android-changed: getParameterTypes() implemented using Executable.
+        return super.getParameterCountInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws GenericSignatureFormatError {@inheritDoc}
+     * @throws TypeNotPresentException {@inheritDoc}
+     * @throws MalformedParameterizedTypeException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public Type[] getGenericParameterTypes() {
+        return super.getGenericParameterTypes();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    // Android-changed: getExceptionTypes() implemented natively.
+    @FastNative
+    public native Class<?>[] getExceptionTypes();
+
+    /**
+     * {@inheritDoc}
+     * @throws GenericSignatureFormatError {@inheritDoc}
+     * @throws TypeNotPresentException {@inheritDoc}
+     * @throws MalformedParameterizedTypeException {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public Type[] getGenericExceptionTypes() {
+        return super.getGenericExceptionTypes();
+    }
+
+    /**
+     * Compares this {@code Method} against the specified object.  Returns
+     * true if the objects are the same.  Two {@code Methods} are the same if
+     * they were declared by the same class and have the same name
+     * and formal parameter types and return type.
+     */
+    public boolean equals(Object obj) {
+        if (obj != null && obj instanceof Method) {
+            Method other = (Method)obj;
+            if ((getDeclaringClass() == other.getDeclaringClass())
+                && (getName() == other.getName())) {
+                // Android-changed: Use getReturnType() instead of deleted returnType field
+                if (!getReturnType().equals(other.getReturnType()))
+                    return false;
+                // Android-changed: Use getParameterTypes() instead of deleted parameterTypes field
+                return equalParamTypes(getParameterTypes(), other.getParameterTypes());
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hashcode for this {@code Method}.  The hashcode is computed
+     * as the exclusive-or of the hashcodes for the underlying
+     * method's declaring class name and the method's name.
+     */
+    public int hashCode() {
+        return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
+    }
+
+    /**
+     * Returns a string describing this {@code Method}.  The string is
+     * formatted as the method access modifiers, if any, followed by
+     * the method return type, followed by a space, followed by the
+     * class declaring the method, followed by a period, followed by
+     * the method name, followed by a parenthesized, comma-separated
+     * list of the method's formal parameter types. If the method
+     * throws checked exceptions, the parameter list is followed by a
+     * space, followed by the word throws followed by a
+     * comma-separated list of the thrown exception types.
+     * For example:
+     * <pre>
+     *    public boolean java.lang.Object.equals(java.lang.Object)
+     * </pre>
+     *
+     * <p>The access modifiers are placed in canonical order as
+     * specified by "The Java Language Specification".  This is
+     * {@code public}, {@code protected} or {@code private} first,
+     * and then other modifiers in the following order:
+     * {@code abstract}, {@code default}, {@code static}, {@code final},
+     * {@code synchronized}, {@code native}, {@code strictfp}.
+     *
+     * @return a string describing this {@code Method}
+     *
+     * @jls 8.4.3 Method Modifiers
+     */
+    public String toString() {
+        // Android-changed: Use getParameterTypes() / getExceptionTypes() instead of deleted fields
+        return sharedToString(Modifier.methodModifiers(),
+                              isDefault(),
+                              getParameterTypes(),
+                              getExceptionTypes());
+    }
+
+    @Override
+    void specificToStringHeader(StringBuilder sb) {
+        sb.append(getReturnType().getTypeName()).append(' ');
+        sb.append(getDeclaringClass().getTypeName()).append('.');
+        sb.append(getName());
+    }
+
+    /**
+     * Returns a string describing this {@code Method}, including
+     * type parameters.  The string is formatted as the method access
+     * modifiers, if any, followed by an angle-bracketed
+     * comma-separated list of the method's type parameters, if any,
+     * followed by the method's generic return type, followed by a
+     * space, followed by the class declaring the method, followed by
+     * a period, followed by the method name, followed by a
+     * parenthesized, comma-separated list of the method's generic
+     * formal parameter types.
+     *
+     * If this method was declared to take a variable number of
+     * arguments, instead of denoting the last parameter as
+     * "<tt><i>Type</i>[]</tt>", it is denoted as
+     * "<tt><i>Type</i>...</tt>".
+     *
+     * A space is used to separate access modifiers from one another
+     * and from the type parameters or return type.  If there are no
+     * type parameters, the type parameter list is elided; if the type
+     * parameter list is present, a space separates the list from the
+     * class name.  If the method is declared to throw exceptions, the
+     * parameter list is followed by a space, followed by the word
+     * throws followed by a comma-separated list of the generic thrown
+     * exception types.
+     *
+     * <p>The access modifiers are placed in canonical order as
+     * specified by "The Java Language Specification".  This is
+     * {@code public}, {@code protected} or {@code private} first,
+     * and then other modifiers in the following order:
+     * {@code abstract}, {@code default}, {@code static}, {@code final},
+     * {@code synchronized}, {@code native}, {@code strictfp}.
+     *
+     * @return a string describing this {@code Method},
+     * include type parameters
+     *
+     * @since 1.5
+     *
+     * @jls 8.4.3 Method Modifiers
+     */
+    @Override
+    public String toGenericString() {
+        return sharedToGenericString(Modifier.methodModifiers(), isDefault());
+    }
+
+    @Override
+    void specificToGenericStringHeader(StringBuilder sb) {
+        Type genRetType = getGenericReturnType();
+        sb.append(genRetType.getTypeName()).append(' ');
+        sb.append(getDeclaringClass().getTypeName()).append('.');
+        sb.append(getName());
+    }
+
+    /**
+     * Invokes the underlying method represented by this {@code Method}
+     * object, on the specified object with the specified parameters.
+     * Individual parameters are automatically unwrapped to match
+     * primitive formal parameters, and both primitive and reference
+     * parameters are subject to method invocation conversions as
+     * necessary.
+     *
+     * <p>If the underlying method is static, then the specified {@code obj}
+     * argument is ignored. It may be null.
+     *
+     * <p>If the number of formal parameters required by the underlying method is
+     * 0, the supplied {@code args} array may be of length 0 or null.
+     *
+     * <p>If the underlying method is an instance method, it is invoked
+     * using dynamic method lookup as documented in The Java Language
+     * Specification, Second Edition, section 15.12.4.4; in particular,
+     * overriding based on the runtime type of the target object will occur.
+     *
+     * <p>If the underlying method is static, the class that declared
+     * the method is initialized if it has not already been initialized.
+     *
+     * <p>If the method completes normally, the value it returns is
+     * returned to the caller of invoke; if the value has a primitive
+     * type, it is first appropriately wrapped in an object. However,
+     * if the value has the type of an array of a primitive type, the
+     * elements of the array are <i>not</i> wrapped in objects; in
+     * other words, an array of primitive type is returned.  If the
+     * underlying method return type is void, the invocation returns
+     * null.
+     *
+     * @param obj  the object the underlying method is invoked from
+     * @param args the arguments used for the method call
+     * @return the result of dispatching the method represented by
+     * this object on {@code obj} with parameters
+     * {@code args}
+     *
+     * @exception IllegalAccessException    if this {@code Method} object
+     *              is enforcing Java language access control and the underlying
+     *              method is inaccessible.
+     * @exception IllegalArgumentException  if the method is an
+     *              instance method and the specified object argument
+     *              is not an instance of the class or interface
+     *              declaring the underlying method (or of a subclass
+     *              or implementor thereof); if the number of actual
+     *              and formal parameters differ; if an unwrapping
+     *              conversion for primitive arguments fails; or if,
+     *              after possible unwrapping, a parameter value
+     *              cannot be converted to the corresponding formal
+     *              parameter type by a method invocation conversion.
+     * @exception InvocationTargetException if the underlying method
+     *              throws an exception.
+     * @exception NullPointerException      if the specified object is null
+     *              and the method is an instance method.
+     * @exception ExceptionInInitializerError if the initialization
+     * provoked by this method fails.
+     */
+    @CallerSensitive
+    // Android-changed: invoke(Object, Object...) implemented natively.
+    @FastNative
+    public native Object invoke(Object obj, Object... args)
+            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
+
+    /**
+     * Returns {@code true} if this method is a bridge
+     * method; returns {@code false} otherwise.
+     *
+     * @return true if and only if this method is a bridge
+     * method as defined by the Java Language Specification.
+     * @since 1.5
+     */
+    public boolean isBridge() {
+        // Android-changed: isBridge() implemented using Executable.
+        return super.isBridgeMethodInternal();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public boolean isVarArgs() {
+        return super.isVarArgs();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @jls 13.1 The Form of a Binary
+     * @since 1.5
+     */
+    @Override
+    public boolean isSynthetic() {
+        return super.isSynthetic();
+    }
+
+    /**
+     * Returns {@code true} if this method is a default
+     * method; returns {@code false} otherwise.
+     *
+     * A default method is a public non-abstract instance method, that
+     * is, a non-static method with a body, declared in an interface
+     * type.
+     *
+     * @return true if and only if this method is a default
+     * method as defined by the Java Language Specification.
+     * @since 1.8
+     */
+    public boolean isDefault() {
+        // Android-changed: isDefault() implemented using Executable.
+        return super.isDefaultMethodInternal();
+    }
+
+    /**
+     * Returns the default value for the annotation member represented by
+     * this {@code Method} instance.  If the member is of a primitive type,
+     * an instance of the corresponding wrapper type is returned. Returns
+     * null if no default is associated with the member, or if the method
+     * instance does not represent a declared member of an annotation type.
+     *
+     * @return the default value for the annotation member represented
+     *     by this {@code Method} instance.
+     * @throws TypeNotPresentException if the annotation is of type
+     *     {@link Class} and no definition can be found for the
+     *     default class value.
+     * @since  1.5
+     */
+    // Android-changed: isDefault() implemented natively.
+    @FastNative
+    public native Object getDefaultValue();
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException  {@inheritDoc}
+     * @since 1.5
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        return super.getAnnotation(annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.5
+     */
+    public Annotation[] getDeclaredAnnotations()  {
+        return super.getDeclaredAnnotations();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @since 1.5
+     */
+    @Override
+    public Annotation[][] getParameterAnnotations() {
+        // Android-changed: getParameterAnnotations() implemented using Executable.
+        return super.getParameterAnnotationsInternal();
+    }
+
+    // Android-added: equalNameAndParameters(Method) for Proxy support.
+    /**
+     * Returns true if this and {@code method} have the same name and the same
+     * parameters in the same order. Such methods can share implementation if
+     * one method's return types is assignable to the other.
+     *
+     * @hide needed by Proxy
+     */
+    boolean equalNameAndParameters(Method m) {
+        return equalNameAndParametersInternal(m);
+    }
+}
diff --git a/java/lang/reflect/Modifier.java b/java/lang/reflect/Modifier.java
new file mode 100644
index 0000000..28d89bb
--- /dev/null
+++ b/java/lang/reflect/Modifier.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * The Modifier class provides {@code static} methods and
+ * constants to decode class and member access modifiers.  The sets of
+ * modifiers are represented as integers with distinct bit positions
+ * representing different modifiers.  The values for the constants
+ * representing the modifiers are taken from the tables in sections 4.1, 4.4, 4.5, and 4.7 of
+ * <cite>The Java&trade; Virtual Machine Specification</cite>.
+ *
+ * @see Class#getModifiers()
+ * @see Member#getModifiers()
+ *
+ * @author Nakul Saraiya
+ * @author Kenneth Russell
+ */
+public class Modifier {
+
+    // Android-removed: ReflectionFactory bootstrapping code not used on Android.
+    /*
+    /*
+     * Bootstrapping protocol between java.lang and java.lang.reflect
+     *  packages
+     *
+    static {
+        sun.reflect.ReflectionFactory factory =
+            AccessController.doPrivileged(
+                new ReflectionFactory.GetReflectionFactoryAction());
+        factory.setLangReflectAccess(new java.lang.reflect.ReflectAccess());
+    }
+    */
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code public} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code public} modifier; {@code false} otherwise.
+     */
+    public static boolean isPublic(int mod) {
+        return (mod & PUBLIC) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code private} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code private} modifier; {@code false} otherwise.
+     */
+    public static boolean isPrivate(int mod) {
+        return (mod & PRIVATE) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code protected} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code protected} modifier; {@code false} otherwise.
+     */
+    public static boolean isProtected(int mod) {
+        return (mod & PROTECTED) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code static} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code static} modifier; {@code false} otherwise.
+     */
+    public static boolean isStatic(int mod) {
+        return (mod & STATIC) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code final} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code final} modifier; {@code false} otherwise.
+     */
+    public static boolean isFinal(int mod) {
+        return (mod & FINAL) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code synchronized} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code synchronized} modifier; {@code false} otherwise.
+     */
+    public static boolean isSynchronized(int mod) {
+        return (mod & SYNCHRONIZED) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code volatile} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code volatile} modifier; {@code false} otherwise.
+     */
+    public static boolean isVolatile(int mod) {
+        return (mod & VOLATILE) != 0;
+    }
+
+    // Android-added: isConstructor(int) to support DEX-defined modifier flag.
+    /**
+     * Returns true if the given modifiers contain {@link Modifier#CONSTRUCTOR}.
+     * @hide
+     */
+    public static boolean isConstructor(int modifiers) {
+        return ((modifiers & Modifier.CONSTRUCTOR) != 0);
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code transient} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code transient} modifier; {@code false} otherwise.
+     */
+    public static boolean isTransient(int mod) {
+        return (mod & TRANSIENT) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code native} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code native} modifier; {@code false} otherwise.
+     */
+    public static boolean isNative(int mod) {
+        return (mod & NATIVE) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code interface} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code interface} modifier; {@code false} otherwise.
+     */
+    public static boolean isInterface(int mod) {
+        return (mod & INTERFACE) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code abstract} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code abstract} modifier; {@code false} otherwise.
+     */
+    public static boolean isAbstract(int mod) {
+        return (mod & ABSTRACT) != 0;
+    }
+
+    /**
+     * Return {@code true} if the integer argument includes the
+     * {@code strictfp} modifier, {@code false} otherwise.
+     *
+     * @param   mod a set of modifiers
+     * @return {@code true} if {@code mod} includes the
+     * {@code strictfp} modifier; {@code false} otherwise.
+     */
+    public static boolean isStrict(int mod) {
+        return (mod & STRICT) != 0;
+    }
+
+    /**
+     * Return a string describing the access modifier flags in
+     * the specified modifier. For example:
+     * <blockquote><pre>
+     *    public final synchronized strictfp
+     * </pre></blockquote>
+     * The modifier names are returned in an order consistent with the
+     * suggested modifier orderings given in sections 8.1.1, 8.3.1, 8.4.3, 8.8.3, and 9.1.1 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     * The full modifier ordering used by this method is:
+     * <blockquote> {@code
+     * public protected private abstract static final transient
+     * volatile synchronized native strictfp
+     * interface } </blockquote>
+     * The {@code interface} modifier discussed in this class is
+     * not a true modifier in the Java language and it appears after
+     * all other modifiers listed by this method.  This method may
+     * return a string of modifiers that are not valid modifiers of a
+     * Java entity; in other words, no checking is done on the
+     * possible validity of the combination of modifiers represented
+     * by the input.
+     *
+     * Note that to perform such checking for a known kind of entity,
+     * such as a constructor or method, first AND the argument of
+     * {@code toString} with the appropriate mask from a method like
+     * {@link #constructorModifiers} or {@link #methodModifiers}.
+     *
+     * @param   mod a set of modifiers
+     * @return  a string representation of the set of modifiers
+     * represented by {@code mod}
+     */
+    public static String toString(int mod) {
+        StringBuilder sb = new StringBuilder();
+        int len;
+
+        if ((mod & PUBLIC) != 0)        sb.append("public ");
+        if ((mod & PROTECTED) != 0)     sb.append("protected ");
+        if ((mod & PRIVATE) != 0)       sb.append("private ");
+
+        /* Canonical order */
+        if ((mod & ABSTRACT) != 0)      sb.append("abstract ");
+        if ((mod & STATIC) != 0)        sb.append("static ");
+        if ((mod & FINAL) != 0)         sb.append("final ");
+        if ((mod & TRANSIENT) != 0)     sb.append("transient ");
+        if ((mod & VOLATILE) != 0)      sb.append("volatile ");
+        if ((mod & SYNCHRONIZED) != 0)  sb.append("synchronized ");
+        if ((mod & NATIVE) != 0)        sb.append("native ");
+        if ((mod & STRICT) != 0)        sb.append("strictfp ");
+        if ((mod & INTERFACE) != 0)     sb.append("interface ");
+
+        if ((len = sb.length()) > 0)    /* trim trailing space */
+            return sb.toString().substring(0, len-1);
+        return "";
+    }
+
+    /*
+     * Access modifier flag constants from tables 4.1, 4.4, 4.5, and 4.7 of
+     * <cite>The Java&trade; Virtual Machine Specification</cite>
+     */
+
+    /**
+     * The {@code int} value representing the {@code public}
+     * modifier.
+     */
+    public static final int PUBLIC           = 0x00000001;
+
+    /**
+     * The {@code int} value representing the {@code private}
+     * modifier.
+     */
+    public static final int PRIVATE          = 0x00000002;
+
+    /**
+     * The {@code int} value representing the {@code protected}
+     * modifier.
+     */
+    public static final int PROTECTED        = 0x00000004;
+
+    /**
+     * The {@code int} value representing the {@code static}
+     * modifier.
+     */
+    public static final int STATIC           = 0x00000008;
+
+    /**
+     * The {@code int} value representing the {@code final}
+     * modifier.
+     */
+    public static final int FINAL            = 0x00000010;
+
+    /**
+     * The {@code int} value representing the {@code synchronized}
+     * modifier.
+     */
+    public static final int SYNCHRONIZED     = 0x00000020;
+
+    /**
+     * The {@code int} value representing the {@code volatile}
+     * modifier.
+     */
+    public static final int VOLATILE         = 0x00000040;
+
+    /**
+     * The {@code int} value representing the {@code transient}
+     * modifier.
+     */
+    public static final int TRANSIENT        = 0x00000080;
+
+    /**
+     * The {@code int} value representing the {@code native}
+     * modifier.
+     */
+    public static final int NATIVE           = 0x00000100;
+
+    /**
+     * The {@code int} value representing the {@code interface}
+     * modifier.
+     */
+    public static final int INTERFACE        = 0x00000200;
+
+    /**
+     * The {@code int} value representing the {@code abstract}
+     * modifier.
+     */
+    public static final int ABSTRACT         = 0x00000400;
+
+    /**
+     * The {@code int} value representing the {@code strictfp}
+     * modifier.
+     */
+    public static final int STRICT           = 0x00000800;
+
+    // Bits not (yet) exposed in the public API either because they
+    // have different meanings for fields and methods and there is no
+    // way to distinguish between the two in this class, or because
+    // they are not Java programming language keywords
+    static final int BRIDGE    = 0x00000040;
+    static final int VARARGS   = 0x00000080;
+    // Android-changed: SYNTHETIC made public for use in tests.
+    /**
+     * @hide
+     */
+    public static final int SYNTHETIC = 0x00001000;
+    static final int ANNOTATION  = 0x00002000;
+    static final int ENUM      = 0x00004000;
+    static final int MANDATED  = 0x00008000;
+    static boolean isSynthetic(int mod) {
+      return (mod & SYNTHETIC) != 0;
+    }
+
+    static boolean isMandated(int mod) {
+      return (mod & MANDATED) != 0;
+    }
+
+    // Note on the FOO_MODIFIERS fields and fooModifiers() methods:
+    // the sets of modifiers are not guaranteed to be constants
+    // across time and Java SE releases. Therefore, it would not be
+    // appropriate to expose an external interface to this information
+    // that would allow the values to be treated as Java-level
+    // constants since the values could be constant folded and updates
+    // to the sets of modifiers missed. Thus, the fooModifiers()
+    // methods return an unchanging values for a given release, but a
+    // value that can potentially change over time.
+
+    // Android-added: CONSTRUCTOR to support DEX-defined modifier flag.
+    /**
+     * Dex addition to mark instance constructors and static class
+     * initializer methods.
+     * @hide
+     */
+    public static final int CONSTRUCTOR = 0x10000;
+
+    // Android-added: DEFAULT to support DEX-defined modifier flag.
+    /**
+     * Default methods are marked with a synthetic access flag
+     * to speed up class loading and invocation target lookup.
+     * Implies INTERFACE, not-ABSTRACT, and not-STATIC.
+     *
+     * @hide
+     */
+    public static final int DEFAULT = 0x00400000;
+
+    /**
+     * The Java source modifiers that can be applied to a class.
+     * @jls 8.1.1 Class Modifiers
+     */
+    private static final int CLASS_MODIFIERS =
+        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
+        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.FINAL   |
+        Modifier.STRICT;
+
+    /**
+     * The Java source modifiers that can be applied to an interface.
+     * @jls 9.1.1 Interface Modifiers
+     */
+    private static final int INTERFACE_MODIFIERS =
+        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
+        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.STRICT;
+
+
+    /**
+     * The Java source modifiers that can be applied to a constructor.
+     * @jls 8.8.3 Constructor Modifiers
+     */
+    private static final int CONSTRUCTOR_MODIFIERS =
+        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE;
+
+    /**
+     * The Java source modifiers that can be applied to a method.
+     * @jls8.4.3  Method Modifiers
+     */
+    private static final int METHOD_MODIFIERS =
+        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
+        Modifier.ABSTRACT       | Modifier.STATIC       | Modifier.FINAL   |
+        Modifier.SYNCHRONIZED   | Modifier.NATIVE       | Modifier.STRICT;
+
+    /**
+     * The Java source modifiers that can be applied to a field.
+     * @jls 8.3.1  Field Modifiers
+     */
+    private static final int FIELD_MODIFIERS =
+        Modifier.PUBLIC         | Modifier.PROTECTED    | Modifier.PRIVATE |
+        Modifier.STATIC         | Modifier.FINAL        | Modifier.TRANSIENT |
+        Modifier.VOLATILE;
+
+    /**
+     * The Java source modifiers that can be applied to a method or constructor parameter.
+     * @jls 8.4.1 Formal Parameters
+     */
+    private static final int PARAMETER_MODIFIERS =
+        Modifier.FINAL;
+
+    /**
+     *
+     */
+    static final int ACCESS_MODIFIERS =
+        Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
+
+    /**
+     * Return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a class.
+     * @return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a class.
+     *
+     * @jls 8.1.1 Class Modifiers
+     * @since 1.7
+     */
+    public static int classModifiers() {
+        return CLASS_MODIFIERS;
+    }
+
+    /**
+     * Return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to an interface.
+     * @return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to an interface.
+     *
+     * @jls 9.1.1 Interface Modifiers
+     * @since 1.7
+     */
+    public static int interfaceModifiers() {
+        return INTERFACE_MODIFIERS;
+    }
+
+    /**
+     * Return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a constructor.
+     * @return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a constructor.
+     *
+     * @jls 8.8.3 Constructor Modifiers
+     * @since 1.7
+     */
+    public static int constructorModifiers() {
+        return CONSTRUCTOR_MODIFIERS;
+    }
+
+    /**
+     * Return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a method.
+     * @return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a method.
+     *
+     * @jls 8.4.3 Method Modifiers
+     * @since 1.7
+     */
+    public static int methodModifiers() {
+        return METHOD_MODIFIERS;
+    }
+
+    /**
+     * Return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a field.
+     * @return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a field.
+     *
+     * @jls 8.3.1 Field Modifiers
+     * @since 1.7
+     */
+    public static int fieldModifiers() {
+        return FIELD_MODIFIERS;
+    }
+
+    /**
+     * Return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a parameter.
+     * @return an {@code int} value OR-ing together the source language
+     * modifiers that can be applied to a parameter.
+     *
+     * @jls 8.4.1 Formal Parameters
+     * @since 1.8
+     */
+    public static int parameterModifiers() {
+        return PARAMETER_MODIFIERS;
+    }
+}
diff --git a/java/lang/reflect/Parameter.annotated.java b/java/lang/reflect/Parameter.annotated.java
new file mode 100644
index 0000000..247db53
--- /dev/null
+++ b/java/lang/reflect/Parameter.annotated.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import java.lang.annotation.*;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Parameter implements java.lang.reflect.AnnotatedElement {
+
+Parameter(java.lang.String name, int modifiers, java.lang.reflect.Executable executable, int index) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean isNamePresent() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.reflect.Executable getDeclaringExecutable() { throw new RuntimeException("Stub!"); }
+
+public int getModifiers() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.reflect.Type getParameterizedType() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Class<?> getType() { throw new RuntimeException("Stub!"); }
+
+public boolean isImplicit() { throw new RuntimeException("Stub!"); }
+
+public boolean isSynthetic() { throw new RuntimeException("Stub!"); }
+
+public boolean isVarArgs() { throw new RuntimeException("Stub!"); }
+
[email protected] public <T extends java.lang.annotation.Annotation> T getAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Annotation @libcore.util.NonNull [] getDeclaredAnnotations() { throw new RuntimeException("Stub!"); }
+
[email protected] public <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(@libcore.util.NonNull java.lang.Class<T> annotationClass) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Annotation @libcore.util.NonNull [] getAnnotations() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/lang/reflect/Parameter.java b/java/lang/reflect/Parameter.java
new file mode 100644
index 0000000..4dc32b4
--- /dev/null
+++ b/java/lang/reflect/Parameter.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.reflect;
+
+import dalvik.annotation.optimization.FastNative;
+import java.lang.annotation.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import libcore.reflect.AnnotatedElements;
+
+/**
+ * Information about method parameters.
+ *
+ * A {@code Parameter} provides information about method parameters,
+ * including its name and modifiers.  It also provides an alternate
+ * means of obtaining attributes for the parameter.
+ *
+ * @since 1.8
+ */
+public final class Parameter implements AnnotatedElement {
+    // Android-changed: Extensive modifications made throughout the class for ART.
+    // Android-removed: Type annotations runtime code. Not supported on Android.
+    // Android-removed: Annotation retrieval is implemented natively in ART.
+
+    private final String name;
+    private final int modifiers;
+    private final Executable executable;
+    private final int index;
+
+    /**
+     * Package-private constructor for {@code Parameter}.
+     *
+     * If method parameter data is present in the classfile, then the
+     * JVM creates {@code Parameter} objects directly.  If it is
+     * absent, however, then {@code Executable} uses this constructor
+     * to synthesize them.
+     *
+     * @param name The name of the parameter.
+     * @param modifiers The modifier flags for the parameter.
+     * @param executable The executable which defines this parameter.
+     * @param index The index of the parameter.
+     */
+    Parameter(String name,
+              int modifiers,
+              Executable executable,
+              int index) {
+        this.name = name;
+        this.modifiers = modifiers;
+        this.executable = executable;
+        this.index = index;
+    }
+
+    /**
+     * Compares based on the executable and the index.
+     *
+     * @param obj The object to compare.
+     * @return Whether or not this is equal to the argument.
+     */
+    public boolean equals(Object obj) {
+        if(obj instanceof Parameter) {
+            Parameter other = (Parameter)obj;
+            return (other.executable.equals(executable) &&
+                    other.index == index);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code based on the executable's hash code and the
+     * index.
+     *
+     * @return A hash code based on the executable's hash code.
+     */
+    public int hashCode() {
+        return executable.hashCode() ^ index;
+    }
+
+    // Android-changed: Removed references in javadoc to the class file format.
+    /**
+     * Returns true if the parameter has a name; returns false otherwise.
+     * Whether a parameter has a name is determined by compiler options
+     * and whether the parameter is synthesized.
+     *
+     * @return true if and only if the parameter has a name
+     */
+    public boolean isNamePresent() {
+        return executable.hasRealParameterData() && name != null;
+    }
+
+    /**
+     * Returns a string describing this parameter.  The format is the
+     * modifiers for the parameter, if any, in canonical order as
+     * recommended by <cite>The Java&trade; Language
+     * Specification</cite>, followed by the fully- qualified type of
+     * the parameter (excluding the last [] if the parameter is
+     * variable arity), followed by "..." if the parameter is variable
+     * arity, followed by a space, followed by the name of the
+     * parameter.
+     *
+     * @return A string representation of the parameter and associated
+     * information.
+     */
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        final Type type = getParameterizedType();
+        final String typename = type.getTypeName();
+
+        sb.append(Modifier.toString(getModifiers()));
+
+        if(0 != modifiers)
+            sb.append(' ');
+
+        if(isVarArgs())
+            sb.append(typename.replaceFirst("\\[\\]$", "..."));
+        else
+            sb.append(typename);
+
+        sb.append(' ');
+        sb.append(getName());
+
+        return sb.toString();
+    }
+
+    /**
+     * Return the {@code Executable} which declares this parameter.
+     *
+     * @return The {@code Executable} declaring this parameter.
+     */
+    public Executable getDeclaringExecutable() {
+        return executable;
+    }
+
+    /**
+     * Get the modifier flags for this the parameter represented by
+     * this {@code Parameter} object.
+     *
+     * @return The modifier flags for this parameter.
+     */
+    public int getModifiers() {
+        return modifiers;
+    }
+
+    /**
+     * Returns the name of the parameter.  If the parameter's name is
+     * {@linkplain #isNamePresent() present}, then this method returns
+     * the name provided by the class file. Otherwise, this method
+     * synthesizes a name of the form argN, where N is the index of
+     * the parameter in the descriptor of the method which declares
+     * the parameter.
+     *
+     * @return The name of the parameter, either provided by the class
+     *         file or synthesized if the class file does not provide
+     *         a name.
+     */
+    public String getName() {
+        // Note: empty strings as paramete names are now outlawed.
+        // The .equals("") is for compatibility with current JVM
+        // behavior.  It may be removed at some point.
+        if(name == null || name.equals(""))
+            return "arg" + index;
+        else
+            return name;
+    }
+
+    // Package-private accessor to the real name field.
+    String getRealName() {
+        return name;
+    }
+
+    /**
+     * Returns a {@code Type} object that identifies the parameterized
+     * type for the parameter represented by this {@code Parameter}
+     * object.
+     *
+     * @return a {@code Type} object identifying the parameterized
+     * type of the parameter represented by this object
+     */
+    public Type getParameterizedType() {
+        Type tmp = parameterTypeCache;
+        if (null == tmp) {
+            tmp = executable.getAllGenericParameterTypes()[index];
+            parameterTypeCache = tmp;
+        }
+
+        return tmp;
+    }
+
+    private transient volatile Type parameterTypeCache = null;
+
+    /**
+     * Returns a {@code Class} object that identifies the
+     * declared type for the parameter represented by this
+     * {@code Parameter} object.
+     *
+     * @return a {@code Class} object identifying the declared
+     * type of the parameter represented by this object
+     */
+    public Class<?> getType() {
+        Class<?> tmp = parameterClassCache;
+        if (null == tmp) {
+            tmp = executable.getParameterTypes()[index];
+            parameterClassCache = tmp;
+        }
+        return tmp;
+    }
+
+    private transient volatile Class<?> parameterClassCache = null;
+
+    /**
+     * Returns {@code true} if this parameter is implicitly declared
+     * in source code; returns {@code false} otherwise.
+     *
+     * @return true if and only if this parameter is implicitly
+     * declared as defined by <cite>The Java&trade; Language
+     * Specification</cite>.
+     */
+    public boolean isImplicit() {
+        return Modifier.isMandated(getModifiers());
+    }
+
+    /**
+     * Returns {@code true} if this parameter is neither implicitly
+     * nor explicitly declared in source code; returns {@code false}
+     * otherwise.
+     *
+     * @jls 13.1 The Form of a Binary
+     * @return true if and only if this parameter is a synthetic
+     * construct as defined by
+     * <cite>The Java&trade; Language Specification</cite>.
+     */
+    public boolean isSynthetic() {
+        return Modifier.isSynthetic(getModifiers());
+    }
+
+    /**
+     * Returns {@code true} if this parameter represents a variable
+     * argument list; returns {@code false} otherwise.
+     *
+     * @return {@code true} if an only if this parameter represents a
+     * variable argument list.
+     */
+    public boolean isVarArgs() {
+        return executable.isVarArgs() &&
+            index == executable.getParameterCount() - 1;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+        Objects.requireNonNull(annotationClass);
+        // Android-changed: getAnnotation(Class) Uses native code to obtain annotation information.
+        return getAnnotationNative(executable, index, annotationClass);
+    }
+    // Android-added: getAnnotation(Class) Uses native code to obtain annotation information.
+    @FastNative
+    private static native <A extends Annotation> A getAnnotationNative(
+            Executable executable, int parameterIndex, Class<A> annotationType);
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+        // Android-changed: getAnnotationsByType(Class), Android uses AnnotatedElements instead.
+        return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Annotation[] getDeclaredAnnotations() {
+        return executable.getParameterAnnotations()[index];
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
+        // Only annotations on classes are inherited, for all other
+        // objects getDeclaredAnnotation is the same as
+        // getAnnotation.
+        return getAnnotation(annotationClass);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @Override
+    public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
+        // Only annotations on classes are inherited, for all other
+        // objects getDeclaredAnnotations is the same as
+        // getAnnotations.
+        return getAnnotationsByType(annotationClass);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Annotation[] getAnnotations() {
+        return getDeclaredAnnotations();
+    }
+
+}
diff --git a/java/lang/reflect/ParameterizedType.annotated.java b/java/lang/reflect/ParameterizedType.annotated.java
new file mode 100644
index 0000000..1502d68
--- /dev/null
+++ b/java/lang/reflect/ParameterizedType.annotated.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface ParameterizedType extends java.lang.reflect.Type {
+
+public [email protected] Type @libcore.util.NonNull [] getActualTypeArguments();
+
[email protected] public java.lang.reflect.Type getRawType();
+
[email protected] public java.lang.reflect.Type getOwnerType();
+}
diff --git a/java/lang/reflect/ParameterizedType.java b/java/lang/reflect/ParameterizedType.java
new file mode 100644
index 0000000..a1b1398
--- /dev/null
+++ b/java/lang/reflect/ParameterizedType.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+
+/**
+ * ParameterizedType represents a parameterized type such as
+ * Collection&lt;String&gt;.
+ *
+ * <p>A parameterized type is created the first time it is needed by a
+ * reflective method, as specified in this package. When a
+ * parameterized type p is created, the generic type declaration that
+ * p instantiates is resolved, and all type arguments of p are created
+ * recursively. See {@link java.lang.reflect.TypeVariable
+ * TypeVariable} for details on the creation process for type
+ * variables. Repeated creation of a parameterized type has no effect.
+ *
+ * <p>Instances of classes that implement this interface must implement
+ * an equals() method that equates any two instances that share the
+ * same generic type declaration and have equal type parameters.
+ *
+ * @since 1.5
+ */
+public interface ParameterizedType extends Type {
+    /**
+     * Returns an array of {@code Type} objects representing the actual type
+     * arguments to this type.
+     *
+     * <p>Note that in some cases, the returned array be empty. This can occur
+     * if this type represents a non-parameterized type nested within
+     * a parameterized type.
+     *
+     * @return an array of {@code Type} objects representing the actual type
+     *     arguments to this type
+     * @throws TypeNotPresentException if any of the
+     *     actual type arguments refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if any of the
+     *     actual type parameters refer to a parameterized type that cannot
+     *     be instantiated for any reason
+     * @since 1.5
+     */
+    Type[] getActualTypeArguments();
+
+    /**
+     * Returns the {@code Type} object representing the class or interface
+     * that declared this type.
+     *
+     * @return the {@code Type} object representing the class or interface
+     *     that declared this type
+     * @since 1.5
+     */
+    Type getRawType();
+
+    /**
+     * Returns a {@code Type} object representing the type that this type
+     * is a member of.  For example, if this type is {@code O<T>.I<S>},
+     * return a representation of {@code O<T>}.
+     *
+     * <p>If this type is a top-level type, {@code null} is returned.
+     *
+     * @return a {@code Type} object representing the type that
+     *     this type is a member of. If this type is a top-level type,
+     *     {@code null} is returned
+     * @throws TypeNotPresentException if the owner type
+     *     refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if the owner type
+     *     refers to a parameterized type that cannot be instantiated
+     *     for any reason
+     * @since 1.5
+     */
+    Type getOwnerType();
+}
diff --git a/java/lang/reflect/Proxy.annotated.java b/java/lang/reflect/Proxy.annotated.java
new file mode 100644
index 0000000..eb396c7
--- /dev/null
+++ b/java/lang/reflect/Proxy.annotated.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+import java.security.Permission;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Proxy implements java.io.Serializable {
+
+protected Proxy(@libcore.util.NonNull java.lang.reflect.InvocationHandler h) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Class<?> getProxyClass(@libcore.util.Nullable java.lang.ClassLoader loader, [email protected] Class<?> @libcore.util.NonNull ... interfaces) throws java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.Object newProxyInstance(@libcore.util.Nullable java.lang.ClassLoader loader, [email protected] Class<?> @libcore.util.NonNull [] interfaces, @libcore.util.NonNull java.lang.reflect.InvocationHandler h) throws java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public static boolean isProxyClass(@libcore.util.NonNull java.lang.Class<?> cl) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.reflect.InvocationHandler getInvocationHandler(@libcore.util.NonNull java.lang.Object proxy) throws java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+protected java.lang.reflect.InvocationHandler h;
+}
diff --git a/java/lang/reflect/Proxy.java b/java/lang/reflect/Proxy.java
new file mode 100644
index 0000000..584d568
--- /dev/null
+++ b/java/lang/reflect/Proxy.java
@@ -0,0 +1,1008 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+
+import dalvik.annotation.optimization.FastNative;
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiFunction;
+import libcore.util.EmptyArray;
+import sun.reflect.CallerSensitive;
+import sun.reflect.misc.ReflectUtil;
+import sun.security.util.SecurityConstants;
+
+/**
+ * {@code Proxy} provides static methods for creating dynamic proxy
+ * classes and instances, and it is also the superclass of all
+ * dynamic proxy classes created by those methods.
+ *
+ * <p>To create a proxy for some interface {@code Foo}:
+ * <pre>
+ *     InvocationHandler handler = new MyInvocationHandler(...);
+ *     Class&lt;?&gt; proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
+ *     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
+ *                     newInstance(handler);
+ * </pre>
+ * or more simply:
+ * <pre>
+ *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
+ *                                          new Class&lt;?&gt;[] { Foo.class },
+ *                                          handler);
+ * </pre>
+ *
+ * <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
+ * class</i> below) is a class that implements a list of interfaces
+ * specified at runtime when the class is created, with behavior as
+ * described below.
+ *
+ * A <i>proxy interface</i> is such an interface that is implemented
+ * by a proxy class.
+ *
+ * A <i>proxy instance</i> is an instance of a proxy class.
+ *
+ * Each proxy instance has an associated <i>invocation handler</i>
+ * object, which implements the interface {@link InvocationHandler}.
+ * A method invocation on a proxy instance through one of its proxy
+ * interfaces will be dispatched to the {@link InvocationHandler#invoke
+ * invoke} method of the instance's invocation handler, passing the proxy
+ * instance, a {@code java.lang.reflect.Method} object identifying
+ * the method that was invoked, and an array of type {@code Object}
+ * containing the arguments.  The invocation handler processes the
+ * encoded method invocation as appropriate and the result that it
+ * returns will be returned as the result of the method invocation on
+ * the proxy instance.
+ *
+ * <p>A proxy class has the following properties:
+ *
+ * <ul>
+ * <li>Proxy classes are <em>public, final, and not abstract</em> if
+ * all proxy interfaces are public.</li>
+ *
+ * <li>Proxy classes are <em>non-public, final, and not abstract</em> if
+ * any of the proxy interfaces is non-public.</li>
+ *
+ * <li>The unqualified name of a proxy class is unspecified.  The space
+ * of class names that begin with the string {@code "$Proxy"}
+ * should be, however, reserved for proxy classes.
+ *
+ * <li>A proxy class extends {@code java.lang.reflect.Proxy}.
+ *
+ * <li>A proxy class implements exactly the interfaces specified at its
+ * creation, in the same order.
+ *
+ * <li>If a proxy class implements a non-public interface, then it will
+ * be defined in the same package as that interface.  Otherwise, the
+ * package of a proxy class is also unspecified.  Note that package
+ * sealing will not prevent a proxy class from being successfully defined
+ * in a particular package at runtime, and neither will classes already
+ * defined by the same class loader and the same package with particular
+ * signers.
+ *
+ * <li>Since a proxy class implements all of the interfaces specified at
+ * its creation, invoking {@code getInterfaces} on its
+ * {@code Class} object will return an array containing the same
+ * list of interfaces (in the order specified at its creation), invoking
+ * {@code getMethods} on its {@code Class} object will return
+ * an array of {@code Method} objects that include all of the
+ * methods in those interfaces, and invoking {@code getMethod} will
+ * find methods in the proxy interfaces as would be expected.
+ *
+ * <li>The {@link Proxy#isProxyClass Proxy.isProxyClass} method will
+ * return true if it is passed a proxy class-- a class returned by
+ * {@code Proxy.getProxyClass} or the class of an object returned by
+ * {@code Proxy.newProxyInstance}-- and false otherwise.
+ *
+ * <li>The {@code java.security.ProtectionDomain} of a proxy class
+ * is the same as that of system classes loaded by the bootstrap class
+ * loader, such as {@code java.lang.Object}, because the code for a
+ * proxy class is generated by trusted system code.  This protection
+ * domain will typically be granted
+ * {@code java.security.AllPermission}.
+ *
+ * <li>Each proxy class has one public constructor that takes one argument,
+ * an implementation of the interface {@link InvocationHandler}, to set
+ * the invocation handler for a proxy instance.  Rather than having to use
+ * the reflection API to access the public constructor, a proxy instance
+ * can be also be created by calling the {@link Proxy#newProxyInstance
+ * Proxy.newProxyInstance} method, which combines the actions of calling
+ * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the
+ * constructor with an invocation handler.
+ * </ul>
+ *
+ * <p>A proxy instance has the following properties:
+ *
+ * <ul>
+ * <li>Given a proxy instance {@code proxy} and one of the
+ * interfaces implemented by its proxy class {@code Foo}, the
+ * following expression will return true:
+ * <pre>
+ *     {@code proxy instanceof Foo}
+ * </pre>
+ * and the following cast operation will succeed (rather than throwing
+ * a {@code ClassCastException}):
+ * <pre>
+ *     {@code (Foo) proxy}
+ * </pre>
+ *
+ * <li>Each proxy instance has an associated invocation handler, the one
+ * that was passed to its constructor.  The static
+ * {@link Proxy#getInvocationHandler Proxy.getInvocationHandler} method
+ * will return the invocation handler associated with the proxy instance
+ * passed as its argument.
+ *
+ * <li>An interface method invocation on a proxy instance will be
+ * encoded and dispatched to the invocation handler's {@link
+ * InvocationHandler#invoke invoke} method as described in the
+ * documentation for that method.
+ *
+ * <li>An invocation of the {@code hashCode},
+ * {@code equals}, or {@code toString} methods declared in
+ * {@code java.lang.Object} on a proxy instance will be encoded and
+ * dispatched to the invocation handler's {@code invoke} method in
+ * the same manner as interface method invocations are encoded and
+ * dispatched, as described above.  The declaring class of the
+ * {@code Method} object passed to {@code invoke} will be
+ * {@code java.lang.Object}.  Other public methods of a proxy
+ * instance inherited from {@code java.lang.Object} are not
+ * overridden by a proxy class, so invocations of those methods behave
+ * like they do for instances of {@code java.lang.Object}.
+ * </ul>
+ *
+ * <h3>Methods Duplicated in Multiple Proxy Interfaces</h3>
+ *
+ * <p>When two or more interfaces of a proxy class contain a method with
+ * the same name and parameter signature, the order of the proxy class's
+ * interfaces becomes significant.  When such a <i>duplicate method</i>
+ * is invoked on a proxy instance, the {@code Method} object passed
+ * to the invocation handler will not necessarily be the one whose
+ * declaring class is assignable from the reference type of the interface
+ * that the proxy's method was invoked through.  This limitation exists
+ * because the corresponding method implementation in the generated proxy
+ * class cannot determine which interface it was invoked through.
+ * Therefore, when a duplicate method is invoked on a proxy instance,
+ * the {@code Method} object for the method in the foremost interface
+ * that contains the method (either directly or inherited through a
+ * superinterface) in the proxy class's list of interfaces is passed to
+ * the invocation handler's {@code invoke} method, regardless of the
+ * reference type through which the method invocation occurred.
+ *
+ * <p>If a proxy interface contains a method with the same name and
+ * parameter signature as the {@code hashCode}, {@code equals},
+ * or {@code toString} methods of {@code java.lang.Object},
+ * when such a method is invoked on a proxy instance, the
+ * {@code Method} object passed to the invocation handler will have
+ * {@code java.lang.Object} as its declaring class.  In other words,
+ * the public, non-final methods of {@code java.lang.Object}
+ * logically precede all of the proxy interfaces for the determination of
+ * which {@code Method} object to pass to the invocation handler.
+ *
+ * <p>Note also that when a duplicate method is dispatched to an
+ * invocation handler, the {@code invoke} method may only throw
+ * checked exception types that are assignable to one of the exception
+ * types in the {@code throws} clause of the method in <i>all</i> of
+ * the proxy interfaces that it can be invoked through.  If the
+ * {@code invoke} method throws a checked exception that is not
+ * assignable to any of the exception types declared by the method in one
+ * of the proxy interfaces that it can be invoked through, then an
+ * unchecked {@code UndeclaredThrowableException} will be thrown by
+ * the invocation on the proxy instance.  This restriction means that not
+ * all of the exception types returned by invoking
+ * {@code getExceptionTypes} on the {@code Method} object
+ * passed to the {@code invoke} method can necessarily be thrown
+ * successfully by the {@code invoke} method.
+ *
+ * @author      Peter Jones
+ * @see         InvocationHandler
+ * @since       1.3
+ */
+public class Proxy implements java.io.Serializable {
+
+    private static final long serialVersionUID = -2222568056686623797L;
+
+    /** parameter types of a proxy class constructor */
+    private static final Class<?>[] constructorParams =
+        { InvocationHandler.class };
+
+    /**
+     * a cache of proxy classes
+     */
+    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
+        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
+
+    /**
+     * the invocation handler for this proxy instance.
+     * @serial
+     */
+    protected InvocationHandler h;
+
+    /**
+     * Prohibits instantiation.
+     */
+    private Proxy() {
+    }
+
+    /**
+     * Constructs a new {@code Proxy} instance from a subclass
+     * (typically, a dynamic proxy class) with the specified value
+     * for its invocation handler.
+     *
+     * @param  h the invocation handler for this proxy instance
+     *
+     * @throws NullPointerException if the given invocation handler, {@code h},
+     *         is {@code null}.
+     */
+    protected Proxy(InvocationHandler h) {
+        Objects.requireNonNull(h);
+        this.h = h;
+    }
+
+    /**
+     * Returns the {@code java.lang.Class} object for a proxy class
+     * given a class loader and an array of interfaces.  The proxy class
+     * will be defined by the specified class loader and will implement
+     * all of the supplied interfaces.  If any of the given interfaces
+     * is non-public, the proxy class will be non-public. If a proxy class
+     * for the same permutation of interfaces has already been defined by the
+     * class loader, then the existing proxy class will be returned; otherwise,
+     * a proxy class for those interfaces will be generated dynamically
+     * and defined by the class loader.
+     *
+     * <p>There are several restrictions on the parameters that may be
+     * passed to {@code Proxy.getProxyClass}:
+     *
+     * <ul>
+     * <li>All of the {@code Class} objects in the
+     * {@code interfaces} array must represent interfaces, not
+     * classes or primitive types.
+     *
+     * <li>No two elements in the {@code interfaces} array may
+     * refer to identical {@code Class} objects.
+     *
+     * <li>All of the interface types must be visible by name through the
+     * specified class loader.  In other words, for class loader
+     * {@code cl} and every interface {@code i}, the following
+     * expression must be true:
+     * <pre>
+     *     Class.forName(i.getName(), false, cl) == i
+     * </pre>
+     *
+     * <li>All non-public interfaces must be in the same package;
+     * otherwise, it would not be possible for the proxy class to
+     * implement all of the interfaces, regardless of what package it is
+     * defined in.
+     *
+     * <li>For any set of member methods of the specified interfaces
+     * that have the same signature:
+     * <ul>
+     * <li>If the return type of any of the methods is a primitive
+     * type or void, then all of the methods must have that same
+     * return type.
+     * <li>Otherwise, one of the methods must have a return type that
+     * is assignable to all of the return types of the rest of the
+     * methods.
+     * </ul>
+     *
+     * <li>The resulting proxy class must not exceed any limits imposed
+     * on classes by the virtual machine.  For example, the VM may limit
+     * the number of interfaces that a class may implement to 65535; in
+     * that case, the size of the {@code interfaces} array must not
+     * exceed 65535.
+     * </ul>
+     *
+     * <p>If any of these restrictions are violated,
+     * {@code Proxy.getProxyClass} will throw an
+     * {@code IllegalArgumentException}.  If the {@code interfaces}
+     * array argument or any of its elements are {@code null}, a
+     * {@code NullPointerException} will be thrown.
+     *
+     * <p>Note that the order of the specified proxy interfaces is
+     * significant: two requests for a proxy class with the same combination
+     * of interfaces but in a different order will result in two distinct
+     * proxy classes.
+     *
+     * @param   loader the class loader to define the proxy class
+     * @param   interfaces the list of interfaces for the proxy class
+     *          to implement
+     * @return  a proxy class that is defined in the specified class loader
+     *          and that implements the specified interfaces
+     * @throws  IllegalArgumentException if any of the restrictions on the
+     *          parameters that may be passed to {@code getProxyClass}
+     *          are violated
+     * @throws  SecurityException if a security manager, <em>s</em>, is present
+     *          and any of the following conditions is met:
+     *          <ul>
+     *             <li> the given {@code loader} is {@code null} and
+     *             the caller's class loader is not {@code null} and the
+     *             invocation of {@link SecurityManager#checkPermission
+     *             s.checkPermission} with
+     *             {@code RuntimePermission("getClassLoader")} permission
+     *             denies access.</li>
+     *             <li> for each proxy interface, {@code intf},
+     *             the caller's class loader is not the same as or an
+     *             ancestor of the class loader for {@code intf} and
+     *             invocation of {@link SecurityManager#checkPackageAccess
+     *             s.checkPackageAccess()} denies access to {@code intf}.</li>
+     *          </ul>
+     * @throws  NullPointerException if the {@code interfaces} array
+     *          argument or any of its elements are {@code null}
+     */
+    @CallerSensitive
+    public static Class<?> getProxyClass(ClassLoader loader,
+                                         Class<?>... interfaces)
+        throws IllegalArgumentException
+    {
+        // BEGIN Android-changed: Excluded SecurityManager / permission checks.
+        /*
+        final Class<?>[] intfs = interfaces.clone();
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
+        }
+
+        return getProxyClass0(loader, intfs);
+        */
+
+        return getProxyClass0(loader, interfaces);
+        // END Android-changed: Excluded SecurityManager / permission checks.
+    }
+
+    // Android-removed: SecurityManager / permission check code.
+    /*
+    /*
+     * Check permissions required to create a Proxy class.
+     *
+     * To define a proxy class, it performs the access checks as in
+     * Class.forName (VM will invoke ClassLoader.checkPackageAccess):
+     * 1. "getClassLoader" permission check if loader == null
+     * 2. checkPackageAccess on the interfaces it implements
+     *
+     * To get a constructor and new instance of a proxy class, it performs
+     * the package access check on the interfaces it implements
+     * as in Class.getConstructor.
+     *
+     * If an interface is non-public, the proxy class must be defined by
+     * the defining loader of the interface.  If the caller's class loader
+     * is not the same as the defining loader of the interface, the VM
+     * will throw IllegalAccessError when the generated proxy class is
+     * being defined via the defineClass0 method.
+     *
+    private static void checkProxyAccess(Class<?> caller,
+                                         ClassLoader loader,
+                                         Class<?>... interfaces)
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            ClassLoader ccl = caller.getClassLoader();
+            if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+            }
+            ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
+        }
+    }
+    */
+
+    /**
+     * Generate a proxy class.  Must call the checkProxyAccess method
+     * to perform permission checks before calling this.
+     */
+    private static Class<?> getProxyClass0(ClassLoader loader,
+                                           Class<?>... interfaces) {
+        if (interfaces.length > 65535) {
+            throw new IllegalArgumentException("interface limit exceeded");
+        }
+
+        // If the proxy class defined by the given loader implementing
+        // the given interfaces exists, this will simply return the cached copy;
+        // otherwise, it will create the proxy class via the ProxyClassFactory
+        return proxyClassCache.get(loader, interfaces);
+    }
+
+    /*
+     * a key used for proxy class with 0 implemented interfaces
+     */
+    private static final Object key0 = new Object();
+
+    /*
+     * Key1 and Key2 are optimized for the common use of dynamic proxies
+     * that implement 1 or 2 interfaces.
+     */
+
+    /*
+     * a key used for proxy class with 1 implemented interface
+     */
+    private static final class Key1 extends WeakReference<Class<?>> {
+        private final int hash;
+
+        Key1(Class<?> intf) {
+            super(intf);
+            this.hash = intf.hashCode();
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            Class<?> intf;
+            return this == obj ||
+                   obj != null &&
+                   obj.getClass() == Key1.class &&
+                   (intf = get()) != null &&
+                   intf == ((Key1) obj).get();
+        }
+    }
+
+    /*
+     * a key used for proxy class with 2 implemented interfaces
+     */
+    private static final class Key2 extends WeakReference<Class<?>> {
+        private final int hash;
+        private final WeakReference<Class<?>> ref2;
+
+        Key2(Class<?> intf1, Class<?> intf2) {
+            super(intf1);
+            hash = 31 * intf1.hashCode() + intf2.hashCode();
+            ref2 = new WeakReference<Class<?>>(intf2);
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            Class<?> intf1, intf2;
+            return this == obj ||
+                   obj != null &&
+                   obj.getClass() == Key2.class &&
+                   (intf1 = get()) != null &&
+                   intf1 == ((Key2) obj).get() &&
+                   (intf2 = ref2.get()) != null &&
+                   intf2 == ((Key2) obj).ref2.get();
+        }
+    }
+
+    /*
+     * a key used for proxy class with any number of implemented interfaces
+     * (used here for 3 or more only)
+     */
+    private static final class KeyX {
+        private final int hash;
+        private final WeakReference<Class<?>>[] refs;
+
+        @SuppressWarnings("unchecked")
+        KeyX(Class<?>[] interfaces) {
+            hash = Arrays.hashCode(interfaces);
+            refs = (WeakReference<Class<?>>[])new WeakReference<?>[interfaces.length];
+            for (int i = 0; i < interfaces.length; i++) {
+                refs[i] = new WeakReference<>(interfaces[i]);
+            }
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return this == obj ||
+                   obj != null &&
+                   obj.getClass() == KeyX.class &&
+                   equals(refs, ((KeyX) obj).refs);
+        }
+
+        private static boolean equals(WeakReference<Class<?>>[] refs1,
+                                      WeakReference<Class<?>>[] refs2) {
+            if (refs1.length != refs2.length) {
+                return false;
+            }
+            for (int i = 0; i < refs1.length; i++) {
+                Class<?> intf = refs1[i].get();
+                if (intf == null || intf != refs2[i].get()) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * A function that maps an array of interfaces to an optimal key where
+     * Class objects representing interfaces are weakly referenced.
+     */
+    private static final class KeyFactory
+        implements BiFunction<ClassLoader, Class<?>[], Object>
+    {
+        @Override
+        public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
+            switch (interfaces.length) {
+                case 1: return new Key1(interfaces[0]); // the most frequent
+                case 2: return new Key2(interfaces[0], interfaces[1]);
+                case 0: return key0;
+                default: return new KeyX(interfaces);
+            }
+        }
+    }
+
+    // BEGIN Android-changed: How proxies are generated.
+    /**
+     * Orders methods by their name, parameters, return type and inheritance relationship.
+     *
+     * @hide
+     */
+    private static final Comparator<Method> ORDER_BY_SIGNATURE_AND_SUBTYPE = new Comparator<Method>() {
+        @Override public int compare(Method a, Method b) {
+            int comparison = Method.ORDER_BY_SIGNATURE.compare(a, b);
+            if (comparison != 0) {
+                return comparison;
+            }
+            Class<?> aClass = a.getDeclaringClass();
+            Class<?> bClass = b.getDeclaringClass();
+            if (aClass == bClass) {
+                return 0;
+            } else if (aClass.isAssignableFrom(bClass)) {
+                return 1;
+            } else if (bClass.isAssignableFrom(aClass)) {
+                return -1;
+            } else {
+                return 0;
+            }
+        }
+    };
+
+    /**
+     * A factory function that generates, defines and returns the proxy class given
+     * the ClassLoader and array of interfaces.
+     */
+    private static final class ProxyClassFactory
+        implements BiFunction<ClassLoader, Class<?>[], Class<?>>
+    {
+        // prefix for all proxy class names
+        private static final String proxyClassNamePrefix = "$Proxy";
+
+        // next number to use for generation of unique proxy class names
+        private static final AtomicLong nextUniqueNumber = new AtomicLong();
+
+        @Override
+        public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
+
+            Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
+            for (Class<?> intf : interfaces) {
+                /*
+                 * Verify that the class loader resolves the name of this
+                 * interface to the same Class object.
+                 */
+                Class<?> interfaceClass = null;
+                try {
+                    interfaceClass = Class.forName(intf.getName(), false, loader);
+                } catch (ClassNotFoundException e) {
+                }
+                if (interfaceClass != intf) {
+                    throw new IllegalArgumentException(
+                        intf + " is not visible from class loader");
+                }
+                /*
+                 * Verify that the Class object actually represents an
+                 * interface.
+                 */
+                if (!interfaceClass.isInterface()) {
+                    throw new IllegalArgumentException(
+                        interfaceClass.getName() + " is not an interface");
+                }
+                /*
+                 * Verify that this interface is not a duplicate.
+                 */
+                if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
+                    throw new IllegalArgumentException(
+                        "repeated interface: " + interfaceClass.getName());
+                }
+            }
+
+            String proxyPkg = null;     // package to define proxy class in
+            int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
+
+            /*
+             * Record the package of a non-public proxy interface so that the
+             * proxy class will be defined in the same package.  Verify that
+             * all non-public proxy interfaces are in the same package.
+             */
+            for (Class<?> intf : interfaces) {
+                int flags = intf.getModifiers();
+                if (!Modifier.isPublic(flags)) {
+                    accessFlags = Modifier.FINAL;
+                    String name = intf.getName();
+                    int n = name.lastIndexOf('.');
+                    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
+                    if (proxyPkg == null) {
+                        proxyPkg = pkg;
+                    } else if (!pkg.equals(proxyPkg)) {
+                        throw new IllegalArgumentException(
+                            "non-public interfaces from different packages");
+                    }
+                }
+            }
+
+            if (proxyPkg == null) {
+                // if no non-public proxy interfaces, use the default package.
+                proxyPkg = "";
+            }
+
+            {
+                // Android-changed: Generate the proxy directly instead of calling
+                // through to ProxyGenerator.
+                List<Method> methods = getMethods(interfaces);
+                Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
+                validateReturnTypes(methods);
+                List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
+
+                Method[] methodsArray = methods.toArray(new Method[methods.size()]);
+                Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
+
+                /*
+                 * Choose a name for the proxy class to generate.
+                 */
+                long num = nextUniqueNumber.getAndIncrement();
+                String proxyName = proxyPkg + proxyClassNamePrefix + num;
+
+                return generateProxy(proxyName, interfaces, loader, methodsArray,
+                                     exceptionsArray);
+            }
+        }
+    }
+
+    /**
+     * Remove methods that have the same name, parameters and return type. This
+     * computes the exceptions of each method; this is the intersection of the
+     * exceptions of equivalent methods.
+     *
+     * @param methods the methods to find exceptions for, ordered by name and
+     *     signature.
+     */
+    private static List<Class<?>[]> deduplicateAndGetExceptions(List<Method> methods) {
+        List<Class<?>[]> exceptions = new ArrayList<Class<?>[]>(methods.size());
+
+        for (int i = 0; i < methods.size(); ) {
+            Method method = methods.get(i);
+            Class<?>[] exceptionTypes = method.getExceptionTypes();
+
+            if (i > 0 && Method.ORDER_BY_SIGNATURE.compare(method, methods.get(i - 1)) == 0) {
+                exceptions.set(i - 1, intersectExceptions(exceptions.get(i - 1), exceptionTypes));
+                methods.remove(i);
+            } else {
+                exceptions.add(exceptionTypes);
+                i++;
+            }
+        }
+        return exceptions;
+    }
+
+    /**
+     * Returns the exceptions that are declared in both {@code aExceptions} and
+     * {@code bExceptions}. If an exception type in one array is a subtype of an
+     * exception from the other, the subtype is included in the intersection.
+     */
+    private static Class<?>[] intersectExceptions(Class<?>[] aExceptions, Class<?>[] bExceptions) {
+        if (aExceptions.length == 0 || bExceptions.length == 0) {
+            return EmptyArray.CLASS;
+        }
+        if (Arrays.equals(aExceptions, bExceptions)) {
+            return aExceptions;
+        }
+        Set<Class<?>> intersection = new HashSet<Class<?>>();
+        for (Class<?> a : aExceptions) {
+            for (Class<?> b : bExceptions) {
+                if (a.isAssignableFrom(b)) {
+                    intersection.add(b);
+                } else if (b.isAssignableFrom(a)) {
+                    intersection.add(a);
+                }
+            }
+        }
+        return intersection.toArray(new Class<?>[intersection.size()]);
+    }
+
+    /**
+     * Throws if any two methods in {@code methods} have the same name and
+     * parameters but incompatible return types.
+     *
+     * @param methods the methods to find exceptions for, ordered by name and
+     *     signature.
+     */
+    private static void validateReturnTypes(List<Method> methods) {
+        Method vs = null;
+        for (Method method : methods) {
+            if (vs == null || !vs.equalNameAndParameters(method)) {
+                vs = method; // this has a different name or parameters
+                continue;
+            }
+            Class<?> returnType = method.getReturnType();
+            Class<?> vsReturnType = vs.getReturnType();
+            if (returnType.isInterface() && vsReturnType.isInterface()) {
+                // all interfaces are mutually compatible
+            } else if (vsReturnType.isAssignableFrom(returnType)) {
+                vs = method; // the new return type is a subtype; use it instead
+            } else if (!returnType.isAssignableFrom(vsReturnType)) {
+                throw new IllegalArgumentException("proxied interface methods have incompatible "
+                        + "return types:\n  " + vs + "\n  " + method);
+            }
+        }
+    }
+
+    private static List<Method> getMethods(Class<?>[] interfaces) {
+        List<Method> result = new ArrayList<Method>();
+        try {
+            result.add(Object.class.getMethod("equals", Object.class));
+            result.add(Object.class.getMethod("hashCode", EmptyArray.CLASS));
+            result.add(Object.class.getMethod("toString", EmptyArray.CLASS));
+        } catch (NoSuchMethodException e) {
+            throw new AssertionError();
+        }
+
+        getMethodsRecursive(interfaces, result);
+        return result;
+    }
+
+    /**
+     * Fills {@code proxiedMethods} with the methods of {@code interfaces} and
+     * the interfaces they extend. May contain duplicates.
+     */
+    private static void getMethodsRecursive(Class<?>[] interfaces, List<Method> methods) {
+        for (Class<?> i : interfaces) {
+            getMethodsRecursive(i.getInterfaces(), methods);
+            Collections.addAll(methods, i.getDeclaredMethods());
+        }
+    }
+
+    @FastNative
+    private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
+                                                 ClassLoader loader, Method[] methods,
+                                                 Class<?>[][] exceptions);
+    // END Android-changed: How proxies are generated.
+
+
+    /**
+     * Returns an instance of a proxy class for the specified interfaces
+     * that dispatches method invocations to the specified invocation
+     * handler.
+     *
+     * <p>{@code Proxy.newProxyInstance} throws
+     * {@code IllegalArgumentException} for the same reasons that
+     * {@code Proxy.getProxyClass} does.
+     *
+     * @param   loader the class loader to define the proxy class
+     * @param   interfaces the list of interfaces for the proxy class
+     *          to implement
+     * @param   h the invocation handler to dispatch method invocations to
+     * @return  a proxy instance with the specified invocation handler of a
+     *          proxy class that is defined by the specified class loader
+     *          and that implements the specified interfaces
+     * @throws  IllegalArgumentException if any of the restrictions on the
+     *          parameters that may be passed to {@code getProxyClass}
+     *          are violated
+     * @throws  SecurityException if a security manager, <em>s</em>, is present
+     *          and any of the following conditions is met:
+     *          <ul>
+     *          <li> the given {@code loader} is {@code null} and
+     *               the caller's class loader is not {@code null} and the
+     *               invocation of {@link SecurityManager#checkPermission
+     *               s.checkPermission} with
+     *               {@code RuntimePermission("getClassLoader")} permission
+     *               denies access;</li>
+     *          <li> for each proxy interface, {@code intf},
+     *               the caller's class loader is not the same as or an
+     *               ancestor of the class loader for {@code intf} and
+     *               invocation of {@link SecurityManager#checkPackageAccess
+     *               s.checkPackageAccess()} denies access to {@code intf};</li>
+     *          <li> any of the given proxy interfaces is non-public and the
+     *               caller class is not in the same {@linkplain Package runtime package}
+     *               as the non-public interface and the invocation of
+     *               {@link SecurityManager#checkPermission s.checkPermission} with
+     *               {@code ReflectPermission("newProxyInPackage.{package name}")}
+     *               permission denies access.</li>
+     *          </ul>
+     * @throws  NullPointerException if the {@code interfaces} array
+     *          argument or any of its elements are {@code null}, or
+     *          if the invocation handler, {@code h}, is
+     *          {@code null}
+     */
+    @CallerSensitive
+    public static Object newProxyInstance(ClassLoader loader,
+                                          Class<?>[] interfaces,
+                                          InvocationHandler h)
+        throws IllegalArgumentException
+    {
+        Objects.requireNonNull(h);
+
+        final Class<?>[] intfs = interfaces.clone();
+        // Android-removed: SecurityManager calls
+        /*
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
+        }
+        */
+
+        /*
+         * Look up or generate the designated proxy class.
+         */
+        Class<?> cl = getProxyClass0(loader, intfs);
+
+        /*
+         * Invoke its constructor with the designated invocation handler.
+         */
+        try {
+            // Android-removed: SecurityManager / permission checks.
+            /*
+            if (sm != null) {
+                checkNewProxyPermission(Reflection.getCallerClass(), cl);
+            }
+            */
+
+            final Constructor<?> cons = cl.getConstructor(constructorParams);
+            final InvocationHandler ih = h;
+            if (!Modifier.isPublic(cl.getModifiers())) {
+                // BEGIN Android-removed: Excluded AccessController.doPrivileged call.
+                /*
+                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    public Void run() {
+                        cons.setAccessible(true);
+                        return null;
+                    }
+                });
+                */
+
+                cons.setAccessible(true);
+                // END Android-removed: Excluded AccessController.doPrivileged call.
+            }
+            return cons.newInstance(new Object[]{h});
+        } catch (IllegalAccessException|InstantiationException e) {
+            throw new InternalError(e.toString(), e);
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getCause();
+            if (t instanceof RuntimeException) {
+                throw (RuntimeException) t;
+            } else {
+                throw new InternalError(t.toString(), t);
+            }
+        } catch (NoSuchMethodException e) {
+            throw new InternalError(e.toString(), e);
+        }
+    }
+
+    // Android-removed: SecurityManager / permission checks.
+    /*
+    private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
+                ClassLoader ccl = caller.getClassLoader();
+                ClassLoader pcl = proxyClass.getClassLoader();
+
+                // do permission check if the caller is in a different runtime package
+                // of the proxy class
+                int n = proxyClass.getName().lastIndexOf('.');
+                String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n);
+
+                n = caller.getName().lastIndexOf('.');
+                String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
+
+                if (pcl != ccl || !pkg.equals(callerPkg)) {
+                    sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
+                }
+            }
+        }
+    }
+    */
+
+    /**
+     * Returns true if and only if the specified class was dynamically
+     * generated to be a proxy class using the {@code getProxyClass}
+     * method or the {@code newProxyInstance} method.
+     *
+     * <p>The reliability of this method is important for the ability
+     * to use it to make security decisions, so its implementation should
+     * not just test if the class in question extends {@code Proxy}.
+     *
+     * @param   cl the class to test
+     * @return  {@code true} if the class is a proxy class and
+     *          {@code false} otherwise
+     * @throws  NullPointerException if {@code cl} is {@code null}
+     */
+    public static boolean isProxyClass(Class<?> cl) {
+        return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl);
+    }
+
+    /**
+     * Returns the invocation handler for the specified proxy instance.
+     *
+     * @param   proxy the proxy instance to return the invocation handler for
+     * @return  the invocation handler for the proxy instance
+     * @throws  IllegalArgumentException if the argument is not a
+     *          proxy instance
+     * @throws  SecurityException if a security manager, <em>s</em>, is present
+     *          and the caller's class loader is not the same as or an
+     *          ancestor of the class loader for the invocation handler
+     *          and invocation of {@link SecurityManager#checkPackageAccess
+     *          s.checkPackageAccess()} denies access to the invocation
+     *          handler's class.
+     */
+    @CallerSensitive
+    public static InvocationHandler getInvocationHandler(Object proxy)
+        throws IllegalArgumentException
+    {
+        /*
+         * Verify that the object is actually a proxy instance.
+         */
+        if (!isProxyClass(proxy.getClass())) {
+            throw new IllegalArgumentException("not a proxy instance");
+        }
+
+        final Proxy p = (Proxy) proxy;
+        final InvocationHandler ih = p.h;
+        // Android-removed: SecurityManager / access checks.
+        /*
+        if (System.getSecurityManager() != null) {
+            Class<?> ihClass = ih.getClass();
+            Class<?> caller = Reflection.getCallerClass();
+            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
+                                                    ihClass.getClassLoader()))
+            {
+                ReflectUtil.checkPackageAccess(ihClass);
+            }
+        }
+        */
+
+        return ih;
+    }
+
+    // Android-added: Helper method invoke(Proxy, Method, Object[]) for ART native code.
+    private static Object invoke(Proxy proxy, Method method, Object[] args) throws Throwable {
+        InvocationHandler h = proxy.h;
+        return h.invoke(proxy, method, args);
+    }
+}
diff --git a/java/lang/reflect/ReflectPermission.java b/java/lang/reflect/ReflectPermission.java
new file mode 100644
index 0000000..a5e5be1
--- /dev/null
+++ b/java/lang/reflect/ReflectPermission.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public final
+class ReflectPermission extends java.security.BasicPermission {
+
+    public ReflectPermission(String name) {
+        super(name);
+    }
+
+    public ReflectPermission(String name, String actions) {
+        super("", "");
+    }
+}
diff --git a/java/lang/reflect/Type.annotated.java b/java/lang/reflect/Type.annotated.java
new file mode 100644
index 0000000..f2b646b
--- /dev/null
+++ b/java/lang/reflect/Type.annotated.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Type {
+
[email protected] public default java.lang.String getTypeName() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/lang/reflect/Type.java b/java/lang/reflect/Type.java
new file mode 100644
index 0000000..eee7443
--- /dev/null
+++ b/java/lang/reflect/Type.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Type is the common superinterface for all types in the Java
+ * programming language. These include raw types, parameterized types,
+ * array types, type variables and primitive types.
+ *
+ * @since 1.5
+ */
+public interface Type {
+    /**
+     * Returns a string describing this type, including information
+     * about any type parameters.
+     *
+     * @implSpec The default implementation calls {@code toString}.
+     *
+     * @return a string describing this type
+     * @since 1.8
+     */
+    default String getTypeName() {
+        return toString();
+    }
+}
diff --git a/java/lang/reflect/TypeVariable.annotated.java b/java/lang/reflect/TypeVariable.annotated.java
new file mode 100644
index 0000000..5654963
--- /dev/null
+++ b/java/lang/reflect/TypeVariable.annotated.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface TypeVariable<D extends java.lang.reflect.GenericDeclaration> extends java.lang.reflect.Type {
+
+public [email protected] Type @libcore.util.NonNull [] getBounds();
+
[email protected] public D getGenericDeclaration();
+
[email protected] public java.lang.String getName();
+}
diff --git a/java/lang/reflect/TypeVariable.java b/java/lang/reflect/TypeVariable.java
new file mode 100644
index 0000000..4e29a94
--- /dev/null
+++ b/java/lang/reflect/TypeVariable.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * TypeVariable is the common superinterface for type variables of kinds.
+ * A type variable is created the first time it is needed by a reflective
+ * method, as specified in this package.  If a type variable t is referenced
+ * by a type (i.e, class, interface or annotation type) T, and T is declared
+ * by the nth enclosing class of T (see JLS 8.1.2), then the creation of t
+ * requires the resolution (see JVMS 5) of the ith enclosing class of T,
+ * for i = 0 to n, inclusive. Creating a type variable must not cause the
+ * creation of its bounds. Repeated creation of a type variable has no effect.
+ *
+ * <p>Multiple objects may be instantiated at run-time to
+ * represent a given type variable. Even though a type variable is
+ * created only once, this does not imply any requirement to cache
+ * instances representing the type variable. However, all instances
+ * representing a type variable must be equal() to each other.
+ * As a consequence, users of type variables must not rely on the identity
+ * of instances of classes implementing this interface.
+ *
+ * @param <D> the type of generic declaration that declared the
+ * underlying type variable.
+ *
+ * @since 1.5
+ */
+// Android-changed: Removed support for type annotations at runtime.
+// Removed AnnotatedElement super-class.
+public interface TypeVariable<D extends GenericDeclaration> extends Type/*, AnnotatedElement*/ {
+    /**
+     * Returns an array of {@code Type} objects representing the
+     * upper bound(s) of this type variable.  Note that if no upper bound is
+     * explicitly declared, the upper bound is {@code Object}.
+     *
+     * <p>For each upper bound B: <ul> <li>if B is a parameterized
+     * type or a type variable, it is created, (see {@link
+     * java.lang.reflect.ParameterizedType ParameterizedType} for the
+     * details of the creation process for parameterized types).
+     * <li>Otherwise, B is resolved.  </ul>
+     *
+     * @throws TypeNotPresentException  if any of the
+     *     bounds refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if any of the
+     *     bounds refer to a parameterized type that cannot be instantiated
+     *     for any reason
+     * @return an array of {@code Type}s representing the upper
+     *     bound(s) of this type variable
+    */
+    Type[] getBounds();
+
+    /**
+     * Returns the {@code GenericDeclaration} object representing the
+     * generic declaration declared this type variable.
+     *
+     * @return the generic declaration declared for this type variable.
+     *
+     * @since 1.5
+     */
+    D getGenericDeclaration();
+
+    /**
+     * Returns the name of this type variable, as it occurs in the source code.
+     *
+     * @return the name of this type variable, as it appears in the source code
+     */
+    String getName();
+
+    // Android-removed: getAnnotatedBounds(), no support for runtime type annotations on Android.
+    /*
+    /**
+     * Returns an array of AnnotatedType objects that represent the use of
+     * types to denote the upper bounds of the type parameter represented by
+     * this TypeVariable. The order of the objects in the array corresponds to
+     * the order of the bounds in the declaration of the type parameter.
+     *
+     * Returns an array of length 0 if the type parameter declares no bounds.
+     *
+     * @return an array of objects representing the upper bounds of the type variable
+     * @since 1.8
+     *
+     AnnotatedType[] getAnnotatedBounds();
+    */
+}
diff --git a/java/lang/reflect/UndeclaredThrowableException.java b/java/lang/reflect/UndeclaredThrowableException.java
new file mode 100644
index 0000000..a585745
--- /dev/null
+++ b/java/lang/reflect/UndeclaredThrowableException.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1999, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Thrown by a method invocation on a proxy instance if its invocation
+ * handler's {@link InvocationHandler#invoke invoke} method throws a
+ * checked exception (a {@code Throwable} that is not assignable
+ * to {@code RuntimeException} or {@code Error}) that
+ * is not assignable to any of the exception types declared in the
+ * {@code throws} clause of the method that was invoked on the
+ * proxy instance and dispatched to the invocation handler.
+ *
+ * <p>An {@code UndeclaredThrowableException} instance contains
+ * the undeclared checked exception that was thrown by the invocation
+ * handler, and it can be retrieved with the
+ * {@code getUndeclaredThrowable()} method.
+ * {@code UndeclaredThrowableException} extends
+ * {@code RuntimeException}, so it is an unchecked exception
+ * that wraps a checked exception.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to
+ * conform to the general purpose exception-chaining mechanism.  The
+ * "undeclared checked exception that was thrown by the invocation
+ * handler" that may be provided at construction time and accessed via
+ * the {@link #getUndeclaredThrowable()} method is now known as the
+ * <i>cause</i>, and may be accessed via the {@link
+ * Throwable#getCause()} method, as well as the aforementioned "legacy
+ * method."
+ *
+ * @author      Peter Jones
+ * @see         InvocationHandler
+ * @since       1.3
+ */
+public class UndeclaredThrowableException extends RuntimeException {
+    static final long serialVersionUID = 330127114055056639L;
+
+    /**
+     * the undeclared checked exception that was thrown
+     * @serial
+     */
+    private Throwable undeclaredThrowable;
+
+    /**
+     * Constructs an {@code UndeclaredThrowableException} with the
+     * specified {@code Throwable}.
+     *
+     * @param   undeclaredThrowable the undeclared checked exception
+     *          that was thrown
+     */
+    public UndeclaredThrowableException(Throwable undeclaredThrowable) {
+        super((Throwable) null);  // Disallow initCause
+        this.undeclaredThrowable = undeclaredThrowable;
+    }
+
+    /**
+     * Constructs an {@code UndeclaredThrowableException} with the
+     * specified {@code Throwable} and a detail message.
+     *
+     * @param   undeclaredThrowable the undeclared checked exception
+     *          that was thrown
+     * @param   s the detail message
+     */
+    public UndeclaredThrowableException(Throwable undeclaredThrowable,
+                                        String s)
+    {
+        super(s, null);  // Disallow initCause
+        this.undeclaredThrowable = undeclaredThrowable;
+    }
+
+    /**
+     * Returns the {@code Throwable} instance wrapped in this
+     * {@code UndeclaredThrowableException}, which may be {@code null}.
+     *
+     * <p>This method predates the general-purpose exception chaining facility.
+     * The {@link Throwable#getCause()} method is now the preferred means of
+     * obtaining this information.
+     *
+     * @return the undeclared checked exception that was thrown
+     */
+    public Throwable getUndeclaredThrowable() {
+        return undeclaredThrowable;
+    }
+
+    /**
+     * Returns the cause of this exception (the {@code Throwable}
+     * instance wrapped in this {@code UndeclaredThrowableException},
+     * which may be {@code null}).
+     *
+     * @return  the cause of this exception.
+     * @since   1.4
+     */
+    public Throwable getCause() {
+        return undeclaredThrowable;
+    }
+}
diff --git a/java/lang/reflect/WeakCache.java b/java/lang/reflect/WeakCache.java
new file mode 100644
index 0000000..4c28024
--- /dev/null
+++ b/java/lang/reflect/WeakCache.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.reflect;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+
+/**
+ * Cache mapping pairs of {@code (key, sub-key) -> value}. Keys and values are
+ * weakly but sub-keys are strongly referenced.  Keys are passed directly to
+ * {@link #get} method which also takes a {@code parameter}. Sub-keys are
+ * calculated from keys and parameters using the {@code subKeyFactory} function
+ * passed to the constructor. Values are calculated from keys and parameters
+ * using the {@code valueFactory} function passed to the constructor.
+ * Keys can be {@code null} and are compared by identity while sub-keys returned by
+ * {@code subKeyFactory} or values returned by {@code valueFactory}
+ * can not be null. Sub-keys are compared using their {@link #equals} method.
+ * Entries are expunged from cache lazily on each invocation to {@link #get},
+ * {@link #containsValue} or {@link #size} methods when the WeakReferences to
+ * keys are cleared. Cleared WeakReferences to individual values don't cause
+ * expunging, but such entries are logically treated as non-existent and
+ * trigger re-evaluation of {@code valueFactory} on request for their
+ * key/subKey.
+ *
+ * @author Peter Levart
+ * @param <K> type of keys
+ * @param <P> type of parameters
+ * @param <V> type of values
+ */
+final class WeakCache<K, P, V> {
+
+    private final ReferenceQueue<K> refQueue
+        = new ReferenceQueue<>();
+    // the key type is Object for supporting null key
+    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
+        = new ConcurrentHashMap<>();
+    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
+        = new ConcurrentHashMap<>();
+    private final BiFunction<K, P, ?> subKeyFactory;
+    private final BiFunction<K, P, V> valueFactory;
+
+    /**
+     * Construct an instance of {@code WeakCache}
+     *
+     * @param subKeyFactory a function mapping a pair of
+     *                      {@code (key, parameter) -> sub-key}
+     * @param valueFactory  a function mapping a pair of
+     *                      {@code (key, parameter) -> value}
+     * @throws NullPointerException if {@code subKeyFactory} or
+     *                              {@code valueFactory} is null.
+     */
+    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
+                     BiFunction<K, P, V> valueFactory) {
+        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
+        this.valueFactory = Objects.requireNonNull(valueFactory);
+    }
+
+    /**
+     * Look-up the value through the cache. This always evaluates the
+     * {@code subKeyFactory} function and optionally evaluates
+     * {@code valueFactory} function if there is no entry in the cache for given
+     * pair of (key, subKey) or the entry has already been cleared.
+     *
+     * @param key       possibly null key
+     * @param parameter parameter used together with key to create sub-key and
+     *                  value (should not be null)
+     * @return the cached value (never null)
+     * @throws NullPointerException if {@code parameter} passed in or
+     *                              {@code sub-key} calculated by
+     *                              {@code subKeyFactory} or {@code value}
+     *                              calculated by {@code valueFactory} is null.
+     */
+    public V get(K key, P parameter) {
+        Objects.requireNonNull(parameter);
+
+        expungeStaleEntries();
+
+        Object cacheKey = CacheKey.valueOf(key, refQueue);
+
+        // lazily install the 2nd level valuesMap for the particular cacheKey
+        ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
+        if (valuesMap == null) {
+            ConcurrentMap<Object, Supplier<V>> oldValuesMap
+                = map.putIfAbsent(cacheKey,
+                                  valuesMap = new ConcurrentHashMap<>());
+            if (oldValuesMap != null) {
+                valuesMap = oldValuesMap;
+            }
+        }
+
+        // create subKey and retrieve the possible Supplier<V> stored by that
+        // subKey from valuesMap
+        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
+        Supplier<V> supplier = valuesMap.get(subKey);
+        Factory factory = null;
+
+        while (true) {
+            if (supplier != null) {
+                // supplier might be a Factory or a CacheValue<V> instance
+                V value = supplier.get();
+                if (value != null) {
+                    return value;
+                }
+            }
+            // else no supplier in cache
+            // or a supplier that returned null (could be a cleared CacheValue
+            // or a Factory that wasn't successful in installing the CacheValue)
+
+            // lazily construct a Factory
+            if (factory == null) {
+                factory = new Factory(key, parameter, subKey, valuesMap);
+            }
+
+            if (supplier == null) {
+                supplier = valuesMap.putIfAbsent(subKey, factory);
+                if (supplier == null) {
+                    // successfully installed Factory
+                    supplier = factory;
+                }
+                // else retry with winning supplier
+            } else {
+                if (valuesMap.replace(subKey, supplier, factory)) {
+                    // successfully replaced
+                    // cleared CacheEntry / unsuccessful Factory
+                    // with our Factory
+                    supplier = factory;
+                } else {
+                    // retry with current supplier
+                    supplier = valuesMap.get(subKey);
+                }
+            }
+        }
+    }
+
+    /**
+     * Checks whether the specified non-null value is already present in this
+     * {@code WeakCache}. The check is made using identity comparison regardless
+     * of whether value's class overrides {@link Object#equals} or not.
+     *
+     * @param value the non-null value to check
+     * @return true if given {@code value} is already cached
+     * @throws NullPointerException if value is null
+     */
+    public boolean containsValue(V value) {
+        Objects.requireNonNull(value);
+
+        expungeStaleEntries();
+        return reverseMap.containsKey(new LookupValue<>(value));
+    }
+
+    /**
+     * Returns the current number of cached entries that
+     * can decrease over time when keys/values are GC-ed.
+     */
+    public int size() {
+        expungeStaleEntries();
+        return reverseMap.size();
+    }
+
+    private void expungeStaleEntries() {
+        CacheKey<K> cacheKey;
+        while ((cacheKey = (CacheKey<K>)refQueue.poll()) != null) {
+            cacheKey.expungeFrom(map, reverseMap);
+        }
+    }
+
+    /**
+     * A factory {@link Supplier} that implements the lazy synchronized
+     * construction of the value and installment of it into the cache.
+     */
+    private final class Factory implements Supplier<V> {
+
+        private final K key;
+        private final P parameter;
+        private final Object subKey;
+        private final ConcurrentMap<Object, Supplier<V>> valuesMap;
+
+        Factory(K key, P parameter, Object subKey,
+                ConcurrentMap<Object, Supplier<V>> valuesMap) {
+            this.key = key;
+            this.parameter = parameter;
+            this.subKey = subKey;
+            this.valuesMap = valuesMap;
+        }
+
+        @Override
+        public synchronized V get() { // serialize access
+            // re-check
+            Supplier<V> supplier = valuesMap.get(subKey);
+            if (supplier != this) {
+                // something changed while we were waiting:
+                // might be that we were replaced by a CacheValue
+                // or were removed because of failure ->
+                // return null to signal WeakCache.get() to retry
+                // the loop
+                return null;
+            }
+            // else still us (supplier == this)
+
+            // create new value
+            V value = null;
+            try {
+                value = Objects.requireNonNull(valueFactory.apply(key, parameter));
+            } finally {
+                if (value == null) { // remove us on failure
+                    valuesMap.remove(subKey, this);
+                }
+            }
+            // the only path to reach here is with non-null value
+            assert value != null;
+
+            // wrap value with CacheValue (WeakReference)
+            CacheValue<V> cacheValue = new CacheValue<>(value);
+
+            // try replacing us with CacheValue (this should always succeed)
+            if (valuesMap.replace(subKey, this, cacheValue)) {
+                // put also in reverseMap
+                reverseMap.put(cacheValue, Boolean.TRUE);
+            } else {
+                throw new AssertionError("Should not reach here");
+            }
+
+            // successfully replaced us with new CacheValue -> return the value
+            // wrapped by it
+            return value;
+        }
+    }
+
+    /**
+     * Common type of value suppliers that are holding a referent.
+     * The {@link #equals} and {@link #hashCode} of implementations is defined
+     * to compare the referent by identity.
+     */
+    private interface Value<V> extends Supplier<V> {}
+
+    /**
+     * An optimized {@link Value} used to look-up the value in
+     * {@link WeakCache#containsValue} method so that we are not
+     * constructing the whole {@link CacheValue} just to look-up the referent.
+     */
+    private static final class LookupValue<V> implements Value<V> {
+        private final V value;
+
+        LookupValue(V value) {
+            this.value = value;
+        }
+
+        @Override
+        public V get() {
+            return value;
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(value); // compare by identity
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj == this ||
+                   obj instanceof Value &&
+                   this.value == ((Value<?>) obj).get();  // compare by identity
+        }
+    }
+
+    /**
+     * A {@link Value} that weakly references the referent.
+     */
+    private static final class CacheValue<V>
+        extends WeakReference<V> implements Value<V>
+    {
+        private final int hash;
+
+        CacheValue(V value) {
+            super(value);
+            this.hash = System.identityHashCode(value); // compare by identity
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            V value;
+            return obj == this ||
+                   obj instanceof Value &&
+                   // cleared CacheValue is only equal to itself
+                   (value = get()) != null &&
+                   value == ((Value<?>) obj).get(); // compare by identity
+        }
+    }
+
+    /**
+     * CacheKey containing a weakly referenced {@code key}. It registers
+     * itself with the {@code refQueue} so that it can be used to expunge
+     * the entry when the {@link WeakReference} is cleared.
+     */
+    private static final class CacheKey<K> extends WeakReference<K> {
+
+        // a replacement for null keys
+        private static final Object NULL_KEY = new Object();
+
+        static <K> Object valueOf(K key, ReferenceQueue<K> refQueue) {
+            return key == null
+                   // null key means we can't weakly reference it,
+                   // so we use a NULL_KEY singleton as cache key
+                   ? NULL_KEY
+                   // non-null key requires wrapping with a WeakReference
+                   : new CacheKey<>(key, refQueue);
+        }
+
+        private final int hash;
+
+        private CacheKey(K key, ReferenceQueue<K> refQueue) {
+            super(key, refQueue);
+            this.hash = System.identityHashCode(key);  // compare by identity
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            K key;
+            return obj == this ||
+                   obj != null &&
+                   obj.getClass() == this.getClass() &&
+                   // cleared CacheKey is only equal to itself
+                   (key = this.get()) != null &&
+                   // compare key by identity
+                   key == ((CacheKey<K>) obj).get();
+        }
+
+        void expungeFrom(ConcurrentMap<?, ? extends ConcurrentMap<?, ?>> map,
+                         ConcurrentMap<?, Boolean> reverseMap) {
+            // removing just by key is always safe here because after a CacheKey
+            // is cleared and enqueue-ed it is only equal to itself
+            // (see equals method)...
+            ConcurrentMap<?, ?> valuesMap = map.remove(this);
+            // remove also from reverseMap if needed
+            if (valuesMap != null) {
+                for (Object cacheValue : valuesMap.values()) {
+                    reverseMap.remove(cacheValue);
+                }
+            }
+        }
+    }
+}
diff --git a/java/lang/reflect/WildcardType.annotated.java b/java/lang/reflect/WildcardType.annotated.java
new file mode 100644
index 0000000..c8b90a0
--- /dev/null
+++ b/java/lang/reflect/WildcardType.annotated.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.lang.reflect;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface WildcardType extends java.lang.reflect.Type {
+
+public [email protected] Type @libcore.util.NonNull [] getUpperBounds();
+
+public [email protected] Type @libcore.util.NonNull [] getLowerBounds();
+}
diff --git a/java/lang/reflect/WildcardType.java b/java/lang/reflect/WildcardType.java
new file mode 100644
index 0000000..aa8e824
--- /dev/null
+++ b/java/lang/reflect/WildcardType.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * WildcardType represents a wildcard type expression, such as
+ * {@code ?}, {@code ? extends Number}, or {@code ? super Integer}.
+ *
+ * @since 1.5
+ */
+public interface WildcardType extends Type {
+    /**
+     * Returns an array of {@code Type} objects representing the  upper
+     * bound(s) of this type variable.  Note that if no upper bound is
+     * explicitly declared, the upper bound is {@code Object}.
+     *
+     * <p>For each upper bound B :
+     * <ul>
+     *  <li>if B is a parameterized type or a type variable, it is created,
+     *  (see {@link java.lang.reflect.ParameterizedType ParameterizedType}
+     *  for the details of the creation process for parameterized types).
+     *  <li>Otherwise, B is resolved.
+     * </ul>
+     *
+     * @return an array of Types representing the upper bound(s) of this
+     *     type variable
+     * @throws TypeNotPresentException if any of the
+     *     bounds refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if any of the
+     *     bounds refer to a parameterized type that cannot be instantiated
+     *     for any reason
+     */
+    Type[] getUpperBounds();
+
+    /**
+     * Returns an array of {@code Type} objects representing the
+     * lower bound(s) of this type variable.  Note that if no lower bound is
+     * explicitly declared, the lower bound is the type of {@code null}.
+     * In this case, a zero length array is returned.
+     *
+     * <p>For each lower bound B :
+     * <ul>
+     *   <li>if B is a parameterized type or a type variable, it is created,
+     *  (see {@link java.lang.reflect.ParameterizedType ParameterizedType}
+     *  for the details of the creation process for parameterized types).
+     *   <li>Otherwise, B is resolved.
+     * </ul>
+     *
+     * @return an array of Types representing the lower bound(s) of this
+     *     type variable
+     * @throws TypeNotPresentException if any of the
+     *     bounds refers to a non-existent type declaration
+     * @throws MalformedParameterizedTypeException if any of the
+     *     bounds refer to a parameterized type that cannot be instantiated
+     *     for any reason
+     */
+    Type[] getLowerBounds();
+    // one or many? Up to language spec; currently only one, but this API
+    // allows for generalization.
+}
diff --git a/java/lang/reflect/package-info.java b/java/lang/reflect/package-info.java
new file mode 100644
index 0000000..258a07e
--- /dev/null
+++ b/java/lang/reflect/package-info.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides classes and interfaces for obtaining reflective
+ * information about classes and objects.  Reflection allows
+ * programmatic access to information about the fields, methods and
+ * constructors of loaded classes, and the use of reflected fields,
+ * methods, and constructors to operate on their underlying
+ * counterparts, within security restrictions.
+ *
+ * <p>{@code AccessibleObject} allows suppression of access checks if
+ * the necessary {@code ReflectPermission} is available.
+ *
+ * <p>{@code Array} provides static methods to dynamically create and
+ * access arrays.
+ *
+ * <p>Classes in this package, along with {@code java.lang.Class}
+ * accommodate applications such as debuggers, interpreters, object
+ * inspectors, class browsers, and services such as Object
+ * Serialization and JavaBeans that need access to either the public
+ * members of a target object (based on its runtime class) or the
+ * members declared by a given class.
+ *
+ * @since JDK1.1
+ */
+package java.lang.reflect;
diff --git a/java/math/BigDecimal.java b/java/math/BigDecimal.java
new file mode 100644
index 0000000..6ba251b
--- /dev/null
+++ b/java/math/BigDecimal.java
@@ -0,0 +1,2973 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Arrays;
+import libcore.math.MathUtils;
+
+/**
+ * An immutable arbitrary-precision signed decimal.
+ *
+ * <p>A value is represented by an arbitrary-precision "unscaled value" and a signed 32-bit "scale",
+ * combined thus: {@code unscaled * 10<sup>-scale</sup>}. See {@link #unscaledValue} and {@link #scale}.
+ *
+ * <p>Most operations allow you to supply a {@link MathContext} to specify a desired rounding mode.
+ */
+public class BigDecimal extends Number implements Comparable<BigDecimal>, Serializable {
+
+    /**
+     * Rounding mode where positive values are rounded towards positive infinity
+     * and negative values towards negative infinity.
+     *
+     * @see RoundingMode#UP
+     */
+    public static final int ROUND_UP = 0;
+
+    /**
+     * Rounding mode where the values are rounded towards zero.
+     *
+     * @see RoundingMode#DOWN
+     */
+    public static final int ROUND_DOWN = 1;
+
+    /**
+     * Rounding mode to round towards positive infinity. For positive values
+     * this rounding mode behaves as {@link #ROUND_UP}, for negative values as
+     * {@link #ROUND_DOWN}.
+     *
+     * @see RoundingMode#CEILING
+     */
+    public static final int ROUND_CEILING = 2;
+
+    /**
+     * Rounding mode to round towards negative infinity. For positive values
+     * this rounding mode behaves as {@link #ROUND_DOWN}, for negative values as
+     * {@link #ROUND_UP}.
+     *
+     * @see RoundingMode#FLOOR
+     */
+    public static final int ROUND_FLOOR = 3;
+
+    /**
+     * Rounding mode where values are rounded towards the nearest neighbor.
+     * Ties are broken by rounding up.
+     *
+     * @see RoundingMode#HALF_UP
+     */
+    public static final int ROUND_HALF_UP = 4;
+
+    /**
+     * Rounding mode where values are rounded towards the nearest neighbor.
+     * Ties are broken by rounding down.
+     *
+     * @see RoundingMode#HALF_DOWN
+     */
+    public static final int ROUND_HALF_DOWN = 5;
+
+    /**
+     * Rounding mode where values are rounded towards the nearest neighbor.
+     * Ties are broken by rounding to the even neighbor.
+     *
+     * @see RoundingMode#HALF_EVEN
+     */
+    public static final int ROUND_HALF_EVEN = 6;
+
+    /**
+     * Rounding mode where the rounding operations throws an {@code
+     * ArithmeticException} for the case that rounding is necessary, i.e. for
+     * the case that the value cannot be represented exactly.
+     *
+     * @see RoundingMode#UNNECESSARY
+     */
+    public static final int ROUND_UNNECESSARY = 7;
+
+    /** This is the serialVersionUID used by the sun implementation. */
+    private static final long serialVersionUID = 6108874887143696463L;
+
+    /** The double closest to {@code Log10(2)}. */
+    private static final double LOG10_2 = 0.3010299956639812;
+
+    /** The <code>String</code> representation is cached. */
+    private transient String toStringImage = null;
+
+    /** Cache for the hash code. */
+    private transient int hashCode = 0;
+
+    /**
+     * An array with powers of five that fit in the type <code>long</code>
+     * (<code>5^0,5^1,...,5^27</code>).
+     */
+    private static final BigInteger[] FIVE_POW;
+
+    /**
+     * An array with powers of ten that fit in the type <code>long</code>
+     * (<code>10^0,10^1,...,10^18</code>).
+     */
+    private static final BigInteger[] TEN_POW;
+
+    private static final long[] LONG_FIVE_POW = new long[]
+    {   1L,
+        5L,
+        25L,
+        125L,
+        625L,
+        3125L,
+        15625L,
+        78125L,
+        390625L,
+        1953125L,
+        9765625L,
+        48828125L,
+        244140625L,
+        1220703125L,
+        6103515625L,
+        30517578125L,
+        152587890625L,
+        762939453125L,
+        3814697265625L,
+        19073486328125L,
+        95367431640625L,
+        476837158203125L,
+        2384185791015625L,
+        11920928955078125L,
+        59604644775390625L,
+        298023223876953125L,
+        1490116119384765625L,
+        7450580596923828125L, };
+
+    private static final int[] LONG_FIVE_POW_BIT_LENGTH = new int[LONG_FIVE_POW.length];
+    private static final int[] LONG_POWERS_OF_TEN_BIT_LENGTH = new int[MathUtils.LONG_POWERS_OF_TEN.length];
+
+    private static final int BI_SCALED_BY_ZERO_LENGTH = 11;
+
+    /**
+     * An array with the first <code>BigInteger</code> scaled by zero.
+     * (<code>[0,0],[1,0],...,[10,0]</code>).
+     */
+    private static final BigDecimal[] BI_SCALED_BY_ZERO = new BigDecimal[BI_SCALED_BY_ZERO_LENGTH];
+
+    /**
+     * An array with the zero number scaled by the first positive scales.
+     * (<code>0*10^0, 0*10^1, ..., 0*10^10</code>).
+     */
+    private static final BigDecimal[] ZERO_SCALED_BY = new BigDecimal[11];
+
+    /** An array filled with characters <code>'0'</code>. */
+    private static final char[] CH_ZEROS = new char[100];
+
+    static {
+        Arrays.fill(CH_ZEROS, '0');
+
+        for (int i = 0; i < ZERO_SCALED_BY.length; ++i) {
+            BI_SCALED_BY_ZERO[i] = new BigDecimal(i, 0);
+            ZERO_SCALED_BY[i] = new BigDecimal(0, i);
+        }
+        for (int i = 0; i < LONG_FIVE_POW_BIT_LENGTH.length; ++i) {
+            LONG_FIVE_POW_BIT_LENGTH[i] = bitLength(LONG_FIVE_POW[i]);
+        }
+        for (int i = 0; i < LONG_POWERS_OF_TEN_BIT_LENGTH.length; ++i) {
+            LONG_POWERS_OF_TEN_BIT_LENGTH[i] = bitLength(MathUtils.LONG_POWERS_OF_TEN[i]);
+        }
+
+        // Taking the references of useful powers.
+        TEN_POW = Multiplication.bigTenPows;
+        FIVE_POW = Multiplication.bigFivePows;
+    }
+
+    /**
+     * The constant zero as a {@code BigDecimal}.
+     */
+    public static final BigDecimal ZERO = new BigDecimal(0, 0);
+
+    /**
+     * The constant one as a {@code BigDecimal}.
+     */
+    public static final BigDecimal ONE = new BigDecimal(1, 0);
+
+    /**
+     * The constant ten as a {@code BigDecimal}.
+     */
+    public static final BigDecimal TEN = new BigDecimal(10, 0);
+
+    /**
+     * The arbitrary precision integer (unscaled value) in the internal
+     * representation of {@code BigDecimal}.
+     */
+    private BigInteger intVal;
+
+    private transient int bitLength;
+
+    private transient long smallValue;
+
+    /**
+     * The 32-bit integer scale in the internal representation of {@code BigDecimal}.
+     */
+    private int scale;
+
+    /**
+     * Represent the number of decimal digits in the unscaled value. This
+     * precision is calculated the first time, and used in the following calls
+     * of method <code>precision()</code>. Note that some call to the private
+     * method <code>inplaceRound()</code> could update this field.
+     *
+     * @see #precision()
+     * @see #inplaceRound(MathContext)
+     */
+    private transient int precision = 0;
+
+    private BigDecimal(long smallValue, int scale){
+        this.smallValue = smallValue;
+        this.scale = scale;
+        this.bitLength = bitLength(smallValue);
+    }
+
+    private BigDecimal(int smallValue, int scale){
+        this.smallValue = smallValue;
+        this.scale = scale;
+        this.bitLength = bitLength(smallValue);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a string representation
+     * given as a character array.
+     *
+     * @param in
+     *            array of characters containing the string representation of
+     *            this {@code BigDecimal}.
+     * @param offset
+     *            first index to be copied.
+     * @param len
+     *            number of characters to be used.
+     * @throws NumberFormatException
+     *             if {@code offset < 0 || len <= 0 || offset+len-1 < 0 ||
+     *             offset+len-1 >= in.length}, or if {@code in} does not
+     *             contain a valid string representation of a big decimal.
+     */
+    public BigDecimal(char[] in, int offset, int len) {
+        int begin = offset; // first index to be copied
+        int last = offset + (len - 1); // last index to be copied
+        String scaleString; // buffer for scale
+        StringBuilder unscaledBuffer; // buffer for unscaled value
+        long newScale; // the new scale
+
+        if (in == null) {
+            throw new NullPointerException("in == null");
+        }
+        if ((last >= in.length) || (offset < 0) || (len <= 0) || (last < 0)) {
+            throw new NumberFormatException("Bad offset/length: offset=" + offset +
+                    " len=" + len + " in.length=" + in.length);
+        }
+        unscaledBuffer = new StringBuilder(len);
+        int bufLength = 0;
+        // To skip a possible '+' symbol
+        if ((offset <= last) && (in[offset] == '+')) {
+            offset++;
+            begin++;
+        }
+        int counter = 0;
+        boolean wasNonZero = false;
+        // Accumulating all digits until a possible decimal point
+        for (; (offset <= last) && (in[offset] != '.') && (in[offset] != 'e') && (in[offset] != 'E'); offset++) {
+            if (!wasNonZero) {
+                if (in[offset] == '0') {
+                    counter++;
+                } else {
+                    wasNonZero = true;
+                }
+            }
+
+        }
+        unscaledBuffer.append(in, begin, offset - begin);
+        bufLength += offset - begin;
+        // A decimal point was found
+        if ((offset <= last) && (in[offset] == '.')) {
+            offset++;
+            // Accumulating all digits until a possible exponent
+            begin = offset;
+            for (; (offset <= last) && (in[offset] != 'e')
+            && (in[offset] != 'E'); offset++) {
+                if (!wasNonZero) {
+                    if (in[offset] == '0') {
+                        counter++;
+                    } else {
+                        wasNonZero = true;
+                    }
+                }
+            }
+            scale = offset - begin;
+            bufLength +=scale;
+            unscaledBuffer.append(in, begin, scale);
+        } else {
+            scale = 0;
+        }
+        // An exponent was found
+        if ((offset <= last) && ((in[offset] == 'e') || (in[offset] == 'E'))) {
+            offset++;
+            // Checking for a possible sign of scale
+            begin = offset;
+            if ((offset <= last) && (in[offset] == '+')) {
+                offset++;
+                if ((offset <= last) && (in[offset] != '-')) {
+                    begin++;
+                }
+            }
+            // Accumulating all remaining digits
+            scaleString = String.valueOf(in, begin, last + 1 - begin);
+            // Checking if the scale is defined
+            newScale = (long)scale - Integer.parseInt(scaleString);
+            scale = (int)newScale;
+            if (newScale != scale) {
+                throw new NumberFormatException("Scale out of range");
+            }
+        }
+        // Parsing the unscaled value
+        if (bufLength < 19) {
+            smallValue = Long.parseLong(unscaledBuffer.toString());
+            bitLength = bitLength(smallValue);
+        } else {
+            setUnscaledValue(new BigInteger(unscaledBuffer.toString()));
+        }
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a string representation
+     * given as a character array.
+     *
+     * @param in
+     *            array of characters containing the string representation of
+     *            this {@code BigDecimal}.
+     * @param offset
+     *            first index to be copied.
+     * @param len
+     *            number of characters to be used.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws NumberFormatException
+     *             if {@code offset < 0 || len <= 0 || offset+len-1 < 0 ||
+     *             offset+len-1 >= in.length}, or if {@code in} does not
+     *             contain a valid string representation of a big decimal.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(char[] in, int offset, int len, MathContext mc) {
+        this(in, offset, len);
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a string representation
+     * given as a character array.
+     *
+     * @param in
+     *            array of characters containing the string representation of
+     *            this {@code BigDecimal}.
+     * @throws NumberFormatException
+     *             if {@code in} does not contain a valid string representation
+     *             of a big decimal.
+     */
+    public BigDecimal(char[] in) {
+        this(in, 0, in.length);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a string representation
+     * given as a character array. The result is rounded according to the
+     * specified math context.
+     *
+     * @param in
+     *            array of characters containing the string representation of
+     *            this {@code BigDecimal}.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws NumberFormatException
+     *             if {@code in} does not contain a valid string representation
+     *             of a big decimal.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(char[] in, MathContext mc) {
+        this(in, 0, in.length);
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a string
+     * representation.
+     *
+     * @throws NumberFormatException
+     *             if {@code val} does not contain a valid string representation
+     *             of a big decimal.
+     */
+    public BigDecimal(String val) {
+        this(val.toCharArray(), 0, val.length());
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a string
+     * representation. The result is rounded according to the specified math
+     * context.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws NumberFormatException
+     *             if {@code val} does not contain a valid string representation
+     *             of a big decimal.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(String val, MathContext mc) {
+        this(val.toCharArray(), 0, val.length());
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the 64bit double
+     * {@code val}. The constructed big decimal is equivalent to the given
+     * double. For example, {@code new BigDecimal(0.1)} is equal to {@code
+     * 0.1000000000000000055511151231257827021181583404541015625}. This happens
+     * as {@code 0.1} cannot be represented exactly in binary.
+     * <p>
+     * To generate a big decimal instance which is equivalent to {@code 0.1} use
+     * the {@code BigDecimal(String)} constructor.
+     *
+     * @param val
+     *            double value to be converted to a {@code BigDecimal} instance.
+     * @throws NumberFormatException
+     *             if {@code val} is infinity or not a number.
+     */
+    public BigDecimal(double val) {
+        if (Double.isInfinite(val) || Double.isNaN(val)) {
+            throw new NumberFormatException("Infinity or NaN: " + val);
+        }
+        long bits = Double.doubleToLongBits(val); // IEEE-754
+        long mantissa;
+        int trailingZeros;
+        // Extracting the exponent, note that the bias is 1023
+        scale = 1075 - (int)((bits >> 52) & 0x7FFL);
+        // Extracting the 52 bits of the mantissa.
+        mantissa = (scale == 1075) ? (bits & 0xFFFFFFFFFFFFFL) << 1
+                : (bits & 0xFFFFFFFFFFFFFL) | 0x10000000000000L;
+        if (mantissa == 0) {
+            scale = 0;
+            precision = 1;
+        }
+        // To simplify all factors '2' in the mantissa
+        if (scale > 0) {
+            trailingZeros = Math.min(scale, Long.numberOfTrailingZeros(mantissa));
+            mantissa >>>= trailingZeros;
+            scale -= trailingZeros;
+        }
+        // Calculating the new unscaled value and the new scale
+        if((bits >> 63) != 0) {
+            mantissa = -mantissa;
+        }
+        int mantissaBits = bitLength(mantissa);
+        if (scale < 0) {
+            bitLength = mantissaBits == 0 ? 0 : mantissaBits - scale;
+            if(bitLength < 64) {
+                smallValue = mantissa << (-scale);
+            } else {
+                BigInt bi = new BigInt();
+                bi.putLongInt(mantissa);
+                bi.shift(-scale);
+                intVal = new BigInteger(bi);
+            }
+            scale = 0;
+        } else if (scale > 0) {
+            // m * 2^e =  (m * 5^(-e)) * 10^e
+            if(scale < LONG_FIVE_POW.length
+                    && mantissaBits+LONG_FIVE_POW_BIT_LENGTH[scale] < 64) {
+                smallValue = mantissa * LONG_FIVE_POW[scale];
+                bitLength = bitLength(smallValue);
+            } else {
+                setUnscaledValue(Multiplication.multiplyByFivePow(BigInteger.valueOf(mantissa), scale));
+            }
+        } else { // scale == 0
+            smallValue = mantissa;
+            bitLength = mantissaBits;
+        }
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the 64bit double
+     * {@code val}. The constructed big decimal is equivalent to the given
+     * double. For example, {@code new BigDecimal(0.1)} is equal to {@code
+     * 0.1000000000000000055511151231257827021181583404541015625}. This happens
+     * as {@code 0.1} cannot be represented exactly in binary.
+     * <p>
+     * To generate a big decimal instance which is equivalent to {@code 0.1} use
+     * the {@code BigDecimal(String)} constructor.
+     *
+     * @param val
+     *            double value to be converted to a {@code BigDecimal} instance.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws NumberFormatException
+     *             if {@code val} is infinity or not a number.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(double val, MathContext mc) {
+        this(val);
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the given big integer
+     * {@code val}. The scale of the result is {@code 0}.
+     */
+    public BigDecimal(BigInteger val) {
+        this(val, 0);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the given big integer
+     * {@code val}. The scale of the result is {@code 0}.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(BigInteger val, MathContext mc) {
+        this(val);
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a given unscaled value
+     * {@code unscaledVal} and a given scale. The value of this instance is
+     * {@code unscaledVal * 10<sup>-scale</sup>}).
+     *
+     * @throws NullPointerException
+     *             if {@code unscaledVal == null}.
+     */
+    public BigDecimal(BigInteger unscaledVal, int scale) {
+        if (unscaledVal == null) {
+            throw new NullPointerException("unscaledVal == null");
+        }
+        this.scale = scale;
+        setUnscaledValue(unscaledVal);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from a given unscaled value
+     * {@code unscaledVal} and a given scale. The value of this instance is
+     * {@code unscaledVal * 10<sup>-scale</sup>). The result is rounded according
+     * to the specified math context.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     * @throws NullPointerException
+     *             if {@code unscaledVal == null}.
+     */
+    public BigDecimal(BigInteger unscaledVal, int scale, MathContext mc) {
+        this(unscaledVal, scale);
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the given int
+     * {@code val}. The scale of the result is 0.
+     *
+     * @param val
+     *            int value to be converted to a {@code BigDecimal} instance.
+     */
+    public BigDecimal(int val) {
+        this(val,0);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the given int {@code
+     * val}. The scale of the result is {@code 0}. The result is rounded
+     * according to the specified math context.
+     *
+     * @param val
+     *            int value to be converted to a {@code BigDecimal} instance.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code c.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(int val, MathContext mc) {
+        this(val,0);
+        inplaceRound(mc);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the given long {@code
+     * val}. The scale of the result is {@code 0}.
+     *
+     * @param val
+     *            long value to be converted to a {@code BigDecimal} instance.
+     */
+    public BigDecimal(long val) {
+        this(val,0);
+    }
+
+    /**
+     * Constructs a new {@code BigDecimal} instance from the given long {@code
+     * val}. The scale of the result is {@code 0}. The result is rounded
+     * according to the specified math context.
+     *
+     * @param val
+     *            long value to be converted to a {@code BigDecimal} instance.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and the new big decimal cannot be represented
+     *             within the given precision without rounding.
+     */
+    public BigDecimal(long val, MathContext mc) {
+        this(val);
+        inplaceRound(mc);
+    }
+
+    /* Public Methods */
+
+    /**
+     * Returns a new {@code BigDecimal} instance whose value is equal to {@code
+     * unscaledVal * 10<sup>-scale</sup>}). The scale of the result is {@code
+     * scale}, and its unscaled value is {@code unscaledVal}.
+     */
+    public static BigDecimal valueOf(long unscaledVal, int scale) {
+        if (scale == 0) {
+            return valueOf(unscaledVal);
+        }
+        if ((unscaledVal == 0) && (scale >= 0)
+                && (scale < ZERO_SCALED_BY.length)) {
+            return ZERO_SCALED_BY[scale];
+        }
+        return new BigDecimal(unscaledVal, scale);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance whose value is equal to {@code
+     * unscaledVal}. The scale of the result is {@code 0}, and its unscaled
+     * value is {@code unscaledVal}.
+     *
+     * @param unscaledVal
+     *            value to be converted to a {@code BigDecimal}.
+     * @return {@code BigDecimal} instance with the value {@code unscaledVal}.
+     */
+    public static BigDecimal valueOf(long unscaledVal) {
+        if ((unscaledVal >= 0) && (unscaledVal < BI_SCALED_BY_ZERO_LENGTH)) {
+            return BI_SCALED_BY_ZERO[(int)unscaledVal];
+        }
+        return new BigDecimal(unscaledVal,0);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance whose value is equal to {@code
+     * val}. The new decimal is constructed as if the {@code BigDecimal(String)}
+     * constructor is called with an argument which is equal to {@code
+     * Double.toString(val)}. For example, {@code valueOf("0.1")} is converted to
+     * (unscaled=1, scale=1), although the double {@code 0.1} cannot be
+     * represented exactly as a double value. In contrast to that, a new {@code
+     * BigDecimal(0.1)} instance has the value {@code
+     * 0.1000000000000000055511151231257827021181583404541015625} with an
+     * unscaled value {@code 1000000000000000055511151231257827021181583404541015625}
+     * and the scale {@code 55}.
+     *
+     * @param val
+     *            double value to be converted to a {@code BigDecimal}.
+     * @return {@code BigDecimal} instance with the value {@code val}.
+     * @throws NumberFormatException
+     *             if {@code val} is infinite or {@code val} is not a number
+     */
+    public static BigDecimal valueOf(double val) {
+        if (Double.isInfinite(val) || Double.isNaN(val)) {
+            throw new NumberFormatException("Infinity or NaN: " + val);
+        }
+        return new BigDecimal(Double.toString(val));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this + augend}.
+     * The scale of the result is the maximum of the scales of the two
+     * arguments.
+     *
+     * @param augend
+     *            value to be added to {@code this}.
+     * @return {@code this + augend}.
+     * @throws NullPointerException
+     *             if {@code augend == null}.
+     */
+    public BigDecimal add(BigDecimal augend) {
+        int diffScale = this.scale - augend.scale;
+        // Fast return when some operand is zero
+        if (this.isZero()) {
+            if (diffScale <= 0) {
+                return augend;
+            }
+            if (augend.isZero()) {
+                return this;
+            }
+        } else if (augend.isZero()) {
+            if (diffScale >= 0) {
+                return this;
+            }
+        }
+        // Let be:  this = [u1,s1]  and  augend = [u2,s2]
+        if (diffScale == 0) {
+            // case s1 == s2: [u1 + u2 , s1]
+            if (Math.max(this.bitLength, augend.bitLength) + 1 < 64) {
+                return valueOf(this.smallValue + augend.smallValue, this.scale);
+            }
+            return new BigDecimal(this.getUnscaledValue().add(augend.getUnscaledValue()), this.scale);
+        } else if (diffScale > 0) {
+            // case s1 > s2 : [(u1 + u2) * 10 ^ (s1 - s2) , s1]
+            return addAndMult10(this, augend, diffScale);
+        } else {// case s2 > s1 : [(u2 + u1) * 10 ^ (s2 - s1) , s2]
+            return addAndMult10(augend, this, -diffScale);
+        }
+    }
+
+    private static BigDecimal addAndMult10(BigDecimal thisValue,BigDecimal augend, int diffScale) {
+        if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                Math.max(thisValue.bitLength,augend.bitLength+LONG_POWERS_OF_TEN_BIT_LENGTH[diffScale])+1<64) {
+            return valueOf(thisValue.smallValue+augend.smallValue*MathUtils.LONG_POWERS_OF_TEN[diffScale],thisValue.scale);
+        } else {
+            BigInt bi = Multiplication.multiplyByTenPow(augend.getUnscaledValue(),diffScale).getBigInt();
+            bi.add(thisValue.getUnscaledValue().getBigInt());
+            return new BigDecimal(new BigInteger(bi), thisValue.scale);
+        }
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this + augend}.
+     * The result is rounded according to the passed context {@code mc}.
+     *
+     * @param augend
+     *            value to be added to {@code this}.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code this + augend}.
+     * @throws NullPointerException
+     *             if {@code augend == null} or {@code mc == null}.
+     */
+    public BigDecimal add(BigDecimal augend, MathContext mc) {
+        BigDecimal larger; // operand with the largest unscaled value
+        BigDecimal smaller; // operand with the smallest unscaled value
+        BigInteger tempBI;
+        long diffScale = (long)this.scale - augend.scale;
+        int largerSignum;
+        // Some operand is zero or the precision is infinity
+        if ((augend.isZero()) || (this.isZero())
+                || (mc.getPrecision() == 0)) {
+            return add(augend).round(mc);
+        }
+        // Cases where there is room for optimizations
+        if (this.approxPrecision() < diffScale - 1) {
+            larger = augend;
+            smaller = this;
+        } else if (augend.approxPrecision() < -diffScale - 1) {
+            larger = this;
+            smaller = augend;
+        } else {// No optimization is done
+            return add(augend).round(mc);
+        }
+        if (mc.getPrecision() >= larger.approxPrecision()) {
+            // No optimization is done
+            return add(augend).round(mc);
+        }
+        // Cases where it's unnecessary to add two numbers with very different scales
+        largerSignum = larger.signum();
+        if (largerSignum == smaller.signum()) {
+            tempBI = Multiplication.multiplyByPositiveInt(larger.getUnscaledValue(),10)
+            .add(BigInteger.valueOf(largerSignum));
+        } else {
+            tempBI = larger.getUnscaledValue().subtract(
+                    BigInteger.valueOf(largerSignum));
+            tempBI = Multiplication.multiplyByPositiveInt(tempBI,10)
+            .add(BigInteger.valueOf(largerSignum * 9));
+        }
+        // Rounding the improved adding
+        larger = new BigDecimal(tempBI, larger.scale + 1);
+        return larger.round(mc);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this - subtrahend}.
+     * The scale of the result is the maximum of the scales of the two arguments.
+     *
+     * @param subtrahend
+     *            value to be subtracted from {@code this}.
+     * @return {@code this - subtrahend}.
+     * @throws NullPointerException
+     *             if {@code subtrahend == null}.
+     */
+    public BigDecimal subtract(BigDecimal subtrahend) {
+        int diffScale = this.scale - subtrahend.scale;
+        // Fast return when some operand is zero
+        if (this.isZero()) {
+            if (diffScale <= 0) {
+                return subtrahend.negate();
+            }
+            if (subtrahend.isZero()) {
+                return this;
+            }
+        } else if (subtrahend.isZero()) {
+            if (diffScale >= 0) {
+                return this;
+            }
+        }
+        // Let be: this = [u1,s1] and subtrahend = [u2,s2] so:
+        if (diffScale == 0) {
+            // case s1 = s2 : [u1 - u2 , s1]
+            if (Math.max(this.bitLength, subtrahend.bitLength) + 1 < 64) {
+                return valueOf(this.smallValue - subtrahend.smallValue,this.scale);
+            }
+            return new BigDecimal(this.getUnscaledValue().subtract(subtrahend.getUnscaledValue()), this.scale);
+        } else if (diffScale > 0) {
+            // case s1 > s2 : [ u1 - u2 * 10 ^ (s1 - s2) , s1 ]
+            if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                    Math.max(this.bitLength,subtrahend.bitLength+LONG_POWERS_OF_TEN_BIT_LENGTH[diffScale])+1<64) {
+                return valueOf(this.smallValue-subtrahend.smallValue*MathUtils.LONG_POWERS_OF_TEN[diffScale],this.scale);
+            }
+            return new BigDecimal(this.getUnscaledValue().subtract(
+                    Multiplication.multiplyByTenPow(subtrahend.getUnscaledValue(),diffScale)), this.scale);
+        } else {// case s2 > s1 : [ u1 * 10 ^ (s2 - s1) - u2 , s2 ]
+            diffScale = -diffScale;
+            if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                    Math.max(this.bitLength+LONG_POWERS_OF_TEN_BIT_LENGTH[diffScale],subtrahend.bitLength)+1<64) {
+                return valueOf(this.smallValue*MathUtils.LONG_POWERS_OF_TEN[diffScale]-subtrahend.smallValue,subtrahend.scale);
+            }
+            return new BigDecimal(Multiplication.multiplyByTenPow(this.getUnscaledValue(),diffScale)
+            .subtract(subtrahend.getUnscaledValue()), subtrahend.scale);
+        }
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this - subtrahend}.
+     * The result is rounded according to the passed context {@code mc}.
+     *
+     * @param subtrahend
+     *            value to be subtracted from {@code this}.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code this - subtrahend}.
+     * @throws NullPointerException
+     *             if {@code subtrahend == null} or {@code mc == null}.
+     */
+    public BigDecimal subtract(BigDecimal subtrahend, MathContext mc) {
+        long diffScale = subtrahend.scale - (long)this.scale;
+        int thisSignum;
+        BigDecimal leftOperand; // it will be only the left operand (this)
+        BigInteger tempBI;
+        // Some operand is zero or the precision is infinity
+        if ((subtrahend.isZero()) || (this.isZero())
+                || (mc.getPrecision() == 0)) {
+            return subtract(subtrahend).round(mc);
+        }
+        // Now:   this != 0   and   subtrahend != 0
+        if (subtrahend.approxPrecision() < diffScale - 1) {
+            // Cases where it is unnecessary to subtract two numbers with very different scales
+            if (mc.getPrecision() < this.approxPrecision()) {
+                thisSignum = this.signum();
+                if (thisSignum != subtrahend.signum()) {
+                    tempBI = Multiplication.multiplyByPositiveInt(this.getUnscaledValue(), 10)
+                    .add(BigInteger.valueOf(thisSignum));
+                } else {
+                    tempBI = this.getUnscaledValue().subtract(BigInteger.valueOf(thisSignum));
+                    tempBI = Multiplication.multiplyByPositiveInt(tempBI, 10)
+                    .add(BigInteger.valueOf(thisSignum * 9));
+                }
+                // Rounding the improved subtracting
+                leftOperand = new BigDecimal(tempBI, this.scale + 1);
+                return leftOperand.round(mc);
+            }
+        }
+        // No optimization is done
+        return subtract(subtrahend).round(mc);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this *
+     * multiplicand}. The scale of the result is the sum of the scales of the
+     * two arguments.
+     *
+     * @param multiplicand
+     *            value to be multiplied with {@code this}.
+     * @return {@code this * multiplicand}.
+     * @throws NullPointerException
+     *             if {@code multiplicand == null}.
+     */
+    public BigDecimal multiply(BigDecimal multiplicand) {
+        long newScale = (long)this.scale + multiplicand.scale;
+
+        if ((this.isZero()) || (multiplicand.isZero())) {
+            return zeroScaledBy(newScale);
+        }
+        /* Let be: this = [u1,s1] and multiplicand = [u2,s2] so:
+         * this x multiplicand = [ s1 * s2 , s1 + s2 ] */
+        if (this.bitLength + multiplicand.bitLength < 64) {
+            long unscaledValue = this.smallValue * multiplicand.smallValue;
+            // b/19185440 Case where result should be +2^63 but unscaledValue overflowed to -2^63
+            boolean longMultiplicationOverflowed = (unscaledValue == Long.MIN_VALUE) &&
+                    (Math.signum(smallValue) * Math.signum(multiplicand.smallValue) > 0);
+            if (!longMultiplicationOverflowed) {
+                return valueOf(unscaledValue, safeLongToInt(newScale));
+            }
+        }
+        return new BigDecimal(this.getUnscaledValue().multiply(
+                multiplicand.getUnscaledValue()), safeLongToInt(newScale));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this *
+     * multiplicand}. The result is rounded according to the passed context
+     * {@code mc}.
+     *
+     * @param multiplicand
+     *            value to be multiplied with {@code this}.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code this * multiplicand}.
+     * @throws NullPointerException
+     *             if {@code multiplicand == null} or {@code mc == null}.
+     */
+    public BigDecimal multiply(BigDecimal multiplicand, MathContext mc) {
+        BigDecimal result = multiply(multiplicand);
+
+        result.inplaceRound(mc);
+        return result;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
+     * As scale of the result the parameter {@code scale} is used. If rounding
+     * is required to meet the specified scale, then the specified rounding mode
+     * {@code roundingMode} is applied.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param scale
+     *            the scale of the result returned.
+     * @param roundingMode
+     *            rounding mode to be used to round the result.
+     * @return {@code this / divisor} rounded according to the given rounding
+     *         mode.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws IllegalArgumentException
+     *             if {@code roundingMode} is not a valid rounding mode.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code roundingMode == ROUND_UNNECESSARY} and rounding is
+     *             necessary according to the given scale.
+     */
+    public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
+        return divide(divisor, scale, RoundingMode.valueOf(roundingMode));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
+     * As scale of the result the parameter {@code scale} is used. If rounding
+     * is required to meet the specified scale, then the specified rounding mode
+     * {@code roundingMode} is applied.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param scale
+     *            the scale of the result returned.
+     * @param roundingMode
+     *            rounding mode to be used to round the result.
+     * @return {@code this / divisor} rounded according to the given rounding
+     *         mode.
+     * @throws NullPointerException
+     *             if {@code divisor == null} or {@code roundingMode == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code roundingMode == RoundingMode.UNNECESSAR}Y and
+     *             rounding is necessary according to the given scale and given
+     *             precision.
+     */
+    public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode) {
+        // Let be: this = [u1,s1]  and  divisor = [u2,s2]
+        if (roundingMode == null) {
+            throw new NullPointerException("roundingMode == null");
+        }
+        if (divisor.isZero()) {
+            throw new ArithmeticException("Division by zero");
+        }
+
+        long diffScale = ((long)this.scale - divisor.scale) - scale;
+
+        // Check whether the diffScale will fit into an int. See http://b/17393664.
+        if (bitLength(diffScale) > 32) {
+            throw new ArithmeticException(
+                    "Unable to perform divisor / dividend scaling: the difference in scale is too" +
+                            " big (" + diffScale + ")");
+        }
+
+        if(this.bitLength < 64 && divisor.bitLength < 64 ) {
+            if(diffScale == 0) {
+                // http://b/26105053 - corner case: Long.MIN_VALUE / (-1) overflows a long
+                if (this.smallValue != Long.MIN_VALUE || divisor.smallValue != -1) {
+                    return dividePrimitiveLongs(this.smallValue,
+                            divisor.smallValue,
+                            scale,
+                            roundingMode);
+                }
+            } else if(diffScale > 0) {
+                if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                        divisor.bitLength + LONG_POWERS_OF_TEN_BIT_LENGTH[(int)diffScale] < 64) {
+                    return dividePrimitiveLongs(this.smallValue,
+                            divisor.smallValue*MathUtils.LONG_POWERS_OF_TEN[(int)diffScale],
+                            scale,
+                            roundingMode);
+                }
+            } else { // diffScale < 0
+                if(-diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                        this.bitLength + LONG_POWERS_OF_TEN_BIT_LENGTH[(int)-diffScale] < 64) {
+                    return dividePrimitiveLongs(this.smallValue*MathUtils.LONG_POWERS_OF_TEN[(int)-diffScale],
+                            divisor.smallValue,
+                            scale,
+                            roundingMode);
+                }
+
+            }
+        }
+        BigInteger scaledDividend = this.getUnscaledValue();
+        BigInteger scaledDivisor = divisor.getUnscaledValue(); // for scaling of 'u2'
+
+        if (diffScale > 0) {
+            // Multiply 'u2'  by:  10^((s1 - s2) - scale)
+            scaledDivisor = Multiplication.multiplyByTenPow(scaledDivisor, (int)diffScale);
+        } else if (diffScale < 0) {
+            // Multiply 'u1'  by:  10^(scale - (s1 - s2))
+            scaledDividend  = Multiplication.multiplyByTenPow(scaledDividend, (int)-diffScale);
+        }
+        return divideBigIntegers(scaledDividend, scaledDivisor, scale, roundingMode);
+        }
+
+    private static BigDecimal divideBigIntegers(BigInteger scaledDividend, BigInteger scaledDivisor, int scale, RoundingMode roundingMode) {
+
+        BigInteger[] quotAndRem = scaledDividend.divideAndRemainder(scaledDivisor);  // quotient and remainder
+        // If after division there is a remainder...
+        BigInteger quotient = quotAndRem[0];
+        BigInteger remainder = quotAndRem[1];
+        if (remainder.signum() == 0) {
+            return new BigDecimal(quotient, scale);
+        }
+        int sign = scaledDividend.signum() * scaledDivisor.signum();
+        int compRem;                                      // 'compare to remainder'
+        if(scaledDivisor.bitLength() < 63) { // 63 in order to avoid out of long after *2
+            long rem = remainder.longValue();
+            long divisor = scaledDivisor.longValue();
+            compRem = compareForRounding(rem, divisor);
+            // To look if there is a carry
+            compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0,
+                    sign * (5 + compRem), roundingMode);
+
+        } else {
+            // Checking if:  remainder * 2 >= scaledDivisor
+            compRem = remainder.abs().shiftLeftOneBit().compareTo(scaledDivisor.abs());
+            compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0,
+                    sign * (5 + compRem), roundingMode);
+        }
+            if (compRem != 0) {
+            if(quotient.bitLength() < 63) {
+                return valueOf(quotient.longValue() + compRem,scale);
+            }
+            quotient = quotient.add(BigInteger.valueOf(compRem));
+            return new BigDecimal(quotient, scale);
+        }
+        // Constructing the result with the appropriate unscaled value
+        return new BigDecimal(quotient, scale);
+    }
+
+    private static BigDecimal dividePrimitiveLongs(long scaledDividend, long scaledDivisor, int scale, RoundingMode roundingMode) {
+        long quotient = scaledDividend / scaledDivisor;
+        long remainder = scaledDividend % scaledDivisor;
+        int sign = Long.signum( scaledDividend ) * Long.signum( scaledDivisor );
+        if (remainder != 0) {
+            // Checking if:  remainder * 2 >= scaledDivisor
+            int compRem = compareForRounding(remainder, scaledDivisor); // 'compare to remainder'
+            // To look if there is a carry
+            quotient += roundingBehavior(((int)quotient) & 1,
+                    sign * (5 + compRem),
+                    roundingMode);
+        }
+        // Constructing the result with the appropriate unscaled value
+        return valueOf(quotient, scale);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
+     * The scale of the result is the scale of {@code this}. If rounding is
+     * required to meet the specified scale, then the specified rounding mode
+     * {@code roundingMode} is applied.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param roundingMode
+     *            rounding mode to be used to round the result.
+     * @return {@code this / divisor} rounded according to the given rounding
+     *         mode.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws IllegalArgumentException
+     *             if {@code roundingMode} is not a valid rounding mode.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code roundingMode == ROUND_UNNECESSARY} and rounding is
+     *             necessary according to the scale of this.
+     */
+    public BigDecimal divide(BigDecimal divisor, int roundingMode) {
+        return divide(divisor, scale, RoundingMode.valueOf(roundingMode));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
+     * The scale of the result is the scale of {@code this}. If rounding is
+     * required to meet the specified scale, then the specified rounding mode
+     * {@code roundingMode} is applied.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param roundingMode
+     *            rounding mode to be used to round the result.
+     * @return {@code this / divisor} rounded according to the given rounding
+     *         mode.
+     * @throws NullPointerException
+     *             if {@code divisor == null} or {@code roundingMode == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code roundingMode == RoundingMode.UNNECESSARY} and
+     *             rounding is necessary according to the scale of this.
+     */
+    public BigDecimal divide(BigDecimal divisor, RoundingMode roundingMode) {
+        return divide(divisor, scale, roundingMode);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
+     * The scale of the result is the difference of the scales of {@code this}
+     * and {@code divisor}. If the exact result requires more digits, then the
+     * scale is adjusted accordingly. For example, {@code 1/128 = 0.0078125}
+     * which has a scale of {@code 7} and precision {@code 5}.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @return {@code this / divisor}.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if the result cannot be represented exactly.
+     */
+    public BigDecimal divide(BigDecimal divisor) {
+        BigInteger p = this.getUnscaledValue();
+        BigInteger q = divisor.getUnscaledValue();
+        BigInteger gcd; // greatest common divisor between 'p' and 'q'
+        BigInteger quotAndRem[];
+        long diffScale = (long)scale - divisor.scale;
+        int newScale; // the new scale for final quotient
+        int k; // number of factors "2" in 'q'
+        int l = 0; // number of factors "5" in 'q'
+        int i = 1;
+        int lastPow = FIVE_POW.length - 1;
+
+        if (divisor.isZero()) {
+            throw new ArithmeticException("Division by zero");
+        }
+        if (p.signum() == 0) {
+            return zeroScaledBy(diffScale);
+        }
+        // To divide both by the GCD
+        gcd = p.gcd(q);
+        p = p.divide(gcd);
+        q = q.divide(gcd);
+        // To simplify all "2" factors of q, dividing by 2^k
+        k = q.getLowestSetBit();
+        q = q.shiftRight(k);
+        // To simplify all "5" factors of q, dividing by 5^l
+        do {
+            quotAndRem = q.divideAndRemainder(FIVE_POW[i]);
+            if (quotAndRem[1].signum() == 0) {
+                l += i;
+                if (i < lastPow) {
+                    i++;
+                }
+                q = quotAndRem[0];
+            } else {
+                if (i == 1) {
+                    break;
+                }
+                i = 1;
+            }
+        } while (true);
+        // If  abs(q) != 1  then the quotient is periodic
+        if (!q.abs().equals(BigInteger.ONE)) {
+            throw new ArithmeticException("Non-terminating decimal expansion; no exact representable decimal result");
+        }
+        // The sign of the is fixed and the quotient will be saved in 'p'
+        if (q.signum() < 0) {
+            p = p.negate();
+        }
+        // Checking if the new scale is out of range
+        newScale = safeLongToInt(diffScale + Math.max(k, l));
+        // k >= 0  and  l >= 0  implies that  k - l  is in the 32-bit range
+        i = k - l;
+
+        p = (i > 0) ? Multiplication.multiplyByFivePow(p, i)
+        : p.shiftLeft(-i);
+        return new BigDecimal(p, newScale);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this / divisor}.
+     * The result is rounded according to the passed context {@code mc}. If the
+     * passed math context specifies precision {@code 0}, then this call is
+     * equivalent to {@code this.divide(divisor)}.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code this / divisor}.
+     * @throws NullPointerException
+     *             if {@code divisor == null} or {@code mc == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code mc.getRoundingMode() == UNNECESSARY} and rounding
+     *             is necessary according {@code mc.getPrecision()}.
+     */
+    public BigDecimal divide(BigDecimal divisor, MathContext mc) {
+        /* Calculating how many zeros must be append to 'dividend'
+         * to obtain a  quotient with at least 'mc.precision()' digits */
+        long trailingZeros = mc.getPrecision() + 2L
+                + divisor.approxPrecision() - approxPrecision();
+        long diffScale = (long)scale - divisor.scale;
+        long newScale = diffScale; // scale of the final quotient
+        int compRem; // to compare the remainder
+        int i = 1; // index
+        int lastPow = TEN_POW.length - 1; // last power of ten
+        BigInteger integerQuot; // for temporal results
+        BigInteger quotAndRem[] = {getUnscaledValue()};
+        // In special cases it reduces the problem to call the dual method
+        if ((mc.getPrecision() == 0) || (this.isZero())
+        || (divisor.isZero())) {
+            return this.divide(divisor);
+        }
+        if (trailingZeros > 0) {
+            // To append trailing zeros at end of dividend
+            quotAndRem[0] = getUnscaledValue().multiply( Multiplication.powerOf10(trailingZeros) );
+            newScale += trailingZeros;
+        }
+        quotAndRem = quotAndRem[0].divideAndRemainder( divisor.getUnscaledValue() );
+        integerQuot = quotAndRem[0];
+        // Calculating the exact quotient with at least 'mc.precision()' digits
+        if (quotAndRem[1].signum() != 0) {
+            // Checking if:   2 * remainder >= divisor ?
+            compRem = quotAndRem[1].shiftLeftOneBit().compareTo( divisor.getUnscaledValue() );
+            // quot := quot * 10 + r;     with 'r' in {-6,-5,-4, 0,+4,+5,+6}
+            integerQuot = integerQuot.multiply(BigInteger.TEN)
+            .add(BigInteger.valueOf(quotAndRem[0].signum() * (5 + compRem)));
+            newScale++;
+        } else {
+            // To strip trailing zeros until the preferred scale is reached
+            while (!integerQuot.testBit(0)) {
+                quotAndRem = integerQuot.divideAndRemainder(TEN_POW[i]);
+                if ((quotAndRem[1].signum() == 0)
+                        && (newScale - i >= diffScale)) {
+                    newScale -= i;
+                    if (i < lastPow) {
+                        i++;
+                    }
+                    integerQuot = quotAndRem[0];
+                } else {
+                    if (i == 1) {
+                        break;
+                    }
+                    i = 1;
+                }
+            }
+        }
+        // To perform rounding
+        return new BigDecimal(integerQuot, safeLongToInt(newScale), mc);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is the integral part of
+     * {@code this / divisor}. The quotient is rounded down towards zero to the
+     * next integer. For example, {@code 0.5/0.2 = 2}.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @return integral part of {@code this / divisor}.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     */
+    public BigDecimal divideToIntegralValue(BigDecimal divisor) {
+        BigInteger integralValue; // the integer of result
+        BigInteger powerOfTen; // some power of ten
+
+        long newScale = (long)this.scale - divisor.scale;
+        long tempScale = 0;
+        int i = 1;
+        int lastPow = TEN_POW.length - 1;
+
+        if (divisor.isZero()) {
+            throw new ArithmeticException("Division by zero");
+        }
+        if ((divisor.approxPrecision() + newScale > this.approxPrecision() + 1L)
+        || (this.isZero())) {
+            /* If the divisor's integer part is greater than this's integer part,
+             * the result must be zero with the appropriate scale */
+            integralValue = BigInteger.ZERO;
+        } else if (newScale == 0) {
+            integralValue = getUnscaledValue().divide( divisor.getUnscaledValue() );
+        } else if (newScale > 0) {
+            powerOfTen = Multiplication.powerOf10(newScale);
+            integralValue = getUnscaledValue().divide( divisor.getUnscaledValue().multiply(powerOfTen) );
+            integralValue = integralValue.multiply(powerOfTen);
+        } else {// (newScale < 0)
+            powerOfTen = Multiplication.powerOf10(-newScale);
+            integralValue = getUnscaledValue().multiply(powerOfTen).divide( divisor.getUnscaledValue() );
+            // To strip trailing zeros approximating to the preferred scale
+            while (!integralValue.testBit(0)) {
+                BigInteger[] quotAndRem = integralValue.divideAndRemainder(TEN_POW[i]);
+                if ((quotAndRem[1].signum() == 0)
+                        && (tempScale - i >= newScale)) {
+                    tempScale -= i;
+                    if (i < lastPow) {
+                        i++;
+                    }
+                    integralValue = quotAndRem[0];
+                } else {
+                    if (i == 1) {
+                        break;
+                    }
+                    i = 1;
+                }
+            }
+            newScale = tempScale;
+        }
+        return ((integralValue.signum() == 0)
+        ? zeroScaledBy(newScale)
+                : new BigDecimal(integralValue, safeLongToInt(newScale)));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is the integral part of
+     * {@code this / divisor}. The quotient is rounded down towards zero to the
+     * next integer. The rounding mode passed with the parameter {@code mc} is
+     * not considered. But if the precision of {@code mc > 0} and the integral
+     * part requires more digits, then an {@code ArithmeticException} is thrown.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param mc
+     *            math context which determines the maximal precision of the
+     *            result.
+     * @return integral part of {@code this / divisor}.
+     * @throws NullPointerException
+     *             if {@code divisor == null} or {@code mc == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code mc.getPrecision() > 0} and the result requires more
+     *             digits to be represented.
+     */
+    public BigDecimal divideToIntegralValue(BigDecimal divisor, MathContext mc) {
+        int mcPrecision = mc.getPrecision();
+        int diffPrecision = this.precision() - divisor.precision();
+        int lastPow = TEN_POW.length - 1;
+        long diffScale = (long)this.scale - divisor.scale;
+        long newScale = diffScale;
+        long quotPrecision = diffPrecision - diffScale + 1;
+        BigInteger quotAndRem[] = new BigInteger[2];
+        // In special cases it call the dual method
+        if ((mcPrecision == 0) || (this.isZero()) || (divisor.isZero())) {
+            return this.divideToIntegralValue(divisor);
+        }
+        // Let be:   this = [u1,s1]   and   divisor = [u2,s2]
+        if (quotPrecision <= 0) {
+            quotAndRem[0] = BigInteger.ZERO;
+        } else if (diffScale == 0) {
+            // CASE s1 == s2:  to calculate   u1 / u2
+            quotAndRem[0] = this.getUnscaledValue().divide( divisor.getUnscaledValue() );
+        } else if (diffScale > 0) {
+            // CASE s1 >= s2:  to calculate   u1 / (u2 * 10^(s1-s2)
+            quotAndRem[0] = this.getUnscaledValue().divide(
+                    divisor.getUnscaledValue().multiply(Multiplication.powerOf10(diffScale)) );
+            // To chose  10^newScale  to get a quotient with at least 'mc.precision()' digits
+            newScale = Math.min(diffScale, Math.max(mcPrecision - quotPrecision + 1, 0));
+            // To calculate: (u1 / (u2 * 10^(s1-s2)) * 10^newScale
+            quotAndRem[0] = quotAndRem[0].multiply(Multiplication.powerOf10(newScale));
+        } else {// CASE s2 > s1:
+            /* To calculate the minimum power of ten, such that the quotient
+             *   (u1 * 10^exp) / u2   has at least 'mc.precision()' digits. */
+            long exp = Math.min(-diffScale, Math.max((long)mcPrecision - diffPrecision, 0));
+            long compRemDiv;
+            // Let be:   (u1 * 10^exp) / u2 = [q,r]
+            quotAndRem = this.getUnscaledValue().multiply(Multiplication.powerOf10(exp)).
+                    divideAndRemainder(divisor.getUnscaledValue());
+            newScale += exp; // To fix the scale
+            exp = -newScale; // The remaining power of ten
+            // If after division there is a remainder...
+            if ((quotAndRem[1].signum() != 0) && (exp > 0)) {
+                // Log10(r) + ((s2 - s1) - exp) > mc.precision ?
+                compRemDiv = (new BigDecimal(quotAndRem[1])).precision()
+                + exp - divisor.precision();
+                if (compRemDiv == 0) {
+                    // To calculate:  (r * 10^exp2) / u2
+                    quotAndRem[1] = quotAndRem[1].multiply(Multiplication.powerOf10(exp)).
+                            divide(divisor.getUnscaledValue());
+                    compRemDiv = Math.abs(quotAndRem[1].signum());
+                }
+                if (compRemDiv > 0) {
+                    throw new ArithmeticException("Division impossible");
+                }
+            }
+        }
+        // Fast return if the quotient is zero
+        if (quotAndRem[0].signum() == 0) {
+            return zeroScaledBy(diffScale);
+        }
+        BigInteger strippedBI = quotAndRem[0];
+        BigDecimal integralValue = new BigDecimal(quotAndRem[0]);
+        long resultPrecision = integralValue.precision();
+        int i = 1;
+        // To strip trailing zeros until the specified precision is reached
+        while (!strippedBI.testBit(0)) {
+            quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]);
+            if ((quotAndRem[1].signum() == 0) &&
+                    ((resultPrecision - i >= mcPrecision)
+                    || (newScale - i >= diffScale)) ) {
+                resultPrecision -= i;
+                newScale -= i;
+                if (i < lastPow) {
+                    i++;
+                }
+                strippedBI = quotAndRem[0];
+            } else {
+                if (i == 1) {
+                    break;
+                }
+                i = 1;
+            }
+        }
+        // To check if the result fit in 'mc.precision()' digits
+        if (resultPrecision > mcPrecision) {
+            throw new ArithmeticException("Division impossible");
+        }
+        integralValue.scale = safeLongToInt(newScale);
+        integralValue.setUnscaledValue(strippedBI);
+        return integralValue;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this % divisor}.
+     * <p>
+     * The remainder is defined as {@code this -
+     * this.divideToIntegralValue(divisor) * divisor}.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @return {@code this % divisor}.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     */
+    public BigDecimal remainder(BigDecimal divisor) {
+        return divideAndRemainder(divisor)[1];
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this % divisor}.
+     * <p>
+     * The remainder is defined as {@code this -
+     * this.divideToIntegralValue(divisor) * divisor}.
+     * <p>
+     * The specified rounding mode {@code mc} is used for the division only.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param mc
+     *            rounding mode and precision to be used.
+     * @return {@code this % divisor}.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @throws ArithmeticException
+     *             if {@code mc.getPrecision() > 0} and the result of {@code
+     *             this.divideToIntegralValue(divisor, mc)} requires more digits
+     *             to be represented.
+     */
+    public BigDecimal remainder(BigDecimal divisor, MathContext mc) {
+        return divideAndRemainder(divisor, mc)[1];
+    }
+
+    /**
+     * Returns a {@code BigDecimal} array which contains the integral part of
+     * {@code this / divisor} at index 0 and the remainder {@code this %
+     * divisor} at index 1. The quotient is rounded down towards zero to the
+     * next integer.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @return {@code [this.divideToIntegralValue(divisor),
+     *         this.remainder(divisor)]}.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @see #divideToIntegralValue
+     * @see #remainder
+     */
+    public BigDecimal[] divideAndRemainder(BigDecimal divisor) {
+        BigDecimal quotAndRem[] = new BigDecimal[2];
+
+        quotAndRem[0] = this.divideToIntegralValue(divisor);
+        quotAndRem[1] = this.subtract( quotAndRem[0].multiply(divisor) );
+        return quotAndRem;
+    }
+
+    /**
+     * Returns a {@code BigDecimal} array which contains the integral part of
+     * {@code this / divisor} at index 0 and the remainder {@code this %
+     * divisor} at index 1. The quotient is rounded down towards zero to the
+     * next integer. The rounding mode passed with the parameter {@code mc} is
+     * not considered. But if the precision of {@code mc > 0} and the integral
+     * part requires more digits, then an {@code ArithmeticException} is thrown.
+     *
+     * @param divisor
+     *            value by which {@code this} is divided.
+     * @param mc
+     *            math context which determines the maximal precision of the
+     *            result.
+     * @return {@code [this.divideToIntegralValue(divisor),
+     *         this.remainder(divisor)]}.
+     * @throws NullPointerException
+     *             if {@code divisor == null}.
+     * @throws ArithmeticException
+     *             if {@code divisor == 0}.
+     * @see #divideToIntegralValue
+     * @see #remainder
+     */
+    public BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc) {
+        BigDecimal quotAndRem[] = new BigDecimal[2];
+
+        quotAndRem[0] = this.divideToIntegralValue(divisor, mc);
+        quotAndRem[1] = this.subtract( quotAndRem[0].multiply(divisor) );
+        return quotAndRem;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this<sup>n</sup>}. The
+     * scale of the result is {@code n * this.scale()}.
+     *
+     * <p>{@code x.pow(0)} returns {@code 1}, even if {@code x == 0}.
+     *
+     * <p>Implementation Note: The implementation is based on the ANSI standard
+     * X3.274-1996 algorithm.
+     *
+     * @throws ArithmeticException
+     *             if {@code n < 0} or {@code n > 999999999}.
+     */
+    public BigDecimal pow(int n) {
+        if (n == 0) {
+            return ONE;
+        }
+        if ((n < 0) || (n > 999999999)) {
+            throw new ArithmeticException("Invalid operation");
+        }
+        long newScale = scale * (long)n;
+        // Let be: this = [u,s]   so:  this^n = [u^n, s*n]
+        return isZero() ? zeroScaledBy(newScale)
+                : new BigDecimal(getUnscaledValue().pow(n), safeLongToInt(newScale));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this<sup>n</sup>}. The
+     * result is rounded according to the passed context {@code mc}.
+     *
+     * <p>Implementation Note: The implementation is based on the ANSI standard
+     * X3.274-1996 algorithm.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @throws ArithmeticException
+     *             if {@code n < 0} or {@code n > 999999999}.
+     */
+    public BigDecimal pow(int n, MathContext mc) {
+        // The ANSI standard X3.274-1996 algorithm
+        int m = Math.abs(n);
+        int mcPrecision = mc.getPrecision();
+        int elength = (int)Math.log10(m) + 1;   // decimal digits in 'n'
+        int oneBitMask; // mask of bits
+        BigDecimal accum; // the single accumulator
+        MathContext newPrecision = mc; // MathContext by default
+
+        // In particular cases, it reduces the problem to call the other 'pow()'
+        if ((n == 0) || ((isZero()) && (n > 0))) {
+            return pow(n);
+        }
+        if ((m > 999999999) || ((mcPrecision == 0) && (n < 0))
+                || ((mcPrecision > 0) && (elength > mcPrecision))) {
+            throw new ArithmeticException("Invalid operation");
+        }
+        if (mcPrecision > 0) {
+            newPrecision = new MathContext( mcPrecision + elength + 1,
+                    mc.getRoundingMode());
+        }
+        // The result is calculated as if 'n' were positive
+        accum = round(newPrecision);
+        oneBitMask = Integer.highestOneBit(m) >> 1;
+
+        while (oneBitMask > 0) {
+            accum = accum.multiply(accum, newPrecision);
+            if ((m & oneBitMask) == oneBitMask) {
+                accum = accum.multiply(this, newPrecision);
+            }
+            oneBitMask >>= 1;
+        }
+        // If 'n' is negative, the value is divided into 'ONE'
+        if (n < 0) {
+            accum = ONE.divide(accum, newPrecision);
+        }
+        // The final value is rounded to the destination precision
+        accum.inplaceRound(mc);
+        return accum;
+    }
+
+    /**
+     * Returns a {@code BigDecimal} whose value is the absolute value of
+     * {@code this}. The scale of the result is the same as the scale of this.
+     */
+    public BigDecimal abs() {
+        return ((signum() < 0) ? negate() : this);
+    }
+
+    /**
+     * Returns a {@code BigDecimal} whose value is the absolute value of
+     * {@code this}. The result is rounded according to the passed context
+     * {@code mc}.
+     */
+    public BigDecimal abs(MathContext mc) {
+        BigDecimal result = (signum() < 0) ? negate() : new BigDecimal(getUnscaledValue(), scale);
+        result.inplaceRound(mc);
+        return result;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is the {@code -this}. The
+     * scale of the result is the same as the scale of this.
+     *
+     * @return {@code -this}
+     */
+    public BigDecimal negate() {
+        if(bitLength < 63 || (bitLength == 63 && smallValue!=Long.MIN_VALUE)) {
+            return valueOf(-smallValue,scale);
+        }
+        return new BigDecimal(getUnscaledValue().negate(), scale);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is the {@code -this}. The
+     * result is rounded according to the passed context {@code mc}.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code -this}
+     */
+    public BigDecimal negate(MathContext mc) {
+        BigDecimal result = negate();
+        result.inplaceRound(mc);
+        return result;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code +this}. The scale
+     * of the result is the same as the scale of this.
+     *
+     * @return {@code this}
+     */
+    public BigDecimal plus() {
+        return this;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code +this}. The result
+     * is rounded according to the passed context {@code mc}.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code this}, rounded
+     */
+    public BigDecimal plus(MathContext mc) {
+        return round(mc);
+    }
+
+    /**
+     * Returns the sign of this {@code BigDecimal}.
+     *
+     * @return {@code -1} if {@code this < 0},
+     *         {@code 0} if {@code this == 0},
+     *         {@code 1} if {@code this > 0}.
+     */
+    public int signum() {
+        if( bitLength < 64) {
+            return Long.signum( this.smallValue );
+        }
+        return getUnscaledValue().signum();
+    }
+
+    private boolean isZero() {
+        //Watch out: -1 has a bitLength=0
+        return bitLength == 0 && this.smallValue != -1;
+    }
+
+    /**
+     * Returns the scale of this {@code BigDecimal}. The scale is the number of
+     * digits behind the decimal point. The value of this {@code BigDecimal} is
+     * the {@code unsignedValue * 10<sup>-scale</sup>}. If the scale is negative,
+     * then this {@code BigDecimal} represents a big integer.
+     *
+     * @return the scale of this {@code BigDecimal}.
+     */
+    public int scale() {
+        return scale;
+    }
+
+    /**
+     * Returns the precision of this {@code BigDecimal}. The precision is the
+     * number of decimal digits used to represent this decimal. It is equivalent
+     * to the number of digits of the unscaled value. The precision of {@code 0}
+     * is {@code 1} (independent of the scale).
+     *
+     * @return the precision of this {@code BigDecimal}.
+     */
+    public int precision() {
+        // Return the cached value if we have one.
+        if (precision != 0) {
+            return precision;
+        }
+
+        if (bitLength == 0) {
+            precision = 1;
+        } else if (bitLength < 64) {
+            precision = decimalDigitsInLong(smallValue);
+        } else {
+            int decimalDigits = 1 + (int) ((bitLength - 1) * LOG10_2);
+            // If after division the number isn't zero, there exists an additional digit
+            if (getUnscaledValue().divide(Multiplication.powerOf10(decimalDigits)).signum() != 0) {
+                decimalDigits++;
+            }
+            precision = decimalDigits;
+        }
+        return precision;
+    }
+
+    private int decimalDigitsInLong(long value) {
+        if (value == Long.MIN_VALUE) {
+            return 19; // special case required because abs(MIN_VALUE) == MIN_VALUE
+        } else {
+            int index = Arrays.binarySearch(MathUtils.LONG_POWERS_OF_TEN, Math.abs(value));
+            return (index < 0) ? (-index - 1) : (index + 1);
+        }
+    }
+
+    /**
+     * Returns the unscaled value (mantissa) of this {@code BigDecimal} instance
+     * as a {@code BigInteger}. The unscaled value can be computed as
+     * {@code this * 10<sup>scale</sup>}.
+     */
+    public BigInteger unscaledValue() {
+        return getUnscaledValue();
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this}, rounded
+     * according to the passed context {@code mc}.
+     * <p>
+     * If {@code mc.precision = 0}, then no rounding is performed.
+     * <p>
+     * If {@code mc.precision > 0} and {@code mc.roundingMode == UNNECESSARY},
+     * then an {@code ArithmeticException} is thrown if the result cannot be
+     * represented exactly within the given precision.
+     *
+     * @param mc
+     *            rounding mode and precision for the result of this operation.
+     * @return {@code this} rounded according to the passed context.
+     * @throws ArithmeticException
+     *             if {@code mc.precision > 0} and {@code mc.roundingMode ==
+     *             UNNECESSARY} and this cannot be represented within the given
+     *             precision.
+     */
+    public BigDecimal round(MathContext mc) {
+        BigDecimal thisBD = new BigDecimal(getUnscaledValue(), scale);
+
+        thisBD.inplaceRound(mc);
+        return thisBD;
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance with the specified scale.
+     * <p>
+     * If the new scale is greater than the old scale, then additional zeros are
+     * added to the unscaled value. In this case no rounding is necessary.
+     * <p>
+     * If the new scale is smaller than the old scale, then trailing digits are
+     * removed. If these trailing digits are not zero, then the remaining
+     * unscaled value has to be rounded. For this rounding operation the
+     * specified rounding mode is used.
+     *
+     * @param newScale
+     *            scale of the result returned.
+     * @param roundingMode
+     *            rounding mode to be used to round the result.
+     * @return a new {@code BigDecimal} instance with the specified scale.
+     * @throws NullPointerException
+     *             if {@code roundingMode == null}.
+     * @throws ArithmeticException
+     *             if {@code roundingMode == ROUND_UNNECESSARY} and rounding is
+     *             necessary according to the given scale.
+     */
+    public BigDecimal setScale(int newScale, RoundingMode roundingMode) {
+        if (roundingMode == null) {
+            throw new NullPointerException("roundingMode == null");
+        }
+        long diffScale = newScale - (long)scale;
+        // Let be:  'this' = [u,s]
+        if(diffScale == 0) {
+            return this;
+        }
+        if(diffScale > 0) {
+        // return  [u * 10^(s2 - s), newScale]
+            if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                    (this.bitLength + LONG_POWERS_OF_TEN_BIT_LENGTH[(int)diffScale]) < 64 ) {
+                return valueOf(this.smallValue*MathUtils.LONG_POWERS_OF_TEN[(int)diffScale],newScale);
+            }
+            return new BigDecimal(Multiplication.multiplyByTenPow(getUnscaledValue(),(int)diffScale), newScale);
+        }
+        // diffScale < 0
+        // return  [u,s] / [1,newScale]  with the appropriate scale and rounding
+        if(this.bitLength < 64 && -diffScale < MathUtils.LONG_POWERS_OF_TEN.length) {
+            return dividePrimitiveLongs(this.smallValue, MathUtils.LONG_POWERS_OF_TEN[(int)-diffScale], newScale,roundingMode);
+        }
+        return divideBigIntegers(this.getUnscaledValue(),Multiplication.powerOf10(-diffScale),newScale,roundingMode);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance with the specified scale.
+     * <p>
+     * If the new scale is greater than the old scale, then additional zeros are
+     * added to the unscaled value. In this case no rounding is necessary.
+     * <p>
+     * If the new scale is smaller than the old scale, then trailing digits are
+     * removed. If these trailing digits are not zero, then the remaining
+     * unscaled value has to be rounded. For this rounding operation the
+     * specified rounding mode is used.
+     *
+     * @param newScale
+     *            scale of the result returned.
+     * @param roundingMode
+     *            rounding mode to be used to round the result.
+     * @return a new {@code BigDecimal} instance with the specified scale.
+     * @throws IllegalArgumentException
+     *             if {@code roundingMode} is not a valid rounding mode.
+     * @throws ArithmeticException
+     *             if {@code roundingMode == ROUND_UNNECESSARY} and rounding is
+     *             necessary according to the given scale.
+     */
+    public BigDecimal setScale(int newScale, int roundingMode) {
+        return setScale(newScale, RoundingMode.valueOf(roundingMode));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance with the specified scale. If
+     * the new scale is greater than the old scale, then additional zeros are
+     * added to the unscaled value. If the new scale is smaller than the old
+     * scale, then trailing zeros are removed. If the trailing digits are not
+     * zeros then an ArithmeticException is thrown.
+     * <p>
+     * If no exception is thrown, then the following equation holds: {@code
+     * x.setScale(s).compareTo(x) == 0}.
+     *
+     * @param newScale
+     *            scale of the result returned.
+     * @return a new {@code BigDecimal} instance with the specified scale.
+     * @throws ArithmeticException
+     *             if rounding would be necessary.
+     */
+    public BigDecimal setScale(int newScale) {
+        return setScale(newScale, RoundingMode.UNNECESSARY);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance where the decimal point has
+     * been moved {@code n} places to the left. If {@code n < 0} then the
+     * decimal point is moved {@code -n} places to the right.
+     *
+     * <p>The result is obtained by changing its scale. If the scale of the result
+     * becomes negative, then its precision is increased such that the scale is
+     * zero.
+     *
+     * <p>Note, that {@code movePointLeft(0)} returns a result which is
+     * mathematically equivalent, but which has {@code scale >= 0}.
+     */
+    public BigDecimal movePointLeft(int n) {
+        return movePoint(scale + (long)n);
+    }
+
+    private BigDecimal movePoint(long newScale) {
+        if (isZero()) {
+            return zeroScaledBy(Math.max(newScale, 0));
+        }
+        /*
+         * When: 'n'== Integer.MIN_VALUE isn't possible to call to
+         * movePointRight(-n) since -Integer.MIN_VALUE == Integer.MIN_VALUE
+         */
+        if(newScale >= 0) {
+            if(bitLength < 64) {
+                return valueOf(smallValue, safeLongToInt(newScale));
+            }
+            return new BigDecimal(getUnscaledValue(), safeLongToInt(newScale));
+        }
+        if(-newScale < MathUtils.LONG_POWERS_OF_TEN.length &&
+                bitLength + LONG_POWERS_OF_TEN_BIT_LENGTH[(int)-newScale] < 64 ) {
+            return valueOf(smallValue*MathUtils.LONG_POWERS_OF_TEN[(int)-newScale],0);
+        }
+        return new BigDecimal(Multiplication.multiplyByTenPow(
+                getUnscaledValue(), safeLongToInt(-newScale)), 0);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance where the decimal point has
+     * been moved {@code n} places to the right. If {@code n < 0} then the
+     * decimal point is moved {@code -n} places to the left.
+     *
+     * <p>The result is obtained by changing its scale. If the scale of the result
+     * becomes negative, then its precision is increased such that the scale is
+     * zero.
+     *
+     * <p>Note, that {@code movePointRight(0)} returns a result which is
+     * mathematically equivalent, but which has scale >= 0.
+     */
+    public BigDecimal movePointRight(int n) {
+        return movePoint(scale - (long)n);
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} whose value is {@code this * 10<sup>n</sup>}.
+     * The scale of the result is {@code this.scale()} - {@code n}.
+     * The precision of the result is the precision of {@code this}.
+     *
+     * <p>This method has the same effect as {@link #movePointRight}, except that
+     * the precision is not changed.
+     */
+    public BigDecimal scaleByPowerOfTen(int n) {
+        long newScale = scale - (long)n;
+        if(bitLength < 64) {
+            //Taking care when a 0 is to be scaled
+            if( smallValue==0  ){
+                return zeroScaledBy( newScale );
+            }
+            return valueOf(smallValue, safeLongToInt(newScale));
+        }
+        return new BigDecimal(getUnscaledValue(), safeLongToInt(newScale));
+    }
+
+    /**
+     * Returns a new {@code BigDecimal} instance with the same value as {@code
+     * this} but with a unscaled value where the trailing zeros have been
+     * removed. If the unscaled value of {@code this} has n trailing zeros, then
+     * the scale and the precision of the result has been reduced by n.
+     *
+     * @return a new {@code BigDecimal} instance equivalent to this where the
+     *         trailing zeros of the unscaled value have been removed.
+     */
+    public BigDecimal stripTrailingZeros() {
+        int i = 1; // 1 <= i <= 18
+        int lastPow = TEN_POW.length - 1;
+        long newScale = scale;
+
+        if (isZero()) {
+            return new BigDecimal(BigInteger.ZERO, 0);
+        }
+        BigInteger strippedBI = getUnscaledValue();
+        BigInteger[] quotAndRem;
+
+        // while the number is even...
+        while (!strippedBI.testBit(0)) {
+            // To divide by 10^i
+            quotAndRem = strippedBI.divideAndRemainder(TEN_POW[i]);
+            // To look the remainder
+            if (quotAndRem[1].signum() == 0) {
+                // To adjust the scale
+                newScale -= i;
+                if (i < lastPow) {
+                    // To set to the next power
+                    i++;
+                }
+                strippedBI = quotAndRem[0];
+            } else {
+                if (i == 1) {
+                    // 'this' has no more trailing zeros
+                    break;
+                }
+                // To set to the smallest power of ten
+                i = 1;
+            }
+        }
+        return new BigDecimal(strippedBI, safeLongToInt(newScale));
+    }
+
+    /**
+     * Compares this {@code BigDecimal} with {@code val}. Returns one of the
+     * three values {@code 1}, {@code 0}, or {@code -1}. The method behaves as
+     * if {@code this.subtract(val)} is computed. If this difference is > 0 then
+     * 1 is returned, if the difference is < 0 then -1 is returned, and if the
+     * difference is 0 then 0 is returned. This means, that if two decimal
+     * instances are compared which are equal in value but differ in scale, then
+     * these two instances are considered as equal.
+     *
+     * @param val
+     *            value to be compared with {@code this}.
+     * @return {@code 1} if {@code this > val}, {@code -1} if {@code this < val},
+     *         {@code 0} if {@code this == val}.
+     * @throws NullPointerException
+     *             if {@code val == null}.
+     */
+    public int compareTo(BigDecimal val) {
+        int thisSign = signum();
+        int valueSign = val.signum();
+
+        if( thisSign == valueSign) {
+            if(this.scale == val.scale && this.bitLength<64 && val.bitLength<64 ) {
+                return (smallValue < val.smallValue) ? -1 : (smallValue > val.smallValue) ? 1 : 0;
+            }
+            long diffScale = (long)this.scale - val.scale;
+            int diffPrecision = this.approxPrecision() - val.approxPrecision();
+            if (diffPrecision > diffScale + 1) {
+                return thisSign;
+            } else if (diffPrecision < diffScale - 1) {
+                return -thisSign;
+            } else {// thisSign == val.signum()  and  diffPrecision is aprox. diffScale
+                BigInteger thisUnscaled = this.getUnscaledValue();
+                BigInteger valUnscaled = val.getUnscaledValue();
+                // If any of both precision is bigger, append zeros to the shorter one
+                if (diffScale < 0) {
+                    thisUnscaled = thisUnscaled.multiply(Multiplication.powerOf10(-diffScale));
+                } else if (diffScale > 0) {
+                    valUnscaled = valUnscaled.multiply(Multiplication.powerOf10(diffScale));
+                }
+                return thisUnscaled.compareTo(valUnscaled);
+            }
+        } else if (thisSign < valueSign) {
+            return -1;
+        } else  {
+            return 1;
+        }
+    }
+
+    /**
+     * Returns {@code true} if {@code x} is a {@code BigDecimal} instance and if
+     * this instance is equal to this big decimal. Two big decimals are equal if
+     * their unscaled value and their scale is equal. For example, 1.0
+     * (10*10<sup>-1</sup>) is not equal to 1.00 (100*10<sup>-2</sup>). Similarly, zero
+     * instances are not equal if their scale differs.
+     */
+    @Override
+    public boolean equals(Object x) {
+        if (this == x) {
+            return true;
+        }
+        if (x instanceof BigDecimal) {
+            BigDecimal x1 = (BigDecimal) x;
+            return x1.scale == scale
+                    && x1.bitLength == bitLength
+                    && (bitLength < 64 ? (x1.smallValue == smallValue) : x1.intVal.equals(intVal));
+        }
+        return false;
+    }
+
+    /**
+     * Returns the minimum of this {@code BigDecimal} and {@code val}.
+     *
+     * @param val
+     *            value to be used to compute the minimum with this.
+     * @return {@code min(this, val}.
+     * @throws NullPointerException
+     *             if {@code val == null}.
+     */
+    public BigDecimal min(BigDecimal val) {
+        return ((compareTo(val) <= 0) ? this : val);
+    }
+
+    /**
+     * Returns the maximum of this {@code BigDecimal} and {@code val}.
+     *
+     * @param val
+     *            value to be used to compute the maximum with this.
+     * @return {@code max(this, val}.
+     * @throws NullPointerException
+     *             if {@code val == null}.
+     */
+    public BigDecimal max(BigDecimal val) {
+        return ((compareTo(val) >= 0) ? this : val);
+    }
+
+    /**
+     * Returns a hash code for this {@code BigDecimal}.
+     *
+     * @return hash code for {@code this}.
+     */
+    @Override
+    public int hashCode() {
+        if (hashCode != 0) {
+            return hashCode;
+        }
+        if (bitLength < 64) {
+            hashCode = (int)(smallValue & 0xffffffff);
+            hashCode = 33 * hashCode +  (int)((smallValue >> 32) & 0xffffffff);
+            hashCode = 17 * hashCode + scale;
+            return hashCode;
+        }
+        hashCode = 17 * intVal.hashCode() + scale;
+        return hashCode;
+    }
+
+    /**
+     * Returns a canonical string representation of this {@code BigDecimal}. If
+     * necessary, scientific notation is used. This representation always prints
+     * all significant digits of this value.
+     * <p>
+     * If the scale is negative or if {@code scale - precision >= 6} then
+     * scientific notation is used.
+     *
+     * @return a string representation of {@code this} in scientific notation if
+     *         necessary.
+     */
+    @Override
+    public String toString() {
+        if (toStringImage != null) {
+            return toStringImage;
+        }
+        if(bitLength < 32) {
+            toStringImage = Conversion.toDecimalScaledString(smallValue,scale);
+            return toStringImage;
+        }
+        String intString = getUnscaledValue().toString();
+        if (scale == 0) {
+            return intString;
+        }
+        int begin = (getUnscaledValue().signum() < 0) ? 2 : 1;
+        int end = intString.length();
+        long exponent = -(long)scale + end - begin;
+        StringBuilder result = new StringBuilder();
+
+        result.append(intString);
+        if ((scale > 0) && (exponent >= -6)) {
+            if (exponent >= 0) {
+                result.insert(end - scale, '.');
+            } else {
+                result.insert(begin - 1, "0.");
+                result.insert(begin + 1, CH_ZEROS, 0, -(int)exponent - 1);
+            }
+        } else {
+            if (end - begin >= 1) {
+                result.insert(begin, '.');
+                end++;
+            }
+            result.insert(end, 'E');
+            if (exponent > 0) {
+                result.insert(++end, '+');
+            }
+            result.insert(++end, Long.toString(exponent));
+        }
+        toStringImage = result.toString();
+        return toStringImage;
+    }
+
+    /**
+     * Returns a string representation of this {@code BigDecimal}. This
+     * representation always prints all significant digits of this value.
+     * <p>
+     * If the scale is negative or if {@code scale - precision >= 6} then
+     * engineering notation is used. Engineering notation is similar to the
+     * scientific notation except that the exponent is made to be a multiple of
+     * 3 such that the integer part is >= 1 and < 1000.
+     *
+     * @return a string representation of {@code this} in engineering notation
+     *         if necessary.
+     */
+    public String toEngineeringString() {
+        String intString = getUnscaledValue().toString();
+        if (scale == 0) {
+            return intString;
+        }
+        int begin = (getUnscaledValue().signum() < 0) ? 2 : 1;
+        int end = intString.length();
+        long exponent = -(long)scale + end - begin;
+        StringBuilder result = new StringBuilder(intString);
+
+        if ((scale > 0) && (exponent >= -6)) {
+            if (exponent >= 0) {
+                result.insert(end - scale, '.');
+            } else {
+                result.insert(begin - 1, "0.");
+                result.insert(begin + 1, CH_ZEROS, 0, -(int)exponent - 1);
+            }
+        } else {
+            int delta = end - begin;
+            int rem = (int)(exponent % 3);
+
+            if (rem != 0) {
+                // adjust exponent so it is a multiple of three
+                if (getUnscaledValue().signum() == 0) {
+                    // zero value
+                    rem = (rem < 0) ? -rem : 3 - rem;
+                    exponent += rem;
+                } else {
+                    // nonzero value
+                    rem = (rem < 0) ? rem + 3 : rem;
+                    exponent -= rem;
+                    begin += rem;
+                }
+                if (delta < 3) {
+                    for (int i = rem - delta; i > 0; i--) {
+                        result.insert(end++, '0');
+                    }
+                }
+            }
+            if (end - begin >= 1) {
+                result.insert(begin, '.');
+                end++;
+            }
+            if (exponent != 0) {
+                result.insert(end, 'E');
+                if (exponent > 0) {
+                    result.insert(++end, '+');
+                }
+                result.insert(++end, Long.toString(exponent));
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Returns a string representation of this {@code BigDecimal}. No scientific
+     * notation is used. This methods adds zeros where necessary.
+     * <p>
+     * If this string representation is used to create a new instance, this
+     * instance is generally not identical to {@code this} as the precision
+     * changes.
+     * <p>
+     * {@code x.equals(new BigDecimal(x.toPlainString())} usually returns
+     * {@code false}.
+     * <p>
+     * {@code x.compareTo(new BigDecimal(x.toPlainString())} returns {@code 0}.
+     *
+     * @return a string representation of {@code this} without exponent part.
+     */
+    public String toPlainString() {
+        String intStr = getUnscaledValue().toString();
+        if ((scale == 0) || ((isZero()) && (scale < 0))) {
+            return intStr;
+        }
+        int begin = (signum() < 0) ? 1 : 0;
+        int delta = scale;
+        // We take space for all digits, plus a possible decimal point, plus 'scale'
+        StringBuilder result = new StringBuilder(intStr.length() + 1 + Math.abs(scale));
+
+        if (begin == 1) {
+            // If the number is negative, we insert a '-' character at front
+            result.append('-');
+        }
+        if (scale > 0) {
+            delta -= (intStr.length() - begin);
+            if (delta >= 0) {
+                result.append("0.");
+                // To append zeros after the decimal point
+                for (; delta > CH_ZEROS.length; delta -= CH_ZEROS.length) {
+                    result.append(CH_ZEROS);
+                }
+                result.append(CH_ZEROS, 0, delta);
+                result.append(intStr.substring(begin));
+            } else {
+                delta = begin - delta;
+                result.append(intStr.substring(begin, delta));
+                result.append('.');
+                result.append(intStr.substring(delta));
+            }
+        } else {// (scale <= 0)
+            result.append(intStr.substring(begin));
+            // To append trailing zeros
+            for (; delta < -CH_ZEROS.length; delta += CH_ZEROS.length) {
+                result.append(CH_ZEROS);
+            }
+            result.append(CH_ZEROS, 0, -delta);
+        }
+        return result.toString();
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a big integer instance. A fractional
+     * part is discarded.
+     *
+     * @return this {@code BigDecimal} as a big integer instance.
+     */
+    public BigInteger toBigInteger() {
+        if ((scale == 0) || (isZero())) {
+            return getUnscaledValue();
+        } else if (scale < 0) {
+            return getUnscaledValue().multiply(Multiplication.powerOf10(-(long)scale));
+        } else {// (scale > 0)
+            return getUnscaledValue().divide(Multiplication.powerOf10(scale));
+        }
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a big integer instance if it has no
+     * fractional part. If this {@code BigDecimal} has a fractional part, i.e.
+     * if rounding would be necessary, an {@code ArithmeticException} is thrown.
+     *
+     * @return this {@code BigDecimal} as a big integer value.
+     * @throws ArithmeticException
+     *             if rounding is necessary.
+     */
+    public BigInteger toBigIntegerExact() {
+        if ((scale == 0) || (isZero())) {
+            return getUnscaledValue();
+        } else if (scale < 0) {
+            return getUnscaledValue().multiply(Multiplication.powerOf10(-(long)scale));
+        } else {// (scale > 0)
+            BigInteger[] integerAndFraction;
+            // An optimization before do a heavy division
+            if ((scale > approxPrecision()) || (scale > getUnscaledValue().getLowestSetBit())) {
+                throw new ArithmeticException("Rounding necessary");
+            }
+            integerAndFraction = getUnscaledValue().divideAndRemainder(Multiplication.powerOf10(scale));
+            if (integerAndFraction[1].signum() != 0) {
+                // It exists a non-zero fractional part
+                throw new ArithmeticException("Rounding necessary");
+            }
+            return integerAndFraction[0];
+        }
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as an long value. Any fractional part is
+     * discarded. If the integral part of {@code this} is too big to be
+     * represented as an long, then {@code this % 2<sup>64</sup>} is returned.
+     */
+    @Override
+    public long longValue() {
+        /*
+         * If scale <= -64 there are at least 64 trailing bits zero in
+         * 10^(-scale). If the scale is positive and very large the long value
+         * could be zero.
+         */
+        return ((scale <= -64) || (scale > approxPrecision()) ? 0L : toBigInteger().longValue());
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a long value if it has no fractional
+     * part and if its value fits to the int range ([-2<sup>63</sup>..2<sup>63</sup>-1]). If
+     * these conditions are not met, an {@code ArithmeticException} is thrown.
+     *
+     * @throws ArithmeticException
+     *             if rounding is necessary or the number doesn't fit in a long.
+     */
+    public long longValueExact() {
+        return valueExact(64);
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as an int value. Any fractional part is
+     * discarded. If the integral part of {@code this} is too big to be
+     * represented as an int, then {@code this % 2<sup>32</sup>} is returned.
+     */
+    @Override
+    public int intValue() {
+        /*
+         * If scale <= -32 there are at least 32 trailing bits zero in
+         * 10^(-scale). If the scale is positive and very large the long value
+         * could be zero.
+         */
+        return ((scale <= -32) || (scale > approxPrecision()) ? 0 : toBigInteger().intValue());
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a int value if it has no fractional
+     * part and if its value fits to the int range ([-2<sup>31</sup>..2<sup>31</sup>-1]). If
+     * these conditions are not met, an {@code ArithmeticException} is thrown.
+     *
+     * @throws ArithmeticException
+     *             if rounding is necessary or the number doesn't fit in an int.
+     */
+    public int intValueExact() {
+        return (int) valueExact(32);
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a short value if it has no fractional
+     * part and if its value fits to the short range ([-2<sup>15</sup>..2<sup>15</sup>-1]). If
+     * these conditions are not met, an {@code ArithmeticException} is thrown.
+     *
+     * @throws ArithmeticException
+     *             if rounding is necessary of the number doesn't fit in a short.
+     */
+    public short shortValueExact() {
+        return (short) valueExact(16);
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a byte value if it has no fractional
+     * part and if its value fits to the byte range ([-128..127]). If these
+     * conditions are not met, an {@code ArithmeticException} is thrown.
+     *
+     * @throws ArithmeticException
+     *             if rounding is necessary or the number doesn't fit in a byte.
+     */
+    public byte byteValueExact() {
+        return (byte) valueExact(8);
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a float value. If {@code this} is too
+     * big to be represented as an float, then {@code Float.POSITIVE_INFINITY}
+     * or {@code Float.NEGATIVE_INFINITY} is returned.
+     * <p>
+     * Note, that if the unscaled value has more than 24 significant digits,
+     * then this decimal cannot be represented exactly in a float variable. In
+     * this case the result is rounded.
+     * <p>
+     * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
+     * represented exactly as a float, and thus {@code x1.equals(new
+     * BigDecimal(x1.floatValue())} returns {@code false} for this case.
+     * <p>
+     * Similarly, if the instance {@code new BigDecimal(16777217)} is converted
+     * to a float, the result is {@code 1.6777216E}7.
+     *
+     * @return this {@code BigDecimal} as a float value.
+     */
+    @Override
+    public float floatValue() {
+        /* A similar code like in doubleValue() could be repeated here,
+         * but this simple implementation is quite efficient. */
+        float floatResult = signum();
+        long powerOfTwo = this.bitLength - (long)(scale / LOG10_2);
+        if ((powerOfTwo < -149) || (floatResult == 0.0f)) {
+            // Cases which 'this' is very small
+            floatResult *= 0.0f;
+        } else if (powerOfTwo > 129) {
+            // Cases which 'this' is very large
+            floatResult *= Float.POSITIVE_INFINITY;
+        } else {
+            floatResult = (float)doubleValue();
+        }
+        return floatResult;
+    }
+
+    /**
+     * Returns this {@code BigDecimal} as a double value. If {@code this} is too
+     * big to be represented as an float, then {@code Double.POSITIVE_INFINITY}
+     * or {@code Double.NEGATIVE_INFINITY} is returned.
+     * <p>
+     * Note, that if the unscaled value has more than 53 significant digits,
+     * then this decimal cannot be represented exactly in a double variable. In
+     * this case the result is rounded.
+     * <p>
+     * For example, if the instance {@code x1 = new BigDecimal("0.1")} cannot be
+     * represented exactly as a double, and thus {@code x1.equals(new
+     * BigDecimal(x1.doubleValue())} returns {@code false} for this case.
+     * <p>
+     * Similarly, if the instance {@code new BigDecimal(9007199254740993L)} is
+     * converted to a double, the result is {@code 9.007199254740992E15}.
+     * <p>
+     *
+     * @return this {@code BigDecimal} as a double value.
+     */
+    @Override
+    public double doubleValue() {
+        int sign = signum();
+        int exponent = 1076; // bias + 53
+        int lowestSetBit;
+        int discardedSize;
+        long powerOfTwo = this.bitLength - (long)(scale / LOG10_2);
+        long bits; // IEEE-754 Standard
+        long tempBits; // for temporal calculations
+        BigInteger mantissa;
+
+        if ((powerOfTwo < -1074) || (sign == 0)) {
+            // Cases which 'this' is very small
+            return (sign * 0.0d);
+        } else if (powerOfTwo > 1025) {
+            // Cases which 'this' is very large
+            return (sign * Double.POSITIVE_INFINITY);
+        }
+        mantissa = getUnscaledValue().abs();
+        // Let be:  this = [u,s], with s > 0
+        if (scale <= 0) {
+            // mantissa = abs(u) * 10^s
+            mantissa = mantissa.multiply(Multiplication.powerOf10(-scale));
+        } else {// (scale > 0)
+            BigInteger quotAndRem[];
+            BigInteger powerOfTen = Multiplication.powerOf10(scale);
+            int k = 100 - (int)powerOfTwo;
+            int compRem;
+
+            if (k > 0) {
+                /* Computing (mantissa * 2^k) , where 'k' is a enough big
+                 * power of '2' to can divide by 10^s */
+                mantissa = mantissa.shiftLeft(k);
+                exponent -= k;
+            }
+            // Computing (mantissa * 2^k) / 10^s
+            quotAndRem = mantissa.divideAndRemainder(powerOfTen);
+            // To check if the fractional part >= 0.5
+            compRem = quotAndRem[1].shiftLeftOneBit().compareTo(powerOfTen);
+            // To add two rounded bits at end of mantissa
+            mantissa = quotAndRem[0].shiftLeft(2).add(
+                    BigInteger.valueOf((compRem * (compRem + 3)) / 2 + 1));
+            exponent -= 2;
+        }
+        lowestSetBit = mantissa.getLowestSetBit();
+        discardedSize = mantissa.bitLength() - 54;
+        if (discardedSize > 0) {// (n > 54)
+            // mantissa = (abs(u) * 10^s) >> (n - 54)
+            bits = mantissa.shiftRight(discardedSize).longValue();
+            tempBits = bits;
+            // #bits = 54, to check if the discarded fraction produces a carry
+            if ((((bits & 1) == 1) && (lowestSetBit < discardedSize))
+                    || ((bits & 3) == 3)) {
+                bits += 2;
+            }
+        } else {// (n <= 54)
+            // mantissa = (abs(u) * 10^s) << (54 - n)
+            bits = mantissa.longValue() << -discardedSize;
+            tempBits = bits;
+            // #bits = 54, to check if the discarded fraction produces a carry:
+            if ((bits & 3) == 3) {
+                bits += 2;
+            }
+        }
+        // Testing bit 54 to check if the carry creates a new binary digit
+        if ((bits & 0x40000000000000L) == 0) {
+            // To drop the last bit of mantissa (first discarded)
+            bits >>= 1;
+            // exponent = 2^(s-n+53+bias)
+            exponent += discardedSize;
+        } else {// #bits = 54
+            bits >>= 2;
+            exponent += discardedSize + 1;
+        }
+        // To test if the 53-bits number fits in 'double'
+        if (exponent > 2046) {// (exponent - bias > 1023)
+            return (sign * Double.POSITIVE_INFINITY);
+        } else if (exponent <= 0) {// (exponent - bias <= -1023)
+            // Denormalized numbers (having exponent == 0)
+            if (exponent < -53) {// exponent - bias < -1076
+                return (sign * 0.0d);
+            }
+            // -1076 <= exponent - bias <= -1023
+            // To discard '- exponent + 1' bits
+            bits = tempBits >> 1;
+            tempBits = bits & (-1L >>> (63 + exponent));
+            bits >>= (-exponent );
+            // To test if after discard bits, a new carry is generated
+            if (((bits & 3) == 3) || (((bits & 1) == 1) && (tempBits != 0)
+            && (lowestSetBit < discardedSize))) {
+                bits += 1;
+            }
+            exponent = 0;
+            bits >>= 1;
+        }
+        // Construct the 64 double bits: [sign(1), exponent(11), mantissa(52)]
+        bits = (sign & 0x8000000000000000L) | ((long)exponent << 52)
+                | (bits & 0xFFFFFFFFFFFFFL);
+        return Double.longBitsToDouble(bits);
+    }
+
+    /**
+     * Returns the unit in the last place (ULP) of this {@code BigDecimal}
+     * instance. An ULP is the distance to the nearest big decimal with the same
+     * precision.
+     *
+     * <p>The amount of a rounding error in the evaluation of a floating-point
+     * operation is often expressed in ULPs. An error of 1 ULP is often seen as
+     * a tolerable error.
+     *
+     * <p>For class {@code BigDecimal}, the ULP of a number is simply 10<sup>-scale</sup>.
+     * For example, {@code new BigDecimal(0.1).ulp()} returns {@code 1E-55}.
+     *
+     * @return unit in the last place (ULP) of this {@code BigDecimal} instance.
+     */
+    public BigDecimal ulp() {
+        return valueOf(1, scale);
+    }
+
+    /* Private Methods */
+
+    /**
+     * It does all rounding work of the public method
+     * {@code round(MathContext)}, performing an inplace rounding
+     * without creating a new object.
+     *
+     * @param mc
+     *            the {@code MathContext} for perform the rounding.
+     * @see #round(MathContext)
+     */
+    private void inplaceRound(MathContext mc) {
+        int mcPrecision = mc.getPrecision();
+        if (approxPrecision() < mcPrecision || mcPrecision == 0) {
+            return;
+        }
+        int discardedPrecision = precision() - mcPrecision;
+        // If no rounding is necessary it returns immediately
+        if ((discardedPrecision <= 0)) {
+            return;
+        }
+        // When the number is small perform an efficient rounding
+        if (this.bitLength < 64) {
+            smallRound(mc, discardedPrecision);
+            return;
+        }
+        // Getting the integer part and the discarded fraction
+        BigInteger sizeOfFraction = Multiplication.powerOf10(discardedPrecision);
+        BigInteger[] integerAndFraction = getUnscaledValue().divideAndRemainder(sizeOfFraction);
+        long newScale = (long)scale - discardedPrecision;
+        int compRem;
+        BigDecimal tempBD;
+        // If the discarded fraction is non-zero, perform rounding
+        if (integerAndFraction[1].signum() != 0) {
+            // To check if the discarded fraction >= 0.5
+            compRem = (integerAndFraction[1].abs().shiftLeftOneBit().compareTo(sizeOfFraction));
+            // To look if there is a carry
+            compRem =  roundingBehavior( integerAndFraction[0].testBit(0) ? 1 : 0,
+                    integerAndFraction[1].signum() * (5 + compRem),
+                    mc.getRoundingMode());
+            if (compRem != 0) {
+                integerAndFraction[0] = integerAndFraction[0].add(BigInteger.valueOf(compRem));
+            }
+            tempBD = new BigDecimal(integerAndFraction[0]);
+            // If after to add the increment the precision changed, we normalize the size
+            if (tempBD.precision() > mcPrecision) {
+                integerAndFraction[0] = integerAndFraction[0].divide(BigInteger.TEN);
+                newScale--;
+            }
+        }
+        // To update all internal fields
+        scale = safeLongToInt(newScale);
+        precision = mcPrecision;
+        setUnscaledValue(integerAndFraction[0]);
+    }
+
+    /**
+     * Returns -1, 0, and 1 if {@code value1 < value2}, {@code value1 == value2},
+     * and {@code value1 > value2}, respectively, when comparing without regard
+     * to the values' sign.
+     *
+     * <p>Note that this implementation deals correctly with Long.MIN_VALUE,
+     * whose absolute magnitude is larger than any other {@code long} value.
+     */
+    private static int compareAbsoluteValues(long value1, long value2) {
+        // Map long values to the range -1 .. Long.MAX_VALUE so that comparison
+        // of absolute magnitude can be done using regular long arithmetics.
+        // This deals correctly with Long.MIN_VALUE, whose absolute magnitude
+        // is larger than any other long value, and which is mapped to
+        // Long.MAX_VALUE here.
+        // Values that only differ by sign get mapped to the same value, for
+        // example both +3 and -3 get mapped to +2.
+        value1 = Math.abs(value1) - 1;
+        value2 = Math.abs(value2) - 1;
+        // Unlike Long.compare(), we guarantee to return specifically -1 and +1
+        return value1 > value2 ? 1 : (value1 < value2 ? -1 : 0);
+    }
+
+    /**
+     * Compares {@code n} against {@code 0.5 * d} in absolute terms (ignoring sign)
+     * and with arithmetics that are safe against overflow or loss of precision.
+     * Returns -1 if {@code n} is less than {@code 0.5 * d}, 0 if {@code n == 0.5 * d},
+     * or +1 if {@code n > 0.5 * d} when comparing the absolute values under such
+     * arithmetics.
+     */
+    private static int compareForRounding(long n, long d) {
+        long halfD = d / 2; //  rounds towards 0
+        if (n == halfD || n == -halfD) {
+            // In absolute terms: Because n == halfD, we know that 2 * n + lsb == d
+            // for some lsb value 0 or 1. This means that n == d/2 (result 0) if
+            // lsb is 0, or n < d/2 (result -1) if lsb is 1. In either case, the
+            // result is -lsb.
+            // Since we're calculating in absolute terms, we need the absolute lsb
+            // (d & 1) as opposed to the signed lsb (d % 2) which would be -1 for
+            // negative odd values of d.
+            int lsb = (int) d & 1;
+            return -lsb; // returns 0 or -1
+        } else {
+            // In absolute terms, either 2 * n + 1 < d (in the case of n < halfD),
+            // or 2 * n > d (in the case of n > halfD).
+            // In either case, comparing n against halfD gets the right result
+            // -1 or +1, respectively.
+            return compareAbsoluteValues(n, halfD);
+        }
+    }
+
+    /**
+     * This method implements an efficient rounding for numbers which unscaled
+     * value fits in the type {@code long}.
+     *
+     * @param mc
+     *            the context to use
+     * @param discardedPrecision
+     *            the number of decimal digits that are discarded
+     * @see #round(MathContext)
+     */
+    private void smallRound(MathContext mc, int discardedPrecision) {
+        long sizeOfFraction = MathUtils.LONG_POWERS_OF_TEN[discardedPrecision];
+        long newScale = (long)scale - discardedPrecision;
+        long unscaledVal = smallValue;
+        // Getting the integer part and the discarded fraction
+        long integer = unscaledVal / sizeOfFraction;
+        long fraction = unscaledVal % sizeOfFraction;
+        int compRem;
+        // If the discarded fraction is non-zero perform rounding
+        if (fraction != 0) {
+            // To check if the discarded fraction >= 0.5
+            compRem = compareForRounding(fraction, sizeOfFraction);
+            // To look if there is a carry
+            integer += roundingBehavior( ((int)integer) & 1,
+                    Long.signum(fraction) * (5 + compRem),
+                    mc.getRoundingMode());
+            // If after to add the increment the precision changed, we normalize the size
+            if (Math.log10(Math.abs(integer)) >= mc.getPrecision()) {
+                integer /= 10;
+                newScale--;
+            }
+        }
+        // To update all internal fields
+        scale = safeLongToInt(newScale);
+        precision = mc.getPrecision();
+        smallValue = integer;
+        bitLength = bitLength(integer);
+        intVal = null;
+    }
+
+    /**
+     * Return an increment that can be -1,0 or 1, depending of
+     * {@code roundingMode}.
+     *
+     * @param parityBit
+     *            can be 0 or 1, it's only used in the case
+     *            {@code HALF_EVEN}
+     * @param fraction
+     *            the mantissa to be analyzed
+     * @param roundingMode
+     *            the type of rounding
+     * @return the carry propagated after rounding
+     */
+    private static int roundingBehavior(int parityBit, int fraction, RoundingMode roundingMode) {
+        int increment = 0; // the carry after rounding
+
+        switch (roundingMode) {
+            case UNNECESSARY:
+                if (fraction != 0) {
+                    throw new ArithmeticException("Rounding necessary");
+                }
+                break;
+            case UP:
+                increment = Integer.signum(fraction);
+                break;
+            case DOWN:
+                break;
+            case CEILING:
+                increment = Math.max(Integer.signum(fraction), 0);
+                break;
+            case FLOOR:
+                increment = Math.min(Integer.signum(fraction), 0);
+                break;
+            case HALF_UP:
+                if (Math.abs(fraction) >= 5) {
+                    increment = Integer.signum(fraction);
+                }
+                break;
+            case HALF_DOWN:
+                if (Math.abs(fraction) > 5) {
+                    increment = Integer.signum(fraction);
+                }
+                break;
+            case HALF_EVEN:
+                if (Math.abs(fraction) + parityBit > 5) {
+                    increment = Integer.signum(fraction);
+                }
+                break;
+        }
+        return increment;
+    }
+
+    /**
+     * If {@code intVal} has a fractional part throws an exception,
+     * otherwise it counts the number of bits of value and checks if it's out of
+     * the range of the primitive type. If the number fits in the primitive type
+     * returns this number as {@code long}, otherwise throws an
+     * exception.
+     *
+     * @param bitLengthOfType
+     *            number of bits of the type whose value will be calculated
+     *            exactly
+     * @return the exact value of the integer part of {@code BigDecimal}
+     *         when is possible
+     * @throws ArithmeticException when rounding is necessary or the
+     *             number don't fit in the primitive type
+     */
+    private long valueExact(int bitLengthOfType) {
+        BigInteger bigInteger = toBigIntegerExact();
+
+        if (bigInteger.bitLength() < bitLengthOfType) {
+            // It fits in the primitive type
+            return bigInteger.longValue();
+        }
+        throw new ArithmeticException("Rounding necessary");
+    }
+
+    /**
+     * If the precision already was calculated it returns that value, otherwise
+     * it calculates a very good approximation efficiently . Note that this
+     * value will be {@code precision()} or {@code precision()-1}
+     * in the worst case.
+     *
+     * @return an approximation of {@code precision()} value
+     */
+    private int approxPrecision() {
+        return precision > 0
+                ? precision
+                : (int) ((this.bitLength - 1) * LOG10_2) + 1;
+    }
+
+    private static int safeLongToInt(long longValue) {
+        if (longValue < Integer.MIN_VALUE || longValue > Integer.MAX_VALUE) {
+            throw new ArithmeticException("Out of int range: " + longValue);
+        }
+        return (int) longValue;
+    }
+
+    /**
+     * It returns the value 0 with the most approximated scale of type
+     * {@code int}. if {@code longScale > Integer.MAX_VALUE} the
+     * scale will be {@code Integer.MAX_VALUE}; if
+     * {@code longScale < Integer.MIN_VALUE} the scale will be
+     * {@code Integer.MIN_VALUE}; otherwise {@code longScale} is
+     * casted to the type {@code int}.
+     *
+     * @param longScale
+     *            the scale to which the value 0 will be scaled.
+     * @return the value 0 scaled by the closer scale of type {@code int}.
+     * @see #scale
+     */
+    private static BigDecimal zeroScaledBy(long longScale) {
+        if (longScale == (int) longScale) {
+            return valueOf(0,(int)longScale);
+            }
+        if (longScale >= 0) {
+            return new BigDecimal( 0, Integer.MAX_VALUE);
+        }
+        return new BigDecimal( 0, Integer.MIN_VALUE);
+    }
+
+    /**
+     * Assigns all transient fields upon deserialization of a
+     * {@code BigDecimal} instance (bitLength and smallValue). The transient
+     * field precision is assigned lazily.
+     */
+    private void readObject(ObjectInputStream in) throws IOException,
+            ClassNotFoundException {
+        in.defaultReadObject();
+
+        this.bitLength = intVal.bitLength();
+        if (this.bitLength < 64) {
+            this.smallValue = intVal.longValue();
+        }
+    }
+
+    /**
+     * Prepares this {@code BigDecimal} for serialization, i.e. the
+     * non-transient field {@code intVal} is assigned.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        getUnscaledValue();
+        out.defaultWriteObject();
+    }
+
+    private BigInteger getUnscaledValue() {
+        if(intVal == null) {
+            intVal = BigInteger.valueOf(smallValue);
+        }
+        return intVal;
+    }
+
+    private void setUnscaledValue(BigInteger unscaledValue) {
+        this.intVal = unscaledValue;
+        this.bitLength = unscaledValue.bitLength();
+        if(this.bitLength < 64) {
+            this.smallValue = unscaledValue.longValue();
+        }
+    }
+
+    private static int bitLength(long smallValue) {
+        if(smallValue < 0) {
+            smallValue = ~smallValue;
+        }
+        return 64 - Long.numberOfLeadingZeros(smallValue);
+    }
+
+    private static int bitLength(int smallValue) {
+        if(smallValue < 0) {
+            smallValue = ~smallValue;
+        }
+        return 32 - Integer.numberOfLeadingZeros(smallValue);
+    }
+
+}
diff --git a/java/math/BigInt.java b/java/math/BigInt.java
new file mode 100644
index 0000000..4448ce1
--- /dev/null
+++ b/java/math/BigInt.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.math;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import libcore.util.NativeAllocationRegistry;
+
+/*
+ * In contrast to BigIntegers this class doesn't fake two's complement representation.
+ * Any Bit-Operations, including Shifting, solely regard the unsigned magnitude.
+ * Moreover BigInt objects are mutable and offer efficient in-place-operations.
+ */
+final class BigInt {
+
+    private static NativeAllocationRegistry registry = NativeAllocationRegistry.createMalloced(
+            BigInt.class.getClassLoader(), NativeBN.getNativeFinalizer());
+
+    /* Fields used for the internal representation. */
+    @ReachabilitySensitive
+    private transient long bignum = 0;
+
+    @Override
+    public String toString() {
+        return this.decString();
+    }
+
+    boolean hasNativeBignum() {
+        return this.bignum != 0;
+    }
+
+    private void makeValid() {
+        if (this.bignum == 0) {
+            this.bignum = NativeBN.BN_new();
+            registry.registerNativeAllocation(this, this.bignum);
+        }
+    }
+
+    private static BigInt newBigInt() {
+        BigInt bi = new BigInt();
+        bi.bignum = NativeBN.BN_new();
+        registry.registerNativeAllocation(bi, bi.bignum);
+        return bi;
+    }
+
+
+    static int cmp(BigInt a, BigInt b) {
+        return NativeBN.BN_cmp(a.bignum, b.bignum);
+    }
+
+
+    void putCopy(BigInt from) {
+        this.makeValid();
+        NativeBN.BN_copy(this.bignum, from.bignum);
+    }
+
+    BigInt copy() {
+        BigInt bi = new BigInt();
+        bi.putCopy(this);
+        return bi;
+    }
+
+
+    void putLongInt(long val) {
+        this.makeValid();
+        NativeBN.putLongInt(this.bignum, val);
+    }
+
+    void putULongInt(long val, boolean neg) {
+        this.makeValid();
+        NativeBN.putULongInt(this.bignum, val, neg);
+    }
+
+    private NumberFormatException invalidBigInteger(String s) {
+        throw new NumberFormatException("Invalid BigInteger: " + s);
+    }
+
+    void putDecString(String original) {
+        String s = checkString(original, 10);
+        this.makeValid();
+        int usedLen = NativeBN.BN_dec2bn(this.bignum, s);
+        if (usedLen < s.length()) {
+            throw invalidBigInteger(original);
+        }
+    }
+
+    void putHexString(String original) {
+        String s = checkString(original, 16);
+        this.makeValid();
+        int usedLen = NativeBN.BN_hex2bn(this.bignum, s);
+        if (usedLen < s.length()) {
+            throw invalidBigInteger(original);
+        }
+    }
+
+    /**
+     * Returns a string suitable for passing to OpenSSL.
+     * Throws if 's' doesn't match Java's rules for valid BigInteger strings.
+     * BN_dec2bn and BN_hex2bn do very little checking, so we need to manually
+     * ensure we comply with Java's rules.
+     * http://code.google.com/p/android/issues/detail?id=7036
+     */
+    String checkString(String s, int base) {
+        if (s == null) {
+            throw new NullPointerException("s == null");
+        }
+        // A valid big integer consists of an optional '-' or '+' followed by
+        // one or more digit characters appropriate to the given base,
+        // and no other characters.
+        int charCount = s.length();
+        int i = 0;
+        if (charCount > 0) {
+            char ch = s.charAt(0);
+            if (ch == '+') {
+                // Java supports leading +, but OpenSSL doesn't, so we need to strip it.
+                s = s.substring(1);
+                --charCount;
+            } else if (ch == '-') {
+                ++i;
+            }
+        }
+        if (charCount - i == 0) {
+            throw invalidBigInteger(s);
+        }
+        boolean nonAscii = false;
+        for (; i < charCount; ++i) {
+            char ch = s.charAt(i);
+            if (Character.digit(ch, base) == -1) {
+                throw invalidBigInteger(s);
+            }
+            if (ch > 128) {
+                nonAscii = true;
+            }
+        }
+        return nonAscii ? toAscii(s, base) : s;
+    }
+
+    // Java supports non-ASCII decimal digits, but OpenSSL doesn't.
+    // We need to translate the decimal digits but leave any other characters alone.
+    // This method assumes it's being called on a string that has already been validated.
+    private static String toAscii(String s, int base) {
+        int length = s.length();
+        StringBuilder result = new StringBuilder(length);
+        for (int i = 0; i < length; ++i) {
+            char ch = s.charAt(i);
+            int value = Character.digit(ch, base);
+            if (value >= 0 && value <= 9) {
+                ch = (char) ('0' + value);
+            }
+            result.append(ch);
+        }
+        return result.toString();
+    }
+
+    void putBigEndian(byte[] a, boolean neg) {
+        this.makeValid();
+        NativeBN.BN_bin2bn(a, a.length, neg, this.bignum);
+    }
+
+    void putLittleEndianInts(int[] a, boolean neg) {
+        this.makeValid();
+        NativeBN.litEndInts2bn(a, a.length, neg, this.bignum);
+    }
+
+    void putBigEndianTwosComplement(byte[] a) {
+        this.makeValid();
+        NativeBN.twosComp2bn(a, a.length, this.bignum);
+    }
+
+
+    long longInt() {
+        return NativeBN.longInt(this.bignum);
+    }
+
+    String decString() {
+        return NativeBN.BN_bn2dec(this.bignum);
+    }
+
+    String hexString() {
+        return NativeBN.BN_bn2hex(this.bignum);
+    }
+
+    byte[] bigEndianMagnitude() {
+        return NativeBN.BN_bn2bin(this.bignum);
+    }
+
+    int[] littleEndianIntsMagnitude() {
+        return NativeBN.bn2litEndInts(this.bignum);
+    }
+
+    int sign() {
+        return NativeBN.sign(this.bignum);
+    }
+
+    void setSign(int val) {
+        if (val > 0) {
+            NativeBN.BN_set_negative(this.bignum, 0);
+        } else {
+            if (val < 0) NativeBN.BN_set_negative(this.bignum, 1);
+        }
+    }
+
+    boolean twosCompFitsIntoBytes(int desiredByteCount) {
+        int actualByteCount = (NativeBN.bitLength(this.bignum) + 7) / 8;
+        return actualByteCount <= desiredByteCount;
+    }
+
+    int bitLength() {
+        return NativeBN.bitLength(this.bignum);
+    }
+
+    boolean isBitSet(int n) {
+        return NativeBN.BN_is_bit_set(this.bignum, n);
+    }
+
+    // n > 0: shift left (multiply)
+    static BigInt shift(BigInt a, int n) {
+        BigInt r = newBigInt();
+        NativeBN.BN_shift(r.bignum, a.bignum, n);
+        return r;
+    }
+
+    void shift(int n) {
+        NativeBN.BN_shift(this.bignum, this.bignum, n);
+    }
+
+    void addPositiveInt(int w) {
+        NativeBN.BN_add_word(this.bignum, w);
+    }
+
+    void multiplyByPositiveInt(int w) {
+        NativeBN.BN_mul_word(this.bignum, w);
+    }
+
+    static int remainderByPositiveInt(BigInt a, int w) {
+        return NativeBN.BN_mod_word(a.bignum, w);
+    }
+
+    static BigInt addition(BigInt a, BigInt b) {
+        BigInt r = newBigInt();
+        NativeBN.BN_add(r.bignum, a.bignum, b.bignum);
+        return r;
+    }
+
+    void add(BigInt a) {
+        NativeBN.BN_add(this.bignum, this.bignum, a.bignum);
+    }
+
+    static BigInt subtraction(BigInt a, BigInt b) {
+        BigInt r = newBigInt();
+        NativeBN.BN_sub(r.bignum, a.bignum, b.bignum);
+        return r;
+    }
+
+
+    static BigInt gcd(BigInt a, BigInt b) {
+        BigInt r = newBigInt();
+        NativeBN.BN_gcd(r.bignum, a.bignum, b.bignum);
+        return r;
+    }
+
+    static BigInt product(BigInt a, BigInt b) {
+        BigInt r = newBigInt();
+        NativeBN.BN_mul(r.bignum, a.bignum, b.bignum);
+        return r;
+    }
+
+    static BigInt bigExp(BigInt a, BigInt p) {
+        // Sign of p is ignored!
+        BigInt r = newBigInt();
+        NativeBN.BN_exp(r.bignum, a.bignum, p.bignum);
+        return r;
+    }
+
+    static BigInt exp(BigInt a, int p) {
+        // Sign of p is ignored!
+        BigInt power = new BigInt();
+        power.putLongInt(p);
+        return bigExp(a, power);
+        // OPTIONAL:
+        // int BN_sqr(BigInteger r, BigInteger a, BN_CTX ctx);
+        // int BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx);
+    }
+
+    static void division(BigInt dividend, BigInt divisor, BigInt quotient, BigInt remainder) {
+        long quot, rem;
+        if (quotient != null) {
+            quotient.makeValid();
+            quot = quotient.bignum;
+        } else {
+            quot = 0;
+        }
+        if (remainder != null) {
+            remainder.makeValid();
+            rem = remainder.bignum;
+        } else {
+            rem = 0;
+        }
+        NativeBN.BN_div(quot, rem, dividend.bignum, divisor.bignum);
+    }
+
+    static BigInt modulus(BigInt a, BigInt m) {
+        // Sign of p is ignored! ?
+        BigInt r = newBigInt();
+        NativeBN.BN_nnmod(r.bignum, a.bignum, m.bignum);
+        return r;
+    }
+
+    static BigInt modExp(BigInt a, BigInt p, BigInt m) {
+        // Sign of p is ignored!
+        BigInt r = newBigInt();
+        NativeBN.BN_mod_exp(r.bignum, a.bignum, p.bignum, m.bignum);
+        return r;
+    }
+
+
+    static BigInt modInverse(BigInt a, BigInt m) {
+        BigInt r = newBigInt();
+        NativeBN.BN_mod_inverse(r.bignum, a.bignum, m.bignum);
+        return r;
+    }
+
+
+    static BigInt generatePrimeDefault(int bitLength) {
+        BigInt r = newBigInt();
+        NativeBN.BN_generate_prime_ex(r.bignum, bitLength, false, 0, 0);
+        return r;
+    }
+
+    boolean isPrime(int certainty) {
+        return NativeBN.BN_primality_test(bignum, certainty, false);
+    }
+}
diff --git a/java/math/BigInteger.java b/java/math/BigInteger.java
new file mode 100644
index 0000000..b96fdb2
--- /dev/null
+++ b/java/math/BigInteger.java
@@ -0,0 +1,1275 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Random;
+import libcore.util.NonNull;
+import libcore.util.Nullable;
+
+/**
+ * An immutable arbitrary-precision signed integer.
+ *
+ * <h3>Fast Cryptography</h3>
+ * This implementation is efficient for operations traditionally used in
+ * cryptography, such as the generation of large prime numbers and computation
+ * of the modular inverse.
+ *
+ * <h3>Slow Two's Complement Bitwise Operations</h3>
+ * This API includes operations for bitwise operations in two's complement
+ * representation. Two's complement is not the internal representation used by
+ * this implementation, so such methods may be inefficient. Use {@link
+ * java.util.BitSet} for high-performance bitwise operations on
+ * arbitrarily-large sequences of bits.
+ */
+public class BigInteger extends Number
+        implements Comparable<BigInteger>, Serializable {
+
+    /** This is the serialVersionUID used by the sun implementation. */
+    private static final long serialVersionUID = -8287574255936472291L;
+
+    private transient BigInt bigInt;
+
+    private transient boolean nativeIsValid = false;
+
+    private transient boolean javaIsValid = false;
+
+    /** The magnitude of this in the little-endian representation. */
+    transient int[] digits;
+
+    /**
+     * The length of this in measured in ints. Can be less than
+     * digits.length().
+     */
+    transient int numberLength;
+
+    /** The sign of this. */
+    transient int sign;
+
+    /** The {@code BigInteger} constant 0. */
+    @NonNull public static final BigInteger ZERO = new BigInteger(0, 0);
+
+    /** The {@code BigInteger} constant 1. */
+    @NonNull public static final BigInteger ONE = new BigInteger(1, 1);
+
+    /** The {@code BigInteger} constant 10. */
+    @NonNull public static final BigInteger TEN = new BigInteger(1, 10);
+
+    /** The {@code BigInteger} constant -1. */
+    static final BigInteger MINUS_ONE = new BigInteger(-1, 1);
+
+    /** All the {@code BigInteger} numbers in the range [0,10] are cached. */
+    static final BigInteger[] SMALL_VALUES = { ZERO, ONE, new BigInteger(1, 2),
+            new BigInteger(1, 3), new BigInteger(1, 4), new BigInteger(1, 5),
+            new BigInteger(1, 6), new BigInteger(1, 7), new BigInteger(1, 8),
+            new BigInteger(1, 9), TEN };
+
+    private transient int firstNonzeroDigit = -2;
+
+    /** sign field, used for serialization. */
+    private int signum;
+
+    /** absolute value field, used for serialization */
+    private byte[] magnitude;
+
+    /** Cache for the hash code. */
+    private transient int hashCode = 0;
+
+    BigInteger(BigInt bigInt) {
+        if (bigInt == null || !bigInt.hasNativeBignum()) {
+            throw new AssertionError();
+        }
+        setBigInt(bigInt);
+    }
+
+    BigInteger(int sign, long value) {
+        BigInt bigInt = new BigInt();
+        bigInt.putULongInt(value, (sign < 0));
+        setBigInt(bigInt);
+    }
+
+    /**
+     * Constructs a number without creating new space. This construct should be
+     * used only if the three fields of representation are known.
+     *
+     * @param sign the sign of the number.
+     * @param numberLength the length of the internal array.
+     * @param digits a reference of some array created before.
+     */
+    BigInteger(int sign, int numberLength, int[] digits) {
+        setJavaRepresentation(sign, numberLength, digits);
+    }
+
+    /**
+     * Constructs a random non-negative {@code BigInteger} instance in the range
+     * {@code [0, pow(2, numBits)-1]}.
+     *
+     * @param numBits maximum length of the new {@code BigInteger} in bits.
+     * @param random is the random number generator to be used.
+     * @throws IllegalArgumentException if {@code numBits} < 0.
+     */
+    public BigInteger(int numBits, @NonNull Random random) {
+        if (numBits < 0) {
+            throw new IllegalArgumentException("numBits < 0: " + numBits);
+        }
+        if (numBits == 0) {
+            setJavaRepresentation(0, 1, new int[] { 0 });
+        } else {
+            int sign = 1;
+            int numberLength = (numBits + 31) >> 5;
+            int[] digits = new int[numberLength];
+            for (int i = 0; i < numberLength; i++) {
+                digits[i] = random.nextInt();
+            }
+            // Clear any extra bits.
+            digits[numberLength - 1] >>>= (-numBits) & 31;
+            setJavaRepresentation(sign, numberLength, digits);
+        }
+        javaIsValid = true;
+    }
+
+    /**
+     * Constructs a random {@code BigInteger} instance in the range {@code [0,
+     * pow(2, bitLength)-1]} which is probably prime. The probability that the
+     * returned {@code BigInteger} is prime is greater than
+     * {@code 1 - 1/2<sup>certainty</sup>)}.
+     *
+     * <p><b>Note:</b> the {@code Random} argument is ignored if
+     * {@code bitLength >= 16}, where this implementation will use OpenSSL's
+     * {@code BN_generate_prime_ex} as a source of cryptographically strong pseudo-random numbers.
+     *
+     * @param bitLength length of the new {@code BigInteger} in bits.
+     * @param certainty tolerated primality uncertainty.
+     * @throws ArithmeticException if {@code bitLength < 2}.
+     * @see <a href="http://www.openssl.org/docs/crypto/BN_rand.html">
+     *      Specification of random generator used from OpenSSL library</a>
+     */
+    public BigInteger(int bitLength, int certainty, @NonNull Random random) {
+        if (bitLength < 2) {
+            throw new ArithmeticException("bitLength < 2: " + bitLength);
+        }
+        if (bitLength < 16) {
+            // We have to generate short primes ourselves, because OpenSSL bottoms out at 16 bits.
+            int candidate;
+            do {
+                candidate = random.nextInt() & ((1 << bitLength) - 1);
+                candidate |= (1 << (bitLength - 1)); // Set top bit.
+                if (bitLength > 2) {
+                    candidate |= 1; // Any prime longer than 2 bits must have the bottom bit set.
+                }
+            } while (!isSmallPrime(candidate));
+            BigInt prime = new BigInt();
+            prime.putULongInt(candidate, false);
+            setBigInt(prime);
+        } else {
+            // We need a loop here to work around an OpenSSL bug; http://b/8588028.
+            do {
+                setBigInt(BigInt.generatePrimeDefault(bitLength));
+            } while (bitLength() != bitLength);
+        }
+    }
+
+    private static boolean isSmallPrime(int x) {
+        if (x == 2) {
+            return true;
+        }
+        if ((x % 2) == 0) {
+            return false;
+        }
+        final int max = (int) Math.sqrt(x);
+        for (int i = 3; i <= max; i += 2) {
+            if ((x % i) == 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Constructs a new {@code BigInteger} by parsing {@code value}. The string
+     * representation consists of an optional plus or minus sign followed by a
+     * non-empty sequence of decimal digits. Digits are interpreted as if by
+     * {@code Character.digit(char,10)}.
+     *
+     * @param value string representation of the new {@code BigInteger}.
+     * @throws NullPointerException if {@code value == null}.
+     * @throws NumberFormatException if {@code value} is not a valid
+     *     representation of a {@code BigInteger}.
+     */
+    public BigInteger(@NonNull String value) {
+        BigInt bigInt = new BigInt();
+        bigInt.putDecString(value);
+        setBigInt(bigInt);
+    }
+
+    /**
+     * Constructs a new {@code BigInteger} instance by parsing {@code value}.
+     * The string representation consists of an optional plus or minus sign
+     * followed by a non-empty sequence of digits in the specified radix. Digits
+     * are interpreted as if by {@code Character.digit(char, radix)}.
+     *
+     * @param value string representation of the new {@code BigInteger}.
+     * @param radix the base to be used for the conversion.
+     * @throws NullPointerException if {@code value == null}.
+     * @throws NumberFormatException if {@code value} is not a valid
+     *     representation of a {@code BigInteger} or if {@code radix <
+     *     Character.MIN_RADIX} or {@code radix > Character.MAX_RADIX}.
+     */
+    public BigInteger(@NonNull String value, int radix) {
+        if (value == null) {
+            throw new NullPointerException("value == null");
+        }
+        if (radix == 10) {
+            BigInt bigInt = new BigInt();
+            bigInt.putDecString(value);
+            setBigInt(bigInt);
+        } else if (radix == 16) {
+            BigInt bigInt = new BigInt();
+            bigInt.putHexString(value);
+            setBigInt(bigInt);
+        } else {
+            if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) {
+                throw new NumberFormatException("Invalid radix: " + radix);
+            }
+            if (value.isEmpty()) {
+                throw new NumberFormatException("value.isEmpty()");
+            }
+            BigInteger.parseFromString(this, value, radix);
+        }
+    }
+
+    /**
+     * Constructs a new {@code BigInteger} instance with the given sign and
+     * magnitude.
+     *
+     * @param signum sign of the new {@code BigInteger} (-1 for negative, 0 for
+     *     zero, 1 for positive).
+     * @param magnitude magnitude of the new {@code BigInteger} with the most
+     *     significant byte first.
+     * @throws NullPointerException if {@code magnitude == null}.
+     * @throws NumberFormatException if the sign is not one of -1, 0, 1 or if
+     *     the sign is zero and the magnitude contains non-zero entries.
+     */
+    public BigInteger(int signum, byte @NonNull [] magnitude) {
+        if (magnitude == null) {
+            throw new NullPointerException("magnitude == null");
+        }
+        if (signum < -1 || signum > 1) {
+            throw new NumberFormatException("Invalid signum: " + signum);
+        }
+        if (signum == 0) {
+            for (byte element : magnitude) {
+                if (element != 0) {
+                    throw new NumberFormatException("signum-magnitude mismatch");
+                }
+            }
+        }
+        BigInt bigInt = new BigInt();
+        bigInt.putBigEndian(magnitude, signum < 0);
+        setBigInt(bigInt);
+    }
+
+    /**
+     * Constructs a new {@code BigInteger} from the given two's complement
+     * representation. The most significant byte is the entry at index 0. The
+     * most significant bit of this entry determines the sign of the new {@code
+     * BigInteger} instance. The array must be nonempty.
+     *
+     * @param value two's complement representation of the new {@code
+     *     BigInteger}.
+     * @throws NullPointerException if {@code value == null}.
+     * @throws NumberFormatException if the length of {@code value} is zero.
+     */
+    public BigInteger(byte @NonNull [] value) {
+        if (value.length == 0) {
+            throw new NumberFormatException("value.length == 0");
+        }
+        BigInt bigInt = new BigInt();
+        bigInt.putBigEndianTwosComplement(value);
+        setBigInt(bigInt);
+    }
+
+    /**
+     * Returns the internal native representation of this big integer, computing
+     * it if necessary.
+     */
+    BigInt getBigInt() {
+        if (nativeIsValid) {
+            return bigInt;
+        }
+
+        synchronized (this) {
+            if (nativeIsValid) {
+                return bigInt;
+            }
+            BigInt bigInt = new BigInt();
+            bigInt.putLittleEndianInts(digits, (sign < 0));
+            setBigInt(bigInt);
+            return bigInt;
+        }
+    }
+
+    private void setBigInt(BigInt bigInt) {
+        this.bigInt = bigInt;
+        this.nativeIsValid = true;
+    }
+
+    private void setJavaRepresentation(int sign, int numberLength, int[] digits) {
+        // decrement numberLength to drop leading zeroes...
+        while (numberLength > 0 && digits[--numberLength] == 0) {
+            ;
+        }
+        // ... and then increment it back because we always drop one too many
+        if (digits[numberLength++] == 0) {
+            sign = 0;
+        }
+        this.sign = sign;
+        this.digits = digits;
+        this.numberLength = numberLength;
+        this.javaIsValid = true;
+    }
+
+    void prepareJavaRepresentation() {
+        if (javaIsValid) {
+            return;
+        }
+
+        synchronized (this) {
+            if (javaIsValid) {
+                return;
+            }
+            int sign = bigInt.sign();
+            int[] digits = (sign != 0) ? bigInt.littleEndianIntsMagnitude() : new int[] { 0 };
+            setJavaRepresentation(sign, digits.length, digits);
+        }
+    }
+
+    /** Returns a {@code BigInteger} whose value is equal to {@code value}. */
+    @NonNull public static BigInteger valueOf(long value) {
+        if (value < 0) {
+            if (value != -1) {
+                return new BigInteger(-1, -value);
+            }
+            return MINUS_ONE;
+        } else if (value < SMALL_VALUES.length) {
+            return SMALL_VALUES[(int) value];
+        } else {// (value > 10)
+            return new BigInteger(1, value);
+        }
+    }
+
+    /**
+     * Returns the two's complement representation of this {@code BigInteger} in
+     * a byte array.
+     */
+    public byte @NonNull [] toByteArray() {
+        return twosComplement();
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is the absolute value of {@code
+     * this}.
+     */
+    @NonNull public BigInteger abs() {
+        BigInt bigInt = getBigInt();
+        if (bigInt.sign() >= 0) {
+            return this;
+        }
+        BigInt a = bigInt.copy();
+        a.setSign(1);
+        return new BigInteger(a);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is the {@code -this}.
+     */
+    @NonNull public BigInteger negate() {
+        BigInt bigInt = getBigInt();
+        int sign = bigInt.sign();
+        if (sign == 0) {
+            return this;
+        }
+        BigInt a = bigInt.copy();
+        a.setSign(-sign);
+        return new BigInteger(a);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this + value}.
+     */
+    @NonNull public BigInteger add(@NonNull BigInteger value) {
+        BigInt lhs = getBigInt();
+        BigInt rhs = value.getBigInt();
+        if (rhs.sign() == 0) {
+            return this;
+        }
+        if (lhs.sign() == 0) {
+            return value;
+        }
+        return new BigInteger(BigInt.addition(lhs, rhs));
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this - value}.
+     */
+    @NonNull public BigInteger subtract(@NonNull BigInteger value) {
+        BigInt lhs = getBigInt();
+        BigInt rhs = value.getBigInt();
+        if (rhs.sign() == 0) {
+            return this;
+        }
+        return new BigInteger(BigInt.subtraction(lhs, rhs));
+    }
+
+    /**
+     * Returns the sign of this {@code BigInteger}.
+     *
+     * @return {@code -1} if {@code this < 0}, {@code 0} if {@code this == 0},
+     *     {@code 1} if {@code this > 0}.
+     */
+    public int signum() {
+        if (javaIsValid) {
+            return sign;
+        }
+        return getBigInt().sign();
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this >> n}. For
+     * negative arguments, the result is also negative. The shift distance may
+     * be negative which means that {@code this} is shifted left.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method on negative values is
+     * not recommended as the current implementation is not efficient.
+     *
+     * @param n shift distance
+     * @return {@code this >> n} if {@code n >= 0}; {@code this << (-n)}
+     *     otherwise
+     */
+    @NonNull public BigInteger shiftRight(int n) {
+        return shiftLeft(-n);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this << n}. The
+     * result is equivalent to {@code this * pow(2, n)} if n >= 0. The shift
+     * distance may be negative which means that {@code this} is shifted right.
+     * The result then corresponds to {@code floor(this / pow(2, -n))}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method on negative values is
+     * not recommended as the current implementation is not efficient.
+     *
+     * @param n shift distance.
+     * @return {@code this << n} if {@code n >= 0}; {@code this >> (-n)}.
+     *     otherwise
+     */
+    @NonNull public BigInteger shiftLeft(int n) {
+        if (n == 0) {
+            return this;
+        }
+        int sign = signum();
+        if (sign == 0) {
+            return this;
+        }
+        if ((sign > 0) || (n >= 0)) {
+            return new BigInteger(BigInt.shift(getBigInt(), n));
+        } else {
+            // Negative numbers faking 2's complement:
+            // Not worth optimizing this:
+            // Sticking to Harmony Java implementation.
+            return BitLevel.shiftRight(this, -n);
+        }
+    }
+
+    BigInteger shiftLeftOneBit() {
+        return (signum() == 0) ? this : BitLevel.shiftLeftOneBit(this);
+    }
+
+    /**
+     * Returns the length of the value's two's complement representation without
+     * leading zeros for positive numbers / without leading ones for negative
+     * values.
+     *
+     * <p>The two's complement representation of {@code this} will be at least
+     * {@code bitLength() + 1} bits long.
+     *
+     * <p>The value will fit into an {@code int} if {@code bitLength() < 32} or
+     * into a {@code long} if {@code bitLength() < 64}.
+     *
+     * @return the length of the minimal two's complement representation for
+     *     {@code this} without the sign bit.
+     */
+    public int bitLength() {
+        // Optimization to avoid unnecessary duplicate representation:
+        if (!nativeIsValid && javaIsValid) {
+            return BitLevel.bitLength(this);
+        }
+        return getBigInt().bitLength();
+    }
+
+    /**
+     * Tests whether the bit at position n in {@code this} is set. The result is
+     * equivalent to {@code this & pow(2, n) != 0}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     *
+     * @param n position where the bit in {@code this} has to be inspected.
+     * @throws ArithmeticException if {@code n < 0}.
+     */
+    public boolean testBit(int n) {
+        if (n < 0) {
+            throw new ArithmeticException("n < 0: " + n);
+        }
+        int sign = signum();
+        if (sign > 0 && nativeIsValid && !javaIsValid) {
+            return getBigInt().isBitSet(n);
+        } else {
+            // Negative numbers faking 2's complement:
+            // Not worth optimizing this:
+            // Sticking to Harmony Java implementation.
+            prepareJavaRepresentation();
+            if (n == 0) {
+                return ((digits[0] & 1) != 0);
+            }
+            int intCount = n >> 5;
+            if (intCount >= numberLength) {
+                return (sign < 0);
+            }
+            int digit = digits[intCount];
+            n = (1 << (n & 31)); // int with 1 set to the needed position
+            if (sign < 0) {
+                int firstNonZeroDigit = getFirstNonzeroDigit();
+                if (intCount < firstNonZeroDigit) {
+                    return false;
+                } else if (firstNonZeroDigit == intCount) {
+                    digit = -digit;
+                } else {
+                    digit = ~digit;
+                }
+            }
+            return ((digit & n) != 0);
+        }
+    }
+
+    /**
+     * Returns a {@code BigInteger} which has the same binary representation
+     * as {@code this} but with the bit at position n set. The result is
+     * equivalent to {@code this | pow(2, n)}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     *
+     * @param n position where the bit in {@code this} has to be set.
+     * @throws ArithmeticException if {@code n < 0}.
+     */
+    @NonNull public BigInteger setBit(int n) {
+        prepareJavaRepresentation();
+        if (!testBit(n)) {
+            return BitLevel.flipBit(this, n);
+        } else {
+            return this;
+        }
+    }
+
+    /**
+     * Returns a {@code BigInteger} which has the same binary representation
+     * as {@code this} but with the bit at position n cleared. The result is
+     * equivalent to {@code this & ~pow(2, n)}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     *
+     * @param n position where the bit in {@code this} has to be cleared.
+     * @throws ArithmeticException if {@code n < 0}.
+     */
+    @NonNull public BigInteger clearBit(int n) {
+        prepareJavaRepresentation();
+        if (testBit(n)) {
+            return BitLevel.flipBit(this, n);
+        } else {
+            return this;
+        }
+    }
+
+    /**
+     * Returns a {@code BigInteger} which has the same binary representation
+     * as {@code this} but with the bit at position n flipped. The result is
+     * equivalent to {@code this ^ pow(2, n)}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     *
+     * @param n position where the bit in {@code this} has to be flipped.
+     * @throws ArithmeticException if {@code n < 0}.
+     */
+    @NonNull public BigInteger flipBit(int n) {
+        prepareJavaRepresentation();
+        if (n < 0) {
+            throw new ArithmeticException("n < 0: " + n);
+        }
+        return BitLevel.flipBit(this, n);
+    }
+
+    /**
+     * Returns the position of the lowest set bit in the two's complement
+     * representation of this {@code BigInteger}. If all bits are zero (this==0)
+     * then -1 is returned as result.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     */
+    public int getLowestSetBit() {
+        prepareJavaRepresentation();
+        if (sign == 0) {
+            return -1;
+        }
+        // (sign != 0) implies that exists some non zero digit
+        int i = getFirstNonzeroDigit();
+        return ((i << 5) + Integer.numberOfTrailingZeros(digits[i]));
+    }
+
+    /**
+     * Returns the number of bits in the two's complement representation of
+     * {@code this} which differ from the sign bit. If {@code this} is negative,
+     * the result is equivalent to the number of bits set in the two's
+     * complement representation of {@code -this - 1}.
+     *
+     * <p>Use {@code bitLength(0)} to find the length of the binary value in
+     * bits.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     */
+    public int bitCount() {
+        prepareJavaRepresentation();
+        return BitLevel.bitCount(this);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code ~this}. The result
+     * of this operation is {@code -this-1}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     */
+    @NonNull public BigInteger not() {
+        this.prepareJavaRepresentation();
+        return Logical.not(this);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this & value}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended
+     * as the current implementation is not efficient.
+     *
+     * @param value value to be and'ed with {@code this}.
+     * @throws NullPointerException if {@code value == null}.
+     */
+    @NonNull public BigInteger and(@NonNull BigInteger value) {
+        this.prepareJavaRepresentation();
+        value.prepareJavaRepresentation();
+        return Logical.and(this, value);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this | value}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     *
+     * @param value value to be or'ed with {@code this}.
+     * @throws NullPointerException if {@code value == null}.
+     */
+    @NonNull public BigInteger or(@NonNull BigInteger value) {
+        this.prepareJavaRepresentation();
+        value.prepareJavaRepresentation();
+        return Logical.or(this, value);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this ^ value}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended as
+     * the current implementation is not efficient.
+     *
+     * @param value value to be xor'ed with {@code this}
+     * @throws NullPointerException if {@code value == null}
+     */
+    @NonNull public BigInteger xor(@NonNull BigInteger value) {
+        this.prepareJavaRepresentation();
+        value.prepareJavaRepresentation();
+        return Logical.xor(this, value);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this & ~value}.
+     * Evaluating {@code x.andNot(value)} returns the same result as {@code
+     * x.and(value.not())}.
+     *
+     * <p><b>Implementation Note:</b> Usage of this method is not recommended
+     * as the current implementation is not efficient.
+     *
+     * @param value value to be not'ed and then and'ed with {@code this}.
+     * @throws NullPointerException if {@code value == null}.
+     */
+    @NonNull public BigInteger andNot(@NonNull BigInteger value) {
+        this.prepareJavaRepresentation();
+        value.prepareJavaRepresentation();
+        return Logical.andNot(this, value);
+    }
+
+    /**
+     * Returns this {@code BigInteger} as an int value. If {@code this} is too
+     * big to be represented as an int, then {@code this % (1 << 32)} is
+     * returned.
+     */
+    @Override
+    public int intValue() {
+        if (nativeIsValid && bigInt.twosCompFitsIntoBytes(4)) {
+            return (int) bigInt.longInt();
+        }
+        this.prepareJavaRepresentation();
+        return (sign * digits[0]);
+    }
+
+    /**
+     * Returns this {@code BigInteger} as a long value. If {@code this} is too
+     * big to be represented as a long, then {@code this % pow(2, 64)} is
+     * returned.
+     */
+    @Override
+    public long longValue() {
+        if (nativeIsValid && bigInt.twosCompFitsIntoBytes(8)) {
+            return bigInt.longInt();
+        }
+        prepareJavaRepresentation();
+        long value = numberLength > 1
+                ? ((long) digits[1]) << 32 | digits[0] & 0xFFFFFFFFL
+                : digits[0] & 0xFFFFFFFFL;
+        return sign * value;
+    }
+
+    /**
+     * Returns this {@code BigInteger} as a float. If {@code this} is too big to
+     * be represented as a float, then {@code Float.POSITIVE_INFINITY} or
+     * {@code Float.NEGATIVE_INFINITY} is returned. Note that not all integers
+     * in the range {@code [-Float.MAX_VALUE, Float.MAX_VALUE]} can be exactly
+     * represented as a float.
+     */
+    @Override
+    public float floatValue() {
+        return (float) doubleValue();
+    }
+
+    /**
+     * Returns this {@code BigInteger} as a double. If {@code this} is too big
+     * to be represented as a double, then {@code Double.POSITIVE_INFINITY} or
+     * {@code Double.NEGATIVE_INFINITY} is returned. Note that not all integers
+     * in the range {@code [-Double.MAX_VALUE, Double.MAX_VALUE]} can be exactly
+     * represented as a double.
+     */
+    @Override
+    public double doubleValue() {
+        return Conversion.bigInteger2Double(this);
+    }
+
+    /**
+     * Compares this {@code BigInteger} with {@code value}. Returns {@code -1}
+     * if {@code this < value}, {@code 0} if {@code this == value} and {@code 1}
+     * if {@code this > value}, .
+     *
+     * @param value value to be compared with {@code this}.
+     * @throws NullPointerException if {@code value == null}.
+     */
+    public int compareTo(@NonNull BigInteger value) {
+        return BigInt.cmp(getBigInt(), value.getBigInt());
+    }
+
+    /**
+     * Returns the minimum of this {@code BigInteger} and {@code value}.
+     *
+     * @param value value to be used to compute the minimum with {@code this}.
+     * @throws NullPointerException if {@code value == null}.
+     */
+    @NonNull public BigInteger min(@NonNull BigInteger value) {
+        return this.compareTo(value) == -1 ? this : value;
+    }
+
+    /**
+     * Returns the maximum of this {@code BigInteger} and {@code value}.
+     *
+     * @param value value to be used to compute the maximum with {@code this}
+     * @throws NullPointerException if {@code value == null}
+     */
+    @NonNull public BigInteger max(@NonNull BigInteger value) {
+        return this.compareTo(value) == 1 ? this : value;
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == 0) {
+            prepareJavaRepresentation();
+            int hash = 0;
+            for (int i = 0; i < numberLength; ++i) {
+                hash = hash * 33 + digits[i];
+            }
+            hashCode = hash * sign;
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(@Nullable Object x) {
+        if (this == x) {
+            return true;
+        }
+        if (x instanceof BigInteger) {
+            return this.compareTo((BigInteger) x) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a string representation of this {@code BigInteger} in decimal
+     * form.
+     */
+    @Override
+    @NonNull public String toString() {
+        return getBigInt().decString();
+    }
+
+    /**
+     * Returns a string containing a string representation of this {@code
+     * BigInteger} with base radix. If {@code radix < Character.MIN_RADIX} or
+     * {@code radix > Character.MAX_RADIX} then a decimal representation is
+     * returned. The characters of the string representation are generated with
+     * method {@code Character.forDigit}.
+     *
+     * @param radix base to be used for the string representation.
+     */
+    @NonNull public String toString(int radix) {
+        if (radix == 10) {
+            return getBigInt().decString();
+        } else {
+            prepareJavaRepresentation();
+            return Conversion.bigInteger2String(this, radix);
+        }
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is greatest common divisor
+     * of {@code this} and {@code value}. If {@code this == 0} and {@code
+     * value == 0} then zero is returned, otherwise the result is positive.
+     *
+     * @param value value with which the greatest common divisor is computed.
+     * @throws NullPointerException if {@code value == null}.
+     */
+    @NonNull public BigInteger gcd(@NonNull BigInteger value) {
+        // First optimize the case in which the two arguments have very different
+        // length.
+        int thisLen = bitLength();
+        int valueLen = value.bitLength();
+        final int gcdDirectRatio = 16;
+        if (thisLen > gcdDirectRatio * valueLen) {
+            // A division-based step reduces the length of this by a factor of at
+            // least gcdDirectRatio, thus ensuring that a division-based step will
+            // easily pay for itself.
+            if (value.signum() == 0) {
+                return this.abs();
+            }
+            return value.gcd(this.mod(value.abs()));
+        } else if (valueLen > gcdDirectRatio * thisLen) {
+            if (signum() == 0) {
+                return value.abs();
+            }
+            return this.gcd(value.mod(this.abs()));
+        }
+
+        return new BigInteger(BigInt.gcd(getBigInt(), value.getBigInt()));
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this * value}.
+     *
+     * @throws NullPointerException if {@code value == null}.
+     */
+    @NonNull public BigInteger multiply(@NonNull BigInteger value) {
+        return new BigInteger(BigInt.product(getBigInt(), value.getBigInt()));
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code pow(this, exp)}.
+     *
+     * @throws ArithmeticException if {@code exp < 0}.
+     */
+    @NonNull public BigInteger pow(int exp) {
+        if (exp < 0) {
+            throw new ArithmeticException("exp < 0: " + exp);
+        }
+        return new BigInteger(BigInt.exp(getBigInt(), exp));
+    }
+
+    /**
+     * Returns a two element {@code BigInteger} array containing
+     * {@code this / divisor} at index 0 and {@code this % divisor} at index 1.
+     *
+     * @param divisor value by which {@code this} is divided.
+     * @throws NullPointerException if {@code divisor == null}.
+     * @throws ArithmeticException if {@code divisor == 0}.
+     * @see #divide
+     * @see #remainder
+     */
+    public @NonNull BigInteger @NonNull [] divideAndRemainder(@NonNull BigInteger divisor) {
+        BigInt divisorBigInt = divisor.getBigInt();
+        BigInt quotient = new BigInt();
+        BigInt remainder = new BigInt();
+        BigInt.division(getBigInt(), divisorBigInt, quotient, remainder);
+        return new BigInteger[] {new BigInteger(quotient), new BigInteger(remainder) };
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this / divisor}.
+     *
+     * @param divisor value by which {@code this} is divided.
+     * @return {@code this / divisor}.
+     * @throws NullPointerException if {@code divisor == null}.
+     * @throws ArithmeticException if {@code divisor == 0}.
+     */
+    @NonNull public BigInteger divide(@NonNull BigInteger divisor) {
+        BigInt quotient = new BigInt();
+        BigInt.division(getBigInt(), divisor.getBigInt(), quotient, null);
+        return new BigInteger(quotient);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this % divisor}.
+     * Regarding signs this methods has the same behavior as the % operator on
+     * ints: the sign of the remainder is the same as the sign of this.
+     *
+     * @param divisor value by which {@code this} is divided.
+     * @throws NullPointerException if {@code divisor == null}.
+     * @throws ArithmeticException if {@code divisor == 0}.
+     */
+    @NonNull public BigInteger remainder(@NonNull BigInteger divisor) {
+        BigInt remainder = new BigInt();
+        BigInt.division(getBigInt(), divisor.getBigInt(), null, remainder);
+        return new BigInteger(remainder);
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code 1/this mod m}. The
+     * modulus {@code m} must be positive. The result is guaranteed to be in the
+     * interval {@code [0, m)} (0 inclusive, m exclusive). If {@code this} is
+     * not relatively prime to m, then an exception is thrown.
+     *
+     * @param m the modulus.
+     * @throws NullPointerException if {@code m == null}
+     * @throws ArithmeticException if {@code m < 0 or} if {@code this} is not
+     *     relatively prime to {@code m}
+     */
+    @NonNull public BigInteger modInverse(@NonNull BigInteger m) {
+        if (m.signum() <= 0) {
+            throw new ArithmeticException("modulus not positive");
+        }
+        return new BigInteger(BigInt.modInverse(getBigInt(), m.getBigInt()));
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code
+     * pow(this, exponent) mod modulus}. The modulus must be positive. The
+     * result is guaranteed to be in the interval {@code [0, modulus)}.
+     * If the exponent is negative, then
+     * {@code pow(this.modInverse(modulus), -exponent) mod modulus} is computed.
+     * The inverse of this only exists if {@code this} is relatively prime to the modulus,
+     * otherwise an exception is thrown.
+     *
+     * @throws NullPointerException if {@code modulus == null} or {@code exponent == null}.
+     * @throws ArithmeticException if {@code modulus < 0} or if {@code exponent < 0} and
+     *     not relatively prime to {@code modulus}.
+     */
+    @NonNull public BigInteger modPow(@NonNull BigInteger exponent, @NonNull BigInteger modulus) {
+        if (modulus.signum() <= 0) {
+            throw new ArithmeticException("modulus.signum() <= 0");
+        }
+        int exponentSignum = exponent.signum();
+        if (exponentSignum == 0) { // OpenSSL gets this case wrong; http://b/8574367.
+            return ONE.mod(modulus);
+        }
+        BigInteger base = exponentSignum < 0 ? modInverse(modulus) : this;
+        return new BigInteger(BigInt.modExp(base.getBigInt(), exponent.getBigInt(), modulus.getBigInt()));
+    }
+
+    /**
+     * Returns a {@code BigInteger} whose value is {@code this mod m}. The
+     * modulus {@code m} must be positive. The result is guaranteed to be in the
+     * interval {@code [0, m)} (0 inclusive, m exclusive). The behavior of this
+     * function is not equivalent to the behavior of the % operator defined for
+     * the built-in {@code int}'s.
+     *
+     * @param m the modulus.
+     * @return {@code this mod m}.
+     * @throws NullPointerException if {@code m == null}.
+     * @throws ArithmeticException if {@code m < 0}.
+     */
+    @NonNull public BigInteger mod(@NonNull BigInteger m) {
+        if (m.signum() <= 0) {
+            throw new ArithmeticException("m.signum() <= 0");
+        }
+        return new BigInteger(BigInt.modulus(getBigInt(), m.getBigInt()));
+    }
+
+    /**
+     * Tests whether this {@code BigInteger} is probably prime. If {@code true}
+     * is returned, then this is prime with a probability greater than
+     * {@code 1 - 1/2<sup>certainty</sup>)}. If {@code false} is returned, then this
+     * is definitely composite. If the argument {@code certainty} <= 0, then
+     * this method returns true.
+     *
+     * @param certainty tolerated primality uncertainty.
+     * @return {@code true}, if {@code this} is probably prime, {@code false}
+     *     otherwise.
+     */
+    public boolean isProbablePrime(int certainty) {
+        if (certainty <= 0) {
+            return true;
+        }
+        return getBigInt().isPrime(certainty);
+    }
+
+    /**
+     * Returns the smallest integer x > {@code this} which is probably prime as
+     * a {@code BigInteger} instance. The probability that the returned {@code
+     * BigInteger} is prime is greater than {@code 1 - 1/2<sup>100</sup>}.
+     *
+     * @return smallest integer > {@code this} which is probably prime.
+     * @throws ArithmeticException if {@code this < 0}.
+     */
+    @NonNull public BigInteger nextProbablePrime() {
+        if (sign < 0) {
+            throw new ArithmeticException("sign < 0");
+        }
+        return Primality.nextProbablePrime(this);
+    }
+
+    /**
+     * Returns a random positive {@code BigInteger} instance in the range {@code
+     * [0, pow(2, bitLength)-1]} which is probably prime. The probability that
+     * the returned {@code BigInteger} is prime is greater than {@code 1 - 1/2<sup>100</sup>)}.
+     *
+     * @param bitLength length of the new {@code BigInteger} in bits.
+     * @return probably prime random {@code BigInteger} instance.
+     * @throws IllegalArgumentException if {@code bitLength < 2}.
+     */
+    @NonNull public static BigInteger probablePrime(int bitLength, @NonNull Random random) {
+        return new BigInteger(bitLength, 100, random);
+    }
+
+    /* Private Methods */
+
+    /**
+     * Returns the two's complement representation of this BigInteger in a byte
+     * array.
+     */
+    private byte[] twosComplement() {
+        prepareJavaRepresentation();
+        if (this.sign == 0) {
+            return new byte[] { 0 };
+        }
+        BigInteger temp = this;
+        int bitLen = bitLength();
+        int iThis = getFirstNonzeroDigit();
+        int bytesLen = (bitLen >> 3) + 1;
+        /* Puts the little-endian int array representing the magnitude
+         * of this BigInteger into the big-endian byte array. */
+        byte[] bytes = new byte[bytesLen];
+        int firstByteNumber = 0;
+        int highBytes;
+        int bytesInInteger = 4;
+        int hB;
+
+        if (bytesLen - (numberLength << 2) == 1) {
+            bytes[0] = (byte) ((sign < 0) ? -1 : 0);
+            highBytes = 4;
+            firstByteNumber++;
+        } else {
+            hB = bytesLen & 3;
+            highBytes = (hB == 0) ? 4 : hB;
+        }
+
+        int digitIndex = iThis;
+        bytesLen -= iThis << 2;
+
+        if (sign < 0) {
+            int digit = -temp.digits[digitIndex];
+            digitIndex++;
+            if (digitIndex == numberLength) {
+                bytesInInteger = highBytes;
+            }
+            for (int i = 0; i < bytesInInteger; i++, digit >>= 8) {
+                bytes[--bytesLen] = (byte) digit;
+            }
+            while (bytesLen > firstByteNumber) {
+                digit = ~temp.digits[digitIndex];
+                digitIndex++;
+                if (digitIndex == numberLength) {
+                    bytesInInteger = highBytes;
+                }
+                for (int i = 0; i < bytesInInteger; i++, digit >>= 8) {
+                    bytes[--bytesLen] = (byte) digit;
+                }
+            }
+        } else {
+            while (bytesLen > firstByteNumber) {
+                int digit = temp.digits[digitIndex];
+                digitIndex++;
+                if (digitIndex == numberLength) {
+                    bytesInInteger = highBytes;
+                }
+                for (int i = 0; i < bytesInInteger; i++, digit >>= 8) {
+                    bytes[--bytesLen] = (byte) digit;
+                }
+            }
+        }
+        return bytes;
+    }
+
+
+    static int multiplyByInt(int[] res, int[] a, int aSize, int factor) {
+        long carry = 0;
+
+        for (int i = 0; i < aSize; i++) {
+            carry += (a[i] & 0xFFFFFFFFL) * (factor & 0xFFFFFFFFL);
+            res[i] = (int) carry;
+            carry >>>= 32;
+        }
+        return (int) carry;
+    }
+
+    static int inplaceAdd(int[] a, int aSize, int addend) {
+        long carry = addend & 0xFFFFFFFFL;
+
+        for (int i = 0; (carry != 0) && (i < aSize); i++) {
+            carry += a[i] & 0xFFFFFFFFL;
+            a[i] = (int) carry;
+            carry >>= 32;
+        }
+        return (int) carry;
+    }
+
+    /** @see BigInteger#BigInteger(String, int) */
+    private static void parseFromString(BigInteger bi, String value, int radix) {
+        int stringLength = value.length();
+        int endChar = stringLength;
+
+        int sign;
+        int startChar;
+        if (value.charAt(0) == '-') {
+            sign = -1;
+            startChar = 1;
+            stringLength--;
+        } else {
+            sign = 1;
+            startChar = 0;
+        }
+
+        /*
+         * We use the following algorithm: split a string into portions of n
+         * characters and convert each portion to an integer according to the
+         * radix. Then convert an pow(radix, n) based number to binary using the
+         * multiplication method. See D. Knuth, The Art of Computer Programming,
+         * vol. 2.
+         */
+
+        int charsPerInt = Conversion.digitFitInInt[radix];
+        int bigRadixDigitsLength = stringLength / charsPerInt;
+        int topChars = stringLength % charsPerInt;
+
+        if (topChars != 0) {
+            bigRadixDigitsLength++;
+        }
+        int[] digits = new int[bigRadixDigitsLength];
+        // Get the maximal power of radix that fits in int
+        int bigRadix = Conversion.bigRadices[radix - 2];
+        // Parse an input string and accumulate the BigInteger's magnitude
+        int digitIndex = 0; // index of digits array
+        int substrEnd = startChar + ((topChars == 0) ? charsPerInt : topChars);
+
+        for (int substrStart = startChar; substrStart < endChar;
+                substrStart = substrEnd, substrEnd = substrStart + charsPerInt) {
+            int bigRadixDigit = Integer.parseInt(value.substring(substrStart, substrEnd), radix);
+            int newDigit = multiplyByInt(digits, digits, digitIndex, bigRadix);
+            newDigit += inplaceAdd(digits, digitIndex, bigRadixDigit);
+            digits[digitIndex++] = newDigit;
+        }
+        int numberLength = digitIndex;
+        bi.setJavaRepresentation(sign, numberLength, digits);
+    }
+
+    int getFirstNonzeroDigit() {
+        if (firstNonzeroDigit == -2) {
+            int i;
+            if (this.sign == 0) {
+                i = -1;
+            } else {
+                for (i = 0; digits[i] == 0; i++) {
+                    ;
+                }
+            }
+            firstNonzeroDigit = i;
+        }
+        return firstNonzeroDigit;
+    }
+
+    /**
+     * Returns a copy of the current instance to achieve immutability
+     */
+    BigInteger copy() {
+        prepareJavaRepresentation();
+        int[] copyDigits = new int[numberLength];
+        System.arraycopy(digits, 0, copyDigits, 0, numberLength);
+        return new BigInteger(sign, numberLength, copyDigits);
+    }
+
+    /**
+     * Assigns all transient fields upon deserialization of a {@code BigInteger}
+     * instance.
+     */
+    private void readObject(ObjectInputStream in)
+            throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        BigInt bigInt = new BigInt();
+        bigInt.putBigEndian(magnitude, signum < 0);
+        setBigInt(bigInt);
+    }
+
+    /**
+     * Prepares this {@code BigInteger} for serialization, i.e. the
+     * non-transient fields {@code signum} and {@code magnitude} are assigned.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        BigInt bigInt = getBigInt();
+        signum = bigInt.sign();
+        magnitude = bigInt.bigEndianMagnitude();
+        out.defaultWriteObject();
+    }
+}
diff --git a/java/math/BitLevel.java b/java/math/BitLevel.java
new file mode 100644
index 0000000..91f7a9b
--- /dev/null
+++ b/java/math/BitLevel.java
@@ -0,0 +1,255 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+/**
+ * Static library that provides all the <b>bit level</b> operations for
+ * {@link BigInteger}. The operations are:
+ * <ul type="circle">
+ * <li>Left Shifting</li>
+ * <li>Right Shifting</li>
+ * <li>Bit clearing</li>
+ * <li>Bit setting</li>
+ * <li>Bit counting</li>
+ * <li>Bit testing</li>
+ * <li>Getting of the lowest bit set</li>
+ * </ul>
+ * All operations are provided in immutable way, and some in both mutable and
+ * immutable.
+ */
+class BitLevel {
+
+    /** Just to denote that this class can't be instantiated. */
+    private BitLevel() {}
+
+    /** @see BigInteger#bitLength() */
+    static int bitLength(BigInteger val) {
+        val.prepareJavaRepresentation();
+        if (val.sign == 0) {
+            return 0;
+        }
+        int bLength = (val.numberLength << 5);
+        int highDigit = val.digits[val.numberLength - 1];
+
+        if (val.sign < 0) {
+            int i = val.getFirstNonzeroDigit();
+            // We reduce the problem to the positive case.
+            if (i == val.numberLength - 1) {
+                highDigit--;
+            }
+        }
+        // Subtracting all sign bits
+        bLength -= Integer.numberOfLeadingZeros(highDigit);
+        return bLength;
+    }
+
+    /** @see BigInteger#bitCount() */
+    static int bitCount(BigInteger val) {
+        val.prepareJavaRepresentation();
+        int bCount = 0;
+
+        if (val.sign == 0) {
+            return 0;
+        }
+
+        int i = val.getFirstNonzeroDigit();
+        if (val.sign > 0) {
+            for ( ; i < val.numberLength; i++) {
+                bCount += Integer.bitCount(val.digits[i]);
+            }
+        } else {// (sign < 0)
+            // this digit absorbs the carry
+            bCount += Integer.bitCount(-val.digits[i]);
+            for (i++; i < val.numberLength; i++) {
+                bCount += Integer.bitCount(~val.digits[i]);
+            }
+            // We take the complement sum:
+            bCount = (val.numberLength << 5) - bCount;
+        }
+        return bCount;
+    }
+
+    /**
+     * Performs a fast bit testing for positive numbers. The bit to to be tested
+     * must be in the range {@code [0, val.bitLength()-1]}
+     */
+    static boolean testBit(BigInteger val, int n) {
+        val.prepareJavaRepresentation();
+        // PRE: 0 <= n < val.bitLength()
+        return ((val.digits[n >> 5] & (1 << (n & 31))) != 0);
+    }
+
+    /**
+     * Check if there are 1s in the lowest bits of this BigInteger
+     *
+     * @param numberOfBits the number of the lowest bits to check
+     * @return false if all bits are 0s, true otherwise
+     */
+    static boolean nonZeroDroppedBits(int numberOfBits, int[] digits) {
+        int intCount = numberOfBits >> 5;
+        int bitCount = numberOfBits & 31;
+        int i;
+
+        for (i = 0; (i < intCount) && (digits[i] == 0); i++) {
+            ;
+        }
+        return ((i != intCount) || (digits[i] << (32 - bitCount) != 0));
+    }
+
+    static void shiftLeftOneBit(int[] result, int[] source, int srcLen) {
+        int carry = 0;
+        for (int i = 0; i < srcLen; i++) {
+            int val = source[i];
+            result[i] = (val << 1) | carry;
+            carry = val >>> 31;
+        }
+        if(carry != 0) {
+            result[srcLen] = carry;
+        }
+    }
+
+    static BigInteger shiftLeftOneBit(BigInteger source) {
+        source.prepareJavaRepresentation();
+        int srcLen = source.numberLength;
+        int resLen = srcLen + 1;
+        int[] resDigits = new int[resLen];
+        shiftLeftOneBit(resDigits, source.digits, srcLen);
+        return new BigInteger(source.sign, resLen, resDigits);
+    }
+
+    /** @see BigInteger#shiftRight(int) */
+    static BigInteger shiftRight(BigInteger source, int count) {
+        source.prepareJavaRepresentation();
+        int intCount = count >> 5; // count of integers
+        count &= 31; // count of remaining bits
+        if (intCount >= source.numberLength) {
+            return ((source.sign < 0) ? BigInteger.MINUS_ONE : BigInteger.ZERO);
+        }
+        int i;
+        int resLength = source.numberLength - intCount;
+        int[] resDigits = new int[resLength + 1];
+
+        shiftRight(resDigits, resLength, source.digits, intCount, count);
+        if (source.sign < 0) {
+            // Checking if the dropped bits are zeros (the remainder equals to
+            // 0)
+            for (i = 0; (i < intCount) && (source.digits[i] == 0); i++) {
+                ;
+            }
+            // If the remainder is not zero, add 1 to the result
+            if ((i < intCount)
+                    || ((count > 0) && ((source.digits[i] << (32 - count)) != 0))) {
+                for (i = 0; (i < resLength) && (resDigits[i] == -1); i++) {
+                    resDigits[i] = 0;
+                }
+                if (i == resLength) {
+                    resLength++;
+                }
+                resDigits[i]++;
+            }
+        }
+        return new BigInteger(source.sign, resLength, resDigits);
+    }
+
+    /**
+     * Shifts right an array of integers. Total shift distance in bits is
+     * intCount * 32 + count.
+     *
+     * @param result
+     *            the destination array
+     * @param resultLen
+     *            the destination array's length
+     * @param source
+     *            the source array
+     * @param intCount
+     *            the number of elements to be shifted
+     * @param count
+     *            the number of bits to be shifted
+     * @return dropped bit's are all zero (i.e. remaider is zero)
+     */
+    static boolean shiftRight(int[] result, int resultLen, int[] source, int intCount, int count) {
+        int i;
+        boolean allZero = true;
+        for (i = 0; i < intCount; i++)
+            allZero &= source[i] == 0;
+        if (count == 0) {
+            System.arraycopy(source, intCount, result, 0, resultLen);
+            i = resultLen;
+        } else {
+            int leftShiftCount = 32 - count;
+
+            allZero &= ( source[i] << leftShiftCount ) == 0;
+            for (i = 0; i < resultLen - 1; i++) {
+                result[i] = ( source[i + intCount] >>> count )
+                | ( source[i + intCount + 1] << leftShiftCount );
+            }
+            result[i] = ( source[i + intCount] >>> count );
+            i++;
+        }
+
+        return allZero;
+    }
+
+
+    /**
+     * Performs a flipBit on the BigInteger, returning a BigInteger with the the
+     * specified bit flipped.
+     */
+    static BigInteger flipBit(BigInteger val, int n){
+        val.prepareJavaRepresentation();
+        int resSign = (val.sign == 0) ? 1 : val.sign;
+        int intCount = n >> 5;
+        int bitN = n & 31;
+        int resLength = Math.max(intCount + 1, val.numberLength) + 1;
+        int[] resDigits = new int[resLength];
+        int i;
+
+        int bitNumber = 1 << bitN;
+        System.arraycopy(val.digits, 0, resDigits, 0, val.numberLength);
+
+        if (val.sign < 0) {
+            if (intCount >= val.numberLength) {
+                resDigits[intCount] = bitNumber;
+            } else {
+                //val.sign<0 y intCount < val.numberLength
+                int firstNonZeroDigit = val.getFirstNonzeroDigit();
+                if (intCount > firstNonZeroDigit) {
+                    resDigits[intCount] ^= bitNumber;
+                } else if (intCount < firstNonZeroDigit) {
+                    resDigits[intCount] = -bitNumber;
+                    for (i=intCount + 1; i < firstNonZeroDigit; i++) {
+                        resDigits[i]=-1;
+                    }
+                    resDigits[i] = resDigits[i]--;
+                } else {
+                    i = intCount;
+                    resDigits[i] = -((-resDigits[intCount]) ^ bitNumber);
+                    if (resDigits[i] == 0) {
+                        for (i++; resDigits[i] == -1 ; i++) {
+                            resDigits[i] = 0;
+                        }
+                        resDigits[i]++;
+                    }
+                }
+            }
+        } else {//case where val is positive
+            resDigits[intCount] ^= bitNumber;
+        }
+        return new BigInteger(resSign, resLength, resDigits);
+    }
+}
diff --git a/java/math/Conversion.java b/java/math/Conversion.java
new file mode 100644
index 0000000..585fff4
--- /dev/null
+++ b/java/math/Conversion.java
@@ -0,0 +1,461 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+/**
+ * Static library that provides {@link BigInteger} base conversion from/to any
+ * integer represented in an {@link java.lang.String} Object.
+ */
+class Conversion {
+
+    /** Just to denote that this class can't be instantiated */
+    private Conversion() {}
+
+    /**
+     * Holds the maximal exponent for each radix, so that radix<sup>digitFitInInt[radix]</sup>
+     * fit in an {@code int} (32 bits).
+     */
+    static final int[] digitFitInInt = { -1, -1, 31, 19, 15, 13, 11,
+            11, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
+            6, 6, 6, 6, 6, 6, 6, 5 };
+
+    /**
+     * bigRadices values are precomputed maximal powers of radices (integer
+     * numbers from 2 to 36) that fit into unsigned int (32 bits). bigRadices[0] =
+     * 2 ^ 31, bigRadices[8] = 10 ^ 9, etc.
+     */
+
+    static final int[] bigRadices = { -2147483648, 1162261467,
+            1073741824, 1220703125, 362797056, 1977326743, 1073741824,
+            387420489, 1000000000, 214358881, 429981696, 815730721, 1475789056,
+            170859375, 268435456, 410338673, 612220032, 893871739, 1280000000,
+            1801088541, 113379904, 148035889, 191102976, 244140625, 308915776,
+            387420489, 481890304, 594823321, 729000000, 887503681, 1073741824,
+            1291467969, 1544804416, 1838265625, 60466176 };
+
+
+    /** @see BigInteger#toString(int) */
+    static String bigInteger2String(BigInteger val, int radix) {
+        val.prepareJavaRepresentation();
+        int sign = val.sign;
+        int numberLength = val.numberLength;
+        int[] digits = val.digits;
+
+        if (sign == 0) {
+            return "0";
+        }
+        if (numberLength == 1) {
+            int highDigit = digits[numberLength - 1];
+            long v = highDigit & 0xFFFFFFFFL;
+            if (sign < 0) {
+                v = -v;
+            }
+            return Long.toString(v, radix);
+        }
+        if ((radix == 10) || (radix < Character.MIN_RADIX)
+                || (radix > Character.MAX_RADIX)) {
+            return val.toString();
+        }
+        double bitsForRadixDigit;
+        bitsForRadixDigit = Math.log(radix) / Math.log(2);
+        int resLengthInChars = (int) (val.abs().bitLength() / bitsForRadixDigit + ((sign < 0) ? 1
+                : 0)) + 1;
+
+        char[] result = new char[resLengthInChars];
+        int currentChar = resLengthInChars;
+        int resDigit;
+        if (radix != 16) {
+            int[] temp = new int[numberLength];
+            System.arraycopy(digits, 0, temp, 0, numberLength);
+            int tempLen = numberLength;
+            int charsPerInt = digitFitInInt[radix];
+            int i;
+            // get the maximal power of radix that fits in int
+            int bigRadix = bigRadices[radix - 2];
+            while (true) {
+                // divide the array of digits by bigRadix and convert remainders
+                // to characters collecting them in the char array
+                resDigit = Division.divideArrayByInt(temp, temp, tempLen,
+                        bigRadix);
+                int previous = currentChar;
+                do {
+                    result[--currentChar] = Character.forDigit(
+                            resDigit % radix, radix);
+                } while (((resDigit /= radix) != 0) && (currentChar != 0));
+                int delta = charsPerInt - previous + currentChar;
+                for (i = 0; i < delta && currentChar > 0; i++) {
+                    result[--currentChar] = '0';
+                }
+                for (i = tempLen - 1; (i > 0) && (temp[i] == 0); i--) {
+                    ;
+                }
+                tempLen = i + 1;
+                if ((tempLen == 1) && (temp[0] == 0)) { // the quotient is 0
+                    break;
+                }
+            }
+        } else {
+            // radix == 16
+            for (int i = 0; i < numberLength; i++) {
+                for (int j = 0; (j < 8) && (currentChar > 0); j++) {
+                    resDigit = digits[i] >> (j << 2) & 0xf;
+                    result[--currentChar] = Character.forDigit(resDigit, 16);
+                }
+            }
+        }
+        while (result[currentChar] == '0') {
+            currentChar++;
+        }
+        if (sign == -1) {
+            result[--currentChar] = '-';
+        }
+        return new String(result, currentChar, resLengthInChars - currentChar);
+    }
+
+    /**
+     * Builds the correspondent {@code String} representation of {@code val}
+     * being scaled by {@code scale}.
+     *
+     * @see BigInteger#toString()
+     * @see BigDecimal#toString()
+     */
+    static String toDecimalScaledString(BigInteger val, int scale) {
+        val.prepareJavaRepresentation();
+        int sign = val.sign;
+        int numberLength = val.numberLength;
+        int[] digits = val.digits;
+        int resLengthInChars;
+        int currentChar;
+        char[] result;
+
+        if (sign == 0) {
+            switch (scale) {
+                case 0:
+                    return "0";
+                case 1:
+                    return "0.0";
+                case 2:
+                    return "0.00";
+                case 3:
+                    return "0.000";
+                case 4:
+                    return "0.0000";
+                case 5:
+                    return "0.00000";
+                case 6:
+                    return "0.000000";
+                default:
+                    StringBuilder result1 = new StringBuilder();
+                    if (scale < 0) {
+                        result1.append("0E+");
+                    } else {
+                        result1.append("0E");
+                    }
+                    result1.append(-scale);
+                    return result1.toString();
+            }
+        }
+        // one 32-bit unsigned value may contains 10 decimal digits
+        resLengthInChars = numberLength * 10 + 1 + 7;
+        // Explanation why +1+7:
+        // +1 - one char for sign if needed.
+        // +7 - For "special case 2" (see below) we have 7 free chars for
+        // inserting necessary scaled digits.
+        result = new char[resLengthInChars + 1];
+        // allocated [resLengthInChars+1] characters.
+        // a free latest character may be used for "special case 1" (see
+        // below)
+        currentChar = resLengthInChars;
+        if (numberLength == 1) {
+            int highDigit = digits[0];
+            if (highDigit < 0) {
+                long v = highDigit & 0xFFFFFFFFL;
+                do {
+                    long prev = v;
+                    v /= 10;
+                    result[--currentChar] = (char) (0x0030 + ((int) (prev - v * 10)));
+                } while (v != 0);
+            } else {
+                int v = highDigit;
+                do {
+                    int prev = v;
+                    v /= 10;
+                    result[--currentChar] = (char) (0x0030 + (prev - v * 10));
+                } while (v != 0);
+            }
+        } else {
+            int[] temp = new int[numberLength];
+            int tempLen = numberLength;
+            System.arraycopy(digits, 0, temp, 0, tempLen);
+            BIG_LOOP: while (true) {
+                // divide the array of digits by bigRadix and convert
+                // remainders
+                // to characters collecting them in the char array
+                long result11 = 0;
+                for (int i1 = tempLen - 1; i1 >= 0; i1--) {
+                    long temp1 = (result11 << 32)
+                            + (temp[i1] & 0xFFFFFFFFL);
+                    long res = divideLongByBillion(temp1);
+                    temp[i1] = (int) res;
+                    result11 = (int) (res >> 32);
+                }
+                int resDigit = (int) result11;
+                int previous = currentChar;
+                do {
+                    result[--currentChar] = (char) (0x0030 + (resDigit % 10));
+                } while (((resDigit /= 10) != 0) && (currentChar != 0));
+                int delta = 9 - previous + currentChar;
+                for (int i = 0; (i < delta) && (currentChar > 0); i++) {
+                    result[--currentChar] = '0';
+                }
+                int j = tempLen - 1;
+                for (; temp[j] == 0; j--) {
+                    if (j == 0) { // means temp[0] == 0
+                        break BIG_LOOP;
+                    }
+                }
+                tempLen = j + 1;
+            }
+            while (result[currentChar] == '0') {
+                currentChar++;
+            }
+        }
+        boolean negNumber = (sign < 0);
+        int exponent = resLengthInChars - currentChar - scale - 1;
+        if (scale == 0) {
+            if (negNumber) {
+                result[--currentChar] = '-';
+            }
+            return new String(result, currentChar, resLengthInChars
+                    - currentChar);
+        }
+        if ((scale > 0) && (exponent >= -6)) {
+            if (exponent >= 0) {
+                // special case 1
+                int insertPoint = currentChar + exponent;
+                for (int j = resLengthInChars - 1; j >= insertPoint; j--) {
+                    result[j + 1] = result[j];
+                }
+                result[++insertPoint] = '.';
+                if (negNumber) {
+                    result[--currentChar] = '-';
+                }
+                return new String(result, currentChar, resLengthInChars
+                        - currentChar + 1);
+            }
+            // special case 2
+            for (int j = 2; j < -exponent + 1; j++) {
+                result[--currentChar] = '0';
+            }
+            result[--currentChar] = '.';
+            result[--currentChar] = '0';
+            if (negNumber) {
+                result[--currentChar] = '-';
+            }
+            return new String(result, currentChar, resLengthInChars
+                    - currentChar);
+        }
+        int startPoint = currentChar + 1;
+        int endPoint = resLengthInChars;
+        StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint);
+        if (negNumber) {
+            result1.append('-');
+        }
+        if (endPoint - startPoint >= 1) {
+            result1.append(result[currentChar]);
+            result1.append('.');
+            result1.append(result, currentChar + 1, resLengthInChars
+                    - currentChar - 1);
+        } else {
+            result1.append(result, currentChar, resLengthInChars
+                    - currentChar);
+        }
+        result1.append('E');
+        if (exponent > 0) {
+            result1.append('+');
+        }
+        result1.append(Integer.toString(exponent));
+        return result1.toString();
+    }
+
+    /* can process only 32-bit numbers */
+    static String toDecimalScaledString(long value, int scale) {
+        int resLengthInChars;
+        int currentChar;
+        char[] result;
+        boolean negNumber = value < 0;
+        if(negNumber) {
+            value = -value;
+        }
+        if (value == 0) {
+            switch (scale) {
+                case 0: return "0";
+                case 1: return "0.0";
+                case 2: return "0.00";
+                case 3: return "0.000";
+                case 4: return "0.0000";
+                case 5: return "0.00000";
+                case 6: return "0.000000";
+                default:
+                    StringBuilder result1 = new StringBuilder();
+                    if (scale  < 0) {
+                        result1.append("0E+");
+                    } else {
+                        result1.append("0E");
+                    }
+                    result1.append( (scale == Integer.MIN_VALUE) ? "2147483648" : Integer.toString(-scale));
+                    return result1.toString();
+            }
+        }
+        // one 32-bit unsigned value may contains 10 decimal digits
+        resLengthInChars = 18;
+        // Explanation why +1+7:
+        // +1 - one char for sign if needed.
+        // +7 - For "special case 2" (see below) we have 7 free chars for
+        //  inserting necessary scaled digits.
+        result = new char[resLengthInChars+1];
+        //  Allocated [resLengthInChars+1] characters.
+        // a free latest character may be used for "special case 1" (see below)
+        currentChar = resLengthInChars;
+        long v = value;
+        do {
+            long prev = v;
+            v /= 10;
+            result[--currentChar] = (char) (0x0030 + (prev - v * 10));
+        } while (v != 0);
+
+        long exponent = (long)resLengthInChars - (long)currentChar - scale - 1L;
+        if (scale == 0) {
+            if (negNumber) {
+                result[--currentChar] = '-';
+            }
+            return new String(result, currentChar, resLengthInChars - currentChar);
+        }
+        if (scale > 0 && exponent >= -6) {
+            if (exponent >= 0) {
+                // special case 1
+                int insertPoint = currentChar + (int) exponent ;
+                for (int j=resLengthInChars-1; j>=insertPoint; j--) {
+                    result[j+1] = result[j];
+                }
+                result[++insertPoint]='.';
+                if (negNumber) {
+                    result[--currentChar] = '-';
+                }
+                return new String(result, currentChar, resLengthInChars - currentChar + 1);
+            }
+            // special case 2
+            for (int j = 2; j < -exponent + 1; j++) {
+                result[--currentChar] = '0';
+            }
+            result[--currentChar] = '.';
+            result[--currentChar] = '0';
+            if (negNumber) {
+                result[--currentChar] = '-';
+            }
+            return new String(result, currentChar, resLengthInChars - currentChar);
+        }
+        int startPoint = currentChar + 1;
+        int endPoint = resLengthInChars;
+        StringBuilder result1 = new StringBuilder(16 + endPoint - startPoint);
+        if (negNumber) {
+            result1.append('-');
+        }
+        if (endPoint - startPoint >= 1) {
+            result1.append(result[currentChar]);
+            result1.append('.');
+            result1.append(result,currentChar+1,resLengthInChars - currentChar-1);
+        } else {
+            result1.append(result,currentChar,resLengthInChars - currentChar);
+        }
+        result1.append('E');
+        if (exponent > 0) {
+            result1.append('+');
+        }
+        result1.append(Long.toString(exponent));
+        return result1.toString();
+    }
+
+    static long divideLongByBillion(long a) {
+        long quot;
+        long rem;
+
+        if (a >= 0) {
+            long bLong = 1000000000L;
+            quot = (a / bLong);
+            rem = (a % bLong);
+        } else {
+            /*
+             * Make the dividend positive shifting it right by 1 bit then get
+             * the quotient an remainder and correct them properly
+             */
+            long aPos = a >>> 1;
+            long bPos = 1000000000L >>> 1;
+            quot = aPos / bPos;
+            rem = aPos % bPos;
+            // double the remainder and add 1 if 'a' is odd
+            rem = (rem << 1) + (a & 1);
+        }
+        return ((rem << 32) | (quot & 0xFFFFFFFFL));
+    }
+
+    /** @see BigInteger#doubleValue() */
+    static double bigInteger2Double(BigInteger val) {
+        val.prepareJavaRepresentation();
+        // val.bitLength() < 64
+        if ((val.numberLength < 2)
+                || ((val.numberLength == 2) && (val.digits[1] > 0))) {
+            return val.longValue();
+        }
+        // val.bitLength() >= 33 * 32 > 1024
+        if (val.numberLength > 32) {
+            return ((val.sign > 0) ? Double.POSITIVE_INFINITY
+                    : Double.NEGATIVE_INFINITY);
+        }
+        int bitLen = val.abs().bitLength();
+        long exponent = bitLen - 1;
+        int delta = bitLen - 54;
+        // We need 54 top bits from this, the 53th bit is always 1 in lVal.
+        long lVal = val.abs().shiftRight(delta).longValue();
+        /*
+         * Take 53 bits from lVal to mantissa. The least significant bit is
+         * needed for rounding.
+         */
+        long mantissa = lVal & 0x1FFFFFFFFFFFFFL;
+        if (exponent == 1023) {
+            if (mantissa == 0X1FFFFFFFFFFFFFL) {
+                return ((val.sign > 0) ? Double.POSITIVE_INFINITY
+                        : Double.NEGATIVE_INFINITY);
+            }
+            if (mantissa == 0x1FFFFFFFFFFFFEL) {
+                return ((val.sign > 0) ? Double.MAX_VALUE : -Double.MAX_VALUE);
+            }
+        }
+        // Round the mantissa
+        if (((mantissa & 1) == 1)
+                && (((mantissa & 2) == 2) || BitLevel.nonZeroDroppedBits(delta,
+                        val.digits))) {
+            mantissa += 2;
+        }
+        mantissa >>= 1; // drop the rounding bit
+        long resSign = (val.sign < 0) ? 0x8000000000000000L : 0;
+        exponent = ((1023 + exponent) << 52) & 0x7FF0000000000000L;
+        long result = resSign | exponent | mantissa;
+        return Double.longBitsToDouble(result);
+    }
+}
diff --git a/java/math/Division.java b/java/math/Division.java
new file mode 100644
index 0000000..d642783
--- /dev/null
+++ b/java/math/Division.java
@@ -0,0 +1,91 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+/**
+ * Static library that provides all operations related with division and modular
+ * arithmetic to {@link BigInteger}. Some methods are provided in both mutable
+ * and immutable way. There are several variants provided listed below:
+ *
+ * <ul type="circle">
+ * <li> <b>Division</b>
+ * <ul type="circle">
+ * <li>{@link BigInteger} division and remainder by {@link BigInteger}.</li>
+ * <li>{@link BigInteger} division and remainder by {@code int}.</li>
+ * <li><i>gcd</i> between {@link BigInteger} numbers.</li>
+ * </ul>
+ * </li>
+ * <li> <b>Modular arithmetic </b>
+ * <ul type="circle">
+ * <li>Modular exponentiation between {@link BigInteger} numbers.</li>
+ * <li>Modular inverse of a {@link BigInteger} numbers.</li>
+ * </ul>
+ * </li>
+ *</ul>
+ */
+class Division {
+
+    /**
+     * Divides an array by an integer value. Implements the Knuth's division
+     * algorithm. See D. Knuth, The Art of Computer Programming, vol. 2.
+     *
+     * @return remainder
+     */
+    static int divideArrayByInt(int[] quotient, int[] dividend, final int dividendLength,
+            final int divisor) {
+
+        long rem = 0;
+        long bLong = divisor & 0xffffffffL;
+
+        for (int i = dividendLength - 1; i >= 0; i--) {
+            long temp = (rem << 32) | (dividend[i] & 0xffffffffL);
+            long quot;
+            if (temp >= 0) {
+                quot = (temp / bLong);
+                rem = (temp % bLong);
+            } else {
+                /*
+                 * make the dividend positive shifting it right by 1 bit then
+                 * get the quotient an remainder and correct them properly
+                 */
+                long aPos = temp >>> 1;
+                long bPos = divisor >>> 1;
+                quot = aPos / bPos;
+                rem = aPos % bPos;
+                // double the remainder and add 1 if a is odd
+                rem = (rem << 1) + (temp & 1);
+                if ((divisor & 1) != 0) {
+                    // the divisor is odd
+                    if (quot <= rem) {
+                        rem -= quot;
+                    } else {
+                        if (quot - rem <= bLong) {
+                            rem += bLong - quot;
+                            quot -= 1;
+                        } else {
+                            rem += (bLong << 1) - quot;
+                            quot -= 2;
+                        }
+                    }
+                }
+            }
+            quotient[i] = (int) (quot & 0xffffffffL);
+        }
+        return (int) rem;
+    }
+}
diff --git a/java/math/Logical.java b/java/math/Logical.java
new file mode 100644
index 0000000..9de0924
--- /dev/null
+++ b/java/math/Logical.java
@@ -0,0 +1,773 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+/**
+ * The library implements some logical operations over {@code BigInteger}. The
+ * operations provided are listed below.
+ * <ul type="circle">
+ * <li>not</li>
+ * <li>and</li>
+ * <li>andNot</li>
+ * <li>or</li>
+ * <li>xor</li>
+ * </ul>
+ */
+class Logical {
+
+    /** Just to denote that this class can't be instantiated. */
+
+    private Logical() {}
+
+
+    /** @see BigInteger#not() */
+    static BigInteger not(BigInteger val) {
+        if (val.sign == 0) {
+            return BigInteger.MINUS_ONE;
+        }
+        if (val.equals(BigInteger.MINUS_ONE)) {
+            return BigInteger.ZERO;
+        }
+        int[] resDigits = new int[val.numberLength + 1];
+        int i;
+
+        if (val.sign > 0) {
+            // ~val = -val + 1
+            if (val.digits[val.numberLength - 1] != -1) {
+                for (i = 0; val.digits[i] == -1; i++) {
+                    ;
+                }
+            } else {
+                for (i = 0; (i < val.numberLength) && (val.digits[i] == -1); i++) {
+                    ;
+                }
+                if (i == val.numberLength) {
+                    resDigits[i] = 1;
+                    return new BigInteger(-val.sign, i + 1, resDigits);
+                }
+            }
+            // Here a carry 1 was generated
+        } else {// (val.sign < 0)
+            // ~val = -val - 1
+            for (i = 0; val.digits[i] == 0; i++) {
+                resDigits[i] = -1;
+            }
+            // Here a borrow -1 was generated
+        }
+        // Now, the carry/borrow can be absorbed
+        resDigits[i] = val.digits[i] + val.sign;
+        // Copying the remaining unchanged digit
+        for (i++; i < val.numberLength; i++) {
+            resDigits[i] = val.digits[i];
+        }
+        return new BigInteger(-val.sign, i, resDigits);
+    }
+
+    /** @see BigInteger#and(BigInteger) */
+    static BigInteger and(BigInteger val, BigInteger that) {
+        if (that.sign == 0 || val.sign == 0) {
+            return BigInteger.ZERO;
+        }
+        if (that.equals(BigInteger.MINUS_ONE)){
+            return val;
+        }
+        if (val.equals(BigInteger.MINUS_ONE)) {
+            return that;
+        }
+
+        if (val.sign > 0) {
+            if (that.sign > 0) {
+                return andPositive(val, that);
+            } else {
+                return andDiffSigns(val, that);
+            }
+        } else {
+            if (that.sign > 0) {
+                return andDiffSigns(that, val);
+            } else if (val.numberLength > that.numberLength) {
+                return andNegative(val, that);
+            } else {
+                return andNegative(that, val);
+            }
+        }
+    }
+
+    /** @return sign = 1, magnitude = val.magnitude & that.magnitude*/
+    static BigInteger andPositive(BigInteger val, BigInteger that) {
+        // PRE: both arguments are positive
+        int resLength = Math.min(val.numberLength, that.numberLength);
+        int i = Math.max(val.getFirstNonzeroDigit(), that.getFirstNonzeroDigit());
+
+        if (i >= resLength) {
+            return BigInteger.ZERO;
+        }
+
+        int[] resDigits = new int[resLength];
+        for ( ; i < resLength; i++) {
+            resDigits[i] = val.digits[i] & that.digits[i];
+        }
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @return sign = positive.magnitude & magnitude = -negative.magnitude */
+    static BigInteger andDiffSigns(BigInteger positive, BigInteger negative) {
+        // PRE: positive is positive and negative is negative
+        int iPos = positive.getFirstNonzeroDigit();
+        int iNeg = negative.getFirstNonzeroDigit();
+
+        // Look if the trailing zeros of the negative will "blank" all
+        // the positive digits
+        if (iNeg >= positive.numberLength) {
+            return BigInteger.ZERO;
+        }
+        int resLength = positive.numberLength;
+        int[] resDigits = new int[resLength];
+
+        // Must start from max(iPos, iNeg)
+        int i = Math.max(iPos, iNeg);
+        if (i == iNeg) {
+            resDigits[i] = -negative.digits[i] & positive.digits[i];
+            i++;
+        }
+        int limit = Math.min(negative.numberLength, positive.numberLength);
+        for ( ; i < limit; i++) {
+            resDigits[i] = ~negative.digits[i] & positive.digits[i];
+        }
+        // if the negative was shorter must copy the remaining digits
+        // from positive
+        if (i >= negative.numberLength) {
+            for ( ; i < positive.numberLength; i++) {
+                resDigits[i] = positive.digits[i];
+            }
+        } // else positive ended and must "copy" virtual 0's, do nothing then
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @return sign = -1, magnitude = -(-longer.magnitude & -shorter.magnitude)*/
+    static BigInteger andNegative(BigInteger longer, BigInteger shorter) {
+        // PRE: longer and shorter are negative
+        // PRE: longer has at least as many digits as shorter
+        int iLonger = longer.getFirstNonzeroDigit();
+        int iShorter = shorter.getFirstNonzeroDigit();
+
+        // Does shorter matter?
+        if (iLonger >= shorter.numberLength) {
+            return longer;
+        }
+
+        int resLength;
+        int[] resDigits;
+        int i = Math.max(iShorter, iLonger);
+        int digit;
+        if (iShorter > iLonger) {
+            digit = -shorter.digits[i] & ~longer.digits[i];
+        } else if (iShorter < iLonger) {
+            digit = ~shorter.digits[i] & -longer.digits[i];
+        } else {
+            digit = -shorter.digits[i] & -longer.digits[i];
+        }
+        if (digit == 0) {
+            for (i++; i < shorter.numberLength && (digit = ~(longer.digits[i] | shorter.digits[i])) == 0; i++)
+                ;  // digit = ~longer.digits[i] & ~shorter.digits[i]
+            if (digit == 0) {
+                // shorter has only the remaining virtual sign bits
+                for ( ; i < longer.numberLength && (digit = ~longer.digits[i]) == 0; i++)
+                    ;
+                if (digit == 0) {
+                    resLength = longer.numberLength + 1;
+                    resDigits = new int[resLength];
+                    resDigits[resLength - 1] = 1;
+
+                    return new BigInteger(-1, resLength, resDigits);
+                }
+            }
+        }
+        resLength = longer.numberLength;
+                resDigits = new int[resLength];
+        resDigits[i] = -digit;
+        for (i++; i < shorter.numberLength; i++){
+            // resDigits[i] = ~(~longer.digits[i] & ~shorter.digits[i];)
+            resDigits[i] = longer.digits[i] | shorter.digits[i];
+        }
+        // shorter has only the remaining virtual sign bits
+        for ( ; i < longer.numberLength; i++){
+            resDigits[i] = longer.digits[i];
+        }
+
+        return new BigInteger(-1, resLength, resDigits);
+    }
+
+    /** @see BigInteger#andNot(BigInteger) */
+    static BigInteger andNot(BigInteger val, BigInteger that) {
+        if (that.sign == 0 ) {
+            return val;
+        }
+        if (val.sign == 0) {
+            return BigInteger.ZERO;
+        }
+        if (val.equals(BigInteger.MINUS_ONE)) {
+            return that.not();
+        }
+        if (that.equals(BigInteger.MINUS_ONE)){
+            return BigInteger.ZERO;
+        }
+
+        //if val == that, return 0
+
+       if (val.sign > 0) {
+            if (that.sign > 0) {
+                return andNotPositive(val, that);
+            } else {
+                return andNotPositiveNegative(val, that);
+                    }
+                } else {
+            if (that.sign > 0) {
+                return andNotNegativePositive(val, that);
+            } else  {
+                return andNotNegative(val, that);
+            }
+        }
+    }
+
+    /** @return sign = 1, magnitude = val.magnitude & ~that.magnitude*/
+    static BigInteger andNotPositive(BigInteger val, BigInteger that) {
+        // PRE: both arguments are positive
+        int[] resDigits = new int[val.numberLength];
+
+        int limit = Math.min(val.numberLength, that.numberLength);
+        int i;
+        for (i = val.getFirstNonzeroDigit(); i < limit; i++) {
+            resDigits[i] = val.digits[i] & ~that.digits[i];
+        }
+        for ( ; i < val.numberLength; i++) {
+            resDigits[i] = val.digits[i];
+        }
+
+        return new BigInteger(1, val.numberLength, resDigits);
+    }
+
+    /** @return sign = 1, magnitude = positive.magnitude & ~(-negative.magnitude)*/
+    static BigInteger andNotPositiveNegative(BigInteger positive, BigInteger negative) {
+        // PRE: positive > 0 && negative < 0
+        int iNeg = negative.getFirstNonzeroDigit();
+        int iPos = positive.getFirstNonzeroDigit();
+
+        if (iNeg >= positive.numberLength) {
+            return positive;
+        }
+
+        int resLength = Math.min(positive.numberLength, negative.numberLength);
+        int[] resDigits = new int[resLength];
+
+        // Always start from first non zero of positive
+        int i = iPos;
+        for ( ; i < iNeg; i++) {
+            // resDigits[i] = positive.digits[i] & -1 (~0)
+            resDigits[i] = positive.digits[i];
+        }
+        if (i == iNeg) {
+            resDigits[i] = positive.digits[i] & (negative.digits[i] - 1);
+            i++;
+        }
+        for ( ; i < resLength; i++) {
+            // resDigits[i] = positive.digits[i] & ~(~negative.digits[i]);
+            resDigits[i] = positive.digits[i] & negative.digits[i];
+        }
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @return sign = -1, magnitude = -(-negative.magnitude & ~positive.magnitude)*/
+    static BigInteger andNotNegativePositive(BigInteger negative, BigInteger positive) {
+        // PRE: negative < 0 && positive > 0
+        int resLength;
+        int[] resDigits;
+        int limit;
+        int digit;
+
+        int iNeg = negative.getFirstNonzeroDigit();
+        int iPos = positive.getFirstNonzeroDigit();
+
+        if (iNeg >= positive.numberLength) {
+            return negative;
+        }
+
+        resLength = Math.max(negative.numberLength, positive.numberLength);
+        int i = iNeg;
+        if (iPos > iNeg) {
+            resDigits = new int[resLength];
+            limit = Math.min(negative.numberLength, iPos);
+            for ( ; i < limit; i++) {
+                // 1st case:  resDigits [i] = -(-negative.digits[i] & (~0))
+                // otherwise: resDigits[i] = ~(~negative.digits[i] & ~0)  ;
+                resDigits[i] = negative.digits[i];
+            }
+            if (i == negative.numberLength) {
+                for (i = iPos; i < positive.numberLength; i++) {
+                    // resDigits[i] = ~(~positive.digits[i] & -1);
+                    resDigits[i] = positive.digits[i];
+                }
+            }
+        } else {
+            digit = -negative.digits[i] & ~positive.digits[i];
+            if (digit == 0) {
+                limit = Math.min(positive.numberLength, negative.numberLength);
+                for (i++; i < limit && (digit = ~(negative.digits[i] | positive.digits[i])) == 0; i++)
+                    ; // digit = ~negative.digits[i] & ~positive.digits[i]
+                if (digit == 0) {
+                    // the shorter has only the remaining virtual sign bits
+                    for ( ; i < positive.numberLength && (digit = ~positive.digits[i]) == 0; i++)
+                        ; // digit = -1 & ~positive.digits[i]
+                    for ( ; i < negative.numberLength && (digit = ~negative.digits[i]) == 0; i++)
+                        ; // digit = ~negative.digits[i] & ~0
+                    if (digit == 0) {
+                        resLength++;
+                        resDigits = new int[resLength];
+                        resDigits[resLength - 1] = 1;
+
+                        return new BigInteger(-1, resLength, resDigits);
+                    }
+                }
+            }
+                        resDigits = new int[resLength];
+            resDigits[i] = -digit;
+            i++;
+                    }
+
+        limit = Math.min(positive.numberLength, negative.numberLength);
+        for ( ; i < limit; i++) {
+            //resDigits[i] = ~(~negative.digits[i] & ~positive.digits[i]);
+            resDigits[i] = negative.digits[i] | positive.digits[i];
+        }
+        // Actually one of the next two cycles will be executed
+        for ( ; i < negative.numberLength; i++) {
+            resDigits[i] = negative.digits[i];
+                }
+        for ( ; i < positive.numberLength; i++) {
+            resDigits[i] = positive.digits[i];
+        }
+
+        return new BigInteger(-1, resLength, resDigits);
+    }
+
+    /** @return sign = 1, magnitude = -val.magnitude & ~(-that.magnitude)*/
+    static BigInteger andNotNegative(BigInteger val, BigInteger that) {
+        // PRE: val < 0 && that < 0
+        int iVal = val.getFirstNonzeroDigit();
+        int iThat = that.getFirstNonzeroDigit();
+
+        if (iVal >= that.numberLength) {
+            return BigInteger.ZERO;
+        }
+
+        int resLength = that.numberLength;
+        int[] resDigits = new int[resLength];
+        int limit;
+        int i = iVal;
+        if (iVal < iThat) {
+            // resDigits[i] = -val.digits[i] & -1;
+            resDigits[i] = -val.digits[i];
+            limit = Math.min(val.numberLength, iThat);
+            for (i++; i < limit; i++) {
+                // resDigits[i] = ~val.digits[i] & -1;
+                resDigits[i] = ~val.digits[i];
+            }
+            if (i == val.numberLength) {
+                for ( ; i < iThat; i++) {
+                    // resDigits[i] = -1 & -1;
+                    resDigits[i] = -1;
+                }
+                // resDigits[i] = -1 & ~-that.digits[i];
+                resDigits[i] = that.digits[i] - 1;
+        } else {
+                // resDigits[i] = ~val.digits[i] & ~-that.digits[i];
+                resDigits[i] = ~val.digits[i] & (that.digits[i] - 1);
+            }
+        } else if (iThat < iVal ) {
+            // resDigits[i] = -val.digits[i] & ~~that.digits[i];
+            resDigits[i] = -val.digits[i] & that.digits[i];
+        } else {
+            // resDigits[i] = -val.digits[i] & ~-that.digits[i];
+            resDigits[i] = -val.digits[i] & (that.digits[i] - 1);
+            }
+
+        limit = Math.min(val.numberLength, that.numberLength);
+        for (i++; i < limit; i++) {
+            // resDigits[i] = ~val.digits[i] & ~~that.digits[i];
+            resDigits[i] = ~val.digits[i] & that.digits[i];
+        }
+        for ( ; i < that.numberLength; i++) {
+            // resDigits[i] = -1 & ~~that.digits[i];
+            resDigits[i] = that.digits[i];
+        }
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @see BigInteger#or(BigInteger) */
+    static BigInteger or(BigInteger val, BigInteger that) {
+        if (that.equals(BigInteger.MINUS_ONE) || val.equals(BigInteger.MINUS_ONE)) {
+            return BigInteger.MINUS_ONE;
+        }
+        if (that.sign == 0) {
+            return val;
+        }
+        if (val.sign == 0) {
+            return that;
+        }
+
+        if (val.sign > 0) {
+            if (that.sign > 0) {
+                if (val.numberLength > that.numberLength) {
+                    return orPositive(val, that);
+                } else {
+                    return orPositive(that, val);
+                }
+            } else {
+                return orDiffSigns(val, that);
+            }
+        } else {
+            if (that.sign > 0) {
+                return orDiffSigns(that, val);
+            } else if (that.getFirstNonzeroDigit() > val.getFirstNonzeroDigit()) {
+                return orNegative(that, val);
+            } else {
+                return orNegative(val, that);
+            }
+        }
+    }
+
+    /** @return sign = 1, magnitude = longer.magnitude | shorter.magnitude*/
+    static BigInteger orPositive(BigInteger longer, BigInteger shorter) {
+        // PRE: longer and shorter are positive;
+        // PRE: longer has at least as many digits as shorter
+        int resLength = longer.numberLength;
+        int[] resDigits = new int[resLength];
+
+        int i;
+        for (i = 0; i < shorter.numberLength; i++) {
+            resDigits[i] = longer.digits[i] | shorter.digits[i];
+        }
+        for ( ; i < resLength; i++) {
+            resDigits[i] = longer.digits[i];
+        }
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @return sign = -1, magnitude = -(-val.magnitude | -that.magnitude) */
+    static BigInteger orNegative(BigInteger val, BigInteger that){
+        // PRE: val and that are negative;
+        // PRE: val has at least as many trailing zeros digits as that
+        int iThat = that.getFirstNonzeroDigit();
+        int iVal = val.getFirstNonzeroDigit();
+        int i;
+
+        if (iVal >= that.numberLength) {
+            return that;
+        }else if (iThat >= val.numberLength) {
+            return val;
+        }
+
+        int resLength = Math.min(val.numberLength, that.numberLength);
+        int[] resDigits = new int[resLength];
+
+        //Looking for the first non-zero digit of the result
+        if (iThat == iVal) {
+            resDigits[iVal] = -(-val.digits[iVal] | -that.digits[iVal]);
+            i = iVal;
+        } else {
+            for (i = iThat; i < iVal; i++) {
+                resDigits[i] = that.digits[i];
+            }
+            resDigits[i] = that.digits[i] & (val.digits[i] - 1);
+        }
+
+        for (i++; i < resLength; i++) {
+            resDigits[i] = val.digits[i] & that.digits[i];
+        }
+
+        return new BigInteger(-1, resLength, resDigits);
+    }
+
+    /** @return sign = -1, magnitude = -(positive.magnitude | -negative.magnitude) */
+    static BigInteger orDiffSigns(BigInteger positive, BigInteger negative){
+        // Jumping over the least significant zero bits
+        int iNeg = negative.getFirstNonzeroDigit();
+        int iPos = positive.getFirstNonzeroDigit();
+        int i;
+        int limit;
+
+        // Look if the trailing zeros of the positive will "copy" all
+        // the negative digits
+        if (iPos >= negative.numberLength) {
+            return negative;
+        }
+        int resLength = negative.numberLength;
+        int[] resDigits = new int[resLength];
+
+        if (iNeg < iPos ) {
+            // We know for sure that this will
+            // be the first non zero digit in the result
+            for (i = iNeg; i < iPos; i++) {
+            resDigits[i] = negative.digits[i];
+            }
+        } else if (iPos < iNeg) {
+            i = iPos;
+            resDigits[i] = -positive.digits[i];
+            limit = Math.min(positive.numberLength, iNeg);
+            for (i++; i < limit; i++ ) {
+                resDigits[i] = ~positive.digits[i];
+            }
+            if (i != positive.numberLength) {
+                resDigits[i] = ~(-negative.digits[i] | positive.digits[i]);
+            } else{
+                  for (; i<iNeg; i++) {
+                      resDigits[i] = -1;
+                  }
+                  // resDigits[i] = ~(-negative.digits[i] | 0);
+                  resDigits[i] = negative.digits[i] - 1;
+            }
+            i++;
+        } else {// iNeg == iPos
+            // Applying two complement to negative and to result
+            i = iPos;
+            resDigits[i] = -(-negative.digits[i] | positive.digits[i]);
+            i++;
+        }
+        limit = Math.min(negative.numberLength, positive.numberLength);
+        for (; i < limit; i++) {
+            // Applying two complement to negative and to result
+            // resDigits[i] = ~(~negative.digits[i] | positive.digits[i] );
+            resDigits[i] = negative.digits[i] & ~positive.digits[i];
+        }
+        for ( ; i < negative.numberLength; i++) {
+            resDigits[i] = negative.digits[i];
+        }
+
+        return new BigInteger(-1, resLength, resDigits);
+    }
+
+    /** @see BigInteger#xor(BigInteger) */
+    static BigInteger xor(BigInteger val, BigInteger that) {
+        if (that.sign == 0) {
+            return val;
+        }
+        if (val.sign == 0) {
+            return that;
+        }
+        if (that.equals(BigInteger.MINUS_ONE)) {
+            return val.not();
+        }
+        if (val.equals(BigInteger.MINUS_ONE)) {
+            return that.not();
+        }
+
+        if (val.sign > 0) {
+            if (that.sign > 0) {
+                if (val.numberLength > that.numberLength) {
+                    return xorPositive(val, that);
+                } else {
+                    return xorPositive(that, val);
+                }
+            } else {
+                return xorDiffSigns(val, that);
+            }
+        } else {
+            if (that.sign > 0) {
+                return xorDiffSigns(that, val);
+            } else if (that.getFirstNonzeroDigit() > val.getFirstNonzeroDigit()) {
+                return xorNegative(that, val);
+            } else {
+                return xorNegative(val, that);
+            }
+        }
+    }
+
+    /** @return sign = 0, magnitude = longer.magnitude | shorter.magnitude */
+    static BigInteger xorPositive(BigInteger longer, BigInteger shorter) {
+        // PRE: longer and shorter are positive;
+        // PRE: longer has at least as many digits as shorter
+        int resLength = longer.numberLength;
+        int[] resDigits = new int[resLength];
+        int i = Math.min(longer.getFirstNonzeroDigit(), shorter.getFirstNonzeroDigit());
+        for ( ; i < shorter.numberLength; i++) {
+            resDigits[i] = longer.digits[i] ^ shorter.digits[i];
+        }
+        for ( ; i < longer.numberLength; i++ ){
+            resDigits[i] = longer.digits[i];
+        }
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @return sign = 0, magnitude = -val.magnitude ^ -that.magnitude */
+    static BigInteger xorNegative(BigInteger val, BigInteger that){
+        // PRE: val and that are negative
+        // PRE: val has at least as many trailing zero digits as that
+        int resLength = Math.max(val.numberLength, that.numberLength);
+        int[] resDigits = new int[resLength];
+        int iVal = val.getFirstNonzeroDigit();
+        int iThat = that.getFirstNonzeroDigit();
+        int i = iThat;
+        int limit;
+
+
+        if (iVal == iThat) {
+            resDigits[i] = -val.digits[i] ^ -that.digits[i];
+        } else {
+            resDigits[i] = -that.digits[i];
+            limit = Math.min(that.numberLength, iVal);
+            for (i++; i < limit; i++) {
+                resDigits[i] = ~that.digits[i];
+            }
+            // Remains digits in that?
+            if (i == that.numberLength) {
+                //Jumping over the remaining zero to the first non one
+                for ( ;i < iVal; i++) {
+                    //resDigits[i] = 0 ^ -1;
+                    resDigits[i] = -1;
+                }
+                //resDigits[i] = -val.digits[i] ^ -1;
+                resDigits[i] = val.digits[i] - 1;
+            } else {
+                resDigits[i] = -val.digits[i] ^ ~that.digits[i];
+            }
+        }
+
+        limit = Math.min(val.numberLength, that.numberLength);
+        //Perform ^ between that al val until that ends
+        for (i++; i < limit; i++) {
+            //resDigits[i] = ~val.digits[i] ^ ~that.digits[i];
+            resDigits[i] = val.digits[i] ^ that.digits[i];
+        }
+        //Perform ^ between val digits and -1 until val ends
+        for ( ; i < val.numberLength; i++) {
+            //resDigits[i] = ~val.digits[i] ^ -1  ;
+            resDigits[i] = val.digits[i] ;
+        }
+        for ( ; i < that.numberLength; i++) {
+            //resDigits[i] = -1 ^ ~that.digits[i] ;
+            resDigits[i] = that.digits[i];
+        }
+
+        return new BigInteger(1, resLength, resDigits);
+    }
+
+    /** @return sign = 1, magnitude = -(positive.magnitude ^ -negative.magnitude)*/
+    static BigInteger xorDiffSigns(BigInteger positive, BigInteger negative){
+        int resLength = Math.max(negative.numberLength, positive.numberLength);
+        int[] resDigits;
+        int iNeg = negative.getFirstNonzeroDigit();
+        int iPos = positive.getFirstNonzeroDigit();
+        int i;
+        int limit;
+
+        //The first
+        if (iNeg < iPos) {
+            resDigits = new int[resLength];
+            i = iNeg;
+            //resDigits[i] = -(-negative.digits[i]);
+            resDigits[i] = negative.digits[i];
+            limit = Math.min(negative.numberLength, iPos);
+            //Skip the positive digits while they are zeros
+            for (i++; i < limit; i++) {
+                //resDigits[i] = ~(~negative.digits[i]);
+                resDigits[i] = negative.digits[i];
+            }
+            //if the negative has no more elements, must fill the
+            //result with the remaining digits of the positive
+            if (i == negative.numberLength) {
+                for ( ; i < positive.numberLength; i++) {
+                    //resDigits[i] = ~(positive.digits[i] ^ -1) -> ~(~positive.digits[i])
+                    resDigits[i] = positive.digits[i];
+                }
+            }
+        } else if (iPos < iNeg) {
+            resDigits = new int[resLength];
+            i = iPos;
+            //Applying two complement to the first non-zero digit of the result
+            resDigits[i] = -positive.digits[i];
+            limit = Math.min(positive.numberLength, iNeg);
+            for (i++; i < limit; i++) {
+                //Continue applying two complement the result
+                resDigits[i] = ~positive.digits[i];
+            }
+            //When the first non-zero digit of the negative is reached, must apply
+            //two complement (arithmetic negation) to it, and then operate
+            if (i == iNeg) {
+                resDigits[i] = ~(positive.digits[i] ^ -negative.digits[i]);
+                i++;
+            } else {
+                //if the positive has no more elements must fill the remaining digits with
+                //the negative ones
+                for ( ; i < iNeg; i++) {
+                    // resDigits[i] = ~(0 ^ 0)
+                    resDigits[i] = -1;
+                }
+                for ( ; i < negative.numberLength; i++) {
+                    //resDigits[i] = ~(~negative.digits[i] ^ 0)
+                    resDigits[i] = negative.digits[i];
+                }
+            }
+                } else {
+            //The first non-zero digit of the positive and negative are the same
+            i = iNeg;
+            int digit = positive.digits[i] ^ -negative.digits[i];
+            if (digit == 0) {
+                limit = Math.min(positive.numberLength, negative.numberLength);
+                for (i++; i < limit && (digit = positive.digits[i] ^ ~negative.digits[i]) == 0; i++)
+                    ;
+                if (digit == 0) {
+                    // shorter has only the remaining virtual sign bits
+                    for ( ; i < positive.numberLength && (digit = ~positive.digits[i]) == 0; i++)
+                        ;
+                    for ( ; i < negative.numberLength && (digit = ~negative.digits[i]) == 0; i++)
+                        ;
+                    if (digit == 0) {
+                        resLength = resLength + 1;
+                        resDigits = new int[resLength];
+                        resDigits[resLength - 1] = 1;
+
+                        return new BigInteger(-1, resLength, resDigits);
+                }
+            }
+        }
+            resDigits = new int[resLength];
+            resDigits[i] = -digit;
+            i++;
+        }
+
+        limit = Math.min(negative.numberLength, positive.numberLength);
+        for ( ; i < limit; i++) {
+            resDigits[i] = ~(~negative.digits[i] ^ positive.digits[i]);
+        }
+        for ( ; i < positive.numberLength; i++) {
+            // resDigits[i] = ~(positive.digits[i] ^ -1)
+            resDigits[i] = positive.digits[i];
+        }
+        for ( ; i < negative.numberLength; i++) {
+            // resDigits[i] = ~(0 ^ ~negative.digits[i])
+            resDigits[i] = negative.digits[i];
+        }
+
+        return new BigInteger(-1, resLength, resDigits);
+    }
+}
diff --git a/java/math/MathContext.java b/java/math/MathContext.java
new file mode 100644
index 0000000..6f3f1ed
--- /dev/null
+++ b/java/math/MathContext.java
@@ -0,0 +1,249 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.io.StreamCorruptedException;
+
+/**
+ * Immutable objects describing settings such as rounding mode and digit
+ * precision for the numerical operations provided by class {@link BigDecimal}.
+ */
+public final class MathContext implements Serializable {
+    private static final long serialVersionUID = 5579720004786848255L;
+
+    /**
+     * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> quadruple
+     * decimal precision format: 34 digit precision and
+     * {@link RoundingMode#HALF_EVEN} rounding.
+     */
+    public static final MathContext DECIMAL128 = new MathContext(34, RoundingMode.HALF_EVEN);
+
+    /**
+     * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> single decimal
+     * precision format: 7 digit precision and {@link RoundingMode#HALF_EVEN}
+     * rounding.
+     */
+    public static final MathContext DECIMAL32 = new MathContext(7, RoundingMode.HALF_EVEN);
+
+    /**
+     * A {@code MathContext} which corresponds to the <a href="http://en.wikipedia.org/wiki/IEEE_754-1985">IEEE 754</a> double decimal
+     * precision format: 16 digit precision and {@link RoundingMode#HALF_EVEN}
+     * rounding.
+     */
+    public static final MathContext DECIMAL64 = new MathContext(16, RoundingMode.HALF_EVEN);
+
+    /**
+     * A {@code MathContext} for unlimited precision with
+     * {@link RoundingMode#HALF_UP} rounding.
+     */
+    public static final MathContext UNLIMITED = new MathContext(0, RoundingMode.HALF_UP);
+
+    /**
+     * The number of digits to be used for an operation; results are rounded to
+     * this precision.
+     */
+    private final int precision;
+
+    /**
+     * A {@code RoundingMode} object which specifies the algorithm to be used
+     * for rounding.
+     */
+    private final RoundingMode roundingMode;
+
+    /**
+     * Constructs a new {@code MathContext} with the specified precision and
+     * with the rounding mode {@link RoundingMode#HALF_UP HALF_UP}. If the
+     * precision passed is zero, then this implies that the computations have to
+     * be performed exact, the rounding mode in this case is irrelevant.
+     *
+     * @param precision
+     *            the precision for the new {@code MathContext}.
+     * @throws IllegalArgumentException
+     *             if {@code precision < 0}.
+     */
+    public MathContext(int precision) {
+        this(precision, RoundingMode.HALF_UP);
+    }
+
+    /**
+     * Constructs a new {@code MathContext} with the specified precision and
+     * with the specified rounding mode. If the precision passed is zero, then
+     * this implies that the computations have to be performed exact, the
+     * rounding mode in this case is irrelevant.
+     *
+     * @param precision
+     *            the precision for the new {@code MathContext}.
+     * @param roundingMode
+     *            the rounding mode for the new {@code MathContext}.
+     * @throws IllegalArgumentException
+     *             if {@code precision < 0}.
+     * @throws NullPointerException
+     *             if {@code roundingMode} is {@code null}.
+     */
+    public MathContext(int precision, RoundingMode roundingMode) {
+        this.precision = precision;
+        this.roundingMode = roundingMode;
+        checkValid();
+    }
+
+    /**
+     * Constructs a new {@code MathContext} from a string. The string has to
+     * specify the precision and the rounding mode to be used and has to follow
+     * the following syntax: "precision=&lt;precision&gt; roundingMode=&lt;roundingMode&gt;"
+     * This is the same form as the one returned by the {@link #toString}
+     * method.
+     *
+     * @throws IllegalArgumentException
+     *             if the string is not in the correct format or if the
+     *             precision specified is < 0.
+     */
+    public MathContext(String s) {
+        int precisionLength = "precision=".length();
+        int roundingModeLength = "roundingMode=".length();
+
+        int spaceIndex;
+        if (!s.startsWith("precision=") || (spaceIndex = s.indexOf(' ', precisionLength)) == -1) {
+            throw invalidMathContext("Missing precision", s);
+        }
+        String precisionString = s.substring(precisionLength, spaceIndex);
+        try {
+            this.precision = Integer.parseInt(precisionString);
+        } catch (NumberFormatException nfe) {
+            throw invalidMathContext("Bad precision", s);
+        }
+
+        int roundingModeStart = spaceIndex + 1;
+        if (!s.regionMatches(roundingModeStart, "roundingMode=", 0, roundingModeLength)) {
+            throw invalidMathContext("Missing rounding mode", s);
+        }
+        roundingModeStart += roundingModeLength;
+        this.roundingMode = RoundingMode.valueOf(s.substring(roundingModeStart));
+
+        checkValid();
+    }
+
+    private IllegalArgumentException invalidMathContext(String reason, String s) {
+        throw new IllegalArgumentException(reason + ": " + s);
+    }
+
+    private void checkValid() {
+        if (precision < 0) {
+            throw new IllegalArgumentException("Negative precision: " + precision);
+        }
+        if (roundingMode == null) {
+            throw new NullPointerException("roundingMode == null");
+        }
+    }
+
+    /**
+     * Returns the precision. The precision is the number of digits used for an
+     * operation. Results are rounded to this precision. The precision is
+     * guaranteed to be non negative. If the precision is zero, then the
+     * computations have to be performed exact, results are not rounded in this
+     * case.
+     *
+     * @return the precision.
+     */
+    public int getPrecision() {
+        return precision;
+    }
+
+    /**
+     * Returns the rounding mode. The rounding mode is the strategy to be used
+     * to round results.
+     * <p>
+     * The rounding mode is one of
+     * {@link RoundingMode#UP},
+     * {@link RoundingMode#DOWN},
+     * {@link RoundingMode#CEILING},
+     * {@link RoundingMode#FLOOR},
+     * {@link RoundingMode#HALF_UP},
+     * {@link RoundingMode#HALF_DOWN},
+     * {@link RoundingMode#HALF_EVEN}, or
+     * {@link RoundingMode#UNNECESSARY}.
+     *
+     * @return the rounding mode.
+     */
+    public RoundingMode getRoundingMode() {
+        return roundingMode;
+    }
+
+    /**
+     * Returns true if x is a {@code MathContext} with the same precision
+     * setting and the same rounding mode as this {@code MathContext} instance.
+     *
+     * @param x
+     *            object to be compared.
+     * @return {@code true} if this {@code MathContext} instance is equal to the
+     *         {@code x} argument; {@code false} otherwise.
+     */
+    @Override
+    public boolean equals(Object x) {
+        return ((x instanceof MathContext)
+                && (((MathContext) x).getPrecision() == precision) && (((MathContext) x)
+                .getRoundingMode() == roundingMode));
+    }
+
+    /**
+     * Returns the hash code for this {@code MathContext} instance.
+     *
+     * @return the hash code for this {@code MathContext}.
+     */
+    @Override
+    public int hashCode() {
+        // Make place for the necessary bits to represent 8 rounding modes
+        return ((precision << 3) | roundingMode.ordinal());
+    }
+
+    /**
+     * Returns the string representation for this {@code MathContext} instance.
+     * The string has the form
+     * {@code
+     * "precision=<precision> roundingMode=<roundingMode>"
+     * } where {@code <precision>} is an integer describing the number
+     * of digits used for operations and {@code <roundingMode>} is the
+     * string representation of the rounding mode.
+     *
+     * @return a string representation for this {@code MathContext} instance
+     */
+    @Override
+    public String toString() {
+        return "precision=" + precision + " roundingMode=" + roundingMode;
+    }
+
+    /**
+     * Makes checks upon deserialization of a {@code MathContext} instance.
+     * Checks whether {@code precision >= 0} and {@code roundingMode != null}
+     *
+     * @throws StreamCorruptedException
+     *             if {@code precision < 0}
+     * @throws StreamCorruptedException
+     *             if {@code roundingMode == null}
+     */
+    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        try {
+            checkValid();
+        } catch (Exception ex) {
+            throw new StreamCorruptedException(ex.getMessage());
+        }
+    }
+}
diff --git a/java/math/Multiplication.java b/java/math/Multiplication.java
new file mode 100644
index 0000000..2a4285b
--- /dev/null
+++ b/java/math/Multiplication.java
@@ -0,0 +1,187 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+/**
+ * Static library that provides all multiplication of {@link BigInteger} methods.
+ */
+class Multiplication {
+
+    /** Just to denote that this class can't be instantiated. */
+    private Multiplication() {}
+
+    // BEGIN Android-removed
+    // /**
+    //  * Break point in digits (number of {@code int} elements)
+    //  * between Karatsuba and Pencil and Paper multiply.
+    //  */
+    // static final int whenUseKaratsuba = 63; // an heuristic value
+    // END Android-removed
+
+    /**
+     * An array with powers of ten that fit in the type {@code int}.
+     * ({@code 10^0,10^1,...,10^9})
+     */
+    static final int[] tenPows = {
+        1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+    };
+
+    /**
+     * An array with powers of five that fit in the type {@code int}.
+     * ({@code 5^0,5^1,...,5^13})
+     */
+    static final int[] fivePows = {
+        1, 5, 25, 125, 625, 3125, 15625, 78125, 390625,
+        1953125, 9765625, 48828125, 244140625, 1220703125
+    };
+
+    /**
+     * An array with the first powers of ten in {@code BigInteger} version.
+     * ({@code 10^0,10^1,...,10^31})
+     */
+    static final BigInteger[] bigTenPows = new BigInteger[32];
+
+    /**
+     * An array with the first powers of five in {@code BigInteger} version.
+     * ({@code 5^0,5^1,...,5^31})
+     */
+    static final BigInteger bigFivePows[] = new BigInteger[32];
+
+
+
+    static {
+        int i;
+        long fivePow = 1L;
+
+        for (i = 0; i <= 18; i++) {
+            bigFivePows[i] = BigInteger.valueOf(fivePow);
+            bigTenPows[i] = BigInteger.valueOf(fivePow << i);
+            fivePow *= 5;
+        }
+        for (; i < bigTenPows.length; i++) {
+            bigFivePows[i] = bigFivePows[i - 1].multiply(bigFivePows[1]);
+            bigTenPows[i] = bigTenPows[i - 1].multiply(BigInteger.TEN);
+        }
+    }
+
+    // BEGIN android-note: multiply has been removed in favor of using OpenSSL BIGNUM
+    // END android-note
+
+    /**
+     * Multiplies a number by a positive integer.
+     * @param val an arbitrary {@code BigInteger}
+     * @param factor a positive {@code int} number
+     * @return {@code val * factor}
+     */
+    static BigInteger multiplyByPositiveInt(BigInteger val, int factor) {
+        BigInt bi = val.getBigInt().copy();
+        bi.multiplyByPositiveInt(factor);
+        return new BigInteger(bi);
+    }
+
+    /**
+     * Multiplies a number by a power of ten.
+     * This method is used in {@code BigDecimal} class.
+     * @param val the number to be multiplied
+     * @param exp a positive {@code long} exponent
+     * @return {@code val * 10<sup>exp</sup>}
+     */
+    static BigInteger multiplyByTenPow(BigInteger val, long exp) {
+        // PRE: exp >= 0
+        return ((exp < tenPows.length)
+        ? multiplyByPositiveInt(val, tenPows[(int)exp])
+        : val.multiply(powerOf10(exp)));
+    }
+
+    /**
+     * It calculates a power of ten, which exponent could be out of 32-bit range.
+     * Note that internally this method will be used in the worst case with
+     * an exponent equals to: {@code Integer.MAX_VALUE - Integer.MIN_VALUE}.
+     * @param exp the exponent of power of ten, it must be positive.
+     * @return a {@code BigInteger} with value {@code 10<sup>exp</sup>}.
+     */
+    static BigInteger powerOf10(long exp) {
+        // PRE: exp >= 0
+        int intExp = (int)exp;
+        // "SMALL POWERS"
+        if (exp < bigTenPows.length) {
+            // The largest power that fit in 'long' type
+            return bigTenPows[intExp];
+        } else if (exp <= 50) {
+            // To calculate:    10^exp
+            return BigInteger.TEN.pow(intExp);
+        }
+
+        BigInteger res = null;
+        try {
+            // "LARGE POWERS"
+            if (exp <= Integer.MAX_VALUE) {
+                // To calculate:    5^exp * 2^exp
+                res = bigFivePows[1].pow(intExp).shiftLeft(intExp);
+            } else {
+                /*
+                 * "HUGE POWERS"
+                 *
+                 * This branch probably won't be executed since the power of ten is too
+                 * big.
+                 */
+                // To calculate:    5^exp
+                BigInteger powerOfFive = bigFivePows[1].pow(Integer.MAX_VALUE);
+                res = powerOfFive;
+                long longExp = exp - Integer.MAX_VALUE;
+
+                intExp = (int) (exp % Integer.MAX_VALUE);
+                while (longExp > Integer.MAX_VALUE) {
+                    res = res.multiply(powerOfFive);
+                    longExp -= Integer.MAX_VALUE;
+                }
+                res = res.multiply(bigFivePows[1].pow(intExp));
+                // To calculate:    5^exp << exp
+                res = res.shiftLeft(Integer.MAX_VALUE);
+                longExp = exp - Integer.MAX_VALUE;
+                while (longExp > Integer.MAX_VALUE) {
+                    res = res.shiftLeft(Integer.MAX_VALUE);
+                    longExp -= Integer.MAX_VALUE;
+                }
+                res = res.shiftLeft(intExp);
+            }
+        } catch (OutOfMemoryError error) {
+            throw new ArithmeticException(error.getMessage());
+        }
+
+        return res;
+    }
+
+    /**
+     * Multiplies a number by a power of five.
+     * This method is used in {@code BigDecimal} class.
+     * @param val the number to be multiplied
+     * @param exp a positive {@code int} exponent
+     * @return {@code val * 5<sup>exp</sup>}
+     */
+    static BigInteger multiplyByFivePow(BigInteger val, int exp) {
+        // PRE: exp >= 0
+        if (exp < fivePows.length) {
+            return multiplyByPositiveInt(val, fivePows[exp]);
+        } else if (exp < bigFivePows.length) {
+            return val.multiply(bigFivePows[exp]);
+        } else {// Large powers of five
+            return val.multiply(bigFivePows[1].pow(exp));
+        }
+    }
+}
diff --git a/java/math/NativeBN.java b/java/math/NativeBN.java
new file mode 100644
index 0000000..ab9b2e0
--- /dev/null
+++ b/java/math/NativeBN.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * 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.math;
+
+final class NativeBN {
+
+    public static native long BN_new();
+    // BIGNUM *BN_new(void);
+
+    public static native void BN_free(long a);
+    // void BN_free(BIGNUM *a);
+
+    public static native int BN_cmp(long a, long b);
+    // int BN_cmp(const BIGNUM *a, const BIGNUM *b);
+
+    public static native void BN_copy(long to, long from);
+    // BIGNUM *BN_copy(BIGNUM *to, const BIGNUM *from);
+
+    public static native void putLongInt(long a, long dw);
+    public static native void putULongInt(long a, long dw, boolean neg);
+
+    public static native int BN_dec2bn(long a, String str);
+    // int BN_dec2bn(BIGNUM **a, const char *str);
+
+    public static native int BN_hex2bn(long a, String str);
+    // int BN_hex2bn(BIGNUM **a, const char *str);
+
+    public static native void BN_bin2bn(byte[] s, int len, boolean neg, long ret);
+    // BIGNUM * BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
+    // BN-Docu: s is taken as unsigned big endian;
+    // Additional parameter: neg.
+
+    public static native void litEndInts2bn(int[] ints, int len, boolean neg, long ret);
+
+    public static native void twosComp2bn(byte[] s, int len, long ret);
+
+
+    public static native long longInt(long a);
+    // unsigned long BN_get_word(BIGNUM *a);
+
+    public static native String BN_bn2dec(long a);
+    // char * BN_bn2dec(const BIGNUM *a);
+
+    public static native String BN_bn2hex(long a);
+    // char * BN_bn2hex(const BIGNUM *a);
+
+    public static native byte[] BN_bn2bin(long a);
+    // Returns result byte[] AND NOT length.
+    // int BN_bn2bin(const BIGNUM *a, unsigned char *to);
+
+    public static native int[] bn2litEndInts(long a);
+
+    public static native int sign(long a);
+    // Returns -1, 0, 1 AND NOT boolean.
+    // #define BN_is_negative(a) ((a)->neg != 0)
+
+    public static native void BN_set_negative(long b, int n);
+    // void BN_set_negative(BIGNUM *b, int n);
+
+    public static native int bitLength(long a);
+
+    public static native boolean BN_is_bit_set(long a, int n);
+    // int BN_is_bit_set(const BIGNUM *a, int n);
+
+    public static native void BN_shift(long r, long a, int n);
+    // int BN_shift(BIGNUM *r, const BIGNUM *a, int n);
+
+    public static native void BN_add_word(long a, int w);
+    // ATTENTION: w is treated as unsigned.
+    // int BN_add_word(BIGNUM *a, BN_ULONG w);
+
+    public static native void BN_mul_word(long a, int w);
+    // ATTENTION: w is treated as unsigned.
+    // int BN_mul_word(BIGNUM *a, BN_ULONG w);
+
+    public static native int BN_mod_word(long a, int w);
+    // ATTENTION: w is treated as unsigned.
+    // BN_ULONG BN_mod_word(BIGNUM *a, BN_ULONG w);
+
+    public static native void BN_add(long r, long a, long b);
+    // int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+
+    public static native void BN_sub(long r, long a, long b);
+    // int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+
+    public static native void BN_gcd(long r, long a, long b);
+    // int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+    public static native void BN_mul(long r, long a, long b);
+    // int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+
+    public static native void BN_exp(long r, long a, long p);
+    // int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+
+    public static native void BN_div(long dv, long rem, long m, long d);
+    // int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx);
+
+    public static native void BN_nnmod(long r, long a, long m);
+    // int BN_nnmod(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+
+    public static native void BN_mod_exp(long r, long a, long p, long m);
+    // int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx);
+
+    public static native void BN_mod_inverse(long ret, long a, long n);
+    // BIGNUM * BN_mod_inverse(BIGNUM *ret, const BIGNUM *a, const BIGNUM *n, BN_CTX *ctx);
+
+
+    public static native void BN_generate_prime_ex(long ret, int bits, boolean safe,
+                                                   long add, long rem);
+    // int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe,
+    //         const BIGNUM *add, const BIGNUM *rem, BN_GENCB *cb);
+
+    public static native boolean BN_primality_test(long candidate, int checks,
+                                                   boolean do_trial_division);
+    // int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate, int checks,
+    //                       BN_CTX *ctx, int do_trial_division, BN_GENCB *cb);
+    // Returns *is_probably_prime on success and throws an exception on error.
+
+    public static native long getNativeFinalizer();
+    // &BN_free
+
+}
diff --git a/java/math/Primality.java b/java/math/Primality.java
new file mode 100644
index 0000000..eacc893
--- /dev/null
+++ b/java/math/Primality.java
@@ -0,0 +1,145 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+import java.util.Arrays;
+
+/**
+ * Provides primality probabilistic methods.
+ */
+class Primality {
+
+    /** Just to denote that this class can't be instantiated. */
+    private Primality() {}
+
+    /** All prime numbers with bit length lesser than 10 bits. */
+    private static final int[] primes = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
+            31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
+            103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167,
+            173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239,
+            241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
+            317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
+            401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467,
+            479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
+            571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
+            647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
+            739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823,
+            827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911,
+            919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009,
+            1013, 1019, 1021 };
+
+    /** All {@code BigInteger} prime numbers with bit length lesser than 10 bits. */
+    private static final BigInteger BIprimes[] = new BigInteger[primes.length];
+
+//    /**
+//     * It encodes how many iterations of Miller-Rabin test are need to get an
+//     * error bound not greater than {@code 2<sup>(-100)</sup>}. For example:
+//     * for a {@code 1000}-bit number we need {@code 4} iterations, since
+//     * {@code BITS[3] < 1000 <= BITS[4]}.
+//     */
+//    private static final int[] BITS = { 0, 0, 1854, 1233, 927, 747, 627, 543,
+//            480, 431, 393, 361, 335, 314, 295, 279, 265, 253, 242, 232, 223,
+//            216, 181, 169, 158, 150, 145, 140, 136, 132, 127, 123, 119, 114,
+//            110, 105, 101, 96, 92, 87, 83, 78, 73, 69, 64, 59, 54, 49, 44, 38,
+//            32, 26, 1 };
+//
+//    /**
+//     * It encodes how many i-bit primes there are in the table for
+//     * {@code i=2,...,10}. For example {@code offsetPrimes[6]} says that from
+//     * index {@code 11} exists {@code 7} consecutive {@code 6}-bit prime
+//     * numbers in the array.
+//     */
+//    private static final int[][] offsetPrimes = { null, null, { 0, 2 },
+//            { 2, 2 }, { 4, 2 }, { 6, 5 }, { 11, 7 }, { 18, 13 }, { 31, 23 },
+//            { 54, 43 }, { 97, 75 } };
+
+    static {// To initialize the dual table of BigInteger primes
+        for (int i = 0; i < primes.length; i++) {
+            BIprimes[i] = BigInteger.valueOf(primes[i]);
+        }
+    }
+
+    /**
+     * It uses the sieve of Eratosthenes to discard several composite numbers in
+     * some appropriate range (at the moment {@code [this, this + 1024]}). After
+     * this process it applies the Miller-Rabin test to the numbers that were
+     * not discarded in the sieve.
+     *
+     * @see BigInteger#nextProbablePrime()
+     */
+    static BigInteger nextProbablePrime(BigInteger n) {
+        // PRE: n >= 0
+        int i, j;
+//        int certainty;
+        int gapSize = 1024; // for searching of the next probable prime number
+        int[] modules = new int[primes.length];
+        boolean isDivisible[] = new boolean[gapSize];
+        BigInt ni = n.getBigInt();
+        // If n < "last prime of table" searches next prime in the table
+        if (ni.bitLength() <= 10) {
+            int l = (int)ni.longInt();
+            if (l < primes[primes.length - 1]) {
+                for (i = 0; l >= primes[i]; i++) {}
+                return BIprimes[i];
+            }
+        }
+
+        BigInt startPoint = ni.copy();
+        BigInt probPrime = new BigInt();
+
+        // Fix startPoint to "next odd number":
+        startPoint.addPositiveInt(BigInt.remainderByPositiveInt(ni, 2) + 1);
+
+//        // To set the improved certainty of Miller-Rabin
+//        j = startPoint.bitLength();
+//        for (certainty = 2; j < BITS[certainty]; certainty++) {
+//            ;
+//        }
+
+        // To calculate modules: N mod p1, N mod p2, ... for first primes.
+        for (i = 0; i < primes.length; i++) {
+            modules[i] = BigInt.remainderByPositiveInt(startPoint, primes[i]) - gapSize;
+        }
+        while (true) {
+            // At this point, all numbers in the gap are initialized as
+            // probably primes
+            Arrays.fill(isDivisible, false);
+            // To discard multiples of first primes
+            for (i = 0; i < primes.length; i++) {
+                modules[i] = (modules[i] + gapSize) % primes[i];
+                j = (modules[i] == 0) ? 0 : (primes[i] - modules[i]);
+                for (; j < gapSize; j += primes[i]) {
+                    isDivisible[j] = true;
+                }
+            }
+            // To execute Miller-Rabin for non-divisible numbers by all first
+            // primes
+            for (j = 0; j < gapSize; j++) {
+                if (!isDivisible[j]) {
+                    probPrime.putCopy(startPoint);
+                    probPrime.addPositiveInt(j);
+                    if (probPrime.isPrime(100)) {
+                        return new BigInteger(probPrime);
+                    }
+                }
+            }
+            startPoint.addPositiveInt(gapSize);
+        }
+    }
+
+}
diff --git a/java/math/RoundingMode.java b/java/math/RoundingMode.java
new file mode 100644
index 0000000..f4c181e
--- /dev/null
+++ b/java/math/RoundingMode.java
@@ -0,0 +1,122 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package java.math;
+
+/**
+ * Specifies the rounding behavior for operations whose results cannot be
+ * represented exactly.
+ */
+public enum RoundingMode {
+
+    /**
+     * Rounding mode where positive values are rounded towards positive infinity
+     * and negative values towards negative infinity.
+     * <br>
+     * Rule: {@code x.round().abs() >= x.abs()}
+     */
+    UP(BigDecimal.ROUND_UP),
+
+    /**
+     * Rounding mode where the values are rounded towards zero.
+     * <br>
+     * Rule: {@code x.round().abs() <= x.abs()}
+     */
+    DOWN(BigDecimal.ROUND_DOWN),
+
+    /**
+     * Rounding mode to round towards positive infinity. For positive values
+     * this rounding mode behaves as {@link #UP}, for negative values as
+     * {@link #DOWN}.
+     * <br>
+     * Rule: {@code x.round() >= x}
+     */
+    CEILING(BigDecimal.ROUND_CEILING),
+
+    /**
+     * Rounding mode to round towards negative infinity. For positive values
+     * this rounding mode behaves as {@link #DOWN}, for negative values as
+     * {@link #UP}.
+     * <br>
+     * Rule: {@code x.round() <= x}
+     */
+    FLOOR(BigDecimal.ROUND_FLOOR),
+
+    /**
+     * Rounding mode where values are rounded towards the nearest neighbor. Ties
+     * are broken by rounding up.
+     */
+    HALF_UP(BigDecimal.ROUND_HALF_UP),
+
+    /**
+     * Rounding mode where values are rounded towards the nearest neighbor. Ties
+     * are broken by rounding down.
+     */
+    HALF_DOWN(BigDecimal.ROUND_HALF_DOWN),
+
+    /**
+     * Rounding mode where values are rounded towards the nearest neighbor. Ties
+     * are broken by rounding to the even neighbor.
+     */
+    HALF_EVEN(BigDecimal.ROUND_HALF_EVEN),
+
+    /**
+     * Rounding mode where the rounding operations throws an ArithmeticException
+     * for the case that rounding is necessary, i.e. for the case that the value
+     * cannot be represented exactly.
+     */
+    UNNECESSARY(BigDecimal.ROUND_UNNECESSARY);
+
+    /** The old constant of <code>BigDecimal</code>. */
+    private final int bigDecimalRM;
+
+    /** It sets the old constant. */
+    RoundingMode(int rm) {
+        bigDecimalRM = rm;
+    }
+
+    /**
+     * Converts rounding mode constants from class {@code BigDecimal} into
+     * {@code RoundingMode} values.
+     *
+     * @param mode
+     *            rounding mode constant as defined in class {@code BigDecimal}
+     * @return corresponding rounding mode object
+     */
+    public static RoundingMode valueOf(int mode) {
+        switch (mode) {
+            case BigDecimal.ROUND_CEILING:
+                return CEILING;
+            case BigDecimal.ROUND_DOWN:
+                return DOWN;
+            case BigDecimal.ROUND_FLOOR:
+                return FLOOR;
+            case BigDecimal.ROUND_HALF_DOWN:
+                return HALF_DOWN;
+            case BigDecimal.ROUND_HALF_EVEN:
+                return HALF_EVEN;
+            case BigDecimal.ROUND_HALF_UP:
+                return HALF_UP;
+            case BigDecimal.ROUND_UNNECESSARY:
+                return UNNECESSARY;
+            case BigDecimal.ROUND_UP:
+                return UP;
+            default:
+                throw new IllegalArgumentException("Invalid rounding mode");
+        }
+    }
+}
diff --git a/java/net/AbstractPlainDatagramSocketImpl.java b/java/net/AbstractPlainDatagramSocketImpl.java
new file mode 100644
index 0000000..a3c738a
--- /dev/null
+++ b/java/net/AbstractPlainDatagramSocketImpl.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import libcore.io.IoBridge;
+import libcore.io.IoUtils;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.security.AccessController;
+
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import sun.net.ResourceManager;
+
+/**
+ * Abstract datagram and multicast socket implementation base class.
+ * Note: This is not a public class, so that applets cannot call
+ * into the implementation directly and hence cannot bypass the
+ * security checks present in the DatagramSocket and MulticastSocket
+ * classes.
+ *
+ * @author Pavani Diwanji
+ */
+
+abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
+{
+    /* timeout value for receive() */
+    int timeout = 0;
+    boolean connected = false;
+    private int trafficClass = 0;
+    protected InetAddress connectedAddress = null;
+    private int connectedPort = -1;
+
+    // Android-added: CloseGuard
+    private final CloseGuard guard = CloseGuard.get();
+
+    private static final String os = AccessController.doPrivileged(
+        new sun.security.action.GetPropertyAction("os.name")
+    );
+
+    /**
+     * flag set if the native connect() call not to be used
+     */
+    private final static boolean connectDisabled = os.contains("OS X");
+
+    // BEGIN Android-removed: Android doesn't need to load native net library
+    /**
+     * Load net library into runtime.
+     *
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+    }
+    */
+    // END Android-removed: Android doesn't need to load native net library
+
+    /**
+     * Creates a datagram socket
+     */
+    protected synchronized void create() throws SocketException {
+        ResourceManager.beforeUdpCreate();
+        fd = new FileDescriptor();
+        try {
+            datagramSocketCreate();
+        } catch (SocketException ioe) {
+            ResourceManager.afterUdpClose();
+            fd = null;
+            throw ioe;
+        }
+
+        // Android-added: CloseGuard/fdsan
+        if (fd != null && fd.valid()) {
+            guard.open("close");
+            IoUtils.setFdOwner(fd, this);
+        }
+    }
+
+    /**
+     * Binds a datagram socket to a local port.
+     */
+    protected synchronized void bind(int lport, InetAddress laddr)
+        throws SocketException {
+        bind0(lport, laddr);
+    }
+
+    protected abstract void bind0(int lport, InetAddress laddr)
+        throws SocketException;
+
+    /**
+     * Sends a datagram packet. The packet contains the data and the
+     * destination address to send the packet to.
+     * @param p the packet to be sent.
+     */
+    protected abstract void send(DatagramPacket p) throws IOException;
+
+    /**
+     * Connects a datagram socket to a remote destination. This associates the remote
+     * address with the local socket so that datagrams may only be sent to this destination
+     * and received from this destination.
+     * @param address the remote InetAddress to connect to
+     * @param port the remote port number
+     */
+    protected void connect(InetAddress address, int port) throws SocketException {
+        // Android-added: BlockGuard
+        BlockGuard.getThreadPolicy().onNetwork();
+        connect0(address, port);
+        connectedAddress = address;
+        connectedPort = port;
+        connected = true;
+    }
+
+    /**
+     * Disconnects a previously connected socket. Does nothing if the socket was
+     * not connected already.
+     */
+    protected void disconnect() {
+        disconnect0(connectedAddress.holder().getFamily());
+        connected = false;
+        connectedAddress = null;
+        connectedPort = -1;
+    }
+
+    /**
+     * Peek at the packet to see who it is from.
+     * @param i the address to populate with the sender address
+     */
+    protected abstract int peek(InetAddress i) throws IOException;
+    protected abstract int peekData(DatagramPacket p) throws IOException;
+    /**
+     * Receive the datagram packet.
+     * @param p the packet to receive into
+     */
+    protected synchronized void receive(DatagramPacket p)
+        throws IOException {
+        receive0(p);
+    }
+
+    protected abstract void receive0(DatagramPacket p)
+        throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl TTL to be set.
+     */
+    protected abstract void setTimeToLive(int ttl) throws IOException;
+
+    /**
+     * Get the TTL (time-to-live) option.
+     */
+    protected abstract int getTimeToLive() throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl TTL to be set.
+     */
+    @Deprecated
+    protected abstract void setTTL(byte ttl) throws IOException;
+
+    /**
+     * Get the TTL (time-to-live) option.
+     */
+    @Deprecated
+    protected abstract byte getTTL() throws IOException;
+
+    /**
+     * Join the multicast group.
+     * @param inetaddr multicast address to join.
+     */
+    protected void join(InetAddress inetaddr) throws IOException {
+        join(inetaddr, null);
+    }
+
+    /**
+     * Leave the multicast group.
+     * @param inetaddr multicast address to leave.
+     */
+    protected void leave(InetAddress inetaddr) throws IOException {
+        leave(inetaddr, null);
+    }
+    /**
+     * Join the multicast group.
+     * @param mcastaddr multicast address to join.
+     * @param netIf specifies the local interface to receive multicast
+     *        datagram packets
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+
+    protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        join(((InetSocketAddress)mcastaddr).getAddress(), netIf);
+    }
+
+    protected abstract void join(InetAddress inetaddr, NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Leave the multicast group.
+     * @param mcastaddr  multicast address to leave.
+     * @param netIf specified the local interface to leave the group at
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        leave(((InetSocketAddress)mcastaddr).getAddress(), netIf);
+    }
+
+    protected abstract void leave(InetAddress inetaddr, NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Close the socket.
+     */
+    protected void close() {
+        // Android-added: CloseGuard
+        guard.close();
+
+        if (fd != null) {
+            datagramSocketClose();
+            ResourceManager.afterUdpClose();
+            fd = null;
+        }
+    }
+
+    protected boolean isClosed() {
+        return (fd == null) ? true : false;
+    }
+
+    protected void finalize() {
+        // Android-added: CloseGuard
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        close();
+    }
+
+    /**
+     * set a value - since we only support (setting) binary options
+     * here, o must be a Boolean
+     */
+
+     public void setOption(int optID, Object o) throws SocketException {
+         if (isClosed()) {
+             throw new SocketException("Socket Closed");
+         }
+         switch (optID) {
+            /* check type safety b4 going native.  These should never
+             * fail, since only java.Socket* has access to
+             * PlainSocketImpl.setOption().
+             */
+         case SO_TIMEOUT:
+             if (o == null || !(o instanceof Integer)) {
+                 throw new SocketException("bad argument for SO_TIMEOUT");
+             }
+             int tmp = ((Integer) o).intValue();
+             if (tmp < 0)
+                 throw new IllegalArgumentException("timeout < 0");
+             timeout = tmp;
+             return;
+         case IP_TOS:
+             if (o == null || !(o instanceof Integer)) {
+                 throw new SocketException("bad argument for IP_TOS");
+             }
+             trafficClass = ((Integer)o).intValue();
+             break;
+         case SO_REUSEADDR:
+             if (o == null || !(o instanceof Boolean)) {
+                 throw new SocketException("bad argument for SO_REUSEADDR");
+             }
+             break;
+         case SO_BROADCAST:
+             if (o == null || !(o instanceof Boolean)) {
+                 throw new SocketException("bad argument for SO_BROADCAST");
+             }
+             break;
+         case SO_BINDADDR:
+             throw new SocketException("Cannot re-bind Socket");
+         case SO_RCVBUF:
+         case SO_SNDBUF:
+             if (o == null || !(o instanceof Integer) ||
+                 ((Integer)o).intValue() < 0) {
+                 throw new SocketException("bad argument for SO_SNDBUF or " +
+                                           "SO_RCVBUF");
+             }
+             break;
+         case IP_MULTICAST_IF:
+             if (o == null || !(o instanceof InetAddress))
+                 throw new SocketException("bad argument for IP_MULTICAST_IF");
+             break;
+         case IP_MULTICAST_IF2:
+             // Android-changed: Support Integer IP_MULTICAST_IF2 values for app compat. b/26790580
+             // if (o == null || !(o instanceof NetworkInterface))
+             if (o == null || !(o instanceof Integer || o instanceof NetworkInterface))
+                 throw new SocketException("bad argument for IP_MULTICAST_IF2");
+             if (o instanceof NetworkInterface) {
+                 o = new Integer(((NetworkInterface)o).getIndex());
+             }
+             break;
+         case IP_MULTICAST_LOOP:
+             if (o == null || !(o instanceof Boolean))
+                 throw new SocketException("bad argument for IP_MULTICAST_LOOP");
+             break;
+         default:
+             throw new SocketException("invalid option: " + optID);
+         }
+         socketSetOption(optID, o);
+     }
+
+    /*
+     * get option's state - set or not
+     */
+
+    public Object getOption(int optID) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket Closed");
+        }
+
+        Object result;
+
+        switch (optID) {
+            case SO_TIMEOUT:
+                result = new Integer(timeout);
+                break;
+
+            case IP_TOS:
+                result = socketGetOption(optID);
+                if ( ((Integer)result).intValue() == -1) {
+                    result = new Integer(trafficClass);
+                }
+                break;
+
+            case SO_BINDADDR:
+            case IP_MULTICAST_IF:
+            case IP_MULTICAST_IF2:
+            case SO_RCVBUF:
+            case SO_SNDBUF:
+            case IP_MULTICAST_LOOP:
+            case SO_REUSEADDR:
+            case SO_BROADCAST:
+                result = socketGetOption(optID);
+                // Android-added: Added for app compat reason. See methodgetNIFirstAddress
+                if (optID == IP_MULTICAST_IF) {
+                    return getNIFirstAddress((Integer)result);
+                }
+                break;
+
+            default:
+                throw new SocketException("invalid option: " + optID);
+        }
+
+        return result;
+    }
+
+    // BEGIN Android-added: Support Integer IP_MULTICAST_IF2 values for app compat. b/26790580
+    // Native code is changed to return the index of network interface when calling
+    // getOption(IP_MULTICAST_IF2) due to app compat reason.
+    //
+    // For getOption(IP_MULTICAST_IF), we should keep returning InetAddress instance. This method
+    // convert NetworkInterface index into InetAddress instance.
+    /** Return the first address bound to NetworkInterface with given ID.
+     * In case of niIndex == 0 or no address return anyLocalAddress
+     */
+    static InetAddress getNIFirstAddress(int niIndex) throws SocketException {
+        if (niIndex > 0) {
+            NetworkInterface networkInterface = NetworkInterface.getByIndex(niIndex);
+            Enumeration<InetAddress> addressesEnum = networkInterface.getInetAddresses();
+            if (addressesEnum.hasMoreElements()) {
+                return addressesEnum.nextElement();
+            }
+        }
+        return InetAddress.anyLocalAddress();
+    }
+    // END Android-added: Support Integer IP_MULTICAST_IF2 values for app compat. b/26790580
+
+    protected abstract void datagramSocketCreate() throws SocketException;
+    protected abstract void datagramSocketClose();
+    protected abstract void socketSetOption(int opt, Object val)
+        throws SocketException;
+    protected abstract Object socketGetOption(int opt) throws SocketException;
+
+    protected abstract void connect0(InetAddress address, int port) throws SocketException;
+    protected abstract void disconnect0(int family);
+
+    protected boolean nativeConnectDisabled() {
+        return connectDisabled;
+    }
+
+    // Android-changed: rewritten on the top of IoBridge
+    int dataAvailable() {
+        try {
+            return IoBridge.available(fd);
+        } catch (IOException e) {
+            return -1;
+        }
+    }
+}
diff --git a/java/net/AbstractPlainSocketImpl.java b/java/net/AbstractPlainSocketImpl.java
new file mode 100644
index 0000000..0500811
--- /dev/null
+++ b/java/net/AbstractPlainSocketImpl.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileDescriptor;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.BlockGuard;
+import dalvik.system.CloseGuard;
+import dalvik.system.SocketTagger;
+import sun.net.ConnectionResetException;
+import sun.net.NetHooks;
+import sun.net.ResourceManager;
+
+/**
+ * Default Socket Implementation. This implementation does
+ * not implement any security checks.
+ * Note this class should <b>NOT</b> be public.
+ *
+ * @author  Steven B. Byrne
+ */
+abstract class AbstractPlainSocketImpl extends SocketImpl
+{
+    /* instance variable for SO_TIMEOUT */
+    int timeout;   // timeout in millisec
+    // Android-removed: traffic class is set through socket
+    // private int trafficClass;
+
+    private boolean shut_rd = false;
+    private boolean shut_wr = false;
+
+    private SocketInputStream socketInputStream = null;
+    private SocketOutputStream socketOutputStream = null;
+
+    /* number of threads using the FileDescriptor */
+    protected int fdUseCount = 0;
+
+    /* lock when increment/decrementing fdUseCount */
+    // Android-added: @ReachabilitySensitive
+    // Marked mostly because it's used where fd is, and fd isn't declared here.
+    // This adds reachabilityFences where we would if fd were annotated.
+    @ReachabilitySensitive
+    protected final Object fdLock = new Object();
+
+    /* indicates a close is pending on the file descriptor */
+    protected boolean closePending = false;
+
+    /* indicates connection reset state */
+    private int CONNECTION_NOT_RESET = 0;
+    private int CONNECTION_RESET_PENDING = 1;
+    private int CONNECTION_RESET = 2;
+    private int resetState;
+    private final Object resetLock = new Object();
+
+   /* whether this Socket is a stream (TCP) socket or not (UDP)
+    */
+    protected boolean stream;
+
+    // BEGIN Android-removed: Android doesn't need to load native net library
+    /*
+    /**
+     * Load net library into runtime.
+     *
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+    }
+    */
+    // END Android-removed: Android doesn't need to load native net library
+
+    // Android-added: logs a warning if socket is not closed
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    /**
+     * Creates a socket with a boolean that specifies whether this
+     * is a stream socket (true) or an unconnected UDP socket (false).
+     */
+    protected synchronized void create(boolean stream) throws IOException {
+        this.stream = stream;
+        if (!stream) {
+            ResourceManager.beforeUdpCreate();
+            // Android-removed: socketCreate should set fd if it succeeds
+            // fd = new FileDescriptor();
+            try {
+                socketCreate(false);
+            } catch (IOException ioe) {
+                ResourceManager.afterUdpClose();
+                // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null.
+                // fd = null;
+                throw ioe;
+            }
+        } else {
+            // Android-removed: socketCreate should set fd if it succeeds
+            // fd = new FileDescriptor();
+            socketCreate(true);
+        }
+        if (socket != null)
+            socket.setCreated();
+        if (serverSocket != null)
+            serverSocket.setCreated();
+
+        // Android-added: CloseGuard
+        if (fd != null && fd.valid()) {
+            guard.open("close");
+        }
+    }
+
+    /**
+     * Creates a socket and connects it to the specified port on
+     * the specified host.
+     * @param host the specified host
+     * @param port the specified port
+     */
+    protected void connect(String host, int port)
+        throws UnknownHostException, IOException
+    {
+        boolean connected = false;
+        try {
+            InetAddress address = InetAddress.getByName(host);
+            this.port = port;
+            this.address = address;
+
+            connectToAddress(address, port, timeout);
+            connected = true;
+        } finally {
+            if (!connected) {
+                try {
+                    close();
+                } catch (IOException ioe) {
+                    /* Do nothing. If connect threw an exception then
+                       it will be passed up the call stack */
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates a socket and connects it to the specified address on
+     * the specified port.
+     * @param address the address
+     * @param port the specified port
+     */
+    protected void connect(InetAddress address, int port) throws IOException {
+        this.port = port;
+        this.address = address;
+
+        try {
+            connectToAddress(address, port, timeout);
+            return;
+        } catch (IOException e) {
+            // everything failed
+            close();
+            throw e;
+        }
+    }
+
+    /**
+     * Creates a socket and connects it to the specified address on
+     * the specified port.
+     * @param address the address
+     * @param timeout the timeout value in milliseconds, or zero for no timeout.
+     * @throws IOException if connection fails
+     * @throws  IllegalArgumentException if address is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    protected void connect(SocketAddress address, int timeout)
+            throws IOException {
+        boolean connected = false;
+        try {
+            if (address == null || !(address instanceof InetSocketAddress))
+                throw new IllegalArgumentException("unsupported address type");
+            InetSocketAddress addr = (InetSocketAddress) address;
+            if (addr.isUnresolved())
+                throw new UnknownHostException(addr.getHostName());
+            this.port = addr.getPort();
+            this.address = addr.getAddress();
+
+            connectToAddress(this.address, port, timeout);
+            connected = true;
+        } finally {
+            if (!connected) {
+                try {
+                    close();
+                } catch (IOException ioe) {
+                    /* Do nothing. If connect threw an exception then
+                       it will be passed up the call stack */
+                }
+            }
+        }
+    }
+
+    private void connectToAddress(InetAddress address, int port, int timeout) throws IOException {
+        if (address.isAnyLocalAddress()) {
+            doConnect(InetAddress.getLocalHost(), port, timeout);
+        } else {
+            doConnect(address, port, timeout);
+        }
+    }
+
+    public void setOption(int opt, Object val) throws SocketException {
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket Closed");
+        }
+        // BEGIN Android-removed: Logic dealing with value type moved to socketSetOption.
+        /*
+        boolean on = true;
+        switch (opt) {
+            /* check type safety b4 going native.  These should never
+             * fail, since only java.Socket* has access to
+             * PlainSocketImpl.setOption().
+             *
+        case SO_LINGER:
+            if (val == null || (!(val instanceof Integer) && !(val instanceof Boolean)))
+                throw new SocketException("Bad parameter for option");
+            if (val instanceof Boolean) {
+                /* true only if disabling - enabling should be Integer *
+                on = false;
+            }
+            break;
+        case SO_TIMEOUT:
+            if (val == null || (!(val instanceof Integer)))
+                throw new SocketException("Bad parameter for SO_TIMEOUT");
+            int tmp = ((Integer) val).intValue();
+            if (tmp < 0)
+                throw new IllegalArgumentException("timeout < 0");
+            timeout = tmp;
+            break;
+        case IP_TOS:
+             if (val == null || !(val instanceof Integer)) {
+                 throw new SocketException("bad argument for IP_TOS");
+             }
+             trafficClass = ((Integer)val).intValue();
+             break;
+        case SO_BINDADDR:
+            throw new SocketException("Cannot re-bind socket");
+        case TCP_NODELAY:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for TCP_NODELAY");
+            on = ((Boolean)val).booleanValue();
+            break;
+        case SO_SNDBUF:
+        case SO_RCVBUF:
+            if (val == null || !(val instanceof Integer) ||
+                !(((Integer)val).intValue() > 0)) {
+                throw new SocketException("bad parameter for SO_SNDBUF " +
+                                          "or SO_RCVBUF");
+            }
+            break;
+        case SO_KEEPALIVE:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_KEEPALIVE");
+            on = ((Boolean)val).booleanValue();
+            break;
+        case SO_OOBINLINE:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_OOBINLINE");
+            on = ((Boolean)val).booleanValue();
+            break;
+        case SO_REUSEADDR:
+            if (val == null || !(val instanceof Boolean))
+                throw new SocketException("bad parameter for SO_REUSEADDR");
+            on = ((Boolean)val).booleanValue();
+            break;
+        default:
+            throw new SocketException("unrecognized TCP option: " + opt);
+        }
+        socketSetOption(opt, on, val);
+        */
+        // END Android-removed: Logic dealing with value type moved to socketSetOption.
+        // Android-added: Keep track of timeout value not handled by socketSetOption
+        if (opt == SO_TIMEOUT) {
+            timeout = (Integer) val;
+        }
+        socketSetOption(opt, val);
+    }
+    public Object getOption(int opt) throws SocketException {
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket Closed");
+        }
+        if (opt == SO_TIMEOUT) {
+            return new Integer(timeout);
+        }
+        // BEGIN Android-changed: Logic dealing with value type moved to socketGetOption.
+        /*
+        int ret = 0;
+        /*
+         * The native socketGetOption() knows about 3 options.
+         * The 32 bit value it returns will be interpreted according
+         * to what we're asking.  A return of -1 means it understands
+         * the option but its turned off.  It will raise a SocketException
+         * if "opt" isn't one it understands.
+         *
+
+        switch (opt) {
+        case TCP_NODELAY:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        case SO_OOBINLINE:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        case SO_LINGER:
+            ret = socketGetOption(opt, null);
+            return (ret == -1) ? Boolean.FALSE: (Object)(new Integer(ret));
+        case SO_REUSEADDR:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        case SO_BINDADDR:
+            InetAddressContainer in = new InetAddressContainer();
+            ret = socketGetOption(opt, in);
+            return in.addr;
+        case SO_SNDBUF:
+        case SO_RCVBUF:
+            ret = socketGetOption(opt, null);
+            return new Integer(ret);
+        case IP_TOS:
+            try {
+                ret = socketGetOption(opt, null);
+                if (ret == -1) { // ipv6 tos
+                    return trafficClass;
+                } else {
+                    return ret;
+                }
+            } catch (SocketException se) {
+                // TODO - should make better effort to read TOS or TCLASS
+                return trafficClass; // ipv6 tos
+            }
+        case SO_KEEPALIVE:
+            ret = socketGetOption(opt, null);
+            return Boolean.valueOf(ret != -1);
+        // should never get here
+        default:
+            return null;
+        }
+        */
+        return socketGetOption(opt);
+        // END Android-changed: Logic dealing with value type moved to socketGetOption.
+    }
+
+    /**
+     * The workhorse of the connection operation.  Tries several times to
+     * establish a connection to the given <host, port>.  If unsuccessful,
+     * throws an IOException indicating what went wrong.
+     */
+
+    synchronized void doConnect(InetAddress address, int port, int timeout) throws IOException {
+        synchronized (fdLock) {
+            if (!closePending && (socket == null || !socket.isBound())) {
+                NetHooks.beforeTcpConnect(fd, address, port);
+            }
+        }
+        try {
+            acquireFD();
+            try {
+                // Android-added: BlockGuard
+                BlockGuard.getThreadPolicy().onNetwork();
+                socketConnect(address, port, timeout);
+                /* socket may have been closed during poll/select */
+                synchronized (fdLock) {
+                    if (closePending) {
+                        throw new SocketException ("Socket closed");
+                    }
+                }
+                // If we have a ref. to the Socket, then sets the flags
+                // created, bound & connected to true.
+                // This is normally done in Socket.connect() but some
+                // subclasses of Socket may call impl.connect() directly!
+                if (socket != null) {
+                    socket.setBound();
+                    socket.setConnected();
+                }
+            } finally {
+                releaseFD();
+            }
+        } catch (IOException e) {
+            close();
+            throw e;
+        }
+    }
+
+    /**
+     * Binds the socket to the specified address of the specified local port.
+     * @param address the address
+     * @param lport the port
+     */
+    protected synchronized void bind(InetAddress address, int lport)
+        throws IOException
+    {
+       synchronized (fdLock) {
+            if (!closePending && (socket == null || !socket.isBound())) {
+                NetHooks.beforeTcpBind(fd, address, lport);
+            }
+        }
+        socketBind(address, lport);
+        if (socket != null)
+            socket.setBound();
+        if (serverSocket != null)
+            serverSocket.setBound();
+    }
+
+    /**
+     * Listens, for a specified amount of time, for connections.
+     * @param count the amount of time to listen for connections
+     */
+    protected synchronized void listen(int count) throws IOException {
+        socketListen(count);
+    }
+
+    /**
+     * Accepts connections.
+     * @param s the connection
+     */
+    protected void accept(SocketImpl s) throws IOException {
+        acquireFD();
+        try {
+            // Android-added: BlockGuard
+            BlockGuard.getThreadPolicy().onNetwork();
+            socketAccept(s);
+        } finally {
+            releaseFD();
+        }
+    }
+
+    /**
+     * Gets an InputStream for this socket.
+     */
+    protected synchronized InputStream getInputStream() throws IOException {
+        synchronized (fdLock) {
+            if (isClosedOrPending())
+                throw new IOException("Socket Closed");
+            if (shut_rd)
+                throw new IOException("Socket input is shutdown");
+            if (socketInputStream == null)
+                socketInputStream = new SocketInputStream(this);
+        }
+        return socketInputStream;
+    }
+
+    void setInputStream(SocketInputStream in) {
+        socketInputStream = in;
+    }
+
+    /**
+     * Gets an OutputStream for this socket.
+     */
+    protected synchronized OutputStream getOutputStream() throws IOException {
+        synchronized (fdLock) {
+            if (isClosedOrPending())
+                throw new IOException("Socket Closed");
+            if (shut_wr)
+                throw new IOException("Socket output is shutdown");
+            if (socketOutputStream == null)
+                socketOutputStream = new SocketOutputStream(this);
+        }
+        return socketOutputStream;
+    }
+
+    // Android-removed: this.fd is maintained by the concrete implementation.
+    /*
+    void setFileDescriptor(FileDescriptor fd) {
+        this.fd = fd;
+    }
+    */
+
+    void setAddress(InetAddress address) {
+        this.address = address;
+    }
+
+    void setPort(int port) {
+        this.port = port;
+    }
+
+    void setLocalPort(int localport) {
+        this.localport = localport;
+    }
+
+    /**
+     * Returns the number of bytes that can be read without blocking.
+     */
+    protected synchronized int available() throws IOException {
+        if (isClosedOrPending()) {
+            throw new IOException("Stream closed.");
+        }
+
+        /*
+         * If connection has been reset or shut down for input, then return 0
+         * to indicate there are no buffered bytes.
+         */
+        if (isConnectionReset() || shut_rd) {
+            return 0;
+        }
+
+        /*
+         * If no bytes available and we were previously notified
+         * of a connection reset then we move to the reset state.
+         *
+         * If are notified of a connection reset then check
+         * again if there are bytes buffered on the socket.
+         */
+        int n = 0;
+        try {
+            n = socketAvailable();
+            if (n == 0 && isConnectionResetPending()) {
+                setConnectionReset();
+            }
+        } catch (ConnectionResetException exc1) {
+            setConnectionResetPending();
+            try {
+                n = socketAvailable();
+                if (n == 0) {
+                    setConnectionReset();
+                }
+            } catch (ConnectionResetException exc2) {
+            }
+        }
+        return n;
+    }
+
+    /**
+     * Closes the socket.
+     */
+    protected void close() throws IOException {
+        synchronized(fdLock) {
+            if (fd != null && fd.valid()) {
+                if (!stream) {
+                    ResourceManager.afterUdpClose();
+                }
+                // Android-changed:
+                // Socket should be untagged before the preclose. After preclose,
+                // socket will dup2-ed to marker_fd, therefore, it won't describe the same file.
+                // If closingPending is true, then the socket has been preclosed.
+                //
+                // Also, close the CloseGuard when the #close is called.
+                if (!closePending) {
+                    closePending = true;
+                    guard.close();
+
+                    if (fdUseCount == 0) {
+                        /*
+                         * We close the FileDescriptor in two-steps - first the
+                         * "pre-close" which closes the socket but doesn't
+                         * release the underlying file descriptor. This operation
+                         * may be lengthy due to untransmitted data and a long
+                         * linger interval. Once the pre-close is done we do the
+                         * actual socket to release the fd.
+                         */
+                        try {
+                            socketPreClose();
+                        } finally {
+                            socketClose();
+                        }
+                        // Android-changed(http://b/26470377): Some Android code doesn't expect file
+                        // descriptor to be null. socketClose invalidates the fd by closing the fd.
+                        // fd = null;
+                        return;
+                    } else {
+                        /*
+                         * If a thread has acquired the fd and a close
+                         * isn't pending then use a deferred close.
+                         * Also decrement fdUseCount to signal the last
+                         * thread that releases the fd to close it.
+                         */
+                        fdUseCount--;
+                        socketPreClose();
+                    }
+                }
+            }
+        }
+    }
+
+    void reset() throws IOException {
+        if (fd != null && fd.valid()) {
+            socketClose();
+            // Android-changed: Notified the CloseGuard object as the fd has been released.
+            guard.close();
+        }
+        // Android-removed: b/26470377 Represent closed sockets with invalid fd, not null.
+        // fd = null;
+        super.reset();
+    }
+
+
+    /**
+     * Shutdown read-half of the socket connection;
+     */
+    protected void shutdownInput() throws IOException {
+      // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+      if (fd != null && fd.valid()) {
+          socketShutdown(SHUT_RD);
+          if (socketInputStream != null) {
+              socketInputStream.setEOF(true);
+          }
+          shut_rd = true;
+      }
+    }
+
+    /**
+     * Shutdown write-half of the socket connection;
+     */
+    protected void shutdownOutput() throws IOException {
+      // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+      if (fd != null && fd.valid()) {
+          socketShutdown(SHUT_WR);
+          shut_wr = true;
+      }
+    }
+
+    protected boolean supportsUrgentData () {
+        return true;
+    }
+
+    protected void sendUrgentData (int data) throws IOException {
+        // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+        if (fd == null || !fd.valid()) {
+            throw new IOException("Socket Closed");
+        }
+        socketSendUrgentData (data);
+    }
+
+    /**
+     * Cleans up if the user forgets to close it.
+     */
+    protected void finalize() throws IOException {
+        // Android-added: CloseGuard
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        close();
+    }
+
+    /*
+     * "Acquires" and returns the FileDescriptor for this impl
+     *
+     * A corresponding releaseFD is required to "release" the
+     * FileDescriptor.
+     */
+    FileDescriptor acquireFD() {
+        synchronized (fdLock) {
+            fdUseCount++;
+            return fd;
+        }
+    }
+
+    /*
+     * "Release" the FileDescriptor for this impl.
+     *
+     * If the use count goes to -1 then the socket is closed.
+     */
+    void releaseFD() {
+        synchronized (fdLock) {
+            fdUseCount--;
+            if (fdUseCount == -1) {
+                if (fd != null) {
+                    try {
+                        socketClose();
+                    } catch (IOException e) {
+                        // Android-removed: b/26470377 Some Android code doesn't expect file
+                        // descriptor to be null. socketClose invalidates the fd by closing the fd.
+                        // } finally {
+                        //     fd = null;
+                    }
+                }
+            }
+        }
+    }
+
+    public boolean isConnectionReset() {
+        synchronized (resetLock) {
+            return (resetState == CONNECTION_RESET);
+        }
+    }
+
+    public boolean isConnectionResetPending() {
+        synchronized (resetLock) {
+            return (resetState == CONNECTION_RESET_PENDING);
+        }
+    }
+
+    public void setConnectionReset() {
+        synchronized (resetLock) {
+            resetState = CONNECTION_RESET;
+        }
+    }
+
+    public void setConnectionResetPending() {
+        synchronized (resetLock) {
+            if (resetState == CONNECTION_NOT_RESET) {
+                resetState = CONNECTION_RESET_PENDING;
+            }
+        }
+
+    }
+
+    /*
+     * Return true if already closed or close is pending
+     */
+    public boolean isClosedOrPending() {
+        /*
+         * Lock on fdLock to ensure that we wait if a
+         * close is in progress.
+         */
+        synchronized (fdLock) {
+            // Android-changed: b/26470377 Represent closed sockets with invalid fd, not null.
+            if (closePending || (fd == null) || !fd.valid()) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /*
+     * Return the current value of SO_TIMEOUT
+     */
+    public int getTimeout() {
+        return timeout;
+    }
+
+    /*
+     * "Pre-close" a socket by dup'ing the file descriptor - this enables
+     * the socket to be closed without releasing the file descriptor.
+     */
+    private void socketPreClose() throws IOException {
+        socketClose0(true);
+    }
+
+    /*
+     * Close the socket (and release the file descriptor).
+     */
+    protected void socketClose() throws IOException {
+        socketClose0(false);
+    }
+
+    abstract void socketCreate(boolean isServer) throws IOException;
+    abstract void socketConnect(InetAddress address, int port, int timeout)
+        throws IOException;
+    abstract void socketBind(InetAddress address, int port)
+        throws IOException;
+    abstract void socketListen(int count)
+        throws IOException;
+    abstract void socketAccept(SocketImpl s)
+        throws IOException;
+    abstract int socketAvailable()
+        throws IOException;
+    abstract void socketClose0(boolean useDeferredClose)
+        throws IOException;
+    abstract void socketShutdown(int howto)
+        throws IOException;
+
+    // Android-changed: Method signature changed, socket{Get,Set}Option work directly with Object
+    // values.
+    abstract void socketSetOption(int cmd, Object value) throws SocketException;
+    abstract Object socketGetOption(int opt) throws SocketException;
+
+    abstract void socketSendUrgentData(int data)
+        throws IOException;
+
+    public final static int SHUT_RD = 0;
+    public final static int SHUT_WR = 1;
+}
diff --git a/java/net/AddressCache.java b/java/net/AddressCache.java
new file mode 100644
index 0000000..3026923
--- /dev/null
+++ b/java/net/AddressCache.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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.net;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import libcore.util.BasicLruCache;
+
+/**
+ * Implements caching for {@code InetAddress}. We use a unified cache for both positive and negative
+ * cache entries.
+ *
+ * TODO: benchmark and optimize InetAddress until we get to the point where we can just rely on
+ * the C library level caching. The main thing caching at this level buys us is avoiding repeated
+ * conversions from 'struct sockaddr's to InetAddress[].
+ */
+class AddressCache {
+    /**
+     * When the cache contains more entries than this, we start dropping the oldest ones.
+     * This should be a power of two to avoid wasted space in our custom map.
+     */
+    private static final int MAX_ENTRIES = 16;
+
+    // The TTL for the Java-level cache is short, just 2s.
+    private static final long TTL_NANOS = 2 * 1000000000L;
+
+    // The actual cache.
+    @UnsupportedAppUsage
+    private final BasicLruCache<AddressCacheKey, AddressCacheEntry> cache
+            = new BasicLruCache<AddressCacheKey, AddressCacheEntry>(MAX_ENTRIES);
+
+    static class AddressCacheKey {
+        @UnsupportedAppUsage
+        private final String mHostname;
+        private final int mNetId;
+
+        AddressCacheKey(String hostname, int netId) {
+            mHostname = hostname;
+            mNetId = netId;
+        }
+
+        @Override public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof AddressCacheKey)) {
+                return false;
+            }
+            AddressCacheKey lhs = (AddressCacheKey) o;
+            return mHostname.equals(lhs.mHostname) && mNetId == lhs.mNetId;
+        }
+
+        @Override public int hashCode() {
+            int result = 17;
+            result = 31 * result + mNetId;
+            result = 31 * result + mHostname.hashCode();
+            return result;
+        }
+    }
+
+    static class AddressCacheEntry {
+        // Either an InetAddress[] for a positive entry,
+        // or a String detail message for a negative entry.
+        @UnsupportedAppUsage
+        final Object value;
+
+        /**
+         * The absolute expiry time in nanoseconds. Nanoseconds from System.nanoTime is ideal
+         * because -- unlike System.currentTimeMillis -- it can never go backwards.
+         *
+         * We don't need to worry about overflow with a TTL_NANOS of 2s.
+         */
+        @UnsupportedAppUsage
+        final long expiryNanos;
+
+        @UnsupportedAppUsage
+        AddressCacheEntry(Object value) {
+            this.value = value;
+            this.expiryNanos = System.nanoTime() + TTL_NANOS;
+        }
+    }
+
+    /**
+     * Removes all entries from the cache.
+     */
+    public void clear() {
+        cache.evictAll();
+    }
+
+    /**
+     * Returns the cached InetAddress[] for 'hostname' on network 'netId'. Returns null
+     * if nothing is known about 'hostname'. Returns a String suitable for use as an
+     * UnknownHostException detail message if 'hostname' is known not to exist.
+     */
+    public Object get(String hostname, int netId) {
+        AddressCacheEntry entry = cache.get(new AddressCacheKey(hostname, netId));
+        // Do we have a valid cache entry?
+        if (entry != null && entry.expiryNanos >= System.nanoTime()) {
+            return entry.value;
+        }
+        // Either we didn't find anything, or it had expired.
+        // No need to remove expired entries: the caller will provide a replacement shortly.
+        return null;
+    }
+
+    /**
+     * Associates the given 'addresses' with 'hostname'. The association will expire after a
+     * certain length of time.
+     */
+    public void put(String hostname, int netId, InetAddress[] addresses) {
+        cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(addresses));
+    }
+
+    /**
+     * Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
+     * negative cache entry.)
+     */
+    public void putUnknownHost(String hostname, int netId, String detailMessage) {
+        cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(detailMessage));
+    }
+}
diff --git a/java/net/Authenticator.java b/java/net/Authenticator.java
new file mode 100644
index 0000000..c88a600
--- /dev/null
+++ b/java/net/Authenticator.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * The class Authenticator represents an object that knows how to obtain
+ * authentication for a network connection.  Usually, it will do this
+ * by prompting the user for information.
+ * <p>
+ * Applications use this class by overriding {@link
+ * #getPasswordAuthentication()} in a sub-class. This method will
+ * typically use the various getXXX() accessor methods to get information
+ * about the entity requesting authentication. It must then acquire a
+ * username and password either by interacting with the user or through
+ * some other non-interactive means. The credentials are then returned
+ * as a {@link PasswordAuthentication} return value.
+ * <p>
+ * An instance of this concrete sub-class is then registered
+ * with the system by calling {@link #setDefault(Authenticator)}.
+ * When authentication is required, the system will invoke one of the
+ * requestPasswordAuthentication() methods which in turn will call the
+ * getPasswordAuthentication() method of the registered object.
+ * <p>
+ * All methods that request authentication have a default implementation
+ * that fails.
+ *
+ * @see java.net.Authenticator#setDefault(java.net.Authenticator)
+ * @see java.net.Authenticator#getPasswordAuthentication()
+ *
+ * @author  Bill Foote
+ * @since   1.2
+ */
+
+// There are no abstract methods, but to be useful the user must
+// subclass.
+public abstract
+class Authenticator {
+
+    // The system-wide authenticator object.  See setDefault().
+    private static Authenticator theAuthenticator;
+
+    private String requestingHost;
+    private InetAddress requestingSite;
+    private int requestingPort;
+    private String requestingProtocol;
+    private String requestingPrompt;
+    private String requestingScheme;
+    private URL requestingURL;
+    private RequestorType requestingAuthType;
+
+    /**
+     * The type of the entity requesting authentication.
+     *
+     * @since 1.5
+     */
+    public enum RequestorType {
+        /**
+         * Entity requesting authentication is a HTTP proxy server.
+         */
+        PROXY,
+        /**
+         * Entity requesting authentication is a HTTP origin server.
+         */
+        SERVER
+    }
+
+    private void reset() {
+        requestingHost = null;
+        requestingSite = null;
+        requestingPort = -1;
+        requestingProtocol = null;
+        requestingPrompt = null;
+        requestingScheme = null;
+        requestingURL = null;
+        requestingAuthType = RequestorType.SERVER;
+    }
+
+
+    /**
+     * Sets the authenticator that will be used by the networking code
+     * when a proxy or an HTTP server asks for authentication.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("setDefaultAuthenticator")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param   a       The authenticator to be set. If a is {@code null} then
+     *                  any previously set authenticator is removed.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        setting the default authenticator.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     */
+    public synchronized static void setDefault(Authenticator a) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission setDefaultPermission
+                = new NetPermission("setDefaultAuthenticator");
+            sm.checkPermission(setDefaultPermission);
+        }
+
+        theAuthenticator = a;
+    }
+
+    /**
+     * Ask the authenticator that has been registered with the system
+     * for a password.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     *
+     * @return The username/password, or null if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                            InetAddress addr,
+                                            int port,
+                                            String protocol,
+                                            String prompt,
+                                            String scheme) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = theAuthenticator;
+        if (a == null) {
+            return null;
+        } else {
+            synchronized(a) {
+                a.reset();
+                a.requestingSite = addr;
+                a.requestingPort = port;
+                a.requestingProtocol = protocol;
+                a.requestingPrompt = prompt;
+                a.requestingScheme = scheme;
+                return a.getPasswordAuthentication();
+            }
+        }
+    }
+
+    /**
+     * Ask the authenticator that has been registered with the system
+     * for a password. This is the preferred method for requesting a password
+     * because the hostname can be provided in cases where the InetAddress
+     * is not available.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authentication,
+     *             or null if not known.
+     * @param port the port for the requested connection.
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user which identifies the authentication realm.
+     * @param scheme The authentication scheme
+     *
+     * @return The username/password, or null if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     * @since 1.4
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                            String host,
+                                            InetAddress addr,
+                                            int port,
+                                            String protocol,
+                                            String prompt,
+                                            String scheme) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = theAuthenticator;
+        if (a == null) {
+            return null;
+        } else {
+            synchronized(a) {
+                a.reset();
+                a.requestingHost = host;
+                a.requestingSite = addr;
+                a.requestingPort = port;
+                a.requestingProtocol = protocol;
+                a.requestingPrompt = prompt;
+                a.requestingScheme = scheme;
+                return a.getPasswordAuthentication();
+            }
+        }
+    }
+
+    /**
+     * Ask the authenticator that has been registered with the system
+     * for a password.
+     * <p>
+     * First, if there is a security manager, its {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("requestPasswordAuthentication")} permission.
+     * This may result in a java.lang.SecurityException.
+     *
+     * @param host The hostname of the site requesting authentication.
+     * @param addr The InetAddress of the site requesting authorization,
+     *             or null if not known.
+     * @param port the port for the requested connection
+     * @param protocol The protocol that's requesting the connection
+     *          ({@link java.net.Authenticator#getRequestingProtocol()})
+     * @param prompt A prompt string for the user
+     * @param scheme The authentication scheme
+     * @param url The requesting URL that caused the authentication
+     * @param reqType The type (server or proxy) of the entity requesting
+     *              authentication.
+     *
+     * @return The username/password, or null if one can't be gotten.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        the password authentication request.
+     *
+     * @see SecurityManager#checkPermission
+     * @see java.net.NetPermission
+     *
+     * @since 1.5
+     */
+    public static PasswordAuthentication requestPasswordAuthentication(
+                                    String host,
+                                    InetAddress addr,
+                                    int port,
+                                    String protocol,
+                                    String prompt,
+                                    String scheme,
+                                    URL url,
+                                    RequestorType reqType) {
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            NetPermission requestPermission
+                = new NetPermission("requestPasswordAuthentication");
+            sm.checkPermission(requestPermission);
+        }
+
+        Authenticator a = theAuthenticator;
+        if (a == null) {
+            return null;
+        } else {
+            synchronized(a) {
+                a.reset();
+                a.requestingHost = host;
+                a.requestingSite = addr;
+                a.requestingPort = port;
+                a.requestingProtocol = protocol;
+                a.requestingPrompt = prompt;
+                a.requestingScheme = scheme;
+                a.requestingURL = url;
+                a.requestingAuthType = reqType;
+                return a.getPasswordAuthentication();
+            }
+        }
+    }
+
+    /**
+     * Gets the {@code hostname} of the
+     * site or proxy requesting authentication, or {@code null}
+     * if not available.
+     *
+     * @return the hostname of the connection requiring authentication, or null
+     *          if it's not available.
+     * @since 1.4
+     */
+    protected final String getRequestingHost() {
+        return requestingHost;
+    }
+
+    /**
+     * Gets the {@code InetAddress} of the
+     * site requesting authorization, or {@code null}
+     * if not available.
+     *
+     * @return the InetAddress of the site requesting authorization, or null
+     *          if it's not available.
+     */
+    protected final InetAddress getRequestingSite() {
+        return requestingSite;
+    }
+
+    /**
+     * Gets the port number for the requested connection.
+     * @return an {@code int} indicating the
+     * port for the requested connection.
+     */
+    protected final int getRequestingPort() {
+        return requestingPort;
+    }
+
+    /**
+     * Give the protocol that's requesting the connection.  Often this
+     * will be based on a URL, but in a future JDK it could be, for
+     * example, "SOCKS" for a password-protected SOCKS5 firewall.
+     *
+     * @return the protocol, optionally followed by "/version", where
+     *          version is a version number.
+     *
+     * @see java.net.URL#getProtocol()
+     */
+    protected final String getRequestingProtocol() {
+        return requestingProtocol;
+    }
+
+    /**
+     * Gets the prompt string given by the requestor.
+     *
+     * @return the prompt string given by the requestor (realm for
+     *          http requests)
+     */
+    protected final String getRequestingPrompt() {
+        return requestingPrompt;
+    }
+
+    /**
+     * Gets the scheme of the requestor (the HTTP scheme
+     * for an HTTP firewall, for example).
+     *
+     * @return the scheme of the requestor
+     *
+     */
+    protected final String getRequestingScheme() {
+        return requestingScheme;
+    }
+
+    /**
+     * Called when password authorization is needed.  Subclasses should
+     * override the default implementation, which returns null.
+     * @return The PasswordAuthentication collected from the
+     *          user, or null if none is provided.
+     */
+    protected PasswordAuthentication getPasswordAuthentication() {
+        return null;
+    }
+
+    /**
+     * Returns the URL that resulted in this
+     * request for authentication.
+     *
+     * @since 1.5
+     *
+     * @return the requesting URL
+     *
+     */
+    protected URL getRequestingURL () {
+        return requestingURL;
+    }
+
+    /**
+     * Returns whether the requestor is a Proxy or a Server.
+     *
+     * @since 1.5
+     *
+     * @return the authentication type of the requestor
+     *
+     */
+    protected RequestorType getRequestorType () {
+        return requestingAuthType;
+    }
+}
diff --git a/java/net/BindException.java b/java/net/BindException.java
new file mode 100644
index 0000000..9c2bb48
--- /dev/null
+++ b/java/net/BindException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an error occurred while attempting to bind a
+ * socket to a local address and port.  Typically, the port is
+ * in use, or the requested local address could not be assigned.
+ *
+ * @since   JDK1.1
+ */
+
+public class BindException extends SocketException {
+    private static final long serialVersionUID = -5945005768251722951L;
+
+    /**
+     * Constructs a new BindException with the specified detail
+     * message as to why the bind error occurred.
+     * A detail message is a String that gives a specific
+     * description of this error.
+     * @param msg the detail message
+     */
+    public BindException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new BindException with no detailed message.
+     */
+    public BindException() {}
+
+    // Android-added: Constructor called by IoBridge
+    /** @hide */
+    public BindException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/java/net/CacheRequest.java b/java/net/CacheRequest.java
new file mode 100644
index 0000000..a6fbbc3
--- /dev/null
+++ b/java/net/CacheRequest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * Represents channels for storing resources in the
+ * ResponseCache. Instances of such a class provide an
+ * OutputStream object which is called by protocol handlers to
+ * store the resource data into the cache, and also an abort() method
+ * which allows a cache store operation to be interrupted and
+ * abandoned. If an IOException is encountered while reading the
+ * response or writing to the cache, the current cache store operation
+ * will be aborted.
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class CacheRequest {
+
+    /**
+     * Returns an OutputStream to which the response body can be
+     * written.
+     *
+     * @return an OutputStream to which the response body can
+     *         be written
+     * @throws IOException if an I/O error occurs while
+     *         writing the response body
+     */
+    public abstract OutputStream getBody() throws IOException;
+
+    /**
+     * Aborts the attempt to cache the response. If an IOException is
+     * encountered while reading the response or writing to the cache,
+     * the current cache store operation will be abandoned.
+     */
+    public abstract void abort();
+}
diff --git a/java/net/CacheResponse.java b/java/net/CacheResponse.java
new file mode 100644
index 0000000..272b3d9
--- /dev/null
+++ b/java/net/CacheResponse.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * Represent channels for retrieving resources from the
+ * ResponseCache. Instances of such a class provide an
+ * InputStream that returns the entity body, and also a
+ * getHeaders() method which returns the associated response headers.
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class CacheResponse {
+
+    /**
+     * Returns the response headers as a Map.
+     *
+     * @return An immutable Map from response header field names to
+     *         lists of field values. The status line has null as its
+     *         field name.
+     * @throws IOException if an I/O error occurs
+     *            while getting the response headers
+     */
+    public abstract Map<String, List<String>> getHeaders() throws IOException;
+
+    /**
+     * Returns the response body as an InputStream.
+     *
+     * @return an InputStream from which the response body can
+     *         be accessed
+     * @throws IOException if an I/O error occurs while
+     *         getting the response body
+     */
+    public abstract InputStream getBody() throws IOException;
+}
diff --git a/java/net/ConnectException.java b/java/net/ConnectException.java
new file mode 100644
index 0000000..ff58643
--- /dev/null
+++ b/java/net/ConnectException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an error occurred while attempting to connect a
+ * socket to a remote address and port.  Typically, the connection
+ * was refused remotely (e.g., no process is listening on the
+ * remote address/port).
+ *
+ * @since   JDK1.1
+ */
+public class ConnectException extends SocketException {
+    private static final long serialVersionUID = 3831404271622369215L;
+
+    /**
+     * Constructs a new ConnectException with the specified detail
+     * message as to why the connect error occurred.
+     * A detail message is a String that gives a specific
+     * description of this error.
+     * @param msg the detail message
+     */
+    public ConnectException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new ConnectException with no detailed message.
+     */
+    public ConnectException() {}
+
+    // Android-added: Constructor called by IoBridge
+    /** @hide */
+    public ConnectException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/java/net/ContentHandler.java b/java/net/ContentHandler.java
new file mode 100644
index 0000000..c658585
--- /dev/null
+++ b/java/net/ContentHandler.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * The abstract class {@code ContentHandler} is the superclass
+ * of all classes that read an {@code Object} from a
+ * {@code URLConnection}.
+ * <p>
+ * An application does not generally call the
+ * {@code getContent} method in this class directly. Instead, an
+ * application calls the {@code getContent} method in class
+ * {@code URL} or in {@code URLConnection}.
+ * The application's content handler factory (an instance of a class that
+ * implements the interface {@code ContentHandlerFactory} set
+ * up by a call to {@code setContentHandler}) is
+ * called with a {@code String} giving the MIME type of the
+ * object being received on the socket. The factory returns an
+ * instance of a subclass of {@code ContentHandler}, and its
+ * {@code getContent} method is called to create the object.
+ * <p>
+ * If no content handler could be found, URLConnection will
+ * look for a content handler in a user-defineable set of places.
+ * By default it looks in sun.net.www.content, but users can define a
+ * vertical-bar delimited set of class prefixes to search through in
+ * addition by defining the java.content.handler.pkgs property.
+ * The class name must be of the form:
+ * <pre>
+ *     {package-prefix}.{major}.{minor}
+ * e.g.
+ *     YoyoDyne.experimental.text.plain
+ * </pre>
+ * If the loading of the content handler class would be performed by
+ * a classloader that is outside of the delegation chain of the caller,
+ * the JVM will need the RuntimePermission "getClassLoader".
+ *
+ * @author  James Gosling
+ * @see     java.net.ContentHandler#getContent(java.net.URLConnection)
+ * @see     java.net.ContentHandlerFactory
+ * @see     java.net.URL#getContent()
+ * @see     java.net.URLConnection
+ * @see     java.net.URLConnection#getContent()
+ * @see     java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
+ * @since   JDK1.0
+ */
+abstract public class ContentHandler {
+    /**
+     * Given a URL connect stream positioned at the beginning of the
+     * representation of an object, this method reads that stream and
+     * creates an object from it.
+     *
+     * @param      urlc   a URL connection.
+     * @return     the object read by the {@code ContentHandler}.
+     * @exception  IOException  if an I/O error occurs while reading the object.
+     */
+    abstract public Object getContent(URLConnection urlc) throws IOException;
+
+    /**
+     * Given a URL connect stream positioned at the beginning of the
+     * representation of an object, this method reads that stream and
+     * creates an object that matches one of the types specified.
+     *
+     * The default implementation of this method should call getContent()
+     * and screen the return type for a match of the suggested types.
+     *
+     * @param      urlc   a URL connection.
+     * @param      classes      an array of types requested
+     * @return     the object read by the {@code ContentHandler} that is
+     *                 the first match of the suggested types.
+     *                 null if none of the requested  are supported.
+     * @exception  IOException  if an I/O error occurs while reading the object.
+     * @since 1.3
+     */
+    @SuppressWarnings("rawtypes")
+    public Object getContent(URLConnection urlc, Class[] classes) throws IOException {
+        Object obj = getContent(urlc);
+
+        for (int i = 0; i < classes.length; i++) {
+          if (classes[i].isInstance(obj)) {
+                return obj;
+          }
+        }
+        return null;
+    }
+
+}
diff --git a/java/net/ContentHandlerFactory.java b/java/net/ContentHandlerFactory.java
new file mode 100644
index 0000000..64112e3
--- /dev/null
+++ b/java/net/ContentHandlerFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for content handlers. An
+ * implementation of this interface should map a MIME type into an
+ * instance of {@code ContentHandler}.
+ * <p>
+ * This interface is used by the {@code URLStreamHandler} class
+ * to create a {@code ContentHandler} for a MIME type.
+ *
+ * @author  James Gosling
+ * @see     java.net.ContentHandler
+ * @see     java.net.URLStreamHandler
+ * @since   JDK1.0
+ */
+public interface ContentHandlerFactory {
+    /**
+     * Creates a new {@code ContentHandler} to read an object from
+     * a {@code URLStreamHandler}.
+     *
+     * @param   mimetype   the MIME type for which a content handler is desired.
+
+     * @return  a new {@code ContentHandler} to read an object from a
+     *          {@code URLStreamHandler}.
+     * @see     java.net.ContentHandler
+     * @see     java.net.URLStreamHandler
+     */
+    ContentHandler createContentHandler(String mimetype);
+}
diff --git a/java/net/CookieHandler.java b/java/net/CookieHandler.java
new file mode 100644
index 0000000..ef91d00
--- /dev/null
+++ b/java/net/CookieHandler.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.Map;
+import java.util.List;
+import java.io.IOException;
+import sun.security.util.SecurityConstants;
+
+/**
+ * A CookieHandler object provides a callback mechanism to hook up a
+ * HTTP state management policy implementation into the HTTP protocol
+ * handler. The HTTP state management mechanism specifies a way to
+ * create a stateful session with HTTP requests and responses.
+ *
+ * <p>A system-wide CookieHandler that to used by the HTTP protocol
+ * handler can be registered by doing a
+ * CookieHandler.setDefault(CookieHandler). The currently registered
+ * CookieHandler can be retrieved by calling
+ * CookieHandler.getDefault().
+ *
+ * For more information on HTTP state management, see <a
+ * href="http://www.ietf.org/rfc/rfc2965.txt"><i>RFC&nbsp;2965: HTTP
+ * State Management Mechanism</i></a>
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class CookieHandler {
+    /**
+     * The system-wide cookie handler that will apply cookies to the
+     * request headers and manage cookies from the response headers.
+     *
+     * @see setDefault(CookieHandler)
+     * @see getDefault()
+     */
+    private static CookieHandler cookieHandler;
+
+    /**
+     * Gets the system-wide cookie handler.
+     *
+     * @return the system-wide cookie handler; A null return means
+     *        there is no system-wide cookie handler currently set.
+     * @throws SecurityException
+     *       If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("getCookieHandler")}
+     * @see #setDefault(CookieHandler)
+     */
+    public synchronized static CookieHandler getDefault() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_COOKIEHANDLER_PERMISSION);
+        }
+        return cookieHandler;
+    }
+
+    /**
+     * Sets (or unsets) the system-wide cookie handler.
+     *
+     * Note: non-standard http protocol handlers may ignore this setting.
+     *
+     * @param cHandler The HTTP cookie handler, or
+     *       {@code null} to unset.
+     * @throws SecurityException
+     *       If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("setCookieHandler")}
+     * @see #getDefault()
+     */
+    public synchronized static void setDefault(CookieHandler cHandler) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.SET_COOKIEHANDLER_PERMISSION);
+        }
+        cookieHandler = cHandler;
+    }
+
+    /**
+     * Gets all the applicable cookies from a cookie cache for the
+     * specified uri in the request header.
+     *
+     * <P>The {@code URI} passed as an argument specifies the intended use for
+     * the cookies. In particular the scheme should reflect whether the cookies
+     * will be sent over http, https or used in another context like javascript.
+     * The host part should reflect either the destination of the cookies or
+     * their origin in the case of javascript.</P>
+     * <P>It is up to the implementation to take into account the {@code URI} and
+     * the cookies attributes and security settings to determine which ones
+     * should be returned.</P>
+     *
+     * <P>HTTP protocol implementers should make sure that this method is
+     * called after all request headers related to choosing cookies
+     * are added, and before the request is sent.</P>
+     *
+     * @param uri a {@code URI} representing the intended use for the
+     *            cookies
+     * @param requestHeaders - a Map from request header
+     *            field names to lists of field values representing
+     *            the current request headers
+     * @return an immutable map from state management headers, with
+     *            field names "Cookie" or "Cookie2" to a list of
+     *            cookies containing state information
+     *
+     * @throws IOException if an I/O error occurs
+     * @throws IllegalArgumentException if either argument is null
+     * @see #put(URI, Map)
+     */
+    public abstract Map<String, List<String>>
+        get(URI uri, Map<String, List<String>> requestHeaders)
+        throws IOException;
+
+    /**
+     * Sets all the applicable cookies, examples are response header
+     * fields that are named Set-Cookie2, present in the response
+     * headers into a cookie cache.
+     *
+     * @param uri a {@code URI} where the cookies come from
+     * @param responseHeaders an immutable map from field names to
+     *            lists of field values representing the response
+     *            header fields returned
+     * @throws  IOException if an I/O error occurs
+     * @throws  IllegalArgumentException if either argument is null
+     * @see #get(URI, Map)
+     */
+    public abstract void
+        put(URI uri, Map<String, List<String>> responseHeaders)
+        throws IOException;
+}
diff --git a/java/net/CookieManager.java b/java/net/CookieManager.java
new file mode 100644
index 0000000..dfd3b86
--- /dev/null
+++ b/java/net/CookieManager.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.Map;
+import java.util.List;
+import java.util.Collections;
+import java.util.Comparator;
+import java.io.IOException;
+import sun.util.logging.PlatformLogger;
+
+/**
+ * CookieManager provides a concrete implementation of {@link CookieHandler},
+ * which separates the storage of cookies from the policy surrounding accepting
+ * and rejecting cookies. A CookieManager is initialized with a {@link CookieStore}
+ * which manages storage, and a {@link CookiePolicy} object, which makes
+ * policy decisions on cookie acceptance/rejection.
+ *
+ * <p> The HTTP cookie management in java.net package looks like:
+ * <blockquote>
+ * <pre>{@code
+ *                  use
+ * CookieHandler <------- HttpURLConnection
+ *       ^
+ *       | impl
+ *       |         use
+ * CookieManager -------> CookiePolicy
+ *             |   use
+ *             |--------> HttpCookie
+ *             |              ^
+ *             |              | use
+ *             |   use        |
+ *             |--------> CookieStore
+ *                            ^
+ *                            | impl
+ *                            |
+ *                  Internal in-memory implementation
+ * }</pre>
+ * <ul>
+ *   <li>
+ *     CookieHandler is at the core of cookie management. User can call
+ *     CookieHandler.setDefault to set a concrete CookieHanlder implementation
+ *     to be used.
+ *   </li>
+ *   <li>
+ *     CookiePolicy.shouldAccept will be called by CookieManager.put to see whether
+ *     or not one cookie should be accepted and put into cookie store. User can use
+ *     any of three pre-defined CookiePolicy, namely ACCEPT_ALL, ACCEPT_NONE and
+ *     ACCEPT_ORIGINAL_SERVER, or user can define his own CookiePolicy implementation
+ *     and tell CookieManager to use it.
+ *   </li>
+ *   <li>
+ *     CookieStore is the place where any accepted HTTP cookie is stored in.
+ *     If not specified when created, a CookieManager instance will use an internal
+ *     in-memory implementation. Or user can implements one and tell CookieManager
+ *     to use it.
+ *   </li>
+ *   <li>
+ *     Currently, only CookieStore.add(URI, HttpCookie) and CookieStore.get(URI)
+ *     are used by CookieManager. Others are for completeness and might be needed
+ *     by a more sophisticated CookieStore implementation, e.g. a NetscapeCookieSotre.
+ *   </li>
+ * </ul>
+ * </blockquote>
+ *
+ * <p>There're various ways user can hook up his own HTTP cookie management behavior, e.g.
+ * <blockquote>
+ * <ul>
+ *   <li>Use CookieHandler.setDefault to set a brand new {@link CookieHandler} implementation
+ *   <li>Let CookieManager be the default {@link CookieHandler} implementation,
+ *       but implement user's own {@link CookieStore} and {@link CookiePolicy}
+ *       and tell default CookieManager to use them:
+ *     <blockquote><pre>
+ *       // this should be done at the beginning of an HTTP session
+ *       CookieHandler.setDefault(new CookieManager(new MyCookieStore(), new MyCookiePolicy()));
+ *     </pre></blockquote>
+ *   <li>Let CookieManager be the default {@link CookieHandler} implementation, but
+ *       use customized {@link CookiePolicy}:
+ *     <blockquote><pre>
+ *       // this should be done at the beginning of an HTTP session
+ *       CookieHandler.setDefault(new CookieManager());
+ *       // this can be done at any point of an HTTP session
+ *       ((CookieManager)CookieHandler.getDefault()).setCookiePolicy(new MyCookiePolicy());
+ *     </pre></blockquote>
+ * </ul>
+ * </blockquote>
+ *
+ * <p>The implementation conforms to <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>, section 3.3.
+ *
+ * @see CookiePolicy
+ * @author Edward Wang
+ * @since 1.6
+ */
+public class CookieManager extends CookieHandler
+{
+    /* ---------------- Fields -------------- */
+
+    private CookiePolicy policyCallback;
+
+
+    private CookieStore cookieJar = null;
+
+
+    /* ---------------- Ctors -------------- */
+
+    /**
+     * Create a new cookie manager.
+     *
+     * <p>This constructor will create new cookie manager with default
+     * cookie store and accept policy. The effect is same as
+     * {@code CookieManager(null, null)}.
+     */
+    public CookieManager() {
+        this(null, null);
+    }
+
+
+    /**
+     * Create a new cookie manager with specified cookie store and cookie policy.
+     *
+     * @param store     a {@code CookieStore} to be used by cookie manager.
+     *                  if {@code null}, cookie manager will use a default one,
+     *                  which is an in-memory CookieStore implementation.
+     * @param cookiePolicy      a {@code CookiePolicy} instance
+     *                          to be used by cookie manager as policy callback.
+     *                          if {@code null}, ACCEPT_ORIGINAL_SERVER will
+     *                          be used.
+     */
+    public CookieManager(CookieStore store,
+                         CookiePolicy cookiePolicy)
+    {
+        // use default cookie policy if not specify one
+        policyCallback = (cookiePolicy == null) ? CookiePolicy.ACCEPT_ORIGINAL_SERVER
+                                                : cookiePolicy;
+
+        // if not specify CookieStore to use, use default one
+        if (store == null) {
+            cookieJar = new InMemoryCookieStore();
+        } else {
+            cookieJar = store;
+        }
+    }
+
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * To set the cookie policy of this cookie manager.
+     *
+     * <p> A instance of {@code CookieManager} will have
+     * cookie policy ACCEPT_ORIGINAL_SERVER by default. Users always
+     * can call this method to set another cookie policy.
+     *
+     * @param cookiePolicy      the cookie policy. Can be {@code null}, which
+     *                          has no effects on current cookie policy.
+     */
+    public void setCookiePolicy(CookiePolicy cookiePolicy) {
+        if (cookiePolicy != null) policyCallback = cookiePolicy;
+    }
+
+
+    /**
+     * To retrieve current cookie store.
+     *
+     * @return  the cookie store currently used by cookie manager.
+     */
+    public CookieStore getCookieStore() {
+        return cookieJar;
+    }
+
+
+    public Map<String, List<String>>
+        get(URI uri, Map<String, List<String>> requestHeaders)
+        throws IOException
+    {
+        // pre-condition check
+        if (uri == null || requestHeaders == null) {
+            throw new IllegalArgumentException("Argument is null");
+        }
+
+        Map<String, List<String>> cookieMap =
+                        new java.util.HashMap<String, List<String>>();
+        // if there's no default CookieStore, no way for us to get any cookie
+        if (cookieJar == null)
+            return Collections.unmodifiableMap(cookieMap);
+
+        boolean secureLink = "https".equalsIgnoreCase(uri.getScheme());
+        List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>();
+        // BEGIN Android-removed: The logic of converting null path is moved into pathMatches.
+        /*
+        String path = uri.getPath();
+        if (path == null || path.isEmpty()) {
+            path = "/";
+        }
+        */
+        // END Android-removed: The logic of converting null path is moved into pathMatches.
+        for (HttpCookie cookie : cookieJar.get(uri)) {
+            // apply path-matches rule (RFC 2965 sec. 3.3.4)
+            // and check for the possible "secure" tag (i.e. don't send
+            // 'secure' cookies over unsecure links)
+            if (pathMatches(uri, cookie) &&
+                    (secureLink || !cookie.getSecure())) {
+                // BEGIN Android-removed: App compat: b/25897688 InMemoryCookieStore ignores scheme.
+                /*
+                if (cookie.isHttpOnly()) {
+                    String s = uri.getScheme();
+                    if (!"http".equalsIgnoreCase(s) && !"https".equalsIgnoreCase(s)) {
+                        continue;
+                    }
+                }
+                */
+                // END Android-removed: App compat: b/25897688 InMemoryCookieStore ignores scheme.
+
+                // Let's check the authorize port list if it exists
+                String ports = cookie.getPortlist();
+                if (ports != null && !ports.isEmpty()) {
+                    int port = uri.getPort();
+                    if (port == -1) {
+                        port = "https".equals(uri.getScheme()) ? 443 : 80;
+                    }
+                    if (isInPortList(ports, port)) {
+                        cookies.add(cookie);
+                    }
+                } else {
+                    cookies.add(cookie);
+                }
+            }
+        }
+        // Android-added: b/25897688 A fix to return empty map if cookies list is empty
+        if (cookies.isEmpty()) {
+            return Collections.emptyMap();
+        }
+
+        // apply sort rule (RFC 2965 sec. 3.3.4)
+        List<String> cookieHeader = sortByPath(cookies);
+
+        cookieMap.put("Cookie", cookieHeader);
+        return Collections.unmodifiableMap(cookieMap);
+    }
+
+    public void
+        put(URI uri, Map<String, List<String>> responseHeaders)
+        throws IOException
+    {
+        // pre-condition check
+        if (uri == null || responseHeaders == null) {
+            throw new IllegalArgumentException("Argument is null");
+        }
+
+
+        // if there's no default CookieStore, no need to remember any cookie
+        if (cookieJar == null)
+            return;
+
+    PlatformLogger logger = PlatformLogger.getLogger("java.net.CookieManager");
+        for (String headerKey : responseHeaders.keySet()) {
+            // RFC 2965 3.2.2, key must be 'Set-Cookie2'
+            // we also accept 'Set-Cookie' here for backward compatibility
+            if (headerKey == null
+                || !(headerKey.equalsIgnoreCase("Set-Cookie2")
+                     || headerKey.equalsIgnoreCase("Set-Cookie")
+                    )
+                )
+            {
+                continue;
+            }
+
+            for (String headerValue : responseHeaders.get(headerKey)) {
+                try {
+                    List<HttpCookie> cookies;
+                    try {
+                        cookies = HttpCookie.parse(headerValue);
+                    } catch (IllegalArgumentException e) {
+                        // Bogus header, make an empty list and log the error
+                        cookies = java.util.Collections.emptyList();
+                        if (logger.isLoggable(PlatformLogger.Level.SEVERE)) {
+                            logger.severe("Invalid cookie for " + uri + ": " + headerValue);
+                        }
+                    }
+                    for (HttpCookie cookie : cookies) {
+                        if (cookie.getPath() == null) {
+                            // If no path is specified, then by default
+                            // the path is the directory of the page/doc
+                            String path = uri.getPath();
+                            if (!path.endsWith("/")) {
+                                int i = path.lastIndexOf("/");
+                                if (i > 0) {
+                                    path = path.substring(0, i + 1);
+                                } else {
+                                    path = "/";
+                                }
+                            }
+                            cookie.setPath(path);
+                        // Android-added: b/25763487 A fix to verify cookie URI before removal
+                        } else {
+                            // Validate existing path
+                            if (!pathMatches(uri, cookie)) {
+                                continue;
+                            }
+                        }
+
+                        // As per RFC 2965, section 3.3.1:
+                        // Domain  Defaults to the effective request-host.  (Note that because
+                        // there is no dot at the beginning of effective request-host,
+                        // the default Domain can only domain-match itself.)
+                        if (cookie.getDomain() == null) {
+                            String host = uri.getHost();
+                            if (host != null && !host.contains("."))
+                                host += ".local";
+                            cookie.setDomain(host);
+                        }
+                        String ports = cookie.getPortlist();
+                        if (ports != null) {
+                            int port = uri.getPort();
+                            if (port == -1) {
+                                port = "https".equals(uri.getScheme()) ? 443 : 80;
+                            }
+                            if (ports.isEmpty()) {
+                                // Empty port list means this should be restricted
+                                // to the incoming URI port
+                                cookie.setPortlist("" + port );
+                                if (shouldAcceptInternal(uri, cookie)) {
+                                    cookieJar.add(uri, cookie);
+                                }
+                            } else {
+                                // Only store cookies with a port list
+                                // IF the URI port is in that list, as per
+                                // RFC 2965 section 3.3.2
+                                if (isInPortList(ports, port) &&
+                                        shouldAcceptInternal(uri, cookie)) {
+                                    cookieJar.add(uri, cookie);
+                                }
+                            }
+                        } else {
+                            if (shouldAcceptInternal(uri, cookie)) {
+                                cookieJar.add(uri, cookie);
+                            }
+                        }
+                    }
+                } catch (IllegalArgumentException e) {
+                    // invalid set-cookie header string
+                    // no-op
+                }
+            }
+        }
+    }
+
+
+    /* ---------------- Private operations -------------- */
+
+    // to determine whether or not accept this cookie
+    private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) {
+        try {
+            return policyCallback.shouldAccept(uri, cookie);
+        } catch (Exception ignored) { // pretect against malicious callback
+            return false;
+        }
+    }
+
+
+    static private boolean isInPortList(String lst, int port) {
+        int i = lst.indexOf(",");
+        int val = -1;
+        while (i > 0) {
+            try {
+                val = Integer.parseInt(lst.substring(0, i));
+                if (val == port) {
+                    return true;
+                }
+            } catch (NumberFormatException numberFormatException) {
+            }
+            lst = lst.substring(i+1);
+            i = lst.indexOf(",");
+        }
+        if (!lst.isEmpty()) {
+            try {
+                val = Integer.parseInt(lst);
+                if (val == port) {
+                    return true;
+                }
+            } catch (NumberFormatException numberFormatException) {
+            }
+        }
+        return false;
+    }
+
+    // Android-changed: b/25763487 Cookie path matching logic in OpenJDK was wrong
+    /**
+     * Return true iff. the path from {@code cookie} matches the path from {@code uri}.
+     */
+    private static boolean pathMatches(URI uri, HttpCookie cookie) {
+        return normalizePath(uri.getPath()).startsWith(normalizePath(cookie.getPath()));
+    }
+
+    private static String normalizePath(String path) {
+        if (path == null) {
+            path = "";
+        }
+
+        if (!path.endsWith("/")) {
+            path = path + "/";
+        }
+
+        return path;
+    }
+
+
+    /*
+     * sort cookies with respect to their path: those with more specific Path attributes
+     * precede those with less specific, as defined in RFC 2965 sec. 3.3.4
+     */
+    private List<String> sortByPath(List<HttpCookie> cookies) {
+        Collections.sort(cookies, new CookiePathComparator());
+
+        // BEGIN Android-changed: Netscape cookie spec and RFC 2965 have different format
+        // of Cookie header; RFC 2965 requires a leading $Version="1" string while Netscape does not
+        // The workaround here is to add a $Version="1" string in advance
+        final StringBuilder result = new StringBuilder();
+        int minVersion = 1;
+        for (HttpCookie cookie : cookies) {
+            if (cookie.getVersion() < minVersion) {
+                minVersion = cookie.getVersion();
+            }
+        }
+
+        if (minVersion == 1) {
+            result.append("$Version=\"1\"; ");
+        }
+
+        for (int i = 0; i < cookies.size(); ++i) {
+            if (i != 0) {
+                result.append("; ");
+            }
+
+            result.append(cookies.get(i).toString());
+        }
+
+        List<String> cookieHeader = new java.util.ArrayList<String>();
+        cookieHeader.add(result.toString());
+        // END Android-changed: Netscape cookie spec and RFC 2965 have different format
+        return cookieHeader;
+    }
+
+
+    static class CookiePathComparator implements Comparator<HttpCookie> {
+        public int compare(HttpCookie c1, HttpCookie c2) {
+            if (c1 == c2) return 0;
+            if (c1 == null) return -1;
+            if (c2 == null) return 1;
+
+            // path rule only applies to the cookies with same name
+            if (!c1.getName().equals(c2.getName())) return 0;
+
+            // Android-changed: normalize before comparison
+            final String c1Path = normalizePath(c1.getPath());
+            final String c2Path = normalizePath(c2.getPath());
+
+            // those with more specific Path attributes precede those with less specific
+            if (c1Path.startsWith(c2Path))
+                return -1;
+            else if (c2Path.startsWith(c1Path))
+                return 1;
+            else
+                return 0;
+        }
+    }
+}
diff --git a/java/net/CookiePolicy.java b/java/net/CookiePolicy.java
new file mode 100644
index 0000000..8094835
--- /dev/null
+++ b/java/net/CookiePolicy.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * CookiePolicy implementations decide which cookies should be accepted
+ * and which should be rejected. Three pre-defined policy implementations
+ * are provided, namely ACCEPT_ALL, ACCEPT_NONE and ACCEPT_ORIGINAL_SERVER.
+ *
+ * <p>See RFC 2965 sec. 3.3 and 7 for more detail.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ */
+public interface CookiePolicy {
+    /**
+     * One pre-defined policy which accepts all cookies.
+     */
+    public static final CookiePolicy ACCEPT_ALL = new CookiePolicy(){
+        public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            return true;
+        }
+    };
+
+    /**
+     * One pre-defined policy which accepts no cookies.
+     */
+    public static final CookiePolicy ACCEPT_NONE = new CookiePolicy(){
+        public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            return false;
+        }
+    };
+
+    /**
+     * One pre-defined policy which only accepts cookies from original server.
+     */
+    public static final CookiePolicy ACCEPT_ORIGINAL_SERVER  = new CookiePolicy(){
+        public boolean shouldAccept(URI uri, HttpCookie cookie) {
+            if (uri == null || cookie == null)
+                return false;
+            return HttpCookie.domainMatches(cookie.getDomain(), uri.getHost());
+        }
+    };
+
+
+    /**
+     * Will be called to see whether or not this cookie should be accepted.
+     *
+     * @param uri       the URI to consult accept policy with
+     * @param cookie    the HttpCookie object in question
+     * @return          {@code true} if this cookie should be accepted;
+     *                  otherwise, {@code false}
+     */
+    public boolean shouldAccept(URI uri, HttpCookie cookie);
+}
diff --git a/java/net/CookieStore.java b/java/net/CookieStore.java
new file mode 100644
index 0000000..105cc66
--- /dev/null
+++ b/java/net/CookieStore.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A CookieStore object represents a storage for cookie. Can store and retrieve
+ * cookies.
+ *
+ * <p>{@link CookieManager} will call {@code CookieStore.add} to save cookies
+ * for every incoming HTTP response, and call {@code CookieStore.get} to
+ * retrieve cookie for every outgoing HTTP request. A CookieStore
+ * is responsible for removing HttpCookie instances which have expired.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ */
+public interface CookieStore {
+    /**
+     * Adds one HTTP cookie to the store. This is called for every
+     * incoming HTTP response.
+     *
+     * <p>A cookie to store may or may not be associated with an URI. If it
+     * is not associated with an URI, the cookie's domain and path attribute
+     * will indicate where it comes from. If it is associated with an URI and
+     * its domain and path attribute are not specified, given URI will indicate
+     * where this cookie comes from.
+     *
+     * <p>If a cookie corresponding to the given URI already exists,
+     * then it is replaced with the new one.
+     *
+     * @param uri       the uri this cookie associated with.
+     *                  if {@code null}, this cookie will not be associated
+     *                  with an URI
+     * @param cookie    the cookie to store
+     *
+     * @throws NullPointerException if {@code cookie} is {@code null}
+     *
+     * @see #get
+     *
+     */
+    public void add(URI uri, HttpCookie cookie);
+
+
+    /**
+     * Retrieve cookies associated with given URI, or whose domain matches the
+     * given URI. Only cookies that have not expired are returned.
+     * This is called for every outgoing HTTP request.
+     *
+     * @return          an immutable list of HttpCookie,
+     *                  return empty list if no cookies match the given URI
+     *
+     * @param uri       the uri associated with the cookies to be returned
+     *
+     * @throws NullPointerException if {@code uri} is {@code null}
+     *
+     * @see #add
+     *
+     */
+    public List<HttpCookie> get(URI uri);
+
+
+    /**
+     * Get all not-expired cookies in cookie store.
+     *
+     * @return          an immutable list of http cookies;
+     *                  return empty list if there's no http cookie in store
+     */
+    public List<HttpCookie> getCookies();
+
+
+    /**
+     * Get all URIs which identify the cookies in this cookie store.
+     *
+     * @return          an immutable list of URIs;
+     *                  return empty list if no cookie in this cookie store
+     *                  is associated with an URI
+     */
+    public List<URI> getURIs();
+
+
+    /**
+     * Remove a cookie from store.
+     *
+     * @param uri       the uri this cookie associated with.
+     *                  if {@code null}, the cookie to be removed is not associated
+     *                  with an URI when added; if not {@code null}, the cookie
+     *                  to be removed is associated with the given URI when added.
+     * @param cookie    the cookie to remove
+     *
+     * @return          {@code true} if this store contained the specified cookie
+     *
+     * @throws NullPointerException if {@code cookie} is {@code null}
+     */
+    public boolean remove(URI uri, HttpCookie cookie);
+
+
+    /**
+     * Remove all cookies in this cookie store.
+     *
+     * @return          {@code true} if this store changed as a result of the call
+     */
+    public boolean removeAll();
+}
diff --git a/java/net/DatagramPacket.java b/java/net/DatagramPacket.java
new file mode 100644
index 0000000..c1bd692
--- /dev/null
+++ b/java/net/DatagramPacket.java
@@ -0,0 +1,415 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This class represents a datagram packet.
+ * <p>
+ * Datagram packets are used to implement a connectionless packet
+ * delivery service. Each message is routed from one machine to
+ * another based solely on information contained within that packet.
+ * Multiple packets sent from one machine to another might be routed
+ * differently, and might arrive in any order. Packet delivery is
+ * not guaranteed.
+ *
+ * @author  Pavani Diwanji
+ * @author  Benjamin Renaud
+ * @since   JDK1.0
+ */
+public final
+class DatagramPacket {
+
+    // BEGIN Android-removed: Android doesn't need to load native net library.
+    /**
+     * Perform class initialization
+     *
+    static {
+        java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+        init();
+    }
+    */
+    // END Android-removed: Android doesn't need to load native net library.
+
+    /*
+     * The fields of this class are package-private since DatagramSocketImpl
+     * classes needs to access them.
+     */
+    byte[] buf;
+    int offset;
+    int length;
+    int bufLength;
+    InetAddress address;
+    int port;
+
+    /**
+     * Constructs a {@code DatagramPacket} for receiving packets of
+     * length {@code length}, specifying an offset into the buffer.
+     * <p>
+     * The {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * @param   buf      buffer for holding the incoming datagram.
+     * @param   offset   the offset for the buffer
+     * @param   length   the number of bytes to read.
+     *
+     * @since 1.2
+     */
+    public DatagramPacket(byte buf[], int offset, int length) {
+        setData(buf, offset, length);
+        this.address = null;
+        this.port = -1;
+    }
+
+    /**
+     * Constructs a {@code DatagramPacket} for receiving packets of
+     * length {@code length}.
+     * <p>
+     * The {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * @param   buf      buffer for holding the incoming datagram.
+     * @param   length   the number of bytes to read.
+     */
+    public DatagramPacket(byte buf[], int length) {
+        this (buf, 0, length);
+    }
+
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} with offset {@code ioffset}to the
+     * specified port number on the specified host. The
+     * {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * @param   buf      the packet data.
+     * @param   offset   the packet data offset.
+     * @param   length   the packet data length.
+     * @param   address  the destination address.
+     * @param   port     the destination port number.
+     * @see java.net.InetAddress
+     *
+     * @since 1.2
+     */
+    public DatagramPacket(byte buf[], int offset, int length,
+                          InetAddress address, int port) {
+        setData(buf, offset, length);
+        setAddress(address);
+        setPort(port);
+    }
+
+    // Android-changed: Added Android-specific notes regarding the exception signature change.
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} with offset {@code ioffset}to the
+     * specified port number on the specified host. The
+     * {@code length} argument must be less than or equal to
+     * {@code buf.length}.
+     *
+     * <p>
+     * <em>Android note</em>: Up to and including API 25 this method declared that a SocketException
+     * can be thrown, although the exception is never thrown. Code compiled against a newer SDK does
+     * not need to catch the exception and will be binary compatible with older versions of Android.
+     *
+     * @param   buf      the packet data.
+     * @param   offset   the packet data offset.
+     * @param   length   the packet data length.
+     * @param   address  the destination socket address.
+     * @throws  IllegalArgumentException if address type is not supported
+     * @see java.net.InetAddress
+     *
+     * @since 1.4
+     */
+    public DatagramPacket(byte buf[], int offset, int length, SocketAddress address) {
+        setData(buf, offset, length);
+        setSocketAddress(address);
+    }
+
+    // Android-changed: Added Android-specific notes regarding the exception signature change.
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} to the specified port number on the specified
+     * host. The {@code length} argument must be less than or equal
+     * to {@code buf.length}.
+     *
+     * <p>
+     * <em>Android note</em>: Up to and including API 25 this method declared that a SocketException
+     * can be thrown, although the exception is never thrown. Code compiled against a newer SDK does
+     * not need to catch the exception and will be binary compatible with older versions of Android.
+     *
+     * @param   buf      the packet data.
+     * @param   length   the packet length.
+     * @param   address  the destination address.
+     * @param   port     the destination port number.
+     * @see     java.net.InetAddress
+     */
+    public DatagramPacket(byte buf[], int length,
+                          InetAddress address, int port) {
+        this(buf, 0, length, address, port);
+    }
+
+    /**
+     * Constructs a datagram packet for sending packets of length
+     * {@code length} to the specified port number on the specified
+     * host. The {@code length} argument must be less than or equal
+     * to {@code buf.length}.
+     *
+     * @param   buf      the packet data.
+     * @param   length   the packet length.
+     * @param   address  the destination address.
+     * @throws  IllegalArgumentException if address type is not supported
+     * @since 1.4
+     * @see     java.net.InetAddress
+     */
+    public DatagramPacket(byte buf[], int length, SocketAddress address) {
+        this(buf, 0, length, address);
+    }
+
+    /**
+     * Returns the IP address of the machine to which this datagram is being
+     * sent or from which the datagram was received.
+     *
+     * @return  the IP address of the machine to which this datagram is being
+     *          sent or from which the datagram was received.
+     * @see     java.net.InetAddress
+     * @see #setAddress(java.net.InetAddress)
+     */
+    public synchronized InetAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Returns the port number on the remote host to which this datagram is
+     * being sent or from which the datagram was received.
+     *
+     * @return  the port number on the remote host to which this datagram is
+     *          being sent or from which the datagram was received.
+     * @see #setPort(int)
+     */
+    public synchronized int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns the data buffer. The data received or the data to be sent
+     * starts from the {@code offset} in the buffer,
+     * and runs for {@code length} long.
+     *
+     * @return  the buffer used to receive or  send data
+     * @see #setData(byte[], int, int)
+     */
+    public synchronized byte[] getData() {
+        return buf;
+    }
+
+    /**
+     * Returns the offset of the data to be sent or the offset of the
+     * data received.
+     *
+     * @return  the offset of the data to be sent or the offset of the
+     *          data received.
+     *
+     * @since 1.2
+     */
+    public synchronized int getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns the length of the data to be sent or the length of the
+     * data received.
+     *
+     * @return  the length of the data to be sent or the length of the
+     *          data received.
+     * @see #setLength(int)
+     */
+    public synchronized int getLength() {
+        return length;
+    }
+
+    /**
+     * Set the data buffer for this packet. This sets the
+     * data, length and offset of the packet.
+     *
+     * @param buf the buffer to set for this packet
+     *
+     * @param offset the offset into the data
+     *
+     * @param length the length of the data
+     *       and/or the length of the buffer used to receive data
+     *
+     * @exception NullPointerException if the argument is null
+     *
+     * @see #getData
+     * @see #getOffset
+     * @see #getLength
+     *
+     * @since 1.2
+     */
+    public synchronized void setData(byte[] buf, int offset, int length) {
+        /* this will check to see if buf is null */
+        if (length < 0 || offset < 0 ||
+            (length + offset) < 0 ||
+            ((length + offset) > buf.length)) {
+            throw new IllegalArgumentException("illegal length or offset");
+        }
+        this.buf = buf;
+        this.length = length;
+        this.bufLength = length;
+        this.offset = offset;
+    }
+
+    /**
+     * Sets the IP address of the machine to which this datagram
+     * is being sent.
+     * @param iaddr the {@code InetAddress}
+     * @since   JDK1.1
+     * @see #getAddress()
+     */
+    public synchronized void setAddress(InetAddress iaddr) {
+        address = iaddr;
+    }
+
+    // BEGIN Android-changed
+    /**
+     * Sets 'length' without changing 'userSuppliedLength', after receiving a packet.
+     * @hide for IoBridge
+     */
+    public void setReceivedLength(int length) {
+        this.length = length;
+    }
+    // END Android-changed
+
+    /**
+     * Sets the port number on the remote host to which this datagram
+     * is being sent.
+     * @param iport the port number
+     * @since   JDK1.1
+     * @see #getPort()
+     */
+    public synchronized void setPort(int iport) {
+        if (iport < 0 || iport > 0xFFFF) {
+            throw new IllegalArgumentException("Port out of range:"+ iport);
+        }
+        port = iport;
+    }
+
+    /**
+     * Sets the SocketAddress (usually IP address + port number) of the remote
+     * host to which this datagram is being sent.
+     *
+     * @param address the {@code SocketAddress}
+     * @throws  IllegalArgumentException if address is null or is a
+     *          SocketAddress subclass not supported by this socket
+     *
+     * @since 1.4
+     * @see #getSocketAddress
+     */
+    public synchronized void setSocketAddress(SocketAddress address) {
+        if (address == null || !(address instanceof InetSocketAddress))
+            throw new IllegalArgumentException("unsupported address type");
+        InetSocketAddress addr = (InetSocketAddress) address;
+        if (addr.isUnresolved())
+            throw new IllegalArgumentException("unresolved address");
+        setAddress(addr.getAddress());
+        setPort(addr.getPort());
+    }
+
+    /**
+     * Gets the SocketAddress (usually IP address + port number) of the remote
+     * host that this packet is being sent to or is coming from.
+     *
+     * @return the {@code SocketAddress}
+     * @since 1.4
+     * @see #setSocketAddress
+     */
+    public synchronized SocketAddress getSocketAddress() {
+        return new InetSocketAddress(getAddress(), getPort());
+    }
+
+    /**
+     * Set the data buffer for this packet. With the offset of
+     * this DatagramPacket set to 0, and the length set to
+     * the length of {@code buf}.
+     *
+     * @param buf the buffer to set for this packet.
+     *
+     * @exception NullPointerException if the argument is null.
+     *
+     * @see #getLength
+     * @see #getData
+     *
+     * @since JDK1.1
+     */
+    public synchronized void setData(byte[] buf) {
+        if (buf == null) {
+            throw new NullPointerException("null packet buffer");
+        }
+        this.buf = buf;
+        this.offset = 0;
+        this.length = buf.length;
+        this.bufLength = buf.length;
+    }
+
+    /**
+     * Set the length for this packet. The length of the packet is
+     * the number of bytes from the packet's data buffer that will be
+     * sent, or the number of bytes of the packet's data buffer that
+     * will be used for receiving data. The length must be lesser or
+     * equal to the offset plus the length of the packet's buffer.
+     *
+     * @param length the length to set for this packet.
+     *
+     * @exception IllegalArgumentException if the length is negative
+     * of if the length is greater than the packet's data buffer
+     * length.
+     *
+     * @see #getLength
+     * @see #setData
+     *
+     * @since JDK1.1
+     */
+    public synchronized void setLength(int length) {
+        if ((length + offset) > buf.length || length < 0 ||
+            (length + offset) < 0) {
+            throw new IllegalArgumentException("illegal length");
+        }
+        this.length = length;
+        this.bufLength = this.length;
+    }
+
+    // Android-removed: JNI has been removed
+    // /**
+    //  * Perform class load-time initializations.
+    //  */
+    // private native static void init();
+}
diff --git a/java/net/DatagramSocket.annotated.java b/java/net/DatagramSocket.annotated.java
new file mode 100644
index 0000000..b462769
--- /dev/null
+++ b/java/net/DatagramSocket.annotated.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.nio.channels.DatagramChannel;
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class DatagramSocket implements java.io.Closeable {
+
+public DatagramSocket() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+protected DatagramSocket(java.net.DatagramSocketImpl impl) { throw new RuntimeException("Stub!"); }
+
+public DatagramSocket(java.net.SocketAddress bindaddr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public DatagramSocket(int port) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public DatagramSocket(int port, java.net.InetAddress laddr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void bind(java.net.SocketAddress addr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.InetAddress address, int port) { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.SocketAddress addr) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void disconnect() { throw new RuntimeException("Stub!"); }
+
+public boolean isBound() { throw new RuntimeException("Stub!"); }
+
+public boolean isConnected() { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+public int getPort() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getRemoteSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getLocalSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public void send(java.net.DatagramPacket p) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void receive(java.net.DatagramPacket p) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSoTimeout(int timeout) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSoTimeout() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSendBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSendBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReceiveBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getReceiveBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReuseAddress(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean getReuseAddress() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setBroadcast(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean getBroadcast() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setTrafficClass(int tc) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getTrafficClass() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void close() { throw new RuntimeException("Stub!"); }
+
+public boolean isClosed() { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.DatagramChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setDatagramSocketImplFactory(java.net.DatagramSocketImplFactory fac) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.io.FileDescriptor getFileDescriptor$() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/DatagramSocket.java b/java/net/DatagramSocket.java
new file mode 100644
index 0000000..3e3faf7
--- /dev/null
+++ b/java/net/DatagramSocket.java
@@ -0,0 +1,1358 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import static android.system.OsConstants.SOL_SOCKET;
+import static android.system.OsConstants.SO_BINDTODEVICE;
+
+import android.system.ErrnoException;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.channels.DatagramChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import libcore.io.Libcore;
+
+/**
+ * This class represents a socket for sending and receiving datagram packets.
+ *
+ * <p>A datagram socket is the sending or receiving point for a packet
+ * delivery service. Each packet sent or received on a datagram socket
+ * is individually addressed and routed. Multiple packets sent from
+ * one machine to another may be routed differently, and may arrive in
+ * any order.
+ *
+ * <p> Where possible, a newly constructed {@code DatagramSocket} has the
+ * {@link SocketOptions#SO_BROADCAST SO_BROADCAST} socket option enabled so as
+ * to allow the transmission of broadcast datagrams. In order to receive
+ * broadcast packets a DatagramSocket should be bound to the wildcard address.
+ * In some implementations, broadcast packets may also be received when
+ * a DatagramSocket is bound to a more specific address.
+ * <p>
+ * Example:
+ * {@code
+ *              DatagramSocket s = new DatagramSocket(null);
+ *              s.bind(new InetSocketAddress(8888));
+ * }
+ * Which is equivalent to:
+ * {@code
+ *              DatagramSocket s = new DatagramSocket(8888);
+ * }
+ * Both cases will create a DatagramSocket able to receive broadcasts on
+ * UDP port 8888.
+ *
+ * @author  Pavani Diwanji
+ * @see     java.net.DatagramPacket
+ * @see     java.nio.channels.DatagramChannel
+ * @since JDK1.0
+ */
+public
+class DatagramSocket implements java.io.Closeable {
+    /**
+     * Various states of this socket.
+     */
+    private boolean created = false;
+    private boolean bound = false;
+    private boolean closed = false;
+    private Object closeLock = new Object();
+
+    /*
+     * The implementation of this DatagramSocket.
+     */
+    DatagramSocketImpl impl;
+
+    /**
+     * Are we using an older DatagramSocketImpl?
+     */
+    boolean oldImpl = false;
+
+    /**
+     * Set when a socket is ST_CONNECTED until we are certain
+     * that any packets which might have been received prior
+     * to calling connect() but not read by the application
+     * have been read. During this time we check the source
+     * address of all packets received to be sure they are from
+     * the connected destination. Other packets are read but
+     * silently dropped.
+     */
+    private boolean explicitFilter = false;
+    private int bytesLeftToFilter;
+    /*
+     * Connection state:
+     * ST_NOT_CONNECTED = socket not connected
+     * ST_CONNECTED = socket connected
+     * ST_CONNECTED_NO_IMPL = socket connected but not at impl level
+     */
+    static final int ST_NOT_CONNECTED = 0;
+    static final int ST_CONNECTED = 1;
+    static final int ST_CONNECTED_NO_IMPL = 2;
+
+    int connectState = ST_NOT_CONNECTED;
+
+    /*
+     * Connected address & port
+     */
+    InetAddress connectedAddress = null;
+    int connectedPort = -1;
+
+    // Android-added: Store pending exception from connect
+    private SocketException pendingConnectException;
+
+    /**
+     * Connects this socket to a remote socket address (IP address + port number).
+     * Binds socket if not already bound.
+     * <p>
+     * @param   address The remote address.
+     * @param   port    The remote port
+     * @throws  SocketException if binding the socket fails.
+     */
+    private synchronized void connectInternal(InetAddress address, int port) throws SocketException {
+        if (port < 0 || port > 0xFFFF) {
+            throw new IllegalArgumentException("connect: " + port);
+        }
+        if (address == null) {
+            throw new IllegalArgumentException("connect: null address");
+        }
+        checkAddress (address, "connect");
+        if (isClosed())
+            return;
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            if (address.isMulticastAddress()) {
+                security.checkMulticast(address);
+            } else {
+                security.checkConnect(address.getHostAddress(), port);
+                security.checkAccept(address.getHostAddress(), port);
+            }
+        }
+
+        if (!isBound())
+          bind(new InetSocketAddress(0));
+
+        // Android-changed: This section now throws any SocketException generated by connect()
+        // to enable it to be recorded as the pendingConnectException. It has been enclosed in a
+        // try-finally to ensure connectedAddress and connectedPort are set when the exception
+        // is thrown.
+        try {
+            // old impls do not support connect/disconnect
+            // Android-changed: Added special handling for AbstractPlainDatagramSocketImpl in
+            // the condition below.
+            if (oldImpl || (impl instanceof AbstractPlainDatagramSocketImpl &&
+                    ((AbstractPlainDatagramSocketImpl)impl).nativeConnectDisabled())) {
+                connectState = ST_CONNECTED_NO_IMPL;
+            } else {
+                try {
+                    getImpl().connect(address, port);
+
+                    // socket is now connected by the impl
+                    connectState = ST_CONNECTED;
+
+                    // Do we need to filter some packets?
+                    int avail = getImpl().dataAvailable();
+                    if (avail == -1) {
+                        throw new SocketException();
+                    }
+                    explicitFilter = avail > 0;
+                    if (explicitFilter) {
+                        bytesLeftToFilter = getReceiveBufferSize();
+                    }
+                } catch (SocketException se) {
+                    // connection will be emulated by DatagramSocket
+                    connectState = ST_CONNECTED_NO_IMPL;
+                    // Android-changed: Propagate the SocketException so connect() can store it.
+                    throw se;
+                }
+           }
+        } finally {
+            connectedAddress = address;
+            connectedPort = port;
+        }
+    }
+
+
+    /**
+     * Constructs a datagram socket and binds it to any available port
+     * on the local host machine.  The socket will be bound to the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address,
+     * an IP address chosen by the kernel.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with 0 as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     */
+    public DatagramSocket() throws SocketException {
+        this(new InetSocketAddress(0));
+    }
+
+    /**
+     * Creates an unbound datagram socket with the specified
+     * DatagramSocketImpl.
+     *
+     * @param impl an instance of a <B>DatagramSocketImpl</B>
+     *        the subclass wishes to use on the DatagramSocket.
+     * @since   1.4
+     */
+    protected DatagramSocket(DatagramSocketImpl impl) {
+        if (impl == null)
+            throw new NullPointerException();
+        this.impl = impl;
+        checkOldImpl();
+    }
+
+    /**
+     * Creates a datagram socket, bound to the specified local
+     * socket address.
+     * <p>
+     * If, if the address is {@code null}, creates an unbound socket.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the port from the socket address
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param bindaddr local socket address to bind, or {@code null}
+     *                 for an unbound socket.
+     *
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     * @since   1.4
+     */
+    public DatagramSocket(SocketAddress bindaddr) throws SocketException {
+        // create a datagram socket.
+        createImpl();
+        if (bindaddr != null) {
+            try {
+                bind(bindaddr);
+            } finally {
+                if (!isBound())
+                    close();
+            }
+        }
+    }
+
+    /**
+     * Constructs a datagram socket and binds it to the specified port
+     * on the local host machine.  The socket will be bound to the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address,
+     * an IP address chosen by the kernel.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      port port to use.
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     */
+    public DatagramSocket(int port) throws SocketException {
+        this(port, null);
+    }
+
+    /**
+     * Creates a datagram socket, bound to the specified local
+     * address.  The local port must be between 0 and 65535 inclusive.
+     * If the IP address is 0.0.0.0, the socket will be bound to the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address,
+     * an IP address chosen by the kernel.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param port local port to use
+     * @param laddr local address to bind
+     *
+     * @exception  SocketException  if the socket could not be opened,
+     *               or the socket could not bind to the specified local port.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkListen
+     * @since   JDK1.1
+     */
+    public DatagramSocket(int port, InetAddress laddr) throws SocketException {
+        this(new InetSocketAddress(laddr, port));
+    }
+
+    private void checkOldImpl() {
+        if (impl == null)
+            return;
+        // DatagramSocketImpl.peekdata() is a protected method, therefore we need to use
+        // getDeclaredMethod, therefore we need permission to access the member
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws NoSuchMethodException {
+                        Class<?>[] cl = new Class<?>[1];
+                        cl[0] = DatagramPacket.class;
+                        impl.getClass().getDeclaredMethod("peekData", cl);
+                        return null;
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            oldImpl = true;
+        }
+    }
+
+    static Class<?> implClass = null;
+
+    void createImpl() throws SocketException {
+        if (impl == null) {
+            if (factory != null) {
+                impl = factory.createDatagramSocketImpl();
+                checkOldImpl();
+            } else {
+                boolean isMulticast = (this instanceof MulticastSocket) ? true : false;
+                impl = DefaultDatagramSocketImplFactory.createDatagramSocketImpl(isMulticast);
+
+                checkOldImpl();
+            }
+        }
+        // creates a udp socket
+        impl.create();
+        impl.setDatagramSocket(this);
+        created = true;
+    }
+
+    /**
+     * Get the {@code DatagramSocketImpl} attached to this socket,
+     * creating it if necessary.
+     *
+     * @return  the {@code DatagramSocketImpl} attached to that
+     *          DatagramSocket
+     * @throws SocketException if creation fails.
+     * @since 1.4
+     */
+    DatagramSocketImpl getImpl() throws SocketException {
+        if (!created)
+            createImpl();
+        return impl;
+    }
+
+    /**
+     * Binds this DatagramSocket to a specific address and port.
+     * <p>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     *<p>
+     * @param   addr The address and port to bind to.
+     * @throws  SocketException if any error happens during the bind, or if the
+     *          socket is already bound.
+     * @throws  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @throws IllegalArgumentException if addr is a SocketAddress subclass
+     *         not supported by this socket.
+     * @since 1.4
+     */
+    public synchronized void bind(SocketAddress addr) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (isBound())
+            throw new SocketException("already bound");
+        if (addr == null)
+            addr = new InetSocketAddress(0);
+        if (!(addr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type!");
+        InetSocketAddress epoint = (InetSocketAddress) addr;
+        if (epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        InetAddress iaddr = epoint.getAddress();
+        int port = epoint.getPort();
+        checkAddress(iaddr, "bind");
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            sec.checkListen(port);
+        }
+        try {
+            getImpl().bind(port, iaddr);
+        } catch (SocketException e) {
+            getImpl().close();
+            throw e;
+        }
+        bound = true;
+    }
+
+    void checkAddress (InetAddress addr, String op) {
+        if (addr == null) {
+            return;
+        }
+        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
+            throw new IllegalArgumentException(op + ": invalid address type");
+        }
+    }
+
+    /**
+     * Connects the socket to a remote address for this socket. When a
+     * socket is connected to a remote address, packets may only be
+     * sent to or received from that address. By default a datagram
+     * socket is not connected.
+     *
+     * <p>If the remote destination to which the socket is connected does not
+     * exist, or is otherwise unreachable, and if an ICMP destination unreachable
+     * packet has been received for that address, then a subsequent call to
+     * send or receive may throw a PortUnreachableException. Note, there is no
+     * guarantee that the exception will be thrown.
+     *
+     * <p> If a security manager has been installed then it is invoked to check
+     * access to the remote address. Specifically, if the given {@code address}
+     * is a {@link InetAddress#isMulticastAddress multicast address},
+     * the security manager's {@link
+     * java.lang.SecurityManager#checkMulticast(InetAddress)
+     * checkMulticast} method is invoked with the given {@code address}.
+     * Otherwise, the security manager's {@link
+     * java.lang.SecurityManager#checkConnect(String,int) checkConnect}
+     * and {@link java.lang.SecurityManager#checkAccept checkAccept} methods
+     * are invoked, with the given {@code address} and {@code port}, to
+     * verify that datagrams are permitted to be sent and received
+     * respectively.
+     *
+     * <p> When a socket is connected, {@link #receive receive} and
+     * {@link #send send} <b>will not perform any security checks</b>
+     * on incoming and outgoing packets, other than matching the packet's
+     * and the socket's address and port. On a send operation, if the
+     * packet's address is set and the packet's address and the socket's
+     * address do not match, an {@code IllegalArgumentException} will be
+     * thrown. A socket connected to a multicast address may only be used
+     * to send packets.
+     *
+     * @param address the remote address for the socket
+     *
+     * @param port the remote port for the socket.
+     *
+     * @throws IllegalArgumentException
+     *         if the address is null, or the port is out of range.
+     *
+     * @throws SecurityException
+     *         if a security manager has been installed and it does
+     *         not permit access to the given remote address
+     *
+     * @see #disconnect
+     */
+    public void connect(InetAddress address, int port) {
+        try {
+            connectInternal(address, port);
+        } catch (SocketException se) {
+            // Android-changed: this method can't throw checked SocketException. Throw it later
+            // throw new Error("connect failed", se);
+            // TODO: or just use SneakyThrow? There's a clear API bug here.
+            pendingConnectException = se;
+        }
+    }
+
+    /**
+     * Connects this socket to a remote socket address (IP address + port number).
+     *
+     * <p> If given an {@link InetSocketAddress InetSocketAddress}, this method
+     * behaves as if invoking {@link #connect(InetAddress,int) connect(InetAddress,int)}
+     * with the the given socket addresses IP address and port number.
+     *
+     * @param   addr    The remote address.
+     *
+     * @throws  SocketException
+     *          if the connect fails
+     *
+     * @throws IllegalArgumentException
+     *         if {@code addr} is {@code null}, or {@code addr} is a SocketAddress
+     *         subclass not supported by this socket
+     *
+     * @throws SecurityException
+     *         if a security manager has been installed and it does
+     *         not permit access to the given remote address
+     *
+     * @since 1.4
+     */
+    public void connect(SocketAddress addr) throws SocketException {
+        if (addr == null)
+            throw new IllegalArgumentException("Address can't be null");
+        if (!(addr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) addr;
+        if (epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        connectInternal(epoint.getAddress(), epoint.getPort());
+    }
+
+    /**
+     * Disconnects the socket. If the socket is closed or not connected,
+     * then this method has no effect.
+     *
+     * @see #connect
+     */
+    public void disconnect() {
+        synchronized (this) {
+            if (isClosed())
+                return;
+            if (connectState == ST_CONNECTED) {
+                impl.disconnect ();
+            }
+            connectedAddress = null;
+            connectedPort = -1;
+            connectState = ST_NOT_CONNECTED;
+            explicitFilter = false;
+        }
+    }
+
+    /**
+     * Returns the binding state of the socket.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return {@code true}
+     * after the socket is closed.
+     *
+     * @return true if the socket successfully bound to an address
+     * @since 1.4
+     */
+    public boolean isBound() {
+        return bound;
+    }
+
+    /**
+     * Returns the connection state of the socket.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return {@code true}
+     * after the socket is closed.
+     *
+     * @return true if the socket successfully connected to a server
+     * @since 1.4
+     */
+    public boolean isConnected() {
+        return connectState != ST_NOT_CONNECTED;
+    }
+
+    /**
+     * Returns the address to which this socket is connected. Returns
+     * {@code null} if the socket is not connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+     * @return the address to which this socket is connected.
+     */
+    public InetAddress getInetAddress() {
+        return connectedAddress;
+    }
+
+    /**
+     * Returns the port number to which this socket is connected.
+     * Returns {@code -1} if the socket is not connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected port number
+     * after the socket is closed.
+     *
+     * @return the port number to which this socket is connected.
+     */
+    public int getPort() {
+        return connectedPort;
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is connected to, or
+     * {@code null} if it is unconnected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+     * @return a {@code SocketAddress} representing the remote
+     *         endpoint of this socket, or {@code null} if it is
+     *         not connected yet.
+     * @see #getInetAddress()
+     * @see #getPort()
+     * @see #connect(SocketAddress)
+     * @since 1.4
+     */
+    public SocketAddress getRemoteSocketAddress() {
+        if (!isConnected())
+            return null;
+        return new InetSocketAddress(getInetAddress(), getPort());
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is bound to.
+     *
+     * @return a {@code SocketAddress} representing the local endpoint of this
+     *         socket, or {@code null} if it is closed or not bound yet.
+     * @see #getLocalAddress()
+     * @see #getLocalPort()
+     * @see #bind(SocketAddress)
+     * @since 1.4
+     */
+
+    public SocketAddress getLocalSocketAddress() {
+        if (isClosed())
+            return null;
+        if (!isBound())
+            return null;
+        return new InetSocketAddress(getLocalAddress(), getLocalPort());
+    }
+
+    /**
+     * Sends a datagram packet from this socket. The
+     * {@code DatagramPacket} includes information indicating the
+     * data to be sent, its length, the IP address of the remote host,
+     * and the port number on the remote host.
+     *
+     * <p>If there is a security manager, and the socket is not currently
+     * connected to a remote address, this method first performs some
+     * security checks. First, if {@code p.getAddress().isMulticastAddress()}
+     * is true, this method calls the
+     * security manager's {@code checkMulticast} method
+     * with {@code p.getAddress()} as its argument.
+     * If the evaluation of that expression is false,
+     * this method instead calls the security manager's
+     * {@code checkConnect} method with arguments
+     * {@code p.getAddress().getHostAddress()} and
+     * {@code p.getPort()}. Each call to a security manager method
+     * could result in a SecurityException if the operation is not allowed.
+     *
+     * @param      p   the {@code DatagramPacket} to be sent.
+     *
+     * @exception  IOException  if an I/O error occurs.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkMulticast} or {@code checkConnect}
+     *             method doesn't allow the send.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *             to a currently unreachable destination. Note, there is no
+     *             guarantee that the exception will be thrown.
+     * @exception  java.nio.channels.IllegalBlockingModeException
+     *             if this socket has an associated channel,
+     *             and the channel is in non-blocking mode.
+     * @exception  IllegalArgumentException if the socket is connected,
+     *             and connected address and packet address differ.
+     *
+     * @see        java.net.DatagramPacket
+     * @see        SecurityManager#checkMulticast(InetAddress)
+     * @see        SecurityManager#checkConnect
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void send(DatagramPacket p) throws IOException  {
+        InetAddress packetAddress = null;
+        synchronized (p) {
+            // BEGIN Android-changed
+            if (pendingConnectException != null) {
+                throw new SocketException("Pending connect failure", pendingConnectException);
+            }
+            // END Android-changed
+            if (isClosed())
+                throw new SocketException("Socket is closed");
+            checkAddress (p.getAddress(), "send");
+            if (connectState == ST_NOT_CONNECTED) {
+                // check the address is ok wiht the security manager on every send.
+                SecurityManager security = System.getSecurityManager();
+
+                // The reason you want to synchronize on datagram packet
+                // is because you don't want an applet to change the address
+                // while you are trying to send the packet for example
+                // after the security check but before the send.
+                if (security != null) {
+                    if (p.getAddress().isMulticastAddress()) {
+                        security.checkMulticast(p.getAddress());
+                    } else {
+                        security.checkConnect(p.getAddress().getHostAddress(),
+                                              p.getPort());
+                    }
+                }
+            } else {
+                // we're connected
+                packetAddress = p.getAddress();
+                if (packetAddress == null) {
+                    p.setAddress(connectedAddress);
+                    p.setPort(connectedPort);
+                } else if ((!packetAddress.equals(connectedAddress)) ||
+                           p.getPort() != connectedPort) {
+                    throw new IllegalArgumentException("connected address " +
+                                                       "and packet address" +
+                                                       " differ");
+                }
+            }
+            // Check whether the socket is bound
+            if (!isBound())
+                bind(new InetSocketAddress(0));
+            // call the  method to send
+            getImpl().send(p);
+        }
+    }
+
+    /**
+     * Receives a datagram packet from this socket. When this method
+     * returns, the {@code DatagramPacket}'s buffer is filled with
+     * the data received. The datagram packet also contains the sender's
+     * IP address, and the port number on the sender's machine.
+     * <p>
+     * This method blocks until a datagram is received. The
+     * {@code length} field of the datagram packet object contains
+     * the length of the received message. If the message is longer than
+     * the packet's length, the message is truncated.
+     * <p>
+     * If there is a security manager, a packet cannot be received if the
+     * security manager's {@code checkAccept} method
+     * does not allow it.
+     *
+     * @param      p   the {@code DatagramPacket} into which to place
+     *                 the incoming data.
+     * @exception  IOException  if an I/O error occurs.
+     * @exception  SocketTimeoutException  if setSoTimeout was previously called
+     *                 and the timeout has expired.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *             to a currently unreachable destination. Note, there is no guarantee that the
+     *             exception will be thrown.
+     * @exception  java.nio.channels.IllegalBlockingModeException
+     *             if this socket has an associated channel,
+     *             and the channel is in non-blocking mode.
+     * @see        java.net.DatagramPacket
+     * @see        java.net.DatagramSocket
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public synchronized void receive(DatagramPacket p) throws IOException {
+        synchronized (p) {
+            if (!isBound())
+                bind(new InetSocketAddress(0));
+
+            // BEGIN Android-changed
+            if (pendingConnectException != null) {
+                throw new SocketException("Pending connect failure", pendingConnectException);
+            }
+            // END Android-changed
+
+            if (connectState == ST_NOT_CONNECTED) {
+                // check the address is ok with the security manager before every recv.
+                SecurityManager security = System.getSecurityManager();
+                if (security != null) {
+                    while(true) {
+                        String peekAd = null;
+                        int peekPort = 0;
+                        // peek at the packet to see who it is from.
+                        if (!oldImpl) {
+                            // We can use the new peekData() API
+                            DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
+                            peekPort = getImpl().peekData(peekPacket);
+                            peekAd = peekPacket.getAddress().getHostAddress();
+                        } else {
+                            InetAddress adr = new InetAddress();
+                            peekPort = getImpl().peek(adr);
+                            peekAd = adr.getHostAddress();
+                        }
+                        try {
+                            security.checkAccept(peekAd, peekPort);
+                            // security check succeeded - so now break
+                            // and recv the packet.
+                            break;
+                        } catch (SecurityException se) {
+                            // Throw away the offending packet by consuming
+                            // it in a tmp buffer.
+                            DatagramPacket tmp = new DatagramPacket(new byte[1], 1);
+                            getImpl().receive(tmp);
+
+                            // silently discard the offending packet
+                            // and continue: unknown/malicious
+                            // entities on nets should not make
+                            // runtime throw security exception and
+                            // disrupt the applet by sending random
+                            // datagram packets.
+                            continue;
+                        }
+                    } // end of while
+                }
+            }
+            DatagramPacket tmp = null;
+            if ((connectState == ST_CONNECTED_NO_IMPL) || explicitFilter) {
+                // We have to do the filtering the old fashioned way since
+                // the native impl doesn't support connect or the connect
+                // via the impl failed, or .. "explicitFilter" may be set when
+                // a socket is connected via the impl, for a period of time
+                // when packets from other sources might be queued on socket.
+                boolean stop = false;
+                while (!stop) {
+                    InetAddress peekAddress = null;
+                    int peekPort = -1;
+                    // peek at the packet to see who it is from.
+                    if (!oldImpl) {
+                        // We can use the new peekData() API
+                        DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
+                        peekPort = getImpl().peekData(peekPacket);
+                        peekAddress = peekPacket.getAddress();
+                    } else {
+                        // this api only works for IPv4
+                        peekAddress = new InetAddress();
+                        peekPort = getImpl().peek(peekAddress);
+                    }
+                    if ((!connectedAddress.equals(peekAddress)) ||
+                        (connectedPort != peekPort)) {
+                        // throw the packet away and silently continue
+                        tmp = new DatagramPacket(
+                                                new byte[1024], 1024);
+                        getImpl().receive(tmp);
+                        if (explicitFilter) {
+                            if (checkFiltering(tmp)) {
+                                stop = true;
+                            }
+                        }
+                    } else {
+                        stop = true;
+                    }
+                }
+            }
+            // If the security check succeeds, or the datagram is
+            // connected then receive the packet
+            getImpl().receive(p);
+            if (explicitFilter && tmp == null) {
+                // packet was not filtered, account for it here
+                checkFiltering(p);
+            }
+        }
+    }
+
+    private boolean checkFiltering(DatagramPacket p) throws SocketException {
+        bytesLeftToFilter -= p.getLength();
+        if (bytesLeftToFilter <= 0 || getImpl().dataAvailable() <= 0) {
+            explicitFilter = false;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Gets the local address to which the socket is bound.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is first called
+     * with the host address and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     *
+     * @see SecurityManager#checkConnect
+     * @return  the local address to which the socket is bound,
+     *          {@code null} if the socket is closed, or
+     *          an {@code InetAddress} representing
+     *          {@link InetAddress#isAnyLocalAddress wildcard}
+     *          address if either the socket is not bound, or
+     *          the security manager {@code checkConnect}
+     *          method does not allow the operation
+     * @since   1.1
+     */
+    public InetAddress getLocalAddress() {
+        if (isClosed())
+            return null;
+        InetAddress in = null;
+        try {
+            in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+            if (in.isAnyLocalAddress()) {
+                in = InetAddress.anyLocalAddress();
+            }
+            SecurityManager s = System.getSecurityManager();
+            if (s != null) {
+                s.checkConnect(in.getHostAddress(), -1);
+            }
+        } catch (Exception e) {
+            in = InetAddress.anyLocalAddress(); // "0.0.0.0"
+        }
+        return in;
+    }
+
+    /**
+     * Returns the port number on the local host to which this socket
+     * is bound.
+     *
+     * @return  the port number on the local host to which this socket is bound,
+                {@code -1} if the socket is closed, or
+                {@code 0} if it is not bound yet.
+     */
+    public int getLocalPort() {
+        if (isClosed())
+            return -1;
+        try {
+            return getImpl().getLocalPort();
+        } catch (Exception e) {
+            return 0;
+        }
+    }
+
+    /** Enable/disable SO_TIMEOUT with the specified timeout, in
+     *  milliseconds. With this option set to a non-zero timeout,
+     *  a call to receive() for this DatagramSocket
+     *  will block for only this amount of time.  If the timeout expires,
+     *  a <B>java.net.SocketTimeoutException</B> is raised, though the
+     *  DatagramSocket is still valid.  The option <B>must</B> be enabled
+     *  prior to entering the blocking operation to have effect.  The
+     *  timeout must be {@code > 0}.
+     *  A timeout of zero is interpreted as an infinite timeout.
+     *
+     * @param timeout the specified timeout in milliseconds.
+     * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
+     * @since   JDK1.1
+     * @see #getSoTimeout()
+     */
+    public synchronized void setSoTimeout(int timeout) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    }
+
+    /**
+     * Retrieve setting for SO_TIMEOUT.  0 returns implies that the
+     * option is disabled (i.e., timeout of infinity).
+     *
+     * @return the setting for SO_TIMEOUT
+     * @throws SocketException if there is an error in the underlying protocol, such as an UDP error.
+     * @since   JDK1.1
+     * @see #setSoTimeout(int)
+     */
+    public synchronized int getSoTimeout() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (getImpl() == null)
+            return 0;
+        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+        /* extra type safety */
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the SO_SNDBUF option to the specified value for this
+     * {@code DatagramSocket}. The SO_SNDBUF option is used by the
+     * network implementation as a hint to size the underlying
+     * network I/O buffers. The SO_SNDBUF setting may also be used
+     * by the network implementation to determine the maximum size
+     * of the packet that can be sent on this socket.
+     * <p>
+     * As SO_SNDBUF is a hint, applications that want to verify
+     * what size the buffer is should call {@link #getSendBufferSize()}.
+     * <p>
+     * Increasing the buffer size may allow multiple outgoing packets
+     * to be queued by the network implementation when the send rate
+     * is high.
+     * <p>
+     * Note: If {@link #send(DatagramPacket)} is used to send a
+     * {@code DatagramPacket} that is larger than the setting
+     * of SO_SNDBUF then it is implementation specific if the
+     * packet is sent or discarded.
+     *
+     * @param size the size to which to set the send buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as an UDP error.
+     * @exception IllegalArgumentException if the value is 0 or is
+     * negative.
+     * @see #getSendBufferSize()
+     */
+    public synchronized void setSendBufferSize(int size)
+    throws SocketException{
+        if (!(size > 0)) {
+            throw new IllegalArgumentException("negative send size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
+    }
+
+    /**
+     * Get value of the SO_SNDBUF option for this {@code DatagramSocket}, that is the
+     * buffer size used by the platform for output on this {@code DatagramSocket}.
+     *
+     * @return the value of the SO_SNDBUF option for this {@code DatagramSocket}
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as an UDP error.
+     * @see #setSendBufferSize
+     */
+    public synchronized int getSendBufferSize() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Sets the SO_RCVBUF option to the specified value for this
+     * {@code DatagramSocket}. The SO_RCVBUF option is used by the
+     * the network implementation as a hint to size the underlying
+     * network I/O buffers. The SO_RCVBUF setting may also be used
+     * by the network implementation to determine the maximum size
+     * of the packet that can be received on this socket.
+     * <p>
+     * Because SO_RCVBUF is a hint, applications that want to
+     * verify what size the buffers were set to should call
+     * {@link #getReceiveBufferSize()}.
+     * <p>
+     * Increasing SO_RCVBUF may allow the network implementation
+     * to buffer multiple packets when packets arrive faster than
+     * are being received using {@link #receive(DatagramPacket)}.
+     * <p>
+     * Note: It is implementation specific if a packet larger
+     * than SO_RCVBUF can be received.
+     *
+     * @param size the size to which to set the receive buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as an UDP error.
+     * @exception IllegalArgumentException if the value is 0 or is
+     * negative.
+     * @see #getReceiveBufferSize()
+     */
+    public synchronized void setReceiveBufferSize(int size)
+    throws SocketException{
+        if (size <= 0) {
+            throw new IllegalArgumentException("invalid receive size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+    }
+
+    /**
+     * Get value of the SO_RCVBUF option for this {@code DatagramSocket}, that is the
+     * buffer size used by the platform for input on this {@code DatagramSocket}.
+     *
+     * @return the value of the SO_RCVBUF option for this {@code DatagramSocket}
+     * @exception SocketException if there is an error in the underlying protocol, such as an UDP error.
+     * @see #setReceiveBufferSize(int)
+     */
+    public synchronized int getReceiveBufferSize()
+    throws SocketException{
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Enable/disable the SO_REUSEADDR socket option.
+     * <p>
+     * For UDP sockets it may be necessary to bind more than one
+     * socket to the same socket address. This is typically for the
+     * purpose of receiving multicast packets
+     * (See {@link java.net.MulticastSocket}). The
+     * {@code SO_REUSEADDR} socket option allows multiple
+     * sockets to be bound to the same socket address if the
+     * {@code SO_REUSEADDR} socket option is enabled prior
+     * to binding the socket using {@link #bind(SocketAddress)}.
+     * <p>
+     * Note: This functionality is not supported by all existing platforms,
+     * so it is implementation specific whether this option will be ignored
+     * or not. However, if it is not supported then
+     * {@link #getReuseAddress()} will always return {@code false}.
+     * <p>
+     * When a {@code DatagramSocket} is created the initial setting
+     * of {@code SO_REUSEADDR} is disabled.
+     * <p>
+     * The behaviour when {@code SO_REUSEADDR} is enabled or
+     * disabled after a socket is bound (See {@link #isBound()})
+     * is not defined.
+     *
+     * @param on  whether to enable or disable the
+     * @exception SocketException if an error occurs enabling or
+     *            disabling the {@code SO_RESUEADDR} socket option,
+     *            or the socket is closed.
+     * @since 1.4
+     * @see #getReuseAddress()
+     * @see #bind(SocketAddress)
+     * @see #isBound()
+     * @see #isClosed()
+     */
+    public synchronized void setReuseAddress(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        // Integer instead of Boolean for compatibility with older DatagramSocketImpl
+        if (oldImpl)
+            getImpl().setOption(SocketOptions.SO_REUSEADDR, new Integer(on?-1:0));
+        else
+            getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if SO_REUSEADDR is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not SO_REUSEADDR is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as an UDP error.
+     * @since   1.4
+     * @see #setReuseAddress(boolean)
+     */
+    public synchronized boolean getReuseAddress() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_REUSEADDR);
+        return ((Boolean)o).booleanValue();
+    }
+
+    /**
+     * Enable/disable SO_BROADCAST.
+     *
+     * <p> Some operating systems may require that the Java virtual machine be
+     * started with implementation specific privileges to enable this option or
+     * send broadcast datagrams.
+     *
+     * @param  on
+     *         whether or not to have broadcast turned on.
+     *
+     * @throws  SocketException
+     *          if there is an error in the underlying protocol, such as an UDP
+     *          error.
+     *
+     * @since 1.4
+     * @see #getBroadcast()
+     */
+    public synchronized void setBroadcast(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_BROADCAST, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if SO_BROADCAST is enabled.
+     * @return a {@code boolean} indicating whether or not SO_BROADCAST is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as an UDP error.
+     * @since 1.4
+     * @see #setBroadcast(boolean)
+     */
+    public synchronized boolean getBroadcast() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean)(getImpl().getOption(SocketOptions.SO_BROADCAST))).booleanValue();
+    }
+
+    /**
+     * Sets traffic class or type-of-service octet in the IP
+     * datagram header for datagrams sent from this DatagramSocket.
+     * As the underlying network implementation may ignore this
+     * value applications should consider it a hint.
+     *
+     * <P> The tc <B>must</B> be in the range {@code 0 <= tc <=
+     * 255} or an IllegalArgumentException will be thrown.
+     * <p>Notes:
+     * <p>For Internet Protocol v4 the value consists of an
+     * {@code integer}, the least significant 8 bits of which
+     * represent the value of the TOS octet in IP packets sent by
+     * the socket.
+     * RFC 1349 defines the TOS values as follows:
+     *
+     * <UL>
+     * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
+     * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
+     * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
+     * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
+     * </UL>
+     * The last low order bit is always ignored as this
+     * corresponds to the MBZ (must be zero) bit.
+     * <p>
+     * Setting bits in the precedence field may result in a
+     * SocketException indicating that the operation is not
+     * permitted.
+     * <p>
+     * for Internet Protocol v6 {@code tc} is the value that
+     * would be placed into the sin6_flowinfo field of the IP header.
+     *
+     * @param tc        an {@code int} value for the bitset.
+     * @throws SocketException if there is an error setting the
+     * traffic class or type-of-service
+     * @since 1.4
+     * @see #getTrafficClass
+     */
+    public synchronized void setTrafficClass(int tc) throws SocketException {
+        if (tc < 0 || tc > 255)
+            throw new IllegalArgumentException("tc is not in range 0 -- 255");
+
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        try {
+            getImpl().setOption(SocketOptions.IP_TOS, tc);
+        } catch (SocketException se) {
+            // not supported if socket already connected
+            // Solaris returns error in such cases
+            if(!isConnected())
+                throw se;
+        }
+    }
+
+    /**
+     * Gets traffic class or type-of-service in the IP datagram
+     * header for packets sent from this DatagramSocket.
+     * <p>
+     * As the underlying network implementation may ignore the
+     * traffic class or type-of-service set using {@link #setTrafficClass(int)}
+     * this method may return a different value than was previously
+     * set using the {@link #setTrafficClass(int)} method on this
+     * DatagramSocket.
+     *
+     * @return the traffic class or type-of-service already set
+     * @throws SocketException if there is an error obtaining the
+     * traffic class or type-of-service value.
+     * @since 1.4
+     * @see #setTrafficClass(int)
+     */
+    public synchronized int getTrafficClass() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Integer)(getImpl().getOption(SocketOptions.IP_TOS))).intValue();
+    }
+
+    /**
+     * Closes this datagram socket.
+     * <p>
+     * Any thread currently blocked in {@link #receive} upon this socket
+     * will throw a {@link SocketException}.
+     *
+     * <p> If this socket has an associated channel then the channel is closed
+     * as well.
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() {
+        synchronized(closeLock) {
+            if (isClosed())
+                return;
+            impl.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Returns whether the socket is closed or not.
+     *
+     * @return true if the socket has been closed
+     * @since 1.4
+     */
+    public boolean isClosed() {
+        synchronized(closeLock) {
+            return closed;
+        }
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.DatagramChannel} object
+     * associated with this datagram socket, if any.
+     *
+     * <p> A datagram socket will have a channel if, and only if, the channel
+     * itself was created via the {@link java.nio.channels.DatagramChannel#open
+     * DatagramChannel.open} method.
+     *
+     * @return  the datagram channel associated with this datagram socket,
+     *          or {@code null} if this socket was not created for a channel
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public DatagramChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * User defined factory for all datagram sockets.
+     */
+    static DatagramSocketImplFactory factory;
+
+    /**
+     * Sets the datagram socket implementation factory for the
+     * application. The factory can be specified only once.
+     * <p>
+     * When an application creates a new datagram socket, the socket
+     * implementation factory's {@code createDatagramSocketImpl} method is
+     * called to create the actual datagram socket implementation.
+     * <p>
+     * Passing {@code null} to the method is a no-op unless the factory
+     * was already set.
+     *
+     * <p>If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  IOException  if an I/O error occurs when setting the
+     *              datagram socket factory.
+     * @exception  SocketException  if the factory is already defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the
+     operation.
+     * @see
+     java.net.DatagramSocketImplFactory#createDatagramSocketImpl()
+     * @see       SecurityManager#checkSetFactory
+     * @since 1.3
+     */
+    public static synchronized void
+    setDatagramSocketImplFactory(DatagramSocketImplFactory fac)
+       throws IOException
+    {
+        if (factory != null) {
+            throw new SocketException("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    // Android-added: for testing and internal use.
+    /**
+     * @hide internal use only
+     */
+    public FileDescriptor getFileDescriptor$() {
+        return impl.fd;
+    }
+
+}
diff --git a/java/net/DatagramSocketImpl.java b/java/net/DatagramSocketImpl.java
new file mode 100644
index 0000000..537edfe
--- /dev/null
+++ b/java/net/DatagramSocketImpl.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+/**
+ * Abstract datagram and multicast socket implementation base class.
+ * @author Pavani Diwanji
+ * @since  JDK1.1
+ */
+
+public abstract class DatagramSocketImpl implements SocketOptions {
+
+    /**
+     * The local port number.
+     */
+    protected int localPort;
+
+    /**
+     * The file descriptor object.
+     */
+    protected FileDescriptor fd;
+
+    int dataAvailable() {
+        // default impl returns zero, which disables the calling
+        // functionality
+        return 0;
+    }
+
+    /**
+     * The DatagramSocket or MulticastSocket
+     * that owns this impl
+     */
+    DatagramSocket socket;
+
+    void setDatagramSocket(DatagramSocket socket) {
+        this.socket = socket;
+    }
+
+    DatagramSocket getDatagramSocket() {
+        return socket;
+    }
+
+    /**
+     * Creates a datagram socket.
+     * @exception SocketException if there is an error in the
+     * underlying protocol, such as a TCP error.
+     */
+    protected abstract void create() throws SocketException;
+
+    /**
+     * Binds a datagram socket to a local port and address.
+     * @param lport the local port
+     * @param laddr the local address
+     * @exception SocketException if there is an error in the
+     * underlying protocol, such as a TCP error.
+     */
+    protected abstract void bind(int lport, InetAddress laddr) throws SocketException;
+
+    /**
+     * Sends a datagram packet. The packet contains the data and the
+     * destination address to send the packet to.
+     * @param p the packet to be sent.
+     * @exception IOException if an I/O exception occurs while sending the
+     * datagram packet.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     * to a currently unreachable destination. Note, there is no guarantee that
+     * the exception will be thrown.
+     */
+    protected abstract void send(DatagramPacket p) throws IOException;
+
+    /**
+     * Connects a datagram socket to a remote destination. This associates the remote
+     * address with the local socket so that datagrams may only be sent to this destination
+     * and received from this destination. This may be overridden to call a native
+     * system connect.
+     *
+     * <p>If the remote destination to which the socket is connected does not
+     * exist, or is otherwise unreachable, and if an ICMP destination unreachable
+     * packet has been received for that address, then a subsequent call to
+     * send or receive may throw a PortUnreachableException.
+     * Note, there is no guarantee that the exception will be thrown.
+     * @param address the remote InetAddress to connect to
+     * @param port the remote port number
+     * @exception   SocketException may be thrown if the socket cannot be
+     * connected to the remote destination
+     * @since 1.4
+     */
+    protected void connect(InetAddress address, int port) throws SocketException {}
+
+    /**
+     * Disconnects a datagram socket from its remote destination.
+     * @since 1.4
+     */
+    protected void disconnect() {}
+
+    /**
+     * Peek at the packet to see who it is from. Updates the specified {@code InetAddress}
+     * to the address which the packet came from.
+     * @param i an InetAddress object
+     * @return the port number which the packet came from.
+     * @exception IOException if an I/O exception occurs
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *       to a currently unreachable destination. Note, there is no guarantee that the
+     *       exception will be thrown.
+     */
+    protected abstract int peek(InetAddress i) throws IOException;
+
+    /**
+     * Peek at the packet to see who it is from. The data is copied into the specified
+     * {@code DatagramPacket}. The data is returned,
+     * but not consumed, so that a subsequent peekData/receive operation
+     * will see the same data.
+     * @param p the Packet Received.
+     * @return the port number which the packet came from.
+     * @exception IOException if an I/O exception occurs
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *       to a currently unreachable destination. Note, there is no guarantee that the
+     *       exception will be thrown.
+     * @since 1.4
+     */
+    protected abstract int peekData(DatagramPacket p) throws IOException;
+    /**
+     * Receive the datagram packet.
+     * @param p the Packet Received.
+     * @exception IOException if an I/O exception occurs
+     * while receiving the datagram packet.
+     * @exception  PortUnreachableException may be thrown if the socket is connected
+     *       to a currently unreachable destination. Note, there is no guarantee that the
+     *       exception will be thrown.
+     */
+    protected abstract void receive(DatagramPacket p) throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl a byte specifying the TTL value
+     *
+     * @deprecated use setTimeToLive instead.
+     * @exception IOException if an I/O exception occurs while setting
+     * the time-to-live option.
+     * @see #getTTL()
+     */
+    @Deprecated
+    protected abstract void setTTL(byte ttl) throws IOException;
+
+    /**
+     * Retrieve the TTL (time-to-live) option.
+     *
+     * @exception IOException if an I/O exception occurs
+     * while retrieving the time-to-live option
+     * @deprecated use getTimeToLive instead.
+     * @return a byte representing the TTL value
+     * @see #setTTL(byte)
+     */
+    @Deprecated
+    protected abstract byte getTTL() throws IOException;
+
+    /**
+     * Set the TTL (time-to-live) option.
+     * @param ttl an {@code int} specifying the time-to-live value
+     * @exception IOException if an I/O exception occurs
+     * while setting the time-to-live option.
+     * @see #getTimeToLive()
+     */
+    protected abstract void setTimeToLive(int ttl) throws IOException;
+
+    /**
+     * Retrieve the TTL (time-to-live) option.
+     * @exception IOException if an I/O exception occurs
+     * while retrieving the time-to-live option
+     * @return an {@code int} representing the time-to-live value
+     * @see #setTimeToLive(int)
+     */
+    protected abstract int getTimeToLive() throws IOException;
+
+    /**
+     * Join the multicast group.
+     * @param inetaddr multicast address to join.
+     * @exception IOException if an I/O exception occurs
+     * while joining the multicast group.
+     */
+    protected abstract void join(InetAddress inetaddr) throws IOException;
+
+    /**
+     * Leave the multicast group.
+     * @param inetaddr multicast address to leave.
+     * @exception IOException if an I/O exception occurs
+     * while leaving the multicast group.
+     */
+    protected abstract void leave(InetAddress inetaddr) throws IOException;
+
+    /**
+     * Join the multicast group.
+     * @param mcastaddr address to join.
+     * @param netIf specifies the local interface to receive multicast
+     *        datagram packets
+     * @throws IOException if an I/O exception occurs while joining
+     * the multicast group
+     * @since 1.4
+     */
+    protected abstract void joinGroup(SocketAddress mcastaddr,
+                                      NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Leave the multicast group.
+     * @param mcastaddr address to leave.
+     * @param netIf specified the local interface to leave the group at
+     * @throws IOException if an I/O exception occurs while leaving
+     * the multicast group
+     * @since 1.4
+     */
+    protected abstract void leaveGroup(SocketAddress mcastaddr,
+                                       NetworkInterface netIf)
+        throws IOException;
+
+    /**
+     * Close the socket.
+     */
+    protected abstract void close();
+
+    /**
+     * Gets the local port.
+     * @return an {@code int} representing the local port value
+     */
+    protected int getLocalPort() {
+        return localPort;
+    }
+
+    <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (name == StandardSocketOptions.SO_SNDBUF) {
+            setOption(SocketOptions.SO_SNDBUF, value);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            setOption(SocketOptions.SO_RCVBUF, value);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            setOption(SocketOptions.IP_TOS, value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            setOption(SocketOptions.IP_MULTICAST_IF2, value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            if (! (value instanceof Integer)) {
+                throw new IllegalArgumentException("not an integer");
+            }
+            setTimeToLive((Integer)value);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            setOption(SocketOptions.IP_MULTICAST_LOOP, value);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == StandardSocketOptions.SO_SNDBUF) {
+            return (T) getOption(SocketOptions.SO_SNDBUF);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            return (T) getOption(SocketOptions.SO_RCVBUF);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            return (T) getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            return (T) getOption(SocketOptions.IP_TOS);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_IF &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            return (T) getOption(SocketOptions.IP_MULTICAST_IF2);
+        } else if (name == StandardSocketOptions.IP_MULTICAST_TTL &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            Integer ttl = getTimeToLive();
+            return (T)ttl;
+        } else if (name == StandardSocketOptions.IP_MULTICAST_LOOP &&
+            (getDatagramSocket() instanceof MulticastSocket)) {
+            return (T) getOption(SocketOptions.IP_MULTICAST_LOOP);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    /**
+     * Gets the datagram socket file descriptor.
+     * @return a {@code FileDescriptor} object representing the datagram socket
+     * file descriptor
+     */
+    protected FileDescriptor getFileDescriptor() {
+        return fd;
+    }
+}
diff --git a/java/net/DatagramSocketImplFactory.java b/java/net/DatagramSocketImplFactory.java
new file mode 100644
index 0000000..4d89196
--- /dev/null
+++ b/java/net/DatagramSocketImplFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for datagram socket implementations. It
+ * is used by the classes {@code DatagramSocket} to create actual socket
+ * implementations.
+ *
+ * @author  Yingxian Wang
+ * @see     java.net.DatagramSocket
+ * @since   1.3
+ */
+public
+interface DatagramSocketImplFactory {
+    /**
+     * Creates a new {@code DatagramSocketImpl} instance.
+     *
+     * @return  a new instance of {@code DatagramSocketImpl}.
+     * @see     java.net.DatagramSocketImpl
+     */
+    DatagramSocketImpl createDatagramSocketImpl();
+}
diff --git a/java/net/DefaultDatagramSocketImplFactory.java b/java/net/DefaultDatagramSocketImplFactory.java
new file mode 100644
index 0000000..ad62c58
--- /dev/null
+++ b/java/net/DefaultDatagramSocketImplFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2007,2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import java.security.AccessController;
+
+/**
+ * This class defines a factory for creating DatagramSocketImpls. It defaults
+ * to creating plain DatagramSocketImpls, but may create other DatagramSocketImpls
+ * by setting the impl.prefix system property.
+ *
+ * @author Chris Hegarty
+ */
+
+class DefaultDatagramSocketImplFactory {
+    static Class<?> prefixImplClass = null;
+
+    static {
+        String prefix = null;
+        try {
+            prefix = AccessController.doPrivileged(
+                new sun.security.action.GetPropertyAction("impl.prefix", null));
+            if (prefix != null)
+                prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl");
+        } catch (Exception e) {
+            System.err.println("Can't find class: java.net." +
+                                prefix +
+                                "DatagramSocketImpl: check impl.prefix property");
+            //prefixImplClass = null;
+        }
+    }
+
+    /**
+     * Creates a new <code>DatagramSocketImpl</code> instance.
+     *
+     * @param   isMulticast     true if this impl if for a MutlicastSocket
+     * @return  a new instance of a <code>DatagramSocketImpl</code>.
+     */
+    static DatagramSocketImpl createDatagramSocketImpl(boolean isMulticast /*unused on unix*/)
+        throws SocketException {
+        if (prefixImplClass != null) {
+            try {
+                return (DatagramSocketImpl)prefixImplClass.newInstance();
+            } catch (Exception e) {
+                throw new SocketException("can't instantiate DatagramSocketImpl");
+            }
+        } else {
+            return new java.net.PlainDatagramSocketImpl();
+        }
+    }
+}
diff --git a/java/net/DefaultFileNameMap.java b/java/net/DefaultFileNameMap.java
new file mode 100644
index 0000000..da67d14
--- /dev/null
+++ b/java/net/DefaultFileNameMap.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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.net;
+
+import libcore.content.type.MimeMap;
+
+/**
+ * Implements {@link FileNameMap} in terms of {@link MimeMap}.
+ */
+class DefaultFileNameMap implements FileNameMap {
+
+    public String getContentTypeFor(String filename) {
+        int fragmentIndex = filename.indexOf('#');
+        if (fragmentIndex >= 0) {
+            filename = filename.substring(0, fragmentIndex);
+        }
+        if (filename.endsWith("/")) { // a directory
+            return "text/html";
+        }
+
+        int slashIndex = filename.lastIndexOf('/');
+        if (slashIndex >= 0) {
+            filename = filename.substring(slashIndex);
+        }
+
+        MimeMap mimeMap = MimeMap.getDefault();
+        int dotIndex = -1;
+        do {
+            String ext = filename.substring(dotIndex + 1);
+            String result = mimeMap.guessMimeTypeFromExtension(ext);
+            if ((result != null) &&
+                    // Compat behavior: If there's a '/', then extension must not be the
+                    // whole string. http://b/144977800
+                    (slashIndex < 0 || dotIndex >= 0)) {
+                return result;
+            }
+            dotIndex = filename.indexOf('.', dotIndex + 1);
+        } while (dotIndex >= 0);
+        return null;
+    }
+}
diff --git a/java/net/DefaultInterface.java b/java/net/DefaultInterface.java
new file mode 100644
index 0000000..0c31cb6
--- /dev/null
+++ b/java/net/DefaultInterface.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Choose a network interface to be the default for
+ * outgoing IPv6 traffic that does not specify a scope_id (and which needs one).
+ *
+ * Platforms that do not require a default interface may return null
+ * which is what this implementation does.
+ */
+
+class DefaultInterface {
+
+    static NetworkInterface getDefault() {
+        return null;
+    }
+}
diff --git a/java/net/FileNameMap.java b/java/net/FileNameMap.java
new file mode 100644
index 0000000..393b5aa
--- /dev/null
+++ b/java/net/FileNameMap.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * A simple interface which provides a mechanism to map
+ * between a file name and a MIME type string.
+ *
+ * @author  Steven B. Byrne
+ * @since   JDK1.1
+ */
+public interface FileNameMap {
+
+    /**
+     * Gets the MIME type for the specified file name.
+     * @param fileName the specified file name
+     * @return a {@code String} indicating the MIME
+     * type for the specified file name.
+     */
+    public String getContentTypeFor(String fileName);
+}
diff --git a/java/net/HttpCookie.java b/java/net/HttpCookie.java
new file mode 100644
index 0000000..3ff33c7
--- /dev/null
+++ b/java/net/HttpCookie.java
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import libcore.net.http.HttpDate;
+
+/**
+ * An HttpCookie object represents an HTTP cookie, which carries state
+ * information between server and user agent. Cookie is widely adopted
+ * to create stateful sessions.
+ *
+ * <p> There are 3 HTTP cookie specifications:
+ * <blockquote>
+ *   Netscape draft<br>
+ *   RFC 2109 - <a href="http://www.ietf.org/rfc/rfc2109.txt">
+ * <i>http://www.ietf.org/rfc/rfc2109.txt</i></a><br>
+ *   RFC 2965 - <a href="http://www.ietf.org/rfc/rfc2965.txt">
+ * <i>http://www.ietf.org/rfc/rfc2965.txt</i></a>
+ * </blockquote>
+ *
+ * <p> HttpCookie class can accept all these 3 forms of syntax.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ */
+public final class HttpCookie implements Cloneable {
+    // BEGIN Android-added: Reserved name can't be HttpCookie name
+    private static final Set<String> RESERVED_NAMES = new HashSet<String>();
+
+    static {
+        RESERVED_NAMES.add("comment");    //           RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("commenturl"); //                     RFC 2965  RFC 6265
+        RESERVED_NAMES.add("discard");    //                     RFC 2965  RFC 6265
+        RESERVED_NAMES.add("domain");     // Netscape  RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("expires");    // Netscape
+        RESERVED_NAMES.add("httponly");   //                               RFC 6265
+        RESERVED_NAMES.add("max-age");    //           RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("path");       // Netscape  RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("port");       //                     RFC 2965  RFC 6265
+        RESERVED_NAMES.add("secure");     // Netscape  RFC 2109  RFC 2965  RFC 6265
+        RESERVED_NAMES.add("version");    //           RFC 2109  RFC 2965  RFC 6265
+    }
+    // END Android-added: Reserved name can't be HttpCookie name
+
+    // ---------------- Fields --------------
+
+    // The value of the cookie itself.
+    private final String name;  // NAME= ... "$Name" style is reserved
+    private String value;       // value of NAME
+
+    // Attributes encoded in the header's cookie fields.
+    private String comment;     // Comment=VALUE ... describes cookie's use
+    private String commentURL;  // CommentURL="http URL" ... describes cookie's use
+    private boolean toDiscard;  // Discard ... discard cookie unconditionally
+    private String domain;      // Domain=VALUE ... domain that sees cookie
+    private long maxAge = MAX_AGE_UNSPECIFIED;  // Max-Age=VALUE ... cookies auto-expire
+    private String path;        // Path=VALUE ... URLs that see the cookie
+    private String portlist;    // Port[="portlist"] ... the port cookie may be returned to
+    private boolean secure;     // Secure ... e.g. use SSL
+    private boolean httpOnly;   // HttpOnly ... i.e. not accessible to scripts
+    private int version = 1;    // Version=1 ... RFC 2965 style
+
+    // The original header this cookie was consructed from, if it was
+    // constructed by parsing a header, otherwise null.
+    private final String header;
+
+    //
+    // Android-changed: Fixed units, s/seconds/milliseconds/, in comment below.
+    // Hold the creation time (in milliseconds) of the http cookie for later
+    // expiration calculation
+    private final long whenCreated;
+
+    // Since the positive and zero max-age have their meanings,
+    // this value serves as a hint as 'not specify max-age'
+    private final static long MAX_AGE_UNSPECIFIED = -1;
+
+    // BEGIN Android-removed: Use libcore.net.http.HttpDate for parsing.
+    // date formats used by Netscape's cookie draft
+    // as well as formats seen on various sites
+    /*
+    private final static String[] COOKIE_DATE_FORMATS = {
+        "EEE',' dd-MMM-yyyy HH:mm:ss 'GMT'",
+        "EEE',' dd MMM yyyy HH:mm:ss 'GMT'",
+        "EEE MMM dd yyyy HH:mm:ss 'GMT'Z",
+        "EEE',' dd-MMM-yy HH:mm:ss 'GMT'",
+        "EEE',' dd MMM yy HH:mm:ss 'GMT'",
+        "EEE MMM dd yy HH:mm:ss 'GMT'Z"
+    };
+    */
+    // END Android-removed: Use libcore.net.http.HttpDate for parsing.
+
+    // constant strings represent set-cookie header token
+    private final static String SET_COOKIE = "set-cookie:";
+    private final static String SET_COOKIE2 = "set-cookie2:";
+
+    // ---------------- Ctors --------------
+
+    /**
+     * Constructs a cookie with a specified name and value.
+     *
+     * <p> The name must conform to RFC 2965. That means it can contain
+     * only ASCII alphanumeric characters and cannot contain commas,
+     * semicolons, or white space or begin with a $ character. The cookie's
+     * name cannot be changed after creation.
+     *
+     * <p> The value can be anything the server chooses to send. Its
+     * value is probably of interest only to the server. The cookie's
+     * value can be changed after creation with the
+     * {@code setValue} method.
+     *
+     * <p> By default, cookies are created according to the RFC 2965
+     * cookie specification. The version can be changed with the
+     * {@code setVersion} method.
+     *
+     *
+     * @param  name
+     *         a {@code String} specifying the name of the cookie
+     *
+     * @param  value
+     *         a {@code String} specifying the value of the cookie
+     *
+     * @throws  IllegalArgumentException
+     *          if the cookie name contains illegal characters
+     * @throws  NullPointerException
+     *          if {@code name} is {@code null}
+     *
+     * @see #setValue
+     * @see #setVersion
+     */
+    public HttpCookie(String name, String value) {
+        this(name, value, null /*header*/);
+    }
+
+    private HttpCookie(String name, String value, String header) {
+        name = name.trim();
+        if (name.length() == 0 || !isToken(name) || name.charAt(0) == '$') {
+            throw new IllegalArgumentException("Illegal cookie name");
+        }
+
+        this.name = name;
+        this.value = value;
+        toDiscard = false;
+        secure = false;
+
+        whenCreated = System.currentTimeMillis();
+        portlist = null;
+        this.header = header;
+    }
+
+    /**
+     * Constructs cookies from set-cookie or set-cookie2 header string.
+     * RFC 2965 section 3.2.2 set-cookie2 syntax indicates that one header line
+     * may contain more than one cookie definitions, so this is a static
+     * utility method instead of another constructor.
+     *
+     * @param  header
+     *         a {@code String} specifying the set-cookie header. The header
+     *         should start with "set-cookie", or "set-cookie2" token; or it
+     *         should have no leading token at all.
+     *
+     * @return  a List of cookie parsed from header line string
+     *
+     * @throws  IllegalArgumentException
+     *          if header string violates the cookie specification's syntax or
+     *          the cookie name contains illegal characters.
+     * @throws  NullPointerException
+     *          if the header string is {@code null}
+     */
+    public static List<HttpCookie> parse(String header) {
+        return parse(header, false);
+    }
+
+    // Private version of parse() that will store the original header used to
+    // create the cookie, in the cookie itself. This can be useful for filtering
+    // Set-Cookie[2] headers, using the internal parsing logic defined in this
+    // class.
+    private static List<HttpCookie> parse(String header, boolean retainHeader) {
+
+        int version = guessCookieVersion(header);
+
+        // if header start with set-cookie or set-cookie2, strip it off
+        if (startsWithIgnoreCase(header, SET_COOKIE2)) {
+            header = header.substring(SET_COOKIE2.length());
+        } else if (startsWithIgnoreCase(header, SET_COOKIE)) {
+            header = header.substring(SET_COOKIE.length());
+        }
+
+        List<HttpCookie> cookies = new java.util.ArrayList<>();
+        // The Netscape cookie may have a comma in its expires attribute, while
+        // the comma is the delimiter in rfc 2965/2109 cookie header string.
+        // so the parse logic is slightly different
+        if (version == 0) {
+            // Netscape draft cookie
+            HttpCookie cookie = parseInternal(header, retainHeader);
+            cookie.setVersion(0);
+            cookies.add(cookie);
+        } else {
+            // rfc2965/2109 cookie
+            // if header string contains more than one cookie,
+            // it'll separate them with comma
+            List<String> cookieStrings = splitMultiCookies(header);
+            for (String cookieStr : cookieStrings) {
+                HttpCookie cookie = parseInternal(cookieStr, retainHeader);
+                cookie.setVersion(1);
+                cookies.add(cookie);
+            }
+        }
+
+        return cookies;
+    }
+
+    // ---------------- Public operations --------------
+
+    /**
+     * Reports whether this HTTP cookie has expired or not.
+     *
+     * @return  {@code true} to indicate this HTTP cookie has expired;
+     *          otherwise, {@code false}
+     */
+    public boolean hasExpired() {
+        if (maxAge == 0) return true;
+
+        // if not specify max-age, this cookie should be
+        // discarded when user agent is to be closed, but
+        // it is not expired.
+        if (maxAge == MAX_AGE_UNSPECIFIED) return false;
+
+        long deltaSecond = (System.currentTimeMillis() - whenCreated) / 1000;
+        if (deltaSecond > maxAge)
+            return true;
+        else
+            return false;
+    }
+
+    /**
+     * Specifies a comment that describes a cookie's purpose.
+     * The comment is useful if the browser presents the cookie
+     * to the user. Comments are not supported by Netscape Version 0 cookies.
+     *
+     * @param  purpose
+     *         a {@code String} specifying the comment to display to the user
+     *
+     * @see  #getComment
+     */
+    public void setComment(String purpose) {
+        comment = purpose;
+    }
+
+    /**
+     * Returns the comment describing the purpose of this cookie, or
+     * {@code null} if the cookie has no comment.
+     *
+     * @return  a {@code String} containing the comment, or {@code null} if none
+     *
+     * @see  #setComment
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Specifies a comment URL that describes a cookie's purpose.
+     * The comment URL is useful if the browser presents the cookie
+     * to the user. Comment URL is RFC 2965 only.
+     *
+     * @param  purpose
+     *         a {@code String} specifying the comment URL to display to the user
+     *
+     * @see  #getCommentURL
+     */
+    public void setCommentURL(String purpose) {
+        commentURL = purpose;
+    }
+
+    /**
+     * Returns the comment URL describing the purpose of this cookie, or
+     * {@code null} if the cookie has no comment URL.
+     *
+     * @return  a {@code String} containing the comment URL, or {@code null}
+     *          if none
+     *
+     * @see  #setCommentURL
+     */
+    public String getCommentURL() {
+        return commentURL;
+    }
+
+    /**
+     * Specify whether user agent should discard the cookie unconditionally.
+     * This is RFC 2965 only attribute.
+     *
+     * @param  discard
+     *         {@code true} indicates to discard cookie unconditionally
+     *
+     * @see  #getDiscard
+     */
+    public void setDiscard(boolean discard) {
+        toDiscard = discard;
+    }
+
+    /**
+     * Returns the discard attribute of the cookie
+     *
+     * @return  a {@code boolean} to represent this cookie's discard attribute
+     *
+     * @see  #setDiscard
+     */
+    public boolean getDiscard() {
+        return toDiscard;
+    }
+
+    /**
+     * Specify the portlist of the cookie, which restricts the port(s)
+     * to which a cookie may be sent back in a Cookie header.
+     *
+     * @param  ports
+     *         a {@code String} specify the port list, which is comma separated
+     *         series of digits
+     *
+     * @see  #getPortlist
+     */
+    public void setPortlist(String ports) {
+        portlist = ports;
+    }
+
+    /**
+     * Returns the port list attribute of the cookie
+     *
+     * @return  a {@code String} contains the port list or {@code null} if none
+     *
+     * @see  #setPortlist
+     */
+    public String getPortlist() {
+        return portlist;
+    }
+
+    /**
+     * Specifies the domain within which this cookie should be presented.
+     *
+     * <p> The form of the domain name is specified by RFC 2965. A domain
+     * name begins with a dot ({@code .foo.com}) and means that
+     * the cookie is visible to servers in a specified Domain Name System
+     * (DNS) zone (for example, {@code www.foo.com}, but not
+     * {@code a.b.foo.com}). By default, cookies are only returned
+     * to the server that sent them.
+     *
+     * @param  pattern
+     *         a {@code String} containing the domain name within which this
+     *         cookie is visible; form is according to RFC 2965
+     *
+     * @see  #getDomain
+     */
+    public void setDomain(String pattern) {
+        if (pattern != null)
+            domain = pattern.toLowerCase();
+        else
+            domain = pattern;
+    }
+
+    /**
+     * Returns the domain name set for this cookie. The form of the domain name
+     * is set by RFC 2965.
+     *
+     * @return  a {@code String} containing the domain name
+     *
+     * @see  #setDomain
+     */
+    public String getDomain() {
+        return domain;
+    }
+
+    /**
+     * Sets the maximum age of the cookie in seconds.
+     *
+     * <p> A positive value indicates that the cookie will expire
+     * after that many seconds have passed. Note that the value is
+     * the <i>maximum</i> age when the cookie will expire, not the cookie's
+     * current age.
+     *
+     * <p> A negative value means that the cookie is not stored persistently
+     * and will be deleted when the Web browser exits. A zero value causes the
+     * cookie to be deleted.
+     *
+     * @param  expiry
+     *         an integer specifying the maximum age of the cookie in seconds;
+     *         if zero, the cookie should be discarded immediately; otherwise,
+     *         the cookie's max age is unspecified.
+     *
+     * @see  #getMaxAge
+     */
+    public void setMaxAge(long expiry) {
+        maxAge = expiry;
+    }
+
+    /**
+     * Returns the maximum age of the cookie, specified in seconds. By default,
+     * {@code -1} indicating the cookie will persist until browser shutdown.
+     *
+     * @return  an integer specifying the maximum age of the cookie in seconds
+     *
+     * @see  #setMaxAge
+     */
+    public long getMaxAge() {
+        return maxAge;
+    }
+
+    /**
+     * Specifies a path for the cookie to which the client should return
+     * the cookie.
+     *
+     * <p> The cookie is visible to all the pages in the directory
+     * you specify, and all the pages in that directory's subdirectories.
+     * A cookie's path must include the servlet that set the cookie,
+     * for example, <i>/catalog</i>, which makes the cookie
+     * visible to all directories on the server under <i>/catalog</i>.
+     *
+     * <p> Consult RFC 2965 (available on the Internet) for more
+     * information on setting path names for cookies.
+     *
+     * @param  uri
+     *         a {@code String} specifying a path
+     *
+     * @see  #getPath
+     */
+    public void setPath(String uri) {
+        path = uri;
+    }
+
+    /**
+     * Returns the path on the server to which the browser returns this cookie.
+     * The cookie is visible to all subpaths on the server.
+     *
+     * @return  a {@code String} specifying a path that contains a servlet name,
+     *          for example, <i>/catalog</i>
+     *
+     * @see  #setPath
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Indicates whether the cookie should only be sent using a secure protocol,
+     * such as HTTPS or SSL.
+     *
+     * <p> The default value is {@code false}.
+     *
+     * @param  flag
+     *         If {@code true}, the cookie can only be sent over a secure
+     *         protocol like HTTPS. If {@code false}, it can be sent over
+     *         any protocol.
+     *
+     * @see  #getSecure
+     */
+    public void setSecure(boolean flag) {
+        secure = flag;
+    }
+
+    /**
+     * Returns {@code true} if sending this cookie should be restricted to a
+     * secure protocol, or {@code false} if the it can be sent using any
+     * protocol.
+     *
+     * @return  {@code false} if the cookie can be sent over any standard
+     *          protocol; otherwise, {@code true}
+     *
+     * @see  #setSecure
+     */
+    public boolean getSecure() {
+        return secure;
+    }
+
+    /**
+     * Returns the name of the cookie. The name cannot be changed after
+     * creation.
+     *
+     * @return  a {@code String} specifying the cookie's name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Assigns a new value to a cookie after the cookie is created.
+     * If you use a binary value, you may want to use BASE64 encoding.
+     *
+     * <p> With Version 0 cookies, values should not contain white space,
+     * brackets, parentheses, equals signs, commas, double quotes, slashes,
+     * question marks, at signs, colons, and semicolons. Empty values may not
+     * behave the same way on all browsers.
+     *
+     * @param  newValue
+     *         a {@code String} specifying the new value
+     *
+     * @see  #getValue
+     */
+    public void setValue(String newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Returns the value of the cookie.
+     *
+     * @return  a {@code String} containing the cookie's present value
+     *
+     * @see  #setValue
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the version of the protocol this cookie complies with. Version 1
+     * complies with RFC 2965/2109, and version 0 complies with the original
+     * cookie specification drafted by Netscape. Cookies provided by a browser
+     * use and identify the browser's cookie version.
+     *
+     * @return  0 if the cookie complies with the original Netscape
+     *          specification; 1 if the cookie complies with RFC 2965/2109
+     *
+     * @see  #setVersion
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * Sets the version of the cookie protocol this cookie complies
+     * with. Version 0 complies with the original Netscape cookie
+     * specification. Version 1 complies with RFC 2965/2109.
+     *
+     * @param  v
+     *         0 if the cookie should comply with the original Netscape
+     *         specification; 1 if the cookie should comply with RFC 2965/2109
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code v} is neither 0 nor 1
+     *
+     * @see  #getVersion
+     */
+    public void setVersion(int v) {
+        if (v != 0 && v != 1) {
+            throw new IllegalArgumentException("cookie version should be 0 or 1");
+        }
+
+        version = v;
+    }
+
+    /**
+     * Returns {@code true} if this cookie contains the <i>HttpOnly</i>
+     * attribute. This means that the cookie should not be accessible to
+     * scripting engines, like javascript.
+     *
+     * @return  {@code true} if this cookie should be considered HTTPOnly
+     *
+     * @see  #setHttpOnly(boolean)
+     */
+    public boolean isHttpOnly() {
+        return httpOnly;
+    }
+
+    /**
+     * Indicates whether the cookie should be considered HTTP Only. If set to
+     * {@code true} it means the cookie should not be accessible to scripting
+     * engines like javascript.
+     *
+     * @param  httpOnly
+     *         if {@code true} make the cookie HTTP only, i.e. only visible as
+     *         part of an HTTP request.
+     *
+     * @see  #isHttpOnly()
+     */
+    public void setHttpOnly(boolean httpOnly) {
+        this.httpOnly = httpOnly;
+    }
+
+    /**
+     * The utility method to check whether a host name is in a domain or not.
+     *
+     * <p> This concept is described in the cookie specification.
+     * To understand the concept, some terminologies need to be defined first:
+     * <blockquote>
+     * effective host name = hostname if host name contains dot<br>
+     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;or = hostname.local if not
+     * </blockquote>
+     * <p>Host A's name domain-matches host B's if:
+     * <blockquote><ul>
+     *   <li>their host name strings string-compare equal; or</li>
+     *   <li>A is a HDN string and has the form NB, where N is a non-empty
+     *   name string, B has the form .B', and B' is a HDN string.  (So,
+     *   x.y.com domain-matches .Y.com but not Y.com.)</li>
+     * </ul></blockquote>
+     *
+     * <p>A host isn't in a domain (RFC 2965 sec. 3.3.2) if:
+     * <blockquote><ul>
+     *   <li>The value for the Domain attribute contains no embedded dots,
+     *   and the value is not .local.</li>
+     *   <li>The effective host name that derives from the request-host does
+     *   not domain-match the Domain attribute.</li>
+     *   <li>The request-host is a HDN (not IP address) and has the form HD,
+     *   where D is the value of the Domain attribute, and H is a string
+     *   that contains one or more dots.</li>
+     * </ul></blockquote>
+     *
+     * <p>Examples:
+     * <blockquote><ul>
+     *   <li>A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com
+     *   would be rejected, because H is y.x and contains a dot.</li>
+     *   <li>A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com
+     *   would be accepted.</li>
+     *   <li>A Set-Cookie2 with Domain=.com or Domain=.com., will always be
+     *   rejected, because there is no embedded dot.</li>
+     *   <li>A Set-Cookie2 from request-host example for Domain=.local will
+     *   be accepted, because the effective host name for the request-
+     *   host is example.local, and example.local domain-matches .local.</li>
+     * </ul></blockquote>
+     *
+     * @param  domain
+     *         the domain name to check host name with
+     *
+     * @param  host
+     *         the host name in question
+     *
+     * @return  {@code true} if they domain-matches; {@code false} if not
+     */
+    public static boolean domainMatches(String domain, String host) {
+        if (domain == null || host == null)
+            return false;
+
+        // if there's no embedded dot in domain and domain is not .local
+        boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
+        int embeddedDotInDomain = domain.indexOf('.');
+        if (embeddedDotInDomain == 0)
+            embeddedDotInDomain = domain.indexOf('.', 1);
+        if (!isLocalDomain
+            && (embeddedDotInDomain == -1 ||
+                embeddedDotInDomain == domain.length() - 1))
+            return false;
+
+        // if the host name contains no dot and the domain name
+        // is .local or host.local
+        int firstDotInHost = host.indexOf('.');
+        if (firstDotInHost == -1 &&
+            (isLocalDomain ||
+             domain.equalsIgnoreCase(host + ".local"))) {
+            return true;
+        }
+
+        int domainLength = domain.length();
+        int lengthDiff = host.length() - domainLength;
+        if (lengthDiff == 0) {
+            // if the host name and the domain name are just string-compare euqal
+            return host.equalsIgnoreCase(domain);
+        }
+        else if (lengthDiff > 0) {
+            // need to check H & D component
+            String H = host.substring(0, lengthDiff);
+            String D = host.substring(lengthDiff);
+
+            // BEGIN Android-changed: App compat reason
+            // 1) Disregard RFC 2965 sec. 3.3.2, the "The request-host is a HDN..."
+            // 2) match "foo.local" for domain ".local".
+            // return (H.indexOf('.') == -1 && D.equalsIgnoreCase(domain));
+            return D.equalsIgnoreCase(domain) && ((domain.startsWith(".") && isFullyQualifiedDomainName(domain, 1))
+                || isLocalDomain);
+            // END Android-changed: App compat reason
+        }
+        else if (lengthDiff == -1) {
+            // if domain is actually .host
+            return (domain.charAt(0) == '.' &&
+                        host.equalsIgnoreCase(domain.substring(1)));
+        }
+
+        return false;
+    }
+
+    // BEGIN Android-added: App compat reason
+    private static boolean isFullyQualifiedDomainName(String s, int firstCharacter) {
+        int dotPosition = s.indexOf('.', firstCharacter + 1);
+        return dotPosition != -1 && dotPosition < s.length() - 1;
+    }
+    // END Android-added: App compat reason
+
+    /**
+     * Constructs a cookie header string representation of this cookie,
+     * which is in the format defined by corresponding cookie specification,
+     * but without the leading "Cookie:" token.
+     *
+     * @return  a string form of the cookie. The string has the defined format
+     */
+    @Override
+    public String toString() {
+        if (getVersion() > 0) {
+            return toRFC2965HeaderString();
+        } else {
+            return toNetscapeHeaderString();
+        }
+    }
+
+    /**
+     * Test the equality of two HTTP cookies.
+     *
+     * <p> The result is {@code true} only if two cookies come from same domain
+     * (case-insensitive), have same name (case-insensitive), and have same path
+     * (case-sensitive).
+     *
+     * @return  {@code true} if two HTTP cookies equal to each other;
+     *          otherwise, {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this)
+            return true;
+        if (!(obj instanceof HttpCookie))
+            return false;
+        HttpCookie other = (HttpCookie)obj;
+
+        // One http cookie equals to another cookie (RFC 2965 sec. 3.3.3) if:
+        //   1. they come from same domain (case-insensitive),
+        //   2. have same name (case-insensitive),
+        //   3. and have same path (case-sensitive).
+        return equalsIgnoreCase(getName(), other.getName()) &&
+               equalsIgnoreCase(getDomain(), other.getDomain()) &&
+               Objects.equals(getPath(), other.getPath());
+    }
+
+    /**
+     * Returns the hash code of this HTTP cookie. The result is the sum of
+     * hash code value of three significant components of this cookie: name,
+     * domain, and path. That is, the hash code is the value of the expression:
+     * <blockquote>
+     * getName().toLowerCase().hashCode()<br>
+     * + getDomain().toLowerCase().hashCode()<br>
+     * + getPath().hashCode()
+     * </blockquote>
+     *
+     * @return  this HTTP cookie's hash code
+     */
+    @Override
+    public int hashCode() {
+        int h1 = name.toLowerCase().hashCode();
+        int h2 = (domain!=null) ? domain.toLowerCase().hashCode() : 0;
+        int h3 = (path!=null) ? path.hashCode() : 0;
+
+        return h1 + h2 + h3;
+    }
+
+    /**
+     * Create and return a copy of this object.
+     *
+     * @return  a clone of this HTTP cookie
+     */
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    // ---------------- Private operations --------------
+
+    // Note -- disabled for now to allow full Netscape compatibility
+    // from RFC 2068, token special case characters
+    //
+    // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t";
+    // Android-changed: App compat reason. Disallow "=\t" as token
+    // private static final String tspecials = ",; ";  // deliberately includes space
+    private static final String tspecials = ",;= \t";
+
+    /*
+     * Tests a string and returns true if the string counts as a token.
+     *
+     * @param  value
+     *         the {@code String} to be tested
+     *
+     * @return  {@code true} if the {@code String} is a token;
+     *          {@code false} if it is not
+     */
+    private static boolean isToken(String value) {
+        // Android-added: Reserved name can't be a token
+        if (RESERVED_NAMES.contains(value.toLowerCase(Locale.US))) {
+            return false;
+        }
+
+        int len = value.length();
+
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+
+            if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1)
+                return false;
+        }
+        return true;
+    }
+
+    /*
+     * Parse header string to cookie object.
+     *
+     * @param  header
+     *         header string; should contain only one NAME=VALUE pair
+     *
+     * @return  an HttpCookie being extracted
+     *
+     * @throws  IllegalArgumentException
+     *          if header string violates the cookie specification
+     */
+    private static HttpCookie parseInternal(String header,
+                                            boolean retainHeader)
+    {
+        HttpCookie cookie = null;
+        String namevaluePair = null;
+
+        StringTokenizer tokenizer = new StringTokenizer(header, ";");
+
+        // there should always have at least on name-value pair;
+        // it's cookie's name
+        try {
+            namevaluePair = tokenizer.nextToken();
+            int index = namevaluePair.indexOf('=');
+            if (index != -1) {
+                String name = namevaluePair.substring(0, index).trim();
+                String value = namevaluePair.substring(index + 1).trim();
+                if (retainHeader)
+                    cookie = new HttpCookie(name,
+                                            stripOffSurroundingQuote(value),
+                                            header);
+                else
+                    cookie = new HttpCookie(name,
+                                            stripOffSurroundingQuote(value));
+            } else {
+                // no "=" in name-value pair; it's an error
+                throw new IllegalArgumentException("Invalid cookie name-value pair");
+            }
+        } catch (NoSuchElementException ignored) {
+            throw new IllegalArgumentException("Empty cookie header string");
+        }
+
+        // remaining name-value pairs are cookie's attributes
+        while (tokenizer.hasMoreTokens()) {
+            namevaluePair = tokenizer.nextToken();
+            int index = namevaluePair.indexOf('=');
+            String name, value;
+            if (index != -1) {
+                name = namevaluePair.substring(0, index).trim();
+                value = namevaluePair.substring(index + 1).trim();
+            } else {
+                name = namevaluePair.trim();
+                value = null;
+            }
+
+            // assign attribute to cookie
+            assignAttribute(cookie, name, value);
+        }
+
+        return cookie;
+    }
+
+    /*
+     * assign cookie attribute value to attribute name;
+     * use a map to simulate method dispatch
+     */
+    static interface CookieAttributeAssignor {
+            public void assign(HttpCookie cookie,
+                               String attrName,
+                               String attrValue);
+    }
+    static final java.util.Map<String, CookieAttributeAssignor> assignors =
+            new java.util.HashMap<>();
+    static {
+        assignors.put("comment", new CookieAttributeAssignor() {
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getComment() == null)
+                        cookie.setComment(attrValue);
+                }
+            });
+        assignors.put("commenturl", new CookieAttributeAssignor() {
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getCommentURL() == null)
+                        cookie.setCommentURL(attrValue);
+                }
+            });
+        assignors.put("discard", new CookieAttributeAssignor() {
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    cookie.setDiscard(true);
+                }
+            });
+        assignors.put("domain", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getDomain() == null)
+                        cookie.setDomain(attrValue);
+                }
+            });
+        assignors.put("max-age", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    try {
+                        long maxage = Long.parseLong(attrValue);
+                        if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED)
+                            cookie.setMaxAge(maxage);
+                    } catch (NumberFormatException ignored) {
+                        throw new IllegalArgumentException(
+                                "Illegal cookie max-age attribute");
+                    }
+                }
+            });
+        assignors.put("path", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getPath() == null)
+                        cookie.setPath(attrValue);
+                }
+            });
+        assignors.put("port", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getPortlist() == null)
+                        cookie.setPortlist(attrValue == null ? "" : attrValue);
+                }
+            });
+        assignors.put("secure", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    cookie.setSecure(true);
+                }
+            });
+        assignors.put("httponly", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    cookie.setHttpOnly(true);
+                }
+            });
+        assignors.put("version", new CookieAttributeAssignor(){
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    try {
+                        int version = Integer.parseInt(attrValue);
+                        cookie.setVersion(version);
+                    } catch (NumberFormatException ignored) {
+                        // Just ignore bogus version, it will default to 0 or 1
+                    }
+                }
+            });
+        assignors.put("expires", new CookieAttributeAssignor(){ // Netscape only
+                public void assign(HttpCookie cookie,
+                                   String attrName,
+                                   String attrValue) {
+                    if (cookie.getMaxAge() == MAX_AGE_UNSPECIFIED) {
+                        // BEGIN Android-changed: Use HttpDate for date parsing.
+                        // it accepts broader set of date formats.
+                        // cookie.setMaxAge(cookie.expiryDate2DeltaSeconds(attrValue));
+                        // Android-changed: Altered max age calculation to avoid setting
+                        // it to MAX_AGE_UNSPECIFIED (-1) if "expires" is one second in past.
+                        Date date = HttpDate.parse(attrValue);
+                        long maxAgeInSeconds = 0;
+                        if (date != null) {
+                            maxAgeInSeconds = (date.getTime() - cookie.whenCreated) / 1000;
+                            // Avoid MAX_AGE_UNSPECIFIED
+                            if (maxAgeInSeconds == MAX_AGE_UNSPECIFIED) {
+                                maxAgeInSeconds = 0;
+                            }
+                        }
+                        cookie.setMaxAge(maxAgeInSeconds);
+                        // END Android-changed: Use HttpDate for date parsing.
+                    }
+                }
+            });
+    }
+    private static void assignAttribute(HttpCookie cookie,
+                                        String attrName,
+                                        String attrValue)
+    {
+        // strip off the surrounding "-sign if there's any
+        attrValue = stripOffSurroundingQuote(attrValue);
+
+        CookieAttributeAssignor assignor = assignors.get(attrName.toLowerCase());
+        if (assignor != null) {
+            assignor.assign(cookie, attrName, attrValue);
+        } else {
+            // Ignore the attribute as per RFC 2965
+        }
+    }
+
+    // BEGIN Android-removed: Android doesn't use JavaNetHttpCookieAccess
+    /*
+    static {
+        sun.misc.SharedSecrets.setJavaNetHttpCookieAccess(
+            new sun.misc.JavaNetHttpCookieAccess() {
+                public List<HttpCookie> parse(String header) {
+                    return HttpCookie.parse(header, true);
+                }
+
+                public String header(HttpCookie cookie) {
+                    return cookie.header;
+                }
+            }
+        );
+    }
+    */
+    // END Android-removed: Android doesn't use JavaNetHttpCookieAccess
+
+    /*
+     * Returns the original header this cookie was consructed from, if it was
+     * constructed by parsing a header, otherwise null.
+     */
+    private String header() {
+        return header;
+    }
+
+    /*
+     * Constructs a string representation of this cookie. The string format is
+     * as Netscape spec, but without leading "Cookie:" token.
+     */
+    private String toNetscapeHeaderString() {
+        return getName() + "=" + getValue();
+    }
+
+    /*
+     * Constructs a string representation of this cookie. The string format is
+     * as RFC 2965/2109, but without leading "Cookie:" token.
+     */
+    private String toRFC2965HeaderString() {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append(getName()).append("=\"").append(getValue()).append('"');
+        if (getPath() != null)
+            sb.append(";$Path=\"").append(getPath()).append('"');
+        if (getDomain() != null)
+            sb.append(";$Domain=\"").append(getDomain()).append('"');
+        if (getPortlist() != null)
+            sb.append(";$Port=\"").append(getPortlist()).append('"');
+
+        return sb.toString();
+    }
+
+    static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+    // BEGIN Android-removed: not used.
+    /*
+     * @param  dateString
+     *         a date string in one of the formats defined in Netscape cookie spec
+     *
+     * @return  delta seconds between this cookie's creation time and the time
+     *          specified by dateString
+     *
+    private long expiryDate2DeltaSeconds(String dateString) {
+        Calendar cal = new GregorianCalendar(GMT);
+        for (int i = 0; i < COOKIE_DATE_FORMATS.length; i++) {
+            SimpleDateFormat df = new SimpleDateFormat(COOKIE_DATE_FORMATS[i],
+                                                       Locale.US);
+            cal.set(1970, 0, 1, 0, 0, 0);
+            df.setTimeZone(GMT);
+            df.setLenient(false);
+            df.set2DigitYearStart(cal.getTime());
+            try {
+                cal.setTime(df.parse(dateString));
+                if (!COOKIE_DATE_FORMATS[i].contains("yyyy")) {
+                    // 2-digit years following the standard set
+                    // out it rfc 6265
+                    int year = cal.get(Calendar.YEAR);
+                    year %= 100;
+                    if (year < 70) {
+                        year += 2000;
+                    } else {
+                        year += 1900;
+                    }
+                    cal.set(Calendar.YEAR, year);
+                }
+                return (cal.getTimeInMillis() - whenCreated) / 1000;
+            } catch (Exception e) {
+                // Ignore, try the next date format
+            }
+        }
+        return 0;
+    }
+    */
+    // END Android-removed: not used.
+
+    /*
+     * try to guess the cookie version through set-cookie header string
+     */
+    private static int guessCookieVersion(String header) {
+        int version = 0;
+
+        header = header.toLowerCase();
+        if (header.indexOf("expires=") != -1) {
+            // only netscape cookie using 'expires'
+            version = 0;
+        } else if (header.indexOf("version=") != -1) {
+            // version is mandatory for rfc 2965/2109 cookie
+            version = 1;
+        } else if (header.indexOf("max-age") != -1) {
+            // rfc 2965/2109 use 'max-age'
+            version = 1;
+        } else if (startsWithIgnoreCase(header, SET_COOKIE2)) {
+            // only rfc 2965 cookie starts with 'set-cookie2'
+            version = 1;
+        }
+
+        return version;
+    }
+
+    private static String stripOffSurroundingQuote(String str) {
+        if (str != null && str.length() > 2 &&
+            str.charAt(0) == '"' && str.charAt(str.length() - 1) == '"') {
+            return str.substring(1, str.length() - 1);
+        }
+        if (str != null && str.length() > 2 &&
+            str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'') {
+            return str.substring(1, str.length() - 1);
+        }
+        return str;
+    }
+
+    private static boolean equalsIgnoreCase(String s, String t) {
+        if (s == t) return true;
+        if ((s != null) && (t != null)) {
+            return s.equalsIgnoreCase(t);
+        }
+        return false;
+    }
+
+    private static boolean startsWithIgnoreCase(String s, String start) {
+        if (s == null || start == null) return false;
+
+        if (s.length() >= start.length() &&
+                start.equalsIgnoreCase(s.substring(0, start.length()))) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /*
+     * Split cookie header string according to rfc 2965:
+     *   1) split where it is a comma;
+     *   2) but not the comma surrounding by double-quotes, which is the comma
+     *      inside port list or embeded URIs.
+     *
+     * @param  header
+     *         the cookie header string to split
+     *
+     * @return  list of strings; never null
+     */
+    private static List<String> splitMultiCookies(String header) {
+        List<String> cookies = new java.util.ArrayList<String>();
+        int quoteCount = 0;
+        int p, q;
+
+        for (p = 0, q = 0; p < header.length(); p++) {
+            char c = header.charAt(p);
+            if (c == '"') quoteCount++;
+            if (c == ',' && (quoteCount % 2 == 0)) {
+                // it is comma and not surrounding by double-quotes
+                cookies.add(header.substring(q, p));
+                q = p + 1;
+            }
+        }
+
+        cookies.add(header.substring(q));
+
+        return cookies;
+    }
+}
diff --git a/java/net/HttpRetryException.java b/java/net/HttpRetryException.java
new file mode 100644
index 0000000..d498a65
--- /dev/null
+++ b/java/net/HttpRetryException.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that a HTTP request needs to be retried
+ * but cannot be retried automatically, due to streaming mode
+ * being enabled.
+ *
+ * @author  Michael McMahon
+ * @since   1.5
+ */
+public
+class HttpRetryException extends IOException {
+    private static final long serialVersionUID = -9186022286469111381L;
+
+    private int responseCode;
+    private String location;
+
+    /**
+     * Constructs a new {@code HttpRetryException} from the
+     * specified response code and exception detail message
+     *
+     * @param   detail   the detail message.
+     * @param   code   the HTTP response code from server.
+     */
+    public HttpRetryException(String detail, int code) {
+        super(detail);
+        responseCode = code;
+    }
+
+    /**
+     * Constructs a new {@code HttpRetryException} with detail message
+     * responseCode and the contents of the Location response header field.
+     *
+     * @param   detail   the detail message.
+     * @param   code   the HTTP response code from server.
+     * @param   location   the URL to be redirected to
+     */
+    public HttpRetryException(String detail, int code, String location) {
+        super (detail);
+        responseCode = code;
+        this.location = location;
+    }
+
+    /**
+     * Returns the http response code
+     *
+     * @return  The http response code.
+     */
+    public int responseCode() {
+        return responseCode;
+    }
+
+    /**
+     * Returns a string explaining why the http request could
+     * not be retried.
+     *
+     * @return  The reason string
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns the value of the Location header field if the
+     * error resulted from redirection.
+     *
+     * @return The location string
+     */
+    public String getLocation() {
+        return location;
+    }
+}
diff --git a/java/net/HttpURLConnection.java b/java/net/HttpURLConnection.java
new file mode 100644
index 0000000..b72168b
--- /dev/null
+++ b/java/net/HttpURLConnection.java
@@ -0,0 +1,1023 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.security.Permission;
+import java.util.Date;
+
+// Android-changed: top-level documentation substantially changed/rewritten.
+/**
+ * A URLConnection with support for HTTP-specific features. See
+ * <A HREF="http://www.w3.org/pub/WWW/Protocols/"> the spec </A> for
+ * details.
+ * <p>
+ *
+ * <p>Uses of this class follow a pattern:
+ * <ol>
+ *   <li>Obtain a new {@code HttpURLConnection} by calling {@link
+ *       URL#openConnection() URL.openConnection()} and casting the result to
+ *       {@code HttpURLConnection}.
+ *   <li>Prepare the request. The primary property of a request is its URI.
+ *       Request headers may also include metadata such as credentials, preferred
+ *       content types, and session cookies.
+ *   <li>Optionally upload a request body. Instances must be configured with
+ *       {@link #setDoOutput(boolean) setDoOutput(true)} if they include a
+ *       request body. Transmit data by writing to the stream returned by {@link
+ *       #getOutputStream()}.
+ *   <li>Read the response. Response headers typically include metadata such as
+ *       the response body's content type and length, modified dates and session
+ *       cookies. The response body may be read from the stream returned by {@link
+ *       #getInputStream()}. If the response has no body, that method returns an
+ *       empty stream.
+ *   <li>Disconnect. Once the response body has been read, the {@code
+ *       HttpURLConnection} should be closed by calling {@link #disconnect()}.
+ *       Disconnecting releases the resources held by a connection so they may
+ *       be closed or reused.
+ * </ol>
+ *
+ * <p>For example, to retrieve the webpage at {@code http://www.android.com/}:
+ * <pre>   {@code
+ *   URL url = new URL("http://www.android.com/");
+ *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ *   try {
+ *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ *     readStream(in);
+ *   } finally {
+ *     urlConnection.disconnect();
+ *   }
+ * }</pre>
+ *
+ * <h3>Secure Communication with HTTPS</h3>
+ * Calling {@link URL#openConnection()} on a URL with the "https"
+ * scheme will return an {@code HttpsURLConnection}, which allows for
+ * overriding the default {@link javax.net.ssl.HostnameVerifier
+ * HostnameVerifier} and {@link javax.net.ssl.SSLSocketFactory
+ * SSLSocketFactory}. An application-supplied {@code SSLSocketFactory}
+ * created from an {@link javax.net.ssl.SSLContext SSLContext} can
+ * provide a custom {@link javax.net.ssl.X509TrustManager
+ * X509TrustManager} for verifying certificate chains and a custom
+ * {@link javax.net.ssl.X509KeyManager X509KeyManager} for supplying
+ * client certificates. See {@link javax.net.ssl.HttpsURLConnection
+ * HttpsURLConnection} for more details.
+ *
+ * <h3>Response Handling</h3>
+ * {@code HttpURLConnection} will follow up to five HTTP redirects. It will
+ * follow redirects from one origin server to another. This implementation
+ * doesn't follow redirects from HTTPS to HTTP or vice versa.
+ *
+ * <p>If the HTTP response indicates that an error occurred, {@link
+ * #getInputStream()} will throw an {@link IOException}. Use {@link
+ * #getErrorStream()} to read the error response. The headers can be read in
+ * the normal way using {@link #getHeaderFields()},
+ *
+ * <h3>Posting Content</h3>
+ * To upload data to a web server, configure the connection for output using
+ * {@link #setDoOutput(boolean) setDoOutput(true)}.
+ *
+ * <p>For best performance, you should call either {@link
+ * #setFixedLengthStreamingMode(int)} when the body length is known in advance,
+ * or {@link #setChunkedStreamingMode(int)} when it is not. Otherwise {@code
+ * HttpURLConnection} will be forced to buffer the complete request body in
+ * memory before it is transmitted, wasting (and possibly exhausting) heap and
+ * increasing latency.
+ *
+ * <p>For example, to perform an upload: <pre>   {@code
+ *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ *   try {
+ *     urlConnection.setDoOutput(true);
+ *     urlConnection.setChunkedStreamingMode(0);
+ *
+ *     OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
+ *     writeStream(out);
+ *
+ *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ *     readStream(in);
+ *   } finally {
+ *     urlConnection.disconnect();
+ *   }
+ * }</pre>
+ *
+ * <h3>Performance</h3>
+ * The input and output streams returned by this class are <strong>not
+ * buffered</strong>. Most callers should wrap the returned streams with {@link
+ * java.io.BufferedInputStream BufferedInputStream} or {@link
+ * java.io.BufferedOutputStream BufferedOutputStream}. Callers that do only bulk
+ * reads or writes may omit buffering.
+ *
+ * <p>When transferring large amounts of data to or from a server, use streams
+ * to limit how much data is in memory at once. Unless you need the entire
+ * body to be in memory at once, process it as a stream (rather than storing
+ * the complete body as a single byte array or string).
+ *
+ * <p>To reduce latency, this class may reuse the same underlying {@code Socket}
+ * for multiple request/response pairs. As a result, HTTP connections may be
+ * held open longer than necessary. Calls to {@link #disconnect()} may return
+ * the socket to a pool of connected sockets.
+ *
+ * <p>By default, this implementation of {@code HttpURLConnection} requests that
+ * servers use gzip compression and it automatically decompresses the data for
+ * callers of {@link #getInputStream()}. The Content-Encoding and Content-Length
+ * response headers are cleared in this case. Gzip compression can be disabled by
+ * setting the acceptable encodings in the request header: <pre>   {@code
+ *   urlConnection.setRequestProperty("Accept-Encoding", "identity");
+ * }</pre>
+ *
+ * <p>Setting the Accept-Encoding request header explicitly disables automatic
+ * decompression and leaves the response headers intact; callers must handle
+ * decompression as needed, according to the Content-Encoding header of the
+ * response.
+ *
+ * <p>{@link #getContentLength()} returns the number of bytes transmitted and
+ * cannot be used to predict how many bytes can be read from
+ * {@link #getInputStream()} for compressed streams. Instead, read that stream
+ * until it is exhausted, i.e. when {@link InputStream#read} returns -1.
+ *
+ * <h3>Handling Network Sign-On</h3>
+ * Some Wi-Fi networks block Internet access until the user clicks through a
+ * sign-on page. Such sign-on pages are typically presented by using HTTP
+ * redirects. You can use {@link #getURL()} to test if your connection has been
+ * unexpectedly redirected. This check is not valid until <strong>after</strong>
+ * the response headers have been received, which you can trigger by calling
+ * {@link #getHeaderFields()} or {@link #getInputStream()}. For example, to
+ * check that a response was not redirected to an unexpected host:
+ * <pre>   {@code
+ *   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ *   try {
+ *     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ *     if (!url.getHost().equals(urlConnection.getURL().getHost())) {
+ *       // we were redirected! Kick the user out to the browser to sign on?
+ *     }
+ *     ...
+ *   } finally {
+ *     urlConnection.disconnect();
+ *   }
+ * }</pre>
+ *
+ * <h3>HTTP Authentication</h3>
+ * {@code HttpURLConnection} supports <a
+ * href="http://www.ietf.org/rfc/rfc2617">HTTP basic authentication</a>. Use
+ * {@link Authenticator} to set the VM-wide authentication handler:
+ * <pre>   {@code
+ *   Authenticator.setDefault(new Authenticator() {
+ *     protected PasswordAuthentication getPasswordAuthentication() {
+ *       return new PasswordAuthentication(username, password.toCharArray());
+ *     }
+ *   });
+ * }</pre>
+ * Unless paired with HTTPS, this is <strong>not</strong> a secure mechanism for
+ * user authentication. In particular, the username, password, request and
+ * response are all transmitted over the network without encryption.
+ *
+ * <h3>Sessions with Cookies</h3>
+ * To establish and maintain a potentially long-lived session between client
+ * and server, {@code HttpURLConnection} includes an extensible cookie manager.
+ * Enable VM-wide cookie management using {@link CookieHandler} and {@link
+ * CookieManager}: <pre>   {@code
+ *   CookieManager cookieManager = new CookieManager();
+ *   CookieHandler.setDefault(cookieManager);
+ * }</pre>
+ * By default, {@code CookieManager} accepts cookies from the <a
+ * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
+ * server</a> only. Two other policies are included: {@link
+ * CookiePolicy#ACCEPT_ALL} and {@link CookiePolicy#ACCEPT_NONE}. Implement
+ * {@link CookiePolicy} to define a custom policy.
+ *
+ * <p>The default {@code CookieManager} keeps all accepted cookies in memory. It
+ * will forget these cookies when the VM exits. Implement {@link CookieStore} to
+ * define a custom cookie store.
+ *
+ * <p>In addition to the cookies set by HTTP responses, you may set cookies
+ * programmatically. To be included in HTTP request headers, cookies must have
+ * the domain and path properties set.
+ *
+ * <p>By default, new instances of {@code HttpCookie} work only with servers
+ * that support <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>
+ * cookies. Many web servers support only the older specification, <a
+ * href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a>. For compatibility
+ * with the most web servers, set the cookie version to 0.
+ *
+ * <p>For example, to receive {@code www.twitter.com} in French: <pre>   {@code
+ *   HttpCookie cookie = new HttpCookie("lang", "fr");
+ *   cookie.setDomain("twitter.com");
+ *   cookie.setPath("/");
+ *   cookie.setVersion(0);
+ *   cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);
+ * }</pre>
+ *
+ * <h3>HTTP Methods</h3>
+ * <p>{@code HttpURLConnection} uses the {@code GET} method by default. It will
+ * use {@code POST} if {@link #setDoOutput setDoOutput(true)} has been called.
+ * Other HTTP methods ({@code OPTIONS}, {@code HEAD}, {@code PUT}, {@code
+ * DELETE} and {@code TRACE}) can be used with {@link #setRequestMethod}.
+ *
+ * <h3>Proxies</h3>
+ * By default, this class will connect directly to the <a
+ * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
+ * server</a>. It can also connect via an {@link Proxy.Type#HTTP HTTP} or {@link
+ * Proxy.Type#SOCKS SOCKS} proxy. To use a proxy, use {@link
+ * URL#openConnection(Proxy) URL.openConnection(Proxy)} when creating the
+ * connection.
+ *
+ * <h3>IPv6 Support</h3>
+ * <p>This class includes transparent support for IPv6. For hosts with both IPv4
+ * and IPv6 addresses, it will attempt to connect to each of a host's addresses
+ * until a connection is established.
+ *
+ * <h3>Response Caching</h3>
+ * Android 4.0 (Ice Cream Sandwich, API level 15) includes a response cache. See
+ * {@code android.net.http.HttpResponseCache} for instructions on enabling HTTP
+ * caching in your application.
+ *
+ * <h3>Avoiding Bugs In Earlier Releases</h3>
+ * Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In
+ * particular, calling {@code close()} on a readable {@code InputStream} could
+ * <a href="http://code.google.com/p/android/issues/detail?id=2939">poison the
+ * connection pool</a>. Work around this by disabling connection pooling:
+ * <pre>   {@code
+ * private void disableConnectionReuseIfNecessary() {
+ *   // Work around pre-Froyo bugs in HTTP connection reuse.
+ *   if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
+ *     System.setProperty("http.keepAlive", "false");
+ *   }
+ * }}</pre>
+ *
+ * <p>Each instance of {@code HttpURLConnection} may be used for one
+ * request/response pair. Instances of this class are not thread safe.
+ *
+ * @see     java.net.HttpURLConnection#disconnect()
+ * @since JDK1.1
+ */
+abstract public class HttpURLConnection extends URLConnection {
+    /* instance variables */
+
+    /**
+     * The HTTP method (GET,POST,PUT,etc.).
+     */
+    protected String method = "GET";
+
+    /**
+     * The chunk-length when using chunked encoding streaming mode for output.
+     * A value of {@code -1} means chunked encoding is disabled for output.
+     * @since 1.5
+     */
+    protected int chunkLength = -1;
+
+    /**
+     * The fixed content-length when using fixed-length streaming mode.
+     * A value of {@code -1} means fixed-length streaming mode is disabled
+     * for output.
+     *
+     * <P> <B>NOTE:</B> {@link #fixedContentLengthLong} is recommended instead
+     * of this field, as it allows larger content lengths to be set.
+     *
+     * @since 1.5
+     */
+    protected int fixedContentLength = -1;
+
+    /**
+     * The fixed content-length when using fixed-length streaming mode.
+     * A value of {@code -1} means fixed-length streaming mode is disabled
+     * for output.
+     *
+     * @since 1.7
+     */
+    protected long fixedContentLengthLong = -1;
+
+    /**
+     * Returns the key for the {@code n}<sup>th</sup> header field.
+     * Some implementations may treat the {@code 0}<sup>th</sup>
+     * header field as special, i.e. as the status line returned by the HTTP
+     * server. In this case, {@link #getHeaderField(int) getHeaderField(0)} returns the status
+     * line, but {@code getHeaderFieldKey(0)} returns null.
+     *
+     * @param   n   an index, where {@code n >=0}.
+     * @return  the key for the {@code n}<sup>th</sup> header field,
+     *          or {@code null} if the key does not exist.
+     */
+    public String getHeaderFieldKey (int n) {
+        return null;
+    }
+
+    /**
+     * This method is used to enable streaming of a HTTP request body
+     * without internal buffering, when the content length is known in
+     * advance.
+     * <p>
+     * An exception will be thrown if the application
+     * attempts to write more data than the indicated
+     * content-length, or if the application closes the OutputStream
+     * before writing the indicated amount.
+     * <p>
+     * When output streaming is enabled, authentication
+     * and redirection cannot be handled automatically.
+     * A HttpRetryException will be thrown when reading
+     * the response if authentication or redirection are required.
+     * This exception can be queried for the details of the error.
+     * <p>
+     * This method must be called before the URLConnection is connected.
+     * <p>
+     * <B>NOTE:</B> {@link #setFixedLengthStreamingMode(long)} is recommended
+     * instead of this method as it allows larger content lengths to be set.
+     *
+     * @param   contentLength The number of bytes which will be written
+     *          to the OutputStream.
+     *
+     * @throws  IllegalStateException if URLConnection is already connected
+     *          or if a different streaming mode is already enabled.
+     *
+     * @throws  IllegalArgumentException if a content length less than
+     *          zero is specified.
+     *
+     * @see     #setChunkedStreamingMode(int)
+     * @since 1.5
+     */
+    public void setFixedLengthStreamingMode (int contentLength) {
+        if (connected) {
+            throw new IllegalStateException ("Already connected");
+        }
+        if (chunkLength != -1) {
+            throw new IllegalStateException ("Chunked encoding streaming mode set");
+        }
+        if (contentLength < 0) {
+            throw new IllegalArgumentException ("invalid content length");
+        }
+        fixedContentLength = contentLength;
+    }
+
+    /**
+     * This method is used to enable streaming of a HTTP request body
+     * without internal buffering, when the content length is known in
+     * advance.
+     *
+     * <P> An exception will be thrown if the application attempts to write
+     * more data than the indicated content-length, or if the application
+     * closes the OutputStream before writing the indicated amount.
+     *
+     * <P> When output streaming is enabled, authentication and redirection
+     * cannot be handled automatically. A {@linkplain HttpRetryException} will
+     * be thrown when reading the response if authentication or redirection
+     * are required. This exception can be queried for the details of the
+     * error.
+     *
+     * <P> This method must be called before the URLConnection is connected.
+     *
+     * <P> The content length set by invoking this method takes precedence
+     * over any value set by {@link #setFixedLengthStreamingMode(int)}.
+     *
+     * @param  contentLength
+     *         The number of bytes which will be written to the OutputStream.
+     *
+     * @throws  IllegalStateException
+     *          if URLConnection is already connected or if a different
+     *          streaming mode is already enabled.
+     *
+     * @throws  IllegalArgumentException
+     *          if a content length less than zero is specified.
+     *
+     * @since 1.7
+     */
+    public void setFixedLengthStreamingMode(long contentLength) {
+        if (connected) {
+            throw new IllegalStateException("Already connected");
+        }
+        if (chunkLength != -1) {
+            throw new IllegalStateException(
+                "Chunked encoding streaming mode set");
+        }
+        if (contentLength < 0) {
+            throw new IllegalArgumentException("invalid content length");
+        }
+        fixedContentLengthLong = contentLength;
+    }
+
+    /* Default chunk size (including chunk header) if not specified;
+     * we want to keep this in sync with the one defined in
+     * sun.net.www.http.ChunkedOutputStream
+     */
+    private static final int DEFAULT_CHUNK_SIZE = 4096;
+
+    /**
+     * This method is used to enable streaming of a HTTP request body
+     * without internal buffering, when the content length is <b>not</b>
+     * known in advance. In this mode, chunked transfer encoding
+     * is used to send the request body. Note, not all HTTP servers
+     * support this mode.
+     * <p>
+     * When output streaming is enabled, authentication
+     * and redirection cannot be handled automatically.
+     * A HttpRetryException will be thrown when reading
+     * the response if authentication or redirection are required.
+     * This exception can be queried for the details of the error.
+     * <p>
+     * This method must be called before the URLConnection is connected.
+     *
+     * @param   chunklen The number of bytes to write in each chunk.
+     *          If chunklen is less than or equal to zero, a default
+     *          value will be used.
+     *
+     * @throws  IllegalStateException if URLConnection is already connected
+     *          or if a different streaming mode is already enabled.
+     *
+     * @see     #setFixedLengthStreamingMode(int)
+     * @since 1.5
+     */
+    public void setChunkedStreamingMode (int chunklen) {
+        if (connected) {
+            throw new IllegalStateException ("Can't set streaming mode: already connected");
+        }
+        if (fixedContentLength != -1 || fixedContentLengthLong != -1) {
+            throw new IllegalStateException ("Fixed length streaming mode set");
+        }
+        chunkLength = chunklen <=0? DEFAULT_CHUNK_SIZE : chunklen;
+    }
+
+    /**
+     * Returns the value for the {@code n}<sup>th</sup> header field.
+     * Some implementations may treat the {@code 0}<sup>th</sup>
+     * header field as special, i.e. as the status line returned by the HTTP
+     * server.
+     * <p>
+     * This method can be used in conjunction with the
+     * {@link #getHeaderFieldKey getHeaderFieldKey} method to iterate through all
+     * the headers in the message.
+     *
+     * @param   n   an index, where {@code n>=0}.
+     * @return  the value of the {@code n}<sup>th</sup> header field,
+     *          or {@code null} if the value does not exist.
+     * @see     java.net.HttpURLConnection#getHeaderFieldKey(int)
+     */
+    public String getHeaderField(int n) {
+        return null;
+    }
+
+    /**
+     * An {@code int} representing the three digit HTTP Status-Code.
+     * <ul>
+     * <li> 1xx: Informational
+     * <li> 2xx: Success
+     * <li> 3xx: Redirection
+     * <li> 4xx: Client Error
+     * <li> 5xx: Server Error
+     * </ul>
+     */
+    protected int responseCode = -1;
+
+    /**
+     * The HTTP response message.
+     */
+    protected String responseMessage = null;
+
+    /* static variables */
+
+    /* do we automatically follow redirects? The default is true. */
+    private static boolean followRedirects = true;
+
+    /**
+     * If {@code true}, the protocol will automatically follow redirects.
+     * If {@code false}, the protocol will not automatically follow
+     * redirects.
+     * <p>
+     * This field is set by the {@code setInstanceFollowRedirects}
+     * method. Its value is returned by the {@code getInstanceFollowRedirects}
+     * method.
+     * <p>
+     * Its default value is based on the value of the static followRedirects
+     * at HttpURLConnection construction time.
+     *
+     * @see     java.net.HttpURLConnection#setInstanceFollowRedirects(boolean)
+     * @see     java.net.HttpURLConnection#getInstanceFollowRedirects()
+     * @see     java.net.HttpURLConnection#setFollowRedirects(boolean)
+     */
+    protected boolean instanceFollowRedirects = followRedirects;
+
+    /* valid HTTP methods */
+    private static final String[] methods = {
+        "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
+    };
+
+    /**
+     * Constructor for the HttpURLConnection.
+     * @param u the URL
+     */
+    protected HttpURLConnection (URL u) {
+        super(u);
+    }
+
+    /**
+     * Sets whether HTTP redirects  (requests with response code 3xx) should
+     * be automatically followed by this class.  True by default.  Applets
+     * cannot change this variable.
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param set a {@code boolean} indicating whether or not
+     * to follow HTTP redirects.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't
+     *             allow the operation.
+     * @see        SecurityManager#checkSetFactory
+     * @see #getFollowRedirects()
+     */
+    public static void setFollowRedirects(boolean set) {
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            // seems to be the best check here...
+            sec.checkSetFactory();
+        }
+        followRedirects = set;
+    }
+
+    /**
+     * Returns a {@code boolean} indicating
+     * whether or not HTTP redirects (3xx) should
+     * be automatically followed.
+     *
+     * @return {@code true} if HTTP redirects should
+     * be automatically followed, {@code false} if not.
+     * @see #setFollowRedirects(boolean)
+     */
+    public static boolean getFollowRedirects() {
+        return followRedirects;
+    }
+
+    /**
+     * Sets whether HTTP redirects (requests with response code 3xx) should
+     * be automatically followed by this {@code HttpURLConnection}
+     * instance.
+     * <p>
+     * The default value comes from followRedirects, which defaults to
+     * true.
+     *
+     * @param followRedirects a {@code boolean} indicating
+     * whether or not to follow HTTP redirects.
+     *
+     * @see    java.net.HttpURLConnection#instanceFollowRedirects
+     * @see #getInstanceFollowRedirects
+     * @since 1.3
+     */
+     public void setInstanceFollowRedirects(boolean followRedirects) {
+        instanceFollowRedirects = followRedirects;
+     }
+
+     /**
+     * Returns the value of this {@code HttpURLConnection}'s
+     * {@code instanceFollowRedirects} field.
+     *
+     * @return  the value of this {@code HttpURLConnection}'s
+     *          {@code instanceFollowRedirects} field.
+     * @see     java.net.HttpURLConnection#instanceFollowRedirects
+     * @see #setInstanceFollowRedirects(boolean)
+     * @since 1.3
+     */
+     public boolean getInstanceFollowRedirects() {
+         return instanceFollowRedirects;
+     }
+
+    /**
+     * Set the method for the URL request, one of:
+     * <UL>
+     *  <LI>GET
+     *  <LI>POST
+     *  <LI>HEAD
+     *  <LI>OPTIONS
+     *  <LI>PUT
+     *  <LI>DELETE
+     *  <LI>TRACE
+     * </UL> are legal, subject to protocol restrictions.  The default
+     * method is GET.
+     *
+     * @param method the HTTP method
+     * @exception ProtocolException if the method cannot be reset or if
+     *              the requested method isn't valid for HTTP.
+     * @exception SecurityException if a security manager is set and the
+     *              method is "TRACE", but the "allowHttpTrace"
+     *              NetPermission is not granted.
+     * @see #getRequestMethod()
+     */
+    public void setRequestMethod(String method) throws ProtocolException {
+        if (connected) {
+            throw new ProtocolException("Can't reset method: already connected");
+        }
+        // This restriction will prevent people from using this class to
+        // experiment w/ new HTTP methods using java.  But it should
+        // be placed for security - the request String could be
+        // arbitrarily long.
+
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].equals(method)) {
+                if (method.equals("TRACE")) {
+                    SecurityManager s = System.getSecurityManager();
+                    if (s != null) {
+                        s.checkPermission(new NetPermission("allowHttpTrace"));
+                    }
+                }
+                this.method = method;
+                return;
+            }
+        }
+        throw new ProtocolException("Invalid HTTP method: " + method);
+    }
+
+    /**
+     * Get the request method.
+     * @return the HTTP request method
+     * @see #setRequestMethod(java.lang.String)
+     */
+    public String getRequestMethod() {
+        return method;
+    }
+
+    /**
+     * Gets the status code from an HTTP response message.
+     * For example, in the case of the following status lines:
+     * <PRE>
+     * HTTP/1.0 200 OK
+     * HTTP/1.0 401 Unauthorized
+     * </PRE>
+     * It will return 200 and 401 respectively.
+     * Returns -1 if no code can be discerned
+     * from the response (i.e., the response is not valid HTTP).
+     * @throws IOException if an error occurred connecting to the server.
+     * @return the HTTP Status-Code, or -1
+     */
+    public int getResponseCode() throws IOException {
+        /*
+         * We're got the response code already
+         */
+        if (responseCode != -1) {
+            return responseCode;
+        }
+
+        /*
+         * Ensure that we have connected to the server. Record
+         * exception as we need to re-throw it if there isn't
+         * a status line.
+         */
+        Exception exc = null;
+        try {
+            getInputStream();
+        } catch (Exception e) {
+            exc = e;
+        }
+
+        /*
+         * If we can't a status-line then re-throw any exception
+         * that getInputStream threw.
+         */
+        String statusLine = getHeaderField(0);
+        if (statusLine == null) {
+            if (exc != null) {
+                if (exc instanceof RuntimeException)
+                    throw (RuntimeException)exc;
+                else
+                    throw (IOException)exc;
+            }
+            return -1;
+        }
+
+        /*
+         * Examine the status-line - should be formatted as per
+         * section 6.1 of RFC 2616 :-
+         *
+         * Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase
+         *
+         * If status line can't be parsed return -1.
+         */
+        if (statusLine.startsWith("HTTP/1.")) {
+            int codePos = statusLine.indexOf(' ');
+            if (codePos > 0) {
+
+                int phrasePos = statusLine.indexOf(' ', codePos+1);
+                if (phrasePos > 0 && phrasePos < statusLine.length()) {
+                    responseMessage = statusLine.substring(phrasePos+1);
+                }
+
+                // deviation from RFC 2616 - don't reject status line
+                // if SP Reason-Phrase is not included.
+                if (phrasePos < 0)
+                    phrasePos = statusLine.length();
+
+                try {
+                    responseCode = Integer.parseInt
+                            (statusLine.substring(codePos+1, phrasePos));
+                    return responseCode;
+                } catch (NumberFormatException e) { }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Gets the HTTP response message, if any, returned along with the
+     * response code from a server.  From responses like:
+     * <PRE>
+     * HTTP/1.0 200 OK
+     * HTTP/1.0 404 Not Found
+     * </PRE>
+     * Extracts the Strings "OK" and "Not Found" respectively.
+     * Returns null if none could be discerned from the responses
+     * (the result was not valid HTTP).
+     * @throws IOException if an error occurred connecting to the server.
+     * @return the HTTP response message, or {@code null}
+     */
+    public String getResponseMessage() throws IOException {
+        getResponseCode();
+        return responseMessage;
+    }
+
+    @SuppressWarnings("deprecation")
+    public long getHeaderFieldDate(String name, long Default) {
+        String dateString = getHeaderField(name);
+        try {
+            if (dateString.indexOf("GMT") == -1) {
+                dateString = dateString+" GMT";
+            }
+            return Date.parse(dateString);
+        } catch (Exception e) {
+        }
+        return Default;
+    }
+
+
+    /**
+     * Indicates that other requests to the server
+     * are unlikely in the near future. Calling disconnect()
+     * should not imply that this HttpURLConnection
+     * instance can be reused for other requests.
+     */
+    public abstract void disconnect();
+
+    /**
+     * Indicates if the connection is going through a proxy.
+     * @return a boolean indicating if the connection is
+     * using a proxy.
+     */
+    public abstract boolean usingProxy();
+
+    /**
+     * Returns a {@link SocketPermission} object representing the
+     * permission necessary to connect to the destination host and port.
+     *
+     * @exception IOException if an error occurs while computing
+     *            the permission.
+     *
+     * @return a {@code SocketPermission} object representing the
+     *         permission necessary to connect to the destination
+     *         host and port.
+     */
+    public Permission getPermission() throws IOException {
+        int port = url.getPort();
+        port = port < 0 ? 80 : port;
+        String host = url.getHost() + ":" + port;
+        Permission permission = new SocketPermission(host, "connect");
+        return permission;
+    }
+
+   /**
+    * Returns the error stream if the connection failed
+    * but the server sent useful data nonetheless. The
+    * typical example is when an HTTP server responds
+    * with a 404, which will cause a FileNotFoundException
+    * to be thrown in connect, but the server sent an HTML
+    * help page with suggestions as to what to do.
+    *
+    * <p>This method will not cause a connection to be initiated.  If
+    * the connection was not connected, or if the server did not have
+    * an error while connecting or if the server had an error but
+    * no error data was sent, this method will return null. This is
+    * the default.
+    *
+    * @return an error stream if any, null if there have been no
+    * errors, the connection is not connected or the server sent no
+    * useful data.
+    */
+    public InputStream getErrorStream() {
+        return null;
+    }
+
+    /**
+     * The response codes for HTTP, as of version 1.1.
+     */
+
+    // REMIND: do we want all these??
+    // Others not here that we do want??
+
+    /* 2XX: generally "OK" */
+
+    /**
+     * HTTP Status-Code 200: OK.
+     */
+    public static final int HTTP_OK = 200;
+
+    /**
+     * HTTP Status-Code 201: Created.
+     */
+    public static final int HTTP_CREATED = 201;
+
+    /**
+     * HTTP Status-Code 202: Accepted.
+     */
+    public static final int HTTP_ACCEPTED = 202;
+
+    /**
+     * HTTP Status-Code 203: Non-Authoritative Information.
+     */
+    public static final int HTTP_NOT_AUTHORITATIVE = 203;
+
+    /**
+     * HTTP Status-Code 204: No Content.
+     */
+    public static final int HTTP_NO_CONTENT = 204;
+
+    /**
+     * HTTP Status-Code 205: Reset Content.
+     */
+    public static final int HTTP_RESET = 205;
+
+    /**
+     * HTTP Status-Code 206: Partial Content.
+     */
+    public static final int HTTP_PARTIAL = 206;
+
+    /* 3XX: relocation/redirect */
+
+    /**
+     * HTTP Status-Code 300: Multiple Choices.
+     */
+    public static final int HTTP_MULT_CHOICE = 300;
+
+    /**
+     * HTTP Status-Code 301: Moved Permanently.
+     */
+    public static final int HTTP_MOVED_PERM = 301;
+
+    /**
+     * HTTP Status-Code 302: Temporary Redirect.
+     */
+    public static final int HTTP_MOVED_TEMP = 302;
+
+    /**
+     * HTTP Status-Code 303: See Other.
+     */
+    public static final int HTTP_SEE_OTHER = 303;
+
+    /**
+     * HTTP Status-Code 304: Not Modified.
+     */
+    public static final int HTTP_NOT_MODIFIED = 304;
+
+    /**
+     * HTTP Status-Code 305: Use Proxy.
+     */
+    public static final int HTTP_USE_PROXY = 305;
+
+    /* 4XX: client error */
+
+    /**
+     * HTTP Status-Code 400: Bad Request.
+     */
+    public static final int HTTP_BAD_REQUEST = 400;
+
+    /**
+     * HTTP Status-Code 401: Unauthorized.
+     */
+    public static final int HTTP_UNAUTHORIZED = 401;
+
+    /**
+     * HTTP Status-Code 402: Payment Required.
+     */
+    public static final int HTTP_PAYMENT_REQUIRED = 402;
+
+    /**
+     * HTTP Status-Code 403: Forbidden.
+     */
+    public static final int HTTP_FORBIDDEN = 403;
+
+    /**
+     * HTTP Status-Code 404: Not Found.
+     */
+    public static final int HTTP_NOT_FOUND = 404;
+
+    /**
+     * HTTP Status-Code 405: Method Not Allowed.
+     */
+    public static final int HTTP_BAD_METHOD = 405;
+
+    /**
+     * HTTP Status-Code 406: Not Acceptable.
+     */
+    public static final int HTTP_NOT_ACCEPTABLE = 406;
+
+    /**
+     * HTTP Status-Code 407: Proxy Authentication Required.
+     */
+    public static final int HTTP_PROXY_AUTH = 407;
+
+    /**
+     * HTTP Status-Code 408: Request Time-Out.
+     */
+    public static final int HTTP_CLIENT_TIMEOUT = 408;
+
+    /**
+     * HTTP Status-Code 409: Conflict.
+     */
+    public static final int HTTP_CONFLICT = 409;
+
+    /**
+     * HTTP Status-Code 410: Gone.
+     */
+    public static final int HTTP_GONE = 410;
+
+    /**
+     * HTTP Status-Code 411: Length Required.
+     */
+    public static final int HTTP_LENGTH_REQUIRED = 411;
+
+    /**
+     * HTTP Status-Code 412: Precondition Failed.
+     */
+    public static final int HTTP_PRECON_FAILED = 412;
+
+    /**
+     * HTTP Status-Code 413: Request Entity Too Large.
+     */
+    public static final int HTTP_ENTITY_TOO_LARGE = 413;
+
+    /**
+     * HTTP Status-Code 414: Request-URI Too Large.
+     */
+    public static final int HTTP_REQ_TOO_LONG = 414;
+
+    /**
+     * HTTP Status-Code 415: Unsupported Media Type.
+     */
+    public static final int HTTP_UNSUPPORTED_TYPE = 415;
+
+    /* 5XX: server error */
+
+    /**
+     * HTTP Status-Code 500: Internal Server Error.
+     * @deprecated   it is misplaced and shouldn't have existed.
+     */
+    @Deprecated
+    public static final int HTTP_SERVER_ERROR = 500;
+
+    /**
+     * HTTP Status-Code 500: Internal Server Error.
+     */
+    public static final int HTTP_INTERNAL_ERROR = 500;
+
+    /**
+     * HTTP Status-Code 501: Not Implemented.
+     */
+    public static final int HTTP_NOT_IMPLEMENTED = 501;
+
+    /**
+     * HTTP Status-Code 502: Bad Gateway.
+     */
+    public static final int HTTP_BAD_GATEWAY = 502;
+
+    /**
+     * HTTP Status-Code 503: Service Unavailable.
+     */
+    public static final int HTTP_UNAVAILABLE = 503;
+
+    /**
+     * HTTP Status-Code 504: Gateway Timeout.
+     */
+    public static final int HTTP_GATEWAY_TIMEOUT = 504;
+
+    /**
+     * HTTP Status-Code 505: HTTP Version Not Supported.
+     */
+    public static final int HTTP_VERSION = 505;
+
+}
diff --git a/java/net/IDN.java b/java/net/IDN.java
new file mode 100644
index 0000000..a18c3a8
--- /dev/null
+++ b/java/net/IDN.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import android.icu.text.IDNA;
+
+/**
+ * Provides methods to convert internationalized domain names (IDNs) between
+ * a normal Unicode representation and an ASCII Compatible Encoding (ACE) representation.
+ * Internationalized domain names can use characters from the entire range of
+ * Unicode, while traditional domain names are restricted to ASCII characters.
+ * ACE is an encoding of Unicode strings that uses only ASCII characters and
+ * can be used with software (such as the Domain Name System) that only
+ * understands traditional domain names.
+ *
+ * <p>Internationalized domain names are defined in <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+ * RFC 3490 defines two operations: ToASCII and ToUnicode. These 2 operations employ
+ * <a href="http://www.ietf.org/rfc/rfc3491.txt">Nameprep</a> algorithm, which is a
+ * profile of <a href="http://www.ietf.org/rfc/rfc3454.txt">Stringprep</a>, and
+ * <a href="http://www.ietf.org/rfc/rfc3492.txt">Punycode</a> algorithm to convert
+ * domain name string back and forth.
+ *
+ * <p>The behavior of aforementioned conversion process can be adjusted by various flags:
+ *   <ul>
+ *     <li>If the ALLOW_UNASSIGNED flag is used, the domain name string to be converted
+ *         can contain code points that are unassigned in Unicode 3.2, which is the
+ *         Unicode version on which IDN conversion is based. If the flag is not used,
+ *         the presence of such unassigned code points is treated as an error.
+ *     <li>If the USE_STD3_ASCII_RULES flag is used, ASCII strings are checked against <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC 1122</a> and <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a>.
+ *         It is an error if they don't meet the requirements.
+ *   </ul>
+ * These flags can be logically OR'ed together.
+ *
+ * <p>The security consideration is important with respect to internationalization
+ * domain name support. For example, English domain names may be <i>homographed</i>
+ * - maliciously misspelled by substitution of non-Latin letters.
+ * <a href="http://www.unicode.org/reports/tr36/">Unicode Technical Report #36</a>
+ * discusses security issues of IDN support as well as possible solutions.
+ * Applications are responsible for taking adequate security measures when using
+ * international domain names.
+ *
+ * @author Edward Wang
+ * @since 1.6
+ *
+ */
+public final class IDN {
+    /**
+     * Flag to allow processing of unassigned code points
+     */
+    public static final int ALLOW_UNASSIGNED = 0x01;
+
+    /**
+     * Flag to turn on the check against STD-3 ASCII rules
+     */
+    public static final int USE_STD3_ASCII_RULES = 0x02;
+
+
+    /**
+     * Translates a string from Unicode to ASCII Compatible Encoding (ACE),
+     * as defined by the ToASCII operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p>ToASCII operation can fail. ToASCII fails if any step of it fails.
+     * If ToASCII operation fails, an IllegalArgumentException will be thrown.
+     * In this case, the input string should not be used in an internationalized domain name.
+     *
+     * <p> A label is an individual part of a domain name. The original ToASCII operation,
+     * as defined in RFC 3490, only operates on a single label. This method can handle
+     * both label and entire domain name, by assuming that labels in a domain name are
+     * always separated by dots. The following characters are recognized as dots:
+     * &#0092;u002E (full stop), &#0092;u3002 (ideographic full stop), &#0092;uFF0E (fullwidth full stop),
+     * and &#0092;uFF61 (halfwidth ideographic full stop). if dots are
+     * used as label separators, this method also changes all of them to &#0092;u002E (full stop)
+     * in output translated string.
+     *
+     * @param input     the string to be processed
+     * @param flag      process flag; can be 0 or any logical OR of possible flags
+     *
+     * @return          the translated {@code String}
+     *
+     * @throws IllegalArgumentException   if the input string doesn't conform to RFC 3490 specification
+     */
+    public static String toASCII(String input, int flag) {
+        // BEGIN Android-changed: Use ICU4J implementation
+        try {
+            return IDNA.convertIDNToASCII(input, flag).toString();
+        } catch (android.icu.text.StringPrepParseException e) {
+            // b/113787610: "." is a valid IDN but is rejected by ICU.
+            // Usage is relatively uncommon, so only check for it if ICU throws.
+            if (".".equals(input)) {
+                return input;
+            }
+            throw new IllegalArgumentException("Invalid input to toASCII: " + input, e);
+        }
+        // END Android-changed: Use ICU4J implementation
+    }
+
+
+    /**
+     * Translates a string from Unicode to ASCII Compatible Encoding (ACE),
+     * as defined by the ToASCII operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p> This convenience method works as if by invoking the
+     * two-argument counterpart as follows:
+     * <blockquote>
+     * {@link #toASCII(String, int) toASCII}(input,&nbsp;0);
+     * </blockquote>
+     *
+     * @param input     the string to be processed
+     *
+     * @return          the translated {@code String}
+     *
+     * @throws IllegalArgumentException   if the input string doesn't conform to RFC 3490 specification
+     */
+    public static String toASCII(String input) {
+        return toASCII(input, 0);
+    }
+
+
+    /**
+     * Translates a string from ASCII Compatible Encoding (ACE) to Unicode,
+     * as defined by the ToUnicode operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p>ToUnicode never fails. In case of any error, the input string is returned unmodified.
+     *
+     * <p> A label is an individual part of a domain name. The original ToUnicode operation,
+     * as defined in RFC 3490, only operates on a single label. This method can handle
+     * both label and entire domain name, by assuming that labels in a domain name are
+     * always separated by dots. The following characters are recognized as dots:
+     * &#0092;u002E (full stop), &#0092;u3002 (ideographic full stop), &#0092;uFF0E (fullwidth full stop),
+     * and &#0092;uFF61 (halfwidth ideographic full stop).
+     *
+     * @param input     the string to be processed
+     * @param flag      process flag; can be 0 or any logical OR of possible flags
+     *
+     * @return          the translated {@code String}
+     */
+    public static String toUnicode(String input, int flag) {
+        // BEGIN Android-changed: Use ICU4J implementation
+        try {
+            // ICU only translates separators to ASCII for toASCII.
+            // Java expects the translation for toUnicode too.
+            return convertFullStop(IDNA.convertIDNToUnicode(input, flag)).toString();
+        } catch (android.icu.text.StringPrepParseException e) {
+            // The RI documentation explicitly states that if the conversion was unsuccessful
+            // the original string is returned.
+            return input;
+        }
+        // END Android-changed: Use ICU4J implementation
+    }
+
+    // BEGIN Android-added: Use ICU4J implementation
+    private static boolean isLabelSeperator(char c) {
+        return (c == '\u3002' || c == '\uff0e' || c == '\uff61');
+    }
+
+    private static StringBuffer convertFullStop(StringBuffer input) {
+        for (int i = 0; i < input.length(); i++) {
+            if (isLabelSeperator(input.charAt(i))) {
+                input.setCharAt(i, '.');
+            }
+        }
+        return input;
+    }
+    // END Android-added: Use ICU4J implementation
+
+    /**
+     * Translates a string from ASCII Compatible Encoding (ACE) to Unicode,
+     * as defined by the ToUnicode operation of <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a>.
+     *
+     * <p> This convenience method works as if by invoking the
+     * two-argument counterpart as follows:
+     * <blockquote>
+     * {@link #toUnicode(String, int) toUnicode}(input,&nbsp;0);
+     * </blockquote>
+     *
+     * @param input     the string to be processed
+     *
+     * @return          the translated {@code String}
+     */
+    public static String toUnicode(String input) {
+        return toUnicode(input, 0);
+    }
+
+
+    /* ---------------- Private members -------------- */
+
+    // Android-removed: Private helper methods, unused because we use ICU.
+    /*
+    // ACE Prefix is "xn--"
+    private static final String ACE_PREFIX = "xn--";
+    private static final int ACE_PREFIX_LENGTH = ACE_PREFIX.length();
+
+    private static final int MAX_LABEL_LENGTH   = 63;
+
+    // single instance of nameprep
+    private static StringPrep namePrep = null;
+
+    static {
+        InputStream stream = null;
+
+        try {
+            final String IDN_PROFILE = "uidna.spp";
+            if (System.getSecurityManager() != null) {
+                stream = AccessController.doPrivileged(new PrivilegedAction<InputStream>() {
+                    public InputStream run() {
+                        return StringPrep.class.getResourceAsStream(IDN_PROFILE);
+                    }
+                });
+            } else {
+                stream = StringPrep.class.getResourceAsStream(IDN_PROFILE);
+            }
+
+            namePrep = new StringPrep(stream);
+            stream.close();
+        } catch (IOException e) {
+            // should never reach here
+            assert false;
+        }
+    }
+    */
+
+    /* ---------------- Private operations -------------- */
+
+
+    //
+    // to suppress the default zero-argument constructor
+    //
+    private IDN() {}
+
+    // Android-removed: Private helper methods, unused because we use ICU.
+    /*
+    //
+    // toASCII operation; should only apply to a single label
+    //
+    private static String toASCIIInternal(String label, int flag)
+    {
+        // step 1
+        // Check if the string contains code points outside the ASCII range 0..0x7c.
+        boolean isASCII  = isAllASCII(label);
+        StringBuffer dest;
+
+        // step 2
+        // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here
+        if (!isASCII) {
+            UCharacterIterator iter = UCharacterIterator.getInstance(label);
+            try {
+                dest = namePrep.prepare(iter, flag);
+            } catch (java.text.ParseException e) {
+                throw new IllegalArgumentException(e);
+            }
+        } else {
+            dest = new StringBuffer(label);
+        }
+
+        // step 8, move forward to check the smallest number of the code points
+        // the length must be inside 1..63
+        if (dest.length() == 0) {
+            throw new IllegalArgumentException(
+                        "Empty label is not a legal name");
+        }
+
+        // step 3
+        // Verify the absence of non-LDH ASCII code points
+        //   0..0x2c, 0x2e..0x2f, 0x3a..0x40, 0x5b..0x60, 0x7b..0x7f
+        // Verify the absence of leading and trailing hyphen
+        boolean useSTD3ASCIIRules = ((flag & USE_STD3_ASCII_RULES) != 0);
+        if (useSTD3ASCIIRules) {
+            for (int i = 0; i < dest.length(); i++) {
+                int c = dest.charAt(i);
+                if (isNonLDHAsciiCodePoint(c)) {
+                    throw new IllegalArgumentException(
+                        "Contains non-LDH ASCII characters");
+                }
+            }
+
+            if (dest.charAt(0) == '-' ||
+                dest.charAt(dest.length() - 1) == '-') {
+
+                throw new IllegalArgumentException(
+                        "Has leading or trailing hyphen");
+            }
+        }
+
+        if (!isASCII) {
+            // step 4
+            // If all code points are inside 0..0x7f, skip to step 8
+            if (!isAllASCII(dest.toString())) {
+                // step 5
+                // verify the sequence does not begin with ACE prefix
+                if(!startsWithACEPrefix(dest)){
+
+                    // step 6
+                    // encode the sequence with punycode
+                    try {
+                        dest = Punycode.encode(dest, null);
+                    } catch (java.text.ParseException e) {
+                        throw new IllegalArgumentException(e);
+                    }
+
+                    dest = toASCIILower(dest);
+
+                    // step 7
+                    // prepend the ACE prefix
+                    dest.insert(0, ACE_PREFIX);
+                } else {
+                    throw new IllegalArgumentException("The input starts with the ACE Prefix");
+                }
+
+            }
+        }
+
+        // step 8
+        // the length must be inside 1..63
+        if (dest.length() > MAX_LABEL_LENGTH) {
+            throw new IllegalArgumentException("The label in the input is too long");
+        }
+
+        return dest.toString();
+    }
+
+    //
+    // toUnicode operation; should only apply to a single label
+    //
+    private static String toUnicodeInternal(String label, int flag) {
+        boolean[] caseFlags = null;
+        StringBuffer dest;
+
+        // step 1
+        // find out if all the codepoints in input are ASCII
+        boolean isASCII = isAllASCII(label);
+
+        if(!isASCII){
+            // step 2
+            // perform the nameprep operation; flag ALLOW_UNASSIGNED is used here
+            try {
+                UCharacterIterator iter = UCharacterIterator.getInstance(label);
+                dest = namePrep.prepare(iter, flag);
+            } catch (Exception e) {
+                // toUnicode never fails; if any step fails, return the input string
+                return label;
+            }
+        } else {
+            dest = new StringBuffer(label);
+        }
+
+        // step 3
+        // verify ACE Prefix
+        if(startsWithACEPrefix(dest)) {
+
+            // step 4
+            // Remove the ACE Prefix
+            String temp = dest.substring(ACE_PREFIX_LENGTH, dest.length());
+
+            try {
+                // step 5
+                // Decode using punycode
+                StringBuffer decodeOut = Punycode.decode(new StringBuffer(temp), null);
+
+                // step 6
+                // Apply toASCII
+                String toASCIIOut = toASCII(decodeOut.toString(), flag);
+
+                // step 7
+                // verify
+                if (toASCIIOut.equalsIgnoreCase(dest.toString())) {
+                    // step 8
+                    // return output of step 5
+                    return decodeOut.toString();
+                }
+            } catch (Exception ignored) {
+                // no-op
+            }
+        }
+
+        // just return the input
+        return label;
+    }
+
+
+    //
+    // LDH stands for "letter/digit/hyphen", with characters restricted to the
+    // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
+    // <->.
+    // Non LDH refers to characters in the ASCII range, but which are not
+    // letters, digits or the hypen.
+    //
+    // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
+    //
+    private static boolean isNonLDHAsciiCodePoint(int ch){
+        return (0x0000 <= ch && ch <= 0x002C) ||
+               (0x002E <= ch && ch <= 0x002F) ||
+               (0x003A <= ch && ch <= 0x0040) ||
+               (0x005B <= ch && ch <= 0x0060) ||
+               (0x007B <= ch && ch <= 0x007F);
+    }
+
+    //
+    // search dots in a string and return the index of that character;
+    // or if there is no dots, return the length of input string
+    // dots might be: \u002E (full stop), \u3002 (ideographic full stop), \uFF0E (fullwidth full stop),
+    // and \uFF61 (halfwidth ideographic full stop).
+    //
+    private static int searchDots(String s, int start) {
+        int i;
+        for (i = start; i < s.length(); i++) {
+            if (isLabelSeparator(s.charAt(i))) {
+                break;
+            }
+        }
+
+        return i;
+    }
+
+    //
+    // to check if a string is a root label, ".".
+    //
+    private static boolean isRootLabel(String s) {
+        return (s.length() == 1 && isLabelSeparator(s.charAt(0)));
+    }
+
+    //
+    // to check if a character is a label separator, i.e. a dot character.
+    //
+    private static boolean isLabelSeparator(char c) {
+        return (c == '.' || c == '\u3002' || c == '\uFF0E' || c == '\uFF61');
+    }
+
+    //
+    // to check if a string only contains US-ASCII code point
+    //
+    private static boolean isAllASCII(String input) {
+        boolean isASCII = true;
+        for (int i = 0; i < input.length(); i++) {
+            int c = input.charAt(i);
+            if (c > 0x7F) {
+                isASCII = false;
+                break;
+            }
+        }
+        return isASCII;
+    }
+
+    //
+    // to check if a string starts with ACE-prefix
+    //
+    private static boolean startsWithACEPrefix(StringBuffer input){
+        boolean startsWithPrefix = true;
+
+        if(input.length() < ACE_PREFIX_LENGTH){
+            return false;
+        }
+        for(int i = 0; i < ACE_PREFIX_LENGTH; i++){
+            if(toASCIILower(input.charAt(i)) != ACE_PREFIX.charAt(i)){
+                startsWithPrefix = false;
+            }
+        }
+        return startsWithPrefix;
+    }
+
+    private static char toASCIILower(char ch){
+        if('A' <= ch && ch <= 'Z'){
+            return (char)(ch + 'a' - 'A');
+        }
+        return ch;
+    }
+
+    private static StringBuffer toASCIILower(StringBuffer input){
+        StringBuffer dest = new StringBuffer();
+        for(int i = 0; i < input.length();i++){
+            dest.append(toASCIILower(input.charAt(i)));
+        }
+        return dest;
+    }
+    */
+}
diff --git a/java/net/InMemoryCookieStore.java b/java/net/InMemoryCookieStore.java
new file mode 100644
index 0000000..5df66c0
--- /dev/null
+++ b/java/net/InMemoryCookieStore.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import dalvik.system.VMRuntime;
+
+import java.util.List;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.concurrent.locks.ReentrantLock;
+
+// Android-changed: App compat changes and bug fixes
+// b/26456024 Add targetSdkVersion based compatibility for domain matching
+// b/33034917 Support clearing cookies by adding it with "max-age=0"
+// b/25897688 InMemoryCookieStore ignores scheme (http/https) port and path of the cookie
+// Remove cookieJar and domainIndex. Use urlIndex as single Cookie storage
+// Fix InMemoryCookieStore#remove to verify cookie URI before removal
+// Fix InMemoryCookieStore#removeAll to return false if it's empty.
+/**
+ * A simple in-memory java.net.CookieStore implementation
+ *
+ * @author Edward Wang
+ * @since 1.6
+ * @hide Visible for testing only.
+ */
+public class InMemoryCookieStore implements CookieStore {
+    // the in-memory representation of cookies
+    // BEGIN Android-removed: Remove cookieJar and domainIndex
+    /*
+    private List<HttpCookie> cookieJar = null;
+
+    // the cookies are indexed by its domain and associated uri (if present)
+    // CAUTION: when a cookie removed from main data structure (i.e. cookieJar),
+    //          it won't be cleared in domainIndex & uriIndex. Double-check the
+    //          presence of cookie when retrieve one form index store.
+    private Map<String, List<HttpCookie>> domainIndex = null;
+    */
+    // END Android-removed: Remove cookieJar and domainIndex
+    private Map<URI, List<HttpCookie>> uriIndex = null;
+
+    // use ReentrantLock instead of syncronized for scalability
+    private ReentrantLock lock = null;
+
+    // BEGIN Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex
+    private final boolean applyMCompatibility;
+
+    /**
+     * The default ctor
+     */
+    public InMemoryCookieStore() {
+        this(VMRuntime.getRuntime().getTargetSdkVersion());
+    }
+
+    public InMemoryCookieStore(int targetSdkVersion) {
+        uriIndex = new HashMap<>();
+        lock = new ReentrantLock(false);
+        applyMCompatibility = (targetSdkVersion <= 23);
+    }
+    // END Android-changed: Add targetSdkVersion and remove cookieJar and domainIndex
+
+    /**
+     * Add one cookie into cookie store.
+     */
+    public void add(URI uri, HttpCookie cookie) {
+        // pre-condition : argument can't be null
+        if (cookie == null) {
+            throw new NullPointerException("cookie is null");
+        }
+
+        lock.lock();
+        try {
+            // Android-changed: http://b/33034917, android supports clearing cookies
+            // by adding the cookie with max-age: 0.
+            //if (cookie.getMaxAge() != 0) {
+            addIndex(uriIndex, getEffectiveURI(uri), cookie);
+            //}
+        } finally {
+            lock.unlock();
+        }
+    }
+
+
+    /**
+     * Get all cookies, which:
+     *  1) given uri domain-matches with, or, associated with
+     *     given uri when added to the cookie store.
+     *  3) not expired.
+     * See RFC 2965 sec. 3.3.4 for more detail.
+     */
+    public List<HttpCookie> get(URI uri) {
+        // argument can't be null
+        if (uri == null) {
+            throw new NullPointerException("uri is null");
+        }
+
+        List<HttpCookie> cookies = new ArrayList<HttpCookie>();
+        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        lock.lock();
+        try {
+            // check domainIndex first
+            getInternal1(cookies, uriIndex, uri.getHost());
+            // check uriIndex then
+            getInternal2(cookies, uriIndex, getEffectiveURI(uri));
+        } finally {
+            lock.unlock();
+        }
+        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        return cookies;
+    }
+
+    /**
+     * Get all cookies in cookie store, except those have expired
+     */
+    public List<HttpCookie> getCookies() {
+        // BEGIN Android-changed: Remove cookieJar and domainIndex
+        List<HttpCookie> rt = new ArrayList<HttpCookie>();
+
+        lock.lock();
+        try {
+            for (List<HttpCookie> list : uriIndex.values()) {
+                Iterator<HttpCookie> it = list.iterator();
+                while (it.hasNext()) {
+                    HttpCookie cookie = it.next();
+                    if (cookie.hasExpired()) {
+                        it.remove();
+                    } else if (!rt.contains(cookie)) {
+                        rt.add(cookie);
+                    }
+                }
+            }
+        } finally {
+            rt = Collections.unmodifiableList(rt);
+            lock.unlock();
+        }
+        // END Android-changed: Remove cookieJar and domainIndex
+
+        return rt;
+    }
+
+    /**
+     * Get all URIs, which are associated with at least one cookie
+     * of this cookie store.
+     */
+    public List<URI> getURIs() {
+        // BEGIN Android-changed: App compat. Return URI with no cookies. http://b/65538736
+        /*
+        List<URI> uris = new ArrayList<URI>();
+
+        lock.lock();
+        try {
+            Iterator<URI> it = uriIndex.keySet().iterator();
+            while (it.hasNext()) {
+                URI uri = it.next();
+                List<HttpCookie> cookies = uriIndex.get(uri);
+                if (cookies == null || cookies.size() == 0) {
+                    // no cookies list or an empty list associated with
+                    // this uri entry, delete it
+                    it.remove();
+                }
+            }
+        } finally {
+            uris.addAll(uriIndex.keySet());
+            lock.unlock();
+        }
+
+        return uris;
+         */
+        lock.lock();
+        try {
+            List<URI> result = new ArrayList<URI>(uriIndex.keySet());
+            result.remove(null);
+            return Collections.unmodifiableList(result);
+        } finally {
+            lock.unlock();
+        }
+        // END Android-changed: App compat. Return URI with no cookies. http://b/65538736
+    }
+
+
+    /**
+     * Remove a cookie from store
+     */
+    public boolean remove(URI uri, HttpCookie ck) {
+        // argument can't be null
+        if (ck == null) {
+            throw new NullPointerException("cookie is null");
+        }
+
+        // BEGIN Android-changed: Fix uri not being removed from uriIndex
+        lock.lock();
+        try {
+            uri = getEffectiveURI(uri);
+            if (uriIndex.get(uri) == null) {
+                return false;
+            } else {
+                List<HttpCookie> cookies = uriIndex.get(uri);
+                if (cookies != null) {
+                    return cookies.remove(ck);
+                } else {
+                    return false;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+        // END Android-changed: Fix uri not being removed from uriIndex
+    }
+
+
+    /**
+     * Remove all cookies in this cookie store.
+     */
+    public boolean removeAll() {
+        lock.lock();
+        // BEGIN Android-changed: Let removeAll() return false when there are no cookies.
+        boolean result = false;
+
+        try {
+            result = !uriIndex.isEmpty();
+            uriIndex.clear();
+        } finally {
+            lock.unlock();
+        }
+
+        return result;
+        // END Android-changed: Let removeAll() return false when there are no cookies.
+    }
+
+
+    /* ---------------- Private operations -------------- */
+
+
+    /*
+     * This is almost the same as HttpCookie.domainMatches except for
+     * one difference: It won't reject cookies when the 'H' part of the
+     * domain contains a dot ('.').
+     * I.E.: RFC 2965 section 3.3.2 says that if host is x.y.domain.com
+     * and the cookie domain is .domain.com, then it should be rejected.
+     * However that's not how the real world works. Browsers don't reject and
+     * some sites, like yahoo.com do actually expect these cookies to be
+     * passed along.
+     * And should be used for 'old' style cookies (aka Netscape type of cookies)
+     */
+    private boolean netscapeDomainMatches(String domain, String host)
+    {
+        if (domain == null || host == null) {
+            return false;
+        }
+
+        // if there's no embedded dot in domain and domain is not .local
+        boolean isLocalDomain = ".local".equalsIgnoreCase(domain);
+        int embeddedDotInDomain = domain.indexOf('.');
+        if (embeddedDotInDomain == 0) {
+            embeddedDotInDomain = domain.indexOf('.', 1);
+        }
+        if (!isLocalDomain && (embeddedDotInDomain == -1 || embeddedDotInDomain == domain.length() - 1)) {
+            return false;
+        }
+
+        // if the host name contains no dot and the domain name is .local
+        int firstDotInHost = host.indexOf('.');
+        if (firstDotInHost == -1 && isLocalDomain) {
+            return true;
+        }
+
+        int domainLength = domain.length();
+        int lengthDiff = host.length() - domainLength;
+        if (lengthDiff == 0) {
+            // if the host name and the domain name are just string-compare euqal
+            return host.equalsIgnoreCase(domain);
+        } else if (lengthDiff > 0) {
+            // need to check H & D component
+            String D = host.substring(lengthDiff);
+
+            // Android-changed: b/26456024 targetSdkVersion based compatibility for domain matching
+            // Android M and earlier: Cookies with domain "foo.com" would not match "bar.foo.com".
+            // The RFC dictates that the user agent must treat those domains as if they had a
+            // leading period and must therefore match "bar.foo.com".
+            if (applyMCompatibility && !domain.startsWith(".")) {
+                return false;
+            }
+
+            return (D.equalsIgnoreCase(domain));
+        } else if (lengthDiff == -1) {
+            // if domain is actually .host
+            return (domain.charAt(0) == '.' &&
+                    host.equalsIgnoreCase(domain.substring(1)));
+        }
+
+        return false;
+    }
+
+    private void getInternal1(List<HttpCookie> cookies, Map<URI, List<HttpCookie>> cookieIndex,
+            String host) {
+        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // Use a separate list to handle cookies that need to be removed so
+        // that there is no conflict with iterators.
+        ArrayList<HttpCookie> toRemove = new ArrayList<HttpCookie>();
+        for (Map.Entry<URI, List<HttpCookie>> entry : cookieIndex.entrySet()) {
+            List<HttpCookie> lst = entry.getValue();
+            for (HttpCookie c : lst) {
+                String domain = c.getDomain();
+                if ((c.getVersion() == 0 && netscapeDomainMatches(domain, host)) ||
+                        (c.getVersion() == 1 && HttpCookie.domainMatches(domain, host))) {
+
+                    // the cookie still in main cookie store
+                    if (!c.hasExpired()) {
+                        // don't add twice
+                        if (!cookies.contains(c)) {
+                            cookies.add(c);
+                        }
+                    } else {
+                        toRemove.add(c);
+                    }
+                }
+            }
+            // Clear up the cookies that need to be removed
+            for (HttpCookie c : toRemove) {
+                lst.remove(c);
+
+            }
+            toRemove.clear();
+        }
+        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+    }
+
+    // @param cookies           [OUT] contains the found cookies
+    // @param cookieIndex       the index
+    // @param comparator        the prediction to decide whether or not
+    //                          a cookie in index should be returned
+    private <T extends Comparable<T>>
+        void getInternal2(List<HttpCookie> cookies, Map<T, List<HttpCookie>> cookieIndex,
+                          T comparator)
+    {
+        // BEGIN Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+        // Removed cookieJar
+        for (T index : cookieIndex.keySet()) {
+            if ((index == comparator) || (index != null && comparator.compareTo(index) == 0)) {
+                List<HttpCookie> indexedCookies = cookieIndex.get(index);
+                // check the list of cookies associated with this domain
+                if (indexedCookies != null) {
+                    Iterator<HttpCookie> it = indexedCookies.iterator();
+                    while (it.hasNext()) {
+                        HttpCookie ck = it.next();
+                        // the cookie still in main cookie store
+                        if (!ck.hasExpired()) {
+                            // don't add twice
+                            if (!cookies.contains(ck))
+                                cookies.add(ck);
+                        } else {
+                            it.remove();
+                        }
+                    }
+                } // end of indexedCookies != null
+            } // end of comparator.compareTo(index) == 0
+        } // end of cookieIndex iteration
+        // END Android-changed: b/25897688 InMemoryCookieStore ignores scheme (http/https)
+    }
+
+    // add 'cookie' indexed by 'index' into 'indexStore'
+    private <T> void addIndex(Map<T, List<HttpCookie>> indexStore,
+                              T index,
+                              HttpCookie cookie)
+    {
+        // Android-changed: "index" can be null. We only use the URI based
+        // index on Android and we want to support null URIs. The underlying
+        // store is a HashMap which will support null keys anyway.
+        // if (index != null) {
+        List<HttpCookie> cookies = indexStore.get(index);
+        if (cookies != null) {
+            // there may already have the same cookie, so remove it first
+            cookies.remove(cookie);
+
+            cookies.add(cookie);
+        } else {
+            cookies = new ArrayList<HttpCookie>();
+            cookies.add(cookie);
+            indexStore.put(index, cookies);
+        }
+    }
+
+
+    //
+    // for cookie purpose, the effective uri should only be http://host
+    // the path will be taken into account when path-match algorithm applied
+    //
+    private URI getEffectiveURI(URI uri) {
+        URI effectiveURI = null;
+        // Android-added: Fix NullPointerException
+        if (uri == null) {
+            return null;
+        }
+        try {
+            effectiveURI = new URI("http",
+                                   uri.getHost(),
+                                   null,  // path component
+                                   null,  // query component
+                                   null   // fragment component
+                                  );
+        } catch (URISyntaxException ignored) {
+            effectiveURI = uri;
+        }
+
+        return effectiveURI;
+    }
+}
diff --git a/java/net/Inet4Address.annotated.java b/java/net/Inet4Address.annotated.java
new file mode 100644
index 0000000..e10debf
--- /dev/null
+++ b/java/net/Inet4Address.annotated.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.io.ObjectStreamException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Inet4Address extends java.net.InetAddress {
+
+Inet4Address() { throw new RuntimeException("Stub!"); }
+
+public boolean isMulticastAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnyLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLinkLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isSiteLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCGlobal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCNodeLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCLinkLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCSiteLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCOrgLocal() { throw new RuntimeException("Stub!"); }
+
+public byte[] getAddress() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostAddress() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static final java.net.InetAddress ALL;
+static { ALL = null; }
+
[email protected]
+public static final java.net.InetAddress ANY;
+static { ANY = null; }
+
[email protected]
+public static final java.net.InetAddress LOOPBACK;
+static { LOOPBACK = null; }
+}
+
diff --git a/java/net/Inet4Address.java b/java/net/Inet4Address.java
new file mode 100644
index 0000000..1fb7b92
--- /dev/null
+++ b/java/net/Inet4Address.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.ObjectStreamException;
+import static android.system.OsConstants.*;
+
+/**
+ * This class represents an Internet Protocol version 4 (IPv4) address.
+ * Defined by <a href="http://www.ietf.org/rfc/rfc790.txt">
+ * <i>RFC&nbsp;790: Assigned Numbers</i></a>,
+ * <a href="http://www.ietf.org/rfc/rfc1918.txt">
+ * <i>RFC&nbsp;1918: Address Allocation for Private Internets</i></a>,
+ * and <a href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC&nbsp;2365:
+ * Administratively Scoped IP Multicast</i></a>
+ *
+ * <h3> <A NAME="format">Textual representation of IP addresses</a> </h3>
+ *
+ * Textual representation of IPv4 address used as input to methods
+ * takes one of the following forms:
+ *
+ * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ * <tr><td>{@code d.d.d.d}</td></tr>
+ * <tr><td>{@code d.d.d}</td></tr>
+ * <tr><td>{@code d.d}</td></tr>
+ * <tr><td>{@code d}</td></tr>
+ * </table></blockquote>
+ *
+ * <p> When four parts are specified, each is interpreted as a byte of
+ * data and assigned, from left to right, to the four bytes of an IPv4
+ * address.
+
+ * <p> When a three part address is specified, the last part is
+ * interpreted as a 16-bit quantity and placed in the right most two
+ * bytes of the network address. This makes the three part address
+ * format convenient for specifying Class B net- work addresses as
+ * 128.net.host.
+ *
+ * <p> When a two part address is supplied, the last part is
+ * interpreted as a 24-bit quantity and placed in the right most three
+ * bytes of the network address. This makes the two part address
+ * format convenient for specifying Class A network addresses as
+ * net.host.
+ *
+ * <p> When only one part is given, the value is stored directly in
+ * the network address without any byte rearrangement.
+ *
+ * <p> For methods that return a textual representation as output
+ * value, the first form, i.e. a dotted-quad string, is used.
+ *
+ * <h4> The Scope of a Multicast Address </h4>
+ *
+ * Historically the IPv4 TTL field in the IP header has doubled as a
+ * multicast scope field: a TTL of 0 means node-local, 1 means
+ * link-local, up through 32 means site-local, up through 64 means
+ * region-local, up through 128 means continent-local, and up through
+ * 255 are global. However, the administrative scoping is preferred.
+ * Please refer to <a href="http://www.ietf.org/rfc/rfc2365.txt">
+ * <i>RFC&nbsp;2365: Administratively Scoped IP Multicast</i></a>
+ * @since 1.4
+ */
+
+public final
+class Inet4Address extends InetAddress {
+    final static int INADDRSZ = 4;
+
+    /** use serialVersionUID from InetAddress, but Inet4Address instance
+     *  is always replaced by an InetAddress instance before being
+     *  serialized */
+    private static final long serialVersionUID = 3286316764910316507L;
+
+    // BEGIN Android-added: Define special-purpose IPv4 address
+    /** @hide */
+    public static final InetAddress ANY = new Inet4Address(null, new byte[] { 0, 0, 0, 0 });
+
+    /** @hide */
+    public static final InetAddress ALL =
+            new Inet4Address(null, new byte[] { (byte) 255, (byte) 255,
+                  (byte) 255, (byte) 255 });
+    /** @hide */
+    public static final InetAddress LOOPBACK =
+            new Inet4Address("localhost", new byte[] { 127, 0, 0, 1 });
+    // END Android-added: Define special-purpose IPv4 address
+
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+     * Perform initializations.
+     *
+    static {
+        init();
+    }
+    */
+    // END Android-removed: Android doesn't need to call native init
+    Inet4Address() {
+        super();
+        holder().hostName = null;
+        holder().address = 0;
+        holder().family = AF_INET;
+    }
+
+    Inet4Address(String hostName, byte addr[]) {
+        holder().hostName = hostName;
+        holder().family = AF_INET;
+        if (addr != null) {
+            if (addr.length == INADDRSZ) {
+                int address  = addr[3] & 0xFF;
+                address |= ((addr[2] << 8) & 0xFF00);
+                address |= ((addr[1] << 16) & 0xFF0000);
+                address |= ((addr[0] << 24) & 0xFF000000);
+                holder().address = address;
+            }
+        }
+        holder().originalHostName = hostName;
+    }
+    Inet4Address(String hostName, int address) {
+        holder().hostName = hostName;
+        holder().family = AF_INET;
+        holder().address = address;
+        holder().originalHostName = hostName;
+    }
+
+    /**
+     * Replaces the object to be serialized with an InetAddress object.
+     *
+     * @return the alternate object to be serialized.
+     *
+     * @throws ObjectStreamException if a new object replacing this
+     * object could not be created
+     */
+    private Object writeReplace() throws ObjectStreamException {
+        // will replace the to be serialized 'this' object
+        InetAddress inet = new InetAddress();
+        inet.holder().hostName = holder().getHostName();
+        inet.holder().address = holder().getAddress();
+
+        /**
+         * Prior to 1.4 an InetAddress was created with a family
+         * based on the platform AF_INET value (usually 2).
+         * For compatibility reasons we must therefore write the
+         * the InetAddress with this family.
+         */
+        inet.holder().family = 2;
+
+        return inet;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an
+     * IP multicast address. IP multicast address is a Class D
+     * address i.e first four bits of the address are 1110.
+     * @return a {@code boolean} indicating if the InetAddress is
+     * an IP multicast address
+     * @since   JDK1.1
+     */
+    public boolean isMulticastAddress() {
+        return ((holder().getAddress() & 0xf0000000) == 0xe0000000);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress in a wildcard address.
+     * @return a {@code boolean} indicating if the Inetaddress is
+     *         a wildcard address.
+     * @since 1.4
+     */
+    public boolean isAnyLocalAddress() {
+        return holder().getAddress() == 0;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a loopback address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a loopback address; or false otherwise.
+     * @since 1.4
+     */
+    public boolean isLoopbackAddress() {
+        /* 127.x.x.x */
+        byte[] byteAddr = getAddress();
+        return byteAddr[0] == 127;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an link local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a link local address; or false if address is not a link local unicast address.
+     * @since 1.4
+     */
+    public boolean isLinkLocalAddress() {
+        // link-local unicast in IPv4 (169.254.0.0/16)
+        // defined in "Documenting Special Use IPv4 Address Blocks
+        // that have been Registered with IANA" by Bill Manning
+        // draft-manning-dsua-06.txt
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 169)
+            && (((address >>> 16) & 0xFF) == 254);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a site local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a site local address; or false if address is not a site local unicast address.
+     * @since 1.4
+     */
+    public boolean isSiteLocalAddress() {
+        // refer to RFC 1918
+        // 10/8 prefix
+        // 172.16/12 prefix
+        // 192.168/16 prefix
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 10)
+            || ((((address >>> 24) & 0xFF) == 172)
+                && (((address >>> 16) & 0xF0) == 16))
+            || ((((address >>> 24) & 0xFF) == 192)
+                && (((address >>> 16) & 0xFF) == 168));
+    }
+
+    /**
+     * Utility routine to check if the multicast address has global scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of global scope, false if it is not
+     *         of global scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCGlobal() {
+        // 224.0.1.0 to 238.255.255.255
+        byte[] byteAddr = getAddress();
+        return ((byteAddr[0] & 0xff) >= 224 && (byteAddr[0] & 0xff) <= 238 ) &&
+            !((byteAddr[0] & 0xff) == 224 && byteAddr[1] == 0 &&
+              byteAddr[2] == 0);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has node scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of node-local scope, false if it is not
+     *         of node-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCNodeLocal() {
+        // unless ttl == 0
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has link scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of link-local scope, false if it is not
+     *         of link-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCLinkLocal() {
+        // 224.0.0/24 prefix and ttl == 1
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 224)
+            && (((address >>> 16) & 0xFF) == 0)
+            && (((address >>> 8) & 0xFF) == 0);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has site scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of site-local scope, false if it is not
+     *         of site-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCSiteLocal() {
+        // 239.255/16 prefix or ttl < 32
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 239)
+            && (((address >>> 16) & 0xFF) == 255);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has organization scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of organization-local scope,
+     *         false if it is not of organization-local scope
+     *         or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCOrgLocal() {
+        // 239.192 - 239.195
+        int address = holder().getAddress();
+        return (((address >>> 24) & 0xFF) == 239)
+            && (((address >>> 16) & 0xFF) >= 192)
+            && (((address >>> 16) & 0xFF) <= 195);
+    }
+
+    /**
+     * Returns the raw IP address of this {@code InetAddress}
+     * object. The result is in network byte order: the highest order
+     * byte of the address is in {@code getAddress()[0]}.
+     *
+     * @return  the raw IP address of this object.
+     */
+    public byte[] getAddress() {
+        int address = holder().getAddress();
+        byte[] addr = new byte[INADDRSZ];
+
+        addr[0] = (byte) ((address >>> 24) & 0xFF);
+        addr[1] = (byte) ((address >>> 16) & 0xFF);
+        addr[2] = (byte) ((address >>> 8) & 0xFF);
+        addr[3] = (byte) (address & 0xFF);
+        return addr;
+    }
+
+    /**
+     * Returns the IP address string in textual presentation form.
+     *
+     * @return  the raw IP address in a string format.
+     * @since   JDK1.0.2
+     */
+    public String getHostAddress() {
+        return numericToTextFormat(getAddress());
+    }
+
+    /**
+     * Returns a hashcode for this IP address.
+     *
+     * @return  a hash code value for this IP address.
+     */
+    public int hashCode() {
+        return holder().getAddress();
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same IP address as
+     * this object.
+     * <p>
+     * Two instances of {@code InetAddress} represent the same IP
+     * address if the length of the byte arrays returned by
+     * {@code getAddress} is the same for both, and each of the
+     * array components is the same for the byte arrays.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InetAddress#getAddress()
+     */
+    public boolean equals(Object obj) {
+        return (obj != null) && (obj instanceof Inet4Address) &&
+            (((InetAddress)obj).holder().getAddress() == holder().getAddress());
+    }
+
+    // Utilities
+    /*
+     * Converts IPv4 binary address into a string suitable for presentation.
+     *
+     * @param src a byte array representing an IPv4 numeric address
+     * @return a String representing the IPv4 address in
+     *         textual representation format
+     * @since 1.4
+     */
+
+    static String numericToTextFormat(byte[] src)
+    {
+        return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff);
+    }
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+     * Perform class load-time initializations.
+     *
+    private static native void init();
+    */
+    // END Android-removed: Android doesn't need to call native init
+}
diff --git a/java/net/Inet6Address.annotated.java b/java/net/Inet6Address.annotated.java
new file mode 100644
index 0000000..7888710
--- /dev/null
+++ b/java/net/Inet6Address.annotated.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+
[email protected]
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Inet6Address extends java.net.InetAddress {
+
+Inet6Address() { throw new RuntimeException("Stub!"); }
+
+public static java.net.Inet6Address getByAddress(java.lang.String host, byte[] addr, java.net.NetworkInterface nif) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.Inet6Address getByAddress(java.lang.String host, byte[] addr, int scope_id) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public boolean isMulticastAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnyLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLinkLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isSiteLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCGlobal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCNodeLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCLinkLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCSiteLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCOrgLocal() { throw new RuntimeException("Stub!"); }
+
+public byte[] getAddress() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public int getScopeId() { throw new RuntimeException("Stub!"); }
+
+public java.net.NetworkInterface getScopedInterface() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostAddress() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public boolean isIPv4CompatibleAddress() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static final java.net.InetAddress ANY;
+static { ANY = null; }
+
[email protected]
+public static final java.net.InetAddress LOOPBACK;
+static { LOOPBACK = null; }
+}
diff --git a/java/net/Inet6Address.java b/java/net/Inet6Address.java
new file mode 100644
index 0000000..c0aadb3
--- /dev/null
+++ b/java/net/Inet6Address.java
@@ -0,0 +1,981 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.util.Enumeration;
+import java.util.Arrays;
+import libcore.io.Libcore;
+import static android.system.OsConstants.*;
+
+/**
+ * This class represents an Internet Protocol version 6 (IPv6) address.
+ * Defined by <a href="http://www.ietf.org/rfc/rfc2373.txt">
+ * <i>RFC&nbsp;2373: IP Version 6 Addressing Architecture</i></a>.
+ *
+ * <h3> <A NAME="format">Textual representation of IP addresses</a> </h3>
+ *
+ * Textual representation of IPv6 address used as input to methods
+ * takes one of the following forms:
+ *
+ * <ol>
+ *   <li><p> <A NAME="lform">The preferred form</a> is x:x:x:x:x:x:x:x,
+ *   where the 'x's are
+ *   the hexadecimal values of the eight 16-bit pieces of the
+ *   address. This is the full form.  For example,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code 1080:0:0:0:8:800:200C:417A}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> Note that it is not necessary to write the leading zeros in
+ *   an individual field. However, there must be at least one numeral
+ *   in every field, except as described below.</li>
+ *
+ *   <li><p> Due to some methods of allocating certain styles of IPv6
+ *   addresses, it will be common for addresses to contain long
+ *   strings of zero bits. In order to make writing addresses
+ *   containing zero bits easier, a special syntax is available to
+ *   compress the zeros. The use of "::" indicates multiple groups
+ *   of 16-bits of zeros. The "::" can only appear once in an address.
+ *   The "::" can also be used to compress the leading and/or trailing
+ *   zeros in an address. For example,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code 1080::8:800:200C:417A}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <li><p> An alternative form that is sometimes more convenient
+ *   when dealing with a mixed environment of IPv4 and IPv6 nodes is
+ *   x:x:x:x:x:x:d.d.d.d, where the 'x's are the hexadecimal values
+ *   of the six high-order 16-bit pieces of the address, and the 'd's
+ *   are the decimal values of the four low-order 8-bit pieces of the
+ *   standard IPv4 representation address, for example,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::FFFF:129.144.52.38}<td></tr>
+ *   <tr><td>{@code ::129.144.52.38}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> where "::FFFF:d.d.d.d" and "::d.d.d.d" are, respectively, the
+ *   general forms of an IPv4-mapped IPv6 address and an
+ *   IPv4-compatible IPv6 address. Note that the IPv4 portion must be
+ *   in the "d.d.d.d" form. The following forms are invalid:
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::FFFF:d.d.d}<td></tr>
+ *   <tr><td>{@code ::FFFF:d.d}<td></tr>
+ *   <tr><td>{@code ::d.d.d}<td></tr>
+ *   <tr><td>{@code ::d.d}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> The following form:
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::FFFF:d}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> is valid, however it is an unconventional representation of
+ *   the IPv4-compatible IPv6 address,
+ *
+ *   <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ *   <tr><td>{@code ::255.255.0.d}<td></tr>
+ *   </table></blockquote>
+ *
+ *   <p> while "::d" corresponds to the general IPv6 address
+ *   "0:0:0:0:0:0:0:d".</li>
+ * </ol>
+ *
+ * <p> For methods that return a textual representation as output
+ * value, the full form is used. Inet6Address will return the full
+ * form because it is unambiguous when used in combination with other
+ * textual data.
+ *
+ * <h4> Special IPv6 address </h4>
+ *
+ * <blockquote>
+ * <table cellspacing=2 summary="Description of IPv4-mapped address">
+ * <tr><th valign=top><i>IPv4-mapped address</i></th>
+ *         <td>Of the form::ffff:w.x.y.z, this IPv6 address is used to
+ *         represent an IPv4 address. It allows the native program to
+ *         use the same address data structure and also the same
+ *         socket when communicating with both IPv4 and IPv6 nodes.
+ *
+ *         <p>In InetAddress and Inet6Address, it is used for internal
+ *         representation; it has no functional role. Java will never
+ *         return an IPv4-mapped address.  These classes can take an
+ *         IPv4-mapped address as input, both in byte array and text
+ *         representation. However, it will be converted into an IPv4
+ *         address.</td></tr>
+ * </table></blockquote>
+ *
+ * <h4><A NAME="scoped">Textual representation of IPv6 scoped addresses</a></h4>
+ *
+ * <p> The textual representation of IPv6 addresses as described above can be
+ * extended to specify IPv6 scoped addresses. This extension to the basic
+ * addressing architecture is described in [draft-ietf-ipngwg-scoping-arch-04.txt].
+ *
+ * <p> Because link-local and site-local addresses are non-global, it is possible
+ * that different hosts may have the same destination address and may be
+ * reachable through different interfaces on the same originating system. In
+ * this case, the originating system is said to be connected to multiple zones
+ * of the same scope. In order to disambiguate which is the intended destination
+ * zone, it is possible to append a zone identifier (or <i>scope_id</i>) to an
+ * IPv6 address.
+ *
+ * <p> The general format for specifying the <i>scope_id</i> is the following:
+ *
+ * <blockquote><i>IPv6-address</i>%<i>scope_id</i></blockquote>
+ * <p> The IPv6-address is a literal IPv6 address as described above.
+ * The <i>scope_id</i> refers to an interface on the local system, and it can be
+ * specified in two ways.
+ * <ol><li><i>As a numeric identifier.</i> This must be a positive integer
+ * that identifies the particular interface and scope as understood by the
+ * system. Usually, the numeric values can be determined through administration
+ * tools on the system. Each interface may have multiple values, one for each
+ * scope. If the scope is unspecified, then the default value used is zero.</li>
+ * <li><i>As a string.</i> This must be the exact string that is returned by
+ * {@link java.net.NetworkInterface#getName()} for the particular interface in
+ * question. When an Inet6Address is created in this way, the numeric scope-id
+ * is determined at the time the object is created by querying the relevant
+ * NetworkInterface.</li></ol>
+ *
+ * <p> Note also, that the numeric <i>scope_id</i> can be retrieved from
+ * Inet6Address instances returned from the NetworkInterface class. This can be
+ * used to find out the current scope ids configured on the system.
+ * @since 1.4
+ */
+
+public final
+class Inet6Address extends InetAddress {
+    final static int INADDRSZ = 16;
+
+    // BEGIN Android-removed: Remove special handling for link-local addresses
+    /*
+    * cached scope_id - for link-local address use only.
+    *
+    private transient int cached_scope_id;  // 0
+    */
+    // END Android-removed: Remove special handling for link-local addresses
+
+    // BEGIN Android-added: Define special-purpose IPv6 address
+    /** @hide */
+    public static final InetAddress ANY =
+            new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
+
+    /** @hide */
+    public static final InetAddress LOOPBACK = new Inet6Address("ip6-localhost",
+            new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 0);
+    // END Android-added: Define special-purpose IPv6 address
+
+    private class Inet6AddressHolder {
+
+        private Inet6AddressHolder() {
+            ipaddress = new byte[INADDRSZ];
+        }
+
+        private Inet6AddressHolder(
+            byte[] ipaddress, int scope_id, boolean scope_id_set,
+            NetworkInterface ifname, boolean scope_ifname_set)
+        {
+            this.ipaddress = ipaddress;
+            this.scope_id = scope_id;
+            this.scope_id_set = scope_id_set;
+            this.scope_ifname_set = scope_ifname_set;
+            this.scope_ifname = ifname;
+        }
+
+        /**
+         * Holds a 128-bit (16 bytes) IPv6 address.
+         */
+        byte[] ipaddress;
+
+        /**
+         * scope_id. The scope specified when the object is created. If the object
+         * is created with an interface name, then the scope_id is not determined
+         * until the time it is needed.
+         */
+        int scope_id;  // 0
+
+        /**
+         * This will be set to true when the scope_id field contains a valid
+         * integer scope_id.
+         */
+        boolean scope_id_set;  // false
+
+        /**
+         * scoped interface. scope_id is derived from this as the scope_id of the first
+         * address whose scope is the same as this address for the named interface.
+         */
+        NetworkInterface scope_ifname;  // null
+
+        /**
+         * set if the object is constructed with a scoped
+         * interface instead of a numeric scope id.
+         */
+        boolean scope_ifname_set; // false;
+
+        void setAddr(byte addr[]) {
+            if (addr.length == INADDRSZ) { // normal IPv6 address
+                System.arraycopy(addr, 0, ipaddress, 0, INADDRSZ);
+            }
+        }
+
+        void init(byte addr[], int scope_id) {
+            setAddr(addr);
+
+            // Android-changed: was >= 0
+            if (scope_id > 0) {
+                this.scope_id = scope_id;
+                this.scope_id_set = true;
+            }
+        }
+
+        void init(byte addr[], NetworkInterface nif)
+            throws UnknownHostException
+        {
+            setAddr(addr);
+
+            if (nif != null) {
+                this.scope_id = deriveNumericScope(ipaddress, nif);
+                this.scope_id_set = true;
+                this.scope_ifname = nif;
+                this.scope_ifname_set = true;
+            }
+        }
+
+        // Android-removed: getnameinfo returns smarter representations than getHostAddress()
+        /*
+        String getHostAddress() {
+            String s = numericToTextFormat(ipaddress);
+            if (scope_ifname != null) { // must check this first
+                s = s + "%" + scope_ifname.getName();
+            } else if (scope_id_set) {
+                s = s + "%" + scope_id;
+            }
+            return s;
+        }
+        */
+
+        public boolean equals(Object o) {
+            if (! (o instanceof Inet6AddressHolder)) {
+                return false;
+            }
+            Inet6AddressHolder that = (Inet6AddressHolder)o;
+
+            return Arrays.equals(this.ipaddress, that.ipaddress);
+        }
+
+        public int hashCode() {
+            if (ipaddress != null) {
+
+                int hash = 0;
+                int i=0;
+                while (i<INADDRSZ) {
+                    int j=0;
+                    int component=0;
+                    while (j<4 && i<INADDRSZ) {
+                        component = (component << 8) + ipaddress[i];
+                        j++;
+                        i++;
+                    }
+                    hash += component;
+                }
+                return hash;
+
+            } else {
+                return 0;
+            }
+        }
+
+        boolean isIPv4CompatibleAddress() {
+            if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) &&
+                (ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) &&
+                (ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) &&
+                (ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) &&
+                (ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) &&
+                (ipaddress[10] == 0x00) && (ipaddress[11] == 0x00))  {
+                return true;
+            }
+            return false;
+        }
+
+        boolean isMulticastAddress() {
+            return ((ipaddress[0] & 0xff) == 0xff);
+        }
+
+        boolean isAnyLocalAddress() {
+            byte test = 0x00;
+            for (int i = 0; i < INADDRSZ; i++) {
+                test |= ipaddress[i];
+            }
+            return (test == 0x00);
+        }
+
+        boolean isLoopbackAddress() {
+            byte test = 0x00;
+            for (int i = 0; i < 15; i++) {
+                test |= ipaddress[i];
+            }
+            return (test == 0x00) && (ipaddress[15] == 0x01);
+        }
+
+        boolean isLinkLocalAddress() {
+            return ((ipaddress[0] & 0xff) == 0xfe
+                    && (ipaddress[1] & 0xc0) == 0x80);
+        }
+
+
+        boolean isSiteLocalAddress() {
+            return ((ipaddress[0] & 0xff) == 0xfe
+                    && (ipaddress[1] & 0xc0) == 0xc0);
+        }
+
+        boolean isMCGlobal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x0e);
+        }
+
+        boolean isMCNodeLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x01);
+        }
+
+        boolean isMCLinkLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x02);
+        }
+
+        boolean isMCSiteLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x05);
+        }
+
+        boolean isMCOrgLocal() {
+            return ((ipaddress[0] & 0xff) == 0xff
+                    && (ipaddress[1] & 0x0f) == 0x08);
+        }
+    }
+
+    private final transient Inet6AddressHolder holder6;
+
+    private static final long serialVersionUID = 6880410070516793377L;
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+    // Perform native initialization
+    static { init(); }
+    // END Android-removed: Android doesn't need to call native init
+    */
+
+    Inet6Address() {
+        super();
+        holder.init(null, AF_INET6);
+        holder6 = new Inet6AddressHolder();
+    }
+
+    /* checking of value for scope_id should be done by caller
+     * scope_id must be >= 0, or -1 to indicate not being set
+     */
+    Inet6Address(String hostName, byte addr[], int scope_id) {
+        holder.init(hostName, AF_INET6);
+        holder6 = new Inet6AddressHolder();
+        holder6.init(addr, scope_id);
+    }
+
+    Inet6Address(String hostName, byte addr[]) {
+        holder6 = new Inet6AddressHolder();
+        try {
+            initif (hostName, addr, null);
+        } catch (UnknownHostException e) {} /* cant happen if ifname is null */
+    }
+
+    Inet6Address (String hostName, byte addr[], NetworkInterface nif)
+        throws UnknownHostException
+    {
+        holder6 = new Inet6AddressHolder();
+        initif (hostName, addr, nif);
+    }
+
+    Inet6Address (String hostName, byte addr[], String ifname)
+        throws UnknownHostException
+    {
+        holder6 = new Inet6AddressHolder();
+        initstr (hostName, addr, ifname);
+    }
+
+    /**
+     * Create an Inet6Address in the exact manner of {@link
+     * InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
+     * set to the value corresponding to the given interface for the address
+     * type specified in {@code addr}. The call will fail with an
+     * UnknownHostException if the given interface does not have a numeric
+     * scope_id assigned for the given address type (eg. link-local or site-local).
+     * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+     *
+     * @param host the specified host
+     * @param addr the raw IP address in network byte order
+     * @param nif an interface this address must be associated with.
+     * @return  an Inet6Address object created from the raw IP address.
+     * @throws  UnknownHostException
+     *          if IP address is of illegal length, or if the interface does not
+     *          have a numeric scope_id assigned for the given address type.
+     *
+     * @since 1.5
+     */
+    public static Inet6Address getByAddress(String host, byte[] addr,
+                                            NetworkInterface nif)
+        throws UnknownHostException
+    {
+        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
+            if (host.charAt(host.length()-1) == ']') {
+                host = host.substring(1, host.length() -1);
+            }
+        }
+        if (addr != null) {
+            if (addr.length == Inet6Address.INADDRSZ) {
+                return new Inet6Address(host, addr, nif);
+            }
+        }
+        throw new UnknownHostException("addr is of illegal length");
+    }
+
+    /**
+     * Create an Inet6Address in the exact manner of {@link
+     * InetAddress#getByAddress(String,byte[])} except that the IPv6 scope_id is
+     * set to the given numeric value. The scope_id is not checked to determine
+     * if it corresponds to any interface on the system.
+     * See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+     *
+     * @param host the specified host
+     * @param addr the raw IP address in network byte order
+     * @param scope_id the numeric scope_id for the address.
+     * @return  an Inet6Address object created from the raw IP address.
+     * @throws  UnknownHostException  if IP address is of illegal length.
+     *
+     * @since 1.5
+     */
+    public static Inet6Address getByAddress(String host, byte[] addr,
+                                            int scope_id)
+        throws UnknownHostException
+    {
+        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
+            if (host.charAt(host.length()-1) == ']') {
+                host = host.substring(1, host.length() -1);
+            }
+        }
+        if (addr != null) {
+            if (addr.length == Inet6Address.INADDRSZ) {
+                return new Inet6Address(host, addr, scope_id);
+            }
+        }
+        throw new UnknownHostException("addr is of illegal length");
+    }
+
+    private void initstr(String hostName, byte addr[], String ifname)
+        throws UnknownHostException
+    {
+        try {
+            NetworkInterface nif = NetworkInterface.getByName (ifname);
+            if (nif == null) {
+                throw new UnknownHostException ("no such interface " + ifname);
+            }
+            initif (hostName, addr, nif);
+        } catch (SocketException e) {
+            throw new UnknownHostException ("SocketException thrown" + ifname);
+        }
+    }
+
+    private void initif(String hostName, byte addr[], NetworkInterface nif)
+        throws UnknownHostException
+    {
+        int family = -1;
+        holder6.init(addr, nif);
+
+        if (addr.length == INADDRSZ) { // normal IPv6 address
+            family = AF_INET6;
+        }
+        holder.init(hostName, family);
+    }
+
+    /* check the two Ipv6 addresses and return false if they are both
+     * non global address types, but not the same.
+     * (ie. one is sitelocal and the other linklocal)
+     * return true otherwise.
+     */
+
+    private static boolean isDifferentLocalAddressType(
+        byte[] thisAddr, byte[] otherAddr) {
+
+        if (Inet6Address.isLinkLocalAddress(thisAddr) &&
+                !Inet6Address.isLinkLocalAddress(otherAddr)) {
+            return false;
+        }
+        if (Inet6Address.isSiteLocalAddress(thisAddr) &&
+                !Inet6Address.isSiteLocalAddress(otherAddr)) {
+            return false;
+        }
+        return true;
+    }
+
+    private static int deriveNumericScope (byte[] thisAddr, NetworkInterface ifc) throws UnknownHostException {
+        Enumeration<InetAddress> addresses = ifc.getInetAddresses();
+        while (addresses.hasMoreElements()) {
+            InetAddress addr = addresses.nextElement();
+            if (!(addr instanceof Inet6Address)) {
+                continue;
+            }
+            Inet6Address ia6_addr = (Inet6Address)addr;
+            /* check if site or link local prefixes match */
+            if (!isDifferentLocalAddressType(thisAddr, ia6_addr.getAddress())){
+                /* type not the same, so carry on searching */
+                continue;
+            }
+            /* found a matching address - return its scope_id */
+            return ia6_addr.getScopeId();
+        }
+        throw new UnknownHostException ("no scope_id found");
+    }
+
+    private int deriveNumericScope (String ifname) throws UnknownHostException {
+        Enumeration<NetworkInterface> en;
+        try {
+            en = NetworkInterface.getNetworkInterfaces();
+        } catch (SocketException e) {
+            throw new UnknownHostException ("could not enumerate local network interfaces");
+        }
+        while (en.hasMoreElements()) {
+            NetworkInterface ifc = en.nextElement();
+            if (ifc.getName().equals (ifname)) {
+                return deriveNumericScope(holder6.ipaddress, ifc);
+            }
+        }
+        throw new UnknownHostException ("No matching address found for interface : " +ifname);
+    }
+
+    /**
+     * @serialField ipaddress byte[]
+     * @serialField scope_id int
+     * @serialField scope_id_set boolean
+     * @serialField scope_ifname_set boolean
+     * @serialField ifname String
+     */
+
+    private static final ObjectStreamField[] serialPersistentFields = {
+         new ObjectStreamField("ipaddress", byte[].class),
+         new ObjectStreamField("scope_id", int.class),
+         new ObjectStreamField("scope_id_set", boolean.class),
+         new ObjectStreamField("scope_ifname_set", boolean.class),
+         new ObjectStreamField("ifname", String.class)
+    };
+
+    private static final long FIELDS_OFFSET;
+    private static final sun.misc.Unsafe UNSAFE;
+
+    static {
+        try {
+            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            FIELDS_OFFSET = unsafe.objectFieldOffset(
+                    Inet6Address.class.getDeclaredField("holder6"));
+            UNSAFE = unsafe;
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * restore the state of this object from stream
+     * including the scope information, only if the
+     * scoped interface name is valid on this system
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+        NetworkInterface scope_ifname = null;
+
+        // Android-changed: was getClass().getClassLoader() != null
+        if (getClass().getClassLoader() != Class.class.getClassLoader()) {
+            throw new SecurityException ("invalid address type");
+        }
+
+        ObjectInputStream.GetField gf = s.readFields();
+        byte[] ipaddress = (byte[])gf.get("ipaddress", null);
+        int scope_id = (int)gf.get("scope_id", -1);
+        boolean scope_id_set = (boolean)gf.get("scope_id_set", false);
+        boolean scope_ifname_set = (boolean)gf.get("scope_ifname_set", false);
+        String ifname = (String)gf.get("ifname", null);
+
+        if (ifname != null && !"".equals (ifname)) {
+            try {
+                scope_ifname = NetworkInterface.getByName(ifname);
+                if (scope_ifname == null) {
+                    /* the interface does not exist on this system, so we clear
+                     * the scope information completely */
+                    scope_id_set = false;
+                    scope_ifname_set = false;
+                    scope_id = 0;
+                } else {
+                    scope_ifname_set = true;
+                    try {
+                        scope_id = deriveNumericScope (ipaddress, scope_ifname);
+                    } catch (UnknownHostException e) {
+                        // typically should not happen, but it may be that
+                        // the machine being used for deserialization has
+                        // the same interface name but without IPv6 configured.
+                    }
+                }
+            } catch (SocketException e) {}
+        }
+
+        /* if ifname was not supplied, then the numeric info is used */
+
+        ipaddress = ipaddress.clone();
+
+        // Check that our invariants are satisfied
+        if (ipaddress.length != INADDRSZ) {
+            throw new InvalidObjectException("invalid address length: "+
+                                             ipaddress.length);
+        }
+
+        if (holder().getFamily() != AF_INET6) {
+            throw new InvalidObjectException("invalid address family type");
+        }
+
+        Inet6AddressHolder h = new Inet6AddressHolder(
+            ipaddress, scope_id, scope_id_set, scope_ifname, scope_ifname_set
+        );
+
+        UNSAFE.putObject(this, FIELDS_OFFSET, h);
+    }
+
+    /**
+     * default behavior is overridden in order to write the
+     * scope_ifname field as a String, rather than a NetworkInterface
+     * which is not serializable
+     */
+    private synchronized void writeObject(ObjectOutputStream s)
+        throws IOException
+    {
+            String ifname = null;
+
+        if (holder6.scope_ifname != null) {
+            ifname = holder6.scope_ifname.getName();
+            holder6.scope_ifname_set = true;
+        }
+        ObjectOutputStream.PutField pfields = s.putFields();
+        pfields.put("ipaddress", holder6.ipaddress);
+        pfields.put("scope_id", holder6.scope_id);
+        pfields.put("scope_id_set", holder6.scope_id_set);
+        pfields.put("scope_ifname_set", holder6.scope_ifname_set);
+        pfields.put("ifname", ifname);
+        s.writeFields();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an IP multicast
+     * address. 11111111 at the start of the address identifies the
+     * address as being a multicast address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is an IP
+     *         multicast address
+     *
+     * @since JDK1.1
+     */
+    @Override
+    public boolean isMulticastAddress() {
+        return holder6.isMulticastAddress();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress in a wildcard address.
+     *
+     * @return a {@code boolean} indicating if the Inetaddress is
+     *         a wildcard address.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isAnyLocalAddress() {
+        return holder6.isAnyLocalAddress();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a loopback address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is a loopback
+     *         address; or false otherwise.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isLoopbackAddress() {
+        return holder6.isLoopbackAddress();
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an link local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is a link local
+     *         address; or false if address is not a link local unicast address.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isLinkLocalAddress() {
+        return holder6.isLinkLocalAddress();
+    }
+
+    /* static version of above */
+    static boolean isLinkLocalAddress(byte[] ipaddress) {
+        return ((ipaddress[0] & 0xff) == 0xfe
+                && (ipaddress[1] & 0xc0) == 0x80);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a site local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is a site local
+     *         address; or false if address is not a site local unicast address.
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isSiteLocalAddress() {
+        return holder6.isSiteLocalAddress();
+    }
+
+    /* static version of above */
+    static boolean isSiteLocalAddress(byte[] ipaddress) {
+        return ((ipaddress[0] & 0xff) == 0xfe
+                && (ipaddress[1] & 0xc0) == 0xc0);
+    }
+
+    /**
+     * Utility routine to check if the multicast address has global scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of global scope, false if it is not of global scope or
+     *         it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCGlobal() {
+        return holder6.isMCGlobal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has node scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of node-local scope, false if it is not of node-local
+     *         scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCNodeLocal() {
+        return holder6.isMCNodeLocal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has link scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of link-local scope, false if it is not of link-local
+     *         scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCLinkLocal() {
+        return holder6.isMCLinkLocal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has site scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of site-local scope, false if it is not  of site-local
+     *         scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCSiteLocal() {
+        return holder6.isMCSiteLocal();
+    }
+
+    /**
+     * Utility routine to check if the multicast address has organization scope.
+     *
+     * @return a {@code boolean} indicating if the address has is a multicast
+     *         address of organization-local scope, false if it is not of
+     *         organization-local scope or it is not a multicast address
+     *
+     * @since 1.4
+     */
+    @Override
+    public boolean isMCOrgLocal() {
+        return holder6.isMCOrgLocal();
+    }
+    /**
+     * Returns the raw IP address of this {@code InetAddress} object. The result
+     * is in network byte order: the highest order byte of the address is in
+     * {@code getAddress()[0]}.
+     *
+     * @return  the raw IP address of this object.
+     */
+    @Override
+    public byte[] getAddress() {
+        return holder6.ipaddress.clone();
+    }
+
+    /**
+     * Returns the numeric scopeId, if this instance is associated with
+     * an interface. If no scoped_id is set, the returned value is zero.
+     *
+     * @return the scopeId, or zero if not set.
+     *
+     * @since 1.5
+     */
+     public int getScopeId() {
+        return holder6.scope_id;
+     }
+
+    /**
+     * Returns the scoped interface, if this instance was created with
+     * with a scoped interface.
+     *
+     * @return the scoped interface, or null if not set.
+     * @since 1.5
+     */
+     public NetworkInterface getScopedInterface() {
+        return holder6.scope_ifname;
+     }
+
+    /**
+     * Returns the IP address string in textual presentation. If the instance
+     * was created specifying a scope identifier then the scope id is appended
+     * to the IP address preceded by a "%" (per-cent) character. This can be
+     * either a numeric value or a string, depending on which was used to create
+     * the instance.
+     *
+     * @return  the raw IP address in a string format.
+     */
+    @Override
+    public String getHostAddress() {
+        // Android-changed: getnameinfo returns smarter representations than getHostAddress()
+        // return holder6.getHostAddress();
+        return Libcore.os.getnameinfo(this, NI_NUMERICHOST); // Can't throw.
+    }
+
+    /**
+     * Returns a hashcode for this IP address.
+     *
+     * @return  a hash code value for this IP address.
+     */
+    @Override
+    public int hashCode() {
+        return holder6.hashCode();
+    }
+
+    /**
+     * Compares this object against the specified object. The result is {@code
+     * true} if and only if the argument is not {@code null} and it represents
+     * the same IP address as this object.
+     *
+     * <p> Two instances of {@code InetAddress} represent the same IP address
+     * if the length of the byte arrays returned by {@code getAddress} is the
+     * same for both, and each of the array components is the same for the byte
+     * arrays.
+     *
+     * @param   obj   the object to compare against.
+     *
+     * @return  {@code true} if the objects are the same; {@code false} otherwise.
+     *
+     * @see     java.net.InetAddress#getAddress()
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof Inet6Address))
+            return false;
+
+        Inet6Address inetAddr = (Inet6Address)obj;
+
+        return holder6.equals(inetAddr.holder6);
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an
+     * IPv4 compatible IPv6 address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is an IPv4
+     *         compatible IPv6 address; or false if address is IPv4 address.
+     *
+     * @since 1.4
+     */
+    public boolean isIPv4CompatibleAddress() {
+        return holder6.isIPv4CompatibleAddress();
+    }
+
+    // Utilities
+    private final static int INT16SZ = 2;
+
+    /*
+     * Convert IPv6 binary address into presentation (printable) format.
+     *
+     * @param src a byte array representing the IPv6 numeric address
+     * @return a String representing an IPv6 address in
+     *         textual representation format
+     * @since 1.4
+     */
+    static String numericToTextFormat(byte[] src) {
+        StringBuilder sb = new StringBuilder(39);
+        for (int i = 0; i < (INADDRSZ / INT16SZ); i++) {
+            sb.append(Integer.toHexString(((src[i<<1]<<8) & 0xff00)
+                                          | (src[(i<<1)+1] & 0xff)));
+            if (i < (INADDRSZ / INT16SZ) -1 ) {
+               sb.append(":");
+            }
+        }
+        return sb.toString();
+    }
+
+    // BEGIN Android-removed: Android doesn't need to call native init
+    /*
+     * Perform class load-time initializations.
+     *
+    private static native void init();
+    */
+    // END Android-removed: Android doesn't need to call native init
+}
diff --git a/java/net/Inet6AddressImpl.java b/java/net/Inet6AddressImpl.java
new file mode 100644
index 0000000..84bcf17
--- /dev/null
+++ b/java/net/Inet6AddressImpl.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+import android.system.ErrnoException;
+import android.system.GaiException;
+import android.system.StructAddrinfo;
+import android.system.IcmpHeaders;
+
+import dalvik.system.BlockGuard;
+
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import libcore.net.InetAddressUtils;
+
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
+import static android.system.OsConstants.AI_ADDRCONFIG;
+import static android.system.OsConstants.EACCES;
+import static android.system.OsConstants.ECONNREFUSED;
+import static android.system.OsConstants.EPERM;
+import static android.system.OsConstants.NI_NAMEREQD;
+import static android.system.OsConstants.ICMP6_ECHO_REPLY;
+import static android.system.OsConstants.ICMP_ECHOREPLY;
+import static android.system.OsConstants.IPPROTO_ICMP;
+import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+
+// Android-note: Android-specific behavior and Linux-based implementation
+// http://b/36933260 Implement root-less ICMP for isReachable()
+// http://b/28609551 Rewrite getHostByAddr0 using POSIX library Libcore.os.
+// http://b/25861497 Add BlockGuard checks.
+// http://b/26700324 Fix odd dependency chains of the static InetAddress.
+// anyLocalAddress() Let anyLocalAddress() always return an IPv6 address.
+// Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+// Rewrote hostname lookup methods on top of Libcore.os. Merge implementation from InetAddress
+//   and remove native methods in this class
+/*
+ * Package private implementation of InetAddressImpl for dual
+ * IPv4/IPv6 stack. {@code #anyLocalAddress()} will always return an IPv6 address.
+ *
+ * @since 1.4
+ */
+
+class Inet6AddressImpl implements InetAddressImpl {
+
+    // @GuardedBy(Inet6AddressImpl.class)
+    private static InetAddress anyLocalAddress;
+    // @GuardedBy(Inet6AddressImpl.class)
+    private static InetAddress[] loopbackAddresses;
+
+    private static final AddressCache addressCache = new AddressCache();
+
+    // BEGIN Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+    /*
+    public native String getLocalHostName() throws UnknownHostException;
+    public native InetAddress[]
+        lookupAllHostAddr(String hostname) throws UnknownHostException;
+    public native String getHostByAddr(byte[] addr) throws UnknownHostException;
+    private native boolean isReachable0(byte[] addr, int scope, int timeout, byte[] inf, int ttl, int if_scope) throws IOException;
+    */
+    @Override
+    public InetAddress[] lookupAllHostAddr(String host, int netId) throws UnknownHostException {
+        if (host == null || host.isEmpty()) {
+            // Android-changed: Return both the Inet4 and Inet6 loopback addresses
+            // when host == null or empty.
+            return loopbackAddresses();
+        }
+
+        // Is it a numeric address?
+        InetAddress result = InetAddressUtils.parseNumericAddressNoThrowStripOptionalBrackets(host);
+        if (result != null) {
+            return new InetAddress[] { result };
+        }
+
+        return lookupHostByName(host, netId);
+    }
+
+    /**
+     * Resolves a hostname to its IP addresses using a cache.
+     *
+     * @param host the hostname to resolve.
+     * @param netId the network to perform resolution upon.
+     * @return the IP addresses of the host.
+     */
+    private static InetAddress[] lookupHostByName(String host, int netId)
+            throws UnknownHostException {
+        BlockGuard.getThreadPolicy().onNetwork();
+        // Do we have a result cached?
+        Object cachedResult = addressCache.get(host, netId);
+        if (cachedResult != null) {
+            if (cachedResult instanceof InetAddress[]) {
+                // A cached positive result.
+                return (InetAddress[]) cachedResult;
+            } else {
+                // A cached negative result.
+                throw new UnknownHostException((String) cachedResult);
+            }
+        }
+        try {
+            StructAddrinfo hints = new StructAddrinfo();
+            hints.ai_flags = AI_ADDRCONFIG;
+            hints.ai_family = AF_UNSPEC;
+            // If we don't specify a socket type, every address will appear twice, once
+            // for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
+            // anyway, just pick one.
+            hints.ai_socktype = SOCK_STREAM;
+            InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
+            // TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
+            for (InetAddress address : addresses) {
+                address.holder().hostName = host;
+                address.holder().originalHostName = host;
+            }
+            addressCache.put(host, netId, addresses);
+            return addresses;
+        } catch (GaiException gaiException) {
+            // If the failure appears to have been a lack of INTERNET permission, throw a clear
+            // SecurityException to aid in debugging this common mistake.
+            // http://code.google.com/p/android/issues/detail?id=15722
+            if (gaiException.getCause() instanceof ErrnoException) {
+                int errno = ((ErrnoException) gaiException.getCause()).errno;
+                if (errno == EACCES || errno == EPERM) {
+                    throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
+                }
+            }
+            // Otherwise, throw an UnknownHostException.
+            String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
+            addressCache.putUnknownHost(host, netId, detailMessage);
+            throw gaiException.rethrowAsUnknownHostException(detailMessage);
+        }
+    }
+
+    @Override
+    public String getHostByAddr(byte[] addr) throws UnknownHostException {
+        BlockGuard.getThreadPolicy().onNetwork();
+
+        return getHostByAddr0(addr);
+    }
+
+    @Override
+    public void clearAddressCache() {
+        addressCache.clear();
+    }
+    // END Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+
+    @Override
+    public boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif, int ttl) throws IOException {
+        // Android-changed: rewritten on the top of IoBridge and Libcore.os.
+        InetAddress sourceAddr = null;
+        if (netif != null) {
+            /*
+             * Let's make sure we bind to an address of the proper family.
+             * Which means same family as addr because at this point it could
+             * be either an IPv6 address or an IPv4 address (case of a dual
+             * stack system).
+             */
+            java.util.Enumeration<InetAddress> it = netif.getInetAddresses();
+            InetAddress inetaddr = null;
+            while (it.hasMoreElements()) {
+                inetaddr = it.nextElement();
+                if (inetaddr.getClass().isInstance(addr)) {
+                    sourceAddr = inetaddr;
+                    break;
+                }
+            }
+
+            if (sourceAddr == null) {
+                // Interface doesn't support the address family of
+                // the destination
+                return false;
+            }
+        }
+
+        // Android-changed: http://b/36933260 Implement root-less ICMP for isReachable().
+        /*
+        if (addr instanceof Inet6Address)
+            scope = ((Inet6Address) addr).getScopeId();
+        return isReachable0(addr.getAddress(), scope, timeout, ifaddr, ttl, netif_scope);
+        */
+        // Try ICMP first
+        if (icmpEcho(addr, timeout, sourceAddr, ttl)) {
+            return true;
+        }
+
+        // No good, let's fall back to TCP
+        return tcpEcho(addr, timeout, sourceAddr, ttl);
+    }
+
+    // BEGIN Android-added: http://b/36933260 Implement root-less ICMP for isReachable().
+    private boolean tcpEcho(InetAddress addr, int timeout, InetAddress sourceAddr, int ttl)
+            throws IOException {
+        FileDescriptor fd = null;
+        try {
+            fd = IoBridge.socket(AF_INET6, SOCK_STREAM, 0);
+            if (ttl > 0) {
+                IoBridge.setSocketOption(fd, IoBridge.JAVA_IP_TTL, ttl);
+            }
+            if (sourceAddr != null) {
+                IoBridge.bind(fd, sourceAddr, 0);
+            }
+            IoBridge.connect(fd, addr, 7 /* Echo-protocol port */, timeout);
+            return true;
+        } catch (IOException e) {
+            // Connection refused by remote (ECONNREFUSED) implies reachable. Otherwise silently
+            // ignore the exception and return false.
+            Throwable cause = e.getCause();
+            return cause instanceof ErrnoException
+                    && ((ErrnoException) cause).errno == ECONNREFUSED;
+        } finally {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        }
+    }
+
+    protected boolean icmpEcho(InetAddress addr, int timeout, InetAddress sourceAddr, int ttl)
+            throws IOException {
+
+        FileDescriptor fd = null;
+        try {
+            boolean isIPv4 = addr instanceof Inet4Address;
+            int domain = isIPv4 ? AF_INET : AF_INET6;
+            int icmpProto = isIPv4 ? IPPROTO_ICMP : IPPROTO_ICMPV6;
+            fd = IoBridge.socket(domain, SOCK_DGRAM, icmpProto);
+
+            if (ttl > 0) {
+                IoBridge.setSocketOption(fd, IoBridge.JAVA_IP_TTL, ttl);
+            }
+            if (sourceAddr != null) {
+                IoBridge.bind(fd, sourceAddr, 0);
+            }
+
+            byte[] packet;
+
+            // ICMP is unreliable, try sending requests every second until timeout.
+            for (int to = timeout, seq = 1; to > 0; ++seq) {
+                int sockTo = to >= 1000 ? 1000 : to;
+
+                IoBridge.setSocketOption(fd, SocketOptions.SO_TIMEOUT, sockTo);
+
+                packet = IcmpHeaders.createIcmpEchoHdr(isIPv4, seq);
+                IoBridge.sendto(fd, packet, 0, packet.length, 0, addr, 0);
+                final int icmpId = IoBridge.getLocalInetSocketAddress(fd).getPort();
+
+                byte[] received = new byte[packet.length];
+                DatagramPacket receivedPacket = new DatagramPacket(received, packet.length);
+                int size = IoBridge
+                        .recvfrom(true, fd, received, 0, received.length, 0, receivedPacket, false);
+                if (size == packet.length) {
+                    byte expectedType = isIPv4 ? (byte) ICMP_ECHOREPLY
+                            : (byte) ICMP6_ECHO_REPLY;
+                    if (receivedPacket.getAddress().equals(addr)
+                            && received[0] == expectedType
+                            && received[4] == (byte) (icmpId >> 8)
+                            && received[5] == (byte) icmpId) {
+                        int receivedSequence = ((received[6] & 0xff) << 8) + (received[7] & 0xff);
+                        if (receivedSequence <= seq) {
+                            return true;
+                        }
+                    }
+                }
+                to -= sockTo;
+            }
+        } catch (IOException e) {
+            // Silently ignore and fall back.
+        } finally {
+            if (fd != null) {
+                try {
+                    Libcore.os.close(fd);
+                } catch (ErrnoException e) { }
+            }
+        }
+
+        return false;
+    }
+    // END Android-added: http://b/36933260 Implement root-less ICMP for isReachable().
+
+    // BEGIN Android-changed: Let anyLocalAddress() always return an IPv6 address.
+    @Override
+    public InetAddress anyLocalAddress() {
+        synchronized (Inet6AddressImpl.class) {
+            // We avoid initializing anyLocalAddress during <clinit> to avoid issues
+            // caused by the dependency chains of these classes. InetAddress depends on
+            // InetAddressImpl, but Inet6Address & Inet4Address are its subclasses.
+            // Also see {@code loopbackAddresses). http://b/26700324
+            if (anyLocalAddress == null) {
+                Inet6Address anyAddress = new Inet6Address();
+                anyAddress.holder().hostName = "::";
+                anyLocalAddress = anyAddress;
+            }
+
+            return anyLocalAddress;
+        }
+    }
+    // END Android-changed: Let anyLocalAddress() always return an IPv6 address.
+
+    // BEGIN Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+    @Override
+    public InetAddress[] loopbackAddresses() {
+        synchronized (Inet6AddressImpl.class) {
+            // We avoid initializing anyLocalAddress during <clinit> to avoid issues
+            // caused by the dependency chains of these classes. InetAddress depends on
+            // InetAddressImpl, but Inet6Address & Inet4Address are its subclasses.
+            // Also see {@code anyLocalAddress).
+            if (loopbackAddresses == null) {
+                loopbackAddresses = new InetAddress[]{Inet6Address.LOOPBACK, Inet4Address.LOOPBACK};
+            }
+
+            return loopbackAddresses;
+        }
+    }
+    // END Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+
+    // BEGIN Android-changed: b/28609551 Rewrite getHostByAddr0 using POSIX library Libcore.os.
+    private String getHostByAddr0(byte[] addr) throws UnknownHostException {
+        // Android-changed: Rewritten on the top of Libcore.os
+        InetAddress hostaddr = InetAddress.getByAddress(addr);
+        try {
+            return Libcore.os.getnameinfo(hostaddr, NI_NAMEREQD);
+        } catch (GaiException e) {
+            UnknownHostException uhe = new UnknownHostException(hostaddr.toString());
+            uhe.initCause(e);
+            throw uhe;
+        }
+    }
+    // END Android-changed: b/28609551 Rewrite getHostByAddr0 using POSIX library Libcore.os.
+}
diff --git a/java/net/InetAddress.annotated.java b/java/net/InetAddress.annotated.java
new file mode 100644
index 0000000..6f4492d
--- /dev/null
+++ b/java/net/InetAddress.annotated.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.io.ObjectStreamException;
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class InetAddress implements java.io.Serializable {
+
+InetAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMulticastAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isAnyLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isLinkLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isSiteLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCGlobal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCNodeLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCLinkLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCSiteLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isMCOrgLocal() { throw new RuntimeException("Stub!"); }
+
+public boolean isReachable(int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public boolean isReachable(java.net.NetworkInterface netif, int ttl, int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public boolean isReachableByICMP(int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getCanonicalHostName() { throw new RuntimeException("Stub!"); }
+
+public byte[] getAddress() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getHostAddress() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getByAddress(java.lang.String host, byte[] addr) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getByName(java.lang.String host) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress[] getAllByName(java.lang.String host) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getLoopbackAddress() { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getByAddress(byte[] addr) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetAddress getLocalHost() throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static boolean isNumeric(java.lang.String address) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.net.InetAddress parseNumericAddress(java.lang.String numericAddress) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static void clearDnsCache() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.net.InetAddress getByNameOnNet(java.lang.String host, int netId) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.net.InetAddress[] getAllByNameOnNet(java.lang.String host, int netId) throws java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/InetAddress.java b/java/net/InetAddress.java
new file mode 100644
index 0000000..e4f8660
--- /dev/null
+++ b/java/net/InetAddress.java
@@ -0,0 +1,1702 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
+import java.io.ObjectOutputStream;
+import java.io.ObjectOutputStream.PutField;
+import libcore.net.InetAddressUtils;
+import sun.net.util.IPAddressUtil;
+import sun.net.spi.nameservice.*;
+import libcore.io.Libcore;
+
+/**
+ * This class represents an Internet Protocol (IP) address.
+ *
+ * <p> An IP address is either a 32-bit or 128-bit unsigned number
+ * used by IP, a lower-level protocol on which protocols like UDP and
+ * TCP are built. The IP address architecture is defined by <a
+ * href="http://www.ietf.org/rfc/rfc790.txt"><i>RFC&nbsp;790:
+ * Assigned Numbers</i></a>, <a
+ * href="http://www.ietf.org/rfc/rfc1918.txt"> <i>RFC&nbsp;1918:
+ * Address Allocation for Private Internets</i></a>, <a
+ * href="http://www.ietf.org/rfc/rfc2365.txt"><i>RFC&nbsp;2365:
+ * Administratively Scoped IP Multicast</i></a>, and <a
+ * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
+ * Version 6 Addressing Architecture</i></a>. An instance of an
+ * InetAddress consists of an IP address and possibly its
+ * corresponding host name (depending on whether it is constructed
+ * with a host name or whether it has already done reverse host name
+ * resolution).
+ *
+ * <h3> Address types </h3>
+ *
+ * <blockquote><table cellspacing=2 summary="Description of unicast and multicast address types">
+ *   <tr><th valign=top><i>unicast</i></th>
+ *       <td>An identifier for a single interface. A packet sent to
+ *         a unicast address is delivered to the interface identified by
+ *         that address.
+ *
+ *         <p> The Unspecified Address -- Also called anylocal or wildcard
+ *         address. It must never be assigned to any node. It indicates the
+ *         absence of an address. One example of its use is as the target of
+ *         bind, which allows a server to accept a client connection on any
+ *         interface, in case the server host has multiple interfaces.
+ *
+ *         <p> The <i>unspecified</i> address must not be used as
+ *         the destination address of an IP packet.
+ *
+ *         <p> The <i>Loopback</i> Addresses -- This is the address
+ *         assigned to the loopback interface. Anything sent to this
+ *         IP address loops around and becomes IP input on the local
+ *         host. This address is often used when testing a
+ *         client.</td></tr>
+ *   <tr><th valign=top><i>multicast</i></th>
+ *       <td>An identifier for a set of interfaces (typically belonging
+ *         to different nodes). A packet sent to a multicast address is
+ *         delivered to all interfaces identified by that address.</td></tr>
+ * </table></blockquote>
+ *
+ * <h4> IP address scope </h4>
+ *
+ * <p> <i>Link-local</i> addresses are designed to be used for addressing
+ * on a single link for purposes such as auto-address configuration,
+ * neighbor discovery, or when no routers are present.
+ *
+ * <p> <i>Site-local</i> addresses are designed to be used for addressing
+ * inside of a site without the need for a global prefix.
+ *
+ * <p> <i>Global</i> addresses are unique across the internet.
+ *
+ * <h4> Textual representation of IP addresses </h4>
+ *
+ * The textual representation of an IP address is address family specific.
+ *
+ * <p>
+ *
+ * For IPv4 address format, please refer to <A
+ * HREF="Inet4Address.html#format">Inet4Address#format</A>; For IPv6
+ * address format, please refer to <A
+ * HREF="Inet6Address.html#format">Inet6Address#format</A>.
+ *
+ * <P>There is a <a href="doc-files/net-properties.html#Ipv4IPv6">couple of
+ * System Properties</a> affecting how IPv4 and IPv6 addresses are used.</P>
+ *
+ * <h4> Host Name Resolution </h4>
+ *
+ * Host name-to-IP address <i>resolution</i> is accomplished through
+ * the use of a combination of local machine configuration information
+ * and network naming services such as the Domain Name System (DNS)
+ * and Network Information Service(NIS). The particular naming
+ * services(s) being used is by default the local machine configured
+ * one. For any host name, its corresponding IP address is returned.
+ *
+ * <p> <i>Reverse name resolution</i> means that for any IP address,
+ * the host associated with the IP address is returned.
+ *
+ * <p> The InetAddress class provides methods to resolve host names to
+ * their IP addresses and vice versa.
+ *
+ * <h4> InetAddress Caching </h4>
+ *
+ * The InetAddress class has a cache to store successful as well as
+ * unsuccessful host name resolutions.
+ *
+ * <p> By default, when a security manager is installed, in order to
+ * protect against DNS spoofing attacks,
+ * the result of positive host name resolutions are
+ * cached forever. When a security manager is not installed, the default
+ * behavior is to cache entries for a finite (implementation dependent)
+ * period of time. The result of unsuccessful host
+ * name resolution is cached for a very short period of time (10
+ * seconds) to improve performance.
+ *
+ * <p> If the default behavior is not desired, then a Java security property
+ * can be set to a different Time-to-live (TTL) value for positive
+ * caching. Likewise, a system admin can configure a different
+ * negative caching TTL value when needed.
+ *
+ * <p> Two Java security properties control the TTL values used for
+ *  positive and negative host name resolution caching:
+ *
+ * <blockquote>
+ * <dl>
+ * <dt><b>networkaddress.cache.ttl</b></dt>
+ * <dd>Indicates the caching policy for successful name lookups from
+ * the name service. The value is specified as as integer to indicate
+ * the number of seconds to cache the successful lookup. The default
+ * setting is to cache for an implementation specific period of time.
+ * <p>
+ * A value of -1 indicates "cache forever".
+ * </dd>
+ * <dt><b>networkaddress.cache.negative.ttl</b> (default: 10)</dt>
+ * <dd>Indicates the caching policy for un-successful name lookups
+ * from the name service. The value is specified as as integer to
+ * indicate the number of seconds to cache the failure for
+ * un-successful lookups.
+ * <p>
+ * A value of 0 indicates "never cache".
+ * A value of -1 indicates "cache forever".
+ * </dd>
+ * </dl>
+ * </blockquote>
+ *
+ * @author  Chris Warth
+ * @see     java.net.InetAddress#getByAddress(byte[])
+ * @see     java.net.InetAddress#getByAddress(java.lang.String, byte[])
+ * @see     java.net.InetAddress#getAllByName(java.lang.String)
+ * @see     java.net.InetAddress#getByName(java.lang.String)
+ * @see     java.net.InetAddress#getLocalHost()
+ * @since JDK1.0
+ */
+public
+class InetAddress implements java.io.Serializable {
+    // BEGIN Android-removed: Android uses linux-based OsConstants.
+    /*
+     * Specify the address family: Internet Protocol, Version 4
+     * @since 1.4
+     *
+    static final int IPv4 = 1;
+
+    /**
+     * Specify the address family: Internet Protocol, Version 6
+     * @since 1.4
+     *
+    static final int IPv6 = 2;
+    */
+    // END Android-removed: Android uses linux-based OsConstants.
+
+    // Android-removed: Android doesn't support the preference.
+    // /* Specify address family preference */
+    //static transient boolean preferIPv6Address = false;
+
+    static class InetAddressHolder {
+        /**
+         * Reserve the original application specified hostname.
+         *
+         * The original hostname is useful for domain-based endpoint
+         * identification (see RFC 2818 and RFC 6125).  If an address
+         * was created with a raw IP address, a reverse name lookup
+         * may introduce endpoint identification security issue via
+         * DNS forging.
+         *
+         * Oracle JSSE provider is using this original hostname, via
+         * sun.misc.JavaNetAccess, for SSL/TLS endpoint identification.
+         *
+         * Note: May define a new public method in the future if necessary.
+         */
+        String originalHostName;
+
+        InetAddressHolder() {}
+
+        InetAddressHolder(String hostName, int address, int family) {
+            this.originalHostName = hostName;
+            this.hostName = hostName;
+            this.address = address;
+            this.family = family;
+        }
+
+        void init(String hostName, int family) {
+            this.originalHostName = hostName;
+            this.hostName = hostName;
+            if (family != -1) {
+                this.family = family;
+            }
+        }
+
+        String hostName;
+
+        String getHostName() {
+            return hostName;
+        }
+
+        String getOriginalHostName() {
+            return originalHostName;
+        }
+
+        /**
+         * Holds a 32-bit IPv4 address.
+         */
+        int address;
+
+        int getAddress() {
+            return address;
+        }
+
+        // Android-changed: Documentation: use Linux-based OsConstants.
+        /**
+         * Specifies the address family type, for instance, AF_INET for IPv4
+         * addresses, and AF_INET6 for IPv6 addresses.
+         */
+        int family;
+
+        int getFamily() {
+            return family;
+        }
+    }
+
+    transient InetAddressHolder holder;
+
+    InetAddressHolder holder() {
+        return holder;
+    }
+
+    /* The implementation is always dual stack IPv6/IPv4 on android */
+    static final InetAddressImpl impl = new Inet6AddressImpl();
+
+    /* Used to store the name service provider */
+    // Android-changed: Android has only one name service.
+    // Android doesn't allow user to provide custom name services.
+    // private static List<NameService> nameServices = null;
+    private static final NameService nameService = new NameService() {
+        public InetAddress[] lookupAllHostAddr(String host, int netId)
+                throws UnknownHostException {
+            return impl.lookupAllHostAddr(host, netId);
+        }
+        public String getHostByAddr(byte[] addr)
+                throws UnknownHostException {
+            return impl.getHostByAddr(addr);
+        }
+    };
+
+    /* Used to store the best available hostname */
+    private transient String canonicalHostName = null;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 3286316764910316507L;
+
+
+    // BEGIN Android-removed: Android doesn't need to load native library.
+    /*
+     * Load net library into runtime, and perform initializations.
+     *
+    static {
+        preferIPv6Address = java.security.AccessController.doPrivileged(
+            new GetBooleanAction("java.net.preferIPv6Addresses")).booleanValue();
+        AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+        init();
+    }
+    */
+    // END Android-removed: Android doesn't need to load native library.
+
+    /**
+     * Constructor for the Socket.accept() method.
+     * This creates an empty InetAddress, which is filled in by
+     * the accept() method.  This InetAddress, however, is not
+     * put in the address cache, since it is not created by name.
+     */
+    InetAddress() {
+        holder = new InetAddressHolder();
+    }
+
+    /**
+     * Replaces the de-serialized object with an Inet4Address object.
+     *
+     * @return the alternate object to the de-serialized object.
+     *
+     * @throws ObjectStreamException if a new object replacing this
+     * object could not be created
+     */
+    private Object readResolve() throws ObjectStreamException {
+        // will replace the deserialized 'this' object
+        return new Inet4Address(holder().getHostName(), holder().getAddress());
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an
+     * IP multicast address.
+     * @return a {@code boolean} indicating if the InetAddress is
+     * an IP multicast address
+     * @since   JDK1.1
+     */
+    public boolean isMulticastAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress in a wildcard address.
+     * @return a {@code boolean} indicating if the Inetaddress is
+     *         a wildcard address.
+     * @since 1.4
+     */
+    public boolean isAnyLocalAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a loopback address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a loopback address; or false otherwise.
+     * @since 1.4
+     */
+    public boolean isLoopbackAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is an link local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a link local address; or false if address is not a link local unicast address.
+     * @since 1.4
+     */
+    public boolean isLinkLocalAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the InetAddress is a site local address.
+     *
+     * @return a {@code boolean} indicating if the InetAddress is
+     * a site local address; or false if address is not a site local unicast address.
+     * @since 1.4
+     */
+    public boolean isSiteLocalAddress() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has global scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of global scope, false if it is not
+     *         of global scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCGlobal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has node scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of node-local scope, false if it is not
+     *         of node-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCNodeLocal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has link scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of link-local scope, false if it is not
+     *         of link-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCLinkLocal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has site scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of site-local scope, false if it is not
+     *         of site-local scope or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCSiteLocal() {
+        return false;
+    }
+
+    /**
+     * Utility routine to check if the multicast address has organization scope.
+     *
+     * @return a {@code boolean} indicating if the address has
+     *         is a multicast address of organization-local scope,
+     *         false if it is not of organization-local scope
+     *         or it is not a multicast address
+     * @since 1.4
+     */
+    public boolean isMCOrgLocal() {
+        return false;
+    }
+
+
+    // Android-changed: Document that impl tries ICMP ECHO REQUESTs first.
+    // The sole implementation, Inet6AddressImpl.isReachable(), tries ICMP ECHO REQUESTs before
+    // TCP ECHO REQUESTs on Android. On Android, these are both possible without root access.
+    /**
+     * Test whether that address is reachable. Best effort is made by the
+     * implementation to try to reach the host, but firewalls and server
+     * configuration may block requests resulting in a unreachable status
+     * while some specific ports may be accessible.
+     * <p>
+     * Android implementation attempts ICMP ECHO REQUESTs first, on failure it
+     * will fall back to TCP ECHO REQUESTs. Success on either protocol will
+     * return true.
+     * <p>
+     * The timeout value, in milliseconds, indicates the maximum amount of time
+     * the try should take. If the operation times out before getting an
+     * answer, the host is deemed unreachable. A negative value will result
+     * in an IllegalArgumentException being thrown.
+     *
+     * @param   timeout the time, in milliseconds, before the call aborts
+     * @return a {@code boolean} indicating if the address is reachable.
+     * @throws IOException if a network error occurs
+     * @throws  IllegalArgumentException if {@code timeout} is negative.
+     * @since 1.5
+     */
+    public boolean isReachable(int timeout) throws IOException {
+        return isReachable(null, 0 , timeout);
+    }
+
+    // Android-changed: Document that impl tries ICMP ECHO REQUESTs first.
+    // The sole implementation, Inet6AddressImpl.isReachable(), tries ICMP ECHO REQUESTs before
+    // TCP ECHO REQUESTs on Android. On Android, these are both possible without root access.
+    /**
+     * Test whether that address is reachable. Best effort is made by the
+     * implementation to try to reach the host, but firewalls and server
+     * configuration may block requests resulting in a unreachable status
+     * while some specific ports may be accessible.
+     * <p>
+     * Android implementation attempts ICMP ECHO REQUESTs first, on failure it
+     * will fall back to TCP ECHO REQUESTs. Success on either protocol will
+     * return true.
+     * <p>
+     * The {@code network interface} and {@code ttl} parameters
+     * let the caller specify which network interface the test will go through
+     * and the maximum number of hops the packets should go through.
+     * A negative value for the {@code ttl} will result in an
+     * IllegalArgumentException being thrown.
+     * <p>
+     * The timeout value, in milliseconds, indicates the maximum amount of time
+     * the try should take. If the operation times out before getting an
+     * answer, the host is deemed unreachable. A negative value will result
+     * in an IllegalArgumentException being thrown.
+     *
+     * @param   netif   the NetworkInterface through which the
+     *                    test will be done, or null for any interface
+     * @param   ttl     the maximum numbers of hops to try or 0 for the
+     *                  default
+     * @param   timeout the time, in milliseconds, before the call aborts
+     * @throws  IllegalArgumentException if either {@code timeout}
+     *                          or {@code ttl} are negative.
+     * @return a {@code boolean}indicating if the address is reachable.
+     * @throws IOException if a network error occurs
+     * @since 1.5
+     */
+    public boolean isReachable(NetworkInterface netif, int ttl,
+                               int timeout) throws IOException {
+        if (ttl < 0)
+            throw new IllegalArgumentException("ttl can't be negative");
+        if (timeout < 0)
+            throw new IllegalArgumentException("timeout can't be negative");
+
+        return impl.isReachable(this, timeout, netif, ttl);
+    }
+
+    // BEGIN Android-added: isReachableByICMP(timeout).
+    /**
+     * @hide For testing only
+     */
+    public boolean isReachableByICMP(int timeout) throws IOException {
+        return ((Inet6AddressImpl) impl).icmpEcho(this, timeout, null, 0);
+    }
+    // END Android-added: isReachableByICMP(timeout).
+
+    /**
+     * Gets the host name for this IP address.
+     *
+     * <p>If this InetAddress was created with a host name,
+     * this host name will be remembered and returned;
+     * otherwise, a reverse name lookup will be performed
+     * and the result will be returned based on the system
+     * configured name lookup service. If a lookup of the name service
+     * is required, call
+     * {@link #getCanonicalHostName() getCanonicalHostName}.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is first called
+     * with the hostname and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the host name for this IP address, or if the operation
+     *    is not allowed by the security check, the textual
+     *    representation of the IP address.
+     *
+     * @see InetAddress#getCanonicalHostName
+     * @see SecurityManager#checkConnect
+     */
+    public String getHostName() {
+        // Android-changed: Remove SecurityManager check.
+        if (holder().getHostName() == null) {
+            holder().hostName = InetAddress.getHostFromNameService(this);
+        }
+        return holder().getHostName();
+    }
+
+    // BEGIN Android-removed: Android doesn't support SecurityManager.
+    /*
+     * Returns the hostname for this address.
+     * If the host is equal to null, then this address refers to any
+     * of the local machine's available network addresses.
+     * this is package private so SocketPermission can make calls into
+     * here without a security check.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkConnect} method
+     * with the hostname and {@code -1}
+     * as its arguments to see if the calling code is allowed to know
+     * the hostname for this IP address, i.e., to connect to the host.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the host name for this IP address, or if the operation
+     *    is not allowed by the security check, the textual
+     *    representation of the IP address.
+     *
+     * @param check make security check if true
+     *
+     * @see SecurityManager#checkConnect
+     *
+    String getHostName(boolean check) {
+        if (holder().getHostName() == null) {
+            holder().hostName = InetAddress.getHostFromNameService(this, check);
+        }
+        return holder().getHostName();
+    }
+    */
+    // END Android-removed: Android doesn't support SecurityManager.
+
+    /**
+     * Gets the fully qualified domain name for this IP address.
+     * Best effort method, meaning we may not be able to return
+     * the FQDN depending on the underlying system configuration.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkConnect} method
+     * with the hostname and {@code -1}
+     * as its arguments to see if the calling code is allowed to know
+     * the hostname for this IP address, i.e., to connect to the host.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the fully qualified domain name for this IP address,
+     *    or if the operation is not allowed by the security check,
+     *    the textual representation of the IP address.
+     *
+     * @see SecurityManager#checkConnect
+     *
+     * @since 1.4
+     */
+    public String getCanonicalHostName() {
+        // Android-changed: Remove SecurityManager check.
+        if (canonicalHostName == null) {
+            canonicalHostName = InetAddress.getHostFromNameService(this);
+        }
+        return canonicalHostName;
+    }
+
+    // Android-changed: Remove SecurityManager check.
+    // * @param check make security check if true
+    /**
+     * Returns the hostname for this address.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkConnect} method
+     * with the hostname and {@code -1}
+     * as its arguments to see if the calling code is allowed to know
+     * the hostname for this IP address, i.e., to connect to the host.
+     * If the operation is not allowed, it will return
+     * the textual representation of the IP address.
+     *
+     * @return  the host name for this IP address, or if the operation
+     *    is not allowed by the security check, the textual
+     *    representation of the IP address.
+     *
+     * @see SecurityManager#checkConnect
+     */
+    private static String getHostFromNameService(InetAddress addr) {
+        String host = null;
+        try {
+            // first lookup the hostname
+            // Android-changed: Android has only one name service.
+            host = nameService.getHostByAddr(addr.getAddress());
+
+                /* now get all the IP addresses for this hostname,
+                 * and make sure one of them matches the original IP
+                 * address. We do this to try and prevent spoofing.
+                 */
+            InetAddress[] arr = nameService.lookupAllHostAddr(host, NETID_UNSET);
+            boolean ok = false;
+
+            if (arr != null) {
+                for(int i = 0; !ok && i < arr.length; i++) {
+                    ok = addr.equals(arr[i]);
+                }
+            }
+
+            //XXX: if it looks a spoof just return the address?
+            if (!ok) {
+                host = addr.getHostAddress();
+                return host;
+            }
+        } catch (UnknownHostException e) {
+            host = addr.getHostAddress();
+        }
+
+        return host;
+    }
+
+    /**
+     * Returns the raw IP address of this {@code InetAddress}
+     * object. The result is in network byte order: the highest order
+     * byte of the address is in {@code getAddress()[0]}.
+     *
+     * @return  the raw IP address of this object.
+     */
+    public byte[] getAddress() {
+        return null;
+    }
+
+    /**
+     * Returns the IP address string in textual presentation.
+     *
+     * @return  the raw IP address in a string format.
+     * @since   JDK1.0.2
+     */
+    public String getHostAddress() {
+        return null;
+     }
+
+    /**
+     * Returns a hashcode for this IP address.
+     *
+     * @return  a hash code value for this IP address.
+     */
+    public int hashCode() {
+        return -1;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same IP address as
+     * this object.
+     * <p>
+     * Two instances of {@code InetAddress} represent the same IP
+     * address if the length of the byte arrays returned by
+     * {@code getAddress} is the same for both, and each of the
+     * array components is the same for the byte arrays.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InetAddress#getAddress()
+     */
+    public boolean equals(Object obj) {
+        return false;
+    }
+
+    /**
+     * Converts this IP address to a {@code String}. The
+     * string returned is of the form: hostname / literal IP
+     * address.
+     *
+     * If the host name is unresolved, no reverse name service lookup
+     * is performed. The hostname part will be represented by an empty string.
+     *
+     * @return  a string representation of this IP address.
+     */
+    public String toString() {
+        String hostName = holder().getHostName();
+        return ((hostName != null) ? hostName : "")
+            + "/" + getHostAddress();
+    }
+
+    // BEGIN Android-removed: Resolves a hostname using Libcore.os.
+    /*
+     * Cached addresses - our own litle nis, not!
+     *
+    private static Cache addressCache = new Cache(Cache.Type.Positive);
+
+    private static Cache negativeCache = new Cache(Cache.Type.Negative);
+
+    private static boolean addressCacheInit = false;
+
+    static InetAddress[]    unknown_array; // put THIS in cache
+
+    static InetAddressImpl  impl;
+
+    private static final HashMap<String, Void> lookupTable = new HashMap<>();
+
+    /**
+     * Represents a cache entry
+     *
+    static final class CacheEntry {
+
+        CacheEntry(InetAddress[] addresses, long expiration) {
+            this.addresses = addresses;
+            this.expiration = expiration;
+        }
+
+        InetAddress[] addresses;
+        long expiration;
+    }
+
+    /**
+     * A cache that manages entries based on a policy specified
+     * at creation time.
+     *
+    static final class Cache {
+        private LinkedHashMap<String, CacheEntry> cache;
+        private Type type;
+
+        enum Type {Positive, Negative};
+
+        /**
+         * Create cache
+         *
+        public Cache(Type type) {
+            this.type = type;
+            cache = new LinkedHashMap<String, CacheEntry>();
+        }
+
+        private int getPolicy() {
+            if (type == Type.Positive) {
+                return InetAddressCachePolicy.get();
+            } else {
+                return InetAddressCachePolicy.getNegative();
+            }
+        }
+
+        /**
+         * Add an entry to the cache. If there's already an
+         * entry then for this host then the entry will be
+         * replaced.
+         *
+        public Cache put(String host, InetAddress[] addresses) {
+            int policy = getPolicy();
+            if (policy == InetAddressCachePolicy.NEVER) {
+                return this;
+            }
+
+            // purge any expired entries
+
+            if (policy != InetAddressCachePolicy.FOREVER) {
+
+                // As we iterate in insertion order we can
+                // terminate when a non-expired entry is found.
+                LinkedList<String> expired = new LinkedList<>();
+                long now = System.currentTimeMillis();
+                for (String key : cache.keySet()) {
+                    CacheEntry entry = cache.get(key);
+
+                    if (entry.expiration >= 0 && entry.expiration < now) {
+                        expired.add(key);
+                    } else {
+                        break;
+                    }
+                }
+
+                for (String key : expired) {
+                    cache.remove(key);
+                }
+            }
+
+            // create new entry and add it to the cache
+            // -- as a HashMap replaces existing entries we
+            //    don't need to explicitly check if there is
+            //    already an entry for this host.
+            long expiration;
+            if (policy == InetAddressCachePolicy.FOREVER) {
+                expiration = -1;
+            } else {
+                expiration = System.currentTimeMillis() + (policy * 1000);
+            }
+            CacheEntry entry = new CacheEntry(addresses, expiration);
+            cache.put(host, entry);
+            return this;
+        }
+
+        /**
+         * Query the cache for the specific host. If found then
+         * return its CacheEntry, or null if not found.
+         *
+        public CacheEntry get(String host) {
+            int policy = getPolicy();
+            if (policy == InetAddressCachePolicy.NEVER) {
+                return null;
+            }
+            CacheEntry entry = cache.get(host);
+
+            // check if entry has expired
+            if (entry != null && policy != InetAddressCachePolicy.FOREVER) {
+                if (entry.expiration >= 0 &&
+                        entry.expiration < System.currentTimeMillis()) {
+                    cache.remove(host);
+                    entry = null;
+                }
+            }
+
+            return entry;
+        }
+    }
+
+    /*
+     * Initialize cache and insert anyLocalAddress into the
+     * unknown array with no expiry.
+     *
+    private static void cacheInitIfNeeded() {
+        assert Thread.holdsLock(addressCache);
+        if (addressCacheInit) {
+            return;
+        }
+        unknown_array = new InetAddress[1];
+        unknown_array[0] = impl.anyLocalAddress();
+
+        addressCache.put(impl.anyLocalAddress().getHostName(),
+                         unknown_array);
+
+        addressCacheInit = true;
+    }
+
+    /*
+     * Cache the given hostname and addresses.
+     *
+    private static void cacheAddresses(String hostname,
+                                       InetAddress[] addresses,
+                                       boolean success) {
+        hostname = hostname.toLowerCase();
+        synchronized (addressCache) {
+            cacheInitIfNeeded();
+            if (success) {
+                addressCache.put(hostname, addresses);
+            } else {
+                negativeCache.put(hostname, addresses);
+            }
+        }
+    }
+
+    /*
+     * Lookup hostname in cache (positive & negative cache). If
+     * found return addresses, null if not found.
+     *
+    private static InetAddress[] getCachedAddresses(String hostname) {
+        hostname = hostname.toLowerCase();
+
+        // search both positive & negative caches
+
+        synchronized (addressCache) {
+            cacheInitIfNeeded();
+
+            CacheEntry entry = addressCache.get(hostname);
+            if (entry == null) {
+                entry = negativeCache.get(hostname);
+            }
+
+            if (entry != null) {
+                return entry.addresses;
+            }
+        }
+
+        // not found
+        return null;
+    }
+
+    private static NameService createNSProvider(String provider) {
+        if (provider == null)
+            return null;
+
+        NameService nameService = null;
+        if (provider.equals("default")) {
+            // initialize the default name service
+            nameService = new NameService() {
+                public InetAddress[] lookupAllHostAddr(String host)
+                    throws UnknownHostException {
+                    return impl.lookupAllHostAddr(host);
+                }
+                public String getHostByAddr(byte[] addr)
+                    throws UnknownHostException {
+                    return impl.getHostByAddr(addr);
+                }
+            };
+        } else {
+            final String providerName = provider;
+            try {
+                nameService = java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedExceptionAction<NameService>() {
+                        public NameService run() {
+                            Iterator<NameServiceDescriptor> itr =
+                                ServiceLoader.load(NameServiceDescriptor.class)
+                                    .iterator();
+                            while (itr.hasNext()) {
+                                NameServiceDescriptor nsd = itr.next();
+                                if (providerName.
+                                    equalsIgnoreCase(nsd.getType()+","
+                                        +nsd.getProviderName())) {
+                                    try {
+                                        return nsd.createNameService();
+                                    } catch (Exception e) {
+                                        e.printStackTrace();
+                                        System.err.println(
+                                            "Cannot create name service:"
+                                             +providerName+": " + e);
+                                    }
+                                }
+                            }
+
+                            return null;
+                        }
+                    }
+                );
+            } catch (java.security.PrivilegedActionException e) {
+            }
+        }
+
+        return nameService;
+    }
+
+    static {
+        // create the impl
+        impl = InetAddressImplFactory.create();
+
+        // get name service if provided and requested
+        String provider = null;;
+        String propPrefix = "sun.net.spi.nameservice.provider.";
+        int n = 1;
+        nameServices = new ArrayList<NameService>();
+        provider = AccessController.doPrivileged(
+                new GetPropertyAction(propPrefix + n));
+        while (provider != null) {
+            NameService ns = createNSProvider(provider);
+            if (ns != null)
+                nameServices.add(ns);
+
+            n++;
+            provider = AccessController.doPrivileged(
+                    new GetPropertyAction(propPrefix + n));
+        }
+
+        // if not designate any name services provider,
+        // create a default one
+        if (nameServices.size() == 0) {
+            NameService ns = createNSProvider("default");
+            nameServices.add(ns);
+        }
+    }
+    */
+    // END Android-removed: Resolves a hostname using Libcore.os.
+
+    /**
+     * Creates an InetAddress based on the provided host name and IP address.
+     * No name service is checked for the validity of the address.
+     *
+     * <p> The host name can either be a machine name, such as
+     * "{@code java.sun.com}", or a textual representation of its IP
+     * address.
+     * <p> No validity checking is done on the host name either.
+     *
+     * <p> If addr specifies an IPv4 address an instance of Inet4Address
+     * will be returned; otherwise, an instance of Inet6Address
+     * will be returned.
+     *
+     * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array
+     * must be 16 bytes long
+     *
+     * @param host the specified host
+     * @param addr the raw IP address in network byte order
+     * @return  an InetAddress object created from the raw IP address.
+     * @exception  UnknownHostException  if IP address is of illegal length
+     * @since 1.4
+     */
+    public static InetAddress getByAddress(String host, byte[] addr) throws UnknownHostException {
+        return getByAddress(host, addr, -1 /* scopeId */);
+    }
+
+    // Android-added: Called by native code in Libcore.io.
+    // Do not delete. Called from native code.
+    private static InetAddress getByAddress(String host, byte[] addr, int scopeId)
+        throws UnknownHostException {
+        if (host != null && host.length() > 0 && host.charAt(0) == '[') {
+            if (host.charAt(host.length()-1) == ']') {
+                host = host.substring(1, host.length() -1);
+            }
+        }
+        if (addr != null) {
+            if (addr.length == Inet4Address.INADDRSZ) {
+                return new Inet4Address(host, addr);
+            } else if (addr.length == Inet6Address.INADDRSZ) {
+                byte[] newAddr
+                    = IPAddressUtil.convertFromIPv4MappedAddress(addr);
+                if (newAddr != null) {
+                    return new Inet4Address(host, newAddr);
+                } else {
+                    return new Inet6Address(host, addr, scopeId);
+                }
+            }
+        }
+        throw new UnknownHostException("addr is of illegal length");
+    }
+
+
+    /**
+     * Determines the IP address of a host, given the host's name.
+     *
+     * <p> The host name can either be a machine name, such as
+     * "{@code java.sun.com}", or a textual representation of its
+     * IP address. If a literal IP address is supplied, only the
+     * validity of the address format is checked.
+     *
+     * <p> For {@code host} specified in literal IPv6 address,
+     * either the form defined in RFC 2732 or the literal IPv6 address
+     * format defined in RFC 2373 is accepted. IPv6 scoped addresses are also
+     * supported. See <a href="Inet6Address.html#scoped">here</a> for a description of IPv6
+     * scoped addresses.
+     *
+     * <p> If the host is {@code null} then an {@code InetAddress}
+     * representing an address of the loopback interface is returned.
+     * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC&nbsp;3330</a>
+     * section&nbsp;2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>
+     * section&nbsp;2.5.3. </p>
+     *
+     * @param      host   the specified host, or {@code null}.
+     * @return     an IP address for the given host name.
+     * @exception  UnknownHostException  if no IP address for the
+     *               {@code host} could be found, or if a scope_id was specified
+     *               for a global IPv6 address.
+     * @exception  SecurityException if a security manager exists
+     *             and its checkConnect method doesn't allow the operation
+     */
+    public static InetAddress getByName(String host)
+        throws UnknownHostException {
+        // Android-changed: Rewritten on the top of Libcore.os.
+        return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
+    }
+
+    /**
+     * Given the name of a host, returns an array of its IP addresses,
+     * based on the configured name service on the system.
+     *
+     * <p> The host name can either be a machine name, such as
+     * "{@code java.sun.com}", or a textual representation of its IP
+     * address. If a literal IP address is supplied, only the
+     * validity of the address format is checked.
+     *
+     * <p> For {@code host} specified in <i>literal IPv6 address</i>,
+     * either the form defined in RFC 2732 or the literal IPv6 address
+     * format defined in RFC 2373 is accepted. A literal IPv6 address may
+     * also be qualified by appending a scoped zone identifier or scope_id.
+     * The syntax and usage of scope_ids is described
+     * <a href="Inet6Address.html#scoped">here</a>.
+     * <p> If the host is {@code null} then an {@code InetAddress}
+     * representing an address of the loopback interface is returned.
+     * See <a href="http://www.ietf.org/rfc/rfc3330.txt">RFC&nbsp;3330</a>
+     * section&nbsp;2 and <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>
+     * section&nbsp;2.5.3. </p>
+     *
+     * <p> If there is a security manager and {@code host} is not
+     * null and {@code host.length() } is not equal to zero, the
+     * security manager's
+     * {@code checkConnect} method is called
+     * with the hostname and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     *
+     * @param      host   the name of the host, or {@code null}.
+     * @return     an array of all the IP addresses for a given host name.
+     *
+     * @exception  UnknownHostException  if no IP address for the
+     *               {@code host} could be found, or if a scope_id was specified
+     *               for a global IPv6 address.
+     * @exception  SecurityException  if a security manager exists and its
+     *               {@code checkConnect} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkConnect
+     */
+    public static InetAddress[] getAllByName(String host)
+        throws UnknownHostException {
+        // Android-changed: Resolves a hostname using Libcore.os.
+        // Also, returns both the Inet4 and Inet6 loopback for null/empty host
+        return impl.lookupAllHostAddr(host, NETID_UNSET).clone();
+    }
+
+    /**
+     * Returns the loopback address.
+     * <p>
+     * The InetAddress returned will represent the IPv4
+     * loopback address, 127.0.0.1, or the IPv6 loopback
+     * address, ::1. The IPv4 loopback address returned
+     * is only one of many in the form 127.*.*.*
+     *
+     * @return  the InetAddress loopback instance.
+     * @since 1.7
+     */
+    public static InetAddress getLoopbackAddress() {
+        // Android-changed: Always returns IPv6 loopback address in Android.
+        return impl.loopbackAddresses()[0];
+    }
+
+    // BEGIN Android-removed: Resolves a hostname using Libcore.os.
+    /*
+     * check if the literal address string has %nn appended
+     * returns -1 if not, or the numeric value otherwise.
+     *
+     * %nn may also be a string that represents the displayName of
+     * a currently available NetworkInterface.
+     *
+    private static int checkNumericZone (String s) throws UnknownHostException {
+        int percent = s.indexOf ('%');
+        int slen = s.length();
+        int digit, zone=0;
+        if (percent == -1) {
+            return -1;
+        }
+        for (int i=percent+1; i<slen; i++) {
+            char c = s.charAt(i);
+            if (c == ']') {
+                if (i == percent+1) {
+                    /* empty per-cent field *
+                    return -1;
+                }
+                break;
+            }
+            if ((digit = Character.digit (c, 10)) < 0) {
+                return -1;
+            }
+            zone = (zone * 10) + digit;
+        }
+        return zone;
+    }
+
+    private static InetAddress[] getAllByName0 (String host)
+        throws UnknownHostException
+    {
+        return getAllByName0(host, true);
+    }
+
+    /**
+     * package private so SocketPermission can call it
+     *
+    static InetAddress[] getAllByName0 (String host, boolean check)
+        throws UnknownHostException  {
+        return getAllByName0 (host, null, check);
+    }
+
+    private static InetAddress[] getAllByName0 (String host, InetAddress reqAddr, boolean check)
+        throws UnknownHostException  {
+
+        /* If it gets here it is presumed to be a hostname */
+        /* Cache.get can return: null, unknownAddress, or InetAddress[] */
+
+        /* make sure the connection to the host is allowed, before we
+         * give out a hostname
+         *
+        if (check) {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkConnect(host, -1);
+            }
+        }
+
+        InetAddress[] addresses = getCachedAddresses(host);
+
+        /* If no entry in cache, then do the host lookup *
+        if (addresses == null) {
+            addresses = getAddressesFromNameService(host, reqAddr);
+        }
+
+        if (addresses == unknown_array)
+            throw new UnknownHostException(host);
+
+        return addresses.clone();
+    }
+
+    private static InetAddress[] getAddressesFromNameService(String host, InetAddress reqAddr)
+        throws UnknownHostException
+    {
+        InetAddress[] addresses = null;
+        boolean success = false;
+        UnknownHostException ex = null;
+
+        // Check whether the host is in the lookupTable.
+        // 1) If the host isn't in the lookupTable when
+        //    checkLookupTable() is called, checkLookupTable()
+        //    would add the host in the lookupTable and
+        //    return null. So we will do the lookup.
+        // 2) If the host is in the lookupTable when
+        //    checkLookupTable() is called, the current thread
+        //    would be blocked until the host is removed
+        //    from the lookupTable. Then this thread
+        //    should try to look up the addressCache.
+        //     i) if it found the addresses in the
+        //        addressCache, checkLookupTable()  would
+        //        return the addresses.
+        //     ii) if it didn't find the addresses in the
+        //         addressCache for any reason,
+        //         it should add the host in the
+        //         lookupTable and return null so the
+        //         following code would do  a lookup itself.
+        if ((addresses = checkLookupTable(host)) == null) {
+            try {
+                // This is the first thread which looks up the addresses
+                // this host or the cache entry for this host has been
+                // expired so this thread should do the lookup.
+                for (NameService nameService : nameServices) {
+                    try {
+                        /*
+                         * Do not put the call to lookup() inside the
+                         * constructor.  if you do you will still be
+                         * allocating space when the lookup fails.
+                         *
+
+                        addresses = nameService.lookupAllHostAddr(host);
+                        success = true;
+                        break;
+                    } catch (UnknownHostException uhe) {
+                        if (host.equalsIgnoreCase("localhost")) {
+                            InetAddress[] local = new InetAddress[] { impl.loopbackAddress() };
+                            addresses = local;
+                            success = true;
+                            break;
+                        }
+                        else {
+                            addresses = unknown_array;
+                            success = false;
+                            ex = uhe;
+                        }
+                    }
+                }
+
+                // More to do?
+                if (reqAddr != null && addresses.length > 1 && !addresses[0].equals(reqAddr)) {
+                    // Find it?
+                    int i = 1;
+                    for (; i < addresses.length; i++) {
+                        if (addresses[i].equals(reqAddr)) {
+                            break;
+                        }
+                    }
+                    // Rotate
+                    if (i < addresses.length) {
+                        InetAddress tmp, tmp2 = reqAddr;
+                        for (int j = 0; j < i; j++) {
+                            tmp = addresses[j];
+                            addresses[j] = tmp2;
+                            tmp2 = tmp;
+                        }
+                        addresses[i] = tmp2;
+                    }
+                }
+                // Cache the address.
+                cacheAddresses(host, addresses, success);
+
+                if (!success && ex != null)
+                    throw ex;
+
+            } finally {
+                // Delete host from the lookupTable and notify
+                // all threads waiting on the lookupTable monitor.
+                updateLookupTable(host);
+            }
+        }
+
+        return addresses;
+    }
+
+
+    private static InetAddress[] checkLookupTable(String host) {
+        synchronized (lookupTable) {
+            // If the host isn't in the lookupTable, add it in the
+            // lookuptable and return null. The caller should do
+            // the lookup.
+            if (lookupTable.containsKey(host) == false) {
+                lookupTable.put(host, null);
+                return null;
+            }
+
+            // If the host is in the lookupTable, it means that another
+            // thread is trying to look up the addresses of this host.
+            // This thread should wait.
+            while (lookupTable.containsKey(host)) {
+                try {
+                    lookupTable.wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+
+        // The other thread has finished looking up the addresses of
+        // the host. This thread should retry to get the addresses
+        // from the addressCache. If it doesn't get the addresses from
+        // the cache, it will try to look up the addresses itself.
+        InetAddress[] addresses = getCachedAddresses(host);
+        if (addresses == null) {
+            synchronized (lookupTable) {
+                lookupTable.put(host, null);
+                return null;
+            }
+        }
+
+        return addresses;
+    }
+
+    private static void updateLookupTable(String host) {
+        synchronized (lookupTable) {
+            lookupTable.remove(host);
+            lookupTable.notifyAll();
+        }
+    }
+    */
+    // END Android-removed: Resolves a hostname using Libcore.os.
+
+    /**
+     * Returns an {@code InetAddress} object given the raw IP address .
+     * The argument is in network byte order: the highest order
+     * byte of the address is in {@code getAddress()[0]}.
+     *
+     * <p> This method doesn't block, i.e. no reverse name service lookup
+     * is performed.
+     *
+     * <p> IPv4 address byte array must be 4 bytes long and IPv6 byte array
+     * must be 16 bytes long
+     *
+     * @param addr the raw IP address in network byte order
+     * @return  an InetAddress object created from the raw IP address.
+     * @exception  UnknownHostException  if IP address is of illegal length
+     * @since 1.4
+     */
+    public static InetAddress getByAddress(byte[] addr)
+        throws UnknownHostException {
+        return getByAddress(null, addr);
+    }
+
+    // BEGIN Android-removed: Resolves a hostname using Libcore.os.
+    /*
+    private static InetAddress cachedLocalHost = null;
+    private static long cacheTime = 0;
+    private static final long maxCacheTime = 5000L;
+    private static final Object cacheLock = new Object();
+    */
+    // END Android-removed: Resolves a hostname using Libcore.os.
+
+    /**
+     * Returns the address of the local host. This is achieved by retrieving
+     * the name of the host from the system, then resolving that name into
+     * an {@code InetAddress}.
+     *
+     * <P>Note: The resolved address may be cached for a short period of time.
+     * </P>
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the local host name and {@code -1}
+     * as its arguments to see if the operation is allowed.
+     * If the operation is not allowed, an InetAddress representing
+     * the loopback address is returned.
+     *
+     * @return     the address of the local host.
+     *
+     * @exception  UnknownHostException  if the local host name could not
+     *             be resolved into an address.
+     *
+     * @see SecurityManager#checkConnect
+     * @see java.net.InetAddress#getByName(java.lang.String)
+     */
+    public static InetAddress getLocalHost() throws UnknownHostException {
+        // BEGIN Android-changed: Resolves a hostname using Libcore.os.
+        /*
+        SecurityManager security = System.getSecurityManager();
+        try {
+            String local = impl.getLocalHostName();
+
+            if (security != null) {
+                security.checkConnect(local, -1);
+            }
+
+            if (local.equals("localhost")) {
+                return impl.loopbackAddress();
+            }
+
+            InetAddress ret = null;
+            synchronized (cacheLock) {
+                long now = System.currentTimeMillis();
+                if (cachedLocalHost != null) {
+                    if ((now - cacheTime) < maxCacheTime) // Less than 5s old?
+                        ret = cachedLocalHost;
+                    else
+                        cachedLocalHost = null;
+                }
+
+                // we are calling getAddressesFromNameService directly
+                // to avoid getting localHost from cache
+                if (ret == null) {
+                    InetAddress[] localAddrs;
+                    try {
+                        localAddrs =
+                            InetAddress.getAddressesFromNameService(local, null);
+                    } catch (UnknownHostException uhe) {
+                        // Rethrow with a more informative error message.
+                        UnknownHostException uhe2 =
+                            new UnknownHostException(local + ": " +
+                                                     uhe.getMessage());
+                        uhe2.initCause(uhe);
+                        throw uhe2;
+                    }
+                    cachedLocalHost = localAddrs[0];
+                    cacheTime = now;
+                    ret = localAddrs[0];
+                }
+            }
+            return ret;
+        } catch (java.lang.SecurityException e) {
+            return impl.loopbackAddress();
+        }
+        */
+        String local = Libcore.os.uname().nodename;
+        return impl.lookupAllHostAddr(local, NETID_UNSET)[0];
+        // END Android-changed: Resolves a hostname using Libcore.os.
+    }
+
+    // BEGIN Android-removed: Android doesn't need to call native init.
+    /**
+     * Perform class load-time initializations.
+     *
+    private static native void init();
+    */
+    // END Android-removed: Android doesn't need to call native init.
+
+    /*
+     * Returns the InetAddress representing anyLocalAddress
+     * (typically 0.0.0.0 or ::0)
+     */
+    static InetAddress anyLocalAddress() {
+        return impl.anyLocalAddress();
+    }
+
+    // BEGIN Android-removed: Android doesn't load user-provided implementation.
+    /*
+     * Load and instantiate an underlying impl class
+     *
+    static InetAddressImpl loadImpl(String implName) {
+        Object impl = null;
+
+        /*
+         * Property "impl.prefix" will be prepended to the classname
+         * of the implementation object we instantiate, to which we
+         * delegate the real work (like native methods).  This
+         * property can vary across implementations of the java.
+         * classes.  The default is an empty String "".
+         *
+        String prefix = AccessController.doPrivileged(
+                      new GetPropertyAction("impl.prefix", ""));
+        try {
+            impl = Class.forName("java.net." + prefix + implName).newInstance();
+        } catch (ClassNotFoundException e) {
+            System.err.println("Class not found: java.net." + prefix +
+                               implName + ":\ncheck impl.prefix property " +
+                               "in your properties file.");
+        } catch (InstantiationException e) {
+            System.err.println("Could not instantiate: java.net." + prefix +
+                               implName + ":\ncheck impl.prefix property " +
+                               "in your properties file.");
+        } catch (IllegalAccessException e) {
+            System.err.println("Cannot access class: java.net." + prefix +
+                               implName + ":\ncheck impl.prefix property " +
+                               "in your properties file.");
+        }
+
+        if (impl == null) {
+            try {
+                impl = Class.forName(implName).newInstance();
+            } catch (Exception e) {
+                throw new Error("System property impl.prefix incorrect");
+            }
+        }
+
+        return (InetAddressImpl) impl;
+    }
+    */
+    // END Android-removed: Android doesn't load user-provided implementation.
+
+    private void readObjectNoData (ObjectInputStream s) throws
+                         IOException, ClassNotFoundException {
+        // Android-changed: Don't use null to mean the boot classloader.
+        if (getClass().getClassLoader() != BOOT_CLASSLOADER) {
+            throw new SecurityException ("invalid address type");
+        }
+    }
+
+    // Android-changed: Don't use null to mean the boot classloader.
+    private static final ClassLoader BOOT_CLASSLOADER = Object.class.getClassLoader();
+
+    private void readObject (ObjectInputStream s) throws
+                         IOException, ClassNotFoundException {
+        // Android-changed: Don't use null to mean the boot classloader.
+        if (getClass().getClassLoader() != BOOT_CLASSLOADER) {
+            throw new SecurityException ("invalid address type");
+        }
+        GetField gf = s.readFields();
+        String host = (String)gf.get("hostName", null);
+        int address= gf.get("address", 0);
+        int family= gf.get("family", 0);
+        holder = new InetAddressHolder(host, address, family);
+    }
+
+    /* needed because the serializable fields no longer exist */
+
+    /**
+     * @serialField hostName String
+     * @serialField address int
+     * @serialField family int
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("hostName", String.class),
+        new ObjectStreamField("address", int.class),
+        new ObjectStreamField("family", int.class),
+    };
+
+    private void writeObject (ObjectOutputStream s) throws
+                        IOException {
+        // Android-changed: Don't use null to mean the boot classloader.
+        if (getClass().getClassLoader() != BOOT_CLASSLOADER) {
+            throw new SecurityException ("invalid address type");
+        }
+        PutField pf = s.putFields();
+        pf.put("hostName", holder().hostName);
+        pf.put("address", holder().address);
+        pf.put("family", holder().family);
+        s.writeFields();
+        s.flush();
+    }
+
+    static final int NETID_UNSET = 0;
+
+    // BEGIN Android-added: Add methods required by frameworks/base.
+    // Particularly those required to deal with scope ids.
+    /**
+     * Returns true if the string is a valid numeric IPv4 or IPv6 address (such as "192.168.0.1").
+     *
+     * <p>This copes with all forms of address that Java supports, detailed in the
+     * {@link InetAddress} class documentation. An empty string is not treated as numeric.
+     *
+     * @hide used by frameworks/base to ensure that a getAllByName won't cause a DNS lookup.
+     * @deprecated Use {@link InetAddressUtils#isNumericAddress(String)} instead, if possible.
+     * @throws NullPointerException if the {@code address} is {@code null}.
+     */
+    @Deprecated
+    public static boolean isNumeric(String address) {
+        return InetAddressUtils.parseNumericAddressNoThrowStripOptionalBrackets(address) != null;
+    }
+
+    /**
+     * Returns an InetAddress corresponding to the given numeric address (such
+     * as {@code "192.168.0.1"} or {@code "2001:4860:800d::68"}).
+     *
+     * <p>This method will never do a DNS lookup. Non-numeric addresses are errors. Passing either
+     * an empty string or a {@code null} as the {@code numericAddress} will return the
+     * {@link Inet6Address#LOOPBACK} address.
+     *
+     * @hide used by frameworks/base's NetworkUtils.numericToInetAddress
+     * @throws IllegalArgumentException if {@code numericAddress} is not a numeric address
+     * @deprecated Use {@link InetAddressUtils#parseNumericAddress(String)} instead, if possible.
+     */
+    @Deprecated
+    public static InetAddress parseNumericAddress(String numericAddress) {
+        if (numericAddress == null || numericAddress.isEmpty()) {
+            return Inet6Address.LOOPBACK;
+        }
+        InetAddress result = InetAddressUtils
+                .parseNumericAddressNoThrowStripOptionalBrackets(numericAddress);
+        if (result == null) {
+            throw new IllegalArgumentException("Not a numeric address: " + numericAddress);
+        }
+        return result;
+    }
+
+    /**
+     * Removes all entries from the VM's DNS cache. This does not affect the C library's DNS
+     * cache, nor any caching DNS servers between you and the canonical server.
+     * @hide
+     */
+    public static void clearDnsCache() {
+        impl.clearAddressCache();
+    }
+    // END Android-added: Add methods required by frameworks/base.
+    // BEGIN Android-added: Support for network (netId)-specific DNS resolution.
+    /**
+     * Operates identically to {@code getByName} except host resolution is
+     * performed on the network designated by {@code netId}.
+     *
+     * @param host
+     *            the hostName to be resolved to an address or {@code null}.
+     * @param netId the network to use for host resolution.
+     * @return the {@code InetAddress} instance representing the host.
+     * @throws UnknownHostException if the address lookup fails.
+     * @hide internal use only
+     */
+    public static InetAddress getByNameOnNet(String host, int netId) throws UnknownHostException {
+        return impl.lookupAllHostAddr(host, netId)[0];
+    }
+
+    /**
+     * Operates identically to {@code getAllByName} except host resolution is
+     * performed on the network designated by {@code netId}.
+     *
+     * @param host the hostname or literal IP string to be resolved.
+     * @param netId the network to use for host resolution.
+     * @return the array of addresses associated with the specified host.
+     * @throws UnknownHostException if the address lookup fails.
+     * @hide internal use only
+     */
+    public static InetAddress[] getAllByNameOnNet(String host, int netId) throws UnknownHostException {
+        return impl.lookupAllHostAddr(host, netId).clone();
+    }
+    // END Android-added: Support for network (netId)-specific DNS resolution.
+}
+// BEGIN Android-removed: Android doesn't load user-provided implementation.
+/*
+ * Simple factory to create the impl
+ *
+class InetAddressImplFactory {
+
+    static InetAddressImpl create() {
+        return InetAddress.loadImpl(isIPv6Supported() ?
+                                    "Inet6AddressImpl" : "Inet4AddressImpl");
+    }
+
+    static native boolean isIPv6Supported();
+}
+*/
+// END Android-removed: Android doesn't load user-provided implementation.
diff --git a/java/net/InetAddressContainer.java b/java/net/InetAddressContainer.java
new file mode 100644
index 0000000..28b6402
--- /dev/null
+++ b/java/net/InetAddressContainer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+class InetAddressContainer {
+    InetAddress addr;
+}
diff --git a/java/net/InetAddressImpl.java b/java/net/InetAddressImpl.java
new file mode 100644
index 0000000..a636c1e
--- /dev/null
+++ b/java/net/InetAddressImpl.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+import java.io.IOException;
+/*
+ * Package private interface to "implementation" used by
+ * {@link InetAddress}.
+ * <p>
+ * See {@link java.net.Inet4AddressImp} and
+ * {@link java.net.Inet6AddressImp}.
+ *
+ * @since 1.4
+ */
+interface InetAddressImpl {
+
+    // BEGIN Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+    /*
+    String getLocalHostName() throws UnknownHostException;
+    InetAddress[]
+        lookupAllHostAddr(String hostname) throws UnknownHostException;
+     */
+    /**
+     * Lookup all addresses for {@code hostname} on the given {@code netId}.
+     */
+    InetAddress[] lookupAllHostAddr(String hostname, int netId) throws UnknownHostException;
+
+    /**
+     * Reverse-lookup the host name for a given {@code addr}.
+     */
+    String getHostByAddr(byte[] addr) throws UnknownHostException;
+
+    /**
+     * Clear address caches (if any).
+     */
+    public void clearAddressCache();
+    // END Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
+
+    /**
+     * Return the "any" local address.
+     */
+    InetAddress anyLocalAddress();
+
+    // Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
+    // InetAddress loopbackAddress();
+    /**
+     * Return a list of loop back adresses for this implementation.
+     */
+    InetAddress[] loopbackAddresses();
+
+    /**
+     * Whether {@code addr} is reachable over {@code netif}.
+     */
+    boolean isReachable(InetAddress addr, int timeout, NetworkInterface netif,
+                        int ttl) throws IOException;
+}
diff --git a/java/net/InetSocketAddress.annotated.java b/java/net/InetSocketAddress.annotated.java
new file mode 100644
index 0000000..554b8e3
--- /dev/null
+++ b/java/net/InetSocketAddress.annotated.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class InetSocketAddress extends java.net.SocketAddress {
+
[email protected]
+public InetSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public InetSocketAddress(int port) { throw new RuntimeException("Stub!"); }
+
+public InetSocketAddress(java.net.InetAddress addr, int port) { throw new RuntimeException("Stub!"); }
+
+public InetSocketAddress(java.lang.String hostname, int port) { throw new RuntimeException("Stub!"); }
+
+public static java.net.InetSocketAddress createUnresolved(java.lang.String host, int port) { throw new RuntimeException("Stub!"); }
+
+public final int getPort() { throw new RuntimeException("Stub!"); }
+
+public final java.net.InetAddress getAddress() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getHostName() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getHostString() { throw new RuntimeException("Stub!"); }
+
+public final boolean isUnresolved() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public final boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public final int hashCode() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/InetSocketAddress.java b/java/net/InetSocketAddress.java
new file mode 100644
index 0000000..74b559b
--- /dev/null
+++ b/java/net/InetSocketAddress.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+
+/**
+ *
+ * This class implements an IP Socket Address (IP address + port number)
+ * It can also be a pair (hostname + port number), in which case an attempt
+ * will be made to resolve the hostname. If resolution fails then the address
+ * is said to be <I>unresolved</I> but can still be used on some circumstances
+ * like connecting through a proxy.
+ * <p>
+ * It provides an immutable object used by sockets for binding, connecting, or
+ * as returned values.
+ * <p>
+ * The <i>wildcard</i> is a special local IP address. It usually means "any"
+ * and can only be used for {@code bind} operations.
+ *
+ * @see java.net.Socket
+ * @see java.net.ServerSocket
+ * @since 1.4
+ */
+public class InetSocketAddress
+    extends SocketAddress
+{
+    // Private implementation class pointed to by all public methods.
+    private static class InetSocketAddressHolder {
+        // The hostname of the Socket Address
+        private String hostname;
+        // The IP address of the Socket Address
+        private InetAddress addr;
+        // The port number of the Socket Address
+        private int port;
+
+        private InetSocketAddressHolder(String hostname, InetAddress addr, int port) {
+            this.hostname = hostname;
+            this.addr = addr;
+            this.port = port;
+        }
+
+        private int getPort() {
+            return port;
+        }
+
+        private InetAddress getAddress() {
+            return addr;
+        }
+
+        private String getHostName() {
+            if (hostname != null)
+                return hostname;
+            if (addr != null)
+                return addr.getHostName();
+            return null;
+        }
+
+        private String getHostString() {
+            if (hostname != null)
+                return hostname;
+            if (addr != null) {
+                if (addr.holder().getHostName() != null)
+                    return addr.holder().getHostName();
+                else
+                    return addr.getHostAddress();
+            }
+            return null;
+        }
+
+        private boolean isUnresolved() {
+            return addr == null;
+        }
+
+        @Override
+        public String toString() {
+            if (isUnresolved()) {
+                return hostname + ":" + port;
+            } else {
+                return addr.toString() + ":" + port;
+            }
+        }
+
+        @Override
+        public final boolean equals(Object obj) {
+            if (obj == null || !(obj instanceof InetSocketAddressHolder))
+                return false;
+            InetSocketAddressHolder that = (InetSocketAddressHolder)obj;
+            boolean sameIP;
+            if (addr != null)
+                sameIP = addr.equals(that.addr);
+            else if (hostname != null)
+                sameIP = (that.addr == null) &&
+                    hostname.equalsIgnoreCase(that.hostname);
+            else
+                sameIP = (that.addr == null) && (that.hostname == null);
+            return sameIP && (port == that.port);
+        }
+
+        @Override
+        public final int hashCode() {
+            if (addr != null)
+                return addr.hashCode() + port;
+            if (hostname != null)
+                return hostname.toLowerCase().hashCode() + port;
+            return port;
+        }
+    }
+
+    private final transient InetSocketAddressHolder holder;
+
+    private static final long serialVersionUID = 5076001401234631237L;
+
+    private static int checkPort(int port) {
+        if (port < 0 || port > 0xFFFF)
+            throw new IllegalArgumentException("port out of range:" + port);
+        return port;
+    }
+
+    private static String checkHost(String hostname) {
+        if (hostname == null)
+            throw new IllegalArgumentException("hostname can't be null");
+        return hostname;
+    }
+
+    // BEGIN Android-added: InetSocketAddress() ctor used by IoBridge.
+    /**
+     * @hide internal use only
+     */
+    public InetSocketAddress() {
+        // These will be filled in the native implementation of recvfrom.
+        holder = new InetSocketAddressHolder(null, null, 0);
+    }
+    // END Android-added: InetSocketAddress() ctor used by IoBridge.
+
+    /**
+     * Creates a socket address where the IP address is the wildcard address
+     * and the port number a specified value.
+     * <p>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <p>
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside the specified
+     * range of valid port values.
+     */
+    public InetSocketAddress(int port) {
+        // Android-changed: Defaults to IPv6.
+        // this(InetAddress.anyLocalAddress(), port);
+        this((InetAddress)null, port);
+    }
+
+    /**
+     *
+     * Creates a socket address from an IP address and a port number.
+     * <p>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <P>
+     * A {@code null} address will assign the <i>wildcard</i> address.
+     * <p>
+     * @param   addr    The IP address
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside the specified
+     * range of valid port values.
+     */
+    public InetSocketAddress(InetAddress addr, int port) {
+        holder = new InetSocketAddressHolder(
+                        null,
+                        // Android-changed: Defaults to IPv6 if addr is null.
+                        // addr == null ? InetAddress.anyLocalAddress() : addr,
+                        addr == null ? Inet6Address.ANY : addr,
+                        checkPort(port));
+    }
+
+    /**
+     *
+     * Creates a socket address from a hostname and a port number.
+     * <p>
+     * An attempt will be made to resolve the hostname into an InetAddress.
+     * If that attempt fails, the address will be flagged as <I>unresolved</I>.
+     * <p>
+     * If there is a security manager, its {@code checkConnect} method
+     * is called with the host name as its argument to check the permission
+     * to resolve it. This could result in a SecurityException.
+     * <P>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <P>
+     * @param   hostname the Host name
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside the range
+     * of valid port values, or if the hostname parameter is <TT>null</TT>.
+     * @throws SecurityException if a security manager is present and
+     *                           permission to resolve the host name is
+     *                           denied.
+     * @see     #isUnresolved()
+     */
+    public InetSocketAddress(String hostname, int port) {
+        checkHost(hostname);
+        InetAddress addr = null;
+        String host = null;
+        try {
+            addr = InetAddress.getByName(hostname);
+        } catch(UnknownHostException e) {
+            host = hostname;
+        }
+        holder = new InetSocketAddressHolder(host, addr, checkPort(port));
+    }
+
+    // private constructor for creating unresolved instances
+    private InetSocketAddress(int port, String hostname) {
+        holder = new InetSocketAddressHolder(hostname, null, port);
+    }
+
+    /**
+     *
+     * Creates an unresolved socket address from a hostname and a port number.
+     * <p>
+     * No attempt will be made to resolve the hostname into an InetAddress.
+     * The address will be flagged as <I>unresolved</I>.
+     * <p>
+     * A valid port value is between 0 and 65535.
+     * A port number of {@code zero} will let the system pick up an
+     * ephemeral port in a {@code bind} operation.
+     * <P>
+     * @param   host    the Host name
+     * @param   port    The port number
+     * @throws IllegalArgumentException if the port parameter is outside
+     *                  the range of valid port values, or if the hostname
+     *                  parameter is <TT>null</TT>.
+     * @see     #isUnresolved()
+     * @return  a {@code InetSocketAddress} representing the unresolved
+     *          socket address
+     * @since 1.5
+     */
+    public static InetSocketAddress createUnresolved(String host, int port) {
+        return new InetSocketAddress(checkPort(port), checkHost(host));
+    }
+
+    /**
+     * @serialField hostname String
+     * @serialField addr InetAddress
+     * @serialField port int
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+         new ObjectStreamField("hostname", String.class),
+         new ObjectStreamField("addr", InetAddress.class),
+         new ObjectStreamField("port", int.class)};
+
+    private void writeObject(ObjectOutputStream out)
+        throws IOException
+    {
+        // Don't call defaultWriteObject()
+         ObjectOutputStream.PutField pfields = out.putFields();
+         pfields.put("hostname", holder.hostname);
+         pfields.put("addr", holder.addr);
+         pfields.put("port", holder.port);
+         out.writeFields();
+     }
+
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        // Don't call defaultReadObject()
+        ObjectInputStream.GetField oisFields = in.readFields();
+        final String oisHostname = (String)oisFields.get("hostname", null);
+        final InetAddress oisAddr = (InetAddress)oisFields.get("addr", null);
+        final int oisPort = oisFields.get("port", -1);
+
+        // Check that our invariants are satisfied
+        checkPort(oisPort);
+        if (oisHostname == null && oisAddr == null)
+            throw new InvalidObjectException("hostname and addr " +
+                                             "can't both be null");
+
+        InetSocketAddressHolder h = new InetSocketAddressHolder(oisHostname,
+                                                                oisAddr,
+                                                                oisPort);
+        UNSAFE.putObject(this, FIELDS_OFFSET, h);
+    }
+
+    private void readObjectNoData()
+        throws ObjectStreamException
+    {
+        throw new InvalidObjectException("Stream data required");
+    }
+
+    private static final long FIELDS_OFFSET;
+    private static final sun.misc.Unsafe UNSAFE;
+    static {
+        try {
+            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            FIELDS_OFFSET = unsafe.objectFieldOffset(
+                    InetSocketAddress.class.getDeclaredField("holder"));
+            UNSAFE = unsafe;
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * Gets the port number.
+     *
+     * @return the port number.
+     */
+    public final int getPort() {
+        return holder.getPort();
+    }
+
+    /**
+     *
+     * Gets the {@code InetAddress}.
+     *
+     * @return the InetAdress or {@code null} if it is unresolved.
+     */
+    public final InetAddress getAddress() {
+        return holder.getAddress();
+    }
+
+    /**
+     * Gets the {@code hostname}.
+     * Note: This method may trigger a name service reverse lookup if the
+     * address was created with a literal IP address.
+     *
+     * @return  the hostname part of the address.
+     */
+    public final String getHostName() {
+        return holder.getHostName();
+    }
+
+    /**
+     * Returns the hostname, or the String form of the address if it
+     * doesn't have a hostname (it was created using a literal).
+     * This has the benefit of <b>not</b> attempting a reverse lookup.
+     *
+     * @return the hostname, or String representation of the address.
+     * @since 1.7
+     */
+    public final String getHostString() {
+        return holder.getHostString();
+    }
+
+    /**
+     * Checks whether the address has been resolved or not.
+     *
+     * @return {@code true} if the hostname couldn't be resolved into
+     *          an {@code InetAddress}.
+     */
+    public final boolean isUnresolved() {
+        return holder.isUnresolved();
+    }
+
+    /**
+     * Constructs a string representation of this InetSocketAddress.
+     * This String is constructed by calling toString() on the InetAddress
+     * and concatenating the port number (with a colon). If the address
+     * is unresolved then the part before the colon will only contain the hostname.
+     *
+     * @return  a string representation of this object.
+     */
+    @Override
+    public String toString() {
+        return holder.toString();
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same address as
+     * this object.
+     * <p>
+     * Two instances of {@code InetSocketAddress} represent the same
+     * address if both the InetAddresses (or hostnames if it is unresolved) and port
+     * numbers are equal.
+     * If both addresses are unresolved, then the hostname and the port number
+     * are compared.
+     *
+     * Note: Hostnames are case insensitive. e.g. "FooBar" and "foobar" are
+     * considered equal.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see java.net.InetAddress#equals(java.lang.Object)
+     */
+    @Override
+    public final boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof InetSocketAddress))
+            return false;
+        return holder.equals(((InetSocketAddress) obj).holder);
+    }
+
+    /**
+     * Returns a hashcode for this socket address.
+     *
+     * @return  a hash code value for this socket address.
+     */
+    @Override
+    public final int hashCode() {
+        return holder.hashCode();
+    }
+}
diff --git a/java/net/InterfaceAddress.java b/java/net/InterfaceAddress.java
new file mode 100644
index 0000000..85f9e58
--- /dev/null
+++ b/java/net/InterfaceAddress.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This class represents a Network Interface address. In short it's an
+ * IP address, a subnet mask and a broadcast address when the address is
+ * an IPv4 one. An IP address and a network prefix length in the case
+ * of IPv6 address.
+ *
+ * @see java.net.NetworkInterface
+ * @since 1.6
+ */
+public class InterfaceAddress {
+    private InetAddress address = null;
+    private Inet4Address broadcast = null;
+    private short        maskLength = 0;
+
+    /*
+     * Package private constructor. Can't be built directly, instances are
+     * obtained through the NetworkInterface class.
+     */
+    InterfaceAddress() {
+    }
+
+    // BEGIN Android-added: Rewrote NetworkInterface on top of Libcore.io.
+    InterfaceAddress(InetAddress address, Inet4Address broadcast, InetAddress netmask) {
+        this.address = address;
+        this.broadcast = broadcast;
+        this.maskLength = countPrefixLength(netmask);
+    }
+
+    /**
+     * Counts the prefix length for the netmask address.
+     *
+     * A valid netmask address must start with a continuous sequence of 1, followed by a continuous
+     * sequence of 0.
+     */
+    private short countPrefixLength(InetAddress netmask) {
+        short count = 0;
+        for (byte b : netmask.getAddress()) {
+            for (; b != 0; b <<= 1, ++count);
+        }
+        return count;
+    }
+    // END Android-added: Rewrote NetworkInterface on top of Libcore.io.
+
+    /**
+     * Returns an {@code InetAddress} for this address.
+     *
+     * @return the {@code InetAddress} for this address.
+     */
+    public InetAddress getAddress() {
+        return address;
+    }
+
+    /**
+     * Returns an {@code InetAddress} for the broadcast address
+     * for this InterfaceAddress.
+     * <p>
+     * Only IPv4 networks have broadcast address therefore, in the case
+     * of an IPv6 network, {@code null} will be returned.
+     *
+     * @return the {@code InetAddress} representing the broadcast
+     *         address or {@code null} if there is no broadcast address.
+     */
+    public InetAddress getBroadcast() {
+        return broadcast;
+    }
+
+    /**
+     * Returns the network prefix length for this address. This is also known
+     * as the subnet mask in the context of IPv4 addresses.
+     * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0)
+     * or 24 (255.255.255.0). <p>
+     * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10)
+     *
+     * @return a {@code short} representing the prefix length for the
+     *         subnet of that address.
+     */
+     public short getNetworkPrefixLength() {
+        return maskLength;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same interface address as
+     * this object.
+     * <p>
+     * Two instances of {@code InterfaceAddress} represent the same
+     * address if the InetAddress, the prefix length and the broadcast are
+     * the same for both.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InterfaceAddress#hashCode()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof InterfaceAddress)) {
+            return false;
+        }
+        InterfaceAddress cmp = (InterfaceAddress) obj;
+        if ( !(address == null ? cmp.address == null : address.equals(cmp.address)) )
+            return false;
+        if ( !(broadcast  == null ? cmp.broadcast == null : broadcast.equals(cmp.broadcast)) )
+            return false;
+        if (maskLength != cmp.maskLength)
+            return false;
+        return true;
+    }
+
+    /**
+     * Returns a hashcode for this Interface address.
+     *
+     * @return  a hash code value for this Interface address.
+     */
+    public int hashCode() {
+        return address.hashCode() + ((broadcast != null) ? broadcast.hashCode() : 0) + maskLength;
+    }
+
+    /**
+     * Converts this Interface address to a {@code String}. The
+     * string returned is of the form: InetAddress / prefix length [ broadcast address ].
+     *
+     * @return  a string representation of this Interface address.
+     */
+    public String toString() {
+        return address + "/" + maskLength + " [" + broadcast + "]";
+    }
+
+}
diff --git a/java/net/JarURLConnection.java b/java/net/JarURLConnection.java
new file mode 100644
index 0000000..70dedec
--- /dev/null
+++ b/java/net/JarURLConnection.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+import java.security.Permission;
+import sun.net.www.ParseUtil;
+
+/**
+ * A URL Connection to a Java ARchive (JAR) file or an entry in a JAR
+ * file.
+ *
+ * <p>The syntax of a JAR URL is:
+ *
+ * <pre>
+ * jar:&lt;url&gt;!/{entry}
+ * </pre>
+ *
+ * <p>for example:
+ *
+ * <p>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class}
+ *
+ * <p>Jar URLs should be used to refer to a JAR file or entries in
+ * a JAR file. The example above is a JAR URL which refers to a JAR
+ * entry. If the entry name is omitted, the URL refers to the whole
+ * JAR file:
+ *
+ * {@code jar:http://www.foo.com/bar/baz.jar!/}
+ *
+ * <p>Users should cast the generic URLConnection to a
+ * JarURLConnection when they know that the URL they created is a JAR
+ * URL, and they need JAR-specific functionality. For example:
+ *
+ * <pre>
+ * URL url = new URL("jar:file:/home/duke/duke.jar!/");
+ * JarURLConnection jarConnection = (JarURLConnection)url.openConnection();
+ * Manifest manifest = jarConnection.getManifest();
+ * </pre>
+ *
+ * <p>JarURLConnection instances can only be used to read from JAR files.
+ * It is not possible to get a {@link java.io.OutputStream} to modify or write
+ * to the underlying JAR file using this class.
+ * <p>Examples:
+ *
+ * <dl>
+ *
+ * <dt>A Jar entry
+ * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class}
+ *
+ * <dt>A Jar file
+ * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/}
+ *
+ * <dt>A Jar directory
+ * <dd>{@code jar:http://www.foo.com/bar/baz.jar!/COM/foo/}
+ *
+ * </dl>
+ *
+ * <p>{@code !/} is referred to as the <em>separator</em>.
+ *
+ * <p>When constructing a JAR url via {@code new URL(context, spec)},
+ * the following rules apply:
+ *
+ * <ul>
+ *
+ * <li>if there is no context URL and the specification passed to the
+ * URL constructor doesn't contain a separator, the URL is considered
+ * to refer to a JarFile.
+ *
+ * <li>if there is a context URL, the context URL is assumed to refer
+ * to a JAR file or a Jar directory.
+ *
+ * <li>if the specification begins with a '/', the Jar directory is
+ * ignored, and the spec is considered to be at the root of the Jar
+ * file.
+ *
+ * <p>Examples:
+ *
+ * <dl>
+ *
+ * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/</b>,
+ * spec:<b>baz/entry.txt</b>
+ *
+ * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b>
+ *
+ * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>,
+ * spec:<b>entry.txt</b>
+ *
+ * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/baz/entry.txt</b>
+ *
+ * <dt>context: <b>jar:http://www.foo.com/bar/jar.jar!/baz</b>,
+ * spec:<b>/entry.txt</b>
+ *
+ * <dd>url:<b>jar:http://www.foo.com/bar/jar.jar!/entry.txt</b>
+ *
+ * </dl>
+ *
+ * </ul>
+ *
+ * @see java.net.URL
+ * @see java.net.URLConnection
+ *
+ * @see java.util.jar.JarFile
+ * @see java.util.jar.JarInputStream
+ * @see java.util.jar.Manifest
+ * @see java.util.zip.ZipEntry
+ *
+ * @author Benjamin Renaud
+ * @since 1.2
+ */
+public abstract class JarURLConnection extends URLConnection {
+
+    private URL jarFileURL;
+    private String entryName;
+
+    /**
+     * The connection to the JAR file URL, if the connection has been
+     * initiated. This should be set by connect.
+     */
+    protected URLConnection jarFileURLConnection;
+
+    /**
+     * Creates the new JarURLConnection to the specified URL.
+     * @param url the URL
+     * @throws MalformedURLException if no legal protocol
+     * could be found in a specification string or the
+     * string could not be parsed.
+     */
+
+    protected JarURLConnection(URL url) throws MalformedURLException {
+        super(url);
+        parseSpecs(url);
+    }
+
+    /* get the specs for a given url out of the cache, and compute and
+     * cache them if they're not there.
+     */
+    private void parseSpecs(URL url) throws MalformedURLException {
+        String spec = url.getFile();
+
+        int separator = spec.indexOf("!/");
+        /*
+         * REMIND: we don't handle nested JAR URLs
+         */
+        if (separator == -1) {
+            throw new MalformedURLException("no !/ found in url spec:" + spec);
+        }
+
+        jarFileURL = new URL(spec.substring(0, separator++));
+        entryName = null;
+
+        /* if ! is the last letter of the innerURL, entryName is null */
+        if (++separator != spec.length()) {
+            entryName = spec.substring(separator, spec.length());
+            entryName = ParseUtil.decode (entryName);
+        }
+    }
+
+    /**
+     * Returns the URL for the Jar file for this connection.
+     *
+     * @return the URL for the Jar file for this connection.
+     */
+    public URL getJarFileURL() {
+        return jarFileURL;
+    }
+
+    /**
+     * Return the entry name for this connection. This method
+     * returns null if the JAR file URL corresponding to this
+     * connection points to a JAR file and not a JAR file entry.
+     *
+     * @return the entry name for this connection, if any.
+     */
+    public String getEntryName() {
+        return entryName;
+    }
+
+    /**
+     * Return the JAR file for this connection.
+     *
+     * @return the JAR file for this connection. If the connection is
+     * a connection to an entry of a JAR file, the JAR file object is
+     * returned
+     *
+     * @exception IOException if an IOException occurs while trying to
+     * connect to the JAR file for this connection.
+     *
+     * @see #connect
+     */
+    public abstract JarFile getJarFile() throws IOException;
+
+    /**
+     * Returns the Manifest for this connection, or null if none.
+     *
+     * @return the manifest object corresponding to the JAR file object
+     * for this connection.
+     *
+     * @exception IOException if getting the JAR file for this
+     * connection causes an IOException to be thrown.
+     *
+     * @see #getJarFile
+     */
+    public Manifest getManifest() throws IOException {
+        return getJarFile().getManifest();
+    }
+
+    /**
+     * Return the JAR entry object for this connection, if any. This
+     * method returns null if the JAR file URL corresponding to this
+     * connection points to a JAR file and not a JAR file entry.
+     *
+     * @return the JAR entry object for this connection, or null if
+     * the JAR URL for this connection points to a JAR file.
+     *
+     * @exception IOException if getting the JAR file for this
+     * connection causes an IOException to be thrown.
+     *
+     * @see #getJarFile
+     * @see #getJarEntry
+     */
+    public JarEntry getJarEntry() throws IOException {
+        return getJarFile().getJarEntry(entryName);
+    }
+
+    /**
+     * Return the Attributes object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise.
+     *
+     * @return the Attributes object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise.
+     *
+     * @exception IOException if getting the JAR entry causes an
+     * IOException to be thrown.
+     *
+     * @see #getJarEntry
+     */
+    public Attributes getAttributes() throws IOException {
+        JarEntry e = getJarEntry();
+        return e != null ? e.getAttributes() : null;
+    }
+
+    /**
+     * Returns the main Attributes for the JAR file for this
+     * connection.
+     *
+     * @return the main Attributes for the JAR file for this
+     * connection.
+     *
+     * @exception IOException if getting the manifest causes an
+     * IOException to be thrown.
+     *
+     * @see #getJarFile
+     * @see #getManifest
+     */
+    public Attributes getMainAttributes() throws IOException {
+        Manifest man = getManifest();
+        return man != null ? man.getMainAttributes() : null;
+    }
+
+    /**
+     * Return the Certificate object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise. This method
+     * can only be called once
+     * the connection has been completely verified by reading
+     * from the input stream until the end of the stream has been
+     * reached. Otherwise, this method will return {@code null}
+     *
+     * @return the Certificate object for this connection if the URL
+     * for it points to a JAR file entry, null otherwise.
+     *
+     * @exception IOException if getting the JAR entry causes an
+     * IOException to be thrown.
+     *
+     * @see #getJarEntry
+     */
+    public java.security.cert.Certificate[] getCertificates()
+         throws IOException
+    {
+        JarEntry e = getJarEntry();
+        return e != null ? e.getCertificates() : null;
+    }
+}
diff --git a/java/net/MalformedURLException.java b/java/net/MalformedURLException.java
new file mode 100644
index 0000000..7aef75c
--- /dev/null
+++ b/java/net/MalformedURLException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that a malformed URL has occurred. Either no
+ * legal protocol could be found in a specification string or the
+ * string could not be parsed.
+ *
+ * @author  Arthur van Hoff
+ * @since   JDK1.0
+ */
+public class MalformedURLException extends IOException {
+    private static final long serialVersionUID = -182787522200415866L;
+
+    /**
+     * Constructs a {@code MalformedURLException} with no detail message.
+     */
+    public MalformedURLException() {
+    }
+
+    /**
+     * Constructs a {@code MalformedURLException} with the
+     * specified detail message.
+     *
+     * @param   msg   the detail message.
+     */
+    public MalformedURLException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/net/MulticastSocket.java b/java/net/MulticastSocket.java
new file mode 100644
index 0000000..83a18c3
--- /dev/null
+++ b/java/net/MulticastSocket.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+// Android-changed: Updated example code to handle non-ASCII characters
+/**
+ * The multicast datagram socket class is useful for sending
+ * and receiving IP multicast packets.  A MulticastSocket is
+ * a (UDP) DatagramSocket, with additional capabilities for
+ * joining "groups" of other multicast hosts on the internet.
+ * <P>
+ * A multicast group is specified by a class D IP address
+ * and by a standard UDP port number. Class D IP addresses
+ * are in the range <CODE>224.0.0.0</CODE> to <CODE>239.255.255.255</CODE>,
+ * inclusive. The address 224.0.0.0 is reserved and should not be used.
+ * <P>
+ * One would join a multicast group by first creating a MulticastSocket
+ * with the desired port, then invoking the
+ * <CODE>joinGroup(InetAddress groupAddr)</CODE>
+ * method:
+ * <PRE>
+ * // join a Multicast group and send the group salutations
+ * ...
+ * String msg = "Hello";
+ * InetAddress group = InetAddress.getByName("228.5.6.7");
+ * MulticastSocket s = new MulticastSocket(6789);
+ * s.joinGroup(group);
+ * byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
+ * DatagramPacket hi = new DatagramPacket(bytes, bytes.length,
+ *                             group, 6789);
+ * s.send(hi);
+ * // get their responses!
+ * byte[] buf = new byte[1000];
+ * DatagramPacket recv = new DatagramPacket(buf, buf.length);
+ * s.receive(recv);
+ * ...
+ * // OK, I'm done talking - leave the group...
+ * s.leaveGroup(group);
+ * </PRE>
+ *
+ * When one sends a message to a multicast group, <B>all</B> subscribing
+ * recipients to that host and port receive the message (within the
+ * time-to-live range of the packet, see below).  The socket needn't
+ * be a member of the multicast group to send messages to it.
+ * <P>
+ * When a socket subscribes to a multicast group/port, it receives
+ * datagrams sent by other hosts to the group/port, as do all other
+ * members of the group and port.  A socket relinquishes membership
+ * in a group by the leaveGroup(InetAddress addr) method.  <B>
+ * Multiple MulticastSocket's</B> may subscribe to a multicast group
+ * and port concurrently, and they will all receive group datagrams.
+ * <P>
+ * Currently applets are not allowed to use multicast sockets.
+ *
+ * @author Pavani Diwanji
+ * @since  JDK1.1
+ */
+public
+class MulticastSocket extends DatagramSocket {
+
+    /**
+     * Used on some platforms to record if an outgoing interface
+     * has been set for this socket.
+     */
+    private boolean interfaceSet;
+
+    /**
+     * Create a multicast socket.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with 0 as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     * <p>
+     * When the socket is created the
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is
+     * called to enable the SO_REUSEADDR socket option.
+     *
+     * @exception IOException if an I/O exception occurs
+     * while creating the MulticastSocket
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @see SecurityManager#checkListen
+     * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     */
+    public MulticastSocket() throws IOException {
+        this(new InetSocketAddress(0));
+    }
+
+    /**
+     * Create a multicast socket and bind it to a specific port.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     * <p>
+     * When the socket is created the
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is
+     * called to enable the SO_REUSEADDR socket option.
+     *
+     * @param port port to use
+     * @exception IOException if an I/O exception occurs
+     * while creating the MulticastSocket
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @see SecurityManager#checkListen
+     * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     */
+    public MulticastSocket(int port) throws IOException {
+        this(new InetSocketAddress(port));
+    }
+
+    /**
+     * Create a MulticastSocket bound to the specified socket address.
+     * <p>
+     * Or, if the address is {@code null}, create an unbound socket.
+     *
+     * <p>If there is a security manager,
+     * its {@code checkListen} method is first called
+     * with the SocketAddress port as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     * <p>
+     * When the socket is created the
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is
+     * called to enable the SO_REUSEADDR socket option.
+     *
+     * @param bindaddr Socket address to bind to, or {@code null} for
+     *                 an unbound socket.
+     * @exception IOException if an I/O exception occurs
+     * while creating the MulticastSocket
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkListen} method doesn't allow the operation.
+     * @see SecurityManager#checkListen
+     * @see java.net.DatagramSocket#setReuseAddress(boolean)
+     *
+     * @since 1.4
+     */
+    public MulticastSocket(SocketAddress bindaddr) throws IOException {
+        super((SocketAddress) null);
+
+        // Enable SO_REUSEADDR before binding
+        setReuseAddress(true);
+
+        if (bindaddr != null) {
+            try {
+                bind(bindaddr);
+            } finally {
+                if (!isBound())
+                    close();
+            }
+        }
+    }
+
+    /**
+     * The lock on the socket's TTL. This is for set/getTTL and
+     * send(packet,ttl).
+     */
+    private Object ttlLock = new Object();
+
+    /**
+     * The lock on the socket's interface - used by setInterface
+     * and getInterface
+     */
+    private Object infLock = new Object();
+
+    /**
+     * The "last" interface set by setInterface on this MulticastSocket
+     */
+    private InetAddress infAddress = null;
+
+
+    /**
+     * Set the default time-to-live for multicast packets sent out
+     * on this {@code MulticastSocket} in order to control the
+     * scope of the multicasts.
+     *
+     * <p>The ttl is an <b>unsigned</b> 8-bit quantity, and so <B>must</B> be
+     * in the range {@code 0 <= ttl <= 0xFF }.
+     *
+     * @param ttl the time-to-live
+     * @exception IOException if an I/O exception occurs
+     * while setting the default time-to-live value
+     * @deprecated use the setTimeToLive method instead, which uses
+     * <b>int</b> instead of <b>byte</b> as the type for ttl.
+     * @see #getTTL()
+     */
+    @Deprecated
+    public void setTTL(byte ttl) throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setTTL(ttl);
+    }
+
+    /**
+     * Set the default time-to-live for multicast packets sent out
+     * on this {@code MulticastSocket} in order to control the
+     * scope of the multicasts.
+     *
+     * <P> The ttl <B>must</B> be in the range {@code  0 <= ttl <=
+     * 255} or an {@code IllegalArgumentException} will be thrown.
+     * Multicast packets sent with a TTL of {@code 0} are not transmitted
+     * on the network but may be delivered locally.
+     *
+     * @param  ttl
+     *         the time-to-live
+     *
+     * @throws  IOException
+     *          if an I/O exception occurs while setting the
+     *          default time-to-live value
+     *
+     * @see #getTimeToLive()
+     */
+    public void setTimeToLive(int ttl) throws IOException {
+        if (ttl < 0 || ttl > 255) {
+            throw new IllegalArgumentException("ttl out of range");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setTimeToLive(ttl);
+    }
+
+    /**
+     * Get the default time-to-live for multicast packets sent out on
+     * the socket.
+     *
+     * @exception IOException if an I/O exception occurs
+     * while getting the default time-to-live value
+     * @return the default time-to-live value
+     * @deprecated use the getTimeToLive method instead, which returns
+     * an <b>int</b> instead of a <b>byte</b>.
+     * @see #setTTL(byte)
+     */
+    @Deprecated
+    public byte getTTL() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return getImpl().getTTL();
+    }
+
+    /**
+     * Get the default time-to-live for multicast packets sent out on
+     * the socket.
+     * @exception IOException if an I/O exception occurs while
+     * getting the default time-to-live value
+     * @return the default time-to-live value
+     * @see #setTimeToLive(int)
+     */
+    public int getTimeToLive() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return getImpl().getTimeToLive();
+    }
+
+    /**
+     * Joins a multicast group. Its behavior may be affected by
+     * {@code setInterface} or {@code setNetworkInterface}.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to join
+     *
+     * @exception IOException if there is an error joining
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the join.
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     */
+    public void joinGroup(InetAddress mcastaddr) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        checkAddress(mcastaddr, "joinGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(mcastaddr);
+        }
+
+        if (!mcastaddr.isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        /**
+         * required for some platforms where it's not possible to join
+         * a group without setting the interface first.
+         */
+        NetworkInterface defaultInterface = NetworkInterface.getDefault();
+
+        if (!interfaceSet && defaultInterface != null) {
+            setNetworkInterface(defaultInterface);
+        }
+
+        getImpl().join(mcastaddr);
+    }
+
+    /**
+     * Leave a multicast group. Its behavior may be affected by
+     * {@code setInterface} or {@code setNetworkInterface}.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to leave
+     * @exception IOException if there is an error leaving
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the operation.
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     */
+    public void leaveGroup(InetAddress mcastaddr) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        checkAddress(mcastaddr, "leaveGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(mcastaddr);
+        }
+
+        if (!mcastaddr.isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        getImpl().leave(mcastaddr);
+    }
+
+    /**
+     * Joins the specified multicast group at the specified interface.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to join
+     * @param netIf specifies the local interface to receive multicast
+     *        datagram packets, or <i>null</i> to defer to the interface set by
+     *       {@link MulticastSocket#setInterface(InetAddress)} or
+     *       {@link MulticastSocket#setNetworkInterface(NetworkInterface)}
+     *
+     * @exception IOException if there is an error joining
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the join.
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     * @since 1.4
+     */
+    public void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+
+        if (oldImpl)
+            throw new UnsupportedOperationException();
+
+        checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "joinGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
+        }
+
+        if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        getImpl().joinGroup(mcastaddr, netIf);
+    }
+
+    /**
+     * Leave a multicast group on a specified local interface.
+     *
+     * <p>If there is a security manager, this method first
+     * calls its {@code checkMulticast} method
+     * with the {@code mcastaddr} argument
+     * as its argument.
+     *
+     * @param mcastaddr is the multicast address to leave
+     * @param netIf specifies the local interface or <i>null</i> to defer
+     *             to the interface set by
+     *             {@link MulticastSocket#setInterface(InetAddress)} or
+     *             {@link MulticastSocket#setNetworkInterface(NetworkInterface)}
+     * @exception IOException if there is an error leaving
+     * or when the address is not a multicast address.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkMulticast} method doesn't allow the operation.
+     * @throws  IllegalArgumentException if mcastaddr is null or is a
+     *          SocketAddress subclass not supported by this socket
+     *
+     * @see SecurityManager#checkMulticast(InetAddress)
+     * @since 1.4
+     */
+    public void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf)
+        throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+
+        if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+
+        if (oldImpl)
+            throw new UnsupportedOperationException();
+
+        checkAddress(((InetSocketAddress)mcastaddr).getAddress(), "leaveGroup");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkMulticast(((InetSocketAddress)mcastaddr).getAddress());
+        }
+
+        if (!((InetSocketAddress)mcastaddr).getAddress().isMulticastAddress()) {
+            throw new SocketException("Not a multicast address");
+        }
+
+        getImpl().leaveGroup(mcastaddr, netIf);
+     }
+
+    /**
+     * Set the multicast network interface used by methods
+     * whose behavior would be affected by the value of the
+     * network interface. Useful for multihomed hosts.
+     * @param inf the InetAddress
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @see #getInterface()
+     */
+    public void setInterface(InetAddress inf) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+        checkAddress(inf, "setInterface");
+        synchronized (infLock) {
+            getImpl().setOption(SocketOptions.IP_MULTICAST_IF, inf);
+            infAddress = inf;
+            interfaceSet = true;
+        }
+    }
+
+    /**
+     * Retrieve the address of the network interface used for
+     * multicast packets.
+     *
+     * @return An {@code InetAddress} representing
+     *  the address of the network interface used for
+     *  multicast packets.
+     *
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     *
+     * @see #setInterface(java.net.InetAddress)
+     */
+    public InetAddress getInterface() throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+        synchronized (infLock) {
+            InetAddress ia =
+                (InetAddress)getImpl().getOption(SocketOptions.IP_MULTICAST_IF);
+
+            /**
+             * No previous setInterface or interface can be
+             * set using setNetworkInterface
+             */
+            if (infAddress == null) {
+                return ia;
+            }
+
+            /**
+             * Same interface set with setInterface?
+             */
+            if (ia.equals(infAddress)) {
+                return ia;
+            }
+
+            /**
+             * Different InetAddress from what we set with setInterface
+             * so enumerate the current interface to see if the
+             * address set by setInterface is bound to this interface.
+             */
+            try {
+                NetworkInterface ni = NetworkInterface.getByInetAddress(ia);
+                Enumeration<InetAddress> addrs = ni.getInetAddresses();
+                while (addrs.hasMoreElements()) {
+                    InetAddress addr = addrs.nextElement();
+                    if (addr.equals(infAddress)) {
+                        return infAddress;
+                    }
+                }
+
+                /**
+                 * No match so reset infAddress to indicate that the
+                 * interface has changed via means
+                 */
+                infAddress = null;
+                return ia;
+            } catch (Exception e) {
+                return ia;
+            }
+        }
+    }
+
+    /**
+     * Specify the network interface for outgoing multicast datagrams
+     * sent on this socket.
+     *
+     * @param netIf the interface
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @see #getNetworkInterface()
+     * @since 1.4
+     */
+    public void setNetworkInterface(NetworkInterface netIf)
+        throws SocketException {
+
+        synchronized (infLock) {
+            getImpl().setOption(SocketOptions.IP_MULTICAST_IF2, netIf);
+            infAddress = null;
+            interfaceSet = true;
+        }
+    }
+
+    /**
+     * Get the multicast network interface set.
+     *
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @return the multicast {@code NetworkInterface} currently set
+     * @see #setNetworkInterface(NetworkInterface)
+     * @since 1.4
+     */
+    public NetworkInterface getNetworkInterface() throws SocketException {
+        // Android-changed: Support Integer IP_MULTICAST_IF2 values for app compat.
+        Integer niIndex
+            = (Integer)getImpl().getOption(SocketOptions.IP_MULTICAST_IF2);
+        if (niIndex == 0) {
+            InetAddress[] addrs = new InetAddress[1];
+            addrs[0] = InetAddress.anyLocalAddress();
+            return new NetworkInterface(addrs[0].getHostName(), 0, addrs);
+        } else {
+            return NetworkInterface.getByIndex(niIndex);
+        }
+    }
+
+    /**
+     * Disable/Enable local loopback of multicast datagrams
+     * The option is used by the platform's networking code as a hint
+     * for setting whether multicast data will be looped back to
+     * the local socket.
+     *
+     * <p>Because this option is a hint, applications that want to
+     * verify what loopback mode is set to should call
+     * {@link #getLoopbackMode()}
+     * @param disable {@code true} to disable the LoopbackMode
+     * @throws SocketException if an error occurs while setting the value
+     * @since 1.4
+     * @see #getLoopbackMode
+     */
+    public void setLoopbackMode(boolean disable) throws SocketException {
+        getImpl().setOption(SocketOptions.IP_MULTICAST_LOOP, Boolean.valueOf(disable));
+    }
+
+    /**
+     * Get the setting for local loopback of multicast datagrams.
+     *
+     * @throws SocketException  if an error occurs while getting the value
+     * @return true if the LoopbackMode has been disabled
+     * @since 1.4
+     * @see #setLoopbackMode
+     */
+    public boolean getLoopbackMode() throws SocketException {
+        return ((Boolean)getImpl().getOption(SocketOptions.IP_MULTICAST_LOOP)).booleanValue();
+    }
+
+    /**
+     * Sends a datagram packet to the destination, with a TTL (time-
+     * to-live) other than the default for the socket.  This method
+     * need only be used in instances where a particular TTL is desired;
+     * otherwise it is preferable to set a TTL once on the socket, and
+     * use that default TTL for all packets.  This method does <B>not
+     * </B> alter the default TTL for the socket. Its behavior may be
+     * affected by {@code setInterface}.
+     *
+     * <p>If there is a security manager, this method first performs some
+     * security checks. First, if {@code p.getAddress().isMulticastAddress()}
+     * is true, this method calls the
+     * security manager's {@code checkMulticast} method
+     * with {@code p.getAddress()} and {@code ttl} as its arguments.
+     * If the evaluation of that expression is false,
+     * this method instead calls the security manager's
+     * {@code checkConnect} method with arguments
+     * {@code p.getAddress().getHostAddress()} and
+     * {@code p.getPort()}. Each call to a security manager method
+     * could result in a SecurityException if the operation is not allowed.
+     *
+     * @param p is the packet to be sent. The packet should contain
+     * the destination multicast ip address and the data to be sent.
+     * One does not need to be the member of the group to send
+     * packets to a destination multicast address.
+     * @param ttl optional time to live for multicast packet.
+     * default ttl is 1.
+     *
+     * @exception IOException is raised if an error occurs i.e
+     * error while setting ttl.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkMulticast} or {@code checkConnect}
+     *             method doesn't allow the send.
+     *
+     * @deprecated Use the following code or its equivalent instead:
+     *  ......
+     *  int ttl = mcastSocket.getTimeToLive();
+     *  mcastSocket.setTimeToLive(newttl);
+     *  mcastSocket.send(p);
+     *  mcastSocket.setTimeToLive(ttl);
+     *  ......
+     *
+     * @see DatagramSocket#send
+     * @see DatagramSocket#receive
+     * @see SecurityManager#checkMulticast(java.net.InetAddress, byte)
+     * @see SecurityManager#checkConnect
+     */
+    @Deprecated
+    public void send(DatagramPacket p, byte ttl)
+        throws IOException {
+            if (isClosed())
+                throw new SocketException("Socket is closed");
+            checkAddress(p.getAddress(), "send");
+            synchronized(ttlLock) {
+                synchronized(p) {
+                    if (connectState == ST_NOT_CONNECTED) {
+                        // Security manager makes sure that the multicast address
+                        // is allowed one and that the ttl used is less
+                        // than the allowed maxttl.
+                        SecurityManager security = System.getSecurityManager();
+                        if (security != null) {
+                            if (p.getAddress().isMulticastAddress()) {
+                                security.checkMulticast(p.getAddress(), ttl);
+                            } else {
+                                security.checkConnect(p.getAddress().getHostAddress(),
+                                                      p.getPort());
+                            }
+                        }
+                    } else {
+                        // we're connected
+                        InetAddress packetAddress = null;
+                        packetAddress = p.getAddress();
+                        if (packetAddress == null) {
+                            p.setAddress(connectedAddress);
+                            p.setPort(connectedPort);
+                        } else if ((!packetAddress.equals(connectedAddress)) ||
+                                   p.getPort() != connectedPort) {
+                            throw new SecurityException("connected address and packet address" +
+                                                        " differ");
+                        }
+                    }
+                    byte dttl = getTTL();
+                    try {
+                        if (ttl != dttl) {
+                            // set the ttl
+                            getImpl().setTTL(ttl);
+                        }
+                        // call the datagram method to send
+                        getImpl().send(p);
+                    } finally {
+                        // set it back to default
+                        if (ttl != dttl) {
+                            getImpl().setTTL(dttl);
+                        }
+                    }
+                } // synch p
+            }  //synch ttl
+    } //method
+}
diff --git a/java/net/NetPermission.java b/java/net/NetPermission.java
new file mode 100644
index 0000000..b5a0eab
--- /dev/null
+++ b/java/net/NetPermission.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class NetPermission extends BasicPermission {
+
+    public NetPermission(String name)
+    {
+        super("");
+    }
+
+    public NetPermission(String name, String actions)
+    {
+        super("", "");
+    }
+}
diff --git a/java/net/NetworkInterface.java b/java/net/NetworkInterface.java
new file mode 100644
index 0000000..a30b6bf
--- /dev/null
+++ b/java/net/NetworkInterface.java
@@ -0,0 +1,748 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import android.system.ErrnoException;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import android.system.StructIfaddrs;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import sun.security.action.*;
+import java.security.AccessController;
+
+import static android.system.OsConstants.*;
+
+// Android-note: NetworkInterface has been rewritten to avoid native code.
+// Fix upstream bug not returning link-down interfaces. http://b/26238832
+// Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+/**
+ * This class represents a Network Interface made up of a name,
+ * and a list of IP addresses assigned to this interface.
+ * It is used to identify the local interface on which a multicast group
+ * is joined.
+ *
+ * Interfaces are normally known by names such as "le0".
+ * <p>
+ * <a name="access-restrictions"></a>Note that information about
+ * {@link NetworkInterface}s may be restricted. For example, non-system apps
+ * with {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R} will only
+ * have access to information about {@link NetworkInterface}s that are
+ * associated with an {@link InetAddress}.
+ *
+ * @since 1.4
+ */
+public final class NetworkInterface {
+    private String name;
+    private String displayName;
+    private int index;
+    private InetAddress addrs[];
+    private InterfaceAddress bindings[];
+    // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+    // private NetworkInterface childs[];
+    private List<NetworkInterface> childs;
+    private NetworkInterface parent = null;
+    private boolean virtual = false;
+    private static final NetworkInterface defaultInterface;
+    private static final int defaultIndex; /* index of defaultInterface */
+
+    // Android-changed: Fix upstream bug not returning link-down interfaces. http://b/26238832
+    private byte[] hardwareAddr;
+
+    static {
+        // Android-removed: Android doesn't need to call native init.
+        /*
+        AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Void>() {
+                public Void run() {
+                    System.loadLibrary("net");
+                    return null;
+                }
+            });
+
+        init();
+        */
+        defaultInterface = DefaultInterface.getDefault();
+        if (defaultInterface != null) {
+            defaultIndex = defaultInterface.getIndex();
+        } else {
+            defaultIndex = 0;
+        }
+    }
+
+    /**
+     * Returns an NetworkInterface object with index set to 0 and name to null.
+     * Setting such an interface on a MulticastSocket will cause the
+     * kernel to choose one interface for sending multicast packets.
+     *
+     */
+    NetworkInterface() {
+    }
+
+    NetworkInterface(String name, int index, InetAddress[] addrs) {
+        this.name = name;
+        this.index = index;
+        this.addrs = addrs;
+    }
+
+    /**
+     * Get the name of this network interface.
+     *
+     * @return the name of this network interface
+     */
+    public String getName() {
+            return name;
+    }
+
+    /**
+     * Convenience method to return an Enumeration with all or a
+     * subset of the InetAddresses bound to this network interface.
+     * <p>
+     * If there is a security manager, its {@code checkConnect}
+     * method is called for each InetAddress. Only InetAddresses where
+     * the {@code checkConnect} doesn't throw a SecurityException
+     * will be returned in the Enumeration. However, if the caller has the
+     * {@link NetPermission}("getNetworkInformation") permission, then all
+     * InetAddresses are returned.
+     * @return an Enumeration object with all or a subset of the InetAddresses
+     * bound to this network interface
+     */
+    public Enumeration<InetAddress> getInetAddresses() {
+
+        class checkedAddresses implements Enumeration<InetAddress> {
+
+            private int i=0, count=0;
+            private InetAddress local_addrs[];
+
+            checkedAddresses() {
+                local_addrs = new InetAddress[addrs.length];
+                boolean trusted = true;
+
+                SecurityManager sec = System.getSecurityManager();
+                if (sec != null) {
+                    try {
+                        sec.checkPermission(new NetPermission("getNetworkInformation"));
+                    } catch (SecurityException e) {
+                        trusted = false;
+                    }
+                }
+                for (int j=0; j<addrs.length; j++) {
+                    try {
+                        if (sec != null && !trusted) {
+                            sec.checkConnect(addrs[j].getHostAddress(), -1);
+                        }
+                        local_addrs[count++] = addrs[j];
+                    } catch (SecurityException e) { }
+                }
+
+            }
+
+            public InetAddress nextElement() {
+                if (i < count) {
+                    return local_addrs[i++];
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            public boolean hasMoreElements() {
+                return (i < count);
+            }
+        }
+        return new checkedAddresses();
+
+    }
+
+    /**
+     * Get a List of all or a subset of the {@code InterfaceAddresses}
+     * of this network interface.
+     * <p>
+     * If there is a security manager, its {@code checkConnect}
+     * method is called with the InetAddress for each InterfaceAddress.
+     * Only InterfaceAddresses where the {@code checkConnect} doesn't throw
+     * a SecurityException will be returned in the List.
+     *
+     * @return a {@code List} object with all or a subset of the
+     *         InterfaceAddresss of this network interface
+     * @since 1.6
+     */
+    public java.util.List<InterfaceAddress> getInterfaceAddresses() {
+        java.util.List<InterfaceAddress> lst = new java.util.ArrayList<InterfaceAddress>(1);
+        // BEGIN Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
+        // http://b/30628919
+        if (bindings != null) {
+            SecurityManager sec = System.getSecurityManager();
+            for (int j=0; j<bindings.length; j++) {
+                try {
+                    if (sec != null) {
+                        sec.checkConnect(bindings[j].getAddress().getHostAddress(), -1);
+                    }
+                    lst.add(bindings[j]);
+                } catch (SecurityException e) { }
+            }
+        }
+        // END Android-changed: Cherry-picked upstream OpenJDK9 change rev 59a110a38cea
+        return lst;
+    }
+
+    /**
+     * Get an Enumeration with all the subinterfaces (also known as virtual
+     * interfaces) attached to this network interface.
+     * <p>
+     * For instance eth0:1 will be a subinterface to eth0.
+     *
+     * @return an Enumeration object with all of the subinterfaces
+     * of this network interface
+     * @since 1.6
+     */
+    public Enumeration<NetworkInterface> getSubInterfaces() {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return Collections.enumeration(childs);
+    }
+
+    /**
+     * Returns the parent NetworkInterface of this interface if this is
+     * a subinterface, or {@code null} if it is a physical
+     * (non virtual) interface or has no parent.
+     *
+     * @return The {@code NetworkInterface} this interface is attached to.
+     * @since 1.6
+     */
+    public NetworkInterface getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the index of this network interface. The index is an integer greater
+     * or equal to zero, or {@code -1} for unknown. This is a system specific value
+     * and interfaces with the same name can have different indexes on different
+     * machines.
+     *
+     * @return the index of this network interface or {@code -1} if the index is
+     *         unknown
+     * @see #getByIndex(int)
+     * @since 1.7
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Get the display name of this network interface.
+     * A display name is a human readable String describing the network
+     * device.
+     *
+     * @return a non-empty string representing the display name of this network
+     *         interface, or null if no display name is available.
+     */
+    public String getDisplayName() {
+        /* strict TCK conformance */
+        return "".equals(displayName) ? null : displayName;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Searches for the network interface with the specified name.
+     *
+     * @param   name
+     *          The name of the network interface.
+     *
+     * @return  A {@code NetworkInterface} with the specified name,
+     *          or {@code null} if the network interface with the specified
+     *          name does not exist or <a href="#access-restrictions">can't be
+     *          accessed</a>.
+     *
+     * @throws  SocketException
+     *          If an I/O error occurs.
+     *
+     * @throws  NullPointerException
+     *          If the specified name is {@code null}.
+     */
+    public static NetworkInterface getByName(String name) throws SocketException {
+        if (name == null)
+            throw new NullPointerException();
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        NetworkInterface[] nis = getAll();
+        for (NetworkInterface ni : nis) {
+            if (ni.getName().equals(name)) {
+                return ni;
+            }
+        }
+        return null;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Get a network interface given its index.
+     *
+     * @param index an integer, the index of the interface
+     * @return the NetworkInterface obtained from its index, or {@code null} if
+     *         an interface with the specified index does not exist or
+     *         <a href="#access-restrictions">can't be accessed</a>.
+     * @throws  SocketException  if an I/O error occurs.
+     * @throws  IllegalArgumentException if index has a negative value
+     * @see #getIndex()
+     * @since 1.7
+     */
+    public static NetworkInterface getByIndex(int index) throws SocketException {
+        if (index < 0)
+            throw new IllegalArgumentException("Interface index can't be negative");
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        NetworkInterface[] nis = getAll();
+        for (NetworkInterface ni : nis) {
+            if (ni.getIndex() == index) {
+                return ni;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Convenience method to search for a network interface that
+     * has the specified Internet Protocol (IP) address bound to
+     * it.
+     * <p>
+     * If the specified IP address is bound to multiple network
+     * interfaces it is not defined which network interface is
+     * returned.
+     *
+     * @param   addr
+     *          The {@code InetAddress} to search with.
+     *
+     * @return  A {@code NetworkInterface}
+     *          or {@code null} if there is no network interface
+     *          with the specified IP address.
+     *
+     * @throws  SocketException
+     *          If an I/O error occurs.
+     *
+     * @throws  NullPointerException
+     *          If the specified address is {@code null}.
+     */
+    public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketException {
+        if (addr == null) {
+            throw new NullPointerException();
+        }
+        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
+            throw new IllegalArgumentException ("invalid address type");
+        }
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        NetworkInterface[] nis = getAll();
+        for (NetworkInterface ni : nis) {
+            for (InetAddress inetAddress : Collections.list(ni.getInetAddresses())) {
+                if (inetAddress.equals(addr)) {
+                    return ni;
+                }
+            }
+        }
+        return null;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Returns all the interfaces on this machine. The {@code Enumeration}
+     * contains at least one element, possibly representing a loopback
+     * interface that only supports communication between entities on
+     * this machine.
+     *
+     * NOTE: can use getNetworkInterfaces()+getInetAddresses()
+     *       to obtain all IP addresses for this node
+     * <p>
+     * For non-system apps with
+     * {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}, this
+     * method will only return information for {@link NetworkInterface}s that
+     * are associated with an {@link InetAddress}.
+     *
+     * @return an Enumeration of NetworkInterfaces found on this machine
+     *         that <a href="#access-restrictions">are accessible</a>.
+     * @exception  SocketException  if an I/O error occurs.
+     */
+
+    public static Enumeration<NetworkInterface> getNetworkInterfaces()
+        throws SocketException {
+        final NetworkInterface[] netifs = getAll();
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        // // specified to return null if no network interfaces
+        // if (netifs == null)
+        if (netifs.length == 0)
+            return null;
+
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        /*
+        return new Enumeration<NetworkInterface>() {
+            private int i = 0;
+            public NetworkInterface nextElement() {
+                if (netifs != null && i < netifs.length) {
+                    NetworkInterface netif = netifs[i++];
+                    return netif;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+
+            public boolean hasMoreElements() {
+                return (netifs != null && i < netifs.length);
+            }
+        };
+        */
+        return Collections.enumeration(Arrays.asList(netifs));
+    }
+
+    // BEGIN Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+    // private native static NetworkInterface[] getAll()
+    //    throws SocketException;
+    private static NetworkInterface[] getAll() throws SocketException {
+        // Group Ifaddrs by interface name.
+        Map<String, List<StructIfaddrs>> inetMap = new HashMap<>();
+
+        StructIfaddrs[] ifaddrs;
+        try {
+            ifaddrs = Libcore.os.getifaddrs();
+        } catch (ErrnoException e) {
+            throw e.rethrowAsSocketException();
+        }
+
+        for (StructIfaddrs ifa : ifaddrs) {
+            String name = ifa.ifa_name;
+
+            List<StructIfaddrs> ifas;
+            if ((ifas = inetMap.get(name)) == null) {
+                ifas = new ArrayList<>();
+                inetMap.put(name, ifas);
+            }
+
+            ifas.add(ifa);
+        }
+
+        // Populate NetworkInterface instances.
+        Map<String, NetworkInterface> nis = new HashMap<>(inetMap.size());
+        for (Map.Entry<String, List<StructIfaddrs>> e : inetMap.entrySet()) {
+            String name = e.getKey();
+            int index = Libcore.os.if_nametoindex(e.getKey());
+            if (index == 0) {
+                // This interface has gone away between getifaddrs and if_nametoindex
+                continue;
+            }
+
+            NetworkInterface ni = new NetworkInterface(name, index, null);
+            ni.displayName = name;
+
+            List<InetAddress> addrs = new ArrayList<>();
+            List<InterfaceAddress> binds = new ArrayList<>();
+
+            for (StructIfaddrs ifa : e.getValue()) {
+                if (ifa.ifa_addr != null) {
+                    addrs.add(ifa.ifa_addr);
+                    binds.add(new InterfaceAddress(ifa.ifa_addr, (Inet4Address) ifa.ifa_broadaddr,
+                                                   ifa.ifa_netmask));
+                }
+
+                if (ifa.hwaddr != null) {
+                    ni.hardwareAddr = ifa.hwaddr;
+                }
+            }
+
+            ni.addrs = addrs.toArray(new InetAddress[addrs.size()]);
+            ni.bindings = binds.toArray(new InterfaceAddress[binds.size()]);
+            ni.childs = new ArrayList<>(0);
+            nis.put(name, ni);
+        }
+
+        // Populate childs/parent.
+        for (Map.Entry<String, NetworkInterface> e : nis.entrySet()) {
+            NetworkInterface ni = e.getValue();
+            String niName = ni.getName();
+            int colonIdx = niName.indexOf(':');
+            if (colonIdx != -1) {
+                // This is a virtual interface.
+                String parentName = niName.substring(0, colonIdx);
+                NetworkInterface parent = nis.get(parentName);
+
+                ni.virtual = true;
+                ni.parent = parent;
+                parent.childs.add(ni);
+            }
+        }
+
+        return nis.values().toArray(new NetworkInterface[nis.size()]);
+    }
+    // END Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+
+    /**
+     * Returns whether a network interface is up and running.
+     *
+     * @return  {@code true} if the interface is up and running.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean isUp() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        final int mask = IFF_UP | IFF_RUNNING;
+        return (getFlags() & mask) == mask;
+    }
+
+    /**
+     * Returns whether a network interface is a loopback interface.
+     *
+     * @return  {@code true} if the interface is a loopback interface.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean isLoopback() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return (getFlags() & IFF_LOOPBACK) != 0;
+    }
+
+    /**
+     * Returns whether a network interface is a point to point interface.
+     * A typical point to point interface would be a PPP connection through
+     * a modem.
+     *
+     * @return  {@code true} if the interface is a point to point
+     *          interface.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean isPointToPoint() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return (getFlags() & IFF_POINTOPOINT) != 0;
+    }
+
+    /**
+     * Returns whether a network interface supports multicasting or not.
+     *
+     * @return  {@code true} if the interface supports Multicasting.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+
+    public boolean supportsMulticast() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        return (getFlags() & IFF_MULTICAST) != 0;
+    }
+
+    // Android-added: Document restrictions for targetSdkVersion >= R. http://b/141455849
+    /**
+     * Returns the hardware address (usually MAC) of the interface if it
+     * has one and if it can be accessed given the current privileges.
+     * If a security manager is set, then the caller must have
+     * the permission {@link NetPermission}("getNetworkInformation").
+     *
+     * @return  a byte array containing the address, or {@code null} if
+     *          the address doesn't exist, is not accessible or a security
+     *          manager is set and the caller does not have the permission
+     *          NetPermission("getNetworkInformation"). For example, this
+     *          method will generally return {@code null} when called by
+     *          non-system apps having
+     *          {@code targetSdkVersion >= android.os.Build.VERSION_CODES.R}.
+     *
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+    public byte[] getHardwareAddress() throws SocketException {
+        // BEGIN Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
+        /*
+        for (InetAddress addr : addrs) {
+            if (addr instanceof Inet4Address) {
+                return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
+            }
+        }
+        return getMacAddr0(null, name, index);
+         */
+        NetworkInterface ni = getByName(name);
+        if (ni == null) {
+            throw new SocketException("NetworkInterface doesn't exist anymore");
+        }
+        return ni.hardwareAddr;
+        // END Android-changed: Fix upstream not returning link-down interfaces. http://b/26238832
+    }
+
+    /**
+     * Returns the Maximum Transmission Unit (MTU) of this interface.
+     *
+     * @return the value of the MTU for that interface.
+     * @exception       SocketException if an I/O error occurs.
+     * @since 1.6
+     */
+    public int getMTU() throws SocketException {
+        // Android-changed: Rewrote NetworkInterface on top of Libcore.io.
+        // return getMTU0(name, index);
+        FileDescriptor fd = null;
+        try {
+            fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
+            return Libcore.rawOs.ioctlMTU(fd, name);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsSocketException();
+        } catch (Exception ex) {
+            throw new SocketException(ex);
+        } finally {
+            IoUtils.closeQuietly(fd);
+        }
+    }
+
+    /**
+     * Returns whether this interface is a virtual interface (also called
+     * subinterface).
+     * Virtual interfaces are, on some systems, interfaces created as a child
+     * of a physical interface and given different settings (like address or
+     * MTU). Usually the name of the interface will the name of the parent
+     * followed by a colon (:) and a number identifying the child since there
+     * can be several virtual interfaces attached to a single physical
+     * interface.
+     *
+     * @return {@code true} if this interface is a virtual interface.
+     * @since 1.6
+     */
+    public boolean isVirtual() {
+        return virtual;
+    }
+
+    // BEGIN Android-removed: Rewrote NetworkInterface on top of Libcore.io.
+    /*
+    private native static boolean isUp0(String name, int ind) throws SocketException;
+    private native static boolean isLoopback0(String name, int ind) throws SocketException;
+    private native static boolean supportsMulticast0(String name, int ind) throws SocketException;
+    private native static boolean isP2P0(String name, int ind) throws SocketException;
+    private native static byte[] getMacAddr0(byte[] inAddr, String name, int ind) throws SocketException;
+    private native static int getMTU0(String name, int ind) throws SocketException;
+    */
+    // END Android-removed: Rewrote NetworkInterface on top of Libcore.io.
+
+    // BEGIN Android-added: Rewrote NetworkInterface on top of Libcore.io.
+    private int getFlags() throws SocketException {
+        FileDescriptor fd = null;
+        try {
+            fd = Libcore.rawOs.socket(AF_INET, SOCK_DGRAM, 0);
+            return Libcore.rawOs.ioctlFlags(fd, name);
+        } catch (ErrnoException e) {
+            throw e.rethrowAsSocketException();
+        } catch (Exception ex) {
+            throw new SocketException(ex);
+        } finally {
+            IoUtils.closeQuietly(fd);
+        }
+    }
+    // END Android-added: Rewrote NetworkInterface on top of Libcore.io.
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same NetworkInterface
+     * as this object.
+     * <p>
+     * Two instances of {@code NetworkInterface} represent the same
+     * NetworkInterface if both name and addrs are the same for both.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see     java.net.InetAddress#getAddress()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof NetworkInterface)) {
+            return false;
+        }
+        NetworkInterface that = (NetworkInterface)obj;
+        if (this.name != null ) {
+            if (!this.name.equals(that.name)) {
+                return false;
+            }
+        } else {
+            if (that.name != null) {
+                return false;
+            }
+        }
+
+        if (this.addrs == null) {
+            return that.addrs == null;
+        } else if (that.addrs == null) {
+            return false;
+        }
+
+        /* Both addrs not null. Compare number of addresses */
+
+        if (this.addrs.length != that.addrs.length) {
+            return false;
+        }
+
+        InetAddress[] thatAddrs = that.addrs;
+        int count = thatAddrs.length;
+
+        for (int i=0; i<count; i++) {
+            boolean found = false;
+            for (int j=0; j<count; j++) {
+                if (addrs[i].equals(thatAddrs[j])) {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public int hashCode() {
+        return name == null? 0: name.hashCode();
+    }
+
+    public String toString() {
+        String result = "name:";
+        result += name == null? "null": name;
+        if (displayName != null) {
+            result += " (" + displayName + ")";
+        }
+        return result;
+    }
+
+    // Android-removed: Android doesn't need to call native init.
+    // private static native void init();
+
+    /**
+     * Returns the default network interface of this system
+     *
+     * @return the default interface
+     */
+    static NetworkInterface getDefault() {
+        return defaultInterface;
+    }
+}
diff --git a/java/net/NoRouteToHostException.java b/java/net/NoRouteToHostException.java
new file mode 100644
index 0000000..76f0814
--- /dev/null
+++ b/java/net/NoRouteToHostException.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an error occurred while attempting to connect a
+ * socket to a remote address and port.  Typically, the remote
+ * host cannot be reached because of an intervening firewall, or
+ * if an intermediate router is down.
+ *
+ * @since   JDK1.1
+ */
+public class NoRouteToHostException extends SocketException {
+    private static final long serialVersionUID = -1897550894873493790L;
+
+    /**
+     * Constructs a new NoRouteToHostException with the specified detail
+     * message as to why the remote host cannot be reached.
+     * A detail message is a String that gives a specific
+     * description of this error.
+     * @param msg the detail message
+     */
+    public NoRouteToHostException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new NoRouteToHostException with no detailed message.
+     */
+    public NoRouteToHostException() {}
+}
diff --git a/java/net/PasswordAuthentication.java b/java/net/PasswordAuthentication.java
new file mode 100644
index 0000000..5529568
--- /dev/null
+++ b/java/net/PasswordAuthentication.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+
+/**
+ * The class PasswordAuthentication is a data holder that is used by
+ * Authenticator.  It is simply a repository for a user name and a password.
+ *
+ * @see java.net.Authenticator
+ * @see java.net.Authenticator#getPasswordAuthentication()
+ *
+ * @author  Bill Foote
+ * @since   1.2
+ */
+
+public final class PasswordAuthentication {
+
+    private String userName;
+    private char[] password;
+
+    /**
+     * Creates a new {@code PasswordAuthentication} object from the given
+     * user name and password.
+     *
+     * <p> Note that the given user password is cloned before it is stored in
+     * the new {@code PasswordAuthentication} object.
+     *
+     * @param userName the user name
+     * @param password the user's password
+     */
+    public PasswordAuthentication(String userName, char[] password) {
+        this.userName = userName;
+        this.password = password.clone();
+    }
+
+    /**
+     * Returns the user name.
+     *
+     * @return the user name
+     */
+    public String getUserName() {
+        return userName;
+    }
+
+    /**
+     * Returns the user password.
+     *
+     * <p> Note that this method returns a reference to the password. It is
+     * the caller's responsibility to zero out the password information after
+     * it is no longer needed.
+     *
+     * @return the password
+     */
+    public char[] getPassword() {
+        return password;
+    }
+}
diff --git a/java/net/PlainDatagramSocketImpl.java b/java/net/PlainDatagramSocketImpl.java
new file mode 100644
index 0000000..d4b1f2c
--- /dev/null
+++ b/java/net/PlainDatagramSocketImpl.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2007,2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import android.system.ErrnoException;
+import android.system.StructGroupReq;
+
+import java.io.IOException;
+import libcore.io.IoBridge;
+import libcore.io.Libcore;
+import libcore.util.EmptyArray;
+
+import jdk.net.*;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNSPEC;
+import static android.system.OsConstants.IPPROTO_IP;
+import static android.system.OsConstants.IP_MULTICAST_ALL;
+import static android.system.OsConstants.MSG_PEEK;
+import static android.system.OsConstants.POLLERR;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static libcore.io.IoBridge.JAVA_IP_MULTICAST_TTL;
+import static libcore.io.IoBridge.JAVA_MCAST_JOIN_GROUP;
+import static libcore.io.IoBridge.JAVA_MCAST_LEAVE_GROUP;
+import static sun.net.ExtendedOptionsImpl.*;
+
+/*
+ * On Unix systems we simply delegate to native methods.
+ *
+ * @author Chris Hegarty
+ */
+
+class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
+{
+    // Android-removed: init method has been removed
+    // static {
+    //     init();
+    // }
+
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            super.setOption(name, value);
+        } else {
+            if (isClosed()) {
+                throw new SocketException("Socket closed");
+            }
+            checkSetOptionPermission(name);
+            checkValueType(value, SocketFlow.class);
+            setFlowOption(getFileDescriptor(), (SocketFlow)value);
+        }
+    }
+
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            return super.getOption(name);
+        }
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        checkGetOptionPermission(name);
+        SocketFlow flow = SocketFlow.create();
+        getFlowOption(getFileDescriptor(), flow);
+        return (T)flow;
+    }
+
+    protected void socketSetOption(int opt, Object val) throws SocketException {
+        try {
+            socketSetOption0(opt, val);
+        } catch (SocketException se) {
+            if (!connected)
+                throw se;
+        }
+    }
+
+    // BEGIN Android-changed: Rewrote on top of Libcore.io.
+    protected synchronized void bind0(int lport, InetAddress laddr) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.bind(fd, laddr, lport);
+
+        if (lport == 0) {
+            // Now that we're a connected socket, let's extract the port number that the system
+            // chose for us and store it in the Socket object.
+            localPort = IoBridge.getLocalInetSocketAddress(fd).getPort();
+        } else {
+            localPort = lport;
+        }
+    }
+
+    protected void send(DatagramPacket p) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        if (p.getData() == null || p.getAddress() == null) {
+            throw new NullPointerException("null buffer || null address");
+        }
+
+        int port = connected ? 0 : p.getPort();
+        InetAddress address = connected ? null : p.getAddress();
+        IoBridge.sendto(fd, p.getData(), p.getOffset(), p.getLength(), 0, address, port);
+    }
+
+    protected synchronized int peek(InetAddress i) throws IOException {
+        DatagramPacket p = new DatagramPacket(EmptyArray.BYTE, 0);
+        doRecv(p, MSG_PEEK);
+        i.holder().address = p.getAddress().holder().address;
+        return p.getPort();
+    }
+
+    protected synchronized int peekData(DatagramPacket p) throws IOException {
+        doRecv(p, MSG_PEEK);
+        return p.getPort();
+    }
+
+    protected synchronized void receive0(DatagramPacket p) throws IOException {
+        doRecv(p, 0);
+    }
+
+    private void doRecv(DatagramPacket p, int flags) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        if (timeout != 0) {
+            IoBridge.poll(fd, POLLIN | POLLERR, timeout);
+        }
+
+        IoBridge.recvfrom(false, fd, p.getData(), p.getOffset(), p.bufLength, flags, p,
+                connected);
+    }
+
+    protected void setTimeToLive(int ttl) throws IOException {
+        IoBridge.setSocketOption(fd, JAVA_IP_MULTICAST_TTL, ttl);
+    }
+
+    protected int getTimeToLive() throws IOException {
+        return (Integer) IoBridge.getSocketOption(fd, JAVA_IP_MULTICAST_TTL);
+    }
+
+    protected void setTTL(byte ttl) throws IOException {
+        setTimeToLive((int) ttl & 0xff);
+    }
+
+    protected byte getTTL() throws IOException {
+        return (byte) getTimeToLive();
+    }
+
+    private static StructGroupReq makeGroupReq(InetAddress gr_group,
+            NetworkInterface networkInterface) {
+        int gr_interface = (networkInterface != null) ? networkInterface.getIndex() : 0;
+        return new StructGroupReq(gr_interface, gr_group);
+    }
+
+    protected void join(InetAddress inetaddr, NetworkInterface netIf) throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.setSocketOption(fd, JAVA_MCAST_JOIN_GROUP, makeGroupReq(inetaddr, netIf));
+    }
+
+    protected void leave(InetAddress inetaddr, NetworkInterface netIf)
+        throws IOException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.setSocketOption(fd, JAVA_MCAST_LEAVE_GROUP, makeGroupReq(inetaddr, netIf));
+    }
+
+    protected void datagramSocketCreate() throws SocketException {
+        fd = IoBridge.socket(AF_INET6, SOCK_DGRAM, 0);
+        IoBridge.setSocketOption(fd, SO_BROADCAST, true);
+
+        try {
+            Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_MULTICAST_ALL, 0);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsSocketException();
+        }
+    }
+
+    protected void datagramSocketClose() {
+        try {
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        } catch (IOException ignored) { }
+    }
+
+    protected void socketSetOption0(int opt, Object val) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.setSocketOption(fd, opt, val);
+    }
+
+    protected Object socketGetOption(int opt) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        return IoBridge.getSocketOption(fd, opt);
+    }
+
+    protected void connect0(InetAddress address, int port) throws SocketException {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.connect(fd, address, port);
+    }
+
+    protected void disconnect0(int family) {
+        if (isClosed()) {
+            return;
+        }
+
+        InetAddress inetAddressUnspec = new InetAddress();
+        inetAddressUnspec.holder().family = AF_UNSPEC;
+
+        try {
+            IoBridge.connect(fd, inetAddressUnspec, 0);
+        } catch (SocketException ignored) { }
+    }
+    // END Android-changed: Rewrote on top of Libcore.io.
+
+    // Android-removed: JNI has been removed
+    // /**
+    //  * Perform class load-time initializations.
+    //  */
+    // private native static void init();
+}
diff --git a/java/net/PlainSocketImpl.java b/java/net/PlainSocketImpl.java
new file mode 100644
index 0000000..89ee53e
--- /dev/null
+++ b/java/net/PlainSocketImpl.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+import android.system.ErrnoException;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import libcore.io.AsynchronousCloseMonitor;
+import libcore.io.IoBridge;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import jdk.net.*;
+
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.EAGAIN;
+import static android.system.OsConstants.EBADF;
+import static android.system.OsConstants.EINVAL;
+import static android.system.OsConstants.MSG_OOB;
+import static android.system.OsConstants.POLLERR;
+import static android.system.OsConstants.POLLIN;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.SHUT_RDWR;
+import static sun.net.ExtendedOptionsImpl.*;
+
+// Android-changed: Rewritten to use android.system POSIX calls and assume AF_INET6.
+/*
+ * On Unix systems we simply delegate to native methods.
+ *
+ * @author Chris Hegarty
+ */
+
+class PlainSocketImpl extends AbstractPlainSocketImpl
+{
+    // Android-removed: Android doesn't need to call native initProto.
+    /*
+    static {
+        initProto();
+    }
+    */
+
+    /**
+     * Constructs an empty instance.
+     */
+    PlainSocketImpl() {
+        // Android-changed: Let PlainSocketImpl construct its own FileDescriptor.
+        this.fd = new FileDescriptor();
+    }
+
+    /**
+     * Constructs an instance with the given file descriptor.
+     */
+    // Android-removed: Let PlainSocketImpl construct its own FileDescriptor.
+    /*
+    PlainSocketImpl(FileDescriptor fd) {
+        this.fd = fd;
+    }
+    */
+
+    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            super.setOption(name, value);
+        } else {
+            if (isClosedOrPending()) {
+                throw new SocketException("Socket closed");
+            }
+            checkSetOptionPermission(name);
+            checkValueType(value, SocketFlow.class);
+            setFlowOption(getFileDescriptor(), (SocketFlow)value);
+        }
+    }
+
+    protected <T> T getOption(SocketOption<T> name) throws IOException {
+        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
+            return super.getOption(name);
+        }
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        checkGetOptionPermission(name);
+        SocketFlow flow = SocketFlow.create();
+        getFlowOption(getFileDescriptor(), flow);
+        return (T)flow;
+    }
+
+    // BEGIN Android-changed: Rewrote on top of Libcore.io.
+    protected void socketSetOption(int opt, Object val) throws SocketException {
+        try {
+            socketSetOption0(opt, val);
+        } catch (SocketException se) {
+            if (socket == null || !socket.isConnected())
+                throw se;
+        }
+    }
+
+    void socketCreate(boolean isStream) throws IOException {
+        // The fd object must not change after calling bind, because we rely on this undocumented
+        // behaviour. See libcore.java.net.SocketTest#testFileDescriptorStaysSame.
+        fd.setInt$(IoBridge.socket(AF_INET6, isStream ? SOCK_STREAM : SOCK_DGRAM, 0).getInt$());
+        IoUtils.setFdOwner(fd, this);
+
+        if (serverSocket != null) {
+            IoUtils.setBlocking(fd, false);
+            IoBridge.setSocketOption(fd, SO_REUSEADDR, true);
+        }
+    }
+
+    void socketConnect(InetAddress address, int port, int timeout) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.connect(fd, address, port, timeout);
+
+        this.address = address;
+        this.port = port;
+
+        if (localport == 0) {
+            // If socket is pending close, fd becomes an AF_UNIX socket and calling
+            // getLocalInetSocketAddress will fail.
+            // http://b/34645743
+            if (!isClosedOrPending()) {
+                localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
+            }
+        }
+    }
+
+    void socketBind(InetAddress address, int port) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        IoBridge.bind(fd, address, port);
+
+        this.address = address;
+        if (port == 0) {
+            // Now that we're a connected socket, let's extract the port number that the system
+            // chose for us and store it in the Socket object.
+            localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
+        } else {
+            localport = port;
+        }
+    }
+
+    void socketListen(int count) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        try {
+            Libcore.os.listen(fd, count);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsSocketException();
+        }
+    }
+
+    void socketAccept(SocketImpl s) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        // poll() with a timeout of 0 means "poll for zero millis", but a Socket timeout == 0 means
+        // "wait forever". When timeout == 0 we pass -1 to poll.
+        if (timeout <= 0) {
+            IoBridge.poll(fd, POLLIN | POLLERR, -1);
+        } else {
+            IoBridge.poll(fd, POLLIN | POLLERR, timeout);
+        }
+
+        InetSocketAddress peerAddress = new InetSocketAddress();
+        try {
+            FileDescriptor newfd = Libcore.os.accept(fd, peerAddress);
+
+            s.fd.setInt$(newfd.getInt$());
+            IoUtils.setFdOwner(s.fd, s);
+            s.address = peerAddress.getAddress();
+            s.port = peerAddress.getPort();
+        } catch (ErrnoException errnoException) {
+            if (errnoException.errno == EAGAIN) {
+                SocketTimeoutException e = new SocketTimeoutException();
+                e.initCause(errnoException);
+                throw e;
+            } else if (errnoException.errno == EINVAL || errnoException.errno == EBADF) {
+                throw new SocketException("Socket closed");
+            }
+            errnoException.rethrowAsSocketException();
+        }
+
+        s.localport = IoBridge.getLocalInetSocketAddress(s.fd).getPort();
+    }
+
+    int socketAvailable() throws IOException {
+        return IoBridge.available(fd);
+    }
+
+    void socketClose0(boolean useDeferredClose) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("socket already closed");
+        }
+
+        FileDescriptor markerFD = null;
+        if (useDeferredClose) {
+            markerFD = getMarkerFD();
+        }
+
+        if (useDeferredClose && markerFD != null) {
+            try {
+                Libcore.os.dup2(markerFD, fd.getInt$());
+                Libcore.os.close(markerFD);
+
+                // This effectively closes the socket, needs to signal threads that blocks on this
+                // file descriptor.
+                AsynchronousCloseMonitor.signalBlockedThreads(fd);
+            } catch (ErrnoException errnoException) {
+                // close should not throw
+            }
+        } else {
+            // If requested or a markerFD cannot be created, a non-deferred close is performed
+            // instead.
+            IoBridge.closeAndSignalBlockedThreads(fd);
+        }
+    }
+
+    /*
+     * Create the marker file descriptor by establishing a loopback connection which we shutdown but
+     * do not close the fd. The result is an fd that can be used for read/write.
+     *
+     * The purpose is to keep hold of the raw fd handle until we are sure it is not used in any
+     * thread. Otherwise if we close the file descriptor directly, the system might reuse the raw fd
+     * number and threads holding old fd value might behave incorrectly.
+     */
+    private FileDescriptor getMarkerFD() throws SocketException {
+        FileDescriptor fd1 = new FileDescriptor();
+        FileDescriptor fd2 = new FileDescriptor();
+        try {
+            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
+
+            // Shutdown fd1, any reads to this fd will get EOF; any writes will get an error.
+            Libcore.os.shutdown(fd1, SHUT_RDWR);
+            Libcore.os.close(fd2);
+        } catch (ErrnoException errnoException) {
+            // We might have reached the maximum file descriptor number and socketpair(2) would
+            // fail. In this case, return null and let caller to fall back to an alternative method
+            // that does not allocate more file descriptors.
+            return null;
+        }
+        return fd1;
+    }
+
+    void socketShutdown(int howto) throws IOException {
+        try {
+            Libcore.os.shutdown(fd, howto);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsIOException();
+        }
+    }
+
+    void socketSetOption0(int cmd, Object value) throws SocketException {
+        // OpenJDK does not set SO_TIMEOUT on Linux.
+        if (cmd == SO_TIMEOUT) {
+            return;
+        }
+
+        IoBridge.setSocketOption(fd, cmd, value);
+    }
+
+    Object socketGetOption(int opt) throws SocketException {
+        return IoBridge.getSocketOption(fd, opt);
+    }
+
+    void socketSendUrgentData(int data) throws IOException {
+        if (fd == null || !fd.valid()) {
+            throw new SocketException("Socket closed");
+        }
+
+        try {
+            byte[] buffer = new byte[] { (byte) data };
+            Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
+        } catch (ErrnoException errnoException) {
+            throw errnoException.rethrowAsSocketException();
+        }
+    }
+    // END Android-changed: Rewrote on top of Libcore.io.
+
+}
diff --git a/java/net/PortUnreachableException.java b/java/net/PortUnreachableException.java
new file mode 100644
index 0000000..3e7558b
--- /dev/null
+++ b/java/net/PortUnreachableException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that an ICMP Port Unreachable message has been
+ * received on a connected datagram.
+ *
+ * @since   1.4
+ */
+
+public class PortUnreachableException extends SocketException {
+    private static final long serialVersionUID = 8462541992376507323L;
+
+    /**
+     * Constructs a new {@code PortUnreachableException} with a
+     * detail message.
+     * @param msg the detail message
+     */
+    public PortUnreachableException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new {@code PortUnreachableException} with no
+     * detailed message.
+     */
+    public PortUnreachableException() {}
+
+    // Android-added: PortUnreachableException ctor used by IoBridge.
+    /** @hide */
+    public PortUnreachableException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/java/net/ProtocolException.java b/java/net/ProtocolException.java
new file mode 100644
index 0000000..5944282
--- /dev/null
+++ b/java/net/ProtocolException.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that there is an error in the underlying
+ * protocol, such as a TCP error.
+ *
+ * @author  Chris Warth
+ * @since   JDK1.0
+ */
+public
+class ProtocolException extends IOException {
+    private static final long serialVersionUID = -6098449442062388080L;
+
+    /**
+     * Constructs a new {@code ProtocolException} with the
+     * specified detail message.
+     *
+     * @param   host   the detail message.
+     */
+    public ProtocolException(String host) {
+        super(host);
+    }
+
+    /**
+     * Constructs a new {@code ProtocolException} with no detail message.
+     */
+    public ProtocolException() {
+    }
+}
diff --git a/java/net/ProtocolFamily.java b/java/net/ProtocolFamily.java
new file mode 100644
index 0000000..5d02326
--- /dev/null
+++ b/java/net/ProtocolFamily.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Represents a family of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public interface ProtocolFamily {
+    /**
+     * Returns the name of the protocol family.
+     *
+     * @return the name of the protocol family
+     */
+    String name();
+}
diff --git a/java/net/Proxy.java b/java/net/Proxy.java
new file mode 100644
index 0000000..8ba020e
--- /dev/null
+++ b/java/net/Proxy.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This class represents a proxy setting, typically a type (http, socks) and
+ * a socket address.
+ * A {@code Proxy} is an immutable object.
+ *
+ * @see     java.net.ProxySelector
+ * @author Yingxian Wang
+ * @author Jean-Christophe Collet
+ * @since   1.5
+ */
+public class Proxy {
+
+    /**
+     * Represents the proxy type.
+     *
+     * @since 1.5
+     */
+    public enum Type {
+        /**
+         * Represents a direct connection, or the absence of a proxy.
+         */
+        DIRECT,
+        /**
+         * Represents proxy for high level protocols such as HTTP or FTP.
+         */
+        HTTP,
+        /**
+         * Represents a SOCKS (V4 or V5) proxy.
+         */
+        SOCKS
+    };
+
+    private Type type;
+    private SocketAddress sa;
+
+    /**
+     * A proxy setting that represents a {@code DIRECT} connection,
+     * basically telling the protocol handler not to use any proxying.
+     * Used, for instance, to create sockets bypassing any other global
+     * proxy settings (like SOCKS):
+     * <P>
+     * {@code Socket s = new Socket(Proxy.NO_PROXY);}
+     *
+     */
+    public final static Proxy NO_PROXY = new Proxy();
+
+    // Creates the proxy that represents a {@code DIRECT} connection.
+    private Proxy() {
+        type = Type.DIRECT;
+        sa = null;
+    }
+
+    /**
+     * Creates an entry representing a PROXY connection.
+     * Certain combinations are illegal. For instance, for types Http, and
+     * Socks, a SocketAddress <b>must</b> be provided.
+     * <P>
+     * Use the {@code Proxy.NO_PROXY} constant
+     * for representing a direct connection.
+     *
+     * @param type the {@code Type} of the proxy
+     * @param sa the {@code SocketAddress} for that proxy
+     * @throws IllegalArgumentException when the type and the address are
+     * incompatible
+     */
+    public Proxy(Type type, SocketAddress sa) {
+        if ((type == Type.DIRECT) || !(sa instanceof InetSocketAddress))
+            throw new IllegalArgumentException("type " + type + " is not compatible with address " + sa);
+        this.type = type;
+        this.sa = sa;
+    }
+
+    /**
+     * Returns the proxy type.
+     *
+     * @return a Type representing the proxy type
+     */
+    public Type type() {
+        return type;
+    }
+
+    /**
+     * Returns the socket address of the proxy, or
+     * {@code null} if its a direct connection.
+     *
+     * @return a {@code SocketAddress} representing the socket end
+     *         point of the proxy
+     */
+    public SocketAddress address() {
+        return sa;
+    }
+
+    /**
+     * Constructs a string representation of this Proxy.
+     * This String is constructed by calling toString() on its type
+     * and concatenating " @ " and the toString() result from its address
+     * if its type is not {@code DIRECT}.
+     *
+     * @return  a string representation of this object.
+     */
+    public String toString() {
+        if (type() == Type.DIRECT)
+            return "DIRECT";
+        return type() + " @ " + address();
+    }
+
+        /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and it represents the same proxy as
+     * this object.
+     * <p>
+     * Two instances of {@code Proxy} represent the same
+     * address if both the SocketAddresses and type are equal.
+     *
+     * @param   obj   the object to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     * @see java.net.InetSocketAddress#equals(java.lang.Object)
+     */
+    public final boolean equals(Object obj) {
+        if (obj == null || !(obj instanceof Proxy))
+            return false;
+        Proxy p = (Proxy) obj;
+        if (p.type() == type()) {
+            if (address() == null) {
+                return (p.address() == null);
+            } else
+                return address().equals(p.address());
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hashcode for this Proxy.
+     *
+     * @return  a hash code value for this Proxy.
+     */
+    public final int hashCode() {
+        if (address() == null)
+            return type().hashCode();
+        return type().hashCode() + address().hashCode();
+    }
+}
diff --git a/java/net/ProxySelector.java b/java/net/ProxySelector.java
new file mode 100644
index 0000000..d6bb536
--- /dev/null
+++ b/java/net/ProxySelector.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.List;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Selects the proxy server to use, if any, when connecting to the
+ * network resource referenced by a URL. A proxy selector is a
+ * concrete sub-class of this class and is registered by invoking the
+ * {@link java.net.ProxySelector#setDefault setDefault} method. The
+ * currently registered proxy selector can be retrieved by calling
+ * {@link java.net.ProxySelector#getDefault getDefault} method.
+ *
+ * <p> When a proxy selector is registered, for instance, a subclass
+ * of URLConnection class should call the {@link #select select}
+ * method for each URL request so that the proxy selector can decide
+ * if a direct, or proxied connection should be used. The {@link
+ * #select select} method returns an iterator over a collection with
+ * the preferred connection approach.
+ *
+ * <p> If a connection cannot be established to a proxy (PROXY or
+ * SOCKS) servers then the caller should call the proxy selector's
+ * {@link #connectFailed connectFailed} method to notify the proxy
+ * selector that the proxy server is unavailable. </p>
+ *
+ * <P>The default proxy selector does enforce a
+ * <a href="doc-files/net-properties.html#Proxies">set of System Properties</a>
+ * related to proxy settings.</P>
+ *
+ * @author Yingxian Wang
+ * @author Jean-Christophe Collet
+ * @since 1.5
+ */
+public abstract class ProxySelector {
+    /**
+     * The system wide proxy selector that selects the proxy server to
+     * use, if any, when connecting to a remote object referenced by
+     * an URL.
+     *
+     * @see #setDefault(ProxySelector)
+     */
+    private static ProxySelector theProxySelector;
+
+    static {
+        try {
+            Class<?> c = Class.forName("sun.net.spi.DefaultProxySelector");
+            if (c != null && ProxySelector.class.isAssignableFrom(c)) {
+                theProxySelector = (ProxySelector) c.newInstance();
+            }
+        } catch (Exception e) {
+            theProxySelector = null;
+        }
+    }
+
+    /**
+     * Gets the system-wide proxy selector.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("getProxySelector")}
+     * @see #setDefault(ProxySelector)
+     * @return the system-wide {@code ProxySelector}
+     * @since 1.5
+     */
+    public static ProxySelector getDefault() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_PROXYSELECTOR_PERMISSION);
+        }
+        return theProxySelector;
+    }
+
+    /**
+     * Sets (or unsets) the system-wide proxy selector.
+     *
+     * Note: non-standard protocol handlers may ignore this setting.
+     *
+     * @param ps The HTTP proxy selector, or
+     *          {@code null} to unset the proxy selector.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("setProxySelector")}
+     *
+     * @see #getDefault()
+     * @since 1.5
+     */
+    public static void setDefault(ProxySelector ps) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.SET_PROXYSELECTOR_PERMISSION);
+        }
+        theProxySelector = ps;
+    }
+
+    /**
+     * Selects all the applicable proxies based on the protocol to
+     * access the resource with and a destination address to access
+     * the resource at.
+     * The format of the URI is defined as follow:
+     * <UL>
+     * <LI>http URI for http connections</LI>
+     * <LI>https URI for https connections
+     * <LI>{@code socket://host:port}<br>
+     *     for tcp client sockets connections</LI>
+     * </UL>
+     *
+     * @param   uri
+     *          The URI that a connection is required to
+     *
+     * @return  a List of Proxies. Each element in the
+     *          the List is of type
+     *          {@link java.net.Proxy Proxy};
+     *          when no proxy is available, the list will
+     *          contain one element of type
+     *          {@link java.net.Proxy Proxy}
+     *          that represents a direct connection.
+     * @throws IllegalArgumentException if the argument is null
+     */
+    public abstract List<Proxy> select(URI uri);
+
+    /**
+     * Called to indicate that a connection could not be established
+     * to a proxy/socks server. An implementation of this method can
+     * temporarily remove the proxies or reorder the sequence of
+     * proxies returned by {@link #select(URI)}, using the address
+     * and the IOException caught when trying to connect.
+     *
+     * @param   uri
+     *          The URI that the proxy at sa failed to serve.
+     * @param   sa
+     *          The socket address of the proxy/SOCKS server
+     *
+     * @param   ioe
+     *          The I/O exception thrown when the connect failed.
+     * @throws IllegalArgumentException if either argument is null
+     */
+    public abstract void connectFailed(URI uri, SocketAddress sa, IOException ioe);
+}
diff --git a/java/net/ResponseCache.java b/java/net/ResponseCache.java
new file mode 100644
index 0000000..2dfaf4a
--- /dev/null
+++ b/java/net/ResponseCache.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.List;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Represents implementations of URLConnection caches. An instance of
+ * such a class can be registered with the system by doing
+ * ResponseCache.setDefault(ResponseCache), and the system will call
+ * this object in order to:
+ *
+ *    <ul><li>store resource data which has been retrieved from an
+ *            external source into the cache</li>
+ *         <li>try to fetch a requested resource that may have been
+ *            stored in the cache</li>
+ *    </ul>
+ *
+ * The ResponseCache implementation decides which resources
+ * should be cached, and for how long they should be cached. If a
+ * request resource cannot be retrieved from the cache, then the
+ * protocol handlers will fetch the resource from its original
+ * location.
+ *
+ * The settings for URLConnection#useCaches controls whether the
+ * protocol is allowed to use a cached response.
+ *
+ * For more information on HTTP caching, see <a
+ * href="http://www.ietf.org/rfc/rfc2616.txt"><i>RFC&nbsp;2616: Hypertext
+ * Transfer Protocol -- HTTP/1.1</i></a>
+ *
+ * @author Yingxian Wang
+ * @since 1.5
+ */
+public abstract class ResponseCache {
+
+    /**
+     * The system wide cache that provides access to a url
+     * caching mechanism.
+     *
+     * @see #setDefault(ResponseCache)
+     * @see #getDefault()
+     */
+    private static ResponseCache theResponseCache;
+
+    /**
+     * Gets the system-wide response cache.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("getResponseCache")}
+     *
+     * @see #setDefault(ResponseCache)
+     * @return the system-wide {@code ResponseCache}
+     * @since 1.5
+     */
+    public synchronized  static ResponseCache getDefault() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.GET_RESPONSECACHE_PERMISSION);
+        }
+        return theResponseCache;
+    }
+
+    /**
+     * Sets (or unsets) the system-wide cache.
+     *
+     * Note: non-standard procotol handlers may ignore this setting.
+     *
+     * @param responseCache The response cache, or
+     *          {@code null} to unset the cache.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     * {@link NetPermission}{@code ("setResponseCache")}
+     *
+     * @see #getDefault()
+     * @since 1.5
+     */
+    public synchronized static void setDefault(ResponseCache responseCache) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(SecurityConstants.SET_RESPONSECACHE_PERMISSION);
+        }
+        theResponseCache = responseCache;
+    }
+
+    /**
+     * Retrieve the cached response based on the requesting uri,
+     * request method and request headers. Typically this method is
+     * called by the protocol handler before it sends out the request
+     * to get the network resource. If a cached response is returned,
+     * that resource is used instead.
+     *
+     * @param uri a {@code URI} used to reference the requested
+     *            network resource
+     * @param rqstMethod a {@code String} representing the request
+     *            method
+     * @param rqstHeaders - a Map from request header
+     *            field names to lists of field values representing
+     *            the current request headers
+     * @return a {@code CacheResponse} instance if available
+     *          from cache, or null otherwise
+     * @throws  IOException if an I/O error occurs
+     * @throws  IllegalArgumentException if any one of the arguments is null
+     *
+     * @see     java.net.URLConnection#setUseCaches(boolean)
+     * @see     java.net.URLConnection#getUseCaches()
+     * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
+     * @see     java.net.URLConnection#getDefaultUseCaches()
+     */
+    public abstract CacheResponse
+        get(URI uri, String rqstMethod, Map<String, List<String>> rqstHeaders)
+        throws IOException;
+
+    /**
+     * The protocol handler calls this method after a resource has
+     * been retrieved, and the ResponseCache must decide whether or
+     * not to store the resource in its cache. If the resource is to
+     * be cached, then put() must return a CacheRequest object which
+     * contains an OutputStream that the protocol handler will
+     * use to write the resource into the cache. If the resource is
+     * not to be cached, then put must return null.
+     *
+     * @param uri a {@code URI} used to reference the requested
+     *            network resource
+     * @param conn - a URLConnection instance that is used to fetch
+     *            the response to be cached
+     * @return a {@code CacheRequest} for recording the
+     *            response to be cached. Null return indicates that
+     *            the caller does not intend to cache the response.
+     * @throws IOException if an I/O error occurs
+     * @throws IllegalArgumentException if any one of the arguments is
+     *            null
+     */
+    public abstract CacheRequest put(URI uri, URLConnection conn)  throws IOException;
+}
diff --git a/java/net/SecureCacheResponse.java b/java/net/SecureCacheResponse.java
new file mode 100644
index 0000000..64fd414
--- /dev/null
+++ b/java/net/SecureCacheResponse.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.security.cert.Certificate;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import java.security.Principal;
+import java.util.List;
+
+/**
+ * Represents a cache response originally retrieved through secure
+ * means, such as TLS.
+ *
+ * @since 1.5
+ */
+public abstract class SecureCacheResponse extends CacheResponse {
+    /**
+     * Returns the cipher suite in use on the original connection that
+     * retrieved the network resource.
+     *
+     * @return a string representing the cipher suite
+     */
+    public abstract String getCipherSuite();
+
+    /**
+     * Returns the certificate chain that were sent to the server during
+     * handshaking of the original connection that retrieved the
+     * network resource.  Note: This method is useful only
+     * when using certificate-based cipher suites.
+     *
+     * @return an immutable List of Certificate representing the
+     *           certificate chain that was sent to the server. If no
+     *           certificate chain was sent, null will be returned.
+     * @see #getLocalPrincipal()
+     */
+    public abstract List<Certificate> getLocalCertificateChain();
+
+    /**
+     * Returns the server's certificate chain, which was established as
+     * part of defining the session in the original connection that
+     * retrieved the network resource, from cache.  Note: This method
+     * can be used only when using certificate-based cipher suites;
+     * using it with non-certificate-based cipher suites, such as
+     * Kerberos, will throw an SSLPeerUnverifiedException.
+     *
+     * @return an immutable List of Certificate representing the server's
+     *         certificate chain.
+     * @throws SSLPeerUnverifiedException if the peer is not verified.
+     * @see #getPeerPrincipal()
+     */
+    public abstract List<Certificate> getServerCertificateChain()
+        throws SSLPeerUnverifiedException;
+
+    /**
+     * Returns the server's principal which was established as part of
+     * defining the session during the original connection that
+     * retrieved the network resource.
+     *
+     * @return the server's principal. Returns an X500Principal of the
+     * end-entity certiticate for X509-based cipher suites, and
+     * KerberosPrincipal for Kerberos cipher suites.
+     *
+     * @throws SSLPeerUnverifiedException if the peer was not verified.
+     *
+     * @see #getServerCertificateChain()
+     * @see #getLocalPrincipal()
+     */
+     public abstract Principal getPeerPrincipal()
+             throws SSLPeerUnverifiedException;
+
+    /**
+      * Returns the principal that was sent to the server during
+      * handshaking in the original connection that retrieved the
+      * network resource.
+      *
+      * @return the principal sent to the server. Returns an X500Principal
+      * of the end-entity certificate for X509-based cipher suites, and
+      * KerberosPrincipal for Kerberos cipher suites. If no principal was
+      * sent, then null is returned.
+      *
+      * @see #getLocalCertificateChain()
+      * @see #getPeerPrincipal()
+      */
+     public abstract Principal getLocalPrincipal();
+}
diff --git a/java/net/ServerSocket.annotated.java b/java/net/ServerSocket.annotated.java
new file mode 100644
index 0000000..1fcd05f
--- /dev/null
+++ b/java/net/ServerSocket.annotated.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.nio.channels.ServerSocketChannel;
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ServerSocket implements java.io.Closeable {
+
+public ServerSocket() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public ServerSocket(int port) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public ServerSocket(int port, int backlog) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public ServerSocket(int port, int backlog, java.net.InetAddress bindAddr) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void bind(java.net.SocketAddress endpoint) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void bind(java.net.SocketAddress endpoint, int backlog) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+public int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getLocalSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.Socket accept() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public SocketImpl getImpl() throws SocketException { throw new RuntimeException("Stub!"); }
+
+protected final void implAccept(java.net.Socket s) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.ServerSocketChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+public boolean isBound() { throw new RuntimeException("Stub!"); }
+
+public boolean isClosed() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSoTimeout(int timeout) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSoTimeout() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setReuseAddress(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getReuseAddress() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setSocketFactory(java.net.SocketImplFactory fac) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReceiveBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getReceiveBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/ServerSocket.java b/java/net/ServerSocket.java
new file mode 100644
index 0000000..444a84d
--- /dev/null
+++ b/java/net/ServerSocket.java
@@ -0,0 +1,932 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.channels.ServerSocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * This class implements server sockets. A server socket waits for
+ * requests to come in over the network. It performs some operation
+ * based on that request, and then possibly returns a result to the requester.
+ * <p>
+ * The actual work of the server socket is performed by an instance
+ * of the {@code SocketImpl} class. An application can
+ * change the socket factory that creates the socket
+ * implementation to configure itself to create sockets
+ * appropriate to the local firewall.
+ *
+ * @author  unascribed
+ * @see     java.net.SocketImpl
+ * @see     java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
+ * @see     java.nio.channels.ServerSocketChannel
+ * @since   JDK1.0
+ */
+public
+class ServerSocket implements java.io.Closeable {
+    /**
+     * Various states of this socket.
+     */
+    private boolean created = false;
+    private boolean bound = false;
+    private boolean closed = false;
+    private Object closeLock = new Object();
+
+    /**
+     * The implementation of this Socket.
+     */
+    private SocketImpl impl;
+
+    /**
+     * Are we using an older SocketImpl?
+     */
+    private boolean oldImpl = false;
+
+    /**
+     * Package-private constructor to create a ServerSocket associated with
+     * the given SocketImpl.
+     */
+    ServerSocket(SocketImpl impl) {
+        this.impl = impl;
+        impl.setServerSocket(this);
+    }
+
+    /**
+     * Creates an unbound server socket.
+     *
+     * @exception IOException IO error when opening the socket.
+     * @revised 1.4
+     */
+    public ServerSocket() throws IOException {
+        setImpl();
+    }
+
+    /**
+     * Creates a server socket, bound to the specified port. A port number
+     * of {@code 0} means that the port number is automatically
+     * allocated, typically from an ephemeral port range. This port
+     * number can then be retrieved by calling {@link #getLocalPort getLocalPort}.
+     * <p>
+     * The maximum queue length for incoming connection indications (a
+     * request to connect) is set to {@code 50}. If a connection
+     * indication arrives when the queue is full, the connection is refused.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager,
+     * its {@code checkListen} method is called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     *
+     * @param      port  the port number, or {@code 0} to use a port
+     *                   number that is automatically allocated.
+     *
+     * @exception  IOException  if an I/O error occurs when opening the socket.
+     * @exception  SecurityException
+     * if a security manager exists and its {@code checkListen}
+     * method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     *
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
+     * @see        SecurityManager#checkListen
+     */
+    public ServerSocket(int port) throws IOException {
+        this(port, 50, null);
+    }
+
+    /**
+     * Creates a server socket and binds it to the specified local port
+     * number, with the specified backlog.
+     * A port number of {@code 0} means that the port number is
+     * automatically allocated, typically from an ephemeral port range.
+     * This port number can then be retrieved by calling
+     * {@link #getLocalPort getLocalPort}.
+     * <p>
+     * The maximum queue length for incoming connection indications (a
+     * request to connect) is set to the {@code backlog} parameter. If
+     * a connection indication arrives when the queue is full, the
+     * connection is refused.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager,
+     * its {@code checkListen} method is called
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogther. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     * <P>
+     *
+     * @param      port     the port number, or {@code 0} to use a port
+     *                      number that is automatically allocated.
+     * @param      backlog  requested maximum length of the queue of incoming
+     *                      connections.
+     *
+     * @exception  IOException  if an I/O error occurs when opening the socket.
+     * @exception  SecurityException
+     * if a security manager exists and its {@code checkListen}
+     * method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     *
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory)
+     * @see        SecurityManager#checkListen
+     */
+    public ServerSocket(int port, int backlog) throws IOException {
+        this(port, backlog, null);
+    }
+
+    /**
+     * Create a server with the specified port, listen backlog, and
+     * local IP address to bind to.  The <i>bindAddr</i> argument
+     * can be used on a multi-homed host for a ServerSocket that
+     * will only accept connect requests to one of its addresses.
+     * If <i>bindAddr</i> is null, it will default accepting
+     * connections on any/all local addresses.
+     * The port must be between 0 and 65535, inclusive.
+     * A port number of {@code 0} means that the port number is
+     * automatically allocated, typically from an ephemeral port range.
+     * This port number can then be retrieved by calling
+     * {@link #getLocalPort getLocalPort}.
+     *
+     * <P>If there is a security manager, this method
+     * calls its {@code checkListen} method
+     * with the {@code port} argument
+     * as its argument to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogther. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     * <P>
+     * @param port  the port number, or {@code 0} to use a port
+     *              number that is automatically allocated.
+     * @param backlog requested maximum length of the queue of incoming
+     *                connections.
+     * @param bindAddr the local InetAddress the server will bind to
+     *
+     * @throws  SecurityException if a security manager exists and
+     * its {@code checkListen} method doesn't allow the operation.
+     *
+     * @throws  IOException if an I/O error occurs when opening the socket.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     *
+     * @see SocketOptions
+     * @see SocketImpl
+     * @see SecurityManager#checkListen
+     * @since   JDK1.1
+     */
+    public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
+        setImpl();
+        if (port < 0 || port > 0xFFFF)
+            throw new IllegalArgumentException(
+                       "Port value out of range: " + port);
+        if (backlog < 1)
+          backlog = 50;
+        try {
+            bind(new InetSocketAddress(bindAddr, port), backlog);
+        } catch(SecurityException e) {
+            close();
+            throw e;
+        } catch(IOException e) {
+            close();
+            throw e;
+        }
+    }
+
+    // Android-changed: Made getImpl() public and @hide, for internal use.
+    /**
+     * Get the {@code SocketImpl} attached to this socket, creating
+     * it if necessary.
+     *
+     * @return  the {@code SocketImpl} attached to that ServerSocket.
+     * @throws SocketException if creation fails.
+     * @since 1.4
+     * @hide
+     */
+    public SocketImpl getImpl() throws SocketException {
+        if (!created)
+            createImpl();
+        return impl;
+    }
+
+    private void checkOldImpl() {
+        if (impl == null)
+            return;
+        // SocketImpl.connect() is a protected method, therefore we need to use
+        // getDeclaredMethod, therefore we need permission to access the member
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                    public Void run() throws NoSuchMethodException {
+                        impl.getClass().getDeclaredMethod("connect",
+                                                          SocketAddress.class,
+                                                          int.class);
+                        return null;
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            oldImpl = true;
+        }
+    }
+
+    private void setImpl() {
+        if (factory != null) {
+            impl = factory.createSocketImpl();
+            checkOldImpl();
+        } else {
+            // No need to do a checkOldImpl() here, we know it's an up to date
+            // SocketImpl!
+            impl = new SocksSocketImpl();
+        }
+        if (impl != null)
+            impl.setServerSocket(this);
+    }
+
+    /**
+     * Creates the socket implementation.
+     *
+     * @throws IOException if creation fails
+     * @since 1.4
+     */
+    void createImpl() throws SocketException {
+        if (impl == null)
+            setImpl();
+        try {
+            impl.create(true);
+            created = true;
+        } catch (IOException e) {
+            throw new SocketException(e.getMessage());
+        }
+    }
+
+    /**
+     *
+     * Binds the {@code ServerSocket} to a specific address
+     * (IP address and port number).
+     * <p>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     * <p>
+     * @param   endpoint        The IP address and port number to bind to.
+     * @throws  IOException if the bind operation fails, or if the socket
+     *                     is already bound.
+     * @throws  SecurityException       if a {@code SecurityManager} is present and
+     * its {@code checkListen} method doesn't allow the operation.
+     * @throws  IllegalArgumentException if endpoint is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    public void bind(SocketAddress endpoint) throws IOException {
+        bind(endpoint, 50);
+    }
+
+    /**
+     *
+     * Binds the {@code ServerSocket} to a specific address
+     * (IP address and port number).
+     * <p>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     * <P>
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogther. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     * @param   endpoint        The IP address and port number to bind to.
+     * @param   backlog         requested maximum length of the queue of
+     *                          incoming connections.
+     * @throws  IOException if the bind operation fails, or if the socket
+     *                     is already bound.
+     * @throws  SecurityException       if a {@code SecurityManager} is present and
+     * its {@code checkListen} method doesn't allow the operation.
+     * @throws  IllegalArgumentException if endpoint is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     */
+    public void bind(SocketAddress endpoint, int backlog) throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!oldImpl && isBound())
+            throw new SocketException("Already bound");
+        if (endpoint == null)
+            endpoint = new InetSocketAddress(0);
+        if (!(endpoint instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) endpoint;
+        if (epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        if (backlog < 1)
+          backlog = 50;
+        try {
+            SecurityManager security = System.getSecurityManager();
+            if (security != null)
+                security.checkListen(epoint.getPort());
+            getImpl().bind(epoint.getAddress(), epoint.getPort());
+            getImpl().listen(backlog);
+            bound = true;
+        } catch(SecurityException e) {
+            bound = false;
+            throw e;
+        } catch(IOException e) {
+            bound = false;
+            throw e;
+        }
+    }
+
+    /**
+     * Returns the local address of this server socket.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the local address
+     * after the socket is closed.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * the {@link InetAddress#getLoopbackAddress loopback} address is returned.
+     *
+     * @return  the address to which this socket is bound,
+     *          or the loopback address if denied by the security manager,
+     *          or {@code null} if the socket is unbound.
+     *
+     * @see SecurityManager#checkConnect
+     */
+    public InetAddress getInetAddress() {
+        if (!isBound())
+            return null;
+        try {
+            InetAddress in = getImpl().getInetAddress();
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkConnect(in.getHostAddress(), -1);
+            return in;
+        } catch (SecurityException e) {
+            return InetAddress.getLoopbackAddress();
+        } catch (SocketException e) {
+            // nothing
+            // If we're bound, the impl has been created
+            // so we shouldn't get here
+        }
+        return null;
+    }
+
+    /**
+     * Returns the port number on which this socket is listening.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the port number
+     * after the socket is closed.
+     *
+     * @return  the port number to which this socket is listening or
+     *          -1 if the socket is not bound yet.
+     */
+    public int getLocalPort() {
+        if (!isBound())
+            return -1;
+        try {
+            return getImpl().getLocalPort();
+        } catch (SocketException e) {
+            // nothing
+            // If we're bound, the impl has been created
+            // so we shouldn't get here
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is bound to.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the address of the endpoint
+     * after the socket is closed.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address and the local
+     * port to which the socket is bound is returned.
+     *
+     * @return a {@code SocketAddress} representing the local endpoint of
+     *         this socket, or a {@code SocketAddress} representing the
+     *         loopback address if denied by the security manager,
+     *         or {@code null} if the socket is not bound yet.
+     *
+     * @see #getInetAddress()
+     * @see #getLocalPort()
+     * @see #bind(SocketAddress)
+     * @see SecurityManager#checkConnect
+     * @since 1.4
+     */
+
+    public SocketAddress getLocalSocketAddress() {
+        if (!isBound())
+            return null;
+        return new InetSocketAddress(getInetAddress(), getLocalPort());
+    }
+
+    /**
+     * Listens for a connection to be made to this socket and accepts
+     * it. The method blocks until a connection is made.
+     *
+     * <p>A new Socket {@code s} is created and, if there
+     * is a security manager,
+     * the security manager's {@code checkAccept} method is called
+     * with {@code s.getInetAddress().getHostAddress()} and
+     * {@code s.getPort()}
+     * as its arguments to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @exception  IOException  if an I/O error occurs when waiting for a
+     *               connection.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkAccept} method doesn't allow the operation.
+     * @exception  SocketTimeoutException if a timeout was previously set with setSoTimeout and
+     *             the timeout has been reached.
+     * @exception  java.nio.channels.IllegalBlockingModeException
+     *             if this socket has an associated channel, the channel is in
+     *             non-blocking mode, and there is no connection ready to be
+     *             accepted
+     *
+     * @return the new Socket
+     * @see SecurityManager#checkAccept
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public Socket accept() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isBound())
+            throw new SocketException("Socket is not bound yet");
+        Socket s = new Socket((SocketImpl) null);
+        implAccept(s);
+        return s;
+    }
+
+    /**
+     * Subclasses of ServerSocket use this method to override accept()
+     * to return their own subclass of socket.  So a FooServerSocket
+     * will typically hand this method an <i>empty</i> FooSocket.  On
+     * return from implAccept the FooSocket will be connected to a client.
+     *
+     * @param s the Socket
+     * @throws java.nio.channels.IllegalBlockingModeException
+     *         if this socket has an associated channel,
+     *         and the channel is in non-blocking mode
+     * @throws IOException if an I/O error occurs when waiting
+     * for a connection.
+     * @since   JDK1.1
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    protected final void implAccept(Socket s) throws IOException {
+        SocketImpl si = null;
+        try {
+            if (s.impl == null)
+              s.setImpl();
+            else {
+                s.impl.reset();
+            }
+            si = s.impl;
+            s.impl = null;
+            si.address = new InetAddress();
+            si.fd = new FileDescriptor();
+            getImpl().accept(si);
+
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkAccept(si.getInetAddress().getHostAddress(),
+                                     si.getPort());
+            }
+        } catch (IOException e) {
+            if (si != null)
+                si.reset();
+            s.impl = si;
+            throw e;
+        } catch (SecurityException e) {
+            if (si != null)
+                si.reset();
+            s.impl = si;
+            throw e;
+        }
+        s.impl = si;
+        s.postAccept();
+    }
+
+    /**
+     * Closes this socket.
+     *
+     * Any thread currently blocked in {@link #accept()} will throw
+     * a {@link SocketException}.
+     *
+     * <p> If this socket has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs when closing the socket.
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public void close() throws IOException {
+        synchronized(closeLock) {
+            if (isClosed())
+                return;
+            if (created)
+                impl.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.ServerSocketChannel} object
+     * associated with this socket, if any.
+     *
+     * <p> A server socket will have a channel if, and only if, the channel
+     * itself was created via the {@link
+     * java.nio.channels.ServerSocketChannel#open ServerSocketChannel.open}
+     * method.
+     *
+     * @return  the server-socket channel associated with this socket,
+     *          or {@code null} if this socket was not created
+     *          for a channel
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public ServerSocketChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Returns the binding state of the ServerSocket.
+     *
+     * @return true if the ServerSocket successfully bound to an address
+     * @since 1.4
+     */
+    public boolean isBound() {
+        // Before 1.3 ServerSockets were always bound during creation
+        return bound || oldImpl;
+    }
+
+    /**
+     * Returns the closed state of the ServerSocket.
+     *
+     * @return true if the socket has been closed
+     * @since 1.4
+     */
+    public boolean isClosed() {
+        synchronized(closeLock) {
+            return closed;
+        }
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} with the
+     * specified timeout, in milliseconds.  With this option set to a non-zero
+     * timeout, a call to accept() for this ServerSocket
+     * will block for only this amount of time.  If the timeout expires,
+     * a <B>java.net.SocketTimeoutException</B> is raised, though the
+     * ServerSocket is still valid.  The option <B>must</B> be enabled
+     * prior to entering the blocking operation to have effect.  The
+     * timeout must be {@code > 0}.
+     * A timeout of zero is interpreted as an infinite timeout.
+     * @param timeout the specified timeout, in milliseconds
+     * @exception SocketException if there is an error in
+     * the underlying protocol, such as a TCP error.
+     * @since   JDK1.1
+     * @see #getSoTimeout()
+     */
+    public synchronized void setSoTimeout(int timeout) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    }
+
+    /**
+     * Retrieve setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
+     * 0 returns implies that the option is disabled (i.e., timeout of infinity).
+     * @return the {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} value
+     * @exception IOException if an I/O error occurs
+     * @since   JDK1.1
+     * @see #setSoTimeout(int)
+     */
+    public synchronized int getSoTimeout() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+        /* extra type safety */
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     * socket option.
+     * <p>
+     * When a TCP connection is closed the connection may remain
+     * in a timeout state for a period of time after the connection
+     * is closed (typically known as the {@code TIME_WAIT} state
+     * or {@code 2MSL} wait state).
+     * For applications using a well known socket address or port
+     * it may not be possible to bind a socket to the required
+     * {@code SocketAddress} if there is a connection in the
+     * timeout state involving the socket address or port.
+     * <p>
+     * Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} prior to
+     * binding the socket using {@link #bind(SocketAddress)} allows the socket
+     * to be bound even though a previous connection is in a timeout state.
+     * <p>
+     * When a {@code ServerSocket} is created the initial setting
+     * of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is not defined.
+     * Applications can use {@link #getReuseAddress()} to determine the initial
+     * setting of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}.
+     * <p>
+     * The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is
+     * enabled or disabled after a socket is bound (See {@link #isBound()})
+     * is not defined.
+     *
+     * @param on  whether to enable or disable the socket option
+     * @exception SocketException if an error occurs enabling or
+     *            disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     *            socket option, or the socket is closed.
+     * @since 1.4
+     * @see #getReuseAddress()
+     * @see #bind(SocketAddress)
+     * @see #isBound()
+     * @see #isClosed()
+     */
+    public void setReuseAddress(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.4
+     * @see #setReuseAddress(boolean)
+     */
+    public boolean getReuseAddress() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
+    }
+
+    /**
+     * Returns the implementation address and implementation port of
+     * this socket as a {@code String}.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * an {@code InetAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address is returned as
+     * the implementation address.
+     *
+     * @return  a string representation of this socket.
+     */
+    public String toString() {
+        if (!isBound())
+            return "ServerSocket[unbound]";
+        InetAddress in;
+        if (System.getSecurityManager() != null)
+            in = InetAddress.getLoopbackAddress();
+        else
+            in = impl.getInetAddress();
+        return "ServerSocket[addr=" + in +
+                ",localport=" + impl.getLocalPort()  + "]";
+    }
+
+    void setBound() {
+        bound = true;
+    }
+
+    void setCreated() {
+        created = true;
+    }
+
+    /**
+     * The factory for all server sockets.
+     */
+    private static SocketImplFactory factory = null;
+
+    /**
+     * Sets the server socket implementation factory for the
+     * application. The factory can be specified only once.
+     * <p>
+     * When an application creates a new server socket, the socket
+     * implementation factory's {@code createSocketImpl} method is
+     * called to create the actual socket implementation.
+     * <p>
+     * Passing {@code null} to the method is a no-op unless the factory
+     * was already set.
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  IOException  if an I/O error occurs when setting the
+     *               socket factory.
+     * @exception  SocketException  if the factory has already been defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static synchronized void setSocketFactory(SocketImplFactory fac) throws IOException {
+        if (factory != null) {
+            throw new SocketException("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    /**
+     * Sets a default proposed value for the
+     * {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option for sockets
+     * accepted from this {@code ServerSocket}. The value actually set
+     * in the accepted socket must be determined by calling
+     * {@link Socket#getReceiveBufferSize()} after the socket
+     * is returned by {@link #accept()}.
+     * <p>
+     * The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is used both to
+     * set the size of the internal socket receive buffer, and to set the size
+     * of the TCP receive window that is advertized to the remote peer.
+     * <p>
+     * It is possible to change the value subsequently, by calling
+     * {@link Socket#setReceiveBufferSize(int)}. However, if the application
+     * wishes to allow a receive window larger than 64K bytes, as defined by RFC1323
+     * then the proposed value must be set in the ServerSocket <B>before</B>
+     * it is bound to a local address. This implies, that the ServerSocket must be
+     * created with the no-argument constructor, then setReceiveBufferSize() must
+     * be called and lastly the ServerSocket is bound to an address by calling bind().
+     * <p>
+     * Failure to do this will not cause an error, and the buffer size may be set to the
+     * requested value but the TCP receive window in sockets accepted from
+     * this ServerSocket will be no larger than 64K bytes.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @param size the size to which to set the receive buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception IllegalArgumentException if the
+     * value is 0 or is negative.
+     *
+     * @since 1.4
+     * @see #getReceiveBufferSize
+     */
+     public synchronized void setReceiveBufferSize (int size) throws SocketException {
+        if (!(size > 0)) {
+            throw new IllegalArgumentException("negative receive size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+    }
+
+    /**
+     * Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option
+     * for this {@code ServerSocket}, that is the proposed buffer size that
+     * will be used for Sockets accepted from this {@code ServerSocket}.
+     *
+     * <p>Note, the value actually set in the accepted socket is determined by
+     * calling {@link Socket#getReceiveBufferSize()}.
+     * @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF}
+     *         option for this {@code Socket}.
+     * @exception SocketException if there is an error
+     *            in the underlying protocol, such as a TCP error.
+     * @see #setReceiveBufferSize(int)
+     * @since 1.4
+     */
+    public synchronized int getReceiveBufferSize()
+    throws SocketException{
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Sets performance preferences for this ServerSocket.
+     *
+     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
+     * may offer alternative protocols which have different performance
+     * characteristics than TCP/IP.  This method allows the application to
+     * express its own preferences as to how these tradeoffs should be made
+     * when the implementation chooses from the available protocols.
+     *
+     * <p> Performance preferences are described by three integers
+     * whose values indicate the relative importance of short connection time,
+     * low latency, and high bandwidth.  The absolute values of the integers
+     * are irrelevant; in order to choose a protocol the values are simply
+     * compared, with larger values indicating stronger preferences.  If the
+     * application prefers short connection time over both low latency and high
+     * bandwidth, for example, then it could invoke this method with the values
+     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
+     * latency, and low latency above short connection time, then it could
+     * invoke this method with the values {@code (0, 1, 2)}.
+     *
+     * <p> Invoking this method after this socket has been bound
+     * will have no effect. This implies that in order to use this capability
+     * requires the socket to be created with the no-argument constructor.
+     *
+     * @param  connectionTime
+     *         An {@code int} expressing the relative importance of a short
+     *         connection time
+     *
+     * @param  latency
+     *         An {@code int} expressing the relative importance of low
+     *         latency
+     *
+     * @param  bandwidth
+     *         An {@code int} expressing the relative importance of high
+     *         bandwidth
+     *
+     * @since 1.5
+     */
+    public void setPerformancePreferences(int connectionTime,
+                                          int latency,
+                                          int bandwidth)
+    {
+        /* Not implemented yet */
+    }
+
+    // Android-added: getFileDescriptor$(), for testing / internal use.
+    /**
+     * @hide internal use only
+     */
+    public FileDescriptor getFileDescriptor$() {
+        return impl.getFileDescriptor();
+    }
+}
diff --git a/java/net/Socket.annotated.java b/java/net/Socket.annotated.java
new file mode 100644
index 0000000..e021788
--- /dev/null
+++ b/java/net/Socket.annotated.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.nio.channels.SocketChannel;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Socket implements java.io.Closeable {
+
+public Socket() { throw new RuntimeException("Stub!"); }
+
+public Socket(java.net.Proxy proxy) { throw new RuntimeException("Stub!"); }
+
+protected Socket(java.net.SocketImpl impl) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.lang.String host, int port) throws java.io.IOException, java.net.UnknownHostException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.net.InetAddress address, int port) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.lang.String host, int port, java.net.InetAddress localAddr, int localPort) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public Socket(java.net.InetAddress address, int port, java.net.InetAddress localAddr, int localPort) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public Socket(java.lang.String host, int port, boolean stream) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public Socket(java.net.InetAddress host, int port, boolean stream) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.SocketAddress endpoint) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void connect(java.net.SocketAddress endpoint, int timeout) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void bind(java.net.SocketAddress bindpoint) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.InetAddress getLocalAddress() { throw new RuntimeException("Stub!"); }
+
+public int getPort() { throw new RuntimeException("Stub!"); }
+
+public int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getRemoteSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.net.SocketAddress getLocalSocketAddress() { throw new RuntimeException("Stub!"); }
+
+public java.nio.channels.SocketChannel getChannel() { throw new RuntimeException("Stub!"); }
+
+public java.io.InputStream getInputStream() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.io.OutputStream getOutputStream() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setTcpNoDelay(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getTcpNoDelay() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setSoLinger(boolean on, int linger) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public int getSoLinger() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void sendUrgentData(int data) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setOOBInline(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getOOBInline() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSoTimeout(int timeout) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSoTimeout() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSendBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getSendBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void setReceiveBufferSize(int size) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized int getReceiveBufferSize() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setKeepAlive(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getKeepAlive() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setTrafficClass(int tc) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public int getTrafficClass() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public void setReuseAddress(boolean on) throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public boolean getReuseAddress() throws java.net.SocketException { throw new RuntimeException("Stub!"); }
+
+public synchronized void close() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void shutdownInput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void shutdownOutput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public boolean isConnected() { throw new RuntimeException("Stub!"); }
+
+public boolean isBound() { throw new RuntimeException("Stub!"); }
+
+public boolean isClosed() { throw new RuntimeException("Stub!"); }
+
+public boolean isInputShutdown() { throw new RuntimeException("Stub!"); }
+
+public boolean isOutputShutdown() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setSocketImplFactory(java.net.SocketImplFactory fac) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected]
+public java.io.FileDescriptor getFileDescriptor$() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/net/Socket.java b/java/net/Socket.java
new file mode 100644
index 0000000..bae1d1c
--- /dev/null
+++ b/java/net/Socket.java
@@ -0,0 +1,1783 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.channels.SocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedAction;
+
+/**
+ * This class implements client sockets (also called just
+ * "sockets"). A socket is an endpoint for communication
+ * between two machines.
+ * <p>
+ * The actual work of the socket is performed by an instance of the
+ * {@code SocketImpl} class. An application, by changing
+ * the socket factory that creates the socket implementation,
+ * can configure itself to create sockets appropriate to the local
+ * firewall.
+ *
+ * @author  unascribed
+ * @see     java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+ * @see     java.net.SocketImpl
+ * @see     java.nio.channels.SocketChannel
+ * @since   JDK1.0
+ */
+public
+class Socket implements java.io.Closeable {
+    /**
+     * Various states of this socket.
+     */
+    private boolean created = false;
+    private boolean bound = false;
+    private boolean connected = false;
+    private boolean closed = false;
+    private Object closeLock = new Object();
+    private boolean shutIn = false;
+    private boolean shutOut = false;
+
+    /**
+     * The implementation of this Socket.
+     */
+    SocketImpl impl;
+
+    /**
+     * Are we using an older SocketImpl?
+     */
+    private boolean oldImpl = false;
+
+    /**
+     * Creates an unconnected socket, with the
+     * system-default type of SocketImpl.
+     *
+     * @since   JDK1.1
+     * @revised 1.4
+     */
+    public Socket() {
+        setImpl();
+    }
+
+    /**
+     * Creates an unconnected socket, specifying the type of proxy, if any,
+     * that should be used regardless of any other settings.
+     * <P>
+     * If there is a security manager, its {@code checkConnect} method
+     * is called with the proxy host address and port number
+     * as its arguments. This could result in a SecurityException.
+     * <P>
+     * Examples:
+     * <UL> <LI>{@code Socket s = new Socket(Proxy.NO_PROXY);} will create
+     * a plain socket ignoring any other proxy configuration.</LI>
+     * <LI>{@code Socket s = new Socket(new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("socks.mydom.com", 1080)));}
+     * will create a socket connecting through the specified SOCKS proxy
+     * server.</LI>
+     * </UL>
+     *
+     * @param proxy a {@link java.net.Proxy Proxy} object specifying what kind
+     *              of proxying should be used.
+     * @throws IllegalArgumentException if the proxy is of an invalid type
+     *          or {@code null}.
+     * @throws SecurityException if a security manager is present and
+     *                           permission to connect to the proxy is
+     *                           denied.
+     * @see java.net.ProxySelector
+     * @see java.net.Proxy
+     *
+     * @since   1.5
+     */
+    public Socket(Proxy proxy) {
+        // Create a copy of Proxy as a security measure
+        if (proxy == null) {
+            throw new IllegalArgumentException("Invalid Proxy");
+        }
+        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY
+                                          : sun.net.ApplicationProxy.create(proxy);
+        Proxy.Type type = p.type();
+        // Android-changed: Removed HTTP proxy support.
+        // if (type == Proxy.Type.SOCKS || type == Proxy.Type.HTTP) {
+        if (type == Proxy.Type.SOCKS) {
+            SecurityManager security = System.getSecurityManager();
+            InetSocketAddress epoint = (InetSocketAddress) p.address();
+            if (epoint.getAddress() != null) {
+                checkAddress (epoint.getAddress(), "Socket");
+            }
+            if (security != null) {
+                if (epoint.isUnresolved())
+                    epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort());
+                if (epoint.isUnresolved())
+                    security.checkConnect(epoint.getHostName(), epoint.getPort());
+                else
+                    security.checkConnect(epoint.getAddress().getHostAddress(),
+                                  epoint.getPort());
+            }
+            // Android-changed: Removed HTTP proxy support.
+            // impl = type == Proxy.Type.SOCKS ? new SocksSocketImpl(p)
+            //                                : new HttpConnectSocketImpl(p);
+            impl = new SocksSocketImpl(p);
+            impl.setSocket(this);
+        } else {
+            if (p == Proxy.NO_PROXY) {
+                if (factory == null) {
+                    impl = new PlainSocketImpl();
+                    impl.setSocket(this);
+                } else
+                    setImpl();
+            } else
+                throw new IllegalArgumentException("Invalid Proxy");
+        }
+    }
+
+    /**
+     * Creates an unconnected Socket with a user-specified
+     * SocketImpl.
+     * <P>
+     * @param impl an instance of a <B>SocketImpl</B>
+     * the subclass wishes to use on the Socket.
+     *
+     * @exception SocketException if there is an error in the underlying protocol,
+     * such as a TCP error.
+     * @since   JDK1.1
+     */
+    protected Socket(SocketImpl impl) throws SocketException {
+        this.impl = impl;
+        if (impl != null) {
+            checkOldImpl();
+            this.impl.setSocket(this);
+        }
+    }
+
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number on the named host.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param      host   the host name, or {@code null} for the loopback address.
+     * @param      port   the port number.
+     *
+     * @exception  UnknownHostException if the IP address of
+     * the host could not be determined.
+     *
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     */
+    public Socket(String host, int port)
+        throws UnknownHostException, IOException
+    {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(InetAddress.getAllByName(host), port, (SocketAddress) null, true);
+    }
+
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number at the specified IP address.
+     * <p>
+     * If the application has specified a socket factory, that factory's
+     * {@code createSocketImpl} method is called to create the
+     * actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param      address   the IP address.
+     * @param      port      the port number.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @exception  NullPointerException if {@code address} is null.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     */
+    public Socket(InetAddress address, int port) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(nonNullAddress(address), port, (SocketAddress) null, true);
+    }
+
+    /**
+     * Creates a socket and connects it to the specified remote host on
+     * the specified remote port. The Socket will also bind() to the local
+     * address and port supplied.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * A local port number of {@code zero} will let the system pick up a
+     * free port in the {@code bind} operation.</p>
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param host the name of the remote host, or {@code null} for the loopback address.
+     * @param port the remote port
+     * @param localAddr the local address the socket is bound to, or
+     *        {@code null} for the {@code anyLocal} address.
+     * @param localPort the local port the socket is bound to, or
+     *        {@code zero} for a system selected free port.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the connection
+     *             to the destination, or if its {@code checkListen} method
+     *             doesn't allow the bind to the local port.
+     * @exception  IllegalArgumentException if the port parameter or localPort
+     *             parameter is outside the specified range of valid port values,
+     *             which is between 0 and 65535, inclusive.
+     * @see        SecurityManager#checkConnect
+     * @since   JDK1.1
+     */
+    public Socket(String host, int port, InetAddress localAddr,
+                  int localPort) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(InetAddress.getAllByName(host), port,
+             new InetSocketAddress(localAddr, localPort), true);
+    }
+
+    /**
+     * Creates a socket and connects it to the specified remote address on
+     * the specified remote port. The Socket will also bind() to the local
+     * address and port supplied.
+     * <p>
+     * If the specified local address is {@code null} it is the equivalent of
+     * specifying the address as the AnyLocal address
+     * (see {@link java.net.InetAddress#isAnyLocalAddress InetAddress.isAnyLocalAddress}{@code ()}).
+     * <p>
+     * A local port number of {@code zero} will let the system pick up a
+     * free port in the {@code bind} operation.</p>
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     *
+     * @param address the remote address
+     * @param port the remote port
+     * @param localAddr the local address the socket is bound to, or
+     *        {@code null} for the {@code anyLocal} address.
+     * @param localPort the local port the socket is bound to or
+     *        {@code zero} for a system selected free port.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the connection
+     *             to the destination, or if its {@code checkListen} method
+     *             doesn't allow the bind to the local port.
+     * @exception  IllegalArgumentException if the port parameter or localPort
+     *             parameter is outside the specified range of valid port values,
+     *             which is between 0 and 65535, inclusive.
+     * @exception  NullPointerException if {@code address} is null.
+     * @see        SecurityManager#checkConnect
+     * @since   JDK1.1
+     */
+    public Socket(InetAddress address, int port, InetAddress localAddr,
+                  int localPort) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(nonNullAddress(address), port,
+             new InetSocketAddress(localAddr, localPort), true);
+    }
+
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number on the named host.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * If the stream argument is {@code true}, this creates a
+     * stream socket. If the stream argument is {@code false}, it
+     * creates a datagram socket.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     * <p>
+     * If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with the host address and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     * <p>
+     * If a UDP socket is used, TCP/IP related socket options will not apply.
+     *
+     * @param      host     the host name, or {@code null} for the loopback address.
+     * @param      port     the port number.
+     * @param      stream   a {@code boolean} indicating whether this is
+     *                      a stream socket or a datagram socket.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     * @deprecated Use DatagramSocket instead for UDP transport.
+     */
+    @Deprecated
+    public Socket(String host, int port, boolean stream) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(InetAddress.getAllByName(host), port, (SocketAddress) null, stream);
+    }
+
+    /**
+     * Creates a socket and connects it to the specified port number at
+     * the specified IP address.
+     * <p>
+     * If the stream argument is {@code true}, this creates a
+     * stream socket. If the stream argument is {@code false}, it
+     * creates a datagram socket.
+     * <p>
+     * If the application has specified a server socket factory, that
+     * factory's {@code createSocketImpl} method is called to create
+     * the actual socket implementation. Otherwise a "plain" socket is created.
+     *
+     * <p>If there is a security manager, its
+     * {@code checkConnect} method is called
+     * with {@code host.getHostAddress()} and {@code port}
+     * as its arguments. This could result in a SecurityException.
+     * <p>
+     * If UDP socket is used, TCP/IP related socket options will not apply.
+     *
+     * @param      host     the IP address.
+     * @param      port      the port number.
+     * @param      stream    if {@code true}, create a stream socket;
+     *                       otherwise, create a datagram socket.
+     * @exception  IOException  if an I/O error occurs when creating the socket.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkConnect} method doesn't allow the operation.
+     * @exception  IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     * @exception  NullPointerException if {@code host} is null.
+     * @see        java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
+     * @see        java.net.SocketImpl
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkConnect
+     * @deprecated Use DatagramSocket instead for UDP transport.
+     */
+    @Deprecated
+    public Socket(InetAddress host, int port, boolean stream) throws IOException {
+        // Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+        this(nonNullAddress(host), port, new InetSocketAddress(0), stream);
+    }
+
+    // BEGIN Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+    private static InetAddress[] nonNullAddress(InetAddress address) {
+        // backward compatibility
+        if (address == null)
+            throw new NullPointerException();
+
+        return new InetAddress[] { address };
+    }
+
+    private Socket(InetAddress[] addresses, int port, SocketAddress localAddr,
+            boolean stream) throws IOException {
+        if (addresses == null || addresses.length == 0) {
+            throw new SocketException("Impossible: empty address list");
+        }
+
+        for (int i = 0; i < addresses.length; i++) {
+            setImpl();
+            try {
+                InetSocketAddress address = new InetSocketAddress(addresses[i], port);
+                createImpl(stream);
+                if (localAddr != null) {
+                    bind(localAddr);
+                }
+                connect(address);
+                break;
+            } catch (IOException | IllegalArgumentException | SecurityException e) {
+                try {
+                    // Android-changed: Let ctor call impl.close() instead of overridable close().
+                    // Subclasses may not expect a call to close() coming from this constructor.
+                    impl.close();
+                    closed = true;
+                } catch (IOException ce) {
+                    e.addSuppressed(ce);
+                }
+
+                // Only stop on the last address.
+                if (i == addresses.length - 1) {
+                    throw e;
+                }
+            }
+
+            // Discard the connection state and try again.
+            impl = null;
+            created = false;
+            bound = false;
+            closed = false;
+        }
+    }
+    // END Android-changed: App compat. Socket ctor should try all addresses. http://b/30007735
+
+    /**
+     * Creates the socket implementation.
+     *
+     * @param stream a {@code boolean} value : {@code true} for a TCP socket,
+     *               {@code false} for UDP.
+     * @throws IOException if creation fails
+     * @since 1.4
+     */
+     void createImpl(boolean stream) throws SocketException {
+        if (impl == null)
+            setImpl();
+        try {
+            impl.create(stream);
+            created = true;
+        } catch (IOException e) {
+            throw new SocketException(e.getMessage());
+        }
+    }
+
+    private void checkOldImpl() {
+        if (impl == null)
+            return;
+        // SocketImpl.connect() is a protected method, therefore we need to use
+        // getDeclaredMethod, therefore we need permission to access the member
+
+        oldImpl = AccessController.doPrivileged
+                                (new PrivilegedAction<Boolean>() {
+            public Boolean run() {
+                Class<?> clazz = impl.getClass();
+                while (true) {
+                    try {
+                        clazz.getDeclaredMethod("connect", SocketAddress.class, int.class);
+                        return Boolean.FALSE;
+                    } catch (NoSuchMethodException e) {
+                        clazz = clazz.getSuperclass();
+                        // java.net.SocketImpl class will always have this abstract method.
+                        // If we have not found it by now in the hierarchy then it does not
+                        // exist, we are an old style impl.
+                        if (clazz.equals(java.net.SocketImpl.class)) {
+                            return Boolean.TRUE;
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Sets impl to the system-default type of SocketImpl.
+     * @since 1.4
+     */
+    void setImpl() {
+        if (factory != null) {
+            impl = factory.createSocketImpl();
+            checkOldImpl();
+        } else {
+            // No need to do a checkOldImpl() here, we know it's an up to date
+            // SocketImpl!
+            impl = new SocksSocketImpl();
+        }
+        if (impl != null)
+            impl.setSocket(this);
+    }
+
+
+    /**
+     * Get the {@code SocketImpl} attached to this socket, creating
+     * it if necessary.
+     *
+     * @return  the {@code SocketImpl} attached to that ServerSocket.
+     * @throws SocketException if creation fails
+     * @since 1.4
+     */
+    SocketImpl getImpl() throws SocketException {
+        if (!created)
+            createImpl(true);
+        return impl;
+    }
+
+    /**
+     * Connects this socket to the server.
+     *
+     * @param   endpoint the {@code SocketAddress}
+     * @throws  IOException if an error occurs during the connection
+     * @throws  java.nio.channels.IllegalBlockingModeException
+     *          if this socket has an associated channel,
+     *          and the channel is in non-blocking mode
+     * @throws  IllegalArgumentException if endpoint is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public void connect(SocketAddress endpoint) throws IOException {
+        connect(endpoint, 0);
+    }
+
+    /**
+     * Connects this socket to the server with a specified timeout value.
+     * A timeout of zero is interpreted as an infinite timeout. The connection
+     * will then block until established or an error occurs.
+     *
+     * @param   endpoint the {@code SocketAddress}
+     * @param   timeout  the timeout value to be used in milliseconds.
+     * @throws  IOException if an error occurs during the connection
+     * @throws  SocketTimeoutException if timeout expires before connecting
+     * @throws  java.nio.channels.IllegalBlockingModeException
+     *          if this socket has an associated channel,
+     *          and the channel is in non-blocking mode
+     * @throws  IllegalArgumentException if endpoint is null or is a
+     *          SocketAddress subclass not supported by this socket
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public void connect(SocketAddress endpoint, int timeout) throws IOException {
+        if (endpoint == null)
+            throw new IllegalArgumentException("connect: The address can't be null");
+
+        if (timeout < 0)
+          throw new IllegalArgumentException("connect: timeout can't be negative");
+
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+
+        if (!oldImpl && isConnected())
+            throw new SocketException("already connected");
+
+        if (!(endpoint instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+
+        InetSocketAddress epoint = (InetSocketAddress) endpoint;
+        InetAddress addr = epoint.getAddress ();
+        int port = epoint.getPort();
+        checkAddress(addr, "connect");
+
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            if (epoint.isUnresolved())
+                security.checkConnect(epoint.getHostName(), port);
+            else
+                security.checkConnect(addr.getHostAddress(), port);
+        }
+        if (!created)
+            createImpl(true);
+        if (!oldImpl)
+            impl.connect(epoint, timeout);
+        else if (timeout == 0) {
+            if (epoint.isUnresolved())
+                impl.connect(addr.getHostName(), port);
+            else
+                impl.connect(addr, port);
+        } else
+            throw new UnsupportedOperationException("SocketImpl.connect(addr, timeout)");
+        connected = true;
+        /*
+         * If the socket was not bound before the connect, it is now because
+         * the kernel will have picked an ephemeral port & a local address
+         */
+        bound = true;
+    }
+
+    /**
+     * Binds the socket to a local address.
+     * <P>
+     * If the address is {@code null}, then the system will pick up
+     * an ephemeral port and a valid local address to bind the socket.
+     *
+     * @param   bindpoint the {@code SocketAddress} to bind to
+     * @throws  IOException if the bind operation fails, or if the socket
+     *                     is already bound.
+     * @throws  IllegalArgumentException if bindpoint is a
+     *          SocketAddress subclass not supported by this socket
+     * @throws  SecurityException  if a security manager exists and its
+     *          {@code checkListen} method doesn't allow the bind
+     *          to the local port.
+     *
+     * @since   1.4
+     * @see #isBound
+     */
+    public void bind(SocketAddress bindpoint) throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!oldImpl && isBound())
+            throw new SocketException("Already bound");
+
+        if (bindpoint != null && (!(bindpoint instanceof InetSocketAddress)))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) bindpoint;
+        if (epoint != null && epoint.isUnresolved())
+            throw new SocketException("Unresolved address");
+        if (epoint == null) {
+            epoint = new InetSocketAddress(0);
+        }
+        InetAddress addr = epoint.getAddress();
+        int port = epoint.getPort();
+        checkAddress (addr, "bind");
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkListen(port);
+        }
+        getImpl().bind (addr, port);
+        bound = true;
+    }
+
+    private void checkAddress (InetAddress addr, String op) {
+        if (addr == null) {
+            return;
+        }
+        if (!(addr instanceof Inet4Address || addr instanceof Inet6Address)) {
+            throw new IllegalArgumentException(op + ": invalid address type");
+        }
+    }
+
+    /**
+     * set the flags after an accept() call.
+     */
+    final void postAccept() {
+        connected = true;
+        created = true;
+        bound = true;
+    }
+
+    void setCreated() {
+        created = true;
+    }
+
+    void setBound() {
+        bound = true;
+    }
+
+    void setConnected() {
+        connected = true;
+    }
+
+    /**
+     * Returns the address to which the socket is connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+     * @return  the remote IP address to which this socket is connected,
+     *          or {@code null} if the socket is not connected.
+     */
+    public InetAddress getInetAddress() {
+        if (!isConnected())
+            return null;
+        try {
+            return getImpl().getInetAddress();
+        } catch (SocketException e) {
+        }
+        return null;
+    }
+
+    /**
+     * Gets the local address to which the socket is bound.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * the {@link InetAddress#getLoopbackAddress loopback} address is returned.
+     *
+     * @return the local address to which the socket is bound,
+     *         the loopback address if denied by the security manager, or
+     *         the wildcard address if the socket is closed or not bound yet.
+     * @since   JDK1.1
+     *
+     * @see SecurityManager#checkConnect
+     */
+    public InetAddress getLocalAddress() {
+        // This is for backward compatibility
+        if (!isBound())
+            return InetAddress.anyLocalAddress();
+        InetAddress in = null;
+        try {
+            in = (InetAddress) getImpl().getOption(SocketOptions.SO_BINDADDR);
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkConnect(in.getHostAddress(), -1);
+            if (in.isAnyLocalAddress()) {
+                in = InetAddress.anyLocalAddress();
+            }
+        } catch (SecurityException e) {
+            in = InetAddress.getLoopbackAddress();
+        } catch (Exception e) {
+            in = InetAddress.anyLocalAddress(); // "0.0.0.0"
+        }
+        return in;
+    }
+
+    /**
+     * Returns the remote port number to which this socket is connected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected port number
+     * after the socket is closed.
+     *
+     * @return  the remote port number to which this socket is connected, or
+     *          0 if the socket is not connected yet.
+     */
+    public int getPort() {
+        if (!isConnected())
+            return 0;
+        try {
+            return getImpl().getPort();
+        } catch (SocketException e) {
+            // Shouldn't happen as we're connected
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the local port number to which this socket is bound.
+     * <p>
+     * If the socket was bound prior to being {@link #close closed},
+     * then this method will continue to return the local port number
+     * after the socket is closed.
+     *
+     * @return  the local port number to which this socket is bound or -1
+     *          if the socket is not bound yet.
+     */
+    public int getLocalPort() {
+        if (!isBound())
+            return -1;
+        try {
+            return getImpl().getLocalPort();
+        } catch(SocketException e) {
+            // shouldn't happen as we're bound
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is connected to, or
+     * {@code null} if it is unconnected.
+     * <p>
+     * If the socket was connected prior to being {@link #close closed},
+     * then this method will continue to return the connected address
+     * after the socket is closed.
+     *
+
+     * @return a {@code SocketAddress} representing the remote endpoint of this
+     *         socket, or {@code null} if it is not connected yet.
+     * @see #getInetAddress()
+     * @see #getPort()
+     * @see #connect(SocketAddress, int)
+     * @see #connect(SocketAddress)
+     * @since 1.4
+     */
+    public SocketAddress getRemoteSocketAddress() {
+        if (!isConnected())
+            return null;
+        return new InetSocketAddress(getInetAddress(), getPort());
+    }
+
+    /**
+     * Returns the address of the endpoint this socket is bound to.
+     * <p>
+     * If a socket bound to an endpoint represented by an
+     * {@code InetSocketAddress } is {@link #close closed},
+     * then this method will continue to return an {@code InetSocketAddress}
+     * after the socket is closed. In that case the returned
+     * {@code InetSocketAddress}'s address is the
+     * {@link InetAddress#isAnyLocalAddress wildcard} address
+     * and its port is the local port that it was bound to.
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link InetAddress#getLoopbackAddress loopback} address and the local
+     * port to which this socket is bound is returned.
+     *
+     * @return a {@code SocketAddress} representing the local endpoint of
+     *         this socket, or a {@code SocketAddress} representing the
+     *         loopback address if denied by the security manager, or
+     *         {@code null} if the socket is not bound yet.
+     *
+     * @see #getLocalAddress()
+     * @see #getLocalPort()
+     * @see #bind(SocketAddress)
+     * @see SecurityManager#checkConnect
+     * @since 1.4
+     */
+
+    public SocketAddress getLocalSocketAddress() {
+        if (!isBound())
+            return null;
+        return new InetSocketAddress(getLocalAddress(), getLocalPort());
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.SocketChannel SocketChannel}
+     * object associated with this socket, if any.
+     *
+     * <p> A socket will have a channel if, and only if, the channel itself was
+     * created via the {@link java.nio.channels.SocketChannel#open
+     * SocketChannel.open} or {@link
+     * java.nio.channels.ServerSocketChannel#accept ServerSocketChannel.accept}
+     * methods.
+     *
+     * @return  the socket channel associated with this socket,
+     *          or {@code null} if this socket was not created
+     *          for a channel
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public SocketChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Returns an input stream for this socket.
+     *
+     * <p> If this socket has an associated channel then the resulting input
+     * stream delegates all of its operations to the channel.  If the channel
+     * is in non-blocking mode then the input stream's {@code read} operations
+     * will throw an {@link java.nio.channels.IllegalBlockingModeException}.
+     *
+     * <p>Under abnormal conditions the underlying connection may be
+     * broken by the remote host or the network software (for example
+     * a connection reset in the case of TCP connections). When a
+     * broken connection is detected by the network software the
+     * following applies to the returned input stream :-
+     *
+     * <ul>
+     *
+     *   <li><p>The network software may discard bytes that are buffered
+     *   by the socket. Bytes that aren't discarded by the network
+     *   software can be read using {@link java.io.InputStream#read read}.
+     *
+     *   <li><p>If there are no bytes buffered on the socket, or all
+     *   buffered bytes have been consumed by
+     *   {@link java.io.InputStream#read read}, then all subsequent
+     *   calls to {@link java.io.InputStream#read read} will throw an
+     *   {@link java.io.IOException IOException}.
+     *
+     *   <li><p>If there are no bytes buffered on the socket, and the
+     *   socket has not been closed using {@link #close close}, then
+     *   {@link java.io.InputStream#available available} will
+     *   return {@code 0}.
+     *
+     * </ul>
+     *
+     * <p> Closing the returned {@link java.io.InputStream InputStream}
+     * will close the associated socket.
+     *
+     * @return     an input stream for reading bytes from this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *             input stream, the socket is closed, the socket is
+     *             not connected, or the socket input has been shutdown
+     *             using {@link #shutdownInput()}
+     *
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public InputStream getInputStream() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isInputShutdown())
+            throw new SocketException("Socket input is shutdown");
+        final Socket s = this;
+        InputStream is = null;
+        try {
+            is = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<InputStream>() {
+                    public InputStream run() throws IOException {
+                        return impl.getInputStream();
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            throw (IOException) e.getException();
+        }
+        return is;
+    }
+
+    /**
+     * Returns an output stream for this socket.
+     *
+     * <p> If this socket has an associated channel then the resulting output
+     * stream delegates all of its operations to the channel.  If the channel
+     * is in non-blocking mode then the output stream's {@code write}
+     * operations will throw an {@link
+     * java.nio.channels.IllegalBlockingModeException}.
+     *
+     * <p> Closing the returned {@link java.io.OutputStream OutputStream}
+     * will close the associated socket.
+     *
+     * @return     an output stream for writing bytes to this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *               output stream or if the socket is not connected.
+     * @revised 1.4
+     * @spec JSR-51
+     */
+    public OutputStream getOutputStream() throws IOException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isOutputShutdown())
+            throw new SocketException("Socket output is shutdown");
+        final Socket s = this;
+        OutputStream os = null;
+        try {
+            os = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<OutputStream>() {
+                    public OutputStream run() throws IOException {
+                        return impl.getOutputStream();
+                    }
+                });
+        } catch (java.security.PrivilegedActionException e) {
+            throw (IOException) e.getException();
+        }
+        return os;
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#TCP_NODELAY TCP_NODELAY}
+     * (disable/enable Nagle's algorithm).
+     *
+     * @param on {@code true} to enable TCP_NODELAY,
+     * {@code false} to disable.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @since   JDK1.1
+     *
+     * @see #getTcpNoDelay()
+     */
+    public void setTcpNoDelay(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   JDK1.1
+     * @see #setTcpNoDelay(boolean)
+     */
+    public boolean getTcpNoDelay() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) getImpl().getOption(SocketOptions.TCP_NODELAY)).booleanValue();
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_LINGER SO_LINGER} with the
+     * specified linger time in seconds. The maximum timeout value is platform
+     * specific.
+     *
+     * The setting only affects socket close.
+     *
+     * @param on     whether or not to linger on.
+     * @param linger how long to linger for, if on is true.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @exception IllegalArgumentException if the linger value is negative.
+     * @since JDK1.1
+     * @see #getSoLinger()
+     */
+    public void setSoLinger(boolean on, int linger) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!on) {
+            getImpl().setOption(SocketOptions.SO_LINGER, new Boolean(on));
+        } else {
+            if (linger < 0) {
+                throw new IllegalArgumentException("invalid value for SO_LINGER");
+            }
+            if (linger > 65535)
+                linger = 65535;
+            getImpl().setOption(SocketOptions.SO_LINGER, new Integer(linger));
+        }
+    }
+
+    /**
+     * Returns setting for {@link SocketOptions#SO_LINGER SO_LINGER}.
+     * -1 returns implies that the
+     * option is disabled.
+     *
+     * The setting only affects socket close.
+     *
+     * @return the setting for {@link SocketOptions#SO_LINGER SO_LINGER}.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   JDK1.1
+     * @see #setSoLinger(boolean, int)
+     */
+    public int getSoLinger() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_LINGER);
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Send one byte of urgent data on the socket. The byte to be sent is the lowest eight
+     * bits of the data parameter. The urgent byte is
+     * sent after any preceding writes to the socket OutputStream
+     * and before any future writes to the OutputStream.
+     * @param data The byte of data to send
+     * @exception IOException if there is an error
+     *  sending the data.
+     * @since 1.4
+     */
+    public void sendUrgentData (int data) throws IOException  {
+        // Android-changed: If the socket is closed, sendUrgentData should not create a new impl.
+        // Fail early to avoid leaking resources.
+        // http://b/31818400
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        if (!getImpl().supportsUrgentData ()) {
+            throw new SocketException ("Urgent data not supported");
+        }
+        getImpl().sendUrgentData (data);
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}
+     * (receipt of TCP urgent data)
+     *
+     * By default, this option is disabled and TCP urgent data received on a
+     * socket is silently discarded. If the user wishes to receive urgent data, then
+     * this option must be enabled. When enabled, urgent data is received
+     * inline with normal data.
+     * <p>
+     * Note, only limited support is provided for handling incoming urgent
+     * data. In particular, no notification of incoming urgent data is provided
+     * and there is no capability to distinguish between normal data and urgent
+     * data unless provided by a higher level protocol.
+     *
+     * @param on {@code true} to enable
+     *           {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE},
+     *           {@code false} to disable.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @since   1.4
+     *
+     * @see #getOOBInline()
+     */
+    public void setOOBInline(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_OOBINLINE, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}is enabled.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.4
+     * @see #setOOBInline(boolean)
+     */
+    public boolean getOOBInline() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) getImpl().getOption(SocketOptions.SO_OOBINLINE)).booleanValue();
+    }
+
+    /**
+     *  Enable/disable {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
+     *  with the specified timeout, in milliseconds. With this option set
+     *  to a non-zero timeout, a read() call on the InputStream associated with
+     *  this Socket will block for only this amount of time.  If the timeout
+     *  expires, a <B>java.net.SocketTimeoutException</B> is raised, though the
+     *  Socket is still valid. The option <B>must</B> be enabled
+     *  prior to entering the blocking operation to have effect. The
+     *  timeout must be {@code > 0}.
+     *  A timeout of zero is interpreted as an infinite timeout.
+     *
+     * @param timeout the specified timeout, in milliseconds.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   JDK 1.1
+     * @see #getSoTimeout()
+     */
+    public synchronized void setSoTimeout(int timeout) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (timeout < 0)
+          throw new IllegalArgumentException("timeout can't be negative");
+
+        getImpl().setOption(SocketOptions.SO_TIMEOUT, new Integer(timeout));
+    }
+
+    /**
+     * Returns setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}.
+     * 0 returns implies that the option is disabled (i.e., timeout of infinity).
+     *
+     * @return the setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @since   JDK1.1
+     * @see #setSoTimeout(int)
+     */
+    public synchronized int getSoTimeout() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        Object o = getImpl().getOption(SocketOptions.SO_TIMEOUT);
+        /* extra type safety */
+        if (o instanceof Integer) {
+            return ((Integer) o).intValue();
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Sets the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option to the
+     * specified value for this {@code Socket}.
+     * The {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option is used by the
+     * platform's networking code as a hint for the size to set the underlying
+     * network I/O buffers.
+     *
+     * <p>Because {@link SocketOptions#SO_SNDBUF SO_SNDBUF} is a hint,
+     * applications that want to verify what size the buffers were set to
+     * should call {@link #getSendBufferSize()}.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @param size the size to which to set the send buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception IllegalArgumentException if the
+     * value is 0 or is negative.
+     *
+     * @see #getSendBufferSize()
+     * @since 1.2
+     */
+    public synchronized void setSendBufferSize(int size)
+    throws SocketException{
+        if (!(size > 0)) {
+            throw new IllegalArgumentException("negative send size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_SNDBUF, new Integer(size));
+    }
+
+    /**
+     * Get value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option
+     * for this {@code Socket}, that is the buffer size used by the platform
+     * for output on this {@code Socket}.
+     * @return the value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF}
+     *         option for this {@code Socket}.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @see #setSendBufferSize(int)
+     * @since 1.2
+     */
+    public synchronized int getSendBufferSize() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_SNDBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Sets the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option to the
+     * specified value for this {@code Socket}. The
+     * {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option is
+     * used by the platform's networking code as a hint for the size to set
+     * the underlying network I/O buffers.
+     *
+     * <p>Increasing the receive buffer size can increase the performance of
+     * network I/O for high-volume connection, while decreasing it can
+     * help reduce the backlog of incoming data.
+     *
+     * <p>Because {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is a hint,
+     * applications that want to verify what size the buffers were set to
+     * should call {@link #getReceiveBufferSize()}.
+     *
+     * <p>The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is also used
+     * to set the TCP receive window that is advertized to the remote peer.
+     * Generally, the window size can be modified at any time when a socket is
+     * connected. However, if a receive window larger than 64K is required then
+     * this must be requested <B>before</B> the socket is connected to the
+     * remote peer. There are two cases to be aware of:
+     * <ol>
+     * <li>For sockets accepted from a ServerSocket, this must be done by calling
+     * {@link ServerSocket#setReceiveBufferSize(int)} before the ServerSocket
+     * is bound to a local address.<p></li>
+     * <li>For client sockets, setReceiveBufferSize() must be called before
+     * connecting the socket to its remote peer.</li></ol>
+     * @param size the size to which to set the receive buffer
+     * size. This value must be greater than 0.
+     *
+     * @exception IllegalArgumentException if the value is 0 or is
+     * negative.
+     *
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     *
+     * @see #getReceiveBufferSize()
+     * @see ServerSocket#setReceiveBufferSize(int)
+     * @since 1.2
+     */
+    public synchronized void setReceiveBufferSize(int size)
+    throws SocketException{
+        if (size <= 0) {
+            throw new IllegalArgumentException("invalid receive size");
+        }
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_RCVBUF, new Integer(size));
+    }
+
+    /**
+     * Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option
+     * for this {@code Socket}, that is the buffer size used by the platform
+     * for input on this {@code Socket}.
+     *
+     * @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF}
+     *         option for this {@code Socket}.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @see #setReceiveBufferSize(int)
+     * @since 1.2
+     */
+    public synchronized int getReceiveBufferSize()
+    throws SocketException{
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        int result = 0;
+        Object o = getImpl().getOption(SocketOptions.SO_RCVBUF);
+        if (o instanceof Integer) {
+            result = ((Integer)o).intValue();
+        }
+        return result;
+    }
+
+    /**
+     * Enable/disable {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE}.
+     *
+     * @param on  whether or not to have socket keep alive turned on.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since 1.3
+     * @see #getKeepAlive()
+     */
+    public void setKeepAlive(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_KEEPALIVE, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.3
+     * @see #setKeepAlive(boolean)
+     */
+    public boolean getKeepAlive() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) getImpl().getOption(SocketOptions.SO_KEEPALIVE)).booleanValue();
+    }
+
+    /**
+     * Sets traffic class or type-of-service octet in the IP
+     * header for packets sent from this Socket.
+     * As the underlying network implementation may ignore this
+     * value applications should consider it a hint.
+     *
+     * <P> The tc <B>must</B> be in the range {@code 0 <= tc <=
+     * 255} or an IllegalArgumentException will be thrown.
+     * <p>Notes:
+     * <p>For Internet Protocol v4 the value consists of an
+     * {@code integer}, the least significant 8 bits of which
+     * represent the value of the TOS octet in IP packets sent by
+     * the socket.
+     * RFC 1349 defines the TOS values as follows:
+     *
+     * <UL>
+     * <LI><CODE>IPTOS_LOWCOST (0x02)</CODE></LI>
+     * <LI><CODE>IPTOS_RELIABILITY (0x04)</CODE></LI>
+     * <LI><CODE>IPTOS_THROUGHPUT (0x08)</CODE></LI>
+     * <LI><CODE>IPTOS_LOWDELAY (0x10)</CODE></LI>
+     * </UL>
+     * The last low order bit is always ignored as this
+     * corresponds to the MBZ (must be zero) bit.
+     * <p>
+     * Setting bits in the precedence field may result in a
+     * SocketException indicating that the operation is not
+     * permitted.
+     * <p>
+     * As RFC 1122 section 4.2.4.2 indicates, a compliant TCP
+     * implementation should, but is not required to, let application
+     * change the TOS field during the lifetime of a connection.
+     * So whether the type-of-service field can be changed after the
+     * TCP connection has been established depends on the implementation
+     * in the underlying platform. Applications should not assume that
+     * they can change the TOS field after the connection.
+     * <p>
+     * For Internet Protocol v6 {@code tc} is the value that
+     * would be placed into the sin6_flowinfo field of the IP header.
+     *
+     * @param tc        an {@code int} value for the bitset.
+     * @throws SocketException if there is an error setting the
+     * traffic class or type-of-service
+     * @since 1.4
+     * @see #getTrafficClass
+     * @see SocketOptions#IP_TOS
+     */
+    public void setTrafficClass(int tc) throws SocketException {
+        if (tc < 0 || tc > 255)
+            throw new IllegalArgumentException("tc is not in range 0 -- 255");
+
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        try {
+            getImpl().setOption(SocketOptions.IP_TOS, tc);
+        } catch (SocketException se) {
+            // not supported if socket already connected
+            // Solaris returns error in such cases
+            if(!isConnected())
+                throw se;
+        }
+    }
+
+    /**
+     * Gets traffic class or type-of-service in the IP header
+     * for packets sent from this Socket
+     * <p>
+     * As the underlying network implementation may ignore the
+     * traffic class or type-of-service set using {@link #setTrafficClass(int)}
+     * this method may return a different value than was previously
+     * set using the {@link #setTrafficClass(int)} method on this Socket.
+     *
+     * @return the traffic class or type-of-service already set
+     * @throws SocketException if there is an error obtaining the
+     * traffic class or type-of-service value.
+     * @since 1.4
+     * @see #setTrafficClass(int)
+     * @see SocketOptions#IP_TOS
+     */
+    public int getTrafficClass() throws SocketException {
+        // Android-changed: throw SocketException if the socket is already closed. http://b/31818400
+        if (isClosed()) {
+            throw new SocketException("Socket is closed");
+        }
+
+        return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue();
+    }
+
+    /**
+     * Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     * socket option.
+     * <p>
+     * When a TCP connection is closed the connection may remain
+     * in a timeout state for a period of time after the connection
+     * is closed (typically known as the {@code TIME_WAIT} state
+     * or {@code 2MSL} wait state).
+     * For applications using a well known socket address or port
+     * it may not be possible to bind a socket to the required
+     * {@code SocketAddress} if there is a connection in the
+     * timeout state involving the socket address or port.
+     * <p>
+     * Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     * prior to binding the socket using {@link #bind(SocketAddress)} allows
+     * the socket to be bound even though a previous connection is in a timeout
+     * state.
+     * <p>
+     * When a {@code Socket} is created the initial setting
+     * of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is disabled.
+     * <p>
+     * The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is
+     * enabled or disabled after a socket is bound (See {@link #isBound()})
+     * is not defined.
+     *
+     * @param on  whether to enable or disable the socket option
+     * @exception SocketException if an error occurs enabling or
+     *            disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}
+     *            socket option, or the socket is closed.
+     * @since 1.4
+     * @see #getReuseAddress()
+     * @see #bind(SocketAddress)
+     * @see #isClosed()
+     * @see #isBound()
+     */
+    public void setReuseAddress(boolean on) throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        getImpl().setOption(SocketOptions.SO_REUSEADDR, Boolean.valueOf(on));
+    }
+
+    /**
+     * Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     *
+     * @return a {@code boolean} indicating whether or not
+     *         {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled.
+     * @exception SocketException if there is an error
+     * in the underlying protocol, such as a TCP error.
+     * @since   1.4
+     * @see #setReuseAddress(boolean)
+     */
+    public boolean getReuseAddress() throws SocketException {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        return ((Boolean) (getImpl().getOption(SocketOptions.SO_REUSEADDR))).booleanValue();
+    }
+
+    /**
+     * Closes this socket.
+     * <p>
+     * Any thread currently blocked in an I/O operation upon this socket
+     * will throw a {@link SocketException}.
+     * <p>
+     * Once a socket has been closed, it is not available for further networking
+     * use (i.e. can't be reconnected or rebound). A new socket needs to be
+     * created.
+     *
+     * <p> Closing this socket will also close the socket's
+     * {@link java.io.InputStream InputStream} and
+     * {@link java.io.OutputStream OutputStream}.
+     *
+     * <p> If this socket has an associated channel then the channel is closed
+     * as well.
+     *
+     * @exception  IOException  if an I/O error occurs when closing this socket.
+     * @revised 1.4
+     * @spec JSR-51
+     * @see #isClosed
+     */
+    public synchronized void close() throws IOException {
+        synchronized(closeLock) {
+            if (isClosed())
+                return;
+            if (created)
+                impl.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Places the input stream for this socket at "end of stream".
+     * Any data sent to the input stream side of the socket is acknowledged
+     * and then silently discarded.
+     * <p>
+     * If you read from a socket input stream after invoking this method on the
+     * socket, the stream's {@code available} method will return 0, and its
+     * {@code read} methods will return {@code -1} (end of stream).
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     *
+     * @since 1.3
+     * @see java.net.Socket#shutdownOutput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @see #isInputShutdown
+     */
+    public void shutdownInput() throws IOException
+    {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isInputShutdown())
+            throw new SocketException("Socket input is already shutdown");
+        getImpl().shutdownInput();
+        shutIn = true;
+    }
+
+    /**
+     * Disables the output stream for this socket.
+     * For a TCP socket, any previously written data will be sent
+     * followed by TCP's normal connection termination sequence.
+     *
+     * If you write to a socket output stream after invoking
+     * shutdownOutput() on the socket, the stream will throw
+     * an IOException.
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     *
+     * @since 1.3
+     * @see java.net.Socket#shutdownInput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @see #isOutputShutdown
+     */
+    public void shutdownOutput() throws IOException
+    {
+        if (isClosed())
+            throw new SocketException("Socket is closed");
+        if (!isConnected())
+            throw new SocketException("Socket is not connected");
+        if (isOutputShutdown())
+            throw new SocketException("Socket output is already shutdown");
+        getImpl().shutdownOutput();
+        shutOut = true;
+    }
+
+    /**
+     * Converts this socket to a {@code String}.
+     *
+     * @return  a string representation of this socket.
+     */
+    public String toString() {
+        try {
+            // Android-changed: change localport to localPort, and addr to address.
+            if (isConnected())
+                return "Socket[address=" + getImpl().getInetAddress() +
+                    ",port=" + getImpl().getPort() +
+                    ",localPort=" + getImpl().getLocalPort() + "]";
+        } catch (SocketException e) {
+        }
+        return "Socket[unconnected]";
+    }
+
+    /**
+     * Returns the connection state of the socket.
+     * <p>
+     * Note: Closing a socket doesn't clear its connection state, which means
+     * this method will return {@code true} for a closed socket
+     * (see {@link #isClosed()}) if it was successfuly connected prior
+     * to being closed.
+     *
+     * @return true if the socket was successfuly connected to a server
+     * @since 1.4
+     */
+    public boolean isConnected() {
+        // Before 1.3 Sockets were always connected during creation
+        return connected || oldImpl;
+    }
+
+    /**
+     * Returns the binding state of the socket.
+     * <p>
+     * Note: Closing a socket doesn't clear its binding state, which means
+     * this method will return {@code true} for a closed socket
+     * (see {@link #isClosed()}) if it was successfuly bound prior
+     * to being closed.
+     *
+     * @return true if the socket was successfuly bound to an address
+     * @since 1.4
+     * @see #bind
+     */
+    public boolean isBound() {
+        // Before 1.3 Sockets were always bound during creation
+        return bound || oldImpl;
+    }
+
+    /**
+     * Returns the closed state of the socket.
+     *
+     * @return true if the socket has been closed
+     * @since 1.4
+     * @see #close
+     */
+    public boolean isClosed() {
+        synchronized(closeLock) {
+            return closed;
+        }
+    }
+
+    /**
+     * Returns whether the read-half of the socket connection is closed.
+     *
+     * @return true if the input of the socket has been shutdown
+     * @since 1.4
+     * @see #shutdownInput
+     */
+    public boolean isInputShutdown() {
+        return shutIn;
+    }
+
+    /**
+     * Returns whether the write-half of the socket connection is closed.
+     *
+     * @return true if the output of the socket has been shutdown
+     * @since 1.4
+     * @see #shutdownOutput
+     */
+    public boolean isOutputShutdown() {
+        return shutOut;
+    }
+
+    /**
+     * The factory for all client sockets.
+     */
+    private static SocketImplFactory factory = null;
+
+    /**
+     * Sets the client socket implementation factory for the
+     * application. The factory can be specified only once.
+     * <p>
+     * When an application creates a new client socket, the socket
+     * implementation factory's {@code createSocketImpl} method is
+     * called to create the actual socket implementation.
+     * <p>
+     * Passing {@code null} to the method is a no-op unless the factory
+     * was already set.
+     * <p>If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  IOException  if an I/O error occurs when setting the
+     *               socket factory.
+     * @exception  SocketException  if the factory is already defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        java.net.SocketImplFactory#createSocketImpl()
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static synchronized void setSocketImplFactory(SocketImplFactory fac)
+        throws IOException
+    {
+        if (factory != null) {
+            throw new SocketException("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    /**
+     * Sets performance preferences for this socket.
+     *
+     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
+     * may offer alternative protocols which have different performance
+     * characteristics than TCP/IP.  This method allows the application to
+     * express its own preferences as to how these tradeoffs should be made
+     * when the implementation chooses from the available protocols.
+     *
+     * <p> Performance preferences are described by three integers
+     * whose values indicate the relative importance of short connection time,
+     * low latency, and high bandwidth.  The absolute values of the integers
+     * are irrelevant; in order to choose a protocol the values are simply
+     * compared, with larger values indicating stronger preferences. Negative
+     * values represent a lower priority than positive values. If the
+     * application prefers short connection time over both low latency and high
+     * bandwidth, for example, then it could invoke this method with the values
+     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
+     * latency, and low latency above short connection time, then it could
+     * invoke this method with the values {@code (0, 1, 2)}.
+     *
+     * <p> Invoking this method after this socket has been connected
+     * will have no effect.
+     *
+     * @param  connectionTime
+     *         An {@code int} expressing the relative importance of a short
+     *         connection time
+     *
+     * @param  latency
+     *         An {@code int} expressing the relative importance of low
+     *         latency
+     *
+     * @param  bandwidth
+     *         An {@code int} expressing the relative importance of high
+     *         bandwidth
+     *
+     * @since 1.5
+     */
+    public void setPerformancePreferences(int connectionTime,
+                                          int latency,
+                                          int bandwidth)
+    {
+        /* Not implemented yet */
+    }
+
+    // Android-added: getFileDescriptor$() method for testing and internal use.
+    /**
+     * @hide internal use only
+     */
+    public FileDescriptor getFileDescriptor$() {
+        return impl.getFileDescriptor();
+    }
+}
diff --git a/java/net/SocketAddress.java b/java/net/SocketAddress.java
new file mode 100644
index 0000000..cfb014b
--- /dev/null
+++ b/java/net/SocketAddress.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+
+/**
+ *
+ * This class represents a Socket Address with no protocol attachment.
+ * As an abstract class, it is meant to be subclassed with a specific,
+ * protocol dependent, implementation.
+ * <p>
+ * It provides an immutable object used by sockets for binding, connecting, or
+ * as returned values.
+ *
+ * @see java.net.Socket
+ * @see java.net.ServerSocket
+ * @since 1.4
+ */
+public abstract class SocketAddress implements java.io.Serializable {
+
+    static final long serialVersionUID = 5215720748342549866L;
+
+}
diff --git a/java/net/SocketException.java b/java/net/SocketException.java
new file mode 100644
index 0000000..64ae771
--- /dev/null
+++ b/java/net/SocketException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that there is an error creating or accessing a Socket.
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class SocketException extends IOException {
+    private static final long serialVersionUID = -5935874303556886934L;
+
+    /**
+     * Constructs a new {@code SocketException} with the
+     * specified detail message.
+     *
+     * @param msg the detail message.
+     */
+    public SocketException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new {@code SocketException} with no detail message.
+     */
+    public SocketException() {
+    }
+
+    // BEGIN Android-added: SocketException ctor with cause for internal use.
+    /** @hide */
+    public SocketException(Throwable cause) {
+        super(cause);
+    }
+
+    /** @hide */
+    public SocketException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+    // END Android-added: SocketException ctor with cause for internal use.
+}
diff --git a/java/net/SocketImpl.annotated.java b/java/net/SocketImpl.annotated.java
new file mode 100644
index 0000000..2146d2f
--- /dev/null
+++ b/java/net/SocketImpl.annotated.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.net;
+
+import java.io.IOException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class SocketImpl implements java.net.SocketOptions {
+
+public SocketImpl() { throw new RuntimeException("Stub!"); }
+
+protected abstract void create(boolean stream) throws java.io.IOException;
+
+protected abstract void connect(java.lang.String host, int port) throws java.io.IOException;
+
+protected abstract void connect(java.net.InetAddress address, int port) throws java.io.IOException;
+
+protected abstract void connect(java.net.SocketAddress address, int timeout) throws java.io.IOException;
+
+protected abstract void bind(java.net.InetAddress host, int port) throws java.io.IOException;
+
+protected abstract void listen(int backlog) throws java.io.IOException;
+
+protected abstract void accept(java.net.SocketImpl s) throws java.io.IOException;
+
+protected abstract java.io.InputStream getInputStream() throws java.io.IOException;
+
+protected abstract java.io.OutputStream getOutputStream() throws java.io.IOException;
+
+protected abstract int available() throws java.io.IOException;
+
+protected abstract void close() throws java.io.IOException;
+
+protected void shutdownInput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+protected void shutdownOutput() throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+protected java.io.FileDescriptor getFileDescriptor() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.io.FileDescriptor getFD$() { throw new RuntimeException("Stub!"); }
+
+protected java.net.InetAddress getInetAddress() { throw new RuntimeException("Stub!"); }
+
+protected int getPort() { throw new RuntimeException("Stub!"); }
+
+protected boolean supportsUrgentData() { throw new RuntimeException("Stub!"); }
+
+protected abstract void sendUrgentData(int data) throws java.io.IOException;
+
+protected int getLocalPort() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+protected void setPerformancePreferences(int connectionTime, int latency, int bandwidth) { throw new RuntimeException("Stub!"); }
+
+protected java.net.InetAddress address;
+
+protected java.io.FileDescriptor fd;
+
+protected int localport;
+
+protected int port;
+}
+
diff --git a/java/net/SocketImpl.java b/java/net/SocketImpl.java
new file mode 100644
index 0000000..ade2630
--- /dev/null
+++ b/java/net/SocketImpl.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileDescriptor;
+
+/**
+ * The abstract class {@code SocketImpl} is a common superclass
+ * of all classes that actually implement sockets. It is used to
+ * create both client and server sockets.
+ * <p>
+ * A "plain" socket implements these methods exactly as
+ * described, without attempting to go through a firewall or proxy.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public abstract class SocketImpl implements SocketOptions {
+    /**
+     * The actual Socket object.
+     */
+    Socket socket = null;
+    ServerSocket serverSocket = null;
+
+    /**
+     * The file descriptor object for this socket.
+     */
+    protected FileDescriptor fd;
+
+    /**
+     * The IP address of the remote end of this socket.
+     */
+    protected InetAddress address;
+
+    /**
+     * The port number on the remote host to which this socket is connected.
+     */
+    protected int port;
+
+    /**
+     * The local port number to which this socket is connected.
+     */
+    protected int localport;
+
+    /**
+     * Creates either a stream or a datagram socket.
+     *
+     * @param      stream   if {@code true}, create a stream socket;
+     *                      otherwise, create a datagram socket.
+     * @exception  IOException  if an I/O error occurs while creating the
+     *               socket.
+     */
+    protected abstract void create(boolean stream) throws IOException;
+
+    /**
+     * Connects this socket to the specified port on the named host.
+     *
+     * @param      host   the name of the remote host.
+     * @param      port   the port number.
+     * @exception  IOException  if an I/O error occurs when connecting to the
+     *               remote host.
+     */
+    protected abstract void connect(String host, int port) throws IOException;
+
+    /**
+     * Connects this socket to the specified port number on the specified host.
+     *
+     * @param      address   the IP address of the remote host.
+     * @param      port      the port number.
+     * @exception  IOException  if an I/O error occurs when attempting a
+     *               connection.
+     */
+    protected abstract void connect(InetAddress address, int port) throws IOException;
+
+    /**
+     * Connects this socket to the specified port number on the specified host.
+     * A timeout of zero is interpreted as an infinite timeout. The connection
+     * will then block until established or an error occurs.
+     *
+     * @param      address   the Socket address of the remote host.
+     * @param     timeout  the timeout value, in milliseconds, or zero for no timeout.
+     * @exception  IOException  if an I/O error occurs when attempting a
+     *               connection.
+     * @since 1.4
+     */
+    protected abstract void connect(SocketAddress address, int timeout) throws IOException;
+
+    /**
+     * Binds this socket to the specified local IP address and port number.
+     *
+     * @param      host   an IP address that belongs to a local interface.
+     * @param      port   the port number.
+     * @exception  IOException  if an I/O error occurs when binding this socket.
+     */
+    protected abstract void bind(InetAddress host, int port) throws IOException;
+
+    /**
+     * Sets the maximum queue length for incoming connection indications
+     * (a request to connect) to the {@code count} argument. If a
+     * connection indication arrives when the queue is full, the
+     * connection is refused.
+     *
+     * @param      backlog   the maximum length of the queue.
+     * @exception  IOException  if an I/O error occurs when creating the queue.
+     */
+    protected abstract void listen(int backlog) throws IOException;
+
+    /**
+     * Accepts a connection.
+     *
+     * @param      s   the accepted connection.
+     * @exception  IOException  if an I/O error occurs when accepting the
+     *               connection.
+     */
+    protected abstract void accept(SocketImpl s) throws IOException;
+
+    /**
+     * Returns an input stream for this socket.
+     *
+     * @return     a stream for reading from this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *               input stream.
+    */
+    protected abstract InputStream getInputStream() throws IOException;
+
+    /**
+     * Returns an output stream for this socket.
+     *
+     * @return     an output stream for writing to this socket.
+     * @exception  IOException  if an I/O error occurs when creating the
+     *               output stream.
+     */
+    protected abstract OutputStream getOutputStream() throws IOException;
+
+    /**
+     * Returns the number of bytes that can be read from this socket
+     * without blocking.
+     *
+     * @return     the number of bytes that can be read from this socket
+     *             without blocking.
+     * @exception  IOException  if an I/O error occurs when determining the
+     *               number of bytes available.
+     */
+    protected abstract int available() throws IOException;
+
+    /**
+     * Closes this socket.
+     *
+     * @exception  IOException  if an I/O error occurs when closing this socket.
+     */
+    protected abstract void close() throws IOException;
+
+    /**
+     * Places the input stream for this socket at "end of stream".
+     * Any data sent to this socket is acknowledged and then
+     * silently discarded.
+     *
+     * If you read from a socket input stream after invoking this method on the
+     * socket, the stream's {@code available} method will return 0, and its
+     * {@code read} methods will return {@code -1} (end of stream).
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     * @see java.net.Socket#shutdownOutput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @since 1.3
+     */
+    protected void shutdownInput() throws IOException {
+      throw new IOException("Method not implemented!");
+    }
+
+    /**
+     * Disables the output stream for this socket.
+     * For a TCP socket, any previously written data will be sent
+     * followed by TCP's normal connection termination sequence.
+     *
+     * If you write to a socket output stream after invoking
+     * shutdownOutput() on the socket, the stream will throw
+     * an IOException.
+     *
+     * @exception IOException if an I/O error occurs when shutting down this
+     * socket.
+     * @see java.net.Socket#shutdownInput()
+     * @see java.net.Socket#close()
+     * @see java.net.Socket#setSoLinger(boolean, int)
+     * @since 1.3
+     */
+    protected void shutdownOutput() throws IOException {
+      throw new IOException("Method not implemented!");
+    }
+
+    /**
+     * Returns the value of this socket's {@code fd} field.
+     *
+     * @return  the value of this socket's {@code fd} field.
+     * @see     java.net.SocketImpl#fd
+     */
+    protected FileDescriptor getFileDescriptor() {
+        return fd;
+    }
+
+    // Android-added: getFD$() for testing.
+    /**
+     * @hide used by java.nio tests
+     */
+    public FileDescriptor getFD$() {
+        return fd;
+    }
+
+    /**
+     * Returns the value of this socket's {@code address} field.
+     *
+     * @return  the value of this socket's {@code address} field.
+     * @see     java.net.SocketImpl#address
+     */
+    protected InetAddress getInetAddress() {
+        return address;
+    }
+
+    /**
+     * Returns the value of this socket's {@code port} field.
+     *
+     * @return  the value of this socket's {@code port} field.
+     * @see     java.net.SocketImpl#port
+     */
+    protected int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns whether or not this SocketImpl supports sending
+     * urgent data. By default, false is returned
+     * unless the method is overridden in a sub-class
+     *
+     * @return  true if urgent data supported
+     * @see     java.net.SocketImpl#address
+     * @since 1.4
+     */
+    protected boolean supportsUrgentData () {
+        return false; // must be overridden in sub-class
+    }
+
+    /**
+     * Send one byte of urgent data on the socket.
+     * The byte to be sent is the low eight bits of the parameter
+     * @param data The byte of data to send
+     * @exception IOException if there is an error
+     *  sending the data.
+     * @since 1.4
+     */
+    protected abstract void sendUrgentData (int data) throws IOException;
+
+    /**
+     * Returns the value of this socket's {@code localport} field.
+     *
+     * @return  the value of this socket's {@code localport} field.
+     * @see     java.net.SocketImpl#localport
+     */
+    protected int getLocalPort() {
+        return localport;
+    }
+
+    void setSocket(Socket soc) {
+        this.socket = soc;
+    }
+
+    Socket getSocket() {
+        return socket;
+    }
+
+    void setServerSocket(ServerSocket soc) {
+        this.serverSocket = soc;
+    }
+
+    ServerSocket getServerSocket() {
+        return serverSocket;
+    }
+
+    /**
+     * Returns the address and port of this socket as a {@code String}.
+     *
+     * @return  a string representation of this socket.
+     */
+    public String toString() {
+        return "Socket[addr=" + getInetAddress() +
+            ",port=" + getPort() + ",localport=" + getLocalPort()  + "]";
+    }
+
+    void reset() throws IOException {
+        address = null;
+        port = 0;
+        localport = 0;
+    }
+
+    /**
+     * Sets performance preferences for this socket.
+     *
+     * <p> Sockets use the TCP/IP protocol by default.  Some implementations
+     * may offer alternative protocols which have different performance
+     * characteristics than TCP/IP.  This method allows the application to
+     * express its own preferences as to how these tradeoffs should be made
+     * when the implementation chooses from the available protocols.
+     *
+     * <p> Performance preferences are described by three integers
+     * whose values indicate the relative importance of short connection time,
+     * low latency, and high bandwidth.  The absolute values of the integers
+     * are irrelevant; in order to choose a protocol the values are simply
+     * compared, with larger values indicating stronger preferences. Negative
+     * values represent a lower priority than positive values. If the
+     * application prefers short connection time over both low latency and high
+     * bandwidth, for example, then it could invoke this method with the values
+     * {@code (1, 0, 0)}.  If the application prefers high bandwidth above low
+     * latency, and low latency above short connection time, then it could
+     * invoke this method with the values {@code (0, 1, 2)}.
+     *
+     * By default, this method does nothing, unless it is overridden in a
+     * a sub-class.
+     *
+     * @param  connectionTime
+     *         An {@code int} expressing the relative importance of a short
+     *         connection time
+     *
+     * @param  latency
+     *         An {@code int} expressing the relative importance of low
+     *         latency
+     *
+     * @param  bandwidth
+     *         An {@code int} expressing the relative importance of high
+     *         bandwidth
+     *
+     * @since 1.5
+     */
+    protected void setPerformancePreferences(int connectionTime,
+                                          int latency,
+                                          int bandwidth)
+    {
+        /* Not implemented yet */
+    }
+
+    <T> void setOption(SocketOption<T> name, T value) throws IOException {
+        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+            setOption(SocketOptions.SO_KEEPALIVE, value);
+        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+            setOption(SocketOptions.SO_SNDBUF, value);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            setOption(SocketOptions.SO_RCVBUF, value);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            setOption(SocketOptions.SO_REUSEADDR, value);
+        } else if (name == StandardSocketOptions.SO_LINGER) {
+            setOption(SocketOptions.SO_LINGER, value);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            setOption(SocketOptions.IP_TOS, value);
+        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+            setOption(SocketOptions.TCP_NODELAY, value);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+
+    <T> T getOption(SocketOption<T> name) throws IOException {
+        if (name == StandardSocketOptions.SO_KEEPALIVE) {
+            return (T)getOption(SocketOptions.SO_KEEPALIVE);
+        } else if (name == StandardSocketOptions.SO_SNDBUF) {
+            return (T)getOption(SocketOptions.SO_SNDBUF);
+        } else if (name == StandardSocketOptions.SO_RCVBUF) {
+            return (T)getOption(SocketOptions.SO_RCVBUF);
+        } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+            return (T)getOption(SocketOptions.SO_REUSEADDR);
+        } else if (name == StandardSocketOptions.SO_LINGER) {
+            return (T)getOption(SocketOptions.SO_LINGER);
+        } else if (name == StandardSocketOptions.IP_TOS) {
+            return (T)getOption(SocketOptions.IP_TOS);
+        } else if (name == StandardSocketOptions.TCP_NODELAY) {
+            return (T)getOption(SocketOptions.TCP_NODELAY);
+        } else {
+            throw new UnsupportedOperationException("unsupported option");
+        }
+    }
+}
diff --git a/java/net/SocketImplFactory.java b/java/net/SocketImplFactory.java
new file mode 100644
index 0000000..7aa6363
--- /dev/null
+++ b/java/net/SocketImplFactory.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for socket implementations. It
+ * is used by the classes {@code Socket} and
+ * {@code ServerSocket} to create actual socket
+ * implementations.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.net.Socket
+ * @see     java.net.ServerSocket
+ * @since   JDK1.0
+ */
+public
+interface SocketImplFactory {
+    /**
+     * Creates a new {@code SocketImpl} instance.
+     *
+     * @return  a new instance of {@code SocketImpl}.
+     * @see     java.net.SocketImpl
+     */
+    SocketImpl createSocketImpl();
+}
diff --git a/java/net/SocketInputStream.java b/java/net/SocketInputStream.java
new file mode 100644
index 0000000..8d0e0c5
--- /dev/null
+++ b/java/net/SocketInputStream.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import dalvik.system.BlockGuard;
+import sun.net.ConnectionResetException;
+
+/**
+ * This stream extends FileInputStream to implement a
+ * SocketInputStream. Note that this class should <b>NOT</b> be
+ * public.
+ *
+ * @author      Jonathan Payne
+ * @author      Arthur van Hoff
+ */
+class SocketInputStream extends FileInputStream
+{
+    // Android-removed: Android doesn't need to call native init.
+    // static {
+    //    init();
+    //}
+
+    private boolean eof;
+    private AbstractPlainSocketImpl impl = null;
+    private byte temp[];
+    private Socket socket = null;
+
+    /**
+     * Creates a new SocketInputStream. Can only be called
+     * by a Socket. This method needs to hang on to the owner Socket so
+     * that the fd will not be closed.
+     * @param impl the implemented socket input stream
+     */
+    SocketInputStream(AbstractPlainSocketImpl impl) throws IOException {
+        super(impl.getFileDescriptor());
+        this.impl = impl;
+        socket = impl.getSocket();
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file input stream.</p>
+     *
+     * The {@code getChannel} method of {@code SocketInputStream}
+     * returns {@code null} since it is a socket based stream.</p>
+     *
+     * @return  the file channel associated with this file input stream
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public final FileChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Reads into an array of bytes at the specified offset using
+     * the received socket primitive.
+     * @param fd the FileDescriptor
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes read
+     * @param timeout the read timeout in ms
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    private native int socketRead0(FileDescriptor fd,
+                                   byte b[], int off, int len,
+                                   int timeout)
+        throws IOException;
+
+    // wrap native call to allow instrumentation
+    /**
+     * Reads into an array of bytes at the specified offset using
+     * the received socket primitive.
+     * @param fd the FileDescriptor
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes read
+     * @param timeout the read timeout in ms
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    private int socketRead(FileDescriptor fd,
+                           byte b[], int off, int len,
+                           int timeout)
+        throws IOException {
+        return socketRead0(fd, b, off, len, timeout);
+    }
+
+    /**
+     * Reads into a byte array data from the socket.
+     * @param b the buffer into which the data is read
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read(byte b[]) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Reads into a byte array <i>b</i> at offset <i>off</i>,
+     * <i>length</i> bytes of data.
+     * @param b the buffer into which the data is read
+     * @param off the start offset of the data
+     * @param length the maximum number of bytes read
+     * @return the actual number of bytes read, -1 is
+     *          returned when the end of the stream is reached.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public int read(byte b[], int off, int length) throws IOException {
+        return read(b, off, length, impl.getTimeout());
+    }
+
+    int read(byte b[], int off, int length, int timeout) throws IOException {
+        int n;
+
+        // EOF already encountered
+        if (eof) {
+            return -1;
+        }
+
+        // connection reset
+        if (impl.isConnectionReset()) {
+            throw new SocketException("Connection reset");
+        }
+
+        // bounds check
+        if (length <= 0 || off < 0 || length > b.length - off) {
+            if (length == 0) {
+                return 0;
+            }
+            throw new ArrayIndexOutOfBoundsException("length == " + length
+                    + " off == " + off + " buffer length == " + b.length);
+        }
+
+        boolean gotReset = false;
+
+        // acquire file descriptor and do the read
+        FileDescriptor fd = impl.acquireFD();
+        try {
+            // Android-added: Check BlockGuard policy in read().
+            BlockGuard.getThreadPolicy().onNetwork();
+            n = socketRead(fd, b, off, length, timeout);
+            if (n > 0) {
+                return n;
+            }
+        } catch (ConnectionResetException rstExc) {
+            gotReset = true;
+        } finally {
+            impl.releaseFD();
+        }
+
+        /*
+         * We receive a "connection reset" but there may be bytes still
+         * buffered on the socket
+         */
+        if (gotReset) {
+            impl.setConnectionResetPending();
+            impl.acquireFD();
+            try {
+                n = socketRead(fd, b, off, length, timeout);
+                if (n > 0) {
+                    return n;
+                }
+            } catch (ConnectionResetException rstExc) {
+            } finally {
+                impl.releaseFD();
+            }
+        }
+
+        /*
+         * If we get here we are at EOF, the socket has been closed,
+         * or the connection has been reset.
+         */
+        if (impl.isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        if (impl.isConnectionResetPending()) {
+            impl.setConnectionReset();
+        }
+        if (impl.isConnectionReset()) {
+            throw new SocketException("Connection reset");
+        }
+        eof = true;
+        return -1;
+    }
+
+    /**
+     * Reads a single byte from the socket.
+     */
+    public int read() throws IOException {
+        if (eof) {
+            return -1;
+        }
+        temp = new byte[1];
+        int n = read(temp, 0, 1);
+        if (n <= 0) {
+            return -1;
+        }
+        return temp[0] & 0xff;
+    }
+
+    /**
+     * Skips n bytes of input.
+     * @param numbytes the number of bytes to skip
+     * @return  the actual number of bytes skipped.
+     * @exception IOException If an I/O error has occurred.
+     */
+    public long skip(long numbytes) throws IOException {
+        if (numbytes <= 0) {
+            return 0;
+        }
+        long n = numbytes;
+        int buflen = (int) Math.min(1024, n);
+        byte data[] = new byte[buflen];
+        while (n > 0) {
+            int r = read(data, 0, (int) Math.min((long) buflen, n));
+            if (r < 0) {
+                break;
+            }
+            n -= r;
+        }
+        return numbytes - n;
+    }
+
+    /**
+     * Returns the number of bytes that can be read without blocking.
+     * @return the number of immediately available bytes
+     */
+    public int available() throws IOException {
+        // Android-changed: Bug fix, if eof == true, we must indicate that we
+        // have 0 bytes available.
+        if (eof) {
+            return 0;
+        } else {
+            return impl.available();
+        }
+    }
+
+    /**
+     * Closes the stream.
+     */
+    private boolean closing = false;
+    public void close() throws IOException {
+        // Prevent recursion. See BugId 4484411
+        if (closing)
+            return;
+        closing = true;
+        if (socket != null) {
+            if (!socket.isClosed())
+                socket.close();
+        } else
+            impl.close();
+        closing = false;
+    }
+
+    void setEOF(boolean eof) {
+        this.eof = eof;
+    }
+
+    /**
+     * Overrides finalize, the fd is closed by the Socket.
+     */
+    protected void finalize() {}
+
+    // Android-removed: Android doesn't need native init.
+    /*
+     * Perform class load-time initializations.
+     *
+    private native static void init();
+    */
+}
diff --git a/java/net/SocketOption.java b/java/net/SocketOption.java
new file mode 100644
index 0000000..2ccf57f
--- /dev/null
+++ b/java/net/SocketOption.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * A socket option associated with a socket.
+ *
+ * <p> In the {@link java.nio.channels channels} package, the {@link
+ * java.nio.channels.NetworkChannel} interface defines the {@link
+ * java.nio.channels.NetworkChannel#setOption(SocketOption,Object) setOption}
+ * and {@link java.nio.channels.NetworkChannel#getOption(SocketOption) getOption}
+ * methods to set and query the channel's socket options.
+ *
+ * @param   <T>     The type of the socket option value.
+ *
+ * @since 1.7
+ *
+ * @see StandardSocketOptions
+ */
+
+public interface SocketOption<T> {
+
+    /**
+     * Returns the name of the socket option.
+     *
+     * @return the name of the socket option
+     */
+    String name();
+
+    /**
+     * Returns the type of the socket option value.
+     *
+     * @return the type of the socket option value
+     */
+    Class<T> type();
+}
diff --git a/java/net/SocketOptions.java b/java/net/SocketOptions.java
new file mode 100644
index 0000000..7e1b0fc
--- /dev/null
+++ b/java/net/SocketOptions.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.lang.annotation.Native;
+
+/**
+ * Interface of methods to get/set socket options.  This interface is
+ * implemented by: <B>SocketImpl</B> and  <B>DatagramSocketImpl</B>.
+ * Subclasses of these should override the methods
+ * of this interface in order to support their own options.
+ * <P>
+ * The methods and constants which specify options in this interface are
+ * for implementation only.  If you're not subclassing SocketImpl or
+ * DatagramSocketImpl, <B>you won't use these directly.</B> There are
+ * type-safe methods to get/set each of these options in Socket, ServerSocket,
+ * DatagramSocket and MulticastSocket.
+ * <P>
+ * @author David Brown
+ */
+
+
+public interface SocketOptions {
+
+    /**
+     * Enable/disable the option specified by <I>optID</I>.  If the option
+     * is to be enabled, and it takes an option-specific "value",  this is
+     * passed in <I>value</I>.  The actual type of value is option-specific,
+     * and it is an error to pass something that isn't of the expected type:
+     * <BR><PRE>
+     * SocketImpl s;
+     * ...
+     * s.setOption(SO_LINGER, new Integer(10));
+     *    // OK - set SO_LINGER w/ timeout of 10 sec.
+     * s.setOption(SO_LINGER, new Double(10));
+     *    // ERROR - expects java.lang.Integer
+     *</PRE>
+     * If the requested option is binary, it can be set using this method by
+     * a java.lang.Boolean:
+     * <BR><PRE>
+     * s.setOption(TCP_NODELAY, new Boolean(true));
+     *    // OK - enables TCP_NODELAY, a binary option
+     * </PRE>
+     * <BR>
+     * Any option can be disabled using this method with a Boolean(false):
+     * <BR><PRE>
+     * s.setOption(TCP_NODELAY, new Boolean(false));
+     *    // OK - disables TCP_NODELAY
+     * s.setOption(SO_LINGER, new Boolean(false));
+     *    // OK - disables SO_LINGER
+     * </PRE>
+     * <BR>
+     * For an option that has a notion of on and off, and requires
+     * a non-boolean parameter, setting its value to anything other than
+     * <I>Boolean(false)</I> implicitly enables it.
+     * <BR>
+     * Throws SocketException if the option is unrecognized,
+     * the socket is closed, or some low-level error occurred
+     * <BR>
+     * @param optID identifies the option
+     * @param value the parameter of the socket option
+     * @throws SocketException if the option is unrecognized,
+     * the socket is closed, or some low-level error occurred
+     * @see #getOption(int)
+     */
+    public void
+        setOption(int optID, Object value) throws SocketException;
+
+    /**
+     * Fetch the value of an option.
+     * Binary options will return java.lang.Boolean(true)
+     * if enabled, java.lang.Boolean(false) if disabled, e.g.:
+     * <BR><PRE>
+     * SocketImpl s;
+     * ...
+     * Boolean noDelay = (Boolean)(s.getOption(TCP_NODELAY));
+     * if (noDelay.booleanValue()) {
+     *     // true if TCP_NODELAY is enabled...
+     * ...
+     * }
+     * </PRE>
+     * <P>
+     * For options that take a particular type as a parameter,
+     * getOption(int) will return the parameter's value, else
+     * it will return java.lang.Boolean(false):
+     * <PRE>
+     * Object o = s.getOption(SO_LINGER);
+     * if (o instanceof Integer) {
+     *     System.out.print("Linger time is " + ((Integer)o).intValue());
+     * } else {
+     *   // the true type of o is java.lang.Boolean(false);
+     * }
+     * </PRE>
+     *
+     * @param optID an {@code int} identifying the option to fetch
+     * @return the value of the option
+     * @throws SocketException if the socket is closed
+     * @throws SocketException if <I>optID</I> is unknown along the
+     *         protocol stack (including the SocketImpl)
+     * @see #setOption(int, java.lang.Object)
+     */
+    public Object getOption(int optID) throws SocketException;
+
+    /**
+     * The java-supported BSD-style options.
+     */
+
+    /**
+     * Disable Nagle's algorithm for this connection.  Written data
+     * to the network is not buffered pending acknowledgement of
+     * previously written data.
+     *<P>
+     * Valid for TCP only: SocketImpl.
+     *
+     * @see Socket#setTcpNoDelay
+     * @see Socket#getTcpNoDelay
+     */
+
+    @Native public final static int TCP_NODELAY = 0x0001;
+
+    /**
+     * Fetch the local address binding of a socket (this option cannot
+     * be "set" only "gotten", since sockets are bound at creation time,
+     * and so the locally bound address cannot be changed).  The default local
+     * address of a socket is INADDR_ANY, meaning any local address on a
+     * multi-homed host.  A multi-homed host can use this option to accept
+     * connections to only one of its addresses (in the case of a
+     * ServerSocket or DatagramSocket), or to specify its return address
+     * to the peer (for a Socket or DatagramSocket).  The parameter of
+     * this option is an InetAddress.
+     * <P>
+     * This option <B>must</B> be specified in the constructor.
+     * <P>
+     * Valid for: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#getLocalAddress
+     * @see DatagramSocket#getLocalAddress
+     */
+
+    @Native public final static int SO_BINDADDR = 0x000F;
+
+    /** Sets SO_REUSEADDR for a socket.  This is used only for MulticastSockets
+     * in java, and it is set by default for MulticastSockets.
+     * <P>
+     * Valid for: DatagramSocketImpl
+     */
+
+    @Native public final static int SO_REUSEADDR = 0x04;
+
+    /**
+     * Sets SO_BROADCAST for a socket. This option enables and disables
+     * the ability of the process to send broadcast messages. It is supported
+     * for only datagram sockets and only on networks that support
+     * the concept of a broadcast message (e.g. Ethernet, token ring, etc.),
+     * and it is set by default for DatagramSockets.
+     * @since 1.4
+     */
+
+    @Native public final static int SO_BROADCAST = 0x0020;
+
+    /** Set which outgoing interface on which to send multicast packets.
+     * Useful on hosts with multiple network interfaces, where applications
+     * want to use other than the system default.  Takes/returns an InetAddress.
+     * <P>
+     * Valid for Multicast: DatagramSocketImpl
+     *
+     * @see MulticastSocket#setInterface(InetAddress)
+     * @see MulticastSocket#getInterface()
+     */
+
+    @Native public final static int IP_MULTICAST_IF = 0x10;
+
+    /** Same as above. This option is introduced so that the behaviour
+     *  with IP_MULTICAST_IF will be kept the same as before, while
+     *  this new option can support setting outgoing interfaces with either
+     *  IPv4 and IPv6 addresses.
+     *
+     *  NOTE: make sure there is no conflict with this
+     * @see MulticastSocket#setNetworkInterface(NetworkInterface)
+     * @see MulticastSocket#getNetworkInterface()
+     * @since 1.4
+     */
+    @Native public final static int IP_MULTICAST_IF2 = 0x1f;
+
+    /**
+     * This option enables or disables local loopback of multicast datagrams.
+     * This option is enabled by default for Multicast Sockets.
+     * @since 1.4
+     */
+
+    @Native public final static int IP_MULTICAST_LOOP = 0x12;
+
+    /**
+     * This option sets the type-of-service or traffic class field
+     * in the IP header for a TCP or UDP socket.
+     * @since 1.4
+     */
+
+    @Native public final static int IP_TOS = 0x3;
+
+    /**
+     * Specify a linger-on-close timeout.  This option disables/enables
+     * immediate return from a <B>close()</B> of a TCP Socket.  Enabling
+     * this option with a non-zero Integer <I>timeout</I> means that a
+     * <B>close()</B> will block pending the transmission and acknowledgement
+     * of all data written to the peer, at which point the socket is closed
+     * <I>gracefully</I>.  Upon reaching the linger timeout, the socket is
+     * closed <I>forcefully</I>, with a TCP RST. Enabling the option with a
+     * timeout of zero does a forceful close immediately. If the specified
+     * timeout value exceeds 65,535 it will be reduced to 65,535.
+     * <P>
+     * Valid only for TCP: SocketImpl
+     *
+     * @see Socket#setSoLinger
+     * @see Socket#getSoLinger
+     */
+    @Native public final static int SO_LINGER = 0x0080;
+
+    /** Set a timeout on blocking Socket operations:
+     * <PRE>
+     * ServerSocket.accept();
+     * SocketInputStream.read();
+     * DatagramSocket.receive();
+     * </PRE>
+     *
+     * <P> The option must be set prior to entering a blocking
+     * operation to take effect.  If the timeout expires and the
+     * operation would continue to block,
+     * <B>java.io.InterruptedIOException</B> is raised.  The Socket is
+     * not closed in this case.
+     *
+     * <P> Valid for all sockets: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#setSoTimeout
+     * @see ServerSocket#setSoTimeout
+     * @see DatagramSocket#setSoTimeout
+     */
+    @Native public final static int SO_TIMEOUT = 0x1006;
+
+    /**
+     * Set a hint the size of the underlying buffers used by the
+     * platform for outgoing network I/O. When used in set, this is a
+     * suggestion to the kernel from the application about the size of
+     * buffers to use for the data to be sent over the socket. When
+     * used in get, this must return the size of the buffer actually
+     * used by the platform when sending out data on this socket.
+     *
+     * Valid for all sockets: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#setSendBufferSize
+     * @see Socket#getSendBufferSize
+     * @see DatagramSocket#setSendBufferSize
+     * @see DatagramSocket#getSendBufferSize
+     */
+    @Native public final static int SO_SNDBUF = 0x1001;
+
+    /**
+     * Set a hint the size of the underlying buffers used by the
+     * platform for incoming network I/O. When used in set, this is a
+     * suggestion to the kernel from the application about the size of
+     * buffers to use for the data to be received over the
+     * socket. When used in get, this must return the size of the
+     * buffer actually used by the platform when receiving in data on
+     * this socket.
+     *
+     * Valid for all sockets: SocketImpl, DatagramSocketImpl
+     *
+     * @see Socket#setReceiveBufferSize
+     * @see Socket#getReceiveBufferSize
+     * @see DatagramSocket#setReceiveBufferSize
+     * @see DatagramSocket#getReceiveBufferSize
+     */
+    @Native public final static int SO_RCVBUF = 0x1002;
+
+    /**
+     * When the keepalive option is set for a TCP socket and no data
+     * has been exchanged across the socket in either direction for
+     * 2 hours (NOTE: the actual value is implementation dependent),
+     * TCP automatically sends a keepalive probe to the peer. This probe is a
+     * TCP segment to which the peer must respond.
+     * One of three responses is expected:
+     * 1. The peer responds with the expected ACK. The application is not
+     *    notified (since everything is OK). TCP will send another probe
+     *    following another 2 hours of inactivity.
+     * 2. The peer responds with an RST, which tells the local TCP that
+     *    the peer host has crashed and rebooted. The socket is closed.
+     * 3. There is no response from the peer. The socket is closed.
+     *
+     * The purpose of this option is to detect if the peer host crashes.
+     *
+     * Valid only for TCP socket: SocketImpl
+     *
+     * @see Socket#setKeepAlive
+     * @see Socket#getKeepAlive
+     */
+    @Native public final static int SO_KEEPALIVE = 0x0008;
+
+    /**
+     * When the OOBINLINE option is set, any TCP urgent data received on
+     * the socket will be received through the socket input stream.
+     * When the option is disabled (which is the default) urgent data
+     * is silently discarded.
+     *
+     * @see Socket#setOOBInline
+     * @see Socket#getOOBInline
+     */
+    @Native public final static int SO_OOBINLINE = 0x1003;
+}
diff --git a/java/net/SocketOutputStream.java b/java/net/SocketOutputStream.java
new file mode 100644
index 0000000..9e8e792
--- /dev/null
+++ b/java/net/SocketOutputStream.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import dalvik.system.BlockGuard;
+
+/**
+ * This stream extends FileOutputStream to implement a
+ * SocketOutputStream. Note that this class should <b>NOT</b> be
+ * public.
+ *
+ * @author      Jonathan Payne
+ * @author      Arthur van Hoff
+ */
+class SocketOutputStream extends FileOutputStream
+{
+    // Android-removed: Android doesn't need to call native init.
+    // static {
+    //    init();
+    //}
+
+    private AbstractPlainSocketImpl impl = null;
+    private byte temp[] = new byte[1];
+    private Socket socket = null;
+
+    /**
+     * Creates a new SocketOutputStream. Can only be called
+     * by a Socket. This method needs to hang on to the owner Socket so
+     * that the fd will not be closed.
+     * @param impl the socket output stream inplemented
+     */
+    SocketOutputStream(AbstractPlainSocketImpl impl) throws IOException {
+        super(impl.getFileDescriptor());
+        this.impl = impl;
+        socket = impl.getSocket();
+    }
+
+    /**
+     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
+     * object associated with this file output stream. </p>
+     *
+     * The {@code getChannel} method of {@code SocketOutputStream}
+     * returns {@code null} since it is a socket based stream.</p>
+     *
+     * @return  the file channel associated with this file output stream
+     *
+     * @since 1.4
+     * @spec JSR-51
+     */
+    public final FileChannel getChannel() {
+        return null;
+    }
+
+    /**
+     * Writes to the socket.
+     * @param fd the FileDescriptor
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     */
+    private native void socketWrite0(FileDescriptor fd, byte[] b, int off,
+                                     int len) throws IOException;
+
+    /**
+     * Writes to the socket with appropriate locking of the
+     * FileDescriptor.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception IOException If an I/O error has occurred.
+     */
+    private void socketWrite(byte b[], int off, int len) throws IOException {
+
+
+        if (len <= 0 || off < 0 || len > b.length - off) {
+            if (len == 0) {
+                return;
+            }
+            throw new ArrayIndexOutOfBoundsException("len == " + len
+                    + " off == " + off + " buffer length == " + b.length);
+        }
+
+        FileDescriptor fd = impl.acquireFD();
+        try {
+            // Android-added: Check BlockGuard policy in socketWrite.
+            BlockGuard.getThreadPolicy().onNetwork();
+            socketWrite0(fd, b, off, len);
+        } catch (SocketException se) {
+            if (se instanceof sun.net.ConnectionResetException) {
+                impl.setConnectionResetPending();
+                se = new SocketException("Connection reset");
+            }
+            if (impl.isClosedOrPending()) {
+                throw new SocketException("Socket closed");
+            } else {
+                throw se;
+            }
+        } finally {
+            impl.releaseFD();
+        }
+    }
+
+    /**
+     * Writes a byte to the socket.
+     * @param b the data to be written
+     * @exception IOException If an I/O error has occurred.
+     */
+    public void write(int b) throws IOException {
+        temp[0] = (byte)b;
+        socketWrite(temp, 0, 1);
+    }
+
+    /**
+     * Writes the contents of the buffer <i>b</i> to the socket.
+     * @param b the data to be written
+     * @exception SocketException If an I/O error has occurred.
+     */
+    public void write(byte b[]) throws IOException {
+        socketWrite(b, 0, b.length);
+    }
+
+    /**
+     * Writes <i>length</i> bytes from buffer <i>b</i> starting at
+     * offset <i>len</i>.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception SocketException If an I/O error has occurred.
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+        socketWrite(b, off, len);
+    }
+
+    /**
+     * Closes the stream.
+     */
+    private boolean closing = false;
+    public void close() throws IOException {
+        // Prevent recursion. See BugId 4484411
+        if (closing)
+            return;
+        closing = true;
+        if (socket != null) {
+            if (!socket.isClosed())
+                socket.close();
+        } else
+            impl.close();
+        closing = false;
+    }
+
+    /**
+     * Overrides finalize, the fd is closed by the Socket.
+     */
+    protected void finalize() {}
+
+    // Android-removed: Android doesn't need native init.
+    /*
+     * Perform class load-time initializations.
+     *
+    private native static void init();
+    */
+}
diff --git a/java/net/SocketPermission.java b/java/net/SocketPermission.java
new file mode 100644
index 0000000..2195ecc
--- /dev/null
+++ b/java/net/SocketPermission.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.security.Permission;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class SocketPermission extends Permission
+implements java.io.Serializable
+{
+
+    public SocketPermission(String host, String action) { super(""); }
+
+    public boolean implies(Permission p) { return true; }
+
+    public String getActions() { return null; }
+}
diff --git a/java/net/SocketSecrets.java b/java/net/SocketSecrets.java
new file mode 100644
index 0000000..9772906
--- /dev/null
+++ b/java/net/SocketSecrets.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+class SocketSecrets {
+
+    /* accessed by reflection from jdk.net.Sockets */
+
+    /* obj must be a Socket or ServerSocket */
+
+    private static <T> void setOption(Object obj, SocketOption<T> name, T value) throws IOException {
+        SocketImpl impl;
+
+        if (obj instanceof Socket) {
+            impl = ((Socket)obj).getImpl();
+        } else if (obj instanceof ServerSocket) {
+            impl = ((ServerSocket)obj).getImpl();
+        } else {
+            throw new IllegalArgumentException();
+        }
+        impl.setOption(name, value);
+    }
+
+    private static <T> T getOption(Object obj, SocketOption<T> name) throws IOException {
+        SocketImpl impl;
+
+        if (obj instanceof Socket) {
+            impl = ((Socket)obj).getImpl();
+        } else if (obj instanceof ServerSocket) {
+            impl = ((ServerSocket)obj).getImpl();
+        } else {
+            throw new IllegalArgumentException();
+        }
+        return impl.getOption(name);
+    }
+
+    private static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException {
+        s.getImpl().setOption(name, value);
+    }
+
+    private static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException {
+        return s.getImpl().getOption(name);
+    }
+
+}
diff --git a/java/net/SocketTimeoutException.java b/java/net/SocketTimeoutException.java
new file mode 100644
index 0000000..5daf600
--- /dev/null
+++ b/java/net/SocketTimeoutException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Signals that a timeout has occurred on a socket read or accept.
+ *
+ * @since   1.4
+ */
+
+public class SocketTimeoutException extends java.io.InterruptedIOException {
+    private static final long serialVersionUID = -8846654841826352300L;
+
+    /**
+     * Constructs a new SocketTimeoutException with a detail
+     * message.
+     * @param msg the detail message
+     */
+    public SocketTimeoutException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new SocketTimeoutException with no detailed message.
+     */
+    public SocketTimeoutException() {}
+}
diff --git a/java/net/SocksConsts.java b/java/net/SocksConsts.java
new file mode 100644
index 0000000..df47aa7
--- /dev/null
+++ b/java/net/SocksConsts.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+
+/**
+ * Constants used by the SOCKS protocol implementation.
+ */
+
+interface SocksConsts {
+    static final int PROTO_VERS4                = 4;
+    static final int PROTO_VERS         = 5;
+    static final int DEFAULT_PORT               = 1080;
+
+    static final int NO_AUTH            = 0;
+    static final int GSSAPI             = 1;
+    static final int USER_PASSW         = 2;
+    static final int NO_METHODS         = -1;
+
+    static final int CONNECT            = 1;
+    static final int BIND                       = 2;
+    static final int UDP_ASSOC          = 3;
+
+    static final int IPV4                       = 1;
+    static final int DOMAIN_NAME                = 3;
+    static final int IPV6                       = 4;
+
+    static final int REQUEST_OK         = 0;
+    static final int GENERAL_FAILURE    = 1;
+    static final int NOT_ALLOWED                = 2;
+    static final int NET_UNREACHABLE    = 3;
+    static final int HOST_UNREACHABLE   = 4;
+    static final int CONN_REFUSED               = 5;
+    static final int TTL_EXPIRED                = 6;
+    static final int CMD_NOT_SUPPORTED  = 7;
+    static final int ADDR_TYPE_NOT_SUP  = 8;
+}
diff --git a/java/net/SocksSocketImpl.java b/java/net/SocksSocketImpl.java
new file mode 100644
index 0000000..0d9d8f5
--- /dev/null
+++ b/java/net/SocksSocketImpl.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.net;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.BufferedOutputStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import sun.net.SocksProxy;
+import sun.net.www.ParseUtil;
+/* import org.ietf.jgss.*; */
+
+/**
+ * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
+ * This is a subclass of PlainSocketImpl.
+ * Note this class should <b>NOT</b> be public.
+ */
+
+class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
+    private String server = null;
+    private int serverPort = DEFAULT_PORT;
+    private InetSocketAddress external_address;
+    private boolean useV4 = false;
+    private Socket cmdsock = null;
+    private InputStream cmdIn = null;
+    private OutputStream cmdOut = null;
+    /* true if the Proxy has been set programatically */
+    private boolean applicationSetProxy;  /* false */
+
+
+    SocksSocketImpl() {
+        // Nothing needed
+    }
+
+    SocksSocketImpl(String server, int port) {
+        this.server = server;
+        this.serverPort = (port == -1 ? DEFAULT_PORT : port);
+    }
+
+    SocksSocketImpl(Proxy proxy) {
+        SocketAddress a = proxy.address();
+        if (a instanceof InetSocketAddress) {
+            InetSocketAddress ad = (InetSocketAddress) a;
+            // Use getHostString() to avoid reverse lookups
+            server = ad.getHostString();
+            serverPort = ad.getPort();
+        }
+    }
+
+    void setV4() {
+        useV4 = true;
+    }
+
+    private synchronized void privilegedConnect(final String host,
+                                              final int port,
+                                              final int timeout)
+         throws IOException
+    {
+        try {
+            AccessController.doPrivileged(
+                new java.security.PrivilegedExceptionAction<Void>() {
+                    public Void run() throws IOException {
+                              superConnectServer(host, port, timeout);
+                              cmdIn = getInputStream();
+                              cmdOut = getOutputStream();
+                              return null;
+                          }
+                      });
+        } catch (java.security.PrivilegedActionException pae) {
+            throw (IOException) pae.getException();
+        }
+    }
+
+    private void superConnectServer(String host, int port,
+                                    int timeout) throws IOException {
+        super.connect(new InetSocketAddress(host, port), timeout);
+    }
+
+    private static int remainingMillis(long deadlineMillis) throws IOException {
+        if (deadlineMillis == 0L)
+            return 0;
+
+        final long remaining = deadlineMillis - System.currentTimeMillis();
+        if (remaining > 0)
+            return (int) remaining;
+
+        throw new SocketTimeoutException();
+    }
+
+    private int readSocksReply(InputStream in, byte[] data) throws IOException {
+        return readSocksReply(in, data, 0L);
+    }
+
+    private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
+        int len = data.length;
+        int received = 0;
+        for (int attempts = 0; received < len && attempts < 3; attempts++) {
+            int count;
+            try {
+                count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
+            } catch (SocketTimeoutException e) {
+                throw new SocketTimeoutException("Connect timed out");
+            }
+            if (count < 0)
+                throw new SocketException("Malformed reply from SOCKS server");
+            received += count;
+        }
+        return received;
+    }
+
+    /**
+     * Provides the authentication machanism required by the proxy.
+     */
+    private boolean authenticate(byte method, InputStream in,
+                                 BufferedOutputStream out) throws IOException {
+        return authenticate(method, in, out, 0L);
+    }
+
+    private boolean authenticate(byte method, InputStream in,
+                                 BufferedOutputStream out,
+                                 long deadlineMillis) throws IOException {
+        // No Authentication required. We're done then!
+        if (method == NO_AUTH)
+            return true;
+        /**
+         * User/Password authentication. Try, in that order :
+         * - The application provided Authenticator, if any
+         * - the user.name & no password (backward compatibility behavior).
+         */
+        if (method == USER_PASSW) {
+            String userName;
+            String password = null;
+            final InetAddress addr = InetAddress.getByName(server);
+            PasswordAuthentication pw =
+                java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedAction<PasswordAuthentication>() {
+                        public PasswordAuthentication run() {
+                                return Authenticator.requestPasswordAuthentication(
+                                       server, addr, serverPort, "SOCKS5", "SOCKS authentication", null);
+                            }
+                        });
+            if (pw != null) {
+                userName = pw.getUserName();
+                password = new String(pw.getPassword());
+            } else {
+                userName = java.security.AccessController.doPrivileged(
+                        new sun.security.action.GetPropertyAction("user.name"));
+            }
+            if (userName == null)
+                return false;
+            out.write(1);
+            out.write(userName.length());
+            try {
+                out.write(userName.getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            if (password != null) {
+                out.write(password.length());
+                try {
+                    out.write(password.getBytes("ISO-8859-1"));
+                } catch (java.io.UnsupportedEncodingException uee) {
+                    assert false;
+                }
+            } else
+                out.write(0);
+            out.flush();
+            byte[] data = new byte[2];
+            int i = readSocksReply(in, data, deadlineMillis);
+            if (i != 2 || data[1] != 0) {
+                /* RFC 1929 specifies that the connection MUST be closed if
+                   authentication fails */
+                out.close();
+                in.close();
+                return false;
+            }
+            /* Authentication succeeded */
+            return true;
+        }
+        /**
+         * GSSAPI authentication mechanism.
+         * Unfortunately the RFC seems out of sync with the Reference
+         * implementation. I'll leave this in for future completion.
+         */
+//      if (method == GSSAPI) {
+//          try {
+//              GSSManager manager = GSSManager.getInstance();
+//              GSSName name = manager.createName("SERVICE:socks@"+server,
+//                                                   null);
+//              GSSContext context = manager.createContext(name, null, null,
+//                                                         GSSContext.DEFAULT_LIFETIME);
+//              context.requestMutualAuth(true);
+//              context.requestReplayDet(true);
+//              context.requestSequenceDet(true);
+//              context.requestCredDeleg(true);
+//              byte []inToken = new byte[0];
+//              while (!context.isEstablished()) {
+//                  byte[] outToken
+//                      = context.initSecContext(inToken, 0, inToken.length);
+//                  // send the output token if generated
+//                  if (outToken != null) {
+//                      out.write(1);
+//                      out.write(1);
+//                      out.writeShort(outToken.length);
+//                      out.write(outToken);
+//                      out.flush();
+//                      data = new byte[2];
+//                      i = readSocksReply(in, data, deadlineMillis);
+//                      if (i != 2 || data[1] == 0xff) {
+//                          in.close();
+//                          out.close();
+//                          return false;
+//                      }
+//                      i = readSocksReply(in, data, deadlineMillis);
+//                      int len = 0;
+//                      len = ((int)data[0] & 0xff) << 8;
+//                      len += data[1];
+//                      data = new byte[len];
+//                      i = readSocksReply(in, data, deadlineMillis);
+//                      if (i == len)
+//                          return true;
+//                      in.close();
+//                      out.close();
+//                  }
+//              }
+//          } catch (GSSException e) {
+//              /* RFC 1961 states that if Context initialisation fails the connection
+//                 MUST be closed */
+//              e.printStackTrace();
+//              in.close();
+//              out.close();
+//          }
+//      }
+        return false;
+    }
+
+    private void connectV4(InputStream in, OutputStream out,
+                           InetSocketAddress endpoint,
+                           long deadlineMillis) throws IOException {
+        if (!(endpoint.getAddress() instanceof Inet4Address)) {
+            throw new SocketException("SOCKS V4 requires IPv4 only addresses");
+        }
+        out.write(PROTO_VERS4);
+        out.write(CONNECT);
+        out.write((endpoint.getPort() >> 8) & 0xff);
+        out.write((endpoint.getPort() >> 0) & 0xff);
+        out.write(endpoint.getAddress().getAddress());
+        String userName = getUserName();
+        try {
+            out.write(userName.getBytes("ISO-8859-1"));
+        } catch (java.io.UnsupportedEncodingException uee) {
+            assert false;
+        }
+        out.write(0);
+        out.flush();
+        byte[] data = new byte[8];
+        int n = readSocksReply(in, data, deadlineMillis);
+        if (n != 8)
+            throw new SocketException("Reply from SOCKS server has bad length: " + n);
+        if (data[0] != 0 && data[0] != 4)
+            throw new SocketException("Reply from SOCKS server has bad version");
+        SocketException ex = null;
+        switch (data[1]) {
+        case 90:
+            // Success!
+            external_address = endpoint;
+            break;
+        case 91:
+            ex = new SocketException("SOCKS request rejected");
+            break;
+        case 92:
+            ex = new SocketException("SOCKS server couldn't reach destination");
+            break;
+        case 93:
+            ex = new SocketException("SOCKS authentication failed");
+            break;
+        default:
+            ex = new SocketException("Reply from SOCKS server contains bad status");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            throw ex;
+        }
+    }
+
+    /**
+     * Connects the Socks Socket to the specified endpoint. It will first
+     * connect to the SOCKS proxy and negotiate the access. If the proxy
+     * grants the connections, then the connect is successful and all
+     * further traffic will go to the "real" endpoint.
+     *
+     * @param   endpoint        the {@code SocketAddress} to connect to.
+     * @param   timeout         the timeout value in milliseconds
+     * @throws  IOException     if the connection can't be established.
+     * @throws  SecurityException if there is a security manager and it
+     *                          doesn't allow the connection
+     * @throws  IllegalArgumentException if endpoint is null or a
+     *          SocketAddress subclass not supported by this socket
+     */
+    @Override
+    protected void connect(SocketAddress endpoint, int timeout) throws IOException {
+        final long deadlineMillis;
+
+        if (timeout == 0) {
+            deadlineMillis = 0L;
+        } else {
+            long finish = System.currentTimeMillis() + timeout;
+            deadlineMillis = finish < 0 ? Long.MAX_VALUE : finish;
+        }
+
+        SecurityManager security = System.getSecurityManager();
+        if (endpoint == null || !(endpoint instanceof InetSocketAddress))
+            throw new IllegalArgumentException("Unsupported address type");
+        InetSocketAddress epoint = (InetSocketAddress) endpoint;
+        if (security != null) {
+            if (epoint.isUnresolved())
+                security.checkConnect(epoint.getHostName(),
+                                      epoint.getPort());
+            else
+                security.checkConnect(epoint.getAddress().getHostAddress(),
+                                      epoint.getPort());
+        }
+        if (server == null) {
+            // Android-removed: Logic to establish proxy connection based on default ProxySelector.
+            // Removed code that tried to establish proxy connection if ProxySelector#getDefault()
+            // is not null. This was never the case in previous Android releases, was causing
+            // issues and therefore was removed.
+            /*
+            // This is the general case
+            // server is not null only when the socket was created with a
+            // specified proxy in which case it does bypass the ProxySelector
+            ProxySelector sel = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ProxySelector>() {
+                    public ProxySelector run() {
+                            return ProxySelector.getDefault();
+                        }
+                    });
+            if (sel == null) {
+                /*
+                 * No default proxySelector --> direct connection
+                 *
+                super.connect(epoint, remainingMillis(deadlineMillis));
+                return;
+            }
+            URI uri;
+            // Use getHostString() to avoid reverse lookups
+            String host = epoint.getHostString();
+            // IPv6 litteral?
+            if (epoint.getAddress() instanceof Inet6Address &&
+                (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
+                host = "[" + host + "]";
+            }
+            try {
+                uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
+            } catch (URISyntaxException e) {
+                // This shouldn't happen
+                assert false : e;
+                uri = null;
+            }
+            Proxy p = null;
+            IOException savedExc = null;
+            java.util.Iterator<Proxy> iProxy = null;
+            iProxy = sel.select(uri).iterator();
+            if (iProxy == null || !(iProxy.hasNext())) {
+                super.connect(epoint, remainingMillis(deadlineMillis));
+                return;
+            }
+            while (iProxy.hasNext()) {
+                p = iProxy.next();
+                if (p == null || p.type() != Proxy.Type.SOCKS) {
+                    super.connect(epoint, remainingMillis(deadlineMillis));
+                    return;
+                }
+
+                if (!(p.address() instanceof InetSocketAddress))
+                    throw new SocketException("Unknown address type for proxy: " + p);
+                // Use getHostString() to avoid reverse lookups
+                server = ((InetSocketAddress) p.address()).getHostString();
+                serverPort = ((InetSocketAddress) p.address()).getPort();
+                if (p instanceof SocksProxy) {
+                    if (((SocksProxy)p).protocolVersion() == 4) {
+                        useV4 = true;
+                    }
+                }
+
+                // Connects to the SOCKS server
+                try {
+                    privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
+                    // Worked, let's get outta here
+                    break;
+                } catch (IOException e) {
+                    // Ooops, let's notify the ProxySelector
+                    sel.connectFailed(uri,p.address(),e);
+                    server = null;
+                    serverPort = -1;
+                    savedExc = e;
+                    // Will continue the while loop and try the next proxy
+                }
+            }
+
+            /*
+             * If server is still null at this point, none of the proxy
+             * worked
+             *
+            if (server == null) {
+                throw new SocketException("Can't connect to SOCKS proxy:"
+                                          + savedExc.getMessage());
+            }
+             */
+            super.connect(epoint, remainingMillis(deadlineMillis));
+            return;
+        } else {
+            // Connects to the SOCKS server
+            try {
+                privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
+            } catch (IOException e) {
+                throw new SocketException(e.getMessage());
+            }
+        }
+
+        // cmdIn & cmdOut were initialized during the privilegedConnect() call
+        BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
+        InputStream in = cmdIn;
+
+        if (useV4) {
+            // SOCKS Protocol version 4 doesn't know how to deal with
+            // DOMAIN type of addresses (unresolved addresses here)
+            if (epoint.isUnresolved())
+                throw new UnknownHostException(epoint.toString());
+            connectV4(in, out, epoint, deadlineMillis);
+            return;
+        }
+
+        // This is SOCKS V5
+        out.write(PROTO_VERS);
+        out.write(2);
+        out.write(NO_AUTH);
+        out.write(USER_PASSW);
+        out.flush();
+        byte[] data = new byte[2];
+        int i = readSocksReply(in, data, deadlineMillis);
+        if (i != 2 || ((int)data[0]) != PROTO_VERS) {
+            // Maybe it's not a V5 sever after all
+            // Let's try V4 before we give up
+            // SOCKS Protocol version 4 doesn't know how to deal with
+            // DOMAIN type of addresses (unresolved addresses here)
+            if (epoint.isUnresolved())
+                throw new UnknownHostException(epoint.toString());
+            connectV4(in, out, epoint, deadlineMillis);
+            return;
+        }
+        if (((int)data[1]) == NO_METHODS)
+            throw new SocketException("SOCKS : No acceptable methods");
+        if (!authenticate(data[1], in, out, deadlineMillis)) {
+            throw new SocketException("SOCKS : authentication failed");
+        }
+        out.write(PROTO_VERS);
+        out.write(CONNECT);
+        out.write(0);
+        /* Test for IPV4/IPV6/Unresolved */
+        if (epoint.isUnresolved()) {
+            out.write(DOMAIN_NAME);
+            out.write(epoint.getHostName().length());
+            try {
+                out.write(epoint.getHostName().getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            out.write((epoint.getPort() >> 8) & 0xff);
+            out.write((epoint.getPort() >> 0) & 0xff);
+        } else if (epoint.getAddress() instanceof Inet6Address) {
+            out.write(IPV6);
+            out.write(epoint.getAddress().getAddress());
+            out.write((epoint.getPort() >> 8) & 0xff);
+            out.write((epoint.getPort() >> 0) & 0xff);
+        } else {
+            out.write(IPV4);
+            out.write(epoint.getAddress().getAddress());
+            out.write((epoint.getPort() >> 8) & 0xff);
+            out.write((epoint.getPort() >> 0) & 0xff);
+        }
+        out.flush();
+        data = new byte[4];
+        i = readSocksReply(in, data, deadlineMillis);
+        if (i != 4)
+            throw new SocketException("Reply from SOCKS server has bad length");
+        SocketException ex = null;
+        int len;
+        byte[] addr;
+        switch (data[1]) {
+        case REQUEST_OK:
+            // success!
+            switch(data[3]) {
+            case IPV4:
+                addr = new byte[4];
+                i = readSocksReply(in, addr, deadlineMillis);
+                if (i != 4)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data, deadlineMillis);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                break;
+            case DOMAIN_NAME:
+                len = data[1];
+                byte[] host = new byte[len];
+                i = readSocksReply(in, host, deadlineMillis);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data, deadlineMillis);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                break;
+            case IPV6:
+                len = data[1];
+                addr = new byte[len];
+                i = readSocksReply(in, addr, deadlineMillis);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data, deadlineMillis);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                break;
+            default:
+                ex = new SocketException("Reply from SOCKS server contains wrong code");
+                break;
+            }
+            break;
+        case GENERAL_FAILURE:
+            ex = new SocketException("SOCKS server general failure");
+            break;
+        case NOT_ALLOWED:
+            ex = new SocketException("SOCKS: Connection not allowed by ruleset");
+            break;
+        case NET_UNREACHABLE:
+            ex = new SocketException("SOCKS: Network unreachable");
+            break;
+        case HOST_UNREACHABLE:
+            ex = new SocketException("SOCKS: Host unreachable");
+            break;
+        case CONN_REFUSED:
+            ex = new SocketException("SOCKS: Connection refused");
+            break;
+        case TTL_EXPIRED:
+            ex =  new SocketException("SOCKS: TTL expired");
+            break;
+        case CMD_NOT_SUPPORTED:
+            ex = new SocketException("SOCKS: Command not supported");
+            break;
+        case ADDR_TYPE_NOT_SUP:
+            ex = new SocketException("SOCKS: address type not supported");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            throw ex;
+        }
+        external_address = epoint;
+    }
+
+    // Android-removed: Dead code. bindV4, socksBind, acceptFrom methods.
+    /*
+    private void bindV4(InputStream in, OutputStream out,
+                        InetAddress baddr,
+                        int lport) throws IOException {
+        if (!(baddr instanceof Inet4Address)) {
+            throw new SocketException("SOCKS V4 requires IPv4 only addresses");
+        }
+        super.bind(baddr, lport);
+        byte[] addr1 = baddr.getAddress();
+        /* Test for AnyLocal *
+        InetAddress naddr = baddr;
+        if (naddr.isAnyLocalAddress()) {
+            naddr = AccessController.doPrivileged(
+                        new PrivilegedAction<InetAddress>() {
+                            public InetAddress run() {
+                                return cmdsock.getLocalAddress();
+
+                            }
+                        });
+            addr1 = naddr.getAddress();
+        }
+        out.write(PROTO_VERS4);
+        out.write(BIND);
+        out.write((super.getLocalPort() >> 8) & 0xff);
+        out.write((super.getLocalPort() >> 0) & 0xff);
+        out.write(addr1);
+        String userName = getUserName();
+        try {
+            out.write(userName.getBytes("ISO-8859-1"));
+        } catch (java.io.UnsupportedEncodingException uee) {
+            assert false;
+        }
+        out.write(0);
+        out.flush();
+        byte[] data = new byte[8];
+        int n = readSocksReply(in, data);
+        if (n != 8)
+            throw new SocketException("Reply from SOCKS server has bad length: " + n);
+        if (data[0] != 0 && data[0] != 4)
+            throw new SocketException("Reply from SOCKS server has bad version");
+        SocketException ex = null;
+        switch (data[1]) {
+        case 90:
+            // Success!
+            external_address = new InetSocketAddress(baddr, lport);
+            break;
+        case 91:
+            ex = new SocketException("SOCKS request rejected");
+            break;
+        case 92:
+            ex = new SocketException("SOCKS server couldn't reach destination");
+            break;
+        case 93:
+            ex = new SocketException("SOCKS authentication failed");
+            break;
+        default:
+            ex = new SocketException("Reply from SOCKS server contains bad status");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            throw ex;
+        }
+
+    }
+
+    /**
+     * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
+     * means "accept incoming connection from", so the SocketAddress is the
+     * the one of the host we do accept connection from.
+     *
+     * @param      saddr   the Socket address of the remote host.
+     * @exception  IOException  if an I/O error occurs when binding this socket.
+     *
+    protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
+        if (socket != null) {
+            // this is a client socket, not a server socket, don't
+            // call the SOCKS proxy for a bind!
+            return;
+        }
+
+        // Connects to the SOCKS server
+
+        if (server == null) {
+            // This is the general case
+            // server is not null only when the socket was created with a
+            // specified proxy in which case it does bypass the ProxySelector
+            ProxySelector sel = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ProxySelector>() {
+                    public ProxySelector run() {
+                            return ProxySelector.getDefault();
+                        }
+                    });
+            if (sel == null) {
+                /*
+                 * No default proxySelector --> direct connection
+                 *
+                return;
+            }
+            URI uri;
+            // Use getHostString() to avoid reverse lookups
+            String host = saddr.getHostString();
+            // IPv6 litteral?
+            if (saddr.getAddress() instanceof Inet6Address &&
+                (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
+                host = "[" + host + "]";
+            }
+            try {
+                uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
+            } catch (URISyntaxException e) {
+                // This shouldn't happen
+                assert false : e;
+                uri = null;
+            }
+            Proxy p = null;
+            Exception savedExc = null;
+            java.util.Iterator<Proxy> iProxy = null;
+            iProxy = sel.select(uri).iterator();
+            if (iProxy == null || !(iProxy.hasNext())) {
+                return;
+            }
+            while (iProxy.hasNext()) {
+                p = iProxy.next();
+                if (p == null || p.type() != Proxy.Type.SOCKS) {
+                    return;
+                }
+
+                if (!(p.address() instanceof InetSocketAddress))
+                    throw new SocketException("Unknown address type for proxy: " + p);
+                // Use getHostString() to avoid reverse lookups
+                server = ((InetSocketAddress) p.address()).getHostString();
+                serverPort = ((InetSocketAddress) p.address()).getPort();
+                if (p instanceof SocksProxy) {
+                    if (((SocksProxy)p).protocolVersion() == 4) {
+                        useV4 = true;
+                    }
+                }
+
+                // Connects to the SOCKS server
+                try {
+                    AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<Void>() {
+                            public Void run() throws Exception {
+                                cmdsock = new Socket(new PlainSocketImpl());
+                                cmdsock.connect(new InetSocketAddress(server, serverPort));
+                                cmdIn = cmdsock.getInputStream();
+                                cmdOut = cmdsock.getOutputStream();
+                                return null;
+                            }
+                        });
+                } catch (Exception e) {
+                    // Ooops, let's notify the ProxySelector
+                    sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
+                    server = null;
+                    serverPort = -1;
+                    cmdsock = null;
+                    savedExc = e;
+                    // Will continue the while loop and try the next proxy
+                }
+            }
+
+            /*
+             * If server is still null at this point, none of the proxy
+             * worked
+             *
+            if (server == null || cmdsock == null) {
+                throw new SocketException("Can't connect to SOCKS proxy:"
+                                          + savedExc.getMessage());
+            }
+        } else {
+            try {
+                AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Void>() {
+                        public Void run() throws Exception {
+                            cmdsock = new Socket(new PlainSocketImpl());
+                            cmdsock.connect(new InetSocketAddress(server, serverPort));
+                            cmdIn = cmdsock.getInputStream();
+                            cmdOut = cmdsock.getOutputStream();
+                            return null;
+                        }
+                    });
+            } catch (Exception e) {
+                throw new SocketException(e.getMessage());
+            }
+        }
+        BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
+        InputStream in = cmdIn;
+        if (useV4) {
+            bindV4(in, out, saddr.getAddress(), saddr.getPort());
+            return;
+        }
+        out.write(PROTO_VERS);
+        out.write(2);
+        out.write(NO_AUTH);
+        out.write(USER_PASSW);
+        out.flush();
+        byte[] data = new byte[2];
+        int i = readSocksReply(in, data);
+        if (i != 2 || ((int)data[0]) != PROTO_VERS) {
+            // Maybe it's not a V5 sever after all
+            // Let's try V4 before we give up
+            bindV4(in, out, saddr.getAddress(), saddr.getPort());
+            return;
+        }
+        if (((int)data[1]) == NO_METHODS)
+            throw new SocketException("SOCKS : No acceptable methods");
+        if (!authenticate(data[1], in, out)) {
+            throw new SocketException("SOCKS : authentication failed");
+        }
+        // We're OK. Let's issue the BIND command.
+        out.write(PROTO_VERS);
+        out.write(BIND);
+        out.write(0);
+        int lport = saddr.getPort();
+        if (saddr.isUnresolved()) {
+            out.write(DOMAIN_NAME);
+            out.write(saddr.getHostName().length());
+            try {
+                out.write(saddr.getHostName().getBytes("ISO-8859-1"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+                assert false;
+            }
+            out.write((lport >> 8) & 0xff);
+            out.write((lport >> 0) & 0xff);
+        } else if (saddr.getAddress() instanceof Inet4Address) {
+            byte[] addr1 = saddr.getAddress().getAddress();
+            out.write(IPV4);
+            out.write(addr1);
+            out.write((lport >> 8) & 0xff);
+            out.write((lport >> 0) & 0xff);
+            out.flush();
+        } else if (saddr.getAddress() instanceof Inet6Address) {
+            byte[] addr1 = saddr.getAddress().getAddress();
+            out.write(IPV6);
+            out.write(addr1);
+            out.write((lport >> 8) & 0xff);
+            out.write((lport >> 0) & 0xff);
+            out.flush();
+        } else {
+            cmdsock.close();
+            throw new SocketException("unsupported address type : " + saddr);
+        }
+        data = new byte[4];
+        i = readSocksReply(in, data);
+        SocketException ex = null;
+        int len, nport;
+        byte[] addr;
+        switch (data[1]) {
+        case REQUEST_OK:
+            // success!
+            switch(data[3]) {
+            case IPV4:
+                addr = new byte[4];
+                i = readSocksReply(in, addr);
+                if (i != 4)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                nport = ((int)data[0] & 0xff) << 8;
+                nport += ((int)data[1] & 0xff);
+                external_address =
+                    new InetSocketAddress(new Inet4Address("", addr) , nport);
+                break;
+            case DOMAIN_NAME:
+                len = data[1];
+                byte[] host = new byte[len];
+                i = readSocksReply(in, host);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                nport = ((int)data[0] & 0xff) << 8;
+                nport += ((int)data[1] & 0xff);
+                external_address = new InetSocketAddress(new String(host), nport);
+                break;
+            case IPV6:
+                len = data[1];
+                addr = new byte[len];
+                i = readSocksReply(in, addr);
+                if (i != len)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                data = new byte[2];
+                i = readSocksReply(in, data);
+                if (i != 2)
+                    throw new SocketException("Reply from SOCKS server badly formatted");
+                nport = ((int)data[0] & 0xff) << 8;
+                nport += ((int)data[1] & 0xff);
+                external_address =
+                    new InetSocketAddress(new Inet6Address("", addr), nport);
+                break;
+            }
+            break;
+        case GENERAL_FAILURE:
+            ex = new SocketException("SOCKS server general failure");
+            break;
+        case NOT_ALLOWED:
+            ex = new SocketException("SOCKS: Bind not allowed by ruleset");
+            break;
+        case NET_UNREACHABLE:
+            ex = new SocketException("SOCKS: Network unreachable");
+            break;
+        case HOST_UNREACHABLE:
+            ex = new SocketException("SOCKS: Host unreachable");
+            break;
+        case CONN_REFUSED:
+            ex = new SocketException("SOCKS: Connection refused");
+            break;
+        case TTL_EXPIRED:
+            ex =  new SocketException("SOCKS: TTL expired");
+            break;
+        case CMD_NOT_SUPPORTED:
+            ex = new SocketException("SOCKS: Command not supported");
+            break;
+        case ADDR_TYPE_NOT_SUP:
+            ex = new SocketException("SOCKS: address type not supported");
+            break;
+        }
+        if (ex != null) {
+            in.close();
+            out.close();
+            cmdsock.close();
+            cmdsock = null;
+            throw ex;
+        }
+        cmdIn = in;
+        cmdOut = out;
+    }
+
+    /**
+     * Accepts a connection from a specific host.
+     *
+     * @param      s   the accepted connection.
+     * @param      saddr the socket address of the host we do accept
+     *               connection from
+     * @exception  IOException  if an I/O error occurs when accepting the
+     *               connection.
+     *
+    protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
+        if (cmdsock == null) {
+            // Not a Socks ServerSocket.
+            return;
+        }
+        InputStream in = cmdIn;
+        // Sends the "SOCKS BIND" request.
+        socksBind(saddr);
+        in.read();
+        int i = in.read();
+        in.read();
+        SocketException ex = null;
+        int nport;
+        byte[] addr;
+        InetSocketAddress real_end = null;
+        switch (i) {
+        case REQUEST_OK:
+            // success!
+            i = in.read();
+            switch(i) {
+            case IPV4:
+                addr = new byte[4];
+                readSocksReply(in, addr);
+                nport = in.read() << 8;
+                nport += in.read();
+                real_end =
+                    new InetSocketAddress(new Inet4Address("", addr) , nport);
+                break;
+            case DOMAIN_NAME:
+                int len = in.read();
+                addr = new byte[len];
+                readSocksReply(in, addr);
+                nport = in.read() << 8;
+                nport += in.read();
+                real_end = new InetSocketAddress(new String(addr), nport);
+                break;
+            case IPV6:
+                addr = new byte[16];
+                readSocksReply(in, addr);
+                nport = in.read() << 8;
+                nport += in.read();
+                real_end =
+                    new InetSocketAddress(new Inet6Address("", addr), nport);
+                break;
+            }
+            break;
+        case GENERAL_FAILURE:
+            ex = new SocketException("SOCKS server general failure");
+            break;
+        case NOT_ALLOWED:
+            ex = new SocketException("SOCKS: Accept not allowed by ruleset");
+            break;
+        case NET_UNREACHABLE:
+            ex = new SocketException("SOCKS: Network unreachable");
+            break;
+        case HOST_UNREACHABLE:
+            ex = new SocketException("SOCKS: Host unreachable");
+            break;
+        case CONN_REFUSED:
+            ex = new SocketException("SOCKS: Connection refused");
+            break;
+        case TTL_EXPIRED:
+            ex =  new SocketException("SOCKS: TTL expired");
+            break;
+        case CMD_NOT_SUPPORTED:
+            ex = new SocketException("SOCKS: Command not supported");
+            break;
+        case ADDR_TYPE_NOT_SUP:
+            ex = new SocketException("SOCKS: address type not supported");
+            break;
+        }
+        if (ex != null) {
+            cmdIn.close();
+            cmdOut.close();
+            cmdsock.close();
+            cmdsock = null;
+            throw ex;
+        }
+
+        /**
+         * This is where we have to do some fancy stuff.
+         * The datastream from the socket "accepted" by the proxy will
+         * come through the cmdSocket. So we have to swap the socketImpls
+         *
+        if (s instanceof SocksSocketImpl) {
+            ((SocksSocketImpl)s).external_address = real_end;
+        }
+        if (s instanceof PlainSocketImpl) {
+            PlainSocketImpl psi = (PlainSocketImpl) s;
+            psi.setInputStream((SocketInputStream) in);
+            psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor());
+            psi.setAddress(cmdsock.getImpl().getInetAddress());
+            psi.setPort(cmdsock.getImpl().getPort());
+            psi.setLocalPort(cmdsock.getImpl().getLocalPort());
+        } else {
+            s.fd = cmdsock.getImpl().fd;
+            s.address = cmdsock.getImpl().address;
+            s.port = cmdsock.getImpl().port;
+            s.localport = cmdsock.getImpl().localport;
+        }
+
+        // Need to do that so that the socket won't be closed
+        // when the ServerSocket is closed by the user.
+        // It kinds of detaches the Socket because it is now
+        // used elsewhere.
+        cmdsock = null;
+    }
+    */
+
+    /**
+     * Returns the value of this socket's {@code address} field.
+     *
+     * @return  the value of this socket's {@code address} field.
+     * @see     java.net.SocketImpl#address
+     */
+    @Override
+    protected InetAddress getInetAddress() {
+        if (external_address != null)
+            return external_address.getAddress();
+        else
+            return super.getInetAddress();
+    }
+
+    /**
+     * Returns the value of this socket's {@code port} field.
+     *
+     * @return  the value of this socket's {@code port} field.
+     * @see     java.net.SocketImpl#port
+     */
+    @Override
+    protected int getPort() {
+        if (external_address != null)
+            return external_address.getPort();
+        else
+            return super.getPort();
+    }
+
+    @Override
+    protected int getLocalPort() {
+        if (socket != null)
+            return super.getLocalPort();
+        if (external_address != null)
+            return external_address.getPort();
+        else
+            return super.getLocalPort();
+    }
+
+    @Override
+    protected void close() throws IOException {
+        if (cmdsock != null)
+            cmdsock.close();
+        cmdsock = null;
+        super.close();
+    }
+
+    private String getUserName() {
+        String userName = "";
+        if (applicationSetProxy) {
+            try {
+                userName = System.getProperty("user.name");
+            } catch (SecurityException se) { /* swallow Exception */ }
+        } else {
+            userName = java.security.AccessController.doPrivileged(
+                new sun.security.action.GetPropertyAction("user.name"));
+        }
+        return userName;
+    }
+}
diff --git a/java/net/StandardProtocolFamily.java b/java/net/StandardProtocolFamily.java
new file mode 100644
index 0000000..25aaed4
--- /dev/null
+++ b/java/net/StandardProtocolFamily.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Defines the standard families of communication protocols.
+ *
+ * @since 1.7
+ */
+
+public enum StandardProtocolFamily implements ProtocolFamily {
+
+    /**
+     * Internet Protocol Version 4 (IPv4)
+     */
+    INET,
+
+    /**
+     * Internet Protocol Version 6 (IPv6)
+     */
+    INET6
+}
diff --git a/java/net/StandardSocketOptions.java b/java/net/StandardSocketOptions.java
new file mode 100644
index 0000000..7fdd5f0
--- /dev/null
+++ b/java/net/StandardSocketOptions.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * Defines the <em>standard</em> socket options.
+ *
+ * <p> The {@link SocketOption#name name} of each socket option defined by this
+ * class is its field name.
+ *
+ * <p> In this release, the socket options defined here are used by {@link
+ * java.nio.channels.NetworkChannel network} channels in the {@link
+ * java.nio.channels channels} package.
+ *
+ * @since 1.7
+ */
+
+public final class StandardSocketOptions {
+    private StandardSocketOptions() { }
+
+    // -- SOL_SOCKET --
+
+    /**
+     * Allow transmission of broadcast datagrams.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The option is specific to
+     * datagram-oriented sockets sending to {@link java.net.Inet4Address IPv4}
+     * broadcast addresses. When the socket option is enabled then the socket
+     * can be used to send <em>broadcast datagrams</em>.
+     *
+     * <p> The initial value of this socket option is {@code FALSE}. The socket
+     * option may be enabled or disabled at any time. Some operating systems may
+     * require that the Java virtual machine be started with implementation
+     * specific privileges to enable this option or send broadcast datagrams.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc919.txt">RFC&nbsp;929:
+     * Broadcasting Internet Datagrams</a>
+     * @see DatagramSocket#setBroadcast
+     */
+    public static final SocketOption<Boolean> SO_BROADCAST =
+        new StdSocketOption<Boolean>("SO_BROADCAST", Boolean.class);
+
+    /**
+     * Keep connection alive.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. When the {@code SO_KEEPALIVE}
+     * option is enabled the operating system may use a <em>keep-alive</em>
+     * mechanism to periodically probe the other end of a connection when the
+     * connection is otherwise idle. The exact semantics of the keep alive
+     * mechanism is system dependent and therefore unspecified.
+     *
+     * <p> The initial value of this socket option is {@code FALSE}. The socket
+     * option may be enabled or disabled at any time.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122
+     * Requirements for Internet Hosts -- Communication Layers</a>
+     * @see Socket#setKeepAlive
+     */
+    public static final SocketOption<Boolean> SO_KEEPALIVE =
+        new StdSocketOption<Boolean>("SO_KEEPALIVE", Boolean.class);
+
+    /**
+     * The size of the socket send buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket send buffer in bytes. The socket send buffer is an
+     * output buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections. The value of the socket option is
+     * a <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ. The socket option can be queried to retrieve the actual
+     * size.
+     *
+     * <p> For datagram-oriented sockets, the size of the send buffer may limit
+     * the size of the datagrams that may be sent by the socket. Whether
+     * datagrams larger than the buffer size are sent or discarded is system
+     * dependent.
+     *
+     * <p> The initial/default size of the socket send buffer and the range of
+     * allowable values is system dependent although a negative size is not
+     * allowed. An attempt to set the socket send buffer to larger than its
+     * maximum size causes it to be set to its maximum size.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket send buffer to be changed after the socket is bound is system
+     * dependent.
+     *
+     * @see Socket#setSendBufferSize
+     */
+    public static final SocketOption<Integer> SO_SNDBUF =
+        new StdSocketOption<Integer>("SO_SNDBUF", Integer.class);
+
+
+    /**
+     * The size of the socket receive buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket receive buffer in bytes. The socket receive buffer is
+     * an input buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections or decreased to limit the possible
+     * backlog of incoming data. The value of the socket option is a
+     * <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ.
+     *
+     * <p> For datagram-oriented sockets, the size of the receive buffer may
+     * limit the size of the datagrams that can be received. Whether datagrams
+     * larger than the buffer size can be received is system dependent.
+     * Increasing the socket receive buffer may be important for cases where
+     * datagrams arrive in bursts faster than they can be processed.
+     *
+     * <p> In the case of stream-oriented sockets and the TCP/IP protocol, the
+     * size of the socket receive buffer may be used when advertising the size
+     * of the TCP receive window to the remote peer.
+     *
+     * <p> The initial/default size of the socket receive buffer and the range
+     * of allowable values is system dependent although a negative size is not
+     * allowed. An attempt to set the socket receive buffer to larger than its
+     * maximum size causes it to be set to its maximum size.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket receive buffer to be changed after the socket is bound is system
+     * dependent.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1323.txt">RFC&nbsp;1323: TCP
+     * Extensions for High Performance</a>
+     * @see Socket#setReceiveBufferSize
+     * @see ServerSocket#setReceiveBufferSize
+     */
+    public static final SocketOption<Integer> SO_RCVBUF =
+        new StdSocketOption<Integer>("SO_RCVBUF", Integer.class);
+
+    /**
+     * Re-use address.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The exact semantics of this
+     * socket option are socket type and system dependent.
+     *
+     * <p> In the case of stream-oriented sockets, this socket option will
+     * usually determine whether the socket can be bound to a socket address
+     * when a previous connection involving that socket address is in the
+     * <em>TIME_WAIT</em> state. On implementations where the semantics differ,
+     * and the socket option is not required to be enabled in order to bind the
+     * socket when a previous connection is in this state, then the
+     * implementation may choose to ignore this option.
+     *
+     * <p> For datagram-oriented sockets the socket option is used to allow
+     * multiple programs bind to the same address. This option should be enabled
+     * when the socket is to be used for Internet Protocol (IP) multicasting.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Changing the value of this socket option
+     * after the socket is bound has no effect. The default value of this
+     * socket option is system dependent.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc793.txt">RFC&nbsp;793: Transmission
+     * Control Protocol</a>
+     * @see ServerSocket#setReuseAddress
+     */
+    public static final SocketOption<Boolean> SO_REUSEADDR =
+        new StdSocketOption<Boolean>("SO_REUSEADDR", Boolean.class);
+
+    /**
+     * Linger on close if data is present.
+     *
+     * <p> The value of this socket option is an {@code Integer} that controls
+     * the action taken when unsent data is queued on the socket and a method
+     * to close the socket is invoked. If the value of the socket option is zero
+     * or greater, then it represents a timeout value, in seconds, known as the
+     * <em>linger interval</em>. The linger interval is the timeout for the
+     * {@code close} method to block while the operating system attempts to
+     * transmit the unsent data or it decides that it is unable to transmit the
+     * data. If the value of the socket option is less than zero then the option
+     * is disabled. In that case the {@code close} method does not wait until
+     * unsent data is transmitted; if possible the operating system will transmit
+     * any unsent data before the connection is closed.
+     *
+     * <p> This socket option is intended for use with sockets that are configured
+     * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode
+     * only. The behavior of the {@code close} method when this option is
+     * enabled on a non-blocking socket is not defined.
+     *
+     * <p> The initial value of this socket option is a negative value, meaning
+     * that the option is disabled. The option may be enabled, or the linger
+     * interval changed, at any time. The maximum value of the linger interval
+     * is system dependent. Setting the linger interval to a value that is
+     * greater than its maximum value causes the linger interval to be set to
+     * its maximum value.
+     *
+     * @see Socket#setSoLinger
+     */
+    public static final SocketOption<Integer> SO_LINGER =
+        new StdSocketOption<Integer>("SO_LINGER", Integer.class);
+
+
+    // -- IPPROTO_IP --
+
+    /**
+     * The Type of Service (ToS) octet in the Internet Protocol (IP) header.
+     *
+     * <p> The value of this socket option is an {@code Integer} representing
+     * the value of the ToS octet in IP packets sent by sockets to an {@link
+     * StandardProtocolFamily#INET IPv4} socket. The interpretation of the ToS
+     * octet is network specific and is not defined by this class. Further
+     * information on the ToS octet can be found in <a
+     * href="http://www.ietf.org/rfc/rfc1349.txt">RFC&nbsp;1349</a> and <a
+     * href="http://www.ietf.org/rfc/rfc2474.txt">RFC&nbsp;2474</a>. The value
+     * of the socket option is a <em>hint</em>. An implementation may ignore the
+     * value, or ignore specific values.
+     *
+     * <p> The initial/default value of the TOS field in the ToS octet is
+     * implementation specific but will typically be {@code 0}. For
+     * datagram-oriented sockets the option may be configured at any time after
+     * the socket has been bound. The new value of the octet is used when sending
+     * subsequent datagrams. It is system dependent whether this option can be
+     * queried or changed prior to binding the socket.
+     *
+     * <p> The behavior of this socket option on a stream-oriented socket, or an
+     * {@link StandardProtocolFamily#INET6 IPv6} socket, is not defined in this
+     * release.
+     *
+     * @see DatagramSocket#setTrafficClass
+     */
+    public static final SocketOption<Integer> IP_TOS =
+        new StdSocketOption<Integer>("IP_TOS", Integer.class);
+
+    /**
+     * The network interface for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is a {@link NetworkInterface} that
+     * represents the outgoing interface for multicast datagrams sent by the
+     * datagram-oriented socket. For {@link StandardProtocolFamily#INET6 IPv6}
+     * sockets then it is system dependent whether setting this option also
+     * sets the outgoing interface for multicast datagrams sent to IPv4
+     * addresses.
+     *
+     * <p> The initial/default value of this socket option may be {@code null}
+     * to indicate that outgoing interface will be selected by the operating
+     * system, typically based on the network routing tables. An implementation
+     * allows this socket option to be set after the socket is bound. Whether
+     * the socket option can be queried or changed prior to binding the socket
+     * is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     * @see MulticastSocket#setInterface
+     */
+    public static final SocketOption<NetworkInterface> IP_MULTICAST_IF =
+        new StdSocketOption<NetworkInterface>("IP_MULTICAST_IF", NetworkInterface.class);
+
+    /**
+     * The <em>time-to-live</em> for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is an {@code Integer} in the range
+     * {@code 0 <= value <= 255}. It is used to control the scope of multicast
+     * datagrams sent by the datagram-oriented socket.
+     * In the case of an {@link StandardProtocolFamily#INET IPv4} socket
+     * the option is the time-to-live (TTL) on multicast datagrams sent by the
+     * socket. Datagrams with a TTL of zero are not transmitted on the network
+     * but may be delivered locally. In the case of an {@link
+     * StandardProtocolFamily#INET6 IPv6} socket the option is the
+     * <em>hop limit</em> which is number of <em>hops</em> that the datagram can
+     * pass through before expiring on the network. For IPv6 sockets it is
+     * system dependent whether the option also sets the <em>time-to-live</em>
+     * on multicast datagrams sent to IPv4 addresses.
+     *
+     * <p> The initial/default value of the time-to-live setting is typically
+     * {@code 1}. An implementation allows this socket option to be set after
+     * the socket is bound. Whether the socket option can be queried or changed
+     * prior to binding the socket is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     * @see MulticastSocket#setTimeToLive
+     */
+    public static final SocketOption<Integer> IP_MULTICAST_TTL =
+        new StdSocketOption<Integer>("IP_MULTICAST_TTL", Integer.class);
+
+    /**
+     * Loopback for Internet Protocol (IP) multicast datagrams.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that controls
+     * the <em>loopback</em> of multicast datagrams. The value of the socket
+     * option represents if the option is enabled or disabled.
+     *
+     * <p> The exact semantics of this socket options are system dependent.
+     * In particular, it is system dependent whether the loopback applies to
+     * multicast datagrams sent from the socket or received by the socket.
+     * For {@link StandardProtocolFamily#INET6 IPv6} sockets then it is
+     * system dependent whether the option also applies to multicast datagrams
+     * sent to IPv4 addresses.
+     *
+     * <p> The initial/default value of this socket option is {@code TRUE}. An
+     * implementation allows this socket option to be set after the socket is
+     * bound. Whether the socket option can be queried or changed prior to
+     * binding the socket is system dependent.
+     *
+     * @see java.nio.channels.MulticastChannel
+     *  @see MulticastSocket#setLoopbackMode
+     */
+    public static final SocketOption<Boolean> IP_MULTICAST_LOOP =
+        new StdSocketOption<Boolean>("IP_MULTICAST_LOOP", Boolean.class);
+
+
+    // -- IPPROTO_TCP --
+
+    /**
+     * Disable the Nagle algorithm.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. The socket option is specific to
+     * stream-oriented sockets using the TCP/IP protocol. TCP/IP uses an algorithm
+     * known as <em>The Nagle Algorithm</em> to coalesce short segments and
+     * improve network efficiency.
+     *
+     * <p> The default value of this socket option is {@code FALSE}. The
+     * socket option should only be enabled in cases where it is known that the
+     * coalescing impacts performance. The socket option may be enabled at any
+     * time. In other words, the Nagle Algorithm can be disabled. Once the option
+     * is enabled, it is system dependent whether it can be subsequently
+     * disabled. If it cannot, then invoking the {@code setOption} method to
+     * disable the option has no effect.
+     *
+     * @see <a href="http://www.ietf.org/rfc/rfc1122.txt">RFC&nbsp;1122:
+     * Requirements for Internet Hosts -- Communication Layers</a>
+     * @see Socket#setTcpNoDelay
+     */
+    public static final SocketOption<Boolean> TCP_NODELAY =
+        new StdSocketOption<Boolean>("TCP_NODELAY", Boolean.class);
+
+
+    private static class StdSocketOption<T> implements SocketOption<T> {
+        private final String name;
+        private final Class<T> type;
+        StdSocketOption(String name, Class<T> type) {
+            this.name = name;
+            this.type = type;
+        }
+        @Override public String name() { return name; }
+        @Override public Class<T> type() { return type; }
+        @Override public String toString() { return name; }
+    }
+}
diff --git a/java/net/URI.java b/java/net/URI.java
new file mode 100644
index 0000000..ebba41b
--- /dev/null
+++ b/java/net/URI.java
@@ -0,0 +1,3602 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.CharacterCodingException;
+import java.text.Normalizer;
+import sun.nio.cs.ThreadLocalCoders;
+
+import java.lang.Character;             // for javadoc
+import java.lang.NullPointerException;  // for javadoc
+
+
+// Android-changed: Reformat @see links.
+/**
+ * Represents a Uniform Resource Identifier (URI) reference.
+ *
+ * <p> Aside from some minor deviations noted below, an instance of this
+ * class represents a URI reference as defined by
+ * <a href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
+ * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
+ * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
+ * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
+ * also supports scope_ids. The syntax and usage of scope_ids is described
+ * <a href="Inet6Address.html#scoped">here</a>.
+ * This class provides constructors for creating URI instances from
+ * their components or by parsing their string forms, methods for accessing the
+ * various components of an instance, and methods for normalizing, resolving,
+ * and relativizing URI instances.  Instances of this class are immutable.
+ *
+ *
+ * <h3> URI syntax and components </h3>
+ *
+ * At the highest level a URI reference (hereinafter simply "URI") in string
+ * form has the syntax
+ *
+ * <blockquote>
+ * [<i>scheme</i><b>{@code :}</b>]<i>scheme-specific-part</i>[<b>{@code #}</b><i>fragment</i>]
+ * </blockquote>
+ *
+ * where square brackets [...] delineate optional components and the characters
+ * <b>{@code :}</b> and <b>{@code #}</b> stand for themselves.
+ *
+ * <p> An <i>absolute</i> URI specifies a scheme; a URI that is not absolute is
+ * said to be <i>relative</i>.  URIs are also classified according to whether
+ * they are <i>opaque</i> or <i>hierarchical</i>.
+ *
+ * <p> An <i>opaque</i> URI is an absolute URI whose scheme-specific part does
+ * not begin with a slash character ({@code '/'}).  Opaque URIs are not
+ * subject to further parsing.  Some examples of opaque URIs are:
+ *
+ * <blockquote><table cellpadding=0 cellspacing=0 summary="layout">
+ * <tr><td>{@code mailto:[email protected]}<td></tr>
+ * <tr><td>{@code news:comp.lang.java}<td></tr>
+ * <tr><td>{@code urn:isbn:096139210x}</td></tr>
+ * </table></blockquote>
+ *
+ * <p> A <i>hierarchical</i> URI is either an absolute URI whose
+ * scheme-specific part begins with a slash character, or a relative URI, that
+ * is, a URI that does not specify a scheme.  Some examples of hierarchical
+ * URIs are:
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/}<br>
+ * {@code docs/guide/collections/designfaq.html#28}<br>
+ * {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java}<br>
+ * {@code file:///~/calendar}
+ * </blockquote>
+ *
+ * <p> A hierarchical URI is subject to further parsing according to the syntax
+ *
+ * <blockquote>
+ * [<i>scheme</i><b>{@code :}</b>][<b>{@code //}</b><i>authority</i>][<i>path</i>][<b>{@code ?}</b><i>query</i>][<b>{@code #}</b><i>fragment</i>]
+ * </blockquote>
+ *
+ * where the characters <b>{@code :}</b>, <b>{@code /}</b>,
+ * <b>{@code ?}</b>, and <b>{@code #}</b> stand for themselves.  The
+ * scheme-specific part of a hierarchical URI consists of the characters
+ * between the scheme and fragment components.
+ *
+ * <p> The authority component of a hierarchical URI is, if specified, either
+ * <i>server-based</i> or <i>registry-based</i>.  A server-based authority
+ * parses according to the familiar syntax
+ *
+ * <blockquote>
+ * [<i>user-info</i><b>{@code @}</b>]<i>host</i>[<b>{@code :}</b><i>port</i>]
+ * </blockquote>
+ *
+ * where the characters <b>{@code @}</b> and <b>{@code :}</b> stand for
+ * themselves.  Nearly all URI schemes currently in use are server-based.  An
+ * authority component that does not parse in this way is considered to be
+ * registry-based.
+ *
+ * <p> The path component of a hierarchical URI is itself said to be absolute
+ * if it begins with a slash character ({@code '/'}); otherwise it is
+ * relative.  The path of a hierarchical URI that is either absolute or
+ * specifies an authority is always absolute.
+ *
+ * <p> All told, then, a URI instance has the following nine components:
+ *
+ * <blockquote><table summary="Describes the components of a URI:scheme,scheme-specific-part,authority,user-info,host,port,path,query,fragment">
+ * <tr><th><i>Component</i></th><th><i>Type</i></th></tr>
+ * <tr><td>scheme</td><td>{@code String}</td></tr>
+ * <tr><td>scheme-specific-part&nbsp;&nbsp;&nbsp;&nbsp;</td><td>{@code String}</td></tr>
+ * <tr><td>authority</td><td>{@code String}</td></tr>
+ * <tr><td>user-info</td><td>{@code String}</td></tr>
+ * <tr><td>host</td><td>{@code String}</td></tr>
+ * <tr><td>port</td><td>{@code int}</td></tr>
+ * <tr><td>path</td><td>{@code String}</td></tr>
+ * <tr><td>query</td><td>{@code String}</td></tr>
+ * <tr><td>fragment</td><td>{@code String}</td></tr>
+ * </table></blockquote>
+ *
+ * In a given instance any particular component is either <i>undefined</i> or
+ * <i>defined</i> with a distinct value.  Undefined string components are
+ * represented by {@code null}, while undefined integer components are
+ * represented by {@code -1}.  A string component may be defined to have the
+ * empty string as its value; this is not equivalent to that component being
+ * undefined.
+ *
+ * <p> Whether a particular component is or is not defined in an instance
+ * depends upon the type of the URI being represented.  An absolute URI has a
+ * scheme component.  An opaque URI has a scheme, a scheme-specific part, and
+ * possibly a fragment, but has no other components.  A hierarchical URI always
+ * has a path (though it may be empty) and a scheme-specific-part (which at
+ * least contains the path), and may have any of the other components.  If the
+ * authority component is present and is server-based then the host component
+ * will be defined and the user-information and port components may be defined.
+ *
+ *
+ * <h4> Operations on URI instances </h4>
+ *
+ * The key operations supported by this class are those of
+ * <i>normalization</i>, <i>resolution</i>, and <i>relativization</i>.
+ *
+ * <p> <i>Normalization</i> is the process of removing unnecessary {@code "."}
+ * and {@code ".."} segments from the path component of a hierarchical URI.
+ * Each {@code "."} segment is simply removed.  A {@code ".."} segment is
+ * removed only if it is preceded by a non-{@code ".."} segment.
+ * Normalization has no effect upon opaque URIs.
+ *
+ * <p> <i>Resolution</i> is the process of resolving one URI against another,
+ * <i>base</i> URI.  The resulting URI is constructed from components of both
+ * URIs in the manner specified by RFC&nbsp;2396, taking components from the
+ * base URI for those not specified in the original.  For hierarchical URIs,
+ * the path of the original is resolved against the path of the base and then
+ * normalized.  The result, for example, of resolving
+ *
+ * <blockquote>
+ * {@code docs/guide/collections/designfaq.html#28}
+ * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ * &nbsp;&nbsp;&nbsp;&nbsp;(1)
+ * </blockquote>
+ *
+ * against the base URI {@code http://java.sun.com/j2se/1.3/} is the result
+ * URI
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/docs/guide/collections/designfaq.html#28}
+ * </blockquote>
+ *
+ * Resolving the relative URI
+ *
+ * <blockquote>
+ * {@code ../../../demo/jfc/SwingSet2/src/SwingSet2.java}&nbsp;&nbsp;&nbsp;&nbsp;(2)
+ * </blockquote>
+ *
+ * against this result yields, in turn,
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/demo/jfc/SwingSet2/src/SwingSet2.java}
+ * </blockquote>
+ *
+ * Resolution of both absolute and relative URIs, and of both absolute and
+ * relative paths in the case of hierarchical URIs, is supported.  Resolving
+ * the URI {@code file:///~calendar} against any other URI simply yields the
+ * original URI, since it is absolute.  Resolving the relative URI (2) above
+ * against the relative base URI (1) yields the normalized, but still relative,
+ * URI
+ *
+ * <blockquote>
+ * {@code demo/jfc/SwingSet2/src/SwingSet2.java}
+ * </blockquote>
+ *
+ * <p> <i>Relativization</i>, finally, is the inverse of resolution: For any
+ * two normalized URIs <i>u</i> and&nbsp;<i>v</i>,
+ *
+ * <blockquote>
+ *   <i>u</i>{@code .relativize(}<i>u</i>{@code .resolve(}<i>v</i>{@code )).equals(}<i>v</i>{@code )}&nbsp;&nbsp;and<br>
+ *   <i>u</i>{@code .resolve(}<i>u</i>{@code .relativize(}<i>v</i>{@code )).equals(}<i>v</i>{@code )}&nbsp;&nbsp;.<br>
+ * </blockquote>
+ *
+ * This operation is often useful when constructing a document containing URIs
+ * that must be made relative to the base URI of the document wherever
+ * possible.  For example, relativizing the URI
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3/docs/guide/index.html}
+ * </blockquote>
+ *
+ * against the base URI
+ *
+ * <blockquote>
+ * {@code http://java.sun.com/j2se/1.3}
+ * </blockquote>
+ *
+ * yields the relative URI {@code docs/guide/index.html}.
+ *
+ *
+ * <h4> Character categories </h4>
+ *
+ * RFC&nbsp;2396 specifies precisely which characters are permitted in the
+ * various components of a URI reference.  The following categories, most of
+ * which are taken from that specification, are used below to describe these
+ * constraints:
+ *
+ * <blockquote><table cellspacing=2 summary="Describes categories alpha,digit,alphanum,unreserved,punct,reserved,escaped,and other">
+ *   <tr><th valign=top><i>alpha</i></th>
+ *       <td>The US-ASCII alphabetic characters,
+ *        {@code 'A'}&nbsp;through&nbsp;{@code 'Z'}
+ *        and {@code 'a'}&nbsp;through&nbsp;{@code 'z'}</td></tr>
+ *   <tr><th valign=top><i>digit</i></th>
+ *       <td>The US-ASCII decimal digit characters,
+ *       {@code '0'}&nbsp;through&nbsp;{@code '9'}</td></tr>
+ *   <tr><th valign=top><i>alphanum</i></th>
+ *       <td>All <i>alpha</i> and <i>digit</i> characters</td></tr>
+ *   <tr><th valign=top><i>unreserved</i>&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *       <td>All <i>alphanum</i> characters together with those in the string
+ *        {@code "_-!.~'()*"}</td></tr>
+ *   <tr><th valign=top><i>punct</i></th>
+ *       <td>The characters in the string {@code ",;:$&+="}</td></tr>
+ *   <tr><th valign=top><i>reserved</i></th>
+ *       <td>All <i>punct</i> characters together with those in the string
+ *        {@code "?/[]@"}</td></tr>
+ *   <tr><th valign=top><i>escaped</i></th>
+ *       <td>Escaped octets, that is, triplets consisting of the percent
+ *           character ({@code '%'}) followed by two hexadecimal digits
+ *           ({@code '0'}-{@code '9'}, {@code 'A'}-{@code 'F'}, and
+ *           {@code 'a'}-{@code 'f'})</td></tr>
+ *   <tr><th valign=top><i>other</i></th>
+ *       <td>The Unicode characters that are not in the US-ASCII character set,
+ *           are not control characters (according to the {@link
+ *           java.lang.Character#isISOControl(char) Character.isISOControl}
+ *           method), and are not space characters (according to the {@link
+ *           java.lang.Character#isSpaceChar(char) Character.isSpaceChar}
+ *           method)&nbsp;&nbsp;<i>(<b>Deviation from RFC 2396</b>, which is
+ *           limited to US-ASCII)</i></td></tr>
+ * </table></blockquote>
+ *
+ * <p><a name="legal-chars"></a> The set of all legal URI characters consists of
+ * the <i>unreserved</i>, <i>reserved</i>, <i>escaped</i>, and <i>other</i>
+ * characters.
+ *
+ *
+ * <h4> Escaped octets, quotation, encoding, and decoding </h4>
+ *
+ * RFC 2396 allows escaped octets to appear in the user-info, path, query, and
+ * fragment components.  Escaping serves two purposes in URIs:
+ *
+ * <ul>
+ *
+ *   <li><p> To <i>encode</i> non-US-ASCII characters when a URI is required to
+ *   conform strictly to RFC&nbsp;2396 by not containing any <i>other</i>
+ *   characters.  </p></li>
+ *
+ *   <li><p> To <i>quote</i> characters that are otherwise illegal in a
+ *   component.  The user-info, path, query, and fragment components differ
+ *   slightly in terms of which characters are considered legal and illegal.
+ *   </p></li>
+ *
+ * </ul>
+ *
+ * These purposes are served in this class by three related operations:
+ *
+ * <ul>
+ *
+ *   <li><p><a name="encode"></a> A character is <i>encoded</i> by replacing it
+ *   with the sequence of escaped octets that represent that character in the
+ *   UTF-8 character set.  The Euro currency symbol ({@code '\u005Cu20AC'}),
+ *   for example, is encoded as {@code "%E2%82%AC"}.  <i>(<b>Deviation from
+ *   RFC&nbsp;2396</b>, which does not specify any particular character
+ *   set.)</i> </p></li>
+ *
+ *   <li><p><a name="quote"></a> An illegal character is <i>quoted</i> simply by
+ *   encoding it.  The space character, for example, is quoted by replacing it
+ *   with {@code "%20"}.  UTF-8 contains US-ASCII, hence for US-ASCII
+ *   characters this transformation has exactly the effect required by
+ *   RFC&nbsp;2396. </p></li>
+ *
+ *   <li><p><a name="decode"></a>
+ *   A sequence of escaped octets is <i>decoded</i> by
+ *   replacing it with the sequence of characters that it represents in the
+ *   UTF-8 character set.  UTF-8 contains US-ASCII, hence decoding has the
+ *   effect of de-quoting any quoted US-ASCII characters as well as that of
+ *   decoding any encoded non-US-ASCII characters.  If a <a
+ *   href="../nio/charset/CharsetDecoder.html#ce">decoding error</a> occurs
+ *   when decoding the escaped octets then the erroneous octets are replaced by
+ *   {@code '\u005CuFFFD'}, the Unicode replacement character.  </p></li>
+ *
+ * </ul>
+ *
+ * These operations are exposed in the constructors and methods of this class
+ * as follows:
+ *
+ * <ul>
+ *
+ *   <li><p> The {@linkplain #URI(java.lang.String) single-argument
+ *   constructor} requires any illegal characters in its argument to be
+ *   quoted and preserves any escaped octets and <i>other</i> characters that
+ *   are present.  </p></li>
+ *
+ *   <li><p> The {@linkplain
+ *   #URI(java.lang.String,java.lang.String,java.lang.String,int,java.lang.String,java.lang.String,java.lang.String)
+ *   multi-argument constructors} quote illegal characters as
+ *   required by the components in which they appear.  The percent character
+ *   ({@code '%'}) is always quoted by these constructors.  Any <i>other</i>
+ *   characters are preserved.  </p></li>
+ *
+ *   <li><p> The {@link #getRawUserInfo() getRawUserInfo}, {@link #getRawPath()
+ *   getRawPath}, {@link #getRawQuery() getRawQuery}, {@link #getRawFragment()
+ *   getRawFragment}, {@link #getRawAuthority() getRawAuthority}, and {@link
+ *   #getRawSchemeSpecificPart() getRawSchemeSpecificPart} methods return the
+ *   values of their corresponding components in raw form, without interpreting
+ *   any escaped octets.  The strings returned by these methods may contain
+ *   both escaped octets and <i>other</i> characters, and will not contain any
+ *   illegal characters.  </p></li>
+ *
+ *   <li><p> The {@link #getUserInfo() getUserInfo}, {@link #getPath()
+ *   getPath}, {@link #getQuery() getQuery}, {@link #getFragment()
+ *   getFragment}, {@link #getAuthority() getAuthority}, and {@link
+ *   #getSchemeSpecificPart() getSchemeSpecificPart} methods decode any escaped
+ *   octets in their corresponding components.  The strings returned by these
+ *   methods may contain both <i>other</i> characters and illegal characters,
+ *   and will not contain any escaped octets.  </p></li>
+ *
+ *   <li><p> The {@link #toString() toString} method returns a URI string with
+ *   all necessary quotation but which may contain <i>other</i> characters.
+ *   </p></li>
+ *
+ *   <li><p> The {@link #toASCIIString() toASCIIString} method returns a fully
+ *   quoted and encoded URI string that does not contain any <i>other</i>
+ *   characters.  </p></li>
+ *
+ * </ul>
+ *
+ *
+ * <h4> Identities </h4>
+ *
+ * For any URI <i>u</i>, it is always the case that
+ *
+ * <blockquote>
+ * {@code new URI(}<i>u</i>{@code .toString()).equals(}<i>u</i>{@code )}&nbsp;.
+ * </blockquote>
+ *
+ * For any URI <i>u</i> that does not contain redundant syntax such as two
+ * slashes before an empty authority (as in {@code file:///tmp/}&nbsp;) or a
+ * colon following a host name but no port (as in
+ * {@code http://java.sun.com:}&nbsp;), and that does not encode characters
+ * except those that must be quoted, the following identities also hold:
+ * <pre>
+ *     new URI(<i>u</i>.getScheme(),
+ *             <i>u</i>.getSchemeSpecificPart(),
+ *             <i>u</i>.getFragment())
+ *     .equals(<i>u</i>)</pre>
+ * in all cases,
+ * <pre>
+ *     new URI(<i>u</i>.getScheme(),
+ *             <i>u</i>.getUserInfo(), <i>u</i>.getAuthority(),
+ *             <i>u</i>.getPath(), <i>u</i>.getQuery(),
+ *             <i>u</i>.getFragment())
+ *     .equals(<i>u</i>)</pre>
+ * if <i>u</i> is hierarchical, and
+ * <pre>
+ *     new URI(<i>u</i>.getScheme(),
+ *             <i>u</i>.getUserInfo(), <i>u</i>.getHost(), <i>u</i>.getPort(),
+ *             <i>u</i>.getPath(), <i>u</i>.getQuery(),
+ *             <i>u</i>.getFragment())
+ *     .equals(<i>u</i>)</pre>
+ * if <i>u</i> is hierarchical and has either no authority or a server-based
+ * authority.
+ *
+ *
+ * <h4> URIs, URLs, and URNs </h4>
+ *
+ * A URI is a uniform resource <i>identifier</i> while a URL is a uniform
+ * resource <i>locator</i>.  Hence every URL is a URI, abstractly speaking, but
+ * not every URI is a URL.  This is because there is another subcategory of
+ * URIs, uniform resource <i>names</i> (URNs), which name resources but do not
+ * specify how to locate them.  The {@code mailto}, {@code news}, and
+ * {@code isbn} URIs shown above are examples of URNs.
+ *
+ * <p> The conceptual distinction between URIs and URLs is reflected in the
+ * differences between this class and the {@link URL} class.
+ *
+ * <p> An instance of this class represents a URI reference in the syntactic
+ * sense defined by RFC&nbsp;2396.  A URI may be either absolute or relative.
+ * A URI string is parsed according to the generic syntax without regard to the
+ * scheme, if any, that it specifies.  No lookup of the host, if any, is
+ * performed, and no scheme-dependent stream handler is constructed.  Equality,
+ * hashing, and comparison are defined strictly in terms of the character
+ * content of the instance.  In other words, a URI instance is little more than
+ * a structured string that supports the syntactic, scheme-independent
+ * operations of comparison, normalization, resolution, and relativization.
+ *
+ * <p> An instance of the {@link URL} class, by contrast, represents the
+ * syntactic components of a URL together with some of the information required
+ * to access the resource that it describes.  A URL must be absolute, that is,
+ * it must always specify a scheme.  A URL string is parsed according to its
+ * scheme.  A stream handler is always established for a URL, and in fact it is
+ * impossible to create a URL instance for a scheme for which no handler is
+ * available.  Equality and hashing depend upon both the scheme and the
+ * Internet address of the host, if any; comparison is not defined.  In other
+ * words, a URL is a structured string that supports the syntactic operation of
+ * resolution as well as the network I/O operations of looking up the host and
+ * opening a connection to the specified resource.
+ *
+ *
+ * @author Mark Reinhold
+ * @since 1.4
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2279.txt">RFC&nbsp;2279: UTF-8, a transformation format of ISO 10646</a>
+ * @see <a href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373: IPv6 Addressing Architecture</a>
+ * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396: Uniform Resource Identifiers (URI): Generic Syntax</a>
+ * @see <a href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732: Format for Literal IPv6 Addresses in URLs</a>
+ */
+
+public final class URI
+    implements Comparable<URI>, Serializable
+{
+
+    // Note: Comments containing the word "ASSERT" indicate places where a
+    // throw of an InternalError should be replaced by an appropriate assertion
+    // statement once asserts are enabled in the build.
+
+    static final long serialVersionUID = -6052424284110960213L;
+
+
+    // -- Properties and components of this instance --
+
+    // Components of all URIs: [<scheme>:]<scheme-specific-part>[#<fragment>]
+    private transient String scheme;            // null ==> relative URI
+    private transient String fragment;
+
+    // Hierarchical URI components: [//<authority>]<path>[?<query>]
+    private transient String authority;         // Registry or server
+
+    // Server-based authority: [<userInfo>@]<host>[:<port>]
+    private transient String userInfo;
+    private transient String host;              // null ==> registry-based
+    private transient int port = -1;            // -1 ==> undefined
+
+    // Remaining components of hierarchical URIs
+    private transient String path;              // null ==> opaque
+    private transient String query;
+
+    // The remaining fields may be computed on demand
+
+    private volatile transient String schemeSpecificPart;
+    private volatile transient int hash;        // Zero ==> undefined
+
+    private volatile transient String decodedUserInfo = null;
+    private volatile transient String decodedAuthority = null;
+    private volatile transient String decodedPath = null;
+    private volatile transient String decodedQuery = null;
+    private volatile transient String decodedFragment = null;
+    private volatile transient String decodedSchemeSpecificPart = null;
+
+    /**
+     * The string form of this URI.
+     *
+     * @serial
+     */
+    private volatile String string;             // The only serializable field
+
+
+
+    // -- Constructors and factories --
+
+    private URI() { }                           // Used internally
+
+    /**
+     * Constructs a URI by parsing the given string.
+     *
+     * <p> This constructor parses the given string exactly as specified by the
+     * grammar in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * Appendix&nbsp;A, <b><i>except for the following deviations:</i></b> </p>
+     *
+     * <ul>
+     *
+     *   <li><p> An empty authority component is permitted as long as it is
+     *   followed by a non-empty path, a query component, or a fragment
+     *   component.  This allows the parsing of URIs such as
+     *   {@code "file:///foo/bar"}, which seems to be the intent of
+     *   RFC&nbsp;2396 although the grammar does not permit it.  If the
+     *   authority component is empty then the user-information, host, and port
+     *   components are undefined. </p></li>
+     *
+     *   <li><p> Empty relative paths are permitted; this seems to be the
+     *   intent of RFC&nbsp;2396 although the grammar does not permit it.  The
+     *   primary consequence of this deviation is that a standalone fragment
+     *   such as {@code "#foo"} parses as a relative URI with an empty path
+     *   and the given fragment, and can be usefully <a
+     *   href="#resolve-frag">resolved</a> against a base URI.
+     *
+     *   <li><p> IPv4 addresses in host components are parsed rigorously, as
+     *   specified by <a
+     *   href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>: Each
+     *   element of a dotted-quad address must contain no more than three
+     *   decimal digits.  Each element is further constrained to have a value
+     *   no greater than 255. </p></li>
+     *
+     *   <li> <p> Hostnames in host components that comprise only a single
+     *   domain label are permitted to start with an <i>alphanum</i>
+     *   character. This seems to be the intent of <a
+     *   href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>
+     *   section&nbsp;3.2.2 although the grammar does not permit it. The
+     *   consequence of this deviation is that the authority component of a
+     *   hierarchical URI such as {@code s://123}, will parse as a server-based
+     *   authority. </p></li>
+     *
+     *   <li><p> IPv6 addresses are permitted for the host component.  An IPv6
+     *   address must be enclosed in square brackets ({@code '['} and
+     *   {@code ']'}) as specified by <a
+     *   href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>.  The
+     *   IPv6 address itself must parse according to <a
+     *   href="http://www.ietf.org/rfc/rfc2373.txt">RFC&nbsp;2373</a>.  IPv6
+     *   addresses are further constrained to describe no more than sixteen
+     *   bytes of address information, a constraint implicit in RFC&nbsp;2373
+     *   but not expressible in the grammar. </p></li>
+     *
+     *   <li><p> Characters in the <i>other</i> category are permitted wherever
+     *   RFC&nbsp;2396 permits <i>escaped</i> octets, that is, in the
+     *   user-information, path, query, and fragment components, as well as in
+     *   the authority component if the authority is registry-based.  This
+     *   allows URIs to contain Unicode characters beyond those in the US-ASCII
+     *   character set. </p></li>
+     *
+     * </ul>
+     *
+     * @param  str   The string to be parsed into a URI
+     *
+     * @throws  NullPointerException
+     *          If {@code str} is {@code null}
+     *
+     * @throws  URISyntaxException
+     *          If the given string violates RFC&nbsp;2396, as augmented
+     *          by the above deviations
+     */
+    public URI(String str) throws URISyntaxException {
+        new Parser(str).parse(false);
+    }
+
+    /**
+     * Constructs a hierarchical URI from the given components.
+     *
+     * <p> If a scheme is given then the path, if also given, must either be
+     * empty or begin with a slash character ({@code '/'}).  Otherwise a
+     * component of the new URI may be left undefined by passing {@code null}
+     * for the corresponding parameter or, in the case of the {@code port}
+     * parameter, by passing {@code -1}.
+     *
+     * <p> This constructor first builds a URI string from the given components
+     * according to the rules specified in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;7: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> Initially, the result string is empty. </p></li>
+     *
+     *   <li><p> If a scheme is given then it is appended to the result,
+     *   followed by a colon character ({@code ':'}).  </p></li>
+     *
+     *   <li><p> If user information, a host, or a port are given then the
+     *   string {@code "//"} is appended.  </p></li>
+     *
+     *   <li><p> If user information is given then it is appended, followed by
+     *   a commercial-at character ({@code '@'}).  Any character not in the
+     *   <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories is <a href="#quote">quoted</a>.  </p></li>
+     *
+     *   <li><p> If a host is given then it is appended.  If the host is a
+     *   literal IPv6 address but is not enclosed in square brackets
+     *   ({@code '['} and {@code ']'}) then the square brackets are added.
+     *   </p></li>
+     *
+     *   <li><p> If a port number is given then a colon character
+     *   ({@code ':'}) is appended, followed by the port number in decimal.
+     *   </p></li>
+     *
+     *   <li><p> If a path is given then it is appended.  Any character not in
+     *   the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories, and not equal to the slash character ({@code '/'}) or the
+     *   commercial-at character ({@code '@'}), is quoted.  </p></li>
+     *
+     *   <li><p> If a query is given then a question-mark character
+     *   ({@code '?'}) is appended, followed by the query.  Any character that
+     *   is not a <a href="#legal-chars">legal URI character</a> is quoted.
+     *   </p></li>
+     *
+     *   <li><p> Finally, if a fragment is given then a hash character
+     *   ({@code '#'}) is appended, followed by the fragment.  Any character
+     *   that is not a legal URI character is quoted.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> The resulting URI string is then parsed as if by invoking the {@link
+     * #URI(String)} constructor and then invoking the {@link
+     * #parseServerAuthority()} method upon the result; this may cause a {@link
+     * URISyntaxException} to be thrown.  </p>
+     *
+     * @param   scheme    Scheme name
+     * @param   userInfo  User name and authorization information
+     * @param   host      Host name
+     * @param   port      Port number
+     * @param   path      Path
+     * @param   query     Query
+     * @param   fragment  Fragment
+     *
+     * @throws URISyntaxException
+     *         If both a scheme and a path are given but the path is relative,
+     *         if the URI string constructed from the given components violates
+     *         RFC&nbsp;2396, or if the authority component of the string is
+     *         present but cannot be parsed as a server-based authority
+     */
+    public URI(String scheme,
+               String userInfo, String host, int port,
+               String path, String query, String fragment)
+        throws URISyntaxException
+    {
+        String s = toString(scheme, null,
+                            null, userInfo, host, port,
+                            path, query, fragment);
+        checkPath(s, scheme, path);
+        new Parser(s).parse(true);
+    }
+
+    /**
+     * Constructs a hierarchical URI from the given components.
+     *
+     * <p> If a scheme is given then the path, if also given, must either be
+     * empty or begin with a slash character ({@code '/'}).  Otherwise a
+     * component of the new URI may be left undefined by passing {@code null}
+     * for the corresponding parameter.
+     *
+     * <p> This constructor first builds a URI string from the given components
+     * according to the rules specified in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;7: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> Initially, the result string is empty.  </p></li>
+     *
+     *   <li><p> If a scheme is given then it is appended to the result,
+     *   followed by a colon character ({@code ':'}).  </p></li>
+     *
+     *   <li><p> If an authority is given then the string {@code "//"} is
+     *   appended, followed by the authority.  If the authority contains a
+     *   literal IPv6 address then the address must be enclosed in square
+     *   brackets ({@code '['} and {@code ']'}).  Any character not in the
+     *   <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories, and not equal to the commercial-at character
+     *   ({@code '@'}), is <a href="#quote">quoted</a>.  </p></li>
+     *
+     *   <li><p> If a path is given then it is appended.  Any character not in
+     *   the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, or <i>other</i>
+     *   categories, and not equal to the slash character ({@code '/'}) or the
+     *   commercial-at character ({@code '@'}), is quoted.  </p></li>
+     *
+     *   <li><p> If a query is given then a question-mark character
+     *   ({@code '?'}) is appended, followed by the query.  Any character that
+     *   is not a <a href="#legal-chars">legal URI character</a> is quoted.
+     *   </p></li>
+     *
+     *   <li><p> Finally, if a fragment is given then a hash character
+     *   ({@code '#'}) is appended, followed by the fragment.  Any character
+     *   that is not a legal URI character is quoted.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> The resulting URI string is then parsed as if by invoking the {@link
+     * #URI(String)} constructor and then invoking the {@link
+     * #parseServerAuthority()} method upon the result; this may cause a {@link
+     * URISyntaxException} to be thrown.  </p>
+     *
+     * @param   scheme     Scheme name
+     * @param   authority  Authority
+     * @param   path       Path
+     * @param   query      Query
+     * @param   fragment   Fragment
+     *
+     * @throws URISyntaxException
+     *         If both a scheme and a path are given but the path is relative,
+     *         if the URI string constructed from the given components violates
+     *         RFC&nbsp;2396, or if the authority component of the string is
+     *         present but cannot be parsed as a server-based authority
+     */
+    public URI(String scheme,
+               String authority,
+               String path, String query, String fragment)
+        throws URISyntaxException
+    {
+        String s = toString(scheme, null,
+                            authority, null, null, -1,
+                            path, query, fragment);
+        checkPath(s, scheme, path);
+        new Parser(s).parse(false);
+    }
+
+    /**
+     * Constructs a hierarchical URI from the given components.
+     *
+     * <p> A component may be left undefined by passing {@code null}.
+     *
+     * <p> This convenience constructor works as if by invoking the
+     * seven-argument constructor as follows:
+     *
+     * <blockquote>
+     * {@code new} {@link #URI(String, String, String, int, String, String, String)
+     * URI}{@code (scheme, null, host, -1, path, null, fragment);}
+     * </blockquote>
+     *
+     * @param   scheme    Scheme name
+     * @param   host      Host name
+     * @param   path      Path
+     * @param   fragment  Fragment
+     *
+     * @throws  URISyntaxException
+     *          If the URI string constructed from the given components
+     *          violates RFC&nbsp;2396
+     */
+    public URI(String scheme, String host, String path, String fragment)
+        throws URISyntaxException
+    {
+        this(scheme, null, host, -1, path, null, fragment);
+    }
+
+    /**
+     * Constructs a URI from the given components.
+     *
+     * <p> A component may be left undefined by passing {@code null}.
+     *
+     * <p> This constructor first builds a URI in string form using the given
+     * components as follows:  </p>
+     *
+     * <ol>
+     *
+     *   <li><p> Initially, the result string is empty.  </p></li>
+     *
+     *   <li><p> If a scheme is given then it is appended to the result,
+     *   followed by a colon character ({@code ':'}).  </p></li>
+     *
+     *   <li><p> If a scheme-specific part is given then it is appended.  Any
+     *   character that is not a <a href="#legal-chars">legal URI character</a>
+     *   is <a href="#quote">quoted</a>.  </p></li>
+     *
+     *   <li><p> Finally, if a fragment is given then a hash character
+     *   ({@code '#'}) is appended to the string, followed by the fragment.
+     *   Any character that is not a legal URI character is quoted.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> The resulting URI string is then parsed in order to create the new
+     * URI instance as if by invoking the {@link #URI(String)} constructor;
+     * this may cause a {@link URISyntaxException} to be thrown.  </p>
+     *
+     * @param   scheme    Scheme name
+     * @param   ssp       Scheme-specific part
+     * @param   fragment  Fragment
+     *
+     * @throws  URISyntaxException
+     *          If the URI string constructed from the given components
+     *          violates RFC&nbsp;2396
+     */
+    public URI(String scheme, String ssp, String fragment)
+        throws URISyntaxException
+    {
+        new Parser(toString(scheme, ssp,
+                            null, null, null, -1,
+                            null, null, fragment))
+            .parse(false);
+    }
+
+    /**
+     * Creates a URI by parsing the given string.
+     *
+     * <p> This convenience factory method works as if by invoking the {@link
+     * #URI(String)} constructor; any {@link URISyntaxException} thrown by the
+     * constructor is caught and wrapped in a new {@link
+     * IllegalArgumentException} object, which is then thrown.
+     *
+     * <p> This method is provided for use in situations where it is known that
+     * the given string is a legal URI, for example for URI constants declared
+     * within in a program, and so it would be considered a programming error
+     * for the string not to parse as such.  The constructors, which throw
+     * {@link URISyntaxException} directly, should be used situations where a
+     * URI is being constructed from user input or from some other source that
+     * may be prone to errors.  </p>
+     *
+     * @param  str   The string to be parsed into a URI
+     * @return The new URI
+     *
+     * @throws  NullPointerException
+     *          If {@code str} is {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If the given string violates RFC&nbsp;2396
+     */
+    public static URI create(String str) {
+        try {
+            return new URI(str);
+        } catch (URISyntaxException x) {
+            throw new IllegalArgumentException(x.getMessage(), x);
+        }
+    }
+
+
+    // -- Operations --
+
+    /**
+     * Attempts to parse this URI's authority component, if defined, into
+     * user-information, host, and port components.
+     *
+     * <p> If this URI's authority component has already been recognized as
+     * being server-based then it will already have been parsed into
+     * user-information, host, and port components.  In this case, or if this
+     * URI has no authority component, this method simply returns this URI.
+     *
+     * <p> Otherwise this method attempts once more to parse the authority
+     * component into user-information, host, and port components, and throws
+     * an exception describing why the authority component could not be parsed
+     * in that way.
+     *
+     * <p> This method is provided because the generic URI syntax specified in
+     * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>
+     * cannot always distinguish a malformed server-based authority from a
+     * legitimate registry-based authority.  It must therefore treat some
+     * instances of the former as instances of the latter.  The authority
+     * component in the URI string {@code "//foo:bar"}, for example, is not a
+     * legal server-based authority but it is legal as a registry-based
+     * authority.
+     *
+     * <p> In many common situations, for example when working URIs that are
+     * known to be either URNs or URLs, the hierarchical URIs being used will
+     * always be server-based.  They therefore must either be parsed as such or
+     * treated as an error.  In these cases a statement such as
+     *
+     * <blockquote>
+     * {@code URI }<i>u</i>{@code  = new URI(str).parseServerAuthority();}
+     * </blockquote>
+     *
+     * <p> can be used to ensure that <i>u</i> always refers to a URI that, if
+     * it has an authority component, has a server-based authority with proper
+     * user-information, host, and port components.  Invoking this method also
+     * ensures that if the authority could not be parsed in that way then an
+     * appropriate diagnostic message can be issued based upon the exception
+     * that is thrown. </p>
+     *
+     * @return  A URI whose authority field has been parsed
+     *          as a server-based authority
+     *
+     * @throws  URISyntaxException
+     *          If the authority component of this URI is defined
+     *          but cannot be parsed as a server-based authority
+     *          according to RFC&nbsp;2396
+     */
+    public URI parseServerAuthority()
+        throws URISyntaxException
+    {
+        // We could be clever and cache the error message and index from the
+        // exception thrown during the original parse, but that would require
+        // either more fields or a more-obscure representation.
+        if ((host != null) || (authority == null))
+            return this;
+        defineString();
+        new Parser(string).parse(true);
+        return this;
+    }
+
+    /**
+     * Normalizes this URI's path.
+     *
+     * <p> If this URI is opaque, or if its path is already in normal form,
+     * then this URI is returned.  Otherwise a new URI is constructed that is
+     * identical to this URI except that its path is computed by normalizing
+     * this URI's path in a manner consistent with <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;6, sub-steps&nbsp;c through&nbsp;f; that is:
+     * </p>
+     *
+     * <ol>
+     *
+     *   <li><p> All {@code "."} segments are removed. </p></li>
+     *
+     *   <li><p> If a {@code ".."} segment is preceded by a non-{@code ".."}
+     *   segment then both of these segments are removed.  This step is
+     *   repeated until it is no longer applicable. </p></li>
+     *
+     *   <li><p> If the path is relative, and if its first segment contains a
+     *   colon character ({@code ':'}), then a {@code "."} segment is
+     *   prepended.  This prevents a relative URI with a path such as
+     *   {@code "a:b/c/d"} from later being re-parsed as an opaque URI with a
+     *   scheme of {@code "a"} and a scheme-specific part of {@code "b/c/d"}.
+     *   <b><i>(Deviation from RFC&nbsp;2396)</i></b> </p></li>
+     *
+     * </ol>
+     *
+     * <p> A normalized path will begin with one or more {@code ".."} segments
+     * if there were insufficient non-{@code ".."} segments preceding them to
+     * allow their removal.  A normalized path will begin with a {@code "."}
+     * segment if one was inserted by step 3 above.  Otherwise, a normalized
+     * path will not contain any {@code "."} or {@code ".."} segments. </p>
+     *
+     * @return  A URI equivalent to this URI,
+     *          but whose path is in normal form
+     */
+    public URI normalize() {
+        return normalize(this);
+    }
+
+    /**
+     * Resolves the given URI against this URI.
+     *
+     * <p> If the given URI is already absolute, or if this URI is opaque, then
+     * the given URI is returned.
+     *
+     * <p><a name="resolve-frag"></a> If the given URI's fragment component is
+     * defined, its path component is empty, and its scheme, authority, and
+     * query components are undefined, then a URI with the given fragment but
+     * with all other components equal to those of this URI is returned.  This
+     * allows a URI representing a standalone fragment reference, such as
+     * {@code "#foo"}, to be usefully resolved against a base URI.
+     *
+     * <p> Otherwise this method constructs a new hierarchical URI in a manner
+     * consistent with <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2; that is: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> A new URI is constructed with this URI's scheme and the given
+     *   URI's query and fragment components. </p></li>
+     *
+     *   <li><p> If the given URI has an authority component then the new URI's
+     *   authority and path are taken from the given URI. </p></li>
+     *
+     *   <li><p> Otherwise the new URI's authority component is copied from
+     *   this URI, and its path is computed as follows: </p>
+     *
+     *   <ol>
+     *
+     *     <li><p> If the given URI's path is absolute then the new URI's path
+     *     is taken from the given URI. </p></li>
+     *
+     *     <li><p> Otherwise the given URI's path is relative, and so the new
+     *     URI's path is computed by resolving the path of the given URI
+     *     against the path of this URI.  This is done by concatenating all but
+     *     the last segment of this URI's path, if any, with the given URI's
+     *     path and then normalizing the result as if by invoking the {@link
+     *     #normalize() normalize} method. </p></li>
+     *
+     *   </ol></li>
+     *
+     * </ol>
+     *
+     * <p> The result of this method is absolute if, and only if, either this
+     * URI is absolute or the given URI is absolute.  </p>
+     *
+     * @param  uri  The URI to be resolved against this URI
+     * @return The resulting URI
+     *
+     * @throws  NullPointerException
+     *          If {@code uri} is {@code null}
+     */
+    public URI resolve(URI uri) {
+        return resolve(this, uri);
+    }
+
+    /**
+     * Constructs a new URI by parsing the given string and then resolving it
+     * against this URI.
+     *
+     * <p> This convenience method works as if invoking it were equivalent to
+     * evaluating the expression {@link #resolve(java.net.URI)
+     * resolve}{@code (URI.}{@link #create(String) create}{@code (str))}. </p>
+     *
+     * @param  str   The string to be parsed into a URI
+     * @return The resulting URI
+     *
+     * @throws  NullPointerException
+     *          If {@code str} is {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If the given string violates RFC&nbsp;2396
+     */
+    public URI resolve(String str) {
+        return resolve(URI.create(str));
+    }
+
+    /**
+     * Relativizes the given URI against this URI.
+     *
+     * <p> The relativization of the given URI against this URI is computed as
+     * follows: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> If either this URI or the given URI are opaque, or if the
+     *   scheme and authority components of the two URIs are not identical, or
+     *   if the path of this URI is not a prefix of the path of the given URI,
+     *   then the given URI is returned. </p></li>
+     *
+     *   <li><p> Otherwise a new relative hierarchical URI is constructed with
+     *   query and fragment components taken from the given URI and with a path
+     *   component computed by removing this URI's path from the beginning of
+     *   the given URI's path. </p></li>
+     *
+     * </ol>
+     *
+     * @param  uri  The URI to be relativized against this URI
+     * @return The resulting URI
+     *
+     * @throws  NullPointerException
+     *          If {@code uri} is {@code null}
+     */
+    public URI relativize(URI uri) {
+        return relativize(this, uri);
+    }
+
+    /**
+     * Constructs a URL from this URI.
+     *
+     * <p> This convenience method works as if invoking it were equivalent to
+     * evaluating the expression {@code new URL(this.toString())} after
+     * first checking that this URI is absolute. </p>
+     *
+     * @return  A URL constructed from this URI
+     *
+     * @throws  IllegalArgumentException
+     *          If this URL is not absolute
+     *
+     * @throws  MalformedURLException
+     *          If a protocol handler for the URL could not be found,
+     *          or if some other error occurred while constructing the URL
+     */
+    public URL toURL()
+        throws MalformedURLException {
+        if (!isAbsolute())
+            throw new IllegalArgumentException("URI is not absolute");
+        return new URL(toString());
+    }
+
+    // -- Component access methods --
+
+    /**
+     * Returns the scheme component of this URI.
+     *
+     * <p> The scheme component of a URI, if defined, only contains characters
+     * in the <i>alphanum</i> category and in the string {@code "-.+"}.  A
+     * scheme always starts with an <i>alpha</i> character. <p>
+     *
+     * The scheme component of a URI cannot contain escaped octets, hence this
+     * method does not perform any decoding.
+     *
+     * @return  The scheme component of this URI,
+     *          or {@code null} if the scheme is undefined
+     */
+    public String getScheme() {
+        return scheme;
+    }
+
+    /**
+     * Tells whether or not this URI is absolute.
+     *
+     * <p> A URI is absolute if, and only if, it has a scheme component. </p>
+     *
+     * @return  {@code true} if, and only if, this URI is absolute
+     */
+    public boolean isAbsolute() {
+        return scheme != null;
+    }
+
+    /**
+     * Tells whether or not this URI is opaque.
+     *
+     * <p> A URI is opaque if, and only if, it is absolute and its
+     * scheme-specific part does not begin with a slash character ('/').
+     * An opaque URI has a scheme, a scheme-specific part, and possibly
+     * a fragment; all other components are undefined. </p>
+     *
+     * @return  {@code true} if, and only if, this URI is opaque
+     */
+    public boolean isOpaque() {
+        return path == null;
+    }
+
+    /**
+     * Returns the raw scheme-specific part of this URI.  The scheme-specific
+     * part is never undefined, though it may be empty.
+     *
+     * <p> The scheme-specific part of a URI only contains legal URI
+     * characters. </p>
+     *
+     * @return  The raw scheme-specific part of this URI
+     *          (never {@code null})
+     */
+    public String getRawSchemeSpecificPart() {
+        defineSchemeSpecificPart();
+        return schemeSpecificPart;
+    }
+
+    /**
+     * Returns the decoded scheme-specific part of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawSchemeSpecificPart() getRawSchemeSpecificPart} method
+     * except that all sequences of escaped octets are <a
+     * href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded scheme-specific part of this URI
+     *          (never {@code null})
+     */
+    public String getSchemeSpecificPart() {
+        if (decodedSchemeSpecificPart == null)
+            decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart());
+        return decodedSchemeSpecificPart;
+    }
+
+    /**
+     * Returns the raw authority component of this URI.
+     *
+     * <p> The authority component of a URI, if defined, only contains the
+     * commercial-at character ({@code '@'}) and characters in the
+     * <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and <i>other</i>
+     * categories.  If the authority is server-based then it is further
+     * constrained to have valid user-information, host, and port
+     * components. </p>
+     *
+     * @return  The raw authority component of this URI,
+     *          or {@code null} if the authority is undefined
+     */
+    public String getRawAuthority() {
+        return authority;
+    }
+
+    /**
+     * Returns the decoded authority component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawAuthority() getRawAuthority} method except that all
+     * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded authority component of this URI,
+     *          or {@code null} if the authority is undefined
+     */
+    public String getAuthority() {
+        if (decodedAuthority == null)
+            decodedAuthority = decode(authority);
+        return decodedAuthority;
+    }
+
+    /**
+     * Returns the raw user-information component of this URI.
+     *
+     * <p> The user-information component of a URI, if defined, only contains
+     * characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>, and
+     * <i>other</i> categories. </p>
+     *
+     * @return  The raw user-information component of this URI,
+     *          or {@code null} if the user information is undefined
+     */
+    public String getRawUserInfo() {
+        return userInfo;
+    }
+
+    /**
+     * Returns the decoded user-information component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawUserInfo() getRawUserInfo} method except that all
+     * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded user-information component of this URI,
+     *          or {@code null} if the user information is undefined
+     */
+    public String getUserInfo() {
+        if ((decodedUserInfo == null) && (userInfo != null))
+            decodedUserInfo = decode(userInfo);
+        return decodedUserInfo;
+    }
+
+    /**
+     * Returns the host component of this URI.
+     *
+     * <p> The host component of a URI, if defined, will have one of the
+     * following forms: </p>
+     *
+     * <ul>
+     *
+     *   <li><p> A domain name consisting of one or more <i>labels</i>
+     *   separated by period characters ({@code '.'}), optionally followed by
+     *   a period character.  Each label consists of <i>alphanum</i> characters
+     *   as well as hyphen characters ({@code '-'}), though hyphens never
+     *   occur as the first or last characters in a label. The rightmost
+     *   label of a domain name consisting of two or more labels, begins
+     *   with an <i>alpha</i> character. </li>
+     *
+     *   <li><p> A dotted-quad IPv4 address of the form
+     *   <i>digit</i>{@code +.}<i>digit</i>{@code +.}<i>digit</i>{@code +.}<i>digit</i>{@code +},
+     *   where no <i>digit</i> sequence is longer than three characters and no
+     *   sequence has a value larger than 255. </p></li>
+     *
+     *   <li><p> An IPv6 address enclosed in square brackets ({@code '['} and
+     *   {@code ']'}) and consisting of hexadecimal digits, colon characters
+     *   ({@code ':'}), and possibly an embedded IPv4 address.  The full
+     *   syntax of IPv6 addresses is specified in <a
+     *   href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IPv6
+     *   Addressing Architecture</i></a>.  </p></li>
+     *
+     * </ul>
+     *
+     * The host component of a URI cannot contain escaped octets, hence this
+     * method does not perform any decoding.
+     *
+     * @return  The host component of this URI,
+     *          or {@code null} if the host is undefined
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Returns the port number of this URI.
+     *
+     * <p> The port component of a URI, if defined, is a non-negative
+     * integer. </p>
+     *
+     * @return  The port component of this URI,
+     *          or {@code -1} if the port is undefined
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns the raw path component of this URI.
+     *
+     * <p> The path component of a URI, if defined, only contains the slash
+     * character ({@code '/'}), the commercial-at character ({@code '@'}),
+     * and characters in the <i>unreserved</i>, <i>punct</i>, <i>escaped</i>,
+     * and <i>other</i> categories. </p>
+     *
+     * @return  The path component of this URI,
+     *          or {@code null} if the path is undefined
+     */
+    public String getRawPath() {
+        return path;
+    }
+
+    /**
+     * Returns the decoded path component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawPath() getRawPath} method except that all sequences of
+     * escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded path component of this URI,
+     *          or {@code null} if the path is undefined
+     */
+    public String getPath() {
+        if ((decodedPath == null) && (path != null))
+            decodedPath = decode(path);
+        return decodedPath;
+    }
+
+    /**
+     * Returns the raw query component of this URI.
+     *
+     * <p> The query component of a URI, if defined, only contains legal URI
+     * characters. </p>
+     *
+     * @return  The raw query component of this URI,
+     *          or {@code null} if the query is undefined
+     */
+    public String getRawQuery() {
+        return query;
+    }
+
+    /**
+     * Returns the decoded query component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawQuery() getRawQuery} method except that all sequences of
+     * escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded query component of this URI,
+     *          or {@code null} if the query is undefined
+     */
+    public String getQuery() {
+        if ((decodedQuery == null) && (query != null))
+            decodedQuery = decode(query);
+        return decodedQuery;
+    }
+
+    /**
+     * Returns the raw fragment component of this URI.
+     *
+     * <p> The fragment component of a URI, if defined, only contains legal URI
+     * characters. </p>
+     *
+     * @return  The raw fragment component of this URI,
+     *          or {@code null} if the fragment is undefined
+     */
+    public String getRawFragment() {
+        return fragment;
+    }
+
+    /**
+     * Returns the decoded fragment component of this URI.
+     *
+     * <p> The string returned by this method is equal to that returned by the
+     * {@link #getRawFragment() getRawFragment} method except that all
+     * sequences of escaped octets are <a href="#decode">decoded</a>.  </p>
+     *
+     * @return  The decoded fragment component of this URI,
+     *          or {@code null} if the fragment is undefined
+     */
+    public String getFragment() {
+        if ((decodedFragment == null) && (fragment != null))
+            decodedFragment = decode(fragment);
+        return decodedFragment;
+    }
+
+
+    // -- Equality, comparison, hash code, toString, and serialization --
+
+    /**
+     * Tests this URI for equality with another object.
+     *
+     * <p> If the given object is not a URI then this method immediately
+     * returns {@code false}.
+     *
+     * <p> For two URIs to be considered equal requires that either both are
+     * opaque or both are hierarchical.  Their schemes must either both be
+     * undefined or else be equal without regard to case. Their fragments
+     * must either both be undefined or else be equal.
+     *
+     * <p> For two opaque URIs to be considered equal, their scheme-specific
+     * parts must be equal.
+     *
+     * <p> For two hierarchical URIs to be considered equal, their paths must
+     * be equal and their queries must either both be undefined or else be
+     * equal.  Their authorities must either both be undefined, or both be
+     * registry-based, or both be server-based.  If their authorities are
+     * defined and are registry-based, then they must be equal.  If their
+     * authorities are defined and are server-based, then their hosts must be
+     * equal without regard to case, their port numbers must be equal, and
+     * their user-information components must be equal.
+     *
+     * <p> When testing the user-information, path, query, fragment, authority,
+     * or scheme-specific parts of two URIs for equality, the raw forms rather
+     * than the encoded forms of these components are compared and the
+     * hexadecimal digits of escaped octets are compared without regard to
+     * case.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob   The object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a URI that
+     *          is identical to this URI
+     */
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (!(ob instanceof URI))
+            return false;
+        URI that = (URI)ob;
+        if (this.isOpaque() != that.isOpaque()) return false;
+        if (!equalIgnoringCase(this.scheme, that.scheme)) return false;
+        if (!equal(this.fragment, that.fragment)) return false;
+
+        // Opaque
+        if (this.isOpaque())
+            return equal(this.schemeSpecificPart, that.schemeSpecificPart);
+
+        // Hierarchical
+        if (!equal(this.path, that.path)) return false;
+        if (!equal(this.query, that.query)) return false;
+
+        // Authorities
+        if (this.authority == that.authority) return true;
+        if (this.host != null) {
+            // Server-based
+            if (!equal(this.userInfo, that.userInfo)) return false;
+            if (!equalIgnoringCase(this.host, that.host)) return false;
+            if (this.port != that.port) return false;
+        } else if (this.authority != null) {
+            // Registry-based
+            if (!equal(this.authority, that.authority)) return false;
+        } else if (this.authority != that.authority) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns a hash-code value for this URI.  The hash code is based upon all
+     * of the URI's components, and satisfies the general contract of the
+     * {@link java.lang.Object#hashCode() Object.hashCode} method.
+     *
+     * @return  A hash-code value for this URI
+     */
+    public int hashCode() {
+        if (hash != 0)
+            return hash;
+        int h = hashIgnoringCase(0, scheme);
+        h = hash(h, fragment);
+        if (isOpaque()) {
+            h = hash(h, schemeSpecificPart);
+        } else {
+            h = hash(h, path);
+            h = hash(h, query);
+            if (host != null) {
+                h = hash(h, userInfo);
+                h = hashIgnoringCase(h, host);
+                h += 1949 * port;
+            } else {
+                h = hash(h, authority);
+            }
+        }
+        hash = h;
+        return h;
+    }
+
+    /**
+     * Compares this URI to another object, which must be a URI.
+     *
+     * <p> When comparing corresponding components of two URIs, if one
+     * component is undefined but the other is defined then the first is
+     * considered to be less than the second.  Unless otherwise noted, string
+     * components are ordered according to their natural, case-sensitive
+     * ordering as defined by the {@link java.lang.String#compareTo(Object)
+     * String.compareTo} method.  String components that are subject to
+     * encoding are compared by comparing their raw forms rather than their
+     * encoded forms.
+     *
+     * <p> The ordering of URIs is defined as follows: </p>
+     *
+     * <ul>
+     *
+     *   <li><p> Two URIs with different schemes are ordered according the
+     *   ordering of their schemes, without regard to case. </p></li>
+     *
+     *   <li><p> A hierarchical URI is considered to be less than an opaque URI
+     *   with an identical scheme. </p></li>
+     *
+     *   <li><p> Two opaque URIs with identical schemes are ordered according
+     *   to the ordering of their scheme-specific parts. </p></li>
+     *
+     *   <li><p> Two opaque URIs with identical schemes and scheme-specific
+     *   parts are ordered according to the ordering of their
+     *   fragments. </p></li>
+     *
+     *   <li><p> Two hierarchical URIs with identical schemes are ordered
+     *   according to the ordering of their authority components: </p>
+     *
+     *   <ul>
+     *
+     *     <li><p> If both authority components are server-based then the URIs
+     *     are ordered according to their user-information components; if these
+     *     components are identical then the URIs are ordered according to the
+     *     ordering of their hosts, without regard to case; if the hosts are
+     *     identical then the URIs are ordered according to the ordering of
+     *     their ports. </p></li>
+     *
+     *     <li><p> If one or both authority components are registry-based then
+     *     the URIs are ordered according to the ordering of their authority
+     *     components. </p></li>
+     *
+     *   </ul></li>
+     *
+     *   <li><p> Finally, two hierarchical URIs with identical schemes and
+     *   authority components are ordered according to the ordering of their
+     *   paths; if their paths are identical then they are ordered according to
+     *   the ordering of their queries; if the queries are identical then they
+     *   are ordered according to the order of their fragments. </p></li>
+     *
+     * </ul>
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Comparable#compareTo(Object) Comparable.compareTo}
+     * method. </p>
+     *
+     * @param   that
+     *          The object to which this URI is to be compared
+     *
+     * @return  A negative integer, zero, or a positive integer as this URI is
+     *          less than, equal to, or greater than the given URI
+     *
+     * @throws  ClassCastException
+     *          If the given object is not a URI
+     */
+    public int compareTo(URI that) {
+        int c;
+
+        if ((c = compareIgnoringCase(this.scheme, that.scheme)) != 0)
+            return c;
+
+        if (this.isOpaque()) {
+            if (that.isOpaque()) {
+                // Both opaque
+                if ((c = compare(this.schemeSpecificPart,
+                                 that.schemeSpecificPart)) != 0)
+                    return c;
+                return compare(this.fragment, that.fragment);
+            }
+            return +1;                  // Opaque > hierarchical
+        } else if (that.isOpaque()) {
+            return -1;                  // Hierarchical < opaque
+        }
+
+        // Hierarchical
+        if ((this.host != null) && (that.host != null)) {
+            // Both server-based
+            if ((c = compare(this.userInfo, that.userInfo)) != 0)
+                return c;
+            if ((c = compareIgnoringCase(this.host, that.host)) != 0)
+                return c;
+            if ((c = this.port - that.port) != 0)
+                return c;
+        } else {
+            // If one or both authorities are registry-based then we simply
+            // compare them in the usual, case-sensitive way.  If one is
+            // registry-based and one is server-based then the strings are
+            // guaranteed to be unequal, hence the comparison will never return
+            // zero and the compareTo and equals methods will remain
+            // consistent.
+            if ((c = compare(this.authority, that.authority)) != 0) return c;
+        }
+
+        if ((c = compare(this.path, that.path)) != 0) return c;
+        if ((c = compare(this.query, that.query)) != 0) return c;
+        return compare(this.fragment, that.fragment);
+    }
+
+    /**
+     * Returns the content of this URI as a string.
+     *
+     * <p> If this URI was created by invoking one of the constructors in this
+     * class then a string equivalent to the original input string, or to the
+     * string computed from the originally-given components, as appropriate, is
+     * returned.  Otherwise this URI was created by normalization, resolution,
+     * or relativization, and so a string is constructed from this URI's
+     * components according to the rules specified in <a
+     * href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
+     * section&nbsp;5.2, step&nbsp;7. </p>
+     *
+     * @return  The string form of this URI
+     */
+    public String toString() {
+        defineString();
+        return string;
+    }
+
+    /**
+     * Returns the content of this URI as a US-ASCII string.
+     *
+     * <p> If this URI does not contain any characters in the <i>other</i>
+     * category then an invocation of this method will return the same value as
+     * an invocation of the {@link #toString() toString} method.  Otherwise
+     * this method works as if by invoking that method and then <a
+     * href="#encode">encoding</a> the result.  </p>
+     *
+     * @return  The string form of this URI, encoded as needed
+     *          so that it only contains characters in the US-ASCII
+     *          charset
+     */
+    public String toASCIIString() {
+        defineString();
+        return encode(string);
+    }
+
+
+    // -- Serialization support --
+
+    /**
+     * Saves the content of this URI to the given serial stream.
+     *
+     * <p> The only serializable field of a URI instance is its {@code string}
+     * field.  That field is given a value, if it does not have one already,
+     * and then the {@link java.io.ObjectOutputStream#defaultWriteObject()}
+     * method of the given object-output stream is invoked. </p>
+     *
+     * @param  os  The object-output stream to which this object
+     *             is to be written
+     */
+    private void writeObject(ObjectOutputStream os)
+        throws IOException
+    {
+        defineString();
+        os.defaultWriteObject();        // Writes the string field only
+    }
+
+    /**
+     * Reconstitutes a URI from the given serial stream.
+     *
+     * <p> The {@link java.io.ObjectInputStream#defaultReadObject()} method is
+     * invoked to read the value of the {@code string} field.  The result is
+     * then parsed in the usual way.
+     *
+     * @param  is  The object-input stream from which this object
+     *             is being read
+     */
+    private void readObject(ObjectInputStream is)
+        throws ClassNotFoundException, IOException
+    {
+        port = -1;                      // Argh
+        is.defaultReadObject();
+        try {
+            new Parser(string).parse(false);
+        } catch (URISyntaxException x) {
+            IOException y = new InvalidObjectException("Invalid URI");
+            y.initCause(x);
+            throw y;
+        }
+    }
+
+
+    // -- End of public methods --
+
+
+    // -- Utility methods for string-field comparison and hashing --
+
+    // These methods return appropriate values for null string arguments,
+    // thereby simplifying the equals, hashCode, and compareTo methods.
+    //
+    // The case-ignoring methods should only be applied to strings whose
+    // characters are all known to be US-ASCII.  Because of this restriction,
+    // these methods are faster than the similar methods in the String class.
+
+    // US-ASCII only
+    private static int toLower(char c) {
+        if ((c >= 'A') && (c <= 'Z'))
+            return c + ('a' - 'A');
+        return c;
+    }
+
+    // US-ASCII only
+    private static int toUpper(char c) {
+        if ((c >= 'a') && (c <= 'z'))
+            return c - ('a' - 'A');
+        return c;
+    }
+
+    private static boolean equal(String s, String t) {
+        if (s == t) return true;
+        if ((s != null) && (t != null)) {
+            if (s.length() != t.length())
+                return false;
+            if (s.indexOf('%') < 0)
+                return s.equals(t);
+            int n = s.length();
+            for (int i = 0; i < n;) {
+                char c = s.charAt(i);
+                char d = t.charAt(i);
+                if (c != '%') {
+                    if (c != d)
+                        return false;
+                    i++;
+                    continue;
+                }
+                if (d != '%')
+                    return false;
+                i++;
+                if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
+                    return false;
+                i++;
+                if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
+                    return false;
+                i++;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    // US-ASCII only
+    private static boolean equalIgnoringCase(String s, String t) {
+        if (s == t) return true;
+        if ((s != null) && (t != null)) {
+            int n = s.length();
+            if (t.length() != n)
+                return false;
+            for (int i = 0; i < n; i++) {
+                if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private static int hash(int hash, String s) {
+        if (s == null) return hash;
+        return s.indexOf('%') < 0 ? hash * 127 + s.hashCode()
+                                  : normalizedHash(hash, s);
+    }
+
+
+    private static int normalizedHash(int hash, String s) {
+        int h = 0;
+        for (int index = 0; index < s.length(); index++) {
+            char ch = s.charAt(index);
+            h = 31 * h + ch;
+            if (ch == '%') {
+                /*
+                 * Process the next two encoded characters
+                 */
+                for (int i = index + 1; i < index + 3; i++)
+                    h = 31 * h + toUpper(s.charAt(i));
+                index += 2;
+            }
+        }
+        return hash * 127 + h;
+    }
+
+    // US-ASCII only
+    private static int hashIgnoringCase(int hash, String s) {
+        if (s == null) return hash;
+        int h = hash;
+        int n = s.length();
+        for (int i = 0; i < n; i++)
+            h = 31 * h + toLower(s.charAt(i));
+        return h;
+    }
+
+    private static int compare(String s, String t) {
+        if (s == t) return 0;
+        if (s != null) {
+            if (t != null)
+                return s.compareTo(t);
+            else
+                return +1;
+        } else {
+            return -1;
+        }
+    }
+
+    // US-ASCII only
+    private static int compareIgnoringCase(String s, String t) {
+        if (s == t) return 0;
+        if (s != null) {
+            if (t != null) {
+                int sn = s.length();
+                int tn = t.length();
+                int n = sn < tn ? sn : tn;
+                for (int i = 0; i < n; i++) {
+                    int c = toLower(s.charAt(i)) - toLower(t.charAt(i));
+                    if (c != 0)
+                        return c;
+                }
+                return sn - tn;
+            }
+            return +1;
+        } else {
+            return -1;
+        }
+    }
+
+
+    // -- String construction --
+
+    // If a scheme is given then the path, if given, must be absolute
+    //
+    private static void checkPath(String s, String scheme, String path)
+        throws URISyntaxException
+    {
+        if (scheme != null) {
+            if ((path != null)
+                && ((path.length() > 0) && (path.charAt(0) != '/')))
+                throw new URISyntaxException(s,
+                                             "Relative path in absolute URI");
+        }
+    }
+
+    private void appendAuthority(StringBuffer sb,
+                                 String authority,
+                                 String userInfo,
+                                 String host,
+                                 int port)
+    {
+        if (host != null) {
+            sb.append("//");
+            if (userInfo != null) {
+                sb.append(quote(userInfo, L_USERINFO, H_USERINFO));
+                sb.append('@');
+            }
+            boolean needBrackets = ((host.indexOf(':') >= 0)
+                                    && !host.startsWith("[")
+                                    && !host.endsWith("]"));
+            if (needBrackets) sb.append('[');
+            sb.append(host);
+            if (needBrackets) sb.append(']');
+            if (port != -1) {
+                sb.append(':');
+                sb.append(port);
+            }
+        } else if (authority != null) {
+            sb.append("//");
+            if (authority.startsWith("[")) {
+                // authority should (but may not) contain an embedded IPv6 address
+                int end = authority.indexOf("]");
+                String doquote = authority, dontquote = "";
+                if (end != -1 && authority.indexOf(":") != -1) {
+                    // the authority contains an IPv6 address
+                    if (end == authority.length()) {
+                        dontquote = authority;
+                        doquote = "";
+                    } else {
+                        dontquote = authority.substring(0 , end + 1);
+                        doquote = authority.substring(end + 1);
+                    }
+                }
+                sb.append(dontquote);
+                sb.append(quote(doquote,
+                            L_REG_NAME | L_SERVER,
+                            H_REG_NAME | H_SERVER));
+            } else {
+                sb.append(quote(authority,
+                            L_REG_NAME | L_SERVER,
+                            H_REG_NAME | H_SERVER));
+            }
+        }
+    }
+
+    private void appendSchemeSpecificPart(StringBuffer sb,
+                                          String opaquePart,
+                                          String authority,
+                                          String userInfo,
+                                          String host,
+                                          int port,
+                                          String path,
+                                          String query)
+    {
+        if (opaquePart != null) {
+            /* check if SSP begins with an IPv6 address
+             * because we must not quote a literal IPv6 address
+             */
+            if (opaquePart.startsWith("//[")) {
+                int end =  opaquePart.indexOf("]");
+                if (end != -1 && opaquePart.indexOf(":")!=-1) {
+                    String doquote, dontquote;
+                    if (end == opaquePart.length()) {
+                        dontquote = opaquePart;
+                        doquote = "";
+                    } else {
+                        dontquote = opaquePart.substring(0,end+1);
+                        doquote = opaquePart.substring(end+1);
+                    }
+                    sb.append (dontquote);
+                    sb.append(quote(doquote, L_URIC, H_URIC));
+                }
+            } else {
+                sb.append(quote(opaquePart, L_URIC, H_URIC));
+            }
+        } else {
+            appendAuthority(sb, authority, userInfo, host, port);
+            if (path != null)
+                sb.append(quote(path, L_PATH, H_PATH));
+            if (query != null) {
+                sb.append('?');
+                sb.append(quote(query, L_URIC, H_URIC));
+            }
+        }
+    }
+
+    private void appendFragment(StringBuffer sb, String fragment) {
+        if (fragment != null) {
+            sb.append('#');
+            sb.append(quote(fragment, L_URIC, H_URIC));
+        }
+    }
+
+    private String toString(String scheme,
+                            String opaquePart,
+                            String authority,
+                            String userInfo,
+                            String host,
+                            int port,
+                            String path,
+                            String query,
+                            String fragment)
+    {
+        StringBuffer sb = new StringBuffer();
+        if (scheme != null) {
+            sb.append(scheme);
+            sb.append(':');
+        }
+        appendSchemeSpecificPart(sb, opaquePart,
+                                 authority, userInfo, host, port,
+                                 path, query);
+        appendFragment(sb, fragment);
+        return sb.toString();
+    }
+
+    private void defineSchemeSpecificPart() {
+        if (schemeSpecificPart != null) return;
+        StringBuffer sb = new StringBuffer();
+        appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(),
+                                 host, port, getPath(), getQuery());
+        if (sb.length() == 0) return;
+        schemeSpecificPart = sb.toString();
+    }
+
+    private void defineString() {
+        if (string != null) return;
+
+        StringBuffer sb = new StringBuffer();
+        if (scheme != null) {
+            sb.append(scheme);
+            sb.append(':');
+        }
+        if (isOpaque()) {
+            sb.append(schemeSpecificPart);
+        } else {
+            if (host != null) {
+                sb.append("//");
+                if (userInfo != null) {
+                    sb.append(userInfo);
+                    sb.append('@');
+                }
+                boolean needBrackets = ((host.indexOf(':') >= 0)
+                                    && !host.startsWith("[")
+                                    && !host.endsWith("]"));
+                if (needBrackets) sb.append('[');
+                sb.append(host);
+                if (needBrackets) sb.append(']');
+                if (port != -1) {
+                    sb.append(':');
+                    sb.append(port);
+                }
+            } else if (authority != null) {
+                sb.append("//");
+                sb.append(authority);
+            }
+            if (path != null)
+                sb.append(path);
+            if (query != null) {
+                sb.append('?');
+                sb.append(query);
+            }
+        }
+        if (fragment != null) {
+            sb.append('#');
+            sb.append(fragment);
+        }
+        string = sb.toString();
+    }
+
+
+    // -- Normalization, resolution, and relativization --
+
+    // RFC2396 5.2 (6)
+    private static String resolvePath(String base, String child,
+                                      boolean absolute)
+    {
+        int i = base.lastIndexOf('/');
+        int cn = child.length();
+        String path = "";
+
+        if (cn == 0) {
+            // 5.2 (6a)
+            if (i >= 0)
+                path = base.substring(0, i + 1);
+        } else {
+            StringBuffer sb = new StringBuffer(base.length() + cn);
+            // 5.2 (6a)
+            if (i >= 0)
+                sb.append(base.substring(0, i + 1));
+            // 5.2 (6b)
+            sb.append(child);
+            path = sb.toString();
+        }
+
+        // 5.2 (6c-f)
+        // Android-changed: App compat. Remove leading dots when resolving path. http://b/25897693
+        // String np = normalize(path);
+        String np = normalize(path, true);
+
+        // 5.2 (6g): If the result is absolute but the path begins with "../",
+        // then we simply leave the path as-is
+
+        return np;
+    }
+
+    // RFC2396 5.2
+    private static URI resolve(URI base, URI child) {
+        // check if child if opaque first so that NPE is thrown
+        // if child is null.
+        if (child.isOpaque() || base.isOpaque())
+            return child;
+
+        // 5.2 (2): Reference to current document (lone fragment)
+        if ((child.scheme == null) && (child.authority == null)
+            && child.path.equals("") && (child.fragment != null)
+            && (child.query == null)) {
+            if ((base.fragment != null)
+                && child.fragment.equals(base.fragment)) {
+                return base;
+            }
+            URI ru = new URI();
+            ru.scheme = base.scheme;
+            ru.authority = base.authority;
+            ru.userInfo = base.userInfo;
+            ru.host = base.host;
+            ru.port = base.port;
+            ru.path = base.path;
+            ru.fragment = child.fragment;
+            ru.query = base.query;
+            return ru;
+        }
+
+        // 5.2 (3): Child is absolute
+        if (child.scheme != null)
+            return child;
+
+        URI ru = new URI();             // Resolved URI
+        ru.scheme = base.scheme;
+        ru.query = child.query;
+        ru.fragment = child.fragment;
+
+        // 5.2 (4): Authority
+        if (child.authority == null) {
+            ru.authority = base.authority;
+            ru.host = base.host;
+            ru.userInfo = base.userInfo;
+            ru.port = base.port;
+
+            // BEGIN Android-changed: App Compat. Handle null and empty path using RFC 3986 logic
+            // http://b/25897693
+            if (child.path == null || child.path.isEmpty()) {
+                // This is an additional path from RFC 3986 RI, which fixes following RFC 2396
+                // "normal" examples:
+                // Base: http://a/b/c/d;p?q
+                //   "?y" = "http://a/b/c/d;p?y"
+                //   ""   = "http://a/b/c/d;p?q"
+                // http://b/25897693
+                ru.path = base.path;
+                ru.query = child.query != null ? child.query : base.query;
+            // END Android-changed: App Compat. Handle null and empty path using RFC 3986 logic
+            } else if ((child.path.length() > 0) && (child.path.charAt(0) == '/')) {
+                // 5.2 (5): Child path is absolute
+                //
+                // Android-changed: App Compat. Remove leading dots in path.
+                // There is an additional step from RFC 3986 RI, requiring to remove dots for
+                // absolute path as well.
+                // http://b/25897693
+                // ru.path = child.path;
+                ru.path = normalize(child.path, true);
+            } else {
+                // 5.2 (6): Resolve relative path
+                ru.path = resolvePath(base.path, child.path, base.isAbsolute());
+            }
+        } else {
+            ru.authority = child.authority;
+            ru.host = child.host;
+            ru.userInfo = child.userInfo;
+            ru.host = child.host;
+            ru.port = child.port;
+            ru.path = child.path;
+        }
+
+        // 5.2 (7): Recombine (nothing to do here)
+        return ru;
+    }
+
+    // If the given URI's path is normal then return the URI;
+    // o.w., return a new URI containing the normalized path.
+    //
+    private static URI normalize(URI u) {
+        if (u.isOpaque() || (u.path == null) || (u.path.length() == 0))
+            return u;
+
+        String np = normalize(u.path);
+        if (np == u.path)
+            return u;
+
+        URI v = new URI();
+        v.scheme = u.scheme;
+        v.fragment = u.fragment;
+        v.authority = u.authority;
+        v.userInfo = u.userInfo;
+        v.host = u.host;
+        v.port = u.port;
+        v.path = np;
+        v.query = u.query;
+        return v;
+    }
+
+    // If both URIs are hierarchical, their scheme and authority components are
+    // identical, and the base path is a prefix of the child's path, then
+    // return a relative URI that, when resolved against the base, yields the
+    // child; otherwise, return the child.
+    //
+    private static URI relativize(URI base, URI child) {
+        // check if child if opaque first so that NPE is thrown
+        // if child is null.
+        if (child.isOpaque() || base.isOpaque())
+            return child;
+        if (!equalIgnoringCase(base.scheme, child.scheme)
+            || !equal(base.authority, child.authority))
+            return child;
+
+        String bp = normalize(base.path);
+        String cp = normalize(child.path);
+        if (!bp.equals(cp)) {
+            // Android-changed: App Compat. Interpret ambiguous base path as a file, not a directory
+            // Upstream would append '/' to bp if not present, interpreting it as a directory; thus,
+            // /a/b/c relative to /a/b would become /c, whereas Android would relativize to /b/c.
+            // The spec is pretty vague about this but the Android behavior is kept because several
+            // tests enforce it.
+            // if (!bp.endsWith("/"))
+            //     bp = bp + "/";
+            if (bp.indexOf('/') != -1) {
+                bp = bp.substring(0, bp.lastIndexOf('/') + 1);
+            }
+
+            if (!cp.startsWith(bp))
+                return child;
+        }
+
+        URI v = new URI();
+        v.path = cp.substring(bp.length());
+        v.query = child.query;
+        v.fragment = child.fragment;
+        return v;
+    }
+
+
+
+    // -- Path normalization --
+
+    // The following algorithm for path normalization avoids the creation of a
+    // string object for each segment, as well as the use of a string buffer to
+    // compute the final result, by using a single char array and editing it in
+    // place.  The array is first split into segments, replacing each slash
+    // with '\0' and creating a segment-index array, each element of which is
+    // the index of the first char in the corresponding segment.  We then walk
+    // through both arrays, removing ".", "..", and other segments as necessary
+    // by setting their entries in the index array to -1.  Finally, the two
+    // arrays are used to rejoin the segments and compute the final result.
+    //
+    // This code is based upon src/solaris/native/java/io/canonicalize_md.c
+
+
+    // Check the given path to see if it might need normalization.  A path
+    // might need normalization if it contains duplicate slashes, a "."
+    // segment, or a ".." segment.  Return -1 if no further normalization is
+    // possible, otherwise return the number of segments found.
+    //
+    // This method takes a string argument rather than a char array so that
+    // this test can be performed without invoking path.toCharArray().
+    //
+    static private int needsNormalization(String path) {
+        boolean normal = true;
+        int ns = 0;                     // Number of segments
+        int end = path.length() - 1;    // Index of last char in path
+        int p = 0;                      // Index of next char in path
+
+        // Skip initial slashes
+        while (p <= end) {
+            if (path.charAt(p) != '/') break;
+            p++;
+        }
+        if (p > 1) normal = false;
+
+        // Scan segments
+        while (p <= end) {
+
+            // Looking at "." or ".." ?
+            if ((path.charAt(p) == '.')
+                && ((p == end)
+                    || ((path.charAt(p + 1) == '/')
+                        || ((path.charAt(p + 1) == '.')
+                            && ((p + 1 == end)
+                                || (path.charAt(p + 2) == '/')))))) {
+                normal = false;
+            }
+            ns++;
+
+            // Find beginning of next segment
+            while (p <= end) {
+                if (path.charAt(p++) != '/')
+                    continue;
+
+                // Skip redundant slashes
+                while (p <= end) {
+                    if (path.charAt(p) != '/') break;
+                    normal = false;
+                    p++;
+                }
+
+                break;
+            }
+        }
+
+        return normal ? -1 : ns;
+    }
+
+
+    // Split the given path into segments, replacing slashes with nulls and
+    // filling in the given segment-index array.
+    //
+    // Preconditions:
+    //   segs.length == Number of segments in path
+    //
+    // Postconditions:
+    //   All slashes in path replaced by '\0'
+    //   segs[i] == Index of first char in segment i (0 <= i < segs.length)
+    //
+    static private void split(char[] path, int[] segs) {
+        int end = path.length - 1;      // Index of last char in path
+        int p = 0;                      // Index of next char in path
+        int i = 0;                      // Index of current segment
+
+        // Skip initial slashes
+        while (p <= end) {
+            if (path[p] != '/') break;
+            path[p] = '\0';
+            p++;
+        }
+
+        while (p <= end) {
+
+            // Note start of segment
+            segs[i++] = p++;
+
+            // Find beginning of next segment
+            while (p <= end) {
+                if (path[p++] != '/')
+                    continue;
+                path[p - 1] = '\0';
+
+                // Skip redundant slashes
+                while (p <= end) {
+                    if (path[p] != '/') break;
+                    path[p++] = '\0';
+                }
+                break;
+            }
+        }
+
+        if (i != segs.length)
+            throw new InternalError();  // ASSERT
+    }
+
+
+    // Join the segments in the given path according to the given segment-index
+    // array, ignoring those segments whose index entries have been set to -1,
+    // and inserting slashes as needed.  Return the length of the resulting
+    // path.
+    //
+    // Preconditions:
+    //   segs[i] == -1 implies segment i is to be ignored
+    //   path computed by split, as above, with '\0' having replaced '/'
+    //
+    // Postconditions:
+    //   path[0] .. path[return value] == Resulting path
+    //
+    static private int join(char[] path, int[] segs) {
+        int ns = segs.length;           // Number of segments
+        int end = path.length - 1;      // Index of last char in path
+        int p = 0;                      // Index of next path char to write
+
+        if (path[p] == '\0') {
+            // Restore initial slash for absolute paths
+            path[p++] = '/';
+        }
+
+        for (int i = 0; i < ns; i++) {
+            int q = segs[i];            // Current segment
+            if (q == -1)
+                // Ignore this segment
+                continue;
+
+            if (p == q) {
+                // We're already at this segment, so just skip to its end
+                while ((p <= end) && (path[p] != '\0'))
+                    p++;
+                if (p <= end) {
+                    // Preserve trailing slash
+                    path[p++] = '/';
+                }
+            } else if (p < q) {
+                // Copy q down to p
+                while ((q <= end) && (path[q] != '\0'))
+                    path[p++] = path[q++];
+                if (q <= end) {
+                    // Preserve trailing slash
+                    path[p++] = '/';
+                }
+            } else
+                throw new InternalError(); // ASSERT false
+        }
+
+        return p;
+    }
+
+
+    // Remove "." segments from the given path, and remove segment pairs
+    // consisting of a non-".." segment followed by a ".." segment.
+    //
+    // Android-changed: App compat. Remove leading dots when resolving path. http://b/25897693
+    // private static void removeDots(char[] path, int[] segs) {
+    private static void removeDots(char[] path, int[] segs, boolean removeLeading) {
+        int ns = segs.length;
+        int end = path.length - 1;
+
+        for (int i = 0; i < ns; i++) {
+            int dots = 0;               // Number of dots found (0, 1, or 2)
+
+            // Find next occurrence of "." or ".."
+            do {
+                int p = segs[i];
+                if (path[p] == '.') {
+                    if (p == end) {
+                        dots = 1;
+                        break;
+                    } else if (path[p + 1] == '\0') {
+                        dots = 1;
+                        break;
+                    } else if ((path[p + 1] == '.')
+                               && ((p + 1 == end)
+                                   || (path[p + 2] == '\0'))) {
+                        dots = 2;
+                        break;
+                    }
+                }
+                i++;
+            } while (i < ns);
+            if ((i > ns) || (dots == 0))
+                break;
+
+            if (dots == 1) {
+                // Remove this occurrence of "."
+                segs[i] = -1;
+            } else {
+                // If there is a preceding non-".." segment, remove both that
+                // segment and this occurrence of ".."
+                int j;
+                for (j = i - 1; j >= 0; j--) {
+                    if (segs[j] != -1) break;
+                }
+                if (j >= 0) {
+                    int q = segs[j];
+                    if (!((path[q] == '.')
+                          && (path[q + 1] == '.')
+                          && (path[q + 2] == '\0'))) {
+                        segs[i] = -1;
+                        segs[j] = -1;
+                    }
+                // Android-added: App compat. Remove leading dots when resolving path.
+                // This is a leading ".." segment. Per RFC 3986 RI, this should be removed as
+                // well. This fixes RFC 2396 "abnormal" examples.
+                // http://b/25897693
+                } else if (removeLeading) {
+                    segs[i] = -1;
+                }
+            }
+        }
+    }
+
+
+    // DEVIATION: If the normalized path is relative, and if the first
+    // segment could be parsed as a scheme name, then prepend a "." segment
+    //
+    private static void maybeAddLeadingDot(char[] path, int[] segs) {
+
+        if (path[0] == '\0')
+            // The path is absolute
+            return;
+
+        int ns = segs.length;
+        int f = 0;                      // Index of first segment
+        while (f < ns) {
+            if (segs[f] >= 0)
+                break;
+            f++;
+        }
+        if ((f >= ns) || (f == 0))
+            // The path is empty, or else the original first segment survived,
+            // in which case we already know that no leading "." is needed
+            return;
+
+        int p = segs[f];
+        while ((p < path.length) && (path[p] != ':') && (path[p] != '\0')) p++;
+        if (p >= path.length || path[p] == '\0')
+            // No colon in first segment, so no "." needed
+            return;
+
+        // At this point we know that the first segment is unused,
+        // hence we can insert a "." segment at that position
+        path[0] = '.';
+        path[1] = '\0';
+        segs[0] = 0;
+    }
+
+
+    // Normalize the given path string.  A normal path string has no empty
+    // segments (i.e., occurrences of "//"), no segments equal to ".", and no
+    // segments equal to ".." that are preceded by a segment not equal to "..".
+    // In contrast to Unix-style pathname normalization, for URI paths we
+    // always retain trailing slashes.
+    //
+    private static String normalize(String ps) {
+        // BEGIN Android-changed: App compat. Remove leading dots when resolving path.
+        // Controlled by the "boolean removeLeading" argument added to normalize().
+        return normalize(ps, false);
+    }
+
+    private static String normalize(String ps, boolean removeLeading) {
+        // END Android-changed: App compat. Remove leading dots when resolving path.
+        // Does this path need normalization?
+        int ns = needsNormalization(ps);        // Number of segments
+        if (ns < 0)
+            // Nope -- just return it
+            return ps;
+
+        char[] path = ps.toCharArray();         // Path in char-array form
+
+        // Split path into segments
+        int[] segs = new int[ns];               // Segment-index array
+        split(path, segs);
+
+        // Remove dots
+        // Android-changed: App compat. Remove leading dots when resolving path.
+        // removeDots(path, segs);
+        removeDots(path, segs, removeLeading);
+
+        // Prevent scheme-name confusion
+        maybeAddLeadingDot(path, segs);
+
+        // Join the remaining segments and return the result
+        String s = new String(path, 0, join(path, segs));
+        if (s.equals(ps)) {
+            // string was already normalized
+            return ps;
+        }
+        return s;
+    }
+
+
+
+    // -- Character classes for parsing --
+
+    // RFC2396 precisely specifies which characters in the US-ASCII charset are
+    // permissible in the various components of a URI reference.  We here
+    // define a set of mask pairs to aid in enforcing these restrictions.  Each
+    // mask pair consists of two longs, a low mask and a high mask.  Taken
+    // together they represent a 128-bit mask, where bit i is set iff the
+    // character with value i is permitted.
+    //
+    // This approach is more efficient than sequentially searching arrays of
+    // permitted characters.  It could be made still more efficient by
+    // precompiling the mask information so that a character's presence in a
+    // given mask could be determined by a single table lookup.
+
+    // Compute the low-order mask for the characters in the given string
+    private static long lowMask(String chars) {
+        int n = chars.length();
+        long m = 0;
+        for (int i = 0; i < n; i++) {
+            char c = chars.charAt(i);
+            if (c < 64)
+                m |= (1L << c);
+        }
+        return m;
+    }
+
+    // Compute the high-order mask for the characters in the given string
+    private static long highMask(String chars) {
+        int n = chars.length();
+        long m = 0;
+        for (int i = 0; i < n; i++) {
+            char c = chars.charAt(i);
+            if ((c >= 64) && (c < 128))
+                m |= (1L << (c - 64));
+        }
+        return m;
+    }
+
+    // Compute a low-order mask for the characters
+    // between first and last, inclusive
+    private static long lowMask(char first, char last) {
+        long m = 0;
+        int f = Math.max(Math.min(first, 63), 0);
+        int l = Math.max(Math.min(last, 63), 0);
+        for (int i = f; i <= l; i++)
+            m |= 1L << i;
+        return m;
+    }
+
+    // Compute a high-order mask for the characters
+    // between first and last, inclusive
+    private static long highMask(char first, char last) {
+        long m = 0;
+        int f = Math.max(Math.min(first, 127), 64) - 64;
+        int l = Math.max(Math.min(last, 127), 64) - 64;
+        for (int i = f; i <= l; i++)
+            m |= 1L << i;
+        return m;
+    }
+
+    // Tell whether the given character is permitted by the given mask pair
+    private static boolean match(char c, long lowMask, long highMask) {
+        if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
+            return false;
+        if (c < 64)
+            return ((1L << c) & lowMask) != 0;
+        if (c < 128)
+            return ((1L << (c - 64)) & highMask) != 0;
+        return false;
+    }
+
+    // Character-class masks, in reverse order from RFC2396 because
+    // initializers for static fields cannot make forward references.
+
+    // digit    = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
+    //            "8" | "9"
+    private static final long L_DIGIT = lowMask('0', '9');
+    private static final long H_DIGIT = 0L;
+
+    // upalpha  = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" |
+    //            "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" |
+    //            "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z"
+    private static final long L_UPALPHA = 0L;
+    private static final long H_UPALPHA = highMask('A', 'Z');
+
+    // lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" |
+    //            "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" |
+    //            "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z"
+    private static final long L_LOWALPHA = 0L;
+    private static final long H_LOWALPHA = highMask('a', 'z');
+
+    // alpha         = lowalpha | upalpha
+    private static final long L_ALPHA = L_LOWALPHA | L_UPALPHA;
+    private static final long H_ALPHA = H_LOWALPHA | H_UPALPHA;
+
+    // alphanum      = alpha | digit
+    private static final long L_ALPHANUM = L_DIGIT | L_ALPHA;
+    private static final long H_ALPHANUM = H_DIGIT | H_ALPHA;
+
+    // hex           = digit | "A" | "B" | "C" | "D" | "E" | "F" |
+    //                         "a" | "b" | "c" | "d" | "e" | "f"
+    private static final long L_HEX = L_DIGIT;
+    private static final long H_HEX = highMask('A', 'F') | highMask('a', 'f');
+
+    // mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" |
+    //                 "(" | ")"
+    private static final long L_MARK = lowMask("-_.!~*'()");
+    private static final long H_MARK = highMask("-_.!~*'()");
+
+    // unreserved    = alphanum | mark
+    private static final long L_UNRESERVED = L_ALPHANUM | L_MARK;
+    private static final long H_UNRESERVED = H_ALPHANUM | H_MARK;
+
+    // reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
+    //                 "$" | "," | "[" | "]"
+    // Added per RFC2732: "[", "]"
+    private static final long L_RESERVED = lowMask(";/?:@&=+$,[]");
+    private static final long H_RESERVED = highMask(";/?:@&=+$,[]");
+
+    // The zero'th bit is used to indicate that escape pairs and non-US-ASCII
+    // characters are allowed; this is handled by the scanEscape method below.
+    private static final long L_ESCAPED = 1L;
+    private static final long H_ESCAPED = 0L;
+
+    // uric          = reserved | unreserved | escaped
+    private static final long L_URIC = L_RESERVED | L_UNRESERVED | L_ESCAPED;
+    private static final long H_URIC = H_RESERVED | H_UNRESERVED | H_ESCAPED;
+
+    // pchar         = unreserved | escaped |
+    //                 ":" | "@" | "&" | "=" | "+" | "$" | ","
+    private static final long L_PCHAR
+        = L_UNRESERVED | L_ESCAPED | lowMask(":@&=+$,");
+    private static final long H_PCHAR
+        = H_UNRESERVED | H_ESCAPED | highMask(":@&=+$,");
+
+    // All valid path characters
+    private static final long L_PATH = L_PCHAR | lowMask(";/");
+    private static final long H_PATH = H_PCHAR | highMask(";/");
+
+    // Dash, for use in domainlabel and toplabel
+    private static final long L_DASH = lowMask("-");
+    private static final long H_DASH = highMask("-");
+
+    // BEGIN Android-added: Allow underscore in hostname.
+    // UNDERSCORE, for use in domainlabel and toplabel
+    private static final long L_UNDERSCORE = lowMask("_");
+    private static final long H_UNDERSCORE = highMask("_");
+    // END Android-added: Allow underscore in hostname.
+
+    // Dot, for use in hostnames
+    private static final long L_DOT = lowMask(".");
+    private static final long H_DOT = highMask(".");
+
+    // userinfo      = *( unreserved | escaped |
+    //                    ";" | ":" | "&" | "=" | "+" | "$" | "," )
+    private static final long L_USERINFO
+        = L_UNRESERVED | L_ESCAPED | lowMask(";:&=+$,");
+    private static final long H_USERINFO
+        = H_UNRESERVED | H_ESCAPED | highMask(";:&=+$,");
+
+    // reg_name      = 1*( unreserved | escaped | "$" | "," |
+    //                     ";" | ":" | "@" | "&" | "=" | "+" )
+    private static final long L_REG_NAME
+        = L_UNRESERVED | L_ESCAPED | lowMask("$,;:@&=+");
+    private static final long H_REG_NAME
+        = H_UNRESERVED | H_ESCAPED | highMask("$,;:@&=+");
+
+    // All valid characters for server-based authorities
+    private static final long L_SERVER
+        = L_USERINFO | L_ALPHANUM | L_DASH | lowMask(".:@[]");
+    private static final long H_SERVER
+        = H_USERINFO | H_ALPHANUM | H_DASH | highMask(".:@[]");
+
+    // Special case of server authority that represents an IPv6 address
+    // In this case, a % does not signify an escape sequence
+    private static final long L_SERVER_PERCENT
+        = L_SERVER | lowMask("%");
+    private static final long H_SERVER_PERCENT
+        = H_SERVER | highMask("%");
+    private static final long L_LEFT_BRACKET = lowMask("[");
+    private static final long H_LEFT_BRACKET = highMask("[");
+
+    // scheme        = alpha *( alpha | digit | "+" | "-" | "." )
+    private static final long L_SCHEME = L_ALPHA | L_DIGIT | lowMask("+-.");
+    private static final long H_SCHEME = H_ALPHA | H_DIGIT | highMask("+-.");
+
+    // uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
+    //                 "&" | "=" | "+" | "$" | ","
+    private static final long L_URIC_NO_SLASH
+        = L_UNRESERVED | L_ESCAPED | lowMask(";?:@&=+$,");
+    private static final long H_URIC_NO_SLASH
+        = H_UNRESERVED | H_ESCAPED | highMask(";?:@&=+$,");
+
+
+    // -- Escaping and encoding --
+
+    private final static char[] hexDigits = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+
+    private static void appendEscape(StringBuffer sb, byte b) {
+        sb.append('%');
+        sb.append(hexDigits[(b >> 4) & 0x0f]);
+        sb.append(hexDigits[(b >> 0) & 0x0f]);
+    }
+
+    private static void appendEncoded(StringBuffer sb, char c) {
+        ByteBuffer bb = null;
+        try {
+            bb = ThreadLocalCoders.encoderFor("UTF-8")
+                .encode(CharBuffer.wrap("" + c));
+        } catch (CharacterCodingException x) {
+            assert false;
+        }
+        while (bb.hasRemaining()) {
+            int b = bb.get() & 0xff;
+            if (b >= 0x80)
+                appendEscape(sb, (byte)b);
+            else
+                sb.append((char)b);
+        }
+    }
+
+    // Quote any characters in s that are not permitted
+    // by the given mask pair
+    //
+    private static String quote(String s, long lowMask, long highMask) {
+        int n = s.length();
+        StringBuffer sb = null;
+        boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0);
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c < '\u0080') {
+                if (!match(c, lowMask, highMask)) {
+                    if (sb == null) {
+                        sb = new StringBuffer();
+                        sb.append(s.substring(0, i));
+                    }
+                    appendEscape(sb, (byte)c);
+                } else {
+                    if (sb != null)
+                        sb.append(c);
+                }
+            } else if (allowNonASCII
+                       && (Character.isSpaceChar(c)
+                           || Character.isISOControl(c))) {
+                if (sb == null) {
+                    sb = new StringBuffer();
+                    sb.append(s.substring(0, i));
+                }
+                appendEncoded(sb, c);
+            } else {
+                if (sb != null)
+                    sb.append(c);
+            }
+        }
+        return (sb == null) ? s : sb.toString();
+    }
+
+    // Encodes all characters >= \u0080 into escaped, normalized UTF-8 octets,
+    // assuming that s is otherwise legal
+    //
+    private static String encode(String s) {
+        int n = s.length();
+        if (n == 0)
+            return s;
+
+        // First check whether we actually need to encode
+        for (int i = 0;;) {
+            if (s.charAt(i) >= '\u0080')
+                break;
+            if (++i >= n)
+                return s;
+        }
+
+        String ns = Normalizer.normalize(s, Normalizer.Form.NFC);
+        ByteBuffer bb = null;
+        try {
+            bb = ThreadLocalCoders.encoderFor("UTF-8")
+                .encode(CharBuffer.wrap(ns));
+        } catch (CharacterCodingException x) {
+            assert false;
+        }
+
+        StringBuffer sb = new StringBuffer();
+        while (bb.hasRemaining()) {
+            int b = bb.get() & 0xff;
+            if (b >= 0x80)
+                appendEscape(sb, (byte)b);
+            else
+                sb.append((char)b);
+        }
+        return sb.toString();
+    }
+
+    private static int decode(char c) {
+        if ((c >= '0') && (c <= '9'))
+            return c - '0';
+        if ((c >= 'a') && (c <= 'f'))
+            return c - 'a' + 10;
+        if ((c >= 'A') && (c <= 'F'))
+            return c - 'A' + 10;
+        assert false;
+        return -1;
+    }
+
+    private static byte decode(char c1, char c2) {
+        return (byte)(  ((decode(c1) & 0xf) << 4)
+                      | ((decode(c2) & 0xf) << 0));
+    }
+
+    // Evaluates all escapes in s, applying UTF-8 decoding if needed.  Assumes
+    // that escapes are well-formed syntactically, i.e., of the form %XX.  If a
+    // sequence of escaped octets is not valid UTF-8 then the erroneous octets
+    // are replaced with '\uFFFD'.
+    // Exception: any "%" found between "[]" is left alone. It is an IPv6 literal
+    //            with a scope_id
+    //
+    private static String decode(String s) {
+        if (s == null)
+            return s;
+        int n = s.length();
+        if (n == 0)
+            return s;
+        if (s.indexOf('%') < 0)
+            return s;
+
+        StringBuffer sb = new StringBuffer(n);
+        ByteBuffer bb = ByteBuffer.allocate(n);
+        CharBuffer cb = CharBuffer.allocate(n);
+        CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
+            .onMalformedInput(CodingErrorAction.REPLACE)
+            .onUnmappableCharacter(CodingErrorAction.REPLACE);
+
+        // This is not horribly efficient, but it will do for now
+        char c = s.charAt(0);
+        boolean betweenBrackets = false;
+
+        for (int i = 0; i < n;) {
+            assert c == s.charAt(i);    // Loop invariant
+            if (c == '[') {
+                betweenBrackets = true;
+            } else if (betweenBrackets && c == ']') {
+                betweenBrackets = false;
+            }
+            if (c != '%' || betweenBrackets) {
+                sb.append(c);
+                if (++i >= n)
+                    break;
+                c = s.charAt(i);
+                continue;
+            }
+            bb.clear();
+            int ui = i;
+            for (;;) {
+                assert (n - i >= 2);
+                bb.put(decode(s.charAt(++i), s.charAt(++i)));
+                if (++i >= n)
+                    break;
+                c = s.charAt(i);
+                if (c != '%')
+                    break;
+            }
+            bb.flip();
+            cb.clear();
+            dec.reset();
+            CoderResult cr = dec.decode(bb, cb, true);
+            assert cr.isUnderflow();
+            cr = dec.flush(cb);
+            assert cr.isUnderflow();
+            sb.append(cb.flip().toString());
+        }
+
+        return sb.toString();
+    }
+
+
+    // -- Parsing --
+
+    // For convenience we wrap the input URI string in a new instance of the
+    // following internal class.  This saves always having to pass the input
+    // string as an argument to each internal scan/parse method.
+
+    private class Parser {
+
+        private String input;           // URI input string
+        private boolean requireServerAuthority = false;
+
+        Parser(String s) {
+            input = s;
+            string = s;
+        }
+
+        // -- Methods for throwing URISyntaxException in various ways --
+
+        private void fail(String reason) throws URISyntaxException {
+            throw new URISyntaxException(input, reason);
+        }
+
+        private void fail(String reason, int p) throws URISyntaxException {
+            throw new URISyntaxException(input, reason, p);
+        }
+
+        private void failExpecting(String expected, int p)
+            throws URISyntaxException
+        {
+            fail("Expected " + expected, p);
+        }
+
+        private void failExpecting(String expected, String prior, int p)
+            throws URISyntaxException
+        {
+            fail("Expected " + expected + " following " + prior, p);
+        }
+
+
+        // -- Simple access to the input string --
+
+        // Return a substring of the input string
+        //
+        private String substring(int start, int end) {
+            return input.substring(start, end);
+        }
+
+        // Return the char at position p,
+        // assuming that p < input.length()
+        //
+        private char charAt(int p) {
+            return input.charAt(p);
+        }
+
+        // Tells whether start < end and, if so, whether charAt(start) == c
+        //
+        private boolean at(int start, int end, char c) {
+            return (start < end) && (charAt(start) == c);
+        }
+
+        // Tells whether start + s.length() < end and, if so,
+        // whether the chars at the start position match s exactly
+        //
+        private boolean at(int start, int end, String s) {
+            int p = start;
+            int sn = s.length();
+            if (sn > end - p)
+                return false;
+            int i = 0;
+            while (i < sn) {
+                if (charAt(p++) != s.charAt(i)) {
+                    break;
+                }
+                i++;
+            }
+            return (i == sn);
+        }
+
+
+        // -- Scanning --
+
+        // The various scan and parse methods that follow use a uniform
+        // convention of taking the current start position and end index as
+        // their first two arguments.  The start is inclusive while the end is
+        // exclusive, just as in the String class, i.e., a start/end pair
+        // denotes the left-open interval [start, end) of the input string.
+        //
+        // These methods never proceed past the end position.  They may return
+        // -1 to indicate outright failure, but more often they simply return
+        // the position of the first char after the last char scanned.  Thus
+        // a typical idiom is
+        //
+        //     int p = start;
+        //     int q = scan(p, end, ...);
+        //     if (q > p)
+        //         // We scanned something
+        //         ...;
+        //     else if (q == p)
+        //         // We scanned nothing
+        //         ...;
+        //     else if (q == -1)
+        //         // Something went wrong
+        //         ...;
+
+
+        // Scan a specific char: If the char at the given start position is
+        // equal to c, return the index of the next char; otherwise, return the
+        // start position.
+        //
+        private int scan(int start, int end, char c) {
+            if ((start < end) && (charAt(start) == c))
+                return start + 1;
+            return start;
+        }
+
+        // Scan forward from the given start position.  Stop at the first char
+        // in the err string (in which case -1 is returned), or the first char
+        // in the stop string (in which case the index of the preceding char is
+        // returned), or the end of the input string (in which case the length
+        // of the input string is returned).  May return the start position if
+        // nothing matches.
+        //
+        private int scan(int start, int end, String err, String stop) {
+            int p = start;
+            while (p < end) {
+                char c = charAt(p);
+                if (err.indexOf(c) >= 0)
+                    return -1;
+                if (stop.indexOf(c) >= 0)
+                    break;
+                p++;
+            }
+            return p;
+        }
+
+        // Scan a potential escape sequence, starting at the given position,
+        // with the given first char (i.e., charAt(start) == c).
+        //
+        // This method assumes that if escapes are allowed then visible
+        // non-US-ASCII chars are also allowed.
+        //
+        private int scanEscape(int start, int n, char first)
+            throws URISyntaxException
+        {
+            int p = start;
+            char c = first;
+            if (c == '%') {
+                // Process escape pair
+                if ((p + 3 <= n)
+                    && match(charAt(p + 1), L_HEX, H_HEX)
+                    && match(charAt(p + 2), L_HEX, H_HEX)) {
+                    return p + 3;
+                }
+                fail("Malformed escape pair", p);
+            } else if ((c > 128)
+                       && !Character.isSpaceChar(c)
+                       && !Character.isISOControl(c)) {
+                // Allow unescaped but visible non-US-ASCII chars
+                return p + 1;
+            }
+            return p;
+        }
+
+        // Scan chars that match the given mask pair
+        //
+        private int scan(int start, int n, long lowMask, long highMask)
+            throws URISyntaxException
+        {
+            int p = start;
+            while (p < n) {
+                char c = charAt(p);
+                if (match(c, lowMask, highMask)) {
+                    p++;
+                    continue;
+                }
+                if ((lowMask & L_ESCAPED) != 0) {
+                    int q = scanEscape(p, n, c);
+                    if (q > p) {
+                        p = q;
+                        continue;
+                    }
+                }
+                break;
+            }
+            return p;
+        }
+
+        // Check that each of the chars in [start, end) matches the given mask
+        //
+        private void checkChars(int start, int end,
+                                long lowMask, long highMask,
+                                String what)
+            throws URISyntaxException
+        {
+            int p = scan(start, end, lowMask, highMask);
+            if (p < end)
+                fail("Illegal character in " + what, p);
+        }
+
+        // Check that the char at position p matches the given mask
+        //
+        private void checkChar(int p,
+                               long lowMask, long highMask,
+                               String what)
+            throws URISyntaxException
+        {
+            checkChars(p, p + 1, lowMask, highMask, what);
+        }
+
+
+        // -- Parsing --
+
+        // [<scheme>:]<scheme-specific-part>[#<fragment>]
+        //
+        void parse(boolean rsa) throws URISyntaxException {
+            requireServerAuthority = rsa;
+            int ssp;                    // Start of scheme-specific part
+            int n = input.length();
+            int p = scan(0, n, "/?#", ":");
+            if ((p >= 0) && at(p, n, ':')) {
+                if (p == 0)
+                    failExpecting("scheme name", 0);
+                checkChar(0, L_ALPHA, H_ALPHA, "scheme name");
+                checkChars(1, p, L_SCHEME, H_SCHEME, "scheme name");
+                scheme = substring(0, p);
+                p++;                    // Skip ':'
+                ssp = p;
+                if (at(p, n, '/')) {
+                    p = parseHierarchical(p, n);
+                } else {
+                    int q = scan(p, n, "", "#");
+                    if (q <= p)
+                        failExpecting("scheme-specific part", p);
+                    checkChars(p, q, L_URIC, H_URIC, "opaque part");
+                    p = q;
+                }
+            } else {
+                ssp = 0;
+                p = parseHierarchical(0, n);
+            }
+            schemeSpecificPart = substring(ssp, p);
+            if (at(p, n, '#')) {
+                checkChars(p + 1, n, L_URIC, H_URIC, "fragment");
+                fragment = substring(p + 1, n);
+                p = n;
+            }
+            if (p < n)
+                fail("end of URI", p);
+        }
+
+        // [//authority]<path>[?<query>]
+        //
+        // DEVIATION from RFC2396: We allow an empty authority component as
+        // long as it's followed by a non-empty path, query component, or
+        // fragment component.  This is so that URIs such as "file:///foo/bar"
+        // will parse.  This seems to be the intent of RFC2396, though the
+        // grammar does not permit it.  If the authority is empty then the
+        // userInfo, host, and port components are undefined.
+        //
+        // DEVIATION from RFC2396: We allow empty relative paths.  This seems
+        // to be the intent of RFC2396, but the grammar does not permit it.
+        // The primary consequence of this deviation is that "#f" parses as a
+        // relative URI with an empty path.
+        //
+        private int parseHierarchical(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            if (at(p, n, '/') && at(p + 1, n, '/')) {
+                p += 2;
+                int q = scan(p, n, "", "/?#");
+                if (q > p) {
+                    p = parseAuthority(p, q);
+                } else if (q < n) {
+                    // DEVIATION: Allow empty authority prior to non-empty
+                    // path, query component or fragment identifier
+                } else
+                    failExpecting("authority", p);
+            }
+            int q = scan(p, n, "", "?#"); // DEVIATION: May be empty
+            checkChars(p, q, L_PATH, H_PATH, "path");
+            path = substring(p, q);
+            p = q;
+            if (at(p, n, '?')) {
+                p++;
+                q = scan(p, n, "", "#");
+                checkChars(p, q, L_URIC, H_URIC, "query");
+                query = substring(p, q);
+                p = q;
+            }
+            return p;
+        }
+
+        // authority     = server | reg_name
+        //
+        // Ambiguity: An authority that is a registry name rather than a server
+        // might have a prefix that parses as a server.  We use the fact that
+        // the authority component is always followed by '/' or the end of the
+        // input string to resolve this: If the complete authority did not
+        // parse as a server then we try to parse it as a registry name.
+        //
+        private int parseAuthority(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q = p;
+            URISyntaxException ex = null;
+
+            boolean serverChars;
+            boolean regChars;
+
+            if (scan(p, n, "", "]") > p) {
+                // contains a literal IPv6 address, therefore % is allowed
+                serverChars = (scan(p, n, L_SERVER_PERCENT, H_SERVER_PERCENT) == n);
+            } else {
+                serverChars = (scan(p, n, L_SERVER, H_SERVER) == n);
+            }
+            regChars = (scan(p, n, L_REG_NAME, H_REG_NAME) == n);
+
+            if (regChars && !serverChars) {
+                // Must be a registry-based authority
+                authority = substring(p, n);
+                return n;
+            }
+
+            if (serverChars) {
+                // Might be (probably is) a server-based authority, so attempt
+                // to parse it as such.  If the attempt fails, try to treat it
+                // as a registry-based authority.
+                try {
+                    q = parseServer(p, n);
+                    if (q < n)
+                        failExpecting("end of authority", q);
+                    authority = substring(p, n);
+                } catch (URISyntaxException x) {
+                    // Undo results of failed parse
+                    userInfo = null;
+                    host = null;
+                    port = -1;
+                    if (requireServerAuthority) {
+                        // If we're insisting upon a server-based authority,
+                        // then just re-throw the exception
+                        throw x;
+                    } else {
+                        // Save the exception in case it doesn't parse as a
+                        // registry either
+                        ex = x;
+                        q = p;
+                    }
+                }
+            }
+
+            if (q < n) {
+                if (regChars) {
+                    // Registry-based authority
+                    authority = substring(p, n);
+                } else if (ex != null) {
+                    // Re-throw exception; it was probably due to
+                    // a malformed IPv6 address
+                    throw ex;
+                } else {
+                    fail("Illegal character in authority", q);
+                }
+            }
+
+            return n;
+        }
+
+
+        // [<userinfo>@]<host>[:<port>]
+        //
+        private int parseServer(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+
+            // userinfo
+            q = scan(p, n, "/?#", "@");
+            if ((q >= p) && at(q, n, '@')) {
+                checkChars(p, q, L_USERINFO, H_USERINFO, "user info");
+                userInfo = substring(p, q);
+                p = q + 1;              // Skip '@'
+            }
+
+            // hostname, IPv4 address, or IPv6 address
+            if (at(p, n, '[')) {
+                // DEVIATION from RFC2396: Support IPv6 addresses, per RFC2732
+                p++;
+                q = scan(p, n, "/?#", "]");
+                if ((q > p) && at(q, n, ']')) {
+                    // look for a "%" scope id
+                    int r = scan (p, q, "", "%");
+                    if (r > p) {
+                        parseIPv6Reference(p, r);
+                        if (r+1 == q) {
+                            fail ("scope id expected");
+                        }
+                        checkChars (r+1, q, L_ALPHANUM, H_ALPHANUM,
+                                                "scope id");
+                    } else {
+                        parseIPv6Reference(p, q);
+                    }
+                    host = substring(p-1, q+1);
+                    p = q + 1;
+                } else {
+                    failExpecting("closing bracket for IPv6 address", q);
+                }
+            } else {
+                q = parseIPv4Address(p, n);
+                if (q <= p)
+                    q = parseHostname(p, n);
+                p = q;
+            }
+
+            // port
+            if (at(p, n, ':')) {
+                p++;
+                q = scan(p, n, "", "/");
+                if (q > p) {
+                    checkChars(p, q, L_DIGIT, H_DIGIT, "port number");
+                    try {
+                        port = Integer.parseInt(substring(p, q));
+                    } catch (NumberFormatException x) {
+                        fail("Malformed port number", p);
+                    }
+                    p = q;
+                }
+            }
+            if (p < n)
+                failExpecting("port number", p);
+
+            return p;
+        }
+
+        // Scan a string of decimal digits whose value fits in a byte
+        //
+        private int scanByte(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q = scan(p, n, L_DIGIT, H_DIGIT);
+            if (q <= p) return q;
+            if (Integer.parseInt(substring(p, q)) > 255) return p;
+            return q;
+        }
+
+        // Scan an IPv4 address.
+        //
+        // If the strict argument is true then we require that the given
+        // interval contain nothing besides an IPv4 address; if it is false
+        // then we only require that it start with an IPv4 address.
+        //
+        // If the interval does not contain or start with (depending upon the
+        // strict argument) a legal IPv4 address characters then we return -1
+        // immediately; otherwise we insist that these characters parse as a
+        // legal IPv4 address and throw an exception on failure.
+        //
+        // We assume that any string of decimal digits and dots must be an IPv4
+        // address.  It won't parse as a hostname anyway, so making that
+        // assumption here allows more meaningful exceptions to be thrown.
+        //
+        private int scanIPv4Address(int start, int n, boolean strict)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+            int m = scan(p, n, L_DIGIT | L_DOT, H_DIGIT | H_DOT);
+            if ((m <= p) || (strict && (m != n)))
+                return -1;
+            for (;;) {
+                // Per RFC2732: At most three digits per byte
+                // Further constraint: Each element fits in a byte
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if ((q = scan(p, m, '.')) <= p) break;  p = q;
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if ((q = scan(p, m, '.')) <= p) break;  p = q;
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if ((q = scan(p, m, '.')) <= p) break;  p = q;
+                if ((q = scanByte(p, m)) <= p) break;   p = q;
+                if (q < m) break;
+                return q;
+            }
+            fail("Malformed IPv4 address", q);
+            return -1;
+        }
+
+        // Take an IPv4 address: Throw an exception if the given interval
+        // contains anything except an IPv4 address
+        //
+        private int takeIPv4Address(int start, int n, String expected)
+            throws URISyntaxException
+        {
+            int p = scanIPv4Address(start, n, true);
+            if (p <= start)
+                failExpecting(expected, start);
+            return p;
+        }
+
+        // Attempt to parse an IPv4 address, returning -1 on failure but
+        // allowing the given interval to contain [:<characters>] after
+        // the IPv4 address.
+        //
+        private int parseIPv4Address(int start, int n) {
+            int p;
+
+            try {
+                p = scanIPv4Address(start, n, false);
+            } catch (URISyntaxException x) {
+                return -1;
+            } catch (NumberFormatException nfe) {
+                return -1;
+            }
+
+            if (p > start && p < n) {
+                // IPv4 address is followed by something - check that
+                // it's a ":" as this is the only valid character to
+                // follow an address.
+                if (charAt(p) != ':') {
+                    p = -1;
+                }
+            }
+
+            if (p > start)
+                host = substring(start, p);
+
+            return p;
+        }
+
+        // Android-changed: Allow underscore in hostname.
+        // Added "_" to the grammars for domainLabel and topLabel.
+        // hostname      = domainlabel [ "." ] | 1*( domainlabel "." ) toplabel [ "." ]
+        // domainlabel   = alphanum | alphanum *( alphanum | "-" | "_" ) alphanum
+        // toplabel      = alpha | alpha *( alphanum | "-" | "_" ) alphanum
+        //
+        private int parseHostname(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+            int l = -1;                 // Start of last parsed label
+
+            do {
+                // Android-changed: Allow underscore in hostname.
+                // RFC 2396 only allows alphanumeric characters and hyphens, but real,
+                // large Internet hosts in the wild use underscore, so we have to allow it.
+                // http://code.google.com/p/android/issues/detail?id=37577
+                // http://b/17579865
+                // http://b/18016625
+                // http://b/18023709
+
+                // domainlabel = alphanum [ *( alphanum | "-" | "_" ) alphanum ]
+                q = scan(p, n, L_ALPHANUM, H_ALPHANUM);
+                if (q <= p)
+                    break;
+                l = p;
+                if (q > p) {
+                    p = q;
+                    // Android-changed: Allow underscore in hostname.
+                    // q = scan(p, n, L_ALPHANUM | L_DASH, H_ALPHANUM | H_DASH);
+                    q = scan(p, n, L_ALPHANUM | L_DASH | L_UNDERSCORE, H_ALPHANUM | H_DASH | H_UNDERSCORE);
+                    if (q > p) {
+                        if (charAt(q - 1) == '-')
+                            fail("Illegal character in hostname", q - 1);
+                        p = q;
+                    }
+                }
+                q = scan(p, n, '.');
+                if (q <= p)
+                    break;
+                p = q;
+            } while (p < n);
+
+            if ((p < n) && !at(p, n, ':'))
+                fail("Illegal character in hostname", p);
+
+            if (l < 0)
+                failExpecting("hostname", start);
+
+            // for a fully qualified hostname check that the rightmost
+            // label starts with an alpha character.
+            if (l > start && !match(charAt(l), L_ALPHA, H_ALPHA)) {
+                fail("Illegal character in hostname", l);
+            }
+
+            host = substring(start, p);
+            return p;
+        }
+
+
+        // IPv6 address parsing, from RFC2373: IPv6 Addressing Architecture
+        //
+        // Bug: The grammar in RFC2373 Appendix B does not allow addresses of
+        // the form ::12.34.56.78, which are clearly shown in the examples
+        // earlier in the document.  Here is the original grammar:
+        //
+        //   IPv6address = hexpart [ ":" IPv4address ]
+        //   hexpart     = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
+        //   hexseq      = hex4 *( ":" hex4)
+        //   hex4        = 1*4HEXDIG
+        //
+        // We therefore use the following revised grammar:
+        //
+        //   IPv6address = hexseq [ ":" IPv4address ]
+        //                 | hexseq [ "::" [ hexpost ] ]
+        //                 | "::" [ hexpost ]
+        //   hexpost     = hexseq | hexseq ":" IPv4address | IPv4address
+        //   hexseq      = hex4 *( ":" hex4)
+        //   hex4        = 1*4HEXDIG
+        //
+        // This covers all and only the following cases:
+        //
+        //   hexseq
+        //   hexseq : IPv4address
+        //   hexseq ::
+        //   hexseq :: hexseq
+        //   hexseq :: hexseq : IPv4address
+        //   hexseq :: IPv4address
+        //   :: hexseq
+        //   :: hexseq : IPv4address
+        //   :: IPv4address
+        //   ::
+        //
+        // Additionally we constrain the IPv6 address as follows :-
+        //
+        //  i.  IPv6 addresses without compressed zeros should contain
+        //      exactly 16 bytes.
+        //
+        //  ii. IPv6 addresses with compressed zeros should contain
+        //      less than 16 bytes.
+
+        private int ipv6byteCount = 0;
+
+        private int parseIPv6Reference(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+            boolean compressedZeros = false;
+
+            q = scanHexSeq(p, n);
+
+            if (q > p) {
+                p = q;
+                if (at(p, n, "::")) {
+                    compressedZeros = true;
+                    p = scanHexPost(p + 2, n);
+                } else if (at(p, n, ':')) {
+                    p = takeIPv4Address(p + 1,  n, "IPv4 address");
+                    ipv6byteCount += 4;
+                }
+            } else if (at(p, n, "::")) {
+                compressedZeros = true;
+                p = scanHexPost(p + 2, n);
+            }
+            if (p < n)
+                fail("Malformed IPv6 address", start);
+            if (ipv6byteCount > 16)
+                fail("IPv6 address too long", start);
+            if (!compressedZeros && ipv6byteCount < 16)
+                fail("IPv6 address too short", start);
+            if (compressedZeros && ipv6byteCount == 16)
+                fail("Malformed IPv6 address", start);
+
+            return p;
+        }
+
+        private int scanHexPost(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+
+            if (p == n)
+                return p;
+
+            q = scanHexSeq(p, n);
+            if (q > p) {
+                p = q;
+                if (at(p, n, ':')) {
+                    p++;
+                    p = takeIPv4Address(p, n, "hex digits or IPv4 address");
+                    ipv6byteCount += 4;
+                }
+            } else {
+                p = takeIPv4Address(p, n, "hex digits or IPv4 address");
+                ipv6byteCount += 4;
+            }
+            return p;
+        }
+
+        // Scan a hex sequence; return -1 if one could not be scanned
+        //
+        private int scanHexSeq(int start, int n)
+            throws URISyntaxException
+        {
+            int p = start;
+            int q;
+
+            q = scan(p, n, L_HEX, H_HEX);
+            if (q <= p)
+                return -1;
+            if (at(q, n, '.'))          // Beginning of IPv4 address
+                return -1;
+            if (q > p + 4)
+                fail("IPv6 hexadecimal digit sequence too long", p);
+            ipv6byteCount += 2;
+            p = q;
+            while (p < n) {
+                if (!at(p, n, ':'))
+                    break;
+                if (at(p + 1, n, ':'))
+                    break;              // "::"
+                p++;
+                q = scan(p, n, L_HEX, H_HEX);
+                if (q <= p)
+                    failExpecting("digits for an IPv6 address", p);
+                if (at(q, n, '.')) {    // Beginning of IPv4 address
+                    p--;
+                    break;
+                }
+                if (q > p + 4)
+                    fail("IPv6 hexadecimal digit sequence too long", p);
+                ipv6byteCount += 2;
+                p = q;
+            }
+
+            return p;
+        }
+
+    }
+
+}
diff --git a/java/net/URISyntaxException.java b/java/net/URISyntaxException.java
new file mode 100644
index 0000000..8072c37
--- /dev/null
+++ b/java/net/URISyntaxException.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+
+/**
+ * Checked exception thrown to indicate that a string could not be parsed as a
+ * URI reference.
+ *
+ * @author Mark Reinhold
+ * @see URI
+ * @since 1.4
+ */
+
+public class URISyntaxException
+    extends Exception
+{
+    private static final long serialVersionUID = 2137979680897488891L;
+
+    private String input;
+    private int index;
+
+    /**
+     * Constructs an instance from the given input string, reason, and error
+     * index.
+     *
+     * @param  input   The input string
+     * @param  reason  A string explaining why the input could not be parsed
+     * @param  index   The index at which the parse error occurred,
+     *                 or {@code -1} if the index is not known
+     *
+     * @throws  NullPointerException
+     *          If either the input or reason strings are {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          If the error index is less than {@code -1}
+     */
+    public URISyntaxException(String input, String reason, int index) {
+        super(reason);
+        if ((input == null) || (reason == null))
+            throw new NullPointerException();
+        if (index < -1)
+            throw new IllegalArgumentException();
+        this.input = input;
+        this.index = index;
+    }
+
+    /**
+     * Constructs an instance from the given input string and reason.  The
+     * resulting object will have an error index of {@code -1}.
+     *
+     * @param  input   The input string
+     * @param  reason  A string explaining why the input could not be parsed
+     *
+     * @throws  NullPointerException
+     *          If either the input or reason strings are {@code null}
+     */
+    public URISyntaxException(String input, String reason) {
+        this(input, reason, -1);
+    }
+
+    /**
+     * Returns the input string.
+     *
+     * @return  The input string
+     */
+    public String getInput() {
+        return input;
+    }
+
+    /**
+     * Returns a string explaining why the input string could not be parsed.
+     *
+     * @return  The reason string
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns an index into the input string of the position at which the
+     * parse error occurred, or {@code -1} if this position is not known.
+     *
+     * @return  The error index
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Returns a string describing the parse error.  The resulting string
+     * consists of the reason string followed by a colon character
+     * ({@code ':'}), a space, and the input string.  If the error index is
+     * defined then the string {@code " at index "} followed by the index, in
+     * decimal, is inserted after the reason string and before the colon
+     * character.
+     *
+     * @return  A string describing the parse error
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getReason());
+        if (index > -1) {
+            sb.append(" at index ");
+            sb.append(index);
+        }
+        sb.append(": ");
+        sb.append(input);
+        return sb.toString();
+    }
+
+}
diff --git a/java/net/URL.java b/java/net/URL.java
new file mode 100644
index 0000000..74dec92
--- /dev/null
+++ b/java/net/URL.java
@@ -0,0 +1,1627 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream.GetField;
+import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.StringTokenizer;
+import sun.security.util.SecurityConstants;
+
+/**
+ * Class {@code URL} represents a Uniform Resource
+ * Locator, a pointer to a "resource" on the World
+ * Wide Web. A resource can be something as simple as a file or a
+ * directory, or it can be a reference to a more complicated object,
+ * such as a query to a database or to a search engine. More
+ * information on the types of URLs and their formats can be found at:
+ * <a href=
+ * "http://web.archive.org/web/20051219043731/http://archive.ncsa.uiuc.edu/SDG/Software/Mosaic/Demo/url-primer.html">
+ * <i>Types of URL</i></a>
+ * <p>
+ * In general, a URL can be broken into several parts. Consider the
+ * following example:
+ * <blockquote><pre>
+ *     http://www.example.com/docs/resource1.html
+ * </pre></blockquote>
+ * <p>
+ * The URL above indicates that the protocol to use is
+ * {@code http} (HyperText Transfer Protocol) and that the
+ * information resides on a host machine named
+ * {@code www.example.com}. The information on that host
+ * machine is named {@code /docs/resource1.html}. The exact
+ * meaning of this name on the host machine is both protocol
+ * dependent and host dependent. The information normally resides in
+ * a file, but it could be generated on the fly. This component of
+ * the URL is called the <i>path</i> component.
+ * <p>
+ * A URL can optionally specify a "port", which is the
+ * port number to which the TCP connection is made on the remote host
+ * machine. If the port is not specified, the default port for
+ * the protocol is used instead. For example, the default port for
+ * {@code http} is {@code 80}. An alternative port could be
+ * specified as:
+ * <blockquote><pre>
+ *     http://www.example.com:1080/docs/resource1.html
+ * </pre></blockquote>
+ * <p>
+ * The syntax of {@code URL} is defined by  <a
+ * href="http://www.ietf.org/rfc/rfc2396.txt"><i>RFC&nbsp;2396: Uniform
+ * Resource Identifiers (URI): Generic Syntax</i></a>, amended by <a
+ * href="http://www.ietf.org/rfc/rfc2732.txt"><i>RFC&nbsp;2732: Format for
+ * Literal IPv6 Addresses in URLs</i></a>. The Literal IPv6 address format
+ * also supports scope_ids. The syntax and usage of scope_ids is described
+ * <a href="Inet6Address.html#scoped">here</a>.
+ * <p>
+ * A URL may have appended to it a "fragment", also known
+ * as a "ref" or a "reference". The fragment is indicated by the sharp
+ * sign character "#" followed by more characters. For example,
+ * <blockquote><pre>
+ *     http://java.sun.com/index.html#chapter1
+ * </pre></blockquote>
+ * <p>
+ * This fragment is not technically part of the URL. Rather, it
+ * indicates that after the specified resource is retrieved, the
+ * application is specifically interested in that part of the
+ * document that has the tag {@code chapter1} attached to it. The
+ * meaning of a tag is resource specific.
+ * <p>
+ * An application can also specify a "relative URL",
+ * which contains only enough information to reach the resource
+ * relative to another URL. Relative URLs are frequently used within
+ * HTML pages. For example, if the contents of the URL:
+ * <blockquote><pre>
+ *     http://java.sun.com/index.html
+ * </pre></blockquote>
+ * contained within it the relative URL:
+ * <blockquote><pre>
+ *     FAQ.html
+ * </pre></blockquote>
+ * it would be a shorthand for:
+ * <blockquote><pre>
+ *     http://java.sun.com/FAQ.html
+ * </pre></blockquote>
+ * <p>
+ * The relative URL need not specify all the components of a URL. If
+ * the protocol, host name, or port number is missing, the value is
+ * inherited from the fully specified URL. The file component must be
+ * specified. The optional fragment is not inherited.
+ * <p>
+ * The URL class does not itself encode or decode any URL components
+ * according to the escaping mechanism defined in RFC2396. It is the
+ * responsibility of the caller to encode any fields, which need to be
+ * escaped prior to calling URL, and also to decode any escaped fields,
+ * that are returned from URL. Furthermore, because URL has no knowledge
+ * of URL escaping, it does not recognise equivalence between the encoded
+ * or decoded form of the same URL. For example, the two URLs:<br>
+ * <pre>    http://foo.com/hello world/ and http://foo.com/hello%20world</pre>
+ * would be considered not equal to each other.
+ * <p>
+ * Note, the {@link java.net.URI} class does perform escaping of its
+ * component fields in certain circumstances. The recommended way
+ * to manage the encoding and decoding of URLs is to use {@link java.net.URI},
+ * and to convert between these two classes using {@link #toURI()} and
+ * {@link URI#toURL()}.
+ * <p>
+ * The {@link URLEncoder} and {@link URLDecoder} classes can also be
+ * used, but only for HTML form encoding, which is not the same
+ * as the encoding scheme defined in RFC2396.
+ *
+ * @author  James Gosling
+ * @since JDK1.0
+ */
+public final class URL implements java.io.Serializable {
+
+    // Android-changed: Custom built-in URLStreamHandlers for http, https.
+    // static final String BUILTIN_HANDLERS_PREFIX = "sun.net.www.protocol";
+    private static final Set<String> BUILTIN_HANDLER_CLASS_NAMES = createBuiltinHandlerClassNames();
+    static final long serialVersionUID = -7627629688361524110L;
+
+    /**
+     * The property which specifies the package prefix list to be scanned
+     * for protocol handlers.  The value of this property (if any) should
+     * be a vertical bar delimited list of package names to search through
+     * for a protocol handler to load.  The policy of this class is that
+     * all protocol handlers will be in a class called <protocolname>.Handler,
+     * and each package in the list is examined in turn for a matching
+     * handler.  If none are found (or the property is not specified), the
+     * default package prefix, sun.net.www.protocol, is used.  The search
+     * proceeds from the first package in the list to the last and stops
+     * when a match is found.
+     */
+    private static final String protocolPathProp = "java.protocol.handler.pkgs";
+
+    /**
+     * The protocol to use (ftp, http, nntp, ... etc.) .
+     * @serial
+     */
+    private String protocol;
+
+    /**
+     * The host name to connect to.
+     * @serial
+     */
+    private String host;
+
+    /**
+     * The protocol port to connect to.
+     * @serial
+     */
+    private int port = -1;
+
+    /**
+     * The specified file name on that host. {@code file} is
+     * defined as {@code path[?query]}
+     * @serial
+     */
+    private String file;
+
+    /**
+     * The query part of this URL.
+     */
+    private transient String query;
+
+    /**
+     * The authority part of this URL.
+     * @serial
+     */
+    private String authority;
+
+    /**
+     * The path part of this URL.
+     */
+    private transient String path;
+
+    /**
+     * The userinfo part of this URL.
+     */
+    private transient String userInfo;
+
+    /**
+     * # reference.
+     * @serial
+     */
+    private String ref;
+
+    /**
+     * The host's IP address, used in equals and hashCode.
+     * Computed on demand. An uninitialized or unknown hostAddress is null.
+     */
+    transient InetAddress hostAddress;
+
+    /**
+     * The URLStreamHandler for this URL.
+     */
+    transient URLStreamHandler handler;
+
+    /* Our hash code.
+     * @serial
+     */
+    private int hashCode = -1;
+
+    private transient UrlDeserializedState tempState;
+
+    /**
+     * Creates a {@code URL} object from the specified
+     * {@code protocol}, {@code host}, {@code port}
+     * number, and {@code file}.<p>
+     *
+     * {@code host} can be expressed as a host name or a literal
+     * IP address. If IPv6 literal address is used, it should be
+     * enclosed in square brackets ({@code '['} and {@code ']'}), as
+     * specified by <a
+     * href="http://www.ietf.org/rfc/rfc2732.txt">RFC&nbsp;2732</a>;
+     * However, the literal IPv6 address format defined in <a
+     * href="http://www.ietf.org/rfc/rfc2373.txt"><i>RFC&nbsp;2373: IP
+     * Version 6 Addressing Architecture</i></a> is also accepted.<p>
+     *
+     * Specifying a {@code port} number of {@code -1}
+     * indicates that the URL should use the default port for the
+     * protocol.<p>
+     *
+     * If this is the first URL object being created with the specified
+     * protocol, a <i>stream protocol handler</i> object, an instance of
+     * class {@code URLStreamHandler}, is created for that protocol:
+     * <ol>
+     * <li>If the application has previously set up an instance of
+     *     {@code URLStreamHandlerFactory} as the stream handler factory,
+     *     then the {@code createURLStreamHandler} method of that instance
+     *     is called with the protocol string as an argument to create the
+     *     stream protocol handler.
+     * <li>If no {@code URLStreamHandlerFactory} has yet been set up,
+     *     or if the factory's {@code createURLStreamHandler} method
+     *     returns {@code null}, then the constructor finds the
+     *     value of the system property:
+     *     <blockquote><pre>
+     *         java.protocol.handler.pkgs
+     *     </pre></blockquote>
+     *     If the value of that system property is not {@code null},
+     *     it is interpreted as a list of packages separated by a vertical
+     *     slash character '{@code |}'. The constructor tries to load
+     *     the class named:
+     *     <blockquote><pre>
+     *         &lt;<i>package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
+     *     </pre></blockquote>
+     *     where &lt;<i>package</i>&gt; is replaced by the name of the package
+     *     and &lt;<i>protocol</i>&gt; is replaced by the name of the protocol.
+     *     If this class does not exist, or if the class exists but it is not
+     *     a subclass of {@code URLStreamHandler}, then the next package
+     *     in the list is tried.
+     * <li>If the previous step fails to find a protocol handler, then the
+     *     constructor tries to load from a system default package.
+     *     <blockquote><pre>
+     *         &lt;<i>system default package</i>&gt;.&lt;<i>protocol</i>&gt;.Handler
+     *     </pre></blockquote>
+     *     If this class does not exist, or if the class exists but it is not a
+     *     subclass of {@code URLStreamHandler}, then a
+     *     {@code MalformedURLException} is thrown.
+     * </ol>
+     *
+     * <p>Protocol handlers for the following protocols are guaranteed
+     * to exist on the search path :-
+     * <blockquote><pre>
+     *     http, https, file, and jar
+     * </pre></blockquote>
+     * Protocol handlers for additional protocols may also be
+     * available.
+     *
+     * <p>No validation of the inputs is performed by this constructor.
+     *
+     * @param      protocol   the name of the protocol to use.
+     * @param      host       the name of the host.
+     * @param      port       the port number on the host.
+     * @param      file       the file on the host
+     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @see        java.lang.System#getProperty(java.lang.String)
+     * @see        java.net.URL#setURLStreamHandlerFactory(
+     *                  java.net.URLStreamHandlerFactory)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
+     *                  java.lang.String)
+     */
+    public URL(String protocol, String host, int port, String file)
+        throws MalformedURLException
+    {
+        this(protocol, host, port, file, null);
+    }
+
+    /**
+     * Creates a URL from the specified {@code protocol}
+     * name, {@code host} name, and {@code file} name. The
+     * default port for the specified protocol is used.
+     * <p>
+     * This method is equivalent to calling the four-argument
+     * constructor with the arguments being {@code protocol},
+     * {@code host}, {@code -1}, and {@code file}.
+     *
+     * No validation of the inputs is performed by this constructor.
+     *
+     * @param      protocol   the name of the protocol to use.
+     * @param      host       the name of the host.
+     * @param      file       the file on the host.
+     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     */
+    public URL(String protocol, String host, String file)
+            throws MalformedURLException {
+        this(protocol, host, -1, file);
+    }
+
+    /**
+     * Creates a {@code URL} object from the specified
+     * {@code protocol}, {@code host}, {@code port}
+     * number, {@code file}, and {@code handler}. Specifying
+     * a {@code port} number of {@code -1} indicates that
+     * the URL should use the default port for the protocol. Specifying
+     * a {@code handler} of {@code null} indicates that the URL
+     * should use a default stream handler for the protocol, as outlined
+     * for:
+     *     java.net.URL#URL(java.lang.String, java.lang.String, int,
+     *                      java.lang.String)
+     *
+     * <p>If the handler is not null and there is a security manager,
+     * the security manager's {@code checkPermission}
+     * method is called with a
+     * {@code NetPermission("specifyStreamHandler")} permission.
+     * This may result in a SecurityException.
+     *
+     * No validation of the inputs is performed by this constructor.
+     *
+     * @param      protocol   the name of the protocol to use.
+     * @param      host       the name of the host.
+     * @param      port       the port number on the host.
+     * @param      file       the file on the host
+     * @param      handler    the stream handler for the URL.
+     * @exception  MalformedURLException  if an unknown protocol is specified.
+     * @exception  SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        specifying a stream handler explicitly.
+     * @see        java.lang.System#getProperty(java.lang.String)
+     * @see        java.net.URL#setURLStreamHandlerFactory(
+     *                  java.net.URLStreamHandlerFactory)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandlerFactory#createURLStreamHandler(
+     *                  java.lang.String)
+     * @see        SecurityManager#checkPermission
+     * @see        java.net.NetPermission
+     */
+    public URL(String protocol, String host, int port, String file,
+               URLStreamHandler handler) throws MalformedURLException {
+        if (handler != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                // check for permission to specify a handler
+                checkSpecifyHandler(sm);
+            }
+        }
+
+        protocol = protocol.toLowerCase();
+        this.protocol = protocol;
+        if (host != null) {
+
+            /**
+             * if host is a literal IPv6 address,
+             * we will make it conform to RFC 2732
+             */
+            if (host.indexOf(':') >= 0 && !host.startsWith("[")) {
+                host = "["+host+"]";
+            }
+            this.host = host;
+
+            if (port < -1) {
+                throw new MalformedURLException("Invalid port number :" +
+                                                    port);
+            }
+            this.port = port;
+            authority = (port == -1) ? host : host + ":" + port;
+        }
+
+        // Android-changed: App compat. Prepend '/' if host is null / empty
+        // Parts parts = new Parts(file);
+        Parts parts = new Parts(file, host);
+        path = parts.getPath();
+        query = parts.getQuery();
+
+        if (query != null) {
+            this.file = path + "?" + query;
+        } else {
+            this.file = path;
+        }
+        ref = parts.getRef();
+
+        // Note: we don't do validation of the URL here. Too risky to change
+        // right now, but worth considering for future reference. -br
+        if (handler == null &&
+            (handler = getURLStreamHandler(protocol)) == null) {
+            throw new MalformedURLException("unknown protocol: " + protocol);
+        }
+        this.handler = handler;
+    }
+
+    /**
+     * Creates a {@code URL} object from the {@code String}
+     * representation.
+     * <p>
+     * This constructor is equivalent to a call to the two-argument
+     * constructor with a {@code null} first argument.
+     *
+     * @param      spec   the {@code String} to parse as a URL.
+     * @exception  MalformedURLException  if no protocol is specified, or an
+     *               unknown protocol is found, or {@code spec} is {@code null}.
+     * @see        java.net.URL#URL(java.net.URL, java.lang.String)
+     */
+    public URL(String spec) throws MalformedURLException {
+        this(null, spec);
+    }
+
+    /**
+     * Creates a URL by parsing the given spec within a specified context.
+     *
+     * The new URL is created from the given context URL and the spec
+     * argument as described in
+     * RFC2396 &quot;Uniform Resource Identifiers : Generic * Syntax&quot; :
+     * <blockquote><pre>
+     *          &lt;scheme&gt;://&lt;authority&gt;&lt;path&gt;?&lt;query&gt;#&lt;fragment&gt;
+     * </pre></blockquote>
+     * The reference is parsed into the scheme, authority, path, query and
+     * fragment parts. If the path component is empty and the scheme,
+     * authority, and query components are undefined, then the new URL is a
+     * reference to the current document. Otherwise, the fragment and query
+     * parts present in the spec are used in the new URL.
+     * <p>
+     * If the scheme component is defined in the given spec and does not match
+     * the scheme of the context, then the new URL is created as an absolute
+     * URL based on the spec alone. Otherwise the scheme component is inherited
+     * from the context URL.
+     * <p>
+     * If the authority component is present in the spec then the spec is
+     * treated as absolute and the spec authority and path will replace the
+     * context authority and path. If the authority component is absent in the
+     * spec then the authority of the new URL will be inherited from the
+     * context.
+     * <p>
+     * If the spec's path component begins with a slash character
+     * &quot;/&quot; then the
+     * path is treated as absolute and the spec path replaces the context path.
+     * <p>
+     * Otherwise, the path is treated as a relative path and is appended to the
+     * context path, as described in RFC2396. Also, in this case,
+     * the path is canonicalized through the removal of directory
+     * changes made by occurrences of &quot;..&quot; and &quot;.&quot;.
+     * <p>
+     * For a more detailed description of URL parsing, refer to RFC2396.
+     *
+     * @param      context   the context in which to parse the specification.
+     * @param      spec      the {@code String} to parse as a URL.
+     * @exception  MalformedURLException  if no protocol is specified, or an
+     *               unknown protocol is found, or {@code spec} is {@code null}.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
+     *                  java.lang.String, int, int)
+     */
+    public URL(URL context, String spec) throws MalformedURLException {
+        this(context, spec, null);
+    }
+
+    /**
+     * Creates a URL by parsing the given spec with the specified handler
+     * within a specified context. If the handler is null, the parsing
+     * occurs as with the two argument constructor.
+     *
+     * @param      context   the context in which to parse the specification.
+     * @param      spec      the {@code String} to parse as a URL.
+     * @param      handler   the stream handler for the URL.
+     * @exception  MalformedURLException  if no protocol is specified, or an
+     *               unknown protocol is found, or {@code spec} is {@code null}.
+     * @exception  SecurityException
+     *        if a security manager exists and its
+     *        {@code checkPermission} method doesn't allow
+     *        specifying a stream handler.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     * @see        java.net.URLStreamHandler
+     * @see        java.net.URLStreamHandler#parseURL(java.net.URL,
+     *                  java.lang.String, int, int)
+     */
+    public URL(URL context, String spec, URLStreamHandler handler)
+        throws MalformedURLException
+    {
+        String original = spec;
+        int i, limit, c;
+        int start = 0;
+        String newProtocol = null;
+        boolean aRef=false;
+        boolean isRelative = false;
+
+        // Check for permission to specify a handler
+        if (handler != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                checkSpecifyHandler(sm);
+            }
+        }
+
+        try {
+            limit = spec.length();
+            while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
+                limit--;        //eliminate trailing whitespace
+            }
+            while ((start < limit) && (spec.charAt(start) <= ' ')) {
+                start++;        // eliminate leading whitespace
+            }
+
+            if (spec.regionMatches(true, start, "url:", 0, 4)) {
+                start += 4;
+            }
+            if (start < spec.length() && spec.charAt(start) == '#') {
+                /* we're assuming this is a ref relative to the context URL.
+                 * This means protocols cannot start w/ '#', but we must parse
+                 * ref URL's like: "hello:there" w/ a ':' in them.
+                 */
+                aRef=true;
+            }
+            for (i = start ; !aRef && (i < limit) &&
+                     ((c = spec.charAt(i)) != '/') ; i++) {
+                if (c == ':') {
+
+                    String s = spec.substring(start, i).toLowerCase();
+                    if (isValidProtocol(s)) {
+                        newProtocol = s;
+                        start = i + 1;
+                    }
+                    break;
+                }
+            }
+
+            // Only use our context if the protocols match.
+            protocol = newProtocol;
+            if ((context != null) && ((newProtocol == null) ||
+                            newProtocol.equalsIgnoreCase(context.protocol))) {
+                // inherit the protocol handler from the context
+                // if not specified to the constructor
+                if (handler == null) {
+                    handler = context.handler;
+                }
+
+                // If the context is a hierarchical URL scheme and the spec
+                // contains a matching scheme then maintain backwards
+                // compatibility and treat it as if the spec didn't contain
+                // the scheme; see 5.2.3 of RFC2396
+                if (context.path != null && context.path.startsWith("/"))
+                    newProtocol = null;
+
+                if (newProtocol == null) {
+                    protocol = context.protocol;
+                    authority = context.authority;
+                    userInfo = context.userInfo;
+                    host = context.host;
+                    port = context.port;
+                    file = context.file;
+                    path = context.path;
+                    isRelative = true;
+                }
+            }
+
+            if (protocol == null) {
+                throw new MalformedURLException("no protocol: "+original);
+            }
+
+            // Get the protocol handler if not specified or the protocol
+            // of the context could not be used
+            if (handler == null &&
+                (handler = getURLStreamHandler(protocol)) == null) {
+                throw new MalformedURLException("unknown protocol: "+protocol);
+            }
+
+            this.handler = handler;
+
+            i = spec.indexOf('#', start);
+            if (i >= 0) {
+                ref = spec.substring(i + 1, limit);
+                limit = i;
+            }
+
+            /*
+             * Handle special case inheritance of query and fragment
+             * implied by RFC2396 section 5.2.2.
+             */
+            if (isRelative && start == limit) {
+                query = context.query;
+                if (ref == null) {
+                    ref = context.ref;
+                }
+            }
+
+            handler.parseURL(this, spec, start, limit);
+
+        } catch(MalformedURLException e) {
+            throw e;
+        } catch(Exception e) {
+            MalformedURLException exception = new MalformedURLException(e.getMessage());
+            exception.initCause(e);
+            throw exception;
+        }
+    }
+
+    /*
+     * Returns true if specified string is a valid protocol name.
+     */
+    private boolean isValidProtocol(String protocol) {
+        int len = protocol.length();
+        if (len < 1)
+            return false;
+        char c = protocol.charAt(0);
+        if (!Character.isLetter(c))
+            return false;
+        for (int i = 1; i < len; i++) {
+            c = protocol.charAt(i);
+            if (!Character.isLetterOrDigit(c) && c != '.' && c != '+' &&
+                c != '-') {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Checks for permission to specify a stream handler.
+     */
+    private void checkSpecifyHandler(SecurityManager sm) {
+        sm.checkPermission(SecurityConstants.SPECIFY_HANDLER_PERMISSION);
+    }
+
+    /**
+     * Sets the fields of the URL. This is not a public method so that
+     * only URLStreamHandlers can modify URL fields. URLs are
+     * otherwise constant.
+     *
+     * @param protocol the name of the protocol to use
+     * @param host the name of the host
+       @param port the port number on the host
+     * @param file the file on the host
+     * @param ref the internal reference in the URL
+     */
+    void set(String protocol, String host, int port,
+             String file, String ref) {
+        synchronized (this) {
+            this.protocol = protocol;
+            this.host = host;
+            authority = port == -1 ? host : host + ":" + port;
+            this.port = port;
+            this.file = file;
+            this.ref = ref;
+            /* This is very important. We must recompute this after the
+             * URL has been changed. */
+            hashCode = -1;
+            hostAddress = null;
+            int q = file.lastIndexOf('?');
+            if (q != -1) {
+                query = file.substring(q+1);
+                path = file.substring(0, q);
+            } else
+                path = file;
+        }
+    }
+
+    /**
+     * Sets the specified 8 fields of the URL. This is not a public method so
+     * that only URLStreamHandlers can modify URL fields. URLs are otherwise
+     * constant.
+     *
+     * @param protocol the name of the protocol to use
+     * @param host the name of the host
+     * @param port the port number on the host
+     * @param authority the authority part for the url
+     * @param userInfo the username and password
+     * @param path the file on the host
+     * @param ref the internal reference in the URL
+     * @param query the query part of this URL
+     * @since 1.3
+     */
+    void set(String protocol, String host, int port,
+             String authority, String userInfo, String path,
+             String query, String ref) {
+        synchronized (this) {
+            this.protocol = protocol;
+            this.host = host;
+            this.port = port;
+            // Android-changed: App compat. Only include query part if it's nonempty.
+            // this.file = query == null ? path : path + "?" + query;
+            this.file = (query == null || query.isEmpty()) ? path : path + "?" + query;
+            this.userInfo = userInfo;
+            this.path = path;
+            this.ref = ref;
+            /* This is very important. We must recompute this after the
+             * URL has been changed. */
+            hashCode = -1;
+            hostAddress = null;
+            this.query = query;
+            this.authority = authority;
+        }
+    }
+
+    /**
+     * Gets the query part of this {@code URL}.
+     *
+     * @return  the query part of this {@code URL},
+     * or <CODE>null</CODE> if one does not exist
+     * @since 1.3
+     */
+    public String getQuery() {
+        return query;
+    }
+
+    /**
+     * Gets the path part of this {@code URL}.
+     *
+     * @return  the path part of this {@code URL}, or an
+     * empty string if one does not exist
+     * @since 1.3
+     */
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Gets the userInfo part of this {@code URL}.
+     *
+     * @return  the userInfo part of this {@code URL}, or
+     * <CODE>null</CODE> if one does not exist
+     * @since 1.3
+     */
+    public String getUserInfo() {
+        return userInfo;
+    }
+
+    /**
+     * Gets the authority part of this {@code URL}.
+     *
+     * @return  the authority part of this {@code URL}
+     * @since 1.3
+     */
+    public String getAuthority() {
+        return authority;
+    }
+
+    /**
+     * Gets the port number of this {@code URL}.
+     *
+     * @return  the port number, or -1 if the port is not set
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Gets the default port number of the protocol associated
+     * with this {@code URL}. If the URL scheme or the URLStreamHandler
+     * for the URL do not define a default port number,
+     * then -1 is returned.
+     *
+     * @return  the port number
+     * @since 1.4
+     */
+    public int getDefaultPort() {
+        return handler.getDefaultPort();
+    }
+
+    /**
+     * Gets the protocol name of this {@code URL}.
+     *
+     * @return  the protocol of this {@code URL}.
+     */
+    public String getProtocol() {
+        return protocol;
+    }
+
+    /**
+     * Gets the host name of this {@code URL}, if applicable.
+     * The format of the host conforms to RFC 2732, i.e. for a
+     * literal IPv6 address, this method will return the IPv6 address
+     * enclosed in square brackets ({@code '['} and {@code ']'}).
+     *
+     * @return  the host name of this {@code URL}.
+     */
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * Gets the file name of this {@code URL}.
+     * The returned file portion will be
+     * the same as <CODE>getPath()</CODE>, plus the concatenation of
+     * the value of <CODE>getQuery()</CODE>, if any. If there is
+     * no query portion, this method and <CODE>getPath()</CODE> will
+     * return identical results.
+     *
+     * @return  the file name of this {@code URL},
+     * or an empty string if one does not exist
+     */
+    public String getFile() {
+        return file;
+    }
+
+    /**
+     * Gets the anchor (also known as the "reference") of this
+     * {@code URL}.
+     *
+     * @return  the anchor (also known as the "reference") of this
+     *          {@code URL}, or <CODE>null</CODE> if one does not exist
+     */
+    public String getRef() {
+        return ref;
+    }
+
+    // Android-changed: Don't let URL.equals() attempt to resolve host names.
+    /**
+     * Compares this URL for equality with another object.<p>
+     *
+     * If the given object is not a URL then this method immediately returns
+     * {@code false}.<p>
+     *
+     * Two URL objects are equal if they have the same protocol, reference
+     * equivalent hosts, have the same port number on the host, and the same
+     * file and fragment of the file.<p>
+     *
+     * Returns true if this URL equals {@code o}. URLs are equal if they have
+     * the same protocol, host, port, file, and reference.
+     *
+     * <h3>Network I/O Warning</h3>
+     * <p>Some implementations of URL.equals() resolve host names over the
+     * network. This is problematic:
+     * <ul>
+     * <li><strong>The network may be slow.</strong> Many classes, including
+     * core collections like {@link java.util.Map Map} and {@link java.util.Set
+     * Set} expect that {@code equals} and {@code hashCode} will return quickly.
+     * By violating this assumption, this method posed potential performance
+     * problems.
+     * <li><strong>Equal IP addresses do not imply equal content.</strong>
+     * Virtual hosting permits unrelated sites to share an IP address. This
+     * method could report two otherwise unrelated URLs to be equal because
+     * they're hosted on the same server.</li>
+     * <li><strong>The network may not be available.</strong> Two URLs could be
+     * equal when a network is available and unequal otherwise.</li>
+     * <li><strong>The network may change.</strong> The IP address for a given
+     * host name varies by network and over time. This is problematic for mobile
+     * devices. Two URLs could be equal on some networks and unequal on
+     * others.</li>
+     * </ul>
+     * <p>This problem is fixed in Android 4.0 (Ice Cream Sandwich). In that
+     * release, URLs are only equal if their host names are equal (ignoring
+     * case).
+     *
+     * @param   obj   the URL to compare against.
+     * @return  {@code true} if the objects are the same;
+     *          {@code false} otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof URL))
+            return false;
+        URL u2 = (URL)obj;
+
+        return handler.equals(this, u2);
+    }
+
+    /**
+     * Creates an integer suitable for hash table indexing.<p>
+     *
+     * The hash code is based upon all the URL components relevant for URL
+     * comparison. As such, this operation is a blocking operation.<p>
+     *
+     * @return  a hash code for this {@code URL}.
+     */
+    public synchronized int hashCode() {
+        if (hashCode != -1)
+            return hashCode;
+
+        hashCode = handler.hashCode(this);
+        return hashCode;
+    }
+
+    /**
+     * Compares two URLs, excluding the fragment component.<p>
+     *
+     * Returns {@code true} if this {@code URL} and the
+     * {@code other} argument are equal without taking the
+     * fragment component into consideration.
+     *
+     * @param   other   the {@code URL} to compare against.
+     * @return  {@code true} if they reference the same remote object;
+     *          {@code false} otherwise.
+     */
+    public boolean sameFile(URL other) {
+        return handler.sameFile(this, other);
+    }
+
+    /**
+     * Constructs a string representation of this {@code URL}. The
+     * string is created by calling the {@code toExternalForm}
+     * method of the stream protocol handler for this object.
+     *
+     * @return  a string representation of this object.
+     * @see     java.net.URL#URL(java.lang.String, java.lang.String, int,
+     *                  java.lang.String)
+     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
+     */
+    public String toString() {
+        return toExternalForm();
+    }
+
+    /**
+     * Constructs a string representation of this {@code URL}. The
+     * string is created by calling the {@code toExternalForm}
+     * method of the stream protocol handler for this object.
+     *
+     * @return  a string representation of this object.
+     * @see     java.net.URL#URL(java.lang.String, java.lang.String,
+     *                  int, java.lang.String)
+     * @see     java.net.URLStreamHandler#toExternalForm(java.net.URL)
+     */
+    public String toExternalForm() {
+        return handler.toExternalForm(this);
+    }
+
+    /**
+     * Returns a {@link java.net.URI} equivalent to this URL.
+     * This method functions in the same way as {@code new URI (this.toString())}.
+     * <p>Note, any URL instance that complies with RFC 2396 can be converted
+     * to a URI. However, some URLs that are not strictly in compliance
+     * can not be converted to a URI.
+     *
+     * @exception URISyntaxException if this URL is not formatted strictly according to
+     *            to RFC2396 and cannot be converted to a URI.
+     *
+     * @return    a URI instance equivalent to this URL.
+     * @since 1.5
+     */
+    public URI toURI() throws URISyntaxException {
+        return new URI (toString());
+    }
+
+    /**
+     * Returns a {@link java.net.URLConnection URLConnection} instance that
+     * represents a connection to the remote object referred to by the
+     * {@code URL}.
+     *
+     * <P>A new instance of {@linkplain java.net.URLConnection URLConnection} is
+     * created every time when invoking the
+     * {@linkplain java.net.URLStreamHandler#openConnection(URL)
+     * URLStreamHandler.openConnection(URL)} method of the protocol handler for
+     * this URL.</P>
+     *
+     * <P>It should be noted that a URLConnection instance does not establish
+     * the actual network connection on creation. This will happen only when
+     * calling {@linkplain java.net.URLConnection#connect() URLConnection.connect()}.</P>
+     *
+     * <P>If for the URL's protocol (such as HTTP or JAR), there
+     * exists a public, specialized URLConnection subclass belonging
+     * to one of the following packages or one of their subpackages:
+     * java.lang, java.io, java.util, java.net, the connection
+     * returned will be of that subclass. For example, for HTTP an
+     * HttpURLConnection will be returned, and for JAR a
+     * JarURLConnection will be returned.</P>
+     *
+     * @return     a {@link java.net.URLConnection URLConnection} linking
+     *             to the URL.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *             int, java.lang.String)
+     */
+    public URLConnection openConnection() throws java.io.IOException {
+        return handler.openConnection(this);
+    }
+
+    /**
+     * Same as {@link #openConnection()}, except that the connection will be
+     * made through the specified proxy; Protocol handlers that do not
+     * support proxing will ignore the proxy parameter and make a
+     * normal connection.
+     *
+     * Invoking this method preempts the system's default ProxySelector
+     * settings.
+     *
+     * @param      proxy the Proxy through which this connection
+     *             will be made. If direct connection is desired,
+     *             Proxy.NO_PROXY should be specified.
+     * @return     a {@code URLConnection} to the URL.
+     * @exception  IOException  if an I/O exception occurs.
+     * @exception  SecurityException if a security manager is present
+     *             and the caller doesn't have permission to connect
+     *             to the proxy.
+     * @exception  IllegalArgumentException will be thrown if proxy is null,
+     *             or proxy has the wrong type
+     * @exception  UnsupportedOperationException if the subclass that
+     *             implements the protocol handler doesn't support
+     *             this method.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *             int, java.lang.String)
+     * @see        java.net.URLConnection
+     * @see        java.net.URLStreamHandler#openConnection(java.net.URL,
+     *             java.net.Proxy)
+     * @since      1.5
+     */
+    public URLConnection openConnection(Proxy proxy)
+        throws java.io.IOException {
+        if (proxy == null) {
+            throw new IllegalArgumentException("proxy can not be null");
+        }
+
+        // Create a copy of Proxy as a security measure
+        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
+        SecurityManager sm = System.getSecurityManager();
+        if (p.type() != Proxy.Type.DIRECT && sm != null) {
+            InetSocketAddress epoint = (InetSocketAddress) p.address();
+            if (epoint.isUnresolved())
+                sm.checkConnect(epoint.getHostName(), epoint.getPort());
+            else
+                sm.checkConnect(epoint.getAddress().getHostAddress(),
+                                epoint.getPort());
+        }
+        return handler.openConnection(this, p);
+    }
+
+    /**
+     * Opens a connection to this {@code URL} and returns an
+     * {@code InputStream} for reading from that connection. This
+     * method is a shorthand for:
+     * <blockquote><pre>
+     *     openConnection().getInputStream()
+     * </pre></blockquote>
+     *
+     * @return     an input stream for reading from the URL connection.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URL#openConnection()
+     * @see        java.net.URLConnection#getInputStream()
+     */
+    public final InputStream openStream() throws java.io.IOException {
+        return openConnection().getInputStream();
+    }
+
+    /**
+     * Gets the contents of this URL. This method is a shorthand for:
+     * <blockquote><pre>
+     *     openConnection().getContent()
+     * </pre></blockquote>
+     *
+     * @return     the contents of this URL.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URLConnection#getContent()
+     */
+    public final Object getContent() throws java.io.IOException {
+        return openConnection().getContent();
+    }
+
+    /**
+     * Gets the contents of this URL. This method is a shorthand for:
+     * <blockquote><pre>
+     *     openConnection().getContent(Class[])
+     * </pre></blockquote>
+     *
+     * @param classes an array of Java types
+     * @return     the content object of this URL that is the first match of
+     *               the types specified in the classes array.
+     *               null if none of the requested types are supported.
+     * @exception  IOException  if an I/O exception occurs.
+     * @see        java.net.URLConnection#getContent(Class[])
+     * @since 1.3
+     */
+    public final Object getContent(Class[] classes)
+    throws java.io.IOException {
+        return openConnection().getContent(classes);
+    }
+
+    /**
+     * The URLStreamHandler factory.
+     */
+    static URLStreamHandlerFactory factory;
+
+    /**
+     * Sets an application's {@code URLStreamHandlerFactory}.
+     * This method can be called at most once in a given Java Virtual
+     * Machine.
+     *
+     *<p> The {@code URLStreamHandlerFactory} instance is used to
+     *construct a stream protocol handler from a protocol name.
+     *
+     * <p> If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  Error  if the application has already set a factory.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow
+     *             the operation.
+     * @see        java.net.URL#URL(java.lang.String, java.lang.String,
+     *             int, java.lang.String)
+     * @see        java.net.URLStreamHandlerFactory
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
+        synchronized (streamHandlerLock) {
+            if (factory != null) {
+                throw new Error("factory already defined");
+            }
+            SecurityManager security = System.getSecurityManager();
+            if (security != null) {
+                security.checkSetFactory();
+            }
+            handlers.clear();
+            factory = fac;
+        }
+    }
+
+    /**
+     * A table of protocol handlers.
+     */
+    static Hashtable<String,URLStreamHandler> handlers = new Hashtable<>();
+    private static Object streamHandlerLock = new Object();
+
+    /**
+     * Returns the Stream Handler.
+     * @param protocol the protocol to use
+     */
+    static URLStreamHandler getURLStreamHandler(String protocol) {
+
+        URLStreamHandler handler = handlers.get(protocol);
+        if (handler == null) {
+
+            boolean checkedWithFactory = false;
+
+            // Use the factory (if any)
+            if (factory != null) {
+                handler = factory.createURLStreamHandler(protocol);
+                checkedWithFactory = true;
+            }
+
+            // Try java protocol handler
+            if (handler == null) {
+                // Android-changed: Android doesn't need AccessController.
+                // Remove unnecessary use of reflection for sun classes
+                /*
+                packagePrefixList
+                    = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(
+                        protocolPathProp,""));
+                if (packagePrefixList != "") {
+                    packagePrefixList += "|";
+                }
+
+                // REMIND: decide whether to allow the "null" class prefix
+                // or not.
+                packagePrefixList += "sun.net.www.protocol";
+                 */
+                final String packagePrefixList = System.getProperty(protocolPathProp,"");
+
+                StringTokenizer packagePrefixIter =
+                    new StringTokenizer(packagePrefixList, "|");
+
+                while (handler == null &&
+                       packagePrefixIter.hasMoreTokens()) {
+
+                    String packagePrefix =
+                      packagePrefixIter.nextToken().trim();
+                    try {
+                        String clsName = packagePrefix + "." + protocol +
+                          ".Handler";
+                        Class<?> cls = null;
+                        try {
+                            ClassLoader cl = ClassLoader.getSystemClassLoader();
+                            // BEGIN Android-changed: Fall back to thread's contextClassLoader.
+                            // http://b/25897689
+                            cls = Class.forName(clsName, true, cl);
+                        } catch (ClassNotFoundException e) {
+                            ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+                            if (contextLoader != null) {
+                                cls = Class.forName(clsName, true, contextLoader);
+                            }
+                            // END Android-changed: Fall back to thread's contextClassLoader.
+                        }
+                        if (cls != null) {
+                            handler  =
+                              (URLStreamHandler)cls.newInstance();
+                        }
+                    } catch (ReflectiveOperationException ignored) {
+                    }
+                }
+            }
+
+            // BEGIN Android-added: Custom built-in URLStreamHandlers for http, https.
+            // Fallback to built-in stream handler.
+            if (handler == null) {
+                try {
+                    handler = createBuiltinHandler(protocol);
+                } catch (Exception e) {
+                    throw new AssertionError(e);
+                }
+            }
+            // END Android-added: Custom built-in URLStreamHandlers for http, https.
+
+            synchronized (streamHandlerLock) {
+
+                URLStreamHandler handler2 = null;
+
+                // Check again with hashtable just in case another
+                // thread created a handler since we last checked
+                handler2 = handlers.get(protocol);
+
+                if (handler2 != null) {
+                    return handler2;
+                }
+
+                // Check with factory if another thread set a
+                // factory since our last check
+                if (!checkedWithFactory && factory != null) {
+                    handler2 = factory.createURLStreamHandler(protocol);
+                }
+
+                if (handler2 != null) {
+                    // The handler from the factory must be given more
+                    // importance. Discard the default handler that
+                    // this thread created.
+                    handler = handler2;
+                }
+
+                // Insert this handler into the hashtable
+                if (handler != null) {
+                    handlers.put(protocol, handler);
+                }
+
+            }
+        }
+
+        return handler;
+
+    }
+
+    // BEGIN Android-added: Custom built-in URLStreamHandlers for http, https.
+    /**
+     * Returns an instance of the built-in handler for the given protocol, or null if none exists.
+     */
+    private static URLStreamHandler createBuiltinHandler(String protocol)
+            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+        URLStreamHandler handler = null;
+        if (protocol.equals("file")) {
+            handler = new sun.net.www.protocol.file.Handler();
+        } else if (protocol.equals("ftp")) {
+            handler = new sun.net.www.protocol.ftp.Handler();
+        } else if (protocol.equals("jar")) {
+            handler = new sun.net.www.protocol.jar.Handler();
+        } else if (protocol.equals("http")) {
+            handler = (URLStreamHandler)Class.
+                    forName("com.android.okhttp.HttpHandler").newInstance();
+        } else if (protocol.equals("https")) {
+            handler = (URLStreamHandler)Class.
+                    forName("com.android.okhttp.HttpsHandler").newInstance();
+        }
+        return handler;
+    }
+
+    /** Names of implementation classes returned by {@link #createBuiltinHandler(String)}. */
+    private static Set<String> createBuiltinHandlerClassNames() {
+        Set<String> result = new HashSet<>();
+        // Refer to class names rather than classes to avoid needlessly triggering <clinit>.
+        result.add("sun.net.www.protocol.file.Handler");
+        result.add("sun.net.www.protocol.ftp.Handler");
+        result.add("sun.net.www.protocol.jar.Handler");
+        result.add("com.android.okhttp.HttpHandler");
+        result.add("com.android.okhttp.HttpsHandler");
+        return Collections.unmodifiableSet(result);
+    }
+    // END Android-added: Custom built-in URLStreamHandlers for http, https.
+
+    /**
+     * @serialField    protocol String
+     *
+     * @serialField    host String
+     *
+     * @serialField    port int
+     *
+     * @serialField    authority String
+     *
+     * @serialField    file String
+     *
+     * @serialField    ref String
+     *
+     * @serialField    hashCode int
+     *
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("protocol", String.class),
+        new ObjectStreamField("host", String.class),
+        new ObjectStreamField("port", int.class),
+        new ObjectStreamField("authority", String.class),
+        new ObjectStreamField("file", String.class),
+        new ObjectStreamField("ref", String.class),
+    // Android-changed: App compat: hashCode should not be serialized.
+    //    new ObjectStreamField("hashCode", int.class), };
+    };
+
+    /**
+     * WriteObject is called to save the state of the URL to an
+     * ObjectOutputStream. The handler is not saved since it is
+     * specific to this system.
+     *
+     * @serialData the default write object value. When read back in,
+     * the reader must ensure that calling getURLStreamHandler with
+     * the protocol variable returns a valid URLStreamHandler and
+     * throw an IOException if it does not.
+     */
+    private synchronized void writeObject(java.io.ObjectOutputStream s)
+        throws IOException
+    {
+        s.defaultWriteObject(); // write the fields
+    }
+
+    /**
+     * readObject is called to restore the state of the URL from the
+     * stream.  It reads the components of the URL and finds the local
+     * stream handler.
+     */
+    private synchronized void readObject(java.io.ObjectInputStream s)
+            throws IOException, ClassNotFoundException {
+        GetField gf = s.readFields();
+        String protocol = (String)gf.get("protocol", null);
+        if (getURLStreamHandler(protocol) == null) {
+            throw new IOException("unknown protocol: " + protocol);
+        }
+        String host = (String)gf.get("host", null);
+        int port = gf.get("port", -1);
+        String authority = (String)gf.get("authority", null);
+        String file = (String)gf.get("file", null);
+        String ref = (String)gf.get("ref", null);
+        // Android-changed: App compat: hashCode should not be serialized.
+        // int hashCode = gf.get("hashCode", -1);
+        final int hashCode = -1;
+        if (authority == null
+                && ((host != null && host.length() > 0) || port != -1)) {
+            if (host == null)
+                host = "";
+            authority = (port == -1) ? host : host + ":" + port;
+        }
+        tempState = new UrlDeserializedState(protocol, host, port, authority,
+               file, ref, hashCode);
+    }
+
+    /**
+     * Replaces the de-serialized object with an URL object.
+     *
+     * @return a newly created object from the deserialzed state.
+     *
+     * @throws ObjectStreamException if a new object replacing this
+     * object could not be created
+     */
+
+   private Object readResolve() throws ObjectStreamException {
+
+        URLStreamHandler handler = null;
+        // already been checked in readObject
+        handler = getURLStreamHandler(tempState.getProtocol());
+
+        URL replacementURL = null;
+        if (isBuiltinStreamHandler(handler.getClass().getName())) {
+            replacementURL = fabricateNewURL();
+        } else {
+            replacementURL = setDeserializedFields(handler);
+        }
+        return replacementURL;
+    }
+
+    private URL setDeserializedFields(URLStreamHandler handler) {
+        URL replacementURL;
+        String userInfo = null;
+        String protocol = tempState.getProtocol();
+        String host = tempState.getHost();
+        int port = tempState.getPort();
+        String authority = tempState.getAuthority();
+        String file = tempState.getFile();
+        String ref = tempState.getRef();
+        int hashCode = tempState.getHashCode();
+
+
+        // Construct authority part
+        if (authority == null
+            && ((host != null && host.length() > 0) || port != -1)) {
+            if (host == null)
+                host = "";
+            authority = (port == -1) ? host : host + ":" + port;
+
+            // Handle hosts with userInfo in them
+            int at = host.lastIndexOf('@');
+            if (at != -1) {
+                userInfo = host.substring(0, at);
+                host = host.substring(at+1);
+            }
+        } else if (authority != null) {
+            // Construct user info part
+            int ind = authority.indexOf('@');
+            if (ind != -1)
+                userInfo = authority.substring(0, ind);
+        }
+
+        // Construct path and query part
+        String path = null;
+        String query = null;
+        if (file != null) {
+            // Fix: only do this if hierarchical?
+            int q = file.lastIndexOf('?');
+            if (q != -1) {
+                query = file.substring(q+1);
+                path = file.substring(0, q);
+            } else
+                path = file;
+        }
+
+        // Set the object fields.
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.file = file;
+        this.authority = authority;
+        this.ref = ref;
+        this.hashCode = hashCode;
+        this.handler = handler;
+        this.query = query;
+        this.path = path;
+        this.userInfo = userInfo;
+        replacementURL = this;
+        return replacementURL;
+    }
+
+    private URL fabricateNewURL()
+                throws InvalidObjectException {
+        // create URL string from deserialized object
+        URL replacementURL = null;
+        String urlString = tempState.reconstituteUrlString();
+
+        try {
+            replacementURL = new URL(urlString);
+        } catch (MalformedURLException mEx) {
+            resetState();
+            InvalidObjectException invoEx = new InvalidObjectException(
+                    "Malformed URL: " + urlString);
+            invoEx.initCause(mEx);
+            throw invoEx;
+        }
+        replacementURL.setSerializedHashCode(tempState.getHashCode());
+        resetState();
+        return replacementURL;
+    }
+
+    private boolean isBuiltinStreamHandler(String handlerClassName) {
+        // Android-changed: Some built-in handlers (eg. HttpHandler) are not in sun.net.www.protocol.
+        // return (handlerClassName.startsWith(BUILTIN_HANDLERS_PREFIX));
+        return BUILTIN_HANDLER_CLASS_NAMES.contains(handlerClassName);
+    }
+
+    private void resetState() {
+        this.protocol = null;
+        this.host = null;
+        this.port = -1;
+        this.file = null;
+        this.authority = null;
+        this.ref = null;
+        this.hashCode = -1;
+        this.handler = null;
+        this.query = null;
+        this.path = null;
+        this.userInfo = null;
+        this.tempState = null;
+    }
+
+    private void setSerializedHashCode(int hc) {
+        this.hashCode = hc;
+    }
+}
+
+class Parts {
+    String path, query, ref;
+
+    // Android-changed: App compat. Prepend '/' if host is null / empty.
+    // Parts(String file)
+    Parts(String file, String host) {
+        int ind = file.indexOf('#');
+        ref = ind < 0 ? null: file.substring(ind + 1);
+        file = ind < 0 ? file: file.substring(0, ind);
+        int q = file.lastIndexOf('?');
+        if (q != -1) {
+            query = file.substring(q+1);
+            path = file.substring(0, q);
+        } else {
+            path = file;
+        }
+        // BEGIN Android-changed: App compat. Prepend '/' if host is null / empty.
+        if (path != null && path.length() > 0 && path.charAt(0) != '/' &&
+            host != null && !host.isEmpty()) {
+            path = '/' + path;
+        }
+        // END Android-changed: App compat. Prepend '/' if host is null / empty.
+    }
+
+    String getPath() {
+        return path;
+    }
+
+    String getQuery() {
+        return query;
+    }
+
+    String getRef() {
+        return ref;
+    }
+}
+
+final class UrlDeserializedState {
+    private final String protocol;
+    private final String host;
+    private final int port;
+    private final String authority;
+    private final String file;
+    private final String ref;
+    private final int hashCode;
+
+    public UrlDeserializedState(String protocol,
+                                String host, int port,
+                                String authority, String file,
+                                String ref, int hashCode) {
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.authority = authority;
+        this.file = file;
+        this.ref = ref;
+        this.hashCode = hashCode;
+    }
+
+    String getProtocol() {
+        return protocol;
+    }
+
+    String getHost() {
+        return host;
+    }
+
+    String getAuthority () {
+        return authority;
+    }
+
+    int getPort() {
+        return port;
+    }
+
+    String getFile () {
+        return file;
+    }
+
+    String getRef () {
+        return ref;
+    }
+
+    int getHashCode () {
+        return hashCode;
+    }
+
+    String reconstituteUrlString() {
+
+        // pre-compute length of StringBuilder
+        int len = protocol.length() + 1;
+        if (authority != null && authority.length() > 0)
+            len += 2 + authority.length();
+        if (file != null) {
+            len += file.length();
+        }
+        if (ref != null)
+            len += 1 + ref.length();
+        StringBuilder result = new StringBuilder(len);
+        result.append(protocol);
+        result.append(":");
+        if (authority != null && authority.length() > 0) {
+            result.append("//");
+            result.append(authority);
+        }
+        if (file != null) {
+            result.append(file);
+        }
+        if (ref != null) {
+            result.append("#");
+            result.append(ref);
+        }
+        return result.toString();
+    }
+}
diff --git a/java/net/URLClassLoader.java b/java/net/URLClassLoader.java
new file mode 100644
index 0000000..6e8acb1
--- /dev/null
+++ b/java/net/URLClassLoader.java
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSigner;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureClassLoader;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import sun.misc.Resource;
+import sun.misc.URLClassPath;
+import sun.net.www.ParseUtil;
+import sun.security.util.SecurityConstants;
+
+/**
+ * This class loader is used to load classes and resources from a search
+ * path of URLs referring to both JAR files and directories. Any URL that
+ * ends with a '/' is assumed to refer to a directory. Otherwise, the URL
+ * is assumed to refer to a JAR file which will be opened as needed.
+ * <p>
+ * The AccessControlContext of the thread that created the instance of
+ * URLClassLoader will be used when subsequently loading classes and
+ * resources.
+ * <p>
+ * The classes that are loaded are by default granted permission only to
+ * access the URLs specified when the URLClassLoader was created.
+ *
+ * @author  David Connelly
+ * @since   1.2
+ */
+public class URLClassLoader extends SecureClassLoader implements Closeable {
+    /* The search path for classes and resources */
+    private final URLClassPath ucp;
+
+    /* The context to be used when loading classes and resources */
+    private final AccessControlContext acc;
+
+    /**
+     * Constructs a new URLClassLoader for the given URLs. The URLs will be
+     * searched in the order specified for classes and resources after first
+     * searching in the specified parent class loader. Any URL that ends with
+     * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed
+     * to refer to a JAR file which will be downloaded and opened as needed.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader} method
+     * to ensure creation of a class loader is allowed.
+     *
+     * @param urls the URLs from which to load classes and resources
+     * @param parent the parent class loader for delegation
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    public URLClassLoader(URL[] urls, ClassLoader parent) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    URLClassLoader(URL[] urls, ClassLoader parent,
+                   AccessControlContext acc) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = acc;
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    /**
+     * Constructs a new URLClassLoader for the specified URLs using the
+     * default delegation parent {@code ClassLoader}. The URLs will
+     * be searched in the order specified for classes and resources after
+     * first searching in the parent class loader. Any URL that ends with
+     * a '/' is assumed to refer to a directory. Otherwise, the URL is
+     * assumed to refer to a JAR file which will be downloaded and opened
+     * as needed.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader} method
+     * to ensure creation of a class loader is allowed.
+     *
+     * @param urls the URLs from which to load classes and resources
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    public URLClassLoader(URL[] urls) {
+        super();
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    URLClassLoader(URL[] urls, AccessControlContext acc) {
+        super();
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        this.acc = acc;
+        ucp = new URLClassPath(urls, acc);
+    }
+
+    /**
+     * Constructs a new URLClassLoader for the specified URLs, parent
+     * class loader, and URLStreamHandlerFactory. The parent argument
+     * will be used as the parent class loader for delegation. The
+     * factory argument will be used as the stream handler factory to
+     * obtain protocol handlers when creating new jar URLs.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader} method
+     * to ensure creation of a class loader is allowed.
+     *
+     * @param urls the URLs from which to load classes and resources
+     * @param parent the parent class loader for delegation
+     * @param factory the URLStreamHandlerFactory to use when creating URLs
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    public URLClassLoader(URL[] urls, ClassLoader parent,
+                          URLStreamHandlerFactory factory) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        acc = AccessController.getContext();
+        ucp = new URLClassPath(urls, factory, acc);
+    }
+
+    /* A map (used as a set) to keep track of closeable local resources
+     * (either JarFiles or FileInputStreams). We don't care about
+     * Http resources since they don't need to be closed.
+     *
+     * If the resource is coming from a jar file
+     * we keep a (weak) reference to the JarFile object which can
+     * be closed if URLClassLoader.close() called. Due to jar file
+     * caching there will typically be only one JarFile object
+     * per underlying jar file.
+     *
+     * For file resources, which is probably a less common situation
+     * we have to keep a weak reference to each stream.
+     */
+
+    private WeakHashMap<Closeable,Void>
+        closeables = new WeakHashMap<>();
+
+    /**
+     * Returns an input stream for reading the specified resource.
+     * If this loader is closed, then any resources opened by this method
+     * will be closed.
+     *
+     * <p> The search order is described in the documentation for {@link
+     * #getResource(String)}.  </p>
+     *
+     * @param  name
+     *         The resource name
+     *
+     * @return  An input stream for reading the resource, or {@code null}
+     *          if the resource could not be found
+     *
+     * @since  1.7
+     */
+    public InputStream getResourceAsStream(String name) {
+        URL url = getResource(name);
+        try {
+            if (url == null) {
+                return null;
+            }
+            URLConnection urlc = url.openConnection();
+            InputStream is = urlc.getInputStream();
+            if (urlc instanceof JarURLConnection) {
+                JarURLConnection juc = (JarURLConnection)urlc;
+                JarFile jar = juc.getJarFile();
+                synchronized (closeables) {
+                    if (!closeables.containsKey(jar)) {
+                        closeables.put(jar, null);
+                    }
+                }
+            } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
+                synchronized (closeables) {
+                    closeables.put(is, null);
+                }
+            }
+            return is;
+        } catch (IOException e) {
+            return null;
+        }
+    }
+
+   /**
+    * Closes this URLClassLoader, so that it can no longer be used to load
+    * new classes or resources that are defined by this loader.
+    * Classes and resources defined by any of this loader's parents in the
+    * delegation hierarchy are still accessible. Also, any classes or resources
+    * that are already loaded, are still accessible.
+    * <p>
+    * In the case of jar: and file: URLs, it also closes any files
+    * that were opened by it. If another thread is loading a
+    * class when the {@code close} method is invoked, then the result of
+    * that load is undefined.
+    * <p>
+    * The method makes a best effort attempt to close all opened files,
+    * by catching {@link IOException}s internally. Unchecked exceptions
+    * and errors are not caught. Calling close on an already closed
+    * loader has no effect.
+    * <p>
+    * @exception IOException if closing any file opened by this class loader
+    * resulted in an IOException. Any such exceptions are caught internally.
+    * If only one is caught, then it is re-thrown. If more than one exception
+    * is caught, then the second and following exceptions are added
+    * as suppressed exceptions of the first one caught, which is then re-thrown.
+    *
+    * @exception SecurityException if a security manager is set, and it denies
+    *   {@link RuntimePermission}{@code ("closeClassLoader")}
+    *
+    * @since 1.7
+    */
+    public void close() throws IOException {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(new RuntimePermission("closeClassLoader"));
+        }
+        List<IOException> errors = ucp.closeLoaders();
+
+        // now close any remaining streams.
+
+        synchronized (closeables) {
+            Set<Closeable> keys = closeables.keySet();
+            for (Closeable c : keys) {
+                try {
+                    c.close();
+                } catch (IOException ioex) {
+                    errors.add(ioex);
+                }
+            }
+            closeables.clear();
+        }
+
+        if (errors.isEmpty()) {
+            return;
+        }
+
+        IOException firstex = errors.remove(0);
+
+        // Suppress any remaining exceptions
+
+        for (IOException error: errors) {
+            firstex.addSuppressed(error);
+        }
+        throw firstex;
+    }
+
+    /**
+     * Appends the specified URL to the list of URLs to search for
+     * classes and resources.
+     * <p>
+     * If the URL specified is {@code null} or is already in the
+     * list of URLs, or if this loader is closed, then invoking this
+     * method has no effect.
+     *
+     * @param url the URL to be added to the search path of URLs
+     */
+    protected void addURL(URL url) {
+        ucp.addURL(url);
+    }
+
+    /**
+     * Returns the search path of URLs for loading classes and resources.
+     * This includes the original list of URLs specified to the constructor,
+     * along with any URLs subsequently appended by the addURL() method.
+     * @return the search path of URLs for loading classes and resources.
+     */
+    public URL[] getURLs() {
+        return ucp.getURLs();
+    }
+
+    /**
+     * Finds and loads the class with the specified name from the URL search
+     * path. Any URLs referring to JAR files are loaded and opened as needed
+     * until the class is found.
+     *
+     * @param name the name of the class
+     * @return the resulting class
+     * @exception ClassNotFoundException if the class could not be found,
+     *            or if the loader is closed.
+     * @exception NullPointerException if {@code name} is {@code null}.
+     */
+    protected Class<?> findClass(final String name)
+        throws ClassNotFoundException
+    {
+        final Class<?> result;
+        try {
+            result = AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Class<?>>() {
+                    public Class<?> run() throws ClassNotFoundException {
+                        String path = name.replace('.', '/').concat(".class");
+                        Resource res = ucp.getResource(path, false);
+                        if (res != null) {
+                            try {
+                                return defineClass(name, res);
+                            } catch (IOException e) {
+                                throw new ClassNotFoundException(name, e);
+                            }
+                        } else {
+                            return null;
+                        }
+                    }
+                }, acc);
+        } catch (java.security.PrivilegedActionException pae) {
+            throw (ClassNotFoundException) pae.getException();
+        }
+        if (result == null) {
+            throw new ClassNotFoundException(name);
+        }
+        return result;
+    }
+
+    /*
+     * Retrieve the package using the specified package name.
+     * If non-null, verify the package using the specified code
+     * source and manifest.
+     */
+    private Package getAndVerifyPackage(String pkgname,
+                                        Manifest man, URL url) {
+        Package pkg = getPackage(pkgname);
+        if (pkg != null) {
+            // Package found, so check package sealing.
+            if (pkg.isSealed()) {
+                // Verify that code source URL is the same.
+                if (!pkg.isSealed(url)) {
+                    throw new SecurityException(
+                        "sealing violation: package " + pkgname + " is sealed");
+                }
+            } else {
+                // Make sure we are not attempting to seal the package
+                // at this code source URL.
+                if ((man != null) && isSealed(pkgname, man)) {
+                    throw new SecurityException(
+                        "sealing violation: can't seal package " + pkgname +
+                        ": already loaded");
+                }
+            }
+        }
+        return pkg;
+    }
+
+    // Also called by VM to define Package for classes loaded from the CDS
+    // archive
+    private void definePackageInternal(String pkgname, Manifest man, URL url)
+    {
+        if (getAndVerifyPackage(pkgname, man, url) == null) {
+            try {
+                if (man != null) {
+                    definePackage(pkgname, man, url);
+                } else {
+                    definePackage(pkgname, null, null, null, null, null, null, null);
+                }
+            } catch (IllegalArgumentException iae) {
+                // parallel-capable class loaders: re-verify in case of a
+                // race condition
+                if (getAndVerifyPackage(pkgname, man, url) == null) {
+                    // Should never happen
+                    throw new AssertionError("Cannot find package " +
+                                             pkgname);
+                }
+            }
+        }
+    }
+
+    /*
+     * Defines a Class using the class bytes obtained from the specified
+     * Resource. The resulting Class must be resolved before it can be
+     * used.
+     */
+    private Class<?> defineClass(String name, Resource res) throws IOException {
+        long t0 = System.nanoTime();
+        int i = name.lastIndexOf('.');
+        URL url = res.getCodeSourceURL();
+        if (i != -1) {
+            String pkgname = name.substring(0, i);
+            // Check if package already loaded.
+            Manifest man = res.getManifest();
+            definePackageInternal(pkgname, man, url);
+        }
+        // Now read the class bytes and define the class
+        java.nio.ByteBuffer bb = res.getByteBuffer();
+        if (bb != null) {
+            // Use (direct) ByteBuffer:
+            CodeSigner[] signers = res.getCodeSigners();
+            CodeSource cs = new CodeSource(url, signers);
+            // Android-removed: Android doesn't use sun.misc.PerfCounter.
+            // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
+            return defineClass(name, bb, cs);
+        } else {
+            byte[] b = res.getBytes();
+            // must read certificates AFTER reading bytes.
+            CodeSigner[] signers = res.getCodeSigners();
+            CodeSource cs = new CodeSource(url, signers);
+            // Android-removed: Android doesn't use sun.misc.PerfCounter.
+            // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
+            return defineClass(name, b, 0, b.length, cs);
+        }
+    }
+
+    /**
+     * Defines a new package by name in this ClassLoader. The attributes
+     * contained in the specified Manifest will be used to obtain package
+     * version and sealing information. For sealed packages, the additional
+     * URL specifies the code source URL from which the package was loaded.
+     *
+     * @param name  the package name
+     * @param man   the Manifest containing package version and sealing
+     *              information
+     * @param url   the code source url for the package, or null if none
+     * @exception   IllegalArgumentException if the package name duplicates
+     *              an existing package either in this class loader or one
+     *              of its ancestors
+     * @return the newly defined Package object
+     */
+    protected Package definePackage(String name, Manifest man, URL url)
+        throws IllegalArgumentException
+    {
+        String path = name.replace('.', '/').concat("/");
+        String specTitle = null, specVersion = null, specVendor = null;
+        String implTitle = null, implVersion = null, implVendor = null;
+        String sealed = null;
+        URL sealBase = null;
+
+        Attributes attr = man.getAttributes(path);
+        if (attr != null) {
+            specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
+            specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+            specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
+            implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
+            implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+            implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+            sealed      = attr.getValue(Name.SEALED);
+        }
+        attr = man.getMainAttributes();
+        if (attr != null) {
+            if (specTitle == null) {
+                specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
+            }
+            if (specVersion == null) {
+                specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
+            }
+            if (specVendor == null) {
+                specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
+            }
+            if (implTitle == null) {
+                implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
+            }
+            if (implVersion == null) {
+                implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
+            }
+            if (implVendor == null) {
+                implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
+            }
+            if (sealed == null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        if ("true".equalsIgnoreCase(sealed)) {
+            sealBase = url;
+        }
+        return definePackage(name, specTitle, specVersion, specVendor,
+                             implTitle, implVersion, implVendor, sealBase);
+    }
+
+    /*
+     * Returns true if the specified package name is sealed according to the
+     * given manifest.
+     */
+    private boolean isSealed(String name, Manifest man) {
+        String path = name.replace('.', '/').concat("/");
+        Attributes attr = man.getAttributes(path);
+        String sealed = null;
+        if (attr != null) {
+            sealed = attr.getValue(Name.SEALED);
+        }
+        if (sealed == null) {
+            if ((attr = man.getMainAttributes()) != null) {
+                sealed = attr.getValue(Name.SEALED);
+            }
+        }
+        return "true".equalsIgnoreCase(sealed);
+    }
+
+    /**
+     * Finds the resource with the specified name on the URL search path.
+     *
+     * @param name the name of the resource
+     * @return a {@code URL} for the resource, or {@code null}
+     * if the resource could not be found, or if the loader is closed.
+     */
+    public URL findResource(final String name) {
+        /*
+         * The same restriction to finding classes applies to resources
+         */
+        URL url = AccessController.doPrivileged(
+            new PrivilegedAction<URL>() {
+                public URL run() {
+                    return ucp.findResource(name, true);
+                }
+            }, acc);
+
+        return url != null ? ucp.checkURL(url) : null;
+    }
+
+    /**
+     * Returns an Enumeration of URLs representing all of the resources
+     * on the URL search path having the specified name.
+     *
+     * @param name the resource name
+     * @exception IOException if an I/O exception occurs
+     * @return an {@code Enumeration} of {@code URL}s
+     *         If the loader is closed, the Enumeration will be empty.
+     */
+    public Enumeration<URL> findResources(final String name)
+        throws IOException
+    {
+        final Enumeration<URL> e = ucp.findResources(name, true);
+
+        return new Enumeration<URL>() {
+            private URL url = null;
+
+            private boolean next() {
+                if (url != null) {
+                    return true;
+                }
+                do {
+                    URL u = AccessController.doPrivileged(
+                        new PrivilegedAction<URL>() {
+                            public URL run() {
+                                if (!e.hasMoreElements())
+                                    return null;
+                                return e.nextElement();
+                            }
+                        }, acc);
+                    if (u == null)
+                        break;
+                    url = ucp.checkURL(u);
+                } while (url == null);
+                return url != null;
+            }
+
+            public URL nextElement() {
+                if (!next()) {
+                    throw new NoSuchElementException();
+                }
+                URL u = url;
+                url = null;
+                return u;
+            }
+
+            public boolean hasMoreElements() {
+                return next();
+            }
+        };
+    }
+
+    /**
+     * Returns the permissions for the given codesource object.
+     * The implementation of this method first calls super.getPermissions
+     * and then adds permissions based on the URL of the codesource.
+     * <p>
+     * If the protocol of this URL is "jar", then the permission granted
+     * is based on the permission that is required by the URL of the Jar
+     * file.
+     * <p>
+     * If the protocol is "file" and there is an authority component, then
+     * permission to connect to and accept connections from that authority
+     * may be granted. If the protocol is "file"
+     * and the path specifies a file, then permission to read that
+     * file is granted. If protocol is "file" and the path is
+     * a directory, permission is granted to read all files
+     * and (recursively) all files and subdirectories contained in
+     * that directory.
+     * <p>
+     * If the protocol is not "file", then permission
+     * to connect to and accept connections from the URL's host is granted.
+     * @param codesource the codesource
+     * @exception NullPointerException if {@code codesource} is {@code null}.
+     * @return the permissions granted to the codesource
+     */
+    protected PermissionCollection getPermissions(CodeSource codesource)
+    {
+        PermissionCollection perms = super.getPermissions(codesource);
+
+        URL url = codesource.getLocation();
+
+        Permission p;
+        URLConnection urlConnection;
+
+        try {
+            urlConnection = url.openConnection();
+            p = urlConnection.getPermission();
+        } catch (java.io.IOException ioe) {
+            p = null;
+            urlConnection = null;
+        }
+
+        if (p instanceof FilePermission) {
+            // if the permission has a separator char on the end,
+            // it means the codebase is a directory, and we need
+            // to add an additional permission to read recursively
+            String path = p.getName();
+            if (path.endsWith(File.separator)) {
+                path += "-";
+                p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
+            }
+        } else if ((p == null) && (url.getProtocol().equals("file"))) {
+            String path = url.getFile().replace('/', File.separatorChar);
+            path = ParseUtil.decode(path);
+            if (path.endsWith(File.separator))
+                path += "-";
+            p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
+        } else {
+            /**
+             * Not loading from a 'file:' URL so we want to give the class
+             * permission to connect to and accept from the remote host
+             * after we've made sure the host is the correct one and is valid.
+             */
+            URL locUrl = url;
+            if (urlConnection instanceof JarURLConnection) {
+                locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
+            }
+            String host = locUrl.getHost();
+            if (host != null && (host.length() > 0))
+                p = new SocketPermission(host,
+                                         SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
+        }
+
+        // make sure the person that created this class loader
+        // would have this permission
+
+        if (p != null) {
+            final SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                final Permission fp = p;
+                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    public Void run() throws SecurityException {
+                        sm.checkPermission(fp);
+                        return null;
+                    }
+                }, acc);
+            }
+            perms.add(p);
+        }
+        return perms;
+    }
+
+    /**
+     * Creates a new instance of URLClassLoader for the specified
+     * URLs and parent class loader. If a security manager is
+     * installed, the {@code loadClass} method of the URLClassLoader
+     * returned by this method will invoke the
+     * {@code SecurityManager.checkPackageAccess} method before
+     * loading the class.
+     *
+     * @param urls the URLs to search for classes and resources
+     * @param parent the parent class loader for delegation
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @return the resulting class loader
+     */
+    public static URLClassLoader newInstance(final URL[] urls,
+                                             final ClassLoader parent) {
+        // Save the caller's context
+        final AccessControlContext acc = AccessController.getContext();
+        // Need a privileged block to create the class loader
+        URLClassLoader ucl = AccessController.doPrivileged(
+            new PrivilegedAction<URLClassLoader>() {
+                public URLClassLoader run() {
+                    return new FactoryURLClassLoader(urls, parent, acc);
+                }
+            });
+        return ucl;
+    }
+
+    /**
+     * Creates a new instance of URLClassLoader for the specified
+     * URLs and default parent class loader. If a security manager is
+     * installed, the {@code loadClass} method of the URLClassLoader
+     * returned by this method will invoke the
+     * {@code SecurityManager.checkPackageAccess} before
+     * loading the class.
+     *
+     * @param urls the URLs to search for classes and resources
+     * @exception  NullPointerException if {@code urls} is {@code null}.
+     * @return the resulting class loader
+     */
+    public static URLClassLoader newInstance(final URL[] urls) {
+        // Save the caller's context
+        final AccessControlContext acc = AccessController.getContext();
+        // Need a privileged block to create the class loader
+        URLClassLoader ucl = AccessController.doPrivileged(
+            new PrivilegedAction<URLClassLoader>() {
+                public URLClassLoader run() {
+                    return new FactoryURLClassLoader(urls, acc);
+                }
+            });
+        return ucl;
+    }
+
+    static {
+        // Android-removed: SharedSecrets.setJavaNetAccess call. Android doesn't use it.
+        /*sun.misc.SharedSecrets.setJavaNetAccess (
+            new sun.misc.JavaNetAccess() {
+                public URLClassPath getURLClassPath (URLClassLoader u) {
+                    return u.ucp;
+                }
+
+                public String getOriginalHostName(InetAddress ia) {
+                    return ia.holder.getOriginalHostName();
+                }
+            }
+        );*/
+        ClassLoader.registerAsParallelCapable();
+    }
+}
+
+final class FactoryURLClassLoader extends URLClassLoader {
+
+    static {
+        ClassLoader.registerAsParallelCapable();
+    }
+
+    FactoryURLClassLoader(URL[] urls, ClassLoader parent,
+                          AccessControlContext acc) {
+        super(urls, parent, acc);
+    }
+
+    FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
+        super(urls, acc);
+    }
+
+    public final Class<?> loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        // First check if we have permission to access the package. This
+        // should go away once we've added support for exported packages.
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            int i = name.lastIndexOf('.');
+            if (i != -1) {
+                sm.checkPackageAccess(name.substring(0, i));
+            }
+        }
+        return super.loadClass(name, resolve);
+    }
+}
diff --git a/java/net/URLConnection.java b/java/net/URLConnection.java
new file mode 100644
index 0000000..55ec26d
--- /dev/null
+++ b/java/net/URLConnection.java
@@ -0,0 +1,1820 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Date;
+import java.util.StringTokenizer;
+import java.util.Collections;
+import java.util.Map;
+import java.util.List;
+import java.security.Permission;
+import java.security.AccessController;
+import sun.security.util.SecurityConstants;
+import sun.net.www.MessageHeader;
+
+/**
+ * The abstract class {@code URLConnection} is the superclass
+ * of all classes that represent a communications link between the
+ * application and a URL. Instances of this class can be used both to
+ * read from and to write to the resource referenced by the URL. In
+ * general, creating a connection to a URL is a multistep process:
+ *
+ * <center><table border=2 summary="Describes the process of creating a connection to a URL: openConnection() and connect() over time.">
+ * <tr><th>{@code openConnection()}</th>
+ *     <th>{@code connect()}</th></tr>
+ * <tr><td>Manipulate parameters that affect the connection to the remote
+ *         resource.</td>
+ *     <td>Interact with the resource; query header fields and
+ *         contents.</td></tr>
+ * </table>
+ * ----------------------------&gt;
+ * <br>time</center>
+ *
+ * <ol>
+ * <li>The connection object is created by invoking the
+ *     {@code openConnection} method on a URL.
+ * <li>The setup parameters and general request properties are manipulated.
+ * <li>The actual connection to the remote object is made, using the
+ *    {@code connect} method.
+ * <li>The remote object becomes available. The header fields and the contents
+ *     of the remote object can be accessed.
+ * </ol>
+ * <p>
+ * The setup parameters are modified using the following methods:
+ * <ul>
+ *   <li>{@code setAllowUserInteraction}
+ *   <li>{@code setDoInput}
+ *   <li>{@code setDoOutput}
+ *   <li>{@code setIfModifiedSince}
+ *   <li>{@code setUseCaches}
+ * </ul>
+ * <p>
+ * and the general request properties are modified using the method:
+ * <ul>
+ *   <li>{@code setRequestProperty}
+ * </ul>
+ * <p>
+ * Default values for the {@code AllowUserInteraction} and
+ * {@code UseCaches} parameters can be set using the methods
+ * {@code setDefaultAllowUserInteraction} and
+ * {@code setDefaultUseCaches}.
+ * <p>
+ * Each of the above {@code set} methods has a corresponding
+ * {@code get} method to retrieve the value of the parameter or
+ * general request property. The specific parameters and general
+ * request properties that are applicable are protocol specific.
+ * <p>
+ * The following methods are used to access the header fields and
+ * the contents after the connection is made to the remote object:
+ * <ul>
+ *   <li>{@code getContent}
+ *   <li>{@code getHeaderField}
+ *   <li>{@code getInputStream}
+ *   <li>{@code getOutputStream}
+ * </ul>
+ * <p>
+ * Certain header fields are accessed frequently. The methods:
+ * <ul>
+ *   <li>{@code getContentEncoding}
+ *   <li>{@code getContentLength}
+ *   <li>{@code getContentType}
+ *   <li>{@code getDate}
+ *   <li>{@code getExpiration}
+ *   <li>{@code getLastModifed}
+ * </ul>
+ * <p>
+ * provide convenient access to these fields. The
+ * {@code getContentType} method is used by the
+ * {@code getContent} method to determine the type of the remote
+ * object; subclasses may find it convenient to override the
+ * {@code getContentType} method.
+ * <p>
+ * In the common case, all of the pre-connection parameters and
+ * general request properties can be ignored: the pre-connection
+ * parameters and request properties default to sensible values. For
+ * most clients of this interface, there are only two interesting
+ * methods: {@code getInputStream} and {@code getContent},
+ * which are mirrored in the {@code URL} class by convenience methods.
+ * <p>
+ * More information on the request properties and header fields of
+ * an {@code http} connection can be found at:
+ * <blockquote><pre>
+ * <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
+ * </pre></blockquote>
+ *
+ * Invoking the {@code close()} methods on the {@code InputStream} or {@code OutputStream} of an
+ * {@code URLConnection} after a request may free network resources associated with this
+ * instance, unless particular protocol specifications specify different behaviours
+ * for it.
+ *
+ * @author  James Gosling
+ * @see     java.net.URL#openConnection()
+ * @see     java.net.URLConnection#connect()
+ * @see     java.net.URLConnection#getContent()
+ * @see     java.net.URLConnection#getContentEncoding()
+ * @see     java.net.URLConnection#getContentLength()
+ * @see     java.net.URLConnection#getContentType()
+ * @see     java.net.URLConnection#getDate()
+ * @see     java.net.URLConnection#getExpiration()
+ * @see     java.net.URLConnection#getHeaderField(int)
+ * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+ * @see     java.net.URLConnection#getInputStream()
+ * @see     java.net.URLConnection#getLastModified()
+ * @see     java.net.URLConnection#getOutputStream()
+ * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
+ * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
+ * @see     java.net.URLConnection#setDoInput(boolean)
+ * @see     java.net.URLConnection#setDoOutput(boolean)
+ * @see     java.net.URLConnection#setIfModifiedSince(long)
+ * @see     java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
+ * @see     java.net.URLConnection#setUseCaches(boolean)
+ * @since   JDK1.0
+ */
+public abstract class URLConnection {
+
+   /**
+     * The URL represents the remote object on the World Wide Web to
+     * which this connection is opened.
+     * <p>
+     * The value of this field can be accessed by the
+     * {@code getURL} method.
+     * <p>
+     * The default value of this variable is the value of the URL
+     * argument in the {@code URLConnection} constructor.
+     *
+     * @see     java.net.URLConnection#getURL()
+     * @see     java.net.URLConnection#url
+     */
+    protected URL url;
+
+   /**
+     * This variable is set by the {@code setDoInput} method. Its
+     * value is returned by the {@code getDoInput} method.
+     * <p>
+     * A URL connection can be used for input and/or output. Setting the
+     * {@code doInput} flag to {@code true} indicates that
+     * the application intends to read data from the URL connection.
+     * <p>
+     * The default value of this field is {@code true}.
+     *
+     * @see     java.net.URLConnection#getDoInput()
+     * @see     java.net.URLConnection#setDoInput(boolean)
+     */
+    protected boolean doInput = true;
+
+   /**
+     * This variable is set by the {@code setDoOutput} method. Its
+     * value is returned by the {@code getDoOutput} method.
+     * <p>
+     * A URL connection can be used for input and/or output. Setting the
+     * {@code doOutput} flag to {@code true} indicates
+     * that the application intends to write data to the URL connection.
+     * <p>
+     * The default value of this field is {@code false}.
+     *
+     * @see     java.net.URLConnection#getDoOutput()
+     * @see     java.net.URLConnection#setDoOutput(boolean)
+     */
+    protected boolean doOutput = false;
+
+    private static boolean defaultAllowUserInteraction = false;
+
+   /**
+     * If {@code true}, this {@code URL} is being examined in
+     * a context in which it makes sense to allow user interactions such
+     * as popping up an authentication dialog. If {@code false},
+     * then no user interaction is allowed.
+     * <p>
+     * The value of this field can be set by the
+     * {@code setAllowUserInteraction} method.
+     * Its value is returned by the
+     * {@code getAllowUserInteraction} method.
+     * Its default value is the value of the argument in the last invocation
+     * of the {@code setDefaultAllowUserInteraction} method.
+     *
+     * @see     java.net.URLConnection#getAllowUserInteraction()
+     * @see     java.net.URLConnection#setAllowUserInteraction(boolean)
+     * @see     java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
+     */
+    protected boolean allowUserInteraction = defaultAllowUserInteraction;
+
+    private static boolean defaultUseCaches = true;
+
+   /**
+     * If {@code true}, the protocol is allowed to use caching
+     * whenever it can. If {@code false}, the protocol must always
+     * try to get a fresh copy of the object.
+     * <p>
+     * This field is set by the {@code setUseCaches} method. Its
+     * value is returned by the {@code getUseCaches} method.
+     * <p>
+     * Its default value is the value given in the last invocation of the
+     * {@code setDefaultUseCaches} method.
+     *
+     * @see     java.net.URLConnection#setUseCaches(boolean)
+     * @see     java.net.URLConnection#getUseCaches()
+     * @see     java.net.URLConnection#setDefaultUseCaches(boolean)
+     */
+    protected boolean useCaches = defaultUseCaches;
+
+   /**
+     * Some protocols support skipping the fetching of the object unless
+     * the object has been modified more recently than a certain time.
+     * <p>
+     * A nonzero value gives a time as the number of milliseconds since
+     * January 1, 1970, GMT. The object is fetched only if it has been
+     * modified more recently than that time.
+     * <p>
+     * This variable is set by the {@code setIfModifiedSince}
+     * method. Its value is returned by the
+     * {@code getIfModifiedSince} method.
+     * <p>
+     * The default value of this field is {@code 0}, indicating
+     * that the fetching must always occur.
+     *
+     * @see     java.net.URLConnection#getIfModifiedSince()
+     * @see     java.net.URLConnection#setIfModifiedSince(long)
+     */
+    protected long ifModifiedSince = 0;
+
+   /**
+     * If {@code false}, this connection object has not created a
+     * communications link to the specified URL. If {@code true},
+     * the communications link has been established.
+     */
+    protected boolean connected = false;
+
+    /**
+     * @since 1.5
+     */
+    private int connectTimeout;
+    private int readTimeout;
+
+    /**
+     * @since 1.6
+     */
+    private MessageHeader requests;
+
+   /**
+    * @since   JDK1.1
+    */
+    private static FileNameMap fileNameMap;
+
+    // BEGIN Android-changed: Android has its own mime table.
+    /*
+    /**
+     * @since 1.2.2
+     *
+    private static boolean fileNameMapLoaded = false;
+
+    /**
+     * Loads filename map (a mimetable) from a data file. It will
+     * first try to load the user-specific table, defined
+     * by &quot;content.types.user.table&quot; property. If that fails,
+     * it tries to load the default built-in table.
+     *
+     * @return the FileNameMap
+     * @since 1.2
+     * @see #setFileNameMap(java.net.FileNameMap)
+     *
+    public static synchronized FileNameMap getFileNameMap() {
+        if ((fileNameMap == null) && !fileNameMapLoaded) {
+            fileNameMap = sun.net.www.MimeTable.loadTable();
+            fileNameMapLoaded = true;
+        }
+
+        return new FileNameMap() {
+            private FileNameMap map = fileNameMap;
+            public String getContentTypeFor(String fileName) {
+                return map.getContentTypeFor(fileName);
+            }
+        };
+    }
+    */
+    /**
+     * Returns a {@link FileNameMap} implementation suitable for guessing a
+     * content type based on a URL's "file" component.
+     *
+     * @see #guessContentTypeFromName(String)
+     * @see #setFileNameMap(java.net.FileNameMap)
+     *
+     */
+    public static synchronized FileNameMap getFileNameMap() {
+        if (fileNameMap == null) {
+            fileNameMap = new DefaultFileNameMap();
+        }
+        return fileNameMap;
+    }
+    // END Android-changed: Android has its own mime table.
+
+    /**
+     * Sets the FileNameMap.
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param map the FileNameMap to be set
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        SecurityManager#checkSetFactory
+     * @see #getFileNameMap()
+     * @since 1.2
+     */
+    public static void setFileNameMap(FileNameMap map) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkSetFactory();
+        fileNameMap = map;
+    }
+
+    /**
+     * Opens a communications link to the resource referenced by this
+     * URL, if such a connection has not already been established.
+     * <p>
+     * If the {@code connect} method is called when the connection
+     * has already been opened (indicated by the {@code connected}
+     * field having the value {@code true}), the call is ignored.
+     * <p>
+     * URLConnection objects go through two phases: first they are
+     * created, then they are connected.  After being created, and
+     * before being connected, various options can be specified
+     * (e.g., doInput and UseCaches).  After connecting, it is an
+     * error to try to set them.  Operations that depend on being
+     * connected, like getContentLength, will implicitly perform the
+     * connection, if necessary.
+     *
+     * @throws SocketTimeoutException if the timeout expires before
+     *               the connection can be established
+     * @exception  IOException  if an I/O error occurs while opening the
+     *               connection.
+     * @see java.net.URLConnection#connected
+     * @see #getConnectTimeout()
+     * @see #setConnectTimeout(int)
+     */
+    abstract public void connect() throws IOException;
+
+    // Android-changed: Add javadoc to specify Android's timeout behavior.
+    /**
+     * Sets a specified timeout value, in milliseconds, to be used
+     * when opening a communications link to the resource referenced
+     * by this URLConnection.  If the timeout expires before the
+     * connection can be established, a
+     * java.net.SocketTimeoutException is raised. A timeout of zero is
+     * interpreted as an infinite timeout.
+
+     * <p> Some non-standard implementation of this method may ignore
+     * the specified timeout. To see the connect timeout set, please
+     * call getConnectTimeout().
+     *
+     * <p><strong>Warning</strong>: If the hostname resolves to multiple IP
+     * addresses, Android's default implementation of {@link HttpURLConnection}
+     * will try each in
+     * <a href="http://www.ietf.org/rfc/rfc3484.txt">RFC 3484</a> order. If
+     * connecting to each of these addresses fails, multiple timeouts will
+     * elapse before the connect attempt throws an exception. Host names
+     * that support both IPv6 and IPv4 always have at least 2 IP addresses.
+     *
+     * @param timeout an {@code int} that specifies the connect
+     *               timeout value in milliseconds
+     * @throws IllegalArgumentException if the timeout parameter is negative
+     *
+     * @see #getConnectTimeout()
+     * @see #connect()
+     * @since 1.5
+     */
+    public void setConnectTimeout(int timeout) {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout can not be negative");
+        }
+        connectTimeout = timeout;
+    }
+
+    /**
+     * Returns setting for connect timeout.
+     * <p>
+     * 0 return implies that the option is disabled
+     * (i.e., timeout of infinity).
+     *
+     * @return an {@code int} that indicates the connect timeout
+     *         value in milliseconds
+     * @see #setConnectTimeout(int)
+     * @see #connect()
+     * @since 1.5
+     */
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    /**
+     * Sets the read timeout to a specified timeout, in
+     * milliseconds. A non-zero value specifies the timeout when
+     * reading from Input stream when a connection is established to a
+     * resource. If the timeout expires before there is data available
+     * for read, a java.net.SocketTimeoutException is raised. A
+     * timeout of zero is interpreted as an infinite timeout.
+     *
+     *<p> Some non-standard implementation of this method ignores the
+     * specified timeout. To see the read timeout set, please call
+     * getReadTimeout().
+     *
+     * @param timeout an {@code int} that specifies the timeout
+     * value to be used in milliseconds
+     * @throws IllegalArgumentException if the timeout parameter is negative
+     *
+     * @see #getReadTimeout()
+     * @see InputStream#read()
+     * @since 1.5
+     */
+    public void setReadTimeout(int timeout) {
+        if (timeout < 0) {
+            throw new IllegalArgumentException("timeout can not be negative");
+        }
+        readTimeout = timeout;
+    }
+
+    /**
+     * Returns setting for read timeout. 0 return implies that the
+     * option is disabled (i.e., timeout of infinity).
+     *
+     * @return an {@code int} that indicates the read timeout
+     *         value in milliseconds
+     *
+     * @see #setReadTimeout(int)
+     * @see InputStream#read()
+     * @since 1.5
+     */
+    public int getReadTimeout() {
+        return readTimeout;
+    }
+
+    /**
+     * Constructs a URL connection to the specified URL. A connection to
+     * the object referenced by the URL is not created.
+     *
+     * @param   url   the specified URL.
+     */
+    protected URLConnection(URL url) {
+        this.url = url;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s {@code URL}
+     * field.
+     *
+     * @return  the value of this {@code URLConnection}'s {@code URL}
+     *          field.
+     * @see     java.net.URLConnection#url
+     */
+    public URL getURL() {
+        return url;
+    }
+
+    /**
+     * Returns the value of the {@code content-length} header field.
+     * <P>
+     * <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
+     * should be preferred over this method, since it returns a {@code long}
+     * instead and is therefore more portable.</P>
+     *
+     * @return  the content length of the resource that this connection's URL
+     *          references, {@code -1} if the content length is not known,
+     *          or if the content length is greater than Integer.MAX_VALUE.
+     */
+    public int getContentLength() {
+        long l = getContentLengthLong();
+        if (l > Integer.MAX_VALUE)
+            return -1;
+        return (int) l;
+    }
+
+    /**
+     * Returns the value of the {@code content-length} header field as a
+     * long.
+     *
+     * @return  the content length of the resource that this connection's URL
+     *          references, or {@code -1} if the content length is
+     *          not known.
+     * @since 7.0
+     */
+    public long getContentLengthLong() {
+        return getHeaderFieldLong("content-length", -1);
+    }
+
+    /**
+     * Returns the value of the {@code content-type} header field.
+     *
+     * @return  the content type of the resource that the URL references,
+     *          or {@code null} if not known.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public String getContentType() {
+        return getHeaderField("content-type");
+    }
+
+    /**
+     * Returns the value of the {@code content-encoding} header field.
+     *
+     * @return  the content encoding of the resource that the URL references,
+     *          or {@code null} if not known.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public String getContentEncoding() {
+        return getHeaderField("content-encoding");
+    }
+
+    /**
+     * Returns the value of the {@code expires} header field.
+     *
+     * @return  the expiration date of the resource that this URL references,
+     *          or 0 if not known. The value is the number of milliseconds since
+     *          January 1, 1970 GMT.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public long getExpiration() {
+        return getHeaderFieldDate("expires", 0);
+    }
+
+    /**
+     * Returns the value of the {@code date} header field.
+     *
+     * @return  the sending date of the resource that the URL references,
+     *          or {@code 0} if not known. The value returned is the
+     *          number of milliseconds since January 1, 1970 GMT.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public long getDate() {
+        return getHeaderFieldDate("date", 0);
+    }
+
+    /**
+     * Returns the value of the {@code last-modified} header field.
+     * The result is the number of milliseconds since January 1, 1970 GMT.
+     *
+     * @return  the date the resource referenced by this
+     *          {@code URLConnection} was last modified, or 0 if not known.
+     * @see     java.net.URLConnection#getHeaderField(java.lang.String)
+     */
+    public long getLastModified() {
+        return getHeaderFieldDate("last-modified", 0);
+    }
+
+    /**
+     * Returns the value of the named header field.
+     * <p>
+     * If called on a connection that sets the same header multiple times
+     * with possibly different values, only the last value is returned.
+     *
+     *
+     * @param   name   the name of a header field.
+     * @return  the value of the named header field, or {@code null}
+     *          if there is no such field in the header.
+     */
+    public String getHeaderField(String name) {
+        return null;
+    }
+
+    /**
+     * Returns an unmodifiable Map of the header fields.
+     * The Map keys are Strings that represent the
+     * response-header field names. Each Map value is an
+     * unmodifiable List of Strings that represents
+     * the corresponding field values.
+     *
+     * @return a Map of header fields
+     * @since 1.4
+     */
+    public Map<String,List<String>> getHeaderFields() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Returns the value of the named field parsed as a number.
+     * <p>
+     * This form of {@code getHeaderField} exists because some
+     * connection types (e.g., {@code http-ng}) have pre-parsed
+     * headers. Classes for that connection type can override this method
+     * and short-circuit the parsing.
+     *
+     * @param   name      the name of the header field.
+     * @param   Default   the default value.
+     * @return  the value of the named field, parsed as an integer. The
+     *          {@code Default} value is returned if the field is
+     *          missing or malformed.
+     */
+    public int getHeaderFieldInt(String name, int Default) {
+        String value = getHeaderField(name);
+        try {
+            return Integer.parseInt(value);
+        } catch (Exception e) { }
+        return Default;
+    }
+
+    /**
+     * Returns the value of the named field parsed as a number.
+     * <p>
+     * This form of {@code getHeaderField} exists because some
+     * connection types (e.g., {@code http-ng}) have pre-parsed
+     * headers. Classes for that connection type can override this method
+     * and short-circuit the parsing.
+     *
+     * @param   name      the name of the header field.
+     * @param   Default   the default value.
+     * @return  the value of the named field, parsed as a long. The
+     *          {@code Default} value is returned if the field is
+     *          missing or malformed.
+     * @since 7.0
+     */
+    public long getHeaderFieldLong(String name, long Default) {
+        String value = getHeaderField(name);
+        try {
+            return Long.parseLong(value);
+        } catch (Exception e) { }
+        return Default;
+    }
+
+    /**
+     * Returns the value of the named field parsed as date.
+     * The result is the number of milliseconds since January 1, 1970 GMT
+     * represented by the named field.
+     * <p>
+     * This form of {@code getHeaderField} exists because some
+     * connection types (e.g., {@code http-ng}) have pre-parsed
+     * headers. Classes for that connection type can override this method
+     * and short-circuit the parsing.
+     *
+     * @param   name     the name of the header field.
+     * @param   Default   a default value.
+     * @return  the value of the field, parsed as a date. The value of the
+     *          {@code Default} argument is returned if the field is
+     *          missing or malformed.
+     */
+    @SuppressWarnings("deprecation")
+    public long getHeaderFieldDate(String name, long Default) {
+        String value = getHeaderField(name);
+        try {
+            return Date.parse(value);
+        } catch (Exception e) { }
+        return Default;
+    }
+
+    /**
+     * Returns the key for the {@code n}<sup>th</sup> header field.
+     * It returns {@code null} if there are fewer than {@code n+1} fields.
+     *
+     * @param   n   an index, where {@code n>=0}
+     * @return  the key for the {@code n}<sup>th</sup> header field,
+     *          or {@code null} if there are fewer than {@code n+1}
+     *          fields.
+     */
+    public String getHeaderFieldKey(int n) {
+        return null;
+    }
+
+    /**
+     * Returns the value for the {@code n}<sup>th</sup> header field.
+     * It returns {@code null} if there are fewer than
+     * {@code n+1}fields.
+     * <p>
+     * This method can be used in conjunction with the
+     * {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
+     * the headers in the message.
+     *
+     * @param   n   an index, where {@code n>=0}
+     * @return  the value of the {@code n}<sup>th</sup> header field
+     *          or {@code null} if there are fewer than {@code n+1} fields
+     * @see     java.net.URLConnection#getHeaderFieldKey(int)
+     */
+    public String getHeaderField(int n) {
+        return null;
+    }
+
+    /**
+     * Retrieves the contents of this URL connection.
+     * <p>
+     * This method first determines the content type of the object by
+     * calling the {@code getContentType} method. If this is
+     * the first time that the application has seen that specific content
+     * type, a content handler for that content type is created:
+     * <ol>
+     * <li>If the application has set up a content handler factory instance
+     *     using the {@code setContentHandlerFactory} method, the
+     *     {@code createContentHandler} method of that instance is called
+     *     with the content type as an argument; the result is a content
+     *     handler for that content type.
+     * <li>If no content handler factory has yet been set up, or if the
+     *     factory's {@code createContentHandler} method returns
+     *     {@code null}, then the application loads the class named:
+     *     <blockquote><pre>
+     *         sun.net.www.content.&lt;<i>contentType</i>&gt;
+     *     </pre></blockquote>
+     *     where &lt;<i>contentType</i>&gt; is formed by taking the
+     *     content-type string, replacing all slash characters with a
+     *     {@code period} ('.'), and all other non-alphanumeric characters
+     *     with the underscore character '{@code _}'. The alphanumeric
+     *     characters are specifically the 26 uppercase ASCII letters
+     *     '{@code A}' through '{@code Z}', the 26 lowercase ASCII
+     *     letters '{@code a}' through '{@code z}', and the 10 ASCII
+     *     digits '{@code 0}' through '{@code 9}'. If the specified
+     *     class does not exist, or is not a subclass of
+     *     {@code ContentHandler}, then an
+     *     {@code UnknownServiceException} is thrown.
+     * </ol>
+     *
+     * @return     the object fetched. The {@code instanceof} operator
+     *               should be used to determine the specific kind of object
+     *               returned.
+     * @exception  IOException              if an I/O error occurs while
+     *               getting the content.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               the content type.
+     * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
+     * @see        java.net.URLConnection#getContentType()
+     * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
+     */
+    public Object getContent() throws IOException {
+        // Must call getInputStream before GetHeaderField gets called
+        // so that FileNotFoundException has a chance to be thrown up
+        // from here without being caught.
+        getInputStream();
+        return getContentHandler().getContent(this);
+    }
+
+    /**
+     * Retrieves the contents of this URL connection.
+     *
+     * @param classes the {@code Class} array
+     * indicating the requested types
+     * @return     the object fetched that is the first match of the type
+     *               specified in the classes array. null if none of
+     *               the requested types are supported.
+     *               The {@code instanceof} operator should be used to
+     *               determine the specific kind of object returned.
+     * @exception  IOException              if an I/O error occurs while
+     *               getting the content.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               the content type.
+     * @see        java.net.URLConnection#getContent()
+     * @see        java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
+     * @see        java.net.URLConnection#getContent(java.lang.Class[])
+     * @see        java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
+     * @since 1.3
+     */
+    public Object getContent(Class[] classes) throws IOException {
+        // Must call getInputStream before GetHeaderField gets called
+        // so that FileNotFoundException has a chance to be thrown up
+        // from here without being caught.
+        getInputStream();
+        return getContentHandler().getContent(this, classes);
+    }
+
+    /**
+     * Returns a permission object representing the permission
+     * necessary to make the connection represented by this
+     * object. This method returns null if no permission is
+     * required to make the connection. By default, this method
+     * returns {@code java.security.AllPermission}. Subclasses
+     * should override this method and return the permission
+     * that best represents the permission required to make a
+     * a connection to the URL. For example, a {@code URLConnection}
+     * representing a {@code file:} URL would return a
+     * {@code java.io.FilePermission} object.
+     *
+     * <p>The permission returned may dependent upon the state of the
+     * connection. For example, the permission before connecting may be
+     * different from that after connecting. For example, an HTTP
+     * sever, say foo.com, may redirect the connection to a different
+     * host, say bar.com. Before connecting the permission returned by
+     * the connection will represent the permission needed to connect
+     * to foo.com, while the permission returned after connecting will
+     * be to bar.com.
+     *
+     * <p>Permissions are generally used for two purposes: to protect
+     * caches of objects obtained through URLConnections, and to check
+     * the right of a recipient to learn about a particular URL. In
+     * the first case, the permission should be obtained
+     * <em>after</em> the object has been obtained. For example, in an
+     * HTTP connection, this will represent the permission to connect
+     * to the host from which the data was ultimately fetched. In the
+     * second case, the permission should be obtained and tested
+     * <em>before</em> connecting.
+     *
+     * @return the permission object representing the permission
+     * necessary to make the connection represented by this
+     * URLConnection.
+     *
+     * @exception IOException if the computation of the permission
+     * requires network or file I/O and an exception occurs while
+     * computing it.
+     */
+    public Permission getPermission() throws IOException {
+        return SecurityConstants.ALL_PERMISSION;
+    }
+
+    /**
+     * Returns an input stream that reads from this open connection.
+     *
+     * A SocketTimeoutException can be thrown when reading from the
+     * returned input stream if the read timeout expires before data
+     * is available for read.
+     *
+     * @return     an input stream that reads from this open connection.
+     * @exception  IOException              if an I/O error occurs while
+     *               creating the input stream.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               input.
+     * @see #setReadTimeout(int)
+     * @see #getReadTimeout()
+     */
+    public InputStream getInputStream() throws IOException {
+        throw new UnknownServiceException("protocol doesn't support input");
+    }
+
+    /**
+     * Returns an output stream that writes to this connection.
+     *
+     * @return     an output stream that writes to this connection.
+     * @exception  IOException              if an I/O error occurs while
+     *               creating the output stream.
+     * @exception  UnknownServiceException  if the protocol does not support
+     *               output.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        throw new UnknownServiceException("protocol doesn't support output");
+    }
+
+    /**
+     * Returns a {@code String} representation of this URL connection.
+     *
+     * @return  a string representation of this {@code URLConnection}.
+     */
+    public String toString() {
+        return this.getClass().getName() + ":" + url;
+    }
+
+    /**
+     * Sets the value of the {@code doInput} field for this
+     * {@code URLConnection} to the specified value.
+     * <p>
+     * A URL connection can be used for input and/or output.  Set the DoInput
+     * flag to true if you intend to use the URL connection for input,
+     * false if not.  The default is true.
+     *
+     * @param   doinput   the new value.
+     * @throws IllegalStateException if already connected
+     * @see     java.net.URLConnection#doInput
+     * @see #getDoInput()
+     */
+    public void setDoInput(boolean doinput) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        doInput = doinput;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s
+     * {@code doInput} flag.
+     *
+     * @return  the value of this {@code URLConnection}'s
+     *          {@code doInput} flag.
+     * @see     #setDoInput(boolean)
+     */
+    public boolean getDoInput() {
+        return doInput;
+    }
+
+    /**
+     * Sets the value of the {@code doOutput} field for this
+     * {@code URLConnection} to the specified value.
+     * <p>
+     * A URL connection can be used for input and/or output.  Set the DoOutput
+     * flag to true if you intend to use the URL connection for output,
+     * false if not.  The default is false.
+     *
+     * @param   dooutput   the new value.
+     * @throws IllegalStateException if already connected
+     * @see #getDoOutput()
+     */
+    public void setDoOutput(boolean dooutput) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        doOutput = dooutput;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s
+     * {@code doOutput} flag.
+     *
+     * @return  the value of this {@code URLConnection}'s
+     *          {@code doOutput} flag.
+     * @see     #setDoOutput(boolean)
+     */
+    public boolean getDoOutput() {
+        return doOutput;
+    }
+
+    /**
+     * Set the value of the {@code allowUserInteraction} field of
+     * this {@code URLConnection}.
+     *
+     * @param   allowuserinteraction   the new value.
+     * @throws IllegalStateException if already connected
+     * @see     #getAllowUserInteraction()
+     */
+    public void setAllowUserInteraction(boolean allowuserinteraction) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        allowUserInteraction = allowuserinteraction;
+    }
+
+    /**
+     * Returns the value of the {@code allowUserInteraction} field for
+     * this object.
+     *
+     * @return  the value of the {@code allowUserInteraction} field for
+     *          this object.
+     * @see     #setAllowUserInteraction(boolean)
+     */
+    public boolean getAllowUserInteraction() {
+        return allowUserInteraction;
+    }
+
+    /**
+     * Sets the default value of the
+     * {@code allowUserInteraction} field for all future
+     * {@code URLConnection} objects to the specified value.
+     *
+     * @param   defaultallowuserinteraction   the new value.
+     * @see     #getDefaultAllowUserInteraction()
+     */
+    public static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction) {
+        defaultAllowUserInteraction = defaultallowuserinteraction;
+    }
+
+    /**
+     * Returns the default value of the {@code allowUserInteraction}
+     * field.
+     * <p>
+     * Ths default is "sticky", being a part of the static state of all
+     * URLConnections.  This flag applies to the next, and all following
+     * URLConnections that are created.
+     *
+     * @return  the default value of the {@code allowUserInteraction}
+     *          field.
+     * @see     #setDefaultAllowUserInteraction(boolean)
+     */
+    public static boolean getDefaultAllowUserInteraction() {
+        return defaultAllowUserInteraction;
+    }
+
+    /**
+     * Sets the value of the {@code useCaches} field of this
+     * {@code URLConnection} to the specified value.
+     * <p>
+     * Some protocols do caching of documents.  Occasionally, it is important
+     * to be able to "tunnel through" and ignore the caches (e.g., the
+     * "reload" button in a browser).  If the UseCaches flag on a connection
+     * is true, the connection is allowed to use whatever caches it can.
+     *  If false, caches are to be ignored.
+     *  The default value comes from DefaultUseCaches, which defaults to
+     * true.
+     *
+     * @param usecaches a {@code boolean} indicating whether
+     * or not to allow caching
+     * @throws IllegalStateException if already connected
+     * @see #getUseCaches()
+     */
+    public void setUseCaches(boolean usecaches) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        useCaches = usecaches;
+    }
+
+    /**
+     * Returns the value of this {@code URLConnection}'s
+     * {@code useCaches} field.
+     *
+     * @return  the value of this {@code URLConnection}'s
+     *          {@code useCaches} field.
+     * @see #setUseCaches(boolean)
+     */
+    public boolean getUseCaches() {
+        return useCaches;
+    }
+
+    /**
+     * Sets the value of the {@code ifModifiedSince} field of
+     * this {@code URLConnection} to the specified value.
+     *
+     * @param   ifmodifiedsince   the new value.
+     * @throws IllegalStateException if already connected
+     * @see     #getIfModifiedSince()
+     */
+    public void setIfModifiedSince(long ifmodifiedsince) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        ifModifiedSince = ifmodifiedsince;
+    }
+
+    /**
+     * Returns the value of this object's {@code ifModifiedSince} field.
+     *
+     * @return  the value of this object's {@code ifModifiedSince} field.
+     * @see #setIfModifiedSince(long)
+     */
+    public long getIfModifiedSince() {
+        return ifModifiedSince;
+    }
+
+   /**
+     * Returns the default value of a {@code URLConnection}'s
+     * {@code useCaches} flag.
+     * <p>
+     * Ths default is "sticky", being a part of the static state of all
+     * URLConnections.  This flag applies to the next, and all following
+     * URLConnections that are created.
+     *
+     * @return  the default value of a {@code URLConnection}'s
+     *          {@code useCaches} flag.
+     * @see     #setDefaultUseCaches(boolean)
+     */
+    public boolean getDefaultUseCaches() {
+        return defaultUseCaches;
+    }
+
+   /**
+     * Sets the default value of the {@code useCaches} field to the
+     * specified value.
+     *
+     * @param   defaultusecaches   the new value.
+     * @see     #getDefaultUseCaches()
+     */
+    public void setDefaultUseCaches(boolean defaultusecaches) {
+        defaultUseCaches = defaultusecaches;
+    }
+
+    /**
+     * Sets the general request property. If a property with the key already
+     * exists, overwrite its value with the new value.
+     *
+     * <p> NOTE: HTTP requires all request properties which can
+     * legally have multiple instances with the same key
+     * to use a comma-separated list syntax which enables multiple
+     * properties to be appended into a single property.
+     *
+     * @param   key     the keyword by which the request is known
+     *                  (e.g., "{@code Accept}").
+     * @param   value   the value associated with it.
+     * @throws IllegalStateException if already connected
+     * @throws NullPointerException if key is <CODE>null</CODE>
+     * @see #getRequestProperty(java.lang.String)
+     */
+    public void setRequestProperty(String key, String value) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        if (key == null)
+            throw new NullPointerException ("key is null");
+
+        if (requests == null)
+            requests = new MessageHeader();
+
+        requests.set(key, value);
+    }
+
+    /**
+     * Adds a general request property specified by a
+     * key-value pair.  This method will not overwrite
+     * existing values associated with the same key.
+     *
+     * @param   key     the keyword by which the request is known
+     *                  (e.g., "{@code Accept}").
+     * @param   value  the value associated with it.
+     * @throws IllegalStateException if already connected
+     * @throws NullPointerException if key is null
+     * @see #getRequestProperties()
+     * @since 1.4
+     */
+    public void addRequestProperty(String key, String value) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+        if (key == null)
+            throw new NullPointerException ("key is null");
+
+        if (requests == null)
+            requests = new MessageHeader();
+
+        requests.add(key, value);
+    }
+
+
+    /**
+     * Returns the value of the named general request property for this
+     * connection.
+     *
+     * @param key the keyword by which the request is known (e.g., "Accept").
+     * @return  the value of the named general request property for this
+     *           connection. If key is null, then null is returned.
+     * @throws IllegalStateException if already connected
+     * @see #setRequestProperty(java.lang.String, java.lang.String)
+     */
+    public String getRequestProperty(String key) {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+
+        if (requests == null)
+            return null;
+
+        return requests.findValue(key);
+    }
+
+    /**
+     * Returns an unmodifiable Map of general request
+     * properties for this connection. The Map keys
+     * are Strings that represent the request-header
+     * field names. Each Map value is a unmodifiable List
+     * of Strings that represents the corresponding
+     * field values.
+     *
+     * @return  a Map of the general request properties for this connection.
+     * @throws IllegalStateException if already connected
+     * @since 1.4
+     */
+    public Map<String,List<String>> getRequestProperties() {
+        if (connected)
+            throw new IllegalStateException("Already connected");
+
+        if (requests == null)
+            return Collections.emptyMap();
+
+        return requests.getHeaders(null);
+    }
+
+    /**
+     * Sets the default value of a general request property. When a
+     * {@code URLConnection} is created, it is initialized with
+     * these properties.
+     *
+     * @param   key     the keyword by which the request is known
+     *                  (e.g., "{@code Accept}").
+     * @param   value   the value associated with the key.
+     *
+     * @see java.net.URLConnection#setRequestProperty(java.lang.String,java.lang.String)
+     *
+     * @deprecated The instance specific setRequestProperty method
+     * should be used after an appropriate instance of URLConnection
+     * is obtained. Invoking this method will have no effect.
+     *
+     * @see #getDefaultRequestProperty(java.lang.String)
+     */
+    @Deprecated
+    public static void setDefaultRequestProperty(String key, String value) {
+    }
+
+    /**
+     * Returns the value of the default request property. Default request
+     * properties are set for every connection.
+     *
+     * @param key the keyword by which the request is known (e.g., "Accept").
+     * @return  the value of the default request property
+     * for the specified key.
+     *
+     * @see java.net.URLConnection#getRequestProperty(java.lang.String)
+     *
+     * @deprecated The instance specific getRequestProperty method
+     * should be used after an appropriate instance of URLConnection
+     * is obtained.
+     *
+     * @see #setDefaultRequestProperty(java.lang.String, java.lang.String)
+     */
+    @Deprecated
+    public static String getDefaultRequestProperty(String key) {
+        return null;
+    }
+
+    /**
+     * The ContentHandler factory.
+     */
+    static ContentHandlerFactory factory;
+
+    /**
+     * Sets the {@code ContentHandlerFactory} of an
+     * application. It can be called at most once by an application.
+     * <p>
+     * The {@code ContentHandlerFactory} instance is used to
+     * construct a content handler from a content type
+     * <p>
+     * If there is a security manager, this method first calls
+     * the security manager's {@code checkSetFactory} method
+     * to ensure the operation is allowed.
+     * This could result in a SecurityException.
+     *
+     * @param      fac   the desired factory.
+     * @exception  Error  if the factory has already been defined.
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkSetFactory} method doesn't allow the operation.
+     * @see        java.net.ContentHandlerFactory
+     * @see        java.net.URLConnection#getContent()
+     * @see        SecurityManager#checkSetFactory
+     */
+    public static synchronized void setContentHandlerFactory(ContentHandlerFactory fac) {
+        if (factory != null) {
+            throw new Error("factory already defined");
+        }
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSetFactory();
+        }
+        factory = fac;
+    }
+
+    private static Hashtable<String, ContentHandler> handlers = new Hashtable<>();
+
+    /**
+     * Gets the Content Handler appropriate for this connection.
+     */
+    synchronized ContentHandler getContentHandler()
+        throws IOException
+    {
+        String contentType = stripOffParameters(getContentType());
+        ContentHandler handler = null;
+        // BEGIN Android-changed: App Compat. Android guesses content type from name and stream.
+        if (contentType == null) {
+            if ((contentType = guessContentTypeFromName(url.getFile())) == null) {
+                contentType = guessContentTypeFromStream(getInputStream());
+            }
+        }
+
+        if (contentType == null) {
+            return UnknownContentHandler.INSTANCE;
+        }
+        // END Android-changed: App Compat. Android guesses content type from name and stream.
+        try {
+            handler = handlers.get(contentType);
+            if (handler != null)
+                return handler;
+        } catch(Exception e) {
+        }
+
+        if (factory != null)
+            handler = factory.createContentHandler(contentType);
+        if (handler == null) {
+            try {
+                handler = lookupContentHandlerClassFor(contentType);
+            } catch(Exception e) {
+                e.printStackTrace();
+                handler = UnknownContentHandler.INSTANCE;
+            }
+            handlers.put(contentType, handler);
+        }
+        return handler;
+    }
+
+    /*
+     * Media types are in the format: type/subtype*(; parameter).
+     * For looking up the content handler, we should ignore those
+     * parameters.
+     */
+    private String stripOffParameters(String contentType)
+    {
+        if (contentType == null)
+            return null;
+        int index = contentType.indexOf(';');
+
+        if (index > 0)
+            return contentType.substring(0, index);
+        else
+            return contentType;
+    }
+
+    private static final String contentClassPrefix = "sun.net.www.content";
+    private static final String contentPathProp = "java.content.handler.pkgs";
+
+    /**
+     * Looks for a content handler in a user-defineable set of places.
+     * By default it looks in sun.net.www.content, but users can define a
+     * vertical-bar delimited set of class prefixes to search through in
+     * addition by defining the java.content.handler.pkgs property.
+     * The class name must be of the form:
+     * <pre>
+     *     {package-prefix}.{major}.{minor}
+     * e.g.
+     *     YoyoDyne.experimental.text.plain
+     * </pre>
+     */
+    private ContentHandler lookupContentHandlerClassFor(String contentType)
+        throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+        String contentHandlerClassName = typeToPackageName(contentType);
+
+        String contentHandlerPkgPrefixes =getContentHandlerPkgPrefixes();
+
+        StringTokenizer packagePrefixIter =
+            new StringTokenizer(contentHandlerPkgPrefixes, "|");
+
+        while (packagePrefixIter.hasMoreTokens()) {
+            String packagePrefix = packagePrefixIter.nextToken().trim();
+
+            try {
+                String clsName = packagePrefix + "." + contentHandlerClassName;
+                Class<?> cls = null;
+                try {
+                    cls = Class.forName(clsName);
+                } catch (ClassNotFoundException e) {
+                    ClassLoader cl = ClassLoader.getSystemClassLoader();
+                    if (cl != null) {
+                        cls = cl.loadClass(clsName);
+                    }
+                }
+                if (cls != null) {
+                    ContentHandler handler =
+                        (ContentHandler)cls.newInstance();
+                    return handler;
+                }
+            } catch(Exception e) {
+            }
+        }
+
+        return UnknownContentHandler.INSTANCE;
+    }
+
+    /**
+     * Utility function to map a MIME content type into an equivalent
+     * pair of class name components.  For example: "text/html" would
+     * be returned as "text.html"
+     */
+    private String typeToPackageName(String contentType) {
+        // make sure we canonicalize the class name: all lower case
+        contentType = contentType.toLowerCase();
+        int len = contentType.length();
+        char nm[] = new char[len];
+        contentType.getChars(0, len, nm, 0);
+        for (int i = 0; i < len; i++) {
+            char c = nm[i];
+            if (c == '/') {
+                nm[i] = '.';
+            } else if (!('A' <= c && c <= 'Z' ||
+                       'a' <= c && c <= 'z' ||
+                       '0' <= c && c <= '9')) {
+                nm[i] = '_';
+            }
+        }
+        return new String(nm);
+    }
+
+
+    /**
+     * Returns a vertical bar separated list of package prefixes for potential
+     * content handlers.  Tries to get the java.content.handler.pkgs property
+     * to use as a set of package prefixes to search.  Whether or not
+     * that property has been defined, the sun.net.www.content is always
+     * the last one on the returned package list.
+     */
+    private String getContentHandlerPkgPrefixes() {
+        String packagePrefixList = AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction(contentPathProp, ""));
+
+        if (packagePrefixList != "") {
+            packagePrefixList += "|";
+        }
+
+        return packagePrefixList + contentClassPrefix;
+    }
+
+    /**
+     * Tries to determine the content type of an object, based
+     * on the specified "file" component of a URL.
+     * This is a convenience method that can be used by
+     * subclasses that override the {@code getContentType} method.
+     *
+     * @param   fname   a filename.
+     * @return  a guess as to what the content type of the object is,
+     *          based upon its file name.
+     * @see     java.net.URLConnection#getContentType()
+     */
+    public static String guessContentTypeFromName(String fname) {
+        return getFileNameMap().getContentTypeFor(fname);
+    }
+
+    /**
+     * Tries to determine the type of an input stream based on the
+     * characters at the beginning of the input stream. This method can
+     * be used by subclasses that override the
+     * {@code getContentType} method.
+     * <p>
+     * Ideally, this routine would not be needed. But many
+     * {@code http} servers return the incorrect content type; in
+     * addition, there are many nonstandard extensions. Direct inspection
+     * of the bytes to determine the content type is often more accurate
+     * than believing the content type claimed by the {@code http} server.
+     *
+     * @param      is   an input stream that supports marks.
+     * @return     a guess at the content type, or {@code null} if none
+     *             can be determined.
+     * @exception  IOException  if an I/O error occurs while reading the
+     *               input stream.
+     * @see        java.io.InputStream#mark(int)
+     * @see        java.io.InputStream#markSupported()
+     * @see        java.net.URLConnection#getContentType()
+     */
+    static public String guessContentTypeFromStream(InputStream is)
+                        throws IOException {
+        // If we can't read ahead safely, just give up on guessing
+        if (!is.markSupported())
+            return null;
+
+        is.mark(16);
+        int c1 = is.read();
+        int c2 = is.read();
+        int c3 = is.read();
+        int c4 = is.read();
+        int c5 = is.read();
+        int c6 = is.read();
+        int c7 = is.read();
+        int c8 = is.read();
+        int c9 = is.read();
+        int c10 = is.read();
+        int c11 = is.read();
+        int c12 = is.read();
+        int c13 = is.read();
+        int c14 = is.read();
+        int c15 = is.read();
+        int c16 = is.read();
+        is.reset();
+
+        if (c1 == 0xCA && c2 == 0xFE && c3 == 0xBA && c4 == 0xBE) {
+            return "application/java-vm";
+        }
+
+        if (c1 == 0xAC && c2 == 0xED) {
+            // next two bytes are version number, currently 0x00 0x05
+            return "application/x-java-serialized-object";
+        }
+
+        if (c1 == '<') {
+            if (c2 == '!'
+                || ((c2 == 'h' && (c3 == 't' && c4 == 'm' && c5 == 'l' ||
+                                   c3 == 'e' && c4 == 'a' && c5 == 'd') ||
+                (c2 == 'b' && c3 == 'o' && c4 == 'd' && c5 == 'y'))) ||
+                ((c2 == 'H' && (c3 == 'T' && c4 == 'M' && c5 == 'L' ||
+                                c3 == 'E' && c4 == 'A' && c5 == 'D') ||
+                (c2 == 'B' && c3 == 'O' && c4 == 'D' && c5 == 'Y')))) {
+                return "text/html";
+            }
+
+            if (c2 == '?' && c3 == 'x' && c4 == 'm' && c5 == 'l' && c6 == ' ') {
+                return "application/xml";
+            }
+        }
+
+        // big and little (identical) endian UTF-8 encodings, with BOM
+        if (c1 == 0xef &&  c2 == 0xbb &&  c3 == 0xbf) {
+            if (c4 == '<' &&  c5 == '?' &&  c6 == 'x') {
+                return "application/xml";
+            }
+        }
+
+        // big and little endian UTF-16 encodings, with byte order mark
+        if (c1 == 0xfe && c2 == 0xff) {
+            if (c3 == 0 && c4 == '<' && c5 == 0 && c6 == '?' &&
+                c7 == 0 && c8 == 'x') {
+                return "application/xml";
+            }
+        }
+
+        if (c1 == 0xff && c2 == 0xfe) {
+            if (c3 == '<' && c4 == 0 && c5 == '?' && c6 == 0 &&
+                c7 == 'x' && c8 == 0) {
+                return "application/xml";
+            }
+        }
+
+        // big and little endian UTF-32 encodings, with BOM
+        if (c1 == 0x00 &&  c2 == 0x00 &&  c3 == 0xfe &&  c4 == 0xff) {
+            if (c5  == 0 && c6  == 0 && c7  == 0 && c8  == '<' &&
+                c9  == 0 && c10 == 0 && c11 == 0 && c12 == '?' &&
+                c13 == 0 && c14 == 0 && c15 == 0 && c16 == 'x') {
+                return "application/xml";
+            }
+        }
+
+        if (c1 == 0xff &&  c2 == 0xfe &&  c3 == 0x00 &&  c4 == 0x00) {
+            if (c5  == '<' && c6  == 0 && c7  == 0 && c8  == 0 &&
+                c9  == '?' && c10 == 0 && c11 == 0 && c12 == 0 &&
+                c13 == 'x' && c14 == 0 && c15 == 0 && c16 == 0) {
+                return "application/xml";
+            }
+        }
+
+        if (c1 == 'G' && c2 == 'I' && c3 == 'F' && c4 == '8') {
+            return "image/gif";
+        }
+
+        if (c1 == '#' && c2 == 'd' && c3 == 'e' && c4 == 'f') {
+            return "image/x-bitmap";
+        }
+
+        if (c1 == '!' && c2 == ' ' && c3 == 'X' && c4 == 'P' &&
+                        c5 == 'M' && c6 == '2') {
+            return "image/x-pixmap";
+        }
+
+        if (c1 == 137 && c2 == 80 && c3 == 78 &&
+                c4 == 71 && c5 == 13 && c6 == 10 &&
+                c7 == 26 && c8 == 10) {
+            return "image/png";
+        }
+
+        if (c1 == 0xFF && c2 == 0xD8 && c3 == 0xFF) {
+            if (c4 == 0xE0 || c4 == 0xEE) {
+                return "image/jpeg";
+            }
+
+            /**
+             * File format used by digital cameras to store images.
+             * Exif Format can be read by any application supporting
+             * JPEG. Exif Spec can be found at:
+             * http://www.pima.net/standards/it10/PIMA15740/Exif_2-1.PDF
+             */
+            if ((c4 == 0xE1) &&
+                (c7 == 'E' && c8 == 'x' && c9 == 'i' && c10 =='f' &&
+                 c11 == 0)) {
+                return "image/jpeg";
+            }
+        }
+
+        if (c1 == 0xD0 && c2 == 0xCF && c3 == 0x11 && c4 == 0xE0 &&
+            c5 == 0xA1 && c6 == 0xB1 && c7 == 0x1A && c8 == 0xE1) {
+
+            /* Above is signature of Microsoft Structured Storage.
+             * Below this, could have tests for various SS entities.
+             * For now, just test for FlashPix.
+             */
+            if (checkfpx(is)) {
+                return "image/vnd.fpx";
+            }
+        }
+
+        if (c1 == 0x2E && c2 == 0x73 && c3 == 0x6E && c4 == 0x64) {
+            return "audio/basic";  // .au format, big endian
+        }
+
+        if (c1 == 0x64 && c2 == 0x6E && c3 == 0x73 && c4 == 0x2E) {
+            return "audio/basic";  // .au format, little endian
+        }
+
+        if (c1 == 'R' && c2 == 'I' && c3 == 'F' && c4 == 'F') {
+            /* I don't know if this is official but evidence
+             * suggests that .wav files start with "RIFF" - brown
+             */
+            return "audio/x-wav";
+        }
+        return null;
+    }
+
+    /**
+     * Check for FlashPix image data in InputStream is.  Return true if
+     * the stream has FlashPix data, false otherwise.  Before calling this
+     * method, the stream should have already been checked to be sure it
+     * contains Microsoft Structured Storage data.
+     */
+    static private boolean checkfpx(InputStream is) throws IOException {
+
+        /* Test for FlashPix image data in Microsoft Structured Storage format.
+         * In general, should do this with calls to an SS implementation.
+         * Lacking that, need to dig via offsets to get to the FlashPix
+         * ClassID.  Details:
+         *
+         * Offset to Fpx ClsID from beginning of stream should be:
+         *
+         * FpxClsidOffset = rootEntryOffset + clsidOffset
+         *
+         * where: clsidOffset = 0x50.
+         *        rootEntryOffset = headerSize + sectorSize*sectDirStart
+         *                          + 128*rootEntryDirectory
+         *
+         *        where:  headerSize = 0x200 (always)
+         *                sectorSize = 2 raised to power of uSectorShift,
+         *                             which is found in the header at
+         *                             offset 0x1E.
+         *                sectDirStart = found in the header at offset 0x30.
+         *                rootEntryDirectory = in general, should search for
+         *                                     directory labelled as root.
+         *                                     We will assume value of 0 (i.e.,
+         *                                     rootEntry is in first directory)
+         */
+
+        // Mark the stream so we can reset it. 0x100 is enough for the first
+        // few reads, but the mark will have to be reset and set again once
+        // the offset to the root directory entry is computed. That offset
+        // can be very large and isn't know until the stream has been read from
+        is.mark(0x100);
+
+        // Get the byte ordering located at 0x1E. 0xFE is Intel,
+        // 0xFF is other
+        long toSkip = (long)0x1C;
+        long posn;
+
+        if ((posn = skipForward(is, toSkip)) < toSkip) {
+          is.reset();
+          return false;
+        }
+
+        int c[] = new int[16];
+        if (readBytes(c, 2, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        int byteOrder = c[0];
+
+        posn+=2;
+        int uSectorShift;
+        if (readBytes(c, 2, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        if(byteOrder == 0xFE) {
+            uSectorShift = c[0];
+            uSectorShift += c[1] << 8;
+        }
+        else {
+            uSectorShift = c[0] << 8;
+            uSectorShift += c[1];
+        }
+
+        posn += 2;
+        toSkip = (long)0x30 - posn;
+        long skipped = 0;
+        if ((skipped = skipForward(is, toSkip)) < toSkip) {
+          is.reset();
+          return false;
+        }
+        posn += skipped;
+
+        if (readBytes(c, 4, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        int sectDirStart;
+        if(byteOrder == 0xFE) {
+            sectDirStart = c[0];
+            sectDirStart += c[1] << 8;
+            sectDirStart += c[2] << 16;
+            sectDirStart += c[3] << 24;
+        } else {
+            sectDirStart =  c[0] << 24;
+            sectDirStart += c[1] << 16;
+            sectDirStart += c[2] << 8;
+            sectDirStart += c[3];
+        }
+        posn += 4;
+        is.reset(); // Reset back to the beginning
+
+        toSkip = 0x200L + (long)(1<<uSectorShift)*sectDirStart + 0x50L;
+
+        // Sanity check!
+        if (toSkip < 0) {
+            return false;
+        }
+
+        /*
+         * How far can we skip? Is there any performance problem here?
+         * This skip can be fairly long, at least 0x4c650 in at least
+         * one case. Have to assume that the skip will fit in an int.
+         * Leave room to read whole root dir
+         */
+        is.mark((int)toSkip+0x30);
+
+        if ((skipForward(is, toSkip)) < toSkip) {
+            is.reset();
+            return false;
+        }
+
+        /* should be at beginning of ClassID, which is as follows
+         * (in Intel byte order):
+         *    00 67 61 56 54 C1 CE 11 85 53 00 AA 00 A1 F9 5B
+         *
+         * This is stored from Windows as long,short,short,char[8]
+         * so for byte order changes, the order only changes for
+         * the first 8 bytes in the ClassID.
+         *
+         * Test against this, ignoring second byte (Intel) since
+         * this could change depending on part of Fpx file we have.
+         */
+
+        if (readBytes(c, 16, is) < 0) {
+            is.reset();
+            return false;
+        }
+
+        // intel byte order
+        if (byteOrder == 0xFE &&
+            c[0] == 0x00 && c[2] == 0x61 && c[3] == 0x56 &&
+            c[4] == 0x54 && c[5] == 0xC1 && c[6] == 0xCE &&
+            c[7] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
+            c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
+            c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
+            is.reset();
+            return true;
+        }
+
+        // non-intel byte order
+        else if (c[3] == 0x00 && c[1] == 0x61 && c[0] == 0x56 &&
+            c[5] == 0x54 && c[4] == 0xC1 && c[7] == 0xCE &&
+            c[6] == 0x11 && c[8] == 0x85 && c[9] == 0x53 &&
+            c[10]== 0x00 && c[11]== 0xAA && c[12]== 0x00 &&
+            c[13]== 0xA1 && c[14]== 0xF9 && c[15]== 0x5B) {
+            is.reset();
+            return true;
+        }
+        is.reset();
+        return false;
+    }
+
+    /**
+     * Tries to read the specified number of bytes from the stream
+     * Returns -1, If EOF is reached before len bytes are read, returns 0
+     * otherwise
+     */
+    static private int readBytes(int c[], int len, InputStream is)
+                throws IOException {
+
+        byte buf[] = new byte[len];
+        if (is.read(buf, 0, len) < len) {
+            return -1;
+        }
+
+        // fill the passed in int array
+        for (int i = 0; i < len; i++) {
+             c[i] = buf[i] & 0xff;
+        }
+        return 0;
+    }
+
+
+    /**
+     * Skips through the specified number of bytes from the stream
+     * until either EOF is reached, or the specified
+     * number of bytes have been skipped
+     */
+    static private long skipForward(InputStream is, long toSkip)
+                throws IOException {
+
+        long eachSkip = 0;
+        long skipped = 0;
+
+        while (skipped != toSkip) {
+            eachSkip = is.skip(toSkip - skipped);
+
+            // check if EOF is reached
+            if (eachSkip <= 0) {
+                if (is.read() == -1) {
+                    return skipped ;
+                } else {
+                    skipped++;
+                }
+            }
+            skipped += eachSkip;
+        }
+        return skipped;
+    }
+
+}
+
+
+class UnknownContentHandler extends ContentHandler {
+    static final ContentHandler INSTANCE = new UnknownContentHandler();
+
+    public Object getContent(URLConnection uc) throws IOException {
+        return uc.getInputStream();
+    }
+}
diff --git a/java/net/URLDecoder.java b/java/net/URLDecoder.java
new file mode 100644
index 0000000..8b14eb8
--- /dev/null
+++ b/java/net/URLDecoder.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.*;
+
+/**
+ * Utility class for HTML form decoding. This class contains static methods
+ * for decoding a String from the <CODE>application/x-www-form-urlencoded</CODE>
+ * MIME format.
+ * <p>
+ * The conversion process is the reverse of that used by the URLEncoder class. It is assumed
+ * that all characters in the encoded string are one of the following:
+ * &quot;{@code a}&quot; through &quot;{@code z}&quot;,
+ * &quot;{@code A}&quot; through &quot;{@code Z}&quot;,
+ * &quot;{@code 0}&quot; through &quot;{@code 9}&quot;, and
+ * &quot;{@code -}&quot;, &quot;{@code _}&quot;,
+ * &quot;{@code .}&quot;, and &quot;{@code *}&quot;. The
+ * character &quot;{@code %}&quot; is allowed but is interpreted
+ * as the start of a special escaped sequence.
+ * <p>
+ * The following rules are applied in the conversion:
+ *
+ * <ul>
+ * <li>The alphanumeric characters &quot;{@code a}&quot; through
+ *     &quot;{@code z}&quot;, &quot;{@code A}&quot; through
+ *     &quot;{@code Z}&quot; and &quot;{@code 0}&quot;
+ *     through &quot;{@code 9}&quot; remain the same.
+ * <li>The special characters &quot;{@code .}&quot;,
+ *     &quot;{@code -}&quot;, &quot;{@code *}&quot;, and
+ *     &quot;{@code _}&quot; remain the same.
+ * <li>The plus sign &quot;{@code +}&quot; is converted into a
+ *     space character &quot; &nbsp; &quot; .
+ * <li>A sequence of the form "<i>{@code %xy}</i>" will be
+ *     treated as representing a byte where <i>xy</i> is the two-digit
+ *     hexadecimal representation of the 8 bits. Then, all substrings
+ *     that contain one or more of these byte sequences consecutively
+ *     will be replaced by the character(s) whose encoding would result
+ *     in those consecutive bytes.
+ *     The encoding scheme used to decode these characters may be specified,
+ *     or if unspecified, the default encoding of the platform will be used.
+ * </ul>
+ * <p>
+ * There are two possible ways in which this decoder could deal with
+ * illegal strings.  It could either leave illegal characters alone or
+ * it could throw an {@link java.lang.IllegalArgumentException}.
+ * Which approach the decoder takes is left to the
+ * implementation.
+ *
+ * @author  Mark Chamness
+ * @author  Michael McCloskey
+ * @since   1.2
+ */
+
+public class URLDecoder {
+
+    // The platform default encoding
+    static String dfltEncName = URLEncoder.dfltEncName;
+
+    /**
+     * Decodes a {@code x-www-form-urlencoded} string.
+     * The platform's default encoding is used to determine what characters
+     * are represented by any consecutive sequences of the form
+     * "<i>{@code %xy}</i>".
+     * @param s the {@code String} to decode
+     * @deprecated The resulting string may vary depending on the platform's
+     *          default encoding. Instead, use the decode(String,String) method
+     *          to specify the encoding.
+     * @return the newly decoded {@code String}
+     */
+    @Deprecated
+    public static String decode(String s) {
+
+        String str = null;
+
+        try {
+            str = decode(s, dfltEncName);
+        } catch (UnsupportedEncodingException e) {
+            // The system should always have the platform default
+        }
+
+        return str;
+    }
+
+    /**
+     * Decodes a {@code application/x-www-form-urlencoded} string using a specific
+     * encoding scheme.
+     * The supplied encoding is used to determine
+     * what characters are represented by any consecutive sequences of the
+     * form "<i>{@code %xy}</i>".
+     * <p>
+     * <em><strong>Note:</strong> The <a href=
+     * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
+     * World Wide Web Consortium Recommendation</a> states that
+     * UTF-8 should be used. Not doing so may introduce
+     * incompatibilities.</em>
+     *
+     * @param s the {@code String} to decode
+     * @param enc   The name of a supported
+     *    <a href="../lang/package-summary.html#charenc">character
+     *    encoding</a>.
+     * @return the newly decoded {@code String}
+     * @exception  UnsupportedEncodingException
+     *             If character encoding needs to be consulted, but
+     *             named character encoding is not supported
+     * @see URLEncoder#encode(java.lang.String, java.lang.String)
+     * @since 1.4
+     */
+    public static String decode(String s, String enc)
+        throws UnsupportedEncodingException{
+
+        boolean needToChange = false;
+        int numChars = s.length();
+        StringBuffer sb = new StringBuffer(numChars > 500 ? numChars / 2 : numChars);
+        int i = 0;
+
+        if (enc.length() == 0) {
+            throw new UnsupportedEncodingException ("URLDecoder: empty string enc parameter");
+        }
+
+        char c;
+        byte[] bytes = null;
+        while (i < numChars) {
+            c = s.charAt(i);
+            switch (c) {
+            case '+':
+                sb.append(' ');
+                i++;
+                needToChange = true;
+                break;
+            case '%':
+                /*
+                 * Starting with this instance of %, process all
+                 * consecutive substrings of the form %xy. Each
+                 * substring %xy will yield a byte. Convert all
+                 * consecutive  bytes obtained this way to whatever
+                 * character(s) they represent in the provided
+                 * encoding.
+                 */
+
+                try {
+
+                    // (numChars-i)/3 is an upper bound for the number
+                    // of remaining bytes
+                    if (bytes == null)
+                        bytes = new byte[(numChars-i)/3];
+                    int pos = 0;
+
+                    while ( ((i+2) < numChars) &&
+                            (c=='%')) {
+                        // BEGIN Android-changed: App compat. Forbid non-hex chars after '%'.
+                        if (!isValidHexChar(s.charAt(i+1)) || !isValidHexChar(s.charAt(i+2))) {
+                            throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern : "
+                                    + s.substring(i, i + 3));
+                        }
+                        // END Android-changed: App compat. Forbid non-hex chars after '%'.
+                        int v = Integer.parseInt(s.substring(i+1,i+3),16);
+                        if (v < 0)
+                            // Android-changed: Improve error message by printing the string value.
+                            throw new IllegalArgumentException("URLDecoder: Illegal hex characters in escape (%) pattern - negative value : "
+                                    + s.substring(i, i + 3));
+                        bytes[pos++] = (byte) v;
+                        i+= 3;
+                        if (i < numChars)
+                            c = s.charAt(i);
+                    }
+
+                    // A trailing, incomplete byte encoding such as
+                    // "%x" will cause an exception to be thrown
+
+                    if ((i < numChars) && (c=='%'))
+                        throw new IllegalArgumentException(
+                         "URLDecoder: Incomplete trailing escape (%) pattern");
+
+                    sb.append(new String(bytes, 0, pos, enc));
+                } catch (NumberFormatException e) {
+                    throw new IllegalArgumentException(
+                    "URLDecoder: Illegal hex characters in escape (%) pattern - "
+                    + e.getMessage());
+                }
+                needToChange = true;
+                break;
+            default:
+                sb.append(c);
+                i++;
+                break;
+            }
+        }
+
+        return (needToChange? sb.toString() : s);
+    }
+
+    // BEGIN Android-added: App compat. Forbid non-hex chars after '%'.
+    private static boolean isValidHexChar(char c) {
+        return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+    }
+    // END Android-added: App compat. Forbid non-hex chars after '%'.
+}
diff --git a/java/net/URLEncoder.java b/java/net/URLEncoder.java
new file mode 100644
index 0000000..86377b7
--- /dev/null
+++ b/java/net/URLEncoder.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.ByteArrayOutputStream;
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.io.CharArrayWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException ;
+import java.util.BitSet;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetBooleanAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Utility class for HTML form encoding. This class contains static methods
+ * for converting a String to the <CODE>application/x-www-form-urlencoded</CODE> MIME
+ * format. For more information about HTML form encoding, consult the HTML
+ * <A HREF="http://www.w3.org/TR/html4/">specification</A>.
+ *
+ * <p>
+ * When encoding a String, the following rules apply:
+ *
+ * <ul>
+ * <li>The alphanumeric characters &quot;{@code a}&quot; through
+ *     &quot;{@code z}&quot;, &quot;{@code A}&quot; through
+ *     &quot;{@code Z}&quot; and &quot;{@code 0}&quot;
+ *     through &quot;{@code 9}&quot; remain the same.
+ * <li>The special characters &quot;{@code .}&quot;,
+ *     &quot;{@code -}&quot;, &quot;{@code *}&quot;, and
+ *     &quot;{@code _}&quot; remain the same.
+ * <li>The space character &quot; &nbsp; &quot; is
+ *     converted into a plus sign &quot;{@code +}&quot;.
+ * <li>All other characters are unsafe and are first converted into
+ *     one or more bytes using some encoding scheme. Then each byte is
+ *     represented by the 3-character string
+ *     &quot;<i>{@code %xy}</i>&quot;, where <i>xy</i> is the
+ *     two-digit hexadecimal representation of the byte.
+ *     The recommended encoding scheme to use is UTF-8. However,
+ *     for compatibility reasons, if an encoding is not specified,
+ *     then the default encoding of the platform is used.
+ * </ul>
+ *
+ * <p>
+ * For example using UTF-8 as the encoding scheme the string &quot;The
+ * string &#252;@foo-bar&quot; would get converted to
+ * &quot;The+string+%C3%BC%40foo-bar&quot; because in UTF-8 the character
+ * &#252; is encoded as two bytes C3 (hex) and BC (hex), and the
+ * character @ is encoded as one byte 40 (hex).
+ *
+ * @author  Herb Jellinek
+ * @since   JDK1.0
+ */
+public class URLEncoder {
+    static BitSet dontNeedEncoding;
+    static final int caseDiff = ('a' - 'A');
+    static String dfltEncName = null;
+
+    static {
+
+        /* The list of characters that are not encoded has been
+         * determined as follows:
+         *
+         * RFC 2396 states:
+         * -----
+         * Data characters that are allowed in a URI but do not have a
+         * reserved purpose are called unreserved.  These include upper
+         * and lower case letters, decimal digits, and a limited set of
+         * punctuation marks and symbols.
+         *
+         * unreserved  = alphanum | mark
+         *
+         * mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+         *
+         * Unreserved characters can be escaped without changing the
+         * semantics of the URI, but this should not be done unless the
+         * URI is being used in a context that does not allow the
+         * unescaped character to appear.
+         * -----
+         *
+         * It appears that both Netscape and Internet Explorer escape
+         * all special characters from this list with the exception
+         * of "-", "_", ".", "*". While it is not clear why they are
+         * escaping the other characters, perhaps it is safest to
+         * assume that there might be contexts in which the others
+         * are unsafe if not escaped. Therefore, we will use the same
+         * list. It is also noteworthy that this is consistent with
+         * O'Reilly's "HTML: The Definitive Guide" (page 164).
+         *
+         * As a last note, Intenet Explorer does not encode the "@"
+         * character which is clearly not unreserved according to the
+         * RFC. We are being consistent with the RFC in this matter,
+         * as is Netscape.
+         *
+         */
+
+        dontNeedEncoding = new BitSet(256);
+        int i;
+        for (i = 'a'; i <= 'z'; i++) {
+            dontNeedEncoding.set(i);
+        }
+        for (i = 'A'; i <= 'Z'; i++) {
+            dontNeedEncoding.set(i);
+        }
+        for (i = '0'; i <= '9'; i++) {
+            dontNeedEncoding.set(i);
+        }
+        dontNeedEncoding.set(' '); /* encoding a space to a + is done
+                                    * in the encode() method */
+        dontNeedEncoding.set('-');
+        dontNeedEncoding.set('_');
+        dontNeedEncoding.set('.');
+        dontNeedEncoding.set('*');
+
+        dfltEncName = AccessController.doPrivileged(
+            new GetPropertyAction("file.encoding")
+        );
+    }
+
+    /**
+     * You can't call the constructor.
+     */
+    private URLEncoder() { }
+
+    /**
+     * Translates a string into {@code x-www-form-urlencoded}
+     * format. This method uses the platform's default encoding
+     * as the encoding scheme to obtain the bytes for unsafe characters.
+     *
+     * @param   s   {@code String} to be translated.
+     * @deprecated The resulting string may vary depending on the platform's
+     *             default encoding. Instead, use the encode(String,String)
+     *             method to specify the encoding.
+     * @return  the translated {@code String}.
+     */
+    @Deprecated
+    public static String encode(String s) {
+
+        String str = null;
+
+        try {
+            str = encode(s, dfltEncName);
+        } catch (UnsupportedEncodingException e) {
+            // The system should always have the platform default
+        }
+
+        return str;
+    }
+
+    /**
+     * Translates a string into {@code application/x-www-form-urlencoded}
+     * format using a specific encoding scheme. This method uses the
+     * supplied encoding scheme to obtain the bytes for unsafe
+     * characters.
+     * <p>
+     * <em><strong>Note:</strong> The <a href=
+     * "http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars">
+     * World Wide Web Consortium Recommendation</a> states that
+     * UTF-8 should be used. Not doing so may introduce
+     * incompatibilities.</em>
+     *
+     * @param   s   {@code String} to be translated.
+     * @param   enc   The name of a supported
+     *    <a href="../lang/package-summary.html#charenc">character
+     *    encoding</a>.
+     * @return  the translated {@code String}.
+     * @exception  UnsupportedEncodingException
+     *             If the named encoding is not supported
+     * @see URLDecoder#decode(java.lang.String, java.lang.String)
+     * @since 1.4
+     */
+    public static String encode(String s, String enc)
+        throws UnsupportedEncodingException {
+
+        boolean needToChange = false;
+        StringBuffer out = new StringBuffer(s.length());
+        Charset charset;
+        CharArrayWriter charArrayWriter = new CharArrayWriter();
+
+        if (enc == null)
+            throw new NullPointerException("charsetName");
+
+        try {
+            charset = Charset.forName(enc);
+        } catch (IllegalCharsetNameException e) {
+            throw new UnsupportedEncodingException(enc);
+        } catch (UnsupportedCharsetException e) {
+            throw new UnsupportedEncodingException(enc);
+        }
+
+        for (int i = 0; i < s.length();) {
+            int c = (int) s.charAt(i);
+            //System.out.println("Examining character: " + c);
+            if (dontNeedEncoding.get(c)) {
+                if (c == ' ') {
+                    c = '+';
+                    needToChange = true;
+                }
+                //System.out.println("Storing: " + c);
+                out.append((char)c);
+                i++;
+            } else {
+                // convert to external encoding before hex conversion
+                do {
+                    charArrayWriter.write(c);
+                    /*
+                     * If this character represents the start of a Unicode
+                     * surrogate pair, then pass in two characters. It's not
+                     * clear what should be done if a bytes reserved in the
+                     * surrogate pairs range occurs outside of a legal
+                     * surrogate pair. For now, just treat it as if it were
+                     * any other character.
+                     */
+                    if (c >= 0xD800 && c <= 0xDBFF) {
+                        /*
+                          System.out.println(Integer.toHexString(c)
+                          + " is high surrogate");
+                        */
+                        if ( (i+1) < s.length()) {
+                            int d = (int) s.charAt(i+1);
+                            /*
+                              System.out.println("\tExamining "
+                              + Integer.toHexString(d));
+                            */
+                            if (d >= 0xDC00 && d <= 0xDFFF) {
+                                /*
+                                  System.out.println("\t"
+                                  + Integer.toHexString(d)
+                                  + " is low surrogate");
+                                */
+                                charArrayWriter.write(d);
+                                i++;
+                            }
+                        }
+                    }
+                    i++;
+                } while (i < s.length() && !dontNeedEncoding.get((c = (int) s.charAt(i))));
+
+                charArrayWriter.flush();
+                String str = new String(charArrayWriter.toCharArray());
+                byte[] ba = str.getBytes(charset);
+                for (int j = 0; j < ba.length; j++) {
+                    out.append('%');
+                    char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
+                    // converting to use uppercase letter as part of
+                    // the hex value if ch is a letter.
+                    if (Character.isLetter(ch)) {
+                        ch -= caseDiff;
+                    }
+                    out.append(ch);
+                    ch = Character.forDigit(ba[j] & 0xF, 16);
+                    if (Character.isLetter(ch)) {
+                        ch -= caseDiff;
+                    }
+                    out.append(ch);
+                }
+                charArrayWriter.reset();
+                needToChange = true;
+            }
+        }
+
+        return (needToChange? out.toString() : s);
+    }
+}
diff --git a/java/net/URLStreamHandler.java b/java/net/URLStreamHandler.java
new file mode 100644
index 0000000..dffc6d5
--- /dev/null
+++ b/java/net/URLStreamHandler.java
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import sun.net.util.IPAddressUtil;
+
+/**
+ * The abstract class {@code URLStreamHandler} is the common
+ * superclass for all stream protocol handlers. A stream protocol
+ * handler knows how to make a connection for a particular protocol
+ * type, such as {@code http} or {@code https}.
+ * <p>
+ * In most cases, an instance of a {@code URLStreamHandler}
+ * subclass is not created directly by an application. Rather, the
+ * first time a protocol name is encountered when constructing a
+ * {@code URL}, the appropriate stream protocol handler is
+ * automatically loaded.
+ *
+ * @author  James Gosling
+ * @see     java.net.URL#URL(java.lang.String, java.lang.String, int, java.lang.String)
+ * @since   JDK1.0
+ */
+public abstract class URLStreamHandler {
+    /**
+     * Opens a connection to the object referenced by the
+     * {@code URL} argument.
+     * This method should be overridden by a subclass.
+     *
+     * <p>If for the handler's protocol (such as HTTP or JAR), there
+     * exists a public, specialized URLConnection subclass belonging
+     * to one of the following packages or one of their subpackages:
+     * java.lang, java.io, java.util, java.net, the connection
+     * returned will be of that subclass. For example, for HTTP an
+     * HttpURLConnection will be returned, and for JAR a
+     * JarURLConnection will be returned.
+     *
+     * @param      u   the URL that this connects to.
+     * @return     a {@code URLConnection} object for the {@code URL}.
+     * @exception  IOException  if an I/O error occurs while opening the
+     *               connection.
+     */
+    abstract protected URLConnection openConnection(URL u) throws IOException;
+
+    /**
+     * Same as openConnection(URL), except that the connection will be
+     * made through the specified proxy; Protocol handlers that do not
+     * support proxying will ignore the proxy parameter and make a
+     * normal connection.
+     *
+     * Calling this method preempts the system's default ProxySelector
+     * settings.
+     *
+     * @param      u   the URL that this connects to.
+     * @param      p   the proxy through which the connection will be made.
+     *                 If direct connection is desired, Proxy.NO_PROXY
+     *                 should be specified.
+     * @return     a {@code URLConnection} object for the {@code URL}.
+     * @exception  IOException  if an I/O error occurs while opening the
+     *               connection.
+     * @exception  IllegalArgumentException if either u or p is null,
+     *               or p has the wrong type.
+     * @exception  UnsupportedOperationException if the subclass that
+     *               implements the protocol doesn't support this method.
+     * @since      1.5
+     */
+    protected URLConnection openConnection(URL u, Proxy p) throws IOException {
+        throw new UnsupportedOperationException("Method not implemented.");
+    }
+
+    /**
+     * Parses the string representation of a {@code URL} into a
+     * {@code URL} object.
+     * <p>
+     * If there is any inherited context, then it has already been
+     * copied into the {@code URL} argument.
+     * <p>
+     * The {@code parseURL} method of {@code URLStreamHandler}
+     * parses the string representation as if it were an
+     * {@code http} specification. Most URL protocol families have a
+     * similar parsing. A stream protocol handler for a protocol that has
+     * a different syntax must override this routine.
+     *
+     * @param   u       the {@code URL} to receive the result of parsing
+     *                  the spec.
+     * @param   spec    the {@code String} representing the URL that
+     *                  must be parsed.
+     * @param   start   the character index at which to begin parsing. This is
+     *                  just past the '{@code :}' (if there is one) that
+     *                  specifies the determination of the protocol name.
+     * @param   limit   the character position to stop parsing at. This is the
+     *                  end of the string or the position of the
+     *                  "{@code #}" character, if present. All information
+     *                  after the sharp sign indicates an anchor.
+     */
+    protected void parseURL(URL u, String spec, int start, int limit) {
+        // These fields may receive context content if this was relative URL
+        String protocol = u.getProtocol();
+        String authority = u.getAuthority();
+        String userInfo = u.getUserInfo();
+        String host = u.getHost();
+        int port = u.getPort();
+        String path = u.getPath();
+        String query = u.getQuery();
+
+        // This field has already been parsed
+        String ref = u.getRef();
+
+        boolean isRelPath = false;
+        boolean queryOnly = false;
+        // BEGIN Android-changed: App compat
+        boolean querySet = false;
+        // END Android-changed: App compat
+
+// FIX: should not assume query if opaque
+        // Strip off the query part
+        if (start < limit) {
+            int queryStart = spec.indexOf('?');
+            queryOnly = queryStart == start;
+            if ((queryStart != -1) && (queryStart < limit)) {
+                query = spec.substring(queryStart+1, limit);
+                if (limit > queryStart)
+                    limit = queryStart;
+                spec = spec.substring(0, queryStart);
+                // BEGIN Android-changed: App compat
+                querySet = true;
+                // END Android-changed: App compat
+            }
+        }
+
+        int i = 0;
+        // Parse the authority part if any
+        // BEGIN Android-changed: App compat
+        // boolean isUNCName = (start <= limit - 4) &&
+        //                 (spec.charAt(start) == '/') &&
+        //                 (spec.charAt(start + 1) == '/') &&
+        //                 (spec.charAt(start + 2) == '/') &&
+        //                 (spec.charAt(start + 3) == '/');
+        boolean isUNCName = false;
+        // END Android-changed: App compat
+        if (!isUNCName && (start <= limit - 2) && (spec.charAt(start) == '/') &&
+            (spec.charAt(start + 1) == '/')) {
+            start += 2;
+            // BEGIN Android-changed: Check for all hostname termination chars. http://b/110955991
+            /*
+            i = spec.indexOf('/', start);
+            if (i < 0 || i > limit) {
+                i = spec.indexOf('?', start);
+                if (i < 0 || i > limit)
+                    i = limit;
+            }
+            */
+            LOOP: for (i = start; i < limit; i++) {
+                switch (spec.charAt(i)) {
+                    case '/':  // Start of path
+                    case '\\': // Start of path - see https://url.spec.whatwg.org/#host-state
+                    case '?':  // Start of query
+                    case '#':  // Start of fragment
+                        break LOOP;
+                }
+            }
+            // END Android-changed: Check for all hostname termination chars. http://b/110955991
+
+            host = authority = spec.substring(start, i);
+
+            int ind = authority.indexOf('@');
+            if (ind != -1) {
+                if (ind != authority.lastIndexOf('@')) {
+                    // more than one '@' in authority. This is not server based
+                    userInfo = null;
+                    host = null;
+                } else {
+                    userInfo = authority.substring(0, ind);
+                    host = authority.substring(ind+1);
+                }
+            } else {
+                userInfo = null;
+            }
+            if (host != null) {
+                // If the host is surrounded by [ and ] then its an IPv6
+                // literal address as specified in RFC2732
+                if (host.length()>0 && (host.charAt(0) == '[')) {
+                    if ((ind = host.indexOf(']')) > 2) {
+
+                        String nhost = host ;
+                        host = nhost.substring(0,ind+1);
+                        if (!IPAddressUtil.
+                            isIPv6LiteralAddress(host.substring(1, ind))) {
+                            throw new IllegalArgumentException(
+                                "Invalid host: "+ host);
+                        }
+
+                        port = -1 ;
+                        if (nhost.length() > ind+1) {
+                            if (nhost.charAt(ind+1) == ':') {
+                                ++ind ;
+                                // port can be null according to RFC2396
+                                if (nhost.length() > (ind + 1)) {
+                                    port = Integer.parseInt(nhost.substring(ind+1));
+                                }
+                            } else {
+                                throw new IllegalArgumentException(
+                                    "Invalid authority field: " + authority);
+                            }
+                        }
+                    } else {
+                        throw new IllegalArgumentException(
+                            "Invalid authority field: " + authority);
+                    }
+                } else {
+                    ind = host.indexOf(':');
+                    port = -1;
+                    if (ind >= 0) {
+                        // port can be null according to RFC2396
+                        if (host.length() > (ind + 1)) {
+                            // BEGIN Android-changed: App compat
+                            // port = Integer.parseInt(host.substring(ind + 1));
+                            char firstPortChar = host.charAt(ind+1);
+                            if (firstPortChar >= '0' && firstPortChar <= '9') {
+                                port = Integer.parseInt(host.substring(ind + 1));
+                            } else {
+                                throw new IllegalArgumentException("invalid port: " +
+                                                                   host.substring(ind + 1));
+                            }
+                            // END Android-changed: App compat
+                        }
+                        host = host.substring(0, ind);
+                    }
+                }
+            } else {
+                host = "";
+            }
+            if (port < -1)
+                throw new IllegalArgumentException("Invalid port number :" +
+                                                   port);
+            start = i;
+
+            // If the authority is defined then the path is defined by the
+            // spec only; See RFC 2396 Section 5.2.4.
+            // BEGIN Android-changed: App compat
+            // if (authority != null && authority.length() > 0)
+            //   path = "";
+            path = null;
+            if (!querySet) {
+                query = null;
+            }
+            // END Android-changed: App compat
+        }
+
+        if (host == null) {
+            host = "";
+        }
+
+        // Parse the file path if any
+        if (start < limit) {
+            // Android-changed: Check for all hostname termination chars. http://b/110955991
+            // if (spec.charAt(start) == '/') {
+            if (spec.charAt(start) == '/' || spec.charAt(start) == '\\') {
+                path = spec.substring(start, limit);
+            } else if (path != null && path.length() > 0) {
+                isRelPath = true;
+                int ind = path.lastIndexOf('/');
+                String seperator = "";
+                if (ind == -1 && authority != null)
+                    seperator = "/";
+                path = path.substring(0, ind + 1) + seperator +
+                         spec.substring(start, limit);
+
+            } else {
+                String seperator = (authority != null) ? "/" : "";
+                path = seperator + spec.substring(start, limit);
+            }
+        }
+        // BEGIN Android-changed: App compat
+        //else if (queryOnly && path != null) {
+        //    int ind = path.lastIndexOf('/');
+        //    if (ind < 0)
+        //        ind = 0;
+        //    path = path.substring(0, ind) + "/";
+        //}
+        // END Android-changed: App compat
+        if (path == null)
+            path = "";
+
+        // BEGIN Android-changed
+        //if (isRelPath) {
+        if (true) {
+        // END Android-changed
+            // Remove embedded /./
+            while ((i = path.indexOf("/./")) >= 0) {
+                path = path.substring(0, i) + path.substring(i + 2);
+            }
+            // Remove embedded /../ if possible
+            i = 0;
+            while ((i = path.indexOf("/../", i)) >= 0) {
+                // BEGIN Android-changed: App compat
+                /*
+                 * Trailing /../
+                 */
+                if (i == 0) {
+                    path = path.substring(i + 3);
+                    i = 0;
+                // END Android-changed: App compat
+                /*
+                 * A "/../" will cancel the previous segment and itself,
+                 * unless that segment is a "/../" itself
+                 * i.e. "/a/b/../c" becomes "/a/c"
+                 * but "/../../a" should stay unchanged
+                 */
+                // Android-changed: App compat
+                // if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
+                } else if (i > 0 && (limit = path.lastIndexOf('/', i - 1)) >= 0 &&
+                    (path.indexOf("/../", limit) != 0)) {
+                    path = path.substring(0, limit) + path.substring(i + 3);
+                    i = 0;
+                } else {
+                    i = i + 3;
+                }
+            }
+            // Remove trailing .. if possible
+            while (path.endsWith("/..")) {
+                i = path.indexOf("/..");
+                if ((limit = path.lastIndexOf('/', i - 1)) >= 0) {
+                    path = path.substring(0, limit+1);
+                } else {
+                    break;
+                }
+            }
+            // Remove starting .
+            if (path.startsWith("./") && path.length() > 2)
+                path = path.substring(2);
+
+            // Remove trailing .
+            if (path.endsWith("/."))
+                path = path.substring(0, path.length() -1);
+
+            // Android-changed: App compat: Remove trailing ?
+            if (path.endsWith("?"))
+                path = path.substring(0, path.length() -1);
+        }
+
+        setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
+    }
+
+    /**
+     * Returns the default port for a URL parsed by this handler. This method
+     * is meant to be overidden by handlers with default port numbers.
+     * @return the default port for a {@code URL} parsed by this handler.
+     * @since 1.3
+     */
+    protected int getDefaultPort() {
+        return -1;
+    }
+
+    /**
+     * Provides the default equals calculation. May be overidden by handlers
+     * for other protocols that have different requirements for equals().
+     * This method requires that none of its arguments is null. This is
+     * guaranteed by the fact that it is only called by java.net.URL class.
+     * @param u1 a URL object
+     * @param u2 a URL object
+     * @return {@code true} if the two urls are
+     * considered equal, ie. they refer to the same
+     * fragment in the same file.
+     * @since 1.3
+     */
+    protected boolean equals(URL u1, URL u2) {
+        // Android-changed: Avoid network I/O
+        return Objects.equals(u1.getRef(), u2.getRef()) &&
+               Objects.equals(u1.getQuery(), u2.getQuery()) &&
+               // sameFile compares the protocol, file, port & host components of
+               // the URLs.
+               sameFile(u1, u2);
+    }
+
+    /**
+     * Provides the default hash calculation. May be overidden by handlers for
+     * other protocols that have different requirements for hashCode
+     * calculation.
+     * @param u a URL object
+     * @return an {@code int} suitable for hash table indexing
+     * @since 1.3
+     */
+    protected int hashCode(URL u) {
+        // Android-changed: Avoid network I/O
+        // Hash on the same set of fields that we compare in equals().
+        return Objects.hash(
+                u.getRef(),
+                u.getQuery(),
+                u.getProtocol(),
+                u.getFile(),
+                u.getHost(),
+                u.getPort());
+    }
+
+    /**
+     * Compare two urls to see whether they refer to the same file,
+     * i.e., having the same protocol, host, port, and path.
+     * This method requires that none of its arguments is null. This is
+     * guaranteed by the fact that it is only called indirectly
+     * by java.net.URL class.
+     * @param u1 a URL object
+     * @param u2 a URL object
+     * @return true if u1 and u2 refer to the same file
+     * @since 1.3
+     */
+    protected boolean sameFile(URL u1, URL u2) {
+        // Compare the protocols.
+        if (!((u1.getProtocol() == u2.getProtocol()) ||
+              (u1.getProtocol() != null &&
+               u1.getProtocol().equalsIgnoreCase(u2.getProtocol()))))
+            return false;
+
+        // Compare the files.
+        if (!(u1.getFile() == u2.getFile() ||
+              (u1.getFile() != null && u1.getFile().equals(u2.getFile()))))
+            return false;
+
+        // Compare the ports.
+        int port1, port2;
+        port1 = (u1.getPort() != -1) ? u1.getPort() : u1.handler.getDefaultPort();
+        port2 = (u2.getPort() != -1) ? u2.getPort() : u2.handler.getDefaultPort();
+        if (port1 != port2)
+            return false;
+
+        // Compare the hosts.
+        if (!hostsEqual(u1, u2))
+            return false;
+
+        return true;
+    }
+
+    /**
+     * Get the IP address of our host. An empty host field or a DNS failure
+     * will result in a null return.
+     *
+     * @param u a URL object
+     * @return an {@code InetAddress} representing the host
+     * IP address.
+     * @since 1.3
+     */
+    protected synchronized InetAddress getHostAddress(URL u) {
+        if (u.hostAddress != null)
+            return u.hostAddress;
+
+        String host = u.getHost();
+        if (host == null || host.equals("")) {
+            return null;
+        } else {
+            try {
+                u.hostAddress = InetAddress.getByName(host);
+            } catch (UnknownHostException ex) {
+                return null;
+            } catch (SecurityException se) {
+                return null;
+            }
+        }
+        return u.hostAddress;
+    }
+
+    /**
+     * Compares the host components of two URLs.
+     * @param u1 the URL of the first host to compare
+     * @param u2 the URL of the second host to compare
+     * @return  {@code true} if and only if they
+     * are equal, {@code false} otherwise.
+     * @since 1.3
+     */
+    protected boolean hostsEqual(URL u1, URL u2) {
+        // Android-changed: Don't compare the InetAddresses of the hosts.
+        if (u1.getHost() != null && u2.getHost() != null)
+            return u1.getHost().equalsIgnoreCase(u2.getHost());
+         else
+            return u1.getHost() == null && u2.getHost() == null;
+    }
+
+    /**
+     * Converts a {@code URL} of a specific protocol to a
+     * {@code String}.
+     *
+     * @param   u   the URL.
+     * @return  a string representation of the {@code URL} argument.
+     */
+    protected String toExternalForm(URL u) {
+
+        // pre-compute length of StringBuffer
+        int len = u.getProtocol().length() + 1;
+        if (u.getAuthority() != null && u.getAuthority().length() > 0)
+            len += 2 + u.getAuthority().length();
+        if (u.getPath() != null) {
+            len += u.getPath().length();
+        }
+        if (u.getQuery() != null) {
+            len += 1 + u.getQuery().length();
+        }
+        if (u.getRef() != null)
+            len += 1 + u.getRef().length();
+
+        // BEGIN Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
+        // TODO: The variant has been removed. We can potentially revert the change
+        StringBuilder result = new StringBuilder(len);
+        result.append(u.getProtocol());
+        result.append(":");
+        if (u.getAuthority() != null) {// ANDROID: && u.getAuthority().length() > 0) {
+            result.append("//");
+            result.append(u.getAuthority());
+        }
+        String fileAndQuery = u.getFile();
+        if (fileAndQuery != null) {
+            result.append(fileAndQuery);
+        }
+        // END Android-changed: Add a toExternalForm variant that optionally escapes illegal chars
+        if (u.getRef() != null) {
+            result.append("#");
+            result.append(u.getRef());
+        }
+        return result.toString();
+    }
+
+    // Android-changed: Removed @see tag (target is package-private):
+    // @see     java.net.URL#set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String)
+    /**
+     * Sets the fields of the {@code URL} argument to the indicated values.
+     * Only classes derived from URLStreamHandler are able
+     * to use this method to set the values of the URL fields.
+     *
+     * @param   u         the URL to modify.
+     * @param   protocol  the protocol name.
+     * @param   host      the remote host value for the URL.
+     * @param   port      the port on the remote machine.
+     * @param   authority the authority part for the URL.
+     * @param   userInfo the userInfo part of the URL.
+     * @param   path      the path component of the URL.
+     * @param   query     the query part for the URL.
+     * @param   ref       the reference.
+     * @exception       SecurityException       if the protocol handler of the URL is
+     *                                  different from this one
+     * @since 1.3
+     */
+       protected void setURL(URL u, String protocol, String host, int port,
+                             String authority, String userInfo, String path,
+                             String query, String ref) {
+        if (this != u.handler) {
+            throw new SecurityException("handler for url different from " +
+                                        "this handler");
+        }
+        // ensure that no one can reset the protocol on a given URL.
+        u.set(u.getProtocol(), host, port, authority, userInfo, path, query, ref);
+    }
+
+    /**
+     * Sets the fields of the {@code URL} argument to the indicated values.
+     * Only classes derived from URLStreamHandler are able
+     * to use this method to set the values of the URL fields.
+     *
+     * @param   u         the URL to modify.
+     * @param   protocol  the protocol name. This value is ignored since 1.2.
+     * @param   host      the remote host value for the URL.
+     * @param   port      the port on the remote machine.
+     * @param   file      the file.
+     * @param   ref       the reference.
+     * @exception       SecurityException       if the protocol handler of the URL is
+     *                                  different from this one
+     * @deprecated Use setURL(URL, String, String, int, String, String, String,
+     *             String);
+     */
+    @Deprecated
+    protected void setURL(URL u, String protocol, String host, int port,
+                          String file, String ref) {
+        /*
+         * Only old URL handlers call this, so assume that the host
+         * field might contain "user:passwd@host". Fix as necessary.
+         */
+        String authority = null;
+        String userInfo = null;
+        if (host != null && host.length() != 0) {
+            authority = (port == -1) ? host : host + ":" + port;
+            int at = host.lastIndexOf('@');
+            if (at != -1) {
+                userInfo = host.substring(0, at);
+                host = host.substring(at+1);
+            }
+        }
+
+        /*
+         * Assume file might contain query part. Fix as necessary.
+         */
+        String path = null;
+        String query = null;
+        if (file != null) {
+            int q = file.lastIndexOf('?');
+            if (q != -1) {
+                query = file.substring(q+1);
+                path = file.substring(0, q);
+            } else
+                path = file;
+        }
+        setURL(u, protocol, host, port, authority, userInfo, path, query, ref);
+    }
+}
diff --git a/java/net/URLStreamHandlerFactory.java b/java/net/URLStreamHandlerFactory.java
new file mode 100644
index 0000000..e46e028
--- /dev/null
+++ b/java/net/URLStreamHandlerFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+/**
+ * This interface defines a factory for {@code URL} stream
+ * protocol handlers.
+ * <p>
+ * It is used by the {@code URL} class to create a
+ * {@code URLStreamHandler} for a specific protocol.
+ *
+ * @author  Arthur van Hoff
+ * @see     java.net.URL
+ * @see     java.net.URLStreamHandler
+ * @since   JDK1.0
+ */
+public interface URLStreamHandlerFactory {
+    /**
+     * Creates a new {@code URLStreamHandler} instance with the specified
+     * protocol.
+     *
+     * @param   protocol   the protocol ("{@code ftp}",
+     *                     "{@code http}", "{@code nntp}", etc.).
+     * @return  a {@code URLStreamHandler} for the specific protocol.
+     * @see     java.net.URLStreamHandler
+     */
+    URLStreamHandler createURLStreamHandler(String protocol);
+}
diff --git a/java/net/UnknownHostException.java b/java/net/UnknownHostException.java
new file mode 100644
index 0000000..21a9d14
--- /dev/null
+++ b/java/net/UnknownHostException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that the IP address of a host could not be determined.
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class UnknownHostException extends IOException {
+    private static final long serialVersionUID = -4639126076052875403L;
+
+    /**
+     * Constructs a new {@code UnknownHostException} with the
+     * specified detail message.
+     *
+     * @param   host   the detail message.
+     */
+    public UnknownHostException(String host) {
+        super(host);
+    }
+
+    /**
+     * Constructs a new {@code UnknownHostException} with no detail
+     * message.
+     */
+    public UnknownHostException() {
+    }
+}
diff --git a/java/net/UnknownServiceException.java b/java/net/UnknownServiceException.java
new file mode 100644
index 0000000..4eea4a7
--- /dev/null
+++ b/java/net/UnknownServiceException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that an unknown service exception has
+ * occurred. Either the MIME type returned by a URL connection does
+ * not make sense, or the application is attempting to write to a
+ * read-only URL connection.
+ *
+ * @author  unascribed
+ * @since   JDK1.0
+ */
+public class UnknownServiceException extends IOException {
+    private static final long serialVersionUID = -4169033248853639508L;
+
+    /**
+     * Constructs a new {@code UnknownServiceException} with no
+     * detail message.
+     */
+    public UnknownServiceException() {
+    }
+
+    /**
+     * Constructs a new {@code UnknownServiceException} with the
+     * specified detail message.
+     *
+     * @param   msg   the detail message.
+     */
+    public UnknownServiceException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/net/package-info.java b/java/net/package-info.java
new file mode 100644
index 0000000..fda2e4f
--- /dev/null
+++ b/java/net/package-info.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides the classes for implementing networking applications.
+ *
+ * <p> The java.net package can be roughly divided in two sections:</p>
+ * <ul>
+ *     <li><p><i>A Low Level API</i>, which deals with the
+ *               following abstractions:</p>
+ *     <ul>
+ *       <li><p><i>Addresses</i>, which are networking identifiers,
+ *              like IP addresses.</p></li>
+ *       <li><p><i>Sockets</i>, which are basic bidirectional data communication
+ *              mechanisms.</p></li>
+ *       <li><p><i>Interfaces</i>, which describe network interfaces. </p></li>
+ *     </ul></li>
+ *     <li> <p><i>A High Level API</i>, which deals with the following
+ *          abstractions:</p>
+ *     <ul>
+ *       <li><p><i>URIs</i>, which represent
+ *               Universal Resource Identifiers.</p></li>
+ *       <li><p><i>URLs</i>, which represent
+ *               Universal Resource Locators.</p></li>
+ *       <li><p><i>Connections</i>, which represents connections to the resource
+ *               pointed to by <i>URLs</i>.</p></li>
+ *       </ul></li>
+ * </ul>
+ * <h2>Addresses</h2>
+ * <p>Addresses are used throughout the java.net APIs as either host
+ *    identifiers, or socket endpoint identifiers.</p>
+ * <p>The {@link java.net.InetAddress} class is the abstraction representing an
+ *    IP (Internet Protocol) address.  It has two subclasses:
+ * <ul>
+ *       <li>{@link java.net.Inet4Address} for IPv4 addresses.</li>
+ *       <li>{@link java.net.Inet6Address} for IPv6 addresses.</li>
+ * </ul>
+ * <p>But, in most cases, there is no need to deal directly with the subclasses,
+ *    as the InetAddress abstraction should cover most of the needed
+ *    functionality.</p>
+ * <h3><b>About IPv6</b></h3>
+ * <p>Not all systems have support for the IPv6 protocol, and while the Java
+ *    networking stack will attempt to detect it and use it transparently when
+ *    available, it is also possible to disable its use with a system property.
+ *    In the case where IPv6 is not available, or explicitly disabled,
+ *    Inet6Address are not valid arguments for most networking operations any
+ *    more. While methods like {@link java.net.InetAddress#getByName} are
+ *    guaranteed not to return an Inet6Address when looking up host names, it
+ *    is possible, by passing literals, to create such an object. In which
+ *    case, most methods, when called with an Inet6Address will throw an
+ *    Exception.</p>
+ * <h2>Sockets</h2>
+ * <p>Sockets are means to establish a communication link between machines over
+ *    the network. The java.net package provides 4 kinds of Sockets:</p>
+ * <ul>
+ *       <li>{@link java.net.Socket} is a TCP client API, and will typically
+ *            be used to {@linkplain java.net.Socket#connect(SocketAddress)
+ *            connect} to a remote host.</li>
+ *       <li>{@link java.net.ServerSocket} is a TCP server API, and will
+ *            typically {@linkplain java.net.ServerSocket#accept accept}
+ *            connections from client sockets.</li>
+ *       <li>{@link java.net.DatagramSocket} is a UDP endpoint API and is used
+ *            to {@linkplain java.net.DatagramSocket#send send} and
+ *            {@linkplain java.net.DatagramSocket#receive receive}
+ *            {@linkplain java.net.DatagramPacket datagram packets}.</li>
+ *       <li>{@link java.net.MulticastSocket} is a subclass of
+ *            {@code DatagramSocket} used when dealing with multicast
+ *            groups.</li>
+ * </ul>
+ * <p>Sending and receiving with TCP sockets is done through InputStreams and
+ *    OutputStreams which can be obtained via the
+ *    {@link java.net.Socket#getInputStream} and
+ *    {@link java.net.Socket#getOutputStream} methods.</p>
+ * <h2>Interfaces</h2>
+ * <p>The {@link java.net.NetworkInterface} class provides APIs to browse and
+ *    query all the networking interfaces (e.g. ethernet connection or PPP
+ *    endpoint) of the local machine. It is through that class that you can
+ *    check if any of the local interfaces is configured to support IPv6.</p>
+ * <p>Note, all conforming implementations must support at least one
+ *    {@code NetworkInterface} object, which must either be connected to a
+ *    network, or be a "loopback" interface that can only communicate with
+ *    entities on the same machine.</p>
+ *
+ * <h2>High level API</h2>
+ * <p>A number of classes in the java.net package do provide for a much higher
+ *    level of abstraction and allow for easy access to resources on the
+ *    network. The classes are:
+ * <ul>
+ *       <li>{@link java.net.URI} is the class representing a
+ *            Universal Resource Identifier, as specified in RFC 2396.
+ *            As the name indicates, this is just an Identifier and doesn't
+ *            provide directly the means to access the resource.</li>
+ *       <li>{@link java.net.URL} is the class representing a
+ *            Universal Resource Locator, which is both an older concept for
+ *            URIs and a means to access the resources.</li>
+ *       <li>{@link java.net.URLConnection} is created from a URL and is the
+ *            communication link used to access the resource pointed by the
+ *            URL. This abstract class will delegate most of the work to the
+ *            underlying protocol handlers like http or https.</li>
+ *       <li>{@link java.net.HttpURLConnection} is a subclass of URLConnection
+ *            and provides some additional functionalities specific to the
+ *            HTTP protocol.</li>
+ * </ul>
+ * <p>The recommended usage is to use {@link java.net.URI} to identify
+ *    resources, then convert it into a {@link java.net.URL} when it is time to
+ *    access the resource. From that URL, you can either get the
+ *    {@link java.net.URLConnection} for fine control, or get directly the
+ *    InputStream.
+ * <p>Here is an example:</p>
+ * <pre>
+ * URI uri = new URI("http://java.sun.com/");
+ * URL url = uri.toURL();
+ * InputStream in = url.openStream();
+ * </pre>
+ * <h2>Protocol Handlers</h2>
+ * As mentioned, URL and URLConnection rely on protocol handlers which must be
+ * present, otherwise an Exception is thrown. This is the major difference with
+ * URIs which only identify resources, and therefore don't need to have access
+ * to the protocol handler. So, while it is possible to create an URI with any
+ * kind of protocol scheme (e.g. {@code myproto://myhost.mydomain/resource/}),
+ * a similar URL will try to instantiate the handler for the specified protocol;
+ * if it doesn't exist an exception will be thrown.
+ * <p>By default the protocol handlers are loaded dynamically from the default
+ *    location. It is, however, possible to add to the search path by setting
+ *    the {@code java.protocol.handler.pkgs} system property. For instance if
+ *    it is set to {@code myapp.protocols}, then the URL code will try, in the
+ *    case of http, first to load {@code myapp.protocols.http.Handler}, then,
+ *    if this fails, {@code http.Handler} from the default location.
+ * <p>Note that the Handler class <b>has to</b> be a subclass of the abstract
+ *    class {@link java.net.URLStreamHandler}.</p>
+ * <h2>Additional Specification</h2>
+ * <ul>
+ *       <li><a href="doc-files/net-properties.html">
+ *            Networking System Properties</a></li>
+ * </ul>
+ *
+ * @since JDK1.0
+ */
+package java.net;
diff --git a/java/nio/Bits.java b/java/nio/Bits.java
new file mode 100644
index 0000000..56cb80b
--- /dev/null
+++ b/java/nio/Bits.java
@@ -0,0 +1,881 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import java.security.AccessController;
+
+import sun.misc.Unsafe;
+import sun.misc.VM;
+
+/**
+ * Access to bits, native and otherwise.
+ */
+
+class Bits {                            // package-private
+
+    private Bits() { }
+
+
+    // -- Swapping --
+
+    static short swap(short x) {
+        return Short.reverseBytes(x);
+    }
+
+    static char swap(char x) {
+        return Character.reverseBytes(x);
+    }
+
+    static int swap(int x) {
+        return Integer.reverseBytes(x);
+    }
+
+    static long swap(long x) {
+        return Long.reverseBytes(x);
+    }
+
+
+    // -- get/put char --
+
+    static private char makeChar(byte b1, byte b0) {
+        return (char)((b1 << 8) | (b0 & 0xff));
+    }
+
+    static char getCharL(ByteBuffer bb, int bi) {
+        return makeChar(bb._get(bi + 1),
+                        bb._get(bi    ));
+    }
+
+    static char getCharL(long a) {
+        return makeChar(_get(a + 1),
+                        _get(a    ));
+    }
+
+    static char getCharB(ByteBuffer bb, int bi) {
+        return makeChar(bb._get(bi    ),
+                        bb._get(bi + 1));
+    }
+
+    static char getCharB(long a) {
+        return makeChar(_get(a    ),
+                        _get(a + 1));
+    }
+
+    static char getChar(ByteBuffer bb, int bi, boolean bigEndian) {
+        return bigEndian ? getCharB(bb, bi) : getCharL(bb, bi);
+    }
+
+    static char getChar(long a, boolean bigEndian) {
+        return bigEndian ? getCharB(a) : getCharL(a);
+    }
+
+    private static byte char1(char x) { return (byte)(x >> 8); }
+    private static byte char0(char x) { return (byte)(x     ); }
+
+    static void putCharL(ByteBuffer bb, int bi, char x) {
+        bb._put(bi    , char0(x));
+        bb._put(bi + 1, char1(x));
+    }
+
+    static void putCharL(long a, char x) {
+        _put(a    , char0(x));
+        _put(a + 1, char1(x));
+    }
+
+    static void putCharB(ByteBuffer bb, int bi, char x) {
+        bb._put(bi    , char1(x));
+        bb._put(bi + 1, char0(x));
+    }
+
+    static void putCharB(long a, char x) {
+        _put(a    , char1(x));
+        _put(a + 1, char0(x));
+    }
+
+    static void putChar(ByteBuffer bb, int bi, char x, boolean bigEndian) {
+        if (bigEndian)
+            putCharB(bb, bi, x);
+        else
+            putCharL(bb, bi, x);
+    }
+
+    static void putChar(long a, char x, boolean bigEndian) {
+        if (bigEndian)
+            putCharB(a, x);
+        else
+            putCharL(a, x);
+    }
+
+
+    // -- get/put short --
+
+    static private short makeShort(byte b1, byte b0) {
+        return (short)((b1 << 8) | (b0 & 0xff));
+    }
+
+    static short getShortL(ByteBuffer bb, int bi) {
+        return makeShort(bb._get(bi + 1),
+                         bb._get(bi    ));
+    }
+
+    static short getShortL(long a) {
+        return makeShort(_get(a + 1),
+                         _get(a    ));
+    }
+
+    static short getShortB(ByteBuffer bb, int bi) {
+        return makeShort(bb._get(bi    ),
+                         bb._get(bi + 1));
+    }
+
+    static short getShortB(long a) {
+        return makeShort(_get(a    ),
+                         _get(a + 1));
+    }
+
+    static short getShort(ByteBuffer bb, int bi, boolean bigEndian) {
+        return bigEndian ? getShortB(bb, bi) : getShortL(bb, bi);
+    }
+
+    static short getShort(long a, boolean bigEndian) {
+        return bigEndian ? getShortB(a) : getShortL(a);
+    }
+
+    private static byte short1(short x) { return (byte)(x >> 8); }
+    private static byte short0(short x) { return (byte)(x     ); }
+
+    static void putShortL(ByteBuffer bb, int bi, short x) {
+        bb._put(bi    , short0(x));
+        bb._put(bi + 1, short1(x));
+    }
+
+    static void putShortL(long a, short x) {
+        _put(a    , short0(x));
+        _put(a + 1, short1(x));
+    }
+
+    static void putShortB(ByteBuffer bb, int bi, short x) {
+        bb._put(bi    , short1(x));
+        bb._put(bi + 1, short0(x));
+    }
+
+    static void putShortB(long a, short x) {
+        _put(a    , short1(x));
+        _put(a + 1, short0(x));
+    }
+
+    static void putShort(ByteBuffer bb, int bi, short x, boolean bigEndian) {
+        if (bigEndian)
+            putShortB(bb, bi, x);
+        else
+            putShortL(bb, bi, x);
+    }
+
+    static void putShort(long a, short x, boolean bigEndian) {
+        if (bigEndian)
+            putShortB(a, x);
+        else
+            putShortL(a, x);
+    }
+
+
+    // -- get/put int --
+
+    static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
+        return (((b3       ) << 24) |
+                ((b2 & 0xff) << 16) |
+                ((b1 & 0xff) <<  8) |
+                ((b0 & 0xff)      ));
+    }
+
+    static int getIntL(ByteBuffer bb, int bi) {
+        return makeInt(bb._get(bi + 3),
+                       bb._get(bi + 2),
+                       bb._get(bi + 1),
+                       bb._get(bi    ));
+    }
+
+    static int getIntL(long a) {
+        return makeInt(_get(a + 3),
+                       _get(a + 2),
+                       _get(a + 1),
+                       _get(a    ));
+    }
+
+    static int getIntB(ByteBuffer bb, int bi) {
+        return makeInt(bb._get(bi    ),
+                       bb._get(bi + 1),
+                       bb._get(bi + 2),
+                       bb._get(bi + 3));
+    }
+
+    static int getIntB(long a) {
+        return makeInt(_get(a    ),
+                       _get(a + 1),
+                       _get(a + 2),
+                       _get(a + 3));
+    }
+
+    static int getInt(ByteBuffer bb, int bi, boolean bigEndian) {
+        return bigEndian ? getIntB(bb, bi) : getIntL(bb, bi) ;
+    }
+
+    static int getInt(long a, boolean bigEndian) {
+        return bigEndian ? getIntB(a) : getIntL(a) ;
+    }
+
+    private static byte int3(int x) { return (byte)(x >> 24); }
+    private static byte int2(int x) { return (byte)(x >> 16); }
+    private static byte int1(int x) { return (byte)(x >>  8); }
+    private static byte int0(int x) { return (byte)(x      ); }
+
+    static void putIntL(ByteBuffer bb, int bi, int x) {
+        bb._put(bi + 3, int3(x));
+        bb._put(bi + 2, int2(x));
+        bb._put(bi + 1, int1(x));
+        bb._put(bi    , int0(x));
+    }
+
+    static void putIntL(long a, int x) {
+        _put(a + 3, int3(x));
+        _put(a + 2, int2(x));
+        _put(a + 1, int1(x));
+        _put(a    , int0(x));
+    }
+
+    static void putIntB(ByteBuffer bb, int bi, int x) {
+        bb._put(bi    , int3(x));
+        bb._put(bi + 1, int2(x));
+        bb._put(bi + 2, int1(x));
+        bb._put(bi + 3, int0(x));
+    }
+
+    static void putIntB(long a, int x) {
+        _put(a    , int3(x));
+        _put(a + 1, int2(x));
+        _put(a + 2, int1(x));
+        _put(a + 3, int0(x));
+    }
+
+    static void putInt(ByteBuffer bb, int bi, int x, boolean bigEndian) {
+        if (bigEndian)
+            putIntB(bb, bi, x);
+        else
+            putIntL(bb, bi, x);
+    }
+
+    static void putInt(long a, int x, boolean bigEndian) {
+        if (bigEndian)
+            putIntB(a, x);
+        else
+            putIntL(a, x);
+    }
+
+
+    // -- get/put long --
+
+    static private long makeLong(byte b7, byte b6, byte b5, byte b4,
+                                 byte b3, byte b2, byte b1, byte b0)
+    {
+        return ((((long)b7       ) << 56) |
+                (((long)b6 & 0xff) << 48) |
+                (((long)b5 & 0xff) << 40) |
+                (((long)b4 & 0xff) << 32) |
+                (((long)b3 & 0xff) << 24) |
+                (((long)b2 & 0xff) << 16) |
+                (((long)b1 & 0xff) <<  8) |
+                (((long)b0 & 0xff)      ));
+    }
+
+    static long getLongL(ByteBuffer bb, int bi) {
+        return makeLong(bb._get(bi + 7),
+                        bb._get(bi + 6),
+                        bb._get(bi + 5),
+                        bb._get(bi + 4),
+                        bb._get(bi + 3),
+                        bb._get(bi + 2),
+                        bb._get(bi + 1),
+                        bb._get(bi    ));
+    }
+
+    static long getLongL(long a) {
+        return makeLong(_get(a + 7),
+                        _get(a + 6),
+                        _get(a + 5),
+                        _get(a + 4),
+                        _get(a + 3),
+                        _get(a + 2),
+                        _get(a + 1),
+                        _get(a    ));
+    }
+
+    static long getLongB(ByteBuffer bb, int bi) {
+        return makeLong(bb._get(bi    ),
+                        bb._get(bi + 1),
+                        bb._get(bi + 2),
+                        bb._get(bi + 3),
+                        bb._get(bi + 4),
+                        bb._get(bi + 5),
+                        bb._get(bi + 6),
+                        bb._get(bi + 7));
+    }
+
+    static long getLongB(long a) {
+        return makeLong(_get(a    ),
+                        _get(a + 1),
+                        _get(a + 2),
+                        _get(a + 3),
+                        _get(a + 4),
+                        _get(a + 5),
+                        _get(a + 6),
+                        _get(a + 7));
+    }
+
+    static long getLong(ByteBuffer bb, int bi, boolean bigEndian) {
+        return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi);
+    }
+
+    static long getLong(long a, boolean bigEndian) {
+        return bigEndian ? getLongB(a) : getLongL(a);
+    }
+
+    private static byte long7(long x) { return (byte)(x >> 56); }
+    private static byte long6(long x) { return (byte)(x >> 48); }
+    private static byte long5(long x) { return (byte)(x >> 40); }
+    private static byte long4(long x) { return (byte)(x >> 32); }
+    private static byte long3(long x) { return (byte)(x >> 24); }
+    private static byte long2(long x) { return (byte)(x >> 16); }
+    private static byte long1(long x) { return (byte)(x >>  8); }
+    private static byte long0(long x) { return (byte)(x      ); }
+
+    static void putLongL(ByteBuffer bb, int bi, long x) {
+        bb._put(bi + 7, long7(x));
+        bb._put(bi + 6, long6(x));
+        bb._put(bi + 5, long5(x));
+        bb._put(bi + 4, long4(x));
+        bb._put(bi + 3, long3(x));
+        bb._put(bi + 2, long2(x));
+        bb._put(bi + 1, long1(x));
+        bb._put(bi    , long0(x));
+    }
+
+    static void putLongL(long a, long x) {
+        _put(a + 7, long7(x));
+        _put(a + 6, long6(x));
+        _put(a + 5, long5(x));
+        _put(a + 4, long4(x));
+        _put(a + 3, long3(x));
+        _put(a + 2, long2(x));
+        _put(a + 1, long1(x));
+        _put(a    , long0(x));
+    }
+
+    static void putLongB(ByteBuffer bb, int bi, long x) {
+        bb._put(bi    , long7(x));
+        bb._put(bi + 1, long6(x));
+        bb._put(bi + 2, long5(x));
+        bb._put(bi + 3, long4(x));
+        bb._put(bi + 4, long3(x));
+        bb._put(bi + 5, long2(x));
+        bb._put(bi + 6, long1(x));
+        bb._put(bi + 7, long0(x));
+    }
+
+    static void putLongB(long a, long x) {
+        _put(a    , long7(x));
+        _put(a + 1, long6(x));
+        _put(a + 2, long5(x));
+        _put(a + 3, long4(x));
+        _put(a + 4, long3(x));
+        _put(a + 5, long2(x));
+        _put(a + 6, long1(x));
+        _put(a + 7, long0(x));
+    }
+
+    static void putLong(ByteBuffer bb, int bi, long x, boolean bigEndian) {
+        if (bigEndian)
+            putLongB(bb, bi, x);
+        else
+            putLongL(bb, bi, x);
+    }
+
+    static void putLong(long a, long x, boolean bigEndian) {
+        if (bigEndian)
+            putLongB(a, x);
+        else
+            putLongL(a, x);
+    }
+
+
+    // -- get/put float --
+
+    static float getFloatL(ByteBuffer bb, int bi) {
+        return Float.intBitsToFloat(getIntL(bb, bi));
+    }
+
+    static float getFloatL(long a) {
+        return Float.intBitsToFloat(getIntL(a));
+    }
+
+    static float getFloatB(ByteBuffer bb, int bi) {
+        return Float.intBitsToFloat(getIntB(bb, bi));
+    }
+
+    static float getFloatB(long a) {
+        return Float.intBitsToFloat(getIntB(a));
+    }
+
+    static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) {
+        return bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi);
+    }
+
+    static float getFloat(long a, boolean bigEndian) {
+        return bigEndian ? getFloatB(a) : getFloatL(a);
+    }
+
+    static void putFloatL(ByteBuffer bb, int bi, float x) {
+        putIntL(bb, bi, Float.floatToRawIntBits(x));
+    }
+
+    static void putFloatL(long a, float x) {
+        putIntL(a, Float.floatToRawIntBits(x));
+    }
+
+    static void putFloatB(ByteBuffer bb, int bi, float x) {
+        putIntB(bb, bi, Float.floatToRawIntBits(x));
+    }
+
+    static void putFloatB(long a, float x) {
+        putIntB(a, Float.floatToRawIntBits(x));
+    }
+
+    static void putFloat(ByteBuffer bb, int bi, float x, boolean bigEndian) {
+        if (bigEndian)
+            putFloatB(bb, bi, x);
+        else
+            putFloatL(bb, bi, x);
+    }
+
+    static void putFloat(long a, float x, boolean bigEndian) {
+        if (bigEndian)
+            putFloatB(a, x);
+        else
+            putFloatL(a, x);
+    }
+
+
+    // -- get/put double --
+
+    static double getDoubleL(ByteBuffer bb, int bi) {
+        return Double.longBitsToDouble(getLongL(bb, bi));
+    }
+
+    static double getDoubleL(long a) {
+        return Double.longBitsToDouble(getLongL(a));
+    }
+
+    static double getDoubleB(ByteBuffer bb, int bi) {
+        return Double.longBitsToDouble(getLongB(bb, bi));
+    }
+
+    static double getDoubleB(long a) {
+        return Double.longBitsToDouble(getLongB(a));
+    }
+
+    static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) {
+        return bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi);
+    }
+
+    static double getDouble(long a, boolean bigEndian) {
+        return bigEndian ? getDoubleB(a) : getDoubleL(a);
+    }
+
+    static void putDoubleL(ByteBuffer bb, int bi, double x) {
+        putLongL(bb, bi, Double.doubleToRawLongBits(x));
+    }
+
+    static void putDoubleL(long a, double x) {
+        putLongL(a, Double.doubleToRawLongBits(x));
+    }
+
+    static void putDoubleB(ByteBuffer bb, int bi, double x) {
+        putLongB(bb, bi, Double.doubleToRawLongBits(x));
+    }
+
+    static void putDoubleB(long a, double x) {
+        putLongB(a, Double.doubleToRawLongBits(x));
+    }
+
+    static void putDouble(ByteBuffer bb, int bi, double x, boolean bigEndian) {
+        if (bigEndian)
+            putDoubleB(bb, bi, x);
+        else
+            putDoubleL(bb, bi, x);
+    }
+
+    static void putDouble(long a, double x, boolean bigEndian) {
+        if (bigEndian)
+            putDoubleB(a, x);
+        else
+            putDoubleL(a, x);
+    }
+
+
+    // -- Unsafe access --
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private static byte _get(long a) {
+        return unsafe.getByte(a);
+    }
+
+    private static void _put(long a, byte b) {
+        unsafe.putByte(a, b);
+    }
+
+    static Unsafe unsafe() {
+        return unsafe;
+    }
+
+
+    // -- Processor and memory-system properties --
+
+    private static final ByteOrder byteOrder;
+
+    static ByteOrder byteOrder() {
+        // Android-removed: Android is always little-endian.
+        /*
+        if (byteOrder == null)
+            throw new Error("Unknown byte order");
+        */
+        return byteOrder;
+    }
+
+    static {
+        // BEGIN Android-changed: Android is always little-endian.
+        /*
+        long a = unsafe.allocateMemory(8);
+        try {
+            unsafe.putLong(a, 0x0102030405060708L);
+            byte b = unsafe.getByte(a);
+            switch (b) {
+            case 0x01: byteOrder = ByteOrder.BIG_ENDIAN;     break;
+            case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN;  break;
+            default:
+                assert false;
+                byteOrder = null;
+            }
+        } finally {
+            unsafe.freeMemory(a);
+        }
+        */
+        byteOrder = ByteOrder.LITTLE_ENDIAN;
+        // END Android-changed: Android is always little-endian.
+    }
+
+
+    private static int pageSize = -1;
+
+    static int pageSize() {
+        if (pageSize == -1)
+            pageSize = unsafe().pageSize();
+        return pageSize;
+    }
+
+    static int pageCount(long size) {
+        return (int)(size + (long)pageSize() - 1L) / pageSize();
+    }
+
+    private static boolean unaligned;
+    private static boolean unalignedKnown = false;
+
+    static boolean unaligned() {
+        if (unalignedKnown)
+            return unaligned;
+        String arch = AccessController.doPrivileged(
+            new sun.security.action.GetPropertyAction("os.arch"));
+        unaligned = arch.equals("i386") || arch.equals("x86")
+            || arch.equals("amd64") || arch.equals("x86_64");
+        unalignedKnown = true;
+        return unaligned;
+    }
+
+
+    // -- Direct memory management --
+
+    // BEGIN Android-removed: Direct memory management unused on Android.
+    /*
+    // A user-settable upper limit on the maximum amount of allocatable
+    // direct buffer memory.  This value may be changed during VM
+    // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
+    private static volatile long maxMemory = VM.maxDirectMemory();
+    private static final AtomicLong reservedMemory = new AtomicLong();
+    private static final AtomicLong totalCapacity = new AtomicLong();
+    private static final AtomicLong count = new AtomicLong();
+    private static volatile boolean memoryLimitSet = false;
+    // max. number of sleeps during try-reserving with exponentially
+    // increasing delay before throwing OutOfMemoryError:
+    // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
+    // which means that OOME will be thrown after 0.5 s of trying
+    private static final int MAX_SLEEPS = 9;
+
+    // These methods should be called whenever direct memory is allocated or
+    // freed.  They allow the user to control the amount of direct memory
+    // which a process may access.  All sizes are specified in bytes.
+    static void reserveMemory(long size, int cap) {
+
+        if (!memoryLimitSet && VM.isBooted()) {
+            maxMemory = VM.maxDirectMemory();
+            memoryLimitSet = true;
+        }
+
+        // optimist!
+        if (tryReserveMemory(size, cap)) {
+            return;
+        }
+
+        final JavaLangRefAccess jlra = SharedSecrets.getJavaLangRefAccess();
+
+        // retry while helping enqueue pending Reference objects
+        // which includes executing pending Cleaner(s) which includes
+        // Cleaner(s) that free direct buffer memory
+        while (jlra.tryHandlePendingReference()) {
+            if (tryReserveMemory(size, cap)) {
+                return;
+            }
+        }
+
+        // trigger VM's Reference processing
+        System.gc();
+
+        // a retry loop with exponential back-off delays
+        // (this gives VM some time to do it's job)
+        boolean interrupted = false;
+        try {
+            long sleepTime = 1;
+            int sleeps = 0;
+            while (true) {
+                if (tryReserveMemory(size, cap)) {
+                    return;
+                }
+                if (sleeps >= MAX_SLEEPS) {
+                    break;
+                }
+                if (!jlra.tryHandlePendingReference()) {
+                    try {
+                        Thread.sleep(sleepTime);
+                        sleepTime <<= 1;
+                        sleeps++;
+                    } catch (InterruptedException e) {
+                        interrupted = true;
+                    }
+                }
+            }
+
+            // no luck
+            throw new OutOfMemoryError("Direct buffer memory");
+
+        } finally {
+            if (interrupted) {
+                // don't swallow interrupts
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    private static boolean tryReserveMemory(long size, int cap) {
+
+        // -XX:MaxDirectMemorySize limits the total capacity rather than the
+        // actual memory usage, which will differ when buffers are page
+        // aligned.
+        long totalCap;
+        while (cap <= maxMemory - (totalCap = totalCapacity.get())) {
+            if (totalCapacity.compareAndSet(totalCap, totalCap + cap)) {
+                reservedMemory.addAndGet(size);
+                count.incrementAndGet();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    static void unreserveMemory(long size, int cap) {
+        long cnt = count.decrementAndGet();
+        long reservedMem = reservedMemory.addAndGet(-size);
+        long totalCap = totalCapacity.addAndGet(-cap);
+        assert cnt >= 0 && reservedMem >= 0 && totalCap >= 0;
+    }
+    */
+    // END Android-removed: Direct memory management unused on Android.
+
+    // -- Monitoring of direct buffer usage --
+
+    // BEGIN Android-removed: Remove support for java.lang.management.
+    /*
+    static {
+        // setup access to this package in SharedSecrets
+        sun.misc.SharedSecrets.setJavaNioAccess(
+            new sun.misc.JavaNioAccess() {
+                @Override
+                public sun.misc.JavaNioAccess.BufferPool getDirectBufferPool() {
+                    return new sun.misc.JavaNioAccess.BufferPool() {
+                        @Override
+                        public String getName() {
+                            return "direct";
+                        }
+                        @Override
+                        public long getCount() {
+                            return Bits.count.get();
+                        }
+                        @Override
+                        public long getTotalCapacity() {
+                            return Bits.totalCapacity.get();
+                        }
+                        @Override
+                        public long getMemoryUsed() {
+                            return Bits.reservedMemory.get();
+                        }
+                    };
+                }
+                @Override
+                public ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) {
+                    return new DirectByteBuffer(addr, cap, ob);
+                }
+                @Override
+                public void truncate(Buffer buf) {
+                    buf.truncate();
+                }
+        });
+    }
+    */
+    // END Android-removed: Remove support for java.lang.management.
+
+    // BEGIN Android-removed: Bulk get/put methods are unused on Android.
+    /*
+
+    // -- Bulk get/put acceleration --
+
+    // These numbers represent the point at which we have empirically
+    // determined that the average cost of a JNI call exceeds the expense
+    // of an element by element copy.  These numbers may change over time.
+    static final int JNI_COPY_TO_ARRAY_THRESHOLD   = 6;
+    static final int JNI_COPY_FROM_ARRAY_THRESHOLD = 6;
+
+    // This number limits the number of bytes to copy per call to Unsafe's
+    // copyMemory method. A limit is imposed to allow for safepoint polling
+    // during a large copy
+    static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
+
+    // These methods do no bounds checking.  Verification that the copy will not
+    // result in memory corruption should be done prior to invocation.
+    // All positions and lengths are specified in bytes.
+
+    /**
+     * Copy from given source array to destination address.
+     *
+     * @param   src
+     *          source array
+     * @param   srcBaseOffset
+     *          offset of first element of storage in source array
+     * @param   srcPos
+     *          offset within source array of the first element to read
+     * @param   dstAddr
+     *          destination address
+     * @param   length
+     *          number of bytes to copy
+     *
+    static void copyFromArray(Object src, long srcBaseOffset, long srcPos,
+                              long dstAddr, long length)
+    {
+        long offset = srcBaseOffset + srcPos;
+        while (length > 0) {
+            long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length;
+            unsafe.copyMemory(src, offset, null, dstAddr, size);
+            length -= size;
+            offset += size;
+            dstAddr += size;
+        }
+    }
+
+    /**
+     * Copy from source address into given destination array.
+     *
+     * @param   srcAddr
+     *          source address
+     * @param   dst
+     *          destination array
+     * @param   dstBaseOffset
+     *          offset of first element of storage in destination array
+     * @param   dstPos
+     *          offset within destination array of the first element to write
+     * @param   length
+     *          number of bytes to copy
+     *
+    static void copyToArray(long srcAddr, Object dst, long dstBaseOffset, long dstPos,
+                            long length)
+    {
+        long offset = dstBaseOffset + dstPos;
+        while (length > 0) {
+            long size = (length > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : length;
+            unsafe.copyMemory(null, srcAddr, dst, offset, size);
+            length -= size;
+            srcAddr += size;
+            offset += size;
+        }
+    }
+
+    static void copyFromCharArray(Object src, long srcPos, long dstAddr,
+                                  long length)
+    {
+        copyFromShortArray(src, srcPos, dstAddr, length);
+    }
+
+    static void copyToCharArray(long srcAddr, Object dst, long dstPos,
+                                long length)
+    {
+        copyToShortArray(srcAddr, dst, dstPos, length);
+    }
+
+    static native void copyFromShortArray(Object src, long srcPos, long dstAddr,
+                                          long length);
+    static native void copyToShortArray(long srcAddr, Object dst, long dstPos,
+                                        long length);
+
+    static native void copyFromIntArray(Object src, long srcPos, long dstAddr,
+                                        long length);
+    static native void copyToIntArray(long srcAddr, Object dst, long dstPos,
+                                      long length);
+
+    static native void copyFromLongArray(Object src, long srcPos, long dstAddr,
+                                         long length);
+    static native void copyToLongArray(long srcAddr, Object dst, long dstPos,
+                                       long length);
+    */
+    // END Android-removed: Bulk get/put methods are unused on Android.
+}
diff --git a/java/nio/Buffer.java b/java/nio/Buffer.java
new file mode 100644
index 0000000..e517560
--- /dev/null
+++ b/java/nio/Buffer.java
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import java.util.Spliterator;
+
+/**
+ * A container for data of a specific primitive type.
+ *
+ * <p> A buffer is a linear, finite sequence of elements of a specific
+ * primitive type.  Aside from its content, the essential properties of a
+ * buffer are its capacity, limit, and position: </p>
+ *
+ * <blockquote>
+ *
+ *   <p> A buffer's <i>capacity</i> is the number of elements it contains.  The
+ *   capacity of a buffer is never negative and never changes.  </p>
+ *
+ *   <p> A buffer's <i>limit</i> is the index of the first element that should
+ *   not be read or written.  A buffer's limit is never negative and is never
+ *   greater than its capacity.  </p>
+ *
+ *   <p> A buffer's <i>position</i> is the index of the next element to be
+ *   read or written.  A buffer's position is never negative and is never
+ *   greater than its limit.  </p>
+ *
+ * </blockquote>
+ *
+ * <p> There is one subclass of this class for each non-boolean primitive type.
+ *
+ *
+ * <h2> Transferring data </h2>
+ *
+ * <p> Each subclass of this class defines two categories of <i>get</i> and
+ * <i>put</i> operations: </p>
+ *
+ * <blockquote>
+ *
+ *   <p> <i>Relative</i> operations read or write one or more elements starting
+ *   at the current position and then increment the position by the number of
+ *   elements transferred.  If the requested transfer exceeds the limit then a
+ *   relative <i>get</i> operation throws a {@link BufferUnderflowException}
+ *   and a relative <i>put</i> operation throws a {@link
+ *   BufferOverflowException}; in either case, no data is transferred.  </p>
+ *
+ *   <p> <i>Absolute</i> operations take an explicit element index and do not
+ *   affect the position.  Absolute <i>get</i> and <i>put</i> operations throw
+ *   an {@link IndexOutOfBoundsException} if the index argument exceeds the
+ *   limit.  </p>
+ *
+ * </blockquote>
+ *
+ * <p> Data may also, of course, be transferred in to or out of a buffer by the
+ * I/O operations of an appropriate channel, which are always relative to the
+ * current position.
+ *
+ *
+ * <h2> Marking and resetting </h2>
+ *
+ * <p> A buffer's <i>mark</i> is the index to which its position will be reset
+ * when the {@link #reset reset} method is invoked.  The mark is not always
+ * defined, but when it is defined it is never negative and is never greater
+ * than the position.  If the mark is defined then it is discarded when the
+ * position or the limit is adjusted to a value smaller than the mark.  If the
+ * mark is not defined then invoking the {@link #reset reset} method causes an
+ * {@link InvalidMarkException} to be thrown.
+ *
+ *
+ * <h2> Invariants </h2>
+ *
+ * <p> The following invariant holds for the mark, position, limit, and
+ * capacity values:
+ *
+ * <blockquote>
+ *     <tt>0</tt> <tt>&lt;=</tt>
+ *     <i>mark</i> <tt>&lt;=</tt>
+ *     <i>position</i> <tt>&lt;=</tt>
+ *     <i>limit</i> <tt>&lt;=</tt>
+ *     <i>capacity</i>
+ * </blockquote>
+ *
+ * <p> A newly-created buffer always has a position of zero and a mark that is
+ * undefined.  The initial limit may be zero, or it may be some other value
+ * that depends upon the type of the buffer and the manner in which it is
+ * constructed.  Each element of a newly-allocated buffer is initialized
+ * to zero.
+ *
+ *
+ * <h2> Clearing, flipping, and rewinding </h2>
+ *
+ * <p> In addition to methods for accessing the position, limit, and capacity
+ * values and for marking and resetting, this class also defines the following
+ * operations upon buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> {@link #clear} makes a buffer ready for a new sequence of
+ *   channel-read or relative <i>put</i> operations: It sets the limit to the
+ *   capacity and the position to zero.  </p></li>
+ *
+ *   <li><p> {@link #flip} makes a buffer ready for a new sequence of
+ *   channel-write or relative <i>get</i> operations: It sets the limit to the
+ *   current position and then sets the position to zero.  </p></li>
+ *
+ *   <li><p> {@link #rewind} makes a buffer ready for re-reading the data that
+ *   it already contains: It leaves the limit unchanged and sets the position
+ *   to zero.  </p></li>
+ *
+ * </ul>
+ *
+ *
+ * <h2> Read-only buffers </h2>
+ *
+ * <p> Every buffer is readable, but not every buffer is writable.  The
+ * mutation methods of each buffer class are specified as <i>optional
+ * operations</i> that will throw a {@link ReadOnlyBufferException} when
+ * invoked upon a read-only buffer.  A read-only buffer does not allow its
+ * content to be changed, but its mark, position, and limit values are mutable.
+ * Whether or not a buffer is read-only may be determined by invoking its
+ * {@link #isReadOnly isReadOnly} method.
+ *
+ *
+ * <h2> Thread safety </h2>
+ *
+ * <p> Buffers are not safe for use by multiple concurrent threads.  If a
+ * buffer is to be used by more than one thread then access to the buffer
+ * should be controlled by appropriate synchronization.
+ *
+ *
+ * <h2> Invocation chaining </h2>
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained; for example, the sequence of statements
+ *
+ * <blockquote><pre>
+ * b.flip();
+ * b.position(23);
+ * b.limit(42);</pre></blockquote>
+ *
+ * can be replaced by the single, more compact statement
+ *
+ * <blockquote><pre>
+ * b.flip().position(23).limit(42);</pre></blockquote>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class Buffer {
+
+    /**
+     * The characteristics of Spliterators that traverse and split elements
+     * maintained in Buffers.
+     */
+    static final int SPLITERATOR_CHARACTERISTICS =
+        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
+
+    // Invariants: mark <= position <= limit <= capacity
+    private int mark = -1;
+    // Android-changed: position field non-private for use by Android's nio implementation classes.
+    int position = 0;
+    private int limit;
+    private int capacity;
+
+    // Used only by direct buffers
+    // NOTE: hoisted here for speed in JNI GetDirectBufferAddress
+    long address;
+
+    // Android-added: _elementSizeShift field for NIOAccess class and framework native code.
+    /**
+     * The log base 2 of the element size of this buffer.  Each typed subclass
+     * (ByteBuffer, CharBuffer, etc.) is responsible for initializing this
+     * value.  The value is used by JNI code in frameworks/base/ to avoid the
+     * need for costly 'instanceof' tests.
+     */
+    final int _elementSizeShift;
+
+    // Creates a new buffer with the given mark, position, limit, and capacity,
+    // after checking invariants.
+    //
+    // Android-added: _elementSizeShift field for NIOAccess class and framework native code.
+    Buffer(int mark, int pos, int lim, int cap, int elementSizeShift) {       // package-private
+        if (cap < 0)
+            throw new IllegalArgumentException("Negative capacity: " + cap);
+        this.capacity = cap;
+        limit(lim);
+        position(pos);
+        if (mark >= 0) {
+            if (mark > pos)
+                throw new IllegalArgumentException("mark > position: ("
+                                                   + mark + " > " + pos + ")");
+            this.mark = mark;
+        }
+        // Android-added: _elementSizeShift field for NIOAccess class and framework native code.
+        _elementSizeShift = elementSizeShift;
+    }
+
+    /**
+     * Returns this buffer's capacity.
+     *
+     * @return  The capacity of this buffer
+     */
+    public final int capacity() {
+        return capacity;
+    }
+
+    /**
+     * Returns this buffer's position.
+     *
+     * @return  The position of this buffer
+     */
+    public final int position() {
+        return position;
+    }
+
+    /**
+     * Sets this buffer's position.  If the mark is defined and larger than the
+     * new position then it is discarded.
+     *
+     * @param  newPosition
+     *         The new position value; must be non-negative
+     *         and no larger than the current limit
+     *
+     * @return  This buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on <tt>newPosition</tt> do not hold
+     */
+    public Buffer position(int newPosition) {
+        if ((newPosition > limit) || (newPosition < 0))
+            // Android-changed: Improved error message.
+            throw new IllegalArgumentException("Bad position " + newPosition + "/" + limit);
+        position = newPosition;
+        if (mark > position) mark = -1;
+        return this;
+    }
+
+    /**
+     * Returns this buffer's limit.
+     *
+     * @return  The limit of this buffer
+     */
+    public final int limit() {
+        return limit;
+    }
+
+    /**
+     * Sets this buffer's limit.  If the position is larger than the new limit
+     * then it is set to the new limit.  If the mark is defined and larger than
+     * the new limit then it is discarded.
+     *
+     * @param  newLimit
+     *         The new limit value; must be non-negative
+     *         and no larger than this buffer's capacity
+     *
+     * @return  This buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on <tt>newLimit</tt> do not hold
+     */
+    public Buffer limit(int newLimit) {
+        if ((newLimit > capacity) || (newLimit < 0))
+            throw new IllegalArgumentException();
+        limit = newLimit;
+        if (position > limit) position = limit;
+        if (mark > limit) mark = -1;
+        return this;
+    }
+
+    /**
+     * Sets this buffer's mark at its position.
+     *
+     * @return  This buffer
+     */
+    public Buffer mark() {
+        mark = position;
+        return this;
+    }
+
+    /**
+     * Resets this buffer's position to the previously-marked position.
+     *
+     * <p> Invoking this method neither changes nor discards the mark's
+     * value. </p>
+     *
+     * @return  This buffer
+     *
+     * @throws  InvalidMarkException
+     *          If the mark has not been set
+     */
+    public Buffer reset() {
+        int m = mark;
+        if (m < 0)
+            throw new InvalidMarkException();
+        position = m;
+        return this;
+    }
+
+    /**
+     * Clears this buffer.  The position is set to zero, the limit is set to
+     * the capacity, and the mark is discarded.
+     *
+     * <p> Invoke this method before using a sequence of channel-read or
+     * <i>put</i> operations to fill this buffer.  For example:
+     *
+     * <blockquote><pre>
+     * buf.clear();     // Prepare buffer for reading
+     * in.read(buf);    // Read data</pre></blockquote>
+     *
+     * <p> This method does not actually erase the data in the buffer, but it
+     * is named as if it did because it will most often be used in situations
+     * in which that might as well be the case. </p>
+     *
+     * @return  This buffer
+     */
+    public Buffer clear() {
+        position = 0;
+        limit = capacity;
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * Flips this buffer.  The limit is set to the current position and then
+     * the position is set to zero.  If the mark is defined then it is
+     * discarded.
+     *
+     * <p> After a sequence of channel-read or <i>put</i> operations, invoke
+     * this method to prepare for a sequence of channel-write or relative
+     * <i>get</i> operations.  For example:
+     *
+     * <blockquote><pre>
+     * buf.put(magic);    // Prepend header
+     * in.read(buf);      // Read data into rest of buffer
+     * buf.flip();        // Flip buffer
+     * out.write(buf);    // Write header + data to channel</pre></blockquote>
+     *
+     * <p> This method is often used in conjunction with the {@link
+     * java.nio.ByteBuffer#compact compact} method when transferring data from
+     * one place to another.  </p>
+     *
+     * @return  This buffer
+     */
+    public Buffer flip() {
+        limit = position;
+        position = 0;
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * Rewinds this buffer.  The position is set to zero and the mark is
+     * discarded.
+     *
+     * <p> Invoke this method before a sequence of channel-write or <i>get</i>
+     * operations, assuming that the limit has already been set
+     * appropriately.  For example:
+     *
+     * <blockquote><pre>
+     * out.write(buf);    // Write remaining data
+     * buf.rewind();      // Rewind buffer
+     * buf.get(array);    // Copy data into array</pre></blockquote>
+     *
+     * @return  This buffer
+     */
+    public Buffer rewind() {
+        position = 0;
+        mark = -1;
+        return this;
+    }
+
+    /**
+     * Returns the number of elements between the current position and the
+     * limit.
+     *
+     * @return  The number of elements remaining in this buffer
+     */
+    public final int remaining() {
+        return limit - position;
+    }
+
+    /**
+     * Tells whether there are any elements between the current position and
+     * the limit.
+     *
+     * @return  <tt>true</tt> if, and only if, there is at least one element
+     *          remaining in this buffer
+     */
+    public final boolean hasRemaining() {
+        return position < limit;
+    }
+
+    /**
+     * Tells whether or not this buffer is read-only.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is read-only
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     *
+     * @since 1.6
+     */
+    public abstract boolean hasArray();
+
+    /**
+     * Returns the array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method is intended to allow array-backed buffers to be
+     * passed to native code more efficiently. Concrete subclasses
+     * provide more strongly-typed return values for this method.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     *
+     * @since 1.6
+     */
+    public abstract Object array();
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     *
+     * @since 1.6
+     */
+    public abstract int arrayOffset();
+
+    /**
+     * Tells whether or not this buffer is
+     * <a href="ByteBuffer.html#direct"><i>direct</i></a>.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     *
+     * @since 1.6
+     */
+    public abstract boolean isDirect();
+
+
+    // -- Package-private methods for bounds checking, etc. --
+
+    /**
+     * Checks the current position against the limit, throwing a {@link
+     * BufferUnderflowException} if it is not smaller than the limit, and then
+     * increments the position.
+     *
+     * @return  The current position value, before it is incremented
+     */
+    final int nextGetIndex() {                          // package-private
+        if (position >= limit)
+            throw new BufferUnderflowException();
+        return position++;
+    }
+
+    final int nextGetIndex(int nb) {                    // package-private
+        if (limit - position < nb)
+            throw new BufferUnderflowException();
+        int p = position;
+        position += nb;
+        return p;
+    }
+
+    /**
+     * Checks the current position against the limit, throwing a {@link
+     * BufferOverflowException} if it is not smaller than the limit, and then
+     * increments the position.
+     *
+     * @return  The current position value, before it is incremented
+     */
+    final int nextPutIndex() {                          // package-private
+        if (position >= limit)
+            throw new BufferOverflowException();
+        return position++;
+    }
+
+    final int nextPutIndex(int nb) {                    // package-private
+        if (limit - position < nb)
+            throw new BufferOverflowException();
+        int p = position;
+        position += nb;
+        return p;
+    }
+
+    /**
+     * Checks the given index against the limit, throwing an {@link
+     * IndexOutOfBoundsException} if it is not smaller than the limit
+     * or is smaller than zero.
+     */
+    final int checkIndex(int i) {                       // package-private
+        if ((i < 0) || (i >= limit))
+            // Android-changed: Add bounds details to exception.
+            throw new IndexOutOfBoundsException(
+                    "index=" + i + " out of bounds (limit=" + limit + ")");
+        return i;
+    }
+
+    final int checkIndex(int i, int nb) {               // package-private
+        if ((i < 0) || (nb > limit - i))
+            // Android-changed: Add bounds details to exception.
+            throw new IndexOutOfBoundsException(
+                    "index=" + i + " out of bounds (limit=" + limit + ", nb=" + nb + ")");
+        return i;
+    }
+
+    final int markValue() {                             // package-private
+        return mark;
+    }
+
+    final void truncate() {                             // package-private
+        mark = -1;
+        position = 0;
+        limit = 0;
+        capacity = 0;
+    }
+
+    final void discardMark() {                          // package-private
+        mark = -1;
+    }
+
+    static void checkBounds(int off, int len, int size) { // package-private
+        if ((off | len | (off + len) | (size - (off + len))) < 0)
+            // Android-changed: Add bounds details to exception.
+            throw new IndexOutOfBoundsException(
+                    "off=" + off + ", len=" + len + " out of bounds (size=" + size + ")");
+    }
+
+    // Android-added: getElementSizeShift() method for testing.
+    /**
+     * For testing only. This field is accessed directly via JNI from frameworks code.
+     *
+     * @hide
+     */
+    public int getElementSizeShift() {
+        return _elementSizeShift;
+    }
+
+}
diff --git a/java/nio/BufferOverflowException.java b/java/nio/BufferOverflowException.java
new file mode 100644
index 0000000..d141a82
--- /dev/null
+++ b/java/nio/BufferOverflowException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+/**
+ * Unchecked exception thrown when a relative <i>put</i> operation reaches
+ * the target buffer's limit.
+ *
+ * @since 1.4
+ */
+
+public class BufferOverflowException
+    extends RuntimeException
+{
+
+    private static final long serialVersionUID = -5484897634319144535L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public BufferOverflowException() { }
+
+}
diff --git a/java/nio/BufferUnderflowException.java b/java/nio/BufferUnderflowException.java
new file mode 100644
index 0000000..d7a062a
--- /dev/null
+++ b/java/nio/BufferUnderflowException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+/**
+ * Unchecked exception thrown when a relative <i>get</i> operation reaches
+ * the source buffer's limit.
+ *
+ * @since 1.4
+ */
+
+public class BufferUnderflowException
+    extends RuntimeException
+{
+
+    private static final long serialVersionUID = -1713313658691622206L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public BufferUnderflowException() { }
+
+}
diff --git a/java/nio/ByteBuffer.annotated.java b/java/nio/ByteBuffer.annotated.java
new file mode 100644
index 0000000..d0caba2
--- /dev/null
+++ b/java/nio/ByteBuffer.annotated.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class ByteBuffer extends java.nio.Buffer implements java.lang.Comparable<java.nio.ByteBuffer> {
+
+ByteBuffer(int mark, int pos, int lim, int cap) { super(0, 0, 0, 0, 0); throw new RuntimeException("Stub!"); }
+
+public static java.nio.ByteBuffer allocateDirect(int capacity) { throw new RuntimeException("Stub!"); }
+
+public static java.nio.ByteBuffer allocate(int capacity) { throw new RuntimeException("Stub!"); }
+
+public static java.nio.ByteBuffer wrap(byte[] array, int offset, int length) { throw new RuntimeException("Stub!"); }
+
+public static java.nio.ByteBuffer wrap(byte[] array) { throw new RuntimeException("Stub!"); }
+
+public abstract java.nio.ByteBuffer slice();
+
+public abstract java.nio.ByteBuffer duplicate();
+
+public abstract java.nio.ByteBuffer asReadOnlyBuffer();
+
+public abstract byte get();
+
+public abstract java.nio.ByteBuffer put(byte b);
+
+public abstract byte get(int index);
+
+public abstract java.nio.ByteBuffer put(int index, byte b);
+
+public java.nio.ByteBuffer get(byte[] dst, int offset, int length) { throw new RuntimeException("Stub!"); }
+
+public java.nio.ByteBuffer get(byte[] dst) { throw new RuntimeException("Stub!"); }
+
+public java.nio.ByteBuffer put(java.nio.ByteBuffer src) { throw new RuntimeException("Stub!"); }
+
+public java.nio.ByteBuffer put(byte[] src, int offset, int length) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer put(byte[] src) { throw new RuntimeException("Stub!"); }
+
+public final boolean hasArray() { throw new RuntimeException("Stub!"); }
+
+public final byte[] array() { throw new RuntimeException("Stub!"); }
+
+public final int arrayOffset() { throw new RuntimeException("Stub!"); }
+
+public abstract java.nio.ByteBuffer compact();
+
+public abstract boolean isDirect();
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object ob) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(java.nio.ByteBuffer that) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteOrder order() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer order(java.nio.ByteOrder bo) { throw new RuntimeException("Stub!"); }
+
+public abstract char getChar();
+
+public abstract java.nio.ByteBuffer putChar(char value);
+
+public abstract char getChar(int index);
+
+public abstract java.nio.ByteBuffer putChar(int index, char value);
+
+public abstract java.nio.CharBuffer asCharBuffer();
+
+public abstract short getShort();
+
+public abstract java.nio.ByteBuffer putShort(short value);
+
+public abstract short getShort(int index);
+
+public abstract java.nio.ByteBuffer putShort(int index, short value);
+
+public abstract java.nio.ShortBuffer asShortBuffer();
+
+public abstract int getInt();
+
+public abstract java.nio.ByteBuffer putInt(int value);
+
+public abstract int getInt(int index);
+
+public abstract java.nio.ByteBuffer putInt(int index, int value);
+
+public abstract java.nio.IntBuffer asIntBuffer();
+
+public abstract long getLong();
+
+public abstract java.nio.ByteBuffer putLong(long value);
+
+public abstract long getLong(int index);
+
+public abstract java.nio.ByteBuffer putLong(int index, long value);
+
+public abstract java.nio.LongBuffer asLongBuffer();
+
+public abstract float getFloat();
+
+public abstract java.nio.ByteBuffer putFloat(float value);
+
+public abstract float getFloat(int index);
+
+public abstract java.nio.ByteBuffer putFloat(int index, float value);
+
+public abstract java.nio.FloatBuffer asFloatBuffer();
+
+public abstract double getDouble();
+
+public abstract java.nio.ByteBuffer putDouble(double value);
+
+public abstract double getDouble(int index);
+
+public abstract java.nio.ByteBuffer putDouble(int index, double value);
+
+public abstract java.nio.DoubleBuffer asDoubleBuffer();
+
+public boolean isAccessible() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public void setAccessible(boolean value) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/nio/ByteBuffer.java b/java/nio/ByteBuffer.java
new file mode 100644
index 0000000..b286cbd
--- /dev/null
+++ b/java/nio/ByteBuffer.java
@@ -0,0 +1,1746 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+import libcore.io.Memory;
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+/**
+ * A byte buffer.
+ *
+ * <p> This class defines six categories of operations upon
+ * byte buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(byte) <i>put</i>} methods that read and write
+ *   single bytes; </p></li>
+ *
+ *   <li><p> Relative {@link #get(byte[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of bytes from this buffer
+ *   into an array; </p></li>
+ *
+ *   <li><p> Relative {@link #put(byte[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of bytes from a
+ *   byte array or some other byte
+ *   buffer into this buffer; </p></li>
+ *
+ *
+ *   <li><p> Absolute and relative {@link #getChar() <i>get</i>}
+ *   and {@link #putChar(char) <i>put</i>} methods that read and
+ *   write values of other primitive types, translating them to and from
+ *   sequences of bytes in a particular byte order; </p></li>
+ *
+ *   <li><p> Methods for creating <i><a href="#views">view buffers</a></i>,
+ *   which allow a byte buffer to be viewed as a buffer containing values of
+ *   some other primitive type; and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   a byte buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Byte buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, or by {@link #wrap(byte[]) <i>wrapping</i>} an
+ * existing byte array  into a buffer.
+ *
+ *
+ *
+ * <a name="direct"></a>
+ * <h2> Direct <i>vs.</i> non-direct buffers </h2>
+ *
+ * <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>.  Given a
+ * direct byte buffer, the Java virtual machine will make a best effort to
+ * perform native I/O operations directly upon it.  That is, it will attempt to
+ * avoid copying the buffer's content to (or from) an intermediate buffer
+ * before (or after) each invocation of one of the underlying operating
+ * system's native I/O operations.
+ *
+ * <p> A direct byte buffer may be created by invoking the {@link
+ * #allocateDirect(int) allocateDirect} factory method of this class.  The
+ * buffers returned by this method typically have somewhat higher allocation
+ * and deallocation costs than non-direct buffers.  The contents of direct
+ * buffers may reside outside of the normal garbage-collected heap, and so
+ * their impact upon the memory footprint of an application might not be
+ * obvious.  It is therefore recommended that direct buffers be allocated
+ * primarily for large, long-lived buffers that are subject to the underlying
+ * system's native I/O operations.  In general it is best to allocate direct
+ * buffers only when they yield a measureable gain in program performance.
+ *
+ * <p> A direct byte buffer may also be created by {@link
+ * java.nio.channels.FileChannel#map mapping} a region of a file
+ * directly into memory.  An implementation of the Java platform may optionally
+ * support the creation of direct byte buffers from native code via JNI.  If an
+ * instance of one of these kinds of buffers refers to an inaccessible region
+ * of memory then an attempt to access that region will not change the buffer's
+ * content and will cause an unspecified exception to be thrown either at the
+ * time of the access or at some later time.
+ *
+ * <p> Whether a byte buffer is direct or non-direct may be determined by
+ * invoking its {@link #isDirect isDirect} method.  This method is provided so
+ * that explicit buffer management can be done in performance-critical code.
+ *
+ *
+ * <a name="bin"></a>
+ * <h2> Access to binary data </h2>
+ *
+ * <p> This class defines methods for reading and writing values of all other
+ * primitive types, except <tt>boolean</tt>.  Primitive values are translated
+ * to (or from) sequences of bytes according to the buffer's current byte
+ * order, which may be retrieved and modified via the {@link #order order}
+ * methods.  Specific byte orders are represented by instances of the {@link
+ * ByteOrder} class.  The initial order of a byte buffer is always {@link
+ * ByteOrder#BIG_ENDIAN BIG_ENDIAN}.
+ *
+ * <p> For access to heterogeneous binary data, that is, sequences of values of
+ * different types, this class defines a family of absolute and relative
+ * <i>get</i> and <i>put</i> methods for each type.  For 32-bit floating-point
+ * values, for example, this class defines:
+ *
+ * <blockquote><pre>
+ * float  {@link #getFloat()}
+ * float  {@link #getFloat(int) getFloat(int index)}
+ *  void  {@link #putFloat(float) putFloat(float f)}
+ *  void  {@link #putFloat(int,float) putFloat(int index, float f)}</pre></blockquote>
+ *
+ * <p> Corresponding methods are defined for the types <tt>char</tt>,
+ * <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and <tt>double</tt>.  The index
+ * parameters of the absolute <i>get</i> and <i>put</i> methods are in terms of
+ * bytes rather than of the type being read or written.
+ *
+ * <a name="views"></a>
+ *
+ * <p> For access to homogeneous binary data, that is, sequences of values of
+ * the same type, this class defines methods that can create <i>views</i> of a
+ * given byte buffer.  A <i>view buffer</i> is simply another buffer whose
+ * content is backed by the byte buffer.  Changes to the byte buffer's content
+ * will be visible in the view buffer, and vice versa; the two buffers'
+ * position, limit, and mark values are independent.  The {@link
+ * #asFloatBuffer() asFloatBuffer} method, for example, creates an instance of
+ * the {@link FloatBuffer} class that is backed by the byte buffer upon which
+ * the method is invoked.  Corresponding view-creation methods are defined for
+ * the types <tt>char</tt>, <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and
+ * <tt>double</tt>.
+ *
+ * <p> View buffers have three important advantages over the families of
+ * type-specific <i>get</i> and <i>put</i> methods described above:
+ *
+ * <ul>
+ *
+ *   <li><p> A view buffer is indexed not in terms of bytes but rather in terms
+ *   of the type-specific size of its values;  </p></li>
+ *
+ *   <li><p> A view buffer provides relative bulk <i>get</i> and <i>put</i>
+ *   methods that can transfer contiguous sequences of values between a buffer
+ *   and an array or some other buffer of the same type; and  </p></li>
+ *
+ *   <li><p> A view buffer is potentially much more efficient because it will
+ *   be direct if, and only if, its backing byte buffer is direct.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> The byte order of a view buffer is fixed to be that of its byte buffer
+ * at the time that the view is created.  </p>
+ *
+*
+*
+ *
+ * <h2> Invocation chaining </h2>
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ * The sequence of statements
+ *
+ * <blockquote><pre>
+ * bb.putInt(0xCAFEBABE);
+ * bb.putShort(3);
+ * bb.putShort(45);</pre></blockquote>
+ *
+ * can, for example, be replaced by the single statement
+ *
+ * <blockquote><pre>
+ * bb.putInt(0xCAFEBABE).putShort(3).putShort(45);</pre></blockquote>
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class ByteBuffer
+    extends Buffer
+    implements Comparable<ByteBuffer>
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final byte[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    ByteBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 byte[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 0 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    ByteBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new direct byte buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  Whether or not it has a
+     * {@link #hasArray backing array} is unspecified.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in bytes
+     *
+     * @return  The new byte buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static ByteBuffer allocateDirect(int capacity) {
+        // Android-changed: Android's DirectByteBuffers carry a MemoryRef.
+        // return new DirectByteBuffer(capacity);
+        DirectByteBuffer.MemoryRef memoryRef = new DirectByteBuffer.MemoryRef(capacity);
+        return new DirectByteBuffer(capacity, memoryRef);
+    }
+
+
+    /**
+     * Allocates a new byte buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in bytes
+     *
+     * @return  The new byte buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static ByteBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapByteBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps a byte array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given byte array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new byte buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static ByteBuffer wrap(byte[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapByteBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a byte array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given byte array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new byte buffer
+     */
+    public static ByteBuffer wrap(byte[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Creates a new byte buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new byte buffer
+     */
+    public abstract ByteBuffer slice();
+
+    /**
+     * Creates a new byte buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new byte buffer
+     */
+    public abstract ByteBuffer duplicate();
+
+    /**
+     * Creates a new, read-only byte buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only byte buffer
+     */
+    public abstract ByteBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the byte at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The byte at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract byte get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given byte into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  b
+     *         The byte to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer put(byte b);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the byte at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the byte will be read
+     *
+     * @return  The byte at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract byte get(int index);
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given byte into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the byte will be written
+     *
+     * @param  b
+     *         The byte value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer put(int index, byte b);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers bytes from this buffer into the given
+     * destination array.  If there are fewer bytes remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * bytes are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> bytes from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient bytes in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which bytes are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first byte to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of bytes to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> bytes
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public ByteBuffer get(byte[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers bytes from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> bytes
+     *          remaining in this buffer
+     */
+    public ByteBuffer get(byte[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the bytes remaining in the given source
+     * buffer into this buffer.  If there are more bytes remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no bytes are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> bytes from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which bytes are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining bytes in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public ByteBuffer put(ByteBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+
+        // Android-changed: improve ByteBuffer.put(ByteBuffer) performance through bulk copy.
+        /*
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        */
+        // Note that we use offset instead of arrayOffset because arrayOffset is specified to
+        // throw for read only buffers. Our use of arrayOffset here is provably safe, we only
+        // use it to read *from* readOnly buffers.
+        if (this.hb != null && src.hb != null) {
+            // System.arraycopy is intrinsified by ART and therefore tiny bit faster than memmove
+            System.arraycopy(src.hb, src.position() + src.offset, hb, position() + offset, n);
+        } else {
+            // Use the buffer object (and the raw memory address) if it's a direct buffer. Note that
+            // isDirect() doesn't imply !hasArray(), ByteBuffer.allocateDirect allocated buffer will
+            // have a backing, non-gc-movable byte array. JNI allocated direct byte buffers WILL NOT
+            // have a backing array.
+            final Object srcObject = src.isDirect() ? src : src.hb;
+            int srcOffset = src.position();
+            if (!src.isDirect()) {
+                srcOffset += src.offset;
+            }
+
+            final ByteBuffer dst = this;
+            final Object dstObject = dst.isDirect() ? dst : dst.hb;
+            int dstOffset = dst.position();
+            if (!dst.isDirect()) {
+                dstOffset += dst.offset;
+            }
+            Memory.memmove(dstObject, dstOffset, srcObject, srcOffset, n);
+        }
+        src.position(src.limit());
+        this.position(this.position() + n);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers bytes into this buffer from the given
+     * source array.  If there are more bytes to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * bytes are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> bytes from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which bytes are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first byte to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of bytes to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public ByteBuffer put(byte[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * byte array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final ByteBuffer put(byte[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible byte
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the byte array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final byte[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = ByteBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The bytes between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * byte at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the byte at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the byte at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of bytes copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * <p> Invoke this method after writing data from a buffer in case the
+     * write was incomplete.  The following loop, for example, copies bytes
+     * from one channel to another via the buffer <tt>buf</tt>:
+     *
+     * <blockquote><pre>{@code
+     *   buf.clear();          // Prepare buffer for use
+     *   while (in.read(buf) >= 0 || buf.position != 0) {
+     *       buf.flip();
+     *       out.write(buf);
+     *       buf.compact();    // In case of partial write
+     *   }
+     * }</pre></blockquote>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer compact();
+
+    /**
+     * Tells whether or not this byte buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns a string summarizing the state of this buffer.
+     *
+     * @return  A summary string
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getName());
+        sb.append("[pos=");
+        sb.append(position());
+        sb.append(" lim=");
+        sb.append(limit());
+        sb.append(" cap=");
+        sb.append(capacity());
+        sb.append("]");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a byte buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int)get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two byte buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A byte buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof ByteBuffer))
+            return false;
+        ByteBuffer that = (ByteBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(byte x, byte y) {
+
+
+        return x == y;
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two byte buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     * Pairs of {@code byte} elements are compared as if by invoking
+     * {@link Byte#compare(byte,byte)}.
+
+     *
+     * <p> A byte buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(ByteBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(byte x, byte y) {
+
+
+        return Byte.compare(x, y);
+
+    }
+
+    // -- Other char stuff --
+
+
+    // -- Other byte stuff: Access to binary data --
+
+
+    boolean bigEndian                                   // package-private
+        = true;
+    boolean nativeByteOrder                             // package-private
+        = (Bits.byteOrder() == ByteOrder.BIG_ENDIAN);
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order is used when reading or writing multibyte values, and
+     * when creating buffers that are views of this byte buffer.  The order of
+     * a newly-created byte buffer is always {@link ByteOrder#BIG_ENDIAN
+     * BIG_ENDIAN}.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public final ByteOrder order() {
+        return bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
+    }
+
+    /**
+     * Modifies this buffer's byte order.
+     *
+     * @param  bo
+     *         The new byte order,
+     *         either {@link ByteOrder#BIG_ENDIAN BIG_ENDIAN}
+     *         or {@link ByteOrder#LITTLE_ENDIAN LITTLE_ENDIAN}
+     *
+     * @return  This buffer
+     */
+    public final ByteBuffer order(ByteOrder bo) {
+        bigEndian = (bo == ByteOrder.BIG_ENDIAN);
+        nativeByteOrder =
+            (bigEndian == (Bits.byteOrder() == ByteOrder.BIG_ENDIAN));
+        return this;
+    }
+
+    // Unchecked accessors, for use by ByteBufferAs-X-Buffer classes
+    //
+    abstract byte _get(int i);                          // package-private
+    abstract void _put(int i, byte b);                  // package-private
+
+
+    /**
+     * Relative <i>get</i> method for reading a char value.
+     *
+     * <p> Reads the next two bytes at this buffer's current position,
+     * composing them into a char value according to the current byte order,
+     * and then increments the position by two.  </p>
+     *
+     * @return  The char value at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than two bytes
+     *          remaining in this buffer
+     */
+    public abstract char getChar();
+
+    /**
+     * Relative <i>put</i> method for writing a char
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes two bytes containing the given char value, in the
+     * current byte order, into this buffer at the current position, and then
+     * increments the position by two.  </p>
+     *
+     * @param  value
+     *         The char value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there are fewer than two bytes
+     *          remaining in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putChar(char value);
+
+    /**
+     * Absolute <i>get</i> method for reading a char value.
+     *
+     * <p> Reads two bytes at the given index, composing them into a
+     * char value according to the current byte order.  </p>
+     *
+     * @param  index
+     *         The index from which the bytes will be read
+     *
+     * @return  The char value at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus one
+     */
+    public abstract char getChar(int index);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract char getCharUnchecked(int index);
+    abstract void getUnchecked(int pos, char[] dst, int dstOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Absolute <i>put</i> method for writing a char
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes two bytes containing the given char value, in the
+     * current byte order, into this buffer at the given index.  </p>
+     *
+     * @param  index
+     *         The index at which the bytes will be written
+     *
+     * @param  value
+     *         The char value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus one
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putChar(int index, char value);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract void putCharUnchecked(int index, char value);
+    abstract void putUnchecked(int pos, char[] dst, int srcOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Creates a view of this byte buffer as a char buffer.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer divided by
+     * two, and its mark will be undefined.  The new buffer will be direct
+     * if, and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  A new char buffer
+     */
+    public abstract CharBuffer asCharBuffer();
+
+
+    /**
+     * Relative <i>get</i> method for reading a short value.
+     *
+     * <p> Reads the next two bytes at this buffer's current position,
+     * composing them into a short value according to the current byte order,
+     * and then increments the position by two.  </p>
+     *
+     * @return  The short value at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than two bytes
+     *          remaining in this buffer
+     */
+    public abstract short getShort();
+
+    /**
+     * Relative <i>put</i> method for writing a short
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes two bytes containing the given short value, in the
+     * current byte order, into this buffer at the current position, and then
+     * increments the position by two.  </p>
+     *
+     * @param  value
+     *         The short value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there are fewer than two bytes
+     *          remaining in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putShort(short value);
+
+    /**
+     * Absolute <i>get</i> method for reading a short value.
+     *
+     * <p> Reads two bytes at the given index, composing them into a
+     * short value according to the current byte order.  </p>
+     *
+     * @param  index
+     *         The index from which the bytes will be read
+     *
+     * @return  The short value at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus one
+     */
+    public abstract short getShort(int index);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract short getShortUnchecked(int index);
+    abstract void getUnchecked(int pos, short[] dst, int dstOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Absolute <i>put</i> method for writing a short
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes two bytes containing the given short value, in the
+     * current byte order, into this buffer at the given index.  </p>
+     *
+     * @param  index
+     *         The index at which the bytes will be written
+     *
+     * @param  value
+     *         The short value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus one
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putShort(int index, short value);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract void putShortUnchecked(int index, short value);
+    abstract void putUnchecked(int pos, short[] dst, int srcOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Creates a view of this byte buffer as a short buffer.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer divided by
+     * two, and its mark will be undefined.  The new buffer will be direct
+     * if, and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  A new short buffer
+     */
+    public abstract ShortBuffer asShortBuffer();
+
+
+    /**
+     * Relative <i>get</i> method for reading an int value.
+     *
+     * <p> Reads the next four bytes at this buffer's current position,
+     * composing them into an int value according to the current byte order,
+     * and then increments the position by four.  </p>
+     *
+     * @return  The int value at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than four bytes
+     *          remaining in this buffer
+     */
+    public abstract int getInt();
+
+    /**
+     * Relative <i>put</i> method for writing an int
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes four bytes containing the given int value, in the
+     * current byte order, into this buffer at the current position, and then
+     * increments the position by four.  </p>
+     *
+     * @param  value
+     *         The int value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there are fewer than four bytes
+     *          remaining in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putInt(int value);
+
+    /**
+     * Absolute <i>get</i> method for reading an int value.
+     *
+     * <p> Reads four bytes at the given index, composing them into a
+     * int value according to the current byte order.  </p>
+     *
+     * @param  index
+     *         The index from which the bytes will be read
+     *
+     * @return  The int value at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus three
+     */
+    public abstract int getInt(int index);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract int getIntUnchecked(int index);
+    abstract void getUnchecked(int pos, int[] dst, int dstOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Absolute <i>put</i> method for writing an int
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes four bytes containing the given int value, in the
+     * current byte order, into this buffer at the given index.  </p>
+     *
+     * @param  index
+     *         The index at which the bytes will be written
+     *
+     * @param  value
+     *         The int value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus three
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putInt(int index, int value);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract void putIntUnchecked(int index, int value);
+    abstract void putUnchecked(int pos, int[] dst, int srcOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Creates a view of this byte buffer as an int buffer.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer divided by
+     * four, and its mark will be undefined.  The new buffer will be direct
+     * if, and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  A new int buffer
+     */
+    public abstract IntBuffer asIntBuffer();
+
+
+    /**
+     * Relative <i>get</i> method for reading a long value.
+     *
+     * <p> Reads the next eight bytes at this buffer's current position,
+     * composing them into a long value according to the current byte order,
+     * and then increments the position by eight.  </p>
+     *
+     * @return  The long value at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than eight bytes
+     *          remaining in this buffer
+     */
+    public abstract long getLong();
+
+    /**
+     * Relative <i>put</i> method for writing a long
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes eight bytes containing the given long value, in the
+     * current byte order, into this buffer at the current position, and then
+     * increments the position by eight.  </p>
+     *
+     * @param  value
+     *         The long value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there are fewer than eight bytes
+     *          remaining in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putLong(long value);
+
+    /**
+     * Absolute <i>get</i> method for reading a long value.
+     *
+     * <p> Reads eight bytes at the given index, composing them into a
+     * long value according to the current byte order.  </p>
+     *
+     * @param  index
+     *         The index from which the bytes will be read
+     *
+     * @return  The long value at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus seven
+     */
+    public abstract long getLong(int index);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract long getLongUnchecked(int index);
+    abstract void getUnchecked(int pos, long[] dst, int dstOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Absolute <i>put</i> method for writing a long
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes eight bytes containing the given long value, in the
+     * current byte order, into this buffer at the given index.  </p>
+     *
+     * @param  index
+     *         The index at which the bytes will be written
+     *
+     * @param  value
+     *         The long value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus seven
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putLong(int index, long value);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract void putLongUnchecked(int index, long value);
+    abstract void putUnchecked(int pos, long[] dst, int srcOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Creates a view of this byte buffer as a long buffer.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer divided by
+     * eight, and its mark will be undefined.  The new buffer will be direct
+     * if, and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  A new long buffer
+     */
+    public abstract LongBuffer asLongBuffer();
+
+
+    /**
+     * Relative <i>get</i> method for reading a float value.
+     *
+     * <p> Reads the next four bytes at this buffer's current position,
+     * composing them into a float value according to the current byte order,
+     * and then increments the position by four.  </p>
+     *
+     * @return  The float value at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than four bytes
+     *          remaining in this buffer
+     */
+    public abstract float getFloat();
+
+    /**
+     * Relative <i>put</i> method for writing a float
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes four bytes containing the given float value, in the
+     * current byte order, into this buffer at the current position, and then
+     * increments the position by four.  </p>
+     *
+     * @param  value
+     *         The float value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there are fewer than four bytes
+     *          remaining in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putFloat(float value);
+
+    /**
+     * Absolute <i>get</i> method for reading a float value.
+     *
+     * <p> Reads four bytes at the given index, composing them into a
+     * float value according to the current byte order.  </p>
+     *
+     * @param  index
+     *         The index from which the bytes will be read
+     *
+     * @return  The float value at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus three
+     */
+    public abstract float getFloat(int index);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract float getFloatUnchecked(int index);
+    abstract void getUnchecked(int pos, float[] dst, int dstOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Absolute <i>put</i> method for writing a float
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes four bytes containing the given float value, in the
+     * current byte order, into this buffer at the given index.  </p>
+     *
+     * @param  index
+     *         The index at which the bytes will be written
+     *
+     * @param  value
+     *         The float value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus three
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putFloat(int index, float value);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract void putFloatUnchecked(int index, float value);
+    abstract void putUnchecked(int pos, float[] dst, int srcOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Creates a view of this byte buffer as a float buffer.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer divided by
+     * four, and its mark will be undefined.  The new buffer will be direct
+     * if, and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  A new float buffer
+     */
+    public abstract FloatBuffer asFloatBuffer();
+
+
+    /**
+     * Relative <i>get</i> method for reading a double value.
+     *
+     * <p> Reads the next eight bytes at this buffer's current position,
+     * composing them into a double value according to the current byte order,
+     * and then increments the position by eight.  </p>
+     *
+     * @return  The double value at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than eight bytes
+     *          remaining in this buffer
+     */
+    public abstract double getDouble();
+
+    /**
+     * Relative <i>put</i> method for writing a double
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes eight bytes containing the given double value, in the
+     * current byte order, into this buffer at the current position, and then
+     * increments the position by eight.  </p>
+     *
+     * @param  value
+     *         The double value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there are fewer than eight bytes
+     *          remaining in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putDouble(double value);
+
+    /**
+     * Absolute <i>get</i> method for reading a double value.
+     *
+     * <p> Reads eight bytes at the given index, composing them into a
+     * double value according to the current byte order.  </p>
+     *
+     * @param  index
+     *         The index from which the bytes will be read
+     *
+     * @return  The double value at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus seven
+     */
+    public abstract double getDouble(int index);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract double getDoubleUnchecked(int index);
+    abstract void getUnchecked(int pos, double[] dst, int dstOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Absolute <i>put</i> method for writing a double
+     * value&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes eight bytes containing the given double value, in the
+     * current byte order, into this buffer at the given index.  </p>
+     *
+     * @param  index
+     *         The index at which the bytes will be written
+     *
+     * @param  value
+     *         The double value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit,
+     *          minus seven
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ByteBuffer putDouble(int index, double value);
+
+    // BEGIN Android-added: {get,put}*Unchecked() accessors.
+    abstract void putDoubleUnchecked(int index, double value);
+    abstract void putUnchecked(int pos, double[] dst, int srcOffset, int length);
+    // END Android-added: {get,put}*Unchecked() accessors.
+
+    /**
+     * Creates a view of this byte buffer as a double buffer.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of bytes remaining in this buffer divided by
+     * eight, and its mark will be undefined.  The new buffer will be direct
+     * if, and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  A new double buffer
+     */
+    public abstract DoubleBuffer asDoubleBuffer();
+
+    // BEGIN Android-added: isAccessible(), setAccessible(), for use by frameworks (MediaCodec).
+    /**
+     * @hide
+     */
+    public boolean isAccessible() {
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    public void setAccessible(boolean value) {
+        throw new UnsupportedOperationException();
+    }
+    // END Android-added: isAccessible(), setAccessible(), for use by frameworks (MediaCodec).
+}
diff --git a/java/nio/ByteBufferAsCharBuffer.java b/java/nio/ByteBufferAsCharBuffer.java
new file mode 100644
index 0000000..9dbb8a6
--- /dev/null
+++ b/java/nio/ByteBufferAsCharBuffer.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import libcore.io.Memory;
+
+class ByteBufferAsCharBuffer extends CharBuffer {      // package-private
+
+    protected final ByteBuffer bb;
+    protected final int offset;
+    private final ByteOrder order;
+
+    ByteBufferAsCharBuffer(ByteBuffer bb,
+                           int mark, int pos, int lim, int cap,
+                           int off, ByteOrder order) {
+        super(mark, pos, lim, cap);
+        this.bb = bb.duplicate();
+        this.isReadOnly = bb.isReadOnly;
+        // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
+        // HeapByteBuffer. We only have to initialize the field when bb is an instance of
+        // DirectByteBuffer.
+        // The address field is used by NIOAccess#getBasePointer and GetDirectBufferAddress method
+        // in art which return the address of the first usable byte of the underlying memory, i.e,
+        // the position of parent buffer. Therefore, value of "off" will be equal to parent buffer's
+        // position when the method is called from either HeapByteBuffer or DirectByteBuffer.
+        if (bb instanceof DirectByteBuffer) {
+            this.address = bb.address + off;
+        }
+        this.bb.order(order);
+        this.order = order;
+        offset = off;
+    }
+
+    public CharBuffer slice() {
+        int pos = this.position();
+        int lim = this.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = (pos << 1) + offset;
+        assert (off >= 0);
+        return new ByteBufferAsCharBuffer(bb, -1, 0, rem, rem, off, order);
+    }
+
+    public CharBuffer duplicate() {
+        return new ByteBufferAsCharBuffer(bb,
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    public CharBuffer asReadOnlyBuffer() {
+        return new ByteBufferAsCharBuffer(bb.asReadOnlyBuffer(),
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    protected int ix(int i) {
+        return (i << 1) + offset;
+    }
+
+    public char get() {
+        return get(nextGetIndex());
+    }
+
+    public char get(int i) {
+        return bb.getCharUnchecked(ix(checkIndex(i)));
+    }
+
+    public CharBuffer get(char[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        bb.getUnchecked(ix(position), dst, offset, length);
+        position += length;
+        return this;
+    }
+
+    char getUnchecked(int i) {
+        return bb.getCharUnchecked(ix(i));
+    }
+
+    public CharBuffer put(char x) {
+        put(nextPutIndex(), x);
+        return this;
+    }
+
+    public CharBuffer put(int i, char x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        bb.putCharUnchecked(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    public CharBuffer put(char[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        bb.putUnchecked(ix(position), src, offset, length);
+        position += length;
+        return this;
+    }
+
+    public CharBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (!(bb instanceof DirectByteBuffer)) {
+            System.arraycopy(bb.array(), ix(pos), bb.array(), ix(0), rem << 1);
+        } else {
+            Memory.memmove(this, ix(0), this, ix(pos), rem << 1);
+        }
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public boolean isDirect() {
+        return bb.isDirect();
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public String toString(int start, int end) {
+        if ((end > limit()) || (start > end))
+            throw new IndexOutOfBoundsException();
+        try {
+            int len = end - start;
+            char[] ca = new char[len];
+            CharBuffer cb = CharBuffer.wrap(ca);
+            CharBuffer db = this.duplicate();
+            db.position(start);
+            db.limit(end);
+            cb.put(db);
+            return new String(ca);
+        } catch (StringIndexOutOfBoundsException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    // --- Methods to support CharSequence ---
+
+    public CharBuffer subSequence(int start, int end) {
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        pos = (pos <= lim ? pos : lim);
+        int len = lim - pos;
+
+        if ((start < 0) || (end > len) || (start > end))
+            throw new IndexOutOfBoundsException();
+        return new ByteBufferAsCharBuffer(bb,
+                -1,
+                pos + start,
+                pos + end,
+                capacity(),
+                offset,
+                order);
+    }
+
+    public ByteOrder order() {
+        return order;
+    }
+}
diff --git a/java/nio/ByteBufferAsDoubleBuffer.java b/java/nio/ByteBufferAsDoubleBuffer.java
new file mode 100644
index 0000000..ff4a6bf
--- /dev/null
+++ b/java/nio/ByteBufferAsDoubleBuffer.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import libcore.io.Memory;
+
+class ByteBufferAsDoubleBuffer
+        extends DoubleBuffer {            // package-private
+
+    protected final ByteBuffer bb;
+    protected final int offset;
+    private final ByteOrder order;
+
+    ByteBufferAsDoubleBuffer(ByteBuffer bb,
+                             int mark, int pos, int lim, int cap,
+                             int off, ByteOrder order) {
+        super(mark, pos, lim, cap);
+        this.bb = bb.duplicate();
+        this.isReadOnly = bb.isReadOnly;
+        // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
+        // HeapByteBuffer. We only have to initialize the field when bb is an instance of
+        // DirectByteBuffer.
+        // The address field is used by NIOAccess#getBasePointer and GetDirectBufferAddress method
+        // in art which return the address of the first usable byte of the underlying memory, i.e,
+        // the position of parent buffer. Therefore, value of "off" will be equal to parent buffer's
+        // position when the method is called from either HeapByteBuffer or DirectByteBuffer.
+        if (bb instanceof DirectByteBuffer) {
+            this.address = bb.address + off;
+        }
+        this.bb.order(order);
+        this.order = order;
+        offset = off;
+    }
+
+    public DoubleBuffer slice() {
+        int pos = this.position();
+        int lim = this.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = (pos << 3) + offset;
+        assert (off >= 0);
+        return new ByteBufferAsDoubleBuffer(bb, -1, 0, rem, rem, off, order);
+    }
+
+    public DoubleBuffer duplicate() {
+        return new ByteBufferAsDoubleBuffer(bb,
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    public DoubleBuffer asReadOnlyBuffer() {
+        return new ByteBufferAsDoubleBuffer(bb.asReadOnlyBuffer(),
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    protected int ix(int i) {
+        return (i << 3) + offset;
+    }
+
+    public double get() {
+        return get(nextGetIndex());
+    }
+
+    public double get(int i) {
+        return bb.getDoubleUnchecked(ix(checkIndex(i)));
+    }
+
+    public DoubleBuffer get(double[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        bb.getUnchecked(ix(position), dst, offset, length);
+        position += length;
+        return this;
+    }
+
+    public DoubleBuffer put(double x) {
+        put(nextPutIndex(), x);
+        return this;
+    }
+
+    public DoubleBuffer put(int i, double x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        bb.putDoubleUnchecked(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    public DoubleBuffer put(double[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        bb.putUnchecked(ix(position), src, offset, length);
+        position += length;
+        return this;
+    }
+
+    public DoubleBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (!(bb instanceof DirectByteBuffer)) {
+            System.arraycopy(bb.array(), ix(pos), bb.array(), ix(0), rem << 3);
+        } else {
+            Memory.memmove(this, ix(0), this, ix(pos), rem << 3);
+        }
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public boolean isDirect() {
+        return bb.isDirect();
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public ByteOrder order() {
+        return order;
+    }
+}
diff --git a/java/nio/ByteBufferAsFloatBuffer.java b/java/nio/ByteBufferAsFloatBuffer.java
new file mode 100644
index 0000000..8e4e2e8
--- /dev/null
+++ b/java/nio/ByteBufferAsFloatBuffer.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import libcore.io.Memory;
+
+class ByteBufferAsFloatBuffer extends FloatBuffer {       // package-private
+
+    protected final ByteBuffer bb;
+    protected final int offset;
+    private final ByteOrder order;
+
+    ByteBufferAsFloatBuffer(ByteBuffer bb,
+                            int mark, int pos, int lim, int cap,
+                            int off, ByteOrder order) {
+        super(mark, pos, lim, cap);
+        this.bb = bb.duplicate();
+        this.isReadOnly = bb.isReadOnly;
+        // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
+        // HeapByteBuffer. We only have to initialize the field when bb is an instance of
+        // DirectByteBuffer.
+        // The address field is used by NIOAccess#getBasePointer and GetDirectBufferAddress method
+        // in art which return the address of the first usable byte of the underlying memory, i.e,
+        // the position of parent buffer. Therefore, value of "off" will be equal to parent buffer's
+        // position when the method is called from either HeapByteBuffer or DirectByteBuffer.
+        if (bb instanceof DirectByteBuffer) {
+            this.address = bb.address + off;
+        }
+        this.bb.order(order);
+        this.order = order;
+        offset = off;
+    }
+
+    public FloatBuffer slice() {
+        int pos = this.position();
+        int lim = this.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = (pos << 2) + offset;
+        assert (off >= 0);
+        return new ByteBufferAsFloatBuffer(bb, -1, 0, rem, rem, off, order);
+    }
+
+    public FloatBuffer duplicate() {
+        return new ByteBufferAsFloatBuffer(bb,
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    public FloatBuffer asReadOnlyBuffer() {
+        return new ByteBufferAsFloatBuffer(bb.asReadOnlyBuffer(),
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    protected int ix(int i) {
+        return (i << 2) + offset;
+    }
+
+    public float get() {
+        return get(nextGetIndex());
+    }
+
+    public float get(int i) {
+        return bb.getFloatUnchecked(ix(checkIndex(i)));
+    }
+
+    public FloatBuffer get(float[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        bb.getUnchecked(ix(position), dst, offset, length);
+        position += length;
+        return this;
+    }
+
+    public FloatBuffer put(float x) {
+        put(nextPutIndex(), x);
+        return this;
+    }
+
+    public FloatBuffer put(int i, float x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        bb.putFloatUnchecked(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    public FloatBuffer put(float[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        bb.putUnchecked(ix(position), src, offset, length);
+        position += length;
+        return this;
+    }
+
+    public FloatBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (!(bb instanceof DirectByteBuffer)) {
+            System.arraycopy(bb.array(), ix(pos), bb.array(), ix(0), rem << 2);
+        } else {
+            Memory.memmove(this, ix(0), this, ix(pos), rem << 2);
+        }
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public boolean isDirect() {
+        return bb.isDirect();
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public ByteOrder order() {
+        return order;
+    }
+}
diff --git a/java/nio/ByteBufferAsIntBuffer.java b/java/nio/ByteBufferAsIntBuffer.java
new file mode 100644
index 0000000..e340426
--- /dev/null
+++ b/java/nio/ByteBufferAsIntBuffer.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import libcore.io.Memory;
+
+class ByteBufferAsIntBuffer extends IntBuffer {        // package-private
+
+    protected final ByteBuffer bb;
+    protected final int offset;
+    private final ByteOrder order;
+
+    ByteBufferAsIntBuffer(ByteBuffer bb,
+                          int mark, int pos, int lim, int cap,
+                          int off, ByteOrder order) {
+        super(mark, pos, lim, cap);
+        this.bb = bb.duplicate();
+        this.isReadOnly = bb.isReadOnly;
+        // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
+        // HeapByteBuffer. We only have to initialize the field when bb is an instance of
+        // DirectByteBuffer.
+        // The address field is used by NIOAccess#getBasePointer and GetDirectBufferAddress method
+        // in art which return the address of the first usable byte of the underlying memory, i.e,
+        // the position of parent buffer. Therefore, value of "off" will be equal to parent buffer's
+        // position when the method is called from either HeapByteBuffer or DirectByteBuffer.
+        if (bb instanceof DirectByteBuffer) {
+            this.address = bb.address + off;
+        }
+        this.bb.order(order);
+        this.order = order;
+        offset = off;
+    }
+
+    public IntBuffer slice() {
+        int pos = this.position();
+        int lim = this.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = (pos << 2) + offset;
+        assert (off >= 0);
+        return new ByteBufferAsIntBuffer(bb, -1, 0, rem, rem, off, order);
+    }
+
+    public IntBuffer duplicate() {
+        return new ByteBufferAsIntBuffer(bb,
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    public IntBuffer asReadOnlyBuffer() {
+        return new ByteBufferAsIntBuffer(bb.asReadOnlyBuffer(),
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                order);
+    }
+
+    protected int ix(int i) {
+        return (i << 2) + offset;
+    }
+
+    public int get() {
+        return get(nextGetIndex());
+    }
+
+    public int get(int i) {
+        return bb.getIntUnchecked(ix(checkIndex(i)));
+    }
+
+    public IntBuffer get(int[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        bb.getUnchecked(ix(position), dst, offset, length);
+        position += length;
+        return this;
+    }
+
+    public IntBuffer put(int x) {
+        put(nextPutIndex(), x);
+        return this;
+    }
+
+    public IntBuffer put(int i, int x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        bb.putIntUnchecked(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    public IntBuffer put(int[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        bb.putUnchecked(ix(position), src, offset, length);
+        position += length;
+        return this;
+    }
+
+    public IntBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (!(bb instanceof DirectByteBuffer)) {
+            System.arraycopy(bb.array(), ix(pos), bb.array(), ix(0), rem << 2);
+        } else {
+            Memory.memmove(this, ix(0), this, ix(pos), rem << 2);
+        }
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public boolean isDirect() {
+        return bb.isDirect();
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public ByteOrder order() {
+        return order;
+    }
+}
diff --git a/java/nio/ByteBufferAsLongBuffer.java b/java/nio/ByteBufferAsLongBuffer.java
new file mode 100644
index 0000000..70f59c9
--- /dev/null
+++ b/java/nio/ByteBufferAsLongBuffer.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import libcore.io.Memory;
+
+class ByteBufferAsLongBuffer extends LongBuffer {                 // package-private
+
+    protected final ByteBuffer bb;
+    protected final int offset;
+    private final ByteOrder order;
+
+    ByteBufferAsLongBuffer(ByteBuffer bb,
+                           int mark, int pos, int lim, int cap,
+                           int off, ByteOrder order) {
+        super(mark, pos, lim, cap);
+        this.bb = bb.duplicate();
+        this.isReadOnly = bb.isReadOnly;
+        // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
+        // HeapByteBuffer. We only have to initialize the field when bb is an instance of
+        // DirectByteBuffer.
+        // The address field is used by NIOAccess#getBasePointer and GetDirectBufferAddress method
+        // in art which return the address of the first usable byte of the underlying memory, i.e,
+        // the position of parent buffer. Therefore, value of "off" will be equal to parent buffer's
+        // position when the method is called from either HeapByteBuffer or DirectByteBuffer.
+        if (bb instanceof DirectByteBuffer) {
+            this.address = bb.address + off;
+        }
+        this.bb.order(order);
+        this.order = order;
+        offset = off;
+    }
+
+    public LongBuffer slice() {
+        int pos = this.position();
+        int lim = this.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = (pos << 3) + offset;
+        assert (off >= 0);
+        return new ByteBufferAsLongBuffer(bb, -1, 0, rem, rem, off, order);
+    }
+
+    public LongBuffer duplicate() {
+        return new ByteBufferAsLongBuffer(bb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                order);
+    }
+
+    public LongBuffer asReadOnlyBuffer() {
+        return new ByteBufferAsLongBuffer(bb.asReadOnlyBuffer(),
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                order);
+    }
+
+    protected int ix(int i) {
+        return (i << 3) + offset;
+    }
+
+    public long get() {
+        return get(nextGetIndex());
+    }
+
+    public long get(int i) {
+        return bb.getLongUnchecked(ix(checkIndex(i)));
+    }
+
+    public LongBuffer get(long[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        bb.getUnchecked(ix(position), dst, offset, length);
+        position += length;
+        return this;
+    }
+
+    public LongBuffer put(long x) {
+        put(nextPutIndex(), x);
+        return this;
+    }
+
+    public LongBuffer put(int i, long x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        bb.putLongUnchecked(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    public LongBuffer put(long[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        bb.putUnchecked(ix(position), src, offset, length);
+        position += length;
+        return this;
+    }
+
+    public LongBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (!(bb instanceof DirectByteBuffer)) {
+            System.arraycopy(bb.array(), ix(pos), bb.array(), ix(0), rem << 3);
+        } else {
+            Memory.memmove(this, ix(0), this, ix(pos), rem << 3);
+        }
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public boolean isDirect() {
+        return bb.isDirect();
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public ByteOrder order() {
+        return order;
+    }
+}
diff --git a/java/nio/ByteBufferAsShortBuffer.java b/java/nio/ByteBufferAsShortBuffer.java
new file mode 100644
index 0000000..5178a7e
--- /dev/null
+++ b/java/nio/ByteBufferAsShortBuffer.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import libcore.io.Memory;
+
+class ByteBufferAsShortBuffer extends ShortBuffer {       // package-private
+
+    protected final ByteBuffer bb;
+    protected final int offset;
+    private final ByteOrder order;
+
+    ByteBufferAsShortBuffer(ByteBuffer bb,
+                            int mark, int pos, int lim, int cap,
+                            int off, ByteOrder order) {
+        super(mark, pos, lim, cap);
+        this.bb = bb.duplicate();
+        this.isReadOnly = bb.isReadOnly;
+        // There are only two possibilities for the type of ByteBuffer "bb", viz, DirectByteBuffer and
+        // HeapByteBuffer. We only have to initialize the field when bb is an instance of
+        // DirectByteBuffer.
+        // The address field is use by NIOAccess#getBasePointer and GetDirectBufferAddress method
+        // in art which return the address of the first usable byte of the underlying memory, i.e,
+        // the position of parent buffer. Therefore, value of "off" will be equal to parent buffer's
+        // position when the method is called from either HeapByteBuffer or DirectByteBuffer.
+        if (bb instanceof DirectByteBuffer) {
+            this.address = bb.address + off;
+        }
+        this.bb.order(order);
+        this.order = order;
+        offset = off;
+    }
+
+    public ShortBuffer slice() {
+        int pos = this.position();
+        int lim = this.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = (pos << 1) + offset;
+        assert (off >= 0);
+        return new ByteBufferAsShortBuffer(bb, -1, 0, rem, rem, off, order);
+    }
+
+    public ShortBuffer duplicate() {
+        return new ByteBufferAsShortBuffer(bb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset, order);
+    }
+
+    public ShortBuffer asReadOnlyBuffer() {
+        return new ByteBufferAsShortBuffer(bb.asReadOnlyBuffer(),
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset, order);
+    }
+
+    protected int ix(int i) {
+        return (i << 1) + offset;
+    }
+
+    public short get() {
+        return get(nextGetIndex());
+    }
+
+    public short get(int i) {
+        return bb.getShortUnchecked(ix(checkIndex(i)));
+
+    }
+
+    public ShortBuffer get(short[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        bb.getUnchecked(ix(position), dst, offset, length);
+        position += length;
+        return this;
+    }
+
+    public ShortBuffer put(short x) {
+        put(nextPutIndex(), x);
+        return this;
+    }
+
+    public ShortBuffer put(int i, short x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        bb.putShortUnchecked(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    public ShortBuffer put(short[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        bb.putUnchecked(ix(position), src, offset, length);
+        position += length;
+        return this;
+    }
+
+    public ShortBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (!(bb instanceof DirectByteBuffer)) {
+            System.arraycopy(bb.array(), ix(pos), bb.array(), ix(0), rem << 1);
+        } else {
+            Memory.memmove(this, ix(0), this, ix(pos), rem << 1);
+        }
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public boolean isDirect() {
+        return bb.isDirect();
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public ByteOrder order() {
+        return order;
+    }
+}
diff --git a/java/nio/ByteOrder.java b/java/nio/ByteOrder.java
new file mode 100644
index 0000000..a20cacc
--- /dev/null
+++ b/java/nio/ByteOrder.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+
+/**
+ * A typesafe enumeration for byte orders.
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public final class ByteOrder {
+
+    private String name;
+
+    private ByteOrder(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Constant denoting big-endian byte order.  In this order, the bytes of a
+     * multibyte value are ordered from most significant to least significant.
+     */
+    public static final ByteOrder BIG_ENDIAN
+        = new ByteOrder("BIG_ENDIAN");
+
+    /**
+     * Constant denoting little-endian byte order.  In this order, the bytes of
+     * a multibyte value are ordered from least significant to most
+     * significant.
+     */
+    public static final ByteOrder LITTLE_ENDIAN
+        = new ByteOrder("LITTLE_ENDIAN");
+
+    /**
+     * Retrieves the native byte order of the underlying platform.
+     *
+     * <p> This method is defined so that performance-sensitive Java code can
+     * allocate direct buffers with the same byte order as the hardware.
+     * Native code libraries are often more efficient when such buffers are
+     * used.  </p>
+     *
+     * @return  The native byte order of the hardware upon which this Java
+     *          virtual machine is running
+     */
+    public static ByteOrder nativeOrder() {
+        return Bits.byteOrder();
+    }
+
+    /**
+     * Constructs a string describing this object.
+     *
+     * <p> This method returns the string <tt>"BIG_ENDIAN"</tt> for {@link
+     * #BIG_ENDIAN} and <tt>"LITTLE_ENDIAN"</tt> for {@link #LITTLE_ENDIAN}.
+     * </p>
+     *
+     * @return  The specified string
+     */
+    public String toString() {
+        return name;
+    }
+
+}
diff --git a/java/nio/CharBuffer.java b/java/nio/CharBuffer.java
new file mode 100644
index 0000000..6d73448
--- /dev/null
+++ b/java/nio/CharBuffer.java
@@ -0,0 +1,1274 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+import java.io.IOException;
+import java.util.Spliterator;
+import java.util.stream.StreamSupport;
+import java.util.stream.IntStream;
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+
+/**
+ * A char buffer.
+ *
+ * <p> This class defines four categories of operations upon
+ * char buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(char) <i>put</i>} methods that read and write
+ *   single chars; </p></li>
+ *
+ *   <li><p> Relative {@link #get(char[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of chars from this buffer
+ *   into an array; and</p></li>
+ *
+ *   <li><p> Relative {@link #put(char[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of chars from a
+ *   char array,&#32;a&#32;string, or some other char
+ *   buffer into this buffer;&#32;and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   a char buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Char buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, by {@link #wrap(char[]) <i>wrapping</i>} an existing
+ * char array or&#32;string into a buffer, or by creating a
+ * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer.
+ *
+ *
+*
+ *
+ * <p> Like a byte buffer, a char buffer is either <a
+ * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>.  A
+ * char buffer created via the <tt>wrap</tt> methods of this class will
+ * be non-direct.  A char buffer created as a view of a byte buffer will
+ * be direct if, and only if, the byte buffer itself is direct.  Whether or not
+ * a char buffer is direct may be determined by invoking the {@link
+ * #isDirect isDirect} method.  </p>
+ *
+*
+ *
+ * <p> This class implements the {@link CharSequence} interface so that
+ * character buffers may be used wherever character sequences are accepted, for
+ * example in the regular-expression package <tt>{@link java.util.regex}</tt>.
+ * </p>
+ *
+ *
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ * The sequence of statements
+ *
+ * <blockquote><pre>
+ * cb.put("text/");
+ * cb.put(subtype);
+ * cb.put("; charset=");
+ * cb.put(enc);</pre></blockquote>
+ *
+ * can, for example, be replaced by the single statement
+ *
+ * <blockquote><pre>
+ * cb.put("text/").put(subtype).put("; charset=").put(enc);</pre></blockquote>
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class CharBuffer
+    extends Buffer
+    implements Comparable<CharBuffer>, Appendable, CharSequence, Readable
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final char[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    CharBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 char[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 1 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    CharBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new char buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in chars
+     *
+     * @return  The new char buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static CharBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapCharBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps a char array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given char array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new char buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static CharBuffer wrap(char[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapCharBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a char array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given char array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new char buffer
+     */
+    public static CharBuffer wrap(char[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Attempts to read characters into the specified character buffer.
+     * The buffer is used as a repository of characters as-is: the only
+     * changes made are the results of a put operation. No flipping or
+     * rewinding of the buffer is performed.
+     *
+     * @param target the buffer to read characters into
+     * @return The number of characters added to the buffer, or
+     *         -1 if this source of characters is at its end
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if target is null
+     * @throws ReadOnlyBufferException if target is a read only buffer
+     * @since 1.5
+     */
+    public int read(CharBuffer target) throws IOException {
+        // Determine the number of bytes n that can be transferred
+        int targetRemaining = target.remaining();
+        int remaining = remaining();
+        if (remaining == 0)
+            return -1;
+        int n = Math.min(remaining, targetRemaining);
+        int limit = limit();
+        // Set source limit to prevent target overflow
+        if (targetRemaining < remaining)
+            limit(position() + n);
+        try {
+            if (n > 0)
+                target.put(this);
+        } finally {
+            limit(limit); // restore real limit
+        }
+        return n;
+    }
+
+    /**
+     * Wraps a character sequence into a buffer.
+     *
+     * <p> The content of the new, read-only buffer will be the content of the
+     * given character sequence.  The buffer's capacity will be
+     * <tt>csq.length()</tt>, its position will be <tt>start</tt>, its limit
+     * will be <tt>end</tt>, and its mark will be undefined.  </p>
+     *
+     * @param  csq
+     *         The character sequence from which the new character buffer is to
+     *         be created
+     *
+     * @param  start
+     *         The index of the first character to be used;
+     *         must be non-negative and no larger than <tt>csq.length()</tt>.
+     *         The new buffer's position will be set to this value.
+     *
+     * @param  end
+     *         The index of the character following the last character to be
+     *         used; must be no smaller than <tt>start</tt> and no larger
+     *         than <tt>csq.length()</tt>.
+     *         The new buffer's limit will be set to this value.
+     *
+     * @return  The new character buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>start</tt> and <tt>end</tt>
+     *          parameters do not hold
+     */
+    public static CharBuffer wrap(CharSequence csq, int start, int end) {
+        try {
+            return new StringCharBuffer(csq, start, end);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a character sequence into a buffer.
+     *
+     * <p> The content of the new, read-only buffer will be the content of the
+     * given character sequence.  The new buffer's capacity and limit will be
+     * <tt>csq.length()</tt>, its position will be zero, and its mark will be
+     * undefined.  </p>
+     *
+     * @param  csq
+     *         The character sequence from which the new character buffer is to
+     *         be created
+     *
+     * @return  The new character buffer
+     */
+    public static CharBuffer wrap(CharSequence csq) {
+        return wrap(csq, 0, csq.length());
+    }
+
+
+    /**
+     * Creates a new char buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of chars remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new char buffer
+     */
+    public abstract CharBuffer slice();
+
+    /**
+     * Creates a new char buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new char buffer
+     */
+    public abstract CharBuffer duplicate();
+
+    /**
+     * Creates a new, read-only char buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only char buffer
+     */
+    public abstract CharBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the char at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The char at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract char get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given char into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  c
+     *         The char to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract CharBuffer put(char c);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the char at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the char will be read
+     *
+     * @return  The char at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract char get(int index);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the char at the given
+     * index without any validation of the index.
+     *
+     * @param  index
+     *         The index from which the char will be read
+     *
+     * @return  The char at the given index
+     */
+    abstract char getUnchecked(int index);   // package-private
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given char into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the char will be written
+     *
+     * @param  c
+     *         The char value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract CharBuffer put(int index, char c);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers chars from this buffer into the given
+     * destination array.  If there are fewer chars remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * chars are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> chars from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient chars in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which chars are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first char to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of chars to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> chars
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public CharBuffer get(char[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers chars from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> chars
+     *          remaining in this buffer
+     */
+    public CharBuffer get(char[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the chars remaining in the given source
+     * buffer into this buffer.  If there are more chars remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no chars are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> chars from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which chars are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining chars in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public CharBuffer put(CharBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers chars into this buffer from the given
+     * source array.  If there are more chars to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * chars are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> chars from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which chars are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first char to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of chars to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public CharBuffer put(char[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * char array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final CharBuffer put(char[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers chars from the given string into this
+     * buffer.  If there are more chars to be copied from the string than
+     * remain in this buffer, that is, if
+     * <tt>end&nbsp;-&nbsp;start</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no chars are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>end</tt>&nbsp;-&nbsp;<tt>start</tt> chars
+     * from the given string into this buffer, starting at the given
+     * <tt>start</tt> index and at the current position of this buffer.  The
+     * position of this buffer is then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;start,&nbsp;end)</tt> has exactly the same effect
+     * as the loop
+     *
+     * <pre>{@code
+     *     for (int i = start; i < end; i++)
+     *         dst.put(src.charAt(i));
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The string from which chars are to be read
+     *
+     * @param  start
+     *         The offset within the string of the first char to be read;
+     *         must be non-negative and no larger than
+     *         <tt>string.length()</tt>
+     *
+     * @param  end
+     *         The offset within the string of the last char to be read,
+     *         plus one; must be non-negative and no larger than
+     *         <tt>string.length()</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>start</tt> and <tt>end</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public CharBuffer put(String src, int start, int end) {
+        checkBounds(start, end - start, src.length());
+
+        // BEGIN Android-added: Don't check readonly/overflow if there's nothing to write.
+        // This is questionable behaviour but code expects it.
+        if (start == end) {
+            return this;
+        }
+        // END Android-added: Don't check readonly/overflow if there's nothing to write.
+
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        if (end - start > remaining())
+            throw new BufferOverflowException();
+        for (int i = start; i < end; i++)
+            this.put(src.charAt(i));
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source string
+     * into this buffer.  An invocation of this method of the form
+     * <tt>dst.put(s)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     dst.put(s, 0, s.length()) </pre>
+     *
+     * @param   src
+     *          The source string
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final CharBuffer put(String src) {
+        return put(src, 0, src.length());
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible char
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the char array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final char[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = CharBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The chars between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * char at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the char at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the char at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of chars copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract CharBuffer compact();
+
+    /**
+     * Tells whether or not this char buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a char buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int) get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two char buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A char buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof CharBuffer))
+            return false;
+        CharBuffer that = (CharBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(char x, char y) {
+
+
+        return x == y;
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two char buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     * Pairs of {@code char} elements are compared as if by invoking
+     * {@link Character#compare(char,char)}.
+
+     *
+     * <p> A char buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(CharBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(char x, char y) {
+
+
+        return Character.compare(x, y);
+
+    }
+
+    // -- Other char stuff --
+
+
+    /**
+     * Returns a string containing the characters in this buffer.
+     *
+     * <p> The first character of the resulting string will be the character at
+     * this buffer's position, while the last character will be the character
+     * at index <tt>limit()</tt>&nbsp;-&nbsp;1.  Invoking this method does not
+     * change the buffer's position. </p>
+     *
+     * @return  The specified string
+     */
+    public String toString() {
+        return toString(position(), limit());
+    }
+
+    abstract String toString(int start, int end);       // package-private
+
+
+    // --- Methods to support CharSequence ---
+
+    /**
+     * Returns the length of this character buffer.
+     *
+     * <p> When viewed as a character sequence, the length of a character
+     * buffer is simply the number of characters between the position
+     * (inclusive) and the limit (exclusive); that is, it is equivalent to
+     * <tt>remaining()</tt>. </p>
+     *
+     * @return  The length of this character buffer
+     */
+    public final int length() {
+        return remaining();
+    }
+
+    /**
+     * Reads the character at the given index relative to the current
+     * position.
+     *
+     * @param  index
+     *         The index of the character to be read, relative to the position;
+     *         must be non-negative and smaller than <tt>remaining()</tt>
+     *
+     * @return  The character at index
+     *          <tt>position()&nbsp;+&nbsp;index</tt>
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on <tt>index</tt> do not hold
+     */
+    public final char charAt(int index) {
+        return get(position() + checkIndex(index, 1));
+    }
+
+    /**
+     * Creates a new character buffer that represents the specified subsequence
+     * of this buffer, relative to the current position.
+     *
+     * <p> The new buffer will share this buffer's content; that is, if the
+     * content of this buffer is mutable then modifications to one buffer will
+     * cause the other to be modified.  The new buffer's capacity will be that
+     * of this buffer, its position will be
+     * <tt>position()</tt>&nbsp;+&nbsp;<tt>start</tt>, and its limit will be
+     * <tt>position()</tt>&nbsp;+&nbsp;<tt>end</tt>.  The new buffer will be
+     * direct if, and only if, this buffer is direct, and it will be read-only
+     * if, and only if, this buffer is read-only.  </p>
+     *
+     * @param  start
+     *         The index, relative to the current position, of the first
+     *         character in the subsequence; must be non-negative and no larger
+     *         than <tt>remaining()</tt>
+     *
+     * @param  end
+     *         The index, relative to the current position, of the character
+     *         following the last character in the subsequence; must be no
+     *         smaller than <tt>start</tt> and no larger than
+     *         <tt>remaining()</tt>
+     *
+     * @return  The new character buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on <tt>start</tt> and <tt>end</tt>
+     *          do not hold
+     */
+    public abstract CharBuffer subSequence(int start, int end);
+
+
+    // --- Methods to support Appendable ---
+
+    /**
+     * Appends the specified character sequence  to this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> An invocation of this method of the form <tt>dst.append(csq)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     dst.put(csq.toString()) </pre>
+     *
+     * <p> Depending on the specification of <tt>toString</tt> for the
+     * character sequence <tt>csq</tt>, the entire sequence may not be
+     * appended.  For instance, invoking the {@link CharBuffer#toString()
+     * toString} method of a character buffer will return a subsequence whose
+     * content depends upon the buffer's position and limit.
+     *
+     * @param  csq
+     *         The character sequence to append.  If <tt>csq</tt> is
+     *         <tt>null</tt>, then the four characters <tt>"null"</tt> are
+     *         appended to this character buffer.
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     *
+     * @since  1.5
+     */
+    public CharBuffer append(CharSequence csq) {
+        if (csq == null)
+            return put("null");
+        else
+            return put(csq.toString());
+    }
+
+    /**
+     * Appends a subsequence of the  specified character sequence  to this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> An invocation of this method of the form <tt>dst.append(csq, start,
+     * end)</tt> when <tt>csq</tt> is not <tt>null</tt>, behaves in exactly the
+     * same way as the invocation
+     *
+     * <pre>
+     *     dst.put(csq.subSequence(start, end).toString()) </pre>
+     *
+     * @param  csq
+     *         The character sequence from which a subsequence will be
+     *         appended.  If <tt>csq</tt> is <tt>null</tt>, then characters
+     *         will be appended as if <tt>csq</tt> contained the four
+     *         characters <tt>"null"</tt>.
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt>
+     *          is greater than <tt>end</tt>, or <tt>end</tt> is greater than
+     *          <tt>csq.length()</tt>
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     *
+     * @since  1.5
+     */
+    public CharBuffer append(CharSequence csq, int start, int end) {
+        CharSequence cs = (csq == null ? "null" : csq);
+        return put(cs.subSequence(start, end).toString());
+    }
+
+    /**
+     * Appends the specified char  to this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> An invocation of this method of the form <tt>dst.append(c)</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     dst.put(c) </pre>
+     *
+     * @param  c
+     *         The 16-bit char to append
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     *
+     * @since  1.5
+     */
+    public CharBuffer append(char c) {
+        return put(c);
+    }
+
+
+    // -- Other byte stuff: Access to binary data --
+
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order of a char buffer created by allocation or by
+     * wrapping an existing <tt>char</tt> array is the {@link
+     * ByteOrder#nativeOrder native order} of the underlying
+     * hardware.  The byte order of a char buffer created as a <a
+     * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the
+     * byte buffer at the moment that the view is created.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public abstract ByteOrder order();
+
+    @Override
+    public IntStream chars() {
+        return StreamSupport.intStream(() -> new CharBufferSpliterator(this),
+            Buffer.SPLITERATOR_CHARACTERISTICS, false);
+    }
+}
diff --git a/java/nio/CharBufferSpliterator.java b/java/nio/CharBufferSpliterator.java
new file mode 100644
index 0000000..5b3977a
--- /dev/null
+++ b/java/nio/CharBufferSpliterator.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import java.util.Comparator;
+import java.util.Spliterator;
+import java.util.function.IntConsumer;
+
+/**
+ * A Spliterator.OfInt for sources that traverse and split elements
+ * maintained in a CharBuffer.
+ *
+ * @implNote
+ * The implementation is based on the code for the Array-based spliterators.
+ */
+class CharBufferSpliterator implements Spliterator.OfInt {
+    private final CharBuffer buffer;
+    private int index;   // current index, modified on advance/split
+    private final int limit;
+
+    CharBufferSpliterator(CharBuffer buffer) {
+        this(buffer, buffer.position(), buffer.limit());
+    }
+
+    CharBufferSpliterator(CharBuffer buffer, int origin, int limit) {
+        assert origin <= limit;
+        this.buffer = buffer;
+        this.index = (origin <= limit) ? origin : limit;
+        this.limit = limit;
+    }
+
+    @Override
+    public OfInt trySplit() {
+        int lo = index, mid = (lo + limit) >>> 1;
+        return (lo >= mid)
+               ? null
+               : new CharBufferSpliterator(buffer, lo, index = mid);
+    }
+
+    @Override
+    public void forEachRemaining(IntConsumer action) {
+        if (action == null)
+            throw new NullPointerException();
+        CharBuffer cb = buffer;
+        int i = index;
+        int hi = limit;
+        index = hi;
+        while (i < hi) {
+            action.accept(cb.getUnchecked(i++));
+        }
+    }
+
+    @Override
+    public boolean tryAdvance(IntConsumer action) {
+        if (action == null)
+            throw new NullPointerException();
+        if (index >= 0 && index < limit) {
+            action.accept(buffer.getUnchecked(index++));
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public long estimateSize() {
+        return (long)(limit - index);
+    }
+
+    @Override
+    public int characteristics() {
+        return Buffer.SPLITERATOR_CHARACTERISTICS;
+    }
+}
diff --git a/java/nio/DirectByteBuffer.annotated.java b/java/nio/DirectByteBuffer.annotated.java
new file mode 100644
index 0000000..51e0e9c
--- /dev/null
+++ b/java/nio/DirectByteBuffer.annotated.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.nio;
+
+
[email protected]
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class DirectByteBuffer extends java.nio.MappedByteBuffer implements sun.nio.ch.DirectBuffer {
+
[email protected]
+public DirectByteBuffer(int cap, long addr, java.io.FileDescriptor fd, java.lang.Runnable unmapper, boolean isReadOnly) { super(0, 0, 0, 0); throw new RuntimeException("Stub!"); }
+
+public final java.lang.Object attachment() { throw new RuntimeException("Stub!"); }
+
+public final sun.misc.Cleaner cleaner() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer slice() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer duplicate() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer asReadOnlyBuffer() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public final long address() { throw new RuntimeException("Stub!"); }
+
+public final byte get() { throw new RuntimeException("Stub!"); }
+
+public final byte get(int i) { throw new RuntimeException("Stub!"); }
+
+public java.nio.ByteBuffer get(byte[] dst, int dstOffset, int length) { throw new RuntimeException("Stub!"); }
+
+public java.nio.ByteBuffer put(java.nio.ByteBuffer src) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer put(byte x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer put(int i, byte x) { throw new RuntimeException("Stub!"); }
+
+public java.nio.ByteBuffer put(byte[] src, int srcOffset, int length) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer compact() { throw new RuntimeException("Stub!"); }
+
+public final boolean isDirect() { throw new RuntimeException("Stub!"); }
+
+public final boolean isReadOnly() { throw new RuntimeException("Stub!"); }
+
+public final char getChar() { throw new RuntimeException("Stub!"); }
+
+public final char getChar(int i) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putChar(char x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putChar(int i, char x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.CharBuffer asCharBuffer() { throw new RuntimeException("Stub!"); }
+
+public final short getShort() { throw new RuntimeException("Stub!"); }
+
+public final short getShort(int i) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putShort(short x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putShort(int i, short x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ShortBuffer asShortBuffer() { throw new RuntimeException("Stub!"); }
+
+public int getInt() { throw new RuntimeException("Stub!"); }
+
+public int getInt(int i) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putInt(int x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putInt(int i, int x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.IntBuffer asIntBuffer() { throw new RuntimeException("Stub!"); }
+
+public final long getLong() { throw new RuntimeException("Stub!"); }
+
+public final long getLong(int i) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putLong(long x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putLong(int i, long x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.LongBuffer asLongBuffer() { throw new RuntimeException("Stub!"); }
+
+public final float getFloat() { throw new RuntimeException("Stub!"); }
+
+public final float getFloat(int i) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putFloat(float x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putFloat(int i, float x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.FloatBuffer asFloatBuffer() { throw new RuntimeException("Stub!"); }
+
+public final double getDouble() { throw new RuntimeException("Stub!"); }
+
+public final double getDouble(int i) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putDouble(double x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.ByteBuffer putDouble(int i, double x) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.DoubleBuffer asDoubleBuffer() { throw new RuntimeException("Stub!"); }
+
+public final boolean isAccessible() { throw new RuntimeException("Stub!"); }
+
+public final void setAccessible(boolean value) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/nio/DirectByteBuffer.java b/java/nio/DirectByteBuffer.java
new file mode 100644
index 0000000..3e06011
--- /dev/null
+++ b/java/nio/DirectByteBuffer.java
@@ -0,0 +1,975 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import java.io.FileDescriptor;
+
+import dalvik.system.VMRuntime;
+import libcore.io.Memory;
+import sun.misc.Cleaner;
+import sun.nio.ch.DirectBuffer;
+
+// Not final because it is extended in tests.
+/** @hide */
+public class DirectByteBuffer extends MappedByteBuffer implements DirectBuffer {
+
+    /**
+     * Stores the details of the memory backing a DirectByteBuffer. This could be a pointer
+     * (passed through from JNI or resulting from a mapping) or a non-movable byte array allocated
+     * from Java. Each MemoryRef also has an isAccessible associated with it, which determines
+     * whether the underlying memory is "accessible". The notion of "accessibility" is usually
+     * defined by the allocator of the reference, and is separate from the accessibility of the
+     * memory as defined by the underlying system.
+     *
+     * A single MemoryRef instance is shared across all slices and duplicates of a given buffer.
+     */
+    final static class MemoryRef {
+        byte[] buffer;
+        long allocatedAddress;
+        final int offset;
+        boolean isAccessible;
+        boolean isFreed;
+
+
+        // Reference to original DirectByteBuffer that held this MemoryRef. The field is set
+        // only for the MemoryRef created through JNI NewDirectByteBuffer(void*, long) function.
+        // This allows users of JNI NewDirectByteBuffer to create a PhantomReference on the
+        // DirectByteBuffer instance that will only be put in the associated ReferenceQueue when
+        // the underlying memory is not referenced by any DirectByteBuffer instance. The
+        // MemoryRef can outlive the original DirectByteBuffer instance if, for example, slice()
+        // or asReadOnlyBuffer() are called and all strong references to the original DirectByteBuffer
+        // are discarded.
+        final Object originalBufferObject;
+
+        MemoryRef(int capacity) {
+            VMRuntime runtime = VMRuntime.getRuntime();
+            buffer = (byte[]) runtime.newNonMovableArray(byte.class, capacity + 7);
+            allocatedAddress = runtime.addressOf(buffer);
+            // Offset is set to handle the alignment: http://b/16449607
+            offset = (int) (((allocatedAddress + 7) & ~(long) 7) - allocatedAddress);
+            isAccessible = true;
+            isFreed = false;
+            originalBufferObject = null;
+        }
+
+        MemoryRef(long allocatedAddress, Object originalBufferObject) {
+            buffer = null;
+            this.allocatedAddress = allocatedAddress;
+            this.offset = 0;
+            this.originalBufferObject = originalBufferObject;
+            isAccessible = true;
+        }
+
+        void free() {
+            buffer = null;
+            allocatedAddress = 0;
+            isAccessible = false;
+            isFreed = true;
+        }
+    }
+
+    final Cleaner cleaner;
+    final MemoryRef memoryRef;
+
+    DirectByteBuffer(int capacity, MemoryRef memoryRef) {
+        super(-1, 0, capacity, capacity, memoryRef.buffer, memoryRef.offset);
+        // Only have references to java objects, no need for a cleaner since the GC will do all
+        // the work.
+        this.memoryRef = memoryRef;
+        this.address = memoryRef.allocatedAddress + memoryRef.offset;
+        cleaner = null;
+        this.isReadOnly = false;
+    }
+
+    // Invoked only by JNI: NewDirectByteBuffer(void*, long)
+    @SuppressWarnings("unused")
+    private DirectByteBuffer(long addr, int cap) {
+        super(-1, 0, cap, cap);
+        memoryRef = new MemoryRef(addr, this);
+        address = addr;
+        cleaner = null;
+    }
+
+    /** @hide */
+    public DirectByteBuffer(int cap, long addr,
+                            FileDescriptor fd,
+                            Runnable unmapper,
+                            boolean isReadOnly) {
+        super(-1, 0, cap, cap, fd);
+        this.isReadOnly = isReadOnly;
+        memoryRef = new MemoryRef(addr, null);
+        address = addr;
+        cleaner = Cleaner.create(memoryRef, unmapper);
+    }
+
+    // For duplicates and slices
+    DirectByteBuffer(MemoryRef memoryRef,         // package-private
+                     int mark, int pos, int lim, int cap,
+                     int off) {
+        this(memoryRef, mark, pos, lim, cap, off, false);
+    }
+
+    DirectByteBuffer(MemoryRef memoryRef,         // package-private
+                     int mark, int pos, int lim, int cap,
+                     int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, memoryRef.buffer, off);
+        this.isReadOnly = isReadOnly;
+        this.memoryRef = memoryRef;
+        address = memoryRef.allocatedAddress + off;
+        cleaner = null;
+    }
+
+    @Override
+    public final Object attachment() {
+        return memoryRef;
+    }
+
+    @Override
+    public final Cleaner cleaner() {
+        return cleaner;
+    }
+
+    @Override
+    public final ByteBuffer slice() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        int off = pos + offset;
+        assert (off >= 0);
+        return new DirectByteBuffer(memoryRef, -1, 0, rem, rem, off, isReadOnly);
+    }
+
+    @Override
+    public final ByteBuffer duplicate() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        return new DirectByteBuffer(memoryRef,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                isReadOnly);
+    }
+
+    @Override
+    public final ByteBuffer asReadOnlyBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        return new DirectByteBuffer(memoryRef,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                true);
+    }
+
+    @Override
+    public final long address() {
+        return address;
+    }
+
+    private long ix(int i) {
+        return address + i;
+    }
+
+    private byte get(long a) {
+        return Memory.peekByte(a);
+    }
+
+    @Override
+    public final byte get() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return get(ix(nextGetIndex()));
+    }
+
+    @Override
+    public final byte get(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return get(ix(checkIndex(i)));
+    }
+
+    // This method is not declared final because it is overridden in tests.
+    @Override
+    public ByteBuffer get(byte[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        checkBounds(dstOffset, length, dst.length);
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (length > rem)
+            throw new BufferUnderflowException();
+        Memory.peekByteArray(ix(pos),
+                dst, dstOffset, length);
+        position = pos + length;
+        return this;
+    }
+
+    private ByteBuffer put(long a, byte x) {
+        Memory.pokeByte(a, x);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer put(ByteBuffer src) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return super.put(src);
+    }
+
+    @Override
+    public final ByteBuffer put(byte x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        put(ix(nextPutIndex()), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer put(int i, byte x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        put(ix(checkIndex(i)), x);
+        return this;
+    }
+
+    // This method is not declared final because it is overridden in tests.
+    @Override
+    public ByteBuffer put(byte[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(srcOffset, length, src.length);
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (length > rem)
+            throw new BufferOverflowException();
+        Memory.pokeByteArray(ix(pos),
+                src, srcOffset, length);
+        position = pos + length;
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer compact() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        int pos = position();
+        int lim = limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        System.arraycopy(hb, position + offset, hb, offset, remaining());
+        position(rem);
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    @Override
+    public final boolean isDirect() {
+        return true;
+    }
+
+    @Override
+    public final boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    // Used by java.nio.Bits
+    @Override
+    final byte _get(int i) {                          // package-private
+        return get(i);
+    }
+
+    // Used by java.nio.Bits
+    @Override
+    final void _put(int i, byte b) {                  // package-private
+        put(i, b);
+    }
+
+    @Override
+    public final char getChar() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        int newPosition = position + Character.BYTES;
+        if (newPosition > limit()) {
+            throw new BufferUnderflowException();
+        }
+        char x = (char) Memory.peekShort(ix(position), !nativeByteOrder);
+        position = newPosition;
+        return x;
+    }
+
+    @Override
+    public final char getChar(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        checkIndex(i, Character.BYTES);
+        return (char) Memory.peekShort(ix(i), !nativeByteOrder);
+    }
+
+    @Override
+    char getCharUnchecked(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return (char) Memory.peekShort(ix(i), !nativeByteOrder);
+    }
+
+    @Override
+    void getUnchecked(int pos, char[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.peekCharArray(ix(pos),
+                dst, dstOffset, length, !nativeByteOrder);
+    }
+
+    private ByteBuffer putChar(long a, char x) {
+        Memory.pokeShort(a, (short) x, !nativeByteOrder);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putChar(char x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putChar(ix(nextPutIndex(Character.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putChar(int i, char x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putChar(ix(checkIndex(i, Character.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    void putCharUnchecked(int i, char x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        putChar(ix(i), x);
+    }
+
+    @Override
+    void putUnchecked(int pos, char[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.pokeCharArray(ix(pos),
+                src, srcOffset, length, !nativeByteOrder);
+    }
+
+    @Override
+    public final CharBuffer asCharBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        int off = this.position();
+        int lim = this.limit();
+        assert (off <= lim);
+        int rem = (off <= lim ? lim - off : 0);
+        int size = rem >> 1;
+        return new ByteBufferAsCharBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    private short getShort(long a) {
+        return Memory.peekShort(a, !nativeByteOrder);
+    }
+
+    @Override
+    public final short getShort() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getShort(ix(nextGetIndex(Short.BYTES)));
+    }
+
+    @Override
+    public final short getShort(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getShort(ix(checkIndex(i, Short.BYTES)));
+    }
+
+    @Override
+    short getShortUnchecked(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getShort(ix(i));
+    }
+
+    @Override
+    void getUnchecked(int pos, short[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.peekShortArray(ix(pos),
+                dst, dstOffset, length, !nativeByteOrder);
+    }
+
+    private ByteBuffer putShort(long a, short x) {
+        Memory.pokeShort(a, x, !nativeByteOrder);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putShort(short x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putShort(ix(nextPutIndex(Short.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putShort(int i, short x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putShort(ix(checkIndex(i, Short.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    void putShortUnchecked(int i, short x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        putShort(ix(i), x);
+    }
+
+    @Override
+    void putUnchecked(int pos, short[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.pokeShortArray(ix(pos),
+                src, srcOffset, length, !nativeByteOrder);
+    }
+
+    @Override
+    public final ShortBuffer asShortBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        int off = this.position();
+        int lim = this.limit();
+        assert (off <= lim);
+        int rem = (off <= lim ? lim - off : 0);
+        int size = rem >> 1;
+        return new ByteBufferAsShortBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    private int getInt(long a) {
+        return Memory.peekInt(a, !nativeByteOrder);
+    }
+
+    @Override
+    public int getInt() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getInt(ix(nextGetIndex(Integer.BYTES)));
+    }
+
+    @Override
+    public int getInt(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getInt(ix(checkIndex(i, (Integer.BYTES))));
+    }
+
+    @Override
+    final int getIntUnchecked(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getInt(ix(i));
+    }
+
+    @Override
+    final void getUnchecked(int pos, int[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.peekIntArray(ix(pos),
+                dst, dstOffset, length, !nativeByteOrder);
+    }
+
+    private ByteBuffer putInt(long a, int x) {
+        Memory.pokeInt(a, x, !nativeByteOrder);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putInt(int x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putInt(ix(nextPutIndex(Integer.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putInt(int i, int x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putInt(ix(checkIndex(i, Integer.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    final void putIntUnchecked(int i, int x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        putInt(ix(i), x);
+    }
+
+    @Override
+    final void putUnchecked(int pos, int[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.pokeIntArray(ix(pos),
+                src, srcOffset, length, !nativeByteOrder);
+    }
+
+    @Override
+    public final IntBuffer asIntBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        int off = this.position();
+        int lim = this.limit();
+        assert (off <= lim);
+        int rem = (off <= lim ? lim - off : 0);
+        int size = rem >> 2;
+        return new ByteBufferAsIntBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    private long getLong(long a) {
+        return Memory.peekLong(a, !nativeByteOrder);
+    }
+
+    @Override
+    public final long getLong() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getLong(ix(nextGetIndex(Long.BYTES)));
+    }
+
+    @Override
+    public final long getLong(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getLong(ix(checkIndex(i, Long.BYTES)));
+    }
+
+    @Override
+    final long getLongUnchecked(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getLong(ix(i));
+    }
+
+    @Override
+    final void getUnchecked(int pos, long[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.peekLongArray(ix(pos),
+                dst, dstOffset, length, !nativeByteOrder);
+    }
+
+    private ByteBuffer putLong(long a, long x) {
+        Memory.pokeLong(a, x, !nativeByteOrder);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putLong(long x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putLong(ix(nextPutIndex(Long.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putLong(int i, long x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putLong(ix(checkIndex(i, Long.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    final void putLongUnchecked(int i, long x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        putLong(ix(i), x);
+    }
+
+    @Override
+    final void putUnchecked(int pos, long[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.pokeLongArray(ix(pos),
+                src, srcOffset, length, !nativeByteOrder);
+    }
+
+    @Override
+    public final LongBuffer asLongBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        int off = this.position();
+        int lim = this.limit();
+        assert (off <= lim);
+        int rem = (off <= lim ? lim - off : 0);
+        int size = rem >> 3;
+        return new ByteBufferAsLongBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    private float getFloat(long a) {
+        int x = Memory.peekInt(a, !nativeByteOrder);
+        return Float.intBitsToFloat(x);
+    }
+
+    @Override
+    public final float getFloat() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getFloat(ix(nextGetIndex(Float.BYTES)));
+    }
+
+    @Override
+    public final float getFloat(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getFloat(ix(checkIndex(i, Float.BYTES)));
+    }
+
+    @Override
+    final float getFloatUnchecked(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getFloat(ix(i));
+    }
+
+    @Override
+    final void getUnchecked(int pos, float[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.peekFloatArray(ix(pos),
+                dst, dstOffset, length, !nativeByteOrder);
+    }
+
+    private ByteBuffer putFloat(long a, float x) {
+        int y = Float.floatToRawIntBits(x);
+        Memory.pokeInt(a, y, !nativeByteOrder);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putFloat(float x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putFloat(ix(nextPutIndex(Float.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putFloat(int i, float x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putFloat(ix(checkIndex(i, Float.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    final void putFloatUnchecked(int i, float x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        putFloat(ix(i), x);
+    }
+
+    @Override
+    final void putUnchecked(int pos, float[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.pokeFloatArray(ix(pos),
+                src, srcOffset, length, !nativeByteOrder);
+    }
+
+    @Override
+    public final FloatBuffer asFloatBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        int off = this.position();
+        int lim = this.limit();
+        assert (off <= lim);
+        int rem = (off <= lim ? lim - off : 0);
+        int size = rem >> 2;
+        return new ByteBufferAsFloatBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    private double getDouble(long a) {
+        long x = Memory.peekLong(a, !nativeByteOrder);
+        return Double.longBitsToDouble(x);
+    }
+
+    @Override
+    public final double getDouble() {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getDouble(ix(nextGetIndex(Double.BYTES)));
+    }
+
+    @Override
+    public final double getDouble(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getDouble(ix(checkIndex(i, Double.BYTES)));
+    }
+
+    @Override
+    final double getDoubleUnchecked(int i) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        return getDouble(ix(i));
+    }
+
+    @Override
+    final void getUnchecked(int pos, double[] dst, int dstOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.peekDoubleArray(ix(pos),
+                dst, dstOffset, length, !nativeByteOrder);
+    }
+
+    private ByteBuffer putDouble(long a, double x) {
+        long y = Double.doubleToRawLongBits(x);
+        Memory.pokeLong(a, y, !nativeByteOrder);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putDouble(double x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putDouble(ix(nextPutIndex(Double.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    public final ByteBuffer putDouble(int i, double x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        putDouble(ix(checkIndex(i, Double.BYTES)), x);
+        return this;
+    }
+
+    @Override
+    final void putDoubleUnchecked(int i, double x) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        putDouble(ix(i), x);
+    }
+
+    @Override
+    final void putUnchecked(int pos, double[] src, int srcOffset, int length) {
+        if (!memoryRef.isAccessible) {
+            throw new IllegalStateException("buffer is inaccessible");
+        }
+        Memory.pokeDoubleArray(ix(pos),
+                src, srcOffset, length, !nativeByteOrder);
+    }
+
+    @Override
+    public final DoubleBuffer asDoubleBuffer() {
+        if (memoryRef.isFreed) {
+            throw new IllegalStateException("buffer has been freed");
+        }
+        int off = this.position();
+        int lim = this.limit();
+        assert (off <= lim);
+        int rem = (off <= lim ? lim - off : 0);
+
+        int size = rem >> 3;
+        return new ByteBufferAsDoubleBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    @Override
+    public final boolean isAccessible() {
+        return memoryRef.isAccessible;
+    }
+
+    @Override
+    public final void setAccessible(boolean value) {
+        memoryRef.isAccessible = value;
+    }
+}
diff --git a/java/nio/DoubleBuffer.java b/java/nio/DoubleBuffer.java
new file mode 100644
index 0000000..bd80f4d
--- /dev/null
+++ b/java/nio/DoubleBuffer.java
@@ -0,0 +1,873 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+/**
+ * A double buffer.
+ *
+ * <p> This class defines four categories of operations upon
+ * double buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(double) <i>put</i>} methods that read and write
+ *   single doubles; </p></li>
+ *
+ *   <li><p> Relative {@link #get(double[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of doubles from this buffer
+ *   into an array; and</p></li>
+ *
+ *   <li><p> Relative {@link #put(double[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of doubles from a
+ *   double array or some other double
+ *   buffer into this buffer;&#32;and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   a double buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Double buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, by {@link #wrap(double[]) <i>wrapping</i>} an existing
+ * double array  into a buffer, or by creating a
+ * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer.
+ *
+ *
+*
+ *
+ * <p> Like a byte buffer, a double buffer is either <a
+ * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>.  A
+ * double buffer created via the <tt>wrap</tt> methods of this class will
+ * be non-direct.  A double buffer created as a view of a byte buffer will
+ * be direct if, and only if, the byte buffer itself is direct.  Whether or not
+ * a double buffer is direct may be determined by invoking the {@link
+ * #isDirect isDirect} method.  </p>
+ *
+*
+ *
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class DoubleBuffer
+    extends Buffer
+    implements Comparable<DoubleBuffer>
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final double[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    DoubleBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 double[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 3 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    DoubleBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new double buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in doubles
+     *
+     * @return  The new double buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static DoubleBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapDoubleBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps a double array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given double array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new double buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static DoubleBuffer wrap(double[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapDoubleBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a double array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given double array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new double buffer
+     */
+    public static DoubleBuffer wrap(double[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Creates a new double buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of doubles remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new double buffer
+     */
+    public abstract DoubleBuffer slice();
+
+    /**
+     * Creates a new double buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new double buffer
+     */
+    public abstract DoubleBuffer duplicate();
+
+    /**
+     * Creates a new, read-only double buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only double buffer
+     */
+    public abstract DoubleBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the double at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The double at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract double get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given double into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  d
+     *         The double to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract DoubleBuffer put(double d);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the double at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the double will be read
+     *
+     * @return  The double at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract double get(int index);
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given double into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the double will be written
+     *
+     * @param  d
+     *         The double value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract DoubleBuffer put(int index, double d);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers doubles from this buffer into the given
+     * destination array.  If there are fewer doubles remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * doubles are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> doubles from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient doubles in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which doubles are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first double to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of doubles to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> doubles
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public DoubleBuffer get(double[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers doubles from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> doubles
+     *          remaining in this buffer
+     */
+    public DoubleBuffer get(double[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the doubles remaining in the given source
+     * buffer into this buffer.  If there are more doubles remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no doubles are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> doubles from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which doubles are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining doubles in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public DoubleBuffer put(DoubleBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers doubles into this buffer from the given
+     * source array.  If there are more doubles to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * doubles are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> doubles from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which doubles are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first double to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of doubles to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public DoubleBuffer put(double[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * double array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final DoubleBuffer put(double[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible double
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the double array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final double[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = DoubleBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The doubles between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * double at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the double at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the double at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of doubles copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract DoubleBuffer compact();
+
+    /**
+     * Tells whether or not this double buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns a string summarizing the state of this buffer.
+     *
+     * @return  A summary string
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getName());
+        sb.append("[pos=");
+        sb.append(position());
+        sb.append(" lim=");
+        sb.append(limit());
+        sb.append(" cap=");
+        sb.append(capacity());
+        sb.append("]");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a double buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int) get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two double buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+
+     *   This method considers two double elements {@code a} and {@code b}
+     *   to be equal if
+     *   {@code (a == b) || (Double.isNaN(a) && Double.isNaN(b))}.
+     *   The values {@code -0.0} and {@code +0.0} are considered to be
+     *   equal, unlike {@link Double#equals(Object)}.
+
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A double buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof DoubleBuffer))
+            return false;
+        DoubleBuffer that = (DoubleBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(double x, double y) {
+
+        return (x == y) || (Double.isNaN(x) && Double.isNaN(y));
+
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two double buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+
+     * Pairs of {@code double} elements are compared as if by invoking
+     * {@link Double#compare(double,double)}, except that
+     * {@code -0.0} and {@code 0.0} are considered to be equal.
+     * {@code Double.NaN} is considered by this method to be equal
+     * to itself and greater than all other {@code double} values
+     * (including {@code Double.POSITIVE_INFINITY}).
+
+     *
+     * <p> A double buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(DoubleBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(double x, double y) {
+
+        return ((x < y)  ? -1 :
+                (x > y)  ? +1 :
+                (x == y) ?  0 :
+                Double.isNaN(x) ? (Double.isNaN(y) ? 0 : +1) : -1);
+
+    }
+
+    // -- Other char stuff --
+
+
+    // -- Other byte stuff: Access to binary data --
+
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order of a double buffer created by allocation or by
+     * wrapping an existing <tt>double</tt> array is the {@link
+     * ByteOrder#nativeOrder native order} of the underlying
+     * hardware.  The byte order of a double buffer created as a <a
+     * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the
+     * byte buffer at the moment that the view is created.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public abstract ByteOrder order();
+
+
+}
diff --git a/java/nio/FloatBuffer.java b/java/nio/FloatBuffer.java
new file mode 100644
index 0000000..3d34211
--- /dev/null
+++ b/java/nio/FloatBuffer.java
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+/**
+ * A float buffer.
+ *
+ * <p> This class defines four categories of operations upon
+ * float buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(float) <i>put</i>} methods that read and write
+ *   single floats; </p></li>
+ *
+ *   <li><p> Relative {@link #get(float[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of floats from this buffer
+ *   into an array; and</p></li>
+ *
+ *   <li><p> Relative {@link #put(float[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of floats from a
+ *   float array or some other float
+ *   buffer into this buffer;&#32;and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   a float buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Float buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, by {@link #wrap(float[]) <i>wrapping</i>} an existing
+ * float array  into a buffer, or by creating a
+ * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer.
+ *
+ *
+*
+ *
+ * <p> Like a byte buffer, a float buffer is either <a
+ * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>.  A
+ * float buffer created via the <tt>wrap</tt> methods of this class will
+ * be non-direct.  A float buffer created as a view of a byte buffer will
+ * be direct if, and only if, the byte buffer itself is direct.  Whether or not
+ * a float buffer is direct may be determined by invoking the {@link
+ * #isDirect isDirect} method.  </p>
+ *
+*
+ *
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class FloatBuffer
+    extends Buffer
+    implements Comparable<FloatBuffer>
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final float[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    FloatBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 float[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 2 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    FloatBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new float buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in floats
+     *
+     * @return  The new float buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static FloatBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapFloatBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps a float array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given float array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new float buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static FloatBuffer wrap(float[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapFloatBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a float array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given float array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new float buffer
+     */
+    public static FloatBuffer wrap(float[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Creates a new float buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of floats remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new float buffer
+     */
+    public abstract FloatBuffer slice();
+
+    /**
+     * Creates a new float buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new float buffer
+     */
+    public abstract FloatBuffer duplicate();
+
+    /**
+     * Creates a new, read-only float buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only float buffer
+     */
+    public abstract FloatBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the float at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The float at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract float get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given float into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  f
+     *         The float to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract FloatBuffer put(float f);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the float at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the float will be read
+     *
+     * @return  The float at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract float get(int index);
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given float into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the float will be written
+     *
+     * @param  f
+     *         The float value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract FloatBuffer put(int index, float f);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers floats from this buffer into the given
+     * destination array.  If there are fewer floats remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * floats are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> floats from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient floats in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which floats are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first float to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of floats to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> floats
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public FloatBuffer get(float[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers floats from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> floats
+     *          remaining in this buffer
+     */
+    public FloatBuffer get(float[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the floats remaining in the given source
+     * buffer into this buffer.  If there are more floats remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no floats are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> floats from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which floats are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining floats in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public FloatBuffer put(FloatBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers floats into this buffer from the given
+     * source array.  If there are more floats to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * floats are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> floats from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which floats are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first float to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of floats to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public FloatBuffer put(float[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * float array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final FloatBuffer put(float[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible float
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the float array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final float[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = FloatBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The floats between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * float at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the float at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the float at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of floats copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract FloatBuffer compact();
+
+    /**
+     * Tells whether or not this float buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns a string summarizing the state of this buffer.
+     *
+     * @return  A summary string
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getName());
+        sb.append("[pos=");
+        sb.append(position());
+        sb.append(" lim=");
+        sb.append(limit());
+        sb.append(" cap=");
+        sb.append(capacity());
+        sb.append("]");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a float buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int) get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two float buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+
+     *   This method considers two float elements {@code a} and {@code b}
+     *   to be equal if
+     *   {@code (a == b) || (Float.isNaN(a) && Float.isNaN(b))}.
+     *   The values {@code -0.0} and {@code +0.0} are considered to be
+     *   equal, unlike {@link Float#equals(Object)}.
+
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A float buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof FloatBuffer))
+            return false;
+        FloatBuffer that = (FloatBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(float x, float y) {
+
+        return (x == y) || (Float.isNaN(x) && Float.isNaN(y));
+
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two float buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+
+     * Pairs of {@code float} elements are compared as if by invoking
+     * {@link Float#compare(float,float)}, except that
+     * {@code -0.0} and {@code 0.0} are considered to be equal.
+     * {@code Float.NaN} is considered by this method to be equal
+     * to itself and greater than all other {@code float} values
+     * (including {@code Float.POSITIVE_INFINITY}).
+     *
+     *
+     *
+     *
+     *
+     * <p> A float buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(FloatBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(float x, float y) {
+
+        return ((x < y)  ? -1 :
+                (x > y)  ? +1 :
+                (x == y) ?  0 :
+                Float.isNaN(x) ? (Float.isNaN(y) ? 0 : +1) : -1);
+
+    }
+
+    // -- Other char stuff --
+
+    // -- Other byte stuff: Access to binary data --
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order of a float buffer created by allocation or by
+     * wrapping an existing <tt>float</tt> array is the {@link
+     * ByteOrder#nativeOrder native order} of the underlying
+     * hardware.  The byte order of a float buffer created as a <a
+     * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the
+     * byte buffer at the moment that the view is created.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public abstract ByteOrder order();
+
+
+}
diff --git a/java/nio/HeapByteBuffer.java b/java/nio/HeapByteBuffer.java
new file mode 100644
index 0000000..4666638
--- /dev/null
+++ b/java/nio/HeapByteBuffer.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.nio;
+
+
+import libcore.io.Memory;
+
+/**
+ * A read/write HeapByteBuffer.
+ */
+
+final class HeapByteBuffer extends ByteBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final byte[] hb;
+      protected final int offset;
+
+    */
+
+    HeapByteBuffer(int cap, int lim) {            // packag-private
+        this(cap, lim, false);
+    }
+
+
+    private HeapByteBuffer(int cap, int lim, boolean isReadOnly) {
+        super(-1, 0, lim, cap, new byte[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapByteBuffer(byte[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    private HeapByteBuffer(byte[] buf, int off, int len, boolean isReadOnly) {
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    private HeapByteBuffer(byte[] buf, int mark, int pos, int lim, int cap, int off,
+            boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+    @Override
+    public ByteBuffer slice() {
+        return new HeapByteBuffer(hb,
+                -1,
+                0,
+                remaining(),
+                remaining(),
+                position() + offset,
+                isReadOnly);
+    }
+
+    @Override
+    public ByteBuffer duplicate() {
+        return new HeapByteBuffer(hb,
+                markValue(),
+                position(),
+                limit(),
+                capacity(),
+                offset,
+                isReadOnly);
+    }
+
+    @Override
+    public ByteBuffer asReadOnlyBuffer() {
+        return new HeapByteBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset, true);
+    }
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    @Override
+    public byte get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    @Override
+    public byte get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    @Override
+    public ByteBuffer get(byte[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    @Override
+    public boolean isDirect() {
+        return false;
+    }
+
+    @Override
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    @Override
+    public ByteBuffer put(byte x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    @Override
+    public ByteBuffer put(int i, byte x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    @Override
+    public ByteBuffer put(byte[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    @Override
+    byte _get(int i) {                          // package-private
+        return hb[i];
+    }
+
+    @Override
+    void _put(int i, byte b) {                  // package-private
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[i] = b;
+    }
+
+    @Override
+    public char getChar() {
+        return Bits.getChar(this, ix(nextGetIndex(2)), bigEndian);
+    }
+
+    @Override
+    public char getChar(int i) {
+        return Bits.getChar(this, ix(checkIndex(i, 2)), bigEndian);
+    }
+
+    @Override
+    char getCharUnchecked(int i) {
+        return Bits.getChar(this, ix(i), bigEndian);
+    }
+
+    @Override
+    void getUnchecked(int pos, char[] dst, int dstOffset, int length) {
+        Memory.unsafeBulkGet(dst, dstOffset, length * 2, hb, ix(pos), 2, !nativeByteOrder);
+    }
+
+    @Override
+    public ByteBuffer putChar(char x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer putChar(int i, char x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putChar(this, ix(checkIndex(i, 2)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    void putCharUnchecked(int i, char x) {
+        Bits.putChar(this, ix(i), x, bigEndian);
+    }
+
+    @Override
+    void putUnchecked(int pos, char[] src, int srcOffset, int length) {
+        Memory.unsafeBulkPut(hb, ix(pos), length * 2, src, srcOffset, 2, !nativeByteOrder);
+    }
+
+    @Override
+    public CharBuffer asCharBuffer() {
+        int size = this.remaining() >> 1;
+        int off = position();
+        return new ByteBufferAsCharBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    @Override
+    public short getShort() {
+        return Bits.getShort(this, ix(nextGetIndex(2)), bigEndian);
+    }
+
+    @Override
+    public short getShort(int i) {
+        return Bits.getShort(this, ix(checkIndex(i, 2)), bigEndian);
+    }
+
+    @Override
+    short getShortUnchecked(int i) {
+        return Bits.getShort(this, ix(i), bigEndian);
+    }
+
+    @Override
+    void getUnchecked(int pos, short[] dst, int dstOffset, int length) {
+        Memory.unsafeBulkGet(dst, dstOffset, length * 2, hb, ix(pos), 2, !nativeByteOrder);
+    }
+
+    @Override
+    public ByteBuffer putShort(short x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putShort(this, ix(nextPutIndex(2)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer putShort(int i, short x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putShort(this, ix(checkIndex(i, 2)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    void putShortUnchecked(int i, short x) {
+        Bits.putShort(this, ix(i), x, bigEndian);
+    }
+
+    @Override
+    void putUnchecked(int pos, short[] src, int srcOffset, int length) {
+        Memory.unsafeBulkPut(hb, ix(pos), length * 2, src, srcOffset, 2, !nativeByteOrder);
+    }
+
+    @Override
+    public ShortBuffer asShortBuffer() {
+        int size = this.remaining() >> 1;
+        int off = position();
+        return new ByteBufferAsShortBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    @Override
+    public int getInt() {
+        return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian);
+    }
+
+    @Override
+    public int getInt(int i) {
+        return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian);
+    }
+
+    @Override
+    int getIntUnchecked(int i) {
+        return Bits.getInt(this, ix(i), bigEndian);
+    }
+
+    @Override
+    void getUnchecked(int pos, int[] dst, int dstOffset, int length) {
+        Memory.unsafeBulkGet(dst, dstOffset, length * 4, hb, ix(pos), 4, !nativeByteOrder);
+    }
+
+    @Override
+    public ByteBuffer putInt(int x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer putInt(int i, int x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putInt(this, ix(checkIndex(i, 4)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    void putIntUnchecked(int i, int x) {
+        Bits.putInt(this, ix(i), x, bigEndian);
+    }
+
+    @Override
+    void putUnchecked(int pos, int[] src, int srcOffset, int length) {
+        Memory.unsafeBulkPut(hb, ix(pos), length * 4, src, srcOffset, 4, !nativeByteOrder);
+    }
+
+    @Override
+    public IntBuffer asIntBuffer() {
+        int size = this.remaining() >> 2;
+        int off = position();
+
+        return new ByteBufferAsIntBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    @Override
+    public long getLong() {
+        return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian);
+    }
+
+    @Override
+    public long getLong(int i) {
+        return Bits.getLong(this, ix(checkIndex(i, 8)), bigEndian);
+    }
+
+    @Override
+    long getLongUnchecked(int i) {
+        return Bits.getLong(this, ix(i), bigEndian);
+    }
+
+    @Override
+    void getUnchecked(int pos, long[] dst, int dstOffset, int length) {
+        Memory.unsafeBulkGet(dst, dstOffset, length * 8, hb, ix(pos), 8, !nativeByteOrder);
+    }
+
+    @Override
+    public ByteBuffer putLong(long x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putLong(this, ix(nextPutIndex(8)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer putLong(int i, long x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putLong(this, ix(checkIndex(i, 8)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    void putLongUnchecked(int i, long x) {
+        Bits.putLong(this, ix(i), x, bigEndian);
+    }
+
+    @Override
+    void putUnchecked(int pos, long[] src, int srcOffset, int length) {
+        Memory.unsafeBulkPut(hb, ix(pos), length * 8, src, srcOffset, 8, !nativeByteOrder);
+    }
+
+    @Override
+    public LongBuffer asLongBuffer() {
+        int size = this.remaining() >> 3;
+        int off = position();
+        return new ByteBufferAsLongBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    @Override
+    public float getFloat() {
+        return Bits.getFloat(this, ix(nextGetIndex(4)), bigEndian);
+    }
+
+    @Override
+    public float getFloat(int i) {
+        return Bits.getFloat(this, ix(checkIndex(i, 4)), bigEndian);
+    }
+
+    @Override
+    float getFloatUnchecked(int i) {
+        return Bits.getFloat(this, ix(i), bigEndian);
+    }
+
+    @Override
+    void getUnchecked(int pos, float[] dst, int dstOffset, int length) {
+        Memory.unsafeBulkGet(dst, dstOffset, length * 4, hb, ix(pos), 4, !nativeByteOrder);
+    }
+
+    @Override
+    public ByteBuffer putFloat(float x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putFloat(this, ix(nextPutIndex(4)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer putFloat(int i, float x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putFloat(this, ix(checkIndex(i, 4)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    void putFloatUnchecked(int i, float x) {
+        Bits.putFloat(this, ix(i), x, bigEndian);
+    }
+
+    @Override
+    void putUnchecked(int pos, float[] src, int srcOffset, int length) {
+        Memory.unsafeBulkPut(hb, ix(pos), length * 4, src, srcOffset, 4, !nativeByteOrder);
+    }
+
+    @Override
+    public FloatBuffer asFloatBuffer() {
+        int size = this.remaining() >> 2;
+        int off = position();
+        return new ByteBufferAsFloatBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+
+    @Override
+    public double getDouble() {
+        return Bits.getDouble(this, ix(nextGetIndex(8)), bigEndian);
+    }
+
+    @Override
+    public double getDouble(int i) {
+        return Bits.getDouble(this, ix(checkIndex(i, 8)), bigEndian);
+    }
+
+    @Override
+    double getDoubleUnchecked(int i) {
+        return Bits.getDouble(this, ix(i), bigEndian);
+    }
+
+    @Override
+    void getUnchecked(int pos, double[] dst, int dstOffset, int length) {
+        Memory.unsafeBulkGet(dst, dstOffset, length * 8, hb, ix(pos), 8, !nativeByteOrder);
+    }
+
+    @Override
+    public ByteBuffer putDouble(double x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putDouble(this, ix(nextPutIndex(8)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    public ByteBuffer putDouble(int i, double x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        Bits.putDouble(this, ix(checkIndex(i, 8)), x, bigEndian);
+        return this;
+    }
+
+    @Override
+    void putDoubleUnchecked(int i, double x) {
+        Bits.putDouble(this, ix(i), x, bigEndian);
+    }
+
+    @Override
+    void putUnchecked(int pos, double[] src, int srcOffset, int length) {
+        Memory.unsafeBulkPut(hb, ix(pos), length * 8, src, srcOffset, 8, !nativeByteOrder);
+    }
+
+    @Override
+    public DoubleBuffer asDoubleBuffer() {
+        int size = this.remaining() >> 3;
+        int off = position();
+        return new ByteBufferAsDoubleBuffer(this,
+                -1,
+                0,
+                size,
+                size,
+                off,
+                order());
+    }
+}
diff --git a/java/nio/HeapCharBuffer.java b/java/nio/HeapCharBuffer.java
new file mode 100644
index 0000000..fad4fa6
--- /dev/null
+++ b/java/nio/HeapCharBuffer.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+/**
+ * A read/write HeapCharBuffer.
+ */
+
+class HeapCharBuffer extends CharBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final char[] hb;
+      protected final int offset;
+
+    */
+
+    HeapCharBuffer(int cap, int lim) {            // package-private
+        this(cap, lim, false);
+    }
+
+    HeapCharBuffer(int cap, int lim, boolean isReadOnly) {            // package-private
+        super(-1, 0, lim, cap, new char[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapCharBuffer(char[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    HeapCharBuffer(char[] buf, int off, int len, boolean isReadOnly) { // package-private
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    protected HeapCharBuffer(char[] buf,
+                             int mark, int pos, int lim, int cap,
+                             int off) {
+        this(buf, mark, pos, lim, cap, off, false);
+    }
+
+    protected HeapCharBuffer(char[] buf,
+                             int mark, int pos, int lim, int cap,
+                             int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+    public CharBuffer slice() {
+        return new HeapCharBuffer(hb,
+                -1,
+                0,
+                this.remaining(),
+                this.remaining(),
+                this.position() + offset,
+                isReadOnly);
+    }
+
+    public CharBuffer duplicate() {
+        return new HeapCharBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                isReadOnly);
+    }
+
+    public CharBuffer asReadOnlyBuffer() {
+
+        return new HeapCharBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                true);
+    }
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    public char get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    public char get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    char getUnchecked(int i) {
+        return hb[ix(i)];
+    }
+
+    public CharBuffer get(char[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public CharBuffer put(char x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    public CharBuffer put(int i, char x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    public CharBuffer put(char[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    public CharBuffer put(CharBuffer src) {
+        if (src == this) {
+            throw new IllegalArgumentException();
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        if (src instanceof HeapCharBuffer) {
+            HeapCharBuffer sb = (HeapCharBuffer) src;
+            int n = sb.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            System.arraycopy(sb.hb, sb.ix(sb.position()),
+                    hb, ix(position()), n);
+            sb.position(sb.position() + n);
+            position(position() + n);
+        } else if (src.isDirect()) {
+            int n = src.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            src.get(hb, ix(position()), n);
+            position(position() + n);
+        } else {
+            super.put(src);
+        }
+        return this;
+    }
+
+    public CharBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    String toString(int start, int end) {               // package-private
+        try {
+            return new String(hb, start + offset, end - start);
+        } catch (StringIndexOutOfBoundsException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    public CharBuffer subSequence(int start, int end) {
+        if ((start < 0)
+                || (end > length())
+                || (start > end))
+            throw new IndexOutOfBoundsException();
+        int pos = position();
+        return new HeapCharBuffer(hb,
+                -1,
+                pos + start,
+                pos + end,
+                capacity(),
+                offset, isReadOnly);
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+}
diff --git a/java/nio/HeapDoubleBuffer.java b/java/nio/HeapDoubleBuffer.java
new file mode 100644
index 0000000..02634dd
--- /dev/null
+++ b/java/nio/HeapDoubleBuffer.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+/**
+ * A read/write HeapDoubleBuffer.
+ */
+
+class HeapDoubleBuffer extends DoubleBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final double[] hb;
+      protected final int offset;
+
+    */
+
+    HeapDoubleBuffer(int cap, int lim) {            // package-private
+        this(cap, lim, false);
+    }
+
+    HeapDoubleBuffer(double[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    protected HeapDoubleBuffer(double[] buf,
+                               int mark, int pos, int lim, int cap,
+                               int off) {
+        this(buf, mark, pos, lim, cap, off, false);
+    }
+
+    HeapDoubleBuffer(int cap, int lim, boolean isReadOnly) {            // package-private
+        super(-1, 0, lim, cap, new double[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapDoubleBuffer(double[] buf, int off, int len, boolean isReadOnly) { // package-private
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    protected HeapDoubleBuffer(double[] buf,
+                               int mark, int pos, int lim, int cap,
+                               int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+
+    public DoubleBuffer slice() {
+        return new HeapDoubleBuffer(hb,
+                                    -1,
+                                    0,
+                                    this.remaining(),
+                                    this.remaining(),
+                                    this.position() + offset,
+                                    isReadOnly);
+    }
+
+    public DoubleBuffer duplicate() {
+        return new HeapDoubleBuffer(hb,
+                                    this.markValue(),
+                                    this.position(),
+                                    this.limit(),
+                                    this.capacity(),
+                                    offset,
+                                    isReadOnly);
+    }
+
+    public DoubleBuffer asReadOnlyBuffer() {
+        return new HeapDoubleBuffer(hb,
+                                     this.markValue(),
+                                     this.position(),
+                                     this.limit(),
+                                     this.capacity(),
+                                     offset, true);
+    }
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    public double get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    public double get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    public DoubleBuffer get(double[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public DoubleBuffer put(double x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    public DoubleBuffer put(int i, double x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    public DoubleBuffer put(double[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    public DoubleBuffer put(DoubleBuffer src) {
+        if (src == this) {
+            throw new IllegalArgumentException();
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        if (src instanceof HeapDoubleBuffer) {
+            HeapDoubleBuffer sb = (HeapDoubleBuffer)src;
+            int n = sb.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            System.arraycopy(sb.hb, sb.ix(sb.position()),
+                             hb, ix(position()), n);
+            sb.position(sb.position() + n);
+            position(position() + n);
+        } else if (src.isDirect()) {
+            int n = src.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            src.get(hb, ix(position()), n);
+            position(position() + n);
+        } else {
+            super.put(src);
+        }
+        return this;
+    }
+
+    public DoubleBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+}
diff --git a/java/nio/HeapFloatBuffer.java b/java/nio/HeapFloatBuffer.java
new file mode 100644
index 0000000..42dd8ce
--- /dev/null
+++ b/java/nio/HeapFloatBuffer.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+/**
+ * A read/write HeapFloatBuffer.
+ */
+
+class HeapFloatBuffer extends FloatBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final float[] hb;
+      protected final int offset;
+
+    */
+
+    HeapFloatBuffer(int cap, int lim) {            // package-private
+        this(cap, lim, false);
+    }
+
+    HeapFloatBuffer(int cap, int lim, boolean isReadOnly) {            // package-private
+        super(-1, 0, lim, cap, new float[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapFloatBuffer(float[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    HeapFloatBuffer(float[] buf, int off, int len, boolean isReadOnly) { // package-private
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    protected HeapFloatBuffer(float[] buf,
+                              int mark, int pos, int lim, int cap,
+                              int off) {
+        this(buf, mark, pos, lim, cap, off, false);
+    }
+
+    protected HeapFloatBuffer(float[] buf,
+                              int mark, int pos, int lim, int cap,
+                              int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+    public FloatBuffer slice() {
+        return new HeapFloatBuffer(hb,
+                -1,
+                0,
+                this.remaining(),
+                this.remaining(),
+                this.position() + offset,
+                isReadOnly);
+    }
+
+    public FloatBuffer duplicate() {
+        return new HeapFloatBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                isReadOnly);
+    }
+
+    public FloatBuffer asReadOnlyBuffer() {
+        return new HeapFloatBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset, true);
+    }
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    public float get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    public float get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    public FloatBuffer get(float[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public FloatBuffer put(float x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    public FloatBuffer put(int i, float x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    public FloatBuffer put(float[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    public FloatBuffer put(FloatBuffer src) {
+        if (src == this) {
+            throw new IllegalArgumentException();
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        if (src instanceof HeapFloatBuffer) {
+            HeapFloatBuffer sb = (HeapFloatBuffer) src;
+            int n = sb.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            System.arraycopy(sb.hb, sb.ix(sb.position()),
+                    hb, ix(position()), n);
+            sb.position(sb.position() + n);
+            position(position() + n);
+        } else if (src.isDirect()) {
+            int n = src.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            src.get(hb, ix(position()), n);
+            position(position() + n);
+        } else {
+            super.put(src);
+        }
+        return this;
+    }
+
+    public FloatBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+}
diff --git a/java/nio/HeapIntBuffer.java b/java/nio/HeapIntBuffer.java
new file mode 100644
index 0000000..b4f3bf7
--- /dev/null
+++ b/java/nio/HeapIntBuffer.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+/**
+ * A read/write HeapIntBuffer.
+ */
+
+class HeapIntBuffer extends IntBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final int[] hb;
+      protected final int offset;
+
+    */
+
+    HeapIntBuffer(int cap, int lim) {            // package-private
+        this(cap, lim, false);
+    }
+
+    HeapIntBuffer(int cap, int lim, boolean isReadOnly) {            // package-private
+        super(-1, 0, lim, cap, new int[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapIntBuffer(int[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    HeapIntBuffer(int[] buf, int off, int len, boolean isReadOnly) { // package-private
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    protected HeapIntBuffer(int[] buf,
+                            int mark, int pos, int lim, int cap,
+                            int off) {
+        this(buf, mark, pos, lim, cap, off, false);
+    }
+
+    protected HeapIntBuffer(int[] buf,
+                            int mark, int pos, int lim, int cap,
+                            int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+    public IntBuffer slice() {
+        return new HeapIntBuffer(hb,
+                -1,
+                0,
+                this.remaining(),
+                this.remaining(),
+                this.position() + offset,
+                isReadOnly);
+    }
+
+    public IntBuffer duplicate() {
+        return new HeapIntBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                isReadOnly);
+    }
+
+    public IntBuffer asReadOnlyBuffer() {
+
+        return new HeapIntBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset, true);
+    }
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    public int get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    public int get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    public IntBuffer get(int[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public IntBuffer put(int x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    public IntBuffer put(int i, int x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    public IntBuffer put(int[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    public IntBuffer put(IntBuffer src) {
+        if (src == this) {
+            throw new IllegalArgumentException();
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        if (src instanceof HeapIntBuffer) {
+            HeapIntBuffer sb = (HeapIntBuffer) src;
+            int n = sb.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            System.arraycopy(sb.hb, sb.ix(sb.position()),
+                    hb, ix(position()), n);
+            sb.position(sb.position() + n);
+            position(position() + n);
+        } else if (src.isDirect()) {
+            int n = src.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            src.get(hb, ix(position()), n);
+            position(position() + n);
+        } else {
+            super.put(src);
+        }
+        return this;
+    }
+
+    public IntBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+}
diff --git a/java/nio/HeapLongBuffer.java b/java/nio/HeapLongBuffer.java
new file mode 100644
index 0000000..c0678b3
--- /dev/null
+++ b/java/nio/HeapLongBuffer.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+/**
+ * A read/write HeapLongBuffer.
+ */
+
+class HeapLongBuffer
+        extends LongBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final long[] hb;
+      protected final int offset;
+
+    */
+
+    HeapLongBuffer(int cap, int lim) {            // package-private
+        this(cap, lim, false);
+    }
+
+    HeapLongBuffer(int cap, int lim, boolean isReadOnly) {            // package-private
+        super(-1, 0, lim, cap, new long[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapLongBuffer(long[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    HeapLongBuffer(long[] buf, int off, int len, boolean isReadOnly) { // package-private
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    protected HeapLongBuffer(long[] buf,
+                             int mark, int pos, int lim, int cap,
+                             int off) {
+        this(buf, mark, pos, lim, cap, off, false);
+    }
+
+    protected HeapLongBuffer(long[] buf,
+                             int mark, int pos, int lim, int cap,
+                             int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+    public LongBuffer slice() {
+        return new HeapLongBuffer(hb,
+                -1,
+                0,
+                this.remaining(),
+                this.remaining(),
+                this.position() + offset,
+                isReadOnly);
+    }
+
+    public LongBuffer duplicate() {
+        return new HeapLongBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset,
+                isReadOnly);
+    }
+
+    public LongBuffer asReadOnlyBuffer() {
+        return new HeapLongBuffer(hb,
+                this.markValue(),
+                this.position(),
+                this.limit(),
+                this.capacity(),
+                offset, true);
+    }
+
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    public long get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    public long get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    public LongBuffer get(long[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public LongBuffer put(long x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    public LongBuffer put(int i, long x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    public LongBuffer put(long[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    public LongBuffer put(LongBuffer src) {
+        if (src == this) {
+            throw new IllegalArgumentException();
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        if (src instanceof HeapLongBuffer) {
+            HeapLongBuffer sb = (HeapLongBuffer) src;
+            int n = sb.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            System.arraycopy(sb.hb, sb.ix(sb.position()),
+                    hb, ix(position()), n);
+            sb.position(sb.position() + n);
+            position(position() + n);
+        } else if (src.isDirect()) {
+            int n = src.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            src.get(hb, ix(position()), n);
+            position(position() + n);
+        } else {
+            super.put(src);
+        }
+        return this;
+    }
+
+    public LongBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+}
diff --git a/java/nio/HeapShortBuffer.java b/java/nio/HeapShortBuffer.java
new file mode 100644
index 0000000..af39261
--- /dev/null
+++ b/java/nio/HeapShortBuffer.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+/**
+ * A read/write HeapShortBuffer.
+ */
+
+class HeapShortBuffer extends ShortBuffer {
+
+    // For speed these fields are actually declared in X-Buffer;
+    // these declarations are here as documentation
+    /*
+
+      protected final short[] hb;
+      protected final int offset;
+
+    */
+
+    HeapShortBuffer(int cap, int lim) {            // package-private
+        this(cap, lim, false);
+    }
+
+    HeapShortBuffer(int cap, int lim, boolean isReadOnly) {            // package-private
+        super(-1, 0, lim, cap, new short[cap], 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    HeapShortBuffer(short[] buf, int off, int len) { // package-private
+        this(buf, off, len, false);
+    }
+
+    HeapShortBuffer(short[] buf, int off, int len, boolean isReadOnly) { // package-private
+        super(-1, off, off + len, buf.length, buf, 0);
+        this.isReadOnly = isReadOnly;
+    }
+
+    protected HeapShortBuffer(short[] buf,
+                              int mark, int pos, int lim, int cap,
+                              int off) {
+        this(buf, mark, pos, lim, cap, off, false);
+    }
+
+    protected HeapShortBuffer(short[] buf,
+                              int mark, int pos, int lim, int cap,
+                              int off, boolean isReadOnly) {
+        super(mark, pos, lim, cap, buf, off);
+        this.isReadOnly = isReadOnly;
+    }
+
+    public ShortBuffer slice() {
+        return new HeapShortBuffer(hb,
+                                   -1,
+                                   0,
+                                   this.remaining(),
+                                   this.remaining(),
+                                   this.position() + offset,
+                                   isReadOnly);
+    }
+
+    public ShortBuffer duplicate() {
+        return new HeapShortBuffer(hb,
+                                   this.markValue(),
+                                   this.position(),
+                                   this.limit(),
+                                   this.capacity(),
+                                   offset,
+                                   isReadOnly);
+    }
+
+    public ShortBuffer asReadOnlyBuffer() {
+
+        return new HeapShortBuffer(hb,
+                                    this.markValue(),
+                                    this.position(),
+                                    this.limit(),
+                                    this.capacity(),
+                                    offset, true);
+    }
+
+    protected int ix(int i) {
+        return i + offset;
+    }
+
+    public short get() {
+        return hb[ix(nextGetIndex())];
+    }
+
+    public short get(int i) {
+        return hb[ix(checkIndex(i))];
+    }
+
+    public ShortBuffer get(short[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        System.arraycopy(hb, ix(position()), dst, offset, length);
+        position(position() + length);
+        return this;
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public boolean isReadOnly() {
+        return isReadOnly;
+    }
+
+    public ShortBuffer put(short x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(nextPutIndex())] = x;
+        return this;
+    }
+
+    public ShortBuffer put(int i, short x) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        hb[ix(checkIndex(i))] = x;
+        return this;
+    }
+
+    public ShortBuffer put(short[] src, int offset, int length) {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        System.arraycopy(src, offset, hb, ix(position()), length);
+        position(position() + length);
+        return this;
+    }
+
+    public ShortBuffer put(ShortBuffer src) {
+        if (src == this) {
+            throw new IllegalArgumentException();
+        }
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        if (src instanceof HeapShortBuffer) {
+            HeapShortBuffer sb = (HeapShortBuffer)src;
+            int n = sb.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            System.arraycopy(sb.hb, sb.ix(sb.position()),
+                             hb, ix(position()), n);
+            sb.position(sb.position() + n);
+            position(position() + n);
+        } else if (src.isDirect()) {
+            int n = src.remaining();
+            if (n > remaining())
+                throw new BufferOverflowException();
+            src.get(hb, ix(position()), n);
+            position(position() + n);
+        } else {
+            super.put(src);
+        }
+        return this;
+    }
+
+    public ShortBuffer compact() {
+        if (isReadOnly) {
+            throw new ReadOnlyBufferException();
+        }
+        System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
+        position(remaining());
+        limit(capacity());
+        discardMark();
+        return this;
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+}
diff --git a/java/nio/IntBuffer.java b/java/nio/IntBuffer.java
new file mode 100644
index 0000000..7e34229
--- /dev/null
+++ b/java/nio/IntBuffer.java
@@ -0,0 +1,875 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+/**
+ * An int buffer.
+ *
+ * <p> This class defines four categories of operations upon
+ * int buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(int) <i>put</i>} methods that read and write
+ *   single ints; </p></li>
+ *
+ *   <li><p> Relative {@link #get(int[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of ints from this buffer
+ *   into an array; and</p></li>
+ *
+ *   <li><p> Relative {@link #put(int[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of ints from an
+ *   int array or some other int
+ *   buffer into this buffer;&#32;and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   an int buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Int buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, by {@link #wrap(int[]) <i>wrapping</i>} an existing
+ * int array  into a buffer, or by creating a
+ * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer.
+ *
+ *
+*
+ *
+ * <p> Like a byte buffer, an int buffer is either <a
+ * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>.  A
+ * int buffer created via the <tt>wrap</tt> methods of this class will
+ * be non-direct.  An int buffer created as a view of a byte buffer will
+ * be direct if, and only if, the byte buffer itself is direct.  Whether or not
+ * an int buffer is direct may be determined by invoking the {@link
+ * #isDirect isDirect} method.  </p>
+ *
+*
+ *
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class IntBuffer
+    extends Buffer
+    implements Comparable<IntBuffer>
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final int[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    IntBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 int[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 2 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    IntBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new int buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in ints
+     *
+     * @return  The new int buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static IntBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapIntBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps an int array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given int array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new int buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static IntBuffer wrap(int[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapIntBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps an int array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given int array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new int buffer
+     */
+    public static IntBuffer wrap(int[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Creates a new int buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of ints remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new int buffer
+     */
+    public abstract IntBuffer slice();
+
+    /**
+     * Creates a new int buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new int buffer
+     */
+    public abstract IntBuffer duplicate();
+
+    /**
+     * Creates a new, read-only int buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only int buffer
+     */
+    public abstract IntBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the int at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The int at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract int get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given int into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  i
+     *         The int to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract IntBuffer put(int i);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the int at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the int will be read
+     *
+     * @return  The int at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract int get(int index);
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given int into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the int will be written
+     *
+     * @param  i
+     *         The int value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract IntBuffer put(int index, int i);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers ints from this buffer into the given
+     * destination array.  If there are fewer ints remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * ints are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> ints from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient ints in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which ints are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first int to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of ints to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> ints
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public IntBuffer get(int[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers ints from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> ints
+     *          remaining in this buffer
+     */
+    public IntBuffer get(int[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the ints remaining in the given source
+     * buffer into this buffer.  If there are more ints remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no ints are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> ints from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which ints are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining ints in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public IntBuffer put(IntBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers ints into this buffer from the given
+     * source array.  If there are more ints to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * ints are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> ints from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which ints are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first int to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of ints to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public IntBuffer put(int[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * int array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final IntBuffer put(int[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible int
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the int array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = IntBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The ints between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * int at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the int at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the int at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of ints copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract IntBuffer compact();
+
+    /**
+     * Tells whether or not this int buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns a string summarizing the state of this buffer.
+     *
+     * @return  A summary string
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getName());
+        sb.append("[pos=");
+        sb.append(position());
+        sb.append(" lim=");
+        sb.append(limit());
+        sb.append(" cap=");
+        sb.append(capacity());
+        sb.append("]");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a int buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int) get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two int buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A int buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof IntBuffer))
+            return false;
+        IntBuffer that = (IntBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(int x, int y) {
+
+
+        return x == y;
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two int buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     * Pairs of {@code int} elements are compared as if by invoking
+     * {@link Integer#compare(int,int)}.
+
+     *
+     * <p> A int buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(IntBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(int x, int y) {
+
+
+        return Integer.compare(x, y);
+
+    }
+
+    // -- Other char stuff --
+
+
+    // -- Other byte stuff: Access to binary data --
+
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order of an int buffer created by allocation or by
+     * wrapping an existing <tt>int</tt> array is the {@link
+     * ByteOrder#nativeOrder native order} of the underlying
+     * hardware.  The byte order of an int buffer created as a <a
+     * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the
+     * byte buffer at the moment that the view is created.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public abstract ByteOrder order();
+
+
+}
diff --git a/java/nio/InvalidMarkException.java b/java/nio/InvalidMarkException.java
new file mode 100644
index 0000000..ed1a059
--- /dev/null
+++ b/java/nio/InvalidMarkException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to reset a buffer
+ * when its mark is not defined.
+ *
+ * @since 1.4
+ */
+
+public class InvalidMarkException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 1698329710438510774L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public InvalidMarkException() { }
+
+}
diff --git a/java/nio/LongBuffer.java b/java/nio/LongBuffer.java
new file mode 100644
index 0000000..5e5fa18
--- /dev/null
+++ b/java/nio/LongBuffer.java
@@ -0,0 +1,868 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+/**
+ * A long buffer.
+ *
+ * <p> This class defines four categories of operations upon
+ * long buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(long) <i>put</i>} methods that read and write
+ *   single longs; </p></li>
+ *
+ *   <li><p> Relative {@link #get(long[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of longs from this buffer
+ *   into an array; and</p></li>
+ *
+ *   <li><p> Relative {@link #put(long[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of longs from a
+ *   long array or some other long
+ *   buffer into this buffer;&#32;and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   a long buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Long buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, by {@link #wrap(long[]) <i>wrapping</i>} an existing
+ * long array  into a buffer, or by creating a
+ * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer.
+ *
+ *
+*
+ *
+ * <p> Like a byte buffer, a long buffer is either <a
+ * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>.  A
+ * long buffer created via the <tt>wrap</tt> methods of this class will
+ * be non-direct.  A long buffer created as a view of a byte buffer will
+ * be direct if, and only if, the byte buffer itself is direct.  Whether or not
+ * a long buffer is direct may be determined by invoking the {@link
+ * #isDirect isDirect} method.  </p>
+ *
+*
+ *
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class LongBuffer
+    extends Buffer
+    implements Comparable<LongBuffer>
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final long[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    LongBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 long[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 3 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    LongBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new long buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in longs
+     *
+     * @return  The new long buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static LongBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapLongBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps a long array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given long array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new long buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static LongBuffer wrap(long[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapLongBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a long array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given long array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new long buffer
+     */
+    public static LongBuffer wrap(long[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Creates a new long buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of longs remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new long buffer
+     */
+    public abstract LongBuffer slice();
+
+    /**
+     * Creates a new long buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new long buffer
+     */
+    public abstract LongBuffer duplicate();
+
+    /**
+     * Creates a new, read-only long buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only long buffer
+     */
+    public abstract LongBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the long at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The long at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract long get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given long into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  l
+     *         The long to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract LongBuffer put(long l);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the long at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the long will be read
+     *
+     * @return  The long at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract long get(int index);
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given long into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the long will be written
+     *
+     * @param  l
+     *         The long value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract LongBuffer put(int index, long l);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers longs from this buffer into the given
+     * destination array.  If there are fewer longs remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * longs are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> longs from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient longs in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which longs are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first long to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of longs to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> longs
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public LongBuffer get(long[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers longs from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> longs
+     *          remaining in this buffer
+     */
+    public LongBuffer get(long[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the longs remaining in the given source
+     * buffer into this buffer.  If there are more longs remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no longs are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> longs from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which longs are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining longs in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public LongBuffer put(LongBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers longs into this buffer from the given
+     * source array.  If there are more longs to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * longs are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> longs from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which longs are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first long to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of longs to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public LongBuffer put(long[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * long array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final LongBuffer put(long[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible long
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the long array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final long[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = LongBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The longs between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * long at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the long at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the long at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of longs copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract LongBuffer compact();
+
+    /**
+     * Tells whether or not this long buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns a string summarizing the state of this buffer.
+     *
+     * @return  A summary string
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getName());
+        sb.append("[pos=");
+        sb.append(position());
+        sb.append(" lim=");
+        sb.append(limit());
+        sb.append(" cap=");
+        sb.append(capacity());
+        sb.append("]");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a long buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int) get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two long buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A long buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof LongBuffer))
+            return false;
+        LongBuffer that = (LongBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(long x, long y) {
+
+
+        return x == y;
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two long buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     * Pairs of {@code long} elements are compared as if by invoking
+     * {@link Long#compare(long,long)}.
+
+     *
+     * <p> A long buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(LongBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(long x, long y) {
+
+
+        return Long.compare(x, y);
+
+    }
+
+    // -- Other char stuff --
+
+
+    // -- Other byte stuff: Access to binary data --
+
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order of a long buffer created by allocation or by
+     * wrapping an existing <tt>long</tt> array is the {@link
+     * ByteOrder#nativeOrder native order} of the underlying
+     * hardware.  The byte order of a long buffer created as a <a
+     * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the
+     * byte buffer at the moment that the view is created.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public abstract ByteOrder order();
+
+
+}
diff --git a/java/nio/MappedByteBuffer.java b/java/nio/MappedByteBuffer.java
new file mode 100644
index 0000000..2ea6cbd
--- /dev/null
+++ b/java/nio/MappedByteBuffer.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+import java.io.FileDescriptor;
+import sun.misc.Unsafe;
+
+
+/**
+ * A direct byte buffer whose content is a memory-mapped region of a file.
+ *
+ * <p> Mapped byte buffers are created via the {@link
+ * java.nio.channels.FileChannel#map FileChannel.map} method.  This class
+ * extends the {@link ByteBuffer} class with operations that are specific to
+ * memory-mapped file regions.
+ *
+ * <p> A mapped byte buffer and the file mapping that it represents remain
+ * valid until the buffer itself is garbage-collected.
+ *
+ * <p> The content of a mapped byte buffer can change at any time, for example
+ * if the content of the corresponding region of the mapped file is changed by
+ * this program or another.  Whether or not such changes occur, and when they
+ * occur, is operating-system dependent and therefore unspecified.
+ *
+ * <a name="inaccess"></a><p> All or part of a mapped byte buffer may become
+ * inaccessible at any time, for example if the mapped file is truncated.  An
+ * attempt to access an inaccessible region of a mapped byte buffer will not
+ * change the buffer's content and will cause an unspecified exception to be
+ * thrown either at the time of the access or at some later time.  It is
+ * therefore strongly recommended that appropriate precautions be taken to
+ * avoid the manipulation of a mapped file by this program, or by a
+ * concurrently running program, except to read or write the file's content.
+ *
+ * <p> Mapped byte buffers otherwise behave no differently than ordinary direct
+ * byte buffers. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class MappedByteBuffer
+    extends ByteBuffer
+{
+
+    // This is a little bit backwards: By rights MappedByteBuffer should be a
+    // subclass of DirectByteBuffer, but to keep the spec clear and simple, and
+    // for optimization purposes, it's easier to do it the other way around.
+    // This works because DirectByteBuffer is a package-private class.
+
+    // For mapped buffers, a FileDescriptor that may be used for mapping
+    // operations if valid; null if the buffer is not mapped.
+    private final FileDescriptor fd;
+
+    // This should only be invoked by the DirectByteBuffer constructors
+    //
+    MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
+                     FileDescriptor fd)
+    {
+        super(mark, pos, lim, cap);
+        this.fd = fd;
+    }
+
+    // Android-added: Additional constructor for use by Android's DirectByteBuffer.
+    MappedByteBuffer(int mark, int pos, int lim, int cap, byte[] buf, int offset) {
+        super(mark, pos, lim, cap, buf, offset);
+        this.fd = null;
+    }
+
+    MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
+        super(mark, pos, lim, cap);
+        this.fd = null;
+    }
+
+    private void checkMapped() {
+        if (fd == null)
+            // Can only happen if a luser explicitly casts a direct byte buffer
+            throw new UnsupportedOperationException();
+    }
+
+    // Returns the distance (in bytes) of the buffer from the page aligned address
+    // of the mapping. Computed each time to avoid storing in every direct buffer.
+    private long mappingOffset() {
+        int ps = Bits.pageSize();
+        long offset = address % ps;
+        return (offset >= 0) ? offset : (ps + offset);
+    }
+
+    private long mappingAddress(long mappingOffset) {
+        return address - mappingOffset;
+    }
+
+    private long mappingLength(long mappingOffset) {
+        return (long)capacity() + mappingOffset;
+    }
+
+    /**
+     * Tells whether or not this buffer's content is resident in physical
+     * memory.
+     *
+     * <p> A return value of <tt>true</tt> implies that it is highly likely
+     * that all of the data in this buffer is resident in physical memory and
+     * may therefore be accessed without incurring any virtual-memory page
+     * faults or I/O operations.  A return value of <tt>false</tt> does not
+     * necessarily imply that the buffer's content is not resident in physical
+     * memory.
+     *
+     * <p> The returned value is a hint, rather than a guarantee, because the
+     * underlying operating system may have paged out some of the buffer's data
+     * by the time that an invocation of this method returns.  </p>
+     *
+     * @return  <tt>true</tt> if it is likely that this buffer's content
+     *          is resident in physical memory
+     */
+    public final boolean isLoaded() {
+        checkMapped();
+        if ((address == 0) || (capacity() == 0))
+            return true;
+        long offset = mappingOffset();
+        long length = mappingLength(offset);
+        return isLoaded0(mappingAddress(offset), length, Bits.pageCount(length));
+    }
+
+    // not used, but a potential target for a store, see load() for details.
+    private static byte unused;
+
+    /**
+     * Loads this buffer's content into physical memory.
+     *
+     * <p> This method makes a best effort to ensure that, when it returns,
+     * this buffer's content is resident in physical memory.  Invoking this
+     * method may cause some number of page faults and I/O operations to
+     * occur. </p>
+     *
+     * @return  This buffer
+     */
+    public final MappedByteBuffer load() {
+        checkMapped();
+        if ((address == 0) || (capacity() == 0))
+            return this;
+        long offset = mappingOffset();
+        long length = mappingLength(offset);
+        load0(mappingAddress(offset), length);
+
+        // Read a byte from each page to bring it into memory. A checksum
+        // is computed as we go along to prevent the compiler from otherwise
+        // considering the loop as dead code.
+        Unsafe unsafe = Unsafe.getUnsafe();
+        int ps = Bits.pageSize();
+        int count = Bits.pageCount(length);
+        long a = mappingAddress(offset);
+        byte x = 0;
+        for (int i=0; i<count; i++) {
+            x ^= unsafe.getByte(a);
+            a += ps;
+        }
+        if (unused != 0)
+            unused = x;
+
+        return this;
+    }
+
+    /**
+     * Forces any changes made to this buffer's content to be written to the
+     * storage device containing the mapped file.
+     *
+     * <p> If the file mapped into this buffer resides on a local storage
+     * device then when this method returns it is guaranteed that all changes
+     * made to the buffer since it was created, or since this method was last
+     * invoked, will have been written to that device.
+     *
+     * <p> If the file does not reside on a local device then no such guarantee
+     * is made.
+     *
+     * <p> If this buffer was not mapped in read/write mode ({@link
+     * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this
+     * method has no effect. </p>
+     *
+     * @return  This buffer
+     */
+    public final MappedByteBuffer force() {
+        checkMapped();
+        if ((address != 0) && (capacity() != 0)) {
+            long offset = mappingOffset();
+            force0(fd, mappingAddress(offset), mappingLength(offset));
+        }
+        return this;
+    }
+
+    private native boolean isLoaded0(long address, long length, int pageCount);
+    private native void load0(long address, long length);
+    private native void force0(FileDescriptor fd, long address, long length);
+}
diff --git a/java/nio/NIOAccess.java b/java/nio/NIOAccess.java
new file mode 100644
index 0000000..7345379
--- /dev/null
+++ b/java/nio/NIOAccess.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * 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.nio;
+
+import android.compat.annotation.UnsupportedAppUsage;
+
+/**
+ * This class is used via JNI by code in frameworks/base/ and
+ * by the JniConstants cache in libnativehelper/.
+ * @hide
+ */
+// @VisibleForTesting : was default
[email protected]
+public final class NIOAccess {
+
+    /**
+     * Returns the underlying native pointer to the data of the given
+     * Buffer starting at the Buffer's current position, or 0 if the
+     * Buffer is not backed by native heap storage.
+     * @hide
+     */
+    // @VisibleForTesting : was default
+    @UnsupportedAppUsage
+    public static long getBasePointer(Buffer b) {
+        long address = b.address;
+        if (address == 0L) {
+            return 0L;
+        }
+        return address + (b.position << b._elementSizeShift);
+    }
+
+    /**
+     * Returns the underlying Java array containing the data of the
+     * given Buffer, or null if the Buffer is not backed by a Java array.
+     */
+    @UnsupportedAppUsage
+    @libcore.api.CorePlatformApi
+    public static Object getBaseArray(Buffer b) {
+        return b.hasArray() ? b.array() : null;
+    }
+
+    /**
+     * Returns the offset in bytes from the start of the underlying
+     * Java array object containing the data of the given Buffer to
+     * the actual start of the data. The start of the data takes into
+     * account the Buffer's current position. This method is only
+     * meaningful if getBaseArray() returns non-null.
+     */
+    @UnsupportedAppUsage
+    @libcore.api.CorePlatformApi
+    public static int getBaseArrayOffset(Buffer b) {
+        return b.hasArray() ? ((b.arrayOffset() + b.position) << b._elementSizeShift) : 0;
+    }
+}
diff --git a/java/nio/NioUtils.java b/java/nio/NioUtils.java
new file mode 100644
index 0000000..aca91b0
--- /dev/null
+++ b/java/nio/NioUtils.java
@@ -0,0 +1,92 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.nio;
+
+import android.compat.annotation.UnsupportedAppUsage;
+
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.nio.channels.FileChannel;
+
+import sun.nio.ch.FileChannelImpl;
+
+import static android.system.OsConstants.O_ACCMODE;
+import static android.system.OsConstants.O_APPEND;
+import static android.system.OsConstants.O_RDONLY;
+import static android.system.OsConstants.O_WRONLY;
+
+/**
+ * @hide internal use only
+ */
[email protected]
+public final class NioUtils {
+    private NioUtils() {
+    }
+
+    @UnsupportedAppUsage
+    @libcore.api.CorePlatformApi
+    public static void freeDirectBuffer(ByteBuffer buffer) {
+        if (buffer == null) {
+            return;
+        }
+
+        DirectByteBuffer dbb = (DirectByteBuffer) buffer;
+        // Run the cleaner early, if one is defined.
+        if (dbb.cleaner != null) {
+            dbb.cleaner.clean();
+        }
+
+        dbb.memoryRef.free();
+    }
+
+    /**
+     * Returns the int file descriptor from within the given FileChannel 'fc'.
+     */
+    public static FileDescriptor getFD(FileChannel fc) {
+        return ((FileChannelImpl) fc).fd;
+    }
+
+    /**
+     * Helps bridge between io and nio.
+     */
+    public static FileChannel newFileChannel(Closeable ioObject, FileDescriptor fd, int mode) {
+        boolean readable = (mode & O_ACCMODE) != O_WRONLY;
+        boolean writable = (mode & O_ACCMODE) != O_RDONLY;
+        boolean append = (mode & O_APPEND) != 0;
+        return FileChannelImpl.open(fd, null, readable, writable, append, ioObject);
+    }
+
+    /**
+     * Exposes the array backing a non-direct ByteBuffer, even if the ByteBuffer is read-only.
+     * Normally, attempting to access the array backing a read-only buffer throws.
+     */
+    @UnsupportedAppUsage
+    @libcore.api.CorePlatformApi
+    public static byte[] unsafeArray(ByteBuffer b) {
+        return b.array();
+    }
+
+    /**
+     * Exposes the array offset for the array backing a non-direct ByteBuffer,
+     * even if the ByteBuffer is read-only.
+     */
+    @UnsupportedAppUsage
+    @libcore.api.CorePlatformApi
+    public static int unsafeArrayOffset(ByteBuffer b) {
+        return b.arrayOffset();
+    }
+}
diff --git a/java/nio/ReadOnlyBufferException.java b/java/nio/ReadOnlyBufferException.java
new file mode 100644
index 0000000..5eb4b95
--- /dev/null
+++ b/java/nio/ReadOnlyBufferException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+/**
+ * Unchecked exception thrown when a content-mutation method such as
+ * <tt>put</tt> or <tt>compact</tt> is invoked upon a read-only buffer.
+ *
+ * @since 1.4
+ */
+
+public class ReadOnlyBufferException
+    extends UnsupportedOperationException
+{
+
+    private static final long serialVersionUID = -1210063976496234090L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ReadOnlyBufferException() { }
+
+}
diff --git a/java/nio/ShortBuffer.java b/java/nio/ShortBuffer.java
new file mode 100644
index 0000000..b2a479c
--- /dev/null
+++ b/java/nio/ShortBuffer.java
@@ -0,0 +1,868 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio;
+
+
+import dalvik.annotation.codegen.CovariantReturnType;
+
+/**
+ * A short buffer.
+ *
+ * <p> This class defines four categories of operations upon
+ * short buffers:
+ *
+ * <ul>
+ *
+ *   <li><p> Absolute and relative {@link #get() <i>get</i>} and
+ *   {@link #put(short) <i>put</i>} methods that read and write
+ *   single shorts; </p></li>
+ *
+ *   <li><p> Relative {@link #get(short[]) <i>bulk get</i>}
+ *   methods that transfer contiguous sequences of shorts from this buffer
+ *   into an array; and</p></li>
+ *
+ *   <li><p> Relative {@link #put(short[]) <i>bulk put</i>}
+ *   methods that transfer contiguous sequences of shorts from a
+ *   short array or some other short
+ *   buffer into this buffer;&#32;and </p></li>
+ *
+ *
+ *   <li><p> Methods for {@link #compact compacting}, {@link
+ *   #duplicate duplicating}, and {@link #slice slicing}
+ *   a short buffer.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Short buffers can be created either by {@link #allocate
+ * <i>allocation</i>}, which allocates space for the buffer's
+ *
+ *
+ * content, by {@link #wrap(short[]) <i>wrapping</i>} an existing
+ * short array  into a buffer, or by creating a
+ * <a href="ByteBuffer.html#views"><i>view</i></a> of an existing byte buffer.
+ *
+ *
+*
+ *
+ * <p> Like a byte buffer, a short buffer is either <a
+ * href="ByteBuffer.html#direct"><i>direct</i> or <i>non-direct</i></a>.  A
+ * short buffer created via the <tt>wrap</tt> methods of this class will
+ * be non-direct.  A short buffer created as a view of a byte buffer will
+ * be direct if, and only if, the byte buffer itself is direct.  Whether or not
+ * a short buffer is direct may be determined by invoking the {@link
+ * #isDirect isDirect} method.  </p>
+ *
+*
+ *
+ *
+ * <p> Methods in this class that do not otherwise have a value to return are
+ * specified to return the buffer upon which they are invoked.  This allows
+ * method invocations to be chained.
+ *
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class ShortBuffer
+    extends Buffer
+    implements Comparable<ShortBuffer>
+{
+
+    // These fields are declared here rather than in Heap-X-Buffer in order to
+    // reduce the number of virtual method invocations needed to access these
+    // values, which is especially costly when coding small buffers.
+    //
+    final short[] hb;                  // Non-null only for heap buffers
+    final int offset;
+    boolean isReadOnly;                 // Valid only for heap buffers
+
+    // Creates a new buffer with the given mark, position, limit, capacity,
+    // backing array, and array offset
+    //
+    ShortBuffer(int mark, int pos, int lim, int cap,   // package-private
+                 short[] hb, int offset)
+    {
+        // Android-added: elementSizeShift parameter (log2 of element size).
+        super(mark, pos, lim, cap, 1 /* elementSizeShift */);
+        this.hb = hb;
+        this.offset = offset;
+    }
+
+    // Creates a new buffer with the given mark, position, limit, and capacity
+    //
+    ShortBuffer(int mark, int pos, int lim, int cap) { // package-private
+        this(mark, pos, lim, cap, null, 0);
+    }
+
+
+    /**
+     * Allocates a new short buffer.
+     *
+     * <p> The new buffer's position will be zero, its limit will be its
+     * capacity, its mark will be undefined, and each of its elements will be
+     * initialized to zero.  It will have a {@link #array backing array},
+     * and its {@link #arrayOffset array offset} will be zero.
+     *
+     * @param  capacity
+     *         The new buffer's capacity, in shorts
+     *
+     * @return  The new short buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the <tt>capacity</tt> is a negative integer
+     */
+    public static ShortBuffer allocate(int capacity) {
+        if (capacity < 0)
+            throw new IllegalArgumentException();
+        return new HeapShortBuffer(capacity, capacity);
+    }
+
+    /**
+     * Wraps a short array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given short array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity will be
+     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
+     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its
+     * {@link #array backing array} will be the given array, and
+     * its {@link #arrayOffset array offset} will be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back the new buffer
+     *
+     * @param  offset
+     *         The offset of the subarray to be used; must be non-negative and
+     *         no larger than <tt>array.length</tt>.  The new buffer's position
+     *         will be set to this value.
+     *
+     * @param  length
+     *         The length of the subarray to be used;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>.
+     *         The new buffer's limit will be set to <tt>offset + length</tt>.
+     *
+     * @return  The new short buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public static ShortBuffer wrap(short[] array,
+                                    int offset, int length)
+    {
+        try {
+            return new HeapShortBuffer(array, offset, length);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    /**
+     * Wraps a short array into a buffer.
+     *
+     * <p> The new buffer will be backed by the given short array;
+     * that is, modifications to the buffer will cause the array to be modified
+     * and vice versa.  The new buffer's capacity and limit will be
+     * <tt>array.length</tt>, its position will be zero, and its mark will be
+     * undefined.  Its {@link #array backing array} will be the
+     * given array, and its {@link #arrayOffset array offset>} will
+     * be zero.  </p>
+     *
+     * @param  array
+     *         The array that will back this buffer
+     *
+     * @return  The new short buffer
+     */
+    public static ShortBuffer wrap(short[] array) {
+        return wrap(array, 0, array.length);
+    }
+
+
+    /**
+     * Creates a new short buffer whose content is a shared subsequence of
+     * this buffer's content.
+     *
+     * <p> The content of the new buffer will start at this buffer's current
+     * position.  Changes to this buffer's content will be visible in the new
+     * buffer, and vice versa; the two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's position will be zero, its capacity and its limit
+     * will be the number of shorts remaining in this buffer, and its mark
+     * will be undefined.  The new buffer will be direct if, and only if, this
+     * buffer is direct, and it will be read-only if, and only if, this buffer
+     * is read-only.  </p>
+     *
+     * @return  The new short buffer
+     */
+    public abstract ShortBuffer slice();
+
+    /**
+     * Creates a new short buffer that shares this buffer's content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer, and vice
+     * versa; the two buffers' position, limit, and mark values will be
+     * independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.  The new buffer will be direct if,
+     * and only if, this buffer is direct, and it will be read-only if, and
+     * only if, this buffer is read-only.  </p>
+     *
+     * @return  The new short buffer
+     */
+    public abstract ShortBuffer duplicate();
+
+    /**
+     * Creates a new, read-only short buffer that shares this buffer's
+     * content.
+     *
+     * <p> The content of the new buffer will be that of this buffer.  Changes
+     * to this buffer's content will be visible in the new buffer; the new
+     * buffer itself, however, will be read-only and will not allow the shared
+     * content to be modified.  The two buffers' position, limit, and mark
+     * values will be independent.
+     *
+     * <p> The new buffer's capacity, limit, position, and mark values will be
+     * identical to those of this buffer.
+     *
+     * <p> If this buffer is itself read-only then this method behaves in
+     * exactly the same way as the {@link #duplicate duplicate} method.  </p>
+     *
+     * @return  The new, read-only short buffer
+     */
+    public abstract ShortBuffer asReadOnlyBuffer();
+
+
+    // -- Singleton get/put methods --
+
+    /**
+     * Relative <i>get</i> method.  Reads the short at this buffer's
+     * current position, and then increments the position.
+     *
+     * @return  The short at the buffer's current position
+     *
+     * @throws  BufferUnderflowException
+     *          If the buffer's current position is not smaller than its limit
+     */
+    public abstract short get();
+
+    /**
+     * Relative <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given short into this buffer at the current
+     * position, and then increments the position. </p>
+     *
+     * @param  s
+     *         The short to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If this buffer's current position is not smaller than its limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ShortBuffer put(short s);
+
+    /**
+     * Absolute <i>get</i> method.  Reads the short at the given
+     * index.
+     *
+     * @param  index
+     *         The index from which the short will be read
+     *
+     * @return  The short at the given index
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     */
+    public abstract short get(int index);
+
+    /**
+     * Absolute <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Writes the given short into this buffer at the given
+     * index. </p>
+     *
+     * @param  index
+     *         The index at which the short will be written
+     *
+     * @param  s
+     *         The short value to be written
+     *
+     * @return  This buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If <tt>index</tt> is negative
+     *          or not smaller than the buffer's limit
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ShortBuffer put(int index, short s);
+
+
+    // -- Bulk get operations --
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers shorts from this buffer into the given
+     * destination array.  If there are fewer shorts remaining in the
+     * buffer than are required to satisfy the request, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * shorts are transferred and a {@link BufferUnderflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> shorts from this
+     * buffer into the given array, starting at the current position of this
+     * buffer and at the given offset in the array.  The position of this
+     * buffer is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>src.get(dst,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst[i] = src.get();
+     * }</pre>
+     *
+     * except that it first checks that there are sufficient shorts in
+     * this buffer and it is potentially much more efficient.
+     *
+     * @param  dst
+     *         The array into which shorts are to be written
+     *
+     * @param  offset
+     *         The offset within the array of the first short to be
+     *         written; must be non-negative and no larger than
+     *         <tt>dst.length</tt>
+     *
+     * @param  length
+     *         The maximum number of shorts to be written to the given
+     *         array; must be non-negative and no larger than
+     *         <tt>dst.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> shorts
+     *          remaining in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     */
+    public ShortBuffer get(short[] dst, int offset, int length) {
+        checkBounds(offset, length, dst.length);
+        if (length > remaining())
+            throw new BufferUnderflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            dst[i] = get();
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>get</i> method.
+     *
+     * <p> This method transfers shorts from this buffer into the given
+     * destination array.  An invocation of this method of the form
+     * <tt>src.get(a)</tt> behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     src.get(a, 0, a.length) </pre>
+     *
+     * @param   dst
+     *          The destination array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferUnderflowException
+     *          If there are fewer than <tt>length</tt> shorts
+     *          remaining in this buffer
+     */
+    public ShortBuffer get(short[] dst) {
+        return get(dst, 0, dst.length);
+    }
+
+
+    // -- Bulk put operations --
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the shorts remaining in the given source
+     * buffer into this buffer.  If there are more shorts remaining in the
+     * source buffer than in this buffer, that is, if
+     * <tt>src.remaining()</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>,
+     * then no shorts are transferred and a {@link
+     * BufferOverflowException} is thrown.
+     *
+     * <p> Otherwise, this method copies
+     * <i>n</i>&nbsp;=&nbsp;<tt>src.remaining()</tt> shorts from the given
+     * buffer into this buffer, starting at each buffer's current position.
+     * The positions of both buffers are then incremented by <i>n</i>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src)</tt> has exactly the same effect as the loop
+     *
+     * <pre>
+     *     while (src.hasRemaining())
+     *         dst.put(src.get()); </pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The source buffer from which shorts are to be read;
+     *         must not be this buffer
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *          for the remaining shorts in the source buffer
+     *
+     * @throws  IllegalArgumentException
+     *          If the source buffer is this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public ShortBuffer put(ShortBuffer src) {
+        if (src == this)
+            throw new IllegalArgumentException();
+        if (isReadOnly())
+            throw new ReadOnlyBufferException();
+        int n = src.remaining();
+        if (n > remaining())
+            throw new BufferOverflowException();
+        for (int i = 0; i < n; i++)
+            put(src.get());
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers shorts into this buffer from the given
+     * source array.  If there are more shorts to be copied from the array
+     * than remain in this buffer, that is, if
+     * <tt>length</tt>&nbsp;<tt>&gt;</tt>&nbsp;<tt>remaining()</tt>, then no
+     * shorts are transferred and a {@link BufferOverflowException} is
+     * thrown.
+     *
+     * <p> Otherwise, this method copies <tt>length</tt> shorts from the
+     * given array into this buffer, starting at the given offset in the array
+     * and at the current position of this buffer.  The position of this buffer
+     * is then incremented by <tt>length</tt>.
+     *
+     * <p> In other words, an invocation of this method of the form
+     * <tt>dst.put(src,&nbsp;off,&nbsp;len)</tt> has exactly the same effect as
+     * the loop
+     *
+     * <pre>{@code
+     *     for (int i = off; i < off + len; i++)
+     *         dst.put(a[i]);
+     * }</pre>
+     *
+     * except that it first checks that there is sufficient space in this
+     * buffer and it is potentially much more efficient.
+     *
+     * @param  src
+     *         The array from which shorts are to be read
+     *
+     * @param  offset
+     *         The offset within the array of the first short to be read;
+     *         must be non-negative and no larger than <tt>array.length</tt>
+     *
+     * @param  length
+     *         The number of shorts to be read from the given array;
+     *         must be non-negative and no larger than
+     *         <tt>array.length - offset</tt>
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public ShortBuffer put(short[] src, int offset, int length) {
+        checkBounds(offset, length, src.length);
+        if (length > remaining())
+            throw new BufferOverflowException();
+        int end = offset + length;
+        for (int i = offset; i < end; i++)
+            this.put(src[i]);
+        return this;
+    }
+
+    /**
+     * Relative bulk <i>put</i> method&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> This method transfers the entire content of the given source
+     * short array into this buffer.  An invocation of this method of the
+     * form <tt>dst.put(a)</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     dst.put(a, 0, a.length) </pre>
+     *
+     * @param   src
+     *          The source array
+     *
+     * @return  This buffer
+     *
+     * @throws  BufferOverflowException
+     *          If there is insufficient space in this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public final ShortBuffer put(short[] src) {
+        return put(src, 0, src.length);
+    }
+
+
+    // -- Other stuff --
+
+    /**
+     * Tells whether or not this buffer is backed by an accessible short
+     * array.
+     *
+     * <p> If this method returns <tt>true</tt> then the {@link #array() array}
+     * and {@link #arrayOffset() arrayOffset} methods may safely be invoked.
+     * </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer
+     *          is backed by an array and is not read-only
+     */
+    public final boolean hasArray() {
+        return (hb != null) && !isReadOnly;
+    }
+
+    /**
+     * Returns the short array that backs this
+     * buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> Modifications to this buffer's content will cause the returned
+     * array's content to be modified, and vice versa.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The array that backs this buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final short[] array() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return hb;
+    }
+
+    /**
+     * Returns the offset within this buffer's backing array of the first
+     * element of the buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this buffer is backed by an array then buffer position <i>p</i>
+     * corresponds to array index <i>p</i>&nbsp;+&nbsp;<tt>arrayOffset()</tt>.
+     *
+     * <p> Invoke the {@link #hasArray hasArray} method before invoking this
+     * method in order to ensure that this buffer has an accessible backing
+     * array.  </p>
+     *
+     * @return  The offset within this buffer's array
+     *          of the first element of the buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is backed by an array but is read-only
+     *
+     * @throws  UnsupportedOperationException
+     *          If this buffer is not backed by an accessible array
+     */
+    public final int arrayOffset() {
+        if (hb == null)
+            throw new UnsupportedOperationException();
+        if (isReadOnly)
+            throw new ReadOnlyBufferException();
+        return offset;
+    }
+
+    // BEGIN Android-added: covariant overloads of *Buffer methods that return this.
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer position(int newPosition) {
+        return super.position(newPosition);
+    }
+
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer limit(int newLimit) {
+        return super.limit(newLimit);
+    }
+
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer mark() {
+        return super.mark();
+    }
+
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer reset() {
+        return super.reset();
+    }
+
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer clear() {
+        return super.clear();
+    }
+
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer flip() {
+        return super.flip();
+    }
+
+    @CovariantReturnType(returnType = ShortBuffer.class, presentAfter = 28)
+    @Override
+    public Buffer rewind() {
+        return super.rewind();
+    }
+    // END Android-added: covariant overloads of *Buffer methods that return this.
+
+    /**
+     * Compacts this buffer&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> The shorts between the buffer's current position and its limit,
+     * if any, are copied to the beginning of the buffer.  That is, the
+     * short at index <i>p</i>&nbsp;=&nbsp;<tt>position()</tt> is copied
+     * to index zero, the short at index <i>p</i>&nbsp;+&nbsp;1 is copied
+     * to index one, and so forth until the short at index
+     * <tt>limit()</tt>&nbsp;-&nbsp;1 is copied to index
+     * <i>n</i>&nbsp;=&nbsp;<tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>&nbsp;-&nbsp;<i>p</i>.
+     * The buffer's position is then set to <i>n+1</i> and its limit is set to
+     * its capacity.  The mark, if defined, is discarded.
+     *
+     * <p> The buffer's position is set to the number of shorts copied,
+     * rather than to zero, so that an invocation of this method can be
+     * followed immediately by an invocation of another relative <i>put</i>
+     * method. </p>
+     *
+
+     *
+     * @return  This buffer
+     *
+     * @throws  ReadOnlyBufferException
+     *          If this buffer is read-only
+     */
+    public abstract ShortBuffer compact();
+
+    /**
+     * Tells whether or not this short buffer is direct.
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is direct
+     */
+    public abstract boolean isDirect();
+
+
+    /**
+     * Returns a string summarizing the state of this buffer.
+     *
+     * @return  A summary string
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getClass().getName());
+        sb.append("[pos=");
+        sb.append(position());
+        sb.append(" lim=");
+        sb.append(limit());
+        sb.append(" cap=");
+        sb.append(capacity());
+        sb.append("]");
+        return sb.toString();
+    }
+
+
+    /**
+     * Returns the current hash code of this buffer.
+     *
+     * <p> The hash code of a short buffer depends only upon its remaining
+     * elements; that is, upon the elements from <tt>position()</tt> up to, and
+     * including, the element at <tt>limit()</tt>&nbsp;-&nbsp;<tt>1</tt>.
+     *
+     * <p> Because buffer hash codes are content-dependent, it is inadvisable
+     * to use buffers as keys in hash maps or similar data structures unless it
+     * is known that their contents will not change.  </p>
+     *
+     * @return  The current hash code of this buffer
+     */
+    public int hashCode() {
+        int h = 1;
+        int p = position();
+        for (int i = limit() - 1; i >= p; i--)
+            h = 31 * h + (int) get(i);
+        return h;
+    }
+
+    /**
+     * Tells whether or not this buffer is equal to another object.
+     *
+     * <p> Two short buffers are equal if, and only if,
+     *
+     * <ol>
+     *
+     *   <li><p> They have the same element type,  </p></li>
+     *
+     *   <li><p> They have the same number of remaining elements, and
+     *   </p></li>
+     *
+     *   <li><p> The two sequences of remaining elements, considered
+     *   independently of their starting positions, are pointwise equal.
+
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> A short buffer is not equal to any other type of object.  </p>
+     *
+     * @param  ob  The object to which this buffer is to be compared
+     *
+     * @return  <tt>true</tt> if, and only if, this buffer is equal to the
+     *           given object
+     */
+    public boolean equals(Object ob) {
+        if (this == ob)
+            return true;
+        if (!(ob instanceof ShortBuffer))
+            return false;
+        ShortBuffer that = (ShortBuffer)ob;
+        if (this.remaining() != that.remaining())
+            return false;
+        int p = this.position();
+        for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--)
+            if (!equals(this.get(i), that.get(j)))
+                return false;
+        return true;
+    }
+
+    private static boolean equals(short x, short y) {
+
+
+        return x == y;
+
+    }
+
+    /**
+     * Compares this buffer to another.
+     *
+     * <p> Two short buffers are compared by comparing their sequences of
+     * remaining elements lexicographically, without regard to the starting
+     * position of each sequence within its corresponding buffer.
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     *
+     * Pairs of {@code short} elements are compared as if by invoking
+     * {@link Short#compare(short,short)}.
+
+     *
+     * <p> A short buffer is not comparable to any other type of object.
+     *
+     * @return  A negative integer, zero, or a positive integer as this buffer
+     *          is less than, equal to, or greater than the given buffer
+     */
+    public int compareTo(ShortBuffer that) {
+        int n = this.position() + Math.min(this.remaining(), that.remaining());
+        for (int i = this.position(), j = that.position(); i < n; i++, j++) {
+            int cmp = compare(this.get(i), that.get(j));
+            if (cmp != 0)
+                return cmp;
+        }
+        return this.remaining() - that.remaining();
+    }
+
+    private static int compare(short x, short y) {
+
+
+        return Short.compare(x, y);
+
+    }
+
+    // -- Other char stuff --
+
+
+    // -- Other byte stuff: Access to binary data --
+
+
+    /**
+     * Retrieves this buffer's byte order.
+     *
+     * <p> The byte order of a short buffer created by allocation or by
+     * wrapping an existing <tt>short</tt> array is the {@link
+     * ByteOrder#nativeOrder native order} of the underlying
+     * hardware.  The byte order of a short buffer created as a <a
+     * href="ByteBuffer.html#views">view</a> of a byte buffer is that of the
+     * byte buffer at the moment that the view is created.  </p>
+     *
+     * @return  This buffer's byte order
+     */
+    public abstract ByteOrder order();
+
+
+}
diff --git a/java/nio/StringCharBuffer.java b/java/nio/StringCharBuffer.java
new file mode 100644
index 0000000..0c20fa6
--- /dev/null
+++ b/java/nio/StringCharBuffer.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio;
+
+
+// ## If the sequence is a string, use reflection to share its array
+
+class StringCharBuffer                                  // package-private
+    extends CharBuffer
+{
+    CharSequence str;
+
+    StringCharBuffer(CharSequence s, int start, int end) { // package-private
+        super(-1, start, end, s.length());
+        int n = s.length();
+        if ((start < 0) || (start > n) || (end < start) || (end > n))
+            throw new IndexOutOfBoundsException();
+        str = s;
+    }
+
+    public CharBuffer slice() {
+        return new StringCharBuffer(str,
+                                    -1,
+                                    0,
+                                    this.remaining(),
+                                    this.remaining(),
+                                    offset + this.position());
+    }
+
+    private StringCharBuffer(CharSequence s,
+                             int mark,
+                             int pos,
+                             int limit,
+                             int cap,
+                             int offset) {
+        super(mark, pos, limit, cap, null, offset);
+        str = s;
+    }
+
+    public CharBuffer duplicate() {
+        return new StringCharBuffer(str, markValue(),
+                                    position(), limit(), capacity(), offset);
+    }
+
+    public CharBuffer asReadOnlyBuffer() {
+        return duplicate();
+    }
+
+    public final char get() {
+        return str.charAt(nextGetIndex() + offset);
+    }
+
+    public final char get(int index) {
+        return str.charAt(checkIndex(index) + offset);
+    }
+
+    char getUnchecked(int index) {
+        return str.charAt(index + offset);
+    }
+
+    // ## Override bulk get methods for better performance
+
+    public final CharBuffer put(char c) {
+        throw new ReadOnlyBufferException();
+    }
+
+    public final CharBuffer put(int index, char c) {
+        throw new ReadOnlyBufferException();
+    }
+
+    public final CharBuffer compact() {
+        throw new ReadOnlyBufferException();
+    }
+
+    public final boolean isReadOnly() {
+        return true;
+    }
+
+    final String toString(int start, int end) {
+        return str.toString().substring(start + offset, end + offset);
+    }
+
+    public final CharBuffer subSequence(int start, int end) {
+        try {
+            int pos = position();
+            return new StringCharBuffer(str,
+                                        -1,
+                                        pos + checkIndex(start, pos),
+                                        pos + checkIndex(end, pos),
+                                        capacity(),
+                                        offset);
+        } catch (IllegalArgumentException x) {
+            throw new IndexOutOfBoundsException();
+        }
+    }
+
+    public boolean isDirect() {
+        return false;
+    }
+
+    public ByteOrder order() {
+        return ByteOrder.nativeOrder();
+    }
+
+}
diff --git a/java/nio/channels/AcceptPendingException.java b/java/nio/channels/AcceptPendingException.java
new file mode 100644
index 0000000..dc357f0
--- /dev/null
+++ b/java/nio/channels/AcceptPendingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to initiate an accept
+ * operation on a channel and a previous accept operation has not completed.
+ *
+ * @since 1.7
+ */
+
+public class AcceptPendingException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 2721339977965416421L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public AcceptPendingException() { }
+
+}
diff --git a/java/nio/channels/AlreadyBoundException.java b/java/nio/channels/AlreadyBoundException.java
new file mode 100644
index 0000000..38d1033
--- /dev/null
+++ b/java/nio/channels/AlreadyBoundException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to bind the socket a
+ * network oriented channel that is already bound.
+ *
+ * @since 1.7
+ */
+
+public class AlreadyBoundException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 6796072983322737592L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public AlreadyBoundException() { }
+
+}
diff --git a/java/nio/channels/AlreadyConnectedException.java b/java/nio/channels/AlreadyConnectedException.java
new file mode 100644
index 0000000..931efff
--- /dev/null
+++ b/java/nio/channels/AlreadyConnectedException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to connect a {@link
+ * SocketChannel} that is already connected.
+ *
+ * @since 1.4
+ */
+
+public class AlreadyConnectedException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -7331895245053773357L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public AlreadyConnectedException() { }
+
+}
diff --git a/java/nio/channels/AsynchronousByteChannel.java b/java/nio/channels/AsynchronousByteChannel.java
new file mode 100644
index 0000000..b96a239
--- /dev/null
+++ b/java/nio/channels/AsynchronousByteChannel.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.Future;
+
+/**
+ * An asynchronous channel that can read and write bytes.
+ *
+ * <p> Some channels may not allow more than one read or write to be outstanding
+ * at any given time. If a thread invokes a read method before a previous read
+ * operation has completed then a {@link ReadPendingException} will be thrown.
+ * Similarly, if a write method is invoked before a previous write has completed
+ * then {@link WritePendingException} is thrown. Whether or not other kinds of
+ * I/O operations may proceed concurrently with a read operation depends upon
+ * the type of the channel.
+ *
+ * <p> Note that {@link java.nio.ByteBuffer ByteBuffers} are not safe for use by
+ * multiple concurrent threads. When a read or write operation is initiated then
+ * care must be taken to ensure that the buffer is not accessed until the
+ * operation completes.
+ *
+ * @see Channels#newInputStream(AsynchronousByteChannel)
+ * @see Channels#newOutputStream(AsynchronousByteChannel)
+ *
+ * @since 1.7
+ */
+
+public interface AsynchronousByteChannel
+    extends AsynchronousChannel
+{
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> This method initiates an asynchronous read operation to read a
+     * sequence of bytes from this channel into the given buffer. The {@code
+     * handler} parameter is a completion handler that is invoked when the read
+     * operation completes (or fails). The result passed to the completion
+     * handler is the number of bytes read or {@code -1} if no bytes could be
+     * read because the channel has reached end-of-stream.
+     *
+     * <p> The read operation may read up to <i>r</i> bytes from the channel,
+     * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+     * {@code dst.remaining()} at the time that the read is attempted. Where
+     * <i>r</i> is 0, the read operation completes immediately with a result of
+     * {@code 0} without initiating an I/O operation.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * This byte sequence will be transferred into the buffer so that the first
+     * byte in the sequence is at index <i>p</i> and the last byte is at index
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>,
+     * where <i>p</i> is the buffer's position at the moment the read is
+     * performed. Upon completion the buffer's position will be equal to
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
+     *
+     * <p> Buffers are not safe for use by multiple concurrent threads so care
+     * should be taken to not access the buffer until the operation has
+     * completed.
+     *
+     * <p> This method may be invoked at any time. Some channel types may not
+     * allow more than one read to be outstanding at any given time. If a thread
+     * initiates a read operation before a previous read operation has
+     * completed then a {@link ReadPendingException} will be thrown.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The completion handler
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ReadPendingException
+     *          If the channel does not allow more than one read to be outstanding
+     *          and a previous read has not completed
+     * @throws  ShutdownChannelGroupException
+     *          If the channel is associated with a {@link AsynchronousChannelGroup
+     *          group} that has terminated
+     */
+    <A> void read(ByteBuffer dst,
+                  A attachment,
+                  CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> This method initiates an asynchronous read operation to read a
+     * sequence of bytes from this channel into the given buffer. The method
+     * behaves in exactly the same manner as the {@link
+     * #read(ByteBuffer,Object,CompletionHandler)
+     * read(ByteBuffer,Object,CompletionHandler)} method except that instead
+     * of specifying a completion handler, this method returns a {@code Future}
+     * representing the pending result. The {@code Future}'s {@link Future#get()
+     * get} method returns the number of bytes read or {@code -1} if no bytes
+     * could be read because the channel has reached end-of-stream.
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     *
+     * @return  A Future representing the result of the operation
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ReadPendingException
+     *          If the channel does not allow more than one read to be outstanding
+     *          and a previous read has not completed
+     */
+    Future<Integer> read(ByteBuffer dst);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> This method initiates an asynchronous write operation to write a
+     * sequence of bytes to this channel from the given buffer. The {@code
+     * handler} parameter is a completion handler that is invoked when the write
+     * operation completes (or fails). The result passed to the completion
+     * handler is the number of bytes written.
+     *
+     * <p> The write operation may write up to <i>r</i> bytes to the channel,
+     * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+     * {@code src.remaining()} at the time that the write is attempted. Where
+     * <i>r</i> is 0, the write operation completes immediately with a result of
+     * {@code 0} without initiating an I/O operation.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * This byte sequence will be transferred from the buffer starting at index
+     * <i>p</i>, where <i>p</i> is the buffer's position at the moment the
+     * write is performed; the index of the last byte written will be
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>.
+     * Upon completion the buffer's position will be equal to
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
+     *
+     * <p> Buffers are not safe for use by multiple concurrent threads so care
+     * should be taken to not access the buffer until the operation has
+     * completed.
+     *
+     * <p> This method may be invoked at any time. Some channel types may not
+     * allow more than one write to be outstanding at any given time. If a thread
+     * initiates a write operation before a previous write operation has
+     * completed then a {@link WritePendingException} will be thrown.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   src
+     *          The buffer from which bytes are to be retrieved
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The completion handler object
+     *
+     * @throws  WritePendingException
+     *          If the channel does not allow more than one write to be outstanding
+     *          and a previous write has not completed
+     * @throws  ShutdownChannelGroupException
+     *          If the channel is associated with a {@link AsynchronousChannelGroup
+     *          group} that has terminated
+     */
+    <A> void write(ByteBuffer src,
+                   A attachment,
+                   CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> This method initiates an asynchronous write operation to write a
+     * sequence of bytes to this channel from the given buffer. The method
+     * behaves in exactly the same manner as the {@link
+     * #write(ByteBuffer,Object,CompletionHandler)
+     * write(ByteBuffer,Object,CompletionHandler)} method except that instead
+     * of specifying a completion handler, this method returns a {@code Future}
+     * representing the pending result. The {@code Future}'s {@link Future#get()
+     * get} method returns the number of bytes written.
+     *
+     * @param   src
+     *          The buffer from which bytes are to be retrieved
+     *
+     * @return A Future representing the result of the operation
+     *
+     * @throws  WritePendingException
+     *          If the channel does not allow more than one write to be outstanding
+     *          and a previous write has not completed
+     */
+    Future<Integer> write(ByteBuffer src);
+}
diff --git a/java/nio/channels/AsynchronousChannel.java b/java/nio/channels/AsynchronousChannel.java
new file mode 100644
index 0000000..4668d09
--- /dev/null
+++ b/java/nio/channels/AsynchronousChannel.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.util.concurrent.Future;  // javadoc
+
+/**
+ * A channel that supports asynchronous I/O operations. Asynchronous I/O
+ * operations will usually take one of two forms:
+ *
+ * <ol>
+ * <li><pre>{@link Future}&lt;V&gt; <em>operation</em>(<em>...</em>)</pre></li>
+ * <li><pre>void <em>operation</em>(<em>...</em> A attachment, {@link
+ *   CompletionHandler}&lt;V,? super A&gt; handler)</pre></li>
+ * </ol>
+ *
+ * where <i>operation</i> is the name of the I/O operation (read or write for
+ * example), <i>V</i> is the result type of the I/O operation, and <i>A</i> is
+ * the type of an object attached to the I/O operation to provide context when
+ * consuming the result. The attachment is important for cases where a
+ * <em>state-less</em> {@code CompletionHandler} is used to consume the result
+ * of many I/O operations.
+ *
+ * <p> In the first form, the methods defined by the {@link Future Future}
+ * interface may be used to check if the operation has completed, wait for its
+ * completion, and to retrieve the result. In the second form, a {@link
+ * CompletionHandler} is invoked to consume the result of the I/O operation when
+ * it completes or fails.
+ *
+ * <p> A channel that implements this interface is <em>asynchronously
+ * closeable</em>: If an I/O operation is outstanding on the channel and the
+ * channel's {@link #close close} method is invoked, then the I/O operation
+ * fails with the exception {@link AsynchronousCloseException}.
+ *
+ * <p> Asynchronous channels are safe for use by multiple concurrent threads.
+ * Some channel implementations may support concurrent reading and writing, but
+ * may not allow more than one read and one write operation to be outstanding at
+ * any given time.
+ *
+ * <h2>Cancellation</h2>
+ *
+ * <p> The {@code Future} interface defines the {@link Future#cancel cancel}
+ * method to cancel execution. This causes all threads waiting on the result of
+ * the I/O operation to throw {@link java.util.concurrent.CancellationException}.
+ * Whether the underlying I/O operation can be cancelled is highly implementation
+ * specific and therefore not specified. Where cancellation leaves the channel,
+ * or the entity to which it is connected, in an inconsistent state, then the
+ * channel is put into an implementation specific <em>error state</em> that
+ * prevents further attempts to initiate I/O operations that are <i>similar</i>
+ * to the operation that was cancelled. For example, if a read operation is
+ * cancelled but the implementation cannot guarantee that bytes have not been
+ * read from the channel then it puts the channel into an error state; further
+ * attempts to initiate a {@code read} operation cause an unspecified runtime
+ * exception to be thrown. Similarly, if a write operation is cancelled but the
+ * implementation cannot guarantee that bytes have not been written to the
+ * channel then subsequent attempts to initiate a {@code write} will fail with
+ * an unspecified runtime exception.
+ *
+ * <p> Where the {@link Future#cancel cancel} method is invoked with the {@code
+ * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation
+ * may be interrupted by closing the channel. In that case all threads waiting
+ * on the result of the I/O operation throw {@code CancellationException} and
+ * any other I/O operations outstanding on the channel complete with the
+ * exception {@link AsynchronousCloseException}.
+ *
+ * <p> Where the {@code cancel} method is invoked to cancel read or write
+ * operations then it is recommended that all buffers used in the I/O operations
+ * be discarded or care taken to ensure that the buffers are not accessed while
+ * the channel remains open.
+ *
+ *  @since 1.7
+ */
+
+public interface AsynchronousChannel
+    extends Channel
+{
+    /**
+     * Closes this channel.
+     *
+     * <p> Any outstanding asynchronous operations upon this channel will
+     * complete with the exception {@link AsynchronousCloseException}. After a
+     * channel is closed, further attempts to initiate asynchronous I/O
+     * operations complete immediately with cause {@link ClosedChannelException}.
+     *
+     * <p>  This method otherwise behaves exactly as specified by the {@link
+     * Channel} interface.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @Override
+    void close() throws IOException;
+}
diff --git a/java/nio/channels/AsynchronousChannelGroup.java b/java/nio/channels/AsynchronousChannelGroup.java
new file mode 100644
index 0000000..92b7e66
--- /dev/null
+++ b/java/nio/channels/AsynchronousChannelGroup.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A grouping of asynchronous channels for the purpose of resource sharing.
+ *
+ * <p> An asynchronous channel group encapsulates the mechanics required to
+ * handle the completion of I/O operations initiated by {@link AsynchronousChannel
+ * asynchronous channels} that are bound to the group. A group has an associated
+ * thread pool to which tasks are submitted to handle I/O events and dispatch to
+ * {@link CompletionHandler completion-handlers} that consume the result of
+ * asynchronous operations performed on channels in the group. In addition to
+ * handling I/O events, the pooled threads may also execute other tasks required
+ * to support the execution of asynchronous I/O operations.
+ *
+ * <p> An asynchronous channel group is created by invoking the {@link
+ * #withFixedThreadPool withFixedThreadPool} or {@link #withCachedThreadPool
+ * withCachedThreadPool} methods defined here. Channels are bound to a group by
+ * specifying the group when constructing the channel. The associated thread
+ * pool is <em>owned</em> by the group; termination of the group results in the
+ * shutdown of the associated thread pool.
+ *
+ * <p> In addition to groups created explicitly, the Java virtual machine
+ * maintains a system-wide <em>default group</em> that is constructed
+ * automatically. Asynchronous channels that do not specify a group at
+ * construction time are bound to the default group. The default group has an
+ * associated thread pool that creates new threads as needed. The default group
+ * may be configured by means of system properties defined in the table below.
+ * Where the {@link java.util.concurrent.ThreadFactory ThreadFactory} for the
+ * default group is not configured then the pooled threads of the default group
+ * are {@link Thread#isDaemon daemon} threads.
+ *
+ * <table border summary="System properties">
+ *   <tr>
+ *     <th>System property</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@code java.nio.channels.DefaultThreadPool.threadFactory} </td>
+ *     <td> The value of this property is taken to be the fully-qualified name
+ *     of a concrete {@link java.util.concurrent.ThreadFactory ThreadFactory}
+ *     class. The class is loaded using the system class loader and instantiated.
+ *     The factory's {@link java.util.concurrent.ThreadFactory#newThread
+ *     newThread} method is invoked to create each thread for the default
+ *     group's thread pool. If the process to load and instantiate the value
+ *     of the property fails then an unspecified error is thrown during the
+ *     construction of the default group. </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@code java.nio.channels.DefaultThreadPool.initialSize} </td>
+ *     <td> The value of the {@code initialSize} parameter for the default
+ *     group (see {@link #withCachedThreadPool withCachedThreadPool}).
+ *     The value of the property is taken to be the {@code String}
+ *     representation of an {@code Integer} that is the initial size parameter.
+ *     If the value cannot be parsed as an {@code Integer} it causes an
+ *     unspecified error to be thrown during the construction of the default
+ *     group. </td>
+ *   </tr>
+ * </table>
+ *
+ * <a name="threading"></a><h2>Threading</h2>
+ *
+ * <p> The completion handler for an I/O operation initiated on a channel bound
+ * to a group is guaranteed to be invoked by one of the pooled threads in the
+ * group. This ensures that the completion handler is run by a thread with the
+ * expected <em>identity</em>.
+ *
+ * <p> Where an I/O operation completes immediately, and the initiating thread
+ * is one of the pooled threads in the group then the completion handler may
+ * be invoked directly by the initiating thread. To avoid stack overflow, an
+ * implementation may impose a limit as to the number of activations on the
+ * thread stack. Some I/O operations may prohibit invoking the completion
+ * handler directly by the initiating thread (see {@link
+ * AsynchronousServerSocketChannel#accept(Object,CompletionHandler) accept}).
+ *
+ * <a name="shutdown"></a><h2>Shutdown and Termination</h2>
+ *
+ * <p> The {@link #shutdown() shutdown} method is used to initiate an <em>orderly
+ * shutdown</em> of a group. An orderly shutdown marks the group as shutdown;
+ * further attempts to construct a channel that binds to the group will throw
+ * {@link ShutdownChannelGroupException}. Whether or not a group is shutdown can
+ * be tested using the {@link #isShutdown() isShutdown} method. Once shutdown,
+ * the group <em>terminates</em> when all asynchronous channels that are bound to
+ * the group are closed, all actively executing completion handlers have run to
+ * completion, and resources used by the group are released. No attempt is made
+ * to stop or interrupt threads that are executing completion handlers. The
+ * {@link #isTerminated() isTerminated} method is used to test if the group has
+ * terminated, and the {@link #awaitTermination awaitTermination} method can be
+ * used to block until the group has terminated.
+ *
+ * <p> The {@link #shutdownNow() shutdownNow} method can be used to initiate a
+ * <em>forceful shutdown</em> of the group. In addition to the actions performed
+ * by an orderly shutdown, the {@code shutdownNow} method closes all open channels
+ * in the group as if by invoking the {@link AsynchronousChannel#close close}
+ * method.
+ *
+ * @since 1.7
+ *
+ * @see AsynchronousSocketChannel#open(AsynchronousChannelGroup)
+ * @see AsynchronousServerSocketChannel#open(AsynchronousChannelGroup)
+ */
+
+public abstract class AsynchronousChannelGroup {
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initialize a new instance of this class.
+     *
+     * @param   provider
+     *          The asynchronous channel provider for this group
+     */
+    protected AsynchronousChannelGroup(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel group.
+     *
+     * @return  The provider that created this channel group
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Creates an asynchronous channel group with a fixed thread pool.
+     *
+     * <p> The resulting asynchronous channel group reuses a fixed number of
+     * threads. At any point, at most {@code nThreads} threads will be active
+     * processing tasks that are submitted to handle I/O events and dispatch
+     * completion results for operations initiated on asynchronous channels in
+     * the group.
+     *
+     * <p> The group is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousChannelGroup(int,ThreadFactory)
+     * openAsynchronousChannelGroup(int,ThreadFactory)} method of the system-wide
+     * default {@link AsynchronousChannelProvider} object.
+     *
+     * @param   nThreads
+     *          The number of threads in the pool
+     * @param   threadFactory
+     *          The factory to use when creating new threads
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code nThreads <= 0}
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,
+                                                               ThreadFactory threadFactory)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(nThreads, threadFactory);
+    }
+
+    /**
+     * Creates an asynchronous channel group with a given thread pool that
+     * creates new threads as needed.
+     *
+     * <p> The {@code executor} parameter is an {@code ExecutorService} that
+     * creates new threads as needed to execute tasks that are submitted to
+     * handle I/O events and dispatch completion results for operations initiated
+     * on asynchronous channels in the group. It may reuse previously constructed
+     * threads when they are available.
+     *
+     * <p> The {@code initialSize} parameter may be used by the implementation
+     * as a <em>hint</em> as to the initial number of tasks it may submit. For
+     * example, it may be used to indicate the initial number of threads that
+     * wait on I/O events.
+     *
+     * <p> The executor is intended to be used exclusively by the resulting
+     * asynchronous channel group. Termination of the group results in the
+     * orderly  {@link ExecutorService#shutdown shutdown} of the executor
+     * service. Shutting down the executor service by other means results in
+     * unspecified behavior.
+     *
+     * <p> The group is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int)
+     * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide
+     * default {@link AsynchronousChannelProvider} object.
+     *
+     * @param   executor
+     *          The thread pool for the resulting group
+     * @param   initialSize
+     *          A value {@code >=0} or a negative value for implementation
+     *          specific default
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see java.util.concurrent.Executors#newCachedThreadPool
+     */
+    public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,
+                                                                int initialSize)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(executor, initialSize);
+    }
+
+    /**
+     * Creates an asynchronous channel group with a given thread pool.
+     *
+     * <p> The {@code executor} parameter is an {@code ExecutorService} that
+     * executes tasks submitted to dispatch completion results for operations
+     * initiated on asynchronous channels in the group.
+     *
+     * <p> Care should be taken when configuring the executor service. It
+     * should support <em>direct handoff</em> or <em>unbounded queuing</em> of
+     * submitted tasks, and the thread that invokes the {@link
+     * ExecutorService#execute execute} method should never invoke the task
+     * directly. An implementation may mandate additional constraints.
+     *
+     * <p> The executor is intended to be used exclusively by the resulting
+     * asynchronous channel group. Termination of the group results in the
+     * orderly  {@link ExecutorService#shutdown shutdown} of the executor
+     * service. Shutting down the executor service by other means results in
+     * unspecified behavior.
+     *
+     * <p> The group is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int)
+     * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide
+     * default {@link AsynchronousChannelProvider} object with an {@code
+     * initialSize} of {@code 0}.
+     *
+     * @param   executor
+     *          The thread pool for the resulting group
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousChannelGroup withThreadPool(ExecutorService executor)
+        throws IOException
+    {
+        return AsynchronousChannelProvider.provider()
+            .openAsynchronousChannelGroup(executor, 0);
+    }
+
+    /**
+     * Tells whether or not this asynchronous channel group is shutdown.
+     *
+     * @return  {@code true} if this asynchronous channel group is shutdown or
+     *          has been marked for shutdown.
+     */
+    public abstract boolean isShutdown();
+
+    /**
+     * Tells whether or not this group has terminated.
+     *
+     * <p> Where this method returns {@code true}, then the associated thread
+     * pool has also {@link ExecutorService#isTerminated terminated}.
+     *
+     * @return  {@code true} if this group has terminated
+     */
+    public abstract boolean isTerminated();
+
+    /**
+     * Initiates an orderly shutdown of the group.
+     *
+     * <p> This method marks the group as shutdown. Further attempts to construct
+     * channel that binds to this group will throw {@link ShutdownChannelGroupException}.
+     * The group terminates when all asynchronous channels in the group are
+     * closed, all actively executing completion handlers have run to completion,
+     * and all resources have been released. This method has no effect if the
+     * group is already shutdown.
+     */
+    public abstract void shutdown();
+
+    /**
+     * Shuts down the group and closes all open channels in the group.
+     *
+     * <p> In addition to the actions performed by the {@link #shutdown() shutdown}
+     * method, this method invokes the {@link AsynchronousChannel#close close}
+     * method on all open channels in the group. This method does not attempt to
+     * stop or interrupt threads that are executing completion handlers. The
+     * group terminates when all actively executing completion handlers have run
+     * to completion and all resources have been released. This method may be
+     * invoked at any time. If some other thread has already invoked it, then
+     * another invocation will block until the first invocation is complete,
+     * after which it will return without effect.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract void shutdownNow() throws IOException;
+
+    /**
+     * Awaits termination of the group.
+
+     * <p> This method blocks until the group has terminated, or the timeout
+     * occurs, or the current thread is interrupted, whichever happens first.
+     *
+     * @param   timeout
+     *          The maximum time to wait, or zero or less to not wait
+     * @param   unit
+     *          The time unit of the timeout argument
+     *
+     * @return  {@code true} if the group has terminated; {@code false} if the
+     *          timeout elapsed before termination
+     *
+     * @throws  InterruptedException
+     *          If interrupted while waiting
+     */
+    public abstract boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException;
+}
diff --git a/java/nio/channels/AsynchronousCloseException.java b/java/nio/channels/AsynchronousCloseException.java
new file mode 100644
index 0000000..6fb5e57
--- /dev/null
+++ b/java/nio/channels/AsynchronousCloseException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Checked exception received by a thread when another thread closes the
+ * channel or the part of the channel upon which it is blocked in an I/O
+ * operation.
+ *
+ * @since 1.4
+ */
+
+public class AsynchronousCloseException
+    extends ClosedChannelException
+{
+
+    private static final long serialVersionUID = 6891178312432313966L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public AsynchronousCloseException() { }
+
+}
diff --git a/java/nio/channels/AsynchronousFileChannel.java b/java/nio/channels/AsynchronousFileChannel.java
new file mode 100644
index 0000000..b985d77
--- /dev/null
+++ b/java/nio/channels/AsynchronousFileChannel.java
@@ -0,0 +1,779 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.file.*;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.*;
+import java.nio.ByteBuffer;
+import java.io.IOException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ExecutorService;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+
+/**
+ * An asynchronous channel for reading, writing, and manipulating a file.
+ *
+ * <p> An asynchronous file channel is created when a file is opened by invoking
+ * one of the {@link #open open} methods defined by this class. The file contains
+ * a variable-length sequence of bytes that can be read and written and whose
+ * current size can be {@link #size() queried}. The size of the file increases
+ * when bytes are written beyond its  current size; the size of the file decreases
+ * when it is {@link #truncate truncated}.
+ *
+ * <p> An asynchronous file channel does not have a <i>current position</i>
+ * within the file. Instead, the file position is specified to each read and
+ * write method that initiates asynchronous operations. A {@link CompletionHandler}
+ * is specified as a parameter and is invoked to consume the result of the I/O
+ * operation. This class also defines read and write methods that initiate
+ * asynchronous operations, returning a {@link Future} to represent the pending
+ * result of the operation. The {@code Future} may be used to check if the
+ * operation has completed, wait for its completion, and retrieve the result.
+ *
+ * <p> In addition to read and write operations, this class defines the
+ * following operations: </p>
+ *
+ * <ul>
+ *
+ *   <li><p> Updates made to a file may be {@link #force <i>forced
+ *   out</i>} to the underlying storage device, ensuring that data are not
+ *   lost in the event of a system crash.  </p></li>
+ *
+ *   <li><p> A region of a file may be {@link #lock <i>locked</i>} against
+ *   access by other programs.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> An {@code AsynchronousFileChannel} is associated with a thread pool to
+ * which tasks are submitted to handle I/O events and dispatch to completion
+ * handlers that consume the results of I/O operations on the channel. The
+ * completion handler for an I/O operation initiated on a channel is guaranteed
+ * to be invoked by one of the threads in the thread pool (This ensures that the
+ * completion handler is run by a thread with the expected <em>identity</em>).
+ * Where an I/O operation completes immediately, and the initiating thread is
+ * itself a thread in the thread pool, then the completion handler may be invoked
+ * directly by the initiating thread. When an {@code AsynchronousFileChannel} is
+ * created without specifying a thread pool then the channel is associated with
+ * a system-dependent default thread pool that may be shared with other
+ * channels. The default thread pool is configured by the system properties
+ * defined by the {@link AsynchronousChannelGroup} class.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads. The
+ * {@link Channel#close close} method may be invoked at any time, as specified
+ * by the {@link Channel} interface. This causes all outstanding asynchronous
+ * operations on the channel to complete with the exception {@link
+ * AsynchronousCloseException}. Multiple read and write operations may be
+ * outstanding at the same time. When multiple read and write operations are
+ * outstanding then the ordering of the I/O operations, and the order that the
+ * completion handlers are invoked, is not specified; they are not, in particular,
+ * guaranteed to execute in the order that the operations were initiated. The
+ * {@link java.nio.ByteBuffer ByteBuffers} used when reading or writing are not
+ * safe for use by multiple concurrent I/O operations. Furthermore, after an I/O
+ * operation is initiated then care should be taken to ensure that the buffer is
+ * not accessed until after the operation has completed.
+ *
+ * <p> As with {@link FileChannel}, the view of a file provided by an instance of
+ * this class is guaranteed to be consistent with other views of the same file
+ * provided by other instances in the same program.  The view provided by an
+ * instance of this class may or may not, however, be consistent with the views
+ * seen by other concurrently-running programs due to caching performed by the
+ * underlying operating system and delays induced by network-filesystem protocols.
+ * This is true regardless of the language in which these other programs are
+ * written, and whether they are running on the same machine or on some other
+ * machine.  The exact nature of any such inconsistencies are system-dependent
+ * and are therefore unspecified.
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousFileChannel
+    implements AsynchronousChannel
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AsynchronousFileChannel() {
+    }
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning an
+     * asynchronous file channel to access the file.
+     *
+     * <p> The {@code options} parameter determines how the file is opened.
+     * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE
+     * WRITE} options determines if the file should be opened for reading and/or
+     * writing. If neither option is contained in the array then an existing file
+     * is opened for  reading.
+     *
+     * <p> In addition to {@code READ} and {@code WRITE}, the following options
+     * may be present:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> When opening an existing file, the file is first truncated to a
+     *   size of 0 bytes. This option is ignored when the file is opened only
+     *   for reading.</td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
+     *   <td> If this option is present then a new file is created, failing if
+     *   the file already exists. When creating a file the check for the
+     *   existence of the file and the creation of the file if it does not exist
+     *   is atomic with respect to other file system operations. This option is
+     *   ignored when the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
+     *   <td> If this option is present then an existing file is opened if it
+     *   exists, otherwise a new file is created. When creating a file the check
+     *   for the existence of the file and the creation of the file if it does
+     *   not exist is atomic with respect to other file system operations. This
+     *   option is ignored if the {@code CREATE_NEW} option is also present or
+     *   the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
+     *   <td> When this option is present then the implementation makes a
+     *   <em>best effort</em> attempt to delete the file when closed by the
+     *   the {@link #close close} method. If the {@code close} method is not
+     *   invoked then a <em>best effort</em> attempt is made to delete the file
+     *   when the Java virtual machine terminates. </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
+     *   <td> When creating a new file this option is a <em>hint</em> that the
+     *   new file will be sparse. This option is ignored when not creating
+     *   a new file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation may also support additional options.
+     *
+     * <p> The {@code executor} parameter is the {@link ExecutorService} to
+     * which tasks are submitted to handle I/O events and dispatch completion
+     * results for operations initiated on resulting channel.
+     * The nature of these tasks is highly implementation specific and so care
+     * should be taken when configuring the {@code Executor}. Minimally it
+     * should support an unbounded work queue and should not run tasks on the
+     * caller thread of the {@link ExecutorService#execute execute} method.
+     * Shutting down the executor service while the channel is open results in
+     * unspecified behavior.
+     *
+     * <p> The {@code attrs} parameter is an optional array of file {@link
+     * FileAttribute file-attributes} to set atomically when creating the file.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * FileSystemProvider#newFileChannel newFileChannel} method on the
+     * provider that created the {@code Path}.
+     *
+     * @param   file
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     * @param   executor
+     *          The thread pool or {@code null} to associate the channel with
+     *          the default thread pool
+     * @param   attrs
+     *          An optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  A new asynchronous file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If the {@code file} is associated with a provider that does not
+     *          support creating asynchronous file channels, or an unsupported
+     *          open option is specified, or the array contains an attribute that
+     *          cannot be set atomically when creating the file
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public static AsynchronousFileChannel open(Path file,
+                                               Set<? extends OpenOption> options,
+                                               ExecutorService executor,
+                                               FileAttribute<?>... attrs)
+        throws IOException
+    {
+        FileSystemProvider provider = file.getFileSystem().provider();
+        return provider.newAsynchronousFileChannel(file, options, executor, attrs);
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"}) // generic array construction
+    private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning an
+     * asynchronous file channel to access the file.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     ch.{@link #open(Path,Set,ExecutorService,FileAttribute[])
+     *       open}(file, opts, null, new FileAttribute&lt;?&gt;[0]);
+     * </pre>
+     * where {@code opts} is a {@code Set} containing the options specified to
+     * this method.
+     *
+     * <p> The resulting channel is associated with default thread pool to which
+     * tasks are submitted to handle I/O events and dispatch to completion
+     * handlers that consume the result of asynchronous operations performed on
+     * the resulting channel.
+     *
+     * @param   file
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     *
+     * @return  A new asynchronous file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If the {@code file} is associated with a provider that does not
+     *          support creating file channels, or an unsupported open option is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public static AsynchronousFileChannel open(Path file, OpenOption... options)
+        throws IOException
+    {
+        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
+        Collections.addAll(set, options);
+        return open(file, set, null, NO_ATTRIBUTES);
+    }
+
+    /**
+     * Returns the current size of this channel's file.
+     *
+     * @return  The current size of this channel's file, measured in bytes
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract long size() throws IOException;
+
+    /**
+     * Truncates this channel's file to the given size.
+     *
+     * <p> If the given size is less than the file's current size then the file
+     * is truncated, discarding any bytes beyond the new end of the file.  If
+     * the given size is greater than or equal to the file's current size then
+     * the file is not modified. </p>
+     *
+     * @param  size
+     *         The new size, a non-negative byte count
+     *
+     * @return  This file channel
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IllegalArgumentException
+     *          If the new size is negative
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousFileChannel truncate(long size) throws IOException;
+
+    /**
+     * Forces any updates to this channel's file to be written to the storage
+     * device that contains it.
+     *
+     * <p> If this channel's file resides on a local storage device then when
+     * this method returns it is guaranteed that all changes made to the file
+     * since this channel was created, or since this method was last invoked,
+     * will have been written to that device.  This is useful for ensuring that
+     * critical information is not lost in the event of a system crash.
+     *
+     * <p> If the file does not reside on a local device then no such guarantee
+     * is made.
+     *
+     * <p> The {@code metaData} parameter can be used to limit the number of
+     * I/O operations that this method is required to perform.  Passing
+     * {@code false} for this parameter indicates that only updates to the
+     * file's content need be written to storage; passing {@code true}
+     * indicates that updates to both the file's content and metadata must be
+     * written, which generally requires at least one more I/O operation.
+     * Whether this parameter actually has any effect is dependent upon the
+     * underlying operating system and is therefore unspecified.
+     *
+     * <p> Invoking this method may cause an I/O operation to occur even if the
+     * channel was only opened for reading.  Some operating systems, for
+     * example, maintain a last-access time as part of a file's metadata, and
+     * this time is updated whenever the file is read.  Whether or not this is
+     * actually done is system-dependent and is therefore unspecified.
+     *
+     * <p> This method is only guaranteed to force changes that were made to
+     * this channel's file via the methods defined in this class.
+     *
+     * @param   metaData
+     *          If {@code true} then this method is required to force changes
+     *          to both the file's content and metadata to be written to
+     *          storage; otherwise, it need only force content changes to be
+     *          written
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract void force(boolean metaData) throws IOException;
+
+    /**
+     * Acquires a lock on the given region of this channel's file.
+     *
+     * <p> This method initiates an operation to acquire a lock on the given
+     * region of this channel's file. The {@code handler} parameter is a
+     * completion handler that is invoked when the lock is acquired (or the
+     * operation fails). The result passed to the completion handler is the
+     * resulting {@code FileLock}.
+     *
+     * <p> The region specified by the {@code position} and {@code size}
+     * parameters need not be contained within, or even overlap, the actual
+     * underlying file.  Lock regions are fixed in size; if a locked region
+     * initially contains the end of the file and the file grows beyond the
+     * region then the new portion of the file will not be covered by the lock.
+     * If a file is expected to grow in size and a lock on the entire file is
+     * required then a region starting at zero, and no smaller than the
+     * expected maximum size of the file, should be locked.  The two-argument
+     * {@link #lock(Object,CompletionHandler)} method simply locks a region
+     * of size {@link Long#MAX_VALUE}. If a lock that overlaps the requested
+     * region is already held by this Java virtual machine, or this method has
+     * been invoked to lock an overlapping region and that operation has not
+     * completed, then this method throws {@link OverlappingFileLockException}.
+     *
+     * <p> Some operating systems do not support a mechanism to acquire a file
+     * lock in an asynchronous manner. Consequently an implementation may
+     * acquire the file lock in a background thread or from a task executed by
+     * a thread in the associated thread pool. If there are many lock operations
+     * outstanding then it may consume threads in the Java virtual machine for
+     * indefinite periods.
+     *
+     * <p> Some operating systems do not support shared locks, in which case a
+     * request for a shared lock is automatically converted into a request for
+     * an exclusive lock.  Whether the newly-acquired lock is shared or
+     * exclusive may be tested by invoking the resulting lock object's {@link
+     * FileLock#isShared() isShared} method.
+     *
+     * <p> File locks are held on behalf of the entire Java virtual machine.
+     * They are not suitable for controlling access to a file by multiple
+     * threads within the same virtual machine.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   position
+     *          The position at which the locked region is to start; must be
+     *          non-negative
+     * @param   size
+     *          The size of the locked region; must be non-negative, and the sum
+     *          {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
+     * @param   shared
+     *          {@code true} to request a shared lock, in which case this
+     *          channel must be open for reading (and possibly writing);
+     *          {@code false} to request an exclusive lock, in which case this
+     *          channel must be open for writing (and possibly reading)
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or there is already a pending attempt
+     *          to lock an overlapping region
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     * @throws  NonReadableChannelException
+     *          If {@code shared} is true but this channel was not opened for reading
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     */
+    public abstract <A> void lock(long position,
+                                  long size,
+                                  boolean shared,
+                                  A attachment,
+                                  CompletionHandler<FileLock,? super A> handler);
+
+    /**
+     * Acquires an exclusive lock on this channel's file.
+     *
+     * <p> This method initiates an operation to acquire a lock on the given
+     * region of this channel's file. The {@code handler} parameter is a
+     * completion handler that is invoked when the lock is acquired (or the
+     * operation fails). The result passed to the completion handler is the
+     * resulting {@code FileLock}.
+     *
+     * <p> An invocation of this method of the form {@code ch.lock(att,handler)}
+     * behaves in exactly the same way as the invocation
+     * <pre>
+     *     ch.{@link #lock(long,long,boolean,Object,CompletionHandler) lock}(0L, Long.MAX_VALUE, false, att, handler)
+     * </pre>
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock is already held by this Java virtual machine, or there
+     *          is already a pending attempt to lock a region
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     */
+    public final <A> void lock(A attachment,
+                               CompletionHandler<FileLock,? super A> handler)
+    {
+        lock(0L, Long.MAX_VALUE, false, attachment, handler);
+    }
+
+    /**
+     * Acquires a lock on the given region of this channel's file.
+     *
+     * <p> This method initiates an operation to acquire a lock on the given
+     * region of this channel's file.  The method behaves in exactly the same
+     * manner as the {@link #lock(long, long, boolean, Object, CompletionHandler)}
+     * method except that instead of specifying a completion handler, this
+     * method returns a {@code Future} representing the pending result. The
+     * {@code Future}'s {@link Future#get() get} method returns the {@link
+     * FileLock} on successful completion.
+     *
+     * @param   position
+     *          The position at which the locked region is to start; must be
+     *          non-negative
+     * @param   size
+     *          The size of the locked region; must be non-negative, and the sum
+     *          {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
+     * @param   shared
+     *          {@code true} to request a shared lock, in which case this
+     *          channel must be open for reading (and possibly writing);
+     *          {@code false} to request an exclusive lock, in which case this
+     *          channel must be open for writing (and possibly reading)
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock is already held by this Java virtual machine, or there
+     *          is already a pending attempt to lock a region
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     * @throws  NonReadableChannelException
+     *          If {@code shared} is true but this channel was not opened for reading
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     */
+    public abstract Future<FileLock> lock(long position, long size, boolean shared);
+
+    /**
+     * Acquires an exclusive lock on this channel's file.
+     *
+     * <p> This method initiates an operation to acquire an exclusive lock on this
+     * channel's file. The method returns a {@code Future} representing the
+     * pending result of the operation. The {@code Future}'s {@link Future#get()
+     * get} method returns the {@link FileLock} on successful completion.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     ch.{@link #lock(long,long,boolean) lock}(0L, Long.MAX_VALUE, false)
+     * </pre>
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock is already held by this Java virtual machine, or there
+     *          is already a pending attempt to lock a region
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     */
+    public final Future<FileLock> lock() {
+        return lock(0L, Long.MAX_VALUE, false);
+    }
+
+    /**
+     * Attempts to acquire a lock on the given region of this channel's file.
+     *
+     * <p> This method does not block. An invocation always returns immediately,
+     * either having acquired a lock on the requested region or having failed to
+     * do so.  If it fails to acquire a lock because an overlapping lock is held
+     * by another program then it returns {@code null}.  If it fails to acquire
+     * a lock for any other reason then an appropriate exception is thrown.
+     *
+     * @param  position
+     *         The position at which the locked region is to start; must be
+     *         non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         {@code position}&nbsp;+&nbsp;{@code size} must be non-negative
+     *
+     * @param  shared
+     *         {@code true} to request a shared lock,
+     *         {@code false} to request an exclusive lock
+     *
+     * @return  A lock object representing the newly-acquired lock,
+     *          or {@code null} if the lock could not be acquired
+     *          because another program holds an overlapping lock
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region of the same file
+     * @throws  NonReadableChannelException
+     *          If {@code shared} is true but this channel was not opened for reading
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock(Object,CompletionHandler)
+     * @see     #lock(long,long,boolean,Object,CompletionHandler)
+     * @see     #tryLock()
+     */
+    public abstract FileLock tryLock(long position, long size, boolean shared)
+        throws IOException;
+
+    /**
+     * Attempts to acquire an exclusive lock on this channel's file.
+     *
+     * <p> An invocation of this method of the form {@code ch.tryLock()}
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     ch.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) </pre>
+     *
+     * @return  A lock object representing the newly-acquired lock,
+     *          or {@code null} if the lock could not be acquired
+     *          because another program holds an overlapping lock
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region
+     * @throws  NonWritableChannelException
+     *          If {@code shared} is false but this channel was not opened for writing
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock(Object,CompletionHandler)
+     * @see     #lock(long,long,boolean,Object,CompletionHandler)
+     * @see     #tryLock(long,long,boolean)
+     */
+    public final FileLock tryLock() throws IOException {
+        return tryLock(0L, Long.MAX_VALUE, false);
+    }
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer,
+     * starting at the given file position.
+     *
+     * <p> This method initiates the reading of a sequence of bytes from this
+     * channel into the given buffer, starting at the given file position. The
+     * result of the read is the number of bytes read or {@code -1} if the given
+     * position is greater than or equal to the file's size at the time that the
+     * read is attempted.
+     *
+     * <p> This method works in the same manner as the {@link
+     * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)}
+     * method, except that bytes are read starting at the given file position.
+     * If the given file position is greater than the file's size at the time
+     * that the read is attempted then no bytes are read.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative or the buffer is read-only
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     */
+    public abstract <A> void read(ByteBuffer dst,
+                                  long position,
+                                  A attachment,
+                                  CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer,
+     * starting at the given file position.
+     *
+     * <p> This method initiates the reading of a sequence of bytes from this
+     * channel into the given buffer, starting at the given file position. This
+     * method returns a {@code Future} representing the pending result of the
+     * operation. The {@code Future}'s {@link Future#get() get} method returns
+     * the number of bytes read or {@code -1} if the given position is greater
+     * than or equal to the file's size at the time that the read is attempted.
+     *
+     * <p> This method works in the same manner as the {@link
+     * AsynchronousByteChannel#read(ByteBuffer)} method, except that bytes are
+     * read starting at the given file position. If the given file position is
+     * greater than the file's size at the time that the read is attempted then
+     * no bytes are read.
+     *
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative or the buffer is read-only
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     */
+    public abstract Future<Integer> read(ByteBuffer dst, long position);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer, starting
+     * at the given file position.
+     *
+     * <p> This method works in the same manner as the {@link
+     * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
+     * method, except that bytes are written starting at the given file position.
+     * If the given position is greater than the file's size, at the time that
+     * the write is attempted, then the file will be grown to accommodate the new
+     * bytes; the values of any bytes between the previous end-of-file and the
+     * newly-written bytes are unspecified.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   src
+     *          The buffer from which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     */
+    public abstract <A> void write(ByteBuffer src,
+                                   long position,
+                                   A attachment,
+                                   CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer, starting
+     * at the given file position.
+     *
+     * <p> This method initiates the writing of a sequence of bytes to this
+     * channel from the given buffer, starting at the given file position. The
+     * method returns a {@code Future} representing the pending result of the
+     * write operation. The {@code Future}'s {@link Future#get() get} method
+     * returns the number of bytes written.
+     *
+     * <p> This method works in the same manner as the {@link
+     * AsynchronousByteChannel#write(ByteBuffer)} method, except that bytes are
+     * written starting at the given file position. If the given position is
+     * greater than the file's size, at the time that the write is attempted,
+     * then the file will be grown to accommodate the new bytes; the values of
+     * any bytes between the previous end-of-file and the newly-written bytes
+     * are unspecified.
+     *
+     * @param   src
+     *          The buffer from which bytes are to be transferred
+     * @param   position
+     *          The file position at which the transfer is to begin;
+     *          must be non-negative
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     */
+    public abstract Future<Integer> write(ByteBuffer src, long position);
+}
diff --git a/java/nio/channels/AsynchronousServerSocketChannel.java b/java/nio/channels/AsynchronousServerSocketChannel.java
new file mode 100644
index 0000000..29ecbd6
--- /dev/null
+++ b/java/nio/channels/AsynchronousServerSocketChannel.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.concurrent.Future;
+import java.io.IOException;
+
+/**
+ * An asynchronous channel for stream-oriented listening sockets.
+ *
+ * <p> An asynchronous server-socket channel is created by invoking the
+ * {@link #open open} method of this class.
+ * A newly-created asynchronous server-socket channel is open but not yet bound.
+ * It can be bound to a local address and configured to listen for connections
+ * by invoking the {@link #bind(SocketAddress,int) bind} method. Once bound,
+ * the {@link #accept(Object,CompletionHandler) accept} method
+ * is used to initiate the accepting of connections to the channel's socket.
+ * An attempt to invoke the <tt>accept</tt> method on an unbound channel will
+ * cause a {@link NotYetBoundException} to be thrown.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads
+ * though at most one accept operation can be outstanding at any time.
+ * If a thread initiates an accept operation before a previous accept operation
+ * has completed then an {@link AcceptPendingException} will be thrown.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Channels of this type support the following options:
+ * <blockquote>
+ * <table border summary="Socket options">
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *  final AsynchronousServerSocketChannel listener =
+ *      AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000));
+ *
+ *  listener.accept(null, new CompletionHandler&lt;AsynchronousSocketChannel,Void&gt;() {
+ *      public void completed(AsynchronousSocketChannel ch, Void att) {
+ *          // accept the next connection
+ *          listener.accept(null, this);
+ *
+ *          // handle this connection
+ *          handle(ch);
+ *      }
+ *      public void failed(Throwable exc, Void att) {
+ *          ...
+ *      }
+ *  });
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousServerSocketChannel
+    implements AsynchronousChannel, NetworkChannel
+{
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this channel
+     */
+    protected AsynchronousServerSocketChannel(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     *
+     * @return  The provider that created this channel
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Opens an asynchronous server-socket channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousServerSocketChannel
+     * openAsynchronousServerSocketChannel} method on the {@link
+     * java.nio.channels.spi.AsynchronousChannelProvider} object that created
+     * the given group. If the group parameter is <tt>null</tt> then the
+     * resulting channel is created by the system-wide default provider, and
+     * bound to the <em>default group</em>.
+     *
+     * @param   group
+     *          The group to which the newly constructed channel should be bound,
+     *          or <tt>null</tt> for the default group
+     *
+     * @return  A new asynchronous server socket channel
+     *
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousServerSocketChannel open(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        AsynchronousChannelProvider provider = (group == null) ?
+            AsynchronousChannelProvider.provider() : group.provider();
+        return provider.openAsynchronousServerSocketChannel(group);
+    }
+
+    /**
+     * Opens an asynchronous server-socket channel.
+     *
+     * <p> This method returns an asynchronous server socket channel that is
+     * bound to the <em>default group</em>. This method is equivalent to evaluating
+     * the expression:
+     * <blockquote><pre>
+     * open((AsynchronousChannelGroup)null);
+     * </pre></blockquote>
+     *
+     * @return  A new asynchronous server socket channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousServerSocketChannel open()
+        throws IOException
+    {
+        return open(null);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket to
+     * listen for connections.
+     *
+     * <p> An invocation of this method is equivalent to the following:
+     * <blockquote><pre>
+     * bind(local, 0);
+     * </pre></blockquote>
+     *
+     * @param   local
+     *          The local address to bind the socket, or <tt>null</tt> to bind
+     *          to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  SecurityException                   {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     */
+    public final AsynchronousServerSocketChannel bind(SocketAddress local)
+        throws IOException
+    {
+        return bind(local, 0);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket to
+     * listen for connections.
+     *
+     * <p> This method is used to establish an association between the socket and
+     * a local address. Once an association is established then the socket remains
+     * bound until the associated channel is closed.
+     *
+     * <p> The {@code backlog} parameter is the maximum number of pending
+     * connections on the socket. Its exact semantics are implementation specific.
+     * In particular, an implementation may impose a maximum length or may choose
+     * to ignore the parameter altogther. If the {@code backlog} parameter has
+     * the value {@code 0}, or a negative value, then an implementation specific
+     * default is used.
+     *
+     * @param   local
+     *          The local address to bind the socket, or {@code null} to bind
+     *          to an automatically assigned socket address
+     * @param   backlog
+     *          The maximum number of pending connections
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException
+     *          If the socket is already bound
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the operation
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     */
+    public abstract <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Accepts a connection.
+     *
+     * <p> This method initiates an asynchronous operation to accept a
+     * connection made to this channel's socket. The {@code handler} parameter is
+     * a completion handler that is invoked when a connection is accepted (or
+     * the operation fails). The result passed to the completion handler is
+     * the {@link AsynchronousSocketChannel} to the new connection.
+     *
+     * <p> When a new connection is accepted then the resulting {@code
+     * AsynchronousSocketChannel} will be bound to the same {@link
+     * AsynchronousChannelGroup} as this channel. If the group is {@link
+     * AsynchronousChannelGroup#isShutdown shutdown} and a connection is accepted,
+     * then the connection is closed, and the operation completes with an {@code
+     * IOException} and cause {@link ShutdownChannelGroupException}.
+     *
+     * <p> To allow for concurrent handling of new connections, the completion
+     * handler is not invoked directly by the initiating thread when a new
+     * connection is accepted immediately (see <a
+     * href="AsynchronousChannelGroup.html#threading">Threading</a>).
+     *
+     * <p> If a security manager has been installed then it verifies that the
+     * address and port number of the connection's remote endpoint are permitted
+     * by the security manager's {@link SecurityManager#checkAccept checkAccept}
+     * method. The permission check is performed with privileges that are restricted
+     * by the calling context of this method. If the permission check fails then
+     * the connection is closed and the operation completes with a {@link
+     * SecurityException}.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  AcceptPendingException
+     *          If an accept operation is already in progress on this channel
+     * @throws  NotYetBoundException
+     *          If this channel's socket has not yet been bound
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    public abstract <A> void accept(A attachment,
+                                    CompletionHandler<AsynchronousSocketChannel,? super A> handler);
+
+    /**
+     * Accepts a connection.
+     *
+     * <p> This method initiates an asynchronous operation to accept a
+     * connection made to this channel's socket. The method behaves in exactly
+     * the same manner as the {@link #accept(Object, CompletionHandler)} method
+     * except that instead of specifying a completion handler, this method
+     * returns a {@code Future} representing the pending result. The {@code
+     * Future}'s {@link Future#get() get} method returns the {@link
+     * AsynchronousSocketChannel} to the new connection on successful completion.
+     *
+     * @return  a {@code Future} object representing the pending result
+     *
+     * @throws  AcceptPendingException
+     *          If an accept operation is already in progress on this channel
+     * @throws  NotYetBoundException
+     *          If this channel's socket has not yet been bound
+     */
+    public abstract Future<AsynchronousSocketChannel> accept();
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+}
diff --git a/java/nio/channels/AsynchronousSocketChannel.java b/java/nio/channels/AsynchronousSocketChannel.java
new file mode 100644
index 0000000..1ed1e86
--- /dev/null
+++ b/java/nio/channels/AsynchronousSocketChannel.java
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Future;
+import java.io.IOException;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+
+/**
+ * An asynchronous channel for stream-oriented connecting sockets.
+ *
+ * <p> Asynchronous socket channels are created in one of two ways. A newly-created
+ * {@code AsynchronousSocketChannel} is created by invoking one of the {@link
+ * #open open} methods defined by this class. A newly-created channel is open but
+ * not yet connected. A connected {@code AsynchronousSocketChannel} is created
+ * when a connection is made to the socket of an {@link AsynchronousServerSocketChannel}.
+ * It is not possible to create an asynchronous socket channel for an arbitrary,
+ * pre-existing {@link java.net.Socket socket}.
+ *
+ * <p> A newly-created channel is connected by invoking its {@link #connect connect}
+ * method; once connected, a channel remains connected until it is closed.  Whether
+ * or not a socket channel is connected may be determined by invoking its {@link
+ * #getRemoteAddress getRemoteAddress} method. An attempt to invoke an I/O
+ * operation upon an unconnected channel will cause a {@link NotYetConnectedException}
+ * to be thrown.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads.
+ * They support concurrent reading and writing, though at most one read operation
+ * and one write operation can be outstanding at any time.
+ * If a thread initiates a read operation before a previous read operation has
+ * completed then a {@link ReadPendingException} will be thrown. Similarly, an
+ * attempt to initiate a write operation before a previous write has completed
+ * will throw a {@link WritePendingException}.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Asynchronous socket channels support the following options:
+ * <blockquote>
+ * <table border summary="Socket options">
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE} </td>
+ *     <td> Keep connection alive </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#TCP_NODELAY TCP_NODELAY} </td>
+ *     <td> Disable the Nagle algorithm </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <h2>Timeouts</h2>
+ *
+ * <p> The {@link #read(ByteBuffer,long,TimeUnit,Object,CompletionHandler) read}
+ * and {@link #write(ByteBuffer,long,TimeUnit,Object,CompletionHandler) write}
+ * methods defined by this class allow a timeout to be specified when initiating
+ * a read or write operation. If the timeout elapses before an operation completes
+ * then the operation completes with the exception {@link
+ * InterruptedByTimeoutException}. A timeout may leave the channel, or the
+ * underlying connection, in an inconsistent state. Where the implementation
+ * cannot guarantee that bytes have not been read from the channel then it puts
+ * the channel into an implementation specific <em>error state</em>. A subsequent
+ * attempt to initiate a {@code read} operation causes an unspecified runtime
+ * exception to be thrown. Similarly if a {@code write} operation times out and
+ * the implementation cannot guarantee bytes have not been written to the
+ * channel then further attempts to {@code write} to the channel cause an
+ * unspecified runtime exception to be thrown. When a timeout elapses then the
+ * state of the {@link ByteBuffer}, or the sequence of buffers, for the I/O
+ * operation is not defined. Buffers should be discarded or at least care must
+ * be taken to ensure that the buffers are not accessed while the channel remains
+ * open. All methods that accept timeout parameters treat values less than or
+ * equal to zero to mean that the I/O operation does not timeout.
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousSocketChannel
+    implements AsynchronousByteChannel, NetworkChannel
+{
+    private final AsynchronousChannelProvider provider;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this channel
+     */
+    protected AsynchronousSocketChannel(AsynchronousChannelProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     *
+     * @return  The provider that created this channel
+     */
+    public final AsynchronousChannelProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Opens an asynchronous socket channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * AsynchronousChannelProvider#openAsynchronousSocketChannel
+     * openAsynchronousSocketChannel} method on the {@link
+     * AsynchronousChannelProvider} that created the group. If the group parameter
+     * is {@code null} then the resulting channel is created by the system-wide
+     * default provider, and bound to the <em>default group</em>.
+     *
+     * @param   group
+     *          The group to which the newly constructed channel should be bound,
+     *          or {@code null} for the default group
+     *
+     * @return  A new asynchronous socket channel
+     *
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousSocketChannel open(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        AsynchronousChannelProvider provider = (group == null) ?
+            AsynchronousChannelProvider.provider() : group.provider();
+        return provider.openAsynchronousSocketChannel(group);
+    }
+
+    /**
+     * Opens an asynchronous socket channel.
+     *
+     * <p> This method returns an asynchronous socket channel that is bound to
+     * the <em>default group</em>.This method is equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * open((AsynchronousChannelGroup)null);
+     * </pre></blockquote>
+     *
+     * @return  A new asynchronous socket channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static AsynchronousSocketChannel open()
+        throws IOException
+    {
+        return open(null);
+    }
+
+
+    // -- socket options and related --
+
+    /**
+     * @throws  ConnectionPendingException
+     *          If a connection operation is already in progress on this channel
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its
+     *          {@link SecurityManager#checkListen checkListen} method denies
+     *          the operation
+     */
+    @Override
+    public abstract AsynchronousSocketChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     */
+    @Override
+    public abstract <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Shutdown the connection for reading without closing the channel.
+     *
+     * <p> Once shutdown for reading then further reads on the channel will
+     * return {@code -1}, the end-of-stream indication. If the input side of the
+     * connection is already shutdown then invoking this method has no effect.
+     * The effect on an outstanding read operation is system dependent and
+     * therefore not specified. The effect, if any, when there is data in the
+     * socket receive buffer that has not been read, or data arrives subsequently,
+     * is also system dependent.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousSocketChannel shutdownInput() throws IOException;
+
+    /**
+     * Shutdown the connection for writing without closing the channel.
+     *
+     * <p> Once shutdown for writing then further attempts to write to the
+     * channel will throw {@link ClosedChannelException}. If the output side of
+     * the connection is already shutdown then invoking this method has no
+     * effect. The effect on an outstanding write operation is system dependent
+     * and therefore not specified.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract AsynchronousSocketChannel shutdownOutput() throws IOException;
+
+    // -- state --
+
+    /**
+     * Returns the remote address to which this channel's socket is connected.
+     *
+     * <p> Where the channel is bound and connected to an Internet Protocol
+     * socket address then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract SocketAddress getRemoteAddress() throws IOException;
+
+    // -- asynchronous operations --
+
+    /**
+     * Connects this channel.
+     *
+     * <p> This method initiates an operation to connect this channel. The
+     * {@code handler} parameter is a completion handler that is invoked when
+     * the connection is successfully established or connection cannot be
+     * established. If the connection cannot be established then the channel is
+     * closed.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.Socket} class.  That is, if a security manager has been
+     * installed then this method verifies that its {@link
+     * java.lang.SecurityManager#checkConnect checkConnect} method permits
+     * connecting to the address and port number of the given remote endpoint.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   remote
+     *          The remote address to which this channel is to be connected
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  AlreadyConnectedException
+     *          If this channel is already connected
+     * @throws  ConnectionPendingException
+     *          If a connection operation is already in progress on this channel
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote endpoint
+     *
+     * @see #getRemoteAddress
+     */
+    public abstract <A> void connect(SocketAddress remote,
+                                     A attachment,
+                                     CompletionHandler<Void,? super A> handler);
+
+    /**
+     * Connects this channel.
+     *
+     * <p> This method initiates an operation to connect this channel. This
+     * method behaves in exactly the same manner as the {@link
+     * #connect(SocketAddress, Object, CompletionHandler)} method except that
+     * instead of specifying a completion handler, this method returns a {@code
+     * Future} representing the pending result. The {@code Future}'s {@link
+     * Future#get() get} method returns {@code null} on successful completion.
+     *
+     * @param   remote
+     *          The remote address to which this channel is to be connected
+     *
+     * @return  A {@code Future} object representing the pending result
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     * @throws  AlreadyConnectedException
+     *          If this channel is already connected
+     * @throws  ConnectionPendingException
+     *          If a connection operation is already in progress on this channel
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote endpoint
+     */
+    public abstract Future<Void> connect(SocketAddress remote);
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> This method initiates an asynchronous read operation to read a
+     * sequence of bytes from this channel into the given buffer. The {@code
+     * handler} parameter is a completion handler that is invoked when the read
+     * operation completes (or fails). The result passed to the completion
+     * handler is the number of bytes read or {@code -1} if no bytes could be
+     * read because the channel has reached end-of-stream.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then the operation completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been read, or will not
+     * be read from the channel into the given buffer, then further attempts to
+     * read from the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * <p> Otherwise this method works in the same manner as the {@link
+     * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)}
+     * method.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   dst
+     *          The buffer into which bytes are to be transferred
+     * @param   timeout
+     *          The maximum time for the I/O operation to complete
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ReadPendingException
+     *          If a read operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    public abstract <A> void read(ByteBuffer dst,
+                                  long timeout,
+                                  TimeUnit unit,
+                                  A attachment,
+                                  CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  ReadPendingException            {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    @Override
+    public final <A> void read(ByteBuffer dst,
+                               A attachment,
+                               CompletionHandler<Integer,? super A> handler)
+    {
+        read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * @throws  IllegalArgumentException        {@inheritDoc}
+     * @throws  ReadPendingException            {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    @Override
+    public abstract Future<Integer> read(ByteBuffer dst);
+
+    /**
+     * Reads a sequence of bytes from this channel into a subsequence of the
+     * given buffers. This operation, sometimes called a <em>scattering read</em>,
+     * is often useful when implementing network protocols that group data into
+     * segments consisting of one or more fixed-length headers followed by a
+     * variable-length body. The {@code handler} parameter is a completion
+     * handler that is invoked when the read operation completes (or fails). The
+     * result passed to the completion handler is the number of bytes read or
+     * {@code -1} if no bytes could be read because the channel has reached
+     * end-of-stream.
+     *
+     * <p> This method initiates a read of up to <i>r</i> bytes from this channel,
+     * where <i>r</i> is the total number of bytes remaining in the specified
+     * subsequence of the given buffer array, that is,
+     *
+     * <blockquote><pre>
+     * dsts[offset].remaining()
+     *     + dsts[offset+1].remaining()
+     *     + ... + dsts[offset+length-1].remaining()</pre></blockquote>
+     *
+     * at the moment that the read is attempted.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * Up to the first <tt>dsts[offset].remaining()</tt> bytes of this sequence
+     * are transferred into buffer <tt>dsts[offset]</tt>, up to the next
+     * <tt>dsts[offset+1].remaining()</tt> bytes are transferred into buffer
+     * <tt>dsts[offset+1]</tt>, and so forth, until the entire byte sequence
+     * is transferred into the given buffers.  As many bytes as possible are
+     * transferred into each buffer, hence the final position of each updated
+     * buffer, except the last updated buffer, is guaranteed to be equal to
+     * that buffer's limit. The underlying operating system may impose a limit
+     * on the number of buffers that may be used in an I/O operation. Where the
+     * number of buffers (with bytes remaining), exceeds this limit, then the
+     * I/O operation is performed with the maximum number of buffers allowed by
+     * the operating system.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then it completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been read, or will not
+     * be read from the channel into the given buffers, then further attempts to
+     * read from the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   dsts
+     *          The buffers into which bytes are to be transferred
+     * @param   offset
+     *          The offset within the buffer array of the first buffer into which
+     *          bytes are to be transferred; must be non-negative and no larger than
+     *          {@code dsts.length}
+     * @param   length
+     *          The maximum number of buffers to be accessed; must be non-negative
+     *          and no larger than {@code dsts.length - offset}
+     * @param   timeout
+     *          The maximum time for the I/O operation to complete
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the pre-conditions for the {@code offset}  and {@code length}
+     *          parameter aren't met
+     * @throws  IllegalArgumentException
+     *          If the buffer is read-only
+     * @throws  ReadPendingException
+     *          If a read operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    public abstract <A> void read(ByteBuffer[] dsts,
+                                  int offset,
+                                  int length,
+                                  long timeout,
+                                  TimeUnit unit,
+                                  A attachment,
+                                  CompletionHandler<Long,? super A> handler);
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> This method initiates an asynchronous write operation to write a
+     * sequence of bytes to this channel from the given buffer. The {@code
+     * handler} parameter is a completion handler that is invoked when the write
+     * operation completes (or fails). The result passed to the completion
+     * handler is the number of bytes written.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then it completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been written, or will
+     * not be written to the channel from the given buffer, then further attempts
+     * to write to the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * <p> Otherwise this method works in the same manner as the {@link
+     * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
+     * method.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   src
+     *          The buffer from which bytes are to be retrieved
+     * @param   timeout
+     *          The maximum time for the I/O operation to complete
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  WritePendingException
+     *          If a write operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    public abstract <A> void write(ByteBuffer src,
+                                   long timeout,
+                                   TimeUnit unit,
+                                   A attachment,
+                                   CompletionHandler<Integer,? super A> handler);
+
+    /**
+     * @throws  WritePendingException          {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    @Override
+    public final <A> void write(ByteBuffer src,
+                                A attachment,
+                                CompletionHandler<Integer,? super A> handler)
+
+    {
+        write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+    }
+
+    /**
+     * @throws  WritePendingException       {@inheritDoc}
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    @Override
+    public abstract Future<Integer> write(ByteBuffer src);
+
+    /**
+     * Writes a sequence of bytes to this channel from a subsequence of the given
+     * buffers. This operation, sometimes called a <em>gathering write</em>, is
+     * often useful when implementing network protocols that group data into
+     * segments consisting of one or more fixed-length headers followed by a
+     * variable-length body. The {@code handler} parameter is a completion
+     * handler that is invoked when the write operation completes (or fails).
+     * The result passed to the completion handler is the number of bytes written.
+     *
+     * <p> This method initiates a write of up to <i>r</i> bytes to this channel,
+     * where <i>r</i> is the total number of bytes remaining in the specified
+     * subsequence of the given buffer array, that is,
+     *
+     * <blockquote><pre>
+     * srcs[offset].remaining()
+     *     + srcs[offset+1].remaining()
+     *     + ... + srcs[offset+length-1].remaining()</pre></blockquote>
+     *
+     * at the moment that the write is attempted.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+     * <tt>0</tt>&nbsp;<tt>&lt;</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * Up to the first <tt>srcs[offset].remaining()</tt> bytes of this sequence
+     * are written from buffer <tt>srcs[offset]</tt>, up to the next
+     * <tt>srcs[offset+1].remaining()</tt> bytes are written from buffer
+     * <tt>srcs[offset+1]</tt>, and so forth, until the entire byte sequence is
+     * written.  As many bytes as possible are written from each buffer, hence
+     * the final position of each updated buffer, except the last updated
+     * buffer, is guaranteed to be equal to that buffer's limit. The underlying
+     * operating system may impose a limit on the number of buffers that may be
+     * used in an I/O operation. Where the number of buffers (with bytes
+     * remaining), exceeds this limit, then the I/O operation is performed with
+     * the maximum number of buffers allowed by the operating system.
+     *
+     * <p> If a timeout is specified and the timeout elapses before the operation
+     * completes then it completes with the exception {@link
+     * InterruptedByTimeoutException}. Where a timeout occurs, and the
+     * implementation cannot guarantee that bytes have not been written, or will
+     * not be written to the channel from the given buffers, then further attempts
+     * to write to the channel will cause an unspecific runtime exception to be
+     * thrown.
+     *
+     * @param   <A>
+     *          The type of the attachment
+     * @param   srcs
+     *          The buffers from which bytes are to be retrieved
+     * @param   offset
+     *          The offset within the buffer array of the first buffer from which
+     *          bytes are to be retrieved; must be non-negative and no larger
+     *          than {@code srcs.length}
+     * @param   length
+     *          The maximum number of buffers to be accessed; must be non-negative
+     *          and no larger than {@code srcs.length - offset}
+     * @param   timeout
+     *          The maximum time for the I/O operation to complete
+     * @param   unit
+     *          The time unit of the {@code timeout} argument
+     * @param   attachment
+     *          The object to attach to the I/O operation; can be {@code null}
+     * @param   handler
+     *          The handler for consuming the result
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the pre-conditions for the {@code offset}  and {@code length}
+     *          parameter aren't met
+     * @throws  WritePendingException
+     *          If a write operation is already in progress on this channel
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ShutdownChannelGroupException
+     *          If the channel group has terminated
+     */
+    public abstract <A> void write(ByteBuffer[] srcs,
+                                   int offset,
+                                   int length,
+                                   long timeout,
+                                   TimeUnit unit,
+                                   A attachment,
+                                   CompletionHandler<Long,? super A> handler);
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    public abstract SocketAddress getLocalAddress() throws IOException;
+}
diff --git a/java/nio/channels/ByteChannel.java b/java/nio/channels/ByteChannel.java
new file mode 100644
index 0000000..85d5275
--- /dev/null
+++ b/java/nio/channels/ByteChannel.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+
+
+/**
+ * A channel that can read and write bytes.  This interface simply unifies
+ * {@link ReadableByteChannel} and {@link WritableByteChannel}; it does not
+ * specify any new operations.
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface ByteChannel
+    extends ReadableByteChannel, WritableByteChannel
+{
+
+}
diff --git a/java/nio/channels/CancelledKeyException.java b/java/nio/channels/CancelledKeyException.java
new file mode 100644
index 0000000..b5306f0
--- /dev/null
+++ b/java/nio/channels/CancelledKeyException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to use
+ * a selection key that is no longer valid.
+ *
+ * @since 1.4
+ */
+
+public class CancelledKeyException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -8438032138028814268L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public CancelledKeyException() { }
+
+}
diff --git a/java/nio/channels/Channel.java b/java/nio/channels/Channel.java
new file mode 100644
index 0000000..663d0e0
--- /dev/null
+++ b/java/nio/channels/Channel.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.io.Closeable;
+
+
+/**
+ * A nexus for I/O operations.
+ *
+ * <p> A channel represents an open connection to an entity such as a hardware
+ * device, a file, a network socket, or a program component that is capable of
+ * performing one or more distinct I/O operations, for example reading or
+ * writing.
+ *
+ * <p> A channel is either open or closed.  A channel is open upon creation,
+ * and once closed it remains closed.  Once a channel is closed, any attempt to
+ * invoke an I/O operation upon it will cause a {@link ClosedChannelException}
+ * to be thrown.  Whether or not a channel is open may be tested by invoking
+ * its {@link #isOpen isOpen} method.
+ *
+ * <p> Channels are, in general, intended to be safe for multithreaded access
+ * as described in the specifications of the interfaces and classes that extend
+ * and implement this interface.
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface Channel extends Closeable {
+
+    /**
+     * Tells whether or not this channel is open.
+     *
+     * @return <tt>true</tt> if, and only if, this channel is open
+     */
+    public boolean isOpen();
+
+    /**
+     * Closes this channel.
+     *
+     * <p> After a channel is closed, any further attempt to invoke I/O
+     * operations upon it will cause a {@link ClosedChannelException} to be
+     * thrown.
+     *
+     * <p> If this channel is already closed then invoking this method has no
+     * effect.
+     *
+     * <p> This method may be invoked at any time.  If some other thread has
+     * already invoked it, however, then another invocation will block until
+     * the first invocation is complete, after which it will return without
+     * effect. </p>
+     *
+     * @throws  IOException  If an I/O error occurs
+     */
+    public void close() throws IOException;
+
+}
diff --git a/java/nio/channels/Channels.java b/java/nio/channels/Channels.java
new file mode 100644
index 0000000..1d11262
--- /dev/null
+++ b/java/nio/channels/Channels.java
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.UnsupportedCharsetException;
+import java.nio.channels.spi.AbstractInterruptibleChannel;
+import java.util.concurrent.ExecutionException;
+import sun.nio.ch.ChannelInputStream;
+import sun.nio.cs.StreamDecoder;
+import sun.nio.cs.StreamEncoder;
+
+
+/**
+ * Utility methods for channels and streams.
+ *
+ * <p> This class defines static methods that support the interoperation of the
+ * stream classes of the <tt>{@link java.io}</tt> package with the channel
+ * classes of this package.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author Mike McCloskey
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public final class Channels {
+
+    private Channels() { }              // No instantiation
+
+    private static void checkNotNull(Object o, String name) {
+        if (o == null)
+            throw new NullPointerException("\"" + name + "\" is null!");
+    }
+
+    /**
+     * Write all remaining bytes in buffer to the given channel.
+     * If the channel is selectable then it must be configured blocking.
+     */
+    private static void writeFullyImpl(WritableByteChannel ch, ByteBuffer bb)
+        throws IOException
+    {
+        while (bb.remaining() > 0) {
+            int n = ch.write(bb);
+            if (n <= 0)
+                throw new RuntimeException("no bytes written");
+        }
+    }
+
+    /**
+     * Write all remaining bytes in buffer to the given channel.
+     *
+     * @throws  IllegalBlockingModeException
+     *          If the channel is selectable and configured non-blocking.
+     */
+    private static void writeFully(WritableByteChannel ch, ByteBuffer bb)
+        throws IOException
+    {
+        if (ch instanceof SelectableChannel) {
+            SelectableChannel sc = (SelectableChannel)ch;
+            synchronized (sc.blockingLock()) {
+                if (!sc.isBlocking())
+                    throw new IllegalBlockingModeException();
+                writeFullyImpl(ch, bb);
+            }
+        } else {
+            writeFullyImpl(ch, bb);
+        }
+    }
+
+    // -- Byte streams from channels --
+
+    /**
+     * Constructs a stream that reads bytes from the given channel.
+     *
+     * <p> The <tt>read</tt> methods of the resulting stream will throw an
+     * {@link IllegalBlockingModeException} if invoked while the underlying
+     * channel is in non-blocking mode.  The stream will not be buffered, and
+     * it will not support the {@link InputStream#mark mark} or {@link
+     * InputStream#reset reset} methods.  The stream will be safe for access by
+     * multiple concurrent threads.  Closing the stream will in turn cause the
+     * channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel from which bytes will be read
+     *
+     * @return  A new input stream
+     */
+    public static InputStream newInputStream(ReadableByteChannel ch) {
+        checkNotNull(ch, "ch");
+        return new sun.nio.ch.ChannelInputStream(ch);
+    }
+
+    /**
+     * Constructs a stream that writes bytes to the given channel.
+     *
+     * <p> The <tt>write</tt> methods of the resulting stream will throw an
+     * {@link IllegalBlockingModeException} if invoked while the underlying
+     * channel is in non-blocking mode.  The stream will not be buffered.  The
+     * stream will be safe for access by multiple concurrent threads.  Closing
+     * the stream will in turn cause the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel to which bytes will be written
+     *
+     * @return  A new output stream
+     */
+    public static OutputStream newOutputStream(final WritableByteChannel ch) {
+        checkNotNull(ch, "ch");
+
+        return new OutputStream() {
+
+                private ByteBuffer bb = null;
+                private byte[] bs = null;       // Invoker's previous array
+                private byte[] b1 = null;
+
+                public synchronized void write(int b) throws IOException {
+                   if (b1 == null)
+                        b1 = new byte[1];
+                    b1[0] = (byte)b;
+                    this.write(b1);
+                }
+
+                public synchronized void write(byte[] bs, int off, int len)
+                    throws IOException
+                {
+                    if ((off < 0) || (off > bs.length) || (len < 0) ||
+                        ((off + len) > bs.length) || ((off + len) < 0)) {
+                        throw new IndexOutOfBoundsException();
+                    } else if (len == 0) {
+                        return;
+                    }
+                    ByteBuffer bb = ((this.bs == bs)
+                                     ? this.bb
+                                     : ByteBuffer.wrap(bs));
+                    bb.limit(Math.min(off + len, bb.capacity()));
+                    bb.position(off);
+                    this.bb = bb;
+                    this.bs = bs;
+                    Channels.writeFully(ch, bb);
+                }
+
+                public void close() throws IOException {
+                    ch.close();
+                }
+
+            };
+    }
+
+    /**
+     * Constructs a stream that reads bytes from the given channel.
+     *
+     * <p> The stream will not be buffered, and it will not support the {@link
+     * InputStream#mark mark} or {@link InputStream#reset reset} methods.  The
+     * stream will be safe for access by multiple concurrent threads.  Closing
+     * the stream will in turn cause the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel from which bytes will be read
+     *
+     * @return  A new input stream
+     *
+     * @since 1.7
+     */
+    public static InputStream newInputStream(final AsynchronousByteChannel ch) {
+        checkNotNull(ch, "ch");
+        return new InputStream() {
+
+            private ByteBuffer bb = null;
+            private byte[] bs = null;           // Invoker's previous array
+            private byte[] b1 = null;
+
+            @Override
+            public synchronized int read() throws IOException {
+                if (b1 == null)
+                    b1 = new byte[1];
+                int n = this.read(b1);
+                if (n == 1)
+                    return b1[0] & 0xff;
+                return -1;
+            }
+
+            @Override
+            public synchronized int read(byte[] bs, int off, int len)
+                throws IOException
+            {
+                if ((off < 0) || (off > bs.length) || (len < 0) ||
+                    ((off + len) > bs.length) || ((off + len) < 0)) {
+                    throw new IndexOutOfBoundsException();
+                } else if (len == 0)
+                    return 0;
+
+                ByteBuffer bb = ((this.bs == bs)
+                                 ? this.bb
+                                 : ByteBuffer.wrap(bs));
+                bb.position(off);
+                bb.limit(Math.min(off + len, bb.capacity()));
+                this.bb = bb;
+                this.bs = bs;
+
+                boolean interrupted = false;
+                try {
+                    for (;;) {
+                        try {
+                            return ch.read(bb).get();
+                        } catch (ExecutionException ee) {
+                            throw new IOException(ee.getCause());
+                        } catch (InterruptedException ie) {
+                            interrupted = true;
+                        }
+                    }
+                } finally {
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+            }
+
+            @Override
+            public void close() throws IOException {
+                ch.close();
+            }
+        };
+    }
+
+    /**
+     * Constructs a stream that writes bytes to the given channel.
+     *
+     * <p> The stream will not be buffered. The stream will be safe for access
+     * by multiple concurrent threads.  Closing the stream will in turn cause
+     * the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel to which bytes will be written
+     *
+     * @return  A new output stream
+     *
+     * @since 1.7
+     */
+    public static OutputStream newOutputStream(final AsynchronousByteChannel ch) {
+        checkNotNull(ch, "ch");
+        return new OutputStream() {
+
+            private ByteBuffer bb = null;
+            private byte[] bs = null;   // Invoker's previous array
+            private byte[] b1 = null;
+
+            @Override
+            public synchronized void write(int b) throws IOException {
+               if (b1 == null)
+                    b1 = new byte[1];
+                b1[0] = (byte)b;
+                this.write(b1);
+            }
+
+            @Override
+            public synchronized void write(byte[] bs, int off, int len)
+                throws IOException
+            {
+                if ((off < 0) || (off > bs.length) || (len < 0) ||
+                    ((off + len) > bs.length) || ((off + len) < 0)) {
+                    throw new IndexOutOfBoundsException();
+                } else if (len == 0) {
+                    return;
+                }
+                ByteBuffer bb = ((this.bs == bs)
+                                 ? this.bb
+                                 : ByteBuffer.wrap(bs));
+                bb.limit(Math.min(off + len, bb.capacity()));
+                bb.position(off);
+                this.bb = bb;
+                this.bs = bs;
+
+                boolean interrupted = false;
+                try {
+                    while (bb.remaining() > 0) {
+                        try {
+                            ch.write(bb).get();
+                        } catch (ExecutionException ee) {
+                            throw new IOException(ee.getCause());
+                        } catch (InterruptedException ie) {
+                            interrupted = true;
+                        }
+                    }
+                } finally {
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+            }
+
+            @Override
+            public void close() throws IOException {
+                ch.close();
+            }
+        };
+    }
+
+
+    // -- Channels from streams --
+
+    /**
+     * Constructs a channel that reads bytes from the given stream.
+     *
+     * <p> The resulting channel will not be buffered; it will simply redirect
+     * its I/O operations to the given stream.  Closing the channel will in
+     * turn cause the stream to be closed.  </p>
+     *
+     * @param  in
+     *         The stream from which bytes are to be read
+     *
+     * @return  A new readable byte channel
+     */
+    public static ReadableByteChannel newChannel(final InputStream in) {
+        checkNotNull(in, "in");
+
+        if (in instanceof FileInputStream &&
+            FileInputStream.class.equals(in.getClass())) {
+            return ((FileInputStream)in).getChannel();
+        }
+
+        return new ReadableByteChannelImpl(in);
+    }
+
+    private static class ReadableByteChannelImpl
+        extends AbstractInterruptibleChannel    // Not really interruptible
+        implements ReadableByteChannel
+    {
+        InputStream in;
+        private static final int TRANSFER_SIZE = 8192;
+        private byte buf[] = new byte[0];
+        private boolean open = true;
+        private Object readLock = new Object();
+
+        ReadableByteChannelImpl(InputStream in) {
+            this.in = in;
+        }
+
+        public int read(ByteBuffer dst) throws IOException {
+            int len = dst.remaining();
+            int totalRead = 0;
+            int bytesRead = 0;
+            synchronized (readLock) {
+                while (totalRead < len) {
+                    int bytesToRead = Math.min((len - totalRead),
+                                               TRANSFER_SIZE);
+                    if (buf.length < bytesToRead)
+                        buf = new byte[bytesToRead];
+                    if ((totalRead > 0) && !(in.available() > 0))
+                        break; // block at most once
+                    try {
+                        begin();
+                        bytesRead = in.read(buf, 0, bytesToRead);
+                    } finally {
+                        end(bytesRead > 0);
+                    }
+                    if (bytesRead < 0)
+                        break;
+                    else
+                        totalRead += bytesRead;
+                    dst.put(buf, 0, bytesRead);
+                }
+                if ((bytesRead < 0) && (totalRead == 0))
+                    return -1;
+
+                return totalRead;
+            }
+        }
+
+        protected void implCloseChannel() throws IOException {
+            in.close();
+            open = false;
+        }
+    }
+
+
+    /**
+     * Constructs a channel that writes bytes to the given stream.
+     *
+     * <p> The resulting channel will not be buffered; it will simply redirect
+     * its I/O operations to the given stream.  Closing the channel will in
+     * turn cause the stream to be closed.  </p>
+     *
+     * @param  out
+     *         The stream to which bytes are to be written
+     *
+     * @return  A new writable byte channel
+     */
+    public static WritableByteChannel newChannel(final OutputStream out) {
+        checkNotNull(out, "out");
+        return new WritableByteChannelImpl(out);
+    }
+
+    private static class WritableByteChannelImpl
+        extends AbstractInterruptibleChannel    // Not really interruptible
+        implements WritableByteChannel
+    {
+        OutputStream out;
+        private static final int TRANSFER_SIZE = 8192;
+        private byte buf[] = new byte[0];
+        private boolean open = true;
+        private Object writeLock = new Object();
+
+        WritableByteChannelImpl(OutputStream out) {
+            this.out = out;
+        }
+
+        public int write(ByteBuffer src) throws IOException {
+            int len = src.remaining();
+            int totalWritten = 0;
+            synchronized (writeLock) {
+                while (totalWritten < len) {
+                    int bytesToWrite = Math.min((len - totalWritten),
+                                                TRANSFER_SIZE);
+                    if (buf.length < bytesToWrite)
+                        buf = new byte[bytesToWrite];
+                    src.get(buf, 0, bytesToWrite);
+                    try {
+                        begin();
+                        out.write(buf, 0, bytesToWrite);
+                    } finally {
+                        end(bytesToWrite > 0);
+                    }
+                    totalWritten += bytesToWrite;
+                }
+                return totalWritten;
+            }
+        }
+
+        protected void implCloseChannel() throws IOException {
+            out.close();
+            open = false;
+        }
+    }
+
+
+    // -- Character streams from channels --
+
+    /**
+     * Constructs a reader that decodes bytes from the given channel using the
+     * given decoder.
+     *
+     * <p> The resulting stream will contain an internal input buffer of at
+     * least <tt>minBufferCap</tt> bytes.  The stream's <tt>read</tt> methods
+     * will, as needed, fill the buffer by reading bytes from the underlying
+     * channel; if the channel is in non-blocking mode when bytes are to be
+     * read then an {@link IllegalBlockingModeException} will be thrown.  The
+     * resulting stream will not otherwise be buffered, and it will not support
+     * the {@link Reader#mark mark} or {@link Reader#reset reset} methods.
+     * Closing the stream will in turn cause the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel from which bytes will be read
+     *
+     * @param  dec
+     *         The charset decoder to be used
+     *
+     * @param  minBufferCap
+     *         The minimum capacity of the internal byte buffer,
+     *         or <tt>-1</tt> if an implementation-dependent
+     *         default capacity is to be used
+     *
+     * @return  A new reader
+     */
+    public static Reader newReader(ReadableByteChannel ch,
+                                   CharsetDecoder dec,
+                                   int minBufferCap)
+    {
+        checkNotNull(ch, "ch");
+        return StreamDecoder.forDecoder(ch, dec.reset(), minBufferCap);
+    }
+
+    /**
+     * Constructs a reader that decodes bytes from the given channel according
+     * to the named charset.
+     *
+     * <p> An invocation of this method of the form
+     *
+     * <blockquote><pre>
+     * Channels.newReader(ch, csname)</pre></blockquote>
+     *
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>
+     * Channels.newReader(ch,
+     *                    Charset.forName(csName)
+     *                        .newDecoder(),
+     *                    -1);</pre></blockquote>
+     *
+     * @param  ch
+     *         The channel from which bytes will be read
+     *
+     * @param  csName
+     *         The name of the charset to be used
+     *
+     * @return  A new reader
+     *
+     * @throws  UnsupportedCharsetException
+     *          If no support for the named charset is available
+     *          in this instance of the Java virtual machine
+     */
+    public static Reader newReader(ReadableByteChannel ch,
+                                   String csName)
+    {
+        checkNotNull(csName, "csName");
+        return newReader(ch, Charset.forName(csName).newDecoder(), -1);
+    }
+
+    /**
+     * Constructs a writer that encodes characters using the given encoder and
+     * writes the resulting bytes to the given channel.
+     *
+     * <p> The resulting stream will contain an internal output buffer of at
+     * least <tt>minBufferCap</tt> bytes.  The stream's <tt>write</tt> methods
+     * will, as needed, flush the buffer by writing bytes to the underlying
+     * channel; if the channel is in non-blocking mode when bytes are to be
+     * written then an {@link IllegalBlockingModeException} will be thrown.
+     * The resulting stream will not otherwise be buffered.  Closing the stream
+     * will in turn cause the channel to be closed.  </p>
+     *
+     * @param  ch
+     *         The channel to which bytes will be written
+     *
+     * @param  enc
+     *         The charset encoder to be used
+     *
+     * @param  minBufferCap
+     *         The minimum capacity of the internal byte buffer,
+     *         or <tt>-1</tt> if an implementation-dependent
+     *         default capacity is to be used
+     *
+     * @return  A new writer
+     */
+    public static Writer newWriter(final WritableByteChannel ch,
+                                   final CharsetEncoder enc,
+                                   final int minBufferCap)
+    {
+        checkNotNull(ch, "ch");
+        return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);
+    }
+
+    /**
+     * Constructs a writer that encodes characters according to the named
+     * charset and writes the resulting bytes to the given channel.
+     *
+     * <p> An invocation of this method of the form
+     *
+     * <blockquote><pre>
+     * Channels.newWriter(ch, csname)</pre></blockquote>
+     *
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>
+     * Channels.newWriter(ch,
+     *                    Charset.forName(csName)
+     *                        .newEncoder(),
+     *                    -1);</pre></blockquote>
+     *
+     * @param  ch
+     *         The channel to which bytes will be written
+     *
+     * @param  csName
+     *         The name of the charset to be used
+     *
+     * @return  A new writer
+     *
+     * @throws  UnsupportedCharsetException
+     *          If no support for the named charset is available
+     *          in this instance of the Java virtual machine
+     */
+    public static Writer newWriter(WritableByteChannel ch,
+                                   String csName)
+    {
+        checkNotNull(csName, "csName");
+        return newWriter(ch, Charset.forName(csName).newEncoder(), -1);
+    }
+}
diff --git a/java/nio/channels/ClosedByInterruptException.java b/java/nio/channels/ClosedByInterruptException.java
new file mode 100644
index 0000000..848ee61
--- /dev/null
+++ b/java/nio/channels/ClosedByInterruptException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Checked exception received by a thread when another thread interrupts it
+ * while it is blocked in an I/O operation upon a channel.  Before this
+ * exception is thrown the channel will have been closed and the interrupt
+ * status of the previously-blocked thread will have been set.
+ *
+ * @since 1.4
+ */
+
+public class ClosedByInterruptException
+    extends AsynchronousCloseException
+{
+
+    private static final long serialVersionUID = -4488191543534286750L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedByInterruptException() { }
+
+}
diff --git a/java/nio/channels/ClosedChannelException.java b/java/nio/channels/ClosedChannelException.java
new file mode 100644
index 0000000..a9a2277
--- /dev/null
+++ b/java/nio/channels/ClosedChannelException.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Checked exception thrown when an attempt is made to invoke or complete an
+ * I/O operation upon channel that is closed, or at least closed to that
+ * operation.  That this exception is thrown does not necessarily imply that
+ * the channel is completely closed.  A socket channel whose write half has
+ * been shut down, for example, may still be open for reading.
+ *
+ * @since 1.4
+ */
+
+public class ClosedChannelException
+    extends java.io.IOException
+{
+
+    private static final long serialVersionUID = 882777185433553857L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedChannelException() { }
+
+}
diff --git a/java/nio/channels/ClosedSelectorException.java b/java/nio/channels/ClosedSelectorException.java
new file mode 100644
index 0000000..f3168c2
--- /dev/null
+++ b/java/nio/channels/ClosedSelectorException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an I/O
+ * operation upon a closed selector.
+ *
+ * @since 1.4
+ */
+
+public class ClosedSelectorException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 6466297122317847835L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedSelectorException() { }
+
+}
diff --git a/java/nio/channels/CompletionHandler.java b/java/nio/channels/CompletionHandler.java
new file mode 100644
index 0000000..2574dbf
--- /dev/null
+++ b/java/nio/channels/CompletionHandler.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+/**
+ * A handler for consuming the result of an asynchronous I/O operation.
+ *
+ * <p> The asynchronous channels defined in this package allow a completion
+ * handler to be specified to consume the result of an asynchronous operation.
+ * The {@link #completed completed} method is invoked when the I/O operation
+ * completes successfully. The {@link #failed failed} method is invoked if the
+ * I/O operations fails. The implementations of these methods should complete
+ * in a timely manner so as to avoid keeping the invoking thread from dispatching
+ * to other completion handlers.
+ *
+ * @param   <V>     The result type of the I/O operation
+ * @param   <A>     The type of the object attached to the I/O operation
+ *
+ * @since 1.7
+ */
+
+public interface CompletionHandler<V,A> {
+
+    /**
+     * Invoked when an operation has completed.
+     *
+     * @param   result
+     *          The result of the I/O operation.
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void completed(V result, A attachment);
+
+    /**
+     * Invoked when an operation fails.
+     *
+     * @param   exc
+     *          The exception to indicate why the I/O operation failed
+     * @param   attachment
+     *          The object attached to the I/O operation when it was initiated.
+     */
+    void failed(Throwable exc, A attachment);
+}
diff --git a/java/nio/channels/ConnectionPendingException.java b/java/nio/channels/ConnectionPendingException.java
new file mode 100644
index 0000000..c43927e
--- /dev/null
+++ b/java/nio/channels/ConnectionPendingException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to connect a {@link
+ * SocketChannel} for which a non-blocking connection operation is already in
+ * progress.
+ *
+ * @since 1.4
+ */
+
+public class ConnectionPendingException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 2008393366501760879L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ConnectionPendingException() { }
+
+}
diff --git a/java/nio/channels/DatagramChannel.java b/java/nio/channels/DatagramChannel.java
new file mode 100644
index 0000000..b85c98c
--- /dev/null
+++ b/java/nio/channels/DatagramChannel.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.net.DatagramSocket;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
+
+/**
+ * A selectable channel for datagram-oriented sockets.
+ *
+ * <p> A datagram channel is created by invoking one of the {@link #open open} methods
+ * of this class. It is not possible to create a channel for an arbitrary,
+ * pre-existing datagram socket. A newly-created datagram channel is open but not
+ * connected. A datagram channel need not be connected in order for the {@link #send
+ * send} and {@link #receive receive} methods to be used.  A datagram channel may be
+ * connected, by invoking its {@link #connect connect} method, in order to
+ * avoid the overhead of the security checks are otherwise performed as part of
+ * every send and receive operation.  A datagram channel must be connected in
+ * order to use the {@link #read(java.nio.ByteBuffer) read} and {@link
+ * #write(java.nio.ByteBuffer) write} methods, since those methods do not
+ * accept or return socket addresses.
+ *
+ * <p> Once connected, a datagram channel remains connected until it is
+ * disconnected or closed.  Whether or not a datagram channel is connected may
+ * be determined by invoking its {@link #isConnected isConnected} method.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. A datagram channel to an Internet Protocol socket supports
+ * the following options:
+ * <blockquote>
+ * <table border summary="Socket options">
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_BROADCAST SO_BROADCAST} </td>
+ *     <td> Allow transmission of broadcast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#IP_TOS IP_TOS} </td>
+ *     <td> The Type of Service (ToS) octet in the Internet Protocol (IP) header </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#IP_MULTICAST_IF IP_MULTICAST_IF} </td>
+ *     <td> The network interface for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#IP_MULTICAST_TTL
+ *       IP_MULTICAST_TTL} </td>
+ *     <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast
+ *       datagrams </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#IP_MULTICAST_LOOP
+ *       IP_MULTICAST_LOOP} </td>
+ *     <td> Loopback for Internet Protocol (IP) multicast datagrams </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> Datagram channels are safe for use by multiple concurrent threads.  They
+ * support concurrent reading and writing, though at most one thread may be
+ * reading and at most one thread may be writing at any given time.  </p>
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class DatagramChannel
+    extends AbstractSelectableChannel
+    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
+{
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this channel
+     */
+    protected DatagramChannel(SelectorProvider provider) {
+        super(provider);
+    }
+
+    /**
+     * Opens a datagram channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openDatagramChannel()
+     * openDatagramChannel} method of the system-wide default {@link
+     * java.nio.channels.spi.SelectorProvider} object.  The channel will not be
+     * connected.
+     *
+     * <p> The {@link ProtocolFamily ProtocolFamily} of the channel's socket
+     * is platform (and possibly configuration) dependent and therefore unspecified.
+     * The {@link #open(ProtocolFamily) open} allows the protocol family to be
+     * selected when opening a datagram channel, and should be used to open
+     * datagram channels that are intended for Internet Protocol multicasting.
+     *
+     * @return  A new datagram channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static DatagramChannel open() throws IOException {
+        return SelectorProvider.provider().openDatagramChannel();
+    }
+
+    /**
+     * Opens a datagram channel.
+     *
+     * <p> The {@code family} parameter is used to specify the {@link
+     * ProtocolFamily}. If the datagram channel is to be used for IP multicasting
+     * then this should correspond to the address type of the multicast groups
+     * that this channel will join.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openDatagramChannel(ProtocolFamily)
+     * openDatagramChannel} method of the system-wide default {@link
+     * java.nio.channels.spi.SelectorProvider} object.  The channel will not be
+     * connected.
+     *
+     * @param   family
+     *          The protocol family
+     *
+     * @return  A new datagram channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the specified protocol family is not supported. For example,
+     *          suppose the parameter is specified as {@link
+     *          java.net.StandardProtocolFamily#INET6 StandardProtocolFamily.INET6}
+     *          but IPv6 is not enabled on the platform.
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since   1.7
+     */
+    public static DatagramChannel open(ProtocolFamily family) throws IOException {
+        return SelectorProvider.provider().openDatagramChannel(family);
+    }
+
+    /**
+     * Returns an operation set identifying this channel's supported
+     * operations.
+     *
+     * <p> Datagram channels support reading and writing, so this method
+     * returns <tt>(</tt>{@link SelectionKey#OP_READ} <tt>|</tt>&nbsp;{@link
+     * SelectionKey#OP_WRITE}<tt>)</tt>.  </p>
+     *
+     * @return  The valid-operation set
+     */
+    public final int validOps() {
+        return (SelectionKey.OP_READ
+                | SelectionKey.OP_WRITE);
+    }
+
+
+    // -- Socket-specific operations --
+
+    /**
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     *
+     * @since 1.7
+     */
+    public abstract DatagramChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  UnsupportedOperationException           {@inheritDoc}
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    public abstract <T> DatagramChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Retrieves a datagram socket associated with this channel.
+     *
+     * <p> The returned object will not declare any public methods that are not
+     * declared in the {@link java.net.DatagramSocket} class.  </p>
+     *
+     * @return  A datagram socket associated with this channel
+     */
+    public abstract DatagramSocket socket();
+
+    /**
+     * Tells whether or not this channel's socket is connected.
+     *
+     * @return  {@code true} if, and only if, this channel's socket
+     *          is {@link #isOpen open} and connected
+     */
+    public abstract boolean isConnected();
+
+    /**
+     * Connects this channel's socket.
+     *
+     * <p> The channel's socket is configured so that it only receives
+     * datagrams from, and sends datagrams to, the given remote <i>peer</i>
+     * address.  Once connected, datagrams may not be received from or sent to
+     * any other address.  A datagram socket remains connected until it is
+     * explicitly disconnected or until it is closed.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.DatagramSocket#connect connect} method of the {@link
+     * java.net.DatagramSocket} class.  That is, if a security manager has been
+     * installed then this method verifies that its {@link
+     * java.lang.SecurityManager#checkAccept checkAccept} and {@link
+     * java.lang.SecurityManager#checkConnect checkConnect} methods permit
+     * datagrams to be received from and sent to, respectively, the given
+     * remote address.
+     *
+     * <p> This method may be invoked at any time.  It will not have any effect
+     * on read or write operations that are already in progress at the moment
+     * that it is invoked. If this channel's socket is not bound then this method
+     * will first cause the socket to be bound to an address that is assigned
+     * automatically, as if invoking the {@link #bind bind} method with a
+     * parameter of {@code null}. </p>
+     *
+     * @param  remote
+     *         The remote address to which this channel is to be connected
+     *
+     * @return  This datagram channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract DatagramChannel connect(SocketAddress remote)
+        throws IOException;
+
+    /**
+     * Disconnects this channel's socket.
+     *
+     * <p> The channel's socket is configured so that it can receive datagrams
+     * from, and sends datagrams to, any remote address so long as the security
+     * manager, if installed, permits it.
+     *
+     * <p> This method may be invoked at any time.  It will not have any effect
+     * on read or write operations that are already in progress at the moment
+     * that it is invoked.
+     *
+     * <p> If this channel's socket is not connected, or if the channel is
+     * closed, then invoking this method has no effect.  </p>
+     *
+     * @return  This datagram channel
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract DatagramChannel disconnect() throws IOException;
+
+    /**
+     * Returns the remote address to which this channel's socket is connected.
+     *
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketAddress getRemoteAddress() throws IOException;
+
+    /**
+     * Receives a datagram via this channel.
+     *
+     * <p> If a datagram is immediately available, or if this channel is in
+     * blocking mode and one eventually becomes available, then the datagram is
+     * copied into the given byte buffer and its source address is returned.
+     * If this channel is in non-blocking mode and a datagram is not
+     * immediately available then this method immediately returns
+     * <tt>null</tt>.
+     *
+     * <p> The datagram is transferred into the given byte buffer starting at
+     * its current position, as if by a regular {@link
+     * ReadableByteChannel#read(java.nio.ByteBuffer) read} operation.  If there
+     * are fewer bytes remaining in the buffer than are required to hold the
+     * datagram then the remainder of the datagram is silently discarded.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.DatagramSocket#receive receive} method of the {@link
+     * java.net.DatagramSocket} class.  That is, if the socket is not connected
+     * to a specific remote address and a security manager has been installed
+     * then for each datagram received this method verifies that the source's
+     * address and port number are permitted by the security manager's {@link
+     * java.lang.SecurityManager#checkAccept checkAccept} method.  The overhead
+     * of this security check can be avoided by first connecting the socket via
+     * the {@link #connect connect} method.
+     *
+     * <p> This method may be invoked at any time.  If another thread has
+     * already initiated a read operation upon this channel, however, then an
+     * invocation of this method will block until the first operation is
+     * complete. If this channel's socket is not bound then this method will
+     * first cause the socket to be bound to an address that is assigned
+     * automatically, as if invoking the {@link #bind bind} method with a
+     * parameter of {@code null}. </p>
+     *
+     * @param  dst
+     *         The buffer into which the datagram is to be transferred
+     *
+     * @return  The datagram's source address,
+     *          or <tt>null</tt> if this channel is in non-blocking mode
+     *          and no datagram was immediately available
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit datagrams to be accepted
+     *          from the datagram's sender
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SocketAddress receive(ByteBuffer dst) throws IOException;
+
+    /**
+     * Sends a datagram via this channel.
+     *
+     * <p> If this channel is in non-blocking mode and there is sufficient room
+     * in the underlying output buffer, or if this channel is in blocking mode
+     * and sufficient room becomes available, then the remaining bytes in the
+     * given buffer are transmitted as a single datagram to the given target
+     * address.
+     *
+     * <p> The datagram is transferred from the byte buffer as if by a regular
+     * {@link WritableByteChannel#write(java.nio.ByteBuffer) write} operation.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.DatagramSocket#send send} method of the {@link
+     * java.net.DatagramSocket} class.  That is, if the socket is not connected
+     * to a specific remote address and a security manager has been installed
+     * then for each datagram sent this method verifies that the target address
+     * and port number are permitted by the security manager's {@link
+     * java.lang.SecurityManager#checkConnect checkConnect} method.  The
+     * overhead of this security check can be avoided by first connecting the
+     * socket via the {@link #connect connect} method.
+     *
+     * <p> This method may be invoked at any time.  If another thread has
+     * already initiated a write operation upon this channel, however, then an
+     * invocation of this method will block until the first operation is
+     * complete. If this channel's socket is not bound then this method will
+     * first cause the socket to be bound to an address that is assigned
+     * automatically, as if by invoking the {@link #bind bind} method with a
+     * parameter of {@code null}. </p>
+     *
+     * @param  src
+     *         The buffer containing the datagram to be sent
+     *
+     * @param  target
+     *         The address to which the datagram is to be sent
+     *
+     * @return   The number of bytes sent, which will be either the number
+     *           of bytes that were remaining in the source buffer when this
+     *           method was invoked or, if this channel is non-blocking, may be
+     *           zero if there was insufficient room for the datagram in the
+     *           underlying output buffer
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit datagrams to be sent
+     *          to the given address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract int send(ByteBuffer src, SocketAddress target)
+        throws IOException;
+
+
+    // -- ByteChannel operations --
+
+    /**
+     * Reads a datagram from this channel.
+     *
+     * <p> This method may only be invoked if this channel's socket is
+     * connected, and it only accepts datagrams from the socket's peer.  If
+     * there are more bytes in the datagram than remain in the given buffer
+     * then the remainder of the datagram is silently discarded.  Otherwise
+     * this method behaves exactly as specified in the {@link
+     * ReadableByteChannel} interface.  </p>
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel's socket is not connected
+     */
+    public abstract int read(ByteBuffer dst) throws IOException;
+
+    /**
+     * Reads a datagram from this channel.
+     *
+     * <p> This method may only be invoked if this channel's socket is
+     * connected, and it only accepts datagrams from the socket's peer.  If
+     * there are more bytes in the datagram than remain in the given buffers
+     * then the remainder of the datagram is silently discarded.  Otherwise
+     * this method behaves exactly as specified in the {@link
+     * ScatteringByteChannel} interface.  </p>
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel's socket is not connected
+     */
+    public abstract long read(ByteBuffer[] dsts, int offset, int length)
+        throws IOException;
+
+    /**
+     * Reads a datagram from this channel.
+     *
+     * <p> This method may only be invoked if this channel's socket is
+     * connected, and it only accepts datagrams from the socket's peer.  If
+     * there are more bytes in the datagram than remain in the given buffers
+     * then the remainder of the datagram is silently discarded.  Otherwise
+     * this method behaves exactly as specified in the {@link
+     * ScatteringByteChannel} interface.  </p>
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel's socket is not connected
+     */
+    public final long read(ByteBuffer[] dsts) throws IOException {
+        return read(dsts, 0, dsts.length);
+    }
+
+    /**
+     * Writes a datagram to this channel.
+     *
+     * <p> This method may only be invoked if this channel's socket is
+     * connected, in which case it sends datagrams directly to the socket's
+     * peer.  Otherwise it behaves exactly as specified in the {@link
+     * WritableByteChannel} interface.  </p>
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel's socket is not connected
+     */
+    public abstract int write(ByteBuffer src) throws IOException;
+
+    /**
+     * Writes a datagram to this channel.
+     *
+     * <p> This method may only be invoked if this channel's socket is
+     * connected, in which case it sends datagrams directly to the socket's
+     * peer.  Otherwise it behaves exactly as specified in the {@link
+     * GatheringByteChannel} interface.  </p>
+     *
+     * @return   The number of bytes sent, which will be either the number
+     *           of bytes that were remaining in the source buffer when this
+     *           method was invoked or, if this channel is non-blocking, may be
+     *           zero if there was insufficient room for the datagram in the
+     *           underlying output buffer
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel's socket is not connected
+     */
+    public abstract long write(ByteBuffer[] srcs, int offset, int length)
+        throws IOException;
+
+    /**
+     * Writes a datagram to this channel.
+     *
+     * <p> This method may only be invoked if this channel's socket is
+     * connected, in which case it sends datagrams directly to the socket's
+     * peer.  Otherwise it behaves exactly as specified in the {@link
+     * GatheringByteChannel} interface.  </p>
+     *
+     * @return   The number of bytes sent, which will be either the number
+     *           of bytes that were remaining in the source buffer when this
+     *           method was invoked or, if this channel is non-blocking, may be
+     *           zero if there was insufficient room for the datagram in the
+     *           underlying output buffer
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel's socket is not connected
+     */
+    public final long write(ByteBuffer[] srcs) throws IOException {
+        return write(srcs, 0, srcs.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+
+}
diff --git a/java/nio/channels/FileChannel.java b/java/nio/channels/FileChannel.java
new file mode 100644
index 0000000..a23f1c3
--- /dev/null
+++ b/java/nio/channels/FileChannel.java
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.spi.AbstractInterruptibleChannel;
+import java.nio.file.*;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.spi.*;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+
+/**
+ * A channel for reading, writing, mapping, and manipulating a file.
+ *
+ * <p> A file channel is a {@link SeekableByteChannel} that is connected to
+ * a file. It has a current <i>position</i> within its file which can
+ * be both {@link #position() <i>queried</i>} and {@link #position(long)
+ * <i>modified</i>}.  The file itself contains a variable-length sequence
+ * of bytes that can be read and written and whose current {@link #size
+ * <i>size</i>} can be queried.  The size of the file increases
+ * when bytes are written beyond its current size; the size of the file
+ * decreases when it is {@link #truncate <i>truncated</i>}.  The
+ * file may also have some associated <i>metadata</i> such as access
+ * permissions, content type, and last-modification time; this class does not
+ * define methods for metadata access.
+ *
+ * <p> In addition to the familiar read, write, and close operations of byte
+ * channels, this class defines the following file-specific operations: </p>
+ *
+ * <ul>
+ *
+ *   <li><p> Bytes may be {@link #read(ByteBuffer, long) read} or
+ *   {@link #write(ByteBuffer, long) <i>written</i>} at an absolute
+ *   position in a file in a way that does not affect the channel's current
+ *   position.  </p></li>
+ *
+ *   <li><p> A region of a file may be {@link #map <i>mapped</i>}
+ *   directly into memory; for large files this is often much more efficient
+ *   than invoking the usual <tt>read</tt> or <tt>write</tt> methods.
+ *   </p></li>
+ *
+ *   <li><p> Updates made to a file may be {@link #force <i>forced
+ *   out</i>} to the underlying storage device, ensuring that data are not
+ *   lost in the event of a system crash.  </p></li>
+ *
+ *   <li><p> Bytes can be transferred from a file {@link #transferTo <i>to
+ *   some other channel</i>}, and {@link #transferFrom <i>vice
+ *   versa</i>}, in a way that can be optimized by many operating systems
+ *   into a very fast transfer directly to or from the filesystem cache.
+ *   </p></li>
+ *
+ *   <li><p> A region of a file may be {@link FileLock <i>locked</i>}
+ *   against access by other programs.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> File channels are safe for use by multiple concurrent threads.  The
+ * {@link Channel#close close} method may be invoked at any time, as specified
+ * by the {@link Channel} interface.  Only one operation that involves the
+ * channel's position or can change its file's size may be in progress at any
+ * given time; attempts to initiate a second such operation while the first is
+ * still in progress will block until the first operation completes.  Other
+ * operations, in particular those that take an explicit position, may proceed
+ * concurrently; whether they in fact do so is dependent upon the underlying
+ * implementation and is therefore unspecified.
+ *
+ * <p> The view of a file provided by an instance of this class is guaranteed
+ * to be consistent with other views of the same file provided by other
+ * instances in the same program.  The view provided by an instance of this
+ * class may or may not, however, be consistent with the views seen by other
+ * concurrently-running programs due to caching performed by the underlying
+ * operating system and delays induced by network-filesystem protocols.  This
+ * is true regardless of the language in which these other programs are
+ * written, and whether they are running on the same machine or on some other
+ * machine.  The exact nature of any such inconsistencies are system-dependent
+ * and are therefore unspecified.
+ *
+ * <p> A file channel is created by invoking one of the {@link #open open}
+ * methods defined by this class. A file channel can also be obtained from an
+ * existing {@link java.io.FileInputStream#getChannel FileInputStream}, {@link
+ * java.io.FileOutputStream#getChannel FileOutputStream}, or {@link
+ * java.io.RandomAccessFile#getChannel RandomAccessFile} object by invoking
+ * that object's <tt>getChannel</tt> method, which returns a file channel that
+ * is connected to the same underlying file. Where the file channel is obtained
+ * from an existing stream or random access file then the state of the file
+ * channel is intimately connected to that of the object whose <tt>getChannel</tt>
+ * method returned the channel.  Changing the channel's position, whether
+ * explicitly or by reading or writing bytes, will change the file position of
+ * the originating object, and vice versa. Changing the file's length via the
+ * file channel will change the length seen via the originating object, and vice
+ * versa.  Changing the file's content by writing bytes will change the content
+ * seen by the originating object, and vice versa.
+ *
+ * <a name="open-mode"></a> <p> At various points this class specifies that an
+ * instance that is "open for reading," "open for writing," or "open for
+ * reading and writing" is required.  A channel obtained via the {@link
+ * java.io.FileInputStream#getChannel getChannel} method of a {@link
+ * java.io.FileInputStream} instance will be open for reading.  A channel
+ * obtained via the {@link java.io.FileOutputStream#getChannel getChannel}
+ * method of a {@link java.io.FileOutputStream} instance will be open for
+ * writing.  Finally, a channel obtained via the {@link
+ * java.io.RandomAccessFile#getChannel getChannel} method of a {@link
+ * java.io.RandomAccessFile} instance will be open for reading if the instance
+ * was created with mode <tt>"r"</tt> and will be open for reading and writing
+ * if the instance was created with mode <tt>"rw"</tt>.
+ *
+ * <a name="append-mode"></a><p> A file channel that is open for writing may be in
+ * <i>append mode</i>, for example if it was obtained from a file-output stream
+ * that was created by invoking the {@link
+ * java.io.FileOutputStream#FileOutputStream(java.io.File,boolean)
+ * FileOutputStream(File,boolean)} constructor and passing <tt>true</tt> for
+ * the second parameter.  In this mode each invocation of a relative write
+ * operation first advances the position to the end of the file and then writes
+ * the requested data.  Whether the advancement of the position and the writing
+ * of the data are done in a single atomic operation is system-dependent and
+ * therefore unspecified.
+ *
+ * @see java.io.FileInputStream#getChannel()
+ * @see java.io.FileOutputStream#getChannel()
+ * @see java.io.RandomAccessFile#getChannel()
+ *
+ * @author Mark Reinhold
+ * @author Mike McCloskey
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class FileChannel
+    extends AbstractInterruptibleChannel
+    implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected FileChannel() { }
+
+    /**
+     * Opens or creates a file, returning a file channel to access the file.
+     *
+     * <p> The {@code options} parameter determines how the file is opened.
+     * The {@link StandardOpenOption#READ READ} and {@link StandardOpenOption#WRITE
+     * WRITE} options determine if the file should be opened for reading and/or
+     * writing. If neither option (or the {@link StandardOpenOption#APPEND APPEND}
+     * option) is contained in the array then the file is opened for reading.
+     * By default reading or writing commences at the beginning of the file.
+     *
+     * <p> In the addition to {@code READ} and {@code WRITE}, the following
+     * options may be present:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
+     *   <td> If this option is present then the file is opened for writing and
+     *     each invocation of the channel's {@code write} method first advances
+     *     the position to the end of the file and then writes the requested
+     *     data. Whether the advancement of the position and the writing of the
+     *     data are done in a single atomic operation is system-dependent and
+     *     therefore unspecified. This option may not be used in conjunction
+     *     with the {@code READ} or {@code TRUNCATE_EXISTING} options. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> If this option is present then the existing file is truncated to
+     *   a size of 0 bytes. This option is ignored when the file is opened only
+     *   for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
+     *   <td> If this option is present then a new file is created, failing if
+     *   the file already exists. When creating a file the check for the
+     *   existence of the file and the creation of the file if it does not exist
+     *   is atomic with respect to other file system operations. This option is
+     *   ignored when the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
+     *   <td> If this option is present then an existing file is opened if it
+     *   exists, otherwise a new file is created. When creating a file the check
+     *   for the existence of the file and the creation of the file if it does
+     *   not exist is atomic with respect to other file system operations. This
+     *   option is ignored if the {@code CREATE_NEW} option is also present or
+     *   the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
+     *   <td> When this option is present then the implementation makes a
+     *   <em>best effort</em> attempt to delete the file when closed by the
+     *   the {@link #close close} method. If the {@code close} method is not
+     *   invoked then a <em>best effort</em> attempt is made to delete the file
+     *   when the Java virtual machine terminates. </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
+     *   <td> When creating a new file this option is a <em>hint</em> that the
+     *   new file will be sparse. This option is ignored when not creating
+     *   a new file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="../file/package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation may also support additional options.
+     *
+     * <p> The {@code attrs} parameter is an optional array of file {@link
+     * FileAttribute file-attributes} to set atomically when creating the file.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * FileSystemProvider#newFileChannel newFileChannel} method on the
+     * provider that created the {@code Path}.
+     *
+     * @param   path
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     * @param   attrs
+     *          An optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  A new file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If the {@code path} is associated with a provider that does not
+     *          support creating file channels, or an unsupported open option is
+     *          specified, or the array contains an attribute that cannot be set
+     *          atomically when creating the file
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     *
+     * @since   1.7
+     */
+    public static FileChannel open(Path path,
+                                   Set<? extends OpenOption> options,
+                                   FileAttribute<?>... attrs)
+        throws IOException
+    {
+        FileSystemProvider provider = path.getFileSystem().provider();
+        return provider.newFileChannel(path, options, attrs);
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"}) // generic array construction
+    private static final FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];
+
+    /**
+     * Opens or creates a file, returning a file channel to access the file.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     fc.{@link #open(Path,Set,FileAttribute[]) open}(file, opts, new FileAttribute&lt;?&gt;[0]);
+     * </pre>
+     * where {@code opts} is a set of the options specified in the {@code
+     * options} array.
+     *
+     * @param   path
+     *          The path of the file to open or create
+     * @param   options
+     *          Options specifying how the file is opened
+     *
+     * @return  A new file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If the {@code path} is associated with a provider that does not
+     *          support creating file channels, or an unsupported open option is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an
+     *          unspecified permission required by the implementation.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     *
+     * @since   1.7
+     */
+    public static FileChannel open(Path path, OpenOption... options)
+        throws IOException
+    {
+        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
+        Collections.addAll(set, options);
+        return open(path, set, NO_ATTRIBUTES);
+    }
+
+    // -- Channel operations --
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> Bytes are read starting at this channel's current file position, and
+     * then the file position is updated with the number of bytes actually
+     * read.  Otherwise this method behaves exactly as specified in the {@link
+     * ReadableByteChannel} interface. </p>
+     */
+    public abstract int read(ByteBuffer dst) throws IOException;
+
+    /**
+     * Reads a sequence of bytes from this channel into a subsequence of the
+     * given buffers.
+     *
+     * <p> Bytes are read starting at this channel's current file position, and
+     * then the file position is updated with the number of bytes actually
+     * read.  Otherwise this method behaves exactly as specified in the {@link
+     * ScatteringByteChannel} interface.  </p>
+     */
+    public abstract long read(ByteBuffer[] dsts, int offset, int length)
+        throws IOException;
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffers.
+     *
+     * <p> Bytes are read starting at this channel's current file position, and
+     * then the file position is updated with the number of bytes actually
+     * read.  Otherwise this method behaves exactly as specified in the {@link
+     * ScatteringByteChannel} interface.  </p>
+     */
+    public final long read(ByteBuffer[] dsts) throws IOException {
+        return read(dsts, 0, dsts.length);
+    }
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> Bytes are written starting at this channel's current file position
+     * unless the channel is in append mode, in which case the position is
+     * first advanced to the end of the file.  The file is grown, if necessary,
+     * to accommodate the written bytes, and then the file position is updated
+     * with the number of bytes actually written.  Otherwise this method
+     * behaves exactly as specified by the {@link WritableByteChannel}
+     * interface. </p>
+     */
+    public abstract int write(ByteBuffer src) throws IOException;
+
+    /**
+     * Writes a sequence of bytes to this channel from a subsequence of the
+     * given buffers.
+     *
+     * <p> Bytes are written starting at this channel's current file position
+     * unless the channel is in append mode, in which case the position is
+     * first advanced to the end of the file.  The file is grown, if necessary,
+     * to accommodate the written bytes, and then the file position is updated
+     * with the number of bytes actually written.  Otherwise this method
+     * behaves exactly as specified in the {@link GatheringByteChannel}
+     * interface.  </p>
+     */
+    public abstract long write(ByteBuffer[] srcs, int offset, int length)
+        throws IOException;
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffers.
+     *
+     * <p> Bytes are written starting at this channel's current file position
+     * unless the channel is in append mode, in which case the position is
+     * first advanced to the end of the file.  The file is grown, if necessary,
+     * to accommodate the written bytes, and then the file position is updated
+     * with the number of bytes actually written.  Otherwise this method
+     * behaves exactly as specified in the {@link GatheringByteChannel}
+     * interface.  </p>
+     */
+    public final long write(ByteBuffer[] srcs) throws IOException {
+        return write(srcs, 0, srcs.length);
+    }
+
+
+    // -- Other operations --
+
+    /**
+     * Returns this channel's file position.
+     *
+     * @return  This channel's file position,
+     *          a non-negative integer counting the number of bytes
+     *          from the beginning of the file to the current position
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract long position() throws IOException;
+
+    /**
+     * Sets this channel's file position.
+     *
+     * <p> Setting the position to a value that is greater than the file's
+     * current size is legal but does not change the size of the file.  A later
+     * attempt to read bytes at such a position will immediately return an
+     * end-of-file indication.  A later attempt to write bytes at such a
+     * position will cause the file to be grown to accommodate the new bytes;
+     * the values of any bytes between the previous end-of-file and the
+     * newly-written bytes are unspecified.  </p>
+     *
+     * @param  newPosition
+     *         The new position, a non-negative integer counting
+     *         the number of bytes from the beginning of the file
+     *
+     * @return  This file channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IllegalArgumentException
+     *          If the new position is negative
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract FileChannel position(long newPosition) throws IOException;
+
+    /**
+     * Returns the current size of this channel's file.
+     *
+     * @return  The current size of this channel's file,
+     *          measured in bytes
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract long size() throws IOException;
+
+    /**
+     * Truncates this channel's file to the given size.
+     *
+     * <p> If the given size is less than the file's current size then the file
+     * is truncated, discarding any bytes beyond the new end of the file.  If
+     * the given size is greater than or equal to the file's current size then
+     * the file is not modified.  In either case, if this channel's file
+     * position is greater than the given size then it is set to that size.
+     * </p>
+     *
+     * @param  size
+     *         The new size, a non-negative byte count
+     *
+     * @return  This file channel
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IllegalArgumentException
+     *          If the new size is negative
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract FileChannel truncate(long size) throws IOException;
+
+    /**
+     * Forces any updates to this channel's file to be written to the storage
+     * device that contains it.
+     *
+     * <p> If this channel's file resides on a local storage device then when
+     * this method returns it is guaranteed that all changes made to the file
+     * since this channel was created, or since this method was last invoked,
+     * will have been written to that device.  This is useful for ensuring that
+     * critical information is not lost in the event of a system crash.
+     *
+     * <p> If the file does not reside on a local device then no such guarantee
+     * is made.
+     *
+     * <p> The <tt>metaData</tt> parameter can be used to limit the number of
+     * I/O operations that this method is required to perform.  Passing
+     * <tt>false</tt> for this parameter indicates that only updates to the
+     * file's content need be written to storage; passing <tt>true</tt>
+     * indicates that updates to both the file's content and metadata must be
+     * written, which generally requires at least one more I/O operation.
+     * Whether this parameter actually has any effect is dependent upon the
+     * underlying operating system and is therefore unspecified.
+     *
+     * <p> Invoking this method may cause an I/O operation to occur even if the
+     * channel was only opened for reading.  Some operating systems, for
+     * example, maintain a last-access time as part of a file's metadata, and
+     * this time is updated whenever the file is read.  Whether or not this is
+     * actually done is system-dependent and is therefore unspecified.
+     *
+     * <p> This method is only guaranteed to force changes that were made to
+     * this channel's file via the methods defined in this class.  It may or
+     * may not force changes that were made by modifying the content of a
+     * {@link MappedByteBuffer <i>mapped byte buffer</i>} obtained by
+     * invoking the {@link #map map} method.  Invoking the {@link
+     * MappedByteBuffer#force force} method of the mapped byte buffer will
+     * force changes made to the buffer's content to be written.  </p>
+     *
+     * @param   metaData
+     *          If <tt>true</tt> then this method is required to force changes
+     *          to both the file's content and metadata to be written to
+     *          storage; otherwise, it need only force content changes to be
+     *          written
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract void force(boolean metaData) throws IOException;
+
+    /**
+     * Transfers bytes from this channel's file to the given writable byte
+     * channel.
+     *
+     * <p> An attempt is made to read up to <tt>count</tt> bytes starting at
+     * the given <tt>position</tt> in this channel's file and write them to the
+     * target channel.  An invocation of this method may or may not transfer
+     * all of the requested bytes; whether or not it does so depends upon the
+     * natures and states of the channels.  Fewer than the requested number of
+     * bytes are transferred if this channel's file contains fewer than
+     * <tt>count</tt> bytes starting at the given <tt>position</tt>, or if the
+     * target channel is non-blocking and it has fewer than <tt>count</tt>
+     * bytes free in its output buffer.
+     *
+     * <p> This method does not modify this channel's position.  If the given
+     * position is greater than the file's current size then no bytes are
+     * transferred.  If the target channel has a position then bytes are
+     * written starting at that position and then the position is incremented
+     * by the number of bytes written.
+     *
+     * <p> This method is potentially much more efficient than a simple loop
+     * that reads from this channel and writes to the target channel.  Many
+     * operating systems can transfer bytes directly from the filesystem cache
+     * to the target channel without actually copying them.  </p>
+     *
+     * @param  position
+     *         The position within the file at which the transfer is to begin;
+     *         must be non-negative
+     *
+     * @param  count
+     *         The maximum number of bytes to be transferred; must be
+     *         non-negative
+     *
+     * @param  target
+     *         The target channel
+     *
+     * @return  The number of bytes, possibly zero,
+     *          that were actually transferred
+     *
+     * @throws IllegalArgumentException
+     *         If the preconditions on the parameters do not hold
+     *
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     *
+     * @throws  NonWritableChannelException
+     *          If the target channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If either this channel or the target channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes either channel
+     *          while the transfer is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread while the
+     *          transfer is in progress, thereby closing both channels and
+     *          setting the current thread's interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract long transferTo(long position, long count,
+                                    WritableByteChannel target)
+        throws IOException;
+
+    /**
+     * Transfers bytes into this channel's file from the given readable byte
+     * channel.
+     *
+     * <p> An attempt is made to read up to <tt>count</tt> bytes from the
+     * source channel and write them to this channel's file starting at the
+     * given <tt>position</tt>.  An invocation of this method may or may not
+     * transfer all of the requested bytes; whether or not it does so depends
+     * upon the natures and states of the channels.  Fewer than the requested
+     * number of bytes will be transferred if the source channel has fewer than
+     * <tt>count</tt> bytes remaining, or if the source channel is non-blocking
+     * and has fewer than <tt>count</tt> bytes immediately available in its
+     * input buffer.
+     *
+     * <p> This method does not modify this channel's position.  If the given
+     * position is greater than the file's current size then no bytes are
+     * transferred.  If the source channel has a position then bytes are read
+     * starting at that position and then the position is incremented by the
+     * number of bytes read.
+     *
+     * <p> This method is potentially much more efficient than a simple loop
+     * that reads from the source channel and writes to this channel.  Many
+     * operating systems can transfer bytes directly from the source channel
+     * into the filesystem cache without actually copying them.  </p>
+     *
+     * @param  src
+     *         The source channel
+     *
+     * @param  position
+     *         The position within the file at which the transfer is to begin;
+     *         must be non-negative
+     *
+     * @param  count
+     *         The maximum number of bytes to be transferred; must be
+     *         non-negative
+     *
+     * @return  The number of bytes, possibly zero,
+     *          that were actually transferred
+     *
+     * @throws IllegalArgumentException
+     *         If the preconditions on the parameters do not hold
+     *
+     * @throws  NonReadableChannelException
+     *          If the source channel was not opened for reading
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If either this channel or the source channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes either channel
+     *          while the transfer is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread while the
+     *          transfer is in progress, thereby closing both channels and
+     *          setting the current thread's interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract long transferFrom(ReadableByteChannel src,
+                                      long position, long count)
+        throws IOException;
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer,
+     * starting at the given file position.
+     *
+     * <p> This method works in the same manner as the {@link
+     * #read(ByteBuffer)} method, except that bytes are read starting at the
+     * given file position rather than at the channel's current position.  This
+     * method does not modify this channel's position.  If the given position
+     * is greater than the file's current size then no bytes are read.  </p>
+     *
+     * @param  dst
+     *         The buffer into which bytes are to be transferred
+     *
+     * @param  position
+     *         The file position at which the transfer is to begin;
+     *         must be non-negative
+     *
+     * @return  The number of bytes read, possibly zero, or <tt>-1</tt> if the
+     *          given position is greater than or equal to the file's current
+     *          size
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative
+     *
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract int read(ByteBuffer dst, long position) throws IOException;
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer,
+     * starting at the given file position.
+     *
+     * <p> This method works in the same manner as the {@link
+     * #write(ByteBuffer)} method, except that bytes are written starting at
+     * the given file position rather than at the channel's current position.
+     * This method does not modify this channel's position.  If the given
+     * position is greater than the file's current size then the file will be
+     * grown to accommodate the new bytes; the values of any bytes between the
+     * previous end-of-file and the newly-written bytes are unspecified.  </p>
+     *
+     * @param  src
+     *         The buffer from which bytes are to be transferred
+     *
+     * @param  position
+     *         The file position at which the transfer is to begin;
+     *         must be non-negative
+     *
+     * @return  The number of bytes written, possibly zero
+     *
+     * @throws  IllegalArgumentException
+     *          If the position is negative
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the write operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the write operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract int write(ByteBuffer src, long position) throws IOException;
+
+
+    // -- Memory-mapped buffers --
+
+    /**
+     * A typesafe enumeration for file-mapping modes.
+     *
+     * @since 1.4
+     *
+     * @see java.nio.channels.FileChannel#map
+     */
+    public static class MapMode {
+
+        /**
+         * Mode for a read-only mapping.
+         */
+        public static final MapMode READ_ONLY
+            = new MapMode("READ_ONLY");
+
+        /**
+         * Mode for a read/write mapping.
+         */
+        public static final MapMode READ_WRITE
+            = new MapMode("READ_WRITE");
+
+        /**
+         * Mode for a private (copy-on-write) mapping.
+         */
+        public static final MapMode PRIVATE
+            = new MapMode("PRIVATE");
+
+        private final String name;
+
+        private MapMode(String name) {
+            this.name = name;
+        }
+
+        /**
+         * Returns a string describing this file-mapping mode.
+         *
+         * @return  A descriptive string
+         */
+        public String toString() {
+            return name;
+        }
+
+    }
+
+    /**
+     * Maps a region of this channel's file directly into memory.
+     *
+     * <p> A region of a file may be mapped into memory in one of three modes:
+     * </p>
+     *
+     * <ul>
+     *
+     *   <li><p> <i>Read-only:</i> Any attempt to modify the resulting buffer
+     *   will cause a {@link java.nio.ReadOnlyBufferException} to be thrown.
+     *   ({@link MapMode#READ_ONLY MapMode.READ_ONLY}) </p></li>
+     *
+     *   <li><p> <i>Read/write:</i> Changes made to the resulting buffer will
+     *   eventually be propagated to the file; they may or may not be made
+     *   visible to other programs that have mapped the same file.  ({@link
+     *   MapMode#READ_WRITE MapMode.READ_WRITE}) </p></li>
+     *
+     *   <li><p> <i>Private:</i> Changes made to the resulting buffer will not
+     *   be propagated to the file and will not be visible to other programs
+     *   that have mapped the same file; instead, they will cause private
+     *   copies of the modified portions of the buffer to be created.  ({@link
+     *   MapMode#PRIVATE MapMode.PRIVATE}) </p></li>
+     *
+     * </ul>
+     *
+     * <p> For a read-only mapping, this channel must have been opened for
+     * reading; for a read/write or private mapping, this channel must have
+     * been opened for both reading and writing.
+     *
+     * <p> The {@link MappedByteBuffer <i>mapped byte buffer</i>}
+     * returned by this method will have a position of zero and a limit and
+     * capacity of <tt>size</tt>; its mark will be undefined.  The buffer and
+     * the mapping that it represents will remain valid until the buffer itself
+     * is garbage-collected.
+     *
+     * <p> A mapping, once established, is not dependent upon the file channel
+     * that was used to create it.  Closing the channel, in particular, has no
+     * effect upon the validity of the mapping.
+     *
+     * <p> Many of the details of memory-mapped files are inherently dependent
+     * upon the underlying operating system and are therefore unspecified.  The
+     * behavior of this method when the requested region is not completely
+     * contained within this channel's file is unspecified.  Whether changes
+     * made to the content or size of the underlying file, by this program or
+     * another, are propagated to the buffer is unspecified.  The rate at which
+     * changes to the buffer are propagated to the file is unspecified.
+     *
+     * <p> For most operating systems, mapping a file into memory is more
+     * expensive than reading or writing a few tens of kilobytes of data via
+     * the usual {@link #read read} and {@link #write write} methods.  From the
+     * standpoint of performance it is generally only worth mapping relatively
+     * large files into memory.  </p>
+     *
+     * @param  mode
+     *         One of the constants {@link MapMode#READ_ONLY READ_ONLY}, {@link
+     *         MapMode#READ_WRITE READ_WRITE}, or {@link MapMode#PRIVATE
+     *         PRIVATE} defined in the {@link MapMode} class, according to
+     *         whether the file is to be mapped read-only, read/write, or
+     *         privately (copy-on-write), respectively
+     *
+     * @param  position
+     *         The position within the file at which the mapped region
+     *         is to start; must be non-negative
+     *
+     * @param  size
+     *         The size of the region to be mapped; must be non-negative and
+     *         no greater than {@link java.lang.Integer#MAX_VALUE}
+     *
+     * @return  The mapped byte buffer
+     *
+     * @throws NonReadableChannelException
+     *         If the <tt>mode</tt> is {@link MapMode#READ_ONLY READ_ONLY} but
+     *         this channel was not opened for reading
+     *
+     * @throws NonWritableChannelException
+     *         If the <tt>mode</tt> is {@link MapMode#READ_WRITE READ_WRITE} or
+     *         {@link MapMode#PRIVATE PRIVATE} but this channel was not opened
+     *         for both reading and writing
+     *
+     * @throws IllegalArgumentException
+     *         If the preconditions on the parameters do not hold
+     *
+     * @throws IOException
+     *         If some other I/O error occurs
+     *
+     * @see java.nio.channels.FileChannel.MapMode
+     * @see java.nio.MappedByteBuffer
+     */
+    public abstract MappedByteBuffer map(MapMode mode,
+                                         long position, long size)
+        throws IOException;
+
+
+    // -- Locks --
+
+    /**
+     * Acquires a lock on the given region of this channel's file.
+     *
+     * <p> An invocation of this method will block until the region can be
+     * locked, this channel is closed, or the invoking thread is interrupted,
+     * whichever comes first.
+     *
+     * <p> If this channel is closed by another thread during an invocation of
+     * this method then an {@link AsynchronousCloseException} will be thrown.
+     *
+     * <p> If the invoking thread is interrupted while waiting to acquire the
+     * lock then its interrupt status will be set and a {@link
+     * FileLockInterruptionException} will be thrown.  If the invoker's
+     * interrupt status is set when this method is invoked then that exception
+     * will be thrown immediately; the thread's interrupt status will not be
+     * changed.
+     *
+     * <p> The region specified by the <tt>position</tt> and <tt>size</tt>
+     * parameters need not be contained within, or even overlap, the actual
+     * underlying file.  Lock regions are fixed in size; if a locked region
+     * initially contains the end of the file and the file grows beyond the
+     * region then the new portion of the file will not be covered by the lock.
+     * If a file is expected to grow in size and a lock on the entire file is
+     * required then a region starting at zero, and no smaller than the
+     * expected maximum size of the file, should be locked.  The zero-argument
+     * {@link #lock()} method simply locks a region of size {@link
+     * Long#MAX_VALUE}.
+     *
+     * <p> Some operating systems do not support shared locks, in which case a
+     * request for a shared lock is automatically converted into a request for
+     * an exclusive lock.  Whether the newly-acquired lock is shared or
+     * exclusive may be tested by invoking the resulting lock object's {@link
+     * FileLock#isShared() isShared} method.
+     *
+     * <p> File locks are held on behalf of the entire Java virtual machine.
+     * They are not suitable for controlling access to a file by multiple
+     * threads within the same virtual machine.  </p>
+     *
+     * @param  position
+     *         The position at which the locked region is to start; must be
+     *         non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
+     *
+     * @param  shared
+     *         <tt>true</tt> to request a shared lock, in which case this
+     *         channel must be open for reading (and possibly writing);
+     *         <tt>false</tt> to request an exclusive lock, in which case this
+     *         channel must be open for writing (and possibly reading)
+     *
+     * @return  A lock object representing the newly-acquired lock
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel while the invoking
+     *          thread is blocked in this method
+     *
+     * @throws  FileLockInterruptionException
+     *          If the invoking thread is interrupted while blocked in this
+     *          method
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region
+     *
+     * @throws  NonReadableChannelException
+     *          If <tt>shared</tt> is <tt>true</tt> this channel was not
+     *          opened for reading
+     *
+     * @throws  NonWritableChannelException
+     *          If <tt>shared</tt> is <tt>false</tt> but this channel was not
+     *          opened for writing
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock()
+     * @see     #tryLock()
+     * @see     #tryLock(long,long,boolean)
+     */
+    public abstract FileLock lock(long position, long size, boolean shared)
+        throws IOException;
+
+    /**
+     * Acquires an exclusive lock on this channel's file.
+     *
+     * <p> An invocation of this method of the form <tt>fc.lock()</tt> behaves
+     * in exactly the same way as the invocation
+     *
+     * <pre>
+     *     fc.{@link #lock(long,long,boolean) lock}(0L, Long.MAX_VALUE, false) </pre>
+     *
+     * @return  A lock object representing the newly-acquired lock
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel while the invoking
+     *          thread is blocked in this method
+     *
+     * @throws  FileLockInterruptionException
+     *          If the invoking thread is interrupted while blocked in this
+     *          method
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region of the same file
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock(long,long,boolean)
+     * @see     #tryLock()
+     * @see     #tryLock(long,long,boolean)
+     */
+    public final FileLock lock() throws IOException {
+        return lock(0L, Long.MAX_VALUE, false);
+    }
+
+    /**
+     * Attempts to acquire a lock on the given region of this channel's file.
+     *
+     * <p> This method does not block.  An invocation always returns
+     * immediately, either having acquired a lock on the requested region or
+     * having failed to do so.  If it fails to acquire a lock because an
+     * overlapping lock is held by another program then it returns
+     * <tt>null</tt>.  If it fails to acquire a lock for any other reason then
+     * an appropriate exception is thrown.
+     *
+     * <p> The region specified by the <tt>position</tt> and <tt>size</tt>
+     * parameters need not be contained within, or even overlap, the actual
+     * underlying file.  Lock regions are fixed in size; if a locked region
+     * initially contains the end of the file and the file grows beyond the
+     * region then the new portion of the file will not be covered by the lock.
+     * If a file is expected to grow in size and a lock on the entire file is
+     * required then a region starting at zero, and no smaller than the
+     * expected maximum size of the file, should be locked.  The zero-argument
+     * {@link #tryLock()} method simply locks a region of size {@link
+     * Long#MAX_VALUE}.
+     *
+     * <p> Some operating systems do not support shared locks, in which case a
+     * request for a shared lock is automatically converted into a request for
+     * an exclusive lock.  Whether the newly-acquired lock is shared or
+     * exclusive may be tested by invoking the resulting lock object's {@link
+     * FileLock#isShared() isShared} method.
+     *
+     * <p> File locks are held on behalf of the entire Java virtual machine.
+     * They are not suitable for controlling access to a file by multiple
+     * threads within the same virtual machine.  </p>
+     *
+     * @param  position
+     *         The position at which the locked region is to start; must be
+     *         non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
+     *
+     * @param  shared
+     *         <tt>true</tt> to request a shared lock,
+     *         <tt>false</tt> to request an exclusive lock
+     *
+     * @return  A lock object representing the newly-acquired lock,
+     *          or <tt>null</tt> if the lock could not be acquired
+     *          because another program holds an overlapping lock
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region of the same file
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock()
+     * @see     #lock(long,long,boolean)
+     * @see     #tryLock()
+     */
+    public abstract FileLock tryLock(long position, long size, boolean shared)
+        throws IOException;
+
+    /**
+     * Attempts to acquire an exclusive lock on this channel's file.
+     *
+     * <p> An invocation of this method of the form <tt>fc.tryLock()</tt>
+     * behaves in exactly the same way as the invocation
+     *
+     * <pre>
+     *     fc.{@link #tryLock(long,long,boolean) tryLock}(0L, Long.MAX_VALUE, false) </pre>
+     *
+     * @return  A lock object representing the newly-acquired lock,
+     *          or <tt>null</tt> if the lock could not be acquired
+     *          because another program holds an overlapping lock
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  OverlappingFileLockException
+     *          If a lock that overlaps the requested region is already held by
+     *          this Java virtual machine, or if another thread is already
+     *          blocked in this method and is attempting to lock an overlapping
+     *          region
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @see     #lock()
+     * @see     #lock(long,long,boolean)
+     * @see     #tryLock(long,long,boolean)
+     */
+    public final FileLock tryLock() throws IOException {
+        return tryLock(0L, Long.MAX_VALUE, false);
+    }
+
+}
diff --git a/java/nio/channels/FileLock.java b/java/nio/channels/FileLock.java
new file mode 100644
index 0000000..156071c
--- /dev/null
+++ b/java/nio/channels/FileLock.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+
+/**
+ * A token representing a lock on a region of a file.
+ *
+ * <p> A file-lock object is created each time a lock is acquired on a file via
+ * one of the {@link FileChannel#lock(long,long,boolean) lock} or {@link
+ * FileChannel#tryLock(long,long,boolean) tryLock} methods of the
+ * {@link FileChannel} class, or the {@link
+ * AsynchronousFileChannel#lock(long,long,boolean,Object,CompletionHandler) lock}
+ * or {@link AsynchronousFileChannel#tryLock(long,long,boolean) tryLock}
+ * methods of the {@link AsynchronousFileChannel} class.
+ *
+ * <p> A file-lock object is initially valid.  It remains valid until the lock
+ * is released by invoking the {@link #release release} method, by closing the
+ * channel that was used to acquire it, or by the termination of the Java
+ * virtual machine, whichever comes first.  The validity of a lock may be
+ * tested by invoking its {@link #isValid isValid} method.
+ *
+ * <p> A file lock is either <i>exclusive</i> or <i>shared</i>.  A shared lock
+ * prevents other concurrently-running programs from acquiring an overlapping
+ * exclusive lock, but does allow them to acquire overlapping shared locks.  An
+ * exclusive lock prevents other programs from acquiring an overlapping lock of
+ * either type.  Once it is released, a lock has no further effect on the locks
+ * that may be acquired by other programs.
+ *
+ * <p> Whether a lock is exclusive or shared may be determined by invoking its
+ * {@link #isShared isShared} method.  Some platforms do not support shared
+ * locks, in which case a request for a shared lock is automatically converted
+ * into a request for an exclusive lock.
+ *
+ * <p> The locks held on a particular file by a single Java virtual machine do
+ * not overlap.  The {@link #overlaps overlaps} method may be used to test
+ * whether a candidate lock range overlaps an existing lock.
+ *
+ * <p> A file-lock object records the file channel upon whose file the lock is
+ * held, the type and validity of the lock, and the position and size of the
+ * locked region.  Only the validity of a lock is subject to change over time;
+ * all other aspects of a lock's state are immutable.
+ *
+ * <p> File locks are held on behalf of the entire Java virtual machine.
+ * They are not suitable for controlling access to a file by multiple
+ * threads within the same virtual machine.
+ *
+ * <p> File-lock objects are safe for use by multiple concurrent threads.
+ *
+ *
+ * <a name="pdep"></a><h2> Platform dependencies </h2>
+ *
+ * <p> This file-locking API is intended to map directly to the native locking
+ * facility of the underlying operating system.  Thus the locks held on a file
+ * should be visible to all programs that have access to the file, regardless
+ * of the language in which those programs are written.
+ *
+ * <p> Whether or not a lock actually prevents another program from accessing
+ * the content of the locked region is system-dependent and therefore
+ * unspecified.  The native file-locking facilities of some systems are merely
+ * <i>advisory</i>, meaning that programs must cooperatively observe a known
+ * locking protocol in order to guarantee data integrity.  On other systems
+ * native file locks are <i>mandatory</i>, meaning that if one program locks a
+ * region of a file then other programs are actually prevented from accessing
+ * that region in a way that would violate the lock.  On yet other systems,
+ * whether native file locks are advisory or mandatory is configurable on a
+ * per-file basis.  To ensure consistent and correct behavior across platforms,
+ * it is strongly recommended that the locks provided by this API be used as if
+ * they were advisory locks.
+ *
+ * <p> On some systems, acquiring a mandatory lock on a region of a file
+ * prevents that region from being {@link java.nio.channels.FileChannel#map
+ * <i>mapped into memory</i>}, and vice versa.  Programs that combine
+ * locking and mapping should be prepared for this combination to fail.
+ *
+ * <p> On some systems, closing a channel releases all locks held by the Java
+ * virtual machine on the underlying file regardless of whether the locks were
+ * acquired via that channel or via another channel open on the same file.  It
+ * is strongly recommended that, within a program, a unique channel be used to
+ * acquire all locks on any given file.
+ *
+ * <p> Some network filesystems permit file locking to be used with
+ * memory-mapped files only when the locked regions are page-aligned and a
+ * whole multiple of the underlying hardware's page size.  Some network
+ * filesystems do not implement file locks on regions that extend past a
+ * certain position, often 2<sup>30</sup> or 2<sup>31</sup>.  In general, great
+ * care should be taken when locking files that reside on network filesystems.
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class FileLock implements AutoCloseable {
+
+    private final Channel channel;
+    private final long position;
+    private final long size;
+    private final boolean shared;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  channel
+     *         The file channel upon whose file this lock is held
+     *
+     * @param  position
+     *         The position within the file at which the locked region starts;
+     *         must be non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
+     *
+     * @param  shared
+     *         <tt>true</tt> if this lock is shared,
+     *         <tt>false</tt> if it is exclusive
+     *
+     * @throws IllegalArgumentException
+     *         If the preconditions on the parameters do not hold
+     */
+    protected FileLock(FileChannel channel,
+                       long position, long size, boolean shared)
+    {
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+        if (size < 0)
+            throw new IllegalArgumentException("Negative size");
+        if (position + size < 0)
+            throw new IllegalArgumentException("Negative position + size");
+        this.channel = channel;
+        this.position = position;
+        this.size = size;
+        this.shared = shared;
+    }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  channel
+     *         The channel upon whose file this lock is held
+     *
+     * @param  position
+     *         The position within the file at which the locked region starts;
+     *         must be non-negative
+     *
+     * @param  size
+     *         The size of the locked region; must be non-negative, and the sum
+     *         <tt>position</tt>&nbsp;+&nbsp;<tt>size</tt> must be non-negative
+     *
+     * @param  shared
+     *         <tt>true</tt> if this lock is shared,
+     *         <tt>false</tt> if it is exclusive
+     *
+     * @throws IllegalArgumentException
+     *         If the preconditions on the parameters do not hold
+     *
+     * @since 1.7
+     */
+    protected FileLock(AsynchronousFileChannel channel,
+                       long position, long size, boolean shared)
+    {
+        if (position < 0)
+            throw new IllegalArgumentException("Negative position");
+        if (size < 0)
+            throw new IllegalArgumentException("Negative size");
+        if (position + size < 0)
+            throw new IllegalArgumentException("Negative position + size");
+        this.channel = channel;
+        this.position = position;
+        this.size = size;
+        this.shared = shared;
+    }
+
+    /**
+     * Returns the file channel upon whose file this lock was acquired.
+     *
+     * <p> This method has been superseded by the {@link #acquiredBy acquiredBy}
+     * method.
+     *
+     * @return  The file channel, or {@code null} if the file lock was not
+     *          acquired by a file channel.
+     */
+    public final FileChannel channel() {
+        return (channel instanceof FileChannel) ? (FileChannel)channel : null;
+    }
+
+    /**
+     * Returns the channel upon whose file this lock was acquired.
+     *
+     * @return  The channel upon whose file this lock was acquired.
+     *
+     * @since 1.7
+     */
+    public Channel acquiredBy() {
+        return channel;
+    }
+
+    /**
+     * Returns the position within the file of the first byte of the locked
+     * region.
+     *
+     * <p> A locked region need not be contained within, or even overlap, the
+     * actual underlying file, so the value returned by this method may exceed
+     * the file's current size.  </p>
+     *
+     * @return  The position
+     */
+    public final long position() {
+        return position;
+    }
+
+    /**
+     * Returns the size of the locked region in bytes.
+     *
+     * <p> A locked region need not be contained within, or even overlap, the
+     * actual underlying file, so the value returned by this method may exceed
+     * the file's current size.  </p>
+     *
+     * @return  The size of the locked region
+     */
+    public final long size() {
+        return size;
+    }
+
+    /**
+     * Tells whether this lock is shared.
+     *
+     * @return <tt>true</tt> if lock is shared,
+     *         <tt>false</tt> if it is exclusive
+     */
+    public final boolean isShared() {
+        return shared;
+    }
+
+    /**
+     * Tells whether or not this lock overlaps the given lock range.
+     *
+     * @param   position
+     *          The starting position of the lock range
+     * @param   size
+     *          The size of the lock range
+     *
+     * @return  <tt>true</tt> if, and only if, this lock and the given lock
+     *          range overlap by at least one byte
+     */
+    public final boolean overlaps(long position, long size) {
+        if (position + size <= this.position)
+            return false;               // That is below this
+        if (this.position + this.size <= position)
+            return false;               // This is below that
+        return true;
+    }
+
+    /**
+     * Tells whether or not this lock is valid.
+     *
+     * <p> A lock object remains valid until it is released or the associated
+     * file channel is closed, whichever comes first.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this lock is valid
+     */
+    public abstract boolean isValid();
+
+    /**
+     * Releases this lock.
+     *
+     * <p> If this lock object is valid then invoking this method releases the
+     * lock and renders the object invalid.  If this lock object is invalid
+     * then invoking this method has no effect.  </p>
+     *
+     * @throws  ClosedChannelException
+     *          If the channel that was used to acquire this lock
+     *          is no longer open
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract void release() throws IOException;
+
+    /**
+     * This method invokes the {@link #release} method. It was added
+     * to the class so that it could be used in conjunction with the
+     * automatic resource management block construct.
+     *
+     * @since 1.7
+     */
+    public final void close() throws IOException {
+        release();
+    }
+
+    /**
+     * Returns a string describing the range, type, and validity of this lock.
+     *
+     * @return  A descriptive string
+     */
+    public final String toString() {
+        return (this.getClass().getName()
+                + "[" + position
+                + ":" + size
+                + " " + (shared ? "shared" : "exclusive")
+                + " " + (isValid() ? "valid" : "invalid")
+                + "]");
+    }
+
+}
diff --git a/java/nio/channels/FileLockInterruptionException.java b/java/nio/channels/FileLockInterruptionException.java
new file mode 100644
index 0000000..a9b1bd6
--- /dev/null
+++ b/java/nio/channels/FileLockInterruptionException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Checked exception received by a thread when another thread interrupts it
+ * while it is waiting to acquire a file lock.  Before this exception is thrown
+ * the interrupt status of the previously-blocked thread will have been set.
+ *
+ * @since 1.4
+ */
+
+public class FileLockInterruptionException
+    extends java.io.IOException
+{
+
+    private static final long serialVersionUID = 7104080643653532383L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FileLockInterruptionException() { }
+
+}
diff --git a/java/nio/channels/GatheringByteChannel.java b/java/nio/channels/GatheringByteChannel.java
new file mode 100644
index 0000000..9c50d93
--- /dev/null
+++ b/java/nio/channels/GatheringByteChannel.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A channel that can write bytes from a sequence of buffers.
+ *
+ * <p> A <i>gathering</i> write operation writes, in a single invocation, a
+ * sequence of bytes from one or more of a given sequence of buffers.
+ * Gathering writes are often useful when implementing network protocols or
+ * file formats that, for example, group data into segments consisting of one
+ * or more fixed-length headers followed by a variable-length body.  Similar
+ * <i>scattering</i> read operations are defined in the {@link
+ * ScatteringByteChannel} interface.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface GatheringByteChannel
+    extends WritableByteChannel
+{
+
+    /**
+     * Writes a sequence of bytes to this channel from a subsequence of the
+     * given buffers.
+     *
+     * <p> An attempt is made to write up to <i>r</i> bytes to this channel,
+     * where <i>r</i> is the total number of bytes remaining in the specified
+     * subsequence of the given buffer array, that is,
+     *
+     * <blockquote><pre>
+     * srcs[offset].remaining()
+     *     + srcs[offset+1].remaining()
+     *     + ... + srcs[offset+length-1].remaining()</pre></blockquote>
+     *
+     * at the moment that this method is invoked.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+     * <tt>0</tt>&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * Up to the first <tt>srcs[offset].remaining()</tt> bytes of this sequence
+     * are written from buffer <tt>srcs[offset]</tt>, up to the next
+     * <tt>srcs[offset+1].remaining()</tt> bytes are written from buffer
+     * <tt>srcs[offset+1]</tt>, and so forth, until the entire byte sequence is
+     * written.  As many bytes as possible are written from each buffer, hence
+     * the final position of each updated buffer, except the last updated
+     * buffer, is guaranteed to be equal to that buffer's limit.
+     *
+     * <p> Unless otherwise specified, a write operation will return only after
+     * writing all of the <i>r</i> requested bytes.  Some types of channels,
+     * depending upon their state, may write only some of the bytes or possibly
+     * none at all.  A socket channel in non-blocking mode, for example, cannot
+     * write any more bytes than are free in the socket's output buffer.
+     *
+     * <p> This method may be invoked at any time.  If another thread has
+     * already initiated a write operation upon this channel, however, then an
+     * invocation of this method will block until the first operation is
+     * complete. </p>
+     *
+     * @param  srcs
+     *         The buffers from which bytes are to be retrieved
+     *
+     * @param  offset
+     *         The offset within the buffer array of the first buffer from
+     *         which bytes are to be retrieved; must be non-negative and no
+     *         larger than <tt>srcs.length</tt>
+     *
+     * @param  length
+     *         The maximum number of buffers to be accessed; must be
+     *         non-negative and no larger than
+     *         <tt>srcs.length</tt>&nbsp;-&nbsp;<tt>offset</tt>
+     *
+     * @return  The number of bytes written, possibly zero
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the write operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the write operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public long write(ByteBuffer[] srcs, int offset, int length)
+        throws IOException;
+
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffers.
+     *
+     * <p> An invocation of this method of the form <tt>c.write(srcs)</tt>
+     * behaves in exactly the same manner as the invocation
+     *
+     * <blockquote><pre>
+     * c.write(srcs, 0, srcs.length);</pre></blockquote>
+     *
+     * @param  srcs
+     *         The buffers from which bytes are to be retrieved
+     *
+     * @return  The number of bytes written, possibly zero
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the write operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the write operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public long write(ByteBuffer[] srcs) throws IOException;
+
+}
diff --git a/java/nio/channels/IllegalBlockingModeException.java b/java/nio/channels/IllegalBlockingModeException.java
new file mode 100644
index 0000000..19d0300
--- /dev/null
+++ b/java/nio/channels/IllegalBlockingModeException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when a blocking-mode-specific operation
+ * is invoked upon a channel in the incorrect blocking mode.
+ *
+ * @since 1.4
+ */
+
+public class IllegalBlockingModeException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -3335774961855590474L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public IllegalBlockingModeException() { }
+
+}
diff --git a/java/nio/channels/IllegalChannelGroupException.java b/java/nio/channels/IllegalChannelGroupException.java
new file mode 100644
index 0000000..dd47105
--- /dev/null
+++ b/java/nio/channels/IllegalChannelGroupException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to open a channel
+ * in a group that was not created by the same provider. 
+ *
+ * @since 1.7
+ */
+
+public class IllegalChannelGroupException
+    extends IllegalArgumentException
+{
+
+    private static final long serialVersionUID = -2495041211157744253L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public IllegalChannelGroupException() { }
+
+}
diff --git a/java/nio/channels/IllegalSelectorException.java b/java/nio/channels/IllegalSelectorException.java
new file mode 100644
index 0000000..b10f071
--- /dev/null
+++ b/java/nio/channels/IllegalSelectorException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to register a channel
+ * with a selector that was not created by the provider that created the
+ * channel.
+ *
+ * @since 1.4
+ */
+
+public class IllegalSelectorException
+    extends IllegalArgumentException
+{
+
+    private static final long serialVersionUID = -8406323347253320987L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public IllegalSelectorException() { }
+
+}
diff --git a/java/nio/channels/InterruptedByTimeoutException.java b/java/nio/channels/InterruptedByTimeoutException.java
new file mode 100644
index 0000000..ae2018d
--- /dev/null
+++ b/java/nio/channels/InterruptedByTimeoutException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Checked exception received by a thread when a timeout elapses before an
+ * asynchronous operation completes.
+ *
+ * @since 1.7
+ */
+
+public class InterruptedByTimeoutException
+    extends java.io.IOException
+{
+
+    private static final long serialVersionUID = -4268008601014042947L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public InterruptedByTimeoutException() { }
+
+}
diff --git a/java/nio/channels/InterruptibleChannel.java b/java/nio/channels/InterruptibleChannel.java
new file mode 100644
index 0000000..0e49aa6
--- /dev/null
+++ b/java/nio/channels/InterruptibleChannel.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+
+
+/**
+ * A channel that can be asynchronously closed and interrupted.
+ *
+ * <p> A channel that implements this interface is <i>asynchronously
+ * closeable:</i> If a thread is blocked in an I/O operation on an
+ * interruptible channel then another thread may invoke the channel's {@link
+ * #close close} method.  This will cause the blocked thread to receive an
+ * {@link AsynchronousCloseException}.
+ *
+ * <p> A channel that implements this interface is also <i>interruptible:</i>
+ * If a thread is blocked in an I/O operation on an interruptible channel then
+ * another thread may invoke the blocked thread's {@link Thread#interrupt()
+ * interrupt} method.  This will cause the channel to be closed, the blocked
+ * thread to receive a {@link ClosedByInterruptException}, and the blocked
+ * thread's interrupt status to be set.
+ *
+ * <p> If a thread's interrupt status is already set and it invokes a blocking
+ * I/O operation upon a channel then the channel will be closed and the thread
+ * will immediately receive a {@link ClosedByInterruptException}; its interrupt
+ * status will remain set.
+ *
+ * <p> A channel supports asynchronous closing and interruption if, and only
+ * if, it implements this interface.  This can be tested at runtime, if
+ * necessary, via the <tt>instanceof</tt> operator.
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface InterruptibleChannel
+    extends Channel
+{
+
+    /**
+     * Closes this channel.
+     *
+     * <p> Any thread currently blocked in an I/O operation upon this channel
+     * will receive an {@link AsynchronousCloseException}.
+     *
+     * <p> This method otherwise behaves exactly as specified by the {@link
+     * Channel#close Channel} interface.  </p>
+     *
+     * @throws  IOException  If an I/O error occurs
+     */
+    public void close() throws IOException;
+
+}
diff --git a/java/nio/channels/MembershipKey.java b/java/nio/channels/MembershipKey.java
new file mode 100644
index 0000000..91c2632
--- /dev/null
+++ b/java/nio/channels/MembershipKey.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+
+/**
+ * A token representing the membership of an Internet Protocol (IP) multicast
+ * group.
+ *
+ * <p> A membership key may represent a membership to receive all datagrams sent
+ * to the group, or it may be <em>source-specific</em>, meaning that it
+ * represents a membership that receives only datagrams from a specific source
+ * address. Whether or not a membership key is source-specific may be determined
+ * by invoking its {@link #sourceAddress() sourceAddress} method.
+ *
+ * <p> A membership key is valid upon creation and remains valid until the
+ * membership is dropped by invoking the {@link #drop() drop} method, or
+ * the channel is closed. The validity of the membership key may be tested
+ * by invoking its {@link #isValid() isValid} method.
+ *
+ * <p> Where a membership key is not source-specific and the underlying operation
+ * system supports source filtering, then the {@link #block block} and {@link
+ * #unblock unblock} methods can be used to block or unblock multicast datagrams
+ * from particular source addresses.
+ *
+ * @see MulticastChannel
+ *
+ * @since 1.7
+ */
+public abstract class MembershipKey {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected MembershipKey() {
+    }
+
+    /**
+     * Tells whether or not this membership is valid.
+     *
+     * <p> A multicast group membership is valid upon creation and remains
+     * valid until the membership is dropped by invoking the {@link #drop() drop}
+     * method, or the channel is closed.
+     *
+     * @return  {@code true} if this membership key is valid, {@code false}
+     *          otherwise
+     */
+    public abstract boolean isValid();
+
+    /**
+     * Drop membership.
+     *
+     * <p> If the membership key represents a membership to receive all datagrams
+     * then the membership is dropped and the channel will no longer receive any
+     * datagrams sent to the group. If the membership key is source-specific
+     * then the channel will no longer receive datagrams sent to the group from
+     * that source address.
+     *
+     * <p> After membership is dropped it may still be possible to receive
+     * datagrams sent to the group. This can arise when datagrams are waiting to
+     * be received in the socket's receive buffer. After membership is dropped
+     * then the channel may {@link MulticastChannel#join join} the group again
+     * in which case a new membership key is returned.
+     *
+     * <p> Upon return, this membership object will be {@link #isValid() invalid}.
+     * If the multicast group membership is already invalid then invoking this
+     * method has no effect. Once a multicast group membership is invalid,
+     * it remains invalid forever.
+     */
+    public abstract void drop();
+
+    /**
+     * Block multicast datagrams from the given source address.
+     *
+     * <p> If this membership key is not source-specific, and the underlying
+     * operating system supports source filtering, then this method blocks
+     * multicast datagrams from the given source address. If the given source
+     * address is already blocked then this method has no effect.
+     * After a source address is blocked it may still be possible to receive
+     * datagrams from that source. This can arise when datagrams are waiting to
+     * be received in the socket's receive buffer.
+     *
+     * @param   source
+     *          The source address to block
+     *
+     * @return  This membership key
+     *
+     * @throws  IllegalArgumentException
+     *          If the {@code source} parameter is not a unicast address or
+     *          is not the same address type as the multicast group
+     * @throws  IllegalStateException
+     *          If this membership key is source-specific or is no longer valid
+     * @throws  UnsupportedOperationException
+     *          If the underlying operating system does not support source
+     *          filtering
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract MembershipKey block(InetAddress source) throws IOException;
+
+    /**
+     * Unblock multicast datagrams from the given source address that was
+     * previously blocked using the {@link #block(InetAddress) block} method.
+     *
+     * @param   source
+     *          The source address to unblock
+     *
+     * @return  This membership key
+     *
+     * @throws  IllegalStateException
+     *          If the given source address is not currently blocked or the
+     *          membership key is no longer valid
+     */
+    public abstract MembershipKey unblock(InetAddress source);
+
+    /**
+     * Returns the channel for which this membership key was created. This
+     * method will continue to return the channel even after the membership
+     * becomes {@link #isValid invalid}.
+     *
+     * @return  the channel
+     */
+    public abstract MulticastChannel channel();
+
+    /**
+     * Returns the multicast group for which this membership key was created.
+     * This method will continue to return the group even after the membership
+     * becomes {@link #isValid invalid}.
+     *
+     * @return  the multicast group
+     */
+    public abstract InetAddress group();
+
+    /**
+     * Returns the network interface for which this membership key was created.
+     * This method will continue to return the network interface even after the
+     * membership becomes {@link #isValid invalid}.
+     *
+     * @return  the network interface
+     */
+    public abstract NetworkInterface networkInterface();
+
+    /**
+     * Returns the source address if this membership key is source-specific,
+     * or {@code null} if this membership is not source-specific.
+     *
+     * @return  The source address if this membership key is source-specific,
+     *          otherwise {@code null}
+     */
+    public abstract InetAddress sourceAddress();
+}
diff --git a/java/nio/channels/MulticastChannel.java b/java/nio/channels/MulticastChannel.java
new file mode 100644
index 0000000..d1d13eb
--- /dev/null
+++ b/java/nio/channels/MulticastChannel.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.net.ProtocolFamily;             // javadoc
+import java.net.StandardProtocolFamily;     // javadoc
+import java.net.StandardSocketOptions;      // javadoc
+
+/**
+ * A network channel that supports Internet Protocol (IP) multicasting.
+ *
+ * <p> IP multicasting is the transmission of IP datagrams to members of
+ * a <em>group</em> that is zero or more hosts identified by a single destination
+ * address.
+ *
+ * <p> In the case of a channel to an {@link StandardProtocolFamily#INET IPv4} socket,
+ * the underlying operating system supports <a href="http://www.ietf.org/rfc/rfc2236.txt">
+ * <i>RFC&nbsp;2236: Internet Group Management Protocol, Version 2 (IGMPv2)</i></a>.
+ * It may optionally support source filtering as specified by <a
+ * href="http://www.ietf.org/rfc/rfc3376.txt"> <i>RFC&nbsp;3376: Internet Group
+ * Management Protocol, Version 3 (IGMPv3)</i></a>.
+ * For channels to an {@link StandardProtocolFamily#INET6 IPv6} socket, the equivalent
+ * standards are <a href="http://www.ietf.org/rfc/rfc2710.txt"> <i>RFC&nbsp;2710:
+ * Multicast Listener Discovery (MLD) for IPv6</i></a> and <a
+ * href="http://www.ietf.org/rfc/rfc3810.txt"> <i>RFC&nbsp;3810: Multicast Listener
+ * Discovery Version 2 (MLDv2) for IPv6</i></a>.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface)} method is used to
+ * join a group and receive all multicast datagrams sent to the group. A channel
+ * may join several multicast groups and may join the same group on several
+ * {@link NetworkInterface interfaces}. Membership is dropped by invoking the {@link
+ * MembershipKey#drop drop} method on the returned {@link MembershipKey}. If the
+ * underlying platform supports source filtering then the {@link MembershipKey#block
+ * block} and {@link MembershipKey#unblock unblock} methods can be used to block or
+ * unblock multicast datagrams from particular source addresses.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface,InetAddress)} method
+ * is used to begin receiving datagrams sent to a group whose source address matches
+ * a given source address. This method throws {@link UnsupportedOperationException}
+ * if the underlying platform does not support source filtering.  Membership is
+ * <em>cumulative</em> and this method may be invoked again with the same group
+ * and interface to allow receiving datagrams from other source addresses. The
+ * method returns a {@link MembershipKey} that represents membership to receive
+ * datagrams from the given source address. Invoking the key's {@link
+ * MembershipKey#drop drop} method drops membership so that datagrams from the
+ * source address can no longer be received.
+ *
+ * <h2>Platform dependencies</h2>
+ *
+ * The multicast implementation is intended to map directly to the native
+ * multicasting facility. Consequently, the following items should be considered
+ * when developing an application that receives IP multicast datagrams:
+ *
+ * <ol>
+ *
+ * <li><p> The creation of the channel should specify the {@link ProtocolFamily}
+ * that corresponds to the address type of the multicast groups that the channel
+ * will join. There is no guarantee that a channel to a socket in one protocol
+ * family can join and receive multicast datagrams when the address of the
+ * multicast group corresponds to another protocol family. For example, it is
+ * implementation specific if a channel to an {@link StandardProtocolFamily#INET6 IPv6}
+ * socket can join an {@link StandardProtocolFamily#INET IPv4} multicast group and receive
+ * multicast datagrams sent to the group. </p></li>
+ *
+ * <li><p> The channel's socket should be bound to the {@link
+ * InetAddress#isAnyLocalAddress wildcard} address. If the socket is bound to
+ * a specific address, rather than the wildcard address then it is implementation
+ * specific if multicast datagrams are received by the socket. </p></li>
+ *
+ * <li><p> The {@link StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} option should be
+ * enabled prior to {@link NetworkChannel#bind binding} the socket. This is
+ * required to allow multiple members of the group to bind to the same
+ * address. </p></li>
+ *
+ * </ol>
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *     // join multicast group on this interface, and also use this
+ *     // interface for outgoing multicast datagrams
+ *     NetworkInterface ni = NetworkInterface.getByName("hme0");
+ *
+ *     DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+ *         .setOption(StandardSocketOptions.SO_REUSEADDR, true)
+ *         .bind(new InetSocketAddress(5000))
+ *         .setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
+ *
+ *     InetAddress group = InetAddress.getByName("225.4.5.6");
+ *
+ *     MembershipKey key = dc.join(group, ni);
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface MulticastChannel
+    extends NetworkChannel
+{
+    /**
+     * Closes this channel.
+     *
+     * <p> If the channel is a member of a multicast group then the membership
+     * is {@link MembershipKey#drop dropped}. Upon return, the {@link
+     * MembershipKey membership-key} will be {@link MembershipKey#isValid
+     * invalid}.
+     *
+     * <p> This method otherwise behaves exactly as specified by the {@link
+     * Channel} interface.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    @Override void close() throws IOException;
+
+    /**
+     * Joins a multicast group to begin receiving all datagrams sent to the group,
+     * returning a membership key.
+     *
+     * <p> If this channel is currently a member of the group on the given
+     * interface to receive all datagrams then the membership key, representing
+     * that membership, is returned. Otherwise this channel joins the group and
+     * the resulting new membership key is returned. The resulting membership key
+     * is not {@link MembershipKey#sourceAddress source-specific}.
+     *
+     * <p> A multicast channel may join several multicast groups, including
+     * the same group on more than one interface. An implementation may impose a
+     * limit on the number of groups that may be joined at the same time.
+     *
+     * @param   group
+     *          The multicast address to join
+     * @param   interf
+     *          The network interface on which to join the group
+     *
+     * @return  The membership key
+     *
+     * @throws  IllegalArgumentException
+     *          If the group parameter is not a {@link InetAddress#isMulticastAddress
+     *          multicast} address, or the group parameter is an address type
+     *          that is not supported by this channel
+     * @throws  IllegalStateException
+     *          If the channel already has source-specific membership of the
+     *          group on the interface
+     * @throws  UnsupportedOperationException
+     *          If the channel's socket is not an Internet Protocol socket
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is set, and its
+     *          {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+     *          method denies access to the multiast group
+     */
+    MembershipKey join(InetAddress group, NetworkInterface interf)
+        throws IOException;
+
+    /**
+     * Joins a multicast group to begin receiving datagrams sent to the group
+     * from a given source address.
+     *
+     * <p> If this channel is currently a member of the group on the given
+     * interface to receive datagrams from the given source address then the
+     * membership key, representing that membership, is returned. Otherwise this
+     * channel joins the group and the resulting new membership key is returned.
+     * The resulting membership key is {@link MembershipKey#sourceAddress
+     * source-specific}.
+     *
+     * <p> Membership is <em>cumulative</em> and this method may be invoked
+     * again with the same group and interface to allow receiving datagrams sent
+     * by other source addresses to the group.
+     *
+     * @param   group
+     *          The multicast address to join
+     * @param   interf
+     *          The network interface on which to join the group
+     * @param   source
+     *          The source address
+     *
+     * @return  The membership key
+     *
+     * @throws  IllegalArgumentException
+     *          If the group parameter is not a {@link
+     *          InetAddress#isMulticastAddress multicast} address, the
+     *          source parameter is not a unicast address, the group
+     *          parameter is an address type that is not supported by this channel,
+     *          or the source parameter is not the same address type as the group
+     * @throws  IllegalStateException
+     *          If the channel is currently a member of the group on the given
+     *          interface to receive all datagrams
+     * @throws  UnsupportedOperationException
+     *          If the channel's socket is not an Internet Protocol socket or
+     *          source filtering is not supported
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is set, and its
+     *          {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+     *          method denies access to the multiast group
+     */
+    MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+        throws IOException;
+}
diff --git a/java/nio/channels/NetworkChannel.java b/java/nio/channels/NetworkChannel.java
new file mode 100644
index 0000000..65a7c22
--- /dev/null
+++ b/java/nio/channels/NetworkChannel.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A channel to a network socket.
+ *
+ * <p> A channel that implements this interface is a channel to a network
+ * socket. The {@link #bind(SocketAddress) bind} method is used to bind the
+ * socket to a local {@link SocketAddress address}, the {@link #getLocalAddress()
+ * getLocalAddress} method returns the address that the socket is bound to, and
+ * the {@link #setOption(SocketOption,Object) setOption} and {@link
+ * #getOption(SocketOption) getOption} methods are used to set and query socket
+ * options.  An implementation of this interface should specify the socket options
+ * that it supports.
+ *
+ * <p> The {@link #bind bind} and {@link #setOption setOption} methods that do
+ * not otherwise have a value to return are specified to return the network
+ * channel upon which they are invoked. This allows method invocations to be
+ * chained. Implementations of this interface should specialize the return type
+ * so that method invocations on the implementation class can be chained.
+ *
+ * @since 1.7
+ */
+
+public interface NetworkChannel
+    extends Channel
+{
+    /**
+     * Binds the channel's socket to a local address.
+     *
+     * <p> This method is used to establish an association between the socket and
+     * a local address. Once an association is established then the socket remains
+     * bound until the channel is closed. If the {@code local} parameter has the
+     * value {@code null} then the socket will be bound to an address that is
+     * assigned automatically.
+     *
+     * @param   local
+     *          The address to bind the socket, or {@code null} to bind the socket
+     *          to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException
+     *          If the socket is already bound
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission. An implementation of this interface should specify
+     *          any required permissions.
+     *
+     * @see #getLocalAddress
+     */
+    NetworkChannel bind(SocketAddress local) throws IOException;
+
+    /**
+     * Returns the socket address that this channel's socket is bound to.
+     *
+     * <p> Where the channel is {@link #bind bound} to an Internet Protocol
+     * socket address then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The socket address that the socket is bound to, or {@code null}
+     *          if the channel's socket is not bound
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    SocketAddress getLocalAddress() throws IOException;
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param   <T>
+     *          The type of the socket option value
+     * @param   name
+     *          The socket option
+     * @param   value
+     *          The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @return  This channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     * @throws  IllegalArgumentException
+     *          If the value is not a valid value for this socket option
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    <T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException;
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param   <T>
+     *          The type of the socket option value
+     * @param   name
+     *          The socket option
+     *
+     * @return  The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see java.net.StandardSocketOptions
+     */
+    <T> T getOption(SocketOption<T> name) throws IOException;
+
+    /**
+     * Returns a set of the socket options supported by this channel.
+     *
+     * <p> This method will continue to return the set of options even after the
+     * channel has been closed.
+     *
+     * @return  A set of the socket options supported by this channel
+     */
+    Set<SocketOption<?>> supportedOptions();
+}
diff --git a/java/nio/channels/NoConnectionPendingException.java b/java/nio/channels/NoConnectionPendingException.java
new file mode 100644
index 0000000..cea5ad1
--- /dev/null
+++ b/java/nio/channels/NoConnectionPendingException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when the {@link SocketChannel#finishConnect
+ * finishConnect} method of a {@link SocketChannel} is invoked without first
+ * successfully invoking its {@link SocketChannel#connect connect} method.
+ *
+ * @since 1.4
+ */
+
+public class NoConnectionPendingException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -8296561183633134743L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public NoConnectionPendingException() { }
+
+}
diff --git a/java/nio/channels/NonReadableChannelException.java b/java/nio/channels/NonReadableChannelException.java
new file mode 100644
index 0000000..ddfa7fa
--- /dev/null
+++ b/java/nio/channels/NonReadableChannelException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to read
+ * from a channel that was not originally opened for reading.
+ *
+ * @since 1.4
+ */
+
+public class NonReadableChannelException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -3200915679294993514L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public NonReadableChannelException() { }
+
+}
diff --git a/java/nio/channels/NonWritableChannelException.java b/java/nio/channels/NonWritableChannelException.java
new file mode 100644
index 0000000..17c90f3
--- /dev/null
+++ b/java/nio/channels/NonWritableChannelException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to write
+ * to a channel that was not originally opened for writing.
+ *
+ * @since 1.4
+ */
+
+public class NonWritableChannelException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -7071230488279011621L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public NonWritableChannelException() { }
+
+}
diff --git a/java/nio/channels/NotYetBoundException.java b/java/nio/channels/NotYetBoundException.java
new file mode 100644
index 0000000..b6c6af3
--- /dev/null
+++ b/java/nio/channels/NotYetBoundException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an I/O
+ * operation upon a server socket channel that is not yet bound.
+ *
+ * @since 1.4
+ */
+
+public class NotYetBoundException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 4640999303950202242L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public NotYetBoundException() { }
+
+}
diff --git a/java/nio/channels/NotYetConnectedException.java b/java/nio/channels/NotYetConnectedException.java
new file mode 100644
index 0000000..9e56d07
--- /dev/null
+++ b/java/nio/channels/NotYetConnectedException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an I/O
+ * operation upon a socket channel that is not yet connected.
+ *
+ * @since 1.4
+ */
+
+public class NotYetConnectedException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 4697316551909513464L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public NotYetConnectedException() { }
+
+}
diff --git a/java/nio/channels/OverlappingFileLockException.java b/java/nio/channels/OverlappingFileLockException.java
new file mode 100644
index 0000000..7dd8f24
--- /dev/null
+++ b/java/nio/channels/OverlappingFileLockException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to acquire a lock on a
+ * region of a file that overlaps a region already locked by the same Java
+ * virtual machine, or when another thread is already waiting to lock an
+ * overlapping region of the same file.
+ *
+ * @since 1.4
+ */
+
+public class OverlappingFileLockException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 2047812138163068433L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public OverlappingFileLockException() { }
+
+}
diff --git a/java/nio/channels/Pipe.java b/java/nio/channels/Pipe.java
new file mode 100644
index 0000000..d704680
--- /dev/null
+++ b/java/nio/channels/Pipe.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.nio.channels.spi.*;
+
+
+/**
+ * A pair of channels that implements a unidirectional pipe.
+ *
+ * <p> A pipe consists of a pair of channels: A writable {@link
+ * Pipe.SinkChannel sink} channel and a readable {@link Pipe.SourceChannel source}
+ * channel.  Once some bytes are written to the sink channel they can be read
+ * from source channel in exactlyAthe order in which they were written.
+ *
+ * <p> Whether or not a thread writing bytes to a pipe will block until another
+ * thread reads those bytes, or some previously-written bytes, from the pipe is
+ * system-dependent and therefore unspecified.  Many pipe implementations will
+ * buffer up to a certain number of bytes between the sink and source channels,
+ * but such buffering should not be assumed.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class Pipe {
+
+    /**
+     * A channel representing the readable end of a {@link Pipe}.
+     *
+     * @since 1.4
+     */
+    public static abstract class SourceChannel
+        extends AbstractSelectableChannel
+        implements ReadableByteChannel, ScatteringByteChannel
+    {
+        /**
+         * Constructs a new instance of this class.
+         *
+         * @param  provider
+         *         The selector provider
+         */
+        protected SourceChannel(SelectorProvider provider) {
+            super(provider);
+        }
+
+        /**
+         * Returns an operation set identifying this channel's supported
+         * operations.
+         *
+         * <p> Pipe-source channels only support reading, so this method
+         * returns {@link SelectionKey#OP_READ}.  </p>
+         *
+         * @return  The valid-operation set
+         */
+        public final int validOps() {
+            return SelectionKey.OP_READ;
+        }
+
+    }
+
+    /**
+     * A channel representing the writable end of a {@link Pipe}.
+     *
+     * @since 1.4
+     */
+    public static abstract class SinkChannel
+        extends AbstractSelectableChannel
+        implements WritableByteChannel, GatheringByteChannel
+    {
+        /**
+         * Initializes a new instance of this class.
+         *
+         * @param  provider
+         *         The selector provider
+         */
+        protected SinkChannel(SelectorProvider provider) {
+            super(provider);
+        }
+
+        /**
+         * Returns an operation set identifying this channel's supported
+         * operations.
+         *
+         * <p> Pipe-sink channels only support writing, so this method returns
+         * {@link SelectionKey#OP_WRITE}.  </p>
+         *
+         * @return  The valid-operation set
+         */
+        public final int validOps() {
+            return SelectionKey.OP_WRITE;
+        }
+
+    }
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected Pipe() { }
+
+    /**
+     * Returns this pipe's source channel.
+     *
+     * @return  This pipe's source channel
+     */
+    public abstract SourceChannel source();
+
+    /**
+     * Returns this pipe's sink channel.
+     *
+     * @return  This pipe's sink channel
+     */
+    public abstract SinkChannel sink();
+
+    /**
+     * Opens a pipe.
+     *
+     * <p> The new pipe is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openPipe openPipe} method of the
+     * system-wide default {@link java.nio.channels.spi.SelectorProvider}
+     * object.  </p>
+     *
+     * @return  A new pipe
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static Pipe open() throws IOException {
+        return SelectorProvider.provider().openPipe();
+    }
+
+}
diff --git a/java/nio/channels/ReadPendingException.java b/java/nio/channels/ReadPendingException.java
new file mode 100644
index 0000000..770c9de
--- /dev/null
+++ b/java/nio/channels/ReadPendingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to read from an
+ * asynchronous socket channel and a previous read has not completed.
+ *
+ * @since 1.7
+ */
+
+public class ReadPendingException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 1986315242191227217L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ReadPendingException() { }
+
+}
diff --git a/java/nio/channels/ReadableByteChannel.java b/java/nio/channels/ReadableByteChannel.java
new file mode 100644
index 0000000..4cd99c0
--- /dev/null
+++ b/java/nio/channels/ReadableByteChannel.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A channel that can read bytes.
+ *
+ * <p> Only one read operation upon a readable channel may be in progress at
+ * any given time.  If one thread initiates a read operation upon a channel
+ * then any other thread that attempts to initiate another read operation will
+ * block until the first operation is complete.  Whether or not other kinds of
+ * I/O operations may proceed concurrently with a read operation depends upon
+ * the type of the channel. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface ReadableByteChannel extends Channel {
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> An attempt is made to read up to <i>r</i> bytes from the channel,
+     * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+     * <tt>dst.remaining()</tt>, at the moment this method is invoked.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+     * <tt>0</tt>&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * This byte sequence will be transferred into the buffer so that the first
+     * byte in the sequence is at index <i>p</i> and the last byte is at index
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>,
+     * where <i>p</i> is the buffer's position at the moment this method is
+     * invoked.  Upon return the buffer's position will be equal to
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
+     *
+     * <p> A read operation might not fill the buffer, and in fact it might not
+     * read any bytes at all.  Whether or not it does so depends upon the
+     * nature and state of the channel.  A socket channel in non-blocking mode,
+     * for example, cannot read any more bytes than are immediately available
+     * from the socket's input buffer; similarly, a file channel cannot read
+     * any more bytes than remain in the file.  It is guaranteed, however, that
+     * if a channel is in blocking mode and there is at least one byte
+     * remaining in the buffer then this method will block until at least one
+     * byte is read.
+     *
+     * <p> This method may be invoked at any time.  If another thread has
+     * already initiated a read operation upon this channel, however, then an
+     * invocation of this method will block until the first operation is
+     * complete. </p>
+     *
+     * @param  dst
+     *         The buffer into which bytes are to be transferred
+     *
+     * @return  The number of bytes read, possibly zero, or <tt>-1</tt> if the
+     *          channel has reached end-of-stream
+     *
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public int read(ByteBuffer dst) throws IOException;
+
+}
diff --git a/java/nio/channels/ScatteringByteChannel.java b/java/nio/channels/ScatteringByteChannel.java
new file mode 100644
index 0000000..7922909
--- /dev/null
+++ b/java/nio/channels/ScatteringByteChannel.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A channel that can read bytes into a sequence of buffers.
+ *
+ * <p> A <i>scattering</i> read operation reads, in a single invocation, a
+ * sequence of bytes into one or more of a given sequence of buffers.
+ * Scattering reads are often useful when implementing network protocols or
+ * file formats that, for example, group data into segments consisting of one
+ * or more fixed-length headers followed by a variable-length body.  Similar
+ * <i>gathering</i> write operations are defined in the {@link
+ * GatheringByteChannel} interface.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface ScatteringByteChannel
+    extends ReadableByteChannel
+{
+
+    /**
+     * Reads a sequence of bytes from this channel into a subsequence of the
+     * given buffers.
+     *
+     * <p> An invocation of this method attempts to read up to <i>r</i> bytes
+     * from this channel, where <i>r</i> is the total number of bytes remaining
+     * the specified subsequence of the given buffer array, that is,
+     *
+     * <blockquote><pre>
+     * dsts[offset].remaining()
+     *     + dsts[offset+1].remaining()
+     *     + ... + dsts[offset+length-1].remaining()</pre></blockquote>
+     *
+     * at the moment that this method is invoked.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+     * <tt>0</tt>&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * Up to the first <tt>dsts[offset].remaining()</tt> bytes of this sequence
+     * are transferred into buffer <tt>dsts[offset]</tt>, up to the next
+     * <tt>dsts[offset+1].remaining()</tt> bytes are transferred into buffer
+     * <tt>dsts[offset+1]</tt>, and so forth, until the entire byte sequence
+     * is transferred into the given buffers.  As many bytes as possible are
+     * transferred into each buffer, hence the final position of each updated
+     * buffer, except the last updated buffer, is guaranteed to be equal to
+     * that buffer's limit.
+     *
+     * <p> This method may be invoked at any time.  If another thread has
+     * already initiated a read operation upon this channel, however, then an
+     * invocation of this method will block until the first operation is
+     * complete. </p>
+     *
+     * @param  dsts
+     *         The buffers into which bytes are to be transferred
+     *
+     * @param  offset
+     *         The offset within the buffer array of the first buffer into
+     *         which bytes are to be transferred; must be non-negative and no
+     *         larger than <tt>dsts.length</tt>
+     *
+     * @param  length
+     *         The maximum number of buffers to be accessed; must be
+     *         non-negative and no larger than
+     *         <tt>dsts.length</tt>&nbsp;-&nbsp;<tt>offset</tt>
+     *
+     * @return The number of bytes read, possibly zero,
+     *         or <tt>-1</tt> if the channel has reached end-of-stream
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
+     *          parameters do not hold
+     *
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public long read(ByteBuffer[] dsts, int offset, int length)
+        throws IOException;
+
+    /**
+     * Reads a sequence of bytes from this channel into the given buffers.
+     *
+     * <p> An invocation of this method of the form <tt>c.read(dsts)</tt>
+     * behaves in exactly the same manner as the invocation
+     *
+     * <blockquote><pre>
+     * c.read(dsts, 0, dsts.length);</pre></blockquote>
+     *
+     * @param  dsts
+     *         The buffers into which bytes are to be transferred
+     *
+     * @return The number of bytes read, possibly zero,
+     *         or <tt>-1</tt> if the channel has reached end-of-stream
+     *
+     * @throws  NonReadableChannelException
+     *          If this channel was not opened for reading
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public long read(ByteBuffer[] dsts) throws IOException;
+
+}
diff --git a/java/nio/channels/SeekableByteChannel.java b/java/nio/channels/SeekableByteChannel.java
new file mode 100644
index 0000000..3f5be1c
--- /dev/null
+++ b/java/nio/channels/SeekableByteChannel.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+/**
+ * A byte channel that maintains a current <i>position</i> and allows the
+ * position to be changed.
+ *
+ * <p> A seekable byte channel is connected to an entity, typically a file,
+ * that contains a variable-length sequence of bytes that can be read and
+ * written. The current position can be {@link #position() <i>queried</i>} and
+ * {@link #position(long) <i>modified</i>}. The channel also provides access to
+ * the current <i>size</i> of the entity to which the channel is connected. The
+ * size increases when bytes are written beyond its current size; the size
+ * decreases when it is {@link #truncate <i>truncated</i>}.
+ *
+ * <p> The {@link #position(long) position} and {@link #truncate truncate} methods
+ * which do not otherwise have a value to return are specified to return the
+ * channel upon which they are invoked. This allows method invocations to be
+ * chained. Implementations of this interface should specialize the return type
+ * so that method invocations on the implementation class can be chained.
+ *
+ * @since 1.7
+ * @see java.nio.file.Files#newByteChannel
+ */
+
+public interface SeekableByteChannel
+    extends ByteChannel
+{
+    /**
+     * Reads a sequence of bytes from this channel into the given buffer.
+     *
+     * <p> Bytes are read starting at this channel's current position, and
+     * then the position is updated with the number of bytes actually read.
+     * Otherwise this method behaves exactly as specified in the {@link
+     * ReadableByteChannel} interface.
+     */
+    @Override
+    int read(ByteBuffer dst) throws IOException;
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> Bytes are written starting at this channel's current position, unless
+     * the channel is connected to an entity such as a file that is opened with
+     * the {@link java.nio.file.StandardOpenOption#APPEND APPEND} option, in
+     * which case the position is first advanced to the end. The entity to which
+     * the channel is connected is grown, if necessary, to accommodate the
+     * written bytes, and then the position is updated with the number of bytes
+     * actually written. Otherwise this method behaves exactly as specified by
+     * the {@link WritableByteChannel} interface.
+     */
+    @Override
+    int write(ByteBuffer src) throws IOException;
+
+    /**
+     * Returns this channel's position.
+     *
+     * @return  This channel's position,
+     *          a non-negative integer counting the number of bytes
+     *          from the beginning of the entity to the current position
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    long position() throws IOException;
+
+    /**
+     * Sets this channel's position.
+     *
+     * <p> Setting the position to a value that is greater than the current size
+     * is legal but does not change the size of the entity.  A later attempt to
+     * read bytes at such a position will immediately return an end-of-file
+     * indication.  A later attempt to write bytes at such a position will cause
+     * the entity to grow to accommodate the new bytes; the values of any bytes
+     * between the previous end-of-file and the newly-written bytes are
+     * unspecified.
+     *
+     * <p> Setting the channel's position is not recommended when connected to
+     * an entity, typically a file, that is opened with the {@link
+     * java.nio.file.StandardOpenOption#APPEND APPEND} option. When opened for
+     * append, the position is first advanced to the end before writing.
+     *
+     * @param  newPosition
+     *         The new position, a non-negative integer counting
+     *         the number of bytes from the beginning of the entity
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IllegalArgumentException
+     *          If the new position is negative
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    SeekableByteChannel position(long newPosition) throws IOException;
+
+    /**
+     * Returns the current size of entity to which this channel is connected.
+     *
+     * @return  The current size, measured in bytes
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    long size() throws IOException;
+
+    /**
+     * Truncates the entity, to which this channel is connected, to the given
+     * size.
+     *
+     * <p> If the given size is less than the current size then the entity is
+     * truncated, discarding any bytes beyond the new end. If the given size is
+     * greater than or equal to the current size then the entity is not modified.
+     * In either case, if the current position is greater than the given size
+     * then it is set to that size.
+     *
+     * <p> An implementation of this interface may prohibit truncation when
+     * connected to an entity, typically a file, opened with the {@link
+     * java.nio.file.StandardOpenOption#APPEND APPEND} option.
+     *
+     * @param  size
+     *         The new size, a non-negative byte count
+     *
+     * @return  This channel
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IllegalArgumentException
+     *          If the new size is negative
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    SeekableByteChannel truncate(long size) throws IOException;
+}
diff --git a/java/nio/channels/SelectableChannel.java b/java/nio/channels/SelectableChannel.java
new file mode 100644
index 0000000..997d5c5
--- /dev/null
+++ b/java/nio/channels/SelectableChannel.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.nio.channels.spi.AbstractInterruptibleChannel;
+import java.nio.channels.spi.SelectorProvider;
+
+
+/**
+ * A channel that can be multiplexed via a {@link Selector}.
+ *
+ * <p> In order to be used with a selector, an instance of this class must
+ * first be <i>registered</i> via the {@link #register(Selector,int,Object)
+ * register} method.  This method returns a new {@link SelectionKey} object
+ * that represents the channel's registration with the selector.
+ *
+ * <p> Once registered with a selector, a channel remains registered until it
+ * is <i>deregistered</i>.  This involves deallocating whatever resources were
+ * allocated to the channel by the selector.
+ *
+ * <p> A channel cannot be deregistered directly; instead, the key representing
+ * its registration must be <i>cancelled</i>.  Cancelling a key requests that
+ * the channel be deregistered during the selector's next selection operation.
+ * A key may be cancelled explicitly by invoking its {@link
+ * SelectionKey#cancel() cancel} method.  All of a channel's keys are cancelled
+ * implicitly when the channel is closed, whether by invoking its {@link
+ * Channel#close close} method or by interrupting a thread blocked in an I/O
+ * operation upon the channel.
+ *
+ * <p> If the selector itself is closed then the channel will be deregistered,
+ * and the key representing its registration will be invalidated, without
+ * further delay.
+ *
+ * <p> A channel may be registered at most once with any particular selector.
+ *
+ * <p> Whether or not a channel is registered with one or more selectors may be
+ * determined by invoking the {@link #isRegistered isRegistered} method.
+ *
+ * <p> Selectable channels are safe for use by multiple concurrent
+ * threads. </p>
+ *
+ *
+ * <a name="bm"></a>
+ * <h2>Blocking mode</h2>
+ *
+ * A selectable channel is either in <i>blocking</i> mode or in
+ * <i>non-blocking</i> mode.  In blocking mode, every I/O operation invoked
+ * upon the channel will block until it completes.  In non-blocking mode an I/O
+ * operation will never block and may transfer fewer bytes than were requested
+ * or possibly no bytes at all.  The blocking mode of a selectable channel may
+ * be determined by invoking its {@link #isBlocking isBlocking} method.
+ *
+ * <p> Newly-created selectable channels are always in blocking mode.
+ * Non-blocking mode is most useful in conjunction with selector-based
+ * multiplexing.  A channel must be placed into non-blocking mode before being
+ * registered with a selector, and may not be returned to blocking mode until
+ * it has been deregistered.
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see SelectionKey
+ * @see Selector
+ */
+
+public abstract class SelectableChannel
+    extends AbstractInterruptibleChannel
+    implements Channel
+{
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected SelectableChannel() { }
+
+    /**
+     * Returns the provider that created this channel.
+     *
+     * @return  The provider that created this channel
+     */
+    public abstract SelectorProvider provider();
+
+    /**
+     * Returns an <a href="SelectionKey.html#opsets">operation set</a>
+     * identifying this channel's supported operations.  The bits that are set
+     * in this integer value denote exactly the operations that are valid for
+     * this channel.  This method always returns the same value for a given
+     * concrete channel class.
+     *
+     * @return  The valid-operation set
+     */
+    public abstract int validOps();
+
+    // Internal state:
+    //   keySet, may be empty but is never null, typ. a tiny array
+    //   boolean isRegistered, protected by key set
+    //   regLock, lock object to prevent duplicate registrations
+    //   boolean isBlocking, protected by regLock
+
+    /**
+     * Tells whether or not this channel is currently registered with any
+     * selectors.  A newly-created channel is not registered.
+     *
+     * <p> Due to the inherent delay between key cancellation and channel
+     * deregistration, a channel may remain registered for some time after all
+     * of its keys have been cancelled.  A channel may also remain registered
+     * for some time after it is closed.  </p>
+     *
+     * @return <tt>true</tt> if, and only if, this channel is registered
+     */
+    public abstract boolean isRegistered();
+    //
+    // sync(keySet) { return isRegistered; }
+
+    /**
+     * Retrieves the key representing the channel's registration with the given
+     * selector.
+     *
+     * @param   sel
+     *          The selector
+     *
+     * @return  The key returned when this channel was last registered with the
+     *          given selector, or <tt>null</tt> if this channel is not
+     *          currently registered with that selector
+     */
+    public abstract SelectionKey keyFor(Selector sel);
+    //
+    // sync(keySet) { return findKey(sel); }
+
+    /**
+     * Registers this channel with the given selector, returning a selection
+     * key.
+     *
+     * <p> If this channel is currently registered with the given selector then
+     * the selection key representing that registration is returned.  The key's
+     * interest set will have been changed to <tt>ops</tt>, as if by invoking
+     * the {@link SelectionKey#interestOps(int) interestOps(int)} method.  If
+     * the <tt>att</tt> argument is not <tt>null</tt> then the key's attachment
+     * will have been set to that value.  A {@link CancelledKeyException} will
+     * be thrown if the key has already been cancelled.
+     *
+     * <p> Otherwise this channel has not yet been registered with the given
+     * selector, so it is registered and the resulting new key is returned.
+     * The key's initial interest set will be <tt>ops</tt> and its attachment
+     * will be <tt>att</tt>.
+     *
+     * <p> This method may be invoked at any time.  If this method is invoked
+     * while another invocation of this method or of the {@link
+     * #configureBlocking(boolean) configureBlocking} method is in progress
+     * then it will first block until the other operation is complete.  This
+     * method will then synchronize on the selector's key set and therefore may
+     * block if invoked concurrently with another registration or selection
+     * operation involving the same selector. </p>
+     *
+     * <p> If this channel is closed while this operation is in progress then
+     * the key returned by this method will have been cancelled and will
+     * therefore be invalid. </p>
+     *
+     * @param  sel
+     *         The selector with which this channel is to be registered
+     *
+     * @param  ops
+     *         The interest set for the resulting key
+     *
+     * @param  att
+     *         The attachment for the resulting key; may be <tt>null</tt>
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  ClosedSelectorException
+     *          If the selector is closed
+     *
+     * @throws  IllegalBlockingModeException
+     *          If this channel is in blocking mode
+     *
+     * @throws  IllegalSelectorException
+     *          If this channel was not created by the same provider
+     *          as the given selector
+     *
+     * @throws  CancelledKeyException
+     *          If this channel is currently registered with the given selector
+     *          but the corresponding key has already been cancelled
+     *
+     * @throws  IllegalArgumentException
+     *          If a bit in the <tt>ops</tt> set does not correspond to an
+     *          operation that is supported by this channel, that is, if
+     *          {@code set & ~validOps() != 0}
+     *
+     * @return  A key representing the registration of this channel with
+     *          the given selector
+     */
+    public abstract SelectionKey register(Selector sel, int ops, Object att)
+        throws ClosedChannelException;
+    //
+    // sync(regLock) {
+    //   sync(keySet) { look for selector }
+    //   if (channel found) { set interest ops -- may block in selector;
+    //                        return key; }
+    //   create new key -- may block somewhere in selector;
+    //   sync(keySet) { add key; }
+    //   attach(attachment);
+    //   return key;
+    // }
+
+    /**
+     * Registers this channel with the given selector, returning a selection
+     * key.
+     *
+     * <p> An invocation of this convenience method of the form
+     *
+     * <blockquote><tt>sc.register(sel, ops)</tt></blockquote>
+     *
+     * behaves in exactly the same way as the invocation
+     *
+     * <blockquote><tt>sc.{@link
+     * #register(java.nio.channels.Selector,int,java.lang.Object)
+     * register}(sel, ops, null)</tt></blockquote>
+     *
+     * @param  sel
+     *         The selector with which this channel is to be registered
+     *
+     * @param  ops
+     *         The interest set for the resulting key
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  ClosedSelectorException
+     *          If the selector is closed
+     *
+     * @throws  IllegalBlockingModeException
+     *          If this channel is in blocking mode
+     *
+     * @throws  IllegalSelectorException
+     *          If this channel was not created by the same provider
+     *          as the given selector
+     *
+     * @throws  CancelledKeyException
+     *          If this channel is currently registered with the given selector
+     *          but the corresponding key has already been cancelled
+     *
+     * @throws  IllegalArgumentException
+     *          If a bit in <tt>ops</tt> does not correspond to an operation
+     *          that is supported by this channel, that is, if {@code set &
+     *          ~validOps() != 0}
+     *
+     * @return  A key representing the registration of this channel with
+     *          the given selector
+     */
+    public final SelectionKey register(Selector sel, int ops)
+        throws ClosedChannelException
+    {
+        return register(sel, ops, null);
+    }
+
+    /**
+     * Adjusts this channel's blocking mode.
+     *
+     * <p> If this channel is registered with one or more selectors then an
+     * attempt to place it into blocking mode will cause an {@link
+     * IllegalBlockingModeException} to be thrown.
+     *
+     * <p> This method may be invoked at any time.  The new blocking mode will
+     * only affect I/O operations that are initiated after this method returns.
+     * For some implementations this may require blocking until all pending I/O
+     * operations are complete.
+     *
+     * <p> If this method is invoked while another invocation of this method or
+     * of the {@link #register(Selector, int) register} method is in progress
+     * then it will first block until the other operation is complete. </p>
+     *
+     * @param  block  If <tt>true</tt> then this channel will be placed in
+     *                blocking mode; if <tt>false</tt> then it will be placed
+     *                non-blocking mode
+     *
+     * @return  This selectable channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IllegalBlockingModeException
+     *          If <tt>block</tt> is <tt>true</tt> and this channel is
+     *          registered with one or more selectors
+     *
+     * @throws IOException
+     *         If an I/O error occurs
+     */
+    public abstract SelectableChannel configureBlocking(boolean block)
+        throws IOException;
+    //
+    // sync(regLock) {
+    //   sync(keySet) { throw IBME if block && isRegistered; }
+    //   change mode;
+    // }
+
+    /**
+     * Tells whether or not every I/O operation on this channel will block
+     * until it completes.  A newly-created channel is always in blocking mode.
+     *
+     * <p> If this channel is closed then the value returned by this method is
+     * not specified. </p>
+     *
+     * @return <tt>true</tt> if, and only if, this channel is in blocking mode
+     */
+    public abstract boolean isBlocking();
+
+    /**
+     * Retrieves the object upon which the {@link #configureBlocking
+     * configureBlocking} and {@link #register register} methods synchronize.
+     * This is often useful in the implementation of adaptors that require a
+     * specific blocking mode to be maintained for a short period of time.
+     *
+     * @return  The blocking-mode lock object
+     */
+    public abstract Object blockingLock();
+
+}
diff --git a/java/nio/channels/SelectionKey.java b/java/nio/channels/SelectionKey.java
new file mode 100644
index 0000000..00ea670
--- /dev/null
+++ b/java/nio/channels/SelectionKey.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import java.io.IOException;
+
+
+/**
+ * A token representing the registration of a {@link SelectableChannel} with a
+ * {@link Selector}.
+ *
+ * <p> A selection key is created each time a channel is registered with a
+ * selector.  A key remains valid until it is <i>cancelled</i> by invoking its
+ * {@link #cancel cancel} method, by closing its channel, or by closing its
+ * selector.  Cancelling a key does not immediately remove it from its
+ * selector; it is instead added to the selector's <a
+ * href="Selector.html#ks"><i>cancelled-key set</i></a> for removal during the
+ * next selection operation.  The validity of a key may be tested by invoking
+ * its {@link #isValid isValid} method.
+ *
+ * <a name="opsets"></a>
+ *
+ * <p> A selection key contains two <i>operation sets</i> represented as
+ * integer values.  Each bit of an operation set denotes a category of
+ * selectable operations that are supported by the key's channel.
+ *
+ * <ul>
+ *
+ *   <li><p> The <i>interest set</i> determines which operation categories will
+ *   be tested for readiness the next time one of the selector's selection
+ *   methods is invoked.  The interest set is initialized with the value given
+ *   when the key is created; it may later be changed via the {@link
+ *   #interestOps(int)} method. </p></li>
+ *
+ *   <li><p> The <i>ready set</i> identifies the operation categories for which
+ *   the key's channel has been detected to be ready by the key's selector.
+ *   The ready set is initialized to zero when the key is created; it may later
+ *   be updated by the selector during a selection operation, but it cannot be
+ *   updated directly. </p></li>
+ *
+ * </ul>
+ *
+ * <p> That a selection key's ready set indicates that its channel is ready for
+ * some operation category is a hint, but not a guarantee, that an operation in
+ * such a category may be performed by a thread without causing the thread to
+ * block.  A ready set is most likely to be accurate immediately after the
+ * completion of a selection operation.  It is likely to be made inaccurate by
+ * external events and by I/O operations that are invoked upon the
+ * corresponding channel.
+ *
+ * <p> This class defines all known operation-set bits, but precisely which
+ * bits are supported by a given channel depends upon the type of the channel.
+ * Each subclass of {@link SelectableChannel} defines an {@link
+ * SelectableChannel#validOps() validOps()} method which returns a set
+ * identifying just those operations that are supported by the channel.  An
+ * attempt to set or test an operation-set bit that is not supported by a key's
+ * channel will result in an appropriate run-time exception.
+ *
+ * <p> It is often necessary to associate some application-specific data with a
+ * selection key, for example an object that represents the state of a
+ * higher-level protocol and handles readiness notifications in order to
+ * implement that protocol.  Selection keys therefore support the
+ * <i>attachment</i> of a single arbitrary object to a key.  An object can be
+ * attached via the {@link #attach attach} method and then later retrieved via
+ * the {@link #attachment() attachment} method.
+ *
+ * <p> Selection keys are safe for use by multiple concurrent threads.  The
+ * operations of reading and writing the interest set will, in general, be
+ * synchronized with certain operations of the selector.  Exactly how this
+ * synchronization is performed is implementation-dependent: In a naive
+ * implementation, reading or writing the interest set may block indefinitely
+ * if a selection operation is already in progress; in a high-performance
+ * implementation, reading or writing the interest set may block briefly, if at
+ * all.  In any case, a selection operation will always use the interest-set
+ * value that was current at the moment that the operation began.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see SelectableChannel
+ * @see Selector
+ */
+
+public abstract class SelectionKey {
+
+    /**
+     * Constructs an instance of this class.
+     */
+    protected SelectionKey() { }
+
+
+    // -- Channel and selector operations --
+
+    /**
+     * Returns the channel for which this key was created.  This method will
+     * continue to return the channel even after the key is cancelled.
+     *
+     * @return  This key's channel
+     */
+    public abstract SelectableChannel channel();
+
+    /**
+     * Returns the selector for which this key was created.  This method will
+     * continue to return the selector even after the key is cancelled.
+     *
+     * @return  This key's selector
+     */
+    public abstract Selector selector();
+
+    /**
+     * Tells whether or not this key is valid.
+     *
+     * <p> A key is valid upon creation and remains so until it is cancelled,
+     * its channel is closed, or its selector is closed.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this key is valid
+     */
+    public abstract boolean isValid();
+
+    /**
+     * Requests that the registration of this key's channel with its selector
+     * be cancelled.  Upon return the key will be invalid and will have been
+     * added to its selector's cancelled-key set.  The key will be removed from
+     * all of the selector's key sets during the next selection operation.
+     *
+     * <p> If this key has already been cancelled then invoking this method has
+     * no effect.  Once cancelled, a key remains forever invalid. </p>
+     *
+     * <p> This method may be invoked at any time.  It synchronizes on the
+     * selector's cancelled-key set, and therefore may block briefly if invoked
+     * concurrently with a cancellation or selection operation involving the
+     * same selector.  </p>
+     */
+    public abstract void cancel();
+
+
+    // -- Operation-set accessors --
+
+    /**
+     * Retrieves this key's interest set.
+     *
+     * <p> It is guaranteed that the returned set will only contain operation
+     * bits that are valid for this key's channel.
+     *
+     * <p> This method may be invoked at any time.  Whether or not it blocks,
+     * and for how long, is implementation-dependent.  </p>
+     *
+     * @return  This key's interest set
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public abstract int interestOps();
+
+    /**
+     * Sets this key's interest set to the given value.
+     *
+     * <p> This method may be invoked at any time.  Whether or not it blocks,
+     * and for how long, is implementation-dependent.  </p>
+     *
+     * @param  ops  The new interest set
+     *
+     * @return  This selection key
+     *
+     * @throws  IllegalArgumentException
+     *          If a bit in the set does not correspond to an operation that
+     *          is supported by this key's channel, that is, if
+     *          {@code (ops & ~channel().validOps()) != 0}
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public abstract SelectionKey interestOps(int ops);
+
+    /**
+     * Retrieves this key's ready-operation set.
+     *
+     * <p> It is guaranteed that the returned set will only contain operation
+     * bits that are valid for this key's channel.  </p>
+     *
+     * @return  This key's ready-operation set
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public abstract int readyOps();
+
+
+    // -- Operation bits and bit-testing convenience methods --
+
+    /**
+     * Operation-set bit for read operations.
+     *
+     * <p> Suppose that a selection key's interest set contains
+     * <tt>OP_READ</tt> at the start of a <a
+     * href="Selector.html#selop">selection operation</a>.  If the selector
+     * detects that the corresponding channel is ready for reading, has reached
+     * end-of-stream, has been remotely shut down for further reading, or has
+     * an error pending, then it will add <tt>OP_READ</tt> to the key's
+     * ready-operation set and add the key to its selected-key&nbsp;set.  </p>
+     */
+    public static final int OP_READ = 1 << 0;
+
+    /**
+     * Operation-set bit for write operations.
+     *
+     * <p> Suppose that a selection key's interest set contains
+     * <tt>OP_WRITE</tt> at the start of a <a
+     * href="Selector.html#selop">selection operation</a>.  If the selector
+     * detects that the corresponding channel is ready for writing, has been
+     * remotely shut down for further writing, or has an error pending, then it
+     * will add <tt>OP_WRITE</tt> to the key's ready set and add the key to its
+     * selected-key&nbsp;set.  </p>
+     */
+    public static final int OP_WRITE = 1 << 2;
+
+    /**
+     * Operation-set bit for socket-connect operations.
+     *
+     * <p> Suppose that a selection key's interest set contains
+     * <tt>OP_CONNECT</tt> at the start of a <a
+     * href="Selector.html#selop">selection operation</a>.  If the selector
+     * detects that the corresponding socket channel is ready to complete its
+     * connection sequence, or has an error pending, then it will add
+     * <tt>OP_CONNECT</tt> to the key's ready set and add the key to its
+     * selected-key&nbsp;set.  </p>
+     */
+    public static final int OP_CONNECT = 1 << 3;
+
+    /**
+     * Operation-set bit for socket-accept operations.
+     *
+     * <p> Suppose that a selection key's interest set contains
+     * <tt>OP_ACCEPT</tt> at the start of a <a
+     * href="Selector.html#selop">selection operation</a>.  If the selector
+     * detects that the corresponding server-socket channel is ready to accept
+     * another connection, or has an error pending, then it will add
+     * <tt>OP_ACCEPT</tt> to the key's ready set and add the key to its
+     * selected-key&nbsp;set.  </p>
+     */
+    public static final int OP_ACCEPT = 1 << 4;
+
+    /**
+     * Tests whether this key's channel is ready for reading.
+     *
+     * <p> An invocation of this method of the form <tt>k.isReadable()</tt>
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>{@code
+     * k.readyOps() & OP_READ != 0
+     * }</pre></blockquote>
+     *
+     * <p> If this key's channel does not support read operations then this
+     * method always returns <tt>false</tt>.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if,
+                {@code readyOps() & OP_READ} is nonzero
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public final boolean isReadable() {
+        return (readyOps() & OP_READ) != 0;
+    }
+
+    /**
+     * Tests whether this key's channel is ready for writing.
+     *
+     * <p> An invocation of this method of the form <tt>k.isWritable()</tt>
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>{@code
+     * k.readyOps() & OP_WRITE != 0
+     * }</pre></blockquote>
+     *
+     * <p> If this key's channel does not support write operations then this
+     * method always returns <tt>false</tt>.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if,
+     *          {@code readyOps() & OP_WRITE} is nonzero
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public final boolean isWritable() {
+        return (readyOps() & OP_WRITE) != 0;
+    }
+
+    /**
+     * Tests whether this key's channel has either finished, or failed to
+     * finish, its socket-connection operation.
+     *
+     * <p> An invocation of this method of the form <tt>k.isConnectable()</tt>
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>{@code
+     * k.readyOps() & OP_CONNECT != 0
+     * }</pre></blockquote>
+     *
+     * <p> If this key's channel does not support socket-connect operations
+     * then this method always returns <tt>false</tt>.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if,
+     *          {@code readyOps() & OP_CONNECT} is nonzero
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public final boolean isConnectable() {
+        return (readyOps() & OP_CONNECT) != 0;
+    }
+
+    /**
+     * Tests whether this key's channel is ready to accept a new socket
+     * connection.
+     *
+     * <p> An invocation of this method of the form <tt>k.isAcceptable()</tt>
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>{@code
+     * k.readyOps() & OP_ACCEPT != 0
+     * }</pre></blockquote>
+     *
+     * <p> If this key's channel does not support socket-accept operations then
+     * this method always returns <tt>false</tt>.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if,
+     *          {@code readyOps() & OP_ACCEPT} is nonzero
+     *
+     * @throws  CancelledKeyException
+     *          If this key has been cancelled
+     */
+    public final boolean isAcceptable() {
+        return (readyOps() & OP_ACCEPT) != 0;
+    }
+
+
+    // -- Attachments --
+
+    private volatile Object attachment = null;
+
+    private static final AtomicReferenceFieldUpdater<SelectionKey,Object>
+        attachmentUpdater = AtomicReferenceFieldUpdater.newUpdater(
+            SelectionKey.class, Object.class, "attachment"
+        );
+
+    /**
+     * Attaches the given object to this key.
+     *
+     * <p> An attached object may later be retrieved via the {@link #attachment()
+     * attachment} method.  Only one object may be attached at a time; invoking
+     * this method causes any previous attachment to be discarded.  The current
+     * attachment may be discarded by attaching <tt>null</tt>.  </p>
+     *
+     * @param  ob
+     *         The object to be attached; may be <tt>null</tt>
+     *
+     * @return  The previously-attached object, if any,
+     *          otherwise <tt>null</tt>
+     */
+    public final Object attach(Object ob) {
+        return attachmentUpdater.getAndSet(this, ob);
+    }
+
+    /**
+     * Retrieves the current attachment.
+     *
+     * @return  The object currently attached to this key,
+     *          or <tt>null</tt> if there is no attachment
+     */
+    public final Object attachment() {
+        return attachment;
+    }
+
+}
diff --git a/java/nio/channels/Selector.java b/java/nio/channels/Selector.java
new file mode 100644
index 0000000..ea72acb
--- /dev/null
+++ b/java/nio/channels/Selector.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.Set;
+
+
+/**
+ * A multiplexor of {@link SelectableChannel} objects.
+ *
+ * <p> A selector may be created by invoking the {@link #open open} method of
+ * this class, which will use the system's default {@link
+ * java.nio.channels.spi.SelectorProvider selector provider} to
+ * create a new selector.  A selector may also be created by invoking the
+ * {@link java.nio.channels.spi.SelectorProvider#openSelector openSelector}
+ * method of a custom selector provider.  A selector remains open until it is
+ * closed via its {@link #close close} method.
+ *
+ * <a name="ks"></a>
+ *
+ * <p> A selectable channel's registration with a selector is represented by a
+ * {@link SelectionKey} object.  A selector maintains three sets of selection
+ * keys:
+ *
+ * <ul>
+ *
+ *   <li><p> The <i>key set</i> contains the keys representing the current
+ *   channel registrations of this selector.  This set is returned by the
+ *   {@link #keys() keys} method. </p></li>
+ *
+ *   <li><p> The <i>selected-key set</i> is the set of keys such that each
+ *   key's channel was detected to be ready for at least one of the operations
+ *   identified in the key's interest set during a prior selection operation.
+ *   This set is returned by the {@link #selectedKeys() selectedKeys} method.
+ *   The selected-key set is always a subset of the key set. </p></li>
+ *
+ *   <li><p> The <i>cancelled-key</i> set is the set of keys that have been
+ *   cancelled but whose channels have not yet been deregistered.  This set is
+ *   not directly accessible.  The cancelled-key set is always a subset of the
+ *   key set. </p></li>
+ *
+ * </ul>
+ *
+ * <p> All three sets are empty in a newly-created selector.
+ *
+ * <p> A key is added to a selector's key set as a side effect of registering a
+ * channel via the channel's {@link SelectableChannel#register(Selector,int)
+ * register} method.  Cancelled keys are removed from the key set during
+ * selection operations.  The key set itself is not directly modifiable.
+ *
+ * <p> A key is added to its selector's cancelled-key set when it is cancelled,
+ * whether by closing its channel or by invoking its {@link SelectionKey#cancel
+ * cancel} method.  Cancelling a key will cause its channel to be deregistered
+ * during the next selection operation, at which time the key will removed from
+ * all of the selector's key sets.
+ *
+ * <a name="sks"></a><p> Keys are added to the selected-key set by selection
+ * operations.  A key may be removed directly from the selected-key set by
+ * invoking the set's {@link java.util.Set#remove(java.lang.Object) remove}
+ * method or by invoking the {@link java.util.Iterator#remove() remove} method
+ * of an {@link java.util.Iterator iterator} obtained from the
+ * set.  Keys are never removed from the selected-key set in any other way;
+ * they are not, in particular, removed as a side effect of selection
+ * operations.  Keys may not be added directly to the selected-key set. </p>
+ *
+ *
+ * <a name="selop"></a>
+ * <h2>Selection</h2>
+ *
+ * <p> During each selection operation, keys may be added to and removed from a
+ * selector's selected-key set and may be removed from its key and
+ * cancelled-key sets.  Selection is performed by the {@link #select()}, {@link
+ * #select(long)}, and {@link #selectNow()} methods, and involves three steps:
+ * </p>
+ *
+ * <ol>
+ *
+ *   <li><p> Each key in the cancelled-key set is removed from each key set of
+ *   which it is a member, and its channel is deregistered.  This step leaves
+ *   the cancelled-key set empty. </p></li>
+ *
+ *   <li><p> The underlying operating system is queried for an update as to the
+ *   readiness of each remaining channel to perform any of the operations
+ *   identified by its key's interest set as of the moment that the selection
+ *   operation began.  For a channel that is ready for at least one such
+ *   operation, one of the following two actions is performed: </p>
+ *
+ *   <ol>
+ *
+ *     <li><p> If the channel's key is not already in the selected-key set then
+ *     it is added to that set and its ready-operation set is modified to
+ *     identify exactly those operations for which the channel is now reported
+ *     to be ready.  Any readiness information previously recorded in the ready
+ *     set is discarded.  </p></li>
+ *
+ *     <li><p> Otherwise the channel's key is already in the selected-key set,
+ *     so its ready-operation set is modified to identify any new operations
+ *     for which the channel is reported to be ready.  Any readiness
+ *     information previously recorded in the ready set is preserved; in other
+ *     words, the ready set returned by the underlying system is
+ *     bitwise-disjoined into the key's current ready set. </p></li>
+ *
+ *   </ol>
+ *
+ *   If all of the keys in the key set at the start of this step have empty
+ *   interest sets then neither the selected-key set nor any of the keys'
+ *   ready-operation sets will be updated.
+ *
+ *   <li><p> If any keys were added to the cancelled-key set while step (2) was
+ *   in progress then they are processed as in step (1). </p></li>
+ *
+ * </ol>
+ *
+ * <p> Whether or not a selection operation blocks to wait for one or more
+ * channels to become ready, and if so for how long, is the only essential
+ * difference between the three selection methods. </p>
+ *
+ *
+ * <h2>Concurrency</h2>
+ *
+ * <p> Selectors are themselves safe for use by multiple concurrent threads;
+ * their key sets, however, are not.
+ *
+ * <p> The selection operations synchronize on the selector itself, on the key
+ * set, and on the selected-key set, in that order.  They also synchronize on
+ * the cancelled-key set during steps (1) and (3) above.
+ *
+ * <p> Changes made to the interest sets of a selector's keys while a
+ * selection operation is in progress have no effect upon that operation; they
+ * will be seen by the next selection operation.
+ *
+ * <p> Keys may be cancelled and channels may be closed at any time.  Hence the
+ * presence of a key in one or more of a selector's key sets does not imply
+ * that the key is valid or that its channel is open.  Application code should
+ * be careful to synchronize and check these conditions as necessary if there
+ * is any possibility that another thread will cancel a key or close a channel.
+ *
+ * <p> A thread blocked in one of the {@link #select()} or {@link
+ * #select(long)} methods may be interrupted by some other thread in one of
+ * three ways:
+ *
+ * <ul>
+ *
+ *   <li><p> By invoking the selector's {@link #wakeup wakeup} method,
+ *   </p></li>
+ *
+ *   <li><p> By invoking the selector's {@link #close close} method, or
+ *   </p></li>
+ *
+ *   <li><p> By invoking the blocked thread's {@link
+ *   java.lang.Thread#interrupt() interrupt} method, in which case its
+ *   interrupt status will be set and the selector's {@link #wakeup wakeup}
+ *   method will be invoked. </p></li>
+ *
+ * </ul>
+ *
+ * <p> The {@link #close close} method synchronizes on the selector and all
+ * three key sets in the same order as in a selection operation.
+ *
+ * <a name="ksc"></a>
+ *
+ * <p> A selector's key and selected-key sets are not, in general, safe for use
+ * by multiple concurrent threads.  If such a thread might modify one of these
+ * sets directly then access should be controlled by synchronizing on the set
+ * itself.  The iterators returned by these sets' {@link
+ * java.util.Set#iterator() iterator} methods are <i>fail-fast:</i> If the set
+ * is modified after the iterator is created, in any way except by invoking the
+ * iterator's own {@link java.util.Iterator#remove() remove} method, then a
+ * {@link java.util.ConcurrentModificationException} will be thrown. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see SelectableChannel
+ * @see SelectionKey
+ */
+
+public abstract class Selector implements Closeable {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected Selector() { }
+
+    /**
+     * Opens a selector.
+     *
+     * <p> The new selector is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openSelector openSelector} method
+     * of the system-wide default {@link
+     * java.nio.channels.spi.SelectorProvider} object.  </p>
+     *
+     * @return  A new selector
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static Selector open() throws IOException {
+        return SelectorProvider.provider().openSelector();
+    }
+
+    /**
+     * Tells whether or not this selector is open.
+     *
+     * @return <tt>true</tt> if, and only if, this selector is open
+     */
+    public abstract boolean isOpen();
+
+    /**
+     * Returns the provider that created this channel.
+     *
+     * @return  The provider that created this channel
+     */
+    public abstract SelectorProvider provider();
+
+    /**
+     * Returns this selector's key set.
+     *
+     * <p> The key set is not directly modifiable.  A key is removed only after
+     * it has been cancelled and its channel has been deregistered.  Any
+     * attempt to modify the key set will cause an {@link
+     * UnsupportedOperationException} to be thrown.
+     *
+     * <p> The key set is <a href="#ksc">not thread-safe</a>. </p>
+     *
+     * @return  This selector's key set
+     *
+     * @throws  ClosedSelectorException
+     *          If this selector is closed
+     */
+    public abstract Set<SelectionKey> keys();
+
+    /**
+     * Returns this selector's selected-key set.
+     *
+     * <p> Keys may be removed from, but not directly added to, the
+     * selected-key set.  Any attempt to add an object to the key set will
+     * cause an {@link UnsupportedOperationException} to be thrown.
+     *
+     * <p> The selected-key set is <a href="#ksc">not thread-safe</a>. </p>
+     *
+     * @return  This selector's selected-key set
+     *
+     * @throws  ClosedSelectorException
+     *          If this selector is closed
+     */
+    public abstract Set<SelectionKey> selectedKeys();
+
+    /**
+     * Selects a set of keys whose corresponding channels are ready for I/O
+     * operations.
+     *
+     * <p> This method performs a non-blocking <a href="#selop">selection
+     * operation</a>.  If no channels have become selectable since the previous
+     * selection operation then this method immediately returns zero.
+     *
+     * <p> Invoking this method clears the effect of any previous invocations
+     * of the {@link #wakeup wakeup} method.  </p>
+     *
+     * @return  The number of keys, possibly zero, whose ready-operation sets
+     *          were updated by the selection operation
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  ClosedSelectorException
+     *          If this selector is closed
+     */
+    public abstract int selectNow() throws IOException;
+
+    /**
+     * Selects a set of keys whose corresponding channels are ready for I/O
+     * operations.
+     *
+     * <p> This method performs a blocking <a href="#selop">selection
+     * operation</a>.  It returns only after at least one channel is selected,
+     * this selector's {@link #wakeup wakeup} method is invoked, the current
+     * thread is interrupted, or the given timeout period expires, whichever
+     * comes first.
+     *
+     * <p> This method does not offer real-time guarantees: It schedules the
+     * timeout as if by invoking the {@link Object#wait(long)} method. </p>
+     *
+     * @param  timeout  If positive, block for up to <tt>timeout</tt>
+     *                  milliseconds, more or less, while waiting for a
+     *                  channel to become ready; if zero, block indefinitely;
+     *                  must not be negative
+     *
+     * @return  The number of keys, possibly zero,
+     *          whose ready-operation sets were updated
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  ClosedSelectorException
+     *          If this selector is closed
+     *
+     * @throws  IllegalArgumentException
+     *          If the value of the timeout argument is negative
+     */
+    public abstract int select(long timeout)
+        throws IOException;
+
+    /**
+     * Selects a set of keys whose corresponding channels are ready for I/O
+     * operations.
+     *
+     * <p> This method performs a blocking <a href="#selop">selection
+     * operation</a>.  It returns only after at least one channel is selected,
+     * this selector's {@link #wakeup wakeup} method is invoked, or the current
+     * thread is interrupted, whichever comes first.  </p>
+     *
+     * @return  The number of keys, possibly zero,
+     *          whose ready-operation sets were updated
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  ClosedSelectorException
+     *          If this selector is closed
+     */
+    public abstract int select() throws IOException;
+
+    /**
+     * Causes the first selection operation that has not yet returned to return
+     * immediately.
+     *
+     * <p> If another thread is currently blocked in an invocation of the
+     * {@link #select()} or {@link #select(long)} methods then that invocation
+     * will return immediately.  If no selection operation is currently in
+     * progress then the next invocation of one of these methods will return
+     * immediately unless the {@link #selectNow()} method is invoked in the
+     * meantime.  In any case the value returned by that invocation may be
+     * non-zero.  Subsequent invocations of the {@link #select()} or {@link
+     * #select(long)} methods will block as usual unless this method is invoked
+     * again in the meantime.
+     *
+     * <p> Invoking this method more than once between two successive selection
+     * operations has the same effect as invoking it just once.  </p>
+     *
+     * @return  This selector
+     */
+    public abstract Selector wakeup();
+
+    /**
+     * Closes this selector.
+     *
+     * <p> If a thread is currently blocked in one of this selector's selection
+     * methods then it is interrupted as if by invoking the selector's {@link
+     * #wakeup wakeup} method.
+     *
+     * <p> Any uncancelled keys still associated with this selector are
+     * invalidated, their channels are deregistered, and any other resources
+     * associated with this selector are released.
+     *
+     * <p> If this selector is already closed then invoking this method has no
+     * effect.
+     *
+     * <p> After a selector is closed, any further attempt to use it, except by
+     * invoking this method or the {@link #wakeup wakeup} method, will cause a
+     * {@link ClosedSelectorException} to be thrown. </p>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract void close() throws IOException;
+
+}
diff --git a/java/nio/channels/ServerSocketChannel.java b/java/nio/channels/ServerSocketChannel.java
new file mode 100644
index 0000000..8d967b3
--- /dev/null
+++ b/java/nio/channels/ServerSocketChannel.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
+
+/**
+ * A selectable channel for stream-oriented listening sockets.
+ *
+ * <p> A server-socket channel is created by invoking the {@link #open() open}
+ * method of this class.  It is not possible to create a channel for an arbitrary,
+ * pre-existing {@link ServerSocket}. A newly-created server-socket channel is
+ * open but not yet bound.  An attempt to invoke the {@link #accept() accept}
+ * method of an unbound server-socket channel will cause a {@link NotYetBoundException}
+ * to be thrown. A server-socket channel can be bound by invoking one of the
+ * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Server-socket channels support the following options:
+ * <blockquote>
+ * <table border summary="Socket options">
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> Server-socket channels are safe for use by multiple concurrent threads.
+ * </p>
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class ServerSocketChannel
+    extends AbstractSelectableChannel
+    implements NetworkChannel
+{
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this channel
+     */
+    protected ServerSocketChannel(SelectorProvider provider) {
+        super(provider);
+    }
+
+    /**
+     * Opens a server-socket channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openServerSocketChannel
+     * openServerSocketChannel} method of the system-wide default {@link
+     * java.nio.channels.spi.SelectorProvider} object.
+     *
+     * <p> The new channel's socket is initially unbound; it must be bound to a
+     * specific address via one of its socket's {@link
+     * java.net.ServerSocket#bind(SocketAddress) bind} methods before
+     * connections can be accepted.  </p>
+     *
+     * @return  A new socket channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static ServerSocketChannel open() throws IOException {
+        return SelectorProvider.provider().openServerSocketChannel();
+    }
+
+    /**
+     * Returns an operation set identifying this channel's supported
+     * operations.
+     *
+     * <p> Server-socket channels only support the accepting of new
+     * connections, so this method returns {@link SelectionKey#OP_ACCEPT}.
+     * </p>
+     *
+     * @return  The valid-operation set
+     */
+    public final int validOps() {
+        return SelectionKey.OP_ACCEPT;
+    }
+
+
+    // -- ServerSocket-specific operations --
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket
+     * to listen for connections.
+     *
+     * <p> An invocation of this method is equivalent to the following:
+     * <blockquote><pre>
+     * bind(local, 0);
+     * </pre></blockquote>
+     *
+     * @param   local
+     *          The local address to bind the socket, or {@code null} to bind
+     *          to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     *
+     * @since 1.7
+     */
+    public final ServerSocketChannel bind(SocketAddress local)
+        throws IOException
+    {
+        return bind(local, 0);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket to
+     * listen for connections.
+     *
+     * <p> This method is used to establish an association between the socket and
+     * a local address. Once an association is established then the socket remains
+     * bound until the channel is closed.
+     *
+     * <p> The {@code backlog} parameter is the maximum number of pending
+     * connections on the socket. Its exact semantics are implementation specific.
+     * In particular, an implementation may impose a maximum length or may choose
+     * to ignore the parameter altogther. If the {@code backlog} parameter has
+     * the value {@code 0}, or a negative value, then an implementation specific
+     * default is used.
+     *
+     * @param   local
+     *          The address to bind the socket, or {@code null} to bind to an
+     *          automatically assigned socket address
+     * @param   backlog
+     *          The maximum number of pending connections
+     *
+     * @return  This channel
+     *
+     * @throws  AlreadyBoundException
+     *          If the socket is already bound
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          SecurityManager#checkListen checkListen} method denies the
+     *          operation
+     *
+     * @since 1.7
+     */
+    public abstract ServerSocketChannel bind(SocketAddress local, int backlog)
+        throws IOException;
+
+    /**
+     * @throws  UnsupportedOperationException           {@inheritDoc}
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    public abstract <T> ServerSocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Retrieves a server socket associated with this channel.
+     *
+     * <p> The returned object will not declare any public methods that are not
+     * declared in the {@link java.net.ServerSocket} class.  </p>
+     *
+     * @return  A server socket associated with this channel
+     */
+    public abstract ServerSocket socket();
+
+    /**
+     * Accepts a connection made to this channel's socket.
+     *
+     * <p> If this channel is in non-blocking mode then this method will
+     * immediately return <tt>null</tt> if there are no pending connections.
+     * Otherwise it will block indefinitely until a new connection is available
+     * or an I/O error occurs.
+     *
+     * <p> The socket channel returned by this method, if any, will be in
+     * blocking mode regardless of the blocking mode of this channel.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.ServerSocket#accept accept} method of the {@link
+     * java.net.ServerSocket} class.  That is, if a security manager has been
+     * installed then for each new connection this method verifies that the
+     * address and port number of the connection's remote endpoint are
+     * permitted by the security manager's {@link
+     * java.lang.SecurityManager#checkAccept checkAccept} method.  </p>
+     *
+     * @return  The socket channel for the new connection,
+     *          or <tt>null</tt> if this channel is in non-blocking mode
+     *          and no connection is available to be accepted
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the accept operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the accept operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  NotYetBoundException
+     *          If this channel's socket has not yet been bound
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the remote endpoint
+     *          of the new connection
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SocketChannel accept() throws IOException;
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+
+}
diff --git a/java/nio/channels/ShutdownChannelGroupException.java b/java/nio/channels/ShutdownChannelGroupException.java
new file mode 100644
index 0000000..b4e4b7d
--- /dev/null
+++ b/java/nio/channels/ShutdownChannelGroupException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to construct a channel in 
+ * a group that is shutdown or the completion handler for an I/O operation 
+ * cannot be invoked because the channel group has terminated.
+ *
+ * @since 1.7
+ */
+
+public class ShutdownChannelGroupException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = -3903801676350154157L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ShutdownChannelGroupException() { }
+
+}
diff --git a/java/nio/channels/SocketChannel.java b/java/nio/channels/SocketChannel.java
new file mode 100644
index 0000000..eb13b15
--- /dev/null
+++ b/java/nio/channels/SocketChannel.java
@@ -0,0 +1,526 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
+
+/**
+ * A selectable channel for stream-oriented connecting sockets.
+ *
+ * <p> A socket channel is created by invoking one of the {@link #open open}
+ * methods of this class.  It is not possible to create a channel for an arbitrary,
+ * pre-existing socket. A newly-created socket channel is open but not yet
+ * connected.  An attempt to invoke an I/O operation upon an unconnected
+ * channel will cause a {@link NotYetConnectedException} to be thrown.  A
+ * socket channel can be connected by invoking its {@link #connect connect}
+ * method; once connected, a socket channel remains connected until it is
+ * closed.  Whether or not a socket channel is connected may be determined by
+ * invoking its {@link #isConnected isConnected} method.
+ *
+ * <p> Socket channels support <i>non-blocking connection:</i>&nbsp;A socket
+ * channel may be created and the process of establishing the link to the
+ * remote socket may be initiated via the {@link #connect connect} method for
+ * later completion by the {@link #finishConnect finishConnect} method.
+ * Whether or not a connection operation is in progress may be determined by
+ * invoking the {@link #isConnectionPending isConnectionPending} method.
+ *
+ * <p> Socket channels support <i>asynchronous shutdown,</i> which is similar
+ * to the asynchronous close operation specified in the {@link Channel} class.
+ * If the input side of a socket is shut down by one thread while another
+ * thread is blocked in a read operation on the socket's channel, then the read
+ * operation in the blocked thread will complete without reading any bytes and
+ * will return <tt>-1</tt>.  If the output side of a socket is shut down by one
+ * thread while another thread is blocked in a write operation on the socket's
+ * channel, then the blocked thread will receive an {@link
+ * AsynchronousCloseException}.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Socket channels support the following options:
+ * <blockquote>
+ * <table border summary="Socket options">
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE} </td>
+ *     <td> Keep connection alive </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ *     <td> Re-use address </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#SO_LINGER SO_LINGER} </td>
+ *     <td> Linger on close if data is present (when configured in blocking mode
+ *          only) </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link java.net.StandardSocketOptions#TCP_NODELAY TCP_NODELAY} </td>
+ *     <td> Disable the Nagle algorithm </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> Socket channels are safe for use by multiple concurrent threads.  They
+ * support concurrent reading and writing, though at most one thread may be
+ * reading and at most one thread may be writing at any given time.  The {@link
+ * #connect connect} and {@link #finishConnect finishConnect} methods are
+ * mutually synchronized against each other, and an attempt to initiate a read
+ * or write operation while an invocation of one of these methods is in
+ * progress will block until that invocation is complete.  </p>
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class SocketChannel
+    extends AbstractSelectableChannel
+    implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
+{
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this channel
+     */
+    protected SocketChannel(SelectorProvider provider) {
+        super(provider);
+    }
+
+    /**
+     * Opens a socket channel.
+     *
+     * <p> The new channel is created by invoking the {@link
+     * java.nio.channels.spi.SelectorProvider#openSocketChannel
+     * openSocketChannel} method of the system-wide default {@link
+     * java.nio.channels.spi.SelectorProvider} object.  </p>
+     *
+     * @return  A new socket channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static SocketChannel open() throws IOException {
+        return SelectorProvider.provider().openSocketChannel();
+    }
+
+    /**
+     * Opens a socket channel and connects it to a remote address.
+     *
+     * <p> This convenience method works as if by invoking the {@link #open()}
+     * method, invoking the {@link #connect(SocketAddress) connect} method upon
+     * the resulting socket channel, passing it <tt>remote</tt>, and then
+     * returning that channel.  </p>
+     *
+     * @param  remote
+     *         The remote address to which the new channel is to be connected
+     *
+     * @return  A new, and connected, socket channel
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     *
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote endpoint
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public static SocketChannel open(SocketAddress remote)
+        throws IOException
+    {
+        SocketChannel sc = open();
+        try {
+            sc.connect(remote);
+        } catch (Throwable x) {
+            try {
+                sc.close();
+            } catch (Throwable suppressed) {
+                x.addSuppressed(suppressed);
+            }
+            throw x;
+        }
+        assert sc.isConnected();
+        return sc;
+    }
+
+    /**
+     * Returns an operation set identifying this channel's supported
+     * operations.
+     *
+     * <p> Socket channels support connecting, reading, and writing, so this
+     * method returns <tt>(</tt>{@link SelectionKey#OP_CONNECT}
+     * <tt>|</tt>&nbsp;{@link SelectionKey#OP_READ} <tt>|</tt>&nbsp;{@link
+     * SelectionKey#OP_WRITE}<tt>)</tt>.  </p>
+     *
+     * @return  The valid-operation set
+     */
+    public final int validOps() {
+        return (SelectionKey.OP_READ
+                | SelectionKey.OP_WRITE
+                | SelectionKey.OP_CONNECT);
+    }
+
+
+    // -- Socket-specific operations --
+
+    /**
+     * @throws  ConnectionPendingException
+     *          If a non-blocking connect operation is already in progress on
+     *          this channel
+     * @throws  AlreadyBoundException               {@inheritDoc}
+     * @throws  UnsupportedAddressTypeException     {@inheritDoc}
+     * @throws  ClosedChannelException              {@inheritDoc}
+     * @throws  IOException                         {@inheritDoc}
+     * @throws  SecurityException
+     *          If a security manager has been installed and its
+     *          {@link SecurityManager#checkListen checkListen} method denies
+     *          the operation
+     *
+     * @since 1.7
+     */
+    @Override
+    public abstract SocketChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * @throws  UnsupportedOperationException           {@inheritDoc}
+     * @throws  IllegalArgumentException                {@inheritDoc}
+     * @throws  ClosedChannelException                  {@inheritDoc}
+     * @throws  IOException                             {@inheritDoc}
+     *
+     * @since 1.7
+     */
+    @Override
+    public abstract <T> SocketChannel setOption(SocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Shutdown the connection for reading without closing the channel.
+     *
+     * <p> Once shutdown for reading then further reads on the channel will
+     * return {@code -1}, the end-of-stream indication. If the input side of the
+     * connection is already shutdown then invoking this method has no effect.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketChannel shutdownInput() throws IOException;
+
+    /**
+     * Shutdown the connection for writing without closing the channel.
+     *
+     * <p> Once shutdown for writing then further attempts to write to the
+     * channel will throw {@link ClosedChannelException}. If the output side of
+     * the connection is already shutdown then invoking this method has no
+     * effect.
+     *
+     * @return  The channel
+     *
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     * @throws  IOException
+     *          If some other I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketChannel shutdownOutput() throws IOException;
+
+    /**
+     * Retrieves a socket associated with this channel.
+     *
+     * <p> The returned object will not declare any public methods that are not
+     * declared in the {@link java.net.Socket} class.  </p>
+     *
+     * @return  A socket associated with this channel
+     */
+    public abstract Socket socket();
+
+    /**
+     * Tells whether or not this channel's network socket is connected.
+     *
+     * @return  <tt>true</tt> if, and only if, this channel's network socket
+     *          is {@link #isOpen open} and connected
+     */
+    public abstract boolean isConnected();
+
+    /**
+     * Tells whether or not a connection operation is in progress on this
+     * channel.
+     *
+     * @return  <tt>true</tt> if, and only if, a connection operation has been
+     *          initiated on this channel but not yet completed by invoking the
+     *          {@link #finishConnect finishConnect} method
+     */
+    public abstract boolean isConnectionPending();
+
+    /**
+     * Connects this channel's socket.
+     *
+     * <p> If this channel is in non-blocking mode then an invocation of this
+     * method initiates a non-blocking connection operation.  If the connection
+     * is established immediately, as can happen with a local connection, then
+     * this method returns <tt>true</tt>.  Otherwise this method returns
+     * <tt>false</tt> and the connection operation must later be completed by
+     * invoking the {@link #finishConnect finishConnect} method.
+     *
+     * <p> If this channel is in blocking mode then an invocation of this
+     * method will block until the connection is established or an I/O error
+     * occurs.
+     *
+     * <p> This method performs exactly the same security checks as the {@link
+     * java.net.Socket} class.  That is, if a security manager has been
+     * installed then this method verifies that its {@link
+     * java.lang.SecurityManager#checkConnect checkConnect} method permits
+     * connecting to the address and port number of the given remote endpoint.
+     *
+     * <p> This method may be invoked at any time.  If a read or write
+     * operation upon this channel is invoked while an invocation of this
+     * method is in progress then that operation will first block until this
+     * invocation is complete.  If a connection attempt is initiated but fails,
+     * that is, if an invocation of this method throws a checked exception,
+     * then the channel will be closed.  </p>
+     *
+     * @param  remote
+     *         The remote address to which this channel is to be connected
+     *
+     * @return  <tt>true</tt> if a connection was established,
+     *          <tt>false</tt> if this channel is in non-blocking mode
+     *          and the connection operation is in progress
+     *
+     * @throws  AlreadyConnectedException
+     *          If this channel is already connected
+     *
+     * @throws  ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress
+     *          on this channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     *
+     * @throws  UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote endpoint
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract boolean connect(SocketAddress remote) throws IOException;
+
+    /**
+     * Finishes the process of connecting a socket channel.
+     *
+     * <p> A non-blocking connection operation is initiated by placing a socket
+     * channel in non-blocking mode and then invoking its {@link #connect
+     * connect} method.  Once the connection is established, or the attempt has
+     * failed, the socket channel will become connectable and this method may
+     * be invoked to complete the connection sequence.  If the connection
+     * operation failed then invoking this method will cause an appropriate
+     * {@link java.io.IOException} to be thrown.
+     *
+     * <p> If this channel is already connected then this method will not block
+     * and will immediately return <tt>true</tt>.  If this channel is in
+     * non-blocking mode then this method will return <tt>false</tt> if the
+     * connection process is not yet complete.  If this channel is in blocking
+     * mode then this method will block until the connection either completes
+     * or fails, and will always either return <tt>true</tt> or throw a checked
+     * exception describing the failure.
+     *
+     * <p> This method may be invoked at any time.  If a read or write
+     * operation upon this channel is invoked while an invocation of this
+     * method is in progress then that operation will first block until this
+     * invocation is complete.  If a connection attempt fails, that is, if an
+     * invocation of this method throws a checked exception, then the channel
+     * will be closed.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this channel's socket is now
+     *          connected
+     *
+     * @throws  NoConnectionPendingException
+     *          If this channel is not connected and a connection operation
+     *          has not been initiated
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract boolean finishConnect() throws IOException;
+
+    /**
+     * Returns the remote address to which this channel's socket is connected.
+     *
+     * <p> Where the channel is bound and connected to an Internet Protocol
+     * socket address then the return value from this method is of type {@link
+     * java.net.InetSocketAddress}.
+     *
+     * @return  The remote address; {@code null} if the channel's socket is not
+     *          connected
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract SocketAddress getRemoteAddress() throws IOException;
+
+    // -- ByteChannel operations --
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    public abstract int read(ByteBuffer dst) throws IOException;
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    public abstract long read(ByteBuffer[] dsts, int offset, int length)
+        throws IOException;
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    public final long read(ByteBuffer[] dsts) throws IOException {
+        return read(dsts, 0, dsts.length);
+    }
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    public abstract int write(ByteBuffer src) throws IOException;
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    public abstract long write(ByteBuffer[] srcs, int offset, int length)
+        throws IOException;
+
+    /**
+     * @throws  NotYetConnectedException
+     *          If this channel is not yet connected
+     */
+    public final long write(ByteBuffer[] srcs) throws IOException {
+        return write(srcs, 0, srcs.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p>
+     * If there is a security manager set, its {@code checkConnect} method is
+     * called with the local address and {@code -1} as its arguments to see
+     * if the operation is allowed. If the operation is not allowed,
+     * a {@code SocketAddress} representing the
+     * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the
+     * local port of the channel's socket is returned.
+     *
+     * @return  The {@code SocketAddress} that the socket is bound to, or the
+     *          {@code SocketAddress} representing the loopback address if
+     *          denied by the security manager, or {@code null} if the
+     *          channel's socket is not bound
+     *
+     * @throws  ClosedChannelException     {@inheritDoc}
+     * @throws  IOException                {@inheritDoc}
+     */
+    @Override
+    public abstract SocketAddress getLocalAddress() throws IOException;
+
+}
diff --git a/java/nio/channels/UnresolvedAddressException.java b/java/nio/channels/UnresolvedAddressException.java
new file mode 100644
index 0000000..f5e61b8
--- /dev/null
+++ b/java/nio/channels/UnresolvedAddressException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke a network
+ * operation upon an unresolved socket address.
+ *
+ * @since 1.4
+ */
+
+public class UnresolvedAddressException
+    extends IllegalArgumentException
+{
+
+    private static final long serialVersionUID = 6136959093620794148L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public UnresolvedAddressException() { }
+
+}
diff --git a/java/nio/channels/UnsupportedAddressTypeException.java b/java/nio/channels/UnsupportedAddressTypeException.java
new file mode 100644
index 0000000..9c88b89
--- /dev/null
+++ b/java/nio/channels/UnsupportedAddressTypeException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to bind or connect
+ * to a socket address of a type that is not supported.
+ *
+ * @since 1.4
+ */
+
+public class UnsupportedAddressTypeException
+    extends IllegalArgumentException
+{
+
+    private static final long serialVersionUID = -2964323842829700493L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public UnsupportedAddressTypeException() { }
+
+}
diff --git a/java/nio/channels/WritableByteChannel.java b/java/nio/channels/WritableByteChannel.java
new file mode 100644
index 0000000..b2ea065
--- /dev/null
+++ b/java/nio/channels/WritableByteChannel.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+
+/**
+ * A channel that can write bytes.
+ *
+ * <p> Only one write operation upon a writable channel may be in progress at
+ * any given time.  If one thread initiates a write operation upon a channel
+ * then any other thread that attempts to initiate another write operation will
+ * block until the first operation is complete.  Whether or not other kinds of
+ * I/O operations may proceed concurrently with a write operation depends upon
+ * the type of the channel. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public interface WritableByteChannel
+    extends Channel
+{
+
+    /**
+     * Writes a sequence of bytes to this channel from the given buffer.
+     *
+     * <p> An attempt is made to write up to <i>r</i> bytes to the channel,
+     * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+     * <tt>src.remaining()</tt>, at the moment this method is invoked.
+     *
+     * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+     * <tt>0</tt>&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;<i>r</i>.
+     * This byte sequence will be transferred from the buffer starting at index
+     * <i>p</i>, where <i>p</i> is the buffer's position at the moment this
+     * method is invoked; the index of the last byte written will be
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>.
+     * Upon return the buffer's position will be equal to
+     * <i>p</i>&nbsp;<tt>+</tt>&nbsp;<i>n</i>; its limit will not have changed.
+     *
+     * <p> Unless otherwise specified, a write operation will return only after
+     * writing all of the <i>r</i> requested bytes.  Some types of channels,
+     * depending upon their state, may write only some of the bytes or possibly
+     * none at all.  A socket channel in non-blocking mode, for example, cannot
+     * write any more bytes than are free in the socket's output buffer.
+     *
+     * <p> This method may be invoked at any time.  If another thread has
+     * already initiated a write operation upon this channel, however, then an
+     * invocation of this method will block until the first operation is
+     * complete. </p>
+     *
+     * @param  src
+     *         The buffer from which bytes are to be retrieved
+     *
+     * @return The number of bytes written, possibly zero
+     *
+     * @throws  NonWritableChannelException
+     *          If this channel was not opened for writing
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the write operation is in progress
+     *
+     * @throws  ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the write operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public int write(ByteBuffer src) throws IOException;
+
+}
diff --git a/java/nio/channels/WritePendingException.java b/java/nio/channels/WritePendingException.java
new file mode 100644
index 0000000..8957702
--- /dev/null
+++ b/java/nio/channels/WritePendingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to write to an
+ * asynchronous socket channel and a previous write has not completed.
+ *
+ * @since 1.7
+ */
+
+public class WritePendingException
+    extends IllegalStateException
+{
+
+    private static final long serialVersionUID = 7031871839266032276L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public WritePendingException() { }
+
+}
diff --git a/java/nio/channels/package-info.java b/java/nio/channels/package-info.java
new file mode 100644
index 0000000..8118347
--- /dev/null
+++ b/java/nio/channels/package-info.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines channels, which represent connections to entities that are capable of
+ * performing I/O operations, such as files and sockets; defines selectors, for
+ * multiplexed, non-blocking I/O operations.
+ *
+ * <a name="channels"></a>
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists channels and their descriptions">
+ * <tr><th align="left">Channels</th><th align="left">Description</th></tr>
+ * <tr><td valign=top><tt><i>{@link java.nio.channels.Channel}</i></tt></td>
+ *     <td>A nexus for I/O operations</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ReadableByteChannel}</i></tt></td>
+ *     <td>Can read into a buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.ScatteringByteChannel}&nbsp;&nbsp;</i></tt></td>
+ *     <td>Can read into a sequence of&nbsp;buffers</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.WritableByteChannel}</i></tt></td>
+ *     <td>Can write from a buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.GatheringByteChannel}</i></tt></td>
+ *     <td>Can write from a sequence of&nbsp;buffers</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ByteChannel}</i></tt></td>
+ *     <td>Can read/write to/from a&nbsp;buffer</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.SeekableByteChannel}</i></tt></td>
+ *     <td>A {@code ByteChannel} connected to an entity that contains a variable-length sequence of bytes</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.AsynchronousChannel}</i></tt></td>
+ *     <td>Supports asynchronous I/O operations.</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.AsynchronousByteChannel}</i></tt></td>
+ *     <td>Can read and write bytes asynchronously</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.NetworkChannel}</i></tt></td>
+ *     <td>A channel to a network socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.channels.MulticastChannel}</i></tt></td>
+ *     <td>Can join Internet Protocol (IP) multicast groups</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Channels}</tt></td>
+ *     <td>Utility methods for channel/stream interoperation</td></tr>
+ * </table></blockquote>
+ *
+ * <p> A <i>channel</i> represents an open connection to an entity such as a
+ * hardware device, a file, a network socket, or a program component that is
+ * capable of performing one or more distinct I/O operations, for example reading
+ * or writing.  As specified in the {@link java.nio.channels.Channel} interface,
+ * channels are either open or closed, and they are both <i>asynchronously
+ * closeable</i> and <i>interruptible</i>.
+ *
+ * <p> The {@link java.nio.channels.Channel} interface is extended by several
+ * other interfaces.
+ *
+ * <p> The {@link java.nio.channels.ReadableByteChannel} interface specifies a
+ * {@link java.nio.channels.ReadableByteChannel#read read} method that reads bytes
+ * from the channel into a buffer; similarly, the {@link
+ * java.nio.channels.WritableByteChannel} interface specifies a {@link
+ * java.nio.channels.WritableByteChannel#write write} method that writes bytes
+ * from a buffer to the channel. The {@link java.nio.channels.ByteChannel}
+ * interface unifies these two interfaces for the common case of channels that can
+ * both read and write bytes. The {@link java.nio.channels.SeekableByteChannel}
+ * interface extends the {@code ByteChannel} interface with methods to {@link
+ * java.nio.channels.SeekableByteChannel#position() query} and {@link
+ * java.nio.channels.SeekableByteChannel#position(long) modify} the channel's
+ * current position, and its {@link java.nio.channels.SeekableByteChannel#size
+ * size}.
+ *
+ * <p> The {@link java.nio.channels.ScatteringByteChannel} and {@link
+ * java.nio.channels.GatheringByteChannel} interfaces extend the {@link
+ * java.nio.channels.ReadableByteChannel} and {@link
+ * java.nio.channels.WritableByteChannel} interfaces, respectively, adding {@link
+ * java.nio.channels.ScatteringByteChannel#read read} and {@link
+ * java.nio.channels.GatheringByteChannel#write write} methods that take a
+ * sequence of buffers rather than a single buffer.
+ *
+ * <p> The {@link java.nio.channels.NetworkChannel} interface specifies methods
+ * to {@link java.nio.channels.NetworkChannel#bind bind} the channel's socket,
+ * obtain the address to which the socket is bound, and methods to {@link
+ * java.nio.channels.NetworkChannel#getOption get} and {@link
+ * java.nio.channels.NetworkChannel#setOption set} socket options. The {@link
+ * java.nio.channels.MulticastChannel} interface specifies methods to join
+ * Internet Protocol (IP) multicast groups.
+ *
+ * <p> The {@link java.nio.channels.Channels} utility class defines static methods
+ * that support the interoperation of the stream classes of the <tt>{@link
+ * java.io}</tt> package with the channel classes of this package.  An appropriate
+ * channel can be constructed from an {@link java.io.InputStream} or an {@link
+ * java.io.OutputStream}, and conversely an {@link java.io.InputStream} or an
+ * {@link java.io.OutputStream} can be constructed from a channel.  A {@link
+ * java.io.Reader} can be constructed that uses a given charset to decode bytes
+ * from a given readable byte channel, and conversely a {@link java.io.Writer} can
+ * be constructed that uses a given charset to encode characters into bytes and
+ * write them to a given writable byte channel.
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists file channels and their descriptions">
+ * <tr><th align="left">File channels</th><th align="left">Description</th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.FileChannel}</tt></td>
+ *     <td>Reads, writes, maps, and manipulates files</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.FileLock}</tt></td>
+ *     <td>A lock on a (region of a) file</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.MappedByteBuffer}&nbsp;&nbsp;</tt></td>
+ *     <td>A direct byte buffer mapped to a region of a&nbsp;file</td></tr>
+ * </table></blockquote>
+ *
+ * <p> The {@link java.nio.channels.FileChannel} class supports the usual
+ * operations of reading bytes from, and writing bytes to, a channel connected to
+ * a file, as well as those of querying and modifying the current file position
+ * and truncating the file to a specific size.  It defines methods for acquiring
+ * locks on the whole file or on a specific region of a file; these methods return
+ * instances of the {@link java.nio.channels.FileLock} class.  Finally, it defines
+ * methods for forcing updates to the file to be written to the storage device that
+ * contains it, for efficiently transferring bytes between the file and other
+ * channels, and for mapping a region of the file directly into memory.
+ *
+ * <p> A {@code FileChannel} is created by invoking one of its static {@link
+ * java.nio.channels.FileChannel#open open} methods, or by invoking the {@code
+ * getChannel} method of a {@link java.io.FileInputStream}, {@link
+ * java.io.FileOutputStream}, or {@link java.io.RandomAccessFile} to return a
+ * file channel connected to the same underlying file as the <tt>{@link java.io}</tt>
+ * class.
+ *
+ * <a name="multiplex"></a>
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists multiplexed, non-blocking channels and their descriptions">
+ * <tr><th align="left">Multiplexed, non-blocking I/O</th><th align="left"><p>Description</th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.SelectableChannel}</tt></td>
+ *     <td>A channel that can be multiplexed</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.DatagramChannel}</tt></td>
+ *     <td>A channel to a datagram-oriented socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.Pipe.SinkChannel}</tt></td>
+ *     <td>The write end of a pipe</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.Pipe.SourceChannel}</tt></td>
+ *     <td>The read end of a pipe</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.ServerSocketChannel}&nbsp;&nbsp;</tt></td>
+ *     <td>A channel to a stream-oriented listening socket</td></tr>
+ * <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.SocketChannel}</tt></td>
+ *     <td>A channel for a stream-oriented connecting socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Selector}</tt></td>
+ *     <td>A multiplexor of selectable channels</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.SelectionKey}</tt></td>
+ *     <td>A token representing the registration <br> of a channel
+ *     with&nbsp;a&nbsp;selector</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.Pipe}</tt></td>
+ *     <td>Two channels that form a unidirectional&nbsp;pipe</td></tr>
+ * </table></blockquote>
+ *
+ * <p> Multiplexed, non-blocking I/O, which is much more scalable than
+ * thread-oriented, blocking I/O, is provided by <i>selectors</i>, <i>selectable
+ * channels</i>, and <i>selection keys</i>.
+ *
+ * <p> A <a href="Selector.html"><i>selector</i></a> is a multiplexor of <a
+ * href="SelectableChannel.html"><i>selectable channels</i></a>, which in turn are
+ * a special type of channel that can be put into <a
+ * href="SelectableChannel.html#bm"><i>non-blocking mode</i></a>.  To perform
+ * multiplexed I/O operations, one or more selectable channels are first created,
+ * put into non-blocking mode, and {@link
+ * java.nio.channels.SelectableChannel#register <i>registered</i>}
+ * with a selector.  Registering a channel specifies the set of I/O operations
+ * that will be tested for readiness by the selector, and returns a <a
+ * href="SelectionKey.html"><i>selection key</i></a> that represents the
+ * registration.
+ *
+ * <p> Once some channels have been registered with a selector, a <a
+ * href="Selector.html#selop"><i>selection operation</i></a> can be performed in
+ * order to discover which channels, if any, have become ready to perform one or
+ * more of the operations in which interest was previously declared.  If a channel
+ * is ready then the key returned when it was registered will be added to the
+ * selector's <i>selected-key set</i>.  The key set, and the keys within it, can
+ * be examined in order to determine the operations for which each channel is
+ * ready.  From each key one can retrieve the corresponding channel in order to
+ * perform whatever I/O operations are required.
+ *
+ * <p> That a selection key indicates that its channel is ready for some operation
+ * is a hint, but not a guarantee, that such an operation can be performed by a
+ * thread without causing the thread to block.  It is imperative that code that
+ * performs multiplexed I/O be written so as to ignore these hints when they prove
+ * to be incorrect.
+ *
+ * <p> This package defines selectable-channel classes corresponding to the {@link
+ * java.net.DatagramSocket}, {@link java.net.ServerSocket}, and {@link
+ * java.net.Socket} classes defined in the <tt>{@link java.net}</tt> package.
+ * Minor changes to these classes have been made in order to support sockets that
+ * are associated with channels.  This package also defines a simple class that
+ * implements unidirectional pipes.  In all cases, a new selectable channel is
+ * created by invoking the static <tt>open</tt> method of the corresponding class.
+ * If a channel needs an associated socket then a socket will be created as a side
+ * effect of this operation.
+ *
+ * <p> The implementation of selectors, selectable channels, and selection keys
+ * can be replaced by "plugging in" an alternative definition or instance of the
+ * {@link java.nio.channels.spi.SelectorProvider} class defined in the <tt>{@link
+ * java.nio.channels.spi}</tt> package.  It is not expected that many developers
+ * will actually make use of this facility; it is provided primarily so that
+ * sophisticated users can take advantage of operating-system-specific
+ * I/O-multiplexing mechanisms when very high performance is required.
+ *
+ * <p> Much of the bookkeeping and synchronization required to implement the
+ * multiplexed-I/O abstractions is performed by the {@link
+ * java.nio.channels.spi.AbstractInterruptibleChannel}, {@link
+ * java.nio.channels.spi.AbstractSelectableChannel}, {@link
+ * java.nio.channels.spi.AbstractSelectionKey}, and {@link
+ * java.nio.channels.spi.AbstractSelector} classes in the <tt>{@link
+ * java.nio.channels.spi}</tt> package.  When defining a custom selector provider,
+ * only the {@link java.nio.channels.spi.AbstractSelector} and {@link
+ * java.nio.channels.spi.AbstractSelectionKey} classes should be subclassed
+ * directly; custom channel classes should extend the appropriate {@link
+ * java.nio.channels.SelectableChannel} subclasses defined in this package.
+ *
+ * <a name="async"></a>
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Lists asynchronous channels and their descriptions">
+ * <tr><th align="left">Asynchronous I/O</th><th align="left">Description</th></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousFileChannel}</tt></td>
+ *     <td>An asynchronous channel for reading, writing, and manipulating a file</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousSocketChannel}</tt></td>
+ *     <td>An asynchronous channel to a stream-oriented connecting socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousServerSocketChannel}&nbsp;&nbsp;</tt></td>
+ *     <td>An asynchronous channel to a stream-oriented listening socket</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.CompletionHandler}</tt></td>
+ *     <td>A handler for consuming the result of an asynchronous operation</td></tr>
+ * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousChannelGroup}</tt></td>
+ *     <td>A grouping of asynchronous channels for the purpose of resource sharing</td></tr>
+ * </table></blockquote>
+ *
+ * <p> {@link java.nio.channels.AsynchronousChannel Asynchronous channels} are a
+ * special type of channel capable of asynchronous I/O operations. Asynchronous
+ * channels are non-blocking and define methods to initiate asynchronous
+ * operations, returning a {@link java.util.concurrent.Future} representing the
+ * pending result of each operation. The {@code Future} can be used to poll or
+ * wait for the result of the operation. Asynchronous I/O operations can also
+ * specify a {@link java.nio.channels.CompletionHandler} to invoke when the
+ * operation completes. A completion handler is user provided code that is executed
+ * to consume the result of I/O operation.
+ *
+ * <p> This package defines asynchronous-channel classes that are connected to
+ * a stream-oriented connecting or listening socket, or a datagram-oriented socket.
+ * It also defines the {@link java.nio.channels.AsynchronousFileChannel} class
+ * for asynchronous reading, writing, and manipulating a file. As with the {@link
+ * java.nio.channels.FileChannel} it supports operations to truncate the file
+ * to a specific size, force updates to the file to be written to the storage
+ * device, or acquire locks on the whole file or on a specific region of the file.
+ * Unlike the {@code FileChannel} it does not define methods for mapping a
+ * region of the file directly into memory. Where memory mapped I/O is required,
+ * then a {@code FileChannel} can be used.
+ *
+ * <p> Asynchronous channels are bound to an asynchronous channel group for the
+ * purpose of resource sharing. A group has an associated {@link
+ * java.util.concurrent.ExecutorService} to which tasks are submitted to handle
+ * I/O events and dispatch to completion handlers that consume the result of
+ * asynchronous operations performed on channels in the group. The group can
+ * optionally be specified when creating the channel or the channel can be bound
+ * to a <em>default group</em>. Sophisticated users may wish to create their
+ * own asynchronous channel groups or configure the {@code ExecutorService}
+ * that will be used for the default group.
+ *
+ * <p> As with selectors, the implementation of asynchronous channels can be
+ * replaced by "plugging in" an alternative definition or instance of the {@link
+ * java.nio.channels.spi.AsynchronousChannelProvider} class defined in the
+ * <tt>{@link java.nio.channels.spi}</tt> package.  It is not expected that many
+ * developers will actually make use of this facility; it is provided primarily
+ * so that sophisticated users can take advantage of operating-system-specific
+ * asynchronous I/O mechanisms when very high performance is required.
+ *
+ * <hr width="80%">
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 1.4
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ */
+
+package java.nio.channels;
diff --git a/java/nio/channels/spi/AbstractInterruptibleChannel.java b/java/nio/channels/spi/AbstractInterruptibleChannel.java
new file mode 100644
index 0000000..137c449
--- /dev/null
+++ b/java/nio/channels/spi/AbstractInterruptibleChannel.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ */
+
+package java.nio.channels.spi;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.nio.channels.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.nio.ch.Interruptible;
+
+
+/**
+ * Base implementation class for interruptible channels.
+ *
+ * <p> This class encapsulates the low-level machinery required to implement
+ * the asynchronous closing and interruption of channels.  A concrete channel
+ * class must invoke the {@link #begin begin} and {@link #end end} methods
+ * before and after, respectively, invoking an I/O operation that might block
+ * indefinitely.  In order to ensure that the {@link #end end} method is always
+ * invoked, these methods should be used within a
+ * <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block:
+ *
+ * <blockquote><pre>
+ * boolean completed = false;
+ * try {
+ *     begin();
+ *     completed = ...;    // Perform blocking I/O operation
+ *     return ...;         // Return result
+ * } finally {
+ *     end(completed);
+ * }</pre></blockquote>
+ *
+ * <p> The <tt>completed</tt> argument to the {@link #end end} method tells
+ * whether or not the I/O operation actually completed, that is, whether it had
+ * any effect that would be visible to the invoker.  In the case of an
+ * operation that reads bytes, for example, this argument should be
+ * <tt>true</tt> if, and only if, some bytes were actually transferred into the
+ * invoker's target buffer.
+ *
+ * <p> A concrete channel class must also implement the {@link
+ * #implCloseChannel implCloseChannel} method in such a way that if it is
+ * invoked while another thread is blocked in a native I/O operation upon the
+ * channel then that operation will immediately return, either by throwing an
+ * exception or by returning normally.  If a thread is interrupted or the
+ * channel upon which it is blocked is asynchronously closed then the channel's
+ * {@link #end end} method will throw the appropriate exception.
+ *
+ * <p> This class performs the synchronization required to implement the {@link
+ * java.nio.channels.Channel} specification.  Implementations of the {@link
+ * #implCloseChannel implCloseChannel} method need not synchronize against
+ * other threads that might be attempting to close the channel.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class AbstractInterruptibleChannel
+    implements Channel, InterruptibleChannel
+{
+
+    private final Object closeLock = new Object();
+    private volatile boolean open = true;
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AbstractInterruptibleChannel() { }
+
+    /**
+     * Closes this channel.
+     *
+     * <p> If the channel has already been closed then this method returns
+     * immediately.  Otherwise it marks the channel as closed and then invokes
+     * the {@link #implCloseChannel implCloseChannel} method in order to
+     * complete the close operation.  </p>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public final void close() throws IOException {
+        synchronized (closeLock) {
+            if (!open)
+                return;
+            open = false;
+            implCloseChannel();
+        }
+    }
+
+    /**
+     * Closes this channel.
+     *
+     * <p> This method is invoked by the {@link #close close} method in order
+     * to perform the actual work of closing the channel.  This method is only
+     * invoked if the channel has not yet been closed, and it is never invoked
+     * more than once.
+     *
+     * <p> An implementation of this method must arrange for any other thread
+     * that is blocked in an I/O operation upon this channel to return
+     * immediately, either by throwing an exception or by returning normally.
+     * </p>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs while closing the channel
+     */
+    protected abstract void implCloseChannel() throws IOException;
+
+    public final boolean isOpen() {
+        return open;
+    }
+
+
+    // -- Interruption machinery --
+
+    private Interruptible interruptor;
+    private volatile Thread interrupted;
+
+    /**
+     * Marks the beginning of an I/O operation that might block indefinitely.
+     *
+     * <p> This method should be invoked in tandem with the {@link #end end}
+     * method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block as
+     * shown <a href="#be">above</a>, in order to implement asynchronous
+     * closing and interruption for this channel.  </p>
+     */
+    protected final void begin() {
+        if (interruptor == null) {
+            interruptor = new Interruptible() {
+                    public void interrupt(Thread target) {
+                        synchronized (closeLock) {
+                            if (!open)
+                                return;
+                            open = false;
+                            interrupted = target;
+                            try {
+                                AbstractInterruptibleChannel.this.implCloseChannel();
+                            } catch (IOException x) { }
+                        }
+                    }};
+        }
+        blockedOn(interruptor);
+        Thread me = Thread.currentThread();
+        if (me.isInterrupted())
+            interruptor.interrupt(me);
+    }
+
+    /**
+     * Marks the end of an I/O operation that might block indefinitely.
+     *
+     * <p> This method should be invoked in tandem with the {@link #begin
+     * begin} method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block
+     * as shown <a href="#be">above</a>, in order to implement asynchronous
+     * closing and interruption for this channel.  </p>
+     *
+     * @param  completed
+     *         <tt>true</tt> if, and only if, the I/O operation completed
+     *         successfully, that is, had some effect that would be visible to
+     *         the operation's invoker
+     *
+     * @throws  AsynchronousCloseException
+     *          If the channel was asynchronously closed
+     *
+     * @throws  ClosedByInterruptException
+     *          If the thread blocked in the I/O operation was interrupted
+     */
+    protected final void end(boolean completed)
+        throws AsynchronousCloseException
+    {
+        blockedOn(null);
+        Thread interrupted = this.interrupted;
+        if (interrupted != null && interrupted == Thread.currentThread()) {
+            interrupted = null;
+            throw new ClosedByInterruptException();
+        }
+        if (!completed && !open)
+            throw new AsynchronousCloseException();
+    }
+
+
+    // -- sun.misc.SharedSecrets --
+    static void blockedOn(Interruptible intr) {         // package-private
+        // Android-changed: Call Thread.currentThread().blockedOn() directly.
+        Thread.currentThread().blockedOn(intr);
+    }
+}
diff --git a/java/nio/channels/spi/AbstractSelectableChannel.java b/java/nio/channels/spi/AbstractSelectableChannel.java
new file mode 100644
index 0000000..0de212d
--- /dev/null
+++ b/java/nio/channels/spi/AbstractSelectableChannel.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels.spi;
+
+import java.io.IOException;
+import java.nio.channels.*;
+
+
+/**
+ * Base implementation class for selectable channels.
+ *
+ * <p> This class defines methods that handle the mechanics of channel
+ * registration, deregistration, and closing.  It maintains the current
+ * blocking mode of this channel as well as its current set of selection keys.
+ * It performs all of the synchronization required to implement the {@link
+ * java.nio.channels.SelectableChannel} specification.  Implementations of the
+ * abstract protected methods defined in this class need not synchronize
+ * against other threads that might be engaged in the same operations.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author Mike McCloskey
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class AbstractSelectableChannel
+    extends SelectableChannel
+{
+
+    // The provider that created this channel
+    private final SelectorProvider provider;
+
+    // Keys that have been created by registering this channel with selectors.
+    // They are saved because if this channel is closed the keys must be
+    // deregistered.  Protected by keyLock.
+    //
+    private SelectionKey[] keys = null;
+    private int keyCount = 0;
+
+    // Lock for key set and count
+    private final Object keyLock = new Object();
+
+    // Lock for registration and configureBlocking operations
+    private final Object regLock = new Object();
+
+    // Blocking mode, protected by regLock
+    boolean blocking = true;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this channel
+     */
+    protected AbstractSelectableChannel(SelectorProvider provider) {
+        this.provider = provider;
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     *
+     * @return  The provider that created this channel
+     */
+    public final SelectorProvider provider() {
+        return provider;
+    }
+
+
+    // -- Utility methods for the key set --
+
+    private void addKey(SelectionKey k) {
+        assert Thread.holdsLock(keyLock);
+        int i = 0;
+        if ((keys != null) && (keyCount < keys.length)) {
+            // Find empty element of key array
+            for (i = 0; i < keys.length; i++)
+                if (keys[i] == null)
+                    break;
+        } else if (keys == null) {
+            keys =  new SelectionKey[3];
+        } else {
+            // Grow key array
+            int n = keys.length * 2;
+            SelectionKey[] ks =  new SelectionKey[n];
+            for (i = 0; i < keys.length; i++)
+                ks[i] = keys[i];
+            keys = ks;
+            i = keyCount;
+        }
+        keys[i] = k;
+        keyCount++;
+    }
+
+    private SelectionKey findKey(Selector sel) {
+        synchronized (keyLock) {
+            if (keys == null)
+                return null;
+            for (int i = 0; i < keys.length; i++)
+                if ((keys[i] != null) && (keys[i].selector() == sel))
+                    return keys[i];
+            return null;
+        }
+    }
+
+    void removeKey(SelectionKey k) {                    // package-private
+        synchronized (keyLock) {
+            for (int i = 0; i < keys.length; i++)
+                if (keys[i] == k) {
+                    keys[i] = null;
+                    keyCount--;
+                }
+            ((AbstractSelectionKey)k).invalidate();
+        }
+    }
+
+    private boolean haveValidKeys() {
+        synchronized (keyLock) {
+            if (keyCount == 0)
+                return false;
+            for (int i = 0; i < keys.length; i++) {
+                if ((keys[i] != null) && keys[i].isValid())
+                    return true;
+            }
+            return false;
+        }
+    }
+
+
+    // -- Registration --
+
+    public final boolean isRegistered() {
+        synchronized (keyLock) {
+            return keyCount != 0;
+        }
+    }
+
+    public final SelectionKey keyFor(Selector sel) {
+        return findKey(sel);
+    }
+
+    /**
+     * Registers this channel with the given selector, returning a selection key.
+     *
+     * <p>  This method first verifies that this channel is open and that the
+     * given initial interest set is valid.
+     *
+     * <p> If this channel is already registered with the given selector then
+     * the selection key representing that registration is returned after
+     * setting its interest set to the given value.
+     *
+     * <p> Otherwise this channel has not yet been registered with the given
+     * selector, so the {@link AbstractSelector#register register} method of
+     * the selector is invoked while holding the appropriate locks.  The
+     * resulting key is added to this channel's key set before being returned.
+     * </p>
+     *
+     * @throws  ClosedSelectorException {@inheritDoc}
+     *
+     * @throws  IllegalBlockingModeException {@inheritDoc}
+     *
+     * @throws  IllegalSelectorException {@inheritDoc}
+     *
+     * @throws  CancelledKeyException {@inheritDoc}
+     *
+     * @throws  IllegalArgumentException {@inheritDoc}
+     */
+    public final SelectionKey register(Selector sel, int ops,
+                                       Object att)
+        throws ClosedChannelException
+    {
+        synchronized (regLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if ((ops & ~validOps()) != 0)
+                throw new IllegalArgumentException();
+            if (blocking)
+                throw new IllegalBlockingModeException();
+            SelectionKey k = findKey(sel);
+            if (k != null) {
+                k.interestOps(ops);
+                k.attach(att);
+            }
+            if (k == null) {
+                // New registration
+                synchronized (keyLock) {
+                    if (!isOpen())
+                        throw new ClosedChannelException();
+                    k = ((AbstractSelector)sel).register(this, ops, att);
+                    addKey(k);
+                }
+            }
+            return k;
+        }
+    }
+
+
+    // -- Closing --
+
+    /**
+     * Closes this channel.
+     *
+     * <p> This method, which is specified in the {@link
+     * AbstractInterruptibleChannel} class and is invoked by the {@link
+     * java.nio.channels.Channel#close close} method, in turn invokes the
+     * {@link #implCloseSelectableChannel implCloseSelectableChannel} method in
+     * order to perform the actual work of closing this channel.  It then
+     * cancels all of this channel's keys.  </p>
+     */
+    protected final void implCloseChannel() throws IOException {
+        implCloseSelectableChannel();
+        synchronized (keyLock) {
+            int count = (keys == null) ? 0 : keys.length;
+            for (int i = 0; i < count; i++) {
+                SelectionKey k = keys[i];
+                if (k != null)
+                    k.cancel();
+            }
+        }
+    }
+
+    /**
+     * Closes this selectable channel.
+     *
+     * <p> This method is invoked by the {@link java.nio.channels.Channel#close
+     * close} method in order to perform the actual work of closing the
+     * channel.  This method is only invoked if the channel has not yet been
+     * closed, and it is never invoked more than once.
+     *
+     * <p> An implementation of this method must arrange for any other thread
+     * that is blocked in an I/O operation upon this channel to return
+     * immediately, either by throwing an exception or by returning normally.
+     * </p>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    protected abstract void implCloseSelectableChannel() throws IOException;
+
+
+    // -- Blocking --
+
+    public final boolean isBlocking() {
+        synchronized (regLock) {
+            return blocking;
+        }
+    }
+
+    public final Object blockingLock() {
+        return regLock;
+    }
+
+    /**
+     * Adjusts this channel's blocking mode.
+     *
+     * <p> If the given blocking mode is different from the current blocking
+     * mode then this method invokes the {@link #implConfigureBlocking
+     * implConfigureBlocking} method, while holding the appropriate locks, in
+     * order to change the mode.  </p>
+     */
+    public final SelectableChannel configureBlocking(boolean block)
+        throws IOException
+    {
+        synchronized (regLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (blocking == block)
+                return this;
+            if (block && haveValidKeys())
+                throw new IllegalBlockingModeException();
+            implConfigureBlocking(block);
+            blocking = block;
+        }
+        return this;
+    }
+
+    /**
+     * Adjusts this channel's blocking mode.
+     *
+     * <p> This method is invoked by the {@link #configureBlocking
+     * configureBlocking} method in order to perform the actual work of
+     * changing the blocking mode.  This method is only invoked if the new mode
+     * is different from the current mode.  </p>
+     *
+     * @param  block  If <tt>true</tt> then this channel will be placed in
+     *                blocking mode; if <tt>false</tt> then it will be placed
+     *                non-blocking mode
+     *
+     * @throws IOException
+     *         If an I/O error occurs
+     */
+    protected abstract void implConfigureBlocking(boolean block)
+        throws IOException;
+
+}
diff --git a/java/nio/channels/spi/AbstractSelectionKey.java b/java/nio/channels/spi/AbstractSelectionKey.java
new file mode 100644
index 0000000..015e6c7
--- /dev/null
+++ b/java/nio/channels/spi/AbstractSelectionKey.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels.spi;
+
+import java.nio.channels.*;
+
+
+/**
+ * Base implementation class for selection keys.
+ *
+ * <p> This class tracks the validity of the key and implements cancellation.
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class AbstractSelectionKey
+    extends SelectionKey
+{
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AbstractSelectionKey() { }
+
+    private volatile boolean valid = true;
+
+    public final boolean isValid() {
+        return valid;
+    }
+
+    void invalidate() {                                 // package-private
+        valid = false;
+    }
+
+    /**
+     * Cancels this key.
+     *
+     * <p> If this key has not yet been cancelled then it is added to its
+     * selector's cancelled-key set while synchronized on that set.  </p>
+     */
+    public final void cancel() {
+        // Synchronizing "this" to prevent this key from getting canceled
+        // multiple times by different threads, which might cause race
+        // condition between selector's select() and channel's close().
+        synchronized (this) {
+            if (valid) {
+                valid = false;
+                ((AbstractSelector)selector()).cancel(this);
+            }
+        }
+    }
+}
diff --git a/java/nio/channels/spi/AbstractSelector.java b/java/nio/channels/spi/AbstractSelector.java
new file mode 100644
index 0000000..09e3b61
--- /dev/null
+++ b/java/nio/channels/spi/AbstractSelector.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels.spi;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.util.HashSet;
+import java.util.Set;
+import sun.nio.ch.Interruptible;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+
+/**
+ * Base implementation class for selectors.
+ *
+ * <p> This class encapsulates the low-level machinery required to implement
+ * the interruption of selection operations.  A concrete selector class must
+ * invoke the {@link #begin begin} and {@link #end end} methods before and
+ * after, respectively, invoking an I/O operation that might block
+ * indefinitely.  In order to ensure that the {@link #end end} method is always
+ * invoked, these methods should be used within a
+ * <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block:
+ *
+ * <blockquote><pre>
+ * try {
+ *     begin();
+ *     // Perform blocking I/O operation here
+ *     ...
+ * } finally {
+ *     end();
+ * }</pre></blockquote>
+ *
+ * <p> This class also defines methods for maintaining a selector's
+ * cancelled-key set and for removing a key from its channel's key set, and
+ * declares the abstract {@link #register register} method that is invoked by a
+ * selectable channel's {@link AbstractSelectableChannel#register register}
+ * method in order to perform the actual work of registering a channel.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class AbstractSelector
+    extends Selector
+{
+
+    private AtomicBoolean selectorOpen = new AtomicBoolean(true);
+
+    // The provider that created this selector
+    private final SelectorProvider provider;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The provider that created this selector
+     */
+    protected AbstractSelector(SelectorProvider provider) {
+        this.provider = provider;
+    }
+
+    private final Set<SelectionKey> cancelledKeys = new HashSet<SelectionKey>();
+
+    void cancel(SelectionKey k) {                       // package-private
+        synchronized (cancelledKeys) {
+            cancelledKeys.add(k);
+        }
+    }
+
+    /**
+     * Closes this selector.
+     *
+     * <p> If the selector has already been closed then this method returns
+     * immediately.  Otherwise it marks the selector as closed and then invokes
+     * the {@link #implCloseSelector implCloseSelector} method in order to
+     * complete the close operation.  </p>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public final void close() throws IOException {
+        boolean open = selectorOpen.getAndSet(false);
+        if (!open)
+            return;
+        implCloseSelector();
+    }
+
+    /**
+     * Closes this selector.
+     *
+     * <p> This method is invoked by the {@link #close close} method in order
+     * to perform the actual work of closing the selector.  This method is only
+     * invoked if the selector has not yet been closed, and it is never invoked
+     * more than once.
+     *
+     * <p> An implementation of this method must arrange for any other thread
+     * that is blocked in a selection operation upon this selector to return
+     * immediately as if by invoking the {@link
+     * java.nio.channels.Selector#wakeup wakeup} method. </p>
+     *
+     * @throws  IOException
+     *          If an I/O error occurs while closing the selector
+     */
+    protected abstract void implCloseSelector() throws IOException;
+
+    public final boolean isOpen() {
+        return selectorOpen.get();
+    }
+
+    /**
+     * Returns the provider that created this channel.
+     *
+     * @return  The provider that created this channel
+     */
+    public final SelectorProvider provider() {
+        return provider;
+    }
+
+    /**
+     * Retrieves this selector's cancelled-key set.
+     *
+     * <p> This set should only be used while synchronized upon it.  </p>
+     *
+     * @return  The cancelled-key set
+     */
+    protected final Set<SelectionKey> cancelledKeys() {
+        return cancelledKeys;
+    }
+
+    /**
+     * Registers the given channel with this selector.
+     *
+     * <p> This method is invoked by a channel's {@link
+     * AbstractSelectableChannel#register register} method in order to perform
+     * the actual work of registering the channel with this selector.  </p>
+     *
+     * @param  ch
+     *         The channel to be registered
+     *
+     * @param  ops
+     *         The initial interest set, which must be valid
+     *
+     * @param  att
+     *         The initial attachment for the resulting key
+     *
+     * @return  A new key representing the registration of the given channel
+     *          with this selector
+     */
+    protected abstract SelectionKey register(AbstractSelectableChannel ch,
+                                             int ops, Object att);
+
+    /**
+     * Removes the given key from its channel's key set.
+     *
+     * <p> This method must be invoked by the selector for each channel that it
+     * deregisters.  </p>
+     *
+     * @param  key
+     *         The selection key to be removed
+     */
+    protected final void deregister(AbstractSelectionKey key) {
+        ((AbstractSelectableChannel)key.channel()).removeKey(key);
+    }
+
+
+    // -- Interruption machinery --
+
+    private Interruptible interruptor = null;
+
+    /**
+     * Marks the beginning of an I/O operation that might block indefinitely.
+     *
+     * <p> This method should be invoked in tandem with the {@link #end end}
+     * method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block as
+     * shown <a href="#be">above</a>, in order to implement interruption for
+     * this selector.
+     *
+     * <p> Invoking this method arranges for the selector's {@link
+     * Selector#wakeup wakeup} method to be invoked if a thread's {@link
+     * Thread#interrupt interrupt} method is invoked while the thread is
+     * blocked in an I/O operation upon the selector.  </p>
+     */
+    protected final void begin() {
+        if (interruptor == null) {
+            interruptor = new Interruptible() {
+                    public void interrupt(Thread ignore) {
+                        AbstractSelector.this.wakeup();
+                    }};
+        }
+        AbstractInterruptibleChannel.blockedOn(interruptor);
+        Thread me = Thread.currentThread();
+        if (me.isInterrupted())
+            interruptor.interrupt(me);
+    }
+
+    /**
+     * Marks the end of an I/O operation that might block indefinitely.
+     *
+     * <p> This method should be invoked in tandem with the {@link #begin begin}
+     * method, using a <tt>try</tt>&nbsp;...&nbsp;<tt>finally</tt> block as
+     * shown <a href="#be">above</a>, in order to implement interruption for
+     * this selector.  </p>
+     */
+    protected final void end() {
+        AbstractInterruptibleChannel.blockedOn(null);
+    }
+
+}
diff --git a/java/nio/channels/spi/AsynchronousChannelProvider.java b/java/nio/channels/spi/AsynchronousChannelProvider.java
new file mode 100644
index 0000000..464b4fc
--- /dev/null
+++ b/java/nio/channels/spi/AsynchronousChannelProvider.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels.spi;
+
+import java.nio.channels.*;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+import java.util.concurrent.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Service-provider class for asynchronous channels.
+ *
+ * <p> An asynchronous channel provider is a concrete subclass of this class that
+ * has a zero-argument constructor and implements the abstract methods specified
+ * below.  A given invocation of the Java virtual machine maintains a single
+ * system-wide default provider instance, which is returned by the {@link
+ * #provider() provider} method.  The first invocation of that method will locate
+ * the default provider as specified below.
+ *
+ * <p> All of the methods in this class are safe for use by multiple concurrent
+ * threads.  </p>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousChannelProvider {
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("asynchronousChannelProvider"));
+        return null;
+    }
+    private AsynchronousChannelProvider(Void ignore) { }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt>
+     */
+    protected AsynchronousChannelProvider() {
+        this(checkPermission());
+    }
+
+    // lazy initialization of default provider
+    private static class ProviderHolder {
+        static final AsynchronousChannelProvider provider = load();
+
+        private static AsynchronousChannelProvider load() {
+            return AccessController
+                .doPrivileged(new PrivilegedAction<AsynchronousChannelProvider>() {
+                    public AsynchronousChannelProvider run() {
+                        AsynchronousChannelProvider p;
+                        p = loadProviderFromProperty();
+                        if (p != null)
+                            return p;
+                        p = loadProviderAsService();
+                        if (p != null)
+                            return p;
+                        return sun.nio.ch.DefaultAsynchronousChannelProvider.create();
+                    }});
+        }
+
+        private static AsynchronousChannelProvider loadProviderFromProperty() {
+            String cn = System.getProperty("java.nio.channels.spi.AsynchronousChannelProvider");
+            if (cn == null)
+                return null;
+            try {
+                Class<?> c = Class.forName(cn, true,
+                                           ClassLoader.getSystemClassLoader());
+                return (AsynchronousChannelProvider)c.newInstance();
+            } catch (ClassNotFoundException x) {
+                throw new ServiceConfigurationError(null, x);
+            } catch (IllegalAccessException x) {
+                throw new ServiceConfigurationError(null, x);
+            } catch (InstantiationException x) {
+                throw new ServiceConfigurationError(null, x);
+            } catch (SecurityException x) {
+                throw new ServiceConfigurationError(null, x);
+            }
+        }
+
+        private static AsynchronousChannelProvider loadProviderAsService() {
+            ServiceLoader<AsynchronousChannelProvider> sl =
+                ServiceLoader.load(AsynchronousChannelProvider.class,
+                                   ClassLoader.getSystemClassLoader());
+            Iterator<AsynchronousChannelProvider> i = sl.iterator();
+            for (;;) {
+                try {
+                    return (i.hasNext()) ? i.next() : null;
+                } catch (ServiceConfigurationError sce) {
+                    if (sce.getCause() instanceof SecurityException) {
+                        // Ignore the security exception, try the next provider
+                        continue;
+                    }
+                    throw sce;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the system-wide default asynchronous channel provider for this
+     * invocation of the Java virtual machine.
+     *
+     * <p> The first invocation of this method locates the default provider
+     * object as follows: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> If the system property
+     *   <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> is defined
+     *   then it is taken to be the fully-qualified name of a concrete provider class.
+     *   The class is loaded and instantiated; if this process fails then an
+     *   unspecified error is thrown.  </p></li>
+     *
+     *   <li><p> If a provider class has been installed in a jar file that is
+     *   visible to the system class loader, and that jar file contains a
+     *   provider-configuration file named
+     *   <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> in the resource
+     *   directory <tt>META-INF/services</tt>, then the first class name
+     *   specified in that file is taken.  The class is loaded and
+     *   instantiated; if this process fails then an unspecified error is
+     *   thrown.  </p></li>
+     *
+     *   <li><p> Finally, if no provider has been specified by any of the above
+     *   means then the system-default provider class is instantiated and the
+     *   result is returned.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> Subsequent invocations of this method return the provider that was
+     * returned by the first invocation.  </p>
+     *
+     * @return  The system-wide default AsynchronousChannel provider
+     */
+    public static AsynchronousChannelProvider provider() {
+        return ProviderHolder.provider;
+    }
+
+    /**
+     * Constructs a new asynchronous channel group with a fixed thread pool.
+     *
+     * @param   nThreads
+     *          The number of threads in the pool
+     * @param   threadFactory
+     *          The factory to use when creating new threads
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code nThreads <= 0}
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see AsynchronousChannelGroup#withFixedThreadPool
+     */
+    public abstract AsynchronousChannelGroup
+        openAsynchronousChannelGroup(int nThreads, ThreadFactory threadFactory) throws IOException;
+
+    /**
+     * Constructs a new asynchronous channel group with the given thread pool.
+     *
+     * @param   executor
+     *          The thread pool
+     * @param   initialSize
+     *          A value {@code >=0} or a negative value for implementation
+     *          specific default
+     *
+     * @return  A new asynchronous channel group
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see AsynchronousChannelGroup#withCachedThreadPool
+     */
+    public abstract AsynchronousChannelGroup
+        openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException;
+
+    /**
+     * Opens an asynchronous server-socket channel.
+     *
+     * @param   group
+     *          The group to which the channel is bound, or {@code null} to
+     *          bind to the default group
+     *
+     * @return  The new channel
+     *
+     * @throws  IllegalChannelGroupException
+     *          If the provider that created the group differs from this provider
+     * @throws  ShutdownChannelGroupException
+     *          The group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AsynchronousServerSocketChannel openAsynchronousServerSocketChannel
+        (AsynchronousChannelGroup group) throws IOException;
+
+    /**
+     * Opens an asynchronous socket channel.
+     *
+     * @param   group
+     *          The group to which the channel is bound, or {@code null} to
+     *          bind to the default group
+     *
+     * @return  The new channel
+     *
+     * @throws  IllegalChannelGroupException
+     *          If the provider that created the group differs from this provider
+     * @throws  ShutdownChannelGroupException
+     *          The group is shutdown
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AsynchronousSocketChannel openAsynchronousSocketChannel
+        (AsynchronousChannelGroup group) throws IOException;
+}
diff --git a/java/nio/channels/spi/SelectorProvider.java b/java/nio/channels/spi/SelectorProvider.java
new file mode 100644
index 0000000..2dbef05
--- /dev/null
+++ b/java/nio/channels/spi/SelectorProvider.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.channels.spi;
+
+import java.io.IOException;
+import java.net.ProtocolFamily;
+import java.nio.channels.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+import sun.security.action.GetPropertyAction;
+
+
+/**
+ * Service-provider class for selectors and selectable channels.
+ *
+ * <p> A selector provider is a concrete subclass of this class that has a
+ * zero-argument constructor and implements the abstract methods specified
+ * below.  A given invocation of the Java virtual machine maintains a single
+ * system-wide default provider instance, which is returned by the {@link
+ * #provider() provider} method.  The first invocation of that method will locate
+ * the default provider as specified below.
+ *
+ * <p> The system-wide default provider is used by the static <tt>open</tt>
+ * methods of the {@link java.nio.channels.DatagramChannel#open
+ * DatagramChannel}, {@link java.nio.channels.Pipe#open Pipe}, {@link
+ * java.nio.channels.Selector#open Selector}, {@link
+ * java.nio.channels.ServerSocketChannel#open ServerSocketChannel}, and {@link
+ * java.nio.channels.SocketChannel#open SocketChannel} classes.  It is also
+ * used by the {@link java.lang.System#inheritedChannel System.inheritedChannel()}
+ * method. A program may make use of a provider other than the default provider
+ * by instantiating that provider and then directly invoking the <tt>open</tt>
+ * methods defined in this class.
+ *
+ * <p> All of the methods in this class are safe for use by multiple concurrent
+ * threads.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public abstract class SelectorProvider {
+
+    private static final Object lock = new Object();
+    private static SelectorProvider provider = null;
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("selectorProvider")</tt>
+     */
+    protected SelectorProvider() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("selectorProvider"));
+    }
+
+    private static boolean loadProviderFromProperty() {
+        String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");
+        if (cn == null)
+            return false;
+        try {
+            Class<?> c = Class.forName(cn, true,
+                                       ClassLoader.getSystemClassLoader());
+            provider = (SelectorProvider)c.newInstance();
+            return true;
+        } catch (ClassNotFoundException x) {
+            throw new ServiceConfigurationError(null, x);
+        } catch (IllegalAccessException x) {
+            throw new ServiceConfigurationError(null, x);
+        } catch (InstantiationException x) {
+            throw new ServiceConfigurationError(null, x);
+        } catch (SecurityException x) {
+            throw new ServiceConfigurationError(null, x);
+        }
+    }
+
+    private static boolean loadProviderAsService() {
+
+        ServiceLoader<SelectorProvider> sl =
+            ServiceLoader.load(SelectorProvider.class,
+                               ClassLoader.getSystemClassLoader());
+        Iterator<SelectorProvider> i = sl.iterator();
+        for (;;) {
+            try {
+                if (!i.hasNext())
+                    return false;
+                provider = i.next();
+                return true;
+            } catch (ServiceConfigurationError sce) {
+                if (sce.getCause() instanceof SecurityException) {
+                    // Ignore the security exception, try the next provider
+                    continue;
+                }
+                throw sce;
+            }
+        }
+    }
+
+    /**
+     * Returns the system-wide default selector provider for this invocation of
+     * the Java virtual machine.
+     *
+     * <p> The first invocation of this method locates the default provider
+     * object as follows: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> If the system property
+     *   <tt>java.nio.channels.spi.SelectorProvider</tt> is defined then it is
+     *   taken to be the fully-qualified name of a concrete provider class.
+     *   The class is loaded and instantiated; if this process fails then an
+     *   unspecified error is thrown.  </p></li>
+     *
+     *   <li><p> If a provider class has been installed in a jar file that is
+     *   visible to the system class loader, and that jar file contains a
+     *   provider-configuration file named
+     *   <tt>java.nio.channels.spi.SelectorProvider</tt> in the resource
+     *   directory <tt>META-INF/services</tt>, then the first class name
+     *   specified in that file is taken.  The class is loaded and
+     *   instantiated; if this process fails then an unspecified error is
+     *   thrown.  </p></li>
+     *
+     *   <li><p> Finally, if no provider has been specified by any of the above
+     *   means then the system-default provider class is instantiated and the
+     *   result is returned.  </p></li>
+     *
+     * </ol>
+     *
+     * <p> Subsequent invocations of this method return the provider that was
+     * returned by the first invocation.  </p>
+     *
+     * @return  The system-wide default selector provider
+     */
+    public static SelectorProvider provider() {
+        synchronized (lock) {
+            if (provider != null)
+                return provider;
+            return AccessController.doPrivileged(
+                new PrivilegedAction<SelectorProvider>() {
+                    public SelectorProvider run() {
+                            if (loadProviderFromProperty())
+                                return provider;
+                            if (loadProviderAsService())
+                                return provider;
+                            provider = sun.nio.ch.DefaultSelectorProvider.create();
+                            return provider;
+                        }
+                    });
+        }
+    }
+
+    /**
+     * Opens a datagram channel.
+     *
+     * @return  The new channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract DatagramChannel openDatagramChannel()
+        throws IOException;
+
+    /**
+     * Opens a datagram channel.
+     *
+     * @param   family
+     *          The protocol family
+     *
+     * @return  A new datagram channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the specified protocol family is not supported
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @since 1.7
+     */
+    public abstract DatagramChannel openDatagramChannel(ProtocolFamily family)
+        throws IOException;
+
+    /**
+     * Opens a pipe.
+     *
+     * @return  The new pipe
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract Pipe openPipe()
+        throws IOException;
+
+    /**
+     * Opens a selector.
+     *
+     * @return  The new selector
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract AbstractSelector openSelector()
+        throws IOException;
+
+    /**
+     * Opens a server-socket channel.
+     *
+     * @return  The new channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract ServerSocketChannel openServerSocketChannel()
+        throws IOException;
+
+    /**
+     * Opens a socket channel.
+     *
+     * @return  The new channel
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract SocketChannel openSocketChannel()
+        throws IOException;
+
+    /**
+     * Returns the channel inherited from the entity that created this
+     * Java virtual machine.
+     *
+     * <p> On many operating systems a process, such as a Java virtual
+     * machine, can be started in a manner that allows the process to
+     * inherit a channel from the entity that created the process. The
+     * manner in which this is done is system dependent, as are the
+     * possible entities to which the channel may be connected. For example,
+     * on UNIX systems, the Internet services daemon (<i>inetd</i>) is used to
+     * start programs to service requests when a request arrives on an
+     * associated network port. In this example, the process that is started,
+     * inherits a channel representing a network socket.
+     *
+     * <p> In cases where the inherited channel represents a network socket
+     * then the {@link java.nio.channels.Channel Channel} type returned
+     * by this method is determined as follows:
+     *
+     * <ul>
+     *
+     *  <li><p> If the inherited channel represents a stream-oriented connected
+     *  socket then a {@link java.nio.channels.SocketChannel SocketChannel} is
+     *  returned. The socket channel is, at least initially, in blocking
+     *  mode, bound to a socket address, and connected to a peer.
+     *  </p></li>
+     *
+     *  <li><p> If the inherited channel represents a stream-oriented listening
+     *  socket then a {@link java.nio.channels.ServerSocketChannel
+     *  ServerSocketChannel} is returned. The server-socket channel is, at
+     *  least initially, in blocking mode, and bound to a socket address.
+     *  </p></li>
+     *
+     *  <li><p> If the inherited channel is a datagram-oriented socket
+     *  then a {@link java.nio.channels.DatagramChannel DatagramChannel} is
+     *  returned. The datagram channel is, at least initially, in blocking
+     *  mode, and bound to a socket address.
+     *  </p></li>
+     *
+     * </ul>
+     *
+     * <p> In addition to the network-oriented channels described, this method
+     * may return other kinds of channels in the future.
+     *
+     * <p> The first invocation of this method creates the channel that is
+     * returned. Subsequent invocations of this method return the same
+     * channel. </p>
+     *
+     * @return  The inherited channel, if any, otherwise <tt>null</tt>.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("inheritedChannel")</tt>
+     *
+     * @since 1.5
+     */
+   public Channel inheritedChannel() throws IOException {
+        return null;
+   }
+
+}
diff --git a/java/nio/charset/CharacterCodingException.java b/java/nio/charset/CharacterCodingException.java
new file mode 100644
index 0000000..1cfeb5f
--- /dev/null
+++ b/java/nio/charset/CharacterCodingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.charset;
+
+
+/**
+ * Checked exception thrown when a character encoding
+ * or decoding error occurs.
+ *
+ * @since 1.4
+ */
+
+public class CharacterCodingException
+    extends java.io.IOException
+{
+
+    private static final long serialVersionUID = 8421532232154627783L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public CharacterCodingException() { }
+
+}
diff --git a/java/nio/charset/Charset.java b/java/nio/charset/Charset.java
new file mode 100644
index 0000000..5a3b35a
--- /dev/null
+++ b/java/nio/charset/Charset.java
@@ -0,0 +1,967 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset;
+
+import com.android.icu.charset.CharsetICU;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.spi.CharsetProvider;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.AbstractMap;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import sun.misc.ASCIICaseInsensitiveComparator;
+import sun.nio.cs.ThreadLocalCoders;
+import sun.security.action.GetPropertyAction;
+
+
+// Android-changed: Docs to say UTF-8 is always the platform default charset.
+/**
+ * A named mapping between sequences of sixteen-bit Unicode <a
+ * href="../../lang/Character.html#unicode">code units</a> and sequences of
+ * bytes.  This class defines methods for creating decoders and encoders and
+ * for retrieving the various names associated with a charset.  Instances of
+ * this class are immutable.
+ *
+ * <p> This class also defines static methods for testing whether a particular
+ * charset is supported, for locating charset instances by name, and for
+ * constructing a map that contains every charset for which support is
+ * available in the current Java virtual machine.  Support for new charsets can
+ * be added via the service-provider interface defined in the {@link
+ * java.nio.charset.spi.CharsetProvider} class.
+ *
+ * <p> All of the methods defined in this class are safe for use by multiple
+ * concurrent threads.
+ *
+ *
+ * <a name="names"></a><a name="charenc"></a>
+ * <h2>Charset names</h2>
+ *
+ * <p> Charsets are named by strings composed of the following characters:
+ *
+ * <ul>
+ *
+ *   <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
+ *        (<tt>'&#92;u0041'</tt>&nbsp;through&nbsp;<tt>'&#92;u005a'</tt>),
+ *
+ *   <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
+ *        (<tt>'&#92;u0061'</tt>&nbsp;through&nbsp;<tt>'&#92;u007a'</tt>),
+ *
+ *   <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
+ *        (<tt>'&#92;u0030'</tt>&nbsp;through&nbsp;<tt>'&#92;u0039'</tt>),
+ *
+ *   <li> The dash character <tt>'-'</tt>
+ *        (<tt>'&#92;u002d'</tt>,&nbsp;<small>HYPHEN-MINUS</small>),
+ *
+ *   <li> The plus character <tt>'+'</tt>
+ *        (<tt>'&#92;u002b'</tt>,&nbsp;<small>PLUS SIGN</small>),
+ *
+ *   <li> The period character <tt>'.'</tt>
+ *        (<tt>'&#92;u002e'</tt>,&nbsp;<small>FULL STOP</small>),
+ *
+ *   <li> The colon character <tt>':'</tt>
+ *        (<tt>'&#92;u003a'</tt>,&nbsp;<small>COLON</small>), and
+ *
+ *   <li> The underscore character <tt>'_'</tt>
+ *        (<tt>'&#92;u005f'</tt>,&nbsp;<small>LOW&nbsp;LINE</small>).
+ *
+ * </ul>
+ *
+ * A charset name must begin with either a letter or a digit.  The empty string
+ * is not a legal charset name.  Charset names are not case-sensitive; that is,
+ * case is always ignored when comparing charset names.  Charset names
+ * generally follow the conventions documented in <a
+ * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278:&nbsp;IANA Charset
+ * Registration Procedures</i></a>.
+ *
+ * <p> Every charset has a <i>canonical name</i> and may also have one or more
+ * <i>aliases</i>.  The canonical name is returned by the {@link #name() name} method
+ * of this class.  Canonical names are, by convention, usually in upper case.
+ * The aliases of a charset are returned by the {@link #aliases() aliases}
+ * method.
+ *
+ * <p><a name="hn">Some charsets have an <i>historical name</i> that is defined for
+ * compatibility with previous versions of the Java platform.</a>  A charset's
+ * historical name is either its canonical name or one of its aliases.  The
+ * historical name is returned by the <tt>getEncoding()</tt> methods of the
+ * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
+ * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
+ *
+ * <p><a name="iana"> </a>If a charset listed in the <a
+ * href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
+ * Registry</i></a> is supported by an implementation of the Java platform then
+ * its canonical name must be the name listed in the registry. Many charsets
+ * are given more than one name in the registry, in which case the registry
+ * identifies one of the names as <i>MIME-preferred</i>.  If a charset has more
+ * than one registry name then its canonical name must be the MIME-preferred
+ * name and the other names in the registry must be valid aliases.  If a
+ * supported charset is not listed in the IANA registry then its canonical name
+ * must begin with one of the strings <tt>"X-"</tt> or <tt>"x-"</tt>.
+ *
+ * <p> The IANA charset registry does change over time, and so the canonical
+ * name and the aliases of a particular charset may also change over time.  To
+ * ensure compatibility it is recommended that no alias ever be removed from a
+ * charset, and that if the canonical name of a charset is changed then its
+ * previous canonical name be made into an alias.
+ *
+ *
+ * <h2>Standard charsets</h2>
+ *
+ *
+ *
+ * <p><a name="standard">Every implementation of the Java platform is required to support the
+ * following standard charsets.</a>  Consult the release documentation for your
+ * implementation to see if any other charsets are supported.  The behavior
+ * of such optional charsets may differ between implementations.
+ *
+ * <blockquote><table width="80%" summary="Description of standard charsets">
+ * <tr><th align="left">Charset</th><th align="left">Description</th></tr>
+ * <tr><td valign=top><tt>US-ASCII</tt></td>
+ *     <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
+ *         a.k.a. the Basic Latin block of the Unicode character set</td></tr>
+ * <tr><td valign=top><tt>ISO-8859-1&nbsp;&nbsp;</tt></td>
+ *     <td>ISO Latin Alphabet No. 1, a.k.a. <tt>ISO-LATIN-1</tt></td></tr>
+ * <tr><td valign=top><tt>UTF-8</tt></td>
+ *     <td>Eight-bit UCS Transformation Format</td></tr>
+ * <tr><td valign=top><tt>UTF-16BE</tt></td>
+ *     <td>Sixteen-bit UCS Transformation Format,
+ *         big-endian byte&nbsp;order</td></tr>
+ * <tr><td valign=top><tt>UTF-16LE</tt></td>
+ *     <td>Sixteen-bit UCS Transformation Format,
+ *         little-endian byte&nbsp;order</td></tr>
+ * <tr><td valign=top><tt>UTF-16</tt></td>
+ *     <td>Sixteen-bit UCS Transformation Format,
+ *         byte&nbsp;order identified by an optional byte-order mark</td></tr>
+ * </table></blockquote>
+ *
+ * <p> The <tt>UTF-8</tt> charset is specified by <a
+ * href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC&nbsp;2279</i></a>; the
+ * transformation format upon which it is based is specified in
+ * Amendment&nbsp;2 of ISO&nbsp;10646-1 and is also described in the <a
+ * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
+ * Standard</i></a>.
+ *
+ * <p> The <tt>UTF-16</tt> charsets are specified by <a
+ * href="http://www.ietf.org/rfc/rfc2781.txt"><i>RFC&nbsp;2781</i></a>; the
+ * transformation formats upon which they are based are specified in
+ * Amendment&nbsp;1 of ISO&nbsp;10646-1 and are also described in the <a
+ * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
+ * Standard</i></a>.
+ *
+ * <p> The <tt>UTF-16</tt> charsets use sixteen-bit quantities and are
+ * therefore sensitive to byte order.  In these encodings the byte order of a
+ * stream may be indicated by an initial <i>byte-order mark</i> represented by
+ * the Unicode character <tt>'&#92;uFEFF'</tt>.  Byte-order marks are handled
+ * as follows:
+ *
+ * <ul>
+ *
+ *   <li><p> When decoding, the <tt>UTF-16BE</tt> and <tt>UTF-16LE</tt>
+ *   charsets interpret the initial byte-order marks as a <small>ZERO-WIDTH
+ *   NON-BREAKING SPACE</small>; when encoding, they do not write
+ *   byte-order marks. </p></li>
+
+ *
+ *   <li><p> When decoding, the <tt>UTF-16</tt> charset interprets the
+ *   byte-order mark at the beginning of the input stream to indicate the
+ *   byte-order of the stream but defaults to big-endian if there is no
+ *   byte-order mark; when encoding, it uses big-endian byte order and writes
+ *   a big-endian byte-order mark. </p></li>
+ *
+ * </ul>
+ *
+ * In any case, byte order marks occurring after the first element of an
+ * input sequence are not omitted since the same code is used to represent
+ * <small>ZERO-WIDTH NON-BREAKING SPACE</small>.
+ *
+ * <p>Android note: The Android platform default is always UTF-8.
+ *
+ * <p>The {@link StandardCharsets} class defines constants for each of the
+ * standard charsets.
+ *
+ * <h2>Terminology</h2>
+ *
+ * <p> The name of this class is taken from the terms used in
+ * <a href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278</i></a>.
+ * In that document a <i>charset</i> is defined as the combination of
+ * one or more coded character sets and a character-encoding scheme.
+ * (This definition is confusing; some other software systems define
+ * <i>charset</i> as a synonym for <i>coded character set</i>.)
+ *
+ * <p> A <i>coded character set</i> is a mapping between a set of abstract
+ * characters and a set of integers.  US-ASCII, ISO&nbsp;8859-1,
+ * JIS&nbsp;X&nbsp;0201, and Unicode are examples of coded character sets.
+ *
+ * <p> Some standards have defined a <i>character set</i> to be simply a
+ * set of abstract characters without an associated assigned numbering.
+ * An alphabet is an example of such a character set.  However, the subtle
+ * distinction between <i>character set</i> and <i>coded character set</i>
+ * is rarely used in practice; the former has become a short form for the
+ * latter, including in the Java API specification.
+ *
+ * <p> A <i>character-encoding scheme</i> is a mapping between one or more
+ * coded character sets and a set of octet (eight-bit byte) sequences.
+ * UTF-8, UTF-16, ISO&nbsp;2022, and EUC are examples of
+ * character-encoding schemes.  Encoding schemes are often associated with
+ * a particular coded character set; UTF-8, for example, is used only to
+ * encode Unicode.  Some schemes, however, are associated with multiple
+ * coded character sets; EUC, for example, can be used to encode
+ * characters in a variety of Asian coded character sets.
+ *
+ * <p> When a coded character set is used exclusively with a single
+ * character-encoding scheme then the corresponding charset is usually
+ * named for the coded character set; otherwise a charset is usually named
+ * for the encoding scheme and, possibly, the locale of the coded
+ * character sets that it supports.  Hence <tt>US-ASCII</tt> is both the
+ * name of a coded character set and of the charset that encodes it, while
+ * <tt>EUC-JP</tt> is the name of the charset that encodes the
+ * JIS&nbsp;X&nbsp;0201, JIS&nbsp;X&nbsp;0208, and JIS&nbsp;X&nbsp;0212
+ * coded character sets for the Japanese language.
+ *
+ * <p> The native character encoding of the Java programming language is
+ * UTF-16.  A charset in the Java platform therefore defines a mapping
+ * between sequences of sixteen-bit UTF-16 code units (that is, sequences
+ * of chars) and sequences of bytes. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see CharsetDecoder
+ * @see CharsetEncoder
+ * @see java.nio.charset.spi.CharsetProvider
+ * @see java.lang.Character
+ */
+
+public abstract class Charset
+    implements Comparable<Charset>
+{
+
+    /* -- Static methods -- */
+
+    private static volatile String bugLevel = null;
+
+    static boolean atBugLevel(String bl) {              // package-private
+        String level = bugLevel;
+        if (level == null) {
+            if (!sun.misc.VM.isBooted())
+                return false;
+            bugLevel = level = AccessController.doPrivileged(
+                new GetPropertyAction("sun.nio.cs.bugLevel", ""));
+        }
+        return level.equals(bl);
+    }
+
+    /**
+     * Checks that the given string is a legal charset name. </p>
+     *
+     * @param  s
+     *         A purported charset name
+     *
+     * @throws  IllegalCharsetNameException
+     *          If the given name is not a legal charset name
+     */
+    private static void checkName(String s) {
+        int n = s.length();
+        if (!atBugLevel("1.4")) {
+            if (n == 0)
+                throw new IllegalCharsetNameException(s);
+        }
+        for (int i = 0; i < n; i++) {
+            char c = s.charAt(i);
+            if (c >= 'A' && c <= 'Z') continue;
+            if (c >= 'a' && c <= 'z') continue;
+            if (c >= '0' && c <= '9') continue;
+            if (c == '-' && i != 0) continue;
+            if (c == '+' && i != 0) continue;
+            if (c == ':' && i != 0) continue;
+            if (c == '_' && i != 0) continue;
+            if (c == '.' && i != 0) continue;
+            throw new IllegalCharsetNameException(s);
+        }
+    }
+
+    // Android-removed: We use ICU's list of standard charsets.
+    /* The standard set of charsets */
+    // private static CharsetProvider standardProvider = new StandardCharsets();
+
+    // Cache of the most-recently-returned charsets,
+    // along with the names that were used to find them
+    //
+    // cache1/2 usage is explained in the lookup method
+    //
+    private static volatile Map.Entry<String, Charset> cache1 = null; // "Level 1" cache
+    private static final HashMap<String, Charset> cache2 = new HashMap<>(); // "Level 2" cache
+
+    private static void cache(String charsetName, Charset cs) {
+        synchronized(cache2) {
+            String canonicalName = cs.name();
+            Charset canonicalCharset = cache2.get(canonicalName);
+
+            if (canonicalCharset != null) {
+                cs = canonicalCharset;
+            } else {
+                cache2.put(canonicalName, cs);
+
+                for (String alias : cs.aliases()) {
+                    cache2.put(alias, cs);
+                }
+            }
+
+            cache2.put(charsetName, cs);
+        }
+
+        cache1 = new AbstractMap.SimpleImmutableEntry<>(charsetName, cs);
+    }
+
+    // Creates an iterator that walks over the available providers, ignoring
+    // those whose lookup or instantiation causes a security exception to be
+    // thrown.  Should be invoked with full privileges.
+    //
+    private static Iterator<CharsetProvider> providers() {
+        return new Iterator<CharsetProvider>() {
+
+                ServiceLoader<CharsetProvider> sl =
+                    ServiceLoader.load(CharsetProvider.class);
+                Iterator<CharsetProvider> i = sl.iterator();
+
+                CharsetProvider next = null;
+
+                private boolean getNext() {
+                    while (next == null) {
+                        try {
+                            if (!i.hasNext())
+                                return false;
+                            next = i.next();
+                        } catch (ServiceConfigurationError sce) {
+                            if (sce.getCause() instanceof SecurityException) {
+                                // Ignore security exceptions
+                                continue;
+                            }
+                            throw sce;
+                        }
+                    }
+                    return true;
+                }
+
+                public boolean hasNext() {
+                    return getNext();
+                }
+
+                public CharsetProvider next() {
+                    if (!getNext())
+                        throw new NoSuchElementException();
+                    CharsetProvider n = next;
+                    next = null;
+                    return n;
+                }
+
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+
+            };
+    }
+
+    // Thread-local gate to prevent recursive provider lookups
+    private static ThreadLocal<ThreadLocal<?>> gate =
+            new ThreadLocal<ThreadLocal<?>>();
+
+    private static Charset lookupViaProviders(final String charsetName) {
+
+        // The runtime startup sequence looks up standard charsets as a
+        // consequence of the VM's invocation of System.initializeSystemClass
+        // in order to, e.g., set system properties and encode filenames.  At
+        // that point the application class loader has not been initialized,
+        // however, so we can't look for providers because doing so will cause
+        // that loader to be prematurely initialized with incomplete
+        // information.
+        //
+        if (!sun.misc.VM.isBooted())
+            return null;
+
+        if (gate.get() != null)
+            // Avoid recursive provider lookups
+            return null;
+        try {
+            gate.set(gate);
+
+            return AccessController.doPrivileged(
+                new PrivilegedAction<Charset>() {
+                    public Charset run() {
+                        for (Iterator<CharsetProvider> i = providers();
+                             i.hasNext();) {
+                            CharsetProvider cp = i.next();
+                            Charset cs = cp.charsetForName(charsetName);
+                            if (cs != null)
+                                return cs;
+                        }
+                        return null;
+                    }
+                });
+
+        } finally {
+            gate.set(null);
+        }
+    }
+
+    // Android-removed: Remove support for the extended charset provider.
+    //
+    /* The extended set of charsets */
+    // private static Object extendedProviderLock = new Object();
+    // private static boolean extendedProviderProbed = false;
+    // private static CharsetProvider extendedProvider = null;
+    //
+    // private static void probeExtendedProvider() {
+    //     AccessController.doPrivileged(new PrivilegedAction<Object>() {
+    //            public Object run() {
+    //                 try {
+    //                     Class epc
+    //                         = Class.forName("sun.nio.cs.ext.ExtendedCharsets");
+    //                     extendedProvider = (CharsetProvider)epc.newInstance();
+    //                 } catch (ClassNotFoundException x) {
+    //                     // Extended charsets not available
+    //                     // (charsets.jar not present)
+    //                 } catch (InstantiationException x) {
+    //                     throw new Error(x);
+    //                 } catch (IllegalAccessException x) {
+    //                     throw new Error(x);
+    //                }
+    //                 return null;
+    //             }
+    //         });
+    // }
+    //
+    // private static Charset lookupExtendedCharset(String charsetName) {
+    //     CharsetProvider ecp = null;
+    //     synchronized (extendedProviderLock) {
+    //         if (!extendedProviderProbed) {
+    //             probeExtendedProvider();
+    //             extendedProviderProbed = true;
+    //         }
+    //         ecp = extendedProvider;
+    //     }
+    //     return (ecp != null) ? ecp.charsetForName(charsetName) : null;
+    // }
+
+    // We expect most programs to use one Charset repeatedly, so the most recently used Charset
+    // instance is stored in the level 1 cache. We convey a hint to this effect to the VM by putting
+    // the level 1 cache miss code in a separate method. Since charsetName is not necessarily in
+    // canonical form, we store the mapping from both the canonical name and the aliases to the
+    // instance in a map for level 2 cache.
+    private static Charset lookup(String charsetName) {
+        if (charsetName == null)
+            throw new IllegalArgumentException("Null charset name");
+
+
+        final Map.Entry<String, Charset> cached = cache1;
+        if (cached != null && charsetName.equals(cached.getKey()))
+            return cached.getValue();
+        return lookup2(charsetName);
+    }
+
+    private static Charset lookup2(String charsetName) {
+        Charset cs;
+        synchronized (cache2) {
+            if ((cs = cache2.get(charsetName)) != null) {
+                cache1 = new AbstractMap.SimpleImmutableEntry<>(charsetName, cs);
+                return cs;
+            }
+        }
+
+        // Android-changed: Drop support for "standard" and "extended"
+        // providers.
+        if ((cs = CharsetICU.charsetForName(charsetName))  != null ||
+            (cs = lookupViaProviders(charsetName))              != null)
+        {
+            cache(charsetName, cs);
+            return cs;
+        }
+
+        /* Only need to check the name if we didn't find a charset for it */
+        checkName(charsetName);
+        return null;
+    }
+
+    /**
+     * Tells whether the named charset is supported.
+     *
+     * @param  charsetName
+     *         The name of the requested charset; may be either
+     *         a canonical name or an alias
+     *
+     * @return  <tt>true</tt> if, and only if, support for the named charset
+     *          is available in the current Java virtual machine
+     *
+     * @throws IllegalCharsetNameException
+     *         If the given charset name is illegal
+     *
+     * @throws  IllegalArgumentException
+     *          If the given <tt>charsetName</tt> is null
+     */
+    public static boolean isSupported(String charsetName) {
+        return (lookup(charsetName) != null);
+    }
+
+    /**
+     * Returns a charset object for the named charset.
+     *
+     * @param  charsetName
+     *         The name of the requested charset; may be either
+     *         a canonical name or an alias
+     *
+     * @return  A charset object for the named charset
+     *
+     * @throws  IllegalCharsetNameException
+     *          If the given charset name is illegal
+     *
+     * @throws  IllegalArgumentException
+     *          If the given <tt>charsetName</tt> is null
+     *
+     * @throws  UnsupportedCharsetException
+     *          If no support for the named charset is available
+     *          in this instance of the Java virtual machine
+     */
+    public static Charset forName(String charsetName) {
+        Charset cs = lookup(charsetName);
+        if (cs != null)
+            return cs;
+        throw new UnsupportedCharsetException(charsetName);
+    }
+
+    // BEGIN Android-added: forNameUEE(String) method.
+    /**
+     * Equivalent to {@code forName} but only throws {@code UnsupportedEncodingException},
+     * which is all pre-nio code claims to throw.
+     *
+     * @hide internal use only
+     */
+    public static Charset forNameUEE(String charsetName) throws UnsupportedEncodingException {
+        try {
+            return Charset.forName(charsetName);
+        } catch (Exception cause) {
+            UnsupportedEncodingException ex = new UnsupportedEncodingException(charsetName);
+            ex.initCause(cause);
+            throw ex;
+        }
+    }
+    // END Android-added: forNameUEE(String) method.
+
+    // Fold charsets from the given iterator into the given map, ignoring
+    // charsets whose names already have entries in the map.
+    //
+    private static void put(Iterator<Charset> i, Map<String,Charset> m) {
+        while (i.hasNext()) {
+            Charset cs = i.next();
+            if (!m.containsKey(cs.name()))
+                m.put(cs.name(), cs);
+        }
+    }
+
+    /**
+     * Constructs a sorted map from canonical charset names to charset objects.
+     *
+     * <p> The map returned by this method will have one entry for each charset
+     * for which support is available in the current Java virtual machine.  If
+     * two or more supported charsets have the same canonical name then the
+     * resulting map will contain just one of them; which one it will contain
+     * is not specified. </p>
+     *
+     * <p> The invocation of this method, and the subsequent use of the
+     * resulting map, may cause time-consuming disk or network I/O operations
+     * to occur.  This method is provided for applications that need to
+     * enumerate all of the available charsets, for example to allow user
+     * charset selection.  This method is not used by the {@link #forName
+     * forName} method, which instead employs an efficient incremental lookup
+     * algorithm.
+     *
+     * <p> This method may return different results at different times if new
+     * charset providers are dynamically made available to the current Java
+     * virtual machine.  In the absence of such changes, the charsets returned
+     * by this method are exactly those that can be retrieved via the {@link
+     * #forName forName} method.  </p>
+     *
+     * @return An immutable, case-insensitive map from canonical charset names
+     *         to charset objects
+     */
+    public static SortedMap<String,Charset> availableCharsets() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<SortedMap<String,Charset>>() {
+                public SortedMap<String,Charset> run() {
+                    TreeMap<String,Charset> m =
+                        new TreeMap<String,Charset>(
+                            ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+                    for (String charsetName : CharsetICU.getAvailableCharsetNames()) {
+                        Charset charset = CharsetICU.charsetForName(charsetName);
+                        m.put(charset.name(), charset);
+                    }
+                    // Android-changed: No more "standard" provider.
+                    // put(standardProvider.charsets(), m);
+                    for (Iterator i = providers(); i.hasNext();) {
+                        CharsetProvider cp = (CharsetProvider)i.next();
+                        put(cp.charsets(), m);
+                    }
+                    return Collections.unmodifiableSortedMap(m);
+                }
+            });
+    }
+
+    private static Charset defaultCharset;
+
+    /**
+     * Returns the default charset of this Java virtual machine.
+     *
+     * <p>Android note: The Android platform default is always UTF-8.
+     *
+     * @return  A charset object for the default charset
+     *
+     * @since 1.5
+     */
+    public static Charset defaultCharset() {
+        // Android-changed: Use UTF_8 unconditionally.
+        synchronized (Charset.class) {
+            if (defaultCharset == null) {
+                defaultCharset = java.nio.charset.StandardCharsets.UTF_8;
+            }
+
+            return defaultCharset;
+        }
+    }
+
+
+    /* -- Instance fields and methods -- */
+
+    private final String name;          // tickles a bug in oldjavac
+    private final String[] aliases;     // tickles a bug in oldjavac
+    private Set<String> aliasSet = null;
+
+    /**
+     * Initializes a new charset with the given canonical name and alias
+     * set.
+     *
+     * @param  canonicalName
+     *         The canonical name of this charset
+     *
+     * @param  aliases
+     *         An array of this charset's aliases, or null if it has no aliases
+     *
+     * @throws IllegalCharsetNameException
+     *         If the canonical name or any of the aliases are illegal
+     */
+    @libcore.api.IntraCoreApi
+    protected Charset(String canonicalName, String[] aliases) {
+        checkName(canonicalName);
+        String[] as = (aliases == null) ? new String[0] : aliases;
+        for (int i = 0; i < as.length; i++)
+            checkName(as[i]);
+        this.name = canonicalName;
+        this.aliases = as;
+    }
+
+    /**
+     * Returns this charset's canonical name.
+     *
+     * @return  The canonical name of this charset
+     */
+    public final String name() {
+        return name;
+    }
+
+    /**
+     * Returns a set containing this charset's aliases.
+     *
+     * @return  An immutable set of this charset's aliases
+     */
+    public final Set<String> aliases() {
+        if (aliasSet != null)
+            return aliasSet;
+        int n = aliases.length;
+        HashSet<String> hs = new HashSet<String>(n);
+        for (int i = 0; i < n; i++)
+            hs.add(aliases[i]);
+        aliasSet = Collections.unmodifiableSet(hs);
+        return aliasSet;
+    }
+
+    /**
+     * Returns this charset's human-readable name for the default locale.
+     *
+     * <p> The default implementation of this method simply returns this
+     * charset's canonical name.  Concrete subclasses of this class may
+     * override this method in order to provide a localized display name. </p>
+     *
+     * @return  The display name of this charset in the default locale
+     */
+    public String displayName() {
+        return name;
+    }
+
+    /**
+     * Tells whether or not this charset is registered in the <a
+     * href="http://www.iana.org/assignments/character-sets">IANA Charset
+     * Registry</a>.
+     *
+     * @return  <tt>true</tt> if, and only if, this charset is known by its
+     *          implementor to be registered with the IANA
+     */
+    public final boolean isRegistered() {
+        return !name.startsWith("X-") && !name.startsWith("x-");
+    }
+
+    /**
+     * Returns this charset's human-readable name for the given locale.
+     *
+     * <p> The default implementation of this method simply returns this
+     * charset's canonical name.  Concrete subclasses of this class may
+     * override this method in order to provide a localized display name. </p>
+     *
+     * @param  locale
+     *         The locale for which the display name is to be retrieved
+     *
+     * @return  The display name of this charset in the given locale
+     */
+    public String displayName(Locale locale) {
+        return name;
+    }
+
+    /**
+     * Tells whether or not this charset contains the given charset.
+     *
+     * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,
+     * and only if, every character representable in <i>D</i> is also
+     * representable in <i>C</i>.  If this relationship holds then it is
+     * guaranteed that every string that can be encoded in <i>D</i> can also be
+     * encoded in <i>C</i> without performing any replacements.
+     *
+     * <p> That <i>C</i> contains <i>D</i> does not imply that each character
+     * representable in <i>C</i> by a particular byte sequence is represented
+     * in <i>D</i> by the same byte sequence, although sometimes this is the
+     * case.
+     *
+     * <p> Every charset contains itself.
+     *
+     * <p> This method computes an approximation of the containment relation:
+     * If it returns <tt>true</tt> then the given charset is known to be
+     * contained by this charset; if it returns <tt>false</tt>, however, then
+     * it is not necessarily the case that the given charset is not contained
+     * in this charset.
+     *
+     * @param   cs
+     *          The given charset
+     *
+     * @return  <tt>true</tt> if the given charset is contained in this charset
+     */
+    public abstract boolean contains(Charset cs);
+
+    /**
+     * Constructs a new decoder for this charset.
+     *
+     * @return  A new decoder for this charset
+     */
+    public abstract CharsetDecoder newDecoder();
+
+    /**
+     * Constructs a new encoder for this charset.
+     *
+     * @return  A new encoder for this charset
+     *
+     * @throws  UnsupportedOperationException
+     *          If this charset does not support encoding
+     */
+    public abstract CharsetEncoder newEncoder();
+
+    /**
+     * Tells whether or not this charset supports encoding.
+     *
+     * <p> Nearly all charsets support encoding.  The primary exceptions are
+     * special-purpose <i>auto-detect</i> charsets whose decoders can determine
+     * which of several possible encoding schemes is in use by examining the
+     * input byte sequence.  Such charsets do not support encoding because
+     * there is no way to determine which encoding should be used on output.
+     * Implementations of such charsets should override this method to return
+     * <tt>false</tt>. </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this charset supports encoding
+     */
+    public boolean canEncode() {
+        return true;
+    }
+
+    /**
+     * Convenience method that decodes bytes in this charset into Unicode
+     * characters.
+     *
+     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
+     * same result as the expression
+     *
+     * <pre>
+     *     cs.newDecoder()
+     *       .onMalformedInput(CodingErrorAction.REPLACE)
+     *       .onUnmappableCharacter(CodingErrorAction.REPLACE)
+     *       .decode(bb); </pre>
+     *
+     * except that it is potentially more efficient because it can cache
+     * decoders between successive invocations.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with this charset's default replacement byte array.  In order
+     * to detect such sequences, use the {@link
+     * CharsetDecoder#decode(java.nio.ByteBuffer)} method directly.  </p>
+     *
+     * @param  bb  The byte buffer to be decoded
+     *
+     * @return  A char buffer containing the decoded characters
+     */
+    public final CharBuffer decode(ByteBuffer bb) {
+        try {
+            return ThreadLocalCoders.decoderFor(this)
+                .onMalformedInput(CodingErrorAction.REPLACE)
+                .onUnmappableCharacter(CodingErrorAction.REPLACE)
+                .decode(bb);
+        } catch (CharacterCodingException x) {
+            throw new Error(x);         // Can't happen
+        }
+    }
+
+    /**
+     * Convenience method that encodes Unicode characters into bytes in this
+     * charset.
+     *
+     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
+     * same result as the expression
+     *
+     * <pre>
+     *     cs.newEncoder()
+     *       .onMalformedInput(CodingErrorAction.REPLACE)
+     *       .onUnmappableCharacter(CodingErrorAction.REPLACE)
+     *       .encode(bb); </pre>
+     *
+     * except that it is potentially more efficient because it can cache
+     * encoders between successive invocations.
+     *
+     * <p> This method always replaces malformed-input and unmappable-character
+     * sequences with this charset's default replacement string.  In order to
+     * detect such sequences, use the {@link
+     * CharsetEncoder#encode(java.nio.CharBuffer)} method directly.  </p>
+     *
+     * @param  cb  The char buffer to be encoded
+     *
+     * @return  A byte buffer containing the encoded characters
+     */
+    public final ByteBuffer encode(CharBuffer cb) {
+        try {
+            return ThreadLocalCoders.encoderFor(this)
+                .onMalformedInput(CodingErrorAction.REPLACE)
+                .onUnmappableCharacter(CodingErrorAction.REPLACE)
+                .encode(cb);
+        } catch (CharacterCodingException x) {
+            throw new Error(x);         // Can't happen
+        }
+    }
+
+    /**
+     * Convenience method that encodes a string into bytes in this charset.
+     *
+     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
+     * same result as the expression
+     *
+     * <pre>
+     *     cs.encode(CharBuffer.wrap(s)); </pre>
+     *
+     * @param  str  The string to be encoded
+     *
+     * @return  A byte buffer containing the encoded characters
+     */
+    public final ByteBuffer encode(String str) {
+        return encode(CharBuffer.wrap(str));
+    }
+
+    /**
+     * Compares this charset to another.
+     *
+     * <p> Charsets are ordered by their canonical names, without regard to
+     * case. </p>
+     *
+     * @param  that
+     *         The charset to which this charset is to be compared
+     *
+     * @return A negative integer, zero, or a positive integer as this charset
+     *         is less than, equal to, or greater than the specified charset
+     */
+    public final int compareTo(Charset that) {
+        return (name().compareToIgnoreCase(that.name()));
+    }
+
+    /**
+     * Computes a hashcode for this charset.
+     *
+     * @return  An integer hashcode
+     */
+    public final int hashCode() {
+        return name().hashCode();
+    }
+
+    /**
+     * Tells whether or not this object is equal to another.
+     *
+     * <p> Two charsets are equal if, and only if, they have the same canonical
+     * names.  A charset is never equal to any other type of object.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this charset is equal to the
+     *          given object
+     */
+    public final boolean equals(Object ob) {
+        if (!(ob instanceof Charset))
+            return false;
+        if (this == ob)
+            return true;
+        return name.equals(((Charset)ob).name());
+    }
+
+    /**
+     * Returns a string describing this charset.
+     *
+     * @return  A string describing this charset
+     */
+    public final String toString() {
+        return name();
+    }
+
+}
diff --git a/java/nio/charset/CharsetDecoder.annotated.java b/java/nio/charset/CharsetDecoder.annotated.java
new file mode 100644
index 0000000..ed0f378
--- /dev/null
+++ b/java/nio/charset/CharsetDecoder.annotated.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio.charset;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.charset.CoderMalfunctionError;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class CharsetDecoder {
+
[email protected]
+protected CharsetDecoder(java.nio.charset.Charset cs, float averageCharsPerByte, float maxCharsPerByte) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.Charset charset() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String replacement() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder replaceWith(java.lang.String newReplacement) { throw new RuntimeException("Stub!"); }
+
+protected void implReplaceWith(java.lang.String newReplacement) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction malformedInputAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder onMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction unmappableCharacterAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder onUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public final float averageCharsPerByte() { throw new RuntimeException("Stub!"); }
+
+public final float maxCharsPerByte() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult decode(java.nio.ByteBuffer in, java.nio.CharBuffer out, boolean endOfInput) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult flush(java.nio.CharBuffer out) { throw new RuntimeException("Stub!"); }
+
+protected java.nio.charset.CoderResult implFlush(java.nio.CharBuffer out) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetDecoder reset() { throw new RuntimeException("Stub!"); }
+
+protected void implReset() { throw new RuntimeException("Stub!"); }
+
+protected abstract java.nio.charset.CoderResult decodeLoop(java.nio.ByteBuffer in, java.nio.CharBuffer out);
+
+public final java.nio.CharBuffer decode(java.nio.ByteBuffer in) throws java.nio.charset.CharacterCodingException { throw new RuntimeException("Stub!"); }
+
+public boolean isAutoDetecting() { throw new RuntimeException("Stub!"); }
+
+public boolean isCharsetDetected() { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.Charset detectedCharset() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/nio/charset/CharsetDecoder.java b/java/nio/charset/CharsetDecoder.java
new file mode 100644
index 0000000..34065ee
--- /dev/null
+++ b/java/nio/charset/CharsetDecoder.java
@@ -0,0 +1,998 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.charset;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.lang.ref.WeakReference;
+import java.nio.charset.CoderMalfunctionError;                  // javadoc
+import java.util.Arrays;
+
+
+/**
+ * An engine that can transform a sequence of bytes in a specific charset into a sequence of
+ * sixteen-bit Unicode characters.
+ *
+ * <a name="steps"></a>
+ *
+ * <p> The input byte sequence is provided in a byte buffer or a series
+ * of such buffers.  The output character sequence is written to a character buffer
+ * or a series of such buffers.  A decoder should always be used by making
+ * the following sequence of method invocations, hereinafter referred to as a
+ * <i>decoding operation</i>:
+ *
+ * <ol>
+ *
+ *   <li><p> Reset the decoder via the {@link #reset reset} method, unless it
+ *   has not been used before; </p></li>
+ *
+ *   <li><p> Invoke the {@link #decode decode} method zero or more times, as
+ *   long as additional input may be available, passing <tt>false</tt> for the
+ *   <tt>endOfInput</tt> argument and filling the input buffer and flushing the
+ *   output buffer between invocations; </p></li>
+ *
+ *   <li><p> Invoke the {@link #decode decode} method one final time, passing
+ *   <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
+ *
+ *   <li><p> Invoke the {@link #flush flush} method so that the decoder can
+ *   flush any internal state to the output buffer. </p></li>
+ *
+ * </ol>
+ *
+ * Each invocation of the {@link #decode decode} method will decode as many
+ * bytes as possible from the input buffer, writing the resulting characters
+ * to the output buffer.  The {@link #decode decode} method returns when more
+ * input is required, when there is not enough room in the output buffer, or
+ * when a decoding error has occurred.  In each case a {@link CoderResult}
+ * object is returned to describe the reason for termination.  An invoker can
+ * examine this object and fill the input buffer, flush the output buffer, or
+ * attempt to recover from a decoding error, as appropriate, and try again.
+ *
+ * <a name="ce"></a>
+ *
+ * <p> There are two general types of decoding errors.  If the input byte
+ * sequence is not legal for this charset then the input is considered <i>malformed</i>.  If
+ * the input byte sequence is legal but cannot be mapped to a valid
+ * Unicode character then an <i>unmappable character</i> has been encountered.
+ *
+ * <a name="cae"></a>
+ *
+ * <p> How a decoding error is handled depends upon the action requested for
+ * that type of error, which is described by an instance of the {@link
+ * CodingErrorAction} class.  The possible error actions are to {@linkplain
+ * CodingErrorAction#IGNORE ignore} the erroneous input, {@linkplain
+ * CodingErrorAction#REPORT report} the error to the invoker via
+ * the returned {@link CoderResult} object, or {@linkplain CodingErrorAction#REPLACE
+ * replace} the erroneous input with the current value of the
+ * replacement string.  The replacement
+ *
+
+
+
+
+
+ * has the initial value <tt>"&#92;uFFFD"</tt>;
+
+ *
+ * its value may be changed via the {@link #replaceWith(java.lang.String)
+ * replaceWith} method.
+ *
+ * <p> The default action for malformed-input and unmappable-character errors
+ * is to {@linkplain CodingErrorAction#REPORT report} them.  The
+ * malformed-input error action may be changed via the {@link
+ * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
+ * unmappable-character action may be changed via the {@link
+ * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
+ *
+ * <p> This class is designed to handle many of the details of the decoding
+ * process, including the implementation of error actions.  A decoder for a
+ * specific charset, which is a concrete subclass of this class, need only
+ * implement the abstract {@link #decodeLoop decodeLoop} method, which
+ * encapsulates the basic decoding loop.  A subclass that maintains internal
+ * state should, additionally, override the {@link #implFlush implFlush} and
+ * {@link #implReset implReset} methods.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see ByteBuffer
+ * @see CharBuffer
+ * @see Charset
+ * @see CharsetEncoder
+ */
+
+public abstract class CharsetDecoder {
+
+    private final Charset charset;
+    private final float averageCharsPerByte;
+    private final float maxCharsPerByte;
+
+    private String replacement;
+    private CodingErrorAction malformedInputAction
+        = CodingErrorAction.REPORT;
+    private CodingErrorAction unmappableCharacterAction
+        = CodingErrorAction.REPORT;
+
+    // Internal states
+    //
+    private static final int ST_RESET   = 0;
+    private static final int ST_CODING  = 1;
+    private static final int ST_END     = 2;
+    private static final int ST_FLUSHED = 3;
+
+    private int state = ST_RESET;
+
+    private static String stateNames[]
+        = { "RESET", "CODING", "CODING_END", "FLUSHED" };
+
+
+    /**
+     * Initializes a new decoder.  The new decoder will have the given
+     * chars-per-byte and replacement values.
+     *
+     * @param  cs
+     *         The charset that created this decoder
+     *
+     * @param  averageCharsPerByte
+     *         A positive float value indicating the expected number of
+     *         characters that will be produced for each input byte
+     *
+     * @param  maxCharsPerByte
+     *         A positive float value indicating the maximum number of
+     *         characters that will be produced for each input byte
+     *
+     * @param  replacement
+     *         The initial replacement; must not be <tt>null</tt>, must have
+     *         non-zero length, must not be longer than maxCharsPerByte,
+     *         and must be {@linkplain #isLegalReplacement legal}
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     */
+    private
+    CharsetDecoder(Charset cs,
+                   float averageCharsPerByte,
+                   float maxCharsPerByte,
+                   String replacement)
+    {
+        this.charset = cs;
+        if (averageCharsPerByte <= 0.0f)
+            throw new IllegalArgumentException("Non-positive "
+                                               + "averageCharsPerByte");
+        if (maxCharsPerByte <= 0.0f)
+            throw new IllegalArgumentException("Non-positive "
+                                               + "maxCharsPerByte");
+        if (!Charset.atBugLevel("1.4")) {
+            if (averageCharsPerByte > maxCharsPerByte)
+                throw new IllegalArgumentException("averageCharsPerByte"
+                                                   + " exceeds "
+                                                   + "maxCharsPerByte");
+        }
+        this.replacement = replacement;
+        this.averageCharsPerByte = averageCharsPerByte;
+        this.maxCharsPerByte = maxCharsPerByte;
+        // Android-removed
+        // replaceWith(replacement);
+    }
+
+    /**
+     * Initializes a new decoder.  The new decoder will have the given
+     * chars-per-byte values and its replacement will be the
+     * string <tt>"&#92;uFFFD"</tt>.
+     *
+     * @param  cs
+     *         The charset that created this decoder
+     *
+     * @param  averageCharsPerByte
+     *         A positive float value indicating the expected number of
+     *         characters that will be produced for each input byte
+     *
+     * @param  maxCharsPerByte
+     *         A positive float value indicating the maximum number of
+     *         characters that will be produced for each input byte
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     */
+    protected CharsetDecoder(Charset cs,
+                             float averageCharsPerByte,
+                             float maxCharsPerByte)
+    {
+        this(cs,
+             averageCharsPerByte, maxCharsPerByte,
+             "\uFFFD");
+    }
+
+    /**
+     * Returns the charset that created this decoder.
+     *
+     * @return  This decoder's charset
+     */
+    public final Charset charset() {
+        return charset;
+    }
+
+    /**
+     * Returns this decoder's replacement value.
+     *
+     * @return  This decoder's current replacement,
+     *          which is never <tt>null</tt> and is never empty
+     */
+    public final String replacement() {
+
+        return replacement;
+
+
+
+
+    }
+
+    /**
+     * Changes this decoder's replacement value.
+     *
+     * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
+     * method, passing the new replacement, after checking that the new
+     * replacement is acceptable.  </p>
+     *
+     * @param  newReplacement  The replacement value
+     *
+
+     *         The new replacement; must not be <tt>null</tt>
+     *         and must have non-zero length
+
+
+
+
+
+
+
+     *
+     * @return  This decoder
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameter do not hold
+     */
+    public final CharsetDecoder replaceWith(String newReplacement) {
+        if (newReplacement == null)
+            throw new IllegalArgumentException("Null replacement");
+        int len = newReplacement.length();
+        if (len == 0)
+            throw new IllegalArgumentException("Empty replacement");
+        if (len > maxCharsPerByte)
+            throw new IllegalArgumentException("Replacement too long");
+
+        this.replacement = newReplacement;
+
+
+
+
+
+
+        implReplaceWith(this.replacement);
+        return this;
+    }
+
+    /**
+     * Reports a change to this decoder's replacement value.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by decoders that require notification of changes to
+     * the replacement.  </p>
+     *
+     * @param  newReplacement    The replacement value
+     */
+    protected void implReplaceWith(String newReplacement) {
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    /**
+     * Returns this decoder's current action for malformed-input errors.
+     *
+     * @return The current malformed-input action, which is never <tt>null</tt>
+     */
+    public CodingErrorAction malformedInputAction() {
+        return malformedInputAction;
+    }
+
+    /**
+     * Changes this decoder's action for malformed-input errors.
+     *
+     * <p> This method invokes the {@link #implOnMalformedInput
+     * implOnMalformedInput} method, passing the new action.  </p>
+     *
+     * @param  newAction  The new action; must not be <tt>null</tt>
+     *
+     * @return  This decoder
+     *
+     * @throws IllegalArgumentException
+     *         If the precondition on the parameter does not hold
+     */
+    public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
+        if (newAction == null)
+            throw new IllegalArgumentException("Null action");
+        malformedInputAction = newAction;
+        implOnMalformedInput(newAction);
+        return this;
+    }
+
+    /**
+     * Reports a change to this decoder's malformed-input action.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by decoders that require notification of changes to
+     * the malformed-input action.  </p>
+     *
+     * @param  newAction  The new action
+     */
+    protected void implOnMalformedInput(CodingErrorAction newAction) { }
+
+    /**
+     * Returns this decoder's current action for unmappable-character errors.
+     *
+     * @return The current unmappable-character action, which is never
+     *         <tt>null</tt>
+     */
+    public CodingErrorAction unmappableCharacterAction() {
+        return unmappableCharacterAction;
+    }
+
+    /**
+     * Changes this decoder's action for unmappable-character errors.
+     *
+     * <p> This method invokes the {@link #implOnUnmappableCharacter
+     * implOnUnmappableCharacter} method, passing the new action.  </p>
+     *
+     * @param  newAction  The new action; must not be <tt>null</tt>
+     *
+     * @return  This decoder
+     *
+     * @throws IllegalArgumentException
+     *         If the precondition on the parameter does not hold
+     */
+    public final CharsetDecoder onUnmappableCharacter(CodingErrorAction
+                                                      newAction)
+    {
+        if (newAction == null)
+            throw new IllegalArgumentException("Null action");
+        unmappableCharacterAction = newAction;
+        implOnUnmappableCharacter(newAction);
+        return this;
+    }
+
+    /**
+     * Reports a change to this decoder's unmappable-character action.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by decoders that require notification of changes to
+     * the unmappable-character action.  </p>
+     *
+     * @param  newAction  The new action
+     */
+    protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
+
+    /**
+     * Returns the average number of characters that will be produced for each
+     * byte of input.  This heuristic value may be used to estimate the size
+     * of the output buffer required for a given input sequence.
+     *
+     * @return  The average number of characters produced
+     *          per byte of input
+     */
+    public final float averageCharsPerByte() {
+        return averageCharsPerByte;
+    }
+
+    /**
+     * Returns the maximum number of characters that will be produced for each
+     * byte of input.  This value may be used to compute the worst-case size
+     * of the output buffer required for a given input sequence.
+     *
+     * @return  The maximum number of characters that will be produced per
+     *          byte of input
+     */
+    public final float maxCharsPerByte() {
+        return maxCharsPerByte;
+    }
+
+    /**
+     * Decodes as many bytes as possible from the given input buffer,
+     * writing the results to the given output buffer.
+     *
+     * <p> The buffers are read from, and written to, starting at their current
+     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
+     * will be read and at most {@link Buffer#remaining out.remaining()}
+     * characters will be written.  The buffers' positions will be advanced to
+     * reflect the bytes read and the characters written, but their marks and
+     * limits will not be modified.
+     *
+     * <p> In addition to reading bytes from the input buffer and writing
+     * characters to the output buffer, this method returns a {@link CoderResult}
+     * object to describe its reason for termination:
+     *
+     * <ul>
+     *
+     *   <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
+     *   input buffer as possible has been decoded.  If there is no further
+     *   input then the invoker can proceed to the next step of the
+     *   <a href="#steps">decoding operation</a>.  Otherwise this method
+     *   should be invoked again with further input.  </p></li>
+     *
+     *   <li><p> {@link CoderResult#OVERFLOW} indicates that there is
+     *   insufficient space in the output buffer to decode any more bytes.
+     *   This method should be invoked again with an output buffer that has
+     *   more {@linkplain Buffer#remaining remaining} characters. This is
+     *   typically done by draining any decoded characters from the output
+     *   buffer.  </p></li>
+     *
+     *   <li><p> A {@linkplain CoderResult#malformedForLength
+     *   malformed-input} result indicates that a malformed-input
+     *   error has been detected.  The malformed bytes begin at the input
+     *   buffer's (possibly incremented) position; the number of malformed
+     *   bytes may be determined by invoking the result object's {@link
+     *   CoderResult#length() length} method.  This case applies only if the
+     *   {@linkplain #onMalformedInput malformed action} of this decoder
+     *   is {@link CodingErrorAction#REPORT}; otherwise the malformed input
+     *   will be ignored or replaced, as requested.  </p></li>
+     *
+     *   <li><p> An {@linkplain CoderResult#unmappableForLength
+     *   unmappable-character} result indicates that an
+     *   unmappable-character error has been detected.  The bytes that
+     *   decode the unmappable character begin at the input buffer's (possibly
+     *   incremented) position; the number of such bytes may be determined
+     *   by invoking the result object's {@link CoderResult#length() length}
+     *   method.  This case applies only if the {@linkplain #onUnmappableCharacter
+     *   unmappable action} of this decoder is {@link
+     *   CodingErrorAction#REPORT}; otherwise the unmappable character will be
+     *   ignored or replaced, as requested.  </p></li>
+     *
+     * </ul>
+     *
+     * In any case, if this method is to be reinvoked in the same decoding
+     * operation then care should be taken to preserve any bytes remaining
+     * in the input buffer so that they are available to the next invocation.
+     *
+     * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
+     * the invoker can provide further input beyond that contained in the given
+     * input buffer.  If there is a possibility of providing additional input
+     * then the invoker should pass <tt>false</tt> for this parameter; if there
+     * is no possibility of providing further input then the invoker should
+     * pass <tt>true</tt>.  It is not erroneous, and in fact it is quite
+     * common, to pass <tt>false</tt> in one invocation and later discover that
+     * no further input was actually available.  It is critical, however, that
+     * the final invocation of this method in a sequence of invocations always
+     * pass <tt>true</tt> so that any remaining undecoded input will be treated
+     * as being malformed.
+     *
+     * <p> This method works by invoking the {@link #decodeLoop decodeLoop}
+     * method, interpreting its results, handling error conditions, and
+     * reinvoking it as necessary.  </p>
+     *
+     *
+     * @param  in
+     *         The input byte buffer
+     *
+     * @param  out
+     *         The output character buffer
+     *
+     * @param  endOfInput
+     *         <tt>true</tt> if, and only if, the invoker can provide no
+     *         additional input bytes beyond those in the given buffer
+     *
+     * @return  A coder-result object describing the reason for termination
+     *
+     * @throws  IllegalStateException
+     *          If a decoding operation is already in progress and the previous
+     *          step was an invocation neither of the {@link #reset reset}
+     *          method, nor of this method with a value of <tt>false</tt> for
+     *          the <tt>endOfInput</tt> parameter, nor of this method with a
+     *          value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
+     *          but a return value indicating an incomplete decoding operation
+     *
+     * @throws  CoderMalfunctionError
+     *          If an invocation of the decodeLoop method threw
+     *          an unexpected exception
+     */
+    public final CoderResult decode(ByteBuffer in, CharBuffer out,
+                                    boolean endOfInput)
+    {
+        int newState = endOfInput ? ST_END : ST_CODING;
+        if ((state != ST_RESET) && (state != ST_CODING)
+            && !(endOfInput && (state == ST_END)))
+            throwIllegalStateException(state, newState);
+        state = newState;
+
+        for (;;) {
+
+            CoderResult cr;
+            try {
+                cr = decodeLoop(in, out);
+            } catch (BufferUnderflowException x) {
+                throw new CoderMalfunctionError(x);
+            } catch (BufferOverflowException x) {
+                throw new CoderMalfunctionError(x);
+            }
+
+            if (cr.isOverflow())
+                return cr;
+
+            if (cr.isUnderflow()) {
+                if (endOfInput && in.hasRemaining()) {
+                    cr = CoderResult.malformedForLength(in.remaining());
+                    // Fall through to malformed-input case
+                } else {
+                    return cr;
+                }
+            }
+
+            CodingErrorAction action = null;
+            if (cr.isMalformed())
+                action = malformedInputAction;
+            else if (cr.isUnmappable())
+                action = unmappableCharacterAction;
+            else
+                assert false : cr.toString();
+
+            if (action == CodingErrorAction.REPORT)
+                return cr;
+
+            if (action == CodingErrorAction.REPLACE) {
+                if (out.remaining() < replacement.length())
+                    return CoderResult.OVERFLOW;
+                out.put(replacement);
+            }
+
+            if ((action == CodingErrorAction.IGNORE)
+                || (action == CodingErrorAction.REPLACE)) {
+                // Skip erroneous input either way
+                in.position(in.position() + cr.length());
+                continue;
+            }
+
+            assert false;
+        }
+
+    }
+
+    /**
+     * Flushes this decoder.
+     *
+     * <p> Some decoders maintain internal state and may need to write some
+     * final characters to the output buffer once the overall input sequence has
+     * been read.
+     *
+     * <p> Any additional output is written to the output buffer beginning at
+     * its current position.  At most {@link Buffer#remaining out.remaining()}
+     * characters will be written.  The buffer's position will be advanced
+     * appropriately, but its mark and limit will not be modified.
+     *
+     * <p> If this method completes successfully then it returns {@link
+     * CoderResult#UNDERFLOW}.  If there is insufficient room in the output
+     * buffer then it returns {@link CoderResult#OVERFLOW}.  If this happens
+     * then this method must be invoked again, with an output buffer that has
+     * more room, in order to complete the current <a href="#steps">decoding
+     * operation</a>.
+     *
+     * <p> If this decoder has already been flushed then invoking this method
+     * has no effect.
+     *
+     * <p> This method invokes the {@link #implFlush implFlush} method to
+     * perform the actual flushing operation.  </p>
+     *
+     * @param  out
+     *         The output character buffer
+     *
+     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
+     *          {@link CoderResult#OVERFLOW}
+     *
+     * @throws  IllegalStateException
+     *          If the previous step of the current decoding operation was an
+     *          invocation neither of the {@link #flush flush} method nor of
+     *          the three-argument {@link
+     *          #decode(ByteBuffer,CharBuffer,boolean) decode} method
+     *          with a value of <tt>true</tt> for the <tt>endOfInput</tt>
+     *          parameter
+     */
+    public final CoderResult flush(CharBuffer out) {
+        if (state == ST_END) {
+            CoderResult cr = implFlush(out);
+            if (cr.isUnderflow())
+                state = ST_FLUSHED;
+            return cr;
+        }
+
+        if (state != ST_FLUSHED)
+            throwIllegalStateException(state, ST_FLUSHED);
+
+        return CoderResult.UNDERFLOW; // Already flushed
+    }
+
+    /**
+     * Flushes this decoder.
+     *
+     * <p> The default implementation of this method does nothing, and always
+     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
+     * by decoders that may need to write final characters to the output buffer
+     * once the entire input sequence has been read. </p>
+     *
+     * @param  out
+     *         The output character buffer
+     *
+     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
+     *          {@link CoderResult#OVERFLOW}
+     */
+    protected CoderResult implFlush(CharBuffer out) {
+        return CoderResult.UNDERFLOW;
+    }
+
+    /**
+     * Resets this decoder, clearing any internal state.
+     *
+     * <p> This method resets charset-independent state and also invokes the
+     * {@link #implReset() implReset} method in order to perform any
+     * charset-specific reset actions.  </p>
+     *
+     * @return  This decoder
+     *
+     */
+    public final CharsetDecoder reset() {
+        implReset();
+        state = ST_RESET;
+        return this;
+    }
+
+    /**
+     * Resets this decoder, clearing any charset-specific internal state.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by decoders that maintain internal state.  </p>
+     */
+    protected void implReset() { }
+
+    /**
+     * Decodes one or more bytes into one or more characters.
+     *
+     * <p> This method encapsulates the basic decoding loop, decoding as many
+     * bytes as possible until it either runs out of input, runs out of room
+     * in the output buffer, or encounters a decoding error.  This method is
+     * invoked by the {@link #decode decode} method, which handles result
+     * interpretation and error recovery.
+     *
+     * <p> The buffers are read from, and written to, starting at their current
+     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
+     * will be read, and at most {@link Buffer#remaining out.remaining()}
+     * characters will be written.  The buffers' positions will be advanced to
+     * reflect the bytes read and the characters written, but their marks and
+     * limits will not be modified.
+     *
+     * <p> This method returns a {@link CoderResult} object to describe its
+     * reason for termination, in the same manner as the {@link #decode decode}
+     * method.  Most implementations of this method will handle decoding errors
+     * by returning an appropriate result object for interpretation by the
+     * {@link #decode decode} method.  An optimized implementation may instead
+     * examine the relevant error action and implement that action itself.
+     *
+     * <p> An implementation of this method may perform arbitrary lookahead by
+     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
+     * input.  </p>
+     *
+     * @param  in
+     *         The input byte buffer
+     *
+     * @param  out
+     *         The output character buffer
+     *
+     * @return  A coder-result object describing the reason for termination
+     */
+    protected abstract CoderResult decodeLoop(ByteBuffer in,
+                                              CharBuffer out);
+
+    /**
+     * Convenience method that decodes the remaining content of a single input
+     * byte buffer into a newly-allocated character buffer.
+     *
+     * <p> This method implements an entire <a href="#steps">decoding
+     * operation</a>; that is, it resets this decoder, then it decodes the
+     * bytes in the given byte buffer, and finally it flushes this
+     * decoder.  This method should therefore not be invoked if a decoding
+     * operation is already in progress.  </p>
+     *
+     * @param  in
+     *         The input byte buffer
+     *
+     * @return A newly-allocated character buffer containing the result of the
+     *         decoding operation.  The buffer's position will be zero and its
+     *         limit will follow the last character written.
+     *
+     * @throws  IllegalStateException
+     *          If a decoding operation is already in progress
+     *
+     * @throws  MalformedInputException
+     *          If the byte sequence starting at the input buffer's current
+     *          position is not legal for this charset and the current malformed-input action
+     *          is {@link CodingErrorAction#REPORT}
+     *
+     * @throws  UnmappableCharacterException
+     *          If the byte sequence starting at the input buffer's current
+     *          position cannot be mapped to an equivalent character sequence and
+     *          the current unmappable-character action is {@link
+     *          CodingErrorAction#REPORT}
+     */
+    public final CharBuffer decode(ByteBuffer in)
+        throws CharacterCodingException
+    {
+        int n = (int)(in.remaining() * averageCharsPerByte());
+        CharBuffer out = CharBuffer.allocate(n);
+
+        if ((n == 0) && (in.remaining() == 0))
+            return out;
+        reset();
+        for (;;) {
+            CoderResult cr = in.hasRemaining() ?
+                decode(in, out, true) : CoderResult.UNDERFLOW;
+            if (cr.isUnderflow())
+                cr = flush(out);
+
+            if (cr.isUnderflow())
+                break;
+            if (cr.isOverflow()) {
+                n = 2*n + 1;    // Ensure progress; n might be 0!
+                CharBuffer o = CharBuffer.allocate(n);
+                out.flip();
+                o.put(out);
+                out = o;
+                continue;
+            }
+            cr.throwException();
+        }
+        out.flip();
+        return out;
+    }
+
+
+
+    /**
+     * Tells whether or not this decoder implements an auto-detecting charset.
+     *
+     * <p> The default implementation of this method always returns
+     * <tt>false</tt>; it should be overridden by auto-detecting decoders to
+     * return <tt>true</tt>.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this decoder implements an
+     *          auto-detecting charset
+     */
+    public boolean isAutoDetecting() {
+        return false;
+    }
+
+    /**
+     * Tells whether or not this decoder has yet detected a
+     * charset&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this decoder implements an auto-detecting charset then at a
+     * single point during a decoding operation this method may start returning
+     * <tt>true</tt> to indicate that a specific charset has been detected in
+     * the input byte sequence.  Once this occurs, the {@link #detectedCharset
+     * detectedCharset} method may be invoked to retrieve the detected charset.
+     *
+     * <p> That this method returns <tt>false</tt> does not imply that no bytes
+     * have yet been decoded.  Some auto-detecting decoders are capable of
+     * decoding some, or even all, of an input byte sequence without fixing on
+     * a particular charset.
+     *
+     * <p> The default implementation of this method always throws an {@link
+     * UnsupportedOperationException}; it should be overridden by
+     * auto-detecting decoders to return <tt>true</tt> once the input charset
+     * has been determined.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, this decoder has detected a
+     *          specific charset
+     *
+     * @throws  UnsupportedOperationException
+     *          If this decoder does not implement an auto-detecting charset
+     */
+    public boolean isCharsetDetected() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieves the charset that was detected by this
+     * decoder&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * <p> If this decoder implements an auto-detecting charset then this
+     * method returns the actual charset once it has been detected.  After that
+     * point, this method returns the same value for the duration of the
+     * current decoding operation.  If not enough input bytes have yet been
+     * read to determine the actual charset then this method throws an {@link
+     * IllegalStateException}.
+     *
+     * <p> The default implementation of this method always throws an {@link
+     * UnsupportedOperationException}; it should be overridden by
+     * auto-detecting decoders to return the appropriate value.  </p>
+     *
+     * @return  The charset detected by this auto-detecting decoder,
+     *          or <tt>null</tt> if the charset has not yet been determined
+     *
+     * @throws  IllegalStateException
+     *          If insufficient bytes have been read to determine a charset
+     *
+     * @throws  UnsupportedOperationException
+     *          If this decoder does not implement an auto-detecting charset
+     */
+    public Charset detectedCharset() {
+        throw new UnsupportedOperationException();
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    private void throwIllegalStateException(int from, int to) {
+        throw new IllegalStateException("Current state = " + stateNames[from]
+                                        + ", new state = " + stateNames[to]);
+    }
+
+}
diff --git a/java/nio/charset/CharsetEncoder.annotated.java b/java/nio/charset/CharsetEncoder.annotated.java
new file mode 100644
index 0000000..ceb323e
--- /dev/null
+++ b/java/nio/charset/CharsetEncoder.annotated.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+
+package java.nio.charset;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.charset.CoderMalfunctionError;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class CharsetEncoder {
+
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement) { throw new RuntimeException("Stub!"); }
+
[email protected]
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement, boolean trusted) { throw new RuntimeException("Stub!"); }
+
+protected CharsetEncoder(java.nio.charset.Charset cs, float averageBytesPerChar, float maxBytesPerChar) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.Charset charset() { throw new RuntimeException("Stub!"); }
+
+public final byte[] replacement() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder replaceWith(byte[] newReplacement) { throw new RuntimeException("Stub!"); }
+
+protected void implReplaceWith(byte[] newReplacement) { throw new RuntimeException("Stub!"); }
+
+public boolean isLegalReplacement(byte[] repl) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction malformedInputAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder onMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnMalformedInput(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public java.nio.charset.CodingErrorAction unmappableCharacterAction() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder onUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+protected void implOnUnmappableCharacter(java.nio.charset.CodingErrorAction newAction) { throw new RuntimeException("Stub!"); }
+
+public final float averageBytesPerChar() { throw new RuntimeException("Stub!"); }
+
+public final float maxBytesPerChar() { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult encode(java.nio.CharBuffer in, java.nio.ByteBuffer out, boolean endOfInput) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CoderResult flush(java.nio.ByteBuffer out) { throw new RuntimeException("Stub!"); }
+
+protected java.nio.charset.CoderResult implFlush(java.nio.ByteBuffer out) { throw new RuntimeException("Stub!"); }
+
+public final java.nio.charset.CharsetEncoder reset() { throw new RuntimeException("Stub!"); }
+
+protected void implReset() { throw new RuntimeException("Stub!"); }
+
+protected abstract java.nio.charset.CoderResult encodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out);
+
+public final java.nio.ByteBuffer encode(java.nio.CharBuffer in) throws java.nio.charset.CharacterCodingException { throw new RuntimeException("Stub!"); }
+
+public boolean canEncode(char c) { throw new RuntimeException("Stub!"); }
+
+public boolean canEncode(java.lang.CharSequence cs) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/nio/charset/CharsetEncoder.java b/java/nio/charset/CharsetEncoder.java
new file mode 100644
index 0000000..98b4dea
--- /dev/null
+++ b/java/nio/charset/CharsetEncoder.java
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.charset;
+
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.lang.ref.WeakReference;
+import java.nio.charset.CoderMalfunctionError;                  // javadoc
+import java.util.Arrays;
+
+
+/**
+ * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
+ * bytes in a specific charset.
+ *
+ * <a name="steps"></a>
+ *
+ * <p> The input character sequence is provided in a character buffer or a series
+ * of such buffers.  The output byte sequence is written to a byte buffer
+ * or a series of such buffers.  An encoder should always be used by making
+ * the following sequence of method invocations, hereinafter referred to as an
+ * <i>encoding operation</i>:
+ *
+ * <ol>
+ *
+ *   <li><p> Reset the encoder via the {@link #reset reset} method, unless it
+ *   has not been used before; </p></li>
+ *
+ *   <li><p> Invoke the {@link #encode encode} method zero or more times, as
+ *   long as additional input may be available, passing <tt>false</tt> for the
+ *   <tt>endOfInput</tt> argument and filling the input buffer and flushing the
+ *   output buffer between invocations; </p></li>
+ *
+ *   <li><p> Invoke the {@link #encode encode} method one final time, passing
+ *   <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
+ *
+ *   <li><p> Invoke the {@link #flush flush} method so that the encoder can
+ *   flush any internal state to the output buffer. </p></li>
+ *
+ * </ol>
+ *
+ * Each invocation of the {@link #encode encode} method will encode as many
+ * characters as possible from the input buffer, writing the resulting bytes
+ * to the output buffer.  The {@link #encode encode} method returns when more
+ * input is required, when there is not enough room in the output buffer, or
+ * when an encoding error has occurred.  In each case a {@link CoderResult}
+ * object is returned to describe the reason for termination.  An invoker can
+ * examine this object and fill the input buffer, flush the output buffer, or
+ * attempt to recover from an encoding error, as appropriate, and try again.
+ *
+ * <a name="ce"></a>
+ *
+ * <p> There are two general types of encoding errors.  If the input character
+ * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>.  If
+ * the input character sequence is legal but cannot be mapped to a valid
+ * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
+ *
+ * <a name="cae"></a>
+ *
+ * <p> How an encoding error is handled depends upon the action requested for
+ * that type of error, which is described by an instance of the {@link
+ * CodingErrorAction} class.  The possible error actions are to {@linkplain
+ * CodingErrorAction#IGNORE ignore} the erroneous input, {@linkplain
+ * CodingErrorAction#REPORT report} the error to the invoker via
+ * the returned {@link CoderResult} object, or {@linkplain CodingErrorAction#REPLACE
+ * replace} the erroneous input with the current value of the
+ * replacement byte array.  The replacement
+ *
+
+ * is initially set to the encoder's default replacement, which often
+ * (but not always) has the initial value&nbsp;<tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>;
+
+
+
+
+ *
+ * its value may be changed via the {@link #replaceWith(byte[])
+ * replaceWith} method.
+ *
+ * <p> The default action for malformed-input and unmappable-character errors
+ * is to {@linkplain CodingErrorAction#REPORT report} them.  The
+ * malformed-input error action may be changed via the {@link
+ * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
+ * unmappable-character action may be changed via the {@link
+ * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
+ *
+ * <p> This class is designed to handle many of the details of the encoding
+ * process, including the implementation of error actions.  An encoder for a
+ * specific charset, which is a concrete subclass of this class, need only
+ * implement the abstract {@link #encodeLoop encodeLoop} method, which
+ * encapsulates the basic encoding loop.  A subclass that maintains internal
+ * state should, additionally, override the {@link #implFlush implFlush} and
+ * {@link #implReset implReset} methods.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see ByteBuffer
+ * @see CharBuffer
+ * @see Charset
+ * @see CharsetDecoder
+ */
+
+public abstract class CharsetEncoder {
+
+    private final Charset charset;
+    private final float averageBytesPerChar;
+    private final float maxBytesPerChar;
+
+    private byte[] replacement;
+    private CodingErrorAction malformedInputAction
+        = CodingErrorAction.REPORT;
+    private CodingErrorAction unmappableCharacterAction
+        = CodingErrorAction.REPORT;
+
+    // Internal states
+    //
+    private static final int ST_RESET   = 0;
+    private static final int ST_CODING  = 1;
+    private static final int ST_END     = 2;
+    private static final int ST_FLUSHED = 3;
+
+    private int state = ST_RESET;
+
+    private static String stateNames[]
+        = { "RESET", "CODING", "CODING_END", "FLUSHED" };
+
+
+    /**
+     * Initializes a new encoder.  The new encoder will have the given
+     * bytes-per-char and replacement values.
+     *
+     * @param  cs
+     *         The charset that created this encoder
+     *
+     * @param  averageBytesPerChar
+     *         A positive float value indicating the expected number of
+     *         bytes that will be produced for each input character
+     *
+     * @param  maxBytesPerChar
+     *         A positive float value indicating the maximum number of
+     *         bytes that will be produced for each input character
+     *
+     * @param  replacement
+     *         The initial replacement; must not be <tt>null</tt>, must have
+     *         non-zero length, must not be longer than maxBytesPerChar,
+     *         and must be {@linkplain #isLegalReplacement legal}
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     */
+    protected
+    CharsetEncoder(Charset cs,
+                   float averageBytesPerChar,
+                   float maxBytesPerChar,
+                   byte[] replacement)
+    {
+        // BEGIN Android-added: A hidden constructor for the CharsetEncoderICU subclass.
+        this(cs, averageBytesPerChar, maxBytesPerChar, replacement, false);
+    }
+
+    /**
+     * This constructor is for subclasses to specify whether {@code replacement} can be used as it
+     * is ("trusted"). If it is trusted, {@link #replaceWith(byte[])} and
+     * {@link #implReplaceWith(byte[])} will not be called.
+     * @hide
+     */
+    protected CharsetEncoder(Charset cs, float averageBytesPerChar, float maxBytesPerChar, byte[] replacement,
+            boolean trusted)
+    {
+        // END Android-added: A hidden constructor for the CharsetEncoderICU subclass.
+        this.charset = cs;
+        if (averageBytesPerChar <= 0.0f)
+            throw new IllegalArgumentException("Non-positive "
+                                               + "averageBytesPerChar");
+        if (maxBytesPerChar <= 0.0f)
+            throw new IllegalArgumentException("Non-positive "
+                                               + "maxBytesPerChar");
+        if (!Charset.atBugLevel("1.4")) {
+            if (averageBytesPerChar > maxBytesPerChar)
+                throw new IllegalArgumentException("averageBytesPerChar"
+                                                   + " exceeds "
+                                                   + "maxBytesPerChar");
+        }
+        this.replacement = replacement;
+        this.averageBytesPerChar = averageBytesPerChar;
+        this.maxBytesPerChar = maxBytesPerChar;
+        // BEGIN Android-changed: Avoid calling replaceWith() for trusted subclasses.
+        // replaceWith(replacement);
+        if (!trusted) {
+            replaceWith(replacement);
+        }
+        // END Android-changed: Avoid calling replaceWith() for trusted subclasses.
+    }
+
+    /**
+     * Initializes a new encoder.  The new encoder will have the given
+     * bytes-per-char values and its replacement will be the
+     * byte array <tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>.
+     *
+     * @param  cs
+     *         The charset that created this encoder
+     *
+     * @param  averageBytesPerChar
+     *         A positive float value indicating the expected number of
+     *         bytes that will be produced for each input character
+     *
+     * @param  maxBytesPerChar
+     *         A positive float value indicating the maximum number of
+     *         bytes that will be produced for each input character
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameters do not hold
+     */
+    protected CharsetEncoder(Charset cs,
+                             float averageBytesPerChar,
+                             float maxBytesPerChar)
+    {
+        this(cs,
+             averageBytesPerChar, maxBytesPerChar,
+             new byte[] { (byte)'?' });
+    }
+
+    /**
+     * Returns the charset that created this encoder.
+     *
+     * @return  This encoder's charset
+     */
+    public final Charset charset() {
+        return charset;
+    }
+
+    /**
+     * Returns this encoder's replacement value.
+     *
+     * @return  This encoder's current replacement,
+     *          which is never <tt>null</tt> and is never empty
+     */
+    public final byte[] replacement() {
+
+
+
+
+        return Arrays.copyOf(replacement, replacement.length);
+
+    }
+
+    /**
+     * Changes this encoder's replacement value.
+     *
+     * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
+     * method, passing the new replacement, after checking that the new
+     * replacement is acceptable.  </p>
+     *
+     * @param  newReplacement  The replacement value
+     *
+
+
+
+
+
+     *         The new replacement; must not be <tt>null</tt>, must have
+     *         non-zero length, must not be longer than the value returned by
+     *         the {@link #maxBytesPerChar() maxBytesPerChar} method, and
+     *         must be {@link #isLegalReplacement legal}
+
+     *
+     * @return  This encoder
+     *
+     * @throws  IllegalArgumentException
+     *          If the preconditions on the parameter do not hold
+     */
+    public final CharsetEncoder replaceWith(byte[] newReplacement) {
+        if (newReplacement == null)
+            throw new IllegalArgumentException("Null replacement");
+        int len = newReplacement.length;
+        if (len == 0)
+            throw new IllegalArgumentException("Empty replacement");
+        if (len > maxBytesPerChar)
+            throw new IllegalArgumentException("Replacement too long");
+
+
+
+
+        if (!isLegalReplacement(newReplacement))
+            throw new IllegalArgumentException("Illegal replacement");
+        this.replacement = Arrays.copyOf(newReplacement, newReplacement.length);
+
+        implReplaceWith(this.replacement);
+        return this;
+    }
+
+    /**
+     * Reports a change to this encoder's replacement value.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by encoders that require notification of changes to
+     * the replacement.  </p>
+     *
+     * @param  newReplacement    The replacement value
+     */
+    protected void implReplaceWith(byte[] newReplacement) {
+    }
+
+
+
+    private WeakReference<CharsetDecoder> cachedDecoder = null;
+
+    /**
+     * Tells whether or not the given byte array is a legal replacement value
+     * for this encoder.
+     *
+     * <p> A replacement is legal if, and only if, it is a legal sequence of
+     * bytes in this encoder's charset; that is, it must be possible to decode
+     * the replacement into one or more sixteen-bit Unicode characters.
+     *
+     * <p> The default implementation of this method is not very efficient; it
+     * should generally be overridden to improve performance.  </p>
+     *
+     * @param  repl  The byte array to be tested
+     *
+     * @return  <tt>true</tt> if, and only if, the given byte array
+     *          is a legal replacement value for this encoder
+     */
+    public boolean isLegalReplacement(byte[] repl) {
+        WeakReference<CharsetDecoder> wr = cachedDecoder;
+        CharsetDecoder dec = null;
+        if ((wr == null) || ((dec = wr.get()) == null)) {
+            dec = charset().newDecoder();
+            dec.onMalformedInput(CodingErrorAction.REPORT);
+            dec.onUnmappableCharacter(CodingErrorAction.REPORT);
+            cachedDecoder = new WeakReference<CharsetDecoder>(dec);
+        } else {
+            dec.reset();
+        }
+        ByteBuffer bb = ByteBuffer.wrap(repl);
+        CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
+                                                  * dec.maxCharsPerByte()));
+        CoderResult cr = dec.decode(bb, cb, true);
+        return !cr.isError();
+    }
+
+
+
+    /**
+     * Returns this encoder's current action for malformed-input errors.
+     *
+     * @return The current malformed-input action, which is never <tt>null</tt>
+     */
+    public CodingErrorAction malformedInputAction() {
+        return malformedInputAction;
+    }
+
+    /**
+     * Changes this encoder's action for malformed-input errors.
+     *
+     * <p> This method invokes the {@link #implOnMalformedInput
+     * implOnMalformedInput} method, passing the new action.  </p>
+     *
+     * @param  newAction  The new action; must not be <tt>null</tt>
+     *
+     * @return  This encoder
+     *
+     * @throws IllegalArgumentException
+     *         If the precondition on the parameter does not hold
+     */
+    public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
+        if (newAction == null)
+            throw new IllegalArgumentException("Null action");
+        malformedInputAction = newAction;
+        implOnMalformedInput(newAction);
+        return this;
+    }
+
+    /**
+     * Reports a change to this encoder's malformed-input action.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by encoders that require notification of changes to
+     * the malformed-input action.  </p>
+     *
+     * @param  newAction  The new action
+     */
+    protected void implOnMalformedInput(CodingErrorAction newAction) { }
+
+    /**
+     * Returns this encoder's current action for unmappable-character errors.
+     *
+     * @return The current unmappable-character action, which is never
+     *         <tt>null</tt>
+     */
+    public CodingErrorAction unmappableCharacterAction() {
+        return unmappableCharacterAction;
+    }
+
+    /**
+     * Changes this encoder's action for unmappable-character errors.
+     *
+     * <p> This method invokes the {@link #implOnUnmappableCharacter
+     * implOnUnmappableCharacter} method, passing the new action.  </p>
+     *
+     * @param  newAction  The new action; must not be <tt>null</tt>
+     *
+     * @return  This encoder
+     *
+     * @throws IllegalArgumentException
+     *         If the precondition on the parameter does not hold
+     */
+    public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
+                                                      newAction)
+    {
+        if (newAction == null)
+            throw new IllegalArgumentException("Null action");
+        unmappableCharacterAction = newAction;
+        implOnUnmappableCharacter(newAction);
+        return this;
+    }
+
+    /**
+     * Reports a change to this encoder's unmappable-character action.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by encoders that require notification of changes to
+     * the unmappable-character action.  </p>
+     *
+     * @param  newAction  The new action
+     */
+    protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
+
+    /**
+     * Returns the average number of bytes that will be produced for each
+     * character of input.  This heuristic value may be used to estimate the size
+     * of the output buffer required for a given input sequence.
+     *
+     * @return  The average number of bytes produced
+     *          per character of input
+     */
+    public final float averageBytesPerChar() {
+        return averageBytesPerChar;
+    }
+
+    /**
+     * Returns the maximum number of bytes that will be produced for each
+     * character of input.  This value may be used to compute the worst-case size
+     * of the output buffer required for a given input sequence.
+     *
+     * @return  The maximum number of bytes that will be produced per
+     *          character of input
+     */
+    public final float maxBytesPerChar() {
+        return maxBytesPerChar;
+    }
+
+    /**
+     * Encodes as many characters as possible from the given input buffer,
+     * writing the results to the given output buffer.
+     *
+     * <p> The buffers are read from, and written to, starting at their current
+     * positions.  At most {@link Buffer#remaining in.remaining()} characters
+     * will be read and at most {@link Buffer#remaining out.remaining()}
+     * bytes will be written.  The buffers' positions will be advanced to
+     * reflect the characters read and the bytes written, but their marks and
+     * limits will not be modified.
+     *
+     * <p> In addition to reading characters from the input buffer and writing
+     * bytes to the output buffer, this method returns a {@link CoderResult}
+     * object to describe its reason for termination:
+     *
+     * <ul>
+     *
+     *   <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
+     *   input buffer as possible has been encoded.  If there is no further
+     *   input then the invoker can proceed to the next step of the
+     *   <a href="#steps">encoding operation</a>.  Otherwise this method
+     *   should be invoked again with further input.  </p></li>
+     *
+     *   <li><p> {@link CoderResult#OVERFLOW} indicates that there is
+     *   insufficient space in the output buffer to encode any more characters.
+     *   This method should be invoked again with an output buffer that has
+     *   more {@linkplain Buffer#remaining remaining} bytes. This is
+     *   typically done by draining any encoded bytes from the output
+     *   buffer.  </p></li>
+     *
+     *   <li><p> A {@linkplain CoderResult#malformedForLength
+     *   malformed-input} result indicates that a malformed-input
+     *   error has been detected.  The malformed characters begin at the input
+     *   buffer's (possibly incremented) position; the number of malformed
+     *   characters may be determined by invoking the result object's {@link
+     *   CoderResult#length() length} method.  This case applies only if the
+     *   {@linkplain #onMalformedInput malformed action} of this encoder
+     *   is {@link CodingErrorAction#REPORT}; otherwise the malformed input
+     *   will be ignored or replaced, as requested.  </p></li>
+     *
+     *   <li><p> An {@linkplain CoderResult#unmappableForLength
+     *   unmappable-character} result indicates that an
+     *   unmappable-character error has been detected.  The characters that
+     *   encode the unmappable character begin at the input buffer's (possibly
+     *   incremented) position; the number of such characters may be determined
+     *   by invoking the result object's {@link CoderResult#length() length}
+     *   method.  This case applies only if the {@linkplain #onUnmappableCharacter
+     *   unmappable action} of this encoder is {@link
+     *   CodingErrorAction#REPORT}; otherwise the unmappable character will be
+     *   ignored or replaced, as requested.  </p></li>
+     *
+     * </ul>
+     *
+     * In any case, if this method is to be reinvoked in the same encoding
+     * operation then care should be taken to preserve any characters remaining
+     * in the input buffer so that they are available to the next invocation.
+     *
+     * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
+     * the invoker can provide further input beyond that contained in the given
+     * input buffer.  If there is a possibility of providing additional input
+     * then the invoker should pass <tt>false</tt> for this parameter; if there
+     * is no possibility of providing further input then the invoker should
+     * pass <tt>true</tt>.  It is not erroneous, and in fact it is quite
+     * common, to pass <tt>false</tt> in one invocation and later discover that
+     * no further input was actually available.  It is critical, however, that
+     * the final invocation of this method in a sequence of invocations always
+     * pass <tt>true</tt> so that any remaining unencoded input will be treated
+     * as being malformed.
+     *
+     * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
+     * method, interpreting its results, handling error conditions, and
+     * reinvoking it as necessary.  </p>
+     *
+     *
+     * @param  in
+     *         The input character buffer
+     *
+     * @param  out
+     *         The output byte buffer
+     *
+     * @param  endOfInput
+     *         <tt>true</tt> if, and only if, the invoker can provide no
+     *         additional input characters beyond those in the given buffer
+     *
+     * @return  A coder-result object describing the reason for termination
+     *
+     * @throws  IllegalStateException
+     *          If an encoding operation is already in progress and the previous
+     *          step was an invocation neither of the {@link #reset reset}
+     *          method, nor of this method with a value of <tt>false</tt> for
+     *          the <tt>endOfInput</tt> parameter, nor of this method with a
+     *          value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
+     *          but a return value indicating an incomplete encoding operation
+     *
+     * @throws  CoderMalfunctionError
+     *          If an invocation of the encodeLoop method threw
+     *          an unexpected exception
+     */
+    public final CoderResult encode(CharBuffer in, ByteBuffer out,
+                                    boolean endOfInput)
+    {
+        int newState = endOfInput ? ST_END : ST_CODING;
+        if ((state != ST_RESET) && (state != ST_CODING)
+            && !(endOfInput && (state == ST_END)))
+            throwIllegalStateException(state, newState);
+        state = newState;
+
+        for (;;) {
+
+            CoderResult cr;
+            try {
+                cr = encodeLoop(in, out);
+            } catch (BufferUnderflowException x) {
+                throw new CoderMalfunctionError(x);
+            } catch (BufferOverflowException x) {
+                throw new CoderMalfunctionError(x);
+            }
+
+            if (cr.isOverflow())
+                return cr;
+
+            if (cr.isUnderflow()) {
+                if (endOfInput && in.hasRemaining()) {
+                    cr = CoderResult.malformedForLength(in.remaining());
+                    // Fall through to malformed-input case
+                } else {
+                    return cr;
+                }
+            }
+
+            CodingErrorAction action = null;
+            if (cr.isMalformed())
+                action = malformedInputAction;
+            else if (cr.isUnmappable())
+                action = unmappableCharacterAction;
+            else
+                assert false : cr.toString();
+
+            if (action == CodingErrorAction.REPORT)
+                return cr;
+
+            if (action == CodingErrorAction.REPLACE) {
+                if (out.remaining() < replacement.length)
+                    return CoderResult.OVERFLOW;
+                out.put(replacement);
+            }
+
+            if ((action == CodingErrorAction.IGNORE)
+                || (action == CodingErrorAction.REPLACE)) {
+                // Skip erroneous input either way
+                in.position(in.position() + cr.length());
+                continue;
+            }
+
+            assert false;
+        }
+
+    }
+
+    /**
+     * Flushes this encoder.
+     *
+     * <p> Some encoders maintain internal state and may need to write some
+     * final bytes to the output buffer once the overall input sequence has
+     * been read.
+     *
+     * <p> Any additional output is written to the output buffer beginning at
+     * its current position.  At most {@link Buffer#remaining out.remaining()}
+     * bytes will be written.  The buffer's position will be advanced
+     * appropriately, but its mark and limit will not be modified.
+     *
+     * <p> If this method completes successfully then it returns {@link
+     * CoderResult#UNDERFLOW}.  If there is insufficient room in the output
+     * buffer then it returns {@link CoderResult#OVERFLOW}.  If this happens
+     * then this method must be invoked again, with an output buffer that has
+     * more room, in order to complete the current <a href="#steps">encoding
+     * operation</a>.
+     *
+     * <p> If this encoder has already been flushed then invoking this method
+     * has no effect.
+     *
+     * <p> This method invokes the {@link #implFlush implFlush} method to
+     * perform the actual flushing operation.  </p>
+     *
+     * @param  out
+     *         The output byte buffer
+     *
+     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
+     *          {@link CoderResult#OVERFLOW}
+     *
+     * @throws  IllegalStateException
+     *          If the previous step of the current encoding operation was an
+     *          invocation neither of the {@link #flush flush} method nor of
+     *          the three-argument {@link
+     *          #encode(CharBuffer,ByteBuffer,boolean) encode} method
+     *          with a value of <tt>true</tt> for the <tt>endOfInput</tt>
+     *          parameter
+     */
+    public final CoderResult flush(ByteBuffer out) {
+        if (state == ST_END) {
+            CoderResult cr = implFlush(out);
+            if (cr.isUnderflow())
+                state = ST_FLUSHED;
+            return cr;
+        }
+
+        if (state != ST_FLUSHED)
+            throwIllegalStateException(state, ST_FLUSHED);
+
+        return CoderResult.UNDERFLOW; // Already flushed
+    }
+
+    /**
+     * Flushes this encoder.
+     *
+     * <p> The default implementation of this method does nothing, and always
+     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
+     * by encoders that may need to write final bytes to the output buffer
+     * once the entire input sequence has been read. </p>
+     *
+     * @param  out
+     *         The output byte buffer
+     *
+     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
+     *          {@link CoderResult#OVERFLOW}
+     */
+    protected CoderResult implFlush(ByteBuffer out) {
+        return CoderResult.UNDERFLOW;
+    }
+
+    /**
+     * Resets this encoder, clearing any internal state.
+     *
+     * <p> This method resets charset-independent state and also invokes the
+     * {@link #implReset() implReset} method in order to perform any
+     * charset-specific reset actions.  </p>
+     *
+     * @return  This encoder
+     *
+     */
+    public final CharsetEncoder reset() {
+        implReset();
+        state = ST_RESET;
+        return this;
+    }
+
+    /**
+     * Resets this encoder, clearing any charset-specific internal state.
+     *
+     * <p> The default implementation of this method does nothing.  This method
+     * should be overridden by encoders that maintain internal state.  </p>
+     */
+    protected void implReset() { }
+
+    /**
+     * Encodes one or more characters into one or more bytes.
+     *
+     * <p> This method encapsulates the basic encoding loop, encoding as many
+     * characters as possible until it either runs out of input, runs out of room
+     * in the output buffer, or encounters an encoding error.  This method is
+     * invoked by the {@link #encode encode} method, which handles result
+     * interpretation and error recovery.
+     *
+     * <p> The buffers are read from, and written to, starting at their current
+     * positions.  At most {@link Buffer#remaining in.remaining()} characters
+     * will be read, and at most {@link Buffer#remaining out.remaining()}
+     * bytes will be written.  The buffers' positions will be advanced to
+     * reflect the characters read and the bytes written, but their marks and
+     * limits will not be modified.
+     *
+     * <p> This method returns a {@link CoderResult} object to describe its
+     * reason for termination, in the same manner as the {@link #encode encode}
+     * method.  Most implementations of this method will handle encoding errors
+     * by returning an appropriate result object for interpretation by the
+     * {@link #encode encode} method.  An optimized implementation may instead
+     * examine the relevant error action and implement that action itself.
+     *
+     * <p> An implementation of this method may perform arbitrary lookahead by
+     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
+     * input.  </p>
+     *
+     * @param  in
+     *         The input character buffer
+     *
+     * @param  out
+     *         The output byte buffer
+     *
+     * @return  A coder-result object describing the reason for termination
+     */
+    protected abstract CoderResult encodeLoop(CharBuffer in,
+                                              ByteBuffer out);
+
+    /**
+     * Convenience method that encodes the remaining content of a single input
+     * character buffer into a newly-allocated byte buffer.
+     *
+     * <p> This method implements an entire <a href="#steps">encoding
+     * operation</a>; that is, it resets this encoder, then it encodes the
+     * characters in the given character buffer, and finally it flushes this
+     * encoder.  This method should therefore not be invoked if an encoding
+     * operation is already in progress.  </p>
+     *
+     * @param  in
+     *         The input character buffer
+     *
+     * @return A newly-allocated byte buffer containing the result of the
+     *         encoding operation.  The buffer's position will be zero and its
+     *         limit will follow the last byte written.
+     *
+     * @throws  IllegalStateException
+     *          If an encoding operation is already in progress
+     *
+     * @throws  MalformedInputException
+     *          If the character sequence starting at the input buffer's current
+     *          position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
+     *          is {@link CodingErrorAction#REPORT}
+     *
+     * @throws  UnmappableCharacterException
+     *          If the character sequence starting at the input buffer's current
+     *          position cannot be mapped to an equivalent byte sequence and
+     *          the current unmappable-character action is {@link
+     *          CodingErrorAction#REPORT}
+     */
+    public final ByteBuffer encode(CharBuffer in)
+        throws CharacterCodingException
+    {
+        int n = (int)(in.remaining() * averageBytesPerChar());
+        ByteBuffer out = ByteBuffer.allocate(n);
+
+        if ((n == 0) && (in.remaining() == 0))
+            return out;
+        reset();
+        for (;;) {
+            CoderResult cr = in.hasRemaining() ?
+                encode(in, out, true) : CoderResult.UNDERFLOW;
+            if (cr.isUnderflow())
+                cr = flush(out);
+
+            if (cr.isUnderflow())
+                break;
+            if (cr.isOverflow()) {
+                n = 2*n + 1;    // Ensure progress; n might be 0!
+                ByteBuffer o = ByteBuffer.allocate(n);
+                out.flip();
+                o.put(out);
+                out = o;
+                continue;
+            }
+            cr.throwException();
+        }
+        out.flip();
+        return out;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    private boolean canEncode(CharBuffer cb) {
+        if (state == ST_FLUSHED)
+            reset();
+        else if (state != ST_RESET)
+            throwIllegalStateException(state, ST_CODING);
+
+        // BEGIN Android-added: Fast path handling for empty buffers.
+        // Empty buffers can always be "encoded".
+        if (!cb.hasRemaining()) {
+            return true;
+        }
+        // END Android-added: Fast path handling for empty buffers.
+
+        CodingErrorAction ma = malformedInputAction();
+        CodingErrorAction ua = unmappableCharacterAction();
+        try {
+            onMalformedInput(CodingErrorAction.REPORT);
+            onUnmappableCharacter(CodingErrorAction.REPORT);
+            encode(cb);
+        } catch (CharacterCodingException x) {
+            return false;
+        } finally {
+            onMalformedInput(ma);
+            onUnmappableCharacter(ua);
+            reset();
+        }
+        return true;
+    }
+
+    /**
+     * Tells whether or not this encoder can encode the given character.
+     *
+     * <p> This method returns <tt>false</tt> if the given character is a
+     * surrogate character; such characters can be interpreted only when they
+     * are members of a pair consisting of a high surrogate followed by a low
+     * surrogate.  The {@link #canEncode(java.lang.CharSequence)
+     * canEncode(CharSequence)} method may be used to test whether or not a
+     * character sequence can be encoded.
+     *
+     * <p> This method may modify this encoder's state; it should therefore not
+     * be invoked if an <a href="#steps">encoding operation</a> is already in
+     * progress.
+     *
+     * <p> The default implementation of this method is not very efficient; it
+     * should generally be overridden to improve performance.  </p>
+     *
+     * @param   c
+     *          The given character
+     *
+     * @return  <tt>true</tt> if, and only if, this encoder can encode
+     *          the given character
+     *
+     * @throws  IllegalStateException
+     *          If an encoding operation is already in progress
+     */
+    public boolean canEncode(char c) {
+        CharBuffer cb = CharBuffer.allocate(1);
+        cb.put(c);
+        cb.flip();
+        return canEncode(cb);
+    }
+
+    /**
+     * Tells whether or not this encoder can encode the given character
+     * sequence.
+     *
+     * <p> If this method returns <tt>false</tt> for a particular character
+     * sequence then more information about why the sequence cannot be encoded
+     * may be obtained by performing a full <a href="#steps">encoding
+     * operation</a>.
+     *
+     * <p> This method may modify this encoder's state; it should therefore not
+     * be invoked if an encoding operation is already in progress.
+     *
+     * <p> The default implementation of this method is not very efficient; it
+     * should generally be overridden to improve performance.  </p>
+     *
+     * @param   cs
+     *          The given character sequence
+     *
+     * @return  <tt>true</tt> if, and only if, this encoder can encode
+     *          the given character without throwing any exceptions and without
+     *          performing any replacements
+     *
+     * @throws  IllegalStateException
+     *          If an encoding operation is already in progress
+     */
+    public boolean canEncode(CharSequence cs) {
+        CharBuffer cb;
+        if (cs instanceof CharBuffer)
+            cb = ((CharBuffer)cs).duplicate();
+        else
+            // Android-removed: An unnecessary call to toString().
+            // cb = CharBuffer.wrap(cs.toString());
+            cb = CharBuffer.wrap(cs);
+        return canEncode(cb);
+    }
+
+
+
+
+    private void throwIllegalStateException(int from, int to) {
+        throw new IllegalStateException("Current state = " + stateNames[from]
+                                        + ", new state = " + stateNames[to]);
+    }
+
+}
diff --git a/java/nio/charset/CoderMalfunctionError.java b/java/nio/charset/CoderMalfunctionError.java
new file mode 100644
index 0000000..aec47e5
--- /dev/null
+++ b/java/nio/charset/CoderMalfunctionError.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset;
+
+
+/**
+ * Error thrown when the {@link CharsetDecoder#decodeLoop decodeLoop} method of
+ * a {@link CharsetDecoder}, or the {@link CharsetEncoder#encodeLoop
+ * encodeLoop} method of a {@link CharsetEncoder}, throws an unexpected
+ * exception.
+ *
+ * @since 1.4
+ */
+
+public class CoderMalfunctionError
+    extends Error
+{
+
+    private static final long serialVersionUID = -1151412348057794301L;
+
+    /**
+     * Initializes an instance of this class.
+     *
+     * @param  cause
+     *         The unexpected exception that was thrown
+     */
+    public CoderMalfunctionError(Exception cause) {
+        super(cause);
+    }
+
+}
diff --git a/java/nio/charset/CoderResult.java b/java/nio/charset/CoderResult.java
new file mode 100644
index 0000000..d087c97
--- /dev/null
+++ b/java/nio/charset/CoderResult.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset;
+
+import java.lang.ref.WeakReference;
+import java.nio.*;
+import java.util.Map;
+import java.util.HashMap;
+
+
+/**
+ * A description of the result state of a coder.
+ *
+ * <p> A charset coder, that is, either a decoder or an encoder, consumes bytes
+ * (or characters) from an input buffer, translates them, and writes the
+ * resulting characters (or bytes) to an output buffer.  A coding process
+ * terminates for one of four categories of reasons, which are described by
+ * instances of this class:
+ *
+ * <ul>
+ *
+ *   <li><p> <i>Underflow</i> is reported when there is no more input to be
+ *   processed, or there is insufficient input and additional input is
+ *   required.  This condition is represented by the unique result object
+ *   {@link #UNDERFLOW}, whose {@link #isUnderflow() isUnderflow} method
+ *   returns <tt>true</tt>.  </p></li>
+ *
+ *   <li><p> <i>Overflow</i> is reported when there is insufficient room
+ *   remaining in the output buffer.  This condition is represented by the
+ *   unique result object {@link #OVERFLOW}, whose {@link #isOverflow()
+ *   isOverflow} method returns <tt>true</tt>.  </p></li>
+ *
+ *   <li><p> A <i>malformed-input error</i> is reported when a sequence of
+ *   input units is not well-formed.  Such errors are described by instances of
+ *   this class whose {@link #isMalformed() isMalformed} method returns
+ *   <tt>true</tt> and whose {@link #length() length} method returns the length
+ *   of the malformed sequence.  There is one unique instance of this class for
+ *   all malformed-input errors of a given length.  </p></li>
+ *
+ *   <li><p> An <i>unmappable-character error</i> is reported when a sequence
+ *   of input units denotes a character that cannot be represented in the
+ *   output charset.  Such errors are described by instances of this class
+ *   whose {@link #isUnmappable() isUnmappable} method returns <tt>true</tt> and
+ *   whose {@link #length() length} method returns the length of the input
+ *   sequence denoting the unmappable character.  There is one unique instance
+ *   of this class for all unmappable-character errors of a given length.
+ *   </p></li>
+ *
+ * </ul>
+ *
+ * <p> For convenience, the {@link #isError() isError} method returns <tt>true</tt>
+ * for result objects that describe malformed-input and unmappable-character
+ * errors but <tt>false</tt> for those that describe underflow or overflow
+ * conditions.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public class CoderResult {
+
+    private static final int CR_UNDERFLOW  = 0;
+    private static final int CR_OVERFLOW   = 1;
+    private static final int CR_ERROR_MIN  = 2;
+    private static final int CR_MALFORMED  = 2;
+    private static final int CR_UNMAPPABLE = 3;
+
+    private static final String[] names
+        = { "UNDERFLOW", "OVERFLOW", "MALFORMED", "UNMAPPABLE" };
+
+    private final int type;
+    private final int length;
+
+    private CoderResult(int type, int length) {
+        this.type = type;
+        this.length = length;
+    }
+
+    /**
+     * Returns a string describing this coder result.
+     *
+     * @return  A descriptive string
+     */
+    public String toString() {
+        String nm = names[type];
+        return isError() ? nm + "[" + length + "]" : nm;
+    }
+
+    /**
+     * Tells whether or not this object describes an underflow condition.
+     *
+     * @return  <tt>true</tt> if, and only if, this object denotes underflow
+     */
+    public boolean isUnderflow() {
+        return (type == CR_UNDERFLOW);
+    }
+
+    /**
+     * Tells whether or not this object describes an overflow condition.
+     *
+     * @return  <tt>true</tt> if, and only if, this object denotes overflow
+     */
+    public boolean isOverflow() {
+        return (type == CR_OVERFLOW);
+    }
+
+    /**
+     * Tells whether or not this object describes an error condition.
+     *
+     * @return  <tt>true</tt> if, and only if, this object denotes either a
+     *          malformed-input error or an unmappable-character error
+     */
+    public boolean isError() {
+        return (type >= CR_ERROR_MIN);
+    }
+
+    /**
+     * Tells whether or not this object describes a malformed-input error.
+     *
+     * @return  <tt>true</tt> if, and only if, this object denotes a
+     *          malformed-input error
+     */
+    public boolean isMalformed() {
+        return (type == CR_MALFORMED);
+    }
+
+    /**
+     * Tells whether or not this object describes an unmappable-character
+     * error.
+     *
+     * @return  <tt>true</tt> if, and only if, this object denotes an
+     *          unmappable-character error
+     */
+    public boolean isUnmappable() {
+        return (type == CR_UNMAPPABLE);
+    }
+
+    /**
+     * Returns the length of the erroneous input described by this
+     * object&nbsp;&nbsp;<i>(optional operation)</i>.
+     *
+     * @return  The length of the erroneous input, a positive integer
+     *
+     * @throws  UnsupportedOperationException
+     *          If this object does not describe an error condition, that is,
+     *          if the {@link #isError() isError} does not return <tt>true</tt>
+     */
+    public int length() {
+        if (!isError())
+            throw new UnsupportedOperationException();
+        return length;
+    }
+
+    /**
+     * Result object indicating underflow, meaning that either the input buffer
+     * has been completely consumed or, if the input buffer is not yet empty,
+     * that additional input is required.
+     */
+    public static final CoderResult UNDERFLOW
+        = new CoderResult(CR_UNDERFLOW, 0);
+
+    /**
+     * Result object indicating overflow, meaning that there is insufficient
+     * room in the output buffer.
+     */
+    public static final CoderResult OVERFLOW
+        = new CoderResult(CR_OVERFLOW, 0);
+
+    private static abstract class Cache {
+
+        private Map<Integer,WeakReference<CoderResult>> cache = null;
+
+        protected abstract CoderResult create(int len);
+
+        private synchronized CoderResult get(int len) {
+            if (len <= 0)
+                throw new IllegalArgumentException("Non-positive length");
+            Integer k = new Integer(len);
+            WeakReference<CoderResult> w;
+            CoderResult e = null;
+            if (cache == null) {
+                cache = new HashMap<Integer,WeakReference<CoderResult>>();
+            } else if ((w = cache.get(k)) != null) {
+                e = w.get();
+            }
+            if (e == null) {
+                e = create(len);
+                cache.put(k, new WeakReference<CoderResult>(e));
+            }
+            return e;
+        }
+
+    }
+
+    private static Cache malformedCache
+        = new Cache() {
+                public CoderResult create(int len) {
+                    return new CoderResult(CR_MALFORMED, len);
+                }};
+
+    /**
+     * Static factory method that returns the unique object describing a
+     * malformed-input error of the given length.
+     *
+     * @param   length
+     *          The given length
+     *
+     * @return  The requested coder-result object
+     */
+    public static CoderResult malformedForLength(int length) {
+        return malformedCache.get(length);
+    }
+
+    private static Cache unmappableCache
+        = new Cache() {
+                public CoderResult create(int len) {
+                    return new CoderResult(CR_UNMAPPABLE, len);
+                }};
+
+    /**
+     * Static factory method that returns the unique result object describing
+     * an unmappable-character error of the given length.
+     *
+     * @param   length
+     *          The given length
+     *
+     * @return  The requested coder-result object
+     */
+    public static CoderResult unmappableForLength(int length) {
+        return unmappableCache.get(length);
+    }
+
+    /**
+     * Throws an exception appropriate to the result described by this object.
+     *
+     * @throws  BufferUnderflowException
+     *          If this object is {@link #UNDERFLOW}
+     *
+     * @throws  BufferOverflowException
+     *          If this object is {@link #OVERFLOW}
+     *
+     * @throws  MalformedInputException
+     *          If this object represents a malformed-input error; the
+     *          exception's length value will be that of this object
+     *
+     * @throws  UnmappableCharacterException
+     *          If this object represents an unmappable-character error; the
+     *          exceptions length value will be that of this object
+     */
+    public void throwException()
+        throws CharacterCodingException
+    {
+        switch (type) {
+        case CR_UNDERFLOW:   throw new BufferUnderflowException();
+        case CR_OVERFLOW:    throw new BufferOverflowException();
+        case CR_MALFORMED:   throw new MalformedInputException(length);
+        case CR_UNMAPPABLE:  throw new UnmappableCharacterException(length);
+        default:
+            assert false;
+        }
+    }
+
+}
diff --git a/java/nio/charset/CodingErrorAction.java b/java/nio/charset/CodingErrorAction.java
new file mode 100644
index 0000000..c708e63
--- /dev/null
+++ b/java/nio/charset/CodingErrorAction.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset;
+
+
+/**
+ * A typesafe enumeration for coding-error actions.
+ *
+ * <p> Instances of this class are used to specify how malformed-input and
+ * unmappable-character errors are to be handled by charset <a
+ * href="CharsetDecoder.html#cae">decoders</a> and <a
+ * href="CharsetEncoder.html#cae">encoders</a>.  </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ */
+
+public class CodingErrorAction {
+
+    private String name;
+
+    private CodingErrorAction(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Action indicating that a coding error is to be handled by dropping the
+     * erroneous input and resuming the coding operation.
+     */
+    public static final CodingErrorAction IGNORE
+        = new CodingErrorAction("IGNORE");
+
+    /**
+     * Action indicating that a coding error is to be handled by dropping the
+     * erroneous input, appending the coder's replacement value to the output
+     * buffer, and resuming the coding operation.
+     */
+    public static final CodingErrorAction REPLACE
+        = new CodingErrorAction("REPLACE");
+
+    /**
+     * Action indicating that a coding error is to be reported, either by
+     * returning a {@link CoderResult} object or by throwing a {@link
+     * CharacterCodingException}, whichever is appropriate for the method
+     * implementing the coding process.
+     */
+    public static final CodingErrorAction REPORT
+        = new CodingErrorAction("REPORT");
+
+    /**
+     * Returns a string describing this action.
+     *
+     * @return  A descriptive string
+     */
+    public String toString() {
+        return name;
+    }
+
+}
diff --git a/java/nio/charset/IllegalCharsetNameException.java b/java/nio/charset/IllegalCharsetNameException.java
new file mode 100644
index 0000000..9124282
--- /dev/null
+++ b/java/nio/charset/IllegalCharsetNameException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.charset;
+
+
+/**
+ * Unchecked exception thrown when a string that is not a
+ * <a href=Charset.html#names>legal charset name</a> is used as such.
+ *
+ * @since 1.4
+ */
+
+public class IllegalCharsetNameException
+    extends IllegalArgumentException
+{
+
+    private static final long serialVersionUID = 1457525358470002989L;
+
+    private String charsetName;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param  charsetName
+     *         The illegal charset name
+     */
+    public IllegalCharsetNameException(String charsetName) {
+        super(String.valueOf(charsetName));
+	this.charsetName = charsetName;
+    }
+
+    /**
+     * Retrieves the illegal charset name.
+     *
+     * @return  The illegal charset name
+     */
+    public String getCharsetName() {
+        return charsetName;
+    }
+
+}
diff --git a/java/nio/charset/MalformedInputException.java b/java/nio/charset/MalformedInputException.java
new file mode 100644
index 0000000..aadbadc
--- /dev/null
+++ b/java/nio/charset/MalformedInputException.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset;
+
+
+/**
+ * Checked exception thrown when an input byte sequence is not legal for given
+ * charset, or an input character sequence is not a legal sixteen-bit Unicode
+ * sequence.
+ *
+ * @since 1.4
+ */
+
+public class MalformedInputException
+    extends CharacterCodingException
+{
+
+    private static final long serialVersionUID = -3438823399834806194L;
+
+    private int inputLength;
+
+    /**
+     * Constructs an {@code MalformedInputException} with the given
+     * length.
+     * @param inputLength the length of the input
+     */
+    public MalformedInputException(int inputLength) {
+        this.inputLength = inputLength;
+    }
+
+    /**
+     * Returns the length of the input.
+     * @return the length of the input
+     */
+    public int getInputLength() {
+        return inputLength;
+    }
+
+    /**
+     * Returns the message.
+     * @return the message
+     */
+    public String getMessage() {
+        return "Input length = " + inputLength;
+    }
+
+}
diff --git a/java/nio/charset/StandardCharsets.java b/java/nio/charset/StandardCharsets.java
new file mode 100644
index 0000000..b2572c3
--- /dev/null
+++ b/java/nio/charset/StandardCharsets.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.nio.charset;
+
+/**
+ * Constant definitions for the standard {@link Charset Charsets}. These
+ * charsets are guaranteed to be available on every implementation of the Java
+ * platform.
+ *
+ * @see <a href="Charset#standard">Standard Charsets</a>
+ * @since 1.7
+ */
+public final class StandardCharsets {
+
+    private StandardCharsets() {
+        throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
+    }
+    /**
+     * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
+     * Unicode character set
+     */
+    public static final Charset US_ASCII = Charset.forName("US-ASCII");
+    /**
+     * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
+     */
+    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+    /**
+     * Eight-bit UCS Transformation Format
+     */
+    public static final Charset UTF_8 = Charset.forName("UTF-8");
+    /**
+     * Sixteen-bit UCS Transformation Format, big-endian byte order
+     */
+    public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
+    /**
+     * Sixteen-bit UCS Transformation Format, little-endian byte order
+     */
+    public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
+    /**
+     * Sixteen-bit UCS Transformation Format, byte order identified by an
+     * optional byte-order mark
+     */
+    public static final Charset UTF_16 = Charset.forName("UTF-16");
+}
diff --git a/java/nio/charset/UnmappableCharacterException.java b/java/nio/charset/UnmappableCharacterException.java
new file mode 100644
index 0000000..c33f040
--- /dev/null
+++ b/java/nio/charset/UnmappableCharacterException.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset;
+
+
+/**
+ * Checked exception thrown when an input character (or byte) sequence
+ * is valid but cannot be mapped to an output byte (or character)
+ * sequence.
+ *
+ * @since 1.4
+ */
+
+public class UnmappableCharacterException
+    extends CharacterCodingException
+{
+
+    private static final long serialVersionUID = -7026962371537706123L;
+
+    private int inputLength;
+
+    /**
+     * Constructs an {@code UnmappableCharacterException} with the
+     * given length.
+     * @param inputLength the length of the input
+     */
+    public UnmappableCharacterException(int inputLength) {
+        this.inputLength = inputLength;
+    }
+
+    /**
+     * Returns the length of the input.
+     * @return the length of the input
+     */
+    public int getInputLength() {
+        return inputLength;
+    }
+
+    /**
+     * Returns the message.
+     * @return the message
+     */
+    public String getMessage() {
+        return "Input length = " + inputLength;
+    }
+
+}
diff --git a/java/nio/charset/UnsupportedCharsetException.java b/java/nio/charset/UnsupportedCharsetException.java
new file mode 100644
index 0000000..1774fc0
--- /dev/null
+++ b/java/nio/charset/UnsupportedCharsetException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.charset;
+
+
+/**
+ * Unchecked exception thrown when no support is available
+ * for a requested charset.
+ *
+ * @since 1.4
+ */
+
+public class UnsupportedCharsetException
+    extends IllegalArgumentException
+{
+
+    private static final long serialVersionUID = 1490765524727386367L;
+
+    private String charsetName;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param  charsetName
+     *         The name of the unsupported charset
+     */
+    public UnsupportedCharsetException(String charsetName) {
+        super(String.valueOf(charsetName));
+	this.charsetName = charsetName;
+    }
+
+    /**
+     * Retrieves the name of the unsupported charset.
+     *
+     * @return  The name of the unsupported charset
+     */
+    public String getCharsetName() {
+        return charsetName;
+    }
+
+}
diff --git a/java/nio/charset/package-info.java b/java/nio/charset/package-info.java
new file mode 100644
index 0000000..1fc81e0
--- /dev/null
+++ b/java/nio/charset/package-info.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines charsets, decoders, and encoders, for translating between bytes and
+ * Unicode characters.
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Summary of charsets, decoders, and encoders in this package">
+ *  <tr><th><p align="left">Class name</p></th><th><p align="left">Description</p></th></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.charset.Charset}</tt></td>
+ *       <td>A named mapping between characters<br>and bytes</td></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.charset.CharsetDecoder}</tt></td>
+ *       <td>Decodes bytes into characters</td></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.charset.CharsetEncoder}&nbsp;&nbsp;</tt></td>
+ *       <td>Encodes characters into bytes</td></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.charset.CoderResult}&nbsp;&nbsp;</tt></td>
+ *       <td>Describes coder results</td></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.charset.CodingErrorAction}&nbsp;&nbsp;</tt></td>
+ *       <td>Describes actions to take when<br>coding errors are detected</td></tr>
+ *
+ * </table></blockquote>
+ *
+ * <p> A <i>charset</i> is named mapping between sequences of sixteen-bit Unicode
+ * characters and sequences of bytes, in the sense defined in <a
+ * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278</i></a>.  A
+ * <i>decoder</i> is an engine which transforms bytes in a specific charset into
+ * characters, and an <i>encoder</i> is an engine which transforms characters into
+ * bytes.  Encoders and decoders operate on byte and character buffers.  They are
+ * collectively referred to as <i>coders</i>.
+ *
+ * <p> The {@link java.nio.charset.Charset} class defines methods for creating
+ * coders for a given charset and for retrieving the various names associated with
+ * a charset.  It also defines static methods for testing whether a particular
+ * charset is supported, for locating charset instances by name, and for
+ * constructing a map that contains every charset for which support is available
+ * in the current Java virtual machine.
+ *
+ * <p> Most users will not use these classes directly; instead they will use the
+ * existing charset-related constructors and methods in the {@link
+ * java.lang.String} class, together with the existing {@link
+ * java.io.InputStreamReader} and {@link java.io.OutputStreamWriter} classes, all
+ * of whose implementations have been reworked to make use of the charset
+ * facilities defined in this package.  A small number of changes have been made
+ * to the {@link java.io.InputStreamReader} and {@link java.io.OutputStreamWriter}
+ * classes in order to allow explicit charset objects to be specified in the
+ * construction of instances of those classes.
+ *
+ * <p> Support for new charsets can be made available via the interface defined in
+ * the {@link java.nio.charset.spi.CharsetProvider} class in the <tt>{@link
+ * java.nio.charset.spi}</tt> package.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ *
+ * @since 1.4
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ */
+
+package java.nio.charset;
diff --git a/java/nio/charset/spi/CharsetProvider.java b/java/nio/charset/spi/CharsetProvider.java
new file mode 100644
index 0000000..f7821e7
--- /dev/null
+++ b/java/nio/charset/spi/CharsetProvider.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.charset.spi;
+
+import java.nio.charset.Charset;
+import java.util.Iterator;
+
+
+/**
+ * Charset service-provider class.
+ *
+ * <p> A charset provider is a concrete subclass of this class that has a
+ * zero-argument constructor and some number of associated charset
+ * implementation classes.  Charset providers may be installed in an instance
+ * of the Java platform as extensions, that is, jar files placed into any of
+ * the usual extension directories.  Providers may also be made available by
+ * adding them to the applet or application class path or by some other
+ * platform-specific means.  Charset providers are looked up via the current
+ * thread's {@link java.lang.Thread#getContextClassLoader() context class
+ * loader}.
+ *
+ * <p> A charset provider identifies itself with a provider-configuration file
+ * named <tt>java.nio.charset.spi.CharsetProvider</tt> in the resource
+ * directory <tt>META-INF/services</tt>.  The file should contain a list of
+ * fully-qualified concrete charset-provider class names, one per line.  A line
+ * is terminated by any one of a line feed (<tt>'\n'</tt>), a carriage return
+ * (<tt>'\r'</tt>), or a carriage return followed immediately by a line feed.
+ * Space and tab characters surrounding each name, as well as blank lines, are
+ * ignored.  The comment character is <tt>'#'</tt> (<tt>'&#92;u0023'</tt>); on
+ * each line all characters following the first comment character are ignored.
+ * The file must be encoded in UTF-8.
+ *
+ * <p> If a particular concrete charset provider class is named in more than
+ * one configuration file, or is named in the same configuration file more than
+ * once, then the duplicates will be ignored.  The configuration file naming a
+ * particular provider need not be in the same jar file or other distribution
+ * unit as the provider itself.  The provider must be accessible from the same
+ * class loader that was initially queried to locate the configuration file;
+ * this is not necessarily the class loader that loaded the file. </p>
+ *
+ *
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ * @since 1.4
+ *
+ * @see java.nio.charset.Charset
+ */
+
+public abstract class CharsetProvider {
+
+    /**
+     * Initializes a new charset provider.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("charsetProvider")</tt>
+     */
+    protected CharsetProvider() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("charsetProvider"));
+    }
+
+    /**
+     * Creates an iterator that iterates over the charsets supported by this
+     * provider.  This method is used in the implementation of the {@link
+     * java.nio.charset.Charset#availableCharsets Charset.availableCharsets}
+     * method.
+     *
+     * @return  The new iterator
+     */
+    public abstract Iterator<Charset> charsets();
+
+    /**
+     * Retrieves a charset for the given charset name.
+     *
+     * @param  charsetName
+     *         The name of the requested charset; may be either
+     *         a canonical name or an alias
+     *
+     * @return  A charset object for the named charset,
+     *          or <tt>null</tt> if the named charset
+     *          is not supported by this provider
+     */
+    public abstract Charset charsetForName(String charsetName);
+
+}
diff --git a/java/nio/file/AccessDeniedException.java b/java/nio/file/AccessDeniedException.java
new file mode 100644
index 0000000..43b3862
--- /dev/null
+++ b/java/nio/file/AccessDeniedException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation is denied, typically
+ * due to a file permission or other access check.
+ *
+ * <p> This exception is not related to the {@link
+ * java.security.AccessControlException AccessControlException} or {@link
+ * SecurityException} thrown by access controllers or security managers when
+ * access to a file is denied.
+ *
+ * @since 1.7
+ */
+
+public class AccessDeniedException
+    extends FileSystemException
+{
+    private static final long serialVersionUID = 4943049599949219617L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     */
+    public AccessDeniedException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     * @param   other
+     *          a string identifying the other file or {@code null} if not known
+     * @param   reason
+     *          a reason message with additional information or {@code null}
+     */
+    public AccessDeniedException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
diff --git a/java/nio/file/AccessMode.java b/java/nio/file/AccessMode.java
new file mode 100644
index 0000000..8816e9b
--- /dev/null
+++ b/java/nio/file/AccessMode.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines access modes used to test the accessibility of a file.
+ *
+ * @since 1.7
+ */
+
+public enum AccessMode {
+    /**
+     * Test read access.
+     */
+    READ,
+    /**
+     * Test write access.
+     */
+    WRITE,
+    /**
+     * Test execute access.
+     */
+    EXECUTE;
+}
diff --git a/java/nio/file/AtomicMoveNotSupportedException.java b/java/nio/file/AtomicMoveNotSupportedException.java
new file mode 100644
index 0000000..27947c3
--- /dev/null
+++ b/java/nio/file/AtomicMoveNotSupportedException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file cannot be moved as an atomic file system
+ * operation.
+ *
+ * @since 1.7
+ */
+
+public class AtomicMoveNotSupportedException
+    extends FileSystemException
+{
+    static final long serialVersionUID = 5402760225333135579L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   source
+     *          a string identifying the source file or {@code null} if not known
+     * @param   target
+     *          a string identifying the target file or {@code null} if not known
+     * @param   reason
+     *          a reason message with additional information
+     */
+    public AtomicMoveNotSupportedException(String source,
+                                           String target,
+                                           String reason)
+    {
+        super(source, target, reason);
+    }
+}
diff --git a/java/nio/file/ClosedDirectoryStreamException.java b/java/nio/file/ClosedDirectoryStreamException.java
new file mode 100644
index 0000000..aa1e0ce
--- /dev/null
+++ b/java/nio/file/ClosedDirectoryStreamException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an operation on
+ * a directory stream that is closed.
+ *
+ * @since 1.7
+ */
+
+public class ClosedDirectoryStreamException
+    extends IllegalStateException
+{
+    static final long serialVersionUID = 4228386650900895400L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedDirectoryStreamException() {
+    }
+}
diff --git a/java/nio/file/ClosedFileSystemException.java b/java/nio/file/ClosedFileSystemException.java
new file mode 100644
index 0000000..82cf096
--- /dev/null
+++ b/java/nio/file/ClosedFileSystemException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an operation on
+ * a file and the file system is closed.
+ */
+
+public class ClosedFileSystemException
+    extends IllegalStateException
+{
+    static final long serialVersionUID = -8158336077256193488L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedFileSystemException() {
+    }
+}
diff --git a/java/nio/file/ClosedWatchServiceException.java b/java/nio/file/ClosedWatchServiceException.java
new file mode 100644
index 0000000..3995b6d
--- /dev/null
+++ b/java/nio/file/ClosedWatchServiceException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke an operation on
+ * a watch service that is closed.
+ */
+
+public class ClosedWatchServiceException
+    extends IllegalStateException
+{
+    static final long serialVersionUID = 1853336266231677732L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ClosedWatchServiceException() {
+    }
+}
diff --git a/java/nio/file/CopyMoveHelper.java b/java/nio/file/CopyMoveHelper.java
new file mode 100644
index 0000000..ab92818
--- /dev/null
+++ b/java/nio/file/CopyMoveHelper.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Helper class to support copying or moving files when the source and target
+ * are associated with different providers.
+ */
+
+class CopyMoveHelper {
+    private CopyMoveHelper() { }
+
+    /**
+     * Parses the arguments for a file copy operation.
+     */
+    private static class CopyOptions {
+        boolean replaceExisting = false;
+        boolean copyAttributes = false;
+        boolean followLinks = true;
+
+        private CopyOptions() { }
+
+        static CopyOptions parse(CopyOption... options) {
+            CopyOptions result = new CopyOptions();
+            for (CopyOption option: options) {
+                if (option == StandardCopyOption.REPLACE_EXISTING) {
+                    result.replaceExisting = true;
+                    continue;
+                }
+                if (option == LinkOption.NOFOLLOW_LINKS) {
+                    result.followLinks = false;
+                    continue;
+                }
+                if (option == StandardCopyOption.COPY_ATTRIBUTES) {
+                    result.copyAttributes = true;
+                    continue;
+                }
+                if (option == null)
+                    throw new NullPointerException();
+                throw new UnsupportedOperationException("'" + option +
+                    "' is not a recognized copy option");
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Converts the given array of options for moving a file to options suitable
+     * for copying the file when a move is implemented as copy + delete.
+     */
+    private static CopyOption[] convertMoveToCopyOptions(CopyOption... options)
+        throws AtomicMoveNotSupportedException
+    {
+        int len = options.length;
+        CopyOption[] newOptions = new CopyOption[len+2];
+        for (int i=0; i<len; i++) {
+            CopyOption option = options[i];
+            if (option == StandardCopyOption.ATOMIC_MOVE) {
+                throw new AtomicMoveNotSupportedException(null, null,
+                    "Atomic move between providers is not supported");
+            }
+            newOptions[i] = option;
+        }
+        newOptions[len] = LinkOption.NOFOLLOW_LINKS;
+        newOptions[len+1] = StandardCopyOption.COPY_ATTRIBUTES;
+        return newOptions;
+    }
+
+    /**
+     * Simple copy for use when source and target are associated with different
+     * providers
+     */
+    static void copyToForeignTarget(Path source, Path target,
+                                    CopyOption... options)
+        throws IOException
+    {
+        CopyOptions opts = CopyOptions.parse(options);
+        LinkOption[] linkOptions = (opts.followLinks) ? new LinkOption[0] :
+            new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+
+        // attributes of source file
+        BasicFileAttributes attrs = Files.readAttributes(source,
+                                                         BasicFileAttributes.class,
+                                                         linkOptions);
+        if (attrs.isSymbolicLink())
+            throw new IOException("Copying of symbolic links not supported");
+
+        // delete target if it exists and REPLACE_EXISTING is specified
+        if (opts.replaceExisting) {
+            Files.deleteIfExists(target);
+        } else if (Files.exists(target))
+            throw new FileAlreadyExistsException(target.toString());
+
+        // create directory or copy file
+        if (attrs.isDirectory()) {
+            Files.createDirectory(target);
+        } else {
+            try (InputStream in = Files.newInputStream(source)) {
+                Files.copy(in, target);
+            }
+        }
+
+        // copy basic attributes to target
+        if (opts.copyAttributes) {
+            BasicFileAttributeView view =
+                Files.getFileAttributeView(target, BasicFileAttributeView.class);
+            try {
+                view.setTimes(attrs.lastModifiedTime(),
+                              attrs.lastAccessTime(),
+                              attrs.creationTime());
+            } catch (Throwable x) {
+                // rollback
+                try {
+                    Files.delete(target);
+                } catch (Throwable suppressed) {
+                    x.addSuppressed(suppressed);
+                }
+                throw x;
+            }
+        }
+    }
+
+    /**
+     * Simple move implements as copy+delete for use when source and target are
+     * associated with different providers
+     */
+    static void moveToForeignTarget(Path source, Path target,
+                                    CopyOption... options) throws IOException
+    {
+        copyToForeignTarget(source, target, convertMoveToCopyOptions(options));
+        Files.delete(source);
+    }
+}
diff --git a/java/nio/file/CopyOption.java b/java/nio/file/CopyOption.java
new file mode 100644
index 0000000..e70bf95
--- /dev/null
+++ b/java/nio/file/CopyOption.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An object that configures how to copy or move a file.
+ *
+ * <p> Objects of this type may be used with the {@link
+ * Files#copy(Path,Path,CopyOption[]) Files.copy(Path,Path,CopyOption...)},
+ * {@link Files#copy(java.io.InputStream,Path,CopyOption[])
+ * Files.copy(InputStream,Path,CopyOption...)} and {@link Files#move
+ * Files.move(Path,Path,CopyOption...)} methods to configure how a file is
+ * copied or moved.
+ *
+ * <p> The {@link StandardCopyOption} enumeration type defines the
+ * <i>standard</i> options.
+ *
+ * @since 1.7
+ */
+
+public interface CopyOption {
+}
diff --git a/java/nio/file/DirectoryIteratorException.java b/java/nio/file/DirectoryIteratorException.java
new file mode 100644
index 0000000..4f5a551
--- /dev/null
+++ b/java/nio/file/DirectoryIteratorException.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.util.ConcurrentModificationException;
+import java.util.Objects;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.InvalidObjectException;
+
+/**
+ * Runtime exception thrown if an I/O error is encountered when iterating over
+ * the entries in a directory. The I/O error is retrieved as an {@link
+ * IOException} using the {@link #getCause() getCause()} method.
+ *
+ * @since 1.7
+ * @see DirectoryStream
+ */
+
+public final class DirectoryIteratorException
+    extends ConcurrentModificationException
+{
+    private static final long serialVersionUID = -6012699886086212874L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   cause
+     *          the {@code IOException} that caused the directory iteration
+     *          to fail
+     *
+     * @throws  NullPointerException
+     *          if the cause is {@code null}
+     */
+    public DirectoryIteratorException(IOException cause) {
+        super(Objects.requireNonNull(cause));
+    }
+
+    /**
+     * Returns the cause of this exception.
+     *
+     * @return  the cause
+     */
+    @Override
+    public IOException getCause() {
+        return (IOException)super.getCause();
+    }
+
+    /**
+     * Called to read the object from a stream.
+     *
+     * @throws  InvalidObjectException
+     *          if the object is invalid or has a cause that is not
+     *          an {@code IOException}
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException
+    {
+        s.defaultReadObject();
+        Throwable cause = super.getCause();
+        if (!(cause instanceof IOException))
+            throw new InvalidObjectException("Cause must be an IOException");
+    }
+}
diff --git a/java/nio/file/DirectoryNotEmptyException.java b/java/nio/file/DirectoryNotEmptyException.java
new file mode 100644
index 0000000..7ae9080
--- /dev/null
+++ b/java/nio/file/DirectoryNotEmptyException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation fails because a
+ * directory is not empty.
+ *
+ * @since 1.7
+ */
+
+public class DirectoryNotEmptyException
+    extends FileSystemException
+{
+    static final long serialVersionUID = 3056667871802779003L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   dir
+     *          a string identifying the directory or {@code null} if not known
+     */
+    public DirectoryNotEmptyException(String dir) {
+        super(dir);
+    }
+}
diff --git a/java/nio/file/DirectoryStream.java b/java/nio/file/DirectoryStream.java
new file mode 100644
index 0000000..48da97e
--- /dev/null
+++ b/java/nio/file/DirectoryStream.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.util.Iterator;
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * An object to iterate over the entries in a directory. A directory stream
+ * allows for the convenient use of the for-each construct to iterate over a
+ * directory.
+ *
+ * <p> <b> While {@code DirectoryStream} extends {@code Iterable}, it is not a
+ * general-purpose {@code Iterable} as it supports only a single {@code
+ * Iterator}; invoking the {@link #iterator iterator} method to obtain a second
+ * or subsequent iterator throws {@code IllegalStateException}. </b>
+ *
+ * <p> An important property of the directory stream's {@code Iterator} is that
+ * its {@link Iterator#hasNext() hasNext} method is guaranteed to read-ahead by
+ * at least one element. If {@code hasNext} method returns {@code true}, and is
+ * followed by a call to the {@code next} method, it is guaranteed that the
+ * {@code next} method will not throw an exception due to an I/O error, or
+ * because the stream has been {@link #close closed}. The {@code Iterator} does
+ * not support the {@link Iterator#remove remove} operation.
+ *
+ * <p> A {@code DirectoryStream} is opened upon creation and is closed by
+ * invoking the {@code close} method. Closing a directory stream releases any
+ * resources associated with the stream. Failure to close the stream may result
+ * in a resource leak. The try-with-resources statement provides a useful
+ * construct to ensure that the stream is closed:
+ * <pre>
+ *   Path dir = ...
+ *   try (DirectoryStream&lt;Path&gt; stream = Files.newDirectoryStream(dir)) {
+ *       for (Path entry: stream) {
+ *           ...
+ *       }
+ *   }
+ * </pre>
+ *
+ * <p> Once a directory stream is closed, then further access to the directory,
+ * using the {@code Iterator}, behaves as if the end of stream has been reached.
+ * Due to read-ahead, the {@code Iterator} may return one or more elements
+ * after the directory stream has been closed. Once these buffered elements
+ * have been read, then subsequent calls to the {@code hasNext} method returns
+ * {@code false}, and subsequent calls to the {@code next} method will throw
+ * {@code NoSuchElementException}.
+ *
+ * <p> A directory stream is not required to be <i>asynchronously closeable</i>.
+ * If a thread is blocked on the directory stream's iterator reading from the
+ * directory, and another thread invokes the {@code close} method, then the
+ * second thread may block until the read operation is complete.
+ *
+ * <p> If an I/O error is encountered when accessing the directory then it
+ * causes the {@code Iterator}'s {@code hasNext} or {@code next} methods to
+ * throw {@link DirectoryIteratorException} with the {@link IOException} as the
+ * cause. As stated above, the {@code hasNext} method is guaranteed to
+ * read-ahead by at least one element. This means that if {@code hasNext} method
+ * returns {@code true}, and is followed by a call to the {@code next} method,
+ * then it is guaranteed that the {@code next} method will not fail with a
+ * {@code DirectoryIteratorException}.
+ *
+ * <p> The elements returned by the iterator are in no specific order. Some file
+ * systems maintain special links to the directory itself and the directory's
+ * parent directory. Entries representing these links are not returned by the
+ * iterator.
+ *
+ * <p> The iterator is <i>weakly consistent</i>. It is thread safe but does not
+ * freeze the directory while iterating, so it may (or may not) reflect updates
+ * to the directory that occur after the {@code DirectoryStream} is created.
+ *
+ * <p> <b>Usage Examples:</b>
+ * Suppose we want a list of the source files in a directory. This example uses
+ * both the for-each and try-with-resources constructs.
+ * <pre>
+ *   List&lt;Path&gt; listSourceFiles(Path dir) throws IOException {
+ *       List&lt;Path&gt; result = new ArrayList&lt;&gt;();
+ *       try (DirectoryStream&lt;Path&gt; stream = Files.newDirectoryStream(dir, "*.{c,h,cpp,hpp,java}")) {
+ *           for (Path entry: stream) {
+ *               result.add(entry);
+ *           }
+ *       } catch (DirectoryIteratorException ex) {
+ *           // I/O error encounted during the iteration, the cause is an IOException
+ *           throw ex.getCause();
+ *       }
+ *       return result;
+ *   }
+ * </pre>
+ * @param   <T>     The type of element returned by the iterator
+ *
+ * @since 1.7
+ *
+ * @see Files#newDirectoryStream(Path)
+ */
+
+public interface DirectoryStream<T>
+    extends Closeable, Iterable<T> {
+    /**
+     * An interface that is implemented by objects that decide if a directory
+     * entry should be accepted or filtered. A {@code Filter} is passed as the
+     * parameter to the {@link Files#newDirectoryStream(Path,DirectoryStream.Filter)}
+     * method when opening a directory to iterate over the entries in the
+     * directory.
+     *
+     * @param   <T>     the type of the directory entry
+     *
+     * @since 1.7
+     */
+    @FunctionalInterface
+    public static interface Filter<T> {
+        /**
+         * Decides if the given directory entry should be accepted or filtered.
+         *
+         * @param   entry
+         *          the directory entry to be tested
+         *
+         * @return  {@code true} if the directory entry should be accepted
+         *
+         * @throws  IOException
+         *          If an I/O error occurs
+         */
+        boolean accept(T entry) throws IOException;
+    }
+
+    /**
+     * Returns the iterator associated with this {@code DirectoryStream}.
+     *
+     * @return  the iterator associated with this {@code DirectoryStream}
+     *
+     * @throws  IllegalStateException
+     *          if this directory stream is closed or the iterator has already
+     *          been returned
+     */
+    @Override
+    Iterator<T> iterator();
+}
diff --git a/java/nio/file/FileAlreadyExistsException.java b/java/nio/file/FileAlreadyExistsException.java
new file mode 100644
index 0000000..14496a1
--- /dev/null
+++ b/java/nio/file/FileAlreadyExistsException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when an attempt is made to create a file or
+ * directory and a file of that name already exists.
+ *
+ * @since 1.7
+ */
+
+public class FileAlreadyExistsException
+    extends FileSystemException
+{
+    static final long serialVersionUID = 7579540934498831181L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     */
+    public FileAlreadyExistsException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     * @param   other
+     *          a string identifying the other file or {@code null} if not known
+     * @param   reason
+     *          a reason message with additional information or {@code null}
+     */
+    public FileAlreadyExistsException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
diff --git a/java/nio/file/FileStore.java b/java/nio/file/FileStore.java
new file mode 100644
index 0000000..2b14a4b
--- /dev/null
+++ b/java/nio/file/FileStore.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+/**
+ * Storage for files. A {@code FileStore} represents a storage pool, device,
+ * partition, volume, concrete file system or other implementation specific means
+ * of file storage. The {@code FileStore} for where a file is stored is obtained
+ * by invoking the {@link Files#getFileStore getFileStore} method, or all file
+ * stores can be enumerated by invoking the {@link FileSystem#getFileStores
+ * getFileStores} method.
+ *
+ * <p> In addition to the methods defined by this class, a file store may support
+ * one or more {@link FileStoreAttributeView FileStoreAttributeView} classes
+ * that provide a read-only or updatable view of a set of file store attributes.
+ *
+ * @since 1.7
+ */
+
+public abstract class FileStore {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected FileStore() {
+    }
+
+    /**
+     * Returns the name of this file store. The format of the name is highly
+     * implementation specific. It will typically be the name of the storage
+     * pool or volume.
+     *
+     * <p> The string returned by this method may differ from the string
+     * returned by the {@link Object#toString() toString} method.
+     *
+     * @return  the name of this file store
+     */
+    public abstract String name();
+
+    /**
+     * Returns the <em>type</em> of this file store. The format of the string
+     * returned by this method is highly implementation specific. It may
+     * indicate, for example, the format used or if the file store is local
+     * or remote.
+     *
+     * @return  a string representing the type of this file store
+     */
+    public abstract String type();
+
+    /**
+     * Tells whether this file store is read-only. A file store is read-only if
+     * it does not support write operations or other changes to files. Any
+     * attempt to create a file, open an existing file for writing etc. causes
+     * an {@code IOException} to be thrown.
+     *
+     * @return  {@code true} if, and only if, this file store is read-only
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Returns the size, in bytes, of the file store.
+     *
+     * @return  the size of the file store, in bytes
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    public abstract long getTotalSpace() throws IOException;
+
+    /**
+     * Returns the number of bytes available to this Java virtual machine on the
+     * file store.
+     *
+     * <p> The returned number of available bytes is a hint, but not a
+     * guarantee, that it is possible to use most or any of these bytes.  The
+     * number of usable bytes is most likely to be accurate immediately
+     * after the space attributes are obtained. It is likely to be made inaccurate
+     * by any external I/O operations including those made on the system outside
+     * of this Java virtual machine.
+     *
+     * @return  the number of bytes available
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    public abstract long getUsableSpace() throws IOException;
+
+    /**
+     * Returns the number of unallocated bytes in the file store.
+     *
+     * <p> The returned number of unallocated bytes is a hint, but not a
+     * guarantee, that it is possible to use most or any of these bytes.  The
+     * number of unallocated bytes is most likely to be accurate immediately
+     * after the space attributes are obtained. It is likely to be
+     * made inaccurate by any external I/O operations including those made on
+     * the system outside of this virtual machine.
+     *
+     * @return  the number of unallocated bytes
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    public abstract long getUnallocatedSpace() throws IOException;
+
+    /**
+     * Tells whether or not this file store supports the file attributes
+     * identified by the given file attribute view.
+     *
+     * <p> Invoking this method to test if the file store supports {@link
+     * BasicFileAttributeView} will always return {@code true}. In the case of
+     * the default provider, this method cannot guarantee to give the correct
+     * result when the file store is not a local storage device. The reasons for
+     * this are implementation specific and therefore unspecified.
+     *
+     * @param   type
+     *          the file attribute view type
+     *
+     * @return  {@code true} if, and only if, the file attribute view is
+     *          supported
+     */
+    public abstract boolean supportsFileAttributeView(Class<? extends FileAttributeView> type);
+
+    /**
+     * Tells whether or not this file store supports the file attributes
+     * identified by the given file attribute view.
+     *
+     * <p> Invoking this method to test if the file store supports {@link
+     * BasicFileAttributeView}, identified by the name "{@code basic}" will
+     * always return {@code true}. In the case of the default provider, this
+     * method cannot guarantee to give the correct result when the file store is
+     * not a local storage device. The reasons for this are implementation
+     * specific and therefore unspecified.
+     *
+     * @param   name
+     *          the {@link FileAttributeView#name name} of file attribute view
+     *
+     * @return  {@code true} if, and only if, the file attribute view is
+     *          supported
+     */
+    public abstract boolean supportsFileAttributeView(String name);
+
+    /**
+     * Returns a {@code FileStoreAttributeView} of the given type.
+     *
+     * <p> This method is intended to be used where the file store attribute
+     * view defines type-safe methods to read or update the file store attributes.
+     * The {@code type} parameter is the type of the attribute view required and
+     * the method returns an instance of that type if supported.
+     *
+     * @param   <V>
+     *          The {@code FileStoreAttributeView} type
+     * @param   type
+     *          the {@code Class} object corresponding to the attribute view
+     *
+     * @return  a file store attribute view of the specified type or
+     *          {@code null} if the attribute view is not available
+     */
+    public abstract <V extends FileStoreAttributeView> V
+        getFileStoreAttributeView(Class<V> type);
+
+    /**
+     * Reads the value of a file store attribute.
+     *
+     * <p> The {@code attribute} parameter identifies the attribute to be read
+     * and takes the form:
+     * <blockquote>
+     * <i>view-name</i><b>:</b><i>attribute-name</i>
+     * </blockquote>
+     * where the character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> is the {@link FileStoreAttributeView#name name} of
+     * a {@link FileStore AttributeView} that identifies a set of file attributes.
+     * <i>attribute-name</i> is the name of the attribute.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to know if ZFS compression is enabled (assuming the "zfs"
+     * view is supported):
+     * <pre>
+     *    boolean compression = (Boolean)fs.getAttribute("zfs:compression");
+     * </pre>
+     *
+     * @param   attribute
+     *          the attribute to read
+
+     * @return  the attribute value; {@code null} may be a valid valid for some
+     *          attributes
+     *
+     * @throws  UnsupportedOperationException
+     *          if the attribute view is not available or it does not support
+     *          reading the attribute
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    public abstract Object getAttribute(String attribute) throws IOException;
+}
diff --git a/java/nio/file/FileSystem.java b/java/nio/file/FileSystem.java
new file mode 100644
index 0000000..755d64f
--- /dev/null
+++ b/java/nio/file/FileSystem.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Set;
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * Provides an interface to a file system and is the factory for objects to
+ * access files and other objects in the file system.
+ *
+ * <p> The default file system, obtained by invoking the {@link FileSystems#getDefault
+ * FileSystems.getDefault} method, provides access to the file system that is
+ * accessible to the Java virtual machine. The {@link FileSystems} class defines
+ * methods to create file systems that provide access to other types of (custom)
+ * file systems.
+ *
+ * <p> A file system is the factory for several types of objects:
+ *
+ * <ul>
+ *   <li><p> The {@link #getPath getPath} method converts a system dependent
+ *     <em>path string</em>, returning a {@link Path} object that may be used
+ *     to locate and access a file. </p></li>
+ *   <li><p> The {@link #getPathMatcher  getPathMatcher} method is used
+ *     to create a {@link PathMatcher} that performs match operations on
+ *     paths. </p></li>
+ *   <li><p> The {@link #getFileStores getFileStores} method returns an iterator
+ *     over the underlying {@link FileStore file-stores}. </p></li>
+ *   <li><p> The {@link #getUserPrincipalLookupService getUserPrincipalLookupService}
+ *     method returns the {@link UserPrincipalLookupService} to lookup users or
+ *     groups by name. </p></li>
+ *   <li><p> The {@link #newWatchService newWatchService} method creates a
+ *     {@link WatchService} that may be used to watch objects for changes and
+ *     events. </p></li>
+ * </ul>
+ *
+ * <p> File systems vary greatly. In some cases the file system is a single
+ * hierarchy of files with one top-level root directory. In other cases it may
+ * have several distinct file hierarchies, each with its own top-level root
+ * directory. The {@link #getRootDirectories getRootDirectories} method may be
+ * used to iterate over the root directories in the file system. A file system
+ * is typically composed of one or more underlying {@link FileStore file-stores}
+ * that provide the storage for the files. Theses file stores can also vary in
+ * the features they support, and the file attributes or <em>meta-data</em> that
+ * they associate with files.
+ *
+ * <p> A file system is open upon creation and can be closed by invoking its
+ * {@link #close() close} method. Once closed, any further attempt to access
+ * objects in the file system cause {@link ClosedFileSystemException} to be
+ * thrown. File systems created by the default {@link FileSystemProvider provider}
+ * cannot be closed.
+ *
+ * <p> A {@code FileSystem} can provide read-only or read-write access to the
+ * file system. Whether or not a file system provides read-only access is
+ * established when the {@code FileSystem} is created and can be tested by invoking
+ * its {@link #isReadOnly() isReadOnly} method. Attempts to write to file stores
+ * by means of an object associated with a read-only file system throws {@link
+ * ReadOnlyFileSystemException}.
+ *
+ * <p> File systems are safe for use by multiple concurrent threads. The {@link
+ * #close close} method may be invoked at any time to close a file system but
+ * whether a file system is <i>asynchronously closeable</i> is provider specific
+ * and therefore unspecified. In other words, if a thread is accessing an
+ * object in a file system, and another thread invokes the {@code close} method
+ * then it may require to block until the first operation is complete. Closing
+ * a file system causes all open channels, watch services, and other {@link
+ * Closeable closeable} objects associated with the file system to be closed.
+ *
+ * @since 1.7
+ */
+
+public abstract class FileSystem
+    implements Closeable
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected FileSystem() {
+    }
+
+    /**
+     * Returns the provider that created this file system.
+     *
+     * @return  The provider that created this file system.
+     */
+    public abstract FileSystemProvider provider();
+
+    /**
+     * Closes this file system.
+     *
+     * <p> After a file system is closed then all subsequent access to the file
+     * system, either by methods defined by this class or on objects associated
+     * with this file system, throw {@link ClosedFileSystemException}. If the
+     * file system is already closed then invoking this method has no effect.
+     *
+     * <p> Closing a file system will close all open {@link
+     * java.nio.channels.Channel channels}, {@link DirectoryStream directory-streams},
+     * {@link WatchService watch-service}, and other closeable objects associated
+     * with this file system. The {@link FileSystems#getDefault default} file
+     * system cannot be closed.
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  UnsupportedOperationException
+     *          Thrown in the case of the default file system
+     */
+    @Override
+    public abstract void close() throws IOException;
+
+    /**
+     * Tells whether or not this file system is open.
+     *
+     * <p> File systems created by the default provider are always open.
+     *
+     * @return  {@code true} if, and only if, this file system is open
+     */
+    public abstract boolean isOpen();
+
+    /**
+     * Tells whether or not this file system allows only read-only access to
+     * its file stores.
+     *
+     * @return  {@code true} if, and only if, this file system provides
+     *          read-only access
+     */
+    public abstract boolean isReadOnly();
+
+    /**
+     * Returns the name separator, represented as a string.
+     *
+     * <p> The name separator is used to separate names in a path string. An
+     * implementation may support multiple name separators in which case this
+     * method returns an implementation specific <em>default</em> name separator.
+     * This separator is used when creating path strings by invoking the {@link
+     * Path#toString() toString()} method.
+     *
+     * <p> In the case of the default provider, this method returns the same
+     * separator as {@link java.io.File#separator}.
+     *
+     * @return  The name separator
+     */
+    public abstract String getSeparator();
+
+    /**
+     * Returns an object to iterate over the paths of the root directories.
+     *
+     * <p> A file system provides access to a file store that may be composed
+     * of a number of distinct file hierarchies, each with its own top-level
+     * root directory. Unless denied by the security manager, each element in
+     * the returned iterator corresponds to the root directory of a distinct
+     * file hierarchy. The order of the elements is not defined. The file
+     * hierarchies may change during the lifetime of the Java virtual machine.
+     * For example, in some implementations, the insertion of removable media
+     * may result in the creation of a new file hierarchy with its own
+     * top-level directory.
+     *
+     * <p> When a security manager is installed, it is invoked to check access
+     * to the each root directory. If denied, the root directory is not returned
+     * by the iterator. In the case of the default provider, the {@link
+     * SecurityManager#checkRead(String)} method is invoked to check read access
+     * to each root directory. It is system dependent if the permission checks
+     * are done when the iterator is obtained or during iteration.
+     *
+     * @return  An object to iterate over the root directories
+     */
+    public abstract Iterable<Path> getRootDirectories();
+
+    /**
+     * Returns an object to iterate over the underlying file stores.
+     *
+     * <p> The elements of the returned iterator are the {@link
+     * FileStore FileStores} for this file system. The order of the elements is
+     * not defined and the file stores may change during the lifetime of the
+     * Java virtual machine. When an I/O error occurs, perhaps because a file
+     * store is not accessible, then it is not returned by the iterator.
+     *
+     * <p> In the case of the default provider, and a security manager is
+     * installed, the security manager is invoked to check {@link
+     * RuntimePermission}<tt>("getFileStoreAttributes")</tt>. If denied, then
+     * no file stores are returned by the iterator. In addition, the security
+     * manager's {@link SecurityManager#checkRead(String)} method is invoked to
+     * check read access to the file store's <em>top-most</em> directory. If
+     * denied, the file store is not returned by the iterator. It is system
+     * dependent if the permission checks are done when the iterator is obtained
+     * or during iteration.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to print the space usage for all file stores:
+     * <pre>
+     *     for (FileStore store: FileSystems.getDefault().getFileStores()) {
+     *         long total = store.getTotalSpace() / 1024;
+     *         long used = (store.getTotalSpace() - store.getUnallocatedSpace()) / 1024;
+     *         long avail = store.getUsableSpace() / 1024;
+     *         System.out.format("%-20s %12d %12d %12d%n", store, total, used, avail);
+     *     }
+     * </pre>
+     *
+     * @return  An object to iterate over the backing file stores
+     */
+    public abstract Iterable<FileStore> getFileStores();
+
+    /**
+     * Returns the set of the {@link FileAttributeView#name names} of the file
+     * attribute views supported by this {@code FileSystem}.
+     *
+     * <p> The {@link BasicFileAttributeView} is required to be supported and
+     * therefore the set contains at least one element, "basic".
+     *
+     * <p> The {@link FileStore#supportsFileAttributeView(String)
+     * supportsFileAttributeView(String)} method may be used to test if an
+     * underlying {@link FileStore} supports the file attributes identified by a
+     * file attribute view.
+     *
+     * @return  An unmodifiable set of the names of the supported file attribute
+     *          views
+     */
+    public abstract Set<String> supportedFileAttributeViews();
+
+    /**
+     * Converts a path string, or a sequence of strings that when joined form
+     * a path string, to a {@code Path}. If {@code more} does not specify any
+     * elements then the value of the {@code first} parameter is the path string
+     * to convert. If {@code more} specifies one or more elements then each
+     * non-empty string, including {@code first}, is considered to be a sequence
+     * of name elements (see {@link Path}) and is joined to form a path string.
+     * The details as to how the Strings are joined is provider specific but
+     * typically they will be joined using the {@link #getSeparator
+     * name-separator} as the separator. For example, if the name separator is
+     * "{@code /}" and {@code getPath("/foo","bar","gus")} is invoked, then the
+     * path string {@code "/foo/bar/gus"} is converted to a {@code Path}.
+     * A {@code Path} representing an empty path is returned if {@code first}
+     * is the empty string and {@code more} does not contain any non-empty
+     * strings.
+     *
+     * <p> The parsing and conversion to a path object is inherently
+     * implementation dependent. In the simplest case, the path string is rejected,
+     * and {@link InvalidPathException} thrown, if the path string contains
+     * characters that cannot be converted to characters that are <em>legal</em>
+     * to the file store. For example, on UNIX systems, the NUL (&#92;u0000)
+     * character is not allowed to be present in a path. An implementation may
+     * choose to reject path strings that contain names that are longer than those
+     * allowed by any file store, and where an implementation supports a complex
+     * path syntax, it may choose to reject path strings that are <em>badly
+     * formed</em>.
+     *
+     * <p> In the case of the default provider, path strings are parsed based
+     * on the definition of paths at the platform or virtual file system level.
+     * For example, an operating system may not allow specific characters to be
+     * present in a file name, but a specific underlying file store may impose
+     * different or additional restrictions on the set of legal
+     * characters.
+     *
+     * <p> This method throws {@link InvalidPathException} when the path string
+     * cannot be converted to a path. Where possible, and where applicable,
+     * the exception is created with an {@link InvalidPathException#getIndex
+     * index} value indicating the first position in the {@code path} parameter
+     * that caused the path string to be rejected.
+     *
+     * @param   first
+     *          the path string or initial part of the path string
+     * @param   more
+     *          additional strings to be joined to form the path string
+     *
+     * @return  the resulting {@code Path}
+     *
+     * @throws  InvalidPathException
+     *          If the path string cannot be converted
+     */
+    public abstract Path getPath(String first, String... more);
+
+    // Android-changed: Removed javadoc references to UNIX and Windows.
+    /**
+     * Returns a {@code PathMatcher} that performs match operations on the
+     * {@code String} representation of {@link Path} objects by interpreting a
+     * given pattern.
+     *
+     * The {@code syntaxAndPattern} parameter identifies the syntax and the
+     * pattern and takes the form:
+     * <blockquote><pre>
+     * <i>syntax</i><b>:</b><i>pattern</i>
+     * </pre></blockquote>
+     * where {@code ':'} stands for itself.
+     *
+     * <p> A {@code FileSystem} implementation supports the "{@code glob}" and
+     * "{@code regex}" syntaxes, and may support others. The value of the syntax
+     * component is compared without regard to case.
+     *
+     * <p> When the syntax is "{@code glob}" then the {@code String}
+     * representation of the path is matched using a limited pattern language
+     * that resembles regular expressions but with a simpler syntax. For example:
+     *
+     * <blockquote>
+     * <table border="0" summary="Pattern Language">
+     * <tr>
+     *   <td>{@code *.java}</td>
+     *   <td>Matches a path that represents a file name ending in {@code .java}</td>
+     * </tr>
+     * <tr>
+     *   <td>{@code *.*}</td>
+     *   <td>Matches file names containing a dot</td>
+     * </tr>
+     * <tr>
+     *   <td>{@code *.{java,class}}</td>
+     *   <td>Matches file names ending with {@code .java} or {@code .class}</td>
+     * </tr>
+     * <tr>
+     *   <td>{@code foo.?}</td>
+     *   <td>Matches file names starting with {@code foo.} and a single
+     *   character extension</td>
+     * </tr>
+     * <tr>
+     *   <td><tt>&#47;home&#47;*&#47;*</tt>
+     *   <td>Matches <tt>&#47;home&#47;gus&#47;data</tt></td>
+     * </tr>
+     * <tr>
+     *   <td><tt>&#47;home&#47;**</tt>
+     *   <td>Matches <tt>&#47;home&#47;gus</tt> and
+     *   <tt>&#47;home&#47;gus&#47;data</tt></td>
+     * </tr>
+     *
+     * </table>
+     * </blockquote>
+     *
+     * <p> The following rules are used to interpret glob patterns:
+     *
+     * <ul>
+     *   <li><p> The {@code *} character matches zero or more {@link Character
+     *   characters} of a {@link Path#getName(int) name} component without
+     *   crossing directory boundaries. </p></li>
+     *
+     *   <li><p> The {@code **} characters matches zero or more {@link Character
+     *   characters} crossing directory boundaries. </p></li>
+     *
+     *   <li><p> The {@code ?} character matches exactly one character of a
+     *   name component.</p></li>
+     *
+     *   <li><p> The backslash character ({@code \}) is used to escape characters
+     *   that would otherwise be interpreted as special characters. The expression
+     *   {@code \\} matches a single backslash and "\{" matches a left brace
+     *   for example.  </p></li>
+     *
+     *   <li><p> The {@code [ ]} characters are a <i>bracket expression</i> that
+     *   match a single character of a name component out of a set of characters.
+     *   For example, {@code [abc]} matches {@code "a"}, {@code "b"}, or {@code "c"}.
+     *   The hyphen ({@code -}) may be used to specify a range so {@code [a-z]}
+     *   specifies a range that matches from {@code "a"} to {@code "z"} (inclusive).
+     *   These forms can be mixed so [abce-g] matches {@code "a"}, {@code "b"},
+     *   {@code "c"}, {@code "e"}, {@code "f"} or {@code "g"}. If the character
+     *   after the {@code [} is a {@code !} then it is used for negation so {@code
+     *   [!a-c]} matches any character except {@code "a"}, {@code "b"}, or {@code
+     *   "c"}.
+     *   <p> Within a bracket expression the {@code *}, {@code ?} and {@code \}
+     *   characters match themselves. The ({@code -}) character matches itself if
+     *   it is the first character within the brackets, or the first character
+     *   after the {@code !} if negating.</p></li>
+     *
+     *   <li><p> The {@code { }} characters are a group of subpatterns, where
+     *   the group matches if any subpattern in the group matches. The {@code ","}
+     *   character is used to separate the subpatterns. Groups cannot be nested.
+     *   </p></li>
+     *
+     *   <li><p> Leading period<tt>&#47;</tt>dot characters in file name are
+     *   treated as regular characters in match operations. For example,
+     *   the {@code "*"} glob pattern matches file name {@code ".login"}.
+     *   The {@link Files#isHidden} method may be used to test whether a file
+     *   is considered hidden.
+     *   </p></li>
+     *
+     *   <li><p> All other characters match themselves in an implementation
+     *   dependent manner. This includes characters representing any {@link
+     *   FileSystem#getSeparator name-separators}. </p></li>
+     *
+     *   <li><p> The matching of {@link Path#getRoot root} components is highly
+     *   implementation-dependent and is not specified. </p></li>
+     *
+     * </ul>
+     *
+     * <p> When the syntax is "{@code regex}" then the pattern component is a
+     * regular expression as defined by the {@link java.util.regex.Pattern}
+     * class.
+     *
+     * <p>  For both the glob and regex syntaxes, the matching details, such as
+     * whether the matching is case sensitive, are implementation-dependent
+     * and therefore not specified.
+     *
+     * @param   syntaxAndPattern
+     *          The syntax and pattern
+     *
+     * @return  A path matcher that may be used to match paths against the pattern
+     *
+     * @throws  IllegalArgumentException
+     *          If the parameter does not take the form: {@code syntax:pattern}
+     * @throws  java.util.regex.PatternSyntaxException
+     *          If the pattern is invalid
+     * @throws  UnsupportedOperationException
+     *          If the pattern syntax is not known to the implementation
+     *
+     * @see Files#newDirectoryStream(Path,String)
+     */
+    public abstract PathMatcher getPathMatcher(String syntaxAndPattern);
+
+    /**
+     * Returns the {@code UserPrincipalLookupService} for this file system
+     * <i>(optional operation)</i>. The resulting lookup service may be used to
+     * lookup user or group names.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to make "joe" the owner of a file:
+     * <pre>
+     *     UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService();
+     *     Files.setOwner(path, lookupService.lookupPrincipalByName("joe"));
+     * </pre>
+     *
+     * @throws  UnsupportedOperationException
+     *          If this {@code FileSystem} does not does have a lookup service
+     *
+     * @return  The {@code UserPrincipalLookupService} for this file system
+     */
+    public abstract UserPrincipalLookupService getUserPrincipalLookupService();
+
+    /**
+     * Constructs a new {@link WatchService} <i>(optional operation)</i>.
+     *
+     * <p> This method constructs a new watch service that may be used to watch
+     * registered objects for changes and events.
+     *
+     * @return  a new watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If this {@code FileSystem} does not support watching file system
+     *          objects for changes and events. This exception is not thrown
+     *          by {@code FileSystems} created by the default provider.
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract WatchService newWatchService() throws IOException;
+}
diff --git a/java/nio/file/FileSystemAlreadyExistsException.java b/java/nio/file/FileSystemAlreadyExistsException.java
new file mode 100644
index 0000000..e305542
--- /dev/null
+++ b/java/nio/file/FileSystemAlreadyExistsException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Runtime exception thrown when an attempt is made to create a file system that
+ * already exists.
+ */
+
+public class FileSystemAlreadyExistsException
+    extends RuntimeException
+{
+    static final long serialVersionUID = -5438419127181131148L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FileSystemAlreadyExistsException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          the detail message
+     */
+    public FileSystemAlreadyExistsException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/nio/file/FileSystemException.java b/java/nio/file/FileSystemException.java
new file mode 100644
index 0000000..b130584
--- /dev/null
+++ b/java/nio/file/FileSystemException.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a file system operation fails on one or two files. This class is
+ * the general class for file system exceptions.
+ *
+ * @since 1.7
+ */
+
+public class FileSystemException
+    extends IOException
+{
+    static final long serialVersionUID = -3055425747967319812L;
+
+    private final String file;
+    private final String other;
+
+    /**
+     * Constructs an instance of this class. This constructor should be used
+     * when an operation involving one file fails and there isn't any additional
+     * information to explain the reason.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known.
+     */
+    public FileSystemException(String file) {
+        super((String)null);
+        this.file = file;
+        this.other = null;
+    }
+
+    /**
+     * Constructs an instance of this class. This constructor should be used
+     * when an operation involving two files fails, or there is additional
+     * information to explain the reason.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known.
+     * @param   other
+     *          a string identifying the other file or {@code null} if there
+     *          isn't another file or if not known
+     * @param   reason
+     *          a reason message with additional information or {@code null}
+     */
+    public FileSystemException(String file, String other, String reason) {
+        super(reason);
+        this.file = file;
+        this.other = other;
+    }
+
+    /**
+     * Returns the file used to create this exception.
+     *
+     * @return  the file (can be {@code null})
+     */
+    public String getFile() {
+        return file;
+    }
+
+    /**
+     * Returns the other file used to create this exception.
+     *
+     * @return  the other file (can be {@code null})
+     */
+    public String getOtherFile() {
+        return other;
+    }
+
+    /**
+     * Returns the string explaining why the file system operation failed.
+     *
+     * @return  the string explaining why the file system operation failed
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns the detail message string.
+     */
+    @Override
+    public String getMessage() {
+        if (file == null && other == null)
+            return getReason();
+        StringBuilder sb = new StringBuilder();
+        if (file != null)
+            sb.append(file);
+        if (other != null) {
+            sb.append(" -> ");
+            sb.append(other);
+        }
+        if (getReason() != null) {
+            sb.append(": ");
+            sb.append(getReason());
+        }
+        return sb.toString();
+    }
+}
diff --git a/java/nio/file/FileSystemLoopException.java b/java/nio/file/FileSystemLoopException.java
new file mode 100644
index 0000000..fe6beb5
--- /dev/null
+++ b/java/nio/file/FileSystemLoopException.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system loop, or cycle, is encountered.
+ *
+ * @since 1.7
+ * @see Files#walkFileTree
+ */
+
+public class FileSystemLoopException
+    extends FileSystemException
+{
+    private static final long serialVersionUID = 4843039591949217617L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file causing the cycle or {@code null} if
+     *          not known
+     */
+    public FileSystemLoopException(String file) {
+        super(file);
+    }
+}
diff --git a/java/nio/file/FileSystemNotFoundException.java b/java/nio/file/FileSystemNotFoundException.java
new file mode 100644
index 0000000..1c0ee4c
--- /dev/null
+++ b/java/nio/file/FileSystemNotFoundException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Runtime exception thrown when a file system cannot be found.
+ */
+
+public class FileSystemNotFoundException
+    extends RuntimeException
+{
+    static final long serialVersionUID = 7999581764446402397L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FileSystemNotFoundException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          the detail message
+     */
+    public FileSystemNotFoundException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/nio/file/FileSystems.java b/java/nio/file/FileSystems.java
new file mode 100644
index 0000000..a38aaae
--- /dev/null
+++ b/java/nio/file/FileSystems.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.spi.FileSystemProvider;
+import java.net.URI;
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.*;
+import java.lang.reflect.Constructor;
+
+/**
+ * Factory methods for file systems. This class defines the {@link #getDefault
+ * getDefault} method to get the default file system and factory methods to
+ * construct other types of file systems.
+ *
+ * <p> The first invocation of any of the methods defined by this class causes
+ * the default {@link FileSystemProvider provider} to be loaded. The default
+ * provider, identified by the URI scheme "file", creates the {@link FileSystem}
+ * that provides access to the file systems accessible to the Java virtual
+ * machine. If the process of loading or initializing the default provider fails
+ * then an unspecified error is thrown.
+ *
+ * <p> The first invocation of the {@link FileSystemProvider#installedProviders
+ * installedProviders} method, by way of invoking any of the {@code
+ * newFileSystem} methods defined by this class, locates and loads all
+ * installed file system providers. Installed providers are loaded using the
+ * service-provider loading facility defined by the {@link ServiceLoader} class.
+ * Installed providers are loaded using the system class loader. If the
+ * system class loader cannot be found then the extension class loader is used;
+ * if there is no extension class loader then the bootstrap class loader is used.
+ * Providers are typically installed by placing them in a JAR file on the
+ * application class path or in the extension directory, the JAR file contains a
+ * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider}
+ * in the resource directory {@code META-INF/services}, and the file lists one or
+ * more fully-qualified names of concrete subclass of {@link FileSystemProvider}
+ * that have a zero argument constructor.
+ * The ordering that installed providers are located is implementation specific.
+ * If a provider is instantiated and its {@link FileSystemProvider#getScheme()
+ * getScheme} returns the same URI scheme of a provider that was previously
+ * instantiated then the most recently instantiated duplicate is discarded. URI
+ * schemes are compared without regard to case. During construction a provider
+ * may safely access files associated with the default provider but care needs
+ * to be taken to avoid circular loading of other installed providers. If
+ * circular loading of installed providers is detected then an unspecified error
+ * is thrown.
+ *
+ * <p> This class also defines factory methods that allow a {@link ClassLoader}
+ * to be specified when locating a provider. As with installed providers, the
+ * provider classes are identified by placing the provider configuration file
+ * in the resource directory {@code META-INF/services}.
+ *
+ * <p> If a thread initiates the loading of the installed file system providers
+ * and another thread invokes a method that also attempts to load the providers
+ * then the method will block until the loading completes.
+ *
+ * @since 1.7
+ */
+
+public final class FileSystems {
+    private FileSystems() {
+    }
+
+    // lazy initialization of default file system
+    private static class DefaultFileSystemHolder {
+        static final FileSystem defaultFileSystem = defaultFileSystem();
+
+        // returns default file system
+        private static FileSystem defaultFileSystem() {
+            // load default provider
+            FileSystemProvider provider = AccessController
+                .doPrivileged(new PrivilegedAction<FileSystemProvider>() {
+                    public FileSystemProvider run() {
+                        return getDefaultProvider();
+                    }
+                });
+
+            // return file system
+            return provider.getFileSystem(URI.create("file:///"));
+        }
+
+        // returns default provider
+        private static FileSystemProvider getDefaultProvider() {
+            FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create();
+
+            // if the property java.nio.file.spi.DefaultFileSystemProvider is
+            // set then its value is the name of the default provider (or a list)
+            String propValue = System
+                .getProperty("java.nio.file.spi.DefaultFileSystemProvider");
+            if (propValue != null) {
+                for (String cn: propValue.split(",")) {
+                    try {
+                        Class<?> c = Class
+                            .forName(cn, true, ClassLoader.getSystemClassLoader());
+                        Constructor<?> ctor = c
+                            .getDeclaredConstructor(FileSystemProvider.class);
+                        provider = (FileSystemProvider)ctor.newInstance(provider);
+
+                        // must be "file"
+                        if (!provider.getScheme().equals("file"))
+                            throw new Error("Default provider must use scheme 'file'");
+
+                    } catch (Exception x) {
+                        throw new Error(x);
+                    }
+                }
+            }
+            return provider;
+        }
+    }
+
+    /**
+     * Returns the default {@code FileSystem}. The default file system creates
+     * objects that provide access to the file systems accessible to the Java
+     * virtual machine. The <em>working directory</em> of the file system is
+     * the current user directory, named by the system property {@code user.dir}.
+     * This allows for interoperability with the {@link java.io.File java.io.File}
+     * class.
+     *
+     * <p> The first invocation of any of the methods defined by this class
+     * locates the default {@link FileSystemProvider provider} object. Where the
+     * system property {@code java.nio.file.spi.DefaultFileSystemProvider} is
+     * not defined then the default provider is a system-default provider that
+     * is invoked to create the default file system.
+     *
+     * <p> If the system property {@code java.nio.file.spi.DefaultFileSystemProvider}
+     * is defined then it is taken to be a list of one or more fully-qualified
+     * names of concrete provider classes identified by the URI scheme
+     * {@code "file"}. Where the property is a list of more than one name then
+     * the names are separated by a comma. Each class is loaded, using the system
+     * class loader, and instantiated by invoking a one argument constructor
+     * whose formal parameter type is {@code FileSystemProvider}. The providers
+     * are loaded and instantiated in the order they are listed in the property.
+     * If this process fails or a provider's scheme is not equal to {@code "file"}
+     * then an unspecified error is thrown. URI schemes are normally compared
+     * without regard to case but for the default provider, the scheme is
+     * required to be {@code "file"}. The first provider class is instantiated
+     * by invoking it with a reference to the system-default provider.
+     * The second provider class is instantiated by invoking it with a reference
+     * to the first provider instance. The third provider class is instantiated
+     * by invoking it with a reference to the second instance, and so on. The
+     * last provider to be instantiated becomes the default provider; its {@code
+     * getFileSystem} method is invoked with the URI {@code "file:///"} to
+     * get a reference to the default file system.
+     *
+     * <p> Subsequent invocations of this method return the file system that was
+     * returned by the first invocation.
+     *
+     * @return  the default file system
+     */
+    public static FileSystem getDefault() {
+        return DefaultFileSystemHolder.defaultFileSystem;
+    }
+
+    /**
+     * Returns a reference to an existing {@code FileSystem}.
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers to locate the provider that is identified by the URI
+     * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
+     * without regard to case. The exact form of the URI is highly provider
+     * dependent. If found, the provider's {@link FileSystemProvider#getFileSystem
+     * getFileSystem} method is invoked to obtain a reference to the {@code
+     * FileSystem}.
+     *
+     * <p> Once a file system created by this provider is {@link FileSystem#close
+     * closed} it is provider-dependent if this method returns a reference to
+     * the closed file system or throws {@link FileSystemNotFoundException}.
+     * If the provider allows a new file system to be created with the same URI
+     * as a file system it previously created then this method throws the
+     * exception if invoked after the file system is closed (and before a new
+     * instance is created by the {@link #newFileSystem newFileSystem} method).
+     *
+     * <p> If a security manager is installed then a provider implementation
+     * may require to check a permission before returning a reference to an
+     * existing file system. In the case of the {@link FileSystems#getDefault
+     * default} file system, no permission check is required.
+     *
+     * @param   uri  the URI to locate the file system
+     *
+     * @return  the reference to the file system
+     *
+     * @throws  IllegalArgumentException
+     *          if the pre-conditions for the {@code uri} parameter are not met
+     * @throws  FileSystemNotFoundException
+     *          if the file system, identified by the URI, does not exist
+     * @throws  ProviderNotFoundException
+     *          if a provider supporting the URI scheme is not installed
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission
+     */
+    public static FileSystem getFileSystem(URI uri) {
+        String scheme = uri.getScheme();
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (scheme.equalsIgnoreCase(provider.getScheme())) {
+                return provider.getFileSystem(uri);
+            }
+        }
+        throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
+    }
+
+    /**
+     * Constructs a new file system that is identified by a {@link URI}
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers to locate the provider that is identified by the URI
+     * {@link URI#getScheme scheme} of the given URI. URI schemes are compared
+     * without regard to case. The exact form of the URI is highly provider
+     * dependent. If found, the provider's {@link FileSystemProvider#newFileSystem(URI,Map)
+     * newFileSystem(URI,Map)} method is invoked to construct the new file system.
+     *
+     * <p> Once a file system is {@link FileSystem#close closed} it is
+     * provider-dependent if the provider allows a new file system to be created
+     * with the same URI as a file system it previously created.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose there is a provider identified by the scheme {@code "memory"}
+     * installed:
+     * <pre>
+     *   Map&lt;String,String&gt; env = new HashMap&lt;&gt;();
+     *   env.put("capacity", "16G");
+     *   env.put("blockSize", "4k");
+     *   FileSystem fs = FileSystems.newFileSystem(URI.create("memory:///?name=logfs"), env);
+     * </pre>
+     *
+     * @param   uri
+     *          the URI identifying the file system
+     * @param   env
+     *          a map of provider specific properties to configure the file system;
+     *          may be empty
+     *
+     * @return  a new file system
+     *
+     * @throws  IllegalArgumentException
+     *          if the pre-conditions for the {@code uri} parameter are not met,
+     *          or the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  FileSystemAlreadyExistsException
+     *          if the file system has already been created
+     * @throws  ProviderNotFoundException
+     *          if a provider supporting the URI scheme is not installed
+     * @throws  IOException
+     *          if an I/O error occurs creating the file system
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission required by the file system provider implementation
+     */
+    public static FileSystem newFileSystem(URI uri, Map<String,?> env)
+        throws IOException
+    {
+        return newFileSystem(uri, env, null);
+    }
+
+    /**
+     * Constructs a new file system that is identified by a {@link URI}
+     *
+     * <p> This method first attempts to locate an installed provider in exactly
+     * the same manner as the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
+     * method. If none of the installed providers support the URI scheme then an
+     * attempt is made to locate the provider using the given class loader. If a
+     * provider supporting the URI scheme is located then its {@link
+     * FileSystemProvider#newFileSystem(URI,Map) newFileSystem(URI,Map)} is
+     * invoked to construct the new file system.
+     *
+     * @param   uri
+     *          the URI identifying the file system
+     * @param   env
+     *          a map of provider specific properties to configure the file system;
+     *          may be empty
+     * @param   loader
+     *          the class loader to locate the provider or {@code null} to only
+     *          attempt to locate an installed provider
+     *
+     * @return  a new file system
+     *
+     * @throws  IllegalArgumentException
+     *          if the pre-conditions for the {@code uri} parameter are not met,
+     *          or the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  FileSystemAlreadyExistsException
+     *          if the URI scheme identifies an installed provider and the file
+     *          system has already been created
+     * @throws  ProviderNotFoundException
+     *          if a provider supporting the URI scheme is not found
+     * @throws  ServiceConfigurationError
+     *          when an error occurs while loading a service provider
+     * @throws  IOException
+     *          an I/O error occurs creating the file system
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission required by the file system provider implementation
+     */
+    public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader)
+        throws IOException
+    {
+        String scheme = uri.getScheme();
+
+        // check installed providers
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (scheme.equalsIgnoreCase(provider.getScheme())) {
+                return provider.newFileSystem(uri, env);
+            }
+        }
+
+        // if not found, use service-provider loading facility
+        if (loader != null) {
+            ServiceLoader<FileSystemProvider> sl = ServiceLoader
+                .load(FileSystemProvider.class, loader);
+            for (FileSystemProvider provider: sl) {
+                if (scheme.equalsIgnoreCase(provider.getScheme())) {
+                    return provider.newFileSystem(uri, env);
+                }
+            }
+        }
+
+        throw new ProviderNotFoundException("Provider \"" + scheme + "\" not found");
+    }
+
+    /**
+     * Constructs a new {@code FileSystem} to access the contents of a file as a
+     * file system.
+     *
+     * <p> This method makes use of specialized providers that create pseudo file
+     * systems where the contents of one or more files is treated as a file
+     * system.
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers. It invokes, in turn, each provider's {@link
+     * FileSystemProvider#newFileSystem(Path,Map) newFileSystem(Path,Map)} method
+     * with an empty map. If a provider returns a file system then the iteration
+     * terminates and the file system is returned. If none of the installed
+     * providers return a {@code FileSystem} then an attempt is made to locate
+     * the provider using the given class loader. If a provider returns a file
+     * system then the lookup terminates and the file system is returned.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   loader
+     *          the class loader to locate the provider or {@code null} to only
+     *          attempt to locate an installed provider
+     *
+     * @return  a new file system
+     *
+     * @throws  ProviderNotFoundException
+     *          if a provider supporting this file type cannot be located
+     * @throws  ServiceConfigurationError
+     *          when an error occurs while loading a service provider
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission
+     */
+    public static FileSystem newFileSystem(Path path,
+                                           ClassLoader loader)
+        throws IOException
+    {
+        if (path == null)
+            throw new NullPointerException();
+        Map<String,?> env = Collections.emptyMap();
+
+        // check installed providers
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            try {
+                return provider.newFileSystem(path, env);
+            } catch (UnsupportedOperationException uoe) {
+            }
+        }
+
+        // if not found, use service-provider loading facility
+        if (loader != null) {
+            ServiceLoader<FileSystemProvider> sl = ServiceLoader
+                .load(FileSystemProvider.class, loader);
+            for (FileSystemProvider provider: sl) {
+                try {
+                    return provider.newFileSystem(path, env);
+                } catch (UnsupportedOperationException uoe) {
+                }
+            }
+        }
+
+        throw new ProviderNotFoundException("Provider not found");
+    }
+}
diff --git a/java/nio/file/FileTreeIterator.java b/java/nio/file/FileTreeIterator.java
new file mode 100644
index 0000000..63b4dc7
--- /dev/null
+++ b/java/nio/file/FileTreeIterator.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.nio.file.FileTreeWalker.Event;
+
+/**
+ * An {@code Iterator to iterate over the nodes of a file tree.
+ *
+ * <pre>{@code
+ *     try (FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options)) {
+ *         while (iterator.hasNext()) {
+ *             Event ev = iterator.next();
+ *             Path path = ev.file();
+ *             BasicFileAttributes attrs = ev.attributes();
+ *         }
+ *     }
+ * }</pre>
+ */
+
+class FileTreeIterator implements Iterator<Event>, Closeable {
+    private final FileTreeWalker walker;
+    private Event next;
+
+    /**
+     * Creates a new iterator to walk the file tree starting at the given file.
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code maxDepth} is negative
+     * @throws  IOException
+     *          if an I/O errors occurs opening the starting file
+     * @throws  SecurityException
+     *          if the security manager denies access to the starting file
+     * @throws  NullPointerException
+     *          if {@code start} or {@code options} is {@ocde null} or
+     *          the options array contains a {@code null} element
+     */
+    FileTreeIterator(Path start, int maxDepth, FileVisitOption... options)
+        throws IOException
+    {
+        this.walker = new FileTreeWalker(Arrays.asList(options), maxDepth);
+        this.next = walker.walk(start);
+        assert next.type() == FileTreeWalker.EventType.ENTRY ||
+               next.type() == FileTreeWalker.EventType.START_DIRECTORY;
+
+        // IOException if there a problem accessing the starting file
+        IOException ioe = next.ioeException();
+        if (ioe != null)
+            throw ioe;
+    }
+
+    private void fetchNextIfNeeded() {
+        if (next == null) {
+            FileTreeWalker.Event ev = walker.next();
+            while (ev != null) {
+                IOException ioe = ev.ioeException();
+                if (ioe != null)
+                    throw new UncheckedIOException(ioe);
+
+                // END_DIRECTORY events are ignored
+                if (ev.type() != FileTreeWalker.EventType.END_DIRECTORY) {
+                    next = ev;
+                    return;
+                }
+                ev = walker.next();
+            }
+        }
+    }
+
+    @Override
+    public boolean hasNext() {
+        if (!walker.isOpen())
+            throw new IllegalStateException();
+        fetchNextIfNeeded();
+        return next != null;
+    }
+
+    @Override
+    public Event next() {
+        if (!walker.isOpen())
+            throw new IllegalStateException();
+        fetchNextIfNeeded();
+        if (next == null)
+            throw new NoSuchElementException();
+        Event result = next;
+        next = null;
+        return result;
+    }
+
+    @Override
+    public void close() {
+        walker.close();
+    }
+}
diff --git a/java/nio/file/FileTreeWalker.java b/java/nio/file/FileTreeWalker.java
new file mode 100644
index 0000000..b0cf0d3
--- /dev/null
+++ b/java/nio/file/FileTreeWalker.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.BasicFileAttributes;
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Collection;
+import java.util.Iterator;
+import sun.nio.fs.BasicFileAttributesHolder;
+
+/**
+ * Walks a file tree, generating a sequence of events corresponding to the files
+ * in the tree.
+ *
+ * <pre>{@code
+ *     Path top = ...
+ *     Set<FileVisitOption> options = ...
+ *     int maxDepth = ...
+ *
+ *     try (FileTreeWalker walker = new FileTreeWalker(options, maxDepth)) {
+ *         FileTreeWalker.Event ev = walker.walk(top);
+ *         do {
+ *             process(ev);
+ *             ev = walker.next();
+ *         } while (ev != null);
+ *     }
+ * }</pre>
+ *
+ * @see Files#walkFileTree
+ */
+
+class FileTreeWalker implements Closeable {
+    private final boolean followLinks;
+    private final LinkOption[] linkOptions;
+    private final int maxDepth;
+    private final ArrayDeque<DirectoryNode> stack = new ArrayDeque<>();
+    private boolean closed;
+
+    /**
+     * The element on the walking stack corresponding to a directory node.
+     */
+    private static class DirectoryNode {
+        private final Path dir;
+        private final Object key;
+        private final DirectoryStream<Path> stream;
+        private final Iterator<Path> iterator;
+        private boolean skipped;
+
+        DirectoryNode(Path dir, Object key, DirectoryStream<Path> stream) {
+            this.dir = dir;
+            this.key = key;
+            this.stream = stream;
+            this.iterator = stream.iterator();
+        }
+
+        Path directory() {
+            return dir;
+        }
+
+        Object key() {
+            return key;
+        }
+
+        DirectoryStream<Path> stream() {
+            return stream;
+        }
+
+        Iterator<Path> iterator() {
+            return iterator;
+        }
+
+        void skip() {
+            skipped = true;
+        }
+
+        boolean skipped() {
+            return skipped;
+        }
+    }
+
+    /**
+     * The event types.
+     */
+    static enum EventType {
+        /**
+         * Start of a directory
+         */
+        START_DIRECTORY,
+        /**
+         * End of a directory
+         */
+        END_DIRECTORY,
+        /**
+         * An entry in a directory
+         */
+        ENTRY;
+    }
+
+    /**
+     * Events returned by the {@link #walk} and {@link #next} methods.
+     */
+    static class Event {
+        private final EventType type;
+        private final Path file;
+        private final BasicFileAttributes attrs;
+        private final IOException ioe;
+
+        private Event(EventType type, Path file, BasicFileAttributes attrs, IOException ioe) {
+            this.type = type;
+            this.file = file;
+            this.attrs = attrs;
+            this.ioe = ioe;
+        }
+
+        Event(EventType type, Path file, BasicFileAttributes attrs) {
+            this(type, file, attrs, null);
+        }
+
+        Event(EventType type, Path file, IOException ioe) {
+            this(type, file, null, ioe);
+        }
+
+        EventType type() {
+            return type;
+        }
+
+        Path file() {
+            return file;
+        }
+
+        BasicFileAttributes attributes() {
+            return attrs;
+        }
+
+        IOException ioeException() {
+            return ioe;
+        }
+    }
+
+    /**
+     * Creates a {@code FileTreeWalker}.
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code maxDepth} is negative
+     * @throws  ClassCastException
+     *          if (@code options} contains an element that is not a
+     *          {@code FileVisitOption}
+     * @throws  NullPointerException
+     *          if {@code options} is {@ocde null} or the options
+     *          array contains a {@code null} element
+     */
+    FileTreeWalker(Collection<FileVisitOption> options, int maxDepth) {
+        boolean fl = false;
+        for (FileVisitOption option: options) {
+            // will throw NPE if options contains null
+            switch (option) {
+                case FOLLOW_LINKS : fl = true; break;
+                default:
+                    throw new AssertionError("Should not get here");
+            }
+        }
+        if (maxDepth < 0)
+            throw new IllegalArgumentException("'maxDepth' is negative");
+
+        this.followLinks = fl;
+        this.linkOptions = (fl) ? new LinkOption[0] :
+            new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+        this.maxDepth = maxDepth;
+    }
+
+    /**
+     * Returns the attributes of the given file, taking into account whether
+     * the walk is following sym links is not. The {@code canUseCached}
+     * argument determines whether this method can use cached attributes.
+     */
+    private BasicFileAttributes getAttributes(Path file, boolean canUseCached)
+        throws IOException
+    {
+        // if attributes are cached then use them if possible
+        if (canUseCached &&
+            (file instanceof BasicFileAttributesHolder) &&
+            (System.getSecurityManager() == null))
+        {
+            BasicFileAttributes cached = ((BasicFileAttributesHolder)file).get();
+            if (cached != null && (!followLinks || !cached.isSymbolicLink())) {
+                return cached;
+            }
+        }
+
+        // attempt to get attributes of file. If fails and we are following
+        // links then a link target might not exist so get attributes of link
+        BasicFileAttributes attrs;
+        try {
+            attrs = Files.readAttributes(file, BasicFileAttributes.class, linkOptions);
+        } catch (IOException ioe) {
+            if (!followLinks)
+                throw ioe;
+
+            // attempt to get attrmptes without following links
+            attrs = Files.readAttributes(file,
+                                         BasicFileAttributes.class,
+                                         LinkOption.NOFOLLOW_LINKS);
+        }
+        return attrs;
+    }
+
+    /**
+     * Returns true if walking into the given directory would result in a
+     * file system loop/cycle.
+     */
+    private boolean wouldLoop(Path dir, Object key) {
+        // if this directory and ancestor has a file key then we compare
+        // them; otherwise we use less efficient isSameFile test.
+        for (DirectoryNode ancestor: stack) {
+            Object ancestorKey = ancestor.key();
+            if (key != null && ancestorKey != null) {
+                if (key.equals(ancestorKey)) {
+                    // cycle detected
+                    return true;
+                }
+            } else {
+                try {
+                    if (Files.isSameFile(dir, ancestor.directory())) {
+                        // cycle detected
+                        return true;
+                    }
+                } catch (IOException | SecurityException x) {
+                    // ignore
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Visits the given file, returning the {@code Event} corresponding to that
+     * visit.
+     *
+     * The {@code ignoreSecurityException} parameter determines whether
+     * any SecurityException should be ignored or not. If a SecurityException
+     * is thrown, and is ignored, then this method returns {@code null} to
+     * mean that there is no event corresponding to a visit to the file.
+     *
+     * The {@code canUseCached} parameter determines whether cached attributes
+     * for the file can be used or not.
+     */
+    private Event visit(Path entry, boolean ignoreSecurityException, boolean canUseCached) {
+        // need the file attributes
+        BasicFileAttributes attrs;
+        try {
+            attrs = getAttributes(entry, canUseCached);
+        } catch (IOException ioe) {
+            return new Event(EventType.ENTRY, entry, ioe);
+        } catch (SecurityException se) {
+            if (ignoreSecurityException)
+                return null;
+            throw se;
+        }
+
+        // at maximum depth or file is not a directory
+        int depth = stack.size();
+        if (depth >= maxDepth || !attrs.isDirectory()) {
+            return new Event(EventType.ENTRY, entry, attrs);
+        }
+
+        // check for cycles when following links
+        if (followLinks && wouldLoop(entry, attrs.fileKey())) {
+            return new Event(EventType.ENTRY, entry,
+                             new FileSystemLoopException(entry.toString()));
+        }
+
+        // file is a directory, attempt to open it
+        DirectoryStream<Path> stream = null;
+        try {
+            stream = Files.newDirectoryStream(entry);
+        } catch (IOException ioe) {
+            return new Event(EventType.ENTRY, entry, ioe);
+        } catch (SecurityException se) {
+            if (ignoreSecurityException)
+                return null;
+            throw se;
+        }
+
+        // push a directory node to the stack and return an event
+        stack.push(new DirectoryNode(entry, attrs.fileKey(), stream));
+        return new Event(EventType.START_DIRECTORY, entry, attrs);
+    }
+
+
+    /**
+     * Start walking from the given file.
+     */
+    Event walk(Path file) {
+        if (closed)
+            throw new IllegalStateException("Closed");
+
+        Event ev = visit(file,
+                         false,   // ignoreSecurityException
+                         false);  // canUseCached
+        assert ev != null;
+        return ev;
+    }
+
+    /**
+     * Returns the next Event or {@code null} if there are no more events or
+     * the walker is closed.
+     */
+    Event next() {
+        DirectoryNode top = stack.peek();
+        if (top == null)
+            return null;      // stack is empty, we are done
+
+        // continue iteration of the directory at the top of the stack
+        Event ev;
+        do {
+            Path entry = null;
+            IOException ioe = null;
+
+            // get next entry in the directory
+            if (!top.skipped()) {
+                Iterator<Path> iterator = top.iterator();
+                try {
+                    if (iterator.hasNext()) {
+                        entry = iterator.next();
+                    }
+                } catch (DirectoryIteratorException x) {
+                    ioe = x.getCause();
+                }
+            }
+
+            // no next entry so close and pop directory, creating corresponding event
+            if (entry == null) {
+                try {
+                    top.stream().close();
+                } catch (IOException e) {
+                    if (ioe != null) {
+                        ioe = e;
+                    } else {
+                        ioe.addSuppressed(e);
+                    }
+                }
+                stack.pop();
+                return new Event(EventType.END_DIRECTORY, top.directory(), ioe);
+            }
+
+            // visit the entry
+            ev = visit(entry,
+                       true,   // ignoreSecurityException
+                       true);  // canUseCached
+
+        } while (ev == null);
+
+        return ev;
+    }
+
+    /**
+     * Pops the directory node that is the current top of the stack so that
+     * there are no more events for the directory (including no END_DIRECTORY)
+     * event. This method is a no-op if the stack is empty or the walker is
+     * closed.
+     */
+    void pop() {
+        if (!stack.isEmpty()) {
+            DirectoryNode node = stack.pop();
+            try {
+                node.stream().close();
+            } catch (IOException ignore) { }
+        }
+    }
+
+    /**
+     * Skips the remaining entries in the directory at the top of the stack.
+     * This method is a no-op if the stack is empty or the walker is closed.
+     */
+    void skipRemainingSiblings() {
+        if (!stack.isEmpty()) {
+            stack.peek().skip();
+        }
+    }
+
+    /**
+     * Returns {@code true} if the walker is open.
+     */
+    boolean isOpen() {
+        return !closed;
+    }
+
+    /**
+     * Closes/pops all directories on the stack.
+     */
+    @Override
+    public void close() {
+        if (!closed) {
+            while (!stack.isEmpty()) {
+                pop();
+            }
+            closed = true;
+        }
+    }
+}
diff --git a/java/nio/file/FileVisitOption.java b/java/nio/file/FileVisitOption.java
new file mode 100644
index 0000000..c6c00e5
--- /dev/null
+++ b/java/nio/file/FileVisitOption.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the file tree traversal options.
+ *
+ * @since 1.7
+ *
+ * @see Files#walkFileTree
+ */
+
+public enum FileVisitOption {
+    /**
+     * Follow symbolic links.
+     */
+    FOLLOW_LINKS;
+}
diff --git a/java/nio/file/FileVisitResult.java b/java/nio/file/FileVisitResult.java
new file mode 100644
index 0000000..36bd5c9
--- /dev/null
+++ b/java/nio/file/FileVisitResult.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * The result type of a {@link FileVisitor FileVisitor}.
+ *
+ * @since 1.7
+ *
+ * @see Files#walkFileTree
+ */
+
+public enum FileVisitResult {
+    /**
+     * Continue. When returned from a {@link FileVisitor#preVisitDirectory
+     * preVisitDirectory} method then the entries in the directory should also
+     * be visited.
+     */
+    CONTINUE,
+    /**
+     * Terminate.
+     */
+    TERMINATE,
+    /**
+     * Continue without visiting the entries in this directory. This result
+     * is only meaningful when returned from the {@link
+     * FileVisitor#preVisitDirectory preVisitDirectory} method; otherwise
+     * this result type is the same as returning {@link #CONTINUE}.
+     */
+    SKIP_SUBTREE,
+    /**
+     * Continue without visiting the <em>siblings</em> of this file or directory.
+     * If returned from the {@link FileVisitor#preVisitDirectory
+     * preVisitDirectory} method then the entries in the directory are also
+     * skipped and the {@link FileVisitor#postVisitDirectory postVisitDirectory}
+     * method is not invoked.
+     */
+    SKIP_SIBLINGS;
+}
diff --git a/java/nio/file/FileVisitor.java b/java/nio/file/FileVisitor.java
new file mode 100644
index 0000000..5c555ae
--- /dev/null
+++ b/java/nio/file/FileVisitor.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.BasicFileAttributes;
+import java.io.IOException;
+
+/**
+ * A visitor of files. An implementation of this interface is provided to the
+ * {@link Files#walkFileTree Files.walkFileTree} methods to visit each file in
+ * a file tree.
+ *
+ * <p> <b>Usage Examples:</b>
+ * Suppose we want to delete a file tree. In that case, each directory should
+ * be deleted after the entries in the directory are deleted.
+ * <pre>
+ *     Path start = ...
+ *     Files.walkFileTree(start, new SimpleFileVisitor&lt;Path&gt;() {
+ *         &#64;Override
+ *         public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ *             throws IOException
+ *         {
+ *             Files.delete(file);
+ *             return FileVisitResult.CONTINUE;
+ *         }
+ *         &#64;Override
+ *         public FileVisitResult postVisitDirectory(Path dir, IOException e)
+ *             throws IOException
+ *         {
+ *             if (e == null) {
+ *                 Files.delete(dir);
+ *                 return FileVisitResult.CONTINUE;
+ *             } else {
+ *                 // directory iteration failed
+ *                 throw e;
+ *             }
+ *         }
+ *     });
+ * </pre>
+ * <p> Furthermore, suppose we want to copy a file tree to a target location.
+ * In that case, symbolic links should be followed and the target directory
+ * should be created before the entries in the directory are copied.
+ * <pre>
+ *     final Path source = ...
+ *     final Path target = ...
+ *
+ *     Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
+ *         new SimpleFileVisitor&lt;Path&gt;() {
+ *             &#64;Override
+ *             public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+ *                 throws IOException
+ *             {
+ *                 Path targetdir = target.resolve(source.relativize(dir));
+ *                 try {
+ *                     Files.copy(dir, targetdir);
+ *                 } catch (FileAlreadyExistsException e) {
+ *                      if (!Files.isDirectory(targetdir))
+ *                          throw e;
+ *                 }
+ *                 return CONTINUE;
+ *             }
+ *             &#64;Override
+ *             public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ *                 throws IOException
+ *             {
+ *                 Files.copy(file, target.resolve(source.relativize(file)));
+ *                 return CONTINUE;
+ *             }
+ *         });
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface FileVisitor<T> {
+
+    /**
+     * Invoked for a directory before entries in the directory are visited.
+     *
+     * <p> If this method returns {@link FileVisitResult#CONTINUE CONTINUE},
+     * then entries in the directory are visited. If this method returns {@link
+     * FileVisitResult#SKIP_SUBTREE SKIP_SUBTREE} or {@link
+     * FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS} then entries in the
+     * directory (and any descendants) will not be visited.
+     *
+     * @param   dir
+     *          a reference to the directory
+     * @param   attrs
+     *          the directory's basic attributes
+     *
+     * @return  the visit result
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
+        throws IOException;
+
+    /**
+     * Invoked for a file in a directory.
+     *
+     * @param   file
+     *          a reference to the file
+     * @param   attrs
+     *          the file's basic attributes
+     *
+     * @return  the visit result
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    FileVisitResult visitFile(T file, BasicFileAttributes attrs)
+        throws IOException;
+
+    /**
+     * Invoked for a file that could not be visited. This method is invoked
+     * if the file's attributes could not be read, the file is a directory
+     * that could not be opened, and other reasons.
+     *
+     * @param   file
+     *          a reference to the file
+     * @param   exc
+     *          the I/O exception that prevented the file from being visited
+     *
+     * @return  the visit result
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    FileVisitResult visitFileFailed(T file, IOException exc)
+        throws IOException;
+
+    /**
+     * Invoked for a directory after entries in the directory, and all of their
+     * descendants, have been visited. This method is also invoked when iteration
+     * of the directory completes prematurely (by a {@link #visitFile visitFile}
+     * method returning {@link FileVisitResult#SKIP_SIBLINGS SKIP_SIBLINGS},
+     * or an I/O error when iterating over the directory).
+     *
+     * @param   dir
+     *          a reference to the directory
+     * @param   exc
+     *          {@code null} if the iteration of the directory completes without
+     *          an error; otherwise the I/O exception that caused the iteration
+     *          of the directory to complete prematurely
+     *
+     * @return  the visit result
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    FileVisitResult postVisitDirectory(T dir, IOException exc)
+        throws IOException;
+}
diff --git a/java/nio/file/Files.java b/java/nio/file/Files.java
new file mode 100644
index 0000000..012118c
--- /dev/null
+++ b/java/nio/file/Files.java
@@ -0,0 +1,3787 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.nio.channels.Channels;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.DosFileAttributes;   // javadoc
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileOwnerAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.spi.FileTypeDetector;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiPredicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class consists exclusively of static methods that operate on files,
+ * directories, or other types of files.
+ *
+ * <p> In most cases, the methods defined here will delegate to the associated
+ * file system provider to perform the file operations.
+ *
+ * @since 1.7
+ */
+
+public final class Files {
+    private Files() { }
+
+    /**
+     * Returns the {@code FileSystemProvider} to delegate to.
+     */
+    private static FileSystemProvider provider(Path path) {
+        return path.getFileSystem().provider();
+    }
+
+    /**
+     * Convert a Closeable to a Runnable by converting checked IOException
+     * to UncheckedIOException
+     */
+    private static Runnable asUncheckedRunnable(Closeable c) {
+        return () -> {
+            try {
+                c.close();
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+    }
+
+    // -- File contents --
+
+    /**
+     * Opens a file, returning an input stream to read from the file. The stream
+     * will not be buffered, and is not required to support the {@link
+     * InputStream#mark mark} or {@link InputStream#reset reset} methods. The
+     * stream will be safe for access by multiple concurrent threads. Reading
+     * commences at the beginning of the file. Whether the returned stream is
+     * <i>asynchronously closeable</i> and/or <i>interruptible</i> is highly
+     * file system provider specific and therefore not specified.
+     *
+     * <p> The {@code options} parameter determines how the file is opened.
+     * If no options are present then it is equivalent to opening the file with
+     * the {@link StandardOpenOption#READ READ} option. In addition to the {@code
+     * READ} option, an implementation may also support additional implementation
+     * specific options.
+     *
+     * @param   path
+     *          the path to the file to open
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new input stream
+     *
+     * @throws  IllegalArgumentException
+     *          if an invalid combination of options is specified
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    public static InputStream newInputStream(Path path, OpenOption... options)
+        throws IOException
+    {
+        return provider(path).newInputStream(path, options);
+    }
+
+    /**
+     * Opens or creates a file, returning an output stream that may be used to
+     * write bytes to the file. The resulting stream will not be buffered. The
+     * stream will be safe for access by multiple concurrent threads. Whether
+     * the returned stream is <i>asynchronously closeable</i> and/or
+     * <i>interruptible</i> is highly file system provider specific and
+     * therefore not specified.
+     *
+     * <p> This method opens or creates a file in exactly the manner specified
+     * by the {@link #newByteChannel(Path,Set,FileAttribute[]) newByteChannel}
+     * method with the exception that the {@link StandardOpenOption#READ READ}
+     * option may not be present in the array of options. If no options are
+     * present then this method works as if the {@link StandardOpenOption#CREATE
+     * CREATE}, {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING},
+     * and {@link StandardOpenOption#WRITE WRITE} options are present. In other
+     * words, it opens the file for writing, creating the file if it doesn't
+     * exist, or initially truncating an existing {@link #isRegularFile
+     * regular-file} to a size of {@code 0} if it exists.
+     *
+     * <p> <b>Usage Examples:</b>
+     * <pre>
+     *     Path path = ...
+     *
+     *     // truncate and overwrite an existing file, or create the file if
+     *     // it doesn't initially exist
+     *     OutputStream out = Files.newOutputStream(path);
+     *
+     *     // append to an existing file, fail if the file does not exist
+     *     out = Files.newOutputStream(path, APPEND);
+     *
+     *     // append to an existing file, create file if it doesn't initially exist
+     *     out = Files.newOutputStream(path, CREATE, APPEND);
+     *
+     *     // always create new file, failing if it already exists
+     *     out = Files.newOutputStream(path, CREATE_NEW);
+     * </pre>
+     *
+     * @param   path
+     *          the path to the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new output stream
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code options} contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file. The {@link
+     *          SecurityManager#checkDelete(String) checkDelete} method is
+     *          invoked to check delete access if the file is opened with the
+     *          {@code DELETE_ON_CLOSE} option.
+     */
+    public static OutputStream newOutputStream(Path path, OpenOption... options)
+        throws IOException
+    {
+        return provider(path).newOutputStream(path, options);
+    }
+
+    /**
+     * Opens or creates a file, returning a seekable byte channel to access the
+     * file.
+     *
+     * <p> The {@code options} parameter determines how the file is opened.
+     * The {@link StandardOpenOption#READ READ} and {@link
+     * StandardOpenOption#WRITE WRITE} options determine if the file should be
+     * opened for reading and/or writing. If neither option (or the {@link
+     * StandardOpenOption#APPEND APPEND} option) is present then the file is
+     * opened for reading. By default reading or writing commence at the
+     * beginning of the file.
+     *
+     * <p> In the addition to {@code READ} and {@code WRITE}, the following
+     * options may be present:
+     *
+     * <table border=1 cellpadding=5 summary="Options">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#APPEND APPEND} </td>
+     *   <td> If this option is present then the file is opened for writing and
+     *     each invocation of the channel's {@code write} method first advances
+     *     the position to the end of the file and then writes the requested
+     *     data. Whether the advancement of the position and the writing of the
+     *     data are done in a single atomic operation is system-dependent and
+     *     therefore unspecified. This option may not be used in conjunction
+     *     with the {@code READ} or {@code TRUNCATE_EXISTING} options. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING} </td>
+     *   <td> If this option is present then the existing file is truncated to
+     *   a size of 0 bytes. This option is ignored when the file is opened only
+     *   for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#CREATE_NEW CREATE_NEW} </td>
+     *   <td> If this option is present then a new file is created, failing if
+     *   the file already exists or is a symbolic link. When creating a file the
+     *   check for the existence of the file and the creation of the file if it
+     *   does not exist is atomic with respect to other file system operations.
+     *   This option is ignored when the file is opened only for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#CREATE CREATE} </td>
+     *   <td> If this option is present then an existing file is opened if it
+     *   exists, otherwise a new file is created. This option is ignored if the
+     *   {@code CREATE_NEW} option is also present or the file is opened only
+     *   for reading. </td>
+     * </tr>
+     * <tr>
+     *   <td > {@link StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} </td>
+     *   <td> When this option is present then the implementation makes a
+     *   <em>best effort</em> attempt to delete the file when closed by the
+     *   {@link SeekableByteChannel#close close} method. If the {@code close}
+     *   method is not invoked then a <em>best effort</em> attempt is made to
+     *   delete the file when the Java virtual machine terminates. </td>
+     * </tr>
+     * <tr>
+     *   <td>{@link StandardOpenOption#SPARSE SPARSE} </td>
+     *   <td> When creating a new file this option is a <em>hint</em> that the
+     *   new file will be sparse. This option is ignored when not creating
+     *   a new file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#SYNC SYNC} </td>
+     *   <td> Requires that every update to the file's content or metadata be
+     *   written synchronously to the underlying storage device. (see <a
+     *   href="package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardOpenOption#DSYNC DSYNC} </td>
+     *   <td> Requires that every update to the file's content be written
+     *   synchronously to the underlying storage device. (see <a
+     *   href="package-summary.html#integrity"> Synchronized I/O file
+     *   integrity</a>). </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation may also support additional implementation specific
+     * options.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * file-attributes} to set atomically when a new file is created.
+     *
+     * <p> In the case of the default provider, the returned seekable byte channel
+     * is a {@link java.nio.channels.FileChannel}.
+     *
+     * <p> <b>Usage Examples:</b>
+     * <pre>
+     *     Path path = ...
+     *
+     *     // open file for reading
+     *     ReadableByteChannel rbc = Files.newByteChannel(path, EnumSet.of(READ)));
+     *
+     *     // open file for writing to the end of an existing file, creating
+     *     // the file if it doesn't already exist
+     *     WritableByteChannel wbc = Files.newByteChannel(path, EnumSet.of(CREATE,APPEND));
+     *
+     *     // create file with initial permissions, opening it for both reading and writing
+     *     {@code FileAttribute<Set<PosixFilePermission>> perms = ...}
+     *     SeekableByteChannel sbc = Files.newByteChannel(path, EnumSet.of(CREATE_NEW,READ,WRITE), perms);
+     * </pre>
+     *
+     * @param   path
+     *          the path to the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  a new seekable byte channel
+     *
+     * @throws  IllegalArgumentException
+     *          if the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          if an unsupported open option is specified or the array contains
+     *          attributes that cannot be set atomically when creating the file
+     * @throws  FileAlreadyExistsException
+     *          if a file of that name already exists and the {@link
+     *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the path if the file is
+     *          opened for reading. The {@link SecurityManager#checkWrite(String)
+     *          checkWrite} method is invoked to check write access to the path
+     *          if the file is opened for writing. The {@link
+     *          SecurityManager#checkDelete(String) checkDelete} method is
+     *          invoked to check delete access if the file is opened with the
+     *          {@code DELETE_ON_CLOSE} option.
+     *
+     * @see java.nio.channels.FileChannel#open(Path,Set,FileAttribute[])
+     */
+    public static SeekableByteChannel newByteChannel(Path path,
+                                                     Set<? extends OpenOption> options,
+                                                     FileAttribute<?>... attrs)
+        throws IOException
+    {
+        return provider(path).newByteChannel(path, options, attrs);
+    }
+
+    /**
+     * Opens or creates a file, returning a seekable byte channel to access the
+     * file.
+     *
+     * <p> This method opens or creates a file in exactly the manner specified
+     * by the {@link #newByteChannel(Path,Set,FileAttribute[]) newByteChannel}
+     * method.
+     *
+     * @param   path
+     *          the path to the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new seekable byte channel
+     *
+     * @throws  IllegalArgumentException
+     *          if the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          if an unsupported open option is specified
+     * @throws  FileAlreadyExistsException
+     *          if a file of that name already exists and the {@link
+     *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the path if the file is
+     *          opened for reading. The {@link SecurityManager#checkWrite(String)
+     *          checkWrite} method is invoked to check write access to the path
+     *          if the file is opened for writing. The {@link
+     *          SecurityManager#checkDelete(String) checkDelete} method is
+     *          invoked to check delete access if the file is opened with the
+     *          {@code DELETE_ON_CLOSE} option.
+     *
+     * @see java.nio.channels.FileChannel#open(Path,OpenOption[])
+     */
+    public static SeekableByteChannel newByteChannel(Path path, OpenOption... options)
+        throws IOException
+    {
+        Set<OpenOption> set = new HashSet<OpenOption>(options.length);
+        Collections.addAll(set, options);
+        return newByteChannel(path, set);
+    }
+
+    // -- Directories --
+
+    private static class AcceptAllFilter
+        implements DirectoryStream.Filter<Path>
+    {
+        private AcceptAllFilter() { }
+
+        @Override
+        public boolean accept(Path entry) { return true; }
+
+        static final AcceptAllFilter FILTER = new AcceptAllFilter();
+    }
+
+    /**
+     * Opens a directory, returning a {@link DirectoryStream} to iterate over
+     * all entries in the directory. The elements returned by the directory
+     * stream's {@link DirectoryStream#iterator iterator} are of type {@code
+     * Path}, each one representing an entry in the directory. The {@code Path}
+     * objects are obtained as if by {@link Path#resolve(Path) resolving} the
+     * name of the directory entry against {@code dir}.
+     *
+     * <p> When not using the try-with-resources construct, then directory
+     * stream's {@code close} method should be invoked after iteration is
+     * completed so as to free any resources held for the open directory.
+     *
+     * <p> When an implementation supports operations on entries in the
+     * directory that execute in a race-free manner then the returned directory
+     * stream is a {@link SecureDirectoryStream}.
+     *
+     * @param   dir
+     *          the path to the directory
+     *
+     * @return  a new and open {@code DirectoryStream} object
+     *
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     */
+    public static DirectoryStream<Path> newDirectoryStream(Path dir)
+        throws IOException
+    {
+        return provider(dir).newDirectoryStream(dir, AcceptAllFilter.FILTER);
+    }
+
+    /**
+     * Opens a directory, returning a {@link DirectoryStream} to iterate over
+     * the entries in the directory. The elements returned by the directory
+     * stream's {@link DirectoryStream#iterator iterator} are of type {@code
+     * Path}, each one representing an entry in the directory. The {@code Path}
+     * objects are obtained as if by {@link Path#resolve(Path) resolving} the
+     * name of the directory entry against {@code dir}. The entries returned by
+     * the iterator are filtered by matching the {@code String} representation
+     * of their file names against the given <em>globbing</em> pattern.
+     *
+     * <p> For example, suppose we want to iterate over the files ending with
+     * ".java" in a directory:
+     * <pre>
+     *     Path dir = ...
+     *     try (DirectoryStream&lt;Path&gt; stream = Files.newDirectoryStream(dir, "*.java")) {
+     *         :
+     *     }
+     * </pre>
+     *
+     * <p> The globbing pattern is specified by the {@link
+     * FileSystem#getPathMatcher getPathMatcher} method.
+     *
+     * <p> When not using the try-with-resources construct, then directory
+     * stream's {@code close} method should be invoked after iteration is
+     * completed so as to free any resources held for the open directory.
+     *
+     * <p> When an implementation supports operations on entries in the
+     * directory that execute in a race-free manner then the returned directory
+     * stream is a {@link SecureDirectoryStream}.
+     *
+     * @param   dir
+     *          the path to the directory
+     * @param   glob
+     *          the glob pattern
+     *
+     * @return  a new and open {@code DirectoryStream} object
+     *
+     * @throws  java.util.regex.PatternSyntaxException
+     *          if the pattern is invalid
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     */
+    public static DirectoryStream<Path> newDirectoryStream(Path dir, String glob)
+        throws IOException
+    {
+        // avoid creating a matcher if all entries are required.
+        if (glob.equals("*"))
+            return newDirectoryStream(dir);
+
+        // create a matcher and return a filter that uses it.
+        FileSystem fs = dir.getFileSystem();
+        final PathMatcher matcher = fs.getPathMatcher("glob:" + glob);
+        DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
+            @Override
+            public boolean accept(Path entry)  {
+                return matcher.matches(entry.getFileName());
+            }
+        };
+        return fs.provider().newDirectoryStream(dir, filter);
+    }
+
+    /**
+     * Opens a directory, returning a {@link DirectoryStream} to iterate over
+     * the entries in the directory. The elements returned by the directory
+     * stream's {@link DirectoryStream#iterator iterator} are of type {@code
+     * Path}, each one representing an entry in the directory. The {@code Path}
+     * objects are obtained as if by {@link Path#resolve(Path) resolving} the
+     * name of the directory entry against {@code dir}. The entries returned by
+     * the iterator are filtered by the given {@link DirectoryStream.Filter
+     * filter}.
+     *
+     * <p> When not using the try-with-resources construct, then directory
+     * stream's {@code close} method should be invoked after iteration is
+     * completed so as to free any resources held for the open directory.
+     *
+     * <p> Where the filter terminates due to an uncaught error or runtime
+     * exception then it is propagated to the {@link Iterator#hasNext()
+     * hasNext} or {@link Iterator#next() next} method. Where an {@code
+     * IOException} is thrown, it results in the {@code hasNext} or {@code
+     * next} method throwing a {@link DirectoryIteratorException} with the
+     * {@code IOException} as the cause.
+     *
+     * <p> When an implementation supports operations on entries in the
+     * directory that execute in a race-free manner then the returned directory
+     * stream is a {@link SecureDirectoryStream}.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to iterate over the files in a directory that are
+     * larger than 8K.
+     * <pre>
+     *     DirectoryStream.Filter&lt;Path&gt; filter = new DirectoryStream.Filter&lt;Path&gt;() {
+     *         public boolean accept(Path file) throws IOException {
+     *             return (Files.size(file) &gt; 8192L);
+     *         }
+     *     };
+     *     Path dir = ...
+     *     try (DirectoryStream&lt;Path&gt; stream = Files.newDirectoryStream(dir, filter)) {
+     *         :
+     *     }
+     * </pre>
+     *
+     * @param   dir
+     *          the path to the directory
+     * @param   filter
+     *          the directory stream filter
+     *
+     * @return  a new and open {@code DirectoryStream} object
+     *
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     */
+    public static DirectoryStream<Path> newDirectoryStream(Path dir,
+                                                           DirectoryStream.Filter<? super Path> filter)
+        throws IOException
+    {
+        return provider(dir).newDirectoryStream(dir, filter);
+    }
+
+    // -- Creation and deletion --
+
+    /**
+     * Creates a new and empty file, failing if the file already exists. The
+     * check for the existence of the file and the creation of the new file if
+     * it does not exist are a single operation that is atomic with respect to
+     * all other filesystem activities that might affect the directory.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * file-attributes} to set atomically when creating the file. Each attribute
+     * is identified by its {@link FileAttribute#name name}. If more than one
+     * attribute of the same name is included in the array then all but the last
+     * occurrence is ignored.
+     *
+     * @param   path
+     *          the path to the file to create
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  the file
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the file
+     * @throws  FileAlreadyExistsException
+     *          if a file of that name already exists
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs or the parent directory does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the new file.
+     */
+    public static Path createFile(Path path, FileAttribute<?>... attrs)
+        throws IOException
+    {
+        EnumSet<StandardOpenOption> options =
+            EnumSet.<StandardOpenOption>of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
+        newByteChannel(path, options, attrs).close();
+        return path;
+    }
+
+    /**
+     * Creates a new directory. The check for the existence of the file and the
+     * creation of the directory if it does not exist are a single operation
+     * that is atomic with respect to all other filesystem activities that might
+     * affect the directory. The {@link #createDirectories createDirectories}
+     * method should be used where it is required to create all nonexistent
+     * parent directories first.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * file-attributes} to set atomically when creating the directory. Each
+     * attribute is identified by its {@link FileAttribute#name name}. If more
+     * than one attribute of the same name is included in the array then all but
+     * the last occurrence is ignored.
+     *
+     * @param   dir
+     *          the directory to create
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the directory
+     *
+     * @return  the directory
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  FileAlreadyExistsException
+     *          if a directory could not otherwise be created because a file of
+     *          that name already exists <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs or the parent directory does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the new directory.
+     */
+    public static Path createDirectory(Path dir, FileAttribute<?>... attrs)
+        throws IOException
+    {
+        provider(dir).createDirectory(dir, attrs);
+        return dir;
+    }
+
+    /**
+     * Creates a directory by creating all nonexistent parent directories first.
+     * Unlike the {@link #createDirectory createDirectory} method, an exception
+     * is not thrown if the directory could not be created because it already
+     * exists.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * file-attributes} to set atomically when creating the nonexistent
+     * directories. Each file attribute is identified by its {@link
+     * FileAttribute#name name}. If more than one attribute of the same name is
+     * included in the array then all but the last occurrence is ignored.
+     *
+     * <p> If this method fails, then it may do so after creating some, but not
+     * all, of the parent directories.
+     *
+     * @param   dir
+     *          the directory to create
+     *
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the directory
+     *
+     * @return  the directory
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  FileAlreadyExistsException
+     *          if {@code dir} exists but is not a directory <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          in the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked prior to attempting to create a directory and
+     *          its {@link SecurityManager#checkRead(String) checkRead} is
+     *          invoked for each parent directory that is checked. If {@code
+     *          dir} is not an absolute path then its {@link Path#toAbsolutePath
+     *          toAbsolutePath} may need to be invoked to get its absolute path.
+     *          This may invoke the security manager's {@link
+     *          SecurityManager#checkPropertyAccess(String) checkPropertyAccess}
+     *          method to check access to the system property {@code user.dir}
+     */
+    public static Path createDirectories(Path dir, FileAttribute<?>... attrs)
+        throws IOException
+    {
+        // attempt to create the directory
+        try {
+            createAndCheckIsDirectory(dir, attrs);
+            return dir;
+        } catch (FileAlreadyExistsException x) {
+            // file exists and is not a directory
+            throw x;
+        } catch (IOException x) {
+            // parent may not exist or other reason
+        }
+        SecurityException se = null;
+        try {
+            dir = dir.toAbsolutePath();
+        } catch (SecurityException x) {
+            // don't have permission to get absolute path
+            se = x;
+        }
+        // find a decendent that exists
+        Path parent = dir.getParent();
+        while (parent != null) {
+            try {
+                provider(parent).checkAccess(parent);
+                break;
+            } catch (NoSuchFileException x) {
+                // does not exist
+            }
+            parent = parent.getParent();
+        }
+        if (parent == null) {
+            // unable to find existing parent
+            if (se == null) {
+                throw new FileSystemException(dir.toString(), null,
+                    "Unable to determine if root directory exists");
+            } else {
+                throw se;
+            }
+        }
+
+        // create directories
+        Path child = parent;
+        for (Path name: parent.relativize(dir)) {
+            child = child.resolve(name);
+            createAndCheckIsDirectory(child, attrs);
+        }
+        return dir;
+    }
+
+    /**
+     * Used by createDirectories to attempt to create a directory. A no-op
+     * if the directory already exists.
+     */
+    private static void createAndCheckIsDirectory(Path dir,
+                                                  FileAttribute<?>... attrs)
+        throws IOException
+    {
+        try {
+            createDirectory(dir, attrs);
+        } catch (FileAlreadyExistsException x) {
+            if (!isDirectory(dir, LinkOption.NOFOLLOW_LINKS))
+                throw x;
+        }
+    }
+
+    /**
+     * Creates a new empty file in the specified directory, using the given
+     * prefix and suffix strings to generate its name. The resulting
+     * {@code Path} is associated with the same {@code FileSystem} as the given
+     * directory.
+     *
+     * <p> The details as to how the name of the file is constructed is
+     * implementation dependent and therefore not specified. Where possible
+     * the {@code prefix} and {@code suffix} are used to construct candidate
+     * names in the same manner as the {@link
+     * java.io.File#createTempFile(String,String,File)} method.
+     *
+     * <p> As with the {@code File.createTempFile} methods, this method is only
+     * part of a temporary-file facility. Where used as a <em>work files</em>,
+     * the resulting file may be opened using the {@link
+     * StandardOpenOption#DELETE_ON_CLOSE DELETE_ON_CLOSE} option so that the
+     * file is deleted when the appropriate {@code close} method is invoked.
+     * Alternatively, a {@link Runtime#addShutdownHook shutdown-hook}, or the
+     * {@link java.io.File#deleteOnExit} mechanism may be used to delete the
+     * file automatically.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * file-attributes} to set atomically when creating the file. Each attribute
+     * is identified by its {@link FileAttribute#name name}. If more than one
+     * attribute of the same name is included in the array then all but the last
+     * occurrence is ignored. When no file attributes are specified, then the
+     * resulting file may have more restrictive access permissions to files
+     * created by the {@link java.io.File#createTempFile(String,String,File)}
+     * method.
+     *
+     * @param   dir
+     *          the path to directory in which to create the file
+     * @param   prefix
+     *          the prefix string to be used in generating the file's name;
+     *          may be {@code null}
+     * @param   suffix
+     *          the suffix string to be used in generating the file's name;
+     *          may be {@code null}, in which case "{@code .tmp}" is used
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  the path to the newly created file that did not exist before
+     *          this method was invoked
+     *
+     * @throws  IllegalArgumentException
+     *          if the prefix or suffix parameters cannot be used to generate
+     *          a candidate file name
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  IOException
+     *          if an I/O error occurs or {@code dir} does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     */
+    public static Path createTempFile(Path dir,
+                                      String prefix,
+                                      String suffix,
+                                      FileAttribute<?>... attrs)
+        throws IOException
+    {
+        return TempFileHelper.createTempFile(Objects.requireNonNull(dir),
+                                             prefix, suffix, attrs);
+    }
+
+    /**
+     * Creates an empty file in the default temporary-file directory, using
+     * the given prefix and suffix to generate its name. The resulting {@code
+     * Path} is associated with the default {@code FileSystem}.
+     *
+     * <p> This method works in exactly the manner specified by the
+     * {@link #createTempFile(Path,String,String,FileAttribute[])} method for
+     * the case that the {@code dir} parameter is the temporary-file directory.
+     *
+     * @param   prefix
+     *          the prefix string to be used in generating the file's name;
+     *          may be {@code null}
+     * @param   suffix
+     *          the suffix string to be used in generating the file's name;
+     *          may be {@code null}, in which case "{@code .tmp}" is used
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  the path to the newly created file that did not exist before
+     *          this method was invoked
+     *
+     * @throws  IllegalArgumentException
+     *          if the prefix or suffix parameters cannot be used to generate
+     *          a candidate file name
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  IOException
+     *          if an I/O error occurs or the temporary-file directory does not
+     *          exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     */
+    public static Path createTempFile(String prefix,
+                                      String suffix,
+                                      FileAttribute<?>... attrs)
+        throws IOException
+    {
+        return TempFileHelper.createTempFile(null, prefix, suffix, attrs);
+    }
+
+    /**
+     * Creates a new directory in the specified directory, using the given
+     * prefix to generate its name.  The resulting {@code Path} is associated
+     * with the same {@code FileSystem} as the given directory.
+     *
+     * <p> The details as to how the name of the directory is constructed is
+     * implementation dependent and therefore not specified. Where possible
+     * the {@code prefix} is used to construct candidate names.
+     *
+     * <p> As with the {@code createTempFile} methods, this method is only
+     * part of a temporary-file facility. A {@link Runtime#addShutdownHook
+     * shutdown-hook}, or the {@link java.io.File#deleteOnExit} mechanism may be
+     * used to delete the directory automatically.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * file-attributes} to set atomically when creating the directory. Each
+     * attribute is identified by its {@link FileAttribute#name name}. If more
+     * than one attribute of the same name is included in the array then all but
+     * the last occurrence is ignored.
+     *
+     * @param   dir
+     *          the path to directory in which to create the directory
+     * @param   prefix
+     *          the prefix string to be used in generating the directory's name;
+     *          may be {@code null}
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the directory
+     *
+     * @return  the path to the newly created directory that did not exist before
+     *          this method was invoked
+     *
+     * @throws  IllegalArgumentException
+     *          if the prefix cannot be used to generate a candidate directory name
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  IOException
+     *          if an I/O error occurs or {@code dir} does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access when creating the
+     *          directory.
+     */
+    public static Path createTempDirectory(Path dir,
+                                           String prefix,
+                                           FileAttribute<?>... attrs)
+        throws IOException
+    {
+        return TempFileHelper.createTempDirectory(Objects.requireNonNull(dir),
+                                                  prefix, attrs);
+    }
+
+    /**
+     * Creates a new directory in the default temporary-file directory, using
+     * the given prefix to generate its name. The resulting {@code Path} is
+     * associated with the default {@code FileSystem}.
+     *
+     * <p> This method works in exactly the manner specified by {@link
+     * #createTempDirectory(Path,String,FileAttribute[])} method for the case
+     * that the {@code dir} parameter is the temporary-file directory.
+     *
+     * @param   prefix
+     *          the prefix string to be used in generating the directory's name;
+     *          may be {@code null}
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the directory
+     *
+     * @return  the path to the newly created directory that did not exist before
+     *          this method was invoked
+     *
+     * @throws  IllegalArgumentException
+     *          if the prefix cannot be used to generate a candidate directory name
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  IOException
+     *          if an I/O error occurs or the temporary-file directory does not
+     *          exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access when creating the
+     *          directory.
+     */
+    public static Path createTempDirectory(String prefix,
+                                           FileAttribute<?>... attrs)
+        throws IOException
+    {
+        return TempFileHelper.createTempDirectory(null, prefix, attrs);
+    }
+
+    /**
+     * Creates a symbolic link to a target <i>(optional operation)</i>.
+     *
+     * <p> The {@code target} parameter is the target of the link. It may be an
+     * {@link Path#isAbsolute absolute} or relative path and may not exist. When
+     * the target is a relative path then file system operations on the resulting
+     * link are relative to the path of the link.
+     *
+     * <p> The {@code attrs} parameter is optional {@link FileAttribute
+     * attributes} to set atomically when creating the link. Each attribute is
+     * identified by its {@link FileAttribute#name name}. If more than one attribute
+     * of the same name is included in the array then all but the last occurrence
+     * is ignored.
+     *
+     * <p> Where symbolic links are supported, but the underlying {@link FileStore}
+     * does not support symbolic links, then this may fail with an {@link
+     * IOException}. Additionally, some operating systems may require that the
+     * Java virtual machine be started with implementation specific privileges to
+     * create symbolic links, in which case this method may throw {@code IOException}.
+     *
+     * @param   link
+     *          the path of the symbolic link to create
+     * @param   target
+     *          the target of the symbolic link
+     * @param   attrs
+     *          the array of attributes to set atomically when creating the
+     *          symbolic link
+     *
+     * @return  the path to the symbolic link
+     *
+     * @throws  UnsupportedOperationException
+     *          if the implementation does not support symbolic links or the
+     *          array contains an attribute that cannot be set atomically when
+     *          creating the symbolic link
+     * @throws  FileAlreadyExistsException
+     *          if a file with the name already exists <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, it denies {@link LinkPermission}<tt>("symbolic")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the path of the symbolic link.
+     */
+    public static Path createSymbolicLink(Path link, Path target,
+                                          FileAttribute<?>... attrs)
+        throws IOException
+    {
+        provider(link).createSymbolicLink(link, target, attrs);
+        return link;
+    }
+
+    /**
+     * Creates a new link (directory entry) for an existing file <i>(optional
+     * operation)</i>.
+     *
+     * <p> The {@code link} parameter locates the directory entry to create.
+     * The {@code existing} parameter is the path to an existing file. This
+     * method creates a new directory entry for the file so that it can be
+     * accessed using {@code link} as the path. On some file systems this is
+     * known as creating a "hard link". Whether the file attributes are
+     * maintained for the file or for each directory entry is file system
+     * specific and therefore not specified. Typically, a file system requires
+     * that all links (directory entries) for a file be on the same file system.
+     * Furthermore, on some platforms, the Java virtual machine may require to
+     * be started with implementation specific privileges to create hard links
+     * or to create links to directories.
+     *
+     * @param   link
+     *          the link (directory entry) to create
+     * @param   existing
+     *          a path to an existing file
+     *
+     * @return  the path to the link (directory entry)
+     *
+     * @throws  UnsupportedOperationException
+     *          if the implementation does not support adding an existing file
+     *          to a directory
+     * @throws  FileAlreadyExistsException
+     *          if the entry could not otherwise be created because a file of
+     *          that name already exists <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, it denies {@link LinkPermission}<tt>("hard")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to either the link or the
+     *          existing file.
+     */
+    public static Path createLink(Path link, Path existing) throws IOException {
+        provider(link).createLink(link, existing);
+        return link;
+    }
+
+    /**
+     * Deletes a file.
+     *
+     * <p> An implementation may require to examine the file to determine if the
+     * file is a directory. Consequently this method may not be atomic with respect
+     * to other file system operations.  If the file is a symbolic link then the
+     * symbolic link itself, not the final target of the link, is deleted.
+     *
+     * <p> If the file is a directory then the directory must be empty. In some
+     * implementations a directory has entries for special files or links that
+     * are created when the directory is created. In such implementations a
+     * directory is considered empty when only the special entries exist.
+     * This method can be used with the {@link #walkFileTree walkFileTree}
+     * method to delete a directory and all entries in the directory, or an
+     * entire <i>file-tree</i> where required.
+     *
+     * <p> On some operating systems it may not be possible to remove a file when
+     * it is open and in use by this Java virtual machine or other programs.
+     *
+     * @param   path
+     *          the path to the file to delete
+     *
+     * @throws  NoSuchFileException
+     *          if the file does not exist <i>(optional specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          if the file is a directory and could not otherwise be deleted
+     *          because the directory is not empty <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkDelete(String)} method
+     *          is invoked to check delete access to the file
+     */
+    public static void delete(Path path) throws IOException {
+        provider(path).delete(path);
+    }
+
+    /**
+     * Deletes a file if it exists.
+     *
+     * <p> As with the {@link #delete(Path) delete(Path)} method, an
+     * implementation may need to examine the file to determine if the file is a
+     * directory. Consequently this method may not be atomic with respect to
+     * other file system operations.  If the file is a symbolic link, then the
+     * symbolic link itself, not the final target of the link, is deleted.
+     *
+     * <p> If the file is a directory then the directory must be empty. In some
+     * implementations a directory has entries for special files or links that
+     * are created when the directory is created. In such implementations a
+     * directory is considered empty when only the special entries exist.
+     *
+     * <p> On some operating systems it may not be possible to remove a file when
+     * it is open and in use by this Java virtual machine or other programs.
+     *
+     * @param   path
+     *          the path to the file to delete
+     *
+     * @return  {@code true} if the file was deleted by this method; {@code
+     *          false} if the file could not be deleted because it did not
+     *          exist
+     *
+     * @throws  DirectoryNotEmptyException
+     *          if the file is a directory and could not otherwise be deleted
+     *          because the directory is not empty <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkDelete(String)} method
+     *          is invoked to check delete access to the file.
+     */
+    public static boolean deleteIfExists(Path path) throws IOException {
+        return provider(path).deleteIfExists(path);
+    }
+
+    // -- Copying and moving files --
+
+    /**
+     * Copy a file to a target file.
+     *
+     * <p> This method copies a file to the target file with the {@code
+     * options} parameter specifying how the copy is performed. By default, the
+     * copy fails if the target file already exists or is a symbolic link,
+     * except if the source and target are the {@link #isSameFile same} file, in
+     * which case the method completes without copying the file. File attributes
+     * are not required to be copied to the target file. If symbolic links are
+     * supported, and the file is a symbolic link, then the final target of the
+     * link is copied. If the file is a directory then it creates an empty
+     * directory in the target location (entries in the directory are not
+     * copied). This method can be used with the {@link #walkFileTree
+     * walkFileTree} method to copy a directory and all entries in the directory,
+     * or an entire <i>file-tree</i> where required.
+     *
+     * <p> The {@code options} parameter may include any of the following:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} </td>
+     *   <td> If the target file exists, then the target file is replaced if it
+     *     is not a non-empty directory. If the target file exists and is a
+     *     symbolic link, then the symbolic link itself, not the target of
+     *     the link, is replaced. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#COPY_ATTRIBUTES COPY_ATTRIBUTES} </td>
+     *   <td> Attempts to copy the file attributes associated with this file to
+     *     the target file. The exact file attributes that are copied is platform
+     *     and file system dependent and therefore unspecified. Minimally, the
+     *     {@link BasicFileAttributes#lastModifiedTime last-modified-time} is
+     *     copied to the target file if supported by both the source and target
+     *     file stores. Copying of file timestamps may result in precision
+     *     loss. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} </td>
+     *   <td> Symbolic links are not followed. If the file is a symbolic link,
+     *     then the symbolic link itself, not the target of the link, is copied.
+     *     It is implementation specific if file attributes can be copied to the
+     *     new link. In other words, the {@code COPY_ATTRIBUTES} option may be
+     *     ignored when copying a symbolic link. </td>
+     * </tr>
+     * </table>
+     *
+     * <p> An implementation of this interface may support additional
+     * implementation specific options.
+     *
+     * <p> Copying a file is not an atomic operation. If an {@link IOException}
+     * is thrown, then it is possible that the target file is incomplete or some
+     * of its file attributes have not been copied from the source file. When
+     * the {@code REPLACE_EXISTING} option is specified and the target file
+     * exists, then the target file is replaced. The check for the existence of
+     * the file and the creation of the new file may not be atomic with respect
+     * to other file system activities.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to copy a file into a directory, giving it the same file
+     * name as the source file:
+     * <pre>
+     *     Path source = ...
+     *     Path newdir = ...
+     *     Files.copy(source, newdir.resolve(source.getFileName());
+     * </pre>
+     *
+     * @param   source
+     *          the path to the file to copy
+     * @param   target
+     *          the path to the target file (may be associated with a different
+     *          provider to the source path)
+     * @param   options
+     *          options specifying how the copy should be done
+     *
+     * @return  the path to the target file
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains a copy option that is not supported
+     * @throws  FileAlreadyExistsException
+     *          if the target file exists but cannot be replaced because the
+     *          {@code REPLACE_EXISTING} option is not specified <i>(optional
+     *          specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          the {@code REPLACE_EXISTING} option is specified but the file
+     *          cannot be replaced because it is a non-empty directory
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the source file, the
+     *          {@link SecurityManager#checkWrite(String) checkWrite} is invoked
+     *          to check write access to the target file. If a symbolic link is
+     *          copied the security manager is invoked to check {@link
+     *          LinkPermission}{@code ("symbolic")}.
+     */
+    public static Path copy(Path source, Path target, CopyOption... options)
+        throws IOException
+    {
+        FileSystemProvider provider = provider(source);
+        if (provider(target) == provider) {
+            // same provider
+            provider.copy(source, target, options);
+        } else {
+            // different providers
+            CopyMoveHelper.copyToForeignTarget(source, target, options);
+        }
+        return target;
+    }
+
+    /**
+     * Move or rename a file to a target file.
+     *
+     * <p> By default, this method attempts to move the file to the target
+     * file, failing if the target file exists except if the source and
+     * target are the {@link #isSameFile same} file, in which case this method
+     * has no effect. If the file is a symbolic link then the symbolic link
+     * itself, not the target of the link, is moved. This method may be
+     * invoked to move an empty directory. In some implementations a directory
+     * has entries for special files or links that are created when the
+     * directory is created. In such implementations a directory is considered
+     * empty when only the special entries exist. When invoked to move a
+     * directory that is not empty then the directory is moved if it does not
+     * require moving the entries in the directory.  For example, renaming a
+     * directory on the same {@link FileStore} will usually not require moving
+     * the entries in the directory. When moving a directory requires that its
+     * entries be moved then this method fails (by throwing an {@code
+     * IOException}). To move a <i>file tree</i> may involve copying rather
+     * than moving directories and this can be done using the {@link
+     * #copy copy} method in conjunction with the {@link
+     * #walkFileTree Files.walkFileTree} utility method.
+     *
+     * <p> The {@code options} parameter may include any of the following:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Option</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#REPLACE_EXISTING REPLACE_EXISTING} </td>
+     *   <td> If the target file exists, then the target file is replaced if it
+     *     is not a non-empty directory. If the target file exists and is a
+     *     symbolic link, then the symbolic link itself, not the target of
+     *     the link, is replaced. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} </td>
+     *   <td> The move is performed as an atomic file system operation and all
+     *     other options are ignored. If the target file exists then it is
+     *     implementation specific if the existing file is replaced or this method
+     *     fails by throwing an {@link IOException}. If the move cannot be
+     *     performed as an atomic file system operation then {@link
+     *     AtomicMoveNotSupportedException} is thrown. This can arise, for
+     *     example, when the target location is on a different {@code FileStore}
+     *     and would require that the file be copied, or target location is
+     *     associated with a different provider to this object. </td>
+     * </table>
+     *
+     * <p> An implementation of this interface may support additional
+     * implementation specific options.
+     *
+     * <p> Moving a file will copy the {@link
+     * BasicFileAttributes#lastModifiedTime last-modified-time} to the target
+     * file if supported by both source and target file stores. Copying of file
+     * timestamps may result in precision loss. An implementation may also
+     * attempt to copy other file attributes but is not required to fail if the
+     * file attributes cannot be copied. When the move is performed as
+     * a non-atomic operation, and an {@code IOException} is thrown, then the
+     * state of the files is not defined. The original file and the target file
+     * may both exist, the target file may be incomplete or some of its file
+     * attributes may not been copied from the original file.
+     *
+     * <p> <b>Usage Examples:</b>
+     * Suppose we want to rename a file to "newname", keeping the file in the
+     * same directory:
+     * <pre>
+     *     Path source = ...
+     *     Files.move(source, source.resolveSibling("newname"));
+     * </pre>
+     * Alternatively, suppose we want to move a file to new directory, keeping
+     * the same file name, and replacing any existing file of that name in the
+     * directory:
+     * <pre>
+     *     Path source = ...
+     *     Path newdir = ...
+     *     Files.move(source, newdir.resolve(source.getFileName()), REPLACE_EXISTING);
+     * </pre>
+     *
+     * @param   source
+     *          the path to the file to move
+     * @param   target
+     *          the path to the target file (may be associated with a different
+     *          provider to the source path)
+     * @param   options
+     *          options specifying how the move should be done
+     *
+     * @return  the path to the target file
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains a copy option that is not supported
+     * @throws  FileAlreadyExistsException
+     *          if the target file exists but cannot be replaced because the
+     *          {@code REPLACE_EXISTING} option is not specified <i>(optional
+     *          specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          the {@code REPLACE_EXISTING} option is specified but the file
+     *          cannot be replaced because it is a non-empty directory
+     *          <i>(optional specific exception)</i>
+     * @throws  AtomicMoveNotSupportedException
+     *          if the options array contains the {@code ATOMIC_MOVE} option but
+     *          the file cannot be moved as an atomic file system operation.
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to both the source and
+     *          target file.
+     */
+    public static Path move(Path source, Path target, CopyOption... options)
+        throws IOException
+    {
+        FileSystemProvider provider = provider(source);
+        if (provider(target) == provider) {
+            // same provider
+            provider.move(source, target, options);
+        } else {
+            // different providers
+            CopyMoveHelper.moveToForeignTarget(source, target, options);
+        }
+        return target;
+    }
+
+    // -- Miscellenous --
+
+    /**
+     * Reads the target of a symbolic link <i>(optional operation)</i>.
+     *
+     * <p> If the file system supports <a href="package-summary.html#links">symbolic
+     * links</a> then this method is used to read the target of the link, failing
+     * if the file is not a symbolic link. The target of the link need not exist.
+     * The returned {@code Path} object will be associated with the same file
+     * system as {@code link}.
+     *
+     * @param   link
+     *          the path to the symbolic link
+     *
+     * @return  a {@code Path} object representing the target of the link
+     *
+     * @throws  UnsupportedOperationException
+     *          if the implementation does not support symbolic links
+     * @throws  NotLinkException
+     *          if the target could otherwise not be read because the file
+     *          is not a symbolic link <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, it checks that {@code FilePermission} has been
+     *          granted with the "{@code readlink}" action to read the link.
+     */
+    public static Path readSymbolicLink(Path link) throws IOException {
+        return provider(link).readSymbolicLink(link);
+    }
+
+    /**
+     * Returns the {@link FileStore} representing the file store where a file
+     * is located.
+     *
+     * <p> Once a reference to the {@code FileStore} is obtained it is
+     * implementation specific if operations on the returned {@code FileStore},
+     * or {@link FileStoreAttributeView} objects obtained from it, continue
+     * to depend on the existence of the file. In particular the behavior is not
+     * defined for the case that the file is deleted or moved to a different
+     * file store.
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  the file store where the file is stored
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file, and in
+     *          addition it checks {@link RuntimePermission}<tt>
+     *          ("getFileStoreAttributes")</tt>
+     */
+    public static FileStore getFileStore(Path path) throws IOException {
+        return provider(path).getFileStore(path);
+    }
+
+    /**
+     * Tests if two paths locate the same file.
+     *
+     * <p> If both {@code Path} objects are {@link Path#equals(Object) equal}
+     * then this method returns {@code true} without checking if the file exists.
+     * If the two {@code Path} objects are associated with different providers
+     * then this method returns {@code false}. Otherwise, this method checks if
+     * both {@code Path} objects locate the same file, and depending on the
+     * implementation, may require to open or access both files.
+     *
+     * <p> If the file system and files remain static, then this method implements
+     * an equivalence relation for non-null {@code Paths}.
+     * <ul>
+     * <li>It is <i>reflexive</i>: for {@code Path} {@code f},
+     *     {@code isSameFile(f,f)} should return {@code true}.
+     * <li>It is <i>symmetric</i>: for two {@code Paths} {@code f} and {@code g},
+     *     {@code isSameFile(f,g)} will equal {@code isSameFile(g,f)}.
+     * <li>It is <i>transitive</i>: for three {@code Paths}
+     *     {@code f}, {@code g}, and {@code h}, if {@code isSameFile(f,g)} returns
+     *     {@code true} and {@code isSameFile(g,h)} returns {@code true}, then
+     *     {@code isSameFile(f,h)} will return return {@code true}.
+     * </ul>
+     *
+     * @param   path
+     *          one path to the file
+     * @param   path2
+     *          the other path
+     *
+     * @return  {@code true} if, and only if, the two paths locate the same file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to both files.
+     *
+     * @see java.nio.file.attribute.BasicFileAttributes#fileKey
+     */
+    public static boolean isSameFile(Path path, Path path2) throws IOException {
+        return provider(path).isSameFile(path, path2);
+    }
+
+    /**
+     * Tells whether or not a file is considered <em>hidden</em>. The exact
+     * definition of hidden is platform or provider dependent. On UNIX for
+     * example a file is considered to be hidden if its name begins with a
+     * period character ('.'). On Windows a file is considered hidden if it
+     * isn't a directory and the DOS {@link DosFileAttributes#isHidden hidden}
+     * attribute is set.
+     *
+     * <p> Depending on the implementation this method may require to access
+     * the file system to determine if the file is considered hidden.
+     *
+     * @param   path
+     *          the path to the file to test
+     *
+     * @return  {@code true} if the file is considered hidden
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    public static boolean isHidden(Path path) throws IOException {
+        return provider(path).isHidden(path);
+    }
+
+    // lazy loading of default and installed file type detectors
+    private static class FileTypeDetectors{
+        static final FileTypeDetector defaultFileTypeDetector =
+            createDefaultFileTypeDetector();
+        static final List<FileTypeDetector> installeDetectors =
+            loadInstalledDetectors();
+
+        // creates the default file type detector
+        private static FileTypeDetector createDefaultFileTypeDetector() {
+            return AccessController
+                .doPrivileged(new PrivilegedAction<FileTypeDetector>() {
+                    @Override public FileTypeDetector run() {
+                        return sun.nio.fs.DefaultFileTypeDetector.create();
+                }});
+        }
+
+        // loads all installed file type detectors
+        private static List<FileTypeDetector> loadInstalledDetectors() {
+            return AccessController
+                .doPrivileged(new PrivilegedAction<List<FileTypeDetector>>() {
+                    @Override public List<FileTypeDetector> run() {
+                        List<FileTypeDetector> list = new ArrayList<>();
+                        ServiceLoader<FileTypeDetector> loader = ServiceLoader
+                            .load(FileTypeDetector.class, ClassLoader.getSystemClassLoader());
+                        for (FileTypeDetector detector: loader) {
+                            list.add(detector);
+                        }
+                        return list;
+                }});
+        }
+    }
+
+    /**
+     * Probes the content type of a file.
+     *
+     * <p> This method uses the installed {@link FileTypeDetector} implementations
+     * to probe the given file to determine its content type. Each file type
+     * detector's {@link FileTypeDetector#probeContentType probeContentType} is
+     * invoked, in turn, to probe the file type. If the file is recognized then
+     * the content type is returned. If the file is not recognized by any of the
+     * installed file type detectors then a system-default file type detector is
+     * invoked to guess the content type.
+     *
+     * <p> A given invocation of the Java virtual machine maintains a system-wide
+     * list of file type detectors. Installed file type detectors are loaded
+     * using the service-provider loading facility defined by the {@link ServiceLoader}
+     * class. Installed file type detectors are loaded using the system class
+     * loader. If the system class loader cannot be found then the extension class
+     * loader is used; If the extension class loader cannot be found then the
+     * bootstrap class loader is used. File type detectors are typically installed
+     * by placing them in a JAR file on the application class path or in the
+     * extension directory, the JAR file contains a provider-configuration file
+     * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory
+     * {@code META-INF/services}, and the file lists one or more fully-qualified
+     * names of concrete subclass of {@code FileTypeDetector } that have a zero
+     * argument constructor. If the process of locating or instantiating the
+     * installed file type detectors fails then an unspecified error is thrown.
+     * The ordering that installed providers are located is implementation
+     * specific.
+     *
+     * <p> The return value of this method is the string form of the value of a
+     * Multipurpose Internet Mail Extension (MIME) content type as
+     * defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC&nbsp;2045:
+     * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet
+     * Message Bodies</i></a>. The string is guaranteed to be parsable according
+     * to the grammar in the RFC.
+     *
+     * @param   path
+     *          the path to the file to probe
+     *
+     * @return  The content type of the file, or {@code null} if the content
+     *          type cannot be determined
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required by a file type detector implementation.
+     */
+    public static String probeContentType(Path path)
+        throws IOException
+    {
+        // try installed file type detectors
+        for (FileTypeDetector detector: FileTypeDetectors.installeDetectors) {
+            String result = detector.probeContentType(path);
+            if (result != null)
+                return result;
+        }
+
+        // fallback to default
+        return FileTypeDetectors.defaultFileTypeDetector.probeContentType(path);
+    }
+
+    // -- File Attributes --
+
+    /**
+     * Returns a file attribute view of a given type.
+     *
+     * <p> A file attribute view provides a read-only or updatable view of a
+     * set of file attributes. This method is intended to be used where the file
+     * attribute view defines type-safe methods to read or update the file
+     * attributes. The {@code type} parameter is the type of the attribute view
+     * required and the method returns an instance of that type if supported.
+     * The {@link BasicFileAttributeView} type supports access to the basic
+     * attributes of a file. Invoking this method to select a file attribute
+     * view of that type will always return an instance of that class.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled by the resulting file attribute view for the case that the
+     * file is a symbolic link. By default, symbolic links are followed. If the
+     * option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is present then
+     * symbolic links are not followed. This option is ignored by implementations
+     * that do not support symbolic links.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want read or set a file's ACL, if supported:
+     * <pre>
+     *     Path path = ...
+     *     AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class);
+     *     if (view != null) {
+     *         List&lt;AclEntry&gt; acl = view.getAcl();
+     *         :
+     *     }
+     * </pre>
+     *
+     * @param   <V>
+     *          The {@code FileAttributeView} type
+     * @param   path
+     *          the path to the file
+     * @param   type
+     *          the {@code Class} object corresponding to the file attribute view
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a file attribute view of the specified type, or {@code null} if
+     *          the attribute view type is not available
+     */
+    public static <V extends FileAttributeView> V getFileAttributeView(Path path,
+                                                                       Class<V> type,
+                                                                       LinkOption... options)
+    {
+        return provider(path).getFileAttributeView(path, type, options);
+    }
+
+    /**
+     * Reads a file's attributes as a bulk operation.
+     *
+     * <p> The {@code type} parameter is the type of the attributes required
+     * and this method returns an instance of that type if supported. All
+     * implementations support a basic set of file attributes and so invoking
+     * this method with a  {@code type} parameter of {@code
+     * BasicFileAttributes.class} will not throw {@code
+     * UnsupportedOperationException}.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> It is implementation specific if all file attributes are read as an
+     * atomic operation with respect to other file system operations.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to read a file's attributes in bulk:
+     * <pre>
+     *    Path path = ...
+     *    BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
+     * </pre>
+     * Alternatively, suppose we want to read file's POSIX attributes without
+     * following symbolic links:
+     * <pre>
+     *    PosixFileAttributes attrs = Files.readAttributes(path, PosixFileAttributes.class, NOFOLLOW_LINKS);
+     * </pre>
+     *
+     * @param   <A>
+     *          The {@code BasicFileAttributes} type
+     * @param   path
+     *          the path to the file
+     * @param   type
+     *          the {@code Class} of the file attributes required
+     *          to read
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  the file attributes
+     *
+     * @throws  UnsupportedOperationException
+     *          if an attributes of the given type are not supported
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file. If this
+     *          method is invoked to read security sensitive attributes then the
+     *          security manager may be invoke to check for additional permissions.
+     */
+    public static <A extends BasicFileAttributes> A readAttributes(Path path,
+                                                                   Class<A> type,
+                                                                   LinkOption... options)
+        throws IOException
+    {
+        return provider(path).readAttributes(path, type, options);
+    }
+
+    /**
+     * Sets the value of a file attribute.
+     *
+     * <p> The {@code attribute} parameter identifies the attribute to be set
+     * and takes the form:
+     * <blockquote>
+     * [<i>view-name</i><b>:</b>]<i>attribute-name</i>
+     * </blockquote>
+     * where square brackets [...] delineate an optional component and the
+     * character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> is the {@link FileAttributeView#name name} of a {@link
+     * FileAttributeView} that identifies a set of file attributes. If not
+     * specified then it defaults to {@code "basic"}, the name of the file
+     * attribute view that identifies the basic set of file attributes common to
+     * many file systems. <i>attribute-name</i> is the name of the attribute
+     * within the set.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is set. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to set the DOS "hidden" attribute:
+     * <pre>
+     *    Path path = ...
+     *    Files.setAttribute(path, "dos:hidden", true);
+     * </pre>
+     *
+     * @param   path
+     *          the path to the file
+     * @param   attribute
+     *          the attribute to set
+     * @param   value
+     *          the attribute value
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  the {@code path} parameter
+     *
+     * @throws  UnsupportedOperationException
+     *          if the attribute view is not available
+     * @throws  IllegalArgumentException
+     *          if the attribute name is not specified, or is not recognized, or
+     *          the attribute value is of the correct type but has an
+     *          inappropriate value
+     * @throws  ClassCastException
+     *          if the attribute value is not of the expected type or is a
+     *          collection containing elements that are not of the expected
+     *          type
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file. If this method is invoked
+     *          to set security sensitive attributes then the security manager
+     *          may be invoked to check for additional permissions.
+     */
+    public static Path setAttribute(Path path, String attribute, Object value,
+                                    LinkOption... options)
+        throws IOException
+    {
+        provider(path).setAttribute(path, attribute, value, options);
+        return path;
+    }
+
+    /**
+     * Reads the value of a file attribute.
+     *
+     * <p> The {@code attribute} parameter identifies the attribute to be read
+     * and takes the form:
+     * <blockquote>
+     * [<i>view-name</i><b>:</b>]<i>attribute-name</i>
+     * </blockquote>
+     * where square brackets [...] delineate an optional component and the
+     * character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> is the {@link FileAttributeView#name name} of a {@link
+     * FileAttributeView} that identifies a set of file attributes. If not
+     * specified then it defaults to {@code "basic"}, the name of the file
+     * attribute view that identifies the basic set of file attributes common to
+     * many file systems. <i>attribute-name</i> is the name of the attribute.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we require the user ID of the file owner on a system that
+     * supports a "{@code unix}" view:
+     * <pre>
+     *    Path path = ...
+     *    int uid = (Integer)Files.getAttribute(path, "unix:uid");
+     * </pre>
+     *
+     * @param   path
+     *          the path to the file
+     * @param   attribute
+     *          the attribute to read
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  the attribute value
+     *
+     * @throws  UnsupportedOperationException
+     *          if the attribute view is not available
+     * @throws  IllegalArgumentException
+     *          if the attribute name is not specified or is not recognized
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file. If this method is invoked
+     *          to read security sensitive attributes then the security manager
+     *          may be invoked to check for additional permissions.
+     */
+    public static Object getAttribute(Path path, String attribute,
+                                      LinkOption... options)
+        throws IOException
+    {
+        // only one attribute should be read
+        if (attribute.indexOf('*') >= 0 || attribute.indexOf(',') >= 0)
+            throw new IllegalArgumentException(attribute);
+        Map<String,Object> map = readAttributes(path, attribute, options);
+        assert map.size() == 1;
+        String name;
+        int pos = attribute.indexOf(':');
+        if (pos == -1) {
+            name = attribute;
+        } else {
+            name = (pos == attribute.length()) ? "" : attribute.substring(pos+1);
+        }
+        return map.get(name);
+    }
+
+    /**
+     * Reads a set of file attributes as a bulk operation.
+     *
+     * <p> The {@code attributes} parameter identifies the attributes to be read
+     * and takes the form:
+     * <blockquote>
+     * [<i>view-name</i><b>:</b>]<i>attribute-list</i>
+     * </blockquote>
+     * where square brackets [...] delineate an optional component and the
+     * character {@code ':'} stands for itself.
+     *
+     * <p> <i>view-name</i> is the {@link FileAttributeView#name name} of a {@link
+     * FileAttributeView} that identifies a set of file attributes. If not
+     * specified then it defaults to {@code "basic"}, the name of the file
+     * attribute view that identifies the basic set of file attributes common to
+     * many file systems.
+     *
+     * <p> The <i>attribute-list</i> component is a comma separated list of
+     * zero or more names of attributes to read. If the list contains the value
+     * {@code "*"} then all attributes are read. Attributes that are not supported
+     * are ignored and will not be present in the returned map. It is
+     * implementation specific if all attributes are read as an atomic operation
+     * with respect to other file system operations.
+     *
+     * <p> The following examples demonstrate possible values for the {@code
+     * attributes} parameter:
+     *
+     * <blockquote>
+     * <table border="0" summary="Possible values">
+     * <tr>
+     *   <td> {@code "*"} </td>
+     *   <td> Read all {@link BasicFileAttributes basic-file-attributes}. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code "size,lastModifiedTime,lastAccessTime"} </td>
+     *   <td> Reads the file size, last modified time, and last access time
+     *     attributes. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code "posix:*"} </td>
+     *   <td> Read all {@link PosixFileAttributes POSIX-file-attributes}. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@code "posix:permissions,owner,size"} </td>
+     *   <td> Reads the POSX file permissions, owner, and file size. </td>
+     * </tr>
+     * </table>
+     * </blockquote>
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   attributes
+     *          the attributes to read
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a map of the attributes returned; The map's keys are the
+     *          attribute names, its values are the attribute values
+     *
+     * @throws  UnsupportedOperationException
+     *          if the attribute view is not available
+     * @throws  IllegalArgumentException
+     *          if no attributes are specified or an unrecognized attributes is
+     *          specified
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file. If this method is invoked
+     *          to read security sensitive attributes then the security manager
+     *          may be invoke to check for additional permissions.
+     */
+    public static Map<String,Object> readAttributes(Path path, String attributes,
+                                                    LinkOption... options)
+        throws IOException
+    {
+        return provider(path).readAttributes(path, attributes, options);
+    }
+
+    /**
+     * Returns a file's POSIX file permissions.
+     *
+     * <p> The {@code path} parameter is associated with a {@code FileSystem}
+     * that supports the {@link PosixFileAttributeView}. This attribute view
+     * provides access to file attributes commonly associated with files on file
+     * systems used by operating systems that implement the Portable Operating
+     * System Interface (POSIX) family of standards.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  the file permissions
+     *
+     * @throws  UnsupportedOperationException
+     *          if the associated file system does not support the {@code
+     *          PosixFileAttributeView}
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    public static Set<PosixFilePermission> getPosixFilePermissions(Path path,
+                                                                   LinkOption... options)
+        throws IOException
+    {
+        return readAttributes(path, PosixFileAttributes.class, options).permissions();
+    }
+
+    /**
+     * Sets a file's POSIX permissions.
+     *
+     * <p> The {@code path} parameter is associated with a {@code FileSystem}
+     * that supports the {@link PosixFileAttributeView}. This attribute view
+     * provides access to file attributes commonly associated with files on file
+     * systems used by operating systems that implement the Portable Operating
+     * System Interface (POSIX) family of standards.
+     *
+     * @param   path
+     *          The path to the file
+     * @param   perms
+     *          The new set of permissions
+     *
+     * @return  The path
+     *
+     * @throws  UnsupportedOperationException
+     *          if the associated file system does not support the {@code
+     *          PosixFileAttributeView}
+     * @throws  ClassCastException
+     *          if the sets contains elements that are not of type {@code
+     *          PosixFilePermission}
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    public static Path setPosixFilePermissions(Path path,
+                                               Set<PosixFilePermission> perms)
+        throws IOException
+    {
+        PosixFileAttributeView view =
+            getFileAttributeView(path, PosixFileAttributeView.class);
+        if (view == null)
+            throw new UnsupportedOperationException();
+        view.setPermissions(perms);
+        return path;
+    }
+
+    /**
+     * Returns the owner of a file.
+     *
+     * <p> The {@code path} parameter is associated with a file system that
+     * supports {@link FileOwnerAttributeView}. This file attribute view provides
+     * access to a file attribute that is the owner of the file.
+     *
+     * @param   path
+     *          The path to the file
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  A user principal representing the owner of the file
+     *
+     * @throws  UnsupportedOperationException
+     *          if the associated file system does not support the {@code
+     *          FileOwnerAttributeView}
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    public static UserPrincipal getOwner(Path path, LinkOption... options) throws IOException {
+        FileOwnerAttributeView view =
+            getFileAttributeView(path, FileOwnerAttributeView.class, options);
+        if (view == null)
+            throw new UnsupportedOperationException();
+        return view.getOwner();
+    }
+
+    /**
+     * Updates the file owner.
+     *
+     * <p> The {@code path} parameter is associated with a file system that
+     * supports {@link FileOwnerAttributeView}. This file attribute view provides
+     * access to a file attribute that is the owner of the file.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to make "joe" the owner of a file:
+     * <pre>
+     *     Path path = ...
+     *     UserPrincipalLookupService lookupService =
+     *         provider(path).getUserPrincipalLookupService();
+     *     UserPrincipal joe = lookupService.lookupPrincipalByName("joe");
+     *     Files.setOwner(path, joe);
+     * </pre>
+     *
+     * @param   path
+     *          The path to the file
+     * @param   owner
+     *          The new file owner
+     *
+     * @return  The path
+     *
+     * @throws  UnsupportedOperationException
+     *          if the associated file system does not support the {@code
+     *          FileOwnerAttributeView}
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     *
+     * @see FileSystem#getUserPrincipalLookupService
+     * @see java.nio.file.attribute.UserPrincipalLookupService
+     */
+    public static Path setOwner(Path path, UserPrincipal owner)
+        throws IOException
+    {
+        FileOwnerAttributeView view =
+            getFileAttributeView(path, FileOwnerAttributeView.class);
+        if (view == null)
+            throw new UnsupportedOperationException();
+        view.setOwner(owner);
+        return path;
+    }
+
+    /**
+     * Tests whether a file is a symbolic link.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * that the file is not a symbolic link then the file attributes can be
+     * read with the {@link #readAttributes(Path,Class,LinkOption[])
+     * readAttributes} method and the file type tested with the {@link
+     * BasicFileAttributes#isSymbolicLink} method.
+     *
+     * @param   path  The path to the file
+     *
+     * @return  {@code true} if the file is a symbolic link; {@code false} if
+     *          the file does not exist, is not a symbolic link, or it cannot
+     *          be determined if the file is a symbolic link or not.
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file.
+     */
+    public static boolean isSymbolicLink(Path path) {
+        try {
+            return readAttributes(path,
+                                  BasicFileAttributes.class,
+                                  LinkOption.NOFOLLOW_LINKS).isSymbolicLink();
+        } catch (IOException ioe) {
+            return false;
+        }
+    }
+
+    /**
+     * Tests whether a file is a directory.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * that the file is not a directory then the file attributes can be
+     * read with the {@link #readAttributes(Path,Class,LinkOption[])
+     * readAttributes} method and the file type tested with the {@link
+     * BasicFileAttributes#isDirectory} method.
+     *
+     * @param   path
+     *          the path to the file to test
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  {@code true} if the file is a directory; {@code false} if
+     *          the file does not exist, is not a directory, or it cannot
+     *          be determined if the file is a directory or not.
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file.
+     */
+    public static boolean isDirectory(Path path, LinkOption... options) {
+        try {
+            return readAttributes(path, BasicFileAttributes.class, options).isDirectory();
+        } catch (IOException ioe) {
+            return false;
+        }
+    }
+
+    /**
+     * Tests whether a file is a regular file with opaque content.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> Where it is required to distinguish an I/O exception from the case
+     * that the file is not a regular file then the file attributes can be
+     * read with the {@link #readAttributes(Path,Class,LinkOption[])
+     * readAttributes} method and the file type tested with the {@link
+     * BasicFileAttributes#isRegularFile} method.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  {@code true} if the file is a regular file; {@code false} if
+     *          the file does not exist, is not a regular file, or it
+     *          cannot be determined if the file is a regular file or not.
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file.
+     */
+    public static boolean isRegularFile(Path path, LinkOption... options) {
+        try {
+            return readAttributes(path, BasicFileAttributes.class, options).isRegularFile();
+        } catch (IOException ioe) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a file's last modified time.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed and the file attribute of the final target
+     * of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a {@code FileTime} representing the time the file was last
+     *          modified, or an implementation specific default when a time
+     *          stamp to indicate the time of last modification is not supported
+     *          by the file system
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file.
+     *
+     * @see BasicFileAttributes#lastModifiedTime
+     */
+    public static FileTime getLastModifiedTime(Path path, LinkOption... options)
+        throws IOException
+    {
+        return readAttributes(path, BasicFileAttributes.class, options).lastModifiedTime();
+    }
+
+    /**
+     * Updates a file's last modified time attribute. The file time is converted
+     * to the epoch and precision supported by the file system. Converting from
+     * finer to coarser granularities result in precision loss. The behavior of
+     * this method when attempting to set the last modified time when it is not
+     * supported by the file system or is outside the range supported by the
+     * underlying file store is not defined. It may or not fail by throwing an
+     * {@code IOException}.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to set the last modified time to the current time:
+     * <pre>
+     *    Path path = ...
+     *    FileTime now = FileTime.fromMillis(System.currentTimeMillis());
+     *    Files.setLastModifiedTime(path, now);
+     * </pre>
+     *
+     * @param   path
+     *          the path to the file
+     * @param   time
+     *          the new last modified time
+     *
+     * @return  the path
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, the security manager's {@link
+     *          SecurityManager#checkWrite(String) checkWrite} method is invoked
+     *          to check write access to file
+     *
+     * @see BasicFileAttributeView#setTimes
+     */
+    public static Path setLastModifiedTime(Path path, FileTime time)
+        throws IOException
+    {
+        getFileAttributeView(path, BasicFileAttributeView.class)
+            .setTimes(time, null, null);
+        return path;
+    }
+
+    /**
+     * Returns the size of a file (in bytes). The size may differ from the
+     * actual size on the file system due to compression, support for sparse
+     * files, or other reasons. The size of files that are not {@link
+     * #isRegularFile regular} files is implementation specific and
+     * therefore unspecified.
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  the file size, in bytes
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file.
+     *
+     * @see BasicFileAttributes#size
+     */
+    public static long size(Path path) throws IOException {
+        return readAttributes(path, BasicFileAttributes.class).size();
+    }
+
+    // -- Accessibility --
+
+    /**
+     * Returns {@code false} if NOFOLLOW_LINKS is present.
+     */
+    private static boolean followLinks(LinkOption... options) {
+        boolean followLinks = true;
+        for (LinkOption opt: options) {
+            if (opt == LinkOption.NOFOLLOW_LINKS) {
+                followLinks = false;
+                continue;
+            }
+            if (opt == null)
+                throw new NullPointerException();
+            throw new AssertionError("Should not get here");
+        }
+        return followLinks;
+    }
+
+    /**
+     * Tests whether a file exists.
+     *
+     * <p> The {@code options} parameter may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> Note that the result of this method is immediately outdated. If this
+     * method indicates the file exists then there is no guarantee that a
+     * subsequence access will succeed. Care should be taken when using this
+     * method in security sensitive applications.
+     *
+     * @param   path
+     *          the path to the file to test
+     * @param   options
+     *          options indicating how symbolic links are handled
+     * .
+     * @return  {@code true} if the file exists; {@code false} if the file does
+     *          not exist or its existence cannot be determined.
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} is invoked to check
+     *          read access to the file.
+     *
+     * @see #notExists
+     */
+    public static boolean exists(Path path, LinkOption... options) {
+        try {
+            if (followLinks(options)) {
+                provider(path).checkAccess(path);
+            } else {
+                // attempt to read attributes without following links
+                readAttributes(path, BasicFileAttributes.class,
+                               LinkOption.NOFOLLOW_LINKS);
+            }
+            // file exists
+            return true;
+        } catch (IOException x) {
+            // does not exist or unable to determine if file exists
+            return false;
+        }
+
+    }
+
+    /**
+     * Tests whether the file located by this path does not exist. This method
+     * is intended for cases where it is required to take action when it can be
+     * confirmed that a file does not exist.
+     *
+     * <p> The {@code options} parameter may be used to indicate how symbolic links
+     * are handled for the case that the file is a symbolic link. By default,
+     * symbolic links are followed. If the option {@link LinkOption#NOFOLLOW_LINKS
+     * NOFOLLOW_LINKS} is present then symbolic links are not followed.
+     *
+     * <p> Note that this method is not the complement of the {@link #exists
+     * exists} method. Where it is not possible to determine if a file exists
+     * or not then both methods return {@code false}. As with the {@code exists}
+     * method, the result of this method is immediately outdated. If this
+     * method indicates the file does exist then there is no guarantee that a
+     * subsequence attempt to create the file will succeed. Care should be taken
+     * when using this method in security sensitive applications.
+     *
+     * @param   path
+     *          the path to the file to test
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  {@code true} if the file does not exist; {@code false} if the
+     *          file exists or its existence cannot be determined
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String)} is invoked to check
+     *          read access to the file.
+     */
+    public static boolean notExists(Path path, LinkOption... options) {
+        try {
+            if (followLinks(options)) {
+                provider(path).checkAccess(path);
+            } else {
+                // attempt to read attributes without following links
+                readAttributes(path, BasicFileAttributes.class,
+                               LinkOption.NOFOLLOW_LINKS);
+            }
+            // file exists
+            return false;
+        } catch (NoSuchFileException x) {
+            // file confirmed not to exist
+            return true;
+        } catch (IOException x) {
+            return false;
+        }
+    }
+
+    /**
+     * Used by isReadbale, isWritable, isExecutable to test access to a file.
+     */
+    private static boolean isAccessible(Path path, AccessMode... modes) {
+        try {
+            provider(path).checkAccess(path, modes);
+            return true;
+        } catch (IOException x) {
+            return false;
+        }
+    }
+
+    /**
+     * Tests whether a file is readable. This method checks that a file exists
+     * and that this Java virtual machine has appropriate privileges that would
+     * allow it open the file for reading. Depending on the implementation, this
+     * method may require to read file permissions, access control lists, or
+     * other file attributes in order to check the effective access to the file.
+     * Consequently, this method may not be atomic with respect to other file
+     * system operations.
+     *
+     * <p> Note that the result of this method is immediately outdated, there is
+     * no guarantee that a subsequent attempt to open the file for reading will
+     * succeed (or even that it will access the same file). Care should be taken
+     * when using this method in security sensitive applications.
+     *
+     * @param   path
+     *          the path to the file to check
+     *
+     * @return  {@code true} if the file exists and is readable; {@code false}
+     *          if the file does not exist, read access would be denied because
+     *          the Java virtual machine has insufficient privileges, or access
+     *          cannot be determined
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          is invoked to check read access to the file.
+     */
+    public static boolean isReadable(Path path) {
+        return isAccessible(path, AccessMode.READ);
+    }
+
+    /**
+     * Tests whether a file is writable. This method checks that a file exists
+     * and that this Java virtual machine has appropriate privileges that would
+     * allow it open the file for writing. Depending on the implementation, this
+     * method may require to read file permissions, access control lists, or
+     * other file attributes in order to check the effective access to the file.
+     * Consequently, this method may not be atomic with respect to other file
+     * system operations.
+     *
+     * <p> Note that result of this method is immediately outdated, there is no
+     * guarantee that a subsequent attempt to open the file for writing will
+     * succeed (or even that it will access the same file). Care should be taken
+     * when using this method in security sensitive applications.
+     *
+     * @param   path
+     *          the path to the file to check
+     *
+     * @return  {@code true} if the file exists and is writable; {@code false}
+     *          if the file does not exist, write access would be denied because
+     *          the Java virtual machine has insufficient privileges, or access
+     *          cannot be determined
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          is invoked to check write access to the file.
+     */
+    public static boolean isWritable(Path path) {
+        return isAccessible(path, AccessMode.WRITE);
+    }
+
+    /**
+     * Tests whether a file is executable. This method checks that a file exists
+     * and that this Java virtual machine has appropriate privileges to {@link
+     * Runtime#exec execute} the file. The semantics may differ when checking
+     * access to a directory. For example, on UNIX systems, checking for
+     * execute access checks that the Java virtual machine has permission to
+     * search the directory in order to access file or subdirectories.
+     *
+     * <p> Depending on the implementation, this method may require to read file
+     * permissions, access control lists, or other file attributes in order to
+     * check the effective access to the file. Consequently, this method may not
+     * be atomic with respect to other file system operations.
+     *
+     * <p> Note that the result of this method is immediately outdated, there is
+     * no guarantee that a subsequent attempt to execute the file will succeed
+     * (or even that it will access the same file). Care should be taken when
+     * using this method in security sensitive applications.
+     *
+     * @param   path
+     *          the path to the file to check
+     *
+     * @return  {@code true} if the file exists and is executable; {@code false}
+     *          if the file does not exist, execute access would be denied because
+     *          the Java virtual machine has insufficient privileges, or access
+     *          cannot be determined
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkExec(String)
+     *          checkExec} is invoked to check execute access to the file.
+     */
+    public static boolean isExecutable(Path path) {
+        return isAccessible(path, AccessMode.EXECUTE);
+    }
+
+    // -- Recursive operations --
+
+    /**
+     * Walks a file tree.
+     *
+     * <p> This method walks a file tree rooted at a given starting file. The
+     * file tree traversal is <em>depth-first</em> with the given {@link
+     * FileVisitor} invoked for each file encountered. File tree traversal
+     * completes when all accessible files in the tree have been visited, or a
+     * visit method returns a result of {@link FileVisitResult#TERMINATE
+     * TERMINATE}. Where a visit method terminates due an {@code IOException},
+     * an uncaught error, or runtime exception, then the traversal is terminated
+     * and the error or exception is propagated to the caller of this method.
+     *
+     * <p> For each file encountered this method attempts to read its {@link
+     * java.nio.file.attribute.BasicFileAttributes}. If the file is not a
+     * directory then the {@link FileVisitor#visitFile visitFile} method is
+     * invoked with the file attributes. If the file attributes cannot be read,
+     * due to an I/O exception, then the {@link FileVisitor#visitFileFailed
+     * visitFileFailed} method is invoked with the I/O exception.
+     *
+     * <p> Where the file is a directory, and the directory could not be opened,
+     * then the {@code visitFileFailed} method is invoked with the I/O exception,
+     * after which, the file tree walk continues, by default, at the next
+     * <em>sibling</em> of the directory.
+     *
+     * <p> Where the directory is opened successfully, then the entries in the
+     * directory, and their <em>descendants</em> are visited. When all entries
+     * have been visited, or an I/O error occurs during iteration of the
+     * directory, then the directory is closed and the visitor's {@link
+     * FileVisitor#postVisitDirectory postVisitDirectory} method is invoked.
+     * The file tree walk then continues, by default, at the next <em>sibling</em>
+     * of the directory.
+     *
+     * <p> By default, symbolic links are not automatically followed by this
+     * method. If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
+     * followed. When following links, and the attributes of the target cannot
+     * be read, then this method attempts to get the {@code BasicFileAttributes}
+     * of the link. If they can be read then the {@code visitFile} method is
+     * invoked with the attributes of the link (otherwise the {@code visitFileFailed}
+     * method is invoked as specified above).
+     *
+     * <p> If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then this method keeps
+     * track of directories visited so that cycles can be detected. A cycle
+     * arises when there is an entry in a directory that is an ancestor of the
+     * directory. Cycle detection is done by recording the {@link
+     * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
+     * or if file keys are not available, by invoking the {@link #isSameFile
+     * isSameFile} method to test if a directory is the same file as an
+     * ancestor. When a cycle is detected it is treated as an I/O error, and the
+     * {@link FileVisitor#visitFileFailed visitFileFailed} method is invoked with
+     * an instance of {@link FileSystemLoopException}.
+     *
+     * <p> The {@code maxDepth} parameter is the maximum number of levels of
+     * directories to visit. A value of {@code 0} means that only the starting
+     * file is visited, unless denied by the security manager. A value of
+     * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
+     * levels should be visited. The {@code visitFile} method is invoked for all
+     * files, including directories, encountered at {@code maxDepth}, unless the
+     * basic file attributes cannot be read, in which case the {@code
+     * visitFileFailed} method is invoked.
+     *
+     * <p> If a visitor returns a result of {@code null} then {@code
+     * NullPointerException} is thrown.
+     *
+     * <p> When a security manager is installed and it denies access to a file
+     * (or directory), then it is ignored and the visitor is not invoked for
+     * that file (or directory).
+     *
+     * @param   start
+     *          the starting file
+     * @param   options
+     *          options to configure the traversal
+     * @param   maxDepth
+     *          the maximum number of directory levels to visit
+     * @param   visitor
+     *          the file visitor to invoke for each file
+     *
+     * @return  the starting file
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code maxDepth} parameter is negative
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown by a visitor method
+     */
+    public static Path walkFileTree(Path start,
+                                    Set<FileVisitOption> options,
+                                    int maxDepth,
+                                    FileVisitor<? super Path> visitor)
+        throws IOException
+    {
+        /**
+         * Create a FileTreeWalker to walk the file tree, invoking the visitor
+         * for each event.
+         */
+        try (FileTreeWalker walker = new FileTreeWalker(options, maxDepth)) {
+            FileTreeWalker.Event ev = walker.walk(start);
+            do {
+                FileVisitResult result;
+                switch (ev.type()) {
+                    case ENTRY :
+                        IOException ioe = ev.ioeException();
+                        if (ioe == null) {
+                            assert ev.attributes() != null;
+                            result = visitor.visitFile(ev.file(), ev.attributes());
+                        } else {
+                            result = visitor.visitFileFailed(ev.file(), ioe);
+                        }
+                        break;
+
+                    case START_DIRECTORY :
+                        result = visitor.preVisitDirectory(ev.file(), ev.attributes());
+
+                        // if SKIP_SIBLINGS and SKIP_SUBTREE is returned then
+                        // there shouldn't be any more events for the current
+                        // directory.
+                        if (result == FileVisitResult.SKIP_SUBTREE ||
+                            result == FileVisitResult.SKIP_SIBLINGS)
+                            walker.pop();
+                        break;
+
+                    case END_DIRECTORY :
+                        result = visitor.postVisitDirectory(ev.file(), ev.ioeException());
+
+                        // SKIP_SIBLINGS is a no-op for postVisitDirectory
+                        if (result == FileVisitResult.SKIP_SIBLINGS)
+                            result = FileVisitResult.CONTINUE;
+                        break;
+
+                    default :
+                        throw new AssertionError("Should not get here");
+                }
+
+                if (Objects.requireNonNull(result) != FileVisitResult.CONTINUE) {
+                    if (result == FileVisitResult.TERMINATE) {
+                        break;
+                    } else if (result == FileVisitResult.SKIP_SIBLINGS) {
+                        walker.skipRemainingSiblings();
+                    }
+                }
+                ev = walker.next();
+            } while (ev != null);
+        }
+
+        return start;
+    }
+
+    /**
+     * Walks a file tree.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor)
+     * </pre></blockquote>
+     * In other words, it does not follow symbolic links, and visits all levels
+     * of the file tree.
+     *
+     * @param   start
+     *          the starting file
+     * @param   visitor
+     *          the file visitor to invoke for each file
+     *
+     * @return  the starting file
+     *
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown by a visitor method
+     */
+    public static Path walkFileTree(Path start, FileVisitor<? super Path> visitor)
+        throws IOException
+    {
+        return walkFileTree(start,
+                            EnumSet.noneOf(FileVisitOption.class),
+                            Integer.MAX_VALUE,
+                            visitor);
+    }
+
+
+    // -- Utility methods for simple usages --
+
+    // buffer size used for reading and writing
+    private static final int BUFFER_SIZE = 8192;
+
+    /**
+     * Opens a file for reading, returning a {@code BufferedReader} that may be
+     * used to read text from the file in an efficient manner. Bytes from the
+     * file are decoded into characters using the specified charset. Reading
+     * commences at the beginning of the file.
+     *
+     * <p> The {@code Reader} methods that read from the file throw {@code
+     * IOException} if a malformed or unmappable byte sequence is read.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   cs
+     *          the charset to use for decoding
+     *
+     * @return  a new buffered reader, with default buffer size, to read text
+     *          from the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening the file
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @see #readAllLines
+     */
+    public static BufferedReader newBufferedReader(Path path, Charset cs)
+        throws IOException
+    {
+        CharsetDecoder decoder = cs.newDecoder();
+        Reader reader = new InputStreamReader(newInputStream(path), decoder);
+        return new BufferedReader(reader);
+    }
+
+    /**
+     * Opens a file for reading, returning a {@code BufferedReader} to read text
+     * from the file in an efficient manner. Bytes from the file are decoded into
+     * characters using the {@link StandardCharsets#UTF_8 UTF-8} {@link Charset
+     * charset}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <pre>{@code
+     * Files.newBufferedReader(path, StandardCharsets.UTF_8)
+     * }</pre>
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  a new buffered reader, with default buffer size, to read text
+     *          from the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening the file
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @since 1.8
+     */
+    public static BufferedReader newBufferedReader(Path path) throws IOException {
+        return newBufferedReader(path, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Opens or creates a file for writing, returning a {@code BufferedWriter}
+     * that may be used to write text to the file in an efficient manner.
+     * The {@code options} parameter specifies how the the file is created or
+     * opened. If no options are present then this method works as if the {@link
+     * StandardOpenOption#CREATE CREATE}, {@link
+     * StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, and {@link
+     * StandardOpenOption#WRITE WRITE} options are present. In other words, it
+     * opens the file for writing, creating the file if it doesn't exist, or
+     * initially truncating an existing {@link #isRegularFile regular-file} to
+     * a size of {@code 0} if it exists.
+     *
+     * <p> The {@code Writer} methods to write text throw {@code IOException}
+     * if the text cannot be encoded using the specified charset.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   cs
+     *          the charset to use for encoding
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new buffered writer, with default buffer size, to write text
+     *          to the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening or creating the file
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     *
+     * @see #write(Path,Iterable,Charset,OpenOption[])
+     */
+    public static BufferedWriter newBufferedWriter(Path path, Charset cs,
+                                                   OpenOption... options)
+        throws IOException
+    {
+        CharsetEncoder encoder = cs.newEncoder();
+        Writer writer = new OutputStreamWriter(newOutputStream(path, options), encoder);
+        return new BufferedWriter(writer);
+    }
+
+    /**
+     * Opens or creates a file for writing, returning a {@code BufferedWriter}
+     * to write text to the file in an efficient manner. The text is encoded
+     * into bytes for writing using the {@link StandardCharsets#UTF_8 UTF-8}
+     * {@link Charset charset}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <pre>{@code
+     * Files.newBufferedWriter(path, StandardCharsets.UTF_8, options)
+     * }</pre>
+     *
+     * @param   path
+     *          the path to the file
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new buffered writer, with default buffer size, to write text
+     *          to the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening or creating the file
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     *
+     * @since 1.8
+     */
+    public static BufferedWriter newBufferedWriter(Path path, OpenOption... options) throws IOException {
+        return newBufferedWriter(path, StandardCharsets.UTF_8, options);
+    }
+
+    /**
+     * Reads all bytes from an input stream and writes them to an output stream.
+     */
+    private static long copy(InputStream source, OutputStream sink)
+        throws IOException
+    {
+        long nread = 0L;
+        byte[] buf = new byte[BUFFER_SIZE];
+        int n;
+        while ((n = source.read(buf)) > 0) {
+            sink.write(buf, 0, n);
+            nread += n;
+        }
+        return nread;
+    }
+
+    /**
+     * Copies all bytes from an input stream to a file. On return, the input
+     * stream will be at end of stream.
+     *
+     * <p> By default, the copy fails if the target file already exists or is a
+     * symbolic link. If the {@link StandardCopyOption#REPLACE_EXISTING
+     * REPLACE_EXISTING} option is specified, and the target file already exists,
+     * then it is replaced if it is not a non-empty directory. If the target
+     * file exists and is a symbolic link, then the symbolic link is replaced.
+     * In this release, the {@code REPLACE_EXISTING} option is the only option
+     * required to be supported by this method. Additional options may be
+     * supported in future releases.
+     *
+     * <p>  If an I/O error occurs reading from the input stream or writing to
+     * the file, then it may do so after the target file has been created and
+     * after some bytes have been read or written. Consequently the input
+     * stream may not be at end of stream and may be in an inconsistent state.
+     * It is strongly recommended that the input stream be promptly closed if an
+     * I/O error occurs.
+     *
+     * <p> This method may block indefinitely reading from the input stream (or
+     * writing to the file). The behavior for the case that the input stream is
+     * <i>asynchronously closed</i> or the thread interrupted during the copy is
+     * highly input stream and file system provider specific and therefore not
+     * specified.
+     *
+     * <p> <b>Usage example</b>: Suppose we want to capture a web page and save
+     * it to a file:
+     * <pre>
+     *     Path path = ...
+     *     URI u = URI.create("http://java.sun.com/");
+     *     try (InputStream in = u.toURL().openStream()) {
+     *         Files.copy(in, path);
+     *     }
+     * </pre>
+     *
+     * @param   in
+     *          the input stream to read from
+     * @param   target
+     *          the path to the file
+     * @param   options
+     *          options specifying how the copy should be done
+     *
+     * @return  the number of bytes read or written
+     *
+     * @throws  IOException
+     *          if an I/O error occurs when reading or writing
+     * @throws  FileAlreadyExistsException
+     *          if the target file exists but cannot be replaced because the
+     *          {@code REPLACE_EXISTING} option is not specified <i>(optional
+     *          specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          the {@code REPLACE_EXISTING} option is specified but the file
+     *          cannot be replaced because it is a non-empty directory
+     *          <i>(optional specific exception)</i>     *
+     * @throws  UnsupportedOperationException
+     *          if {@code options} contains a copy option that is not supported
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file. Where the
+     *          {@code REPLACE_EXISTING} option is specified, the security
+     *          manager's {@link SecurityManager#checkDelete(String) checkDelete}
+     *          method is invoked to check that an existing file can be deleted.
+     */
+    public static long copy(InputStream in, Path target, CopyOption... options)
+        throws IOException
+    {
+        // ensure not null before opening file
+        Objects.requireNonNull(in);
+
+        // check for REPLACE_EXISTING
+        boolean replaceExisting = false;
+        for (CopyOption opt: options) {
+            if (opt == StandardCopyOption.REPLACE_EXISTING) {
+                replaceExisting = true;
+            } else {
+                if (opt == null) {
+                    throw new NullPointerException("options contains 'null'");
+                }  else {
+                    throw new UnsupportedOperationException(opt + " not supported");
+                }
+            }
+        }
+
+        // attempt to delete an existing file
+        SecurityException se = null;
+        if (replaceExisting) {
+            try {
+                deleteIfExists(target);
+            } catch (SecurityException x) {
+                se = x;
+            }
+        }
+
+        // attempt to create target file. If it fails with
+        // FileAlreadyExistsException then it may be because the security
+        // manager prevented us from deleting the file, in which case we just
+        // throw the SecurityException.
+        OutputStream ostream;
+        try {
+            ostream = newOutputStream(target, StandardOpenOption.CREATE_NEW,
+                                              StandardOpenOption.WRITE);
+        } catch (FileAlreadyExistsException x) {
+            if (se != null)
+                throw se;
+            // someone else won the race and created the file
+            throw x;
+        }
+
+        // do the copy
+        try (OutputStream out = ostream) {
+            return copy(in, out);
+        }
+    }
+
+    /**
+     * Copies all bytes from a file to an output stream.
+     *
+     * <p> If an I/O error occurs reading from the file or writing to the output
+     * stream, then it may do so after some bytes have been read or written.
+     * Consequently the output stream may be in an inconsistent state. It is
+     * strongly recommended that the output stream be promptly closed if an I/O
+     * error occurs.
+     *
+     * <p> This method may block indefinitely writing to the output stream (or
+     * reading from the file). The behavior for the case that the output stream
+     * is <i>asynchronously closed</i> or the thread interrupted during the copy
+     * is highly output stream and file system provider specific and therefore
+     * not specified.
+     *
+     * <p> Note that if the given output stream is {@link java.io.Flushable}
+     * then its {@link java.io.Flushable#flush flush} method may need to invoked
+     * after this method completes so as to flush any buffered output.
+     *
+     * @param   source
+     *          the  path to the file
+     * @param   out
+     *          the output stream to write to
+     *
+     * @return  the number of bytes read or written
+     *
+     * @throws  IOException
+     *          if an I/O error occurs when reading or writing
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    public static long copy(Path source, OutputStream out) throws IOException {
+        // ensure not null before opening file
+        Objects.requireNonNull(out);
+
+        try (InputStream in = newInputStream(source)) {
+            return copy(in, out);
+        }
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Reads all the bytes from an input stream. Uses {@code initialSize} as a hint
+     * about how many bytes the stream will have.
+     *
+     * @param   source
+     *          the input stream to read from
+     * @param   initialSize
+     *          the initial size of the byte array to allocate
+     *
+     * @return  a byte array containing the bytes read from the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs reading from the stream
+     * @throws  OutOfMemoryError
+     *          if an array of the required size cannot be allocated
+     */
+    private static byte[] read(InputStream source, int initialSize) throws IOException {
+        int capacity = initialSize;
+        byte[] buf = new byte[capacity];
+        int nread = 0;
+        int n;
+        for (;;) {
+            // read to EOF which may read more or less than initialSize (eg: file
+            // is truncated while we are reading)
+            while ((n = source.read(buf, nread, capacity - nread)) > 0)
+                nread += n;
+
+            // if last call to source.read() returned -1, we are done
+            // otherwise, try to read one more byte; if that failed we're done too
+            if (n < 0 || (n = source.read()) < 0)
+                break;
+
+            // one more byte was read; need to allocate a larger buffer
+            if (capacity <= MAX_BUFFER_SIZE - capacity) {
+                capacity = Math.max(capacity << 1, BUFFER_SIZE);
+            } else {
+                if (capacity == MAX_BUFFER_SIZE)
+                    throw new OutOfMemoryError("Required array size too large");
+                capacity = MAX_BUFFER_SIZE;
+            }
+            buf = Arrays.copyOf(buf, capacity);
+            buf[nread++] = (byte)n;
+        }
+        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
+    }
+
+    /**
+     * Reads all the bytes from a file. The method ensures that the file is
+     * closed when all bytes have been read or an I/O error, or other runtime
+     * exception, is thrown.
+     *
+     * <p> Note that this method is intended for simple cases where it is
+     * convenient to read all bytes into a byte array. It is not intended for
+     * reading in large files.
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  a byte array containing the bytes read from the file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs reading from the stream
+     * @throws  OutOfMemoryError
+     *          if an array of the required size cannot be allocated, for
+     *          example the file is larger that {@code 2GB}
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    public static byte[] readAllBytes(Path path) throws IOException {
+        try (SeekableByteChannel sbc = Files.newByteChannel(path);
+             InputStream in = Channels.newInputStream(sbc)) {
+            long size = sbc.size();
+            if (size > (long)MAX_BUFFER_SIZE)
+                throw new OutOfMemoryError("Required array size too large");
+
+            return read(in, (int)size);
+        }
+    }
+
+    /**
+     * Read all lines from a file. This method ensures that the file is
+     * closed when all bytes have been read or an I/O error, or other runtime
+     * exception, is thrown. Bytes from the file are decoded into characters
+     * using the specified charset.
+     *
+     * <p> This method recognizes the following as line terminators:
+     * <ul>
+     *   <li> <code>&#92;u000D</code> followed by <code>&#92;u000A</code>,
+     *     CARRIAGE RETURN followed by LINE FEED </li>
+     *   <li> <code>&#92;u000A</code>, LINE FEED </li>
+     *   <li> <code>&#92;u000D</code>, CARRIAGE RETURN </li>
+     * </ul>
+     * <p> Additional Unicode line terminators may be recognized in future
+     * releases.
+     *
+     * <p> Note that this method is intended for simple cases where it is
+     * convenient to read all lines in a single operation. It is not intended
+     * for reading in large files.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   cs
+     *          the charset to use for decoding
+     *
+     * @return  the lines from the file as a {@code List}; whether the {@code
+     *          List} is modifiable or not is implementation dependent and
+     *          therefore not specified
+     *
+     * @throws  IOException
+     *          if an I/O error occurs reading from the file or a malformed or
+     *          unmappable byte sequence is read
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @see #newBufferedReader
+     */
+    public static List<String> readAllLines(Path path, Charset cs) throws IOException {
+        try (BufferedReader reader = newBufferedReader(path, cs)) {
+            List<String> result = new ArrayList<>();
+            for (;;) {
+                String line = reader.readLine();
+                if (line == null)
+                    break;
+                result.add(line);
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Read all lines from a file. Bytes from the file are decoded into characters
+     * using the {@link StandardCharsets#UTF_8 UTF-8} {@link Charset charset}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <pre>{@code
+     * Files.readAllLines(path, StandardCharsets.UTF_8)
+     * }</pre>
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  the lines from the file as a {@code List}; whether the {@code
+     *          List} is modifiable or not is implementation dependent and
+     *          therefore not specified
+     *
+     * @throws  IOException
+     *          if an I/O error occurs reading from the file or a malformed or
+     *          unmappable byte sequence is read
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @since 1.8
+     */
+    public static List<String> readAllLines(Path path) throws IOException {
+        return readAllLines(path, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Writes bytes to a file. The {@code options} parameter specifies how the
+     * the file is created or opened. If no options are present then this method
+     * works as if the {@link StandardOpenOption#CREATE CREATE}, {@link
+     * StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, and {@link
+     * StandardOpenOption#WRITE WRITE} options are present. In other words, it
+     * opens the file for writing, creating the file if it doesn't exist, or
+     * initially truncating an existing {@link #isRegularFile regular-file} to
+     * a size of {@code 0}. All bytes in the byte array are written to the file.
+     * The method ensures that the file is closed when all bytes have been
+     * written (or an I/O error or other runtime exception is thrown). If an I/O
+     * error occurs then it may do so after the file has created or truncated,
+     * or after some bytes have been written to the file.
+     *
+     * <p> <b>Usage example</b>: By default the method creates a new file or
+     * overwrites an existing file. Suppose you instead want to append bytes
+     * to an existing file:
+     * <pre>
+     *     Path path = ...
+     *     byte[] bytes = ...
+     *     Files.write(path, bytes, StandardOpenOption.APPEND);
+     * </pre>
+     *
+     * @param   path
+     *          the path to the file
+     * @param   bytes
+     *          the byte array with the bytes to write
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  the path
+     *
+     * @throws  IOException
+     *          if an I/O error occurs writing to or creating the file
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     */
+    public static Path write(Path path, byte[] bytes, OpenOption... options)
+        throws IOException
+    {
+        // ensure bytes is not null before opening file
+        Objects.requireNonNull(bytes);
+
+        try (OutputStream out = Files.newOutputStream(path, options)) {
+            int len = bytes.length;
+            int rem = len;
+            while (rem > 0) {
+                int n = Math.min(rem, BUFFER_SIZE);
+                out.write(bytes, (len-rem), n);
+                rem -= n;
+            }
+        }
+        return path;
+    }
+
+    /**
+     * Write lines of text to a file. Each line is a char sequence and is
+     * written to the file in sequence with each line terminated by the
+     * platform's line separator, as defined by the system property {@code
+     * line.separator}. Characters are encoded into bytes using the specified
+     * charset.
+     *
+     * <p> The {@code options} parameter specifies how the the file is created
+     * or opened. If no options are present then this method works as if the
+     * {@link StandardOpenOption#CREATE CREATE}, {@link
+     * StandardOpenOption#TRUNCATE_EXISTING TRUNCATE_EXISTING}, and {@link
+     * StandardOpenOption#WRITE WRITE} options are present. In other words, it
+     * opens the file for writing, creating the file if it doesn't exist, or
+     * initially truncating an existing {@link #isRegularFile regular-file} to
+     * a size of {@code 0}. The method ensures that the file is closed when all
+     * lines have been written (or an I/O error or other runtime exception is
+     * thrown). If an I/O error occurs then it may do so after the file has
+     * created or truncated, or after some bytes have been written to the file.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   lines
+     *          an object to iterate over the char sequences
+     * @param   cs
+     *          the charset to use for encoding
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  the path
+     *
+     * @throws  IOException
+     *          if an I/O error occurs writing to or creating the file, or the
+     *          text cannot be encoded using the specified charset
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     */
+    public static Path write(Path path, Iterable<? extends CharSequence> lines,
+                             Charset cs, OpenOption... options)
+        throws IOException
+    {
+        // ensure lines is not null before opening file
+        Objects.requireNonNull(lines);
+        CharsetEncoder encoder = cs.newEncoder();
+        OutputStream out = newOutputStream(path, options);
+        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, encoder))) {
+            for (CharSequence line: lines) {
+                writer.append(line);
+                writer.newLine();
+            }
+        }
+        return path;
+    }
+
+    /**
+     * Write lines of text to a file. Characters are encoded into bytes using
+     * the {@link StandardCharsets#UTF_8 UTF-8} {@link Charset charset}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <pre>{@code
+     * Files.write(path, lines, StandardCharsets.UTF_8, options);
+     * }</pre>
+     *
+     * @param   path
+     *          the path to the file
+     * @param   lines
+     *          an object to iterate over the char sequences
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  the path
+     *
+     * @throws  IOException
+     *          if an I/O error occurs writing to or creating the file, or the
+     *          text cannot be encoded as {@code UTF-8}
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file.
+     *
+     * @since 1.8
+     */
+    public static Path write(Path path,
+                             Iterable<? extends CharSequence> lines,
+                             OpenOption... options)
+        throws IOException
+    {
+        return write(path, lines, StandardCharsets.UTF_8, options);
+    }
+
+    // -- Stream APIs --
+
+    /**
+     * Return a lazily populated {@code Stream}, the elements of
+     * which are the entries in the directory.  The listing is not recursive.
+     *
+     * <p> The elements of the stream are {@link Path} objects that are
+     * obtained as if by {@link Path#resolve(Path) resolving} the name of the
+     * directory entry against {@code dir}. Some file systems maintain special
+     * links to the directory itself and the directory's parent directory.
+     * Entries representing these links are not included.
+     *
+     * <p> The stream is <i>weakly consistent</i>. It is thread safe but does
+     * not freeze the directory while iterating, so it may (or may not)
+     * reflect updates to the directory that occur after returning from this
+     * method.
+     *
+     * <p> The returned stream encapsulates a {@link DirectoryStream}.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.
+     *
+     * <p> Operating on a closed stream behaves as if the end of stream
+     * has been reached. Due to read-ahead, one or more elements may be
+     * returned after the stream has been closed.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the directory
+     * after this method has returned, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the method that caused
+     * the access to take place.
+     *
+     * @param   dir  The path to the directory
+     *
+     * @return  The {@code Stream} describing the content of the
+     *          directory
+     *
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs when opening the directory
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     *
+     * @see     #newDirectoryStream(Path)
+     * @since   1.8
+     */
+    public static Stream<Path> list(Path dir) throws IOException {
+        DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
+        try {
+            final Iterator<Path> delegate = ds.iterator();
+
+            // Re-wrap DirectoryIteratorException to UncheckedIOException
+            Iterator<Path> it = new Iterator<Path>() {
+                @Override
+                public boolean hasNext() {
+                    try {
+                        return delegate.hasNext();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
+                }
+                @Override
+                public Path next() {
+                    try {
+                        return delegate.next();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
+                }
+            };
+
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
+                                .onClose(asUncheckedRunnable(ds));
+        } catch (Error|RuntimeException e) {
+            try {
+                ds.close();
+            } catch (IOException ex) {
+                try {
+                    e.addSuppressed(ex);
+                } catch (Throwable ignore) {}
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * Return a {@code Stream} that is lazily populated with {@code
+     * Path} by walking the file tree rooted at a given starting file.  The
+     * file tree is traversed <em>depth-first</em>, the elements in the stream
+     * are {@link Path} objects that are obtained as if by {@link
+     * Path#resolve(Path) resolving} the relative path against {@code start}.
+     *
+     * <p> The {@code stream} walks the file tree as elements are consumed.
+     * The {@code Stream} returned is guaranteed to have at least one
+     * element, the starting file itself. For each file visited, the stream
+     * attempts to read its {@link BasicFileAttributes}. If the file is a
+     * directory and can be opened successfully, entries in the directory, and
+     * their <em>descendants</em> will follow the directory in the stream as
+     * they are encountered. When all entries have been visited, then the
+     * directory is closed. The file tree walk then continues at the next
+     * <em>sibling</em> of the directory.
+     *
+     * <p> The stream is <i>weakly consistent</i>. It does not freeze the
+     * file tree while iterating, so it may (or may not) reflect updates to
+     * the file tree that occur after returned from this method.
+     *
+     * <p> By default, symbolic links are not automatically followed by this
+     * method. If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then symbolic links are
+     * followed. When following links, and the attributes of the target cannot
+     * be read, then this method attempts to get the {@code BasicFileAttributes}
+     * of the link.
+     *
+     * <p> If the {@code options} parameter contains the {@link
+     * FileVisitOption#FOLLOW_LINKS FOLLOW_LINKS} option then the stream keeps
+     * track of directories visited so that cycles can be detected. A cycle
+     * arises when there is an entry in a directory that is an ancestor of the
+     * directory. Cycle detection is done by recording the {@link
+     * java.nio.file.attribute.BasicFileAttributes#fileKey file-key} of directories,
+     * or if file keys are not available, by invoking the {@link #isSameFile
+     * isSameFile} method to test if a directory is the same file as an
+     * ancestor. When a cycle is detected it is treated as an I/O error with
+     * an instance of {@link FileSystemLoopException}.
+     *
+     * <p> The {@code maxDepth} parameter is the maximum number of levels of
+     * directories to visit. A value of {@code 0} means that only the starting
+     * file is visited, unless denied by the security manager. A value of
+     * {@link Integer#MAX_VALUE MAX_VALUE} may be used to indicate that all
+     * levels should be visited.
+     *
+     * <p> When a security manager is installed and it denies access to a file
+     * (or directory), then it is ignored and not included in the stream.
+     *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the directory
+     * after this method has returned, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the method that caused
+     * the access to take place.
+     *
+     * @param   start
+     *          the starting file
+     * @param   maxDepth
+     *          the maximum number of directory levels to visit
+     * @param   options
+     *          options to configure the traversal
+     *
+     * @return  the {@link Stream} of {@link Path}
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code maxDepth} parameter is negative
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown when accessing the starting file.
+     * @since   1.8
+     */
+    public static Stream<Path> walk(Path start,
+                                    int maxDepth,
+                                    FileVisitOption... options)
+        throws IOException
+    {
+        FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
+    }
+
+    /**
+     * Return a {@code Stream} that is lazily populated with {@code
+     * Path} by walking the file tree rooted at a given starting file.  The
+     * file tree is traversed <em>depth-first</em>, the elements in the stream
+     * are {@link Path} objects that are obtained as if by {@link
+     * Path#resolve(Path) resolving} the relative path against {@code start}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * walk(start, Integer.MAX_VALUE, options)
+     * </pre></blockquote>
+     * In other words, it visits all levels of the file tree.
+     *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
+     * @param   start
+     *          the starting file
+     * @param   options
+     *          options to configure the traversal
+     *
+     * @return  the {@link Stream} of {@link Path}
+     *
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown when accessing the starting file.
+     *
+     * @see     #walk(Path, int, FileVisitOption...)
+     * @since   1.8
+     */
+    public static Stream<Path> walk(Path start, FileVisitOption... options) throws IOException {
+        return walk(start, Integer.MAX_VALUE, options);
+    }
+
+    /**
+     * Return a {@code Stream} that is lazily populated with {@code
+     * Path} by searching for files in a file tree rooted at a given starting
+     * file.
+     *
+     * <p> This method walks the file tree in exactly the manner specified by
+     * the {@link #walk walk} method. For each file encountered, the given
+     * {@link BiPredicate} is invoked with its {@link Path} and {@link
+     * BasicFileAttributes}. The {@code Path} object is obtained as if by
+     * {@link Path#resolve(Path) resolving} the relative path against {@code
+     * start} and is only included in the returned {@link Stream} if
+     * the {@code BiPredicate} returns true. Compare to calling {@link
+     * java.util.stream.Stream#filter filter} on the {@code Stream}
+     * returned by {@code walk} method, this method may be more efficient by
+     * avoiding redundant retrieval of the {@code BasicFileAttributes}.
+     *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
+     * <p> If an {@link IOException} is thrown when accessing the directory
+     * after returned from this method, it is wrapped in an {@link
+     * UncheckedIOException} which will be thrown from the method that caused
+     * the access to take place.
+     *
+     * @param   start
+     *          the starting file
+     * @param   maxDepth
+     *          the maximum number of directory levels to search
+     * @param   matcher
+     *          the function used to decide whether a file should be included
+     *          in the returned stream
+     * @param   options
+     *          options to configure the traversal
+     *
+     * @return  the {@link Stream} of {@link Path}
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code maxDepth} parameter is negative
+     * @throws  SecurityException
+     *          If the security manager denies access to the starting file.
+     *          In the case of the default provider, the {@link
+     *          SecurityManager#checkRead(String) checkRead} method is invoked
+     *          to check read access to the directory.
+     * @throws  IOException
+     *          if an I/O error is thrown when accessing the starting file.
+     *
+     * @see     #walk(Path, int, FileVisitOption...)
+     * @since   1.8
+     */
+    public static Stream<Path> find(Path start,
+                                    int maxDepth,
+                                    BiPredicate<Path, BasicFileAttributes> matcher,
+                                    FileVisitOption... options)
+        throws IOException
+    {
+        FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .filter(entry -> matcher.test(entry.file(), entry.attributes()))
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
+    }
+
+    /**
+     * Read all lines from a file as a {@code Stream}. Unlike {@link
+     * #readAllLines(Path, Charset) readAllLines}, this method does not read
+     * all lines into a {@code List}, but instead populates lazily as the stream
+     * is consumed.
+     *
+     * <p> Bytes from the file are decoded into characters using the specified
+     * charset and the same line terminators as specified by {@code
+     * readAllLines} are supported.
+     *
+     * <p> After this method returns, then any subsequent I/O exception that
+     * occurs while reading from the file or when a malformed or unmappable byte
+     * sequence is read, is wrapped in an {@link UncheckedIOException} that will
+     * be thrown from the
+     * {@link java.util.stream.Stream} method that caused the read to take
+     * place. In case an {@code IOException} is thrown when closing the file,
+     * it is also wrapped as an {@code UncheckedIOException}.
+     *
+     * <p> The returned stream encapsulates a {@link Reader}.  If timely
+     * disposal of file system resources is required, the try-with-resources
+     * construct should be used to ensure that the stream's
+     * {@link Stream#close close} method is invoked after the stream operations
+     * are completed.
+     *
+     *
+     * @param   path
+     *          the path to the file
+     * @param   cs
+     *          the charset to use for decoding
+     *
+     * @return  the lines from the file as a {@code Stream}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening the file
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @see     #readAllLines(Path, Charset)
+     * @see     #newBufferedReader(Path, Charset)
+     * @see     java.io.BufferedReader#lines()
+     * @since   1.8
+     */
+    public static Stream<String> lines(Path path, Charset cs) throws IOException {
+        BufferedReader br = Files.newBufferedReader(path, cs);
+        try {
+            return br.lines().onClose(asUncheckedRunnable(br));
+        } catch (Error|RuntimeException e) {
+            try {
+                br.close();
+            } catch (IOException ex) {
+                try {
+                    e.addSuppressed(ex);
+                } catch (Throwable ignore) {}
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * Read all lines from a file as a {@code Stream}. Bytes from the file are
+     * decoded into characters using the {@link StandardCharsets#UTF_8 UTF-8}
+     * {@link Charset charset}.
+     *
+     * <p> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <pre>{@code
+     * Files.lines(path, StandardCharsets.UTF_8)
+     * }</pre>
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  the lines from the file as a {@code Stream}
+     *
+     * @throws  IOException
+     *          if an I/O error occurs opening the file
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     *
+     * @since 1.8
+     */
+    public static Stream<String> lines(Path path) throws IOException {
+        return lines(path, StandardCharsets.UTF_8);
+    }
+}
diff --git a/java/nio/file/InvalidPathException.java b/java/nio/file/InvalidPathException.java
new file mode 100644
index 0000000..2c62865
--- /dev/null
+++ b/java/nio/file/InvalidPathException.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when path string cannot be converted into a
+ * {@link Path} because the path string contains invalid characters, or
+ * the path string is invalid for other file system specific reasons.
+ */
+
+public class InvalidPathException
+    extends IllegalArgumentException
+{
+    static final long serialVersionUID = 4355821422286746137L;
+
+    private String input;
+    private int index;
+
+    /**
+     * Constructs an instance from the given input string, reason, and error
+     * index.
+     *
+     * @param  input   the input string
+     * @param  reason  a string explaining why the input was rejected
+     * @param  index   the index at which the error occurred,
+     *                 or <tt>-1</tt> if the index is not known
+     *
+     * @throws  NullPointerException
+     *          if either the input or reason strings are <tt>null</tt>
+     *
+     * @throws  IllegalArgumentException
+     *          if the error index is less than <tt>-1</tt>
+     */
+    public InvalidPathException(String input, String reason, int index) {
+        super(reason);
+        if ((input == null) || (reason == null))
+            throw new NullPointerException();
+        if (index < -1)
+            throw new IllegalArgumentException();
+        this.input = input;
+        this.index = index;
+    }
+
+    /**
+     * Constructs an instance from the given input string and reason.  The
+     * resulting object will have an error index of <tt>-1</tt>.
+     *
+     * @param  input   the input string
+     * @param  reason  a string explaining why the input was rejected
+     *
+     * @throws  NullPointerException
+     *          if either the input or reason strings are <tt>null</tt>
+     */
+    public InvalidPathException(String input, String reason) {
+        this(input, reason, -1);
+    }
+
+    /**
+     * Returns the input string.
+     *
+     * @return  the input string
+     */
+    public String getInput() {
+        return input;
+    }
+
+    /**
+     * Returns a string explaining why the input string was rejected.
+     *
+     * @return  the reason string
+     */
+    public String getReason() {
+        return super.getMessage();
+    }
+
+    /**
+     * Returns an index into the input string of the position at which the
+     * error occurred, or <tt>-1</tt> if this position is not known.
+     *
+     * @return  the error index
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Returns a string describing the error.  The resulting string
+     * consists of the reason string followed by a colon character
+     * (<tt>':'</tt>), a space, and the input string.  If the error index is
+     * defined then the string <tt>" at index "</tt> followed by the index, in
+     * decimal, is inserted after the reason string and before the colon
+     * character.
+     *
+     * @return  a string describing the error
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(getReason());
+        if (index > -1) {
+            sb.append(" at index ");
+            sb.append(index);
+        }
+        sb.append(": ");
+        sb.append(input);
+        return sb.toString();
+    }
+}
diff --git a/java/nio/file/LinkOption.java b/java/nio/file/LinkOption.java
new file mode 100644
index 0000000..f1e133f
--- /dev/null
+++ b/java/nio/file/LinkOption.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the options as to how symbolic links are handled.
+ *
+ * @since 1.7
+ */
+
+public enum LinkOption implements OpenOption, CopyOption {
+    /**
+     * Do not follow symbolic links.
+     *
+     * @see Files#getFileAttributeView(Path,Class,LinkOption[])
+     * @see Files#copy
+     * @see SecureDirectoryStream#newByteChannel
+     */
+    NOFOLLOW_LINKS;
+}
diff --git a/java/nio/file/LinkPermission.java b/java/nio/file/LinkPermission.java
new file mode 100644
index 0000000..bf54e16
--- /dev/null
+++ b/java/nio/file/LinkPermission.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.security.BasicPermission;
+
+/**
+ * The {@code Permission} class for link creation operations.
+ *
+ * <p> The following table provides a summary description of what the permission
+ * allows, and discusses the risks of granting code the permission.
+ *
+ * <table border=1 cellpadding=5
+ *        summary="Table shows permission target name, what the permission allows, and associated risks">
+ * <tr>
+ * <th>Permission Target Name</th>
+ * <th>What the Permission Allows</th>
+ * <th>Risks of Allowing this Permission</th>
+ * </tr>
+ * <tr>
+ *   <td>hard</td>
+ *   <td> Ability to add an existing file to a directory. This is sometimes
+ *   known as creating a link, or hard link. </td>
+ *   <td> Extreme care should be taken when granting this permission. It allows
+ *   linking to any file or directory in the file system thus allowing the
+ *   attacker access to all files. </td>
+ * </tr>
+ * <tr>
+ *   <td>symbolic</td>
+ *   <td> Ability to create symbolic links. </td>
+ *   <td> Extreme care should be taken when granting this permission. It allows
+ *   linking to any file or directory in the file system thus allowing the
+ *   attacker to access to all files. </td>
+ * </tr>
+ * </table>
+ *
+ * @since 1.7
+ *
+ * @see Files#createLink
+ * @see Files#createSymbolicLink
+ */
+public final class LinkPermission extends BasicPermission {
+    static final long serialVersionUID = -1441492453772213220L;
+
+    private void checkName(String name) {
+        if (!name.equals("hard") && !name.equals("symbolic")) {
+            throw new IllegalArgumentException("name: " + name);
+        }
+    }
+
+    /**
+     * Constructs a {@code LinkPermission} with the specified name.
+     *
+     * @param   name
+     *          the name of the permission. It must be "hard" or "symbolic".
+     *
+     * @throws  IllegalArgumentException
+     *          if name is empty or invalid
+     */
+    public LinkPermission(String name) {
+        super(name);
+        checkName(name);
+    }
+
+    /**
+     * Constructs a {@code LinkPermission} with the specified name.
+     *
+     * @param   name
+     *          the name of the permission; must be "hard" or "symbolic".
+     * @param   actions
+     *          the actions for the permission; must be the empty string or
+     *          {@code null}
+     *
+     * @throws  IllegalArgumentException
+     *          if name is empty or invalid, or actions is a non-empty string
+     */
+    public LinkPermission(String name, String actions) {
+        super(name);
+        checkName(name);
+        if (actions != null && actions.length() > 0) {
+            throw new IllegalArgumentException("actions: " + actions);
+        }
+    }
+}
diff --git a/java/nio/file/NoSuchFileException.java b/java/nio/file/NoSuchFileException.java
new file mode 100644
index 0000000..1f2ab3d
--- /dev/null
+++ b/java/nio/file/NoSuchFileException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when an attempt is made to access a file that does
+ * not exist.
+ *
+ * @since 1.7
+ */
+
+public class NoSuchFileException
+    extends FileSystemException
+{
+    static final long serialVersionUID = -1390291775875351931L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known.
+     */
+    public NoSuchFileException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known.
+     * @param   other
+     *          a string identifying the other file or {@code null} if not known.
+     * @param   reason
+     *          a reason message with additional information or {@code null}
+     */
+    public NoSuchFileException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
diff --git a/java/nio/file/NotDirectoryException.java b/java/nio/file/NotDirectoryException.java
new file mode 100644
index 0000000..4082cea
--- /dev/null
+++ b/java/nio/file/NotDirectoryException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation, intended for a
+ * directory, fails because the file is not a directory.
+ *
+ * @since 1.7
+ */
+
+public class NotDirectoryException
+    extends FileSystemException
+{
+    private static final long serialVersionUID = -9011457427178200199L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     */
+    public NotDirectoryException(String file) {
+        super(file);
+    }
+}
diff --git a/java/nio/file/NotLinkException.java b/java/nio/file/NotLinkException.java
new file mode 100644
index 0000000..353e4d7
--- /dev/null
+++ b/java/nio/file/NotLinkException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Checked exception thrown when a file system operation fails because a file
+ * is not a symbolic link.
+ *
+ * @since 1.7
+ */
+
+public class NotLinkException
+    extends FileSystemException
+{
+    static final long serialVersionUID = -388655596416518021L;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     */
+    public NotLinkException(String file) {
+        super(file);
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   file
+     *          a string identifying the file or {@code null} if not known
+     * @param   other
+     *          a string identifying the other file or {@code null} if not known
+     * @param   reason
+     *          a reason message with additional information or {@code null}
+     */
+    public NotLinkException(String file, String other, String reason) {
+        super(file, other, reason);
+    }
+}
diff --git a/java/nio/file/OpenOption.java b/java/nio/file/OpenOption.java
new file mode 100644
index 0000000..aef96fb
--- /dev/null
+++ b/java/nio/file/OpenOption.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An object that configures how to open or create a file.
+ *
+ * <p> Objects of this type are used by methods such as {@link
+ * Files#newOutputStream(Path,OpenOption[]) newOutputStream}, {@link
+ * Files#newByteChannel newByteChannel}, {@link
+ * java.nio.channels.FileChannel#open FileChannel.open}, and {@link
+ * java.nio.channels.AsynchronousFileChannel#open AsynchronousFileChannel.open}
+ * when opening or creating a file.
+ *
+ * <p> The {@link StandardOpenOption} enumeration type defines the
+ * <i>standard</i> options.
+ *
+ * @since 1.7
+ */
+
+public interface OpenOption {
+}
diff --git a/java/nio/file/Path.java b/java/nio/file/Path.java
new file mode 100644
index 0000000..daa09f4
--- /dev/null
+++ b/java/nio/file/Path.java
@@ -0,0 +1,801 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Iterator;
+
+/**
+ * An object that may be used to locate a file in a file system. It will
+ * typically represent a system dependent file path.
+ *
+ * <p> A {@code Path} represents a path that is hierarchical and composed of a
+ * sequence of directory and file name elements separated by a special separator
+ * or delimiter. A <em>root component</em>, that identifies a file system
+ * hierarchy, may also be present. The name element that is <em>farthest</em>
+ * from the root of the directory hierarchy is the name of a file or directory.
+ * The other name elements are directory names. A {@code Path} can represent a
+ * root, a root and a sequence of names, or simply one or more name elements.
+ * A {@code Path} is considered to be an <i>empty path</i> if it consists
+ * solely of one name element that is empty. Accessing a file using an
+ * <i>empty path</i> is equivalent to accessing the default directory of the
+ * file system. {@code Path} defines the {@link #getFileName() getFileName},
+ * {@link #getParent getParent}, {@link #getRoot getRoot}, and {@link #subpath
+ * subpath} methods to access the path components or a subsequence of its name
+ * elements.
+ *
+ * <p> In addition to accessing the components of a path, a {@code Path} also
+ * defines the {@link #resolve(Path) resolve} and {@link #resolveSibling(Path)
+ * resolveSibling} methods to combine paths. The {@link #relativize relativize}
+ * method that can be used to construct a relative path between two paths.
+ * Paths can be {@link #compareTo compared}, and tested against each other using
+ * the {@link #startsWith startsWith} and {@link #endsWith endsWith} methods.
+ *
+ * <p> This interface extends {@link Watchable} interface so that a directory
+ * located by a path can be {@link #register registered} with a {@link
+ * WatchService} and entries in the directory watched. </p>
+ *
+ * <p> <b>WARNING:</b> This interface is only intended to be implemented by
+ * those developing custom file system implementations. Methods may be added to
+ * this interface in future releases. </p>
+ *
+ * <h2>Accessing Files</h2>
+ * <p> Paths may be used with the {@link Files} class to operate on files,
+ * directories, and other types of files. For example, suppose we want a {@link
+ * java.io.BufferedReader} to read text from a file "{@code access.log}". The
+ * file is located in a directory "{@code logs}" relative to the current working
+ * directory and is UTF-8 encoded.
+ * <pre>
+ *     Path path = FileSystems.getDefault().getPath("logs", "access.log");
+ *     BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8);
+ * </pre>
+ *
+ * <a name="interop"></a><h2>Interoperability</h2>
+ * <p> Paths associated with the default {@link
+ * java.nio.file.spi.FileSystemProvider provider} are generally interoperable
+ * with the {@link java.io.File java.io.File} class. Paths created by other
+ * providers are unlikely to be interoperable with the abstract path names
+ * represented by {@code java.io.File}. The {@link java.io.File#toPath toPath}
+ * method may be used to obtain a {@code Path} from the abstract path name
+ * represented by a {@code java.io.File} object. The resulting {@code Path} can
+ * be used to operate on the same file as the {@code java.io.File} object. In
+ * addition, the {@link #toFile toFile} method is useful to construct a {@code
+ * File} from the {@code String} representation of a {@code Path}.
+ *
+ * <h2>Concurrency</h2>
+ * <p> Implementations of this interface are immutable and safe for use by
+ * multiple concurrent threads.
+ *
+ * @since 1.7
+ * @see Paths
+ */
+
+public interface Path
+    extends Comparable<Path>, Iterable<Path>, Watchable
+{
+    /**
+     * Returns the file system that created this object.
+     *
+     * @return  the file system that created this object
+     */
+    FileSystem getFileSystem();
+
+    /**
+     * Tells whether or not this path is absolute.
+     *
+     * <p> An absolute path is complete in that it doesn't need to be combined
+     * with other path information in order to locate a file.
+     *
+     * @return  {@code true} if, and only if, this path is absolute
+     */
+    boolean isAbsolute();
+
+    /**
+     * Returns the root component of this path as a {@code Path} object,
+     * or {@code null} if this path does not have a root component.
+     *
+     * @return  a path representing the root component of this path,
+     *          or {@code null}
+     */
+    Path getRoot();
+
+    /**
+     * Returns the name of the file or directory denoted by this path as a
+     * {@code Path} object. The file name is the <em>farthest</em> element from
+     * the root in the directory hierarchy.
+     *
+     * @return  a path representing the name of the file or directory, or
+     *          {@code null} if this path has zero elements
+     */
+    Path getFileName();
+
+    /**
+     * Returns the <em>parent path</em>, or {@code null} if this path does not
+     * have a parent.
+     *
+     * <p> The parent of this path object consists of this path's root
+     * component, if any, and each element in the path except for the
+     * <em>farthest</em> from the root in the directory hierarchy. This method
+     * does not access the file system; the path or its parent may not exist.
+     * Furthermore, this method does not eliminate special names such as "."
+     * and ".." that may be used in some implementations. On UNIX for example,
+     * the parent of "{@code /a/b/c}" is "{@code /a/b}", and the parent of
+     * {@code "x/y/.}" is "{@code x/y}". This method may be used with the {@link
+     * #normalize normalize} method, to eliminate redundant names, for cases where
+     * <em>shell-like</em> navigation is required.
+     *
+     * <p> If this path has one or more elements, and no root component, then
+     * this method is equivalent to evaluating the expression:
+     * <blockquote><pre>
+     * subpath(0,&nbsp;getNameCount()-1);
+     * </pre></blockquote>
+     *
+     * @return  a path representing the path's parent
+     */
+    Path getParent();
+
+    /**
+     * Returns the number of name elements in the path.
+     *
+     * @return  the number of elements in the path, or {@code 0} if this path
+     *          only represents a root component
+     */
+    int getNameCount();
+
+    /**
+     * Returns a name element of this path as a {@code Path} object.
+     *
+     * <p> The {@code index} parameter is the index of the name element to return.
+     * The element that is <em>closest</em> to the root in the directory hierarchy
+     * has index {@code 0}. The element that is <em>farthest</em> from the root
+     * has index {@link #getNameCount count}{@code -1}.
+     *
+     * @param   index
+     *          the index of the element
+     *
+     * @return  the name element
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code index} is negative, {@code index} is greater than or
+     *          equal to the number of elements, or this path has zero name
+     *          elements
+     */
+    Path getName(int index);
+
+    /**
+     * Returns a relative {@code Path} that is a subsequence of the name
+     * elements of this path.
+     *
+     * <p> The {@code beginIndex} and {@code endIndex} parameters specify the
+     * subsequence of name elements. The name that is <em>closest</em> to the root
+     * in the directory hierarchy has index {@code 0}. The name that is
+     * <em>farthest</em> from the root has index {@link #getNameCount
+     * count}{@code -1}. The returned {@code Path} object has the name elements
+     * that begin at {@code beginIndex} and extend to the element at index {@code
+     * endIndex-1}.
+     *
+     * @param   beginIndex
+     *          the index of the first element, inclusive
+     * @param   endIndex
+     *          the index of the last element, exclusive
+     *
+     * @return  a new {@code Path} object that is a subsequence of the name
+     *          elements in this {@code Path}
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code beginIndex} is negative, or greater than or equal to
+     *          the number of elements. If {@code endIndex} is less than or
+     *          equal to {@code beginIndex}, or larger than the number of elements.
+     */
+    Path subpath(int beginIndex, int endIndex);
+
+    /**
+     * Tests if this path starts with the given path.
+     *
+     * <p> This path <em>starts</em> with the given path if this path's root
+     * component <em>starts</em> with the root component of the given path,
+     * and this path starts with the same name elements as the given path.
+     * If the given path has more name elements than this path then {@code false}
+     * is returned.
+     *
+     * <p> Whether or not the root component of this path starts with the root
+     * component of the given path is file system specific. If this path does
+     * not have a root component and the given path has a root component then
+     * this path does not start with the given path.
+     *
+     * <p> If the given path is associated with a different {@code FileSystem}
+     * to this path then {@code false} is returned.
+     *
+     * @param   other
+     *          the given path
+     *
+     * @return  {@code true} if this path starts with the given path; otherwise
+     *          {@code false}
+     */
+    boolean startsWith(Path other);
+
+    /**
+     * Tests if this path starts with a {@code Path}, constructed by converting
+     * the given path string, in exactly the manner specified by the {@link
+     * #startsWith(Path) startsWith(Path)} method. On UNIX for example, the path
+     * "{@code foo/bar}" starts with "{@code foo}" and "{@code foo/bar}". It
+     * does not start with "{@code f}" or "{@code fo}".
+     *
+     * @param   other
+     *          the given path string
+     *
+     * @return  {@code true} if this path starts with the given path; otherwise
+     *          {@code false}
+     *
+     * @throws  InvalidPathException
+     *          If the path string cannot be converted to a Path.
+     */
+    boolean startsWith(String other);
+
+    /**
+     * Tests if this path ends with the given path.
+     *
+     * <p> If the given path has <em>N</em> elements, and no root component,
+     * and this path has <em>N</em> or more elements, then this path ends with
+     * the given path if the last <em>N</em> elements of each path, starting at
+     * the element farthest from the root, are equal.
+     *
+     * <p> If the given path has a root component then this path ends with the
+     * given path if the root component of this path <em>ends with</em> the root
+     * component of the given path, and the corresponding elements of both paths
+     * are equal. Whether or not the root component of this path ends with the
+     * root component of the given path is file system specific. If this path
+     * does not have a root component and the given path has a root component
+     * then this path does not end with the given path.
+     *
+     * <p> If the given path is associated with a different {@code FileSystem}
+     * to this path then {@code false} is returned.
+     *
+     * @param   other
+     *          the given path
+     *
+     * @return  {@code true} if this path ends with the given path; otherwise
+     *          {@code false}
+     */
+    boolean endsWith(Path other);
+
+    /**
+     * Tests if this path ends with a {@code Path}, constructed by converting
+     * the given path string, in exactly the manner specified by the {@link
+     * #endsWith(Path) endsWith(Path)} method. On UNIX for example, the path
+     * "{@code foo/bar}" ends with "{@code foo/bar}" and "{@code bar}". It does
+     * not end with "{@code r}" or "{@code /bar}". Note that trailing separators
+     * are not taken into account, and so invoking this method on the {@code
+     * Path}"{@code foo/bar}" with the {@code String} "{@code bar/}" returns
+     * {@code true}.
+     *
+     * @param   other
+     *          the given path string
+     *
+     * @return  {@code true} if this path ends with the given path; otherwise
+     *          {@code false}
+     *
+     * @throws  InvalidPathException
+     *          If the path string cannot be converted to a Path.
+     */
+    boolean endsWith(String other);
+
+    /**
+     * Returns a path that is this path with redundant name elements eliminated.
+     *
+     * <p> The precise definition of this method is implementation dependent but
+     * in general it derives from this path, a path that does not contain
+     * <em>redundant</em> name elements. In many file systems, the "{@code .}"
+     * and "{@code ..}" are special names used to indicate the current directory
+     * and parent directory. In such file systems all occurrences of "{@code .}"
+     * are considered redundant. If a "{@code ..}" is preceded by a
+     * non-"{@code ..}" name then both names are considered redundant (the
+     * process to identify such names is repeated until it is no longer
+     * applicable).
+     *
+     * <p> This method does not access the file system; the path may not locate
+     * a file that exists. Eliminating "{@code ..}" and a preceding name from a
+     * path may result in the path that locates a different file than the original
+     * path. This can arise when the preceding name is a symbolic link.
+     *
+     * @return  the resulting path or this path if it does not contain
+     *          redundant name elements; an empty path is returned if this path
+     *          does have a root component and all name elements are redundant
+     *
+     * @see #getParent
+     * @see #toRealPath
+     */
+    Path normalize();
+
+    // -- resolution and relativization --
+
+    /**
+     * Resolve the given path against this path.
+     *
+     * <p> If the {@code other} parameter is an {@link #isAbsolute() absolute}
+     * path then this method trivially returns {@code other}. If {@code other}
+     * is an <i>empty path</i> then this method trivially returns this path.
+     * Otherwise this method considers this path to be a directory and resolves
+     * the given path against this path. In the simplest case, the given path
+     * does not have a {@link #getRoot root} component, in which case this method
+     * <em>joins</em> the given path to this path and returns a resulting path
+     * that {@link #endsWith ends} with the given path. Where the given path has
+     * a root component then resolution is highly implementation dependent and
+     * therefore unspecified.
+     *
+     * @param   other
+     *          the path to resolve against this path
+     *
+     * @return  the resulting path
+     *
+     * @see #relativize
+     */
+    Path resolve(Path other);
+
+    /**
+     * Converts a given path string to a {@code Path} and resolves it against
+     * this {@code Path} in exactly the manner specified by the {@link
+     * #resolve(Path) resolve} method. For example, suppose that the name
+     * separator is "{@code /}" and a path represents "{@code foo/bar}", then
+     * invoking this method with the path string "{@code gus}" will result in
+     * the {@code Path} "{@code foo/bar/gus}".
+     *
+     * @param   other
+     *          the path string to resolve against this path
+     *
+     * @return  the resulting path
+     *
+     * @throws  InvalidPathException
+     *          if the path string cannot be converted to a Path.
+     *
+     * @see FileSystem#getPath
+     */
+    Path resolve(String other);
+
+    /**
+     * Resolves the given path against this path's {@link #getParent parent}
+     * path. This is useful where a file name needs to be <i>replaced</i> with
+     * another file name. For example, suppose that the name separator is
+     * "{@code /}" and a path represents "{@code dir1/dir2/foo}", then invoking
+     * this method with the {@code Path} "{@code bar}" will result in the {@code
+     * Path} "{@code dir1/dir2/bar}". If this path does not have a parent path,
+     * or {@code other} is {@link #isAbsolute() absolute}, then this method
+     * returns {@code other}. If {@code other} is an empty path then this method
+     * returns this path's parent, or where this path doesn't have a parent, the
+     * empty path.
+     *
+     * @param   other
+     *          the path to resolve against this path's parent
+     *
+     * @return  the resulting path
+     *
+     * @see #resolve(Path)
+     */
+    Path resolveSibling(Path other);
+
+    /**
+     * Converts a given path string to a {@code Path} and resolves it against
+     * this path's {@link #getParent parent} path in exactly the manner
+     * specified by the {@link #resolveSibling(Path) resolveSibling} method.
+     *
+     * @param   other
+     *          the path string to resolve against this path's parent
+     *
+     * @return  the resulting path
+     *
+     * @throws  InvalidPathException
+     *          if the path string cannot be converted to a Path.
+     *
+     * @see FileSystem#getPath
+     */
+    Path resolveSibling(String other);
+
+    /**
+     * Constructs a relative path between this path and a given path.
+     *
+     * <p> Relativization is the inverse of {@link #resolve(Path) resolution}.
+     * This method attempts to construct a {@link #isAbsolute relative} path
+     * that when {@link #resolve(Path) resolved} against this path, yields a
+     * path that locates the same file as the given path. For example, on UNIX,
+     * if this path is {@code "/a/b"} and the given path is {@code "/a/b/c/d"}
+     * then the resulting relative path would be {@code "c/d"}. Where this
+     * path and the given path do not have a {@link #getRoot root} component,
+     * then a relative path can be constructed. A relative path cannot be
+     * constructed if only one of the paths have a root component. Where both
+     * paths have a root component then it is implementation dependent if a
+     * relative path can be constructed. If this path and the given path are
+     * {@link #equals equal} then an <i>empty path</i> is returned.
+     *
+     * <p> For any two {@link #normalize normalized} paths <i>p</i> and
+     * <i>q</i>, where <i>q</i> does not have a root component,
+     * <blockquote>
+     *   <i>p</i><tt>.relativize(</tt><i>p</i><tt>.resolve(</tt><i>q</i><tt>)).equals(</tt><i>q</i><tt>)</tt>
+     * </blockquote>
+     *
+     * <p> When symbolic links are supported, then whether the resulting path,
+     * when resolved against this path, yields a path that can be used to locate
+     * the {@link Files#isSameFile same} file as {@code other} is implementation
+     * dependent. For example, if this path is  {@code "/a/b"} and the given
+     * path is {@code "/a/x"} then the resulting relative path may be {@code
+     * "../x"}. If {@code "b"} is a symbolic link then is implementation
+     * dependent if {@code "a/b/../x"} would locate the same file as {@code "/a/x"}.
+     *
+     * @param   other
+     *          the path to relativize against this path
+     *
+     * @return  the resulting relative path, or an empty path if both paths are
+     *          equal
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code other} is not a {@code Path} that can be relativized
+     *          against this path
+     */
+    Path relativize(Path other);
+
+    /**
+     * Returns a URI to represent this path.
+     *
+     * <p> This method constructs an absolute {@link URI} with a {@link
+     * URI#getScheme() scheme} equal to the URI scheme that identifies the
+     * provider. The exact form of the scheme specific part is highly provider
+     * dependent.
+     *
+     * <p> In the case of the default provider, the URI is hierarchical with
+     * a {@link URI#getPath() path} component that is absolute. The query and
+     * fragment components are undefined. Whether the authority component is
+     * defined or not is implementation dependent. There is no guarantee that
+     * the {@code URI} may be used to construct a {@link java.io.File java.io.File}.
+     * In particular, if this path represents a Universal Naming Convention (UNC)
+     * path, then the UNC server name may be encoded in the authority component
+     * of the resulting URI. In the case of the default provider, and the file
+     * exists, and it can be determined that the file is a directory, then the
+     * resulting {@code URI} will end with a slash.
+     *
+     * <p> The default provider provides a similar <em>round-trip</em> guarantee
+     * to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
+     * is guaranteed that
+     * <blockquote><tt>
+     * {@link Paths#get(URI) Paths.get}(</tt><i>p</i><tt>.toUri()).equals(</tt><i>p</i>
+     * <tt>.{@link #toAbsolutePath() toAbsolutePath}())</tt>
+     * </blockquote>
+     * so long as the original {@code Path}, the {@code URI}, and the new {@code
+     * Path} are all created in (possibly different invocations of) the same
+     * Java virtual machine. Whether other providers make any guarantees is
+     * provider specific and therefore unspecified.
+     *
+     * <p> When a file system is constructed to access the contents of a file
+     * as a file system then it is highly implementation specific if the returned
+     * URI represents the given path in the file system or it represents a
+     * <em>compound</em> URI that encodes the URI of the enclosing file system.
+     * A format for compound URIs is not defined in this release; such a scheme
+     * may be added in a future release.
+     *
+     * @return  the URI representing this path
+     *
+     * @throws  java.io.IOError
+     *          if an I/O error occurs obtaining the absolute path, or where a
+     *          file system is constructed to access the contents of a file as
+     *          a file system, and the URI of the enclosing file system cannot be
+     *          obtained
+     *
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, the {@link #toAbsolutePath toAbsolutePath} method
+     *          throws a security exception.
+     */
+    URI toUri();
+
+    /**
+     * Returns a {@code Path} object representing the absolute path of this
+     * path.
+     *
+     * <p> If this path is already {@link Path#isAbsolute absolute} then this
+     * method simply returns this path. Otherwise, this method resolves the path
+     * in an implementation dependent manner, typically by resolving the path
+     * against a file system default directory. Depending on the implementation,
+     * this method may throw an I/O error if the file system is not accessible.
+     *
+     * @return  a {@code Path} object representing the absolute path
+     *
+     * @throws  java.io.IOError
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager
+     *          is installed, and this path is not absolute, then the security
+     *          manager's {@link SecurityManager#checkPropertyAccess(String)
+     *          checkPropertyAccess} method is invoked to check access to the
+     *          system property {@code user.dir}
+     */
+    Path toAbsolutePath();
+
+    /**
+     * Returns the <em>real</em> path of an existing file.
+     *
+     * <p> The precise definition of this method is implementation dependent but
+     * in general it derives from this path, an {@link #isAbsolute absolute}
+     * path that locates the {@link Files#isSameFile same} file as this path, but
+     * with name elements that represent the actual name of the directories
+     * and the file. For example, where filename comparisons on a file system
+     * are case insensitive then the name elements represent the names in their
+     * actual case. Additionally, the resulting path has redundant name
+     * elements removed.
+     *
+     * <p> If this path is relative then its absolute path is first obtained,
+     * as if by invoking the {@link #toAbsolutePath toAbsolutePath} method.
+     *
+     * <p> The {@code options} array may be used to indicate how symbolic links
+     * are handled. By default, symbolic links are resolved to their final
+     * target. If the option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is
+     * present then this method does not resolve symbolic links.
+     *
+     * Some implementations allow special names such as "{@code ..}" to refer to
+     * the parent directory. When deriving the <em>real path</em>, and a
+     * "{@code ..}" (or equivalent) is preceded by a non-"{@code ..}" name then
+     * an implementation will typically cause both names to be removed. When
+     * not resolving symbolic links and the preceding name is a symbolic link
+     * then the names are only removed if it guaranteed that the resulting path
+     * will locate the same file as this path.
+     *
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  an absolute path represent the <em>real</em> path of the file
+     *          located by this object
+     *
+     * @throws  IOException
+     *          if the file does not exist or an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file, and where
+     *          this path is not absolute, its {@link SecurityManager#checkPropertyAccess(String)
+     *          checkPropertyAccess} method is invoked to check access to the
+     *          system property {@code user.dir}
+     */
+    Path toRealPath(LinkOption... options) throws IOException;
+
+    /**
+     * Returns a {@link File} object representing this path. Where this {@code
+     * Path} is associated with the default provider, then this method is
+     * equivalent to returning a {@code File} object constructed with the
+     * {@code String} representation of this path.
+     *
+     * <p> If this path was created by invoking the {@code File} {@link
+     * File#toPath toPath} method then there is no guarantee that the {@code
+     * File} object returned by this method is {@link #equals equal} to the
+     * original {@code File}.
+     *
+     * @return  a {@code File} object representing this path
+     *
+     * @throws  UnsupportedOperationException
+     *          if this {@code Path} is not associated with the default provider
+     */
+    File toFile();
+
+    // -- watchable --
+
+    /**
+     * Registers the file located by this path with a watch service.
+     *
+     * <p> In this release, this path locates a directory that exists. The
+     * directory is registered with the watch service so that entries in the
+     * directory can be watched. The {@code events} parameter is the events to
+     * register and may contain the following events:
+     * <ul>
+     *   <li>{@link StandardWatchEventKinds#ENTRY_CREATE ENTRY_CREATE} -
+     *       entry created or moved into the directory</li>
+     *   <li>{@link StandardWatchEventKinds#ENTRY_DELETE ENTRY_DELETE} -
+     *        entry deleted or moved out of the directory</li>
+     *   <li>{@link StandardWatchEventKinds#ENTRY_MODIFY ENTRY_MODIFY} -
+     *        entry in directory was modified</li>
+     * </ul>
+     *
+     * <p> The {@link WatchEvent#context context} for these events is the
+     * relative path between the directory located by this path, and the path
+     * that locates the directory entry that is created, deleted, or modified.
+     *
+     * <p> The set of events may include additional implementation specific
+     * event that are not defined by the enum {@link StandardWatchEventKinds}
+     *
+     * <p> The {@code modifiers} parameter specifies <em>modifiers</em> that
+     * qualify how the directory is registered. This release does not define any
+     * <em>standard</em> modifiers. It may contain implementation specific
+     * modifiers.
+     *
+     * <p> Where a file is registered with a watch service by means of a symbolic
+     * link then it is implementation specific if the watch continues to depend
+     * on the existence of the symbolic link after it is registered.
+     *
+     * @param   watcher
+     *          the watch service to which this object is to be registered
+     * @param   events
+     *          the events for which this object should be registered
+     * @param   modifiers
+     *          the modifiers, if any, that modify how the object is registered
+     *
+     * @return  a key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          if unsupported events or modifiers are specified
+     * @throws  IllegalArgumentException
+     *          if an invalid combination of events or modifiers is specified
+     * @throws  ClosedWatchServiceException
+     *          if the watch service is closed
+     * @throws  NotDirectoryException
+     *          if the file is registered to watch the entries in a directory
+     *          and the file is not a directory  <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    @Override
+    WatchKey register(WatchService watcher,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+        throws IOException;
+
+    /**
+     * Registers the file located by this path with a watch service.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     watchable.{@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) register}(watcher, events, new WatchEvent.Modifier[0]);
+     * </pre>
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we wish to register a directory for entry create, delete, and modify
+     * events:
+     * <pre>
+     *     Path dir = ...
+     *     WatchService watcher = ...
+     *
+     *     WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+     * </pre>
+     * @param   watcher
+     *          The watch service to which this object is to be registered
+     * @param   events
+     *          The events for which this object should be registered
+     *
+     * @return  A key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          If unsupported events are specified
+     * @throws  IllegalArgumentException
+     *          If an invalid combination of events is specified
+     * @throws  ClosedWatchServiceException
+     *          If the watch service is closed
+     * @throws  NotDirectoryException
+     *          If the file is registered to watch the entries in a directory
+     *          and the file is not a directory  <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    @Override
+    WatchKey register(WatchService watcher,
+                      WatchEvent.Kind<?>... events)
+        throws IOException;
+
+    // -- Iterable --
+
+    /**
+     * Returns an iterator over the name elements of this path.
+     *
+     * <p> The first element returned by the iterator represents the name
+     * element that is closest to the root in the directory hierarchy, the
+     * second element is the next closest, and so on. The last element returned
+     * is the name of the file or directory denoted by this path. The {@link
+     * #getRoot root} component, if present, is not returned by the iterator.
+     *
+     * @return  an iterator over the name elements of this path.
+     */
+    @Override
+    Iterator<Path> iterator();
+
+    // -- compareTo/equals/hashCode --
+
+    /**
+     * Compares two abstract paths lexicographically. The ordering defined by
+     * this method is provider specific, and in the case of the default
+     * provider, platform specific. This method does not access the file system
+     * and neither file is required to exist.
+     *
+     * <p> This method may not be used to compare paths that are associated
+     * with different file system providers.
+     *
+     * @param   other  the path compared to this path.
+     *
+     * @return  zero if the argument is {@link #equals equal} to this path, a
+     *          value less than zero if this path is lexicographically less than
+     *          the argument, or a value greater than zero if this path is
+     *          lexicographically greater than the argument
+     *
+     * @throws  ClassCastException
+     *          if the paths are associated with different providers
+     */
+    @Override
+    int compareTo(Path other);
+
+    /**
+     * Tests this path for equality with the given object.
+     *
+     * <p> If the given object is not a Path, or is a Path associated with a
+     * different {@code FileSystem}, then this method returns {@code false}.
+     *
+     * <p> Whether or not two path are equal depends on the file system
+     * implementation. In some cases the paths are compared without regard
+     * to case, and others are case sensitive. This method does not access the
+     * file system and the file is not required to exist. Where required, the
+     * {@link Files#isSameFile isSameFile} method may be used to check if two
+     * paths locate the same file.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   other
+     *          the object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is a {@code Path}
+     *          that is identical to this {@code Path}
+     */
+    boolean equals(Object other);
+
+    /**
+     * Computes a hash code for this path.
+     *
+     * <p> The hash code is based upon the components of the path, and
+     * satisfies the general contract of the {@link Object#hashCode
+     * Object.hashCode} method.
+     *
+     * @return  the hash-code value for this path
+     */
+    int hashCode();
+
+    /**
+     * Returns the string representation of this path.
+     *
+     * <p> If this path was created by converting a path string using the
+     * {@link FileSystem#getPath getPath} method then the path string returned
+     * by this method may differ from the original String used to create the path.
+     *
+     * <p> The returned path string uses the default name {@link
+     * FileSystem#getSeparator separator} to separate names in the path.
+     *
+     * @return  the string representation of this path
+     */
+    String toString();
+}
diff --git a/java/nio/file/PathMatcher.java b/java/nio/file/PathMatcher.java
new file mode 100644
index 0000000..24e6149
--- /dev/null
+++ b/java/nio/file/PathMatcher.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An interface that is implemented by objects that perform match operations on
+ * paths.
+ *
+ * @since 1.7
+ *
+ * @see FileSystem#getPathMatcher
+ * @see Files#newDirectoryStream(Path,String)
+ */
+@FunctionalInterface
+public interface PathMatcher {
+    /**
+     * Tells if given path matches this matcher's pattern.
+     *
+     * @param   path
+     *          the path to match
+     *
+     * @return  {@code true} if, and only if, the path matches this
+     *          matcher's pattern
+     */
+    boolean matches(Path path);
+}
diff --git a/java/nio/file/Paths.java b/java/nio/file/Paths.java
new file mode 100644
index 0000000..bb49f99
--- /dev/null
+++ b/java/nio/file/Paths.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.spi.FileSystemProvider;
+import java.net.URI;
+
+/**
+ * This class consists exclusively of static methods that return a {@link Path}
+ * by converting a path string or {@link URI}.
+ *
+ * @since 1.7
+ */
+
+public final class Paths {
+    private Paths() { }
+
+    /**
+     * Converts a path string, or a sequence of strings that when joined form
+     * a path string, to a {@code Path}. If {@code more} does not specify any
+     * elements then the value of the {@code first} parameter is the path string
+     * to convert. If {@code more} specifies one or more elements then each
+     * non-empty string, including {@code first}, is considered to be a sequence
+     * of name elements (see {@link Path}) and is joined to form a path string.
+     * The details as to how the Strings are joined is provider specific but
+     * typically they will be joined using the {@link FileSystem#getSeparator
+     * name-separator} as the separator. For example, if the name separator is
+     * "{@code /}" and {@code getPath("/foo","bar","gus")} is invoked, then the
+     * path string {@code "/foo/bar/gus"} is converted to a {@code Path}.
+     * A {@code Path} representing an empty path is returned if {@code first}
+     * is the empty string and {@code more} does not contain any non-empty
+     * strings.
+     *
+     * <p> The {@code Path} is obtained by invoking the {@link FileSystem#getPath
+     * getPath} method of the {@link FileSystems#getDefault default} {@link
+     * FileSystem}.
+     *
+     * <p> Note that while this method is very convenient, using it will imply
+     * an assumed reference to the default {@code FileSystem} and limit the
+     * utility of the calling code. Hence it should not be used in library code
+     * intended for flexible reuse. A more flexible alternative is to use an
+     * existing {@code Path} instance as an anchor, such as:
+     * <pre>
+     *     Path dir = ...
+     *     Path path = dir.resolve("file");
+     * </pre>
+     *
+     * @param   first
+     *          the path string or initial part of the path string
+     * @param   more
+     *          additional strings to be joined to form the path string
+     *
+     * @return  the resulting {@code Path}
+     *
+     * @throws  InvalidPathException
+     *          if the path string cannot be converted to a {@code Path}
+     *
+     * @see FileSystem#getPath
+     */
+    public static Path get(String first, String... more) {
+        return FileSystems.getDefault().getPath(first, more);
+    }
+
+    /**
+     * Converts the given URI to a {@link Path} object.
+     *
+     * <p> This method iterates over the {@link FileSystemProvider#installedProviders()
+     * installed} providers to locate the provider that is identified by the
+     * URI {@link URI#getScheme scheme} of the given URI. URI schemes are
+     * compared without regard to case. If the provider is found then its {@link
+     * FileSystemProvider#getPath getPath} method is invoked to convert the
+     * URI.
+     *
+     * <p> In the case of the default provider, identified by the URI scheme
+     * "file", the given URI has a non-empty path component, and undefined query
+     * and fragment components. Whether the authority component may be present
+     * is platform specific. The returned {@code Path} is associated with the
+     * {@link FileSystems#getDefault default} file system.
+     *
+     * <p> The default provider provides a similar <em>round-trip</em> guarantee
+     * to the {@link java.io.File} class. For a given {@code Path} <i>p</i> it
+     * is guaranteed that
+     * <blockquote><tt>
+     * Paths.get(</tt><i>p</i><tt>.{@link Path#toUri() toUri}()).equals(</tt>
+     * <i>p</i><tt>.{@link Path#toAbsolutePath() toAbsolutePath}())</tt>
+     * </blockquote>
+     * so long as the original {@code Path}, the {@code URI}, and the new {@code
+     * Path} are all created in (possibly different invocations of) the same
+     * Java virtual machine. Whether other providers make any guarantees is
+     * provider specific and therefore unspecified.
+     *
+     * @param   uri
+     *          the URI to convert
+     *
+     * @return  the resulting {@code Path}
+     *
+     * @throws  IllegalArgumentException
+     *          if preconditions on the {@code uri} parameter do not hold. The
+     *          format of the URI is provider specific.
+     * @throws  FileSystemNotFoundException
+     *          The file system, identified by the URI, does not exist and
+     *          cannot be created automatically, or the provider identified by
+     *          the URI's scheme component is not installed
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission to access the file system
+     */
+    public static Path get(URI uri) {
+        String scheme =  uri.getScheme();
+        if (scheme == null)
+            throw new IllegalArgumentException("Missing scheme");
+
+        // check for default provider to avoid loading of installed providers
+        if (scheme.equalsIgnoreCase("file"))
+            return FileSystems.getDefault().provider().getPath(uri);
+
+        // try to find provider
+        for (FileSystemProvider provider: FileSystemProvider.installedProviders()) {
+            if (provider.getScheme().equalsIgnoreCase(scheme)) {
+                return provider.getPath(uri);
+            }
+        }
+
+        throw new FileSystemNotFoundException("Provider \"" + scheme + "\" not installed");
+    }
+}
diff --git a/java/nio/file/ProviderMismatchException.java b/java/nio/file/ProviderMismatchException.java
new file mode 100644
index 0000000..0220d6e
--- /dev/null
+++ b/java/nio/file/ProviderMismatchException.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke a method on an
+ * object created by one file system provider with a parameter created by a
+ * different file system provider.
+ */
+public class ProviderMismatchException
+    extends java.lang.IllegalArgumentException
+{
+    static final long serialVersionUID = 4990847485741612530L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ProviderMismatchException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          the detail message
+     */
+    public ProviderMismatchException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/nio/file/ProviderNotFoundException.java b/java/nio/file/ProviderNotFoundException.java
new file mode 100644
index 0000000..8fa0cef
--- /dev/null
+++ b/java/nio/file/ProviderNotFoundException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Runtime exception thrown when a provider of the required type cannot be found.
+ */
+
+public class ProviderNotFoundException
+    extends RuntimeException
+{
+    static final long serialVersionUID = -1880012509822920354L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ProviderNotFoundException() {
+    }
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   msg
+     *          the detail message
+     */
+    public ProviderNotFoundException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/nio/file/ReadOnlyFileSystemException.java b/java/nio/file/ReadOnlyFileSystemException.java
new file mode 100644
index 0000000..9b25e5f
--- /dev/null
+++ b/java/nio/file/ReadOnlyFileSystemException.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Unchecked exception thrown when an attempt is made to update an object
+ * associated with a {@link FileSystem#isReadOnly() read-only} {@code FileSystem}.
+ */
+
+public class ReadOnlyFileSystemException
+    extends UnsupportedOperationException
+{
+    static final long serialVersionUID = -6822409595617487197L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public ReadOnlyFileSystemException() {
+    }
+}
diff --git a/java/nio/file/SecureDirectoryStream.java b/java/nio/file/SecureDirectoryStream.java
new file mode 100644
index 0000000..064618b
--- /dev/null
+++ b/java/nio/file/SecureDirectoryStream.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.nio.file;
+
+import java.nio.file.attribute.*;
+import java.nio.channels.SeekableByteChannel;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A {@code DirectoryStream} that defines operations on files that are located
+ * relative to an open directory. A {@code SecureDirectoryStream} is intended
+ * for use by sophisticated or security sensitive applications requiring to
+ * traverse file trees or otherwise operate on directories in a race-free manner.
+ * Race conditions can arise when a sequence of file operations cannot be
+ * carried out in isolation. Each of the file operations defined by this
+ * interface specify a relative path. All access to the file is relative
+ * to the open directory irrespective of if the directory is moved or replaced
+ * by an attacker while the directory is open. A {@code SecureDirectoryStream}
+ * may also be used as a virtual <em>working directory</em>.
+ *
+ * <p> A {@code SecureDirectoryStream} requires corresponding support from the
+ * underlying operating system. Where an implementation supports this features
+ * then the {@code DirectoryStream} returned by the {@link Files#newDirectoryStream
+ * newDirectoryStream} method will be a {@code SecureDirectoryStream} and must
+ * be cast to that type in order to invoke the methods defined by this interface.
+ *
+ * <p> In the case of the default {@link java.nio.file.spi.FileSystemProvider
+ * provider}, and a security manager is set, then the permission checks are
+ * performed using the path obtained by resolving the given relative path
+ * against the <i>original path</i> of the directory (irrespective of if the
+ * directory is moved since it was opened).
+ *
+ * @since   1.7
+ */
+
+public interface SecureDirectoryStream<T>
+    extends DirectoryStream<T>
+{
+    /**
+     * Opens the directory identified by the given path, returning a {@code
+     * SecureDirectoryStream} to iterate over the entries in the directory.
+     *
+     * <p> This method works in exactly the manner specified by the {@link
+     * Files#newDirectoryStream(Path) newDirectoryStream} method for the case that
+     * the {@code path} parameter is an {@link Path#isAbsolute absolute} path.
+     * When the parameter is a relative path then the directory to open is
+     * relative to this open directory. The {@link
+     * LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} option may be used to
+     * ensure that this method fails if the file is a symbolic link.
+     *
+     * <p> The new directory stream, once created, is not dependent upon the
+     * directory stream used to create it. Closing this directory stream has no
+     * effect upon newly created directory stream.
+     *
+     * @param   path
+     *          the path to the directory to open
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a new and open {@code SecureDirectoryStream} object
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          if the directory stream is closed
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     */
+    SecureDirectoryStream<T> newDirectoryStream(T path, LinkOption... options)
+        throws IOException;
+
+    /**
+     * Opens or creates a file in this directory, returning a seekable byte
+     * channel to access the file.
+     *
+     * <p> This method works in exactly the manner specified by the {@link
+     * Files#newByteChannel Files.newByteChannel} method for the
+     * case that the {@code path} parameter is an {@link Path#isAbsolute absolute}
+     * path. When the parameter is a relative path then the file to open or
+     * create is relative to this open directory. In addition to the options
+     * defined by the {@code Files.newByteChannel} method, the {@link
+     * LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} option may be used to
+     * ensure that this method fails if the file is a symbolic link.
+     *
+     * <p> The channel, once created, is not dependent upon the directory stream
+     * used to create it. Closing this directory stream has no effect upon the
+     * channel.
+     *
+     * @param   path
+     *          the path of the file to open open or create
+     * @param   options
+     *          options specifying how the file is opened
+     * @param   attrs
+     *          an optional list of attributes to set atomically when creating
+     *          the file
+     *
+     * @return  the seekable byte channel
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          if the directory stream is closed
+     * @throws  IllegalArgumentException
+     *          if the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          if an unsupported open option is specified or the array contains
+     *          attributes that cannot be set atomically when creating the file
+     * @throws  FileAlreadyExistsException
+     *          if a file of that name already exists and the {@link
+     *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the path if the file
+     *          is opened for reading. The {@link SecurityManager#checkWrite(String)
+     *          checkWrite} method is invoked to check write access to the path
+     *          if the file is opened for writing.
+     */
+    SeekableByteChannel newByteChannel(T path,
+                                       Set<? extends OpenOption> options,
+                                       FileAttribute<?>... attrs)
+        throws IOException;
+
+    /**
+     * Deletes a file.
+     *
+     * <p> Unlike the {@link Files#delete delete()} method, this method does
+     * not first examine the file to determine if the file is a directory.
+     * Whether a directory is deleted by this method is system dependent and
+     * therefore not specified. If the file is a symbolic link, then the link
+     * itself, not the final target of the link, is deleted. When the
+     * parameter is a relative path then the file to delete is relative to
+     * this open directory.
+     *
+     * @param   path
+     *          the path of the file to delete
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          if the directory stream is closed
+     * @throws  NoSuchFileException
+     *          if the file does not exist <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkDelete(String) checkDelete}
+     *          method is invoked to check delete access to the file
+     */
+    void deleteFile(T path) throws IOException;
+
+    /**
+     * Deletes a directory.
+     *
+     * <p> Unlike the {@link Files#delete delete()} method, this method
+     * does not first examine the file to determine if the file is a directory.
+     * Whether non-directories are deleted by this method is system dependent and
+     * therefore not specified. When the parameter is a relative path then the
+     * directory to delete is relative to this open directory.
+     *
+     * @param   path
+     *          the path of the directory to delete
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          if the directory stream is closed
+     * @throws  NoSuchFileException
+     *          if the directory does not exist <i>(optional specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          if the directory could not otherwise be deleted because it is
+     *          not empty <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkDelete(String) checkDelete}
+     *          method is invoked to check delete access to the directory
+     */
+    void deleteDirectory(T path) throws IOException;
+
+    /**
+     * Move a file from this directory to another directory.
+     *
+     * <p> This method works in a similar manner to {@link Files#move move}
+     * method when the {@link StandardCopyOption#ATOMIC_MOVE ATOMIC_MOVE} option
+     * is specified. That is, this method moves a file as an atomic file system
+     * operation. If the {@code srcpath} parameter is an {@link Path#isAbsolute
+     * absolute} path then it locates the source file. If the parameter is a
+     * relative path then it is located relative to this open directory. If
+     * the {@code targetpath} parameter is absolute then it locates the target
+     * file (the {@code targetdir} parameter is ignored). If the parameter is
+     * a relative path it is located relative to the open directory identified
+     * by the {@code targetdir} parameter. In all cases, if the target file
+     * exists then it is implementation specific if it is replaced or this
+     * method fails.
+     *
+     * @param   srcpath
+     *          the name of the file to move
+     * @param   targetdir
+     *          the destination directory
+     * @param   targetpath
+     *          the name to give the file in the destination directory
+     *
+     * @throws  ClosedDirectoryStreamException
+     *          if this or the target directory stream is closed
+     * @throws  FileAlreadyExistsException
+     *          if the file already exists in the target directory and cannot
+     *          be replaced <i>(optional specific exception)</i>
+     * @throws  AtomicMoveNotSupportedException
+     *          if the file cannot be moved as an atomic file system operation
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to both the source and
+     *          target file.
+     */
+    void move(T srcpath, SecureDirectoryStream<T> targetdir, T targetpath)
+        throws IOException;
+
+    /**
+     * Returns a new file attribute view to access the file attributes of this
+     * directory.
+     *
+     * <p> The resulting file attribute view can be used to read or update the
+     * attributes of this (open) directory. The {@code type} parameter specifies
+     * the type of the attribute view and the method returns an instance of that
+     * type if supported. Invoking this method to obtain a {@link
+     * BasicFileAttributeView} always returns an instance of that class that is
+     * bound to this open directory.
+     *
+     * <p> The state of resulting file attribute view is intimately connected
+     * to this directory stream. Once the directory stream is {@link #close closed},
+     * then all methods to read or update attributes will throw {@link
+     * ClosedDirectoryStreamException ClosedDirectoryStreamException}.
+     *
+     * @param   <V>
+     *          The {@code FileAttributeView} type
+     * @param   type
+     *          the {@code Class} object corresponding to the file attribute view
+     *
+     * @return  a new file attribute view of the specified type bound to
+     *          this directory stream, or {@code null} if the attribute view
+     *          type is not available
+     */
+    <V extends FileAttributeView> V getFileAttributeView(Class<V> type);
+
+    /**
+     * Returns a new file attribute view to access the file attributes of a file
+     * in this directory.
+     *
+     * <p> The resulting file attribute view can be used to read or update the
+     * attributes of file in this directory. The {@code type} parameter specifies
+     * the type of the attribute view and the method returns an instance of that
+     * type if supported. Invoking this method to obtain a {@link
+     * BasicFileAttributeView} always returns an instance of that class that is
+     * bound to the file in the directory.
+     *
+     * <p> The state of resulting file attribute view is intimately connected
+     * to this directory stream. Once the directory stream {@link #close closed},
+     * then all methods to read or update attributes will throw {@link
+     * ClosedDirectoryStreamException ClosedDirectoryStreamException}. The
+     * file is not required to exist at the time that the file attribute view
+     * is created but methods to read or update attributes of the file will
+     * fail when invoked and the file does not exist.
+     *
+     * @param   <V>
+     *          The {@code FileAttributeView} type
+     * @param   path
+     *          the path of the file
+     * @param   type
+     *          the {@code Class} object corresponding to the file attribute view
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a new file attribute view of the specified type bound to a
+     *          this directory stream, or {@code null} if the attribute view
+     *          type is not available
+     *
+     */
+    <V extends FileAttributeView> V getFileAttributeView(T path,
+                                                         Class<V> type,
+                                                         LinkOption... options);
+}
diff --git a/java/nio/file/SimpleFileVisitor.java b/java/nio/file/SimpleFileVisitor.java
new file mode 100644
index 0000000..321e30e
--- /dev/null
+++ b/java/nio/file/SimpleFileVisitor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.nio.file.attribute.BasicFileAttributes;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * A simple visitor of files with default behavior to visit all files and to
+ * re-throw I/O errors.
+ *
+ * <p> Methods in this class may be overridden subject to their general contract.
+ *
+ * @param   <T>     The type of reference to the files
+ *
+ * @since 1.7
+ */
+
+public class SimpleFileVisitor<T> implements FileVisitor<T> {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected SimpleFileVisitor() {
+    }
+
+    /**
+     * Invoked for a directory before entries in the directory are visited.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE}.
+     */
+    @Override
+    public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)
+        throws IOException
+    {
+        Objects.requireNonNull(dir);
+        Objects.requireNonNull(attrs);
+        return FileVisitResult.CONTINUE;
+    }
+
+    /**
+     * Invoked for a file in a directory.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE}.
+     */
+    @Override
+    public FileVisitResult visitFile(T file, BasicFileAttributes attrs)
+        throws IOException
+    {
+        Objects.requireNonNull(file);
+        Objects.requireNonNull(attrs);
+        return FileVisitResult.CONTINUE;
+    }
+
+    /**
+     * Invoked for a file that could not be visited.
+     *
+     * <p> Unless overridden, this method re-throws the I/O exception that prevented
+     * the file from being visited.
+     */
+    @Override
+    public FileVisitResult visitFileFailed(T file, IOException exc)
+        throws IOException
+    {
+        Objects.requireNonNull(file);
+        throw exc;
+    }
+
+    /**
+     * Invoked for a directory after entries in the directory, and all of their
+     * descendants, have been visited.
+     *
+     * <p> Unless overridden, this method returns {@link FileVisitResult#CONTINUE
+     * CONTINUE} if the directory iteration completes without an I/O exception;
+     * otherwise this method re-throws the I/O exception that caused the iteration
+     * of the directory to terminate prematurely.
+     */
+    @Override
+    public FileVisitResult postVisitDirectory(T dir, IOException exc)
+        throws IOException
+    {
+        Objects.requireNonNull(dir);
+        if (exc != null)
+            throw exc;
+        return FileVisitResult.CONTINUE;
+    }
+}
diff --git a/java/nio/file/StandardCopyOption.java b/java/nio/file/StandardCopyOption.java
new file mode 100644
index 0000000..30a5786
--- /dev/null
+++ b/java/nio/file/StandardCopyOption.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the standard copy options.
+ *
+ * @since 1.7
+ */
+
+public enum StandardCopyOption implements CopyOption {
+    /**
+     * Replace an existing file if it exists.
+     */
+    REPLACE_EXISTING,
+    /**
+     * Copy attributes to the new file.
+     */
+    COPY_ATTRIBUTES,
+    /**
+     * Move the file as an atomic file system operation.
+     */
+    ATOMIC_MOVE;
+}
diff --git a/java/nio/file/StandardOpenOption.java b/java/nio/file/StandardOpenOption.java
new file mode 100644
index 0000000..3ed2a9d
--- /dev/null
+++ b/java/nio/file/StandardOpenOption.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the standard open options.
+ *
+ * @since 1.7
+ */
+
+public enum StandardOpenOption implements OpenOption {
+    /**
+     * Open for read access.
+     */
+    READ,
+
+    /**
+     * Open for write access.
+     */
+    WRITE,
+
+    /**
+     * If the file is opened for {@link #WRITE} access then bytes will be written
+     * to the end of the file rather than the beginning.
+     *
+     * <p> If the file is opened for write access by other programs, then it
+     * is file system specific if writing to the end of the file is atomic.
+     */
+    APPEND,
+
+    /**
+     * If the file already exists and it is opened for {@link #WRITE}
+     * access, then its length is truncated to 0. This option is ignored
+     * if the file is opened only for {@link #READ} access.
+     */
+    TRUNCATE_EXISTING,
+
+    /**
+     * Create a new file if it does not exist.
+     * This option is ignored if the {@link #CREATE_NEW} option is also set.
+     * The check for the existence of the file and the creation of the file
+     * if it does not exist is atomic with respect to other file system
+     * operations.
+     */
+    CREATE,
+
+    /**
+     * Create a new file, failing if the file already exists.
+     * The check for the existence of the file and the creation of the file
+     * if it does not exist is atomic with respect to other file system
+     * operations.
+     */
+    CREATE_NEW,
+
+    /**
+     * Delete on close. When this option is present then the implementation
+     * makes a <em>best effort</em> attempt to delete the file when closed
+     * by the appropriate {@code close} method. If the {@code close} method is
+     * not invoked then a <em>best effort</em> attempt is made to delete the
+     * file when the Java virtual machine terminates (either normally, as
+     * defined by the Java Language Specification, or where possible, abnormally).
+     * This option is primarily intended for use with <em>work files</em> that
+     * are used solely by a single instance of the Java virtual machine. This
+     * option is not recommended for use when opening files that are open
+     * concurrently by other entities. Many of the details as to when and how
+     * the file is deleted are implementation specific and therefore not
+     * specified. In particular, an implementation may be unable to guarantee
+     * that it deletes the expected file when replaced by an attacker while the
+     * file is open. Consequently, security sensitive applications should take
+     * care when using this option.
+     *
+     * <p> For security reasons, this option may imply the {@link
+     * LinkOption#NOFOLLOW_LINKS} option. In other words, if the option is present
+     * when opening an existing file that is a symbolic link then it may fail
+     * (by throwing {@link java.io.IOException}).
+     */
+    DELETE_ON_CLOSE,
+
+    /**
+     * Sparse file. When used with the {@link #CREATE_NEW} option then this
+     * option provides a <em>hint</em> that the new file will be sparse. The
+     * option is ignored when the file system does not support the creation of
+     * sparse files.
+     */
+    SPARSE,
+
+    /**
+     * Requires that every update to the file's content or metadata be written
+     * synchronously to the underlying storage device.
+     *
+     * @see <a href="package-summary.html#integrity">Synchronized I/O file integrity</a>
+     */
+    SYNC,
+
+    /**
+     * Requires that every update to the file's content be written
+     * synchronously to the underlying storage device.
+     *
+     * @see <a href="package-summary.html#integrity">Synchronized I/O file integrity</a>
+     */
+    DSYNC;
+}
diff --git a/java/nio/file/StandardWatchEventKinds.java b/java/nio/file/StandardWatchEventKinds.java
new file mode 100644
index 0000000..8b3aba0
--- /dev/null
+++ b/java/nio/file/StandardWatchEventKinds.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * Defines the <em>standard</em> event kinds.
+ *
+ * @since 1.7
+ */
+
+public final class StandardWatchEventKinds {
+    private StandardWatchEventKinds() { }
+
+    /**
+     * A special event to indicate that events may have been lost or
+     * discarded.
+     *
+     * <p> The {@link WatchEvent#context context} for this event is
+     * implementation specific and may be {@code null}. The event {@link
+     * WatchEvent#count count} may be greater than {@code 1}.
+     *
+     * @see WatchService
+     */
+    public static final WatchEvent.Kind<Object> OVERFLOW =
+        new StdWatchEventKind<Object>("OVERFLOW", Object.class);
+
+    /**
+     * Directory entry created.
+     *
+     * <p> When a directory is registered for this event then the {@link WatchKey}
+     * is queued when it is observed that an entry is created in the directory
+     * or renamed into the directory. The event {@link WatchEvent#count count}
+     * for this event is always {@code 1}.
+     */
+    public static final WatchEvent.Kind<Path> ENTRY_CREATE =
+        new StdWatchEventKind<Path>("ENTRY_CREATE", Path.class);
+
+    /**
+     * Directory entry deleted.
+     *
+     * <p> When a directory is registered for this event then the {@link WatchKey}
+     * is queued when it is observed that an entry is deleted or renamed out of
+     * the directory. The event {@link WatchEvent#count count} for this event
+     * is always {@code 1}.
+     */
+    public static final WatchEvent.Kind<Path> ENTRY_DELETE =
+        new StdWatchEventKind<Path>("ENTRY_DELETE", Path.class);
+
+    /**
+     * Directory entry modified.
+     *
+     * <p> When a directory is registered for this event then the {@link WatchKey}
+     * is queued when it is observed that an entry in the directory has been
+     * modified. The event {@link WatchEvent#count count} for this event is
+     * {@code 1} or greater.
+     */
+    public static final WatchEvent.Kind<Path> ENTRY_MODIFY =
+        new StdWatchEventKind<Path>("ENTRY_MODIFY", Path.class);
+
+    private static class StdWatchEventKind<T> implements WatchEvent.Kind<T> {
+        private final String name;
+        private final Class<T> type;
+        StdWatchEventKind(String name, Class<T> type) {
+            this.name = name;
+            this.type = type;
+        }
+        @Override public String name() { return name; }
+        @Override public Class<T> type() { return type; }
+        @Override public String toString() { return name; }
+    }
+}
diff --git a/java/nio/file/TempFileHelper.java b/java/nio/file/TempFileHelper.java
new file mode 100644
index 0000000..8d171de
--- /dev/null
+++ b/java/nio/file/TempFileHelper.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.util.Set;
+import java.util.EnumSet;
+import java.security.SecureRandom;
+import static java.security.AccessController.*;
+import java.io.IOException;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import static java.nio.file.attribute.PosixFilePermission.*;
+import sun.security.action.GetPropertyAction;
+
+
+/**
+ * Helper class to support creation of temporary files and directories with
+ * initial attributes.
+ */
+
+class TempFileHelper {
+    private TempFileHelper() { }
+
+    // temporary directory location
+    private static final Path tmpdir =
+        Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir")));
+
+    private static final boolean isPosix =
+        FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
+
+    // file name generation, same as java.io.File for now
+    private static final SecureRandom random = new SecureRandom();
+    private static Path generatePath(String prefix, String suffix, Path dir) {
+        long n = random.nextLong();
+        n = (n == Long.MIN_VALUE) ? 0 : Math.abs(n);
+        Path name = dir.getFileSystem().getPath(prefix + Long.toString(n) + suffix);
+        // the generated name should be a simple file name
+        if (name.getParent() != null)
+            throw new IllegalArgumentException("Invalid prefix or suffix");
+        return dir.resolve(name);
+    }
+
+    // default file and directory permissions (lazily initialized)
+    private static class PosixPermissions {
+        static final FileAttribute<Set<PosixFilePermission>> filePermissions =
+            PosixFilePermissions.asFileAttribute(EnumSet.of(OWNER_READ, OWNER_WRITE));
+        static final FileAttribute<Set<PosixFilePermission>> dirPermissions =
+            PosixFilePermissions.asFileAttribute(EnumSet
+                .of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE));
+    }
+
+    /**
+     * Creates a file or directory in in the given given directory (or in the
+     * temporary directory if dir is {@code null}).
+     */
+    private static Path create(Path dir,
+                               String prefix,
+                               String suffix,
+                               boolean createDirectory,
+                               FileAttribute<?>[] attrs)
+        throws IOException
+    {
+        if (prefix == null)
+            prefix = "";
+        if (suffix == null)
+            suffix = (createDirectory) ? "" : ".tmp";
+        if (dir == null)
+            dir = tmpdir;
+
+        // in POSIX environments use default file and directory permissions
+        // if initial permissions not given by caller.
+        if (isPosix && (dir.getFileSystem() == FileSystems.getDefault())) {
+            if (attrs.length == 0) {
+                // no attributes so use default permissions
+                attrs = new FileAttribute<?>[1];
+                attrs[0] = (createDirectory) ? PosixPermissions.dirPermissions :
+                                               PosixPermissions.filePermissions;
+            } else {
+                // check if posix permissions given; if not use default
+                boolean hasPermissions = false;
+                for (int i=0; i<attrs.length; i++) {
+                    if (attrs[i].name().equals("posix:permissions")) {
+                        hasPermissions = true;
+                        break;
+                    }
+                }
+                if (!hasPermissions) {
+                    FileAttribute<?>[] copy = new FileAttribute<?>[attrs.length+1];
+                    System.arraycopy(attrs, 0, copy, 0, attrs.length);
+                    attrs = copy;
+                    attrs[attrs.length-1] = (createDirectory) ?
+                        PosixPermissions.dirPermissions :
+                        PosixPermissions.filePermissions;
+                }
+            }
+        }
+
+        // loop generating random names until file or directory can be created
+        SecurityManager sm = System.getSecurityManager();
+        for (;;) {
+            Path f;
+            try {
+                f = generatePath(prefix, suffix, dir);
+            } catch (InvalidPathException e) {
+                // don't reveal temporary directory location
+                if (sm != null)
+                    throw new IllegalArgumentException("Invalid prefix or suffix");
+                throw e;
+            }
+            try {
+                if (createDirectory) {
+                    return Files.createDirectory(f, attrs);
+                } else {
+                    return Files.createFile(f, attrs);
+                }
+            } catch (SecurityException e) {
+                // don't reveal temporary directory location
+                if (dir == tmpdir && sm != null)
+                    throw new SecurityException("Unable to create temporary file or directory");
+                throw e;
+            } catch (FileAlreadyExistsException e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Creates a temporary file in the given directory, or in in the
+     * temporary directory if dir is {@code null}.
+     */
+    static Path createTempFile(Path dir,
+                               String prefix,
+                               String suffix,
+                               FileAttribute<?>[] attrs)
+        throws IOException
+    {
+        return create(dir, prefix, suffix, false, attrs);
+    }
+
+    /**
+     * Creates a temporary directory in the given directory, or in in the
+     * temporary directory if dir is {@code null}.
+     */
+    static Path createTempDirectory(Path dir,
+                                    String prefix,
+                                    FileAttribute<?>[] attrs)
+        throws IOException
+    {
+        return create(dir, prefix, null, true, attrs);
+    }
+}
diff --git a/java/nio/file/WatchEvent.java b/java/nio/file/WatchEvent.java
new file mode 100644
index 0000000..25438a8
--- /dev/null
+++ b/java/nio/file/WatchEvent.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+/**
+ * An event or a repeated event for an object that is registered with a {@link
+ * WatchService}.
+ *
+ * <p> An event is classified by its {@link #kind() kind} and has a {@link
+ * #count() count} to indicate the number of times that the event has been
+ * observed. This allows for efficient representation of repeated events. The
+ * {@link #context() context} method returns any context associated with
+ * the event. In the case of a repeated event then the context is the same for
+ * all events.
+ *
+ * <p> Watch events are immutable and safe for use by multiple concurrent
+ * threads.
+ *
+ * @param   <T>     The type of the context object associated with the event
+ *
+ * @since 1.7
+ */
+
+public interface WatchEvent<T> {
+
+    /**
+     * An event kind, for the purposes of identification.
+     *
+     * @since 1.7
+     * @see StandardWatchEventKinds
+     */
+    public static interface Kind<T> {
+        /**
+         * Returns the name of the event kind.
+         *
+         * @return the name of the event kind
+         */
+        String name();
+
+        /**
+         * Returns the type of the {@link WatchEvent#context context} value.
+         *
+         *
+         * @return the type of the context value
+         */
+        Class<T> type();
+    }
+
+    /**
+     * An event modifier that qualifies how a {@link Watchable} is registered
+     * with a {@link WatchService}.
+     *
+     * <p> This release does not define any <em>standard</em> modifiers.
+     *
+     * @since 1.7
+     * @see Watchable#register
+     */
+    public static interface Modifier {
+        /**
+         * Returns the name of the modifier.
+         *
+         * @return the name of the modifier
+         */
+        String name();
+    }
+
+    /**
+     * Returns the event kind.
+     *
+     * @return  the event kind
+     */
+    Kind<T> kind();
+
+    /**
+     * Returns the event count. If the event count is greater than {@code 1}
+     * then this is a repeated event.
+     *
+     * @return  the event count
+     */
+    int count();
+
+    /**
+     * Returns the context for the event.
+     *
+     * <p> In the case of {@link StandardWatchEventKinds#ENTRY_CREATE ENTRY_CREATE},
+     * {@link StandardWatchEventKinds#ENTRY_DELETE ENTRY_DELETE}, and {@link
+     * StandardWatchEventKinds#ENTRY_MODIFY ENTRY_MODIFY} events the context is
+     * a {@code Path} that is the {@link Path#relativize relative} path between
+     * the directory registered with the watch service, and the entry that is
+     * created, deleted, or modified.
+     *
+     * @return  the event context; may be {@code null}
+     */
+    T context();
+}
diff --git a/java/nio/file/WatchKey.java b/java/nio/file/WatchKey.java
new file mode 100644
index 0000000..a4933f8
--- /dev/null
+++ b/java/nio/file/WatchKey.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.util.List;
+
+/**
+ * A token representing the registration of a {@link Watchable watchable} object
+ * with a {@link WatchService}.
+ *
+ * <p> A watch key is created when a watchable object is registered with a watch
+ * service. The key remains {@link #isValid valid} until:
+ * <ol>
+ *   <li> It is cancelled, explicitly, by invoking its {@link #cancel cancel}
+ *     method, or</li>
+ *   <li> Cancelled implicitly, because the object is no longer accessible,
+ *     or </li>
+ *   <li> By {@link WatchService#close closing} the watch service. </li>
+ * </ol>
+ *
+ * <p> A watch key has a state. When initially created the key is said to be
+ * <em>ready</em>. When an event is detected then the key is <em>signalled</em>
+ * and queued so that it can be retrieved by invoking the watch service's {@link
+ * WatchService#poll() poll} or {@link WatchService#take() take} methods. Once
+ * signalled, a key remains in this state until its {@link #reset reset} method
+ * is invoked to return the key to the ready state. Events detected while the
+ * key is in the signalled state are queued but do not cause the key to be
+ * re-queued for retrieval from the watch service. Events are retrieved by
+ * invoking the key's {@link #pollEvents pollEvents} method. This method
+ * retrieves and removes all events accumulated for the object. When initially
+ * created, a watch key has no pending events. Typically events are retrieved
+ * when the key is in the signalled state leading to the following idiom:
+ *
+ * <pre>
+ *     for (;;) {
+ *         // retrieve key
+ *         WatchKey key = watcher.take();
+ *
+ *         // process events
+ *         for (WatchEvent&lt;?&gt; event: key.pollEvents()) {
+ *             :
+ *         }
+ *
+ *         // reset the key
+ *         boolean valid = key.reset();
+ *         if (!valid) {
+ *             // object no longer registered
+ *         }
+ *     }
+ * </pre>
+ *
+ * <p> Watch keys are safe for use by multiple concurrent threads. Where there
+ * are several threads retrieving signalled keys from a watch service then care
+ * should be taken to ensure that the {@code reset} method is only invoked after
+ * the events for the object have been processed. This ensures that one thread
+ * is processing the events for an object at any time.
+ *
+ * @since 1.7
+ */
+
+public interface WatchKey {
+
+    /**
+     * Tells whether or not this watch key is valid.
+     *
+     * <p> A watch key is valid upon creation and remains until it is cancelled,
+     * or its watch service is closed.
+     *
+     * @return  {@code true} if, and only if, this watch key is valid
+     */
+    boolean isValid();
+
+    /**
+     * Retrieves and removes all pending events for this watch key, returning
+     * a {@code List} of the events that were retrieved.
+     *
+     * <p> Note that this method does not wait if there are no events pending.
+     *
+     * @return  the list of the events retrieved; may be empty
+     */
+    List<WatchEvent<?>> pollEvents();
+
+    /**
+     * Resets this watch key.
+     *
+     * <p> If this watch key has been cancelled or this watch key is already in
+     * the ready state then invoking this method has no effect. Otherwise
+     * if there are pending events for the object then this watch key is
+     * immediately re-queued to the watch service. If there are no pending
+     * events then the watch key is put into the ready state and will remain in
+     * that state until an event is detected or the watch key is cancelled.
+     *
+     * @return  {@code true} if the watch key is valid and has been reset, and
+     *          {@code false} if the watch key could not be reset because it is
+     *          no longer {@link #isValid valid}
+     */
+    boolean reset();
+
+    /**
+     * Cancels the registration with the watch service. Upon return the watch key
+     * will be invalid. If the watch key is enqueued, waiting to be retrieved
+     * from the watch service, then it will remain in the queue until it is
+     * removed. Pending events, if any, remain pending and may be retrieved by
+     * invoking the {@link #pollEvents pollEvents} method after the key is
+     * cancelled.
+     *
+     * <p> If this watch key has already been cancelled then invoking this
+     * method has no effect.  Once cancelled, a watch key remains forever invalid.
+     */
+    void cancel();
+
+    /**
+     * Returns the object for which this watch key was created. This method will
+     * continue to return the object even after the key is cancelled.
+     *
+     * <p> As the {@code WatchService} is intended to map directly on to the
+     * native file event notification facility (where available) then many of
+     * details on how registered objects are watched is highly implementation
+     * specific. When watching a directory for changes for example, and the
+     * directory is moved or renamed in the file system, there is no guarantee
+     * that the watch key will be cancelled and so the object returned by this
+     * method may no longer be a valid path to the directory.
+     *
+     * @return the object for which this watch key was created
+     */
+    Watchable watchable();
+}
diff --git a/java/nio/file/WatchService.java b/java/nio/file/WatchService.java
new file mode 100644
index 0000000..d06222e
--- /dev/null
+++ b/java/nio/file/WatchService.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A watch service that <em>watches</em> registered objects for changes and
+ * events. For example a file manager may use a watch service to monitor a
+ * directory for changes so that it can update its display of the list of files
+ * when files are created or deleted.
+ *
+ * <p> A {@link Watchable} object is registered with a watch service by invoking
+ * its {@link Watchable#register register} method, returning a {@link WatchKey}
+ * to represent the registration. When an event for an object is detected the
+ * key is <em>signalled</em>, and if not currently signalled, it is queued to
+ * the watch service so that it can be retrieved by consumers that invoke the
+ * {@link #poll() poll} or {@link #take() take} methods to retrieve keys
+ * and process events. Once the events have been processed the consumer
+ * invokes the key's {@link WatchKey#reset reset} method to reset the key which
+ * allows the key to be signalled and re-queued with further events.
+ *
+ * <p> Registration with a watch service is cancelled by invoking the key's
+ * {@link WatchKey#cancel cancel} method. A key that is queued at the time that
+ * it is cancelled remains in the queue until it is retrieved. Depending on the
+ * object, a key may be cancelled automatically. For example, suppose a
+ * directory is watched and the watch service detects that it has been deleted
+ * or its file system is no longer accessible. When a key is cancelled in this
+ * manner it is signalled and queued, if not currently signalled. To ensure
+ * that the consumer is notified the return value from the {@code reset}
+ * method indicates if the key is valid.
+ *
+ * <p> A watch service is safe for use by multiple concurrent consumers. To
+ * ensure that only one consumer processes the events for a particular object at
+ * any time then care should be taken to ensure that the key's {@code reset}
+ * method is only invoked after its events have been processed. The {@link
+ * #close close} method may be invoked at any time to close the service causing
+ * any threads waiting to retrieve keys, to throw {@code
+ * ClosedWatchServiceException}.
+ *
+ * <p> File systems may report events faster than they can be retrieved or
+ * processed and an implementation may impose an unspecified limit on the number
+ * of events that it may accumulate. Where an implementation <em>knowingly</em>
+ * discards events then it arranges for the key's {@link WatchKey#pollEvents
+ * pollEvents} method to return an element with an event type of {@link
+ * StandardWatchEventKinds#OVERFLOW OVERFLOW}. This event can be used by the
+ * consumer as a trigger to re-examine the state of the object.
+ *
+ * <p> When an event is reported to indicate that a file in a watched directory
+ * has been modified then there is no guarantee that the program (or programs)
+ * that have modified the file have completed. Care should be taken to coordinate
+ * access with other programs that may be updating the file.
+ * The {@link java.nio.channels.FileChannel FileChannel} class defines methods
+ * to lock regions of a file against access by other programs.
+ *
+ * <h2>Platform dependencies</h2>
+ *
+ * <p> The implementation that observes events from the file system is intended
+ * to map directly on to the native file event notification facility where
+ * available, or to use a primitive mechanism, such as polling, when a native
+ * facility is not available. Consequently, many of the details on how events
+ * are detected, their timeliness, and whether their ordering is preserved are
+ * highly implementation specific. For example, when a file in a watched
+ * directory is modified then it may result in a single {@link
+ * StandardWatchEventKinds#ENTRY_MODIFY ENTRY_MODIFY} event in some
+ * implementations but several events in other implementations. Short-lived
+ * files (meaning files that are deleted very quickly after they are created)
+ * may not be detected by primitive implementations that periodically poll the
+ * file system to detect changes.
+ *
+ * <p> If a watched file is not located on a local storage device then it is
+ * implementation specific if changes to the file can be detected. In particular,
+ * it is not required that changes to files carried out on remote systems be
+ * detected.
+ *
+ * @since 1.7
+ *
+ * @see FileSystem#newWatchService
+ */
+
+public interface WatchService
+    extends Closeable
+{
+
+    /**
+     * Closes this watch service.
+     *
+     * <p> If a thread is currently blocked in the {@link #take take} or {@link
+     * #poll(long,TimeUnit) poll} methods waiting for a key to be queued then
+     * it immediately receives a {@link ClosedWatchServiceException}. Any
+     * valid keys associated with this watch service are {@link WatchKey#isValid
+     * invalidated}.
+     *
+     * <p> After a watch service is closed, any further attempt to invoke
+     * operations upon it will throw {@link ClosedWatchServiceException}.
+     * If this watch service is already closed then invoking this method
+     * has no effect.
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     */
+    @Override
+    void close() throws IOException;
+
+    /**
+     * Retrieves and removes the next watch key, or {@code null} if none are
+     * present.
+     *
+     * @return  the next watch key, or {@code null}
+     *
+     * @throws  ClosedWatchServiceException
+     *          if this watch service is closed
+     */
+    WatchKey poll();
+
+    /**
+     * Retrieves and removes the next watch key, waiting if necessary up to the
+     * specified wait time if none are yet present.
+     *
+     * @param   timeout
+     *          how to wait before giving up, in units of unit
+     * @param   unit
+     *          a {@code TimeUnit} determining how to interpret the timeout
+     *          parameter
+     *
+     * @return  the next watch key, or {@code null}
+     *
+     * @throws  ClosedWatchServiceException
+     *          if this watch service is closed, or it is closed while waiting
+     *          for the next key
+     * @throws  InterruptedException
+     *          if interrupted while waiting
+     */
+    WatchKey poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes next watch key, waiting if none are yet present.
+     *
+     * @return  the next watch key
+     *
+     * @throws  ClosedWatchServiceException
+     *          if this watch service is closed, or it is closed while waiting
+     *          for the next key
+     * @throws  InterruptedException
+     *          if interrupted while waiting
+     */
+    WatchKey take() throws InterruptedException;
+}
diff --git a/java/nio/file/Watchable.java b/java/nio/file/Watchable.java
new file mode 100644
index 0000000..e3a86e6
--- /dev/null
+++ b/java/nio/file/Watchable.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file;
+
+import java.io.IOException;
+
+/**
+ * An object that may be registered with a watch service so that it can be
+ * <em>watched</em> for changes and events.
+ *
+ * <p> This interface defines the {@link #register register} method to register
+ * the object with a {@link WatchService} returning a {@link WatchKey} to
+ * represent the registration. An object may be registered with more than one
+ * watch service. Registration with a watch service is cancelled by invoking the
+ * key's {@link WatchKey#cancel cancel} method.
+ *
+ * @since 1.7
+ *
+ * @see Path#register
+ */
+
+public interface Watchable {
+
+    /**
+     * Registers an object with a watch service.
+     *
+     * <p> If the file system object identified by this object is currently
+     * registered with the watch service then the watch key, representing that
+     * registration, is returned after changing the event set or modifiers to
+     * those specified by the {@code events} and {@code modifiers} parameters.
+     * Changing the event set does not cause pending events for the object to be
+     * discarded. Objects are automatically registered for the {@link
+     * StandardWatchEventKinds#OVERFLOW OVERFLOW} event. This event is not
+     * required to be present in the array of events.
+     *
+     * <p> Otherwise the file system object has not yet been registered with the
+     * given watch service, so it is registered and the resulting new key is
+     * returned.
+     *
+     * <p> Implementations of this interface should specify the events they
+     * support.
+     *
+     * @param   watcher
+     *          the watch service to which this object is to be registered
+     * @param   events
+     *          the events for which this object should be registered
+     * @param   modifiers
+     *          the modifiers, if any, that modify how the object is registered
+     *
+     * @return  a key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          if unsupported events or modifiers are specified
+     * @throws  IllegalArgumentException
+     *          if an invalid of combination of events are modifiers are specified
+     * @throws  ClosedWatchServiceException
+     *          if the watch service is closed
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission required to monitor this object. Implementations of
+     *          this interface should specify the permission checks.
+     */
+    WatchKey register(WatchService watcher,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+        throws IOException;
+
+
+    /**
+     * Registers an object with a watch service.
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     * <pre>
+     *     watchable.{@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[]) register}(watcher, events, new WatchEvent.Modifier[0]);
+     * </pre>
+     *
+     * @param   watcher
+     *          the watch service to which this object is to be registered
+     * @param   events
+     *          the events for which this object should be registered
+     *
+     * @return  a key representing the registration of this object with the
+     *          given watch service
+     *
+     * @throws  UnsupportedOperationException
+     *          if unsupported events are specified
+     * @throws  IllegalArgumentException
+     *          if an invalid of combination of events are specified
+     * @throws  ClosedWatchServiceException
+     *          if the watch service is closed
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          if a security manager is installed and it denies an unspecified
+     *          permission required to monitor this object. Implementations of
+     *          this interface should specify the permission checks.
+     */
+    WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events)
+        throws IOException;
+}
diff --git a/java/nio/file/attribute/AclEntry.java b/java/nio/file/attribute/AclEntry.java
new file mode 100644
index 0000000..b008494
--- /dev/null
+++ b/java/nio/file/attribute/AclEntry.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.*;
+
+/**
+ * An entry in an access control list (ACL).
+ *
+ * <p> The ACL entry represented by this class is based on the ACL model
+ * specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530:
+ * Network File System (NFS) version 4 Protocol</i></a>. Each entry has four
+ * components as follows:
+ *
+ * <ol>
+ *    <li><p> The {@link #type() type} component determines if the entry
+ *    grants or denies access. </p></li>
+ *
+ *    <li><p> The {@link #principal() principal} component, sometimes called the
+ *    "who" component, is a {@link UserPrincipal} corresponding to the identity
+ *    that the entry grants or denies access
+ *    </p></li>
+ *
+ *    <li><p> The {@link #permissions permissions} component is a set of
+ *    {@link AclEntryPermission permissions}
+ *    </p></li>
+ *
+ *    <li><p> The {@link #flags flags} component is a set of {@link AclEntryFlag
+ *    flags} to indicate how entries are inherited and propagated </p></li>
+ * </ol>
+ *
+ * <p> ACL entries are created using an associated {@link Builder} object by
+ * invoking its {@link Builder#build build} method.
+ *
+ * <p> ACL entries are immutable and are safe for use by multiple concurrent
+ * threads.
+ *
+ * @since 1.7
+ */
+
+public final class AclEntry {
+
+    private final AclEntryType type;
+    private final UserPrincipal who;
+    private final Set<AclEntryPermission> perms;
+    private final Set<AclEntryFlag> flags;
+
+    // cached hash code
+    private volatile int hash;
+
+    // private constructor
+    private AclEntry(AclEntryType type,
+                     UserPrincipal who,
+                     Set<AclEntryPermission> perms,
+                     Set<AclEntryFlag> flags)
+    {
+        this.type = type;
+        this.who = who;
+        this.perms = perms;
+        this.flags = flags;
+    }
+
+    /**
+     * A builder of {@link AclEntry} objects.
+     *
+     * <p> A {@code Builder} object is obtained by invoking one of the {@link
+     * AclEntry#newBuilder newBuilder} methods defined by the {@code AclEntry}
+     * class.
+     *
+     * <p> Builder objects are mutable and are not safe for use by multiple
+     * concurrent threads without appropriate synchronization.
+     *
+     * @since 1.7
+     */
+    public static final class Builder {
+        private AclEntryType type;
+        private UserPrincipal who;
+        private Set<AclEntryPermission> perms;
+        private Set<AclEntryFlag> flags;
+
+        private Builder(AclEntryType type,
+                        UserPrincipal who,
+                        Set<AclEntryPermission> perms,
+                        Set<AclEntryFlag> flags)
+        {
+            assert perms != null && flags != null;
+            this.type = type;
+            this.who = who;
+            this.perms = perms;
+            this.flags = flags;
+        }
+
+        /**
+         * Constructs an {@link AclEntry} from the components of this builder.
+         * The type and who components are required to have been set in order
+         * to construct an {@code AclEntry}.
+         *
+         * @return  a new ACL entry
+         *
+         * @throws  IllegalStateException
+         *          if the type or who component have not been set
+         */
+        public AclEntry build() {
+            if (type == null)
+                throw new IllegalStateException("Missing type component");
+            if (who == null)
+                throw new IllegalStateException("Missing who component");
+            return new AclEntry(type, who, perms, flags);
+        }
+
+        /**
+         * Sets the type component of this builder.
+         *
+         * @param   type  the component type
+         * @return  this builder
+         */
+        public Builder setType(AclEntryType type) {
+            if (type == null)
+                throw new NullPointerException();
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Sets the principal component of this builder.
+         *
+         * @param   who  the principal component
+         * @return  this builder
+         */
+        public Builder setPrincipal(UserPrincipal who) {
+            if (who == null)
+                throw new NullPointerException();
+            this.who = who;
+            return this;
+        }
+
+        // check set only contains elements of the given type
+        private static void checkSet(Set<?> set, Class<?> type) {
+            for (Object e: set) {
+                if (e == null)
+                    throw new NullPointerException();
+                type.cast(e);
+            }
+        }
+
+        /**
+         * Sets the permissions component of this builder. On return, the
+         * permissions component of this builder is a copy of the given set.
+         *
+         * @param   perms  the permissions component
+         * @return  this builder
+         *
+         * @throws  ClassCastException
+         *          if the set contains elements that are not of type {@code
+         *          AclEntryPermission}
+         */
+        public Builder setPermissions(Set<AclEntryPermission> perms) {
+            if (perms.isEmpty()) {
+                // EnumSet.copyOf does not allow empty set
+                perms = Collections.emptySet();
+            } else {
+                // copy and check for erroneous elements
+                perms = EnumSet.copyOf(perms);
+                checkSet(perms, AclEntryPermission.class);
+            }
+
+            this.perms = perms;
+            return this;
+        }
+
+        /**
+         * Sets the permissions component of this builder. On return, the
+         * permissions component of this builder is a copy of the permissions in
+         * the given array.
+         *
+         * @param   perms  the permissions component
+         * @return  this builder
+         */
+        public Builder setPermissions(AclEntryPermission... perms) {
+            Set<AclEntryPermission> set = EnumSet.noneOf(AclEntryPermission.class);
+            // copy and check for null elements
+            for (AclEntryPermission p: perms) {
+                if (p == null)
+                    throw new NullPointerException();
+                set.add(p);
+            }
+            this.perms = set;
+            return this;
+        }
+
+        /**
+         * Sets the flags component of this builder. On return, the flags
+         * component of this builder is a copy of the given set.
+         *
+         * @param   flags  the flags component
+         * @return  this builder
+         *
+         * @throws  ClassCastException
+         *          if the set contains elements that are not of type {@code
+         *          AclEntryFlag}
+         */
+        public Builder setFlags(Set<AclEntryFlag> flags) {
+            if (flags.isEmpty()) {
+                // EnumSet.copyOf does not allow empty set
+                flags = Collections.emptySet();
+            } else {
+                // copy and check for erroneous elements
+                flags = EnumSet.copyOf(flags);
+                checkSet(flags, AclEntryFlag.class);
+            }
+
+            this.flags = flags;
+            return this;
+        }
+
+        /**
+         * Sets the flags component of this builder. On return, the flags
+         * component of this builder is a copy of the flags in the given
+         * array.
+         *
+         * @param   flags  the flags component
+         * @return  this builder
+         */
+        public Builder setFlags(AclEntryFlag... flags) {
+            Set<AclEntryFlag> set = EnumSet.noneOf(AclEntryFlag.class);
+            // copy and check for null elements
+            for (AclEntryFlag f: flags) {
+                if (f == null)
+                    throw new NullPointerException();
+                set.add(f);
+            }
+            this.flags = set;
+            return this;
+        }
+    }
+
+    /**
+     * Constructs a new builder. The initial value of the type and who
+     * components is {@code null}. The initial value of the permissions and
+     * flags components is the empty set.
+     *
+     * @return  a new builder
+     */
+    public static Builder newBuilder() {
+        Set<AclEntryPermission> perms = Collections.emptySet();
+        Set<AclEntryFlag> flags = Collections.emptySet();
+        return new Builder(null, null, perms, flags);
+    }
+
+    /**
+     * Constructs a new builder with the components of an existing ACL entry.
+     *
+     * @param   entry  an ACL entry
+     * @return  a new builder
+     */
+    public static Builder newBuilder(AclEntry entry) {
+        return new Builder(entry.type, entry.who, entry.perms, entry.flags);
+    }
+
+    /**
+     * Returns the ACL entry type.
+     *
+     * @return the ACL entry type
+     */
+    public AclEntryType type() {
+        return type;
+    }
+
+    /**
+     * Returns the principal component.
+     *
+     * @return the principal component
+     */
+    public UserPrincipal principal() {
+        return who;
+    }
+
+    /**
+     * Returns a copy of the permissions component.
+     *
+     * <p> The returned set is a modifiable copy of the permissions.
+     *
+     * @return the permissions component
+     */
+    public Set<AclEntryPermission> permissions() {
+        return new HashSet<AclEntryPermission>(perms);
+    }
+
+    /**
+     * Returns a copy of the flags component.
+     *
+     * <p> The returned set is a modifiable copy of the flags.
+     *
+     * @return the flags component
+     */
+    public Set<AclEntryFlag> flags() {
+        return new HashSet<AclEntryFlag>(flags);
+    }
+
+    /**
+     * Compares the specified object with this ACL entry for equality.
+     *
+     * <p> If the given object is not an {@code AclEntry} then this method
+     * immediately returns {@code false}.
+     *
+     * <p> For two ACL entries to be considered equals requires that they are
+     * both the same type, their who components are equal, their permissions
+     * components are equal, and their flags components are equal.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * java.lang.Object#equals(Object) Object.equals} method. </p>
+     *
+     * @param   ob   the object to which this object is to be compared
+     *
+     * @return  {@code true} if, and only if, the given object is an AclEntry that
+     *          is identical to this AclEntry
+     */
+    @Override
+    public boolean equals(Object ob) {
+        if (ob == this)
+            return true;
+        if (ob == null || !(ob instanceof AclEntry))
+            return false;
+        AclEntry other = (AclEntry)ob;
+        if (this.type != other.type)
+            return false;
+        if (!this.who.equals(other.who))
+            return false;
+        if (!this.perms.equals(other.perms))
+            return false;
+        if (!this.flags.equals(other.flags))
+            return false;
+        return true;
+    }
+
+    private static int hash(int h, Object o) {
+        return h * 127 + o.hashCode();
+    }
+
+    /**
+     * Returns the hash-code value for this ACL entry.
+     *
+     * <p> This method satisfies the general contract of the {@link
+     * Object#hashCode} method.
+     */
+    @Override
+    public int hashCode() {
+        // return cached hash if available
+        if (hash != 0)
+            return hash;
+        int h = type.hashCode();
+        h = hash(h, who);
+        h = hash(h, perms);
+        h = hash(h, flags);
+        hash = h;
+        return hash;
+    }
+
+    /**
+     * Returns the string representation of this ACL entry.
+     *
+     * @return  the string representation of this entry
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        // who
+        sb.append(who.getName());
+        sb.append(':');
+
+        // permissions
+        for (AclEntryPermission perm: perms) {
+            sb.append(perm.name());
+            sb.append('/');
+        }
+        sb.setLength(sb.length()-1); // drop final slash
+        sb.append(':');
+
+        // flags
+        if (!flags.isEmpty()) {
+            for (AclEntryFlag flag: flags) {
+                sb.append(flag.name());
+                sb.append('/');
+            }
+            sb.setLength(sb.length()-1);  // drop final slash
+            sb.append(':');
+        }
+
+        // type
+        sb.append(type.name());
+        return sb.toString();
+    }
+}
diff --git a/java/nio/file/attribute/AclEntryFlag.java b/java/nio/file/attribute/AclEntryFlag.java
new file mode 100644
index 0000000..6cb91f2
--- /dev/null
+++ b/java/nio/file/attribute/AclEntryFlag.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * Defines the flags for used by the flags component of an ACL {@link AclEntry
+ * entry}.
+ *
+ * <p> In this release, this class does not define flags related to {@link
+ * AclEntryType#AUDIT} and {@link AclEntryType#ALARM} entry types.
+ *
+ * @since 1.7
+ */
+
+public enum AclEntryFlag {
+
+    /**
+     * Can be placed on a directory and indicates that the ACL entry should be
+     * added to each new non-directory file created.
+     */
+    FILE_INHERIT,
+
+    /**
+     * Can be placed on a directory and indicates that the ACL entry should be
+     * added to each new directory created.
+     */
+    DIRECTORY_INHERIT,
+
+    /**
+     * Can be placed on a directory to indicate that the ACL entry should not
+     * be placed on the newly created directory which is inheritable by
+     * subdirectories of the created directory.
+     */
+    NO_PROPAGATE_INHERIT,
+
+    /**
+     * Can be placed on a directory but does not apply to the directory,
+     * only to newly created files/directories as specified by the
+     * {@link #FILE_INHERIT} and {@link #DIRECTORY_INHERIT} flags.
+     */
+    INHERIT_ONLY;
+}
diff --git a/java/nio/file/attribute/AclEntryPermission.java b/java/nio/file/attribute/AclEntryPermission.java
new file mode 100644
index 0000000..492ab77
--- /dev/null
+++ b/java/nio/file/attribute/AclEntryPermission.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * Defines the permissions for use with the permissions component of an ACL
+ * {@link AclEntry entry}.
+ *
+ * @since 1.7
+ */
+
+public enum AclEntryPermission {
+
+    /**
+     * Permission to read the data of the file.
+     */
+    READ_DATA,
+
+    /**
+     * Permission to modify the file's data.
+     */
+    WRITE_DATA,
+
+    /**
+     * Permission to append data to a file.
+     */
+    APPEND_DATA,
+
+    /**
+     * Permission to read the named attributes of a file.
+     *
+     * <p> <a href="http://www.ietf.org/rfc/rfc3530.txt">RFC&nbsp;3530: Network
+     * File System (NFS) version 4 Protocol</a> defines <em>named attributes</em>
+     * as opaque files associated with a file in the file system.
+     */
+    READ_NAMED_ATTRS,
+
+    /**
+     * Permission to write the named attributes of a file.
+     *
+     * <p> <a href="http://www.ietf.org/rfc/rfc3530.txt">RFC&nbsp;3530: Network
+     * File System (NFS) version 4 Protocol</a> defines <em>named attributes</em>
+     * as opaque files associated with a file in the file system.
+     */
+    WRITE_NAMED_ATTRS,
+
+    /**
+     * Permission to execute a file.
+     */
+    EXECUTE,
+
+    /**
+     * Permission to delete a file or directory within a directory.
+     */
+    DELETE_CHILD,
+
+    /**
+     * The ability to read (non-acl) file attributes.
+     */
+    READ_ATTRIBUTES,
+
+    /**
+     * The ability to write (non-acl) file attributes.
+     */
+    WRITE_ATTRIBUTES,
+
+    /**
+     * Permission to delete the file.
+     */
+    DELETE,
+
+    /**
+     * Permission to read the ACL attribute.
+     */
+    READ_ACL,
+
+    /**
+     * Permission to write the ACL attribute.
+     */
+    WRITE_ACL,
+
+    /**
+     * Permission to change the owner.
+     */
+    WRITE_OWNER,
+
+    /**
+     * Permission to access file locally at the server with synchronous reads
+     * and writes.
+     */
+    SYNCHRONIZE;
+
+    /**
+     * Permission to list the entries of a directory (equal to {@link #READ_DATA})
+     */
+    public static final AclEntryPermission LIST_DIRECTORY = READ_DATA;
+
+    /**
+     * Permission to add a new file to a directory (equal to {@link #WRITE_DATA})
+     */
+    public static final AclEntryPermission ADD_FILE = WRITE_DATA;
+
+    /**
+     * Permission to create a subdirectory to a directory (equal to {@link #APPEND_DATA})
+     */
+    public static final AclEntryPermission ADD_SUBDIRECTORY = APPEND_DATA;
+}
diff --git a/java/nio/file/attribute/AclEntryType.java b/java/nio/file/attribute/AclEntryType.java
new file mode 100644
index 0000000..9773b3f
--- /dev/null
+++ b/java/nio/file/attribute/AclEntryType.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * A typesafe enumeration of the access control entry types.
+ *
+ * @since 1.7
+ */
+
+public enum AclEntryType {
+    /**
+     * Explicitly grants access to a file or directory.
+     */
+    ALLOW,
+
+    /**
+     * Explicitly denies access to a file or directory.
+     */
+    DENY,
+
+    /**
+     * Log, in a system dependent way, the access specified in the
+     * permissions component of the ACL entry.
+     */
+    AUDIT,
+
+    /**
+     * Generate an alarm, in a system dependent way, the access specified in the
+     * permissions component of the ACL entry.
+     */
+    ALARM
+}
diff --git a/java/nio/file/attribute/AclFileAttributeView.java b/java/nio/file/attribute/AclFileAttributeView.java
new file mode 100644
index 0000000..129d0ee
--- /dev/null
+++ b/java/nio/file/attribute/AclFileAttributeView.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.nio.file.*;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * A file attribute view that supports reading or updating a file's Access
+ * Control Lists (ACL) or file owner attributes.
+ *
+ * <p> ACLs are used to specify access rights to file system objects. An ACL is
+ * an ordered list of {@link AclEntry access-control-entries}, each specifying a
+ * {@link UserPrincipal} and the level of access for that user principal. This
+ * file attribute view defines the {@link #getAcl() getAcl}, and {@link
+ * #setAcl(List) setAcl} methods to read and write ACLs based on the ACL
+ * model specified in <a href="http://www.ietf.org/rfc/rfc3530.txt"><i>RFC&nbsp;3530:
+ * Network File System (NFS) version 4 Protocol</i></a>. This file attribute view
+ * is intended for file system implementations that support the NFSv4 ACL model
+ * or have a <em>well-defined</em> mapping between the NFSv4 ACL model and the ACL
+ * model used by the file system. The details of such mapping are implementation
+ * dependent and are therefore unspecified.
+ *
+ * <p> This class also extends {@code FileOwnerAttributeView} so as to define
+ * methods to get and set the file owner.
+ *
+ * <p> When a file system provides access to a set of {@link FileStore
+ * file-systems} that are not homogeneous then only some of the file systems may
+ * support ACLs. The {@link FileStore#supportsFileAttributeView
+ * supportsFileAttributeView} method can be used to test if a file system
+ * supports ACLs.
+ *
+ * <h2>Interoperability</h2>
+ *
+ * RFC&nbsp;3530 allows for special user identities to be used on platforms that
+ * support the POSIX defined access permissions. The special user identities
+ * are "{@code OWNER@}", "{@code GROUP@}", and "{@code EVERYONE@}". When both
+ * the {@code AclFileAttributeView} and the {@link PosixFileAttributeView}
+ * are supported then these special user identities may be included in ACL {@link
+ * AclEntry entries} that are read or written. The file system's {@link
+ * UserPrincipalLookupService} may be used to obtain a {@link UserPrincipal}
+ * to represent these special identities by invoking the {@link
+ * UserPrincipalLookupService#lookupPrincipalByName lookupPrincipalByName}
+ * method.
+ *
+ * <p> <b>Usage Example:</b>
+ * Suppose we wish to add an entry to an existing ACL to grant "joe" access:
+ * <pre>
+ *     // lookup "joe"
+ *     UserPrincipal joe = file.getFileSystem().getUserPrincipalLookupService()
+ *         .lookupPrincipalByName("joe");
+ *
+ *     // get view
+ *     AclFileAttributeView view = Files.getFileAttributeView(file, AclFileAttributeView.class);
+ *
+ *     // create ACE to give "joe" read access
+ *     AclEntry entry = AclEntry.newBuilder()
+ *         .setType(AclEntryType.ALLOW)
+ *         .setPrincipal(joe)
+ *         .setPermissions(AclEntryPermission.READ_DATA, AclEntryPermission.READ_ATTRIBUTES)
+ *         .build();
+ *
+ *     // read ACL, insert ACE, re-write ACL
+ *     List&lt;AclEntry&gt; acl = view.getAcl();
+ *     acl.add(0, entry);   // insert before any DENY entries
+ *     view.setAcl(acl);
+ * </pre>
+ *
+ * <h2> Dynamic Access </h2>
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view are as follows:
+ * <blockquote>
+ * <table border="1" cellpadding="8" summary="Supported attributes">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *   <tr>
+ *     <td> "acl" </td>
+ *     <td> {@link List}&lt;{@link AclEntry}&gt; </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "owner" </td>
+ *     <td> {@link UserPrincipal} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link Files#getAttribute getAttribute} method may be used to read
+ * the ACL or owner attributes as if by invoking the {@link #getAcl getAcl} or
+ * {@link #getOwner getOwner} methods.
+ *
+ * <p> The {@link Files#setAttribute setAttribute} method may be used to
+ * update the ACL or owner attributes as if by invoking the {@link #setAcl setAcl}
+ * or {@link #setOwner setOwner} methods.
+ *
+ * <h2> Setting the ACL when creating a file </h2>
+ *
+ * <p> Implementations supporting this attribute view may also support setting
+ * the initial ACL when creating a file or directory. The initial ACL
+ * may be provided to methods such as {@link Files#createFile createFile} or {@link
+ * Files#createDirectory createDirectory} as an {@link FileAttribute} with {@link
+ * FileAttribute#name name} {@code "acl:acl"} and a {@link FileAttribute#value
+ * value} that is the list of {@code AclEntry} objects.
+ *
+ * <p> Where an implementation supports an ACL model that differs from the NFSv4
+ * defined ACL model then setting the initial ACL when creating the file must
+ * translate the ACL to the model supported by the file system. Methods that
+ * create a file should reject (by throwing {@link IOException IOException})
+ * any attempt to create a file that would be less secure as a result of the
+ * translation.
+ *
+ * @since 1.7
+ */
+
+public interface AclFileAttributeView
+    extends FileOwnerAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "acl"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Reads the access control list.
+     *
+     * <p> When the file system uses an ACL model that differs from the NFSv4
+     * defined ACL model, then this method returns an ACL that is the translation
+     * of the ACL to the NFSv4 ACL model.
+     *
+     * <p> The returned list is modifiable so as to facilitate changes to the
+     * existing ACL. The {@link #setAcl setAcl} method is used to update
+     * the file's ACL attribute.
+     *
+     * @return  an ordered list of {@link AclEntry entries} representing the
+     *          ACL
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    List<AclEntry> getAcl() throws IOException;
+
+    /**
+     * Updates (replace) the access control list.
+     *
+     * <p> Where the file system supports Access Control Lists, and it uses an
+     * ACL model that differs from the NFSv4 defined ACL model, then this method
+     * must translate the ACL to the model supported by the file system. This
+     * method should reject (by throwing {@link IOException IOException}) any
+     * attempt to write an ACL that would appear to make the file more secure
+     * than would be the case if the ACL were updated. Where an implementation
+     * does not support a mapping of {@link AclEntryType#AUDIT} or {@link
+     * AclEntryType#ALARM} entries, then this method ignores these entries when
+     * writing the ACL.
+     *
+     * <p> If an ACL entry contains a {@link AclEntry#principal user-principal}
+     * that is not associated with the same provider as this attribute view then
+     * {@link ProviderMismatchException} is thrown. Additional validation, if
+     * any, is implementation dependent.
+     *
+     * <p> If the file system supports other security related file attributes
+     * (such as a file {@link PosixFileAttributes#permissions
+     * access-permissions} for example), the updating the access control list
+     * may also cause these security related attributes to be updated.
+     *
+     * @param   acl
+     *          the new access control list
+     *
+     * @throws  IOException
+     *          if an I/O error occurs or the ACL is invalid
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void setAcl(List<AclEntry> acl) throws IOException;
+}
diff --git a/java/nio/file/attribute/AttributeView.java b/java/nio/file/attribute/AttributeView.java
new file mode 100644
index 0000000..569076c
--- /dev/null
+++ b/java/nio/file/attribute/AttributeView.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * An object that provides a read-only or updatable <em>view</em> of non-opaque
+ * values associated with an object in a filesystem. This interface is extended
+ * or implemented by specific attribute views that define the attributes
+ * supported by the view. A specific attribute view will typically define
+ * type-safe methods to read or update the attributes that it supports.
+ *
+ * @since 1.7
+ */
+
+public interface AttributeView {
+    /**
+     * Returns the name of the attribute view.
+     *
+     * @return the name of the attribute view
+     */
+    String name();
+}
diff --git a/java/nio/file/attribute/BasicFileAttributeView.java b/java/nio/file/attribute/BasicFileAttributeView.java
new file mode 100644
index 0000000..bfa3fdc
--- /dev/null
+++ b/java/nio/file/attribute/BasicFileAttributeView.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of a <em>basic set</em> of file
+ * attributes common to many file systems. The basic set of file attributes
+ * consist of <em>mandatory</em> and <em>optional</em> file attributes as
+ * defined by the {@link BasicFileAttributes} interface.
+
+ * <p> The file attributes are retrieved from the file system as a <em>bulk
+ * operation</em> by invoking the {@link #readAttributes() readAttributes} method.
+ * This class also defines the {@link #setTimes setTimes} method to update the
+ * file's time attributes.
+ *
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view have the following names and types:
+ * <blockquote>
+ *  <table border="1" cellpadding="8" summary="Supported attributes">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *  <tr>
+ *     <td> "lastModifiedTime" </td>
+ *     <td> {@link FileTime} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "lastAccessTime" </td>
+ *     <td> {@link FileTime} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "creationTime" </td>
+ *     <td> {@link FileTime} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "size" </td>
+ *     <td> {@link Long} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isRegularFile" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isDirectory" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isSymbolicLink" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "isOther" </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "fileKey" </td>
+ *     <td> {@link Object} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link java.nio.file.Files#getAttribute getAttribute} method may be
+ * used to read any of these attributes as if by invoking the {@link
+ * #readAttributes() readAttributes()} method.
+ *
+ * <p> The {@link java.nio.file.Files#setAttribute setAttribute} method may be
+ * used to update the file's last modified time, last access time or create time
+ * attributes as if by invoking the {@link #setTimes setTimes} method.
+ *
+ * @since 1.7
+ */
+
+public interface BasicFileAttributeView
+    extends FileAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "basic"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Reads the basic file attributes as a bulk operation.
+     *
+     * <p> It is implementation specific if all file attributes are read as an
+     * atomic operation with respect to other file system operations.
+     *
+     * @return  the file attributes
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file
+     */
+    BasicFileAttributes readAttributes() throws IOException;
+
+    /**
+     * Updates any or all of the file's last modified time, last access time,
+     * and create time attributes.
+     *
+     * <p> This method updates the file's timestamp attributes. The values are
+     * converted to the epoch and precision supported by the file system.
+     * Converting from finer to coarser granularities result in precision loss.
+     * The behavior of this method when attempting to set a timestamp that is
+     * not supported or to a value that is outside the range supported by the
+     * underlying file store is not defined. It may or not fail by throwing an
+     * {@code IOException}.
+     *
+     * <p> If any of the {@code lastModifiedTime}, {@code lastAccessTime},
+     * or {@code createTime} parameters has the value {@code null} then the
+     * corresponding timestamp is not changed. An implementation may require to
+     * read the existing values of the file attributes when only some, but not
+     * all, of the timestamp attributes are updated. Consequently, this method
+     * may not be an atomic operation with respect to other file system
+     * operations. Reading and re-writing existing values may also result in
+     * precision loss. If all of the {@code lastModifiedTime}, {@code
+     * lastAccessTime} and {@code createTime} parameters are {@code null} then
+     * this method has no effect.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to change a file's last access time.
+     * <pre>
+     *    Path path = ...
+     *    FileTime time = ...
+     *    Files.getFileAttributeView(path, BasicFileAttributeView.class).setTimes(null, time, null);
+     * </pre>
+     *
+     * @param   lastModifiedTime
+     *          the new last modified time, or {@code null} to not change the
+     *          value
+     * @param   lastAccessTime
+     *          the last access time, or {@code null} to not change the value
+     * @param   createTime
+     *          the file's create time, or {@code null} to not change the value
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, its  {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file
+     *
+     * @see java.nio.file.Files#setLastModifiedTime
+     */
+    void setTimes(FileTime lastModifiedTime,
+                  FileTime lastAccessTime,
+                  FileTime createTime) throws IOException;
+}
diff --git a/java/nio/file/attribute/BasicFileAttributes.java b/java/nio/file/attribute/BasicFileAttributes.java
new file mode 100644
index 0000000..1aeb0d7
--- /dev/null
+++ b/java/nio/file/attribute/BasicFileAttributes.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * Basic attributes associated with a file in a file system.
+ *
+ * <p> Basic file attributes are attributes that are common to many file systems
+ * and consist of mandatory and optional file attributes as defined by this
+ * interface.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *    Path file = ...
+ *    BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
+ * </pre>
+ *
+ * @since 1.7
+ *
+ * @see BasicFileAttributeView
+ */
+
+public interface BasicFileAttributes {
+
+    /**
+     * Returns the time of last modification.
+     *
+     * <p> If the file system implementation does not support a time stamp
+     * to indicate the time of last modification then this method returns an
+     * implementation specific default value, typically a {@code FileTime}
+     * representing the epoch (1970-01-01T00:00:00Z).
+     *
+     * @return  a {@code FileTime} representing the time the file was last
+     *          modified
+     */
+    FileTime lastModifiedTime();
+
+    /**
+     * Returns the time of last access.
+     *
+     * <p> If the file system implementation does not support a time stamp
+     * to indicate the time of last access then this method returns
+     * an implementation specific default value, typically the {@link
+     * #lastModifiedTime() last-modified-time} or a {@code FileTime}
+     * representing the epoch (1970-01-01T00:00:00Z).
+     *
+     * @return  a {@code FileTime} representing the time of last access
+     */
+    FileTime lastAccessTime();
+
+    /**
+     * Returns the creation time. The creation time is the time that the file
+     * was created.
+     *
+     * <p> If the file system implementation does not support a time stamp
+     * to indicate the time when the file was created then this method returns
+     * an implementation specific default value, typically the {@link
+     * #lastModifiedTime() last-modified-time} or a {@code FileTime}
+     * representing the epoch (1970-01-01T00:00:00Z).
+     *
+     * @return   a {@code FileTime} representing the time the file was created
+     */
+    FileTime creationTime();
+
+    /**
+     * Tells whether the file is a regular file with opaque content.
+     *
+     * @return {@code true} if the file is a regular file with opaque content
+     */
+    boolean isRegularFile();
+
+    /**
+     * Tells whether the file is a directory.
+     *
+     * @return {@code true} if the file is a directory
+     */
+    boolean isDirectory();
+
+    /**
+     * Tells whether the file is a symbolic link.
+     *
+     * @return {@code true} if the file is a symbolic link
+     */
+    boolean isSymbolicLink();
+
+    /**
+     * Tells whether the file is something other than a regular file, directory,
+     * or symbolic link.
+     *
+     * @return {@code true} if the file something other than a regular file,
+     *         directory or symbolic link
+     */
+    boolean isOther();
+
+    /**
+     * Returns the size of the file (in bytes). The size may differ from the
+     * actual size on the file system due to compression, support for sparse
+     * files, or other reasons. The size of files that are not {@link
+     * #isRegularFile regular} files is implementation specific and
+     * therefore unspecified.
+     *
+     * @return  the file size, in bytes
+     */
+    long size();
+
+    /**
+     * Returns an object that uniquely identifies the given file, or {@code
+     * null} if a file key is not available. On some platforms or file systems
+     * it is possible to use an identifier, or a combination of identifiers to
+     * uniquely identify a file. Such identifiers are important for operations
+     * such as file tree traversal in file systems that support <a
+     * href="../package-summary.html#links">symbolic links</a> or file systems
+     * that allow a file to be an entry in more than one directory. On UNIX file
+     * systems, for example, the <em>device ID</em> and <em>inode</em> are
+     * commonly used for such purposes.
+     *
+     * <p> The file key returned by this method can only be guaranteed to be
+     * unique if the file system and files remain static. Whether a file system
+     * re-uses identifiers after a file is deleted is implementation dependent and
+     * therefore unspecified.
+     *
+     * <p> File keys returned by this method can be compared for equality and are
+     * suitable for use in collections. If the file system and files remain static,
+     * and two files are the {@link java.nio.file.Files#isSameFile same} with
+     * non-{@code null} file keys, then their file keys are equal.
+     *
+     * @return an object that uniquely identifies the given file, or {@code null}
+     *
+     * @see java.nio.file.Files#walkFileTree
+     */
+    Object fileKey();
+}
diff --git a/java/nio/file/attribute/DosFileAttributeView.java b/java/nio/file/attribute/DosFileAttributeView.java
new file mode 100644
index 0000000..c12d8a0
--- /dev/null
+++ b/java/nio/file/attribute/DosFileAttributeView.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of the legacy "DOS" file attributes.
+ * These attributes are supported by file systems such as the File Allocation
+ * Table (FAT) format commonly used in <em>consumer devices</em>.
+ *
+ * <p> A {@code DosFileAttributeView} is a {@link BasicFileAttributeView} that
+ * additionally supports access to the set of DOS attribute flags that are used
+ * to indicate if the file is read-only, hidden, a system file, or archived.
+ *
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view are as defined by {@code
+ * BasicFileAttributeView}, and in addition, the following attributes are
+ * supported:
+ * <blockquote>
+ * <table border="1" cellpadding="8" summary="Supported attributes">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *   <tr>
+ *     <td> readonly </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> hidden </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> system </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ *   <tr>
+ *     <td> archive </td>
+ *     <td> {@link Boolean} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link java.nio.file.Files#getAttribute getAttribute} method may
+ * be used to read any of these attributes, or any of the attributes defined by
+ * {@link BasicFileAttributeView} as if by invoking the {@link #readAttributes
+ * readAttributes()} method.
+ *
+ * <p> The {@link java.nio.file.Files#setAttribute setAttribute} method may
+ * be used to update the file's last modified time, last access time or create
+ * time attributes as defined by {@link BasicFileAttributeView}. It may also be
+ * used to update the DOS attributes as if by invoking the {@link #setReadOnly
+ * setReadOnly}, {@link #setHidden setHidden}, {@link #setSystem setSystem}, and
+ * {@link #setArchive setArchive} methods respectively.
+ *
+ * @since 1.7
+ */
+
+public interface DosFileAttributeView
+    extends BasicFileAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "dos"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * @throws  IOException                             {@inheritDoc}
+     * @throws  SecurityException                       {@inheritDoc}
+     */
+    @Override
+    DosFileAttributes readAttributes() throws IOException;
+
+    /**
+     * Updates the value of the read-only attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          the new value of the attribute
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setReadOnly(boolean value) throws IOException;
+
+    /**
+     * Updates the value of the hidden attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          the new value of the attribute
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setHidden(boolean value) throws IOException;
+
+    /**
+     * Updates the value of the system attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          the new value of the attribute
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setSystem(boolean value) throws IOException;
+
+    /**
+     * Updates the value of the archive attribute.
+     *
+     * <p> It is implementation specific if the attribute can be updated as an
+     * atomic operation with respect to other file system operations. An
+     * implementation may, for example, require to read the existing value of
+     * the DOS attribute in order to update this attribute.
+     *
+     * @param   value
+     *          the new value of the attribute
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default, and a security manager is installed,
+     *          its  {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          is invoked to check write access to the file
+     */
+    void setArchive(boolean value) throws IOException;
+}
diff --git a/java/nio/file/attribute/DosFileAttributes.java b/java/nio/file/attribute/DosFileAttributes.java
new file mode 100644
index 0000000..e1fbca9
--- /dev/null
+++ b/java/nio/file/attribute/DosFileAttributes.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * File attributes associated with a file in a file system that supports
+ * legacy "DOS" attributes.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ *    Path file = ...
+ *    DosFileAttributes attrs = Files.readAttributes(file, DosFileAttributes.class);
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface DosFileAttributes
+    extends BasicFileAttributes
+{
+    /**
+     * Returns the value of the read-only attribute.
+     *
+     * <p> This attribute is often used as a simple access control mechanism
+     * to prevent files from being deleted or updated. Whether the file system
+     * or platform does any enforcement to prevent <em>read-only</em> files
+     * from being updated is implementation specific.
+     *
+     * @return  the value of the read-only attribute
+     */
+    boolean isReadOnly();
+
+    /**
+     * Returns the value of the hidden attribute.
+     *
+     * <p> This attribute is often used to indicate if the file is visible to
+     * users.
+     *
+     * @return  the value of the hidden attribute
+     */
+    boolean isHidden();
+
+    /**
+     * Returns the value of the archive attribute.
+     *
+     * <p> This attribute is typically used by backup programs.
+     *
+     * @return  the value of the archive attribute
+     */
+    boolean isArchive();
+
+    /**
+     * Returns the value of the system attribute.
+     *
+     * <p> This attribute is often used to indicate that the file is a component
+     * of the operating system.
+     *
+     * @return  the value of the system attribute
+     */
+    boolean isSystem();
+}
diff --git a/java/nio/file/attribute/FileAttribute.java b/java/nio/file/attribute/FileAttribute.java
new file mode 100644
index 0000000..16181dd
--- /dev/null
+++ b/java/nio/file/attribute/FileAttribute.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * An object that encapsulates the value of a file attribute that can be set
+ * atomically when creating a new file or directory by invoking the {@link
+ * java.nio.file.Files#createFile createFile} or {@link
+ * java.nio.file.Files#createDirectory createDirectory} methods.
+ *
+ * @param <T> The type of the file attribute value
+ *
+ * @since 1.7
+ * @see PosixFilePermissions#asFileAttribute
+ */
+
+public interface FileAttribute<T> {
+    /**
+     * Returns the attribute name.
+     *
+     * @return The attribute name
+     */
+    String name();
+
+    /**
+     * Returns the attribute value.
+     *
+     * @return The attribute value
+     */
+    T value();
+}
diff --git a/java/nio/file/attribute/FileAttributeView.java b/java/nio/file/attribute/FileAttributeView.java
new file mode 100644
index 0000000..d82e402
--- /dev/null
+++ b/java/nio/file/attribute/FileAttributeView.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * An attribute view that is a read-only or updatable view of non-opaque
+ * values associated with a file in a filesystem. This interface is extended or
+ * implemented by specific file attribute views that define methods to read
+ * and/or update the attributes of a file.
+ *
+ * @since 1.7
+ *
+ * @see java.nio.file.Files#getFileAttributeView(Path,Class,java.nio.file.LinkOption[])
+ */
+
+public interface FileAttributeView
+    extends AttributeView
+{
+}
diff --git a/java/nio/file/attribute/FileOwnerAttributeView.java b/java/nio/file/attribute/FileOwnerAttributeView.java
new file mode 100644
index 0000000..f18caaf
--- /dev/null
+++ b/java/nio/file/attribute/FileOwnerAttributeView.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * A file attribute view that supports reading or updating the owner of a file.
+ * This file attribute view is intended for file system implementations that
+ * support a file attribute that represents an identity that is the owner of
+ * the file. Often the owner of a file is the identity of the entity that
+ * created the file.
+ *
+ * <p> The {@link #getOwner getOwner} or {@link #setOwner setOwner} methods may
+ * be used to read or update the owner of the file.
+ *
+ * <p> The {@link java.nio.file.Files#getAttribute getAttribute} and
+ * {@link java.nio.file.Files#setAttribute setAttribute} methods may also be
+ * used to read or update the owner. In that case, the owner attribute is
+ * identified by the name {@code "owner"}, and the value of the attribute is
+ * a {@link UserPrincipal}.
+ *
+ * @since 1.7
+ */
+
+public interface FileOwnerAttributeView
+    extends FileAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "owner"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Read the file owner.
+     *
+     * <p> It it implementation specific if the file owner can be a {@link
+     * GroupPrincipal group}.
+     *
+     * @return  the file owner
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserInformation")</tt> or its
+     *          {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    UserPrincipal getOwner() throws IOException;
+
+    /**
+     * Updates the file owner.
+     *
+     * <p> It it implementation specific if the file owner can be a {@link
+     * GroupPrincipal group}. To ensure consistent and correct behavior
+     * across platforms it is recommended that this method should only be used
+     * to set the file owner to a user principal that is not a group.
+     *
+     * @param   owner
+     *          the new file owner
+     *
+     * @throws  IOException
+     *          if an I/O error occurs, or the {@code owner} parameter is a
+     *          group and this implementation does not support setting the owner
+     *          to a group
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserInformation")</tt> or its
+     *          {@link SecurityManager#checkWrite(String) checkWrite} method
+     *          denies write access to the file.
+     */
+    void setOwner(UserPrincipal owner) throws IOException;
+}
diff --git a/java/nio/file/attribute/FileStoreAttributeView.java b/java/nio/file/attribute/FileStoreAttributeView.java
new file mode 100644
index 0000000..0efb9b6
--- /dev/null
+++ b/java/nio/file/attribute/FileStoreAttributeView.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * An attribute view that is a read-only or updatable view of the attributes of
+ * a {@link java.nio.file.FileStore}.
+ *
+ * @since 1.7
+ */
+
+public interface FileStoreAttributeView
+    extends AttributeView
+{
+}
diff --git a/java/nio/file/attribute/FileTime.java b/java/nio/file/attribute/FileTime.java
new file mode 100644
index 0000000..2f3399b
--- /dev/null
+++ b/java/nio/file/attribute/FileTime.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Represents the value of a file's time stamp attribute. For example, it may
+ * represent the time that the file was last
+ * {@link BasicFileAttributes#lastModifiedTime() modified},
+ * {@link BasicFileAttributes#lastAccessTime() accessed},
+ * or {@link BasicFileAttributes#creationTime() created}.
+ *
+ * <p> Instances of this class are immutable.
+ *
+ * @since 1.7
+ * @see java.nio.file.Files#setLastModifiedTime
+ * @see java.nio.file.Files#getLastModifiedTime
+ */
+
+public final class FileTime
+    implements Comparable<FileTime>
+{
+    /**
+     * The unit of granularity to interpret the value. Null if
+     * this {@code FileTime} is converted from an {@code Instant},
+     * the {@code value} and {@code unit} pair will not be used
+     * in this scenario.
+     */
+    private final TimeUnit unit;
+
+    /**
+     * The value since the epoch; can be negative.
+     */
+    private final long value;
+
+    /**
+     * The value as Instant (created lazily, if not from an instant)
+     */
+    private Instant instant;
+
+    /**
+     * The value return by toString (created lazily)
+     */
+    private String valueAsString;
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    private FileTime(long value, TimeUnit unit, Instant instant) {
+        this.value = value;
+        this.unit = unit;
+        this.instant = instant;
+    }
+
+    /**
+     * Returns a {@code FileTime} representing a value at the given unit of
+     * granularity.
+     *
+     * @param   value
+     *          the value since the epoch (1970-01-01T00:00:00Z); can be
+     *          negative
+     * @param   unit
+     *          the unit of granularity to interpret the value
+     *
+     * @return  a {@code FileTime} representing the given value
+     */
+    public static FileTime from(long value, TimeUnit unit) {
+        Objects.requireNonNull(unit, "unit");
+        return new FileTime(value, unit, null);
+    }
+
+    /**
+     * Returns a {@code FileTime} representing the given value in milliseconds.
+     *
+     * @param   value
+     *          the value, in milliseconds, since the epoch
+     *          (1970-01-01T00:00:00Z); can be negative
+     *
+     * @return  a {@code FileTime} representing the given value
+     */
+    public static FileTime fromMillis(long value) {
+        return new FileTime(value, TimeUnit.MILLISECONDS, null);
+    }
+
+    /**
+     * Returns a {@code FileTime} representing the same point of time value
+     * on the time-line as the provided {@code Instant} object.
+     *
+     * @param   instant
+     *          the instant to convert
+     * @return  a {@code FileTime} representing the same point on the time-line
+     *          as the provided instant
+     * @since 1.8
+     */
+    public static FileTime from(Instant instant) {
+        Objects.requireNonNull(instant, "instant");
+        return new FileTime(0, null, instant);
+    }
+
+    /**
+     * Returns the value at the given unit of granularity.
+     *
+     * <p> Conversion from a coarser granularity that would numerically overflow
+     * saturate to {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE}
+     * if positive.
+     *
+     * @param   unit
+     *          the unit of granularity for the return value
+     *
+     * @return  value in the given unit of granularity, since the epoch
+     *          since the epoch (1970-01-01T00:00:00Z); can be negative
+     */
+    public long to(TimeUnit unit) {
+        Objects.requireNonNull(unit, "unit");
+        if (this.unit != null) {
+            return unit.convert(this.value, this.unit);
+        } else {
+            long secs = unit.convert(instant.getEpochSecond(), TimeUnit.SECONDS);
+            if (secs == Long.MIN_VALUE || secs == Long.MAX_VALUE) {
+                return secs;
+            }
+            long nanos = unit.convert(instant.getNano(), TimeUnit.NANOSECONDS);
+            long r = secs + nanos;
+            // Math.addExact() variant
+            if (((secs ^ r) & (nanos ^ r)) < 0) {
+                return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
+            }
+            return r;
+        }
+    }
+
+    /**
+     * Returns the value in milliseconds.
+     *
+     * <p> Conversion from a coarser granularity that would numerically overflow
+     * saturate to {@code Long.MIN_VALUE} if negative or {@code Long.MAX_VALUE}
+     * if positive.
+     *
+     * @return  the value in milliseconds, since the epoch (1970-01-01T00:00:00Z)
+     */
+    public long toMillis() {
+        if (unit != null) {
+            return unit.toMillis(value);
+        } else {
+            long secs = instant.getEpochSecond();
+            int  nanos = instant.getNano();
+            // Math.multiplyExact() variant
+            long r = secs * 1000;
+            long ax = Math.abs(secs);
+            if (((ax | 1000) >>> 31 != 0)) {
+                if ((r / 1000) != secs) {
+                    return (secs < 0) ? Long.MIN_VALUE : Long.MAX_VALUE;
+                }
+            }
+            return r + nanos / 1000_000;
+        }
+    }
+
+    /**
+     * Time unit constants for conversion.
+     */
+    private static final long HOURS_PER_DAY      = 24L;
+    private static final long MINUTES_PER_HOUR   = 60L;
+    private static final long SECONDS_PER_MINUTE = 60L;
+    private static final long SECONDS_PER_HOUR   = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    private static final long SECONDS_PER_DAY    = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    private static final long MILLIS_PER_SECOND  = 1000L;
+    private static final long MICROS_PER_SECOND  = 1000_000L;
+    private static final long NANOS_PER_SECOND   = 1000_000_000L;
+    private static final int  NANOS_PER_MILLI    = 1000_000;
+    private static final int  NANOS_PER_MICRO    = 1000;
+    // The epoch second of Instant.MIN.
+    private static final long MIN_SECOND = -31557014167219200L;
+    // The epoch second of Instant.MAX.
+    private static final long MAX_SECOND = 31556889864403199L;
+
+    /*
+     * Scale d by m, checking for overflow.
+     */
+    private static long scale(long d, long m, long over) {
+        if (d >  over) return Long.MAX_VALUE;
+        if (d < -over) return Long.MIN_VALUE;
+        return d * m;
+    }
+
+    /**
+     * Converts this {@code FileTime} object to an {@code Instant}.
+     *
+     * <p> The conversion creates an {@code Instant} that represents the
+     * same point on the time-line as this {@code FileTime}.
+     *
+     * <p> {@code FileTime} can store points on the time-line further in the
+     * future and further in the past than {@code Instant}. Conversion
+     * from such further time points saturates to {@link Instant#MIN} if
+     * earlier than {@code Instant.MIN} or {@link Instant#MAX} if later
+     * than {@code Instant.MAX}.
+     *
+     * @return  an instant representing the same point on the time-line as
+     *          this {@code FileTime} object
+     * @since 1.8
+     */
+    public Instant toInstant() {
+        if (instant == null) {
+            long secs = 0L;
+            int nanos = 0;
+            switch (unit) {
+                case DAYS:
+                    secs = scale(value, SECONDS_PER_DAY,
+                                 Long.MAX_VALUE/SECONDS_PER_DAY);
+                    break;
+                case HOURS:
+                    secs = scale(value, SECONDS_PER_HOUR,
+                                 Long.MAX_VALUE/SECONDS_PER_HOUR);
+                    break;
+                case MINUTES:
+                    secs = scale(value, SECONDS_PER_MINUTE,
+                                 Long.MAX_VALUE/SECONDS_PER_MINUTE);
+                    break;
+                case SECONDS:
+                    secs = value;
+                    break;
+                case MILLISECONDS:
+                    secs = Math.floorDiv(value, MILLIS_PER_SECOND);
+                    nanos = (int)Math.floorMod(value, MILLIS_PER_SECOND)
+                            * NANOS_PER_MILLI;
+                    break;
+                case MICROSECONDS:
+                    secs = Math.floorDiv(value, MICROS_PER_SECOND);
+                    nanos = (int)Math.floorMod(value, MICROS_PER_SECOND)
+                            * NANOS_PER_MICRO;
+                    break;
+                case NANOSECONDS:
+                    secs = Math.floorDiv(value, NANOS_PER_SECOND);
+                    nanos = (int)Math.floorMod(value, NANOS_PER_SECOND);
+                    break;
+                default : throw new AssertionError("Unit not handled");
+            }
+            if (secs <= MIN_SECOND)
+                instant = Instant.MIN;
+            else if (secs >= MAX_SECOND)
+                instant = Instant.MAX;
+            else
+                instant = Instant.ofEpochSecond(secs, nanos);
+        }
+        return instant;
+    }
+
+    /**
+     * Tests this {@code FileTime} for equality with the given object.
+     *
+     * <p> The result is {@code true} if and only if the argument is not {@code
+     * null} and is a {@code FileTime} that represents the same time. This
+     * method satisfies the general contract of the {@code Object.equals} method.
+     *
+     * @param   obj
+     *          the object to compare with
+     *
+     * @return  {@code true} if, and only if, the given object is a {@code
+     *          FileTime} that represents the same time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return (obj instanceof FileTime) ? compareTo((FileTime)obj) == 0 : false;
+    }
+
+    /**
+     * Computes a hash code for this file time.
+     *
+     * <p> The hash code is based upon the value represented, and satisfies the
+     * general contract of the {@link Object#hashCode} method.
+     *
+     * @return  the hash-code value
+     */
+    @Override
+    public int hashCode() {
+        // hashcode of instant representation to satisfy contract with equals
+        return toInstant().hashCode();
+    }
+
+    private long toDays() {
+        if (unit != null) {
+            return unit.toDays(value);
+        } else {
+            return TimeUnit.SECONDS.toDays(toInstant().getEpochSecond());
+        }
+    }
+
+    private long toExcessNanos(long days) {
+        if (unit != null) {
+            return unit.toNanos(value - unit.convert(days, TimeUnit.DAYS));
+        } else {
+            return TimeUnit.SECONDS.toNanos(toInstant().getEpochSecond()
+                                            - TimeUnit.DAYS.toSeconds(days));
+        }
+    }
+
+    /**
+     * Compares the value of two {@code FileTime} objects for order.
+     *
+     * @param   other
+     *          the other {@code FileTime} to be compared
+     *
+     * @return  {@code 0} if this {@code FileTime} is equal to {@code other}, a
+     *          value less than 0 if this {@code FileTime} represents a time
+     *          that is before {@code other}, and a value greater than 0 if this
+     *          {@code FileTime} represents a time that is after {@code other}
+     */
+    @Override
+    public int compareTo(FileTime other) {
+        // same granularity
+        if (unit != null && unit == other.unit) {
+            return Long.compare(value, other.value);
+        } else {
+            // compare using instant representation when unit differs
+            long secs = toInstant().getEpochSecond();
+            long secsOther = other.toInstant().getEpochSecond();
+            int cmp = Long.compare(secs, secsOther);
+            if (cmp != 0) {
+                return cmp;
+            }
+            cmp = Long.compare(toInstant().getNano(), other.toInstant().getNano());
+            if (cmp != 0) {
+                return cmp;
+            }
+            if (secs != MAX_SECOND && secs != MIN_SECOND) {
+                return 0;
+            }
+            // if both this and other's Instant reps are MIN/MAX,
+            // use daysSinceEpoch and nanosOfDays, which will not
+            // saturate during calculation.
+            long days = toDays();
+            long daysOther = other.toDays();
+            if (days == daysOther) {
+                return Long.compare(toExcessNanos(days), other.toExcessNanos(daysOther));
+            }
+            return Long.compare(days, daysOther);
+        }
+    }
+
+    // days in a 400 year cycle = 146097
+    // days in a 10,000 year cycle = 146097 * 25
+    // seconds per day = 86400
+    private static final long DAYS_PER_10000_YEARS = 146097L * 25L;
+    private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
+    private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L;
+
+    // append year/month/day/hour/minute/second/nano with width and 0 padding
+    private StringBuilder append(StringBuilder sb, int w, int d) {
+        while (w > 0) {
+            sb.append((char)(d/w + '0'));
+            d = d % w;
+            w /= 10;
+        }
+        return sb;
+    }
+
+    /**
+     * Returns the string representation of this {@code FileTime}. The string
+     * is returned in the <a
+     * href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a> format:
+     * <pre>
+     *     YYYY-MM-DDThh:mm:ss[.s+]Z
+     * </pre>
+     * where "{@code [.s+]}" represents a dot followed by one of more digits
+     * for the decimal fraction of a second. It is only present when the decimal
+     * fraction of a second is not zero. For example, {@code
+     * FileTime.fromMillis(1234567890000L).toString()} yields {@code
+     * "2009-02-13T23:31:30Z"}, and {@code FileTime.fromMillis(1234567890123L).toString()}
+     * yields {@code "2009-02-13T23:31:30.123Z"}.
+     *
+     * <p> A {@code FileTime} is primarily intended to represent the value of a
+     * file's time stamp. Where used to represent <i>extreme values</i>, where
+     * the year is less than "{@code 0001}" or greater than "{@code 9999}" then
+     * this method deviates from ISO 8601 in the same manner as the
+     * <a href="http://www.w3.org/TR/xmlschema-2/#deviantformats">XML Schema
+     * language</a>. That is, the year may be expanded to more than four digits
+     * and may be negative-signed. If more than four digits then leading zeros
+     * are not present. The year before "{@code 0001}" is "{@code -0001}".
+     *
+     * @return  the string representation of this file time
+     */
+    @Override
+    public String toString() {
+        if (valueAsString == null) {
+            long secs = 0L;
+            int  nanos = 0;
+            if (instant == null && unit.compareTo(TimeUnit.SECONDS) >= 0) {
+                secs = unit.toSeconds(value);
+            } else {
+                secs = toInstant().getEpochSecond();
+                nanos = toInstant().getNano();
+            }
+            LocalDateTime ldt;
+            int year = 0;
+            if (secs >= -SECONDS_0000_TO_1970) {
+                // current era
+                long zeroSecs = secs - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
+                long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
+                long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
+                ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
+                year = ldt.getYear() +  (int)hi * 10000;
+            } else {
+                // before current era
+                long zeroSecs = secs + SECONDS_0000_TO_1970;
+                long hi = zeroSecs / SECONDS_PER_10000_YEARS;
+                long lo = zeroSecs % SECONDS_PER_10000_YEARS;
+                ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC);
+                year = ldt.getYear() + (int)hi * 10000;
+            }
+            if (year <= 0) {
+                year = year - 1;
+            }
+            int fraction = ldt.getNano();
+            StringBuilder sb = new StringBuilder(64);
+            sb.append(year < 0 ? "-" : "");
+            year = Math.abs(year);
+            if (year < 10000) {
+                append(sb, 1000, Math.abs(year));
+            } else {
+                sb.append(String.valueOf(year));
+            }
+            sb.append('-');
+            append(sb, 10, ldt.getMonthValue());
+            sb.append('-');
+            append(sb, 10, ldt.getDayOfMonth());
+            sb.append('T');
+            append(sb, 10, ldt.getHour());
+            sb.append(':');
+            append(sb, 10, ldt.getMinute());
+            sb.append(':');
+            append(sb, 10, ldt.getSecond());
+            if (fraction != 0) {
+                sb.append('.');
+                // adding leading zeros and stripping any trailing zeros
+                int w = 100_000_000;
+                while (fraction % 10 == 0) {
+                    fraction /= 10;
+                    w /= 10;
+                }
+                append(sb, w, fraction);
+            }
+            sb.append('Z');
+            valueAsString = sb.toString();
+        }
+        return valueAsString;
+    }
+}
diff --git a/java/nio/file/attribute/GroupPrincipal.java b/java/nio/file/attribute/GroupPrincipal.java
new file mode 100644
index 0000000..8c679c5
--- /dev/null
+++ b/java/nio/file/attribute/GroupPrincipal.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * A {@code UserPrincipal} representing a <em>group identity</em>, used to
+ * determine access rights to objects in a file system. The exact definition of
+ * a group is implementation specific, but typically, it represents an identity
+ * created for administrative purposes so as to determine the access rights for
+ * the members of the group. Whether an entity can be a member of multiple
+ * groups, and whether groups can be nested, are implementation specified and
+ * therefore not specified.
+ *
+ * @since 1.7
+ *
+ * @see UserPrincipalLookupService#lookupPrincipalByGroupName
+ */
+
+public interface GroupPrincipal extends UserPrincipal { }
diff --git a/java/nio/file/attribute/PosixFileAttributeView.java b/java/nio/file/attribute/PosixFileAttributeView.java
new file mode 100644
index 0000000..25466f2
--- /dev/null
+++ b/java/nio/file/attribute/PosixFileAttributeView.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.nio.file.*;
+import java.util.Set;
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of the file attributes commonly
+ * associated with files on file systems used by operating systems that implement
+ * the Portable Operating System Interface (POSIX) family of standards.
+ *
+ * <p> Operating systems that implement the <a href="http://www.opengroup.org">
+ * POSIX</a> family of standards commonly use file systems that have a
+ * file <em>owner</em>, <em>group-owner</em>, and related <em>access
+ * permissions</em>. This file attribute view provides read and write access
+ * to these attributes.
+ *
+ * <p> The {@link #readAttributes() readAttributes} method is used to read the
+ * file's attributes. The file {@link PosixFileAttributes#owner() owner} is
+ * represented by a {@link UserPrincipal} that is the identity of the file owner
+ * for the purposes of access control. The {@link PosixFileAttributes#group()
+ * group-owner}, represented by a {@link GroupPrincipal}, is the identity of the
+ * group owner, where a group is an identity created for administrative purposes
+ * so as to determine the access rights for the members of the group.
+ *
+ * <p> The {@link PosixFileAttributes#permissions() permissions} attribute is a
+ * set of access permissions. This file attribute view provides access to the nine
+ * permission defined by the {@link PosixFilePermission} class.
+ * These nine permission bits determine the <em>read</em>, <em>write</em>, and
+ * <em>execute</em> access for the file owner, group, and others (others
+ * meaning identities other than the owner and members of the group). Some
+ * operating systems and file systems may provide additional permission bits
+ * but access to these other bits is not defined by this class in this release.
+ *
+ * <p> <b>Usage Example:</b>
+ * Suppose we need to print out the owner and access permissions of a file:
+ * <pre>
+ *     Path file = ...
+ *     PosixFileAttributes attrs = Files.getFileAttributeView(file, PosixFileAttributeView.class)
+ *         .readAttributes();
+ *     System.out.format("%s %s%n",
+ *         attrs.owner().getName(),
+ *         PosixFilePermissions.toString(attrs.permissions()));
+ * </pre>
+ *
+ * <h2> Dynamic Access </h2>
+ * <p> Where dynamic access to file attributes is required, the attributes
+ * supported by this attribute view are as defined by {@link
+ * BasicFileAttributeView} and {@link FileOwnerAttributeView}, and in addition,
+ * the following attributes are supported:
+ * <blockquote>
+ * <table border="1" cellpadding="8" summary="Supported attributes">
+ *   <tr>
+ *     <th> Name </th>
+ *     <th> Type </th>
+ *   </tr>
+ *  <tr>
+ *     <td> "permissions" </td>
+ *     <td> {@link Set}&lt;{@link PosixFilePermission}&gt; </td>
+ *   </tr>
+ *   <tr>
+ *     <td> "group" </td>
+ *     <td> {@link GroupPrincipal} </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p> The {@link Files#getAttribute getAttribute} method may be used to read
+ * any of these attributes, or any of the attributes defined by {@link
+ * BasicFileAttributeView} as if by invoking the {@link #readAttributes
+ * readAttributes()} method.
+ *
+ * <p> The {@link Files#setAttribute setAttribute} method may be used to update
+ * the file's last modified time, last access time or create time attributes as
+ * defined by {@link BasicFileAttributeView}. It may also be used to update
+ * the permissions, owner, or group-owner as if by invoking the {@link
+ * #setPermissions setPermissions}, {@link #setOwner setOwner}, and {@link
+ * #setGroup setGroup} methods respectively.
+ *
+ * <h2> Setting Initial Permissions </h2>
+ * <p> Implementations supporting this attribute view may also support setting
+ * the initial permissions when creating a file or directory. The
+ * initial permissions are provided to the {@link Files#createFile createFile}
+ * or {@link Files#createDirectory createDirectory} methods as a {@link
+ * FileAttribute} with {@link FileAttribute#name name} {@code "posix:permissions"}
+ * and a {@link FileAttribute#value value} that is the set of permissions. The
+ * following example uses the {@link PosixFilePermissions#asFileAttribute
+ * asFileAttribute} method to construct a {@code FileAttribute} when creating a
+ * file:
+ *
+ * <pre>
+ *     Path path = ...
+ *     Set&lt;PosixFilePermission&gt; perms =
+ *         EnumSet.of(OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ);
+ *     Files.createFile(path, PosixFilePermissions.asFileAttribute(perms));
+ * </pre>
+ *
+ * <p> When the access permissions are set at file creation time then the actual
+ * value of the permissions may differ that the value of the attribute object.
+ * The reasons for this are implementation specific. On UNIX systems, for
+ * example, a process has a <em>umask</em> that impacts the permission bits
+ * of newly created files. Where an implementation supports the setting of
+ * the access permissions, and the underlying file system supports access
+ * permissions, then it is required that the value of the actual access
+ * permissions will be equal or less than the value of the attribute
+ * provided to the {@link Files#createFile createFile} or {@link
+ * Files#createDirectory createDirectory} methods. In other words, the file may
+ * be more secure than requested.
+ *
+ * @since 1.7
+ */
+
+public interface PosixFileAttributeView
+    extends BasicFileAttributeView, FileOwnerAttributeView
+{
+    /**
+     * Returns the name of the attribute view. Attribute views of this type
+     * have the name {@code "posix"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * @throws  IOException                {@inheritDoc}
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    @Override
+    PosixFileAttributes readAttributes() throws IOException;
+
+    /**
+     * Updates the file permissions.
+     *
+     * @param   perms
+     *          the new set of permissions
+     *
+     * @throws  ClassCastException
+     *          if the sets contains elements that are not of type {@code
+     *          PosixFilePermission}
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void setPermissions(Set<PosixFilePermission> perms) throws IOException;
+
+    /**
+     * Updates the file group-owner.
+     *
+     * @param   group
+     *          the new file group-owner
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, it denies {@link RuntimePermission}<tt>("accessUserInformation")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void setGroup(GroupPrincipal group) throws IOException;
+}
diff --git a/java/nio/file/attribute/PosixFileAttributes.java b/java/nio/file/attribute/PosixFileAttributes.java
new file mode 100644
index 0000000..182c422
--- /dev/null
+++ b/java/nio/file/attribute/PosixFileAttributes.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.util.Set;
+
+/**
+ * File attributes associated with files on file systems used by operating systems
+ * that implement the Portable Operating System Interface (POSIX) family of
+ * standards.
+ *
+ * <p> The POSIX attributes of a file are retrieved using a {@link
+ * PosixFileAttributeView} by invoking its {@link
+ * PosixFileAttributeView#readAttributes readAttributes} method.
+ *
+ * @since 1.7
+ */
+
+public interface PosixFileAttributes
+    extends BasicFileAttributes
+{
+    /**
+     * Returns the owner of the file.
+     *
+     * @return  the file owner
+     *
+     * @see PosixFileAttributeView#setOwner
+     */
+    UserPrincipal owner();
+
+    /**
+     * Returns the group owner of the file.
+     *
+     * @return  the file group owner
+     *
+     * @see PosixFileAttributeView#setGroup
+     */
+    GroupPrincipal group();
+
+    /**
+     * Returns the permissions of the file. The file permissions are returned
+     * as a set of {@link PosixFilePermission} elements. The returned set is a
+     * copy of the file permissions and is modifiable. This allows the result
+     * to be modified and passed to the {@link PosixFileAttributeView#setPermissions
+     * setPermissions} method to update the file's permissions.
+     *
+     * @return  the file permissions
+     *
+     * @see PosixFileAttributeView#setPermissions
+     */
+    Set<PosixFilePermission> permissions();
+}
diff --git a/java/nio/file/attribute/PosixFilePermission.java b/java/nio/file/attribute/PosixFilePermission.java
new file mode 100644
index 0000000..03e2209
--- /dev/null
+++ b/java/nio/file/attribute/PosixFilePermission.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+/**
+ * Defines the bits for use with the {@link PosixFileAttributes#permissions()
+ * permissions} attribute.
+ *
+ * <p> The {@link PosixFilePermissions} class defines methods for manipulating
+ * set of permissions.
+ *
+ * @since 1.7
+ */
+
+public enum PosixFilePermission {
+
+    /**
+     * Read permission, owner.
+     */
+    OWNER_READ,
+
+    /**
+     * Write permission, owner.
+     */
+    OWNER_WRITE,
+
+    /**
+     * Execute/search permission, owner.
+     */
+    OWNER_EXECUTE,
+
+    /**
+     * Read permission, group.
+     */
+    GROUP_READ,
+
+    /**
+     * Write permission, group.
+     */
+    GROUP_WRITE,
+
+    /**
+     * Execute/search permission, group.
+     */
+    GROUP_EXECUTE,
+
+    /**
+     * Read permission, others.
+     */
+    OTHERS_READ,
+
+    /**
+     * Write permission, others.
+     */
+    OTHERS_WRITE,
+
+    /**
+     * Execute/search permission, others.
+     */
+    OTHERS_EXECUTE;
+}
diff --git a/java/nio/file/attribute/PosixFilePermissions.java b/java/nio/file/attribute/PosixFilePermissions.java
new file mode 100644
index 0000000..45a866a
--- /dev/null
+++ b/java/nio/file/attribute/PosixFilePermissions.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import static java.nio.file.attribute.PosixFilePermission.*;
+import java.util.*;
+
+/**
+ * This class consists exclusively of static methods that operate on sets of
+ * {@link PosixFilePermission} objects.
+ *
+ * @since 1.7
+ */
+
+public final class PosixFilePermissions {
+    private PosixFilePermissions() { }
+
+    // Write string representation of permission bits to {@code sb}.
+    private static void writeBits(StringBuilder sb, boolean r, boolean w, boolean x) {
+        if (r) {
+            sb.append('r');
+        } else {
+            sb.append('-');
+        }
+        if (w) {
+            sb.append('w');
+        } else {
+            sb.append('-');
+        }
+        if (x) {
+            sb.append('x');
+        } else {
+            sb.append('-');
+        }
+    }
+
+    /**
+     * Returns the {@code String} representation of a set of permissions. It
+     * is guaranteed that the returned {@code String} can be parsed by the
+     * {@link #fromString} method.
+     *
+     * <p> If the set contains {@code null} or elements that are not of type
+     * {@code PosixFilePermission} then these elements are ignored.
+     *
+     * @param   perms
+     *          the set of permissions
+     *
+     * @return  the string representation of the permission set
+     */
+    public static String toString(Set<PosixFilePermission> perms) {
+        StringBuilder sb = new StringBuilder(9);
+        writeBits(sb, perms.contains(OWNER_READ), perms.contains(OWNER_WRITE),
+          perms.contains(OWNER_EXECUTE));
+        writeBits(sb, perms.contains(GROUP_READ), perms.contains(GROUP_WRITE),
+          perms.contains(GROUP_EXECUTE));
+        writeBits(sb, perms.contains(OTHERS_READ), perms.contains(OTHERS_WRITE),
+          perms.contains(OTHERS_EXECUTE));
+        return sb.toString();
+    }
+
+    private static boolean isSet(char c, char setValue) {
+        if (c == setValue)
+            return true;
+        if (c == '-')
+            return false;
+        throw new IllegalArgumentException("Invalid mode");
+    }
+    private static boolean isR(char c) { return isSet(c, 'r'); }
+    private static boolean isW(char c) { return isSet(c, 'w'); }
+    private static boolean isX(char c) { return isSet(c, 'x'); }
+
+    /**
+     * Returns the set of permissions corresponding to a given {@code String}
+     * representation.
+     *
+     * <p> The {@code perms} parameter is a {@code String} representing the
+     * permissions. It has 9 characters that are interpreted as three sets of
+     * three. The first set refers to the owner's permissions; the next to the
+     * group permissions and the last to others. Within each set, the first
+     * character is {@code 'r'} to indicate permission to read, the second
+     * character is {@code 'w'} to indicate permission to write, and the third
+     * character is {@code 'x'} for execute permission. Where a permission is
+     * not set then the corresponding character is set to {@code '-'}.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we require the set of permissions that indicate the owner has read,
+     * write, and execute permissions, the group has read and execute permissions
+     * and others have none.
+     * <pre>
+     *   Set&lt;PosixFilePermission&gt; perms = PosixFilePermissions.fromString("rwxr-x---");
+     * </pre>
+     *
+     * @param   perms
+     *          string representing a set of permissions
+     *
+     * @return  the resulting set of permissions
+     *
+     * @throws  IllegalArgumentException
+     *          if the string cannot be converted to a set of permissions
+     *
+     * @see #toString(Set)
+     */
+    public static Set<PosixFilePermission> fromString(String perms) {
+        if (perms.length() != 9)
+            throw new IllegalArgumentException("Invalid mode");
+        Set<PosixFilePermission> result = EnumSet.noneOf(PosixFilePermission.class);
+        if (isR(perms.charAt(0))) result.add(OWNER_READ);
+        if (isW(perms.charAt(1))) result.add(OWNER_WRITE);
+        if (isX(perms.charAt(2))) result.add(OWNER_EXECUTE);
+        if (isR(perms.charAt(3))) result.add(GROUP_READ);
+        if (isW(perms.charAt(4))) result.add(GROUP_WRITE);
+        if (isX(perms.charAt(5))) result.add(GROUP_EXECUTE);
+        if (isR(perms.charAt(6))) result.add(OTHERS_READ);
+        if (isW(perms.charAt(7))) result.add(OTHERS_WRITE);
+        if (isX(perms.charAt(8))) result.add(OTHERS_EXECUTE);
+        return result;
+    }
+
+    /**
+     * Creates a {@link FileAttribute}, encapsulating a copy of the given file
+     * permissions, suitable for passing to the {@link java.nio.file.Files#createFile
+     * createFile} or {@link java.nio.file.Files#createDirectory createDirectory}
+     * methods.
+     *
+     * @param   perms
+     *          the set of permissions
+     *
+     * @return  an attribute encapsulating the given file permissions with
+     *          {@link FileAttribute#name name} {@code "posix:permissions"}
+     *
+     * @throws  ClassCastException
+     *          if the set contains elements that are not of type {@code
+     *          PosixFilePermission}
+     */
+    public static FileAttribute<Set<PosixFilePermission>>
+        asFileAttribute(Set<PosixFilePermission> perms)
+    {
+        // copy set and check for nulls (CCE will be thrown if an element is not
+        // a PosixFilePermission)
+        perms = new HashSet<PosixFilePermission>(perms);
+        for (PosixFilePermission p: perms) {
+            if (p == null)
+                throw new NullPointerException();
+        }
+        final Set<PosixFilePermission> value = perms;
+        return new FileAttribute<Set<PosixFilePermission>>() {
+            @Override
+            public String name() {
+                return "posix:permissions";
+            }
+            @Override
+            public Set<PosixFilePermission> value() {
+                return Collections.unmodifiableSet(value);
+            }
+        };
+    }
+}
diff --git a/java/nio/file/attribute/UserDefinedFileAttributeView.java b/java/nio/file/attribute/UserDefinedFileAttributeView.java
new file mode 100644
index 0000000..56e7135
--- /dev/null
+++ b/java/nio/file/attribute/UserDefinedFileAttributeView.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.io.IOException;
+
+/**
+ * A file attribute view that provides a view of a file's user-defined
+ * attributes, sometimes known as <em>extended attributes</em>. User-defined
+ * file attributes are used to store metadata with a file that is not meaningful
+ * to the file system. It is primarily intended for file system implementations
+ * that support such a capability directly but may be emulated. The details of
+ * such emulation are highly implementation specific and therefore not specified.
+ *
+ * <p> This {@code FileAttributeView} provides a view of a file's user-defined
+ * attributes as a set of name/value pairs, where the attribute name is
+ * represented by a {@code String}. An implementation may require to encode and
+ * decode from the platform or file system representation when accessing the
+ * attribute. The value has opaque content. This attribute view defines the
+ * {@link #read read} and {@link #write write} methods to read the value into
+ * or write from a {@link ByteBuffer}. This {@code FileAttributeView} is not
+ * intended for use where the size of an attribute value is larger than {@link
+ * Integer#MAX_VALUE}.
+ *
+ * <p> User-defined attributes may be used in some implementations to store
+ * security related attributes so consequently, in the case of the default
+ * provider at least, all methods that access user-defined attributes require the
+ * {@code RuntimePermission("accessUserDefinedAttributes")} permission when a
+ * security manager is installed.
+ *
+ * <p> The {@link java.nio.file.FileStore#supportsFileAttributeView
+ * supportsFileAttributeView} method may be used to test if a specific {@link
+ * java.nio.file.FileStore FileStore} supports the storage of user-defined
+ * attributes.
+ *
+ * <p> Where dynamic access to file attributes is required, the {@link
+ * java.nio.file.Files#getAttribute getAttribute} method may be used to read
+ * the attribute value. The attribute value is returned as a byte array (byte[]).
+ * The {@link java.nio.file.Files#setAttribute setAttribute} method may be used
+ * to write the value of a user-defined attribute from a buffer (as if by
+ * invoking the {@link #write write} method), or byte array (byte[]).
+ *
+ * @since 1.7
+ */
+
+public interface UserDefinedFileAttributeView
+    extends FileAttributeView
+{
+    /**
+     * Returns the name of this attribute view. Attribute views of this type
+     * have the name {@code "user"}.
+     */
+    @Override
+    String name();
+
+    /**
+     * Returns a list containing the names of the user-defined attributes.
+     *
+     * @return  An unmodifiable list containing the names of the file's
+     *          user-defined
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    List<String> list() throws IOException;
+
+    /**
+     * Returns the size of the value of a user-defined attribute.
+     *
+     * @param   name
+     *          The attribute name
+     *
+     * @return  The size of the attribute value, in bytes.
+     *
+     * @throws  ArithmeticException
+     *          If the size of the attribute is larger than {@link Integer#MAX_VALUE}
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     */
+    int size(String name) throws IOException;
+
+    /**
+     * Read the value of a user-defined attribute into a buffer.
+     *
+     * <p> This method reads the value of the attribute into the given buffer
+     * as a sequence of bytes, failing if the number of bytes remaining in
+     * the buffer is insufficient to read the complete attribute value. The
+     * number of bytes transferred into the buffer is {@code n}, where {@code n}
+     * is the size of the attribute value. The first byte in the sequence is at
+     * index {@code p} and the last byte is at index {@code p + n - 1}, where
+     * {@code p} is the buffer's position. Upon return the buffer's position
+     * will be equal to {@code p + n}; its limit will not have changed.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to read a file's MIME type that is stored as a user-defined
+     * attribute with the name "{@code user.mimetype}".
+     * <pre>
+     *    UserDefinedFileAttributeView view =
+     *        Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
+     *    String name = "user.mimetype";
+     *    ByteBuffer buf = ByteBuffer.allocate(view.size(name));
+     *    view.read(name, buf);
+     *    buf.flip();
+     *    String value = Charset.defaultCharset().decode(buf).toString();
+     * </pre>
+     *
+     * @param   name
+     *          The attribute name
+     * @param   dst
+     *          The destination buffer
+     *
+     * @return  The number of bytes read, possibly zero
+     *
+     * @throws  IllegalArgumentException
+     *          If the destination buffer is read-only
+     * @throws  IOException
+     *          If an I/O error occurs or there is insufficient space in the
+     *          destination buffer for the attribute value
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkRead(String) checkRead} method
+     *          denies read access to the file.
+     *
+     * @see #size
+     */
+    int read(String name, ByteBuffer dst) throws IOException;
+
+    /**
+     * Writes the value of a user-defined attribute from a buffer.
+     *
+     * <p> This method writes the value of the attribute from a given buffer as
+     * a sequence of bytes. The size of the value to transfer is {@code r},
+     * where {@code r} is the number of bytes remaining in the buffer, that is
+     * {@code src.remaining()}. The sequence of bytes is transferred from the
+     * buffer starting at index {@code p}, where {@code p} is the buffer's
+     * position. Upon return, the buffer's position will be equal to {@code
+     * p + n}, where {@code n} is the number of bytes transferred; its limit
+     * will not have changed.
+     *
+     * <p> If an attribute of the given name already exists then its value is
+     * replaced. If the attribute does not exist then it is created. If it
+     * implementation specific if a test to check for the existence of the
+     * attribute and the creation of attribute are atomic with respect to other
+     * file system activities.
+     *
+     * <p> Where there is insufficient space to store the attribute, or the
+     * attribute name or value exceed an implementation specific maximum size
+     * then an {@code IOException} is thrown.
+     *
+     * <p> <b>Usage Example:</b>
+     * Suppose we want to write a file's MIME type as a user-defined attribute:
+     * <pre>
+     *    UserDefinedFileAttributeView view =
+     *        FIles.getFileAttributeView(path, UserDefinedFileAttributeView.class);
+     *    view.write("user.mimetype", Charset.defaultCharset().encode("text/html"));
+     * </pre>
+     *
+     * @param   name
+     *          The attribute name
+     * @param   src
+     *          The buffer containing the attribute value
+     *
+     * @return  The number of bytes written, possibly zero
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    int write(String name, ByteBuffer src) throws IOException;
+
+    /**
+     * Deletes a user-defined attribute.
+     *
+     * @param   name
+     *          The attribute name
+     *
+     * @throws  IOException
+     *          If an I/O error occurs or the attribute does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, and it denies {@link
+     *          RuntimePermission}<tt>("accessUserDefinedAttributes")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file.
+     */
+    void delete(String name) throws IOException;
+}
diff --git a/java/nio/file/attribute/UserPrincipal.java b/java/nio/file/attribute/UserPrincipal.java
new file mode 100644
index 0000000..01b26bb
--- /dev/null
+++ b/java/nio/file/attribute/UserPrincipal.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.security.Principal;
+
+/**
+ * A {@code Principal} representing an identity used to determine access rights
+ * to objects in a file system.
+ *
+ * <p> On many platforms and file systems an entity requires appropriate access
+ * rights or permissions in order to access objects in a file system. The
+ * access rights are generally performed by checking the identity of the entity.
+ * For example, on implementations that use Access Control Lists (ACLs) to
+ * enforce privilege separation then a file in the file system may have an
+ * associated ACL that determines the access rights of identities specified in
+ * the ACL.
+ *
+ * <p> A {@code UserPrincipal} object is an abstract representation of an
+ * identity. It has a {@link #getName() name} that is typically the username or
+ * account name that it represents. User principal objects may be obtained using
+ * a {@link UserPrincipalLookupService}, or returned by {@link
+ * FileAttributeView} implementations that provide access to identity related
+ * attributes. For example, the {@link AclFileAttributeView} and {@link
+ * PosixFileAttributeView} provide access to a file's {@link
+ * PosixFileAttributes#owner owner}.
+ *
+ * @since 1.7
+ */
+
+public interface UserPrincipal extends Principal { }
diff --git a/java/nio/file/attribute/UserPrincipalLookupService.java b/java/nio/file/attribute/UserPrincipalLookupService.java
new file mode 100644
index 0000000..c3f3bef
--- /dev/null
+++ b/java/nio/file/attribute/UserPrincipalLookupService.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * An object to lookup user and group principals by name. A {@link UserPrincipal}
+ * represents an identity that may be used to determine access rights to objects
+ * in a file system. A {@link GroupPrincipal} represents a <em>group identity</em>.
+ * A {@code UserPrincipalLookupService} defines methods to lookup identities by
+ * name or group name (which are typically user or account names). Whether names
+ * and group names are case sensitive or not depends on the implementation.
+ * The exact definition of a group is implementation specific but typically a
+ * group represents an identity created for administrative purposes so as to
+ * determine the access rights for the members of the group. In particular it is
+ * implementation specific if the <em>namespace</em> for names and groups is the
+ * same or is distinct. To ensure consistent and correct behavior across
+ * platforms it is recommended that this API be used as if the namespaces are
+ * distinct. In other words, the {@link #lookupPrincipalByName
+ * lookupPrincipalByName} should be used to lookup users, and {@link
+ * #lookupPrincipalByGroupName lookupPrincipalByGroupName} should be used to
+ * lookup groups.
+ *
+ * @since 1.7
+ *
+ * @see java.nio.file.FileSystem#getUserPrincipalLookupService
+ */
+
+public abstract class UserPrincipalLookupService {
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected UserPrincipalLookupService() {
+    }
+
+    /**
+     * Lookup a user principal by name.
+     *
+     * @param   name
+     *          the string representation of the user principal to lookup
+     *
+     * @return  a user principal
+     *
+     * @throws  UserPrincipalNotFoundException
+     *          the principal does not exist
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, it checks {@link RuntimePermission}<tt>("lookupUserInformation")</tt>
+     */
+    public abstract UserPrincipal lookupPrincipalByName(String name)
+        throws IOException;
+
+    /**
+     * Lookup a group principal by group name.
+     *
+     * <p> Where an implementation does not support any notion of group then
+     * this method always throws {@link UserPrincipalNotFoundException}. Where
+     * the namespace for user accounts and groups is the same, then this method
+     * is identical to invoking {@link #lookupPrincipalByName
+     * lookupPrincipalByName}.
+     *
+     * @param   group
+     *          the string representation of the group to lookup
+     *
+     * @return  a group principal
+     *
+     * @throws  UserPrincipalNotFoundException
+     *          the principal does not exist or is not a group
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, it checks {@link RuntimePermission}<tt>("lookupUserInformation")</tt>
+     */
+    public abstract GroupPrincipal lookupPrincipalByGroupName(String group)
+        throws IOException;
+}
diff --git a/java/nio/file/attribute/UserPrincipalNotFoundException.java b/java/nio/file/attribute/UserPrincipalNotFoundException.java
new file mode 100644
index 0000000..5cf0ab0
--- /dev/null
+++ b/java/nio/file/attribute/UserPrincipalNotFoundException.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.attribute;
+
+import java.io.IOException;
+
+/**
+ * Checked exception thrown when a lookup of {@link UserPrincipal} fails because
+ * the principal does not exist.
+ *
+ * @since 1.7
+ */
+
+public class UserPrincipalNotFoundException
+    extends IOException
+{
+    static final long serialVersionUID = -5369283889045833024L;
+
+    private final String name;
+
+    /**
+     * Constructs an instance of this class.
+     *
+     * @param   name
+     *          the principal name; may be {@code null}
+     */
+    public UserPrincipalNotFoundException(String name) {
+        super();
+        this.name = name;
+    }
+
+    /**
+     * Returns the user principal name if this exception was created with the
+     * user principal name that was not found, otherwise <tt>null</tt>.
+     *
+     * @return  the user principal name or {@code null}
+     */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/java/nio/file/spi/FileSystemProvider.java b/java/nio/file/spi/FileSystemProvider.java
new file mode 100644
index 0000000..bed8416
--- /dev/null
+++ b/java/nio/file/spi/FileSystemProvider.java
@@ -0,0 +1,1103 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.spi;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.channels.*;
+import java.net.URI;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Service-provider class for file systems. The methods defined by the {@link
+ * java.nio.file.Files} class will typically delegate to an instance of this
+ * class.
+ *
+ * <p> A file system provider is a concrete implementation of this class that
+ * implements the abstract methods defined by this class. A provider is
+ * identified by a {@code URI} {@link #getScheme() scheme}. The default provider
+ * is identified by the URI scheme "file". It creates the {@link FileSystem} that
+ * provides access to the file systems accessible to the Java virtual machine.
+ * The {@link FileSystems} class defines how file system providers are located
+ * and loaded. The default provider is typically a system-default provider but
+ * may be overridden if the system property {@code
+ * java.nio.file.spi.DefaultFileSystemProvider} is set. In that case, the
+ * provider has a one argument constructor whose formal parameter type is {@code
+ * FileSystemProvider}. All other providers have a zero argument constructor
+ * that initializes the provider.
+ *
+ * <p> A provider is a factory for one or more {@link FileSystem} instances. Each
+ * file system is identified by a {@code URI} where the URI's scheme matches
+ * the provider's {@link #getScheme scheme}. The default file system, for example,
+ * is identified by the URI {@code "file:///"}. A memory-based file system,
+ * for example, may be identified by a URI such as {@code "memory:///?name=logfs"}.
+ * The {@link #newFileSystem newFileSystem} method may be used to create a file
+ * system, and the {@link #getFileSystem getFileSystem} method may be used to
+ * obtain a reference to an existing file system created by the provider. Where
+ * a provider is the factory for a single file system then it is provider dependent
+ * if the file system is created when the provider is initialized, or later when
+ * the {@code newFileSystem} method is invoked. In the case of the default
+ * provider, the {@code FileSystem} is created when the provider is initialized.
+ *
+ * <p> All of the methods in this class are safe for use by multiple concurrent
+ * threads.
+ *
+ * @since 1.7
+ */
+
+public abstract class FileSystemProvider {
+    // lock using when loading providers
+    private static final Object lock = new Object();
+
+    // installed providers
+    private static volatile List<FileSystemProvider> installedProviders;
+
+    // used to avoid recursive loading of instaled providers
+    private static boolean loadingProviders  = false;
+
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("fileSystemProvider"));
+        return null;
+    }
+    private FileSystemProvider(Void ignore) { }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * <p> During construction a provider may safely access files associated
+     * with the default provider but care needs to be taken to avoid circular
+     * loading of other installed providers. If circular loading of installed
+     * providers is detected then an unspecified error is thrown.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("fileSystemProvider")</tt>
+     */
+    protected FileSystemProvider() {
+        this(checkPermission());
+    }
+
+    // loads all installed providers
+    private static List<FileSystemProvider> loadInstalledProviders() {
+        List<FileSystemProvider> list = new ArrayList<FileSystemProvider>();
+
+        ServiceLoader<FileSystemProvider> sl = ServiceLoader
+            .load(FileSystemProvider.class, ClassLoader.getSystemClassLoader());
+
+        // ServiceConfigurationError may be throw here
+        for (FileSystemProvider provider: sl) {
+            String scheme = provider.getScheme();
+
+            // add to list if the provider is not "file" and isn't a duplicate
+            if (!scheme.equalsIgnoreCase("file")) {
+                boolean found = false;
+                for (FileSystemProvider p: list) {
+                    if (p.getScheme().equalsIgnoreCase(scheme)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    list.add(provider);
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a list of the installed file system providers.
+     *
+     * <p> The first invocation of this method causes the default provider to be
+     * initialized (if not already initialized) and loads any other installed
+     * providers as described by the {@link FileSystems} class.
+     *
+     * @return  An unmodifiable list of the installed file system providers. The
+     *          list contains at least one element, that is the default file
+     *          system provider
+     *
+     * @throws  ServiceConfigurationError
+     *          When an error occurs while loading a service provider
+     */
+    public static List<FileSystemProvider> installedProviders() {
+        if (installedProviders == null) {
+            // ensure default provider is initialized
+            FileSystemProvider defaultProvider = FileSystems.getDefault().provider();
+
+            synchronized (lock) {
+                if (installedProviders == null) {
+                    if (loadingProviders) {
+                        throw new Error("Circular loading of installed providers detected");
+                    }
+                    loadingProviders = true;
+
+                    List<FileSystemProvider> list = AccessController
+                        .doPrivileged(new PrivilegedAction<List<FileSystemProvider>>() {
+                            @Override
+                            public List<FileSystemProvider> run() {
+                                return loadInstalledProviders();
+                        }});
+
+                    // insert the default provider at the start of the list
+                    list.add(0, defaultProvider);
+
+                    installedProviders = Collections.unmodifiableList(list);
+                }
+            }
+        }
+        return installedProviders;
+    }
+
+    /**
+     * Returns the URI scheme that identifies this provider.
+     *
+     * @return  The URI scheme
+     */
+    public abstract String getScheme();
+
+    /**
+     * Constructs a new {@code FileSystem} object identified by a URI. This
+     * method is invoked by the {@link FileSystems#newFileSystem(URI,Map)}
+     * method to open a new file system identified by a URI.
+     *
+     * <p> The {@code uri} parameter is an absolute, hierarchical URI, with a
+     * scheme equal (without regard to case) to the scheme supported by this
+     * provider. The exact form of the URI is highly provider dependent. The
+     * {@code env} parameter is a map of provider specific properties to configure
+     * the file system.
+     *
+     * <p> This method throws {@link FileSystemAlreadyExistsException} if the
+     * file system already exists because it was previously created by an
+     * invocation of this method. Once a file system is {@link
+     * java.nio.file.FileSystem#close closed} it is provider-dependent if the
+     * provider allows a new file system to be created with the same URI as a
+     * file system it previously created.
+     *
+     * @param   uri
+     *          URI reference
+     * @param   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     *
+     * @return  A new file system
+     *
+     * @throws  IllegalArgumentException
+     *          If the pre-conditions for the {@code uri} parameter aren't met,
+     *          or the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  IOException
+     *          An I/O error occurs creating the file system
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission required by the file system provider implementation
+     * @throws  FileSystemAlreadyExistsException
+     *          If the file system has already been created
+     */
+    public abstract FileSystem newFileSystem(URI uri, Map<String,?> env)
+        throws IOException;
+
+    /**
+     * Returns an existing {@code FileSystem} created by this provider.
+     *
+     * <p> This method returns a reference to a {@code FileSystem} that was
+     * created by invoking the {@link #newFileSystem(URI,Map) newFileSystem(URI,Map)}
+     * method. File systems created the {@link #newFileSystem(Path,Map)
+     * newFileSystem(Path,Map)} method are not returned by this method.
+     * The file system is identified by its {@code URI}. Its exact form
+     * is highly provider dependent. In the case of the default provider the URI's
+     * path component is {@code "/"} and the authority, query and fragment components
+     * are undefined (Undefined components are represented by {@code null}).
+     *
+     * <p> Once a file system created by this provider is {@link
+     * java.nio.file.FileSystem#close closed} it is provider-dependent if this
+     * method returns a reference to the closed file system or throws {@link
+     * FileSystemNotFoundException}. If the provider allows a new file system to
+     * be created with the same URI as a file system it previously created then
+     * this method throws the exception if invoked after the file system is
+     * closed (and before a new instance is created by the {@link #newFileSystem
+     * newFileSystem} method).
+     *
+     * <p> If a security manager is installed then a provider implementation
+     * may require to check a permission before returning a reference to an
+     * existing file system. In the case of the {@link FileSystems#getDefault
+     * default} file system, no permission check is required.
+     *
+     * @param   uri
+     *          URI reference
+     *
+     * @return  The file system
+     *
+     * @throws  IllegalArgumentException
+     *          If the pre-conditions for the {@code uri} parameter aren't met
+     * @throws  FileSystemNotFoundException
+     *          If the file system does not exist
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public abstract FileSystem getFileSystem(URI uri);
+
+    /**
+     * Return a {@code Path} object by converting the given {@link URI}. The
+     * resulting {@code Path} is associated with a {@link FileSystem} that
+     * already exists or is constructed automatically.
+     *
+     * <p> The exact form of the URI is file system provider dependent. In the
+     * case of the default provider, the URI scheme is {@code "file"} and the
+     * given URI has a non-empty path component, and undefined query, and
+     * fragment components. The resulting {@code Path} is associated with the
+     * default {@link FileSystems#getDefault default} {@code FileSystem}.
+     *
+     * <p> If a security manager is installed then a provider implementation
+     * may require to check a permission. In the case of the {@link
+     * FileSystems#getDefault default} file system, no permission check is
+     * required.
+     *
+     * @param   uri
+     *          The URI to convert
+     *
+     * @return  The resulting {@code Path}
+     *
+     * @throws  IllegalArgumentException
+     *          If the URI scheme does not identify this provider or other
+     *          preconditions on the uri parameter do not hold
+     * @throws  FileSystemNotFoundException
+     *          The file system, identified by the URI, does not exist and
+     *          cannot be created automatically
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public abstract Path getPath(URI uri);
+
+    /**
+     * Constructs a new {@code FileSystem} to access the contents of a file as a
+     * file system.
+     *
+     * <p> This method is intended for specialized providers of pseudo file
+     * systems where the contents of one or more files is treated as a file
+     * system. The {@code env} parameter is a map of provider specific properties
+     * to configure the file system.
+     *
+     * <p> If this provider does not support the creation of such file systems
+     * or if the provider does not recognize the file type of the given file then
+     * it throws {@code UnsupportedOperationException}. The default implementation
+     * of this method throws {@code UnsupportedOperationException}.
+     *
+     * @param   path
+     *          The path to the file
+     * @param   env
+     *          A map of provider specific properties to configure the file system;
+     *          may be empty
+     *
+     * @return  A new file system
+     *
+     * @throws  UnsupportedOperationException
+     *          If this provider does not support access to the contents as a
+     *          file system or it does not recognize the file type of the
+     *          given file
+     * @throws  IllegalArgumentException
+     *          If the {@code env} parameter does not contain properties required
+     *          by the provider, or a property value is invalid
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          If a security manager is installed and it denies an unspecified
+     *          permission.
+     */
+    public FileSystem newFileSystem(Path path, Map<String,?> env)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Opens a file, returning an input stream to read from the file. This
+     * method works in exactly the manner specified by the {@link
+     * Files#newInputStream} method.
+     *
+     * <p> The default implementation of this method opens a channel to the file
+     * as if by invoking the {@link #newByteChannel} method and constructs a
+     * stream that reads bytes from the channel. This method should be overridden
+     * where appropriate.
+     *
+     * @param   path
+     *          the path to the file to open
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new input stream
+     *
+     * @throws  IllegalArgumentException
+     *          if an invalid combination of options is specified
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    public InputStream newInputStream(Path path, OpenOption... options)
+        throws IOException
+    {
+        if (options.length > 0) {
+            for (OpenOption opt: options) {
+                // All OpenOption values except for APPEND and WRITE are allowed
+                if (opt == StandardOpenOption.APPEND ||
+                    opt == StandardOpenOption.WRITE)
+                    throw new UnsupportedOperationException("'" + opt + "' not allowed");
+            }
+        }
+        return Channels.newInputStream(Files.newByteChannel(path, options));
+    }
+
+    /**
+     * Opens or creates a file, returning an output stream that may be used to
+     * write bytes to the file. This method works in exactly the manner
+     * specified by the {@link Files#newOutputStream} method.
+     *
+     * <p> The default implementation of this method opens a channel to the file
+     * as if by invoking the {@link #newByteChannel} method and constructs a
+     * stream that writes bytes to the channel. This method should be overridden
+     * where appropriate.
+     *
+     * @param   path
+     *          the path to the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     *
+     * @return  a new output stream
+     *
+     * @throws  IllegalArgumentException
+     *          if {@code options} contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          if an unsupported option is specified
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the file. The {@link
+     *          SecurityManager#checkDelete(String) checkDelete} method is
+     *          invoked to check delete access if the file is opened with the
+     *          {@code DELETE_ON_CLOSE} option.
+     */
+    public OutputStream newOutputStream(Path path, OpenOption... options)
+        throws IOException
+    {
+        int len = options.length;
+        Set<OpenOption> opts = new HashSet<OpenOption>(len + 3);
+        if (len == 0) {
+            opts.add(StandardOpenOption.CREATE);
+            opts.add(StandardOpenOption.TRUNCATE_EXISTING);
+        } else {
+            for (OpenOption opt: options) {
+                if (opt == StandardOpenOption.READ)
+                    throw new IllegalArgumentException("READ not allowed");
+                opts.add(opt);
+            }
+        }
+        opts.add(StandardOpenOption.WRITE);
+        return Channels.newOutputStream(newByteChannel(path, opts));
+    }
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning a file
+     * channel to access the file. This method works in exactly the manner
+     * specified by the {@link FileChannel#open(Path,Set,FileAttribute[])
+     * FileChannel.open} method. A provider that does not support all the
+     * features required to construct a file channel throws {@code
+     * UnsupportedOperationException}. The default provider is required to
+     * support the creation of file channels. When not overridden, the default
+     * implementation throws {@code UnsupportedOperationException}.
+     *
+     * @param   path
+     *          the path of the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  a new file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If this provider that does not support creating file channels,
+     *          or an unsupported open option or file attribute is specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default file system, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public FileChannel newFileChannel(Path path,
+                                      Set<? extends OpenOption> options,
+                                      FileAttribute<?>... attrs)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Opens or creates a file for reading and/or writing, returning an
+     * asynchronous file channel to access the file. This method works in
+     * exactly the manner specified by the {@link
+     * AsynchronousFileChannel#open(Path,Set,ExecutorService,FileAttribute[])
+     * AsynchronousFileChannel.open} method.
+     * A provider that does not support all the features required to construct
+     * an asynchronous file channel throws {@code UnsupportedOperationException}.
+     * The default provider is required to support the creation of asynchronous
+     * file channels. When not overridden, the default implementation of this
+     * method throws {@code UnsupportedOperationException}.
+     *
+     * @param   path
+     *          the path of the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     * @param   executor
+     *          the thread pool or {@code null} to associate the channel with
+     *          the default thread pool
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  a new asynchronous file channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          If this provider that does not support creating asynchronous file
+     *          channels, or an unsupported open option or file attribute is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default file system, the {@link
+     *          SecurityManager#checkRead(String)} method is invoked to check
+     *          read access if the file is opened for reading. The {@link
+     *          SecurityManager#checkWrite(String)} method is invoked to check
+     *          write access if the file is opened for writing
+     */
+    public AsynchronousFileChannel newAsynchronousFileChannel(Path path,
+                                                              Set<? extends OpenOption> options,
+                                                              ExecutorService executor,
+                                                              FileAttribute<?>... attrs)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Opens or creates a file, returning a seekable byte channel to access the
+     * file. This method works in exactly the manner specified by the {@link
+     * Files#newByteChannel(Path,Set,FileAttribute[])} method.
+     *
+     * @param   path
+     *          the path to the file to open or create
+     * @param   options
+     *          options specifying how the file is opened
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the file
+     *
+     * @return  a new seekable byte channel
+     *
+     * @throws  IllegalArgumentException
+     *          if the set contains an invalid combination of options
+     * @throws  UnsupportedOperationException
+     *          if an unsupported open option is specified or the array contains
+     *          attributes that cannot be set atomically when creating the file
+     * @throws  FileAlreadyExistsException
+     *          if a file of that name already exists and the {@link
+     *          StandardOpenOption#CREATE_NEW CREATE_NEW} option is specified
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the path if the file is
+     *          opened for reading. The {@link SecurityManager#checkWrite(String)
+     *          checkWrite} method is invoked to check write access to the path
+     *          if the file is opened for writing. The {@link
+     *          SecurityManager#checkDelete(String) checkDelete} method is
+     *          invoked to check delete access if the file is opened with the
+     *          {@code DELETE_ON_CLOSE} option.
+     */
+    public abstract SeekableByteChannel newByteChannel(Path path,
+        Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException;
+
+    /**
+     * Opens a directory, returning a {@code DirectoryStream} to iterate over
+     * the entries in the directory. This method works in exactly the manner
+     * specified by the {@link
+     * Files#newDirectoryStream(java.nio.file.Path, java.nio.file.DirectoryStream.Filter)}
+     * method.
+     *
+     * @param   dir
+     *          the path to the directory
+     * @param   filter
+     *          the directory stream filter
+     *
+     * @return  a new and open {@code DirectoryStream} object
+     *
+     * @throws  NotDirectoryException
+     *          if the file could not otherwise be opened because it is not
+     *          a directory <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the directory.
+     */
+    public abstract DirectoryStream<Path> newDirectoryStream(Path dir,
+         DirectoryStream.Filter<? super Path> filter) throws IOException;
+
+    /**
+     * Creates a new directory. This method works in exactly the manner
+     * specified by the {@link Files#createDirectory} method.
+     *
+     * @param   dir
+     *          the directory to create
+     * @param   attrs
+     *          an optional list of file attributes to set atomically when
+     *          creating the directory
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains an attribute that cannot be set atomically
+     *          when creating the directory
+     * @throws  FileAlreadyExistsException
+     *          if a directory could not otherwise be created because a file of
+     *          that name already exists <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs or the parent directory does not exist
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to the new directory.
+     */
+    public abstract void createDirectory(Path dir, FileAttribute<?>... attrs)
+        throws IOException;
+
+    /**
+     * Creates a symbolic link to a target. This method works in exactly the
+     * manner specified by the {@link Files#createSymbolicLink} method.
+     *
+     * <p> The default implementation of this method throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @param   link
+     *          the path of the symbolic link to create
+     * @param   target
+     *          the target of the symbolic link
+     * @param   attrs
+     *          the array of attributes to set atomically when creating the
+     *          symbolic link
+     *
+     * @throws  UnsupportedOperationException
+     *          if the implementation does not support symbolic links or the
+     *          array contains an attribute that cannot be set atomically when
+     *          creating the symbolic link
+     * @throws  FileAlreadyExistsException
+     *          if a file with the name already exists <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, it denies {@link LinkPermission}<tt>("symbolic")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the path of the symbolic link.
+     */
+    public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs)
+        throws IOException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Creates a new link (directory entry) for an existing file. This method
+     * works in exactly the manner specified by the {@link Files#createLink}
+     * method.
+     *
+     * <p> The default implementation of this method throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @param   link
+     *          the link (directory entry) to create
+     * @param   existing
+     *          a path to an existing file
+     *
+     * @throws  UnsupportedOperationException
+     *          if the implementation does not support adding an existing file
+     *          to a directory
+     * @throws  FileAlreadyExistsException
+     *          if the entry could not otherwise be created because a file of
+     *          that name already exists <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, it denies {@link LinkPermission}<tt>("hard")</tt>
+     *          or its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to either the  link or the
+     *          existing file.
+     */
+    public void createLink(Path link, Path existing) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Deletes a file. This method works in exactly the  manner specified by the
+     * {@link Files#delete} method.
+     *
+     * @param   path
+     *          the path to the file to delete
+     *
+     * @throws  NoSuchFileException
+     *          if the file does not exist <i>(optional specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          if the file is a directory and could not otherwise be deleted
+     *          because the directory is not empty <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkDelete(String)} method
+     *          is invoked to check delete access to the file
+     */
+    public abstract void delete(Path path) throws IOException;
+
+    /**
+     * Deletes a file if it exists. This method works in exactly the manner
+     * specified by the {@link Files#deleteIfExists} method.
+     *
+     * <p> The default implementation of this method simply invokes {@link
+     * #delete} ignoring the {@code NoSuchFileException} when the file does not
+     * exist. It may be overridden where appropriate.
+     *
+     * @param   path
+     *          the path to the file to delete
+     *
+     * @return  {@code true} if the file was deleted by this method; {@code
+     *          false} if the file could not be deleted because it did not
+     *          exist
+     *
+     * @throws  DirectoryNotEmptyException
+     *          if the file is a directory and could not otherwise be deleted
+     *          because the directory is not empty <i>(optional specific
+     *          exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkDelete(String)} method
+     *          is invoked to check delete access to the file
+     */
+    public boolean deleteIfExists(Path path) throws IOException {
+        try {
+            delete(path);
+            return true;
+        } catch (NoSuchFileException ignore) {
+            return false;
+        }
+    }
+
+    /**
+     * Reads the target of a symbolic link. This method works in exactly the
+     * manner specified by the {@link Files#readSymbolicLink} method.
+     *
+     * <p> The default implementation of this method throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @param   link
+     *          the path to the symbolic link
+     *
+     * @return  The target of the symbolic link
+     *
+     * @throws  UnsupportedOperationException
+     *          if the implementation does not support symbolic links
+     * @throws  NotLinkException
+     *          if the target could otherwise not be read because the file
+     *          is not a symbolic link <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager
+     *          is installed, it checks that {@code FilePermission} has been
+     *          granted with the "{@code readlink}" action to read the link.
+     */
+    public Path readSymbolicLink(Path link) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Copy a file to a target file. This method works in exactly the manner
+     * specified by the {@link Files#copy(Path,Path,CopyOption[])} method
+     * except that both the source and target paths must be associated with
+     * this provider.
+     *
+     * @param   source
+     *          the path to the file to copy
+     * @param   target
+     *          the path to the target file
+     * @param   options
+     *          options specifying how the copy should be done
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains a copy option that is not supported
+     * @throws  FileAlreadyExistsException
+     *          if the target file exists but cannot be replaced because the
+     *          {@code REPLACE_EXISTING} option is not specified <i>(optional
+     *          specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          the {@code REPLACE_EXISTING} option is specified but the file
+     *          cannot be replaced because it is a non-empty directory
+     *          <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the source file, the
+     *          {@link SecurityManager#checkWrite(String) checkWrite} is invoked
+     *          to check write access to the target file. If a symbolic link is
+     *          copied the security manager is invoked to check {@link
+     *          LinkPermission}{@code ("symbolic")}.
+     */
+    public abstract void copy(Path source, Path target, CopyOption... options)
+        throws IOException;
+
+    /**
+     * Move or rename a file to a target file. This method works in exactly the
+     * manner specified by the {@link Files#move} method except that both the
+     * source and target paths must be associated with this provider.
+     *
+     * @param   source
+     *          the path to the file to move
+     * @param   target
+     *          the path to the target file
+     * @param   options
+     *          options specifying how the move should be done
+     *
+     * @throws  UnsupportedOperationException
+     *          if the array contains a copy option that is not supported
+     * @throws  FileAlreadyExistsException
+     *          if the target file exists but cannot be replaced because the
+     *          {@code REPLACE_EXISTING} option is not specified <i>(optional
+     *          specific exception)</i>
+     * @throws  DirectoryNotEmptyException
+     *          the {@code REPLACE_EXISTING} option is specified but the file
+     *          cannot be replaced because it is a non-empty directory
+     *          <i>(optional specific exception)</i>
+     * @throws  AtomicMoveNotSupportedException
+     *          if the options array contains the {@code ATOMIC_MOVE} option but
+     *          the file cannot be moved as an atomic file system operation.
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method is invoked to check write access to both the source and
+     *          target file.
+     */
+    public abstract void move(Path source, Path target, CopyOption... options)
+        throws IOException;
+
+    /**
+     * Tests if two paths locate the same file. This method works in exactly the
+     * manner specified by the {@link Files#isSameFile} method.
+     *
+     * @param   path
+     *          one path to the file
+     * @param   path2
+     *          the other path
+     *
+     * @return  {@code true} if, and only if, the two paths locate the same file
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to both files.
+     */
+    public abstract boolean isSameFile(Path path, Path path2)
+        throws IOException;
+
+    /**
+     * Tells whether or not a file is considered <em>hidden</em>. This method
+     * works in exactly the manner specified by the {@link Files#isHidden}
+     * method.
+     *
+     * <p> This method is invoked by the {@link Files#isHidden isHidden} method.
+     *
+     * @param   path
+     *          the path to the file to test
+     *
+     * @return  {@code true} if the file is considered hidden
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file.
+     */
+    public abstract boolean isHidden(Path path) throws IOException;
+
+    /**
+     * Returns the {@link FileStore} representing the file store where a file
+     * is located. This method works in exactly the manner specified by the
+     * {@link Files#getFileStore} method.
+     *
+     * @param   path
+     *          the path to the file
+     *
+     * @return  the file store where the file is stored
+     *
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file, and in
+     *          addition it checks {@link RuntimePermission}<tt>
+     *          ("getFileStoreAttributes")</tt>
+     */
+    public abstract FileStore getFileStore(Path path) throws IOException;
+
+    /**
+     * Checks the existence, and optionally the accessibility, of a file.
+     *
+     * <p> This method may be used by the {@link Files#isReadable isReadable},
+     * {@link Files#isWritable isWritable} and {@link Files#isExecutable
+     * isExecutable} methods to check the accessibility of a file.
+     *
+     * <p> This method checks the existence of a file and that this Java virtual
+     * machine has appropriate privileges that would allow it access the file
+     * according to all of access modes specified in the {@code modes} parameter
+     * as follows:
+     *
+     * <table border=1 cellpadding=5 summary="">
+     * <tr> <th>Value</th> <th>Description</th> </tr>
+     * <tr>
+     *   <td> {@link AccessMode#READ READ} </td>
+     *   <td> Checks that the file exists and that the Java virtual machine has
+     *     permission to read the file. </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link AccessMode#WRITE WRITE} </td>
+     *   <td> Checks that the file exists and that the Java virtual machine has
+     *     permission to write to the file, </td>
+     * </tr>
+     * <tr>
+     *   <td> {@link AccessMode#EXECUTE EXECUTE} </td>
+     *   <td> Checks that the file exists and that the Java virtual machine has
+     *     permission to {@link Runtime#exec execute} the file. The semantics
+     *     may differ when checking access to a directory. For example, on UNIX
+     *     systems, checking for {@code EXECUTE} access checks that the Java
+     *     virtual machine has permission to search the directory in order to
+     *     access file or subdirectories. </td>
+     * </tr>
+     * </table>
+     *
+     * <p> If the {@code modes} parameter is of length zero, then the existence
+     * of the file is checked.
+     *
+     * <p> This method follows symbolic links if the file referenced by this
+     * object is a symbolic link. Depending on the implementation, this method
+     * may require to read file permissions, access control lists, or other
+     * file attributes in order to check the effective access to the file. To
+     * determine the effective access to a file may require access to several
+     * attributes and so in some implementations this method may not be atomic
+     * with respect to other file system operations.
+     *
+     * @param   path
+     *          the path to the file to check
+     * @param   modes
+     *          The access modes to check; may have zero elements
+     *
+     * @throws  UnsupportedOperationException
+     *          an implementation is required to support checking for
+     *          {@code READ}, {@code WRITE}, and {@code EXECUTE} access. This
+     *          exception is specified to allow for the {@code Access} enum to
+     *          be extended in future releases.
+     * @throws  NoSuchFileException
+     *          if a file does not exist <i>(optional specific exception)</i>
+     * @throws  AccessDeniedException
+     *          the requested access would be denied or the access cannot be
+     *          determined because the Java virtual machine has insufficient
+     *          privileges or other reasons. <i>(optional specific exception)</i>
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, the {@link SecurityManager#checkRead(String) checkRead}
+     *          is invoked when checking read access to the file or only the
+     *          existence of the file, the {@link SecurityManager#checkWrite(String)
+     *          checkWrite} is invoked when checking write access to the file,
+     *          and {@link SecurityManager#checkExec(String) checkExec} is invoked
+     *          when checking execute access.
+     */
+    public abstract void checkAccess(Path path, AccessMode... modes)
+        throws IOException;
+
+    /**
+     * Returns a file attribute view of a given type. This method works in
+     * exactly the manner specified by the {@link Files#getFileAttributeView}
+     * method.
+     *
+     * @param   <V>
+     *          The {@code FileAttributeView} type
+     * @param   path
+     *          the path to the file
+     * @param   type
+     *          the {@code Class} object corresponding to the file attribute view
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a file attribute view of the specified type, or {@code null} if
+     *          the attribute view type is not available
+     */
+    public abstract <V extends FileAttributeView> V
+        getFileAttributeView(Path path, Class<V> type, LinkOption... options);
+
+    /**
+     * Reads a file's attributes as a bulk operation. This method works in
+     * exactly the manner specified by the {@link
+     * Files#readAttributes(Path,Class,LinkOption[])} method.
+     *
+     * @param   <A>
+     *          The {@code BasicFileAttributes} type
+     * @param   path
+     *          the path to the file
+     * @param   type
+     *          the {@code Class} of the file attributes required
+     *          to read
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  the file attributes
+     *
+     * @throws  UnsupportedOperationException
+     *          if an attributes of the given type are not supported
+     * @throws  IOException
+     *          if an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method is invoked to check read access to the file
+     */
+    public abstract <A extends BasicFileAttributes> A
+        readAttributes(Path path, Class<A> type, LinkOption... options) throws IOException;
+
+    /**
+     * Reads a set of file attributes as a bulk operation. This method works in
+     * exactly the manner specified by the {@link
+     * Files#readAttributes(Path,String,LinkOption[])} method.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   attributes
+     *          the attributes to read
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @return  a map of the attributes returned; may be empty. The map's keys
+     *          are the attribute names, its values are the attribute values
+     *
+     * @throws  UnsupportedOperationException
+     *          if the attribute view is not available
+     * @throws  IllegalArgumentException
+     *          if no attributes are specified or an unrecognized attributes is
+     *          specified
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkRead(String) checkRead}
+     *          method denies read access to the file. If this method is invoked
+     *          to read security sensitive attributes then the security manager
+     *          may be invoke to check for additional permissions.
+     */
+    public abstract Map<String,Object> readAttributes(Path path, String attributes,
+                                                      LinkOption... options)
+        throws IOException;
+
+    /**
+     * Sets the value of a file attribute. This method works in exactly the
+     * manner specified by the {@link Files#setAttribute} method.
+     *
+     * @param   path
+     *          the path to the file
+     * @param   attribute
+     *          the attribute to set
+     * @param   value
+     *          the attribute value
+     * @param   options
+     *          options indicating how symbolic links are handled
+     *
+     * @throws  UnsupportedOperationException
+     *          if the attribute view is not available
+     * @throws  IllegalArgumentException
+     *          if the attribute name is not specified, or is not recognized, or
+     *          the attribute value is of the correct type but has an
+     *          inappropriate value
+     * @throws  ClassCastException
+     *          If the attribute value is not of the expected type or is a
+     *          collection containing elements that are not of the expected
+     *          type
+     * @throws  IOException
+     *          If an I/O error occurs
+     * @throws  SecurityException
+     *          In the case of the default provider, and a security manager is
+     *          installed, its {@link SecurityManager#checkWrite(String) checkWrite}
+     *          method denies write access to the file. If this method is invoked
+     *          to set security sensitive attributes then the security manager
+     *          may be invoked to check for additional permissions.
+     */
+    public abstract void setAttribute(Path path, String attribute,
+                                      Object value, LinkOption... options)
+        throws IOException;
+}
diff --git a/java/nio/file/spi/FileTypeDetector.java b/java/nio/file/spi/FileTypeDetector.java
new file mode 100644
index 0000000..ee118d6
--- /dev/null
+++ b/java/nio/file/spi/FileTypeDetector.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.nio.file.spi;
+
+import java.nio.file.Path;
+import java.io.IOException;
+
+/**
+ * A file type detector for probing a file to guess its file type.
+ *
+ * <p> A file type detector is a concrete implementation of this class, has a
+ * zero-argument constructor, and implements the abstract methods specified
+ * below.
+ *
+ * <p> The means by which a file type detector determines the file type is
+ * highly implementation specific. A simple implementation might examine the
+ * <em>file extension</em> (a convention used in some platforms) and map it to
+ * a file type. In other cases, the file type may be stored as a file <a
+ * href="../attribute/package-summary.html"> attribute</a> or the bytes in a
+ * file may be examined to guess its file type.
+ *
+ * @see java.nio.file.Files#probeContentType(Path)
+ *
+ * @since 1.7
+ */
+
+public abstract class FileTypeDetector {
+
+    private static Void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(new RuntimePermission("fileTypeDetector"));
+        return null;
+    }
+    private FileTypeDetector(Void ignore) { }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it denies
+     *          {@link RuntimePermission}<tt>("fileTypeDetector")</tt>
+     */
+    protected FileTypeDetector() {
+        this(checkPermission());
+    }
+
+    /**
+     * Probes the given file to guess its content type.
+     *
+     * <p> The means by which this method determines the file type is highly
+     * implementation specific. It may simply examine the file name, it may use
+     * a file <a href="../attribute/package-summary.html">attribute</a>,
+     * or it may examines bytes in the file.
+     *
+     * <p> The probe result is the string form of the value of a
+     * Multipurpose Internet Mail Extension (MIME) content type as
+     * defined by <a href="http://www.ietf.org/rfc/rfc2045.txt"><i>RFC&nbsp;2045:
+     * Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet
+     * Message Bodies</i></a>. The string must be parsable according to the
+     * grammar in the RFC 2045.
+     *
+     * @param   path
+     *          the path to the file to probe
+     *
+     * @return  The content type or {@code null} if the file type is not
+     *          recognized
+     *
+     * @throws  IOException
+     *          An I/O error occurs
+     * @throws  SecurityException
+     *          If the implementation requires to access the file, and a
+     *          security manager is installed, and it denies an unspecified
+     *          permission required by a file system provider implementation.
+     *          If the file reference is associated with the default file system
+     *          provider then the {@link SecurityManager#checkRead(String)} method
+     *          is invoked to check read access to the file.
+     *
+     * @see java.nio.file.Files#probeContentType
+     */
+    public abstract String probeContentType(Path path)
+        throws IOException;
+}
diff --git a/java/nio/package-info.java b/java/nio/package-info.java
new file mode 100644
index 0000000..b466dc4
--- /dev/null
+++ b/java/nio/package-info.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Defines buffers, which are containers for data, and provides an overview of the
+ * other NIO packages.
+ *
+ *
+ * <p> The central abstractions of the NIO APIs are: </p>
+ *
+ * <ul>
+ *
+ *   <li><p> <a href="#buffers"><i>Buffers</i></a>, which are containers for data;
+ *   </p></li>
+ *
+ *   <li><p> <a href="charset/package-summary.html"><i>Charsets</i></a> and their
+ *   associated <i>decoders</i> and <i>encoders</i>, <br> which translate between
+ *   bytes and Unicode characters; </p></li>
+ *
+ *   <li><p> <a href="channels/package-summary.html"><i>Channels</i></a> of
+ *   various types, which represent connections <br> to entities capable of
+ *   performing I/O operations; and </p></li>
+ *
+ *   <li><p> <i>Selectors</i> and <i>selection keys</i>, which together with <br>
+ *   <i>selectable channels</i> define a <a
+ *   href="channels/package-summary.html#multiplex">multiplexed, non-blocking <br>
+ *   I/O</a>&nbsp;facility.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> The <tt>java.nio</tt> package defines the buffer classes, which are used
+ * throughout the NIO APIs.  The charset API is defined in the {@link
+ * java.nio.charset} package, and the channel and selector APIs are defined in the
+ * {@link java.nio.channels} package.  Each of these subpackages has its own
+ * service-provider (SPI) subpackage, the contents of which can be used to extend
+ * the platform's default implementations or to construct alternative
+ * implementations.
+ *
+ *
+ * <a name="buffers">
+ *
+ * <blockquote><table cellspacing=1 cellpadding=0 summary="Description of the various buffers">
+ *   <tr><th><p align="left">Buffers</p></th><th><p align="left">Description</p></th></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.Buffer}</tt></td>
+ *       <td>Position, limit, and capacity;
+ *           <br>clear, flip, rewind, and mark/reset</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.ByteBuffer}</tt></td>
+ *       <td>Get/put, compact, views; allocate,&nbsp;wrap</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;{@link java.nio.MappedByteBuffer}&nbsp;&nbsp;</tt></td>
+ *       <td>A byte buffer mapped to a file</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.CharBuffer}</tt></td>
+ *       <td>Get/put, compact; allocate,&nbsp;wrap</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.DoubleBuffer}</tt></td>
+ *       <td>&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;'</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.FloatBuffer}</tt></td>
+ *       <td>&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;'</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.IntBuffer}</tt></td>
+ *       <td>&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;'</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.LongBuffer}</tt></td>
+ *       <td>&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;'</td></tr>
+ *   <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.ShortBuffer}</tt></td>
+ *       <td>&nbsp;&nbsp;&nbsp;&nbsp;'&nbsp;'</td></tr>
+ *   <tr><td valign=top><tt>{@link java.nio.ByteOrder}</tt></td>
+ *       <td>Typesafe enumeration for&nbsp;byte&nbsp;orders</td></tr>
+ * </table></blockquote>
+ *
+ * <p> A <i>buffer</i> is a container for a fixed amount of data of a specific
+ * primitive type.  In addition to its content a buffer has a <i>position</i>,
+ * which is the index of the next element to be read or written, and a
+ * <i>limit</i>, which is the index of the first element that should not be read
+ * or written.  The base {@link java.nio.Buffer} class defines these properties as
+ * well as methods for <i>clearing</i>, <i>flipping</i>, and <i>rewinding</i>, for
+ * <i>marking</i> the current position, and for <i>resetting</i> the position to
+ * the previous mark.
+ *
+ * <p> There is a buffer class for each non-boolean primitive type.  Each class
+ * defines a family of <i>get</i> and <i>put</i> methods for moving data out of
+ * and in to a buffer, methods for <i>compacting</i>, <i>duplicating</i>, and
+ * <i>slicing</i> a buffer, and static methods for <i>allocating</i> a new buffer
+ * as well as for <i>wrapping</i> an existing array into a buffer.
+ *
+ * <p> Byte buffers are distinguished in that they can be used as the sources and
+ * targets of I/O operations.  They also support several features not found in the
+ * other buffer classes:
+ *
+ * <ul>
+ *
+ *   <li><p> A byte buffer can be allocated as a <a href="ByteBuffer.html#direct">
+ *   <i>direct</i></a> buffer, in which case the Java virtual machine will make a
+ *   best effort to perform native I/O operations directly upon it.  </p></li>
+ *
+ *   <li><p> A byte buffer can be created by {@link
+ *   java.nio.channels.FileChannel#map </code><i>mapping</i><code>} a region of a
+ *   file directly into memory, in which case a few additional file-related
+ *   operations defined in the {@link java.nio.MappedByteBuffer} class are
+ *   available.  </p></li>
+ *
+ *   <li><p> A byte buffer provides access to its content as either a heterogeneous
+ *   or homogeneous sequence of <a href="ByteBuffer.html#bin">binary data</i></a>
+ *   of any non-boolean primitive type, in either big-endian or little-endian <a
+ *   href="ByteOrder.html">byte order</a>.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in any class or interface in this package will cause a {@link
+ * java.lang.NullPointerException NullPointerException} to be thrown.
+ *
+ * @since 1.4
+ * @author Mark Reinhold
+ * @author JSR-51 Expert Group
+ */
+
+package java.nio;
diff --git a/java/security/AccessControlContext.java b/java/security/AccessControlContext.java
new file mode 100644
index 0000000..506898f
--- /dev/null
+++ b/java/security/AccessControlContext.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public final class AccessControlContext {
+    public AccessControlContext(ProtectionDomain context[]) {
+    }
+
+    public AccessControlContext(AccessControlContext acc,
+                                DomainCombiner combiner) {
+    }
+
+
+    public DomainCombiner getDomainCombiner() {
+      return null;
+    }
+
+    public void checkPermission(Permission perm)
+        throws AccessControlException {
+    }
+
+}
diff --git a/java/security/AccessControlException.java b/java/security/AccessControlException.java
new file mode 100644
index 0000000..a4f2a78
--- /dev/null
+++ b/java/security/AccessControlException.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * <p> This exception is thrown by the AccessController to indicate
+ * that a requested access (to a critical system resource such as the
+ * file system or the network) is denied.
+ *
+ * <p> The reason to deny access can vary.  For example, the requested
+ * permission might be of an incorrect type,  contain an invalid
+ * value, or request access that is not allowed according to the
+ * security policy.  Such information should be given whenever
+ * possible at the time the exception is thrown.
+ *
+ * @author Li Gong
+ * @author Roland Schemers
+ */
+
+public class AccessControlException extends SecurityException {
+
+    private static final long serialVersionUID = 5138225684096988535L;
+
+    // the permission that caused the exception to be thrown.
+    private Permission perm;
+
+    /**
+     * Constructs an {@code AccessControlException} with the
+     * specified, detailed message.
+     *
+     * @param   s   the detail message.
+     */
+    public AccessControlException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs an {@code AccessControlException} with the
+     * specified, detailed message, and the requested permission that caused
+     * the exception.
+     *
+     * @param   s   the detail message.
+     * @param   p   the permission that caused the exception.
+     */
+    public AccessControlException(String s, Permission p) {
+        super(s);
+        perm = p;
+    }
+
+    /**
+     * Gets the Permission object associated with this exception, or
+     * null if there was no corresponding Permission object.
+     *
+     * @return the Permission object.
+     */
+    public Permission getPermission() {
+        return perm;
+    }
+}
diff --git a/java/security/AccessController.java b/java/security/AccessController.java
new file mode 100644
index 0000000..ad844ba
--- /dev/null
+++ b/java/security/AccessController.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public final class AccessController {
+
+    private AccessController() { }
+
+    /**
+     * Calls {@code action.run()}.
+     */
+    public static <T> T doPrivileged(PrivilegedAction<T> action) {
+        return action.run();
+    }
+
+    /**
+     * Calls {@code action.run()}.
+     */
+    public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
+        return action.run();
+    }
+
+
+    /**
+     * Calls {@code action.run()}.
+     */
+    public static <T> T doPrivileged(PrivilegedAction<T> action,
+                                     AccessControlContext context) {
+        return action.run();
+    }
+
+    /**
+     * Calls {@code action.run()}.
+     */
+    public static <T> T
+        doPrivileged(PrivilegedExceptionAction<T> action)
+        throws PrivilegedActionException {
+        try {
+            return action.run();
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new PrivilegedActionException(e);
+        }
+    }
+
+
+    /**
+     * Calls {@code action.run()}.
+     */
+    public static <T> T doPrivilegedWithCombiner
+        (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
+        return doPrivileged(action);
+    }
+
+
+    /**
+     * Calls {@code action.run()}.
+     */
+    public static <T> T
+        doPrivileged(PrivilegedExceptionAction<T> action,
+                     AccessControlContext context)
+        throws PrivilegedActionException {
+        return doPrivileged(action);
+    }
+
+    public static AccessControlContext getContext() {
+        return new AccessControlContext(null);
+    }
+
+    public static void checkPermission(Permission perm)
+                 throws AccessControlException {
+    }
+}
diff --git a/java/security/AlgorithmConstraints.java b/java/security/AlgorithmConstraints.java
new file mode 100644
index 0000000..7341603
--- /dev/null
+++ b/java/security/AlgorithmConstraints.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.Set;
+
+/**
+ * This interface specifies constraints for cryptographic algorithms,
+ * keys (key sizes), and other algorithm parameters.
+ * <p>
+ * {@code AlgorithmConstraints} objects are immutable.  An implementation
+ * of this interface should not provide methods that can change the state
+ * of an instance once it has been created.
+ * <p>
+ * Note that {@code AlgorithmConstraints} can be used to represent the
+ * restrictions described by the security properties
+ * {@code jdk.certpath.disabledAlgorithms} and
+ * {@code jdk.tls.disabledAlgorithms}, or could be used by a
+ * concrete {@code PKIXCertPathChecker} to check whether a specified
+ * certificate in the certification path contains the required algorithm
+ * constraints.
+ *
+ * @see javax.net.ssl.SSLParameters#getAlgorithmConstraints
+ * @see javax.net.ssl.SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ *
+ * @since 1.7
+ */
+
+public interface AlgorithmConstraints {
+
+    /**
+     * Determines whether an algorithm is granted permission for the
+     * specified cryptographic primitives.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param algorithm the algorithm name
+     * @param parameters the algorithm parameters, or null if no additional
+     *     parameters
+     *
+     * @return true if the algorithm is permitted and can be used for all
+     *     of the specified cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives or algorithm is null
+     *     or empty
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, AlgorithmParameters parameters);
+
+    /**
+     * Determines whether a key is granted permission for the specified
+     * cryptographic primitives.
+     * <p>
+     * This method is usually used to check key size and key usage.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param key the key
+     *
+     * @return true if the key can be used for all of the specified
+     *     cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives is null or empty,
+     *     or the key is null
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives, Key key);
+
+    /**
+     * Determines whether an algorithm and the corresponding key are granted
+     * permission for the specified cryptographic primitives.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param algorithm the algorithm name
+     * @param key the key
+     * @param parameters the algorithm parameters, or null if no additional
+     *     parameters
+     *
+     * @return true if the key and the algorithm can be used for all of the
+     *     specified cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives or algorithm is null
+     *     or empty, or the key is null
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives,
+                String algorithm, Key key, AlgorithmParameters parameters);
+
+}
diff --git a/java/security/AlgorithmParameterGenerator.java b/java/security/AlgorithmParameterGenerator.java
new file mode 100644
index 0000000..7222b44
--- /dev/null
+++ b/java/security/AlgorithmParameterGenerator.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * The {@code AlgorithmParameterGenerator} class is used to generate a
+ * set of
+ * parameters to be used with a certain algorithm. Parameter generators
+ * are constructed using the {@code getInstance} factory methods
+ * (static methods that return instances of a given class).
+ *
+ * <P>The object that will generate the parameters can be initialized
+ * in two different ways: in an algorithm-independent manner, or in an
+ * algorithm-specific manner:
+ *
+ * <ul>
+ * <li>The algorithm-independent approach uses the fact that all parameter
+ * generators share the concept of a "size" and a
+ * source of randomness. The measure of size is universally shared
+ * by all algorithm parameters, though it is interpreted differently
+ * for different algorithms. For example, in the case of parameters for
+ * the <i>DSA</i> algorithm, "size" corresponds to the size
+ * of the prime modulus (in bits).
+ * When using this approach, algorithm-specific parameter generation
+ * values - if any - default to some standard values, unless they can be
+ * derived from the specified size.
+ *
+ * <li>The other approach initializes a parameter generator object
+ * using algorithm-specific semantics, which are represented by a set of
+ * algorithm-specific parameter generation values. To generate
+ * Diffie-Hellman system parameters, for example, the parameter generation
+ * values usually
+ * consist of the size of the prime modulus and the size of the
+ * random exponent, both specified in number of bits.
+ * </ul>
+ *
+ * <P>In case the client does not explicitly initialize the
+ * AlgorithmParameterGenerator
+ * (via a call to an {@code init} method), each provider must supply (and
+ * document) a default initialization. For example, the Sun provider uses a
+ * default modulus prime size of 1024 bits for the generation of DSA
+ * parameters.
+ *
+ * <p> Android provides the following <code>AlgorithmParameterGenerator</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr class="deprecated">
+ *       <td>AES</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DES</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DESede</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DH</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+ * AlgorithmParameterGenerator section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see AlgorithmParameters
+ * @see java.security.spec.AlgorithmParameterSpec
+ *
+ * @since 1.2
+ */
+
+public class AlgorithmParameterGenerator {
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private AlgorithmParameterGeneratorSpi paramGenSpi;
+
+    // The algorithm
+    private String algorithm;
+
+    /**
+     * Creates an AlgorithmParameterGenerator object.
+     *
+     * @param paramGenSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected AlgorithmParameterGenerator
+    (AlgorithmParameterGeneratorSpi paramGenSpi, Provider provider,
+     String algorithm) {
+        this.paramGenSpi = paramGenSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns the standard name of the algorithm this parameter
+     * generator is associated with.
+     *
+     * @return the string name of the algorithm.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns an AlgorithmParameterGenerator object for generating
+     * a set of parameters to be used with the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new AlgorithmParameterGenerator object encapsulating the
+     * AlgorithmParameterGeneratorSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the algorithm this
+     * parameter generator is associated with.
+     * See the AlgorithmParameterGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new AlgorithmParameterGenerator object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports an
+     *          AlgorithmParameterGeneratorSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     */
+    public static AlgorithmParameterGenerator getInstance(String algorithm)
+        throws NoSuchAlgorithmException {
+            try {
+                Object[] objs = Security.getImpl(algorithm,
+                                                 "AlgorithmParameterGenerator",
+                                                 (String)null);
+                return new AlgorithmParameterGenerator
+                    ((AlgorithmParameterGeneratorSpi)objs[0],
+                     (Provider)objs[1],
+                     algorithm);
+            } catch(NoSuchProviderException e) {
+                throw new NoSuchAlgorithmException(algorithm + " not found");
+            }
+    }
+
+    /**
+     * Returns an AlgorithmParameterGenerator object for generating
+     * a set of parameters to be used with the specified algorithm.
+     *
+     * <p> A new AlgorithmParameterGenerator object encapsulating the
+     * AlgorithmParameterGeneratorSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the algorithm this
+     * parameter generator is associated with.
+     * See the AlgorithmParameterGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the string name of the Provider.
+     *
+     * @return the new AlgorithmParameterGenerator object.
+     *
+     * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static AlgorithmParameterGenerator getInstance(String algorithm,
+                                                          String provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        if (provider == null || provider.length() == 0)
+            throw new IllegalArgumentException("missing provider");
+        Object[] objs = Security.getImpl(algorithm,
+                                         "AlgorithmParameterGenerator",
+                                         provider);
+        return new AlgorithmParameterGenerator
+            ((AlgorithmParameterGeneratorSpi)objs[0], (Provider)objs[1],
+             algorithm);
+    }
+
+    /**
+     * Returns an AlgorithmParameterGenerator object for generating
+     * a set of parameters to be used with the specified algorithm.
+     *
+     * <p> A new AlgorithmParameterGenerator object encapsulating the
+     * AlgorithmParameterGeneratorSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the string name of the algorithm this
+     * parameter generator is associated with.
+     * See the AlgorithmParameterGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the Provider object.
+     *
+     * @return the new AlgorithmParameterGenerator object.
+     *
+     * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the specified provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static AlgorithmParameterGenerator getInstance(String algorithm,
+                                                          Provider provider)
+        throws NoSuchAlgorithmException
+    {
+        if (provider == null)
+            throw new IllegalArgumentException("missing provider");
+        Object[] objs = Security.getImpl(algorithm,
+                                         "AlgorithmParameterGenerator",
+                                         provider);
+        return new AlgorithmParameterGenerator
+            ((AlgorithmParameterGeneratorSpi)objs[0], (Provider)objs[1],
+             algorithm);
+    }
+
+    /**
+     * Returns the provider of this algorithm parameter generator object.
+     *
+     * @return the provider of this algorithm parameter generator object
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Initializes this parameter generator for a certain size.
+     * To create the parameters, the {@code SecureRandom}
+     * implementation of the highest-priority installed provider is used as
+     * the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * {@code SecureRandom}, a system-provided source of randomness is
+     * used.)
+     *
+     * @param size the size (number of bits).
+     */
+    public final void init(int size) {
+        paramGenSpi.engineInit(size, new SecureRandom());
+    }
+
+    /**
+     * Initializes this parameter generator for a certain size and source
+     * of randomness.
+     *
+     * @param size the size (number of bits).
+     * @param random the source of randomness.
+     */
+    public final void init(int size, SecureRandom random) {
+        paramGenSpi.engineInit(size, random);
+    }
+
+    /**
+     * Initializes this parameter generator with a set of algorithm-specific
+     * parameter generation values.
+     * To generate the parameters, the {@code SecureRandom}
+     * implementation of the highest-priority installed provider is used as
+     * the source of randomness.
+     * (If none of the installed providers supply an implementation of
+     * {@code SecureRandom}, a system-provided source of randomness is
+     * used.)
+     *
+     * @param genParamSpec the set of algorithm-specific parameter generation values.
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameter
+     * generation values are inappropriate for this parameter generator.
+     */
+    public final void init(AlgorithmParameterSpec genParamSpec)
+        throws InvalidAlgorithmParameterException {
+            paramGenSpi.engineInit(genParamSpec, new SecureRandom());
+    }
+
+    /**
+     * Initializes this parameter generator with a set of algorithm-specific
+     * parameter generation values.
+     *
+     * @param genParamSpec the set of algorithm-specific parameter generation values.
+     * @param random the source of randomness.
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameter
+     * generation values are inappropriate for this parameter generator.
+     */
+    public final void init(AlgorithmParameterSpec genParamSpec,
+                           SecureRandom random)
+        throws InvalidAlgorithmParameterException {
+            paramGenSpi.engineInit(genParamSpec, random);
+    }
+
+    /**
+     * Generates the parameters.
+     *
+     * @return the new AlgorithmParameters object.
+     */
+    public final AlgorithmParameters generateParameters() {
+        return paramGenSpi.engineGenerateParameters();
+    }
+}
diff --git a/java/security/AlgorithmParameterGeneratorSpi.java b/java/security/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..721fb52
--- /dev/null
+++ b/java/security/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code AlgorithmParameterGenerator} class, which
+ * is used to generate a set of parameters to be used with a certain algorithm.
+ *
+ * <p> All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a parameter generator for a particular algorithm.
+ *
+ * <p> In case the client does not explicitly initialize the
+ * AlgorithmParameterGenerator (via a call to an {@code engineInit}
+ * method), each provider must supply (and document) a default initialization.
+ * For example, the Sun provider uses a default modulus prime size of 1024
+ * bits for the generation of DSA parameters.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see AlgorithmParameterGenerator
+ * @see AlgorithmParameters
+ * @see java.security.spec.AlgorithmParameterSpec
+ *
+ * @since 1.2
+ */
+
+public abstract class AlgorithmParameterGeneratorSpi {
+
+    /**
+     * Initializes this parameter generator for a certain size
+     * and source of randomness.
+     *
+     * @param size the size (number of bits).
+     * @param random the source of randomness.
+     */
+    protected abstract void engineInit(int size, SecureRandom random);
+
+    /**
+     * Initializes this parameter generator with a set of
+     * algorithm-specific parameter generation values.
+     *
+     * @param genParamSpec the set of algorithm-specific parameter generation values.
+     * @param random the source of randomness.
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameter
+     * generation values are inappropriate for this parameter generator.
+     */
+    protected abstract void engineInit(AlgorithmParameterSpec genParamSpec,
+                                       SecureRandom random)
+        throws InvalidAlgorithmParameterException;
+
+    /**
+     * Generates the parameters.
+     *
+     * @return the new AlgorithmParameters object.
+     */
+    protected abstract AlgorithmParameters engineGenerateParameters();
+}
diff --git a/java/security/AlgorithmParameters.java b/java/security/AlgorithmParameters.java
new file mode 100644
index 0000000..fd1966f
--- /dev/null
+++ b/java/security/AlgorithmParameters.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import sun.security.jca.Providers;
+
+/**
+ * This class is used as an opaque representation of cryptographic parameters.
+ *
+ * <p>An {@code AlgorithmParameters} object for managing the parameters
+ * for a particular algorithm can be obtained by
+ * calling one of the {@code getInstance} factory methods
+ * (static methods that return instances of a given class).
+ *
+ * <p>Once an {@code AlgorithmParameters} object is obtained, it must be
+ * initialized via a call to {@code init}, using an appropriate parameter
+ * specification or parameter encoding.
+ *
+ * <p>A transparent parameter specification is obtained from an
+ * {@code AlgorithmParameters} object via a call to
+ * {@code getParameterSpec}, and a byte encoding of the parameters is
+ * obtained via a call to {@code getEncoded}.
+ *
+ * <p> Android provides the following <code>AlgorithmParameters</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>AES</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>BLOWFISH</td>
+ *       <td>10+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>ChaCha20</td>
+ *       <td>28+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DES</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DESede</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DH</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>EC</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>GCM</td>
+ *       <td>22+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>IES</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>OAEP</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA1AndAES_128</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA1AndAES_256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA224AndAES_128</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA224AndAES_256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA256AndAES_128</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA256AndAES_256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA384AndAES_128</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA384AndAES_256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA512AndAES_128</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PBEwithHmacSHA512AndAES_256</td>
+ *       <td>26+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PKCS12PBE</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PSS</td>
+ *       <td>1-8,24+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
+ * AlgorithmParameters section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.spec.AlgorithmParameterSpec
+ * @see java.security.spec.DSAParameterSpec
+ * @see KeyPairGenerator
+ *
+ * @since 1.2
+ */
+
+public class AlgorithmParameters {
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private AlgorithmParametersSpi paramSpi;
+
+    // The algorithm
+    private String algorithm;
+
+    // Has this object been initialized?
+    private boolean initialized = false;
+
+    /**
+     * Creates an AlgorithmParameters object.
+     *
+     * @param paramSpi the delegate
+     * @param provider the provider
+     * @param algorithm the algorithm
+     */
+    protected AlgorithmParameters(AlgorithmParametersSpi paramSpi,
+                                  Provider provider, String algorithm)
+    {
+        this.paramSpi = paramSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns the name of the algorithm associated with this parameter object.
+     *
+     * @return the algorithm name.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a parameter object for the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new AlgorithmParameters object encapsulating the
+     * AlgorithmParametersSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p> The returned parameter object must be initialized via a call to
+     * {@code init}, using an appropriate parameter specification or
+     * parameter encoding.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the AlgorithmParameters section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new parameter object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports an
+     *          AlgorithmParametersSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     */
+    public static AlgorithmParameters getInstance(String algorithm)
+    throws NoSuchAlgorithmException {
+        try {
+            Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters",
+                                             (String)null);
+            return new AlgorithmParameters((AlgorithmParametersSpi)objs[0],
+                                           (Provider)objs[1],
+                                           algorithm);
+        } catch(NoSuchProviderException e) {
+            throw new NoSuchAlgorithmException(algorithm + " not found");
+        }
+    }
+
+    /**
+     * Returns a parameter object for the specified algorithm.
+     *
+     * <p> A new AlgorithmParameters object encapsulating the
+     * AlgorithmParametersSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p>The returned parameter object must be initialized via a call to
+     * {@code init}, using an appropriate parameter specification or
+     * parameter encoding.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the AlgorithmParameters section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new parameter object.
+     *
+     * @exception NoSuchAlgorithmException if an AlgorithmParametersSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static AlgorithmParameters getInstance(String algorithm,
+                                                  String provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        if (provider == null || provider.length() == 0)
+            throw new IllegalArgumentException("missing provider");
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "AlgorithmParameters", algorithm);
+        Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters",
+                                         provider);
+        return new AlgorithmParameters((AlgorithmParametersSpi)objs[0],
+                                       (Provider)objs[1],
+                                       algorithm);
+    }
+
+    /**
+     * Returns a parameter object for the specified algorithm.
+     *
+     * <p> A new AlgorithmParameters object encapsulating the
+     * AlgorithmParametersSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * <p>The returned parameter object must be initialized via a call to
+     * {@code init}, using an appropriate parameter specification or
+     * parameter encoding.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the AlgorithmParameters section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#AlgorithmParameters">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new parameter object.
+     *
+     * @exception NoSuchAlgorithmException if an AlgorithmParameterGeneratorSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static AlgorithmParameters getInstance(String algorithm,
+                                                  Provider provider)
+        throws NoSuchAlgorithmException
+    {
+        if (provider == null)
+            throw new IllegalArgumentException("missing provider");
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "AlgorithmParameters", algorithm);
+        Object[] objs = Security.getImpl(algorithm, "AlgorithmParameters",
+                                         provider);
+        return new AlgorithmParameters((AlgorithmParametersSpi)objs[0],
+                                       (Provider)objs[1],
+                                       algorithm);
+    }
+
+    /**
+     * Returns the provider of this parameter object.
+     *
+     * @return the provider of this parameter object
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Initializes this parameter object using the parameters
+     * specified in {@code paramSpec}.
+     *
+     * @param paramSpec the parameter specification.
+     *
+     * @exception InvalidParameterSpecException if the given parameter
+     * specification is inappropriate for the initialization of this parameter
+     * object, or if this parameter object has already been initialized.
+     */
+    public final void init(AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (this.initialized)
+            throw new InvalidParameterSpecException("already initialized");
+        paramSpi.engineInit(paramSpec);
+        this.initialized = true;
+    }
+
+    /**
+     * Imports the specified parameters and decodes them according to the
+     * primary decoding format for parameters. The primary decoding
+     * format for parameters is ASN.1, if an ASN.1 specification for this type
+     * of parameters exists.
+     *
+     * @param params the encoded parameters.
+     *
+     * @exception IOException on decoding errors, or if this parameter object
+     * has already been initialized.
+     */
+    public final void init(byte[] params) throws IOException {
+        if (this.initialized)
+            throw new IOException("already initialized");
+        paramSpi.engineInit(params);
+        this.initialized = true;
+    }
+
+    /**
+     * Imports the parameters from {@code params} and decodes them
+     * according to the specified decoding scheme.
+     * If {@code format} is null, the
+     * primary decoding format for parameters is used. The primary decoding
+     * format is ASN.1, if an ASN.1 specification for these parameters
+     * exists.
+     *
+     * @param params the encoded parameters.
+     *
+     * @param format the name of the decoding scheme.
+     *
+     * @exception IOException on decoding errors, or if this parameter object
+     * has already been initialized.
+     */
+    public final void init(byte[] params, String format) throws IOException {
+        if (this.initialized)
+            throw new IOException("already initialized");
+        paramSpi.engineInit(params, format);
+        this.initialized = true;
+    }
+
+    /**
+     * Returns a (transparent) specification of this parameter object.
+     * {@code paramSpec} identifies the specification class in which
+     * the parameters should be returned. It could, for example, be
+     * {@code DSAParameterSpec.class}, to indicate that the
+     * parameters should be returned in an instance of the
+     * {@code DSAParameterSpec} class.
+     *
+     * @param <T> the type of the parameter specification to be returrned
+     * @param paramSpec the specification class in which
+     * the parameters should be returned.
+     *
+     * @return the parameter specification.
+     *
+     * @exception InvalidParameterSpecException if the requested parameter
+     * specification is inappropriate for this parameter object, or if this
+     * parameter object has not been initialized.
+     */
+    public final <T extends AlgorithmParameterSpec>
+        T getParameterSpec(Class<T> paramSpec)
+        throws InvalidParameterSpecException
+    {
+        if (this.initialized == false) {
+            throw new InvalidParameterSpecException("not initialized");
+        }
+        return paramSpi.engineGetParameterSpec(paramSpec);
+    }
+
+    /**
+     * Returns the parameters in their primary encoding format.
+     * The primary encoding format for parameters is ASN.1, if an ASN.1
+     * specification for this type of parameters exists.
+     *
+     * @return the parameters encoded using their primary encoding format.
+     *
+     * @exception IOException on encoding errors, or if this parameter object
+     * has not been initialized.
+     */
+    public final byte[] getEncoded() throws IOException
+    {
+        if (this.initialized == false) {
+            throw new IOException("not initialized");
+        }
+        return paramSpi.engineGetEncoded();
+    }
+
+    /**
+     * Returns the parameters encoded in the specified scheme.
+     * If {@code format} is null, the
+     * primary encoding format for parameters is used. The primary encoding
+     * format is ASN.1, if an ASN.1 specification for these parameters
+     * exists.
+     *
+     * @param format the name of the encoding format.
+     *
+     * @return the parameters encoded using the specified encoding scheme.
+     *
+     * @exception IOException on encoding errors, or if this parameter object
+     * has not been initialized.
+     */
+    public final byte[] getEncoded(String format) throws IOException
+    {
+        if (this.initialized == false) {
+            throw new IOException("not initialized");
+        }
+        return paramSpi.engineGetEncoded(format);
+    }
+
+    /**
+     * Returns a formatted string describing the parameters.
+     *
+     * @return a formatted string describing the parameters, or null if this
+     * parameter object has not been initialized.
+     */
+    public final String toString() {
+        if (this.initialized == false) {
+            return null;
+        }
+        return paramSpi.engineToString();
+    }
+}
diff --git a/java/security/AlgorithmParametersSpi.java b/java/security/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..282493b
--- /dev/null
+++ b/java/security/AlgorithmParametersSpi.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code AlgorithmParameters} class, which is used to manage
+ * algorithm parameters.
+ *
+ * <p> All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply parameter management
+ * for a particular algorithm.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see AlgorithmParameters
+ * @see java.security.spec.AlgorithmParameterSpec
+ * @see java.security.spec.DSAParameterSpec
+ *
+ * @since 1.2
+ */
+
+public abstract class AlgorithmParametersSpi {
+
+    /**
+     * Initializes this parameters object using the parameters
+     * specified in {@code paramSpec}.
+     *
+     * @param paramSpec the parameter specification.
+     *
+     * @exception InvalidParameterSpecException if the given parameter
+     * specification is inappropriate for the initialization of this parameter
+     * object.
+     */
+    protected abstract void engineInit(AlgorithmParameterSpec paramSpec)
+        throws InvalidParameterSpecException;
+
+    /**
+     * Imports the specified parameters and decodes them
+     * according to the primary decoding format for parameters.
+     * The primary decoding format for parameters is ASN.1, if an ASN.1
+     * specification for this type of parameters exists.
+     *
+     * @param params the encoded parameters.
+     *
+     * @exception IOException on decoding errors
+     */
+    protected abstract void engineInit(byte[] params)
+        throws IOException;
+
+    /**
+     * Imports the parameters from {@code params} and
+     * decodes them according to the specified decoding format.
+     * If {@code format} is null, the
+     * primary decoding format for parameters is used. The primary decoding
+     * format is ASN.1, if an ASN.1 specification for these parameters
+     * exists.
+     *
+     * @param params the encoded parameters.
+     *
+     * @param format the name of the decoding format.
+     *
+     * @exception IOException on decoding errors
+     */
+    protected abstract void engineInit(byte[] params, String format)
+        throws IOException;
+
+    /**
+     * Returns a (transparent) specification of this parameters
+     * object.
+     * {@code paramSpec} identifies the specification class in which
+     * the parameters should be returned. It could, for example, be
+     * {@code DSAParameterSpec.class}, to indicate that the
+     * parameters should be returned in an instance of the
+     * {@code DSAParameterSpec} class.
+     *
+     * @param <T> the type of the parameter specification to be returned
+     *
+     * @param paramSpec the specification class in which
+     * the parameters should be returned.
+     *
+     * @return the parameter specification.
+     *
+     * @exception InvalidParameterSpecException if the requested parameter
+     * specification is inappropriate for this parameter object.
+     */
+    protected abstract
+        <T extends AlgorithmParameterSpec>
+        T engineGetParameterSpec(Class<T> paramSpec)
+        throws InvalidParameterSpecException;
+
+    /**
+     * Returns the parameters in their primary encoding format.
+     * The primary encoding format for parameters is ASN.1, if an ASN.1
+     * specification for this type of parameters exists.
+     *
+     * @return the parameters encoded using their primary encoding format.
+     *
+     * @exception IOException on encoding errors.
+     */
+    protected abstract byte[] engineGetEncoded() throws IOException;
+
+    /**
+     * Returns the parameters encoded in the specified format.
+     * If {@code format} is null, the
+     * primary encoding format for parameters is used. The primary encoding
+     * format is ASN.1, if an ASN.1 specification for these parameters
+     * exists.
+     *
+     * @param format the name of the encoding format.
+     *
+     * @return the parameters encoded using the specified encoding scheme.
+     *
+     * @exception IOException on encoding errors.
+     */
+    protected abstract byte[] engineGetEncoded(String format)
+        throws IOException;
+
+    /**
+     * Returns a formatted string describing the parameters.
+     *
+     * @return a formatted string describing the parameters.
+     */
+    protected abstract String engineToString();
+}
diff --git a/java/security/AllPermission.java b/java/security/AllPermission.java
new file mode 100644
index 0000000..61bcaea
--- /dev/null
+++ b/java/security/AllPermission.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class AllPermission extends Permission {
+
+    public AllPermission() { super(""); }
+
+    public AllPermission(String name, String actions) { super(""); }
+
+    public boolean implies(Permission p) { return true; }
+
+    public String getActions() { return null; }
+}
diff --git a/java/security/AuthProvider.java b/java/security/AuthProvider.java
new file mode 100644
index 0000000..e87daa9
--- /dev/null
+++ b/java/security/AuthProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import javax.security.auth.callback.CallbackHandler;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public abstract class AuthProvider extends Provider {
+
+    protected AuthProvider(String name, double version, String info) {
+        super("", 0d, "");
+    }
+
+    public abstract void login(Subject subject, CallbackHandler handler)
+        throws LoginException;
+
+    public abstract void logout() throws LoginException;
+
+    public abstract void setCallbackHandler(CallbackHandler handler);
+}
diff --git a/java/security/BasicPermission.java b/java/security/BasicPermission.java
new file mode 100644
index 0000000..1836b10
--- /dev/null
+++ b/java/security/BasicPermission.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public abstract class BasicPermission extends Permission
+implements java.io.Serializable
+{
+
+    public BasicPermission(String name) { super(""); }
+
+    public BasicPermission(String name, String actions) { super(""); }
+
+    public boolean implies(Permission p) { return true; }
+
+    public String getActions()
+    {
+        return "";
+    }
+}
diff --git a/java/security/Certificate.java b/java/security/Certificate.java
new file mode 100644
index 0000000..489c6d6
--- /dev/null
+++ b/java/security/Certificate.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.util.Date;
+
+/**
+ * <p>This is an interface of abstract methods for managing a
+ * variety of identity certificates.
+ * An identity certificate is a guarantee by a principal that
+ * a public key is that of another principal.  (A principal represents
+ * an entity such as an individual user, a group, or a corporation.)
+ *
+ * <p>In particular, this interface is intended to be a common
+ * abstraction for constructs that have different formats but
+ * important common uses.  For example, different types of
+ * certificates, such as X.509 certificates and PGP certificates,
+ * share general certificate functionality (the need to encode and
+ * decode certificates) and some types of information, such as a
+ * public key, the principal whose key it is, and the guarantor
+ * guaranteeing that the public key is that of the specified
+ * principal. So an implementation of X.509 certificates and an
+ * implementation of PGP certificates can both utilize the Certificate
+ * interface, even though their formats and additional types and
+ * amounts of information stored are different.
+ *
+ * <p><b>Important</b>: This interface is useful for cataloging and
+ * grouping objects sharing certain common uses. It does not have any
+ * semantics of its own. In particular, a Certificate object does not
+ * make any statement as to the <i>validity</i> of the binding. It is
+ * the duty of the application implementing this interface to verify
+ * the certificate and satisfy itself of its validity.
+ *
+ * @author Benjamin Renaud
+ * @deprecated A new certificate handling package is created in the Java platform.
+ *             This Certificate interface is entirely deprecated and
+ *             is here to allow for a smooth transition to the new
+ *             package.
+ * @see java.security.cert.Certificate
+ */
+@Deprecated
+public interface Certificate {
+
+    /**
+     * Returns the guarantor of the certificate, that is, the principal
+     * guaranteeing that the public key associated with this certificate
+     * is that of the principal associated with this certificate. For X.509
+     * certificates, the guarantor will typically be a Certificate Authority
+     * (such as the United States Postal Service or Verisign, Inc.).
+     *
+     * @return the guarantor which guaranteed the principal-key
+     * binding.
+     */
+    public abstract Principal getGuarantor();
+
+    /**
+     * Returns the principal of the principal-key pair being guaranteed by
+     * the guarantor.
+     *
+     * @return the principal to which this certificate is bound.
+     */
+    public abstract Principal getPrincipal();
+
+    /**
+     * Returns the key of the principal-key pair being guaranteed by
+     * the guarantor.
+     *
+     * @return the public key that this certificate certifies belongs
+     * to a particular principal.
+     */
+    public abstract PublicKey getPublicKey();
+
+    /**
+     * Encodes the certificate to an output stream in a format that can
+     * be decoded by the {@code decode} method.
+     *
+     * @param stream the output stream to which to encode the
+     * certificate.
+     *
+     * @exception KeyException if the certificate is not
+     * properly initialized, or data is missing, etc.
+     *
+     * @exception IOException if a stream exception occurs while
+     * trying to output the encoded certificate to the output stream.
+     *
+     * @see #decode
+     * @see #getFormat
+     */
+    public abstract void encode(OutputStream stream)
+        throws KeyException, IOException;
+
+    /**
+     * Decodes a certificate from an input stream. The format should be
+     * that returned by {@code getFormat} and produced by
+     * {@code encode}.
+     *
+     * @param stream the input stream from which to fetch the data
+     * being decoded.
+     *
+     * @exception KeyException if the certificate is not properly initialized,
+     * or data is missing, etc.
+     *
+     * @exception IOException if an exception occurs while trying to input
+     * the encoded certificate from the input stream.
+     *
+     * @see #encode
+     * @see #getFormat
+     */
+    public abstract void decode(InputStream stream)
+        throws KeyException, IOException;
+
+
+    /**
+     * Returns the name of the coding format. This is used as a hint to find
+     * an appropriate parser. It could be "X.509", "PGP", etc. This is
+     * the format produced and understood by the {@code encode}
+     * and {@code decode} methods.
+     *
+     * @return the name of the coding format.
+     */
+    public abstract String getFormat();
+
+    /**
+     * Returns a string that represents the contents of the certificate.
+     *
+     * @param detailed whether or not to give detailed information
+     * about the certificate
+     *
+     * @return a string representing the contents of the certificate
+     */
+    public String toString(boolean detailed);
+}
diff --git a/java/security/CodeSigner.java b/java/security/CodeSigner.java
new file mode 100644
index 0000000..37c12b1
--- /dev/null
+++ b/java/security/CodeSigner.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.security.cert.CertPath;
+
+/**
+ * This class encapsulates information about a code signer.
+ * It is immutable.
+ *
+ * @since 1.5
+ * @author Vincent Ryan
+ */
+
+public final class CodeSigner implements Serializable {
+
+    private static final long serialVersionUID = 6819288105193937581L;
+
+    /**
+     * The signer's certificate path.
+     *
+     * @serial
+     */
+    private CertPath signerCertPath;
+
+    /*
+     * The signature timestamp.
+     *
+     * @serial
+     */
+    private Timestamp timestamp;
+
+    /*
+     * Hash code for this code signer.
+     */
+    private transient int myhash = -1;
+
+    /**
+     * Constructs a CodeSigner object.
+     *
+     * @param signerCertPath The signer's certificate path.
+     *                       It must not be {@code null}.
+     * @param timestamp A signature timestamp.
+     *                  If {@code null} then no timestamp was generated
+     *                  for the signature.
+     * @throws NullPointerException if {@code signerCertPath} is
+     *                              {@code null}.
+     */
+    public CodeSigner(CertPath signerCertPath, Timestamp timestamp) {
+        if (signerCertPath == null) {
+            throw new NullPointerException();
+        }
+        this.signerCertPath = signerCertPath;
+        this.timestamp = timestamp;
+    }
+
+    /**
+     * Returns the signer's certificate path.
+     *
+     * @return A certificate path.
+     */
+    public CertPath getSignerCertPath() {
+        return signerCertPath;
+    }
+
+    /**
+     * Returns the signature timestamp.
+     *
+     * @return The timestamp or {@code null} if none is present.
+     */
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+
+    /**
+     * Returns the hash code value for this code signer.
+     * The hash code is generated using the signer's certificate path and the
+     * timestamp, if present.
+     *
+     * @return a hash code value for this code signer.
+     */
+    public int hashCode() {
+        if (myhash == -1) {
+            if (timestamp == null) {
+                myhash = signerCertPath.hashCode();
+            } else {
+                myhash = signerCertPath.hashCode() + timestamp.hashCode();
+            }
+        }
+        return myhash;
+    }
+
+    /**
+     * Tests for equality between the specified object and this
+     * code signer. Two code signers are considered equal if their
+     * signer certificate paths are equal and if their timestamps are equal,
+     * if present in both.
+     *
+     * @param obj the object to test for equality with this object.
+     *
+     * @return true if the objects are considered equal, false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj == null || (!(obj instanceof CodeSigner))) {
+            return false;
+        }
+        CodeSigner that = (CodeSigner)obj;
+
+        if (this == that) {
+            return true;
+        }
+        Timestamp thatTimestamp = that.getTimestamp();
+        if (timestamp == null) {
+            if (thatTimestamp != null) {
+                return false;
+            }
+        } else {
+            if (thatTimestamp == null ||
+                (! timestamp.equals(thatTimestamp))) {
+                return false;
+            }
+        }
+        return signerCertPath.equals(that.getSignerCertPath());
+    }
+
+    /**
+     * Returns a string describing this code signer.
+     *
+     * @return A string comprising the signer's certificate and a timestamp,
+     *         if present.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("(");
+        sb.append("Signer: " + signerCertPath.getCertificates().get(0));
+        if (timestamp != null) {
+            sb.append("timestamp: " + timestamp);
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    // Explicitly reset hash code value to -1
+    private void readObject(ObjectInputStream ois)
+        throws IOException, ClassNotFoundException {
+     ois.defaultReadObject();
+     myhash = -1;
+    }
+}
diff --git a/java/security/CodeSource.java b/java/security/CodeSource.java
new file mode 100644
index 0000000..8e6653b
--- /dev/null
+++ b/java/security/CodeSource.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+
+import java.net.URL;
+import java.net.SocketPermission;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Hashtable;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.cert.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public class CodeSource implements java.io.Serializable {
+
+    /**
+     * The code location.
+     *
+     * @serial
+     */
+    private URL location;
+
+    public CodeSource(URL url, java.security.cert.Certificate certs[]) {
+        this.location = url;
+    }
+
+    public CodeSource(URL url, CodeSigner[] signers) {
+        this.location = url;
+    }
+
+    public final URL getLocation() {
+        /* since URL is practically immutable, returning itself is not
+           a security problem */
+        return this.location;
+    }
+
+    public final java.security.cert.Certificate[] getCertificates() { return null; }
+
+    public final CodeSigner[] getCodeSigners() { return null; }
+
+    public boolean implies(CodeSource codesource) { return true; }
+}
diff --git a/java/security/CryptoPrimitive.java b/java/security/CryptoPrimitive.java
new file mode 100644
index 0000000..158643b
--- /dev/null
+++ b/java/security/CryptoPrimitive.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * An enumeration of cryptographic primitives.
+ *
+ * @since 1.7
+ */
+public enum CryptoPrimitive {
+    /**
+     * Hash function
+     */
+    MESSAGE_DIGEST,
+
+    /**
+     * Cryptographic random number generator
+     */
+    SECURE_RANDOM,
+
+    /**
+     * Symmetric primitive: block cipher
+     */
+    BLOCK_CIPHER,
+
+    /**
+     * Symmetric primitive: stream cipher
+     */
+    STREAM_CIPHER,
+
+    /**
+     * Symmetric primitive: message authentication code
+     */
+    MAC,
+
+    /**
+     * Symmetric primitive: key wrap
+     */
+    KEY_WRAP,
+
+    /**
+     * Asymmetric primitive: public key encryption
+     */
+    PUBLIC_KEY_ENCRYPTION,
+
+    /**
+     * Asymmetric primitive: signature scheme
+     */
+    SIGNATURE,
+
+    /**
+     * Asymmetric primitive: key encapsulation mechanism
+     */
+    KEY_ENCAPSULATION,
+
+    /**
+     * Asymmetric primitive: key agreement and key distribution
+     */
+    KEY_AGREEMENT
+}
diff --git a/java/security/DigestException.java b/java/security/DigestException.java
new file mode 100644
index 0000000..2327c98
--- /dev/null
+++ b/java/security/DigestException.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This is the generic Message Digest exception.
+ *
+ * @author Benjamin Renaud
+ */
+public class DigestException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 5821450303093652515L;
+
+    /**
+     * Constructs a DigestException with no detail message.  (A
+     * detail message is a String that describes this particular
+     * exception.)
+     */
+    public DigestException() {
+        super();
+    }
+
+    /**
+     * Constructs a DigestException with the specified detail
+     * message.  (A detail message is a String that describes this
+     * particular exception.)
+     *
+     * @param msg the detail message.
+     */
+   public DigestException(String msg) {
+       super(msg);
+    }
+
+    /**
+     * Creates a {@code DigestException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public DigestException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code DigestException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public DigestException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/DigestInputStream.java b/java/security/DigestInputStream.java
new file mode 100644
index 0000000..a1bf55a
--- /dev/null
+++ b/java/security/DigestInputStream.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.FilterInputStream;
+import java.io.PrintStream;
+import java.io.ByteArrayInputStream;
+
+/**
+ * A transparent stream that updates the associated message digest using
+ * the bits going through the stream.
+ *
+ * <p>To complete the message digest computation, call one of the
+ * {@code digest} methods on the associated message
+ * digest after your calls to one of this digest input stream's
+ * {@link #read() read} methods.
+ *
+ * <p>It is possible to turn this stream on or off (see
+ * {@link #on(boolean) on}). When it is on, a call to one of the
+ * {@code read} methods
+ * results in an update on the message digest.  But when it is off,
+ * the message digest is not updated. The default is for the stream
+ * to be on.
+ *
+ * <p>Note that digest objects can compute only one digest (see
+ * {@link MessageDigest}),
+ * so that in order to compute intermediate digests, a caller should
+ * retain a handle onto the digest object, and clone it for each
+ * digest to be computed, leaving the orginal digest untouched.
+ *
+ * @see MessageDigest
+ *
+ * @see DigestOutputStream
+ *
+ * @author Benjamin Renaud
+ */
+
+public class DigestInputStream extends FilterInputStream {
+
+    /* NOTE: This should be made a generic UpdaterInputStream */
+
+    /* Are we on or off? */
+    private boolean on = true;
+
+    /**
+     * The message digest associated with this stream.
+     */
+    protected MessageDigest digest;
+
+    /**
+     * Creates a digest input stream, using the specified input stream
+     * and message digest.
+     *
+     * @param stream the input stream.
+     *
+     * @param digest the message digest to associate with this stream.
+     */
+    public DigestInputStream(InputStream stream, MessageDigest digest) {
+        super(stream);
+        setMessageDigest(digest);
+    }
+
+    /**
+     * Returns the message digest associated with this stream.
+     *
+     * @return the message digest associated with this stream.
+     * @see #setMessageDigest(java.security.MessageDigest)
+     */
+    public MessageDigest getMessageDigest() {
+        return digest;
+    }
+
+    /**
+     * Associates the specified message digest with this stream.
+     *
+     * @param digest the message digest to be associated with this stream.
+     * @see #getMessageDigest()
+     */
+    public void setMessageDigest(MessageDigest digest) {
+        this.digest = digest;
+    }
+
+    /**
+     * Reads a byte, and updates the message digest (if the digest
+     * function is on).  That is, this method reads a byte from the
+     * input stream, blocking until the byte is actually read. If the
+     * digest function is on (see {@link #on(boolean) on}), this method
+     * will then call {@code update} on the message digest associated
+     * with this stream, passing it the byte read.
+     *
+     * @return the byte read.
+     *
+     * @exception IOException if an I/O error occurs.
+     *
+     * @see MessageDigest#update(byte)
+     */
+    public int read() throws IOException {
+        int ch = in.read();
+        if (on && ch != -1) {
+            digest.update((byte)ch);
+        }
+        return ch;
+    }
+
+    /**
+     * Reads into a byte array, and updates the message digest (if the
+     * digest function is on).  That is, this method reads up to
+     * {@code len} bytes from the input stream into the array
+     * {@code b}, starting at offset {@code off}. This method
+     * blocks until the data is actually
+     * read. If the digest function is on (see
+     * {@link #on(boolean) on}), this method will then call {@code update}
+     * on the message digest associated with this stream, passing it
+     * the data.
+     *
+     * @param b the array into which the data is read.
+     *
+     * @param off the starting offset into {@code b} of where the
+     * data should be placed.
+     *
+     * @param len the maximum number of bytes to be read from the input
+     * stream into b, starting at offset {@code off}.
+     *
+     * @return  the actual number of bytes read. This is less than
+     * {@code len} if the end of the stream is reached prior to
+     * reading {@code len} bytes. -1 is returned if no bytes were
+     * read because the end of the stream had already been reached when
+     * the call was made.
+     *
+     * @exception IOException if an I/O error occurs.
+     *
+     * @see MessageDigest#update(byte[], int, int)
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        int result = in.read(b, off, len);
+        if (on && result != -1) {
+            digest.update(b, off, result);
+        }
+        return result;
+    }
+
+    /**
+     * Turns the digest function on or off. The default is on.  When
+     * it is on, a call to one of the {@code read} methods results in an
+     * update on the message digest.  But when it is off, the message
+     * digest is not updated.
+     *
+     * @param on true to turn the digest function on, false to turn
+     * it off.
+     */
+    public void on(boolean on) {
+        this.on = on;
+    }
+
+    /**
+     * Prints a string representation of this digest input stream and
+     * its associated message digest object.
+     */
+     public String toString() {
+         return "[Digest Input Stream] " + digest.toString();
+     }
+}
diff --git a/java/security/DigestOutputStream.java b/java/security/DigestOutputStream.java
new file mode 100644
index 0000000..619faec
--- /dev/null
+++ b/java/security/DigestOutputStream.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.OutputStream;
+import java.io.FilterOutputStream;
+import java.io.PrintStream;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * A transparent stream that updates the associated message digest using
+ * the bits going through the stream.
+ *
+ * <p>To complete the message digest computation, call one of the
+ * {@code digest} methods on the associated message
+ * digest after your calls to one of this digest output stream's
+ * {@link #write(int) write} methods.
+ *
+ * <p>It is possible to turn this stream on or off (see
+ * {@link #on(boolean) on}). When it is on, a call to one of the
+ * {@code write} methods results in
+ * an update on the message digest.  But when it is off, the message
+ * digest is not updated. The default is for the stream to be on.
+ *
+ * @see MessageDigest
+ * @see DigestInputStream
+ *
+ * @author Benjamin Renaud
+ */
+public class DigestOutputStream extends FilterOutputStream {
+
+    private boolean on = true;
+
+    /**
+     * The message digest associated with this stream.
+     */
+    protected MessageDigest digest;
+
+    /**
+     * Creates a digest output stream, using the specified output stream
+     * and message digest.
+     *
+     * @param stream the output stream.
+     *
+     * @param digest the message digest to associate with this stream.
+     */
+    public DigestOutputStream(OutputStream stream, MessageDigest digest) {
+        super(stream);
+        setMessageDigest(digest);
+    }
+
+    /**
+     * Returns the message digest associated with this stream.
+     *
+     * @return the message digest associated with this stream.
+     * @see #setMessageDigest(java.security.MessageDigest)
+     */
+    public MessageDigest getMessageDigest() {
+        return digest;
+    }
+
+    /**
+     * Associates the specified message digest with this stream.
+     *
+     * @param digest the message digest to be associated with this stream.
+     * @see #getMessageDigest()
+     */
+    public void setMessageDigest(MessageDigest digest) {
+        this.digest = digest;
+    }
+
+    /**
+     * Updates the message digest (if the digest function is on) using
+     * the specified byte, and in any case writes the byte
+     * to the output stream. That is, if the digest function is on
+     * (see {@link #on(boolean) on}), this method calls
+     * {@code update} on the message digest associated with this
+     * stream, passing it the byte {@code b}. This method then
+     * writes the byte to the output stream, blocking until the byte
+     * is actually written.
+     *
+     * @param b the byte to be used for updating and writing to the
+     * output stream.
+     *
+     * @exception IOException if an I/O error occurs.
+     *
+     * @see MessageDigest#update(byte)
+     */
+    public void write(int b) throws IOException {
+        out.write(b);
+        if (on) {
+            digest.update((byte)b);
+        }
+    }
+
+    /**
+     * Updates the message digest (if the digest function is on) using
+     * the specified subarray, and in any case writes the subarray to
+     * the output stream. That is, if the digest function is on (see
+     * {@link #on(boolean) on}), this method calls {@code update}
+     * on the message digest associated with this stream, passing it
+     * the subarray specifications. This method then writes the subarray
+     * bytes to the output stream, blocking until the bytes are actually
+     * written.
+     *
+     * @param b the array containing the subarray to be used for updating
+     * and writing to the output stream.
+     *
+     * @param off the offset into {@code b} of the first byte to
+     * be updated and written.
+     *
+     * @param len the number of bytes of data to be updated and written
+     * from {@code b}, starting at offset {@code off}.
+     *
+     * @exception IOException if an I/O error occurs.
+     *
+     * @see MessageDigest#update(byte[], int, int)
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        // BEGIN Android-added: perform checks for parameters first.
+        // See org.apache.harmony.security.tests.j.s.DigestOutputStreamTest#test_write$BII_6
+        if (b == null || off + len > b.length) {
+            throw new IllegalArgumentException("wrong parameters for write");
+        }
+        if (off < 0 || len < 0) {
+            throw new IndexOutOfBoundsException("wrong index for write");
+        }
+        // END Android-added: perform checks for parameters first.
+        out.write(b, off, len);
+        if (on) {
+            digest.update(b, off, len);
+        }
+    }
+
+    /**
+     * Turns the digest function on or off. The default is on.  When
+     * it is on, a call to one of the {@code write} methods results in an
+     * update on the message digest.  But when it is off, the message
+     * digest is not updated.
+     *
+     * @param on true to turn the digest function on, false to turn it
+     * off.
+     */
+    public void on(boolean on) {
+        this.on = on;
+    }
+
+    /**
+     * Prints a string representation of this digest output stream and
+     * its associated message digest object.
+     */
+     public String toString() {
+         return "[Digest Output Stream] " + digest.toString();
+     }
+}
diff --git a/java/security/DomainCombiner.java b/java/security/DomainCombiner.java
new file mode 100644
index 0000000..e9c010f
--- /dev/null
+++ b/java/security/DomainCombiner.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public interface DomainCombiner {
+
+    ProtectionDomain[] combine(ProtectionDomain[] currentDomains,
+                                ProtectionDomain[] assignedDomains);
+}
diff --git a/java/security/DomainLoadStoreParameter.java b/java/security/DomainLoadStoreParameter.java
new file mode 100644
index 0000000..bc96975
--- /dev/null
+++ b/java/security/DomainLoadStoreParameter.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.net.URI;
+import java.util.*;
+import static java.security.KeyStore.*;
+
+/**
+ * Configuration data that specifies the keystores in a keystore domain.
+ * A keystore domain is a collection of keystores that are presented as a
+ * single logical keystore. The configuration data is used during
+ * {@code KeyStore}
+ * {@link KeyStore#load(KeyStore.LoadStoreParameter) load} and
+ * {@link KeyStore#store(KeyStore.LoadStoreParameter) store} operations.
+ * <p>
+ * The following syntax is supported for configuration data:
+ * <pre>{@code
+ *     domain <domainName> [<property> ...] {
+ *         keystore <keystoreName> [<property> ...] ;
+ *         ...
+ *     };
+ *     ...
+ * }</pre>
+ * where {@code domainName} and {@code keystoreName} are identifiers
+ * and {@code property} is a key/value pairing. The key and value are
+ * separated by an 'equals' symbol and the value is enclosed in double
+ * quotes. A property value may be either a printable string or a binary
+ * string of colon-separated pairs of hexadecimal digits. Multi-valued
+ * properties are represented as a comma-separated list of values,
+ * enclosed in square brackets.
+ * See {@link Arrays#toString(java.lang.Object[])}.
+ * <p>
+ * To ensure that keystore entries are uniquely identified, each
+ * entry's alias is prefixed by its {@code keystoreName} followed
+ * by the entry name separator and each {@code keystoreName} must be
+ * unique within its domain. Entry name prefixes are omitted when
+ * storing a keystore.
+ * <p>
+ * Properties are context-sensitive: properties that apply to
+ * all the keystores in a domain are located in the domain clause,
+ * and properties that apply only to a specific keystore are located
+ * in that keystore's clause.
+ * Unless otherwise specified, a property in a keystore clause overrides
+ * a property of the same name in the domain clause. All property names
+ * are case-insensitive. The following properties are supported:
+ * <dl>
+ * <dt> {@code keystoreType="<type>"} </dt>
+ *     <dd> The keystore type. </dd>
+ * <dt> {@code keystoreURI="<url>"} </dt>
+ *     <dd> The keystore location. </dd>
+ * <dt> {@code keystoreProviderName="<name>"} </dt>
+ *     <dd> The name of the keystore's JCE provider. </dd>
+ * <dt> {@code keystorePasswordEnv="<environment-variable>"} </dt>
+ *     <dd> The environment variable that stores a keystore password.
+ *          Alternatively, passwords may be supplied to the constructor
+ *          method in a {@code Map<String, ProtectionParameter>}. </dd>
+ * <dt> {@code entryNameSeparator="<separator>"} </dt>
+ *     <dd> The separator between a keystore name prefix and an entry name.
+ *          When specified, it applies to all the entries in a domain.
+ *          Its default value is a space. </dd>
+ * </dl>
+ * <p>
+ * For example, configuration data for a simple keystore domain
+ * comprising three keystores is shown below:
+ * <pre>
+ *
+ * domain app1 {
+ *     keystore app1-truststore
+ *         keystoreURI="file:///app1/etc/truststore.jks";
+ *
+ *     keystore system-truststore
+ *         keystoreURI="${java.home}/lib/security/cacerts";
+ *
+ *     keystore app1-keystore
+ *         keystoreType="PKCS12"
+ *         keystoreURI="file:///app1/etc/keystore.p12";
+ * };
+ *
+ * </pre>
+ * @since 1.8
+ */
+public final class DomainLoadStoreParameter implements LoadStoreParameter {
+
+    private final URI configuration;
+    private final Map<String,ProtectionParameter> protectionParams;
+
+    /**
+     * Constructs a DomainLoadStoreParameter for a keystore domain with
+     * the parameters used to protect keystore data.
+     *
+     * @param configuration identifier for the domain configuration data.
+     *     The name of the target domain should be specified in the
+     *     {@code java.net.URI} fragment component when it is necessary
+     *     to distinguish between several domain configurations at the
+     *     same location.
+     *
+     * @param protectionParams the map from keystore name to the parameter
+     *     used to protect keystore data.
+     *     A {@code java.util.Collections.EMPTY_MAP} should be used
+     *     when protection parameters are not required or when they have
+     *     been specified by properties in the domain configuration data.
+     *     It is cloned to prevent subsequent modification.
+     *
+     * @exception NullPointerException if {@code configuration} or
+     *     {@code protectionParams} is {@code null}
+     */
+    public DomainLoadStoreParameter(URI configuration,
+        Map<String,ProtectionParameter> protectionParams) {
+        if (configuration == null || protectionParams == null) {
+            throw new NullPointerException("invalid null input");
+        }
+        this.configuration = configuration;
+        this.protectionParams =
+            Collections.unmodifiableMap(new HashMap<>(protectionParams));
+    }
+
+    /**
+     * Gets the identifier for the domain configuration data.
+     *
+     * @return the identifier for the configuration data
+     */
+    public URI getConfiguration() {
+        return configuration;
+    }
+
+    /**
+     * Gets the keystore protection parameters for keystores in this
+     * domain.
+     *
+     * @return an unmodifiable map of keystore names to protection
+     *     parameters
+     */
+    public Map<String,ProtectionParameter> getProtectionParams() {
+        return protectionParams;
+    }
+
+    /**
+     * Gets the keystore protection parameters for this domain.
+     * Keystore domains do not support a protection parameter.
+     *
+     * @return always returns {@code null}
+     */
+    @Override
+    public KeyStore.ProtectionParameter getProtectionParameter() {
+        return null;
+    }
+}
diff --git a/java/security/GeneralSecurityException.java b/java/security/GeneralSecurityException.java
new file mode 100644
index 0000000..dc9ea06
--- /dev/null
+++ b/java/security/GeneralSecurityException.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * The {@code GeneralSecurityException} class is a generic
+ * security exception class that provides type safety for all the
+ * security-related exception classes that extend from it.
+ *
+ * @author Jan Luehe
+ */
+
+public class GeneralSecurityException extends Exception {
+
+    private static final long serialVersionUID = 894798122053539237L;
+
+    /**
+     * Constructs a GeneralSecurityException with no detail message.
+     */
+    public GeneralSecurityException() {
+        super();
+    }
+
+    /**
+     * Constructs a GeneralSecurityException with the specified detail
+     * message.
+     * A detail message is a String that describes this particular
+     * exception.
+     *
+     * @param msg the detail message.
+     */
+    public GeneralSecurityException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code GeneralSecurityException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public GeneralSecurityException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code GeneralSecurityException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public GeneralSecurityException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/Guard.java b/java/security/Guard.java
new file mode 100644
index 0000000..abafb58
--- /dev/null
+++ b/java/security/Guard.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * <p> This interface represents a guard, which is an object that is used
+ * to protect access to another object.
+ *
+ * <p>This interface contains a single method, {@code checkGuard},
+ * with a single {@code object} argument. {@code checkGuard} is
+ * invoked (by the GuardedObject {@code getObject} method)
+ * to determine whether or not to allow access to the object.
+ *
+ * @see GuardedObject
+ *
+ * @author Roland Schemers
+ * @author Li Gong
+ */
+
+public interface Guard {
+
+    /**
+     * Determines whether or not to allow access to the guarded object
+     * {@code object}. Returns silently if access is allowed.
+     * Otherwise, throws a SecurityException.
+     *
+     * @param object the object being protected by the guard.
+     *
+     * @exception SecurityException if access is denied.
+     *
+     */
+    void checkGuard(Object object) throws SecurityException;
+}
diff --git a/java/security/GuardedObject.java b/java/security/GuardedObject.java
new file mode 100644
index 0000000..a275ddf
--- /dev/null
+++ b/java/security/GuardedObject.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * A GuardedObject is an object that is used to protect access to
+ * another object.
+ *
+ * <p>A GuardedObject encapsulates a target object and a Guard object,
+ * such that access to the target object is possible
+ * only if the Guard object allows it.
+ * Once an object is encapsulated by a GuardedObject,
+ * access to that object is controlled by the {@code getObject}
+ * method, which invokes the
+ * {@code checkGuard} method on the Guard object that is
+ * guarding access. If access is not allowed,
+ * an exception is thrown.
+ *
+ * @see Guard
+ * @see Permission
+ *
+ * @author Roland Schemers
+ * @author Li Gong
+ */
+
+public class GuardedObject implements java.io.Serializable {
+
+    private static final long serialVersionUID = -5240450096227834308L;
+
+    private Object object; // the object we are guarding
+    private Guard guard;   // the guard
+
+    /**
+     * Constructs a GuardedObject using the specified object and guard.
+     * If the Guard object is null, then no restrictions will
+     * be placed on who can access the object.
+     *
+     * @param object the object to be guarded.
+     *
+     * @param guard the Guard object that guards access to the object.
+     */
+
+    public GuardedObject(Object object, Guard guard)
+    {
+        this.guard = guard;
+        this.object = object;
+    }
+
+    /**
+     * Retrieves the guarded object, or throws an exception if access
+     * to the guarded object is denied by the guard.
+     *
+     * @return the guarded object.
+     *
+     * @exception SecurityException if access to the guarded object is
+     * denied.
+     */
+    public Object getObject()
+        throws SecurityException
+    {
+        if (guard != null)
+            guard.checkGuard(object);
+
+        return object;
+    }
+
+    /**
+     * Writes this object out to a stream (i.e., serializes it).
+     * We check the guard if there is one.
+     */
+    private void writeObject(java.io.ObjectOutputStream oos)
+        throws java.io.IOException
+    {
+        if (guard != null)
+            guard.checkGuard(object);
+
+        oos.defaultWriteObject();
+    }
+}
diff --git a/java/security/Identity.java b/java/security/Identity.java
new file mode 100644
index 0000000..e63131e
--- /dev/null
+++ b/java/security/Identity.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * <p>This class represents identities: real-world objects such as people,
+ * companies or organizations whose identities can be authenticated using
+ * their public keys. Identities may also be more abstract (or concrete)
+ * constructs, such as daemon threads or smart cards.
+ *
+ * <p>All Identity objects have a name and a public key. Names are
+ * immutable. Identities may also be scoped. That is, if an Identity is
+ * specified to have a particular scope, then the name and public
+ * key of the Identity are unique within that scope.
+ *
+ * <p>An Identity also has a set of certificates (all certifying its own
+ * public key). The Principal names specified in these certificates need
+ * not be the same, only the key.
+ *
+ * <p>An Identity can be subclassed, to include postal and email addresses,
+ * telephone numbers, images of faces and logos, and so on.
+ *
+ * @see IdentityScope
+ * @see Signer
+ * @see Principal
+ *
+ * @author Benjamin Renaud
+ * @deprecated This class is no longer used. Its functionality has been
+ * replaced by {@code java.security.KeyStore}, the
+ * {@code java.security.cert} package, and
+ * {@code java.security.Principal}.
+ */
+@Deprecated
+public abstract class Identity implements Principal, Serializable {
+
+    /** use serialVersionUID from JDK 1.1.x for interoperability */
+    private static final long serialVersionUID = 3609922007826600659L;
+
+    /**
+     * The name for this identity.
+     *
+     * @serial
+     */
+    private String name;
+
+    /**
+     * The public key for this identity.
+     *
+     * @serial
+     */
+    private PublicKey publicKey;
+
+    /**
+     * Generic, descriptive information about the identity.
+     *
+     * @serial
+     */
+    String info = "No further information available.";
+
+    /**
+     * The scope of the identity.
+     *
+     * @serial
+     */
+    IdentityScope scope;
+
+    /**
+     * The certificates for this identity.
+     *
+     * @serial
+     */
+    Vector<Certificate> certificates;
+
+    /**
+     * Constructor for serialization only.
+     */
+    protected Identity() {
+        this("restoring...");
+    }
+
+    /**
+     * Constructs an identity with the specified name and scope.
+     *
+     * @param name the identity name.
+     * @param scope the scope of the identity.
+     *
+     * @exception KeyManagementException if there is already an identity
+     * with the same name in the scope.
+     */
+    public Identity(String name, IdentityScope scope) throws
+    KeyManagementException {
+        this(name);
+        if (scope != null) {
+            scope.addIdentity(this);
+        }
+        this.scope = scope;
+    }
+
+    /**
+     * Constructs an identity with the specified name and no scope.
+     *
+     * @param name the identity name.
+     */
+    public Identity(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns this identity's name.
+     *
+     * @return the name of this identity.
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Returns this identity's scope.
+     *
+     * @return the scope of this identity.
+     */
+    public final IdentityScope getScope() {
+        return scope;
+    }
+
+    /**
+     * Returns this identity's public key.
+     *
+     * @return the public key for this identity.
+     *
+     * @see #setPublicKey
+     */
+    public PublicKey getPublicKey() {
+        return publicKey;
+    }
+
+    /**
+     * Sets this identity's public key. The old key and all of this
+     * identity's certificates are removed by this operation.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "setIdentityPublicKey"}
+     * as its argument to see if it's ok to set the public key.
+     *
+     * @param key the public key for this identity.
+     *
+     * @exception KeyManagementException if another identity in the
+     * identity's scope has the same public key, or if another exception occurs.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * setting the public key.
+     *
+     * @see #getPublicKey
+     * @see SecurityManager#checkSecurityAccess
+     */
+    /* Should we throw an exception if this is already set? */
+    public void setPublicKey(PublicKey key) throws KeyManagementException {
+
+        check("setIdentityPublicKey");
+        this.publicKey = key;
+        certificates = new Vector<Certificate>();
+    }
+
+    /**
+     * Specifies a general information string for this identity.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "setIdentityInfo"}
+     * as its argument to see if it's ok to specify the information string.
+     *
+     * @param info the information string.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * setting the information string.
+     *
+     * @see #getInfo
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public void setInfo(String info) {
+        check("setIdentityInfo");
+        this.info = info;
+    }
+
+    /**
+     * Returns general information previously specified for this identity.
+     *
+     * @return general information about this identity.
+     *
+     * @see #setInfo
+     */
+    public String getInfo() {
+        return info;
+    }
+
+    /**
+     * Adds a certificate for this identity. If the identity has a public
+     * key, the public key in the certificate must be the same, and if
+     * the identity does not have a public key, the identity's
+     * public key is set to be that specified in the certificate.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "addIdentityCertificate"}
+     * as its argument to see if it's ok to add a certificate.
+     *
+     * @param certificate the certificate to be added.
+     *
+     * @exception KeyManagementException if the certificate is not valid,
+     * if the public key in the certificate being added conflicts with
+     * this identity's public key, or if another exception occurs.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * adding a certificate.
+     *
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public void addCertificate(Certificate certificate)
+    throws KeyManagementException {
+
+        check("addIdentityCertificate");
+
+        if (certificates == null) {
+            certificates = new Vector<Certificate>();
+        }
+        if (publicKey != null) {
+            if (!keyEquals(publicKey, certificate.getPublicKey())) {
+                throw new KeyManagementException(
+                    "public key different from cert public key");
+            }
+        } else {
+            publicKey = certificate.getPublicKey();
+        }
+        certificates.addElement(certificate);
+    }
+
+    private boolean keyEquals(PublicKey aKey, PublicKey anotherKey) {
+        String aKeyFormat = aKey.getFormat();
+        String anotherKeyFormat = anotherKey.getFormat();
+        if ((aKeyFormat == null) ^ (anotherKeyFormat == null))
+            return false;
+        if (aKeyFormat != null && anotherKeyFormat != null)
+            if (!aKeyFormat.equalsIgnoreCase(anotherKeyFormat))
+                return false;
+        return java.util.Arrays.equals(aKey.getEncoded(),
+                                     anotherKey.getEncoded());
+    }
+
+
+    /**
+     * Removes a certificate from this identity.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "removeIdentityCertificate"}
+     * as its argument to see if it's ok to remove a certificate.
+     *
+     * @param certificate the certificate to be removed.
+     *
+     * @exception KeyManagementException if the certificate is
+     * missing, or if another exception occurs.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * removing a certificate.
+     *
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public void removeCertificate(Certificate certificate)
+    throws KeyManagementException {
+        check("removeIdentityCertificate");
+        if (certificates != null) {
+            // Android-changed: Throw a KeyManagementException if certificate is null or
+            // not contained within |certificates|.
+            if (certificate == null || !certificates.contains(certificate)) {
+                throw new KeyManagementException();
+            }
+            certificates.removeElement(certificate);
+        }
+    }
+
+    /**
+     * Returns a copy of all the certificates for this identity.
+     *
+     * @return a copy of all the certificates for this identity.
+     */
+    public Certificate[] certificates() {
+        if (certificates == null) {
+            return new Certificate[0];
+        }
+        int len = certificates.size();
+        Certificate[] certs = new Certificate[len];
+        certificates.copyInto(certs);
+        return certs;
+    }
+
+    /**
+     * Tests for equality between the specified object and this identity.
+     * This first tests to see if the entities actually refer to the same
+     * object, in which case it returns true. Next, it checks to see if
+     * the entities have the same name and the same scope. If they do,
+     * the method returns true. Otherwise, it calls
+     * {@link #identityEquals(Identity) identityEquals}, which subclasses should
+     * override.
+     *
+     * @param identity the object to test for equality with this identity.
+     *
+     * @return true if the objects are considered equal, false otherwise.
+     *
+     * @see #identityEquals
+     */
+    public final boolean equals(Object identity) {
+
+        if (identity == this) {
+            return true;
+        }
+
+        if (identity instanceof Identity) {
+            Identity i = (Identity)identity;
+            if (this.fullName().equals(i.fullName())) {
+                return true;
+            } else {
+                return identityEquals(i);
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests for equality between the specified identity and this identity.
+     * This method should be overriden by subclasses to test for equality.
+     * The default behavior is to return true if the names and public keys
+     * are equal.
+     *
+     * @param identity the identity to test for equality with this identity.
+     *
+     * @return true if the identities are considered equal, false
+     * otherwise.
+     *
+     * @see #equals
+     */
+    protected boolean identityEquals(Identity identity) {
+        if (!name.equalsIgnoreCase(identity.name))
+            return false;
+
+        if ((publicKey == null) ^ (identity.publicKey == null))
+            return false;
+
+        if (publicKey != null && identity.publicKey != null)
+            if (!publicKey.equals(identity.publicKey))
+                return false;
+
+        return true;
+
+    }
+
+    /**
+     * Returns a parsable name for identity: identityName.scopeName
+     */
+    String fullName() {
+        String parsable = name;
+        if (scope != null) {
+            parsable += "." + scope.getName();
+        }
+        return parsable;
+    }
+
+    /**
+     * Returns a short string describing this identity, telling its
+     * name and its scope (if any).
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "printIdentity"}
+     * as its argument to see if it's ok to return the string.
+     *
+     * @return information about this identity, such as its name and the
+     * name of its scope (if any).
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * returning a string describing this identity.
+     *
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public String toString() {
+        check("printIdentity");
+        String printable = name;
+        if (scope != null) {
+            printable += "[" + scope.getName() + "]";
+        }
+        return printable;
+    }
+
+    /**
+     * Returns a string representation of this identity, with
+     * optionally more details than that provided by the
+     * {@code toString} method without any arguments.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "printIdentity"}
+     * as its argument to see if it's ok to return the string.
+     *
+     * @param detailed whether or not to provide detailed information.
+     *
+     * @return information about this identity. If {@code detailed}
+     * is true, then this method returns more information than that
+     * provided by the {@code toString} method without any arguments.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * returning a string describing this identity.
+     *
+     * @see #toString
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public String toString(boolean detailed) {
+        String out = toString();
+        if (detailed) {
+            out += "\n";
+            out += printKeys();
+            out += "\n" + printCertificates();
+            if (info != null) {
+                out += "\n\t" + info;
+            } else {
+                out += "\n\tno additional information available.";
+            }
+        }
+        return out;
+    }
+
+    String printKeys() {
+        String key = "";
+        if (publicKey != null) {
+            key = "\tpublic key initialized";
+        } else {
+            key = "\tno public key";
+        }
+        return key;
+    }
+
+    String printCertificates() {
+        String out = "";
+        if (certificates == null) {
+            return "\tno certificates";
+        } else {
+            out += "\tcertificates: \n";
+
+            int i = 1;
+            for (Certificate cert : certificates) {
+                out += "\tcertificate " + i++ +
+                    "\tfor  : " + cert.getPrincipal() + "\n";
+                out += "\t\t\tfrom : " +
+                    cert.getGuarantor() + "\n";
+            }
+        }
+        return out;
+    }
+
+    /**
+     * Returns a hashcode for this identity.
+     *
+     * @return a hashcode for this identity.
+     */
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    private static void check(String directive) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSecurityAccess(directive);
+        }
+    }
+}
diff --git a/java/security/IdentityScope.java b/java/security/IdentityScope.java
new file mode 100644
index 0000000..61d37cb
--- /dev/null
+++ b/java/security/IdentityScope.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * <p>This class represents a scope for identities. It is an Identity
+ * itself, and therefore has a name and can have a scope. It can also
+ * optionally have a public key and associated certificates.
+ *
+ * <p>An IdentityScope can contain Identity objects of all kinds, including
+ * Signers. All types of Identity objects can be retrieved, added, and
+ * removed using the same methods. Note that it is possible, and in fact
+ * expected, that different types of identity scopes will
+ * apply different policies for their various operations on the
+ * various types of Identities.
+ *
+ * <p>There is a one-to-one mapping between keys and identities, and
+ * there can only be one copy of one key per scope. For example, suppose
+ * <b>Acme Software, Inc</b> is a software publisher known to a user.
+ * Suppose it is an Identity, that is, it has a public key, and a set of
+ * associated certificates. It is named in the scope using the name
+ * "Acme Software". No other named Identity in the scope has the same
+ * public  key. Of course, none has the same name as well.
+ *
+ * @see Identity
+ * @see Signer
+ * @see Principal
+ * @see Key
+ *
+ * @author Benjamin Renaud
+ *
+ * @deprecated This class is no longer used. Its functionality has been
+ * replaced by {@code java.security.KeyStore}, the
+ * {@code java.security.cert} package, and
+ * {@code java.security.Principal}.
+ */
+@Deprecated
+public abstract
+class IdentityScope extends Identity {
+
+    private static final long serialVersionUID = -2337346281189773310L;
+
+    /* The system's scope */
+    private static IdentityScope scope;
+
+    // initialize the system scope
+    private static void initializeSystemScope() {
+
+        String classname = AccessController.doPrivileged(
+                                new PrivilegedAction<String>() {
+            public String run() {
+                return Security.getProperty("system.scope");
+            }
+        });
+
+        if (classname == null) {
+            return;
+
+        } else {
+
+            try {
+                // Android-changed: Actually set the system scope after initializing it
+                // Class.forName(classname);
+                scope = (IdentityScope) Class.forName(classname).newInstance();
+            } catch (Exception e) {
+                //Security.error("unable to establish a system scope from " +
+                //             classname);
+                e.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * This constructor is used for serialization only and should not
+     * be used by subclasses.
+     */
+    protected IdentityScope() {
+        this("restoring...");
+    }
+
+    /**
+     * Constructs a new identity scope with the specified name.
+     *
+     * @param name the scope name.
+     */
+    public IdentityScope(String name) {
+        super(name);
+    }
+
+    /**
+     * Constructs a new identity scope with the specified name and scope.
+     *
+     * @param name the scope name.
+     * @param scope the scope for the new identity scope.
+     *
+     * @exception KeyManagementException if there is already an identity
+     * with the same name in the scope.
+     */
+    public IdentityScope(String name, IdentityScope scope)
+    throws KeyManagementException {
+        super(name, scope);
+    }
+
+    /**
+     * Returns the system's identity scope.
+     *
+     * @return the system's identity scope, or {@code null} if none has been
+     *         set.
+     *
+     * @see #setSystemScope
+     */
+    public static IdentityScope getSystemScope() {
+        if (scope == null) {
+            initializeSystemScope();
+        }
+        return scope;
+    }
+
+
+    /**
+     * Sets the system's identity scope.
+     *
+     * <p>First, if there is a security manager, its
+     * {@code checkSecurityAccess}
+     * method is called with {@code "setSystemScope"}
+     * as its argument to see if it's ok to set the identity scope.
+     *
+     * @param scope the scope to set.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * setting the identity scope.
+     *
+     * @see #getSystemScope
+     * @see SecurityManager#checkSecurityAccess
+     */
+    protected static void setSystemScope(IdentityScope scope) {
+        check("setSystemScope");
+        IdentityScope.scope = scope;
+    }
+
+    /**
+     * Returns the number of identities within this identity scope.
+     *
+     * @return the number of identities within this identity scope.
+     */
+    public abstract int size();
+
+    /**
+     * Returns the identity in this scope with the specified name (if any).
+     *
+     * @param name the name of the identity to be retrieved.
+     *
+     * @return the identity named {@code name}, or null if there are
+     * no identities named {@code name} in this scope.
+     */
+    public abstract Identity getIdentity(String name);
+
+    /**
+     * Retrieves the identity whose name is the same as that of the
+     * specified principal. (Note: Identity implements Principal.)
+     *
+     * @param principal the principal corresponding to the identity
+     * to be retrieved.
+     *
+     * @return the identity whose name is the same as that of the
+     * principal, or null if there are no identities of the same name
+     * in this scope.
+     */
+    public Identity getIdentity(Principal principal) {
+        return getIdentity(principal.getName());
+    }
+
+    /**
+     * Retrieves the identity with the specified public key.
+     *
+     * @param key the public key for the identity to be returned.
+     *
+     * @return the identity with the given key, or null if there are
+     * no identities in this scope with that key.
+     */
+    public abstract Identity getIdentity(PublicKey key);
+
+    /**
+     * Adds an identity to this identity scope.
+     *
+     * @param identity the identity to be added.
+     *
+     * @exception KeyManagementException if the identity is not
+     * valid, a name conflict occurs, another identity has the same
+     * public key as the identity being added, or another exception
+     * occurs. */
+    public abstract void addIdentity(Identity identity)
+    throws KeyManagementException;
+
+    /**
+     * Removes an identity from this identity scope.
+     *
+     * @param identity the identity to be removed.
+     *
+     * @exception KeyManagementException if the identity is missing,
+     * or another exception occurs.
+     */
+    public abstract void removeIdentity(Identity identity)
+    throws KeyManagementException;
+
+    /**
+     * Returns an enumeration of all identities in this identity scope.
+     *
+     * @return an enumeration of all identities in this identity scope.
+     */
+    public abstract Enumeration<Identity> identities();
+
+    /**
+     * Returns a string representation of this identity scope, including
+     * its name, its scope name, and the number of identities in this
+     * identity scope.
+     *
+     * @return a string representation of this identity scope.
+     */
+    public String toString() {
+        return super.toString() + "[" + size() + "]";
+    }
+
+    private static void check(String directive) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSecurityAccess(directive);
+        }
+    }
+
+}
diff --git a/java/security/InvalidAlgorithmParameterException.java b/java/security/InvalidAlgorithmParameterException.java
new file mode 100644
index 0000000..559a8be
--- /dev/null
+++ b/java/security/InvalidAlgorithmParameterException.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This is the exception for invalid or inappropriate algorithm parameters.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see AlgorithmParameters
+ * @see java.security.spec.AlgorithmParameterSpec
+ *
+ * @since 1.2
+ */
+
+public class InvalidAlgorithmParameterException
+extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 2864672297499471472L;
+
+    /**
+     * Constructs an InvalidAlgorithmParameterException with no detail
+     * message.
+     * A detail message is a String that describes this particular
+     * exception.
+     */
+    public InvalidAlgorithmParameterException() {
+        super();
+    }
+
+    /**
+     * Constructs an InvalidAlgorithmParameterException with the specified
+     * detail message.
+     * A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public InvalidAlgorithmParameterException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code InvalidAlgorithmParameterException} with the
+     * specified detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public InvalidAlgorithmParameterException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code InvalidAlgorithmParameterException} with the
+     * specified cause and a detail message of
+     * {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public InvalidAlgorithmParameterException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/InvalidKeyException.java b/java/security/InvalidKeyException.java
new file mode 100644
index 0000000..35fc64c
--- /dev/null
+++ b/java/security/InvalidKeyException.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.security;
+
+/**
+ * This is the exception for invalid Keys (invalid encoding, wrong
+ * length, uninitialized, etc).
+ *
+ * @author Benjamin Renaud
+ */
+
+public class InvalidKeyException extends KeyException {
+
+    private static final long serialVersionUID = 5698479920593359816L;
+
+    /**
+     * Constructs an InvalidKeyException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public InvalidKeyException() {
+        super();
+    }
+
+    /**
+     * Constructs an InvalidKeyException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public InvalidKeyException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code InvalidKeyException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public InvalidKeyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code InvalidKeyException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public InvalidKeyException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/InvalidParameterException.java b/java/security/InvalidParameterException.java
new file mode 100644
index 0000000..a095f90
--- /dev/null
+++ b/java/security/InvalidParameterException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This exception, designed for use by the JCA/JCE engine classes,
+ * is thrown when an invalid parameter is passed
+ * to a method.
+ *
+ * @author Benjamin Renaud
+ */
+
+public class InvalidParameterException extends IllegalArgumentException {
+
+    private static final long serialVersionUID = -857968536935667808L;
+
+    /**
+     * Constructs an InvalidParameterException with no detail message.
+     * A detail message is a String that describes this particular
+     * exception.
+     */
+    public InvalidParameterException() {
+        super();
+    }
+
+    /**
+     * Constructs an InvalidParameterException with the specified
+     * detail message.  A detail message is a String that describes
+     * this particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public InvalidParameterException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/security/Key.java b/java/security/Key.java
new file mode 100644
index 0000000..c0c63d7
--- /dev/null
+++ b/java/security/Key.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * The Key interface is the top-level interface for all keys. It
+ * defines the functionality shared by all key objects. All keys
+ * have three characteristics:
+ *
+ * <UL>
+ *
+ * <LI>An Algorithm
+ *
+ * <P>This is the key algorithm for that key. The key algorithm is usually
+ * an encryption or asymmetric operation algorithm (such as DSA or
+ * RSA), which will work with those algorithms and with related
+ * algorithms (such as MD5 with RSA, SHA-1 with RSA, Raw DSA, etc.)
+ * The name of the algorithm of a key is obtained using the
+ * {@link #getAlgorithm() getAlgorithm} method.
+ *
+ * <LI>An Encoded Form
+ *
+ * <P>This is an external encoded form for the key used when a standard
+ * representation of the key is needed outside the Java Virtual Machine,
+ * as when transmitting the key to some other party. The key
+ * is encoded according to a standard format (such as
+ * X.509 {@code SubjectPublicKeyInfo} or PKCS#8), and
+ * is returned using the {@link #getEncoded() getEncoded} method.
+ * Note: The syntax of the ASN.1 type {@code SubjectPublicKeyInfo}
+ * is defined as follows:
+ *
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ *   algorithm AlgorithmIdentifier,
+ *   subjectPublicKey BIT STRING }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ *   algorithm OBJECT IDENTIFIER,
+ *   parameters ANY DEFINED BY algorithm OPTIONAL }
+ * </pre>
+ *
+ * For more information, see
+ * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
+ * Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a>.
+ *
+ * <LI>A Format
+ *
+ * <P>This is the name of the format of the encoded key. It is returned
+ * by the {@link #getFormat() getFormat} method.
+ *
+ * </UL>
+ *
+ * Keys are generally obtained through key generators, certificates,
+ * or various Identity classes used to manage keys.
+ * Keys may also be obtained from key specifications (transparent
+ * representations of the underlying key material) through the use of a key
+ * factory (see {@link KeyFactory}).
+ *
+ * <p> A Key should use KeyRep as its serialized representation.
+ * Note that a serialized Key may contain sensitive information
+ * which should not be exposed in untrusted environments.  See the
+ * <a href="../../../platform/serialization/spec/security.html">
+ * Security Appendix</a>
+ * of the Serialization Specification for more information.
+ *
+ * @see PublicKey
+ * @see PrivateKey
+ * @see KeyPair
+ * @see KeyPairGenerator
+ * @see KeyFactory
+ * @see KeyRep
+ * @see java.security.spec.KeySpec
+ * @see Identity
+ * @see Signer
+ *
+ * @author Benjamin Renaud
+ */
+
+public interface Key extends java.io.Serializable {
+
+    // Declare serialVersionUID to be compatible with JDK1.1
+
+   /**
+    * The class fingerprint that is set to indicate
+    * serialization compatibility with a previous
+    * version of the class.
+    */
+    static final long serialVersionUID = 6603384152749567654L;
+
+    /**
+     * Returns the standard algorithm name for this key. For
+     * example, "DSA" would indicate that this key is a DSA key.
+     * See Appendix A in the <a href=
+     * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard algorithm names.
+     *
+     * @return the name of the algorithm associated with this key.
+     */
+    public String getAlgorithm();
+
+    /**
+     * Returns the name of the primary encoding format of this key,
+     * or null if this key does not support encoding.
+     * The primary encoding format is
+     * named in terms of the appropriate ASN.1 data format, if an
+     * ASN.1 specification for this key exists.
+     * For example, the name of the ASN.1 data format for public
+     * keys is <I>SubjectPublicKeyInfo</I>, as
+     * defined by the X.509 standard; in this case, the returned format is
+     * {@code "X.509"}. Similarly,
+     * the name of the ASN.1 data format for private keys is
+     * <I>PrivateKeyInfo</I>,
+     * as defined by the PKCS #8 standard; in this case, the returned format is
+     * {@code "PKCS#8"}.
+     *
+     * @return the primary encoding format of the key.
+     */
+    public String getFormat();
+
+    /**
+     * Returns the key in its primary encoding format, or null
+     * if this key does not support encoding.
+     *
+     * @return the encoded key, or null if the key does not support
+     * encoding.
+     */
+    public byte[] getEncoded();
+}
diff --git a/java/security/KeyException.java b/java/security/KeyException.java
new file mode 100644
index 0000000..59cdd6f
--- /dev/null
+++ b/java/security/KeyException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This is the basic key exception.
+ *
+ * @see Key
+ * @see InvalidKeyException
+ * @see KeyManagementException
+ *
+ * @author Benjamin Renaud
+ */
+
+public class KeyException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -7483676942812432108L;
+
+    /**
+     * Constructs a KeyException with no detail message. A detail
+     * message is a String that describes this particular exception.
+     */
+    public KeyException() {
+        super();
+    }
+
+    /**
+     * Constructs a KeyException with the specified detail message.
+     * A detail message is a String that describes this particular
+     * exception.
+     *
+     * @param msg the detail message.
+     */
+    public KeyException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code KeyException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public KeyException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code KeyException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public KeyException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/KeyFactory.java b/java/security/KeyFactory.java
new file mode 100644
index 0000000..716f62d
--- /dev/null
+++ b/java/security/KeyFactory.java
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+import java.security.Provider.Service;
+import java.security.spec.KeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.RSAPrivateKeySpec;
+
+import sun.security.util.Debug;
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * Key factories are used to convert <I>keys</I> (opaque
+ * cryptographic keys of type {@code Key}) into <I>key specifications</I>
+ * (transparent representations of the underlying key material), and vice
+ * versa.
+ *
+ * <P> Key factories are bi-directional. That is, they allow you to build an
+ * opaque key object from a given key specification (key material), or to
+ * retrieve the underlying key material of a key object in a suitable format.
+ *
+ * <P> Multiple compatible key specifications may exist for the same key.
+ * For example, a DSA public key may be specified using
+ * {@code DSAPublicKeySpec} or
+ * {@code X509EncodedKeySpec}. A key factory can be used to translate
+ * between compatible key specifications.
+ *
+ * <P> The following is an example of how to use a key factory in order to
+ * instantiate a DSA public key from its encoding.
+ * Assume Alice has received a digital signature from Bob.
+ * Bob also sent her his public key (in encoded format) to verify
+ * his signature. Alice then performs the following actions:
+ *
+ * <pre>
+ * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
+ * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
+ * Signature sig = Signature.getInstance("DSA");
+ * sig.initVerify(bobPubKey);
+ * sig.update(data);
+ * sig.verify(signature);
+ * </pre>
+ *
+ * <p> Android provides the following <code>KeyFactory</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>DH</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>EC</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>RSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>X.509</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
+ * KeyFactory section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see Key
+ * @see PublicKey
+ * @see PrivateKey
+ * @see java.security.spec.KeySpec
+ * @see java.security.spec.DSAPublicKeySpec
+ * @see java.security.spec.X509EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public class KeyFactory {
+
+    private static final Debug debug =
+                        Debug.getInstance("jca", "KeyFactory");
+
+    // The algorithm associated with this key factory
+    private final String algorithm;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation (delegate)
+    private volatile KeyFactorySpi spi;
+
+    // lock for mutex during provider selection
+    private final Object lock = new Object();
+
+    // remaining services to try in provider selection
+    // null once provider is selected
+    private Iterator<Service> serviceIterator;
+
+    /**
+     * Creates a KeyFactory object.
+     *
+     * @param keyFacSpi the delegate
+     * @param provider the provider
+     * @param algorithm the name of the algorithm
+     * to associate with this {@code KeyFactory}
+     */
+    protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
+                         String algorithm) {
+        this.spi = keyFacSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
+        this.algorithm = algorithm;
+        List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
+        serviceIterator = list.iterator();
+        // fetch and instantiate initial spi
+        if (nextSpi(null) == null) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " KeyFactory not available");
+        }
+    }
+
+    /**
+     * Returns a KeyFactory object that converts
+     * public/private keys of the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyFactory object encapsulating the
+     * KeyFactorySpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the requested key algorithm.
+     * See the KeyFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new KeyFactory object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyFactorySpi implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     */
+    public static KeyFactory getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        return new KeyFactory(algorithm);
+    }
+
+    /**
+     * Returns a KeyFactory object that converts
+     * public/private keys of the specified algorithm.
+     *
+     * <p> A new KeyFactory object encapsulating the
+     * KeyFactorySpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the requested key algorithm.
+     * See the KeyFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new KeyFactory object.
+     *
+     * @exception NoSuchAlgorithmException if a KeyFactorySpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static KeyFactory getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyFactory", algorithm);
+        Instance instance = GetInstance.getInstance("KeyFactory",
+            KeyFactorySpi.class, algorithm, provider);
+        return new KeyFactory((KeyFactorySpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a KeyFactory object that converts
+     * public/private keys of the specified algorithm.
+     *
+     * <p> A new KeyFactory object encapsulating the
+     * KeyFactorySpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the name of the requested key algorithm.
+     * See the KeyFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new KeyFactory object.
+     *
+     * @exception NoSuchAlgorithmException if a KeyFactorySpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the specified provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static KeyFactory getInstance(String algorithm, Provider provider)
+            throws NoSuchAlgorithmException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyFactory", algorithm);
+        Instance instance = GetInstance.getInstance("KeyFactory",
+            KeyFactorySpi.class, algorithm, provider);
+        return new KeyFactory((KeyFactorySpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this key factory object.
+     *
+     * @return the provider of this key factory object
+     */
+    public final Provider getProvider() {
+        synchronized (lock) {
+            // disable further failover after this call
+            serviceIterator = null;
+            return provider;
+        }
+    }
+
+    /**
+     * Gets the name of the algorithm
+     * associated with this {@code KeyFactory}.
+     *
+     * @return the name of the algorithm associated with this
+     * {@code KeyFactory}
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Update the active KeyFactorySpi of this class and return the next
+     * implementation for failover. If no more implemenations are
+     * available, this method returns null. However, the active spi of
+     * this class is never set to null.
+     */
+    private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
+        synchronized (lock) {
+            // somebody else did a failover concurrently
+            // try that spi now
+            if ((oldSpi != null) && (oldSpi != spi)) {
+                return spi;
+            }
+            if (serviceIterator == null) {
+                return null;
+            }
+            while (serviceIterator.hasNext()) {
+                Service s = serviceIterator.next();
+                try {
+                    Object obj = s.newInstance(null);
+                    if (obj instanceof KeyFactorySpi == false) {
+                        continue;
+                    }
+                    KeyFactorySpi spi = (KeyFactorySpi)obj;
+                    provider = s.getProvider();
+                    this.spi = spi;
+                    return spi;
+                } catch (NoSuchAlgorithmException e) {
+                    // ignore
+                }
+            }
+            serviceIterator = null;
+            return null;
+        }
+    }
+
+    /**
+     * Generates a public key object from the provided key specification
+     * (key material).
+     *
+     * @param keySpec the specification (key material) of the public key.
+     *
+     * @return the public key.
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this key factory to produce a public key.
+     */
+    public final PublicKey generatePublic(KeySpec keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGeneratePublic(keySpec);
+        }
+        Exception failure = null;
+        KeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGeneratePublic(keySpec);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof RuntimeException) {
+            throw (RuntimeException)failure;
+        }
+        if (failure instanceof InvalidKeySpecException) {
+            throw (InvalidKeySpecException)failure;
+        }
+        throw new InvalidKeySpecException
+                ("Could not generate public key", failure);
+    }
+
+    /**
+     * Generates a private key object from the provided key specification
+     * (key material).
+     *
+     * @param keySpec the specification (key material) of the private key.
+     *
+     * @return the private key.
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this key factory to produce a private key.
+     */
+    public final PrivateKey generatePrivate(KeySpec keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGeneratePrivate(keySpec);
+        }
+        Exception failure = null;
+        KeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGeneratePrivate(keySpec);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof RuntimeException) {
+            throw (RuntimeException)failure;
+        }
+        if (failure instanceof InvalidKeySpecException) {
+            throw (InvalidKeySpecException)failure;
+        }
+        throw new InvalidKeySpecException
+                ("Could not generate private key", failure);
+    }
+
+    /**
+     * Returns a specification (key material) of the given key object.
+     * {@code keySpec} identifies the specification class in which
+     * the key material should be returned. It could, for example, be
+     * {@code DSAPublicKeySpec.class}, to indicate that the
+     * key material should be returned in an instance of the
+     * {@code DSAPublicKeySpec} class.
+     *
+     * @param <T> the type of the key specification to be returned
+     *
+     * @param key the key.
+     *
+     * @param keySpec the specification class in which
+     * the key material should be returned.
+     *
+     * @return the underlying key specification (key material) in an instance
+     * of the requested specification class.
+     *
+     * @exception InvalidKeySpecException if the requested key specification is
+     * inappropriate for the given key, or the given key cannot be processed
+     * (e.g., the given key has an unrecognized algorithm or format).
+     */
+    public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
+            throws InvalidKeySpecException {
+        if (serviceIterator == null) {
+            return spi.engineGetKeySpec(key, keySpec);
+        }
+        Exception failure = null;
+        KeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineGetKeySpec(key, keySpec);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof RuntimeException) {
+            throw (RuntimeException)failure;
+        }
+        if (failure instanceof InvalidKeySpecException) {
+            throw (InvalidKeySpecException)failure;
+        }
+        throw new InvalidKeySpecException
+                ("Could not get key spec", failure);
+    }
+
+    /**
+     * Translates a key object, whose provider may be unknown or potentially
+     * untrusted, into a corresponding key object of this key factory.
+     *
+     * @param key the key whose provider is unknown or untrusted.
+     *
+     * @return the translated key.
+     *
+     * @exception InvalidKeyException if the given key cannot be processed
+     * by this key factory.
+     */
+    public final Key translateKey(Key key) throws InvalidKeyException {
+        if (serviceIterator == null) {
+            return spi.engineTranslateKey(key);
+        }
+        Exception failure = null;
+        KeyFactorySpi mySpi = spi;
+        do {
+            try {
+                return mySpi.engineTranslateKey(key);
+            } catch (Exception e) {
+                if (failure == null) {
+                    failure = e;
+                }
+                mySpi = nextSpi(mySpi);
+            }
+        } while (mySpi != null);
+        if (failure instanceof RuntimeException) {
+            throw (RuntimeException)failure;
+        }
+        if (failure instanceof InvalidKeyException) {
+            throw (InvalidKeyException)failure;
+        }
+        throw new InvalidKeyException
+                ("Could not translate key", failure);
+    }
+
+}
diff --git a/java/security/KeyFactorySpi.java b/java/security/KeyFactorySpi.java
new file mode 100644
index 0000000..5ee7f45
--- /dev/null
+++ b/java/security/KeyFactorySpi.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.security.spec.KeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code KeyFactory} class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a key factory for a particular algorithm.
+ *
+ * <P> Key factories are used to convert <I>keys</I> (opaque
+ * cryptographic keys of type {@code Key}) into <I>key specifications</I>
+ * (transparent representations of the underlying key material), and vice
+ * versa.
+ *
+ * <P> Key factories are bi-directional. That is, they allow you to build an
+ * opaque key object from a given key specification (key material), or to
+ * retrieve the underlying key material of a key object in a suitable format.
+ *
+ * <P> Multiple compatible key specifications may exist for the same key.
+ * For example, a DSA public key may be specified using
+ * {@code DSAPublicKeySpec} or
+ * {@code X509EncodedKeySpec}. A key factory can be used to translate
+ * between compatible key specifications.
+ *
+ * <P> A provider should document all the key specifications supported by its
+ * key factory.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see KeyFactory
+ * @see Key
+ * @see PublicKey
+ * @see PrivateKey
+ * @see java.security.spec.KeySpec
+ * @see java.security.spec.DSAPublicKeySpec
+ * @see java.security.spec.X509EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public abstract class KeyFactorySpi {
+
+    /**
+     * Generates a public key object from the provided key
+     * specification (key material).
+     *
+     * @param keySpec the specification (key material) of the public key.
+     *
+     * @return the public key.
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this key factory to produce a public key.
+     */
+    protected abstract PublicKey engineGeneratePublic(KeySpec keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Generates a private key object from the provided key
+     * specification (key material).
+     *
+     * @param keySpec the specification (key material) of the private key.
+     *
+     * @return the private key.
+     *
+     * @exception InvalidKeySpecException if the given key specification
+     * is inappropriate for this key factory to produce a private key.
+     */
+    protected abstract PrivateKey engineGeneratePrivate(KeySpec keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Returns a specification (key material) of the given key
+     * object.
+     * {@code keySpec} identifies the specification class in which
+     * the key material should be returned. It could, for example, be
+     * {@code DSAPublicKeySpec.class}, to indicate that the
+     * key material should be returned in an instance of the
+     * {@code DSAPublicKeySpec} class.
+     *
+     * @param <T> the type of the key specification to be returned
+     *
+     * @param key the key.
+     *
+     * @param keySpec the specification class in which
+     * the key material should be returned.
+     *
+     * @return the underlying key specification (key material) in an instance
+     * of the requested specification class.
+
+     * @exception InvalidKeySpecException if the requested key specification is
+     * inappropriate for the given key, or the given key cannot be dealt with
+     * (e.g., the given key has an unrecognized format).
+     */
+    protected abstract <T extends KeySpec>
+        T engineGetKeySpec(Key key, Class<T> keySpec)
+        throws InvalidKeySpecException;
+
+    /**
+     * Translates a key object, whose provider may be unknown or
+     * potentially untrusted, into a corresponding key object of this key
+     * factory.
+     *
+     * @param key the key whose provider is unknown or untrusted.
+     *
+     * @return the translated key.
+     *
+     * @exception InvalidKeyException if the given key cannot be processed
+     * by this key factory.
+     */
+    protected abstract Key engineTranslateKey(Key key)
+        throws InvalidKeyException;
+
+}
diff --git a/java/security/KeyManagementException.java b/java/security/KeyManagementException.java
new file mode 100644
index 0000000..be212b9
--- /dev/null
+++ b/java/security/KeyManagementException.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This is the general key management exception for all operations
+ * dealing with key management. Examples of subclasses of
+ * KeyManagementException that developers might create for
+ * giving more detailed information could include:
+ *
+ * <ul>
+ * <li>KeyIDConflictException
+ * <li>KeyAuthorizationFailureException
+ * <li>ExpiredKeyException
+ * </ul>
+ *
+ * @author Benjamin Renaud
+ *
+ * @see Key
+ * @see KeyException
+ */
+
+public class KeyManagementException extends KeyException {
+
+    private static final long serialVersionUID = 947674216157062695L;
+
+    /**
+     * Constructs a KeyManagementException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public KeyManagementException() {
+        super();
+    }
+
+     /**
+     * Constructs a KeyManagementException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+   public KeyManagementException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code KeyManagementException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public KeyManagementException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code KeyManagementException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public KeyManagementException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/KeyPair.java b/java/security/KeyPair.java
new file mode 100644
index 0000000..6147a16
--- /dev/null
+++ b/java/security/KeyPair.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+
+/**
+ * This class is a simple holder for a key pair (a public key and a
+ * private key). It does not enforce any security, and, when initialized,
+ * should be treated like a PrivateKey.
+ *
+ * @see PublicKey
+ * @see PrivateKey
+ *
+ * @author Benjamin Renaud
+ */
+
+public final class KeyPair implements java.io.Serializable {
+
+    private static final long serialVersionUID = -7565189502268009837L;
+
+    private PrivateKey privateKey;
+    private PublicKey publicKey;
+
+    /**
+     * Constructs a key pair from the given public key and private key.
+     *
+     * <p>Note that this constructor only stores references to the public
+     * and private key components in the generated key pair. This is safe,
+     * because {@code Key} objects are immutable.
+     *
+     * @param publicKey the public key.
+     *
+     * @param privateKey the private key.
+     */
+    public KeyPair(PublicKey publicKey, PrivateKey privateKey) {
+        this.publicKey = publicKey;
+        this.privateKey = privateKey;
+    }
+
+    /**
+     * Returns a reference to the public key component of this key pair.
+     *
+     * @return a reference to the public key.
+     */
+    public PublicKey getPublic() {
+        return publicKey;
+    }
+
+     /**
+     * Returns a reference to the private key component of this key pair.
+     *
+     * @return a reference to the private key.
+     */
+   public PrivateKey getPrivate() {
+        return privateKey;
+    }
+}
diff --git a/java/security/KeyPairGenerator.java b/java/security/KeyPairGenerator.java
new file mode 100644
index 0000000..7c6cdb5
--- /dev/null
+++ b/java/security/KeyPairGenerator.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import java.security.Provider.Service;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * The KeyPairGenerator class is used to generate pairs of
+ * public and private keys. Key pair generators are constructed using the
+ * {@code getInstance} factory methods (static methods that
+ * return instances of a given class).
+ *
+ * <p>A Key pair generator for a particular algorithm creates a public/private
+ * key pair that can be used with this algorithm. It also associates
+ * algorithm-specific parameters with each of the generated keys.
+ *
+ * <p>There are two ways to generate a key pair: in an algorithm-independent
+ * manner, and in an algorithm-specific manner.
+ * The only difference between the two is the initialization of the object:
+ *
+ * <ul>
+ * <li><b>Algorithm-Independent Initialization</b>
+ * <p>All key pair generators share the concepts of a keysize and a
+ * source of randomness. The keysize is interpreted differently for different
+ * algorithms (e.g., in the case of the <i>DSA</i> algorithm, the keysize
+ * corresponds to the length of the modulus).
+ * There is an
+ * {@link #initialize(int, java.security.SecureRandom) initialize}
+ * method in this KeyPairGenerator class that takes these two universally
+ * shared types of arguments. There is also one that takes just a
+ * {@code keysize} argument, and uses the {@code SecureRandom}
+ * implementation of the highest-priority installed provider as the source
+ * of randomness. (If none of the installed providers supply an implementation
+ * of {@code SecureRandom}, a system-provided source of randomness is
+ * used.)
+ *
+ * <p>Since no other parameters are specified when you call the above
+ * algorithm-independent {@code initialize} methods, it is up to the
+ * provider what to do about the algorithm-specific parameters (if any) to be
+ * associated with each of the keys.
+ *
+ * <p>If the algorithm is the <i>DSA</i> algorithm, and the keysize (modulus
+ * size) is 512, 768, or 1024, then the <i>Sun</i> provider uses a set of
+ * precomputed values for the {@code p}, {@code q}, and
+ * {@code g} parameters. If the modulus size is not one of the above
+ * values, the <i>Sun</i> provider creates a new set of parameters. Other
+ * providers might have precomputed parameter sets for more than just the
+ * three modulus sizes mentioned above. Still others might not have a list of
+ * precomputed parameters at all and instead always create new parameter sets.
+ *
+ * <li><b>Algorithm-Specific Initialization</b>
+ * <p>For situations where a set of algorithm-specific parameters already
+ * exists (e.g., so-called <i>community parameters</i> in DSA), there are two
+ * {@link #initialize(java.security.spec.AlgorithmParameterSpec)
+ * initialize} methods that have an {@code AlgorithmParameterSpec}
+ * argument. One also has a {@code SecureRandom} argument, while the
+ * the other uses the {@code SecureRandom}
+ * implementation of the highest-priority installed provider as the source
+ * of randomness. (If none of the installed providers supply an implementation
+ * of {@code SecureRandom}, a system-provided source of randomness is
+ * used.)
+ * </ul>
+ *
+ * <p>In case the client does not explicitly initialize the KeyPairGenerator
+ * (via a call to an {@code initialize} method), each provider must
+ * supply (and document) a default initialization.
+ * For example, the <i>Sun</i> provider uses a default modulus size (keysize)
+ * of 1024 bits.
+ *
+ * <p>Note that this class is abstract and extends from
+ * {@code KeyPairGeneratorSpi} for historical reasons.
+ * Application developers should only take notice of the methods defined in
+ * this {@code KeyPairGenerator} class; all the methods in
+ * the superclass are intended for cryptographic service providers who wish to
+ * supply their own implementations of key pair generators.
+ *
+ * <p> Android provides the following <code>KeyPairGenerator</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>DH</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>EC</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>RSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
+ * KeyPairGenerator section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Benjamin Renaud
+ *
+ * @see java.security.spec.AlgorithmParameterSpec
+ */
+
+public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
+
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("keypairgenerator");
+    */
+
+    private final String algorithm;
+
+    // The provider
+    Provider provider;
+
+    /**
+     * Creates a KeyPairGenerator object for the specified algorithm.
+     *
+     * @param algorithm the standard string name of the algorithm.
+     * See the KeyPairGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     */
+    protected KeyPairGenerator(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns the standard name of the algorithm for this key pair generator.
+     * See the KeyPairGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the standard string name of the algorithm.
+     */
+    public String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    private static KeyPairGenerator getInstance(Instance instance,
+            String algorithm) {
+        KeyPairGenerator kpg;
+        if (instance.impl instanceof KeyPairGenerator) {
+            kpg = (KeyPairGenerator)instance.impl;
+        } else {
+            KeyPairGeneratorSpi spi = (KeyPairGeneratorSpi)instance.impl;
+            kpg = new Delegate(spi, algorithm);
+        }
+        kpg.provider = instance.provider;
+
+        // Android-removed: this debugging mechanism is not used in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("KeyPairGenerator." + algorithm +
+                " algorithm from: " + kpg.provider.getName());
+        }
+        */
+
+        return kpg;
+    }
+
+    /**
+     * Returns a KeyPairGenerator object that generates public/private
+     * key pairs for the specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyPairGenerator object encapsulating the
+     * KeyPairGeneratorSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard string name of the algorithm.
+     * See the KeyPairGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new KeyPairGenerator object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          KeyPairGeneratorSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     */
+    public static KeyPairGenerator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        List<Service> list =
+                GetInstance.getServices("KeyPairGenerator", algorithm);
+        Iterator<Service> t = list.iterator();
+        if (t.hasNext() == false) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " KeyPairGenerator not available");
+        }
+        // find a working Spi or KeyPairGenerator subclass
+        NoSuchAlgorithmException failure = null;
+        do {
+            Service s = t.next();
+            try {
+                Instance instance =
+                    GetInstance.getInstance(s, KeyPairGeneratorSpi.class);
+                if (instance.impl instanceof KeyPairGenerator) {
+                    return getInstance(instance, algorithm);
+                } else {
+                    return new Delegate(instance, t, algorithm);
+                }
+            } catch (NoSuchAlgorithmException e) {
+                if (failure == null) {
+                    failure = e;
+                }
+            }
+        } while (t.hasNext());
+        throw failure;
+    }
+
+    /**
+     * Returns a KeyPairGenerator object that generates public/private
+     * key pairs for the specified algorithm.
+     *
+     * <p> A new KeyPairGenerator object encapsulating the
+     * KeyPairGeneratorSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard string name of the algorithm.
+     * See the KeyPairGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the string name of the provider.
+     *
+     * @return the new KeyPairGenerator object.
+     *
+     * @exception NoSuchAlgorithmException if a KeyPairGeneratorSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static KeyPairGenerator getInstance(String algorithm,
+            String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyPairGenerator", algorithm);
+        Instance instance = GetInstance.getInstance("KeyPairGenerator",
+                KeyPairGeneratorSpi.class, algorithm, provider);
+        return getInstance(instance, algorithm);
+    }
+
+    /**
+     * Returns a KeyPairGenerator object that generates public/private
+     * key pairs for the specified algorithm.
+     *
+     * <p> A new KeyPairGenerator object encapsulating the
+     * KeyPairGeneratorSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the standard string name of the algorithm.
+     * See the KeyPairGenerator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyPairGenerator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new KeyPairGenerator object.
+     *
+     * @exception NoSuchAlgorithmException if a KeyPairGeneratorSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the specified provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static KeyPairGenerator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "KeyPairGenerator", algorithm);
+        Instance instance = GetInstance.getInstance("KeyPairGenerator",
+                KeyPairGeneratorSpi.class, algorithm, provider);
+        return getInstance(instance, algorithm);
+    }
+
+    /**
+     * Returns the provider of this key pair generator object.
+     *
+     * @return the provider of this key pair generator object
+     */
+    public final Provider getProvider() {
+        disableFailover();
+        return this.provider;
+    }
+
+    void disableFailover() {
+        // empty, overridden in Delegate
+    }
+
+    /**
+     * Initializes the key pair generator for a certain keysize using
+     * a default parameter set and the {@code SecureRandom}
+     * implementation of the highest-priority installed provider as the source
+     * of randomness.
+     * (If none of the installed providers supply an implementation of
+     * {@code SecureRandom}, a system-provided source of randomness is
+     * used.)
+     *
+     * @param keysize the keysize. This is an
+     * algorithm-specific metric, such as modulus length, specified in
+     * number of bits.
+     *
+     * @exception InvalidParameterException if the {@code keysize} is not
+     * supported by this KeyPairGenerator object.
+     */
+    public void initialize(int keysize) {
+        initialize(keysize, JCAUtil.getSecureRandom());
+    }
+
+    /**
+     * Initializes the key pair generator for a certain keysize with
+     * the given source of randomness (and a default parameter set).
+     *
+     * @param keysize the keysize. This is an
+     * algorithm-specific metric, such as modulus length, specified in
+     * number of bits.
+     * @param random the source of randomness.
+     *
+     * @exception InvalidParameterException if the {@code keysize} is not
+     * supported by this KeyPairGenerator object.
+     *
+     * @since 1.2
+     */
+    public void initialize(int keysize, SecureRandom random) {
+        // This does nothing, because either
+        // 1. the implementation object returned by getInstance() is an
+        //    instance of KeyPairGenerator which has its own
+        //    initialize(keysize, random) method, so the application would
+        //    be calling that method directly, or
+        // 2. the implementation returned by getInstance() is an instance
+        //    of Delegate, in which case initialize(keysize, random) is
+        //    overridden to call the corresponding SPI method.
+        // (This is a special case, because the API and SPI method have the
+        // same name.)
+    }
+
+    /**
+     * Initializes the key pair generator using the specified parameter
+     * set and the {@code SecureRandom}
+     * implementation of the highest-priority installed provider as the source
+     * of randomness.
+     * (If none of the installed providers supply an implementation of
+     * {@code SecureRandom}, a system-provided source of randomness is
+     * used.).
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class.
+     * This method calls the KeyPairGeneratorSpi
+     * {@link KeyPairGeneratorSpi#initialize(
+     * java.security.spec.AlgorithmParameterSpec,
+     * java.security.SecureRandom) initialize} method,
+     * passing it {@code params} and a source of randomness (obtained
+     * from the highest-priority installed provider or system-provided if none
+     * of the installed providers supply one).
+     * That {@code initialize} method always throws an
+     * UnsupportedOperationException if it is not overridden by the provider.
+     *
+     * @param params the parameter set used to generate the keys.
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key pair generator.
+     *
+     * @since 1.2
+     */
+    public void initialize(AlgorithmParameterSpec params)
+            throws InvalidAlgorithmParameterException {
+        initialize(params, JCAUtil.getSecureRandom());
+    }
+
+    /**
+     * Initializes the key pair generator with the given parameter
+     * set and source of randomness.
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class.
+     * This method calls the KeyPairGeneratorSpi {@link
+     * KeyPairGeneratorSpi#initialize(
+     * java.security.spec.AlgorithmParameterSpec,
+     * java.security.SecureRandom) initialize} method,
+     * passing it {@code params} and {@code random}.
+     * That {@code initialize}
+     * method always throws an
+     * UnsupportedOperationException if it is not overridden by the provider.
+     *
+     * @param params the parameter set used to generate the keys.
+     * @param random the source of randomness.
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key pair generator.
+     *
+     * @since 1.2
+     */
+    public void initialize(AlgorithmParameterSpec params,
+                           SecureRandom random)
+        throws InvalidAlgorithmParameterException
+    {
+        // This does nothing, because either
+        // 1. the implementation object returned by getInstance() is an
+        //    instance of KeyPairGenerator which has its own
+        //    initialize(params, random) method, so the application would
+        //    be calling that method directly, or
+        // 2. the implementation returned by getInstance() is an instance
+        //    of Delegate, in which case initialize(params, random) is
+        //    overridden to call the corresponding SPI method.
+        // (This is a special case, because the API and SPI method have the
+        // same name.)
+    }
+
+    /**
+     * Generates a key pair.
+     *
+     * <p>If this KeyPairGenerator has not been initialized explicitly,
+     * provider-specific defaults will be used for the size and other
+     * (algorithm-specific) values of the generated keys.
+     *
+     * <p>This will generate a new key pair every time it is called.
+     *
+     * <p>This method is functionally equivalent to
+     * {@link #generateKeyPair() generateKeyPair}.
+     *
+     * @return the generated key pair
+     *
+     * @since 1.2
+     */
+    public final KeyPair genKeyPair() {
+        return generateKeyPair();
+    }
+
+    /**
+     * Generates a key pair.
+     *
+     * <p>If this KeyPairGenerator has not been initialized explicitly,
+     * provider-specific defaults will be used for the size and other
+     * (algorithm-specific) values of the generated keys.
+     *
+     * <p>This will generate a new key pair every time it is called.
+     *
+     * <p>This method is functionally equivalent to
+     * {@link #genKeyPair() genKeyPair}.
+     *
+     * @return the generated key pair
+     */
+    public KeyPair generateKeyPair() {
+        // This does nothing (except returning null), because either:
+        //
+        // 1. the implementation object returned by getInstance() is an
+        //    instance of KeyPairGenerator which has its own implementation
+        //    of generateKeyPair (overriding this one), so the application
+        //    would be calling that method directly, or
+        //
+        // 2. the implementation returned by getInstance() is an instance
+        //    of Delegate, in which case generateKeyPair is
+        //    overridden to invoke the corresponding SPI method.
+        //
+        // (This is a special case, because in JDK 1.1.x the generateKeyPair
+        // method was used both as an API and a SPI method.)
+        return null;
+    }
+
+
+    /*
+     * The following class allows providers to extend from KeyPairGeneratorSpi
+     * rather than from KeyPairGenerator. It represents a KeyPairGenerator
+     * with an encapsulated, provider-supplied SPI object (of type
+     * KeyPairGeneratorSpi).
+     * If the provider implementation is an instance of KeyPairGeneratorSpi,
+     * the getInstance() methods above return an instance of this class, with
+     * the SPI object encapsulated.
+     *
+     * Note: All SPI methods from the original KeyPairGenerator class have been
+     * moved up the hierarchy into a new class (KeyPairGeneratorSpi), which has
+     * been interposed in the hierarchy between the API (KeyPairGenerator)
+     * and its original parent (Object).
+     */
+
+    //
+    // error failover notes:
+    //
+    //  . we failover if the implementation throws an error during init
+    //    by retrying the init on other providers
+    //
+    //  . we also failover if the init succeeded but the subsequent call
+    //    to generateKeyPair() fails. In order for this to work, we need
+    //    to remember the parameters to the last successful call to init
+    //    and initialize() the next spi using them.
+    //
+    //  . although not specified, KeyPairGenerators could be thread safe,
+    //    so we make sure we do not interfere with that
+    //
+    //  . failover is not available, if:
+    //    . getInstance(algorithm, provider) was used
+    //    . a provider extends KeyPairGenerator rather than
+    //      KeyPairGeneratorSpi (JDK 1.1 style)
+    //    . once getProvider() is called
+    //
+
+    private static final class Delegate extends KeyPairGenerator {
+
+        // The provider implementation (delegate)
+        private volatile KeyPairGeneratorSpi spi;
+
+        private final Object lock = new Object();
+
+        private Iterator<Service> serviceIterator;
+
+        private final static int I_NONE   = 1;
+        private final static int I_SIZE   = 2;
+        private final static int I_PARAMS = 3;
+
+        private int initType;
+        private int initKeySize;
+        private AlgorithmParameterSpec initParams;
+        private SecureRandom initRandom;
+
+        // constructor
+        Delegate(KeyPairGeneratorSpi spi, String algorithm) {
+            super(algorithm);
+            this.spi = spi;
+        }
+
+        Delegate(Instance instance, Iterator<Service> serviceIterator,
+                String algorithm) {
+            super(algorithm);
+            spi = (KeyPairGeneratorSpi)instance.impl;
+            provider = instance.provider;
+            this.serviceIterator = serviceIterator;
+            initType = I_NONE;
+
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
+            if (!skipDebug && pdebug != null) {
+                pdebug.println("KeyPairGenerator." + algorithm +
+                    " algorithm from: " + provider.getName());
+            }
+            */
+        }
+
+        /**
+         * Update the active spi of this class and return the next
+         * implementation for failover. If no more implemenations are
+         * available, this method returns null. However, the active spi of
+         * this class is never set to null.
+         */
+        private KeyPairGeneratorSpi nextSpi(KeyPairGeneratorSpi oldSpi,
+                boolean reinit) {
+            synchronized (lock) {
+                // somebody else did a failover concurrently
+                // try that spi now
+                if ((oldSpi != null) && (oldSpi != spi)) {
+                    return spi;
+                }
+                if (serviceIterator == null) {
+                    return null;
+                }
+                while (serviceIterator.hasNext()) {
+                    Service s = serviceIterator.next();
+                    try {
+                        Object inst = s.newInstance(null);
+                        // ignore non-spis
+                        if (inst instanceof KeyPairGeneratorSpi == false) {
+                            continue;
+                        }
+                        if (inst instanceof KeyPairGenerator) {
+                            continue;
+                        }
+                        KeyPairGeneratorSpi spi = (KeyPairGeneratorSpi)inst;
+                        if (reinit) {
+                            if (initType == I_SIZE) {
+                                spi.initialize(initKeySize, initRandom);
+                            } else if (initType == I_PARAMS) {
+                                spi.initialize(initParams, initRandom);
+                            } else if (initType != I_NONE) {
+                                throw new AssertionError
+                                    ("KeyPairGenerator initType: " + initType);
+                            }
+                        }
+                        provider = s.getProvider();
+                        this.spi = spi;
+                        return spi;
+                    } catch (Exception e) {
+                        // ignore
+                    }
+                }
+                disableFailover();
+                return null;
+            }
+        }
+
+        void disableFailover() {
+            serviceIterator = null;
+            initType = 0;
+            initParams = null;
+            initRandom = null;
+        }
+
+        // engine method
+        public void initialize(int keysize, SecureRandom random) {
+            if (serviceIterator == null) {
+                spi.initialize(keysize, random);
+                return;
+            }
+            RuntimeException failure = null;
+            KeyPairGeneratorSpi mySpi = spi;
+            do {
+                try {
+                    mySpi.initialize(keysize, random);
+                    initType = I_SIZE;
+                    initKeySize = keysize;
+                    initParams = null;
+                    initRandom = random;
+                    return;
+                } catch (RuntimeException e) {
+                    if (failure == null) {
+                        failure = e;
+                    }
+                    mySpi = nextSpi(mySpi, false);
+                }
+            } while (mySpi != null);
+            throw failure;
+        }
+
+        // engine method
+        public void initialize(AlgorithmParameterSpec params,
+                SecureRandom random) throws InvalidAlgorithmParameterException {
+            if (serviceIterator == null) {
+                spi.initialize(params, random);
+                return;
+            }
+            Exception failure = null;
+            KeyPairGeneratorSpi mySpi = spi;
+            do {
+                try {
+                    mySpi.initialize(params, random);
+                    initType = I_PARAMS;
+                    initKeySize = 0;
+                    initParams = params;
+                    initRandom = random;
+                    return;
+                } catch (Exception e) {
+                    if (failure == null) {
+                        failure = e;
+                    }
+                    mySpi = nextSpi(mySpi, false);
+                }
+            } while (mySpi != null);
+            if (failure instanceof RuntimeException) {
+                throw (RuntimeException)failure;
+            }
+            // must be an InvalidAlgorithmParameterException
+            throw (InvalidAlgorithmParameterException)failure;
+        }
+
+        // engine method
+        public KeyPair generateKeyPair() {
+            if (serviceIterator == null) {
+                return spi.generateKeyPair();
+            }
+            RuntimeException failure = null;
+            KeyPairGeneratorSpi mySpi = spi;
+            do {
+                try {
+                    return mySpi.generateKeyPair();
+                } catch (RuntimeException e) {
+                    if (failure == null) {
+                        failure = e;
+                    }
+                    mySpi = nextSpi(mySpi, true);
+                }
+            } while (mySpi != null);
+            throw failure;
+        }
+    }
+
+}
diff --git a/java/security/KeyPairGeneratorSpi.java b/java/security/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..dfe8c04
--- /dev/null
+++ b/java/security/KeyPairGeneratorSpi.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * <p> This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code KeyPairGenerator} class, which is used to generate
+ * pairs of public and private keys.
+ *
+ * <p> All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a key pair generator for a particular algorithm.
+ *
+ * <p> In case the client does not explicitly initialize the KeyPairGenerator
+ * (via a call to an {@code initialize} method), each provider must
+ * supply (and document) a default initialization.
+ * For example, the <i>Sun</i> provider uses a default modulus size (keysize)
+ * of 1024 bits.
+ *
+ * @author Benjamin Renaud
+ *
+ *
+ * @see KeyPairGenerator
+ * @see java.security.spec.AlgorithmParameterSpec
+ */
+
+public abstract class KeyPairGeneratorSpi {
+
+    /**
+     * Initializes the key pair generator for a certain keysize, using
+     * the default parameter set.
+     *
+     * @param keysize the keysize. This is an
+     * algorithm-specific metric, such as modulus length, specified in
+     * number of bits.
+     *
+     * @param random the source of randomness for this generator.
+     *
+     * @exception InvalidParameterException if the {@code keysize} is not
+     * supported by this KeyPairGeneratorSpi object.
+     */
+    public abstract void initialize(int keysize, SecureRandom random);
+
+    /**
+     * Initializes the key pair generator using the specified parameter
+     * set and user-provided source of randomness.
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. (For backwards compatibility, it cannot be abstract.)
+     * It may be overridden by a provider to initialize the key pair
+     * generator. Such an override
+     * is expected to throw an InvalidAlgorithmParameterException if
+     * a parameter is inappropriate for this key pair generator.
+     * If this method is not overridden, it always throws an
+     * UnsupportedOperationException.
+     *
+     * @param params the parameter set used to generate the keys.
+     *
+     * @param random the source of randomness for this generator.
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this key pair generator.
+     *
+     * @since 1.2
+     */
+    public void initialize(AlgorithmParameterSpec params,
+                           SecureRandom random)
+        throws InvalidAlgorithmParameterException {
+            throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Generates a key pair. Unless an initialization method is called
+     * using a KeyPairGenerator interface, algorithm-specific defaults
+     * will be used. This will generate a new key pair every time it
+     * is called.
+     *
+     * @return the newly generated {@code KeyPair}
+     */
+    public abstract KeyPair generateKeyPair();
+}
diff --git a/java/security/KeyRep.java b/java/security/KeyRep.java
new file mode 100644
index 0000000..0b1412c
--- /dev/null
+++ b/java/security/KeyRep.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.util.Locale;
+
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Standardized representation for serialized Key objects.
+ *
+ * <p>
+ *
+ * Note that a serialized Key may contain sensitive information
+ * which should not be exposed in untrusted environments.  See the
+ * <a href="../../../platform/serialization/spec/security.html">
+ * Security Appendix</a>
+ * of the Serialization Specification for more information.
+ *
+ * @see Key
+ * @see KeyFactory
+ * @see javax.crypto.spec.SecretKeySpec
+ * @see java.security.spec.X509EncodedKeySpec
+ * @see java.security.spec.PKCS8EncodedKeySpec
+ *
+ * @since 1.5
+ */
+
+public class KeyRep implements Serializable {
+
+    private static final long serialVersionUID = -4757683898830641853L;
+
+    /**
+     * Key type.
+     *
+     * @since 1.5
+     */
+    public static enum Type {
+
+        /** Type for secret keys. */
+        SECRET,
+
+        /** Type for public keys. */
+        PUBLIC,
+
+        /** Type for private keys. */
+        PRIVATE,
+
+    }
+
+    private static final String PKCS8 = "PKCS#8";
+    private static final String X509 = "X.509";
+    private static final String RAW = "RAW";
+
+    /**
+     * Either one of Type.SECRET, Type.PUBLIC, or Type.PRIVATE
+     *
+     * @serial
+     */
+    private Type type;
+
+    /**
+     * The Key algorithm
+     *
+     * @serial
+     */
+    private String algorithm;
+
+    /**
+     * The Key encoding format
+     *
+     * @serial
+     */
+    private String format;
+
+    /**
+     * The encoded Key bytes
+     *
+     * @serial
+     */
+    private byte[] encoded;
+
+    /**
+     * Construct the alternate Key class.
+     *
+     * <p>
+     *
+     * @param type either one of Type.SECRET, Type.PUBLIC, or Type.PRIVATE
+     * @param algorithm the algorithm returned from
+     *          {@code Key.getAlgorithm()}
+     * @param format the encoding format returned from
+     *          {@code Key.getFormat()}
+     * @param encoded the encoded bytes returned from
+     *          {@code Key.getEncoded()}
+     *
+     * @exception NullPointerException
+     *          if type is {@code null},
+     *          if algorithm is {@code null},
+     *          if format is {@code null},
+     *          or if encoded is {@code null}
+     */
+    public KeyRep(Type type, String algorithm,
+                String format, byte[] encoded) {
+
+        if (type == null || algorithm == null ||
+            format == null || encoded == null) {
+            throw new NullPointerException("invalid null input(s)");
+        }
+
+        this.type = type;
+        this.algorithm = algorithm;
+        this.format = format.toUpperCase(Locale.ENGLISH);
+        this.encoded = encoded.clone();
+    }
+
+    /**
+     * Resolve the Key object.
+     *
+     * <p> This method supports three Type/format combinations:
+     * <ul>
+     * <li> Type.SECRET/"RAW" - returns a SecretKeySpec object
+     * constructed using encoded key bytes and algorithm
+     * <li> Type.PUBLIC/"X.509" - gets a KeyFactory instance for
+     * the key algorithm, constructs an X509EncodedKeySpec with the
+     * encoded key bytes, and generates a public key from the spec
+     * <li> Type.PRIVATE/"PKCS#8" - gets a KeyFactory instance for
+     * the key algorithm, constructs a PKCS8EncodedKeySpec with the
+     * encoded key bytes, and generates a private key from the spec
+     * </ul>
+     *
+     * <p>
+     *
+     * @return the resolved Key object
+     *
+     * @exception ObjectStreamException if the Type/format
+     *  combination is unrecognized, if the algorithm, key format, or
+     *  encoded key bytes are unrecognized/invalid, of if the
+     *  resolution of the key fails for any reason
+     */
+    protected Object readResolve() throws ObjectStreamException {
+        try {
+            if (type == Type.SECRET && RAW.equals(format)) {
+                return new SecretKeySpec(encoded, algorithm);
+            } else if (type == Type.PUBLIC && X509.equals(format)) {
+                KeyFactory f = KeyFactory.getInstance(algorithm);
+                return f.generatePublic(new X509EncodedKeySpec(encoded));
+            } else if (type == Type.PRIVATE && PKCS8.equals(format)) {
+                KeyFactory f = KeyFactory.getInstance(algorithm);
+                return f.generatePrivate(new PKCS8EncodedKeySpec(encoded));
+            } else {
+                throw new NotSerializableException
+                        ("unrecognized type/format combination: " +
+                        type + "/" + format);
+            }
+        } catch (NotSerializableException nse) {
+            throw nse;
+        } catch (Exception e) {
+            NotSerializableException nse = new NotSerializableException
+                                        ("java.security.Key: " +
+                                        "[" + type + "] " +
+                                        "[" + algorithm + "] " +
+                                        "[" + format + "]");
+            nse.initCause(e);
+            throw nse;
+        }
+    }
+}
diff --git a/java/security/KeyStore.java b/java/security/KeyStore.java
new file mode 100644
index 0000000..7781649
--- /dev/null
+++ b/java/security/KeyStore.java
@@ -0,0 +1,2040 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.net.URI;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.*;
+import javax.crypto.SecretKey;
+
+import javax.security.auth.DestroyFailedException;
+import javax.security.auth.callback.*;
+
+/**
+ * This class represents a storage facility for cryptographic
+ * keys and certificates.
+ *
+ * <p> A {@code KeyStore} manages different types of entries.
+ * Each type of entry implements the {@code KeyStore.Entry} interface.
+ * Three basic {@code KeyStore.Entry} implementations are provided:
+ *
+ * <ul>
+ * <li><b>KeyStore.PrivateKeyEntry</b>
+ * <p> This type of entry holds a cryptographic {@code PrivateKey},
+ * which is optionally stored in a protected format to prevent
+ * unauthorized access.  It is also accompanied by a certificate chain
+ * for the corresponding public key.
+ *
+ * <p> Private keys and certificate chains are used by a given entity for
+ * self-authentication. Applications for this authentication include software
+ * distribution organizations which sign JAR files as part of releasing
+ * and/or licensing software.
+ *
+ * <li><b>KeyStore.SecretKeyEntry</b>
+ * <p> This type of entry holds a cryptographic {@code SecretKey},
+ * which is optionally stored in a protected format to prevent
+ * unauthorized access.
+ *
+ * <li><b>KeyStore.TrustedCertificateEntry</b>
+ * <p> This type of entry contains a single public key {@code Certificate}
+ * belonging to another party. It is called a <i>trusted certificate</i>
+ * because the keystore owner trusts that the public key in the certificate
+ * indeed belongs to the identity identified by the <i>subject</i> (owner)
+ * of the certificate.
+ *
+ * <p>This type of entry can be used to authenticate other parties.
+ * </ul>
+ *
+ * <p> Each entry in a keystore is identified by an "alias" string. In the
+ * case of private keys and their associated certificate chains, these strings
+ * distinguish among the different ways in which the entity may authenticate
+ * itself. For example, the entity may authenticate itself using different
+ * certificate authorities, or using different public key algorithms.
+ *
+ * <p> Whether aliases are case sensitive is implementation dependent. In order
+ * to avoid problems, it is recommended not to use aliases in a KeyStore that
+ * only differ in case.
+ *
+ * <p> Whether keystores are persistent, and the mechanisms used by the
+ * keystore if it is persistent, are not specified here. This allows
+ * use of a variety of techniques for protecting sensitive (e.g., private or
+ * secret) keys. Smart cards or other integrated cryptographic engines
+ * (SafeKeyper) are one option, and simpler mechanisms such as files may also
+ * be used (in a variety of formats).
+ *
+ * <p> Typical ways to request a KeyStore object include
+ * relying on the default type and providing a specific keystore type.
+ *
+ * <ul>
+ * <li>To rely on the default type:
+ * <pre>
+ *    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ * </pre>
+ * The system will return a keystore implementation for the default type.
+ *
+ * <li>To provide a specific keystore type:
+ * <pre>
+ *      KeyStore ks = KeyStore.getInstance("JKS");
+ * </pre>
+ * The system will return the most preferred implementation of the
+ * specified keystore type available in the environment. <p>
+ * </ul>
+ *
+ * <p> Before a keystore can be accessed, it must be
+ * {@link #load(java.io.InputStream, char[]) loaded}.
+ * <pre>
+ *    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ *
+ *    // get user password and file input stream
+ *    char[] password = getPassword();
+ *
+ *    try (FileInputStream fis = new FileInputStream("keyStoreName")) {
+ *        ks.load(fis, password);
+ *    }
+ * </pre>
+ *
+ * To create an empty keystore using the above {@code load} method,
+ * pass {@code null} as the {@code InputStream} argument.
+ *
+ * <p> Once the keystore has been loaded, it is possible
+ * to read existing entries from the keystore, or to write new entries
+ * into the keystore:
+ * <pre>
+ *    KeyStore.ProtectionParameter protParam =
+ *        new KeyStore.PasswordProtection(password);
+ *
+ *    // get my private key
+ *    KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
+ *        ks.getEntry("privateKeyAlias", protParam);
+ *    PrivateKey myPrivateKey = pkEntry.getPrivateKey();
+ *
+ *    // save my secret key
+ *    javax.crypto.SecretKey mySecretKey;
+ *    KeyStore.SecretKeyEntry skEntry =
+ *        new KeyStore.SecretKeyEntry(mySecretKey);
+ *    ks.setEntry("secretKeyAlias", skEntry, protParam);
+ *
+ *    // store away the keystore
+ *    try (FileOutputStream fos = new FileOutputStream("newKeyStoreName")) {
+ *        ks.store(fos, password);
+ *    }
+ * </pre>
+ *
+ * Note that although the same password may be used to
+ * load the keystore, to protect the private key entry,
+ * to protect the secret key entry, and to store the keystore
+ * (as is shown in the sample code above),
+ * different passwords or other protection parameters
+ * may also be used.
+ *
+ * <p> Android provides the following <code>KeyStore</code> types:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>AndroidCAStore</td>
+ *       <td>14+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>AndroidKeyStore</td>
+ *       <td>18+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>BCPKCS12</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>BKS</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>BouncyCastle</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>PKCS12</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>PKCS12-DEF</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These types are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
+ * KeyStore section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Jan Luehe
+ *
+ * @see java.security.PrivateKey
+ * @see javax.crypto.SecretKey
+ * @see java.security.cert.Certificate
+ *
+ * @since 1.2
+ */
+
+public class KeyStore {
+
+    // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+    /*
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("keystore");
+    */
+    // END Android-removed: this debugging mechanism is not supported in Android.
+
+    /*
+     * Constant to lookup in the Security properties file to determine
+     * the default keystore type.
+     * In the Security properties file, the default keystore type is given as:
+     * <pre>
+     * keystore.type=jks
+     * </pre>
+     */
+    private static final String KEYSTORE_TYPE = "keystore.type";
+
+    // The keystore type
+    private String type;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation
+    private KeyStoreSpi keyStoreSpi;
+
+    // Has this keystore been initialized (loaded)?
+    private boolean initialized = false;
+
+    /**
+     * A marker interface for {@code KeyStore}
+     * {@link #load(KeyStore.LoadStoreParameter) load}
+     * and
+     * {@link #store(KeyStore.LoadStoreParameter) store}
+     * parameters.
+     *
+     * @since 1.5
+     */
+    public static interface LoadStoreParameter {
+        /**
+         * Gets the parameter used to protect keystore data.
+         *
+         * @return the parameter used to protect keystore data, or null
+         */
+        public ProtectionParameter getProtectionParameter();
+    }
+
+    /**
+     * A marker interface for keystore protection parameters.
+     *
+     * <p> The information stored in a {@code ProtectionParameter}
+     * object protects the contents of a keystore.
+     * For example, protection parameters may be used to check
+     * the integrity of keystore data, or to protect the
+     * confidentiality of sensitive keystore data
+     * (such as a {@code PrivateKey}).
+     *
+     * @since 1.5
+     */
+    public static interface ProtectionParameter { }
+
+    /**
+     * A password-based implementation of {@code ProtectionParameter}.
+     *
+     * @since 1.5
+     */
+    public static class PasswordProtection implements
+                ProtectionParameter, javax.security.auth.Destroyable {
+
+        private final char[] password;
+        private final String protectionAlgorithm;
+        private final AlgorithmParameterSpec protectionParameters;
+        private volatile boolean destroyed = false;
+
+        /**
+         * Creates a password parameter.
+         *
+         * <p> The specified {@code password} is cloned before it is stored
+         * in the new {@code PasswordProtection} object.
+         *
+         * @param password the password, which may be {@code null}
+         */
+        public PasswordProtection(char[] password) {
+            this.password = (password == null) ? null : password.clone();
+            this.protectionAlgorithm = null;
+            this.protectionParameters = null;
+        }
+
+        /**
+         * Creates a password parameter and specifies the protection algorithm
+         * and associated parameters to use when encrypting a keystore entry.
+         * <p>
+         * The specified {@code password} is cloned before it is stored in the
+         * new {@code PasswordProtection} object.
+         *
+         * @param password the password, which may be {@code null}
+         * @param protectionAlgorithm the encryption algorithm name, for
+         *     example, {@code PBEWithHmacSHA256AndAES_256}.
+         *     See the Cipher section in the <a href=
+         * "{@docRoot}/../technotes/guides/security/StandardNames.html#Cipher">
+         * Java Cryptography Architecture Standard Algorithm Name
+         * Documentation</a>
+         *     for information about standard encryption algorithm names.
+         * @param protectionParameters the encryption algorithm parameter
+         *     specification, which may be {@code null}
+         * @exception NullPointerException if {@code protectionAlgorithm} is
+         *     {@code null}
+         *
+         * @since 1.8
+         */
+        public PasswordProtection(char[] password, String protectionAlgorithm,
+            AlgorithmParameterSpec protectionParameters) {
+            if (protectionAlgorithm == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.password = (password == null) ? null : password.clone();
+            this.protectionAlgorithm = protectionAlgorithm;
+            this.protectionParameters = protectionParameters;
+        }
+
+        /**
+         * Gets the name of the protection algorithm.
+         * If none was set then the keystore provider will use its default
+         * protection algorithm. The name of the default protection algorithm
+         * for a given keystore type is set using the
+         * {@code 'keystore.<type>.keyProtectionAlgorithm'} security property.
+         * For example, the
+         * {@code keystore.PKCS12.keyProtectionAlgorithm} property stores the
+         * name of the default key protection algorithm used for PKCS12
+         * keystores. If the security property is not set, an
+         * implementation-specific algorithm will be used.
+         *
+         * @return the algorithm name, or {@code null} if none was set
+         *
+         * @since 1.8
+         */
+        public String getProtectionAlgorithm() {
+            return protectionAlgorithm;
+        }
+
+        /**
+         * Gets the parameters supplied for the protection algorithm.
+         *
+         * @return the algorithm parameter specification, or {@code  null},
+         *     if none was set
+         *
+         * @since 1.8
+         */
+        public AlgorithmParameterSpec getProtectionParameters() {
+            return protectionParameters;
+        }
+
+        /**
+         * Gets the password.
+         *
+         * <p>Note that this method returns a reference to the password.
+         * If a clone of the array is created it is the caller's
+         * responsibility to zero out the password information
+         * after it is no longer needed.
+         *
+         * @see #destroy()
+         * @return the password, which may be {@code null}
+         * @exception IllegalStateException if the password has
+         *              been cleared (destroyed)
+         */
+        public synchronized char[] getPassword() {
+            if (destroyed) {
+                throw new IllegalStateException("password has been cleared");
+            }
+            return password;
+        }
+
+        /**
+         * Clears the password.
+         *
+         * @exception DestroyFailedException if this method was unable
+         *      to clear the password
+         */
+        public synchronized void destroy() throws DestroyFailedException {
+            destroyed = true;
+            if (password != null) {
+                Arrays.fill(password, ' ');
+            }
+        }
+
+        /**
+         * Determines if password has been cleared.
+         *
+         * @return true if the password has been cleared, false otherwise
+         */
+        public synchronized boolean isDestroyed() {
+            return destroyed;
+        }
+    }
+
+    /**
+     * A ProtectionParameter encapsulating a CallbackHandler.
+     *
+     * @since 1.5
+     */
+    public static class CallbackHandlerProtection
+            implements ProtectionParameter {
+
+        private final CallbackHandler handler;
+
+        /**
+         * Constructs a new CallbackHandlerProtection from a
+         * CallbackHandler.
+         *
+         * @param handler the CallbackHandler
+         * @exception NullPointerException if handler is null
+         */
+        public CallbackHandlerProtection(CallbackHandler handler) {
+            if (handler == null) {
+                throw new NullPointerException("handler must not be null");
+            }
+            this.handler = handler;
+        }
+
+        /**
+         * Returns the CallbackHandler.
+         *
+         * @return the CallbackHandler.
+         */
+        public CallbackHandler getCallbackHandler() {
+            return handler;
+        }
+
+    }
+
+    /**
+     * A marker interface for {@code KeyStore} entry types.
+     *
+     * @since 1.5
+     */
+    public static interface Entry {
+
+        /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         * The default implementation returns an empty {@code Set}.
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        public default Set<Attribute> getAttributes() {
+            return Collections.<Attribute>emptySet();
+        }
+
+        /**
+         * An attribute associated with a keystore entry.
+         * It comprises a name and one or more values.
+         *
+         * @since 1.8
+         */
+        public interface Attribute {
+            /**
+             * Returns the attribute's name.
+             *
+             * @return the attribute name
+             */
+            public String getName();
+
+            /**
+             * Returns the attribute's value.
+             * Multi-valued attributes encode their values as a single string.
+             *
+             * @return the attribute value
+             */
+            public String getValue();
+        }
+    }
+
+    /**
+     * A {@code KeyStore} entry that holds a {@code PrivateKey}
+     * and corresponding certificate chain.
+     *
+     * @since 1.5
+     */
+    public static final class PrivateKeyEntry implements Entry {
+
+        private final PrivateKey privKey;
+        private final Certificate[] chain;
+        private final Set<Attribute> attributes;
+
+        /**
+         * Constructs a {@code PrivateKeyEntry} with a
+         * {@code PrivateKey} and corresponding certificate chain.
+         *
+         * <p> The specified {@code chain} is cloned before it is stored
+         * in the new {@code PrivateKeyEntry} object.
+         *
+         * @param privateKey the {@code PrivateKey}
+         * @param chain an array of {@code Certificate}s
+         *      representing the certificate chain.
+         *      The chain must be ordered and contain a
+         *      {@code Certificate} at index 0
+         *      corresponding to the private key.
+         *
+         * @exception NullPointerException if
+         *      {@code privateKey} or {@code chain}
+         *      is {@code null}
+         * @exception IllegalArgumentException if the specified chain has a
+         *      length of 0, if the specified chain does not contain
+         *      {@code Certificate}s of the same type,
+         *      or if the {@code PrivateKey} algorithm
+         *      does not match the algorithm of the {@code PublicKey}
+         *      in the end entity {@code Certificate} (at index 0)
+         */
+        public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
+            this(privateKey, chain, Collections.<Attribute>emptySet());
+        }
+
+        /**
+         * Constructs a {@code PrivateKeyEntry} with a {@code PrivateKey} and
+         * corresponding certificate chain and associated entry attributes.
+         *
+         * <p> The specified {@code chain} and {@code attributes} are cloned
+         * before they are stored in the new {@code PrivateKeyEntry} object.
+         *
+         * @param privateKey the {@code PrivateKey}
+         * @param chain an array of {@code Certificate}s
+         *      representing the certificate chain.
+         *      The chain must be ordered and contain a
+         *      {@code Certificate} at index 0
+         *      corresponding to the private key.
+         * @param attributes the attributes
+         *
+         * @exception NullPointerException if {@code privateKey}, {@code chain}
+         *      or {@code attributes} is {@code null}
+         * @exception IllegalArgumentException if the specified chain has a
+         *      length of 0, if the specified chain does not contain
+         *      {@code Certificate}s of the same type,
+         *      or if the {@code PrivateKey} algorithm
+         *      does not match the algorithm of the {@code PublicKey}
+         *      in the end entity {@code Certificate} (at index 0)
+         *
+         * @since 1.8
+         */
+        public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain,
+           Set<Attribute> attributes) {
+
+            if (privateKey == null || chain == null || attributes == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            if (chain.length == 0) {
+                throw new IllegalArgumentException
+                                ("invalid zero-length input chain");
+            }
+
+            Certificate[] clonedChain = chain.clone();
+            String certType = clonedChain[0].getType();
+            for (int i = 1; i < clonedChain.length; i++) {
+                if (!certType.equals(clonedChain[i].getType())) {
+                    throw new IllegalArgumentException
+                                ("chain does not contain certificates " +
+                                "of the same type");
+                }
+            }
+            if (!privateKey.getAlgorithm().equals
+                        (clonedChain[0].getPublicKey().getAlgorithm())) {
+                throw new IllegalArgumentException
+                                ("private key algorithm does not match " +
+                                "algorithm of public key in end entity " +
+                                "certificate (at index 0)");
+            }
+            this.privKey = privateKey;
+
+            if (clonedChain[0] instanceof X509Certificate &&
+                !(clonedChain instanceof X509Certificate[])) {
+
+                this.chain = new X509Certificate[clonedChain.length];
+                System.arraycopy(clonedChain, 0,
+                                this.chain, 0, clonedChain.length);
+            } else {
+                this.chain = clonedChain;
+            }
+
+            this.attributes =
+                Collections.unmodifiableSet(new HashSet<>(attributes));
+        }
+
+        /**
+         * Gets the {@code PrivateKey} from this entry.
+         *
+         * @return the {@code PrivateKey} from this entry
+         */
+        public PrivateKey getPrivateKey() {
+            return privKey;
+        }
+
+        /**
+         * Gets the {@code Certificate} chain from this entry.
+         *
+         * <p> The stored chain is cloned before being returned.
+         *
+         * @return an array of {@code Certificate}s corresponding
+         *      to the certificate chain for the public key.
+         *      If the certificates are of type X.509,
+         *      the runtime type of the returned array is
+         *      {@code X509Certificate[]}.
+         */
+        public Certificate[] getCertificateChain() {
+            return chain.clone();
+        }
+
+        /**
+         * Gets the end entity {@code Certificate}
+         * from the certificate chain in this entry.
+         *
+         * @return the end entity {@code Certificate} (at index 0)
+         *      from the certificate chain in this entry.
+         *      If the certificate is of type X.509,
+         *      the runtime type of the returned certificate is
+         *      {@code X509Certificate}.
+         */
+        public Certificate getCertificate() {
+            return chain[0];
+        }
+
+        /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        @Override
+        public Set<Attribute> getAttributes() {
+            return attributes;
+        }
+
+        /**
+         * Returns a string representation of this PrivateKeyEntry.
+         * @return a string representation of this PrivateKeyEntry.
+         */
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Private key entry and certificate chain with "
+                + chain.length + " elements:\r\n");
+            for (Certificate cert : chain) {
+                sb.append(cert);
+                sb.append("\r\n");
+            }
+            return sb.toString();
+        }
+
+    }
+
+    /**
+     * A {@code KeyStore} entry that holds a {@code SecretKey}.
+     *
+     * @since 1.5
+     */
+    public static final class SecretKeyEntry implements Entry {
+
+        private final SecretKey sKey;
+        private final Set<Attribute> attributes;
+
+        /**
+         * Constructs a {@code SecretKeyEntry} with a
+         * {@code SecretKey}.
+         *
+         * @param secretKey the {@code SecretKey}
+         *
+         * @exception NullPointerException if {@code secretKey}
+         *      is {@code null}
+         */
+        public SecretKeyEntry(SecretKey secretKey) {
+            if (secretKey == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.sKey = secretKey;
+            this.attributes = Collections.<Attribute>emptySet();
+        }
+
+        /**
+         * Constructs a {@code SecretKeyEntry} with a {@code SecretKey} and
+         * associated entry attributes.
+         *
+         * <p> The specified {@code attributes} is cloned before it is stored
+         * in the new {@code SecretKeyEntry} object.
+         *
+         * @param secretKey the {@code SecretKey}
+         * @param attributes the attributes
+         *
+         * @exception NullPointerException if {@code secretKey} or
+         *     {@code attributes} is {@code null}
+         *
+         * @since 1.8
+         */
+        public SecretKeyEntry(SecretKey secretKey, Set<Attribute> attributes) {
+
+            if (secretKey == null || attributes == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.sKey = secretKey;
+            this.attributes =
+                Collections.unmodifiableSet(new HashSet<>(attributes));
+        }
+
+        /**
+         * Gets the {@code SecretKey} from this entry.
+         *
+         * @return the {@code SecretKey} from this entry
+         */
+        public SecretKey getSecretKey() {
+            return sKey;
+        }
+
+        /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        @Override
+        public Set<Attribute> getAttributes() {
+            return attributes;
+        }
+
+        /**
+         * Returns a string representation of this SecretKeyEntry.
+         * @return a string representation of this SecretKeyEntry.
+         */
+        public String toString() {
+            return "Secret key entry with algorithm " + sKey.getAlgorithm();
+        }
+    }
+
+    /**
+     * A {@code KeyStore} entry that holds a trusted
+     * {@code Certificate}.
+     *
+     * @since 1.5
+     */
+    public static final class TrustedCertificateEntry implements Entry {
+
+        private final Certificate cert;
+        private final Set<Attribute> attributes;
+
+        /**
+         * Constructs a {@code TrustedCertificateEntry} with a
+         * trusted {@code Certificate}.
+         *
+         * @param trustedCert the trusted {@code Certificate}
+         *
+         * @exception NullPointerException if
+         *      {@code trustedCert} is {@code null}
+         */
+        public TrustedCertificateEntry(Certificate trustedCert) {
+            if (trustedCert == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.cert = trustedCert;
+            this.attributes = Collections.<Attribute>emptySet();
+        }
+
+        /**
+         * Constructs a {@code TrustedCertificateEntry} with a
+         * trusted {@code Certificate} and associated entry attributes.
+         *
+         * <p> The specified {@code attributes} is cloned before it is stored
+         * in the new {@code TrustedCertificateEntry} object.
+         *
+         * @param trustedCert the trusted {@code Certificate}
+         * @param attributes the attributes
+         *
+         * @exception NullPointerException if {@code trustedCert} or
+         *     {@code attributes} is {@code null}
+         *
+         * @since 1.8
+         */
+        public TrustedCertificateEntry(Certificate trustedCert,
+           Set<Attribute> attributes) {
+            if (trustedCert == null || attributes == null) {
+                throw new NullPointerException("invalid null input");
+            }
+            this.cert = trustedCert;
+            this.attributes =
+                Collections.unmodifiableSet(new HashSet<>(attributes));
+        }
+
+        /**
+         * Gets the trusted {@code Certficate} from this entry.
+         *
+         * @return the trusted {@code Certificate} from this entry
+         */
+        public Certificate getTrustedCertificate() {
+            return cert;
+        }
+
+        /**
+         * Retrieves the attributes associated with an entry.
+         * <p>
+         *
+         * @return an unmodifiable {@code Set} of attributes, possibly empty
+         *
+         * @since 1.8
+         */
+        @Override
+        public Set<Attribute> getAttributes() {
+            return attributes;
+        }
+
+        /**
+         * Returns a string representation of this TrustedCertificateEntry.
+         * @return a string representation of this TrustedCertificateEntry.
+         */
+        public String toString() {
+            return "Trusted certificate entry:\r\n" + cert.toString();
+        }
+    }
+
+    /**
+     * Creates a KeyStore object of the given type, and encapsulates the given
+     * provider implementation (SPI object) in it.
+     *
+     * @param keyStoreSpi the provider implementation.
+     * @param provider the provider.
+     * @param type the keystore type.
+     */
+    protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type)
+    {
+        this.keyStoreSpi = keyStoreSpi;
+        this.provider = provider;
+        this.type = type;
+
+        // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("KeyStore." + type.toUpperCase() + " type from: " +
+                this.provider.getName());
+        }
+        */
+        // END Android-removed: this debugging mechanism is not supported in Android.
+    }
+
+    /**
+     * Returns a keystore object of the specified type.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new KeyStore object encapsulating the
+     * KeyStoreSpi implementation from the first
+     * Provider that supports the specified type is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param type the type of keystore.
+     * See the KeyStore section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard keystore types.
+     *
+     * @return a keystore object of the specified type.
+     *
+     * @exception KeyStoreException if no Provider supports a
+     *          KeyStoreSpi implementation for the
+     *          specified type.
+     *
+     * @see Provider
+     */
+    public static KeyStore getInstance(String type)
+        throws KeyStoreException
+    {
+        try {
+            Object[] objs = Security.getImpl(type, "KeyStore", (String)null);
+            return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type);
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new KeyStoreException(type + " not found", nsae);
+        } catch (NoSuchProviderException nspe) {
+            throw new KeyStoreException(type + " not found", nspe);
+        }
+    }
+
+    /**
+     * Returns a keystore object of the specified type.
+     *
+     * <p> A new KeyStore object encapsulating the
+     * KeyStoreSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param type the type of keystore.
+     * See the KeyStore section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard keystore types.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a keystore object of the specified type.
+     *
+     * @exception KeyStoreException if a KeyStoreSpi
+     *          implementation for the specified type is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static KeyStore getInstance(String type, String provider)
+        throws KeyStoreException, NoSuchProviderException
+    {
+        if (provider == null || provider.length() == 0)
+            throw new IllegalArgumentException("missing provider");
+        try {
+            Object[] objs = Security.getImpl(type, "KeyStore", provider);
+            return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type);
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new KeyStoreException(type + " not found", nsae);
+        }
+    }
+
+    /**
+     * Returns a keystore object of the specified type.
+     *
+     * <p> A new KeyStore object encapsulating the
+     * KeyStoreSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param type the type of keystore.
+     * See the KeyStore section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyStore">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard keystore types.
+     *
+     * @param provider the provider.
+     *
+     * @return a keystore object of the specified type.
+     *
+     * @exception KeyStoreException if KeyStoreSpi
+     *          implementation for the specified type is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the specified provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static KeyStore getInstance(String type, Provider provider)
+        throws KeyStoreException
+    {
+        if (provider == null)
+            throw new IllegalArgumentException("missing provider");
+        try {
+            Object[] objs = Security.getImpl(type, "KeyStore", provider);
+            return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type);
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new KeyStoreException(type + " not found", nsae);
+        }
+    }
+
+    /**
+     * Returns the default keystore type as specified by the
+     * {@code keystore.type} security property, or the string
+     * {@literal "jks"} (acronym for {@literal "Java keystore"})
+     * if no such property exists.
+     *
+     * <p>The default keystore type can be used by applications that do not
+     * want to use a hard-coded keystore type when calling one of the
+     * {@code getInstance} methods, and want to provide a default keystore
+     * type in case a user does not specify its own.
+     *
+     * <p>The default keystore type can be changed by setting the value of the
+     * {@code keystore.type} security property to the desired keystore type.
+     *
+     * @return the default keystore type as specified by the
+     * {@code keystore.type} security property, or the string {@literal "jks"}
+     * if no such property exists.
+     * @see java.security.Security security properties
+     */
+    public final static String getDefaultType() {
+        String kstype;
+        kstype = AccessController.doPrivileged(new PrivilegedAction<String>() {
+            public String run() {
+                return Security.getProperty(KEYSTORE_TYPE);
+            }
+        });
+        if (kstype == null) {
+            kstype = "jks";
+        }
+        return kstype;
+    }
+
+    /**
+     * Returns the provider of this keystore.
+     *
+     * @return the provider of this keystore.
+     */
+    public final Provider getProvider()
+    {
+        return this.provider;
+    }
+
+    /**
+     * Returns the type of this keystore.
+     *
+     * @return the type of this keystore.
+     */
+    public final String getType()
+    {
+        return this.type;
+    }
+
+    /**
+     * Returns the key associated with the given alias, using the given
+     * password to recover it.  The key must have been associated with
+     * the alias by a call to {@code setKeyEntry},
+     * or by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry} or {@code SecretKeyEntry}.
+     *
+     * @param alias the alias name
+     * @param password the password for recovering the key
+     *
+     * @return the requested key, or null if the given alias does not exist
+     * or does not identify a key-related entry.
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     * @exception NoSuchAlgorithmException if the algorithm for recovering the
+     * key cannot be found
+     * @exception UnrecoverableKeyException if the key cannot be recovered
+     * (e.g., the given password is wrong).
+     */
+    public final Key getKey(String alias, char[] password)
+        throws KeyStoreException, NoSuchAlgorithmException,
+            UnrecoverableKeyException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineGetKey(alias, password);
+    }
+
+    /**
+     * Returns the certificate chain associated with the given alias.
+     * The certificate chain must have been associated with the alias
+     * by a call to {@code setKeyEntry},
+     * or by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry}.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate chain (ordered with the user's certificate first
+     * followed by zero or more certificate authorities), or null if the given alias
+     * does not exist or does not contain a certificate chain
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final Certificate[] getCertificateChain(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineGetCertificateChain(alias);
+    }
+
+    /**
+     * Returns the certificate associated with the given alias.
+     *
+     * <p> If the given alias name identifies an entry
+     * created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry},
+     * then the trusted certificate contained in that entry is returned.
+     *
+     * <p> If the given alias name identifies an entry
+     * created by a call to {@code setKeyEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry},
+     * then the first element of the certificate chain in that entry
+     * is returned.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate, or null if the given alias does not exist or
+     * does not contain a certificate.
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final Certificate getCertificate(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineGetCertificate(alias);
+    }
+
+    /**
+     * Returns the creation date of the entry identified by the given alias.
+     *
+     * @param alias the alias name
+     *
+     * @return the creation date of this entry, or null if the given alias does
+     * not exist
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final Date getCreationDate(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineGetCreationDate(alias);
+    }
+
+    /**
+     * Assigns the given key to the given alias, protecting it with the given
+     * password.
+     *
+     * <p>If the given key is of type {@code java.security.PrivateKey},
+     * it must be accompanied by a certificate chain certifying the
+     * corresponding public key.
+     *
+     * <p>If the given alias already exists, the keystore information
+     * associated with it is overridden by the given key (and possibly
+     * certificate chain).
+     *
+     * @param alias the alias name
+     * @param key the key to be associated with the alias
+     * @param password the password to protect the key
+     * @param chain the certificate chain for the corresponding public
+     * key (only required if the given key is of type
+     * {@code java.security.PrivateKey}).
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded), the given key cannot be protected, or this operation fails
+     * for some other reason
+     */
+    public final void setKeyEntry(String alias, Key key, char[] password,
+                                  Certificate[] chain)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        if ((key instanceof PrivateKey) &&
+            (chain == null || chain.length == 0)) {
+            throw new IllegalArgumentException("Private key must be "
+                                               + "accompanied by certificate "
+                                               + "chain");
+        }
+        keyStoreSpi.engineSetKeyEntry(alias, key, password, chain);
+    }
+
+    /**
+     * Assigns the given key (that has already been protected) to the given
+     * alias.
+     *
+     * <p>If the protected key is of type
+     * {@code java.security.PrivateKey}, it must be accompanied by a
+     * certificate chain certifying the corresponding public key. If the
+     * underlying keystore implementation is of type {@code jks},
+     * {@code key} must be encoded as an
+     * {@code EncryptedPrivateKeyInfo} as defined in the PKCS #8 standard.
+     *
+     * <p>If the given alias already exists, the keystore information
+     * associated with it is overridden by the given key (and possibly
+     * certificate chain).
+     *
+     * @param alias the alias name
+     * @param key the key (in protected format) to be associated with the alias
+     * @param chain the certificate chain for the corresponding public
+     *          key (only useful if the protected key is of type
+     *          {@code java.security.PrivateKey}).
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded), or if this operation fails for some other reason.
+     */
+    public final void setKeyEntry(String alias, byte[] key,
+                                  Certificate[] chain)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        keyStoreSpi.engineSetKeyEntry(alias, key, chain);
+    }
+
+    /**
+     * Assigns the given trusted certificate to the given alias.
+     *
+     * <p> If the given alias identifies an existing entry
+     * created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry},
+     * the trusted certificate in the existing entry
+     * is overridden by the given certificate.
+     *
+     * @param alias the alias name
+     * @param cert the certificate
+     *
+     * @exception KeyStoreException if the keystore has not been initialized,
+     * or the given alias already exists and does not identify an
+     * entry containing a trusted certificate,
+     * or this operation fails for some other reason.
+     */
+    public final void setCertificateEntry(String alias, Certificate cert)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        keyStoreSpi.engineSetCertificateEntry(alias, cert);
+    }
+
+    /**
+     * Deletes the entry identified by the given alias from this keystore.
+     *
+     * @param alias the alias name
+     *
+     * @exception KeyStoreException if the keystore has not been initialized,
+     * or if the entry cannot be removed.
+     */
+    public final void deleteEntry(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        keyStoreSpi.engineDeleteEntry(alias);
+    }
+
+    /**
+     * Lists all the alias names of this keystore.
+     *
+     * @return enumeration of the alias names
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final Enumeration<String> aliases()
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineAliases();
+    }
+
+    /**
+     * Checks if the given alias exists in this keystore.
+     *
+     * @param alias the alias name
+     *
+     * @return true if the alias exists, false otherwise
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final boolean containsAlias(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineContainsAlias(alias);
+    }
+
+    /**
+     * Retrieves the number of entries in this keystore.
+     *
+     * @return the number of entries in this keystore
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final int size()
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineSize();
+    }
+
+    /**
+     * Returns true if the entry identified by the given alias
+     * was created by a call to {@code setKeyEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry} or a {@code SecretKeyEntry}.
+     *
+     * @param alias the alias for the keystore entry to be checked
+     *
+     * @return true if the entry identified by the given alias is a
+     * key-related entry, false otherwise.
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final boolean isKeyEntry(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineIsKeyEntry(alias);
+    }
+
+    /**
+     * Returns true if the entry identified by the given alias
+     * was created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry}.
+     *
+     * @param alias the alias for the keystore entry to be checked
+     *
+     * @return true if the entry identified by the given alias contains a
+     * trusted certificate, false otherwise.
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final boolean isCertificateEntry(String alias)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineIsCertificateEntry(alias);
+    }
+
+    /**
+     * Returns the (alias) name of the first keystore entry whose certificate
+     * matches the given certificate.
+     *
+     * <p> This method attempts to match the given certificate with each
+     * keystore entry. If the entry being considered was
+     * created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry},
+     * then the given certificate is compared to that entry's certificate.
+     *
+     * <p> If the entry being considered was
+     * created by a call to {@code setKeyEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry},
+     * then the given certificate is compared to the first
+     * element of that entry's certificate chain.
+     *
+     * @param cert the certificate to match with.
+     *
+     * @return the alias name of the first entry with a matching certificate,
+     * or null if no such entry exists in this keystore.
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     */
+    public final String getCertificateAlias(Certificate cert)
+        throws KeyStoreException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineGetCertificateAlias(cert);
+    }
+
+    /**
+     * Stores this keystore to the given output stream, and protects its
+     * integrity with the given password.
+     *
+     * @param stream the output stream to which this keystore is written.
+     * @param password the password to generate the keystore integrity check
+     *
+     * @exception KeyStoreException if the keystore has not been initialized
+     * (loaded).
+     * @exception IOException if there was an I/O problem with data
+     * @exception NoSuchAlgorithmException if the appropriate data integrity
+     * algorithm could not be found
+     * @exception CertificateException if any of the certificates included in
+     * the keystore data could not be stored
+     */
+    public final void store(OutputStream stream, char[] password)
+        throws KeyStoreException, IOException, NoSuchAlgorithmException,
+            CertificateException
+    {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        keyStoreSpi.engineStore(stream, password);
+    }
+
+    /**
+     * Stores this keystore using the given {@code LoadStoreParameter}.
+     *
+     * @param param the {@code LoadStoreParameter}
+     *          that specifies how to store the keystore,
+     *          which may be {@code null}
+     *
+     * @exception IllegalArgumentException if the given
+     *          {@code LoadStoreParameter}
+     *          input is not recognized
+     * @exception KeyStoreException if the keystore has not been initialized
+     *          (loaded)
+     * @exception IOException if there was an I/O problem with data
+     * @exception NoSuchAlgorithmException if the appropriate data integrity
+     *          algorithm could not be found
+     * @exception CertificateException if any of the certificates included in
+     *          the keystore data could not be stored
+     *
+     * @since 1.5
+     */
+    public final void store(LoadStoreParameter param)
+                throws KeyStoreException, IOException,
+                NoSuchAlgorithmException, CertificateException {
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        keyStoreSpi.engineStore(param);
+    }
+
+    /**
+     * Loads this KeyStore from the given input stream.
+     *
+     * <p>A password may be given to unlock the keystore
+     * (e.g. the keystore resides on a hardware token device),
+     * or to check the integrity of the keystore data.
+     * If a password is not given for integrity checking,
+     * then integrity checking is not performed.
+     *
+     * <p>In order to create an empty keystore, or if the keystore cannot
+     * be initialized from a stream, pass {@code null}
+     * as the {@code stream} argument.
+     *
+     * <p> Note that if this keystore has already been loaded, it is
+     * reinitialized and loaded again from the given input stream.
+     *
+     * @param stream the input stream from which the keystore is loaded,
+     * or {@code null}
+     * @param password the password used to check the integrity of
+     * the keystore, the password used to unlock the keystore,
+     * or {@code null}
+     *
+     * @exception IOException if there is an I/O or format problem with the
+     * keystore data, if a password is required but not given,
+     * or if the given password was incorrect. If the error is due to a
+     * wrong password, the {@link Throwable#getCause cause} of the
+     * {@code IOException} should be an
+     * {@code UnrecoverableKeyException}
+     * @exception NoSuchAlgorithmException if the algorithm used to check
+     * the integrity of the keystore cannot be found
+     * @exception CertificateException if any of the certificates in the
+     * keystore could not be loaded
+     */
+    public final void load(InputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException
+    {
+        keyStoreSpi.engineLoad(stream, password);
+        initialized = true;
+    }
+
+    /**
+     * Loads this keystore using the given {@code LoadStoreParameter}.
+     *
+     * <p> Note that if this KeyStore has already been loaded, it is
+     * reinitialized and loaded again from the given parameter.
+     *
+     * @param param the {@code LoadStoreParameter}
+     *          that specifies how to load the keystore,
+     *          which may be {@code null}
+     *
+     * @exception IllegalArgumentException if the given
+     *          {@code LoadStoreParameter}
+     *          input is not recognized
+     * @exception IOException if there is an I/O or format problem with the
+     *          keystore data. If the error is due to an incorrect
+     *         {@code ProtectionParameter} (e.g. wrong password)
+     *         the {@link Throwable#getCause cause} of the
+     *         {@code IOException} should be an
+     *         {@code UnrecoverableKeyException}
+     * @exception NoSuchAlgorithmException if the algorithm used to check
+     *          the integrity of the keystore cannot be found
+     * @exception CertificateException if any of the certificates in the
+     *          keystore could not be loaded
+     *
+     * @since 1.5
+     */
+    public final void load(LoadStoreParameter param)
+                throws IOException, NoSuchAlgorithmException,
+                CertificateException {
+
+        keyStoreSpi.engineLoad(param);
+        initialized = true;
+    }
+
+    /**
+     * Gets a keystore {@code Entry} for the specified alias
+     * with the specified protection parameter.
+     *
+     * @param alias get the keystore {@code Entry} for this alias
+     * @param protParam the {@code ProtectionParameter}
+     *          used to protect the {@code Entry},
+     *          which may be {@code null}
+     *
+     * @return the keystore {@code Entry} for the specified alias,
+     *          or {@code null} if there is no such entry
+     *
+     * @exception NullPointerException if
+     *          {@code alias} is {@code null}
+     * @exception NoSuchAlgorithmException if the algorithm for recovering the
+     *          entry cannot be found
+     * @exception UnrecoverableEntryException if the specified
+     *          {@code protParam} were insufficient or invalid
+     * @exception UnrecoverableKeyException if the entry is a
+     *          {@code PrivateKeyEntry} or {@code SecretKeyEntry}
+     *          and the specified {@code protParam} does not contain
+     *          the information needed to recover the key (e.g. wrong password)
+     * @exception KeyStoreException if the keystore has not been initialized
+     *          (loaded).
+     * @see #setEntry(String, KeyStore.Entry, KeyStore.ProtectionParameter)
+     *
+     * @since 1.5
+     */
+    public final Entry getEntry(String alias, ProtectionParameter protParam)
+                throws NoSuchAlgorithmException, UnrecoverableEntryException,
+                KeyStoreException {
+
+        if (alias == null) {
+            throw new NullPointerException("invalid null input");
+        }
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineGetEntry(alias, protParam);
+    }
+
+    /**
+     * Saves a keystore {@code Entry} under the specified alias.
+     * The protection parameter is used to protect the
+     * {@code Entry}.
+     *
+     * <p> If an entry already exists for the specified alias,
+     * it is overridden.
+     *
+     * @param alias save the keystore {@code Entry} under this alias
+     * @param entry the {@code Entry} to save
+     * @param protParam the {@code ProtectionParameter}
+     *          used to protect the {@code Entry},
+     *          which may be {@code null}
+     *
+     * @exception NullPointerException if
+     *          {@code alias} or {@code entry}
+     *          is {@code null}
+     * @exception KeyStoreException if the keystore has not been initialized
+     *          (loaded), or if this operation fails for some other reason
+     *
+     * @see #getEntry(String, KeyStore.ProtectionParameter)
+     *
+     * @since 1.5
+     */
+    public final void setEntry(String alias, Entry entry,
+                        ProtectionParameter protParam)
+                throws KeyStoreException {
+        if (alias == null || entry == null) {
+            throw new NullPointerException("invalid null input");
+        }
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        keyStoreSpi.engineSetEntry(alias, entry, protParam);
+    }
+
+    /**
+     * Determines if the keystore {@code Entry} for the specified
+     * {@code alias} is an instance or subclass of the specified
+     * {@code entryClass}.
+     *
+     * @param alias the alias name
+     * @param entryClass the entry class
+     *
+     * @return true if the keystore {@code Entry} for the specified
+     *          {@code alias} is an instance or subclass of the
+     *          specified {@code entryClass}, false otherwise
+     *
+     * @exception NullPointerException if
+     *          {@code alias} or {@code entryClass}
+     *          is {@code null}
+     * @exception KeyStoreException if the keystore has not been
+     *          initialized (loaded)
+     *
+     * @since 1.5
+     */
+    public final boolean
+        entryInstanceOf(String alias,
+                        Class<? extends KeyStore.Entry> entryClass)
+        throws KeyStoreException
+    {
+
+        if (alias == null || entryClass == null) {
+            throw new NullPointerException("invalid null input");
+        }
+        if (!initialized) {
+            throw new KeyStoreException("Uninitialized keystore");
+        }
+        return keyStoreSpi.engineEntryInstanceOf(alias, entryClass);
+    }
+
+    /**
+     * A description of a to-be-instantiated KeyStore object.
+     *
+     * <p>An instance of this class encapsulates the information needed to
+     * instantiate and initialize a KeyStore object. That process is
+     * triggered when the {@linkplain #getKeyStore} method is called.
+     *
+     * <p>This makes it possible to decouple configuration from KeyStore
+     * object creation and e.g. delay a password prompt until it is
+     * needed.
+     *
+     * @see KeyStore
+     * @see javax.net.ssl.KeyStoreBuilderParameters
+     * @since 1.5
+     */
+    public static abstract class Builder {
+
+        // maximum times to try the callbackhandler if the password is wrong
+        static final int MAX_CALLBACK_TRIES = 3;
+
+        /**
+         * Construct a new Builder.
+         */
+        protected Builder() {
+            // empty
+        }
+
+        /**
+         * Returns the KeyStore described by this object.
+         *
+         * @return the {@code KeyStore} described by this object
+         * @exception KeyStoreException if an error occurred during the
+         *   operation, for example if the KeyStore could not be
+         *   instantiated or loaded
+         */
+        public abstract KeyStore getKeyStore() throws KeyStoreException;
+
+        /**
+         * Returns the ProtectionParameters that should be used to obtain
+         * the {@link KeyStore.Entry Entry} with the given alias.
+         * The {@code getKeyStore} method must be invoked before this
+         * method may be called.
+         *
+         * @return the ProtectionParameters that should be used to obtain
+         *   the {@link KeyStore.Entry Entry} with the given alias.
+         * @param alias the alias of the KeyStore entry
+         * @throws NullPointerException if alias is null
+         * @throws KeyStoreException if an error occurred during the
+         *   operation
+         * @throws IllegalStateException if the getKeyStore method has
+         *   not been invoked prior to calling this method
+         */
+        public abstract ProtectionParameter getProtectionParameter(String alias)
+            throws KeyStoreException;
+
+        /**
+         * Returns a new Builder that encapsulates the given KeyStore.
+         * The {@linkplain #getKeyStore} method of the returned object
+         * will return {@code keyStore}, the {@linkplain
+         * #getProtectionParameter getProtectionParameter()} method will
+         * return {@code protectionParameters}.
+         *
+         * <p> This is useful if an existing KeyStore object needs to be
+         * used with Builder-based APIs.
+         *
+         * @return a new Builder object
+         * @param keyStore the KeyStore to be encapsulated
+         * @param protectionParameter the ProtectionParameter used to
+         *   protect the KeyStore entries
+         * @throws NullPointerException if keyStore or
+         *   protectionParameters is null
+         * @throws IllegalArgumentException if the keyStore has not been
+         *   initialized
+         */
+        public static Builder newInstance(final KeyStore keyStore,
+                final ProtectionParameter protectionParameter) {
+            if ((keyStore == null) || (protectionParameter == null)) {
+                throw new NullPointerException();
+            }
+            if (keyStore.initialized == false) {
+                throw new IllegalArgumentException("KeyStore not initialized");
+            }
+            return new Builder() {
+                private volatile boolean getCalled;
+
+                public KeyStore getKeyStore() {
+                    getCalled = true;
+                    return keyStore;
+                }
+
+                public ProtectionParameter getProtectionParameter(String alias)
+                {
+                    if (alias == null) {
+                        throw new NullPointerException();
+                    }
+                    if (getCalled == false) {
+                        throw new IllegalStateException
+                            ("getKeyStore() must be called first");
+                    }
+                    return protectionParameter;
+                }
+            };
+        }
+
+        /**
+         * Returns a new Builder object.
+         *
+         * <p>The first call to the {@link #getKeyStore} method on the returned
+         * builder will create a KeyStore of type {@code type} and call
+         * its {@link KeyStore#load load()} method.
+         * The {@code inputStream} argument is constructed from
+         * {@code file}.
+         * If {@code protection} is a
+         * {@code PasswordProtection}, the password is obtained by
+         * calling the {@code getPassword} method.
+         * Otherwise, if {@code protection} is a
+         * {@code CallbackHandlerProtection}, the password is obtained
+         * by invoking the CallbackHandler.
+         *
+         * <p>Subsequent calls to {@link #getKeyStore} return the same object
+         * as the initial call. If the initial call to failed with a
+         * KeyStoreException, subsequent calls also throw a
+         * KeyStoreException.
+         *
+         * <p>The KeyStore is instantiated from {@code provider} if
+         * non-null. Otherwise, all installed providers are searched.
+         *
+         * <p>Calls to {@link #getProtectionParameter getProtectionParameter()}
+         * will return a {@link KeyStore.PasswordProtection PasswordProtection}
+         * object encapsulating the password that was used to invoke the
+         * {@code load} method.
+         *
+         * <p><em>Note</em> that the {@link #getKeyStore} method is executed
+         * within the {@link AccessControlContext} of the code invoking this
+         * method.
+         *
+         * @return a new Builder object
+         * @param type the type of KeyStore to be constructed
+         * @param provider the provider from which the KeyStore is to
+         *   be instantiated (or null)
+         * @param file the File that contains the KeyStore data
+         * @param protection the ProtectionParameter securing the KeyStore data
+         * @throws NullPointerException if type, file or protection is null
+         * @throws IllegalArgumentException if protection is not an instance
+         *   of either PasswordProtection or CallbackHandlerProtection; or
+         *   if file does not exist or does not refer to a normal file
+         */
+        public static Builder newInstance(String type, Provider provider,
+                File file, ProtectionParameter protection) {
+            if ((type == null) || (file == null) || (protection == null)) {
+                throw new NullPointerException();
+            }
+            if ((protection instanceof PasswordProtection == false) &&
+                (protection instanceof CallbackHandlerProtection == false)) {
+                throw new IllegalArgumentException
+                ("Protection must be PasswordProtection or " +
+                 "CallbackHandlerProtection");
+            }
+            if (file.isFile() == false) {
+                throw new IllegalArgumentException
+                    ("File does not exist or it does not refer " +
+                     "to a normal file: " + file);
+            }
+            return new FileBuilder(type, provider, file, protection,
+                AccessController.getContext());
+        }
+
+        private static final class FileBuilder extends Builder {
+
+            private final String type;
+            private final Provider provider;
+            private final File file;
+            private ProtectionParameter protection;
+            private ProtectionParameter keyProtection;
+            private final AccessControlContext context;
+
+            private KeyStore keyStore;
+
+            private Throwable oldException;
+
+            FileBuilder(String type, Provider provider, File file,
+                    ProtectionParameter protection,
+                    AccessControlContext context) {
+                this.type = type;
+                this.provider = provider;
+                this.file = file;
+                this.protection = protection;
+                this.context = context;
+            }
+
+            public synchronized KeyStore getKeyStore() throws KeyStoreException
+            {
+                if (keyStore != null) {
+                    return keyStore;
+                }
+                if (oldException != null) {
+                    throw new KeyStoreException
+                        ("Previous KeyStore instantiation failed",
+                         oldException);
+                }
+                PrivilegedExceptionAction<KeyStore> action =
+                        new PrivilegedExceptionAction<KeyStore>() {
+                    public KeyStore run() throws Exception {
+                        if (protection instanceof CallbackHandlerProtection == false) {
+                            return run0();
+                        }
+                        // when using a CallbackHandler,
+                        // reprompt if the password is wrong
+                        int tries = 0;
+                        while (true) {
+                            tries++;
+                            try {
+                                return run0();
+                            } catch (IOException e) {
+                                if ((tries < MAX_CALLBACK_TRIES)
+                                        && (e.getCause() instanceof UnrecoverableKeyException)) {
+                                    continue;
+                                }
+                                throw e;
+                            }
+                        }
+                    }
+                    public KeyStore run0() throws Exception {
+                        KeyStore ks;
+                        if (provider == null) {
+                            ks = KeyStore.getInstance(type);
+                        } else {
+                            ks = KeyStore.getInstance(type, provider);
+                        }
+                        InputStream in = null;
+                        char[] password = null;
+                        try {
+                            in = new FileInputStream(file);
+                            if (protection instanceof PasswordProtection) {
+                                password =
+                                ((PasswordProtection)protection).getPassword();
+                                keyProtection = protection;
+                            } else {
+                                CallbackHandler handler =
+                                    ((CallbackHandlerProtection)protection)
+                                    .getCallbackHandler();
+                                PasswordCallback callback = new PasswordCallback
+                                    ("Password for keystore " + file.getName(),
+                                    false);
+                                handler.handle(new Callback[] {callback});
+                                password = callback.getPassword();
+                                if (password == null) {
+                                    throw new KeyStoreException("No password" +
+                                                                " provided");
+                                }
+                                callback.clearPassword();
+                                keyProtection = new PasswordProtection(password);
+                            }
+                            ks.load(in, password);
+                            return ks;
+                        } finally {
+                            if (in != null) {
+                                in.close();
+                            }
+                        }
+                    }
+                };
+                try {
+                    keyStore = AccessController.doPrivileged(action, context);
+                    return keyStore;
+                } catch (PrivilegedActionException e) {
+                    oldException = e.getCause();
+                    throw new KeyStoreException
+                        ("KeyStore instantiation failed", oldException);
+                }
+            }
+
+            public synchronized ProtectionParameter
+                        getProtectionParameter(String alias) {
+                if (alias == null) {
+                    throw new NullPointerException();
+                }
+                if (keyStore == null) {
+                    throw new IllegalStateException
+                        ("getKeyStore() must be called first");
+                }
+                return keyProtection;
+            }
+        }
+
+        /**
+         * Returns a new Builder object.
+         *
+         * <p>Each call to the {@link #getKeyStore} method on the returned
+         * builder will return a new KeyStore object of type {@code type}.
+         * Its {@link KeyStore#load(KeyStore.LoadStoreParameter) load()}
+         * method is invoked using a
+         * {@code LoadStoreParameter} that encapsulates
+         * {@code protection}.
+         *
+         * <p>The KeyStore is instantiated from {@code provider} if
+         * non-null. Otherwise, all installed providers are searched.
+         *
+         * <p>Calls to {@link #getProtectionParameter getProtectionParameter()}
+         * will return {@code protection}.
+         *
+         * <p><em>Note</em> that the {@link #getKeyStore} method is executed
+         * within the {@link AccessControlContext} of the code invoking this
+         * method.
+         *
+         * @return a new Builder object
+         * @param type the type of KeyStore to be constructed
+         * @param provider the provider from which the KeyStore is to
+         *   be instantiated (or null)
+         * @param protection the ProtectionParameter securing the Keystore
+         * @throws NullPointerException if type or protection is null
+         */
+        public static Builder newInstance(final String type,
+                final Provider provider, final ProtectionParameter protection) {
+            if ((type == null) || (protection == null)) {
+                throw new NullPointerException();
+            }
+            final AccessControlContext context = AccessController.getContext();
+            return new Builder() {
+                private volatile boolean getCalled;
+                private IOException oldException;
+
+                private final PrivilegedExceptionAction<KeyStore> action
+                        = new PrivilegedExceptionAction<KeyStore>() {
+
+                    public KeyStore run() throws Exception {
+                        KeyStore ks;
+                        if (provider == null) {
+                            ks = KeyStore.getInstance(type);
+                        } else {
+                            ks = KeyStore.getInstance(type, provider);
+                        }
+                        LoadStoreParameter param = new SimpleLoadStoreParameter(protection);
+                        if (protection instanceof CallbackHandlerProtection == false) {
+                            ks.load(param);
+                        } else {
+                            // when using a CallbackHandler,
+                            // reprompt if the password is wrong
+                            int tries = 0;
+                            while (true) {
+                                tries++;
+                                try {
+                                    ks.load(param);
+                                    break;
+                                } catch (IOException e) {
+                                    if (e.getCause() instanceof UnrecoverableKeyException) {
+                                        if (tries < MAX_CALLBACK_TRIES) {
+                                            continue;
+                                        } else {
+                                            oldException = e;
+                                        }
+                                    }
+                                    throw e;
+                                }
+                            }
+                        }
+                        getCalled = true;
+                        return ks;
+                    }
+                };
+
+                public synchronized KeyStore getKeyStore()
+                        throws KeyStoreException {
+                    if (oldException != null) {
+                        throw new KeyStoreException
+                            ("Previous KeyStore instantiation failed",
+                             oldException);
+                    }
+                    try {
+                        return AccessController.doPrivileged(action, context);
+                    } catch (PrivilegedActionException e) {
+                        Throwable cause = e.getCause();
+                        throw new KeyStoreException
+                            ("KeyStore instantiation failed", cause);
+                    }
+                }
+
+                public ProtectionParameter getProtectionParameter(String alias)
+                {
+                    if (alias == null) {
+                        throw new NullPointerException();
+                    }
+                    if (getCalled == false) {
+                        throw new IllegalStateException
+                            ("getKeyStore() must be called first");
+                    }
+                    return protection;
+                }
+            };
+        }
+
+    }
+
+    static class SimpleLoadStoreParameter implements LoadStoreParameter {
+
+        private final ProtectionParameter protection;
+
+        SimpleLoadStoreParameter(ProtectionParameter protection) {
+            this.protection = protection;
+        }
+
+        public ProtectionParameter getProtectionParameter() {
+            return protection;
+        }
+    }
+
+}
diff --git a/java/security/KeyStoreException.java b/java/security/KeyStoreException.java
new file mode 100644
index 0000000..cf56d6a
--- /dev/null
+++ b/java/security/KeyStoreException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This is the generic KeyStore exception.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @since 1.2
+ */
+
+public class KeyStoreException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -1119353179322377262L;
+
+    /**
+     * Constructs a KeyStoreException with no detail message.  (A
+     * detail message is a String that describes this particular
+     * exception.)
+     */
+    public KeyStoreException() {
+        super();
+    }
+
+    /**
+     * Constructs a KeyStoreException with the specified detail
+     * message.  (A detail message is a String that describes this
+     * particular exception.)
+     *
+     * @param msg the detail message.
+     */
+   public KeyStoreException(String msg) {
+       super(msg);
+    }
+
+    /**
+     * Creates a {@code KeyStoreException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public KeyStoreException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code KeyStoreException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public KeyStoreException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/KeyStoreSpi.java b/java/security/KeyStoreSpi.java
new file mode 100644
index 0000000..531a983
--- /dev/null
+++ b/java/security/KeyStoreSpi.java
@@ -0,0 +1,587 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.util.*;
+import java.security.KeyStore;
+import java.security.KeyStore.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+
+import javax.crypto.SecretKey;
+
+import javax.security.auth.callback.*;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code KeyStore} class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a keystore for a particular keystore type.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see KeyStore
+ *
+ * @since 1.2
+ */
+
+public abstract class KeyStoreSpi {
+
+    /**
+     * Returns the key associated with the given alias, using the given
+     * password to recover it.  The key must have been associated with
+     * the alias by a call to {@code setKeyEntry},
+     * or by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry} or {@code SecretKeyEntry}.
+     *
+     * @param alias the alias name
+     * @param password the password for recovering the key
+     *
+     * @return the requested key, or null if the given alias does not exist
+     * or does not identify a key-related entry.
+     *
+     * @exception NoSuchAlgorithmException if the algorithm for recovering the
+     * key cannot be found
+     * @exception UnrecoverableKeyException if the key cannot be recovered
+     * (e.g., the given password is wrong).
+     */
+    public abstract Key engineGetKey(String alias, char[] password)
+        throws NoSuchAlgorithmException, UnrecoverableKeyException;
+
+    /**
+     * Returns the certificate chain associated with the given alias.
+     * The certificate chain must have been associated with the alias
+     * by a call to {@code setKeyEntry},
+     * or by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry}.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate chain (ordered with the user's certificate first
+     * and the root certificate authority last), or null if the given alias
+     * does not exist or does not contain a certificate chain
+     */
+    public abstract Certificate[] engineGetCertificateChain(String alias);
+
+    /**
+     * Returns the certificate associated with the given alias.
+     *
+     * <p> If the given alias name identifies an entry
+     * created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry},
+     * then the trusted certificate contained in that entry is returned.
+     *
+     * <p> If the given alias name identifies an entry
+     * created by a call to {@code setKeyEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry},
+     * then the first element of the certificate chain in that entry
+     * (if a chain exists) is returned.
+     *
+     * @param alias the alias name
+     *
+     * @return the certificate, or null if the given alias does not exist or
+     * does not contain a certificate.
+     */
+    public abstract Certificate engineGetCertificate(String alias);
+
+    /**
+     * Returns the creation date of the entry identified by the given alias.
+     *
+     * @param alias the alias name
+     *
+     * @return the creation date of this entry, or null if the given alias does
+     * not exist
+     */
+    public abstract Date engineGetCreationDate(String alias);
+
+    /**
+     * Assigns the given key to the given alias, protecting it with the given
+     * password.
+     *
+     * <p>If the given key is of type {@code java.security.PrivateKey},
+     * it must be accompanied by a certificate chain certifying the
+     * corresponding public key.
+     *
+     * <p>If the given alias already exists, the keystore information
+     * associated with it is overridden by the given key (and possibly
+     * certificate chain).
+     *
+     * @param alias the alias name
+     * @param key the key to be associated with the alias
+     * @param password the password to protect the key
+     * @param chain the certificate chain for the corresponding public
+     * key (only required if the given key is of type
+     * {@code java.security.PrivateKey}).
+     *
+     * @exception KeyStoreException if the given key cannot be protected, or
+     * this operation fails for some other reason
+     */
+    public abstract void engineSetKeyEntry(String alias, Key key,
+                                           char[] password,
+                                           Certificate[] chain)
+        throws KeyStoreException;
+
+    /**
+     * Assigns the given key (that has already been protected) to the given
+     * alias.
+     *
+     * <p>If the protected key is of type
+     * {@code java.security.PrivateKey},
+     * it must be accompanied by a certificate chain certifying the
+     * corresponding public key.
+     *
+     * <p>If the given alias already exists, the keystore information
+     * associated with it is overridden by the given key (and possibly
+     * certificate chain).
+     *
+     * @param alias the alias name
+     * @param key the key (in protected format) to be associated with the alias
+     * @param chain the certificate chain for the corresponding public
+     * key (only useful if the protected key is of type
+     * {@code java.security.PrivateKey}).
+     *
+     * @exception KeyStoreException if this operation fails.
+     */
+    public abstract void engineSetKeyEntry(String alias, byte[] key,
+                                           Certificate[] chain)
+        throws KeyStoreException;
+
+    /**
+     * Assigns the given certificate to the given alias.
+     *
+     * <p> If the given alias identifies an existing entry
+     * created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry},
+     * the trusted certificate in the existing entry
+     * is overridden by the given certificate.
+     *
+     * @param alias the alias name
+     * @param cert the certificate
+     *
+     * @exception KeyStoreException if the given alias already exists and does
+     * not identify an entry containing a trusted certificate,
+     * or this operation fails for some other reason.
+     */
+    public abstract void engineSetCertificateEntry(String alias,
+                                                   Certificate cert)
+        throws KeyStoreException;
+
+    /**
+     * Deletes the entry identified by the given alias from this keystore.
+     *
+     * @param alias the alias name
+     *
+     * @exception KeyStoreException if the entry cannot be removed.
+     */
+    public abstract void engineDeleteEntry(String alias)
+        throws KeyStoreException;
+
+    /**
+     * Lists all the alias names of this keystore.
+     *
+     * @return enumeration of the alias names
+     */
+    public abstract Enumeration<String> engineAliases();
+
+    /**
+     * Checks if the given alias exists in this keystore.
+     *
+     * @param alias the alias name
+     *
+     * @return true if the alias exists, false otherwise
+     */
+    public abstract boolean engineContainsAlias(String alias);
+
+    /**
+     * Retrieves the number of entries in this keystore.
+     *
+     * @return the number of entries in this keystore
+     */
+    public abstract int engineSize();
+
+    /**
+     * Returns true if the entry identified by the given alias
+     * was created by a call to {@code setKeyEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry} or a {@code SecretKeyEntry}.
+     *
+     * @param alias the alias for the keystore entry to be checked
+     *
+     * @return true if the entry identified by the given alias is a
+     * key-related, false otherwise.
+     */
+    public abstract boolean engineIsKeyEntry(String alias);
+
+    /**
+     * Returns true if the entry identified by the given alias
+     * was created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry}.
+     *
+     * @param alias the alias for the keystore entry to be checked
+     *
+     * @return true if the entry identified by the given alias contains a
+     * trusted certificate, false otherwise.
+     */
+    public abstract boolean engineIsCertificateEntry(String alias);
+
+    /**
+     * Returns the (alias) name of the first keystore entry whose certificate
+     * matches the given certificate.
+     *
+     * <p>This method attempts to match the given certificate with each
+     * keystore entry. If the entry being considered was
+     * created by a call to {@code setCertificateEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code TrustedCertificateEntry},
+     * then the given certificate is compared to that entry's certificate.
+     *
+     * <p> If the entry being considered was
+     * created by a call to {@code setKeyEntry},
+     * or created by a call to {@code setEntry} with a
+     * {@code PrivateKeyEntry},
+     * then the given certificate is compared to the first
+     * element of that entry's certificate chain.
+     *
+     * @param cert the certificate to match with.
+     *
+     * @return the alias name of the first entry with matching certificate,
+     * or null if no such entry exists in this keystore.
+     */
+    public abstract String engineGetCertificateAlias(Certificate cert);
+
+    /**
+     * Stores this keystore to the given output stream, and protects its
+     * integrity with the given password.
+     *
+     * @param stream the output stream to which this keystore is written.
+     * @param password the password to generate the keystore integrity check
+     *
+     * @exception IOException if there was an I/O problem with data
+     * @exception NoSuchAlgorithmException if the appropriate data integrity
+     * algorithm could not be found
+     * @exception CertificateException if any of the certificates included in
+     * the keystore data could not be stored
+     */
+    public abstract void engineStore(OutputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException;
+
+    /**
+     * Stores this keystore using the given
+     * {@code KeyStore.LoadStoreParmeter}.
+     *
+     * @param param the {@code KeyStore.LoadStoreParmeter}
+     *          that specifies how to store the keystore,
+     *          which may be {@code null}
+     *
+     * @exception IllegalArgumentException if the given
+     *          {@code KeyStore.LoadStoreParmeter}
+     *          input is not recognized
+     * @exception IOException if there was an I/O problem with data
+     * @exception NoSuchAlgorithmException if the appropriate data integrity
+     *          algorithm could not be found
+     * @exception CertificateException if any of the certificates included in
+     *          the keystore data could not be stored
+     *
+     * @since 1.5
+     */
+    public void engineStore(KeyStore.LoadStoreParameter param)
+                throws IOException, NoSuchAlgorithmException,
+                CertificateException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Loads the keystore from the given input stream.
+     *
+     * <p>A password may be given to unlock the keystore
+     * (e.g. the keystore resides on a hardware token device),
+     * or to check the integrity of the keystore data.
+     * If a password is not given for integrity checking,
+     * then integrity checking is not performed.
+     *
+     * @param stream the input stream from which the keystore is loaded,
+     * or {@code null}
+     * @param password the password used to check the integrity of
+     * the keystore, the password used to unlock the keystore,
+     * or {@code null}
+     *
+     * @exception IOException if there is an I/O or format problem with the
+     * keystore data, if a password is required but not given,
+     * or if the given password was incorrect. If the error is due to a
+     * wrong password, the {@link Throwable#getCause cause} of the
+     * {@code IOException} should be an
+     * {@code UnrecoverableKeyException}
+     * @exception NoSuchAlgorithmException if the algorithm used to check
+     * the integrity of the keystore cannot be found
+     * @exception CertificateException if any of the certificates in the
+     * keystore could not be loaded
+     */
+    public abstract void engineLoad(InputStream stream, char[] password)
+        throws IOException, NoSuchAlgorithmException, CertificateException;
+
+    /**
+     * Loads the keystore using the given
+     * {@code KeyStore.LoadStoreParameter}.
+     *
+     * <p> Note that if this KeyStore has already been loaded, it is
+     * reinitialized and loaded again from the given parameter.
+     *
+     * @param param the {@code KeyStore.LoadStoreParameter}
+     *          that specifies how to load the keystore,
+     *          which may be {@code null}
+     *
+     * @exception IllegalArgumentException if the given
+     *          {@code KeyStore.LoadStoreParameter}
+     *          input is not recognized
+     * @exception IOException if there is an I/O or format problem with the
+     *          keystore data. If the error is due to an incorrect
+     *         {@code ProtectionParameter} (e.g. wrong password)
+     *         the {@link Throwable#getCause cause} of the
+     *         {@code IOException} should be an
+     *         {@code UnrecoverableKeyException}
+     * @exception NoSuchAlgorithmException if the algorithm used to check
+     *          the integrity of the keystore cannot be found
+     * @exception CertificateException if any of the certificates in the
+     *          keystore could not be loaded
+     *
+     * @since 1.5
+     */
+    public void engineLoad(KeyStore.LoadStoreParameter param)
+                throws IOException, NoSuchAlgorithmException,
+                CertificateException {
+
+        if (param == null) {
+            engineLoad((InputStream)null, (char[])null);
+            return;
+        }
+
+        if (param instanceof KeyStore.SimpleLoadStoreParameter) {
+            ProtectionParameter protection = param.getProtectionParameter();
+            char[] password;
+            if (protection instanceof PasswordProtection) {
+                password = ((PasswordProtection)protection).getPassword();
+            } else if (protection instanceof CallbackHandlerProtection) {
+                CallbackHandler handler =
+                    ((CallbackHandlerProtection)protection).getCallbackHandler();
+                PasswordCallback callback =
+                    new PasswordCallback("Password: ", false);
+                try {
+                    handler.handle(new Callback[] {callback});
+                } catch (UnsupportedCallbackException e) {
+                    throw new NoSuchAlgorithmException
+                        ("Could not obtain password", e);
+                }
+                password = callback.getPassword();
+                callback.clearPassword();
+                if (password == null) {
+                    throw new NoSuchAlgorithmException
+                        ("No password provided");
+                }
+            } else {
+                throw new NoSuchAlgorithmException("ProtectionParameter must"
+                    + " be PasswordProtection or CallbackHandlerProtection");
+            }
+            engineLoad(null, password);
+            return;
+        }
+
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Gets a {@code KeyStore.Entry} for the specified alias
+     * with the specified protection parameter.
+     *
+     * @param alias get the {@code KeyStore.Entry} for this alias
+     * @param protParam the {@code ProtectionParameter}
+     *          used to protect the {@code Entry},
+     *          which may be {@code null}
+     *
+     * @return the {@code KeyStore.Entry} for the specified alias,
+     *          or {@code null} if there is no such entry
+     *
+     * @exception KeyStoreException if the operation failed
+     * @exception NoSuchAlgorithmException if the algorithm for recovering the
+     *          entry cannot be found
+     * @exception UnrecoverableEntryException if the specified
+     *          {@code protParam} were insufficient or invalid
+     * @exception UnrecoverableKeyException if the entry is a
+     *          {@code PrivateKeyEntry} or {@code SecretKeyEntry}
+     *          and the specified {@code protParam} does not contain
+     *          the information needed to recover the key (e.g. wrong password)
+     *
+     * @since 1.5
+     */
+    public KeyStore.Entry engineGetEntry(String alias,
+                        KeyStore.ProtectionParameter protParam)
+                throws KeyStoreException, NoSuchAlgorithmException,
+                UnrecoverableEntryException {
+
+        if (!engineContainsAlias(alias)) {
+            return null;
+        }
+
+        if (protParam == null) {
+            if (engineIsCertificateEntry(alias)) {
+                return new KeyStore.TrustedCertificateEntry
+                                (engineGetCertificate(alias));
+            // Android-removed: Allow access to entries with no password.
+            // } else {
+            //    throw new UnrecoverableKeyException
+            //            ("requested entry requires a password");
+            }
+        }
+
+        // Android-changed: Add protParam == null to allow access to entries with no password.
+        if ((protParam == null) || protParam instanceof KeyStore.PasswordProtection) {
+            if (engineIsCertificateEntry(alias)) {
+                throw new UnsupportedOperationException
+                    ("trusted certificate entries are not password-protected");
+            } else if (engineIsKeyEntry(alias)) {
+                // Android-changed: Allow access to entries with no password.
+                // KeyStore.PasswordProtection pp =
+                //         (KeyStore.PasswordProtection)protParam;
+                // char[] password = pp.getPassword();
+                char[] password = null;
+                if (protParam != null) {
+                    KeyStore.PasswordProtection pp =
+                        (KeyStore.PasswordProtection)protParam;
+                    password = pp.getPassword();
+                }
+                Key key = engineGetKey(alias, password);
+                if (key instanceof PrivateKey) {
+                    Certificate[] chain = engineGetCertificateChain(alias);
+                    return new KeyStore.PrivateKeyEntry((PrivateKey)key, chain);
+                } else if (key instanceof SecretKey) {
+                    return new KeyStore.SecretKeyEntry((SecretKey)key);
+                }
+            }
+        }
+
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Saves a {@code KeyStore.Entry} under the specified alias.
+     * The specified protection parameter is used to protect the
+     * {@code Entry}.
+     *
+     * <p> If an entry already exists for the specified alias,
+     * it is overridden.
+     *
+     * @param alias save the {@code KeyStore.Entry} under this alias
+     * @param entry the {@code Entry} to save
+     * @param protParam the {@code ProtectionParameter}
+     *          used to protect the {@code Entry},
+     *          which may be {@code null}
+     *
+     * @exception KeyStoreException if this operation fails
+     *
+     * @since 1.5
+     */
+    public void engineSetEntry(String alias, KeyStore.Entry entry,
+                        KeyStore.ProtectionParameter protParam)
+                throws KeyStoreException {
+
+        // get password
+        if (protParam != null &&
+            !(protParam instanceof KeyStore.PasswordProtection)) {
+            throw new KeyStoreException("unsupported protection parameter");
+        }
+        KeyStore.PasswordProtection pProtect = null;
+        if (protParam != null) {
+            pProtect = (KeyStore.PasswordProtection)protParam;
+        }
+
+        // BEGIN Android-changed: Allow access to entries with no password.
+        char[] password = (pProtect == null) ? null : pProtect.getPassword();
+        // set entry
+        if (entry instanceof KeyStore.TrustedCertificateEntry) {
+            KeyStore.TrustedCertificateEntry tce =
+                    (KeyStore.TrustedCertificateEntry)entry;
+            engineSetCertificateEntry(alias, tce.getTrustedCertificate());
+            return;
+        } else if (entry instanceof KeyStore.PrivateKeyEntry) {
+            engineSetKeyEntry
+                (alias,
+                ((KeyStore.PrivateKeyEntry)entry).getPrivateKey(),
+                password,
+                ((KeyStore.PrivateKeyEntry)entry).getCertificateChain());
+            return;
+        } else if (entry instanceof KeyStore.SecretKeyEntry) {
+            engineSetKeyEntry
+                (alias,
+                ((KeyStore.SecretKeyEntry)entry).getSecretKey(),
+                password,
+                (Certificate[])null);
+            return;
+        }
+        // END Android-changed: Allow access to entries with no password.
+
+        throw new KeyStoreException
+                ("unsupported entry type: " + entry.getClass().getName());
+    }
+
+    /**
+     * Determines if the keystore {@code Entry} for the specified
+     * {@code alias} is an instance or subclass of the specified
+     * {@code entryClass}.
+     *
+     * @param alias the alias name
+     * @param entryClass the entry class
+     *
+     * @return true if the keystore {@code Entry} for the specified
+     *          {@code alias} is an instance or subclass of the
+     *          specified {@code entryClass}, false otherwise
+     *
+     * @since 1.5
+     */
+    public boolean
+        engineEntryInstanceOf(String alias,
+                              Class<? extends KeyStore.Entry> entryClass)
+    {
+        if (entryClass == KeyStore.TrustedCertificateEntry.class) {
+            return engineIsCertificateEntry(alias);
+        }
+        if (entryClass == KeyStore.PrivateKeyEntry.class) {
+            return engineIsKeyEntry(alias) &&
+                        engineGetCertificate(alias) != null;
+        }
+        if (entryClass == KeyStore.SecretKeyEntry.class) {
+            return engineIsKeyEntry(alias) &&
+                        engineGetCertificate(alias) == null;
+        }
+        return false;
+    }
+}
diff --git a/java/security/MessageDigest.annotated.java b/java/security/MessageDigest.annotated.java
new file mode 100644
index 0000000..7ffbc1c
--- /dev/null
+++ b/java/security/MessageDigest.annotated.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.security;
+
+import java.util.*;
+import java.lang.*;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class MessageDigest extends java.security.MessageDigestSpi {
+
+protected MessageDigest(@libcore.util.NonNull java.lang.String algorithm) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.security.MessageDigest getInstance(@libcore.util.NonNull java.lang.String algorithm) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.security.MessageDigest getInstance(@libcore.util.NonNull java.lang.String algorithm, @libcore.util.NonNull java.lang.String provider) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.security.MessageDigest getInstance(@libcore.util.NonNull java.lang.String algorithm, @libcore.util.NonNull java.security.Provider provider) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.security.Provider getProvider() { throw new RuntimeException("Stub!"); }
+
+public void update(byte input) { throw new RuntimeException("Stub!"); }
+
+public void update(byte @libcore.util.NonNull [] input, int offset, int len) { throw new RuntimeException("Stub!"); }
+
+public void update(byte @libcore.util.NonNull [] input) { throw new RuntimeException("Stub!"); }
+
+public final void update(@libcore.util.NonNull java.nio.ByteBuffer input) { throw new RuntimeException("Stub!"); }
+
+public byte @libcore.util.NonNull [] digest() { throw new RuntimeException("Stub!"); }
+
+public int digest(byte @libcore.util.NonNull [] buf, int offset, int len) throws java.security.DigestException { throw new RuntimeException("Stub!"); }
+
+public byte @libcore.util.NonNull [] digest(byte @libcore.util.NonNull [] input) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public static boolean isEqual(byte @libcore.util.Nullable [] digesta, byte @libcore.util.Nullable [] digestb) { throw new RuntimeException("Stub!"); }
+
+public void reset() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public final int getDigestLength() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/security/MessageDigest.java b/java/security/MessageDigest.java
new file mode 100644
index 0000000..5b9359f
--- /dev/null
+++ b/java/security/MessageDigest.java
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+import java.lang.*;
+import java.io.IOException;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+
+import java.nio.ByteBuffer;
+
+import sun.security.jca.Providers;
+
+/**
+ * This MessageDigest class provides applications the functionality of a
+ * message digest algorithm, such as SHA-1 or SHA-256.
+ * Message digests are secure one-way hash functions that take arbitrary-sized
+ * data and output a fixed-length hash value.
+ *
+ * <p>A MessageDigest object starts out initialized. The data is
+ * processed through it using the {@link #update(byte) update}
+ * methods. At any point {@link #reset() reset} can be called
+ * to reset the digest. Once all the data to be updated has been
+ * updated, one of the {@link #digest() digest} methods should
+ * be called to complete the hash computation.
+ *
+ * <p>The {@code digest} method can be called once for a given number
+ * of updates. After {@code digest} has been called, the MessageDigest
+ * object is reset to its initialized state.
+ *
+ * <p>Implementations are free to implement the Cloneable interface.
+ * Client applications can test cloneability by attempting cloning
+ * and catching the CloneNotSupportedException:
+ *
+ * <pre>{@code
+ * MessageDigest md = MessageDigest.getInstance("SHA");
+ *
+ * try {
+ *     md.update(toChapter1);
+ *     MessageDigest tc1 = md.clone();
+ *     byte[] toChapter1Digest = tc1.digest();
+ *     md.update(toChapter2);
+ *     ...etc.
+ * } catch (CloneNotSupportedException cnse) {
+ *     throw new DigestException("couldn't make digest of partial content");
+ * }
+ * }</pre>
+ *
+ * <p>Note that if a given implementation is not cloneable, it is
+ * still possible to compute intermediate digests by instantiating
+ * several instances, if the number of digests is known in advance.
+ *
+ * <p>Note that this class is abstract and extends from
+ * {@code MessageDigestSpi} for historical reasons.
+ * Application developers should only take notice of the methods defined in
+ * this {@code MessageDigest} class; all the methods in
+ * the superclass are intended for cryptographic service providers who wish to
+ * supply their own implementations of message digest algorithms.
+ *
+ * <p> Android provides the following <code>MessageDigest</code> algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>MD5</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA-1</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA-224</td>
+ *       <td>1-8,22+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA-256</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA-384</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA-512</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+ * MessageDigest section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Benjamin Renaud
+ *
+ * @see DigestInputStream
+ * @see DigestOutputStream
+ */
+
+public abstract class MessageDigest extends MessageDigestSpi {
+
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("messagedigest");
+    */
+
+    private String algorithm;
+
+    // The state of this digest
+    private static final int INITIAL = 0;
+    private static final int IN_PROGRESS = 1;
+    private int state = INITIAL;
+
+    // The provider
+    private Provider provider;
+
+    /**
+     * Creates a message digest with the specified algorithm name.
+     *
+     * @param algorithm the standard name of the digest algorithm.
+     * See the MessageDigest section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     */
+    protected MessageDigest(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns a MessageDigest object that implements the specified digest
+     * algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new MessageDigest object encapsulating the
+     * MessageDigestSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the MessageDigest section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return a Message Digest object that implements the specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          MessageDigestSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     */
+    public static MessageDigest getInstance(String algorithm)
+    throws NoSuchAlgorithmException {
+        try {
+            MessageDigest md;
+            Object[] objs = Security.getImpl(algorithm, "MessageDigest",
+                                             (String)null);
+            if (objs[0] instanceof MessageDigest) {
+                md = (MessageDigest)objs[0];
+            } else {
+                md = new Delegate((MessageDigestSpi)objs[0], algorithm);
+            }
+            md.provider = (Provider)objs[1];
+
+            // Android-removed: this debugging mechanism is not used in Android.
+            /*
+            if (!skipDebug && pdebug != null) {
+                pdebug.println("MessageDigest." + algorithm +
+                    " algorithm from: " + md.provider.getName());
+            }
+            */
+
+            return md;
+
+        } catch(NoSuchProviderException e) {
+            throw new NoSuchAlgorithmException(algorithm + " not found");
+        }
+    }
+
+    /**
+     * Returns a MessageDigest object that implements the specified digest
+     * algorithm.
+     *
+     * <p> A new MessageDigest object encapsulating the
+     * MessageDigestSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the MessageDigest section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a MessageDigest object that implements the specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if a MessageDigestSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static MessageDigest getInstance(String algorithm, String provider)
+        throws NoSuchAlgorithmException, NoSuchProviderException
+    {
+        if (provider == null || provider.length() == 0)
+            throw new IllegalArgumentException("missing provider");
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "MessageDigest", algorithm);
+        Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
+        if (objs[0] instanceof MessageDigest) {
+            MessageDigest md = (MessageDigest)objs[0];
+            md.provider = (Provider)objs[1];
+            return md;
+        } else {
+            MessageDigest delegate =
+                new Delegate((MessageDigestSpi)objs[0], algorithm);
+            delegate.provider = (Provider)objs[1];
+            return delegate;
+        }
+    }
+
+    /**
+     * Returns a MessageDigest object that implements the specified digest
+     * algorithm.
+     *
+     * <p> A new MessageDigest object encapsulating the
+     * MessageDigestSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the MessageDigest section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return a MessageDigest object that implements the specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if a MessageDigestSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the specified provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static MessageDigest getInstance(String algorithm,
+                                            Provider provider)
+        throws NoSuchAlgorithmException
+    {
+        if (provider == null)
+            throw new IllegalArgumentException("missing provider");
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "MessageDigest", algorithm);
+        Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
+        if (objs[0] instanceof MessageDigest) {
+            MessageDigest md = (MessageDigest)objs[0];
+            md.provider = (Provider)objs[1];
+            return md;
+        } else {
+            MessageDigest delegate =
+                new Delegate((MessageDigestSpi)objs[0], algorithm);
+            delegate.provider = (Provider)objs[1];
+            return delegate;
+        }
+    }
+
+    /**
+     * Returns the provider of this message digest object.
+     *
+     * @return the provider of this message digest object
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Updates the digest using the specified byte.
+     *
+     * @param input the byte with which to update the digest.
+     */
+    public void update(byte input) {
+        engineUpdate(input);
+        state = IN_PROGRESS;
+    }
+
+    /**
+     * Updates the digest using the specified array of bytes, starting
+     * at the specified offset.
+     *
+     * @param input the array of bytes.
+     *
+     * @param offset the offset to start from in the array of bytes.
+     *
+     * @param len the number of bytes to use, starting at
+     * {@code offset}.
+     */
+    public void update(byte[] input, int offset, int len) {
+        if (input == null) {
+            throw new IllegalArgumentException("No input buffer given");
+        }
+        if (input.length - offset < len) {
+            throw new IllegalArgumentException("Input buffer too short");
+        }
+        engineUpdate(input, offset, len);
+        state = IN_PROGRESS;
+    }
+
+    /**
+     * Updates the digest using the specified array of bytes.
+     *
+     * @param input the array of bytes.
+     */
+    public void update(byte[] input) {
+        engineUpdate(input, 0, input.length);
+        state = IN_PROGRESS;
+    }
+
+    /**
+     * Update the digest using the specified ByteBuffer. The digest is
+     * updated using the {@code input.remaining()} bytes starting
+     * at {@code input.position()}.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * @param input the ByteBuffer
+     * @since 1.5
+     */
+    public final void update(ByteBuffer input) {
+        if (input == null) {
+            throw new NullPointerException();
+        }
+        engineUpdate(input);
+        state = IN_PROGRESS;
+    }
+
+    /**
+     * Completes the hash computation by performing final operations
+     * such as padding. The digest is reset after this call is made.
+     *
+     * @return the array of bytes for the resulting hash value.
+     */
+    public byte[] digest() {
+        /* Resetting is the responsibility of implementors. */
+        byte[] result = engineDigest();
+        state = INITIAL;
+        return result;
+    }
+
+    /**
+     * Completes the hash computation by performing final operations
+     * such as padding. The digest is reset after this call is made.
+     *
+     * @param buf output buffer for the computed digest
+     *
+     * @param offset offset into the output buffer to begin storing the digest
+     *
+     * @param len number of bytes within buf allotted for the digest
+     *
+     * @return the number of bytes placed into {@code buf}
+     *
+     * @exception DigestException if an error occurs.
+     */
+    public int digest(byte[] buf, int offset, int len) throws DigestException {
+        if (buf == null) {
+            throw new IllegalArgumentException("No output buffer given");
+        }
+        if (buf.length - offset < len) {
+            throw new IllegalArgumentException
+                ("Output buffer too small for specified offset and length");
+        }
+        int numBytes = engineDigest(buf, offset, len);
+        state = INITIAL;
+        return numBytes;
+    }
+
+    /**
+     * Performs a final update on the digest using the specified array
+     * of bytes, then completes the digest computation. That is, this
+     * method first calls {@link #update(byte[]) update(input)},
+     * passing the <i>input</i> array to the {@code update} method,
+     * then calls {@link #digest() digest()}.
+     *
+     * @param input the input to be updated before the digest is
+     * completed.
+     *
+     * @return the array of bytes for the resulting hash value.
+     */
+    public byte[] digest(byte[] input) {
+        update(input);
+        return digest();
+    }
+
+    /**
+     * Returns a string representation of this message digest object.
+     */
+    public String toString() {
+        // BEGIN Android-changed: Use StringBuilder instead of a ByteArrayOutputStream.
+        StringBuilder builder = new StringBuilder();
+        builder.append(algorithm);
+        builder.append(" Message Digest from ");
+        builder.append(provider.getName());
+        builder.append(", ");
+
+        switch (state) {
+        case INITIAL:
+            builder.append("<initialized>");
+            break;
+        case IN_PROGRESS:
+            builder.append("<in progress>");
+            break;
+        }
+
+        return builder.toString();
+        // END Android-changed: Use StringBuilder instead of a ByteArrayOutputStream.
+    }
+
+    /**
+     * Compares two digests for equality. Does a simple byte compare.
+     *
+     * @param digesta one of the digests to compare.
+     *
+     * @param digestb the other digest to compare.
+     *
+     * @return true if the digests are equal, false otherwise.
+     */
+    public static boolean isEqual(byte[] digesta, byte[] digestb) {
+        if (digesta == digestb) return true;
+        if (digesta == null || digestb == null) {
+            return false;
+        }
+        if (digesta.length != digestb.length) {
+            return false;
+        }
+
+        int result = 0;
+        // time-constant comparison
+        for (int i = 0; i < digesta.length; i++) {
+            result |= digesta[i] ^ digestb[i];
+        }
+        return result == 0;
+    }
+
+    /**
+     * Resets the digest for further use.
+     */
+    public void reset() {
+        engineReset();
+        state = INITIAL;
+    }
+
+    /**
+     * Returns a string that identifies the algorithm, independent of
+     * implementation details. The name should be a standard
+     * Java Security name (such as "SHA", "MD5", and so on).
+     * See the MessageDigest section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#MessageDigest">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the name of the algorithm
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns the length of the digest in bytes, or 0 if this operation is
+     * not supported by the provider and the implementation is not cloneable.
+     *
+     * @return the digest length in bytes, or 0 if this operation is not
+     * supported by the provider and the implementation is not cloneable.
+     *
+     * @since 1.2
+     */
+    public final int getDigestLength() {
+        int digestLen = engineGetDigestLength();
+        if (digestLen == 0) {
+            try {
+                MessageDigest md = (MessageDigest)clone();
+                byte[] digest = md.digest();
+                return digest.length;
+            } catch (CloneNotSupportedException e) {
+                return digestLen;
+            }
+        }
+        return digestLen;
+    }
+
+    /**
+     * Returns a clone if the implementation is cloneable.
+     *
+     * @return a clone if the implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called on an
+     * implementation that does not support {@code Cloneable}.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+
+
+
+
+    /*
+     * The following class allows providers to extend from MessageDigestSpi
+     * rather than from MessageDigest. It represents a MessageDigest with an
+     * encapsulated, provider-supplied SPI object (of type MessageDigestSpi).
+     * If the provider implementation is an instance of MessageDigestSpi,
+     * the getInstance() methods above return an instance of this class, with
+     * the SPI object encapsulated.
+     *
+     * Note: All SPI methods from the original MessageDigest class have been
+     * moved up the hierarchy into a new class (MessageDigestSpi), which has
+     * been interposed in the hierarchy between the API (MessageDigest)
+     * and its original parent (Object).
+     */
+
+    static class Delegate extends MessageDigest {
+
+        // The provider implementation (delegate)
+        private MessageDigestSpi digestSpi;
+
+        // constructor
+        public Delegate(MessageDigestSpi digestSpi, String algorithm) {
+            super(algorithm);
+            this.digestSpi = digestSpi;
+        }
+
+        /**
+         * Returns a clone if the delegate is cloneable.
+         *
+         * @return a clone if the delegate is cloneable.
+         *
+         * @exception CloneNotSupportedException if this is called on a
+         * delegate that does not support {@code Cloneable}.
+         */
+        public Object clone() throws CloneNotSupportedException {
+            if (digestSpi instanceof Cloneable) {
+                MessageDigestSpi digestSpiClone =
+                    (MessageDigestSpi)digestSpi.clone();
+                // Because 'algorithm', 'provider', and 'state' are private
+                // members of our supertype, we must perform a cast to
+                // access them.
+                MessageDigest that =
+                    new Delegate(digestSpiClone,
+                                 ((MessageDigest)this).algorithm);
+                that.provider = ((MessageDigest)this).provider;
+                that.state = ((MessageDigest)this).state;
+                return that;
+            } else {
+                throw new CloneNotSupportedException();
+            }
+        }
+
+        protected int engineGetDigestLength() {
+            return digestSpi.engineGetDigestLength();
+        }
+
+        protected void engineUpdate(byte input) {
+            digestSpi.engineUpdate(input);
+        }
+
+        protected void engineUpdate(byte[] input, int offset, int len) {
+            digestSpi.engineUpdate(input, offset, len);
+        }
+
+        protected void engineUpdate(ByteBuffer input) {
+            digestSpi.engineUpdate(input);
+        }
+
+        protected byte[] engineDigest() {
+            return digestSpi.engineDigest();
+        }
+
+        protected int engineDigest(byte[] buf, int offset, int len)
+            throws DigestException {
+                return digestSpi.engineDigest(buf, offset, len);
+        }
+
+        protected void engineReset() {
+            digestSpi.engineReset();
+        }
+    }
+}
diff --git a/java/security/MessageDigestSpi.java b/java/security/MessageDigestSpi.java
new file mode 100644
index 0000000..0d5ace1
--- /dev/null
+++ b/java/security/MessageDigestSpi.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.nio.ByteBuffer;
+
+import sun.security.jca.JCAUtil;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code MessageDigest} class, which provides the functionality
+ * of a message digest algorithm, such as MD5 or SHA. Message digests are
+ * secure one-way hash functions that take arbitrary-sized data and output a
+ * fixed-length hash value.
+ *
+ * <p> All the abstract methods in this class must be implemented by a
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular message digest algorithm.
+ *
+ * <p> Implementations are free to implement the Cloneable interface.
+ *
+ * @author Benjamin Renaud
+ *
+ *
+ * @see MessageDigest
+ */
+
+public abstract class MessageDigestSpi {
+
+    // for re-use in engineUpdate(ByteBuffer input)
+    private byte[] tempArray;
+
+    /**
+     * Returns the digest length in bytes.
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. (For backwards compatibility, it cannot be abstract.)
+     *
+     * <p>The default behavior is to return 0.
+     *
+     * <p>This method may be overridden by a provider to return the digest
+     * length.
+     *
+     * @return the digest length in bytes.
+     *
+     * @since 1.2
+     */
+    protected int engineGetDigestLength() {
+        return 0;
+    }
+
+    /**
+     * Updates the digest using the specified byte.
+     *
+     * @param input the byte to use for the update.
+     */
+    protected abstract void engineUpdate(byte input);
+
+    /**
+     * Updates the digest using the specified array of bytes,
+     * starting at the specified offset.
+     *
+     * @param input the array of bytes to use for the update.
+     *
+     * @param offset the offset to start from in the array of bytes.
+     *
+     * @param len the number of bytes to use, starting at
+     * {@code offset}.
+     */
+    protected abstract void engineUpdate(byte[] input, int offset, int len);
+
+    /**
+     * Update the digest using the specified ByteBuffer. The digest is
+     * updated using the {@code input.remaining()} bytes starting
+     * at {@code input.position()}.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * @param input the ByteBuffer
+     * @since 1.5
+     */
+    protected void engineUpdate(ByteBuffer input) {
+        if (input.hasRemaining() == false) {
+            return;
+        }
+        if (input.hasArray()) {
+            byte[] b = input.array();
+            int ofs = input.arrayOffset();
+            int pos = input.position();
+            int lim = input.limit();
+            engineUpdate(b, ofs + pos, lim - pos);
+            input.position(lim);
+        } else {
+            int len = input.remaining();
+            int n = JCAUtil.getTempArraySize(len);
+            if ((tempArray == null) || (n > tempArray.length)) {
+                tempArray = new byte[n];
+            }
+            while (len > 0) {
+                int chunk = Math.min(len, tempArray.length);
+                input.get(tempArray, 0, chunk);
+                engineUpdate(tempArray, 0, chunk);
+                len -= chunk;
+            }
+        }
+    }
+
+    /**
+     * Completes the hash computation by performing final
+     * operations such as padding. Once {@code engineDigest} has
+     * been called, the engine should be reset (see
+     * {@link #engineReset() engineReset}).
+     * Resetting is the responsibility of the
+     * engine implementor.
+     *
+     * @return the array of bytes for the resulting hash value.
+     */
+    protected abstract byte[] engineDigest();
+
+    /**
+     * Completes the hash computation by performing final
+     * operations such as padding. Once {@code engineDigest} has
+     * been called, the engine should be reset (see
+     * {@link #engineReset() engineReset}).
+     * Resetting is the responsibility of the
+     * engine implementor.
+     *
+     * This method should be abstract, but we leave it concrete for
+     * binary compatibility.  Knowledgeable providers should override this
+     * method.
+     *
+     * @param buf the output buffer in which to store the digest
+     *
+     * @param offset offset to start from in the output buffer
+     *
+     * @param len number of bytes within buf allotted for the digest.
+     * Both this default implementation and the SUN provider do not
+     * return partial digests.  The presence of this parameter is solely
+     * for consistency in our API's.  If the value of this parameter is less
+     * than the actual digest length, the method will throw a DigestException.
+     * This parameter is ignored if its value is greater than or equal to
+     * the actual digest length.
+     *
+     * @return the length of the digest stored in the output buffer.
+     *
+     * @exception DigestException if an error occurs.
+     *
+     * @since 1.2
+     */
+    protected int engineDigest(byte[] buf, int offset, int len)
+                                                throws DigestException {
+
+        byte[] digest = engineDigest();
+        if (len < digest.length)
+                throw new DigestException("partial digests not returned");
+        if (buf.length - offset < digest.length)
+                throw new DigestException("insufficient space in the output "
+                                          + "buffer to store the digest");
+        System.arraycopy(digest, 0, buf, offset, digest.length);
+        return digest.length;
+    }
+
+    /**
+     * Resets the digest for further use.
+     */
+    protected abstract void engineReset();
+
+    /**
+     * Returns a clone if the implementation is cloneable.
+     *
+     * @return a clone if the implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called on an
+     * implementation that does not support {@code Cloneable}.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+}
diff --git a/java/security/NoSuchAlgorithmException.java b/java/security/NoSuchAlgorithmException.java
new file mode 100644
index 0000000..951e44e
--- /dev/null
+++ b/java/security/NoSuchAlgorithmException.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This exception is thrown when a particular cryptographic algorithm is
+ * requested but is not available in the environment.
+ *
+ * @author Benjamin Renaud
+ */
+
+public class NoSuchAlgorithmException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -7443947487218346562L;
+
+    /**
+     * Constructs a NoSuchAlgorithmException with no detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     */
+    public NoSuchAlgorithmException() {
+        super();
+    }
+
+    /**
+     * Constructs a NoSuchAlgorithmException with the specified
+     * detail message. A detail message is a String that describes
+     * this particular exception, which may, for example, specify which
+     * algorithm is not available.
+     *
+     * @param msg the detail message.
+     */
+    public NoSuchAlgorithmException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code NoSuchAlgorithmException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public NoSuchAlgorithmException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code NoSuchAlgorithmException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public NoSuchAlgorithmException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/NoSuchProviderException.java b/java/security/NoSuchProviderException.java
new file mode 100644
index 0000000..9874adb
--- /dev/null
+++ b/java/security/NoSuchProviderException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This exception is thrown when a particular security provider is
+ * requested but is not available in the environment.
+ *
+ * @author Benjamin Renaud
+ */
+
+public class NoSuchProviderException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 8488111756688534474L;
+
+    /**
+     * Constructs a NoSuchProviderException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public NoSuchProviderException() {
+        super();
+    }
+
+    /**
+     * Constructs a NoSuchProviderException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public NoSuchProviderException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/security/PKCS12Attribute.java b/java/security/PKCS12Attribute.java
new file mode 100644
index 0000000..e389862
--- /dev/null
+++ b/java/security/PKCS12Attribute.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.regex.Pattern;
+import sun.security.util.*;
+
+/**
+ * An attribute associated with a PKCS12 keystore entry.
+ * The attribute name is an ASN.1 Object Identifier and the attribute
+ * value is a set of ASN.1 types.
+ *
+ * @since 1.8
+ */
+public final class PKCS12Attribute implements KeyStore.Entry.Attribute {
+
+    private static final Pattern COLON_SEPARATED_HEX_PAIRS =
+        Pattern.compile("^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2})+$");
+    private String name;
+    private String value;
+    private byte[] encoded;
+    private int hashValue = -1;
+
+    /**
+     * Constructs a PKCS12 attribute from its name and value.
+     * The name is an ASN.1 Object Identifier represented as a list of
+     * dot-separated integers.
+     * A string value is represented as the string itself.
+     * A binary value is represented as a string of colon-separated
+     * pairs of hexadecimal digits.
+     * Multi-valued attributes are represented as a comma-separated
+     * list of values, enclosed in square brackets. See
+     * {@link Arrays#toString(java.lang.Object[])}.
+     * <p>
+     * A string value will be DER-encoded as an ASN.1 UTF8String and a
+     * binary value will be DER-encoded as an ASN.1 Octet String.
+     *
+     * @param name the attribute's identifier
+     * @param value the attribute's value
+     *
+     * @exception NullPointerException if {@code name} or {@code value}
+     *     is {@code null}
+     * @exception IllegalArgumentException if {@code name} or
+     *     {@code value} is incorrectly formatted
+     */
+    public PKCS12Attribute(String name, String value) {
+        if (name == null || value == null) {
+            throw new NullPointerException();
+        }
+        // Validate name
+        ObjectIdentifier type;
+        try {
+            type = new ObjectIdentifier(name);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Incorrect format: name", e);
+        }
+        this.name = name;
+
+        // Validate value
+        int length = value.length();
+        String[] values;
+        if (value.charAt(0) == '[' && value.charAt(length - 1) == ']') {
+            values = value.substring(1, length - 1).split(", ");
+        } else {
+            values = new String[]{ value };
+        }
+        this.value = value;
+
+        try {
+            this.encoded = encode(type, values);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Incorrect format: value", e);
+        }
+    }
+
+    /**
+     * Constructs a PKCS12 attribute from its ASN.1 DER encoding.
+     * The DER encoding is specified by the following ASN.1 definition:
+     * <pre>
+     *
+     * Attribute ::= SEQUENCE {
+     *     type   AttributeType,
+     *     values SET OF AttributeValue
+     * }
+     * AttributeType ::= OBJECT IDENTIFIER
+     * AttributeValue ::= ANY defined by type
+     *
+     * </pre>
+     *
+     * @param encoded the attribute's ASN.1 DER encoding. It is cloned
+     *     to prevent subsequent modificaion.
+     *
+     * @exception NullPointerException if {@code encoded} is
+     *     {@code null}
+     * @exception IllegalArgumentException if {@code encoded} is
+     *     incorrectly formatted
+     */
+    public PKCS12Attribute(byte[] encoded) {
+        if (encoded == null) {
+            throw new NullPointerException();
+        }
+        this.encoded = encoded.clone();
+
+        try {
+            parse(encoded);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Incorrect format: encoded", e);
+        }
+    }
+
+    /**
+     * Returns the attribute's ASN.1 Object Identifier represented as a
+     * list of dot-separated integers.
+     *
+     * @return the attribute's identifier
+     */
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the attribute's ASN.1 DER-encoded value as a string.
+     * An ASN.1 DER-encoded value is returned in one of the following
+     * {@code String} formats:
+     * <ul>
+     * <li> the DER encoding of a basic ASN.1 type that has a natural
+     *      string representation is returned as the string itself.
+     *      Such types are currently limited to BOOLEAN, INTEGER,
+     *      OBJECT IDENTIFIER, UTCTime, GeneralizedTime and the
+     *      following six ASN.1 string types: UTF8String,
+     *      PrintableString, T61String, IA5String, BMPString and
+     *      GeneralString.
+     * <li> the DER encoding of any other ASN.1 type is not decoded but
+     *      returned as a binary string of colon-separated pairs of
+     *      hexadecimal digits.
+     * </ul>
+     * Multi-valued attributes are represented as a comma-separated
+     * list of values, enclosed in square brackets. See
+     * {@link Arrays#toString(java.lang.Object[])}.
+     *
+     * @return the attribute value's string encoding
+     */
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the attribute's ASN.1 DER encoding.
+     *
+     * @return a clone of the attribute's DER encoding
+     */
+    public byte[] getEncoded() {
+        return encoded.clone();
+    }
+
+    /**
+     * Compares this {@code PKCS12Attribute} and a specified object for
+     * equality.
+     *
+     * @param obj the comparison object
+     *
+     * @return true if {@code obj} is a {@code PKCS12Attribute} and
+     * their DER encodings are equal.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof PKCS12Attribute)) {
+            return false;
+        }
+        return Arrays.equals(encoded, ((PKCS12Attribute) obj).getEncoded());
+    }
+
+    /**
+     * Returns the hashcode for this {@code PKCS12Attribute}.
+     * The hash code is computed from its DER encoding.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        if (hashValue == -1) {
+            Arrays.hashCode(encoded);
+        }
+        return hashValue;
+    }
+
+    /**
+     * Returns a string representation of this {@code PKCS12Attribute}.
+     *
+     * @return a name/value pair separated by an 'equals' symbol
+     */
+    @Override
+    public String toString() {
+        return (name + "=" + value);
+    }
+
+    private byte[] encode(ObjectIdentifier type, String[] values)
+            throws IOException {
+        DerOutputStream attribute = new DerOutputStream();
+        attribute.putOID(type);
+        DerOutputStream attrContent = new DerOutputStream();
+        for (String value : values) {
+            if (COLON_SEPARATED_HEX_PAIRS.matcher(value).matches()) {
+                byte[] bytes =
+                    new BigInteger(value.replace(":", ""), 16).toByteArray();
+                if (bytes[0] == 0) {
+                    bytes = Arrays.copyOfRange(bytes, 1, bytes.length);
+                }
+                attrContent.putOctetString(bytes);
+            } else {
+                attrContent.putUTF8String(value);
+            }
+        }
+        attribute.write(DerValue.tag_Set, attrContent);
+        DerOutputStream attributeValue = new DerOutputStream();
+        attributeValue.write(DerValue.tag_Sequence, attribute);
+
+        return attributeValue.toByteArray();
+    }
+
+    private void parse(byte[] encoded) throws IOException {
+        DerInputStream attributeValue = new DerInputStream(encoded);
+        DerValue[] attrSeq = attributeValue.getSequence(2);
+        ObjectIdentifier type = attrSeq[0].getOID();
+        DerInputStream attrContent =
+            new DerInputStream(attrSeq[1].toByteArray());
+        DerValue[] attrValueSet = attrContent.getSet(1);
+        String[] values = new String[attrValueSet.length];
+        String printableString;
+        for (int i = 0; i < attrValueSet.length; i++) {
+            if (attrValueSet[i].tag == DerValue.tag_OctetString) {
+                values[i] = Debug.toString(attrValueSet[i].getOctetString());
+            } else if ((printableString = attrValueSet[i].getAsString())
+                != null) {
+                values[i] = printableString;
+            } else if (attrValueSet[i].tag == DerValue.tag_ObjectId) {
+                values[i] = attrValueSet[i].getOID().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_GeneralizedTime) {
+                values[i] = attrValueSet[i].getGeneralizedTime().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_UtcTime) {
+                values[i] = attrValueSet[i].getUTCTime().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_Integer) {
+                values[i] = attrValueSet[i].getBigInteger().toString();
+            } else if (attrValueSet[i].tag == DerValue.tag_Boolean) {
+                values[i] = String.valueOf(attrValueSet[i].getBoolean());
+            } else {
+                values[i] = Debug.toString(attrValueSet[i].getDataBytes());
+            }
+        }
+
+        this.name = type.toString();
+        this.value = values.length == 1 ? values[0] : Arrays.toString(values);
+    }
+}
diff --git a/java/security/Permission.java b/java/security/Permission.java
new file mode 100644
index 0000000..9b258a6
--- /dev/null
+++ b/java/security/Permission.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public abstract class Permission implements Guard, java.io.Serializable {
+
+    private String name;
+
+    public Permission(String name) {
+        this.name = name;
+    }
+
+    public void checkGuard(Object object) throws SecurityException { }
+
+    public abstract boolean implies(Permission permission);
+
+    public final String getName() {
+        return name;
+    }
+
+    public abstract String getActions();
+
+    public PermissionCollection newPermissionCollection() { return new Permissions(); }
+}
diff --git a/java/security/PermissionCollection.java b/java/security/PermissionCollection.java
new file mode 100644
index 0000000..f1015e3
--- /dev/null
+++ b/java/security/PermissionCollection.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public abstract class PermissionCollection implements java.io.Serializable {
+
+    public abstract void add(Permission permission);
+
+    public abstract boolean implies(Permission permission);
+
+    public abstract Enumeration<Permission> elements();
+
+    public void setReadOnly() { }
+
+    public boolean isReadOnly() { return true; }
+}
diff --git a/java/security/Permissions.java b/java/security/Permissions.java
new file mode 100644
index 0000000..9796f01
--- /dev/null
+++ b/java/security/Permissions.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.Enumeration;
+import java.io.Serializable;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class Permissions extends PermissionCollection
+implements Serializable
+{
+    public void add(Permission permission) { }
+
+    public boolean implies(Permission permission) { return true; }
+
+    public Enumeration<Permission> elements() { return null; }
+}
diff --git a/java/security/Policy.java b/java/security/Policy.java
new file mode 100644
index 0000000..cb7fb3b
--- /dev/null
+++ b/java/security/Policy.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.security;
+
+import java.util.Enumeration;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public abstract class Policy {
+
+    public static final PermissionCollection UNSUPPORTED_EMPTY_COLLECTION =
+                        new UnsupportedEmptyCollection();
+
+    public static Policy getPolicy()
+    {
+      return null;
+    }
+
+    public static void setPolicy(Policy p)
+    {
+    }
+
+    public static Policy getInstance(String type, Policy.Parameters params)
+                throws NoSuchAlgorithmException {
+      return null;
+    }
+
+    public static Policy getInstance(String type,
+                                Policy.Parameters params,
+                                String provider)
+                throws NoSuchProviderException, NoSuchAlgorithmException {
+      return null;
+    }
+
+
+    public static Policy getInstance(String type,
+                                Policy.Parameters params,
+                                Provider provider)
+                throws NoSuchAlgorithmException {
+      return null;
+    }
+
+    public Provider getProvider() {
+        return null;
+    }
+
+    public String getType() {
+        return null;
+    }
+
+    public Policy.Parameters getParameters() {
+        return null;
+    }
+
+    public PermissionCollection getPermissions(CodeSource codesource) {
+        return null;
+    }
+
+    public PermissionCollection getPermissions(ProtectionDomain domain) {
+        return null;
+    }
+
+    public boolean implies(ProtectionDomain domain, Permission permission) {
+        return true;
+    }
+
+    public void refresh() { }
+
+    public static interface Parameters { }
+
+    private static class UnsupportedEmptyCollection
+        extends PermissionCollection {
+
+        public UnsupportedEmptyCollection() {
+        }
+
+        @Override public void add(Permission permission) {
+        }
+
+        @Override public boolean implies(Permission permission) {
+            return true;
+        }
+
+        @Override public Enumeration<Permission> elements() {
+            return null;
+        }
+    }
+
+}
diff --git a/java/security/PolicySpi.java b/java/security/PolicySpi.java
new file mode 100644
index 0000000..608ce1f
--- /dev/null
+++ b/java/security/PolicySpi.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.security;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code Policy} class.
+ * All the abstract methods in this class must be implemented by each
+ * service provider who wishes to supply a Policy implementation.
+ *
+ * <p> Subclass implementations of this abstract class must provide
+ * a public constructor that takes a {@code Policy.Parameters}
+ * object as an input parameter.  This constructor also must throw
+ * an IllegalArgumentException if it does not understand the
+ * {@code Policy.Parameters} input.
+ *
+ *
+ * @since 1.6
+ */
+
+public abstract class PolicySpi {
+
+    /**
+     * Check whether the policy has granted a Permission to a ProtectionDomain.
+     *
+     * @param domain the ProtectionDomain to check.
+     *
+     * @param permission check whether this permission is granted to the
+     *          specified domain.
+     *
+     * @return boolean true if the permission is granted to the domain.
+     */
+    protected abstract boolean engineImplies
+        (ProtectionDomain domain, Permission permission);
+
+    /**
+     * Refreshes/reloads the policy configuration. The behavior of this method
+     * depends on the implementation. For example, calling {@code refresh}
+     * on a file-based policy will cause the file to be re-read.
+     *
+     * <p> The default implementation of this method does nothing.
+     * This method should be overridden if a refresh operation is supported
+     * by the policy implementation.
+     */
+    protected void engineRefresh() { }
+
+    /**
+     * Return a PermissionCollection object containing the set of
+     * permissions granted to the specified CodeSource.
+     *
+     * <p> The default implementation of this method returns
+     * Policy.UNSUPPORTED_EMPTY_COLLECTION object.  This method can be
+     * overridden if the policy implementation can return a set of
+     * permissions granted to a CodeSource.
+     *
+     * @param codesource the CodeSource to which the returned
+     *          PermissionCollection has been granted.
+     *
+     * @return a set of permissions granted to the specified CodeSource.
+     *          If this operation is supported, the returned
+     *          set of permissions must be a new mutable instance
+     *          and it must support heterogeneous Permission types.
+     *          If this operation is not supported,
+     *          Policy.UNSUPPORTED_EMPTY_COLLECTION is returned.
+     */
+    protected PermissionCollection engineGetPermissions
+                                        (CodeSource codesource) {
+        return Policy.UNSUPPORTED_EMPTY_COLLECTION;
+    }
+
+    /**
+     * Return a PermissionCollection object containing the set of
+     * permissions granted to the specified ProtectionDomain.
+     *
+     * <p> The default implementation of this method returns
+     * Policy.UNSUPPORTED_EMPTY_COLLECTION object.  This method can be
+     * overridden if the policy implementation can return a set of
+     * permissions granted to a ProtectionDomain.
+     *
+     * @param domain the ProtectionDomain to which the returned
+     *          PermissionCollection has been granted.
+     *
+     * @return a set of permissions granted to the specified ProtectionDomain.
+     *          If this operation is supported, the returned
+     *          set of permissions must be a new mutable instance
+     *          and it must support heterogeneous Permission types.
+     *          If this operation is not supported,
+     *          Policy.UNSUPPORTED_EMPTY_COLLECTION is returned.
+     */
+    protected PermissionCollection engineGetPermissions
+                                        (ProtectionDomain domain) {
+        return Policy.UNSUPPORTED_EMPTY_COLLECTION;
+    }
+}
diff --git a/java/security/Principal.java b/java/security/Principal.java
new file mode 100644
index 0000000..a538e70
--- /dev/null
+++ b/java/security/Principal.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import javax.security.auth.Subject;
+
+/**
+ * This interface represents the abstract notion of a principal, which
+ * can be used to represent any entity, such as an individual, a
+ * corporation, and a login id.
+ *
+ * @see java.security.cert.X509Certificate
+ *
+ * @author Li Gong
+ */
+public interface Principal {
+
+    /**
+     * Compares this principal to the specified object.  Returns true
+     * if the object passed in matches the principal represented by
+     * the implementation of this interface.
+     *
+     * @param another principal to compare with.
+     *
+     * @return true if the principal passed in is the same as that
+     * encapsulated by this principal, and false otherwise.
+     */
+    public boolean equals(Object another);
+
+    /**
+     * Returns a string representation of this principal.
+     *
+     * @return a string representation of this principal.
+     */
+    public String toString();
+
+    /**
+     * Returns a hashcode for this principal.
+     *
+     * @return a hashcode for this principal.
+     */
+    public int hashCode();
+
+    /**
+     * Returns the name of this principal.
+     *
+     * @return the name of this principal.
+     */
+    public String getName();
+
+    /**
+     * Returns true if the specified subject is implied by this principal.
+     *
+     * <p>The default implementation of this method returns true if
+     * {@code subject} is non-null and contains at least one principal that
+     * is equal to this principal.
+     *
+     * <p>Subclasses may override this with a different implementation, if
+     * necessary.
+     *
+     * @param subject the {@code Subject}
+     * @return true if {@code subject} is non-null and is
+     *              implied by this principal, or false otherwise.
+     * @since 1.8
+     */
+    public default boolean implies(Subject subject) {
+        if (subject == null)
+            return false;
+        return subject.getPrincipals().contains(this);
+    }
+}
diff --git a/java/security/PrivateKey.java b/java/security/PrivateKey.java
new file mode 100644
index 0000000..7d8a7ea
--- /dev/null
+++ b/java/security/PrivateKey.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * A private key.
+ * The purpose of this interface is to group (and provide type safety
+ * for) all private key interfaces.
+ * <p>
+ * Note: The specialized private key interfaces extend this interface.
+ * See, for example, the {@code DSAPrivateKey} interface in
+ * {@link java.security.interfaces}.
+ * <p>
+ * Implementations should override the default {@code destroy} and
+ * {@code isDestroyed} methods from the
+ * {@link javax.security.auth.Destroyable} interface to enable
+ * sensitive key information to be destroyed, cleared, or in the case
+ * where such information is immutable, unreferenced.
+ * Finally, since {@code PrivateKey} is {@code Serializable}, implementations
+ * should also override
+ * {@link java.io.ObjectOutputStream#writeObject(java.lang.Object)}
+ * to prevent keys that have been destroyed from being serialized.
+ *
+ * @see Key
+ * @see PublicKey
+ * @see Certificate
+ * @see Signature#initVerify
+ * @see java.security.interfaces.DSAPrivateKey
+ * @see java.security.interfaces.RSAPrivateKey
+ * @see java.security.interfaces.RSAPrivateCrtKey
+ *
+ * @author Benjamin Renaud
+ * @author Josh Bloch
+ */
+
+public interface PrivateKey extends Key, javax.security.auth.Destroyable {
+
+    // Declare serialVersionUID to be compatible with JDK1.1
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility with a previous version of the class.
+     */
+    static final long serialVersionUID = 6034044314589513430L;
+}
diff --git a/java/security/PrivilegedAction.java b/java/security/PrivilegedAction.java
new file mode 100644
index 0000000..5844b4d
--- /dev/null
+++ b/java/security/PrivilegedAction.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public interface PrivilegedAction<T> {
+
+    T run();
+}
diff --git a/java/security/PrivilegedActionException.java b/java/security/PrivilegedActionException.java
new file mode 100644
index 0000000..b1eb28f
--- /dev/null
+++ b/java/security/PrivilegedActionException.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ *
+ * This exception is thrown by
+ * {@code doPrivileged(PrivilegedExceptionAction)} and
+ * {@code doPrivileged(PrivilegedExceptionAction,
+ * AccessControlContext context)} to indicate
+ * that the action being performed threw a checked exception.  The exception
+ * thrown by the action can be obtained by calling the
+ * {@code getException} method.  In effect, an
+ * {@code PrivilegedActionException} is a "wrapper"
+ * for an exception thrown by a privileged action.
+ *
+ * <p>As of release 1.4, this exception has been retrofitted to conform to
+ * the general purpose exception-chaining mechanism.  The "exception thrown
+ * by the privileged computation" that is provided at construction time and
+ * accessed via the {@link #getException()} method is now known as the
+ * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
+ * method, as well as the aforementioned "legacy method."
+ *
+ * @see PrivilegedExceptionAction
+ * @see AccessController#doPrivileged(PrivilegedExceptionAction)
+ * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
+ */
+public class PrivilegedActionException extends Exception {
+    // use serialVersionUID from JDK 1.2.2 for interoperability
+    private static final long serialVersionUID = 4724086851538908602L;
+
+    /**
+     * @serial
+     */
+    private Exception exception;
+
+    /**
+     * Constructs a new PrivilegedActionException &quot;wrapping&quot;
+     * the specific Exception.
+     *
+     * @param exception The exception thrown
+     */
+    public PrivilegedActionException(Exception exception) {
+        super((Throwable)null);  // Disallow initCause
+        this.exception = exception;
+    }
+
+    /**
+     * Returns the exception thrown by the privileged computation that
+     * resulted in this {@code PrivilegedActionException}.
+     *
+     * <p>This method predates the general-purpose exception chaining facility.
+     * The {@link Throwable#getCause()} method is now the preferred means of
+     * obtaining this information.
+     *
+     * @return the exception thrown by the privileged computation that
+     *         resulted in this {@code PrivilegedActionException}.
+     * @see PrivilegedExceptionAction
+     * @see AccessController#doPrivileged(PrivilegedExceptionAction)
+     * @see AccessController#doPrivileged(PrivilegedExceptionAction,
+     *                                            AccessControlContext)
+     */
+    public Exception getException() {
+        return exception;
+    }
+
+    /**
+     * Returns the cause of this exception (the exception thrown by
+     * the privileged computation that resulted in this
+     * {@code PrivilegedActionException}).
+     *
+     * @return  the cause of this exception.
+     * @since   1.4
+     */
+    public Throwable getCause() {
+        return exception;
+    }
+
+    public String toString() {
+        String s = getClass().getName();
+        return (exception != null) ? (s + ": " + exception.toString()) : s;
+    }
+}
diff --git a/java/security/PrivilegedExceptionAction.java b/java/security/PrivilegedExceptionAction.java
new file mode 100644
index 0000000..4023150
--- /dev/null
+++ b/java/security/PrivilegedExceptionAction.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public interface PrivilegedExceptionAction<T> {
+
+    T run() throws Exception;
+}
diff --git a/java/security/ProtectionDomain.java b/java/security/ProtectionDomain.java
new file mode 100644
index 0000000..9e117a6
--- /dev/null
+++ b/java/security/ProtectionDomain.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public class ProtectionDomain {
+
+    public ProtectionDomain(CodeSource codesource,
+                            PermissionCollection permissions) { }
+
+    public ProtectionDomain(CodeSource codesource,
+                            PermissionCollection permissions,
+                            ClassLoader classloader,
+                            Principal[] principals) { }
+
+    public final CodeSource getCodeSource() { return null; }
+
+    public final ClassLoader getClassLoader() { return null; }
+
+    public final Principal[] getPrincipals() { return null; }
+
+    public final PermissionCollection getPermissions() { return null; }
+
+    public boolean implies(Permission permission) { return true; }
+}
diff --git a/java/security/Provider.annotated.java b/java/security/Provider.annotated.java
new file mode 100644
index 0000000..2fce78b
--- /dev/null
+++ b/java/security/Provider.annotated.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.security;
+
+import java.io.*;
+import java.util.*;
+import java.lang.ref.*;
+import java.lang.reflect.*;
+import java.security.Security;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Provider extends java.util.Properties {
+
+protected Provider(java.lang.String name, double version, java.lang.String info) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public double getVersion() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getInfo() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public synchronized void clear() { throw new RuntimeException("Stub!"); }
+
+public synchronized void load(java.io.InputStream inStream) throws java.io.IOException { throw new RuntimeException("Stub!"); }
+
+public synchronized void putAll(java.util.Map<?,?> t) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.util.Set<java.util.Map.Entry<java.lang.Object,java.lang.Object>> entrySet() { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.Object> keySet() { throw new RuntimeException("Stub!"); }
+
+public java.util.Collection<java.lang.Object> values() { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object put(java.lang.Object key, java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object putIfAbsent(java.lang.Object key, java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object remove(java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean remove(java.lang.Object key, java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean replace(java.lang.Object key, java.lang.Object oldValue, java.lang.Object newValue) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object replace(java.lang.Object key, java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public synchronized void replaceAll(java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?> function) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object compute(java.lang.Object key, java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object computeIfAbsent(java.lang.Object key, java.util.function.Function<? super java.lang.Object,?> mappingFunction) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object computeIfPresent(java.lang.Object key, java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object merge(java.lang.Object key, java.lang.Object value, java.util.function.BiFunction<? super java.lang.Object,? super java.lang.Object,?> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object get(java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.lang.Object getOrDefault(java.lang.Object key, java.lang.Object defaultValue) { throw new RuntimeException("Stub!"); }
+
+public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object,? super java.lang.Object> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.Enumeration<java.lang.Object> keys() { throw new RuntimeException("Stub!"); }
+
+public java.util.Enumeration<java.lang.Object> elements() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getProperty(java.lang.String key) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.security.Provider.Service getService(java.lang.String type, java.lang.String algorithm) { throw new RuntimeException("Stub!"); }
+
+public synchronized java.util.Set<java.security.Provider.Service> getServices() { throw new RuntimeException("Stub!"); }
+
+protected synchronized void putService(java.security.Provider.Service s) { throw new RuntimeException("Stub!"); }
+
+protected synchronized void removeService(java.security.Provider.Service s) { throw new RuntimeException("Stub!"); }
+
+public void setRegistered() { throw new RuntimeException("Stub!"); }
+
+public void setUnregistered() { throw new RuntimeException("Stub!"); }
+
+public boolean isRegistered() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public synchronized void warmUpServiceProvision() { throw new RuntimeException("Stub!"); }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class Service {
+
+public Service(java.security.Provider provider, java.lang.String type, java.lang.String algorithm, java.lang.String className, java.util.List<java.lang.String> aliases, java.util.Map<java.lang.String, java.lang.String> attributes) { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getType() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public final java.security.Provider getProvider() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getClassName() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAttribute(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object newInstance(java.lang.Object constructorParameter) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public boolean supportsParameter(java.lang.Object parameter) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
+}
+
diff --git a/java/security/Provider.java b/java/security/Provider.java
new file mode 100644
index 0000000..9936859
--- /dev/null
+++ b/java/security/Provider.java
@@ -0,0 +1,1926 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.util.Locale.ENGLISH;
+
+import java.lang.ref.*;
+import java.lang.reflect.*;
+import java.security.Security;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * This class represents a "provider" for the
+ * Java Security API, where a provider implements some or all parts of
+ * Java Security. Services that a provider may implement include:
+ *
+ * <ul>
+ *
+ * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
+ *
+ * <li>Key generation, conversion, and management facilities (such as for
+ * algorithm-specific keys).
+ *
+ *</ul>
+ *
+ * <p>Each provider has a name and a version number, and is configured
+ * in each runtime it is installed in.
+ *
+ * <p>See <a href =
+ * "../../../technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
+ * in the "Java Cryptography Architecture API Specification &amp; Reference"
+ * for information about how a particular type of provider, the
+ * cryptographic service provider, works and is installed. However,
+ * please note that a provider can be used to implement any security
+ * service in Java that uses a pluggable architecture with a choice
+ * of implementations that fit underneath.
+ *
+ * <p>Some provider implementations may encounter unrecoverable internal
+ * errors during their operation, for example a failure to communicate with a
+ * security token. A {@link ProviderException} should be used to indicate
+ * such errors.
+ *
+ * <p>The service type {@code Provider} is reserved for use by the
+ * security framework. Services of this type cannot be added, removed,
+ * or modified by applications.
+ * The following attributes are automatically placed in each Provider object:
+ * <table cellspacing=4>
+ * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
+ * <tr><th>Name</th><th>Value</th>
+ * <tr><td>{@code Provider.id name}</td>
+  *    <td>{@code String.valueOf(provider.getName())}</td>
+ * <tr><td>{@code Provider.id version}</td>
+ *     <td>{@code String.valueOf(provider.getVersion())}</td>
+ * <tr><td>{@code Provider.id info}</td>
+       <td>{@code String.valueOf(provider.getInfo())}</td>
+ * <tr><td>{@code Provider.id className}</td>
+ *     <td>{@code provider.getClass().getName()}</td>
+ * </table>
+ *
+ * @author Benjamin Renaud
+ * @author Andreas Sterbenz
+ */
+public abstract class Provider extends Properties {
+
+    // Declare serialVersionUID to be compatible with JDK1.1
+    static final long serialVersionUID = -4298000515446427739L;
+
+    // Android-added: Provider registration
+    // Marking a provider as "registered" makes it change the security version when
+    // changes to it are made.  As of 2017-05-22 this is only used in ProviderTest.
+    // TODO: Change ProviderTest to no longer require this mechanism
+    private volatile boolean registered = false;
+
+    private static final sun.security.util.Debug debug =
+        sun.security.util.Debug.getInstance
+        ("provider", "Provider");
+
+    /**
+     * The provider name.
+     *
+     * @serial
+     */
+    private String name;
+
+    /**
+     * A description of the provider and its services.
+     *
+     * @serial
+     */
+    private String info;
+
+    /**
+     * The provider version number.
+     *
+     * @serial
+     */
+    private double version;
+
+
+    private transient Set<Map.Entry<Object,Object>> entrySet = null;
+    private transient int entrySetCallCount = 0;
+
+    private transient boolean initialized;
+
+    /**
+     * Constructs a provider with the specified name, version number,
+     * and information.
+     *
+     * @param name the provider name.
+     *
+     * @param version the provider version number.
+     *
+     * @param info a description of the provider and its services.
+     */
+    protected Provider(String name, double version, String info) {
+        this.name = name;
+        this.version = version;
+        this.info = info;
+        putId();
+        initialized = true;
+    }
+
+    /**
+     * Returns the name of this provider.
+     *
+     * @return the name of this provider.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the version number for this provider.
+     *
+     * @return the version number for this provider.
+     */
+    public double getVersion() {
+        return version;
+    }
+
+    /**
+     * Returns a human-readable description of the provider and its
+     * services.  This may return an HTML page, with relevant links.
+     *
+     * @return a description of the provider and its services.
+     */
+    public String getInfo() {
+        return info;
+    }
+
+    /**
+     * Returns a string with the name and the version number
+     * of this provider.
+     *
+     * @return the string with the name and the version number
+     * for this provider.
+     */
+    public String toString() {
+        return name + " version " + version;
+    }
+
+    /*
+     * override the following methods to ensure that provider
+     * information can only be changed if the caller has the appropriate
+     * permissions.
+     */
+
+    /**
+     * Clears this provider so that it no longer contains the properties
+     * used to look up facilities implemented by the provider.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "clearProviderProperties."+name}
+     * (where {@code name} is the provider name) to see if it's ok to clear
+     * this provider.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to clear this provider
+     *
+     * @since 1.2
+     */
+    @Override
+    public synchronized void clear() {
+        check("clearProviderProperties."+name);
+        if (debug != null) {
+            debug.println("Remove " + name + " provider properties");
+        }
+        implClear();
+    }
+
+    /**
+     * Reads a property list (key and element pairs) from the input stream.
+     *
+     * @param inStream   the input stream.
+     * @exception  IOException  if an error occurred when reading from the
+     *               input stream.
+     * @see java.util.Properties#load
+     */
+    @Override
+    public synchronized void load(InputStream inStream) throws IOException {
+        check("putProviderProperty."+name);
+        if (debug != null) {
+            debug.println("Load " + name + " provider properties");
+        }
+        Properties tempProperties = new Properties();
+        tempProperties.load(inStream);
+        implPutAll(tempProperties);
+    }
+
+    /**
+     * Copies all of the mappings from the specified Map to this provider.
+     * These mappings will replace any properties that this provider had
+     * for any of the keys currently in the specified Map.
+     *
+     * @since 1.2
+     */
+    @Override
+    public synchronized void putAll(Map<?,?> t) {
+        check("putProviderProperty."+name);
+        if (debug != null) {
+            debug.println("Put all " + name + " provider properties");
+        }
+        implPutAll(t);
+    }
+
+    /**
+     * Returns an unmodifiable Set view of the property entries contained
+     * in this Provider.
+     *
+     * @see   java.util.Map.Entry
+     * @since 1.2
+     */
+    @Override
+    public synchronized Set<Map.Entry<Object,Object>> entrySet() {
+        checkInitialized();
+        if (entrySet == null) {
+            if (entrySetCallCount++ == 0)  // Initial call
+                entrySet = Collections.unmodifiableMap(this).entrySet();
+            else
+                return super.entrySet();   // Recursive call
+        }
+
+        // This exception will be thrown if the implementation of
+        // Collections.unmodifiableMap.entrySet() is changed such that it
+        // no longer calls entrySet() on the backing Map.  (Provider's
+        // entrySet implementation depends on this "implementation detail",
+        // which is unlikely to change.
+        if (entrySetCallCount != 2)
+            throw new RuntimeException("Internal error.");
+
+        return entrySet;
+    }
+
+    /**
+     * Returns an unmodifiable Set view of the property keys contained in
+     * this provider.
+     *
+     * @since 1.2
+     */
+    @Override
+    public Set<Object> keySet() {
+        checkInitialized();
+        return Collections.unmodifiableSet(super.keySet());
+    }
+
+    /**
+     * Returns an unmodifiable Collection view of the property values
+     * contained in this provider.
+     *
+     * @since 1.2
+     */
+    @Override
+    public Collection<Object> values() {
+        checkInitialized();
+        return Collections.unmodifiableCollection(super.values());
+    }
+
+    /**
+     * Sets the {@code key} property to have the specified
+     * {@code value}.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "putProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to set this
+     * provider's property values.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values.
+     *
+     * @since 1.2
+     */
+    @Override
+    public synchronized Object put(Object key, Object value) {
+        check("putProviderProperty."+name);
+        if (debug != null) {
+            debug.println("Set " + name + " provider property [" +
+                          key + "/" + value +"]");
+        }
+        return implPut(key, value);
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}) associates it with the given value and returns
+     * {@code null}, else returns the current value.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "putProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to set this
+     * provider's property values.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object putIfAbsent(Object key, Object value) {
+        check("putProviderProperty."+name);
+        if (debug != null) {
+            debug.println("Set " + name + " provider property [" +
+                          key + "/" + value +"]");
+        }
+        return implPutIfAbsent(key, value);
+    }
+
+    /**
+     * Removes the {@code key} property (and its corresponding
+     * {@code value}).
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "removeProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to remove this
+     * provider's properties.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to remove this provider's properties.
+     *
+     * @since 1.2
+     */
+    @Override
+    public synchronized Object remove(Object key) {
+        check("removeProviderProperty."+name);
+        if (debug != null) {
+            debug.println("Remove " + name + " provider property " + key);
+        }
+        return implRemove(key);
+    }
+
+    /**
+     * Removes the entry for the specified key only if it is currently
+     * mapped to the specified value.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "removeProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to remove this
+     * provider's properties.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to remove this provider's properties.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        check("removeProviderProperty."+name);
+        if (debug != null) {
+            debug.println("Remove " + name + " provider property " + key);
+        }
+        return implRemove(key, value);
+    }
+
+    /**
+     * Replaces the entry for the specified key only if currently
+     * mapped to the specified value.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "putProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to set this
+     * provider's property values.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized boolean replace(Object key, Object oldValue,
+            Object newValue) {
+        check("putProviderProperty." + name);
+
+        if (debug != null) {
+            debug.println("Replace " + name + " provider property " + key);
+        }
+        return implReplace(key, oldValue, newValue);
+    }
+
+    /**
+     * Replaces the entry for the specified key only if it is
+     * currently mapped to some value.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "putProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to set this
+     * provider's property values.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object replace(Object key, Object value) {
+        check("putProviderProperty." + name);
+
+        if (debug != null) {
+            debug.println("Replace " + name + " provider property " + key);
+        }
+        return implReplace(key, value);
+    }
+
+    /**
+     * Replaces each entry's value with the result of invoking the given
+     * function on that entry, in the order entries are returned by an entry
+     * set iterator, until all entries have been processed or the function
+     * throws an exception.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the string {@code "putProviderProperty."+name},
+     * where {@code name} is the provider name, to see if it's ok to set this
+     * provider's property values.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
+        check("putProviderProperty." + name);
+
+        if (debug != null) {
+            debug.println("ReplaceAll " + name + " provider property ");
+        }
+        implReplaceAll(function);
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping).
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the strings {@code "putProviderProperty."+name}
+     * and {@code "removeProviderProperty."+name}, where {@code name} is the
+     * provider name, to see if it's ok to set this provider's property values
+     * and remove this provider's properties.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values or remove properties.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object compute(Object key,
+        BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+        check("putProviderProperty." + name);
+        check("removeProviderProperty" + name);
+
+        if (debug != null) {
+            debug.println("Compute " + name + " provider property " + key);
+        }
+        return implCompute(key, remappingFunction);
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or
+     * is mapped to {@code null}), attempts to compute its value using
+     * the given mapping function and enters it into this map unless
+     * {@code null}.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the strings {@code "putProviderProperty."+name}
+     * and {@code "removeProviderProperty."+name}, where {@code name} is the
+     * provider name, to see if it's ok to set this provider's property values
+     * and remove this provider's properties.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values and remove properties.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object computeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
+        check("putProviderProperty." + name);
+        check("removeProviderProperty" + name);
+
+        if (debug != null) {
+            debug.println("ComputeIfAbsent " + name + " provider property " +
+                    key);
+        }
+        return implComputeIfAbsent(key, mappingFunction);
+    }
+
+    /**
+     * If the value for the specified key is present and non-null, attempts to
+     * compute a new mapping given the key and its current mapped value.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the strings {@code "putProviderProperty."+name}
+     * and {@code "removeProviderProperty."+name}, where {@code name} is the
+     * provider name, to see if it's ok to set this provider's property values
+     * and remove this provider's properties.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values or remove properties.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+        check("putProviderProperty." + name);
+        check("removeProviderProperty" + name);
+
+        if (debug != null) {
+            debug.println("ComputeIfPresent " + name + " provider property " +
+                    key);
+        }
+        return implComputeIfPresent(key, remappingFunction);
+    }
+
+    /**
+     * If the specified key is not already associated with a value or is
+     * associated with null, associates it with the given value. Otherwise,
+     * replaces the value with the results of the given remapping function,
+     * or removes if the result is null. This method may be of use when
+     * combining multiple mapped values for a key.
+     *
+     * <p>If a security manager is enabled, its {@code checkSecurityAccess}
+     * method is called with the strings {@code "putProviderProperty."+name}
+     * and {@code "removeProviderProperty."+name}, where {@code name} is the
+     * provider name, to see if it's ok to set this provider's property values
+     * and remove this provider's properties.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to set property values or remove properties.
+     *
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object merge(Object key, Object value,  BiFunction<? super Object, ? super Object, ? extends Object>  remappingFunction) {
+        check("putProviderProperty." + name);
+        check("removeProviderProperty" + name);
+
+        if (debug != null) {
+            debug.println("Merge " + name + " provider property " + key);
+        }
+        return implMerge(key, value, remappingFunction);
+    }
+
+    // let javadoc show doc from superclass
+    @Override
+    public Object get(Object key) {
+        checkInitialized();
+        return super.get(key);
+    }
+    /**
+     * @since 1.8
+     */
+    @Override
+    public synchronized Object getOrDefault(Object key, Object defaultValue) {
+        checkInitialized();
+        return super.getOrDefault(key, defaultValue);
+    }
+
+    /**
+     * @since 1.8
+     */
+    @Override
+    public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
+        checkInitialized();
+        super.forEach(action);
+    }
+
+    // let javadoc show doc from superclass
+    @Override
+    public Enumeration<Object> keys() {
+        checkInitialized();
+        return super.keys();
+    }
+
+    // let javadoc show doc from superclass
+    @Override
+    public Enumeration<Object> elements() {
+        checkInitialized();
+        return super.elements();
+    }
+
+    // let javadoc show doc from superclass
+    public String getProperty(String key) {
+        checkInitialized();
+        return super.getProperty(key);
+    }
+
+    private void checkInitialized() {
+        if (!initialized) {
+            throw new IllegalStateException();
+        }
+    }
+
+    private void check(String directive) {
+        checkInitialized();
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSecurityAccess(directive);
+        }
+    }
+
+    // legacy properties changed since last call to any services method?
+    private transient boolean legacyChanged;
+    // serviceMap changed since last call to getServices()
+    private transient boolean servicesChanged;
+
+    // Map<String,String>
+    private transient Map<String,String> legacyStrings;
+
+    // Map<ServiceKey,Service>
+    // used for services added via putService(), initialized on demand
+    private transient Map<ServiceKey,Service> serviceMap;
+
+    // Map<ServiceKey,Service>
+    // used for services added via legacy methods, init on demand
+    private transient Map<ServiceKey,Service> legacyMap;
+
+    // Set<Service>
+    // Unmodifiable set of all services. Initialized on demand.
+    private transient Set<Service> serviceSet;
+
+    // register the id attributes for this provider
+    // this is to ensure that equals() and hashCode() do not incorrectly
+    // report to different provider objects as the same
+    private void putId() {
+        // note: name and info may be null
+        super.put("Provider.id name", String.valueOf(name));
+        super.put("Provider.id version", String.valueOf(version));
+        super.put("Provider.id info", String.valueOf(info));
+        super.put("Provider.id className", this.getClass().getName());
+    }
+
+    private void readObject(ObjectInputStream in)
+                throws IOException, ClassNotFoundException {
+        // Android-added: Provider registration
+        registered = false;
+        Map<Object,Object> copy = new HashMap<>();
+        for (Map.Entry<Object,Object> entry : super.entrySet()) {
+            copy.put(entry.getKey(), entry.getValue());
+        }
+        defaults = null;
+        in.defaultReadObject();
+        implClear();
+        initialized = true;
+        putAll(copy);
+    }
+
+    private boolean checkLegacy(Object key) {
+        // Android-added: Provider registration
+        if (registered) {
+            Security.increaseVersion();
+        }
+        String keyString = (String)key;
+        if (keyString.startsWith("Provider.")) {
+            return false;
+        }
+
+        legacyChanged = true;
+        if (legacyStrings == null) {
+            legacyStrings = new LinkedHashMap<String,String>();
+        }
+        return true;
+    }
+
+    /**
+     * Copies all of the mappings from the specified Map to this provider.
+     * Internal method to be called AFTER the security check has been
+     * performed.
+     */
+    private void implPutAll(Map<?,?> t) {
+        for (Map.Entry<?,?> e : t.entrySet()) {
+            implPut(e.getKey(), e.getValue());
+        }
+        // Android-added: Provider registration
+        if (registered) {
+            Security.increaseVersion();
+        }
+    }
+
+    private Object implRemove(Object key) {
+        if (key instanceof String) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.remove((String)key);
+        }
+        return super.remove(key);
+    }
+
+    private boolean implRemove(Object key, Object value) {
+        if (key instanceof String && value instanceof String) {
+            if (!checkLegacy(key)) {
+                return false;
+            }
+            legacyStrings.remove((String)key, value);
+        }
+        return super.remove(key, value);
+    }
+
+    private boolean implReplace(Object key, Object oldValue, Object newValue) {
+        if ((key instanceof String) && (oldValue instanceof String) &&
+                (newValue instanceof String)) {
+            if (!checkLegacy(key)) {
+                return false;
+            }
+            legacyStrings.replace((String)key, (String)oldValue,
+                    (String)newValue);
+        }
+        return super.replace(key, oldValue, newValue);
+    }
+
+    private Object implReplace(Object key, Object value) {
+        if ((key instanceof String) && (value instanceof String)) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.replace((String)key, (String)value);
+        }
+        return super.replace(key, value);
+    }
+
+    private void implReplaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
+        legacyChanged = true;
+        if (legacyStrings == null) {
+            legacyStrings = new LinkedHashMap<String,String>();
+        } else {
+            legacyStrings.replaceAll((BiFunction<? super String, ? super String, ? extends String>) function);
+        }
+        super.replaceAll(function);
+    }
+
+
+    private Object implMerge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+        if ((key instanceof String) && (value instanceof String)) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.merge((String)key, (String)value,
+                    (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
+        }
+        return super.merge(key, value, remappingFunction);
+    }
+
+    private Object implCompute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+        if (key instanceof String) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            // BEGIN Android-changed: use compute() instead of computeIfAbsent() to avoid cast fails
+            // The upstream code cannot ever succeed as the cast from BiFunction to Function
+            // always fails.
+            // legacyStrings.computeIfAbsent((String) key,
+            //         (Function<? super String, ? extends String>) remappingFunction);
+            legacyStrings.compute((String) key,
+                    (BiFunction<? super String, ? super String, ? extends String>)
+                            remappingFunction);
+            // END Android-changed: use compute() instead of computeIfAbsent() to avoid cast fails
+        }
+        return super.compute(key, remappingFunction);
+    }
+
+    private Object implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
+        if (key instanceof String) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.computeIfAbsent((String) key,
+                    (Function<? super String, ? extends String>) mappingFunction);
+        }
+        return super.computeIfAbsent(key, mappingFunction);
+    }
+
+    private Object implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
+        if (key instanceof String) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.computeIfPresent((String) key,
+                    (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
+        }
+        return super.computeIfPresent(key, remappingFunction);
+    }
+
+    private Object implPut(Object key, Object value) {
+        if ((key instanceof String) && (value instanceof String)) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.put((String)key, (String)value);
+        }
+        return super.put(key, value);
+    }
+
+    private Object implPutIfAbsent(Object key, Object value) {
+        if ((key instanceof String) && (value instanceof String)) {
+            if (!checkLegacy(key)) {
+                return null;
+            }
+            legacyStrings.putIfAbsent((String)key, (String)value);
+        }
+        return super.putIfAbsent(key, value);
+    }
+
+    private void implClear() {
+        if (legacyStrings != null) {
+            legacyStrings.clear();
+        }
+        if (legacyMap != null) {
+            legacyMap.clear();
+        }
+        if (serviceMap != null) {
+            serviceMap.clear();
+        }
+        legacyChanged = false;
+        servicesChanged = false;
+        serviceSet = null;
+        super.clear();
+        putId();
+        // Android-added: Provider registration
+        if (registered) {
+          Security.increaseVersion();
+        }
+    }
+
+    // used as key in the serviceMap and legacyMap HashMaps
+    private static class ServiceKey {
+        private final String type;
+        private final String algorithm;
+        private final String originalAlgorithm;
+        private ServiceKey(String type, String algorithm, boolean intern) {
+            this.type = type;
+            this.originalAlgorithm = algorithm;
+            algorithm = algorithm.toUpperCase(ENGLISH);
+            this.algorithm = intern ? algorithm.intern() : algorithm;
+        }
+        public int hashCode() {
+            return type.hashCode() + algorithm.hashCode();
+        }
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof ServiceKey == false) {
+                return false;
+            }
+            ServiceKey other = (ServiceKey)obj;
+            return this.type.equals(other.type)
+                && this.algorithm.equals(other.algorithm);
+        }
+        boolean matches(String type, String algorithm) {
+            return (this.type == type) && (this.originalAlgorithm == algorithm);
+        }
+    }
+
+    /**
+     * Ensure all the legacy String properties are fully parsed into
+     * service objects.
+     */
+    private void ensureLegacyParsed() {
+        if ((legacyChanged == false) || (legacyStrings == null)) {
+            return;
+        }
+        serviceSet = null;
+        if (legacyMap == null) {
+            legacyMap = new LinkedHashMap<ServiceKey,Service>();
+        } else {
+            legacyMap.clear();
+        }
+        for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
+            parseLegacyPut(entry.getKey(), entry.getValue());
+        }
+        removeInvalidServices(legacyMap);
+        legacyChanged = false;
+    }
+
+    /**
+     * Remove all invalid services from the Map. Invalid services can only
+     * occur if the legacy properties are inconsistent or incomplete.
+     */
+    private void removeInvalidServices(Map<ServiceKey,Service> map) {
+        for (Iterator<Map.Entry<ServiceKey, Service>> t =
+                map.entrySet().iterator(); t.hasNext(); ) {
+            Service s = t.next().getValue();
+            if (s.isValid() == false) {
+                t.remove();
+            }
+        }
+    }
+
+    private String[] getTypeAndAlgorithm(String key) {
+        int i = key.indexOf(".");
+        if (i < 1) {
+            if (debug != null) {
+                debug.println("Ignoring invalid entry in provider "
+                        + name + ":" + key);
+            }
+            return null;
+        }
+        String type = key.substring(0, i);
+        String alg = key.substring(i + 1);
+        return new String[] {type, alg};
+    }
+
+    private final static String ALIAS_PREFIX = "Alg.Alias.";
+    private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
+    private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
+
+    private void parseLegacyPut(String name, String value) {
+        if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
+            // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
+            // aliasKey ~ MessageDigest.SHA
+            String stdAlg = value;
+            String aliasKey = name.substring(ALIAS_LENGTH);
+            String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
+            if (typeAndAlg == null) {
+                return;
+            }
+            String type = getEngineName(typeAndAlg[0]);
+            String aliasAlg = typeAndAlg[1].intern();
+            ServiceKey key = new ServiceKey(type, stdAlg, true);
+            Service s = legacyMap.get(key);
+            if (s == null) {
+                s = new Service(this);
+                s.type = type;
+                s.algorithm = stdAlg;
+                legacyMap.put(key, s);
+            }
+            legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
+            s.addAlias(aliasAlg);
+        } else {
+            String[] typeAndAlg = getTypeAndAlgorithm(name);
+            if (typeAndAlg == null) {
+                return;
+            }
+            int i = typeAndAlg[1].indexOf(' ');
+            if (i == -1) {
+                // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
+                String type = getEngineName(typeAndAlg[0]);
+                String stdAlg = typeAndAlg[1].intern();
+                String className = value;
+                ServiceKey key = new ServiceKey(type, stdAlg, true);
+                Service s = legacyMap.get(key);
+                if (s == null) {
+                    s = new Service(this);
+                    s.type = type;
+                    s.algorithm = stdAlg;
+                    legacyMap.put(key, s);
+                }
+                s.className = className;
+            } else { // attribute
+                // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
+                String attributeValue = value;
+                String type = getEngineName(typeAndAlg[0]);
+                String attributeString = typeAndAlg[1];
+                String stdAlg = attributeString.substring(0, i).intern();
+                String attributeName = attributeString.substring(i + 1);
+                // kill additional spaces
+                while (attributeName.startsWith(" ")) {
+                    attributeName = attributeName.substring(1);
+                }
+                attributeName = attributeName.intern();
+                ServiceKey key = new ServiceKey(type, stdAlg, true);
+                Service s = legacyMap.get(key);
+                if (s == null) {
+                    s = new Service(this);
+                    s.type = type;
+                    s.algorithm = stdAlg;
+                    legacyMap.put(key, s);
+                }
+                s.addAttribute(attributeName, attributeValue);
+            }
+        }
+    }
+
+    /**
+     * Get the service describing this Provider's implementation of the
+     * specified type of this algorithm or alias. If no such
+     * implementation exists, this method returns null. If there are two
+     * matching services, one added to this provider using
+     * {@link #putService putService()} and one added via {@link #put put()},
+     * the service added via {@link #putService putService()} is returned.
+     *
+     * @param type the type of {@link Service service} requested
+     * (for example, {@code MessageDigest})
+     * @param algorithm the case insensitive algorithm name (or alternate
+     * alias) of the service requested (for example, {@code SHA-1})
+     *
+     * @return the service describing this Provider's matching service
+     * or null if no such service exists
+     *
+     * @throws NullPointerException if type or algorithm is null
+     *
+     * @since 1.5
+     */
+    public synchronized Service getService(String type, String algorithm) {
+        checkInitialized();
+        // avoid allocating a new key object if possible
+        ServiceKey key = previousKey;
+        if (key.matches(type, algorithm) == false) {
+            key = new ServiceKey(type, algorithm, false);
+            previousKey = key;
+        }
+        if (serviceMap != null) {
+            Service service = serviceMap.get(key);
+            if (service != null) {
+                return service;
+            }
+        }
+        ensureLegacyParsed();
+        return (legacyMap != null) ? legacyMap.get(key) : null;
+    }
+
+    // ServiceKey from previous getService() call
+    // by re-using it if possible we avoid allocating a new object
+    // and the toUpperCase() call.
+    // re-use will occur e.g. as the framework traverses the provider
+    // list and queries each provider with the same values until it finds
+    // a matching service
+    private static volatile ServiceKey previousKey =
+                                            new ServiceKey("", "", false);
+
+    /**
+     * Get an unmodifiable Set of all services supported by
+     * this Provider.
+     *
+     * @return an unmodifiable Set of all services supported by
+     * this Provider
+     *
+     * @since 1.5
+     */
+    public synchronized Set<Service> getServices() {
+        checkInitialized();
+        if (legacyChanged || servicesChanged) {
+            serviceSet = null;
+        }
+        if (serviceSet == null) {
+            ensureLegacyParsed();
+            Set<Service> set = new LinkedHashSet<>();
+            if (serviceMap != null) {
+                set.addAll(serviceMap.values());
+            }
+            if (legacyMap != null) {
+                set.addAll(legacyMap.values());
+            }
+            serviceSet = Collections.unmodifiableSet(set);
+            servicesChanged = false;
+        }
+        return serviceSet;
+    }
+
+    /**
+     * Add a service. If a service of the same type with the same algorithm
+     * name exists and it was added using {@link #putService putService()},
+     * it is replaced by the new service.
+     * This method also places information about this service
+     * in the provider's Hashtable values in the format described in the
+     * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>.
+     *
+     * <p>Also, if there is a security manager, its
+     * {@code checkSecurityAccess} method is called with the string
+     * {@code "putProviderProperty."+name}, where {@code name} is
+     * the provider name, to see if it's ok to set this provider's property
+     * values. If the default implementation of {@code checkSecurityAccess}
+     * is used (that is, that method is not overriden), then this results in
+     * a call to the security manager's {@code checkPermission} method with
+     * a {@code SecurityPermission("putProviderProperty."+name)}
+     * permission.
+     *
+     * @param s the Service to add
+     *
+     * @throws SecurityException
+     *      if a security manager exists and its {@link
+     *      java.lang.SecurityManager#checkSecurityAccess} method denies
+     *      access to set property values.
+     * @throws NullPointerException if s is null
+     *
+     * @since 1.5
+     */
+    protected synchronized void putService(Service s) {
+        check("putProviderProperty." + name);
+        if (debug != null) {
+            debug.println(name + ".putService(): " + s);
+        }
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        if (s.getProvider() != this) {
+            throw new IllegalArgumentException
+                    ("service.getProvider() must match this Provider object");
+        }
+        if (serviceMap == null) {
+            serviceMap = new LinkedHashMap<ServiceKey,Service>();
+        }
+        servicesChanged = true;
+        String type = s.getType();
+        String algorithm = s.getAlgorithm();
+        ServiceKey key = new ServiceKey(type, algorithm, true);
+        // remove existing service
+        implRemoveService(serviceMap.get(key));
+        serviceMap.put(key, s);
+        for (String alias : s.getAliases()) {
+            serviceMap.put(new ServiceKey(type, alias, true), s);
+        }
+        putPropertyStrings(s);
+    }
+
+    /**
+     * Put the string properties for this Service in this Provider's
+     * Hashtable.
+     */
+    private void putPropertyStrings(Service s) {
+        String type = s.getType();
+        String algorithm = s.getAlgorithm();
+        // use super() to avoid permission check and other processing
+        super.put(type + "." + algorithm, s.getClassName());
+        for (String alias : s.getAliases()) {
+            super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
+        }
+        for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
+            String key = type + "." + algorithm + " " + entry.getKey();
+            super.put(key, entry.getValue());
+        }
+        // Android-added: Provider registration
+        if (registered) {
+            Security.increaseVersion();
+        }
+    }
+
+    /**
+     * Remove the string properties for this Service from this Provider's
+     * Hashtable.
+     */
+    private void removePropertyStrings(Service s) {
+        String type = s.getType();
+        String algorithm = s.getAlgorithm();
+        // use super() to avoid permission check and other processing
+        super.remove(type + "." + algorithm);
+        for (String alias : s.getAliases()) {
+            super.remove(ALIAS_PREFIX + type + "." + alias);
+        }
+        for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
+            String key = type + "." + algorithm + " " + entry.getKey();
+            super.remove(key);
+        }
+        // Android-added: Provider registration
+        if (registered) {
+          Security.increaseVersion();
+        }
+    }
+
+    /**
+     * Remove a service previously added using
+     * {@link #putService putService()}. The specified service is removed from
+     * this provider. It will no longer be returned by
+     * {@link #getService getService()} and its information will be removed
+     * from this provider's Hashtable.
+     *
+     * <p>Also, if there is a security manager, its
+     * {@code checkSecurityAccess} method is called with the string
+     * {@code "removeProviderProperty."+name}, where {@code name} is
+     * the provider name, to see if it's ok to remove this provider's
+     * properties. If the default implementation of
+     * {@code checkSecurityAccess} is used (that is, that method is not
+     * overriden), then this results in a call to the security manager's
+     * {@code checkPermission} method with a
+     * {@code SecurityPermission("removeProviderProperty."+name)}
+     * permission.
+     *
+     * @param s the Service to be removed
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method denies
+     *          access to remove this provider's properties.
+     * @throws NullPointerException if s is null
+     *
+     * @since 1.5
+     */
+    protected synchronized void removeService(Service s) {
+        check("removeProviderProperty." + name);
+        if (debug != null) {
+            debug.println(name + ".removeService(): " + s);
+        }
+        if (s == null) {
+            throw new NullPointerException();
+        }
+        implRemoveService(s);
+    }
+
+    private void implRemoveService(Service s) {
+        if ((s == null) || (serviceMap == null)) {
+            return;
+        }
+        String type = s.getType();
+        String algorithm = s.getAlgorithm();
+        ServiceKey key = new ServiceKey(type, algorithm, false);
+        Service oldService = serviceMap.get(key);
+        if (s != oldService) {
+            return;
+        }
+        servicesChanged = true;
+        serviceMap.remove(key);
+        for (String alias : s.getAliases()) {
+            serviceMap.remove(new ServiceKey(type, alias, false));
+        }
+        removePropertyStrings(s);
+    }
+
+    // Wrapped String that behaves in a case insensitive way for equals/hashCode
+    private static class UString {
+        final String string;
+        final String lowerString;
+
+        UString(String s) {
+            this.string = s;
+            this.lowerString = s.toLowerCase(ENGLISH);
+        }
+
+        public int hashCode() {
+            return lowerString.hashCode();
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj instanceof UString == false) {
+                return false;
+            }
+            UString other = (UString)obj;
+            return lowerString.equals(other.lowerString);
+        }
+
+        public String toString() {
+            return string;
+        }
+    }
+
+    // describe relevant properties of a type of engine
+    private static class EngineDescription {
+        final String name;
+        final boolean supportsParameter;
+        final String constructorParameterClassName;
+        private volatile Class<?> constructorParameterClass;
+
+        EngineDescription(String name, boolean sp, String paramName) {
+            this.name = name;
+            this.supportsParameter = sp;
+            this.constructorParameterClassName = paramName;
+        }
+        Class<?> getConstructorParameterClass() throws ClassNotFoundException {
+            Class<?> clazz = constructorParameterClass;
+            if (clazz == null) {
+                clazz = Class.forName(constructorParameterClassName);
+                constructorParameterClass = clazz;
+            }
+            return clazz;
+        }
+    }
+
+    // built in knowledge of the engine types shipped as part of the JDK
+    private static final Map<String,EngineDescription> knownEngines;
+
+    private static void addEngine(String name, boolean sp, String paramName) {
+        EngineDescription ed = new EngineDescription(name, sp, paramName);
+        // also index by canonical name to avoid toLowerCase() for some lookups
+        knownEngines.put(name.toLowerCase(ENGLISH), ed);
+        knownEngines.put(name, ed);
+    }
+
+    static {
+        knownEngines = new HashMap<String,EngineDescription>();
+        // JCA
+        addEngine("AlgorithmParameterGenerator",        false, null);
+        addEngine("AlgorithmParameters",                false, null);
+        addEngine("KeyFactory",                         false, null);
+        addEngine("KeyPairGenerator",                   false, null);
+        addEngine("KeyStore",                           false, null);
+        addEngine("MessageDigest",                      false, null);
+        addEngine("SecureRandom",                       false, null);
+        addEngine("Signature",                          true,  null);
+        addEngine("CertificateFactory",                 false, null);
+        addEngine("CertPathBuilder",                    false, null);
+        addEngine("CertPathValidator",                  false, null);
+        addEngine("CertStore",                          false,
+                            "java.security.cert.CertStoreParameters");
+        // JCE
+        addEngine("Cipher",                             true,  null);
+        addEngine("ExemptionMechanism",                 false, null);
+        addEngine("Mac",                                true,  null);
+        addEngine("KeyAgreement",                       true,  null);
+        addEngine("KeyGenerator",                       false, null);
+        addEngine("SecretKeyFactory",                   false, null);
+        // JSSE
+        addEngine("KeyManagerFactory",                  false, null);
+        addEngine("SSLContext",                         false, null);
+        addEngine("TrustManagerFactory",                false, null);
+        // JGSS
+        addEngine("GssApiMechanism",                    false, null);
+        // SASL
+        addEngine("SaslClientFactory",                  false, null);
+        addEngine("SaslServerFactory",                  false, null);
+        // POLICY
+        addEngine("Policy",                             false,
+                            "java.security.Policy$Parameters");
+        // CONFIGURATION
+        addEngine("Configuration",                      false,
+                            "javax.security.auth.login.Configuration$Parameters");
+        // XML DSig
+        addEngine("XMLSignatureFactory",                false, null);
+        addEngine("KeyInfoFactory",                     false, null);
+        addEngine("TransformService",                   false, null);
+        // Smart Card I/O
+        addEngine("TerminalFactory",                    false,
+                            "java.lang.Object");
+    }
+
+    // get the "standard" (mixed-case) engine name for arbitary case engine name
+    // if there is no known engine by that name, return s
+    private static String getEngineName(String s) {
+        // try original case first, usually correct
+        EngineDescription e = knownEngines.get(s);
+        if (e == null) {
+            e = knownEngines.get(s.toLowerCase(ENGLISH));
+        }
+        return (e == null) ? s : e.name;
+    }
+
+    /**
+     * The description of a security service. It encapsulates the properties
+     * of a service and contains a factory method to obtain new implementation
+     * instances of this service.
+     *
+     * <p>Each service has a provider that offers the service, a type,
+     * an algorithm name, and the name of the class that implements the
+     * service. Optionally, it also includes a list of alternate algorithm
+     * names for this service (aliases) and attributes, which are a map of
+     * (name, value) String pairs.
+     *
+     * <p>This class defines the methods {@link #supportsParameter
+     * supportsParameter()} and {@link #newInstance newInstance()}
+     * which are used by the Java security framework when it searches for
+     * suitable services and instantiates them. The valid arguments to those
+     * methods depend on the type of service. For the service types defined
+     * within Java SE, see the
+     * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for the valid values.
+     * Note that components outside of Java SE can define additional types of
+     * services and their behavior.
+     *
+     * <p>Instances of this class are immutable.
+     *
+     * @since 1.5
+     */
+    public static class Service {
+
+        private String type, algorithm, className;
+        private final Provider provider;
+        private List<String> aliases;
+        private Map<UString,String> attributes;
+
+        // Reference to the cached implementation Class object
+        private volatile Reference<Class<?>> classRef;
+
+        // flag indicating whether this service has its attributes for
+        // supportedKeyFormats or supportedKeyClasses set
+        // if null, the values have not been initialized
+        // if TRUE, at least one of supportedFormats/Classes is non null
+        private volatile Boolean hasKeyAttributes;
+
+        // supported encoding formats
+        private String[] supportedFormats;
+
+        // names of the supported key (super) classes
+        private Class[] supportedClasses;
+
+        // whether this service has been registered with the Provider
+        private boolean registered;
+
+        private static final Class<?>[] CLASS0 = new Class<?>[0];
+
+        // this constructor and these methods are used for parsing
+        // the legacy string properties.
+
+        private Service(Provider provider) {
+            this.provider = provider;
+            aliases = Collections.<String>emptyList();
+            attributes = Collections.<UString,String>emptyMap();
+        }
+
+        private boolean isValid() {
+            return (type != null) && (algorithm != null) && (className != null);
+        }
+
+        private void addAlias(String alias) {
+            if (aliases.isEmpty()) {
+                aliases = new ArrayList<String>(2);
+            }
+            aliases.add(alias);
+        }
+
+        void addAttribute(String type, String value) {
+            if (attributes.isEmpty()) {
+                attributes = new HashMap<UString,String>(8);
+            }
+            attributes.put(new UString(type), value);
+        }
+
+        /**
+         * Construct a new service.
+         *
+         * @param provider the provider that offers this service
+         * @param type the type of this service
+         * @param algorithm the algorithm name
+         * @param className the name of the class implementing this service
+         * @param aliases List of aliases or null if algorithm has no aliases
+         * @param attributes Map of attributes or null if this implementation
+         *                   has no attributes
+         *
+         * @throws NullPointerException if provider, type, algorithm, or
+         * className is null
+         */
+        public Service(Provider provider, String type, String algorithm,
+                String className, List<String> aliases,
+                Map<String,String> attributes) {
+            if ((provider == null) || (type == null) ||
+                    (algorithm == null) || (className == null)) {
+                throw new NullPointerException();
+            }
+            this.provider = provider;
+            this.type = getEngineName(type);
+            this.algorithm = algorithm;
+            this.className = className;
+            if (aliases == null) {
+                this.aliases = Collections.<String>emptyList();
+            } else {
+                this.aliases = new ArrayList<String>(aliases);
+            }
+            if (attributes == null) {
+                this.attributes = Collections.<UString,String>emptyMap();
+            } else {
+                this.attributes = new HashMap<UString,String>();
+                for (Map.Entry<String,String> entry : attributes.entrySet()) {
+                    this.attributes.put(new UString(entry.getKey()), entry.getValue());
+                }
+            }
+        }
+
+        /**
+         * Get the type of this service. For example, {@code MessageDigest}.
+         *
+         * @return the type of this service
+         */
+        public final String getType() {
+            return type;
+        }
+
+        /**
+         * Return the name of the algorithm of this service. For example,
+         * {@code SHA-1}.
+         *
+         * @return the algorithm of this service
+         */
+        public final String getAlgorithm() {
+            return algorithm;
+        }
+
+        /**
+         * Return the Provider of this service.
+         *
+         * @return the Provider of this service
+         */
+        public final Provider getProvider() {
+            return provider;
+        }
+
+        /**
+         * Return the name of the class implementing this service.
+         *
+         * @return the name of the class implementing this service
+         */
+        public final String getClassName() {
+            return className;
+        }
+
+        // internal only
+        private final List<String> getAliases() {
+            return aliases;
+        }
+
+        /**
+         * Return the value of the specified attribute or null if this
+         * attribute is not set for this Service.
+         *
+         * @param name the name of the requested attribute
+         *
+         * @return the value of the specified attribute or null if the
+         *         attribute is not present
+         *
+         * @throws NullPointerException if name is null
+         */
+        public final String getAttribute(String name) {
+            if (name == null) {
+                throw new NullPointerException();
+            }
+            return attributes.get(new UString(name));
+        }
+
+        /**
+         * Return a new instance of the implementation described by this
+         * service. The security provider framework uses this method to
+         * construct implementations. Applications will typically not need
+         * to call it.
+         *
+         * <p>The default implementation uses reflection to invoke the
+         * standard constructor for this type of service.
+         * Security providers can override this method to implement
+         * instantiation in a different way.
+         * For details and the values of constructorParameter that are
+         * valid for the various types of services see the
+         * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+         * Java Cryptography Architecture API Specification &amp;
+         * Reference</a>.
+         *
+         * @param constructorParameter the value to pass to the constructor,
+         * or null if this type of service does not use a constructorParameter.
+         *
+         * @return a new implementation of this service
+         *
+         * @throws InvalidParameterException if the value of
+         * constructorParameter is invalid for this type of service.
+         * @throws NoSuchAlgorithmException if instantiation failed for
+         * any other reason.
+         */
+        public Object newInstance(Object constructorParameter)
+                throws NoSuchAlgorithmException {
+            if (registered == false) {
+                if (provider.getService(type, algorithm) != this) {
+                    throw new NoSuchAlgorithmException
+                        ("Service not registered with Provider "
+                        + provider.getName() + ": " + this);
+                }
+                registered = true;
+            }
+            try {
+                EngineDescription cap = knownEngines.get(type);
+                if (cap == null) {
+                    // unknown engine type, use generic code
+                    // this is the code path future for non-core
+                    // optional packages
+                    return newInstanceGeneric(constructorParameter);
+                }
+                if (cap.constructorParameterClassName == null) {
+                    if (constructorParameter != null) {
+                        throw new InvalidParameterException
+                            ("constructorParameter not used with " + type
+                            + " engines");
+                    }
+                    Class<?> clazz = getImplClass();
+                    Class<?>[] empty = {};
+                    Constructor<?> con = clazz.getConstructor(empty);
+                    return con.newInstance();
+                } else {
+                    Class<?> paramClass = cap.getConstructorParameterClass();
+                    if (constructorParameter != null) {
+                        Class<?> argClass = constructorParameter.getClass();
+                        if (paramClass.isAssignableFrom(argClass) == false) {
+                            throw new InvalidParameterException
+                            ("constructorParameter must be instanceof "
+                            + cap.constructorParameterClassName.replace('$', '.')
+                            + " for engine type " + type);
+                        }
+                    }
+                    Class<?> clazz = getImplClass();
+                    Constructor<?> cons = clazz.getConstructor(paramClass);
+                    return cons.newInstance(constructorParameter);
+                }
+            } catch (NoSuchAlgorithmException e) {
+                throw e;
+            } catch (InvocationTargetException e) {
+                throw new NoSuchAlgorithmException
+                    ("Error constructing implementation (algorithm: "
+                    + algorithm + ", provider: " + provider.getName()
+                    + ", class: " + className + ")", e.getCause());
+            } catch (Exception e) {
+                throw new NoSuchAlgorithmException
+                    ("Error constructing implementation (algorithm: "
+                    + algorithm + ", provider: " + provider.getName()
+                    + ", class: " + className + ")", e);
+            }
+        }
+
+        // return the implementation Class object for this service
+        private Class<?> getImplClass() throws NoSuchAlgorithmException {
+            try {
+                Reference<Class<?>> ref = classRef;
+                Class<?> clazz = (ref == null) ? null : ref.get();
+                if (clazz == null) {
+                    ClassLoader cl = provider.getClass().getClassLoader();
+                    if (cl == null) {
+                        clazz = Class.forName(className);
+                    } else {
+                        clazz = cl.loadClass(className);
+                    }
+                    if (!Modifier.isPublic(clazz.getModifiers())) {
+                        throw new NoSuchAlgorithmException
+                            ("class configured for " + type + " (provider: " +
+                            provider.getName() + ") is not public.");
+                    }
+                    classRef = new WeakReference<Class<?>>(clazz);
+                }
+                return clazz;
+            } catch (ClassNotFoundException e) {
+                throw new NoSuchAlgorithmException
+                    ("class configured for " + type + " (provider: " +
+                    provider.getName() + ") cannot be found.", e);
+            }
+        }
+
+        /**
+         * Generic code path for unknown engine types. Call the
+         * no-args constructor if constructorParameter is null, otherwise
+         * use the first matching constructor.
+         */
+        private Object newInstanceGeneric(Object constructorParameter)
+                throws Exception {
+            Class<?> clazz = getImplClass();
+            if (constructorParameter == null) {
+                // create instance with public no-arg constructor if it exists
+                try {
+                    Class<?>[] empty = {};
+                    Constructor<?> con = clazz.getConstructor(empty);
+                    return con.newInstance();
+                } catch (NoSuchMethodException e) {
+                    throw new NoSuchAlgorithmException("No public no-arg "
+                        + "constructor found in class " + className);
+                }
+            }
+            Class<?> argClass = constructorParameter.getClass();
+            Constructor[] cons = clazz.getConstructors();
+            // find first public constructor that can take the
+            // argument as parameter
+            for (Constructor<?> con : cons) {
+                Class<?>[] paramTypes = con.getParameterTypes();
+                if (paramTypes.length != 1) {
+                    continue;
+                }
+                if (paramTypes[0].isAssignableFrom(argClass) == false) {
+                    continue;
+                }
+                return con.newInstance(constructorParameter);
+            }
+            throw new NoSuchAlgorithmException("No public constructor matching "
+                + argClass.getName() + " found in class " + className);
+        }
+
+        /**
+         * Test whether this Service can use the specified parameter.
+         * Returns false if this service cannot use the parameter. Returns
+         * true if this service can use the parameter, if a fast test is
+         * infeasible, or if the status is unknown.
+         *
+         * <p>The security provider framework uses this method with
+         * some types of services to quickly exclude non-matching
+         * implementations for consideration.
+         * Applications will typically not need to call it.
+         *
+         * <p>For details and the values of parameter that are valid for the
+         * various types of services see the top of this class and the
+         * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+         * Java Cryptography Architecture API Specification &amp;
+         * Reference</a>.
+         * Security providers can override it to implement their own test.
+         *
+         * @param parameter the parameter to test
+         *
+         * @return false if this this service cannot use the specified
+         * parameter; true if it can possibly use the parameter
+         *
+         * @throws InvalidParameterException if the value of parameter is
+         * invalid for this type of service or if this method cannot be
+         * used with this type of service
+         */
+        public boolean supportsParameter(Object parameter) {
+            EngineDescription cap = knownEngines.get(type);
+            if (cap == null) {
+                // unknown engine type, return true by default
+                return true;
+            }
+            if (cap.supportsParameter == false) {
+                throw new InvalidParameterException("supportsParameter() not "
+                    + "used with " + type + " engines");
+            }
+            // allow null for keys without attributes for compatibility
+            if ((parameter != null) && (parameter instanceof Key == false)) {
+                throw new InvalidParameterException
+                    ("Parameter must be instanceof Key for engine " + type);
+            }
+            if (hasKeyAttributes() == false) {
+                return true;
+            }
+            if (parameter == null) {
+                return false;
+            }
+            Key key = (Key)parameter;
+            if (supportsKeyFormat(key)) {
+                return true;
+            }
+            if (supportsKeyClass(key)) {
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Return whether this service has its Supported* properties for
+         * keys defined. Parses the attributes if not yet initialized.
+         */
+        private boolean hasKeyAttributes() {
+            Boolean b = hasKeyAttributes;
+            if (b == null) {
+                synchronized (this) {
+                    String s;
+                    s = getAttribute("SupportedKeyFormats");
+                    if (s != null) {
+                        supportedFormats = s.split("\\|");
+                    }
+                    s = getAttribute("SupportedKeyClasses");
+                    if (s != null) {
+                        String[] classNames = s.split("\\|");
+                        List<Class<?>> classList =
+                            new ArrayList<>(classNames.length);
+                        for (String className : classNames) {
+                            Class<?> clazz = getKeyClass(className);
+                            if (clazz != null) {
+                                classList.add(clazz);
+                            }
+                        }
+                        supportedClasses = classList.toArray(CLASS0);
+                    }
+                    boolean bool = (supportedFormats != null)
+                        || (supportedClasses != null);
+                    b = Boolean.valueOf(bool);
+                    hasKeyAttributes = b;
+                }
+            }
+            return b.booleanValue();
+        }
+
+        // get the key class object of the specified name
+        private Class<?> getKeyClass(String name) {
+            try {
+                return Class.forName(name);
+            } catch (ClassNotFoundException e) {
+                // ignore
+            }
+            try {
+                ClassLoader cl = provider.getClass().getClassLoader();
+                if (cl != null) {
+                    return cl.loadClass(name);
+                }
+            } catch (ClassNotFoundException e) {
+                // ignore
+            }
+            return null;
+        }
+
+        private boolean supportsKeyFormat(Key key) {
+            if (supportedFormats == null) {
+                return false;
+            }
+            String format = key.getFormat();
+            if (format == null) {
+                return false;
+            }
+            for (String supportedFormat : supportedFormats) {
+                if (supportedFormat.equals(format)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean supportsKeyClass(Key key) {
+            if (supportedClasses == null) {
+                return false;
+            }
+            Class<?> keyClass = key.getClass();
+            for (Class<?> clazz : supportedClasses) {
+                if (clazz.isAssignableFrom(keyClass)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Return a String representation of this service.
+         *
+         * @return a String representation of this service.
+         */
+        public String toString() {
+            String aString = aliases.isEmpty()
+                ? "" : "\r\n  aliases: " + aliases.toString();
+            String attrs = attributes.isEmpty()
+                ? "" : "\r\n  attributes: " + attributes.toString();
+            return provider.getName() + ": " + type + "." + algorithm
+                + " -> " + className + aString + attrs + "\r\n";
+        }
+
+    }
+
+    // BEGIN Android-added: Provider registration
+    /**
+     * @hide
+     */
+    public void setRegistered() {
+        registered = true;
+    }
+
+    /**
+     * @hide
+     */
+    public void setUnregistered() {
+        registered = false;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isRegistered() {
+        return registered;
+    }
+
+    /**
+     * Ensure the values cached by {@link #getServices} and {@link #getService} are already computed
+     *
+     * Used by the zygote so that initialization is performed during preload for the providers
+     * available at that point.
+     *
+     * @hide
+     */
+    public synchronized void warmUpServiceProvision() {
+        checkInitialized();
+        // Further calls do nothing if the services didn't change. If not called here, it would
+        // parse legacy strings the first time that a service is requested.
+        ensureLegacyParsed();
+        // This call to getServices will update fields so that further calls will just return a
+        // stored field, if the services didn't change in the meantime.
+        getServices();
+    }
+    // END Android-added: Provider registration
+}
diff --git a/java/security/ProviderException.java b/java/security/ProviderException.java
new file mode 100644
index 0000000..b372ee7
--- /dev/null
+++ b/java/security/ProviderException.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * A runtime exception for Provider exceptions (such as
+ * misconfiguration errors or unrecoverable internal errors),
+ * which may be subclassed by Providers to
+ * throw specialized, provider-specific runtime errors.
+ *
+ * @author Benjamin Renaud
+ */
+public class ProviderException extends RuntimeException {
+
+    private static final long serialVersionUID = 5256023526693665674L;
+
+    /**
+     * Constructs a ProviderException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public ProviderException() {
+        super();
+    }
+
+    /**
+     * Constructs a ProviderException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param s the detail message.
+     */
+    public ProviderException(String s) {
+        super(s);
+    }
+
+    /**
+     * Creates a {@code ProviderException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public ProviderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code ProviderException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public ProviderException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/PublicKey.java b/java/security/PublicKey.java
new file mode 100644
index 0000000..df49807
--- /dev/null
+++ b/java/security/PublicKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * <p>A public key. This interface contains no methods or constants.
+ * It merely serves to group (and provide type safety for) all public key
+ * interfaces.
+ *
+ * Note: The specialized public key interfaces extend this interface.
+ * See, for example, the DSAPublicKey interface in
+ * {@code java.security.interfaces}.
+ *
+ * @see Key
+ * @see PrivateKey
+ * @see Certificate
+ * @see Signature#initVerify
+ * @see java.security.interfaces.DSAPublicKey
+ * @see java.security.interfaces.RSAPublicKey
+ *
+ */
+
+public interface PublicKey extends Key {
+    // Declare serialVersionUID to be compatible with JDK1.1
+    /**
+     * The class fingerprint that is set to indicate serialization
+     * compatibility with a previous version of the class.
+     */
+    static final long serialVersionUID = 7187392471159151072L;
+}
diff --git a/java/security/SecureClassLoader.java b/java/security/SecureClassLoader.java
new file mode 100644
index 0000000..145f4fc
--- /dev/null
+++ b/java/security/SecureClassLoader.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.net.URL;
+
+import sun.security.util.Debug;
+
+/**
+ * This class extends ClassLoader with additional support for defining
+ * classes with an associated code source and permissions which are
+ * retrieved by the system policy by default.
+ *
+ * @author  Li Gong
+ * @author  Roland Schemers
+ */
+public class SecureClassLoader extends ClassLoader {
+    /*
+     * If initialization succeed this is set to true and security checks will
+     * succeed. Otherwise the object is not initialized and the object is
+     * useless.
+     */
+    private final boolean initialized;
+
+    // HashMap that maps CodeSource to ProtectionDomain
+    // @GuardedBy("pdcache")
+    private final HashMap<CodeSource, ProtectionDomain> pdcache =
+                        new HashMap<>(11);
+
+    private static final Debug debug = Debug.getInstance("scl");
+
+    static {
+        ClassLoader.registerAsParallelCapable();
+    }
+
+    /**
+     * Creates a new SecureClassLoader using the specified parent
+     * class loader for delegation.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader}
+     * method  to ensure creation of a class loader is allowed.
+     * <p>
+     * @param parent the parent ClassLoader
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    protected SecureClassLoader(ClassLoader parent) {
+        super(parent);
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        initialized = true;
+    }
+
+    /**
+     * Creates a new SecureClassLoader using the default parent class
+     * loader for delegation.
+     *
+     * <p>If there is a security manager, this method first
+     * calls the security manager's {@code checkCreateClassLoader}
+     * method  to ensure creation of a class loader is allowed.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     *             {@code checkCreateClassLoader} method doesn't allow
+     *             creation of a class loader.
+     * @see SecurityManager#checkCreateClassLoader
+     */
+    protected SecureClassLoader() {
+        super();
+        // this is to make the stack depth consistent with 1.1
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkCreateClassLoader();
+        }
+        initialized = true;
+    }
+
+    /**
+     * Converts an array of bytes into an instance of class Class,
+     * with an optional CodeSource. Before the
+     * class can be used it must be resolved.
+     * <p>
+     * If a non-null CodeSource is supplied a ProtectionDomain is
+     * constructed and associated with the class being defined.
+     * <p>
+     * @param      name the expected name of the class, or {@code null}
+     *                  if not known, using '.' and not '/' as the separator
+     *                  and without a trailing ".class" suffix.
+     * @param      b    the bytes that make up the class data. The bytes in
+     *             positions {@code off} through {@code off+len-1}
+     *             should have the format of a valid class file as defined by
+     *             <cite>The Java&trade; Virtual Machine Specification</cite>.
+     * @param      off  the start offset in {@code b} of the class data
+     * @param      len  the length of the class data
+     * @param      cs   the associated CodeSource, or {@code null} if none
+     * @return the {@code Class} object created from the data,
+     *         and optional CodeSource.
+     * @exception  ClassFormatError if the data did not contain a valid class
+     * @exception  IndexOutOfBoundsException if either {@code off} or
+     *             {@code len} is negative, or if
+     *             {@code off+len} is greater than {@code b.length}.
+     *
+     * @exception  SecurityException if an attempt is made to add this class
+     *             to a package that contains classes that were signed by
+     *             a different set of certificates than this class, or if
+     *             the class name begins with "java.".
+     */
+    protected final Class<?> defineClass(String name,
+                                         byte[] b, int off, int len,
+                                         CodeSource cs)
+    {
+        return defineClass(name, b, off, len, getProtectionDomain(cs));
+    }
+
+    /**
+     * Converts a {@link java.nio.ByteBuffer ByteBuffer}
+     * into an instance of class {@code Class}, with an optional CodeSource.
+     * Before the class can be used it must be resolved.
+     * <p>
+     * If a non-null CodeSource is supplied a ProtectionDomain is
+     * constructed and associated with the class being defined.
+     * <p>
+     * @param      name the expected name of the class, or {@code null}
+     *                  if not known, using '.' and not '/' as the separator
+     *                  and without a trailing ".class" suffix.
+     * @param      b    the bytes that make up the class data.  The bytes from positions
+     *                  {@code b.position()} through {@code b.position() + b.limit() -1}
+     *                  should have the format of a valid class file as defined by
+     *                  <cite>The Java&trade; Virtual Machine Specification</cite>.
+     * @param      cs   the associated CodeSource, or {@code null} if none
+     * @return the {@code Class} object created from the data,
+     *         and optional CodeSource.
+     * @exception  ClassFormatError if the data did not contain a valid class
+     * @exception  SecurityException if an attempt is made to add this class
+     *             to a package that contains classes that were signed by
+     *             a different set of certificates than this class, or if
+     *             the class name begins with "java.".
+     *
+     * @since  1.5
+     */
+    protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
+                                         CodeSource cs)
+    {
+        return defineClass(name, b, getProtectionDomain(cs));
+    }
+
+    /**
+     * Returns the permissions for the given CodeSource object.
+     * <p>
+     * This method is invoked by the defineClass method which takes
+     * a CodeSource as an argument when it is constructing the
+     * ProtectionDomain for the class being defined.
+     * <p>
+     * @param codesource the codesource.
+     *
+     * @return the permissions granted to the codesource.
+     *
+     */
+    protected PermissionCollection getPermissions(CodeSource codesource)
+    {
+        check();
+        return new Permissions(); // ProtectionDomain defers the binding
+    }
+
+    /*
+     * Returned cached ProtectionDomain for the specified CodeSource.
+     */
+    private ProtectionDomain getProtectionDomain(CodeSource cs) {
+        if (cs == null)
+            return null;
+
+        ProtectionDomain pd = null;
+        synchronized (pdcache) {
+            pd = pdcache.get(cs);
+            if (pd == null) {
+                PermissionCollection perms = getPermissions(cs);
+                pd = new ProtectionDomain(cs, perms, this, null);
+                pdcache.put(cs, pd);
+                if (debug != null) {
+                    debug.println(" getPermissions "+ pd);
+                    debug.println("");
+                }
+            }
+        }
+        return pd;
+    }
+
+    /*
+     * Check to make sure the class loader has been initialized.
+     */
+    private void check() {
+        if (!initialized) {
+            throw new SecurityException("ClassLoader object not initialized");
+        }
+    }
+
+}
diff --git a/java/security/SecureRandom.java b/java/security/SecureRandom.java
new file mode 100644
index 0000000..79e3840
--- /dev/null
+++ b/java/security/SecureRandom.java
@@ -0,0 +1,699 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+import java.util.regex.*;
+
+import java.security.Provider.Service;
+import java.util.function.Function;
+
+import dalvik.system.VMRuntime;
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class provides a cryptographically strong random number
+ * generator (RNG).
+ *
+ * <p>A cryptographically strong random number
+ * minimally complies with the statistical random number generator tests
+ * specified in <a href="http://csrc.nist.gov/cryptval/140-2.htm">
+ * <i>FIPS 140-2, Security Requirements for Cryptographic Modules</i></a>,
+ * section 4.9.1.
+ * Additionally, SecureRandom must produce non-deterministic output.
+ * Therefore any seed material passed to a SecureRandom object must be
+ * unpredictable, and all SecureRandom output sequences must be
+ * cryptographically strong, as described in
+ * <a href="http://www.ietf.org/rfc/rfc1750.txt">
+ * <i>RFC 1750: Randomness Recommendations for Security</i></a>.
+ *
+ * <p>A caller obtains a SecureRandom instance via the
+ * no-argument constructor or one of the {@code getInstance} methods:
+ *
+ * <pre>
+ *      SecureRandom random = new SecureRandom();
+ * </pre>
+ *
+ * <p> Many SecureRandom implementations are in the form of a pseudo-random
+ * number generator (PRNG), which means they use a deterministic algorithm
+ * to produce a pseudo-random sequence from a true random seed.
+ * Other implementations may produce true random numbers,
+ * and yet others may use a combination of both techniques.
+ *
+ * <p> Typical callers of SecureRandom invoke the following methods
+ * to retrieve random bytes:
+ *
+ * <pre>
+ *      SecureRandom random = new SecureRandom();
+ *      byte bytes[] = new byte[20];
+ *      random.nextBytes(bytes);
+ * </pre>
+ *
+ * <p> Callers may also invoke the {@code generateSeed} method
+ * to generate a given number of seed bytes (to seed other random number
+ * generators, for example):
+ * <pre>
+ *      byte seed[] = random.generateSeed(20);
+ * </pre>
+ *
+ * Note: Depending on the implementation, the {@code generateSeed} and
+ * {@code nextBytes} methods may block as entropy is being gathered,
+ * for example, if they need to read from /dev/random on various Unix-like
+ * operating systems.
+ *
+ * The SHA1PRNG algorithm from the Crypto provider has been deprecated as it was insecure, and also
+ * incorrectly used by some apps as a key derivation function. See
+ * <a href="http://android-developers.blogspot.com/2016/06/security-crypto-provider-deprecated-in.html">
+ * Security &quot;Crypto&quot; provider deprecated in Android N</a> for details.
+ *
+ * @see java.security.SecureRandomSpi
+ * @see java.util.Random
+ *
+ * @author Benjamin Renaud
+ * @author Josh Bloch
+ */
+
+public class SecureRandom extends java.util.Random {
+
+    // Android-removed: this debugging mechanism is not used in Android.
+    /*
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("securerandom");
+    */
+    // END Android-removed
+
+    /**
+     * The provider.
+     *
+     * @serial
+     * @since 1.2
+     */
+    private Provider provider = null;
+
+    /**
+     * The provider implementation.
+     *
+     * @serial
+     * @since 1.2
+     */
+    private SecureRandomSpi secureRandomSpi = null;
+
+    /*
+     * The algorithm name of null if unknown.
+     *
+     * @serial
+     * @since 1.5
+     */
+    private String algorithm;
+
+    // Seed Generator
+    private static volatile SecureRandom seedGenerator = null;
+
+    /**
+     * Constructs a secure random number generator (RNG) implementing the
+     * default random number algorithm.
+     *
+     * <p> This constructor traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new SecureRandom object encapsulating the
+     * SecureRandomSpi implementation from the first
+     * Provider that supports a SecureRandom (RNG) algorithm is returned.
+     * If none of the Providers support a RNG algorithm,
+     * then an implementation-specific default is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p> See the SecureRandom section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard RNG algorithm names.
+     *
+     * <p> The returned SecureRandom object has not been seeded.  To seed the
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
+     * previously called.
+     */
+    public SecureRandom() {
+        /*
+         * This call to our superclass constructor will result in a call
+         * to our own {@code setSeed} method, which will return
+         * immediately when it is passed zero.
+         */
+        super(0);
+        getDefaultPRNG(false, null);
+    }
+
+    /**
+     * Constructs a secure random number generator (RNG) implementing the
+     * default random number algorithm.
+     * The SecureRandom instance is seeded with the specified seed bytes.
+     *
+     * <p> This constructor traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new SecureRandom object encapsulating the
+     * SecureRandomSpi implementation from the first
+     * Provider that supports a SecureRandom (RNG) algorithm is returned.
+     * If none of the Providers support a RNG algorithm,
+     * then an implementation-specific default is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p> See the SecureRandom section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard RNG algorithm names.
+     *
+     * @param seed the seed.
+     */
+    public SecureRandom(byte seed[]) {
+        super(0);
+        getDefaultPRNG(true, seed);
+    }
+
+    private void getDefaultPRNG(boolean setSeed, byte[] seed) {
+        String prng = getPrngAlgorithm();
+        if (prng == null) {
+            // Android-changed: This should never happen, we always provide a SecureRandom
+            throw new IllegalStateException("No SecureRandom implementation!");
+        } else {
+            try {
+                SecureRandom random = SecureRandom.getInstance(prng);
+                this.secureRandomSpi = random.getSecureRandomSpi();
+                this.provider = random.getProvider();
+                if (setSeed) {
+                    this.secureRandomSpi.engineSetSeed(seed);
+                }
+            } catch (NoSuchAlgorithmException nsae) {
+                // never happens, because we made sure the algorithm exists
+                throw new RuntimeException(nsae);
+            }
+        }
+        // JDK 1.1 based implementations subclass SecureRandom instead of
+        // SecureRandomSpi. They will also go through this code path because
+        // they must call a SecureRandom constructor as it is their superclass.
+        // If we are dealing with such an implementation, do not set the
+        // algorithm value as it would be inaccurate.
+        if (getClass() == SecureRandom.class) {
+            this.algorithm = prng;
+        }
+    }
+
+    /**
+     * Creates a SecureRandom object.
+     *
+     * @param secureRandomSpi the SecureRandom implementation.
+     * @param provider the provider.
+     */
+    protected SecureRandom(SecureRandomSpi secureRandomSpi,
+                           Provider provider) {
+        this(secureRandomSpi, provider, null);
+    }
+
+    private SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider,
+            String algorithm) {
+        super(0);
+        this.secureRandomSpi = secureRandomSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+
+        // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("SecureRandom." + algorithm +
+                " algorithm from: " + this.provider.getName());
+        }
+        */
+        // END Android-removed: this debugging mechanism is not supported in Android.
+    }
+
+    /**
+     * Returns a SecureRandom object that implements the specified
+     * Random Number Generator (RNG) algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new SecureRandom object encapsulating the
+     * SecureRandomSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p> The returned SecureRandom object has not been seeded.  To seed the
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
+     * previously called.
+     *
+     * @param algorithm the name of the RNG algorithm.
+     * See the SecureRandom section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard RNG algorithm names.
+     *
+     * @return the new SecureRandom object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          SecureRandomSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     *
+     * @since 1.2
+     */
+    public static SecureRandom getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        Instance instance = GetInstance.getInstance("SecureRandom",
+            SecureRandomSpi.class, algorithm);
+        return new SecureRandom((SecureRandomSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a SecureRandom object that implements the specified
+     * Random Number Generator (RNG) algorithm.
+     *
+     * <p> A new SecureRandom object encapsulating the
+     * SecureRandomSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p> The returned SecureRandom object has not been seeded.  To seed the
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
+     * previously called.
+     *
+     * @param algorithm the name of the RNG algorithm.
+     * See the SecureRandom section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard RNG algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new SecureRandom object.
+     *
+     * @exception NoSuchAlgorithmException if a SecureRandomSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     *
+     * @since 1.2
+     */
+    public static SecureRandom getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        Instance instance = GetInstance.getInstance("SecureRandom",
+            SecureRandomSpi.class, algorithm, provider);
+        return new SecureRandom((SecureRandomSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a SecureRandom object that implements the specified
+     * Random Number Generator (RNG) algorithm.
+     *
+     * <p> A new SecureRandom object encapsulating the
+     * SecureRandomSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * <p> The returned SecureRandom object has not been seeded.  To seed the
+     * returned object, call the {@code setSeed} method.
+     * If {@code setSeed} is not called, the first call to
+     * {@code nextBytes} will force the SecureRandom object to seed itself.
+     * This self-seeding will not occur if {@code setSeed} was
+     * previously called.
+     *
+     * @param algorithm the name of the RNG algorithm.
+     * See the SecureRandom section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard RNG algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new SecureRandom object.
+     *
+     * @exception NoSuchAlgorithmException if a SecureRandomSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the specified provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static SecureRandom getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = GetInstance.getInstance("SecureRandom",
+            SecureRandomSpi.class, algorithm, provider);
+        return new SecureRandom((SecureRandomSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the SecureRandomSpi of this SecureRandom object.
+     */
+    SecureRandomSpi getSecureRandomSpi() {
+        return secureRandomSpi;
+    }
+
+    /**
+     * Returns the provider of this SecureRandom object.
+     *
+     * @return the provider of this SecureRandom object.
+     */
+    public final Provider getProvider() {
+        return provider;
+    }
+
+    /**
+     * Returns the name of the algorithm implemented by this SecureRandom
+     * object.
+     *
+     * @return the name of the algorithm or {@code unknown}
+     *          if the algorithm name cannot be determined.
+     * @since 1.5
+     */
+    public String getAlgorithm() {
+        return (algorithm != null) ? algorithm : "unknown";
+    }
+
+    /**
+     * Reseeds this random object. The given seed supplements, rather than
+     * replaces, the existing seed. Thus, repeated calls are guaranteed
+     * never to reduce randomness.
+     *
+     * @param seed the seed.
+     *
+     * @see #getSeed
+     */
+    synchronized public void setSeed(byte[] seed) {
+        secureRandomSpi.engineSetSeed(seed);
+    }
+
+    /**
+     * Reseeds this random object, using the eight bytes contained
+     * in the given {@code long seed}. The given seed supplements,
+     * rather than replaces, the existing seed. Thus, repeated calls
+     * are guaranteed never to reduce randomness.
+     *
+     * <p>This method is defined for compatibility with
+     * {@code java.util.Random}.
+     *
+     * @param seed the seed.
+     *
+     * @see #getSeed
+     */
+    @Override
+    public void setSeed(long seed) {
+        /*
+         * Ignore call from super constructor (as well as any other calls
+         * unfortunate enough to be passing 0).  It's critical that we
+         * ignore call from superclass constructor, as digest has not
+         * yet been initialized at that point.
+         */
+        if (seed != 0) {
+            secureRandomSpi.engineSetSeed(longToByteArray(seed));
+        }
+    }
+
+    /**
+     * Generates a user-specified number of random bytes.
+     *
+     * <p> If a call to {@code setSeed} had not occurred previously,
+     * the first call to this method forces this SecureRandom object
+     * to seed itself.  This self-seeding will not occur if
+     * {@code setSeed} was previously called.
+     *
+     * @param bytes the array to be filled in with random bytes.
+     */
+    @Override
+    // Android-changed: Added synchronized
+    // This method has been synchronized at least since Cupcake, so it would probably
+    // lead to problems if it was removed.
+    synchronized public void nextBytes(byte[] bytes) {
+        secureRandomSpi.engineNextBytes(bytes);
+    }
+
+    /**
+     * Generates an integer containing the user-specified number of
+     * pseudo-random bits (right justified, with leading zeros).  This
+     * method overrides a {@code java.util.Random} method, and serves
+     * to provide a source of random bits to all of the methods inherited
+     * from that class (for example, {@code nextInt},
+     * {@code nextLong}, and {@code nextFloat}).
+     *
+     * @param numBits number of pseudo-random bits to be generated, where
+     * {@code 0 <= numBits <= 32}.
+     *
+     * @return an {@code int} containing the user-specified number
+     * of pseudo-random bits (right justified, with leading zeros).
+     */
+    @Override
+    final protected int next(int numBits) {
+        int numBytes = (numBits+7)/8;
+        byte b[] = new byte[numBytes];
+        int next = 0;
+
+        nextBytes(b);
+        for (int i = 0; i < numBytes; i++) {
+            next = (next << 8) + (b[i] & 0xFF);
+        }
+
+        return next >>> (numBytes*8 - numBits);
+    }
+
+    /**
+     * Returns the given number of seed bytes, computed using the seed
+     * generation algorithm that this class uses to seed itself.  This
+     * call may be used to seed other random number generators.
+     *
+     * <p>This method is only included for backwards compatibility.
+     * The caller is encouraged to use one of the alternative
+     * {@code getInstance} methods to obtain a SecureRandom object, and
+     * then call the {@code generateSeed} method to obtain seed bytes
+     * from that object.
+     *
+     * @param numBytes the number of seed bytes to generate.
+     *
+     * @return the seed bytes.
+     *
+     * @see #setSeed
+     */
+    public static byte[] getSeed(int numBytes) {
+        if (seedGenerator == null) {
+            seedGenerator = new SecureRandom();
+        }
+        return seedGenerator.generateSeed(numBytes);
+    }
+
+    /**
+     * Returns the given number of seed bytes, computed using the seed
+     * generation algorithm that this class uses to seed itself.  This
+     * call may be used to seed other random number generators.
+     *
+     * @param numBytes the number of seed bytes to generate.
+     *
+     * @return the seed bytes.
+     */
+    public byte[] generateSeed(int numBytes) {
+        return secureRandomSpi.engineGenerateSeed(numBytes);
+    }
+
+    /**
+     * Helper function to convert a long into a byte array (least significant
+     * byte first).
+     */
+    private static byte[] longToByteArray(long l) {
+        byte[] retVal = new byte[8];
+
+        for (int i = 0; i < 8; i++) {
+            retVal[i] = (byte) l;
+            l >>= 8;
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Gets a default PRNG algorithm by looking through all registered
+     * providers. Returns the first PRNG algorithm of the first provider that
+     * has registered a SecureRandom implementation, or null if none of the
+     * registered providers supplies a SecureRandom implementation.
+     */
+    private static String getPrngAlgorithm() {
+        for (Provider p : Providers.getProviderList().providers()) {
+            for (Service s : p.getServices()) {
+                if (s.getType().equals("SecureRandom")) {
+                    return s.getAlgorithm();
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Lazily initialize since Pattern.compile() is heavy.
+     * Effective Java (2nd Edition), Item 71.
+     */
+    private static final class StrongPatternHolder {
+        /*
+         * Entries are alg:prov separated by ,
+         * Allow for prepended/appended whitespace between entries.
+         *
+         * Capture groups:
+         *     1 - alg
+         *     2 - :prov (optional)
+         *     3 - prov (optional)
+         *     4 - ,nextEntry (optional)
+         *     5 - nextEntry (optional)
+         */
+        private static Pattern pattern =
+            Pattern.compile(
+                "\\s*([\\S&&[^:,]]*)(\\:([\\S&&[^,]]*))?\\s*(\\,(.*))?");
+    }
+
+    /**
+     * Returns a {@code SecureRandom} object.
+     *
+     * In Android this is equivalent to get a SHA1PRNG from AndroidOpenSSL.
+     *
+     * Some situations require strong random values, such as when
+     * creating high-value/long-lived secrets like RSA public/private
+     * keys.  To help guide applications in selecting a suitable strong
+     * {@code SecureRandom} implementation, Java distributions
+     * include a list of known strong {@code SecureRandom}
+     * implementations in the {@code securerandom.strongAlgorithms}
+     * Security property.
+     * <p>
+     * Every implementation of the Java platform is required to
+     * support at least one strong {@code SecureRandom} implementation.
+     *
+     * @return a strong {@code SecureRandom} implementation
+     *
+     * @throws NoSuchAlgorithmException if no algorithm is available
+     *
+     * @see Security#getProperty(String)
+     *
+     * @since 1.8
+     */
+    public static SecureRandom getInstanceStrong()
+            throws NoSuchAlgorithmException {
+
+        String property = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return Security.getProperty(
+                        "securerandom.strongAlgorithms");
+                }
+            });
+
+        if ((property == null) || (property.length() == 0)) {
+            throw new NoSuchAlgorithmException(
+                "Null/empty securerandom.strongAlgorithms Security Property");
+        }
+
+        String remainder = property;
+        while (remainder != null) {
+            Matcher m;
+            if ((m = StrongPatternHolder.pattern.matcher(
+                    remainder)).matches()) {
+
+                String alg = m.group(1);
+                String prov = m.group(3);
+
+                try {
+                    if (prov == null) {
+                        return SecureRandom.getInstance(alg);
+                    } else {
+                        return SecureRandom.getInstance(alg, prov);
+                    }
+                } catch (NoSuchAlgorithmException |
+                        NoSuchProviderException e) {
+                }
+                remainder = m.group(5);
+            } else {
+                remainder = null;
+            }
+        }
+
+        throw new NoSuchAlgorithmException(
+            "No strong SecureRandom impls available: " + property);
+    }
+
+    // Declare serialVersionUID to be compatible with JDK1.1
+    static final long serialVersionUID = 4940670005562187L;
+
+    // Retain unused values serialized from JDK1.1
+    /**
+     * @serial
+     */
+    private byte[] state;
+    /**
+     * @serial
+     */
+    private MessageDigest digest = null;
+    /**
+     * @serial
+     *
+     * We know that the MessageDigest class does not implement
+     * java.io.Serializable.  However, since this field is no longer
+     * used, it will always be NULL and won't affect the serialization
+     * of the SecureRandom class itself.
+     */
+    private byte[] randomBytes;
+    /**
+     * @serial
+     */
+    private int randomBytesUsed;
+    /**
+     * @serial
+     */
+    private long counter;
+}
diff --git a/java/security/SecureRandomSpi.java b/java/security/SecureRandomSpi.java
new file mode 100644
index 0000000..ef6c243
--- /dev/null
+++ b/java/security/SecureRandomSpi.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code SecureRandom} class.
+ * All the abstract methods in this class must be implemented by each
+ * service provider who wishes to supply the implementation
+ * of a cryptographically strong pseudo-random number generator.
+ *
+ *
+ * @see SecureRandom
+ * @since 1.2
+ */
+
+public abstract class SecureRandomSpi implements java.io.Serializable {
+
+    private static final long serialVersionUID = -2991854161009191830L;
+
+    /**
+     * Reseeds this random object. The given seed supplements, rather than
+     * replaces, the existing seed. Thus, repeated calls are guaranteed
+     * never to reduce randomness.
+     *
+     * @param seed the seed.
+     */
+    protected abstract void engineSetSeed(byte[] seed);
+
+    /**
+     * Generates a user-specified number of random bytes.
+     *
+     * <p> If a call to {@code engineSetSeed} had not occurred previously,
+     * the first call to this method forces this SecureRandom implementation
+     * to seed itself.  This self-seeding will not occur if
+     * {@code engineSetSeed} was previously called.
+     *
+     * @param bytes the array to be filled in with random bytes.
+     */
+    protected abstract void engineNextBytes(byte[] bytes);
+
+    /**
+     * Returns the given number of seed bytes.  This call may be used to
+     * seed other random number generators.
+     *
+     * @param numBytes the number of seed bytes to generate.
+     *
+     * @return the seed bytes.
+     */
+     protected abstract byte[] engineGenerateSeed(int numBytes);
+}
diff --git a/java/security/Security.java b/java/security/Security.java
new file mode 100644
index 0000000..bb853a6
--- /dev/null
+++ b/java/security/Security.java
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.io.*;
+import sun.security.jca.GetInstance;
+import sun.security.jca.ProviderList;
+import sun.security.jca.Providers;
+
+/**
+ * <p>This class centralizes all security properties and common security
+ * methods. One of its primary uses is to manage providers.
+ *
+ * <p>The default values of security properties are read from an
+ * implementation-specific location, which is typically the properties file
+ * {@code lib/security/java.security} in the Java installation directory.
+ *
+ * @author Benjamin Renaud
+ */
+
+public final class Security {
+
+    // Android-added: Track the version to allow callers know when something has changed.
+    private static final AtomicInteger version = new AtomicInteger();
+
+    // Android-removed: Debug is stubbed and disabled on Android.
+    // /* Are we debugging? -- for developers */
+    // private static final Debug sdebug =
+    //                     Debug.getInstance("properties");
+
+    /* The java.security properties */
+    // Android-changed: Added final.
+    private static final Properties props;
+
+    // An element in the cache
+    private static class ProviderProperty {
+        String className;
+        Provider provider;
+    }
+
+    static {
+// BEGIN Android-changed: doPrivileged is stubbed on Android.
+// Also, because props is final it must be assigned in the static block, not a method.
+        /*
+        // doPrivileged here because there are multiple
+        // things in initialize that might require privs.
+        // (the FileInputStream call and the File.exists call,
+        // the securityPropFile call, etc)
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                initialize();
+                return null;
+            }
+        });
+    }
+
+    private static void initialize() {
+        */
+// END Android-changed: doPrivileged is stubbed on Android.
+        props = new Properties();
+        boolean loadedProps = false;
+        // BEGIN Android-changed: Use a resource file, Android logging, and only one file.
+        InputStream is = null;
+        try {
+            /*
+             * Android keeps the property file in a resource file.
+             */
+            InputStream propStream = Security.class.getResourceAsStream("security.properties");
+            if (propStream == null) {
+                System.logE("Could not find 'security.properties'.");
+            } else {
+                is  = new BufferedInputStream(propStream);
+                props.load(is);
+                loadedProps = true;
+            }
+        } catch (IOException ex) {
+            System.logE("Could not load 'security.properties'", ex);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException ignored) {}
+            }
+        }
+        // END Android-changed: Use a resource file, Android logging, and only one file.
+
+        if (!loadedProps) {
+            initializeStatic();
+        }
+    }
+
+    /*
+     * Initialize to default values, if <java.home>/lib/java.security
+     * is not found.
+     */
+    private static void initializeStatic() {
+        // Android-changed: Use Conscrypt and BC, not the sun.security providers.
+        /*
+        props.put("security.provider.1", "sun.security.provider.Sun");
+        props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
+        props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
+        props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
+        props.put("security.provider.5", "sun.security.jgss.SunProvider");
+        props.put("security.provider.6", "com.sun.security.sasl.Provider");
+        */
+        props.put("security.provider.1", "com.android.org.conscrypt.OpenSSLProvider");
+        props.put("security.provider.2", "sun.security.provider.CertPathProvider");
+        props.put("security.provider.3", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider");
+        props.put("security.provider.4", "com.android.org.conscrypt.JSSEProvider");
+    }
+
+    /**
+     * Don't let anyone instantiate this.
+     */
+    private Security() {
+    }
+
+    /**
+     * Looks up providers, and returns the property (and its associated
+     * provider) mapping the key, if any.
+     * The order in which the providers are looked up is the
+     * provider-preference order, as specificed in the security
+     * properties file.
+     */
+    private static ProviderProperty getProviderProperty(String key) {
+        ProviderProperty entry = null;
+
+        List<Provider> providers = Providers.getProviderList().providers();
+        for (int i = 0; i < providers.size(); i++) {
+
+            String matchKey = null;
+            Provider prov = providers.get(i);
+            String prop = prov.getProperty(key);
+
+            if (prop == null) {
+                // Is there a match if we do a case-insensitive property name
+                // comparison? Let's try ...
+                for (Enumeration<Object> e = prov.keys();
+                                e.hasMoreElements() && prop == null; ) {
+                    matchKey = (String)e.nextElement();
+                    if (key.equalsIgnoreCase(matchKey)) {
+                        prop = prov.getProperty(matchKey);
+                        break;
+                    }
+                }
+            }
+
+            if (prop != null) {
+                ProviderProperty newEntry = new ProviderProperty();
+                newEntry.className = prop;
+                newEntry.provider = prov;
+                return newEntry;
+            }
+        }
+
+        return entry;
+    }
+
+    /**
+     * Returns the property (if any) mapping the key for the given provider.
+     */
+    private static String getProviderProperty(String key, Provider provider) {
+        String prop = provider.getProperty(key);
+        if (prop == null) {
+            // Is there a match if we do a case-insensitive property name
+            // comparison? Let's try ...
+            for (Enumeration<Object> e = provider.keys();
+                                e.hasMoreElements() && prop == null; ) {
+                String matchKey = (String)e.nextElement();
+                if (key.equalsIgnoreCase(matchKey)) {
+                    prop = provider.getProperty(matchKey);
+                    break;
+                }
+            }
+        }
+        return prop;
+    }
+
+    /**
+     * Gets a specified property for an algorithm. The algorithm name
+     * should be a standard name. See the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * One possible use is by specialized algorithm parsers, which may map
+     * classes to algorithms which they understand (much like Key parsers
+     * do).
+     *
+     * @param algName the algorithm name.
+     *
+     * @param propName the name of the property to get.
+     *
+     * @return the value of the specified property.
+     *
+     * @deprecated This method used to return the value of a proprietary
+     * property in the master file of the "SUN" Cryptographic Service
+     * Provider in order to determine how to parse algorithm-specific
+     * parameters. Use the new provider-based and algorithm-independent
+     * {@code AlgorithmParameters} and {@code KeyFactory} engine
+     * classes (introduced in the J2SE version 1.2 platform) instead.
+     */
+    @Deprecated
+    public static String getAlgorithmProperty(String algName,
+                                              String propName) {
+        ProviderProperty entry = getProviderProperty("Alg." + propName
+                                                     + "." + algName);
+        if (entry != null) {
+            return entry.className;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Adds a new provider, at a specified position. The position is
+     * the preference order in which providers are searched for
+     * requested algorithms.  The position is 1-based, that is,
+     * 1 is most preferred, followed by 2, and so on.
+     *
+     * <p>If the given provider is installed at the requested position,
+     * the provider that used to be at that position, and all providers
+     * with a position greater than {@code position}, are shifted up
+     * one position (towards the end of the list of installed providers).
+     *
+     * <p>A provider cannot be added if it is already installed.
+     *
+     * <p>If there is a security manager, the
+     * {@link java.lang.SecurityManager#checkSecurityAccess} method is called
+     * with the {@code "insertProvider"} permission target name to see if
+     * it's ok to add a new provider. If this permission check is denied,
+     * {@code checkSecurityAccess} is called again with the
+     * {@code "insertProvider."+provider.getName()} permission target name. If
+     * both checks are denied, a {@code SecurityException} is thrown.
+     *
+     * @param provider the provider to be added.
+     *
+     * @param position the preference position that the caller would
+     * like for this provider.
+     *
+     * @return the actual preference position in which the provider was
+     * added, or -1 if the provider was not added because it is
+     * already installed.
+     *
+     * @throws  NullPointerException if provider is null
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to add a new provider
+     *
+     * @see #getProvider
+     * @see #removeProvider
+     * @see java.security.SecurityPermission
+     */
+    public static synchronized int insertProviderAt(Provider provider,
+            int position) {
+        String providerName = provider.getName();
+        // Android-removed: Checks using SecurityManager, which is not functional in Android.
+        // checkInsertProvider(providerName);
+        ProviderList list = Providers.getFullProviderList();
+        ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
+        if (list == newList) {
+            return -1;
+        }
+        // Android-added: Version tracking call.
+        increaseVersion();
+        Providers.setProviderList(newList);
+        return newList.getIndex(providerName) + 1;
+    }
+
+    /**
+     * Adds a provider to the next position available.
+     *
+     * <p>If there is a security manager, the
+     * {@link java.lang.SecurityManager#checkSecurityAccess} method is called
+     * with the {@code "insertProvider"} permission target name to see if
+     * it's ok to add a new provider. If this permission check is denied,
+     * {@code checkSecurityAccess} is called again with the
+     * {@code "insertProvider."+provider.getName()} permission target name. If
+     * both checks are denied, a {@code SecurityException} is thrown.
+     *
+     * @param provider the provider to be added.
+     *
+     * @return the preference position in which the provider was
+     * added, or -1 if the provider was not added because it is
+     * already installed.
+     *
+     * @throws  NullPointerException if provider is null
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies access to add a new provider
+     *
+     * @see #getProvider
+     * @see #removeProvider
+     * @see java.security.SecurityPermission
+     */
+    public static int addProvider(Provider provider) {
+        /*
+         * We can't assign a position here because the statically
+         * registered providers may not have been installed yet.
+         * insertProviderAt() will fix that value after it has
+         * loaded the static providers.
+         */
+        return insertProviderAt(provider, 0);
+    }
+
+    /**
+     * Removes the provider with the specified name.
+     *
+     * <p>When the specified provider is removed, all providers located
+     * at a position greater than where the specified provider was are shifted
+     * down one position (towards the head of the list of installed
+     * providers).
+     *
+     * <p>This method returns silently if the provider is not installed or
+     * if name is null.
+     *
+     * <p>First, if there is a security manager, its
+     * {@code checkSecurityAccess}
+     * method is called with the string {@code "removeProvider."+name}
+     * to see if it's ok to remove the provider.
+     * If the default implementation of {@code checkSecurityAccess}
+     * is used (i.e., that method is not overriden), then this will result in
+     * a call to the security manager's {@code checkPermission} method
+     * with a {@code SecurityPermission("removeProvider."+name)}
+     * permission.
+     *
+     * @param name the name of the provider to remove.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkSecurityAccess} method
+     *          denies
+     *          access to remove the provider
+     *
+     * @see #getProvider
+     * @see #addProvider
+     */
+    public static synchronized void removeProvider(String name) {
+        // Android-removed: Checks using SecurityManager, which is not functional in Android.
+        // check("removeProvider." + name);
+        ProviderList list = Providers.getFullProviderList();
+        ProviderList newList = ProviderList.remove(list, name);
+        Providers.setProviderList(newList);
+        // Android-added: Version tracking call.
+        increaseVersion();
+    }
+
+    /**
+     * Returns an array containing all the installed providers. The order of
+     * the providers in the array is their preference order.
+     *
+     * @return an array of all the installed providers.
+     */
+    public static Provider[] getProviders() {
+        return Providers.getFullProviderList().toArray();
+    }
+
+    /**
+     * Returns the provider installed with the specified name, if
+     * any. Returns null if no provider with the specified name is
+     * installed or if name is null.
+     *
+     * @param name the name of the provider to get.
+     *
+     * @return the provider of the specified name.
+     *
+     * @see #removeProvider
+     * @see #addProvider
+     */
+    public static Provider getProvider(String name) {
+        return Providers.getProviderList().getProvider(name);
+    }
+
+    /**
+     * Returns an array containing all installed providers that satisfy the
+     * specified selection criterion, or null if no such providers have been
+     * installed. The returned providers are ordered
+     * according to their
+     * {@linkplain #insertProviderAt(java.security.Provider, int) preference order}.
+     *
+     * <p> A cryptographic service is always associated with a particular
+     * algorithm or type. For example, a digital signature service is
+     * always associated with a particular algorithm (e.g., DSA),
+     * and a CertificateFactory service is always associated with
+     * a particular certificate type (e.g., X.509).
+     *
+     * <p>The selection criterion must be specified in one of the following two
+     * formats:
+     * <ul>
+     * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i>
+     * <p> The cryptographic service name must not contain any dots.
+     * <p> A
+     * provider satisfies the specified selection criterion iff the provider
+     * implements the
+     * specified algorithm or type for the specified cryptographic service.
+     * <p> For example, "CertificateFactory.X.509"
+     * would be satisfied by any provider that supplied
+     * a CertificateFactory implementation for X.509 certificates.
+     * <li> <i>{@literal <crypto_service>.<algorithm_or_type>
+     * <attribute_name>:<attribute_value>}</i>
+     * <p> The cryptographic service name must not contain any dots. There
+     * must be one or more space characters between the
+     * <i>{@literal <algorithm_or_type>}</i> and the
+     * <i>{@literal <attribute_name>}</i>.
+     *  <p> A provider satisfies this selection criterion iff the
+     * provider implements the specified algorithm or type for the specified
+     * cryptographic service and its implementation meets the
+     * constraint expressed by the specified attribute name/value pair.
+     * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
+     * satisfied by any provider that implemented
+     * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
+     *
+     * </ul>
+     *
+     * <p> See the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard cryptographic service names, standard
+     * algorithm names and standard attribute names.
+     *
+     * @param filter the criterion for selecting
+     * providers. The filter is case-insensitive.
+     *
+     * @return all the installed providers that satisfy the selection
+     * criterion, or null if no such providers have been installed.
+     *
+     * @throws InvalidParameterException
+     *         if the filter is not in the required format
+     * @throws NullPointerException if filter is null
+     *
+     * @see #getProviders(java.util.Map)
+     * @since 1.3
+     */
+    public static Provider[] getProviders(String filter) {
+        String key = null;
+        String value = null;
+        int index = filter.indexOf(':');
+
+        if (index == -1) {
+            key = filter;
+            value = "";
+        } else {
+            key = filter.substring(0, index);
+            value = filter.substring(index + 1);
+        }
+
+        Hashtable<String, String> hashtableFilter = new Hashtable<>(1);
+        hashtableFilter.put(key, value);
+
+        return (getProviders(hashtableFilter));
+    }
+
+    /**
+     * Returns an array containing all installed providers that satisfy the
+     * specified* selection criteria, or null if no such providers have been
+     * installed. The returned providers are ordered
+     * according to their
+     * {@linkplain #insertProviderAt(java.security.Provider, int)
+     * preference order}.
+     *
+     * <p>The selection criteria are represented by a map.
+     * Each map entry represents a selection criterion.
+     * A provider is selected iff it satisfies all selection
+     * criteria. The key for any entry in such a map must be in one of the
+     * following two formats:
+     * <ul>
+     * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i>
+     * <p> The cryptographic service name must not contain any dots.
+     * <p> The value associated with the key must be an empty string.
+     * <p> A provider
+     * satisfies this selection criterion iff the provider implements the
+     * specified algorithm or type for the specified cryptographic service.
+     * <li>  <i>{@literal <crypto_service>}.
+     * {@literal <algorithm_or_type> <attribute_name>}</i>
+     * <p> The cryptographic service name must not contain any dots. There
+     * must be one or more space characters between the
+     * <i>{@literal <algorithm_or_type>}</i>
+     * and the <i>{@literal <attribute_name>}</i>.
+     * <p> The value associated with the key must be a non-empty string.
+     * A provider satisfies this selection criterion iff the
+     * provider implements the specified algorithm or type for the specified
+     * cryptographic service and its implementation meets the
+     * constraint expressed by the specified attribute name/value pair.
+     * </ul>
+     *
+     * <p> See the <a href=
+     * "../../../technotes/guides/security/StandardNames.html">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard cryptographic service names, standard
+     * algorithm names and standard attribute names.
+     *
+     * @param filter the criteria for selecting
+     * providers. The filter is case-insensitive.
+     *
+     * @return all the installed providers that satisfy the selection
+     * criteria, or null if no such providers have been installed.
+     *
+     * @throws InvalidParameterException
+     *         if the filter is not in the required format
+     * @throws NullPointerException if filter is null
+     *
+     * @see #getProviders(java.lang.String)
+     * @since 1.3
+     */
+    public static Provider[] getProviders(Map<String,String> filter) {
+        // Get all installed providers first.
+        // Then only return those providers who satisfy the selection criteria.
+        Provider[] allProviders = Security.getProviders();
+        Set<String> keySet = filter.keySet();
+        LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
+
+        // Returns all installed providers
+        // if the selection criteria is null.
+        if ((keySet == null) || (allProviders == null)) {
+            return allProviders;
+        }
+
+        boolean firstSearch = true;
+
+        // For each selection criterion, remove providers
+        // which don't satisfy the criterion from the candidate set.
+        for (Iterator<String> ite = keySet.iterator(); ite.hasNext(); ) {
+            String key = ite.next();
+            String value = filter.get(key);
+
+            LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(key, value,
+                                                               allProviders);
+            if (firstSearch) {
+                candidates = newCandidates;
+                firstSearch = false;
+            }
+
+            if ((newCandidates != null) && !newCandidates.isEmpty()) {
+                // For each provider in the candidates set, if it
+                // isn't in the newCandidate set, we should remove
+                // it from the candidate set.
+                for (Iterator<Provider> cansIte = candidates.iterator();
+                     cansIte.hasNext(); ) {
+                    Provider prov = cansIte.next();
+                    if (!newCandidates.contains(prov)) {
+                        cansIte.remove();
+                    }
+                }
+            } else {
+                candidates = null;
+                break;
+            }
+        }
+
+        if ((candidates == null) || (candidates.isEmpty()))
+            return null;
+
+        Object[] candidatesArray = candidates.toArray();
+        Provider[] result = new Provider[candidatesArray.length];
+
+        for (int i = 0; i < result.length; i++) {
+            result[i] = (Provider)candidatesArray[i];
+        }
+
+        return result;
+    }
+
+    // Map containing cached Spi Class objects of the specified type
+    private static final Map<String, Class<?>> spiMap =
+            new ConcurrentHashMap<>();
+
+    /**
+     * Return the Class object for the given engine type
+     * (e.g. "MessageDigest"). Works for Spis in the java.security package
+     * only.
+     */
+    private static Class<?> getSpiClass(String type) {
+        Class<?> clazz = spiMap.get(type);
+        if (clazz != null) {
+            return clazz;
+        }
+        try {
+            clazz = Class.forName("java.security." + type + "Spi");
+            spiMap.put(type, clazz);
+            return clazz;
+        } catch (ClassNotFoundException e) {
+            throw new AssertionError("Spi class not found", e);
+        }
+    }
+
+    /*
+     * Returns an array of objects: the first object in the array is
+     * an instance of an implementation of the requested algorithm
+     * and type, and the second object in the array identifies the provider
+     * of that implementation.
+     * The {@code provider} argument can be null, in which case all
+     * configured providers will be searched in order of preference.
+     */
+    static Object[] getImpl(String algorithm, String type, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if (provider == null) {
+            return GetInstance.getInstance
+                (type, getSpiClass(type), algorithm).toArray();
+        } else {
+            return GetInstance.getInstance
+                (type, getSpiClass(type), algorithm, provider).toArray();
+        }
+    }
+
+    static Object[] getImpl(String algorithm, String type, String provider,
+            Object params) throws NoSuchAlgorithmException,
+            NoSuchProviderException, InvalidAlgorithmParameterException {
+        if (provider == null) {
+            return GetInstance.getInstance
+                (type, getSpiClass(type), algorithm, params).toArray();
+        } else {
+            return GetInstance.getInstance
+                (type, getSpiClass(type), algorithm, params, provider).toArray();
+        }
+    }
+
+    /*
+     * Returns an array of objects: the first object in the array is
+     * an instance of an implementation of the requested algorithm
+     * and type, and the second object in the array identifies the provider
+     * of that implementation.
+     * The {@code provider} argument cannot be null.
+     */
+    static Object[] getImpl(String algorithm, String type, Provider provider)
+            throws NoSuchAlgorithmException {
+        return GetInstance.getInstance
+            (type, getSpiClass(type), algorithm, provider).toArray();
+    }
+
+    static Object[] getImpl(String algorithm, String type, Provider provider,
+            Object params) throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        return GetInstance.getInstance
+            (type, getSpiClass(type), algorithm, params, provider).toArray();
+    }
+
+    /**
+     * Gets a security property value.
+     *
+     * <p>First, if there is a security manager, its
+     * {@code checkPermission}  method is called with a
+     * {@code java.security.SecurityPermission("getProperty."+key)}
+     * permission to see if it's ok to retrieve the specified
+     * security property value..
+     *
+     * @param key the key of the property being retrieved.
+     *
+     * @return the value of the security property corresponding to key.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkPermission} method
+     *          denies
+     *          access to retrieve the specified security property value
+     * @throws  NullPointerException is key is null
+     *
+     * @see #setProperty
+     * @see java.security.SecurityPermission
+     */
+    public static String getProperty(String key) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new SecurityPermission("getProperty."+
+                                                      key));
+        }
+        String name = props.getProperty(key);
+        if (name != null)
+            name = name.trim(); // could be a class name with trailing ws
+        return name;
+    }
+
+    /**
+     * Sets a security property value.
+     *
+     * <p>First, if there is a security manager, its
+     * {@code checkPermission} method is called with a
+     * {@code java.security.SecurityPermission("setProperty."+key)}
+     * permission to see if it's ok to set the specified
+     * security property value.
+     *
+     * @param key the name of the property to be set.
+     *
+     * @param datum the value of the property to be set.
+     *
+     * @throws  SecurityException
+     *          if a security manager exists and its {@link
+     *          java.lang.SecurityManager#checkPermission} method
+     *          denies access to set the specified security property value
+     * @throws  NullPointerException if key or datum is null
+     *
+     * @see #getProperty
+     * @see java.security.SecurityPermission
+     */
+    public static void setProperty(String key, String datum) {
+        // Android-removed: Checks using SecurityManager, which is not functional in Android.
+        // check("setProperty."+key);
+        props.put(key, datum);
+        // Android-added: Version tracking call.
+        increaseVersion();
+        invalidateSMCache(key);  /* See below. */
+    }
+
+    /*
+     * Implementation detail:  If the property we just set in
+     * setProperty() was either "package.access" or
+     * "package.definition", we need to signal to the SecurityManager
+     * class that the value has just changed, and that it should
+     * invalidate it's local cache values.
+     *
+     * Rather than create a new API entry for this function,
+     * we use reflection to set a private variable.
+     */
+    private static void invalidateSMCache(String key) {
+
+        final boolean pa = key.equals("package.access");
+        final boolean pd = key.equals("package.definition");
+
+        if (pa || pd) {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    try {
+                        /* Get the class via the bootstrap class loader. */
+                        Class<?> cl = Class.forName(
+                            "java.lang.SecurityManager", false, null);
+                        Field f = null;
+                        boolean accessible = false;
+
+                        if (pa) {
+                            f = cl.getDeclaredField("packageAccessValid");
+                            accessible = f.isAccessible();
+                            f.setAccessible(true);
+                        } else {
+                            f = cl.getDeclaredField("packageDefinitionValid");
+                            accessible = f.isAccessible();
+                            f.setAccessible(true);
+                        }
+                        f.setBoolean(f, false);
+                        f.setAccessible(accessible);
+                    }
+                    catch (Exception e1) {
+                        /* If we couldn't get the class, it hasn't
+                         * been loaded yet.  If there is no such
+                         * field, we shouldn't try to set it.  There
+                         * shouldn't be a security execption, as we
+                         * are loaded by boot class loader, and we
+                         * are inside a doPrivileged() here.
+                         *
+                         * NOOP: don't do anything...
+                         */
+                    }
+                    return null;
+                }  /* run */
+            });  /* PrivilegedAction */
+        }  /* if */
+    }
+
+    // BEGIN Android-removed: SecurityManager is stubbed on Android.
+    /*
+    private static void check(String directive) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSecurityAccess(directive);
+        }
+    }
+
+    private static void checkInsertProvider(String name) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            try {
+                security.checkSecurityAccess("insertProvider");
+            } catch (SecurityException se1) {
+                try {
+                    security.checkSecurityAccess("insertProvider." + name);
+                } catch (SecurityException se2) {
+                    // throw first exception, but add second to suppressed
+                    se1.addSuppressed(se2);
+                    throw se1;
+                }
+            }
+        }
+    }
+    */
+    // END Android-removed: SecurityManager is stubbed on Android.
+
+    /*
+    * Returns all providers who satisfy the specified
+    * criterion.
+    */
+    private static LinkedHashSet<Provider> getAllQualifyingCandidates(
+                                                String filterKey,
+                                                String filterValue,
+                                                Provider[] allProviders) {
+        String[] filterComponents = getFilterComponents(filterKey,
+                                                        filterValue);
+
+        // The first component is the service name.
+        // The second is the algorithm name.
+        // If the third isn't null, that is the attrinute name.
+        String serviceName = filterComponents[0];
+        String algName = filterComponents[1];
+        String attrName = filterComponents[2];
+
+        return getProvidersNotUsingCache(serviceName, algName, attrName,
+                                         filterValue, allProviders);
+    }
+
+    private static LinkedHashSet<Provider> getProvidersNotUsingCache(
+                                                String serviceName,
+                                                String algName,
+                                                String attrName,
+                                                String filterValue,
+                                                Provider[] allProviders) {
+        LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
+        for (int i = 0; i < allProviders.length; i++) {
+            if (isCriterionSatisfied(allProviders[i], serviceName,
+                                     algName,
+                                     attrName, filterValue)) {
+                candidates.add(allProviders[i]);
+            }
+        }
+        return candidates;
+    }
+
+    /*
+     * Returns true if the given provider satisfies
+     * the selection criterion key:value.
+     */
+    private static boolean isCriterionSatisfied(Provider prov,
+                                                String serviceName,
+                                                String algName,
+                                                String attrName,
+                                                String filterValue) {
+        String key = serviceName + '.' + algName;
+
+        if (attrName != null) {
+            key += ' ' + attrName;
+        }
+        // Check whether the provider has a property
+        // whose key is the same as the given key.
+        String propValue = getProviderProperty(key, prov);
+
+        if (propValue == null) {
+            // Check whether we have an alias instead
+            // of a standard name in the key.
+            String standardName = getProviderProperty("Alg.Alias." +
+                                                      serviceName + "." +
+                                                      algName,
+                                                      prov);
+            if (standardName != null) {
+                key = serviceName + "." + standardName;
+
+                if (attrName != null) {
+                    key += ' ' + attrName;
+                }
+
+                propValue = getProviderProperty(key, prov);
+            }
+
+            if (propValue == null) {
+                // The provider doesn't have the given
+                // key in its property list.
+                return false;
+            }
+        }
+
+        // If the key is in the format of:
+        // <crypto_service>.<algorithm_or_type>,
+        // there is no need to check the value.
+
+        if (attrName == null) {
+            return true;
+        }
+
+        // If we get here, the key must be in the
+        // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
+        if (isStandardAttr(attrName)) {
+            return isConstraintSatisfied(attrName, filterValue, propValue);
+        } else {
+            return filterValue.equalsIgnoreCase(propValue);
+        }
+    }
+
+    /*
+     * Returns true if the attribute is a standard attribute;
+     * otherwise, returns false.
+     */
+    private static boolean isStandardAttr(String attribute) {
+        // For now, we just have two standard attributes:
+        // KeySize and ImplementedIn.
+        if (attribute.equalsIgnoreCase("KeySize"))
+            return true;
+
+        if (attribute.equalsIgnoreCase("ImplementedIn"))
+            return true;
+
+        return false;
+    }
+
+    /*
+     * Returns true if the requested attribute value is supported;
+     * otherwise, returns false.
+     */
+    private static boolean isConstraintSatisfied(String attribute,
+                                                 String value,
+                                                 String prop) {
+        // For KeySize, prop is the max key size the
+        // provider supports for a specific <crypto_service>.<algorithm>.
+        if (attribute.equalsIgnoreCase("KeySize")) {
+            int requestedSize = Integer.parseInt(value);
+            int maxSize = Integer.parseInt(prop);
+            if (requestedSize <= maxSize) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        // For Type, prop is the type of the implementation
+        // for a specific <crypto service>.<algorithm>.
+        if (attribute.equalsIgnoreCase("ImplementedIn")) {
+            return value.equalsIgnoreCase(prop);
+        }
+
+        return false;
+    }
+
+    static String[] getFilterComponents(String filterKey, String filterValue) {
+        int algIndex = filterKey.indexOf('.');
+
+        if (algIndex < 0) {
+            // There must be a dot in the filter, and the dot
+            // shouldn't be at the beginning of this string.
+            throw new InvalidParameterException("Invalid filter");
+        }
+
+        String serviceName = filterKey.substring(0, algIndex);
+        String algName = null;
+        String attrName = null;
+
+        if (filterValue.length() == 0) {
+            // The filterValue is an empty string. So the filterKey
+            // should be in the format of <crypto_service>.<algorithm_or_type>.
+            algName = filterKey.substring(algIndex + 1).trim();
+            if (algName.length() == 0) {
+                // There must be a algorithm or type name.
+                throw new InvalidParameterException("Invalid filter");
+            }
+        } else {
+            // The filterValue is a non-empty string. So the filterKey must be
+            // in the format of
+            // <crypto_service>.<algorithm_or_type> <attribute_name>
+            int attrIndex = filterKey.indexOf(' ');
+
+            if (attrIndex == -1) {
+                // There is no attribute name in the filter.
+                throw new InvalidParameterException("Invalid filter");
+            } else {
+                attrName = filterKey.substring(attrIndex + 1).trim();
+                if (attrName.length() == 0) {
+                    // There is no attribute name in the filter.
+                    throw new InvalidParameterException("Invalid filter");
+                }
+            }
+
+            // There must be an algorithm name in the filter.
+            if ((attrIndex < algIndex) ||
+                (algIndex == attrIndex - 1)) {
+                throw new InvalidParameterException("Invalid filter");
+            } else {
+                algName = filterKey.substring(algIndex + 1, attrIndex);
+            }
+        }
+
+        String[] result = new String[3];
+        result[0] = serviceName;
+        result[1] = algName;
+        result[2] = attrName;
+
+        return result;
+    }
+
+    /**
+     * Returns a Set of Strings containing the names of all available
+     * algorithms or types for the specified Java cryptographic service
+     * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
+     * an empty Set if there is no provider that supports the
+     * specified service or if serviceName is null. For a complete list
+     * of Java cryptographic services, please see the
+     * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
+     * Cryptography Architecture API Specification &amp; Reference</a>.
+     * Note: the returned set is immutable.
+     *
+     * @param serviceName the name of the Java cryptographic
+     * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
+     * Note: this parameter is case-insensitive.
+     *
+     * @return a Set of Strings containing the names of all available
+     * algorithms or types for the specified Java cryptographic service
+     * or an empty set if no provider supports the specified service.
+     *
+     * @since 1.4
+     **/
+    public static Set<String> getAlgorithms(String serviceName) {
+
+        if ((serviceName == null) || (serviceName.length() == 0) ||
+            (serviceName.endsWith("."))) {
+            return Collections.emptySet();
+        }
+
+        HashSet<String> result = new HashSet<>();
+        Provider[] providers = Security.getProviders();
+
+        for (int i = 0; i < providers.length; i++) {
+            // Check the keys for each provider.
+            for (Enumeration<Object> e = providers[i].keys();
+                                                e.hasMoreElements(); ) {
+                String currentKey =
+                        ((String)e.nextElement()).toUpperCase(Locale.ENGLISH);
+                if (currentKey.startsWith(
+                        serviceName.toUpperCase(Locale.ENGLISH))) {
+                    // We should skip the currentKey if it contains a
+                    // whitespace. The reason is: such an entry in the
+                    // provider property contains attributes for the
+                    // implementation of an algorithm. We are only interested
+                    // in entries which lead to the implementation
+                    // classes.
+                    if (currentKey.indexOf(" ") < 0) {
+                        result.add(currentKey.substring(
+                                                serviceName.length() + 1));
+                    }
+                }
+            }
+        }
+        return Collections.unmodifiableSet(result);
+    }
+
+    // BEGIN Android-added: Methods for version handling.
+    /**
+     * @hide
+     */
+    public static void increaseVersion() {
+        version.incrementAndGet();
+    }
+    /**
+     * @hide
+     */
+    public static int getVersion() {
+        return version.get();
+    }
+    // END Android-added: Methods for version handling.
+}
diff --git a/java/security/SecurityPermission.java b/java/security/SecurityPermission.java
new file mode 100644
index 0000000..f02755c
--- /dev/null
+++ b/java/security/SecurityPermission.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class SecurityPermission extends BasicPermission {
+
+    public SecurityPermission(String name) { super(""); }
+    public SecurityPermission(String name, String actions) { super("", ""); }
+}
diff --git a/java/security/Signature.annotated.java b/java/security/Signature.annotated.java
new file mode 100644
index 0000000..87323e2
--- /dev/null
+++ b/java/security/Signature.annotated.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (C) 2014 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.security;
+
+import java.util.*;
+import java.io.*;
+import sun.security.jca.*;
+import java.nio.ByteBuffer;
+import java.security.spec.AlgorithmParameterSpec;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Signature extends java.security.SignatureSpi {
+
+protected Signature(java.lang.String algorithm) { throw new RuntimeException("Stub!"); }
+
+public static java.security.Signature getInstance(java.lang.String algorithm) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public static java.security.Signature getInstance(java.lang.String algorithm, java.lang.String provider) throws java.security.NoSuchAlgorithmException, java.security.NoSuchProviderException { throw new RuntimeException("Stub!"); }
+
+public static java.security.Signature getInstance(java.lang.String algorithm, java.security.Provider provider) throws java.security.NoSuchAlgorithmException { throw new RuntimeException("Stub!"); }
+
+public final java.security.Provider getProvider() { throw new RuntimeException("Stub!"); }
+
+public final void initVerify(java.security.PublicKey publicKey) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void initVerify(java.security.cert.Certificate certificate) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void initSign(java.security.PrivateKey privateKey) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final void initSign(java.security.PrivateKey privateKey, java.security.SecureRandom random) throws java.security.InvalidKeyException { throw new RuntimeException("Stub!"); }
+
+public final byte[] sign() throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final int sign(byte[] outbuf, int offset, int len) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final boolean verify(byte[] signature) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final boolean verify(byte[] signature, int offset, int length) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte b) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte[] data) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final void update(byte[] data, int off, int len) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final void update(java.nio.ByteBuffer data) throws java.security.SignatureException { throw new RuntimeException("Stub!"); }
+
+public final java.lang.String getAlgorithm() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public final void setParameter(java.lang.String param, java.lang.Object value) throws java.security.InvalidParameterException { throw new RuntimeException("Stub!"); }
+
+public final void setParameter(java.security.spec.AlgorithmParameterSpec params) throws java.security.InvalidAlgorithmParameterException { throw new RuntimeException("Stub!"); }
+
+public final java.security.AlgorithmParameters getParameters() { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public final java.lang.Object getParameter(java.lang.String param) throws java.security.InvalidParameterException { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.security.SignatureSpi getCurrentSpi() { throw new RuntimeException("Stub!"); }
+
+protected static final int SIGN = 2; // 0x2
+
+protected static final int UNINITIALIZED = 0; // 0x0
+
+protected static final int VERIFY = 3; // 0x3
+
+protected int state = 0; // 0x0
+}
+
diff --git a/java/security/Signature.java b/java/security/Signature.java
new file mode 100644
index 0000000..bbe9640
--- /dev/null
+++ b/java/security/Signature.java
@@ -0,0 +1,1564 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (C) 2014 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.io.*;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import java.nio.ByteBuffer;
+
+import java.security.Provider.Service;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.NoSuchPaddingException;
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * The Signature class is used to provide applications the functionality
+ * of a digital signature algorithm. Digital signatures are used for
+ * authentication and integrity assurance of digital data.
+ *
+ * <p> The signature algorithm can be, among others, the NIST standard
+ * DSA, using DSA and SHA-1. The DSA algorithm using the
+ * SHA-1 message digest algorithm can be specified as {@code SHA1withDSA}.
+ * In the case of RSA, there are multiple choices for the message digest
+ * algorithm, so the signing algorithm could be specified as, for example,
+ * {@code MD2withRSA}, {@code MD5withRSA}, or {@code SHA1withRSA}.
+ * The algorithm name must be specified, as there is no default.
+ *
+ * <p> A Signature object can be used to generate and verify digital
+ * signatures.
+ *
+ * <p> There are three phases to the use of a Signature object for
+ * either signing data or verifying a signature:<ol>
+ *
+ * <li>Initialization, with either
+ *
+ *     <ul>
+ *
+ *     <li>a public key, which initializes the signature for
+ *     verification (see {@link #initVerify(PublicKey) initVerify}), or
+ *
+ *     <li>a private key (and optionally a Secure Random Number Generator),
+ *     which initializes the signature for signing
+ *     (see {@link #initSign(PrivateKey)}
+ *     and {@link #initSign(PrivateKey, SecureRandom)}).
+ *
+ *     </ul>
+ *
+ * <li>Updating
+ *
+ * <p>Depending on the type of initialization, this will update the
+ * bytes to be signed or verified. See the
+ * {@link #update(byte) update} methods.
+ *
+ * <li>Signing or Verifying a signature on all updated bytes. See the
+ * {@link #sign() sign} methods and the {@link #verify(byte[]) verify}
+ * method.
+ *
+ * </ol>
+ *
+ * <p>Note that this class is abstract and extends from
+ * {@code SignatureSpi} for historical reasons.
+ * Application developers should only take notice of the methods defined in
+ * this {@code Signature} class; all the methods in
+ * the superclass are intended for cryptographic service providers who wish to
+ * supply their own implementations of digital signature algorithms.
+ *
+ * <p> Android provides the following {@code Signature} algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>DSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>DSAwithSHA1</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>DSS</td>
+ *       <td>1-19</td>
+ *     </tr>
+ *     <tr>
+ *       <td>ECDSA</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>ECDSAwithSHA1</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>MD2withRSA</td>
+ *       <td>1-3</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>MD4withRSA</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>MD5withRSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>MD5withRSA/ISO9796-2</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>NONEwithDSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>NONEwithECDSA</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>NONEwithRSA</td>
+ *       <td>17+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>RSASSA-PSS</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA1withDSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA1withECDSA</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA1withRSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr class="deprecated">
+ *       <td>SHA1withRSA/ISO9796-2</td>
+ *       <td>1-8</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA1withRSA/PSS</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA224withDSA</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA224withECDSA</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA224withRSA</td>
+ *       <td>20+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA224withRSA/PSS</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA256withDSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA256withECDSA</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA256withRSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA256withRSA/PSS</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA384withECDSA</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA384withRSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA384withRSA/PSS</td>
+ *       <td>23+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA512withECDSA</td>
+ *       <td>11+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA512withRSA</td>
+ *       <td>1+</td>
+ *     </tr>
+ *     <tr>
+ *       <td>SHA512withRSA/PSS</td>
+ *       <td>23+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * These algorithms are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+ * Signature section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Benjamin Renaud
+ *
+ */
+
+public abstract class Signature extends SignatureSpi {
+
+    // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+    /*
+    private static final Debug debug =
+                        Debug.getInstance("jca", "Signature");
+
+    private static final Debug pdebug =
+                        Debug.getInstance("provider", "Provider");
+    private static final boolean skipDebug =
+        Debug.isOn("engine=") && !Debug.isOn("signature");
+    // END Android-removed: this debugging mechanism is not supported in Android.
+    */
+
+    /*
+     * The algorithm for this signature object.
+     * This value is used to map an OID to the particular algorithm.
+     * The mapping is done in AlgorithmObject.algOID(String algorithm)
+     */
+    private String algorithm;
+
+    // The provider
+    Provider provider;
+
+    /**
+     * Possible {@link #state} value, signifying that
+     * this signature object has not yet been initialized.
+     */
+    protected final static int UNINITIALIZED = 0;
+
+    /**
+     * Possible {@link #state} value, signifying that
+     * this signature object has been initialized for signing.
+     */
+    protected final static int SIGN = 2;
+
+    /**
+     * Possible {@link #state} value, signifying that
+     * this signature object has been initialized for verification.
+     */
+    protected final static int VERIFY = 3;
+
+    /**
+     * Current state of this signature object.
+     */
+    protected int state = UNINITIALIZED;
+
+    /**
+     * Creates a Signature object for the specified algorithm.
+     *
+     * @param algorithm the standard string name of the algorithm.
+     * See the Signature section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     */
+    protected Signature(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    // name of the special signature alg
+    private final static String RSA_SIGNATURE = "NONEwithRSA";
+
+    // name of the equivalent cipher alg
+    private final static String RSA_CIPHER = "RSA/ECB/PKCS1Padding";
+
+    // all the services we need to lookup for compatibility with Cipher
+    private final static List<ServiceId> rsaIds = Arrays.asList(
+        new ServiceId[] {
+            new ServiceId("Signature", "NONEwithRSA"),
+            new ServiceId("Cipher", "RSA/ECB/PKCS1Padding"),
+            new ServiceId("Cipher", "RSA/ECB"),
+            new ServiceId("Cipher", "RSA//PKCS1Padding"),
+            new ServiceId("Cipher", "RSA"),
+        }
+    );
+
+    /**
+     * Returns a Signature object that implements the specified signature
+     * algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new Signature object encapsulating the
+     * SignatureSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the standard name of the algorithm requested.
+     * See the Signature section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return the new Signature object.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          Signature implementation for the
+     *          specified algorithm.
+     *
+     * @see Provider
+     */
+    public static Signature getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        List<Service> list;
+        if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
+            list = GetInstance.getServices(rsaIds);
+        } else {
+            list = GetInstance.getServices("Signature", algorithm);
+        }
+        Iterator<Service> t = list.iterator();
+        if (t.hasNext() == false) {
+            throw new NoSuchAlgorithmException
+                (algorithm + " Signature not available");
+        }
+        // try services until we find an Spi or a working Signature subclass
+        NoSuchAlgorithmException failure;
+        do {
+            Service s = t.next();
+            if (isSpi(s)) {
+                // Android-changed: Delegate constructor only takes algorithm.
+                // return new Delegate(s, t, algorithm);
+                return new Delegate(algorithm);
+            } else {
+                // must be a subclass of Signature, disable dynamic selection
+                try {
+                    Instance instance =
+                        GetInstance.getInstance(s, SignatureSpi.class);
+                    return getInstance(instance, algorithm);
+                } catch (NoSuchAlgorithmException e) {
+                    failure = e;
+                }
+            }
+        } while (t.hasNext());
+        throw failure;
+    }
+
+    private static Signature getInstance(Instance instance, String algorithm) {
+        Signature sig;
+        if (instance.impl instanceof Signature) {
+            sig = (Signature)instance.impl;
+            sig.algorithm = algorithm;
+        } else {
+            SignatureSpi spi = (SignatureSpi)instance.impl;
+            sig = new Delegate(spi, algorithm);
+        }
+        sig.provider = instance.provider;
+        return sig;
+    }
+
+    private final static Map<String,Boolean> signatureInfo;
+
+    static {
+        signatureInfo = new ConcurrentHashMap<String,Boolean>();
+        Boolean TRUE = Boolean.TRUE;
+        // pre-initialize with values for our SignatureSpi implementations
+        signatureInfo.put("sun.security.provider.DSA$RawDSA", TRUE);
+        signatureInfo.put("sun.security.provider.DSA$SHA1withDSA", TRUE);
+        signatureInfo.put("sun.security.rsa.RSASignature$MD2withRSA", TRUE);
+        signatureInfo.put("sun.security.rsa.RSASignature$MD5withRSA", TRUE);
+        signatureInfo.put("sun.security.rsa.RSASignature$SHA1withRSA", TRUE);
+        signatureInfo.put("sun.security.rsa.RSASignature$SHA256withRSA", TRUE);
+        signatureInfo.put("sun.security.rsa.RSASignature$SHA384withRSA", TRUE);
+        signatureInfo.put("sun.security.rsa.RSASignature$SHA512withRSA", TRUE);
+        signatureInfo.put("com.sun.net.ssl.internal.ssl.RSASignature", TRUE);
+        signatureInfo.put("sun.security.pkcs11.P11Signature", TRUE);
+    }
+
+    private static boolean isSpi(Service s) {
+        if (s.getType().equals("Cipher")) {
+            // must be a CipherSpi, which we can wrap with the CipherAdapter
+            return true;
+        }
+        String className = s.getClassName();
+        Boolean result = signatureInfo.get(className);
+        if (result == null) {
+            try {
+                Object instance = s.newInstance(null);
+                // Signature extends SignatureSpi
+                // so it is a "real" Spi if it is an
+                // instance of SignatureSpi but not Signature
+                boolean r = (instance instanceof SignatureSpi)
+                                && (instance instanceof Signature == false);
+                // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+                /*
+                if ((debug != null) && (r == false)) {
+                    debug.println("Not a SignatureSpi " + className);
+                    debug.println("Delayed provider selection may not be "
+                        + "available for algorithm " + s.getAlgorithm());
+                }
+                */
+                // END Android-removed: this debugging mechanism is not supported in Android.
+                result = Boolean.valueOf(r);
+                signatureInfo.put(className, result);
+            } catch (Exception e) {
+                // something is wrong, assume not an SPI
+                return false;
+            }
+        }
+        return result.booleanValue();
+    }
+
+    /**
+     * Returns a Signature object that implements the specified signature
+     * algorithm.
+     *
+     * <p> A new Signature object encapsulating the
+     * SignatureSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the Signature section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return the new Signature object.
+     *
+     * @exception NoSuchAlgorithmException if a SignatureSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see Provider
+     */
+    public static Signature getInstance(String algorithm, String provider)
+            throws NoSuchAlgorithmException, NoSuchProviderException {
+        if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
+            // exception compatibility with existing code
+            if ((provider == null) || (provider.length() == 0)) {
+                throw new IllegalArgumentException("missing provider");
+            }
+            Provider p = Security.getProvider(provider);
+            if (p == null) {
+                throw new NoSuchProviderException
+                    ("no such provider: " + provider);
+            }
+            return getInstanceRSA(p);
+        }
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "Signature", algorithm);
+        Instance instance = GetInstance.getInstance
+                ("Signature", SignatureSpi.class, algorithm, provider);
+        return getInstance(instance, algorithm);
+    }
+
+    /**
+     * Returns a Signature object that implements the specified
+     * signature algorithm.
+     *
+     * <p> A new Signature object encapsulating the
+     * SignatureSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the name of the algorithm requested.
+     * See the Signature section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return the new Signature object.
+     *
+     * @exception NoSuchAlgorithmException if a SignatureSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the provider is null.
+     *
+     * @see Provider
+     *
+     * @since 1.4
+     */
+    public static Signature getInstance(String algorithm, Provider provider)
+            throws NoSuchAlgorithmException {
+        if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
+            // exception compatibility with existing code
+            if (provider == null) {
+                throw new IllegalArgumentException("missing provider");
+            }
+            return getInstanceRSA(provider);
+        }
+        // Android-added: Check for Bouncy Castle deprecation
+        Providers.checkBouncyCastleDeprecation(provider, "Signature", algorithm);
+        Instance instance = GetInstance.getInstance
+                ("Signature", SignatureSpi.class, algorithm, provider);
+        return getInstance(instance, algorithm);
+    }
+
+    // return an implementation for NONEwithRSA, which is a special case
+    // because of the Cipher.RSA/ECB/PKCS1Padding compatibility wrapper
+    private static Signature getInstanceRSA(Provider p)
+            throws NoSuchAlgorithmException {
+        // try Signature first
+        Service s = p.getService("Signature", RSA_SIGNATURE);
+        if (s != null) {
+            Instance instance = GetInstance.getInstance(s, SignatureSpi.class);
+            return getInstance(instance, RSA_SIGNATURE);
+        }
+        // check Cipher
+        try {
+            Cipher c = Cipher.getInstance(RSA_CIPHER, p);
+            return new Delegate(new CipherAdapter(c), RSA_SIGNATURE);
+        } catch (GeneralSecurityException e) {
+            // throw Signature style exception message to avoid confusion,
+            // but append Cipher exception as cause
+            throw new NoSuchAlgorithmException("no such algorithm: "
+                + RSA_SIGNATURE + " for provider " + p.getName(), e);
+        }
+    }
+
+    /**
+     * Returns the provider of this signature object.
+     *
+     * @return the provider of this signature object
+     */
+    public final Provider getProvider() {
+        chooseFirstProvider();
+        return this.provider;
+    }
+
+    void chooseFirstProvider() {
+        // empty, overridden in Delegate
+    }
+
+    /**
+     * Initializes this object for verification. If this method is called
+     * again with a different argument, it negates the effect
+     * of this call.
+     *
+     * @param publicKey the public key of the identity whose signature is
+     * going to be verified.
+     *
+     * @exception InvalidKeyException if the key is invalid.
+     */
+    public final void initVerify(PublicKey publicKey)
+            throws InvalidKeyException {
+        engineInitVerify(publicKey);
+        state = VERIFY;
+
+        // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Signature." + algorithm +
+                " verification algorithm from: " + this.provider.getName());
+        }
+        */
+        // END Android-removed: this debugging mechanism is not supported in Android.
+    }
+
+    /**
+     * Initializes this object for verification, using the public key from
+     * the given certificate.
+     * <p>If the certificate is of type X.509 and has a <i>key usage</i>
+     * extension field marked as critical, and the value of the <i>key usage</i>
+     * extension field implies that the public key in
+     * the certificate and its corresponding private key are not
+     * supposed to be used for digital signatures, an
+     * {@code InvalidKeyException} is thrown.
+     *
+     * @param certificate the certificate of the identity whose signature is
+     * going to be verified.
+     *
+     * @exception InvalidKeyException  if the public key in the certificate
+     * is not encoded properly or does not include required  parameter
+     * information or cannot be used for digital signature purposes.
+     * @since 1.3
+     */
+    public final void initVerify(Certificate certificate)
+            throws InvalidKeyException {
+        // If the certificate is of type X509Certificate,
+        // we should check whether it has a Key Usage
+        // extension marked as critical.
+        if (certificate instanceof java.security.cert.X509Certificate) {
+            // Check whether the cert has a key usage extension
+            // marked as a critical extension.
+            // The OID for KeyUsage extension is 2.5.29.15.
+            X509Certificate cert = (X509Certificate)certificate;
+            Set<String> critSet = cert.getCriticalExtensionOIDs();
+
+            if (critSet != null && !critSet.isEmpty()
+                && critSet.contains("2.5.29.15")) {
+                boolean[] keyUsageInfo = cert.getKeyUsage();
+                // keyUsageInfo[0] is for digitalSignature.
+                if ((keyUsageInfo != null) && (keyUsageInfo[0] == false))
+                    throw new InvalidKeyException("Wrong key usage");
+            }
+        }
+
+        PublicKey publicKey = certificate.getPublicKey();
+        engineInitVerify(publicKey);
+        state = VERIFY;
+
+        // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Signature." + algorithm +
+                " verification algorithm from: " + this.provider.getName());
+        }
+        */
+        // END Android-removed: this debugging mechanism is not supported in Android.
+    }
+
+    /**
+     * Initialize this object for signing. If this method is called
+     * again with a different argument, it negates the effect
+     * of this call.
+     *
+     * @param privateKey the private key of the identity whose signature
+     * is going to be generated.
+     *
+     * @exception InvalidKeyException if the key is invalid.
+     */
+    public final void initSign(PrivateKey privateKey)
+            throws InvalidKeyException {
+        engineInitSign(privateKey);
+        state = SIGN;
+
+        // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Signature." + algorithm +
+                " signing algorithm from: " + this.provider.getName());
+        }
+        */
+        // END Android-removed: this debugging mechanism is not supported in Android.
+    }
+
+    /**
+     * Initialize this object for signing. If this method is called
+     * again with a different argument, it negates the effect
+     * of this call.
+     *
+     * @param privateKey the private key of the identity whose signature
+     * is going to be generated.
+     *
+     * @param random the source of randomness for this signature.
+     *
+     * @exception InvalidKeyException if the key is invalid.
+     */
+    public final void initSign(PrivateKey privateKey, SecureRandom random)
+            throws InvalidKeyException {
+        engineInitSign(privateKey, random);
+        state = SIGN;
+
+        // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+        /*
+        if (!skipDebug && pdebug != null) {
+            pdebug.println("Signature." + algorithm +
+                " signing algorithm from: " + this.provider.getName());
+        }
+        */
+        // END Android-removed: this debugging mechanism is not supported in Android.
+    }
+
+    /**
+     * Returns the signature bytes of all the data updated.
+     * The format of the signature depends on the underlying
+     * signature scheme.
+     *
+     * <p>A call to this method resets this signature object to the state
+     * it was in when previously initialized for signing via a
+     * call to {@code initSign(PrivateKey)}. That is, the object is
+     * reset and available to generate another signature from the same
+     * signer, if desired, via new calls to {@code update} and
+     * {@code sign}.
+     *
+     * @return the signature bytes of the signing operation's result.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly or if this signature algorithm is unable to
+     * process the input data provided.
+     */
+    public final byte[] sign() throws SignatureException {
+        if (state == SIGN) {
+            return engineSign();
+        }
+        throw new SignatureException("object not initialized for " +
+                                     "signing");
+    }
+
+    /**
+     * Finishes the signature operation and stores the resulting signature
+     * bytes in the provided buffer {@code outbuf}, starting at
+     * {@code offset}.
+     * The format of the signature depends on the underlying
+     * signature scheme.
+     *
+     * <p>This signature object is reset to its initial state (the state it
+     * was in after a call to one of the {@code initSign} methods) and
+     * can be reused to generate further signatures with the same private key.
+     *
+     * @param outbuf buffer for the signature result.
+     *
+     * @param offset offset into {@code outbuf} where the signature is
+     * stored.
+     *
+     * @param len number of bytes within {@code outbuf} allotted for the
+     * signature.
+     *
+     * @return the number of bytes placed into {@code outbuf}.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly, if this signature algorithm is unable to
+     * process the input data provided, or if {@code len} is less
+     * than the actual signature length.
+     *
+     * @since 1.2
+     */
+    public final int sign(byte[] outbuf, int offset, int len)
+        throws SignatureException {
+        if (outbuf == null) {
+            throw new IllegalArgumentException("No output buffer given");
+        }
+        if (offset < 0 || len < 0) {
+            throw new IllegalArgumentException("offset or len is less than 0");
+        }
+        if (outbuf.length - offset < len) {
+            throw new IllegalArgumentException
+                ("Output buffer too small for specified offset and length");
+        }
+        if (state != SIGN) {
+            throw new SignatureException("object not initialized for " +
+                                         "signing");
+        }
+        return engineSign(outbuf, offset, len);
+    }
+
+    /**
+     * Verifies the passed-in signature.
+     *
+     * <p>A call to this method resets this signature object to the state
+     * it was in when previously initialized for verification via a
+     * call to {@code initVerify(PublicKey)}. That is, the object is
+     * reset and available to verify another signature from the identity
+     * whose public key was specified in the call to {@code initVerify}.
+     *
+     * @param signature the signature bytes to be verified.
+     *
+     * @return true if the signature was verified, false if not.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly, the passed-in signature is improperly
+     * encoded or of the wrong type, if this signature algorithm is unable to
+     * process the input data provided, etc.
+     */
+    public final boolean verify(byte[] signature) throws SignatureException {
+        if (state == VERIFY) {
+            return engineVerify(signature);
+        }
+        throw new SignatureException("object not initialized for " +
+                                     "verification");
+    }
+
+    /**
+     * Verifies the passed-in signature in the specified array
+     * of bytes, starting at the specified offset.
+     *
+     * <p>A call to this method resets this signature object to the state
+     * it was in when previously initialized for verification via a
+     * call to {@code initVerify(PublicKey)}. That is, the object is
+     * reset and available to verify another signature from the identity
+     * whose public key was specified in the call to {@code initVerify}.
+     *
+     *
+     * @param signature the signature bytes to be verified.
+     * @param offset the offset to start from in the array of bytes.
+     * @param length the number of bytes to use, starting at offset.
+     *
+     * @return true if the signature was verified, false if not.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly, the passed-in signature is improperly
+     * encoded or of the wrong type, if this signature algorithm is unable to
+     * process the input data provided, etc.
+     * @exception IllegalArgumentException if the {@code signature}
+     * byte array is null, or the {@code offset} or {@code length}
+     * is less than 0, or the sum of the {@code offset} and
+     * {@code length} is greater than the length of the
+     * {@code signature} byte array.
+     * @since 1.4
+     */
+    public final boolean verify(byte[] signature, int offset, int length)
+        throws SignatureException {
+        if (state == VERIFY) {
+            if (signature == null) {
+                throw new IllegalArgumentException("signature is null");
+            }
+            if (offset < 0 || length < 0) {
+                throw new IllegalArgumentException
+                    ("offset or length is less than 0");
+            }
+            if (signature.length - offset < length) {
+                throw new IllegalArgumentException
+                    ("signature too small for specified offset and length");
+            }
+
+            return engineVerify(signature, offset, length);
+        }
+        throw new SignatureException("object not initialized for " +
+                                     "verification");
+    }
+
+    /**
+     * Updates the data to be signed or verified by a byte.
+     *
+     * @param b the byte to use for the update.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly.
+     */
+    public final void update(byte b) throws SignatureException {
+        if (state == VERIFY || state == SIGN) {
+            engineUpdate(b);
+        } else {
+            throw new SignatureException("object not initialized for "
+                                         + "signature or verification");
+        }
+    }
+
+    /**
+     * Updates the data to be signed or verified, using the specified
+     * array of bytes.
+     *
+     * @param data the byte array to use for the update.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly.
+     */
+    public final void update(byte[] data) throws SignatureException {
+        update(data, 0, data.length);
+    }
+
+    /**
+     * Updates the data to be signed or verified, using the specified
+     * array of bytes, starting at the specified offset.
+     *
+     * @param data the array of bytes.
+     * @param off the offset to start from in the array of bytes.
+     * @param len the number of bytes to use, starting at offset.
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly.
+     */
+    public final void update(byte[] data, int off, int len)
+            throws SignatureException {
+        if (state == SIGN || state == VERIFY) {
+            if (data == null) {
+                throw new IllegalArgumentException("data is null");
+            }
+            if (off < 0 || len < 0) {
+                throw new IllegalArgumentException("off or len is less than 0");
+            }
+            if (data.length - off < len) {
+                throw new IllegalArgumentException
+                    ("data too small for specified offset and length");
+            }
+            engineUpdate(data, off, len);
+        } else {
+            throw new SignatureException("object not initialized for "
+                                         + "signature or verification");
+        }
+    }
+
+    /**
+     * Updates the data to be signed or verified using the specified
+     * ByteBuffer. Processes the {@code data.remaining()} bytes
+     * starting at at {@code data.position()}.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * @param data the ByteBuffer
+     *
+     * @exception SignatureException if this signature object is not
+     * initialized properly.
+     * @since 1.5
+     */
+    public final void update(ByteBuffer data) throws SignatureException {
+        if ((state != SIGN) && (state != VERIFY)) {
+            throw new SignatureException("object not initialized for "
+                                         + "signature or verification");
+        }
+        if (data == null) {
+            throw new NullPointerException();
+        }
+        engineUpdate(data);
+    }
+
+    /**
+     * Returns the name of the algorithm for this signature object.
+     *
+     * @return the name of the algorithm for this signature object.
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Returns a string representation of this signature object,
+     * providing information that includes the state of the object
+     * and the name of the algorithm used.
+     *
+     * @return a string representation of this signature object.
+     */
+    public String toString() {
+        String initState = "";
+        switch (state) {
+        case UNINITIALIZED:
+            initState = "<not initialized>";
+            break;
+        case VERIFY:
+            initState = "<initialized for verifying>";
+            break;
+        case SIGN:
+            initState = "<initialized for signing>";
+            break;
+        }
+        return "Signature object: " + getAlgorithm() + initState;
+    }
+
+    /**
+     * Sets the specified algorithm parameter to the specified value.
+     * This method supplies a general-purpose mechanism through
+     * which it is possible to set the various parameters of this object.
+     * A parameter may be any settable parameter for the algorithm, such as
+     * a parameter size, or a source of random bits for signature generation
+     * (if appropriate), or an indication of whether or not to perform
+     * a specific but optional computation. A uniform algorithm-specific
+     * naming scheme for each parameter is desirable but left unspecified
+     * at this time.
+     *
+     * @param param the string identifier of the parameter.
+     * @param value the parameter value.
+     *
+     * @exception InvalidParameterException if {@code param} is an
+     * invalid parameter for this signature algorithm engine,
+     * the parameter is already set
+     * and cannot be set again, a security exception occurs, and so on.
+     *
+     * @see #getParameter
+     *
+     * @deprecated Use
+     * {@link #setParameter(java.security.spec.AlgorithmParameterSpec)
+     * setParameter}.
+     */
+    @Deprecated
+    public final void setParameter(String param, Object value)
+            throws InvalidParameterException {
+        engineSetParameter(param, value);
+    }
+
+    /**
+     * Initializes this signature engine with the specified parameter set.
+     *
+     * @param params the parameters
+     *
+     * @exception InvalidAlgorithmParameterException if the given parameters
+     * are inappropriate for this signature engine
+     *
+     * @see #getParameters
+     */
+    public final void setParameter(AlgorithmParameterSpec params)
+            throws InvalidAlgorithmParameterException {
+        engineSetParameter(params);
+    }
+
+    /**
+     * Returns the parameters used with this signature object.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this signature, or may contain a combination of default and randomly
+     * generated parameter values used by the underlying signature
+     * implementation if this signature requires algorithm parameters but
+     * was not initialized with any.
+     *
+     * @return the parameters used with this signature, or null if this
+     * signature does not use any parameters.
+     *
+     * @see #setParameter(AlgorithmParameterSpec)
+     * @since 1.4
+     */
+    public final AlgorithmParameters getParameters() {
+        return engineGetParameters();
+    }
+
+    /**
+     * Gets the value of the specified algorithm parameter. This method
+     * supplies a general-purpose mechanism through which it is possible to
+     * get the various parameters of this object. A parameter may be any
+     * settable parameter for the algorithm, such as a parameter size, or
+     * a source of random bits for signature generation (if appropriate),
+     * or an indication of whether or not to perform a specific but optional
+     * computation. A uniform algorithm-specific naming scheme for each
+     * parameter is desirable but left unspecified at this time.
+     *
+     * @param param the string name of the parameter.
+     *
+     * @return the object that represents the parameter value, or null if
+     * there is none.
+     *
+     * @exception InvalidParameterException if {@code param} is an invalid
+     * parameter for this engine, or another exception occurs while
+     * trying to get this parameter.
+     *
+     * @see #setParameter(String, Object)
+     *
+     * @deprecated Deprecated.
+     */
+    @Deprecated
+    // Android-changed: add "Deprecated."
+    public final Object getParameter(String param)
+            throws InvalidParameterException {
+        return engineGetParameter(param);
+    }
+
+    /**
+     * Returns a clone if the implementation is cloneable.
+     *
+     * @return a clone if the implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called
+     * on an implementation that does not support {@code Cloneable}.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+
+    // BEGIN Android-added: Allow access to the current SPI for testing purposes.
+    /**
+     * Returns the {@code SignatureSpi} backing this {@code Signature}.
+     *
+     * @hide
+     */
+    public SignatureSpi getCurrentSpi() {
+      return null;
+    }
+    // END Android-added: Allow access to the current SPI for testing purposes.
+
+    /*
+     * The following class allows providers to extend from SignatureSpi
+     * rather than from Signature. It represents a Signature with an
+     * encapsulated, provider-supplied SPI object (of type SignatureSpi).
+     * If the provider implementation is an instance of SignatureSpi, the
+     * getInstance() methods above return an instance of this class, with
+     * the SPI object encapsulated.
+     *
+     * Note: All SPI methods from the original Signature class have been
+     * moved up the hierarchy into a new class (SignatureSpi), which has
+     * been interposed in the hierarchy between the API (Signature)
+     * and its original parent (Object).
+     */
+
+    @SuppressWarnings("deprecation")
+    private static class Delegate extends Signature {
+
+        // The provider implementation (delegate)
+        // filled in once the provider is selected
+        // BEGIN Android-note: Note on sigSpi invariants.
+        // (Not necessarily Android specific)
+        // Invariant to be preserved: sigSpi cannot be changed once it was assigned to something
+        // different than null and lock is null. That is only the case when sigSpi is specified
+        // in the constructor.
+        // END Android-note: Note on sigSpi invariants.
+        private SignatureSpi sigSpi;
+
+        // lock for mutex during provider selection
+        private final Object lock;
+
+        // BEGIN Android-removed: Redo the provider selection logic to allow reselecting provider.
+        // When only the algorithm is specified, we want to allow the Signature provider for that
+        // algorithm to change if multiple providers exist and they support different subsets of
+        // keys.  To that end, we don't hold an iterator and exhaust it when we need to choose
+        // a provider like the upstream implementation, we reestablish the list of providers
+        // each time.
+        /*
+        // next service to try in provider selection
+        // null once provider is selected
+        private Service firstService;
+
+        // remaining services to try in provider selection
+        // null once provider is selected
+        private Iterator<Service> serviceIterator;
+        */
+        // END Android-removed: Redo the provider selection logic to allow reselecting provider.
+
+        // constructor
+        Delegate(SignatureSpi sigSpi, String algorithm) {
+            super(algorithm);
+            this.sigSpi = sigSpi;
+            this.lock = null; // no lock needed
+        }
+
+        // used with delayed provider selection
+        // Android-changed: Remove Service and Iterator from constructor args.
+        Delegate(String algorithm) {
+            super(algorithm);
+            this.lock = new Object();
+        }
+
+        /**
+         * Returns a clone if the delegate is cloneable.
+         *
+         * @return a clone if the delegate is cloneable.
+         *
+         * @exception CloneNotSupportedException if this is called on a
+         * delegate that does not support {@code Cloneable}.
+         */
+        public Object clone() throws CloneNotSupportedException {
+            chooseFirstProvider();
+            if (sigSpi instanceof Cloneable) {
+                SignatureSpi sigSpiClone = (SignatureSpi)sigSpi.clone();
+                // Because 'algorithm' and 'provider' are private
+                // members of our supertype, we must perform a cast to
+                // access them.
+                Signature that =
+                    new Delegate(sigSpiClone, ((Signature)this).algorithm);
+                that.provider = ((Signature)this).provider;
+                return that;
+            } else {
+                throw new CloneNotSupportedException();
+            }
+        }
+
+        private static SignatureSpi newInstance(Service s)
+                throws NoSuchAlgorithmException {
+            if (s.getType().equals("Cipher")) {
+                // must be NONEwithRSA
+                try {
+                    Cipher c = Cipher.getInstance(RSA_CIPHER, s.getProvider());
+                    return new CipherAdapter(c);
+                } catch (NoSuchPaddingException e) {
+                    throw new NoSuchAlgorithmException(e);
+                }
+            } else {
+                Object o = s.newInstance(null);
+                if (o instanceof SignatureSpi == false) {
+                    throw new NoSuchAlgorithmException
+                        ("Not a SignatureSpi: " + o.getClass().getName());
+                }
+                return (SignatureSpi)o;
+            }
+        }
+
+        // max number of debug warnings to print from chooseFirstProvider()
+        private static int warnCount = 10;
+
+        /**
+         * Choose the Spi from the first provider available. Used if
+         * delayed provider selection is not possible because initSign()/
+         * initVerify() is not the first method called.
+         */
+        void chooseFirstProvider() {
+            if (sigSpi != null) {
+                return;
+            }
+            synchronized (lock) {
+                if (sigSpi != null) {
+                    return;
+                }
+                // BEGIN Android-removed: this debugging mechanism is not supported in Android.
+                /*
+                if (debug != null) {
+                    int w = --warnCount;
+                    if (w >= 0) {
+                        debug.println("Signature.init() not first method "
+                            + "called, disabling delayed provider selection");
+                        if (w == 0) {
+                            debug.println("Further warnings of this type will "
+                                + "be suppressed");
+                        }
+                        new Exception("Call trace").printStackTrace();
+                    }
+                }
+                */
+                // END Android-removed: this debugging mechanism is not supported in Android.
+                Exception lastException = null;
+// BEGIN Android-changed: Provider selection; loop over a new list each time.
+                List<Service> list;
+                if (((Signature)this).algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
+                    list = GetInstance.getServices(rsaIds);
+                } else {
+                    list = GetInstance.getServices("Signature",
+                            ((Signature)this).algorithm);
+                }
+                for (Service s : list) {
+// END Android-changed: Provider selection; loop over a new list each time.
+                    if (isSpi(s) == false) {
+                        continue;
+                    }
+                    try {
+                        sigSpi = newInstance(s);
+                        provider = s.getProvider();
+                        // Android-removed: Provider selection; loop over a new list each time.
+                        /*
+                        // not needed any more
+                        firstService = null;
+                        serviceIterator = null;
+                        */
+                        return;
+                    } catch (NoSuchAlgorithmException e) {
+                        lastException = e;
+                    }
+                }
+                ProviderException e = new ProviderException
+                        ("Could not construct SignatureSpi instance");
+                if (lastException != null) {
+                    e.initCause(lastException);
+                }
+                throw e;
+            }
+        }
+
+        private void chooseProvider(int type, Key key, SecureRandom random)
+                throws InvalidKeyException {
+            synchronized (lock) {
+                // Android-changed: Use the currently-selected provider only if no key was provided.
+                // if (sigSpi != null) {
+                if (sigSpi != null && key == null) {
+                    init(sigSpi, type, key, random);
+                    return;
+                }
+                Exception lastException = null;
+// BEGIN Android-changed: Provider selection; loop over a new list each time.
+                List<Service> list;
+                if (((Signature)this).algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
+                    list = GetInstance.getServices(rsaIds);
+                } else {
+                    list = GetInstance.getServices("Signature",
+                            ((Signature)this).algorithm);
+                }
+                for (Service s : list) {
+// END Android-changed: Provider selection; loop over a new list each time.
+                    // if provider says it does not support this key, ignore it
+                    if (s.supportsParameter(key) == false) {
+                        continue;
+                    }
+                    // if instance is not a SignatureSpi, ignore it
+                    if (isSpi(s) == false) {
+                        continue;
+                    }
+                    try {
+                        SignatureSpi spi = newInstance(s);
+                        init(spi, type, key, random);
+                        provider = s.getProvider();
+                        sigSpi = spi;
+                        // Android-removed: Provider selection; loop over a new list each time.
+                        /*
+                        firstService = null;
+                        serviceIterator = null;
+                        */
+                        return;
+                    } catch (Exception e) {
+                        // NoSuchAlgorithmException from newInstance()
+                        // InvalidKeyException from init()
+                        // RuntimeException (ProviderException) from init()
+                        if (lastException == null) {
+                            lastException = e;
+                        }
+                        // Android-added: Throw InvalidKeyException immediately.
+                        if (lastException instanceof InvalidKeyException) {
+                          throw (InvalidKeyException)lastException;
+                        }
+                    }
+                }
+                // no working provider found, fail
+                if (lastException instanceof InvalidKeyException) {
+                    throw (InvalidKeyException)lastException;
+                }
+                if (lastException instanceof RuntimeException) {
+                    throw (RuntimeException)lastException;
+                }
+                String k = (key != null) ? key.getClass().getName() : "(null)";
+                throw new InvalidKeyException
+                    ("No installed provider supports this key: "
+                    + k, lastException);
+            }
+        }
+
+        private final static int I_PUB     = 1;
+        private final static int I_PRIV    = 2;
+        private final static int I_PRIV_SR = 3;
+
+        private void init(SignatureSpi spi, int type, Key  key,
+                SecureRandom random) throws InvalidKeyException {
+            switch (type) {
+            case I_PUB:
+                spi.engineInitVerify((PublicKey)key);
+                break;
+            case I_PRIV:
+                spi.engineInitSign((PrivateKey)key);
+                break;
+            case I_PRIV_SR:
+                spi.engineInitSign((PrivateKey)key, random);
+                break;
+            default:
+                throw new AssertionError("Internal error: " + type);
+            }
+        }
+
+        protected void engineInitVerify(PublicKey publicKey)
+                throws InvalidKeyException {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (sigSpi != null) {
+            if (sigSpi != null && (lock == null || publicKey == null)) {
+                sigSpi.engineInitVerify(publicKey);
+            } else {
+                chooseProvider(I_PUB, publicKey, null);
+            }
+        }
+
+        protected void engineInitSign(PrivateKey privateKey)
+                throws InvalidKeyException {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (sigSpi != null) {
+            if (sigSpi != null && (lock == null || privateKey == null)) {
+                sigSpi.engineInitSign(privateKey);
+            } else {
+                chooseProvider(I_PRIV, privateKey, null);
+            }
+        }
+
+        protected void engineInitSign(PrivateKey privateKey, SecureRandom sr)
+                throws InvalidKeyException {
+            // Android-changed: Use the currently-selected provider only if no key was provided.
+            // if (sigSpi != null) {
+            if (sigSpi != null  && (lock == null || privateKey == null)) {
+                sigSpi.engineInitSign(privateKey, sr);
+            } else {
+                chooseProvider(I_PRIV_SR, privateKey, sr);
+            }
+        }
+
+        protected void engineUpdate(byte b) throws SignatureException {
+            chooseFirstProvider();
+            sigSpi.engineUpdate(b);
+        }
+
+        protected void engineUpdate(byte[] b, int off, int len)
+                throws SignatureException {
+            chooseFirstProvider();
+            sigSpi.engineUpdate(b, off, len);
+        }
+
+        protected void engineUpdate(ByteBuffer data) {
+            chooseFirstProvider();
+            sigSpi.engineUpdate(data);
+        }
+
+        protected byte[] engineSign() throws SignatureException {
+            chooseFirstProvider();
+            return sigSpi.engineSign();
+        }
+
+        protected int engineSign(byte[] outbuf, int offset, int len)
+                throws SignatureException {
+            chooseFirstProvider();
+            return sigSpi.engineSign(outbuf, offset, len);
+        }
+
+        protected boolean engineVerify(byte[] sigBytes)
+                throws SignatureException {
+            chooseFirstProvider();
+            return sigSpi.engineVerify(sigBytes);
+        }
+
+        protected boolean engineVerify(byte[] sigBytes, int offset, int length)
+                throws SignatureException {
+            chooseFirstProvider();
+            return sigSpi.engineVerify(sigBytes, offset, length);
+        }
+
+        protected void engineSetParameter(String param, Object value)
+                throws InvalidParameterException {
+            chooseFirstProvider();
+            sigSpi.engineSetParameter(param, value);
+        }
+
+        protected void engineSetParameter(AlgorithmParameterSpec params)
+                throws InvalidAlgorithmParameterException {
+            chooseFirstProvider();
+            sigSpi.engineSetParameter(params);
+        }
+
+        protected Object engineGetParameter(String param)
+                throws InvalidParameterException {
+            chooseFirstProvider();
+            return sigSpi.engineGetParameter(param);
+        }
+
+        protected AlgorithmParameters engineGetParameters() {
+            chooseFirstProvider();
+            return sigSpi.engineGetParameters();
+        }
+
+        // BEGIN Android-added: Allow access to the current SPI for testing purposes.
+        @Override
+        public SignatureSpi getCurrentSpi() {
+            if (lock == null) {
+                return sigSpi;
+            }
+            synchronized (lock) {
+                return sigSpi;
+            }
+        }
+        // END Android-added: Allow access to the current SPI for testing purposes.
+    }
+
+    // adapter for RSA/ECB/PKCS1Padding ciphers
+    @SuppressWarnings("deprecation")
+    private static class CipherAdapter extends SignatureSpi {
+
+        private final Cipher cipher;
+
+        private ByteArrayOutputStream data;
+
+        CipherAdapter(Cipher cipher) {
+            this.cipher = cipher;
+        }
+
+        protected void engineInitVerify(PublicKey publicKey)
+                throws InvalidKeyException {
+            cipher.init(Cipher.DECRYPT_MODE, publicKey);
+            if (data == null) {
+                data = new ByteArrayOutputStream(128);
+            } else {
+                data.reset();
+            }
+        }
+
+        protected void engineInitSign(PrivateKey privateKey)
+                throws InvalidKeyException {
+            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
+            data = null;
+        }
+
+        protected void engineInitSign(PrivateKey privateKey,
+                SecureRandom random) throws InvalidKeyException {
+            cipher.init(Cipher.ENCRYPT_MODE, privateKey, random);
+            data = null;
+        }
+
+        protected void engineUpdate(byte b) throws SignatureException {
+            engineUpdate(new byte[] {b}, 0, 1);
+        }
+
+        protected void engineUpdate(byte[] b, int off, int len)
+                throws SignatureException {
+            if (data != null) {
+                data.write(b, off, len);
+                return;
+            }
+            byte[] out = cipher.update(b, off, len);
+            if ((out != null) && (out.length != 0)) {
+                throw new SignatureException
+                    ("Cipher unexpectedly returned data");
+            }
+        }
+
+        protected byte[] engineSign() throws SignatureException {
+            try {
+                return cipher.doFinal();
+            } catch (IllegalBlockSizeException e) {
+                throw new SignatureException("doFinal() failed", e);
+            } catch (BadPaddingException e) {
+                throw new SignatureException("doFinal() failed", e);
+            }
+        }
+
+        protected boolean engineVerify(byte[] sigBytes)
+                throws SignatureException {
+            try {
+                byte[] out = cipher.doFinal(sigBytes);
+                byte[] dataBytes = data.toByteArray();
+                data.reset();
+                return MessageDigest.isEqual(out, dataBytes);
+            } catch (BadPaddingException e) {
+                // e.g. wrong public key used
+                // return false rather than throwing exception
+                return false;
+            } catch (IllegalBlockSizeException e) {
+                throw new SignatureException("doFinal() failed", e);
+            }
+        }
+
+        protected void engineSetParameter(String param, Object value)
+                throws InvalidParameterException {
+            throw new InvalidParameterException("Parameters not supported");
+        }
+
+        protected Object engineGetParameter(String param)
+                throws InvalidParameterException {
+            throw new InvalidParameterException("Parameters not supported");
+        }
+
+    }
+
+}
diff --git a/java/security/SignatureException.java b/java/security/SignatureException.java
new file mode 100644
index 0000000..2e1fa59
--- /dev/null
+++ b/java/security/SignatureException.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This is the generic Signature exception.
+ *
+ * @author Benjamin Renaud
+ */
+
+public class SignatureException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 7509989324975124438L;
+
+    /**
+     * Constructs a SignatureException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public SignatureException() {
+        super();
+    }
+
+    /**
+     * Constructs a SignatureException with the specified detail
+     * message.  A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public SignatureException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code SignatureException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public SignatureException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code SignatureException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public SignatureException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/SignatureSpi.java b/java/security/SignatureSpi.java
new file mode 100644
index 0000000..86107a1
--- /dev/null
+++ b/java/security/SignatureSpi.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.*;
+import java.io.*;
+
+import java.nio.ByteBuffer;
+
+import sun.security.jca.JCAUtil;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code Signature} class, which is used to provide the
+ * functionality of a digital signature algorithm. Digital signatures are used
+ * for authentication and integrity assurance of digital data.
+ *.
+ * <p> All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a particular signature algorithm.
+ *
+ * @author Benjamin Renaud
+ *
+ *
+ * @see Signature
+ */
+
+public abstract class SignatureSpi {
+
+    /**
+     * Application-specified source of randomness.
+     */
+    protected SecureRandom appRandom = null;
+
+    /**
+     * Initializes this signature object with the specified
+     * public key for verification operations.
+     *
+     * @param publicKey the public key of the identity whose signature is
+     * going to be verified.
+     *
+     * @exception InvalidKeyException if the key is improperly
+     * encoded, parameters are missing, and so on.
+     */
+    protected abstract void engineInitVerify(PublicKey publicKey)
+        throws InvalidKeyException;
+
+    /**
+     * Initializes this signature object with the specified
+     * private key for signing operations.
+     *
+     * @param privateKey the private key of the identity whose signature
+     * will be generated.
+     *
+     * @exception InvalidKeyException if the key is improperly
+     * encoded, parameters are missing, and so on.
+     */
+    protected abstract void engineInitSign(PrivateKey privateKey)
+        throws InvalidKeyException;
+
+    /**
+     * Initializes this signature object with the specified
+     * private key and source of randomness for signing operations.
+     *
+     * <p>This concrete method has been added to this previously-defined
+     * abstract class. (For backwards compatibility, it cannot be abstract.)
+     *
+     * @param privateKey the private key of the identity whose signature
+     * will be generated.
+     * @param random the source of randomness
+     *
+     * @exception InvalidKeyException if the key is improperly
+     * encoded, parameters are missing, and so on.
+     */
+    protected void engineInitSign(PrivateKey privateKey,
+                                  SecureRandom random)
+        throws InvalidKeyException {
+            this.appRandom = random;
+            engineInitSign(privateKey);
+    }
+
+    /**
+     * Updates the data to be signed or verified
+     * using the specified byte.
+     *
+     * @param b the byte to use for the update.
+     *
+     * @exception SignatureException if the engine is not initialized
+     * properly.
+     */
+    protected abstract void engineUpdate(byte b) throws SignatureException;
+
+    /**
+     * Updates the data to be signed or verified, using the
+     * specified array of bytes, starting at the specified offset.
+     *
+     * @param b the array of bytes
+     * @param off the offset to start from in the array of bytes
+     * @param len the number of bytes to use, starting at offset
+     *
+     * @exception SignatureException if the engine is not initialized
+     * properly
+     */
+    protected abstract void engineUpdate(byte[] b, int off, int len)
+        throws SignatureException;
+
+    /**
+     * Updates the data to be signed or verified using the specified
+     * ByteBuffer. Processes the {@code data.remaining()} bytes
+     * starting at at {@code data.position()}.
+     * Upon return, the buffer's position will be equal to its limit;
+     * its limit will not have changed.
+     *
+     * @param input the ByteBuffer
+     * @since 1.5
+     */
+    protected void engineUpdate(ByteBuffer input) {
+        if (input.hasRemaining() == false) {
+            return;
+        }
+        try {
+            if (input.hasArray()) {
+                byte[] b = input.array();
+                int ofs = input.arrayOffset();
+                int pos = input.position();
+                int lim = input.limit();
+                engineUpdate(b, ofs + pos, lim - pos);
+                input.position(lim);
+            } else {
+                int len = input.remaining();
+                byte[] b = new byte[JCAUtil.getTempArraySize(len)];
+                while (len > 0) {
+                    int chunk = Math.min(len, b.length);
+                    input.get(b, 0, chunk);
+                    engineUpdate(b, 0, chunk);
+                    len -= chunk;
+                }
+            }
+        } catch (SignatureException e) {
+            // is specified to only occur when the engine is not initialized
+            // this case should never occur as it is caught in Signature.java
+            throw new ProviderException("update() failed", e);
+        }
+    }
+
+    /**
+     * Returns the signature bytes of all the data
+     * updated so far.
+     * The format of the signature depends on the underlying
+     * signature scheme.
+     *
+     * @return the signature bytes of the signing operation's result.
+     *
+     * @exception SignatureException if the engine is not
+     * initialized properly or if this signature algorithm is unable to
+     * process the input data provided.
+     */
+    protected abstract byte[] engineSign() throws SignatureException;
+
+    /**
+     * Finishes this signature operation and stores the resulting signature
+     * bytes in the provided buffer {@code outbuf}, starting at
+     * {@code offset}.
+     * The format of the signature depends on the underlying
+     * signature scheme.
+     *
+     * <p>The signature implementation is reset to its initial state
+     * (the state it was in after a call to one of the
+     * {@code engineInitSign} methods)
+     * and can be reused to generate further signatures with the same private
+     * key.
+     *
+     * This method should be abstract, but we leave it concrete for
+     * binary compatibility.  Knowledgeable providers should override this
+     * method.
+     *
+     * @param outbuf buffer for the signature result.
+     *
+     * @param offset offset into {@code outbuf} where the signature is
+     * stored.
+     *
+     * @param len number of bytes within {@code outbuf} allotted for the
+     * signature.
+     * Both this default implementation and the SUN provider do not
+     * return partial digests. If the value of this parameter is less
+     * than the actual signature length, this method will throw a
+     * SignatureException.
+     * This parameter is ignored if its value is greater than or equal to
+     * the actual signature length.
+     *
+     * @return the number of bytes placed into {@code outbuf}
+     *
+     * @exception SignatureException if the engine is not
+     * initialized properly, if this signature algorithm is unable to
+     * process the input data provided, or if {@code len} is less
+     * than the actual signature length.
+     *
+     * @since 1.2
+     */
+    protected int engineSign(byte[] outbuf, int offset, int len)
+                        throws SignatureException {
+        byte[] sig = engineSign();
+        if (len < sig.length) {
+                throw new SignatureException
+                    ("partial signatures not returned");
+        }
+        if (outbuf.length - offset < sig.length) {
+                throw new SignatureException
+                    ("insufficient space in the output buffer to store the "
+                     + "signature");
+        }
+        System.arraycopy(sig, 0, outbuf, offset, sig.length);
+        return sig.length;
+    }
+
+    /**
+     * Verifies the passed-in signature.
+     *
+     * @param sigBytes the signature bytes to be verified.
+     *
+     * @return true if the signature was verified, false if not.
+     *
+     * @exception SignatureException if the engine is not
+     * initialized properly, the passed-in signature is improperly
+     * encoded or of the wrong type, if this signature algorithm is unable to
+     * process the input data provided, etc.
+     */
+    protected abstract boolean engineVerify(byte[] sigBytes)
+        throws SignatureException;
+
+    /**
+     * Verifies the passed-in signature in the specified array
+     * of bytes, starting at the specified offset.
+     *
+     * <p> Note: Subclasses should overwrite the default implementation.
+     *
+     *
+     * @param sigBytes the signature bytes to be verified.
+     * @param offset the offset to start from in the array of bytes.
+     * @param length the number of bytes to use, starting at offset.
+     *
+     * @return true if the signature was verified, false if not.
+     *
+     * @exception SignatureException if the engine is not
+     * initialized properly, the passed-in signature is improperly
+     * encoded or of the wrong type, if this signature algorithm is unable to
+     * process the input data provided, etc.
+     * @since 1.4
+     */
+    protected boolean engineVerify(byte[] sigBytes, int offset, int length)
+        throws SignatureException {
+        byte[] sigBytesCopy = new byte[length];
+        System.arraycopy(sigBytes, offset, sigBytesCopy, 0, length);
+        return engineVerify(sigBytesCopy);
+    }
+
+    /**
+     * Sets the specified algorithm parameter to the specified
+     * value. This method supplies a general-purpose mechanism through
+     * which it is possible to set the various parameters of this object.
+     * A parameter may be any settable parameter for the algorithm, such as
+     * a parameter size, or a source of random bits for signature generation
+     * (if appropriate), or an indication of whether or not to perform
+     * a specific but optional computation. A uniform algorithm-specific
+     * naming scheme for each parameter is desirable but left unspecified
+     * at this time.
+     *
+     * @param param the string identifier of the parameter.
+     *
+     * @param value the parameter value.
+     *
+     * @exception InvalidParameterException if {@code param} is an
+     * invalid parameter for this signature algorithm engine,
+     * the parameter is already set
+     * and cannot be set again, a security exception occurs, and so on.
+     *
+     * @deprecated Replaced by {@link
+     * #engineSetParameter(java.security.spec.AlgorithmParameterSpec)
+     * engineSetParameter}.
+     */
+    @Deprecated
+    protected abstract void engineSetParameter(String param, Object value)
+        throws InvalidParameterException;
+
+    /**
+     * <p>This method is overridden by providers to initialize
+     * this signature engine with the specified parameter set.
+     *
+     * @param params the parameters
+     *
+     * @exception UnsupportedOperationException if this method is not
+     * overridden by a provider
+     *
+     * @exception InvalidAlgorithmParameterException if this method is
+     * overridden by a provider and the given parameters
+     * are inappropriate for this signature engine
+     */
+    protected void engineSetParameter(AlgorithmParameterSpec params)
+        throws InvalidAlgorithmParameterException {
+            throw new UnsupportedOperationException();
+    }
+
+    /**
+     * <p>This method is overridden by providers to return the
+     * parameters used with this signature engine, or null
+     * if this signature engine does not use any parameters.
+     *
+     * <p>The returned parameters may be the same that were used to initialize
+     * this signature engine, or may contain a combination of default and
+     * randomly generated parameter values used by the underlying signature
+     * implementation if this signature engine requires algorithm parameters
+     * but was not initialized with any.
+     *
+     * @return the parameters used with this signature engine, or null if this
+     * signature engine does not use any parameters
+     *
+     * @exception UnsupportedOperationException if this method is
+     * not overridden by a provider
+     * @since 1.4
+     */
+    protected AlgorithmParameters engineGetParameters() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Gets the value of the specified algorithm parameter.
+     * This method supplies a general-purpose mechanism through which it
+     * is possible to get the various parameters of this object. A parameter
+     * may be any settable parameter for the algorithm, such as a parameter
+     * size, or  a source of random bits for signature generation (if
+     * appropriate), or an indication of whether or not to perform a
+     * specific but optional computation. A uniform algorithm-specific
+     * naming scheme for each parameter is desirable but left unspecified
+     * at this time.
+     *
+     * @param param the string name of the parameter.
+     *
+     * @return the object that represents the parameter value, or null if
+     * there is none.
+     *
+     * @exception InvalidParameterException if {@code param} is an
+     * invalid parameter for this engine, or another exception occurs while
+     * trying to get this parameter.
+     *
+     * @deprecated Deprecated.
+     */
+    @Deprecated
+    // Android-changed add "Deprecated."
+    protected abstract Object engineGetParameter(String param)
+        throws InvalidParameterException;
+
+    /**
+     * Returns a clone if the implementation is cloneable.
+     *
+     * @return a clone if the implementation is cloneable.
+     *
+     * @exception CloneNotSupportedException if this is called
+     * on an implementation that does not support {@code Cloneable}.
+     */
+    public Object clone() throws CloneNotSupportedException {
+        if (this instanceof Cloneable) {
+            return super.clone();
+        } else {
+            throw new CloneNotSupportedException();
+        }
+    }
+}
diff --git a/java/security/SignedObject.java b/java/security/SignedObject.java
new file mode 100644
index 0000000..9ac864e
--- /dev/null
+++ b/java/security/SignedObject.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+
+/**
+ * <p> SignedObject is a class for the purpose of creating authentic
+ * runtime objects whose integrity cannot be compromised without being
+ * detected.
+ *
+ * <p> More specifically, a SignedObject contains another Serializable
+ * object, the (to-be-)signed object and its signature.
+ *
+ * <p> The signed object is a "deep copy" (in serialized form) of an
+ * original object.  Once the copy is made, further manipulation of
+ * the original object has no side effect on the copy.
+ *
+ * <p> The underlying signing algorithm is designated by the Signature
+ * object passed to the constructor and the {@code verify} method.
+ * A typical usage for signing is the following:
+ *
+ * <pre>{@code
+ * Signature signingEngine = Signature.getInstance(algorithm,
+ *                                                 provider);
+ * SignedObject so = new SignedObject(myobject, signingKey,
+ *                                    signingEngine);
+ * }</pre>
+ *
+ * <p> A typical usage for verification is the following (having
+ * received SignedObject {@code so}):
+ *
+ * <pre>{@code
+ * Signature verificationEngine =
+ *     Signature.getInstance(algorithm, provider);
+ * if (so.verify(publickey, verificationEngine))
+ *     try {
+ *         Object myobj = so.getObject();
+ *     } catch (java.lang.ClassNotFoundException e) {};
+ * }</pre>
+ *
+ * <p> Several points are worth noting.  First, there is no need to
+ * initialize the signing or verification engine, as it will be
+ * re-initialized inside the constructor and the {@code verify}
+ * method. Secondly, for verification to succeed, the specified
+ * public key must be the public key corresponding to the private key
+ * used to generate the SignedObject.
+ *
+ * <p> More importantly, for flexibility reasons, the
+ * constructor and {@code verify} method allow for
+ * customized signature engines, which can implement signature
+ * algorithms that are not installed formally as part of a crypto
+ * provider.  However, it is crucial that the programmer writing the
+ * verifier code be aware what {@code Signature} engine is being
+ * used, as its own implementation of the {@code verify} method
+ * is invoked to verify a signature.  In other words, a malicious
+ * {@code Signature} may choose to always return true on
+ * verification in an attempt to bypass a security check.
+ *
+ * <p> The signature algorithm can be, among others, the NIST standard
+ * DSA, using DSA and SHA-1.  The algorithm is specified using the
+ * same convention as that for signatures. The DSA algorithm using the
+ * SHA-1 message digest algorithm can be specified, for example, as
+ * "SHA/DSA" or "SHA-1/DSA" (they are equivalent).  In the case of
+ * RSA, there are multiple choices for the message digest algorithm,
+ * so the signing algorithm could be specified as, for example,
+ * "MD2/RSA", "MD5/RSA" or "SHA-1/RSA".  The algorithm name must be
+ * specified, as there is no default.
+ *
+ * <p> The name of the Cryptography Package Provider is designated
+ * also by the Signature parameter to the constructor and the
+ * {@code verify} method.  If the provider is not
+ * specified, the default provider is used.  Each installation can
+ * be configured to use a particular provider as default.
+ *
+ * <p> Potential applications of SignedObject include:
+ * <ul>
+ * <li> It can be used
+ * internally to any Java runtime as an unforgeable authorization
+ * token -- one that can be passed around without the fear that the
+ * token can be maliciously modified without being detected.
+ * <li> It
+ * can be used to sign and serialize data/object for storage outside
+ * the Java runtime (e.g., storing critical access control data on
+ * disk).
+ * <li> Nested SignedObjects can be used to construct a logical
+ * sequence of signatures, resembling a chain of authorization and
+ * delegation.
+ * </ul>
+ *
+ * @see Signature
+ *
+ * @author Li Gong
+ */
+
+public final class SignedObject implements Serializable {
+
+    private static final long serialVersionUID = 720502720485447167L;
+
+    /*
+     * The original content is "deep copied" in its serialized format
+     * and stored in a byte array.  The signature field is also in the
+     * form of byte array.
+     */
+
+    private byte[] content;
+    private byte[] signature;
+    private String thealgorithm;
+
+    /**
+     * Constructs a SignedObject from any Serializable object.
+     * The given object is signed with the given signing key, using the
+     * designated signature engine.
+     *
+     * @param object the object to be signed.
+     * @param signingKey the private key for signing.
+     * @param signingEngine the signature signing engine.
+     *
+     * @exception IOException if an error occurs during serialization
+     * @exception InvalidKeyException if the key is invalid.
+     * @exception SignatureException if signing fails.
+     */
+    public SignedObject(Serializable object, PrivateKey signingKey,
+                        Signature signingEngine)
+        throws IOException, InvalidKeyException, SignatureException {
+            // creating a stream pipe-line, from a to b
+            ByteArrayOutputStream b = new ByteArrayOutputStream();
+            ObjectOutput a = new ObjectOutputStream(b);
+
+            // write and flush the object content to byte array
+            a.writeObject(object);
+            a.flush();
+            a.close();
+            this.content = b.toByteArray();
+            b.close();
+
+            // now sign the encapsulated object
+            this.sign(signingKey, signingEngine);
+    }
+
+    /**
+     * Retrieves the encapsulated object.
+     * The encapsulated object is de-serialized before it is returned.
+     *
+     * @return the encapsulated object.
+     *
+     * @exception IOException if an error occurs during de-serialization
+     * @exception ClassNotFoundException if an error occurs during
+     * de-serialization
+     */
+    public Object getObject()
+        throws IOException, ClassNotFoundException
+    {
+        // creating a stream pipe-line, from b to a
+        ByteArrayInputStream b = new ByteArrayInputStream(this.content);
+        ObjectInput a = new ObjectInputStream(b);
+        Object obj = a.readObject();
+        b.close();
+        a.close();
+        return obj;
+    }
+
+    /**
+     * Retrieves the signature on the signed object, in the form of a
+     * byte array.
+     *
+     * @return the signature. Returns a new array each time this
+     * method is called.
+     */
+    public byte[] getSignature() {
+        return this.signature.clone();
+    }
+
+    /**
+     * Retrieves the name of the signature algorithm.
+     *
+     * @return the signature algorithm name.
+     */
+    public String getAlgorithm() {
+        return this.thealgorithm;
+    }
+
+    /**
+     * Verifies that the signature in this SignedObject is the valid
+     * signature for the object stored inside, with the given
+     * verification key, using the designated verification engine.
+     *
+     * @param verificationKey the public key for verification.
+     * @param verificationEngine the signature verification engine.
+     *
+     * @exception SignatureException if signature verification failed.
+     * @exception InvalidKeyException if the verification key is invalid.
+     *
+     * @return {@code true} if the signature
+     * is valid, {@code false} otherwise
+     */
+    public boolean verify(PublicKey verificationKey,
+                          Signature verificationEngine)
+         throws InvalidKeyException, SignatureException {
+             verificationEngine.initVerify(verificationKey);
+             verificationEngine.update(this.content.clone());
+             return verificationEngine.verify(this.signature.clone());
+    }
+
+    /*
+     * Signs the encapsulated object with the given signing key, using the
+     * designated signature engine.
+     *
+     * @param signingKey the private key for signing.
+     * @param signingEngine the signature signing engine.
+     *
+     * @exception InvalidKeyException if the key is invalid.
+     * @exception SignatureException if signing fails.
+     */
+    private void sign(PrivateKey signingKey, Signature signingEngine)
+        throws InvalidKeyException, SignatureException {
+            // initialize the signing engine
+            signingEngine.initSign(signingKey);
+            signingEngine.update(this.content.clone());
+            this.signature = signingEngine.sign().clone();
+            this.thealgorithm = signingEngine.getAlgorithm();
+    }
+
+    /**
+     * readObject is called to restore the state of the SignedObject from
+     * a stream.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+            java.io.ObjectInputStream.GetField fields = s.readFields();
+            content = ((byte[])fields.get("content", null)).clone();
+            signature = ((byte[])fields.get("signature", null)).clone();
+            thealgorithm = (String)fields.get("thealgorithm", null);
+    }
+}
diff --git a/java/security/Signer.java b/java/security/Signer.java
new file mode 100644
index 0000000..077538d
--- /dev/null
+++ b/java/security/Signer.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+
+/**
+ * This class is used to represent an Identity that can also digitally
+ * sign data.
+ *
+ * <p>The management of a signer's private keys is an important and
+ * sensitive issue that should be handled by subclasses as appropriate
+ * to their intended use.
+ *
+ * @see Identity
+ *
+ * @author Benjamin Renaud
+ *
+ * @deprecated This class is no longer used. Its functionality has been
+ * replaced by {@code java.security.KeyStore}, the
+ * {@code java.security.cert} package, and
+ * {@code java.security.Principal}.
+ */
+@Deprecated
+public abstract class Signer extends Identity {
+
+    private static final long serialVersionUID = -1763464102261361480L;
+
+    /**
+     * The signer's private key.
+     *
+     * @serial
+     */
+    private PrivateKey privateKey;
+
+    /**
+     * Creates a signer. This constructor should only be used for
+     * serialization.
+     */
+    protected Signer() {
+        super();
+    }
+
+
+    /**
+     * Creates a signer with the specified identity name.
+     *
+     * @param name the identity name.
+     */
+    public Signer(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates a signer with the specified identity name and scope.
+     *
+     * @param name the identity name.
+     *
+     * @param scope the scope of the identity.
+     *
+     * @exception KeyManagementException if there is already an identity
+     * with the same name in the scope.
+     */
+    public Signer(String name, IdentityScope scope)
+    throws KeyManagementException {
+        super(name, scope);
+    }
+
+    /**
+     * Returns this signer's private key.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "getSignerPrivateKey"}
+     * as its argument to see if it's ok to return the private key.
+     *
+     * @return this signer's private key, or null if the private key has
+     * not yet been set.
+     *
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * returning the private key.
+     *
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public PrivateKey getPrivateKey() {
+        check("getSignerPrivateKey");
+        return privateKey;
+    }
+
+   /**
+     * Sets the key pair (public key and private key) for this signer.
+     *
+     * <p>First, if there is a security manager, its {@code checkSecurityAccess}
+     * method is called with {@code "setSignerKeyPair"}
+     * as its argument to see if it's ok to set the key pair.
+     *
+     * @param pair an initialized key pair.
+     *
+     * @exception InvalidParameterException if the key pair is not
+     * properly initialized.
+     * @exception KeyException if the key pair cannot be set for any
+     * other reason.
+     * @exception  SecurityException  if a security manager exists and its
+     * {@code checkSecurityAccess} method doesn't allow
+     * setting the key pair.
+     *
+     * @see SecurityManager#checkSecurityAccess
+     */
+    public final void setKeyPair(KeyPair pair)
+    throws InvalidParameterException, KeyException {
+        check("setSignerKeyPair");
+        final PublicKey pub = pair.getPublic();
+        PrivateKey priv = pair.getPrivate();
+
+        if (pub == null || priv == null) {
+            throw new InvalidParameterException();
+        }
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws KeyManagementException {
+                    setPublicKey(pub);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException pae) {
+            throw (KeyManagementException) pae.getException();
+        }
+        privateKey = priv;
+    }
+
+    String printKeys() {
+        String keys = "";
+        PublicKey publicKey = getPublicKey();
+        if (publicKey != null && privateKey != null) {
+            keys = "\tpublic and private keys initialized";
+
+        } else {
+            keys = "\tno keys";
+        }
+        return keys;
+    }
+
+    /**
+     * Returns a string of information about the signer.
+     *
+     * @return a string of information about the signer.
+     */
+    public String toString() {
+        return "[Signer]" + super.toString();
+    }
+
+    private static void check(String directive) {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkSecurityAccess(directive);
+        }
+    }
+
+}
diff --git a/java/security/Timestamp.java b/java/security/Timestamp.java
new file mode 100644
index 0000000..f66d288
--- /dev/null
+++ b/java/security/Timestamp.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.*;
+import java.security.cert.Certificate;
+import java.security.cert.CertPath;
+import java.security.cert.X509Extension;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * This class encapsulates information about a signed timestamp.
+ * It is immutable.
+ * It includes the timestamp's date and time as well as information about the
+ * Timestamping Authority (TSA) which generated and signed the timestamp.
+ *
+ * @since 1.5
+ * @author Vincent Ryan
+ */
+
+public final class Timestamp implements Serializable {
+
+    private static final long serialVersionUID = -5502683707821851294L;
+
+    /**
+     * The timestamp's date and time
+     *
+     * @serial
+     */
+    private Date timestamp;
+
+    /**
+     * The TSA's certificate path.
+     *
+     * @serial
+     */
+    private CertPath signerCertPath;
+
+    /*
+     * Hash code for this timestamp.
+     */
+    private transient int myhash = -1;
+
+    /**
+     * Constructs a Timestamp.
+     *
+     * @param timestamp is the timestamp's date and time. It must not be null.
+     * @param signerCertPath is the TSA's certificate path. It must not be null.
+     * @throws NullPointerException if timestamp or signerCertPath is null.
+     */
+    public Timestamp(Date timestamp, CertPath signerCertPath) {
+        if (timestamp == null || signerCertPath == null) {
+            throw new NullPointerException();
+        }
+        this.timestamp = new Date(timestamp.getTime()); // clone
+        this.signerCertPath = signerCertPath;
+    }
+
+    /**
+     * Returns the date and time when the timestamp was generated.
+     *
+     * @return The timestamp's date and time.
+     */
+    public Date getTimestamp() {
+        return new Date(timestamp.getTime()); // clone
+    }
+
+    /**
+     * Returns the certificate path for the Timestamping Authority.
+     *
+     * @return The TSA's certificate path.
+     */
+    public CertPath getSignerCertPath() {
+        return signerCertPath;
+    }
+
+    /**
+     * Returns the hash code value for this timestamp.
+     * The hash code is generated using the date and time of the timestamp
+     * and the TSA's certificate path.
+     *
+     * @return a hash code value for this timestamp.
+     */
+    public int hashCode() {
+        if (myhash == -1) {
+            myhash = timestamp.hashCode() + signerCertPath.hashCode();
+        }
+        return myhash;
+    }
+
+    /**
+     * Tests for equality between the specified object and this
+     * timestamp. Two timestamps are considered equal if the date and time of
+     * their timestamp's and their signer's certificate paths are equal.
+     *
+     * @param obj the object to test for equality with this timestamp.
+     *
+     * @return true if the timestamp are considered equal, false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj == null || (!(obj instanceof Timestamp))) {
+            return false;
+        }
+        Timestamp that = (Timestamp)obj;
+
+        if (this == that) {
+            return true;
+        }
+        return (timestamp.equals(that.getTimestamp()) &&
+            signerCertPath.equals(that.getSignerCertPath()));
+    }
+
+    /**
+     * Returns a string describing this timestamp.
+     *
+     * @return A string comprising the date and time of the timestamp and
+     *         its signer's certificate.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("(");
+        sb.append("timestamp: " + timestamp);
+        List<? extends Certificate> certs = signerCertPath.getCertificates();
+        if (!certs.isEmpty()) {
+            sb.append("TSA: " + certs.get(0));
+        } else {
+            sb.append("TSA: <empty>");
+        }
+        sb.append(")");
+        return sb.toString();
+    }
+
+    // Explicitly reset hash code value to -1
+    private void readObject(ObjectInputStream ois)
+        throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        myhash = -1;
+        timestamp = new Date(timestamp.getTime());
+    }
+}
diff --git a/java/security/UnrecoverableEntryException.java b/java/security/UnrecoverableEntryException.java
new file mode 100644
index 0000000..0314e3d
--- /dev/null
+++ b/java/security/UnrecoverableEntryException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This exception is thrown if an entry in the keystore cannot be recovered.
+ *
+ *
+ * @since 1.5
+ */
+
+public class UnrecoverableEntryException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -4527142945246286535L;
+
+    /**
+     * Constructs an UnrecoverableEntryException with no detail message.
+     */
+    public UnrecoverableEntryException() {
+        super();
+    }
+
+    /**
+     * Constructs an UnrecoverableEntryException with the specified detail
+     * message, which provides more information about why this exception
+     * has been thrown.
+     *
+     * @param msg the detail message.
+     */
+   public UnrecoverableEntryException(String msg) {
+       super(msg);
+    }
+}
diff --git a/java/security/UnrecoverableKeyException.java b/java/security/UnrecoverableKeyException.java
new file mode 100644
index 0000000..09fcc6e
--- /dev/null
+++ b/java/security/UnrecoverableKeyException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+/**
+ * This exception is thrown if a key in the keystore cannot be recovered.
+ *
+ *
+ * @since 1.2
+ */
+
+public class UnrecoverableKeyException extends UnrecoverableEntryException {
+
+    private static final long serialVersionUID = 7275063078190151277L;
+
+    /**
+     * Constructs an UnrecoverableKeyException with no detail message.
+     */
+    public UnrecoverableKeyException() {
+        super();
+    }
+
+    /**
+     * Constructs an UnrecoverableKeyException with the specified detail
+     * message, which provides more information about why this exception
+     * has been thrown.
+     *
+     * @param msg the detail message.
+     */
+   public UnrecoverableKeyException(String msg) {
+       super(msg);
+    }
+}
diff --git a/java/security/UnresolvedPermission.java b/java/security/UnresolvedPermission.java
new file mode 100644
index 0000000..6f3bf4a
--- /dev/null
+++ b/java/security/UnresolvedPermission.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.io.IOException;
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.lang.reflect.*;
+import java.security.cert.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class UnresolvedPermission extends Permission
+implements java.io.Serializable
+{
+
+    public UnresolvedPermission(String type,
+                                String name,
+                                String actions,
+                                java.security.cert.Certificate certs[]) { super(""); }
+
+    public boolean implies(Permission p) { return false; }
+
+    public String getActions() { return null; }
+
+    public String getUnresolvedType() { return null; }
+
+    public String getUnresolvedName() { return null; }
+
+    public String getUnresolvedActions() { return null; }
+
+    public java.security.cert.Certificate[] getUnresolvedCerts() { return null; }
+}
diff --git a/java/security/UnresolvedPermissionCollection.java b/java/security/UnresolvedPermissionCollection.java
new file mode 100644
index 0000000..7633648
--- /dev/null
+++ b/java/security/UnresolvedPermissionCollection.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.*;
+import java.io.ObjectStreamField;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+
+/**
+ * A UnresolvedPermissionCollection stores a collection
+ * of UnresolvedPermission permissions.
+ *
+ * @see java.security.Permission
+ * @see java.security.Permissions
+ * @see java.security.UnresolvedPermission
+ *
+ *
+ * @author Roland Schemers
+ *
+ * @serial include
+ */
+
+final class UnresolvedPermissionCollection
+extends PermissionCollection
+implements java.io.Serializable
+{
+    /**
+     * Key is permission type, value is a list of the UnresolvedPermissions
+     * of the same type.
+     * Not serialized; see serialization section at end of class.
+     */
+    private transient Map<String, List<UnresolvedPermission>> perms;
+
+    /**
+     * Create an empty UnresolvedPermissionCollection object.
+     *
+     */
+    public UnresolvedPermissionCollection() {
+        perms = new HashMap<String, List<UnresolvedPermission>>(11);
+    }
+
+    /**
+     * Adds a permission to this UnresolvedPermissionCollection.
+     * The key for the hash is the unresolved permission's type (class) name.
+     *
+     * @param permission the Permission object to add.
+     */
+
+    public void add(Permission permission)
+    {
+        if (! (permission instanceof UnresolvedPermission))
+            throw new IllegalArgumentException("invalid permission: "+
+                                               permission);
+        UnresolvedPermission up = (UnresolvedPermission) permission;
+
+        List<UnresolvedPermission> v;
+        synchronized (this) {
+            v = perms.get(up.getName());
+            if (v == null) {
+                v = new ArrayList<UnresolvedPermission>();
+                perms.put(up.getName(), v);
+            }
+        }
+        synchronized (v) {
+            v.add(up);
+        }
+    }
+
+    /**
+     * get any unresolved permissions of the same type as p,
+     * and return the List containing them.
+     */
+    List<UnresolvedPermission> getUnresolvedPermissions(Permission p) {
+        synchronized (this) {
+            return perms.get(p.getClass().getName());
+        }
+    }
+
+    /**
+     * always returns false for unresolved permissions
+     *
+     */
+    public boolean implies(Permission permission)
+    {
+        return false;
+    }
+
+    /**
+     * Returns an enumeration of all the UnresolvedPermission lists in the
+     * container.
+     *
+     * @return an enumeration of all the UnresolvedPermission objects.
+     */
+
+    public Enumeration<Permission> elements() {
+        List<Permission> results =
+            new ArrayList<>(); // where results are stored
+
+        // Get iterator of Map values (which are lists of permissions)
+        synchronized (this) {
+            for (List<UnresolvedPermission> l : perms.values()) {
+                synchronized (l) {
+                    results.addAll(l);
+                }
+            }
+        }
+
+        return Collections.enumeration(results);
+    }
+
+    private static final long serialVersionUID = -7176153071733132400L;
+
+    // Need to maintain serialization interoperability with earlier releases,
+    // which had the serializable field:
+    // private Hashtable permissions; // keyed on type
+
+    /**
+     * @serialField permissions java.util.Hashtable
+     *     A table of the UnresolvedPermissions keyed on type, value is Vector
+     *     of permissions
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("permissions", Hashtable.class),
+    };
+
+    /**
+     * @serialData Default field.
+     */
+    /*
+     * Writes the contents of the perms field out as a Hashtable
+     * in which the values are Vectors for
+     * serialization compatibility with earlier releases.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        // Don't call out.defaultWriteObject()
+
+        // Copy perms into a Hashtable
+        Hashtable<String, Vector<UnresolvedPermission>> permissions =
+            new Hashtable<>(perms.size()*2);
+
+        // Convert each entry (List) into a Vector
+        synchronized (this) {
+            Set<Map.Entry<String, List<UnresolvedPermission>>> set = perms.entrySet();
+            for (Map.Entry<String, List<UnresolvedPermission>> e : set) {
+                // Convert list into Vector
+                List<UnresolvedPermission> list = e.getValue();
+                Vector<UnresolvedPermission> vec = new Vector<>(list.size());
+                synchronized (list) {
+                    vec.addAll(list);
+                }
+
+                // Add to Hashtable being serialized
+                permissions.put(e.getKey(), vec);
+            }
+        }
+
+        // Write out serializable fields
+        ObjectOutputStream.PutField pfields = out.putFields();
+        pfields.put("permissions", permissions);
+        out.writeFields();
+    }
+
+    /*
+     * Reads in a Hashtable in which the values are Vectors of
+     * UnresolvedPermissions and saves them in the perms field.
+     */
+    private void readObject(ObjectInputStream in) throws IOException,
+    ClassNotFoundException {
+        // Don't call defaultReadObject()
+
+        // Read in serialized fields
+        ObjectInputStream.GetField gfields = in.readFields();
+
+        // Get permissions
+        @SuppressWarnings("unchecked")
+        // writeObject writes a Hashtable<String, Vector<UnresolvedPermission>>
+        // for the permissions key, so this cast is safe, unless the data is corrupt.
+        Hashtable<String, Vector<UnresolvedPermission>> permissions =
+                (Hashtable<String, Vector<UnresolvedPermission>>)
+                gfields.get("permissions", null);
+        perms = new HashMap<String, List<UnresolvedPermission>>(permissions.size()*2);
+
+        // Convert each entry (Vector) into a List
+        Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
+        for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
+            // Convert Vector into ArrayList
+            Vector<UnresolvedPermission> vec = e.getValue();
+            List<UnresolvedPermission> list = new ArrayList<>(vec.size());
+            list.addAll(vec);
+
+            // Add to Hashtable being serialized
+            perms.put(e.getKey(), list);
+        }
+    }
+}
diff --git a/java/security/acl/Acl.java b/java/security/acl/Acl.java
new file mode 100644
index 0000000..b9cf004
--- /dev/null
+++ b/java/security/acl/Acl.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+import java.util.Enumeration;
+import java.security.Principal;
+
+/**
+ * Interface representing an Access Control List (ACL).  An Access
+ * Control List is a data structure used to guard access to
+ * resources.<p>
+ *
+ * An ACL can be thought of as a data structure with multiple ACL
+ * entries.  Each ACL entry, of interface type AclEntry, contains a
+ * set of permissions associated with a particular principal. (A
+ * principal represents an entity such as an individual user or a
+ * group). Additionally, each ACL entry is specified as being either
+ * positive or negative. If positive, the permissions are to be
+ * granted to the associated principal. If negative, the permissions
+ * are to be denied.<p>
+ *
+ * The ACL Entries in each ACL observe the following rules:
+ *
+ * <ul> <li>Each principal can have at most one positive ACL entry and
+ * one negative entry; that is, multiple positive or negative ACL
+ * entries are not allowed for any principal.  Each entry specifies
+ * the set of permissions that are to be granted (if positive) or
+ * denied (if negative).
+ *
+ * <li>If there is no entry for a particular principal, then the
+ * principal is considered to have a null (empty) permission set.
+ *
+ * <li>If there is a positive entry that grants a principal a
+ * particular permission, and a negative entry that denies the
+ * principal the same permission, the result is as though the
+ * permission was never granted or denied.
+ *
+ * <li>Individual permissions always override permissions of the
+ * group(s) to which the individual belongs. That is, individual
+ * negative permissions (specific denial of permissions) override the
+ * groups' positive permissions. And individual positive permissions
+ * override the groups' negative permissions.
+ *
+ * </ul>
+ *
+ * The {@code  java.security.acl } package provides the
+ * interfaces to the ACL and related data structures (ACL entries,
+ * groups, permissions, etc.), and the {@code  sun.security.acl }
+ * classes provide a default implementation of the interfaces. For
+ * example, {@code  java.security.acl.Acl } provides the
+ * interface to an ACL and the {@code  sun.security.acl.AclImpl }
+ * class provides the default implementation of the interface.<p>
+ *
+ * The {@code  java.security.acl.Acl } interface extends the
+ * {@code  java.security.acl.Owner } interface. The Owner
+ * interface is used to maintain a list of owners for each ACL.  Only
+ * owners are allowed to modify an ACL. For example, only an owner can
+ * call the ACL's {@code addEntry} method to add a new ACL entry
+ * to the ACL.
+ *
+ * @see java.security.acl.AclEntry
+ * @see java.security.acl.Owner
+ * @see java.security.acl.Acl#getPermissions
+ *
+ * @author Satish Dharmaraj
+ */
+
+public interface Acl extends Owner {
+
+    /**
+     * Sets the name of this ACL.
+     *
+     * @param caller the principal invoking this method. It must be an
+     * owner of this ACL.
+     *
+     * @param name the name to be given to this ACL.
+     *
+     * @exception NotOwnerException if the caller principal
+     * is not an owner of this ACL.
+     *
+     * @see #getName
+     */
+    public void setName(Principal caller, String name)
+      throws NotOwnerException;
+
+    /**
+     * Returns the name of this ACL.
+     *
+     * @return the name of this ACL.
+     *
+     * @see #setName
+     */
+    public String getName();
+
+    /**
+     * Adds an ACL entry to this ACL. An entry associates a principal
+     * (e.g., an individual or a group) with a set of
+     * permissions. Each principal can have at most one positive ACL
+     * entry (specifying permissions to be granted to the principal)
+     * and one negative ACL entry (specifying permissions to be
+     * denied). If there is already an ACL entry of the same type
+     * (negative or positive) already in the ACL, false is returned.
+     *
+     * @param caller the principal invoking this method. It must be an
+     * owner of this ACL.
+     *
+     * @param entry the ACL entry to be added to this ACL.
+     *
+     * @return true on success, false if an entry of the same type
+     * (positive or negative) for the same principal is already
+     * present in this ACL.
+     *
+     * @exception NotOwnerException if the caller principal
+     *  is not an owner of this ACL.
+     */
+    public boolean addEntry(Principal caller, AclEntry entry)
+      throws NotOwnerException;
+
+    /**
+     * Removes an ACL entry from this ACL.
+     *
+     * @param caller the principal invoking this method. It must be an
+     * owner of this ACL.
+     *
+     * @param entry the ACL entry to be removed from this ACL.
+     *
+     * @return true on success, false if the entry is not part of this ACL.
+     *
+     * @exception NotOwnerException if the caller principal is not
+     * an owner of this Acl.
+     */
+    public boolean removeEntry(Principal caller, AclEntry entry)
+          throws NotOwnerException;
+
+    /**
+     * Returns an enumeration for the set of allowed permissions for the
+     * specified principal (representing an entity such as an individual or
+     * a group). This set of allowed permissions is calculated as
+     * follows:
+     *
+     * <ul>
+     *
+     * <li>If there is no entry in this Access Control List for the
+     * specified principal, an empty permission set is returned.
+     *
+     * <li>Otherwise, the principal's group permission sets are determined.
+     * (A principal can belong to one or more groups, where a group is a
+     * group of principals, represented by the Group interface.)
+     * The group positive permission set is the union of all
+     * the positive permissions of each group that the principal belongs to.
+     * The group negative permission set is the union of all
+     * the negative permissions of each group that the principal belongs to.
+     * If there is a specific permission that occurs in both
+     * the positive permission set and the negative permission set,
+     * it is removed from both.<p>
+     *
+     * The individual positive and negative permission sets are also
+     * determined. The positive permission set contains the permissions
+     * specified in the positive ACL entry (if any) for the principal.
+     * Similarly, the negative permission set contains the permissions
+     * specified in the negative ACL entry (if any) for the principal.
+     * The individual positive (or negative) permission set is considered
+     * to be null if there is not a positive (negative) ACL entry for the
+     * principal in this ACL.<p>
+     *
+     * The set of permissions granted to the principal is then calculated
+     * using the simple rule that individual permissions always override
+     * the group permissions. That is, the principal's individual negative
+     * permission set (specific denial of permissions) overrides the group
+     * positive permission set, and the principal's individual positive
+     * permission set overrides the group negative permission set.
+     *
+     * </ul>
+     *
+     * @param user the principal whose permission set is to be returned.
+     *
+     * @return the permission set specifying the permissions the principal
+     * is allowed.
+     */
+    public Enumeration<Permission> getPermissions(Principal user);
+
+    /**
+     * Returns an enumeration of the entries in this ACL. Each element in
+     * the enumeration is of type AclEntry.
+     *
+     * @return an enumeration of the entries in this ACL.
+     */
+    public Enumeration<AclEntry> entries();
+
+    /**
+     * Checks whether or not the specified principal has the specified
+     * permission. If it does, true is returned, otherwise false is returned.
+     *
+     * More specifically, this method checks whether the passed permission
+     * is a member of the allowed permission set of the specified principal.
+     * The allowed permission set is determined by the same algorithm as is
+     * used by the {@code getPermissions} method.
+     *
+     * @param principal the principal, assumed to be a valid authenticated
+     * Principal.
+     *
+     * @param permission the permission to be checked for.
+     *
+     * @return true if the principal has the specified permission, false
+     * otherwise.
+     *
+     * @see #getPermissions
+     */
+    public boolean checkPermission(Principal principal, Permission permission);
+
+    /**
+     * Returns a string representation of the
+     * ACL contents.
+     *
+     * @return a string representation of the ACL contents.
+     */
+    public String toString();
+}
diff --git a/java/security/acl/AclEntry.java b/java/security/acl/AclEntry.java
new file mode 100644
index 0000000..cd9675f
--- /dev/null
+++ b/java/security/acl/AclEntry.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+import java.util.Enumeration;
+import java.security.Principal;
+
+/**
+ * This is the interface used for representing one entry in an Access
+ * Control List (ACL).<p>
+ *
+ * An ACL can be thought of as a data structure with multiple ACL entry
+ * objects. Each ACL entry object contains a set of permissions associated
+ * with a particular principal. (A principal represents an entity such as
+ * an individual user or a group). Additionally, each ACL entry is specified
+ * as being either positive or negative. If positive, the permissions are
+ * to be granted to the associated principal. If negative, the permissions
+ * are to be denied. Each principal can have at most one positive ACL entry
+ * and one negative entry; that is, multiple positive or negative ACL
+ * entries are not allowed for any principal.
+ *
+ * Note: ACL entries are by default positive. An entry becomes a
+ * negative entry only if the
+ * {@link #setNegativePermissions() setNegativePermissions}
+ * method is called on it.
+ *
+ * @see java.security.acl.Acl
+ *
+ * @author      Satish Dharmaraj
+ */
+public interface AclEntry extends Cloneable {
+
+    /**
+     * Specifies the principal for which permissions are granted or denied
+     * by this ACL entry. If a principal was already set for this ACL entry,
+     * false is returned, otherwise true is returned.
+     *
+     * @param user the principal to be set for this entry.
+     *
+     * @return true if the principal is set, false if there was
+     * already a principal set for this entry.
+     *
+     * @see #getPrincipal
+     */
+    public boolean setPrincipal(Principal user);
+
+    /**
+     * Returns the principal for which permissions are granted or denied by
+     * this ACL entry. Returns null if there is no principal set for this
+     * entry yet.
+     *
+     * @return the principal associated with this entry.
+     *
+     * @see #setPrincipal
+     */
+    public Principal getPrincipal();
+
+    /**
+     * Sets this ACL entry to be a negative one. That is, the associated
+     * principal (e.g., a user or a group) will be denied the permission set
+     * specified in the entry.
+     *
+     * Note: ACL entries are by default positive. An entry becomes a
+     * negative entry only if this {@code setNegativePermissions}
+     * method is called on it.
+     */
+    public void setNegativePermissions();
+
+    /**
+     * Returns true if this is a negative ACL entry (one denying the
+     * associated principal the set of permissions in the entry), false
+     * otherwise.
+     *
+     * @return true if this is a negative ACL entry, false if it's not.
+     */
+    public boolean isNegative();
+
+    /**
+     * Adds the specified permission to this ACL entry. Note: An entry can
+     * have multiple permissions.
+     *
+     * @param permission the permission to be associated with
+     * the principal in this entry.
+     *
+     * @return true if the permission was added, false if the
+     * permission was already part of this entry's permission set.
+     */
+    public boolean addPermission(Permission permission);
+
+    /**
+     * Removes the specified permission from this ACL entry.
+     *
+     * @param permission the permission to be removed from this entry.
+     *
+     * @return true if the permission is removed, false if the
+     * permission was not part of this entry's permission set.
+     */
+    public boolean removePermission(Permission permission);
+
+    /**
+     * Checks if the specified permission is part of the
+     * permission set in this entry.
+     *
+     * @param permission the permission to be checked for.
+     *
+     * @return true if the permission is part of the
+     * permission set in this entry, false otherwise.
+     */
+    public boolean checkPermission(Permission permission);
+
+    /**
+     * Returns an enumeration of the permissions in this ACL entry.
+     *
+     * @return an enumeration of the permissions in this ACL entry.
+     */
+    public Enumeration<Permission> permissions();
+
+    /**
+     * Returns a string representation of the contents of this ACL entry.
+     *
+     * @return a string representation of the contents.
+     */
+    public String toString();
+
+    /**
+     * Clones this ACL entry.
+     *
+     * @return a clone of this ACL entry.
+     */
+    public Object clone();
+}
diff --git a/java/security/acl/AclNotFoundException.java b/java/security/acl/AclNotFoundException.java
new file mode 100644
index 0000000..6f08e17
--- /dev/null
+++ b/java/security/acl/AclNotFoundException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+/**
+ * This is an exception that is thrown whenever a reference is made to a
+ * non-existent ACL (Access Control List).
+ *
+ * @author      Satish Dharmaraj
+ */
+public class AclNotFoundException extends Exception {
+
+    private static final long serialVersionUID = 5684295034092681791L;
+
+    /**
+     * Constructs an AclNotFoundException.
+     */
+    public AclNotFoundException() {
+    }
+
+}
diff --git a/java/security/acl/Group.java b/java/security/acl/Group.java
new file mode 100644
index 0000000..ebd9c44
--- /dev/null
+++ b/java/security/acl/Group.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+import java.util.Enumeration;
+import java.security.Principal;
+
+/**
+ * This interface is used to represent a group of principals. (A principal
+ * represents an entity such as an individual user or a company). <p>
+ *
+ * Note that Group extends Principal. Thus, either a Principal or a Group can
+ * be passed as an argument to methods containing a Principal parameter. For
+ * example, you can add either a Principal or a Group to a Group object by
+ * calling the object's {@code addMember} method, passing it the
+ * Principal or Group.
+ *
+ * @author      Satish Dharmaraj
+ */
+public interface Group extends Principal {
+
+    /**
+     * Adds the specified member to the group.
+     *
+     * @param user the principal to add to this group.
+     *
+     * @return true if the member was successfully added,
+     * false if the principal was already a member.
+     */
+    public boolean addMember(Principal user);
+
+    /**
+     * Removes the specified member from the group.
+     *
+     * @param user the principal to remove from this group.
+     *
+     * @return true if the principal was removed, or
+     * false if the principal was not a member.
+     */
+    public boolean removeMember(Principal user);
+
+    /**
+     * Returns true if the passed principal is a member of the group.
+     * This method does a recursive search, so if a principal belongs to a
+     * group which is a member of this group, true is returned.
+     *
+     * @param member the principal whose membership is to be checked.
+     *
+     * @return true if the principal is a member of this group,
+     * false otherwise.
+     */
+    public boolean isMember(Principal member);
+
+
+    /**
+     * Returns an enumeration of the members in the group.
+     * The returned objects can be instances of either Principal
+     * or Group (which is a subclass of Principal).
+     *
+     * @return an enumeration of the group members.
+     */
+    public Enumeration<? extends Principal> members();
+
+}
diff --git a/java/security/acl/LastOwnerException.java b/java/security/acl/LastOwnerException.java
new file mode 100644
index 0000000..196c8f1
--- /dev/null
+++ b/java/security/acl/LastOwnerException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+/**
+ * This is an exception that is thrown whenever an attempt is made to delete
+ * the last owner of an Access Control List.
+ *
+ * @see java.security.acl.Owner#deleteOwner
+ *
+ * @author Satish Dharmaraj
+ */
+public class LastOwnerException extends Exception {
+
+    private static final long serialVersionUID = -5141997548211140359L;
+
+    /**
+     * Constructs a LastOwnerException.
+     */
+    public LastOwnerException() {
+    }
+}
diff --git a/java/security/acl/NotOwnerException.java b/java/security/acl/NotOwnerException.java
new file mode 100644
index 0000000..0a4b04b
--- /dev/null
+++ b/java/security/acl/NotOwnerException.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+/**
+ * This is an exception that is thrown whenever the modification of an object
+ * (such as an Access Control List) is only allowed to be done by an owner of
+ * the object, but the Principal attempting the modification is not an owner.
+ *
+ * @author      Satish Dharmaraj
+ */
+public class NotOwnerException extends Exception {
+
+    private static final long serialVersionUID = -5555597911163362399L;
+
+    /**
+     * Constructs a NotOwnerException.
+     */
+    public NotOwnerException() {
+    }
+}
diff --git a/java/security/acl/Owner.java b/java/security/acl/Owner.java
new file mode 100644
index 0000000..2f649d4
--- /dev/null
+++ b/java/security/acl/Owner.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+import java.security.Principal;
+
+/**
+ * Interface for managing owners of Access Control Lists (ACLs) or ACL
+ * configurations. (Note that the Acl interface in the
+ * {@code  java.security.acl} package extends this Owner
+ * interface.) The initial owner Principal should be specified as an
+ * argument to the constructor of the class implementing this interface.
+ *
+ * @see java.security.acl.Acl
+ *
+ */
+public interface Owner {
+
+    /**
+     * Adds an owner. Only owners can modify ACL contents. The caller
+     * principal must be an owner of the ACL in order to invoke this method.
+     * That is, only an owner can add another owner. The initial owner is
+     * configured at ACL construction time.
+     *
+     * @param caller the principal invoking this method. It must be an owner
+     * of the ACL.
+     *
+     * @param owner the owner that should be added to the list of owners.
+     *
+     * @return true if successful, false if owner is already an owner.
+     * @exception NotOwnerException if the caller principal is not an owner
+     * of the ACL.
+     */
+    public boolean addOwner(Principal caller, Principal owner)
+      throws NotOwnerException;
+
+    /**
+     * Deletes an owner. If this is the last owner in the ACL, an exception is
+     * raised.<p>
+     *
+     * The caller principal must be an owner of the ACL in order to invoke
+     * this method.
+     *
+     * @param caller the principal invoking this method. It must be an owner
+     * of the ACL.
+     *
+     * @param owner the owner to be removed from the list of owners.
+     *
+     * @return true if the owner is removed, false if the owner is not part
+     * of the list of owners.
+     *
+     * @exception NotOwnerException if the caller principal is not an owner
+     * of the ACL.
+     *
+     * @exception LastOwnerException if there is only one owner left, so that
+     * deleteOwner would leave the ACL owner-less.
+     */
+    public boolean deleteOwner(Principal caller, Principal owner)
+      throws NotOwnerException, LastOwnerException;
+
+    /**
+     * Returns true if the given principal is an owner of the ACL.
+     *
+     * @param owner the principal to be checked to determine whether or not
+     * it is an owner.
+     *
+     * @return true if the passed principal is in the list of owners, false
+     * if not.
+     */
+    public boolean isOwner(Principal owner);
+
+}
diff --git a/java/security/acl/Permission.java b/java/security/acl/Permission.java
new file mode 100644
index 0000000..72412de
--- /dev/null
+++ b/java/security/acl/Permission.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.acl;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public interface Permission {
+}
diff --git a/java/security/acl/package-info.java b/java/security/acl/package-info.java
new file mode 100644
index 0000000..356c102
--- /dev/null
+++ b/java/security/acl/package-info.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * The classes and interfaces in this package have been
+ * superseded by classes in the java.security package.
+ * See that package and, for example, java.security.Permission for details.
+ *
+ * @since JDK1.1
+ */
+package java.security.acl;
diff --git a/java/security/cert/CRL.java b/java/security/cert/CRL.java
new file mode 100644
index 0000000..f8083c7
--- /dev/null
+++ b/java/security/cert/CRL.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * This class is an abstraction of certificate revocation lists (CRLs) that
+ * have different formats but important common uses. For example, all CRLs
+ * share the functionality of listing revoked certificates, and can be queried
+ * on whether or not they list a given certificate.
+ * <p>
+ * Specialized CRL types can be defined by subclassing off of this abstract
+ * class.
+ *
+ * @author Hemma Prafullchandra
+ *
+ *
+ * @see X509CRL
+ * @see CertificateFactory
+ *
+ * @since 1.2
+ */
+
+public abstract class CRL {
+
+    // the CRL type
+    private String type;
+
+    /**
+     * Creates a CRL of the specified type.
+     *
+     * @param type the standard name of the CRL type.
+     * See Appendix A in the <a href=
+     * "../../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard CRL types.
+     */
+    protected CRL(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type of this CRL.
+     *
+     * @return the type of this CRL.
+     */
+    public final String getType() {
+        return this.type;
+    }
+
+    /**
+     * Returns a string representation of this CRL.
+     *
+     * @return a string representation of this CRL.
+     */
+    public abstract String toString();
+
+    /**
+     * Checks whether the given certificate is on this CRL.
+     *
+     * @param cert the certificate to check for.
+     * @return true if the given certificate is on this CRL,
+     * false otherwise.
+     */
+    public abstract boolean isRevoked(Certificate cert);
+}
diff --git a/java/security/cert/CRLException.java b/java/security/cert/CRLException.java
new file mode 100644
index 0000000..7a85431
--- /dev/null
+++ b/java/security/cert/CRLException.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * CRL (Certificate Revocation List) Exception.
+ *
+ * @author Hemma Prafullchandra
+ */
+public class CRLException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -6694728944094197147L;
+
+   /**
+     * Constructs a CRLException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public CRLException() {
+        super();
+    }
+
+    /**
+     * Constructs a CRLException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param message the detail message.
+     */
+    public CRLException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a {@code CRLException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CRLException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code CRLException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CRLException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/cert/CRLReason.java b/java/security/cert/CRLReason.java
new file mode 100644
index 0000000..ac0b9e9
--- /dev/null
+++ b/java/security/cert/CRLReason.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * The CRLReason enumeration specifies the reason that a certificate
+ * is revoked, as defined in <a href="http://www.ietf.org/rfc/rfc3280.txt">
+ * RFC 3280: Internet X.509 Public Key Infrastructure Certificate and CRL
+ * Profile</a>.
+ *
+ * @author Sean Mullan
+ * @since 1.7
+ * @see X509CRLEntry#getRevocationReason
+ * @see CertificateRevokedException#getRevocationReason
+ */
+public enum CRLReason {
+    /**
+     * This reason indicates that it is unspecified as to why the
+     * certificate has been revoked.
+     */
+    UNSPECIFIED,
+
+    /**
+     * This reason indicates that it is known or suspected that the
+     * certificate subject's private key has been compromised. It applies
+     * to end-entity certificates only.
+     */
+    KEY_COMPROMISE,
+
+    /**
+     * This reason indicates that it is known or suspected that the
+     * certificate subject's private key has been compromised. It applies
+     * to certificate authority (CA) certificates only.
+     */
+    CA_COMPROMISE,
+
+    /**
+     * This reason indicates that the subject's name or other information
+     * has changed.
+     */
+    AFFILIATION_CHANGED,
+
+    /**
+     * This reason indicates that the certificate has been superseded.
+     */
+    SUPERSEDED,
+
+    /**
+     * This reason indicates that the certificate is no longer needed.
+     */
+    CESSATION_OF_OPERATION,
+
+    /**
+     * This reason indicates that the certificate has been put on hold.
+     */
+    CERTIFICATE_HOLD,
+
+    /**
+     * Unused reason.
+     */
+    UNUSED,
+
+    /**
+     * This reason indicates that the certificate was previously on hold
+     * and should be removed from the CRL. It is for use with delta CRLs.
+     */
+    REMOVE_FROM_CRL,
+
+    /**
+     * This reason indicates that the privileges granted to the subject of
+     * the certificate have been withdrawn.
+     */
+    PRIVILEGE_WITHDRAWN,
+
+    /**
+     * This reason indicates that it is known or suspected that the
+     * certificate subject's private key has been compromised. It applies
+     * to authority attribute (AA) certificates only.
+     */
+    AA_COMPROMISE
+}
diff --git a/java/security/cert/CRLSelector.java b/java/security/cert/CRLSelector.java
new file mode 100644
index 0000000..7ab181d
--- /dev/null
+++ b/java/security/cert/CRLSelector.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * A selector that defines a set of criteria for selecting {@code CRL}s.
+ * Classes that implement this interface are often used to specify
+ * which {@code CRL}s should be retrieved from a {@code CertStore}.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this interface are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CRL
+ * @see CertStore
+ * @see CertStore#getCRLs
+ *
+ * @author      Steve Hanna
+ * @since       1.4
+ */
+public interface CRLSelector extends Cloneable {
+
+    /**
+     * Decides whether a {@code CRL} should be selected.
+     *
+     * @param   crl     the {@code CRL} to be checked
+     * @return  {@code true} if the {@code CRL} should be selected,
+     * {@code false} otherwise
+     */
+    boolean match(CRL crl);
+
+    /**
+     * Makes a copy of this {@code CRLSelector}. Changes to the
+     * copy will not affect the original and vice versa.
+     *
+     * @return a copy of this {@code CRLSelector}
+     */
+    Object clone();
+}
diff --git a/java/security/cert/CertPath.java b/java/security/cert/CertPath.java
new file mode 100644
index 0000000..8717f94
--- /dev/null
+++ b/java/security/cert/CertPath.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * An immutable sequence of certificates (a certification path).
+ * <p>
+ * This is an abstract class that defines the methods common to all
+ * {@code CertPath}s. Subclasses can handle different kinds of
+ * certificates (X.509, PGP, etc.).
+ * <p>
+ * All {@code CertPath} objects have a type, a list of
+ * {@code Certificate}s, and one or more supported encodings. Because the
+ * {@code CertPath} class is immutable, a {@code CertPath} cannot
+ * change in any externally visible way after being constructed. This
+ * stipulation applies to all public fields and methods of this class and any
+ * added or overridden by subclasses.
+ * <p>
+ * The type is a {@code String} that identifies the type of
+ * {@code Certificate}s in the certification path. For each
+ * certificate {@code cert} in a certification path {@code certPath},
+ * {@code cert.getType().equals(certPath.getType())} must be
+ * {@code true}.
+ * <p>
+ * The list of {@code Certificate}s is an ordered {@code List} of
+ * zero or more {@code Certificate}s. This {@code List} and all
+ * of the {@code Certificate}s contained in it must be immutable.
+ * <p>
+ * Each {@code CertPath} object must support one or more encodings
+ * so that the object can be translated into a byte array for storage or
+ * transmission to other parties. Preferably, these encodings should be
+ * well-documented standards (such as PKCS#7). One of the encodings supported
+ * by a {@code CertPath} is considered the default encoding. This
+ * encoding is used if no encoding is explicitly requested (for the
+ * {@link #getEncoded() getEncoded()} method, for instance).
+ * <p>
+ * All {@code CertPath} objects are also {@code Serializable}.
+ * {@code CertPath} objects are resolved into an alternate
+ * {@link CertPathRep CertPathRep} object during serialization. This allows
+ * a {@code CertPath} object to be serialized into an equivalent
+ * representation regardless of its underlying implementation.
+ * <p>
+ * {@code CertPath} objects can be created with a
+ * {@code CertificateFactory} or they can be returned by other classes,
+ * such as a {@code CertPathBuilder}.
+ * <p>
+ * By convention, X.509 {@code CertPath}s (consisting of
+ * {@code X509Certificate}s), are ordered starting with the target
+ * certificate and ending with a certificate issued by the trust anchor. That
+ * is, the issuer of one certificate is the subject of the following one. The
+ * certificate representing the {@link TrustAnchor TrustAnchor} should not be
+ * included in the certification path. Unvalidated X.509 {@code CertPath}s
+ * may not follow these conventions. PKIX {@code CertPathValidator}s will
+ * detect any departure from these conventions that cause the certification
+ * path to be invalid and throw a {@code CertPathValidatorException}.
+ *
+ * <p> Every implementation of the Java platform is required to support the
+ * following standard {@code CertPath} encodings:
+ * <ul>
+ * <li>{@code PKCS7}</li>
+ * <li>{@code PkiPath}</li>
+ * </ul>
+ * These encodings are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
+ * CertPath Encodings section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ * Consult the release documentation for your implementation to see if any
+ * other encodings are supported.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * All {@code CertPath} objects must be thread-safe. That is, multiple
+ * threads may concurrently invoke the methods defined in this class on a
+ * single {@code CertPath} object (or more than one) with no
+ * ill effects. This is also true for the {@code List} returned by
+ * {@code CertPath.getCertificates}.
+ * <p>
+ * Requiring {@code CertPath} objects to be immutable and thread-safe
+ * allows them to be passed around to various pieces of code without worrying
+ * about coordinating access.  Providing this thread-safety is
+ * generally not difficult, since the {@code CertPath} and
+ * {@code List} objects in question are immutable.
+ *
+ * @see CertificateFactory
+ * @see CertPathBuilder
+ *
+ * @author      Yassir Elley
+ * @since       1.4
+ */
+public abstract class CertPath implements Serializable {
+
+    private static final long serialVersionUID = 6068470306649138683L;
+
+    private String type;        // the type of certificates in this chain
+
+    /**
+     * Creates a {@code CertPath} of the specified type.
+     * <p>
+     * This constructor is protected because most users should use a
+     * {@code CertificateFactory} to create {@code CertPath}s.
+     *
+     * @param type the standard name of the type of
+     * {@code Certificate}s in this path
+     */
+    protected CertPath(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type of {@code Certificate}s in this certification
+     * path. This is the same string that would be returned by
+     * {@link java.security.cert.Certificate#getType() cert.getType()}
+     * for all {@code Certificate}s in the certification path.
+     *
+     * @return the type of {@code Certificate}s in this certification
+     * path (never null)
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Returns an iteration of the encodings supported by this certification
+     * path, with the default encoding first. Attempts to modify the returned
+     * {@code Iterator} via its {@code remove} method result in an
+     * {@code UnsupportedOperationException}.
+     *
+     * @return an {@code Iterator} over the names of the supported
+     *         encodings (as Strings)
+     */
+    public abstract Iterator<String> getEncodings();
+
+    /**
+     * Compares this certification path for equality with the specified
+     * object. Two {@code CertPath}s are equal if and only if their
+     * types are equal and their certificate {@code List}s (and by
+     * implication the {@code Certificate}s in those {@code List}s)
+     * are equal. A {@code CertPath} is never equal to an object that is
+     * not a {@code CertPath}.
+     * <p>
+     * This algorithm is implemented by this method. If it is overridden,
+     * the behavior specified here must be maintained.
+     *
+     * @param other the object to test for equality with this certification path
+     * @return true if the specified object is equal to this certification path,
+     * false otherwise
+     */
+    public boolean equals(Object other) {
+        if (this == other)
+            return true;
+
+        if (! (other instanceof CertPath))
+            return false;
+
+        CertPath otherCP = (CertPath) other;
+        if (! otherCP.getType().equals(type))
+            return false;
+
+        List<? extends Certificate> thisCertList = this.getCertificates();
+        List<? extends Certificate> otherCertList = otherCP.getCertificates();
+        return(thisCertList.equals(otherCertList));
+    }
+
+    /**
+     * Returns the hashcode for this certification path. The hash code of
+     * a certification path is defined to be the result of the following
+     * calculation:
+     * <pre>{@code
+     *  hashCode = path.getType().hashCode();
+     *  hashCode = 31*hashCode + path.getCertificates().hashCode();
+     * }</pre>
+     * This ensures that {@code path1.equals(path2)} implies that
+     * {@code path1.hashCode()==path2.hashCode()} for any two certification
+     * paths, {@code path1} and {@code path2}, as required by the
+     * general contract of {@code Object.hashCode}.
+     *
+     * @return the hashcode value for this certification path
+     */
+    public int hashCode() {
+        int hashCode = type.hashCode();
+        hashCode = 31*hashCode + getCertificates().hashCode();
+        return hashCode;
+    }
+
+    /**
+     * Returns a string representation of this certification path.
+     * This calls the {@code toString} method on each of the
+     * {@code Certificate}s in the path.
+     *
+     * @return a string representation of this certification path
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        Iterator<? extends Certificate> stringIterator =
+                                        getCertificates().iterator();
+
+        sb.append("\n" + type + " Cert Path: length = "
+            + getCertificates().size() + ".\n");
+        sb.append("[\n");
+        int i = 1;
+        while (stringIterator.hasNext()) {
+            sb.append("=========================================="
+                + "===============Certificate " + i + " start.\n");
+            Certificate stringCert = stringIterator.next();
+            sb.append(stringCert.toString());
+            sb.append("\n========================================"
+                + "=================Certificate " + i + " end.\n\n\n");
+            i++;
+        }
+
+        sb.append("\n]");
+        return sb.toString();
+    }
+
+    /**
+     * Returns the encoded form of this certification path, using the default
+     * encoding.
+     *
+     * @return the encoded bytes
+     * @exception CertificateEncodingException if an encoding error occurs
+     */
+    public abstract byte[] getEncoded()
+        throws CertificateEncodingException;
+
+    /**
+     * Returns the encoded form of this certification path, using the
+     * specified encoding.
+     *
+     * @param encoding the name of the encoding to use
+     * @return the encoded bytes
+     * @exception CertificateEncodingException if an encoding error occurs or
+     *   the encoding requested is not supported
+     */
+    public abstract byte[] getEncoded(String encoding)
+        throws CertificateEncodingException;
+
+    /**
+     * Returns the list of certificates in this certification path.
+     * The {@code List} returned must be immutable and thread-safe.
+     *
+     * @return an immutable {@code List} of {@code Certificate}s
+     *         (may be empty, but not null)
+     */
+    public abstract List<? extends Certificate> getCertificates();
+
+    /**
+     * Replaces the {@code CertPath} to be serialized with a
+     * {@code CertPathRep} object.
+     *
+     * @return the {@code CertPathRep} to be serialized
+     *
+     * @throws ObjectStreamException if a {@code CertPathRep} object
+     * representing this certification path could not be created
+     */
+    protected Object writeReplace() throws ObjectStreamException {
+        try {
+            return new CertPathRep(type, getEncoded());
+        } catch (CertificateException ce) {
+            NotSerializableException nse =
+                new NotSerializableException
+                    ("java.security.cert.CertPath: " + type);
+            nse.initCause(ce);
+            throw nse;
+        }
+    }
+
+    /**
+     * Alternate {@code CertPath} class for serialization.
+     * @since 1.4
+     */
+    protected static class CertPathRep implements Serializable {
+
+        private static final long serialVersionUID = 3015633072427920915L;
+
+        /** The Certificate type */
+        private String type;
+        /** The encoded form of the cert path */
+        private byte[] data;
+
+        /**
+         * Creates a {@code CertPathRep} with the specified
+         * type and encoded form of a certification path.
+         *
+         * @param type the standard name of a {@code CertPath} type
+         * @param data the encoded form of the certification path
+         */
+        protected CertPathRep(String type, byte[] data) {
+            this.type = type;
+            this.data = data;
+        }
+
+        /**
+         * Returns a {@code CertPath} constructed from the type and data.
+         *
+         * @return the resolved {@code CertPath} object
+         *
+         * @throws ObjectStreamException if a {@code CertPath} could not
+         * be constructed
+         */
+        protected Object readResolve() throws ObjectStreamException {
+            try {
+                CertificateFactory cf = CertificateFactory.getInstance(type);
+                return cf.generateCertPath(new ByteArrayInputStream(data));
+            } catch (CertificateException ce) {
+                NotSerializableException nse =
+                    new NotSerializableException
+                        ("java.security.cert.CertPath: " + type);
+                nse.initCause(ce);
+                throw nse;
+            }
+        }
+    }
+}
diff --git a/java/security/cert/CertPathBuilder.java b/java/security/cert/CertPathBuilder.java
new file mode 100644
index 0000000..891d86c
--- /dev/null
+++ b/java/security/cert/CertPathBuilder.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import sun.security.util.Debug;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * A class for building certification paths (also known as certificate chains).
+ * <p>
+ * This class uses a provider-based architecture.
+ * To create a {@code CertPathBuilder}, call
+ * one of the static {@code getInstance} methods, passing in the
+ * algorithm name of the {@code CertPathBuilder} desired and optionally
+ * the name of the provider desired.
+ *
+ * <p>Once a {@code CertPathBuilder} object has been created, certification
+ * paths can be constructed by calling the {@link #build build} method and
+ * passing it an algorithm-specific set of parameters. If successful, the
+ * result (including the {@code CertPath} that was built) is returned
+ * in an object that implements the {@code CertPathBuilderResult}
+ * interface.
+ *
+ * <p>The {@link #getRevocationChecker} method allows an application to specify
+ * additional algorithm-specific parameters and options used by the
+ * {@code CertPathBuilder} when checking the revocation status of certificates.
+ * Here is an example demonstrating how it is used with the PKIX algorithm:
+ *
+ * <pre>
+ * CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");
+ * PKIXRevocationChecker rc = (PKIXRevocationChecker)cpb.getRevocationChecker();
+ * rc.setOptions(EnumSet.of(Option.PREFER_CRLS));
+ * params.addCertPathChecker(rc);
+ * CertPathBuilderResult cpbr = cpb.build(params);
+ * </pre>
+ *
+ * <p> Android provides the following {@code CertPathBuilder} algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>PKIX</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * This algorithm is described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
+ * CertPathBuilder section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ * Consult the release documentation for your implementation to see if any
+ * other algorithms are supported.
+ *
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * The static methods of this class are guaranteed to be thread-safe.
+ * Multiple threads may concurrently invoke the static methods defined in
+ * this class with no ill effects.
+ * <p>
+ * However, this is not true for the non-static methods defined by this class.
+ * Unless otherwise documented by a specific provider, threads that need to
+ * access a single {@code CertPathBuilder} instance concurrently should
+ * synchronize amongst themselves and provide the necessary locking. Multiple
+ * threads each manipulating a different {@code CertPathBuilder} instance
+ * need not synchronize.
+ *
+ * @see CertPath
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ * @author      Yassir Elley
+ */
+public class CertPathBuilder {
+
+    /*
+     * Constant to lookup in the Security properties file to determine
+     * the default certpathbuilder type. In the Security properties file,
+     * the default certpathbuilder type is given as:
+     * <pre>
+     * certpathbuilder.type=PKIX
+     * </pre>
+     */
+    private static final String CPB_TYPE = "certpathbuilder.type";
+    private final CertPathBuilderSpi builderSpi;
+    private final Provider provider;
+    private final String algorithm;
+
+    /**
+     * Creates a {@code CertPathBuilder} object of the given algorithm,
+     * and encapsulates the given provider implementation (SPI object) in it.
+     *
+     * @param builderSpi the provider implementation
+     * @param provider the provider
+     * @param algorithm the algorithm name
+     */
+    protected CertPathBuilder(CertPathBuilderSpi builderSpi, Provider provider,
+        String algorithm)
+    {
+        this.builderSpi = builderSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns a {@code CertPathBuilder} object that implements the
+     * specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new CertPathBuilder object encapsulating the
+     * CertPathBuilderSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the requested {@code CertPathBuilder}
+     *  algorithm.  See the CertPathBuilder section in the <a href=
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return a {@code CertPathBuilder} object that implements the
+     *          specified algorithm.
+     *
+     * @throws NoSuchAlgorithmException if no Provider supports a
+     *          CertPathBuilderSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static CertPathBuilder getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        Instance instance = GetInstance.getInstance("CertPathBuilder",
+            CertPathBuilderSpi.class, algorithm);
+        return new CertPathBuilder((CertPathBuilderSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a {@code CertPathBuilder} object that implements the
+     * specified algorithm.
+     *
+     * <p> A new CertPathBuilder object encapsulating the
+     * CertPathBuilderSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the requested {@code CertPathBuilder}
+     *  algorithm.  See the CertPathBuilder section in the <a href=
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a {@code CertPathBuilder} object that implements the
+     *          specified algorithm.
+     *
+     * @throws NoSuchAlgorithmException if a CertPathBuilderSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @throws NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static CertPathBuilder getInstance(String algorithm, String provider)
+           throws NoSuchAlgorithmException, NoSuchProviderException {
+        Instance instance = GetInstance.getInstance("CertPathBuilder",
+            CertPathBuilderSpi.class, algorithm, provider);
+        return new CertPathBuilder((CertPathBuilderSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a {@code CertPathBuilder} object that implements the
+     * specified algorithm.
+     *
+     * <p> A new CertPathBuilder object encapsulating the
+     * CertPathBuilderSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the name of the requested {@code CertPathBuilder}
+     *  algorithm.  See the CertPathBuilder section in the <a href=
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathBuilder">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return a {@code CertPathBuilder} object that implements the
+     *          specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if a CertPathBuilderSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null.
+     *
+     * @see java.security.Provider
+     */
+    public static CertPathBuilder getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = GetInstance.getInstance("CertPathBuilder",
+            CertPathBuilderSpi.class, algorithm, provider);
+        return new CertPathBuilder((CertPathBuilderSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the provider of this {@code CertPathBuilder}.
+     *
+     * @return the provider of this {@code CertPathBuilder}
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Returns the name of the algorithm of this {@code CertPathBuilder}.
+     *
+     * @return the name of the algorithm of this {@code CertPathBuilder}
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Attempts to build a certification path using the specified algorithm
+     * parameter set.
+     *
+     * @param params the algorithm parameters
+     * @return the result of the build algorithm
+     * @throws CertPathBuilderException if the builder is unable to construct
+     *  a certification path that satisfies the specified parameters
+     * @throws InvalidAlgorithmParameterException if the specified parameters
+     * are inappropriate for this {@code CertPathBuilder}
+     */
+    public final CertPathBuilderResult build(CertPathParameters params)
+        throws CertPathBuilderException, InvalidAlgorithmParameterException
+    {
+        return builderSpi.engineBuild(params);
+    }
+
+    /**
+     * Returns the default {@code CertPathBuilder} type as specified by
+     * the {@code certpathbuilder.type} security property, or the string
+     * {@literal "PKIX"} if no such property exists.
+     *
+     * <p>The default {@code CertPathBuilder} type can be used by
+     * applications that do not want to use a hard-coded type when calling one
+     * of the {@code getInstance} methods, and want to provide a default
+     * type in case a user does not specify its own.
+     *
+     * <p>The default {@code CertPathBuilder} type can be changed by
+     * setting the value of the {@code certpathbuilder.type} security property
+     * to the desired type.
+     *
+     * @see java.security.Security security properties
+     * @return the default {@code CertPathBuilder} type as specified
+     * by the {@code certpathbuilder.type} security property, or the string
+     * {@literal "PKIX"} if no such property exists.
+     */
+    public final static String getDefaultType() {
+        String cpbtype =
+            AccessController.doPrivileged(new PrivilegedAction<String>() {
+                public String run() {
+                    return Security.getProperty(CPB_TYPE);
+                }
+            });
+        return (cpbtype == null) ? "PKIX" : cpbtype;
+    }
+
+    /**
+     * Returns a {@code CertPathChecker} that the encapsulated
+     * {@code CertPathBuilderSpi} implementation uses to check the revocation
+     * status of certificates. A PKIX implementation returns objects of
+     * type {@code PKIXRevocationChecker}. Each invocation of this method
+     * returns a new instance of {@code CertPathChecker}.
+     *
+     * <p>The primary purpose of this method is to allow callers to specify
+     * additional input parameters and options specific to revocation checking.
+     * See the class description for an example.
+     *
+     * @return a {@code CertPathChecker}
+     * @throws UnsupportedOperationException if the service provider does not
+     *         support this method
+     * @since 1.8
+     */
+    public final CertPathChecker getRevocationChecker() {
+        return builderSpi.engineGetRevocationChecker();
+    }
+}
diff --git a/java/security/cert/CertPathBuilderException.java b/java/security/cert/CertPathBuilderException.java
new file mode 100644
index 0000000..cf95847
--- /dev/null
+++ b/java/security/cert/CertPathBuilderException.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * An exception indicating one of a variety of problems encountered when
+ * building a certification path with a {@code CertPathBuilder}.
+ * <p>
+ * A {@code CertPathBuilderException} provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilder
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public class CertPathBuilderException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 5316471420178794402L;
+
+    /**
+     * Creates a {@code CertPathBuilderException} with {@code null}
+     * as its detail message.
+     */
+    public CertPathBuilderException() {
+        super();
+    }
+
+    /**
+     * Creates a {@code CertPathBuilderException} with the given
+     * detail message. The detail message is a {@code String} that
+     * describes this particular exception in more detail.
+     *
+     * @param msg the detail message
+     */
+    public CertPathBuilderException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code CertPathBuilderException} that wraps the specified
+     * throwable. This allows any exception to be converted into a
+     * {@code CertPathBuilderException}, while retaining information
+     * about the wrapped exception, which may be useful for debugging. The
+     * detail message is set to ({@code cause==null ? null : cause.toString()})
+     * (which typically contains the class and detail message of
+     * cause).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause getCause()} method). (A {@code null} value is
+     * permitted, and indicates that the cause is nonexistent or unknown.)
+     */
+    public CertPathBuilderException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Creates a {@code CertPathBuilderException} with the specified
+     * detail message and cause.
+     *
+     * @param msg the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     * {@link #getCause getCause()} method). (A {@code null} value is
+     * permitted, and indicates that the cause is nonexistent or unknown.)
+     */
+    public CertPathBuilderException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
diff --git a/java/security/cert/CertPathBuilderResult.java b/java/security/cert/CertPathBuilderResult.java
new file mode 100644
index 0000000..ecf53bb
--- /dev/null
+++ b/java/security/cert/CertPathBuilderResult.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * A specification of the result of a certification path builder algorithm.
+ * All results returned by the {@link CertPathBuilder#build
+ * CertPathBuilder.build} method must implement this interface.
+ * <p>
+ * At a minimum, a {@code CertPathBuilderResult} contains the
+ * {@code CertPath} built by the {@code CertPathBuilder} instance.
+ * Implementations of this interface may add methods to return implementation
+ * or algorithm specific information, such as debugging information or
+ * certification path validation results.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this interface are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilder
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public interface CertPathBuilderResult extends Cloneable {
+
+    /**
+     * Returns the built certification path.
+     *
+     * @return the certification path (never {@code null})
+     */
+    CertPath getCertPath();
+
+    /**
+     * Makes a copy of this {@code CertPathBuilderResult}. Changes to the
+     * copy will not affect the original and vice versa.
+     *
+     * @return a copy of this {@code CertPathBuilderResult}
+     */
+    Object clone();
+}
diff --git a/java/security/cert/CertPathBuilderSpi.java b/java/security/cert/CertPathBuilderSpi.java
new file mode 100644
index 0000000..e775541
--- /dev/null
+++ b/java/security/cert/CertPathBuilderSpi.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@link CertPathBuilder CertPathBuilder} class. All
+ * {@code CertPathBuilder} implementations must include a class (the
+ * SPI class) that extends this class ({@code CertPathBuilderSpi}) and
+ * implements all of its methods. In general, instances of this class should
+ * only be accessed through the {@code CertPathBuilder} class. For
+ * details, see the Java Cryptography Architecture.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Instances of this class need not be protected against concurrent
+ * access from multiple threads. Threads that need to access a single
+ * {@code CertPathBuilderSpi} instance concurrently should synchronize
+ * amongst themselves and provide the necessary locking before calling the
+ * wrapping {@code CertPathBuilder} object.
+ * <p>
+ * However, implementations of {@code CertPathBuilderSpi} may still
+ * encounter concurrency issues, since multiple threads each
+ * manipulating a different {@code CertPathBuilderSpi} instance need not
+ * synchronize.
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public abstract class CertPathBuilderSpi {
+
+    /**
+     * The default constructor.
+     */
+    public CertPathBuilderSpi() { }
+
+    /**
+     * Attempts to build a certification path using the specified
+     * algorithm parameter set.
+     *
+     * @param params the algorithm parameters
+     * @return the result of the build algorithm
+     * @throws CertPathBuilderException if the builder is unable to construct
+     * a certification path that satisfies the specified parameters
+     * @throws InvalidAlgorithmParameterException if the specified parameters
+     * are inappropriate for this {@code CertPathBuilder}
+     */
+    public abstract CertPathBuilderResult engineBuild(CertPathParameters params)
+        throws CertPathBuilderException, InvalidAlgorithmParameterException;
+
+    /**
+     * Returns a {@code CertPathChecker} that this implementation uses to
+     * check the revocation status of certificates. A PKIX implementation
+     * returns objects of type {@code PKIXRevocationChecker}.
+     *
+     * <p>The primary purpose of this method is to allow callers to specify
+     * additional input parameters and options specific to revocation checking.
+     * See the class description of {@code CertPathBuilder} for an example.
+     *
+     * <p>This method was added to version 1.8 of the Java Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method cannot be abstract and by default throws
+     * an {@code UnsupportedOperationException}.
+     *
+     * @return a {@code CertPathChecker} that this implementation uses to
+     * check the revocation status of certificates
+     * @throws UnsupportedOperationException if this method is not supported
+     * @since 1.8
+     */
+    public CertPathChecker engineGetRevocationChecker() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/java/security/cert/CertPathChecker.java b/java/security/cert/CertPathChecker.java
new file mode 100644
index 0000000..c40a65b
--- /dev/null
+++ b/java/security/cert/CertPathChecker.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * <p>Performs one or more checks on each {@code Certificate} of a
+ * {@code CertPath}.
+ *
+ * <p>A {@code CertPathChecker} implementation is typically created to extend
+ * a certification path validation algorithm. For example, an implementation
+ * may check for and process a critical private extension of each certificate
+ * in a certification path.
+ *
+ * @since 1.8
+ */
+public interface CertPathChecker {
+
+    /**
+     * Initializes the internal state of this {@code CertPathChecker}.
+     *
+     * <p>The {@code forward} flag specifies the order that certificates will
+     * be passed to the {@link #check check} method (forward or reverse).
+     *
+     * @param forward the order that certificates are presented to the
+     *        {@code check} method. If {@code true}, certificates are
+     *        presented from target to trust anchor (forward); if
+     *        {@code false}, from trust anchor to target (reverse).
+     * @throws CertPathValidatorException if this {@code CertPathChecker} is
+     *         unable to check certificates in the specified order
+     */
+    void init(boolean forward) throws CertPathValidatorException;
+
+    /**
+     * Indicates if forward checking is supported. Forward checking refers
+     * to the ability of the {@code CertPathChecker} to perform its checks
+     * when certificates are presented to the {@code check} method in the
+     * forward direction (from target to trust anchor).
+     *
+     * @return {@code true} if forward checking is supported, {@code false}
+     *         otherwise
+     */
+    boolean isForwardCheckingSupported();
+
+    /**
+     * Performs the check(s) on the specified certificate using its internal
+     * state. The certificates are presented in the order specified by the
+     * {@code init} method.
+     *
+     * @param cert the {@code Certificate} to be checked
+     * @throws CertPathValidatorException if the specified certificate does
+     *         not pass the check
+     */
+    void check(Certificate cert) throws CertPathValidatorException;
+}
diff --git a/java/security/cert/CertPathHelperImpl.java b/java/security/cert/CertPathHelperImpl.java
new file mode 100644
index 0000000..fd9e111
--- /dev/null
+++ b/java/security/cert/CertPathHelperImpl.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.util.*;
+
+import sun.security.provider.certpath.CertPathHelper;
+
+import sun.security.x509.GeneralNameInterface;
+
+/**
+ * Helper class that allows the Sun CertPath provider to access
+ * implementation dependent APIs in CertPath framework.
+ *
+ * @author Andreas Sterbenz
+ */
+class CertPathHelperImpl extends CertPathHelper {
+
+    private CertPathHelperImpl() {
+        // empty
+    }
+
+    /**
+     * Initialize the helper framework. This method must be called from
+     * the static initializer of each class that is the target of one of
+     * the methods in this class. This ensures that the helper is initialized
+     * prior to a tunneled call from the Sun provider.
+     */
+    synchronized static void initialize() {
+        if (CertPathHelper.instance == null) {
+            CertPathHelper.instance = new CertPathHelperImpl();
+        }
+    }
+
+    protected void implSetPathToNames(X509CertSelector sel,
+            Set<GeneralNameInterface> names) {
+        sel.setPathToNamesInternal(names);
+    }
+
+    protected void implSetDateAndTime(X509CRLSelector sel, Date date, long skew) {
+        sel.setDateAndTime(date, skew);
+    }
+}
diff --git a/java/security/cert/CertPathParameters.java b/java/security/cert/CertPathParameters.java
new file mode 100644
index 0000000..ace1b21
--- /dev/null
+++ b/java/security/cert/CertPathParameters.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * A specification of certification path algorithm parameters.
+ * The purpose of this interface is to group (and provide type safety for)
+ * all {@code CertPath} parameter specifications. All
+ * {@code CertPath} parameter specifications must implement this
+ * interface.
+ *
+ * @author      Yassir Elley
+ * @see         CertPathValidator#validate(CertPath, CertPathParameters)
+ * @see         CertPathBuilder#build(CertPathParameters)
+ * @since       1.4
+ */
+public interface CertPathParameters extends Cloneable {
+
+  /**
+   * Makes a copy of this {@code CertPathParameters}. Changes to the
+   * copy will not affect the original and vice versa.
+   *
+   * @return a copy of this {@code CertPathParameters}
+   */
+  Object clone();
+}
diff --git a/java/security/cert/CertPathValidator.java b/java/security/cert/CertPathValidator.java
new file mode 100644
index 0000000..942c5fa
--- /dev/null
+++ b/java/security/cert/CertPathValidator.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import sun.security.util.Debug;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * A class for validating certification paths (also known as certificate
+ * chains).
+ * <p>
+ * This class uses a provider-based architecture.
+ * To create a {@code CertPathValidator},
+ * call one of the static {@code getInstance} methods, passing in the
+ * algorithm name of the {@code CertPathValidator} desired and
+ * optionally the name of the provider desired.
+ *
+ * <p>Once a {@code CertPathValidator} object has been created, it can
+ * be used to validate certification paths by calling the {@link #validate
+ * validate} method and passing it the {@code CertPath} to be validated
+ * and an algorithm-specific set of parameters. If successful, the result is
+ * returned in an object that implements the
+ * {@code CertPathValidatorResult} interface.
+ *
+ * <p>The {@link #getRevocationChecker} method allows an application to specify
+ * additional algorithm-specific parameters and options used by the
+ * {@code CertPathValidator} when checking the revocation status of
+ * certificates. Here is an example demonstrating how it is used with the PKIX
+ * algorithm:
+ *
+ * <pre>
+ * CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+ * PKIXRevocationChecker rc = (PKIXRevocationChecker)cpv.getRevocationChecker();
+ * rc.setOptions(EnumSet.of(Option.SOFT_FAIL));
+ * params.addCertPathChecker(rc);
+ * CertPathValidatorResult cpvr = cpv.validate(path, params);
+ * </pre>
+ *
+ * <p> Android provides the following {@code CertPathValidator} algorithms:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>PKIX</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * This algorithm is described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
+ * CertPathValidator section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * The static methods of this class are guaranteed to be thread-safe.
+ * Multiple threads may concurrently invoke the static methods defined in
+ * this class with no ill effects.
+ * <p>
+ * However, this is not true for the non-static methods defined by this class.
+ * Unless otherwise documented by a specific provider, threads that need to
+ * access a single {@code CertPathValidator} instance concurrently should
+ * synchronize amongst themselves and provide the necessary locking. Multiple
+ * threads each manipulating a different {@code CertPathValidator}
+ * instance need not synchronize.
+ *
+ * @see CertPath
+ *
+ * @since       1.4
+ * @author      Yassir Elley
+ */
+public class CertPathValidator {
+
+    /*
+     * Constant to lookup in the Security properties file to determine
+     * the default certpathvalidator type. In the Security properties file,
+     * the default certpathvalidator type is given as:
+     * <pre>
+     * certpathvalidator.type=PKIX
+     * </pre>
+     */
+    private static final String CPV_TYPE = "certpathvalidator.type";
+    private final CertPathValidatorSpi validatorSpi;
+    private final Provider provider;
+    private final String algorithm;
+
+    /**
+     * Creates a {@code CertPathValidator} object of the given algorithm,
+     * and encapsulates the given provider implementation (SPI object) in it.
+     *
+     * @param validatorSpi the provider implementation
+     * @param provider the provider
+     * @param algorithm the algorithm name
+     */
+    protected CertPathValidator(CertPathValidatorSpi validatorSpi,
+        Provider provider, String algorithm)
+    {
+        this.validatorSpi = validatorSpi;
+        this.provider = provider;
+        this.algorithm = algorithm;
+    }
+
+    /**
+     * Returns a {@code CertPathValidator} object that implements the
+     * specified algorithm.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new CertPathValidator object encapsulating the
+     * CertPathValidatorSpi implementation from the first
+     * Provider that supports the specified algorithm is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the requested {@code CertPathValidator}
+     *  algorithm. See the CertPathValidator section in the <a href=
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @return a {@code CertPathValidator} object that implements the
+     *          specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if no Provider supports a
+     *          CertPathValidatorSpi implementation for the
+     *          specified algorithm.
+     *
+     * @see java.security.Provider
+     */
+    public static CertPathValidator getInstance(String algorithm)
+            throws NoSuchAlgorithmException {
+        Instance instance = GetInstance.getInstance("CertPathValidator",
+            CertPathValidatorSpi.class, algorithm);
+        return new CertPathValidator((CertPathValidatorSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a {@code CertPathValidator} object that implements the
+     * specified algorithm.
+     *
+     * <p> A new CertPathValidator object encapsulating the
+     * CertPathValidatorSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param algorithm the name of the requested {@code CertPathValidator}
+     *  algorithm. See the CertPathValidator section in the <a href=
+     *  "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a {@code CertPathValidator} object that implements the
+     *          specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if a CertPathValidatorSpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static CertPathValidator getInstance(String algorithm,
+            String provider) throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        Instance instance = GetInstance.getInstance("CertPathValidator",
+            CertPathValidatorSpi.class, algorithm, provider);
+        return new CertPathValidator((CertPathValidatorSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns a {@code CertPathValidator} object that implements the
+     * specified algorithm.
+     *
+     * <p> A new CertPathValidator object encapsulating the
+     * CertPathValidatorSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param algorithm the name of the requested {@code CertPathValidator}
+     * algorithm. See the CertPathValidator section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathValidator">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard algorithm names.
+     *
+     * @param provider the provider.
+     *
+     * @return a {@code CertPathValidator} object that implements the
+     *          specified algorithm.
+     *
+     * @exception NoSuchAlgorithmException if a CertPathValidatorSpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null.
+     *
+     * @see java.security.Provider
+     */
+    public static CertPathValidator getInstance(String algorithm,
+            Provider provider) throws NoSuchAlgorithmException {
+        Instance instance = GetInstance.getInstance("CertPathValidator",
+            CertPathValidatorSpi.class, algorithm, provider);
+        return new CertPathValidator((CertPathValidatorSpi)instance.impl,
+            instance.provider, algorithm);
+    }
+
+    /**
+     * Returns the {@code Provider} of this
+     * {@code CertPathValidator}.
+     *
+     * @return the {@code Provider} of this {@code CertPathValidator}
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Returns the algorithm name of this {@code CertPathValidator}.
+     *
+     * @return the algorithm name of this {@code CertPathValidator}
+     */
+    public final String getAlgorithm() {
+        return this.algorithm;
+    }
+
+    /**
+     * Validates the specified certification path using the specified
+     * algorithm parameter set.
+     * <p>
+     * The {@code CertPath} specified must be of a type that is
+     * supported by the validation algorithm, otherwise an
+     * {@code InvalidAlgorithmParameterException} will be thrown. For
+     * example, a {@code CertPathValidator} that implements the PKIX
+     * algorithm validates {@code CertPath} objects of type X.509.
+     *
+     * @param certPath the {@code CertPath} to be validated
+     * @param params the algorithm parameters
+     * @return the result of the validation algorithm
+     * @exception CertPathValidatorException if the {@code CertPath}
+     * does not validate
+     * @exception InvalidAlgorithmParameterException if the specified
+     * parameters or the type of the specified {@code CertPath} are
+     * inappropriate for this {@code CertPathValidator}
+     */
+    public final CertPathValidatorResult validate(CertPath certPath,
+        CertPathParameters params)
+        throws CertPathValidatorException, InvalidAlgorithmParameterException
+    {
+        return validatorSpi.engineValidate(certPath, params);
+    }
+
+    /**
+     * Returns the default {@code CertPathValidator} type as specified by
+     * the {@code certpathvalidator.type} security property, or the string
+     * {@literal "PKIX"} if no such property exists.
+     *
+     * <p>The default {@code CertPathValidator} type can be used by
+     * applications that do not want to use a hard-coded type when calling one
+     * of the {@code getInstance} methods, and want to provide a default
+     * type in case a user does not specify its own.
+     *
+     * <p>The default {@code CertPathValidator} type can be changed by
+     * setting the value of the {@code certpathvalidator.type} security
+     * property to the desired type.
+     *
+     * @see java.security.Security security properties
+     * @return the default {@code CertPathValidator} type as specified
+     * by the {@code certpathvalidator.type} security property, or the string
+     * {@literal "PKIX"} if no such property exists.
+     */
+    public final static String getDefaultType() {
+        String cpvtype =
+            AccessController.doPrivileged(new PrivilegedAction<String>() {
+                public String run() {
+                    return Security.getProperty(CPV_TYPE);
+                }
+            });
+        return (cpvtype == null) ? "PKIX" : cpvtype;
+    }
+
+    /**
+     * Returns a {@code CertPathChecker} that the encapsulated
+     * {@code CertPathValidatorSpi} implementation uses to check the revocation
+     * status of certificates. A PKIX implementation returns objects of
+     * type {@code PKIXRevocationChecker}. Each invocation of this method
+     * returns a new instance of {@code CertPathChecker}.
+     *
+     * <p>The primary purpose of this method is to allow callers to specify
+     * additional input parameters and options specific to revocation checking.
+     * See the class description for an example.
+     *
+     * @return a {@code CertPathChecker}
+     * @throws UnsupportedOperationException if the service provider does not
+     *         support this method
+     * @since 1.8
+     */
+    public final CertPathChecker getRevocationChecker() {
+        return validatorSpi.engineGetRevocationChecker();
+    }
+}
diff --git a/java/security/cert/CertPathValidatorException.java b/java/security/cert/CertPathValidatorException.java
new file mode 100644
index 0000000..7e6b916
--- /dev/null
+++ b/java/security/cert/CertPathValidatorException.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.InvalidObjectException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.security.GeneralSecurityException;
+
+/**
+ * An exception indicating one of a variety of problems encountered when
+ * validating a certification path.
+ * <p>
+ * A {@code CertPathValidatorException} provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown.
+ * <p>
+ * A {@code CertPathValidatorException} may also include the
+ * certification path that was being validated when the exception was thrown,
+ * the index of the certificate in the certification path that caused the
+ * exception to be thrown, and the reason that caused the failure. Use the
+ * {@link #getCertPath getCertPath}, {@link #getIndex getIndex}, and
+ * {@link #getReason getReason} methods to retrieve this information.
+ *
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathValidator
+ *
+ * @since       1.4
+ * @author      Yassir Elley
+ */
+public class CertPathValidatorException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -3083180014971893139L;
+
+    /**
+     * @serial the index of the certificate in the certification path
+     * that caused the exception to be thrown
+     */
+    private int index = -1;
+
+    /**
+     * @serial the {@code CertPath} that was being validated when
+     * the exception was thrown
+     */
+    private CertPath certPath;
+
+    /**
+     * @serial the reason the validation failed
+     */
+    private Reason reason = BasicReason.UNSPECIFIED;
+
+    /**
+     * Creates a {@code CertPathValidatorException} with
+     * no detail message.
+     */
+    public CertPathValidatorException() {
+        this(null, null);
+    }
+
+    /**
+     * Creates a {@code CertPathValidatorException} with the given
+     * detail message. A detail message is a {@code String} that
+     * describes this particular exception.
+     *
+     * @param msg the detail message
+     */
+    public CertPathValidatorException(String msg) {
+        this(msg, null);
+    }
+
+    /**
+     * Creates a {@code CertPathValidatorException} that wraps the
+     * specified throwable. This allows any exception to be converted into a
+     * {@code CertPathValidatorException}, while retaining information
+     * about the wrapped exception, which may be useful for debugging. The
+     * detail message is set to ({@code cause==null ? null : cause.toString()})
+     * (which typically contains the class and detail message of
+     * cause).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause getCause()} method). (A {@code null} value is
+     * permitted, and indicates that the cause is nonexistent or unknown.)
+     */
+    public CertPathValidatorException(Throwable cause) {
+        this((cause == null ? null : cause.toString()), cause);
+    }
+
+    /**
+     * Creates a {@code CertPathValidatorException} with the specified
+     * detail message and cause.
+     *
+     * @param msg the detail message
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause getCause()} method). (A {@code null} value is
+     * permitted, and indicates that the cause is nonexistent or unknown.)
+     */
+    public CertPathValidatorException(String msg, Throwable cause) {
+        this(msg, cause, null, -1);
+    }
+
+    /**
+     * Creates a {@code CertPathValidatorException} with the specified
+     * detail message, cause, certification path, and index.
+     *
+     * @param msg the detail message (or {@code null} if none)
+     * @param cause the cause (or {@code null} if none)
+     * @param certPath the certification path that was in the process of
+     * being validated when the error was encountered
+     * @param index the index of the certificate in the certification path
+     * that caused the error (or -1 if not applicable). Note that
+     * the list of certificates in a {@code CertPath} is zero based.
+     * @throws IndexOutOfBoundsException if the index is out of range
+     * {@code (index < -1 || (certPath != null && index >=
+     * certPath.getCertificates().size()) }
+     * @throws IllegalArgumentException if {@code certPath} is
+     * {@code null} and {@code index} is not -1
+     */
+    public CertPathValidatorException(String msg, Throwable cause,
+            CertPath certPath, int index) {
+        this(msg, cause, certPath, index, BasicReason.UNSPECIFIED);
+    }
+
+    /**
+     * Creates a {@code CertPathValidatorException} with the specified
+     * detail message, cause, certification path, index, and reason.
+     *
+     * @param msg the detail message (or {@code null} if none)
+     * @param cause the cause (or {@code null} if none)
+     * @param certPath the certification path that was in the process of
+     * being validated when the error was encountered
+     * @param index the index of the certificate in the certification path
+     * that caused the error (or -1 if not applicable). Note that
+     * the list of certificates in a {@code CertPath} is zero based.
+     * @param reason the reason the validation failed
+     * @throws IndexOutOfBoundsException if the index is out of range
+     * {@code (index < -1 || (certPath != null && index >=
+     * certPath.getCertificates().size()) }
+     * @throws IllegalArgumentException if {@code certPath} is
+     * {@code null} and {@code index} is not -1
+     * @throws NullPointerException if {@code reason} is {@code null}
+     *
+     * @since 1.7
+     */
+    public CertPathValidatorException(String msg, Throwable cause,
+            CertPath certPath, int index, Reason reason) {
+        super(msg, cause);
+        if (certPath == null && index != -1) {
+            throw new IllegalArgumentException();
+        }
+        if (index < -1 ||
+            (certPath != null && index >= certPath.getCertificates().size())) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (reason == null) {
+            throw new NullPointerException("reason can't be null");
+        }
+        this.certPath = certPath;
+        this.index = index;
+        this.reason = reason;
+    }
+
+    /**
+     * Returns the certification path that was being validated when
+     * the exception was thrown.
+     *
+     * @return the {@code CertPath} that was being validated when
+     * the exception was thrown (or {@code null} if not specified)
+     */
+    public CertPath getCertPath() {
+        return this.certPath;
+    }
+
+    /**
+     * Returns the index of the certificate in the certification path
+     * that caused the exception to be thrown. Note that the list of
+     * certificates in a {@code CertPath} is zero based. If no
+     * index has been set, -1 is returned.
+     *
+     * @return the index that has been set, or -1 if none has been set
+     */
+    public int getIndex() {
+        return this.index;
+    }
+
+    /**
+     * Returns the reason that the validation failed. The reason is
+     * associated with the index of the certificate returned by
+     * {@link #getIndex}.
+     *
+     * @return the reason that the validation failed, or
+     *    {@code BasicReason.UNSPECIFIED} if a reason has not been
+     *    specified
+     *
+     * @since 1.7
+     */
+    public Reason getReason() {
+        return this.reason;
+    }
+
+    private void readObject(ObjectInputStream stream)
+        throws ClassNotFoundException, IOException {
+        stream.defaultReadObject();
+        if (reason == null) {
+            reason = BasicReason.UNSPECIFIED;
+        }
+        if (certPath == null && index != -1) {
+            throw new InvalidObjectException("certpath is null and index != -1");
+        }
+        if (index < -1 ||
+            (certPath != null && index >= certPath.getCertificates().size())) {
+            throw new InvalidObjectException("index out of range");
+        }
+    }
+
+    /**
+     * The reason the validation algorithm failed.
+     *
+     * @since 1.7
+     */
+    public static interface Reason extends java.io.Serializable { }
+
+
+    /**
+     * The BasicReason enumerates the potential reasons that a certification
+     * path of any type may be invalid.
+     *
+     * @since 1.7
+     */
+    public static enum BasicReason implements Reason {
+        /**
+         * Unspecified reason.
+         */
+        UNSPECIFIED,
+
+        /**
+         * The certificate is expired.
+         */
+        EXPIRED,
+
+        /**
+         * The certificate is not yet valid.
+         */
+        NOT_YET_VALID,
+
+        /**
+         * The certificate is revoked.
+         */
+        REVOKED,
+
+        /**
+         * The revocation status of the certificate could not be determined.
+         */
+        UNDETERMINED_REVOCATION_STATUS,
+
+        /**
+         * The signature is invalid.
+         */
+        INVALID_SIGNATURE,
+
+        /**
+         * The public key or the signature algorithm has been constrained.
+         */
+        ALGORITHM_CONSTRAINED
+    }
+}
diff --git a/java/security/cert/CertPathValidatorResult.java b/java/security/cert/CertPathValidatorResult.java
new file mode 100644
index 0000000..ae07dc4
--- /dev/null
+++ b/java/security/cert/CertPathValidatorResult.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * A specification of the result of a certification path validator algorithm.
+ * <p>
+ * The purpose of this interface is to group (and provide type safety
+ * for) all certification path validator results. All results returned
+ * by the {@link CertPathValidator#validate CertPathValidator.validate}
+ * method must implement this interface.
+ *
+ * @see CertPathValidator
+ *
+ * @since       1.4
+ * @author      Yassir Elley
+ */
+public interface CertPathValidatorResult extends Cloneable {
+
+    /**
+     * Makes a copy of this {@code CertPathValidatorResult}. Changes to the
+     * copy will not affect the original and vice versa.
+     *
+     * @return a copy of this {@code CertPathValidatorResult}
+     */
+    Object clone();
+}
diff --git a/java/security/cert/CertPathValidatorSpi.java b/java/security/cert/CertPathValidatorSpi.java
new file mode 100644
index 0000000..02d503c
--- /dev/null
+++ b/java/security/cert/CertPathValidatorSpi.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+
+/**
+ *
+ * The <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@link CertPathValidator CertPathValidator} class. All
+ * {@code CertPathValidator} implementations must include a class (the
+ * SPI class) that extends this class ({@code CertPathValidatorSpi})
+ * and implements all of its methods. In general, instances of this class
+ * should only be accessed through the {@code CertPathValidator} class.
+ * For details, see the Java Cryptography Architecture.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Instances of this class need not be protected against concurrent
+ * access from multiple threads. Threads that need to access a single
+ * {@code CertPathValidatorSpi} instance concurrently should synchronize
+ * amongst themselves and provide the necessary locking before calling the
+ * wrapping {@code CertPathValidator} object.
+ * <p>
+ * However, implementations of {@code CertPathValidatorSpi} may still
+ * encounter concurrency issues, since multiple threads each
+ * manipulating a different {@code CertPathValidatorSpi} instance need not
+ * synchronize.
+ *
+ * @since       1.4
+ * @author      Yassir Elley
+ */
+public abstract class CertPathValidatorSpi {
+
+    /**
+     * The default constructor.
+     */
+    public CertPathValidatorSpi() {}
+
+    /**
+     * Validates the specified certification path using the specified
+     * algorithm parameter set.
+     * <p>
+     * The {@code CertPath} specified must be of a type that is
+     * supported by the validation algorithm, otherwise an
+     * {@code InvalidAlgorithmParameterException} will be thrown. For
+     * example, a {@code CertPathValidator} that implements the PKIX
+     * algorithm validates {@code CertPath} objects of type X.509.
+     *
+     * @param certPath the {@code CertPath} to be validated
+     * @param params the algorithm parameters
+     * @return the result of the validation algorithm
+     * @exception CertPathValidatorException if the {@code CertPath}
+     * does not validate
+     * @exception InvalidAlgorithmParameterException if the specified
+     * parameters or the type of the specified {@code CertPath} are
+     * inappropriate for this {@code CertPathValidator}
+     */
+    public abstract CertPathValidatorResult
+        engineValidate(CertPath certPath, CertPathParameters params)
+        throws CertPathValidatorException, InvalidAlgorithmParameterException;
+
+    /**
+     * Returns a {@code CertPathChecker} that this implementation uses to
+     * check the revocation status of certificates. A PKIX implementation
+     * returns objects of type {@code PKIXRevocationChecker}.
+     *
+     * <p>The primary purpose of this method is to allow callers to specify
+     * additional input parameters and options specific to revocation checking.
+     * See the class description of {@code CertPathValidator} for an example.
+     *
+     * <p>This method was added to version 1.8 of the Java Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method cannot be abstract and by default throws
+     * an {@code UnsupportedOperationException}.
+     *
+     * @return a {@code CertPathChecker} that this implementation uses to
+     * check the revocation status of certificates
+     * @throws UnsupportedOperationException if this method is not supported
+     * @since 1.8
+     */
+    public CertPathChecker engineGetRevocationChecker() {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/java/security/cert/CertSelector.java b/java/security/cert/CertSelector.java
new file mode 100644
index 0000000..a06cc84
--- /dev/null
+++ b/java/security/cert/CertSelector.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * A selector that defines a set of criteria for selecting
+ * {@code Certificate}s. Classes that implement this interface
+ * are often used to specify which {@code Certificate}s should
+ * be retrieved from a {@code CertStore}.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this interface are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see Certificate
+ * @see CertStore
+ * @see CertStore#getCertificates
+ *
+ * @author      Steve Hanna
+ * @since       1.4
+ */
+public interface CertSelector extends Cloneable {
+
+    /**
+     * Decides whether a {@code Certificate} should be selected.
+     *
+     * @param   cert    the {@code Certificate} to be checked
+     * @return  {@code true} if the {@code Certificate}
+     * should be selected, {@code false} otherwise
+     */
+    boolean match(Certificate cert);
+
+    /**
+     * Makes a copy of this {@code CertSelector}. Changes to the
+     * copy will not affect the original and vice versa.
+     *
+     * @return a copy of this {@code CertSelector}
+     */
+    Object clone();
+}
diff --git a/java/security/cert/CertStore.java b/java/security/cert/CertStore.java
new file mode 100644
index 0000000..6eaee5c
--- /dev/null
+++ b/java/security/cert/CertStore.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.Security;
+import java.util.Collection;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * A class for retrieving {@code Certificate}s and {@code CRL}s
+ * from a repository.
+ * <p>
+ * This class uses a provider-based architecture.
+ * To create a {@code CertStore}, call one of the static
+ * {@code getInstance} methods, passing in the type of
+ * {@code CertStore} desired, any applicable initialization parameters
+ * and optionally the name of the provider desired.
+ * <p>
+ * Once the {@code CertStore} has been created, it can be used to
+ * retrieve {@code Certificate}s and {@code CRL}s by calling its
+ * {@link #getCertificates(CertSelector selector) getCertificates} and
+ * {@link #getCRLs(CRLSelector selector) getCRLs} methods.
+ * <p>
+ * Unlike a {@link java.security.KeyStore KeyStore}, which provides access
+ * to a cache of private keys and trusted certificates, a
+ * {@code CertStore} is designed to provide access to a potentially
+ * vast repository of untrusted certificates and CRLs. For example, an LDAP
+ * implementation of {@code CertStore} provides access to certificates
+ * and CRLs stored in one or more directories using the LDAP protocol and the
+ * schema as defined in the RFC service attribute.
+ *
+ * <p> Android provides the following <code>CertStore</code> types:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>Collection</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ *
+ * This type is described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
+ * CertStore section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * All public methods of {@code CertStore} objects must be thread-safe.
+ * That is, multiple threads may concurrently invoke these methods on a
+ * single {@code CertStore} object (or more than one) with no
+ * ill effects. This allows a {@code CertPathBuilder} to search for a
+ * CRL while simultaneously searching for further certificates, for instance.
+ * <p>
+ * The static methods of this class are also guaranteed to be thread-safe.
+ * Multiple threads may concurrently invoke the static methods defined in
+ * this class with no ill effects.
+ *
+ * @since       1.4
+ * @author      Sean Mullan, Steve Hanna
+ */
+public class CertStore {
+    /*
+     * Constant to lookup in the Security properties file to determine
+     * the default certstore type. In the Security properties file, the
+     * default certstore type is given as:
+     * <pre>
+     * certstore.type=LDAP
+     * </pre>
+     */
+    private static final String CERTSTORE_TYPE = "certstore.type";
+    private CertStoreSpi storeSpi;
+    private Provider provider;
+    private String type;
+    private CertStoreParameters params;
+
+    /**
+     * Creates a {@code CertStore} object of the given type, and
+     * encapsulates the given provider implementation (SPI object) in it.
+     *
+     * @param storeSpi the provider implementation
+     * @param provider the provider
+     * @param type the type
+     * @param params the initialization parameters (may be {@code null})
+     */
+    protected CertStore(CertStoreSpi storeSpi, Provider provider,
+                        String type, CertStoreParameters params) {
+        this.storeSpi = storeSpi;
+        this.provider = provider;
+        this.type = type;
+        if (params != null)
+            this.params = (CertStoreParameters) params.clone();
+    }
+
+    /**
+     * Returns a {@code Collection} of {@code Certificate}s that
+     * match the specified selector. If no {@code Certificate}s
+     * match the selector, an empty {@code Collection} will be returned.
+     * <p>
+     * For some {@code CertStore} types, the resulting
+     * {@code Collection} may not contain <b>all</b> of the
+     * {@code Certificate}s that match the selector. For instance,
+     * an LDAP {@code CertStore} may not search all entries in the
+     * directory. Instead, it may just search entries that are likely to
+     * contain the {@code Certificate}s it is looking for.
+     * <p>
+     * Some {@code CertStore} implementations (especially LDAP
+     * {@code CertStore}s) may throw a {@code CertStoreException}
+     * unless a non-null {@code CertSelector} is provided that
+     * includes specific criteria that can be used to find the certificates.
+     * Issuer and/or subject names are especially useful criteria.
+     *
+     * @param selector A {@code CertSelector} used to select which
+     *  {@code Certificate}s should be returned. Specify {@code null}
+     *  to return all {@code Certificate}s (if supported).
+     * @return A {@code Collection} of {@code Certificate}s that
+     *         match the specified selector (never {@code null})
+     * @throws CertStoreException if an exception occurs
+     */
+    public final Collection<? extends Certificate> getCertificates
+            (CertSelector selector) throws CertStoreException {
+        return storeSpi.engineGetCertificates(selector);
+    }
+
+    /**
+     * Returns a {@code Collection} of {@code CRL}s that
+     * match the specified selector. If no {@code CRL}s
+     * match the selector, an empty {@code Collection} will be returned.
+     * <p>
+     * For some {@code CertStore} types, the resulting
+     * {@code Collection} may not contain <b>all</b> of the
+     * {@code CRL}s that match the selector. For instance,
+     * an LDAP {@code CertStore} may not search all entries in the
+     * directory. Instead, it may just search entries that are likely to
+     * contain the {@code CRL}s it is looking for.
+     * <p>
+     * Some {@code CertStore} implementations (especially LDAP
+     * {@code CertStore}s) may throw a {@code CertStoreException}
+     * unless a non-null {@code CRLSelector} is provided that
+     * includes specific criteria that can be used to find the CRLs.
+     * Issuer names and/or the certificate to be checked are especially useful.
+     *
+     * @param selector A {@code CRLSelector} used to select which
+     *  {@code CRL}s should be returned. Specify {@code null}
+     *  to return all {@code CRL}s (if supported).
+     * @return A {@code Collection} of {@code CRL}s that
+     *         match the specified selector (never {@code null})
+     * @throws CertStoreException if an exception occurs
+     */
+    public final Collection<? extends CRL> getCRLs(CRLSelector selector)
+            throws CertStoreException {
+        return storeSpi.engineGetCRLs(selector);
+    }
+
+    /**
+     * Returns a {@code CertStore} object that implements the specified
+     * {@code CertStore} type and is initialized with the specified
+     * parameters.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new CertStore object encapsulating the
+     * CertStoreSpi implementation from the first
+     * Provider that supports the specified type is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p>The {@code CertStore} that is returned is initialized with the
+     * specified {@code CertStoreParameters}. The type of parameters
+     * needed may vary between different types of {@code CertStore}s.
+     * Note that the specified {@code CertStoreParameters} object is
+     * cloned.
+     *
+     * @param type the name of the requested {@code CertStore} type.
+     * See the CertStore section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard types.
+     *
+     * @param params the initialization parameters (may be {@code null}).
+     *
+     * @return a {@code CertStore} object that implements the specified
+     *          {@code CertStore} type.
+     *
+     * @throws NoSuchAlgorithmException if no Provider supports a
+     *          CertStoreSpi implementation for the specified type.
+     *
+     * @throws InvalidAlgorithmParameterException if the specified
+     *          initialization parameters are inappropriate for this
+     *          {@code CertStore}.
+     *
+     * @see java.security.Provider
+     */
+    public static CertStore getInstance(String type, CertStoreParameters params)
+            throws InvalidAlgorithmParameterException,
+            NoSuchAlgorithmException {
+        try {
+            Instance instance = GetInstance.getInstance("CertStore",
+                CertStoreSpi.class, type, params);
+            return new CertStore((CertStoreSpi)instance.impl,
+                instance.provider, type, params);
+        } catch (NoSuchAlgorithmException e) {
+            return handleException(e);
+        }
+    }
+
+    private static CertStore handleException(NoSuchAlgorithmException e)
+            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+        Throwable cause = e.getCause();
+        if (cause instanceof InvalidAlgorithmParameterException) {
+            throw (InvalidAlgorithmParameterException)cause;
+        }
+        throw e;
+    }
+
+    /**
+     * Returns a {@code CertStore} object that implements the specified
+     * {@code CertStore} type.
+     *
+     * <p> A new CertStore object encapsulating the
+     * CertStoreSpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * <p>The {@code CertStore} that is returned is initialized with the
+     * specified {@code CertStoreParameters}. The type of parameters
+     * needed may vary between different types of {@code CertStore}s.
+     * Note that the specified {@code CertStoreParameters} object is
+     * cloned.
+     *
+     * @param type the requested {@code CertStore} type.
+     * See the CertStore section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard types.
+     *
+     * @param params the initialization parameters (may be {@code null}).
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a {@code CertStore} object that implements the
+     *          specified type.
+     *
+     * @throws NoSuchAlgorithmException if a CertStoreSpi
+     *          implementation for the specified type is not
+     *          available from the specified provider.
+     *
+     * @throws InvalidAlgorithmParameterException if the specified
+     *          initialization parameters are inappropriate for this
+     *          {@code CertStore}.
+     *
+     * @throws NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static CertStore getInstance(String type,
+            CertStoreParameters params, String provider)
+            throws InvalidAlgorithmParameterException,
+            NoSuchAlgorithmException, NoSuchProviderException {
+        try {
+            Instance instance = GetInstance.getInstance("CertStore",
+                CertStoreSpi.class, type, params, provider);
+            return new CertStore((CertStoreSpi)instance.impl,
+                instance.provider, type, params);
+        } catch (NoSuchAlgorithmException e) {
+            return handleException(e);
+        }
+    }
+
+    /**
+     * Returns a {@code CertStore} object that implements the specified
+     * {@code CertStore} type.
+     *
+     * <p> A new CertStore object encapsulating the
+     * CertStoreSpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * <p>The {@code CertStore} that is returned is initialized with the
+     * specified {@code CertStoreParameters}. The type of parameters
+     * needed may vary between different types of {@code CertStore}s.
+     * Note that the specified {@code CertStoreParameters} object is
+     * cloned.
+     *
+     * @param type the requested {@code CertStore} type.
+     * See the CertStore section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertStore">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard types.
+     *
+     * @param params the initialization parameters (may be {@code null}).
+     *
+     * @param provider the provider.
+     *
+     * @return a {@code CertStore} object that implements the
+     *          specified type.
+     *
+     * @exception NoSuchAlgorithmException if a CertStoreSpi
+     *          implementation for the specified type is not available
+     *          from the specified Provider object.
+     *
+     * @throws InvalidAlgorithmParameterException if the specified
+     *          initialization parameters are inappropriate for this
+     *          {@code CertStore}
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null.
+     *
+     * @see java.security.Provider
+     */
+    public static CertStore getInstance(String type, CertStoreParameters params,
+            Provider provider) throws NoSuchAlgorithmException,
+            InvalidAlgorithmParameterException {
+        try {
+            Instance instance = GetInstance.getInstance("CertStore",
+                CertStoreSpi.class, type, params, provider);
+            return new CertStore((CertStoreSpi)instance.impl,
+                instance.provider, type, params);
+        } catch (NoSuchAlgorithmException e) {
+            return handleException(e);
+        }
+    }
+
+    /**
+     * Returns the parameters used to initialize this {@code CertStore}.
+     * Note that the {@code CertStoreParameters} object is cloned before
+     * it is returned.
+     *
+     * @return the parameters used to initialize this {@code CertStore}
+     * (may be {@code null})
+     */
+    public final CertStoreParameters getCertStoreParameters() {
+        return (params == null ? null : (CertStoreParameters) params.clone());
+    }
+
+    /**
+     * Returns the type of this {@code CertStore}.
+     *
+     * @return the type of this {@code CertStore}
+     */
+    public final String getType() {
+        return this.type;
+    }
+
+    /**
+     * Returns the provider of this {@code CertStore}.
+     *
+     * @return the provider of this {@code CertStore}
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Returns the default {@code CertStore} type as specified by the
+     * {@code certstore.type} security property, or the string
+     * {@literal "LDAP"} if no such property exists.
+     *
+     * <p>The default {@code CertStore} type can be used by applications
+     * that do not want to use a hard-coded type when calling one of the
+     * {@code getInstance} methods, and want to provide a default
+     * {@code CertStore} type in case a user does not specify its own.
+     *
+     * <p>The default {@code CertStore} type can be changed by setting
+     * the value of the {@code certstore.type} security property to the
+     * desired type.
+     *
+     * @see java.security.Security security properties
+     * @return the default {@code CertStore} type as specified by the
+     * {@code certstore.type} security property, or the string
+     * {@literal "LDAP"} if no such property exists.
+     */
+    public final static String getDefaultType() {
+        String cstype;
+        cstype = AccessController.doPrivileged(new PrivilegedAction<String>() {
+            public String run() {
+                return Security.getProperty(CERTSTORE_TYPE);
+            }
+        });
+        if (cstype == null) {
+            cstype = "LDAP";
+        }
+        return cstype;
+    }
+}
diff --git a/java/security/cert/CertStoreException.java b/java/security/cert/CertStoreException.java
new file mode 100644
index 0000000..77b1c23
--- /dev/null
+++ b/java/security/cert/CertStoreException.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * An exception indicating one of a variety of problems retrieving
+ * certificates and CRLs from a {@code CertStore}.
+ * <p>
+ * A {@code CertStoreException} provides support for wrapping
+ * exceptions. The {@link #getCause getCause} method returns the throwable,
+ * if any, that caused this exception to be thrown.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertStore
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public class CertStoreException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 2395296107471573245L;
+
+    /**
+     * Creates a {@code CertStoreException} with {@code null} as
+     * its detail message.
+     */
+    public CertStoreException() {
+        super();
+    }
+
+    /**
+     * Creates a {@code CertStoreException} with the given detail
+     * message. A detail message is a {@code String} that describes this
+     * particular exception.
+     *
+     * @param msg the detail message
+     */
+    public CertStoreException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code CertStoreException} that wraps the specified
+     * throwable. This allows any exception to be converted into a
+     * {@code CertStoreException}, while retaining information about the
+     * cause, which may be useful for debugging. The detail message is
+     * set to ({@code cause==null ? null : cause.toString()}) (which
+     * typically contains the class and detail message of cause).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause getCause()} method). (A {@code null} value is
+     * permitted, and indicates that the cause is nonexistent or unknown.)
+     */
+    public CertStoreException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Creates a {@code CertStoreException} with the specified detail
+     * message and cause.
+     *
+     * @param msg the detail message
+     * @param cause the cause (which is saved for later retrieval by the
+     * {@link #getCause getCause()} method). (A {@code null} value is
+     * permitted, and indicates that the cause is nonexistent or unknown.)
+     */
+    public CertStoreException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
diff --git a/java/security/cert/CertStoreParameters.java b/java/security/cert/CertStoreParameters.java
new file mode 100644
index 0000000..9938ba2
--- /dev/null
+++ b/java/security/cert/CertStoreParameters.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * A specification of {@code CertStore} parameters.
+ * <p>
+ * The purpose of this interface is to group (and provide type safety for)
+ * all {@code CertStore} parameter specifications. All
+ * {@code CertStore} parameter specifications must implement this
+ * interface.
+ * <p>
+ * Typically, a {@code CertStoreParameters} object is passed as a parameter
+ * to one of the {@link CertStore#getInstance CertStore.getInstance} methods.
+ * The {@code getInstance} method returns a {@code CertStore} that
+ * is used for retrieving {@code Certificate}s and {@code CRL}s. The
+ * {@code CertStore} that is returned is initialized with the specified
+ * parameters. The type of parameters needed may vary between different types
+ * of {@code CertStore}s.
+ *
+ * @see CertStore#getInstance
+ *
+ * @since       1.4
+ * @author      Steve Hanna
+ */
+public interface CertStoreParameters extends Cloneable {
+
+    /**
+     * Makes a copy of this {@code CertStoreParameters}.
+     * <p>
+     * The precise meaning of "copy" may depend on the class of
+     * the {@code CertStoreParameters} object. A typical implementation
+     * performs a "deep copy" of this object, but this is not an absolute
+     * requirement. Some implementations may perform a "shallow copy" of some
+     * or all of the fields of this object.
+     * <p>
+     * Note that the {@code CertStore.getInstance} methods make a copy
+     * of the specified {@code CertStoreParameters}. A deep copy
+     * implementation of {@code clone} is safer and more robust, as it
+     * prevents the caller from corrupting a shared {@code CertStore} by
+     * subsequently modifying the contents of its initialization parameters.
+     * However, a shallow copy implementation of {@code clone} is more
+     * appropriate for applications that need to hold a reference to a
+     * parameter contained in the {@code CertStoreParameters}. For example,
+     * a shallow copy clone allows an application to release the resources of
+     * a particular {@code CertStore} initialization parameter immediately,
+     * rather than waiting for the garbage collection mechanism. This should
+     * be done with the utmost care, since the {@code CertStore} may still
+     * be in use by other threads.
+     * <p>
+     * Each subclass should state the precise behavior of this method so
+     * that users and developers know what to expect.
+     *
+     * @return a copy of this {@code CertStoreParameters}
+     */
+    Object clone();
+}
diff --git a/java/security/cert/CertStoreSpi.java b/java/security/cert/CertStoreSpi.java
new file mode 100644
index 0000000..fc98e9e
--- /dev/null
+++ b/java/security/cert/CertStoreSpi.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.util.Collection;
+
+/**
+ * The <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@link CertStore CertStore} class. All {@code CertStore}
+ * implementations must include a class (the SPI class) that extends
+ * this class ({@code CertStoreSpi}), provides a constructor with
+ * a single argument of type {@code CertStoreParameters}, and implements
+ * all of its methods. In general, instances of this class should only be
+ * accessed through the {@code CertStore} class.
+ * For details, see the Java Cryptography Architecture.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * The public methods of all {@code CertStoreSpi} objects must be
+ * thread-safe. That is, multiple threads may concurrently invoke these
+ * methods on a single {@code CertStoreSpi} object (or more than one)
+ * with no ill effects. This allows a {@code CertPathBuilder} to search
+ * for a CRL while simultaneously searching for further certificates, for
+ * instance.
+ * <p>
+ * Simple {@code CertStoreSpi} implementations will probably ensure
+ * thread safety by adding a {@code synchronized} keyword to their
+ * {@code engineGetCertificates} and {@code engineGetCRLs} methods.
+ * More sophisticated ones may allow truly concurrent access.
+ *
+ * @since       1.4
+ * @author      Steve Hanna
+ */
+public abstract class CertStoreSpi {
+
+    /**
+     * The sole constructor.
+     *
+     * @param params the initialization parameters (may be {@code null})
+     * @throws InvalidAlgorithmParameterException if the initialization
+     * parameters are inappropriate for this {@code CertStoreSpi}
+     */
+    public CertStoreSpi(CertStoreParameters params)
+    throws InvalidAlgorithmParameterException { }
+
+    /**
+     * Returns a {@code Collection} of {@code Certificate}s that
+     * match the specified selector. If no {@code Certificate}s
+     * match the selector, an empty {@code Collection} will be returned.
+     * <p>
+     * For some {@code CertStore} types, the resulting
+     * {@code Collection} may not contain <b>all</b> of the
+     * {@code Certificate}s that match the selector. For instance,
+     * an LDAP {@code CertStore} may not search all entries in the
+     * directory. Instead, it may just search entries that are likely to
+     * contain the {@code Certificate}s it is looking for.
+     * <p>
+     * Some {@code CertStore} implementations (especially LDAP
+     * {@code CertStore}s) may throw a {@code CertStoreException}
+     * unless a non-null {@code CertSelector} is provided that includes
+     * specific criteria that can be used to find the certificates. Issuer
+     * and/or subject names are especially useful criteria.
+     *
+     * @param selector A {@code CertSelector} used to select which
+     *  {@code Certificate}s should be returned. Specify {@code null}
+     *  to return all {@code Certificate}s (if supported).
+     * @return A {@code Collection} of {@code Certificate}s that
+     *         match the specified selector (never {@code null})
+     * @throws CertStoreException if an exception occurs
+     */
+    public abstract Collection<? extends Certificate> engineGetCertificates
+            (CertSelector selector) throws CertStoreException;
+
+    /**
+     * Returns a {@code Collection} of {@code CRL}s that
+     * match the specified selector. If no {@code CRL}s
+     * match the selector, an empty {@code Collection} will be returned.
+     * <p>
+     * For some {@code CertStore} types, the resulting
+     * {@code Collection} may not contain <b>all</b> of the
+     * {@code CRL}s that match the selector. For instance,
+     * an LDAP {@code CertStore} may not search all entries in the
+     * directory. Instead, it may just search entries that are likely to
+     * contain the {@code CRL}s it is looking for.
+     * <p>
+     * Some {@code CertStore} implementations (especially LDAP
+     * {@code CertStore}s) may throw a {@code CertStoreException}
+     * unless a non-null {@code CRLSelector} is provided that includes
+     * specific criteria that can be used to find the CRLs. Issuer names
+     * and/or the certificate to be checked are especially useful.
+     *
+     * @param selector A {@code CRLSelector} used to select which
+     *  {@code CRL}s should be returned. Specify {@code null}
+     *  to return all {@code CRL}s (if supported).
+     * @return A {@code Collection} of {@code CRL}s that
+     *         match the specified selector (never {@code null})
+     * @throws CertStoreException if an exception occurs
+     */
+    public abstract Collection<? extends CRL> engineGetCRLs
+            (CRLSelector selector) throws CertStoreException;
+}
diff --git a/java/security/cert/Certificate.java b/java/security/cert/Certificate.java
new file mode 100644
index 0000000..1054498
--- /dev/null
+++ b/java/security/cert/Certificate.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.util.Arrays;
+
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.SignatureException;
+
+import sun.security.x509.X509CertImpl;
+
+/**
+ * <p>Abstract class for managing a variety of identity certificates.
+ * An identity certificate is a binding of a principal to a public key which
+ * is vouched for by another principal.  (A principal represents
+ * an entity such as an individual user, a group, or a corporation.)
+ *<p>
+ * This class is an abstraction for certificates that have different
+ * formats but important common uses.  For example, different types of
+ * certificates, such as X.509 and PGP, share general certificate
+ * functionality (like encoding and verifying) and
+ * some types of information (like a public key).
+ * <p>
+ * X.509, PGP, and SDSI certificates can all be implemented by
+ * subclassing the Certificate class, even though they contain different
+ * sets of information, and they store and retrieve the information in
+ * different ways.
+ *
+ * @see X509Certificate
+ * @see CertificateFactory
+ *
+ * @author Hemma Prafullchandra
+ */
+
+public abstract class Certificate implements java.io.Serializable {
+
+    private static final long serialVersionUID = -3585440601605666277L;
+
+    // the certificate type
+    private final String type;
+
+    /** Cache the hash code for the certiticate */
+    private int hash = -1; // Default to -1
+
+    /**
+     * Creates a certificate of the specified type.
+     *
+     * @param type the standard name of the certificate type.
+     * See the CertificateFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard certificate types.
+     */
+    protected Certificate(String type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type of this certificate.
+     *
+     * @return the type of this certificate.
+     */
+    public final String getType() {
+        return this.type;
+    }
+
+    /**
+     * Compares this certificate for equality with the specified
+     * object. If the {@code other} object is an
+     * {@code instanceof} {@code Certificate}, then
+     * its encoded form is retrieved and compared with the
+     * encoded form of this certificate.
+     *
+     * @param other the object to test for equality with this certificate.
+     * @return true iff the encoded forms of the two certificates
+     * match, false otherwise.
+     */
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof Certificate)) {
+            return false;
+        }
+        try {
+            byte[] thisCert = X509CertImpl.getEncodedInternal(this);
+            byte[] otherCert = X509CertImpl.getEncodedInternal((Certificate)other);
+
+            return Arrays.equals(thisCert, otherCert);
+        } catch (CertificateException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hashcode value for this certificate from its
+     * encoded form.
+     *
+     * @return the hashcode value.
+     */
+    public int hashCode() {
+        int h = hash;
+        if (h == -1) {
+            try {
+                h = Arrays.hashCode(X509CertImpl.getEncodedInternal(this));
+            } catch (CertificateException e) {
+                h = 0;
+            }
+            hash = h;
+        }
+        return h;
+    }
+
+    /**
+     * Returns the encoded form of this certificate. It is
+     * assumed that each certificate type would have only a single
+     * form of encoding; for example, X.509 certificates would
+     * be encoded as ASN.1 DER.
+     *
+     * @return the encoded form of this certificate
+     *
+     * @exception CertificateEncodingException if an encoding error occurs.
+     */
+    public abstract byte[] getEncoded()
+        throws CertificateEncodingException;
+
+    /**
+     * Verifies that this certificate was signed using the
+     * private key that corresponds to the specified public key.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception NoSuchProviderException if there's no default provider.
+     * @exception SignatureException on signature errors.
+     * @exception CertificateException on encoding errors.
+     */
+    public abstract void verify(PublicKey key)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException,
+        SignatureException;
+
+    /**
+     * Verifies that this certificate was signed using the
+     * private key that corresponds to the specified public key.
+     * This method uses the signature verification engine
+     * supplied by the specified provider.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     * @param sigProvider the name of the signature provider.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception NoSuchProviderException on incorrect provider.
+     * @exception SignatureException on signature errors.
+     * @exception CertificateException on encoding errors.
+     */
+    public abstract void verify(PublicKey key, String sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException,
+        SignatureException;
+
+    /**
+     * Verifies that this certificate was signed using the
+     * private key that corresponds to the specified public key.
+     * This method uses the signature verification engine
+     * supplied by the specified provider. Note that the specified
+     * Provider object does not have to be registered in the provider list.
+     *
+     * <p> This method was added to version 1.8 of the Java Platform
+     * Standard Edition. In order to maintain backwards compatibility with
+     * existing service providers, this method cannot be {@code abstract}
+     * and by default throws an {@code UnsupportedOperationException}.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     * @param sigProvider the signature provider.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception SignatureException on signature errors.
+     * @exception CertificateException on encoding errors.
+     * @exception UnsupportedOperationException if the method is not supported
+     * @since 1.8
+     */
+    public void verify(PublicKey key, Provider sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns a string representation of this certificate.
+     *
+     * @return a string representation of this certificate.
+     */
+    public abstract String toString();
+
+    /**
+     * Gets the public key from this certificate.
+     *
+     * @return the public key.
+     */
+    public abstract PublicKey getPublicKey();
+
+    /**
+     * Alternate Certificate class for serialization.
+     * @since 1.3
+     */
+    protected static class CertificateRep implements java.io.Serializable {
+
+        private static final long serialVersionUID = -8563758940495660020L;
+
+        private String type;
+        private byte[] data;
+
+        /**
+         * Construct the alternate Certificate class with the Certificate
+         * type and Certificate encoding bytes.
+         *
+         * <p>
+         *
+         * @param type the standard name of the Certificate type. <p>
+         *
+         * @param data the Certificate data.
+         */
+        protected CertificateRep(String type, byte[] data) {
+            this.type = type;
+            this.data = data;
+        }
+
+        /**
+         * Resolve the Certificate Object.
+         *
+         * <p>
+         *
+         * @return the resolved Certificate Object
+         *
+         * @throws java.io.ObjectStreamException if the Certificate
+         *      could not be resolved
+         */
+        protected Object readResolve() throws java.io.ObjectStreamException {
+            try {
+                CertificateFactory cf = CertificateFactory.getInstance(type);
+                return cf.generateCertificate
+                        (new java.io.ByteArrayInputStream(data));
+            } catch (CertificateException e) {
+                throw new java.io.NotSerializableException
+                                ("java.security.cert.Certificate: " +
+                                type +
+                                ": " +
+                                e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Replace the Certificate to be serialized.
+     *
+     * @return the alternate Certificate object to be serialized
+     *
+     * @throws java.io.ObjectStreamException if a new object representing
+     * this Certificate could not be created
+     * @since 1.3
+     */
+    protected Object writeReplace() throws java.io.ObjectStreamException {
+        try {
+            return new CertificateRep(type, getEncoded());
+        } catch (CertificateException e) {
+            throw new java.io.NotSerializableException
+                                ("java.security.cert.Certificate: " +
+                                type +
+                                ": " +
+                                e.getMessage());
+        }
+    }
+}
diff --git a/java/security/cert/CertificateEncodingException.java b/java/security/cert/CertificateEncodingException.java
new file mode 100644
index 0000000..618ee0a
--- /dev/null
+++ b/java/security/cert/CertificateEncodingException.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * Certificate Encoding Exception. This is thrown whenever an error
+ * occurs while attempting to encode a certificate.
+ *
+ * @author Hemma Prafullchandra
+ */
+public class CertificateEncodingException extends CertificateException {
+
+    private static final long serialVersionUID = 6219492851589449162L;
+
+    /**
+     * Constructs a CertificateEncodingException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public CertificateEncodingException() {
+        super();
+    }
+
+    /**
+     * Constructs a CertificateEncodingException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param message the detail message.
+     */
+    public CertificateEncodingException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a {@code CertificateEncodingException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CertificateEncodingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code CertificateEncodingException}
+     * with the specified cause and a detail message of
+     * {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CertificateEncodingException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/cert/CertificateException.java b/java/security/cert/CertificateException.java
new file mode 100644
index 0000000..f663054
--- /dev/null
+++ b/java/security/cert/CertificateException.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This exception indicates one of a variety of certificate problems.
+ *
+ * @author Hemma Prafullchandra
+ * @see Certificate
+ */
+public class CertificateException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 3192535253797119798L;
+
+    /**
+     * Constructs a certificate exception with no detail message. A detail
+     * message is a String that describes this particular exception.
+     */
+    public CertificateException() {
+        super();
+    }
+
+    /**
+     * Constructs a certificate exception with the given detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public CertificateException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code CertificateException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CertificateException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code CertificateException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CertificateException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/cert/CertificateExpiredException.java b/java/security/cert/CertificateExpiredException.java
new file mode 100644
index 0000000..9de0c23
--- /dev/null
+++ b/java/security/cert/CertificateExpiredException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * Certificate Expired Exception. This is thrown whenever the current
+ * {@code Date} or the specified {@code Date} is after the
+ * {@code notAfter} date/time specified in the validity period
+ * of the certificate.
+ *
+ * @author Hemma Prafullchandra
+ */
+public class CertificateExpiredException extends CertificateException {
+
+    private static final long serialVersionUID = 9071001339691533771L;
+
+    /**
+     * Constructs a CertificateExpiredException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public CertificateExpiredException() {
+        super();
+    }
+
+    /**
+     * Constructs a CertificateExpiredException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param message the detail message.
+     */
+    public CertificateExpiredException(String message) {
+        super(message);
+    }
+}
diff --git a/java/security/cert/CertificateFactory.java b/java/security/cert/CertificateFactory.java
new file mode 100644
index 0000000..a47b788
--- /dev/null
+++ b/java/security/cert/CertificateFactory.java
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.security.Provider;
+import java.security.Security;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import sun.security.jca.*;
+import sun.security.jca.GetInstance.Instance;
+
+/**
+ * This class defines the functionality of a certificate factory, which is
+ * used to generate certificate, certification path ({@code CertPath})
+ * and certificate revocation list (CRL) objects from their encodings.
+ *
+ * <p>For encodings consisting of multiple certificates, use
+ * {@code generateCertificates} when you want to
+ * parse a collection of possibly unrelated certificates. Otherwise,
+ * use {@code generateCertPath} when you want to generate
+ * a {@code CertPath} (a certificate chain) and subsequently
+ * validate it with a {@code CertPathValidator}.
+ *
+ * <p>A certificate factory for X.509 must return certificates that are an
+ * instance of {@code java.security.cert.X509Certificate}, and CRLs
+ * that are an instance of {@code java.security.cert.X509CRL}.
+ *
+ * <p>The following example reads a file with Base64 encoded certificates,
+ * which are each bounded at the beginning by -----BEGIN CERTIFICATE-----, and
+ * bounded at the end by -----END CERTIFICATE-----. We convert the
+ * {@code FileInputStream} (which does not support {@code mark}
+ * and {@code reset}) to a {@code BufferedInputStream} (which
+ * supports those methods), so that each call to
+ * {@code generateCertificate} consumes only one certificate, and the
+ * read position of the input stream is positioned to the next certificate in
+ * the file:
+ *
+ * <pre>{@code
+ * FileInputStream fis = new FileInputStream(filename);
+ * BufferedInputStream bis = new BufferedInputStream(fis);
+ *
+ * CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ *
+ * while (bis.available() > 0) {
+ *    Certificate cert = cf.generateCertificate(bis);
+ *    System.out.println(cert.toString());
+ * }
+ * }</pre>
+ *
+ * <p>The following example parses a PKCS#7-formatted certificate reply stored
+ * in a file and extracts all the certificates from it:
+ *
+ * <pre>
+ * FileInputStream fis = new FileInputStream(filename);
+ * CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ * Collection c = cf.generateCertificates(fis);
+ * Iterator i = c.iterator();
+ * while (i.hasNext()) {
+ *    Certificate cert = (Certificate)i.next();
+ *    System.out.println(cert);
+ * }
+ * </pre>
+ *
+ * <p> Android provides the following <code>CertificateFactory</code> types:
+ * <table>
+ *   <thead>
+ *     <tr>
+ *       <th>Algorithm</th>
+ *       <th>Supported API Levels</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *     <tr>
+ *       <td>X.509</td>
+ *       <td>1+</td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ * and the following <code>CertPath</code> encodings:
+ * <table>
+ *     <thead>
+ *         <tr>
+ *             <th>Name</th>
+ *             <th>Supported (API Levels)</th>
+ *         </tr>
+ *     </thead>
+ *     <tbody>
+ *         <tr>
+ *             <td>PKCS7</td>
+ *             <td>1+</td>
+ *         </tr>
+ *         <tr>
+ *             <td>PkiPath</td>
+ *             <td>1+</td>
+ *         </tr>
+ *     </tbody>
+ * </table>
+ *
+ * The type and encodings are described in the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
+ * CertificateFactory section</a> and the <a href=
+ * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
+ * CertPath Encodings section</a> of the
+ * Java Cryptography Architecture Standard Algorithm Name Documentation.
+ *
+ * @author Hemma Prafullchandra
+ * @author Jan Luehe
+ * @author Sean Mullan
+ *
+ * @see Certificate
+ * @see X509Certificate
+ * @see CertPath
+ * @see CRL
+ * @see X509CRL
+ *
+ * @since 1.2
+ */
+
+public class CertificateFactory {
+
+    // The certificate type
+    private String type;
+
+    // The provider
+    private Provider provider;
+
+    // The provider implementation
+    private CertificateFactorySpi certFacSpi;
+
+    /**
+     * Creates a CertificateFactory object of the given type, and encapsulates
+     * the given provider implementation (SPI object) in it.
+     *
+     * @param certFacSpi the provider implementation.
+     * @param provider the provider.
+     * @param type the certificate type.
+     */
+    protected CertificateFactory(CertificateFactorySpi certFacSpi,
+                                 Provider provider, String type)
+    {
+        this.certFacSpi = certFacSpi;
+        this.provider = provider;
+        this.type = type;
+    }
+
+    /**
+     * Returns a certificate factory object that implements the
+     * specified certificate type.
+     *
+     * <p> This method traverses the list of registered security Providers,
+     * starting with the most preferred Provider.
+     * A new CertificateFactory object encapsulating the
+     * CertificateFactorySpi implementation from the first
+     * Provider that supports the specified type is returned.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param type the name of the requested certificate type.
+     * See the CertificateFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard certificate types.
+     *
+     * @return a certificate factory object for the specified type.
+     *
+     * @exception CertificateException if no Provider supports a
+     *          CertificateFactorySpi implementation for the
+     *          specified type.
+     *
+     * @see java.security.Provider
+     */
+    public static final CertificateFactory getInstance(String type)
+            throws CertificateException {
+        try {
+            Instance instance = GetInstance.getInstance("CertificateFactory",
+                CertificateFactorySpi.class, type);
+            return new CertificateFactory((CertificateFactorySpi)instance.impl,
+                instance.provider, type);
+        } catch (NoSuchAlgorithmException e) {
+            throw new CertificateException(type + " not found", e);
+        }
+    }
+
+    /**
+     * Returns a certificate factory object for the specified
+     * certificate type.
+     *
+     * <p> A new CertificateFactory object encapsulating the
+     * CertificateFactorySpi implementation from the specified provider
+     * is returned.  The specified provider must be registered
+     * in the security provider list.
+     *
+     * <p> Note that the list of registered providers may be retrieved via
+     * the {@link Security#getProviders() Security.getProviders()} method.
+     *
+     * @param type the certificate type.
+     * See the CertificateFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard certificate types.
+     *
+     * @param provider the name of the provider.
+     *
+     * @return a certificate factory object for the specified type.
+     *
+     * @exception CertificateException if a CertificateFactorySpi
+     *          implementation for the specified algorithm is not
+     *          available from the specified provider.
+     *
+     * @exception NoSuchProviderException if the specified provider is not
+     *          registered in the security provider list.
+     *
+     * @exception IllegalArgumentException if the provider name is null
+     *          or empty.
+     *
+     * @see java.security.Provider
+     */
+    public static final CertificateFactory getInstance(String type,
+            String provider) throws CertificateException,
+            NoSuchProviderException {
+        try {
+            // Android-added: Check for Bouncy Castle deprecation
+            Providers.checkBouncyCastleDeprecation(provider, "CertificateFactory", type);
+            Instance instance = GetInstance.getInstance("CertificateFactory",
+                CertificateFactorySpi.class, type, provider);
+            return new CertificateFactory((CertificateFactorySpi)instance.impl,
+                instance.provider, type);
+        } catch (NoSuchAlgorithmException e) {
+            throw new CertificateException(type + " not found", e);
+        }
+    }
+
+    /**
+     * Returns a certificate factory object for the specified
+     * certificate type.
+     *
+     * <p> A new CertificateFactory object encapsulating the
+     * CertificateFactorySpi implementation from the specified Provider
+     * object is returned.  Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * @param type the certificate type.
+     * See the CertificateFactory section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard certificate types.
+     * @param provider the provider.
+     *
+     * @return a certificate factory object for the specified type.
+     *
+     * @exception CertificateException if a CertificateFactorySpi
+     *          implementation for the specified algorithm is not available
+     *          from the specified Provider object.
+     *
+     * @exception IllegalArgumentException if the {@code provider} is
+     *          null.
+     *
+     * @see java.security.Provider
+     *
+     * @since 1.4
+     */
+    public static final CertificateFactory getInstance(String type,
+            Provider provider) throws CertificateException {
+        try {
+            // Android-added: Check for Bouncy Castle deprecation
+            Providers.checkBouncyCastleDeprecation(provider, "CertificateFactory", type);
+            Instance instance = GetInstance.getInstance("CertificateFactory",
+                CertificateFactorySpi.class, type, provider);
+            return new CertificateFactory((CertificateFactorySpi)instance.impl,
+                instance.provider, type);
+        } catch (NoSuchAlgorithmException e) {
+            throw new CertificateException(type + " not found", e);
+        }
+    }
+
+    /**
+     * Returns the provider of this certificate factory.
+     *
+     * @return the provider of this certificate factory.
+     */
+    public final Provider getProvider() {
+        return this.provider;
+    }
+
+    /**
+     * Returns the name of the certificate type associated with this
+     * certificate factory.
+     *
+     * @return the name of the certificate type associated with this
+     * certificate factory.
+     */
+    public final String getType() {
+        return this.type;
+    }
+
+    /**
+     * Generates a certificate object and initializes it with
+     * the data read from the input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized certificate format
+     * supported by this certificate factory,
+     * the returned certificate object can be typecast to the corresponding
+     * certificate class. For example, if this certificate
+     * factory implements X.509 certificates, the returned certificate object
+     * can be typecast to the {@code X509Certificate} class.
+     *
+     * <p>In the case of a certificate factory for X.509 certificates, the
+     * certificate provided in {@code inStream} must be DER-encoded and
+     * may be supplied in binary or printable (Base64) encoding. If the
+     * certificate is provided in Base64 encoding, it must be bounded at
+     * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
+     * the end by -----END CERTIFICATE-----.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream. Otherwise, each call to this
+     * method consumes one certificate and the read position of the
+     * input stream is positioned to the next available byte after
+     * the inherent end-of-certificate marker. If the data in the input stream
+     * does not contain an inherent end-of-certificate marker (other
+     * than EOF) and there is trailing data after the certificate is parsed, a
+     * {@code CertificateException} is thrown.
+     *
+     * @param inStream an input stream with the certificate data.
+     *
+     * @return a certificate object initialized with the data
+     * from the input stream.
+     *
+     * @exception CertificateException on parsing errors.
+     */
+    public final Certificate generateCertificate(InputStream inStream)
+        throws CertificateException
+    {
+        return certFacSpi.engineGenerateCertificate(inStream);
+    }
+
+    /**
+     * Returns an iteration of the {@code CertPath} encodings supported
+     * by this certificate factory, with the default encoding first. See
+     * the CertPath Encodings section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard encoding names and their formats.
+     * <p>
+     * Attempts to modify the returned {@code Iterator} via its
+     * {@code remove} method result in an
+     * {@code UnsupportedOperationException}.
+     *
+     * @return an {@code Iterator} over the names of the supported
+     *         {@code CertPath} encodings (as {@code String}s)
+     * @since 1.4
+     */
+    public final Iterator<String> getCertPathEncodings() {
+        return(certFacSpi.engineGetCertPathEncodings());
+    }
+
+    /**
+     * Generates a {@code CertPath} object and initializes it with
+     * the data read from the {@code InputStream} inStream. The data
+     * is assumed to be in the default encoding. The name of the default
+     * encoding is the first element of the {@code Iterator} returned by
+     * the {@link #getCertPathEncodings getCertPathEncodings} method.
+     *
+     * @param inStream an {@code InputStream} containing the data
+     * @return a {@code CertPath} initialized with the data from the
+     *   {@code InputStream}
+     * @exception CertificateException if an exception occurs while decoding
+     * @since 1.4
+     */
+    public final CertPath generateCertPath(InputStream inStream)
+        throws CertificateException
+    {
+        return(certFacSpi.engineGenerateCertPath(inStream));
+    }
+
+    /**
+     * Generates a {@code CertPath} object and initializes it with
+     * the data read from the {@code InputStream} inStream. The data
+     * is assumed to be in the specified encoding. See
+     * the CertPath Encodings section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard encoding names and their formats.
+     *
+     * @param inStream an {@code InputStream} containing the data
+     * @param encoding the encoding used for the data
+     * @return a {@code CertPath} initialized with the data from the
+     *   {@code InputStream}
+     * @exception CertificateException if an exception occurs while decoding or
+     *   the encoding requested is not supported
+     * @since 1.4
+     */
+    public final CertPath generateCertPath(InputStream inStream,
+        String encoding) throws CertificateException
+    {
+        return(certFacSpi.engineGenerateCertPath(inStream, encoding));
+    }
+
+    /**
+     * Generates a {@code CertPath} object and initializes it with
+     * a {@code List} of {@code Certificate}s.
+     * <p>
+     * The certificates supplied must be of a type supported by the
+     * {@code CertificateFactory}. They will be copied out of the supplied
+     * {@code List} object.
+     *
+     * @param certificates a {@code List} of {@code Certificate}s
+     * @return a {@code CertPath} initialized with the supplied list of
+     *   certificates
+     * @exception CertificateException if an exception occurs
+     * @since 1.4
+     */
+    public final CertPath
+        generateCertPath(List<? extends Certificate> certificates)
+        throws CertificateException
+    {
+        return(certFacSpi.engineGenerateCertPath(certificates));
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the certificates read
+     * from the given input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized certificate format
+     * supported by this certificate factory, each element in
+     * the returned collection view can be typecast to the corresponding
+     * certificate class. For example, if this certificate
+     * factory implements X.509 certificates, the elements in the returned
+     * collection can be typecast to the {@code X509Certificate} class.
+     *
+     * <p>In the case of a certificate factory for X.509 certificates,
+     * {@code inStream} may contain a sequence of DER-encoded certificates
+     * in the formats described for
+     * {@link #generateCertificate(java.io.InputStream) generateCertificate}.
+     * In addition, {@code inStream} may contain a PKCS#7 certificate
+     * chain. This is a PKCS#7 <i>SignedData</i> object, with the only
+     * significant field being <i>certificates</i>. In particular, the
+     * signature and the contents are ignored. This format allows multiple
+     * certificates to be downloaded at once. If no certificates are present,
+     * an empty collection is returned.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream.
+     *
+     * @param inStream the input stream with the certificates.
+     *
+     * @return a (possibly empty) collection view of
+     * java.security.cert.Certificate objects
+     * initialized with the data from the input stream.
+     *
+     * @exception CertificateException on parsing errors.
+     */
+    public final Collection<? extends Certificate> generateCertificates
+            (InputStream inStream) throws CertificateException {
+        return certFacSpi.engineGenerateCertificates(inStream);
+    }
+
+    /**
+     * Generates a certificate revocation list (CRL) object and initializes it
+     * with the data read from the input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized CRL format
+     * supported by this certificate factory,
+     * the returned CRL object can be typecast to the corresponding
+     * CRL class. For example, if this certificate
+     * factory implements X.509 CRLs, the returned CRL object
+     * can be typecast to the {@code X509CRL} class.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream. Otherwise, each call to this
+     * method consumes one CRL and the read position of the input stream
+     * is positioned to the next available byte after the inherent
+     * end-of-CRL marker. If the data in the
+     * input stream does not contain an inherent end-of-CRL marker (other
+     * than EOF) and there is trailing data after the CRL is parsed, a
+     * {@code CRLException} is thrown.
+     *
+     * @param inStream an input stream with the CRL data.
+     *
+     * @return a CRL object initialized with the data
+     * from the input stream.
+     *
+     * @exception CRLException on parsing errors.
+     */
+    public final CRL generateCRL(InputStream inStream)
+        throws CRLException
+    {
+        return certFacSpi.engineGenerateCRL(inStream);
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the CRLs read
+     * from the given input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized CRL format
+     * supported by this certificate factory, each element in
+     * the returned collection view can be typecast to the corresponding
+     * CRL class. For example, if this certificate
+     * factory implements X.509 CRLs, the elements in the returned
+     * collection can be typecast to the {@code X509CRL} class.
+     *
+     * <p>In the case of a certificate factory for X.509 CRLs,
+     * {@code inStream} may contain a sequence of DER-encoded CRLs.
+     * In addition, {@code inStream} may contain a PKCS#7 CRL
+     * set. This is a PKCS#7 <i>SignedData</i> object, with the only
+     * significant field being <i>crls</i>. In particular, the
+     * signature and the contents are ignored. This format allows multiple
+     * CRLs to be downloaded at once. If no CRLs are present,
+     * an empty collection is returned.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream.
+     *
+     * @param inStream the input stream with the CRLs.
+     *
+     * @return a (possibly empty) collection view of
+     * java.security.cert.CRL objects initialized with the data from the input
+     * stream.
+     *
+     * @exception CRLException on parsing errors.
+     */
+    public final Collection<? extends CRL> generateCRLs(InputStream inStream)
+            throws CRLException {
+        return certFacSpi.engineGenerateCRLs(inStream);
+    }
+}
diff --git a/java/security/cert/CertificateFactorySpi.java b/java/security/cert/CertificateFactorySpi.java
new file mode 100644
index 0000000..35aee84
--- /dev/null
+++ b/java/security/cert/CertificateFactorySpi.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.security.Provider;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/**
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
+ * for the {@code CertificateFactory} class.
+ * All the abstract methods in this class must be implemented by each
+ * cryptographic service provider who wishes to supply the implementation
+ * of a certificate factory for a particular certificate type, e.g., X.509.
+ *
+ * <p>Certificate factories are used to generate certificate, certification path
+ * ({@code CertPath}) and certificate revocation list (CRL) objects from
+ * their encodings.
+ *
+ * <p>A certificate factory for X.509 must return certificates that are an
+ * instance of {@code java.security.cert.X509Certificate}, and CRLs
+ * that are an instance of {@code java.security.cert.X509CRL}.
+ *
+ * @author Hemma Prafullchandra
+ * @author Jan Luehe
+ * @author Sean Mullan
+ *
+ *
+ * @see CertificateFactory
+ * @see Certificate
+ * @see X509Certificate
+ * @see CertPath
+ * @see CRL
+ * @see X509CRL
+ *
+ * @since 1.2
+ */
+
+public abstract class CertificateFactorySpi {
+
+    /**
+     * Generates a certificate object and initializes it with
+     * the data read from the input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized certificate format
+     * supported by this certificate factory,
+     * the returned certificate object can be typecast to the corresponding
+     * certificate class. For example, if this certificate
+     * factory implements X.509 certificates, the returned certificate object
+     * can be typecast to the {@code X509Certificate} class.
+     *
+     * <p>In the case of a certificate factory for X.509 certificates, the
+     * certificate provided in {@code inStream} must be DER-encoded and
+     * may be supplied in binary or printable (Base64) encoding. If the
+     * certificate is provided in Base64 encoding, it must be bounded at
+     * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
+     * the end by -----END CERTIFICATE-----.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream. Otherwise, each call to this
+     * method consumes one certificate and the read position of the input stream
+     * is positioned to the next available byte after the inherent
+     * end-of-certificate marker. If the data in the
+     * input stream does not contain an inherent end-of-certificate marker (other
+     * than EOF) and there is trailing data after the certificate is parsed, a
+     * {@code CertificateException} is thrown.
+     *
+     * @param inStream an input stream with the certificate data.
+     *
+     * @return a certificate object initialized with the data
+     * from the input stream.
+     *
+     * @exception CertificateException on parsing errors.
+     */
+    public abstract Certificate engineGenerateCertificate(InputStream inStream)
+        throws CertificateException;
+
+    /**
+     * Generates a {@code CertPath} object and initializes it with
+     * the data read from the {@code InputStream} inStream. The data
+     * is assumed to be in the default encoding.
+     *
+     * <p> This method was added to version 1.4 of the Java 2 Platform
+     * Standard Edition. In order to maintain backwards compatibility with
+     * existing service providers, this method cannot be {@code abstract}
+     * and by default throws an {@code UnsupportedOperationException}.
+     *
+     * @param inStream an {@code InputStream} containing the data
+     * @return a {@code CertPath} initialized with the data from the
+     *   {@code InputStream}
+     * @exception CertificateException if an exception occurs while decoding
+     * @exception UnsupportedOperationException if the method is not supported
+     * @since 1.4
+     */
+    public CertPath engineGenerateCertPath(InputStream inStream)
+        throws CertificateException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Generates a {@code CertPath} object and initializes it with
+     * the data read from the {@code InputStream} inStream. The data
+     * is assumed to be in the specified encoding.
+     *
+     * <p> This method was added to version 1.4 of the Java 2 Platform
+     * Standard Edition. In order to maintain backwards compatibility with
+     * existing service providers, this method cannot be {@code abstract}
+     * and by default throws an {@code UnsupportedOperationException}.
+     *
+     * @param inStream an {@code InputStream} containing the data
+     * @param encoding the encoding used for the data
+     * @return a {@code CertPath} initialized with the data from the
+     *   {@code InputStream}
+     * @exception CertificateException if an exception occurs while decoding or
+     *   the encoding requested is not supported
+     * @exception UnsupportedOperationException if the method is not supported
+     * @since 1.4
+     */
+    public CertPath engineGenerateCertPath(InputStream inStream,
+        String encoding) throws CertificateException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Generates a {@code CertPath} object and initializes it with
+     * a {@code List} of {@code Certificate}s.
+     * <p>
+     * The certificates supplied must be of a type supported by the
+     * {@code CertificateFactory}. They will be copied out of the supplied
+     * {@code List} object.
+     *
+     * <p> This method was added to version 1.4 of the Java 2 Platform
+     * Standard Edition. In order to maintain backwards compatibility with
+     * existing service providers, this method cannot be {@code abstract}
+     * and by default throws an {@code UnsupportedOperationException}.
+     *
+     * @param certificates a {@code List} of {@code Certificate}s
+     * @return a {@code CertPath} initialized with the supplied list of
+     *   certificates
+     * @exception CertificateException if an exception occurs
+     * @exception UnsupportedOperationException if the method is not supported
+     * @since 1.4
+     */
+    public CertPath
+        engineGenerateCertPath(List<? extends Certificate> certificates)
+        throws CertificateException
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns an iteration of the {@code CertPath} encodings supported
+     * by this certificate factory, with the default encoding first. See
+     * the CertPath Encodings section in the <a href=
+     * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
+     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
+     * for information about standard encoding names.
+     * <p>
+     * Attempts to modify the returned {@code Iterator} via its
+     * {@code remove} method result in an
+     * {@code UnsupportedOperationException}.
+     *
+     * <p> This method was added to version 1.4 of the Java 2 Platform
+     * Standard Edition. In order to maintain backwards compatibility with
+     * existing service providers, this method cannot be {@code abstract}
+     * and by default throws an {@code UnsupportedOperationException}.
+     *
+     * @return an {@code Iterator} over the names of the supported
+     *         {@code CertPath} encodings (as {@code String}s)
+     * @exception UnsupportedOperationException if the method is not supported
+     * @since 1.4
+     */
+    public Iterator<String> engineGetCertPathEncodings() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns a (possibly empty) collection view of the certificates read
+     * from the given input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized certificate format
+     * supported by this certificate factory, each element in
+     * the returned collection view can be typecast to the corresponding
+     * certificate class. For example, if this certificate
+     * factory implements X.509 certificates, the elements in the returned
+     * collection can be typecast to the {@code X509Certificate} class.
+     *
+     * <p>In the case of a certificate factory for X.509 certificates,
+     * {@code inStream} may contain a single DER-encoded certificate
+     * in the formats described for
+     * {@link CertificateFactory#generateCertificate(java.io.InputStream)
+     * generateCertificate}.
+     * In addition, {@code inStream} may contain a PKCS#7 certificate
+     * chain. This is a PKCS#7 <i>SignedData</i> object, with the only
+     * significant field being <i>certificates</i>. In particular, the
+     * signature and the contents are ignored. This format allows multiple
+     * certificates to be downloaded at once. If no certificates are present,
+     * an empty collection is returned.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream.
+     *
+     * @param inStream the input stream with the certificates.
+     *
+     * @return a (possibly empty) collection view of
+     * java.security.cert.Certificate objects
+     * initialized with the data from the input stream.
+     *
+     * @exception CertificateException on parsing errors.
+     */
+    public abstract Collection<? extends Certificate>
+            engineGenerateCertificates(InputStream inStream)
+            throws CertificateException;
+
+    /**
+     * Generates a certificate revocation list (CRL) object and initializes it
+     * with the data read from the input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized CRL format
+     * supported by this certificate factory,
+     * the returned CRL object can be typecast to the corresponding
+     * CRL class. For example, if this certificate
+     * factory implements X.509 CRLs, the returned CRL object
+     * can be typecast to the {@code X509CRL} class.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream. Otherwise, each call to this
+     * method consumes one CRL and the read position of the input stream
+     * is positioned to the next available byte after the inherent
+     * end-of-CRL marker. If the data in the
+     * input stream does not contain an inherent end-of-CRL marker (other
+     * than EOF) and there is trailing data after the CRL is parsed, a
+     * {@code CRLException} is thrown.
+     *
+     * @param inStream an input stream with the CRL data.
+     *
+     * @return a CRL object initialized with the data
+     * from the input stream.
+     *
+     * @exception CRLException on parsing errors.
+     */
+    public abstract CRL engineGenerateCRL(InputStream inStream)
+        throws CRLException;
+
+    /**
+     * Returns a (possibly empty) collection view of the CRLs read
+     * from the given input stream {@code inStream}.
+     *
+     * <p>In order to take advantage of the specialized CRL format
+     * supported by this certificate factory, each element in
+     * the returned collection view can be typecast to the corresponding
+     * CRL class. For example, if this certificate
+     * factory implements X.509 CRLs, the elements in the returned
+     * collection can be typecast to the {@code X509CRL} class.
+     *
+     * <p>In the case of a certificate factory for X.509 CRLs,
+     * {@code inStream} may contain a single DER-encoded CRL.
+     * In addition, {@code inStream} may contain a PKCS#7 CRL
+     * set. This is a PKCS#7 <i>SignedData</i> object, with the only
+     * significant field being <i>crls</i>. In particular, the
+     * signature and the contents are ignored. This format allows multiple
+     * CRLs to be downloaded at once. If no CRLs are present,
+     * an empty collection is returned.
+     *
+     * <p>Note that if the given input stream does not support
+     * {@link java.io.InputStream#mark(int) mark} and
+     * {@link java.io.InputStream#reset() reset}, this method will
+     * consume the entire input stream.
+     *
+     * @param inStream the input stream with the CRLs.
+     *
+     * @return a (possibly empty) collection view of
+     * java.security.cert.CRL objects initialized with the data from the input
+     * stream.
+     *
+     * @exception CRLException on parsing errors.
+     */
+    public abstract Collection<? extends CRL> engineGenerateCRLs
+            (InputStream inStream) throws CRLException;
+}
diff --git a/java/security/cert/CertificateNotYetValidException.java b/java/security/cert/CertificateNotYetValidException.java
new file mode 100644
index 0000000..e8722bd
--- /dev/null
+++ b/java/security/cert/CertificateNotYetValidException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * Certificate is not yet valid exception. This is thrown whenever
+ * the current {@code Date} or the specified {@code Date}
+ * is before the {@code notBefore} date/time in the Certificate
+ * validity period.
+ *
+ * @author Hemma Prafullchandra
+ */
+public class CertificateNotYetValidException extends CertificateException {
+
+    static final long serialVersionUID = 4355919900041064702L;
+
+    /**
+     * Constructs a CertificateNotYetValidException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public CertificateNotYetValidException() {
+        super();
+    }
+
+    /**
+     * Constructs a CertificateNotYetValidException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param message the detail message.
+     */
+    public CertificateNotYetValidException(String message) {
+        super(message);
+    }
+}
diff --git a/java/security/cert/CertificateParsingException.java b/java/security/cert/CertificateParsingException.java
new file mode 100644
index 0000000..06a7d60
--- /dev/null
+++ b/java/security/cert/CertificateParsingException.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * Certificate Parsing Exception. This is thrown whenever an
+ * invalid DER-encoded certificate is parsed or unsupported DER features
+ * are found in the Certificate.
+ *
+ * @author Hemma Prafullchandra
+ */
+public class CertificateParsingException extends CertificateException {
+
+    private static final long serialVersionUID = -7989222416793322029L;
+
+    /**
+     * Constructs a CertificateParsingException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public CertificateParsingException() {
+        super();
+    }
+
+    /**
+     * Constructs a CertificateParsingException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param message the detail message.
+     */
+    public CertificateParsingException(String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a {@code CertificateParsingException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CertificateParsingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code CertificateParsingException} with the
+     * specified cause and a detail message of
+     * {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public CertificateParsingException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/cert/CertificateRevokedException.java b/java/security/cert/CertificateRevokedException.java
new file mode 100644
index 0000000..505a007
--- /dev/null
+++ b/java/security/cert/CertificateRevokedException.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.InvalidityDateExtension;
+
+/**
+ * An exception that indicates an X.509 certificate is revoked. A
+ * {@code CertificateRevokedException} contains additional information
+ * about the revoked certificate, such as the date on which the
+ * certificate was revoked and the reason it was revoked.
+ *
+ * @author Sean Mullan
+ * @since 1.7
+ * @see CertPathValidatorException
+ */
+public class CertificateRevokedException extends CertificateException {
+
+    private static final long serialVersionUID = 7839996631571608627L;
+
+    /**
+     * @serial the date on which the certificate was revoked
+     */
+    private Date revocationDate;
+    /**
+     * @serial the revocation reason
+     */
+    private final CRLReason reason;
+    /**
+     * @serial the {@code X500Principal} that represents the name of the
+     * authority that signed the certificate's revocation status information
+     */
+    private final X500Principal authority;
+
+    private transient Map<String, Extension> extensions;
+
+    /**
+     * Constructs a {@code CertificateRevokedException} with
+     * the specified revocation date, reason code, authority name, and map
+     * of extensions.
+     *
+     * @param revocationDate the date on which the certificate was revoked. The
+     *    date is copied to protect against subsequent modification.
+     * @param reason the revocation reason
+     * @param extensions a map of X.509 Extensions. Each key is an OID String
+     *    that maps to the corresponding Extension. The map is copied to
+     *    prevent subsequent modification.
+     * @param authority the {@code X500Principal} that represents the name
+     *    of the authority that signed the certificate's revocation status
+     *    information
+     * @throws NullPointerException if {@code revocationDate},
+     *    {@code reason}, {@code authority}, or
+     *    {@code extensions} is {@code null}
+     */
+    public CertificateRevokedException(Date revocationDate, CRLReason reason,
+        X500Principal authority, Map<String, Extension> extensions) {
+        if (revocationDate == null || reason == null || authority == null ||
+            extensions == null) {
+            throw new NullPointerException();
+        }
+        this.revocationDate = new Date(revocationDate.getTime());
+        this.reason = reason;
+        this.authority = authority;
+        // make sure Map only contains correct types
+        this.extensions = Collections.checkedMap(new HashMap<>(),
+                                                 String.class, Extension.class);
+        this.extensions.putAll(extensions);
+    }
+
+    /**
+     * Returns the date on which the certificate was revoked. A new copy is
+     * returned each time the method is invoked to protect against subsequent
+     * modification.
+     *
+     * @return the revocation date
+     */
+    public Date getRevocationDate() {
+        return (Date) revocationDate.clone();
+    }
+
+    /**
+     * Returns the reason the certificate was revoked.
+     *
+     * @return the revocation reason
+     */
+    public CRLReason getRevocationReason() {
+        return reason;
+    }
+
+    /**
+     * Returns the name of the authority that signed the certificate's
+     * revocation status information.
+     *
+     * @return the {@code X500Principal} that represents the name of the
+     *     authority that signed the certificate's revocation status information
+     */
+    public X500Principal getAuthorityName() {
+        return authority;
+    }
+
+    /**
+     * Returns the invalidity date, as specified in the Invalidity Date
+     * extension of this {@code CertificateRevokedException}. The
+     * invalidity date is the date on which it is known or suspected that the
+     * private key was compromised or that the certificate otherwise became
+     * invalid. This implementation calls {@code getExtensions()} and
+     * checks the returned map for an entry for the Invalidity Date extension
+     * OID ("2.5.29.24"). If found, it returns the invalidity date in the
+     * extension; otherwise null. A new Date object is returned each time the
+     * method is invoked to protect against subsequent modification.
+     *
+     * @return the invalidity date, or {@code null} if not specified
+     */
+    public Date getInvalidityDate() {
+        Extension ext = getExtensions().get("2.5.29.24");
+        if (ext == null) {
+            return null;
+        } else {
+            try {
+                Date invalidity = InvalidityDateExtension.toImpl(ext).get("DATE");
+                return new Date(invalidity.getTime());
+            } catch (IOException ioe) {
+                return null;
+            }
+        }
+    }
+
+    /**
+     * Returns a map of X.509 extensions containing additional information
+     * about the revoked certificate, such as the Invalidity Date
+     * Extension. Each key is an OID String that maps to the corresponding
+     * Extension.
+     *
+     * @return an unmodifiable map of X.509 extensions, or an empty map
+     *    if there are no extensions
+     */
+    public Map<String, Extension> getExtensions() {
+        return Collections.unmodifiableMap(extensions);
+    }
+
+    @Override
+    public String getMessage() {
+        return "Certificate has been revoked, reason: "
+               + reason + ", revocation date: " + revocationDate
+               + ", authority: " + authority + ", extension OIDs: "
+               + extensions.keySet();
+    }
+
+    /**
+     * Serialize this {@code CertificateRevokedException} instance.
+     *
+     * @serialData the size of the extensions map (int), followed by all of
+     * the extensions in the map, in no particular order. For each extension,
+     * the following data is emitted: the OID String (Object), the criticality
+     * flag (boolean), the length of the encoded extension value byte array
+     * (int), and the encoded extension value bytes.
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        // Write out the non-transient fields
+        // (revocationDate, reason, authority)
+        oos.defaultWriteObject();
+
+        // Write out the size (number of mappings) of the extensions map
+        oos.writeInt(extensions.size());
+
+        // For each extension in the map, the following are emitted (in order):
+        // the OID String (Object), the criticality flag (boolean), the length
+        // of the encoded extension value byte array (int), and the encoded
+        // extension value byte array. The extensions themselves are emitted
+        // in no particular order.
+        for (Map.Entry<String, Extension> entry : extensions.entrySet()) {
+            Extension ext = entry.getValue();
+            oos.writeObject(ext.getId());
+            oos.writeBoolean(ext.isCritical());
+            byte[] extVal = ext.getValue();
+            oos.writeInt(extVal.length);
+            oos.write(extVal);
+        }
+    }
+
+    /**
+     * Deserialize the {@code CertificateRevokedException} instance.
+     */
+    private void readObject(ObjectInputStream ois)
+        throws IOException, ClassNotFoundException {
+        // Read in the non-transient fields
+        // (revocationDate, reason, authority)
+        ois.defaultReadObject();
+
+        // Defensively copy the revocation date
+        revocationDate = new Date(revocationDate.getTime());
+
+        // Read in the size (number of mappings) of the extensions map
+        // and create the extensions map
+        int size = ois.readInt();
+        if (size == 0) {
+            extensions = Collections.emptyMap();
+        } else {
+            extensions = new HashMap<String, Extension>(size);
+        }
+
+        // Read in the extensions and put the mappings in the extensions map
+        for (int i = 0; i < size; i++) {
+            String oid = (String) ois.readObject();
+            boolean critical = ois.readBoolean();
+            int length = ois.readInt();
+            byte[] extVal = new byte[length];
+            ois.readFully(extVal);
+            Extension ext = sun.security.x509.Extension.newExtension
+                (new ObjectIdentifier(oid), critical, extVal);
+            extensions.put(oid, ext);
+        }
+    }
+}
diff --git a/java/security/cert/CollectionCertStoreParameters.java b/java/security/cert/CollectionCertStoreParameters.java
new file mode 100644
index 0000000..12bd358
--- /dev/null
+++ b/java/security/cert/CollectionCertStoreParameters.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * Parameters used as input for the Collection {@code CertStore}
+ * algorithm.
+ * <p>
+ * This class is used to provide necessary configuration parameters
+ * to implementations of the Collection {@code CertStore}
+ * algorithm. The only parameter included in this class is the
+ * {@code Collection} from which the {@code CertStore} will
+ * retrieve certificates and CRLs.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @since       1.4
+ * @author      Steve Hanna
+ * @see         java.util.Collection
+ * @see         CertStore
+ */
+public class CollectionCertStoreParameters
+    implements CertStoreParameters {
+
+    private Collection<?> coll;
+
+    /**
+     * Creates an instance of {@code CollectionCertStoreParameters}
+     * which will allow certificates and CRLs to be retrieved from the
+     * specified {@code Collection}. If the specified
+     * {@code Collection} contains an object that is not a
+     * {@code Certificate} or {@code CRL}, that object will be
+     * ignored by the Collection {@code CertStore}.
+     * <p>
+     * The {@code Collection} is <b>not</b> copied. Instead, a
+     * reference is used. This allows the caller to subsequently add or
+     * remove {@code Certificates} or {@code CRL}s from the
+     * {@code Collection}, thus changing the set of
+     * {@code Certificates} or {@code CRL}s available to the
+     * Collection {@code CertStore}. The Collection {@code CertStore}
+     * will not modify the contents of the {@code Collection}.
+     * <p>
+     * If the {@code Collection} will be modified by one thread while
+     * another thread is calling a method of a Collection {@code CertStore}
+     * that has been initialized with this {@code Collection}, the
+     * {@code Collection} must have fail-fast iterators.
+     *
+     * @param collection a {@code Collection} of
+     *        {@code Certificate}s and {@code CRL}s
+     * @exception NullPointerException if {@code collection} is
+     * {@code null}
+     */
+    public CollectionCertStoreParameters(Collection<?> collection) {
+        if (collection == null)
+            throw new NullPointerException();
+        coll = collection;
+    }
+
+    /**
+     * Creates an instance of {@code CollectionCertStoreParameters} with
+     * the default parameter values (an empty and immutable
+     * {@code Collection}).
+     */
+    public CollectionCertStoreParameters() {
+        coll = Collections.EMPTY_SET;
+    }
+
+    /**
+     * Returns the {@code Collection} from which {@code Certificate}s
+     * and {@code CRL}s are retrieved. This is <b>not</b> a copy of the
+     * {@code Collection}, it is a reference. This allows the caller to
+     * subsequently add or remove {@code Certificates} or
+     * {@code CRL}s from the {@code Collection}.
+     *
+     * @return the {@code Collection} (never null)
+     */
+    public Collection<?> getCollection() {
+        return coll;
+    }
+
+    /**
+     * Returns a copy of this object. Note that only a reference to the
+     * {@code Collection} is copied, and not the contents.
+     *
+     * @return the copy
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+
+    /**
+     * Returns a formatted string describing the parameters.
+     *
+     * @return a formatted string describing the parameters
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("CollectionCertStoreParameters: [\n");
+        sb.append("  collection: " + coll + "\n");
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/Extension.java b/java/security/cert/Extension.java
new file mode 100644
index 0000000..98e827c
--- /dev/null
+++ b/java/security/cert/Extension.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Serializable;
+
+/**
+ * This interface represents an X.509 extension.
+ *
+ * <p>
+ * Extensions provide a means of associating additional attributes with users
+ * or public keys and for managing a certification hierarchy.  The extension
+ * format also allows communities to define private extensions to carry
+ * information unique to those communities.
+ *
+ * <p>
+ * Each extension contains an object identifier, a criticality setting
+ * indicating whether it is a critical or a non-critical extension, and
+ * and an ASN.1 DER-encoded value. Its ASN.1 definition is:
+ *
+ * <pre>
+ *
+ *     Extension ::= SEQUENCE {
+ *         extnId        OBJECT IDENTIFIER,
+ *         critical      BOOLEAN DEFAULT FALSE,
+ *         extnValue     OCTET STRING
+ *                 -- contains a DER encoding of a value
+ *                 -- of the type registered for use with
+ *                 -- the extnId object identifier value
+ *     }
+ *
+ * </pre>
+ *
+ * <p>
+ * This interface is designed to provide access to a single extension,
+ * unlike {@link java.security.cert.X509Extension} which is more suitable
+ * for accessing a set of extensions.
+ *
+ * @since 1.7
+ */
+public interface Extension {
+
+    /**
+     * Gets the extensions's object identifier.
+     *
+     * @return the object identifier as a String
+     */
+    String getId();
+
+    /**
+     * Gets the extension's criticality setting.
+     *
+     * @return true if this is a critical extension.
+     */
+    boolean isCritical();
+
+    /**
+     * Gets the extensions's DER-encoded value. Note, this is the bytes
+     * that are encoded as an OCTET STRING. It does not include the OCTET
+     * STRING tag and length.
+     *
+     * @return a copy of the extension's value, or {@code null} if no
+     *    extension value is present.
+     */
+    byte[] getValue();
+
+    /**
+     * Generates the extension's DER encoding and writes it to the output
+     * stream.
+     *
+     * @param out the output stream
+     * @exception IOException on encoding or output error.
+     * @exception NullPointerException if {@code out} is {@code null}.
+     */
+    void encode(OutputStream out) throws IOException;
+}
diff --git a/java/security/cert/LDAPCertStoreParameters.java b/java/security/cert/LDAPCertStoreParameters.java
new file mode 100644
index 0000000..96fe9cd
--- /dev/null
+++ b/java/security/cert/LDAPCertStoreParameters.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * Parameters used as input for the LDAP {@code CertStore} algorithm.
+ * <p>
+ * This class is used to provide necessary configuration parameters (server
+ * name and port number) to implementations of the LDAP {@code CertStore}
+ * algorithm.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @since       1.4
+ * @author      Steve Hanna
+ * @see         CertStore
+ */
+public class LDAPCertStoreParameters implements CertStoreParameters {
+
+    private static final int LDAP_DEFAULT_PORT = 389;
+
+    /**
+     * the port number of the LDAP server
+     */
+    private int port;
+
+    /**
+     * the DNS name of the LDAP server
+     */
+    private String serverName;
+
+    /**
+     * Creates an instance of {@code LDAPCertStoreParameters} with the
+     * specified parameter values.
+     *
+     * @param serverName the DNS name of the LDAP server
+     * @param port the port number of the LDAP server
+     * @exception NullPointerException if {@code serverName} is
+     * {@code null}
+     */
+    public LDAPCertStoreParameters(String serverName, int port) {
+        if (serverName == null)
+            throw new NullPointerException();
+        this.serverName = serverName;
+        this.port = port;
+    }
+
+    /**
+     * Creates an instance of {@code LDAPCertStoreParameters} with the
+     * specified server name and a default port of 389.
+     *
+     * @param serverName the DNS name of the LDAP server
+     * @exception NullPointerException if {@code serverName} is
+     * {@code null}
+     */
+    public LDAPCertStoreParameters(String serverName) {
+        this(serverName, LDAP_DEFAULT_PORT);
+    }
+
+    /**
+     * Creates an instance of {@code LDAPCertStoreParameters} with the
+     * default parameter values (server name "localhost", port 389).
+     */
+    public LDAPCertStoreParameters() {
+        this("localhost", LDAP_DEFAULT_PORT);
+    }
+
+    /**
+     * Returns the DNS name of the LDAP server.
+     *
+     * @return the name (not {@code null})
+     */
+    public String getServerName() {
+        return serverName;
+    }
+
+    /**
+     * Returns the port number of the LDAP server.
+     *
+     * @return the port number
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * Returns a copy of this object. Changes to the copy will not affect
+     * the original and vice versa.
+     * <p>
+     * Note: this method currently performs a shallow copy of the object
+     * (simply calls {@code Object.clone()}). This may be changed in a
+     * future revision to perform a deep copy if new parameters are added
+     * that should not be shared.
+     *
+     * @return the copy
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+
+    /**
+     * Returns a formatted string describing the parameters.
+     *
+     * @return a formatted string describing the parameters
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("LDAPCertStoreParameters: [\n");
+
+        sb.append("  serverName: " + serverName + "\n");
+        sb.append("  port: " + port + "\n");
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/PKIXBuilderParameters.java b/java/security/cert/PKIXBuilderParameters.java
new file mode 100644
index 0000000..b33e1f8
--- /dev/null
+++ b/java/security/cert/PKIXBuilderParameters.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.util.Set;
+
+/**
+ * Parameters used as input for the PKIX {@code CertPathBuilder}
+ * algorithm.
+ * <p>
+ * A PKIX {@code CertPathBuilder} uses these parameters to {@link
+ * CertPathBuilder#build build} a {@code CertPath} which has been
+ * validated according to the PKIX certification path validation algorithm.
+ *
+ * <p>To instantiate a {@code PKIXBuilderParameters} object, an
+ * application must specify one or more <i>most-trusted CAs</i> as defined by
+ * the PKIX certification path validation algorithm. The most-trusted CA
+ * can be specified using one of two constructors. An application
+ * can call {@link #PKIXBuilderParameters(Set, CertSelector)
+ * PKIXBuilderParameters(Set, CertSelector)}, specifying a
+ * {@code Set} of {@code TrustAnchor} objects, each of which
+ * identifies a most-trusted CA. Alternatively, an application can call
+ * {@link #PKIXBuilderParameters(KeyStore, CertSelector)
+ * PKIXBuilderParameters(KeyStore, CertSelector)}, specifying a
+ * {@code KeyStore} instance containing trusted certificate entries, each
+ * of which will be considered as a most-trusted CA.
+ *
+ * <p>In addition, an application must specify constraints on the target
+ * certificate that the {@code CertPathBuilder} will attempt
+ * to build a path to. The constraints are specified as a
+ * {@code CertSelector} object. These constraints should provide the
+ * {@code CertPathBuilder} with enough search criteria to find the target
+ * certificate. Minimal criteria for an {@code X509Certificate} usually
+ * include the subject name and/or one or more subject alternative names.
+ * If enough criteria is not specified, the {@code CertPathBuilder}
+ * may throw a {@code CertPathBuilderException}.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilder
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public class PKIXBuilderParameters extends PKIXParameters {
+
+    private int maxPathLength = 5;
+
+    /**
+     * Creates an instance of {@code PKIXBuilderParameters} with
+     * the specified {@code Set} of most-trusted CAs.
+     * Each element of the set is a {@link TrustAnchor TrustAnchor}.
+     *
+     * <p>Note that the {@code Set} is copied to protect against
+     * subsequent modifications.
+     *
+     * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
+     * @param targetConstraints a {@code CertSelector} specifying the
+     * constraints on the target certificate
+     * @throws InvalidAlgorithmParameterException if {@code trustAnchors}
+     * is empty {@code (trustAnchors.isEmpty() == true)}
+     * @throws NullPointerException if {@code trustAnchors} is
+     * {@code null}
+     * @throws ClassCastException if any of the elements of
+     * {@code trustAnchors} are not of type
+     * {@code java.security.cert.TrustAnchor}
+     */
+    public PKIXBuilderParameters(Set<TrustAnchor> trustAnchors, CertSelector
+        targetConstraints) throws InvalidAlgorithmParameterException
+    {
+        super(trustAnchors);
+        setTargetCertConstraints(targetConstraints);
+    }
+
+    /**
+     * Creates an instance of {@code PKIXBuilderParameters} that
+     * populates the set of most-trusted CAs from the trusted
+     * certificate entries contained in the specified {@code KeyStore}.
+     * Only keystore entries that contain trusted {@code X509Certificate}s
+     * are considered; all other certificate types are ignored.
+     *
+     * @param keystore a {@code KeyStore} from which the set of
+     * most-trusted CAs will be populated
+     * @param targetConstraints a {@code CertSelector} specifying the
+     * constraints on the target certificate
+     * @throws KeyStoreException if {@code keystore} has not been
+     * initialized
+     * @throws InvalidAlgorithmParameterException if {@code keystore} does
+     * not contain at least one trusted certificate entry
+     * @throws NullPointerException if {@code keystore} is
+     * {@code null}
+     */
+    public PKIXBuilderParameters(KeyStore keystore,
+        CertSelector targetConstraints)
+        throws KeyStoreException, InvalidAlgorithmParameterException
+    {
+        super(keystore);
+        setTargetCertConstraints(targetConstraints);
+    }
+
+    /**
+     * Sets the value of the maximum number of non-self-issued intermediate
+     * certificates that may exist in a certification path. A certificate
+     * is self-issued if the DNs that appear in the subject and issuer
+     * fields are identical and are not empty. Note that the last certificate
+     * in a certification path is not an intermediate certificate, and is not
+     * included in this limit. Usually the last certificate is an end entity
+     * certificate, but it can be a CA certificate. A PKIX
+     * {@code CertPathBuilder} instance must not build
+     * paths longer than the length specified.
+     *
+     * <p> A value of 0 implies that the path can only contain
+     * a single certificate. A value of -1 implies that the
+     * path length is unconstrained (i.e. there is no maximum).
+     * The default maximum path length, if not specified, is 5.
+     * Setting a value less than -1 will cause an exception to be thrown.
+     *
+     * <p> If any of the CA certificates contain the
+     * {@code BasicConstraintsExtension}, the value of the
+     * {@code pathLenConstraint} field of the extension overrides
+     * the maximum path length parameter whenever the result is a
+     * certification path of smaller length.
+     *
+     * @param maxPathLength the maximum number of non-self-issued intermediate
+     *  certificates that may exist in a certification path
+     * @throws InvalidParameterException if {@code maxPathLength} is set
+     *  to a value less than -1
+     *
+     * @see #getMaxPathLength
+     */
+    public void setMaxPathLength(int maxPathLength) {
+        if (maxPathLength < -1) {
+            throw new InvalidParameterException("the maximum path "
+                + "length parameter can not be less than -1");
+        }
+        this.maxPathLength = maxPathLength;
+    }
+
+    /**
+     * Returns the value of the maximum number of intermediate non-self-issued
+     * certificates that may exist in a certification path. See
+     * the {@link #setMaxPathLength} method for more details.
+     *
+     * @return the maximum number of non-self-issued intermediate certificates
+     *  that may exist in a certification path, or -1 if there is no limit
+     *
+     * @see #setMaxPathLength
+     */
+    public int getMaxPathLength() {
+        return maxPathLength;
+    }
+
+    /**
+     * Returns a formatted string describing the parameters.
+     *
+     * @return a formatted string describing the parameters
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[\n");
+        sb.append(super.toString());
+        sb.append("  Maximum Path Length: " + maxPathLength + "\n");
+        sb.append("]\n");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/PKIXCertPathBuilderResult.java b/java/security/cert/PKIXCertPathBuilderResult.java
new file mode 100644
index 0000000..3255a3b
--- /dev/null
+++ b/java/security/cert/PKIXCertPathBuilderResult.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.PublicKey;
+
+/**
+ * This class represents the successful result of the PKIX certification
+ * path builder algorithm. All certification paths that are built and
+ * returned using this algorithm are also validated according to the PKIX
+ * certification path validation algorithm.
+ *
+ * <p>Instances of {@code PKIXCertPathBuilderResult} are returned by
+ * the {@code build} method of {@code CertPathBuilder}
+ * objects implementing the PKIX algorithm.
+ *
+ * <p>All {@code PKIXCertPathBuilderResult} objects contain the
+ * certification path constructed by the build algorithm, the
+ * valid policy tree and subject public key resulting from the build
+ * algorithm, and a {@code TrustAnchor} describing the certification
+ * authority (CA) that served as a trust anchor for the certification path.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathBuilderResult
+ *
+ * @since       1.4
+ * @author      Anne Anderson
+ */
+public class PKIXCertPathBuilderResult extends PKIXCertPathValidatorResult
+    implements CertPathBuilderResult {
+
+    private CertPath certPath;
+
+    /**
+     * Creates an instance of {@code PKIXCertPathBuilderResult}
+     * containing the specified parameters.
+     *
+     * @param certPath the validated {@code CertPath}
+     * @param trustAnchor a {@code TrustAnchor} describing the CA that
+     * served as a trust anchor for the certification path
+     * @param policyTree the immutable valid policy tree, or {@code null}
+     * if there are no valid policies
+     * @param subjectPublicKey the public key of the subject
+     * @throws NullPointerException if the {@code certPath},
+     * {@code trustAnchor} or {@code subjectPublicKey} parameters
+     * are {@code null}
+     */
+    public PKIXCertPathBuilderResult(CertPath certPath,
+        TrustAnchor trustAnchor, PolicyNode policyTree,
+        PublicKey subjectPublicKey)
+    {
+        super(trustAnchor, policyTree, subjectPublicKey);
+        if (certPath == null)
+            throw new NullPointerException("certPath must be non-null");
+        this.certPath = certPath;
+    }
+
+    /**
+     * Returns the built and validated certification path. The
+     * {@code CertPath} object does not include the trust anchor.
+     * Instead, use the {@link #getTrustAnchor() getTrustAnchor()} method to
+     * obtain the {@code TrustAnchor} that served as the trust anchor
+     * for the certification path.
+     *
+     * @return the built and validated {@code CertPath} (never
+     * {@code null})
+     */
+    public CertPath getCertPath() {
+        return certPath;
+    }
+
+    /**
+     * Return a printable representation of this
+     * {@code PKIXCertPathBuilderResult}.
+     *
+     * @return a {@code String} describing the contents of this
+     *         {@code PKIXCertPathBuilderResult}
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("PKIXCertPathBuilderResult: [\n");
+        sb.append("  Certification Path: " + certPath + "\n");
+        sb.append("  Trust Anchor: " + getTrustAnchor().toString() + "\n");
+        sb.append("  Policy Tree: " + String.valueOf(getPolicyTree()) + "\n");
+        sb.append("  Subject Public Key: " + getPublicKey() + "\n");
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/PKIXCertPathChecker.java b/java/security/cert/PKIXCertPathChecker.java
new file mode 100644
index 0000000..21e01bf
--- /dev/null
+++ b/java/security/cert/PKIXCertPathChecker.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * An abstract class that performs one or more checks on an
+ * {@code X509Certificate}.
+ *
+ * <p>A concrete implementation of the {@code PKIXCertPathChecker} class
+ * can be created to extend the PKIX certification path validation algorithm.
+ * For example, an implementation may check for and process a critical private
+ * extension of each certificate in a certification path.
+ *
+ * <p>Instances of {@code PKIXCertPathChecker} are passed as parameters
+ * using the {@link PKIXParameters#setCertPathCheckers setCertPathCheckers}
+ * or {@link PKIXParameters#addCertPathChecker addCertPathChecker} methods
+ * of the {@code PKIXParameters} and {@code PKIXBuilderParameters}
+ * class. Each of the {@code PKIXCertPathChecker}s {@link #check check}
+ * methods will be called, in turn, for each certificate processed by a PKIX
+ * {@code CertPathValidator} or {@code CertPathBuilder}
+ * implementation.
+ *
+ * <p>A {@code PKIXCertPathChecker} may be called multiple times on
+ * successive certificates in a certification path. Concrete subclasses
+ * are expected to maintain any internal state that may be necessary to
+ * check successive certificates. The {@link #init init} method is used
+ * to initialize the internal state of the checker so that the certificates
+ * of a new certification path may be checked. A stateful implementation
+ * <b>must</b> override the {@link #clone clone} method if necessary in
+ * order to allow a PKIX {@code CertPathBuilder} to efficiently
+ * backtrack and try other paths. In these situations, the
+ * {@code CertPathBuilder} is able to restore prior path validation
+ * states by restoring the cloned {@code PKIXCertPathChecker}s.
+ *
+ * <p>The order in which the certificates are presented to the
+ * {@code PKIXCertPathChecker} may be either in the forward direction
+ * (from target to most-trusted CA) or in the reverse direction (from
+ * most-trusted CA to target). A {@code PKIXCertPathChecker} implementation
+ * <b>must</b> support reverse checking (the ability to perform its checks when
+ * it is presented with certificates in the reverse direction) and <b>may</b>
+ * support forward checking (the ability to perform its checks when it is
+ * presented with certificates in the forward direction). The
+ * {@link #isForwardCheckingSupported isForwardCheckingSupported} method
+ * indicates whether forward checking is supported.
+ * <p>
+ * Additional input parameters required for executing the check may be
+ * specified through constructors of concrete implementations of this class.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see PKIXParameters
+ * @see PKIXBuilderParameters
+ *
+ * @since       1.4
+ * @author      Yassir Elley
+ * @author      Sean Mullan
+ */
+public abstract class PKIXCertPathChecker
+    implements CertPathChecker, Cloneable {
+
+    /**
+     * Default constructor.
+     */
+    protected PKIXCertPathChecker() {}
+
+    /**
+     * Initializes the internal state of this {@code PKIXCertPathChecker}.
+     * <p>
+     * The {@code forward} flag specifies the order that
+     * certificates will be passed to the {@link #check check} method
+     * (forward or reverse). A {@code PKIXCertPathChecker} <b>must</b>
+     * support reverse checking and <b>may</b> support forward checking.
+     *
+     * @param forward the order that certificates are presented to
+     * the {@code check} method. If {@code true}, certificates
+     * are presented from target to most-trusted CA (forward); if
+     * {@code false}, from most-trusted CA to target (reverse).
+     * @throws CertPathValidatorException if this
+     * {@code PKIXCertPathChecker} is unable to check certificates in
+     * the specified order; it should never be thrown if the forward flag
+     * is false since reverse checking must be supported
+     */
+    @Override
+    public abstract void init(boolean forward)
+        throws CertPathValidatorException;
+
+    /**
+     * Indicates if forward checking is supported. Forward checking refers
+     * to the ability of the {@code PKIXCertPathChecker} to perform
+     * its checks when certificates are presented to the {@code check}
+     * method in the forward direction (from target to most-trusted CA).
+     *
+     * @return {@code true} if forward checking is supported,
+     * {@code false} otherwise
+     */
+    @Override
+    public abstract boolean isForwardCheckingSupported();
+
+    /**
+     * Returns an immutable {@code Set} of X.509 certificate extensions
+     * that this {@code PKIXCertPathChecker} supports (i.e. recognizes, is
+     * able to process), or {@code null} if no extensions are supported.
+     * <p>
+     * Each element of the set is a {@code String} representing the
+     * Object Identifier (OID) of the X.509 extension that is supported.
+     * The OID is represented by a set of nonnegative integers separated by
+     * periods.
+     * <p>
+     * All X.509 certificate extensions that a {@code PKIXCertPathChecker}
+     * might possibly be able to process should be included in the set.
+     *
+     * @return an immutable {@code Set} of X.509 extension OIDs (in
+     * {@code String} format) supported by this
+     * {@code PKIXCertPathChecker}, or {@code null} if no
+     * extensions are supported
+     */
+    public abstract Set<String> getSupportedExtensions();
+
+    /**
+     * Performs the check(s) on the specified certificate using its internal
+     * state and removes any critical extensions that it processes from the
+     * specified collection of OID strings that represent the unresolved
+     * critical extensions. The certificates are presented in the order
+     * specified by the {@code init} method.
+     *
+     * @param cert the {@code Certificate} to be checked
+     * @param unresolvedCritExts a {@code Collection} of OID strings
+     * representing the current set of unresolved critical extensions
+     * @exception CertPathValidatorException if the specified certificate does
+     * not pass the check
+     */
+    public abstract void check(Certificate cert,
+            Collection<String> unresolvedCritExts)
+            throws CertPathValidatorException;
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation calls
+     * {@code check(cert, java.util.Collections.<String>emptySet())}.
+     */
+    @Override
+    public void check(Certificate cert) throws CertPathValidatorException {
+        check(cert, java.util.Collections.<String>emptySet());
+    }
+
+    /**
+     * Returns a clone of this object. Calls the {@code Object.clone()}
+     * method.
+     * All subclasses which maintain state must support and
+     * override this method, if necessary.
+     *
+     * @return a copy of this {@code PKIXCertPathChecker}
+     */
+    @Override
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+}
diff --git a/java/security/cert/PKIXCertPathValidatorResult.java b/java/security/cert/PKIXCertPathValidatorResult.java
new file mode 100644
index 0000000..b40cd39
--- /dev/null
+++ b/java/security/cert/PKIXCertPathValidatorResult.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.PublicKey;
+
+/**
+ * This class represents the successful result of the PKIX certification
+ * path validation algorithm.
+ *
+ * <p>Instances of {@code PKIXCertPathValidatorResult} are returned by the
+ * {@link CertPathValidator#validate validate} method of
+ * {@code CertPathValidator} objects implementing the PKIX algorithm.
+ *
+ * <p> All {@code PKIXCertPathValidatorResult} objects contain the
+ * valid policy tree and subject public key resulting from the
+ * validation algorithm, as well as a {@code TrustAnchor} describing
+ * the certification authority (CA) that served as a trust anchor for the
+ * certification path.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathValidatorResult
+ *
+ * @since       1.4
+ * @author      Yassir Elley
+ * @author      Sean Mullan
+ */
+public class PKIXCertPathValidatorResult implements CertPathValidatorResult {
+
+    private TrustAnchor trustAnchor;
+    private PolicyNode policyTree;
+    private PublicKey subjectPublicKey;
+
+    /**
+     * Creates an instance of {@code PKIXCertPathValidatorResult}
+     * containing the specified parameters.
+     *
+     * @param trustAnchor a {@code TrustAnchor} describing the CA that
+     * served as a trust anchor for the certification path
+     * @param policyTree the immutable valid policy tree, or {@code null}
+     * if there are no valid policies
+     * @param subjectPublicKey the public key of the subject
+     * @throws NullPointerException if the {@code subjectPublicKey} or
+     * {@code trustAnchor} parameters are {@code null}
+     */
+    public PKIXCertPathValidatorResult(TrustAnchor trustAnchor,
+        PolicyNode policyTree, PublicKey subjectPublicKey)
+    {
+        if (subjectPublicKey == null)
+            throw new NullPointerException("subjectPublicKey must be non-null");
+        if (trustAnchor == null)
+            throw new NullPointerException("trustAnchor must be non-null");
+        this.trustAnchor = trustAnchor;
+        this.policyTree = policyTree;
+        this.subjectPublicKey = subjectPublicKey;
+    }
+
+    /**
+     * Returns the {@code TrustAnchor} describing the CA that served
+     * as a trust anchor for the certification path.
+     *
+     * @return the {@code TrustAnchor} (never {@code null})
+     */
+    public TrustAnchor getTrustAnchor() {
+        return trustAnchor;
+    }
+
+    /**
+     * Returns the root node of the valid policy tree resulting from the
+     * PKIX certification path validation algorithm. The
+     * {@code PolicyNode} object that is returned and any objects that
+     * it returns through public methods are immutable.
+     *
+     * <p>Most applications will not need to examine the valid policy tree.
+     * They can achieve their policy processing goals by setting the
+     * policy-related parameters in {@code PKIXParameters}. However, more
+     * sophisticated applications, especially those that process policy
+     * qualifiers, may need to traverse the valid policy tree using the
+     * {@link PolicyNode#getParent PolicyNode.getParent} and
+     * {@link PolicyNode#getChildren PolicyNode.getChildren} methods.
+     *
+     * @return the root node of the valid policy tree, or {@code null}
+     * if there are no valid policies
+     */
+    public PolicyNode getPolicyTree() {
+        return policyTree;
+    }
+
+    /**
+     * Returns the public key of the subject (target) of the certification
+     * path, including any inherited public key parameters if applicable.
+     *
+     * @return the public key of the subject (never {@code null})
+     */
+    public PublicKey getPublicKey() {
+        return subjectPublicKey;
+    }
+
+    /**
+     * Returns a copy of this object.
+     *
+     * @return the copy
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+
+    /**
+     * Return a printable representation of this
+     * {@code PKIXCertPathValidatorResult}.
+     *
+     * @return a {@code String} describing the contents of this
+     *         {@code PKIXCertPathValidatorResult}
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("PKIXCertPathValidatorResult: [\n");
+        sb.append("  Trust Anchor: " + trustAnchor.toString() + "\n");
+        sb.append("  Policy Tree: " + String.valueOf(policyTree) + "\n");
+        sb.append("  Subject Public Key: " + subjectPublicKey + "\n");
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/PKIXParameters.java b/java/security/cert/PKIXParameters.java
new file mode 100644
index 0000000..4d8a344
--- /dev/null
+++ b/java/security/cert/PKIXParameters.java
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Parameters used as input for the PKIX {@code CertPathValidator}
+ * algorithm.
+ * <p>
+ * A PKIX {@code CertPathValidator} uses these parameters to
+ * validate a {@code CertPath} according to the PKIX certification path
+ * validation algorithm.
+ *
+ * <p>To instantiate a {@code PKIXParameters} object, an
+ * application must specify one or more <i>most-trusted CAs</i> as defined by
+ * the PKIX certification path validation algorithm. The most-trusted CAs
+ * can be specified using one of two constructors. An application
+ * can call {@link #PKIXParameters(Set) PKIXParameters(Set)},
+ * specifying a {@code Set} of {@code TrustAnchor} objects, each
+ * of which identify a most-trusted CA. Alternatively, an application can call
+ * {@link #PKIXParameters(KeyStore) PKIXParameters(KeyStore)}, specifying a
+ * {@code KeyStore} instance containing trusted certificate entries, each
+ * of which will be considered as a most-trusted CA.
+ * <p>
+ * Once a {@code PKIXParameters} object has been created, other parameters
+ * can be specified (by calling {@link #setInitialPolicies setInitialPolicies}
+ * or {@link #setDate setDate}, for instance) and then the
+ * {@code PKIXParameters} is passed along with the {@code CertPath}
+ * to be validated to {@link CertPathValidator#validate
+ * CertPathValidator.validate}.
+ * <p>
+ * Any parameter that is not set (or is set to {@code null}) will
+ * be set to the default value for that parameter. The default value for the
+ * {@code date} parameter is {@code null}, which indicates
+ * the current time when the path is validated. The default for the
+ * remaining parameters is the least constrained.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertPathValidator
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ * @author      Yassir Elley
+ */
+public class PKIXParameters implements CertPathParameters {
+
+    private Set<TrustAnchor> unmodTrustAnchors;
+    private Date date;
+    private List<PKIXCertPathChecker> certPathCheckers;
+    private String sigProvider;
+    private boolean revocationEnabled = true;
+    private Set<String> unmodInitialPolicies;
+    private boolean explicitPolicyRequired = false;
+    private boolean policyMappingInhibited = false;
+    private boolean anyPolicyInhibited = false;
+    private boolean policyQualifiersRejected = true;
+    private List<CertStore> certStores;
+    private CertSelector certSelector;
+
+    /**
+     * Creates an instance of {@code PKIXParameters} with the specified
+     * {@code Set} of most-trusted CAs. Each element of the
+     * set is a {@link TrustAnchor TrustAnchor}.
+     * <p>
+     * Note that the {@code Set} is copied to protect against
+     * subsequent modifications.
+     *
+     * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
+     * @throws InvalidAlgorithmParameterException if the specified
+     * {@code Set} is empty {@code (trustAnchors.isEmpty() == true)}
+     * @throws NullPointerException if the specified {@code Set} is
+     * {@code null}
+     * @throws ClassCastException if any of the elements in the {@code Set}
+     * are not of type {@code java.security.cert.TrustAnchor}
+     */
+    public PKIXParameters(Set<TrustAnchor> trustAnchors)
+        throws InvalidAlgorithmParameterException
+    {
+        setTrustAnchors(trustAnchors);
+
+        this.unmodInitialPolicies = Collections.<String>emptySet();
+        this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+        this.certStores = new ArrayList<CertStore>();
+    }
+
+    /**
+     * Creates an instance of {@code PKIXParameters} that
+     * populates the set of most-trusted CAs from the trusted
+     * certificate entries contained in the specified {@code KeyStore}.
+     * Only keystore entries that contain trusted {@code X509Certificates}
+     * are considered; all other certificate types are ignored.
+     *
+     * @param keystore a {@code KeyStore} from which the set of
+     * most-trusted CAs will be populated
+     * @throws KeyStoreException if the keystore has not been initialized
+     * @throws InvalidAlgorithmParameterException if the keystore does
+     * not contain at least one trusted certificate entry
+     * @throws NullPointerException if the keystore is {@code null}
+     */
+    public PKIXParameters(KeyStore keystore)
+        throws KeyStoreException, InvalidAlgorithmParameterException
+    {
+        if (keystore == null)
+            throw new NullPointerException("the keystore parameter must be " +
+                "non-null");
+        Set<TrustAnchor> hashSet = new HashSet<TrustAnchor>();
+        Enumeration<String> aliases = keystore.aliases();
+        while (aliases.hasMoreElements()) {
+            String alias = aliases.nextElement();
+            if (keystore.isCertificateEntry(alias)) {
+                Certificate cert = keystore.getCertificate(alias);
+                if (cert instanceof X509Certificate)
+                    hashSet.add(new TrustAnchor((X509Certificate)cert, null));
+            }
+        }
+        setTrustAnchors(hashSet);
+        this.unmodInitialPolicies = Collections.<String>emptySet();
+        this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+        this.certStores = new ArrayList<CertStore>();
+    }
+
+    /**
+     * Returns an immutable {@code Set} of the most-trusted
+     * CAs.
+     *
+     * @return an immutable {@code Set} of {@code TrustAnchor}s
+     * (never {@code null})
+     *
+     * @see #setTrustAnchors
+     */
+    public Set<TrustAnchor> getTrustAnchors() {
+        return this.unmodTrustAnchors;
+    }
+
+    /**
+     * Sets the {@code Set} of most-trusted CAs.
+     * <p>
+     * Note that the {@code Set} is copied to protect against
+     * subsequent modifications.
+     *
+     * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
+     * @throws InvalidAlgorithmParameterException if the specified
+     * {@code Set} is empty {@code (trustAnchors.isEmpty() == true)}
+     * @throws NullPointerException if the specified {@code Set} is
+     * {@code null}
+     * @throws ClassCastException if any of the elements in the set
+     * are not of type {@code java.security.cert.TrustAnchor}
+     *
+     * @see #getTrustAnchors
+     */
+    public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
+        throws InvalidAlgorithmParameterException
+    {
+        if (trustAnchors == null) {
+            throw new NullPointerException("the trustAnchors parameters must" +
+                " be non-null");
+        }
+        if (trustAnchors.isEmpty()) {
+            throw new InvalidAlgorithmParameterException("the trustAnchors " +
+                "parameter must be non-empty");
+        }
+        for (Iterator<TrustAnchor> i = trustAnchors.iterator(); i.hasNext(); ) {
+            if (!(i.next() instanceof TrustAnchor)) {
+                throw new ClassCastException("all elements of set must be "
+                    + "of type java.security.cert.TrustAnchor");
+            }
+        }
+        this.unmodTrustAnchors = Collections.unmodifiableSet
+                (new HashSet<TrustAnchor>(trustAnchors));
+    }
+
+    /**
+     * Returns an immutable {@code Set} of initial
+     * policy identifiers (OID strings), indicating that any one of these
+     * policies would be acceptable to the certificate user for the purposes of
+     * certification path processing. The default return value is an empty
+     * {@code Set}, which is interpreted as meaning that any policy would
+     * be acceptable.
+     *
+     * @return an immutable {@code Set} of initial policy OIDs in
+     * {@code String} format, or an empty {@code Set} (implying any
+     * policy is acceptable). Never returns {@code null}.
+     *
+     * @see #setInitialPolicies
+     */
+    public Set<String> getInitialPolicies() {
+        return this.unmodInitialPolicies;
+    }
+
+    /**
+     * Sets the {@code Set} of initial policy identifiers
+     * (OID strings), indicating that any one of these
+     * policies would be acceptable to the certificate user for the purposes of
+     * certification path processing. By default, any policy is acceptable
+     * (i.e. all policies), so a user that wants to allow any policy as
+     * acceptable does not need to call this method, or can call it
+     * with an empty {@code Set} (or {@code null}).
+     * <p>
+     * Note that the {@code Set} is copied to protect against
+     * subsequent modifications.
+     *
+     * @param initialPolicies a {@code Set} of initial policy
+     * OIDs in {@code String} format (or {@code null})
+     * @throws ClassCastException if any of the elements in the set are
+     * not of type {@code String}
+     *
+     * @see #getInitialPolicies
+     */
+    public void setInitialPolicies(Set<String> initialPolicies) {
+        if (initialPolicies != null) {
+            for (Iterator<String> i = initialPolicies.iterator();
+                        i.hasNext();) {
+                if (!(i.next() instanceof String))
+                    throw new ClassCastException("all elements of set must be "
+                        + "of type java.lang.String");
+            }
+            this.unmodInitialPolicies =
+                Collections.unmodifiableSet(new HashSet<String>(initialPolicies));
+        } else
+            this.unmodInitialPolicies = Collections.<String>emptySet();
+    }
+
+    /**
+     * Sets the list of {@code CertStore}s to be used in finding
+     * certificates and CRLs. May be {@code null}, in which case
+     * no {@code CertStore}s will be used. The first
+     * {@code CertStore}s in the list may be preferred to those that
+     * appear later.
+     * <p>
+     * Note that the {@code List} is copied to protect against
+     * subsequent modifications.
+     *
+     * @param stores a {@code List} of {@code CertStore}s (or
+     * {@code null})
+     * @throws ClassCastException if any of the elements in the list are
+     * not of type {@code java.security.cert.CertStore}
+     *
+     * @see #getCertStores
+     */
+    public void setCertStores(List<CertStore> stores) {
+        if (stores == null) {
+            this.certStores = new ArrayList<CertStore>();
+        } else {
+            for (Iterator<CertStore> i = stores.iterator(); i.hasNext();) {
+                if (!(i.next() instanceof CertStore)) {
+                    throw new ClassCastException("all elements of list must be "
+                        + "of type java.security.cert.CertStore");
+                }
+            }
+            this.certStores = new ArrayList<CertStore>(stores);
+        }
+    }
+
+    /**
+     * Adds a {@code CertStore} to the end of the list of
+     * {@code CertStore}s used in finding certificates and CRLs.
+     *
+     * @param store the {@code CertStore} to add. If {@code null},
+     * the store is ignored (not added to list).
+     */
+    public void addCertStore(CertStore store) {
+        if (store != null) {
+            this.certStores.add(store);
+        }
+    }
+
+    /**
+     * Returns an immutable {@code List} of {@code CertStore}s that
+     * are used to find certificates and CRLs.
+     *
+     * @return an immutable {@code List} of {@code CertStore}s
+     * (may be empty, but never {@code null})
+     *
+     * @see #setCertStores
+     */
+    public List<CertStore> getCertStores() {
+        return Collections.unmodifiableList
+                (new ArrayList<CertStore>(this.certStores));
+    }
+
+    /**
+     * Sets the RevocationEnabled flag. If this flag is true, the default
+     * revocation checking mechanism of the underlying PKIX service provider
+     * will be used. If this flag is false, the default revocation checking
+     * mechanism will be disabled (not used).
+     * <p>
+     * When a {@code PKIXParameters} object is created, this flag is set
+     * to true. This setting reflects the most common strategy for checking
+     * revocation, since each service provider must support revocation
+     * checking to be PKIX compliant. Sophisticated applications should set
+     * this flag to false when it is not practical to use a PKIX service
+     * provider's default revocation checking mechanism or when an alternative
+     * revocation checking mechanism is to be substituted (by also calling the
+     * {@link #addCertPathChecker addCertPathChecker} or {@link
+     * #setCertPathCheckers setCertPathCheckers} methods).
+     *
+     * @param val the new value of the RevocationEnabled flag
+     */
+    public void setRevocationEnabled(boolean val) {
+        revocationEnabled = val;
+    }
+
+    /**
+     * Checks the RevocationEnabled flag. If this flag is true, the default
+     * revocation checking mechanism of the underlying PKIX service provider
+     * will be used. If this flag is false, the default revocation checking
+     * mechanism will be disabled (not used). See the {@link
+     * #setRevocationEnabled setRevocationEnabled} method for more details on
+     * setting the value of this flag.
+     *
+     * @return the current value of the RevocationEnabled flag
+     */
+    public boolean isRevocationEnabled() {
+        return revocationEnabled;
+    }
+
+    /**
+     * Sets the ExplicitPolicyRequired flag. If this flag is true, an
+     * acceptable policy needs to be explicitly identified in every certificate.
+     * By default, the ExplicitPolicyRequired flag is false.
+     *
+     * @param val {@code true} if explicit policy is to be required,
+     * {@code false} otherwise
+     */
+    public void setExplicitPolicyRequired(boolean val) {
+        explicitPolicyRequired = val;
+    }
+
+    /**
+     * Checks if explicit policy is required. If this flag is true, an
+     * acceptable policy needs to be explicitly identified in every certificate.
+     * By default, the ExplicitPolicyRequired flag is false.
+     *
+     * @return {@code true} if explicit policy is required,
+     * {@code false} otherwise
+     */
+    public boolean isExplicitPolicyRequired() {
+        return explicitPolicyRequired;
+    }
+
+    /**
+     * Sets the PolicyMappingInhibited flag. If this flag is true, policy
+     * mapping is inhibited. By default, policy mapping is not inhibited (the
+     * flag is false).
+     *
+     * @param val {@code true} if policy mapping is to be inhibited,
+     * {@code false} otherwise
+     */
+    public void setPolicyMappingInhibited(boolean val) {
+        policyMappingInhibited = val;
+    }
+
+    /**
+     * Checks if policy mapping is inhibited. If this flag is true, policy
+     * mapping is inhibited. By default, policy mapping is not inhibited (the
+     * flag is false).
+     *
+     * @return true if policy mapping is inhibited, false otherwise
+     */
+    public boolean isPolicyMappingInhibited() {
+        return policyMappingInhibited;
+    }
+
+    /**
+     * Sets state to determine if the any policy OID should be processed
+     * if it is included in a certificate. By default, the any policy OID
+     * is not inhibited ({@link #isAnyPolicyInhibited isAnyPolicyInhibited()}
+     * returns {@code false}).
+     *
+     * @param val {@code true} if the any policy OID is to be
+     * inhibited, {@code false} otherwise
+     */
+    public void setAnyPolicyInhibited(boolean val) {
+        anyPolicyInhibited = val;
+    }
+
+    /**
+     * Checks whether the any policy OID should be processed if it
+     * is included in a certificate.
+     *
+     * @return {@code true} if the any policy OID is inhibited,
+     * {@code false} otherwise
+     */
+    public boolean isAnyPolicyInhibited() {
+        return anyPolicyInhibited;
+    }
+
+    /**
+     * Sets the PolicyQualifiersRejected flag. If this flag is true,
+     * certificates that include policy qualifiers in a certificate
+     * policies extension that is marked critical are rejected.
+     * If the flag is false, certificates are not rejected on this basis.
+     *
+     * <p> When a {@code PKIXParameters} object is created, this flag is
+     * set to true. This setting reflects the most common (and simplest)
+     * strategy for processing policy qualifiers. Applications that want to use
+     * a more sophisticated policy must set this flag to false.
+     * <p>
+     * Note that the PKIX certification path validation algorithm specifies
+     * that any policy qualifier in a certificate policies extension that is
+     * marked critical must be processed and validated. Otherwise the
+     * certification path must be rejected. If the policyQualifiersRejected flag
+     * is set to false, it is up to the application to validate all policy
+     * qualifiers in this manner in order to be PKIX compliant.
+     *
+     * @param qualifiersRejected the new value of the PolicyQualifiersRejected
+     * flag
+     * @see #getPolicyQualifiersRejected
+     * @see PolicyQualifierInfo
+     */
+    public void setPolicyQualifiersRejected(boolean qualifiersRejected) {
+        policyQualifiersRejected = qualifiersRejected;
+    }
+
+    /**
+     * Gets the PolicyQualifiersRejected flag. If this flag is true,
+     * certificates that include policy qualifiers in a certificate policies
+     * extension that is marked critical are rejected.
+     * If the flag is false, certificates are not rejected on this basis.
+     *
+     * <p> When a {@code PKIXParameters} object is created, this flag is
+     * set to true. This setting reflects the most common (and simplest)
+     * strategy for processing policy qualifiers. Applications that want to use
+     * a more sophisticated policy must set this flag to false.
+     *
+     * @return the current value of the PolicyQualifiersRejected flag
+     * @see #setPolicyQualifiersRejected
+     */
+    public boolean getPolicyQualifiersRejected() {
+        return policyQualifiersRejected;
+    }
+
+    /**
+     * Returns the time for which the validity of the certification path
+     * should be determined. If {@code null}, the current time is used.
+     * <p>
+     * Note that the {@code Date} returned is copied to protect against
+     * subsequent modifications.
+     *
+     * @return the {@code Date}, or {@code null} if not set
+     * @see #setDate
+     */
+    public Date getDate() {
+        if (date == null)
+            return null;
+        else
+            return (Date) this.date.clone();
+    }
+
+    /**
+     * Sets the time for which the validity of the certification path
+     * should be determined. If {@code null}, the current time is used.
+     * <p>
+     * Note that the {@code Date} supplied here is copied to protect
+     * against subsequent modifications.
+     *
+     * @param date the {@code Date}, or {@code null} for the
+     * current time
+     * @see #getDate
+     */
+    public void setDate(Date date) {
+        if (date != null)
+            this.date = (Date) date.clone();
+        else
+            date = null;
+    }
+
+    /**
+     * Sets a {@code List} of additional certification path checkers. If
+     * the specified {@code List} contains an object that is not a
+     * {@code PKIXCertPathChecker}, it is ignored.
+     * <p>
+     * Each {@code PKIXCertPathChecker} specified implements
+     * additional checks on a certificate. Typically, these are checks to
+     * process and verify private extensions contained in certificates.
+     * Each {@code PKIXCertPathChecker} should be instantiated with any
+     * initialization parameters needed to execute the check.
+     * <p>
+     * This method allows sophisticated applications to extend a PKIX
+     * {@code CertPathValidator} or {@code CertPathBuilder}.
+     * Each of the specified {@code PKIXCertPathChecker}s will be called,
+     * in turn, by a PKIX {@code CertPathValidator} or
+     * {@code CertPathBuilder} for each certificate processed or
+     * validated.
+     * <p>
+     * Regardless of whether these additional {@code PKIXCertPathChecker}s
+     * are set, a PKIX {@code CertPathValidator} or
+     * {@code CertPathBuilder} must perform all of the required PKIX
+     * checks on each certificate. The one exception to this rule is if the
+     * RevocationEnabled flag is set to false (see the {@link
+     * #setRevocationEnabled setRevocationEnabled} method).
+     * <p>
+     * Note that the {@code List} supplied here is copied and each
+     * {@code PKIXCertPathChecker} in the list is cloned to protect
+     * against subsequent modifications.
+     *
+     * @param checkers a {@code List} of {@code PKIXCertPathChecker}s.
+     * May be {@code null}, in which case no additional checkers will be
+     * used.
+     * @throws ClassCastException if any of the elements in the list
+     * are not of type {@code java.security.cert.PKIXCertPathChecker}
+     * @see #getCertPathCheckers
+     */
+    public void setCertPathCheckers(List<PKIXCertPathChecker> checkers) {
+        if (checkers != null) {
+            List<PKIXCertPathChecker> tmpList =
+                        new ArrayList<PKIXCertPathChecker>();
+            for (PKIXCertPathChecker checker : checkers) {
+                tmpList.add((PKIXCertPathChecker)checker.clone());
+            }
+            this.certPathCheckers = tmpList;
+        } else {
+            this.certPathCheckers = new ArrayList<PKIXCertPathChecker>();
+        }
+    }
+
+    /**
+     * Returns the {@code List} of certification path checkers.
+     * The returned {@code List} is immutable, and each
+     * {@code PKIXCertPathChecker} in the {@code List} is cloned
+     * to protect against subsequent modifications.
+     *
+     * @return an immutable {@code List} of
+     * {@code PKIXCertPathChecker}s (may be empty, but not
+     * {@code null})
+     * @see #setCertPathCheckers
+     */
+    public List<PKIXCertPathChecker> getCertPathCheckers() {
+        List<PKIXCertPathChecker> tmpList = new ArrayList<PKIXCertPathChecker>();
+        for (PKIXCertPathChecker ck : certPathCheckers) {
+            tmpList.add((PKIXCertPathChecker)ck.clone());
+        }
+        return Collections.unmodifiableList(tmpList);
+    }
+
+    /**
+     * Adds a {@code PKIXCertPathChecker} to the list of certification
+     * path checkers. See the {@link #setCertPathCheckers setCertPathCheckers}
+     * method for more details.
+     * <p>
+     * Note that the {@code PKIXCertPathChecker} is cloned to protect
+     * against subsequent modifications.
+     *
+     * @param checker a {@code PKIXCertPathChecker} to add to the list of
+     * checks. If {@code null}, the checker is ignored (not added to list).
+     */
+    public void addCertPathChecker(PKIXCertPathChecker checker) {
+        if (checker != null) {
+            certPathCheckers.add((PKIXCertPathChecker)checker.clone());
+        }
+    }
+
+    /**
+     * Returns the signature provider's name, or {@code null}
+     * if not set.
+     *
+     * @return the signature provider's name (or {@code null})
+     * @see #setSigProvider
+     */
+    public String getSigProvider() {
+        return this.sigProvider;
+    }
+
+    /**
+     * Sets the signature provider's name. The specified provider will be
+     * preferred when creating {@link java.security.Signature Signature}
+     * objects. If {@code null} or not set, the first provider found
+     * supporting the algorithm will be used.
+     *
+     * @param sigProvider the signature provider's name (or {@code null})
+     * @see #getSigProvider
+    */
+    public void setSigProvider(String sigProvider) {
+        this.sigProvider = sigProvider;
+    }
+
+    /**
+     * Returns the required constraints on the target certificate.
+     * The constraints are returned as an instance of {@code CertSelector}.
+     * If {@code null}, no constraints are defined.
+     *
+     * <p>Note that the {@code CertSelector} returned is cloned
+     * to protect against subsequent modifications.
+     *
+     * @return a {@code CertSelector} specifying the constraints
+     * on the target certificate (or {@code null})
+     * @see #setTargetCertConstraints
+     */
+    public CertSelector getTargetCertConstraints() {
+        if (certSelector != null) {
+            return (CertSelector) certSelector.clone();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the required constraints on the target certificate.
+     * The constraints are specified as an instance of
+     * {@code CertSelector}. If {@code null}, no constraints are
+     * defined.
+     *
+     * <p>Note that the {@code CertSelector} specified is cloned
+     * to protect against subsequent modifications.
+     *
+     * @param selector a {@code CertSelector} specifying the constraints
+     * on the target certificate (or {@code null})
+     * @see #getTargetCertConstraints
+     */
+    public void setTargetCertConstraints(CertSelector selector) {
+        if (selector != null)
+            certSelector = (CertSelector) selector.clone();
+        else
+            certSelector = null;
+    }
+
+    /**
+     * Makes a copy of this {@code PKIXParameters} object. Changes
+     * to the copy will not affect the original and vice versa.
+     *
+     * @return a copy of this {@code PKIXParameters} object
+     */
+    public Object clone() {
+        try {
+            PKIXParameters copy = (PKIXParameters)super.clone();
+
+            // must clone these because addCertStore, et al. modify them
+            if (certStores != null) {
+                copy.certStores = new ArrayList<CertStore>(certStores);
+            }
+            if (certPathCheckers != null) {
+                copy.certPathCheckers =
+                    new ArrayList<PKIXCertPathChecker>(certPathCheckers.size());
+                for (PKIXCertPathChecker checker : certPathCheckers) {
+                    copy.certPathCheckers.add(
+                                    (PKIXCertPathChecker)checker.clone());
+                }
+            }
+
+            // other class fields are immutable to public, don't bother
+            // to clone the read-only fields.
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+
+    /**
+     * Returns a formatted string describing the parameters.
+     *
+     * @return a formatted string describing the parameters.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[\n");
+
+        /* start with trusted anchor info */
+        if (unmodTrustAnchors != null) {
+            sb.append("  Trust Anchors: " + unmodTrustAnchors.toString()
+                + "\n");
+        }
+
+        /* now, append initial state information */
+        if (unmodInitialPolicies != null) {
+            if (unmodInitialPolicies.isEmpty()) {
+                sb.append("  Initial Policy OIDs: any\n");
+            } else {
+                sb.append("  Initial Policy OIDs: ["
+                    + unmodInitialPolicies.toString() + "]\n");
+            }
+        }
+
+        /* now, append constraints on all certificates in the path */
+        sb.append("  Validity Date: " + String.valueOf(date) + "\n");
+        sb.append("  Signature Provider: " + String.valueOf(sigProvider) + "\n");
+        sb.append("  Default Revocation Enabled: " + revocationEnabled + "\n");
+        sb.append("  Explicit Policy Required: " + explicitPolicyRequired + "\n");
+        sb.append("  Policy Mapping Inhibited: " + policyMappingInhibited + "\n");
+        sb.append("  Any Policy Inhibited: " + anyPolicyInhibited + "\n");
+        sb.append("  Policy Qualifiers Rejected: " + policyQualifiersRejected + "\n");
+
+        /* now, append target cert requirements */
+        sb.append("  Target Cert Constraints: " + String.valueOf(certSelector) + "\n");
+
+        /* finally, append miscellaneous parameters */
+        if (certPathCheckers != null)
+            sb.append("  Certification Path Checkers: ["
+                + certPathCheckers.toString() + "]\n");
+        if (certStores != null)
+            sb.append("  CertStores: [" + certStores.toString() + "]\n");
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/PKIXReason.java b/java/security/cert/PKIXReason.java
new file mode 100644
index 0000000..d58ded9
--- /dev/null
+++ b/java/security/cert/PKIXReason.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+/**
+ * The {@code PKIXReason} enumerates the potential PKIX-specific reasons
+ * that an X.509 certification path may be invalid according to the PKIX
+ * (RFC 3280) standard. These reasons are in addition to those of the
+ * {@code CertPathValidatorException.BasicReason} enumeration.
+ *
+ * @since 1.7
+ */
+public enum PKIXReason implements CertPathValidatorException.Reason {
+    /**
+     * The certificate does not chain correctly.
+     */
+    NAME_CHAINING,
+
+    /**
+     * The certificate's key usage is invalid.
+     */
+    INVALID_KEY_USAGE,
+
+    /**
+     * The policy constraints have been violated.
+     */
+    INVALID_POLICY,
+
+    /**
+     * No acceptable trust anchor found.
+     */
+    NO_TRUST_ANCHOR,
+
+    /**
+     * The certificate contains one or more unrecognized critical
+     * extensions.
+     */
+    UNRECOGNIZED_CRIT_EXT,
+
+    /**
+     * The certificate is not a CA certificate.
+     */
+    NOT_CA_CERT,
+
+    /**
+     * The path length constraint has been violated.
+     */
+    PATH_TOO_LONG,
+
+    /**
+     * The name constraints have been violated.
+     */
+    INVALID_NAME
+}
diff --git a/java/security/cert/PKIXRevocationChecker.java b/java/security/cert/PKIXRevocationChecker.java
new file mode 100644
index 0000000..620291e
--- /dev/null
+++ b/java/security/cert/PKIXRevocationChecker.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.cert;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A {@code PKIXCertPathChecker} for checking the revocation status of
+ * certificates with the PKIX algorithm.
+ *
+ * <p>A {@code PKIXRevocationChecker} checks the revocation status of
+ * certificates with the Online Certificate Status Protocol (OCSP) or
+ * Certificate Revocation Lists (CRLs). OCSP is described in RFC 2560 and
+ * is a network protocol for determining the status of a certificate. A CRL
+ * is a time-stamped list identifying revoked certificates, and RFC 5280
+ * describes an algorithm for determining the revocation status of certificates
+ * using CRLs.
+ *
+ * <p>Each {@code PKIXRevocationChecker} must be able to check the revocation
+ * status of certificates with OCSP and CRLs. By default, OCSP is the
+ * preferred mechanism for checking revocation status, with CRLs as the
+ * fallback mechanism. However, this preference can be switched to CRLs with
+ * the {@link Option#PREFER_CRLS PREFER_CRLS} option. In addition, the fallback
+ * mechanism can be disabled with the {@link Option#NO_FALLBACK NO_FALLBACK}
+ * option.
+ *
+ * <p>A {@code PKIXRevocationChecker} is obtained by calling the
+ * {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
+ * of a PKIX {@code CertPathValidator}. Additional parameters and options
+ * specific to revocation can be set (by calling the
+ * {@link #setOcspResponder setOcspResponder} method for instance). The
+ * {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object
+ * using the {@link PKIXParameters#addCertPathChecker addCertPathChecker}
+ * or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
+ * and then the {@code PKIXParameters} is passed along with the {@code CertPath}
+ * to be validated to the {@link CertPathValidator#validate validate} method
+ * of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
+ * this manner, it will be used to check revocation irrespective of the setting
+ * of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag.
+ * Similarly, a {@code PKIXRevocationChecker} may be added to a
+ * {@code PKIXBuilderParameters} object for use with a PKIX
+ * {@code CertPathBuilder}.
+ *
+ * <p>Note that when a {@code PKIXRevocationChecker} is added to
+ * {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
+ * thus any subsequent modifications to the {@code PKIXRevocationChecker}
+ * have no effect.
+ *
+ * <p>Any parameter that is not set (or is set to {@code null}) will be set to
+ * the default value for that parameter.
+ *
+ * <p><b>Concurrent Access</b>
+ *
+ * <p>Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the
+ * necessary locking. Multiple threads each manipulating separate objects
+ * need not synchronize.
+ *
+ * <p>See RFC 2560: X.509 Internet Public Key Infrastructure Online Certificate Status Protocol -
+ * OCSP, RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation
+ * List (CRL) Profile (Android note: this paragraph was originally in a malformed "see" tag below,
+ * moved here for correct construction of the docs).
+ *
+ * @since 1.8
+
+ */
+public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
+    private URI ocspResponder;
+    private X509Certificate ocspResponderCert;
+    private List<Extension> ocspExtensions = Collections.<Extension>emptyList();
+    private Map<X509Certificate, byte[]> ocspResponses = Collections.emptyMap();
+    private Set<Option> options = Collections.emptySet();
+
+    /**
+     * Default constructor.
+     */
+    protected PKIXRevocationChecker() {}
+
+    /**
+     * Sets the URI that identifies the location of the OCSP responder. This
+     * overrides the {@code ocsp.responderURL} security property and any
+     * responder specified in a certificate's Authority Information Access
+     * Extension, as defined in RFC 5280.
+     *
+     * @param uri the responder URI
+     */
+    public void setOcspResponder(URI uri) {
+        this.ocspResponder = uri;
+    }
+
+    /**
+     * Gets the URI that identifies the location of the OCSP responder. This
+     * overrides the {@code ocsp.responderURL} security property. If this
+     * parameter or the {@code ocsp.responderURL} property is not set, the
+     * location is determined from the certificate's Authority Information
+     * Access Extension, as defined in RFC 5280.
+     *
+     * @return the responder URI, or {@code null} if not set
+     */
+    public URI getOcspResponder() {
+        return ocspResponder;
+    }
+
+    /**
+     * Sets the OCSP responder's certificate. This overrides the
+     * {@code ocsp.responderCertSubjectName},
+     * {@code ocsp.responderCertIssuerName},
+     * and {@code ocsp.responderCertSerialNumber} security properties.
+     *
+     * @param cert the responder's certificate
+     */
+    public void setOcspResponderCert(X509Certificate cert) {
+        this.ocspResponderCert = cert;
+    }
+
+    /**
+     * Gets the OCSP responder's certificate. This overrides the
+     * {@code ocsp.responderCertSubjectName},
+     * {@code ocsp.responderCertIssuerName},
+     * and {@code ocsp.responderCertSerialNumber} security properties. If this
+     * parameter or the aforementioned properties are not set, then the
+     * responder's certificate is determined as specified in RFC 2560.
+     *
+     * @return the responder's certificate, or {@code null} if not set
+     */
+    public X509Certificate getOcspResponderCert() {
+        return ocspResponderCert;
+    }
+
+    // request extensions; single extensions not supported
+    /**
+     * Sets the optional OCSP request extensions.
+     *
+     * @param extensions a list of extensions. The list is copied to protect
+     *        against subsequent modification.
+     */
+    public void setOcspExtensions(List<Extension> extensions)
+    {
+        this.ocspExtensions = (extensions == null)
+                              ? Collections.<Extension>emptyList()
+                              : new ArrayList<Extension>(extensions);
+    }
+
+    /**
+     * Gets the optional OCSP request extensions.
+     *
+     * @return an unmodifiable list of extensions. The list is empty if no
+     *         extensions have been specified.
+     */
+    public List<Extension> getOcspExtensions() {
+        return Collections.unmodifiableList(ocspExtensions);
+    }
+
+    /**
+     * Sets the OCSP responses. These responses are used to determine
+     * the revocation status of the specified certificates when OCSP is used.
+     *
+     * @param responses a map of OCSP responses. Each key is an
+     *        {@code X509Certificate} that maps to the corresponding
+     *        DER-encoded OCSP response for that certificate. A deep copy of
+     *        the map is performed to protect against subsequent modification.
+     */
+    public void setOcspResponses(Map<X509Certificate, byte[]> responses)
+    {
+        if (responses == null) {
+            this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
+        } else {
+            Map<X509Certificate, byte[]> copy = new HashMap<>(responses.size());
+            for (Map.Entry<X509Certificate, byte[]> e : responses.entrySet()) {
+                copy.put(e.getKey(), e.getValue().clone());
+            }
+            this.ocspResponses = copy;
+        }
+    }
+
+    /**
+     * Gets the OCSP responses. These responses are used to determine
+     * the revocation status of the specified certificates when OCSP is used.
+     *
+     * @return a map of OCSP responses. Each key is an
+     *        {@code X509Certificate} that maps to the corresponding
+     *        DER-encoded OCSP response for that certificate. A deep copy of
+     *        the map is returned to protect against subsequent modification.
+     *        Returns an empty map if no responses have been specified.
+     */
+    public Map<X509Certificate, byte[]> getOcspResponses() {
+        Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
+        for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
+            copy.put(e.getKey(), e.getValue().clone());
+        }
+        return copy;
+    }
+
+    /**
+     * Sets the revocation options.
+     *
+     * @param options a set of revocation options. The set is copied to protect
+     *        against subsequent modification.
+     */
+    public void setOptions(Set<Option> options) {
+        this.options = (options == null)
+                       ? Collections.<Option>emptySet()
+                       : new HashSet<Option>(options);
+    }
+
+    /**
+     * Gets the revocation options.
+     *
+     * @return an unmodifiable set of revocation options. The set is empty if
+     *         no options have been specified.
+     */
+    public Set<Option> getOptions() {
+        return Collections.unmodifiableSet(options);
+    }
+
+    /**
+     * Returns a list containing the exceptions that are ignored by the
+     * revocation checker when the {@link Option#SOFT_FAIL SOFT_FAIL} option
+     * is set. The list is cleared each time {@link #init init} is called.
+     * The list is ordered in ascending order according to the certificate
+     * index returned by {@link CertPathValidatorException#getIndex getIndex}
+     * method of each entry.
+     * <p>
+     * An implementation of {@code PKIXRevocationChecker} is responsible for
+     * adding the ignored exceptions to the list.
+     *
+     * @return an unmodifiable list containing the ignored exceptions. The list
+     *         is empty if no exceptions have been ignored.
+     */
+    public abstract List<CertPathValidatorException> getSoftFailExceptions();
+
+    @Override
+    public PKIXRevocationChecker clone() {
+        PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
+        copy.ocspExtensions = new ArrayList<>(ocspExtensions);
+        copy.ocspResponses = new HashMap<>(ocspResponses);
+        // deep-copy the encoded responses, since they are mutable
+        for (Map.Entry<X509Certificate, byte[]> entry :
+                 copy.ocspResponses.entrySet())
+        {
+            byte[] encoded = entry.getValue();
+            entry.setValue(encoded.clone());
+        }
+        copy.options = new HashSet<>(options);
+        return copy;
+    }
+
+    /**
+     * Various revocation options that can be specified for the revocation
+     * checking mechanism.
+     */
+    public enum Option {
+        /**
+         * Only check the revocation status of end-entity certificates.
+         */
+        ONLY_END_ENTITY,
+        /**
+         * Prefer CRLs to OSCP. The default behavior is to prefer OCSP. Each
+         * PKIX implementation should document further details of their
+         * specific preference rules and fallback policies.
+         */
+        PREFER_CRLS,
+        /**
+         * Disable the fallback mechanism.
+         */
+        NO_FALLBACK,
+        /**
+         * Allow revocation check to succeed if the revocation status cannot be
+         * determined for one of the following reasons:
+         * <ul>
+         *  <li>The CRL or OCSP response cannot be obtained because of a
+         *      network error.
+         *  <li>The OCSP responder returns one of the following errors
+         *      specified in section 2.3 of RFC 2560: internalError or tryLater.
+         * </ul><br>
+         * Note that these conditions apply to both OCSP and CRLs, and unless
+         * the {@code NO_FALLBACK} option is set, the revocation check is
+         * allowed to succeed only if both mechanisms fail under one of the
+         * conditions as stated above.
+         * Exceptions that cause the network errors are ignored but can be
+         * later retrieved by calling the
+         * {@link #getSoftFailExceptions getSoftFailExceptions} method.
+         */
+        SOFT_FAIL
+    }
+}
diff --git a/java/security/cert/PolicyNode.java b/java/security/cert/PolicyNode.java
new file mode 100644
index 0000000..1633dcb
--- /dev/null
+++ b/java/security/cert/PolicyNode.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * An immutable valid policy tree node as defined by the PKIX certification
+ * path validation algorithm.
+ *
+ * <p>One of the outputs of the PKIX certification path validation
+ * algorithm is a valid policy tree, which includes the policies that
+ * were determined to be valid, how this determination was reached,
+ * and any policy qualifiers encountered. This tree is of depth
+ * <i>n</i>, where <i>n</i> is the length of the certification
+ * path that has been validated.
+ *
+ * <p>Most applications will not need to examine the valid policy tree.
+ * They can achieve their policy processing goals by setting the
+ * policy-related parameters in {@code PKIXParameters}. However,
+ * the valid policy tree is available for more sophisticated applications,
+ * especially those that process policy qualifiers.
+ *
+ * <p>{@link PKIXCertPathValidatorResult#getPolicyTree()
+ * PKIXCertPathValidatorResult.getPolicyTree} returns the root node of the
+ * valid policy tree. The tree can be traversed using the
+ * {@link #getChildren getChildren} and {@link #getParent getParent} methods.
+ * Data about a particular node can be retrieved using other methods of
+ * {@code PolicyNode}.
+ *
+ * <p><b>Concurrent Access</b>
+ * <p>All {@code PolicyNode} objects must be immutable and
+ * thread-safe. Multiple threads may concurrently invoke the methods defined
+ * in this class on a single {@code PolicyNode} object (or more than one)
+ * with no ill effects. This stipulation applies to all public fields and
+ * methods of this class and any added or overridden by subclasses.
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public interface PolicyNode {
+
+    /**
+     * Returns the parent of this node, or {@code null} if this is the
+     * root node.
+     *
+     * @return the parent of this node, or {@code null} if this is the
+     * root node
+     */
+    PolicyNode getParent();
+
+    /**
+     * Returns an iterator over the children of this node. Any attempts to
+     * modify the children of this node through the
+     * {@code Iterator}'s remove method must throw an
+     * {@code UnsupportedOperationException}.
+     *
+     * @return an iterator over the children of this node
+     */
+    Iterator<? extends PolicyNode> getChildren();
+
+    /**
+     * Returns the depth of this node in the valid policy tree.
+     *
+     * @return the depth of this node (0 for the root node, 1 for its
+     * children, and so on)
+     */
+    int getDepth();
+
+    /**
+     * Returns the valid policy represented by this node.
+     *
+     * @return the {@code String} OID of the valid policy
+     * represented by this node. For the root node, this method always returns
+     * the special anyPolicy OID: "2.5.29.32.0".
+     */
+    String getValidPolicy();
+
+    /**
+     * Returns the set of policy qualifiers associated with the
+     * valid policy represented by this node.
+     *
+     * @return an immutable {@code Set} of
+     * {@code PolicyQualifierInfo}s. For the root node, this
+     * is always an empty {@code Set}.
+     */
+    Set<? extends PolicyQualifierInfo> getPolicyQualifiers();
+
+    /**
+     * Returns the set of expected policies that would satisfy this
+     * node's valid policy in the next certificate to be processed.
+     *
+     * @return an immutable {@code Set} of expected policy
+     * {@code String} OIDs. For the root node, this method
+     * always returns a {@code Set} with one element, the
+     * special anyPolicy OID: "2.5.29.32.0".
+     */
+    Set<String> getExpectedPolicies();
+
+    /**
+     * Returns the criticality indicator of the certificate policy extension
+     * in the most recently processed certificate.
+     *
+     * @return {@code true} if extension marked critical,
+     * {@code false} otherwise. For the root node, {@code false}
+     * is always returned.
+     */
+    boolean isCritical();
+}
diff --git a/java/security/cert/PolicyQualifierInfo.java b/java/security/cert/PolicyQualifierInfo.java
new file mode 100644
index 0000000..ec06a88
--- /dev/null
+++ b/java/security/cert/PolicyQualifierInfo.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+
+import sun.misc.HexDumpEncoder;
+import sun.security.util.DerValue;
+
+/**
+ * An immutable policy qualifier represented by the ASN.1 PolicyQualifierInfo
+ * structure.
+ *
+ * <p>The ASN.1 definition is as follows:
+ * <pre>
+ *   PolicyQualifierInfo ::= SEQUENCE {
+ *        policyQualifierId       PolicyQualifierId,
+ *        qualifier               ANY DEFINED BY policyQualifierId }
+ * </pre>
+ * <p>
+ * A certificate policies extension, if present in an X.509 version 3
+ * certificate, contains a sequence of one or more policy information terms,
+ * each of which consists of an object identifier (OID) and optional
+ * qualifiers. In an end-entity certificate, these policy information terms
+ * indicate the policy under which the certificate has been issued and the
+ * purposes for which the certificate may be used. In a CA certificate, these
+ * policy information terms limit the set of policies for certification paths
+ * which include this certificate.
+ * <p>
+ * A {@code Set} of {@code PolicyQualifierInfo} objects are returned
+ * by the {@link PolicyNode#getPolicyQualifiers PolicyNode.getPolicyQualifiers}
+ * method. This allows applications with specific policy requirements to
+ * process and validate each policy qualifier. Applications that need to
+ * process policy qualifiers should explicitly set the
+ * {@code policyQualifiersRejected} flag to false (by calling the
+ * {@link PKIXParameters#setPolicyQualifiersRejected
+ * PKIXParameters.setPolicyQualifiersRejected} method) before validating
+ * a certification path.
+ *
+ * <p>Note that the PKIX certification path validation algorithm specifies
+ * that any policy qualifier in a certificate policies extension that is
+ * marked critical must be processed and validated. Otherwise the
+ * certification path must be rejected. If the
+ * {@code policyQualifiersRejected} flag is set to false, it is up to
+ * the application to validate all policy qualifiers in this manner in order
+ * to be PKIX compliant.
+ *
+ * <p><b>Concurrent Access</b>
+ *
+ * <p>All {@code PolicyQualifierInfo} objects must be immutable and
+ * thread-safe. That is, multiple threads may concurrently invoke the
+ * methods defined in this class on a single {@code PolicyQualifierInfo}
+ * object (or more than one) with no ill effects. Requiring
+ * {@code PolicyQualifierInfo} objects to be immutable and thread-safe
+ * allows them to be passed around to various pieces of code without
+ * worrying about coordinating access.
+ *
+ * @author      seth proctor
+ * @author      Sean Mullan
+ * @since       1.4
+ */
+public class PolicyQualifierInfo {
+
+    private byte [] mEncoded;
+    private String mId;
+    private byte [] mData;
+    private String pqiString;
+
+    /**
+     * Creates an instance of {@code PolicyQualifierInfo} from the
+     * encoded bytes. The encoded byte array is copied on construction.
+     *
+     * @param encoded a byte array containing the qualifier in DER encoding
+     * @exception IOException thrown if the byte array does not represent a
+     * valid and parsable policy qualifier
+     */
+    public PolicyQualifierInfo(byte[] encoded) throws IOException {
+        mEncoded = encoded.clone();
+
+        DerValue val = new DerValue(mEncoded);
+        if (val.tag != DerValue.tag_Sequence)
+            throw new IOException("Invalid encoding for PolicyQualifierInfo");
+
+        mId = (val.data.getDerValue()).getOID().toString();
+        byte [] tmp = val.data.toByteArray();
+        if (tmp == null) {
+            mData = null;
+        } else {
+            mData = new byte[tmp.length];
+            System.arraycopy(tmp, 0, mData, 0, tmp.length);
+        }
+    }
+
+    /**
+     * Returns the {@code policyQualifierId} field of this
+     * {@code PolicyQualifierInfo}. The {@code policyQualifierId}
+     * is an Object Identifier (OID) represented by a set of nonnegative
+     * integers separated by periods.
+     *
+     * @return the OID (never {@code null})
+     */
+    public final String getPolicyQualifierId() {
+        return mId;
+    }
+
+    /**
+     * Returns the ASN.1 DER encoded form of this
+     * {@code PolicyQualifierInfo}.
+     *
+     * @return the ASN.1 DER encoded bytes (never {@code null}).
+     * Note that a copy is returned, so the data is cloned each time
+     * this method is called.
+     */
+    public final byte[] getEncoded() {
+        return mEncoded.clone();
+    }
+
+    /**
+     * Returns the ASN.1 DER encoded form of the {@code qualifier}
+     * field of this {@code PolicyQualifierInfo}.
+     *
+     * @return the ASN.1 DER encoded bytes of the {@code qualifier}
+     * field. Note that a copy is returned, so the data is cloned each
+     * time this method is called.
+     */
+    public final byte[] getPolicyQualifier() {
+        return (mData == null ? null : mData.clone());
+    }
+
+    /**
+     * Return a printable representation of this
+     * {@code PolicyQualifierInfo}.
+     *
+     * @return a {@code String} describing the contents of this
+     *         {@code PolicyQualifierInfo}
+     */
+    public String toString() {
+        if (pqiString != null)
+            return pqiString;
+        HexDumpEncoder enc = new HexDumpEncoder();
+        StringBuffer sb = new StringBuffer();
+        sb.append("PolicyQualifierInfo: [\n");
+        sb.append("  qualifierID: " + mId + "\n");
+        sb.append("  qualifier: " +
+            (mData == null ? "null" : enc.encodeBuffer(mData)) + "\n");
+        sb.append("]");
+        pqiString = sb.toString();
+        return pqiString;
+    }
+}
diff --git a/java/security/cert/TrustAnchor.java b/java/security/cert/TrustAnchor.java
new file mode 100644
index 0000000..c98bf81
--- /dev/null
+++ b/java/security/cert/TrustAnchor.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.x509.NameConstraintsExtension;
+import sun.security.x509.X500Name;
+
+/**
+ * A trust anchor or most-trusted Certification Authority (CA).
+ * <p>
+ * This class represents a "most-trusted CA", which is used as a trust anchor
+ * for validating X.509 certification paths. A most-trusted CA includes the
+ * public key of the CA, the CA's name, and any constraints upon the set of
+ * paths which may be validated using this key. These parameters can be
+ * specified in the form of a trusted {@code X509Certificate} or as
+ * individual parameters.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>All {@code TrustAnchor} objects must be immutable and
+ * thread-safe. That is, multiple threads may concurrently invoke the
+ * methods defined in this class on a single {@code TrustAnchor}
+ * object (or more than one) with no ill effects. Requiring
+ * {@code TrustAnchor} objects to be immutable and thread-safe
+ * allows them to be passed around to various pieces of code without
+ * worrying about coordinating access. This stipulation applies to all
+ * public fields and methods of this class and any added or overridden
+ * by subclasses.
+ *
+ * @see PKIXParameters#PKIXParameters(Set)
+ * @see PKIXBuilderParameters#PKIXBuilderParameters(Set, CertSelector)
+ *
+ * @since       1.4
+ * @author      Sean Mullan
+ */
+public class TrustAnchor {
+
+    private final PublicKey pubKey;
+    private final String caName;
+    private final X500Principal caPrincipal;
+    private final X509Certificate trustedCert;
+    private byte[] ncBytes;
+    private NameConstraintsExtension nc;
+
+    /**
+     * Creates an instance of {@code TrustAnchor} with the specified
+     * {@code X509Certificate} and optional name constraints, which
+     * are intended to be used as additional constraints when validating
+     * an X.509 certification path.
+     * <p>
+     * The name constraints are specified as a byte array. This byte array
+     * should contain the DER encoded form of the name constraints, as they
+     * would appear in the NameConstraints structure defined in
+     * <a href="http://www.ietf.org/rfc/rfc3280">RFC 3280</a>
+     * and X.509. The ASN.1 definition of this structure appears below.
+     *
+     * <pre>{@code
+     *  NameConstraints ::= SEQUENCE {
+     *       permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+     *       excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+     *
+     *  GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+     *
+     *  GeneralSubtree ::= SEQUENCE {
+     *       base                    GeneralName,
+     *       minimum         [0]     BaseDistance DEFAULT 0,
+     *       maximum         [1]     BaseDistance OPTIONAL }
+     *
+     *  BaseDistance ::= INTEGER (0..MAX)
+     *
+     *  GeneralName ::= CHOICE {
+     *       otherName                       [0]     OtherName,
+     *       rfc822Name                      [1]     IA5String,
+     *       dNSName                         [2]     IA5String,
+     *       x400Address                     [3]     ORAddress,
+     *       directoryName                   [4]     Name,
+     *       ediPartyName                    [5]     EDIPartyName,
+     *       uniformResourceIdentifier       [6]     IA5String,
+     *       iPAddress                       [7]     OCTET STRING,
+     *       registeredID                    [8]     OBJECT IDENTIFIER}
+     * }</pre>
+     * <p>
+     * Note that the name constraints byte array supplied is cloned to protect
+     * against subsequent modifications.
+     *
+     * @param trustedCert a trusted {@code X509Certificate}
+     * @param nameConstraints a byte array containing the ASN.1 DER encoding of
+     * a NameConstraints extension to be used for checking name constraints.
+     * Only the value of the extension is included, not the OID or criticality
+     * flag. Specify {@code null} to omit the parameter.
+     * @throws IllegalArgumentException if the name constraints cannot be
+     * decoded
+     * @throws NullPointerException if the specified
+     * {@code X509Certificate} is {@code null}
+     */
+    public TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints)
+    {
+        if (trustedCert == null)
+            throw new NullPointerException("the trustedCert parameter must " +
+                "be non-null");
+        this.trustedCert = trustedCert;
+        this.pubKey = null;
+        this.caName = null;
+        this.caPrincipal = null;
+        setNameConstraints(nameConstraints);
+    }
+
+    /**
+     * Creates an instance of {@code TrustAnchor} where the
+     * most-trusted CA is specified as an X500Principal and public key.
+     * Name constraints are an optional parameter, and are intended to be used
+     * as additional constraints when validating an X.509 certification path.
+     * <p>
+     * The name constraints are specified as a byte array. This byte array
+     * contains the DER encoded form of the name constraints, as they
+     * would appear in the NameConstraints structure defined in RFC 3280
+     * and X.509. The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #TrustAnchor(X509Certificate, byte[])
+     * TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) }.
+     * <p>
+     * Note that the name constraints byte array supplied here is cloned to
+     * protect against subsequent modifications.
+     *
+     * @param caPrincipal the name of the most-trusted CA as X500Principal
+     * @param pubKey the public key of the most-trusted CA
+     * @param nameConstraints a byte array containing the ASN.1 DER encoding of
+     * a NameConstraints extension to be used for checking name constraints.
+     * Only the value of the extension is included, not the OID or criticality
+     * flag. Specify {@code null} to omit the parameter.
+     * @throws NullPointerException if the specified {@code caPrincipal} or
+     * {@code pubKey} parameter is {@code null}
+     * @since 1.5
+     */
+    public TrustAnchor(X500Principal caPrincipal, PublicKey pubKey,
+            byte[] nameConstraints) {
+        if ((caPrincipal == null) || (pubKey == null)) {
+            throw new NullPointerException();
+        }
+        this.trustedCert = null;
+        this.caPrincipal = caPrincipal;
+        this.caName = caPrincipal.getName();
+        this.pubKey = pubKey;
+        setNameConstraints(nameConstraints);
+    }
+
+    /**
+     * Creates an instance of {@code TrustAnchor} where the
+     * most-trusted CA is specified as a distinguished name and public key.
+     * Name constraints are an optional parameter, and are intended to be used
+     * as additional constraints when validating an X.509 certification path.
+     * <p>
+     * The name constraints are specified as a byte array. This byte array
+     * contains the DER encoded form of the name constraints, as they
+     * would appear in the NameConstraints structure defined in RFC 3280
+     * and X.509. The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #TrustAnchor(X509Certificate, byte[])
+     * TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) }.
+     * <p>
+     * Note that the name constraints byte array supplied here is cloned to
+     * protect against subsequent modifications.
+     *
+     * @param caName the X.500 distinguished name of the most-trusted CA in
+     * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a>
+     * {@code String} format
+     * @param pubKey the public key of the most-trusted CA
+     * @param nameConstraints a byte array containing the ASN.1 DER encoding of
+     * a NameConstraints extension to be used for checking name constraints.
+     * Only the value of the extension is included, not the OID or criticality
+     * flag. Specify {@code null} to omit the parameter.
+     * @throws IllegalArgumentException if the specified
+     * {@code caName} parameter is empty {@code (caName.length() == 0)}
+     * or incorrectly formatted or the name constraints cannot be decoded
+     * @throws NullPointerException if the specified {@code caName} or
+     * {@code pubKey} parameter is {@code null}
+     */
+    public TrustAnchor(String caName, PublicKey pubKey, byte[] nameConstraints)
+    {
+        if (pubKey == null)
+            throw new NullPointerException("the pubKey parameter must be " +
+                "non-null");
+        if (caName == null)
+            throw new NullPointerException("the caName parameter must be " +
+                "non-null");
+        if (caName.length() == 0)
+            throw new IllegalArgumentException("the caName " +
+                "parameter must be a non-empty String");
+        // check if caName is formatted correctly
+        this.caPrincipal = new X500Principal(caName);
+        this.pubKey = pubKey;
+        this.caName = caName;
+        this.trustedCert = null;
+        setNameConstraints(nameConstraints);
+    }
+
+    /**
+     * Returns the most-trusted CA certificate.
+     *
+     * @return a trusted {@code X509Certificate} or {@code null}
+     * if the trust anchor was not specified as a trusted certificate
+     */
+    public final X509Certificate getTrustedCert() {
+        return this.trustedCert;
+    }
+
+    /**
+     * Returns the name of the most-trusted CA as an X500Principal.
+     *
+     * @return the X.500 distinguished name of the most-trusted CA, or
+     * {@code null} if the trust anchor was not specified as a trusted
+     * public key and name or X500Principal pair
+     * @since 1.5
+     */
+    public final X500Principal getCA() {
+        return this.caPrincipal;
+    }
+
+    /**
+     * Returns the name of the most-trusted CA in RFC 2253 {@code String}
+     * format.
+     *
+     * @return the X.500 distinguished name of the most-trusted CA, or
+     * {@code null} if the trust anchor was not specified as a trusted
+     * public key and name or X500Principal pair
+     */
+    public final String getCAName() {
+        return this.caName;
+    }
+
+    /**
+     * Returns the public key of the most-trusted CA.
+     *
+     * @return the public key of the most-trusted CA, or {@code null}
+     * if the trust anchor was not specified as a trusted public key and name
+     * or X500Principal pair
+     */
+    public final PublicKey getCAPublicKey() {
+        return this.pubKey;
+    }
+
+    /**
+     * Decode the name constraints and clone them if not null.
+     */
+    private void setNameConstraints(byte[] bytes) {
+        if (bytes == null) {
+            ncBytes = null;
+            nc = null;
+        } else {
+            ncBytes = bytes.clone();
+            // validate DER encoding
+            try {
+                nc = new NameConstraintsExtension(Boolean.FALSE, bytes);
+            } catch (IOException ioe) {
+                IllegalArgumentException iae =
+                    new IllegalArgumentException(ioe.getMessage());
+                iae.initCause(ioe);
+                throw iae;
+            }
+        }
+    }
+
+    /**
+     * Returns the name constraints parameter. The specified name constraints
+     * are associated with this trust anchor and are intended to be used
+     * as additional constraints when validating an X.509 certification path.
+     * <p>
+     * The name constraints are returned as a byte array. This byte array
+     * contains the DER encoded form of the name constraints, as they
+     * would appear in the NameConstraints structure defined in RFC 3280
+     * and X.509. The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #TrustAnchor(X509Certificate, byte[])
+     * TrustAnchor(X509Certificate trustedCert, byte[] nameConstraints) }.
+     * <p>
+     * Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return a byte array containing the ASN.1 DER encoding of
+     *         a NameConstraints extension used for checking name constraints,
+     *         or {@code null} if not set.
+     */
+    public final byte [] getNameConstraints() {
+        return ncBytes == null ? null : ncBytes.clone();
+    }
+
+    /**
+     * Returns a formatted string describing the {@code TrustAnchor}.
+     *
+     * @return a formatted string describing the {@code TrustAnchor}
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("[\n");
+        if (pubKey != null) {
+            sb.append("  Trusted CA Public Key: " + pubKey.toString() + "\n");
+            sb.append("  Trusted CA Issuer Name: "
+                + String.valueOf(caName) + "\n");
+        } else {
+            sb.append("  Trusted CA cert: " + trustedCert.toString() + "\n");
+        }
+        if (nc != null)
+            sb.append("  Name Constraints: " + nc.toString() + "\n");
+        return sb.toString();
+    }
+}
diff --git a/java/security/cert/X509CRL.java b/java/security/cert/X509CRL.java
new file mode 100644
index 0000000..927852b
--- /dev/null
+++ b/java/security/cert/X509CRL.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.InvalidKeyException;
+import java.security.SignatureException;
+import java.security.Principal;
+import java.security.Provider;
+import java.security.PublicKey;
+import javax.security.auth.x500.X500Principal;
+
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.Set;
+import java.util.Arrays;
+
+import sun.security.x509.X509CRLImpl;
+
+/**
+ * <p>
+ * Abstract class for an X.509 Certificate Revocation List (CRL).
+ * A CRL is a time-stamped list identifying revoked certificates.
+ * It is signed by a Certificate Authority (CA) and made freely
+ * available in a public repository.
+ *
+ * <p>Each revoked certificate is
+ * identified in a CRL by its certificate serial number. When a
+ * certificate-using system uses a certificate (e.g., for verifying a
+ * remote user's digital signature), that system not only checks the
+ * certificate signature and validity but also acquires a suitably-
+ * recent CRL and checks that the certificate serial number is not on
+ * that CRL.  The meaning of "suitably-recent" may vary with local
+ * policy, but it usually means the most recently-issued CRL.  A CA
+ * issues a new CRL on a regular periodic basis (e.g., hourly, daily, or
+ * weekly).  Entries are added to CRLs as revocations occur, and an
+ * entry may be removed when the certificate expiration date is reached.
+ * <p>
+ * The X.509 v2 CRL format is described below in ASN.1:
+ * <pre>
+ * CertificateList  ::=  SEQUENCE  {
+ *     tbsCertList          TBSCertList,
+ *     signatureAlgorithm   AlgorithmIdentifier,
+ *     signature            BIT STRING  }
+ * </pre>
+ * <p>
+ * More information can be found in
+ * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
+ * Public Key Infrastructure Certificate and CRL Profile</a>.
+ * <p>
+ * The ASN.1 definition of {@code tbsCertList} is:
+ * <pre>
+ * TBSCertList  ::=  SEQUENCE  {
+ *     version                 Version OPTIONAL,
+ *                             -- if present, must be v2
+ *     signature               AlgorithmIdentifier,
+ *     issuer                  Name,
+ *     thisUpdate              ChoiceOfTime,
+ *     nextUpdate              ChoiceOfTime OPTIONAL,
+ *     revokedCertificates     SEQUENCE OF SEQUENCE  {
+ *         userCertificate         CertificateSerialNumber,
+ *         revocationDate          ChoiceOfTime,
+ *         crlEntryExtensions      Extensions OPTIONAL
+ *                                 -- if present, must be v2
+ *         }  OPTIONAL,
+ *     crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
+ *                                  -- if present, must be v2
+ *     }
+ * </pre>
+ * <p>
+ * CRLs are instantiated using a certificate factory. The following is an
+ * example of how to instantiate an X.509 CRL:
+ * <pre>{@code
+ * try (InputStream inStream = new FileInputStream("fileName-of-crl")) {
+ *     CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ *     X509CRL crl = (X509CRL)cf.generateCRL(inStream);
+ * }
+ * }</pre>
+ *
+ * @author Hemma Prafullchandra
+ *
+ *
+ * @see CRL
+ * @see CertificateFactory
+ * @see X509Extension
+ */
+
+public abstract class X509CRL extends CRL implements X509Extension {
+
+    private transient X500Principal issuerPrincipal;
+
+    /**
+     * Constructor for X.509 CRLs.
+     */
+    protected X509CRL() {
+        super("X.509");
+    }
+
+    /**
+     * Compares this CRL for equality with the given
+     * object. If the {@code other} object is an
+     * {@code instanceof} {@code X509CRL}, then
+     * its encoded form is retrieved and compared with the
+     * encoded form of this CRL.
+     *
+     * @param other the object to test for equality with this CRL.
+     *
+     * @return true iff the encoded forms of the two CRLs
+     * match, false otherwise.
+     */
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof X509CRL)) {
+            return false;
+        }
+        try {
+            byte[] thisCRL = X509CRLImpl.getEncodedInternal(this);
+            byte[] otherCRL = X509CRLImpl.getEncodedInternal((X509CRL)other);
+
+            return Arrays.equals(thisCRL, otherCRL);
+        } catch (CRLException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns a hashcode value for this CRL from its
+     * encoded form.
+     *
+     * @return the hashcode value.
+     */
+    public int hashCode() {
+        int retval = 0;
+        try {
+            byte[] crlData = X509CRLImpl.getEncodedInternal(this);
+            for (int i = 1; i < crlData.length; i++) {
+                 retval += crlData[i] * i;
+            }
+            return retval;
+        } catch (CRLException e) {
+            return retval;
+        }
+    }
+
+    /**
+     * Returns the ASN.1 DER-encoded form of this CRL.
+     *
+     * @return the encoded form of this certificate
+     * @exception CRLException if an encoding error occurs.
+     */
+    public abstract byte[] getEncoded()
+        throws CRLException;
+
+    /**
+     * Verifies that this CRL was signed using the
+     * private key that corresponds to the given public key.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception NoSuchProviderException if there's no default provider.
+     * @exception SignatureException on signature errors.
+     * @exception CRLException on encoding errors.
+     */
+    public abstract void verify(PublicKey key)
+        throws CRLException,  NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException,
+        SignatureException;
+
+    /**
+     * Verifies that this CRL was signed using the
+     * private key that corresponds to the given public key.
+     * This method uses the signature verification engine
+     * supplied by the given provider.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     * @param sigProvider the name of the signature provider.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception NoSuchProviderException on incorrect provider.
+     * @exception SignatureException on signature errors.
+     * @exception CRLException on encoding errors.
+     */
+    public abstract void verify(PublicKey key, String sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, NoSuchProviderException,
+        SignatureException;
+
+    /**
+     * Verifies that this CRL was signed using the
+     * private key that corresponds to the given public key.
+     * This method uses the signature verification engine
+     * supplied by the given provider. Note that the specified Provider object
+     * does not have to be registered in the provider list.
+     *
+     * This method was added to version 1.8 of the Java Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method is not {@code abstract}
+     * and it provides a default implementation.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     * @param sigProvider the signature provider.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception SignatureException on signature errors.
+     * @exception CRLException on encoding errors.
+     * @since 1.8
+     */
+    public void verify(PublicKey key, Provider sigProvider)
+        throws CRLException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException {
+        // Android-changed: Eliminate infinite recursion in default implementation.
+        // As the javadoc says, this "default implementation" was introduced as to avoid breaking
+        // providers that generate concrete subclasses of this class.
+        // The method X509Impl in the original definition calls this method, thus entering an
+        // infinite recursive loop. This strange behaviour was checked to be not specific to
+        // libcore by running a test with vogar --mode=jvm .  See b/31294527.
+        // This is fixed upstream in OpenJDK 10.
+        //
+        // X509CRLImpl.verify(this, key, sigProvider);
+        throw new UnsupportedOperationException(
+                "X509CRL instance doesn't not support X509CRL#verify(PublicKey, Provider)");
+    }
+
+    /**
+     * Gets the {@code version} (version number) value from the CRL.
+     * The ASN.1 definition for this is:
+     * <pre>
+     * version    Version OPTIONAL,
+     *             -- if present, must be v2
+     *
+     * Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+     *             -- v3 does not apply to CRLs but appears for consistency
+     *             -- with definition of Version for certs
+     * </pre>
+     *
+     * @return the version number, i.e. 1 or 2.
+     */
+    public abstract int getVersion();
+
+    /**
+     * <strong>Denigrated</strong>, replaced by {@linkplain
+     * #getIssuerX500Principal()}. This method returns the {@code issuer}
+     * as an implementation specific Principal object, which should not be
+     * relied upon by portable code.
+     *
+     * <p>
+     * Gets the {@code issuer} (issuer distinguished name) value from
+     * the CRL. The issuer name identifies the entity that signed (and
+     * issued) the CRL.
+     *
+     * <p>The issuer name field contains an
+     * X.500 distinguished name (DN).
+     * The ASN.1 definition for this is:
+     * <pre>
+     * issuer    Name
+     *
+     * Name ::= CHOICE { RDNSequence }
+     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+     * RelativeDistinguishedName ::=
+     *     SET OF AttributeValueAssertion
+     *
+     * AttributeValueAssertion ::= SEQUENCE {
+     *                               AttributeType,
+     *                               AttributeValue }
+     * AttributeType ::= OBJECT IDENTIFIER
+     * AttributeValue ::= ANY
+     * </pre>
+     * The {@code Name} describes a hierarchical name composed of
+     * attributes,
+     * such as country name, and corresponding values, such as US.
+     * The type of the {@code AttributeValue} component is determined by
+     * the {@code AttributeType}; in general it will be a
+     * {@code directoryString}. A {@code directoryString} is usually
+     * one of {@code PrintableString},
+     * {@code TeletexString} or {@code UniversalString}.
+     *
+     * @return a Principal whose name is the issuer distinguished name.
+     */
+    public abstract Principal getIssuerDN();
+
+    /**
+     * Returns the issuer (issuer distinguished name) value from the
+     * CRL as an {@code X500Principal}.
+     * <p>
+     * It is recommended that subclasses override this method.
+     *
+     * @return an {@code X500Principal} representing the issuer
+     *          distinguished name
+     * @since 1.4
+     */
+    public X500Principal getIssuerX500Principal() {
+        if (issuerPrincipal == null) {
+            issuerPrincipal = X509CRLImpl.getIssuerX500Principal(this);
+        }
+        return issuerPrincipal;
+    }
+
+    /**
+     * Gets the {@code thisUpdate} date from the CRL.
+     * The ASN.1 definition for this is:
+     * <pre>
+     * thisUpdate   ChoiceOfTime
+     * ChoiceOfTime ::= CHOICE {
+     *     utcTime        UTCTime,
+     *     generalTime    GeneralizedTime }
+     * </pre>
+     *
+     * @return the {@code thisUpdate} date from the CRL.
+     */
+    public abstract Date getThisUpdate();
+
+    /**
+     * Gets the {@code nextUpdate} date from the CRL.
+     *
+     * @return the {@code nextUpdate} date from the CRL, or null if
+     * not present.
+     */
+    public abstract Date getNextUpdate();
+
+    /**
+     * Gets the CRL entry, if any, with the given certificate serialNumber.
+     *
+     * @param serialNumber the serial number of the certificate for which a CRL entry
+     * is to be looked up
+     * @return the entry with the given serial number, or null if no such entry
+     * exists in this CRL.
+     * @see X509CRLEntry
+     */
+    public abstract X509CRLEntry
+        getRevokedCertificate(BigInteger serialNumber);
+
+    /**
+     * Get the CRL entry, if any, for the given certificate.
+     *
+     * <p>This method can be used to lookup CRL entries in indirect CRLs,
+     * that means CRLs that contain entries from issuers other than the CRL
+     * issuer. The default implementation will only return entries for
+     * certificates issued by the CRL issuer. Subclasses that wish to
+     * support indirect CRLs should override this method.
+     *
+     * @param certificate the certificate for which a CRL entry is to be looked
+     *   up
+     * @return the entry for the given certificate, or null if no such entry
+     *   exists in this CRL.
+     * @exception NullPointerException if certificate is null
+     *
+     * @since 1.5
+     */
+    public X509CRLEntry getRevokedCertificate(X509Certificate certificate) {
+        X500Principal certIssuer = certificate.getIssuerX500Principal();
+        X500Principal crlIssuer = getIssuerX500Principal();
+        if (certIssuer.equals(crlIssuer) == false) {
+            return null;
+        }
+        return getRevokedCertificate(certificate.getSerialNumber());
+    }
+
+    /**
+     * Gets all the entries from this CRL.
+     * This returns a Set of X509CRLEntry objects.
+     *
+     * @return all the entries or null if there are none present.
+     * @see X509CRLEntry
+     */
+    public abstract Set<? extends X509CRLEntry> getRevokedCertificates();
+
+    /**
+     * Gets the DER-encoded CRL information, the
+     * {@code tbsCertList} from this CRL.
+     * This can be used to verify the signature independently.
+     *
+     * @return the DER-encoded CRL information.
+     * @exception CRLException if an encoding error occurs.
+     */
+    public abstract byte[] getTBSCertList() throws CRLException;
+
+    /**
+     * Gets the {@code signature} value (the raw signature bits) from
+     * the CRL.
+     * The ASN.1 definition for this is:
+     * <pre>
+     * signature     BIT STRING
+     * </pre>
+     *
+     * @return the signature.
+     */
+    public abstract byte[] getSignature();
+
+    /**
+     * Gets the signature algorithm name for the CRL
+     * signature algorithm. An example is the string "SHA256withRSA".
+     * The ASN.1 definition for this is:
+     * <pre>
+     * signatureAlgorithm   AlgorithmIdentifier
+     *
+     * AlgorithmIdentifier  ::=  SEQUENCE  {
+     *     algorithm               OBJECT IDENTIFIER,
+     *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     *                             -- contains a value of the type
+     *                             -- registered for use with the
+     *                             -- algorithm object identifier value
+     * </pre>
+     *
+     * <p>The algorithm name is determined from the {@code algorithm}
+     * OID string.
+     *
+     * @return the signature algorithm name.
+     */
+    public abstract String getSigAlgName();
+
+    /**
+     * Gets the signature algorithm OID string from the CRL.
+     * An OID is represented by a set of nonnegative whole numbers separated
+     * by periods.
+     * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
+     * with DSA signature algorithm defined in
+     * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
+     * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
+     * and CRL Profile</a>.
+     *
+     * <p>See {@link #getSigAlgName() getSigAlgName} for
+     * relevant ASN.1 definitions.
+     *
+     * @return the signature algorithm OID string.
+     */
+    public abstract String getSigAlgOID();
+
+    /**
+     * Gets the DER-encoded signature algorithm parameters from this
+     * CRL's signature algorithm. In most cases, the signature
+     * algorithm parameters are null; the parameters are usually
+     * supplied with the public key.
+     * If access to individual parameter values is needed then use
+     * {@link java.security.AlgorithmParameters AlgorithmParameters}
+     * and instantiate with the name returned by
+     * {@link #getSigAlgName() getSigAlgName}.
+     *
+     * <p>See {@link #getSigAlgName() getSigAlgName} for
+     * relevant ASN.1 definitions.
+     *
+     * @return the DER-encoded signature algorithm parameters, or
+     *         null if no parameters are present.
+     */
+    public abstract byte[] getSigAlgParams();
+}
diff --git a/java/security/cert/X509CRLEntry.java b/java/security/cert/X509CRLEntry.java
new file mode 100644
index 0000000..268fa81
--- /dev/null
+++ b/java/security/cert/X509CRLEntry.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.math.BigInteger;
+import java.util.Date;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.x509.X509CRLEntryImpl;
+
+/**
+ * <p>Abstract class for a revoked certificate in a CRL (Certificate
+ * Revocation List).
+ *
+ * The ASN.1 definition for <em>revokedCertificates</em> is:
+ * <pre>
+ * revokedCertificates    SEQUENCE OF SEQUENCE  {
+ *     userCertificate    CertificateSerialNumber,
+ *     revocationDate     ChoiceOfTime,
+ *     crlEntryExtensions Extensions OPTIONAL
+ *                        -- if present, must be v2
+ * }  OPTIONAL
+ *
+ * CertificateSerialNumber  ::=  INTEGER
+ *
+ * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension  ::=  SEQUENCE  {
+ *     extnId        OBJECT IDENTIFIER,
+ *     critical      BOOLEAN DEFAULT FALSE,
+ *     extnValue     OCTET STRING
+ *                   -- contains a DER encoding of a value
+ *                   -- of the type registered for use with
+ *                   -- the extnId object identifier value
+ * }
+ * </pre>
+ *
+ * @see X509CRL
+ * @see X509Extension
+ *
+ * @author Hemma Prafullchandra
+ */
+
+public abstract class X509CRLEntry implements X509Extension {
+
+    /**
+     * Compares this CRL entry for equality with the given
+     * object. If the {@code other} object is an
+     * {@code instanceof} {@code X509CRLEntry}, then
+     * its encoded form (the inner SEQUENCE) is retrieved and compared
+     * with the encoded form of this CRL entry.
+     *
+     * @param other the object to test for equality with this CRL entry.
+     * @return true iff the encoded forms of the two CRL entries
+     * match, false otherwise.
+     */
+    public boolean equals(Object other) {
+        if (this == other)
+            return true;
+        if (!(other instanceof X509CRLEntry))
+            return false;
+        try {
+            byte[] thisCRLEntry = this.getEncoded();
+            byte[] otherCRLEntry = ((X509CRLEntry)other).getEncoded();
+
+            if (thisCRLEntry.length != otherCRLEntry.length)
+                return false;
+            for (int i = 0; i < thisCRLEntry.length; i++)
+                 if (thisCRLEntry[i] != otherCRLEntry[i])
+                     return false;
+        } catch (CRLException ce) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns a hashcode value for this CRL entry from its
+     * encoded form.
+     *
+     * @return the hashcode value.
+     */
+    public int hashCode() {
+        int     retval = 0;
+        try {
+            byte[] entryData = this.getEncoded();
+            for (int i = 1; i < entryData.length; i++)
+                 retval += entryData[i] * i;
+
+        } catch (CRLException ce) {
+            return(retval);
+        }
+        return(retval);
+    }
+
+    /**
+     * Returns the ASN.1 DER-encoded form of this CRL Entry,
+     * that is the inner SEQUENCE.
+     *
+     * @return the encoded form of this certificate
+     * @exception CRLException if an encoding error occurs.
+     */
+    public abstract byte[] getEncoded() throws CRLException;
+
+    /**
+     * Gets the serial number from this X509CRLEntry,
+     * the <em>userCertificate</em>.
+     *
+     * @return the serial number.
+     */
+    public abstract BigInteger getSerialNumber();
+
+    /**
+     * Get the issuer of the X509Certificate described by this entry. If
+     * the certificate issuer is also the CRL issuer, this method returns
+     * null.
+     *
+     * <p>This method is used with indirect CRLs. The default implementation
+     * always returns null. Subclasses that wish to support indirect CRLs
+     * should override it.
+     *
+     * @return the issuer of the X509Certificate described by this entry
+     * or null if it is issued by the CRL issuer.
+     *
+     * @since 1.5
+     */
+    public X500Principal getCertificateIssuer() {
+        return null;
+    }
+
+    /**
+     * Gets the revocation date from this X509CRLEntry,
+     * the <em>revocationDate</em>.
+     *
+     * @return the revocation date.
+     */
+    public abstract Date getRevocationDate();
+
+    /**
+     * Returns true if this CRL entry has extensions.
+     *
+     * @return true if this entry has extensions, false otherwise.
+     */
+    public abstract boolean hasExtensions();
+
+    /**
+     * Returns a string representation of this CRL entry.
+     *
+     * @return a string representation of this CRL entry.
+     */
+    public abstract String toString();
+
+    /**
+     * Returns the reason the certificate has been revoked, as specified
+     * in the Reason Code extension of this CRL entry.
+     *
+     * @return the reason the certificate has been revoked, or
+     *    {@code null} if this CRL entry does not have
+     *    a Reason Code extension
+     * @since 1.7
+     */
+    public CRLReason getRevocationReason() {
+        if (!hasExtensions()) {
+            return null;
+        }
+        return X509CRLEntryImpl.getRevocationReason(this);
+    }
+}
diff --git a/java/security/cert/X509CRLSelector.java b/java/security/cert/X509CRLSelector.java
new file mode 100644
index 0000000..face5ff
--- /dev/null
+++ b/java/security/cert/X509CRLSelector.java
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.*;
+
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.util.Debug;
+import sun.security.util.DerInputStream;
+import sun.security.x509.CRLNumberExtension;
+import sun.security.x509.X500Name;
+
+/**
+ * A {@code CRLSelector} that selects {@code X509CRLs} that
+ * match all specified criteria. This class is particularly useful when
+ * selecting CRLs from a {@code CertStore} to check revocation status
+ * of a particular certificate.
+ * <p>
+ * When first constructed, an {@code X509CRLSelector} has no criteria
+ * enabled and each of the {@code get} methods return a default
+ * value ({@code null}). Therefore, the {@link #match match} method
+ * would return {@code true} for any {@code X509CRL}. Typically,
+ * several criteria are enabled (by calling {@link #setIssuers setIssuers}
+ * or {@link #setDateAndTime setDateAndTime}, for instance) and then the
+ * {@code X509CRLSelector} is passed to
+ * {@link CertStore#getCRLs CertStore.getCRLs} or some similar
+ * method.
+ * <p>
+ * Please refer to <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
+ * Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a>
+ * for definitions of the X.509 CRL fields and extensions mentioned below.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CRLSelector
+ * @see X509CRL
+ *
+ * @since       1.4
+ * @author      Steve Hanna
+ */
+public class X509CRLSelector implements CRLSelector {
+
+    static {
+        CertPathHelperImpl.initialize();
+    }
+
+    private static final Debug debug = Debug.getInstance("certpath");
+    private HashSet<Object> issuerNames;
+    private HashSet<X500Principal> issuerX500Principals;
+    private BigInteger minCRL;
+    private BigInteger maxCRL;
+    private Date dateAndTime;
+    private X509Certificate certChecking;
+    private long skew = 0;
+
+    /**
+     * Creates an {@code X509CRLSelector}. Initially, no criteria are set
+     * so any {@code X509CRL} will match.
+     */
+    public X509CRLSelector() {}
+
+    /**
+     * Sets the issuerNames criterion. The issuer distinguished name in the
+     * {@code X509CRL} must match at least one of the specified
+     * distinguished names. If {@code null}, any issuer distinguished name
+     * will do.
+     * <p>
+     * This method allows the caller to specify, with a single method call,
+     * the complete set of issuer names which {@code X509CRLs} may contain.
+     * The specified value replaces the previous value for the issuerNames
+     * criterion.
+     * <p>
+     * The {@code names} parameter (if not {@code null}) is a
+     * {@code Collection} of {@code X500Principal}s.
+     * <p>
+     * Note that the {@code names} parameter can contain duplicate
+     * distinguished names, but they may be removed from the
+     * {@code Collection} of names returned by the
+     * {@link #getIssuers getIssuers} method.
+     * <p>
+     * Note that a copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @param issuers a {@code Collection} of X500Principals
+     *   (or {@code null})
+     * @see #getIssuers
+     * @since 1.5
+     */
+    public void setIssuers(Collection<X500Principal> issuers) {
+        if ((issuers == null) || issuers.isEmpty()) {
+            issuerNames = null;
+            issuerX500Principals = null;
+        } else {
+            // clone
+            issuerX500Principals = new HashSet<X500Principal>(issuers);
+            issuerNames = new HashSet<Object>();
+            for (X500Principal p : issuerX500Principals) {
+                issuerNames.add(p.getEncoded());
+            }
+        }
+    }
+
+    /**
+     * <strong>Note:</strong> use {@linkplain #setIssuers(Collection)} instead
+     * or only specify the byte array form of distinguished names when using
+     * this method. See {@link #addIssuerName(String)} for more information.
+     * <p>
+     * Sets the issuerNames criterion. The issuer distinguished name in the
+     * {@code X509CRL} must match at least one of the specified
+     * distinguished names. If {@code null}, any issuer distinguished name
+     * will do.
+     * <p>
+     * This method allows the caller to specify, with a single method call,
+     * the complete set of issuer names which {@code X509CRLs} may contain.
+     * The specified value replaces the previous value for the issuerNames
+     * criterion.
+     * <p>
+     * The {@code names} parameter (if not {@code null}) is a
+     * {@code Collection} of names. Each name is a {@code String}
+     * or a byte array representing a distinguished name (in
+     * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> or
+     * ASN.1 DER encoded form, respectively). If {@code null} is supplied
+     * as the value for this argument, no issuerNames check will be performed.
+     * <p>
+     * Note that the {@code names} parameter can contain duplicate
+     * distinguished names, but they may be removed from the
+     * {@code Collection} of names returned by the
+     * {@link #getIssuerNames getIssuerNames} method.
+     * <p>
+     * If a name is specified as a byte array, it should contain a single DER
+     * encoded distinguished name, as defined in X.501. The ASN.1 notation for
+     * this structure is as follows.
+     * <pre>{@code
+     * Name ::= CHOICE {
+     *   RDNSequence }
+     *
+     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+     *
+     * RelativeDistinguishedName ::=
+     *   SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+     *
+     * AttributeTypeAndValue ::= SEQUENCE {
+     *   type     AttributeType,
+     *   value    AttributeValue }
+     *
+     * AttributeType ::= OBJECT IDENTIFIER
+     *
+     * AttributeValue ::= ANY DEFINED BY AttributeType
+     * ....
+     * DirectoryString ::= CHOICE {
+     *       teletexString           TeletexString (SIZE (1..MAX)),
+     *       printableString         PrintableString (SIZE (1..MAX)),
+     *       universalString         UniversalString (SIZE (1..MAX)),
+     *       utf8String              UTF8String (SIZE (1.. MAX)),
+     *       bmpString               BMPString (SIZE (1..MAX)) }
+     * }</pre>
+     * <p>
+     * Note that a deep copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @param names a {@code Collection} of names (or {@code null})
+     * @throws IOException if a parsing error occurs
+     * @see #getIssuerNames
+     */
+    public void setIssuerNames(Collection<?> names) throws IOException {
+        if (names == null || names.size() == 0) {
+            issuerNames = null;
+            issuerX500Principals = null;
+        } else {
+            HashSet<Object> tempNames = cloneAndCheckIssuerNames(names);
+            // Ensure that we either set both of these or neither
+            issuerX500Principals = parseIssuerNames(tempNames);
+            issuerNames = tempNames;
+        }
+    }
+
+    /**
+     * Adds a name to the issuerNames criterion. The issuer distinguished
+     * name in the {@code X509CRL} must match at least one of the specified
+     * distinguished names.
+     * <p>
+     * This method allows the caller to add a name to the set of issuer names
+     * which {@code X509CRLs} may contain. The specified name is added to
+     * any previous value for the issuerNames criterion.
+     * If the specified name is a duplicate, it may be ignored.
+     *
+     * @param issuer the issuer as X500Principal
+     * @since 1.5
+     */
+    public void addIssuer(X500Principal issuer) {
+        addIssuerNameInternal(issuer.getEncoded(), issuer);
+    }
+
+    /**
+     * <strong>Denigrated</strong>, use
+     * {@linkplain #addIssuer(X500Principal)} or
+     * {@linkplain #addIssuerName(byte[])} instead. This method should not be
+     * relied on as it can fail to match some CRLs because of a loss of
+     * encoding information in the RFC 2253 String form of some distinguished
+     * names.
+     * <p>
+     * Adds a name to the issuerNames criterion. The issuer distinguished
+     * name in the {@code X509CRL} must match at least one of the specified
+     * distinguished names.
+     * <p>
+     * This method allows the caller to add a name to the set of issuer names
+     * which {@code X509CRLs} may contain. The specified name is added to
+     * any previous value for the issuerNames criterion.
+     * If the specified name is a duplicate, it may be ignored.
+     *
+     * @param name the name in RFC 2253 form
+     * @throws IOException if a parsing error occurs
+     */
+    public void addIssuerName(String name) throws IOException {
+        addIssuerNameInternal(name, new X500Name(name).asX500Principal());
+    }
+
+    /**
+     * Adds a name to the issuerNames criterion. The issuer distinguished
+     * name in the {@code X509CRL} must match at least one of the specified
+     * distinguished names.
+     * <p>
+     * This method allows the caller to add a name to the set of issuer names
+     * which {@code X509CRLs} may contain. The specified name is added to
+     * any previous value for the issuerNames criterion. If the specified name
+     * is a duplicate, it may be ignored.
+     * If a name is specified as a byte array, it should contain a single DER
+     * encoded distinguished name, as defined in X.501. The ASN.1 notation for
+     * this structure is as follows.
+     * <p>
+     * The name is provided as a byte array. This byte array should contain
+     * a single DER encoded distinguished name, as defined in X.501. The ASN.1
+     * notation for this structure appears in the documentation for
+     * {@link #setIssuerNames setIssuerNames(Collection names)}.
+     * <p>
+     * Note that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param name a byte array containing the name in ASN.1 DER encoded form
+     * @throws IOException if a parsing error occurs
+     */
+    public void addIssuerName(byte[] name) throws IOException {
+        // clone because byte arrays are modifiable
+        addIssuerNameInternal(name.clone(), new X500Name(name).asX500Principal());
+    }
+
+    /**
+     * A private method that adds a name (String or byte array) to the
+     * issuerNames criterion. The issuer distinguished
+     * name in the {@code X509CRL} must match at least one of the specified
+     * distinguished names.
+     *
+     * @param name the name in string or byte array form
+     * @param principal the name in X500Principal form
+     * @throws IOException if a parsing error occurs
+     */
+    private void addIssuerNameInternal(Object name, X500Principal principal) {
+        if (issuerNames == null) {
+            issuerNames = new HashSet<Object>();
+        }
+        if (issuerX500Principals == null) {
+            issuerX500Principals = new HashSet<X500Principal>();
+        }
+        issuerNames.add(name);
+        issuerX500Principals.add(principal);
+    }
+
+    /**
+     * Clone and check an argument of the form passed to
+     * setIssuerNames. Throw an IOException if the argument is malformed.
+     *
+     * @param names a {@code Collection} of names. Each entry is a
+     *              String or a byte array (the name, in string or ASN.1
+     *              DER encoded form, respectively). {@code null} is
+     *              not an acceptable value.
+     * @return a deep copy of the specified {@code Collection}
+     * @throws IOException if a parsing error occurs
+     */
+    private static HashSet<Object> cloneAndCheckIssuerNames(Collection<?> names)
+        throws IOException
+    {
+        HashSet<Object> namesCopy = new HashSet<Object>();
+        Iterator<?> i = names.iterator();
+        while (i.hasNext()) {
+            Object nameObject = i.next();
+            if (!(nameObject instanceof byte []) &&
+                !(nameObject instanceof String))
+                throw new IOException("name not byte array or String");
+            if (nameObject instanceof byte [])
+                namesCopy.add(((byte []) nameObject).clone());
+            else
+                namesCopy.add(nameObject);
+        }
+        return(namesCopy);
+    }
+
+    /**
+     * Clone an argument of the form passed to setIssuerNames.
+     * Throw a RuntimeException if the argument is malformed.
+     * <p>
+     * This method wraps cloneAndCheckIssuerNames, changing any IOException
+     * into a RuntimeException. This method should be used when the object being
+     * cloned has already been checked, so there should never be any exceptions.
+     *
+     * @param names a {@code Collection} of names. Each entry is a
+     *              String or a byte array (the name, in string or ASN.1
+     *              DER encoded form, respectively). {@code null} is
+     *              not an acceptable value.
+     * @return a deep copy of the specified {@code Collection}
+     * @throws RuntimeException if a parsing error occurs
+     */
+    private static HashSet<Object> cloneIssuerNames(Collection<Object> names) {
+        try {
+            return cloneAndCheckIssuerNames(names);
+        } catch (IOException ioe) {
+            throw new RuntimeException(ioe);
+        }
+    }
+
+    /**
+     * Parse an argument of the form passed to setIssuerNames,
+     * returning a Collection of issuerX500Principals.
+     * Throw an IOException if the argument is malformed.
+     *
+     * @param names a {@code Collection} of names. Each entry is a
+     *              String or a byte array (the name, in string or ASN.1
+     *              DER encoded form, respectively). <Code>Null</Code> is
+     *              not an acceptable value.
+     * @return a HashSet of issuerX500Principals
+     * @throws IOException if a parsing error occurs
+     */
+    private static HashSet<X500Principal> parseIssuerNames(Collection<Object> names)
+    throws IOException {
+        HashSet<X500Principal> x500Principals = new HashSet<X500Principal>();
+        for (Iterator<Object> t = names.iterator(); t.hasNext(); ) {
+            Object nameObject = t.next();
+            if (nameObject instanceof String) {
+                x500Principals.add(new X500Name((String)nameObject).asX500Principal());
+            } else {
+                try {
+                    x500Principals.add(new X500Principal((byte[])nameObject));
+                } catch (IllegalArgumentException e) {
+                    throw (IOException)new IOException("Invalid name").initCause(e);
+                }
+            }
+        }
+        return x500Principals;
+    }
+
+    /**
+     * Sets the minCRLNumber criterion. The {@code X509CRL} must have a
+     * CRL number extension whose value is greater than or equal to the
+     * specified value. If {@code null}, no minCRLNumber check will be
+     * done.
+     *
+     * @param minCRL the minimum CRL number accepted (or {@code null})
+     */
+    public void setMinCRLNumber(BigInteger minCRL) {
+        this.minCRL = minCRL;
+    }
+
+    /**
+     * Sets the maxCRLNumber criterion. The {@code X509CRL} must have a
+     * CRL number extension whose value is less than or equal to the
+     * specified value. If {@code null}, no maxCRLNumber check will be
+     * done.
+     *
+     * @param maxCRL the maximum CRL number accepted (or {@code null})
+     */
+    public void setMaxCRLNumber(BigInteger maxCRL) {
+        this.maxCRL = maxCRL;
+    }
+
+    /**
+     * Sets the dateAndTime criterion. The specified date must be
+     * equal to or later than the value of the thisUpdate component
+     * of the {@code X509CRL} and earlier than the value of the
+     * nextUpdate component. There is no match if the {@code X509CRL}
+     * does not contain a nextUpdate component.
+     * If {@code null}, no dateAndTime check will be done.
+     * <p>
+     * Note that the {@code Date} supplied here is cloned to protect
+     * against subsequent modifications.
+     *
+     * @param dateAndTime the {@code Date} to match against
+     *                    (or {@code null})
+     * @see #getDateAndTime
+     */
+    public void setDateAndTime(Date dateAndTime) {
+        if (dateAndTime == null)
+            this.dateAndTime = null;
+        else
+            this.dateAndTime = new Date(dateAndTime.getTime());
+        this.skew = 0;
+    }
+
+    /**
+     * Sets the dateAndTime criterion and allows for the specified clock skew
+     * (in milliseconds) when checking against the validity period of the CRL.
+     */
+    void setDateAndTime(Date dateAndTime, long skew) {
+        this.dateAndTime =
+            (dateAndTime == null ? null : new Date(dateAndTime.getTime()));
+        this.skew = skew;
+    }
+
+    /**
+     * Sets the certificate being checked. This is not a criterion. Rather,
+     * it is optional information that may help a {@code CertStore}
+     * find CRLs that would be relevant when checking revocation for the
+     * specified certificate. If {@code null} is specified, then no
+     * such optional information is provided.
+     *
+     * @param cert the {@code X509Certificate} being checked
+     *             (or {@code null})
+     * @see #getCertificateChecking
+     */
+    public void setCertificateChecking(X509Certificate cert) {
+        certChecking = cert;
+    }
+
+    /**
+     * Returns the issuerNames criterion. The issuer distinguished
+     * name in the {@code X509CRL} must match at least one of the specified
+     * distinguished names. If the value returned is {@code null}, any
+     * issuer distinguished name will do.
+     * <p>
+     * If the value returned is not {@code null}, it is a
+     * unmodifiable {@code Collection} of {@code X500Principal}s.
+     *
+     * @return an unmodifiable {@code Collection} of names
+     *   (or {@code null})
+     * @see #setIssuers
+     * @since 1.5
+     */
+    public Collection<X500Principal> getIssuers() {
+        if (issuerX500Principals == null) {
+            return null;
+        }
+        return Collections.unmodifiableCollection(issuerX500Principals);
+    }
+
+    /**
+     * Returns a copy of the issuerNames criterion. The issuer distinguished
+     * name in the {@code X509CRL} must match at least one of the specified
+     * distinguished names. If the value returned is {@code null}, any
+     * issuer distinguished name will do.
+     * <p>
+     * If the value returned is not {@code null}, it is a
+     * {@code Collection} of names. Each name is a {@code String}
+     * or a byte array representing a distinguished name (in RFC 2253 or
+     * ASN.1 DER encoded form, respectively).  Note that the
+     * {@code Collection} returned may contain duplicate names.
+     * <p>
+     * If a name is specified as a byte array, it should contain a single DER
+     * encoded distinguished name, as defined in X.501. The ASN.1 notation for
+     * this structure is given in the documentation for
+     * {@link #setIssuerNames setIssuerNames(Collection names)}.
+     * <p>
+     * Note that a deep copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @return a {@code Collection} of names (or {@code null})
+     * @see #setIssuerNames
+     */
+    public Collection<Object> getIssuerNames() {
+        if (issuerNames == null) {
+            return null;
+        }
+        return cloneIssuerNames(issuerNames);
+    }
+
+    /**
+     * Returns the minCRLNumber criterion. The {@code X509CRL} must have a
+     * CRL number extension whose value is greater than or equal to the
+     * specified value. If {@code null}, no minCRLNumber check will be done.
+     *
+     * @return the minimum CRL number accepted (or {@code null})
+     */
+    public BigInteger getMinCRL() {
+        return minCRL;
+    }
+
+    /**
+     * Returns the maxCRLNumber criterion. The {@code X509CRL} must have a
+     * CRL number extension whose value is less than or equal to the
+     * specified value. If {@code null}, no maxCRLNumber check will be
+     * done.
+     *
+     * @return the maximum CRL number accepted (or {@code null})
+     */
+    public BigInteger getMaxCRL() {
+        return maxCRL;
+    }
+
+    /**
+     * Returns the dateAndTime criterion. The specified date must be
+     * equal to or later than the value of the thisUpdate component
+     * of the {@code X509CRL} and earlier than the value of the
+     * nextUpdate component. There is no match if the
+     * {@code X509CRL} does not contain a nextUpdate component.
+     * If {@code null}, no dateAndTime check will be done.
+     * <p>
+     * Note that the {@code Date} returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return the {@code Date} to match against (or {@code null})
+     * @see #setDateAndTime
+     */
+    public Date getDateAndTime() {
+        if (dateAndTime == null)
+            return null;
+        return (Date) dateAndTime.clone();
+    }
+
+    /**
+     * Returns the certificate being checked. This is not a criterion. Rather,
+     * it is optional information that may help a {@code CertStore}
+     * find CRLs that would be relevant when checking revocation for the
+     * specified certificate. If the value returned is {@code null}, then
+     * no such optional information is provided.
+     *
+     * @return the certificate being checked (or {@code null})
+     * @see #setCertificateChecking
+     */
+    public X509Certificate getCertificateChecking() {
+        return certChecking;
+    }
+
+    /**
+     * Returns a printable representation of the {@code X509CRLSelector}.
+     *
+     * @return a {@code String} describing the contents of the
+     *         {@code X509CRLSelector}.
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("X509CRLSelector: [\n");
+        if (issuerNames != null) {
+            sb.append("  IssuerNames:\n");
+            Iterator<Object> i = issuerNames.iterator();
+            while (i.hasNext())
+                sb.append("    " + i.next() + "\n");
+        }
+        if (minCRL != null)
+            sb.append("  minCRLNumber: " + minCRL + "\n");
+        if (maxCRL != null)
+            sb.append("  maxCRLNumber: " + maxCRL + "\n");
+        if (dateAndTime != null)
+            sb.append("  dateAndTime: " + dateAndTime + "\n");
+        if (certChecking != null)
+            sb.append("  Certificate being checked: " + certChecking + "\n");
+        sb.append("]");
+        return sb.toString();
+    }
+
+    /**
+     * Decides whether a {@code CRL} should be selected.
+     *
+     * @param crl the {@code CRL} to be checked
+     * @return {@code true} if the {@code CRL} should be selected,
+     *         {@code false} otherwise
+     */
+    public boolean match(CRL crl) {
+        if (!(crl instanceof X509CRL)) {
+            return false;
+        }
+        X509CRL xcrl = (X509CRL)crl;
+
+        /* match on issuer name */
+        if (issuerNames != null) {
+            X500Principal issuer = xcrl.getIssuerX500Principal();
+            Iterator<X500Principal> i = issuerX500Principals.iterator();
+            boolean found = false;
+            while (!found && i.hasNext()) {
+                if (i.next().equals(issuer)) {
+                    found = true;
+                }
+            }
+            if (!found) {
+                if (debug != null) {
+                    debug.println("X509CRLSelector.match: issuer DNs "
+                        + "don't match");
+                }
+                return false;
+            }
+        }
+
+        if ((minCRL != null) || (maxCRL != null)) {
+            /* Get CRL number extension from CRL */
+            byte[] crlNumExtVal = xcrl.getExtensionValue("2.5.29.20");
+            if (crlNumExtVal == null) {
+                if (debug != null) {
+                    debug.println("X509CRLSelector.match: no CRLNumber");
+                }
+            }
+            BigInteger crlNum;
+            try {
+                DerInputStream in = new DerInputStream(crlNumExtVal);
+                byte[] encoded = in.getOctetString();
+                CRLNumberExtension crlNumExt =
+                    new CRLNumberExtension(Boolean.FALSE, encoded);
+                crlNum = crlNumExt.get(CRLNumberExtension.NUMBER);
+            } catch (IOException ex) {
+                if (debug != null) {
+                    debug.println("X509CRLSelector.match: exception in "
+                        + "decoding CRL number");
+                }
+                return false;
+            }
+
+            /* match on minCRLNumber */
+            if (minCRL != null) {
+                if (crlNum.compareTo(minCRL) < 0) {
+                    if (debug != null) {
+                        debug.println("X509CRLSelector.match: CRLNumber too small");
+                    }
+                    return false;
+                }
+            }
+
+            /* match on maxCRLNumber */
+            if (maxCRL != null) {
+                if (crlNum.compareTo(maxCRL) > 0) {
+                    if (debug != null) {
+                        debug.println("X509CRLSelector.match: CRLNumber too large");
+                    }
+                    return false;
+                }
+            }
+        }
+
+
+        /* match on dateAndTime */
+        if (dateAndTime != null) {
+            Date crlThisUpdate = xcrl.getThisUpdate();
+            Date nextUpdate = xcrl.getNextUpdate();
+            if (nextUpdate == null) {
+                if (debug != null) {
+                    debug.println("X509CRLSelector.match: nextUpdate null");
+                }
+                return false;
+            }
+            Date nowPlusSkew = dateAndTime;
+            Date nowMinusSkew = dateAndTime;
+            if (skew > 0) {
+                nowPlusSkew = new Date(dateAndTime.getTime() + skew);
+                nowMinusSkew = new Date(dateAndTime.getTime() - skew);
+            }
+
+            // Check that the test date is within the validity interval:
+            //   [ thisUpdate - MAX_CLOCK_SKEW,
+            //     nextUpdate + MAX_CLOCK_SKEW ]
+            if (nowMinusSkew.after(nextUpdate)
+                || nowPlusSkew.before(crlThisUpdate)) {
+                if (debug != null) {
+                    debug.println("X509CRLSelector.match: update out-of-range");
+                }
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns a copy of this object.
+     *
+     * @return the copy
+     */
+    public Object clone() {
+        try {
+            X509CRLSelector copy = (X509CRLSelector)super.clone();
+            if (issuerNames != null) {
+                copy.issuerNames =
+                        new HashSet<Object>(issuerNames);
+                copy.issuerX500Principals =
+                        new HashSet<X500Principal>(issuerX500Principals);
+            }
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+}
diff --git a/java/security/cert/X509CertSelector.java b/java/security/cert/X509CertSelector.java
new file mode 100644
index 0000000..4a1ff7e
--- /dev/null
+++ b/java/security/cert/X509CertSelector.java
@@ -0,0 +1,2623 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.util.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.misc.HexDumpEncoder;
+import sun.security.util.Debug;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerValue;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.*;
+
+/**
+ * A {@code CertSelector} that selects {@code X509Certificates} that
+ * match all specified criteria. This class is particularly useful when
+ * selecting certificates from a {@code CertStore} to build a
+ * PKIX-compliant certification path.
+ * <p>
+ * When first constructed, an {@code X509CertSelector} has no criteria
+ * enabled and each of the {@code get} methods return a default value
+ * ({@code null}, or {@code -1} for the {@link #getBasicConstraints
+ * getBasicConstraints} method). Therefore, the {@link #match match}
+ * method would return {@code true} for any {@code X509Certificate}.
+ * Typically, several criteria are enabled (by calling
+ * {@link #setIssuer setIssuer} or
+ * {@link #setKeyUsage setKeyUsage}, for instance) and then the
+ * {@code X509CertSelector} is passed to
+ * {@link CertStore#getCertificates CertStore.getCertificates} or some similar
+ * method.
+ * <p>
+ * Several criteria can be enabled (by calling {@link #setIssuer setIssuer}
+ * and {@link #setSerialNumber setSerialNumber},
+ * for example) such that the {@code match} method
+ * usually uniquely matches a single {@code X509Certificate}. We say
+ * usually, since it is possible for two issuing CAs to have the same
+ * distinguished name and each issue a certificate with the same serial
+ * number. Other unique combinations include the issuer, subject,
+ * subjectKeyIdentifier and/or the subjectPublicKey criteria.
+ * <p>
+ * Please refer to <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
+ * Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a> for
+ * definitions of the X.509 certificate extensions mentioned below.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single
+ * object concurrently should synchronize amongst themselves and
+ * provide the necessary locking. Multiple threads each manipulating
+ * separate objects need not synchronize.
+ *
+ * @see CertSelector
+ * @see X509Certificate
+ *
+ * @since       1.4
+ * @author      Steve Hanna
+ */
+public class X509CertSelector implements CertSelector {
+
+    private static final Debug debug = Debug.getInstance("certpath");
+
+    private final static ObjectIdentifier ANY_EXTENDED_KEY_USAGE =
+        ObjectIdentifier.newInternal(new int[] {2, 5, 29, 37, 0});
+
+    static {
+        CertPathHelperImpl.initialize();
+    }
+
+    private BigInteger serialNumber;
+    private X500Principal issuer;
+    private X500Principal subject;
+    private byte[] subjectKeyID;
+    private byte[] authorityKeyID;
+    private Date certificateValid;
+    private Date privateKeyValid;
+    private ObjectIdentifier subjectPublicKeyAlgID;
+    private PublicKey subjectPublicKey;
+    private byte[] subjectPublicKeyBytes;
+    private boolean[] keyUsage;
+    private Set<String> keyPurposeSet;
+    private Set<ObjectIdentifier> keyPurposeOIDSet;
+    private Set<List<?>> subjectAlternativeNames;
+    private Set<GeneralNameInterface> subjectAlternativeGeneralNames;
+    private CertificatePolicySet policy;
+    private Set<String> policySet;
+    private Set<List<?>> pathToNames;
+    private Set<GeneralNameInterface> pathToGeneralNames;
+    private NameConstraintsExtension nc;
+    private byte[] ncBytes;
+    private int basicConstraints = -1;
+    private X509Certificate x509Cert;
+    private boolean matchAllSubjectAltNames = true;
+
+    private static final Boolean FALSE = Boolean.FALSE;
+
+    private static final int PRIVATE_KEY_USAGE_ID = 0;
+    private static final int SUBJECT_ALT_NAME_ID = 1;
+    private static final int NAME_CONSTRAINTS_ID = 2;
+    private static final int CERT_POLICIES_ID = 3;
+    private static final int EXTENDED_KEY_USAGE_ID = 4;
+    private static final int NUM_OF_EXTENSIONS = 5;
+    private static final String[] EXTENSION_OIDS = new String[NUM_OF_EXTENSIONS];
+
+    static {
+        EXTENSION_OIDS[PRIVATE_KEY_USAGE_ID]  = "2.5.29.16";
+        EXTENSION_OIDS[SUBJECT_ALT_NAME_ID]   = "2.5.29.17";
+        EXTENSION_OIDS[NAME_CONSTRAINTS_ID]   = "2.5.29.30";
+        EXTENSION_OIDS[CERT_POLICIES_ID]      = "2.5.29.32";
+        EXTENSION_OIDS[EXTENDED_KEY_USAGE_ID] = "2.5.29.37";
+    };
+
+    /* Constants representing the GeneralName types */
+    static final int NAME_ANY = 0;
+    static final int NAME_RFC822 = 1;
+    static final int NAME_DNS = 2;
+    static final int NAME_X400 = 3;
+    static final int NAME_DIRECTORY = 4;
+    static final int NAME_EDI = 5;
+    static final int NAME_URI = 6;
+    static final int NAME_IP = 7;
+    static final int NAME_OID = 8;
+
+    /**
+     * Creates an {@code X509CertSelector}. Initially, no criteria are set
+     * so any {@code X509Certificate} will match.
+     */
+    public X509CertSelector() {
+        // empty
+    }
+
+    /**
+     * Sets the certificateEquals criterion. The specified
+     * {@code X509Certificate} must be equal to the
+     * {@code X509Certificate} passed to the {@code match} method.
+     * If {@code null}, then this check is not applied.
+     *
+     * <p>This method is particularly useful when it is necessary to
+     * match a single certificate. Although other criteria can be specified
+     * in conjunction with the certificateEquals criterion, it is usually not
+     * practical or necessary.
+     *
+     * @param cert the {@code X509Certificate} to match (or
+     * {@code null})
+     * @see #getCertificate
+     */
+    public void setCertificate(X509Certificate cert) {
+        x509Cert = cert;
+    }
+
+    /**
+     * Sets the serialNumber criterion. The specified serial number
+     * must match the certificate serial number in the
+     * {@code X509Certificate}. If {@code null}, any certificate
+     * serial number will do.
+     *
+     * @param serial the certificate serial number to match
+     *        (or {@code null})
+     * @see #getSerialNumber
+     */
+    public void setSerialNumber(BigInteger serial) {
+        serialNumber = serial;
+    }
+
+    /**
+     * Sets the issuer criterion. The specified distinguished name
+     * must match the issuer distinguished name in the
+     * {@code X509Certificate}. If {@code null}, any issuer
+     * distinguished name will do.
+     *
+     * @param issuer a distinguished name as X500Principal
+     *                 (or {@code null})
+     * @since 1.5
+     */
+    public void setIssuer(X500Principal issuer) {
+        this.issuer = issuer;
+    }
+
+    /**
+     * <strong>Denigrated</strong>, use {@linkplain #setIssuer(X500Principal)}
+     * or {@linkplain #setIssuer(byte[])} instead. This method should not be
+     * relied on as it can fail to match some certificates because of a loss of
+     * encoding information in the
+     * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> String form
+     * of some distinguished names.
+     * <p>
+     * Sets the issuer criterion. The specified distinguished name
+     * must match the issuer distinguished name in the
+     * {@code X509Certificate}. If {@code null}, any issuer
+     * distinguished name will do.
+     * <p>
+     * If {@code issuerDN} is not {@code null}, it should contain a
+     * distinguished name, in RFC 2253 format.
+     *
+     * @param issuerDN a distinguished name in RFC 2253 format
+     *                 (or {@code null})
+     * @throws IOException if a parsing error occurs (incorrect form for DN)
+     */
+    public void setIssuer(String issuerDN) throws IOException {
+        if (issuerDN == null) {
+            issuer = null;
+        } else {
+            issuer = new X500Name(issuerDN).asX500Principal();
+        }
+    }
+
+    /**
+     * Sets the issuer criterion. The specified distinguished name
+     * must match the issuer distinguished name in the
+     * {@code X509Certificate}. If {@code null} is specified,
+     * the issuer criterion is disabled and any issuer distinguished name will
+     * do.
+     * <p>
+     * If {@code issuerDN} is not {@code null}, it should contain a
+     * single DER encoded distinguished name, as defined in X.501. The ASN.1
+     * notation for this structure is as follows.
+     * <pre>{@code
+     * Name ::= CHOICE {
+     *   RDNSequence }
+     *
+     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+     *
+     * RelativeDistinguishedName ::=
+     *   SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+     *
+     * AttributeTypeAndValue ::= SEQUENCE {
+     *   type     AttributeType,
+     *   value    AttributeValue }
+     *
+     * AttributeType ::= OBJECT IDENTIFIER
+     *
+     * AttributeValue ::= ANY DEFINED BY AttributeType
+     * ....
+     * DirectoryString ::= CHOICE {
+     *       teletexString           TeletexString (SIZE (1..MAX)),
+     *       printableString         PrintableString (SIZE (1..MAX)),
+     *       universalString         UniversalString (SIZE (1..MAX)),
+     *       utf8String              UTF8String (SIZE (1.. MAX)),
+     *       bmpString               BMPString (SIZE (1..MAX)) }
+     * }</pre>
+     * <p>
+     * Note that the byte array specified here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param issuerDN a byte array containing the distinguished name
+     *                 in ASN.1 DER encoded form (or {@code null})
+     * @throws IOException if an encoding error occurs (incorrect form for DN)
+     */
+    public void setIssuer(byte[] issuerDN) throws IOException {
+        try {
+            issuer = (issuerDN == null ? null : new X500Principal(issuerDN));
+        } catch (IllegalArgumentException e) {
+            throw new IOException("Invalid name", e);
+        }
+    }
+
+    /**
+     * Sets the subject criterion. The specified distinguished name
+     * must match the subject distinguished name in the
+     * {@code X509Certificate}. If {@code null}, any subject
+     * distinguished name will do.
+     *
+     * @param subject a distinguished name as X500Principal
+     *                  (or {@code null})
+     * @since 1.5
+     */
+    public void setSubject(X500Principal subject) {
+        this.subject = subject;
+    }
+
+    /**
+     * <strong>Denigrated</strong>, use {@linkplain #setSubject(X500Principal)}
+     * or {@linkplain #setSubject(byte[])} instead. This method should not be
+     * relied on as it can fail to match some certificates because of a loss of
+     * encoding information in the RFC 2253 String form of some distinguished
+     * names.
+     * <p>
+     * Sets the subject criterion. The specified distinguished name
+     * must match the subject distinguished name in the
+     * {@code X509Certificate}. If {@code null}, any subject
+     * distinguished name will do.
+     * <p>
+     * If {@code subjectDN} is not {@code null}, it should contain a
+     * distinguished name, in RFC 2253 format.
+     *
+     * @param subjectDN a distinguished name in RFC 2253 format
+     *                  (or {@code null})
+     * @throws IOException if a parsing error occurs (incorrect form for DN)
+     */
+    public void setSubject(String subjectDN) throws IOException {
+        if (subjectDN == null) {
+            subject = null;
+        } else {
+            subject = new X500Name(subjectDN).asX500Principal();
+        }
+    }
+
+    /**
+     * Sets the subject criterion. The specified distinguished name
+     * must match the subject distinguished name in the
+     * {@code X509Certificate}. If {@code null}, any subject
+     * distinguished name will do.
+     * <p>
+     * If {@code subjectDN} is not {@code null}, it should contain a
+     * single DER encoded distinguished name, as defined in X.501. For the ASN.1
+     * notation for this structure, see
+     * {@link #setIssuer(byte [] issuerDN) setIssuer(byte [] issuerDN)}.
+     *
+     * @param subjectDN a byte array containing the distinguished name in
+     *                  ASN.1 DER format (or {@code null})
+     * @throws IOException if an encoding error occurs (incorrect form for DN)
+     */
+    public void setSubject(byte[] subjectDN) throws IOException {
+        try {
+            subject = (subjectDN == null ? null : new X500Principal(subjectDN));
+        } catch (IllegalArgumentException e) {
+            throw new IOException("Invalid name", e);
+        }
+    }
+
+    /**
+     * Sets the subjectKeyIdentifier criterion. The
+     * {@code X509Certificate} must contain a SubjectKeyIdentifier
+     * extension for which the contents of the extension
+     * matches the specified criterion value.
+     * If the criterion value is {@code null}, no
+     * subjectKeyIdentifier check will be done.
+     * <p>
+     * If {@code subjectKeyID} is not {@code null}, it
+     * should contain a single DER encoded value corresponding to the contents
+     * of the extension value (not including the object identifier,
+     * criticality setting, and encapsulating OCTET STRING)
+     * for a SubjectKeyIdentifier extension.
+     * The ASN.1 notation for this structure follows.
+     *
+     * <pre>{@code
+     * SubjectKeyIdentifier ::= KeyIdentifier
+     *
+     * KeyIdentifier ::= OCTET STRING
+     * }</pre>
+     * <p>
+     * Since the format of subject key identifiers is not mandated by
+     * any standard, subject key identifiers are not parsed by the
+     * {@code X509CertSelector}. Instead, the values are compared using
+     * a byte-by-byte comparison.
+     * <p>
+     * Note that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param subjectKeyID the subject key identifier (or {@code null})
+     * @see #getSubjectKeyIdentifier
+     */
+    public void setSubjectKeyIdentifier(byte[] subjectKeyID) {
+        if (subjectKeyID == null) {
+            this.subjectKeyID = null;
+        } else {
+            this.subjectKeyID = subjectKeyID.clone();
+        }
+    }
+
+    /**
+     * Sets the authorityKeyIdentifier criterion. The
+     * {@code X509Certificate} must contain an
+     * AuthorityKeyIdentifier extension for which the contents of the
+     * extension value matches the specified criterion value.
+     * If the criterion value is {@code null}, no
+     * authorityKeyIdentifier check will be done.
+     * <p>
+     * If {@code authorityKeyID} is not {@code null}, it
+     * should contain a single DER encoded value corresponding to the contents
+     * of the extension value (not including the object identifier,
+     * criticality setting, and encapsulating OCTET STRING)
+     * for an AuthorityKeyIdentifier extension.
+     * The ASN.1 notation for this structure follows.
+     *
+     * <pre>{@code
+     * AuthorityKeyIdentifier ::= SEQUENCE {
+     *    keyIdentifier             [0] KeyIdentifier           OPTIONAL,
+     *    authorityCertIssuer       [1] GeneralNames            OPTIONAL,
+     *    authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }
+     *
+     * KeyIdentifier ::= OCTET STRING
+     * }</pre>
+     * <p>
+     * Authority key identifiers are not parsed by the
+     * {@code X509CertSelector}.  Instead, the values are
+     * compared using a byte-by-byte comparison.
+     * <p>
+     * When the {@code keyIdentifier} field of
+     * {@code AuthorityKeyIdentifier} is populated, the value is
+     * usually taken from the {@code SubjectKeyIdentifier} extension
+     * in the issuer's certificate.  Note, however, that the result of
+     * {@code X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object
+     * Identifier>)} on the issuer's certificate may NOT be used
+     * directly as the input to {@code setAuthorityKeyIdentifier}.
+     * This is because the SubjectKeyIdentifier contains
+     * only a KeyIdentifier OCTET STRING, and not a SEQUENCE of
+     * KeyIdentifier, GeneralNames, and CertificateSerialNumber.
+     * In order to use the extension value of the issuer certificate's
+     * {@code SubjectKeyIdentifier}
+     * extension, it will be necessary to extract the value of the embedded
+     * {@code KeyIdentifier} OCTET STRING, then DER encode this OCTET
+     * STRING inside a SEQUENCE.
+     * For more details on SubjectKeyIdentifier, see
+     * {@link #setSubjectKeyIdentifier(byte[] subjectKeyID)}.
+     * <p>
+     * Note also that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param authorityKeyID the authority key identifier
+     *        (or {@code null})
+     * @see #getAuthorityKeyIdentifier
+     */
+    public void setAuthorityKeyIdentifier(byte[] authorityKeyID) {
+        if (authorityKeyID == null) {
+            this.authorityKeyID = null;
+        } else {
+            this.authorityKeyID = authorityKeyID.clone();
+        }
+    }
+
+    /**
+     * Sets the certificateValid criterion. The specified date must fall
+     * within the certificate validity period for the
+     * {@code X509Certificate}. If {@code null}, no certificateValid
+     * check will be done.
+     * <p>
+     * Note that the {@code Date} supplied here is cloned to protect
+     * against subsequent modifications.
+     *
+     * @param certValid the {@code Date} to check (or {@code null})
+     * @see #getCertificateValid
+     */
+    public void setCertificateValid(Date certValid) {
+        if (certValid == null) {
+            certificateValid = null;
+        } else {
+            certificateValid = (Date)certValid.clone();
+        }
+    }
+
+    /**
+     * Sets the privateKeyValid criterion. The specified date must fall
+     * within the private key validity period for the
+     * {@code X509Certificate}. If {@code null}, no privateKeyValid
+     * check will be done.
+     * <p>
+     * Note that the {@code Date} supplied here is cloned to protect
+     * against subsequent modifications.
+     *
+     * @param privateKeyValid the {@code Date} to check (or
+     *                        {@code null})
+     * @see #getPrivateKeyValid
+     */
+    public void setPrivateKeyValid(Date privateKeyValid) {
+        if (privateKeyValid == null) {
+            this.privateKeyValid = null;
+        } else {
+            this.privateKeyValid = (Date)privateKeyValid.clone();
+        }
+    }
+
+    /**
+     * Sets the subjectPublicKeyAlgID criterion. The
+     * {@code X509Certificate} must contain a subject public key
+     * with the specified algorithm. If {@code null}, no
+     * subjectPublicKeyAlgID check will be done.
+     *
+     * @param oid The object identifier (OID) of the algorithm to check
+     *            for (or {@code null}). An OID is represented by a
+     *            set of nonnegative integers separated by periods.
+     * @throws IOException if the OID is invalid, such as
+     * the first component being not 0, 1 or 2 or the second component
+     * being greater than 39.
+     *
+     * @see #getSubjectPublicKeyAlgID
+     */
+    public void setSubjectPublicKeyAlgID(String oid) throws IOException {
+        if (oid == null) {
+            subjectPublicKeyAlgID = null;
+        } else {
+            subjectPublicKeyAlgID = new ObjectIdentifier(oid);
+        }
+    }
+
+    /**
+     * Sets the subjectPublicKey criterion. The
+     * {@code X509Certificate} must contain the specified subject public
+     * key. If {@code null}, no subjectPublicKey check will be done.
+     *
+     * @param key the subject public key to check for (or {@code null})
+     * @see #getSubjectPublicKey
+     */
+    public void setSubjectPublicKey(PublicKey key) {
+        if (key == null) {
+            subjectPublicKey = null;
+            subjectPublicKeyBytes = null;
+        } else {
+            subjectPublicKey = key;
+            subjectPublicKeyBytes = key.getEncoded();
+        }
+    }
+
+    /**
+     * Sets the subjectPublicKey criterion. The {@code X509Certificate}
+     * must contain the specified subject public key. If {@code null},
+     * no subjectPublicKey check will be done.
+     * <p>
+     * Because this method allows the public key to be specified as a byte
+     * array, it may be used for unknown key types.
+     * <p>
+     * If {@code key} is not {@code null}, it should contain a
+     * single DER encoded SubjectPublicKeyInfo structure, as defined in X.509.
+     * The ASN.1 notation for this structure is as follows.
+     * <pre>{@code
+     * SubjectPublicKeyInfo  ::=  SEQUENCE  {
+     *   algorithm            AlgorithmIdentifier,
+     *   subjectPublicKey     BIT STRING  }
+     *
+     * AlgorithmIdentifier  ::=  SEQUENCE  {
+     *   algorithm               OBJECT IDENTIFIER,
+     *   parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     *                              -- contains a value of the type
+     *                              -- registered for use with the
+     *                              -- algorithm object identifier value
+     * }</pre>
+     * <p>
+     * Note that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param key a byte array containing the subject public key in ASN.1 DER
+     *            form (or {@code null})
+     * @throws IOException if an encoding error occurs (incorrect form for
+     * subject public key)
+     * @see #getSubjectPublicKey
+     */
+    public void setSubjectPublicKey(byte[] key) throws IOException {
+        if (key == null) {
+            subjectPublicKey = null;
+            subjectPublicKeyBytes = null;
+        } else {
+            subjectPublicKeyBytes = key.clone();
+            subjectPublicKey = X509Key.parse(new DerValue(subjectPublicKeyBytes));
+        }
+    }
+
+    /**
+     * Sets the keyUsage criterion. The {@code X509Certificate}
+     * must allow the specified keyUsage values. If {@code null}, no
+     * keyUsage check will be done. Note that an {@code X509Certificate}
+     * that has no keyUsage extension implicitly allows all keyUsage values.
+     * <p>
+     * Note that the boolean array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param keyUsage a boolean array in the same format as the boolean
+     *                 array returned by
+     * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
+     *                 Or {@code null}.
+     * @see #getKeyUsage
+     */
+    public void setKeyUsage(boolean[] keyUsage) {
+        if (keyUsage == null) {
+            this.keyUsage = null;
+        } else {
+            this.keyUsage = keyUsage.clone();
+        }
+    }
+
+    /**
+     * Sets the extendedKeyUsage criterion. The {@code X509Certificate}
+     * must allow the specified key purposes in its extended key usage
+     * extension. If {@code keyPurposeSet} is empty or {@code null},
+     * no extendedKeyUsage check will be done. Note that an
+     * {@code X509Certificate} that has no extendedKeyUsage extension
+     * implicitly allows all key purposes.
+     * <p>
+     * Note that the {@code Set} is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param keyPurposeSet a {@code Set} of key purpose OIDs in string
+     * format (or {@code null}). Each OID is represented by a set of
+     * nonnegative integers separated by periods.
+     * @throws IOException if the OID is invalid, such as
+     * the first component being not 0, 1 or 2 or the second component
+     * being greater than 39.
+     * @see #getExtendedKeyUsage
+     */
+    public void setExtendedKeyUsage(Set<String> keyPurposeSet) throws IOException {
+        if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
+            this.keyPurposeSet = null;
+            keyPurposeOIDSet = null;
+        } else {
+            this.keyPurposeSet =
+                Collections.unmodifiableSet(new HashSet<String>(keyPurposeSet));
+            keyPurposeOIDSet = new HashSet<ObjectIdentifier>();
+            for (String s : this.keyPurposeSet) {
+                keyPurposeOIDSet.add(new ObjectIdentifier(s));
+            }
+        }
+    }
+
+    /**
+     * Enables/disables matching all of the subjectAlternativeNames
+     * specified in the {@link #setSubjectAlternativeNames
+     * setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
+     * addSubjectAlternativeName} methods. If enabled,
+     * the {@code X509Certificate} must contain all of the
+     * specified subject alternative names. If disabled, the
+     * {@code X509Certificate} must contain at least one of the
+     * specified subject alternative names.
+     *
+     * <p>The matchAllNames flag is {@code true} by default.
+     *
+     * @param matchAllNames if {@code true}, the flag is enabled;
+     * if {@code false}, the flag is disabled.
+     * @see #getMatchAllSubjectAltNames
+     */
+    public void setMatchAllSubjectAltNames(boolean matchAllNames) {
+        this.matchAllSubjectAltNames = matchAllNames;
+    }
+
+    /**
+     * Sets the subjectAlternativeNames criterion. The
+     * {@code X509Certificate} must contain all or at least one of the
+     * specified subjectAlternativeNames, depending on the value of
+     * the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
+     * setMatchAllSubjectAltNames}).
+     * <p>
+     * This method allows the caller to specify, with a single method call,
+     * the complete set of subject alternative names for the
+     * subjectAlternativeNames criterion. The specified value replaces
+     * the previous value for the subjectAlternativeNames criterion.
+     * <p>
+     * The {@code names} parameter (if not {@code null}) is a
+     * {@code Collection} with one
+     * entry for each name to be included in the subject alternative name
+     * criterion. Each entry is a {@code List} whose first entry is an
+     * {@code Integer} (the name type, 0-8) and whose second
+     * entry is a {@code String} or a byte array (the name, in
+     * string or ASN.1 DER encoded form, respectively).
+     * There can be multiple names of the same type. If {@code null}
+     * is supplied as the value for this argument, no
+     * subjectAlternativeNames check will be performed.
+     * <p>
+     * Each subject alternative name in the {@code Collection}
+     * may be specified either as a {@code String} or as an ASN.1 encoded
+     * byte array. For more details about the formats used, see
+     * {@link #addSubjectAlternativeName(int type, String name)
+     * addSubjectAlternativeName(int type, String name)} and
+     * {@link #addSubjectAlternativeName(int type, byte [] name)
+     * addSubjectAlternativeName(int type, byte [] name)}.
+     * <p>
+     * <strong>Note:</strong> for distinguished names, specify the byte
+     * array form instead of the String form. See the note in
+     * {@link #addSubjectAlternativeName(int, String)} for more information.
+     * <p>
+     * Note that the {@code names} parameter can contain duplicate
+     * names (same name and name type), but they may be removed from the
+     * {@code Collection} of names returned by the
+     * {@link #getSubjectAlternativeNames getSubjectAlternativeNames} method.
+     * <p>
+     * Note that a deep copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @param names a {@code Collection} of names (or {@code null})
+     * @throws IOException if a parsing error occurs
+     * @see #getSubjectAlternativeNames
+     */
+    public void setSubjectAlternativeNames(Collection<List<?>> names)
+            throws IOException {
+        if (names == null) {
+            subjectAlternativeNames = null;
+            subjectAlternativeGeneralNames = null;
+        } else {
+            if (names.isEmpty()) {
+                subjectAlternativeNames = null;
+                subjectAlternativeGeneralNames = null;
+                return;
+            }
+            Set<List<?>> tempNames = cloneAndCheckNames(names);
+            // Ensure that we either set both of these or neither
+            subjectAlternativeGeneralNames = parseNames(tempNames);
+            subjectAlternativeNames = tempNames;
+        }
+    }
+
+    /**
+     * Adds a name to the subjectAlternativeNames criterion. The
+     * {@code X509Certificate} must contain all or at least one
+     * of the specified subjectAlternativeNames, depending on the value of
+     * the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
+     * setMatchAllSubjectAltNames}).
+     * <p>
+     * This method allows the caller to add a name to the set of subject
+     * alternative names.
+     * The specified name is added to any previous value for the
+     * subjectAlternativeNames criterion. If the specified name is a
+     * duplicate, it may be ignored.
+     * <p>
+     * The name is provided in string format.
+     * <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a>, DNS, and URI
+     * names use the well-established string formats for those types (subject to
+     * the restrictions included in RFC 3280). IPv4 address names are
+     * supplied using dotted quad notation. OID address names are represented
+     * as a series of nonnegative integers separated by periods. And
+     * directory names (distinguished names) are supplied in RFC 2253 format.
+     * No standard string format is defined for otherNames, X.400 names,
+     * EDI party names, IPv6 address names, or any other type of names. They
+     * should be specified using the
+     * {@link #addSubjectAlternativeName(int type, byte [] name)
+     * addSubjectAlternativeName(int type, byte [] name)}
+     * method.
+     * <p>
+     * <strong>Note:</strong> for distinguished names, use
+     * {@linkplain #addSubjectAlternativeName(int, byte[])} instead.
+     * This method should not be relied on as it can fail to match some
+     * certificates because of a loss of encoding information in the RFC 2253
+     * String form of some distinguished names.
+     *
+     * @param type the name type (0-8, as specified in
+     *             RFC 3280, section 4.2.1.7)
+     * @param name the name in string form (not {@code null})
+     * @throws IOException if a parsing error occurs
+     */
+    public void addSubjectAlternativeName(int type, String name)
+            throws IOException {
+        addSubjectAlternativeNameInternal(type, name);
+    }
+
+    /**
+     * Adds a name to the subjectAlternativeNames criterion. The
+     * {@code X509Certificate} must contain all or at least one
+     * of the specified subjectAlternativeNames, depending on the value of
+     * the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
+     * setMatchAllSubjectAltNames}).
+     * <p>
+     * This method allows the caller to add a name to the set of subject
+     * alternative names.
+     * The specified name is added to any previous value for the
+     * subjectAlternativeNames criterion. If the specified name is a
+     * duplicate, it may be ignored.
+     * <p>
+     * The name is provided as a byte array. This byte array should contain
+     * the DER encoded name, as it would appear in the GeneralName structure
+     * defined in RFC 3280 and X.509. The encoded byte array should only contain
+     * the encoded value of the name, and should not include the tag associated
+     * with the name in the GeneralName structure. The ASN.1 definition of this
+     * structure appears below.
+     * <pre>{@code
+     *  GeneralName ::= CHOICE {
+     *       otherName                       [0]     OtherName,
+     *       rfc822Name                      [1]     IA5String,
+     *       dNSName                         [2]     IA5String,
+     *       x400Address                     [3]     ORAddress,
+     *       directoryName                   [4]     Name,
+     *       ediPartyName                    [5]     EDIPartyName,
+     *       uniformResourceIdentifier       [6]     IA5String,
+     *       iPAddress                       [7]     OCTET STRING,
+     *       registeredID                    [8]     OBJECT IDENTIFIER}
+     * }</pre>
+     * <p>
+     * Note that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param type the name type (0-8, as listed above)
+     * @param name a byte array containing the name in ASN.1 DER encoded form
+     * @throws IOException if a parsing error occurs
+     */
+    public void addSubjectAlternativeName(int type, byte[] name)
+            throws IOException {
+        // clone because byte arrays are modifiable
+        addSubjectAlternativeNameInternal(type, name.clone());
+    }
+
+    /**
+     * A private method that adds a name (String or byte array) to the
+     * subjectAlternativeNames criterion. The {@code X509Certificate}
+     * must contain the specified subjectAlternativeName.
+     *
+     * @param type the name type (0-8, as specified in
+     *             RFC 3280, section 4.2.1.7)
+     * @param name the name in string or byte array form
+     * @throws IOException if a parsing error occurs
+     */
+    private void addSubjectAlternativeNameInternal(int type, Object name)
+            throws IOException {
+        // First, ensure that the name parses
+        GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
+        if (subjectAlternativeNames == null) {
+            subjectAlternativeNames = new HashSet<List<?>>();
+        }
+        if (subjectAlternativeGeneralNames == null) {
+            subjectAlternativeGeneralNames = new HashSet<GeneralNameInterface>();
+        }
+        List<Object> list = new ArrayList<Object>(2);
+        list.add(Integer.valueOf(type));
+        list.add(name);
+        subjectAlternativeNames.add(list);
+        subjectAlternativeGeneralNames.add(tempName);
+    }
+
+    /**
+     * Parse an argument of the form passed to setSubjectAlternativeNames,
+     * returning a {@code Collection} of
+     * {@code GeneralNameInterface}s.
+     * Throw an IllegalArgumentException or a ClassCastException
+     * if the argument is malformed.
+     *
+     * @param names a Collection with one entry per name.
+     *              Each entry is a {@code List} whose first entry
+     *              is an Integer (the name type, 0-8) and whose second
+     *              entry is a String or a byte array (the name, in
+     *              string or ASN.1 DER encoded form, respectively).
+     *              There can be multiple names of the same type. Null is
+     *              not an acceptable value.
+     * @return a Set of {@code GeneralNameInterface}s
+     * @throws IOException if a parsing error occurs
+     */
+    private static Set<GeneralNameInterface> parseNames(Collection<List<?>> names) throws IOException {
+        Set<GeneralNameInterface> genNames = new HashSet<GeneralNameInterface>();
+        for (List<?> nameList : names) {
+            if (nameList.size() != 2) {
+                throw new IOException("name list size not 2");
+            }
+            Object o =  nameList.get(0);
+            if (!(o instanceof Integer)) {
+                throw new IOException("expected an Integer");
+            }
+            int nameType = ((Integer)o).intValue();
+            o = nameList.get(1);
+            genNames.add(makeGeneralNameInterface(nameType, o));
+        }
+
+        return genNames;
+    }
+
+    /**
+     * Compare for equality two objects of the form passed to
+     * setSubjectAlternativeNames (or X509CRLSelector.setIssuerNames).
+     * Throw an {@code IllegalArgumentException} or a
+     * {@code ClassCastException} if one of the objects is malformed.
+     *
+     * @param object1 a Collection containing the first object to compare
+     * @param object2 a Collection containing the second object to compare
+     * @return true if the objects are equal, false otherwise
+     */
+    static boolean equalNames(Collection<?> object1, Collection<?> object2) {
+        if ((object1 == null) || (object2 == null)) {
+            return object1 == object2;
+        }
+        return object1.equals(object2);
+    }
+
+    /**
+     * Make a {@code GeneralNameInterface} out of a name type (0-8) and an
+     * Object that may be a byte array holding the ASN.1 DER encoded
+     * name or a String form of the name.  Except for X.509
+     * Distinguished Names, the String form of the name must not be the
+     * result from calling toString on an existing GeneralNameInterface
+     * implementing class.  The output of toString is not compatible
+     * with the String constructors for names other than Distinguished
+     * Names.
+     *
+     * @param type name type (0-8)
+     * @param name name as ASN.1 Der-encoded byte array or String
+     * @return a GeneralNameInterface name
+     * @throws IOException if a parsing error occurs
+     */
+    static GeneralNameInterface makeGeneralNameInterface(int type, Object name)
+            throws IOException {
+        GeneralNameInterface result;
+        if (debug != null) {
+            debug.println("X509CertSelector.makeGeneralNameInterface("
+                + type + ")...");
+        }
+
+        if (name instanceof String) {
+            if (debug != null) {
+                debug.println("X509CertSelector.makeGeneralNameInterface() "
+                    + "name is String: " + name);
+            }
+            switch (type) {
+            case NAME_RFC822:
+                result = new RFC822Name((String)name);
+                break;
+            case NAME_DNS:
+                result = new DNSName((String)name);
+                break;
+            case NAME_DIRECTORY:
+                result = new X500Name((String)name);
+                break;
+            case NAME_URI:
+                result = new URIName((String)name);
+                break;
+            case NAME_IP:
+                result = new IPAddressName((String)name);
+                break;
+            case NAME_OID:
+                result = new OIDName((String)name);
+                break;
+            default:
+                throw new IOException("unable to parse String names of type "
+                                      + type);
+            }
+            if (debug != null) {
+                debug.println("X509CertSelector.makeGeneralNameInterface() "
+                    + "result: " + result.toString());
+            }
+        } else if (name instanceof byte[]) {
+            DerValue val = new DerValue((byte[]) name);
+            if (debug != null) {
+                debug.println
+                    ("X509CertSelector.makeGeneralNameInterface() is byte[]");
+            }
+
+            switch (type) {
+            case NAME_ANY:
+                result = new OtherName(val);
+                break;
+            case NAME_RFC822:
+                result = new RFC822Name(val);
+                break;
+            case NAME_DNS:
+                result = new DNSName(val);
+                break;
+            case NAME_X400:
+                result = new X400Address(val);
+                break;
+            case NAME_DIRECTORY:
+                result = new X500Name(val);
+                break;
+            case NAME_EDI:
+                result = new EDIPartyName(val);
+                break;
+            case NAME_URI:
+                result = new URIName(val);
+                break;
+            case NAME_IP:
+                result = new IPAddressName(val);
+                break;
+            case NAME_OID:
+                result = new OIDName(val);
+                break;
+            default:
+                throw new IOException("unable to parse byte array names of "
+                    + "type " + type);
+            }
+            if (debug != null) {
+                debug.println("X509CertSelector.makeGeneralNameInterface() result: "
+                    + result.toString());
+            }
+        } else {
+            if (debug != null) {
+                debug.println("X509CertSelector.makeGeneralName() input name "
+                    + "not String or byte array");
+            }
+            throw new IOException("name not String or byte array");
+        }
+        return result;
+    }
+
+
+    /**
+     * Sets the name constraints criterion. The {@code X509Certificate}
+     * must have subject and subject alternative names that
+     * meet the specified name constraints.
+     * <p>
+     * The name constraints are specified as a byte array. This byte array
+     * should contain the DER encoded form of the name constraints, as they
+     * would appear in the NameConstraints structure defined in RFC 3280
+     * and X.509. The ASN.1 definition of this structure appears below.
+     *
+     * <pre>{@code
+     *  NameConstraints ::= SEQUENCE {
+     *       permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+     *       excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+     *
+     *  GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+     *
+     *  GeneralSubtree ::= SEQUENCE {
+     *       base                    GeneralName,
+     *       minimum         [0]     BaseDistance DEFAULT 0,
+     *       maximum         [1]     BaseDistance OPTIONAL }
+     *
+     *  BaseDistance ::= INTEGER (0..MAX)
+     *
+     *  GeneralName ::= CHOICE {
+     *       otherName                       [0]     OtherName,
+     *       rfc822Name                      [1]     IA5String,
+     *       dNSName                         [2]     IA5String,
+     *       x400Address                     [3]     ORAddress,
+     *       directoryName                   [4]     Name,
+     *       ediPartyName                    [5]     EDIPartyName,
+     *       uniformResourceIdentifier       [6]     IA5String,
+     *       iPAddress                       [7]     OCTET STRING,
+     *       registeredID                    [8]     OBJECT IDENTIFIER}
+     * }</pre>
+     * <p>
+     * Note that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param bytes a byte array containing the ASN.1 DER encoding of
+     *              a NameConstraints extension to be used for checking
+     *              name constraints. Only the value of the extension is
+     *              included, not the OID or criticality flag. Can be
+     *              {@code null},
+     *              in which case no name constraints check will be performed.
+     * @throws IOException if a parsing error occurs
+     * @see #getNameConstraints
+     */
+    public void setNameConstraints(byte[] bytes) throws IOException {
+        if (bytes == null) {
+            ncBytes = null;
+            nc = null;
+        } else {
+            ncBytes = bytes.clone();
+            nc = new NameConstraintsExtension(FALSE, bytes);
+        }
+    }
+
+    /**
+     * Sets the basic constraints constraint. If the value is greater than or
+     * equal to zero, {@code X509Certificates} must include a
+     * basicConstraints extension with
+     * a pathLen of at least this value. If the value is -2, only end-entity
+     * certificates are accepted. If the value is -1, no check is done.
+     * <p>
+     * This constraint is useful when building a certification path forward
+     * (from the target toward the trust anchor. If a partial path has been
+     * built, any candidate certificate must have a maxPathLen value greater
+     * than or equal to the number of certificates in the partial path.
+     *
+     * @param minMaxPathLen the value for the basic constraints constraint
+     * @throws IllegalArgumentException if the value is less than -2
+     * @see #getBasicConstraints
+     */
+    public void setBasicConstraints(int minMaxPathLen) {
+        if (minMaxPathLen < -2) {
+            throw new IllegalArgumentException("basic constraints less than -2");
+        }
+        basicConstraints = minMaxPathLen;
+    }
+
+    /**
+     * Sets the policy constraint. The {@code X509Certificate} must
+     * include at least one of the specified policies in its certificate
+     * policies extension. If {@code certPolicySet} is empty, then the
+     * {@code X509Certificate} must include at least some specified policy
+     * in its certificate policies extension. If {@code certPolicySet} is
+     * {@code null}, no policy check will be performed.
+     * <p>
+     * Note that the {@code Set} is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param certPolicySet a {@code Set} of certificate policy OIDs in
+     *                      string format (or {@code null}). Each OID is
+     *                      represented by a set of nonnegative integers
+     *                    separated by periods.
+     * @throws IOException if a parsing error occurs on the OID such as
+     * the first component is not 0, 1 or 2 or the second component is
+     * greater than 39.
+     * @see #getPolicy
+     */
+    public void setPolicy(Set<String> certPolicySet) throws IOException {
+        if (certPolicySet == null) {
+            policySet = null;
+            policy = null;
+        } else {
+            // Snapshot set and parse it
+            Set<String> tempSet = Collections.unmodifiableSet
+                                        (new HashSet<String>(certPolicySet));
+            /* Convert to Vector of ObjectIdentifiers */
+            Iterator<String> i = tempSet.iterator();
+            Vector<CertificatePolicyId> polIdVector = new Vector<CertificatePolicyId>();
+            while (i.hasNext()) {
+                Object o = i.next();
+                if (!(o instanceof String)) {
+                    throw new IOException("non String in certPolicySet");
+                }
+                polIdVector.add(new CertificatePolicyId(new ObjectIdentifier(
+                  (String)o)));
+            }
+            // If everything went OK, make the changes
+            policySet = tempSet;
+            policy = new CertificatePolicySet(polIdVector);
+        }
+    }
+
+    /**
+     * Sets the pathToNames criterion. The {@code X509Certificate} must
+     * not include name constraints that would prohibit building a
+     * path to the specified names.
+     * <p>
+     * This method allows the caller to specify, with a single method call,
+     * the complete set of names which the {@code X509Certificates}'s
+     * name constraints must permit. The specified value replaces
+     * the previous value for the pathToNames criterion.
+     * <p>
+     * This constraint is useful when building a certification path forward
+     * (from the target toward the trust anchor. If a partial path has been
+     * built, any candidate certificate must not include name constraints that
+     * would prohibit building a path to any of the names in the partial path.
+     * <p>
+     * The {@code names} parameter (if not {@code null}) is a
+     * {@code Collection} with one
+     * entry for each name to be included in the pathToNames
+     * criterion. Each entry is a {@code List} whose first entry is an
+     * {@code Integer} (the name type, 0-8) and whose second
+     * entry is a {@code String} or a byte array (the name, in
+     * string or ASN.1 DER encoded form, respectively).
+     * There can be multiple names of the same type. If {@code null}
+     * is supplied as the value for this argument, no
+     * pathToNames check will be performed.
+     * <p>
+     * Each name in the {@code Collection}
+     * may be specified either as a {@code String} or as an ASN.1 encoded
+     * byte array. For more details about the formats used, see
+     * {@link #addPathToName(int type, String name)
+     * addPathToName(int type, String name)} and
+     * {@link #addPathToName(int type, byte [] name)
+     * addPathToName(int type, byte [] name)}.
+     * <p>
+     * <strong>Note:</strong> for distinguished names, specify the byte
+     * array form instead of the String form. See the note in
+     * {@link #addPathToName(int, String)} for more information.
+     * <p>
+     * Note that the {@code names} parameter can contain duplicate
+     * names (same name and name type), but they may be removed from the
+     * {@code Collection} of names returned by the
+     * {@link #getPathToNames getPathToNames} method.
+     * <p>
+     * Note that a deep copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @param names a {@code Collection} with one entry per name
+     *              (or {@code null})
+     * @throws IOException if a parsing error occurs
+     * @see #getPathToNames
+     */
+    public void setPathToNames(Collection<List<?>> names) throws IOException {
+        if ((names == null) || names.isEmpty()) {
+            pathToNames = null;
+            pathToGeneralNames = null;
+        } else {
+            Set<List<?>> tempNames = cloneAndCheckNames(names);
+            pathToGeneralNames = parseNames(tempNames);
+            // Ensure that we either set both of these or neither
+            pathToNames = tempNames;
+        }
+    }
+
+    // called from CertPathHelper
+    void setPathToNamesInternal(Set<GeneralNameInterface> names) {
+        // set names to non-null dummy value
+        // this breaks getPathToNames()
+        pathToNames = Collections.<List<?>>emptySet();
+        pathToGeneralNames = names;
+    }
+
+    /**
+     * Adds a name to the pathToNames criterion. The {@code X509Certificate}
+     * must not include name constraints that would prohibit building a
+     * path to the specified name.
+     * <p>
+     * This method allows the caller to add a name to the set of names which
+     * the {@code X509Certificates}'s name constraints must permit.
+     * The specified name is added to any previous value for the
+     * pathToNames criterion.  If the name is a duplicate, it may be ignored.
+     * <p>
+     * The name is provided in string format. RFC 822, DNS, and URI names
+     * use the well-established string formats for those types (subject to
+     * the restrictions included in RFC 3280). IPv4 address names are
+     * supplied using dotted quad notation. OID address names are represented
+     * as a series of nonnegative integers separated by periods. And
+     * directory names (distinguished names) are supplied in RFC 2253 format.
+     * No standard string format is defined for otherNames, X.400 names,
+     * EDI party names, IPv6 address names, or any other type of names. They
+     * should be specified using the
+     * {@link #addPathToName(int type, byte [] name)
+     * addPathToName(int type, byte [] name)} method.
+     * <p>
+     * <strong>Note:</strong> for distinguished names, use
+     * {@linkplain #addPathToName(int, byte[])} instead.
+     * This method should not be relied on as it can fail to match some
+     * certificates because of a loss of encoding information in the RFC 2253
+     * String form of some distinguished names.
+     *
+     * @param type the name type (0-8, as specified in
+     *             RFC 3280, section 4.2.1.7)
+     * @param name the name in string form
+     * @throws IOException if a parsing error occurs
+     */
+    public void addPathToName(int type, String name) throws IOException {
+        addPathToNameInternal(type, name);
+    }
+
+    /**
+     * Adds a name to the pathToNames criterion. The {@code X509Certificate}
+     * must not include name constraints that would prohibit building a
+     * path to the specified name.
+     * <p>
+     * This method allows the caller to add a name to the set of names which
+     * the {@code X509Certificates}'s name constraints must permit.
+     * The specified name is added to any previous value for the
+     * pathToNames criterion. If the name is a duplicate, it may be ignored.
+     * <p>
+     * The name is provided as a byte array. This byte array should contain
+     * the DER encoded name, as it would appear in the GeneralName structure
+     * defined in RFC 3280 and X.509. The ASN.1 definition of this structure
+     * appears in the documentation for
+     * {@link #addSubjectAlternativeName(int type, byte [] name)
+     * addSubjectAlternativeName(int type, byte [] name)}.
+     * <p>
+     * Note that the byte array supplied here is cloned to protect against
+     * subsequent modifications.
+     *
+     * @param type the name type (0-8, as specified in
+     *             RFC 3280, section 4.2.1.7)
+     * @param name a byte array containing the name in ASN.1 DER encoded form
+     * @throws IOException if a parsing error occurs
+     */
+    public void addPathToName(int type, byte [] name) throws IOException {
+        // clone because byte arrays are modifiable
+        addPathToNameInternal(type, name.clone());
+    }
+
+    /**
+     * A private method that adds a name (String or byte array) to the
+     * pathToNames criterion. The {@code X509Certificate} must contain
+     * the specified pathToName.
+     *
+     * @param type the name type (0-8, as specified in
+     *             RFC 3280, section 4.2.1.7)
+     * @param name the name in string or byte array form
+     * @throws IOException if an encoding error occurs (incorrect form for DN)
+     */
+    private void addPathToNameInternal(int type, Object name)
+            throws IOException {
+        // First, ensure that the name parses
+        GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
+        if (pathToGeneralNames == null) {
+            pathToNames = new HashSet<List<?>>();
+            pathToGeneralNames = new HashSet<GeneralNameInterface>();
+        }
+        List<Object> list = new ArrayList<Object>(2);
+        list.add(Integer.valueOf(type));
+        list.add(name);
+        pathToNames.add(list);
+        pathToGeneralNames.add(tempName);
+    }
+
+    /**
+     * Returns the certificateEquals criterion. The specified
+     * {@code X509Certificate} must be equal to the
+     * {@code X509Certificate} passed to the {@code match} method.
+     * If {@code null}, this check is not applied.
+     *
+     * @return the {@code X509Certificate} to match (or {@code null})
+     * @see #setCertificate
+     */
+    public X509Certificate getCertificate() {
+        return x509Cert;
+    }
+
+    /**
+     * Returns the serialNumber criterion. The specified serial number
+     * must match the certificate serial number in the
+     * {@code X509Certificate}. If {@code null}, any certificate
+     * serial number will do.
+     *
+     * @return the certificate serial number to match
+     *                (or {@code null})
+     * @see #setSerialNumber
+     */
+    public BigInteger getSerialNumber() {
+        return serialNumber;
+    }
+
+    /**
+     * Returns the issuer criterion as an {@code X500Principal}. This
+     * distinguished name must match the issuer distinguished name in the
+     * {@code X509Certificate}. If {@code null}, the issuer criterion
+     * is disabled and any issuer distinguished name will do.
+     *
+     * @return the required issuer distinguished name as X500Principal
+     *         (or {@code null})
+     * @since 1.5
+     */
+    public X500Principal getIssuer() {
+        return issuer;
+    }
+
+    /**
+     * <strong>Denigrated</strong>, use {@linkplain #getIssuer()} or
+     * {@linkplain #getIssuerAsBytes()} instead. This method should not be
+     * relied on as it can fail to match some certificates because of a loss of
+     * encoding information in the RFC 2253 String form of some distinguished
+     * names.
+     * <p>
+     * Returns the issuer criterion as a {@code String}. This
+     * distinguished name must match the issuer distinguished name in the
+     * {@code X509Certificate}. If {@code null}, the issuer criterion
+     * is disabled and any issuer distinguished name will do.
+     * <p>
+     * If the value returned is not {@code null}, it is a
+     * distinguished name, in RFC 2253 format.
+     *
+     * @return the required issuer distinguished name in RFC 2253 format
+     *         (or {@code null})
+     */
+    public String getIssuerAsString() {
+        return (issuer == null ? null : issuer.getName());
+    }
+
+    /**
+     * Returns the issuer criterion as a byte array. This distinguished name
+     * must match the issuer distinguished name in the
+     * {@code X509Certificate}. If {@code null}, the issuer criterion
+     * is disabled and any issuer distinguished name will do.
+     * <p>
+     * If the value returned is not {@code null}, it is a byte
+     * array containing a single DER encoded distinguished name, as defined in
+     * X.501. The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #setIssuer(byte [] issuerDN) setIssuer(byte [] issuerDN)}.
+     * <p>
+     * Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return a byte array containing the required issuer distinguished name
+     *         in ASN.1 DER format (or {@code null})
+     * @throws IOException if an encoding error occurs
+     */
+    public byte[] getIssuerAsBytes() throws IOException {
+        return (issuer == null ? null: issuer.getEncoded());
+    }
+
+    /**
+     * Returns the subject criterion as an {@code X500Principal}. This
+     * distinguished name must match the subject distinguished name in the
+     * {@code X509Certificate}. If {@code null}, the subject criterion
+     * is disabled and any subject distinguished name will do.
+     *
+     * @return the required subject distinguished name as X500Principal
+     *         (or {@code null})
+     * @since 1.5
+     */
+    public X500Principal getSubject() {
+        return subject;
+    }
+
+    /**
+     * <strong>Denigrated</strong>, use {@linkplain #getSubject()} or
+     * {@linkplain #getSubjectAsBytes()} instead. This method should not be
+     * relied on as it can fail to match some certificates because of a loss of
+     * encoding information in the RFC 2253 String form of some distinguished
+     * names.
+     * <p>
+     * Returns the subject criterion as a {@code String}. This
+     * distinguished name must match the subject distinguished name in the
+     * {@code X509Certificate}. If {@code null}, the subject criterion
+     * is disabled and any subject distinguished name will do.
+     * <p>
+     * If the value returned is not {@code null}, it is a
+     * distinguished name, in RFC 2253 format.
+     *
+     * @return the required subject distinguished name in RFC 2253 format
+     *         (or {@code null})
+     */
+    public String getSubjectAsString() {
+        return (subject == null ? null : subject.getName());
+    }
+
+    /**
+     * Returns the subject criterion as a byte array. This distinguished name
+     * must match the subject distinguished name in the
+     * {@code X509Certificate}. If {@code null}, the subject criterion
+     * is disabled and any subject distinguished name will do.
+     * <p>
+     * If the value returned is not {@code null}, it is a byte
+     * array containing a single DER encoded distinguished name, as defined in
+     * X.501. The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #setSubject(byte [] subjectDN) setSubject(byte [] subjectDN)}.
+     * <p>
+     * Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return a byte array containing the required subject distinguished name
+     *         in ASN.1 DER format (or {@code null})
+     * @throws IOException if an encoding error occurs
+     */
+    public byte[] getSubjectAsBytes() throws IOException {
+        return (subject == null ? null : subject.getEncoded());
+    }
+
+    /**
+     * Returns the subjectKeyIdentifier criterion. The
+     * {@code X509Certificate} must contain a SubjectKeyIdentifier
+     * extension with the specified value. If {@code null}, no
+     * subjectKeyIdentifier check will be done.
+     * <p>
+     * Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return the key identifier (or {@code null})
+     * @see #setSubjectKeyIdentifier
+     */
+    public byte[] getSubjectKeyIdentifier() {
+        if (subjectKeyID == null) {
+            return null;
+        }
+        return subjectKeyID.clone();
+    }
+
+    /**
+     * Returns the authorityKeyIdentifier criterion. The
+     * {@code X509Certificate} must contain a AuthorityKeyIdentifier
+     * extension with the specified value. If {@code null}, no
+     * authorityKeyIdentifier check will be done.
+     * <p>
+     * Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return the key identifier (or {@code null})
+     * @see #setAuthorityKeyIdentifier
+     */
+    public byte[] getAuthorityKeyIdentifier() {
+        if (authorityKeyID == null) {
+          return null;
+        }
+        return authorityKeyID.clone();
+    }
+
+    /**
+     * Returns the certificateValid criterion. The specified date must fall
+     * within the certificate validity period for the
+     * {@code X509Certificate}. If {@code null}, no certificateValid
+     * check will be done.
+     * <p>
+     * Note that the {@code Date} returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return the {@code Date} to check (or {@code null})
+     * @see #setCertificateValid
+     */
+    public Date getCertificateValid() {
+        if (certificateValid == null) {
+            return null;
+        }
+        return (Date)certificateValid.clone();
+    }
+
+    /**
+     * Returns the privateKeyValid criterion. The specified date must fall
+     * within the private key validity period for the
+     * {@code X509Certificate}. If {@code null}, no privateKeyValid
+     * check will be done.
+     * <p>
+     * Note that the {@code Date} returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return the {@code Date} to check (or {@code null})
+     * @see #setPrivateKeyValid
+     */
+    public Date getPrivateKeyValid() {
+        if (privateKeyValid == null) {
+            return null;
+        }
+        return (Date)privateKeyValid.clone();
+    }
+
+    /**
+     * Returns the subjectPublicKeyAlgID criterion. The
+     * {@code X509Certificate} must contain a subject public key
+     * with the specified algorithm. If {@code null}, no
+     * subjectPublicKeyAlgID check will be done.
+     *
+     * @return the object identifier (OID) of the signature algorithm to check
+     *         for (or {@code null}). An OID is represented by a set of
+     *         nonnegative integers separated by periods.
+     * @see #setSubjectPublicKeyAlgID
+     */
+    public String getSubjectPublicKeyAlgID() {
+        if (subjectPublicKeyAlgID == null) {
+            return null;
+        }
+        return subjectPublicKeyAlgID.toString();
+    }
+
+    /**
+     * Returns the subjectPublicKey criterion. The
+     * {@code X509Certificate} must contain the specified subject
+     * public key. If {@code null}, no subjectPublicKey check will be done.
+     *
+     * @return the subject public key to check for (or {@code null})
+     * @see #setSubjectPublicKey
+     */
+    public PublicKey getSubjectPublicKey() {
+        return subjectPublicKey;
+    }
+
+    /**
+     * Returns the keyUsage criterion. The {@code X509Certificate}
+     * must allow the specified keyUsage values. If null, no keyUsage
+     * check will be done.
+     * <p>
+     * Note that the boolean array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return a boolean array in the same format as the boolean
+     *                 array returned by
+     * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
+     *                 Or {@code null}.
+     * @see #setKeyUsage
+     */
+    public boolean[] getKeyUsage() {
+        if (keyUsage == null) {
+            return null;
+        }
+        return keyUsage.clone();
+    }
+
+    /**
+     * Returns the extendedKeyUsage criterion. The {@code X509Certificate}
+     * must allow the specified key purposes in its extended key usage
+     * extension. If the {@code keyPurposeSet} returned is empty or
+     * {@code null}, no extendedKeyUsage check will be done. Note that an
+     * {@code X509Certificate} that has no extendedKeyUsage extension
+     * implicitly allows all key purposes.
+     *
+     * @return an immutable {@code Set} of key purpose OIDs in string
+     * format (or {@code null})
+     * @see #setExtendedKeyUsage
+     */
+    public Set<String> getExtendedKeyUsage() {
+        return keyPurposeSet;
+    }
+
+    /**
+     * Indicates if the {@code X509Certificate} must contain all
+     * or at least one of the subjectAlternativeNames
+     * specified in the {@link #setSubjectAlternativeNames
+     * setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
+     * addSubjectAlternativeName} methods. If {@code true},
+     * the {@code X509Certificate} must contain all of the
+     * specified subject alternative names. If {@code false}, the
+     * {@code X509Certificate} must contain at least one of the
+     * specified subject alternative names.
+     *
+     * @return {@code true} if the flag is enabled;
+     * {@code false} if the flag is disabled. The flag is
+     * {@code true} by default.
+     * @see #setMatchAllSubjectAltNames
+     */
+    public boolean getMatchAllSubjectAltNames() {
+        return matchAllSubjectAltNames;
+    }
+
+    /**
+     * Returns a copy of the subjectAlternativeNames criterion.
+     * The {@code X509Certificate} must contain all or at least one
+     * of the specified subjectAlternativeNames, depending on the value
+     * of the matchAllNames flag (see {@link #getMatchAllSubjectAltNames
+     * getMatchAllSubjectAltNames}). If the value returned is
+     * {@code null}, no subjectAlternativeNames check will be performed.
+     * <p>
+     * If the value returned is not {@code null}, it is a
+     * {@code Collection} with
+     * one entry for each name to be included in the subject alternative name
+     * criterion. Each entry is a {@code List} whose first entry is an
+     * {@code Integer} (the name type, 0-8) and whose second
+     * entry is a {@code String} or a byte array (the name, in
+     * string or ASN.1 DER encoded form, respectively).
+     * There can be multiple names of the same type.  Note that the
+     * {@code Collection} returned may contain duplicate names (same name
+     * and name type).
+     * <p>
+     * Each subject alternative name in the {@code Collection}
+     * may be specified either as a {@code String} or as an ASN.1 encoded
+     * byte array. For more details about the formats used, see
+     * {@link #addSubjectAlternativeName(int type, String name)
+     * addSubjectAlternativeName(int type, String name)} and
+     * {@link #addSubjectAlternativeName(int type, byte [] name)
+     * addSubjectAlternativeName(int type, byte [] name)}.
+     * <p>
+     * Note that a deep copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @return a {@code Collection} of names (or {@code null})
+     * @see #setSubjectAlternativeNames
+     */
+    public Collection<List<?>> getSubjectAlternativeNames() {
+        if (subjectAlternativeNames == null) {
+            return null;
+        }
+        return cloneNames(subjectAlternativeNames);
+    }
+
+    /**
+     * Clone an object of the form passed to
+     * setSubjectAlternativeNames and setPathToNames.
+     * Throw a {@code RuntimeException} if the argument is malformed.
+     * <p>
+     * This method wraps cloneAndCheckNames, changing any
+     * {@code IOException} into a {@code RuntimeException}. This
+     * method should be used when the object being
+     * cloned has already been checked, so there should never be any exceptions.
+     *
+     * @param names a {@code Collection} with one entry per name.
+     *              Each entry is a {@code List} whose first entry
+     *              is an Integer (the name type, 0-8) and whose second
+     *              entry is a String or a byte array (the name, in
+     *              string or ASN.1 DER encoded form, respectively).
+     *              There can be multiple names of the same type. Null
+     *              is not an acceptable value.
+     * @return a deep copy of the specified {@code Collection}
+     * @throws RuntimeException if a parsing error occurs
+     */
+    private static Set<List<?>> cloneNames(Collection<List<?>> names) {
+        try {
+            return cloneAndCheckNames(names);
+        } catch (IOException e) {
+            throw new RuntimeException("cloneNames encountered IOException: " +
+                                       e.getMessage());
+        }
+    }
+
+    /**
+     * Clone and check an argument of the form passed to
+     * setSubjectAlternativeNames and setPathToNames.
+     * Throw an {@code IOException} if the argument is malformed.
+     *
+     * @param names a {@code Collection} with one entry per name.
+     *              Each entry is a {@code List} whose first entry
+     *              is an Integer (the name type, 0-8) and whose second
+     *              entry is a String or a byte array (the name, in
+     *              string or ASN.1 DER encoded form, respectively).
+     *              There can be multiple names of the same type.
+     *              {@code null} is not an acceptable value.
+     * @return a deep copy of the specified {@code Collection}
+     * @throws IOException if a parsing error occurs
+     */
+    private static Set<List<?>> cloneAndCheckNames(Collection<List<?>> names) throws IOException {
+        // Copy the Lists and Collection
+        Set<List<?>> namesCopy = new HashSet<List<?>>();
+        for (List<?> o : names)
+        {
+            namesCopy.add(new ArrayList<Object>(o));
+        }
+
+        // Check the contents of the Lists and clone any byte arrays
+        for (List<?> list : namesCopy) {
+            @SuppressWarnings("unchecked") // See javadoc for parameter "names".
+            List<Object> nameList = (List<Object>)list;
+            if (nameList.size() != 2) {
+                throw new IOException("name list size not 2");
+            }
+            Object o = nameList.get(0);
+            if (!(o instanceof Integer)) {
+                throw new IOException("expected an Integer");
+            }
+            int nameType = ((Integer)o).intValue();
+            if ((nameType < 0) || (nameType > 8)) {
+                throw new IOException("name type not 0-8");
+            }
+            Object nameObject = nameList.get(1);
+            if (!(nameObject instanceof byte[]) &&
+                !(nameObject instanceof String)) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.cloneAndCheckNames() "
+                        + "name not byte array");
+                }
+                throw new IOException("name not byte array or String");
+            }
+            if (nameObject instanceof byte[]) {
+                nameList.set(1, ((byte[]) nameObject).clone());
+            }
+        }
+        return namesCopy;
+    }
+
+    /**
+     * Returns the name constraints criterion. The {@code X509Certificate}
+     * must have subject and subject alternative names that
+     * meet the specified name constraints.
+     * <p>
+     * The name constraints are returned as a byte array. This byte array
+     * contains the DER encoded form of the name constraints, as they
+     * would appear in the NameConstraints structure defined in RFC 3280
+     * and X.509. The ASN.1 notation for this structure is supplied in the
+     * documentation for
+     * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}.
+     * <p>
+     * Note that the byte array returned is cloned to protect against
+     * subsequent modifications.
+     *
+     * @return a byte array containing the ASN.1 DER encoding of
+     *         a NameConstraints extension used for checking name constraints.
+     *         {@code null} if no name constraints check will be performed.
+     * @see #setNameConstraints
+     */
+    public byte[] getNameConstraints() {
+        if (ncBytes == null) {
+            return null;
+        } else {
+            return ncBytes.clone();
+        }
+    }
+
+    /**
+     * Returns the basic constraints constraint. If the value is greater than
+     * or equal to zero, the {@code X509Certificates} must include a
+     * basicConstraints extension with a pathLen of at least this value.
+     * If the value is -2, only end-entity certificates are accepted. If
+     * the value is -1, no basicConstraints check is done.
+     *
+     * @return the value for the basic constraints constraint
+     * @see #setBasicConstraints
+     */
+    public int getBasicConstraints() {
+        return basicConstraints;
+    }
+
+    /**
+     * Returns the policy criterion. The {@code X509Certificate} must
+     * include at least one of the specified policies in its certificate policies
+     * extension. If the {@code Set} returned is empty, then the
+     * {@code X509Certificate} must include at least some specified policy
+     * in its certificate policies extension. If the {@code Set} returned is
+     * {@code null}, no policy check will be performed.
+     *
+     * @return an immutable {@code Set} of certificate policy OIDs in
+     *         string format (or {@code null})
+     * @see #setPolicy
+     */
+    public Set<String> getPolicy() {
+        return policySet;
+    }
+
+    /**
+     * Returns a copy of the pathToNames criterion. The
+     * {@code X509Certificate} must not include name constraints that would
+     * prohibit building a path to the specified names. If the value
+     * returned is {@code null}, no pathToNames check will be performed.
+     * <p>
+     * If the value returned is not {@code null}, it is a
+     * {@code Collection} with one
+     * entry for each name to be included in the pathToNames
+     * criterion. Each entry is a {@code List} whose first entry is an
+     * {@code Integer} (the name type, 0-8) and whose second
+     * entry is a {@code String} or a byte array (the name, in
+     * string or ASN.1 DER encoded form, respectively).
+     * There can be multiple names of the same type. Note that the
+     * {@code Collection} returned may contain duplicate names (same
+     * name and name type).
+     * <p>
+     * Each name in the {@code Collection}
+     * may be specified either as a {@code String} or as an ASN.1 encoded
+     * byte array. For more details about the formats used, see
+     * {@link #addPathToName(int type, String name)
+     * addPathToName(int type, String name)} and
+     * {@link #addPathToName(int type, byte [] name)
+     * addPathToName(int type, byte [] name)}.
+     * <p>
+     * Note that a deep copy is performed on the {@code Collection} to
+     * protect against subsequent modifications.
+     *
+     * @return a {@code Collection} of names (or {@code null})
+     * @see #setPathToNames
+     */
+    public Collection<List<?>> getPathToNames() {
+        if (pathToNames == null) {
+            return null;
+        }
+        return cloneNames(pathToNames);
+    }
+
+    /**
+     * Return a printable representation of the {@code CertSelector}.
+     *
+     * @return a {@code String} describing the contents of the
+     *         {@code CertSelector}
+     */
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+        sb.append("X509CertSelector: [\n");
+        if (x509Cert != null) {
+            sb.append("  Certificate: " + x509Cert.toString() + "\n");
+        }
+        if (serialNumber != null) {
+            sb.append("  Serial Number: " + serialNumber.toString() + "\n");
+        }
+        if (issuer != null) {
+            sb.append("  Issuer: " + getIssuerAsString() + "\n");
+        }
+        if (subject != null) {
+            sb.append("  Subject: " + getSubjectAsString() + "\n");
+        }
+        sb.append("  matchAllSubjectAltNames flag: "
+                  + String.valueOf(matchAllSubjectAltNames) + "\n");
+        if (subjectAlternativeNames != null) {
+            sb.append("  SubjectAlternativeNames:\n");
+            Iterator<List<?>> i = subjectAlternativeNames.iterator();
+            while (i.hasNext()) {
+                List<?> list = i.next();
+                sb.append("    type " + list.get(0) +
+                          ", name " + list.get(1) + "\n");
+            }
+        }
+        if (subjectKeyID != null) {
+            HexDumpEncoder enc = new HexDumpEncoder();
+            sb.append("  Subject Key Identifier: " +
+                      enc.encodeBuffer(subjectKeyID) + "\n");
+        }
+        if (authorityKeyID != null) {
+            HexDumpEncoder enc = new HexDumpEncoder();
+            sb.append("  Authority Key Identifier: " +
+                      enc.encodeBuffer(authorityKeyID) + "\n");
+        }
+        if (certificateValid != null) {
+            sb.append("  Certificate Valid: " +
+                      certificateValid.toString() + "\n");
+        }
+        if (privateKeyValid != null) {
+            sb.append("  Private Key Valid: " +
+                      privateKeyValid.toString() + "\n");
+        }
+        if (subjectPublicKeyAlgID != null) {
+            sb.append("  Subject Public Key AlgID: " +
+                      subjectPublicKeyAlgID.toString() + "\n");
+        }
+        if (subjectPublicKey != null) {
+            sb.append("  Subject Public Key: " +
+                      subjectPublicKey.toString() + "\n");
+        }
+        if (keyUsage != null) {
+            sb.append("  Key Usage: " + keyUsageToString(keyUsage) + "\n");
+        }
+        if (keyPurposeSet != null) {
+            sb.append("  Extended Key Usage: " +
+                      keyPurposeSet.toString() + "\n");
+        }
+        if (policy != null) {
+            sb.append("  Policy: " + policy.toString() + "\n");
+        }
+        if (pathToGeneralNames != null) {
+            sb.append("  Path to names:\n");
+            Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();
+            while (i.hasNext()) {
+                sb.append("    " + i.next() + "\n");
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    // Copied from sun.security.x509.KeyUsageExtension
+    // (without calling the superclass)
+    /**
+     * Returns a printable representation of the KeyUsage.
+     */
+    private static String keyUsageToString(boolean[] k) {
+        String s = "KeyUsage [\n";
+        try {
+            if (k[0]) {
+                s += "  DigitalSignature\n";
+            }
+            if (k[1]) {
+                s += "  Non_repudiation\n";
+            }
+            if (k[2]) {
+                s += "  Key_Encipherment\n";
+            }
+            if (k[3]) {
+                s += "  Data_Encipherment\n";
+            }
+            if (k[4]) {
+                s += "  Key_Agreement\n";
+            }
+            if (k[5]) {
+                s += "  Key_CertSign\n";
+            }
+            if (k[6]) {
+                s += "  Crl_Sign\n";
+            }
+            if (k[7]) {
+                s += "  Encipher_Only\n";
+            }
+            if (k[8]) {
+                s += "  Decipher_Only\n";
+            }
+        } catch (ArrayIndexOutOfBoundsException ex) {}
+
+        s += "]\n";
+
+        return (s);
+    }
+
+    /**
+     * Returns an Extension object given any X509Certificate and extension oid.
+     * Throw an {@code IOException} if the extension byte value is
+     * malformed.
+     *
+     * @param cert a {@code X509Certificate}
+     * @param extId an {@code integer} which specifies the extension index.
+     * Currently, the supported extensions are as follows:
+     * index 0 - PrivateKeyUsageExtension
+     * index 1 - SubjectAlternativeNameExtension
+     * index 2 - NameConstraintsExtension
+     * index 3 - CertificatePoliciesExtension
+     * index 4 - ExtendedKeyUsageExtension
+     * @return an {@code Extension} object whose real type is as specified
+     * by the extension oid.
+     * @throws IOException if cannot construct the {@code Extension}
+     * object with the extension encoding retrieved from the passed in
+     * {@code X509Certificate}.
+     */
+    private static Extension getExtensionObject(X509Certificate cert, int extId)
+            throws IOException {
+        if (cert instanceof X509CertImpl) {
+            X509CertImpl impl = (X509CertImpl)cert;
+            switch (extId) {
+            case PRIVATE_KEY_USAGE_ID:
+                return impl.getPrivateKeyUsageExtension();
+            case SUBJECT_ALT_NAME_ID:
+                return impl.getSubjectAlternativeNameExtension();
+            case NAME_CONSTRAINTS_ID:
+                return impl.getNameConstraintsExtension();
+            case CERT_POLICIES_ID:
+                return impl.getCertificatePoliciesExtension();
+            case EXTENDED_KEY_USAGE_ID:
+                return impl.getExtendedKeyUsageExtension();
+            default:
+                return null;
+            }
+        }
+        byte[] rawExtVal = cert.getExtensionValue(EXTENSION_OIDS[extId]);
+        if (rawExtVal == null) {
+            return null;
+        }
+        DerInputStream in = new DerInputStream(rawExtVal);
+        byte[] encoded = in.getOctetString();
+        switch (extId) {
+        case PRIVATE_KEY_USAGE_ID:
+            try {
+                return new PrivateKeyUsageExtension(FALSE, encoded);
+            } catch (CertificateException ex) {
+                throw new IOException(ex.getMessage());
+            }
+        case SUBJECT_ALT_NAME_ID:
+            return new SubjectAlternativeNameExtension(FALSE, encoded);
+        case NAME_CONSTRAINTS_ID:
+            return new NameConstraintsExtension(FALSE, encoded);
+        case CERT_POLICIES_ID:
+            return new CertificatePoliciesExtension(FALSE, encoded);
+        case EXTENDED_KEY_USAGE_ID:
+            return new ExtendedKeyUsageExtension(FALSE, encoded);
+        default:
+            return null;
+        }
+    }
+
+    /**
+     * Decides whether a {@code Certificate} should be selected.
+     *
+     * @param cert the {@code Certificate} to be checked
+     * @return {@code true} if the {@code Certificate} should be
+     *         selected, {@code false} otherwise
+     */
+    public boolean match(Certificate cert) {
+        if (!(cert instanceof X509Certificate)) {
+            return false;
+        }
+        X509Certificate xcert = (X509Certificate)cert;
+
+        if (debug != null) {
+            debug.println("X509CertSelector.match(SN: "
+                + (xcert.getSerialNumber()).toString(16) + "\n  Issuer: "
+                + xcert.getIssuerDN() + "\n  Subject: " + xcert.getSubjectDN()
+                + ")");
+        }
+
+        /* match on X509Certificate */
+        if (x509Cert != null) {
+            if (!x509Cert.equals(xcert)) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "certs don't match");
+                }
+                return false;
+            }
+        }
+
+        /* match on serial number */
+        if (serialNumber != null) {
+            if (!serialNumber.equals(xcert.getSerialNumber())) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "serial numbers don't match");
+                }
+                return false;
+            }
+        }
+
+        /* match on issuer name */
+        if (issuer != null) {
+            if (!issuer.equals(xcert.getIssuerX500Principal())) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "issuer DNs don't match");
+                }
+                return false;
+            }
+        }
+
+        /* match on subject name */
+        if (subject != null) {
+            if (!subject.equals(xcert.getSubjectX500Principal())) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "subject DNs don't match");
+                }
+                return false;
+            }
+        }
+
+        /* match on certificate validity range */
+        if (certificateValid != null) {
+            try {
+                xcert.checkValidity(certificateValid);
+            } catch (CertificateException e) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "certificate not within validity period");
+                }
+                return false;
+            }
+        }
+
+        /* match on subject public key */
+        if (subjectPublicKeyBytes != null) {
+            byte[] certKey = xcert.getPublicKey().getEncoded();
+            if (!Arrays.equals(subjectPublicKeyBytes, certKey)) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "subject public keys don't match");
+                }
+                return false;
+            }
+        }
+
+        boolean result = matchBasicConstraints(xcert)
+                      && matchKeyUsage(xcert)
+                      && matchExtendedKeyUsage(xcert)
+                      && matchSubjectKeyID(xcert)
+                      && matchAuthorityKeyID(xcert)
+                      && matchPrivateKeyValid(xcert)
+                      && matchSubjectPublicKeyAlgID(xcert)
+                      && matchPolicy(xcert)
+                      && matchSubjectAlternativeNames(xcert)
+                      && matchPathToNames(xcert)
+                      && matchNameConstraints(xcert);
+
+        if (result && (debug != null)) {
+            debug.println("X509CertSelector.match returning: true");
+        }
+        return result;
+    }
+
+    /* match on subject key identifier extension value */
+    private boolean matchSubjectKeyID(X509Certificate xcert) {
+        if (subjectKeyID == null) {
+            return true;
+        }
+        try {
+            byte[] extVal = xcert.getExtensionValue("2.5.29.14");
+            if (extVal == null) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "no subject key ID extension");
+                }
+                return false;
+            }
+            DerInputStream in = new DerInputStream(extVal);
+            byte[] certSubjectKeyID = in.getOctetString();
+            if (certSubjectKeyID == null ||
+                    !Arrays.equals(subjectKeyID, certSubjectKeyID)) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "subject key IDs don't match");
+                }
+                return false;
+            }
+        } catch (IOException ex) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: "
+                    + "exception in subject key ID check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on authority key identifier extension value */
+    private boolean matchAuthorityKeyID(X509Certificate xcert) {
+        if (authorityKeyID == null) {
+            return true;
+        }
+        try {
+            byte[] extVal = xcert.getExtensionValue("2.5.29.35");
+            if (extVal == null) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "no authority key ID extension");
+                }
+                return false;
+            }
+            DerInputStream in = new DerInputStream(extVal);
+            byte[] certAuthKeyID = in.getOctetString();
+            if (certAuthKeyID == null ||
+                    !Arrays.equals(authorityKeyID, certAuthKeyID)) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "authority key IDs don't match");
+                }
+                return false;
+            }
+        } catch (IOException ex) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: "
+                    + "exception in authority key ID check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on private key usage range */
+    private boolean matchPrivateKeyValid(X509Certificate xcert) {
+        if (privateKeyValid == null) {
+            return true;
+        }
+        PrivateKeyUsageExtension ext = null;
+        try {
+            ext = (PrivateKeyUsageExtension)
+                getExtensionObject(xcert, PRIVATE_KEY_USAGE_ID);
+            if (ext != null) {
+                ext.valid(privateKeyValid);
+            }
+        } catch (CertificateExpiredException e1) {
+            if (debug != null) {
+                String time = "n/a";
+                try {
+                    Date notAfter = ext.get(PrivateKeyUsageExtension.NOT_AFTER);
+                    time = notAfter.toString();
+                } catch (CertificateException ex) {
+                    // not able to retrieve notAfter value
+                }
+                debug.println("X509CertSelector.match: private key usage not "
+                    + "within validity date; ext.NOT_After: "
+                    + time + "; X509CertSelector: "
+                    + this.toString());
+                e1.printStackTrace();
+            }
+            return false;
+        } catch (CertificateNotYetValidException e2) {
+            if (debug != null) {
+                String time = "n/a";
+                try {
+                    Date notBefore = ext.get(PrivateKeyUsageExtension.NOT_BEFORE);
+                    time = notBefore.toString();
+                } catch (CertificateException ex) {
+                    // not able to retrieve notBefore value
+                }
+                debug.println("X509CertSelector.match: private key usage not "
+                    + "within validity date; ext.NOT_BEFORE: "
+                    + time + "; X509CertSelector: "
+                    + this.toString());
+                e2.printStackTrace();
+            }
+            return false;
+        } catch (IOException e4) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: IOException in "
+                    + "private key usage check; X509CertSelector: "
+                    + this.toString());
+                e4.printStackTrace();
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on subject public key algorithm OID */
+    private boolean matchSubjectPublicKeyAlgID(X509Certificate xcert) {
+        if (subjectPublicKeyAlgID == null) {
+            return true;
+        }
+        try {
+            byte[] encodedKey = xcert.getPublicKey().getEncoded();
+            DerValue val = new DerValue(encodedKey);
+            if (val.tag != DerValue.tag_Sequence) {
+                throw new IOException("invalid key format");
+            }
+
+            AlgorithmId algID = AlgorithmId.parse(val.data.getDerValue());
+            if (debug != null) {
+                debug.println("X509CertSelector.match: subjectPublicKeyAlgID = "
+                    + subjectPublicKeyAlgID + ", xcert subjectPublicKeyAlgID = "
+                    + algID.getOID());
+            }
+            if (!subjectPublicKeyAlgID.equals((Object)algID.getOID())) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "subject public key alg IDs don't match");
+                }
+                return false;
+            }
+        } catch (IOException e5) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: IOException in subject "
+                    + "public key algorithm OID check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on key usage extension value */
+    private boolean matchKeyUsage(X509Certificate xcert) {
+        if (keyUsage == null) {
+            return true;
+        }
+        boolean[] certKeyUsage = xcert.getKeyUsage();
+        if (certKeyUsage != null) {
+            for (int keyBit = 0; keyBit < keyUsage.length; keyBit++) {
+                if (keyUsage[keyBit] &&
+                    ((keyBit >= certKeyUsage.length) || !certKeyUsage[keyBit])) {
+                    if (debug != null) {
+                        debug.println("X509CertSelector.match: "
+                            + "key usage bits don't match");
+                    }
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /* match on extended key usage purpose OIDs */
+    private boolean matchExtendedKeyUsage(X509Certificate xcert) {
+        if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
+            return true;
+        }
+        try {
+            ExtendedKeyUsageExtension ext =
+                (ExtendedKeyUsageExtension)getExtensionObject(xcert,
+                                                EXTENDED_KEY_USAGE_ID);
+            if (ext != null) {
+                Vector<ObjectIdentifier> certKeyPurposeVector =
+                    ext.get(ExtendedKeyUsageExtension.USAGES);
+                if (!certKeyPurposeVector.contains(ANY_EXTENDED_KEY_USAGE)
+                        && !certKeyPurposeVector.containsAll(keyPurposeOIDSet)) {
+                    if (debug != null) {
+                        debug.println("X509CertSelector.match: cert failed "
+                            + "extendedKeyUsage criterion");
+                    }
+                    return false;
+                }
+            }
+        } catch (IOException ex) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: "
+                    + "IOException in extended key usage check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on subject alternative name extension names */
+    private boolean matchSubjectAlternativeNames(X509Certificate xcert) {
+        if ((subjectAlternativeNames == null) || subjectAlternativeNames.isEmpty()) {
+            return true;
+        }
+        try {
+            SubjectAlternativeNameExtension sanExt =
+                (SubjectAlternativeNameExtension) getExtensionObject(xcert,
+                                                      SUBJECT_ALT_NAME_ID);
+            if (sanExt == null) {
+                if (debug != null) {
+                  debug.println("X509CertSelector.match: "
+                      + "no subject alternative name extension");
+                }
+                return false;
+            }
+            GeneralNames certNames =
+                    sanExt.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
+            Iterator<GeneralNameInterface> i =
+                                subjectAlternativeGeneralNames.iterator();
+            while (i.hasNext()) {
+                GeneralNameInterface matchName = i.next();
+                boolean found = false;
+                for (Iterator<GeneralName> t = certNames.iterator();
+                                                t.hasNext() && !found; ) {
+                    GeneralNameInterface certName = (t.next()).getName();
+                    found = certName.equals(matchName);
+                }
+                if (!found && (matchAllSubjectAltNames || !i.hasNext())) {
+                    if (debug != null) {
+                      debug.println("X509CertSelector.match: subject alternative "
+                          + "name " + matchName + " not found");
+                    }
+                    return false;
+                } else if (found && !matchAllSubjectAltNames) {
+                    break;
+                }
+            }
+        } catch (IOException ex) {
+            if (debug != null)
+                debug.println("X509CertSelector.match: IOException in subject "
+                    + "alternative name check");
+            return false;
+        }
+        return true;
+    }
+
+    /* match on name constraints */
+    private boolean matchNameConstraints(X509Certificate xcert) {
+        if (nc == null) {
+            return true;
+        }
+        try {
+            if (!nc.verify(xcert)) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: "
+                        + "name constraints not satisfied");
+                }
+                return false;
+            }
+        } catch (IOException e) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: "
+                    + "IOException in name constraints check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on policy OIDs */
+    private boolean matchPolicy(X509Certificate xcert) {
+        if (policy == null) {
+            return true;
+        }
+        try {
+            CertificatePoliciesExtension ext = (CertificatePoliciesExtension)
+                getExtensionObject(xcert, CERT_POLICIES_ID);
+            if (ext == null) {
+                if (debug != null) {
+                  debug.println("X509CertSelector.match: "
+                      + "no certificate policy extension");
+                }
+                return false;
+            }
+            List<PolicyInformation> policies = ext.get(CertificatePoliciesExtension.POLICIES);
+            /*
+             * Convert the Vector of PolicyInformation to a Vector
+             * of CertificatePolicyIds for easier comparison.
+             */
+            List<CertificatePolicyId> policyIDs = new ArrayList<CertificatePolicyId>(policies.size());
+            for (PolicyInformation info : policies) {
+                policyIDs.add(info.getPolicyIdentifier());
+            }
+            if (policy != null) {
+                boolean foundOne = false;
+                /*
+                 * if the user passes in an empty policy Set, then
+                 * we just want to make sure that the candidate certificate
+                 * has some policy OID in its CertPoliciesExtension
+                 */
+                if (policy.getCertPolicyIds().isEmpty()) {
+                    if (policyIDs.isEmpty()) {
+                        if (debug != null) {
+                            debug.println("X509CertSelector.match: "
+                                + "cert failed policyAny criterion");
+                        }
+                        return false;
+                    }
+                } else {
+                    for (CertificatePolicyId id : policy.getCertPolicyIds()) {
+                        if (policyIDs.contains(id)) {
+                            foundOne = true;
+                            break;
+                        }
+                    }
+                    if (!foundOne) {
+                        if (debug != null) {
+                            debug.println("X509CertSelector.match: "
+                                + "cert failed policyAny criterion");
+                        }
+                        return false;
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: "
+                    + "IOException in certificate policy ID check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /* match on pathToNames */
+    private boolean matchPathToNames(X509Certificate xcert) {
+        if (pathToGeneralNames == null) {
+            return true;
+        }
+        try {
+            NameConstraintsExtension ext = (NameConstraintsExtension)
+                getExtensionObject(xcert, NAME_CONSTRAINTS_ID);
+            if (ext == null) {
+                return true;
+            }
+            if ((debug != null) && Debug.isOn("certpath")) {
+                debug.println("X509CertSelector.match pathToNames:\n");
+                Iterator<GeneralNameInterface> i =
+                                        pathToGeneralNames.iterator();
+                while (i.hasNext()) {
+                    debug.println("    " + i.next() + "\n");
+                }
+            }
+
+            GeneralSubtrees permitted =
+                    ext.get(NameConstraintsExtension.PERMITTED_SUBTREES);
+            GeneralSubtrees excluded =
+                    ext.get(NameConstraintsExtension.EXCLUDED_SUBTREES);
+            if (excluded != null) {
+                if (matchExcluded(excluded) == false) {
+                    return false;
+                }
+            }
+            if (permitted != null) {
+                if (matchPermitted(permitted) == false) {
+                    return false;
+                }
+            }
+        } catch (IOException ex) {
+            if (debug != null) {
+                debug.println("X509CertSelector.match: "
+                    + "IOException in name constraints check");
+            }
+            return false;
+        }
+        return true;
+    }
+
+    private boolean matchExcluded(GeneralSubtrees excluded) {
+        /*
+         * Enumerate through excluded and compare each entry
+         * to all pathToNames. If any pathToName is within any of the
+         * subtrees listed in excluded, return false.
+         */
+        for (Iterator<GeneralSubtree> t = excluded.iterator(); t.hasNext(); ) {
+            GeneralSubtree tree = t.next();
+            GeneralNameInterface excludedName = tree.getName().getName();
+            Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();
+            while (i.hasNext()) {
+                GeneralNameInterface pathToName = i.next();
+                if (excludedName.getType() == pathToName.getType()) {
+                    switch (pathToName.constrains(excludedName)) {
+                    case GeneralNameInterface.NAME_WIDENS:
+                    case GeneralNameInterface.NAME_MATCH:
+                        if (debug != null) {
+                            debug.println("X509CertSelector.match: name constraints "
+                                + "inhibit path to specified name");
+                            debug.println("X509CertSelector.match: excluded name: " +
+                                pathToName);
+                        }
+                        return false;
+                    default:
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean matchPermitted(GeneralSubtrees permitted) {
+        /*
+         * Enumerate through pathToNames, checking that each pathToName
+         * is in at least one of the subtrees listed in permitted.
+         * If not, return false. However, if no subtrees of a given type
+         * are listed, all names of that type are permitted.
+         */
+        Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();
+        while (i.hasNext()) {
+            GeneralNameInterface pathToName = i.next();
+            Iterator<GeneralSubtree> t = permitted.iterator();
+            boolean permittedNameFound = false;
+            boolean nameTypeFound = false;
+            String names = "";
+            while (t.hasNext() && !permittedNameFound) {
+                GeneralSubtree tree = t.next();
+                GeneralNameInterface permittedName = tree.getName().getName();
+                if (permittedName.getType() == pathToName.getType()) {
+                    nameTypeFound = true;
+                    names = names + "  " + permittedName;
+                    switch (pathToName.constrains(permittedName)) {
+                    case GeneralNameInterface.NAME_WIDENS:
+                    case GeneralNameInterface.NAME_MATCH:
+                        permittedNameFound = true;
+                        break;
+                    default:
+                    }
+                }
+            }
+            if (!permittedNameFound && nameTypeFound) {
+                if (debug != null)
+                  debug.println("X509CertSelector.match: " +
+                            "name constraints inhibit path to specified name; " +
+                            "permitted names of type " + pathToName.getType() +
+                            ": " + names);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /* match on basic constraints */
+    private boolean matchBasicConstraints(X509Certificate xcert) {
+        if (basicConstraints == -1) {
+            return true;
+        }
+        int maxPathLen = xcert.getBasicConstraints();
+        if (basicConstraints == -2) {
+            if (maxPathLen != -1) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: not an EE cert");
+                }
+                return false;
+            }
+        } else {
+            if (maxPathLen < basicConstraints) {
+                if (debug != null) {
+                    debug.println("X509CertSelector.match: cert's maxPathLen " +
+                            "is less than the min maxPathLen set by " +
+                            "basicConstraints. " +
+                            "(" + maxPathLen + " < " + basicConstraints + ")");
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
+    private static <T> Set<T> cloneSet(Set<T> set) {
+        if (set instanceof HashSet) {
+            Object clone = ((HashSet<T>)set).clone();
+            return (Set<T>)clone;
+        } else {
+            return new HashSet<T>(set);
+        }
+    }
+
+    /**
+     * Returns a copy of this object.
+     *
+     * @return the copy
+     */
+    public Object clone() {
+        try {
+            X509CertSelector copy = (X509CertSelector)super.clone();
+            // Must clone these because addPathToName et al. modify them
+            if (subjectAlternativeNames != null) {
+                copy.subjectAlternativeNames =
+                        cloneSet(subjectAlternativeNames);
+                copy.subjectAlternativeGeneralNames =
+                        cloneSet(subjectAlternativeGeneralNames);
+            }
+            if (pathToGeneralNames != null) {
+                copy.pathToNames = cloneSet(pathToNames);
+                copy.pathToGeneralNames = cloneSet(pathToGeneralNames);
+            }
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            /* Cannot happen */
+            throw new InternalError(e.toString(), e);
+        }
+    }
+}
diff --git a/java/security/cert/X509Certificate.java b/java/security/cert/X509Certificate.java
new file mode 100644
index 0000000..f7cb9ef
--- /dev/null
+++ b/java/security/cert/X509Certificate.java
@@ -0,0 +1,685 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.math.BigInteger;
+import java.security.*;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.x509.X509CertImpl;
+
+/**
+ * <p>
+ * Abstract class for X.509 certificates. This provides a standard
+ * way to access all the attributes of an X.509 certificate.
+ * <p>
+ * In June of 1996, the basic X.509 v3 format was completed by
+ * ISO/IEC and ANSI X9, which is described below in ASN.1:
+ * <pre>
+ * Certificate  ::=  SEQUENCE  {
+ *     tbsCertificate       TBSCertificate,
+ *     signatureAlgorithm   AlgorithmIdentifier,
+ *     signature            BIT STRING  }
+ * </pre>
+ * <p>
+ * These certificates are widely used to support authentication and
+ * other functionality in Internet security systems. Common applications
+ * include Privacy Enhanced Mail (PEM), Transport Layer Security (SSL),
+ * code signing for trusted software distribution, and Secure Electronic
+ * Transactions (SET).
+ * <p>
+ * These certificates are managed and vouched for by <em>Certificate
+ * Authorities</em> (CAs). CAs are services which create certificates by
+ * placing data in the X.509 standard format and then digitally signing
+ * that data. CAs act as trusted third parties, making introductions
+ * between principals who have no direct knowledge of each other.
+ * CA certificates are either signed by themselves, or by some other
+ * CA such as a "root" CA.
+ * <p>
+ * More information can be found in
+ * <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
+ * Public Key Infrastructure Certificate and CRL Profile</a>.
+ * <p>
+ * The ASN.1 definition of {@code tbsCertificate} is:
+ * <pre>
+ * TBSCertificate  ::=  SEQUENCE  {
+ *     version         [0]  EXPLICIT Version DEFAULT v1,
+ *     serialNumber         CertificateSerialNumber,
+ *     signature            AlgorithmIdentifier,
+ *     issuer               Name,
+ *     validity             Validity,
+ *     subject              Name,
+ *     subjectPublicKeyInfo SubjectPublicKeyInfo,
+ *     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+ *                          -- If present, version must be v2 or v3
+ *     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+ *                          -- If present, version must be v2 or v3
+ *     extensions      [3]  EXPLICIT Extensions OPTIONAL
+ *                          -- If present, version must be v3
+ *     }
+ * </pre>
+ * <p>
+ * Certificates are instantiated using a certificate factory. The following is
+ * an example of how to instantiate an X.509 certificate:
+ * <pre>
+ * try (InputStream inStream = new FileInputStream("fileName-of-cert")) {
+ *     CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ *     X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);
+ * }
+ * </pre>
+ *
+ * @author Hemma Prafullchandra
+ *
+ *
+ * @see Certificate
+ * @see CertificateFactory
+ * @see X509Extension
+ */
+
+public abstract class X509Certificate extends Certificate
+implements X509Extension {
+
+    private static final long serialVersionUID = -2491127588187038216L;
+
+    private transient X500Principal subjectX500Principal, issuerX500Principal;
+
+    /**
+     * Constructor for X.509 certificates.
+     */
+    protected X509Certificate() {
+        super("X.509");
+    }
+
+    /**
+     * Checks that the certificate is currently valid. It is if
+     * the current date and time are within the validity period given in the
+     * certificate.
+     * <p>
+     * The validity period consists of two date/time values:
+     * the first and last dates (and times) on which the certificate
+     * is valid. It is defined in
+     * ASN.1 as:
+     * <pre>
+     * validity             Validity
+     *
+     * Validity ::= SEQUENCE {
+     *     notBefore      CertificateValidityDate,
+     *     notAfter       CertificateValidityDate }
+     *
+     * CertificateValidityDate ::= CHOICE {
+     *     utcTime        UTCTime,
+     *     generalTime    GeneralizedTime }
+     * </pre>
+     *
+     * @exception CertificateExpiredException if the certificate has expired.
+     * @exception CertificateNotYetValidException if the certificate is not
+     * yet valid.
+     */
+    public abstract void checkValidity()
+        throws CertificateExpiredException, CertificateNotYetValidException;
+
+    /**
+     * Checks that the given date is within the certificate's
+     * validity period. In other words, this determines whether the
+     * certificate would be valid at the given date/time.
+     *
+     * @param date the Date to check against to see if this certificate
+     *        is valid at that date/time.
+     *
+     * @exception CertificateExpiredException if the certificate has expired
+     * with respect to the {@code date} supplied.
+     * @exception CertificateNotYetValidException if the certificate is not
+     * yet valid with respect to the {@code date} supplied.
+     *
+     * @see #checkValidity()
+     */
+    public abstract void checkValidity(Date date)
+        throws CertificateExpiredException, CertificateNotYetValidException;
+
+    /**
+     * Gets the {@code version} (version number) value from the
+     * certificate.
+     * The ASN.1 definition for this is:
+     * <pre>
+     * version  [0] EXPLICIT Version DEFAULT v1
+     *
+     * Version ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+     * </pre>
+     * @return the version number, i.e. 1, 2 or 3.
+     */
+    public abstract int getVersion();
+
+    /**
+     * Gets the {@code serialNumber} value from the certificate.
+     * The serial number is an integer assigned by the certification
+     * authority to each certificate. It must be unique for each
+     * certificate issued by a given CA (i.e., the issuer name and
+     * serial number identify a unique certificate).
+     * The ASN.1 definition for this is:
+     * <pre>
+     * serialNumber     CertificateSerialNumber
+     *
+     * CertificateSerialNumber  ::=  INTEGER
+     * </pre>
+     *
+     * @return the serial number.
+     */
+    public abstract BigInteger getSerialNumber();
+
+    /**
+     * <strong>Denigrated</strong>, replaced by {@linkplain
+     * #getIssuerX500Principal()}. This method returns the {@code issuer}
+     * as an implementation specific Principal object, which should not be
+     * relied upon by portable code.
+     *
+     * <p>
+     * Gets the {@code issuer} (issuer distinguished name) value from
+     * the certificate. The issuer name identifies the entity that signed (and
+     * issued) the certificate.
+     *
+     * <p>The issuer name field contains an
+     * X.500 distinguished name (DN).
+     * The ASN.1 definition for this is:
+     * <pre>
+     * issuer    Name
+     *
+     * Name ::= CHOICE { RDNSequence }
+     * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+     * RelativeDistinguishedName ::=
+     *     SET OF AttributeValueAssertion
+     *
+     * AttributeValueAssertion ::= SEQUENCE {
+     *                               AttributeType,
+     *                               AttributeValue }
+     * AttributeType ::= OBJECT IDENTIFIER
+     * AttributeValue ::= ANY
+     * </pre>
+     * The {@code Name} describes a hierarchical name composed of
+     * attributes,
+     * such as country name, and corresponding values, such as US.
+     * The type of the {@code AttributeValue} component is determined by
+     * the {@code AttributeType}; in general it will be a
+     * {@code directoryString}. A {@code directoryString} is usually
+     * one of {@code PrintableString},
+     * {@code TeletexString} or {@code UniversalString}.
+     *
+     * @return a Principal whose name is the issuer distinguished name.
+     */
+    public abstract Principal getIssuerDN();
+
+    /**
+     * Returns the issuer (issuer distinguished name) value from the
+     * certificate as an {@code X500Principal}.
+     * <p>
+     * It is recommended that subclasses override this method.
+     *
+     * @return an {@code X500Principal} representing the issuer
+     *          distinguished name
+     * @since 1.4
+     */
+    public X500Principal getIssuerX500Principal() {
+        if (issuerX500Principal == null) {
+            issuerX500Principal = X509CertImpl.getIssuerX500Principal(this);
+        }
+        return issuerX500Principal;
+    }
+
+    /**
+     * <strong>Denigrated</strong>, replaced by {@linkplain
+     * #getSubjectX500Principal()}. This method returns the {@code subject}
+     * as an implementation specific Principal object, which should not be
+     * relied upon by portable code.
+     *
+     * <p>
+     * Gets the {@code subject} (subject distinguished name) value
+     * from the certificate.  If the {@code subject} value is empty,
+     * then the {@code getName()} method of the returned
+     * {@code Principal} object returns an empty string ("").
+     *
+     * <p> The ASN.1 definition for this is:
+     * <pre>
+     * subject    Name
+     * </pre>
+     *
+     * <p>See {@link #getIssuerDN() getIssuerDN} for {@code Name}
+     * and other relevant definitions.
+     *
+     * @return a Principal whose name is the subject name.
+     */
+    public abstract Principal getSubjectDN();
+
+    /**
+     * Returns the subject (subject distinguished name) value from the
+     * certificate as an {@code X500Principal}.  If the subject value
+     * is empty, then the {@code getName()} method of the returned
+     * {@code X500Principal} object returns an empty string ("").
+     * <p>
+     * It is recommended that subclasses override this method.
+     *
+     * @return an {@code X500Principal} representing the subject
+     *          distinguished name
+     * @since 1.4
+     */
+    public X500Principal getSubjectX500Principal() {
+        if (subjectX500Principal == null) {
+            subjectX500Principal = X509CertImpl.getSubjectX500Principal(this);
+        }
+        return subjectX500Principal;
+    }
+
+    /**
+     * Gets the {@code notBefore} date from the validity period of
+     * the certificate.
+     * The relevant ASN.1 definitions are:
+     * <pre>
+     * validity             Validity
+     *
+     * Validity ::= SEQUENCE {
+     *     notBefore      CertificateValidityDate,
+     *     notAfter       CertificateValidityDate }
+     *
+     * CertificateValidityDate ::= CHOICE {
+     *     utcTime        UTCTime,
+     *     generalTime    GeneralizedTime }
+     * </pre>
+     *
+     * @return the start date of the validity period.
+     * @see #checkValidity
+     */
+    public abstract Date getNotBefore();
+
+    /**
+     * Gets the {@code notAfter} date from the validity period of
+     * the certificate. See {@link #getNotBefore() getNotBefore}
+     * for relevant ASN.1 definitions.
+     *
+     * @return the end date of the validity period.
+     * @see #checkValidity
+     */
+    public abstract Date getNotAfter();
+
+    /**
+     * Gets the DER-encoded certificate information, the
+     * {@code tbsCertificate} from this certificate.
+     * This can be used to verify the signature independently.
+     *
+     * @return the DER-encoded certificate information.
+     * @exception CertificateEncodingException if an encoding error occurs.
+     */
+    public abstract byte[] getTBSCertificate()
+        throws CertificateEncodingException;
+
+    /**
+     * Gets the {@code signature} value (the raw signature bits) from
+     * the certificate.
+     * The ASN.1 definition for this is:
+     * <pre>
+     * signature     BIT STRING
+     * </pre>
+     *
+     * @return the signature.
+     */
+    public abstract byte[] getSignature();
+
+    /**
+     * Gets the signature algorithm name for the certificate
+     * signature algorithm. An example is the string "SHA256withRSA".
+     * The ASN.1 definition for this is:
+     * <pre>
+     * signatureAlgorithm   AlgorithmIdentifier
+     *
+     * AlgorithmIdentifier  ::=  SEQUENCE  {
+     *     algorithm               OBJECT IDENTIFIER,
+     *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
+     *                             -- contains a value of the type
+     *                             -- registered for use with the
+     *                             -- algorithm object identifier value
+     * </pre>
+     *
+     * <p>The algorithm name is determined from the {@code algorithm}
+     * OID string.
+     *
+     * @return the signature algorithm name.
+     */
+    public abstract String getSigAlgName();
+
+    /**
+     * Gets the signature algorithm OID string from the certificate.
+     * An OID is represented by a set of nonnegative whole numbers separated
+     * by periods.
+     * For example, the string "1.2.840.10040.4.3" identifies the SHA-1
+     * with DSA signature algorithm defined in
+     * <a href="http://www.ietf.org/rfc/rfc3279.txt">RFC 3279: Algorithms and
+     * Identifiers for the Internet X.509 Public Key Infrastructure Certificate
+     * and CRL Profile</a>.
+     *
+     * <p>See {@link #getSigAlgName() getSigAlgName} for
+     * relevant ASN.1 definitions.
+     *
+     * @return the signature algorithm OID string.
+     */
+    public abstract String getSigAlgOID();
+
+    /**
+     * Gets the DER-encoded signature algorithm parameters from this
+     * certificate's signature algorithm. In most cases, the signature
+     * algorithm parameters are null; the parameters are usually
+     * supplied with the certificate's public key.
+     * If access to individual parameter values is needed then use
+     * {@link java.security.AlgorithmParameters AlgorithmParameters}
+     * and instantiate with the name returned by
+     * {@link #getSigAlgName() getSigAlgName}.
+     *
+     * <p>See {@link #getSigAlgName() getSigAlgName} for
+     * relevant ASN.1 definitions.
+     *
+     * @return the DER-encoded signature algorithm parameters, or
+     *         null if no parameters are present.
+     */
+    public abstract byte[] getSigAlgParams();
+
+    /**
+     * Gets the {@code issuerUniqueID} value from the certificate.
+     * The issuer unique identifier is present in the certificate
+     * to handle the possibility of reuse of issuer names over time.
+     * RFC 3280 recommends that names not be reused and that
+     * conforming certificates not make use of unique identifiers.
+     * Applications conforming to that profile should be capable of
+     * parsing unique identifiers and making comparisons.
+     *
+     * <p>The ASN.1 definition for this is:
+     * <pre>
+     * issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL
+     *
+     * UniqueIdentifier  ::=  BIT STRING
+     * </pre>
+     *
+     * @return the issuer unique identifier or null if it is not
+     * present in the certificate.
+     */
+    public abstract boolean[] getIssuerUniqueID();
+
+    /**
+     * Gets the {@code subjectUniqueID} value from the certificate.
+     *
+     * <p>The ASN.1 definition for this is:
+     * <pre>
+     * subjectUniqueID  [2]  IMPLICIT UniqueIdentifier OPTIONAL
+     *
+     * UniqueIdentifier  ::=  BIT STRING
+     * </pre>
+     *
+     * @return the subject unique identifier or null if it is not
+     * present in the certificate.
+     */
+    public abstract boolean[] getSubjectUniqueID();
+
+    /**
+     * Gets a boolean array representing bits of
+     * the {@code KeyUsage} extension, (OID = 2.5.29.15).
+     * The key usage extension defines the purpose (e.g., encipherment,
+     * signature, certificate signing) of the key contained in the
+     * certificate.
+     * The ASN.1 definition for this is:
+     * <pre>
+     * KeyUsage ::= BIT STRING {
+     *     digitalSignature        (0),
+     *     nonRepudiation          (1),
+     *     keyEncipherment         (2),
+     *     dataEncipherment        (3),
+     *     keyAgreement            (4),
+     *     keyCertSign             (5),
+     *     cRLSign                 (6),
+     *     encipherOnly            (7),
+     *     decipherOnly            (8) }
+     * </pre>
+     * RFC 3280 recommends that when used, this be marked
+     * as a critical extension.
+     *
+     * @return the KeyUsage extension of this certificate, represented as
+     * an array of booleans. The order of KeyUsage values in the array is
+     * the same as in the above ASN.1 definition. The array will contain a
+     * value for each KeyUsage defined above. If the KeyUsage list encoded
+     * in the certificate is longer than the above list, it will not be
+     * truncated. Returns null if this certificate does not
+     * contain a KeyUsage extension.
+     */
+    public abstract boolean[] getKeyUsage();
+
+    /**
+     * Gets an unmodifiable list of Strings representing the OBJECT
+     * IDENTIFIERs of the {@code ExtKeyUsageSyntax} field of the
+     * extended key usage extension, (OID = 2.5.29.37).  It indicates
+     * one or more purposes for which the certified public key may be
+     * used, in addition to or in place of the basic purposes
+     * indicated in the key usage extension field.  The ASN.1
+     * definition for this is:
+     * <pre>
+     * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+     *
+     * KeyPurposeId ::= OBJECT IDENTIFIER
+     * </pre>
+     *
+     * Key purposes may be defined by any organization with a
+     * need. Object identifiers used to identify key purposes shall be
+     * assigned in accordance with IANA or ITU-T Rec. X.660 |
+     * ISO/IEC/ITU 9834-1.
+     * <p>
+     * This method was added to version 1.4 of the Java 2 Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method is not {@code abstract}
+     * and it provides a default implementation. Subclasses
+     * should override this method with a correct implementation.
+     *
+     * @return the ExtendedKeyUsage extension of this certificate,
+     *         as an unmodifiable list of object identifiers represented
+     *         as Strings. Returns null if this certificate does not
+     *         contain an ExtendedKeyUsage extension.
+     * @throws CertificateParsingException if the extension cannot be decoded
+     * @since 1.4
+     */
+    public List<String> getExtendedKeyUsage() throws CertificateParsingException {
+        return X509CertImpl.getExtendedKeyUsage(this);
+    }
+
+    /**
+     * Gets the certificate constraints path length from the
+     * critical {@code BasicConstraints} extension, (OID = 2.5.29.19).
+     * <p>
+     * The basic constraints extension identifies whether the subject
+     * of the certificate is a Certificate Authority (CA) and
+     * how deep a certification path may exist through that CA. The
+     * {@code pathLenConstraint} field (see below) is meaningful
+     * only if {@code cA} is set to TRUE. In this case, it gives the
+     * maximum number of CA certificates that may follow this certificate in a
+     * certification path. A value of zero indicates that only an end-entity
+     * certificate may follow in the path.
+     * <p>
+     * The ASN.1 definition for this is:
+     * <pre>
+     * BasicConstraints ::= SEQUENCE {
+     *     cA                  BOOLEAN DEFAULT FALSE,
+     *     pathLenConstraint   INTEGER (0..MAX) OPTIONAL }
+     * </pre>
+     *
+     * @return the value of {@code pathLenConstraint} if the
+     * BasicConstraints extension is present in the certificate and the
+     * subject of the certificate is a CA, otherwise -1.
+     * If the subject of the certificate is a CA and
+     * {@code pathLenConstraint} does not appear,
+     * {@code Integer.MAX_VALUE} is returned to indicate that there is no
+     * limit to the allowed length of the certification path.
+     */
+    public abstract int getBasicConstraints();
+
+    /**
+     * Gets an immutable collection of subject alternative names from the
+     * {@code SubjectAltName} extension, (OID = 2.5.29.17).
+     * <p>
+     * The ASN.1 definition of the {@code SubjectAltName} extension is:
+     * <pre>
+     * SubjectAltName ::= GeneralNames
+     *
+     * GeneralNames :: = SEQUENCE SIZE (1..MAX) OF GeneralName
+     *
+     * GeneralName ::= CHOICE {
+     *      otherName                       [0]     OtherName,
+     *      rfc822Name                      [1]     IA5String,
+     *      dNSName                         [2]     IA5String,
+     *      x400Address                     [3]     ORAddress,
+     *      directoryName                   [4]     Name,
+     *      ediPartyName                    [5]     EDIPartyName,
+     *      uniformResourceIdentifier       [6]     IA5String,
+     *      iPAddress                       [7]     OCTET STRING,
+     *      registeredID                    [8]     OBJECT IDENTIFIER}
+     * </pre>
+     * <p>
+     * If this certificate does not contain a {@code SubjectAltName}
+     * extension, {@code null} is returned. Otherwise, a
+     * {@code Collection} is returned with an entry representing each
+     * {@code GeneralName} included in the extension. Each entry is a
+     * {@code List} whose first entry is an {@code Integer}
+     * (the name type, 0-8) and whose second entry is a {@code String}
+     * or a byte array (the name, in string or ASN.1 DER encoded form,
+     * respectively).
+     * <p>
+     * <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a>, DNS, and URI
+     * names are returned as {@code String}s,
+     * using the well-established string formats for those types (subject to
+     * the restrictions included in RFC 3280). IPv4 address names are
+     * returned using dotted quad notation. IPv6 address names are returned
+     * in the form "a1:a2:...:a8", where a1-a8 are hexadecimal values
+     * representing the eight 16-bit pieces of the address. OID names are
+     * returned as {@code String}s represented as a series of nonnegative
+     * integers separated by periods. And directory names (distinguished names)
+     * are returned in <a href="http://www.ietf.org/rfc/rfc2253.txt">
+     * RFC 2253</a> string format. No standard string format is
+     * defined for otherNames, X.400 names, EDI party names, or any
+     * other type of names. They are returned as byte arrays
+     * containing the ASN.1 DER encoded form of the name.
+     * <p>
+     * Note that the {@code Collection} returned may contain more
+     * than one name of the same type. Also, note that the returned
+     * {@code Collection} is immutable and any entries containing byte
+     * arrays are cloned to protect against subsequent modifications.
+     * <p>
+     * This method was added to version 1.4 of the Java 2 Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method is not {@code abstract}
+     * and it provides a default implementation. Subclasses
+     * should override this method with a correct implementation.
+     *
+     * @return an immutable {@code Collection} of subject alternative
+     * names (or {@code null})
+     * @throws CertificateParsingException if the extension cannot be decoded
+     * @since 1.4
+     */
+    public Collection<List<?>> getSubjectAlternativeNames()
+        throws CertificateParsingException {
+        return X509CertImpl.getSubjectAlternativeNames(this);
+    }
+
+    /**
+     * Gets an immutable collection of issuer alternative names from the
+     * {@code IssuerAltName} extension, (OID = 2.5.29.18).
+     * <p>
+     * The ASN.1 definition of the {@code IssuerAltName} extension is:
+     * <pre>
+     * IssuerAltName ::= GeneralNames
+     * </pre>
+     * The ASN.1 definition of {@code GeneralNames} is defined
+     * in {@link #getSubjectAlternativeNames getSubjectAlternativeNames}.
+     * <p>
+     * If this certificate does not contain an {@code IssuerAltName}
+     * extension, {@code null} is returned. Otherwise, a
+     * {@code Collection} is returned with an entry representing each
+     * {@code GeneralName} included in the extension. Each entry is a
+     * {@code List} whose first entry is an {@code Integer}
+     * (the name type, 0-8) and whose second entry is a {@code String}
+     * or a byte array (the name, in string or ASN.1 DER encoded form,
+     * respectively). For more details about the formats used for each
+     * name type, see the {@code getSubjectAlternativeNames} method.
+     * <p>
+     * Note that the {@code Collection} returned may contain more
+     * than one name of the same type. Also, note that the returned
+     * {@code Collection} is immutable and any entries containing byte
+     * arrays are cloned to protect against subsequent modifications.
+     * <p>
+     * This method was added to version 1.4 of the Java 2 Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method is not {@code abstract}
+     * and it provides a default implementation. Subclasses
+     * should override this method with a correct implementation.
+     *
+     * @return an immutable {@code Collection} of issuer alternative
+     * names (or {@code null})
+     * @throws CertificateParsingException if the extension cannot be decoded
+     * @since 1.4
+     */
+    public Collection<List<?>> getIssuerAlternativeNames()
+        throws CertificateParsingException {
+        return X509CertImpl.getIssuerAlternativeNames(this);
+    }
+
+     /**
+     * Verifies that this certificate was signed using the
+     * private key that corresponds to the specified public key.
+     * This method uses the signature verification engine
+     * supplied by the specified provider. Note that the specified
+     * Provider object does not have to be registered in the provider list.
+     *
+     * This method was added to version 1.8 of the Java Platform Standard
+     * Edition. In order to maintain backwards compatibility with existing
+     * service providers, this method is not {@code abstract}
+     * and it provides a default implementation.
+     *
+     * @param key the PublicKey used to carry out the verification.
+     * @param sigProvider the signature provider.
+     *
+     * @exception NoSuchAlgorithmException on unsupported signature
+     * algorithms.
+     * @exception InvalidKeyException on incorrect key.
+     * @exception SignatureException on signature errors.
+     * @exception CertificateException on encoding errors.
+     * @exception UnsupportedOperationException if the method is not supported
+     * @since 1.8
+     */
+    public void verify(PublicKey key, Provider sigProvider)
+        throws CertificateException, NoSuchAlgorithmException,
+        InvalidKeyException, SignatureException {
+        // Android-changed: Eliminate infinite recursion in default implementation.
+        // The method X509CertImpl calls this method, thus entering an
+        // infinite recursive loop. This strange behaviour was checked to be not
+        // specific to libcore by running a test with vogar --mode=jvm.
+        // This is fixed upstream in OpenJDK 10.
+        //
+        // X509CertImpl.verify(this, key, sigProvider);
+        super.verify(key, sigProvider);
+    }
+}
diff --git a/java/security/cert/X509Extension.java b/java/security/cert/X509Extension.java
new file mode 100644
index 0000000..0346960
--- /dev/null
+++ b/java/security/cert/X509Extension.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.cert;
+
+import java.util.Set;
+
+/**
+ * Interface for an X.509 extension.
+ *
+ * <p>The extensions defined for X.509 v3
+ * {@link X509Certificate Certificates} and v2
+ * {@link X509CRL CRLs} (Certificate Revocation
+ * Lists) provide methods
+ * for associating additional attributes with users or public keys,
+ * for managing the certification hierarchy, and for managing CRL
+ * distribution. The X.509 extensions format also allows communities
+ * to define private extensions to carry information unique to those
+ * communities.
+ *
+ * <p>Each extension in a certificate/CRL may be designated as
+ * critical or non-critical.  A certificate/CRL-using system (an application
+ * validating a certificate/CRL) must reject the certificate/CRL if it
+ * encounters a critical extension it does not recognize.  A non-critical
+ * extension may be ignored if it is not recognized.
+ * <p>
+ * The ASN.1 definition for this is:
+ * <pre>
+ * Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension  ::=  SEQUENCE  {
+ *     extnId        OBJECT IDENTIFIER,
+ *     critical      BOOLEAN DEFAULT FALSE,
+ *     extnValue     OCTET STRING
+ *                   -- contains a DER encoding of a value
+ *                   -- of the type registered for use with
+ *                   -- the extnId object identifier value
+ * }
+ * </pre>
+ * Since not all extensions are known, the {@code getExtensionValue}
+ * method returns the DER-encoded OCTET STRING of the
+ * extension value (i.e., the {@code extnValue}). This can then
+ * be handled by a <em>Class</em> that understands the extension.
+ *
+ * @author Hemma Prafullchandra
+ */
+
+public interface X509Extension {
+
+    /**
+     * Check if there is a critical extension that is not supported.
+     *
+     * @return {@code true} if a critical extension is found that is
+     * not supported, otherwise {@code false}.
+     */
+    public boolean hasUnsupportedCriticalExtension();
+
+    /**
+     * Gets a Set of the OID strings for the extension(s) marked
+     * CRITICAL in the certificate/CRL managed by the object
+     * implementing this interface.
+     *
+     * Here is sample code to get a Set of critical extensions from an
+     * X509Certificate and print the OIDs:
+     * <pre>{@code
+     * X509Certificate cert = null;
+     * try (InputStream inStrm = new FileInputStream("DER-encoded-Cert")) {
+     *     CertificateFactory cf = CertificateFactory.getInstance("X.509");
+     *     cert = (X509Certificate)cf.generateCertificate(inStrm);
+     * }
+     *
+     * Set<String> critSet = cert.getCriticalExtensionOIDs();
+     * if (critSet != null && !critSet.isEmpty()) {
+     *     System.out.println("Set of critical extensions:");
+     *     for (String oid : critSet) {
+     *         System.out.println(oid);
+     *     }
+     * }
+     * }</pre>
+     * @return a Set (or an empty Set if none are marked critical) of
+     * the extension OID strings for extensions that are marked critical.
+     * If there are no extensions present at all, then this method returns
+     * null.
+     */
+    public Set<String> getCriticalExtensionOIDs();
+
+    /**
+     * Gets a Set of the OID strings for the extension(s) marked
+     * NON-CRITICAL in the certificate/CRL managed by the object
+     * implementing this interface.
+     *
+     * Here is sample code to get a Set of non-critical extensions from an
+     * X509CRL revoked certificate entry and print the OIDs:
+     * <pre>{@code
+     * CertificateFactory cf = null;
+     * X509CRL crl = null;
+     * try (InputStream inStrm = new FileInputStream("DER-encoded-CRL")) {
+     *     cf = CertificateFactory.getInstance("X.509");
+     *     crl = (X509CRL)cf.generateCRL(inStrm);
+     * }
+     *
+     * byte[] certData = <DER-encoded certificate data>
+     * ByteArrayInputStream bais = new ByteArrayInputStream(certData);
+     * X509Certificate cert = (X509Certificate)cf.generateCertificate(bais);
+     * X509CRLEntry badCert =
+     *              crl.getRevokedCertificate(cert.getSerialNumber());
+     *
+     * if (badCert != null) {
+     *     Set<String> nonCritSet = badCert.getNonCriticalExtensionOIDs();
+     *     if (nonCritSet != null)
+     *         for (String oid : nonCritSet) {
+     *             System.out.println(oid);
+     *         }
+     * }
+     * }</pre>
+     *
+     * @return a Set (or an empty Set if none are marked non-critical) of
+     * the extension OID strings for extensions that are marked non-critical.
+     * If there are no extensions present at all, then this method returns
+     * null.
+     */
+    public Set<String> getNonCriticalExtensionOIDs();
+
+    /**
+     * Gets the DER-encoded OCTET string for the extension value
+     * (<em>extnValue</em>) identified by the passed-in {@code oid}
+     * String.
+     * The {@code oid} string is
+     * represented by a set of nonnegative whole numbers separated
+     * by periods.
+     *
+     * <p>For example:<br>
+     * <table border=groove summary="Examples of OIDs and extension names">
+     * <tr>
+     * <th>OID <em>(Object Identifier)</em></th>
+     * <th>Extension Name</th></tr>
+     * <tr><td>2.5.29.14</td>
+     * <td>SubjectKeyIdentifier</td></tr>
+     * <tr><td>2.5.29.15</td>
+     * <td>KeyUsage</td></tr>
+     * <tr><td>2.5.29.16</td>
+     * <td>PrivateKeyUsage</td></tr>
+     * <tr><td>2.5.29.17</td>
+     * <td>SubjectAlternativeName</td></tr>
+     * <tr><td>2.5.29.18</td>
+     * <td>IssuerAlternativeName</td></tr>
+     * <tr><td>2.5.29.19</td>
+     * <td>BasicConstraints</td></tr>
+     * <tr><td>2.5.29.30</td>
+     * <td>NameConstraints</td></tr>
+     * <tr><td>2.5.29.33</td>
+     * <td>PolicyMappings</td></tr>
+     * <tr><td>2.5.29.35</td>
+     * <td>AuthorityKeyIdentifier</td></tr>
+     * <tr><td>2.5.29.36</td>
+     * <td>PolicyConstraints</td></tr>
+     * </table>
+     *
+     * @param oid the Object Identifier value for the extension.
+     * @return the DER-encoded octet string of the extension value or
+     * null if it is not present.
+     */
+    public byte[] getExtensionValue(String oid);
+}
diff --git a/java/security/cert/package-info.java b/java/security/cert/package-info.java
new file mode 100644
index 0000000..58f5fb7
--- /dev/null
+++ b/java/security/cert/package-info.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides classes and interfaces for parsing and managing
+ * certificates, certificate revocation lists (CRLs), and
+ * certification paths. It contains support for X.509 v3
+ * certificates and X.509 v2 CRLs.
+ *
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *   <li><a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
+ *     <b>Java&trade;
+ *     Cryptography Architecture (JCA) Reference Guide</b></a>
+ *   <li>RFC 5280: Internet X.509 Public Key Infrastructure Certificate and
+ *     Certificate Revocation List (CRL) Profile
+ *   <li>RFC 2560: X.509 Internet Public Key Infrastructure Online Certificate
+ *     Status Protocol - OCSP
+ *   <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
+ *     <b>Java&trade;
+ *     Cryptography Architecture Standard Algorithm Name
+ *     Documentation</b></a></li>
+ * </ul>
+ *
+ * <h2>Related Documentation</h2>
+ *
+ * For information about X.509 certificates and CRLs, please see:
+ * <ul>
+ *   <li><a href="http://www.ietf.org/rfc/rfc5280.txt">
+ *     http://www.ietf.org/rfc/rfc5280.txt</a>
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/certpath/CertPathProgGuide.html">
+ *     <b>Java&trade;
+ *     PKI Programmer's Guide</b></a>
+ *   <li><a href="{@docRoot}/../technotes/guides/security/cert3.html">
+ *     <b>X.509 Certificates and Certificate Revocation Lists (CRLs)</b></a>
+ * </ul>
+ *
+ * @since 1.2
+ */
+package java.security.cert;
diff --git a/java/security/interfaces/DSAKey.java b/java/security/interfaces/DSAKey.java
new file mode 100644
index 0000000..d78b3e1
--- /dev/null
+++ b/java/security/interfaces/DSAKey.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+/**
+ * The interface to a DSA public or private key. DSA (Digital Signature
+ * Algorithm) is defined in NIST's FIPS-186.
+ *
+ * @see DSAParams
+ * @see java.security.Key
+ * @see java.security.Signature
+ *
+ * @author Benjamin Renaud
+ * @author Josh Bloch
+ */
+public interface DSAKey {
+
+    /**
+     * Returns the DSA-specific key parameters. These parameters are
+     * never secret.
+     *
+     * @return the DSA-specific key parameters.
+     *
+     * @see DSAParams
+     */
+    public DSAParams getParams();
+}
diff --git a/java/security/interfaces/DSAKeyPairGenerator.java b/java/security/interfaces/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..e50cfd2
--- /dev/null
+++ b/java/security/interfaces/DSAKeyPairGenerator.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.security.*;
+
+/**
+ * An interface to an object capable of generating DSA key pairs.
+ *
+ * <p>The {@code initialize} methods may each be called any number
+ * of times. If no {@code initialize} method is called on a
+ * DSAKeyPairGenerator, the default is to generate 1024-bit keys, using
+ * precomputed p, q and g parameters and an instance of SecureRandom as
+ * the random bit source.
+ *
+ * <p>Users wishing to indicate DSA-specific parameters, and to generate a key
+ * pair suitable for use with the DSA algorithm typically
+ *
+ * <ol>
+ *
+ * <li>Get a key pair generator for the DSA algorithm by calling the
+ * KeyPairGenerator {@code getInstance} method with "DSA"
+ * as its argument.
+ *
+ * <li>Initialize the generator by casting the result to a DSAKeyPairGenerator
+ * and calling one of the
+ * {@code initialize} methods from this DSAKeyPairGenerator interface.
+ *
+ * <li>Generate a key pair by calling the {@code generateKeyPair}
+ * method from the KeyPairGenerator class.
+ *
+ * </ol>
+ *
+ * <p>Note: it is not always necessary to do do algorithm-specific
+ * initialization for a DSA key pair generator. That is, it is not always
+ * necessary to call an {@code initialize} method in this interface.
+ * Algorithm-independent initialization using the {@code initialize} method
+ * in the KeyPairGenerator
+ * interface is all that is needed when you accept defaults for algorithm-specific
+ * parameters.
+ *
+ * <p>Note: Some earlier implementations of this interface may not support
+ * larger sizes of DSA parameters such as 2048 and 3072-bit.
+ *
+ * @see java.security.KeyPairGenerator
+ */
+public interface DSAKeyPairGenerator {
+
+    /**
+     * Initializes the key pair generator using the DSA family parameters
+     * (p,q and g) and an optional SecureRandom bit source. If a
+     * SecureRandom bit source is needed but not supplied, i.e. null, a
+     * default SecureRandom instance will be used.
+     *
+     * @param params the parameters to use to generate the keys.
+     *
+     * @param random the random bit source to use to generate key bits;
+     * can be null.
+     *
+     * @exception InvalidParameterException if the {@code params}
+     * value is invalid, null, or unsupported.
+     */
+   public void initialize(DSAParams params, SecureRandom random)
+   throws InvalidParameterException;
+
+    /**
+     * Initializes the key pair generator for a given modulus length
+     * (instead of parameters), and an optional SecureRandom bit source.
+     * If a SecureRandom bit source is needed but not supplied, i.e.
+     * null, a default SecureRandom instance will be used.
+     *
+     * <p>If {@code genParams} is true, this method generates new
+     * p, q and g parameters. If it is false, the method uses precomputed
+     * parameters for the modulus length requested. If there are no
+     * precomputed parameters for that modulus length, an exception will be
+     * thrown. It is guaranteed that there will always be
+     * default parameters for modulus lengths of 512 and 1024 bits.
+     *
+     * @param modlen the modulus length in bits. Valid values are any
+     * multiple of 64 between 512 and 1024, inclusive, 2048, and 3072.
+     *
+     * @param random the random bit source to use to generate key bits;
+     * can be null.
+     *
+     * @param genParams whether or not to generate new parameters for
+     * the modulus length requested.
+     *
+     * @exception InvalidParameterException if {@code modlen} is
+     * invalid, or unsupported, or if {@code genParams} is false and there
+     * are no precomputed parameters for the requested modulus length.
+     */
+    public void initialize(int modlen, boolean genParams, SecureRandom random)
+    throws InvalidParameterException;
+}
diff --git a/java/security/interfaces/DSAParams.java b/java/security/interfaces/DSAParams.java
new file mode 100644
index 0000000..8c46ed5
--- /dev/null
+++ b/java/security/interfaces/DSAParams.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * Interface to a DSA-specific set of key parameters, which defines a
+ * DSA <em>key family</em>. DSA (Digital Signature Algorithm) is defined
+ * in NIST's FIPS-186.
+ *
+ * @see DSAKey
+ * @see java.security.Key
+ * @see java.security.Signature
+ *
+ * @author Benjamin Renaud
+ * @author Josh Bloch
+ */
+public interface DSAParams {
+
+    /**
+     * Returns the prime, {@code p}.
+     *
+     * @return the prime, {@code p}.
+     */
+    public BigInteger getP();
+
+    /**
+     * Returns the subprime, {@code q}.
+     *
+     * @return the subprime, {@code q}.
+     */
+    public BigInteger getQ();
+
+    /**
+     * Returns the base, {@code g}.
+     *
+     * @return the base, {@code g}.
+     */
+    public BigInteger getG();
+}
diff --git a/java/security/interfaces/DSAPrivateKey.java b/java/security/interfaces/DSAPrivateKey.java
new file mode 100644
index 0000000..81ab358
--- /dev/null
+++ b/java/security/interfaces/DSAPrivateKey.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The standard interface to a DSA private key. DSA (Digital Signature
+ * Algorithm) is defined in NIST's FIPS-186.
+ *
+ * @see java.security.Key
+ * @see java.security.Signature
+ * @see DSAKey
+ * @see DSAPublicKey
+ *
+ * @author Benjamin Renaud
+ */
+public interface DSAPrivateKey extends DSAKey, java.security.PrivateKey {
+
+    // Declare serialVersionUID to be compatible with JDK1.1
+
+   /**
+    * The class fingerprint that is set to indicate
+    * serialization compatibility with a previous
+    * version of the class.
+    */
+    static final long serialVersionUID = 7776497482533790279L;
+
+    /**
+     * Returns the value of the private key, {@code x}.
+     *
+     * @return the value of the private key, {@code x}.
+     */
+    public BigInteger getX();
+}
diff --git a/java/security/interfaces/DSAPublicKey.java b/java/security/interfaces/DSAPublicKey.java
new file mode 100644
index 0000000..e56b795
--- /dev/null
+++ b/java/security/interfaces/DSAPublicKey.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to a DSA public key. DSA (Digital Signature Algorithm)
+ * is defined in NIST's FIPS-186.
+ *
+ * @see java.security.Key
+ * @see java.security.Signature
+ * @see DSAKey
+ * @see DSAPrivateKey
+ *
+ * @author Benjamin Renaud
+ */
+public interface DSAPublicKey extends DSAKey, java.security.PublicKey {
+
+    // Declare serialVersionUID to be compatible with JDK1.1
+
+   /**
+    * The class fingerprint that is set to indicate
+    * serialization compatibility with a previous
+    * version of the class.
+    */
+    static final long serialVersionUID = 1234526332779022332L;
+
+    /**
+     * Returns the value of the public key, {@code y}.
+     *
+     * @return the value of the public key, {@code y}.
+     */
+    public BigInteger getY();
+}
diff --git a/java/security/interfaces/ECKey.java b/java/security/interfaces/ECKey.java
new file mode 100644
index 0000000..dd4b9d1
--- /dev/null
+++ b/java/security/interfaces/ECKey.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.interfaces;
+
+import java.security.spec.ECParameterSpec;
+
+/**
+ * The interface to an elliptic curve (EC) key.
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public interface ECKey {
+    /**
+     * Returns the domain parameters associated
+     * with this key. The domain parameters are
+     * either explicitly specified or implicitly
+     * created during key generation.
+     * @return the associated domain parameters.
+     */
+    ECParameterSpec getParams();
+}
diff --git a/java/security/interfaces/ECPrivateKey.java b/java/security/interfaces/ECPrivateKey.java
new file mode 100644
index 0000000..0ccdc2d
--- /dev/null
+++ b/java/security/interfaces/ECPrivateKey.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * The interface to an elliptic curve (EC) private key.
+ *
+ * @author Valerie Peng
+ *
+ *
+ * @see PrivateKey
+ * @see ECKey
+ *
+ * @since 1.5
+ */
+public interface ECPrivateKey extends PrivateKey, ECKey {
+   /**
+    * The class fingerprint that is set to indicate
+    * serialization compatibility.
+    */
+    static final long serialVersionUID = -7896394956925609184L;
+
+    /**
+     * Returns the private value S.
+     * @return the private value S.
+     */
+    BigInteger getS();
+}
diff --git a/java/security/interfaces/ECPublicKey.java b/java/security/interfaces/ECPublicKey.java
new file mode 100644
index 0000000..6d16157
--- /dev/null
+++ b/java/security/interfaces/ECPublicKey.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.interfaces;
+
+import java.security.PublicKey;
+import java.security.spec.ECPoint;
+
+/**
+ * The interface to an elliptic curve (EC) public key.
+ *
+ * @author Valerie Peng
+ *
+ *
+ * @see PublicKey
+ * @see ECKey
+ * @see java.security.spec.ECPoint
+ *
+ * @since 1.5
+ */
+public interface ECPublicKey extends PublicKey, ECKey {
+
+   /**
+    * The class fingerprint that is set to indicate
+    * serialization compatibility.
+    */
+    static final long serialVersionUID = -3314988629879632826L;
+
+    /**
+     * Returns the public point W.
+     * @return the public point W.
+     */
+    ECPoint getW();
+}
diff --git a/java/security/interfaces/RSAKey.java b/java/security/interfaces/RSAKey.java
new file mode 100644
index 0000000..67fbe2b
--- /dev/null
+++ b/java/security/interfaces/RSAKey.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to an RSA public or private key.
+ *
+ * @author Jan Luehe
+ *
+ * @see RSAPublicKey
+ * @see RSAPrivateKey
+ *
+ * @since 1.3
+ */
+
+public interface RSAKey {
+
+    /**
+     * Returns the modulus.
+     *
+     * @return the modulus
+     */
+    public BigInteger getModulus();
+}
diff --git a/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java b/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
new file mode 100644
index 0000000..f85d96a
--- /dev/null
+++ b/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+import java.security.spec.RSAOtherPrimeInfo;
+
+/**
+ * The interface to an RSA multi-prime private key, as defined in the
+ * PKCS#1 v2.1, using the <i>Chinese Remainder Theorem</i>
+ * (CRT) information values.
+ *
+ * @author Valerie Peng
+ *
+ *
+ * @see java.security.spec.RSAPrivateKeySpec
+ * @see java.security.spec.RSAMultiPrimePrivateCrtKeySpec
+ * @see RSAPrivateKey
+ * @see RSAPrivateCrtKey
+ *
+ * @since 1.4
+ */
+
+public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey {
+
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
+    static final long serialVersionUID = 618058533534628008L;
+
+    /**
+     * Returns the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent();
+
+    /**
+     * Returns the primeP.
+     *
+     * @return the primeP.
+     */
+    public BigInteger getPrimeP();
+
+    /**
+     * Returns the primeQ.
+     *
+     * @return the primeQ.
+     */
+    public BigInteger getPrimeQ();
+
+    /**
+     * Returns the primeExponentP.
+     *
+     * @return the primeExponentP.
+     */
+    public BigInteger getPrimeExponentP();
+
+    /**
+     * Returns the primeExponentQ.
+     *
+     * @return the primeExponentQ.
+     */
+    public BigInteger getPrimeExponentQ();
+
+    /**
+     * Returns the crtCoefficient.
+     *
+     * @return the crtCoefficient.
+     */
+    public BigInteger getCrtCoefficient();
+
+    /**
+     * Returns the otherPrimeInfo or null if there are only
+     * two prime factors (p and q).
+     *
+     * @return the otherPrimeInfo.
+     */
+    public RSAOtherPrimeInfo[] getOtherPrimeInfo();
+}
diff --git a/java/security/interfaces/RSAPrivateCrtKey.java b/java/security/interfaces/RSAPrivateCrtKey.java
new file mode 100644
index 0000000..0408fea
--- /dev/null
+++ b/java/security/interfaces/RSAPrivateCrtKey.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to an RSA private key, as defined in the PKCS#1 standard,
+ * using the <i>Chinese Remainder Theorem</i> (CRT) information values.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see RSAPrivateKey
+ */
+
+public interface RSAPrivateCrtKey extends RSAPrivateKey {
+
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
+    static final long serialVersionUID = -5682214253527700368L;
+
+    /**
+     * Returns the public exponent.
+     *
+     * @return the public exponent
+     */
+    public BigInteger getPublicExponent();
+
+    /**
+     * Returns the primeP.
+
+     * @return the primeP
+     */
+    public BigInteger getPrimeP();
+
+    /**
+     * Returns the primeQ.
+     *
+     * @return the primeQ
+     */
+    public BigInteger getPrimeQ();
+
+    /**
+     * Returns the primeExponentP.
+     *
+     * @return the primeExponentP
+     */
+    public BigInteger getPrimeExponentP();
+
+    /**
+     * Returns the primeExponentQ.
+     *
+     * @return the primeExponentQ
+     */
+    public BigInteger getPrimeExponentQ();
+
+    /**
+     * Returns the crtCoefficient.
+     *
+     * @return the crtCoefficient
+     */
+    public BigInteger getCrtCoefficient();
+}
diff --git a/java/security/interfaces/RSAPrivateKey.java b/java/security/interfaces/RSAPrivateKey.java
new file mode 100644
index 0000000..5d69ad6
--- /dev/null
+++ b/java/security/interfaces/RSAPrivateKey.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to an RSA private key.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see RSAPrivateCrtKey
+ */
+
+public interface RSAPrivateKey extends java.security.PrivateKey, RSAKey
+{
+
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
+    static final long serialVersionUID = 5187144804936595022L;
+
+    /**
+     * Returns the private exponent.
+     *
+     * @return the private exponent
+     */
+    public BigInteger getPrivateExponent();
+}
diff --git a/java/security/interfaces/RSAPublicKey.java b/java/security/interfaces/RSAPublicKey.java
new file mode 100644
index 0000000..a698c05
--- /dev/null
+++ b/java/security/interfaces/RSAPublicKey.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.interfaces;
+
+import java.math.BigInteger;
+
+/**
+ * The interface to an RSA public key.
+ *
+ * @author Jan Luehe
+ *
+ */
+
+public interface RSAPublicKey extends java.security.PublicKey, RSAKey
+{
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
+    static final long serialVersionUID = -8727434096241101194L;
+
+    /**
+     * Returns the public exponent.
+     *
+     * @return the public exponent
+     */
+    public BigInteger getPublicExponent();
+}
diff --git a/java/security/interfaces/package-info.java b/java/security/interfaces/package-info.java
new file mode 100644
index 0000000..54c9397
--- /dev/null
+++ b/java/security/interfaces/package-info.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides interfaces for generating RSA (Rivest, Shamir and
+ * Adleman AsymmetricCipher algorithm)
+ * keys as defined in the RSA Laboratory Technical Note
+ * PKCS#1, and DSA (Digital Signature
+ * Algorithm) keys as defined in NIST's FIPS-186.
+ * <P>
+ * Note that these interfaces are intended only for key
+ * implementations whose key material is accessible and
+ * available. These interfaces are not intended for key
+ * implementations whose key material resides in
+ * inaccessible, protected storage (such as in a
+ * hardware device).
+ * <P>
+ * For more developer information on how to use these
+ * interfaces, including information on how to design
+ * {@code Key} classes for hardware devices, please refer
+ * to these cryptographic provider developer guides:
+ * <ul>
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
+ *     <b>How to Implement a Provider for the
+ *     Java&trade; Cryptography Architecture
+ *     </b></a></li>
+ * </ul>
+ *
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *   <li>PKCS #1: RSA Encryption Standard, Version 1.5, November 1993 </li>
+ *   <li>Federal Information Processing Standards Publication (FIPS PUB) 186:
+ *     Digital Signature Standard (DSS) </li>
+ * </ul>
+ *
+ * <h2>Related Documentation</h2>
+ *
+ * For further documentation, please see:
+ * <ul>
+ *   <li>
+ *     <a href=
+ *       "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
+ *       <b>Java&trade;
+ *       Cryptography Architecture API Specification and Reference
+ *       </b></a></li>
+ * </ul>
+ *
+ * @since JDK1.1
+ */
+package java.security.interfaces;
diff --git a/java/security/package-info.java b/java/security/package-info.java
new file mode 100644
index 0000000..2c8205b
--- /dev/null
+++ b/java/security/package-info.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides the classes and interfaces for the security framework.
+ * This includes classes that implement an easily configurable,
+ * fine-grained access control security architecture.
+ * This package also supports
+ * the generation and storage of cryptographic public key pairs,
+ * as well as a number of exportable cryptographic operations
+ * including those for message digest and signature generation.  Finally,
+ * this package provides classes that support signed/guarded objects
+ * and secure random number generation.
+ *
+ * Many of the classes provided in this package (the cryptographic
+ * and secure random number generator classes in particular) are
+ * provider-based.  The class itself defines a programming interface
+ * to which applications may write.  The implementations themselves may
+ * then be written by independent third-party vendors and plugged
+ * in seamlessly as needed.  Therefore application developers may
+ * take advantage of any number of provider-based implementations
+ * without having to add or rewrite code.
+ *
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *   <li><a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
+ *     <b>Java&trade;
+ *     Cryptography Architecture (JCA) Reference Guide</b></a></li>
+ *
+ *   <li>PKCS #8: Private-Key Information Syntax Standard, Version 1.2,
+ *     November 1993</li>
+ *
+ *   <li><a href="{@docRoot}/../technotes/guides/security/StandardNames.html">
+ *     <b>Java&trade;
+ *     Cryptography Architecture Standard Algorithm Name
+ *     Documentation</b></a></li>
+ * </ul>
+ *
+ * <h2>Related Documentation</h2>
+ *
+ * For further documentation, please see:
+ * <ul>
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/spec/security-spec.doc.html">
+ *     <b>Java&trade;
+ *     SE Platform Security Architecture</b></a></li>
+ *
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
+ *     <b>How to Implement a Provider in the
+ *     Java&trade; Cryptography Architecture
+ *     </b></a></li>
+ *
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/PolicyFiles.html"><b>
+ *     Default Policy Implementation and Policy File Syntax
+ *     </b></a></li>
+ *
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/permissions.html"><b>
+ *     Permissions in the
+ *     Java&trade; SE Development Kit (JDK)
+ *     </b></a></li>
+ *
+ *   <li><a href=
+ *     "{@docRoot}/../technotes/guides/security/SecurityToolsSummary.html"><b>
+ *     Summary of Tools for
+ *     Java&trade; Platform Security
+ *     </b></a></li>
+ *
+ *   <li><b>keytool</b>
+ *     (<a href="{@docRoot}/../technotes/tools/unix/keytool.html">
+ *       for Solaris/Linux</a>)
+ *     (<a href="{@docRoot}/../technotes/tools/windows/keytool.html">
+ *       for Windows</a>)
+ *     </li>
+ *
+ *   <li><b>jarsigner</b>
+ *     (<a href="{@docRoot}/../technotes/tools/unix/jarsigner.html">
+ *       for Solaris/Linux</a>)
+ *     (<a href="{@docRoot}/../technotes/tools/windows/jarsigner.html">
+ *       for Windows</a>)
+ *     </li>
+ *
+ * </ul>
+ *
+ * @since 1.1
+ */
+package java.security;
diff --git a/java/security/spec/AlgorithmParameterSpec.java b/java/security/spec/AlgorithmParameterSpec.java
new file mode 100644
index 0000000..7714c30
--- /dev/null
+++ b/java/security/spec/AlgorithmParameterSpec.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+/**
+ * A (transparent) specification of cryptographic parameters.
+ *
+ * <P> This interface contains no methods or constants. Its only purpose
+ * is to group (and provide type safety for) all parameter specifications.
+ * All parameter specifications must implement this interface.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.AlgorithmParameters
+ * @see DSAParameterSpec
+ *
+ * @since 1.2
+ */
+
+public interface AlgorithmParameterSpec { }
diff --git a/java/security/spec/DSAParameterSpec.java b/java/security/spec/DSAParameterSpec.java
new file mode 100644
index 0000000..eed6bdc
--- /dev/null
+++ b/java/security/spec/DSAParameterSpec.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies the set of parameters used with the DSA algorithm.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see AlgorithmParameterSpec
+ *
+ * @since 1.2
+ */
+
+public class DSAParameterSpec implements AlgorithmParameterSpec,
+java.security.interfaces.DSAParams {
+
+    BigInteger p;
+    BigInteger q;
+    BigInteger g;
+
+    /**
+     * Creates a new DSAParameterSpec with the specified parameter values.
+     *
+     * @param p the prime.
+     *
+     * @param q the sub-prime.
+     *
+     * @param g the base.
+     */
+    public DSAParameterSpec(BigInteger p, BigInteger q, BigInteger g) {
+        this.p = p;
+        this.q = q;
+        this.g = g;
+    }
+
+    /**
+     * Returns the prime {@code p}.
+     *
+     * @return the prime {@code p}.
+     */
+    public BigInteger getP() {
+        return this.p;
+    }
+
+    /**
+     * Returns the sub-prime {@code q}.
+     *
+     * @return the sub-prime {@code q}.
+     */
+    public BigInteger getQ() {
+        return this.q;
+    }
+
+    /**
+     * Returns the base {@code g}.
+     *
+     * @return the base {@code g}.
+     */
+    public BigInteger getG() {
+        return this.g;
+    }
+}
diff --git a/java/security/spec/DSAPrivateKeySpec.java b/java/security/spec/DSAPrivateKeySpec.java
new file mode 100644
index 0000000..a004de7
--- /dev/null
+++ b/java/security/spec/DSAPrivateKeySpec.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies a DSA private key with its associated parameters.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see DSAPublicKeySpec
+ * @see PKCS8EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public class DSAPrivateKeySpec implements KeySpec {
+
+    private BigInteger x;
+    private BigInteger p;
+    private BigInteger q;
+    private BigInteger g;
+
+    /**
+     * Creates a new DSAPrivateKeySpec with the specified parameter values.
+     *
+     * @param x the private key.
+     *
+     * @param p the prime.
+     *
+     * @param q the sub-prime.
+     *
+     * @param g the base.
+     */
+    public DSAPrivateKeySpec(BigInteger x, BigInteger p, BigInteger q,
+                             BigInteger g) {
+        this.x = x;
+        this.p = p;
+        this.q = q;
+        this.g = g;
+    }
+
+    /**
+     * Returns the private key {@code x}.
+     *
+     * @return the private key {@code x}.
+     */
+    public BigInteger getX() {
+        return this.x;
+    }
+
+    /**
+     * Returns the prime {@code p}.
+     *
+     * @return the prime {@code p}.
+     */
+    public BigInteger getP() {
+        return this.p;
+    }
+
+    /**
+     * Returns the sub-prime {@code q}.
+     *
+     * @return the sub-prime {@code q}.
+     */
+    public BigInteger getQ() {
+        return this.q;
+    }
+
+    /**
+     * Returns the base {@code g}.
+     *
+     * @return the base {@code g}.
+     */
+    public BigInteger getG() {
+        return this.g;
+    }
+}
diff --git a/java/security/spec/DSAPublicKeySpec.java b/java/security/spec/DSAPublicKeySpec.java
new file mode 100644
index 0000000..a56e6f9
--- /dev/null
+++ b/java/security/spec/DSAPublicKeySpec.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies a DSA public key with its associated parameters.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see DSAPrivateKeySpec
+ * @see X509EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public class DSAPublicKeySpec implements KeySpec {
+
+    private BigInteger y;
+    private BigInteger p;
+    private BigInteger q;
+    private BigInteger g;
+
+    /**
+     * Creates a new DSAPublicKeySpec with the specified parameter values.
+     *
+     * @param y the public key.
+     *
+     * @param p the prime.
+     *
+     * @param q the sub-prime.
+     *
+     * @param g the base.
+     */
+    public DSAPublicKeySpec(BigInteger y, BigInteger p, BigInteger q,
+                            BigInteger g) {
+        this.y = y;
+        this.p = p;
+        this.q = q;
+        this.g = g;
+    }
+
+    /**
+     * Returns the public key {@code y}.
+     *
+     * @return the public key {@code y}.
+     */
+    public BigInteger getY() {
+        return this.y;
+    }
+
+    /**
+     * Returns the prime {@code p}.
+     *
+     * @return the prime {@code p}.
+     */
+    public BigInteger getP() {
+        return this.p;
+    }
+
+    /**
+     * Returns the sub-prime {@code q}.
+     *
+     * @return the sub-prime {@code q}.
+     */
+    public BigInteger getQ() {
+        return this.q;
+    }
+
+    /**
+     * Returns the base {@code g}.
+     *
+     * @return the base {@code g}.
+     */
+    public BigInteger getG() {
+        return this.g;
+    }
+}
diff --git a/java/security/spec/ECField.java b/java/security/spec/ECField.java
new file mode 100644
index 0000000..6a42521
--- /dev/null
+++ b/java/security/spec/ECField.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * This interface represents an elliptic curve (EC) finite field.
+ * All specialized EC fields must implements this interface.
+ *
+ * @see ECFieldFp
+ * @see ECFieldF2m
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public interface ECField {
+    /**
+     * Returns the field size in bits. Note: For prime finite
+     * field ECFieldFp, size of prime p in bits is returned.
+     * For characteristic 2 finite field ECFieldF2m, m is returned.
+     * @return the field size in bits.
+     */
+    int getFieldSize();
+}
diff --git a/java/security/spec/ECFieldF2m.java b/java/security/spec/ECFieldF2m.java
new file mode 100644
index 0000000..4076fa6
--- /dev/null
+++ b/java/security/spec/ECFieldF2m.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * This immutable class defines an elliptic curve (EC)
+ * characteristic 2 finite field.
+ *
+ * @see ECField
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECFieldF2m implements ECField {
+
+    private int m;
+    private int[] ks;
+    private BigInteger rp;
+
+    /**
+     * Creates an elliptic curve characteristic 2 finite
+     * field which has 2^{@code m} elements with normal basis.
+     * @param m with 2^{@code m} being the number of elements.
+     * @exception IllegalArgumentException if {@code m}
+     * is not positive.
+     */
+    public ECFieldF2m(int m) {
+        if (m <= 0) {
+            throw new IllegalArgumentException("m is not positive");
+        }
+        this.m = m;
+        this.ks = null;
+        this.rp = null;
+    }
+
+    /**
+     * Creates an elliptic curve characteristic 2 finite
+     * field which has 2^{@code m} elements with
+     * polynomial basis.
+     * The reduction polynomial for this field is based
+     * on {@code rp} whose i-th bit corresponds to
+     * the i-th coefficient of the reduction polynomial.<p>
+     * Note: A valid reduction polynomial is either a
+     * trinomial (X^{@code m} + X^{@code k} + 1
+     * with {@code m} &gt; {@code k} &gt;= 1) or a
+     * pentanomial (X^{@code m} + X^{@code k3}
+     * + X^{@code k2} + X^{@code k1} + 1 with
+     * {@code m} &gt; {@code k3} &gt; {@code k2}
+     * &gt; {@code k1} &gt;= 1).
+     * @param m with 2^{@code m} being the number of elements.
+     * @param rp the BigInteger whose i-th bit corresponds to
+     * the i-th coefficient of the reduction polynomial.
+     * @exception NullPointerException if {@code rp} is null.
+     * @exception IllegalArgumentException if {@code m}
+     * is not positive, or {@code rp} does not represent
+     * a valid reduction polynomial.
+     */
+    public ECFieldF2m(int m, BigInteger rp) {
+        // check m and rp
+        this.m = m;
+        this.rp = rp;
+        if (m <= 0) {
+            throw new IllegalArgumentException("m is not positive");
+        }
+        int bitCount = this.rp.bitCount();
+        if (!this.rp.testBit(0) || !this.rp.testBit(m) ||
+            ((bitCount != 3) && (bitCount != 5))) {
+            throw new IllegalArgumentException
+                ("rp does not represent a valid reduction polynomial");
+        }
+        // convert rp into ks
+        BigInteger temp = this.rp.clearBit(0).clearBit(m);
+        this.ks = new int[bitCount-2];
+        for (int i = this.ks.length-1; i >= 0; i--) {
+            int index = temp.getLowestSetBit();
+            this.ks[i] = index;
+            temp = temp.clearBit(index);
+        }
+    }
+
+    /**
+     * Creates an elliptic curve characteristic 2 finite
+     * field which has 2^{@code m} elements with
+     * polynomial basis. The reduction polynomial for this
+     * field is based on {@code ks} whose content
+     * contains the order of the middle term(s) of the
+     * reduction polynomial.
+     * Note: A valid reduction polynomial is either a
+     * trinomial (X^{@code m} + X^{@code k} + 1
+     * with {@code m} &gt; {@code k} &gt;= 1) or a
+     * pentanomial (X^{@code m} + X^{@code k3}
+     * + X^{@code k2} + X^{@code k1} + 1 with
+     * {@code m} &gt; {@code k3} &gt; {@code k2}
+     * &gt; {@code k1} &gt;= 1), so {@code ks} should
+     * have length 1 or 3.
+     * @param m with 2^{@code m} being the number of elements.
+     * @param ks the order of the middle term(s) of the
+     * reduction polynomial. Contents of this array are copied
+     * to protect against subsequent modification.
+     * @exception NullPointerException if {@code ks} is null.
+     * @exception IllegalArgumentException if{@code m}
+     * is not positive, or the length of {@code ks}
+     * is neither 1 nor 3, or values in {@code ks}
+     * are not between {@code m}-1 and 1 (inclusive)
+     * and in descending order.
+     */
+    public ECFieldF2m(int m, int[] ks) {
+        // check m and ks
+        this.m = m;
+        this.ks = ks.clone();
+        if (m <= 0) {
+            throw new IllegalArgumentException("m is not positive");
+        }
+        if ((this.ks.length != 1) && (this.ks.length != 3)) {
+            throw new IllegalArgumentException
+                ("length of ks is neither 1 nor 3");
+        }
+        for (int i = 0; i < this.ks.length; i++) {
+            if ((this.ks[i] < 1) || (this.ks[i] > m-1)) {
+                throw new IllegalArgumentException
+                    ("ks["+ i + "] is out of range");
+            }
+            if ((i != 0) && (this.ks[i] >= this.ks[i-1])) {
+                throw new IllegalArgumentException
+                    ("values in ks are not in descending order");
+            }
+        }
+        // convert ks into rp
+        this.rp = BigInteger.ONE;
+        this.rp = rp.setBit(m);
+        for (int j = 0; j < this.ks.length; j++) {
+            rp = rp.setBit(this.ks[j]);
+        }
+    }
+
+    /**
+     * Returns the field size in bits which is {@code m}
+     * for this characteristic 2 finite field.
+     * @return the field size in bits.
+     */
+    public int getFieldSize() {
+        return m;
+    }
+
+    /**
+     * Returns the value {@code m} of this characteristic
+     * 2 finite field.
+     * @return {@code m} with 2^{@code m} being the
+     * number of elements.
+     */
+    public int getM() {
+        return m;
+    }
+
+    /**
+     * Returns a BigInteger whose i-th bit corresponds to the
+     * i-th coefficient of the reduction polynomial for polynomial
+     * basis or null for normal basis.
+     * @return a BigInteger whose i-th bit corresponds to the
+     * i-th coefficient of the reduction polynomial for polynomial
+     * basis or null for normal basis.
+     */
+    public BigInteger getReductionPolynomial() {
+        return rp;
+    }
+
+    /**
+     * Returns an integer array which contains the order of the
+     * middle term(s) of the reduction polynomial for polynomial
+     * basis or null for normal basis.
+     * @return an integer array which contains the order of the
+     * middle term(s) of the reduction polynomial for polynomial
+     * basis or null for normal basis. A new array is returned
+     * each time this method is called.
+     */
+    public int[] getMidTermsOfReductionPolynomial() {
+        if (ks == null) {
+            return null;
+        } else {
+            return ks.clone();
+        }
+    }
+
+    /**
+     * Compares this finite field for equality with the
+     * specified object.
+     * @param obj the object to be compared.
+     * @return true if {@code obj} is an instance
+     * of ECFieldF2m and both {@code m} and the reduction
+     * polynomial match, false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj instanceof ECFieldF2m) {
+            // no need to compare rp here since ks and rp
+            // should be equivalent
+            return ((m == ((ECFieldF2m)obj).m) &&
+                    (Arrays.equals(ks, ((ECFieldF2m) obj).ks)));
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this characteristic 2
+     * finite field.
+     * @return a hash code value.
+     */
+    public int hashCode() {
+        int value = m << 5;
+        value += (rp==null? 0:rp.hashCode());
+        // no need to involve ks here since ks and rp
+        // should be equivalent.
+        return value;
+    }
+}
diff --git a/java/security/spec/ECFieldFp.java b/java/security/spec/ECFieldFp.java
new file mode 100644
index 0000000..c578962
--- /dev/null
+++ b/java/security/spec/ECFieldFp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * This immutable class defines an elliptic curve (EC) prime
+ * finite field.
+ *
+ * @see ECField
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECFieldFp implements ECField {
+
+    private BigInteger p;
+
+    /**
+     * Creates an elliptic curve prime finite field
+     * with the specified prime {@code p}.
+     * @param p the prime.
+     * @exception NullPointerException if {@code p} is null.
+     * @exception IllegalArgumentException if {@code p}
+     * is not positive.
+     */
+    public ECFieldFp(BigInteger p) {
+        if (p.signum() != 1) {
+            throw new IllegalArgumentException("p is not positive");
+        }
+        this.p = p;
+    }
+
+    /**
+     * Returns the field size in bits which is size of prime p
+     * for this prime finite field.
+     * @return the field size in bits.
+     */
+    public int getFieldSize() {
+        return p.bitLength();
+    };
+
+    /**
+     * Returns the prime {@code p} of this prime finite field.
+     * @return the prime.
+     */
+    public BigInteger getP() {
+        return p;
+    }
+
+    /**
+     * Compares this prime finite field for equality with the
+     * specified object.
+     * @param obj the object to be compared.
+     * @return true if {@code obj} is an instance
+     * of ECFieldFp and the prime value match, false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (this == obj)  return true;
+        if (obj instanceof ECFieldFp) {
+            return (p.equals(((ECFieldFp)obj).p));
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this prime finite field.
+     * @return a hash code value.
+     */
+    public int hashCode() {
+        return p.hashCode();
+    }
+}
diff --git a/java/security/spec/ECGenParameterSpec.java b/java/security/spec/ECGenParameterSpec.java
new file mode 100644
index 0000000..4f3f63b
--- /dev/null
+++ b/java/security/spec/ECGenParameterSpec.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+/**
+ * This immutable class specifies the set of parameters used for
+ * generating elliptic curve (EC) domain parameters.
+ *
+ * @see AlgorithmParameterSpec
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECGenParameterSpec implements AlgorithmParameterSpec {
+
+    private String name;
+
+    /**
+     * Creates a parameter specification for EC parameter
+     * generation using a standard (or predefined) name
+     * {@code stdName} in order to generate the corresponding
+     * (precomputed) elliptic curve domain parameters. For the
+     * list of supported names, please consult the documentation
+     * of provider whose implementation will be used.
+     * @param stdName the standard name of the to-be-generated EC
+     * domain parameters.
+     * @exception NullPointerException if {@code stdName}
+     * is null.
+     */
+    public ECGenParameterSpec(String stdName) {
+        if (stdName == null) {
+            throw new NullPointerException("stdName is null");
+        }
+        this.name = stdName;
+    }
+
+    /**
+     * Returns the standard or predefined name of the
+     * to-be-generated EC domain parameters.
+     * @return the standard or predefined name.
+     */
+    public String getName() {
+        return name;
+    }
+}
diff --git a/java/security/spec/ECParameterSpec.annotated.java b/java/security/spec/ECParameterSpec.annotated.java
new file mode 100644
index 0000000..926ee08
--- /dev/null
+++ b/java/security/spec/ECParameterSpec.annotated.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ECParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+
+public ECParameterSpec(java.security.spec.EllipticCurve curve, java.security.spec.ECPoint g, java.math.BigInteger n, int h) { throw new RuntimeException("Stub!"); }
+
+public java.security.spec.EllipticCurve getCurve() { throw new RuntimeException("Stub!"); }
+
+public java.security.spec.ECPoint getGenerator() { throw new RuntimeException("Stub!"); }
+
+public java.math.BigInteger getOrder() { throw new RuntimeException("Stub!"); }
+
+public int getCofactor() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public void setCurveName(String curveName) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public String getCurveName() { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/security/spec/ECParameterSpec.java b/java/security/spec/ECParameterSpec.java
new file mode 100644
index 0000000..65bd027
--- /dev/null
+++ b/java/security/spec/ECParameterSpec.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This immutable class specifies the set of domain parameters
+ * used with elliptic curve cryptography (ECC).
+ *
+ * @see AlgorithmParameterSpec
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECParameterSpec implements AlgorithmParameterSpec {
+
+    private final EllipticCurve curve;
+    private final ECPoint g;
+    private final BigInteger n;
+    private final int h;
+
+    /**
+     * Creates elliptic curve domain parameters based on the
+     * specified values.
+     * @param curve the elliptic curve which this parameter
+     * defines.
+     * @param g the generator which is also known as the base point.
+     * @param n the order of the generator {@code g}.
+     * @param h the cofactor.
+     * @exception NullPointerException if {@code curve},
+     * {@code g}, or {@code n} is null.
+     * @exception IllegalArgumentException if {@code n}
+     * or {@code h} is not positive.
+     */
+    public ECParameterSpec(EllipticCurve curve, ECPoint g,
+                           BigInteger n, int h) {
+        if (curve == null) {
+            throw new NullPointerException("curve is null");
+        }
+        if (g == null) {
+            throw new NullPointerException("g is null");
+        }
+        if (n == null) {
+            throw new NullPointerException("n is null");
+        }
+        if (n.signum() != 1) {
+            throw new IllegalArgumentException("n is not positive");
+        }
+        if (h <= 0) {
+            throw new IllegalArgumentException("h is not positive");
+        }
+        this.curve = curve;
+        this.g = g;
+        this.n = n;
+        this.h = h;
+    }
+
+    /**
+     * Returns the elliptic curve that this parameter defines.
+     * @return the elliptic curve that this parameter defines.
+     */
+    public EllipticCurve getCurve() {
+        return curve;
+    }
+
+    /**
+     * Returns the generator which is also known as the base point.
+     * @return the generator which is also known as the base point.
+     */
+    public ECPoint getGenerator() {
+        return g;
+    }
+
+    /**
+     * Returns the order of the generator.
+     * @return the order of the generator.
+     */
+    public BigInteger getOrder() {
+        return n;
+    }
+
+    /**
+     * Returns the cofactor.
+     * @return the cofactor.
+     */
+    public int getCofactor() {
+        return h;
+    }
+    // BEGIN Android-added: Store the curve name as part of the parameters
+    // Knowing the name of the curve sometimes allows implementations to operate
+    // more efficiently.
+    private String curveName;
+
+    /**
+     * Used to set the curve name if available.
+     *
+     * @hide
+     */
+    public void setCurveName(String curveName) {
+        this.curveName = curveName;
+    }
+
+    /**
+     * Returns the name of the curve if this is a named curve. Returns
+     * {@code null} if this is not known to be a named curve.
+     *
+     * @hide
+     */
+    public String getCurveName() {
+        return curveName;
+    }
+    // END Android-added: Store the curve name as part of the parameters
+}
diff --git a/java/security/spec/ECPoint.java b/java/security/spec/ECPoint.java
new file mode 100644
index 0000000..1b051c7
--- /dev/null
+++ b/java/security/spec/ECPoint.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This immutable class represents a point on an elliptic curve (EC)
+ * in affine coordinates. Other coordinate systems can
+ * extend this class to represent this point in other
+ * coordinates.
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECPoint {
+
+    private final BigInteger x;
+    private final BigInteger y;
+
+    /**
+     * This defines the point at infinity.
+     */
+    public static final ECPoint POINT_INFINITY = new ECPoint();
+
+    // private constructor for constructing point at infinity
+    private ECPoint() {
+        this.x = null;
+        this.y = null;
+    }
+
+    /**
+     * Creates an ECPoint from the specified affine x-coordinate
+     * {@code x} and affine y-coordinate {@code y}.
+     * @param x the affine x-coordinate.
+     * @param y the affine y-coordinate.
+     * @exception NullPointerException if {@code x} or
+     * {@code y} is null.
+     */
+    public ECPoint(BigInteger x, BigInteger y) {
+        if ((x==null) || (y==null)) {
+            throw new NullPointerException("affine coordinate x or y is null");
+        }
+        this.x = x;
+        this.y = y;
+    }
+
+    /**
+     * Returns the affine x-coordinate {@code x}.
+     * Note: POINT_INFINITY has a null affine x-coordinate.
+     * @return the affine x-coordinate.
+     */
+    public BigInteger getAffineX() {
+        return x;
+    }
+
+    /**
+     * Returns the affine y-coordinate {@code y}.
+     * Note: POINT_INFINITY has a null affine y-coordinate.
+     * @return the affine y-coordinate.
+     */
+    public BigInteger getAffineY() {
+        return y;
+    }
+
+    /**
+     * Compares this elliptic curve point for equality with
+     * the specified object.
+     * @param obj the object to be compared.
+     * @return true if {@code obj} is an instance of
+     * ECPoint and the affine coordinates match, false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (this == POINT_INFINITY) return false;
+        if (obj instanceof ECPoint) {
+            return ((x.equals(((ECPoint)obj).x)) &&
+                    (y.equals(((ECPoint)obj).y)));
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this elliptic curve point.
+     * @return a hash code value.
+     */
+    public int hashCode() {
+        if (this == POINT_INFINITY) return 0;
+        return x.hashCode() << 5 + y.hashCode();
+    }
+}
diff --git a/java/security/spec/ECPrivateKeySpec.java b/java/security/spec/ECPrivateKeySpec.java
new file mode 100644
index 0000000..7f03cfd
--- /dev/null
+++ b/java/security/spec/ECPrivateKeySpec.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This immutable class specifies an elliptic curve private key with
+ * its associated parameters.
+ *
+ * @see KeySpec
+ * @see ECParameterSpec
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECPrivateKeySpec implements KeySpec {
+
+    private BigInteger s;
+    private ECParameterSpec params;
+
+    /**
+     * Creates a new ECPrivateKeySpec with the specified
+     * parameter values.
+     * @param s the private value.
+     * @param params the associated elliptic curve domain
+     * parameters.
+     * @exception NullPointerException if {@code s}
+     * or {@code params} is null.
+     */
+    public ECPrivateKeySpec(BigInteger s, ECParameterSpec params) {
+        if (s == null) {
+            throw new NullPointerException("s is null");
+        }
+        if (params == null) {
+            throw new NullPointerException("params is null");
+        }
+        this.s = s;
+        this.params = params;
+    }
+
+    /**
+     * Returns the private value S.
+     * @return the private value S.
+     */
+    public BigInteger getS() {
+        return s;
+    }
+
+    /**
+     * Returns the associated elliptic curve domain
+     * parameters.
+     * @return the EC domain parameters.
+     */
+    public ECParameterSpec getParams() {
+        return params;
+    }
+}
diff --git a/java/security/spec/ECPublicKeySpec.java b/java/security/spec/ECPublicKeySpec.java
new file mode 100644
index 0000000..e0cfb77
--- /dev/null
+++ b/java/security/spec/ECPublicKeySpec.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.security.spec;
+
+/**
+ * This immutable class specifies an elliptic curve public key with
+ * its associated parameters.
+ *
+ * @see KeySpec
+ * @see ECPoint
+ * @see ECParameterSpec
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class ECPublicKeySpec implements KeySpec {
+
+    private ECPoint w;
+    private ECParameterSpec params;
+
+    /**
+     * Creates a new ECPublicKeySpec with the specified
+     * parameter values.
+     * @param w the public point.
+     * @param params the associated elliptic curve domain
+     * parameters.
+     * @exception NullPointerException if {@code w}
+     * or {@code params} is null.
+     * @exception IllegalArgumentException if {@code w}
+     * is point at infinity, i.e. ECPoint.POINT_INFINITY
+     */
+    public ECPublicKeySpec(ECPoint w, ECParameterSpec params) {
+        if (w == null) {
+            throw new NullPointerException("w is null");
+        }
+        if (params == null) {
+            throw new NullPointerException("params is null");
+        }
+        if (w == ECPoint.POINT_INFINITY) {
+            throw new IllegalArgumentException("w is ECPoint.POINT_INFINITY");
+        }
+        this.w = w;
+        this.params = params;
+    }
+
+    /**
+     * Returns the public point W.
+     * @return the public point W.
+     */
+    public ECPoint getW() {
+        return w;
+    }
+
+    /**
+     * Returns the associated elliptic curve domain
+     * parameters.
+     * @return the EC domain parameters.
+     */
+    public ECParameterSpec getParams() {
+        return params;
+    }
+}
diff --git a/java/security/spec/EllipticCurve.java b/java/security/spec/EllipticCurve.java
new file mode 100644
index 0000000..8ec97b0
--- /dev/null
+++ b/java/security/spec/EllipticCurve.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+/**
+ * This immutable class holds the necessary values needed to represent
+ * an elliptic curve.
+ *
+ * @see ECField
+ * @see ECFieldFp
+ * @see ECFieldF2m
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class EllipticCurve {
+
+    private final ECField field;
+    private final BigInteger a;
+    private final BigInteger b;
+    private final byte[] seed;
+
+    // Check coefficient c is a valid element in ECField field.
+    private static void checkValidity(ECField field, BigInteger c,
+        String cName) {
+        // can only perform check if field is ECFieldFp or ECFieldF2m.
+        if (field instanceof ECFieldFp) {
+            BigInteger p = ((ECFieldFp)field).getP();
+            if (p.compareTo(c) != 1) {
+                throw new IllegalArgumentException(cName + " is too large");
+            } else if (c.signum() < 0) {
+                throw new IllegalArgumentException(cName + " is negative");
+            }
+        } else if (field instanceof ECFieldF2m) {
+            int m = ((ECFieldF2m)field).getM();
+            if (c.bitLength() > m) {
+                throw new IllegalArgumentException(cName + " is too large");
+            }
+        }
+    }
+
+    /**
+     * Creates an elliptic curve with the specified elliptic field
+     * {@code field} and the coefficients {@code a} and
+     * {@code b}.
+     * @param field the finite field that this elliptic curve is over.
+     * @param a the first coefficient of this elliptic curve.
+     * @param b the second coefficient of this elliptic curve.
+     * @exception NullPointerException if {@code field},
+     * {@code a}, or {@code b} is null.
+     * @exception IllegalArgumentException if {@code a}
+     * or {@code b} is not null and not in {@code field}.
+     */
+    public EllipticCurve(ECField field, BigInteger a,
+                         BigInteger b) {
+        this(field, a, b, null);
+    }
+
+    /**
+     * Creates an elliptic curve with the specified elliptic field
+     * {@code field}, the coefficients {@code a} and
+     * {@code b}, and the {@code seed} used for curve generation.
+     * @param field the finite field that this elliptic curve is over.
+     * @param a the first coefficient of this elliptic curve.
+     * @param b the second coefficient of this elliptic curve.
+     * @param seed the bytes used during curve generation for later
+     * validation. Contents of this array are copied to protect against
+     * subsequent modification.
+     * @exception NullPointerException if {@code field},
+     * {@code a}, or {@code b} is null.
+     * @exception IllegalArgumentException if {@code a}
+     * or {@code b} is not null and not in {@code field}.
+     */
+    public EllipticCurve(ECField field, BigInteger a,
+                         BigInteger b, byte[] seed) {
+        if (field == null) {
+            throw new NullPointerException("field is null");
+        }
+        if (a == null) {
+            throw new NullPointerException("first coefficient is null");
+        }
+        if (b == null) {
+            throw new NullPointerException("second coefficient is null");
+        }
+        checkValidity(field, a, "first coefficient");
+        checkValidity(field, b, "second coefficient");
+        this.field = field;
+        this.a = a;
+        this.b = b;
+        if (seed != null) {
+            this.seed = seed.clone();
+        } else {
+            this.seed = null;
+        }
+    }
+
+    /**
+     * Returns the finite field {@code field} that this
+     * elliptic curve is over.
+     * @return the field {@code field} that this curve
+     * is over.
+     */
+    public ECField getField() {
+        return field;
+    }
+
+    /**
+     * Returns the first coefficient {@code a} of the
+     * elliptic curve.
+     * @return the first coefficient {@code a}.
+     */
+    public BigInteger getA() {
+        return a;
+    }
+
+    /**
+     * Returns the second coefficient {@code b} of the
+     * elliptic curve.
+     * @return the second coefficient {@code b}.
+     */
+    public BigInteger getB() {
+        return b;
+    }
+
+    /**
+     * Returns the seeding bytes {@code seed} used
+     * during curve generation. May be null if not specified.
+     * @return the seeding bytes {@code seed}. A new
+     * array is returned each time this method is called.
+     */
+    public byte[] getSeed() {
+        if (seed == null) return null;
+        else return seed.clone();
+    }
+
+    /**
+     * Compares this elliptic curve for equality with the
+     * specified object.
+     * @param obj the object to be compared.
+     * @return true if {@code obj} is an instance of
+     * EllipticCurve and the field, A, and B match, false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj instanceof EllipticCurve) {
+            EllipticCurve curve = (EllipticCurve) obj;
+            if ((field.equals(curve.field)) &&
+                (a.equals(curve.a)) &&
+                (b.equals(curve.b))) {
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this elliptic curve.
+     * @return a hash code value computed from the hash codes of the field, A,
+     * and B, as follows:
+     * <pre>{@code
+     *     (field.hashCode() << 6) + (a.hashCode() << 4) + (b.hashCode() << 2)
+     * }</pre>
+     */
+    public int hashCode() {
+        return (field.hashCode() << 6 +
+            (a.hashCode() << 4) +
+            (b.hashCode() << 2));
+    }
+}
diff --git a/java/security/spec/EncodedKeySpec.java b/java/security/spec/EncodedKeySpec.java
new file mode 100644
index 0000000..cc3b81e
--- /dev/null
+++ b/java/security/spec/EncodedKeySpec.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+/**
+ * This class represents a public or private key in encoded format.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see X509EncodedKeySpec
+ * @see PKCS8EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public abstract class EncodedKeySpec implements KeySpec {
+
+    private byte[] encodedKey;
+
+    /**
+     * Creates a new EncodedKeySpec with the given encoded key.
+     *
+     * @param encodedKey the encoded key. The contents of the
+     * array are copied to protect against subsequent modification.
+     * @exception NullPointerException if {@code encodedKey}
+     * is null.
+     */
+    public EncodedKeySpec(byte[] encodedKey) {
+        this.encodedKey = encodedKey.clone();
+    }
+
+    /**
+     * Returns the encoded key.
+     *
+     * @return the encoded key. Returns a new array each time
+     * this method is called.
+     */
+    public byte[] getEncoded() {
+        return this.encodedKey.clone();
+    }
+
+    /**
+     * Returns the name of the encoding format associated with this
+     * key specification.
+     *
+     * <p>If the opaque representation of a key
+     * (see {@link java.security.Key Key}) can be transformed
+     * (see {@link java.security.KeyFactory KeyFactory})
+     * into this key specification (or a subclass of it),
+     * {@code getFormat} called
+     * on the opaque key returns the same value as the
+     * {@code getFormat} method
+     * of this key specification.
+     *
+     * @return a string representation of the encoding format.
+     */
+    public abstract String getFormat();
+}
diff --git a/java/security/spec/InvalidKeySpecException.java b/java/security/spec/InvalidKeySpecException.java
new file mode 100644
index 0000000..4655c4a
--- /dev/null
+++ b/java/security/spec/InvalidKeySpecException.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This is the exception for invalid key specifications.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see KeySpec
+ *
+ * @since 1.2
+ */
+
+public class InvalidKeySpecException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = 3546139293998810778L;
+
+    /**
+     * Constructs an InvalidKeySpecException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public InvalidKeySpecException() {
+        super();
+    }
+
+    /**
+     * Constructs an InvalidKeySpecException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public InvalidKeySpecException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Creates a {@code InvalidKeySpecException} with the specified
+     * detail message and cause.
+     *
+     * @param message the detail message (which is saved for later retrieval
+     *        by the {@link #getMessage()} method).
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public InvalidKeySpecException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a {@code InvalidKeySpecException} with the specified cause
+     * and a detail message of {@code (cause==null ? null : cause.toString())}
+     * (which typically contains the class and detail message of
+     * {@code cause}).
+     *
+     * @param cause the cause (which is saved for later retrieval by the
+     *        {@link #getCause()} method).  (A {@code null} value is permitted,
+     *        and indicates that the cause is nonexistent or unknown.)
+     * @since 1.5
+     */
+    public InvalidKeySpecException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/security/spec/InvalidParameterSpecException.java b/java/security/spec/InvalidParameterSpecException.java
new file mode 100644
index 0000000..3059c77
--- /dev/null
+++ b/java/security/spec/InvalidParameterSpecException.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * This is the exception for invalid parameter specifications.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.AlgorithmParameters
+ * @see AlgorithmParameterSpec
+ * @see DSAParameterSpec
+ *
+ * @since 1.2
+ */
+
+public class InvalidParameterSpecException extends GeneralSecurityException {
+
+    private static final long serialVersionUID = -970468769593399342L;
+
+    /**
+     * Constructs an InvalidParameterSpecException with no detail message. A
+     * detail message is a String that describes this particular
+     * exception.
+     */
+    public InvalidParameterSpecException() {
+        super();
+    }
+
+    /**
+     * Constructs an InvalidParameterSpecException with the specified detail
+     * message. A detail message is a String that describes this
+     * particular exception.
+     *
+     * @param msg the detail message.
+     */
+    public InvalidParameterSpecException(String msg) {
+        super(msg);
+    }
+}
diff --git a/java/security/spec/KeySpec.java b/java/security/spec/KeySpec.java
new file mode 100644
index 0000000..34fec5d
--- /dev/null
+++ b/java/security/spec/KeySpec.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+/**
+ * A (transparent) specification of the key material
+ * that constitutes a cryptographic key.
+ *
+ * <p>If the key is stored on a hardware device, its
+ * specification may contain information that helps identify the key on the
+ * device.
+ *
+ * <P> A key may be specified in an algorithm-specific way, or in an
+ * algorithm-independent encoding format (such as ASN.1).
+ * For example, a DSA private key may be specified by its components
+ * {@code x}, {@code p}, {@code q}, and {@code g}
+ * (see {@link DSAPrivateKeySpec}), or it may be
+ * specified using its DER encoding
+ * (see {@link PKCS8EncodedKeySpec}).
+ *
+ * <P> This interface contains no methods or constants. Its only purpose
+ * is to group (and provide type safety for) all key specifications.
+ * All key specifications must implement this interface.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see EncodedKeySpec
+ * @see X509EncodedKeySpec
+ * @see PKCS8EncodedKeySpec
+ * @see DSAPrivateKeySpec
+ * @see DSAPublicKeySpec
+ *
+ * @since 1.2
+ */
+
+public interface KeySpec { }
diff --git a/java/security/spec/MGF1ParameterSpec.java b/java/security/spec/MGF1ParameterSpec.java
new file mode 100644
index 0000000..1be267f
--- /dev/null
+++ b/java/security/spec/MGF1ParameterSpec.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used with mask generation
+ * function MGF1 in OAEP Padding and RSA-PSS signature scheme, as
+ * defined in the
+ * <a href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1 v2.1</a>
+ * standard.
+ *
+ * <p>Its ASN.1 definition in PKCS#1 standard is described below:
+ * <pre>
+ * MGF1Parameters ::= OAEP-PSSDigestAlgorthms
+ * </pre>
+ * where
+ * <pre>
+ * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+ *   { OID id-sha1 PARAMETERS NULL   }|
+ *   { OID id-sha224 PARAMETERS NULL   }|
+ *   { OID id-sha256 PARAMETERS NULL }|
+ *   { OID id-sha384 PARAMETERS NULL }|
+ *   { OID id-sha512 PARAMETERS NULL },
+ *   ...  -- Allows for future expansion --
+ * }
+ * </pre>
+ * @see PSSParameterSpec
+ * @see javax.crypto.spec.OAEPParameterSpec
+ *
+ * @author Valerie Peng
+ *
+ * @since 1.5
+ */
+public class MGF1ParameterSpec implements AlgorithmParameterSpec {
+
+    /**
+     * The MGF1ParameterSpec which uses "SHA-1" message digest.
+     */
+    public static final MGF1ParameterSpec SHA1 =
+        new MGF1ParameterSpec("SHA-1");
+    /**
+     * The MGF1ParameterSpec which uses "SHA-224" message digest.
+     */
+    public static final MGF1ParameterSpec SHA224 =
+        new MGF1ParameterSpec("SHA-224");
+    /**
+     * The MGF1ParameterSpec which uses "SHA-256" message digest.
+     */
+    public static final MGF1ParameterSpec SHA256 =
+        new MGF1ParameterSpec("SHA-256");
+    /**
+     * The MGF1ParameterSpec which uses "SHA-384" message digest.
+     */
+    public static final MGF1ParameterSpec SHA384 =
+        new MGF1ParameterSpec("SHA-384");
+    /**
+     * The MGF1ParameterSpec which uses SHA-512 message digest.
+     */
+    public static final MGF1ParameterSpec SHA512 =
+        new MGF1ParameterSpec("SHA-512");
+
+    private String mdName;
+
+    /**
+     * Constructs a parameter set for mask generation function MGF1
+     * as defined in the PKCS #1 standard.
+     *
+     * @param mdName the algorithm name for the message digest
+     * used in this mask generation function MGF1.
+     * @exception NullPointerException if {@code mdName} is null.
+     */
+    public MGF1ParameterSpec(String mdName) {
+        if (mdName == null) {
+            throw new NullPointerException("digest algorithm is null");
+        }
+        this.mdName = mdName;
+    }
+
+    /**
+     * Returns the algorithm name of the message digest used by the mask
+     * generation function.
+     *
+     * @return the algorithm name of the message digest.
+     */
+    public String getDigestAlgorithm() {
+        return mdName;
+    }
+}
diff --git a/java/security/spec/PKCS8EncodedKeySpec.java b/java/security/spec/PKCS8EncodedKeySpec.java
new file mode 100644
index 0000000..060f266
--- /dev/null
+++ b/java/security/spec/PKCS8EncodedKeySpec.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+/**
+ * This class represents the ASN.1 encoding of a private key,
+ * encoded according to the ASN.1 type {@code PrivateKeyInfo}.
+ * The {@code PrivateKeyInfo} syntax is defined in the PKCS#8 standard
+ * as follows:
+ *
+ * <pre>
+ * PrivateKeyInfo ::= SEQUENCE {
+ *   version Version,
+ *   privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ *   privateKey PrivateKey,
+ *   attributes [0] IMPLICIT Attributes OPTIONAL }
+ *
+ * Version ::= INTEGER
+ *
+ * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * PrivateKey ::= OCTET STRING
+ *
+ * Attributes ::= SET OF Attribute
+ * </pre>
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see EncodedKeySpec
+ * @see X509EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public class PKCS8EncodedKeySpec extends EncodedKeySpec {
+
+    /**
+     * Creates a new PKCS8EncodedKeySpec with the given encoded key.
+     *
+     * @param encodedKey the key, which is assumed to be
+     * encoded according to the PKCS #8 standard. The contents of
+     * the array are copied to protect against subsequent modification.
+     * @exception NullPointerException if {@code encodedKey}
+     * is null.
+     */
+    public PKCS8EncodedKeySpec(byte[] encodedKey) {
+        super(encodedKey);
+    }
+
+    /**
+     * Returns the key bytes, encoded according to the PKCS #8 standard.
+     *
+     * @return the PKCS #8 encoding of the key. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getEncoded() {
+        return super.getEncoded();
+    }
+
+    /**
+     * Returns the name of the encoding format associated with this
+     * key specification.
+     *
+     * @return the string {@code "PKCS#8"}.
+     */
+    public final String getFormat() {
+        return "PKCS#8";
+    }
+}
diff --git a/java/security/spec/PSSParameterSpec.java b/java/security/spec/PSSParameterSpec.java
new file mode 100644
index 0000000..a9b82d8
--- /dev/null
+++ b/java/security/spec/PSSParameterSpec.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.security.spec.MGF1ParameterSpec;
+
+/**
+ * This class specifies a parameter spec for RSA-PSS signature scheme,
+ * as defined in the
+ * <a href="http://www.ietf.org/rfc/rfc3447.txt">PKCS#1 v2.1</a>
+ * standard.
+ *
+ * <p>Its ASN.1 definition in PKCS#1 standard is described below:
+ * <pre>
+ * RSASSA-PSS-params ::= SEQUENCE {
+ *   hashAlgorithm      [0] OAEP-PSSDigestAlgorithms  DEFAULT sha1,
+ *   maskGenAlgorithm   [1] PKCS1MGFAlgorithms  DEFAULT mgf1SHA1,
+ *   saltLength         [2] INTEGER  DEFAULT 20,
+ *   trailerField       [3] INTEGER  DEFAULT 1
+ * }
+ * </pre>
+ * where
+ * <pre>
+ * OAEP-PSSDigestAlgorithms    ALGORITHM-IDENTIFIER ::= {
+ *   { OID id-sha1 PARAMETERS NULL   }|
+ *   { OID id-sha224 PARAMETERS NULL   }|
+ *   { OID id-sha256 PARAMETERS NULL }|
+ *   { OID id-sha384 PARAMETERS NULL }|
+ *   { OID id-sha512 PARAMETERS NULL },
+ *   ...  -- Allows for future expansion --
+ * }
+ *
+ * PKCS1MGFAlgorithms    ALGORITHM-IDENTIFIER ::= {
+ *   { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+ *   ...  -- Allows for future expansion --
+ * }
+ * </pre>
+ * <p>Note: the PSSParameterSpec.DEFAULT uses the following:
+ *     message digest  -- "SHA-1"
+ *     mask generation function (mgf) -- "MGF1"
+ *     parameters for mgf -- MGF1ParameterSpec.SHA1
+ *     SaltLength   -- 20
+ *     TrailerField -- 1
+ *
+ * @see MGF1ParameterSpec
+ * @see AlgorithmParameterSpec
+ * @see java.security.Signature
+ *
+ * @author Valerie Peng
+ *
+ *
+ * @since 1.4
+ */
+
+public class PSSParameterSpec implements AlgorithmParameterSpec {
+
+    private String mdName = "SHA-1";
+    private String mgfName = "MGF1";
+    private AlgorithmParameterSpec mgfSpec = MGF1ParameterSpec.SHA1;
+    private int saltLen = 20;
+    private int trailerField = 1;
+
+    /**
+     * The PSS parameter set with all default values.
+     * @since 1.5
+     */
+    public static final PSSParameterSpec DEFAULT = new PSSParameterSpec();
+
+    /**
+     * Constructs a new {@code PSSParameterSpec} as defined in
+     * the PKCS #1 standard using the default values.
+     */
+    private PSSParameterSpec() {
+    }
+
+    /**
+     * Creates a new {@code PSSParameterSpec} as defined in
+     * the PKCS #1 standard using the specified message digest,
+     * mask generation function, parameters for mask generation
+     * function, salt length, and trailer field values.
+     *
+     * @param mdName the algorithm name of the hash function.
+     * @param mgfName the algorithm name of the mask generation
+     * function.
+     * @param mgfSpec the parameters for the mask generation
+     * function. If null is specified, null will be returned by
+     * getMGFParameters().
+     * @param saltLen the length of salt.
+     * @param trailerField the value of the trailer field.
+     * @exception NullPointerException if {@code mdName},
+     * or {@code mgfName} is null.
+     * @exception IllegalArgumentException if {@code saltLen}
+     * or {@code trailerField} is less than 0.
+     * @since 1.5
+     */
+    public PSSParameterSpec(String mdName, String mgfName,
+                            AlgorithmParameterSpec mgfSpec,
+                            int saltLen, int trailerField) {
+        if (mdName == null) {
+            throw new NullPointerException("digest algorithm is null");
+        }
+        if (mgfName == null) {
+            throw new NullPointerException("mask generation function " +
+                                           "algorithm is null");
+        }
+        if (saltLen < 0) {
+            throw new IllegalArgumentException("negative saltLen value: " +
+                                               saltLen);
+        }
+        if (trailerField < 0) {
+            throw new IllegalArgumentException("negative trailerField: " +
+                                               trailerField);
+        }
+        this.mdName = mdName;
+        this.mgfName = mgfName;
+        this.mgfSpec = mgfSpec;
+        this.saltLen = saltLen;
+        this.trailerField = trailerField;
+    }
+
+    /**
+     * Creates a new {@code PSSParameterSpec}
+     * using the specified salt length and other default values as
+     * defined in PKCS#1.
+     *
+     * @param saltLen the length of salt in bits to be used in PKCS#1
+     * PSS encoding.
+     * @exception IllegalArgumentException if {@code saltLen} is
+     * less than 0.
+     */
+    public PSSParameterSpec(int saltLen) {
+        if (saltLen < 0) {
+            throw new IllegalArgumentException("negative saltLen value: " +
+                                               saltLen);
+        }
+        this.saltLen = saltLen;
+    }
+
+    /**
+     * Returns the message digest algorithm name.
+     *
+     * @return the message digest algorithm name.
+     * @since 1.5
+     */
+    public String getDigestAlgorithm() {
+        return mdName;
+    }
+
+    /**
+     * Returns the mask generation function algorithm name.
+     *
+     * @return the mask generation function algorithm name.
+     *
+     * @since 1.5
+     */
+    public String getMGFAlgorithm() {
+        return mgfName;
+    }
+
+    /**
+     * Returns the parameters for the mask generation function.
+     *
+     * @return the parameters for the mask generation function.
+     * @since 1.5
+     */
+    public AlgorithmParameterSpec getMGFParameters() {
+        return mgfSpec;
+    }
+
+    /**
+     * Returns the salt length in bits.
+     *
+     * @return the salt length.
+     */
+    public int getSaltLength() {
+        return saltLen;
+    }
+
+    /**
+     * Returns the value for the trailer field, i.e. bc in PKCS#1 v2.1.
+     *
+     * @return the value for the trailer field, i.e. bc in PKCS#1 v2.1.
+     * @since 1.5
+     */
+    public int getTrailerField() {
+        return trailerField;
+    }
+}
diff --git a/java/security/spec/RSAKeyGenParameterSpec.java b/java/security/spec/RSAKeyGenParameterSpec.java
new file mode 100644
index 0000000..a73c6cd
--- /dev/null
+++ b/java/security/spec/RSAKeyGenParameterSpec.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * This class specifies the set of parameters used to generate an RSA
+ * key pair.
+ *
+ * @author Jan Luehe
+ *
+ * @see java.security.KeyPairGenerator#initialize(java.security.spec.AlgorithmParameterSpec)
+ *
+ * @since 1.3
+ */
+
+public class RSAKeyGenParameterSpec implements AlgorithmParameterSpec {
+
+    private int keysize;
+    private BigInteger publicExponent;
+
+    /**
+     * The public-exponent value F0 = 3.
+     */
+    public static final BigInteger F0 = BigInteger.valueOf(3);
+
+    /**
+     * The public exponent-value F4 = 65537.
+     */
+    public static final BigInteger F4 = BigInteger.valueOf(65537);
+
+    /**
+     * Constructs a new {@code RSAParameterSpec} object from the
+     * given keysize and public-exponent value.
+     *
+     * @param keysize the modulus size (specified in number of bits)
+     * @param publicExponent the public exponent
+     */
+    public RSAKeyGenParameterSpec(int keysize, BigInteger publicExponent) {
+        this.keysize = keysize;
+        this.publicExponent = publicExponent;
+    }
+
+    /**
+     * Returns the keysize.
+     *
+     * @return the keysize.
+     */
+    public int getKeysize() {
+        return keysize;
+    }
+
+    /**
+     * Returns the public-exponent value.
+     *
+     * @return the public-exponent value.
+     */
+    public BigInteger getPublicExponent() {
+        return publicExponent;
+    }
+}
diff --git a/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java b/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java
new file mode 100644
index 0000000..a198e43
--- /dev/null
+++ b/java/security/spec/RSAMultiPrimePrivateCrtKeySpec.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies an RSA multi-prime private key, as defined in the
+ * PKCS#1 v2.1, using the Chinese Remainder Theorem (CRT) information
+ * values for efficiency.
+ *
+ * @author Valerie Peng
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see PKCS8EncodedKeySpec
+ * @see RSAPrivateKeySpec
+ * @see RSAPublicKeySpec
+ * @see RSAOtherPrimeInfo
+ *
+ * @since 1.4
+ */
+
+public class RSAMultiPrimePrivateCrtKeySpec extends RSAPrivateKeySpec {
+
+    private final BigInteger publicExponent;
+    private final BigInteger primeP;
+    private final BigInteger primeQ;
+    private final BigInteger primeExponentP;
+    private final BigInteger primeExponentQ;
+    private final BigInteger crtCoefficient;
+    private final RSAOtherPrimeInfo otherPrimeInfo[];
+
+   /**
+    * Creates a new {@code RSAMultiPrimePrivateCrtKeySpec}
+    * given the modulus, publicExponent, privateExponent,
+    * primeP, primeQ, primeExponentP, primeExponentQ,
+    * crtCoefficient, and otherPrimeInfo as defined in PKCS#1 v2.1.
+    *
+    * <p>Note that the contents of {@code otherPrimeInfo}
+    * are copied to protect against subsequent modification when
+    * constructing this object.
+    *
+    * @param modulus the modulus n.
+    * @param publicExponent the public exponent e.
+    * @param privateExponent the private exponent d.
+    * @param primeP the prime factor p of n.
+    * @param primeQ the prime factor q of n.
+    * @param primeExponentP this is d mod (p-1).
+    * @param primeExponentQ this is d mod (q-1).
+    * @param crtCoefficient the Chinese Remainder Theorem
+    * coefficient q-1 mod p.
+    * @param otherPrimeInfo triplets of the rest of primes, null can be
+    * specified if there are only two prime factors (p and q).
+    * @exception NullPointerException if any of the parameters, i.e.
+    * {@code modulus},
+    * {@code publicExponent}, {@code privateExponent},
+    * {@code primeP}, {@code primeQ},
+    * {@code primeExponentP}, {@code primeExponentQ},
+    * {@code crtCoefficient}, is null.
+    * @exception IllegalArgumentException if an empty, i.e. 0-length,
+    * {@code otherPrimeInfo} is specified.
+    */
+    public RSAMultiPrimePrivateCrtKeySpec(BigInteger modulus,
+                                BigInteger publicExponent,
+                                BigInteger privateExponent,
+                                BigInteger primeP,
+                                BigInteger primeQ,
+                                BigInteger primeExponentP,
+                                BigInteger primeExponentQ,
+                                BigInteger crtCoefficient,
+                                RSAOtherPrimeInfo[] otherPrimeInfo) {
+        super(modulus, privateExponent);
+        if (modulus == null) {
+            throw new NullPointerException("the modulus parameter must be " +
+                                            "non-null");
+        }
+        if (publicExponent == null) {
+            throw new NullPointerException("the publicExponent parameter " +
+                                            "must be non-null");
+        }
+        if (privateExponent == null) {
+            throw new NullPointerException("the privateExponent parameter " +
+                                            "must be non-null");
+        }
+        if (primeP == null) {
+            throw new NullPointerException("the primeP parameter " +
+                                            "must be non-null");
+        }
+        if (primeQ == null) {
+            throw new NullPointerException("the primeQ parameter " +
+                                            "must be non-null");
+        }
+        if (primeExponentP == null) {
+            throw new NullPointerException("the primeExponentP parameter " +
+                                            "must be non-null");
+        }
+        if (primeExponentQ == null) {
+            throw new NullPointerException("the primeExponentQ parameter " +
+                                            "must be non-null");
+        }
+        if (crtCoefficient == null) {
+            throw new NullPointerException("the crtCoefficient parameter " +
+                                            "must be non-null");
+        }
+        this.publicExponent = publicExponent;
+        this.primeP = primeP;
+        this.primeQ = primeQ;
+        this.primeExponentP = primeExponentP;
+        this.primeExponentQ = primeExponentQ;
+        this.crtCoefficient = crtCoefficient;
+        if (otherPrimeInfo == null)  {
+            this.otherPrimeInfo = null;
+        } else if (otherPrimeInfo.length == 0) {
+            throw new IllegalArgumentException("the otherPrimeInfo " +
+                                                "parameter must not be empty");
+        } else {
+            this.otherPrimeInfo = otherPrimeInfo.clone();
+        }
+    }
+
+    /**
+     * Returns the public exponent.
+     *
+     * @return the public exponent.
+     */
+    public BigInteger getPublicExponent() {
+        return this.publicExponent;
+    }
+
+    /**
+     * Returns the primeP.
+     *
+     * @return the primeP.
+     */
+    public BigInteger getPrimeP() {
+        return this.primeP;
+    }
+
+    /**
+     * Returns the primeQ.
+     *
+     * @return the primeQ.
+     */
+    public BigInteger getPrimeQ() {
+        return this.primeQ;
+    }
+
+    /**
+     * Returns the primeExponentP.
+     *
+     * @return the primeExponentP.
+     */
+    public BigInteger getPrimeExponentP() {
+        return this.primeExponentP;
+    }
+
+    /**
+     * Returns the primeExponentQ.
+     *
+     * @return the primeExponentQ.
+     */
+    public BigInteger getPrimeExponentQ() {
+        return this.primeExponentQ;
+    }
+
+    /**
+     * Returns the crtCoefficient.
+     *
+     * @return the crtCoefficient.
+     */
+    public BigInteger getCrtCoefficient() {
+        return this.crtCoefficient;
+    }
+
+    /**
+     * Returns a copy of the otherPrimeInfo or null if there are
+     * only two prime factors (p and q).
+     *
+     * @return the otherPrimeInfo. Returns a new array each
+     * time this method is called.
+     */
+    public RSAOtherPrimeInfo[] getOtherPrimeInfo() {
+        if (otherPrimeInfo == null) return null;
+        return otherPrimeInfo.clone();
+    }
+}
diff --git a/java/security/spec/RSAOtherPrimeInfo.java b/java/security/spec/RSAOtherPrimeInfo.java
new file mode 100644
index 0000000..10d8471
--- /dev/null
+++ b/java/security/spec/RSAOtherPrimeInfo.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class represents the triplet (prime, exponent, and coefficient)
+ * inside RSA's OtherPrimeInfo structure, as defined in the PKCS#1 v2.1.
+ * The ASN.1 syntax of RSA's OtherPrimeInfo is as follows:
+ *
+ * <pre>
+ * OtherPrimeInfo ::= SEQUENCE {
+ *   prime INTEGER,
+ *   exponent INTEGER,
+ *   coefficient INTEGER
+ *   }
+ *
+ * </pre>
+ *
+ * @author Valerie Peng
+ *
+ *
+ * @see RSAPrivateCrtKeySpec
+ * @see java.security.interfaces.RSAMultiPrimePrivateCrtKey
+ *
+ * @since 1.4
+ */
+
+public class RSAOtherPrimeInfo {
+
+    private BigInteger prime;
+    private BigInteger primeExponent;
+    private BigInteger crtCoefficient;
+
+
+   /**
+    * Creates a new {@code RSAOtherPrimeInfo}
+    * given the prime, primeExponent, and
+    * crtCoefficient as defined in PKCS#1.
+    *
+    * @param prime the prime factor of n.
+    * @param primeExponent the exponent.
+    * @param crtCoefficient the Chinese Remainder Theorem
+    * coefficient.
+    * @exception NullPointerException if any of the parameters, i.e.
+    * {@code prime}, {@code primeExponent},
+    * {@code crtCoefficient}, is null.
+    *
+    */
+    public RSAOtherPrimeInfo(BigInteger prime,
+                          BigInteger primeExponent,
+                          BigInteger crtCoefficient) {
+        if (prime == null) {
+            throw new NullPointerException("the prime parameter must be " +
+                                            "non-null");
+        }
+        if (primeExponent == null) {
+            throw new NullPointerException("the primeExponent parameter " +
+                                            "must be non-null");
+        }
+        if (crtCoefficient == null) {
+            throw new NullPointerException("the crtCoefficient parameter " +
+                                            "must be non-null");
+        }
+        this.prime = prime;
+        this.primeExponent = primeExponent;
+        this.crtCoefficient = crtCoefficient;
+    }
+
+    /**
+     * Returns the prime.
+     *
+     * @return the prime.
+     */
+    public final BigInteger getPrime() {
+        return this.prime;
+    }
+
+    /**
+     * Returns the prime's exponent.
+     *
+     * @return the primeExponent.
+     */
+    public final BigInteger getExponent() {
+        return this.primeExponent;
+    }
+
+    /**
+     * Returns the prime's crtCoefficient.
+     *
+     * @return the crtCoefficient.
+     */
+    public final BigInteger getCrtCoefficient() {
+        return this.crtCoefficient;
+    }
+}
diff --git a/java/security/spec/RSAPrivateCrtKeySpec.java b/java/security/spec/RSAPrivateCrtKeySpec.java
new file mode 100644
index 0000000..d0ba70b
--- /dev/null
+++ b/java/security/spec/RSAPrivateCrtKeySpec.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies an RSA private key, as defined in the PKCS#1
+ * standard, using the Chinese Remainder Theorem (CRT) information values for
+ * efficiency.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see PKCS8EncodedKeySpec
+ * @see RSAPrivateKeySpec
+ * @see RSAPublicKeySpec
+ */
+
+public class RSAPrivateCrtKeySpec extends RSAPrivateKeySpec {
+
+    private final BigInteger publicExponent;
+    private final BigInteger primeP;
+    private final BigInteger primeQ;
+    private final BigInteger primeExponentP;
+    private final BigInteger primeExponentQ;
+    private final BigInteger crtCoefficient;
+
+
+
+   /**
+    * Creates a new {@code RSAPrivateCrtKeySpec}
+    * given the modulus, publicExponent, privateExponent,
+    * primeP, primeQ, primeExponentP, primeExponentQ, and
+    * crtCoefficient as defined in PKCS#1.
+    *
+    * @param modulus the modulus n
+    * @param publicExponent the public exponent e
+    * @param privateExponent the private exponent d
+    * @param primeP the prime factor p of n
+    * @param primeQ the prime factor q of n
+    * @param primeExponentP this is d mod (p-1)
+    * @param primeExponentQ this is d mod (q-1)
+    * @param crtCoefficient the Chinese Remainder Theorem
+    * coefficient q-1 mod p
+    */
+    public RSAPrivateCrtKeySpec(BigInteger modulus,
+                                BigInteger publicExponent,
+                                BigInteger privateExponent,
+                                BigInteger primeP,
+                                BigInteger primeQ,
+                                BigInteger primeExponentP,
+                                BigInteger primeExponentQ,
+                                BigInteger crtCoefficient) {
+        super(modulus, privateExponent);
+        this.publicExponent = publicExponent;
+        this.primeP = primeP;
+        this.primeQ = primeQ;
+        this.primeExponentP = primeExponentP;
+        this.primeExponentQ = primeExponentQ;
+        this.crtCoefficient = crtCoefficient;
+    }
+
+    /**
+     * Returns the public exponent.
+     *
+     * @return the public exponent
+     */
+    public BigInteger getPublicExponent() {
+        return this.publicExponent;
+    }
+
+    /**
+     * Returns the primeP.
+
+     * @return the primeP
+     */
+    public BigInteger getPrimeP() {
+        return this.primeP;
+    }
+
+    /**
+     * Returns the primeQ.
+     *
+     * @return the primeQ
+     */
+    public BigInteger getPrimeQ() {
+        return this.primeQ;
+    }
+
+    /**
+     * Returns the primeExponentP.
+     *
+     * @return the primeExponentP
+     */
+    public BigInteger getPrimeExponentP() {
+        return this.primeExponentP;
+    }
+
+    /**
+     * Returns the primeExponentQ.
+     *
+     * @return the primeExponentQ
+     */
+    public BigInteger getPrimeExponentQ() {
+        return this.primeExponentQ;
+    }
+
+    /**
+     * Returns the crtCoefficient.
+     *
+     * @return the crtCoefficient
+     */
+    public BigInteger getCrtCoefficient() {
+        return this.crtCoefficient;
+    }
+}
diff --git a/java/security/spec/RSAPrivateKeySpec.java b/java/security/spec/RSAPrivateKeySpec.java
new file mode 100644
index 0000000..e749146
--- /dev/null
+++ b/java/security/spec/RSAPrivateKeySpec.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies an RSA private key.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see PKCS8EncodedKeySpec
+ * @see RSAPublicKeySpec
+ * @see RSAPrivateCrtKeySpec
+ */
+
+public class RSAPrivateKeySpec implements KeySpec {
+
+    private BigInteger modulus;
+    private BigInteger privateExponent;
+
+    /**
+     * Creates a new RSAPrivateKeySpec.
+     *
+     * @param modulus the modulus
+     * @param privateExponent the private exponent
+     */
+    public RSAPrivateKeySpec(BigInteger modulus, BigInteger privateExponent) {
+        this.modulus = modulus;
+        this.privateExponent = privateExponent;
+    }
+
+    /**
+     * Returns the modulus.
+     *
+     * @return the modulus
+     */
+    public BigInteger getModulus() {
+        return this.modulus;
+    }
+
+    /**
+     * Returns the private exponent.
+     *
+     * @return the private exponent
+     */
+    public BigInteger getPrivateExponent() {
+        return this.privateExponent;
+    }
+}
diff --git a/java/security/spec/RSAPublicKeySpec.java b/java/security/spec/RSAPublicKeySpec.java
new file mode 100644
index 0000000..9a944f9
--- /dev/null
+++ b/java/security/spec/RSAPublicKeySpec.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+import java.math.BigInteger;
+
+/**
+ * This class specifies an RSA public key.
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see X509EncodedKeySpec
+ * @see RSAPrivateKeySpec
+ * @see RSAPrivateCrtKeySpec
+ */
+
+public class RSAPublicKeySpec implements KeySpec {
+
+    private BigInteger modulus;
+    private BigInteger publicExponent;
+
+    /**
+     * Creates a new RSAPublicKeySpec.
+     *
+     * @param modulus the modulus
+     * @param publicExponent the public exponent
+     */
+    public RSAPublicKeySpec(BigInteger modulus, BigInteger publicExponent) {
+        this.modulus = modulus;
+        this.publicExponent = publicExponent;
+    }
+
+    /**
+     * Returns the modulus.
+     *
+     * @return the modulus
+     */
+    public BigInteger getModulus() {
+        return this.modulus;
+    }
+
+    /**
+     * Returns the public exponent.
+     *
+     * @return the public exponent
+     */
+    public BigInteger getPublicExponent() {
+        return this.publicExponent;
+    }
+}
diff --git a/java/security/spec/X509EncodedKeySpec.java b/java/security/spec/X509EncodedKeySpec.java
new file mode 100644
index 0000000..b9984de
--- /dev/null
+++ b/java/security/spec/X509EncodedKeySpec.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security.spec;
+
+/**
+ * This class represents the ASN.1 encoding of a public key,
+ * encoded according to the ASN.1 type {@code SubjectPublicKeyInfo}.
+ * The {@code SubjectPublicKeyInfo} syntax is defined in the X.509
+ * standard as follows:
+ *
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ *   algorithm AlgorithmIdentifier,
+ *   subjectPublicKey BIT STRING }
+ * </pre>
+ *
+ * @author Jan Luehe
+ *
+ *
+ * @see java.security.Key
+ * @see java.security.KeyFactory
+ * @see KeySpec
+ * @see EncodedKeySpec
+ * @see PKCS8EncodedKeySpec
+ *
+ * @since 1.2
+ */
+
+public class X509EncodedKeySpec extends EncodedKeySpec {
+
+    /**
+     * Creates a new X509EncodedKeySpec with the given encoded key.
+     *
+     * @param encodedKey the key, which is assumed to be
+     * encoded according to the X.509 standard. The contents of the
+     * array are copied to protect against subsequent modification.
+     * @exception NullPointerException if {@code encodedKey}
+     * is null.
+     */
+    public X509EncodedKeySpec(byte[] encodedKey) {
+        super(encodedKey);
+    }
+
+    /**
+     * Returns the key bytes, encoded according to the X.509 standard.
+     *
+     * @return the X.509 encoding of the key. Returns a new array
+     * each time this method is called.
+     */
+    public byte[] getEncoded() {
+        return super.getEncoded();
+    }
+
+    /**
+     * Returns the name of the encoding format associated with this
+     * key specification.
+     *
+     * @return the string {@code "X.509"}.
+     */
+    public final String getFormat() {
+        return "X.509";
+    }
+}
diff --git a/java/security/spec/package-info.java b/java/security/spec/package-info.java
new file mode 100644
index 0000000..cb39308
--- /dev/null
+++ b/java/security/spec/package-info.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Provides classes and interfaces for key specifications and algorithm
+ * parameter specifications.
+ *
+ * <p>A key specification is a transparent representation of the key material
+ * that constitutes a key. A key may be specified in an algorithm-specific
+ * way, or in an algorithm-independent encoding format (such as ASN.1).
+ * This package contains key specifications for DSA public and private keys,
+ * RSA public and private keys, PKCS #8 private keys in DER-encoded format,
+ * and X.509 public and private keys in DER-encoded format.
+ *
+ * <p>An algorithm parameter specification is a transparent representation
+ * of the sets of parameters used with an algorithm. This package contains
+ * an algorithm parameter specification for parameters used with the
+ * DSA algorithm.
+ *
+ * <h2>Package Specification</h2>
+ *
+ * <ul>
+ *   <li>PKCS #1: RSA Encryption Standard, Version 1.5, November 1993</li>
+ *   <li>PKCS #8: Private-Key Information Syntax Standard,
+ *     Version 1.2, November 1993</li>
+ *   <li>Federal Information Processing Standards Publication (FIPS PUB) 186:
+ *     Digital Signature Standard (DSS)</li>
+ * </ul>
+ *
+ * <h2>Related Documentation</h2>
+ *
+ * For documentation that includes information about algorithm parameter
+ * and key specifications, please see:
+ * <ul>
+ *   <li>
+ *     <a href=
+ *       "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
+ *       <b>Java&trade;
+ *       Cryptography Architecture API Specification and Reference
+ *       </b></a></li>
+ *   <li>
+ *     <a href=
+ *       "{@docRoot}/../technotes/guides/security/crypto/HowToImplAProvider.html">
+ *       <b>How to Implement a Provider for the
+ *       Java&trade; Cryptography Architecture
+ *       </b></a></li>
+ * </ul>
+ *
+ * @since 1.2
+ */
+package java.security.spec;
diff --git a/java/sql/Array.java b/java/sql/Array.java
new file mode 100644
index 0000000..584c63f
--- /dev/null
+++ b/java/sql/Array.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The mapping in the Java programming language for the SQL type
+ * <code>ARRAY</code>.
+ * By default, an <code>Array</code> value is a transaction-duration
+ * reference to an SQL <code>ARRAY</code> value.  By default, an <code>Array</code>
+ * object is implemented using an SQL LOCATOR(array) internally, which
+ * means that an <code>Array</code> object contains a logical pointer
+ * to the data in the SQL <code>ARRAY</code> value rather
+ * than containing the <code>ARRAY</code> value's data.
+ * <p>
+ * The <code>Array</code> interface provides methods for bringing an SQL
+ * <code>ARRAY</code> value's data to the client as either an array or a
+ * <code>ResultSet</code> object.
+ * If the elements of the SQL <code>ARRAY</code>
+ * are a UDT, they may be custom mapped.  To create a custom mapping,
+ * a programmer must do two things:
+ * <ul>
+ * <li>create a class that implements the {@link SQLData}
+ * interface for the UDT to be custom mapped.
+ * <li>make an entry in a type map that contains
+ *   <ul>
+ *   <li>the fully-qualified SQL type name of the UDT
+ *   <li>the <code>Class</code> object for the class implementing
+ *       <code>SQLData</code>
+ *   </ul>
+ * </ul>
+ * <p>
+ * When a type map with an entry for
+ * the base type is supplied to the methods <code>getArray</code>
+ * and <code>getResultSet</code>, the mapping
+ * it contains will be used to map the elements of the <code>ARRAY</code> value.
+ * If no type map is supplied, which would typically be the case,
+ * the connection's type map is used by default.
+ * If the connection's type map or a type map supplied to a method has no entry
+ * for the base type, the elements are mapped according to the standard mapping.
+ * <p>
+ * All methods on the <code>Array</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @since 1.2
+ */
+
+public interface Array {
+
+  /**
+   * Retrieves the SQL type name of the elements in
+   * the array designated by this <code>Array</code> object.
+   * If the elements are a built-in type, it returns
+   * the database-specific type name of the elements.
+   * If the elements are a user-defined type (UDT),
+   * this method returns the fully-qualified SQL type name.
+   *
+   * @return a <code>String</code> that is the database-specific
+   * name for a built-in base type; or the fully-qualified SQL type
+   * name for a base type that is a UDT
+   * @exception SQLException if an error occurs while attempting
+   * to access the type name
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  String getBaseTypeName() throws SQLException;
+
+  /**
+   * Retrieves the JDBC type of the elements in the array designated
+   * by this <code>Array</code> object.
+   *
+   * @return a constant from the class {@link java.sql.Types} that is
+   * the type code for the elements in the array designated by this
+   * <code>Array</code> object
+   * @exception SQLException if an error occurs while attempting
+   * to access the base type
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  int getBaseType() throws SQLException;
+
+  /**
+   * Retrieves the contents of the SQL <code>ARRAY</code> value designated
+   * by this
+   * <code>Array</code> object in the form of an array in the Java
+   * programming language. This version of the method <code>getArray</code>
+   * uses the type map associated with the connection for customizations of
+   * the type mappings.
+   * <p>
+   * <strong>Note:</strong> When <code>getArray</code> is used to materialize
+   * a base type that maps to a primitive data type, then it is
+   * implementation-defined whether the array returned is an array of
+   * that primitive data type or an array of <code>Object</code>.
+   *
+   * @return an array in the Java programming language that contains
+   * the ordered elements of the SQL <code>ARRAY</code> value
+   * designated by this <code>Array</code> object
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  Object getArray() throws SQLException;
+
+  /**
+   * Retrieves the contents of the SQL <code>ARRAY</code> value designated by this
+   * <code>Array</code> object.
+   * This method uses
+   * the specified <code>map</code> for type map customizations
+   * unless the base type of the array does not match a user-defined
+   * type in <code>map</code>, in which case it
+   * uses the standard mapping. This version of the method
+   * <code>getArray</code> uses either the given type map or the standard mapping;
+   * it never uses the type map associated with the connection.
+   * <p>
+   * <strong>Note:</strong> When <code>getArray</code> is used to materialize
+   * a base type that maps to a primitive data type, then it is
+   * implementation-defined whether the array returned is an array of
+   * that primitive data type or an array of <code>Object</code>.
+   *
+   * @param map a <code>java.util.Map</code> object that contains mappings
+   *            of SQL type names to classes in the Java programming language
+   * @return an array in the Java programming language that contains the ordered
+   *         elements of the SQL array designated by this object
+   * @exception SQLException if an error occurs while attempting to
+   *                         access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  Object getArray(java.util.Map<String,Class<?>> map) throws SQLException;
+
+  /**
+   * Retrieves a slice of the SQL <code>ARRAY</code>
+   * value designated by this <code>Array</code> object, beginning with the
+   * specified <code>index</code> and containing up to <code>count</code>
+   * successive elements of the SQL array.  This method uses the type map
+   * associated with the connection for customizations of the type mappings.
+   * <p>
+   * <strong>Note:</strong> When <code>getArray</code> is used to materialize
+   * a base type that maps to a primitive data type, then it is
+   * implementation-defined whether the array returned is an array of
+   * that primitive data type or an array of <code>Object</code>.
+   *
+   * @param index the array index of the first element to retrieve;
+   *              the first element is at index 1
+   * @param count the number of successive SQL array elements to retrieve
+   * @return an array containing up to <code>count</code> consecutive elements
+   * of the SQL array, beginning with element <code>index</code>
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  Object getArray(long index, int count) throws SQLException;
+
+  /**
+   * Retreives a slice of the SQL <code>ARRAY</code> value
+   * designated by this <code>Array</code> object, beginning with the specified
+   * <code>index</code> and containing up to <code>count</code>
+   * successive elements of the SQL array.
+   * <P>
+   * This method uses
+   * the specified <code>map</code> for type map customizations
+   * unless the base type of the array does not match a user-defined
+   * type in <code>map</code>, in which case it
+   * uses the standard mapping. This version of the method
+   * <code>getArray</code> uses either the given type map or the standard mapping;
+   * it never uses the type map associated with the connection.
+   * <p>
+   * <strong>Note:</strong> When <code>getArray</code> is used to materialize
+   * a base type that maps to a primitive data type, then it is
+   * implementation-defined whether the array returned is an array of
+   * that primitive data type or an array of <code>Object</code>.
+   *
+   * @param index the array index of the first element to retrieve;
+   *              the first element is at index 1
+   * @param count the number of successive SQL array elements to
+   * retrieve
+   * @param map a <code>java.util.Map</code> object
+   * that contains SQL type names and the classes in
+   * the Java programming language to which they are mapped
+   * @return an array containing up to <code>count</code>
+   * consecutive elements of the SQL <code>ARRAY</code> value designated by this
+   * <code>Array</code> object, beginning with element
+   * <code>index</code>
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  Object getArray(long index, int count, java.util.Map<String,Class<?>> map)
+    throws SQLException;
+
+  /**
+   * Retrieves a result set that contains the elements of the SQL
+   * <code>ARRAY</code> value
+   * designated by this <code>Array</code> object.  If appropriate,
+   * the elements of the array are mapped using the connection's type
+   * map; otherwise, the standard mapping is used.
+   * <p>
+   * The result set contains one row for each array element, with
+   * two columns in each row.  The second column stores the element
+   * value; the first column stores the index into the array for
+   * that element (with the first array element being at index 1).
+   * The rows are in ascending order corresponding to
+   * the order of the indices.
+   *
+   * @return a {@link ResultSet} object containing one row for each
+   * of the elements in the array designated by this <code>Array</code>
+   * object, with the rows in ascending order based on the indices.
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  ResultSet getResultSet () throws SQLException;
+
+  /**
+   * Retrieves a result set that contains the elements of the SQL
+   * <code>ARRAY</code> value designated by this <code>Array</code> object.
+   * This method uses
+   * the specified <code>map</code> for type map customizations
+   * unless the base type of the array does not match a user-defined
+   * type in <code>map</code>, in which case it
+   * uses the standard mapping. This version of the method
+   * <code>getResultSet</code> uses either the given type map or the standard mapping;
+   * it never uses the type map associated with the connection.
+   * <p>
+   * The result set contains one row for each array element, with
+   * two columns in each row.  The second column stores the element
+   * value; the first column stores the index into the array for
+   * that element (with the first array element being at index 1).
+   * The rows are in ascending order corresponding to
+   * the order of the indices.
+   *
+   * @param map contains the mapping of SQL user-defined types to
+   * classes in the Java programming language
+   * @return a <code>ResultSet</code> object containing one row for each
+   * of the elements in the array designated by this <code>Array</code>
+   * object, with the rows in ascending order based on the indices.
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  ResultSet getResultSet (java.util.Map<String,Class<?>> map) throws SQLException;
+
+  /**
+   * Retrieves a result set holding the elements of the subarray that
+   * starts at index <code>index</code> and contains up to
+   * <code>count</code> successive elements.  This method uses
+   * the connection's type map to map the elements of the array if
+   * the map contains an entry for the base type. Otherwise, the
+   * standard mapping is used.
+   * <P>
+   * The result set has one row for each element of the SQL array
+   * designated by this object, with the first row containing the
+   * element at index <code>index</code>.  The result set has
+   * up to <code>count</code> rows in ascending order based on the
+   * indices.  Each row has two columns:  The second column stores
+   * the element value; the first column stores the index into the
+   * array for that element.
+   *
+   * @param index the array index of the first element to retrieve;
+   *              the first element is at index 1
+   * @param count the number of successive SQL array elements to retrieve
+   * @return a <code>ResultSet</code> object containing up to
+   * <code>count</code> consecutive elements of the SQL array
+   * designated by this <code>Array</code> object, starting at
+   * index <code>index</code>.
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  ResultSet getResultSet(long index, int count) throws SQLException;
+
+  /**
+   * Retrieves a result set holding the elements of the subarray that
+   * starts at index <code>index</code> and contains up to
+   * <code>count</code> successive elements.
+   * This method uses
+   * the specified <code>map</code> for type map customizations
+   * unless the base type of the array does not match a user-defined
+   * type in <code>map</code>, in which case it
+   * uses the standard mapping. This version of the method
+   * <code>getResultSet</code> uses either the given type map or the standard mapping;
+   * it never uses the type map associated with the connection.
+   * <P>
+   * The result set has one row for each element of the SQL array
+   * designated by this object, with the first row containing the
+   * element at index <code>index</code>.  The result set has
+   * up to <code>count</code> rows in ascending order based on the
+   * indices.  Each row has two columns:  The second column stores
+   * the element value; the first column stroes the index into the
+   * array for that element.
+   *
+   * @param index the array index of the first element to retrieve;
+   *              the first element is at index 1
+   * @param count the number of successive SQL array elements to retrieve
+   * @param map the <code>Map</code> object that contains the mapping
+   * of SQL type names to classes in the Java(tm) programming language
+   * @return a <code>ResultSet</code> object containing up to
+   * <code>count</code> consecutive elements of the SQL array
+   * designated by this <code>Array</code> object, starting at
+   * index <code>index</code>.
+   * @exception SQLException if an error occurs while attempting to
+   * access the array
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  ResultSet getResultSet (long index, int count,
+                          java.util.Map<String,Class<?>> map)
+    throws SQLException;
+    /**
+     * This method frees the <code>Array</code> object and releases the resources that
+     * it holds. The object is invalid once the <code>free</code>
+     * method is called.
+     *<p>
+     * After <code>free</code> has been called, any attempt to invoke a
+     * method other than <code>free</code> will result in a <code>SQLException</code>
+     * being thrown.  If <code>free</code> is called multiple times, the subsequent
+     * calls to <code>free</code> are treated as a no-op.
+     *<p>
+     *
+     * @throws SQLException if an error occurs releasing
+     * the Array's resources
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void free() throws SQLException;
+
+}
diff --git a/java/sql/BatchUpdateException.java b/java/sql/BatchUpdateException.java
new file mode 100644
index 0000000..19742c8
--- /dev/null
+++ b/java/sql/BatchUpdateException.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.Arrays;
+
+/**
+ * The subclass of {@link SQLException} thrown when an error
+ * occurs during a batch update operation.  In addition to the
+ * information provided by {@link SQLException}, a
+ * <code>BatchUpdateException</code> provides the update
+ * counts for all commands that were executed successfully during the
+ * batch update, that is, all commands that were executed before the error
+ * occurred.  The order of elements in an array of update counts
+ * corresponds to the order in which commands were added to the batch.
+ * <P>
+ * After a command in a batch update fails to execute properly
+ * and a <code>BatchUpdateException</code> is thrown, the driver
+ * may or may not continue to process the remaining commands in
+ * the batch.  If the driver continues processing after a failure,
+ * the array returned by the method
+ * <code>BatchUpdateException.getUpdateCounts</code> will have
+ * an element for every command in the batch rather than only
+ * elements for the commands that executed successfully before
+ * the error.  In the case where the driver continues processing
+ * commands, the array element for any command
+ * that failed is <code>Statement.EXECUTE_FAILED</code>.
+ * <P>
+ * @since 1.2
+ */
+
+public class BatchUpdateException extends SQLException {
+
+  /**
+   * Constructs a <code>BatchUpdateException</code> object initialized with a given
+   * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code> and
+   * <code>updateCounts</code>.
+   * The <code>cause</code> is not initialized, and may subsequently be
+   * initialized by a call to the
+   * {@link Throwable#initCause(java.lang.Throwable)} method.
+   * <p>
+   *
+   * @param reason a description of the error
+   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+   * @param vendorCode an exception code used by a particular
+   * database vendor
+   * @param updateCounts an array of <code>int</code>, with each element
+   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+   * @since 1.2
+   */
+  public BatchUpdateException( String reason, String SQLState, int vendorCode,
+                               int[] updateCounts ) {
+      super(reason, SQLState, vendorCode);
+      this.updateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
+  }
+
+  /**
+   * Constructs a <code>BatchUpdateException</code> object initialized with a given
+   * <code>reason</code>, <code>SQLState</code> and
+   * <code>updateCounts</code>.
+   * The <code>cause</code> is not initialized, and may subsequently be
+   * initialized by a call to the
+   * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+   * is initialized to 0.
+   * <p>
+   *
+   * @param reason a description of the exception
+   * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+   * @param updateCounts an array of <code>int</code>, with each element
+   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+   * @since 1.2
+   */
+  public BatchUpdateException(String reason, String SQLState,
+                              int[] updateCounts) {
+      this(reason, SQLState, 0, updateCounts);
+  }
+
+  /**
+   * Constructs a <code>BatchUpdateException</code> object initialized with a given
+   * <code>reason</code> and <code>updateCounts</code>.
+   * The <code>cause</code> is not initialized, and may subsequently be
+   * initialized by a call to the
+   * {@link Throwable#initCause(java.lang.Throwable)} method.  The
+   * <code>SQLState</code> is initialized to <code>null</code>
+   * and the vender code is initialized to 0.
+   * <p>
+   *
+   *
+   * @param reason a description of the exception
+   * @param updateCounts an array of <code>int</code>, with each element
+   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+   * @since 1.2
+   */
+  public  BatchUpdateException(String reason, int[] updateCounts) {
+      this(reason, null, 0, updateCounts);
+  }
+
+  /**
+   * Constructs a <code>BatchUpdateException</code> object initialized with a given
+   * <code>updateCounts</code>.
+   * initialized by a call to the
+   * {@link Throwable#initCause(java.lang.Throwable)} method. The  <code>reason</code>
+   * and <code>SQLState</code> are initialized to null and the vendor code
+   * is initialized to 0.
+   * <p>
+   *
+   * @param updateCounts an array of <code>int</code>, with each element
+   * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+   * @since 1.2
+   */
+  public BatchUpdateException(int[] updateCounts) {
+      this(null, null, 0, updateCounts);
+  }
+
+  /**
+   * Constructs a <code>BatchUpdateException</code> object.
+   * The <code>reason</code>, <code>SQLState</code> and <code>updateCounts</code>
+   *  are initialized to <code>null</code> and the vendor code is initialized to 0.
+   * The <code>cause</code> is not initialized, and may subsequently be
+   * initialized by a call to the
+   * {@link Throwable#initCause(java.lang.Throwable)} method.
+   * <p>
+   *
+   * @since 1.2
+   */
+  public BatchUpdateException() {
+        this(null, null, 0, null);
+  }
+
+    /**
+     * Constructs a <code>BatchUpdateException</code> object initialized with
+     *  a given <code>cause</code>.
+     * The <code>SQLState</code> and <code>updateCounts</code>
+     * are initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     *  <code>cause!=null</code>.
+     * @param cause the underlying reason for this <code>SQLException</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public BatchUpdateException(Throwable cause) {
+        this((cause == null ? null : cause.toString()), null, 0, null, cause);
+    }
+
+    /**
+     * Constructs a <code>BatchUpdateException</code> object initialized with a
+     * given <code>cause</code> and <code>updateCounts</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     *
+     * @param updateCounts an array of <code>int</code>, with each element
+     * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+     * @param cause the underlying reason for this <code>SQLException</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     * the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public BatchUpdateException(int []updateCounts , Throwable cause) {
+        this((cause == null ? null : cause.toString()), null, 0, updateCounts, cause);
+    }
+
+    /**
+     * Constructs a <code>BatchUpdateException</code> object initialized with
+     * a given <code>reason</code>, <code>cause</code>
+     * and <code>updateCounts</code>. The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     *
+     * @param reason a description of the exception
+     * @param updateCounts an array of <code>int</code>, with each element
+     *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating
+     * the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public BatchUpdateException(String reason, int []updateCounts, Throwable cause) {
+        this(reason, null, 0, updateCounts, cause);
+    }
+
+    /**
+     * Constructs a <code>BatchUpdateException</code> object initialized with
+     * a given <code>reason</code>, <code>SQLState</code>,<code>cause</code>, and
+   * <code>updateCounts</code>. The vendor code is initialized to 0.
+     *
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param updateCounts an array of <code>int</code>, with each element
+     * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating
+     * the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public BatchUpdateException(String reason, String SQLState,
+                                int []updateCounts, Throwable cause) {
+        this(reason, SQLState, 0, updateCounts, cause);
+    }
+
+    /**
+     * Constructs a <code>BatchUpdateException</code> object initialized with
+     * a given <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * <code>cause</code> and <code>updateCounts</code>.
+     *
+     * @param reason a description of the error
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode an exception code used by a particular
+     * database vendor
+     * @param updateCounts an array of <code>int</code>, with each element
+     *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
+   * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
+   * the batch for JDBC drivers that continue processing
+   * after a command failure; an update count or
+   * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
+   * prior to the failure for JDBC drivers that stop processing after a command
+   * failure
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating
+     * the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public BatchUpdateException(String reason, String SQLState, int vendorCode,
+                                int []updateCounts,Throwable cause) {
+        super(reason, SQLState, vendorCode, cause);
+        this.updateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
+    }
+
+  /**
+   * Retrieves the update count for each update statement in the batch
+   * update that executed successfully before this exception occurred.
+   * A driver that implements batch updates may or may not continue to
+   * process the remaining commands in a batch when one of the commands
+   * fails to execute properly. If the driver continues processing commands,
+   * the array returned by this method will have as many elements as
+   * there are commands in the batch; otherwise, it will contain an
+   * update count for each command that executed successfully before
+   * the <code>BatchUpdateException</code> was thrown.
+   *<P>
+   * The possible return values for this method were modified for
+   * the Java 2 SDK, Standard Edition, version 1.3.  This was done to
+   * accommodate the new option of continuing to process commands
+   * in a batch update after a <code>BatchUpdateException</code> object
+   * has been thrown.
+   *
+   * @return an array of <code>int</code> containing the update counts
+   * for the updates that were executed successfully before this error
+   * occurred.  Or, if the driver continues to process commands after an
+   * error, one of the following for every command in the batch:
+   * <OL>
+   * <LI>an update count
+   *  <LI><code>Statement.SUCCESS_NO_INFO</code> to indicate that the command
+   *     executed successfully but the number of rows affected is unknown
+   *  <LI><code>Statement.EXECUTE_FAILED</code> to indicate that the command
+   *     failed to execute successfully
+   * </OL>
+   * @since 1.3
+   */
+  public int[] getUpdateCounts() {
+      return (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
+  }
+
+  /**
+   * The array that describes the outcome of a batch execution.
+   * @serial
+   * @since 1.2
+   */
+  private final int[] updateCounts;
+
+  private static final long serialVersionUID = 5977529877145521757L;
+}
diff --git a/java/sql/Blob.java b/java/sql/Blob.java
new file mode 100644
index 0000000..46b7c2f
--- /dev/null
+++ b/java/sql/Blob.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.io.InputStream;
+
+/**
+ * The representation (mapping) in
+ * the Java<sup><font size=-2>TM</font></sup> programming
+ * language of an SQL
+ * <code>BLOB</code> value.  An SQL <code>BLOB</code> is a built-in type
+ * that stores a Binary Large Object as a column value in a row of
+ * a database table. By default drivers implement <code>Blob</code> using
+ * an SQL <code>locator(BLOB)</code>, which means that a
+ * <code>Blob</code> object contains a logical pointer to the
+ * SQL <code>BLOB</code> data rather than the data itself.
+ * A <code>Blob</code> object is valid for the duration of the
+ * transaction in which is was created.
+ *
+ * <P>Methods in the interfaces {@link ResultSet},
+ * {@link CallableStatement}, and {@link PreparedStatement}, such as
+ * <code>getBlob</code> and <code>setBlob</code> allow a programmer to
+ * access an SQL <code>BLOB</code> value.
+ * The <code>Blob</code> interface provides methods for getting the
+ * length of an SQL <code>BLOB</code> (Binary Large Object) value,
+ * for materializing a <code>BLOB</code> value on the client, and for
+ * determining the position of a pattern of bytes within a
+ * <code>BLOB</code> value. In addition, this interface has methods for updating
+ * a <code>BLOB</code> value.
+ * <p>
+ * All methods on the <code>Blob</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @since 1.2
+ */
+
+public interface Blob {
+
+  /**
+   * Returns the number of bytes in the <code>BLOB</code> value
+   * designated by this <code>Blob</code> object.
+   * @return length of the <code>BLOB</code> in bytes
+   * @exception SQLException if there is an error accessing the
+   * length of the <code>BLOB</code>
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  long length() throws SQLException;
+
+  /**
+   * Retrieves all or part of the <code>BLOB</code>
+   * value that this <code>Blob</code> object represents, as an array of
+   * bytes.  This <code>byte</code> array contains up to <code>length</code>
+   * consecutive bytes starting at position <code>pos</code>.
+   *
+   * @param pos the ordinal position of the first byte in the
+   *        <code>BLOB</code> value to be extracted; the first byte is at
+   *        position 1
+   * @param length the number of consecutive bytes to be copied; the value
+   * for length must be 0 or greater
+   * @return a byte array containing up to <code>length</code>
+   *         consecutive bytes from the <code>BLOB</code> value designated
+   *         by this <code>Blob</code> object, starting with the
+   *         byte at position <code>pos</code>
+   * @exception SQLException if there is an error accessing the
+   *            <code>BLOB</code> value; if pos is less than 1 or length is
+   * less than 0
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @see #setBytes
+   * @since 1.2
+   */
+  byte[] getBytes(long pos, int length) throws SQLException;
+
+  /**
+   * Retrieves the <code>BLOB</code> value designated by this
+   * <code>Blob</code> instance as a stream.
+   *
+   * @return a stream containing the <code>BLOB</code> data
+   * @exception SQLException if there is an error accessing the
+   *            <code>BLOB</code> value
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @see #setBinaryStream
+   * @since 1.2
+   */
+  java.io.InputStream getBinaryStream () throws SQLException;
+
+  /**
+   * Retrieves the byte position at which the specified byte array
+   * <code>pattern</code> begins within the <code>BLOB</code>
+   * value that this <code>Blob</code> object represents.  The
+   * search for <code>pattern</code> begins at position
+   * <code>start</code>.
+   *
+   * @param pattern the byte array for which to search
+   * @param start the position at which to begin searching; the
+   *        first position is 1
+   * @return the position at which the pattern appears, else -1
+   * @exception SQLException if there is an error accessing the
+   * <code>BLOB</code> or if start is less than 1
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  long position(byte pattern[], long start) throws SQLException;
+
+  /**
+   * Retrieves the byte position in the <code>BLOB</code> value
+   * designated by this <code>Blob</code> object at which
+   * <code>pattern</code> begins.  The search begins at position
+   * <code>start</code>.
+   *
+   * @param pattern the <code>Blob</code> object designating
+   * the <code>BLOB</code> value for which to search
+   * @param start the position in the <code>BLOB</code> value
+   *        at which to begin searching; the first position is 1
+   * @return the position at which the pattern begins, else -1
+   * @exception SQLException if there is an error accessing the
+   *            <code>BLOB</code> value or if start is less than 1
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  long position(Blob pattern, long start) throws SQLException;
+
+    // -------------------------- JDBC 3.0 -----------------------------------
+
+    /**
+     * Writes the given array of bytes to the <code>BLOB</code> value that
+     * this <code>Blob</code> object represents, starting at position
+     * <code>pos</code>, and returns the number of bytes written.
+     * The array of bytes will overwrite the existing bytes
+     * in the <code>Blob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Blob</code> value is reached
+     * while writing the array of bytes, then the length of the <code>Blob</code>
+     * value will be increased to accomodate the extra bytes.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>BLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param pos the position in the <code>BLOB</code> object at which
+     *        to start writing; the first position is 1
+     * @param bytes the array of bytes to be written to the <code>BLOB</code>
+     *        value that this <code>Blob</code> object represents
+     * @return the number of bytes written
+     * @exception SQLException if there is an error accessing the
+     *            <code>BLOB</code> value or if pos is less than 1
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getBytes
+     * @since 1.4
+     */
+    int setBytes(long pos, byte[] bytes) throws SQLException;
+
+    /**
+     * Writes all or part of the given <code>byte</code> array to the
+     * <code>BLOB</code> value that this <code>Blob</code> object represents
+     * and returns the number of bytes written.
+     * Writing starts at position <code>pos</code> in the <code>BLOB</code>
+     * value; <code>len</code> bytes from the given byte array are written.
+     * The array of bytes will overwrite the existing bytes
+     * in the <code>Blob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Blob</code> value is reached
+     * while writing the array of bytes, then the length of the <code>Blob</code>
+     * value will be increased to accomodate the extra bytes.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>BLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param pos the position in the <code>BLOB</code> object at which
+     *        to start writing; the first position is 1
+     * @param bytes the array of bytes to be written to this <code>BLOB</code>
+     *        object
+     * @param offset the offset into the array <code>bytes</code> at which
+     *        to start reading the bytes to be set
+     * @param len the number of bytes to be written to the <code>BLOB</code>
+     *        value from the array of bytes <code>bytes</code>
+     * @return the number of bytes written
+     * @exception SQLException if there is an error accessing the
+     *            <code>BLOB</code> value or if pos is less than 1
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getBytes
+     * @since 1.4
+     */
+    int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException;
+
+    /**
+     * Retrieves a stream that can be used to write to the <code>BLOB</code>
+     * value that this <code>Blob</code> object represents.  The stream begins
+     * at position <code>pos</code>.
+     * The  bytes written to the stream will overwrite the existing bytes
+     * in the <code>Blob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Blob</code> value is reached
+     * while writing to the stream, then the length of the <code>Blob</code>
+     * value will be increased to accomodate the extra bytes.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>BLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param pos the position in the <code>BLOB</code> value at which
+     *        to start writing; the first position is 1
+     * @return a <code>java.io.OutputStream</code> object to which data can
+     *         be written
+     * @exception SQLException if there is an error accessing the
+     *            <code>BLOB</code> value or if pos is less than 1
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getBinaryStream
+     * @since 1.4
+     */
+    java.io.OutputStream setBinaryStream(long pos) throws SQLException;
+
+    /**
+     * Truncates the <code>BLOB</code> value that this <code>Blob</code>
+     * object represents to be <code>len</code> bytes in length.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>BLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param len the length, in bytes, to which the <code>BLOB</code> value
+     *        that this <code>Blob</code> object represents should be truncated
+     * @exception SQLException if there is an error accessing the
+     *            <code>BLOB</code> value or if len is less than 0
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void truncate(long len) throws SQLException;
+
+    /**
+     * This method frees the <code>Blob</code> object and releases the resources that
+     * it holds. The object is invalid once the <code>free</code>
+     * method is called.
+     *<p>
+     * After <code>free</code> has been called, any attempt to invoke a
+     * method other than <code>free</code> will result in a <code>SQLException</code>
+     * being thrown.  If <code>free</code> is called multiple times, the subsequent
+     * calls to <code>free</code> are treated as a no-op.
+     *<p>
+     *
+     * @throws SQLException if an error occurs releasing
+     * the Blob's resources
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void free() throws SQLException;
+
+    /**
+     * Returns an <code>InputStream</code> object that contains a partial <code>Blob</code> value,
+     * starting  with the byte specified by pos, which is length bytes in length.
+     *
+     * @param pos the offset to the first byte of the partial value to be retrieved.
+     *  The first byte in the <code>Blob</code> is at position 1
+     * @param length the length in bytes of the partial value to be retrieved
+     * @return <code>InputStream</code> through which the partial <code>Blob</code> value can be read.
+     * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes
+     * in the <code>Blob</code> or if pos + length is greater than the number of bytes
+     * in the <code>Blob</code>
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    InputStream getBinaryStream(long pos, long length) throws SQLException;
+}
diff --git a/java/sql/CallableStatement.java b/java/sql/CallableStatement.java
new file mode 100644
index 0000000..d58c88b
--- /dev/null
+++ b/java/sql/CallableStatement.java
@@ -0,0 +1,2444 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.io.Reader;
+import java.io.InputStream;
+
+/**
+ * The interface used to execute SQL stored procedures.  The JDBC API
+ * provides a stored procedure SQL escape syntax that allows stored procedures
+ * to be called in a standard way for all RDBMSs. This escape syntax has one
+ * form that includes a result parameter and one that does not. If used, the result
+ * parameter must be registered as an OUT parameter. The other parameters
+ * can be used for input, output or both. Parameters are referred to
+ * sequentially, by number, with the first parameter being 1.
+ * <PRE>
+ *   {?= call &lt;procedure-name&gt;[(&lt;arg1&gt;,&lt;arg2&gt;, ...)]}
+ *   {call &lt;procedure-name&gt;[(&lt;arg1&gt;,&lt;arg2&gt;, ...)]}
+ * </PRE>
+ * <P>
+ * IN parameter values are set using the <code>set</code> methods inherited from
+ * {@link PreparedStatement}.  The type of all OUT parameters must be
+ * registered prior to executing the stored procedure; their values
+ * are retrieved after execution via the <code>get</code> methods provided here.
+ * <P>
+ * A <code>CallableStatement</code> can return one {@link ResultSet} object or
+ * multiple <code>ResultSet</code> objects.  Multiple
+ * <code>ResultSet</code> objects are handled using operations
+ * inherited from {@link Statement}.
+ * <P>
+ * For maximum portability, a call's <code>ResultSet</code> objects and
+ * update counts should be processed prior to getting the values of output
+ * parameters.
+ * <P>
+ *
+ * @see Connection#prepareCall
+ * @see ResultSet
+ */
+
+public interface CallableStatement extends PreparedStatement {
+
+    /**
+     * Registers the OUT parameter in ordinal position
+     * <code>parameterIndex</code> to the JDBC type
+     * <code>sqlType</code>.  All OUT parameters must be registered
+     * before a stored procedure is executed.
+     * <p>
+     * The JDBC type specified by <code>sqlType</code> for an OUT
+     * parameter determines the Java type that must be used
+     * in the <code>get</code> method to read the value of that parameter.
+     * <p>
+     * If the JDBC type expected to be returned to this output parameter
+     * is specific to this particular database, <code>sqlType</code>
+     * should be <code>java.sql.Types.OTHER</code>.  The method
+     * {@link #getObject} retrieves the value.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @param sqlType the JDBC type code defined by <code>java.sql.Types</code>.
+     *        If the parameter is of JDBC type <code>NUMERIC</code>
+     *        or <code>DECIMAL</code>, the version of
+     *        <code>registerOutParameter</code> that accepts a scale value
+     *        should be used.
+     *
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     * @see Types
+     */
+    void registerOutParameter(int parameterIndex, int sqlType)
+        throws SQLException;
+
+    /**
+     * Registers the parameter in ordinal position
+     * <code>parameterIndex</code> to be of JDBC type
+     * <code>sqlType</code>. All OUT parameters must be registered
+     * before a stored procedure is executed.
+     * <p>
+     * The JDBC type specified by <code>sqlType</code> for an OUT
+     * parameter determines the Java type that must be used
+     * in the <code>get</code> method to read the value of that parameter.
+     * <p>
+     * This version of <code>registerOutParameter</code> should be
+     * used when the parameter is of JDBC type <code>NUMERIC</code>
+     * or <code>DECIMAL</code>.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @param sqlType the SQL type code defined by <code>java.sql.Types</code>.
+     * @param scale the desired number of digits to the right of the
+     * decimal point.  It must be greater than or equal to zero.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     * @see Types
+     */
+    void registerOutParameter(int parameterIndex, int sqlType, int scale)
+        throws SQLException;
+
+    /**
+     * Retrieves whether the last OUT parameter read had the value of
+     * SQL <code>NULL</code>.  Note that this method should be called only after
+     * calling a getter method; otherwise, there is no value to use in
+     * determining whether it is <code>null</code> or not.
+     *
+     * @return <code>true</code> if the last parameter read was SQL
+     * <code>NULL</code>; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     */
+    boolean wasNull() throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>CHAR</code>,
+     * <code>VARCHAR</code>, or <code>LONGVARCHAR</code> parameter as a
+     * <code>String</code> in the Java programming language.
+     * <p>
+     * For the fixed-length type JDBC <code>CHAR</code>,
+     * the <code>String</code> object
+     * returned has exactly the same value the SQL
+     * <code>CHAR</code> value had in the
+     * database, including any padding added by the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value. If the value is SQL <code>NULL</code>,
+     *         the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setString
+     */
+    String getString(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>BIT</code>
+     * or <code>BOOLEAN</code> parameter as a
+     * <code>boolean</code> in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>,
+     *         the result is <code>false</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setBoolean
+     */
+    boolean getBoolean(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>TINYINT</code> parameter
+     * as a <code>byte</code> in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>0</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setByte
+     */
+    byte getByte(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>SMALLINT</code> parameter
+     * as a <code>short</code> in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>0</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setShort
+     */
+    short getShort(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>INTEGER</code> parameter
+     * as an <code>int</code> in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>0</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setInt
+     */
+    int getInt(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>BIGINT</code> parameter
+     * as a <code>long</code> in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>0</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setLong
+     */
+    long getLong(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>FLOAT</code> parameter
+     * as a <code>float</code> in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>0</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setFloat
+     */
+    float getFloat(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>DOUBLE</code> parameter as a <code>double</code>
+     * in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>0</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setDouble
+     */
+    double getDouble(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>NUMERIC</code> parameter as a
+     * <code>java.math.BigDecimal</code> object with <i>scale</i> digits to
+     * the right of the decimal point.
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @param scale the number of digits to the right of the decimal point
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @deprecated use <code>getBigDecimal(int parameterIndex)</code>
+     *             or <code>getBigDecimal(String parameterName)</code>
+     * @see #setBigDecimal
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    BigDecimal getBigDecimal(int parameterIndex, int scale)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>BINARY</code> or
+     * <code>VARBINARY</code> parameter as an array of <code>byte</code>
+     * values in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setBytes
+     */
+    byte[] getBytes(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>DATE</code> parameter as a
+     * <code>java.sql.Date</code> object.
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setDate
+     */
+    java.sql.Date getDate(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>TIME</code> parameter as a
+     * <code>java.sql.Time</code> object.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setTime
+     */
+    java.sql.Time getTime(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>TIMESTAMP</code> parameter as a
+     * <code>java.sql.Timestamp</code> object.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setTimestamp
+     */
+    java.sql.Timestamp getTimestamp(int parameterIndex)
+        throws SQLException;
+
+    //----------------------------------------------------------------------
+    // Advanced features:
+
+
+    /**
+     * Retrieves the value of the designated parameter as an <code>Object</code>
+     * in the Java programming language. If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * <p>
+     * This method returns a Java object whose type corresponds to the JDBC
+     * type that was registered for this parameter using the method
+     * <code>registerOutParameter</code>.  By registering the target JDBC
+     * type as <code>java.sql.Types.OTHER</code>, this method can be used
+     * to read database-specific abstract data types.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     *        and so on
+     * @return A <code>java.lang.Object</code> holding the OUT parameter value
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see Types
+     * @see #setObject
+     */
+    Object getObject(int parameterIndex) throws SQLException;
+
+
+    //--------------------------JDBC 2.0-----------------------------
+
+    /**
+     * Retrieves the value of the designated JDBC <code>NUMERIC</code> parameter as a
+     * <code>java.math.BigDecimal</code> object with as many digits to the
+     * right of the decimal point as the value contains.
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value in full precision.  If the value is
+     * SQL <code>NULL</code>, the result is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setBigDecimal
+     * @since 1.2
+     */
+    BigDecimal getBigDecimal(int parameterIndex) throws SQLException;
+
+    /**
+     * Returns an object representing the value of OUT parameter
+     * <code>parameterIndex</code> and uses <code>map</code> for the custom
+     * mapping of the parameter value.
+     * <p>
+     * This method returns a Java object whose type corresponds to the
+     * JDBC type that was registered for this parameter using the method
+     * <code>registerOutParameter</code>.  By registering the target
+     * JDBC type as <code>java.sql.Types.OTHER</code>, this method can
+     * be used to read database-specific abstract data types.
+     * @param parameterIndex the first parameter is 1, the second is 2, and so on
+     * @param map the mapping from SQL type names to Java classes
+     * @return a <code>java.lang.Object</code> holding the OUT parameter value
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setObject
+     * @since 1.2
+     */
+    Object getObject(int parameterIndex, java.util.Map<String,Class<?>> map)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>REF(&lt;structured-type&gt;)</code>
+     * parameter as a {@link java.sql.Ref} object in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @return the parameter value as a <code>Ref</code> object in the
+     * Java programming language.  If the value was SQL <code>NULL</code>, the value
+     * <code>null</code> is returned.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Ref getRef (int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>BLOB</code> parameter as a
+     * {@link java.sql.Blob} object in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2, and so on
+     * @return the parameter value as a <code>Blob</code> object in the
+     * Java programming language.  If the value was SQL <code>NULL</code>, the value
+     * <code>null</code> is returned.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Blob getBlob (int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>CLOB</code> parameter as a
+     * <code>java.sql.Clob</code> object in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2, and
+     * so on
+     * @return the parameter value as a <code>Clob</code> object in the
+     * Java programming language.  If the value was SQL <code>NULL</code>, the
+     * value <code>null</code> is returned.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Clob getClob (int parameterIndex) throws SQLException;
+
+    /**
+     *
+     * Retrieves the value of the designated JDBC <code>ARRAY</code> parameter as an
+     * {@link java.sql.Array} object in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2, and
+     * so on
+     * @return the parameter value as an <code>Array</code> object in
+     * the Java programming language.  If the value was SQL <code>NULL</code>, the
+     * value <code>null</code> is returned.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Array getArray (int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>DATE</code> parameter as a
+     * <code>java.sql.Date</code> object, using
+     * the given <code>Calendar</code> object
+     * to construct the date.
+     * With a <code>Calendar</code> object, the driver
+     * can calculate the date taking into account a custom timezone and locale.
+     * If no <code>Calendar</code> object is specified, the driver uses the
+     * default timezone and locale.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the date
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setDate
+     * @since 1.2
+     */
+    java.sql.Date getDate(int parameterIndex, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>TIME</code> parameter as a
+     * <code>java.sql.Time</code> object, using
+     * the given <code>Calendar</code> object
+     * to construct the time.
+     * With a <code>Calendar</code> object, the driver
+     * can calculate the time taking into account a custom timezone and locale.
+     * If no <code>Calendar</code> object is specified, the driver uses the
+     * default timezone and locale.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the time
+     * @return the parameter value; if the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setTime
+     * @since 1.2
+     */
+    java.sql.Time getTime(int parameterIndex, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>TIMESTAMP</code> parameter as a
+     * <code>java.sql.Timestamp</code> object, using
+     * the given <code>Calendar</code> object to construct
+     * the <code>Timestamp</code> object.
+     * With a <code>Calendar</code> object, the driver
+     * can calculate the timestamp taking into account a custom timezone and locale.
+     * If no <code>Calendar</code> object is specified, the driver uses the
+     * default timezone and locale.
+     *
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,
+     * and so on
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the timestamp
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     *         is <code>null</code>.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #setTimestamp
+     * @since 1.2
+     */
+    java.sql.Timestamp getTimestamp(int parameterIndex, Calendar cal)
+        throws SQLException;
+
+
+    /**
+     * Registers the designated output parameter.
+     * This version of
+     * the method <code>registerOutParameter</code>
+     * should be used for a user-defined or <code>REF</code> output parameter.  Examples
+     * of user-defined types include: <code>STRUCT</code>, <code>DISTINCT</code>,
+     * <code>JAVA_OBJECT</code>, and named array types.
+     *<p>
+     * All OUT parameters must be registered
+     * before a stored procedure is executed.
+     * <p>  For a user-defined parameter, the fully-qualified SQL
+     * type name of the parameter should also be given, while a <code>REF</code>
+     * parameter requires that the fully-qualified type name of the
+     * referenced type be given.  A JDBC driver that does not need the
+     * type code and type name information may ignore it.   To be portable,
+     * however, applications should always provide these values for
+     * user-defined and <code>REF</code> parameters.
+     *
+     * Although it is intended for user-defined and <code>REF</code> parameters,
+     * this method may be used to register a parameter of any JDBC type.
+     * If the parameter does not have a user-defined or <code>REF</code> type, the
+     * <i>typeName</i> parameter is ignored.
+     *
+     * <P><B>Note:</B> When reading the value of an out parameter, you
+     * must use the getter method whose Java type corresponds to the
+     * parameter's registered SQL type.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,...
+     * @param sqlType a value from {@link java.sql.Types}
+     * @param typeName the fully-qualified name of an SQL structured type
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     * @see Types
+     * @since 1.2
+     */
+    void registerOutParameter (int parameterIndex, int sqlType, String typeName)
+        throws SQLException;
+
+  //--------------------------JDBC 3.0-----------------------------
+
+    /**
+     * Registers the OUT parameter named
+     * <code>parameterName</code> to the JDBC type
+     * <code>sqlType</code>.  All OUT parameters must be registered
+     * before a stored procedure is executed.
+     * <p>
+     * The JDBC type specified by <code>sqlType</code> for an OUT
+     * parameter determines the Java type that must be used
+     * in the <code>get</code> method to read the value of that parameter.
+     * <p>
+     * If the JDBC type expected to be returned to this output parameter
+     * is specific to this particular database, <code>sqlType</code>
+     * should be <code>java.sql.Types.OTHER</code>.  The method
+     * {@link #getObject} retrieves the value.
+     * @param parameterName the name of the parameter
+     * @param sqlType the JDBC type code defined by <code>java.sql.Types</code>.
+     * If the parameter is of JDBC type <code>NUMERIC</code>
+     * or <code>DECIMAL</code>, the version of
+     * <code>registerOutParameter</code> that accepts a scale value
+     * should be used.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type or if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     * @see Types
+     */
+    void registerOutParameter(String parameterName, int sqlType)
+        throws SQLException;
+
+    /**
+     * Registers the parameter named
+     * <code>parameterName</code> to be of JDBC type
+     * <code>sqlType</code>.  All OUT parameters must be registered
+     * before a stored procedure is executed.
+     * <p>
+     * The JDBC type specified by <code>sqlType</code> for an OUT
+     * parameter determines the Java type that must be used
+     * in the <code>get</code> method to read the value of that parameter.
+     * <p>
+     * This version of <code>registerOutParameter</code> should be
+     * used when the parameter is of JDBC type <code>NUMERIC</code>
+     * or <code>DECIMAL</code>.
+     *
+     * @param parameterName the name of the parameter
+     * @param sqlType SQL type code defined by <code>java.sql.Types</code>.
+     * @param scale the desired number of digits to the right of the
+     * decimal point.  It must be greater than or equal to zero.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type or if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     * @see Types
+     */
+    void registerOutParameter(String parameterName, int sqlType, int scale)
+        throws SQLException;
+
+    /**
+     * Registers the designated output parameter.  This version of
+     * the method <code>registerOutParameter</code>
+     * should be used for a user-named or REF output parameter.  Examples
+     * of user-named types include: STRUCT, DISTINCT, JAVA_OBJECT, and
+     * named array types.
+     *<p>
+     * All OUT parameters must be registered
+     * before a stored procedure is executed.
+     * <p>
+     * For a user-named parameter the fully-qualified SQL
+     * type name of the parameter should also be given, while a REF
+     * parameter requires that the fully-qualified type name of the
+     * referenced type be given.  A JDBC driver that does not need the
+     * type code and type name information may ignore it.   To be portable,
+     * however, applications should always provide these values for
+     * user-named and REF parameters.
+     *
+     * Although it is intended for user-named and REF parameters,
+     * this method may be used to register a parameter of any JDBC type.
+     * If the parameter does not have a user-named or REF type, the
+     * typeName parameter is ignored.
+     *
+     * <P><B>Note:</B> When reading the value of an out parameter, you
+     * must use the <code>getXXX</code> method whose Java type XXX corresponds to the
+     * parameter's registered SQL type.
+     *
+     * @param parameterName the name of the parameter
+     * @param sqlType a value from {@link java.sql.Types}
+     * @param typeName the fully-qualified name of an SQL structured type
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type or if the JDBC driver does not support
+     * this method
+     * @see Types
+     * @since 1.4
+     */
+    void registerOutParameter (String parameterName, int sqlType, String typeName)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>DATALINK</code> parameter as a
+     * <code>java.net.URL</code> object.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,...
+     * @return a <code>java.net.URL</code> object that represents the
+     *         JDBC <code>DATALINK</code> value used as the designated
+     *         parameter
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs,
+     * this method is called on a closed <code>CallableStatement</code>,
+     *            or if the URL being returned is
+     *            not a valid URL on the Java platform
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setURL
+     * @since 1.4
+     */
+    java.net.URL getURL(int parameterIndex) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.net.URL</code> object.
+     * The driver converts this to an SQL <code>DATALINK</code> value when
+     * it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param val the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs;
+     * this method is called on a closed <code>CallableStatement</code>
+     *            or if a URL is malformed
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getURL
+     * @since 1.4
+     */
+    void setURL(String parameterName, java.net.URL val) throws SQLException;
+
+    /**
+     * Sets the designated parameter to SQL <code>NULL</code>.
+     *
+     * <P><B>Note:</B> You must specify the parameter's SQL type.
+     *
+     * @param parameterName the name of the parameter
+     * @param sqlType the SQL type code defined in <code>java.sql.Types</code>
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void setNull(String parameterName, int sqlType) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>boolean</code> value.
+     * The driver converts this
+     * to an SQL <code>BIT</code> or <code>BOOLEAN</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @see #getBoolean
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void setBoolean(String parameterName, boolean x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>byte</code> value.
+     * The driver converts this
+     * to an SQL <code>TINYINT</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getByte
+     * @since 1.4
+     */
+    void setByte(String parameterName, byte x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>short</code> value.
+     * The driver converts this
+     * to an SQL <code>SMALLINT</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getShort
+     * @since 1.4
+     */
+    void setShort(String parameterName, short x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>int</code> value.
+     * The driver converts this
+     * to an SQL <code>INTEGER</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getInt
+     * @since 1.4
+     */
+    void setInt(String parameterName, int x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>long</code> value.
+     * The driver converts this
+     * to an SQL <code>BIGINT</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getLong
+     * @since 1.4
+     */
+    void setLong(String parameterName, long x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>float</code> value.
+     * The driver converts this
+     * to an SQL <code>FLOAT</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getFloat
+     * @since 1.4
+     */
+    void setFloat(String parameterName, float x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>double</code> value.
+     * The driver converts this
+     * to an SQL <code>DOUBLE</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getDouble
+     * @since 1.4
+     */
+    void setDouble(String parameterName, double x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given
+     * <code>java.math.BigDecimal</code> value.
+     * The driver converts this to an SQL <code>NUMERIC</code> value when
+     * it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getBigDecimal
+     * @since 1.4
+     */
+    void setBigDecimal(String parameterName, BigDecimal x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>String</code> value.
+     * The driver converts this
+     * to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value
+     * (depending on the argument's
+     * size relative to the driver's limits on <code>VARCHAR</code> values)
+     * when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getString
+     * @since 1.4
+     */
+    void setString(String parameterName, String x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java array of bytes.
+     * The driver converts this to an SQL <code>VARBINARY</code> or
+     * <code>LONGVARBINARY</code> (depending on the argument's size relative
+     * to the driver's limits on <code>VARBINARY</code> values) when it sends
+     * it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getBytes
+     * @since 1.4
+     */
+    void setBytes(String parameterName, byte x[]) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Date</code> value
+     * using the default time zone of the virtual machine that is running
+     * the application.
+     * The driver converts this
+     * to an SQL <code>DATE</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getDate
+     * @since 1.4
+     */
+    void setDate(String parameterName, java.sql.Date x)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Time</code> value.
+     * The driver converts this
+     * to an SQL <code>TIME</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getTime
+     * @since 1.4
+     */
+    void setTime(String parameterName, java.sql.Time x)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value.
+     * The driver
+     * converts this to an SQL <code>TIMESTAMP</code> value when it sends it to the
+     * database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getTimestamp
+     * @since 1.4
+     */
+    void setTimestamp(String parameterName, java.sql.Timestamp x)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from ASCII to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void setAsciiStream(String parameterName, java.io.InputStream x, int length)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the java input stream which contains the binary parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void setBinaryStream(String parameterName, java.io.InputStream x,
+                         int length) throws SQLException;
+
+    /**
+     * Sets the value of the designated parameter with the given object. The second
+     * argument must be an object type; for integral values, the
+     * <code>java.lang</code> equivalent objects should be used.
+     *
+     * <p>The given Java object will be converted to the given targetSqlType
+     * before being sent to the database.
+     *
+     * If the object has a custom mapping (is of a class implementing the
+     * interface <code>SQLData</code>),
+     * the JDBC driver should call the method <code>SQLData.writeSQL</code> to write it
+     * to the SQL data stream.
+     * If, on the other hand, the object is of a class implementing
+     * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>,  <code>NClob</code>,
+     *  <code>Struct</code>, <code>java.net.URL</code>,
+     * or <code>Array</code>, the driver should pass it to the database as a
+     * value of the corresponding SQL type.
+     * <P>
+     * Note that this method may be used to pass datatabase-
+     * specific abstract data types.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the object containing the input parameter value
+     * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
+     * sent to the database. The scale argument may further qualify this type.
+     * @param scale for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types,
+     *          this is the number of digits after the decimal point.  For all other
+     *          types, this value will be ignored.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>targetSqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     * @see Types
+     * @see #getObject
+     * @since 1.4
+     */
+    void setObject(String parameterName, Object x, int targetSqlType, int scale)
+        throws SQLException;
+
+    /**
+     * Sets the value of the designated parameter with the given object.
+     * This method is like the method <code>setObject</code>
+     * above, except that it assumes a scale of zero.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the object containing the input parameter value
+     * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
+     *                      sent to the database
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>targetSqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     * @see #getObject
+     * @since 1.4
+     */
+    void setObject(String parameterName, Object x, int targetSqlType)
+        throws SQLException;
+
+    /**
+     * Sets the value of the designated parameter with the given object.
+     * The second parameter must be of type <code>Object</code>; therefore, the
+     * <code>java.lang</code> equivalent objects should be used for built-in types.
+     *
+     * <p>The JDBC specification specifies a standard mapping from
+     * Java <code>Object</code> types to SQL types.  The given argument
+     * will be converted to the corresponding SQL type before being
+     * sent to the database.
+     * <p>Note that this method may be used to pass datatabase-
+     * specific abstract data types, by using a driver-specific Java
+     * type.
+     *
+     * If the object is of a class implementing the interface <code>SQLData</code>,
+     * the JDBC driver should call the method <code>SQLData.writeSQL</code>
+     * to write it to the SQL data stream.
+     * If, on the other hand, the object is of a class implementing
+     * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>,  <code>NClob</code>,
+     *  <code>Struct</code>, <code>java.net.URL</code>,
+     * or <code>Array</code>, the driver should pass it to the database as a
+     * value of the corresponding SQL type.
+     * <P>
+     * This method throws an exception if there is an ambiguity, for example, if the
+     * object is of a class implementing more than one of the interfaces named above.
+     *<p>
+     *<b>Note:</b> Not all databases allow for a non-typed Null to be sent to
+     * the backend. For maximum portability, the <code>setNull</code> or the
+     * <code>setObject(String parameterName, Object x, int sqlType)</code>
+     * method should be used
+     * instead of <code>setObject(String parameterName, Object x)</code>.
+     *<p>
+     * @param parameterName the name of the parameter
+     * @param x the object containing the input parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs,
+     * this method is called on a closed <code>CallableStatement</code> or if the given
+     *            <code>Object</code> parameter is ambiguous
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getObject
+     * @since 1.4
+     */
+    void setObject(String parameterName, Object x) throws SQLException;
+
+
+    /**
+     * Sets the designated parameter to the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterName the name of the parameter
+     * @param reader the <code>java.io.Reader</code> object that
+     *        contains the UNICODE data used as the designated parameter
+     * @param length the number of characters in the stream
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void setCharacterStream(String parameterName,
+                            java.io.Reader reader,
+                            int length) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Date</code> value,
+     * using the given <code>Calendar</code> object.  The driver uses
+     * the <code>Calendar</code> object to construct an SQL <code>DATE</code> value,
+     * which the driver then sends to the database.  With a
+     * a <code>Calendar</code> object, the driver can calculate the date
+     * taking into account a custom timezone.  If no
+     * <code>Calendar</code> object is specified, the driver uses the default
+     * timezone, which is that of the virtual machine running the application.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the date
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getDate
+     * @since 1.4
+     */
+    void setDate(String parameterName, java.sql.Date x, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Time</code> value,
+     * using the given <code>Calendar</code> object.  The driver uses
+     * the <code>Calendar</code> object to construct an SQL <code>TIME</code> value,
+     * which the driver then sends to the database.  With a
+     * a <code>Calendar</code> object, the driver can calculate the time
+     * taking into account a custom timezone.  If no
+     * <code>Calendar</code> object is specified, the driver uses the default
+     * timezone, which is that of the virtual machine running the application.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the time
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getTime
+     * @since 1.4
+     */
+    void setTime(String parameterName, java.sql.Time x, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value,
+     * using the given <code>Calendar</code> object.  The driver uses
+     * the <code>Calendar</code> object to construct an SQL <code>TIMESTAMP</code> value,
+     * which the driver then sends to the database.  With a
+     * a <code>Calendar</code> object, the driver can calculate the timestamp
+     * taking into account a custom timezone.  If no
+     * <code>Calendar</code> object is specified, the driver uses the default
+     * timezone, which is that of the virtual machine running the application.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the timestamp
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getTimestamp
+     * @since 1.4
+     */
+    void setTimestamp(String parameterName, java.sql.Timestamp x, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to SQL <code>NULL</code>.
+     * This version of the method <code>setNull</code> should
+     * be used for user-defined types and REF type parameters.  Examples
+     * of user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT, and
+     * named array types.
+     *
+     * <P><B>Note:</B> To be portable, applications must give the
+     * SQL type code and the fully-qualified SQL type name when specifying
+     * a NULL user-defined or REF parameter.  In the case of a user-defined type
+     * the name is the type name of the parameter itself.  For a REF
+     * parameter, the name is the type name of the referenced type.
+     * <p>
+     * Although it is intended for user-defined and Ref parameters,
+     * this method may be used to set a null parameter of any JDBC type.
+     * If the parameter does not have a user-defined or REF type, the given
+     * typeName is ignored.
+     *
+     *
+     * @param parameterName the name of the parameter
+     * @param sqlType a value from <code>java.sql.Types</code>
+     * @param typeName the fully-qualified name of an SQL user-defined type;
+     *        ignored if the parameter is not a user-defined type or
+     *        SQL <code>REF</code> value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void setNull (String parameterName, int sqlType, String typeName)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>CHAR</code>, <code>VARCHAR</code>,
+     * or <code>LONGVARCHAR</code> parameter as a <code>String</code> in
+     * the Java programming language.
+     * <p>
+     * For the fixed-length type JDBC <code>CHAR</code>,
+     * the <code>String</code> object
+     * returned has exactly the same value the SQL
+     * <code>CHAR</code> value had in the
+     * database, including any padding added by the database.
+     * @param parameterName the name of the parameter
+     * @return the parameter value. If the value is SQL <code>NULL</code>, the result
+     * is <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setString
+     * @since 1.4
+     */
+    String getString(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>BIT</code> or <code>BOOLEAN</code>
+     * parameter as a
+     * <code>boolean</code> in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>false</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setBoolean
+     * @since 1.4
+     */
+    boolean getBoolean(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>TINYINT</code> parameter as a <code>byte</code>
+     * in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>0</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setByte
+     * @since 1.4
+     */
+    byte getByte(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>SMALLINT</code> parameter as a <code>short</code>
+     * in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>0</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setShort
+     * @since 1.4
+     */
+    short getShort(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>INTEGER</code> parameter as an <code>int</code>
+     * in the Java programming language.
+     *
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>,
+     *         the result is <code>0</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setInt
+     * @since 1.4
+     */
+    int getInt(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>BIGINT</code> parameter as a <code>long</code>
+     * in the Java programming language.
+     *
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>,
+     *         the result is <code>0</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setLong
+     * @since 1.4
+     */
+    long getLong(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>FLOAT</code> parameter as a <code>float</code>
+     * in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>,
+     *         the result is <code>0</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setFloat
+     * @since 1.4
+     */
+    float getFloat(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>DOUBLE</code> parameter as a <code>double</code>
+     * in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>,
+     *         the result is <code>0</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setDouble
+     * @since 1.4
+     */
+    double getDouble(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>BINARY</code> or <code>VARBINARY</code>
+     * parameter as an array of <code>byte</code> values in the Java
+     * programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result is
+     *  <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setBytes
+     * @since 1.4
+     */
+    byte[] getBytes(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>DATE</code> parameter as a
+     * <code>java.sql.Date</code> object.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setDate
+     * @since 1.4
+     */
+    java.sql.Date getDate(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>TIME</code> parameter as a
+     * <code>java.sql.Time</code> object.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setTime
+     * @since 1.4
+     */
+    java.sql.Time getTime(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>TIMESTAMP</code> parameter as a
+     * <code>java.sql.Timestamp</code> object.
+     * @param parameterName the name of the parameter
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result
+     * is <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setTimestamp
+     * @since 1.4
+     */
+    java.sql.Timestamp getTimestamp(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a parameter as an <code>Object</code> in the Java
+     * programming language. If the value is an SQL <code>NULL</code>, the
+     * driver returns a Java <code>null</code>.
+     * <p>
+     * This method returns a Java object whose type corresponds to the JDBC
+     * type that was registered for this parameter using the method
+     * <code>registerOutParameter</code>.  By registering the target JDBC
+     * type as <code>java.sql.Types.OTHER</code>, this method can be used
+     * to read database-specific abstract data types.
+     * @param parameterName the name of the parameter
+     * @return A <code>java.lang.Object</code> holding the OUT parameter value.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see Types
+     * @see #setObject
+     * @since 1.4
+     */
+    Object getObject(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>NUMERIC</code> parameter as a
+     * <code>java.math.BigDecimal</code> object with as many digits to the
+     * right of the decimal point as the value contains.
+     * @param parameterName the name of the parameter
+     * @return the parameter value in full precision.  If the value is
+     * SQL <code>NULL</code>, the result is <code>null</code>.
+     * @exception SQLExceptionif parameterName does not correspond to a named
+     * parameter;  if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setBigDecimal
+     * @since 1.4
+     */
+    BigDecimal getBigDecimal(String parameterName) throws SQLException;
+
+    /**
+     * Returns an object representing the value of OUT parameter
+     * <code>parameterName</code> and uses <code>map</code> for the custom
+     * mapping of the parameter value.
+     * <p>
+     * This method returns a Java object whose type corresponds to the
+     * JDBC type that was registered for this parameter using the method
+     * <code>registerOutParameter</code>.  By registering the target
+     * JDBC type as <code>java.sql.Types.OTHER</code>, this method can
+     * be used to read database-specific abstract data types.
+     * @param parameterName the name of the parameter
+     * @param map the mapping from SQL type names to Java classes
+     * @return a <code>java.lang.Object</code> holding the OUT parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setObject
+     * @since 1.4
+     */
+    Object getObject(String parameterName, java.util.Map<String,Class<?>> map)
+      throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>REF(&lt;structured-type&gt;)</code>
+     * parameter as a {@link java.sql.Ref} object in the Java programming language.
+     *
+     * @param parameterName the name of the parameter
+     * @return the parameter value as a <code>Ref</code> object in the
+     *         Java programming language.  If the value was SQL <code>NULL</code>,
+     *         the value <code>null</code> is returned.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    Ref getRef (String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>BLOB</code> parameter as a
+     * {@link java.sql.Blob} object in the Java programming language.
+     *
+     * @param parameterName the name of the parameter
+     * @return the parameter value as a <code>Blob</code> object in the
+     *         Java programming language.  If the value was SQL <code>NULL</code>,
+     *         the value <code>null</code> is returned.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    Blob getBlob (String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>CLOB</code> parameter as a
+     * <code>java.sql.Clob</code> object in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value as a <code>Clob</code> object in the
+     *         Java programming language.  If the value was SQL <code>NULL</code>,
+     *         the value <code>null</code> is returned.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    Clob getClob (String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>ARRAY</code> parameter as an
+     * {@link java.sql.Array} object in the Java programming language.
+     *
+     * @param parameterName the name of the parameter
+     * @return the parameter value as an <code>Array</code> object in
+     *         Java programming language.  If the value was SQL <code>NULL</code>,
+     *         the value <code>null</code> is returned.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    Array getArray (String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>DATE</code> parameter as a
+     * <code>java.sql.Date</code> object, using
+     * the given <code>Calendar</code> object
+     * to construct the date.
+     * With a <code>Calendar</code> object, the driver
+     * can calculate the date taking into account a custom timezone and locale.
+     * If no <code>Calendar</code> object is specified, the driver uses the
+     * default timezone and locale.
+     *
+     * @param parameterName the name of the parameter
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the date
+     * @return the parameter value.  If the value is SQL <code>NULL</code>,
+     * the result is <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setDate
+     * @since 1.4
+     */
+    java.sql.Date getDate(String parameterName, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>TIME</code> parameter as a
+     * <code>java.sql.Time</code> object, using
+     * the given <code>Calendar</code> object
+     * to construct the time.
+     * With a <code>Calendar</code> object, the driver
+     * can calculate the time taking into account a custom timezone and locale.
+     * If no <code>Calendar</code> object is specified, the driver uses the
+     * default timezone and locale.
+     *
+     * @param parameterName the name of the parameter
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the time
+     * @return the parameter value; if the value is SQL <code>NULL</code>, the result is
+     * <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setTime
+     * @since 1.4
+     */
+    java.sql.Time getTime(String parameterName, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>TIMESTAMP</code> parameter as a
+     * <code>java.sql.Timestamp</code> object, using
+     * the given <code>Calendar</code> object to construct
+     * the <code>Timestamp</code> object.
+     * With a <code>Calendar</code> object, the driver
+     * can calculate the timestamp taking into account a custom timezone and locale.
+     * If no <code>Calendar</code> object is specified, the driver uses the
+     * default timezone and locale.
+     *
+     *
+     * @param parameterName the name of the parameter
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the timestamp
+     * @return the parameter value.  If the value is SQL <code>NULL</code>, the result is
+     * <code>null</code>.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setTimestamp
+     * @since 1.4
+     */
+    java.sql.Timestamp getTimestamp(String parameterName, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of a JDBC <code>DATALINK</code> parameter as a
+     * <code>java.net.URL</code> object.
+     *
+     * @param parameterName the name of the parameter
+     * @return the parameter value as a <code>java.net.URL</code> object in the
+     * Java programming language.  If the value was SQL <code>NULL</code>, the
+     * value <code>null</code> is returned.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs,
+     * this method is called on a closed <code>CallableStatement</code>,
+     *            or if there is a problem with the URL
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #setURL
+     * @since 1.4
+     */
+    java.net.URL getURL(String parameterName) throws SQLException;
+
+    //------------------------- JDBC 4.0 -----------------------------------
+
+    /**
+     * Retrieves the value of the designated JDBC <code>ROWID</code> parameter as a
+     * <code>java.sql.RowId</code> object.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2,...
+     * @return a <code>RowId</code> object that represents the JDBC <code>ROWID</code>
+     *     value is used as the designated parameter. If the parameter contains
+     * a SQL <code>NULL</code>, then a <code>null</code> value is returned.
+     * @throws SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    RowId getRowId(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>ROWID</code> parameter as a
+     * <code>java.sql.RowId</code> object.
+     *
+     * @param parameterName the name of the parameter
+     * @return a <code>RowId</code> object that represents the JDBC <code>ROWID</code>
+     *     value is used as the designated parameter. If the parameter contains
+     * a SQL <code>NULL</code>, then a <code>null</code> value is returned.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    RowId getRowId(String parameterName) throws SQLException;
+
+     /**
+     * Sets the designated parameter to the given <code>java.sql.RowId</code> object. The
+     * driver converts this to a SQL <code>ROWID</code> when it sends it to the
+     * database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the parameter value
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setRowId(String parameterName, RowId x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>String</code> object.
+     * The driver converts this to a SQL <code>NCHAR</code> or
+     * <code>NVARCHAR</code> or <code>LONGNVARCHAR</code>
+     * @param parameterName the name of the parameter to be set
+     * @param value the parameter value
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setNString(String parameterName, String value)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object. The
+     * <code>Reader</code> reads the data till end-of-file is reached. The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+     * @param parameterName the name of the parameter to be set
+     * @param value the parameter value
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setNCharacterStream(String parameterName, Reader value, long length)
+            throws SQLException;
+
+     /**
+     * Sets the designated parameter to a <code>java.sql.NClob</code> object. The object
+     * implements the <code>java.sql.NClob</code> interface. This <code>NClob</code>
+     * object maps to a SQL <code>NCLOB</code>.
+     * @param parameterName the name of the parameter to be set
+     * @param value the parameter value
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+     void setNClob(String parameterName, NClob value) throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.  The <code>reader</code> must contain  the number
+     * of characters specified by length otherwise a <code>SQLException</code> will be
+     * generated when the <code>CallableStatement</code> is executed.
+     * This method differs from the <code>setCharacterStream (int, Reader, int)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>CLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be send to the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>
+     * @param parameterName the name of the parameter to be set
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the length specified is less than zero;
+     * a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @since 1.6
+     */
+     void setClob(String parameterName, Reader reader, long length)
+       throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>InputStream</code> object.  The <code>inputstream</code> must contain  the number
+     * of characters specified by length, otherwise a <code>SQLException</code> will be
+     * generated when the <code>CallableStatement</code> is executed.
+     * This method differs from the <code>setBinaryStream (int, InputStream, int)</code>
+     * method because it informs the driver that the parameter value should be
+     * sent to the server as a <code>BLOB</code>.  When the <code>setBinaryStream</code> method is used,
+     * the driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
+     *
+     * @param parameterName the name of the parameter to be set
+     * the second is 2, ...
+     *
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @param length the number of bytes in the parameter data.
+     * @throws SQLException  if parameterName does not correspond to a named
+     * parameter; if the length specified
+     * is less than zero; if the number of bytes in the inputstream does not match
+     * the specfied length; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @since 1.6
+     */
+     void setBlob(String parameterName, InputStream inputStream, long length)
+        throws SQLException;
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.  The <code>reader</code> must contain  the number
+     * of characters specified by length otherwise a <code>SQLException</code> will be
+     * generated when the <code>CallableStatement</code> is executed.
+     * This method differs from the <code>setCharacterStream (int, Reader, int)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>NCLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be send to the server as a <code>LONGNVARCHAR</code> or a <code>NCLOB</code>
+     *
+     * @param parameterName the name of the parameter to be set
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the length specified is less than zero;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+     void setNClob(String parameterName, Reader reader, long length)
+       throws SQLException;
+
+    /**
+     * Retrieves the value of the designated JDBC <code>NCLOB</code> parameter as a
+     * <code>java.sql.NClob</code> object in the Java programming language.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, and
+     * so on
+     * @return the parameter value as a <code>NClob</code> object in the
+     * Java programming language.  If the value was SQL <code>NULL</code>, the
+     * value <code>null</code> is returned.
+     * @exception SQLException if the parameterIndex is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    NClob getNClob (int parameterIndex) throws SQLException;
+
+
+    /**
+     * Retrieves the value of a JDBC <code>NCLOB</code> parameter as a
+     * <code>java.sql.NClob</code> object in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return the parameter value as a <code>NClob</code> object in the
+     *         Java programming language.  If the value was SQL <code>NULL</code>,
+     *         the value <code>null</code> is returned.
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    NClob getNClob (String parameterName) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.SQLXML</code> object. The driver converts this to an
+     * <code>SQL XML</code> value when it sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param xmlObject a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs;
+     * this method is called on a closed <code>CallableStatement</code> or
+     * the <code>java.xml.transform.Result</code>,
+   *  <code>Writer</code> or <code>OutputStream</code> has not been closed for the <code>SQLXML</code> object
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @since 1.6
+     */
+    void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated <code>SQL XML</code> parameter as a
+     * <code>java.sql.SQLXML</code> object in the Java programming language.
+     * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+     * @return a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
+     * @throws SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    SQLXML getSQLXML(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated <code>SQL XML</code> parameter as a
+     * <code>java.sql.SQLXML</code> object in the Java programming language.
+     * @param parameterName the name of the parameter
+     * @return a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    SQLXML getSQLXML(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated <code>NCHAR</code>,
+     * <code>NVARCHAR</code>
+     * or <code>LONGNVARCHAR</code> parameter as
+     * a <code>String</code> in the Java programming language.
+     *  <p>
+     * For the fixed-length type JDBC <code>NCHAR</code>,
+     * the <code>String</code> object
+     * returned has exactly the same value the SQL
+     * <code>NCHAR</code> value had in the
+     * database, including any padding added by the database.
+     *
+     * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+     * @return a <code>String</code> object that maps an
+     * <code>NCHAR</code>, <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     * @see #setNString
+     */
+    String getNString(int parameterIndex) throws SQLException;
+
+
+    /**
+     *  Retrieves the value of the designated <code>NCHAR</code>,
+     * <code>NVARCHAR</code>
+     * or <code>LONGNVARCHAR</code> parameter as
+     * a <code>String</code> in the Java programming language.
+     * <p>
+     * For the fixed-length type JDBC <code>NCHAR</code>,
+     * the <code>String</code> object
+     * returned has exactly the same value the SQL
+     * <code>NCHAR</code> value had in the
+     * database, including any padding added by the database.
+     *
+     * @param parameterName the name of the parameter
+     * @return a <code>String</code> object that maps an
+     * <code>NCHAR</code>, <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     * @see #setNString
+     */
+    String getNString(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated parameter as a
+     * <code>java.io.Reader</code> object in the Java programming language.
+     * It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> parameters.
+     *
+     * @return a <code>java.io.Reader</code> object that contains the parameter
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @exception SQLException if the parameterIndex is not valid;
+     * if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    java.io.Reader getNCharacterStream(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated parameter as a
+     * <code>java.io.Reader</code> object in the Java programming language.
+     * It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> parameters.
+     *
+     * @param parameterName the name of the parameter
+     * @return a <code>java.io.Reader</code> object that contains the parameter
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    java.io.Reader getNCharacterStream(String parameterName) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated parameter as a
+     * <code>java.io.Reader</code> object in the Java programming language.
+     *
+     * @return a <code>java.io.Reader</code> object that contains the parameter
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language.
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @exception SQLException if the parameterIndex is not valid; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @since 1.6
+     */
+    java.io.Reader getCharacterStream(int parameterIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated parameter as a
+     * <code>java.io.Reader</code> object in the Java programming language.
+     *
+     * @param parameterName the name of the parameter
+     * @return a <code>java.io.Reader</code> object that contains the parameter
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    java.io.Reader getCharacterStream(String parameterName) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Blob</code> object.
+     * The driver converts this to an SQL <code>BLOB</code> value when it
+     * sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x a <code>Blob</code> object that maps an SQL <code>BLOB</code> value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setBlob (String parameterName, Blob x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Clob</code> object.
+     * The driver converts this to an SQL <code>CLOB</code> value when it
+     * sends it to the database.
+     *
+     * @param parameterName the name of the parameter
+     * @param x a <code>Clob</code> object that maps an SQL <code>CLOB</code> value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setClob (String parameterName, Clob x) throws SQLException;
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from ASCII to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setAsciiStream(String parameterName, java.io.InputStream x, long length)
+        throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the java input stream which contains the binary parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setBinaryStream(String parameterName, java.io.InputStream x,
+                         long length) throws SQLException;
+        /**
+     * Sets the designated parameter to the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterName the name of the parameter
+     * @param reader the <code>java.io.Reader</code> object that
+     *        contains the UNICODE data used as the designated parameter
+     * @param length the number of characters in the stream
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void setCharacterStream(String parameterName,
+                            java.io.Reader reader,
+                            long length) throws SQLException;
+     //--
+    /**
+     * Sets the designated parameter to the given input stream.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from ASCII to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setAsciiStream</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+       * @since 1.6
+    */
+    void setAsciiStream(String parameterName, java.io.InputStream x)
+            throws SQLException;
+    /**
+     * Sets the designated parameter to the given input stream.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the
+     * stream as needed until end-of-file is reached.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setBinaryStream</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param x the java input stream which contains the binary parameter value
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+    void setBinaryStream(String parameterName, java.io.InputStream x)
+    throws SQLException;
+    /**
+     * Sets the designated parameter to the given <code>Reader</code>
+     * object.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setCharacterStream</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param reader the <code>java.io.Reader</code> object that contains the
+     *        Unicode data
+     * @exception SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+    void setCharacterStream(String parameterName,
+                          java.io.Reader reader) throws SQLException;
+  /**
+     * Sets the designated parameter to a <code>Reader</code> object. The
+     * <code>Reader</code> reads the data till end-of-file is reached. The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setNCharacterStream</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param value the parameter value
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs; or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setNCharacterStream(String parameterName, Reader value) throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.
+     * This method differs from the <code>setCharacterStream (int, Reader)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>CLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be send to the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setClob</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param reader An object that contains the data to set the parameter value to.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or this method is called on
+     * a closed <code>CallableStatement</code>
+     *
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setClob(String parameterName, Reader reader)
+       throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>InputStream</code> object.
+     * This method differs from the <code>setBinaryStream (int, InputStream)</code>
+     * method because it informs the driver that the parameter value should be
+     * sent to the server as a <code>BLOB</code>.  When the <code>setBinaryStream</code> method is used,
+     * the driver may have to do extra work to determine whether the parameter
+     * data should be send to the server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setBlob</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+     void setBlob(String parameterName, InputStream inputStream)
+        throws SQLException;
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.
+     * This method differs from the <code>setCharacterStream (int, Reader)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>NCLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be send to the server as a <code>LONGNVARCHAR</code> or a <code>NCLOB</code>
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setNClob</code> which takes a length parameter.
+     *
+     * @param parameterName the name of the parameter
+     * @param reader An object that contains the data to set the parameter value to.
+     * @throws SQLException if parameterName does not correspond to a named
+     * parameter; if the driver does not support national character sets;
+     * if the driver can detect that a data conversion
+     *  error could occur;  if a database access error occurs or
+     * this method is called on a closed <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+     void setNClob(String parameterName, Reader reader)
+       throws SQLException;
+
+    // Android-removed: JDBC 4.1 methods were removed immediately after the initial import.
+}
diff --git a/java/sql/ClientInfoStatus.java b/java/sql/ClientInfoStatus.java
new file mode 100644
index 0000000..bf13e5f
--- /dev/null
+++ b/java/sql/ClientInfoStatus.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.*;
+
+/**
+ * Enumeration for status of the reason that a property could not be set
+ * via a call to <code>Connection.setClientInfo</code>
+ * @since 1.6
+ */
+
+public enum ClientInfoStatus {
+
+    /**
+     * The client info property could not be set for some unknown reason
+     * @since 1.6
+     */
+    REASON_UNKNOWN,
+
+    /**
+     * The client info property name specified was not a recognized property
+     * name.
+     * @since 1.6
+     */
+    REASON_UNKNOWN_PROPERTY,
+
+    /**
+     * The value specified for the client info property was not valid.
+     * @since 1.6
+     */
+    REASON_VALUE_INVALID,
+
+    /**
+     * The value specified for the client info property was too large.
+     * @since 1.6
+     */
+    REASON_VALUE_TRUNCATED
+}
diff --git a/java/sql/Clob.java b/java/sql/Clob.java
new file mode 100644
index 0000000..868c862
--- /dev/null
+++ b/java/sql/Clob.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.io.Reader;
+
+/**
+ * The mapping in the Java<sup><font size=-2>TM</font></sup> programming language
+ * for the SQL <code>CLOB</code> type.
+ * An SQL <code>CLOB</code> is a built-in type
+ * that stores a Character Large Object as a column value in a row of
+ * a database table.
+ * By default drivers implement a <code>Clob</code> object using an SQL
+ * <code>locator(CLOB)</code>, which means that a <code>Clob</code> object
+ * contains a logical pointer to the SQL <code>CLOB</code> data rather than
+ * the data itself. A <code>Clob</code> object is valid for the duration
+ * of the transaction in which it was created.
+ * <P>The <code>Clob</code> interface provides methods for getting the
+ * length of an SQL <code>CLOB</code> (Character Large Object) value,
+ * for materializing a <code>CLOB</code> value on the client, and for
+ * searching for a substring or <code>CLOB</code> object within a
+ * <code>CLOB</code> value.
+ * Methods in the interfaces {@link ResultSet},
+ * {@link CallableStatement}, and {@link PreparedStatement}, such as
+ * <code>getClob</code> and <code>setClob</code> allow a programmer to
+ * access an SQL <code>CLOB</code> value.  In addition, this interface
+ * has methods for updating a <code>CLOB</code> value.
+ * <p>
+ * All methods on the <code>Clob</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @since 1.2
+ */
+
+public interface Clob {
+
+  /**
+   * Retrieves the number of characters
+   * in the <code>CLOB</code> value
+   * designated by this <code>Clob</code> object.
+   *
+   * @return length of the <code>CLOB</code> in characters
+   * @exception SQLException if there is an error accessing the
+   *            length of the <code>CLOB</code> value
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  long length() throws SQLException;
+
+  /**
+   * Retrieves a copy of the specified substring
+   * in the <code>CLOB</code> value
+   * designated by this <code>Clob</code> object.
+   * The substring begins at position
+   * <code>pos</code> and has up to <code>length</code> consecutive
+   * characters.
+   *
+   * @param pos the first character of the substring to be extracted.
+   *            The first character is at position 1.
+   * @param length the number of consecutive characters to be copied;
+   * the value for length must be 0 or greater
+   * @return a <code>String</code> that is the specified substring in
+   *         the <code>CLOB</code> value designated by this <code>Clob</code> object
+   * @exception SQLException if there is an error accessing the
+   *            <code>CLOB</code> value; if pos is less than 1 or length is
+   * less than 0
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  String getSubString(long pos, int length) throws SQLException;
+
+  /**
+   * Retrieves the <code>CLOB</code> value designated by this <code>Clob</code>
+   * object as a <code>java.io.Reader</code> object (or as a stream of
+   * characters).
+   *
+   * @return a <code>java.io.Reader</code> object containing the
+   *         <code>CLOB</code> data
+   * @exception SQLException if there is an error accessing the
+   *            <code>CLOB</code> value
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @see #setCharacterStream
+   * @since 1.2
+   */
+  java.io.Reader getCharacterStream() throws SQLException;
+
+  /**
+   * Retrieves the <code>CLOB</code> value designated by this <code>Clob</code>
+   * object as an ascii stream.
+   *
+   * @return a <code>java.io.InputStream</code> object containing the
+   *         <code>CLOB</code> data
+   * @exception SQLException if there is an error accessing the
+   *            <code>CLOB</code> value
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @see #setAsciiStream
+   * @since 1.2
+   */
+  java.io.InputStream getAsciiStream() throws SQLException;
+
+  /**
+   * Retrieves the character position at which the specified substring
+   * <code>searchstr</code> appears in the SQL <code>CLOB</code> value
+   * represented by this <code>Clob</code> object.  The search
+   * begins at position <code>start</code>.
+   *
+   * @param searchstr the substring for which to search
+   * @param start the position at which to begin searching; the first position
+   *              is 1
+   * @return the position at which the substring appears or -1 if it is not
+   *         present; the first position is 1
+   * @exception SQLException if there is an error accessing the
+   *            <code>CLOB</code> value or if pos is less than 1
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  long position(String searchstr, long start) throws SQLException;
+
+  /**
+   * Retrieves the character position at which the specified
+   * <code>Clob</code> object <code>searchstr</code> appears in this
+   * <code>Clob</code> object.  The search begins at position
+   * <code>start</code>.
+   *
+   * @param searchstr the <code>Clob</code> object for which to search
+   * @param start the position at which to begin searching; the first
+   *              position is 1
+   * @return the position at which the <code>Clob</code> object appears
+   *              or -1 if it is not present; the first position is 1
+   * @exception SQLException if there is an error accessing the
+   *            <code>CLOB</code> value or if start is less than 1
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  long position(Clob searchstr, long start) throws SQLException;
+
+    //---------------------------- jdbc 3.0 -----------------------------------
+
+    /**
+     * Writes the given Java <code>String</code> to the <code>CLOB</code>
+     * value that this <code>Clob</code> object designates at the position
+     * <code>pos</code>. The string will overwrite the existing characters
+     * in the <code>Clob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Clob</code> value is reached
+     * while writing the given string, then the length of the <code>Clob</code>
+     * value will be increased to accomodate the extra characters.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>CLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param pos the position at which to start writing to the <code>CLOB</code>
+     *         value that this <code>Clob</code> object represents;
+     * The first position is 1
+     * @param str the string to be written to the <code>CLOB</code>
+     *        value that this <code>Clob</code> designates
+     * @return the number of characters written
+     * @exception SQLException if there is an error accessing the
+     *            <code>CLOB</code> value or if pos is less than 1
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    int setString(long pos, String str) throws SQLException;
+
+    /**
+     * Writes <code>len</code> characters of <code>str</code>, starting
+     * at character <code>offset</code>, to the <code>CLOB</code> value
+     * that this <code>Clob</code> represents.  The string will overwrite the existing characters
+     * in the <code>Clob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Clob</code> value is reached
+     * while writing the given string, then the length of the <code>Clob</code>
+     * value will be increased to accomodate the extra characters.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>CLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param pos the position at which to start writing to this
+     *        <code>CLOB</code> object; The first position  is 1
+     * @param str the string to be written to the <code>CLOB</code>
+     *        value that this <code>Clob</code> object represents
+     * @param offset the offset into <code>str</code> to start reading
+     *        the characters to be written
+     * @param len the number of characters to be written
+     * @return the number of characters written
+     * @exception SQLException if there is an error accessing the
+     *            <code>CLOB</code> value or if pos is less than 1
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    int setString(long pos, String str, int offset, int len) throws SQLException;
+
+    /**
+     * Retrieves a stream to be used to write Ascii characters to the
+     * <code>CLOB</code> value that this <code>Clob</code> object represents,
+     * starting at position <code>pos</code>.  Characters written to the stream
+     * will overwrite the existing characters
+     * in the <code>Clob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Clob</code> value is reached
+     * while writing characters to the stream, then the length of the <code>Clob</code>
+     * value will be increased to accomodate the extra characters.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>CLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param pos the position at which to start writing to this
+     *        <code>CLOB</code> object; The first position is 1
+     * @return the stream to which ASCII encoded characters can be written
+     * @exception SQLException if there is an error accessing the
+     *            <code>CLOB</code> value or if pos is less than 1
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getAsciiStream
+     *
+     * @since 1.4
+     */
+    java.io.OutputStream setAsciiStream(long pos) throws SQLException;
+
+    /**
+     * Retrieves a stream to be used to write a stream of Unicode characters
+     * to the <code>CLOB</code> value that this <code>Clob</code> object
+     * represents, at position <code>pos</code>. Characters written to the stream
+     * will overwrite the existing characters
+     * in the <code>Clob</code> object starting at the position
+     * <code>pos</code>.  If the end of the <code>Clob</code> value is reached
+     * while writing characters to the stream, then the length of the <code>Clob</code>
+     * value will be increased to accomodate the extra characters.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>CLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param  pos the position at which to start writing to the
+     *        <code>CLOB</code> value; The first position is 1
+     *
+     * @return a stream to which Unicode encoded characters can be written
+     * @exception SQLException if there is an error accessing the
+     *            <code>CLOB</code> value or if pos is less than 1
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see #getCharacterStream
+     *
+     * @since 1.4
+     */
+    java.io.Writer setCharacterStream(long pos) throws SQLException;
+
+    /**
+     * Truncates the <code>CLOB</code> value that this <code>Clob</code>
+     * designates to have a length of <code>len</code>
+     * characters.
+     * <p>
+     * <b>Note:</b> If the value specified for <code>pos</code>
+     * is greater then the length+1 of the <code>CLOB</code> value then the
+     * behavior is undefined. Some JDBC drivers may throw a
+     * <code>SQLException</code> while other drivers may support this
+     * operation.
+     *
+     * @param len the length, in characters, to which the <code>CLOB</code> value
+     *        should be truncated
+     * @exception SQLException if there is an error accessing the
+     *            <code>CLOB</code> value or if len is less than 0
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void truncate(long len) throws SQLException;
+
+    /**
+     * This method frees the <code>Clob</code> object and releases the resources the resources
+     * that it holds.  The object is invalid once the <code>free</code> method
+     * is called.
+     * <p>
+     * After <code>free</code> has been called, any attempt to invoke a
+     * method other than <code>free</code> will result in a <code>SQLException</code>
+     * being thrown.  If <code>free</code> is called multiple times, the subsequent
+     * calls to <code>free</code> are treated as a no-op.
+     * <p>
+     * @throws SQLException if an error occurs releasing
+     * the Clob's resources
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void free() throws SQLException;
+
+    /**
+     * Returns a <code>Reader</code> object that contains a partial <code>Clob</code> value, starting
+     * with the character specified by pos, which is length characters in length.
+     *
+     * @param pos the offset to the first character of the partial value to
+     * be retrieved.  The first character in the Clob is at position 1.
+     * @param length the length in characters of the partial value to be retrieved.
+     * @return <code>Reader</code> through which the partial <code>Clob</code> value can be read.
+     * @throws SQLException if pos is less than 1 or if pos is greater than the number of
+     * characters in the <code>Clob</code> or if pos + length is greater than the number of
+     * characters in the <code>Clob</code>
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    Reader getCharacterStream(long pos, long length) throws SQLException;
+
+}
diff --git a/java/sql/Connection.java b/java/sql/Connection.java
new file mode 100644
index 0000000..b742388
--- /dev/null
+++ b/java/sql/Connection.java
@@ -0,0 +1,1307 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+/**
+ * <P>A connection (session) with a specific
+ * database. SQL statements are executed and results are returned
+ * within the context of a connection.
+ * <P>
+ * A <code>Connection</code> object's database is able to provide information
+ * describing its tables, its supported SQL grammar, its stored
+ * procedures, the capabilities of this connection, and so on. This
+ * information is obtained with the <code>getMetaData</code> method.
+ *
+ * <P><B>Note:</B> When configuring a <code>Connection</code>, JDBC applications
+ *  should use the appropriate <code>Connection</code> method such as
+ *  <code>setAutoCommit</code> or <code>setTransactionIsolation</code>.
+ *  Applications should not invoke SQL commands directly to change the connection's
+ *   configuration when there is a JDBC method available.  By default a <code>Connection</code> object is in
+ * auto-commit mode, which means that it automatically commits changes
+ * after executing each statement. If auto-commit mode has been
+ * disabled, the method <code>commit</code> must be called explicitly in
+ * order to commit changes; otherwise, database changes will not be saved.
+ * <P>
+ * A new <code>Connection</code> object created using the JDBC 2.1 core API
+ * has an initially empty type map associated with it. A user may enter a
+ * custom mapping for a UDT in this type map.
+ * When a UDT is retrieved from a data source with the
+ * method <code>ResultSet.getObject</code>, the <code>getObject</code> method
+ * will check the connection's type map to see if there is an entry for that
+ * UDT.  If so, the <code>getObject</code> method will map the UDT to the
+ * class indicated.  If there is no entry, the UDT will be mapped using the
+ * standard mapping.
+ * <p>
+ * A user may create a new type map, which is a <code>java.util.Map</code>
+ * object, make an entry in it, and pass it to the <code>java.sql</code>
+ * methods that can perform custom mapping.  In this case, the method
+ * will use the given type map instead of the one associated with
+ * the connection.
+ * <p>
+ * For example, the following code fragment specifies that the SQL
+ * type <code>ATHLETES</code> will be mapped to the class
+ * <code>Athletes</code> in the Java programming language.
+ * The code fragment retrieves the type map for the <code>Connection
+ * </code> object <code>con</code>, inserts the entry into it, and then sets
+ * the type map with the new entry as the connection's type map.
+ * <pre>
+ *      java.util.Map map = con.getTypeMap();
+ *      map.put("mySchemaName.ATHLETES", Class.forName("Athletes"));
+ *      con.setTypeMap(map);
+ * </pre>
+ *
+ * @see DriverManager#getConnection
+ * @see Statement
+ * @see ResultSet
+ * @see DatabaseMetaData
+ */
+public interface Connection  extends Wrapper, AutoCloseable {
+
+    /**
+     * Creates a <code>Statement</code> object for sending
+     * SQL statements to the database.
+     * SQL statements without parameters are normally
+     * executed using <code>Statement</code> objects. If the same SQL statement
+     * is executed many times, it may be more efficient to use a
+     * <code>PreparedStatement</code> object.
+     * <P>
+     * Result sets created using the returned <code>Statement</code>
+     * object will by default be type <code>TYPE_FORWARD_ONLY</code>
+     * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @return a new default <code>Statement</code> object
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    Statement createStatement() throws SQLException;
+
+    /**
+     * Creates a <code>PreparedStatement</code> object for sending
+     * parameterized SQL statements to the database.
+     * <P>
+     * A SQL statement with or without IN parameters can be
+     * pre-compiled and stored in a <code>PreparedStatement</code> object. This
+     * object can then be used to efficiently execute this statement
+     * multiple times.
+     *
+     * <P><B>Note:</B> This method is optimized for handling
+     * parametric SQL statements that benefit from precompilation. If
+     * the driver supports precompilation,
+     * the method <code>prepareStatement</code> will send
+     * the statement to the database for precompilation. Some drivers
+     * may not support precompilation. In this case, the statement may
+     * not be sent to the database until the <code>PreparedStatement</code>
+     * object is executed.  This has no direct effect on users; however, it does
+     * affect which methods throw certain <code>SQLException</code> objects.
+     * <P>
+     * Result sets created using the returned <code>PreparedStatement</code>
+     * object will by default be type <code>TYPE_FORWARD_ONLY</code>
+     * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql an SQL statement that may contain one or more '?' IN
+     * parameter placeholders
+     * @return a new default <code>PreparedStatement</code> object containing the
+     * pre-compiled SQL statement
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    PreparedStatement prepareStatement(String sql)
+        throws SQLException;
+
+    /**
+     * Creates a <code>CallableStatement</code> object for calling
+     * database stored procedures.
+     * The <code>CallableStatement</code> object provides
+     * methods for setting up its IN and OUT parameters, and
+     * methods for executing the call to a stored procedure.
+     *
+     * <P><B>Note:</B> This method is optimized for handling stored
+     * procedure call statements. Some drivers may send the call
+     * statement to the database when the method <code>prepareCall</code>
+     * is done; others
+     * may wait until the <code>CallableStatement</code> object
+     * is executed. This has no
+     * direct effect on users; however, it does affect which method
+     * throws certain SQLExceptions.
+     * <P>
+     * Result sets created using the returned <code>CallableStatement</code>
+     * object will by default be type <code>TYPE_FORWARD_ONLY</code>
+     * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql an SQL statement that may contain one or more '?'
+     * parameter placeholders. Typically this statement is specified using JDBC
+     * call escape syntax.
+     * @return a new default <code>CallableStatement</code> object containing the
+     * pre-compiled SQL statement
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    CallableStatement prepareCall(String sql) throws SQLException;
+
+    /**
+     * Converts the given SQL statement into the system's native SQL grammar.
+     * A driver may convert the JDBC SQL grammar into its system's
+     * native SQL grammar prior to sending it. This method returns the
+     * native form of the statement that the driver would have sent.
+     *
+     * @param sql an SQL statement that may contain one or more '?'
+     * parameter placeholders
+     * @return the native form of this statement
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    String nativeSQL(String sql) throws SQLException;
+
+    /**
+     * Sets this connection's auto-commit mode to the given state.
+     * If a connection is in auto-commit mode, then all its SQL
+     * statements will be executed and committed as individual
+     * transactions.  Otherwise, its SQL statements are grouped into
+     * transactions that are terminated by a call to either
+     * the method <code>commit</code> or the method <code>rollback</code>.
+     * By default, new connections are in auto-commit
+     * mode.
+     * <P>
+     * The commit occurs when the statement completes. The time when the statement
+     * completes depends on the type of SQL Statement:
+     * <ul>
+     * <li>For DML statements, such as Insert, Update or Delete, and DDL statements,
+     * the statement is complete as soon as it has finished executing.
+     * <li>For Select statements, the statement is complete when the associated result
+     * set is closed.
+     * <li>For <code>CallableStatement</code> objects or for statements that return
+     * multiple results, the statement is complete
+     * when all of the associated result sets have been closed, and all update
+     * counts and output parameters have been retrieved.
+     *</ul>
+     * <P>
+     * <B>NOTE:</B>  If this method is called during a transaction and the
+     * auto-commit mode is changed, the transaction is committed.  If
+     * <code>setAutoCommit</code> is called and the auto-commit mode is
+     * not changed, the call is a no-op.
+     *
+     * @param autoCommit <code>true</code> to enable auto-commit mode;
+     *         <code>false</code> to disable it
+     * @exception SQLException if a database access error occurs,
+     *  setAutoCommit(true) is called while participating in a distributed transaction,
+     * or this method is called on a closed connection
+     * @see #getAutoCommit
+     */
+    void setAutoCommit(boolean autoCommit) throws SQLException;
+
+    /**
+     * Retrieves the current auto-commit mode for this <code>Connection</code>
+     * object.
+     *
+     * @return the current state of this <code>Connection</code> object's
+     *         auto-commit mode
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @see #setAutoCommit
+     */
+    boolean getAutoCommit() throws SQLException;
+
+    /**
+     * Makes all changes made since the previous
+     * commit/rollback permanent and releases any database locks
+     * currently held by this <code>Connection</code> object.
+     * This method should be
+     * used only when auto-commit mode has been disabled.
+     *
+     * @exception SQLException if a database access error occurs,
+     * this method is called while participating in a distributed transaction,
+     * if this method is called on a closed conection or this
+     *            <code>Connection</code> object is in auto-commit mode
+     * @see #setAutoCommit
+     */
+    void commit() throws SQLException;
+
+    /**
+     * Undoes all changes made in the current transaction
+     * and releases any database locks currently held
+     * by this <code>Connection</code> object. This method should be
+     * used only when auto-commit mode has been disabled.
+     *
+     * @exception SQLException if a database access error occurs,
+     * this method is called while participating in a distributed transaction,
+     * this method is called on a closed connection or this
+     *            <code>Connection</code> object is in auto-commit mode
+     * @see #setAutoCommit
+     */
+    void rollback() throws SQLException;
+
+    /**
+     * Releases this <code>Connection</code> object's database and JDBC resources
+     * immediately instead of waiting for them to be automatically released.
+     * <P>
+     * Calling the method <code>close</code> on a <code>Connection</code>
+     * object that is already closed is a no-op.
+     * <P>
+     * It is <b>strongly recommended</b> that an application explicitly
+     * commits or rolls back an active transaction prior to calling the
+     * <code>close</code> method.  If the <code>close</code> method is called
+     * and there is an active transaction, the results are implementation-defined.
+     * <P>
+     *
+     * @exception SQLException SQLException if a database access error occurs
+     */
+    void close() throws SQLException;
+
+    /**
+     * Retrieves whether this <code>Connection</code> object has been
+     * closed.  A connection is closed if the method <code>close</code>
+     * has been called on it or if certain fatal errors have occurred.
+     * This method is guaranteed to return <code>true</code> only when
+     * it is called after the method <code>Connection.close</code> has
+     * been called.
+     * <P>
+     * This method generally cannot be called to determine whether a
+     * connection to a database is valid or invalid.  A typical client
+     * can determine that a connection is invalid by catching any
+     * exceptions that might be thrown when an operation is attempted.
+     *
+     * @return <code>true</code> if this <code>Connection</code> object
+     *         is closed; <code>false</code> if it is still open
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isClosed() throws SQLException;
+
+    //======================================================================
+    // Advanced features:
+
+    /**
+     * Retrieves a <code>DatabaseMetaData</code> object that contains
+     * metadata about the database to which this
+     * <code>Connection</code> object represents a connection.
+     * The metadata includes information about the database's
+     * tables, its supported SQL grammar, its stored
+     * procedures, the capabilities of this connection, and so on.
+     *
+     * @return a <code>DatabaseMetaData</code> object for this
+     *         <code>Connection</code> object
+     * @exception  SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    DatabaseMetaData getMetaData() throws SQLException;
+
+    /**
+     * Puts this connection in read-only mode as a hint to the driver to enable
+     * database optimizations.
+     *
+     * <P><B>Note:</B> This method cannot be called during a transaction.
+     *
+     * @param readOnly <code>true</code> enables read-only mode;
+     *        <code>false</code> disables it
+     * @exception SQLException if a database access error occurs, this
+     *  method is called on a closed connection or this
+     *            method is called during a transaction
+     */
+    void setReadOnly(boolean readOnly) throws SQLException;
+
+    /**
+     * Retrieves whether this <code>Connection</code>
+     * object is in read-only mode.
+     *
+     * @return <code>true</code> if this <code>Connection</code> object
+     *         is read-only; <code>false</code> otherwise
+     * @exception SQLException SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    boolean isReadOnly() throws SQLException;
+
+    /**
+     * Sets the given catalog name in order to select
+     * a subspace of this <code>Connection</code> object's database
+     * in which to work.
+     * <P>
+     * If the driver does not support catalogs, it will
+     * silently ignore this request.
+     * <p>
+     * Calling {@code setCatalog} has no effect on previously created or prepared
+     * {@code Statement} objects. It is implementation defined whether a DBMS
+     * prepare operation takes place immediately when the {@code Connection}
+     * method {@code prepareStatement} or {@code prepareCall} is invoked.
+     * For maximum portability, {@code setCatalog} should be called before a
+     * {@code Statement} is created or prepared.
+     *
+     * @param catalog the name of a catalog (subspace in this
+     *        <code>Connection</code> object's database) in which to work
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @see #getCatalog
+     */
+    void setCatalog(String catalog) throws SQLException;
+
+    /**
+     * Retrieves this <code>Connection</code> object's current catalog name.
+     *
+     * @return the current catalog name or <code>null</code> if there is none
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @see #setCatalog
+     */
+    String getCatalog() throws SQLException;
+
+    /**
+     * A constant indicating that transactions are not supported.
+     */
+    int TRANSACTION_NONE             = 0;
+
+    /**
+     * A constant indicating that
+     * dirty reads, non-repeatable reads and phantom reads can occur.
+     * This level allows a row changed by one transaction to be read
+     * by another transaction before any changes in that row have been
+     * committed (a "dirty read").  If any of the changes are rolled back,
+     * the second transaction will have retrieved an invalid row.
+     */
+    int TRANSACTION_READ_UNCOMMITTED = 1;
+
+    /**
+     * A constant indicating that
+     * dirty reads are prevented; non-repeatable reads and phantom
+     * reads can occur.  This level only prohibits a transaction
+     * from reading a row with uncommitted changes in it.
+     */
+    int TRANSACTION_READ_COMMITTED   = 2;
+
+    /**
+     * A constant indicating that
+     * dirty reads and non-repeatable reads are prevented; phantom
+     * reads can occur.  This level prohibits a transaction from
+     * reading a row with uncommitted changes in it, and it also
+     * prohibits the situation where one transaction reads a row,
+     * a second transaction alters the row, and the first transaction
+     * rereads the row, getting different values the second time
+     * (a "non-repeatable read").
+     */
+    int TRANSACTION_REPEATABLE_READ  = 4;
+
+    /**
+     * A constant indicating that
+     * dirty reads, non-repeatable reads and phantom reads are prevented.
+     * This level includes the prohibitions in
+     * <code>TRANSACTION_REPEATABLE_READ</code> and further prohibits the
+     * situation where one transaction reads all rows that satisfy
+     * a <code>WHERE</code> condition, a second transaction inserts a row that
+     * satisfies that <code>WHERE</code> condition, and the first transaction
+     * rereads for the same condition, retrieving the additional
+     * "phantom" row in the second read.
+     */
+    int TRANSACTION_SERIALIZABLE     = 8;
+
+    /**
+     * Attempts to change the transaction isolation level for this
+     * <code>Connection</code> object to the one given.
+     * The constants defined in the interface <code>Connection</code>
+     * are the possible transaction isolation levels.
+     * <P>
+     * <B>Note:</B> If this method is called during a transaction, the result
+     * is implementation-defined.
+     *
+     * @param level one of the following <code>Connection</code> constants:
+     *        <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+     *        <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+     *        <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or
+     *        <code>Connection.TRANSACTION_SERIALIZABLE</code>.
+     *        (Note that <code>Connection.TRANSACTION_NONE</code> cannot be used
+     *        because it specifies that transactions are not supported.)
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection
+     *            or the given parameter is not one of the <code>Connection</code>
+     *            constants
+     * @see DatabaseMetaData#supportsTransactionIsolationLevel
+     * @see #getTransactionIsolation
+     */
+    void setTransactionIsolation(int level) throws SQLException;
+
+    /**
+     * Retrieves this <code>Connection</code> object's current
+     * transaction isolation level.
+     *
+     * @return the current transaction isolation level, which will be one
+     *         of the following constants:
+     *        <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
+     *        <code>Connection.TRANSACTION_READ_COMMITTED</code>,
+     *        <code>Connection.TRANSACTION_REPEATABLE_READ</code>,
+     *        <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
+     *        <code>Connection.TRANSACTION_NONE</code>.
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @see #setTransactionIsolation
+     */
+    int getTransactionIsolation() throws SQLException;
+
+    /**
+     * Retrieves the first warning reported by calls on this
+     * <code>Connection</code> object.  If there is more than one
+     * warning, subsequent warnings will be chained to the first one
+     * and can be retrieved by calling the method
+     * <code>SQLWarning.getNextWarning</code> on the warning
+     * that was retrieved previously.
+     * <P>
+     * This method may not be
+     * called on a closed connection; doing so will cause an
+     * <code>SQLException</code> to be thrown.
+     *
+     * <P><B>Note:</B> Subsequent warnings will be chained to this
+     * SQLWarning.
+     *
+     * @return the first <code>SQLWarning</code> object or <code>null</code>
+     *         if there are none
+     * @exception SQLException if a database access error occurs or
+     *            this method is called on a closed connection
+     * @see SQLWarning
+     */
+    SQLWarning getWarnings() throws SQLException;
+
+    /**
+     * Clears all warnings reported for this <code>Connection</code> object.
+     * After a call to this method, the method <code>getWarnings</code>
+     * returns <code>null</code> until a new warning is
+     * reported for this <code>Connection</code> object.
+     *
+     * @exception SQLException SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     */
+    void clearWarnings() throws SQLException;
+
+
+    //--------------------------JDBC 2.0-----------------------------
+
+    /**
+     * Creates a <code>Statement</code> object that will generate
+     * <code>ResultSet</code> objects with the given type and concurrency.
+     * This method is the same as the <code>createStatement</code> method
+     * above, but it allows the default result set
+     * type and concurrency to be overridden.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param resultSetType a result set type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency a concurrency type; one of
+     *        <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *        <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @return a new <code>Statement</code> object that will generate
+     *         <code>ResultSet</code> objects with the given type and
+     *         concurrency
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection
+     *         or the given parameters are not <code>ResultSet</code>
+     *         constants indicating type and concurrency
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type and result set concurrency.
+     * @since 1.2
+     */
+    Statement createStatement(int resultSetType, int resultSetConcurrency)
+        throws SQLException;
+
+    /**
+     *
+     * Creates a <code>PreparedStatement</code> object that will generate
+     * <code>ResultSet</code> objects with the given type and concurrency.
+     * This method is the same as the <code>prepareStatement</code> method
+     * above, but it allows the default result set
+     * type and concurrency to be overridden.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql a <code>String</code> object that is the SQL statement to
+     *            be sent to the database; may contain one or more '?' IN
+     *            parameters
+     * @param resultSetType a result set type; one of
+     *         <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *         <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency a concurrency type; one of
+     *         <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *         <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @return a new PreparedStatement object containing the
+     * pre-compiled SQL statement that will produce <code>ResultSet</code>
+     * objects with the given type and concurrency
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection
+     *         or the given parameters are not <code>ResultSet</code>
+     *         constants indicating type and concurrency
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type and result set concurrency.
+     * @since 1.2
+     */
+    PreparedStatement prepareStatement(String sql, int resultSetType,
+                                       int resultSetConcurrency)
+        throws SQLException;
+
+    /**
+     * Creates a <code>CallableStatement</code> object that will generate
+     * <code>ResultSet</code> objects with the given type and concurrency.
+     * This method is the same as the <code>prepareCall</code> method
+     * above, but it allows the default result set
+     * type and concurrency to be overridden.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql a <code>String</code> object that is the SQL statement to
+     *            be sent to the database; may contain on or more '?' parameters
+     * @param resultSetType a result set type; one of
+     *         <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *         <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency a concurrency type; one of
+     *         <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *         <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @return a new <code>CallableStatement</code> object containing the
+     * pre-compiled SQL statement that will produce <code>ResultSet</code>
+     * objects with the given type and concurrency
+     * @exception SQLException if a database access error occurs, this method
+     * is called on a closed connection
+     *         or the given parameters are not <code>ResultSet</code>
+     *         constants indicating type and concurrency
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type and result set concurrency.
+     * @since 1.2
+     */
+    CallableStatement prepareCall(String sql, int resultSetType,
+                                  int resultSetConcurrency) throws SQLException;
+
+    /**
+     * Retrieves the <code>Map</code> object associated with this
+     * <code>Connection</code> object.
+     * Unless the application has added an entry, the type map returned
+     * will be empty.
+     * <p>
+     * You must invoke <code>setTypeMap</code> after making changes to the
+     * <code>Map</code> object returned from
+     *  <code>getTypeMap</code> as a JDBC driver may create an internal
+     * copy of the <code>Map</code> object passed to <code>setTypeMap</code>:
+     * <p>
+     * <pre>
+     *      Map&lt;String,Class&lt;?&gt;&gt; myMap = con.getTypeMap();
+     *      myMap.put("mySchemaName.ATHLETES", Athletes.class);
+     *      con.setTypeMap(myMap);
+     * </pre>
+     * @return the <code>java.util.Map</code> object associated
+     *         with this <code>Connection</code> object
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     * @see #setTypeMap
+     */
+    java.util.Map<String,Class<?>> getTypeMap() throws SQLException;
+
+    /**
+     * Installs the given <code>TypeMap</code> object as the type map for
+     * this <code>Connection</code> object.  The type map will be used for the
+     * custom mapping of SQL structured types and distinct types.
+     *<p>
+     * You must set the the values for the <code>TypeMap</code> prior to
+     * callng <code>setMap</code> as a JDBC driver may create an internal copy
+     * of the <code>TypeMap</code>:
+     * <p>
+     * <pre>
+     *      Map myMap&lt;String,Class&lt;?&gt;&gt; = new HashMap&lt;String,Class&lt;?&gt;&gt;();
+     *      myMap.put("mySchemaName.ATHLETES", Athletes.class);
+     *      con.setTypeMap(myMap);
+     * </pre>
+     * @param map the <code>java.util.Map</code> object to install
+     *        as the replacement for this <code>Connection</code>
+     *        object's default type map
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection or
+     *        the given parameter is not a <code>java.util.Map</code>
+     *        object
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     * @see #getTypeMap
+     */
+    void setTypeMap(java.util.Map<String,Class<?>> map) throws SQLException;
+
+    //--------------------------JDBC 3.0-----------------------------
+
+
+    /**
+     * Changes the default holdability of <code>ResultSet</code> objects
+     * created using this <code>Connection</code> object to the given
+     * holdability.  The default holdability of <code>ResultSet</code> objects
+     * can be be determined by invoking
+     * {@link DatabaseMetaData#getResultSetHoldability}.
+     *
+     * @param holdability a <code>ResultSet</code> holdability constant; one of
+     *        <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *        <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @throws SQLException if a database access occurs, this method is called
+     * on a closed connection, or the given parameter
+     *         is not a <code>ResultSet</code> constant indicating holdability
+     * @exception SQLFeatureNotSupportedException if the given holdability is not supported
+     * @see #getHoldability
+     * @see DatabaseMetaData#getResultSetHoldability
+     * @see ResultSet
+     * @since 1.4
+     */
+    void setHoldability(int holdability) throws SQLException;
+
+    /**
+     * Retrieves the current holdability of <code>ResultSet</code> objects
+     * created using this <code>Connection</code> object.
+     *
+     * @return the holdability, one of
+     *        <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *        <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @throws SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @see #setHoldability
+     * @see DatabaseMetaData#getResultSetHoldability
+     * @see ResultSet
+     * @since 1.4
+     */
+    int getHoldability() throws SQLException;
+
+    /**
+     * Creates an unnamed savepoint in the current transaction and
+     * returns the new <code>Savepoint</code> object that represents it.
+     *
+     *<p> if setSavepoint is invoked outside of an active transaction, a transaction will be started at this newly created
+     *savepoint.
+     *
+     * @return the new <code>Savepoint</code> object
+     * @exception SQLException if a database access error occurs,
+     * this method is called while participating in a distributed transaction,
+     * this method is called on a closed connection
+     *            or this <code>Connection</code> object is currently in
+     *            auto-commit mode
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see Savepoint
+     * @since 1.4
+     */
+    Savepoint setSavepoint() throws SQLException;
+
+    /**
+     * Creates a savepoint with the given name in the current transaction
+     * and returns the new <code>Savepoint</code> object that represents it.
+     *
+     * <p> if setSavepoint is invoked outside of an active transaction, a transaction will be started at this newly created
+     *savepoint.
+     *
+     * @param name a <code>String</code> containing the name of the savepoint
+     * @return the new <code>Savepoint</code> object
+     * @exception SQLException if a database access error occurs,
+          * this method is called while participating in a distributed transaction,
+     * this method is called on a closed connection
+     *            or this <code>Connection</code> object is currently in
+     *            auto-commit mode
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see Savepoint
+     * @since 1.4
+     */
+    Savepoint setSavepoint(String name) throws SQLException;
+
+    /**
+     * Undoes all changes made after the given <code>Savepoint</code> object
+     * was set.
+     * <P>
+     * This method should be used only when auto-commit has been disabled.
+     *
+     * @param savepoint the <code>Savepoint</code> object to roll back to
+     * @exception SQLException if a database access error occurs,
+     * this method is called while participating in a distributed transaction,
+     * this method is called on a closed connection,
+     *            the <code>Savepoint</code> object is no longer valid,
+     *            or this <code>Connection</code> object is currently in
+     *            auto-commit mode
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see Savepoint
+     * @see #rollback
+     * @since 1.4
+     */
+    void rollback(Savepoint savepoint) throws SQLException;
+
+    /**
+     * Removes the specified <code>Savepoint</code>  and subsequent <code>Savepoint</code> objects from the current
+     * transaction. Any reference to the savepoint after it have been removed
+     * will cause an <code>SQLException</code> to be thrown.
+     *
+     * @param savepoint the <code>Savepoint</code> object to be removed
+     * @exception SQLException if a database access error occurs, this
+     *  method is called on a closed connection or
+     *            the given <code>Savepoint</code> object is not a valid
+     *            savepoint in the current transaction
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void releaseSavepoint(Savepoint savepoint) throws SQLException;
+
+    /**
+     * Creates a <code>Statement</code> object that will generate
+     * <code>ResultSet</code> objects with the given type, concurrency,
+     * and holdability.
+     * This method is the same as the <code>createStatement</code> method
+     * above, but it allows the default result set
+     * type, concurrency, and holdability to be overridden.
+     *
+     * @param resultSetType one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *         <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *         <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @param resultSetHoldability one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @return a new <code>Statement</code> object that will generate
+     *         <code>ResultSet</code> objects with the given type,
+     *         concurrency, and holdability
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection
+     *            or the given parameters are not <code>ResultSet</code>
+     *            constants indicating type, concurrency, and holdability
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type, result set holdability and result set concurrency.
+     * @see ResultSet
+     * @since 1.4
+     */
+    Statement createStatement(int resultSetType, int resultSetConcurrency,
+                              int resultSetHoldability) throws SQLException;
+
+    /**
+     * Creates a <code>PreparedStatement</code> object that will generate
+     * <code>ResultSet</code> objects with the given type, concurrency,
+     * and holdability.
+     * <P>
+     * This method is the same as the <code>prepareStatement</code> method
+     * above, but it allows the default result set
+     * type, concurrency, and holdability to be overridden.
+     *
+     * @param sql a <code>String</code> object that is the SQL statement to
+     *            be sent to the database; may contain one or more '?' IN
+     *            parameters
+     * @param resultSetType one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *         <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *         <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @param resultSetHoldability one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @return a new <code>PreparedStatement</code> object, containing the
+     *         pre-compiled SQL statement, that will generate
+     *         <code>ResultSet</code> objects with the given type,
+     *         concurrency, and holdability
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection
+     *            or the given parameters are not <code>ResultSet</code>
+     *            constants indicating type, concurrency, and holdability
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type, result set holdability and result set concurrency.
+     * @see ResultSet
+     * @since 1.4
+     */
+    PreparedStatement prepareStatement(String sql, int resultSetType,
+                                       int resultSetConcurrency, int resultSetHoldability)
+        throws SQLException;
+
+    /**
+     * Creates a <code>CallableStatement</code> object that will generate
+     * <code>ResultSet</code> objects with the given type and concurrency.
+     * This method is the same as the <code>prepareCall</code> method
+     * above, but it allows the default result set
+     * type, result set concurrency type and holdability to be overridden.
+     *
+     * @param sql a <code>String</code> object that is the SQL statement to
+     *            be sent to the database; may contain on or more '?' parameters
+     * @param resultSetType one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *         <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @param resultSetConcurrency one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.CONCUR_READ_ONLY</code> or
+     *         <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @param resultSetHoldability one of the following <code>ResultSet</code>
+     *        constants:
+     *         <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @return a new <code>CallableStatement</code> object, containing the
+     *         pre-compiled SQL statement, that will generate
+     *         <code>ResultSet</code> objects with the given type,
+     *         concurrency, and holdability
+     * @exception SQLException if a database access error occurs, this
+     * method is called on a closed connection
+     *            or the given parameters are not <code>ResultSet</code>
+     *            constants indicating type, concurrency, and holdability
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type, result set holdability and result set concurrency.
+     * @see ResultSet
+     * @since 1.4
+     */
+    CallableStatement prepareCall(String sql, int resultSetType,
+                                  int resultSetConcurrency,
+                                  int resultSetHoldability) throws SQLException;
+
+
+    /**
+     * Creates a default <code>PreparedStatement</code> object that has
+     * the capability to retrieve auto-generated keys. The given constant
+     * tells the driver whether it should make auto-generated keys
+     * available for retrieval.  This parameter is ignored if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     * <P>
+     * <B>Note:</B> This method is optimized for handling
+     * parametric SQL statements that benefit from precompilation. If
+     * the driver supports precompilation,
+     * the method <code>prepareStatement</code> will send
+     * the statement to the database for precompilation. Some drivers
+     * may not support precompilation. In this case, the statement may
+     * not be sent to the database until the <code>PreparedStatement</code>
+     * object is executed.  This has no direct effect on users; however, it does
+     * affect which methods throw certain SQLExceptions.
+     * <P>
+     * Result sets created using the returned <code>PreparedStatement</code>
+     * object will by default be type <code>TYPE_FORWARD_ONLY</code>
+     * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql an SQL statement that may contain one or more '?' IN
+     *        parameter placeholders
+     * @param autoGeneratedKeys a flag indicating whether auto-generated keys
+     *        should be returned; one of
+     *        <code>Statement.RETURN_GENERATED_KEYS</code> or
+     *        <code>Statement.NO_GENERATED_KEYS</code>
+     * @return a new <code>PreparedStatement</code> object, containing the
+     *         pre-compiled SQL statement, that will have the capability of
+     *         returning auto-generated keys
+     * @exception SQLException if a database access error occurs, this
+     *  method is called on a closed connection
+     *         or the given parameter is not a <code>Statement</code>
+     *         constant indicating whether auto-generated keys should be
+     *         returned
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method with a constant of Statement.RETURN_GENERATED_KEYS
+     * @since 1.4
+     */
+    PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
+        throws SQLException;
+
+    /**
+     * Creates a default <code>PreparedStatement</code> object capable
+     * of returning the auto-generated keys designated by the given array.
+     * This array contains the indexes of the columns in the target
+     * table that contain the auto-generated keys that should be made
+     * available.  The driver will ignore the array if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     *<p>
+     * An SQL statement with or without IN parameters can be
+     * pre-compiled and stored in a <code>PreparedStatement</code> object. This
+     * object can then be used to efficiently execute this statement
+     * multiple times.
+     * <P>
+     * <B>Note:</B> This method is optimized for handling
+     * parametric SQL statements that benefit from precompilation. If
+     * the driver supports precompilation,
+     * the method <code>prepareStatement</code> will send
+     * the statement to the database for precompilation. Some drivers
+     * may not support precompilation. In this case, the statement may
+     * not be sent to the database until the <code>PreparedStatement</code>
+     * object is executed.  This has no direct effect on users; however, it does
+     * affect which methods throw certain SQLExceptions.
+     * <P>
+     * Result sets created using the returned <code>PreparedStatement</code>
+     * object will by default be type <code>TYPE_FORWARD_ONLY</code>
+     * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql an SQL statement that may contain one or more '?' IN
+     *        parameter placeholders
+     * @param columnIndexes an array of column indexes indicating the columns
+     *        that should be returned from the inserted row or rows
+     * @return a new <code>PreparedStatement</code> object, containing the
+     *         pre-compiled statement, that is capable of returning the
+     *         auto-generated keys designated by the given array of column
+     *         indexes
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @since 1.4
+     */
+    PreparedStatement prepareStatement(String sql, int columnIndexes[])
+        throws SQLException;
+
+    /**
+     * Creates a default <code>PreparedStatement</code> object capable
+     * of returning the auto-generated keys designated by the given array.
+     * This array contains the names of the columns in the target
+     * table that contain the auto-generated keys that should be returned.
+     * The driver will ignore the array if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     * <P>
+     * An SQL statement with or without IN parameters can be
+     * pre-compiled and stored in a <code>PreparedStatement</code> object. This
+     * object can then be used to efficiently execute this statement
+     * multiple times.
+     * <P>
+     * <B>Note:</B> This method is optimized for handling
+     * parametric SQL statements that benefit from precompilation. If
+     * the driver supports precompilation,
+     * the method <code>prepareStatement</code> will send
+     * the statement to the database for precompilation. Some drivers
+     * may not support precompilation. In this case, the statement may
+     * not be sent to the database until the <code>PreparedStatement</code>
+     * object is executed.  This has no direct effect on users; however, it does
+     * affect which methods throw certain SQLExceptions.
+     * <P>
+     * Result sets created using the returned <code>PreparedStatement</code>
+     * object will by default be type <code>TYPE_FORWARD_ONLY</code>
+     * and have a concurrency level of <code>CONCUR_READ_ONLY</code>.
+     * The holdability of the created result sets can be determined by
+     * calling {@link #getHoldability}.
+     *
+     * @param sql an SQL statement that may contain one or more '?' IN
+     *        parameter placeholders
+     * @param columnNames an array of column names indicating the columns
+     *        that should be returned from the inserted row or rows
+     * @return a new <code>PreparedStatement</code> object, containing the
+     *         pre-compiled statement, that is capable of returning the
+     *         auto-generated keys designated by the given array of column
+     *         names
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed connection
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @since 1.4
+     */
+    PreparedStatement prepareStatement(String sql, String columnNames[])
+        throws SQLException;
+
+    /**
+     * Constructs an object that implements the <code>Clob</code> interface. The object
+     * returned initially contains no data.  The <code>setAsciiStream</code>,
+     * <code>setCharacterStream</code> and <code>setString</code> methods of
+     * the <code>Clob</code> interface may be used to add data to the <code>Clob</code>.
+     * @return An object that implements the <code>Clob</code> interface
+     * @throws SQLException if an object that implements the
+     * <code>Clob</code> interface can not be constructed, this method is
+     * called on a closed connection or a database access error occurs.
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this data type
+     *
+     * @since 1.6
+     */
+    Clob createClob() throws SQLException;
+
+    /**
+     * Constructs an object that implements the <code>Blob</code> interface. The object
+     * returned initially contains no data.  The <code>setBinaryStream</code> and
+     * <code>setBytes</code> methods of the <code>Blob</code> interface may be used to add data to
+     * the <code>Blob</code>.
+     * @return  An object that implements the <code>Blob</code> interface
+     * @throws SQLException if an object that implements the
+     * <code>Blob</code> interface can not be constructed, this method is
+     * called on a closed connection or a database access error occurs.
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this data type
+     *
+     * @since 1.6
+     */
+    Blob createBlob() throws SQLException;
+
+    /**
+     * Constructs an object that implements the <code>NClob</code> interface. The object
+     * returned initially contains no data.  The <code>setAsciiStream</code>,
+     * <code>setCharacterStream</code> and <code>setString</code> methods of the <code>NClob</code> interface may
+     * be used to add data to the <code>NClob</code>.
+     * @return An object that implements the <code>NClob</code> interface
+     * @throws SQLException if an object that implements the
+     * <code>NClob</code> interface can not be constructed, this method is
+     * called on a closed connection or a database access error occurs.
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this data type
+     *
+     * @since 1.6
+     */
+    NClob createNClob() throws SQLException;
+
+    /**
+     * Constructs an object that implements the <code>SQLXML</code> interface. The object
+     * returned initially contains no data. The <code>createXmlStreamWriter</code> object and
+     * <code>setString</code> method of the <code>SQLXML</code> interface may be used to add data to the <code>SQLXML</code>
+     * object.
+     * @return An object that implements the <code>SQLXML</code> interface
+     * @throws SQLException if an object that implements the <code>SQLXML</code> interface can not
+     * be constructed, this method is
+     * called on a closed connection or a database access error occurs.
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this data type
+     * @since 1.6
+     */
+    SQLXML createSQLXML() throws SQLException;
+
+        /**
+         * Returns true if the connection has not been closed and is still valid.
+         * The driver shall submit a query on the connection or use some other
+         * mechanism that positively verifies the connection is still valid when
+         * this method is called.
+         * <p>
+         * The query submitted by the driver to validate the connection shall be
+         * executed in the context of the current transaction.
+         *
+         * @param timeout -             The time in seconds to wait for the database operation
+         *                                              used to validate the connection to complete.  If
+         *                                              the timeout period expires before the operation
+         *                                              completes, this method returns false.  A value of
+         *                                              0 indicates a timeout is not applied to the
+         *                                              database operation.
+         * <p>
+         * @return true if the connection is valid, false otherwise
+         * @exception SQLException if the value supplied for <code>timeout</code>
+         * is less then 0
+         * @since 1.6
+         * <p>
+         * @see java.sql.DatabaseMetaData#getClientInfoProperties
+         */
+         boolean isValid(int timeout) throws SQLException;
+
+        /**
+         * Sets the value of the client info property specified by name to the
+         * value specified by value.
+         * <p>
+         * Applications may use the <code>DatabaseMetaData.getClientInfoProperties</code>
+         * method to determine the client info properties supported by the driver
+         * and the maximum length that may be specified for each property.
+         * <p>
+         * The driver stores the value specified in a suitable location in the
+         * database.  For example in a special register, session parameter, or
+         * system table column.  For efficiency the driver may defer setting the
+         * value in the database until the next time a statement is executed or
+         * prepared.  Other than storing the client information in the appropriate
+         * place in the database, these methods shall not alter the behavior of
+         * the connection in anyway.  The values supplied to these methods are
+         * used for accounting, diagnostics and debugging purposes only.
+         * <p>
+         * The driver shall generate a warning if the client info name specified
+         * is not recognized by the driver.
+         * <p>
+         * If the value specified to this method is greater than the maximum
+         * length for the property the driver may either truncate the value and
+         * generate a warning or generate a <code>SQLClientInfoException</code>.  If the driver
+         * generates a <code>SQLClientInfoException</code>, the value specified was not set on the
+         * connection.
+         * <p>
+         * The following are standard client info properties.  Drivers are not
+         * required to support these properties however if the driver supports a
+         * client info property that can be described by one of the standard
+         * properties, the standard property name should be used.
+         * <p>
+         * <ul>
+         * <li>ApplicationName  -       The name of the application currently utilizing
+         *                                                      the connection</li>
+         * <li>ClientUser               -       The name of the user that the application using
+         *                                                      the connection is performing work for.  This may
+         *                                                      not be the same as the user name that was used
+         *                                                      in establishing the connection.</li>
+         * <li>ClientHostname   -       The hostname of the computer the application
+         *                                                      using the connection is running on.</li>
+         * </ul>
+         * <p>
+         * @param name          The name of the client info property to set
+         * @param value         The value to set the client info property to.  If the
+         *                                      value is null, the current value of the specified
+         *                                      property is cleared.
+         * <p>
+         * @throws      SQLClientInfoException if the database server returns an error while
+         *                      setting the client info value on the database server or this method
+         * is called on a closed connection
+         * <p>
+         * @since 1.6
+         */
+         void setClientInfo(String name, String value)
+                throws SQLClientInfoException;
+
+        /**
+     * Sets the value of the connection's client info properties.  The
+     * <code>Properties</code> object contains the names and values of the client info
+     * properties to be set.  The set of client info properties contained in
+     * the properties list replaces the current set of client info properties
+     * on the connection.  If a property that is currently set on the
+     * connection is not present in the properties list, that property is
+     * cleared.  Specifying an empty properties list will clear all of the
+     * properties on the connection.  See <code>setClientInfo (String, String)</code> for
+     * more information.
+     * <p>
+     * If an error occurs in setting any of the client info properties, a
+     * <code>SQLClientInfoException</code> is thrown. The <code>SQLClientInfoException</code>
+     * contains information indicating which client info properties were not set.
+     * The state of the client information is unknown because
+     * some databases do not allow multiple client info properties to be set
+     * atomically.  For those databases, one or more properties may have been
+     * set before the error occurred.
+     * <p>
+     *
+     * @param properties                the list of client info properties to set
+     * <p>
+     * @see java.sql.Connection#setClientInfo(String, String) setClientInfo(String, String)
+     * @since 1.6
+     * <p>
+     * @throws SQLClientInfoException if the database server returns an error while
+     *                  setting the clientInfo values on the database server or this method
+     * is called on a closed connection
+     * <p>
+     */
+         void setClientInfo(Properties properties)
+                throws SQLClientInfoException;
+
+        /**
+         * Returns the value of the client info property specified by name.  This
+         * method may return null if the specified client info property has not
+         * been set and does not have a default value.  This method will also
+         * return null if the specified client info property name is not supported
+         * by the driver.
+         * <p>
+         * Applications may use the <code>DatabaseMetaData.getClientInfoProperties</code>
+         * method to determine the client info properties supported by the driver.
+         * <p>
+         * @param name          The name of the client info property to retrieve
+         * <p>
+         * @return                      The value of the client info property specified
+         * <p>
+         * @throws SQLException         if the database server returns an error when
+         *                                                      fetching the client info value from the database
+         *or this method is called on a closed connection
+         * <p>
+         * @since 1.6
+         * <p>
+         * @see java.sql.DatabaseMetaData#getClientInfoProperties
+         */
+         String getClientInfo(String name)
+                throws SQLException;
+
+        /**
+         * Returns a list containing the name and current value of each client info
+         * property supported by the driver.  The value of a client info property
+         * may be null if the property has not been set and does not have a
+         * default value.
+         * <p>
+         * @return      A <code>Properties</code> object that contains the name and current value of
+         *                      each of the client info properties supported by the driver.
+         * <p>
+         * @throws      SQLException if the database server returns an error when
+         *                      fetching the client info values from the database
+         * or this method is called on a closed connection
+         * <p>
+         * @since 1.6
+         */
+         Properties getClientInfo()
+                throws SQLException;
+
+/**
+  * Factory method for creating Array objects.
+  *<p>
+  * <b>Note: </b>When <code>createArrayOf</code> is used to create an array object
+  * that maps to a primitive data type, then it is implementation-defined
+  * whether the <code>Array</code> object is an array of that primitive
+  * data type or an array of <code>Object</code>.
+  * <p>
+  * <b>Note: </b>The JDBC driver is responsible for mapping the elements
+  * <code>Object</code> array to the default JDBC SQL type defined in
+  * java.sql.Types for the given class of <code>Object</code>. The default
+  * mapping is specified in Appendix B of the JDBC specification.  If the
+  * resulting JDBC type is not the appropriate type for the given typeName then
+  * it is implementation defined whether an <code>SQLException</code> is
+  * thrown or the driver supports the resulting conversion.
+  *
+  * @param typeName the SQL name of the type the elements of the array map to. The typeName is a
+  * database-specific name which may be the name of a built-in type, a user-defined type or a standard  SQL type supported by this database. This
+  *  is the value returned by <code>Array.getBaseTypeName</code>
+  * @param elements the elements that populate the returned object
+  * @return an Array object whose elements map to the specified SQL type
+  * @throws SQLException if a database error occurs, the JDBC type is not
+  *  appropriate for the typeName and the conversion is not supported, the typeName is null or this method is called on a closed connection
+  * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this data type
+  * @since 1.6
+  */
+ Array createArrayOf(String typeName, Object[] elements) throws
+SQLException;
+
+/**
+  * Factory method for creating Struct objects.
+  *
+  * @param typeName the SQL type name of the SQL structured type that this <code>Struct</code>
+  * object maps to. The typeName is the name of  a user-defined type that
+  * has been defined for this database. It is the value returned by
+  * <code>Struct.getSQLTypeName</code>.
+
+  * @param attributes the attributes that populate the returned object
+  *  @return a Struct object that maps to the given SQL type and is populated with the given attributes
+  * @throws SQLException if a database error occurs, the typeName is null or this method is called on a closed connection
+  * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this data type
+  * @since 1.6
+  */
+ Struct createStruct(String typeName, Object[] attributes)
+throws SQLException;
+
+    // Android-removed: JDBC 4.1 methods were removed immediately after the initial import.
+}
diff --git a/java/sql/DataTruncation.java b/java/sql/DataTruncation.java
new file mode 100644
index 0000000..09d43ac
--- /dev/null
+++ b/java/sql/DataTruncation.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * An exception  thrown as a <code>DataTruncation</code> exception
+ * (on writes) or reported as a
+ * <code>DataTruncation</code> warning (on reads)
+ *  when a data values is unexpectedly truncated for reasons other than its having
+ *  execeeded <code>MaxFieldSize</code>.
+ *
+ * <P>The SQLstate for a <code>DataTruncation</code> during read is <code>01004</code>.
+ * <P>The SQLstate for a <code>DataTruncation</code> during write is <code>22001</code>.
+ */
+
+public class DataTruncation extends SQLWarning {
+
+    /**
+     * Creates a <code>DataTruncation</code> object
+     * with the SQLState initialized
+     * to 01004 when <code>read</code> is set to <code>true</code> and 22001
+     * when <code>read</code> is set to <code>false</code>,
+     * the reason set to "Data truncation", the
+     * vendor code set to 0, and
+     * the other fields set to the given values.
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     *
+     * @param index The index of the parameter or column value
+     * @param parameter true if a parameter value was truncated
+     * @param read true if a read was truncated
+     * @param dataSize the original size of the data
+     * @param transferSize the size after truncation
+     */
+    public DataTruncation(int index, boolean parameter,
+                          boolean read, int dataSize,
+                          int transferSize) {
+        super("Data truncation", read == true?"01004":"22001");
+        this.index = index;
+        this.parameter = parameter;
+        this.read = read;
+        this.dataSize = dataSize;
+        this.transferSize = transferSize;
+
+    }
+
+    /**
+     * Creates a <code>DataTruncation</code> object
+     * with the SQLState initialized
+     * to 01004 when <code>read</code> is set to <code>true</code> and 22001
+     * when <code>read</code> is set to <code>false</code>,
+     * the reason set to "Data truncation", the
+     * vendor code set to 0, and
+     * the other fields set to the given values.
+     * <p>
+     *
+     * @param index The index of the parameter or column value
+     * @param parameter true if a parameter value was truncated
+     * @param read true if a read was truncated
+     * @param dataSize the original size of the data
+     * @param transferSize the size after truncation
+     * @param cause the underlying reason for this <code>DataTruncation</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating the cause is non-existent or unknown.
+     *
+     * @since 1.6
+     */
+    public DataTruncation(int index, boolean parameter,
+                          boolean read, int dataSize,
+                          int transferSize, Throwable cause) {
+        super("Data truncation", read == true?"01004":"22001",cause);
+        this.index = index;
+        this.parameter = parameter;
+        this.read = read;
+        this.dataSize = dataSize;
+        this.transferSize = transferSize;
+    }
+
+    /**
+     * Retrieves the index of the column or parameter that was truncated.
+     *
+     * <P>This may be -1 if the column or parameter index is unknown, in
+     * which case the <code>parameter</code> and <code>read</code> fields should be ignored.
+     *
+     * @return the index of the truncated paramter or column value
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Indicates whether the value truncated was a parameter value or
+         * a column value.
+     *
+     * @return <code>true</code> if the value truncated was a parameter;
+         *         <code>false</code> if it was a column value
+     */
+    public boolean getParameter() {
+        return parameter;
+    }
+
+    /**
+     * Indicates whether or not the value was truncated on a read.
+     *
+     * @return <code>true</code> if the value was truncated when read from
+         *         the database; <code>false</code> if the data was truncated on a write
+     */
+    public boolean getRead() {
+        return read;
+    }
+
+    /**
+     * Gets the number of bytes of data that should have been transferred.
+     * This number may be approximate if data conversions were being
+     * performed.  The value may be <code>-1</code> if the size is unknown.
+     *
+     * @return the number of bytes of data that should have been transferred
+     */
+    public int getDataSize() {
+        return dataSize;
+    }
+
+    /**
+     * Gets the number of bytes of data actually transferred.
+     * The value may be <code>-1</code> if the size is unknown.
+     *
+     * @return the number of bytes of data actually transferred
+     */
+    public int getTransferSize() {
+        return transferSize;
+    }
+
+        /**
+        * @serial
+        */
+    private int index;
+
+        /**
+        * @serial
+        */
+    private boolean parameter;
+
+        /**
+        * @serial
+        */
+    private boolean read;
+
+        /**
+        * @serial
+        */
+    private int dataSize;
+
+        /**
+        * @serial
+        */
+    private int transferSize;
+
+    /**
+     * @serial
+     */
+    private static final long serialVersionUID = 6464298989504059473L;
+
+}
diff --git a/java/sql/DatabaseMetaData.java b/java/sql/DatabaseMetaData.java
new file mode 100644
index 0000000..8e7441c
--- /dev/null
+++ b/java/sql/DatabaseMetaData.java
@@ -0,0 +1,3578 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.sql;
+
+/**
+ * Comprehensive information about the database as a whole.
+ * <P>
+ * This interface is implemented by driver vendors to let users know the capabilities
+ * of a Database Management System (DBMS) in combination with
+ * the driver based on JDBC<sup><font size=-2>TM</font></sup> technology
+ * ("JDBC driver") that is used with it.  Different relational DBMSs often support
+ * different features, implement features in different ways, and use different
+ * data types.  In addition, a driver may implement a feature on top of what the
+ * DBMS offers.  Information returned by methods in this interface applies
+ * to the capabilities of a particular driver and a particular DBMS working
+ * together. Note that as used in this documentation, the term "database" is
+ * used generically to refer to both the driver and DBMS.
+ * <P>
+ * A user for this interface is commonly a tool that needs to discover how to
+ * deal with the underlying DBMS.  This is especially true for applications
+ * that are intended to be used with more than one DBMS. For example, a tool might use the method
+ * <code>getTypeInfo</code> to find out what data types can be used in a
+ * <code>CREATE TABLE</code> statement.  Or a user might call the method
+ * <code>supportsCorrelatedSubqueries</code> to see if it is possible to use
+ * a correlated subquery or <code>supportsBatchUpdates</code> to see if it is
+ * possible to use batch updates.
+ * <P>
+ * Some <code>DatabaseMetaData</code> methods return lists of information
+ * in the form of <code>ResultSet</code> objects.
+ * Regular <code>ResultSet</code> methods, such as
+ * <code>getString</code> and <code>getInt</code>, can be used
+ * to retrieve the data from these <code>ResultSet</code> objects.  If
+ * a given form of metadata is not available, an empty <code>ResultSet</code>
+ * will be returned. Additional columns beyond the columns defined to be
+ * returned by the <code>ResultSet</code> object for a given method
+ * can be defined by the JDBC driver vendor and must be accessed
+ * by their <B>column label</B>.
+ * <P>
+ * Some <code>DatabaseMetaData</code> methods take arguments that are
+ * String patterns.  These arguments all have names such as fooPattern.
+ * Within a pattern String, "%" means match any substring of 0 or more
+ * characters, and "_" means match any one character. Only metadata
+ * entries matching the search pattern are returned. If a search pattern
+ * argument is set to <code>null</code>, that argument's criterion will
+ * be dropped from the search.
+ * <P>
+ */
+public interface DatabaseMetaData extends Wrapper {
+
+    //----------------------------------------------------------------------
+    // First, a variety of minor information about the target database.
+
+    /**
+     * Retrieves whether the current user can call all the procedures
+     * returned by the method <code>getProcedures</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean allProceduresAreCallable() throws SQLException;
+
+    /**
+     * Retrieves whether the current user can use all the tables returned
+     * by the method <code>getTables</code> in a <code>SELECT</code>
+     * statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean allTablesAreSelectable() throws SQLException;
+
+    /**
+     * Retrieves the URL for this DBMS.
+     *
+     * @return the URL for this DBMS or <code>null</code> if it cannot be
+     *          generated
+     * @exception SQLException if a database access error occurs
+     */
+    String getURL() throws SQLException;
+
+    /**
+     * Retrieves the user name as known to this database.
+     *
+     * @return the database user name
+     * @exception SQLException if a database access error occurs
+     */
+    String getUserName() throws SQLException;
+
+    /**
+     * Retrieves whether this database is in read-only mode.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isReadOnly() throws SQLException;
+
+    /**
+     * Retrieves whether <code>NULL</code> values are sorted high.
+     * Sorted high means that <code>NULL</code> values
+     * sort higher than any other value in a domain.  In an ascending order,
+     * if this method returns <code>true</code>,  <code>NULL</code> values
+     * will appear at the end. By contrast, the method
+     * <code>nullsAreSortedAtEnd</code> indicates whether <code>NULL</code> values
+     * are sorted at the end regardless of sort order.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean nullsAreSortedHigh() throws SQLException;
+
+    /**
+     * Retrieves whether <code>NULL</code> values are sorted low.
+     * Sorted low means that <code>NULL</code> values
+     * sort lower than any other value in a domain.  In an ascending order,
+     * if this method returns <code>true</code>,  <code>NULL</code> values
+     * will appear at the beginning. By contrast, the method
+     * <code>nullsAreSortedAtStart</code> indicates whether <code>NULL</code> values
+     * are sorted at the beginning regardless of sort order.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean nullsAreSortedLow() throws SQLException;
+
+    /**
+     * Retrieves whether <code>NULL</code> values are sorted at the start regardless
+     * of sort order.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean nullsAreSortedAtStart() throws SQLException;
+
+    /**
+     * Retrieves whether <code>NULL</code> values are sorted at the end regardless of
+     * sort order.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean nullsAreSortedAtEnd() throws SQLException;
+
+    /**
+     * Retrieves the name of this database product.
+     *
+     * @return database product name
+     * @exception SQLException if a database access error occurs
+     */
+    String getDatabaseProductName() throws SQLException;
+
+    /**
+     * Retrieves the version number of this database product.
+     *
+     * @return database version number
+     * @exception SQLException if a database access error occurs
+     */
+    String getDatabaseProductVersion() throws SQLException;
+
+    /**
+     * Retrieves the name of this JDBC driver.
+     *
+     * @return JDBC driver name
+     * @exception SQLException if a database access error occurs
+     */
+    String getDriverName() throws SQLException;
+
+    /**
+     * Retrieves the version number of this JDBC driver as a <code>String</code>.
+     *
+     * @return JDBC driver version
+     * @exception SQLException if a database access error occurs
+     */
+    String getDriverVersion() throws SQLException;
+
+    /**
+     * Retrieves this JDBC driver's major version number.
+     *
+     * @return JDBC driver major version
+     */
+    int getDriverMajorVersion();
+
+    /**
+     * Retrieves this JDBC driver's minor version number.
+     *
+     * @return JDBC driver minor version number
+     */
+    int getDriverMinorVersion();
+
+    /**
+     * Retrieves whether this database stores tables in a local file.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean usesLocalFiles() throws SQLException;
+
+    /**
+     * Retrieves whether this database uses a file for each table.
+     *
+     * @return <code>true</code> if this database uses a local file for each table;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean usesLocalFilePerTable() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case unquoted SQL identifiers as
+     * case sensitive and as a result stores them in mixed case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsMixedCaseIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case unquoted SQL identifiers as
+     * case insensitive and stores them in upper case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean storesUpperCaseIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case unquoted SQL identifiers as
+     * case insensitive and stores them in lower case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean storesLowerCaseIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case unquoted SQL identifiers as
+     * case insensitive and stores them in mixed case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean storesMixedCaseIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case quoted SQL identifiers as
+     * case sensitive and as a result stores them in mixed case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsMixedCaseQuotedIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case quoted SQL identifiers as
+     * case insensitive and stores them in upper case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean storesUpperCaseQuotedIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case quoted SQL identifiers as
+     * case insensitive and stores them in lower case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean storesLowerCaseQuotedIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves whether this database treats mixed case quoted SQL identifiers as
+     * case insensitive and stores them in mixed case.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean storesMixedCaseQuotedIdentifiers() throws SQLException;
+
+    /**
+     * Retrieves the string used to quote SQL identifiers.
+     * This method returns a space " " if identifier quoting is not supported.
+     *
+     * @return the quoting string or a space if quoting is not supported
+     * @exception SQLException if a database access error occurs
+     */
+    String getIdentifierQuoteString() throws SQLException;
+
+    /**
+     * Retrieves a comma-separated list of all of this database's SQL keywords
+     * that are NOT also SQL:2003 keywords.
+     *
+     * @return the list of this database's keywords that are not also
+     *         SQL:2003 keywords
+     * @exception SQLException if a database access error occurs
+     */
+    String getSQLKeywords() throws SQLException;
+
+    /**
+     * Retrieves a comma-separated list of math functions available with
+     * this database.  These are the Open /Open CLI math function names used in
+     * the JDBC function escape clause.
+     *
+     * @return the list of math functions supported by this database
+     * @exception SQLException if a database access error occurs
+     */
+    String getNumericFunctions() throws SQLException;
+
+    /**
+     * Retrieves a comma-separated list of string functions available with
+     * this database.  These are the  Open Group CLI string function names used
+     * in the JDBC function escape clause.
+     *
+     * @return the list of string functions supported by this database
+     * @exception SQLException if a database access error occurs
+     */
+    String getStringFunctions() throws SQLException;
+
+    /**
+     * Retrieves a comma-separated list of system functions available with
+     * this database.  These are the  Open Group CLI system function names used
+     * in the JDBC function escape clause.
+     *
+     * @return a list of system functions supported by this database
+     * @exception SQLException if a database access error occurs
+     */
+    String getSystemFunctions() throws SQLException;
+
+    /**
+     * Retrieves a comma-separated list of the time and date functions available
+     * with this database.
+     *
+     * @return the list of time and date functions supported by this database
+     * @exception SQLException if a database access error occurs
+     */
+    String getTimeDateFunctions() throws SQLException;
+
+    /**
+     * Retrieves the string that can be used to escape wildcard characters.
+     * This is the string that can be used to escape '_' or '%' in
+     * the catalog search parameters that are a pattern (and therefore use one
+     * of the wildcard characters).
+     *
+     * <P>The '_' character represents any single character;
+     * the '%' character represents any sequence of zero or
+     * more characters.
+     *
+     * @return the string used to escape wildcard characters
+     * @exception SQLException if a database access error occurs
+     */
+    String getSearchStringEscape() throws SQLException;
+
+    /**
+     * Retrieves all the "extra" characters that can be used in unquoted
+     * identifier names (those beyond a-z, A-Z, 0-9 and _).
+     *
+     * @return the string containing the extra characters
+     * @exception SQLException if a database access error occurs
+     */
+    String getExtraNameCharacters() throws SQLException;
+
+    //--------------------------------------------------------------------
+    // Functions describing which features are supported.
+
+    /**
+     * Retrieves whether this database supports <code>ALTER TABLE</code>
+     * with add column.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsAlterTableWithAddColumn() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports <code>ALTER TABLE</code>
+     * with drop column.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsAlterTableWithDropColumn() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports column aliasing.
+     *
+     * <P>If so, the SQL AS clause can be used to provide names for
+     * computed columns or to provide alias names for columns as
+     * required.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsColumnAliasing() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports concatenations between
+     * <code>NULL</code> and non-<code>NULL</code> values being
+     * <code>NULL</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean nullPlusNonNullIsNull() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the JDBC scalar function
+     * <code>CONVERT</code> for the conversion of one JDBC type to another.
+     * The JDBC types are the generic SQL data types defined
+     * in <code>java.sql.Types</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsConvert() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the JDBC scalar function
+     * <code>CONVERT</code> for conversions between the JDBC types <i>fromType</i>
+     * and <i>toType</i>.  The JDBC types are the generic SQL data types defined
+     * in <code>java.sql.Types</code>.
+     *
+     * @param fromType the type to convert from; one of the type codes from
+     *        the class <code>java.sql.Types</code>
+     * @param toType the type to convert to; one of the type codes from
+     *        the class <code>java.sql.Types</code>
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @see Types
+     */
+    boolean supportsConvert(int fromType, int toType) throws SQLException;
+
+    /**
+     * Retrieves whether this database supports table correlation names.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsTableCorrelationNames() throws SQLException;
+
+    /**
+     * Retrieves whether, when table correlation names are supported, they
+     * are restricted to being different from the names of the tables.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsDifferentTableCorrelationNames() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports expressions in
+     * <code>ORDER BY</code> lists.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsExpressionsInOrderBy() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports using a column that is
+     * not in the <code>SELECT</code> statement in an
+     * <code>ORDER BY</code> clause.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsOrderByUnrelated() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports some form of
+     * <code>GROUP BY</code> clause.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsGroupBy() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports using a column that is
+     * not in the <code>SELECT</code> statement in a
+     * <code>GROUP BY</code> clause.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsGroupByUnrelated() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports using columns not included in
+     * the <code>SELECT</code> statement in a <code>GROUP BY</code> clause
+     * provided that all of the columns in the <code>SELECT</code> statement
+     * are included in the <code>GROUP BY</code> clause.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsGroupByBeyondSelect() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports specifying a
+     * <code>LIKE</code> escape clause.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsLikeEscapeClause() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports getting multiple
+     * <code>ResultSet</code> objects from a single call to the
+     * method <code>execute</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsMultipleResultSets() throws SQLException;
+
+    /**
+     * Retrieves whether this database allows having multiple
+     * transactions open at once (on different connections).
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsMultipleTransactions() throws SQLException;
+
+    /**
+     * Retrieves whether columns in this database may be defined as non-nullable.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsNonNullableColumns() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the ODBC Minimum SQL grammar.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsMinimumSQLGrammar() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the ODBC Core SQL grammar.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCoreSQLGrammar() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the ODBC Extended SQL grammar.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsExtendedSQLGrammar() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the ANSI92 entry level SQL
+     * grammar.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsANSI92EntryLevelSQL() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the ANSI92 intermediate SQL grammar supported.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsANSI92IntermediateSQL() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the ANSI92 full SQL grammar supported.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsANSI92FullSQL() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the SQL Integrity
+     * Enhancement Facility.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsIntegrityEnhancementFacility() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports some form of outer join.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsOuterJoins() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports full nested outer joins.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsFullOuterJoins() throws SQLException;
+
+    /**
+     * Retrieves whether this database provides limited support for outer
+     * joins.  (This will be <code>true</code> if the method
+     * <code>supportsFullOuterJoins</code> returns <code>true</code>).
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsLimitedOuterJoins() throws SQLException;
+
+    /**
+     * Retrieves the database vendor's preferred term for "schema".
+     *
+     * @return the vendor term for "schema"
+     * @exception SQLException if a database access error occurs
+     */
+    String getSchemaTerm() throws SQLException;
+
+    /**
+     * Retrieves the database vendor's preferred term for "procedure".
+     *
+     * @return the vendor term for "procedure"
+     * @exception SQLException if a database access error occurs
+     */
+    String getProcedureTerm() throws SQLException;
+
+    /**
+     * Retrieves the database vendor's preferred term for "catalog".
+     *
+     * @return the vendor term for "catalog"
+     * @exception SQLException if a database access error occurs
+     */
+    String getCatalogTerm() throws SQLException;
+
+    /**
+     * Retrieves whether a catalog appears at the start of a fully qualified
+     * table name.  If not, the catalog appears at the end.
+     *
+     * @return <code>true</code> if the catalog name appears at the beginning
+     *         of a fully qualified table name; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isCatalogAtStart() throws SQLException;
+
+    /**
+     * Retrieves the <code>String</code> that this database uses as the
+     * separator between a catalog and table name.
+     *
+     * @return the separator string
+     * @exception SQLException if a database access error occurs
+     */
+    String getCatalogSeparator() throws SQLException;
+
+    /**
+     * Retrieves whether a schema name can be used in a data manipulation statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSchemasInDataManipulation() throws SQLException;
+
+    /**
+     * Retrieves whether a schema name can be used in a procedure call statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSchemasInProcedureCalls() throws SQLException;
+
+    /**
+     * Retrieves whether a schema name can be used in a table definition statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSchemasInTableDefinitions() throws SQLException;
+
+    /**
+     * Retrieves whether a schema name can be used in an index definition statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSchemasInIndexDefinitions() throws SQLException;
+
+    /**
+     * Retrieves whether a schema name can be used in a privilege definition statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSchemasInPrivilegeDefinitions() throws SQLException;
+
+    /**
+     * Retrieves whether a catalog name can be used in a data manipulation statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCatalogsInDataManipulation() throws SQLException;
+
+    /**
+     * Retrieves whether a catalog name can be used in a procedure call statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCatalogsInProcedureCalls() throws SQLException;
+
+    /**
+     * Retrieves whether a catalog name can be used in a table definition statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCatalogsInTableDefinitions() throws SQLException;
+
+    /**
+     * Retrieves whether a catalog name can be used in an index definition statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCatalogsInIndexDefinitions() throws SQLException;
+
+    /**
+     * Retrieves whether a catalog name can be used in a privilege definition statement.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException;
+
+
+    /**
+     * Retrieves whether this database supports positioned <code>DELETE</code>
+     * statements.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsPositionedDelete() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports positioned <code>UPDATE</code>
+     * statements.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsPositionedUpdate() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports <code>SELECT FOR UPDATE</code>
+     * statements.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSelectForUpdate() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports stored procedure calls
+     * that use the stored procedure escape syntax.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsStoredProcedures() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports subqueries in comparison
+     * expressions.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSubqueriesInComparisons() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports subqueries in
+     * <code>EXISTS</code> expressions.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSubqueriesInExists() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports subqueries in
+     * <code>IN</code> expressions.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSubqueriesInIns() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports subqueries in quantified
+     * expressions.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsSubqueriesInQuantifieds() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports correlated subqueries.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsCorrelatedSubqueries() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports SQL <code>UNION</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsUnion() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports SQL <code>UNION ALL</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsUnionAll() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports keeping cursors open
+     * across commits.
+     *
+     * @return <code>true</code> if cursors always remain open;
+     *       <code>false</code> if they might not remain open
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsOpenCursorsAcrossCommit() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports keeping cursors open
+     * across rollbacks.
+     *
+     * @return <code>true</code> if cursors always remain open;
+     *       <code>false</code> if they might not remain open
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsOpenCursorsAcrossRollback() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports keeping statements open
+     * across commits.
+     *
+     * @return <code>true</code> if statements always remain open;
+     *       <code>false</code> if they might not remain open
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsOpenStatementsAcrossCommit() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports keeping statements open
+     * across rollbacks.
+     *
+     * @return <code>true</code> if statements always remain open;
+     *       <code>false</code> if they might not remain open
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsOpenStatementsAcrossRollback() throws SQLException;
+
+
+
+    //----------------------------------------------------------------------
+    // The following group of methods exposes various limitations
+    // based on the target database with the current driver.
+    // Unless otherwise specified, a result of zero means there is no
+    // limit, or the limit is not known.
+
+    /**
+     * Retrieves the maximum number of hex characters this database allows in an
+     * inline binary literal.
+     *
+     * @return max the maximum length (in hex characters) for a binary literal;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxBinaryLiteralLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters this database allows
+     * for a character literal.
+     *
+     * @return the maximum number of characters allowed for a character literal;
+     *      a result of zero means that there is no limit or the limit is
+     *      not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxCharLiteralLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters this database allows
+     * for a column name.
+     *
+     * @return the maximum number of characters allowed for a column name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxColumnNameLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of columns this database allows in a
+     * <code>GROUP BY</code> clause.
+     *
+     * @return the maximum number of columns allowed;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxColumnsInGroupBy() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of columns this database allows in an index.
+     *
+     * @return the maximum number of columns allowed;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxColumnsInIndex() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of columns this database allows in an
+     * <code>ORDER BY</code> clause.
+     *
+     * @return the maximum number of columns allowed;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxColumnsInOrderBy() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of columns this database allows in a
+     * <code>SELECT</code> list.
+     *
+     * @return the maximum number of columns allowed;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxColumnsInSelect() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of columns this database allows in a table.
+     *
+     * @return the maximum number of columns allowed;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxColumnsInTable() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of concurrent connections to this
+     * database that are possible.
+     *
+     * @return the maximum number of active connections possible at one time;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxConnections() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters that this database allows in a
+     * cursor name.
+     *
+     * @return the maximum number of characters allowed in a cursor name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxCursorNameLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of bytes this database allows for an
+     * index, including all of the parts of the index.
+     *
+     * @return the maximum number of bytes allowed; this limit includes the
+     *      composite of all the constituent parts of the index;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxIndexLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters that this database allows in a
+     * schema name.
+     *
+     * @return the maximum number of characters allowed in a schema name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxSchemaNameLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters that this database allows in a
+     * procedure name.
+     *
+     * @return the maximum number of characters allowed in a procedure name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxProcedureNameLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters that this database allows in a
+     * catalog name.
+     *
+     * @return the maximum number of characters allowed in a catalog name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxCatalogNameLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of bytes this database allows in
+     * a single row.
+     *
+     * @return the maximum number of bytes allowed for a row; a result of
+     *         zero means that there is no limit or the limit is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxRowSize() throws SQLException;
+
+    /**
+     * Retrieves whether the return value for the method
+     * <code>getMaxRowSize</code> includes the SQL data types
+     * <code>LONGVARCHAR</code> and <code>LONGVARBINARY</code>.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean doesMaxRowSizeIncludeBlobs() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters this database allows in
+     * an SQL statement.
+     *
+     * @return the maximum number of characters allowed for an SQL statement;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxStatementLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of active statements to this database
+     * that can be open at the same time.
+     *
+     * @return the maximum number of statements that can be open at one time;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxStatements() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters this database allows in
+     * a table name.
+     *
+     * @return the maximum number of characters allowed for a table name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxTableNameLength() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of tables this database allows in a
+     * <code>SELECT</code> statement.
+     *
+     * @return the maximum number of tables allowed in a <code>SELECT</code>
+     *         statement; a result of zero means that there is no limit or
+     *         the limit is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxTablesInSelect() throws SQLException;
+
+    /**
+     * Retrieves the maximum number of characters this database allows in
+     * a user name.
+     *
+     * @return the maximum number of characters allowed for a user name;
+     *      a result of zero means that there is no limit or the limit
+     *      is not known
+     * @exception SQLException if a database access error occurs
+     */
+    int getMaxUserNameLength() throws SQLException;
+
+    //----------------------------------------------------------------------
+
+    /**
+     * Retrieves this database's default transaction isolation level.  The
+     * possible values are defined in <code>java.sql.Connection</code>.
+     *
+     * @return the default isolation level
+     * @exception SQLException if a database access error occurs
+     * @see Connection
+     */
+    int getDefaultTransactionIsolation() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports transactions. If not, invoking the
+     * method <code>commit</code> is a noop, and the isolation level is
+     * <code>TRANSACTION_NONE</code>.
+     *
+     * @return <code>true</code> if transactions are supported;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsTransactions() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the given transaction isolation level.
+     *
+     * @param level one of the transaction isolation levels defined in
+     *         <code>java.sql.Connection</code>
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @see Connection
+     */
+    boolean supportsTransactionIsolationLevel(int level)
+        throws SQLException;
+
+    /**
+     * Retrieves whether this database supports both data definition and
+     * data manipulation statements within a transaction.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsDataDefinitionAndDataManipulationTransactions()
+        throws SQLException;
+    /**
+     * Retrieves whether this database supports only data manipulation
+     * statements within a transaction.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean supportsDataManipulationTransactionsOnly()
+        throws SQLException;
+
+    /**
+     * Retrieves whether a data definition statement within a transaction forces
+     * the transaction to commit.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean dataDefinitionCausesTransactionCommit()
+        throws SQLException;
+
+    /**
+     * Retrieves whether this database ignores a data definition statement
+     * within a transaction.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean dataDefinitionIgnoredInTransactions()
+        throws SQLException;
+
+    /**
+     * Retrieves a description of the stored procedures available in the given
+     * catalog.
+     * <P>
+     * Only procedure descriptions matching the schema and
+     * procedure name criteria are returned.  They are ordered by
+     * <code>PROCEDURE_CAT</code>, <code>PROCEDURE_SCHEM</code>,
+     * <code>PROCEDURE_NAME</code> and <code>SPECIFIC_ NAME</code>.
+     *
+     * <P>Each procedure description has the the following columns:
+     *  <OL>
+     *  <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be <code>null</code>)
+     *  <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be <code>null</code>)
+     *  <LI><B>PROCEDURE_NAME</B> String => procedure name
+     *  <LI> reserved for future use
+     *  <LI> reserved for future use
+     *  <LI> reserved for future use
+     *  <LI><B>REMARKS</B> String => explanatory comment on the procedure
+     *  <LI><B>PROCEDURE_TYPE</B> short => kind of procedure:
+     *      <UL>
+     *      <LI> procedureResultUnknown - Cannot determine if  a return value
+     *       will be returned
+     *      <LI> procedureNoResult - Does not return a return value
+     *      <LI> procedureReturnsResult - Returns a return value
+     *      </UL>
+     *  <LI><B>SPECIFIC_NAME</B> String  => The name which uniquely identifies this
+     * procedure within its schema.
+     *  </OL>
+     * <p>
+     * A user may not have permissions to execute any of the procedures that are
+     * returned by <code>getProcedures</code>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param procedureNamePattern a procedure name pattern; must match the
+     *        procedure name as it is stored in the database
+     * @return <code>ResultSet</code> - each row is a procedure description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     */
+    ResultSet getProcedures(String catalog, String schemaPattern,
+                            String procedureNamePattern) throws SQLException;
+
+    /**
+     * Indicates that it is not known whether the procedure returns
+     * a result.
+     * <P>
+     * A possible value for column <code>PROCEDURE_TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getProcedures</code>.
+     */
+    int procedureResultUnknown  = 0;
+
+    /**
+     * Indicates that the procedure does not return a result.
+     * <P>
+     * A possible value for column <code>PROCEDURE_TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getProcedures</code>.
+     */
+    int procedureNoResult               = 1;
+
+    /**
+     * Indicates that the procedure returns a result.
+     * <P>
+     * A possible value for column <code>PROCEDURE_TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getProcedures</code>.
+     */
+    int procedureReturnsResult  = 2;
+
+    /**
+     * Retrieves a description of the given catalog's stored procedure parameter
+     * and result columns.
+     *
+     * <P>Only descriptions matching the schema, procedure and
+     * parameter name criteria are returned.  They are ordered by
+     * PROCEDURE_CAT, PROCEDURE_SCHEM, PROCEDURE_NAME and SPECIFIC_NAME. Within this, the return value,
+     * if any, is first. Next are the parameter descriptions in call
+     * order. The column descriptions follow in column number order.
+     *
+     * <P>Each row in the <code>ResultSet</code> is a parameter description or
+     * column description with the following fields:
+     *  <OL>
+     *  <LI><B>PROCEDURE_CAT</B> String => procedure catalog (may be <code>null</code>)
+     *  <LI><B>PROCEDURE_SCHEM</B> String => procedure schema (may be <code>null</code>)
+     *  <LI><B>PROCEDURE_NAME</B> String => procedure name
+     *  <LI><B>COLUMN_NAME</B> String => column/parameter name
+     *  <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter:
+     *      <UL>
+     *      <LI> procedureColumnUnknown - nobody knows
+     *      <LI> procedureColumnIn - IN parameter
+     *      <LI> procedureColumnInOut - INOUT parameter
+     *      <LI> procedureColumnOut - OUT parameter
+     *      <LI> procedureColumnReturn - procedure return value
+     *      <LI> procedureColumnResult - result column in <code>ResultSet</code>
+     *      </UL>
+     *  <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
+     *  <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the
+     *  type name is fully qualified
+     *  <LI><B>PRECISION</B> int => precision
+     *  <LI><B>LENGTH</B> int => length in bytes of data
+     *  <LI><B>SCALE</B> short => scale -  null is returned for data types where
+     * SCALE is not applicable.
+     *  <LI><B>RADIX</B> short => radix
+     *  <LI><B>NULLABLE</B> short => can it contain NULL.
+     *      <UL>
+     *      <LI> procedureNoNulls - does not allow NULL values
+     *      <LI> procedureNullable - allows NULL values
+     *      <LI> procedureNullableUnknown - nullability unknown
+     *      </UL>
+     *  <LI><B>REMARKS</B> String => comment describing parameter/column
+     *  <LI><B>COLUMN_DEF</B> String => default value for the column, which should be interpreted as a string when the value is enclosed in single quotes (may be <code>null</code>)
+     *      <UL>
+     *      <LI> The string NULL (not enclosed in quotes) - if NULL was specified as the default value
+     *      <LI> TRUNCATE (not enclosed in quotes)        - if the specified default value cannot be represented without truncation
+     *      <LI> NULL                                     - if a default value was not specified
+     *      </UL>
+     *  <LI><B>SQL_DATA_TYPE</B> int  => reserved for future use
+     *  <LI><B>SQL_DATETIME_SUB</B> int  => reserved for future use
+     *  <LI><B>CHAR_OCTET_LENGTH</B> int  => the maximum length of binary and character based columns.  For any other datatype the returned value is a
+     * NULL
+     *  <LI><B>ORDINAL_POSITION</B> int  => the ordinal position, starting from 1, for the input and output parameters for a procedure. A value of 0
+     *is returned if this row describes the procedure's return value.  For result set columns, it is the
+     *ordinal position of the column in the result set starting from 1.  If there are
+     *multiple result sets, the column ordinal positions are implementation
+     * defined.
+     *  <LI><B>IS_NULLABLE</B> String  => ISO rules are used to determine the nullability for a column.
+     *       <UL>
+     *       <LI> YES           --- if the column can include NULLs
+     *       <LI> NO            --- if the column cannot include NULLs
+     *       <LI> empty string  --- if the nullability for the
+     * column is unknown
+     *       </UL>
+     *  <LI><B>SPECIFIC_NAME</B> String  => the name which uniquely identifies this procedure within its schema.
+     *  </OL>
+     *
+     * <P><B>Note:</B> Some databases may not return the column
+     * descriptions for a procedure.
+     *
+     * <p>The PRECISION column represents the specified column size for the given column.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. Null is returned for data types where the
+     * column size is not applicable.
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param procedureNamePattern a procedure name pattern; must match the
+     *        procedure name as it is stored in the database
+     * @param columnNamePattern a column name pattern; must match the column name
+     *        as it is stored in the database
+     * @return <code>ResultSet</code> - each row describes a stored procedure parameter or
+     *      column
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     */
+    ResultSet getProcedureColumns(String catalog,
+                                  String schemaPattern,
+                                  String procedureNamePattern,
+                                  String columnNamePattern) throws SQLException;
+
+    /**
+     * Indicates that type of the column is unknown.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureColumnUnknown = 0;
+
+    /**
+     * Indicates that the column stores IN parameters.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureColumnIn = 1;
+
+    /**
+     * Indicates that the column stores INOUT parameters.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureColumnInOut = 2;
+
+    /**
+     * Indicates that the column stores OUT parameters.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+    * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureColumnOut = 4;
+    /**
+     * Indicates that the column stores return values.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureColumnReturn = 5;
+
+    /**
+     * Indicates that the column stores results.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureColumnResult = 3;
+
+    /**
+     * Indicates that <code>NULL</code> values are not allowed.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureNoNulls = 0;
+
+    /**
+     * Indicates that <code>NULL</code> values are allowed.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureNullable = 1;
+
+    /**
+     * Indicates that whether <code>NULL</code> values are allowed
+     * is unknown.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getProcedureColumns</code>.
+     */
+    int procedureNullableUnknown = 2;
+
+
+    /**
+     * Retrieves a description of the tables available in the given catalog.
+     * Only table descriptions matching the catalog, schema, table
+     * name and type criteria are returned.  They are ordered by
+     * <code>TABLE_TYPE</code>, <code>TABLE_CAT</code>,
+     * <code>TABLE_SCHEM</code> and <code>TABLE_NAME</code>.
+     * <P>
+     * Each table description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => table name
+     *  <LI><B>TABLE_TYPE</B> String => table type.  Typical types are "TABLE",
+     *                  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
+     *                  "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
+     *  <LI><B>REMARKS</B> String => explanatory comment on the table
+     *  <LI><B>TYPE_CAT</B> String => the types catalog (may be <code>null</code>)
+     *  <LI><B>TYPE_SCHEM</B> String => the types schema (may be <code>null</code>)
+     *  <LI><B>TYPE_NAME</B> String => type name (may be <code>null</code>)
+     *  <LI><B>SELF_REFERENCING_COL_NAME</B> String => name of the designated
+     *                  "identifier" column of a typed table (may be <code>null</code>)
+     *  <LI><B>REF_GENERATION</B> String => specifies how values in
+     *                  SELF_REFERENCING_COL_NAME are created. Values are
+     *                  "SYSTEM", "USER", "DERIVED". (may be <code>null</code>)
+     *  </OL>
+     *
+     * <P><B>Note:</B> Some databases may not return information for
+     * all tables.
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param tableNamePattern a table name pattern; must match the
+     *        table name as it is stored in the database
+     * @param types a list of table types, which must be from the list of table types
+     *         returned from {@link #getTableTypes},to include; <code>null</code> returns
+     * all types
+     * @return <code>ResultSet</code> - each row is a table description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     */
+    ResultSet getTables(String catalog, String schemaPattern,
+                        String tableNamePattern, String types[]) throws SQLException;
+
+    /**
+     * Retrieves the schema names available in this database.  The results
+     * are ordered by <code>TABLE_CATALOG</code> and
+     * <code>TABLE_SCHEM</code>.
+     *
+     * <P>The schema columns are:
+     *  <OL>
+     *  <LI><B>TABLE_SCHEM</B> String => schema name
+     *  <LI><B>TABLE_CATALOG</B> String => catalog name (may be <code>null</code>)
+     *  </OL>
+     *
+     * @return a <code>ResultSet</code> object in which each row is a
+     *         schema description
+     * @exception SQLException if a database access error occurs
+     *
+     */
+    ResultSet getSchemas() throws SQLException;
+
+    /**
+     * Retrieves the catalog names available in this database.  The results
+     * are ordered by catalog name.
+     *
+     * <P>The catalog column is:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => catalog name
+     *  </OL>
+     *
+     * @return a <code>ResultSet</code> object in which each row has a
+     *         single <code>String</code> column that is a catalog name
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getCatalogs() throws SQLException;
+
+    /**
+     * Retrieves the table types available in this database.  The results
+     * are ordered by table type.
+     *
+     * <P>The table type is:
+     *  <OL>
+     *  <LI><B>TABLE_TYPE</B> String => table type.  Typical types are "TABLE",
+     *                  "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
+     *                  "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
+     *  </OL>
+     *
+     * @return a <code>ResultSet</code> object in which each row has a
+     *         single <code>String</code> column that is a table type
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getTableTypes() throws SQLException;
+
+    /**
+     * Retrieves a description of table columns available in
+     * the specified catalog.
+     *
+     * <P>Only column descriptions matching the catalog, schema, table
+     * and column name criteria are returned.  They are ordered by
+     * <code>TABLE_CAT</code>,<code>TABLE_SCHEM</code>,
+     * <code>TABLE_NAME</code>, and <code>ORDINAL_POSITION</code>.
+     *
+     * <P>Each column description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => table name
+     *  <LI><B>COLUMN_NAME</B> String => column name
+     *  <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
+     *  <LI><B>TYPE_NAME</B> String => Data source dependent type name,
+     *  for a UDT the type name is fully qualified
+     *  <LI><B>COLUMN_SIZE</B> int => column size.
+     *  <LI><B>BUFFER_LENGTH</B> is not used.
+     *  <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits. Null is returned for data types where
+     * DECIMAL_DIGITS is not applicable.
+     *  <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
+     *  <LI><B>NULLABLE</B> int => is NULL allowed.
+     *      <UL>
+     *      <LI> columnNoNulls - might not allow <code>NULL</code> values
+     *      <LI> columnNullable - definitely allows <code>NULL</code> values
+     *      <LI> columnNullableUnknown - nullability unknown
+     *      </UL>
+     *  <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
+     *  <LI><B>COLUMN_DEF</B> String => default value for the column, which should be interpreted as a string when the value is enclosed in single quotes (may be <code>null</code>)
+     *  <LI><B>SQL_DATA_TYPE</B> int => unused
+     *  <LI><B>SQL_DATETIME_SUB</B> int => unused
+     *  <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
+     *       maximum number of bytes in the column
+     *  <LI><B>ORDINAL_POSITION</B> int => index of column in table
+     *      (starting at 1)
+     *  <LI><B>IS_NULLABLE</B> String  => ISO rules are used to determine the nullability for a column.
+     *       <UL>
+     *       <LI> YES           --- if the column can include NULLs
+     *       <LI> NO            --- if the column cannot include NULLs
+     *       <LI> empty string  --- if the nullability for the
+     * column is unknown
+     *       </UL>
+     *  <LI><B>SCOPE_CATALOG</B> String => catalog of table that is the scope
+     *      of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
+     *  <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the scope
+     *      of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
+     *  <LI><B>SCOPE_TABLE</B> String => table name that this the scope
+     *      of a reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
+     *  <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
+     *      Ref type, SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
+     *      isn't DISTINCT or user-generated REF)
+     *   <LI><B>IS_AUTOINCREMENT</B> String  => Indicates whether this column is auto incremented
+     *       <UL>
+     *       <LI> YES           --- if the column is auto incremented
+     *       <LI> NO            --- if the column is not auto incremented
+     *       <LI> empty string  --- if it cannot be determined whether the column is auto incremented
+     *       </UL>
+     *   <LI><B>IS_GENERATEDCOLUMN</B> String  => Indicates whether this is a generated column
+     *       <UL>
+     *       <LI> YES           --- if this a generated column
+     *       <LI> NO            --- if this not a generated column
+     *       <LI> empty string  --- if it cannot be determined whether this is a generated column
+     *       </UL>
+     *  </OL>
+     *
+     * <p>The COLUMN_SIZE column specifies the column size for the given column.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. Null is returned for data types where the
+     * column size is not applicable.
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param tableNamePattern a table name pattern; must match the
+     *        table name as it is stored in the database
+     * @param columnNamePattern a column name pattern; must match the column
+     *        name as it is stored in the database
+     * @return <code>ResultSet</code> - each row is a column description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     */
+    ResultSet getColumns(String catalog, String schemaPattern,
+                         String tableNamePattern, String columnNamePattern)
+        throws SQLException;
+
+    /**
+     * Indicates that the column might not allow <code>NULL</code> values.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> returned by the method
+     * <code>getColumns</code>.
+     */
+    int columnNoNulls = 0;
+
+    /**
+     * Indicates that the column definitely allows <code>NULL</code> values.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> returned by the method
+     * <code>getColumns</code>.
+     */
+    int columnNullable = 1;
+
+    /**
+     * Indicates that the nullability of columns is unknown.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> returned by the method
+     * <code>getColumns</code>.
+     */
+    int columnNullableUnknown = 2;
+
+    /**
+     * Retrieves a description of the access rights for a table's columns.
+     *
+     * <P>Only privileges matching the column name criteria are
+     * returned.  They are ordered by COLUMN_NAME and PRIVILEGE.
+     *
+     * <P>Each privilige description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => table name
+     *  <LI><B>COLUMN_NAME</B> String => column name
+     *  <LI><B>GRANTOR</B> String => grantor of access (may be <code>null</code>)
+     *  <LI><B>GRANTEE</B> String => grantee of access
+     *  <LI><B>PRIVILEGE</B> String => name of access (SELECT,
+     *      INSERT, UPDATE, REFRENCES, ...)
+     *  <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
+     *      to grant to others; "NO" if not; <code>null</code> if unknown
+     *  </OL>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name as it is
+     *        stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is
+     *        stored in the database
+     * @param columnNamePattern a column name pattern; must match the column
+     *        name as it is stored in the database
+     * @return <code>ResultSet</code> - each row is a column privilege description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     */
+    ResultSet getColumnPrivileges(String catalog, String schema,
+                                  String table, String columnNamePattern) throws SQLException;
+
+    /**
+     * Retrieves a description of the access rights for each table available
+     * in a catalog. Note that a table privilege applies to one or
+     * more columns in the table. It would be wrong to assume that
+     * this privilege applies to all columns (this may be true for
+     * some systems but is not true for all.)
+     *
+     * <P>Only privileges matching the schema and table name
+     * criteria are returned.  They are ordered by
+     * <code>TABLE_CAT</code>,
+     * <code>TABLE_SCHEM</code>, <code>TABLE_NAME</code>,
+     * and <code>PRIVILEGE</code>.
+     *
+     * <P>Each privilige description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => table name
+     *  <LI><B>GRANTOR</B> String => grantor of access (may be <code>null</code>)
+     *  <LI><B>GRANTEE</B> String => grantee of access
+     *  <LI><B>PRIVILEGE</B> String => name of access (SELECT,
+     *      INSERT, UPDATE, REFRENCES, ...)
+     *  <LI><B>IS_GRANTABLE</B> String => "YES" if grantee is permitted
+     *      to grant to others; "NO" if not; <code>null</code> if unknown
+     *  </OL>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param tableNamePattern a table name pattern; must match the
+     *        table name as it is stored in the database
+     * @return <code>ResultSet</code> - each row is a table privilege description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     */
+    ResultSet getTablePrivileges(String catalog, String schemaPattern,
+                                 String tableNamePattern) throws SQLException;
+
+    /**
+     * Retrieves a description of a table's optimal set of columns that
+     * uniquely identifies a row. They are ordered by SCOPE.
+     *
+     * <P>Each column description has the following columns:
+     *  <OL>
+     *  <LI><B>SCOPE</B> short => actual scope of result
+     *      <UL>
+     *      <LI> bestRowTemporary - very temporary, while using row
+     *      <LI> bestRowTransaction - valid for remainder of current transaction
+     *      <LI> bestRowSession - valid for remainder of current session
+     *      </UL>
+     *  <LI><B>COLUMN_NAME</B> String => column name
+     *  <LI><B>DATA_TYPE</B> int => SQL data type from java.sql.Types
+     *  <LI><B>TYPE_NAME</B> String => Data source dependent type name,
+     *  for a UDT the type name is fully qualified
+     *  <LI><B>COLUMN_SIZE</B> int => precision
+     *  <LI><B>BUFFER_LENGTH</B> int => not used
+     *  <LI><B>DECIMAL_DIGITS</B> short  => scale - Null is returned for data types where
+     * DECIMAL_DIGITS is not applicable.
+     *  <LI><B>PSEUDO_COLUMN</B> short => is this a pseudo column
+     *      like an Oracle ROWID
+     *      <UL>
+     *      <LI> bestRowUnknown - may or may not be pseudo column
+     *      <LI> bestRowNotPseudo - is NOT a pseudo column
+     *      <LI> bestRowPseudo - is a pseudo column
+     *      </UL>
+     *  </OL>
+     *
+     * <p>The COLUMN_SIZE column represents the specified column size for the given column.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. Null is returned for data types where the
+     * column size is not applicable.
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is stored
+     *        in the database
+     * @param scope the scope of interest; use same values as SCOPE
+     * @param nullable include columns that are nullable.
+     * @return <code>ResultSet</code> - each row is a column description
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getBestRowIdentifier(String catalog, String schema,
+                                   String table, int scope, boolean nullable) throws SQLException;
+
+    /**
+     * Indicates that the scope of the best row identifier is
+     * very temporary, lasting only while the
+     * row is being used.
+     * <P>
+     * A possible value for the column
+     * <code>SCOPE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getBestRowIdentifier</code>.
+     */
+    int bestRowTemporary   = 0;
+
+    /**
+     * Indicates that the scope of the best row identifier is
+     * the remainder of the current transaction.
+     * <P>
+     * A possible value for the column
+     * <code>SCOPE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getBestRowIdentifier</code>.
+     */
+    int bestRowTransaction = 1;
+
+    /**
+     * Indicates that the scope of the best row identifier is
+     * the remainder of the current session.
+     * <P>
+     * A possible value for the column
+     * <code>SCOPE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getBestRowIdentifier</code>.
+     */
+    int bestRowSession     = 2;
+
+    /**
+     * Indicates that the best row identifier may or may not be a pseudo column.
+     * <P>
+     * A possible value for the column
+     * <code>PSEUDO_COLUMN</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getBestRowIdentifier</code>.
+     */
+    int bestRowUnknown  = 0;
+
+    /**
+     * Indicates that the best row identifier is NOT a pseudo column.
+     * <P>
+     * A possible value for the column
+     * <code>PSEUDO_COLUMN</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getBestRowIdentifier</code>.
+     */
+    int bestRowNotPseudo        = 1;
+
+    /**
+     * Indicates that the best row identifier is a pseudo column.
+     * <P>
+     * A possible value for the column
+     * <code>PSEUDO_COLUMN</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getBestRowIdentifier</code>.
+     */
+    int bestRowPseudo   = 2;
+
+    /**
+     * Retrieves a description of a table's columns that are automatically
+     * updated when any value in a row is updated.  They are
+     * unordered.
+     *
+     * <P>Each column description has the following columns:
+     *  <OL>
+     *  <LI><B>SCOPE</B> short => is not used
+     *  <LI><B>COLUMN_NAME</B> String => column name
+     *  <LI><B>DATA_TYPE</B> int => SQL data type from <code>java.sql.Types</code>
+     *  <LI><B>TYPE_NAME</B> String => Data source-dependent type name
+     *  <LI><B>COLUMN_SIZE</B> int => precision
+     *  <LI><B>BUFFER_LENGTH</B> int => length of column value in bytes
+     *  <LI><B>DECIMAL_DIGITS</B> short  => scale - Null is returned for data types where
+     * DECIMAL_DIGITS is not applicable.
+     *  <LI><B>PSEUDO_COLUMN</B> short => whether this is pseudo column
+     *      like an Oracle ROWID
+     *      <UL>
+     *      <LI> versionColumnUnknown - may or may not be pseudo column
+     *      <LI> versionColumnNotPseudo - is NOT a pseudo column
+     *      <LI> versionColumnPseudo - is a pseudo column
+     *      </UL>
+     *  </OL>
+     *
+     * <p>The COLUMN_SIZE column represents the specified column size for the given column.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. Null is returned for data types where the
+     * column size is not applicable.
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is stored
+     *        in the database
+     * @return a <code>ResultSet</code> object in which each row is a
+     *         column description
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getVersionColumns(String catalog, String schema,
+                                String table) throws SQLException;
+
+    /**
+     * Indicates that this version column may or may not be a pseudo column.
+     * <P>
+     * A possible value for the column
+     * <code>PSEUDO_COLUMN</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getVersionColumns</code>.
+     */
+    int versionColumnUnknown    = 0;
+
+    /**
+     * Indicates that this version column is NOT a pseudo column.
+     * <P>
+     * A possible value for the column
+     * <code>PSEUDO_COLUMN</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getVersionColumns</code>.
+     */
+    int versionColumnNotPseudo  = 1;
+
+    /**
+     * Indicates that this version column is a pseudo column.
+     * <P>
+     * A possible value for the column
+     * <code>PSEUDO_COLUMN</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getVersionColumns</code>.
+     */
+    int versionColumnPseudo     = 2;
+
+    /**
+     * Retrieves a description of the given table's primary key columns.  They
+     * are ordered by COLUMN_NAME.
+     *
+     * <P>Each primary key column description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => table name
+     *  <LI><B>COLUMN_NAME</B> String => column name
+     *  <LI><B>KEY_SEQ</B> short => sequence number within primary key( a value
+     *  of 1 represents the first column of the primary key, a value of 2 would
+     *  represent the second column within the primary key).
+     *  <LI><B>PK_NAME</B> String => primary key name (may be <code>null</code>)
+     *  </OL>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is stored
+     *        in the database
+     * @return <code>ResultSet</code> - each row is a primary key column description
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getPrimaryKeys(String catalog, String schema,
+                             String table) throws SQLException;
+
+    /**
+     * Retrieves a description of the primary key columns that are
+     * referenced by the given table's foreign key columns (the primary keys
+     * imported by a table).  They are ordered by PKTABLE_CAT,
+     * PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
+     *
+     * <P>Each primary key column description has the following columns:
+     *  <OL>
+     *  <LI><B>PKTABLE_CAT</B> String => primary key table catalog
+     *      being imported (may be <code>null</code>)
+     *  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema
+     *      being imported (may be <code>null</code>)
+     *  <LI><B>PKTABLE_NAME</B> String => primary key table name
+     *      being imported
+     *  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
+     *      being imported
+     *  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be <code>null</code>)
+     *  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be <code>null</code>)
+     *  <LI><B>FKTABLE_NAME</B> String => foreign key table name
+     *  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
+     *  <LI><B>KEY_SEQ</B> short => sequence number within a foreign key( a value
+     *  of 1 represents the first column of the foreign key, a value of 2 would
+     *  represent the second column within the foreign key).
+     *  <LI><B>UPDATE_RULE</B> short => What happens to a
+     *       foreign key when the primary key is updated:
+     *      <UL>
+     *      <LI> importedNoAction - do not allow update of primary
+     *               key if it has been imported
+     *      <LI> importedKeyCascade - change imported key to agree
+     *               with primary key update
+     *      <LI> importedKeySetNull - change imported key to <code>NULL</code>
+     *               if its primary key has been updated
+     *      <LI> importedKeySetDefault - change imported key to default values
+     *               if its primary key has been updated
+     *      <LI> importedKeyRestrict - same as importedKeyNoAction
+     *                                 (for ODBC 2.x compatibility)
+     *      </UL>
+     *  <LI><B>DELETE_RULE</B> short => What happens to
+     *      the foreign key when primary is deleted.
+     *      <UL>
+     *      <LI> importedKeyNoAction - do not allow delete of primary
+     *               key if it has been imported
+     *      <LI> importedKeyCascade - delete rows that import a deleted key
+     *      <LI> importedKeySetNull - change imported key to NULL if
+     *               its primary key has been deleted
+     *      <LI> importedKeyRestrict - same as importedKeyNoAction
+     *                                 (for ODBC 2.x compatibility)
+     *      <LI> importedKeySetDefault - change imported key to default if
+     *               its primary key has been deleted
+     *      </UL>
+     *  <LI><B>FK_NAME</B> String => foreign key name (may be <code>null</code>)
+     *  <LI><B>PK_NAME</B> String => primary key name (may be <code>null</code>)
+     *  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
+     *      constraints be deferred until commit
+     *      <UL>
+     *      <LI> importedKeyInitiallyDeferred - see SQL92 for definition
+     *      <LI> importedKeyInitiallyImmediate - see SQL92 for definition
+     *      <LI> importedKeyNotDeferrable - see SQL92 for definition
+     *      </UL>
+     *  </OL>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is stored
+     *        in the database
+     * @return <code>ResultSet</code> - each row is a primary key column description
+     * @exception SQLException if a database access error occurs
+     * @see #getExportedKeys
+     */
+    ResultSet getImportedKeys(String catalog, String schema,
+                              String table) throws SQLException;
+
+    /**
+     * For the column <code>UPDATE_RULE</code>,
+     * indicates that
+     * when the primary key is updated, the foreign key (imported key)
+     * is changed to agree with it.
+     * For the column <code>DELETE_RULE</code>,
+     * it indicates that
+     * when the primary key is deleted, rows that imported that key
+     * are deleted.
+     * <P>
+     * A possible value for the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code> in the
+     * <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeyCascade      = 0;
+
+    /**
+     * For the column <code>UPDATE_RULE</code>, indicates that
+     * a primary key may not be updated if it has been imported by
+     * another table as a foreign key.
+     * For the column <code>DELETE_RULE</code>, indicates that
+     * a primary key may not be deleted if it has been imported by
+     * another table as a foreign key.
+     * <P>
+     * A possible value for the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code> in the
+     * <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeyRestrict = 1;
+
+    /**
+     * For the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code>, indicates that
+     * when the primary key is updated or deleted, the foreign key (imported key)
+     * is changed to <code>NULL</code>.
+     * <P>
+     * A possible value for the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code> in the
+     * <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeySetNull  = 2;
+
+    /**
+     * For the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code>, indicates that
+     * if the primary key has been imported, it cannot be updated or deleted.
+     * <P>
+     * A possible value for the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code> in the
+     * <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeyNoAction = 3;
+
+    /**
+     * For the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code>, indicates that
+     * if the primary key is updated or deleted, the foreign key (imported key)
+     * is set to the default value.
+     * <P>
+     * A possible value for the columns <code>UPDATE_RULE</code>
+     * and <code>DELETE_RULE</code> in the
+     * <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeySetDefault  = 4;
+
+    /**
+     * Indicates deferrability.  See SQL-92 for a definition.
+     * <P>
+     * A possible value for the column <code>DEFERRABILITY</code>
+     * in the <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeyInitiallyDeferred  = 5;
+
+    /**
+     * Indicates deferrability.  See SQL-92 for a definition.
+     * <P>
+     * A possible value for the column <code>DEFERRABILITY</code>
+     * in the <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeyInitiallyImmediate  = 6;
+
+    /**
+     * Indicates deferrability.  See SQL-92 for a definition.
+     * <P>
+     * A possible value for the column <code>DEFERRABILITY</code>
+     * in the <code>ResultSet</code> objects returned by the methods
+     * <code>getImportedKeys</code>,  <code>getExportedKeys</code>,
+     * and <code>getCrossReference</code>.
+     */
+    int importedKeyNotDeferrable  = 7;
+
+    /**
+     * Retrieves a description of the foreign key columns that reference the
+     * given table's primary key columns (the foreign keys exported by a
+     * table).  They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
+     * FKTABLE_NAME, and KEY_SEQ.
+     *
+     * <P>Each foreign key column description has the following columns:
+     *  <OL>
+     *  <LI><B>PKTABLE_CAT</B> String => primary key table catalog (may be <code>null</code>)
+     *  <LI><B>PKTABLE_SCHEM</B> String => primary key table schema (may be <code>null</code>)
+     *  <LI><B>PKTABLE_NAME</B> String => primary key table name
+     *  <LI><B>PKCOLUMN_NAME</B> String => primary key column name
+     *  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be <code>null</code>)
+     *      being exported (may be <code>null</code>)
+     *  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be <code>null</code>)
+     *      being exported (may be <code>null</code>)
+     *  <LI><B>FKTABLE_NAME</B> String => foreign key table name
+     *      being exported
+     *  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
+     *      being exported
+     *  <LI><B>KEY_SEQ</B> short => sequence number within foreign key( a value
+     *  of 1 represents the first column of the foreign key, a value of 2 would
+     *  represent the second column within the foreign key).
+     *  <LI><B>UPDATE_RULE</B> short => What happens to
+     *       foreign key when primary is updated:
+     *      <UL>
+     *      <LI> importedNoAction - do not allow update of primary
+     *               key if it has been imported
+     *      <LI> importedKeyCascade - change imported key to agree
+     *               with primary key update
+     *      <LI> importedKeySetNull - change imported key to <code>NULL</code> if
+     *               its primary key has been updated
+     *      <LI> importedKeySetDefault - change imported key to default values
+     *               if its primary key has been updated
+     *      <LI> importedKeyRestrict - same as importedKeyNoAction
+     *                                 (for ODBC 2.x compatibility)
+     *      </UL>
+     *  <LI><B>DELETE_RULE</B> short => What happens to
+     *      the foreign key when primary is deleted.
+     *      <UL>
+     *      <LI> importedKeyNoAction - do not allow delete of primary
+     *               key if it has been imported
+     *      <LI> importedKeyCascade - delete rows that import a deleted key
+     *      <LI> importedKeySetNull - change imported key to <code>NULL</code> if
+     *               its primary key has been deleted
+     *      <LI> importedKeyRestrict - same as importedKeyNoAction
+     *                                 (for ODBC 2.x compatibility)
+     *      <LI> importedKeySetDefault - change imported key to default if
+     *               its primary key has been deleted
+     *      </UL>
+     *  <LI><B>FK_NAME</B> String => foreign key name (may be <code>null</code>)
+     *  <LI><B>PK_NAME</B> String => primary key name (may be <code>null</code>)
+     *  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
+     *      constraints be deferred until commit
+     *      <UL>
+     *      <LI> importedKeyInitiallyDeferred - see SQL92 for definition
+     *      <LI> importedKeyInitiallyImmediate - see SQL92 for definition
+     *      <LI> importedKeyNotDeferrable - see SQL92 for definition
+     *      </UL>
+     *  </OL>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in this database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is stored
+     *        in this database
+     * @return a <code>ResultSet</code> object in which each row is a
+     *         foreign key column description
+     * @exception SQLException if a database access error occurs
+     * @see #getImportedKeys
+     */
+    ResultSet getExportedKeys(String catalog, String schema,
+                              String table) throws SQLException;
+
+    /**
+     * Retrieves a description of the foreign key columns in the given foreign key
+     * table that reference the primary key or the columns representing a unique constraint of the  parent table (could be the same or a different table).
+     * The number of columns returned from the parent table must match the number of
+     * columns that make up the foreign key.  They
+     * are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and
+     * KEY_SEQ.
+     *
+     * <P>Each foreign key column description has the following columns:
+     *  <OL>
+     *  <LI><B>PKTABLE_CAT</B> String => parent key table catalog (may be <code>null</code>)
+     *  <LI><B>PKTABLE_SCHEM</B> String => parent key table schema (may be <code>null</code>)
+     *  <LI><B>PKTABLE_NAME</B> String => parent key table name
+     *  <LI><B>PKCOLUMN_NAME</B> String => parent key column name
+     *  <LI><B>FKTABLE_CAT</B> String => foreign key table catalog (may be <code>null</code>)
+     *      being exported (may be <code>null</code>)
+     *  <LI><B>FKTABLE_SCHEM</B> String => foreign key table schema (may be <code>null</code>)
+     *      being exported (may be <code>null</code>)
+     *  <LI><B>FKTABLE_NAME</B> String => foreign key table name
+     *      being exported
+     *  <LI><B>FKCOLUMN_NAME</B> String => foreign key column name
+     *      being exported
+     *  <LI><B>KEY_SEQ</B> short => sequence number within foreign key( a value
+     *  of 1 represents the first column of the foreign key, a value of 2 would
+     *  represent the second column within the foreign key).
+     *  <LI><B>UPDATE_RULE</B> short => What happens to
+     *       foreign key when parent key is updated:
+     *      <UL>
+     *      <LI> importedNoAction - do not allow update of parent
+     *               key if it has been imported
+     *      <LI> importedKeyCascade - change imported key to agree
+     *               with parent key update
+     *      <LI> importedKeySetNull - change imported key to <code>NULL</code> if
+     *               its parent key has been updated
+     *      <LI> importedKeySetDefault - change imported key to default values
+     *               if its parent key has been updated
+     *      <LI> importedKeyRestrict - same as importedKeyNoAction
+     *                                 (for ODBC 2.x compatibility)
+     *      </UL>
+     *  <LI><B>DELETE_RULE</B> short => What happens to
+     *      the foreign key when parent key is deleted.
+     *      <UL>
+     *      <LI> importedKeyNoAction - do not allow delete of parent
+     *               key if it has been imported
+     *      <LI> importedKeyCascade - delete rows that import a deleted key
+     *      <LI> importedKeySetNull - change imported key to <code>NULL</code> if
+     *               its primary key has been deleted
+     *      <LI> importedKeyRestrict - same as importedKeyNoAction
+     *                                 (for ODBC 2.x compatibility)
+     *      <LI> importedKeySetDefault - change imported key to default if
+     *               its parent key has been deleted
+     *      </UL>
+     *  <LI><B>FK_NAME</B> String => foreign key name (may be <code>null</code>)
+     *  <LI><B>PK_NAME</B> String => parent key name (may be <code>null</code>)
+     *  <LI><B>DEFERRABILITY</B> short => can the evaluation of foreign key
+     *      constraints be deferred until commit
+     *      <UL>
+     *      <LI> importedKeyInitiallyDeferred - see SQL92 for definition
+     *      <LI> importedKeyInitiallyImmediate - see SQL92 for definition
+     *      <LI> importedKeyNotDeferrable - see SQL92 for definition
+     *      </UL>
+     *  </OL>
+     *
+     * @param parentCatalog a catalog name; must match the catalog name
+     * as it is stored in the database; "" retrieves those without a
+     * catalog; <code>null</code> means drop catalog name from the selection criteria
+     * @param parentSchema a schema name; must match the schema name as
+     * it is stored in the database; "" retrieves those without a schema;
+     * <code>null</code> means drop schema name from the selection criteria
+     * @param parentTable the name of the table that exports the key; must match
+     * the table name as it is stored in the database
+     * @param foreignCatalog a catalog name; must match the catalog name as
+     * it is stored in the database; "" retrieves those without a
+     * catalog; <code>null</code> means drop catalog name from the selection criteria
+     * @param foreignSchema a schema name; must match the schema name as it
+     * is stored in the database; "" retrieves those without a schema;
+     * <code>null</code> means drop schema name from the selection criteria
+     * @param foreignTable the name of the table that imports the key; must match
+     * the table name as it is stored in the database
+     * @return <code>ResultSet</code> - each row is a foreign key column description
+     * @exception SQLException if a database access error occurs
+     * @see #getImportedKeys
+     */
+    ResultSet getCrossReference(
+                                String parentCatalog, String parentSchema, String parentTable,
+                                String foreignCatalog, String foreignSchema, String foreignTable
+                                ) throws SQLException;
+
+    /**
+     * Retrieves a description of all the data types supported by
+     * this database. They are ordered by DATA_TYPE and then by how
+     * closely the data type maps to the corresponding JDBC SQL type.
+     *
+     * <P>If the database supports SQL distinct types, then getTypeInfo() will return
+     * a single row with a TYPE_NAME of DISTINCT and a DATA_TYPE of Types.DISTINCT.
+     * If the database supports SQL structured types, then getTypeInfo() will return
+     * a single row with a TYPE_NAME of STRUCT and a DATA_TYPE of Types.STRUCT.
+     *
+     * <P>If SQL distinct or structured types are supported, then information on the
+     * individual types may be obtained from the getUDTs() method.
+     *
+
+     *
+     * <P>Each type description has the following columns:
+     *  <OL>
+     *  <LI><B>TYPE_NAME</B> String => Type name
+     *  <LI><B>DATA_TYPE</B> int => SQL data type from java.sql.Types
+     *  <LI><B>PRECISION</B> int => maximum precision
+     *  <LI><B>LITERAL_PREFIX</B> String => prefix used to quote a literal
+     *      (may be <code>null</code>)
+     *  <LI><B>LITERAL_SUFFIX</B> String => suffix used to quote a literal
+     (may be <code>null</code>)
+     *  <LI><B>CREATE_PARAMS</B> String => parameters used in creating
+     *      the type (may be <code>null</code>)
+     *  <LI><B>NULLABLE</B> short => can you use NULL for this type.
+     *      <UL>
+     *      <LI> typeNoNulls - does not allow NULL values
+     *      <LI> typeNullable - allows NULL values
+     *      <LI> typeNullableUnknown - nullability unknown
+     *      </UL>
+     *  <LI><B>CASE_SENSITIVE</B> boolean=> is it case sensitive.
+     *  <LI><B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
+     *      <UL>
+     *      <LI> typePredNone - No support
+     *      <LI> typePredChar - Only supported with WHERE .. LIKE
+     *      <LI> typePredBasic - Supported except for WHERE .. LIKE
+     *      <LI> typeSearchable - Supported for all WHERE ..
+     *      </UL>
+     *  <LI><B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned.
+     *  <LI><B>FIXED_PREC_SCALE</B> boolean => can it be a money value.
+     *  <LI><B>AUTO_INCREMENT</B> boolean => can it be used for an
+     *      auto-increment value.
+     *  <LI><B>LOCAL_TYPE_NAME</B> String => localized version of type name
+     *      (may be <code>null</code>)
+     *  <LI><B>MINIMUM_SCALE</B> short => minimum scale supported
+     *  <LI><B>MAXIMUM_SCALE</B> short => maximum scale supported
+     *  <LI><B>SQL_DATA_TYPE</B> int => unused
+     *  <LI><B>SQL_DATETIME_SUB</B> int => unused
+     *  <LI><B>NUM_PREC_RADIX</B> int => usually 2 or 10
+     *  </OL>
+     *
+     * <p>The PRECISION column represents the maximum column size that the server supports for the given datatype.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. Null is returned for data types where the
+     * column size is not applicable.
+     *
+     * @return a <code>ResultSet</code> object in which each row is an SQL
+     *         type description
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getTypeInfo() throws SQLException;
+
+    /**
+     * Indicates that a <code>NULL</code> value is NOT allowed for this
+     * data type.
+     * <P>
+     * A possible value for column <code>NULLABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typeNoNulls = 0;
+
+    /**
+     * Indicates that a <code>NULL</code> value is allowed for this
+     * data type.
+     * <P>
+     * A possible value for column <code>NULLABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typeNullable = 1;
+
+    /**
+     * Indicates that it is not known whether a <code>NULL</code> value
+     * is allowed for this data type.
+     * <P>
+     * A possible value for column <code>NULLABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typeNullableUnknown = 2;
+
+    /**
+     * Indicates that <code>WHERE</code> search clauses are not supported
+     * for this type.
+     * <P>
+     * A possible value for column <code>SEARCHABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typePredNone = 0;
+
+    /**
+     * Indicates that the data type
+     * can be only be used in <code>WHERE</code> search clauses
+     * that  use <code>LIKE</code> predicates.
+     * <P>
+     * A possible value for column <code>SEARCHABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typePredChar = 1;
+
+    /**
+     * Indicates that the data type can be only be used in <code>WHERE</code>
+     * search clauses
+     * that do not use <code>LIKE</code> predicates.
+     * <P>
+     * A possible value for column <code>SEARCHABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typePredBasic = 2;
+
+    /**
+     * Indicates that all <code>WHERE</code> search clauses can be
+     * based on this type.
+     * <P>
+     * A possible value for column <code>SEARCHABLE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getTypeInfo</code>.
+     */
+    int typeSearchable  = 3;
+
+    /**
+     * Retrieves a description of the given table's indices and statistics. They are
+     * ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
+     *
+     * <P>Each index column description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => table catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => table schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => table name
+     *  <LI><B>NON_UNIQUE</B> boolean => Can index values be non-unique.
+     *      false when TYPE is tableIndexStatistic
+     *  <LI><B>INDEX_QUALIFIER</B> String => index catalog (may be <code>null</code>);
+     *      <code>null</code> when TYPE is tableIndexStatistic
+     *  <LI><B>INDEX_NAME</B> String => index name; <code>null</code> when TYPE is
+     *      tableIndexStatistic
+     *  <LI><B>TYPE</B> short => index type:
+     *      <UL>
+     *      <LI> tableIndexStatistic - this identifies table statistics that are
+     *           returned in conjuction with a table's index descriptions
+     *      <LI> tableIndexClustered - this is a clustered index
+     *      <LI> tableIndexHashed - this is a hashed index
+     *      <LI> tableIndexOther - this is some other style of index
+     *      </UL>
+     *  <LI><B>ORDINAL_POSITION</B> short => column sequence number
+     *      within index; zero when TYPE is tableIndexStatistic
+     *  <LI><B>COLUMN_NAME</B> String => column name; <code>null</code> when TYPE is
+     *      tableIndexStatistic
+     *  <LI><B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending,
+     *      "D" => descending, may be <code>null</code> if sort sequence is not supported;
+     *      <code>null</code> when TYPE is tableIndexStatistic
+     *  <LI><B>CARDINALITY</B> int => When TYPE is tableIndexStatistic, then
+     *      this is the number of rows in the table; otherwise, it is the
+     *      number of unique values in the index.
+     *  <LI><B>PAGES</B> int => When TYPE is  tableIndexStatisic then
+     *      this is the number of pages used for the table, otherwise it
+     *      is the number of pages used for the current index.
+     *  <LI><B>FILTER_CONDITION</B> String => Filter condition, if any.
+     *      (may be <code>null</code>)
+     *  </OL>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in this database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schema a schema name; must match the schema name
+     *        as it is stored in this database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param table a table name; must match the table name as it is stored
+     *        in this database
+     * @param unique when true, return only indices for unique values;
+     *     when false, return indices regardless of whether unique or not
+     * @param approximate when true, result is allowed to reflect approximate
+     *     or out of data values; when false, results are requested to be
+     *     accurate
+     * @return <code>ResultSet</code> - each row is an index column description
+     * @exception SQLException if a database access error occurs
+     */
+    ResultSet getIndexInfo(String catalog, String schema, String table,
+                           boolean unique, boolean approximate)
+        throws SQLException;
+
+    /**
+     * Indicates that this column contains table statistics that
+     * are returned in conjunction with a table's index descriptions.
+     * <P>
+     * A possible value for column <code>TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getIndexInfo</code>.
+     */
+    short tableIndexStatistic = 0;
+
+    /**
+     * Indicates that this table index is a clustered index.
+     * <P>
+     * A possible value for column <code>TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getIndexInfo</code>.
+     */
+    short tableIndexClustered = 1;
+
+    /**
+     * Indicates that this table index is a hashed index.
+     * <P>
+     * A possible value for column <code>TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getIndexInfo</code>.
+     */
+    short tableIndexHashed    = 2;
+
+    /**
+     * Indicates that this table index is not a clustered
+     * index, a hashed index, or table statistics;
+     * it is something other than these.
+     * <P>
+     * A possible value for column <code>TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getIndexInfo</code>.
+     */
+    short tableIndexOther     = 3;
+
+    //--------------------------JDBC 2.0-----------------------------
+
+    /**
+     * Retrieves whether this database supports the given result set type.
+     *
+     * @param type defined in <code>java.sql.ResultSet</code>
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @see Connection
+     * @since 1.2
+     */
+    boolean supportsResultSetType(int type) throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the given concurrency type
+     * in combination with the given result set type.
+     *
+     * @param type defined in <code>java.sql.ResultSet</code>
+     * @param concurrency type defined in <code>java.sql.ResultSet</code>
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @see Connection
+     * @since 1.2
+     */
+    boolean supportsResultSetConcurrency(int type, int concurrency)
+        throws SQLException;
+
+    /**
+     *
+     * Retrieves whether for the given type of <code>ResultSet</code> object,
+     * the result set's own updates are visible.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if updates are visible for the given result set type;
+     *        <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean ownUpdatesAreVisible(int type) throws SQLException;
+
+    /**
+     * Retrieves whether a result set's own deletes are visible.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if deletes are visible for the given result set type;
+     *        <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean ownDeletesAreVisible(int type) throws SQLException;
+
+    /**
+     * Retrieves whether a result set's own inserts are visible.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if inserts are visible for the given result set type;
+     *        <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean ownInsertsAreVisible(int type) throws SQLException;
+
+    /**
+     * Retrieves whether updates made by others are visible.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if updates made by others
+     *        are visible for the given result set type;
+     *        <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean othersUpdatesAreVisible(int type) throws SQLException;
+
+    /**
+     * Retrieves whether deletes made by others are visible.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if deletes made by others
+     *        are visible for the given result set type;
+     *        <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean othersDeletesAreVisible(int type) throws SQLException;
+
+    /**
+     * Retrieves whether inserts made by others are visible.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if inserts made by others
+     *         are visible for the given result set type;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean othersInsertsAreVisible(int type) throws SQLException;
+
+    /**
+     * Retrieves whether or not a visible row update can be detected by
+     * calling the method <code>ResultSet.rowUpdated</code>.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if changes are detected by the result set type;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean updatesAreDetected(int type) throws SQLException;
+
+    /**
+     * Retrieves whether or not a visible row delete can be detected by
+     * calling the method <code>ResultSet.rowDeleted</code>.  If the method
+     * <code>deletesAreDetected</code> returns <code>false</code>, it means that
+     * deleted rows are removed from the result set.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if deletes are detected by the given result set type;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean deletesAreDetected(int type) throws SQLException;
+
+    /**
+     * Retrieves whether or not a visible row insert can be detected
+     * by calling the method <code>ResultSet.rowInserted</code>.
+     *
+     * @param type the <code>ResultSet</code> type; one of
+     *        <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *        <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     *        <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @return <code>true</code> if changes are detected by the specified result
+     *         set type; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean insertsAreDetected(int type) throws SQLException;
+
+    /**
+     * Retrieves whether this database supports batch updates.
+     *
+     * @return <code>true</code> if this database supports batch upcates;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    boolean supportsBatchUpdates() throws SQLException;
+
+    /**
+     * Retrieves a description of the user-defined types (UDTs) defined
+     * in a particular schema.  Schema-specific UDTs may have type
+     * <code>JAVA_OBJECT</code>, <code>STRUCT</code>,
+     * or <code>DISTINCT</code>.
+     *
+     * <P>Only types matching the catalog, schema, type name and type
+     * criteria are returned.  They are ordered by <code>DATA_TYPE</code>,
+     * <code>TYPE_CAT</code>, <code>TYPE_SCHEM</code>  and
+     * <code>TYPE_NAME</code>.  The type name parameter may be a fully-qualified
+     * name.  In this case, the catalog and schemaPattern parameters are
+     * ignored.
+     *
+     * <P>Each type description has the following columns:
+     *  <OL>
+     *  <LI><B>TYPE_CAT</B> String => the type's catalog (may be <code>null</code>)
+     *  <LI><B>TYPE_SCHEM</B> String => type's schema (may be <code>null</code>)
+     *  <LI><B>TYPE_NAME</B> String => type name
+     *  <LI><B>CLASS_NAME</B> String => Java class name
+     *  <LI><B>DATA_TYPE</B> int => type value defined in java.sql.Types.
+     *     One of JAVA_OBJECT, STRUCT, or DISTINCT
+     *  <LI><B>REMARKS</B> String => explanatory comment on the type
+     *  <LI><B>BASE_TYPE</B> short => type code of the source type of a
+     *     DISTINCT type or the type that implements the user-generated
+     *     reference type of the SELF_REFERENCING_COLUMN of a structured
+     *     type as defined in java.sql.Types (<code>null</code> if DATA_TYPE is not
+     *     DISTINCT or not STRUCT with REFERENCE_GENERATION = USER_DEFINED)
+     *  </OL>
+     *
+     * <P><B>Note:</B> If the driver does not support UDTs, an empty
+     * result set is returned.
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema pattern name; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param typeNamePattern a type name pattern; must match the type name
+     *        as it is stored in the database; may be a fully qualified name
+     * @param types a list of user-defined types (JAVA_OBJECT,
+     *        STRUCT, or DISTINCT) to include; <code>null</code> returns all types
+     * @return <code>ResultSet</code> object in which each row describes a UDT
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.2
+     */
+    ResultSet getUDTs(String catalog, String schemaPattern,
+                      String typeNamePattern, int[] types)
+        throws SQLException;
+
+    /**
+     * Retrieves the connection that produced this metadata object.
+     * <P>
+     * @return the connection that produced this metadata object
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    Connection getConnection() throws SQLException;
+
+    // ------------------- JDBC 3.0 -------------------------
+
+    /**
+     * Retrieves whether this database supports savepoints.
+     *
+     * @return <code>true</code> if savepoints are supported;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    boolean supportsSavepoints() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports named parameters to callable
+     * statements.
+     *
+     * @return <code>true</code> if named parameters are supported;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    boolean supportsNamedParameters() throws SQLException;
+
+    /**
+     * Retrieves whether it is possible to have multiple <code>ResultSet</code> objects
+     * returned from a <code>CallableStatement</code> object
+     * simultaneously.
+     *
+     * @return <code>true</code> if a <code>CallableStatement</code> object
+     *         can return multiple <code>ResultSet</code> objects
+     *         simultaneously; <code>false</code> otherwise
+     * @exception SQLException if a datanase access error occurs
+     * @since 1.4
+     */
+    boolean supportsMultipleOpenResults() throws SQLException;
+
+    /**
+     * Retrieves whether auto-generated keys can be retrieved after
+     * a statement has been executed
+     *
+     * @return <code>true</code> if auto-generated keys can be retrieved
+     *         after a statement has executed; <code>false</code> otherwise
+     *<p>If <code>true</code> is returned, the JDBC driver must support the
+     * returning of auto-generated keys for at least SQL INSERT statements
+     *<p>
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    boolean supportsGetGeneratedKeys() throws SQLException;
+
+    /**
+     * Retrieves a description of the user-defined type (UDT) hierarchies defined in a
+     * particular schema in this database. Only the immediate super type/
+     * sub type relationship is modeled.
+     * <P>
+     * Only supertype information for UDTs matching the catalog,
+     * schema, and type name is returned. The type name parameter
+     * may be a fully-qualified name. When the UDT name supplied is a
+     * fully-qualified name, the catalog and schemaPattern parameters are
+     * ignored.
+     * <P>
+     * If a UDT does not have a direct super type, it is not listed here.
+     * A row of the <code>ResultSet</code> object returned by this method
+     * describes the designated UDT and a direct supertype. A row has the following
+     * columns:
+     *  <OL>
+     *  <LI><B>TYPE_CAT</B> String => the UDT's catalog (may be <code>null</code>)
+     *  <LI><B>TYPE_SCHEM</B> String => UDT's schema (may be <code>null</code>)
+     *  <LI><B>TYPE_NAME</B> String => type name of the UDT
+     *  <LI><B>SUPERTYPE_CAT</B> String => the direct super type's catalog
+     *                           (may be <code>null</code>)
+     *  <LI><B>SUPERTYPE_SCHEM</B> String => the direct super type's schema
+     *                             (may be <code>null</code>)
+     *  <LI><B>SUPERTYPE_NAME</B> String => the direct super type's name
+     *  </OL>
+     *
+     * <P><B>Note:</B> If the driver does not support type hierarchies, an
+     * empty result set is returned.
+     *
+     * @param catalog a catalog name; "" retrieves those without a catalog;
+     *        <code>null</code> means drop catalog name from the selection criteria
+     * @param schemaPattern a schema name pattern; "" retrieves those
+     *        without a schema
+     * @param typeNamePattern a UDT name pattern; may be a fully-qualified
+     *        name
+     * @return a <code>ResultSet</code> object in which a row gives information
+     *         about the designated UDT
+     * @throws SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.4
+     */
+    ResultSet getSuperTypes(String catalog, String schemaPattern,
+                            String typeNamePattern) throws SQLException;
+
+    /**
+     * Retrieves a description of the table hierarchies defined in a particular
+     * schema in this database.
+     *
+     * <P>Only supertable information for tables matching the catalog, schema
+     * and table name are returned. The table name parameter may be a fully-
+     * qualified name, in which case, the catalog and schemaPattern parameters
+     * are ignored. If a table does not have a super table, it is not listed here.
+     * Supertables have to be defined in the same catalog and schema as the
+     * sub tables. Therefore, the type description does not need to include
+     * this information for the supertable.
+     *
+     * <P>Each type description has the following columns:
+     *  <OL>
+     *  <LI><B>TABLE_CAT</B> String => the type's catalog (may be <code>null</code>)
+     *  <LI><B>TABLE_SCHEM</B> String => type's schema (may be <code>null</code>)
+     *  <LI><B>TABLE_NAME</B> String => type name
+     *  <LI><B>SUPERTABLE_NAME</B> String => the direct super type's name
+     *  </OL>
+     *
+     * <P><B>Note:</B> If the driver does not support type hierarchies, an
+     * empty result set is returned.
+     *
+     * @param catalog a catalog name; "" retrieves those without a catalog;
+     *        <code>null</code> means drop catalog name from the selection criteria
+     * @param schemaPattern a schema name pattern; "" retrieves those
+     *        without a schema
+     * @param tableNamePattern a table name pattern; may be a fully-qualified
+     *        name
+     * @return a <code>ResultSet</code> object in which each row is a type description
+     * @throws SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.4
+     */
+    ResultSet getSuperTables(String catalog, String schemaPattern,
+                             String tableNamePattern) throws SQLException;
+
+    /**
+     * Indicates that <code>NULL</code> values might not be allowed.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code> in the <code>ResultSet</code> object
+     * returned by the method <code>getAttributes</code>.
+     */
+    short attributeNoNulls = 0;
+
+    /**
+     * Indicates that <code>NULL</code> values are definitely allowed.
+     * <P>
+     * A possible value for the column <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getAttributes</code>.
+     */
+    short attributeNullable = 1;
+
+    /**
+     * Indicates that whether <code>NULL</code> values are allowed is not
+     * known.
+     * <P>
+     * A possible value for the column <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getAttributes</code>.
+     */
+    short attributeNullableUnknown = 2;
+
+    /**
+     * Retrieves a description of the given attribute of the given type
+     * for a user-defined type (UDT) that is available in the given schema
+     * and catalog.
+     * <P>
+     * Descriptions are returned only for attributes of UDTs matching the
+     * catalog, schema, type, and attribute name criteria. They are ordered by
+     * <code>TYPE_CAT</code>, <code>TYPE_SCHEM</code>,
+     * <code>TYPE_NAME</code> and <code>ORDINAL_POSITION</code>. This description
+     * does not contain inherited attributes.
+     * <P>
+     * The <code>ResultSet</code> object that is returned has the following
+     * columns:
+     * <OL>
+     *  <LI><B>TYPE_CAT</B> String => type catalog (may be <code>null</code>)
+     *  <LI><B>TYPE_SCHEM</B> String => type schema (may be <code>null</code>)
+     *  <LI><B>TYPE_NAME</B> String => type name
+     *  <LI><B>ATTR_NAME</B> String => attribute name
+     *  <LI><B>DATA_TYPE</B> int => attribute type SQL type from java.sql.Types
+     *  <LI><B>ATTR_TYPE_NAME</B> String => Data source dependent type name.
+     *  For a UDT, the type name is fully qualified. For a REF, the type name is
+     *  fully qualified and represents the target type of the reference type.
+     *  <LI><B>ATTR_SIZE</B> int => column size.  For char or date
+     *      types this is the maximum number of characters; for numeric or
+     *      decimal types this is precision.
+     *  <LI><B>DECIMAL_DIGITS</B> int => the number of fractional digits. Null is returned for data types where
+     * DECIMAL_DIGITS is not applicable.
+     *  <LI><B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
+     *  <LI><B>NULLABLE</B> int => whether NULL is allowed
+     *      <UL>
+     *      <LI> attributeNoNulls - might not allow NULL values
+     *      <LI> attributeNullable - definitely allows NULL values
+     *      <LI> attributeNullableUnknown - nullability unknown
+     *      </UL>
+     *  <LI><B>REMARKS</B> String => comment describing column (may be <code>null</code>)
+     *  <LI><B>ATTR_DEF</B> String => default value (may be <code>null</code>)
+     *  <LI><B>SQL_DATA_TYPE</B> int => unused
+     *  <LI><B>SQL_DATETIME_SUB</B> int => unused
+     *  <LI><B>CHAR_OCTET_LENGTH</B> int => for char types the
+     *       maximum number of bytes in the column
+     *  <LI><B>ORDINAL_POSITION</B> int => index of the attribute in the UDT
+     *      (starting at 1)
+     *  <LI><B>IS_NULLABLE</B> String  => ISO rules are used to determine
+     * the nullability for a attribute.
+     *       <UL>
+     *       <LI> YES           --- if the attribute can include NULLs
+     *       <LI> NO            --- if the attribute cannot include NULLs
+     *       <LI> empty string  --- if the nullability for the
+     * attribute is unknown
+     *       </UL>
+     *  <LI><B>SCOPE_CATALOG</B> String => catalog of table that is the
+     *      scope of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
+     *  <LI><B>SCOPE_SCHEMA</B> String => schema of table that is the
+     *      scope of a reference attribute (<code>null</code> if DATA_TYPE isn't REF)
+     *  <LI><B>SCOPE_TABLE</B> String => table name that is the scope of a
+     *      reference attribute (<code>null</code> if the DATA_TYPE isn't REF)
+     * <LI><B>SOURCE_DATA_TYPE</B> short => source type of a distinct type or user-generated
+     *      Ref type,SQL type from java.sql.Types (<code>null</code> if DATA_TYPE
+     *      isn't DISTINCT or user-generated REF)
+     *  </OL>
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param typeNamePattern a type name pattern; must match the
+     *        type name as it is stored in the database
+     * @param attributeNamePattern an attribute name pattern; must match the attribute
+     *        name as it is declared in the database
+     * @return a <code>ResultSet</code> object in which each row is an
+     *         attribute description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.4
+     */
+    ResultSet getAttributes(String catalog, String schemaPattern,
+                            String typeNamePattern, String attributeNamePattern)
+        throws SQLException;
+
+    /**
+     * Retrieves whether this database supports the given result set holdability.
+     *
+     * @param holdability one of the following constants:
+     *          <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *          <code>ResultSet.CLOSE_CURSORS_AT_COMMIT<code>
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @see Connection
+     * @since 1.4
+     */
+    boolean supportsResultSetHoldability(int holdability) throws SQLException;
+
+    /**
+     * Retrieves this database's default holdability for <code>ResultSet</code>
+     * objects.
+     *
+     * @return the default holdability; either
+     *         <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getResultSetHoldability() throws SQLException;
+
+    /**
+     * Retrieves the major version number of the underlying database.
+     *
+     * @return the underlying database's major version
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getDatabaseMajorVersion() throws SQLException;
+
+    /**
+     * Retrieves the minor version number of the underlying database.
+     *
+     * @return underlying database's minor version
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getDatabaseMinorVersion() throws SQLException;
+
+    /**
+     * Retrieves the major JDBC version number for this
+     * driver.
+     *
+     * @return JDBC version major number
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getJDBCMajorVersion() throws SQLException;
+
+    /**
+     * Retrieves the minor JDBC version number for this
+     * driver.
+     *
+     * @return JDBC version minor number
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getJDBCMinorVersion() throws SQLException;
+
+    /**
+     *  A possible return value for the method
+     * <code>DatabaseMetaData.getSQLStateType</code> which is used to indicate
+     * whether the value returned by the method
+     * <code>SQLException.getSQLState</code> is an
+     * X/Open (now know as Open Group) SQL CLI SQLSTATE value.
+     * <P>
+     * @since 1.4
+     */
+    int sqlStateXOpen = 1;
+
+    /**
+     *  A possible return value for the method
+     * <code>DatabaseMetaData.getSQLStateType</code> which is used to indicate
+     * whether the value returned by the method
+     * <code>SQLException.getSQLState</code> is an SQLSTATE value.
+     * <P>
+     * @since 1.6
+     */
+    int sqlStateSQL = 2;
+
+     /**
+     *  A possible return value for the method
+     * <code>DatabaseMetaData.getSQLStateType</code> which is used to indicate
+     * whether the value returned by the method
+     * <code>SQLException.getSQLState</code> is an SQL99 SQLSTATE value.
+     * <P>
+     * <b>Note:</b>This constant remains only for compatibility reasons. Developers
+     * should use the constant <code>sqlStateSQL</code> instead.
+     *
+     * @since 1.4
+     */
+    int sqlStateSQL99 = sqlStateSQL;
+
+    /**
+     * Indicates whether the SQLSTATE returned by <code>SQLException.getSQLState</code>
+     * is X/Open (now known as Open Group) SQL CLI or SQL:2003.
+     * @return the type of SQLSTATE; one of:
+     *        sqlStateXOpen or
+     *        sqlStateSQL
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getSQLStateType() throws SQLException;
+
+    /**
+     * Indicates whether updates made to a LOB are made on a copy or directly
+     * to the LOB.
+     * @return <code>true</code> if updates are made to a copy of the LOB;
+     *         <code>false</code> if updates are made directly to the LOB
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    boolean locatorsUpdateCopy() throws SQLException;
+
+    /**
+     * Retrieves whether this database supports statement pooling.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @throws SQLException if a database access error occurs
+     * @since 1.4
+     */
+    boolean supportsStatementPooling() throws SQLException;
+
+    //------------------------- JDBC 4.0 -----------------------------------
+
+    /**
+     * Indicates whether or not this data source supports the SQL <code>ROWID</code> type,
+     * and if so  the lifetime for which a <code>RowId</code> object remains valid.
+     * <p>
+     * The returned int values have the following relationship:
+     * <pre>
+     *     ROWID_UNSUPPORTED < ROWID_VALID_OTHER < ROWID_VALID_TRANSACTION
+     *         < ROWID_VALID_SESSION < ROWID_VALID_FOREVER
+     * </pre>
+     * so conditional logic such as
+     * <pre>
+     *     if (metadata.getRowIdLifetime() > DatabaseMetaData.ROWID_VALID_TRANSACTION)
+     * </pre>
+     * can be used. Valid Forever means valid across all Sessions, and valid for
+     * a Session means valid across all its contained Transactions.
+     *
+     * @return the status indicating the lifetime of a <code>RowId</code>
+     * @throws SQLException if a database access error occurs
+     * @since 1.6
+     */
+    RowIdLifetime getRowIdLifetime() throws SQLException;
+
+    /**
+     * Retrieves the schema names available in this database.  The results
+     * are ordered by <code>TABLE_CATALOG</code> and
+     * <code>TABLE_SCHEM</code>.
+     *
+     * <P>The schema columns are:
+     *  <OL>
+     *  <LI><B>TABLE_SCHEM</B> String => schema name
+     *  <LI><B>TABLE_CATALOG</B> String => catalog name (may be <code>null</code>)
+     *  </OL>
+     *
+     *
+     * @param catalog a catalog name; must match the catalog name as it is stored
+     * in the database;"" retrieves those without a catalog; null means catalog
+     * name should not be used to narrow down the search.
+     * @param schemaPattern a schema name; must match the schema name as it is
+     * stored in the database; null means
+     * schema name should not be used to narrow down the search.
+     * @return a <code>ResultSet</code> object in which each row is a
+     *         schema description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.6
+     */
+    ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException;
+
+    /**
+     * Retrieves whether this database supports invoking user-defined or vendor functions
+     * using the stored procedure escape syntax.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.6
+     */
+    boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException;
+
+    /**
+     * Retrieves whether a <code>SQLException</code> while autoCommit is <code>true</code> inidcates
+     * that all open ResultSets are closed, even ones that are holdable.  When a <code>SQLException</code> occurs while
+     * autocommit is <code>true</code>, it is vendor specific whether the JDBC driver responds with a commit operation, a
+     * rollback operation, or by doing neither a commit nor a rollback.  A potential result of this difference
+     * is in whether or not holdable ResultSets are closed.
+     *
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.6
+     */
+    boolean autoCommitFailureClosesAllResultSets() throws SQLException;
+        /**
+         * Retrieves a list of the client info properties
+         * that the driver supports.  The result set contains the following columns
+         * <p>
+         * <ol>
+         * <li><b>NAME</b> String=> The name of the client info property<br>
+         * <li><b>MAX_LEN</b> int=> The maximum length of the value for the property<br>
+         * <li><b>DEFAULT_VALUE</b> String=> The default value of the property<br>
+         * <li><b>DESCRIPTION</b> String=> A description of the property.  This will typically
+         *                                              contain information as to where this property is
+         *                                              stored in the database.
+         * </ol>
+         * <p>
+         * The <code>ResultSet</code> is sorted by the NAME column
+         * <p>
+         * @return      A <code>ResultSet</code> object; each row is a supported client info
+         * property
+         * <p>
+         *  @exception SQLException if a database access error occurs
+         * <p>
+         * @since 1.6
+         */
+        ResultSet getClientInfoProperties()
+                throws SQLException;
+
+    /**
+     * Retrieves a description of the  system and user functions available
+     * in the given catalog.
+     * <P>
+     * Only system and user function descriptions matching the schema and
+     * function name criteria are returned.  They are ordered by
+     * <code>FUNCTION_CAT</code>, <code>FUNCTION_SCHEM</code>,
+     * <code>FUNCTION_NAME</code> and
+     * <code>SPECIFIC_ NAME</code>.
+     *
+     * <P>Each function description has the the following columns:
+     *  <OL>
+     *  <LI><B>FUNCTION_CAT</B> String => function catalog (may be <code>null</code>)
+     *  <LI><B>FUNCTION_SCHEM</B> String => function schema (may be <code>null</code>)
+     *  <LI><B>FUNCTION_NAME</B> String => function name.  This is the name
+     * used to invoke the function
+     *  <LI><B>REMARKS</B> String => explanatory comment on the function
+     * <LI><B>FUNCTION_TYPE</B> short => kind of function:
+     *      <UL>
+     *      <LI>functionResultUnknown - Cannot determine if a return value
+     *       or table will be returned
+     *      <LI> functionNoTable- Does not return a table
+     *      <LI> functionReturnsTable - Returns a table
+     *      </UL>
+     *  <LI><B>SPECIFIC_NAME</B> String  => the name which uniquely identifies
+     *  this function within its schema.  This is a user specified, or DBMS
+     * generated, name that may be different then the <code>FUNCTION_NAME</code>
+     * for example with overload functions
+     *  </OL>
+     * <p>
+     * A user may not have permission to execute any of the functions that are
+     * returned by <code>getFunctions</code>
+     *
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param functionNamePattern a function name pattern; must match the
+     *        function name as it is stored in the database
+     * @return <code>ResultSet</code> - each row is a function description
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.6
+     */
+    ResultSet getFunctions(String catalog, String schemaPattern,
+                            String functionNamePattern) throws SQLException;
+    /**
+     * Retrieves a description of the given catalog's system or user
+     * function parameters and return type.
+     *
+     * <P>Only descriptions matching the schema,  function and
+     * parameter name criteria are returned. They are ordered by
+     * <code>FUNCTION_CAT</code>, <code>FUNCTION_SCHEM</code>,
+     * <code>FUNCTION_NAME</code> and
+     * <code>SPECIFIC_ NAME</code>. Within this, the return value,
+     * if any, is first. Next are the parameter descriptions in call
+     * order. The column descriptions follow in column number order.
+     *
+     * <P>Each row in the <code>ResultSet</code>
+     * is a parameter description, column description or
+     * return type description with the following fields:
+     *  <OL>
+     *  <LI><B>FUNCTION_CAT</B> String => function catalog (may be <code>null</code>)
+     *  <LI><B>FUNCTION_SCHEM</B> String => function schema (may be <code>null</code>)
+     *  <LI><B>FUNCTION_NAME</B> String => function name.  This is the name
+     * used to invoke the function
+     *  <LI><B>COLUMN_NAME</B> String => column/parameter name
+     *  <LI><B>COLUMN_TYPE</B> Short => kind of column/parameter:
+     *      <UL>
+     *      <LI> functionColumnUnknown - nobody knows
+     *      <LI> functionColumnIn - IN parameter
+     *      <LI> functionColumnInOut - INOUT parameter
+     *      <LI> functionColumnOut - OUT parameter
+     *      <LI> functionColumnReturn - function return value
+     *      <LI> functionColumnResult - Indicates that the parameter or column
+     *  is a column in the <code>ResultSet</code>
+     *      </UL>
+     *  <LI><B>DATA_TYPE</B> int => SQL type from java.sql.Types
+     *  <LI><B>TYPE_NAME</B> String => SQL type name, for a UDT type the
+     *  type name is fully qualified
+     *  <LI><B>PRECISION</B> int => precision
+     *  <LI><B>LENGTH</B> int => length in bytes of data
+     *  <LI><B>SCALE</B> short => scale -  null is returned for data types where
+     * SCALE is not applicable.
+     *  <LI><B>RADIX</B> short => radix
+     *  <LI><B>NULLABLE</B> short => can it contain NULL.
+     *      <UL>
+     *      <LI> functionNoNulls - does not allow NULL values
+     *      <LI> functionNullable - allows NULL values
+     *      <LI> functionNullableUnknown - nullability unknown
+     *      </UL>
+     *  <LI><B>REMARKS</B> String => comment describing column/parameter
+     *  <LI><B>CHAR_OCTET_LENGTH</B> int  => the maximum length of binary
+     * and character based parameters or columns.  For any other datatype the returned value
+     * is a NULL
+     *  <LI><B>ORDINAL_POSITION</B> int  => the ordinal position, starting
+     * from 1, for the input and output parameters. A value of 0
+     * is returned if this row describes the function's return value.
+     * For result set columns, it is the
+     * ordinal position of the column in the result set starting from 1.
+     *  <LI><B>IS_NULLABLE</B> String  => ISO rules are used to determine
+     * the nullability for a parameter or column.
+     *       <UL>
+     *       <LI> YES           --- if the parameter or column can include NULLs
+     *       <LI> NO            --- if the parameter or column  cannot include NULLs
+     *       <LI> empty string  --- if the nullability for the
+     * parameter  or column is unknown
+     *       </UL>
+     *  <LI><B>SPECIFIC_NAME</B> String  => the name which uniquely identifies
+     * this function within its schema.  This is a user specified, or DBMS
+     * generated, name that may be different then the <code>FUNCTION_NAME</code>
+     * for example with overload functions
+     *  </OL>
+     *
+     * <p>The PRECISION column represents the specified column size for the given
+     * parameter or column.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. Null is returned for data types where the
+     * column size is not applicable.
+     * @param catalog a catalog name; must match the catalog name as it
+     *        is stored in the database; "" retrieves those without a catalog;
+     *        <code>null</code> means that the catalog name should not be used to narrow
+     *        the search
+     * @param schemaPattern a schema name pattern; must match the schema name
+     *        as it is stored in the database; "" retrieves those without a schema;
+     *        <code>null</code> means that the schema name should not be used to narrow
+     *        the search
+     * @param functionNamePattern a procedure name pattern; must match the
+     *        function name as it is stored in the database
+     * @param columnNamePattern a parameter name pattern; must match the
+     * parameter or column name as it is stored in the database
+     * @return <code>ResultSet</code> - each row describes a
+     * user function parameter, column  or return type
+     *
+     * @exception SQLException if a database access error occurs
+     * @see #getSearchStringEscape
+     * @since 1.6
+     */
+    ResultSet getFunctionColumns(String catalog,
+                                  String schemaPattern,
+                                  String functionNamePattern,
+                                  String columnNamePattern) throws SQLException;
+
+
+    /**
+     * Indicates that type of the parameter or column is unknown.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getFunctionColumns</code>.
+     */
+    int functionColumnUnknown = 0;
+
+    /**
+     * Indicates that the parameter or column is an IN parameter.
+     * <P>
+     *  A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionColumnIn = 1;
+
+    /**
+     * Indicates that the parameter or column is an INOUT parameter.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionColumnInOut = 2;
+
+    /**
+     * Indicates that the parameter or column is an OUT parameter.
+     * <P>
+     * A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionColumnOut = 3;
+    /**
+     * Indicates that the parameter or column is a return value.
+     * <P>
+     *  A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionReturn = 4;
+
+       /**
+     * Indicates that the parameter or column is a column in a result set.
+     * <P>
+     *  A possible value for the column
+     * <code>COLUMN_TYPE</code>
+     * in the <code>ResultSet</code>
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionColumnResult = 5;
+
+
+    /**
+     * Indicates that <code>NULL</code> values are not allowed.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionNoNulls = 0;
+
+    /**
+     * Indicates that <code>NULL</code> values are allowed.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionNullable = 1;
+
+    /**
+     * Indicates that whether <code>NULL</code> values are allowed
+     * is unknown.
+     * <P>
+     * A possible value for the column
+     * <code>NULLABLE</code>
+     * in the <code>ResultSet</code> object
+     * returned by the method <code>getFunctionColumns</code>.
+     * @since 1.6
+     */
+    int functionNullableUnknown = 2;
+
+    /**
+     * Indicates that it is not known whether the function returns
+     * a result or a table.
+     * <P>
+     * A possible value for column <code>FUNCTION_TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getFunctions</code>.
+     * @since 1.6
+     */
+    int functionResultUnknown   = 0;
+
+    /**
+     * Indicates that the function  does not return a table.
+     * <P>
+     * A possible value for column <code>FUNCTION_TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getFunctions</code>.
+     * @since 1.6
+     */
+    int functionNoTable         = 1;
+
+    /**
+     * Indicates that the function  returns a table.
+     * <P>
+     * A possible value for column <code>FUNCTION_TYPE</code> in the
+     * <code>ResultSet</code> object returned by the method
+     * <code>getFunctions</code>.
+     * @since 1.6
+     */
+    int functionReturnsTable    = 2;
+
+    // Android-removed: JDBC 4.1 methods were removed immediately after the initial import.
+}
diff --git a/java/sql/Date.java b/java/sql/Date.java
new file mode 100644
index 0000000..b96828a
--- /dev/null
+++ b/java/sql/Date.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <P>A thin wrapper around a millisecond value that allows
+ * JDBC to identify this as an SQL <code>DATE</code> value.  A
+ * milliseconds value represents the number of milliseconds that
+ * have passed since January 1, 1970 00:00:00.000 GMT.
+ * <p>
+ * To conform with the definition of SQL <code>DATE</code>, the
+ * millisecond values wrapped by a <code>java.sql.Date</code> instance
+ * must be 'normalized' by setting the
+ * hours, minutes, seconds, and milliseconds to zero in the particular
+ * time zone with which the instance is associated.
+ */
+public class Date extends java.util.Date {
+
+    /**
+     * Constructs a <code>Date</code> object initialized with the given
+     * year, month, and day.
+     * <P>
+     * The result is undefined if a given argument is out of bounds.
+     *
+     * @param year the year minus 1900; must be 0 to 8099. (Note that
+     *        8099 is 9999 minus 1900.)
+     * @param month 0 to 11
+     * @param day 1 to 31
+     * @deprecated instead use the constructor <code>Date(long date)</code>
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public Date(int year, int month, int day) {
+        super(year, month, day);
+    }
+
+    /**
+     * Constructs a <code>Date</code> object using the given milliseconds
+     * time value.  If the given milliseconds value contains time
+     * information, the driver will set the time components to the
+     * time in the default time zone (the time zone of the Java virtual
+     * machine running the application) that corresponds to zero GMT.
+     *
+     * @param date milliseconds since January 1, 1970, 00:00:00 GMT not
+     *        to exceed the milliseconds representation for the year 8099.
+     *        A negative number indicates the number of milliseconds
+     *        before January 1, 1970, 00:00:00 GMT.
+     */
+    public Date(long date) {
+        // If the millisecond date value contains time info, mask it out.
+        super(date);
+
+    }
+
+    /**
+     * Sets an existing <code>Date</code> object
+     * using the given milliseconds time value.
+     * If the given milliseconds value contains time information,
+     * the driver will set the time components to the
+     * time in the default time zone (the time zone of the Java virtual
+     * machine running the application) that corresponds to zero GMT.
+     *
+     * @param date milliseconds since January 1, 1970, 00:00:00 GMT not
+     *        to exceed the milliseconds representation for the year 8099.
+     *        A negative number indicates the number of milliseconds
+     *        before January 1, 1970, 00:00:00 GMT.
+     */
+    public void setTime(long date) {
+        // If the millisecond date value contains time info, mask it out.
+        super.setTime(date);
+    }
+
+    /**
+     * Converts a string in JDBC date escape format to
+     * a <code>Date</code> value.
+     *
+     * @param s a <code>String</code> object representing a date in
+     *        in the format "yyyy-[m]m-[d]d". The leading zero for <code>mm</code>
+     * and <code>dd</code> may also be omitted.
+     * @return a <code>java.sql.Date</code> object representing the
+     *         given date
+     * @throws IllegalArgumentException if the date given is not in the
+     *         JDBC date escape format (yyyy-[m]m-[d]d)
+     */
+    public static Date valueOf(String s) {
+        final int YEAR_LENGTH = 4;
+        final int MONTH_LENGTH = 2;
+        final int DAY_LENGTH = 2;
+        final int MAX_MONTH = 12;
+        final int MAX_DAY = 31;
+        int firstDash;
+        int secondDash;
+        Date d = null;
+
+        if (s == null) {
+            throw new java.lang.IllegalArgumentException();
+        }
+
+        firstDash = s.indexOf('-');
+        secondDash = s.indexOf('-', firstDash + 1);
+
+        if ((firstDash > 0) && (secondDash > 0) && (secondDash < s.length() - 1)) {
+            String yyyy = s.substring(0, firstDash);
+            String mm = s.substring(firstDash + 1, secondDash);
+            String dd = s.substring(secondDash + 1);
+            if (yyyy.length() == YEAR_LENGTH &&
+                    (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
+                    (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
+                int year = Integer.parseInt(yyyy);
+                int month = Integer.parseInt(mm);
+                int day = Integer.parseInt(dd);
+
+                if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
+                    d = new Date(year - 1900, month - 1, day);
+                }
+            }
+        }
+        if (d == null) {
+            throw new java.lang.IllegalArgumentException();
+        }
+
+        return d;
+
+    }
+
+
+    /**
+     * Formats a date in the date escape format yyyy-mm-dd.
+     * <P>
+     * @return a String in yyyy-mm-dd format
+     */
+    public String toString () {
+        int year = super.getYear() + 1900;
+        int month = super.getMonth() + 1;
+        int day = super.getDate();
+
+        char buf[] = "2000-00-00".toCharArray();
+        buf[0] = Character.forDigit(year/1000,10);
+        buf[1] = Character.forDigit((year/100)%10,10);
+        buf[2] = Character.forDigit((year/10)%10,10);
+        buf[3] = Character.forDigit(year%10,10);
+        buf[5] = Character.forDigit(month/10,10);
+        buf[6] = Character.forDigit(month%10,10);
+        buf[8] = Character.forDigit(day/10,10);
+        buf[9] = Character.forDigit(day%10,10);
+
+        return new String(buf);
+    }
+
+    // Override all the time operations inherited from java.util.Date;
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL Date
+    * values do not have a time component.
+    *
+    * @exception java.lang.IllegalArgumentException if this method is invoked
+    * @see #setHours
+    */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public int getHours() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL Date
+    * values do not have a time component.
+    *
+    * @exception java.lang.IllegalArgumentException if this method is invoked
+    * @see #setMinutes
+    */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public int getMinutes() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL Date
+    * values do not have a time component.
+    *
+    * @exception java.lang.IllegalArgumentException if this method is invoked
+    * @see #setSeconds
+    */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public int getSeconds() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL Date
+    * values do not have a time component.
+    *
+    * @exception java.lang.IllegalArgumentException if this method is invoked
+    * @see #getHours
+    */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public void setHours(int i) {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL Date
+    * values do not have a time component.
+    *
+    * @exception java.lang.IllegalArgumentException if this method is invoked
+    * @see #getMinutes
+    */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public void setMinutes(int i) {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL Date
+    * values do not have a time component.
+    *
+    * @exception java.lang.IllegalArgumentException if this method is invoked
+    * @see #getSeconds
+    */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public void setSeconds(int i) {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   /**
+    * Private serial version unique ID to ensure serialization
+    * compatibility.
+    */
+    static final long serialVersionUID = 1511598038487230103L;
+}
diff --git a/java/sql/Driver.java b/java/sql/Driver.java
new file mode 100644
index 0000000..3970b1c
--- /dev/null
+++ b/java/sql/Driver.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.logging.Logger;
+
+/**
+ * The interface that every driver class must implement.
+ * <P>The Java SQL framework allows for multiple database drivers.
+ *
+ * <P>Each driver should supply a class that implements
+ * the Driver interface.
+ *
+ * <P>The DriverManager will try to load as many drivers as it can
+ * find and then for any given connection request, it will ask each
+ * driver in turn to try to connect to the target URL.
+ *
+ * <P>It is strongly recommended that each Driver class should be
+ * small and standalone so that the Driver class can be loaded and
+ * queried without bringing in vast quantities of supporting code.
+ *
+ * <P>When a Driver class is loaded, it should create an instance of
+ * itself and register it with the DriverManager. This means that a
+ * user can load and register a driver by calling
+ * <pre>
+ *   <code>Class.forName("foo.bah.Driver")</code>
+ * </pre>
+ *
+ * @see DriverManager
+ * @see Connection
+ */
+public interface Driver {
+
+    /**
+     * Attempts to make a database connection to the given URL.
+     * The driver should return "null" if it realizes it is the wrong kind
+     * of driver to connect to the given URL.  This will be common, as when
+     * the JDBC driver manager is asked to connect to a given URL it passes
+     * the URL to each loaded driver in turn.
+     *
+     * <P>The driver should throw an <code>SQLException</code> if it is the right
+     * driver to connect to the given URL but has trouble connecting to
+     * the database.
+     *
+     * <P>The <code>java.util.Properties</code> argument can be used to pass
+     * arbitrary string tag/value pairs as connection arguments.
+     * Normally at least "user" and "password" properties should be
+     * included in the <code>Properties</code> object.
+     *
+     * @param url the URL of the database to which to connect
+     * @param info a list of arbitrary string tag/value pairs as
+     * connection arguments. Normally at least a "user" and
+     * "password" property should be included.
+     * @return a <code>Connection</code> object that represents a
+     *         connection to the URL
+     * @exception SQLException if a database access error occurs
+     */
+    Connection connect(String url, java.util.Properties info)
+        throws SQLException;
+
+    /**
+     * Retrieves whether the driver thinks that it can open a connection
+     * to the given URL.  Typically drivers will return <code>true</code> if they
+     * understand the subprotocol specified in the URL and <code>false</code> if
+     * they do not.
+     *
+     * @param url the URL of the database
+     * @return <code>true</code> if this driver understands the given URL;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean acceptsURL(String url) throws SQLException;
+
+
+    /**
+     * Gets information about the possible properties for this driver.
+     * <P>
+     * The <code>getPropertyInfo</code> method is intended to allow a generic
+     * GUI tool to discover what properties it should prompt
+     * a human for in order to get
+     * enough information to connect to a database.  Note that depending on
+     * the values the human has supplied so far, additional values may become
+     * necessary, so it may be necessary to iterate though several calls
+     * to the <code>getPropertyInfo</code> method.
+     *
+     * @param url the URL of the database to which to connect
+     * @param info a proposed list of tag/value pairs that will be sent on
+     *          connect open
+     * @return an array of <code>DriverPropertyInfo</code> objects describing
+     *          possible properties.  This array may be an empty array if
+     *          no properties are required.
+     * @exception SQLException if a database access error occurs
+     */
+    DriverPropertyInfo[] getPropertyInfo(String url, java.util.Properties info)
+                         throws SQLException;
+
+
+    /**
+     * Retrieves the driver's major version number. Initially this should be 1.
+     *
+     * @return this driver's major version number
+     */
+    int getMajorVersion();
+
+    /**
+     * Gets the driver's minor version number. Initially this should be 0.
+     * @return this driver's minor version number
+     */
+    int getMinorVersion();
+
+
+    /**
+     * Reports whether this driver is a genuine JDBC
+     * Compliant<sup><font size=-2>TM</font></sup> driver.
+     * A driver may only report <code>true</code> here if it passes the JDBC
+     * compliance tests; otherwise it is required to return <code>false</code>.
+     * <P>
+     * JDBC compliance requires full support for the JDBC API and full support
+     * for SQL 92 Entry Level.  It is expected that JDBC compliant drivers will
+     * be available for all the major commercial databases.
+     * <P>
+     * This method is not intended to encourage the development of non-JDBC
+     * compliant drivers, but is a recognition of the fact that some vendors
+     * are interested in using the JDBC API and framework for lightweight
+     * databases that do not support full database functionality, or for
+     * special databases such as document information retrieval where a SQL
+     * implementation may not be feasible.
+     * @return <code>true</code> if this driver is JDBC Compliant; <code>false</code>
+     *         otherwise
+     */
+    boolean jdbcCompliant();
+
+    // Android-removed: JDBC 4.1 methods were removed immediately after the initial import.
+}
diff --git a/java/sql/DriverManager.java b/java/sql/DriverManager.java
new file mode 100644
index 0000000..08755b0
--- /dev/null
+++ b/java/sql/DriverManager.java
@@ -0,0 +1,633 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+// Android-changed line 2 of the javadoc to "{@code DataSource}".
+/**
+ * <P>The basic service for managing a set of JDBC drivers.<br>
+ * <B>NOTE:</B> The {@code DataSource} interface, new in the
+ * JDBC 2.0 API, provides another way to connect to a data source.
+ * The use of a <code>DataSource</code> object is the preferred means of
+ * connecting to a data source.
+ *
+ * <P>As part of its initialization, the <code>DriverManager</code> class will
+ * attempt to load the driver classes referenced in the "jdbc.drivers"
+ * system property. This allows a user to customize the JDBC Drivers
+ * used by their applications. For example in your
+ * ~/.hotjava/properties file you might specify:
+ * <pre>
+ * <CODE>jdbc.drivers=foo.bah.Driver:wombat.sql.Driver:bad.taste.ourDriver</CODE>
+ * </pre>
+ *<P> The <code>DriverManager</code> methods <code>getConnection</code> and
+ * <code>getDrivers</code> have been enhanced to support the Java Standard Edition
+ * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
+ * include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
+ * implementation of <code>java.sql.Driver</code>.  For example, to load the <code>my.sql.Driver</code> class,
+ * the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
+ * <pre>
+ * <code>my.sql.Driver</code>
+ * </pre>
+ *
+ * <P>Applications no longer need to explictly load JDBC drivers using <code>Class.forName()</code>. Existing programs
+ * which currently load JDBC drivers using <code>Class.forName()</code> will continue to work without
+ * modification.
+ *
+ * <P>When the method <code>getConnection</code> is called,
+ * the <code>DriverManager</code> will attempt to
+ * locate a suitable driver from amongst those loaded at
+ * initialization and those loaded explicitly using the same classloader
+ * as the current applet or application.
+ *
+ * <P>
+ * Starting with the Java 2 SDK, Standard Edition, version 1.3, a
+ * logging stream can be set only if the proper
+ * permission has been granted.  Normally this will be done with
+ * the tool PolicyTool, which can be used to grant <code>permission
+ * java.sql.SQLPermission "setLog"</code>.
+ * @see Driver
+ * @see Connection
+ */
+public class DriverManager {
+
+
+    // List of registered JDBC drivers
+    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();
+    private static volatile int loginTimeout = 0;
+    private static volatile java.io.PrintWriter logWriter = null;
+    private static volatile java.io.PrintStream logStream = null;
+    // Used in println() to synchronize logWriter
+    private final static  Object logSync = new Object();
+
+    /* Prevent the DriverManager class from being instantiated. */
+    private DriverManager(){}
+
+
+    /**
+     * Load the initial JDBC drivers by checking the System property
+     * jdbc.properties and then use the {@code ServiceLoader} mechanism
+     */
+    static {
+        loadInitialDrivers();
+        println("JDBC DriverManager initialized");
+    }
+
+    /**
+     * The <code>SQLPermission</code> constant that allows the
+     * setting of the logging stream.
+     * @since 1.3
+     */
+    final static SQLPermission SET_LOG_PERMISSION =
+        new SQLPermission("setLog");
+
+    //--------------------------JDBC 2.0-----------------------------
+
+    /**
+     * Retrieves the log writer.
+     *
+     * The <code>getLogWriter</code> and <code>setLogWriter</code>
+     * methods should be used instead
+     * of the <code>get/setlogStream</code> methods, which are deprecated.
+     * @return a <code>java.io.PrintWriter</code> object
+     * @see #setLogWriter
+     * @since 1.2
+     */
+    public static java.io.PrintWriter getLogWriter() {
+            return logWriter;
+    }
+
+    /**
+     * Sets the logging/tracing <code>PrintWriter</code> object
+     * that is used by the <code>DriverManager</code> and all drivers.
+     * <P>
+     * There is a minor versioning problem created by the introduction
+     * of the method <code>setLogWriter</code>.  The
+     * method <code>setLogWriter</code> cannot create a <code>PrintStream</code> object
+     * that will be returned by <code>getLogStream</code>---the Java platform does
+     * not provide a backward conversion.  As a result, a new application
+     * that uses <code>setLogWriter</code> and also uses a JDBC 1.0 driver that uses
+     * <code>getLogStream</code> will likely not see debugging information written
+     * by that driver.
+     *<P>
+     * Starting with the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
+     * to see that there is an <code>SQLPermission</code> object before setting
+     * the logging stream.  If a <code>SecurityManager</code> exists and its
+     * <code>checkPermission</code> method denies setting the log writer, this
+     * method throws a <code>java.lang.SecurityException</code>.
+     *
+     * @param out the new logging/tracing <code>PrintStream</code> object;
+     *      <code>null</code> to disable logging and tracing
+     * @throws SecurityException
+     *    if a security manager exists and its
+     *    <code>checkPermission</code> method denies
+     *    setting the log writer
+     *
+     * @see SecurityManager#checkPermission
+     * @see #getLogWriter
+     * @since 1.2
+     */
+    public static void setLogWriter(java.io.PrintWriter out) {
+
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            sec.checkPermission(SET_LOG_PERMISSION);
+        }
+            logStream = null;
+            logWriter = out;
+    }
+
+
+    //---------------------------------------------------------------
+
+    /**
+     * Attempts to establish a connection to the given database URL.
+     * The <code>DriverManager</code> attempts to select an appropriate driver from
+     * the set of registered JDBC drivers.
+     *
+     * @param url a database url of the form
+     * <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     * @param info a list of arbitrary string tag/value pairs as
+     * connection arguments; normally at least a "user" and
+     * "password" property should be included
+     * @return a Connection to the URL
+     * @exception SQLException if a database access error occurs
+     */
+    @CallerSensitive
+    public static Connection getConnection(String url,
+        java.util.Properties info) throws SQLException {
+        return (getConnection(url, info, Reflection.getCallerClass()));
+    }
+
+    /**
+     * Attempts to establish a connection to the given database URL.
+     * The <code>DriverManager</code> attempts to select an appropriate driver from
+     * the set of registered JDBC drivers.
+     *
+     * @param url a database url of the form
+     * <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     * @param user the database user on whose behalf the connection is being
+     *   made
+     * @param password the user's password
+     * @return a connection to the URL
+     * @exception SQLException if a database access error occurs
+     */
+    @CallerSensitive
+    public static Connection getConnection(String url,
+        String user, String password) throws SQLException {
+        java.util.Properties info = new java.util.Properties();
+
+        if (user != null) {
+            info.put("user", user);
+        }
+        if (password != null) {
+            info.put("password", password);
+        }
+
+        return (getConnection(url, info, Reflection.getCallerClass()));
+    }
+
+    /**
+     * Attempts to establish a connection to the given database URL.
+     * The <code>DriverManager</code> attempts to select an appropriate driver from
+     * the set of registered JDBC drivers.
+     *
+     * @param url a database url of the form
+     *  <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     * @return a connection to the URL
+     * @exception SQLException if a database access error occurs
+     */
+    @CallerSensitive
+    public static Connection getConnection(String url)
+        throws SQLException {
+
+        java.util.Properties info = new java.util.Properties();
+        return (getConnection(url, info, Reflection.getCallerClass()));
+    }
+
+    /**
+     * Attempts to locate a driver that understands the given URL.
+     * The <code>DriverManager</code> attempts to select an appropriate driver from
+     * the set of registered JDBC drivers.
+     *
+     * @param url a database URL of the form
+     *     <code>jdbc:<em>subprotocol</em>:<em>subname</em></code>
+     * @return a <code>Driver</code> object representing a driver
+     * that can connect to the given URL
+     * @exception SQLException if a database access error occurs
+     */
+    @CallerSensitive
+    public static Driver getDriver(String url)
+        throws SQLException {
+
+        println("DriverManager.getDriver(\"" + url + "\")");
+
+        Class<?> callerClass = Reflection.getCallerClass();
+
+        // Walk through the loaded registeredDrivers attempting to locate someone
+        // who understands the given URL.
+        for (DriverInfo aDriver : registeredDrivers) {
+            // If the caller does not have permission to load the driver then
+            // skip it.
+            if(isDriverAllowed(aDriver.driver, callerClass)) {
+                try {
+                    if(aDriver.driver.acceptsURL(url)) {
+                        // Success!
+                        println("getDriver returning " + aDriver.driver.getClass().getName());
+                    return (aDriver.driver);
+                    }
+
+                } catch(SQLException sqe) {
+                    // Drop through and try the next driver.
+                }
+            } else {
+                println("    skipping: " + aDriver.driver.getClass().getName());
+            }
+
+        }
+
+        println("getDriver: no suitable driver");
+        throw new SQLException("No suitable driver", "08001");
+    }
+
+
+    /**
+     * Registers the given driver with the <code>DriverManager</code>.
+     * A newly-loaded driver class should call
+     * the method <code>registerDriver</code> to make itself
+     * known to the <code>DriverManager</code>.
+     *
+     * @param driver the new JDBC Driver that is to be registered with the
+     *               <code>DriverManager</code>
+     * @exception SQLException if a database access error occurs
+     */
+    public static synchronized void registerDriver(java.sql.Driver driver)
+        throws SQLException {
+
+        /* Register the driver if it has not already been added to our list */
+        if(driver != null) {
+            registeredDrivers.addIfAbsent(new DriverInfo(driver));
+        } else {
+            // This is for compatibility with the original DriverManager
+            throw new NullPointerException();
+        }
+
+        println("registerDriver: " + driver);
+
+    }
+
+    /**
+     * Drops a driver from the <code>DriverManager</code>'s list.
+     *  Applets can only deregister drivers from their own classloaders.
+     *
+     * @param driver the JDBC Driver to drop
+     * @exception SQLException if a database access error occurs
+     */
+    @CallerSensitive
+    public static synchronized void deregisterDriver(Driver driver)
+        throws SQLException {
+        if (driver == null) {
+            return;
+        }
+
+        println("DriverManager.deregisterDriver: " + driver);
+
+        DriverInfo aDriver = new DriverInfo(driver);
+        if(registeredDrivers.contains(aDriver)) {
+            if (isDriverAllowed(driver, Reflection.getCallerClass())) {
+                 registeredDrivers.remove(aDriver);
+            } else {
+                // If the caller does not have permission to load the driver then
+                // throw a SecurityException.
+                throw new SecurityException();
+            }
+        } else {
+            println("    couldn't find driver to unload");
+        }
+    }
+
+    /**
+     * Retrieves an Enumeration with all of the currently loaded JDBC drivers
+     * to which the current caller has access.
+     *
+     * <P><B>Note:</B> The classname of a driver can be found using
+     * <CODE>d.getClass().getName()</CODE>
+     *
+     * @return the list of JDBC Drivers loaded by the caller's class loader
+     */
+    @CallerSensitive
+    public static java.util.Enumeration<Driver> getDrivers() {
+        java.util.Vector<Driver> result = new java.util.Vector<Driver>();
+
+        Class<?> callerClass = Reflection.getCallerClass();
+
+        // Walk through the loaded registeredDrivers.
+        for(DriverInfo aDriver : registeredDrivers) {
+            // If the caller does not have permission to load the driver then
+            // skip it.
+            if(isDriverAllowed(aDriver.driver, callerClass)) {
+                result.addElement(aDriver.driver);
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
+            }
+        }
+        return (result.elements());
+    }
+
+
+    /**
+     * Sets the maximum time in seconds that a driver will wait
+     * while attempting to connect to a database.
+     *
+     * @param seconds the login time limit in seconds; zero means there is no limit
+     * @see #getLoginTimeout
+     */
+    public static void setLoginTimeout(int seconds) {
+        loginTimeout = seconds;
+    }
+
+    /**
+     * Gets the maximum time in seconds that a driver can wait
+     * when attempting to log in to a database.
+     *
+     * @return the driver login time limit in seconds
+     * @see #setLoginTimeout
+     */
+    public static int getLoginTimeout() {
+        return (loginTimeout);
+    }
+
+    // Android-changed: Added reason to @deprecated to improve the documentation.
+    /**
+     * Sets the logging/tracing PrintStream that is used
+     * by the <code>DriverManager</code>
+     * and all drivers.
+     *<P>
+     * In the Java 2 SDK, Standard Edition, version 1.3 release, this method checks
+     * to see that there is an <code>SQLPermission</code> object before setting
+     * the logging stream.  If a <code>SecurityManager</code> exists and its
+     * <code>checkPermission</code> method denies setting the log writer, this
+     * method throws a <code>java.lang.SecurityException</code>.
+     *
+     * @param out the new logging/tracing PrintStream; to disable, set to <code>null</code>
+     * @deprecated Use {@code setLogWriter} instead.
+     * @throws SecurityException if a security manager exists and its
+     *    <code>checkPermission</code> method denies setting the log stream
+     *
+     * @see SecurityManager#checkPermission
+     * @see #getLogStream
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public static void setLogStream(java.io.PrintStream out) {
+
+        SecurityManager sec = System.getSecurityManager();
+        if (sec != null) {
+            sec.checkPermission(SET_LOG_PERMISSION);
+        }
+
+        logStream = out;
+        if ( out != null )
+            logWriter = new java.io.PrintWriter(out);
+        else
+            logWriter = null;
+    }
+
+    // Android-changed: Added reason to @deprecated to improve the documentation.
+    /**
+     * Retrieves the logging/tracing PrintStream that is used by the <code>DriverManager</code>
+     * and all drivers.
+     *
+     * @return the logging/tracing PrintStream; if disabled, is <code>null</code>
+     * @deprecated Use {@code getLogWriter} instead.
+     * @see #setLogStream
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    public static java.io.PrintStream getLogStream() {
+        return logStream;
+    }
+
+    /**
+     * Prints a message to the current JDBC log stream.
+     *
+     * @param message a log or tracing message
+     */
+    public static void println(String message) {
+        synchronized (logSync) {
+            if (logWriter != null) {
+                logWriter.println(message);
+
+                // automatic flushing is never enabled, so we must do it ourselves
+                logWriter.flush();
+            }
+        }
+    }
+
+    //------------------------------------------------------------------------
+
+    // Indicates whether the class object that would be created if the code calling
+    // DriverManager is accessible.
+    private static boolean isDriverAllowed(Driver driver, Class<?> caller) {
+        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
+        return isDriverAllowed(driver, callerCL);
+    }
+
+    private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
+        boolean result = false;
+        if(driver != null) {
+            Class<?> aClass = null;
+            try {
+                aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
+            } catch (Exception ex) {
+                result = false;
+            }
+
+             result = ( aClass == driver.getClass() ) ? true : false;
+        }
+
+        return result;
+    }
+
+    private static void loadInitialDrivers() {
+        String drivers;
+        try {
+            drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
+                public String run() {
+                    return System.getProperty("jdbc.drivers");
+                }
+            });
+        } catch (Exception ex) {
+            drivers = null;
+        }
+        // If the driver is packaged as a Service Provider, load it.
+        // Get all the drivers through the classloader
+        // exposed as a java.sql.Driver.class service.
+        // ServiceLoader.load() replaces the sun.misc.Providers()
+
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+
+                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
+                Iterator driversIterator = loadedDrivers.iterator();
+
+                /* Load these drivers, so that they can be instantiated.
+                 * It may be the case that the driver class may not be there
+                 * i.e. there may be a packaged driver with the service class
+                 * as implementation of java.sql.Driver but the actual class
+                 * may be missing. In that case a java.util.ServiceConfigurationError
+                 * will be thrown at runtime by the VM trying to locate
+                 * and load the service.
+                 *
+                 * Adding a try catch block to catch those runtime errors
+                 * if driver not available in classpath but it's
+                 * packaged as service and that service is there in classpath.
+                 */
+                try{
+                    while(driversIterator.hasNext()) {
+                        driversIterator.next();
+                    }
+                } catch(Throwable t) {
+                // Do nothing
+                }
+                return null;
+            }
+        });
+
+        println("DriverManager.initialize: jdbc.drivers = " + drivers);
+
+        if (drivers == null || drivers.equals("")) {
+            return;
+        }
+        String[] driversList = drivers.split(":");
+        println("number of Drivers:" + driversList.length);
+        for (String aDriver : driversList) {
+            try {
+                println("DriverManager.Initialize: loading " + aDriver);
+                Class.forName(aDriver, true,
+                        ClassLoader.getSystemClassLoader());
+            } catch (Exception ex) {
+                println("DriverManager.Initialize: load failed: " + ex);
+            }
+        }
+    }
+
+
+    //  Worker method called by the public getConnection() methods.
+    private static Connection getConnection(
+        String url, java.util.Properties info, Class<?> caller) throws SQLException {
+        /*
+         * When callerCl is null, we should check the application's
+         * (which is invoking this class indirectly)
+         * classloader, so that the JDBC driver class outside rt.jar
+         * can be loaded from here.
+         */
+        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
+        synchronized (DriverManager.class) {
+            // synchronize loading of the correct classloader.
+            if (callerCL == null) {
+                callerCL = Thread.currentThread().getContextClassLoader();
+            }
+        }
+
+        if(url == null) {
+            throw new SQLException("The url cannot be null", "08001");
+        }
+
+        println("DriverManager.getConnection(\"" + url + "\")");
+
+        // Walk through the loaded registeredDrivers attempting to make a connection.
+        // Remember the first exception that gets raised so we can reraise it.
+        SQLException reason = null;
+
+        for(DriverInfo aDriver : registeredDrivers) {
+            // If the caller does not have permission to load the driver then
+            // skip it.
+            if(isDriverAllowed(aDriver.driver, callerCL)) {
+                try {
+                    println("    trying " + aDriver.driver.getClass().getName());
+                    Connection con = aDriver.driver.connect(url, info);
+                    if (con != null) {
+                        // Success!
+                        println("getConnection returning " + aDriver.driver.getClass().getName());
+                        return (con);
+                    }
+                } catch (SQLException ex) {
+                    if (reason == null) {
+                        reason = ex;
+                    }
+                }
+
+            } else {
+                println("    skipping: " + aDriver.getClass().getName());
+            }
+
+        }
+
+        // if we got here nobody could connect.
+        if (reason != null)    {
+            println("getConnection failed: " + reason);
+            throw reason;
+        }
+
+        println("getConnection: no suitable driver found for "+ url);
+        throw new SQLException("No suitable driver found for "+ url, "08001");
+    }
+}
+
+/*
+ * Wrapper class for registered Drivers in order to not expose Driver.equals()
+ * to avoid the capture of the Driver it being compared to as it might not
+ * normally have access.
+ */
+class DriverInfo {
+
+    final Driver driver;
+    DriverInfo(Driver driver) {
+        this.driver = driver;
+    }
+
+    public boolean equals(Object other) {
+        return (other instanceof DriverInfo)
+                && this.driver == ((DriverInfo) other).driver;
+    }
+
+    public int hashCode() {
+        return driver.hashCode();
+    }
+
+    public String toString() {
+        return ("driver[className="  + driver + "]");
+    }
+}
diff --git a/java/sql/DriverPropertyInfo.java b/java/sql/DriverPropertyInfo.java
new file mode 100644
index 0000000..6e78e07
--- /dev/null
+++ b/java/sql/DriverPropertyInfo.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <p>Driver properties for making a connection. The
+ * <code>DriverPropertyInfo</code> class is of interest only to advanced programmers
+ * who need to interact with a Driver via the method
+ * <code>getDriverProperties</code> to discover
+ * and supply properties for connections.
+ */
+
+public class DriverPropertyInfo {
+
+    /**
+     * Constructs a <code>DriverPropertyInfo</code> object with a  given
+     * name and value.  The <code>description</code> and <code>choices</code>
+     * are intialized to <code>null</code> and <code>required</code> is initialized
+     * to <code>false</code>.
+     *
+     * @param name the name of the property
+     * @param value the current value, which may be null
+     */
+    public DriverPropertyInfo(String name, String value) {
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+     * The name of the property.
+     */
+    public String name;
+
+    /**
+     * A brief description of the property, which may be null.
+     */
+    public String description = null;
+
+    /**
+     * The <code>required</code> field is <code>true</code> if a value must be
+         * supplied for this property
+     * during <code>Driver.connect</code> and <code>false</code> otherwise.
+     */
+    public boolean required = false;
+
+    /**
+     * The <code>value</code> field specifies the current value of
+         * the property, based on a combination of the information
+         * supplied to the method <code>getPropertyInfo</code>, the
+     * Java environment, and the driver-supplied default values.  This field
+     * may be null if no value is known.
+     */
+    public String value = null;
+
+    /**
+     * An array of possible values if the value for the field
+         * <code>DriverPropertyInfo.value</code> may be selected
+         * from a particular set of values; otherwise null.
+     */
+    public String[] choices = null;
+}
diff --git a/java/sql/NClob.java b/java/sql/NClob.java
new file mode 100644
index 0000000..a70ed61
--- /dev/null
+++ b/java/sql/NClob.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.sql.Clob;
+
+/**
+ * The mapping in the Java<sup><font size=-2>TM</font></sup> programming language
+ * for the SQL <code>NCLOB</code> type.
+ * An SQL <code>NCLOB</code> is a built-in type
+ * that stores a Character Large Object using the National Character Set
+ *  as a column value in a row of  a database table.
+ * <P>The <code>NClob</code> interface extends the <code>Clob</code> interface
+ * which provides provides methods for getting the
+ * length of an SQL <code>NCLOB</code> value,
+ * for materializing a <code>NCLOB</code> value on the client, and for
+ * searching for a substring or <code>NCLOB</code> object within a
+ * <code>NCLOB</code> value. A <code>NClob</code> object, just like a <code>Clob</code> object, is valid for the duration
+ * of the transaction in which it was created.
+ * Methods in the interfaces {@link ResultSet},
+ * {@link CallableStatement}, and {@link PreparedStatement}, such as
+ * <code>getNClob</code> and <code>setNClob</code> allow a programmer to
+ * access an SQL <code>NCLOB</code> value.  In addition, this interface
+ * has methods for updating a <code>NCLOB</code> value.
+ * <p>
+ * All methods on the <code>NClob</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @since 1.6
+ */
+
+public interface NClob extends Clob { }
diff --git a/java/sql/ParameterMetaData.java b/java/sql/ParameterMetaData.java
new file mode 100644
index 0000000..84eafdc
--- /dev/null
+++ b/java/sql/ParameterMetaData.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * An object that can be used to get information about the types
+ * and properties for each parameter marker in a
+ * <code>PreparedStatement</code> object. For some queries and driver
+ * implementations, the data that would be returned by a <code>ParameterMetaData</code>
+ * object may not be available until the <code>PreparedStatement</code> has
+ * been executed.
+ *<p>
+ *Some driver implementations may not be able to provide information about the
+ *types and properties for each parameter marker in a <code>CallableStatement</code>
+ *object.
+ *
+ * @since 1.4
+ */
+
+public interface ParameterMetaData extends Wrapper {
+
+    /**
+     * Retrieves the number of parameters in the <code>PreparedStatement</code>
+     * object for which this <code>ParameterMetaData</code> object contains
+     * information.
+     *
+     * @return the number of parameters
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getParameterCount() throws SQLException;
+
+    /**
+     * Retrieves whether null values are allowed in the designated parameter.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return the nullability status of the given parameter; one of
+     *        <code>ParameterMetaData.parameterNoNulls</code>,
+     *        <code>ParameterMetaData.parameterNullable</code>, or
+     *        <code>ParameterMetaData.parameterNullableUnknown</code>
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int isNullable(int param) throws SQLException;
+
+    /**
+     * The constant indicating that a
+     * parameter will not allow <code>NULL</code> values.
+     */
+    int parameterNoNulls = 0;
+
+    /**
+     * The constant indicating that a
+     * parameter will allow <code>NULL</code> values.
+     */
+    int parameterNullable = 1;
+
+    /**
+     * The constant indicating that the
+     * nullability of a parameter is unknown.
+     */
+    int parameterNullableUnknown = 2;
+
+    /**
+     * Retrieves whether values for the designated parameter can be signed numbers.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    boolean isSigned(int param) throws SQLException;
+
+    /**
+     * Retrieves the designated parameter's specified column size.
+     *
+     * <P>The returned value represents the maximum column size for the given parameter.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. 0 is returned for data types where the
+     * column size is not applicable.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return precision
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getPrecision(int param) throws SQLException;
+
+    /**
+     * Retrieves the designated parameter's number of digits to right of the decimal point.
+     * 0 is returned for data types where the scale is not applicable.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return scale
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getScale(int param) throws SQLException;
+
+    /**
+     * Retrieves the designated parameter's SQL type.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return SQL type from <code>java.sql.Types</code>
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     * @see Types
+     */
+    int getParameterType(int param) throws SQLException;
+
+    /**
+     * Retrieves the designated parameter's database-specific type name.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return type the name used by the database. If the parameter type is
+     * a user-defined type, then a fully-qualified type name is returned.
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    String getParameterTypeName(int param) throws SQLException;
+
+
+    /**
+     * Retrieves the fully-qualified name of the Java class whose instances
+     * should be passed to the method <code>PreparedStatement.setObject</code>.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return the fully-qualified name of the class in the Java programming
+     *         language that would be used by the method
+     *         <code>PreparedStatement.setObject</code> to set the value
+     *         in the specified parameter. This is the class name used
+     *         for custom mapping.
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    String getParameterClassName(int param) throws SQLException;
+
+    /**
+     * The constant indicating that the mode of the parameter is unknown.
+     */
+    int parameterModeUnknown = 0;
+
+    /**
+     * The constant indicating that the parameter's mode is IN.
+     */
+    int parameterModeIn = 1;
+
+    /**
+     * The constant indicating that the parameter's mode is INOUT.
+     */
+    int parameterModeInOut = 2;
+
+    /**
+     * The constant indicating that the parameter's mode is  OUT.
+     */
+    int parameterModeOut = 4;
+
+    /**
+     * Retrieves the designated parameter's mode.
+     *
+     * @param param the first parameter is 1, the second is 2, ...
+     * @return mode of the parameter; one of
+     *        <code>ParameterMetaData.parameterModeIn</code>,
+     *        <code>ParameterMetaData.parameterModeOut</code>, or
+     *        <code>ParameterMetaData.parameterModeInOut</code>
+     *        <code>ParameterMetaData.parameterModeUnknown</code>.
+     * @exception SQLException if a database access error occurs
+     * @since 1.4
+     */
+    int getParameterMode(int param) throws SQLException;
+}
diff --git a/java/sql/PreparedStatement.java b/java/sql/PreparedStatement.java
new file mode 100644
index 0000000..ef57f69
--- /dev/null
+++ b/java/sql/PreparedStatement.java
@@ -0,0 +1,1227 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.io.Reader;
+import java.io.InputStream;
+
+/**
+ * An object that represents a precompiled SQL statement.
+ * <P>A SQL statement is precompiled and stored in a
+ * <code>PreparedStatement</code> object. This object can then be used to
+ * efficiently execute this statement multiple times.
+ *
+ * <P><B>Note:</B> The setter methods (<code>setShort</code>, <code>setString</code>,
+ * and so on) for setting IN parameter values
+ * must specify types that are compatible with the defined SQL type of
+ * the input parameter. For instance, if the IN parameter has SQL type
+ * <code>INTEGER</code>, then the method <code>setInt</code> should be used.
+ *
+ * <p>If arbitrary parameter type conversions are required, the method
+ * <code>setObject</code> should be used with a target SQL type.
+ * <P>
+ * In the following example of setting a parameter, <code>con</code> represents
+ * an active connection:
+ * <PRE>
+ *   PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
+ *                                     SET SALARY = ? WHERE ID = ?");
+ *   pstmt.setBigDecimal(1, 153833.00)
+ *   pstmt.setInt(2, 110592)
+ * </PRE>
+ *
+ * @see Connection#prepareStatement
+ * @see ResultSet
+ */
+
+public interface PreparedStatement extends Statement {
+
+    /**
+     * Executes the SQL query in this <code>PreparedStatement</code> object
+     * and returns the <code>ResultSet</code> object generated by the query.
+     *
+     * @return a <code>ResultSet</code> object that contains the data produced by the
+     *         query; never <code>null</code>
+     * @exception SQLException if a database access error occurs;
+     * this method is called on a closed  <code>PreparedStatement</code> or the SQL
+     *            statement does not return a <code>ResultSet</code> object
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     */
+    ResultSet executeQuery() throws SQLException;
+
+    /**
+     * Executes the SQL statement in this <code>PreparedStatement</code> object,
+     * which must be an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
+     * <code>DELETE</code>; or an SQL statement that returns nothing,
+     * such as a DDL statement.
+     *
+     * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+     *         or (2) 0 for SQL statements that return nothing
+     * @exception SQLException if a database access error occurs;
+     * this method is called on a closed  <code>PreparedStatement</code>
+     * or the SQL statement returns a <code>ResultSet</code> object
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     */
+    int executeUpdate() throws SQLException;
+
+    /**
+     * Sets the designated parameter to SQL <code>NULL</code>.
+     *
+     * <P><B>Note:</B> You must specify the parameter's SQL type.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param sqlType the SQL type code defined in <code>java.sql.Types</code>
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     */
+    void setNull(int parameterIndex, int sqlType) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>boolean</code> value.
+     * The driver converts this
+     * to an SQL <code>BIT</code> or <code>BOOLEAN</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement;
+     * if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setBoolean(int parameterIndex, boolean x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>byte</code> value.
+     * The driver converts this
+     * to an SQL <code>TINYINT</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setByte(int parameterIndex, byte x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>short</code> value.
+     * The driver converts this
+     * to an SQL <code>SMALLINT</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setShort(int parameterIndex, short x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>int</code> value.
+     * The driver converts this
+     * to an SQL <code>INTEGER</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setInt(int parameterIndex, int x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>long</code> value.
+     * The driver converts this
+     * to an SQL <code>BIGINT</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setLong(int parameterIndex, long x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>float</code> value.
+     * The driver converts this
+     * to an SQL <code>REAL</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setFloat(int parameterIndex, float x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>double</code> value.
+     * The driver converts this
+     * to an SQL <code>DOUBLE</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setDouble(int parameterIndex, double x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.math.BigDecimal</code> value.
+     * The driver converts this to an SQL <code>NUMERIC</code> value when
+     * it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java <code>String</code> value.
+     * The driver converts this
+     * to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value
+     * (depending on the argument's
+     * size relative to the driver's limits on <code>VARCHAR</code> values)
+     * when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setString(int parameterIndex, String x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given Java array of bytes.  The driver converts
+     * this to an SQL <code>VARBINARY</code> or <code>LONGVARBINARY</code>
+     * (depending on the argument's size relative to the driver's limits on
+     * <code>VARBINARY</code> values) when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setBytes(int parameterIndex, byte x[]) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Date</code> value
+     * using the default time zone of the virtual machine that is running
+     * the application.
+     * The driver converts this
+     * to an SQL <code>DATE</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setDate(int parameterIndex, java.sql.Date x)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Time</code> value.
+     * The driver converts this
+     * to an SQL <code>TIME</code> value when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setTime(int parameterIndex, java.sql.Time x)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value.
+     * The driver
+     * converts this to an SQL <code>TIMESTAMP</code> value when it sends it to the
+     * database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>     */
+    void setTimestamp(int parameterIndex, java.sql.Timestamp x)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from ASCII to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setAsciiStream(int parameterIndex, java.io.InputStream x, int length)
+            throws SQLException;
+
+    // Android-changed: Added reason to @deprecated to improve the documentation.
+    /**
+     * Sets the designated parameter to the given input stream, which
+     * will have the specified number of bytes.
+     *
+     * When a very large Unicode value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the
+     * stream as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from Unicode to the database char format.
+     *
+     *The byte format of the Unicode stream must be a Java UTF-8, as defined in the
+     *Java Virtual Machine Specification.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x a <code>java.io.InputStream</code> object that contains the
+     *        Unicode parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @deprecated Use setCharacterStream
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    void setUnicodeStream(int parameterIndex, java.io.InputStream x,
+                          int length) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the
+     * stream as needed until end-of-file is reached.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the java input stream which contains the binary parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void setBinaryStream(int parameterIndex, java.io.InputStream x,
+                         int length) throws SQLException;
+
+    /**
+     * Clears the current parameter values immediately.
+     * <P>In general, parameter values remain in force for repeated use of a
+     * statement. Setting a parameter value automatically clears its
+     * previous value.  However, in some cases it is useful to immediately
+     * release the resources used by the current parameter values; this can
+     * be done by calling the method <code>clearParameters</code>.
+     *
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     */
+    void clearParameters() throws SQLException;
+
+    //----------------------------------------------------------------------
+    // Advanced features:
+
+   /**
+    * Sets the value of the designated parameter with the given object.
+    * This method is like the method <code>setObject</code>
+    * above, except that it assumes a scale of zero.
+    *
+    * @param parameterIndex the first parameter is 1, the second is 2, ...
+    * @param x the object containing the input parameter value
+    * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
+    *                      sent to the database
+    * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+    * this method is called on a closed <code>PreparedStatement</code>
+    * @exception SQLFeatureNotSupportedException if <code>targetSqlType</code> is
+    * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+    * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+    * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+    *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+    * or  <code>STRUCT</code> data type and the JDBC driver does not support
+    * this data type
+    * @see Types
+    */
+    void setObject(int parameterIndex, Object x, int targetSqlType)
+      throws SQLException;
+
+    /**
+     * <p>Sets the value of the designated parameter using the given object.
+     * The second parameter must be of type <code>Object</code>; therefore, the
+     * <code>java.lang</code> equivalent objects should be used for built-in types.
+     *
+     * <p>The JDBC specification specifies a standard mapping from
+     * Java <code>Object</code> types to SQL types.  The given argument
+     * will be converted to the corresponding SQL type before being
+     * sent to the database.
+     *
+     * <p>Note that this method may be used to pass datatabase-
+     * specific abstract data types, by using a driver-specific Java
+     * type.
+     *
+     * If the object is of a class implementing the interface <code>SQLData</code>,
+     * the JDBC driver should call the method <code>SQLData.writeSQL</code>
+     * to write it to the SQL data stream.
+     * If, on the other hand, the object is of a class implementing
+     * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>,  <code>NClob</code>,
+     *  <code>Struct</code>, <code>java.net.URL</code>, <code>RowId</code>, <code>SQLXML</code>
+     * or <code>Array</code>, the driver should pass it to the database as a
+     * value of the corresponding SQL type.
+     * <P>
+     *<b>Note:</b> Not all databases allow for a non-typed Null to be sent to
+     * the backend. For maximum portability, the <code>setNull</code> or the
+     * <code>setObject(int parameterIndex, Object x, int sqlType)</code>
+     * method should be used
+     * instead of <code>setObject(int parameterIndex, Object x)</code>.
+     *<p>
+     * <b>Note:</b> This method throws an exception if there is an ambiguity, for example, if the
+     * object is of a class implementing more than one of the interfaces named above.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the object containing the input parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs;
+     *  this method is called on a closed <code>PreparedStatement</code>
+     * or the type of the given object is ambiguous
+     */
+    void setObject(int parameterIndex, Object x) throws SQLException;
+
+    /**
+     * Executes the SQL statement in this <code>PreparedStatement</code> object,
+     * which may be any kind of SQL statement.
+     * Some prepared statements return multiple results; the <code>execute</code>
+     * method handles these complex statements as well as the simpler
+     * form of statements handled by the methods <code>executeQuery</code>
+     * and <code>executeUpdate</code>.
+     * <P>
+     * The <code>execute</code> method returns a <code>boolean</code> to
+     * indicate the form of the first result.  You must call either the method
+     * <code>getResultSet</code> or <code>getUpdateCount</code>
+     * to retrieve the result; you must call <code>getMoreResults</code> to
+     * move to any subsequent result(s).
+     *
+     * @return <code>true</code> if the first result is a <code>ResultSet</code>
+     *         object; <code>false</code> if the first result is an update
+     *         count or there is no result
+     * @exception SQLException if a database access error occurs;
+     * this method is called on a closed <code>PreparedStatement</code>
+     * or an argument is supplied to this method
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @see Statement#execute
+     * @see Statement#getResultSet
+     * @see Statement#getUpdateCount
+     * @see Statement#getMoreResults
+
+     */
+    boolean execute() throws SQLException;
+
+    //--------------------------JDBC 2.0-----------------------------
+
+    /**
+     * Adds a set of parameters to this <code>PreparedStatement</code>
+     * object's batch of commands.
+     *
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @see Statement#addBatch
+     * @since 1.2
+     */
+    void addBatch() throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param reader the <code>java.io.Reader</code> object that contains the
+     *        Unicode data
+     * @param length the number of characters in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.2
+     */
+    void setCharacterStream(int parameterIndex,
+                          java.io.Reader reader,
+                          int length) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given
+     *  <code>REF(&lt;structured-type&gt;)</code> value.
+     * The driver converts this to an SQL <code>REF</code> value when it
+     * sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x an SQL <code>REF</code> value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.2
+     */
+    void setRef (int parameterIndex, Ref x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Blob</code> object.
+     * The driver converts this to an SQL <code>BLOB</code> value when it
+     * sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x a <code>Blob</code> object that maps an SQL <code>BLOB</code> value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.2
+     */
+    void setBlob (int parameterIndex, Blob x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Clob</code> object.
+     * The driver converts this to an SQL <code>CLOB</code> value when it
+     * sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x a <code>Clob</code> object that maps an SQL <code>CLOB</code> value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.2
+     */
+    void setClob (int parameterIndex, Clob x) throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Array</code> object.
+     * The driver converts this to an SQL <code>ARRAY</code> value when it
+     * sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x an <code>Array</code> object that maps an SQL <code>ARRAY</code> value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.2
+     */
+    void setArray (int parameterIndex, Array x) throws SQLException;
+
+    /**
+     * Retrieves a <code>ResultSetMetaData</code> object that contains
+     * information about the columns of the <code>ResultSet</code> object
+     * that will be returned when this <code>PreparedStatement</code> object
+     * is executed.
+     * <P>
+     * Because a <code>PreparedStatement</code> object is precompiled, it is
+     * possible to know about the <code>ResultSet</code> object that it will
+     * return without having to execute it.  Consequently, it is possible
+     * to invoke the method <code>getMetaData</code> on a
+     * <code>PreparedStatement</code> object rather than waiting to execute
+     * it and then invoking the <code>ResultSet.getMetaData</code> method
+     * on the <code>ResultSet</code> object that is returned.
+     * <P>
+     * <B>NOTE:</B> Using this method may be expensive for some drivers due
+     * to the lack of underlying DBMS support.
+     *
+     * @return the description of a <code>ResultSet</code> object's columns or
+     *         <code>null</code> if the driver cannot return a
+     *         <code>ResultSetMetaData</code> object
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    ResultSetMetaData getMetaData() throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Date</code> value,
+     * using the given <code>Calendar</code> object.  The driver uses
+     * the <code>Calendar</code> object to construct an SQL <code>DATE</code> value,
+     * which the driver then sends to the database.  With
+     * a <code>Calendar</code> object, the driver can calculate the date
+     * taking into account a custom timezone.  If no
+     * <code>Calendar</code> object is specified, the driver uses the default
+     * timezone, which is that of the virtual machine running the application.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the date
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.2
+     */
+    void setDate(int parameterIndex, java.sql.Date x, Calendar cal)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Time</code> value,
+     * using the given <code>Calendar</code> object.  The driver uses
+     * the <code>Calendar</code> object to construct an SQL <code>TIME</code> value,
+     * which the driver then sends to the database.  With
+     * a <code>Calendar</code> object, the driver can calculate the time
+     * taking into account a custom timezone.  If no
+     * <code>Calendar</code> object is specified, the driver uses the default
+     * timezone, which is that of the virtual machine running the application.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the time
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.2
+     */
+    void setTime(int parameterIndex, java.sql.Time x, Calendar cal)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.Timestamp</code> value,
+     * using the given <code>Calendar</code> object.  The driver uses
+     * the <code>Calendar</code> object to construct an SQL <code>TIMESTAMP</code> value,
+     * which the driver then sends to the database.  With a
+     *  <code>Calendar</code> object, the driver can calculate the timestamp
+     * taking into account a custom timezone.  If no
+     * <code>Calendar</code> object is specified, the driver uses the default
+     * timezone, which is that of the virtual machine running the application.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @param cal the <code>Calendar</code> object the driver will use
+     *            to construct the timestamp
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.2
+     */
+    void setTimestamp(int parameterIndex, java.sql.Timestamp x, Calendar cal)
+            throws SQLException;
+
+    /**
+     * Sets the designated parameter to SQL <code>NULL</code>.
+     * This version of the method <code>setNull</code> should
+     * be used for user-defined types and REF type parameters.  Examples
+     * of user-defined types include: STRUCT, DISTINCT, JAVA_OBJECT, and
+     * named array types.
+     *
+     * <P><B>Note:</B> To be portable, applications must give the
+     * SQL type code and the fully-qualified SQL type name when specifying
+     * a NULL user-defined or REF parameter.  In the case of a user-defined type
+     * the name is the type name of the parameter itself.  For a REF
+     * parameter, the name is the type name of the referenced type.  If
+     * a JDBC driver does not need the type code or type name information,
+     * it may ignore it.
+     *
+     * Although it is intended for user-defined and Ref parameters,
+     * this method may be used to set a null parameter of any JDBC type.
+     * If the parameter does not have a user-defined or REF type, the given
+     * typeName is ignored.
+     *
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param sqlType a value from <code>java.sql.Types</code>
+     * @param typeName the fully-qualified name of an SQL user-defined type;
+     *  ignored if the parameter is not a user-defined type or REF
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @exception SQLFeatureNotSupportedException if <code>sqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type or if the JDBC driver does not support this method
+     * @since 1.2
+     */
+  void setNull (int parameterIndex, int sqlType, String typeName)
+    throws SQLException;
+
+    //------------------------- JDBC 3.0 -----------------------------------
+
+    /**
+     * Sets the designated parameter to the given <code>java.net.URL</code> value.
+     * The driver converts this to an SQL <code>DATALINK</code> value
+     * when it sends it to the database.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the <code>java.net.URL</code> object to be set
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.4
+     */
+    void setURL(int parameterIndex, java.net.URL x) throws SQLException;
+
+    /**
+     * Retrieves the number, types and properties of this
+     * <code>PreparedStatement</code> object's parameters.
+     *
+     * @return a <code>ParameterMetaData</code> object that contains information
+     *         about the number, types and properties for each
+     *  parameter marker of this <code>PreparedStatement</code> object
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @see ParameterMetaData
+     * @since 1.4
+     */
+    ParameterMetaData getParameterMetaData() throws SQLException;
+
+    //------------------------- JDBC 4.0 -----------------------------------
+
+    /**
+     * Sets the designated parameter to the given <code>java.sql.RowId</code> object. The
+     * driver converts this to a SQL <code>ROWID</code> value when it sends it
+     * to the database
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the parameter value
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+    void setRowId(int parameterIndex, RowId x) throws SQLException;
+
+
+    /**
+     * Sets the designated paramter to the given <code>String</code> object.
+     * The driver converts this to a SQL <code>NCHAR</code> or
+     * <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
+     * (depending on the argument's
+     * size relative to the driver's limits on <code>NVARCHAR</code> values)
+     * when it sends it to the database.
+     *
+     * @param parameterIndex of the first parameter is 1, the second is 2, ...
+     * @param value the parameter value
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs; or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setNString(int parameterIndex, String value) throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object. The
+     * <code>Reader</code> reads the data till end-of-file is reached. The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+     * @param parameterIndex of the first parameter is 1, the second is 2, ...
+     * @param value the parameter value
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs; or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>java.sql.NClob</code> object. The driver converts this to a
+     * SQL <code>NCLOB</code> value when it sends it to the database.
+     * @param parameterIndex of the first parameter is 1, the second is 2, ...
+     * @param value the parameter value
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs; or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setNClob(int parameterIndex, NClob value) throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.  The reader must contain  the number
+     * of characters specified by length otherwise a <code>SQLException</code> will be
+     * generated when the <code>PreparedStatement</code> is executed.
+     *This method differs from the <code>setCharacterStream (int, Reader, int)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>CLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>
+     * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs; this method is called on
+     * a closed <code>PreparedStatement</code> or if the length specified is less than zero.
+     *
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setClob(int parameterIndex, Reader reader, long length)
+       throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>InputStream</code> object.  The inputstream must contain  the number
+     * of characters specified by length otherwise a <code>SQLException</code> will be
+     * generated when the <code>PreparedStatement</code> is executed.
+     * This method differs from the <code>setBinaryStream (int, InputStream, int)</code>
+     * method because it informs the driver that the parameter value should be
+     * sent to the server as a <code>BLOB</code>.  When the <code>setBinaryStream</code> method is used,
+     * the driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
+     * @param parameterIndex index of the first parameter is 1,
+     * the second is 2, ...
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @param length the number of bytes in the parameter data.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs;
+     * this method is called on a closed <code>PreparedStatement</code>;
+     *  if the length specified
+     * is less than zero or if the number of bytes in the inputstream does not match
+     * the specfied length.
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+     void setBlob(int parameterIndex, InputStream inputStream, long length)
+        throws SQLException;
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.  The reader must contain  the number
+     * of characters specified by length otherwise a <code>SQLException</code> will be
+     * generated when the <code>PreparedStatement</code> is executed.
+     * This method differs from the <code>setCharacterStream (int, Reader, int)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>NCLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGNVARCHAR</code> or a <code>NCLOB</code>
+     * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if the length specified is less than zero;
+     * if the driver does not support national character sets;
+     * if the driver can detect that a data conversion
+     *  error could occur;  if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+     void setNClob(int parameterIndex, Reader reader, long length)
+       throws SQLException;
+
+     /**
+      * Sets the designated parameter to the given <code>java.sql.SQLXML</code> object.
+      * The driver converts this to an
+      * SQL <code>XML</code> value when it sends it to the database.
+      * <p>
+      *
+      * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+      * @param xmlObject a <code>SQLXML</code> object that maps an SQL <code>XML</code> value
+      * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs;
+      *  this method is called on a closed <code>PreparedStatement</code>
+      * or the <code>java.xml.transform.Result</code>,
+      *  <code>Writer</code> or <code>OutputStream</code> has not been closed for
+      * the <code>SQLXML</code> object
+      * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+      *
+      * @since 1.6
+      */
+     void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException;
+
+    /**
+     * <p>Sets the value of the designated parameter with the given object. The second
+     * argument must be an object type; for integral values, the
+     * <code>java.lang</code> equivalent objects should be used.
+     *
+     * If the second argument is an <code>InputStream</code> then the stream must contain
+     * the number of bytes specified by scaleOrLength.  If the second argument is a
+     * <code>Reader</code> then the reader must contain the number of characters specified
+     * by scaleOrLength. If these conditions are not true the driver will generate a
+     * <code>SQLException</code> when the prepared statement is executed.
+     *
+     * <p>The given Java object will be converted to the given targetSqlType
+     * before being sent to the database.
+     *
+     * If the object has a custom mapping (is of a class implementing the
+     * interface <code>SQLData</code>),
+     * the JDBC driver should call the method <code>SQLData.writeSQL</code> to
+     * write it to the SQL data stream.
+     * If, on the other hand, the object is of a class implementing
+     * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>,  <code>NClob</code>,
+     *  <code>Struct</code>, <code>java.net.URL</code>,
+     * or <code>Array</code>, the driver should pass it to the database as a
+     * value of the corresponding SQL type.
+     *
+     * <p>Note that this method may be used to pass database-specific
+     * abstract data types.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the object containing the input parameter value
+     * @param targetSqlType the SQL type (as defined in java.sql.Types) to be
+     * sent to the database. The scale argument may further qualify this type.
+     * @param scaleOrLength for <code>java.sql.Types.DECIMAL</code>
+     *          or <code>java.sql.Types.NUMERIC types</code>,
+     *          this is the number of digits after the decimal point. For
+     *          Java Object types <code>InputStream</code> and <code>Reader</code>,
+     *          this is the length
+     *          of the data in the stream or reader.  For all other types,
+     *          this value will be ignored.
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs;
+     * this method is called on a closed <code>PreparedStatement</code> or
+     *            if the Java Object specified by x is an InputStream
+     *            or Reader object and the value of the scale parameter is less
+     *            than zero
+     * @exception SQLFeatureNotSupportedException if <code>targetSqlType</code> is
+     * a <code>ARRAY</code>, <code>BLOB</code>, <code>CLOB</code>,
+     * <code>DATALINK</code>, <code>JAVA_OBJECT</code>, <code>NCHAR</code>,
+     * <code>NCLOB</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>,
+     *  <code>REF</code>, <code>ROWID</code>, <code>SQLXML</code>
+     * or  <code>STRUCT</code> data type and the JDBC driver does not support
+     * this data type
+     * @see Types
+     *
+     * @since 1.6
+     */
+    void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
+            throws SQLException;
+   /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from ASCII to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.6
+    */
+    void setAsciiStream(int parameterIndex, java.io.InputStream x, long length)
+            throws SQLException;
+    /**
+     * Sets the designated parameter to the given input stream, which will have
+     * the specified number of bytes.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the
+     * stream as needed until end-of-file is reached.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the java input stream which contains the binary parameter value
+     * @param length the number of bytes in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.6
+     */
+    void setBinaryStream(int parameterIndex, java.io.InputStream x,
+                         long length) throws SQLException;
+        /**
+     * Sets the designated parameter to the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param reader the <code>java.io.Reader</code> object that contains the
+     *        Unicode data
+     * @param length the number of characters in the stream
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @since 1.6
+     */
+    void setCharacterStream(int parameterIndex,
+                          java.io.Reader reader,
+                          long length) throws SQLException;
+    //-----
+    /**
+     * Sets the designated parameter to the given input stream.
+     * When a very large ASCII value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code>. Data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from ASCII to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setAsciiStream</code> which takes a length parameter.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the Java input stream that contains the ASCII parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+       * @since 1.6
+    */
+    void setAsciiStream(int parameterIndex, java.io.InputStream x)
+            throws SQLException;
+    /**
+     * Sets the designated parameter to the given input stream.
+     * When a very large binary value is input to a <code>LONGVARBINARY</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.InputStream</code> object. The data will be read from the
+     * stream as needed until end-of-file is reached.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setBinaryStream</code> which takes a length parameter.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param x the java input stream which contains the binary parameter value
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+    void setBinaryStream(int parameterIndex, java.io.InputStream x)
+    throws SQLException;
+        /**
+     * Sets the designated parameter to the given <code>Reader</code>
+     * object.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The data will be read from the stream
+     * as needed until end-of-file is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setCharacterStream</code> which takes a length parameter.
+     *
+     * @param parameterIndex the first parameter is 1, the second is 2, ...
+     * @param reader the <code>java.io.Reader</code> object that contains the
+     *        Unicode data
+     * @exception SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+    void setCharacterStream(int parameterIndex,
+                          java.io.Reader reader) throws SQLException;
+  /**
+     * Sets the designated parameter to a <code>Reader</code> object. The
+     * <code>Reader</code> reads the data till end-of-file is reached. The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+
+     * <P><B>Note:</B> This stream object can either be a standard
+     * Java stream object or your own subclass that implements the
+     * standard interface.
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setNCharacterStream</code> which takes a length parameter.
+     *
+     * @param parameterIndex of the first parameter is 1, the second is 2, ...
+     * @param value the parameter value
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; if a database access error occurs; or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setNCharacterStream(int parameterIndex, Reader value) throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.
+     * This method differs from the <code>setCharacterStream (int, Reader)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>CLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGVARCHAR</code> or a <code>CLOB</code>
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setClob</code> which takes a length parameter.
+     *
+     * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs; this method is called on
+     * a closed <code>PreparedStatement</code>or if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement
+     *
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.6
+     */
+     void setClob(int parameterIndex, Reader reader)
+       throws SQLException;
+
+    /**
+     * Sets the designated parameter to a <code>InputStream</code> object.
+     * This method differs from the <code>setBinaryStream (int, InputStream)</code>
+     * method because it informs the driver that the parameter value should be
+     * sent to the server as a <code>BLOB</code>.  When the <code>setBinaryStream</code> method is used,
+     * the driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGVARBINARY</code> or a <code>BLOB</code>
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setBlob</code> which takes a length parameter.
+     *
+     * @param parameterIndex index of the first parameter is 1,
+     * the second is 2, ...
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement; if a database access error occurs;
+     * this method is called on a closed <code>PreparedStatement</code> or
+     * if parameterIndex does not correspond
+     * to a parameter marker in the SQL statement,
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+     void setBlob(int parameterIndex, InputStream inputStream)
+        throws SQLException;
+    /**
+     * Sets the designated parameter to a <code>Reader</code> object.
+     * This method differs from the <code>setCharacterStream (int, Reader)</code> method
+     * because it informs the driver that the parameter value should be sent to
+     * the server as a <code>NCLOB</code>.  When the <code>setCharacterStream</code> method is used, the
+     * driver may have to do extra work to determine whether the parameter
+     * data should be sent to the server as a <code>LONGNVARCHAR</code> or a <code>NCLOB</code>
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>setNClob</code> which takes a length parameter.
+     *
+     * @param parameterIndex index of the first parameter is 1, the second is 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @throws SQLException if parameterIndex does not correspond to a parameter
+     * marker in the SQL statement;
+     * if the driver does not support national character sets;
+     * if the driver can detect that a data conversion
+     *  error could occur;  if a database access error occurs or
+     * this method is called on a closed <code>PreparedStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     *
+     * @since 1.6
+     */
+     void setNClob(int parameterIndex, Reader reader)
+       throws SQLException;
+
+
+}
diff --git a/java/sql/Ref.java b/java/sql/Ref.java
new file mode 100644
index 0000000..5918dd9
--- /dev/null
+++ b/java/sql/Ref.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The mapping in the Java programming language of an SQL <code>REF</code>
+ * value, which is a reference to an SQL structured type value in the database.
+ * <P>
+ * SQL <code>REF</code> values are stored in a table that contains
+ * instances of a referenceable SQL structured type, and each <code>REF</code>
+ * value is a unique identifier for one instance in that table.
+ * An SQL <code>REF</code> value may be used in place of the
+ * SQL structured type it references, either as a column value in a
+ * table or an attribute value in a structured type.
+ * <P>
+ * Because an SQL <code>REF</code> value is a logical pointer to an
+ * SQL structured type, a <code>Ref</code> object is by default also a logical
+ * pointer. Thus, retrieving an SQL <code>REF</code> value as
+ * a <code>Ref</code> object does not materialize
+ * the attributes of the structured type on the client.
+ * <P>
+ * A <code>Ref</code> object can be stored in the database using the
+ * <code>PreparedStatement.setRef</code> method.
+  * <p>
+ * All methods on the <code>Ref</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @see Struct
+ * @since 1.2
+ */
+public interface Ref {
+
+    /**
+     * Retrieves the fully-qualified SQL name of the SQL structured type that
+     * this <code>Ref</code> object references.
+     *
+     * @return the fully-qualified SQL name of the referenced SQL structured type
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    String getBaseTypeName() throws SQLException;
+
+    /**
+     * Retrieves the referenced object and maps it to a Java type
+     * using the given type map.
+     *
+     * @param map a <code>java.util.Map</code> object that contains
+     *        the mapping to use (the fully-qualified name of the SQL
+     *        structured type being referenced and the class object for
+     *        <code>SQLData</code> implementation to which the SQL
+     *        structured type will be mapped)
+     * @return  a Java <code>Object</code> that is the custom mapping for
+     *          the SQL structured type to which this <code>Ref</code>
+     *          object refers
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     * @see #setObject
+     */
+    Object getObject(java.util.Map<String,Class<?>> map) throws SQLException;
+
+
+    /**
+     * Retrieves the SQL structured type instance referenced by
+     * this <code>Ref</code> object.  If the connection's type map has an entry
+     * for the structured type, the instance will be custom mapped to
+     * the Java class indicated in the type map.  Otherwise, the
+     * structured type instance will be mapped to a <code>Struct</code> object.
+     *
+     * @return  a Java <code>Object</code> that is the mapping for
+     *          the SQL structured type to which this <code>Ref</code>
+     *          object refers
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     * @see #setObject
+     */
+    Object getObject() throws SQLException;
+
+    /**
+     * Sets the structured type value that this <code>Ref</code>
+     * object references to the given instance of <code>Object</code>.
+     * The driver converts this to an SQL structured type when it
+     * sends it to the database.
+     *
+     * @param value an <code>Object</code> representing the SQL
+     *        structured type instance that this
+     *        <code>Ref</code> object will reference
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     * @see #getObject()
+     * @see #getObject(Map)
+     * @see PreparedStatement#setObject(int, Object)
+     * @see CallableStatement#setObject(String, Object)
+     */
+    void setObject(Object value) throws SQLException;
+
+}
diff --git a/java/sql/ResultSet.java b/java/sql/ResultSet.java
new file mode 100644
index 0000000..f9ca407
--- /dev/null
+++ b/java/sql/ResultSet.java
@@ -0,0 +1,4093 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.io.Reader;
+import java.io.InputStream;
+
+/**
+ * A table of data representing a database result set, which
+ * is usually generated by executing a statement that queries the database.
+ *
+ * <P>A <code>ResultSet</code> object  maintains a cursor pointing
+ * to its current row of data.  Initially the cursor is positioned
+ * before the first row. The <code>next</code> method moves the
+ * cursor to the next row, and because it returns <code>false</code>
+ * when there are no more rows in the <code>ResultSet</code> object,
+ * it can be used in a <code>while</code> loop to iterate through
+ * the result set.
+ * <P>
+ * A default <code>ResultSet</code> object is not updatable and
+ * has a cursor that moves forward only.  Thus, you can
+ * iterate through it only once and only from the first row to the
+ * last row. It is possible to
+ * produce <code>ResultSet</code> objects that are scrollable and/or
+ * updatable.  The following code fragment, in which <code>con</code>
+ * is a valid <code>Connection</code> object, illustrates how to make
+ * a result set that is scrollable and insensitive to updates by others, and
+ * that is updatable. See <code>ResultSet</code> fields for other
+ * options.
+ * <PRE>
+ *
+ *       Statement stmt = con.createStatement(
+ *                                      ResultSet.TYPE_SCROLL_INSENSITIVE,
+ *                                      ResultSet.CONCUR_UPDATABLE);
+ *       ResultSet rs = stmt.executeQuery("SELECT a, b FROM TABLE2");
+ *       // rs will be scrollable, will not show changes made by others,
+ *       // and will be updatable
+ *
+ * </PRE>
+ * The <code>ResultSet</code> interface provides
+ * <i>getter</i> methods (<code>getBoolean</code>, <code>getLong</code>, and so on)
+ * for retrieving column values from the current row.
+ * Values can be retrieved using either the index number of the
+ * column or the name of the column.  In general, using the
+ * column index will be more efficient.  Columns are numbered from 1.
+ * For maximum portability, result set columns within each row should be
+ * read in left-to-right order, and each column should be read only once.
+ *
+ * <P>For the getter methods, a JDBC driver attempts
+ * to convert the underlying data to the Java type specified in the
+ * getter method and returns a suitable Java value.  The JDBC specification
+ * has a table showing the allowable mappings from SQL types to Java types
+ * that can be used by the <code>ResultSet</code> getter methods.
+ * <P>
+ * <P>Column names used as input to getter methods are case
+ * insensitive.  When a getter method is called  with
+ * a column name and several columns have the same name,
+ * the value of the first matching column will be returned.
+ * The column name option is
+ * designed to be used when column names are used in the SQL
+ * query that generated the result set.
+ * For columns that are NOT explicitly named in the query, it
+ * is best to use column numbers. If column names are used, the
+ * programmer should take care to guarantee that they uniquely refer to
+ * the intended columns, which can be assured with the SQL <i>AS</i> clause.
+ * <P>
+ * A set of updater methods were added to this interface
+ * in the JDBC 2.0 API (Java<sup><font size=-2>TM</font></sup> 2 SDK,
+ * Standard Edition, version 1.2). The comments regarding parameters
+ * to the getter methods also apply to parameters to the
+ * updater methods.
+ *<P>
+ * The updater methods may be used in two ways:
+ * <ol>
+ * <LI>to update a column value in the current row.  In a scrollable
+ *     <code>ResultSet</code> object, the cursor can be moved backwards
+ *     and forwards, to an absolute position, or to a position
+ *     relative to the current row.
+ *     The following code fragment updates the <code>NAME</code> column
+ *     in the fifth row of the <code>ResultSet</code> object
+ *     <code>rs</code> and then uses the method <code>updateRow</code>
+ *     to update the data source table from which <code>rs</code> was derived.
+ * <PRE>
+ *
+ *       rs.absolute(5); // moves the cursor to the fifth row of rs
+ *       rs.updateString("NAME", "AINSWORTH"); // updates the
+ *          // <code>NAME</code> column of row 5 to be <code>AINSWORTH</code>
+ *       rs.updateRow(); // updates the row in the data source
+ *
+ * </PRE>
+ * <LI>to insert column values into the insert row.  An updatable
+ *     <code>ResultSet</code> object has a special row associated with
+ *     it that serves as a staging area for building a row to be inserted.
+ *     The following code fragment moves the cursor to the insert row, builds
+ *     a three-column row, and inserts it into <code>rs</code> and into
+ *     the data source table using the method <code>insertRow</code>.
+ * <PRE>
+ *
+ *       rs.moveToInsertRow(); // moves cursor to the insert row
+ *       rs.updateString(1, "AINSWORTH"); // updates the
+ *          // first column of the insert row to be <code>AINSWORTH</code>
+ *       rs.updateInt(2,35); // updates the second column to be <code>35</code>
+ *       rs.updateBoolean(3, true); // updates the third column to <code>true</code>
+ *       rs.insertRow();
+ *       rs.moveToCurrentRow();
+ *
+ * </PRE>
+ * </ol>
+ * <P>A <code>ResultSet</code> object is automatically closed when the
+ * <code>Statement</code> object that
+ * generated it is closed, re-executed, or used
+ * to retrieve the next result from a sequence of multiple results.
+ *
+ * <P>The number, types and properties of a <code>ResultSet</code>
+ * object's columns are provided by the <code>ResultSetMetaData</code>
+ * object returned by the <code>ResultSet.getMetaData</code> method.
+ *
+ * @see Statement#executeQuery
+ * @see Statement#getResultSet
+ * @see ResultSetMetaData
+ */
+
+public interface ResultSet extends Wrapper, AutoCloseable {
+
+    /**
+     * Moves the cursor froward one row from its current position.
+     * A <code>ResultSet</code> cursor is initially positioned
+     * before the first row; the first call to the method
+     * <code>next</code> makes the first row the current row; the
+     * second call makes the second row the current row, and so on.
+     * <p>
+     * When a call to the <code>next</code> method returns <code>false</code>,
+     * the cursor is positioned after the last row. Any
+     * invocation of a <code>ResultSet</code> method which requires a
+     * current row will result in a <code>SQLException</code> being thrown.
+     *  If the result set type is <code>TYPE_FORWARD_ONLY</code>, it is vendor specified
+     * whether their JDBC driver implementation will return <code>false</code> or
+     *  throw an <code>SQLException</code> on a
+     * subsequent call to <code>next</code>.
+     *
+     * <P>If an input stream is open for the current row, a call
+     * to the method <code>next</code> will
+     * implicitly close it. A <code>ResultSet</code> object's
+     * warning chain is cleared when a new row is read.
+     *
+     * @return <code>true</code> if the new current row is valid;
+     * <code>false</code> if there are no more rows
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    boolean next() throws SQLException;
+
+
+    /**
+     * Releases this <code>ResultSet</code> object's database and
+     * JDBC resources immediately instead of waiting for
+     * this to happen when it is automatically closed.
+     *
+     * <P>The closing of a <code>ResultSet</code> object does <strong>not</strong> close the <code>Blob</code>,
+     * <code>Clob</code> or <code>NClob</code> objects created by the <code>ResultSet</code>. <code>Blob</code>,
+     * <code>Clob</code> or <code>NClob</code> objects remain valid for at least the duration of the
+     * transaction in which they are creataed, unless their <code>free</code> method is invoked.
+     *<p>
+     * When a <code>ResultSet</code> is closed, any <code>ResultSetMetaData</code>
+     * instances that were created by calling the  <code>getMetaData</code>
+     * method remain accessible.
+     *
+     * <P><B>Note:</B> A <code>ResultSet</code> object
+     * is automatically closed by the
+     * <code>Statement</code> object that generated it when
+     * that <code>Statement</code> object is closed,
+     * re-executed, or is used to retrieve the next result from a
+     * sequence of multiple results.
+     *<p>
+     * Calling the method <code>close</code> on a <code>ResultSet</code>
+     * object that is already closed is a no-op.
+     * <P>
+     * <p>
+     *
+     * @exception SQLException if a database access error occurs
+     */
+    void close() throws SQLException;
+
+    /**
+     * Reports whether
+     * the last column read had a value of SQL <code>NULL</code>.
+     * Note that you must first call one of the getter methods
+     * on a column to try to read its value and then call
+     * the method <code>wasNull</code> to see if the value read was
+     * SQL <code>NULL</code>.
+     *
+     * @return <code>true</code> if the last column value read was SQL
+     *         <code>NULL</code> and <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    boolean wasNull() throws SQLException;
+
+    // Methods for accessing results by column index
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>String</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    String getString(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>boolean</code> in the Java programming language.
+     *
+     * <P>If the designated column has a datatype of CHAR or VARCHAR
+     * and contains a "0" or has a datatype of BIT, TINYINT, SMALLINT, INTEGER or BIGINT
+     * and contains  a 0, a value of <code>false</code> is returned.  If the designated column has a datatype
+     * of CHAR or VARCHAR
+     * and contains a "1" or has a datatype of BIT, TINYINT, SMALLINT, INTEGER or BIGINT
+     * and contains  a 1, a value of <code>true</code> is returned.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>false</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    boolean getBoolean(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>byte</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    byte getByte(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>short</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    short getShort(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * an <code>int</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    int getInt(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>long</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    long getLong(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>float</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    float getFloat(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>double</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    double getDouble(int columnIndex) throws SQLException;
+
+    // Android-changed: Added reason to @deprecated to improve the documentation.
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.BigDecimal</code> in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param scale the number of digits to the right of the decimal point
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @deprecated Use {@code getBigDecimal(int columnIndex)}
+     *             or {@code getBigDecimal(String columnLabel)}
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>byte</code> array in the Java programming language.
+     * The bytes represent the raw values returned by the driver.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    byte[] getBytes(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.Date</code> object in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.sql.Date getDate(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.Time</code> object in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.sql.Time getTime(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.Timestamp</code> object in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.sql.Timestamp getTimestamp(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a stream of ASCII characters. The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code> values.
+     * The JDBC driver will
+     * do any necessary conversion from the database format into ASCII.
+     *
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.  Also, a
+     * stream may return <code>0</code> when the method
+     * <code>InputStream.available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a Java input stream that delivers the database column value
+     * as a stream of one-byte ASCII characters;
+     * if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.io.InputStream getAsciiStream(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * as a stream of two-byte 3 characters. The first byte is
+     * the high byte; the second byte is the low byte.
+     *
+     * The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code>values.  The
+     * JDBC driver will do any necessary conversion from the database
+     * format into Unicode.
+     *
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.
+     * Also, a stream may return <code>0</code> when the method
+     * <code>InputStream.available</code>
+     * is called, whether there is data available or not.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of two-byte Unicode characters;
+     *         if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code>
+     *
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @deprecated use <code>getCharacterStream</code> in place of
+     *              <code>getUnicodeStream</code>
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    java.io.InputStream getUnicodeStream(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a  stream of
+     * uninterpreted bytes. The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARBINARY</code> values.
+     *
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.  Also, a
+     * stream may return <code>0</code> when the method
+     * <code>InputStream.available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of uninterpreted bytes;
+     *         if the value is SQL <code>NULL</code>, the value returned is
+     *         <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.io.InputStream getBinaryStream(int columnIndex)
+        throws SQLException;
+
+
+    // Methods for accessing results by column label
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>String</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    String getString(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>boolean</code> in the Java programming language.
+     *
+     * <P>If the designated column has a datatype of CHAR or VARCHAR
+     * and contains a "0" or has a datatype of BIT, TINYINT, SMALLINT, INTEGER or BIGINT
+     * and contains  a 0, a value of <code>false</code> is returned.  If the designated column has a datatype
+     * of CHAR or VARCHAR
+     * and contains a "1" or has a datatype of BIT, TINYINT, SMALLINT, INTEGER or BIGINT
+     * and contains  a 1, a value of <code>true</code> is returned.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>false</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    boolean getBoolean(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>byte</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    byte getByte(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>short</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    short getShort(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * an <code>int</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    int getInt(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>long</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    long getLong(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>float</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    float getFloat(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>double</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>0</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    double getDouble(String columnLabel) throws SQLException;
+
+    // Android-changed: Added reason to @deprecated to improve the documentation.
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.math.BigDecimal</code> in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param scale the number of digits to the right of the decimal point
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @deprecated Use {@code getBigDecimal(int columnIndex)}
+     *             or {@code getBigDecimal(String columnLabel)}
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>byte</code> array in the Java programming language.
+     * The bytes represent the raw values returned by the driver.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    byte[] getBytes(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.Date</code> object in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.sql.Date getDate(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.Time</code> object in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.sql.Time getTime(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>java.sql.Timestamp</code> object in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.sql.Timestamp getTimestamp(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a stream of
+     * ASCII characters. The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code> values.
+     * The JDBC driver will
+     * do any necessary conversion from the database format into ASCII.
+     *
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream. Also, a
+     * stream may return <code>0</code> when the method <code>available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a Java input stream that delivers the database column value
+     * as a stream of one-byte ASCII characters.
+     * If the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code>.
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.io.InputStream getAsciiStream(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a stream of two-byte
+     * Unicode characters. The first byte is the high byte; the second
+     * byte is the low byte.
+     *
+     * The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARCHAR</code> values.
+     * The JDBC technology-enabled driver will
+     * do any necessary conversion from the database format into Unicode.
+     *
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream.
+     * Also, a stream may return <code>0</code> when the method
+     * <code>InputStream.available</code> is called, whether there
+     * is data available or not.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a Java input stream that delivers the database column value
+     *         as a stream of two-byte Unicode characters.
+     *         If the value is SQL <code>NULL</code>, the value returned
+     *         is <code>null</code>.
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @deprecated use <code>getCharacterStream</code> instead
+     */
+    // Android-added: @Deprecated annotation from OpenJDK8u121-b13 to fix build warnings.
+    @Deprecated
+    java.io.InputStream getUnicodeStream(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a stream of uninterpreted
+     * <code>byte</code>s.
+     * The value can then be read in chunks from the
+     * stream. This method is particularly
+     * suitable for retrieving large <code>LONGVARBINARY</code>
+     * values.
+     *
+     * <P><B>Note:</B> All the data in the returned stream must be
+     * read prior to getting the value of any other column. The next
+     * call to a getter method implicitly closes the stream. Also, a
+     * stream may return <code>0</code> when the method <code>available</code>
+     * is called whether there is data available or not.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a Java input stream that delivers the database column value
+     * as a stream of uninterpreted bytes;
+     * if the value is SQL <code>NULL</code>, the result is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    java.io.InputStream getBinaryStream(String columnLabel)
+        throws SQLException;
+
+
+    // Advanced features:
+
+    /**
+     * Retrieves the first warning reported by calls on this
+     * <code>ResultSet</code> object.
+     * Subsequent warnings on this <code>ResultSet</code> object
+     * will be chained to the <code>SQLWarning</code> object that
+     * this method returns.
+     *
+     * <P>The warning chain is automatically cleared each time a new
+     * row is read.  This method may not be called on a <code>ResultSet</code>
+     * object that has been closed; doing so will cause an
+     * <code>SQLException</code> to be thrown.
+     * <P>
+     * <B>Note:</B> This warning chain only covers warnings caused
+     * by <code>ResultSet</code> methods.  Any warning caused by
+     * <code>Statement</code> methods
+     * (such as reading OUT parameters) will be chained on the
+     * <code>Statement</code> object.
+     *
+     * @return the first <code>SQLWarning</code> object reported or
+     *         <code>null</code> if there are none
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    SQLWarning getWarnings() throws SQLException;
+
+    /**
+     * Clears all warnings reported on this <code>ResultSet</code> object.
+     * After this method is called, the method <code>getWarnings</code>
+     * returns <code>null</code> until a new warning is
+     * reported for this <code>ResultSet</code> object.
+     *
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    void clearWarnings() throws SQLException;
+
+    /**
+     * Retrieves the name of the SQL cursor used by this <code>ResultSet</code>
+     * object.
+     *
+     * <P>In SQL, a result table is retrieved through a cursor that is
+     * named. The current row of a result set can be updated or deleted
+     * using a positioned update/delete statement that references the
+     * cursor name. To insure that the cursor has the proper isolation
+     * level to support update, the cursor's <code>SELECT</code> statement
+     * should be of the form <code>SELECT FOR UPDATE</code>. If
+     * <code>FOR UPDATE</code> is omitted, the positioned updates may fail.
+     *
+     * <P>The JDBC API supports this SQL feature by providing the name of the
+     * SQL cursor used by a <code>ResultSet</code> object.
+     * The current row of a <code>ResultSet</code> object
+     * is also the current row of this SQL cursor.
+     *
+     * @return the SQL name for this <code>ResultSet</code> object's cursor
+     * @exception SQLException if a database access error occurs or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     */
+    String getCursorName() throws SQLException;
+
+    /**
+     * Retrieves the  number, types and properties of
+     * this <code>ResultSet</code> object's columns.
+     *
+     * @return the description of this <code>ResultSet</code> object's columns
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    ResultSetMetaData getMetaData() throws SQLException;
+
+    /**
+     * <p>Gets the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * an <code>Object</code> in the Java programming language.
+     *
+     * <p>This method will return the value of the given column as a
+     * Java object.  The type of the Java object will be the default
+     * Java object type corresponding to the column's SQL type,
+     * following the mapping for built-in types specified in the JDBC
+     * specification. If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     *
+     * <p>This method may also be used to read database-specific
+     * abstract data types.
+     *
+     * In the JDBC 2.0 API, the behavior of method
+     * <code>getObject</code> is extended to materialize
+     * data of SQL user-defined types.
+     * <p>
+     * If <code>Connection.getTypeMap</code> does not throw a
+     * <code>SQLFeatureNotSupportedException</code>,
+     * then when a column contains a structured or distinct value,
+     * the behavior of this method is as
+     * if it were a call to: <code>getObject(columnIndex,
+     * this.getStatement().getConnection().getTypeMap())</code>.
+     *
+     * If <code>Connection.getTypeMap</code> does throw a
+     * <code>SQLFeatureNotSupportedException</code>,
+     * then structured values are not supported, and distinct values
+     * are mapped to the default Java class as determined by the
+     * underlying SQL type of the DISTINCT type.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>java.lang.Object</code> holding the column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    Object getObject(int columnIndex) throws SQLException;
+
+    /**
+     * <p>Gets the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * an <code>Object</code> in the Java programming language.
+     *
+     * <p>This method will return the value of the given column as a
+     * Java object.  The type of the Java object will be the default
+     * Java object type corresponding to the column's SQL type,
+     * following the mapping for built-in types specified in the JDBC
+     * specification. If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * <P>
+     * This method may also be used to read database-specific
+     * abstract data types.
+     * <P>
+     * In the JDBC 2.0 API, the behavior of the method
+     * <code>getObject</code> is extended to materialize
+     * data of SQL user-defined types.  When a column contains
+     * a structured or distinct value, the behavior of this method is as
+     * if it were a call to: <code>getObject(columnIndex,
+     * this.getStatement().getConnection().getTypeMap())</code>.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>java.lang.Object</code> holding the column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     */
+    Object getObject(String columnLabel) throws SQLException;
+
+    //----------------------------------------------------------------
+
+    /**
+     * Maps the given <code>ResultSet</code> column label to its
+     * <code>ResultSet</code> column index.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column index of the given column name
+     * @exception SQLException if the <code>ResultSet</code> object
+     * does not contain a column labeled <code>columnLabel</code>, a database access error occurs
+     *  or this method is called on a closed result set
+     */
+    int findColumn(String columnLabel) throws SQLException;
+
+
+    //--------------------------JDBC 2.0-----------------------------------
+
+    //---------------------------------------------------------------------
+    // Getters and Setters
+    //---------------------------------------------------------------------
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a
+     * <code>java.io.Reader</code> object.
+     * @return a <code>java.io.Reader</code> object that contains the column
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language.
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @since 1.2
+     */
+    java.io.Reader getCharacterStream(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a
+     * <code>java.io.Reader</code> object.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>java.io.Reader</code> object that contains the column
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @since 1.2
+     */
+    java.io.Reader getCharacterStream(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a
+     * <code>java.math.BigDecimal</code> with full precision.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value (full precision);
+     * if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language.
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @since 1.2
+     */
+    BigDecimal getBigDecimal(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a
+     * <code>java.math.BigDecimal</code> with full precision.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value (full precision);
+     * if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language.
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs or this method is
+     *            called on a closed result set
+     * @since 1.2
+     *
+     */
+    BigDecimal getBigDecimal(String columnLabel) throws SQLException;
+
+    //---------------------------------------------------------------------
+    // Traversal/Positioning
+    //---------------------------------------------------------------------
+
+    /**
+     * Retrieves whether the cursor is before the first row in
+     * this <code>ResultSet</code> object.
+     * <p>
+     * <strong>Note:</strong>Support for the <code>isBeforeFirst</code> method
+     * is optional for <code>ResultSet</code>s with a result
+     * set type of <code>TYPE_FORWARD_ONLY</code>
+     *
+     * @return <code>true</code> if the cursor is before the first row;
+     * <code>false</code> if the cursor is at any other position or the
+     * result set contains no rows
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean isBeforeFirst() throws SQLException;
+
+    /**
+     * Retrieves whether the cursor is after the last row in
+     * this <code>ResultSet</code> object.
+     * <p>
+     * <strong>Note:</strong>Support for the <code>isAfterLast</code> method
+     * is optional for <code>ResultSet</code>s with a result
+     * set type of <code>TYPE_FORWARD_ONLY</code>
+     *
+     * @return <code>true</code> if the cursor is after the last row;
+     * <code>false</code> if the cursor is at any other position or the
+     * result set contains no rows
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean isAfterLast() throws SQLException;
+
+    /**
+     * Retrieves whether the cursor is on the first row of
+     * this <code>ResultSet</code> object.
+     * <p>
+     * <strong>Note:</strong>Support for the <code>isFirst</code> method
+     * is optional for <code>ResultSet</code>s with a result
+     * set type of <code>TYPE_FORWARD_ONLY</code>
+     *
+     * @return <code>true</code> if the cursor is on the first row;
+     * <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean isFirst() throws SQLException;
+
+    /**
+     * Retrieves whether the cursor is on the last row of
+     * this <code>ResultSet</code> object.
+     *  <strong>Note:</strong> Calling the method <code>isLast</code> may be expensive
+     * because the JDBC driver
+     * might need to fetch ahead one row in order to determine
+     * whether the current row is the last row in the result set.
+     * <p>
+     * <strong>Note:</strong> Support for the <code>isLast</code> method
+     * is optional for <code>ResultSet</code>s with a result
+     * set type of <code>TYPE_FORWARD_ONLY</code>
+     * @return <code>true</code> if the cursor is on the last row;
+     * <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs or this method is
+     *            called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean isLast() throws SQLException;
+
+    /**
+     * Moves the cursor to the front of
+     * this <code>ResultSet</code> object, just before the
+     * first row. This method has no effect if the result set contains no rows.
+     *
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set or the
+     * result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void beforeFirst() throws SQLException;
+
+    /**
+     * Moves the cursor to the end of
+     * this <code>ResultSet</code> object, just after the
+     * last row. This method has no effect if the result set contains no rows.
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set
+     * or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void afterLast() throws SQLException;
+
+    /**
+     * Moves the cursor to the first row in
+     * this <code>ResultSet</code> object.
+     *
+     * @return <code>true</code> if the cursor is on a valid row;
+     * <code>false</code> if there are no rows in the result set
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set
+     * or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean first() throws SQLException;
+
+    /**
+     * Moves the cursor to the last row in
+     * this <code>ResultSet</code> object.
+     *
+     * @return <code>true</code> if the cursor is on a valid row;
+     * <code>false</code> if there are no rows in the result set
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set
+     * or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean last() throws SQLException;
+
+    /**
+     * Retrieves the current row number.  The first row is number 1, the
+     * second number 2, and so on.
+     * <p>
+     * <strong>Note:</strong>Support for the <code>getRow</code> method
+     * is optional for <code>ResultSet</code>s with a result
+     * set type of <code>TYPE_FORWARD_ONLY</code>
+     *
+     * @return the current row number; <code>0</code> if there is no current row
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    int getRow() throws SQLException;
+
+    /**
+     * Moves the cursor to the given row number in
+     * this <code>ResultSet</code> object.
+     *
+     * <p>If the row number is positive, the cursor moves to
+     * the given row number with respect to the
+     * beginning of the result set.  The first row is row 1, the second
+     * is row 2, and so on.
+     *
+     * <p>If the given row number is negative, the cursor moves to
+     * an absolute row position with respect to
+     * the end of the result set.  For example, calling the method
+     * <code>absolute(-1)</code> positions the
+     * cursor on the last row; calling the method <code>absolute(-2)</code>
+     * moves the cursor to the next-to-last row, and so on.
+     *
+     * <p>If the row number specified is zero, the cursor is moved to
+     * before the first row.
+     *
+     * <p>An attempt to position the cursor beyond the first/last row in
+     * the result set leaves the cursor before the first row or after
+     * the last row.
+     *
+     * <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
+     * as calling <code>first()</code>. Calling <code>absolute(-1)</code>
+     * is the same as calling <code>last()</code>.
+     *
+     * @param row the number of the row to which the cursor should move.
+     *        A value of zero indicates that the cursor will be positioned
+     *        before the first row; a positive number indicates the row number
+     *        counting from the beginning of the result set; a negative number
+     *        indicates the row number counting from the end of the result set
+     * @return <code>true</code> if the cursor is moved to a position in this
+     * <code>ResultSet</code> object;
+     * <code>false</code> if the cursor is before the first row or after the
+     * last row
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set
+     * or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean absolute( int row ) throws SQLException;
+
+    /**
+     * Moves the cursor a relative number of rows, either positive or negative.
+     * Attempting to move beyond the first/last row in the
+     * result set positions the cursor before/after the
+     * the first/last row. Calling <code>relative(0)</code> is valid, but does
+     * not change the cursor position.
+     *
+     * <p>Note: Calling the method <code>relative(1)</code>
+     * is identical to calling the method <code>next()</code> and
+     * calling the method <code>relative(-1)</code> is identical
+     * to calling the method <code>previous()</code>.
+     *
+     * @param rows an <code>int</code> specifying the number of rows to
+     *        move from the current row; a positive number moves the cursor
+     *        forward; a negative number moves the cursor backward
+     * @return <code>true</code> if the cursor is on a row;
+     *         <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs;  this method
+     * is called on a closed result set or the result set type is
+     *            <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean relative( int rows ) throws SQLException;
+
+    /**
+     * Moves the cursor to the previous row in this
+     * <code>ResultSet</code> object.
+     *<p>
+     * When a call to the <code>previous</code> method returns <code>false</code>,
+     * the cursor is positioned before the first row.  Any invocation of a
+     * <code>ResultSet</code> method which requires a current row will result in a
+     * <code>SQLException</code> being thrown.
+     *<p>
+     * If an input stream is open for the current row, a call to the method
+     * <code>previous</code> will implicitly close it.  A <code>ResultSet</code>
+     *  object's warning change is cleared when a new row is read.
+     *<p>
+     *
+     * @return <code>true</code> if the cursor is now positioned on a valid row;
+     * <code>false</code> if the cursor is positioned before the first row
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set
+     * or the result set type is <code>TYPE_FORWARD_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean previous() throws SQLException;
+
+    //---------------------------------------------------------------------
+    // Properties
+    //---------------------------------------------------------------------
+
+    /**
+     * The constant indicating that the rows in a result set will be
+     * processed in a forward direction; first-to-last.
+     * This constant is used by the method <code>setFetchDirection</code>
+     * as a hint to the driver, which the driver may ignore.
+     * @since 1.2
+     */
+    int FETCH_FORWARD = 1000;
+
+    /**
+     * The constant indicating that the rows in a result set will be
+     * processed in a reverse direction; last-to-first.
+     * This constant is used by the method <code>setFetchDirection</code>
+     * as a hint to the driver, which the driver may ignore.
+     * @since 1.2
+     */
+    int FETCH_REVERSE = 1001;
+
+    /**
+     * The constant indicating that the order in which rows in a
+     * result set will be processed is unknown.
+     * This constant is used by the method <code>setFetchDirection</code>
+     * as a hint to the driver, which the driver may ignore.
+     */
+    int FETCH_UNKNOWN = 1002;
+
+    /**
+     * Gives a hint as to the direction in which the rows in this
+     * <code>ResultSet</code> object will be processed.
+     * The initial value is determined by the
+     * <code>Statement</code> object
+     * that produced this <code>ResultSet</code> object.
+     * The fetch direction may be changed at any time.
+     *
+     * @param direction an <code>int</code> specifying the suggested
+     *        fetch direction; one of <code>ResultSet.FETCH_FORWARD</code>,
+     *        <code>ResultSet.FETCH_REVERSE</code>, or
+     *        <code>ResultSet.FETCH_UNKNOWN</code>
+     * @exception SQLException if a database access error occurs; this
+     * method is called on a closed result set or
+     * the result set type is <code>TYPE_FORWARD_ONLY</code> and the fetch
+     * direction is not <code>FETCH_FORWARD</code>
+     * @since 1.2
+     * @see Statement#setFetchDirection
+     * @see #getFetchDirection
+     */
+    void setFetchDirection(int direction) throws SQLException;
+
+    /**
+     * Retrieves the fetch direction for this
+     * <code>ResultSet</code> object.
+     *
+     * @return the current fetch direction for this <code>ResultSet</code> object
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     * @see #setFetchDirection
+     */
+    int getFetchDirection() throws SQLException;
+
+    /**
+     * Gives the JDBC driver a hint as to the number of rows that should
+     * be fetched from the database when more rows are needed for this
+     * <code>ResultSet</code> object.
+     * If the fetch size specified is zero, the JDBC driver
+     * ignores the value and is free to make its own best guess as to what
+     * the fetch size should be.  The default value is set by the
+     * <code>Statement</code> object
+     * that created the result set.  The fetch size may be changed at any time.
+     *
+     * @param rows the number of rows to fetch
+     * @exception SQLException if a database access error occurs; this method
+     * is called on a closed result set or the
+     * condition <code>rows >= 0 </code> is not satisfied
+     * @since 1.2
+     * @see #getFetchSize
+     */
+    void setFetchSize(int rows) throws SQLException;
+
+    /**
+     * Retrieves the fetch size for this
+     * <code>ResultSet</code> object.
+     *
+     * @return the current fetch size for this <code>ResultSet</code> object
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     * @see #setFetchSize
+     */
+    int getFetchSize() throws SQLException;
+
+    /**
+     * The constant indicating the type for a <code>ResultSet</code> object
+     * whose cursor may move only forward.
+     * @since 1.2
+     */
+    int TYPE_FORWARD_ONLY = 1003;
+
+    /**
+     * The constant indicating the type for a <code>ResultSet</code> object
+     * that is scrollable but generally not sensitive to changes to the data
+     * that underlies the <code>ResultSet</code>.
+     * @since 1.2
+     */
+    int TYPE_SCROLL_INSENSITIVE = 1004;
+
+    /**
+     * The constant indicating the type for a <code>ResultSet</code> object
+     * that is scrollable and generally sensitive to changes to the data
+     * that underlies the <code>ResultSet</code>.
+     * @since 1.2
+     */
+    int TYPE_SCROLL_SENSITIVE = 1005;
+
+    /**
+     * Retrieves the type of this <code>ResultSet</code> object.
+     * The type is determined by the <code>Statement</code> object
+     * that created the result set.
+     *
+     * @return <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     *         <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>,
+     *         or <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    int getType() throws SQLException;
+
+    /**
+     * The constant indicating the concurrency mode for a
+     * <code>ResultSet</code> object that may NOT be updated.
+     * @since 1.2
+     */
+    int CONCUR_READ_ONLY = 1007;
+
+    /**
+     * The constant indicating the concurrency mode for a
+     * <code>ResultSet</code> object that may be updated.
+     * @since 1.2
+     */
+    int CONCUR_UPDATABLE = 1008;
+
+    /**
+     * Retrieves the concurrency mode of this <code>ResultSet</code> object.
+     * The concurrency used is determined by the
+     * <code>Statement</code> object that created the result set.
+     *
+     * @return the concurrency type, either
+     *         <code>ResultSet.CONCUR_READ_ONLY</code>
+     *         or <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    int getConcurrency() throws SQLException;
+
+    //---------------------------------------------------------------------
+    // Updates
+    //---------------------------------------------------------------------
+
+    /**
+     * Retrieves whether the current row has been updated.  The value returned
+     * depends on whether or not the result set can detect updates.
+     * <p>
+     * <strong>Note:</strong> Support for the <code>rowUpdated</code> method is optional with a result set
+     * concurrency of <code>CONCUR_READ_ONLY</code>
+     * @return <code>true</code> if the current row is detected to
+     * have been visibly updated by the owner or another; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @see DatabaseMetaData#updatesAreDetected
+     * @since 1.2
+     */
+    boolean rowUpdated() throws SQLException;
+
+    /**
+     * Retrieves whether the current row has had an insertion.
+     * The value returned depends on whether or not this
+     * <code>ResultSet</code> object can detect visible inserts.
+     * <p>
+     * <strong>Note:</strong> Support for the <code>rowInserted</code> method is optional with a result set
+     * concurrency of <code>CONCUR_READ_ONLY</code>
+     * @return <code>true</code> if the current row is detected to
+     * have been inserted; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @see DatabaseMetaData#insertsAreDetected
+     * @since 1.2
+     */
+    boolean rowInserted() throws SQLException;
+
+    /**
+     * Retrieves whether a row has been deleted.  A deleted row may leave
+     * a visible "hole" in a result set.  This method can be used to
+     * detect holes in a result set.  The value returned depends on whether
+     * or not this <code>ResultSet</code> object can detect deletions.
+     * <p>
+     * <strong>Note:</strong> Support for the <code>rowDeleted</code> method is optional with a result set
+     * concurrency of <code>CONCUR_READ_ONLY</code>
+     * @return <code>true</code> if the current row is detected to
+     * have been deleted by the owner or another; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     *
+     * @see DatabaseMetaData#deletesAreDetected
+     * @since 1.2
+     */
+    boolean rowDeleted() throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>null</code> value.
+     *
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code>
+     * or <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateNull(int columnIndex) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>boolean</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBoolean(int columnIndex, boolean x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>byte</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateByte(int columnIndex, byte x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>short</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateShort(int columnIndex, short x) throws SQLException;
+
+    /**
+     * Updates the designated column with an <code>int</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateInt(int columnIndex, int x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>long</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateLong(int columnIndex, long x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>float</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateFloat(int columnIndex, float x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>double</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateDouble(int columnIndex, double x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.math.BigDecimal</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>String</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateString(int columnIndex, String x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>byte</code> array value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBytes(int columnIndex, byte x[]) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Date</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateDate(int columnIndex, java.sql.Date x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Time</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateTime(int columnIndex, java.sql.Time x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Timestamp</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateTimestamp(int columnIndex, java.sql.Timestamp x)
+      throws SQLException;
+
+    /**
+     * Updates the designated column with an ascii stream value, which will have
+     * the specified number of bytes.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateAsciiStream(int columnIndex,
+                           java.io.InputStream x,
+                           int length) throws SQLException;
+
+    /**
+     * Updates the designated column with a binary stream value, which will have
+     * the specified number of bytes.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBinaryStream(int columnIndex,
+                            java.io.InputStream x,
+                            int length) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value, which will have
+     * the specified number of bytes.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateCharacterStream(int columnIndex,
+                             java.io.Reader x,
+                             int length) throws SQLException;
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *<p>
+     * If the second argument is an <code>InputStream</code> then the stream must contain
+     * the number of bytes specified by scaleOrLength.  If the second argument is a
+     * <code>Reader</code> then the reader must contain the number of characters specified
+     * by scaleOrLength. If these conditions are not true the driver will generate a
+     * <code>SQLException</code> when the statement is executed.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param scaleOrLength for an object of <code>java.math.BigDecimal</code> ,
+     *          this is the number of digits after the decimal point. For
+     *          Java Object types <code>InputStream</code> and <code>Reader</code>,
+     *          this is the length
+     *          of the data in the stream or reader.  For all other types,
+     *          this value will be ignored.
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateObject(int columnIndex, Object x, int scaleOrLength)
+      throws SQLException;
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateObject(int columnIndex, Object x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>null</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateNull(String columnLabel) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>boolean</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBoolean(String columnLabel, boolean x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>byte</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateByte(String columnLabel, byte x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>short</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateShort(String columnLabel, short x) throws SQLException;
+
+    /**
+     * Updates the designated column with an <code>int</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateInt(String columnLabel, int x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>long</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateLong(String columnLabel, long x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>float </code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateFloat(String columnLabel, float x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>double</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateDouble(String columnLabel, double x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.BigDecimal</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>String</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateString(String columnLabel, String x) throws SQLException;
+
+    /**
+     * Updates the designated column with a byte array value.
+     *
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code>
+     * or <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBytes(String columnLabel, byte x[]) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Date</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateDate(String columnLabel, java.sql.Date x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Time</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateTime(String columnLabel, java.sql.Time x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Timestamp</code>
+     * value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateTimestamp(String columnLabel, java.sql.Timestamp x)
+      throws SQLException;
+
+    /**
+     * Updates the designated column with an ascii stream value, which will have
+     * the specified number of bytes.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateAsciiStream(String columnLabel,
+                           java.io.InputStream x,
+                           int length) throws SQLException;
+
+    /**
+     * Updates the designated column with a binary stream value, which will have
+     * the specified number of bytes.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateBinaryStream(String columnLabel,
+                            java.io.InputStream x,
+                            int length) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value, which will have
+     * the specified number of bytes.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader the <code>java.io.Reader</code> object containing
+     *        the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateCharacterStream(String columnLabel,
+                             java.io.Reader reader,
+                             int length) throws SQLException;
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *<p>
+     * If the second argument is an <code>InputStream</code> then the stream must contain
+     * the number of bytes specified by scaleOrLength.  If the second argument is a
+     * <code>Reader</code> then the reader must contain the number of characters specified
+     * by scaleOrLength. If these conditions are not true the driver will generate a
+     * <code>SQLException</code> when the statement is executed.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @param scaleOrLength for an object of <code>java.math.BigDecimal</code> ,
+     *          this is the number of digits after the decimal point. For
+     *          Java Object types <code>InputStream</code> and <code>Reader</code>,
+     *          this is the length
+     *          of the data in the stream or reader.  For all other types,
+     *          this value will be ignored.
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateObject(String columnLabel, Object x, int scaleOrLength)
+      throws SQLException;
+
+    /**
+     * Updates the designated column with an <code>Object</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateObject(String columnLabel, Object x) throws SQLException;
+
+    /**
+     * Inserts the contents of the insert row into this
+     * <code>ResultSet</code> object and into the database.
+     * The cursor must be on the insert row when this method is called.
+     *
+     * @exception SQLException if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>,
+     * this method is called on a closed result set,
+     * if this method is called when the cursor is not on the insert row,
+     * or if not all of non-nullable columns in
+     * the insert row have been given a non-null value
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void insertRow() throws SQLException;
+
+    /**
+     * Updates the underlying database with the new contents of the
+     * current row of this <code>ResultSet</code> object.
+     * This method cannot be called when the cursor is on the insert row.
+     *
+     * @exception SQLException if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>;
+     *  this method is called on a closed result set or
+     * if this method is called when the cursor is on the insert row
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void updateRow() throws SQLException;
+
+    /**
+     * Deletes the current row from this <code>ResultSet</code> object
+     * and from the underlying database.  This method cannot be called when
+     * the cursor is on the insert row.
+     *
+     * @exception SQLException if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>;
+     * this method is called on a closed result set
+     * or if this method is called when the cursor is on the insert row
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void deleteRow() throws SQLException;
+
+    /**
+     * Refreshes the current row with its most recent value in
+     * the database.  This method cannot be called when
+     * the cursor is on the insert row.
+     *
+     * <P>The <code>refreshRow</code> method provides a way for an
+     * application to
+     * explicitly tell the JDBC driver to refetch a row(s) from the
+     * database.  An application may want to call <code>refreshRow</code> when
+     * caching or prefetching is being done by the JDBC driver to
+     * fetch the latest value of a row from the database.  The JDBC driver
+     * may actually refresh multiple rows at once if the fetch size is
+     * greater than one.
+     *
+     * <P> All values are refetched subject to the transaction isolation
+     * level and cursor sensitivity.  If <code>refreshRow</code> is called after
+     * calling an updater method, but before calling
+     * the method <code>updateRow</code>, then the
+     * updates made to the row are lost.  Calling the method
+     * <code>refreshRow</code> frequently will likely slow performance.
+     *
+     * @exception SQLException if a database access error
+     * occurs; this method is called on a closed result set;
+     * the result set type is <code>TYPE_FORWARD_ONLY</code> or if this
+     * method is called when the cursor is on the insert row
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method or this method is not supported for the specified result
+     * set type and result set concurrency.
+     * @since 1.2
+     */
+    void refreshRow() throws SQLException;
+
+    /**
+     * Cancels the updates made to the current row in this
+     * <code>ResultSet</code> object.
+     * This method may be called after calling an
+     * updater method(s) and before calling
+     * the method <code>updateRow</code> to roll back
+     * the updates made to a row.  If no updates have been made or
+     * <code>updateRow</code> has already been called, this method has no
+     * effect.
+     *
+     * @exception SQLException if a database access error
+     *            occurs; this method is called on a closed result set;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or if this method is called when the cursor is
+     *            on the insert row
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void cancelRowUpdates() throws SQLException;
+
+    /**
+     * Moves the cursor to the insert row.  The current cursor position is
+     * remembered while the cursor is positioned on the insert row.
+     *
+     * The insert row is a special row associated with an updatable
+     * result set.  It is essentially a buffer where a new row may
+     * be constructed by calling the updater methods prior to
+     * inserting the row into the result set.
+     *
+     * Only the updater, getter,
+     * and <code>insertRow</code> methods may be
+     * called when the cursor is on the insert row.  All of the columns in
+     * a result set must be given a value each time this method is
+     * called before calling <code>insertRow</code>.
+     * An updater method must be called before a
+     * getter method can be called on a column value.
+     *
+     * @exception SQLException if a database access error occurs; this
+     * method is called on a closed result set
+     * or the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void moveToInsertRow() throws SQLException;
+
+    /**
+     * Moves the cursor to the remembered cursor position, usually the
+     * current row.  This method has no effect if the cursor is not on
+     * the insert row.
+     *
+     * @exception SQLException if a database access error occurs; this
+     * method is called on a closed result set
+     *  or the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    void moveToCurrentRow() throws SQLException;
+
+    /**
+     * Retrieves the <code>Statement</code> object that produced this
+     * <code>ResultSet</code> object.
+     * If the result set was generated some other way, such as by a
+     * <code>DatabaseMetaData</code> method, this method  may return
+     * <code>null</code>.
+     *
+     * @return the <code>Statment</code> object that produced
+     * this <code>ResultSet</code> object or <code>null</code>
+     * if the result set was produced some other way
+     * @exception SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    Statement getStatement() throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as an <code>Object</code>
+     * in the Java programming language.
+     * If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * This method uses the given <code>Map</code> object
+     * for the custom mapping of the
+     * SQL structured or distinct type that is being retrieved.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param map a <code>java.util.Map</code> object that contains the mapping
+     * from SQL type names to classes in the Java programming language
+     * @return an <code>Object</code> in the Java programming language
+     * representing the SQL value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Object getObject(int columnIndex, java.util.Map<String,Class<?>> map)
+        throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>Ref</code> object
+     * in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>Ref</code> object representing an SQL <code>REF</code>
+     *         value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Ref getRef(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>Blob</code> object
+     * in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>Blob</code> object representing the SQL
+     *         <code>BLOB</code> value in the specified column
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Blob getBlob(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>Clob</code> object
+     * in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>Clob</code> object representing the SQL
+     *         <code>CLOB</code> value in the specified column
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Clob getClob(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as an <code>Array</code> object
+     * in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return an <code>Array</code> object representing the SQL
+     *         <code>ARRAY</code> value in the specified column
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Array getArray(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as an <code>Object</code>
+     * in the Java programming language.
+     * If the value is an SQL <code>NULL</code>,
+     * the driver returns a Java <code>null</code>.
+     * This method uses the specified <code>Map</code> object for
+     * custom mapping if appropriate.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param map a <code>java.util.Map</code> object that contains the mapping
+     * from SQL type names to classes in the Java programming language
+     * @return an <code>Object</code> representing the SQL value in the
+     *         specified column
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Object getObject(String columnLabel, java.util.Map<String,Class<?>> map)
+      throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>Ref</code> object
+     * in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>Ref</code> object representing the SQL <code>REF</code>
+     *         value in the specified column
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Ref getRef(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>Blob</code> object
+     * in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>Blob</code> object representing the SQL <code>BLOB</code>
+     *         value in the specified column
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Blob getBlob(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>Clob</code> object
+     * in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>Clob</code> object representing the SQL <code>CLOB</code>
+     * value in the specified column
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Clob getClob(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as an <code>Array</code> object
+     * in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return an <code>Array</code> object representing the SQL <code>ARRAY</code> value in
+     *         the specified column
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Array getArray(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.sql.Date</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the date if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param cal the <code>java.util.Calendar</code> object
+     * to use in constructing the date
+     * @return the column value as a <code>java.sql.Date</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    java.sql.Date getDate(int columnIndex, Calendar cal) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.sql.Date</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the date if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param cal the <code>java.util.Calendar</code> object
+     * to use in constructing the date
+     * @return the column value as a <code>java.sql.Date</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    java.sql.Date getDate(String columnLabel, Calendar cal) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.sql.Time</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the time if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param cal the <code>java.util.Calendar</code> object
+     * to use in constructing the time
+     * @return the column value as a <code>java.sql.Time</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    java.sql.Time getTime(int columnIndex, Calendar cal) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.sql.Time</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the time if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param cal the <code>java.util.Calendar</code> object
+     * to use in constructing the time
+     * @return the column value as a <code>java.sql.Time</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    java.sql.Time getTime(String columnLabel, Calendar cal) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.sql.Timestamp</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the timestamp if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param cal the <code>java.util.Calendar</code> object
+     * to use in constructing the timestamp
+     * @return the column value as a <code>java.sql.Timestamp</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal)
+      throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.sql.Timestamp</code> object
+     * in the Java programming language.
+     * This method uses the given calendar to construct an appropriate millisecond
+     * value for the timestamp if the underlying database does not store
+     * timezone information.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param cal the <code>java.util.Calendar</code> object
+     * to use in constructing the date
+     * @return the column value as a <code>java.sql.Timestamp</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnLabel is not valid or
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.2
+     */
+    java.sql.Timestamp getTimestamp(String columnLabel, Calendar cal)
+      throws SQLException;
+
+    //-------------------------- JDBC 3.0 ----------------------------------------
+
+    /**
+     * The constant indicating that open <code>ResultSet</code> objects with this
+     * holdability will remain open when the current transaction is commited.
+     *
+     * @since 1.4
+     */
+    int HOLD_CURSORS_OVER_COMMIT = 1;
+
+    /**
+     * The constant indicating that open <code>ResultSet</code> objects with this
+     * holdability will be closed when the current transaction is commited.
+     *
+     * @since 1.4
+     */
+    int CLOSE_CURSORS_AT_COMMIT = 2;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.net.URL</code>
+     * object in the Java programming language.
+     *
+     * @param columnIndex the index of the column 1 is the first, 2 is the second,...
+     * @return the column value as a <code>java.net.URL</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs; this method
+     * is called on a closed result set or if a URL is malformed
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    java.net.URL getURL(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>java.net.URL</code>
+     * object in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value as a <code>java.net.URL</code> object;
+     * if the value is SQL <code>NULL</code>,
+     * the value returned is <code>null</code> in the Java programming language
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs; this method
+     * is called on a closed result set or if a URL is malformed
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    java.net.URL getURL(String columnLabel) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Ref</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateRef(int columnIndex, java.sql.Ref x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Ref</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateRef(String columnLabel, java.sql.Ref x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Blob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateBlob(int columnIndex, java.sql.Blob x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Blob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateBlob(String columnLabel, java.sql.Blob x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Clob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateClob(int columnIndex, java.sql.Clob x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Clob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateClob(String columnLabel, java.sql.Clob x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Array</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateArray(int columnIndex, java.sql.Array x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.Array</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    void updateArray(String columnLabel, java.sql.Array x) throws SQLException;
+
+    //------------------------- JDBC 4.0 -----------------------------------
+
+    /**
+     * Retrieves the value of the designated column in the current row of this
+     * <code>ResultSet</code> object as a <code>java.sql.RowId</code> object in the Java
+     * programming language.
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @return the column value; if the value is a SQL <code>NULL</code> the
+     *     value returned is <code>null</code>
+     * @throws SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    RowId getRowId(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row of this
+     * <code>ResultSet</code> object as a <code>java.sql.RowId</code> object in the Java
+     * programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value ; if the value is a SQL <code>NULL</code> the
+     *     value returned is <code>null</code>
+     * @throws SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    RowId getRowId(String columnLabel) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>RowId</code> value. The updater
+     * methods are used to update column values in the current row or the insert
+     * row. The updater methods do not update the underlying database; instead
+     * the <code>updateRow</code> or <code>insertRow</code> methods are called
+     * to update the database.
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @param x the column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateRowId(int columnIndex, RowId x) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>RowId</code> value. The updater
+     * methods are used to update column values in the current row or the insert
+     * row. The updater methods do not update the underlying database; instead
+     * the <code>updateRow</code> or <code>insertRow</code> methods are called
+     * to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateRowId(String columnLabel, RowId x) throws SQLException;
+
+    /**
+     * Retrieves the holdability of this <code>ResultSet</code> object
+     * @return  either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @throws SQLException if a database access error occurs
+     * or this method is called on a closed result set
+     * @since 1.6
+     */
+    int getHoldability() throws SQLException;
+
+    /**
+     * Retrieves whether this <code>ResultSet</code> object has been closed. A <code>ResultSet</code> is closed if the
+     * method close has been called on it, or if it is automatically closed.
+     *
+     * @return true if this <code>ResultSet</code> object is closed; false if it is still open
+     * @throws SQLException if a database access error occurs
+     * @since 1.6
+     */
+    boolean isClosed() throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>String</code> value.
+     * It is intended for use when updating <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @param nString the value for the column to be updated
+     * @throws SQLException if the columnIndex is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNString(int columnIndex, String nString) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>String</code> value.
+     * It is intended for use when updating <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param nString the value for the column to be updated
+     * @throws SQLException if the columnLabel is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set;
+     * the result set concurrency is <CODE>CONCUR_READ_ONLY</code>
+     *  or if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNString(String columnLabel, String nString) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.NClob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @param nClob the value for the column to be updated
+     * @throws SQLException if the columnIndex is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set;
+     * if a database access error occurs or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNClob(int columnIndex, NClob nClob) throws SQLException;
+
+    /**
+     * Updates the designated column with a <code>java.sql.NClob</code> value.
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param nClob the value for the column to be updated
+     * @throws SQLException if the columnLabel is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set;
+     *  if a database access error occurs or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNClob(String columnLabel, NClob nClob) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>NClob</code> object
+     * in the Java programming language.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>NClob</code> object representing the SQL
+     *         <code>NCLOB</code> value in the specified column
+     * @exception SQLException if the columnIndex is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set
+     * or if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    NClob getNClob(int columnIndex) throws SQLException;
+
+  /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a <code>NClob</code> object
+     * in the Java programming language.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>NClob</code> object representing the SQL <code>NCLOB</code>
+     * value in the specified column
+     * @exception SQLException if the columnLabel is not valid;
+   * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set
+     * or if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    NClob getNClob(String columnLabel) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in  the current row of
+     *  this <code>ResultSet</code> as a
+     * <code>java.sql.SQLXML</code> object in the Java programming language.
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
+     * @throws SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    SQLXML getSQLXML(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in  the current row of
+     *  this <code>ResultSet</code> as a
+     * <code>java.sql.SQLXML</code> object in the Java programming language.
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>SQLXML</code> object that maps an <code>SQL XML</code> value
+     * @throws SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    SQLXML getSQLXML(String columnLabel) throws SQLException;
+    /**
+     * Updates the designated column with a <code>java.sql.SQLXML</code> value.
+     * The updater
+     * methods are used to update column values in the current row or the insert
+     * row. The updater methods do not update the underlying database; instead
+     * the <code>updateRow</code> or <code>insertRow</code> methods are called
+     * to update the database.
+     * <p>
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @param xmlObject the value for the column to be updated
+     * @throws SQLException if the columnIndex is not valid;
+     * if a database access error occurs; this method
+     *  is called on a closed result set;
+     * the <code>java.xml.transform.Result</code>,
+     *  <code>Writer</code> or <code>OutputStream</code> has not been closed
+     * for the <code>SQLXML</code> object;
+     *  if there is an error processing the XML value or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>.  The <code>getCause</code> method
+     *  of the exception may provide a more detailed exception, for example, if the
+     *  stream does not contain valid XML.
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException;
+    /**
+     * Updates the designated column with a <code>java.sql.SQLXML</code> value.
+     * The updater
+     * methods are used to update column values in the current row or the insert
+     * row. The updater methods do not update the underlying database; instead
+     * the <code>updateRow</code> or <code>insertRow</code> methods are called
+     * to update the database.
+     * <p>
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param xmlObject the column value
+     * @throws SQLException if the columnLabel is not valid;
+     * if a database access error occurs; this method
+     *  is called on a closed result set;
+     * the <code>java.xml.transform.Result</code>,
+     *  <code>Writer</code> or <code>OutputStream</code> has not been closed
+     * for the <code>SQLXML</code> object;
+     *  if there is an error processing the XML value or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>.  The <code>getCause</code> method
+     *  of the exception may provide a more detailed exception, for example, if the
+     *  stream does not contain valid XML.
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>String</code> in the Java programming language.
+     * It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    String getNString(int columnIndex) throws SQLException;
+
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as
+     * a <code>String</code> in the Java programming language.
+     * It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return the column value; if the value is SQL <code>NULL</code>, the
+     * value returned is <code>null</code>
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    String getNString(String columnLabel) throws SQLException;
+
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a
+     * <code>java.io.Reader</code> object.
+     * It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     *
+     * @return a <code>java.io.Reader</code> object that contains the column
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language.
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    java.io.Reader getNCharacterStream(int columnIndex) throws SQLException;
+
+    /**
+     * Retrieves the value of the designated column in the current row
+     * of this <code>ResultSet</code> object as a
+     * <code>java.io.Reader</code> object.
+     * It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @return a <code>java.io.Reader</code> object that contains the column
+     * value; if the value is SQL <code>NULL</code>, the value returned is
+     * <code>null</code> in the Java programming language
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    java.io.Reader getNCharacterStream(String columnLabel) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value, which will have
+     * the specified number of bytes.   The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+     * It is intended for use when
+     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNCharacterStream(int columnIndex,
+                             java.io.Reader x,
+                             long length) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value, which will have
+     * the specified number of bytes.  The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+     * It is intended for use when
+     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader the <code>java.io.Reader</code> object containing
+     *        the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNCharacterStream(String columnLabel,
+                             java.io.Reader reader,
+                             long length) throws SQLException;
+    /**
+     * Updates the designated column with an ascii stream value, which will have
+     * the specified number of bytes.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateAsciiStream(int columnIndex,
+                           java.io.InputStream x,
+                           long length) throws SQLException;
+
+    /**
+     * Updates the designated column with a binary stream value, which will have
+     * the specified number of bytes.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBinaryStream(int columnIndex,
+                            java.io.InputStream x,
+                            long length) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value, which will have
+     * the specified number of bytes.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateCharacterStream(int columnIndex,
+                             java.io.Reader x,
+                             long length) throws SQLException;
+    /**
+     * Updates the designated column with an ascii stream value, which will have
+     * the specified number of bytes.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateAsciiStream(String columnLabel,
+                           java.io.InputStream x,
+                           long length) throws SQLException;
+
+    /**
+     * Updates the designated column with a binary stream value, which will have
+     * the specified number of bytes.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBinaryStream(String columnLabel,
+                            java.io.InputStream x,
+                            long length) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value, which will have
+     * the specified number of bytes.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader the <code>java.io.Reader</code> object containing
+     *        the new column value
+     * @param length the length of the stream
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateCharacterStream(String columnLabel,
+                             java.io.Reader reader,
+                             long length) throws SQLException;
+    /**
+     * Updates the designated column using the given input stream, which
+     * will have the specified number of bytes.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @param length the number of bytes in the parameter data.
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException;
+
+    /**
+     * Updates the designated column using the given input stream, which
+     * will have the specified number of bytes.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @param length the number of bytes in the parameter data.
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException;
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateClob(int columnIndex,  Reader reader, long length) throws SQLException;
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateClob(String columnLabel,  Reader reader, long length) throws SQLException;
+   /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if the columnIndex is not valid;
+    * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set,
+     * if a database access error occurs or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNClob(int columnIndex,  Reader reader, long length) throws SQLException;
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object, which is the given number of characters long.
+     * When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
+     * parameter, it may be more practical to send it via a
+     * <code>java.io.Reader</code> object. The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader An object that contains the data to set the parameter value to.
+     * @param length the number of characters in the parameter data.
+     * @throws SQLException if the columnLabel is not valid;
+     * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set;
+     *  if a database access error occurs or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNClob(String columnLabel,  Reader reader, long length) throws SQLException;
+
+    //---
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.  The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+     * It is intended for use when
+     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateNCharacterStream</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNCharacterStream(int columnIndex,
+                             java.io.Reader x) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.  The
+     * driver does the necessary conversion from Java character format to
+     * the national character set in the database.
+     * It is intended for use when
+     * updating  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateNCharacterStream</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader the <code>java.io.Reader</code> object containing
+     *        the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code> or this method is called on a closed result set
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNCharacterStream(String columnLabel,
+                             java.io.Reader reader) throws SQLException;
+    /**
+     * Updates the designated column with an ascii stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateAsciiStream</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateAsciiStream(int columnIndex,
+                           java.io.InputStream x) throws SQLException;
+
+    /**
+     * Updates the designated column with a binary stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateBinaryStream</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBinaryStream(int columnIndex,
+                            java.io.InputStream x) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateCharacterStream</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param x the new column value
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateCharacterStream(int columnIndex,
+                             java.io.Reader x) throws SQLException;
+    /**
+     * Updates the designated column with an ascii stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateAsciiStream</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateAsciiStream(String columnLabel,
+                           java.io.InputStream x) throws SQLException;
+
+    /**
+     * Updates the designated column with a binary stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateBinaryStream</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param x the new column value
+     * @exception SQLException if the columnLabel is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBinaryStream(String columnLabel,
+                            java.io.InputStream x) throws SQLException;
+
+    /**
+     * Updates the designated column with a character stream value.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateCharacterStream</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader the <code>java.io.Reader</code> object containing
+     *        the new column value
+     * @exception SQLException if the columnLabel is not valid; if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateCharacterStream(String columnLabel,
+                             java.io.Reader reader) throws SQLException;
+    /**
+     * Updates the designated column using the given input stream. The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateBlob</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @exception SQLException if the columnIndex is not valid; if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBlob(int columnIndex, InputStream inputStream) throws SQLException;
+
+    /**
+     * Updates the designated column using the given input stream. The data will be read from the stream
+     * as needed until end-of-stream is reached.
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     *   <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateBlob</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param inputStream An object that contains the data to set the parameter
+     * value to.
+     * @exception SQLException if the columnLabel is not valid; if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateBlob(String columnLabel, InputStream inputStream) throws SQLException;
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object.
+     *  The data will be read from the stream
+     * as needed until end-of-stream is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     *   <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateClob</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second is 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @exception SQLException if the columnIndex is not valid;
+     * if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateClob(int columnIndex,  Reader reader) throws SQLException;
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object.
+     *  The data will be read from the stream
+     * as needed until end-of-stream is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateClob</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader An object that contains the data to set the parameter value to.
+     * @exception SQLException if the columnLabel is not valid; if a database access error occurs;
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * or this method is called on a closed result set
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateClob(String columnLabel,  Reader reader) throws SQLException;
+   /**
+     * Updates the designated column using the given <code>Reader</code>
+     *
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateNClob</code> which takes a length parameter.
+     *
+     * @param columnIndex the first column is 1, the second 2, ...
+     * @param reader An object that contains the data to set the parameter value to.
+     * @throws SQLException if the columnIndex is not valid;
+    * if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set,
+     * if a database access error occurs or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNClob(int columnIndex,  Reader reader) throws SQLException;
+
+    /**
+     * Updates the designated column using the given <code>Reader</code>
+     * object.
+     * The data will be read from the stream
+     * as needed until end-of-stream is reached.  The JDBC driver will
+     * do any necessary conversion from UNICODE to the database char format.
+     *
+     * <p>
+     * The updater methods are used to update column values in the
+     * current row or the insert row.  The updater methods do not
+     * update the underlying database; instead the <code>updateRow</code> or
+     * <code>insertRow</code> methods are called to update the database.
+     *
+     * <P><B>Note:</B> Consult your JDBC driver documentation to determine if
+     * it might be more efficient to use a version of
+     * <code>updateNClob</code> which takes a length parameter.
+     *
+     * @param columnLabel the label for the column specified with the SQL AS clause.  If the SQL AS clause was not specified, then the label is the name of the column
+     * @param reader An object that contains the data to set the parameter value to.
+     * @throws SQLException if the columnLabel is not valid; if the driver does not support national
+     *         character sets;  if the driver can detect that a data conversion
+     *  error could occur; this method is called on a closed result set;
+     *  if a database access error occurs or
+     * the result set concurrency is <code>CONCUR_READ_ONLY</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    void updateNClob(String columnLabel,  Reader reader) throws SQLException;
+
+    // Android-removed: JDBC 4.1 methods were removed immediately after the initial import.
+}
diff --git a/java/sql/ResultSetMetaData.java b/java/sql/ResultSetMetaData.java
new file mode 100644
index 0000000..c1dd474
--- /dev/null
+++ b/java/sql/ResultSetMetaData.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * An object that can be used to get information about the types
+ * and properties of the columns in a <code>ResultSet</code> object.
+ * The following code fragment creates the <code>ResultSet</code> object rs,
+ * creates the <code>ResultSetMetaData</code> object rsmd, and uses rsmd
+ * to find out how many columns rs has and whether the first column in rs
+ * can be used in a <code>WHERE</code> clause.
+ * <PRE>
+ *
+ *     ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
+ *     ResultSetMetaData rsmd = rs.getMetaData();
+ *     int numberOfColumns = rsmd.getColumnCount();
+ *     boolean b = rsmd.isSearchable(1);
+ *
+ * </PRE>
+ */
+
+public interface ResultSetMetaData extends Wrapper {
+
+    /**
+     * Returns the number of columns in this <code>ResultSet</code> object.
+     *
+     * @return the number of columns
+     * @exception SQLException if a database access error occurs
+     */
+    int getColumnCount() throws SQLException;
+
+    /**
+     * Indicates whether the designated column is automatically numbered.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isAutoIncrement(int column) throws SQLException;
+
+    /**
+     * Indicates whether a column's case matters.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isCaseSensitive(int column) throws SQLException;
+
+    /**
+     * Indicates whether the designated column can be used in a where clause.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isSearchable(int column) throws SQLException;
+
+    /**
+     * Indicates whether the designated column is a cash value.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isCurrency(int column) throws SQLException;
+
+    /**
+     * Indicates the nullability of values in the designated column.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return the nullability status of the given column; one of <code>columnNoNulls</code>,
+     *          <code>columnNullable</code> or <code>columnNullableUnknown</code>
+     * @exception SQLException if a database access error occurs
+     */
+    int isNullable(int column) throws SQLException;
+
+    /**
+     * The constant indicating that a
+     * column does not allow <code>NULL</code> values.
+     */
+    int columnNoNulls = 0;
+
+    /**
+     * The constant indicating that a
+     * column allows <code>NULL</code> values.
+     */
+    int columnNullable = 1;
+
+    /**
+     * The constant indicating that the
+     * nullability of a column's values is unknown.
+     */
+    int columnNullableUnknown = 2;
+
+    /**
+     * Indicates whether values in the designated column are signed numbers.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isSigned(int column) throws SQLException;
+
+    /**
+     * Indicates the designated column's normal maximum width in characters.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return the normal maximum number of characters allowed as the width
+     *          of the designated column
+     * @exception SQLException if a database access error occurs
+     */
+    int getColumnDisplaySize(int column) throws SQLException;
+
+    /**
+     * Gets the designated column's suggested title for use in printouts and
+     * displays. The suggested title is usually specified by the SQL <code>AS</code>
+     * clause.  If a SQL <code>AS</code> is not specified, the value returned from
+     * <code>getColumnLabel</code> will be the same as the value returned by the
+     * <code>getColumnName</code> method.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return the suggested column title
+     * @exception SQLException if a database access error occurs
+     */
+    String getColumnLabel(int column) throws SQLException;
+
+    /**
+     * Get the designated column's name.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return column name
+     * @exception SQLException if a database access error occurs
+     */
+    String getColumnName(int column) throws SQLException;
+
+    /**
+     * Get the designated column's table's schema.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return schema name or "" if not applicable
+     * @exception SQLException if a database access error occurs
+     */
+    String getSchemaName(int column) throws SQLException;
+
+    /**
+     * Get the designated column's specified column size.
+     * For numeric data, this is the maximum precision.  For character data, this is the length in characters.
+     * For datetime datatypes, this is the length in characters of the String representation (assuming the
+     * maximum allowed precision of the fractional seconds component). For binary data, this is the length in bytes.  For the ROWID datatype,
+     * this is the length in bytes. 0 is returned for data types where the
+     * column size is not applicable.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return precision
+     * @exception SQLException if a database access error occurs
+     */
+    int getPrecision(int column) throws SQLException;
+
+    /**
+     * Gets the designated column's number of digits to right of the decimal point.
+     * 0 is returned for data types where the scale is not applicable.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return scale
+     * @exception SQLException if a database access error occurs
+     */
+    int getScale(int column) throws SQLException;
+
+    /**
+     * Gets the designated column's table name.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return table name or "" if not applicable
+     * @exception SQLException if a database access error occurs
+     */
+    String getTableName(int column) throws SQLException;
+
+    /**
+     * Gets the designated column's table's catalog name.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return the name of the catalog for the table in which the given column
+     *          appears or "" if not applicable
+     * @exception SQLException if a database access error occurs
+     */
+    String getCatalogName(int column) throws SQLException;
+
+    /**
+     * Retrieves the designated column's SQL type.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return SQL type from java.sql.Types
+     * @exception SQLException if a database access error occurs
+     * @see Types
+     */
+    int getColumnType(int column) throws SQLException;
+
+    /**
+     * Retrieves the designated column's database-specific type name.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return type name used by the database. If the column type is
+     * a user-defined type, then a fully-qualified type name is returned.
+     * @exception SQLException if a database access error occurs
+     */
+    String getColumnTypeName(int column) throws SQLException;
+
+    /**
+     * Indicates whether the designated column is definitely not writable.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isReadOnly(int column) throws SQLException;
+
+    /**
+     * Indicates whether it is possible for a write on the designated column to succeed.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isWritable(int column) throws SQLException;
+
+    /**
+     * Indicates whether a write on the designated column will definitely succeed.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return <code>true</code> if so; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     */
+    boolean isDefinitelyWritable(int column) throws SQLException;
+
+    //--------------------------JDBC 2.0-----------------------------------
+
+    /**
+     * <p>Returns the fully-qualified name of the Java class whose instances
+     * are manufactured if the method <code>ResultSet.getObject</code>
+     * is called to retrieve a value
+     * from the column.  <code>ResultSet.getObject</code> may return a subclass of the
+     * class returned by this method.
+     *
+     * @param column the first column is 1, the second is 2, ...
+     * @return the fully-qualified name of the class in the Java programming
+     *         language that would be used by the method
+     * <code>ResultSet.getObject</code> to retrieve the value in the specified
+     * column. This is the class name used for custom mapping.
+     * @exception SQLException if a database access error occurs
+     * @since 1.2
+     */
+    String getColumnClassName(int column) throws SQLException;
+}
diff --git a/java/sql/RowId.java b/java/sql/RowId.java
new file mode 100644
index 0000000..11e79b3
--- /dev/null
+++ b/java/sql/RowId.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ *
+ * The representation (mapping) in the Java programming language of an SQL ROWID
+ * value. An SQL ROWID is a built-in type, a value of which can be thought of as
+ * an address  for its identified row in a database table. Whether that address
+ * is logical or, in any  respects, physical is determined by its originating data
+ * source.
+ * <p>
+ * Methods in the interfaces <code>ResultSet</code>, <code>CallableStatement</code>,
+ * and <code>PreparedStatement</code>, such as <code>getRowId</code> and <code>setRowId</code>
+ * allow a programmer to access a SQL <code>ROWID</code>  value. The <code>RowId</code>
+ * interface provides a method
+ * for representing the value of the <code>ROWID</code> as a byte array or as a
+ * <code>String</code>.
+ * <p>
+ * The method <code>getRowIdLifetime</code> in the interface <code>DatabaseMetaData</code>,
+ * can be used
+ * to determine if a <code>RowId</code> object remains valid for the duration of the transaction in
+ * which  the <code>RowId</code> was created, the duration of the session in which
+ * the <code>RowId</code> was created,
+ * or, effectively, for as long as its identified row is not deleted. In addition
+ * to specifying the duration of its valid lifetime outside its originating data
+ * source, <code>getRowIdLifetime</code> specifies the duration of a <code>ROWID</code>
+ * value's valid lifetime
+ * within its originating data source. In this, it differs from a large object,
+ * because there is no limit on the valid lifetime of a large  object within its
+ * originating data source.
+ * <p>
+ * All methods on the <code>RowId</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @see java.sql.DatabaseMetaData
+ * @since 1.6
+ */
+
+public interface RowId {
+    /**
+     * Compares this <code>RowId</code> to the specified object. The result is
+     * <code>true</code> if and only if the argument is not null and is a RowId
+     * object that represents the same ROWID as  this object.
+     * <p>
+     * It is important
+     * to consider both the origin and the valid lifetime of a <code>RowId</code>
+     * when comparing it to another <code>RowId</code>. If both are valid, and
+     * both are from the same table on the same data source, then if they are equal
+     * they identify
+     * the same row; if one or more is no longer guaranteed to be valid, or if
+     * they originate from different data sources, or different tables on the
+     * same data source, they  may be equal but still
+     * not identify the same row.
+     *
+     * @param obj the <code>Object</code> to compare this <code>RowId</code> object
+     *     against.
+     * @return true if the <code>RowId</code>s are equal; false otherwise
+     * @since 1.6
+     */
+    boolean equals(Object obj);
+
+    /**
+     * Returns an array of bytes representing the value of the SQL <code>ROWID</code>
+     * designated by this <code>java.sql.RowId</code> object.
+     *
+     * @return an array of bytes, whose length is determined by the driver supplying
+     *     the connection, representing the value of the ROWID designated by this
+     *     java.sql.RowId object.
+     */
+     byte[] getBytes();
+
+     /**
+      * Returns a String representing the value of the SQL ROWID designated by this
+      * <code>java.sql.RowId</code> object.
+      * <p>
+      *Like <code>java.sql.Date.toString()</code>
+      * returns the contents of its DATE as the <code>String</code> "2004-03-17"
+      * rather than as  DATE literal in SQL (which would have been the <code>String</code>
+      * DATE "2004-03-17"), toString()
+      * returns the contents of its ROWID in a form specific to the driver supplying
+      * the connection, and possibly not as a <code>ROWID</code> literal.
+      *
+      * @return a String whose format is determined by the driver supplying the
+      *     connection, representing the value of the <code>ROWID</code> designated
+      *     by this <code>java.sql.RowId</code>  object.
+      */
+     String toString();
+
+     /**
+      * Returns a hash code value of this <code>RowId</code> object.
+      *
+      * @return a hash code for the <code>RowId</code>
+      */
+     int hashCode();
+
+}
diff --git a/java/sql/RowIdLifetime.java b/java/sql/RowIdLifetime.java
new file mode 100644
index 0000000..165577d
--- /dev/null
+++ b/java/sql/RowIdLifetime.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.*;
+
+/**
+ * Enumeration for RowId life-time values.
+ *
+ * @since 1.6
+ */
+
+public enum RowIdLifetime {
+
+    /**
+     * Indicates that this data source does not support the ROWID type.
+     */
+    ROWID_UNSUPPORTED,
+
+    /**
+     * Indicates that the lifetime of a RowId from this data source is indeterminate;
+     * but not one of ROWID_VALID_TRANSACTION, ROWID_VALID_SESSION, or,
+     * ROWID_VALID_FOREVER.
+     */
+    ROWID_VALID_OTHER,
+
+    /**
+     * Indicates that the lifetime of a RowId from this data source is at least the
+     * containing session.
+     */
+    ROWID_VALID_SESSION,
+
+    /**
+     * Indicates that the lifetime of a RowId from this data source is at least the
+     * containing transaction.
+     */
+    ROWID_VALID_TRANSACTION,
+
+    /**
+     * Indicates that the lifetime of a RowId from this data source is, effectively,
+     * unlimited.
+     */
+    ROWID_VALID_FOREVER
+}
diff --git a/java/sql/SQLClientInfoException.java b/java/sql/SQLClientInfoException.java
new file mode 100644
index 0000000..131e407
--- /dev/null
+++ b/java/sql/SQLClientInfoException.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.sql;
+
+import java.util.Map;
+
+/**
+ * The subclass of {@link SQLException} is thrown when one or more client info properties
+ * could not be set on a <code>Connection</code>.  In addition to the information provided
+ * by <code>SQLException</code>, a <code>SQLClientInfoException</code> provides a list of client info
+ * properties that were not set.
+ *
+ * Some databases do not allow multiple client info properties to be set
+ * atomically.  For those databases, it is possible that some of the client
+ * info properties had been set even though the <code>Connection.setClientInfo</code>
+ * method threw an exception.  An application can use the <code>getFailedProperties </code>
+ * method to retrieve a list of client info properties that were not set.  The
+ * properties are identified by passing a
+ * <code>Map&lt;String,ClientInfoStatus&gt;</code> to
+ * the appropriate <code>SQLClientInfoException</code> constructor.
+ * <p>
+ * @see ClientInfoStatus
+ * @see Connection#setClientInfo
+ * @since 1.6
+ */
+public class SQLClientInfoException extends SQLException {
+
+
+
+
+        private Map<String, ClientInfoStatus>   failedProperties;
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code>  Object.
+     * The <code>reason</code>,
+     * <code>SQLState</code>, and failedProperties list are initialized to
+     * <code> null</code> and the vendor code is initialized to 0.
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     *
+     * @since 1.6
+     */
+        public SQLClientInfoException() {
+
+                this.failedProperties = null;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given <code>failedProperties</code>.
+     * The <code>reason</code> and <code>SQLState</code> are initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     *
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(Map<String, ClientInfoStatus> failedProperties) {
+
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with
+     * a given <code>cause</code> and <code>failedProperties</code>.
+     *
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code> and the vendor code is initialized to 0.
+     *
+     * <p>
+     *
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * @param cause                                     the (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(Map<String, ClientInfoStatus> failedProperties,
+                                                           Throwable cause) {
+
+                super(cause != null?cause.toString():null);
+                initCause(cause);
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given <code>reason</code> and <code>failedProperties</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     *
+     * @param reason                            a description of the exception
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(String reason,
+                Map<String, ClientInfoStatus> failedProperties) {
+
+                super(reason);
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given <code>reason</code>, <code>cause</code> and
+     * <code>failedProperties</code>.
+     * The  <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * <p>
+     *
+     * @param reason                            a description of the exception
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * @param cause                                     the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(String reason,
+                                                           Map<String, ClientInfoStatus> failedProperties,
+                                                           Throwable cause) {
+
+                super(reason);
+                initCause(cause);
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given  <code>reason</code>, <code>SQLState</code>  and
+     * <code>failedProperties</code>.
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+     * is initialized to 0.
+     * <p>
+     *
+     * @param reason                            a description of the exception
+     * @param SQLState                          an XOPEN or SQL:2003 code identifying the exception
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(String reason,
+                                                           String SQLState,
+                                                           Map<String, ClientInfoStatus> failedProperties) {
+
+                super(reason, SQLState);
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given  <code>reason</code>, <code>SQLState</code>, <code>cause</code>
+     * and <code>failedProperties</code>.  The vendor code is initialized to 0.
+     * <p>
+     *
+     * @param reason                            a description of the exception
+     * @param SQLState                          an XOPEN or SQL:2003 code identifying the exception
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * @param cause                                     the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(String reason,
+                                                           String SQLState,
+                                                           Map<String, ClientInfoStatus> failedProperties,
+                                                           Throwable cause) {
+
+                super(reason, SQLState);
+                initCause(cause);
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given  <code>reason</code>, <code>SQLState</code>,
+     * <code>vendorCode</code>  and <code>failedProperties</code>.
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     *
+     * @param reason                            a description of the exception
+     * @param SQLState                          an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode                        a database vendor-specific exception code
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(String reason,
+                                                           String SQLState,
+                                                           int vendorCode,
+                                                           Map<String, ClientInfoStatus> failedProperties) {
+
+                super(reason, SQLState, vendorCode);
+                this.failedProperties = failedProperties;
+        }
+
+        /**
+     * Constructs a <code>SQLClientInfoException</code> object initialized with a
+     * given  <code>reason</code>, <code>SQLState</code>,
+     * <code>cause</code>, <code>vendorCode</code> and
+     * <code>failedProperties</code>.
+     * <p>
+     *
+     * @param reason                            a description of the exception
+     * @param SQLState                          an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode                        a database vendor-specific exception code
+     * @param failedProperties          A Map containing the property values that could not
+     *                                  be set.  The keys in the Map
+     *                                  contain the names of the client info
+     *                                  properties that could not be set and
+     *                                  the values contain one of the reason codes
+     *                                  defined in <code>ClientInfoStatus</code>
+     * @param cause                     the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * <p>
+     * @since 1.6
+     */
+        public SQLClientInfoException(String reason,
+                                                           String SQLState,
+                                                           int vendorCode,
+                                                           Map<String, ClientInfoStatus> failedProperties,
+                                                           Throwable cause) {
+
+                super(reason, SQLState, vendorCode);
+                initCause(cause);
+                this.failedProperties = failedProperties;
+        }
+
+    /**
+     * Returns the list of client info properties that could not be set.  The
+     * keys in the Map  contain the names of the client info
+     * properties that could not be set and the values contain one of the
+     * reason codes defined in <code>ClientInfoStatus</code>
+     * <p>
+     *
+     * @return Map list containing the client info properties that could
+     * not be set
+     * <p>
+     * @since 1.6
+     */
+        public Map<String, ClientInfoStatus> getFailedProperties() {
+
+                return this.failedProperties;
+        }
+
+    private static final long serialVersionUID = -4319604256824655880L;
+}
diff --git a/java/sql/SQLData.java b/java/sql/SQLData.java
new file mode 100644
index 0000000..7d83c73
--- /dev/null
+++ b/java/sql/SQLData.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The interface used for the custom mapping of an SQL user-defined type (UDT) to
+ * a class in the Java programming language. The class object for a class
+ * implementing the <code>SQLData</code> interface will be entered in the
+ * appropriate <code>Connection</code> object's type map along with the SQL
+ * name of the UDT for which it is a custom mapping.
+ * <P>
+ * Typically, a <code>SQLData</code> implementation
+ * will define a field for each attribute of an SQL structured type or a
+ * single field for an SQL <code>DISTINCT</code> type. When the UDT is
+ * retrieved from a data source with the <code>ResultSet.getObject</code>
+ * method, it will be mapped as an instance of this class.  A programmer
+ * can operate on this class instance just as on any other object in the
+ * Java programming language and then store any changes made to it by
+ * calling the <code>PreparedStatement.setObject</code> method,
+ * which will map it back to the SQL type.
+ * <p>
+ * It is expected that the implementation of the class for a custom
+ * mapping will be done by a tool.  In a typical implementation, the
+ * programmer would simply supply the name of the SQL UDT, the name of
+ * the class to which it is being mapped, and the names of the fields to
+ * which each of the attributes of the UDT is to be mapped.  The tool will use
+ * this information to implement the <code>SQLData.readSQL</code> and
+ * <code>SQLData.writeSQL</code> methods.  The <code>readSQL</code> method
+ * calls the appropriate <code>SQLInput</code> methods to read
+ * each attribute from an <code>SQLInput</code> object, and the
+ * <code>writeSQL</code> method calls <code>SQLOutput</code> methods
+ * to write each attribute back to the data source via an
+ * <code>SQLOutput</code> object.
+ * <P>
+ * An application programmer will not normally call <code>SQLData</code> methods
+ * directly, and the <code>SQLInput</code> and <code>SQLOutput</code> methods
+ * are called internally by <code>SQLData</code> methods, not by application code.
+ *
+ * @since 1.2
+ */
+public interface SQLData {
+
+ /**
+  * Returns the fully-qualified
+  * name of the SQL user-defined type that this object represents.
+  * This method is called by the JDBC driver to get the name of the
+  * UDT instance that is being mapped to this instance of
+  * <code>SQLData</code>.
+  *
+  * @return the type name that was passed to the method <code>readSQL</code>
+  *            when this object was constructed and populated
+  * @exception SQLException if there is a database access error
+  * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+  * this method
+  * @since 1.2
+  */
+  String getSQLTypeName() throws SQLException;
+
+ /**
+  * Populates this object with data read from the database.
+  * The implementation of the method must follow this protocol:
+  * <UL>
+  * <LI>It must read each of the attributes or elements of the SQL
+  * type  from the given input stream.  This is done
+  * by calling a method of the input stream to read each
+  * item, in the order that they appear in the SQL definition
+  * of the type.
+  * <LI>The method <code>readSQL</code> then
+  * assigns the data to appropriate fields or
+  * elements (of this or other objects).
+  * Specifically, it must call the appropriate <i>reader</i> method
+  * (<code>SQLInput.readString</code>, <code>SQLInput.readBigDecimal</code>,
+  * and so on) method(s) to do the following:
+  * for a distinct type, read its single data element;
+  * for a structured type, read a value for each attribute of the SQL type.
+  * </UL>
+  * The JDBC driver initializes the input stream with a type map
+  * before calling this method, which is used by the appropriate
+  * <code>SQLInput</code> reader method on the stream.
+  *
+  * @param stream the <code>SQLInput</code> object from which to read the data for
+  * the value that is being custom mapped
+  * @param typeName the SQL type name of the value on the data stream
+  * @exception SQLException if there is a database access error
+  * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+  * this method
+  * @see SQLInput
+  * @since 1.2
+  */
+  void readSQL (SQLInput stream, String typeName) throws SQLException;
+
+  /**
+  * Writes this object to the given SQL data stream, converting it back to
+  * its SQL value in the data source.
+  * The implementation of the method must follow this protocol:<BR>
+  * It must write each of the attributes of the SQL type
+  * to the given output stream.  This is done by calling a
+  * method of the output stream to write each item, in the order that
+  * they appear in the SQL definition of the type.
+  * Specifically, it must call the appropriate <code>SQLOutput</code> writer
+  * method(s) (<code>writeInt</code>, <code>writeString</code>, and so on)
+  * to do the following: for a Distinct Type, write its single data element;
+  * for a Structured Type, write a value for each attribute of the SQL type.
+  *
+  * @param stream the <code>SQLOutput</code> object to which to write the data for
+  * the value that was custom mapped
+  * @exception SQLException if there is a database access error
+  * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+  * this method
+  * @see SQLOutput
+  * @since 1.2
+  */
+  void writeSQL (SQLOutput stream) throws SQLException;
+}
diff --git a/java/sql/SQLDataException.java b/java/sql/SQLDataException.java
new file mode 100644
index 0000000..8dc1753
--- /dev/null
+++ b/java/sql/SQLDataException.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>22</i>', or under vendor-specified conditions.  This indicates
+ * various data errors, including but not limited to data conversion errors,
+ * division by 0, and invalid arguments to functions.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLDataException extends SQLNonTransientException {
+
+        /**
+         * Constructs a <code>SQLDataException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         *
+         * @since 1.6
+         */
+        public SQLDataException() {
+                 super();
+        }
+
+        /**
+         * Constructs a <code>SQLDataException</code> object with a given
+         * <code>reason</code>.
+         * The <code>SQLState</code> is initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         *
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLDataException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLDataException</code> object with a given
+         * <code>reason</code> and <code>SQLState</code>. The
+         * vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLDataException(String reason, String SQLState) {
+                super(reason, SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLDataException</code> object with a given
+         * <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLDataException(String reason, String SQLState, int vendorCode) {
+                 super(reason, SQLState, vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLDataException</code> object with a given
+     * <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+         */
+    public SQLDataException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLDataException</code> object with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLDataException(String reason, Throwable cause) {
+         super(reason, cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLDataException</code> object with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLDataException(String reason, String SQLState, Throwable cause) {
+        super(reason, SQLState, cause);
+    }
+
+    /**
+     * Constructs a <code>SQLDataException</code> object with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLDataException(String reason, String SQLState, int vendorCode, Throwable cause) {
+          super(reason, SQLState, vendorCode, cause);
+    }
+
+   private static final long serialVersionUID = -6889123282670549800L;
+}
diff --git a/java/sql/SQLException.java b/java/sql/SQLException.java
new file mode 100644
index 0000000..4f9d752
--- /dev/null
+++ b/java/sql/SQLException.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+/**
+ * <P>An exception that provides information on a database access
+ * error or other errors.
+ *
+ * <P>Each <code>SQLException</code> provides several kinds of information:
+ * <UL>
+ *   <LI> a string describing the error.  This is used as the Java Exception
+ *       message, available via the method <code>getMesasge</code>.
+ *   <LI> a "SQLstate" string, which follows either the XOPEN SQLstate conventions
+ *        or the SQL:2003 conventions.
+ *       The values of the SQLState string are described in the appropriate spec.
+ *       The <code>DatabaseMetaData</code> method <code>getSQLStateType</code>
+ *       can be used to discover whether the driver returns the XOPEN type or
+ *       the SQL:2003 type.
+ *   <LI> an integer error code that is specific to each vendor.  Normally this will
+ *       be the actual error code returned by the underlying database.
+ *   <LI> a chain to a next Exception.  This can be used to provide additional
+ *       error information.
+ *   <LI> the causal relationship, if any for this <code>SQLException</code>.
+ * </UL>
+ */
+public class SQLException extends java.lang.Exception
+                          implements Iterable<Throwable> {
+
+    /**
+     *  Constructs a <code>SQLException</code> object with a given
+     * <code>reason</code>, <code>SQLState</code>  and
+     * <code>vendorCode</code>.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     */
+    public SQLException(String reason, String SQLState, int vendorCode) {
+        super(reason);
+        this.SQLState = SQLState;
+        this.vendorCode = vendorCode;
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                DriverManager.println("SQLState(" + SQLState +
+                                                ") vendor code(" + vendorCode + ")");
+                printStackTrace(DriverManager.getLogWriter());
+            }
+        }
+    }
+
+
+    /**
+     * Constructs a <code>SQLException</code> object with a given
+     * <code>reason</code> and <code>SQLState</code>.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+     * is initialized to 0.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     */
+    public SQLException(String reason, String SQLState) {
+        super(reason);
+        this.SQLState = SQLState;
+        this.vendorCode = 0;
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                printStackTrace(DriverManager.getLogWriter());
+                DriverManager.println("SQLException: SQLState(" + SQLState + ")");
+            }
+        }
+    }
+
+    /**
+     *  Constructs a <code>SQLException</code> object with a given
+     * <code>reason</code>. The  <code>SQLState</code>  is initialized to
+     * <code>null</code> and the vender code is initialized to 0.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     * @param reason a description of the exception
+     */
+    public SQLException(String reason) {
+        super(reason);
+        this.SQLState = null;
+        this.vendorCode = 0;
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                printStackTrace(DriverManager.getLogWriter());
+            }
+        }
+    }
+
+    /**
+     * Constructs a <code>SQLException</code> object.
+     * The <code>reason</code>, <code>SQLState</code> are initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     */
+    public SQLException() {
+        super();
+        this.SQLState = null;
+        this.vendorCode = 0;
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                printStackTrace(DriverManager.getLogWriter());
+            }
+        }
+    }
+
+    /**
+     *  Constructs a <code>SQLException</code> object with a given
+     * <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLException(Throwable cause) {
+        super(cause);
+
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                printStackTrace(DriverManager.getLogWriter());
+            }
+        }
+    }
+
+    /**
+     * Constructs a <code>SQLException</code> object with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLException(String reason, Throwable cause) {
+        super(reason,cause);
+
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                    printStackTrace(DriverManager.getLogWriter());
+            }
+        }
+    }
+
+    /**
+     * Constructs a <code>SQLException</code> object with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param sqlState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code>
+     * (which is saved for later retrieval by the
+     * <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLException(String reason, String sqlState, Throwable cause) {
+        super(reason,cause);
+
+        this.SQLState = sqlState;
+        this.vendorCode = 0;
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                printStackTrace(DriverManager.getLogWriter());
+                DriverManager.println("SQLState(" + SQLState + ")");
+            }
+        }
+    }
+
+    /**
+     * Constructs a <code>SQLException</code> object with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param sqlState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLException(String reason, String sqlState, int vendorCode, Throwable cause) {
+        super(reason,cause);
+
+        this.SQLState = sqlState;
+        this.vendorCode = vendorCode;
+        if (!(this instanceof SQLWarning)) {
+            if (DriverManager.getLogWriter() != null) {
+                DriverManager.println("SQLState(" + SQLState +
+                                                ") vendor code(" + vendorCode + ")");
+                printStackTrace(DriverManager.getLogWriter());
+            }
+        }
+    }
+
+    /**
+     * Retrieves the SQLState for this <code>SQLException</code> object.
+     *
+     * @return the SQLState value
+     */
+    public String getSQLState() {
+        return (SQLState);
+    }
+
+    /**
+     * Retrieves the vendor-specific exception code
+     * for this <code>SQLException</code> object.
+     *
+     * @return the vendor's error code
+     */
+    public int getErrorCode() {
+        return (vendorCode);
+    }
+
+    /**
+     * Retrieves the exception chained to this
+     * <code>SQLException</code> object by setNextException(SQLException ex).
+     *
+     * @return the next <code>SQLException</code> object in the chain;
+     *         <code>null</code> if there are none
+     * @see #setNextException
+     */
+    public SQLException getNextException() {
+        return (next);
+    }
+
+    /**
+     * Adds an <code>SQLException</code> object to the end of the chain.
+     *
+     * @param ex the new exception that will be added to the end of
+     *            the <code>SQLException</code> chain
+     * @see #getNextException
+     */
+    public void setNextException(SQLException ex) {
+
+        SQLException current = this;
+        for(;;) {
+            SQLException next=current.next;
+            if (next != null) {
+                current = next;
+                continue;
+            }
+
+            if (nextUpdater.compareAndSet(current,null,ex)) {
+                return;
+            }
+            current=current.next;
+        }
+    }
+
+    /**
+     * Returns an iterator over the chained SQLExceptions.  The iterator will
+     * be used to iterate over each SQLException and its underlying cause
+     * (if any).
+     *
+     * @return an iterator over the chained SQLExceptions and causes in the proper
+     * order
+     *
+     * @since 1.6
+     */
+    public Iterator<Throwable> iterator() {
+
+       return new Iterator<Throwable>() {
+
+           SQLException firstException = SQLException.this;
+           SQLException nextException = firstException.getNextException();
+           Throwable cause = firstException.getCause();
+
+           public boolean hasNext() {
+               if(firstException != null || nextException != null || cause != null)
+                   return true;
+               return false;
+           }
+
+           public Throwable next() {
+               Throwable throwable = null;
+               if(firstException != null){
+                   throwable = firstException;
+                   firstException = null;
+               }
+               else if(cause != null){
+                   throwable = cause;
+                   cause = cause.getCause();
+               }
+               else if(nextException != null){
+                   throwable = nextException;
+                   cause = nextException.getCause();
+                   nextException = nextException.getNextException();
+               }
+               else
+                   throw new NoSuchElementException();
+               return throwable;
+           }
+
+           public void remove() {
+               throw new UnsupportedOperationException();
+           }
+
+       };
+
+    }
+
+    /**
+         * @serial
+         */
+    private String SQLState;
+
+        /**
+         * @serial
+         */
+    private int vendorCode;
+
+        /**
+         * @serial
+         */
+    private volatile SQLException next;
+
+    private static final AtomicReferenceFieldUpdater<SQLException,SQLException> nextUpdater =
+            AtomicReferenceFieldUpdater.newUpdater(SQLException.class,SQLException.class,"next");
+
+    private static final long serialVersionUID = 2135244094396331484L;
+}
diff --git a/java/sql/SQLFeatureNotSupportedException.java b/java/sql/SQLFeatureNotSupportedException.java
new file mode 100644
index 0000000..e9a38d6
--- /dev/null
+++ b/java/sql/SQLFeatureNotSupportedException.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when the SQLState class value is '<i>0A</i>'
+ * ( the value is 'zero' A).
+ * This indicates that the JDBC driver does not support an optional JDBC feature.
+ * Optional JDBC features can fall into the fallowing categories:
+ *<p>
+ *<UL>
+ *<LI>no support for an optional feature
+ *<LI>no support for an optional overloaded method
+ *<LI>no support for an optional mode for a method.  The mode for a method is
+ *determined based on constants passed as parameter values to a method
+ *</UL>
+ *
+ * @since 1.6
+ */
+public class SQLFeatureNotSupportedException extends SQLNonTransientException {
+
+        /**
+         * Constructs a <code>SQLFeatureNotSupportedException</code> object.
+         *  The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLFeatureNotSupportedException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLFeatureNotSupportedException</code> object
+         * with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLFeatureNotSupportedException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLFeatureNotSupportedException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLFeatureNotSupportedException(String reason, String SQLState) {
+                super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLFeatureNotSupportedException</code> object
+         *  with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLFeatureNotSupportedException(String reason, String SQLState, int vendorCode) {
+                super(reason,SQLState,vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLFeatureNotSupportedException</code> object
+     *   with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval bythe <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLFeatureNotSupportedException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLFeatureNotSupportedException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLFeatureNotSupportedException(String reason, Throwable cause) {
+        super(reason,cause);
+    }
+
+    /**
+     * Constructs a <code>SQLFeatureNotSupportedException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLFeatureNotSupportedException(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLFeatureNotSupportedException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLFeatureNotSupportedException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+    }
+
+    private static final long serialVersionUID = -1026510870282316051L;
+}
diff --git a/java/sql/SQLInput.java b/java/sql/SQLInput.java
new file mode 100644
index 0000000..c607e83
--- /dev/null
+++ b/java/sql/SQLInput.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * An input stream that contains a stream of values representing an
+ * instance of an SQL structured type or an SQL distinct type.
+ * This interface, used only for custom mapping, is used by the driver
+ * behind the scenes, and a programmer never directly invokes
+ * <code>SQLInput</code> methods. The <i>reader</i> methods
+ * (<code>readLong</code>, <code>readBytes</code>, and so on)
+ * provide a way  for an implementation of the <code>SQLData</code>
+ *  interface to read the values in an <code>SQLInput</code> object.
+ *  And as described in <code>SQLData</code>, calls to reader methods must
+ * be made in the order that their corresponding attributes appear in the
+ * SQL definition of the type.
+ * The method <code>wasNull</code> is used to determine whether
+ * the last value read was SQL <code>NULL</code>.
+ * <P>When the method <code>getObject</code> is called with an
+ * object of a class implementing the interface <code>SQLData</code>,
+ * the JDBC driver calls the method <code>SQLData.getSQLType</code>
+ * to determine the SQL type of the user-defined type (UDT)
+ * being custom mapped. The driver
+ * creates an instance of <code>SQLInput</code>, populating it with the
+ * attributes of the UDT.  The driver then passes the input
+ * stream to the method <code>SQLData.readSQL</code>, which in turn
+ * calls the <code>SQLInput</code> reader methods
+ * in its implementation for reading the
+ * attributes from the input stream.
+ * @since 1.2
+ */
+
+public interface SQLInput {
+
+
+    //================================================================
+    // Methods for reading attributes from the stream of SQL data.
+    // These methods correspond to the column-accessor methods of
+    // java.sql.ResultSet.
+    //================================================================
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>String</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    String readString() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>boolean</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>false</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean readBoolean() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>byte</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>0</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    byte readByte() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>short</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>0</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    short readShort() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as an <code>int</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>0</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    int readInt() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>long</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>0</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    long readLong() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>float</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>0</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    float readFloat() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>double</code>
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>0</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    double readDouble() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>java.math.BigDecimal</code>
+     * object in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.math.BigDecimal readBigDecimal() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as an array of bytes
+     * in the Java programming language.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    byte[] readBytes() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>java.sql.Date</code> object.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.sql.Date readDate() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>java.sql.Time</code> object.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.sql.Time readTime() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>java.sql.Timestamp</code> object.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.sql.Timestamp readTimestamp() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a stream of Unicode characters.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.io.Reader readCharacterStream() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a stream of ASCII characters.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.io.InputStream readAsciiStream() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a stream of uninterpreted
+     * bytes.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    java.io.InputStream readBinaryStream() throws SQLException;
+
+    //================================================================
+    // Methods for reading items of SQL user-defined types from the stream.
+    //================================================================
+
+    /**
+     * Reads the datum at the head of the stream and returns it as an
+     * <code>Object</code> in the Java programming language.  The
+     * actual type of the object returned is determined by the default type
+     * mapping, and any customizations present in this stream's type map.
+     *
+     * <P>A type map is registered with the stream by the JDBC driver before the
+     * stream is passed to the application.
+     *
+     * <P>When the datum at the head of the stream is an SQL <code>NULL</code>,
+     * the method returns <code>null</code>.  If the datum is an SQL structured or distinct
+     * type, it determines the SQL type of the datum at the head of the stream.
+     * If the stream's type map has an entry for that SQL type, the driver
+     * constructs an object of the appropriate class and calls the method
+     * <code>SQLData.readSQL</code> on that object, which reads additional data from the
+     * stream, using the protocol described for that method.
+     *
+     * @return the datum at the head of the stream as an <code>Object</code> in the
+     * Java programming language;<code>null</code> if the datum is SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Object readObject() throws SQLException;
+
+    /**
+     * Reads an SQL <code>REF</code> value from the stream and returns it as a
+     * <code>Ref</code> object in the Java programming language.
+     *
+     * @return a <code>Ref</code> object representing the SQL <code>REF</code> value
+     * at the head of the stream; <code>null</code> if the value read is
+     * SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Ref readRef() throws SQLException;
+
+    /**
+     * Reads an SQL <code>BLOB</code> value from the stream and returns it as a
+     * <code>Blob</code> object in the Java programming language.
+     *
+     * @return a <code>Blob</code> object representing data of the SQL <code>BLOB</code> value
+     * at the head of the stream; <code>null</code> if the value read is
+     * SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Blob readBlob() throws SQLException;
+
+    /**
+     * Reads an SQL <code>CLOB</code> value from the stream and returns it as a
+     * <code>Clob</code> object in the Java programming language.
+     *
+     * @return a <code>Clob</code> object representing data of the SQL <code>CLOB</code> value
+     * at the head of the stream; <code>null</code> if the value read is
+     * SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Clob readClob() throws SQLException;
+
+    /**
+     * Reads an SQL <code>ARRAY</code> value from the stream and returns it as an
+     * <code>Array</code> object in the Java programming language.
+     *
+     * @return an <code>Array</code> object representing data of the SQL
+     * <code>ARRAY</code> value at the head of the stream; <code>null</code>
+     * if the value read is SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    Array readArray() throws SQLException;
+
+    /**
+     * Retrieves whether the last value read was SQL <code>NULL</code>.
+     *
+     * @return <code>true</code> if the most recently read SQL value was SQL
+     * <code>NULL</code>; <code>false</code> otherwise
+     * @exception SQLException if a database access error occurs
+     *
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.2
+     */
+    boolean wasNull() throws SQLException;
+
+    //---------------------------- JDBC 3.0 -------------------------
+
+    /**
+     * Reads an SQL <code>DATALINK</code> value from the stream and returns it as a
+     * <code>java.net.URL</code> object in the Java programming language.
+     *
+     * @return a <code>java.net.URL</code> object.
+     * @exception SQLException if a database access error occurs,
+     *            or if a URL is malformed
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.4
+     */
+    java.net.URL readURL() throws SQLException;
+
+     //---------------------------- JDBC 4.0 -------------------------
+
+    /**
+     * Reads an SQL <code>NCLOB</code> value from the stream and returns it as a
+     * <code>NClob</code> object in the Java programming language.
+     *
+     * @return a <code>NClob</code> object representing data of the SQL <code>NCLOB</code> value
+     * at the head of the stream; <code>null</code> if the value read is
+     * SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    NClob readNClob() throws SQLException;
+
+    /**
+     * Reads the next attribute in the stream and returns it as a <code>String</code>
+     * in the Java programming language. It is intended for use when
+     * accessing  <code>NCHAR</code>,<code>NVARCHAR</code>
+     * and <code>LONGNVARCHAR</code> columns.
+     *
+     * @return the attribute; if the value is SQL <code>NULL</code>, returns <code>null</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    String readNString() throws SQLException;
+
+    /**
+     * Reads an SQL <code>XML</code> value from the stream and returns it as a
+     * <code>SQLXML</code> object in the Java programming language.
+     *
+     * @return a <code>SQLXML</code> object representing data of the SQL <code>XML</code> value
+     * at the head of the stream; <code>null</code> if the value read is
+     * SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    SQLXML readSQLXML() throws SQLException;
+
+    /**
+     * Reads an SQL <code>ROWID</code> value from the stream and returns it as a
+     * <code>RowId</code> object in the Java programming language.
+     *
+     * @return a <code>RowId</code> object representing data of the SQL <code>ROWID</code> value
+     * at the head of the stream; <code>null</code> if the value read is
+     * SQL <code>NULL</code>
+     * @exception SQLException if a database access error occurs
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     * @since 1.6
+     */
+    RowId readRowId() throws SQLException;
+
+}
diff --git a/java/sql/SQLIntegrityConstraintViolationException.java b/java/sql/SQLIntegrityConstraintViolationException.java
new file mode 100644
index 0000000..0f92ac5
--- /dev/null
+++ b/java/sql/SQLIntegrityConstraintViolationException.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>23</i>', or under vendor-specified conditions.
+ * This indicates that an integrity
+ * constraint (foreign key, primary key or unique key) has been violated.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLIntegrityConstraintViolationException extends SQLNonTransientException {
+
+        /**
+         * Constructs a <code>SQLIntegrityConstraintViolationException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLIntegrityConstraintViolationException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLIntegrityConstraintViolationException</code>
+         *  with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLIntegrityConstraintViolationException(String reason) {
+        super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLIntegrityConstraintViolationException</code>
+         * object with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLIntegrityConstraintViolationException(String reason, String SQLState) {
+                super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLIntegrityConstraintViolationException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLIntegrityConstraintViolationException(String reason, String SQLState, int vendorCode) {
+                 super(reason,SQLState,vendorCode);
+        }
+
+        /**
+         * Constructs an <code>SQLIntegrityConstraintViolationException</code> object with
+         *  a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+         * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code>  method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+         */
+    public SQLIntegrityConstraintViolationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLIntegrityConstraintViolationException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLIntegrityConstraintViolationException(String reason, Throwable cause) {
+         super(reason,cause);
+    }
+
+    /**
+     * Constructs a <code>SQLIntegrityConstraintViolationException</code> object
+     *  with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code>  method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLIntegrityConstraintViolationException(String reason, String SQLState, Throwable cause) {
+          super(reason,SQLState, cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLIntegrityConstraintViolationException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLIntegrityConstraintViolationException(String reason, String SQLState, int vendorCode, Throwable cause) {
+          super(reason,SQLState,vendorCode,cause);
+    }
+
+    private static final long serialVersionUID = 8033405298774849169L;
+}
diff --git a/java/sql/SQLInvalidAuthorizationSpecException.java b/java/sql/SQLInvalidAuthorizationSpecException.java
new file mode 100644
index 0000000..0b4d206
--- /dev/null
+++ b/java/sql/SQLInvalidAuthorizationSpecException.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>28</i>', or under vendor-specified conditions. This indicates that
+ * the authorization credentials presented during connection establishment
+ * are not valid.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLInvalidAuthorizationSpecException extends SQLNonTransientException {
+
+        /**
+         * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLInvalidAuthorizationSpecException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+         *  with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLInvalidAuthorizationSpecException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLInvalidAuthorizationSpecException(String reason, String SQLState) {
+                super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLInvalidAuthorizationSpecException(String reason, String SQLState, int vendorCode) {
+                  super(reason,SQLState,vendorCode);
+        }
+
+        /**
+     * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+         * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+         * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+         */
+    public SQLInvalidAuthorizationSpecException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+     *  with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLInvalidAuthorizationSpecException(String reason, Throwable cause) {
+        super(reason,cause);
+    }
+
+    /**
+     * Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+     *  with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code>  method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLInvalidAuthorizationSpecException(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLInvalidAuthorizationSpecException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLInvalidAuthorizationSpecException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+    }
+
+   private static final long serialVersionUID = -64105250450891498L;
+}
diff --git a/java/sql/SQLNonTransientConnectionException.java b/java/sql/SQLNonTransientConnectionException.java
new file mode 100644
index 0000000..036c881
--- /dev/null
+++ b/java/sql/SQLNonTransientConnectionException.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown for the SQLState
+ * class value '<i>08</i>', or under vendor-specified conditions.  This
+ * indicates that the connection operation that failed will not succeed if
+ * the operation is retried without the cause of the failure being corrected.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLNonTransientConnectionException extends java.sql.SQLNonTransientException {
+
+        /**
+         * Constructs a <code>SQLNonTransientConnectionException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         *
+         * @since 1.6
+         */
+        public SQLNonTransientConnectionException() {
+                 super();
+        }
+
+        /**
+         * Constructs a <code>SQLNonTransientConnectionException</code> object
+         *  with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLNonTransientConnectionException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLNonTransientConnectionException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLNonTransientConnectionException(String reason, String SQLState) {
+                 super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLNonTransientConnectionException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLNonTransientConnectionException(String reason, String SQLState, int vendorCode) {
+                super(reason,SQLState,vendorCode);
+        }
+
+        /**
+     * Constructs a <code>SQLNonTransientConnectionException</code> object
+         * with a given  <code>cause</code>.
+           * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+         * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientConnectionException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransientException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientConnectionException(String reason, Throwable cause) {
+        super(reason,cause);
+    }
+
+    /**
+     * Constructs a <code>SQLNonTransientConnectionException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientConnectionException(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLNonTransientConnectionException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientConnectionException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+    }
+
+    private static final long serialVersionUID = -5852318857474782892L;
+
+}
diff --git a/java/sql/SQLNonTransientException.java b/java/sql/SQLNonTransientException.java
new file mode 100644
index 0000000..1e68893
--- /dev/null
+++ b/java/sql/SQLNonTransientException.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when an instance where a retry
+ * of the same operation would fail unless the cause of the <code>SQLException</code>
+ * is corrected.
+ *<p>
+ *
+ * @since 1.6
+ */
+public class SQLNonTransientException extends java.sql.SQLException {
+
+        /**
+         * Constructs a <code>SQLNonTransientException</code> object.
+         *  The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         *
+         * @since 1.6
+         */
+        public SQLNonTransientException() {
+        super();
+        }
+
+        /**
+         * Constructs a <code>SQLNonTransientException</code> object
+         * with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         *
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLNonTransientException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLNonTransientException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLNonTransientException(String reason, String SQLState) {
+                super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLNonTransientException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLNonTransientException(String reason, String SQLState, int vendorCode) {
+                 super(reason,SQLState,vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLNonTransientException</code> object
+     *  with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransientException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientException(String reason, Throwable cause) {
+        super(reason,cause);
+
+    }
+
+    /**
+     * Constructs a <code>SQLNonTransientException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientException(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLNonTransientException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLNonTransientException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+    }
+
+   private static final long serialVersionUID = -9104382843534716547L;
+}
diff --git a/java/sql/SQLOutput.java b/java/sql/SQLOutput.java
new file mode 100644
index 0000000..8aa1d14
--- /dev/null
+++ b/java/sql/SQLOutput.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The output stream for writing the attributes of a user-defined
+ * type back to the database.  This interface, used
+ * only for custom mapping, is used by the driver, and its
+ * methods are never directly invoked by a programmer.
+ * <p>When an object of a class implementing the interface
+ * <code>SQLData</code> is passed as an argument to an SQL statement, the
+ * JDBC driver calls the method <code>SQLData.getSQLType</code> to
+ * determine the  kind of SQL
+ * datum being passed to the database.
+ * The driver then creates an instance of <code>SQLOutput</code> and
+ * passes it to the method <code>SQLData.writeSQL</code>.
+ * The method <code>writeSQL</code> in turn calls the
+ * appropriate <code>SQLOutput</code> <i>writer</i> methods
+ * <code>writeBoolean</code>, <code>writeCharacterStream</code>, and so on)
+ * to write data from the <code>SQLData</code> object to
+ * the <code>SQLOutput</code> output stream as the
+ * representation of an SQL user-defined type.
+ * @since 1.2
+ */
+
+ public interface SQLOutput {
+
+  //================================================================
+  // Methods for writing attributes to the stream of SQL data.
+  // These methods correspond to the column-accessor methods of
+  // java.sql.ResultSet.
+  //================================================================
+
+  /**
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeString(String x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java boolean.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeBoolean(boolean x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java byte.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeByte(byte x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java short.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeShort(short x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java int.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeInt(int x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java long.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeLong(long x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java float.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeFloat(float x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a Java double.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeDouble(double x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a java.math.BigDecimal object.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeBigDecimal(java.math.BigDecimal x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as an array of bytes.
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeBytes(byte[] x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a java.sql.Date object.
+   * Writes the next attribute to the stream as a <code>java.sql.Date</code> object
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeDate(java.sql.Date x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a java.sql.Time object.
+   * Writes the next attribute to the stream as a <code>java.sql.Date</code> object
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeTime(java.sql.Time x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a java.sql.Timestamp object.
+   * Writes the next attribute to the stream as a <code>java.sql.Date</code> object
+   * in the Java programming language.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeTimestamp(java.sql.Timestamp x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a stream of Unicode characters.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeCharacterStream(java.io.Reader x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a stream of ASCII characters.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeAsciiStream(java.io.InputStream x) throws SQLException;
+
+  /**
+   * Writes the next attribute to the stream as a stream of uninterpreted
+   * bytes.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeBinaryStream(java.io.InputStream x) throws SQLException;
+
+  //================================================================
+  // Methods for writing items of SQL user-defined types to the stream.
+  // These methods pass objects to the database as values of SQL
+  // Structured Types, Distinct Types, Constructed Types, and Locator
+  // Types.  They decompose the Java object(s) and write leaf data
+  // items using the methods above.
+  //================================================================
+
+  /**
+   * Writes to the stream the data contained in the given
+   * <code>SQLData</code> object.
+   * When the <code>SQLData</code> object is <code>null</code>, this
+   * method writes an SQL <code>NULL</code> to the stream.
+   * Otherwise, it calls the <code>SQLData.writeSQL</code>
+   * method of the given object, which
+   * writes the object's attributes to the stream.
+   * The implementation of the method <code>SQLData.writeSQ</code>
+   * calls the appropriate <code>SQLOutput</code> writer method(s)
+   * for writing each of the object's attributes in order.
+   * The attributes must be read from an <code>SQLInput</code>
+   * input stream and written to an <code>SQLOutput</code>
+   * output stream in the same order in which they were
+   * listed in the SQL definition of the user-defined type.
+   *
+   * @param x the object representing data of an SQL structured or
+   * distinct type
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeObject(SQLData x) throws SQLException;
+
+  /**
+   * Writes an SQL <code>REF</code> value to the stream.
+   *
+   * @param x a <code>Ref</code> object representing data of an SQL
+   * <code>REF</code> value
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeRef(Ref x) throws SQLException;
+
+  /**
+   * Writes an SQL <code>BLOB</code> value to the stream.
+   *
+   * @param x a <code>Blob</code> object representing data of an SQL
+   * <code>BLOB</code> value
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeBlob(Blob x) throws SQLException;
+
+  /**
+   * Writes an SQL <code>CLOB</code> value to the stream.
+   *
+   * @param x a <code>Clob</code> object representing data of an SQL
+   * <code>CLOB</code> value
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeClob(Clob x) throws SQLException;
+
+  /**
+   * Writes an SQL structured type value to the stream.
+   *
+   * @param x a <code>Struct</code> object representing data of an SQL
+   * structured type
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeStruct(Struct x) throws SQLException;
+
+  /**
+   * Writes an SQL <code>ARRAY</code> value to the stream.
+   *
+   * @param x an <code>Array</code> object representing data of an SQL
+   * <code>ARRAY</code> type
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  void writeArray(Array x) throws SQLException;
+
+     //--------------------------- JDBC 3.0 ------------------------
+
+     /**
+      * Writes a SQL <code>DATALINK</code> value to the stream.
+      *
+      * @param x a <code>java.net.URL</code> object representing the data
+      * of SQL DATALINK type
+      *
+      * @exception SQLException if a database access error occurs
+      * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+      * this method
+      * @since 1.4
+      */
+     void writeURL(java.net.URL x) throws SQLException;
+
+     //--------------------------- JDBC 4.0 ------------------------
+
+  /**
+   * Writes the next attribute to the stream as a <code>String</code>
+   * in the Java programming language. The driver converts this to a
+   * SQL <code>NCHAR</code> or
+   * <code>NVARCHAR</code> or <code>LONGNVARCHAR</code> value
+   * (depending on the argument's
+   * size relative to the driver's limits on <code>NVARCHAR</code> values)
+   * when it sends it to the stream.
+   *
+   * @param x the value to pass to the database
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  void writeNString(String x) throws SQLException;
+
+  /**
+   * Writes an SQL <code>NCLOB</code> value to the stream.
+   *
+   * @param x a <code>NClob</code> object representing data of an SQL
+   * <code>NCLOB</code> value
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  void writeNClob(NClob x) throws SQLException;
+
+
+  /**
+   * Writes an SQL <code>ROWID</code> value to the stream.
+   *
+   * @param x a <code>RowId</code> object representing data of an SQL
+   * <code>ROWID</code> value
+   *
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  void writeRowId(RowId x) throws SQLException;
+
+
+  /**
+   * Writes an SQL <code>XML</code> value to the stream.
+   *
+   * @param x a <code>SQLXML</code> object representing data of an SQL
+   * <code>XML</code> value
+   *
+   * @throws SQLException if a database access error occurs,
+   * the <code>java.xml.transform.Result</code>,
+   *  <code>Writer</code> or <code>OutputStream</code> has not been closed for the <code>SQLXML</code> object or
+   *  if there is an error processing the XML value.  The <code>getCause</code> method
+   *  of the exception may provide a more detailed exception, for example, if the
+   *  stream does not contain valid XML.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  void writeSQLXML(SQLXML x) throws SQLException;
+
+
+}
diff --git a/java/sql/SQLPermission.java b/java/sql/SQLPermission.java
new file mode 100644
index 0000000..d90cf64
--- /dev/null
+++ b/java/sql/SQLPermission.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.sql;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class SQLPermission extends BasicPermission {
+
+    public SQLPermission(String name) {
+        super("");
+    }
+
+    public SQLPermission(String name, String actions) {
+        super("", "");
+    }
+}
diff --git a/java/sql/SQLRecoverableException.java b/java/sql/SQLRecoverableException.java
new file mode 100644
index 0000000..08de9d7
--- /dev/null
+++ b/java/sql/SQLRecoverableException.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown in situations where a
+ * previously failed operation might be able to succeed if the application performs
+ *  some recovery steps and retries the entire transaction or in the case of a
+ * distributed transaction, the transaction branch.  At a minimum,
+ * the recovery operation must include closing the current connection and getting
+ * a new connection.
+ *<p>
+ *
+ * @since 1.6
+ */
+public class SQLRecoverableException extends java.sql.SQLException {
+
+        /**
+         * Constructs a <code>SQLRecoverableException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+        */
+        public SQLRecoverableException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLRecoverableException</code> object
+         *  with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLRecoverableException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLRecoverableException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLRecoverableException(String reason, String SQLState) {
+                super(reason, SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLRecoverableException</code> object
+         *  with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLRecoverableException(String reason, String SQLState, int vendorCode) {
+                super(reason, SQLState, vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLRecoverableException</code> object
+     * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLRecoverableException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLRecoverableException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLRecoverableException(String reason, Throwable cause) {
+        super(reason, cause);
+    }
+
+    /**
+     * Constructs a <code>SQLRecoverableException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLRecoverableException(String reason, String SQLState, Throwable cause) {
+        super(reason, SQLState, cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLRecoverableException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLRecoverableException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason, SQLState, vendorCode, cause);
+    }
+
+   private static final long serialVersionUID = -4144386502923131579L;
+}
diff --git a/java/sql/SQLSyntaxErrorException.java b/java/sql/SQLSyntaxErrorException.java
new file mode 100644
index 0000000..b65dec7
--- /dev/null
+++ b/java/sql/SQLSyntaxErrorException.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>42</i>', or under vendor-specified conditions. This indicates that the
+ * in-progress query has violated SQL syntax rules.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLSyntaxErrorException extends SQLNonTransientException {
+
+        /**
+         * Constructs a <code>SQLSyntaxErrorException</code> object.
+         *  The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLSyntaxErrorException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLSyntaxErrorException</code> object
+         * with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLSyntaxErrorException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLSyntaxErrorException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLSyntaxErrorException(String reason, String SQLState) {
+                super(reason, SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLSyntaxErrorException</code> object
+         *  with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLSyntaxErrorException(String reason, String SQLState, int vendorCode) {
+                super(reason, SQLState, vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLSyntaxErrorException</code> object
+     *   with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval bythe <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLSyntaxErrorException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLSyntaxErrorException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLSyntaxErrorException(String reason, Throwable cause) {
+        super(reason, cause);
+    }
+
+    /**
+     * Constructs a <code>SQLSyntaxErrorException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLSyntaxErrorException(String reason, String SQLState, Throwable cause) {
+        super(reason, SQLState, cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLSyntaxErrorException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLSyntaxErrorException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason, SQLState, vendorCode, cause);
+    }
+
+    private static final long serialVersionUID = -1843832610477496053L;
+}
diff --git a/java/sql/SQLTimeoutException.java b/java/sql/SQLTimeoutException.java
new file mode 100644
index 0000000..57abd3b
--- /dev/null
+++ b/java/sql/SQLTimeoutException.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <P>The subclass of {@link SQLException} thrown when the timeout specified by <code>Statement</code>
+ *  has expired.
+ * <P> This exception does not correspond to a standard SQLState.
+ *
+ * @since 1.6
+ */
+
+public class SQLTimeoutException extends SQLTransientException {
+        /**
+         * Constructs a <code>SQLTimeoutException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLTimeoutException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLTimeoutException</code> object
+         * with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLTimeoutException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLTimeoutException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLTimeoutException(String reason, String SQLState) {
+                super(reason, SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLTimeoutException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLTimeoutException(String reason, String SQLState, int vendorCode) {
+                super(reason, SQLState, vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLTimeoutException</code> object
+     * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTimeoutException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTimeoutException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTimeoutException(String reason, Throwable cause) {
+        super(reason, cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTimeoutException</code> object
+     *  with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTimeoutException(String reason, String SQLState, Throwable cause) {
+        super(reason, SQLState, cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLTimeoutException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTimeoutException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason, SQLState, vendorCode, cause);
+    }
+
+    private static final long serialVersionUID = -4487171280562520262L;
+}
diff --git a/java/sql/SQLTransactionRollbackException.java b/java/sql/SQLTransactionRollbackException.java
new file mode 100644
index 0000000..90eb702
--- /dev/null
+++ b/java/sql/SQLTransactionRollbackException.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} thrown when the SQLState class value
+ * is '<i>40</i>', or under vendor-specified conditions. This indicates that the
+ * current statement was automatically rolled back by the database because
+ * of deadlock or other transaction serialization failures.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLTransactionRollbackException extends SQLTransientException {
+        /**
+         * Constructs a <code>SQLTransactionRollbackException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLTransactionRollbackException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLTransactionRollbackException</code> object
+         * with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLTransactionRollbackException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLTransactionRollbackException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLTransactionRollbackException(String reason, String SQLState) {
+                super(reason, SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLTransactionRollbackException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLTransactionRollbackException(String reason, String SQLState, int vendorCode) {
+                super(reason, SQLState, vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLTransactionRollbackException</code> object
+     * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransactionRollbackException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransactionRollbackException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransactionRollbackException(String reason, Throwable cause) {
+        super(reason, cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransactionRollbackException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransactionRollbackException(String reason, String SQLState, Throwable cause) {
+        super(reason, SQLState, cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLTransactionRollbackException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransactionRollbackException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason, SQLState, vendorCode, cause);
+    }
+
+    private static final long serialVersionUID = 5246680841170837229L;
+}
diff --git a/java/sql/SQLTransientConnectionException.java b/java/sql/SQLTransientConnectionException.java
new file mode 100644
index 0000000..cebc67d
--- /dev/null
+++ b/java/sql/SQLTransientConnectionException.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} for the SQLState class
+ * value '<i>08</i>', or under vendor-specified conditions.  This indicates
+ * that the connection operation that failed might be able to succeed if
+ * the operation is retried without any application-level changes.
+ * <p>
+ * Please consult your driver vendor documentation for the vendor-specified
+ * conditions for which this <code>Exception</code> may be thrown.
+ * @since 1.6
+ */
+public class SQLTransientConnectionException extends java.sql.SQLTransientException {
+
+        /**
+         * Constructs a <code>SQLTransientConnectionException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+         */
+        public SQLTransientConnectionException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLTransientConnectionException</code> object
+         * with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLTransientConnectionException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLTransientConnectionException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLTransientConnectionException(String reason, String SQLState) {
+                super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLTransientConnectionException</code> object
+         * with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLTransientConnectionException(String reason, String SQLState, int vendorCode) {
+                super(reason,SQLState,vendorCode);
+        }
+
+   /**
+     * Constructs a <code>SQLTransientConnectionException</code> object
+     * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+    */
+    public SQLTransientConnectionException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransientConnectionException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code>(which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+    * @since 1.6
+     */
+    public SQLTransientConnectionException(String reason, Throwable cause) {
+        super(reason,cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransientConnectionException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransientConnectionException(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLTransientConnectionException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransientConnectionException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+    }
+
+    private static final long serialVersionUID = -2520155553543391200L;
+}
diff --git a/java/sql/SQLTransientException.java b/java/sql/SQLTransientException.java
new file mode 100644
index 0000000..644be1b
--- /dev/null
+++ b/java/sql/SQLTransientException.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The subclass of {@link SQLException} is thrown in situations where a
+ * previoulsy failed operation might be able to succeed when the operation is
+ * retried without any intervention by application-level functionality.
+ *<p>
+ *
+ * @since 1.6
+ */
+public class SQLTransientException extends java.sql.SQLException {
+
+        /**
+         * Constructs a <code>SQLTransientException</code> object.
+         * The <code>reason</code>, <code>SQLState</code> are initialized
+         * to <code>null</code> and the vendor code is initialized to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @since 1.6
+        */
+        public SQLTransientException() {
+                super();
+        }
+
+        /**
+         * Constructs a <code>SQLTransientException</code> object
+         *  with a given <code>reason</code>. The <code>SQLState</code>
+         * is initialized to <code>null</code> and the vender code is initialized
+         * to 0.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @since 1.6
+         */
+        public SQLTransientException(String reason) {
+                super(reason);
+        }
+
+        /**
+         * Constructs a <code>SQLTransientException</code> object
+         * with a given <code>reason</code> and <code>SQLState</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+         * is initialized to 0.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @since 1.6
+         */
+        public SQLTransientException(String reason, String SQLState) {
+                super(reason,SQLState);
+        }
+
+        /**
+         * Constructs a <code>SQLTransientException</code> object
+         *  with a given <code>reason</code>, <code>SQLState</code>  and
+         * <code>vendorCode</code>.
+         *
+         * The <code>cause</code> is not initialized, and may subsequently be
+         * initialized by a call to the
+         * {@link Throwable#initCause(java.lang.Throwable)} method.
+         * <p>
+         * @param reason a description of the exception
+         * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+         * @param vendorCode a database vendor specific exception code
+         * @since 1.6
+         */
+        public SQLTransientException(String reason, String SQLState, int vendorCode) {
+                super(reason,SQLState,vendorCode);
+        }
+
+    /**
+     * Constructs a <code>SQLTransientException</code> object
+     * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransientException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransientException</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransientException(String reason, Throwable cause) {
+        super(reason,cause);
+    }
+
+    /**
+     * Constructs a <code>SQLTransientException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the exception.
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransientException(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+    }
+
+    /**
+     *  Constructs a <code>SQLTransientException</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the exception
+     * @param SQLState an XOPEN or SQL:2003 code identifying the exception
+     * @param vendorCode a database vendor-specific exception code
+     * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     * @since 1.6
+     */
+    public SQLTransientException(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+    }
+
+    private static final long serialVersionUID = -9042733978262274539L;
+}
diff --git a/java/sql/SQLWarning.java b/java/sql/SQLWarning.java
new file mode 100644
index 0000000..3c88ba0
--- /dev/null
+++ b/java/sql/SQLWarning.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <P>An exception that provides information on  database access
+ * warnings. Warnings are silently chained to the object whose method
+ * caused it to be reported.
+ * <P>
+ * Warnings may be retrieved from <code>Connection</code>, <code>Statement</code>,
+ * and <code>ResultSet</code> objects.  Trying to retrieve a warning on a
+ * connection after it has been closed will cause an exception to be thrown.
+ * Similarly, trying to retrieve a warning on a statement after it has been
+ * closed or on a result set after it has been closed will cause
+ * an exception to be thrown. Note that closing a statement also
+ * closes a result set that it might have produced.
+ *
+ * @see Connection#getWarnings
+ * @see Statement#getWarnings
+ * @see ResultSet#getWarnings
+ */
+public class SQLWarning extends SQLException {
+
+    /**
+     * Constructs a  <code>SQLWarning</code> object
+     *  with a given <code>reason</code>, <code>SQLState</code>  and
+     * <code>vendorCode</code>.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     * @param reason a description of the warning
+     * @param SQLState an XOPEN or SQL:2003 code identifying the warning
+     * @param vendorCode a database vendor-specific warning code
+     */
+     public SQLWarning(String reason, String SQLState, int vendorCode) {
+        super(reason, SQLState, vendorCode);
+        DriverManager.println("SQLWarning: reason(" + reason +
+                              ") SQLState(" + SQLState +
+                              ") vendor code(" + vendorCode + ")");
+    }
+
+
+    /**
+     * Constructs a <code>SQLWarning</code> object
+     * with a given <code>reason</code> and <code>SQLState</code>.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
+     * is initialized to 0.
+     * <p>
+     * @param reason a description of the warning
+     * @param SQLState an XOPEN or SQL:2003 code identifying the warning
+     */
+    public SQLWarning(String reason, String SQLState) {
+        super(reason, SQLState);
+        DriverManager.println("SQLWarning: reason(" + reason +
+                                  ") SQLState(" + SQLState + ")");
+    }
+
+    /**
+     * Constructs a <code>SQLWarning</code> object
+     * with a given <code>reason</code>. The <code>SQLState</code>
+     * is initialized to <code>null</code> and the vender code is initialized
+     * to 0.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     * @param reason a description of the warning
+     */
+    public SQLWarning(String reason) {
+        super(reason);
+        DriverManager.println("SQLWarning: reason(" + reason + ")");
+    }
+
+    /**
+     * Constructs a  <code>SQLWarning</code> object.
+     * The <code>reason</code>, <code>SQLState</code> are initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     *
+     * The <code>cause</code> is not initialized, and may subsequently be
+     * initialized by a call to the
+     * {@link Throwable#initCause(java.lang.Throwable)} method.
+     * <p>
+     */
+    public SQLWarning() {
+        super();
+        DriverManager.println("SQLWarning: ");
+    }
+
+    /**
+     * Constructs a <code>SQLWarning</code> object
+     * with a given  <code>cause</code>.
+     * The <code>SQLState</code> is initialized
+     * to <code>null</code> and the vendor code is initialized to 0.
+     * The <code>reason</code>  is initialized to <code>null</code> if
+     * <code>cause==null</code> or to <code>cause.toString()</code> if
+     * <code>cause!=null</code>.
+     * <p>
+     * @param cause the underlying reason for this <code>SQLWarning</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     */
+    public SQLWarning(Throwable cause) {
+        super(cause);
+        DriverManager.println("SQLWarning");
+    }
+
+    /**
+     * Constructs a <code>SQLWarning</code> object
+     * with a given
+     * <code>reason</code> and  <code>cause</code>.
+     * The <code>SQLState</code> is  initialized to <code>null</code>
+     * and the vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the warning
+     * @param cause  the underlying reason for this <code>SQLWarning</code>
+     * (which is saved for later retrieval by the <code>getCause()</code> method);
+     * may be null indicating the cause is non-existent or unknown.
+     */
+    public SQLWarning(String reason, Throwable cause) {
+        super(reason,cause);
+        DriverManager.println("SQLWarning : reason("+ reason + ")");
+    }
+
+    /**
+     * Constructs a <code>SQLWarning</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code> and  <code>cause</code>.
+     * The vendor code is initialized to 0.
+     * <p>
+     * @param reason a description of the warning
+     * @param SQLState an XOPEN or SQL:2003 code identifying the warning
+     * @param cause the underlying reason for this <code>SQLWarning</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     */
+    public SQLWarning(String reason, String SQLState, Throwable cause) {
+        super(reason,SQLState,cause);
+        DriverManager.println("SQLWarning: reason(" + reason +
+                                  ") SQLState(" + SQLState + ")");
+    }
+
+    /**
+     * Constructs a<code>SQLWarning</code> object
+     * with a given
+     * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
+     * and  <code>cause</code>.
+     * <p>
+     * @param reason a description of the warning
+     * @param SQLState an XOPEN or SQL:2003 code identifying the warning
+     * @param vendorCode a database vendor-specific warning code
+     * @param cause the underlying reason for this <code>SQLWarning</code> (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
+     *     the cause is non-existent or unknown.
+     */
+    public SQLWarning(String reason, String SQLState, int vendorCode, Throwable cause) {
+        super(reason,SQLState,vendorCode,cause);
+        DriverManager.println("SQLWarning: reason(" + reason +
+                              ") SQLState(" + SQLState +
+                              ") vendor code(" + vendorCode + ")");
+
+    }
+    /**
+     * Retrieves the warning chained to this <code>SQLWarning</code> object by
+     * <code>setNextWarning</code>.
+     *
+     * @return the next <code>SQLException</code> in the chain; <code>null</code> if none
+     * @see #setNextWarning
+     */
+    public SQLWarning getNextWarning() {
+        try {
+            return ((SQLWarning)getNextException());
+        } catch (ClassCastException ex) {
+            // The chained value isn't a SQLWarning.
+            // This is a programming error by whoever added it to
+            // the SQLWarning chain.  We throw a Java "Error".
+            throw new Error("SQLWarning chain holds value that is not a SQLWarning");
+        }
+    }
+
+    /**
+     * Adds a <code>SQLWarning</code> object to the end of the chain.
+     *
+     * @param w the new end of the <code>SQLException</code> chain
+     * @see #getNextWarning
+     */
+    public void setNextWarning(SQLWarning w) {
+        setNextException(w);
+    }
+
+    private static final long serialVersionUID = 3917336774604784856L;
+}
diff --git a/java/sql/SQLXML.java b/java/sql/SQLXML.java
new file mode 100644
index 0000000..e27edf5
--- /dev/null
+++ b/java/sql/SQLXML.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+
+// Android-changed: Removed @see tag (target does not exist on Android):
+// @see javax.xml.stream
+/**
+ * The mapping in the JavaTM programming language for the SQL XML type.
+ * XML is a built-in type that stores an XML value
+ * as a column value in a row of a database table.
+ * By default drivers implement an SQLXML object as
+ * a logical pointer to the XML data
+ * rather than the data itself.
+ * An SQLXML object is valid for the duration of the transaction in which it was created.
+ * <p>
+ * The SQLXML interface provides methods for accessing the XML value
+ * as a String, a Reader or Writer, or as a Stream.  The XML value
+ * may also be accessed through a Source or set as a Result, which
+ * are used with XML Parser APIs such as DOM, SAX, and StAX, as
+ * well as with XSLT transforms and XPath evaluations.
+ * <p>
+ * Methods in the interfaces ResultSet, CallableStatement, and PreparedStatement,
+ * such as getSQLXML allow a programmer to access an XML value.
+ * In addition, this interface has methods for updating an XML value.
+ * <p>
+ * The XML value of the SQLXML instance may be obtained as a BinaryStream using
+ * <pre>
+ *   SQLXML sqlxml = resultSet.getSQLXML(column);
+ *   InputStream binaryStream = sqlxml.getBinaryStream();
+ * </pre>
+ * For example, to parse an XML value with a DOM parser:
+ * <pre>
+ *   DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ *   Document result = parser.parse(binaryStream);
+ * </pre>
+ * or to parse an XML value with a SAX parser to your handler:
+ * <pre>
+ *   SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
+ *   parser.parse(binaryStream, myHandler);
+ * </pre>
+ * or to parse an XML value with a StAX parser:
+ * <pre>
+ *   XMLInputFactory factory = XMLInputFactory.newInstance();
+ *   XMLStreamReader streamReader = factory.createXMLStreamReader(binaryStream);
+ * </pre>
+ * <p>
+ * Because databases may use an optimized representation for the XML,
+ * accessing the value through getSource() and
+ * setResult() can lead to improved processing performance
+ * without serializing to a stream representation and parsing the XML.
+ * <p>
+ * For example, to obtain a DOM Document Node:
+ * <pre>
+ *   DOMSource domSource = sqlxml.getSource(DOMSource.class);
+ *   Document document = (Document) domSource.getNode();
+ * </pre>
+ * or to set the value to a DOM Document Node to myNode:
+ * <pre>
+ *   DOMResult domResult = sqlxml.setResult(DOMResult.class);
+ *   domResult.setNode(myNode);
+ * </pre>
+ * or, to send SAX events to your handler:
+ * <pre>
+ *   SAXSource saxSource = sqlxml.getSource(SAXSource.class);
+ *   XMLReader xmlReader = saxSource.getXMLReader();
+ *   xmlReader.setContentHandler(myHandler);
+ *   xmlReader.parse(saxSource.getInputSource());
+ * </pre>
+ * or, to set the result value from SAX events:
+ * <pre>
+ *   SAXResult saxResult = sqlxml.setResult(SAXResult.class);
+ *   ContentHandler contentHandler = saxResult.getXMLReader().getContentHandler();
+ *   contentHandler.startDocument();
+ *   // set the XML elements and attributes into the result
+ *   contentHandler.endDocument();
+ * </pre>
+ * or, to obtain StAX events:
+ * <pre>
+ *   StAXSource staxSource = sqlxml.getSource(StAXSource.class);
+ *   XMLStreamReader streamReader = staxSource.getXMLStreamReader();
+ * </pre>
+ * or, to set the result value from StAX events:
+ * <pre>
+ *   StAXResult staxResult = sqlxml.setResult(StAXResult.class);
+ *   XMLStreamWriter streamWriter = staxResult.getXMLStreamWriter();
+ * </pre>
+ * or, to perform XSLT transformations on the XML value using the XSLT in xsltFile
+ * output to file resultFile:
+ * <pre>
+ *   File xsltFile = new File("a.xslt");
+ *   File myFile = new File("result.xml");
+ *   Transformer xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltFile));
+ *   Source source = sqlxml.getSource(null);
+ *   Result result = new StreamResult(myFile);
+ *   xslt.transform(source, result);
+ * </pre>
+ * or, to evaluate an XPath expression on the XML value:
+ * <pre>
+ *   XPath xpath = XPathFactory.newInstance().newXPath();
+ *   DOMSource domSource = sqlxml.getSource(DOMSource.class);
+ *   Document document = (Document) domSource.getNode();
+ *   String expression = "/foo/@bar";
+ *   String barValue = xpath.evaluate(expression, document);
+ * </pre>
+ * To set the XML value to be the result of an XSLT transform:
+ * <pre>
+ *   File sourceFile = new File("source.xml");
+ *   Transformer xslt = TransformerFactory.newInstance().newTransformer(new StreamSource(xsltFile));
+ *   Source streamSource = new StreamSource(sourceFile);
+ *   Result result = sqlxml.setResult(null);
+ *   xslt.transform(streamSource, result);
+ * </pre>
+ * Any Source can be transformed to a Result using the identity transform
+ * specified by calling newTransformer():
+ * <pre>
+ *   Transformer identity = TransformerFactory.newInstance().newTransformer();
+ *   Source source = sqlxml.getSource(null);
+ *   File myFile = new File("result.xml");
+ *   Result result = new StreamResult(myFile);
+ *   identity.transform(source, result);
+ * </pre>
+ * To write the contents of a Source to standard output:
+ * <pre>
+ *   Transformer identity = TransformerFactory.newInstance().newTransformer();
+ *   Source source = sqlxml.getSource(null);
+ *   Result result = new StreamResult(System.out);
+ *   identity.transform(source, result);
+ * </pre>
+ * To create a DOMSource from a DOMResult:
+ * <pre>
+ *    DOMSource domSource = new DOMSource(domResult.getNode());
+ * </pre>
+ * <p>
+ * Incomplete or invalid XML values may cause an SQLException when
+ * set or the exception may occur when execute() occurs.  All streams
+ * must be closed before execute() occurs or an SQLException will be thrown.
+ * <p>
+ * Reading and writing XML values to or from an SQLXML object can happen at most once.
+ * The conceptual states of readable and not readable determine if one
+ * of the reading APIs will return a value or throw an exception.
+ * The conceptual states of writable and not writable determine if one
+ * of the writing APIs will set a value or throw an exception.
+ * <p>
+ * The state moves from readable to not readable once free() or any of the
+ * reading APIs are called: getBinaryStream(), getCharacterStream(), getSource(), and getString().
+ * Implementations may also change the state to not writable when this occurs.
+ * <p>
+ * The state moves from writable to not writeable once free() or any of the
+ * writing APIs are called: setBinaryStream(), setCharacterStream(), setResult(), and setString().
+ * Implementations may also change the state to not readable when this occurs.
+ * <p>
+  * <p>
+ * All methods on the <code>SQLXML</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ *
+ * @see javax.xml.parsers
+ * @see javax.xml.transform
+ * @see javax.xml.xpath
+ * @since 1.6
+ */
+public interface SQLXML
+{
+  /**
+   * This method closes this object and releases the resources that it held.
+   * The SQL XML object becomes invalid and neither readable or writeable
+   * when this method is called.
+   *
+   * After <code>free</code> has been called, any attempt to invoke a
+   * method other than <code>free</code> will result in a <code>SQLException</code>
+   * being thrown.  If <code>free</code> is called multiple times, the subsequent
+   * calls to <code>free</code> are treated as a no-op.
+   * @throws SQLException if there is an error freeing the XML value.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  void free() throws SQLException;
+
+  /**
+   * Retrieves the XML value designated by this SQLXML instance as a stream.
+   * The bytes of the input stream are interpreted according to appendix F of the XML 1.0 specification.
+   * The behavior of this method is the same as ResultSet.getBinaryStream()
+   * when the designated column of the ResultSet has a type java.sql.Types of SQLXML.
+   * <p>
+   * The SQL XML object becomes not readable when this method is called and
+   * may also become not writable depending on implementation.
+   *
+   * @return a stream containing the XML data.
+   * @throws SQLException if there is an error processing the XML value.
+   *   An exception is thrown if the state is not readable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  InputStream getBinaryStream() throws SQLException;
+
+  /**
+   * Retrieves a stream that can be used to write the XML value that this SQLXML instance represents.
+   * The stream begins at position 0.
+   * The bytes of the stream are interpreted according to appendix F of the XML 1.0 specification
+   * The behavior of this method is the same as ResultSet.updateBinaryStream()
+   * when the designated column of the ResultSet has a type java.sql.Types of SQLXML.
+   * <p>
+   * The SQL XML object becomes not writeable when this method is called and
+   * may also become not readable depending on implementation.
+   *
+   * @return a stream to which data can be written.
+   * @throws SQLException if there is an error processing the XML value.
+   *   An exception is thrown if the state is not writable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  OutputStream setBinaryStream() throws SQLException;
+
+  /**
+   * Retrieves the XML value designated by this SQLXML instance as a java.io.Reader object.
+   * The format of this stream is defined by org.xml.sax.InputSource,
+   * where the characters in the stream represent the unicode code points for
+   * XML according to section 2 and appendix B of the XML 1.0 specification.
+   * Although an encoding declaration other than unicode may be present,
+   * the encoding of the stream is unicode.
+   * The behavior of this method is the same as ResultSet.getCharacterStream()
+   * when the designated column of the ResultSet has a type java.sql.Types of SQLXML.
+   * <p>
+   * The SQL XML object becomes not readable when this method is called and
+   * may also become not writable depending on implementation.
+   *
+   * @return a stream containing the XML data.
+   * @throws SQLException if there is an error processing the XML value.
+   *   The getCause() method of the exception may provide a more detailed exception, for example,
+   *   if the stream does not contain valid characters.
+   *   An exception is thrown if the state is not readable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  Reader getCharacterStream() throws SQLException;
+
+  /**
+   * Retrieves a stream to be used to write the XML value that this SQLXML instance represents.
+   * The format of this stream is defined by org.xml.sax.InputSource,
+   * where the characters in the stream represent the unicode code points for
+   * XML according to section 2 and appendix B of the XML 1.0 specification.
+   * Although an encoding declaration other than unicode may be present,
+   * the encoding of the stream is unicode.
+   * The behavior of this method is the same as ResultSet.updateCharacterStream()
+   * when the designated column of the ResultSet has a type java.sql.Types of SQLXML.
+   * <p>
+   * The SQL XML object becomes not writeable when this method is called and
+   * may also become not readable depending on implementation.
+   *
+   * @return a stream to which data can be written.
+   * @throws SQLException if there is an error processing the XML value.
+   *   The getCause() method of the exception may provide a more detailed exception, for example,
+   *   if the stream does not contain valid characters.
+   *   An exception is thrown if the state is not writable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  Writer setCharacterStream() throws SQLException;
+
+  /**
+   * Returns a string representation of the XML value designated by this SQLXML instance.
+   * The format of this String is defined by org.xml.sax.InputSource,
+   * where the characters in the stream represent the unicode code points for
+   * XML according to section 2 and appendix B of the XML 1.0 specification.
+   * Although an encoding declaration other than unicode may be present,
+   * the encoding of the String is unicode.
+   * The behavior of this method is the same as ResultSet.getString()
+   * when the designated column of the ResultSet has a type java.sql.Types of SQLXML.
+   * <p>
+   * The SQL XML object becomes not readable when this method is called and
+   * may also become not writable depending on implementation.
+   *
+   * @return a string representation of the XML value designated by this SQLXML instance.
+   * @throws SQLException if there is an error processing the XML value.
+   *   The getCause() method of the exception may provide a more detailed exception, for example,
+   *   if the stream does not contain valid characters.
+   *   An exception is thrown if the state is not readable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  String getString() throws SQLException;
+
+  /**
+   * Sets the XML value designated by this SQLXML instance to the given String representation.
+   * The format of this String is defined by org.xml.sax.InputSource,
+   * where the characters in the stream represent the unicode code points for
+   * XML according to section 2 and appendix B of the XML 1.0 specification.
+   * Although an encoding declaration other than unicode may be present,
+   * the encoding of the String is unicode.
+   * The behavior of this method is the same as ResultSet.updateString()
+   * when the designated column of the ResultSet has a type java.sql.Types of SQLXML.
+   * <p>
+   * The SQL XML object becomes not writeable when this method is called and
+   * may also become not readable depending on implementation.
+   *
+   * @param value the XML value
+   * @throws SQLException if there is an error processing the XML value.
+   *   The getCause() method of the exception may provide a more detailed exception, for example,
+   *   if the stream does not contain valid characters.
+   *   An exception is thrown if the state is not writable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  void setString(String value) throws SQLException;
+
+  /**
+   * Returns a Source for reading the XML value designated by this SQLXML instance.
+   * Sources are used as inputs to XML parsers and XSLT transformers.
+   * <p>
+   * Sources for XML parsers will have namespace processing on by default.
+   * The systemID of the Source is implementation dependent.
+   * <p>
+   * The SQL XML object becomes not readable when this method is called and
+   * may also become not writable depending on implementation.
+   * <p>
+   * Note that SAX is a callback architecture, so a returned
+   * SAXSource should then be set with a content handler that will
+   * receive the SAX events from parsing.  The content handler
+   * will receive callbacks based on the contents of the XML.
+   * <pre>
+   *   SAXSource saxSource = sqlxml.getSource(SAXSource.class);
+   *   XMLReader xmlReader = saxSource.getXMLReader();
+   *   xmlReader.setContentHandler(myHandler);
+   *   xmlReader.parse(saxSource.getInputSource());
+   * </pre>
+   *
+   * @param sourceClass The class of the source, or null.
+   * If the class is null, a vendor specifc Source implementation will be returned.
+   * The following classes are supported at a minimum:
+   * <pre>
+   *   javax.xml.transform.dom.DOMSource - returns a DOMSource
+   *   javax.xml.transform.sax.SAXSource - returns a SAXSource
+   *   javax.xml.transform.stax.StAXSource - returns a StAXSource
+   *   javax.xml.transform.stream.StreamSource - returns a StreamSource
+   * </pre>
+   * @return a Source for reading the XML value.
+   * @throws SQLException if there is an error processing the XML value
+   *   or if this feature is not supported.
+   *   The getCause() method of the exception may provide a more detailed exception, for example,
+   *   if an XML parser exception occurs.
+   *   An exception is thrown if the state is not readable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  <T extends Source> T getSource(Class<T> sourceClass) throws SQLException;
+
+  /**
+   * Returns a Result for setting the XML value designated by this SQLXML instance.
+   * <p>
+   * The systemID of the Result is implementation dependent.
+   * <p>
+   * The SQL XML object becomes not writeable when this method is called and
+   * may also become not readable depending on implementation.
+   * <p>
+   * Note that SAX is a callback architecture and the returned
+   * SAXResult has a content handler assigned that will receive the
+   * SAX events based on the contents of the XML.  Call the content
+   * handler with the contents of the XML document to assign the values.
+   * <pre>
+   *   SAXResult saxResult = sqlxml.setResult(SAXResult.class);
+   *   ContentHandler contentHandler = saxResult.getXMLReader().getContentHandler();
+   *   contentHandler.startDocument();
+   *   // set the XML elements and attributes into the result
+   *   contentHandler.endDocument();
+   * </pre>
+   *
+   * @param resultClass The class of the result, or null.
+   * If resultClass is null, a vendor specific Result implementation will be returned.
+   * The following classes are supported at a minimum:
+   * <pre>
+   *   javax.xml.transform.dom.DOMResult - returns a DOMResult
+   *   javax.xml.transform.sax.SAXResult - returns a SAXResult
+   *   javax.xml.transform.stax.StAXResult - returns a StAXResult
+   *   javax.xml.transform.stream.StreamResult - returns a StreamResult
+   * </pre>
+   * @return Returns a Result for setting the XML value.
+   * @throws SQLException if there is an error processing the XML value
+   *   or if this feature is not supported.
+   *   The getCause() method of the exception may provide a more detailed exception, for example,
+   *   if an XML parser exception occurs.
+   *   An exception is thrown if the state is not writable.
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.6
+   */
+  <T extends Result> T setResult(Class<T> resultClass) throws SQLException;
+
+}
diff --git a/java/sql/Savepoint.java b/java/sql/Savepoint.java
new file mode 100644
index 0000000..07d1ae1
--- /dev/null
+++ b/java/sql/Savepoint.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * The representation of a savepoint, which is a point within
+ * the current transaction that can be referenced from the
+ * <code>Connection.rollback</code> method. When a transaction
+ * is rolled back to a savepoint all changes made after that
+ * savepoint are undone.
+ * <p>
+ * Savepoints can be either named or unnamed. Unnamed savepoints
+ * are identified by an ID generated by the underlying data source.
+ *
+ * @since 1.4
+ */
+
+public interface Savepoint {
+
+    /**
+     * Retrieves the generated ID for the savepoint that this
+     * <code>Savepoint</code> object represents.
+     * @return the numeric ID of this savepoint
+     * @exception SQLException if this is a named savepoint
+     * @since 1.4
+     */
+    int getSavepointId() throws SQLException;
+
+    /**
+     * Retrieves the name of the savepoint that this <code>Savepoint</code>
+     * object represents.
+     * @return the name of this savepoint
+     * @exception SQLException if this is an un-named savepoint
+     * @since 1.4
+     */
+    String getSavepointName() throws SQLException;
+}
diff --git a/java/sql/Statement.java b/java/sql/Statement.java
new file mode 100644
index 0000000..5915114
--- /dev/null
+++ b/java/sql/Statement.java
@@ -0,0 +1,1035 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <P>The object used for executing a static SQL statement
+ * and returning the results it produces.
+ * <P>
+ * By default, only one <code>ResultSet</code> object per <code>Statement</code>
+ * object can be open at the same time. Therefore, if the reading of one
+ * <code>ResultSet</code> object is interleaved
+ * with the reading of another, each must have been generated by
+ * different <code>Statement</code> objects. All execution methods in the
+ * <code>Statement</code> interface implicitly close a statment's current
+ * <code>ResultSet</code> object if an open one exists.
+ *
+ * @see Connection#createStatement
+ * @see ResultSet
+ */
+public interface Statement extends Wrapper, AutoCloseable {
+
+    /**
+     * Executes the given SQL statement, which returns a single
+     * <code>ResultSet</code> object.
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql an SQL statement to be sent to the database, typically a
+     *        static SQL <code>SELECT</code> statement
+     * @return a <code>ResultSet</code> object that contains the data produced
+     *         by the given query; never <code>null</code>
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>, the given
+     *            SQL statement produces anything other than a single
+     *            <code>ResultSet</code> object, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     */
+    ResultSet executeQuery(String sql) throws SQLException;
+
+    /**
+     * Executes the given SQL statement, which may be an <code>INSERT</code>,
+     * <code>UPDATE</code>, or <code>DELETE</code> statement or an
+     * SQL statement that returns nothing, such as an SQL DDL statement.
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
+     * <code>DELETE</code>; or an SQL statement that returns nothing,
+     * such as a DDL statement.
+     *
+     * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+     *         or (2) 0 for SQL statements that return nothing
+     *
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>, the given
+     * SQL statement produces a <code>ResultSet</code> object, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     */
+    int executeUpdate(String sql) throws SQLException;
+
+    /**
+     * Releases this <code>Statement</code> object's database
+     * and JDBC resources immediately instead of waiting for
+     * this to happen when it is automatically closed.
+     * It is generally good practice to release resources as soon as
+     * you are finished with them to avoid tying up database
+     * resources.
+     * <P>
+     * Calling the method <code>close</code> on a <code>Statement</code>
+     * object that is already closed has no effect.
+     * <P>
+     * <B>Note:</B>When a <code>Statement</code> object is
+     * closed, its current <code>ResultSet</code> object, if one exists, is
+     * also closed.
+     *
+     * @exception SQLException if a database access error occurs
+     */
+    void close() throws SQLException;
+
+    //----------------------------------------------------------------------
+
+    /**
+     * Retrieves the maximum number of bytes that can be
+     * returned for character and binary column values in a <code>ResultSet</code>
+     * object produced by this <code>Statement</code> object.
+     * This limit applies only to  <code>BINARY</code>, <code>VARBINARY</code>,
+     * <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>,
+     * <code>NCHAR</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code>
+     * and <code>LONGVARCHAR</code> columns.  If the limit is exceeded, the
+     * excess data is silently discarded.
+     *
+     * @return the current column size limit for columns storing character and
+     *         binary values; zero means there is no limit
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @see #setMaxFieldSize
+     */
+    int getMaxFieldSize() throws SQLException;
+
+    /**
+     * Sets the limit for the maximum number of bytes that can be returned for
+     * character and binary column values in a <code>ResultSet</code>
+     * object produced by this <code>Statement</code> object.
+     *
+     * This limit applies
+     * only to <code>BINARY</code>, <code>VARBINARY</code>,
+     * <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>,
+     * <code>NCHAR</code>, <code>NVARCHAR</code>, <code>LONGNVARCHAR</code> and
+     * <code>LONGVARCHAR</code> fields.  If the limit is exceeded, the excess data
+     * is silently discarded. For maximum portability, use values
+     * greater than 256.
+     *
+     * @param max the new column size limit in bytes; zero means there is no limit
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>
+     *            or the condition max >= 0 is not satisfied
+     * @see #getMaxFieldSize
+     */
+    void setMaxFieldSize(int max) throws SQLException;
+
+    /**
+     * Retrieves the maximum number of rows that a
+     * <code>ResultSet</code> object produced by this
+     * <code>Statement</code> object can contain.  If this limit is exceeded,
+     * the excess rows are silently dropped.
+     *
+     * @return the current maximum number of rows for a <code>ResultSet</code>
+     *         object produced by this <code>Statement</code> object;
+     *         zero means there is no limit
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @see #setMaxRows
+     */
+    int getMaxRows() throws SQLException;
+
+    /**
+     * Sets the limit for the maximum number of rows that any
+     * <code>ResultSet</code> object  generated by this <code>Statement</code>
+     * object can contain to the given number.
+     * If the limit is exceeded, the excess
+     * rows are silently dropped.
+     *
+     * @param max the new max rows limit; zero means there is no limit
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>
+     *            or the condition max >= 0 is not satisfied
+     * @see #getMaxRows
+     */
+    void setMaxRows(int max) throws SQLException;
+
+    /**
+     * Sets escape processing on or off.
+     * If escape scanning is on (the default), the driver will do
+     * escape substitution before sending the SQL statement to the database.
+     *
+     * Note: Since prepared statements have usually been parsed prior
+     * to making this call, disabling escape processing for
+     * <code>PreparedStatements</code> objects will have no effect.
+     *
+     * @param enable <code>true</code> to enable escape processing;
+     *       <code>false</code> to disable it
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     */
+    void setEscapeProcessing(boolean enable) throws SQLException;
+
+    /**
+     * Retrieves the number of seconds the driver will
+     * wait for a <code>Statement</code> object to execute.
+     * If the limit is exceeded, a
+     * <code>SQLException</code> is thrown.
+     *
+     * @return the current query timeout limit in seconds; zero means there is
+     *         no limit
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @see #setQueryTimeout
+     */
+    int getQueryTimeout() throws SQLException;
+
+    /**
+     * Sets the number of seconds the driver will wait for a
+     * <code>Statement</code> object to execute to the given number of seconds.
+     *By default there is no limit on the amount of time allowed for a running
+     * statement to complete. If the limit is exceeded, an
+     * <code>SQLTimeoutException</code> is thrown.
+     * A JDBC driver must apply this limit to the <code>execute</code>,
+     * <code>executeQuery</code> and <code>executeUpdate</code> methods.
+     * <p>
+     * <strong>Note:</strong> JDBC driver implementations may also apply this
+     * limit to {@code ResultSet} methods
+     * (consult your driver vendor documentation for details).
+     * <p>
+     * <strong>Note:</strong> In the case of {@code Statement} batching, it is
+     * implementation defined as to whether the time-out is applied to
+     * individual SQL commands added via the {@code addBatch} method or to
+     * the entire batch of SQL commands invoked by the {@code executeBatch}
+     * method (consult your driver vendor documentation for details).
+     *
+     * @param seconds the new query timeout limit in seconds; zero means
+     *        there is no limit
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>
+     *            or the condition seconds >= 0 is not satisfied
+     * @see #getQueryTimeout
+     */
+    void setQueryTimeout(int seconds) throws SQLException;
+
+    /**
+     * Cancels this <code>Statement</code> object if both the DBMS and
+     * driver support aborting an SQL statement.
+     * This method can be used by one thread to cancel a statement that
+     * is being executed by another thread.
+     *
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method
+     */
+    void cancel() throws SQLException;
+
+    /**
+     * Retrieves the first warning reported by calls on this <code>Statement</code> object.
+     * Subsequent <code>Statement</code> object warnings will be chained to this
+     * <code>SQLWarning</code> object.
+     *
+     * <p>The warning chain is automatically cleared each time
+     * a statement is (re)executed. This method may not be called on a closed
+     * <code>Statement</code> object; doing so will cause an <code>SQLException</code>
+     * to be thrown.
+     *
+     * <P><B>Note:</B> If you are processing a <code>ResultSet</code> object, any
+     * warnings associated with reads on that <code>ResultSet</code> object
+     * will be chained on it rather than on the <code>Statement</code>
+     * object that produced it.
+     *
+     * @return the first <code>SQLWarning</code> object or <code>null</code>
+     *         if there are no warnings
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     */
+    SQLWarning getWarnings() throws SQLException;
+
+    /**
+     * Clears all the warnings reported on this <code>Statement</code>
+     * object. After a call to this method,
+     * the method <code>getWarnings</code> will return
+     * <code>null</code> until a new warning is reported for this
+     * <code>Statement</code> object.
+     *
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     */
+    void clearWarnings() throws SQLException;
+
+    /**
+     * Sets the SQL cursor name to the given <code>String</code>, which
+     * will be used by subsequent <code>Statement</code> object
+     * <code>execute</code> methods. This name can then be
+     * used in SQL positioned update or delete statements to identify the
+     * current row in the <code>ResultSet</code> object generated by this
+     * statement.  If the database does not support positioned update/delete,
+     * this method is a noop.  To insure that a cursor has the proper isolation
+     * level to support updates, the cursor's <code>SELECT</code> statement
+     * should have the form <code>SELECT FOR UPDATE</code>.  If
+     * <code>FOR UPDATE</code> is not present, positioned updates may fail.
+     *
+     * <P><B>Note:</B> By definition, the execution of positioned updates and
+     * deletes must be done by a different <code>Statement</code> object than
+     * the one that generated the <code>ResultSet</code> object being used for
+     * positioning. Also, cursor names must be unique within a connection.
+     *
+     * @param name the new cursor name, which must be unique within
+     *             a connection
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     */
+    void setCursorName(String name) throws SQLException;
+
+    //----------------------- Multiple Results --------------------------
+
+    /**
+     * Executes the given SQL statement, which may return multiple results.
+     * In some (uncommon) situations, a single SQL statement may return
+     * multiple result sets and/or update counts.  Normally you can ignore
+     * this unless you are (1) executing a stored procedure that you know may
+     * return multiple results or (2) you are dynamically executing an
+     * unknown SQL string.
+     * <P>
+     * The <code>execute</code> method executes an SQL statement and indicates the
+     * form of the first result.  You must then use the methods
+     * <code>getResultSet</code> or <code>getUpdateCount</code>
+     * to retrieve the result, and <code>getMoreResults</code> to
+     * move to any subsequent result(s).
+     * <p>
+     *<strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql any SQL statement
+     * @return <code>true</code> if the first result is a <code>ResultSet</code>
+     *         object; <code>false</code> if it is an update count or there are
+     *         no results
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>,
+     * the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @see #getResultSet
+     * @see #getUpdateCount
+     * @see #getMoreResults
+     */
+    boolean execute(String sql) throws SQLException;
+
+    /**
+     *  Retrieves the current result as a <code>ResultSet</code> object.
+     *  This method should be called only once per result.
+     *
+     * @return the current result as a <code>ResultSet</code> object or
+     * <code>null</code> if the result is an update count or there are no more results
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @see #execute
+     */
+    ResultSet getResultSet() throws SQLException;
+
+    /**
+     *  Retrieves the current result as an update count;
+     *  if the result is a <code>ResultSet</code> object or there are no more results, -1
+     *  is returned. This method should be called only once per result.
+     *
+     * @return the current result as an update count; -1 if the current result is a
+     * <code>ResultSet</code> object or there are no more results
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @see #execute
+     */
+    int getUpdateCount() throws SQLException;
+
+    /**
+     * Moves to this <code>Statement</code> object's next result, returns
+     * <code>true</code> if it is a <code>ResultSet</code> object, and
+     * implicitly closes any current <code>ResultSet</code>
+     * object(s) obtained with the method <code>getResultSet</code>.
+     *
+     * <P>There are no more results when the following is true:
+     * <PRE>
+     *     // stmt is a Statement object
+     *     ((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
+     * </PRE>
+     *
+     * @return <code>true</code> if the next result is a <code>ResultSet</code>
+     *         object; <code>false</code> if it is an update count or there are
+     *         no more results
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @see #execute
+     */
+    boolean getMoreResults() throws SQLException;
+
+
+    //--------------------------JDBC 2.0-----------------------------
+
+
+    /**
+     * Gives the driver a hint as to the direction in which
+     * rows will be processed in <code>ResultSet</code>
+     * objects created using this <code>Statement</code> object.  The
+     * default value is <code>ResultSet.FETCH_FORWARD</code>.
+     * <P>
+     * Note that this method sets the default fetch direction for
+     * result sets generated by this <code>Statement</code> object.
+     * Each result set has its own methods for getting and setting
+     * its own fetch direction.
+     *
+     * @param direction the initial direction for processing rows
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>
+     * or the given direction
+     * is not one of <code>ResultSet.FETCH_FORWARD</code>,
+     * <code>ResultSet.FETCH_REVERSE</code>, or <code>ResultSet.FETCH_UNKNOWN</code>
+     * @since 1.2
+     * @see #getFetchDirection
+     */
+    void setFetchDirection(int direction) throws SQLException;
+
+    /**
+     * Retrieves the direction for fetching rows from
+     * database tables that is the default for result sets
+     * generated from this <code>Statement</code> object.
+     * If this <code>Statement</code> object has not set
+     * a fetch direction by calling the method <code>setFetchDirection</code>,
+     * the return value is implementation-specific.
+     *
+     * @return the default fetch direction for result sets generated
+     *          from this <code>Statement</code> object
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @since 1.2
+     * @see #setFetchDirection
+     */
+    int getFetchDirection() throws SQLException;
+
+    /**
+     * Gives the JDBC driver a hint as to the number of rows that should
+     * be fetched from the database when more rows are needed for
+     * <code>ResultSet</code> objects genrated by this <code>Statement</code>.
+     * If the value specified is zero, then the hint is ignored.
+     * The default value is zero.
+     *
+     * @param rows the number of rows to fetch
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code> or the
+     *        condition  <code>rows >= 0</code> is not satisfied.
+     * @since 1.2
+     * @see #getFetchSize
+     */
+    void setFetchSize(int rows) throws SQLException;
+
+    /**
+     * Retrieves the number of result set rows that is the default
+     * fetch size for <code>ResultSet</code> objects
+     * generated from this <code>Statement</code> object.
+     * If this <code>Statement</code> object has not set
+     * a fetch size by calling the method <code>setFetchSize</code>,
+     * the return value is implementation-specific.
+     *
+     * @return the default fetch size for result sets generated
+     *          from this <code>Statement</code> object
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @since 1.2
+     * @see #setFetchSize
+     */
+    int getFetchSize() throws SQLException;
+
+    /**
+     * Retrieves the result set concurrency for <code>ResultSet</code> objects
+     * generated by this <code>Statement</code> object.
+     *
+     * @return either <code>ResultSet.CONCUR_READ_ONLY</code> or
+     * <code>ResultSet.CONCUR_UPDATABLE</code>
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @since 1.2
+     */
+    int getResultSetConcurrency() throws SQLException;
+
+    /**
+     * Retrieves the result set type for <code>ResultSet</code> objects
+     * generated by this <code>Statement</code> object.
+     *
+     * @return one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
+     * <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
+     * <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @since 1.2
+     */
+    int getResultSetType()  throws SQLException;
+
+    /**
+     * Adds the given SQL command to the current list of commmands for this
+     * <code>Statement</code> object. The commands in this list can be
+     * executed as a batch by calling the method <code>executeBatch</code>.
+     * <P>
+     *<strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql typically this is a SQL <code>INSERT</code> or
+     * <code>UPDATE</code> statement
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>, the
+     * driver does not support batch updates, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @see #executeBatch
+     * @see DatabaseMetaData#supportsBatchUpdates
+     * @since 1.2
+     */
+    void addBatch( String sql ) throws SQLException;
+
+    /**
+     * Empties this <code>Statement</code> object's current list of
+     * SQL commands.
+     * <P>
+     * @exception SQLException if a database access error occurs,
+     *  this method is called on a closed <code>Statement</code> or the
+     * driver does not support batch updates
+     * @see #addBatch
+     * @see DatabaseMetaData#supportsBatchUpdates
+     * @since 1.2
+     */
+    void clearBatch() throws SQLException;
+
+    /**
+     * Submits a batch of commands to the database for execution and
+     * if all commands execute successfully, returns an array of update counts.
+     * The <code>int</code> elements of the array that is returned are ordered
+     * to correspond to the commands in the batch, which are ordered
+     * according to the order in which they were added to the batch.
+     * The elements in the array returned by the method <code>executeBatch</code>
+     * may be one of the following:
+     * <OL>
+     * <LI>A number greater than or equal to zero -- indicates that the
+     * command was processed successfully and is an update count giving the
+     * number of rows in the database that were affected by the command's
+     * execution
+     * <LI>A value of <code>SUCCESS_NO_INFO</code> -- indicates that the command was
+     * processed successfully but that the number of rows affected is
+     * unknown
+     * <P>
+     * If one of the commands in a batch update fails to execute properly,
+     * this method throws a <code>BatchUpdateException</code>, and a JDBC
+     * driver may or may not continue to process the remaining commands in
+     * the batch.  However, the driver's behavior must be consistent with a
+     * particular DBMS, either always continuing to process commands or never
+     * continuing to process commands.  If the driver continues processing
+     * after a failure, the array returned by the method
+     * <code>BatchUpdateException.getUpdateCounts</code>
+     * will contain as many elements as there are commands in the batch, and
+     * at least one of the elements will be the following:
+     * <P>
+     * <LI>A value of <code>EXECUTE_FAILED</code> -- indicates that the command failed
+     * to execute successfully and occurs only if a driver continues to
+     * process commands after a command fails
+     * </OL>
+     * <P>
+     * The possible implementations and return values have been modified in
+     * the Java 2 SDK, Standard Edition, version 1.3 to
+     * accommodate the option of continuing to proccess commands in a batch
+     * update after a <code>BatchUpdateException</code> obejct has been thrown.
+     *
+     * @return an array of update counts containing one element for each
+     * command in the batch.  The elements of the array are ordered according
+     * to the order in which commands were added to the batch.
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code> or the
+     * driver does not support batch statements. Throws {@link BatchUpdateException}
+     * (a subclass of <code>SQLException</code>) if one of the commands sent to the
+     * database fails to execute properly or attempts to return a result set.
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     *
+     * @see #addBatch
+     * @see DatabaseMetaData#supportsBatchUpdates
+     * @since 1.2
+     */
+    int[] executeBatch() throws SQLException;
+
+    /**
+     * Retrieves the <code>Connection</code> object
+     * that produced this <code>Statement</code> object.
+     * @return the connection that produced this statement
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @since 1.2
+     */
+    Connection getConnection()  throws SQLException;
+
+  //--------------------------JDBC 3.0-----------------------------
+
+    /**
+     * The constant indicating that the current <code>ResultSet</code> object
+     * should be closed when calling <code>getMoreResults</code>.
+     *
+     * @since 1.4
+     */
+    int CLOSE_CURRENT_RESULT = 1;
+
+    /**
+     * The constant indicating that the current <code>ResultSet</code> object
+     * should not be closed when calling <code>getMoreResults</code>.
+     *
+     * @since 1.4
+     */
+    int KEEP_CURRENT_RESULT = 2;
+
+    /**
+     * The constant indicating that all <code>ResultSet</code> objects that
+     * have previously been kept open should be closed when calling
+     * <code>getMoreResults</code>.
+     *
+     * @since 1.4
+     */
+    int CLOSE_ALL_RESULTS = 3;
+
+    /**
+     * The constant indicating that a batch statement executed successfully
+     * but that no count of the number of rows it affected is available.
+     *
+     * @since 1.4
+     */
+    int SUCCESS_NO_INFO = -2;
+
+    /**
+     * The constant indicating that an error occured while executing a
+     * batch statement.
+     *
+     * @since 1.4
+     */
+    int EXECUTE_FAILED = -3;
+
+    /**
+     * The constant indicating that generated keys should be made
+     * available for retrieval.
+     *
+     * @since 1.4
+     */
+    int RETURN_GENERATED_KEYS = 1;
+
+    /**
+     * The constant indicating that generated keys should not be made
+     * available for retrieval.
+     *
+     * @since 1.4
+     */
+    int NO_GENERATED_KEYS = 2;
+
+    /**
+     * Moves to this <code>Statement</code> object's next result, deals with
+     * any current <code>ResultSet</code> object(s) according  to the instructions
+     * specified by the given flag, and returns
+     * <code>true</code> if the next result is a <code>ResultSet</code> object.
+     *
+     * <P>There are no more results when the following is true:
+     * <PRE>
+     *     // stmt is a Statement object
+     *     ((stmt.getMoreResults(current) == false) && (stmt.getUpdateCount() == -1))
+     * </PRE>
+     *
+     * @param current one of the following <code>Statement</code>
+     *        constants indicating what should happen to current
+     *        <code>ResultSet</code> objects obtained using the method
+     *        <code>getResultSet</code>:
+     *        <code>Statement.CLOSE_CURRENT_RESULT</code>,
+     *        <code>Statement.KEEP_CURRENT_RESULT</code>, or
+     *        <code>Statement.CLOSE_ALL_RESULTS</code>
+     * @return <code>true</code> if the next result is a <code>ResultSet</code>
+     *         object; <code>false</code> if it is an update count or there are no
+     *         more results
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code> or the argument
+         *         supplied is not one of the following:
+     *        <code>Statement.CLOSE_CURRENT_RESULT</code>,
+     *        <code>Statement.KEEP_CURRENT_RESULT</code> or
+     *        <code>Statement.CLOSE_ALL_RESULTS</code>
+     *@exception SQLFeatureNotSupportedException if
+     * <code>DatabaseMetaData.supportsMultipleOpenResults</code> returns
+     * <code>false</code> and either
+     *        <code>Statement.KEEP_CURRENT_RESULT</code> or
+     *        <code>Statement.CLOSE_ALL_RESULTS</code> are supplied as
+     * the argument.
+     * @since 1.4
+     * @see #execute
+     */
+    boolean getMoreResults(int current) throws SQLException;
+
+    /**
+     * Retrieves any auto-generated keys created as a result of executing this
+     * <code>Statement</code> object. If this <code>Statement</code> object did
+     * not generate any keys, an empty <code>ResultSet</code>
+     * object is returned.
+     *
+     *<p><B>Note:</B>If the columns which represent the auto-generated keys were not specified,
+     * the JDBC driver implementation will determine the columns which best represent the auto-generated keys.
+     *
+     * @return a <code>ResultSet</code> object containing the auto-generated key(s)
+     *         generated by the execution of this <code>Statement</code> object
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @since 1.4
+     */
+    ResultSet getGeneratedKeys() throws SQLException;
+
+    /**
+     * Executes the given SQL statement and signals the driver with the
+     * given flag about whether the
+     * auto-generated keys produced by this <code>Statement</code> object
+     * should be made available for retrieval.  The driver will ignore the
+     * flag if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
+     * <code>DELETE</code>; or an SQL statement that returns nothing,
+     * such as a DDL statement.
+     *
+     * @param autoGeneratedKeys a flag indicating whether auto-generated keys
+     *        should be made available for retrieval;
+     *         one of the following constants:
+     *         <code>Statement.RETURN_GENERATED_KEYS</code>
+     *         <code>Statement.NO_GENERATED_KEYS</code>
+     * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+     *         or (2) 0 for SQL statements that return nothing
+     *
+     * @exception SQLException if a database access error occurs,
+     *  this method is called on a closed <code>Statement</code>, the given
+     *            SQL statement returns a <code>ResultSet</code> object,
+     *            the given constant is not one of those allowed, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method with a constant of Statement.RETURN_GENERATED_KEYS
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @since 1.4
+     */
+    int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException;
+
+    /**
+     * Executes the given SQL statement and signals the driver that the
+     * auto-generated keys indicated in the given array should be made available
+     * for retrieval.   This array contains the indexes of the columns in the
+     * target table that contain the auto-generated keys that should be made
+     * available. The driver will ignore the array if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
+     * <code>DELETE</code>; or an SQL statement that returns nothing,
+     * such as a DDL statement.
+     *
+     * @param columnIndexes an array of column indexes indicating the columns
+     *        that should be returned from the inserted row
+     * @return either (1) the row count for SQL Data Manipulation Language (DML) statements
+     *         or (2) 0 for SQL statements that return nothing
+     *
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>, the SQL
+     * statement returns a <code>ResultSet</code> object,the second argument
+     * supplied to this method is not an
+     * <code>int</code> array whose elements are valid column indexes, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @since 1.4
+     */
+    int executeUpdate(String sql, int columnIndexes[]) throws SQLException;
+
+    /**
+     * Executes the given SQL statement and signals the driver that the
+     * auto-generated keys indicated in the given array should be made available
+     * for retrieval.   This array contains the names of the columns in the
+     * target table that contain the auto-generated keys that should be made
+     * available. The driver will ignore the array if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql an SQL Data Manipulation Language (DML) statement, such as <code>INSERT</code>, <code>UPDATE</code> or
+     * <code>DELETE</code>; or an SQL statement that returns nothing,
+     * such as a DDL statement.
+     * @param columnNames an array of the names of the columns that should be
+     *        returned from the inserted row
+     * @return either the row count for <code>INSERT</code>, <code>UPDATE</code>,
+     *         or <code>DELETE</code> statements, or 0 for SQL statements
+     *         that return nothing
+     * @exception SQLException if a database access error occurs,
+     *  this method is called on a closed <code>Statement</code>, the SQL
+     *            statement returns a <code>ResultSet</code> object, the
+     *            second argument supplied to this method is not a <code>String</code> array
+     *            whose elements are valid column names, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @since 1.4
+     */
+    int executeUpdate(String sql, String columnNames[]) throws SQLException;
+
+    /**
+     * Executes the given SQL statement, which may return multiple results,
+     * and signals the driver that any
+     * auto-generated keys should be made available
+     * for retrieval.  The driver will ignore this signal if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     * <P>
+     * In some (uncommon) situations, a single SQL statement may return
+     * multiple result sets and/or update counts.  Normally you can ignore
+     * this unless you are (1) executing a stored procedure that you know may
+     * return multiple results or (2) you are dynamically executing an
+     * unknown SQL string.
+     * <P>
+     * The <code>execute</code> method executes an SQL statement and indicates the
+     * form of the first result.  You must then use the methods
+     * <code>getResultSet</code> or <code>getUpdateCount</code>
+     * to retrieve the result, and <code>getMoreResults</code> to
+     * move to any subsequent result(s).
+     *<p>
+     *<strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql any SQL statement
+     * @param autoGeneratedKeys a constant indicating whether auto-generated
+     *        keys should be made available for retrieval using the method
+     *        <code>getGeneratedKeys</code>; one of the following constants:
+     *        <code>Statement.RETURN_GENERATED_KEYS</code> or
+     *        <code>Statement.NO_GENERATED_KEYS</code>
+     * @return <code>true</code> if the first result is a <code>ResultSet</code>
+     *         object; <code>false</code> if it is an update count or there are
+     *         no results
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>, the second
+     *         parameter supplied to this method is not
+     *         <code>Statement.RETURN_GENERATED_KEYS</code> or
+     *         <code>Statement.NO_GENERATED_KEYS</code>,
+     * the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+     * this method with a constant of Statement.RETURN_GENERATED_KEYS
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @see #getResultSet
+     * @see #getUpdateCount
+     * @see #getMoreResults
+     * @see #getGeneratedKeys
+     *
+     * @since 1.4
+     */
+    boolean execute(String sql, int autoGeneratedKeys) throws SQLException;
+
+    /**
+     * Executes the given SQL statement, which may return multiple results,
+     * and signals the driver that the
+     * auto-generated keys indicated in the given array should be made available
+     * for retrieval.  This array contains the indexes of the columns in the
+     * target table that contain the auto-generated keys that should be made
+     * available.  The driver will ignore the array if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     * <P>
+     * Under some (uncommon) situations, a single SQL statement may return
+     * multiple result sets and/or update counts.  Normally you can ignore
+     * this unless you are (1) executing a stored procedure that you know may
+     * return multiple results or (2) you are dynamically executing an
+     * unknown SQL string.
+     * <P>
+     * The <code>execute</code> method executes an SQL statement and indicates the
+     * form of the first result.  You must then use the methods
+     * <code>getResultSet</code> or <code>getUpdateCount</code>
+     * to retrieve the result, and <code>getMoreResults</code> to
+     * move to any subsequent result(s).
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql any SQL statement
+     * @param columnIndexes an array of the indexes of the columns in the
+     *        inserted row that should be  made available for retrieval by a
+     *        call to the method <code>getGeneratedKeys</code>
+     * @return <code>true</code> if the first result is a <code>ResultSet</code>
+     *         object; <code>false</code> if it is an update count or there
+     *         are no results
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>, the
+     *            elements in the <code>int</code> array passed to this method
+     *            are not valid column indexes, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @see #getResultSet
+     * @see #getUpdateCount
+     * @see #getMoreResults
+     *
+     * @since 1.4
+     */
+    boolean execute(String sql, int columnIndexes[]) throws SQLException;
+
+    /**
+     * Executes the given SQL statement, which may return multiple results,
+     * and signals the driver that the
+     * auto-generated keys indicated in the given array should be made available
+     * for retrieval. This array contains the names of the columns in the
+     * target table that contain the auto-generated keys that should be made
+     * available.  The driver will ignore the array if the SQL statement
+     * is not an <code>INSERT</code> statement, or an SQL statement able to return
+     * auto-generated keys (the list of such statements is vendor-specific).
+     * <P>
+     * In some (uncommon) situations, a single SQL statement may return
+     * multiple result sets and/or update counts.  Normally you can ignore
+     * this unless you are (1) executing a stored procedure that you know may
+     * return multiple results or (2) you are dynamically executing an
+     * unknown SQL string.
+     * <P>
+     * The <code>execute</code> method executes an SQL statement and indicates the
+     * form of the first result.  You must then use the methods
+     * <code>getResultSet</code> or <code>getUpdateCount</code>
+     * to retrieve the result, and <code>getMoreResults</code> to
+     * move to any subsequent result(s).
+     *<p>
+     * <strong>Note:</strong>This method cannot be called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>.
+     * @param sql any SQL statement
+     * @param columnNames an array of the names of the columns in the inserted
+     *        row that should be made available for retrieval by a call to the
+     *        method <code>getGeneratedKeys</code>
+     * @return <code>true</code> if the next result is a <code>ResultSet</code>
+     *         object; <code>false</code> if it is an update count or there
+     *         are no more results
+     * @exception SQLException if a database access error occurs,
+     * this method is called on a closed <code>Statement</code>,the
+     *          elements of the <code>String</code> array passed to this
+     *          method are not valid column names, the method is called on a
+     * <code>PreparedStatement</code> or <code>CallableStatement</code>
+     * @throws SQLFeatureNotSupportedException  if the JDBC driver does not support this method
+     * @throws SQLTimeoutException when the driver has determined that the
+     * timeout value that was specified by the {@code setQueryTimeout}
+     * method has been exceeded and has at least attempted to cancel
+     * the currently running {@code Statement}
+     * @see #getResultSet
+     * @see #getUpdateCount
+     * @see #getMoreResults
+     * @see #getGeneratedKeys
+     *
+     * @since 1.4
+     */
+    boolean execute(String sql, String columnNames[]) throws SQLException;
+
+   /**
+     * Retrieves the result set holdability for <code>ResultSet</code> objects
+     * generated by this <code>Statement</code> object.
+     *
+     * @return either <code>ResultSet.HOLD_CURSORS_OVER_COMMIT</code> or
+     *         <code>ResultSet.CLOSE_CURSORS_AT_COMMIT</code>
+     * @exception SQLException if a database access error occurs or
+     * this method is called on a closed <code>Statement</code>
+     *
+     * @since 1.4
+     */
+    int getResultSetHoldability() throws SQLException;
+
+    /**
+     * Retrieves whether this <code>Statement</code> object has been closed. A <code>Statement</code> is closed if the
+     * method close has been called on it, or if it is automatically closed.
+     * @return true if this <code>Statement</code> object is closed; false if it is still open
+     * @throws SQLException if a database access error occurs
+     * @since 1.6
+     */
+    boolean isClosed() throws SQLException;
+
+        /**
+         * Requests that a <code>Statement</code> be pooled or not pooled.  The value
+         * specified is a hint to the statement pool implementation indicating
+         * whether the applicaiton wants the statement to be pooled.  It is up to
+         * the statement pool manager as to whether the hint is used.
+         * <p>
+         * The poolable value of a statement is applicable to both internal
+         * statement caches implemented by the driver and external statement caches
+         * implemented by application servers and other applications.
+         * <p>
+         * By default, a <code>Statement</code> is not poolable when created, and
+         * a <code>PreparedStatement</code> and <code>CallableStatement</code>
+         * are poolable when created.
+         * <p>
+         * @param poolable              requests that the statement be pooled if true and
+         *                                              that the statement not be pooled if false
+         * <p>
+         * @throws SQLException if this method is called on a closed
+         * <code>Statement</code>
+         * <p>
+         * @since 1.6
+         */
+        void setPoolable(boolean poolable)
+                throws SQLException;
+
+        /**
+         * Returns a  value indicating whether the <code>Statement</code>
+         * is poolable or not.
+         * <p>
+         * @return              <code>true</code> if the <code>Statement</code>
+         * is poolable; <code>false</code> otherwise
+         * <p>
+         * @throws SQLException if this method is called on a closed
+         * <code>Statement</code>
+         * <p>
+         * @since 1.6
+         * <p>
+         * @see java.sql.Statement#setPoolable(boolean) setPoolable(boolean)
+         */
+        boolean isPoolable()
+                throws SQLException;
+
+    // Android-removed: JDBC 4.1 methods were removed immediately after the initial import.
+}
diff --git a/java/sql/Struct.java b/java/sql/Struct.java
new file mode 100644
index 0000000..50261a6
--- /dev/null
+++ b/java/sql/Struct.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <p>The standard mapping in the Java programming language for an SQL
+ * structured type. A <code>Struct</code> object contains a
+ * value for each attribute of the SQL structured type that
+ * it represents.
+ * By default, an instance of<code>Struct</code> is valid as long as the
+ * application has a reference to it.
+ * <p>
+ * All methods on the <code>Struct</code> interface must be fully implemented if the
+ * JDBC driver supports the data type.
+ * @since 1.2
+ */
+
+public interface Struct {
+
+  /**
+   * Retrieves the SQL type name of the SQL structured type
+   * that this <code>Struct</code> object represents.
+   *
+   * @return the fully-qualified type name of the SQL structured
+   *          type for which this <code>Struct</code> object
+   *          is the generic representation
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  String getSQLTypeName() throws SQLException;
+
+  /**
+   * Produces the ordered values of the attributes of the SQL
+   * structured type that this <code>Struct</code> object represents.
+   * As individual attributes are processed, this method uses the type map
+   * associated with the
+   * connection for customizations of the type mappings.
+   * If there is no
+   * entry in the connection's type map that matches the structured
+   * type that an attribute represents,
+   * the driver uses the standard mapping.
+   * <p>
+   * Conceptually, this method calls the method
+   * <code>getObject</code> on each attribute
+   * of the structured type and returns a Java array containing
+   * the result.
+   *
+   * @return an array containing the ordered attribute values
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  Object[] getAttributes() throws SQLException;
+
+  /**
+   * Produces the ordered values of the attributes of the SQL
+   * structured type that this <code>Struct</code> object represents.
+   *  As individual attrbutes are proccessed, this method uses the given type map
+   * for customizations of the type mappings.
+   * If there is no
+   * entry in the given type map that matches the structured
+   * type that an attribute represents,
+   * the driver uses the standard mapping. This method never
+   * uses the type map associated with the connection.
+   * <p>
+   * Conceptually, this method calls the method
+   * <code>getObject</code> on each attribute
+   * of the structured type and returns a Java array containing
+   * the result.
+   *
+   * @param map a mapping of SQL type names to Java classes
+   * @return an array containing the ordered attribute values
+   * @exception SQLException if a database access error occurs
+   * @exception SQLFeatureNotSupportedException if the JDBC driver does not support
+   * this method
+   * @since 1.2
+   */
+  Object[] getAttributes(java.util.Map<String,Class<?>> map)
+      throws SQLException;
+}
diff --git a/java/sql/Time.java b/java/sql/Time.java
new file mode 100644
index 0000000..1300003
--- /dev/null
+++ b/java/sql/Time.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <P>A thin wrapper around the <code>java.util.Date</code> class that allows the JDBC
+ * API to identify this as an SQL <code>TIME</code> value. The <code>Time</code>
+ * class adds formatting and
+ * parsing operations to support the JDBC escape syntax for time
+ * values.
+ * <p>The date components should be set to the "zero epoch"
+ * value of January 1, 1970 and should not be accessed.
+ */
+public class Time extends java.util.Date {
+
+    /**
+     * Constructs a <code>Time</code> object initialized with the
+     * given values for the hour, minute, and second.
+     * The driver sets the date components to January 1, 1970.
+     * Any method that attempts to access the date components of a
+     * <code>Time</code> object will throw a
+     * <code>java.lang.IllegalArgumentException</code>.
+     * <P>
+     * The result is undefined if a given argument is out of bounds.
+     *
+     * @param hour 0 to 23
+     * @param minute 0 to 59
+     * @param second 0 to 59
+     *
+     * @deprecated Use the constructor that takes a milliseconds value
+     *             in place of this constructor
+     */
+    @Deprecated
+    public Time(int hour, int minute, int second) {
+        super(70, 0, 1, hour, minute, second);
+    }
+
+    /**
+     * Constructs a <code>Time</code> object using a milliseconds time value.
+     *
+     * @param time milliseconds since January 1, 1970, 00:00:00 GMT;
+     *             a negative number is milliseconds before
+     *               January 1, 1970, 00:00:00 GMT
+     */
+    public Time(long time) {
+        super(time);
+    }
+
+    /**
+     * Sets a <code>Time</code> object using a milliseconds time value.
+     *
+     * @param time milliseconds since January 1, 1970, 00:00:00 GMT;
+     *             a negative number is milliseconds before
+     *               January 1, 1970, 00:00:00 GMT
+     */
+    public void setTime(long time) {
+        super.setTime(time);
+    }
+
+    /**
+     * Converts a string in JDBC time escape format to a <code>Time</code> value.
+     *
+     * @param s time in format "hh:mm:ss"
+     * @return a corresponding <code>Time</code> object
+     */
+    public static Time valueOf(String s) {
+        int hour;
+        int minute;
+        int second;
+        int firstColon;
+        int secondColon;
+
+        if (s == null) throw new java.lang.IllegalArgumentException();
+
+        firstColon = s.indexOf(':');
+        secondColon = s.indexOf(':', firstColon+1);
+        if ((firstColon > 0) & (secondColon > 0) &
+            (secondColon < s.length()-1)) {
+            hour = Integer.parseInt(s.substring(0, firstColon));
+            minute =
+                Integer.parseInt(s.substring(firstColon+1, secondColon));
+            second = Integer.parseInt(s.substring(secondColon+1));
+        } else {
+            throw new java.lang.IllegalArgumentException();
+        }
+
+        return new Time(hour, minute, second);
+    }
+
+    /**
+     * Formats a time in JDBC time escape format.
+     *
+     * @return a <code>String</code> in hh:mm:ss format
+     */
+    public String toString () {
+        int hour = super.getHours();
+        int minute = super.getMinutes();
+        int second = super.getSeconds();
+        String hourString;
+        String minuteString;
+        String secondString;
+
+        if (hour < 10) {
+            hourString = "0" + hour;
+        } else {
+            hourString = Integer.toString(hour);
+        }
+        if (minute < 10) {
+            minuteString = "0" + minute;
+        } else {
+            minuteString = Integer.toString(minute);
+        }
+        if (second < 10) {
+            secondString = "0" + second;
+        } else {
+            secondString = Integer.toString(second);
+        }
+        return (hourString + ":" + minuteString + ":" + secondString);
+    }
+
+    // Override all the date operations inherited from java.util.Date;
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a year component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    * @see #setYear
+    */
+    @Deprecated
+    public int getYear() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a month component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    * @see #setMonth
+    */
+    @Deprecated
+    public int getMonth() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a day component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    */
+    @Deprecated
+    public int getDay() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a date component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    * @see #setDate
+    */
+    @Deprecated
+    public int getDate() {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a year component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    * @see #getYear
+    */
+    @Deprecated
+    public void setYear(int i) {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a month component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    * @see #getMonth
+    */
+    @Deprecated
+    public void setMonth(int i) {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   // Android-changed: Moved @deprecated to include a deprecation reason in the documentation.
+   /**
+    * @deprecated This method is deprecated and should not be used because SQL <code>TIME</code>
+    * values do not have a date component.
+    *
+    * @exception java.lang.IllegalArgumentException if this
+    *           method is invoked
+    * @see #getDate
+    */
+    @Deprecated
+    public void setDate(int i) {
+        throw new java.lang.IllegalArgumentException();
+    }
+
+   /**
+    * Private serial version unique ID to ensure serialization
+    * compatibility.
+    */
+    static final long serialVersionUID = 8397324403548013681L;
+}
diff --git a/java/sql/Timestamp.java b/java/sql/Timestamp.java
new file mode 100644
index 0000000..14f648b
--- /dev/null
+++ b/java/sql/Timestamp.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+import java.util.StringTokenizer;
+
+/**
+ * <P>A thin wrapper around <code>java.util.Date</code> that allows
+ * the JDBC API to identify this as an SQL <code>TIMESTAMP</code> value.
+ * It adds the ability
+ * to hold the SQL <code>TIMESTAMP</code> fractional seconds value, by allowing
+ * the specification of fractional seconds to a precision of nanoseconds.
+ * A Timestamp also provides formatting and
+ * parsing operations to support the JDBC escape syntax for timestamp values.
+ *
+ * <p>The precision of a Timestamp object is calculated to be either:
+ * <ul>
+ * <li><code>19 </code>, which is the number of characters in yyyy-mm-dd hh:mm:ss
+ * <li> <code> 20 + s </code>, which is the number
+ * of characters in the yyyy-mm-dd hh:mm:ss.[fff...] and <code>s</code> represents  the scale of the given Timestamp,
+ * its fractional seconds precision.
+ *</ul>
+ *
+ * <P><B>Note:</B> This type is a composite of a <code>java.util.Date</code> and a
+ * separate nanoseconds value. Only integral seconds are stored in the
+ * <code>java.util.Date</code> component. The fractional seconds - the nanos - are
+ * separate.  The <code>Timestamp.equals(Object)</code> method never returns
+ * <code>true</code> when passed an object
+ * that isn't an instance of <code>java.sql.Timestamp</code>,
+ * because the nanos component of a date is unknown.
+ * As a result, the <code>Timestamp.equals(Object)</code>
+ * method is not symmetric with respect to the
+ * <code>java.util.Date.equals(Object)</code>
+ * method.  Also, the <code>hashCode</code> method uses the underlying
+ * <code>java.util.Date</code>
+ * implementation and therefore does not include nanos in its computation.
+ * <P>
+ * Due to the differences between the <code>Timestamp</code> class
+ * and the <code>java.util.Date</code>
+ * class mentioned above, it is recommended that code not view
+ * <code>Timestamp</code> values generically as an instance of
+ * <code>java.util.Date</code>.  The
+ * inheritance relationship between <code>Timestamp</code>
+ * and <code>java.util.Date</code> really
+ * denotes implementation inheritance, and not type inheritance.
+ */
+public class Timestamp extends java.util.Date {
+
+    /**
+     * Constructs a <code>Timestamp</code> object initialized
+     * with the given values.
+     *
+     * @param year the year minus 1900
+     * @param month 0 to 11
+     * @param date 1 to 31
+     * @param hour 0 to 23
+     * @param minute 0 to 59
+     * @param second 0 to 59
+     * @param nano 0 to 999,999,999
+     * @deprecated instead use the constructor <code>Timestamp(long millis)</code>
+     * @exception IllegalArgumentException if the nano argument is out of bounds
+     */
+    @Deprecated
+    public Timestamp(int year, int month, int date,
+                     int hour, int minute, int second, int nano) {
+        super(year, month, date, hour, minute, second);
+        if (nano > 999999999 || nano < 0) {
+            throw new IllegalArgumentException("nanos > 999999999 or < 0");
+        }
+        nanos = nano;
+    }
+
+    /**
+     * Constructs a <code>Timestamp</code> object
+     * using a milliseconds time value. The
+     * integral seconds are stored in the underlying date value; the
+     * fractional seconds are stored in the <code>nanos</code> field of
+     * the <code>Timestamp</code> object.
+     *
+     * @param time milliseconds since January 1, 1970, 00:00:00 GMT.
+     *        A negative number is the number of milliseconds before
+     *         January 1, 1970, 00:00:00 GMT.
+     * @see java.util.Calendar
+     */
+    public Timestamp(long time) {
+        super((time/1000)*1000);
+        nanos = (int)((time%1000) * 1000000);
+        if (nanos < 0) {
+            nanos = 1000000000 + nanos;
+            super.setTime(((time/1000)-1)*1000);
+        }
+    }
+
+    /**
+     * Sets this <code>Timestamp</code> object to represent a point in time that is
+     * <tt>time</tt> milliseconds after January 1, 1970 00:00:00 GMT.
+     *
+     * @param time   the number of milliseconds.
+     * @see #getTime
+     * @see #Timestamp(long time)
+     * @see java.util.Calendar
+     */
+    public void setTime(long time) {
+        super.setTime((time/1000)*1000);
+        nanos = (int)((time%1000) * 1000000);
+        if (nanos < 0) {
+            nanos = 1000000000 + nanos;
+            super.setTime(((time/1000)-1)*1000);
+        }
+    }
+
+    /**
+     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     * represented by this <code>Timestamp</code> object.
+     *
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by this date.
+     * @see #setTime
+     */
+    public long getTime() {
+        long time = super.getTime();
+        return (time + (nanos / 1000000));
+    }
+
+
+    /**
+     * @serial
+     */
+    private int nanos;
+
+    /**
+     * Converts a <code>String</code> object in JDBC timestamp escape format to a
+     * <code>Timestamp</code> value.
+     *
+     * @param s timestamp in format <code>yyyy-[m]m-[d]d hh:mm:ss[.f...]</code>.  The
+     * fractional seconds may be omitted. The leading zero for <code>mm</code>
+     * and <code>dd</code> may also be omitted.
+     *
+     * @return corresponding <code>Timestamp</code> value
+     * @exception java.lang.IllegalArgumentException if the given argument
+     * does not have the format <code>yyyy-[m]m-[d]d hh:mm:ss[.f...]</code>
+     */
+    public static Timestamp valueOf(String s) {
+        final int YEAR_LENGTH = 4;
+        final int MONTH_LENGTH = 2;
+        final int DAY_LENGTH = 2;
+        final int MAX_MONTH = 12;
+        final int MAX_DAY = 31;
+        String date_s;
+        String time_s;
+        String nanos_s;
+        int year = 0;
+        int month = 0;
+        int day = 0;
+        int hour;
+        int minute;
+        int second;
+        int a_nanos = 0;
+        int firstDash;
+        int secondDash;
+        int dividingSpace;
+        int firstColon = 0;
+        int secondColon = 0;
+        int period = 0;
+        String formatError = "Timestamp format must be yyyy-mm-dd hh:mm:ss[.fffffffff]";
+        String zeros = "000000000";
+        String delimiterDate = "-";
+        String delimiterTime = ":";
+
+        if (s == null) throw new java.lang.IllegalArgumentException("null string");
+
+        // Split the string into date and time components
+        s = s.trim();
+        dividingSpace = s.indexOf(' ');
+        if (dividingSpace > 0) {
+            date_s = s.substring(0,dividingSpace);
+            time_s = s.substring(dividingSpace+1);
+        } else {
+            throw new java.lang.IllegalArgumentException(formatError);
+        }
+
+        // Parse the date
+        firstDash = date_s.indexOf('-');
+        secondDash = date_s.indexOf('-', firstDash+1);
+
+        // Parse the time
+        if (time_s == null)
+            throw new java.lang.IllegalArgumentException(formatError);
+        firstColon = time_s.indexOf(':');
+        secondColon = time_s.indexOf(':', firstColon+1);
+        period = time_s.indexOf('.', secondColon+1);
+
+        // Convert the date
+        boolean parsedDate = false;
+        if ((firstDash > 0) && (secondDash > 0) && (secondDash < date_s.length() - 1)) {
+            String yyyy = date_s.substring(0, firstDash);
+            String mm = date_s.substring(firstDash + 1, secondDash);
+            String dd = date_s.substring(secondDash + 1);
+            if (yyyy.length() == YEAR_LENGTH &&
+                    (mm.length() >= 1 && mm.length() <= MONTH_LENGTH) &&
+                    (dd.length() >= 1 && dd.length() <= DAY_LENGTH)) {
+                 year = Integer.parseInt(yyyy);
+                 month = Integer.parseInt(mm);
+                 day = Integer.parseInt(dd);
+
+                if ((month >= 1 && month <= MAX_MONTH) && (day >= 1 && day <= MAX_DAY)) {
+                    parsedDate = true;
+                }
+            }
+        }
+        if (! parsedDate) {
+            throw new java.lang.IllegalArgumentException(formatError);
+        }
+
+        // Convert the time; default missing nanos
+        if ((firstColon > 0) & (secondColon > 0) &
+            (secondColon < time_s.length()-1)) {
+            hour = Integer.parseInt(time_s.substring(0, firstColon));
+            minute =
+                Integer.parseInt(time_s.substring(firstColon+1, secondColon));
+            if ((period > 0) & (period < time_s.length()-1)) {
+                second =
+                    Integer.parseInt(time_s.substring(secondColon+1, period));
+                nanos_s = time_s.substring(period+1);
+                if (nanos_s.length() > 9)
+                    throw new java.lang.IllegalArgumentException(formatError);
+                if (!Character.isDigit(nanos_s.charAt(0)))
+                    throw new java.lang.IllegalArgumentException(formatError);
+                nanos_s = nanos_s + zeros.substring(0,9-nanos_s.length());
+                a_nanos = Integer.parseInt(nanos_s);
+            } else if (period > 0) {
+                throw new java.lang.IllegalArgumentException(formatError);
+            } else {
+                second = Integer.parseInt(time_s.substring(secondColon+1));
+            }
+        } else {
+            throw new java.lang.IllegalArgumentException(formatError);
+        }
+
+        return new Timestamp(year - 1900, month - 1, day, hour, minute, second, a_nanos);
+    }
+
+    /**
+     * Formats a timestamp in JDBC timestamp escape format.
+     *         <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>,
+     * where <code>ffffffffff</code> indicates nanoseconds.
+     * <P>
+     * @return a <code>String</code> object in
+     *           <code>yyyy-mm-dd hh:mm:ss.fffffffff</code> format
+     */
+    public String toString () {
+
+        int year = super.getYear() + 1900;
+        int month = super.getMonth() + 1;
+        int day = super.getDate();
+        int hour = super.getHours();
+        int minute = super.getMinutes();
+        int second = super.getSeconds();
+        String yearString;
+        String monthString;
+        String dayString;
+        String hourString;
+        String minuteString;
+        String secondString;
+        String nanosString;
+        String zeros = "000000000";
+        String yearZeros = "0000";
+        StringBuffer timestampBuf;
+
+        if (year < 1000) {
+            // Add leading zeros
+            yearString = "" + year;
+            yearString = yearZeros.substring(0, (4-yearString.length())) +
+                yearString;
+        } else {
+            yearString = "" + year;
+        }
+        if (month < 10) {
+            monthString = "0" + month;
+        } else {
+            monthString = Integer.toString(month);
+        }
+        if (day < 10) {
+            dayString = "0" + day;
+        } else {
+            dayString = Integer.toString(day);
+        }
+        if (hour < 10) {
+            hourString = "0" + hour;
+        } else {
+            hourString = Integer.toString(hour);
+        }
+        if (minute < 10) {
+            minuteString = "0" + minute;
+        } else {
+            minuteString = Integer.toString(minute);
+        }
+        if (second < 10) {
+            secondString = "0" + second;
+        } else {
+            secondString = Integer.toString(second);
+        }
+        if (nanos == 0) {
+            nanosString = "0";
+        } else {
+            nanosString = Integer.toString(nanos);
+
+            // Add leading zeros
+            nanosString = zeros.substring(0, (9-nanosString.length())) +
+                nanosString;
+
+            // Truncate trailing zeros
+            char[] nanosChar = new char[nanosString.length()];
+            nanosString.getChars(0, nanosString.length(), nanosChar, 0);
+            int truncIndex = 8;
+            while (nanosChar[truncIndex] == '0') {
+                truncIndex--;
+            }
+
+            nanosString = new String(nanosChar, 0, truncIndex + 1);
+        }
+
+        // do a string buffer here instead.
+        timestampBuf = new StringBuffer(20+nanosString.length());
+        timestampBuf.append(yearString);
+        timestampBuf.append("-");
+        timestampBuf.append(monthString);
+        timestampBuf.append("-");
+        timestampBuf.append(dayString);
+        timestampBuf.append(" ");
+        timestampBuf.append(hourString);
+        timestampBuf.append(":");
+        timestampBuf.append(minuteString);
+        timestampBuf.append(":");
+        timestampBuf.append(secondString);
+        timestampBuf.append(".");
+        timestampBuf.append(nanosString);
+
+        return (timestampBuf.toString());
+    }
+
+    /**
+     * Gets this <code>Timestamp</code> object's <code>nanos</code> value.
+     *
+     * @return this <code>Timestamp</code> object's fractional seconds component
+     * @see #setNanos
+     */
+    public int getNanos() {
+        return nanos;
+    }
+
+    /**
+     * Sets this <code>Timestamp</code> object's <code>nanos</code> field
+     * to the given value.
+     *
+     * @param n the new fractional seconds component
+     * @exception java.lang.IllegalArgumentException if the given argument
+     *            is greater than 999999999 or less than 0
+     * @see #getNanos
+     */
+    public void setNanos(int n) {
+        if (n > 999999999 || n < 0) {
+            throw new IllegalArgumentException("nanos > 999999999 or < 0");
+        }
+        nanos = n;
+    }
+
+    /**
+     * Tests to see if this <code>Timestamp</code> object is
+     * equal to the given <code>Timestamp</code> object.
+     *
+     * @param ts the <code>Timestamp</code> value to compare with
+     * @return <code>true</code> if the given <code>Timestamp</code>
+     *         object is equal to this <code>Timestamp</code> object;
+     *         <code>false</code> otherwise
+     */
+    public boolean equals(Timestamp ts) {
+        if (super.equals(ts)) {
+            if  (nanos == ts.nanos) {
+                return true;
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Tests to see if this <code>Timestamp</code> object is
+     * equal to the given object.
+     *
+     * This version of the method <code>equals</code> has been added
+     * to fix the incorrect
+     * signature of <code>Timestamp.equals(Timestamp)</code> and to preserve backward
+     * compatibility with existing class files.
+     *
+     * Note: This method is not symmetric with respect to the
+     * <code>equals(Object)</code> method in the base class.
+     *
+     * @param ts the <code>Object</code> value to compare with
+     * @return <code>true</code> if the given <code>Object</code> is an instance
+     *         of a <code>Timestamp</code> that
+     *         is equal to this <code>Timestamp</code> object;
+     *         <code>false</code> otherwise
+     */
+    public boolean equals(java.lang.Object ts) {
+      if (ts instanceof Timestamp) {
+        return this.equals((Timestamp)ts);
+      } else {
+        return false;
+      }
+    }
+
+    /**
+     * Indicates whether this <code>Timestamp</code> object is
+     * earlier than the given <code>Timestamp</code> object.
+     *
+     * @param ts the <code>Timestamp</code> value to compare with
+     * @return <code>true</code> if this <code>Timestamp</code> object is earlier;
+     *        <code>false</code> otherwise
+     */
+    public boolean before(Timestamp ts) {
+        return compareTo(ts) < 0;
+    }
+
+    /**
+     * Indicates whether this <code>Timestamp</code> object is
+     * later than the given <code>Timestamp</code> object.
+     *
+     * @param ts the <code>Timestamp</code> value to compare with
+     * @return <code>true</code> if this <code>Timestamp</code> object is later;
+     *        <code>false</code> otherwise
+     */
+    public boolean after(Timestamp ts) {
+        return compareTo(ts) > 0;
+    }
+
+    /**
+     * Compares this <code>Timestamp</code> object to the given
+     * <code>Timestamp</code> object.
+     *
+     * @param   ts   the <code>Timestamp</code> object to be compared to
+     *                this <code>Timestamp</code> object
+     * @return  the value <code>0</code> if the two <code>Timestamp</code>
+     *          objects are equal; a value less than <code>0</code> if this
+     *          <code>Timestamp</code> object is before the given argument;
+     *          and a value greater than <code>0</code> if this
+     *          <code>Timestamp</code> object is after the given argument.
+     * @since   1.4
+     */
+    public int compareTo(Timestamp ts) {
+        long thisTime = this.getTime();
+        long anotherTime = ts.getTime();
+        int i = (thisTime<anotherTime ? -1 :(thisTime==anotherTime?0 :1));
+        if (i == 0) {
+            if (nanos > ts.nanos) {
+                    return 1;
+            } else if (nanos < ts.nanos) {
+                return -1;
+            }
+        }
+        return i;
+
+    }
+
+    /**
+     * Compares this <code>Timestamp</code> object to the given
+     * <code>Date</code> object.
+     *
+     * @param o the <code>Date</code> to be compared to
+     *          this <code>Timestamp</code> object
+     * @return  the value <code>0</code> if this <code>Timestamp</code> object
+     *          and the given object are equal; a value less than <code>0</code>
+     *          if this  <code>Timestamp</code> object is before the given argument;
+     *          and a value greater than <code>0</code> if this
+     *          <code>Timestamp</code> object is after the given argument.
+     *
+     * @since   1.5
+     */
+    public int compareTo(java.util.Date o) {
+       if(o instanceof Timestamp) {
+            // When Timestamp instance compare it with a Timestamp
+            // Hence it is basically calling this.compareTo((Timestamp))o);
+            // Note typecasting is safe because o is instance of Timestamp
+           return compareTo((Timestamp)o);
+      } else {
+            // When Date doing a o.compareTo(this)
+            // will give wrong results.
+          Timestamp ts = new Timestamp(o.getTime());
+          return this.compareTo(ts);
+      }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * The {@code hashCode} method uses the underlying {@code java.util.Date}
+     * implementation and therefore does not include nanos in its computation.
+     *
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode();
+    }
+
+    static final long serialVersionUID = 2745179027874758501L;
+
+}
diff --git a/java/sql/Types.java b/java/sql/Types.java
new file mode 100644
index 0000000..5b800a9
--- /dev/null
+++ b/java/sql/Types.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * <P>The class that defines the constants that are used to identify generic
+ * SQL types, called JDBC types.
+ * <p>
+ * This class is never instantiated.
+ */
+public class Types {
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>BIT</code>.
+ */
+        public final static int BIT             =  -7;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>TINYINT</code>.
+ */
+        public final static int TINYINT         =  -6;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>SMALLINT</code>.
+ */
+        public final static int SMALLINT        =   5;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>INTEGER</code>.
+ */
+        public final static int INTEGER         =   4;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>BIGINT</code>.
+ */
+        public final static int BIGINT          =  -5;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>FLOAT</code>.
+ */
+        public final static int FLOAT           =   6;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>REAL</code>.
+ */
+        public final static int REAL            =   7;
+
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>DOUBLE</code>.
+ */
+        public final static int DOUBLE          =   8;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>NUMERIC</code>.
+ */
+        public final static int NUMERIC         =   2;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>DECIMAL</code>.
+ */
+        public final static int DECIMAL         =   3;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>CHAR</code>.
+ */
+        public final static int CHAR            =   1;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>VARCHAR</code>.
+ */
+        public final static int VARCHAR         =  12;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>LONGVARCHAR</code>.
+ */
+        public final static int LONGVARCHAR     =  -1;
+
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>DATE</code>.
+ */
+        public final static int DATE            =  91;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>TIME</code>.
+ */
+        public final static int TIME            =  92;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>TIMESTAMP</code>.
+ */
+        public final static int TIMESTAMP       =  93;
+
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>BINARY</code>.
+ */
+        public final static int BINARY          =  -2;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>VARBINARY</code>.
+ */
+        public final static int VARBINARY       =  -3;
+
+/**
+ * <P>The constant in the Java programming language, sometimes referred
+ * to as a type code, that identifies the generic SQL type
+ * <code>LONGVARBINARY</code>.
+ */
+        public final static int LONGVARBINARY   =  -4;
+
+/**
+ * <P>The constant in the Java programming language
+ * that identifies the generic SQL value
+ * <code>NULL</code>.
+ */
+        public final static int NULL            =   0;
+
+    /**
+     * The constant in the Java programming language that indicates
+     * that the SQL type is database-specific and
+     * gets mapped to a Java object that can be accessed via
+     * the methods <code>getObject</code> and <code>setObject</code>.
+     */
+        public final static int OTHER           = 1111;
+
+
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>JAVA_OBJECT</code>.
+     * @since 1.2
+     */
+        public final static int JAVA_OBJECT         = 2000;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>DISTINCT</code>.
+     * @since 1.2
+     */
+        public final static int DISTINCT            = 2001;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>STRUCT</code>.
+     * @since 1.2
+     */
+        public final static int STRUCT              = 2002;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>ARRAY</code>.
+     * @since 1.2
+     */
+        public final static int ARRAY               = 2003;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>BLOB</code>.
+     * @since 1.2
+     */
+        public final static int BLOB                = 2004;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>CLOB</code>.
+     * @since 1.2
+     */
+        public final static int CLOB                = 2005;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type
+     * <code>REF</code>.
+     * @since 1.2
+     */
+        public final static int REF                 = 2006;
+
+    /**
+     * The constant in the Java programming language, somtimes referred to
+     * as a type code, that identifies the generic SQL type <code>DATALINK</code>.
+     *
+     * @since 1.4
+     */
+    public final static int DATALINK = 70;
+
+    /**
+     * The constant in the Java programming language, somtimes referred to
+     * as a type code, that identifies the generic SQL type <code>BOOLEAN</code>.
+     *
+     * @since 1.4
+     */
+    public final static int BOOLEAN = 16;
+
+    //------------------------- JDBC 4.0 -----------------------------------
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type <code>ROWID</code>
+     *
+     * @since 1.6
+     *
+     */
+    public final static int ROWID = -8;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type <code>NCHAR</code>
+     *
+     * @since 1.6
+     */
+    public static final int NCHAR = -15;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type <code>NVARCHAR</code>.
+     *
+     * @since 1.6
+     */
+    public static final int NVARCHAR = -9;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type <code>LONGNVARCHAR</code>.
+     *
+     * @since 1.6
+     */
+    public static final int LONGNVARCHAR = -16;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type <code>NCLOB</code>.
+     *
+     * @since 1.6
+     */
+    public static final int NCLOB = 2011;
+
+    /**
+     * The constant in the Java programming language, sometimes referred to
+     * as a type code, that identifies the generic SQL type <code>XML</code>.
+     *
+     * @since 1.6
+     */
+    public static final int SQLXML = 2009;
+
+    // Prevent instantiation
+    private Types() {}
+}
diff --git a/java/sql/Wrapper.java b/java/sql/Wrapper.java
new file mode 100644
index 0000000..2eaa003
--- /dev/null
+++ b/java/sql/Wrapper.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.sql;
+
+/**
+ * Interface for JDBC classes which provide the ability to retrieve the delegate instance when the instance
+ * in question is in fact a proxy class.
+ * <p>
+ * The wrapper pattern is employed by many JDBC driver implementations to provide extensions beyond
+ * the traditional JDBC API that are specific to a data source. Developers may wish to gain access to
+ * these resources that are wrapped (the delegates) as  proxy class instances representing the
+ * the actual resources. This interface describes a standard mechanism to access
+ * these wrapped resources
+ * represented by their proxy, to permit direct access to the resource delegates.
+ *
+ * @since 1.6
+ */
+
+public interface Wrapper {
+
+    /**
+     * Returns an object that implements the given interface to allow access to
+     * non-standard methods, or standard methods not exposed by the proxy.
+     *
+     * If the receiver implements the interface then the result is the receiver
+     * or a proxy for the receiver. If the receiver is a wrapper
+     * and the wrapped object implements the interface then the result is the
+     * wrapped object or a proxy for the wrapped object. Otherwise return the
+     * the result of calling <code>unwrap</code> recursively on the wrapped object
+     * or a proxy for that result. If the receiver is not a
+     * wrapper and does not implement the interface, then an <code>SQLException</code> is thrown.
+     *
+     * @param iface A Class defining an interface that the result must implement.
+     * @return an object that implements the interface. May be a proxy for the actual implementing object.
+     * @throws java.sql.SQLException If no object found that implements the interface
+     * @since 1.6
+     */
+        <T> T unwrap(java.lang.Class<T> iface) throws java.sql.SQLException;
+
+    /**
+     * Returns true if this either implements the interface argument or is directly or indirectly a wrapper
+     * for an object that does. Returns false otherwise. If this implements the interface then return true,
+     * else if this is a wrapper then return the result of recursively calling <code>isWrapperFor</code> on the wrapped
+     * object. If this does not implement the interface and is not a wrapper, return false.
+     * This method should be implemented as a low-cost operation compared to <code>unwrap</code> so that
+     * callers can use this method to avoid expensive <code>unwrap</code> calls that may fail. If this method
+     * returns true then calling <code>unwrap</code> with the same argument should succeed.
+     *
+     * @param iface a Class defining an interface.
+     * @return true if this implements the interface or directly or indirectly wraps an object that does.
+     * @throws java.sql.SQLException  if an error occurs while determining whether this is a wrapper
+     * for an object with the given interface.
+     * @since 1.6
+     */
+    boolean isWrapperFor(java.lang.Class<?> iface) throws java.sql.SQLException;
+
+}
diff --git a/java/text/Annotation.java b/java/text/Annotation.java
new file mode 100644
index 0000000..1f5577c
--- /dev/null
+++ b/java/text/Annotation.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+/**
+* An Annotation object is used as a wrapper for a text attribute value if
+* the attribute has annotation characteristics. These characteristics are:
+* <ul>
+* <li>The text range that the attribute is applied to is critical to the
+* semantics of the range. That means, the attribute cannot be applied to subranges
+* of the text range that it applies to, and, if two adjacent text ranges have
+* the same value for this attribute, the attribute still cannot be applied to
+* the combined range as a whole with this value.
+* <li>The attribute or its value usually do no longer apply if the underlying text is
+* changed.
+* </ul>
+*
+* An example is grammatical information attached to a sentence:
+* For the previous sentence, you can say that "an example"
+* is the subject, but you cannot say the same about "an", "example", or "exam".
+* When the text is changed, the grammatical information typically becomes invalid.
+* Another example is Japanese reading information (yomi).
+*
+* <p>
+* Wrapping the attribute value into an Annotation object guarantees that
+* adjacent text runs don't get merged even if the attribute values are equal,
+* and indicates to text containers that the attribute should be discarded if
+* the underlying text is modified.
+*
+* @see AttributedCharacterIterator
+* @since 1.2
+*/
+
+public class Annotation {
+
+    /**
+     * Constructs an annotation record with the given value, which
+     * may be null.
+     *
+     * @param value the value of the attribute
+     */
+    public Annotation(Object value) {
+        this.value = value;
+    }
+
+    /**
+     * Returns the value of the attribute, which may be null.
+     *
+     * @return the value of the attribute
+     */
+    public Object getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the String representation of this Annotation.
+     *
+     * @return the {@code String} representation of this {@code Annotation}
+     */
+    public String toString() {
+        return getClass().getName() + "[value=" + value + "]";
+    }
+
+    private Object value;
+
+};
diff --git a/java/text/AttributedCharacterIterator.java b/java/text/AttributedCharacterIterator.java
new file mode 100644
index 0000000..26a7e88
--- /dev/null
+++ b/java/text/AttributedCharacterIterator.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An {@code AttributedCharacterIterator} allows iteration through both text and
+ * related attribute information.
+ *
+ * <p>
+ * An attribute is a key/value pair, identified by the key.  No two
+ * attributes on a given character can have the same key.
+ *
+ * <p>The values for an attribute are immutable, or must not be mutated
+ * by clients or storage.  They are always passed by reference, and not
+ * cloned.
+ *
+ * <p>A <em>run with respect to an attribute</em> is a maximum text range for
+ * which:
+ * <ul>
+ * <li>the attribute is undefined or {@code null} for the entire range, or
+ * <li>the attribute value is defined and has the same non-{@code null} value for the
+ *     entire range.
+ * </ul>
+ *
+ * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
+ * which this condition is met for each member attribute.
+ *
+ * <p>When getting a run with no explicit attributes specified (i.e.,
+ * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
+ * contiguous text segments having the same attributes (the same set
+ * of attribute/value pairs) are treated as separate runs if the
+ * attributes have been given to those text segments separately.
+ *
+ * <p>The returned indexes are limited to the range of the iterator.
+ *
+ * <p>The returned attribute information is limited to runs that contain
+ * the current character.
+ *
+ * <p>
+ * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
+ * subclasses, such as {@link java.awt.font.TextAttribute}.
+ *
+ * @see AttributedCharacterIterator.Attribute
+ * @see java.awt.font.TextAttribute
+ * @see AttributedString
+ * @see Annotation
+ * @since 1.2
+ */
+
+public interface AttributedCharacterIterator extends CharacterIterator {
+
+    /**
+     * Defines attribute keys that are used to identify text attributes. These
+     * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
+     * @see AttributedCharacterIterator
+     * @see AttributedString
+     * @since 1.2
+     */
+
+    public static class Attribute implements Serializable {
+
+        /**
+         * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
+         * to look up the corresponding predefined instance when deserializing
+         * an instance.
+         * @serial
+         */
+        private String name;
+
+        // table of all instances in this class, used by readResolve
+        private static final Map<String, Attribute> instanceMap = new HashMap<>(7);
+
+        /**
+         * Constructs an {@code Attribute} with the given name.
+         *
+         * @param name the name of {@code Attribute}
+         */
+        protected Attribute(String name) {
+            this.name = name;
+            if (this.getClass() == Attribute.class) {
+                instanceMap.put(name, this);
+            }
+        }
+
+        /**
+         * Compares two objects for equality. This version only returns true
+         * for {@code x.equals(y)} if {@code x} and {@code y} refer
+         * to the same object, and guarantees this for all subclasses.
+         */
+        public final boolean equals(Object obj) {
+            return super.equals(obj);
+        }
+
+        /**
+         * Returns a hash code value for the object. This version is identical to
+         * the one in {@code Object}, but is also final.
+         */
+        public final int hashCode() {
+            return super.hashCode();
+        }
+
+        /**
+         * Returns a string representation of the object. This version returns the
+         * concatenation of class name, {@code "("}, a name identifying the attribute
+         * and {@code ")"}.
+         */
+        public String toString() {
+            return getClass().getName() + "(" + name + ")";
+        }
+
+        /**
+         * Returns the name of the attribute.
+         *
+         * @return the name of {@code Attribute}
+         */
+        protected String getName() {
+            return name;
+        }
+
+        /**
+         * Resolves instances being deserialized to the predefined constants.
+         *
+         * @return the resolved {@code Attribute} object
+         * @throws InvalidObjectException if the object to resolve is not
+         *                                an instance of {@code Attribute}
+         */
+        protected Object readResolve() throws InvalidObjectException {
+            if (this.getClass() != Attribute.class) {
+                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
+            }
+
+            Attribute instance = instanceMap.get(getName());
+            if (instance != null) {
+                return instance;
+            } else {
+                throw new InvalidObjectException("unknown attribute name");
+            }
+        }
+
+        /**
+         * Attribute key for the language of some text.
+         * <p> Values are instances of {@link java.util.Locale Locale}.
+         * @see java.util.Locale
+         */
+        public static final Attribute LANGUAGE = new Attribute("language");
+
+        /**
+         * Attribute key for the reading of some text. In languages where the written form
+         * and the pronunciation of a word are only loosely related (such as Japanese),
+         * it is often necessary to store the reading (pronunciation) along with the
+         * written form.
+         * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
+         *
+         * @see Annotation
+         * @see java.lang.String
+         */
+        public static final Attribute READING = new Attribute("reading");
+
+        /**
+         * Attribute key for input method segments. Input methods often break
+         * up text into segments, which usually correspond to words.
+         * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
+         * @see Annotation
+         */
+        public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
+
+        // make sure the serial version doesn't change between compiler versions
+        private static final long serialVersionUID = -9142742483513960612L;
+
+    };
+
+    /**
+     * Returns the index of the first character of the run
+     * with respect to all attributes containing the current character.
+     *
+     * <p>Any contiguous text segments having the same attributes (the
+     * same set of attribute/value pairs) are treated as separate runs
+     * if the attributes have been given to those text segments separately.
+     *
+     * @return the index of the first character of the run
+     */
+    public int getRunStart();
+
+    /**
+     * Returns the index of the first character of the run
+     * with respect to the given {@code attribute} containing the current character.
+     *
+     * @param attribute the desired attribute.
+     * @return the index of the first character of the run
+     */
+    public int getRunStart(Attribute attribute);
+
+    /**
+     * Returns the index of the first character of the run
+     * with respect to the given {@code attributes} containing the current character.
+     *
+     * @param attributes a set of the desired attributes.
+     * @return the index of the first character of the run
+     */
+    public int getRunStart(Set<? extends Attribute> attributes);
+
+    /**
+     * Returns the index of the first character following the run
+     * with respect to all attributes containing the current character.
+     *
+     * <p>Any contiguous text segments having the same attributes (the
+     * same set of attribute/value pairs) are treated as separate runs
+     * if the attributes have been given to those text segments separately.
+     *
+     * @return the index of the first character following the run
+     */
+    public int getRunLimit();
+
+    /**
+     * Returns the index of the first character following the run
+     * with respect to the given {@code attribute} containing the current character.
+     *
+     * @param attribute the desired attribute
+     * @return the index of the first character following the run
+     */
+    public int getRunLimit(Attribute attribute);
+
+    /**
+     * Returns the index of the first character following the run
+     * with respect to the given {@code attributes} containing the current character.
+     *
+     * @param attributes a set of the desired attributes
+     * @return the index of the first character following the run
+     */
+    public int getRunLimit(Set<? extends Attribute> attributes);
+
+    /**
+     * Returns a map with the attributes defined on the current
+     * character.
+     *
+     * @return a map with the attributes defined on the current character
+     */
+    public Map<Attribute,Object> getAttributes();
+
+    /**
+     * Returns the value of the named {@code attribute} for the current character.
+     * Returns {@code null} if the {@code attribute} is not defined.
+     *
+     * @param attribute the desired attribute
+     * @return the value of the named {@code attribute} or {@code null}
+     */
+    public Object getAttribute(Attribute attribute);
+
+    /**
+     * Returns the keys of all attributes defined on the
+     * iterator's text range. The set is empty if no
+     * attributes are defined.
+     *
+     * @return the keys of all attributes
+     */
+    public Set<Attribute> getAllAttributeKeys();
+};
diff --git a/java/text/AttributedString.java b/java/text/AttributedString.java
new file mode 100644
index 0000000..fa398e9
--- /dev/null
+++ b/java/text/AttributedString.java
@@ -0,0 +1,1133 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+import java.util.*;
+import java.text.AttributedCharacterIterator.Attribute;
+
+/**
+ * An AttributedString holds text and related attribute information. It
+ * may be used as the actual data storage in some cases where a text
+ * reader wants to access attributed text through the AttributedCharacterIterator
+ * interface.
+ *
+ * <p>
+ * An attribute is a key/value pair, identified by the key.  No two
+ * attributes on a given character can have the same key.
+ *
+ * <p>The values for an attribute are immutable, or must not be mutated
+ * by clients or storage.  They are always passed by reference, and not
+ * cloned.
+ *
+ * @see AttributedCharacterIterator
+ * @see Annotation
+ * @since 1.2
+ */
+
+public class AttributedString {
+
+    // since there are no vectors of int, we have to use arrays.
+    // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
+    private static final int ARRAY_SIZE_INCREMENT = 10;
+
+    // field holding the text
+    String text;
+
+    // fields holding run attribute information
+    // run attributes are organized by run
+    int runArraySize;               // current size of the arrays
+    int runCount;                   // actual number of runs, <= runArraySize
+    int runStarts[];                // start index for each run
+    Vector<Attribute> runAttributes[];         // vector of attribute keys for each run
+    Vector<Object> runAttributeValues[];    // parallel vector of attribute values for each run
+
+    /**
+     * Constructs an AttributedString instance with the given
+     * AttributedCharacterIterators.
+     *
+     * @param iterators AttributedCharacterIterators to construct
+     * AttributedString from.
+     * @throws NullPointerException if iterators is null
+     */
+    AttributedString(AttributedCharacterIterator[] iterators) {
+        if (iterators == null) {
+            throw new NullPointerException("Iterators must not be null");
+        }
+        if (iterators.length == 0) {
+            text = "";
+        }
+        else {
+            // Build the String contents
+            StringBuffer buffer = new StringBuffer();
+            for (int counter = 0; counter < iterators.length; counter++) {
+                appendContents(buffer, iterators[counter]);
+            }
+
+            text = buffer.toString();
+
+            if (text.length() > 0) {
+                // Determine the runs, creating a new run when the attributes
+                // differ.
+                int offset = 0;
+                Map<Attribute,Object> last = null;
+
+                for (int counter = 0; counter < iterators.length; counter++) {
+                    AttributedCharacterIterator iterator = iterators[counter];
+                    int start = iterator.getBeginIndex();
+                    int end = iterator.getEndIndex();
+                    int index = start;
+
+                    while (index < end) {
+                        iterator.setIndex(index);
+
+                        Map<Attribute,Object> attrs = iterator.getAttributes();
+
+                        if (mapsDiffer(last, attrs)) {
+                            setAttributes(attrs, index - start + offset);
+                        }
+                        last = attrs;
+                        index = iterator.getRunLimit();
+                    }
+                    offset += (end - start);
+                }
+            }
+        }
+    }
+
+    /**
+     * Constructs an AttributedString instance with the given text.
+     * @param text The text for this attributed string.
+     * @exception NullPointerException if <code>text</code> is null.
+     */
+    public AttributedString(String text) {
+        if (text == null) {
+            throw new NullPointerException();
+        }
+        this.text = text;
+    }
+
+    /**
+     * Constructs an AttributedString instance with the given text and attributes.
+     * @param text The text for this attributed string.
+     * @param attributes The attributes that apply to the entire string.
+     * @exception NullPointerException if <code>text</code> or
+     *            <code>attributes</code> is null.
+     * @exception IllegalArgumentException if the text has length 0
+     * and the attributes parameter is not an empty Map (attributes
+     * cannot be applied to a 0-length range).
+     */
+    public AttributedString(String text,
+                            Map<? extends Attribute, ?> attributes)
+    {
+        if (text == null || attributes == null) {
+            throw new NullPointerException();
+        }
+        this.text = text;
+
+        if (text.length() == 0) {
+            if (attributes.isEmpty())
+                return;
+            throw new IllegalArgumentException("Can't add attribute to 0-length text");
+        }
+
+        int attributeCount = attributes.size();
+        if (attributeCount > 0) {
+            createRunAttributeDataVectors();
+            Vector<Attribute> newRunAttributes = new Vector<>(attributeCount);
+            Vector<Object> newRunAttributeValues = new Vector<>(attributeCount);
+            runAttributes[0] = newRunAttributes;
+            runAttributeValues[0] = newRunAttributeValues;
+
+            Iterator<? extends Map.Entry<? extends Attribute, ?>> iterator = attributes.entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry<? extends Attribute, ?> entry = iterator.next();
+                newRunAttributes.addElement(entry.getKey());
+                newRunAttributeValues.addElement(entry.getValue());
+            }
+        }
+    }
+
+    /**
+     * Constructs an AttributedString instance with the given attributed
+     * text represented by AttributedCharacterIterator.
+     * @param text The text for this attributed string.
+     * @exception NullPointerException if <code>text</code> is null.
+     */
+    public AttributedString(AttributedCharacterIterator text) {
+        // If performance is critical, this constructor should be
+        // implemented here rather than invoking the constructor for a
+        // subrange. We can avoid some range checking in the loops.
+        this(text, text.getBeginIndex(), text.getEndIndex(), null);
+    }
+
+    /**
+     * Constructs an AttributedString instance with the subrange of
+     * the given attributed text represented by
+     * AttributedCharacterIterator. If the given range produces an
+     * empty text, all attributes will be discarded.  Note that any
+     * attributes wrapped by an Annotation object are discarded for a
+     * subrange of the original attribute range.
+     *
+     * @param text The text for this attributed string.
+     * @param beginIndex Index of the first character of the range.
+     * @param endIndex Index of the character following the last character
+     * of the range.
+     * @exception NullPointerException if <code>text</code> is null.
+     * @exception IllegalArgumentException if the subrange given by
+     * beginIndex and endIndex is out of the text range.
+     * @see java.text.Annotation
+     */
+    public AttributedString(AttributedCharacterIterator text,
+                            int beginIndex,
+                            int endIndex) {
+        this(text, beginIndex, endIndex, null);
+    }
+
+    /**
+     * Constructs an AttributedString instance with the subrange of
+     * the given attributed text represented by
+     * AttributedCharacterIterator.  Only attributes that match the
+     * given attributes will be incorporated into the instance. If the
+     * given range produces an empty text, all attributes will be
+     * discarded. Note that any attributes wrapped by an Annotation
+     * object are discarded for a subrange of the original attribute
+     * range.
+     *
+     * @param text The text for this attributed string.
+     * @param beginIndex Index of the first character of the range.
+     * @param endIndex Index of the character following the last character
+     * of the range.
+     * @param attributes Specifies attributes to be extracted
+     * from the text. If null is specified, all available attributes will
+     * be used.
+     * @exception NullPointerException if <code>text</code> is null.
+     * @exception IllegalArgumentException if the subrange given by
+     * beginIndex and endIndex is out of the text range.
+     * @see java.text.Annotation
+     */
+    public AttributedString(AttributedCharacterIterator text,
+                            int beginIndex,
+                            int endIndex,
+                            Attribute[] attributes) {
+        if (text == null) {
+            throw new NullPointerException();
+        }
+
+        // Validate the given subrange
+        int textBeginIndex = text.getBeginIndex();
+        int textEndIndex = text.getEndIndex();
+        if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
+            throw new IllegalArgumentException("Invalid substring range");
+
+        // Copy the given string
+        StringBuffer textBuffer = new StringBuffer();
+        text.setIndex(beginIndex);
+        for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
+            textBuffer.append(c);
+        this.text = textBuffer.toString();
+
+        if (beginIndex == endIndex)
+            return;
+
+        // Select attribute keys to be taken care of
+        HashSet<Attribute> keys = new HashSet<>();
+        if (attributes == null) {
+            keys.addAll(text.getAllAttributeKeys());
+        } else {
+            for (int i = 0; i < attributes.length; i++)
+                keys.add(attributes[i]);
+            keys.retainAll(text.getAllAttributeKeys());
+        }
+        if (keys.isEmpty())
+            return;
+
+        // Get and set attribute runs for each attribute name. Need to
+        // scan from the top of the text so that we can discard any
+        // Annotation that is no longer applied to a subset text segment.
+        Iterator<Attribute> itr = keys.iterator();
+        while (itr.hasNext()) {
+            Attribute attributeKey = itr.next();
+            text.setIndex(textBeginIndex);
+            while (text.getIndex() < endIndex) {
+                int start = text.getRunStart(attributeKey);
+                int limit = text.getRunLimit(attributeKey);
+                Object value = text.getAttribute(attributeKey);
+
+                if (value != null) {
+                    if (value instanceof Annotation) {
+                        if (start >= beginIndex && limit <= endIndex) {
+                            addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
+                        } else {
+                            if (limit > endIndex)
+                                break;
+                        }
+                    } else {
+                        // if the run is beyond the given (subset) range, we
+                        // don't need to process further.
+                        if (start >= endIndex)
+                            break;
+                        if (limit > beginIndex) {
+                            // attribute is applied to any subrange
+                            if (start < beginIndex)
+                                start = beginIndex;
+                            if (limit > endIndex)
+                                limit = endIndex;
+                            if (start != limit) {
+                                addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
+                            }
+                        }
+                    }
+                }
+                text.setIndex(limit);
+            }
+        }
+    }
+
+    /**
+     * Adds an attribute to the entire string.
+     * @param attribute the attribute key
+     * @param value the value of the attribute; may be null
+     * @exception NullPointerException if <code>attribute</code> is null.
+     * @exception IllegalArgumentException if the AttributedString has length 0
+     * (attributes cannot be applied to a 0-length range).
+     */
+    public void addAttribute(Attribute attribute, Object value) {
+
+        if (attribute == null) {
+            throw new NullPointerException();
+        }
+
+        int len = length();
+        if (len == 0) {
+            throw new IllegalArgumentException("Can't add attribute to 0-length text");
+        }
+
+        addAttributeImpl(attribute, value, 0, len);
+    }
+
+    /**
+     * Adds an attribute to a subrange of the string.
+     * @param attribute the attribute key
+     * @param value The value of the attribute. May be null.
+     * @param beginIndex Index of the first character of the range.
+     * @param endIndex Index of the character following the last character of the range.
+     * @exception NullPointerException if <code>attribute</code> is null.
+     * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
+     * greater than the length of the string, or beginIndex and endIndex together don't
+     * define a non-empty subrange of the string.
+     */
+    public void addAttribute(Attribute attribute, Object value,
+            int beginIndex, int endIndex) {
+
+        if (attribute == null) {
+            throw new NullPointerException();
+        }
+
+        if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
+            throw new IllegalArgumentException("Invalid substring range");
+        }
+
+        addAttributeImpl(attribute, value, beginIndex, endIndex);
+    }
+
+    /**
+     * Adds a set of attributes to a subrange of the string.
+     * @param attributes The attributes to be added to the string.
+     * @param beginIndex Index of the first character of the range.
+     * @param endIndex Index of the character following the last
+     * character of the range.
+     * @exception NullPointerException if <code>attributes</code> is null.
+     * @exception IllegalArgumentException if beginIndex is less then
+     * 0, endIndex is greater than the length of the string, or
+     * beginIndex and endIndex together don't define a non-empty
+     * subrange of the string and the attributes parameter is not an
+     * empty Map.
+     */
+    public void addAttributes(Map<? extends Attribute, ?> attributes,
+                              int beginIndex, int endIndex)
+    {
+        if (attributes == null) {
+            throw new NullPointerException();
+        }
+
+        if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
+            throw new IllegalArgumentException("Invalid substring range");
+        }
+        if (beginIndex == endIndex) {
+            if (attributes.isEmpty())
+                return;
+            throw new IllegalArgumentException("Can't add attribute to 0-length text");
+        }
+
+        // make sure we have run attribute data vectors
+        if (runCount == 0) {
+            createRunAttributeDataVectors();
+        }
+
+        // break up runs if necessary
+        int beginRunIndex = ensureRunBreak(beginIndex);
+        int endRunIndex = ensureRunBreak(endIndex);
+
+        Iterator<? extends Map.Entry<? extends Attribute, ?>> iterator =
+            attributes.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<? extends Attribute, ?> entry = iterator.next();
+            addAttributeRunData(entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
+        }
+    }
+
+    private synchronized void addAttributeImpl(Attribute attribute, Object value,
+            int beginIndex, int endIndex) {
+
+        // make sure we have run attribute data vectors
+        if (runCount == 0) {
+            createRunAttributeDataVectors();
+        }
+
+        // break up runs if necessary
+        int beginRunIndex = ensureRunBreak(beginIndex);
+        int endRunIndex = ensureRunBreak(endIndex);
+
+        addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
+    }
+
+    private final void createRunAttributeDataVectors() {
+        // use temporary variables so things remain consistent in case of an exception
+        int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
+
+        @SuppressWarnings("unchecked")
+        Vector<Attribute> newRunAttributes[] = (Vector<Attribute>[]) new Vector<?>[ARRAY_SIZE_INCREMENT];
+
+        @SuppressWarnings("unchecked")
+        Vector<Object> newRunAttributeValues[] = (Vector<Object>[]) new Vector<?>[ARRAY_SIZE_INCREMENT];
+
+        runStarts = newRunStarts;
+        runAttributes = newRunAttributes;
+        runAttributeValues = newRunAttributeValues;
+        runArraySize = ARRAY_SIZE_INCREMENT;
+        runCount = 1; // assume initial run starting at index 0
+    }
+
+    // ensure there's a run break at offset, return the index of the run
+    private final int ensureRunBreak(int offset) {
+        return ensureRunBreak(offset, true);
+    }
+
+    /**
+     * Ensures there is a run break at offset, returning the index of
+     * the run. If this results in splitting a run, two things can happen:
+     * <ul>
+     * <li>If copyAttrs is true, the attributes from the existing run
+     *     will be placed in both of the newly created runs.
+     * <li>If copyAttrs is false, the attributes from the existing run
+     * will NOT be copied to the run to the right (>= offset) of the break,
+     * but will exist on the run to the left (< offset).
+     * </ul>
+     */
+    private final int ensureRunBreak(int offset, boolean copyAttrs) {
+        if (offset == length()) {
+            return runCount;
+        }
+
+        // search for the run index where this offset should be
+        int runIndex = 0;
+        while (runIndex < runCount && runStarts[runIndex] < offset) {
+            runIndex++;
+        }
+
+        // if the offset is at a run start already, we're done
+        if (runIndex < runCount && runStarts[runIndex] == offset) {
+            return runIndex;
+        }
+
+        // we'll have to break up a run
+        // first, make sure we have enough space in our arrays
+        if (runCount == runArraySize) {
+            int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
+            int newRunStarts[] = new int[newArraySize];
+
+            @SuppressWarnings("unchecked")
+            Vector<Attribute> newRunAttributes[] = (Vector<Attribute>[]) new Vector<?>[newArraySize];
+
+            @SuppressWarnings("unchecked")
+            Vector<Object> newRunAttributeValues[] = (Vector<Object>[]) new Vector<?>[newArraySize];
+
+            for (int i = 0; i < runArraySize; i++) {
+                newRunStarts[i] = runStarts[i];
+                newRunAttributes[i] = runAttributes[i];
+                newRunAttributeValues[i] = runAttributeValues[i];
+            }
+            runStarts = newRunStarts;
+            runAttributes = newRunAttributes;
+            runAttributeValues = newRunAttributeValues;
+            runArraySize = newArraySize;
+        }
+
+        // make copies of the attribute information of the old run that the new one used to be part of
+        // use temporary variables so things remain consistent in case of an exception
+        Vector<Attribute> newRunAttributes = null;
+        Vector<Object> newRunAttributeValues = null;
+
+        if (copyAttrs) {
+            Vector<Attribute> oldRunAttributes = runAttributes[runIndex - 1];
+            Vector<Object> oldRunAttributeValues = runAttributeValues[runIndex - 1];
+            if (oldRunAttributes != null) {
+                newRunAttributes = new Vector<>(oldRunAttributes);
+            }
+            if (oldRunAttributeValues != null) {
+                newRunAttributeValues =  new Vector<>(oldRunAttributeValues);
+            }
+        }
+
+        // now actually break up the run
+        runCount++;
+        for (int i = runCount - 1; i > runIndex; i--) {
+            runStarts[i] = runStarts[i - 1];
+            runAttributes[i] = runAttributes[i - 1];
+            runAttributeValues[i] = runAttributeValues[i - 1];
+        }
+        runStarts[runIndex] = offset;
+        runAttributes[runIndex] = newRunAttributes;
+        runAttributeValues[runIndex] = newRunAttributeValues;
+
+        return runIndex;
+    }
+
+    // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
+    private void addAttributeRunData(Attribute attribute, Object value,
+            int beginRunIndex, int endRunIndex) {
+
+        for (int i = beginRunIndex; i < endRunIndex; i++) {
+            int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
+            if (runAttributes[i] == null) {
+                Vector<Attribute> newRunAttributes = new Vector<>();
+                Vector<Object> newRunAttributeValues = new Vector<>();
+                runAttributes[i] = newRunAttributes;
+                runAttributeValues[i] = newRunAttributeValues;
+            } else {
+                // check whether we have an entry already
+                keyValueIndex = runAttributes[i].indexOf(attribute);
+            }
+
+            if (keyValueIndex == -1) {
+                // create new entry
+                int oldSize = runAttributes[i].size();
+                runAttributes[i].addElement(attribute);
+                try {
+                    runAttributeValues[i].addElement(value);
+                }
+                catch (Exception e) {
+                    runAttributes[i].setSize(oldSize);
+                    runAttributeValues[i].setSize(oldSize);
+                }
+            } else {
+                // update existing entry
+                runAttributeValues[i].set(keyValueIndex, value);
+            }
+        }
+    }
+
+    /**
+     * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
+     * this string.
+     *
+     * @return An iterator providing access to the text and its attributes.
+     */
+    public AttributedCharacterIterator getIterator() {
+        return getIterator(null, 0, length());
+    }
+
+    /**
+     * Creates an AttributedCharacterIterator instance that provides access to
+     * selected contents of this string.
+     * Information about attributes not listed in attributes that the
+     * implementor may have need not be made accessible through the iterator.
+     * If the list is null, all available attribute information should be made
+     * accessible.
+     *
+     * @param attributes a list of attributes that the client is interested in
+     * @return an iterator providing access to the entire text and its selected attributes
+     */
+    public AttributedCharacterIterator getIterator(Attribute[] attributes) {
+        return getIterator(attributes, 0, length());
+    }
+
+    /**
+     * Creates an AttributedCharacterIterator instance that provides access to
+     * selected contents of this string.
+     * Information about attributes not listed in attributes that the
+     * implementor may have need not be made accessible through the iterator.
+     * If the list is null, all available attribute information should be made
+     * accessible.
+     *
+     * @param attributes a list of attributes that the client is interested in
+     * @param beginIndex the index of the first character
+     * @param endIndex the index of the character following the last character
+     * @return an iterator providing access to the text and its attributes
+     * @exception IllegalArgumentException if beginIndex is less then 0,
+     * endIndex is greater than the length of the string, or beginIndex is
+     * greater than endIndex.
+     */
+    public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
+        return new AttributedStringIterator(attributes, beginIndex, endIndex);
+    }
+
+    // all (with the exception of length) reading operations are private,
+    // since AttributedString instances are accessed through iterators.
+
+    // length is package private so that CharacterIteratorFieldDelegate can
+    // access it without creating an AttributedCharacterIterator.
+    int length() {
+        return text.length();
+    }
+
+    private char charAt(int index) {
+        return text.charAt(index);
+    }
+
+    private synchronized Object getAttribute(Attribute attribute, int runIndex) {
+        Vector<Attribute> currentRunAttributes = runAttributes[runIndex];
+        Vector<Object> currentRunAttributeValues = runAttributeValues[runIndex];
+        if (currentRunAttributes == null) {
+            return null;
+        }
+        int attributeIndex = currentRunAttributes.indexOf(attribute);
+        if (attributeIndex != -1) {
+            return currentRunAttributeValues.elementAt(attributeIndex);
+        }
+        else {
+            return null;
+        }
+    }
+
+    // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
+    private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
+        Object value = getAttribute(attribute, runIndex);
+        if (value instanceof Annotation) {
+            // need to check whether the annotation's range extends outside the iterator's range
+            if (beginIndex > 0) {
+                int currIndex = runIndex;
+                int runStart = runStarts[currIndex];
+                while (runStart >= beginIndex &&
+                        valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
+                    currIndex--;
+                    runStart = runStarts[currIndex];
+                }
+                if (runStart < beginIndex) {
+                    // annotation's range starts before iterator's range
+                    return null;
+                }
+            }
+            int textLength = length();
+            if (endIndex < textLength) {
+                int currIndex = runIndex;
+                int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
+                while (runLimit <= endIndex &&
+                        valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
+                    currIndex++;
+                    runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
+                }
+                if (runLimit > endIndex) {
+                    // annotation's range ends after iterator's range
+                    return null;
+                }
+            }
+            // annotation's range is subrange of iterator's range,
+            // so we can return the value
+        }
+        return value;
+    }
+
+    // returns whether all specified attributes have equal values in the runs with the given indices
+    private boolean attributeValuesMatch(Set<? extends Attribute> attributes, int runIndex1, int runIndex2) {
+        Iterator<? extends Attribute> iterator = attributes.iterator();
+        while (iterator.hasNext()) {
+            Attribute key = iterator.next();
+           if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // returns whether the two objects are either both null or equal
+    private final static boolean valuesMatch(Object value1, Object value2) {
+        if (value1 == null) {
+            return value2 == null;
+        } else {
+            return value1.equals(value2);
+        }
+    }
+
+    /**
+     * Appends the contents of the CharacterIterator iterator into the
+     * StringBuffer buf.
+     */
+    private final void appendContents(StringBuffer buf,
+                                      CharacterIterator iterator) {
+        int index = iterator.getBeginIndex();
+        int end = iterator.getEndIndex();
+
+        while (index < end) {
+            iterator.setIndex(index++);
+            buf.append(iterator.current());
+        }
+    }
+
+    /**
+     * Sets the attributes for the range from offset to the next run break
+     * (typically the end of the text) to the ones specified in attrs.
+     * This is only meant to be called from the constructor!
+     */
+    private void setAttributes(Map<Attribute, Object> attrs, int offset) {
+        if (runCount == 0) {
+            createRunAttributeDataVectors();
+        }
+
+        int index = ensureRunBreak(offset, false);
+        int size;
+
+        if (attrs != null && (size = attrs.size()) > 0) {
+            Vector<Attribute> runAttrs = new Vector<>(size);
+            Vector<Object> runValues = new Vector<>(size);
+            Iterator<Map.Entry<Attribute, Object>> iterator = attrs.entrySet().iterator();
+
+            while (iterator.hasNext()) {
+                Map.Entry<Attribute, Object> entry = iterator.next();
+
+                runAttrs.add(entry.getKey());
+                runValues.add(entry.getValue());
+            }
+            runAttributes[index] = runAttrs;
+            runAttributeValues[index] = runValues;
+        }
+    }
+
+    /**
+     * Returns true if the attributes specified in last and attrs differ.
+     */
+    private static <K,V> boolean mapsDiffer(Map<K, V> last, Map<K, V> attrs) {
+        if (last == null) {
+            return (attrs != null && attrs.size() > 0);
+        }
+        return (!last.equals(attrs));
+    }
+
+
+    // the iterator class associated with this string class
+
+    final private class AttributedStringIterator implements AttributedCharacterIterator {
+
+        // note on synchronization:
+        // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
+        // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
+
+        // start and end index for our iteration
+        private int beginIndex;
+        private int endIndex;
+
+        // attributes that our client is interested in
+        private Attribute[] relevantAttributes;
+
+        // the current index for our iteration
+        // invariant: beginIndex <= currentIndex <= endIndex
+        private int currentIndex;
+
+        // information about the run that includes currentIndex
+        private int currentRunIndex;
+        private int currentRunStart;
+        private int currentRunLimit;
+
+        // constructor
+        AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
+
+            if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
+                throw new IllegalArgumentException("Invalid substring range");
+            }
+
+            this.beginIndex = beginIndex;
+            this.endIndex = endIndex;
+            this.currentIndex = beginIndex;
+            updateRunInfo();
+            if (attributes != null) {
+                relevantAttributes = attributes.clone();
+            }
+        }
+
+        // Object methods. See documentation in that class.
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof AttributedStringIterator)) {
+                return false;
+            }
+
+            AttributedStringIterator that = (AttributedStringIterator) obj;
+
+            if (AttributedString.this != that.getString())
+                return false;
+            if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
+                return false;
+            return true;
+        }
+
+        public int hashCode() {
+            return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
+        }
+
+        public Object clone() {
+            try {
+                AttributedStringIterator other = (AttributedStringIterator) super.clone();
+                return other;
+            }
+            catch (CloneNotSupportedException e) {
+                throw new InternalError(e);
+            }
+        }
+
+        // CharacterIterator methods. See documentation in that interface.
+
+        public char first() {
+            return internalSetIndex(beginIndex);
+        }
+
+        public char last() {
+            if (endIndex == beginIndex) {
+                return internalSetIndex(endIndex);
+            } else {
+                return internalSetIndex(endIndex - 1);
+            }
+        }
+
+        public char current() {
+            if (currentIndex == endIndex) {
+                return DONE;
+            } else {
+                return charAt(currentIndex);
+            }
+        }
+
+        public char next() {
+            if (currentIndex < endIndex) {
+                return internalSetIndex(currentIndex + 1);
+            }
+            else {
+                return DONE;
+            }
+        }
+
+        public char previous() {
+            if (currentIndex > beginIndex) {
+                return internalSetIndex(currentIndex - 1);
+            }
+            else {
+                return DONE;
+            }
+        }
+
+        public char setIndex(int position) {
+            if (position < beginIndex || position > endIndex)
+                throw new IllegalArgumentException("Invalid index");
+            return internalSetIndex(position);
+        }
+
+        public int getBeginIndex() {
+            return beginIndex;
+        }
+
+        public int getEndIndex() {
+            return endIndex;
+        }
+
+        public int getIndex() {
+            return currentIndex;
+        }
+
+        // AttributedCharacterIterator methods. See documentation in that interface.
+
+        public int getRunStart() {
+            return currentRunStart;
+        }
+
+        public int getRunStart(Attribute attribute) {
+            if (currentRunStart == beginIndex || currentRunIndex == -1) {
+                return currentRunStart;
+            } else {
+                Object value = getAttribute(attribute);
+                int runStart = currentRunStart;
+                int runIndex = currentRunIndex;
+                while (runStart > beginIndex &&
+                        valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
+                    runIndex--;
+                    runStart = runStarts[runIndex];
+                }
+                if (runStart < beginIndex) {
+                    runStart = beginIndex;
+                }
+                return runStart;
+            }
+        }
+
+        public int getRunStart(Set<? extends Attribute> attributes) {
+            if (currentRunStart == beginIndex || currentRunIndex == -1) {
+                return currentRunStart;
+            } else {
+                int runStart = currentRunStart;
+                int runIndex = currentRunIndex;
+                while (runStart > beginIndex &&
+                        AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
+                    runIndex--;
+                    runStart = runStarts[runIndex];
+                }
+                if (runStart < beginIndex) {
+                    runStart = beginIndex;
+                }
+                return runStart;
+            }
+        }
+
+        public int getRunLimit() {
+            return currentRunLimit;
+        }
+
+        public int getRunLimit(Attribute attribute) {
+            if (currentRunLimit == endIndex || currentRunIndex == -1) {
+                return currentRunLimit;
+            } else {
+                Object value = getAttribute(attribute);
+                int runLimit = currentRunLimit;
+                int runIndex = currentRunIndex;
+                while (runLimit < endIndex &&
+                        valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
+                    runIndex++;
+                    runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
+                }
+                if (runLimit > endIndex) {
+                    runLimit = endIndex;
+                }
+                return runLimit;
+            }
+        }
+
+        public int getRunLimit(Set<? extends Attribute> attributes) {
+            if (currentRunLimit == endIndex || currentRunIndex == -1) {
+                return currentRunLimit;
+            } else {
+                int runLimit = currentRunLimit;
+                int runIndex = currentRunIndex;
+                while (runLimit < endIndex &&
+                        AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
+                    runIndex++;
+                    runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
+                }
+                if (runLimit > endIndex) {
+                    runLimit = endIndex;
+                }
+                return runLimit;
+            }
+        }
+
+        public Map<Attribute,Object> getAttributes() {
+            if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
+                // ??? would be nice to return null, but current spec doesn't allow it
+                // returning Hashtable saves AttributeMap from dealing with emptiness
+                return new Hashtable<>();
+            }
+            return new AttributeMap(currentRunIndex, beginIndex, endIndex);
+        }
+
+        public Set<Attribute> getAllAttributeKeys() {
+            // ??? This should screen out attribute keys that aren't relevant to the client
+            if (runAttributes == null) {
+                // ??? would be nice to return null, but current spec doesn't allow it
+                // returning HashSet saves us from dealing with emptiness
+                return new HashSet<>();
+            }
+            synchronized (AttributedString.this) {
+                // ??? should try to create this only once, then update if necessary,
+                // and give callers read-only view
+                Set<Attribute> keys = new HashSet<>();
+                int i = 0;
+                while (i < runCount) {
+                    if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
+                        Vector<Attribute> currentRunAttributes = runAttributes[i];
+                        if (currentRunAttributes != null) {
+                            int j = currentRunAttributes.size();
+                            while (j-- > 0) {
+                                keys.add(currentRunAttributes.get(j));
+                            }
+                        }
+                    }
+                    i++;
+                }
+                return keys;
+            }
+        }
+
+        public Object getAttribute(Attribute attribute) {
+            int runIndex = currentRunIndex;
+            if (runIndex < 0) {
+                return null;
+            }
+            return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
+        }
+
+        // internally used methods
+
+        private AttributedString getString() {
+            return AttributedString.this;
+        }
+
+        // set the current index, update information about the current run if necessary,
+        // return the character at the current index
+        private char internalSetIndex(int position) {
+            currentIndex = position;
+            if (position < currentRunStart || position >= currentRunLimit) {
+                updateRunInfo();
+            }
+            if (currentIndex == endIndex) {
+                return DONE;
+            } else {
+                return charAt(position);
+            }
+        }
+
+        // update the information about the current run
+        private void updateRunInfo() {
+            if (currentIndex == endIndex) {
+                currentRunStart = currentRunLimit = endIndex;
+                currentRunIndex = -1;
+            } else {
+                synchronized (AttributedString.this) {
+                    int runIndex = -1;
+                    while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
+                        runIndex++;
+                    currentRunIndex = runIndex;
+                    if (runIndex >= 0) {
+                        currentRunStart = runStarts[runIndex];
+                        if (currentRunStart < beginIndex)
+                            currentRunStart = beginIndex;
+                    }
+                    else {
+                        currentRunStart = beginIndex;
+                    }
+                    if (runIndex < runCount - 1) {
+                        currentRunLimit = runStarts[runIndex + 1];
+                        if (currentRunLimit > endIndex)
+                            currentRunLimit = endIndex;
+                    }
+                    else {
+                        currentRunLimit = endIndex;
+                    }
+                }
+            }
+        }
+
+    }
+
+    // the map class associated with this string class, giving access to the attributes of one run
+
+    final private class AttributeMap extends AbstractMap<Attribute,Object> {
+
+        int runIndex;
+        int beginIndex;
+        int endIndex;
+
+        AttributeMap(int runIndex, int beginIndex, int endIndex) {
+            this.runIndex = runIndex;
+            this.beginIndex = beginIndex;
+            this.endIndex = endIndex;
+        }
+
+        public Set<Map.Entry<Attribute, Object>> entrySet() {
+            HashSet<Map.Entry<Attribute, Object>> set = new HashSet<>();
+            synchronized (AttributedString.this) {
+                int size = runAttributes[runIndex].size();
+                for (int i = 0; i < size; i++) {
+                    Attribute key = runAttributes[runIndex].get(i);
+                    Object value = runAttributeValues[runIndex].get(i);
+                    if (value instanceof Annotation) {
+                        value = AttributedString.this.getAttributeCheckRange(key,
+                                                             runIndex, beginIndex, endIndex);
+                        if (value == null) {
+                            continue;
+                        }
+                    }
+
+                    Map.Entry<Attribute, Object> entry = new AttributeEntry(key, value);
+                    set.add(entry);
+                }
+            }
+            return set;
+        }
+
+        public Object get(Object key) {
+            return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
+        }
+    }
+}
+
+class AttributeEntry implements Map.Entry<Attribute,Object> {
+
+    private Attribute key;
+    private Object value;
+
+    AttributeEntry(Attribute key, Object value) {
+        this.key = key;
+        this.value = value;
+    }
+
+    public boolean equals(Object o) {
+        if (!(o instanceof AttributeEntry)) {
+            return false;
+        }
+        AttributeEntry other = (AttributeEntry) o;
+        return other.key.equals(key) &&
+            (value == null ? other.value == null : other.value.equals(value));
+    }
+
+    public Attribute getKey() {
+        return key;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public Object setValue(Object newValue) {
+        throw new UnsupportedOperationException();
+    }
+
+    public int hashCode() {
+        return key.hashCode() ^ (value==null ? 0 : value.hashCode());
+    }
+
+    public String toString() {
+        return key.toString()+"="+value.toString();
+    }
+}
diff --git a/java/text/Bidi.java b/java/text/Bidi.java
new file mode 100644
index 0000000..70e29aa
--- /dev/null
+++ b/java/text/Bidi.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved
+ *
+ * The original version of this source code and documentation is
+ * copyrighted and owned by IBM. These materials are provided
+ * under terms of a License Agreement between IBM and Sun.
+ * This technology is protected by multiple US and International
+ * patents. This notice and attribution to IBM may not be removed.
+ */
+
+package java.text;
+
+/**
+ * This class implements the Unicode Bidirectional Algorithm.
+ * <p>
+ * A Bidi object provides information on the bidirectional reordering of the text
+ * used to create it.  This is required, for example, to properly display Arabic
+ * or Hebrew text.  These languages are inherently mixed directional, as they order
+ * numbers from left-to-right while ordering most other text from right-to-left.
+ * <p>
+ * Once created, a Bidi object can be queried to see if the text it represents is
+ * all left-to-right or all right-to-left.  Such objects are very lightweight and
+ * this text is relatively easy to process.
+ * <p>
+ * If there are multiple runs of text, information about the runs can be accessed
+ * by indexing to get the start, limit, and level of a run.  The level represents
+ * both the direction and the 'nesting level' of a directional run.  Odd levels
+ * are right-to-left, while even levels are left-to-right.  So for example level
+ * 0 represents left-to-right text, while level 1 represents right-to-left text, and
+ * level 2 represents left-to-right text embedded in a right-to-left run.
+ *
+ * @since 1.4
+ */
+public final class Bidi {
+
+    /** Constant indicating base direction is left-to-right. */
+    public static final int DIRECTION_LEFT_TO_RIGHT = 0;
+
+    /** Constant indicating base direction is right-to-left. */
+    public static final int DIRECTION_RIGHT_TO_LEFT = 1;
+
+    /**
+     * Constant indicating that the base direction depends on the first strong
+     * directional character in the text according to the Unicode
+     * Bidirectional Algorithm.  If no strong directional character is present,
+     * the base direction is left-to-right.
+     */
+    public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2;
+
+    /**
+     * Constant indicating that the base direction depends on the first strong
+     * directional character in the text according to the Unicode
+     * Bidirectional Algorithm.  If no strong directional character is present,
+     * the base direction is right-to-left.
+     */
+    public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1;
+
+    // Android-note: Upstream this class delegates to an internal implementation class BidiBase.
+    // For Android that is replaced with android.icu.text.Bidi. BidiBase and ICU Bidi work very
+    // similarly, but differ in some details like level of argument validation and how how exactly
+    // runs are counted. The majority of the changes in this file exist to allow for backwards
+    // compatibility with an earlier ICU4C based Bidi implementation.
+
+    // BEGIN Android-added: translateConstToIcu(int).
+    private static int translateConstToIcu(int javaInt) {
+        switch (javaInt) {
+            case DIRECTION_DEFAULT_LEFT_TO_RIGHT:
+                return android.icu.text.Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT;
+            case DIRECTION_DEFAULT_RIGHT_TO_LEFT:
+                return android.icu.text.Bidi.DIRECTION_DEFAULT_RIGHT_TO_LEFT;
+            case DIRECTION_LEFT_TO_RIGHT:
+                return android.icu.text.Bidi.DIRECTION_LEFT_TO_RIGHT;
+            case DIRECTION_RIGHT_TO_LEFT:
+                return android.icu.text.Bidi.DIRECTION_RIGHT_TO_LEFT;
+            // If the parameter was unrecognized use LEFT_TO_RIGHT.
+            default:
+                return android.icu.text.Bidi.DIRECTION_LEFT_TO_RIGHT;
+        }
+    }
+    // END Android-added: translateConstToIcu(int).
+
+    // Android-changed: use ICU Bidi class instead of BidiBase.
+    private final android.icu.text.Bidi bidiBase;
+
+    /**
+     * Create Bidi from the given paragraph of text and base direction.
+     * @param paragraph a paragraph of text
+     * @param flags a collection of flags that control the algorithm.  The
+     * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
+     * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
+     * Other values are reserved.
+     */
+    public Bidi(String paragraph, int flags) {
+        if (paragraph == null) {
+            throw new IllegalArgumentException("paragraph is null");
+        }
+
+        // Android-changed: use ICU Bidi class instead of BidiBase.
+        bidiBase = new android.icu.text.Bidi(paragraph.toCharArray(), 0, null, 0,
+                                             paragraph.length(), translateConstToIcu(flags));
+    }
+
+    /**
+     * Create Bidi from the given paragraph of text.
+     * <p>
+     * The RUN_DIRECTION attribute in the text, if present, determines the base
+     * direction (left-to-right or right-to-left).  If not present, the base
+     * direction is computes using the Unicode Bidirectional Algorithm, defaulting to left-to-right
+     * if there are no strong directional characters in the text.  This attribute, if
+     * present, must be applied to all the text in the paragraph.
+     * <p>
+     * The BIDI_EMBEDDING attribute in the text, if present, represents embedding level
+     * information.  Negative values from -1 to -62 indicate overrides at the absolute value
+     * of the level.  Positive values from 1 to 62 indicate embeddings.  Where values are
+     * zero or not defined, the base embedding level as determined by the base direction
+     * is assumed.
+     * <p>
+     * The NUMERIC_SHAPING attribute in the text, if present, converts European digits to
+     * other decimal digits before running the bidi algorithm.  This attribute, if present,
+     * must be applied to all the text in the paragraph.
+     *
+     * @param paragraph a paragraph of text with optional character and paragraph attribute information
+     *
+     * @see java.awt.font.TextAttribute#BIDI_EMBEDDING
+     * @see java.awt.font.TextAttribute#NUMERIC_SHAPING
+     * @see java.awt.font.TextAttribute#RUN_DIRECTION
+     */
+    public Bidi(AttributedCharacterIterator paragraph) {
+        if (paragraph == null) {
+            throw new IllegalArgumentException("paragraph is null");
+        }
+
+        // Android-changed: change from BidiBase to ICU Bidi class.
+        this.bidiBase = new android.icu.text.Bidi(paragraph);
+    }
+
+    /**
+     * Create Bidi from the given text, embedding, and direction information.
+     * The embeddings array may be null.  If present, the values represent embedding level
+     * information.  Negative values from -1 to -61 indicate overrides at the absolute value
+     * of the level.  Positive values from 1 to 61 indicate embeddings.  Where values are
+     * zero, the base embedding level as determined by the base direction is assumed.
+     * @param text an array containing the paragraph of text to process.
+     * @param textStart the index into the text array of the start of the paragraph.
+     * @param embeddings an array containing embedding values for each character in the paragraph.
+     * This can be null, in which case it is assumed that there is no external embedding information.
+     * @param embStart the index into the embedding array of the start of the paragraph.
+     * @param paragraphLength the length of the paragraph in the text and embeddings arrays.
+     * @param flags a collection of flags that control the algorithm.  The
+     * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
+     * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
+     * Other values are reserved.
+     */
+    public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) {
+        if (text == null) {
+            throw new IllegalArgumentException("text is null");
+        }
+        if (paragraphLength < 0) {
+            throw new IllegalArgumentException("bad length: " + paragraphLength);
+        }
+        if (textStart < 0 || paragraphLength > text.length - textStart) {
+            throw new IllegalArgumentException("bad range: " + textStart +
+                                               " length: " + paragraphLength +
+                                               " for text of length: " + text.length);
+        }
+        if (embeddings != null && (embStart < 0 || paragraphLength > embeddings.length - embStart)) {
+            throw new IllegalArgumentException("bad range: " + embStart +
+                                               " length: " + paragraphLength +
+                                               " for embeddings of length: " + text.length);
+        }
+
+        // Android-changed: use ICU Bidi class instead of BidiBase.
+        bidiBase = new android.icu.text.Bidi(text, textStart, embeddings, embStart,
+                                             paragraphLength, translateConstToIcu(flags));
+    }
+
+    // Android-added: private constructor based on ICU Bidi object.
+    private Bidi(android.icu.text.Bidi bidiBase) {
+        this.bidiBase = bidiBase;
+    }
+
+    /**
+     * Create a Bidi object representing the bidi information on a line of text within
+     * the paragraph represented by the current Bidi.  This call is not required if the
+     * entire paragraph fits on one line.
+     *
+     * @param lineStart the offset from the start of the paragraph to the start of the line.
+     * @param lineLimit the offset from the start of the paragraph to the limit of the line.
+     * @return a {@code Bidi} object
+     */
+    public Bidi createLineBidi(int lineStart, int lineLimit) {
+        // BEGIN Android-changed: add explict argument checks and use ICU Bidi class.
+        if (lineStart < 0 || lineLimit < 0 || lineStart > lineLimit || lineLimit > getLength()) {
+            throw new IllegalArgumentException("Invalid ranges (start=" + lineStart + ", " +
+                                               "limit=" + lineLimit + ", length=" + getLength() + ")");
+        }
+
+        // In the special case where the start and end positions are the same, we return a new bidi
+        // instance which is empty. Note that the default constructor for an empty ICU4J bidi
+        // instance is not the same as passing in empty values. This way allows one to call
+        // .getLength() for example and return a correct value instead of an IllegalStateException
+        // being thrown, which happens in the case of using the empty constructor.
+        if (lineStart == lineLimit) {
+            return new Bidi(new android.icu.text.Bidi(new char[] {}, 0, new byte[] {}, 0, 0,
+                                                      translateConstToIcu(DIRECTION_LEFT_TO_RIGHT)));
+         }
+
+        return new Bidi(bidiBase.createLineBidi(lineStart, lineLimit));
+        // END Android-changed: add explict argument checks and use ICU Bidi class.
+    }
+
+    /**
+     * Return true if the line is not left-to-right or right-to-left.  This means it either has mixed runs of left-to-right
+     * and right-to-left text, or the base direction differs from the direction of the only run of text.
+     *
+     * @return true if the line is not left-to-right or right-to-left.
+     */
+    public boolean isMixed() {
+        return bidiBase.isMixed();
+    }
+
+    /**
+     * Return true if the line is all left-to-right text and the base direction is left-to-right.
+     *
+     * @return true if the line is all left-to-right text and the base direction is left-to-right
+     */
+    public boolean isLeftToRight() {
+        return bidiBase.isLeftToRight();
+    }
+
+    /**
+     * Return true if the line is all right-to-left text, and the base direction is right-to-left.
+     * @return true if the line is all right-to-left text, and the base direction is right-to-left
+     */
+    public boolean isRightToLeft() {
+        return bidiBase.isRightToLeft();
+    }
+
+    /**
+     * Return the length of text in the line.
+     * @return the length of text in the line
+     */
+    public int getLength() {
+        return bidiBase.getLength();
+    }
+
+    /**
+     * Return true if the base direction is left-to-right.
+     * @return true if the base direction is left-to-right
+     */
+    public boolean baseIsLeftToRight() {
+        return bidiBase.baseIsLeftToRight();
+    }
+
+    /**
+     * Return the base level (0 if left-to-right, 1 if right-to-left).
+     * @return the base level
+     */
+    public int getBaseLevel() {
+        return bidiBase.getParaLevel();
+    }
+
+    /**
+     * Return the resolved level of the character at offset.  If offset is
+     * {@literal <} 0 or &ge; the length of the line, return the base direction
+     * level.
+     *
+     * @param offset the index of the character for which to return the level
+     * @return the resolved level of the character at offset
+     */
+    public int getLevelAt(int offset) {
+        // BEGIN Android-changed: return base level on out of range offset argument.
+        try {
+            return bidiBase.getLevelAt(offset);
+        } catch (IllegalArgumentException e) {
+            return getBaseLevel();
+        }
+        // END Android-changed: return base level on out of range offset argument.
+    }
+
+    /**
+     * Return the number of level runs.
+     * @return the number of level runs
+     */
+    public int getRunCount() {
+        // Android-changed: ICU treats the empty string as having 0 runs, we see it as 1 empty run.
+        int runCount = bidiBase.countRuns();
+        return (runCount == 0 ? 1 : runCount);
+    }
+
+    /**
+     * Return the level of the nth logical run in this line.
+     * @param run the index of the run, between 0 and <code>getRunCount()</code>
+     * @return the level of the run
+     */
+    public int getRunLevel(int run) {
+        // Android-added: Tolerate calls with run == getRunCount() for backwards compatibility.
+        if (run == getRunCount()) {
+            return getBaseLevel();
+        }
+        // Android-changed: ICU treats the empty string as having 0 runs, we see it as 1 empty run.
+        return (bidiBase.countRuns() == 0 ? bidiBase.getBaseLevel() : bidiBase.getRunLevel(run));
+    }
+
+    /**
+     * Return the index of the character at the start of the nth logical run in this line, as
+     * an offset from the start of the line.
+     * @param run the index of the run, between 0 and <code>getRunCount()</code>
+     * @return the start of the run
+     */
+    public int getRunStart(int run) {
+        // Android-added: Tolerate calls with run == getRunCount() for backwards compatibility.
+        if (run == getRunCount()) {
+            return getBaseLevel();
+        }
+        // Android-changed: ICU treats the empty string as having 0 runs, we see it as 1 empty run.
+        return (bidiBase.countRuns() == 0 ? 0 : bidiBase.getRunStart(run));
+    }
+
+    /**
+     * Return the index of the character past the end of the nth logical run in this line, as
+     * an offset from the start of the line.  For example, this will return the length
+     * of the line for the last run on the line.
+     * @param run the index of the run, between 0 and <code>getRunCount()</code>
+     * @return limit the limit of the run
+     */
+    public int getRunLimit(int run) {
+        // Android-added: Tolerate calls with run == getRunCount() for backwards compatibility.
+        if (run == getRunCount()) {
+            return getBaseLevel();
+        }
+        // Android-changed: ICU treats the empty string as having 0 runs, we see it as 1 empty run.
+        return (bidiBase.countRuns() == 0 ? bidiBase.getLength() : bidiBase.getRunLimit(run));
+    }
+
+    /**
+     * Return true if the specified text requires bidi analysis.  If this returns false,
+     * the text will display left-to-right.  Clients can then avoid constructing a Bidi object.
+     * Text in the Arabic Presentation Forms area of Unicode is presumed to already be shaped
+     * and ordered for display, and so will not cause this function to return true.
+     *
+     * @param text the text containing the characters to test
+     * @param start the start of the range of characters to test
+     * @param limit the limit of the range of characters to test
+     * @return true if the range of characters requires bidi analysis
+     */
+    public static boolean requiresBidi(char[] text, int start, int limit) {
+        // Android-added: Check arguments to throw correct exception.
+        if (0 > start || start > limit || limit > text.length) {
+            throw new IllegalArgumentException("Value start " + start +
+                                               " is out of range 0 to " + limit);
+        }
+        return android.icu.text.Bidi.requiresBidi(text, start, limit);
+    }
+
+    /**
+     * Reorder the objects in the array into visual order based on their levels.
+     * This is a utility function to use when you have a collection of objects
+     * representing runs of text in logical order, each run containing text
+     * at a single level.  The elements at <code>index</code> from
+     * <code>objectStart</code> up to <code>objectStart + count</code>
+     * in the objects array will be reordered into visual order assuming
+     * each run of text has the level indicated by the corresponding element
+     * in the levels array (at <code>index - objectStart + levelStart</code>).
+     *
+     * @param levels an array representing the bidi level of each object
+     * @param levelStart the start position in the levels array
+     * @param objects the array of objects to be reordered into visual order
+     * @param objectStart the start position in the objects array
+     * @param count the number of objects to reorder
+     */
+    public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) {
+        // BEGIN Android-added: Check arguments to throw correct exception.
+        if (0 > levelStart || levels.length <= levelStart) {
+            throw new IllegalArgumentException("Value levelStart " +
+                      levelStart + " is out of range 0 to " +
+                      (levels.length-1));
+        }
+        if (0 > objectStart || objects.length <= objectStart) {
+            throw new IllegalArgumentException("Value objectStart " +
+                      levelStart + " is out of range 0 to " +
+                      (objects.length-1));
+        }
+        if (0 > count || objects.length < (objectStart+count)) {
+            throw new IllegalArgumentException("Value count " +
+                      levelStart + " is out of range 0 to " +
+                      (objects.length - objectStart));
+        }
+        // END Android-added: Check arguments to throw correct exception.
+
+        // Android-changed: use ICU Bidi class instead of BidiBase.
+        android.icu.text.Bidi.reorderVisually(levels, levelStart, objects, objectStart, count);
+    }
+
+    /**
+     * Display the bidi internal state, used in debugging.
+     */
+    public String toString() {
+        // Android-changed: construct String representation from ICU Bidi object values.
+        return getClass().getName()
+            + "[direction: " + bidiBase.getDirection() + " baseLevel: " + bidiBase.getBaseLevel()
+            + " length: " + bidiBase.getLength() + " runs: " + bidiBase.getRunCount() + "]";
+    }
+
+}
diff --git a/java/text/BreakIterator.java b/java/text/BreakIterator.java
new file mode 100644
index 0000000..a875ec1
--- /dev/null
+++ b/java/text/BreakIterator.java
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.util.Locale;
+
+
+// Android-changed: Discourage modification on CharacterIterator after setText. http://b/80456574
+/**
+ * The <code>BreakIterator</code> class implements methods for finding
+ * the location of boundaries in text. Instances of <code>BreakIterator</code>
+ * maintain a current position and scan over text
+ * returning the index of characters where boundaries occur.
+ * Internally, <code>BreakIterator</code> scans text using a
+ * <code>CharacterIterator</code>, and is thus able to scan text held
+ * by any object implementing that protocol. A <code>StringCharacterIterator</code>
+ * is used to scan <code>String</code> objects passed to <code>setText</code>.
+ * The <code>CharacterIterator</code> object must not be modified after having been
+ * passed to <code>setText</code>. If the text in the <code>CharacterIterator</code> object
+ * is changed, the caller must reset <code>BreakIterator</code> by calling
+ * <code>setText</code>.
+ *
+ * <p>
+ * You use the factory methods provided by this class to create
+ * instances of various types of break iterators. In particular,
+ * use <code>getWordInstance</code>, <code>getLineInstance</code>,
+ * <code>getSentenceInstance</code>, and <code>getCharacterInstance</code>
+ * to create <code>BreakIterator</code>s that perform
+ * word, line, sentence, and character boundary analysis respectively.
+ * A single <code>BreakIterator</code> can work only on one unit
+ * (word, line, sentence, and so on). You must use a different iterator
+ * for each unit boundary analysis you wish to perform.
+ *
+ * <p><a name="line"></a>
+ * Line boundary analysis determines where a text string can be
+ * broken when line-wrapping. The mechanism correctly handles
+ * punctuation and hyphenated words. Actual line breaking needs
+ * to also consider the available line width and is handled by
+ * higher-level software.
+ *
+ * <p><a name="sentence"></a>
+ * Sentence boundary analysis allows selection with correct interpretation
+ * of periods within numbers and abbreviations, and trailing punctuation
+ * marks such as quotation marks and parentheses.
+ *
+ * <p><a name="word"></a>
+ * Word boundary analysis is used by search and replace functions, as
+ * well as within text editing applications that allow the user to
+ * select words with a double click. Word selection provides correct
+ * interpretation of punctuation marks within and following
+ * words. Characters that are not part of a word, such as symbols
+ * or punctuation marks, have word-breaks on both sides.
+ *
+ * <p><a name="character"></a>
+ * Character boundary analysis allows users to interact with characters
+ * as they expect to, for example, when moving the cursor through a text
+ * string. Character boundary analysis provides correct navigation
+ * through character strings, regardless of how the character is stored.
+ * The boundaries returned may be those of supplementary characters,
+ * combining character sequences, or ligature clusters.
+ * For example, an accented character might be stored as a base character
+ * and a diacritical mark. What users consider to be a character can
+ * differ between languages.
+ *
+ * <p>
+ * The <code>BreakIterator</code> instances returned by the factory methods
+ * of this class are intended for use with natural languages only, not for
+ * programming language text. It is however possible to define subclasses
+ * that tokenize a programming language.
+ *
+ * <P>
+ * <strong>Examples</strong>:<P>
+ * Creating and using text boundaries:
+ * <blockquote>
+ * <pre>
+ * public static void main(String args[]) {
+ *      if (args.length == 1) {
+ *          String stringToExamine = args[0];
+ *          //print each word in order
+ *          BreakIterator boundary = BreakIterator.getWordInstance();
+ *          boundary.setText(stringToExamine);
+ *          printEachForward(boundary, stringToExamine);
+ *          //print each sentence in reverse order
+ *          boundary = BreakIterator.getSentenceInstance(Locale.US);
+ *          boundary.setText(stringToExamine);
+ *          printEachBackward(boundary, stringToExamine);
+ *          printFirst(boundary, stringToExamine);
+ *          printLast(boundary, stringToExamine);
+ *      }
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * Print each element in order:
+ * <blockquote>
+ * <pre>
+ * public static void printEachForward(BreakIterator boundary, String source) {
+ *     int start = boundary.first();
+ *     for (int end = boundary.next();
+ *          end != BreakIterator.DONE;
+ *          start = end, end = boundary.next()) {
+ *          System.out.println(source.substring(start,end));
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * Print each element in reverse order:
+ * <blockquote>
+ * <pre>
+ * public static void printEachBackward(BreakIterator boundary, String source) {
+ *     int end = boundary.last();
+ *     for (int start = boundary.previous();
+ *          start != BreakIterator.DONE;
+ *          end = start, start = boundary.previous()) {
+ *         System.out.println(source.substring(start,end));
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * Print first element:
+ * <blockquote>
+ * <pre>
+ * public static void printFirst(BreakIterator boundary, String source) {
+ *     int start = boundary.first();
+ *     int end = boundary.next();
+ *     System.out.println(source.substring(start,end));
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * Print last element:
+ * <blockquote>
+ * <pre>
+ * public static void printLast(BreakIterator boundary, String source) {
+ *     int end = boundary.last();
+ *     int start = boundary.previous();
+ *     System.out.println(source.substring(start,end));
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * Print the element at a specified position:
+ * <blockquote>
+ * <pre>
+ * public static void printAt(BreakIterator boundary, int pos, String source) {
+ *     int end = boundary.following(pos);
+ *     int start = boundary.previous();
+ *     System.out.println(source.substring(start,end));
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * Find the next word:
+ * <blockquote>
+ * <pre>{@code
+ * public static int nextWordStartAfter(int pos, String text) {
+ *     BreakIterator wb = BreakIterator.getWordInstance();
+ *     wb.setText(text);
+ *     int last = wb.following(pos);
+ *     int current = wb.next();
+ *     while (current != BreakIterator.DONE) {
+ *         for (int p = last; p < current; p++) {
+ *             if (Character.isLetter(text.codePointAt(p)))
+ *                 return last;
+ *         }
+ *         last = current;
+ *         current = wb.next();
+ *     }
+ *     return BreakIterator.DONE;
+ * }
+ * }</pre>
+ * (The iterator returned by BreakIterator.getWordInstance() is unique in that
+ * the break positions it returns don't represent both the start and end of the
+ * thing being iterated over.  That is, a sentence-break iterator returns breaks
+ * that each represent the end of one sentence and the beginning of the next.
+ * With the word-break iterator, the characters between two boundaries might be a
+ * word, or they might be the punctuation or whitespace between two words.  The
+ * above code uses a simple heuristic to determine which boundary is the beginning
+ * of a word: If the characters between this boundary and the next boundary
+ * include at least one letter (this can be an alphabetical letter, a CJK ideograph,
+ * a Hangul syllable, a Kana character, etc.), then the text between this boundary
+ * and the next is a word; otherwise, it's the material between words.)
+ * </blockquote>
+ *
+ * @see CharacterIterator
+ *
+ */
+
+public abstract class BreakIterator implements Cloneable
+{
+    /**
+     * Constructor. BreakIterator is stateless and has no default behavior.
+     */
+    protected BreakIterator()
+    {
+    }
+
+    /**
+     * Create a copy of this iterator
+     * @return A copy of this
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            return super.clone();
+        }
+        catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * DONE is returned by previous(), next(), next(int), preceding(int)
+     * and following(int) when either the first or last text boundary has been
+     * reached.
+     */
+    public static final int DONE = -1;
+
+    /**
+     * Returns the first boundary. The iterator's current position is set
+     * to the first text boundary.
+     * @return The character index of the first text boundary.
+     */
+    public abstract int first();
+
+    /**
+     * Returns the last boundary. The iterator's current position is set
+     * to the last text boundary.
+     * @return The character index of the last text boundary.
+     */
+    public abstract int last();
+
+    /**
+     * Returns the nth boundary from the current boundary. If either
+     * the first or last text boundary has been reached, it returns
+     * <code>BreakIterator.DONE</code> and the current position is set to either
+     * the first or last text boundary depending on which one is reached. Otherwise,
+     * the iterator's current position is set to the new boundary.
+     * For example, if the iterator's current position is the mth text boundary
+     * and three more boundaries exist from the current boundary to the last text
+     * boundary, the next(2) call will return m + 2. The new text position is set
+     * to the (m + 2)th text boundary. A next(4) call would return
+     * <code>BreakIterator.DONE</code> and the last text boundary would become the
+     * new text position.
+     * @param n which boundary to return.  A value of 0
+     * does nothing.  Negative values move to previous boundaries
+     * and positive values move to later boundaries.
+     * @return The character index of the nth boundary from the current position
+     * or <code>BreakIterator.DONE</code> if either first or last text boundary
+     * has been reached.
+     */
+    public abstract int next(int n);
+
+    /**
+     * Returns the boundary following the current boundary. If the current boundary
+     * is the last text boundary, it returns <code>BreakIterator.DONE</code> and
+     * the iterator's current position is unchanged. Otherwise, the iterator's
+     * current position is set to the boundary following the current boundary.
+     * @return The character index of the next text boundary or
+     * <code>BreakIterator.DONE</code> if the current boundary is the last text
+     * boundary.
+     * Equivalent to next(1).
+     * @see #next(int)
+     */
+    public abstract int next();
+
+    /**
+     * Returns the boundary preceding the current boundary. If the current boundary
+     * is the first text boundary, it returns <code>BreakIterator.DONE</code> and
+     * the iterator's current position is unchanged. Otherwise, the iterator's
+     * current position is set to the boundary preceding the current boundary.
+     * @return The character index of the previous text boundary or
+     * <code>BreakIterator.DONE</code> if the current boundary is the first text
+     * boundary.
+     */
+    public abstract int previous();
+
+    /**
+     * Returns the first boundary following the specified character offset. If the
+     * specified offset equals to the last text boundary, it returns
+     * <code>BreakIterator.DONE</code> and the iterator's current position is unchanged.
+     * Otherwise, the iterator's current position is set to the returned boundary.
+     * The value returned is always greater than the offset or the value
+     * <code>BreakIterator.DONE</code>.
+     * @param offset the character offset to begin scanning.
+     * @return The first boundary after the specified offset or
+     * <code>BreakIterator.DONE</code> if the last text boundary is passed in
+     * as the offset.
+     * @exception  IllegalArgumentException if the specified offset is less than
+     * the first text boundary or greater than the last text boundary.
+     */
+    public abstract int following(int offset);
+
+    /**
+     * Returns the last boundary preceding the specified character offset. If the
+     * specified offset equals to the first text boundary, it returns
+     * <code>BreakIterator.DONE</code> and the iterator's current position is unchanged.
+     * Otherwise, the iterator's current position is set to the returned boundary.
+     * The value returned is always less than the offset or the value
+     * <code>BreakIterator.DONE</code>.
+     * @param offset the character offset to begin scanning.
+     * @return The last boundary before the specified offset or
+     * <code>BreakIterator.DONE</code> if the first text boundary is passed in
+     * as the offset.
+     * @exception   IllegalArgumentException if the specified offset is less than
+     * the first text boundary or greater than the last text boundary.
+     * @since 1.2
+     */
+    public int preceding(int offset) {
+        // NOTE:  This implementation is here solely because we can't add new
+        // abstract methods to an existing class.  There is almost ALWAYS a
+        // better, faster way to do this.
+        int pos = following(offset);
+        while (pos >= offset && pos != DONE) {
+            pos = previous();
+        }
+        return pos;
+    }
+
+    /**
+     * Returns true if the specified character offset is a text boundary.
+     * @param offset the character offset to check.
+     * @return <code>true</code> if "offset" is a boundary position,
+     * <code>false</code> otherwise.
+     * @exception   IllegalArgumentException if the specified offset is less than
+     * the first text boundary or greater than the last text boundary.
+     * @since 1.2
+     */
+    public boolean isBoundary(int offset) {
+        // NOTE: This implementation probably is wrong for most situations
+        // because it fails to take into account the possibility that a
+        // CharacterIterator passed to setText() may not have a begin offset
+        // of 0.  But since the abstract BreakIterator doesn't have that
+        // knowledge, it assumes the begin offset is 0.  If you subclass
+        // BreakIterator, copy the SimpleTextBoundary implementation of this
+        // function into your subclass.  [This should have been abstract at
+        // this level, but it's too late to fix that now.]
+        if (offset == 0) {
+            return true;
+        }
+        int boundary = following(offset - 1);
+        if (boundary == DONE) {
+            throw new IllegalArgumentException();
+        }
+        return boundary == offset;
+    }
+
+    /**
+     * Returns character index of the text boundary that was most
+     * recently returned by next(), next(int), previous(), first(), last(),
+     * following(int) or preceding(int). If any of these methods returns
+     * <code>BreakIterator.DONE</code> because either first or last text boundary
+     * has been reached, it returns the first or last text boundary depending on
+     * which one is reached.
+     * @return The text boundary returned from the above methods, first or last
+     * text boundary.
+     * @see #next()
+     * @see #next(int)
+     * @see #previous()
+     * @see #first()
+     * @see #last()
+     * @see #following(int)
+     * @see #preceding(int)
+     */
+    public abstract int current();
+
+    /**
+     * Get the text being scanned
+     * @return the text being scanned
+     */
+    public abstract CharacterIterator getText();
+
+    /**
+     * Set a new text string to be scanned.  The current scan
+     * position is reset to first().
+     * @param newText new text to scan.
+     */
+    public void setText(String newText)
+    {
+        setText(new StringCharacterIterator(newText));
+    }
+
+    /**
+     * Set a new text for scanning.  The current scan
+     * position is reset to first().
+     * @param newText new text to scan.
+     */
+    public abstract void setText(CharacterIterator newText);
+
+    // Android-removed: Removed code related to BreakIteratorProvider support.
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#word">word breaks</a>
+     * for the {@linkplain Locale#getDefault() default locale}.
+     * @return A break iterator for word breaks
+     */
+    public static BreakIterator getWordInstance()
+    {
+        return getWordInstance(Locale.getDefault());
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#word">word breaks</a>
+     * for the given locale.
+     * @param locale the desired locale
+     * @return A break iterator for word breaks
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public static BreakIterator getWordInstance(Locale locale)
+    {
+        // Android-changed: Switched to ICU.
+        return new IcuIteratorWrapper(
+                android.icu.text.BreakIterator.getWordInstance(locale));
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#line">line breaks</a>
+     * for the {@linkplain Locale#getDefault() default locale}.
+     * @return A break iterator for line breaks
+     */
+    public static BreakIterator getLineInstance()
+    {
+        return getLineInstance(Locale.getDefault());
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#line">line breaks</a>
+     * for the given locale.
+     * @param locale the desired locale
+     * @return A break iterator for line breaks
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public static BreakIterator getLineInstance(Locale locale)
+    {
+        // Android-changed: Switched to ICU.
+        return new IcuIteratorWrapper(
+                android.icu.text.BreakIterator.getLineInstance(locale));
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#character">character breaks</a>
+     * for the {@linkplain Locale#getDefault() default locale}.
+     * @return A break iterator for character breaks
+     */
+    public static BreakIterator getCharacterInstance()
+    {
+        return getCharacterInstance(Locale.getDefault());
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#character">character breaks</a>
+     * for the given locale.
+     * @param locale the desired locale
+     * @return A break iterator for character breaks
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public static BreakIterator getCharacterInstance(Locale locale)
+    {
+        // Android-changed: Switched to ICU.
+        return new IcuIteratorWrapper(
+                android.icu.text.BreakIterator.getCharacterInstance(locale));
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#sentence">sentence breaks</a>
+     * for the {@linkplain Locale#getDefault() default locale}.
+     * @return A break iterator for sentence breaks
+     */
+    public static BreakIterator getSentenceInstance()
+    {
+        return getSentenceInstance(Locale.getDefault());
+    }
+
+    /**
+     * Returns a new <code>BreakIterator</code> instance
+     * for <a href="BreakIterator.html#sentence">sentence breaks</a>
+     * for the given locale.
+     * @param locale the desired locale
+     * @return A break iterator for sentence breaks
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public static BreakIterator getSentenceInstance(Locale locale)
+    {
+        // Android-changed: Switched to ICU.
+        return new IcuIteratorWrapper(
+                android.icu.text.BreakIterator.getSentenceInstance(locale));
+    }
+
+    // Android-removed: Removed code related to BreakIteratorProvider support.
+
+    // Android-changed: Removed references to BreakIteratorProvider from JavaDoc.
+    /**
+     * Returns an array of all locales for which the
+     * <code>get*Instance</code> methods of this class can return
+     * localized instances.
+     *
+     * @return An array of locales for which localized
+     *         <code>BreakIterator</code> instances are available.
+     */
+    public static synchronized Locale[] getAvailableLocales()
+    {
+        // Android-changed: Switched to ICU.
+        return android.icu.text.BreakIterator.getAvailableLocales();
+    }
+}
diff --git a/java/text/CalendarBuilder.java b/java/text/CalendarBuilder.java
new file mode 100644
index 0000000..a8246b6
--- /dev/null
+++ b/java/text/CalendarBuilder.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+import java.util.Calendar;
+import static java.util.GregorianCalendar.*;
+
+/**
+ * {@code CalendarBuilder} keeps field-value pairs for setting
+ * the calendar fields of the given {@code Calendar}. It has the
+ * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
+ * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
+ * {@code DAY_OF_WEEK} in the ISO day of week numbering.
+ *
+ * <p>{@code CalendarBuilder} retains the semantic of the pseudo
+ * timestamp for fields. {@code CalendarBuilder} uses a single
+ * int array combining fields[] and stamp[] of {@code Calendar}.
+ *
+ * @author Masayoshi Okutsu
+ */
+class CalendarBuilder {
+    /*
+     * Pseudo time stamp constants used in java.util.Calendar
+     */
+    private static final int UNSET = 0;
+    private static final int COMPUTED = 1;
+    private static final int MINIMUM_USER_STAMP = 2;
+
+    private static final int MAX_FIELD = FIELD_COUNT + 1;
+
+    public static final int WEEK_YEAR = FIELD_COUNT;
+    public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
+
+    // stamp[] (lower half) and field[] (upper half) combined
+    private final int[] field;
+    private int nextStamp;
+    private int maxFieldIndex;
+
+    CalendarBuilder() {
+        field = new int[MAX_FIELD * 2];
+        nextStamp = MINIMUM_USER_STAMP;
+        maxFieldIndex = -1;
+    }
+
+    CalendarBuilder set(int index, int value) {
+        if (index == ISO_DAY_OF_WEEK) {
+            index = DAY_OF_WEEK;
+            value = toCalendarDayOfWeek(value);
+        }
+        field[index] = nextStamp++;
+        field[MAX_FIELD + index] = value;
+        if (index > maxFieldIndex && index < FIELD_COUNT) {
+            maxFieldIndex = index;
+        }
+        return this;
+    }
+
+    CalendarBuilder addYear(int value) {
+        field[MAX_FIELD + YEAR] += value;
+        field[MAX_FIELD + WEEK_YEAR] += value;
+        return this;
+    }
+
+    boolean isSet(int index) {
+        if (index == ISO_DAY_OF_WEEK) {
+            index = DAY_OF_WEEK;
+        }
+        return field[index] > UNSET;
+    }
+
+    CalendarBuilder clear(int index) {
+        if (index == ISO_DAY_OF_WEEK) {
+            index = DAY_OF_WEEK;
+        }
+        field[index] = UNSET;
+        field[MAX_FIELD + index] = 0;
+        return this;
+    }
+
+    Calendar establish(Calendar cal) {
+        boolean weekDate = isSet(WEEK_YEAR)
+                            && field[WEEK_YEAR] > field[YEAR];
+        if (weekDate && !cal.isWeekDateSupported()) {
+            // Use YEAR instead
+            if (!isSet(YEAR)) {
+                set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
+            }
+            weekDate = false;
+        }
+
+        cal.clear();
+        // Set the fields from the min stamp to the max stamp so that
+        // the field resolution works in the Calendar.
+        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
+            for (int index = 0; index <= maxFieldIndex; index++) {
+                if (field[index] == stamp) {
+                    cal.set(index, field[MAX_FIELD + index]);
+                    break;
+                }
+            }
+        }
+
+        if (weekDate) {
+            int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
+            int dayOfWeek = isSet(DAY_OF_WEEK) ?
+                                field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
+            if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
+                if (dayOfWeek >= 8) {
+                    dayOfWeek--;
+                    weekOfYear += dayOfWeek / 7;
+                    dayOfWeek = (dayOfWeek % 7) + 1;
+                } else {
+                    while (dayOfWeek <= 0) {
+                        dayOfWeek += 7;
+                        weekOfYear--;
+                    }
+                }
+                dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
+            }
+            cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
+        }
+        return cal;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("CalendarBuilder:[");
+        for (int i = 0; i < field.length; i++) {
+            if (isSet(i)) {
+                sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
+            }
+        }
+        int lastIndex = sb.length() - 1;
+        if (sb.charAt(lastIndex) == ',') {
+            sb.setLength(lastIndex);
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+
+    static int toISODayOfWeek(int calendarDayOfWeek) {
+        return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
+    }
+
+    static int toCalendarDayOfWeek(int isoDayOfWeek) {
+        if (!isValidDayOfWeek(isoDayOfWeek)) {
+            // adjust later for lenient mode
+            return isoDayOfWeek;
+        }
+        return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
+    }
+
+    static boolean isValidDayOfWeek(int dayOfWeek) {
+        return dayOfWeek > 0 && dayOfWeek <= 7;
+    }
+}
diff --git a/java/text/CharacterIterator.java b/java/text/CharacterIterator.java
new file mode 100644
index 0000000..efa7ab4
--- /dev/null
+++ b/java/text/CharacterIterator.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+
+/**
+ * This interface defines a protocol for bidirectional iteration over text.
+ * The iterator iterates over a bounded sequence of characters.  Characters
+ * are indexed with values beginning with the value returned by getBeginIndex() and
+ * continuing through the value returned by getEndIndex()-1.
+ * <p>
+ * Iterators maintain a current character index, whose valid range is from
+ * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
+ * handling of zero-length text ranges and for historical reasons.
+ * The current index can be retrieved by calling getIndex() and set directly
+ * by calling setIndex(), first(), and last().
+ * <p>
+ * The methods previous() and next() are used for iteration. They return DONE if
+ * they would move outside the range from getBeginIndex() to getEndIndex() -1,
+ * signaling that the iterator has reached the end of the sequence. DONE is
+ * also returned by other methods to indicate that the current index is
+ * outside this range.
+ *
+ * <P>Examples:<P>
+ *
+ * Traverse the text from start to finish
+ * <pre>{@code
+ * public void traverseForward(CharacterIterator iter) {
+ *     for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
+ *         processChar(c);
+ *     }
+ * }
+ * }</pre>
+ *
+ * Traverse the text backwards, from end to start
+ * <pre>{@code
+ * public void traverseBackward(CharacterIterator iter) {
+ *     for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
+ *         processChar(c);
+ *     }
+ * }
+ * }</pre>
+ *
+ * Traverse both forward and backward from a given position in the text.
+ * Calls to notBoundary() in this example represents some
+ * additional stopping criteria.
+ * <pre>{@code
+ * public void traverseOut(CharacterIterator iter, int pos) {
+ *     for (char c = iter.setIndex(pos);
+ *              c != CharacterIterator.DONE && notBoundary(c);
+ *              c = iter.next()) {
+ *     }
+ *     int end = iter.getIndex();
+ *     for (char c = iter.setIndex(pos);
+ *             c != CharacterIterator.DONE && notBoundary(c);
+ *             c = iter.previous()) {
+ *     }
+ *     int start = iter.getIndex();
+ *     processSection(start, end);
+ * }
+ * }</pre>
+ *
+ * @see StringCharacterIterator
+ * @see AttributedCharacterIterator
+ */
+
+public interface CharacterIterator extends Cloneable
+{
+
+    /**
+     * Constant that is returned when the iterator has reached either the end
+     * or the beginning of the text. The value is '\\uFFFF', the "not a
+     * character" value which should not occur in any valid Unicode string.
+     */
+    public static final char DONE = '\uFFFF';
+
+    /**
+     * Sets the position to getBeginIndex() and returns the character at that
+     * position.
+     * @return the first character in the text, or DONE if the text is empty
+     * @see #getBeginIndex()
+     */
+    public char first();
+
+    /**
+     * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
+     * and returns the character at that position.
+     * @return the last character in the text, or DONE if the text is empty
+     * @see #getEndIndex()
+     */
+    public char last();
+
+    /**
+     * Gets the character at the current position (as returned by getIndex()).
+     * @return the character at the current position or DONE if the current
+     * position is off the end of the text.
+     * @see #getIndex()
+     */
+    public char current();
+
+    /**
+     * Increments the iterator's index by one and returns the character
+     * at the new index.  If the resulting index is greater or equal
+     * to getEndIndex(), the current index is reset to getEndIndex() and
+     * a value of DONE is returned.
+     * @return the character at the new position or DONE if the new
+     * position is off the end of the text range.
+     */
+    public char next();
+
+    /**
+     * Decrements the iterator's index by one and returns the character
+     * at the new index. If the current index is getBeginIndex(), the index
+     * remains at getBeginIndex() and a value of DONE is returned.
+     * @return the character at the new position or DONE if the current
+     * position is equal to getBeginIndex().
+     */
+    public char previous();
+
+    /**
+     * Sets the position to the specified position in the text and returns that
+     * character.
+     * @param position the position within the text.  Valid values range from
+     * getBeginIndex() to getEndIndex().  An IllegalArgumentException is thrown
+     * if an invalid value is supplied.
+     * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
+     */
+    public char setIndex(int position);
+
+    /**
+     * Returns the start index of the text.
+     * @return the index at which the text begins.
+     */
+    public int getBeginIndex();
+
+    /**
+     * Returns the end index of the text.  This index is the index of the first
+     * character following the end of the text.
+     * @return the index after the last character in the text
+     */
+    public int getEndIndex();
+
+    /**
+     * Returns the current index.
+     * @return the current index.
+     */
+    public int getIndex();
+
+    /**
+     * Create a copy of this iterator
+     * @return A copy of this
+     */
+    public Object clone();
+
+}
diff --git a/java/text/CharacterIteratorFieldDelegate.java b/java/text/CharacterIteratorFieldDelegate.java
new file mode 100644
index 0000000..9e22ee7
--- /dev/null
+++ b/java/text/CharacterIteratorFieldDelegate.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.text;
+
+import java.util.ArrayList;
+
+/**
+ * CharacterIteratorFieldDelegate combines the notifications from a Format
+ * into a resulting <code>AttributedCharacterIterator</code>. The resulting
+ * <code>AttributedCharacterIterator</code> can be retrieved by way of
+ * the <code>getIterator</code> method.
+ *
+ */
+class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
+    /**
+     * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
+     * for a region > size, a new instance of AttributedString is added to
+     * attributedStrings. Subsequent invocations of <code>formatted</code>
+     * for existing regions result in invoking addAttribute on the existing
+     * AttributedStrings.
+     */
+    private ArrayList<AttributedString> attributedStrings;
+    /**
+     * Running count of the number of characters that have
+     * been encountered.
+     */
+    private int size;
+
+
+    CharacterIteratorFieldDelegate() {
+        attributedStrings = new ArrayList<>();
+    }
+
+    public void formatted(Format.Field attr, Object value, int start, int end,
+                          StringBuffer buffer) {
+        if (start != end) {
+            if (start < size) {
+                // Adjust attributes of existing runs
+                int index = size;
+                int asIndex = attributedStrings.size() - 1;
+
+                while (start < index) {
+                    AttributedString as = attributedStrings.
+                                           get(asIndex--);
+                    int newIndex = index - as.length();
+                    int aStart = Math.max(0, start - newIndex);
+
+                    as.addAttribute(attr, value, aStart, Math.min(
+                                    end - start, as.length() - aStart) +
+                                    aStart);
+                    index = newIndex;
+                }
+            }
+            if (size < start) {
+                // Pad attributes
+                attributedStrings.add(new AttributedString(
+                                          buffer.substring(size, start)));
+                size = start;
+            }
+            if (size < end) {
+                // Add new string
+                int aStart = Math.max(start, size);
+                AttributedString string = new AttributedString(
+                                   buffer.substring(aStart, end));
+
+                string.addAttribute(attr, value);
+                attributedStrings.add(string);
+                size = end;
+            }
+        }
+    }
+
+    public void formatted(int fieldID, Format.Field attr, Object value,
+                          int start, int end, StringBuffer buffer) {
+        formatted(attr, value, start, end, buffer);
+    }
+
+    /**
+     * Returns an <code>AttributedCharacterIterator</code> that can be used
+     * to iterate over the resulting formatted String.
+     *
+     * @pararm string Result of formatting.
+     */
+    public AttributedCharacterIterator getIterator(String string) {
+        // Add the last AttributedCharacterIterator if necessary
+        // assert(size <= string.length());
+        if (string.length() > size) {
+            attributedStrings.add(new AttributedString(
+                                  string.substring(size)));
+            size = string.length();
+        }
+        int iCount = attributedStrings.size();
+        AttributedCharacterIterator iterators[] = new
+                                    AttributedCharacterIterator[iCount];
+
+        for (int counter = 0; counter < iCount; counter++) {
+            iterators[counter] = attributedStrings.
+                                  get(counter).getIterator();
+        }
+        return new AttributedString(iterators).getIterator();
+    }
+}
diff --git a/java/text/ChoiceFormat.java b/java/text/ChoiceFormat.java
new file mode 100644
index 0000000..3baaa90
--- /dev/null
+++ b/java/text/ChoiceFormat.java
@@ -0,0 +1,643 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.InvalidObjectException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+
+/**
+ * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
+ * It is generally used in a <code>MessageFormat</code> for handling plurals.
+ * The choice is specified with an ascending list of doubles, where each item
+ * specifies a half-open interval up to the next item:
+ * <blockquote>
+ * <pre>
+ * X matches j if and only if limit[j] &le; X &lt; limit[j+1]
+ * </pre>
+ * </blockquote>
+ * If there is no match, then either the first or last index is used, depending
+ * on whether the number (X) is too low or too high.  If the limit array is not
+ * in ascending order, the results of formatting will be incorrect.  ChoiceFormat
+ * also accepts <code>&#92;u221E</code> as equivalent to infinity(INF).
+ *
+ * <p>
+ * <strong>Note:</strong>
+ * <code>ChoiceFormat</code> differs from the other <code>Format</code>
+ * classes in that you create a <code>ChoiceFormat</code> object with a
+ * constructor (not with a <code>getInstance</code> style factory
+ * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
+ * doesn't require any complex setup for a given locale. In fact,
+ * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
+ *
+ * <p>
+ * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
+ * and an array of limits. The length of these arrays must be the same.
+ * For example,
+ * <ul>
+ * <li>
+ *     <em>limits</em> = {1,2,3,4,5,6,7}<br>
+ *     <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
+ * <li>
+ *     <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
+ *     <em>formats</em> = {"no files", "one file", "many files"}<br>
+ *     (<code>nextDouble</code> can be used to get the next higher double, to
+ *     make the half-open interval.)
+ * </ul>
+ *
+ * <p>
+ * Here is a simple example that shows formatting and parsing:
+ * <blockquote>
+ * <pre>{@code
+ * double[] limits = {1,2,3,4,5,6,7};
+ * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
+ * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
+ * ParsePosition status = new ParsePosition(0);
+ * for (double i = 0.0; i <= 8.0; ++i) {
+ *     status.setIndex(0);
+ *     System.out.println(i + " -> " + form.format(i) + " -> "
+ *                              + form.parse(form.format(i),status));
+ * }
+ * }</pre>
+ * </blockquote>
+ * Here is a more complex example, with a pattern format:
+ * <blockquote>
+ * <pre>{@code
+ * double[] filelimits = {0,1,2};
+ * String[] filepart = {"are no files","is one file","are {2} files"};
+ * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
+ * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
+ * MessageFormat pattform = new MessageFormat("There {0} on {1}");
+ * pattform.setFormats(testFormats);
+ * Object[] testArgs = {null, "ADisk", null};
+ * for (int i = 0; i < 4; ++i) {
+ *     testArgs[0] = new Integer(i);
+ *     testArgs[2] = testArgs[0];
+ *     System.out.println(pattform.format(testArgs));
+ * }
+ * }</pre>
+ * </blockquote>
+ * <p>
+ * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
+ * For example:
+ * <blockquote>
+ * <pre>{@code
+ * ChoiceFormat fmt = new ChoiceFormat(
+ *      "-1#is negative| 0#is zero or fraction | 1#is one |1.0<is 1+ |2#is two |2<is more than 2.");
+ * System.out.println("Formatter Pattern : " + fmt.toPattern());
+ *
+ * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
+ * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
+ * System.out.println("Format with 0 : " + fmt.format(0));
+ * System.out.println("Format with 0.9 : " + fmt.format(0.9));
+ * System.out.println("Format with 1.0 : " + fmt.format(1));
+ * System.out.println("Format with 1.5 : " + fmt.format(1.5));
+ * System.out.println("Format with 2 : " + fmt.format(2));
+ * System.out.println("Format with 2.1 : " + fmt.format(2.1));
+ * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
+ * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
+ * }</pre>
+ * </blockquote>
+ * And the output result would be like the following:
+ * <blockquote>
+ * <pre>{@code
+ * Format with -INF : is negative
+ * Format with -1.0 : is negative
+ * Format with 0 : is zero or fraction
+ * Format with 0.9 : is zero or fraction
+ * Format with 1.0 : is one
+ * Format with 1.5 : is 1+
+ * Format with 2 : is two
+ * Format with 2.1 : is more than 2.
+ * Format with NaN : is negative
+ * Format with +INF : is more than 2.
+ * }</pre>
+ * </blockquote>
+ *
+ * <h3><a name="synchronization">Synchronization</a></h3>
+ *
+ * <p>
+ * Choice formats are not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ *
+ * @see          DecimalFormat
+ * @see          MessageFormat
+ * @author       Mark Davis
+ */
+public class ChoiceFormat extends NumberFormat {
+
+    // Proclaim serial compatibility with 1.1 FCS
+    private static final long serialVersionUID = 1795184449645032964L;
+
+    /**
+     * Sets the pattern.
+     * @param newPattern See the class description.
+     */
+    public void applyPattern(String newPattern) {
+        StringBuffer[] segments = new StringBuffer[2];
+        for (int i = 0; i < segments.length; ++i) {
+            segments[i] = new StringBuffer();
+        }
+        double[] newChoiceLimits = new double[30];
+        String[] newChoiceFormats = new String[30];
+        int count = 0;
+        int part = 0;
+        double startValue = 0;
+        double oldStartValue = Double.NaN;
+        boolean inQuote = false;
+        for (int i = 0; i < newPattern.length(); ++i) {
+            char ch = newPattern.charAt(i);
+            if (ch=='\'') {
+                // Check for "''" indicating a literal quote
+                if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
+                    segments[part].append(ch);
+                    ++i;
+                } else {
+                    inQuote = !inQuote;
+                }
+            } else if (inQuote) {
+                segments[part].append(ch);
+            } else if (ch == '<' || ch == '#' || ch == '\u2264') {
+                if (segments[0].length() == 0) {
+                    throw new IllegalArgumentException();
+                }
+                try {
+                    String tempBuffer = segments[0].toString();
+                    if (tempBuffer.equals("\u221E")) {
+                        startValue = Double.POSITIVE_INFINITY;
+                    } else if (tempBuffer.equals("-\u221E")) {
+                        startValue = Double.NEGATIVE_INFINITY;
+                    } else {
+                        // Android-changed: avoid object instantiation followed by unboxing.
+                        startValue = Double.parseDouble(segments[0].toString());
+                    }
+                } catch (Exception e) {
+                    throw new IllegalArgumentException();
+                }
+                if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
+                        startValue != Double.NEGATIVE_INFINITY) {
+                    startValue = nextDouble(startValue);
+                }
+                if (startValue <= oldStartValue) {
+                    throw new IllegalArgumentException();
+                }
+                segments[0].setLength(0);
+                part = 1;
+            } else if (ch == '|') {
+                if (count == newChoiceLimits.length) {
+                    newChoiceLimits = doubleArraySize(newChoiceLimits);
+                    newChoiceFormats = doubleArraySize(newChoiceFormats);
+                }
+                newChoiceLimits[count] = startValue;
+                newChoiceFormats[count] = segments[1].toString();
+                ++count;
+                oldStartValue = startValue;
+                segments[1].setLength(0);
+                part = 0;
+            } else {
+                segments[part].append(ch);
+            }
+        }
+        // clean up last one
+        if (part == 1) {
+            if (count == newChoiceLimits.length) {
+                newChoiceLimits = doubleArraySize(newChoiceLimits);
+                newChoiceFormats = doubleArraySize(newChoiceFormats);
+            }
+            newChoiceLimits[count] = startValue;
+            newChoiceFormats[count] = segments[1].toString();
+            ++count;
+        }
+        choiceLimits = new double[count];
+        System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
+        choiceFormats = new String[count];
+        System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
+    }
+
+    /**
+     * Gets the pattern.
+     *
+     * @return the pattern string
+     */
+    public String toPattern() {
+        StringBuffer result = new StringBuffer();
+        for (int i = 0; i < choiceLimits.length; ++i) {
+            if (i != 0) {
+                result.append('|');
+            }
+            // choose based upon which has less precision
+            // approximate that by choosing the closest one to an integer.
+            // could do better, but it's not worth it.
+            double less = previousDouble(choiceLimits[i]);
+            double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
+            double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
+
+            if (tryLessOrEqual < tryLess) {
+                result.append(""+choiceLimits[i]);
+                result.append('#');
+            } else {
+                if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
+                    result.append("\u221E");
+                } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
+                    result.append("-\u221E");
+                } else {
+                    result.append(""+less);
+                }
+                result.append('<');
+            }
+            // Append choiceFormats[i], using quotes if there are special characters.
+            // Single quotes themselves must be escaped in either case.
+            String text = choiceFormats[i];
+            boolean needQuote = text.indexOf('<') >= 0
+                || text.indexOf('#') >= 0
+                || text.indexOf('\u2264') >= 0
+                || text.indexOf('|') >= 0;
+            if (needQuote) result.append('\'');
+            if (text.indexOf('\'') < 0) result.append(text);
+            else {
+                for (int j=0; j<text.length(); ++j) {
+                    char c = text.charAt(j);
+                    result.append(c);
+                    if (c == '\'') result.append(c);
+                }
+            }
+            if (needQuote) result.append('\'');
+        }
+        return result.toString();
+    }
+
+    /**
+     * Constructs with limits and corresponding formats based on the pattern.
+     *
+     * @param newPattern the new pattern string
+     * @see #applyPattern
+     */
+    public ChoiceFormat(String newPattern)  {
+        applyPattern(newPattern);
+    }
+
+    /**
+     * Constructs with the limits and the corresponding formats.
+     *
+     * @param limits limits in ascending order
+     * @param formats corresponding format strings
+     * @see #setChoices
+     */
+    public ChoiceFormat(double[] limits, String[] formats) {
+        setChoices(limits, formats);
+    }
+
+    /**
+     * Set the choices to be used in formatting.
+     * @param limits contains the top value that you want
+     * parsed with that format, and should be in ascending sorted order. When
+     * formatting X, the choice will be the i, where
+     * limit[i] &le; X {@literal <} limit[i+1].
+     * If the limit array is not in ascending order, the results of formatting
+     * will be incorrect.
+     * @param formats are the formats you want to use for each limit.
+     * They can be either Format objects or Strings.
+     * When formatting with object Y,
+     * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
+     * is called. Otherwise Y.toString() is called.
+     */
+    public void setChoices(double[] limits, String formats[]) {
+        if (limits.length != formats.length) {
+            throw new IllegalArgumentException(
+                "Array and limit arrays must be of the same length.");
+        }
+        choiceLimits = Arrays.copyOf(limits, limits.length);
+        choiceFormats = Arrays.copyOf(formats, formats.length);
+    }
+
+    // Android-changed: Clarify that calling setChoices() changes what is returned here.
+    /**
+     * @return a copy of the {@code double[]} array supplied to the constructor or the most recent
+     * call to {@link #setChoices(double[], String[])}.
+     */
+    public double[] getLimits() {
+        double[] newLimits = Arrays.copyOf(choiceLimits, choiceLimits.length);
+        return newLimits;
+    }
+
+    // Android-changed: Clarify that calling setChoices() changes what is returned here.
+    /**
+     * @return a copy of the {@code String[]} array supplied to the constructor or the most recent
+     * call to {@link #setChoices(double[], String[])}.
+     */
+    public Object[] getFormats() {
+        Object[] newFormats = Arrays.copyOf(choiceFormats, choiceFormats.length);
+        return newFormats;
+    }
+
+    // Overrides
+
+    /**
+     * Specialization of format. This method really calls
+     * <code>format(double, StringBuffer, FieldPosition)</code>
+     * thus the range of longs that are supported is only equal to
+     * the range that can be stored by double. This will never be
+     * a practical limitation.
+     */
+    public StringBuffer format(long number, StringBuffer toAppendTo,
+                               FieldPosition status) {
+        return format((double)number, toAppendTo, status);
+    }
+
+    /**
+     * Returns pattern with formatted double.
+     * @param number number to be formatted and substituted.
+     * @param toAppendTo where text is appended.
+     * @param status ignore no useful status is returned.
+     */
+   public StringBuffer format(double number, StringBuffer toAppendTo,
+                               FieldPosition status) {
+        // find the number
+        int i;
+        for (i = 0; i < choiceLimits.length; ++i) {
+            if (!(number >= choiceLimits[i])) {
+                // same as number < choiceLimits, except catchs NaN
+                break;
+            }
+        }
+        --i;
+        if (i < 0) i = 0;
+        // return either a formatted number, or a string
+        return toAppendTo.append(choiceFormats[i]);
+    }
+
+    /**
+     * Parses a Number from the input text.
+     * @param text the source text.
+     * @param status an input-output parameter.  On input, the
+     * status.index field indicates the first character of the
+     * source text that should be parsed.  On exit, if no error
+     * occurred, status.index is set to the first unparsed character
+     * in the source text.  On exit, if an error did occur,
+     * status.index is unchanged and status.errorIndex is set to the
+     * first index of the character that caused the parse to fail.
+     * @return A Number representing the value of the number parsed.
+     */
+    public Number parse(String text, ParsePosition status) {
+        // find the best number (defined as the one with the longest parse)
+        int start = status.index;
+        int furthest = start;
+        double bestNumber = Double.NaN;
+        double tempNumber = 0.0;
+        for (int i = 0; i < choiceFormats.length; ++i) {
+            String tempString = choiceFormats[i];
+            if (text.regionMatches(start, tempString, 0, tempString.length())) {
+                status.index = start + tempString.length();
+                tempNumber = choiceLimits[i];
+                if (status.index > furthest) {
+                    furthest = status.index;
+                    bestNumber = tempNumber;
+                    if (furthest == text.length()) break;
+                }
+            }
+        }
+        status.index = furthest;
+        if (status.index == start) {
+            status.errorIndex = furthest;
+        }
+        return new Double(bestNumber);
+    }
+
+    /**
+     * Finds the least double greater than {@code d}.
+     * If {@code NaN}, returns same value.
+     * <p>Used to make half-open intervals.
+     *
+     * @param d the reference value
+     * @return the least double value greather than {@code d}
+     * @see #previousDouble
+     */
+    public static final double nextDouble (double d) {
+        return nextDouble(d,true);
+    }
+
+    /**
+     * Finds the greatest double less than {@code d}.
+     * If {@code NaN}, returns same value.
+     *
+     * @param d the reference value
+     * @return the greatest double value less than {@code d}
+     * @see #nextDouble
+     */
+    public static final double previousDouble (double d) {
+        return nextDouble(d,false);
+    }
+
+    /**
+     * Overrides Cloneable
+     */
+    public Object clone()
+    {
+        ChoiceFormat other = (ChoiceFormat) super.clone();
+        // for primitives or immutables, shallow clone is enough
+        other.choiceLimits = choiceLimits.clone();
+        other.choiceFormats = choiceFormats.clone();
+        return other;
+    }
+
+    /**
+     * Generates a hash code for the message format object.
+     */
+    public int hashCode() {
+        int result = choiceLimits.length;
+        if (choiceFormats.length > 0) {
+            // enough for reasonable distribution
+            result ^= choiceFormats[choiceFormats.length-1].hashCode();
+        }
+        return result;
+    }
+
+    /**
+     * Equality comparision between two
+     */
+    public boolean equals(Object obj) {
+        if (obj == null) return false;
+        if (this == obj)                      // quick check
+            return true;
+        if (getClass() != obj.getClass())
+            return false;
+        ChoiceFormat other = (ChoiceFormat) obj;
+        return (Arrays.equals(choiceLimits, other.choiceLimits)
+             && Arrays.equals(choiceFormats, other.choiceFormats));
+    }
+
+    /**
+     * After reading an object from the input stream, do a simple verification
+     * to maintain class invariants.
+     * @throws InvalidObjectException if the objects read from the stream is invalid.
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        if (choiceLimits.length != choiceFormats.length) {
+            throw new InvalidObjectException(
+                    "limits and format arrays of different length.");
+        }
+    }
+
+    // ===============privates===========================
+
+    /**
+     * A list of lower bounds for the choices.  The formatter will return
+     * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
+     * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
+     * @serial
+     */
+    private double[] choiceLimits;
+
+    /**
+     * A list of choice strings.  The formatter will return
+     * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
+     * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
+     * @serial
+     */
+    private String[] choiceFormats;
+
+    /*
+    static final long SIGN          = 0x8000000000000000L;
+    static final long EXPONENT      = 0x7FF0000000000000L;
+    static final long SIGNIFICAND   = 0x000FFFFFFFFFFFFFL;
+
+    private static double nextDouble (double d, boolean positive) {
+        if (Double.isNaN(d) || Double.isInfinite(d)) {
+                return d;
+            }
+        long bits = Double.doubleToLongBits(d);
+        long significand = bits & SIGNIFICAND;
+        if (bits < 0) {
+            significand |= (SIGN | EXPONENT);
+        }
+        long exponent = bits & EXPONENT;
+        if (positive) {
+            significand += 1;
+            // FIXME fix overflow & underflow
+        } else {
+            significand -= 1;
+            // FIXME fix overflow & underflow
+        }
+        bits = exponent | (significand & ~EXPONENT);
+        return Double.longBitsToDouble(bits);
+    }
+    */
+
+    static final long SIGN                = 0x8000000000000000L;
+    static final long EXPONENT            = 0x7FF0000000000000L;
+    static final long POSITIVEINFINITY    = 0x7FF0000000000000L;
+
+    /**
+     * Finds the least double greater than {@code d} (if {@code positive} is
+     * {@code true}), or the greatest double less than {@code d} (if
+     * {@code positive} is {@code false}).
+     * If {@code NaN}, returns same value.
+     *
+     * Does not affect floating-point flags,
+     * provided these member functions do not:
+     *          Double.longBitsToDouble(long)
+     *          Double.doubleToLongBits(double)
+     *          Double.isNaN(double)
+     *
+     * @param d        the reference value
+     * @param positive {@code true} if the least double is desired;
+     *                 {@code false} otherwise
+     * @return the least or greater double value
+     */
+    public static double nextDouble (double d, boolean positive) {
+
+        /* filter out NaN's */
+        if (Double.isNaN(d)) {
+            return d;
+        }
+
+        /* zero's are also a special case */
+        if (d == 0.0) {
+            double smallestPositiveDouble = Double.longBitsToDouble(1L);
+            if (positive) {
+                return smallestPositiveDouble;
+            } else {
+                return -smallestPositiveDouble;
+            }
+        }
+
+        /* if entering here, d is a nonzero value */
+
+        /* hold all bits in a long for later use */
+        long bits = Double.doubleToLongBits(d);
+
+        /* strip off the sign bit */
+        long magnitude = bits & ~SIGN;
+
+        /* if next double away from zero, increase magnitude */
+        if ((bits > 0) == positive) {
+            if (magnitude != POSITIVEINFINITY) {
+                magnitude += 1;
+            }
+        }
+        /* else decrease magnitude */
+        else {
+            magnitude -= 1;
+        }
+
+        /* restore sign bit and return */
+        long signbit = bits & SIGN;
+        return Double.longBitsToDouble (magnitude | signbit);
+    }
+
+    private static double[] doubleArraySize(double[] array) {
+        int oldSize = array.length;
+        double[] newArray = new double[oldSize * 2];
+        System.arraycopy(array, 0, newArray, 0, oldSize);
+        return newArray;
+    }
+
+    private String[] doubleArraySize(String[] array) {
+        int oldSize = array.length;
+        String[] newArray = new String[oldSize * 2];
+        System.arraycopy(array, 0, newArray, 0, oldSize);
+        return newArray;
+    }
+
+}
diff --git a/java/text/CollationElementIterator.java b/java/text/CollationElementIterator.java
new file mode 100644
index 0000000..fede747
--- /dev/null
+++ b/java/text/CollationElementIterator.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+/**
+ * The <code>CollationElementIterator</code> class is used as an iterator
+ * to walk through each character of an international string. Use the iterator
+ * to return the ordering priority of the positioned character. The ordering
+ * priority of a character, which we refer to as a key, defines how a character
+ * is collated in the given collation object.
+ *
+ * <p>
+ * For example, consider the following in Spanish:
+ * <blockquote>
+ * <pre>
+ * "ca" &rarr; the first key is key('c') and second key is key('a').
+ * "cha" &rarr; the first key is key('ch') and second key is key('a').
+ * </pre>
+ * </blockquote>
+ * And in German,
+ * <blockquote>
+ * <pre>
+ * "\u00e4b" &rarr; the first key is key('a'), the second key is key('e'), and
+ * the third key is key('b').
+ * </pre>
+ * </blockquote>
+ * The key of a character is an integer composed of primary order(short),
+ * secondary order(byte), and tertiary order(byte). Java strictly defines
+ * the size and signedness of its primitive data types. Therefore, the static
+ * functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
+ * <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
+ * and <code>short</code> respectively to ensure the correctness of the key
+ * value.
+ *
+ * <p>
+ * Example of the iterator usage,
+ * <blockquote>
+ * <pre>
+ *
+ *  String testString = "This is a test";
+ *  Collator col = Collator.getInstance();
+ *  if (col instanceof RuleBasedCollator) {
+ *      RuleBasedCollator ruleBasedCollator = (RuleBasedCollator)col;
+ *      CollationElementIterator collationElementIterator = ruleBasedCollator.getCollationElementIterator(testString);
+ *      int primaryOrder = CollationElementIterator.primaryOrder(collationElementIterator.next());
+ *          :
+ *  }
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * <code>CollationElementIterator.next</code> returns the collation order
+ * of the next character. A collation order consists of primary order,
+ * secondary order and tertiary order. The data type of the collation
+ * order is <strong>int</strong>. The first 16 bits of a collation order
+ * is its primary order; the next 8 bits is the secondary order and the
+ * last 8 bits is the tertiary order.
+ *
+ * <p><b>Note:</b> <code>CollationElementIterator</code> is a part of
+ * <code>RuleBasedCollator</code> implementation. It is only usable
+ * with <code>RuleBasedCollator</code> instances.
+ *
+ * @see                Collator
+ * @see                RuleBasedCollator
+ * @author             Helena Shih, Laura Werner, Richard Gillam
+ */
+public final class CollationElementIterator
+{
+    /**
+     * Null order which indicates the end of string is reached by the
+     * cursor.
+     */
+    // Android-changed: use ICU CollationElementIterator constant.
+    public final static int NULLORDER = android.icu.text.CollationElementIterator.NULLORDER;
+
+    // Android-removed: internal constructors.
+
+    // Android-added: ICU iterator to delegate to.
+    private android.icu.text.CollationElementIterator icuIterator;
+
+   // Android-added: internal constructor taking an ICU CollationElementIterator.
+    CollationElementIterator(android.icu.text.CollationElementIterator iterator) {
+        icuIterator = iterator;
+    }
+
+    /**
+     * Resets the cursor to the beginning of the string.  The next call
+     * to next() will return the first collation element in the string.
+     */
+    public void reset()
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        icuIterator.reset();
+    }
+
+    /**
+     * Get the next collation element in the string.  <p>This iterator iterates
+     * over a sequence of collation elements that were built from the string.
+     * Because there isn't necessarily a one-to-one mapping from characters to
+     * collation elements, this doesn't mean the same thing as "return the
+     * collation element [or ordering priority] of the next character in the
+     * string".</p>
+     * <p>This function returns the collation element that the iterator is currently
+     * pointing to and then updates the internal pointer to point to the next element.
+     * previous() updates the pointer first and then returns the element.  This
+     * means that when you change direction while iterating (i.e., call next() and
+     * then call previous(), or call previous() and then call next()), you'll get
+     * back the same element twice.</p>
+     *
+     * @return the next collation element
+     */
+    public int next()
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        return icuIterator.next();
+    }
+
+    /**
+     * Get the previous collation element in the string.  <p>This iterator iterates
+     * over a sequence of collation elements that were built from the string.
+     * Because there isn't necessarily a one-to-one mapping from characters to
+     * collation elements, this doesn't mean the same thing as "return the
+     * collation element [or ordering priority] of the previous character in the
+     * string".</p>
+     * <p>This function updates the iterator's internal pointer to point to the
+     * collation element preceding the one it's currently pointing to and then
+     * returns that element, while next() returns the current element and then
+     * updates the pointer.  This means that when you change direction while
+     * iterating (i.e., call next() and then call previous(), or call previous()
+     * and then call next()), you'll get back the same element twice.</p>
+     *
+     * @return the previous collation element
+     * @since 1.2
+     */
+    public int previous()
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        return icuIterator.previous();
+    }
+
+    /**
+     * Return the primary component of a collation element.
+     * @param order the collation element
+     * @return the element's primary component
+     */
+    public final static int primaryOrder(int order)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        return android.icu.text.CollationElementIterator.primaryOrder(order);
+    }
+    /**
+     * Return the secondary component of a collation element.
+     * @param order the collation element
+     * @return the element's secondary component
+     */
+    public final static short secondaryOrder(int order)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+       return (short) android.icu.text.CollationElementIterator.secondaryOrder(order);
+    }
+    /**
+     * Return the tertiary component of a collation element.
+     * @param order the collation element
+     * @return the element's tertiary component
+     */
+    public final static short tertiaryOrder(int order)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        return (short) android.icu.text.CollationElementIterator.tertiaryOrder(order);
+    }
+
+    /**
+     * Sets the iterator to point to the collation element corresponding to
+     * the specified character (the parameter is a CHARACTER offset in the
+     * original string, not an offset into its corresponding sequence of
+     * collation elements).  The value returned by the next call to next()
+     * will be the collation element corresponding to the specified position
+     * in the text.  If that position is in the middle of a contracting
+     * character sequence, the result of the next call to next() is the
+     * collation element for that sequence.  This means that getOffset()
+     * is not guaranteed to return the same value as was passed to a preceding
+     * call to setOffset().
+     *
+     * @param newOffset The new character offset into the original text.
+     * @since 1.2
+     */
+    @SuppressWarnings("deprecation") // getBeginIndex, getEndIndex and setIndex are deprecated
+    public void setOffset(int newOffset)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        icuIterator.setOffset(newOffset);
+    }
+
+    /**
+     * Returns the character offset in the original text corresponding to the next
+     * collation element.  (That is, getOffset() returns the position in the text
+     * corresponding to the collation element that will be returned by the next
+     * call to next().)  This value will always be the index of the FIRST character
+     * corresponding to the collation element (a contracting character sequence is
+     * when two or more characters all correspond to the same collation element).
+     * This means if you do setOffset(x) followed immediately by getOffset(), getOffset()
+     * won't necessarily return x.
+     *
+     * @return The character offset in the original text corresponding to the collation
+     * element that will be returned by the next call to next().
+     * @since 1.2
+     */
+    public int getOffset()
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        return icuIterator.getOffset();
+    }
+
+
+    /**
+     * Return the maximum length of any expansion sequences that end
+     * with the specified comparison order.
+     * @param order a collation order returned by previous or next.
+     * @return the maximum length of any expansion sequences ending
+     *         with the specified order.
+     * @since 1.2
+     */
+    public int getMaxExpansion(int order)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        return icuIterator.getMaxExpansion(order);
+    }
+
+    /**
+     * Set a new string over which to iterate.
+     *
+     * @param source  the new source text
+     * @since 1.2
+     */
+    public void setText(String source)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        icuIterator.setText(source);
+    }
+
+    /**
+     * Set a new string over which to iterate.
+     *
+     * @param source  the new source text.
+     * @since 1.2
+     */
+    public void setText(CharacterIterator source)
+    {
+        // Android-changed: delegate to ICU CollationElementIterator.
+        icuIterator.setText(source);
+    }
+
+    // Android-removed: private helper methods and fields.
+}
diff --git a/java/text/CollationKey.java b/java/text/CollationKey.java
new file mode 100644
index 0000000..d4c7751
--- /dev/null
+++ b/java/text/CollationKey.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+/**
+ * A <code>CollationKey</code> represents a <code>String</code> under the
+ * rules of a specific <code>Collator</code> object. Comparing two
+ * <code>CollationKey</code>s returns the relative order of the
+ * <code>String</code>s they represent. Using <code>CollationKey</code>s
+ * to compare <code>String</code>s is generally faster than using
+ * <code>Collator.compare</code>. Thus, when the <code>String</code>s
+ * must be compared multiple times, for example when sorting a list
+ * of <code>String</code>s. It's more efficient to use <code>CollationKey</code>s.
+ *
+ * <p>
+ * You can not create <code>CollationKey</code>s directly. Rather,
+ * generate them by calling <code>Collator.getCollationKey</code>.
+ * You can only compare <code>CollationKey</code>s generated from
+ * the same <code>Collator</code> object.
+ *
+ * <p>
+ * Generating a <code>CollationKey</code> for a <code>String</code>
+ * involves examining the entire <code>String</code>
+ * and converting it to series of bits that can be compared bitwise. This
+ * allows fast comparisons once the keys are generated. The cost of generating
+ * keys is recouped in faster comparisons when <code>String</code>s need
+ * to be compared many times. On the other hand, the result of a comparison
+ * is often determined by the first couple of characters of each <code>String</code>.
+ * <code>Collator.compare</code> examines only as many characters as it needs which
+ * allows it to be faster when doing single comparisons.
+ * <p>
+ * The following example shows how <code>CollationKey</code>s might be used
+ * to sort a list of <code>String</code>s.
+ * <blockquote>
+ * <pre>{@code
+ * // Create an array of CollationKeys for the Strings to be sorted.
+ * Collator myCollator = Collator.getInstance();
+ * CollationKey[] keys = new CollationKey[3];
+ * keys[0] = myCollator.getCollationKey("Tom");
+ * keys[1] = myCollator.getCollationKey("Dick");
+ * keys[2] = myCollator.getCollationKey("Harry");
+ * sort(keys);
+ *
+ * //...
+ *
+ * // Inside body of sort routine, compare keys this way
+ * if (keys[i].compareTo(keys[j]) > 0)
+ *    // swap keys[i] and keys[j]
+ *
+ * //...
+ *
+ * // Finally, when we've returned from sort.
+ * System.out.println(keys[0].getSourceString());
+ * System.out.println(keys[1].getSourceString());
+ * System.out.println(keys[2].getSourceString());
+ * }</pre>
+ * </blockquote>
+ *
+ * @see          Collator
+ * @see          RuleBasedCollator
+ * @author       Helena Shih
+ */
+
+public abstract class CollationKey implements Comparable<CollationKey> {
+    /**
+     * Compare this CollationKey to the target CollationKey. The collation rules of the
+     * Collator object which created these keys are applied. <strong>Note:</strong>
+     * CollationKeys created by different Collators can not be compared.
+     * @param target target CollationKey
+     * @return Returns an integer value. Value is less than zero if this is less
+     * than target, value is zero if this and target are equal and value is greater than
+     * zero if this is greater than target.
+     * @see java.text.Collator#compare
+     */
+    abstract public int compareTo(CollationKey target);
+
+    /**
+     * Returns the String that this CollationKey represents.
+     *
+     * @return the source string of this CollationKey
+     */
+    public String getSourceString() {
+        return source;
+    }
+
+
+    /**
+     * Converts the CollationKey to a sequence of bits. If two CollationKeys
+     * could be legitimately compared, then one could compare the byte arrays
+     * for each of those keys to obtain the same result.  Byte arrays are
+     * organized most significant byte first.
+     *
+     * @return a byte array representation of the CollationKey
+     */
+    abstract public byte[] toByteArray();
+
+
+  /**
+   * CollationKey constructor.
+   *
+   * @param source the source string
+   * @exception NullPointerException if {@code source} is null
+   * @since 1.6
+   */
+    protected CollationKey(String source) {
+        if (source==null){
+            throw new NullPointerException();
+        }
+        this.source = source;
+    }
+
+    final private String source;
+}
diff --git a/java/text/Collator.java b/java/text/Collator.java
new file mode 100644
index 0000000..e7fc8b7
--- /dev/null
+++ b/java/text/Collator.java
@@ -0,0 +1,501 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 -  All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.util.Locale;
+
+import libcore.icu.ICU;
+
+/**
+ * The <code>Collator</code> class performs locale-sensitive
+ * <code>String</code> comparison. You use this class to build
+ * searching and sorting routines for natural language text.
+ *
+ * <p>
+ * <code>Collator</code> is an abstract base class. Subclasses
+ * implement specific collation strategies. One subclass,
+ * <code>RuleBasedCollator</code>, is currently provided with
+ * the Java Platform and is applicable to a wide set of languages. Other
+ * subclasses may be created to handle more specialized needs.
+ *
+ * <p>
+ * Like other locale-sensitive classes, you can use the static
+ * factory method, <code>getInstance</code>, to obtain the appropriate
+ * <code>Collator</code> object for a given locale. You will only need
+ * to look at the subclasses of <code>Collator</code> if you need
+ * to understand the details of a particular collation strategy or
+ * if you need to modify that strategy.
+ *
+ * <p>
+ * The following example shows how to compare two strings using
+ * the <code>Collator</code> for the default locale.
+ * <blockquote>
+ * <pre>{@code
+ * // Compare two strings in the default locale
+ * Collator myCollator = Collator.getInstance();
+ * if( myCollator.compare("abc", "ABC") < 0 )
+ *     System.out.println("abc is less than ABC");
+ * else
+ *     System.out.println("abc is greater than or equal to ABC");
+ * }</pre>
+ * </blockquote>
+ *
+ * <p>
+ * You can set a <code>Collator</code>'s <em>strength</em> property
+ * to determine the level of difference considered significant in
+ * comparisons. Four strengths are provided: <code>PRIMARY</code>,
+ * <code>SECONDARY</code>, <code>TERTIARY</code>, and <code>IDENTICAL</code>.
+ * The exact assignment of strengths to language features is
+ * locale dependant.  For example, in Czech, "e" and "f" are considered
+ * primary differences, while "e" and "&#283;" are secondary differences,
+ * "e" and "E" are tertiary differences and "e" and "e" are identical.
+ * The following shows how both case and accents could be ignored for
+ * US English.
+ * <blockquote>
+ * <pre>
+ * //Get the Collator for US English and set its strength to PRIMARY
+ * Collator usCollator = Collator.getInstance(Locale.US);
+ * usCollator.setStrength(Collator.PRIMARY);
+ * if( usCollator.compare("abc", "ABC") == 0 ) {
+ *     System.out.println("Strings are equivalent");
+ * }
+ * </pre>
+ * </blockquote>
+ * <p>
+ * For comparing <code>String</code>s exactly once, the <code>compare</code>
+ * method provides the best performance. When sorting a list of
+ * <code>String</code>s however, it is generally necessary to compare each
+ * <code>String</code> multiple times. In this case, <code>CollationKey</code>s
+ * provide better performance. The <code>CollationKey</code> class converts
+ * a <code>String</code> to a series of bits that can be compared bitwise
+ * against other <code>CollationKey</code>s. A <code>CollationKey</code> is
+ * created by a <code>Collator</code> object for a given <code>String</code>.
+ * <br>
+ * <strong>Note:</strong> <code>CollationKey</code>s from different
+ * <code>Collator</code>s can not be compared. See the class description
+ * for {@link CollationKey}
+ * for an example using <code>CollationKey</code>s.
+ *
+ * @see         RuleBasedCollator
+ * @see         CollationKey
+ * @see         CollationElementIterator
+ * @see         Locale
+ * @author      Helena Shih, Laura Werner, Richard Gillam
+ */
+
+public abstract class Collator
+    implements java.util.Comparator<Object>, Cloneable
+{
+    /**
+     * Collator strength value.  When set, only PRIMARY differences are
+     * considered significant during comparison. The assignment of strengths
+     * to language features is locale dependant. A common example is for
+     * different base letters ("a" vs "b") to be considered a PRIMARY difference.
+     * @see java.text.Collator#setStrength
+     * @see java.text.Collator#getStrength
+     */
+    public final static int PRIMARY = 0;
+    /**
+     * Collator strength value.  When set, only SECONDARY and above differences are
+     * considered significant during comparison. The assignment of strengths
+     * to language features is locale dependant. A common example is for
+     * different accented forms of the same base letter ("a" vs "\u00E4") to be
+     * considered a SECONDARY difference.
+     * @see java.text.Collator#setStrength
+     * @see java.text.Collator#getStrength
+     */
+    public final static int SECONDARY = 1;
+    /**
+     * Collator strength value.  When set, only TERTIARY and above differences are
+     * considered significant during comparison. The assignment of strengths
+     * to language features is locale dependant. A common example is for
+     * case differences ("a" vs "A") to be considered a TERTIARY difference.
+     * @see java.text.Collator#setStrength
+     * @see java.text.Collator#getStrength
+     */
+    public final static int TERTIARY = 2;
+
+    /**
+     * Collator strength value.  When set, all differences are
+     * considered significant during comparison. The assignment of strengths
+     * to language features is locale dependant. A common example is for control
+     * characters ("&#092;u0001" vs "&#092;u0002") to be considered equal at the
+     * PRIMARY, SECONDARY, and TERTIARY levels but different at the IDENTICAL
+     * level.  Additionally, differences between pre-composed accents such as
+     * "&#092;u00C0" (A-grave) and combining accents such as "A&#092;u0300"
+     * (A, combining-grave) will be considered significant at the IDENTICAL
+     * level if decomposition is set to NO_DECOMPOSITION.
+     */
+    public final static int IDENTICAL = 3;
+
+    /**
+     * Decomposition mode value. With NO_DECOMPOSITION
+     * set, accented characters will not be decomposed for collation. This
+     * is the default setting and provides the fastest collation but
+     * will only produce correct results for languages that do not use accents.
+     * @see java.text.Collator#getDecomposition
+     * @see java.text.Collator#setDecomposition
+     */
+    public final static int NO_DECOMPOSITION = 0;
+
+    /**
+     * Decomposition mode value. With CANONICAL_DECOMPOSITION
+     * set, characters that are canonical variants according to Unicode
+     * standard will be decomposed for collation. This should be used to get
+     * correct collation of accented characters.
+     * <p>
+     * CANONICAL_DECOMPOSITION corresponds to Normalization Form D as
+     * described in
+     * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode
+     * Technical Report #15</a>.
+     * @see java.text.Collator#getDecomposition
+     * @see java.text.Collator#setDecomposition
+     */
+    public final static int CANONICAL_DECOMPOSITION = 1;
+
+    /**
+     * Decomposition mode value. With FULL_DECOMPOSITION
+     * set, both Unicode canonical variants and Unicode compatibility variants
+     * will be decomposed for collation.  This causes not only accented
+     * characters to be collated, but also characters that have special formats
+     * to be collated with their norminal form. For example, the half-width and
+     * full-width ASCII and Katakana characters are then collated together.
+     * FULL_DECOMPOSITION is the most complete and therefore the slowest
+     * decomposition mode.
+     * <p>
+     * FULL_DECOMPOSITION corresponds to Normalization Form KD as
+     * described in
+     * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode
+     * Technical Report #15</a>.
+     * @see java.text.Collator#getDecomposition
+     * @see java.text.Collator#setDecomposition
+     */
+    public final static int FULL_DECOMPOSITION = 2;
+
+    /**
+     * Gets the Collator for the current default locale.
+     * The default locale is determined by java.util.Locale.getDefault.
+     * @return the Collator for the default locale.(for example, en_US)
+     * @see java.util.Locale#getDefault
+     */
+    public static synchronized Collator getInstance() {
+        return getInstance(Locale.getDefault());
+    }
+
+    /**
+     * Gets the Collator for the desired locale.
+     * @param desiredLocale the desired locale.
+     * @return the Collator for the desired locale.
+     * @see java.util.Locale
+     * @see java.util.ResourceBundle
+     */
+    public static Collator getInstance(Locale desiredLocale) {
+        // BEGIN Android-changed: Switched to ICU.
+        synchronized(Collator.class) {
+            if (desiredLocale == null) {
+                throw new NullPointerException("locale == null");
+            }
+            return new RuleBasedCollator((android.icu.text.RuleBasedCollator)
+                    android.icu.text.Collator.getInstance(desiredLocale));
+        }
+        // END Android-changed: Switched to ICU.
+    }
+
+    /**
+     * Compares the source string to the target string according to the
+     * collation rules for this Collator.  Returns an integer less than,
+     * equal to or greater than zero depending on whether the source String is
+     * less than, equal to or greater than the target string.  See the Collator
+     * class description for an example of use.
+     * <p>
+     * For a one time comparison, this method has the best performance. If a
+     * given String will be involved in multiple comparisons, CollationKey.compareTo
+     * has the best performance. See the Collator class description for an example
+     * using CollationKeys.
+     * @param source the source string.
+     * @param target the target string.
+     * @return Returns an integer value. Value is less than zero if source is less than
+     * target, value is zero if source and target are equal, value is greater than zero
+     * if source is greater than target.
+     * @see java.text.CollationKey
+     * @see java.text.Collator#getCollationKey
+     */
+    public abstract int compare(String source, String target);
+
+    /**
+     * Compares its two arguments for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.
+     * <p>
+     * This implementation merely returns
+     *  <code> compare((String)o1, (String)o2) </code>.
+     *
+     * @return a negative integer, zero, or a positive integer as the
+     *         first argument is less than, equal to, or greater than the
+     *         second.
+     * @exception ClassCastException the arguments cannot be cast to Strings.
+     * @see java.util.Comparator
+     * @since   1.2
+     */
+    @Override
+    public int compare(Object o1, Object o2) {
+    return compare((String)o1, (String)o2);
+    }
+
+    /**
+     * Transforms the String into a series of bits that can be compared bitwise
+     * to other CollationKeys. CollationKeys provide better performance than
+     * Collator.compare when Strings are involved in multiple comparisons.
+     * See the Collator class description for an example using CollationKeys.
+     * @param source the string to be transformed into a collation key.
+     * @return the CollationKey for the given String based on this Collator's collation
+     * rules. If the source String is null, a null CollationKey is returned.
+     * @see java.text.CollationKey
+     * @see java.text.Collator#compare
+     */
+    public abstract CollationKey getCollationKey(String source);
+
+    /**
+     * Convenience method for comparing the equality of two strings based on
+     * this Collator's collation rules.
+     * @param source the source string to be compared with.
+     * @param target the target string to be compared with.
+     * @return true if the strings are equal according to the collation
+     * rules.  false, otherwise.
+     * @see java.text.Collator#compare
+     */
+    public boolean equals(String source, String target)
+    {
+        // Android-changed: remove use of unnecessary EQUAL constant.
+        return (compare(source, target) == 0);
+    }
+
+    /**
+     * Returns this Collator's strength property.  The strength property determines
+     * the minimum level of difference considered significant during comparison.
+     * See the Collator class description for an example of use.
+     * @return this Collator's current strength property.
+     * @see java.text.Collator#setStrength
+     * @see java.text.Collator#PRIMARY
+     * @see java.text.Collator#SECONDARY
+     * @see java.text.Collator#TERTIARY
+     * @see java.text.Collator#IDENTICAL
+     */
+    public synchronized int getStrength()
+    {
+        // Android-changed: Switched to ICU.
+        // The value for IDENTICAL in ICU differs from that used in this class.
+        int value = icuColl.getStrength();
+        return (value == android.icu.text.Collator.IDENTICAL) ? IDENTICAL : value;
+    }
+
+    /**
+     * Sets this Collator's strength property.  The strength property determines
+     * the minimum level of difference considered significant during comparison.
+     * See the Collator class description for an example of use.
+     * @param newStrength  the new strength value.
+     * @see java.text.Collator#getStrength
+     * @see java.text.Collator#PRIMARY
+     * @see java.text.Collator#SECONDARY
+     * @see java.text.Collator#TERTIARY
+     * @see java.text.Collator#IDENTICAL
+     * @exception  IllegalArgumentException If the new strength value is not one of
+     * PRIMARY, SECONDARY, TERTIARY or IDENTICAL.
+     */
+    public synchronized void setStrength(int newStrength) {
+        // Android-changed: Switched to ICU.
+        // The ICU value for IDENTICAL differs from that defined in this class.
+        if (newStrength == IDENTICAL) {
+            newStrength = android.icu.text.Collator.IDENTICAL;
+        }
+        icuColl.setStrength(newStrength);
+    }
+
+    /**
+     * Get the decomposition mode of this Collator. Decomposition mode
+     * determines how Unicode composed characters are handled. Adjusting
+     * decomposition mode allows the user to select between faster and more
+     * complete collation behavior.
+     * <p>The three values for decomposition mode are:
+     * <UL>
+     * <LI>NO_DECOMPOSITION,
+     * <LI>CANONICAL_DECOMPOSITION
+     * <LI>FULL_DECOMPOSITION.
+     * </UL>
+     * See the documentation for these three constants for a description
+     * of their meaning.
+     * @return the decomposition mode
+     * @see java.text.Collator#setDecomposition
+     * @see java.text.Collator#NO_DECOMPOSITION
+     * @see java.text.Collator#CANONICAL_DECOMPOSITION
+     * @see java.text.Collator#FULL_DECOMPOSITION
+     */
+    public synchronized int getDecomposition()
+    {
+        // Android-changed: Switched to ICU.
+        return decompositionMode_ICU_Java(icuColl.getDecomposition());
+    }
+    /**
+     * Set the decomposition mode of this Collator. See getDecomposition
+     * for a description of decomposition mode.
+     * @param decompositionMode  the new decomposition mode.
+     * @see java.text.Collator#getDecomposition
+     * @see java.text.Collator#NO_DECOMPOSITION
+     * @see java.text.Collator#CANONICAL_DECOMPOSITION
+     * @see java.text.Collator#FULL_DECOMPOSITION
+     * @exception IllegalArgumentException If the given value is not a valid decomposition
+     * mode.
+     */
+    public synchronized void setDecomposition(int decompositionMode) {
+        // Android-changed: Switched to ICU.
+        icuColl.setDecomposition(decompositionMode_Java_ICU(decompositionMode));
+    }
+
+    // Android-changed: Removed javadoc references to CollatorProvider.
+    /**
+     * Returns an array of all locales for which the
+     * <code>getInstance</code> methods of this class can return
+     * localized instances.
+     *
+     * @return An array of locales for which localized
+     *         <code>Collator</code> instances are available.
+     */
+    public static synchronized Locale[] getAvailableLocales() {
+        // Android-changed: Removed reference to CollatorProvider. Switched to ICU.
+        return android.icu.text.Collator.getAvailableLocales();
+    }
+
+    // BEGIN Android-added: conversion method for decompositionMode constants.
+    private int decompositionMode_Java_ICU(int mode) {
+        switch (mode) {
+            case Collator.CANONICAL_DECOMPOSITION:
+                return android.icu.text.Collator.CANONICAL_DECOMPOSITION;
+            case Collator.NO_DECOMPOSITION:
+                return android.icu.text.Collator.NO_DECOMPOSITION;
+        }
+        throw new IllegalArgumentException("Bad mode: " + mode);
+    }
+
+    private int decompositionMode_ICU_Java(int mode) {
+        int javaMode = mode;
+        switch (mode) {
+            case android.icu.text.Collator.NO_DECOMPOSITION:
+                javaMode = Collator.NO_DECOMPOSITION;
+                break;
+            case android.icu.text.Collator.CANONICAL_DECOMPOSITION:
+                javaMode = Collator.CANONICAL_DECOMPOSITION;
+                break;
+        }
+        return javaMode;
+    }
+    // END Android-added: conversion method for decompositionMode constants.
+
+    // Android-changed: improve clone() documentation.
+    /**
+     * Returns a new collator with the same decomposition mode and
+     * strength value as this collator.
+     *
+     * @return a shallow copy of this collator.
+     * @see java.lang.Cloneable
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            // Android-changed: Switched to ICU.
+            Collator clone = (Collator) super.clone();
+            clone.icuColl = (android.icu.text.Collator) icuColl.clone();
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Compares the equality of two Collators.
+     * @param that the Collator to be compared with this.
+     * @return true if this Collator is the same as that Collator;
+     * false otherwise.
+     */
+    @Override
+    public boolean equals(Object that)
+    {
+        if (this == that) {
+            return true;
+        }
+        if (that == null) {
+            return false;
+        }
+        if (getClass() != that.getClass()) {
+            return false;
+        }
+        Collator other = (Collator) that;
+        // Android-changed: Switched to ICU.
+        return icuColl == null ? other.icuColl == null : icuColl.equals(other.icuColl);
+    }
+
+    /**
+     * Generates the hash code for this Collator.
+     */
+    @Override
+    abstract public int hashCode();
+
+    /**
+     * Default constructor.  This constructor is
+     * protected so subclasses can get access to it. Users typically create
+     * a Collator sub-class by calling the factory method getInstance.
+     * @see java.text.Collator#getInstance
+     */
+    protected Collator()
+    {
+        // Android-changed: Switched to ICU.
+        icuColl = android.icu.text.RuleBasedCollator.getInstance(Locale.getDefault());
+    }
+
+    // Android-added: ICU Collator this delegates to.
+    android.icu.text.Collator icuColl;
+
+    // Android-added: protected constructor taking a Collator.
+    Collator(android.icu.text.Collator icuColl) {
+        this.icuColl = icuColl;
+    }
+
+    // Android-removed: Fields and constants.
+}
diff --git a/java/text/DateFormat.annotated.java b/java/text/DateFormat.annotated.java
new file mode 100644
index 0000000..5a28d02
--- /dev/null
+++ b/java/text/DateFormat.annotated.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+
+package java.text;
+
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Calendar;
+import java.util.Date;
+import java.io.InvalidObjectException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class DateFormat extends java.text.Format {
+
+protected DateFormat() { throw new RuntimeException("Stub!"); }
+
+public final java.lang.StringBuffer format(java.lang.Object obj, java.lang.StringBuffer toAppendTo, java.text.FieldPosition fieldPosition) { throw new RuntimeException("Stub!"); }
+
+public abstract java.lang.StringBuffer format(java.util.Date date, java.lang.StringBuffer toAppendTo, java.text.FieldPosition fieldPosition);
+
+public final java.lang.String format(java.util.Date date) { throw new RuntimeException("Stub!"); }
+
+public java.util.Date parse(java.lang.String source) throws java.text.ParseException { throw new RuntimeException("Stub!"); }
+
+public abstract java.util.Date parse(java.lang.String source, java.text.ParsePosition pos);
+
+public java.lang.Object parseObject(java.lang.String source, java.text.ParsePosition pos) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getTimeInstance() { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getTimeInstance(int style) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getTimeInstance(int style, java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getDateInstance() { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getDateInstance(int style) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getDateInstance(int style, java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getDateTimeInstance() { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getDateTimeInstance(int dateStyle, int timeStyle) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getDateTimeInstance(int dateStyle, int timeStyle, java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat getInstance() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static final void set24HourTimePref(java.lang.Boolean is24Hour) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale[] getAvailableLocales() { throw new RuntimeException("Stub!"); }
+
+public void setCalendar(java.util.Calendar newCalendar) { throw new RuntimeException("Stub!"); }
+
+public java.util.Calendar getCalendar() { throw new RuntimeException("Stub!"); }
+
+public void setNumberFormat(java.text.NumberFormat newNumberFormat) { throw new RuntimeException("Stub!"); }
+
+public java.text.NumberFormat getNumberFormat() { throw new RuntimeException("Stub!"); }
+
+public void setTimeZone(java.util.TimeZone zone) { throw new RuntimeException("Stub!"); }
+
+public java.util.TimeZone getTimeZone() { throw new RuntimeException("Stub!"); }
+
+public void setLenient(boolean lenient) { throw new RuntimeException("Stub!"); }
+
+public boolean isLenient() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public static final int AM_PM_FIELD = 14; // 0xe
+
+public static final int DATE_FIELD = 3; // 0x3
+
+public static final int DAY_OF_WEEK_FIELD = 9; // 0x9
+
+public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11; // 0xb
+
+public static final int DAY_OF_YEAR_FIELD = 10; // 0xa
+
+public static final int DEFAULT = 2; // 0x2
+
+public static final int ERA_FIELD = 0; // 0x0
+
+public static final int FULL = 0; // 0x0
+
+public static final int HOUR0_FIELD = 16; // 0x10
+
+public static final int HOUR1_FIELD = 15; // 0xf
+
+public static final int HOUR_OF_DAY0_FIELD = 5; // 0x5
+
+public static final int HOUR_OF_DAY1_FIELD = 4; // 0x4
+
+public static final int LONG = 1; // 0x1
+
+public static final int MEDIUM = 2; // 0x2
+
+public static final int MILLISECOND_FIELD = 8; // 0x8
+
+public static final int MINUTE_FIELD = 6; // 0x6
+
+public static final int MONTH_FIELD = 2; // 0x2
+
+public static final int SECOND_FIELD = 7; // 0x7
+
+public static final int SHORT = 3; // 0x3
+
+public static final int TIMEZONE_FIELD = 17; // 0x11
+
+public static final int WEEK_OF_MONTH_FIELD = 13; // 0xd
+
+public static final int WEEK_OF_YEAR_FIELD = 12; // 0xc
+
+public static final int YEAR_FIELD = 1; // 0x1
+
+protected java.util.Calendar calendar;
+
+public static java.lang.Boolean is24Hour;
+
+protected java.text.NumberFormat numberFormat;
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class Field extends java.text.Format.Field {
+
+protected Field(java.lang.String name, int calendarField) { super(null); throw new RuntimeException("Stub!"); }
+
+public static java.text.DateFormat.Field ofCalendarField(int calendarField) { throw new RuntimeException("Stub!"); }
+
+public int getCalendarField() { throw new RuntimeException("Stub!"); }
+
+protected java.lang.Object readResolve() throws java.io.InvalidObjectException { throw new RuntimeException("Stub!"); }
+
+public static final java.text.DateFormat.Field AM_PM;
+static { AM_PM = null; }
+
+public static final java.text.DateFormat.Field DAY_OF_MONTH;
+static { DAY_OF_MONTH = null; }
+
+public static final java.text.DateFormat.Field DAY_OF_WEEK;
+static { DAY_OF_WEEK = null; }
+
+public static final java.text.DateFormat.Field DAY_OF_WEEK_IN_MONTH;
+static { DAY_OF_WEEK_IN_MONTH = null; }
+
+public static final java.text.DateFormat.Field DAY_OF_YEAR;
+static { DAY_OF_YEAR = null; }
+
+public static final java.text.DateFormat.Field ERA;
+static { ERA = null; }
+
+public static final java.text.DateFormat.Field HOUR0;
+static { HOUR0 = null; }
+
+public static final java.text.DateFormat.Field HOUR1;
+static { HOUR1 = null; }
+
+public static final java.text.DateFormat.Field HOUR_OF_DAY0;
+static { HOUR_OF_DAY0 = null; }
+
+public static final java.text.DateFormat.Field HOUR_OF_DAY1;
+static { HOUR_OF_DAY1 = null; }
+
+public static final java.text.DateFormat.Field MILLISECOND;
+static { MILLISECOND = null; }
+
+public static final java.text.DateFormat.Field MINUTE;
+static { MINUTE = null; }
+
+public static final java.text.DateFormat.Field MONTH;
+static { MONTH = null; }
+
+public static final java.text.DateFormat.Field SECOND;
+static { SECOND = null; }
+
+public static final java.text.DateFormat.Field TIME_ZONE;
+static { TIME_ZONE = null; }
+
+public static final java.text.DateFormat.Field WEEK_OF_MONTH;
+static { WEEK_OF_MONTH = null; }
+
+public static final java.text.DateFormat.Field WEEK_OF_YEAR;
+static { WEEK_OF_YEAR = null; }
+
+public static final java.text.DateFormat.Field YEAR;
+static { YEAR = null; }
+}
+
+}
+
diff --git a/java/text/DateFormat.java b/java/text/DateFormat.java
new file mode 100644
index 0000000..d7d5081
--- /dev/null
+++ b/java/text/DateFormat.java
@@ -0,0 +1,1044 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.InvalidObjectException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.TimeZone;
+import libcore.icu.ICU;
+
+/**
+ * {@code DateFormat} is an abstract class for date/time formatting subclasses which
+ * formats and parses dates or time in a language-independent manner.
+ * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
+ * formatting (i.e., date &rarr; text), parsing (text &rarr; date), and
+ * normalization.  The date is represented as a <code>Date</code> object or
+ * as the milliseconds since January 1, 1970, 00:00:00 GMT.
+ *
+ * <p>{@code DateFormat} provides many class methods for obtaining default date/time
+ * formatters based on the default or a given locale and a number of formatting
+ * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
+ * detail and examples of using these styles are provided in the method
+ * descriptions.
+ *
+ * <p>{@code DateFormat} helps you to format and parse dates for any locale.
+ * Your code can be completely independent of the locale conventions for
+ * months, days of the week, or even the calendar format: lunar vs. solar.
+ *
+ * <p>To format a date for the current Locale, use one of the
+ * static factory methods:
+ * <blockquote>
+ * <pre>{@code
+ * myString = DateFormat.getDateInstance().format(myDate);
+ * }</pre>
+ * </blockquote>
+ * <p>If you are formatting multiple dates, it is
+ * more efficient to get the format and use it multiple times so that
+ * the system doesn't have to fetch the information about the local
+ * language and country conventions multiple times.
+ * <blockquote>
+ * <pre>{@code
+ * DateFormat df = DateFormat.getDateInstance();
+ * for (int i = 0; i < myDate.length; ++i) {
+ *     output.println(df.format(myDate[i]) + "; ");
+ * }
+ * }</pre>
+ * </blockquote>
+ * <p>To format a date for a different Locale, specify it in the
+ * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
+ * <blockquote>
+ * <pre>{@code
+ * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
+ * }</pre>
+ * </blockquote>
+ * <p>You can use a DateFormat to parse also.
+ * <blockquote>
+ * <pre>{@code
+ * myDate = df.parse(myString);
+ * }</pre>
+ * </blockquote>
+ * <p>Use {@code getDateInstance} to get the normal date format for that country.
+ * There are other static factory methods available.
+ * Use {@code getTimeInstance} to get the time format for that country.
+ * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
+ * different options to these factory methods to control the length of the
+ * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
+ * on the locale, but generally:
+ * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
+ * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
+ * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
+ * <li>{@link #FULL} is pretty completely specified, such as
+ * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
+ * </ul>
+ *
+ * <p>You can also set the time zone on the format if you wish.
+ * If you want even more control over the format or parsing,
+ * (or want to give your users more control),
+ * you can try casting the {@code DateFormat} you get from the factory methods
+ * to a {@link SimpleDateFormat}. This will work for the majority
+ * of countries; just remember to put it in a {@code try} block in case you
+ * encounter an unusual one.
+ *
+ * <p>You can also use forms of the parse and format methods with
+ * {@link ParsePosition} and {@link FieldPosition} to
+ * allow you to
+ * <ul><li>progressively parse through pieces of a string.
+ * <li>align any particular field, or find out where it is for selection
+ * on the screen.
+ * </ul>
+ *
+ * <h3><a name="synchronization">Synchronization</a></h3>
+ *
+ * <p>
+ * Date formats are not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * @see          Format
+ * @see          NumberFormat
+ * @see          SimpleDateFormat
+ * @see          java.util.Calendar
+ * @see          java.util.GregorianCalendar
+ * @see          java.util.TimeZone
+ * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
+ */
+public abstract class DateFormat extends Format {
+
+    /**
+     * The {@link Calendar} instance used for calculating the date-time fields
+     * and the instant of time. This field is used for both formatting and
+     * parsing.
+     *
+     * <p>Subclasses should initialize this field to a {@link Calendar}
+     * appropriate for the {@link Locale} associated with this
+     * <code>DateFormat</code>.
+     * @serial
+     */
+    protected Calendar calendar;
+
+    /**
+     * The number formatter that <code>DateFormat</code> uses to format numbers
+     * in dates and times.  Subclasses should initialize this to a number format
+     * appropriate for the locale associated with this <code>DateFormat</code>.
+     * @serial
+     */
+    protected NumberFormat numberFormat;
+
+    /**
+     * Useful constant for ERA field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int ERA_FIELD = 0;
+    /**
+     * Useful constant for YEAR field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int YEAR_FIELD = 1;
+    /**
+     * Useful constant for MONTH field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int MONTH_FIELD = 2;
+    /**
+     * Useful constant for DATE field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int DATE_FIELD = 3;
+    /**
+     * Useful constant for one-based HOUR_OF_DAY field alignment.
+     * Used in FieldPosition of date/time formatting.
+     * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
+     * For example, 23:59 + 01:00 results in 24:59.
+     */
+    public final static int HOUR_OF_DAY1_FIELD = 4;
+    /**
+     * Useful constant for zero-based HOUR_OF_DAY field alignment.
+     * Used in FieldPosition of date/time formatting.
+     * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
+     * For example, 23:59 + 01:00 results in 00:59.
+     */
+    public final static int HOUR_OF_DAY0_FIELD = 5;
+    /**
+     * Useful constant for MINUTE field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int MINUTE_FIELD = 6;
+    /**
+     * Useful constant for SECOND field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int SECOND_FIELD = 7;
+    /**
+     * Useful constant for MILLISECOND field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int MILLISECOND_FIELD = 8;
+    /**
+     * Useful constant for DAY_OF_WEEK field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int DAY_OF_WEEK_FIELD = 9;
+    /**
+     * Useful constant for DAY_OF_YEAR field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int DAY_OF_YEAR_FIELD = 10;
+    /**
+     * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
+    /**
+     * Useful constant for WEEK_OF_YEAR field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int WEEK_OF_YEAR_FIELD = 12;
+    /**
+     * Useful constant for WEEK_OF_MONTH field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int WEEK_OF_MONTH_FIELD = 13;
+    /**
+     * Useful constant for AM_PM field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int AM_PM_FIELD = 14;
+    /**
+     * Useful constant for one-based HOUR field alignment.
+     * Used in FieldPosition of date/time formatting.
+     * HOUR1_FIELD is used for the one-based 12-hour clock.
+     * For example, 11:30 PM + 1 hour results in 12:30 AM.
+     */
+    public final static int HOUR1_FIELD = 15;
+    /**
+     * Useful constant for zero-based HOUR field alignment.
+     * Used in FieldPosition of date/time formatting.
+     * HOUR0_FIELD is used for the zero-based 12-hour clock.
+     * For example, 11:30 PM + 1 hour results in 00:30 AM.
+     */
+    public final static int HOUR0_FIELD = 16;
+    /**
+     * Useful constant for TIMEZONE field alignment.
+     * Used in FieldPosition of date/time formatting.
+     */
+    public final static int TIMEZONE_FIELD = 17;
+
+    // Proclaim serial compatibility with 1.1 FCS
+    private static final long serialVersionUID = 7218322306649953788L;
+
+    /**
+     * Overrides Format.
+     * Formats a time object into a time string. Examples of time objects
+     * are a time value expressed in milliseconds and a Date object.
+     * @param obj must be a Number or a Date.
+     * @param toAppendTo the string buffer for the returning time string.
+     * @return the string buffer passed in as toAppendTo, with formatted text appended.
+     * @param fieldPosition keeps track of the position of the field
+     * within the returned string.
+     * On input: an alignment field,
+     * if desired. On output: the offsets of the alignment field. For
+     * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
+     * if the given fieldPosition is DateFormat.YEAR_FIELD, the
+     * begin index and end index of fieldPosition will be set to
+     * 0 and 4, respectively.
+     * Notice that if the same time field appears
+     * more than once in a pattern, the fieldPosition will be set for the first
+     * occurrence of that time field. For instance, formatting a Date to
+     * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
+     * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
+     * the begin index and end index of fieldPosition will be set to
+     * 5 and 8, respectively, for the first occurrence of the timezone
+     * pattern character 'z'.
+     * @see java.text.Format
+     */
+    public final StringBuffer format(Object obj, StringBuffer toAppendTo,
+                                     FieldPosition fieldPosition)
+    {
+        if (obj instanceof Date)
+            return format( (Date)obj, toAppendTo, fieldPosition );
+        else if (obj instanceof Number)
+            return format( new Date(((Number)obj).longValue()),
+                          toAppendTo, fieldPosition );
+        else
+            throw new IllegalArgumentException("Cannot format given Object as a Date");
+    }
+
+    /**
+     * Formats a Date into a date/time string.
+     * @param date a Date to be formatted into a date/time string.
+     * @param toAppendTo the string buffer for the returning date/time string.
+     * @param fieldPosition keeps track of the position of the field
+     * within the returned string.
+     * On input: an alignment field,
+     * if desired. On output: the offsets of the alignment field. For
+     * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
+     * if the given fieldPosition is DateFormat.YEAR_FIELD, the
+     * begin index and end index of fieldPosition will be set to
+     * 0 and 4, respectively.
+     * Notice that if the same time field appears
+     * more than once in a pattern, the fieldPosition will be set for the first
+     * occurrence of that time field. For instance, formatting a Date to
+     * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
+     * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
+     * the begin index and end index of fieldPosition will be set to
+     * 5 and 8, respectively, for the first occurrence of the timezone
+     * pattern character 'z'.
+     * @return the string buffer passed in as toAppendTo, with formatted text appended.
+     */
+    public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
+                                        FieldPosition fieldPosition);
+
+    /**
+     * Formats a Date into a date/time string.
+     * @param date the time value to be formatted into a time string.
+     * @return the formatted time string.
+     */
+    public final String format(Date date)
+    {
+        return format(date, new StringBuffer(),
+                      DontCareFieldPosition.INSTANCE).toString();
+    }
+
+    /**
+     * Parses text from the beginning of the given string to produce a date.
+     * The method may not use the entire text of the given string.
+     * <p>
+     * See the {@link #parse(String, ParsePosition)} method for more information
+     * on date parsing.
+     *
+     * @param source A <code>String</code> whose beginning should be parsed.
+     * @return A <code>Date</code> parsed from the string.
+     * @exception ParseException if the beginning of the specified string
+     *            cannot be parsed.
+     */
+    public Date parse(String source) throws ParseException
+    {
+        ParsePosition pos = new ParsePosition(0);
+        Date result = parse(source, pos);
+        if (pos.index == 0)
+            throw new ParseException("Unparseable date: \"" + source + "\"" ,
+                pos.errorIndex);
+        return result;
+    }
+
+    /**
+     * Parse a date/time string according to the given parse position.  For
+     * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
+     * that is equivalent to {@code Date(837039900000L)}.
+     *
+     * <p> By default, parsing is lenient: If the input is not in the form used
+     * by this object's format method but can still be parsed as a date, then
+     * the parse succeeds.  Clients may insist on strict adherence to the
+     * format by calling {@link #setLenient(boolean) setLenient(false)}.
+     *
+     * <p>This parsing operation uses the {@link #calendar} to produce
+     * a {@code Date}. As a result, the {@code calendar}'s date-time
+     * fields and the {@code TimeZone} value may have been
+     * overwritten, depending on subclass implementations. Any {@code
+     * TimeZone} value that has previously been set by a call to
+     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
+     * to be restored for further operations.
+     *
+     * @param source  The date/time string to be parsed
+     *
+     * @param pos   On input, the position at which to start parsing; on
+     *              output, the position at which parsing terminated, or the
+     *              start position if the parse failed.
+     *
+     * @return      A {@code Date}, or {@code null} if the input could not be parsed
+     */
+    public abstract Date parse(String source, ParsePosition pos);
+
+    /**
+     * Parses text from a string to produce a <code>Date</code>.
+     * <p>
+     * The method attempts to parse text starting at the index given by
+     * <code>pos</code>.
+     * If parsing succeeds, then the index of <code>pos</code> is updated
+     * to the index after the last character used (parsing does not necessarily
+     * use all characters up to the end of the string), and the parsed
+     * date is returned. The updated <code>pos</code> can be used to
+     * indicate the starting point for the next call to this method.
+     * If an error occurs, then the index of <code>pos</code> is not
+     * changed, the error index of <code>pos</code> is set to the index of
+     * the character where the error occurred, and null is returned.
+     * <p>
+     * See the {@link #parse(String, ParsePosition)} method for more information
+     * on date parsing.
+     *
+     * @param source A <code>String</code>, part of which should be parsed.
+     * @param pos A <code>ParsePosition</code> object with index and error
+     *            index information as described above.
+     * @return A <code>Date</code> parsed from the string. In case of
+     *         error, returns null.
+     * @exception NullPointerException if <code>pos</code> is null.
+     */
+    public Object parseObject(String source, ParsePosition pos) {
+        return parse(source, pos);
+    }
+
+    /**
+     * Constant for full style pattern.
+     */
+    public static final int FULL = 0;
+    /**
+     * Constant for long style pattern.
+     */
+    public static final int LONG = 1;
+    /**
+     * Constant for medium style pattern.
+     */
+    public static final int MEDIUM = 2;
+    /**
+     * Constant for short style pattern.
+     */
+    public static final int SHORT = 3;
+    /**
+     * Constant for default style pattern.  Its value is MEDIUM.
+     */
+    public static final int DEFAULT = MEDIUM;
+
+    /**
+     * Gets the time formatter with the default formatting style
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getTimeInstance(int, Locale) getTimeInstance(DEFAULT,
+     *     Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @return a time formatter.
+     */
+    public final static DateFormat getTimeInstance()
+    {
+        return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets the time formatter with the given formatting style
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getTimeInstance(int, Locale) getTimeInstance(style,
+     *     Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @param style the given formatting style. For example,
+     * SHORT for "h:mm a" in the US locale.
+     * @return a time formatter.
+     */
+    public final static DateFormat getTimeInstance(int style)
+    {
+        return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets the time formatter with the given formatting style
+     * for the given locale.
+     * @param style the given formatting style. For example,
+     * SHORT for "h:mm a" in the US locale.
+     * @param aLocale the given locale.
+     * @return a time formatter.
+     */
+    public final static DateFormat getTimeInstance(int style,
+                                                 Locale aLocale)
+    {
+        return get(style, 0, 1, aLocale);
+    }
+
+    /**
+     * Gets the date formatter with the default formatting style
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getDateInstance(int, Locale) getDateInstance(DEFAULT,
+     *     Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @return a date formatter.
+     */
+    public final static DateFormat getDateInstance()
+    {
+        return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets the date formatter with the given formatting style
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getDateInstance(int, Locale) getDateInstance(style,
+     *     Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @param style the given formatting style. For example,
+     * SHORT for "M/d/yy" in the US locale.
+     * @return a date formatter.
+     */
+    public final static DateFormat getDateInstance(int style)
+    {
+        return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets the date formatter with the given formatting style
+     * for the given locale.
+     * @param style the given formatting style. For example,
+     * SHORT for "M/d/yy" in the US locale.
+     * @param aLocale the given locale.
+     * @return a date formatter.
+     */
+    public final static DateFormat getDateInstance(int style,
+                                                 Locale aLocale)
+    {
+        return get(0, style, 2, aLocale);
+    }
+
+    /**
+     * Gets the date/time formatter with the default formatting style
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getDateTimeInstance(int, int, Locale) getDateTimeInstance(DEFAULT,
+     *     DEFAULT, Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @return a date/time formatter.
+     */
+    public final static DateFormat getDateTimeInstance()
+    {
+        return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets the date/time formatter with the given date and time
+     * formatting styles for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getDateTimeInstance(int, int, Locale) getDateTimeInstance(dateStyle,
+     *     timeStyle, Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @param dateStyle the given date formatting style. For example,
+     * SHORT for "M/d/yy" in the US locale.
+     * @param timeStyle the given time formatting style. For example,
+     * SHORT for "h:mm a" in the US locale.
+     * @return a date/time formatter.
+     */
+    public final static DateFormat getDateTimeInstance(int dateStyle,
+                                                       int timeStyle)
+    {
+        return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets the date/time formatter with the given formatting styles
+     * for the given locale.
+     * @param dateStyle the given date formatting style.
+     * @param timeStyle the given time formatting style.
+     * @param aLocale the given locale.
+     * @return a date/time formatter.
+     */
+    public final static DateFormat
+        getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
+    {
+        return get(timeStyle, dateStyle, 3, aLocale);
+    }
+
+    /**
+     * Get a default date/time formatter that uses the SHORT style for both the
+     * date and the time.
+     *
+     * @return a date/time formatter
+     */
+    public final static DateFormat getInstance() {
+        return getDateTimeInstance(SHORT, SHORT);
+    }
+
+    // Android-changed: Added support for overriding locale default 12 / 24 hour preference.
+    /**
+     * {@code null}: use Locale default. {@code true}: force 24-hour format.
+     * {@code false} force 12-hour format.
+     * @hide
+     */
+    public static Boolean is24Hour;
+
+    /**
+     * Override the time formatting behavior for SHORT and MEDIUM time formats.
+     * {@code null}: use Locale default. {@code true}: force 24-hour format.
+     * {@code false} force 12-hour format.
+     *
+     * @hide for internal use only.
+     */
+    public static final void set24HourTimePref(Boolean is24Hour) {
+        DateFormat.is24Hour = is24Hour;
+    }
+
+    // Android-changed: Remove reference to DateFormatProvider.
+    /**
+     * Returns an array of all locales for which the
+     * <code>get*Instance</code> methods of this class can return
+     * localized instances.
+     *
+     * @return An array of locales for which localized
+     *         <code>DateFormat</code> instances are available.
+     */
+    public static Locale[] getAvailableLocales()
+    {
+        // Android-changed: Removed used of DateFormatProvider. Switched to use ICU.
+        return ICU.getAvailableLocales();
+    }
+
+    /**
+     * Set the calendar to be used by this date format.  Initially, the default
+     * calendar for the specified or default locale is used.
+     *
+     * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
+     * #isLenient() leniency} values that have previously been set are
+     * overwritten by {@code newCalendar}'s values.
+     *
+     * @param newCalendar the new {@code Calendar} to be used by the date format
+     */
+    public void setCalendar(Calendar newCalendar)
+    {
+        this.calendar = newCalendar;
+    }
+
+    /**
+     * Gets the calendar associated with this date/time formatter.
+     *
+     * @return the calendar associated with this date/time formatter.
+     */
+    public Calendar getCalendar()
+    {
+        return calendar;
+    }
+
+    /**
+     * Allows you to set the number formatter.
+     * @param newNumberFormat the given new NumberFormat.
+     */
+    public void setNumberFormat(NumberFormat newNumberFormat)
+    {
+        this.numberFormat = newNumberFormat;
+    }
+
+    /**
+     * Gets the number formatter which this date/time formatter uses to
+     * format and parse a time.
+     * @return the number formatter which this date/time formatter uses.
+     */
+    public NumberFormat getNumberFormat()
+    {
+        return numberFormat;
+    }
+
+    /**
+     * Sets the time zone for the calendar of this {@code DateFormat} object.
+     * This method is equivalent to the following call.
+     * <blockquote><pre>{@code
+     * getCalendar().setTimeZone(zone)
+     * }</pre></blockquote>
+     *
+     * <p>The {@code TimeZone} set by this method is overwritten by a
+     * {@link #setCalendar(java.util.Calendar) setCalendar} call.
+     *
+     * <p>The {@code TimeZone} set by this method may be overwritten as
+     * a result of a call to the parse method.
+     *
+     * @param zone the given new time zone.
+     */
+    public void setTimeZone(TimeZone zone)
+    {
+        calendar.setTimeZone(zone);
+    }
+
+    /**
+     * Gets the time zone.
+     * This method is equivalent to the following call.
+     * <blockquote><pre>{@code
+     * getCalendar().getTimeZone()
+     * }</pre></blockquote>
+     *
+     * @return the time zone associated with the calendar of DateFormat.
+     */
+    public TimeZone getTimeZone()
+    {
+        return calendar.getTimeZone();
+    }
+
+    /**
+     * Specify whether or not date/time parsing is to be lenient.  With
+     * lenient parsing, the parser may use heuristics to interpret inputs that
+     * do not precisely match this object's format.  With strict parsing,
+     * inputs must match this object's format.
+     *
+     * <p>This method is equivalent to the following call.
+     * <blockquote><pre>{@code
+     * getCalendar().setLenient(lenient)
+     * }</pre></blockquote>
+     *
+     * <p>This leniency value is overwritten by a call to {@link
+     * #setCalendar(java.util.Calendar) setCalendar()}.
+     *
+     * @param lenient when {@code true}, parsing is lenient
+     * @see java.util.Calendar#setLenient(boolean)
+     */
+    public void setLenient(boolean lenient)
+    {
+        calendar.setLenient(lenient);
+    }
+
+    /**
+     * Tell whether date/time parsing is to be lenient.
+     * This method is equivalent to the following call.
+     * <blockquote><pre>{@code
+     * getCalendar().isLenient()
+     * }</pre></blockquote>
+     *
+     * @return {@code true} if the {@link #calendar} is lenient;
+     *         {@code false} otherwise.
+     * @see java.util.Calendar#isLenient()
+     */
+    public boolean isLenient()
+    {
+        return calendar.isLenient();
+    }
+
+    /**
+     * Overrides hashCode
+     */
+    public int hashCode() {
+        return numberFormat.hashCode();
+        // just enough fields for a reasonable distribution
+    }
+
+    /**
+     * Overrides equals
+     */
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        DateFormat other = (DateFormat) obj;
+        return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
+                calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
+                calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
+                calendar.isLenient() == other.calendar.isLenient() &&
+                calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
+                numberFormat.equals(other.numberFormat));
+    }
+
+    /**
+     * Overrides Cloneable
+     */
+    public Object clone()
+    {
+        DateFormat other = (DateFormat) super.clone();
+        other.calendar = (Calendar) calendar.clone();
+        other.numberFormat = (NumberFormat) numberFormat.clone();
+        return other;
+    }
+
+    /**
+     * Creates a DateFormat with the given time and/or date style in the given
+     * locale.
+     * @param timeStyle a value from 0 to 3 indicating the time format,
+     * ignored if flags is 2
+     * @param dateStyle a value from 0 to 3 indicating the time format,
+     * ignored if flags is 1
+     * @param flags either 1 for a time format, 2 for a date format,
+     * or 3 for a date/time format
+     * @param loc the locale for the format
+     */
+    private static DateFormat get(int timeStyle, int dateStyle,
+                                  int flags, Locale loc) {
+        if ((flags & 1) != 0) {
+            if (timeStyle < 0 || timeStyle > 3) {
+                throw new IllegalArgumentException("Illegal time style " + timeStyle);
+            }
+        } else {
+            timeStyle = -1;
+        }
+        if ((flags & 2) != 0) {
+            if (dateStyle < 0 || dateStyle > 3) {
+                throw new IllegalArgumentException("Illegal date style " + dateStyle);
+            }
+        } else {
+            dateStyle = -1;
+        }
+
+        // BEGIN Android-changed: Remove use of DateFormatProvider and LocaleProviderAdapter.
+        /*
+        LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, loc);
+        DateFormat dateFormat = get(adapter, timeStyle, dateStyle, loc);
+        if (dateFormat == null) {
+            dateFormat = get(LocaleProviderAdapter.forJRE(), timeStyle, dateStyle, loc);
+        }
+        return dateFormat;
+        */
+        try {
+            return new SimpleDateFormat(timeStyle, dateStyle, loc);
+        } catch (MissingResourceException e) {
+            return new SimpleDateFormat("M/d/yy h:mm a");
+        }
+        // END Android-changed: Remove use of DateFormatProvider and LocaleProviderAdapter.
+    }
+
+    /**
+     * Create a new date format.
+     */
+    protected DateFormat() {}
+
+    /**
+     * Defines constants that are used as attribute keys in the
+     * <code>AttributedCharacterIterator</code> returned
+     * from <code>DateFormat.formatToCharacterIterator</code> and as
+     * field identifiers in <code>FieldPosition</code>.
+     * <p>
+     * The class also provides two methods to map
+     * between its constants and the corresponding Calendar constants.
+     *
+     * @since 1.4
+     * @see java.util.Calendar
+     */
+    public static class Field extends Format.Field {
+
+        // Proclaim serial compatibility with 1.4 FCS
+        private static final long serialVersionUID = 7441350119349544720L;
+
+        // table of all instances in this class, used by readResolve
+        private static final Map<String, Field> instanceMap = new HashMap<>(18);
+        // Maps from Calendar constant (such as Calendar.ERA) to Field
+        // constant (such as Field.ERA).
+        private static final Field[] calendarToFieldMapping =
+                                             new Field[Calendar.FIELD_COUNT];
+
+        /** Calendar field. */
+        private int calendarField;
+
+        /**
+         * Returns the <code>Field</code> constant that corresponds to
+         * the <code>Calendar</code> constant <code>calendarField</code>.
+         * If there is no direct mapping between the <code>Calendar</code>
+         * constant and a <code>Field</code>, null is returned.
+         *
+         * @throws IllegalArgumentException if <code>calendarField</code> is
+         *         not the value of a <code>Calendar</code> field constant.
+         * @param calendarField Calendar field constant
+         * @return Field instance representing calendarField.
+         * @see java.util.Calendar
+         */
+        public static Field ofCalendarField(int calendarField) {
+            if (calendarField < 0 || calendarField >=
+                        calendarToFieldMapping.length) {
+                throw new IllegalArgumentException("Unknown Calendar constant "
+                                                   + calendarField);
+            }
+            return calendarToFieldMapping[calendarField];
+        }
+
+        /**
+         * Creates a <code>Field</code>.
+         *
+         * @param name the name of the <code>Field</code>
+         * @param calendarField the <code>Calendar</code> constant this
+         *        <code>Field</code> corresponds to; any value, even one
+         *        outside the range of legal <code>Calendar</code> values may
+         *        be used, but <code>-1</code> should be used for values
+         *        that don't correspond to legal <code>Calendar</code> values
+         */
+        protected Field(String name, int calendarField) {
+            super(name);
+            this.calendarField = calendarField;
+            if (this.getClass() == DateFormat.Field.class) {
+                instanceMap.put(name, this);
+                if (calendarField >= 0) {
+                    // assert(calendarField < Calendar.FIELD_COUNT);
+                    calendarToFieldMapping[calendarField] = this;
+                }
+            }
+        }
+
+        /**
+         * Returns the <code>Calendar</code> field associated with this
+         * attribute. For example, if this represents the hours field of
+         * a <code>Calendar</code>, this would return
+         * <code>Calendar.HOUR</code>. If there is no corresponding
+         * <code>Calendar</code> constant, this will return -1.
+         *
+         * @return Calendar constant for this field
+         * @see java.util.Calendar
+         */
+        public int getCalendarField() {
+            return calendarField;
+        }
+
+        /**
+         * Resolves instances being deserialized to the predefined constants.
+         *
+         * @throws InvalidObjectException if the constant could not be
+         *         resolved.
+         * @return resolved DateFormat.Field constant
+         */
+        @Override
+        protected Object readResolve() throws InvalidObjectException {
+            if (this.getClass() != DateFormat.Field.class) {
+                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
+            }
+
+            Object instance = instanceMap.get(getName());
+            if (instance != null) {
+                return instance;
+            } else {
+                throw new InvalidObjectException("unknown attribute name");
+            }
+        }
+
+        //
+        // The constants
+        //
+
+        /**
+         * Constant identifying the era field.
+         */
+        public final static Field ERA = new Field("era", Calendar.ERA);
+
+        /**
+         * Constant identifying the year field.
+         */
+        public final static Field YEAR = new Field("year", Calendar.YEAR);
+
+        /**
+         * Constant identifying the month field.
+         */
+        public final static Field MONTH = new Field("month", Calendar.MONTH);
+
+        /**
+         * Constant identifying the day of month field.
+         */
+        public final static Field DAY_OF_MONTH = new
+                            Field("day of month", Calendar.DAY_OF_MONTH);
+
+        /**
+         * Constant identifying the hour of day field, where the legal values
+         * are 1 to 24.
+         */
+        public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
+
+        /**
+         * Constant identifying the hour of day field, where the legal values
+         * are 0 to 23.
+         */
+        public final static Field HOUR_OF_DAY0 = new
+               Field("hour of day", Calendar.HOUR_OF_DAY);
+
+        /**
+         * Constant identifying the minute field.
+         */
+        public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
+
+        /**
+         * Constant identifying the second field.
+         */
+        public final static Field SECOND =new Field("second", Calendar.SECOND);
+
+        /**
+         * Constant identifying the millisecond field.
+         */
+        public final static Field MILLISECOND = new
+                Field("millisecond", Calendar.MILLISECOND);
+
+        /**
+         * Constant identifying the day of week field.
+         */
+        public final static Field DAY_OF_WEEK = new
+                Field("day of week", Calendar.DAY_OF_WEEK);
+
+        /**
+         * Constant identifying the day of year field.
+         */
+        public final static Field DAY_OF_YEAR = new
+                Field("day of year", Calendar.DAY_OF_YEAR);
+
+        /**
+         * Constant identifying the day of week field.
+         */
+        public final static Field DAY_OF_WEEK_IN_MONTH =
+                     new Field("day of week in month",
+                                            Calendar.DAY_OF_WEEK_IN_MONTH);
+
+        /**
+         * Constant identifying the week of year field.
+         */
+        public final static Field WEEK_OF_YEAR = new
+              Field("week of year", Calendar.WEEK_OF_YEAR);
+
+        /**
+         * Constant identifying the week of month field.
+         */
+        public final static Field WEEK_OF_MONTH = new
+            Field("week of month", Calendar.WEEK_OF_MONTH);
+
+        /**
+         * Constant identifying the time of day indicator
+         * (e.g. "a.m." or "p.m.") field.
+         */
+        public final static Field AM_PM = new
+                            Field("am pm", Calendar.AM_PM);
+
+        /**
+         * Constant identifying the hour field, where the legal values are
+         * 1 to 12.
+         */
+        public final static Field HOUR1 = new Field("hour 1", -1);
+
+        /**
+         * Constant identifying the hour field, where the legal values are
+         * 0 to 11.
+         */
+        public final static Field HOUR0 = new
+                            Field("hour", Calendar.HOUR);
+
+        /**
+         * Constant identifying the time zone field.
+         */
+        public final static Field TIME_ZONE = new Field("time zone", -1);
+    }
+}
diff --git a/java/text/DateFormatSymbols.java b/java/text/DateFormatSymbols.java
new file mode 100644
index 0000000..97dc528
--- /dev/null
+++ b/java/text/DateFormatSymbols.java
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import libcore.icu.ICU;
+import libcore.icu.LocaleData;
+import libcore.icu.TimeZoneNames;
+
+/**
+ * <code>DateFormatSymbols</code> is a public class for encapsulating
+ * localizable date-time formatting data, such as the names of the
+ * months, the names of the days of the week, and the time zone data.
+ * <code>SimpleDateFormat</code> uses
+ * <code>DateFormatSymbols</code> to encapsulate this information.
+ *
+ * <p>
+ * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
+ * Rather, you are encouraged to create a date-time formatter with the
+ * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
+ * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
+ * These methods automatically create a <code>DateFormatSymbols</code> for
+ * the formatter so that you don't have to. After the
+ * formatter is created, you may modify its format pattern using the
+ * <code>setPattern</code> method. For more information about
+ * creating formatters using <code>DateFormat</code>'s factory methods,
+ * see {@link DateFormat}.
+ *
+ * <p>
+ * If you decide to create a date-time formatter with a specific
+ * format pattern for a specific locale, you can do so with:
+ * <blockquote>
+ * <pre>
+ * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
+ * a <code>DateFormatSymbols</code> object, feel free to modify the
+ * date-time formatting data. For instance, you can replace the localized
+ * date-time format pattern characters with the ones that you feel easy
+ * to remember. Or you can change the representative cities
+ * to your favorite ones.
+ *
+ * <p>
+ * New <code>DateFormatSymbols</code> subclasses may be added to support
+ * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
+
+ * @see          DateFormat
+ * @see          SimpleDateFormat
+ * @see          java.util.SimpleTimeZone
+ * @author       Chen-Lieh Huang
+ */
+public class DateFormatSymbols implements Serializable, Cloneable {
+
+    // Android-changed: Removed reference to DateFormatSymbolsProvider but suggested getInstance()
+    // be used instead in case Android supports it in future.
+    /**
+     * Construct a DateFormatSymbols object by loading format data from
+     * resources for the default {@link java.util.Locale.Category#FORMAT FORMAT}
+     * locale. It is recommended that the {@link #getInstance(Locale) getInstance} method is used
+     * instead.
+     * <p>This is equivalent to calling
+     * {@link #DateFormatSymbols(Locale)
+     *     DateFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see #getInstance()
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @exception  java.util.MissingResourceException
+     *             if the resources for the default locale cannot be
+     *             found or cannot be loaded.
+     */
+    public DateFormatSymbols()
+    {
+        initializeData(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    // Android-changed: Removed reference to DateFormatSymbolsProvider but suggested getInstance()
+    // be used instead in case Android supports it in future.
+    /**
+     * Construct a DateFormatSymbols object by loading format data from
+     * resources for the given locale. It is recommended that the
+     * {@link #getInstance(Locale) getInstance} method is used instead.
+     *
+     * @param locale the desired locale
+     * @see #getInstance(Locale)
+     * @exception  java.util.MissingResourceException
+     *             if the resources for the specified locale cannot be
+     *             found or cannot be loaded.
+     */
+    public DateFormatSymbols(Locale locale)
+    {
+        initializeData(locale);
+    }
+
+    // Android-removed: unused private DateFormatSymbols(boolean) constructor.
+
+    /**
+     * Era strings. For example: "AD" and "BC".  An array of 2 strings,
+     * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
+     * @serial
+     */
+    String eras[] = null;
+
+    /**
+     * Month strings. For example: "January", "February", etc.  An array
+     * of 13 strings (some calendars have 13 months), indexed by
+     * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
+     * @serial
+     */
+    String months[] = null;
+
+    /**
+     * Short month strings. For example: "Jan", "Feb", etc.  An array of
+     * 13 strings (some calendars have 13 months), indexed by
+     * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
+
+     * @serial
+     */
+    String shortMonths[] = null;
+
+    /**
+     * Weekday strings. For example: "Sunday", "Monday", etc.  An array
+     * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
+     * <code>Calendar.MONDAY</code>, etc.
+     * The element <code>weekdays[0]</code> is ignored.
+     * @serial
+     */
+    String weekdays[] = null;
+
+    /**
+     * Short weekday strings. For example: "Sun", "Mon", etc.  An array
+     * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
+     * <code>Calendar.MONDAY</code>, etc.
+     * The element <code>shortWeekdays[0]</code> is ignored.
+     * @serial
+     */
+    String shortWeekdays[] = null;
+
+    /**
+     * AM and PM strings. For example: "AM" and "PM".  An array of
+     * 2 strings, indexed by <code>Calendar.AM</code> and
+     * <code>Calendar.PM</code>.
+     * @serial
+     */
+    String ampms[] = null;
+
+    /**
+     * Localized names of time zones in this locale.  This is a
+     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
+     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
+     * entry containing the localized names for a single <code>TimeZone</code>.
+     * Each such row contains (with <code>i</code> ranging from
+     * 0..<em>n</em>-1):
+     * <ul>
+     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
+     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
+     * time</li>
+     * <li><code>zoneStrings[i][2]</code> - short name of zone in
+     * standard time</li>
+     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
+     * saving time</li>
+     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
+     * saving time</li>
+     * </ul>
+     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
+     * the {@link java.util.TimeZone TimeZone} class that are not
+     * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
+     * All other entries are localized names.
+     * @see java.util.TimeZone
+     * @serial
+     */
+    String zoneStrings[][] = null;
+
+    /**
+     * Indicates that zoneStrings is set externally with setZoneStrings() method.
+     */
+    transient boolean isZoneStringsSet = false;
+
+    /**
+     * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
+     * All locales use the same these unlocalized pattern characters.
+     */
+    // Android-changed: Add 'c' (standalone day of week), 'b' (day period),
+    //   'B' (flexible day period)
+    static final String  patternChars = "GyMdkHmsSEDFwWahKzZYuXLcbB";
+
+    static final int PATTERN_ERA                  =  0; // G
+    static final int PATTERN_YEAR                 =  1; // y
+    static final int PATTERN_MONTH                =  2; // M
+    static final int PATTERN_DAY_OF_MONTH         =  3; // d
+    static final int PATTERN_HOUR_OF_DAY1         =  4; // k
+    static final int PATTERN_HOUR_OF_DAY0         =  5; // H
+    static final int PATTERN_MINUTE               =  6; // m
+    static final int PATTERN_SECOND               =  7; // s
+    static final int PATTERN_MILLISECOND          =  8; // S
+    static final int PATTERN_DAY_OF_WEEK          =  9; // E
+    static final int PATTERN_DAY_OF_YEAR          = 10; // D
+    static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
+    static final int PATTERN_WEEK_OF_YEAR         = 12; // w
+    static final int PATTERN_WEEK_OF_MONTH        = 13; // W
+    static final int PATTERN_AM_PM                = 14; // a
+    static final int PATTERN_HOUR1                = 15; // h
+    static final int PATTERN_HOUR0                = 16; // K
+    static final int PATTERN_ZONE_NAME            = 17; // z
+    static final int PATTERN_ZONE_VALUE           = 18; // Z
+    static final int PATTERN_WEEK_YEAR            = 19; // Y
+    static final int PATTERN_ISO_DAY_OF_WEEK      = 20; // u
+    static final int PATTERN_ISO_ZONE             = 21; // X
+    static final int PATTERN_MONTH_STANDALONE     = 22; // L
+    // Android-added: Constant for standalone day of week.
+    static final int PATTERN_STANDALONE_DAY_OF_WEEK = 23; // c
+    // Android-added: Constant for pattern letter 'b', 'B'
+    static final int PATTERN_DAY_PERIOD = 24; // b
+    static final int PATTERN_FLEXIBLE_DAY_PERIOD = 25; // B
+
+    /**
+     * Localized date-time pattern characters. For example, a locale may
+     * wish to use 'u' rather than 'y' to represent years in its date format
+     * pattern strings.
+     * This string must be exactly 18 characters long, with the index of
+     * the characters described by <code>DateFormat.ERA_FIELD</code>,
+     * <code>DateFormat.YEAR_FIELD</code>, etc.  Thus, if the string were
+     * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
+     * @serial
+     */
+    String  localPatternChars = null;
+
+    /**
+     * The locale which is used for initializing this DateFormatSymbols object.
+     *
+     * @since 1.6
+     * @serial
+     */
+    Locale locale = null;
+
+    /* use serialVersionUID from JDK 1.1.4 for interoperability */
+    static final long serialVersionUID = -5987973545549424702L;
+
+    // BEGIN Android-added: Android specific serialization code.
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.4
+    // - 1 Android version that contains a whole bunch of new fields.
+    static final int currentSerialVersion = 1;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <ul>
+     * <li><b>0</b> or not present on stream: JDK 1.1.4.
+     * <li><b>1</b> Android:
+     * </ul>
+     * When streaming out this class, the most recent format
+     * and the highest allowable <code>serialVersionOnStream</code>
+     * is written.
+     * @serial
+     * @since JDK1.1.4
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+    // END Android-added: Android specific serialization code.
+
+    // BEGIN Android-added: Support for tiny and standalone field names.
+    /**
+     * Tiny month strings; "J", "F", "M" etc.
+     *
+     * @serial
+     */
+    private String[] tinyMonths;
+
+    /**
+     * Tiny weekday strings: "M", "F", "W" etc.
+     *
+     * @serial
+     */
+    private String[] tinyWeekdays;
+
+    /**
+     * Standalone month strings; "January", "February", "March" etc.
+     *
+     * @serial
+     */
+    private String[] standAloneMonths;
+
+    /**
+     * Short standalone month strings: "Jan", "Feb", "Mar" etc.
+     *
+     * @serial
+     */
+    private String[] shortStandAloneMonths;
+
+    /**
+     * Tiny standalone month strings: "J", "F", "M" etc.
+     *
+     * @serial
+     */
+    private String[] tinyStandAloneMonths;
+
+    /**
+     * Standalone weekday strings; "Monday", "Tuesday", "Wednesday" etc.
+     *
+     * @serial
+     */
+    private String[] standAloneWeekdays;
+
+    /**
+     * Short standalone weekday strings; "Mon", "Tue", "Wed" etc.
+     *
+     * @serial
+     */
+    private String[] shortStandAloneWeekdays;
+
+    /**
+     * Tiny standalone weekday strings; "M", "T", "W" etc.
+     *
+     * @serial
+     */
+    private String[] tinyStandAloneWeekdays;
+    // END Android-added: Support for tiny and standalone field names.
+
+    // Android-changed: Removed reference to DateFormatSymbolsProvider.
+    /**
+     * Returns an array of all locales for which the
+     * <code>getInstance</code> methods of this class can return
+     * localized instances.
+     *
+     * @return An array of locales for which localized
+     *         <code>DateFormatSymbols</code> instances are available.
+     * @since 1.6
+     */
+    public static Locale[] getAvailableLocales() {
+        // Android-changed: No support for DateFormatSymbolsProvider.
+        return ICU.getAvailableLocales();
+    }
+
+    // Android-changed: Removed reference to DateFormatSymbolsProvider.
+    /**
+     * Gets the <code>DateFormatSymbols</code> instance for the default
+     * locale.
+     * <p>This is equivalent to calling {@link #getInstance(Locale)
+     *     getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @return a <code>DateFormatSymbols</code> instance.
+     * @since 1.6
+     */
+    public static final DateFormatSymbols getInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    // Android-changed: Removed reference to DateFormatSymbolsProvider.
+    /**
+     * Gets the <code>DateFormatSymbols</code> instance for the specified
+     * locale.
+     * @param locale the given locale.
+     * @return a <code>DateFormatSymbols</code> instance.
+     * @exception NullPointerException if <code>locale</code> is null
+     * @since 1.6
+     */
+    public static final DateFormatSymbols getInstance(Locale locale) {
+        // Android-changed: Removed used of DateFormatSymbolsProvider.
+        return (DateFormatSymbols) getCachedInstance(locale).clone();
+    }
+
+    /**
+     * Returns a DateFormatSymbols provided by a provider or found in
+     * the cache. Note that this method returns a cached instance,
+     * not its clone. Therefore, the instance should never be given to
+     * an application.
+     */
+    static final DateFormatSymbols getInstanceRef(Locale locale) {
+        // Android-changed: Removed used of DateFormatSymbolsProvider.
+        return getCachedInstance(locale);
+    }
+
+    // BEGIN Android-changed: Replace getProviderInstance() with getCachedInstance().
+    // Android removed support for DateFormatSymbolsProviders, but still caches DFS.
+    /**
+     * Returns a cached DateFormatSymbols if it's found in the
+     * cache. Otherwise, this method returns a newly cached instance
+     * for the given locale.
+     */
+    private static DateFormatSymbols getCachedInstance(Locale locale) {
+        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+        DateFormatSymbols dfs;
+        if (ref == null || (dfs = ref.get()) == null) {
+            dfs = new DateFormatSymbols(locale);
+            ref = new SoftReference<>(dfs);
+            SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
+            if (x != null) {
+                DateFormatSymbols y = x.get();
+                if (y != null) {
+                    dfs = y;
+                } else {
+                    // Replace the empty SoftReference with ref.
+                    cachedInstances.put(locale, ref);
+                }
+            }
+        }
+        return dfs;
+    }
+    // END Android-changed: Replace getProviderInstance() with getCachedInstance().
+
+    /**
+     * Gets era strings. For example: "AD" and "BC".
+     * @return the era strings.
+     */
+    public String[] getEras() {
+        return Arrays.copyOf(eras, eras.length);
+    }
+
+    /**
+     * Sets era strings. For example: "AD" and "BC".
+     * @param newEras the new era strings.
+     */
+    public void setEras(String[] newEras) {
+        eras = Arrays.copyOf(newEras, newEras.length);
+        cachedHashCode = 0;
+    }
+
+    /**
+     * Gets month strings. For example: "January", "February", etc.
+     *
+     * <p>If the language requires different forms for formatting and
+     * stand-alone usages, this method returns month names in the
+     * formatting form. For example, the preferred month name for
+     * January in the Czech language is <em>ledna</em> in the
+     * formatting form, while it is <em>leden</em> in the stand-alone
+     * form. This method returns {@code "ledna"} in this case. Refer
+     * to the <a href="http://unicode.org/reports/tr35/#Calendar_Elements">
+     * Calendar Elements in the Unicode Locale Data Markup Language
+     * (LDML) specification</a> for more details.
+     *
+     * @return the month strings.
+     */
+    public String[] getMonths() {
+        return Arrays.copyOf(months, months.length);
+    }
+
+    /**
+     * Sets month strings. For example: "January", "February", etc.
+     * @param newMonths the new month strings.
+     */
+    public void setMonths(String[] newMonths) {
+        months = Arrays.copyOf(newMonths, newMonths.length);
+        cachedHashCode = 0;
+    }
+
+    /**
+     * Gets short month strings. For example: "Jan", "Feb", etc.
+     *
+     * <p>If the language requires different forms for formatting and
+     * stand-alone usages, This method returns short month names in
+     * the formatting form. For example, the preferred abbreviation
+     * for January in the Catalan language is <em>de gen.</em> in the
+     * formatting form, while it is <em>gen.</em> in the stand-alone
+     * form. This method returns {@code "de gen."} in this case. Refer
+     * to the <a href="http://unicode.org/reports/tr35/#Calendar_Elements">
+     * Calendar Elements in the Unicode Locale Data Markup Language
+     * (LDML) specification</a> for more details.
+     *
+     * @return the short month strings.
+     */
+    public String[] getShortMonths() {
+        return Arrays.copyOf(shortMonths, shortMonths.length);
+    }
+
+    /**
+     * Sets short month strings. For example: "Jan", "Feb", etc.
+     * @param newShortMonths the new short month strings.
+     */
+    public void setShortMonths(String[] newShortMonths) {
+        shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
+        cachedHashCode = 0;
+    }
+
+    /**
+     * Gets weekday strings. For example: "Sunday", "Monday", etc.
+     * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
+     * <code>Calendar.MONDAY</code>, etc. to index the result array.
+     */
+    public String[] getWeekdays() {
+        return Arrays.copyOf(weekdays, weekdays.length);
+    }
+
+    /**
+     * Sets weekday strings. For example: "Sunday", "Monday", etc.
+     * @param newWeekdays the new weekday strings. The array should
+     * be indexed by <code>Calendar.SUNDAY</code>,
+     * <code>Calendar.MONDAY</code>, etc.
+     */
+    public void setWeekdays(String[] newWeekdays) {
+        weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
+        cachedHashCode = 0;
+    }
+
+    /**
+     * Gets short weekday strings. For example: "Sun", "Mon", etc.
+     * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
+     * <code>Calendar.MONDAY</code>, etc. to index the result array.
+     */
+    public String[] getShortWeekdays() {
+        return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
+    }
+
+    /**
+     * Sets short weekday strings. For example: "Sun", "Mon", etc.
+     * @param newShortWeekdays the new short weekday strings. The array should
+     * be indexed by <code>Calendar.SUNDAY</code>,
+     * <code>Calendar.MONDAY</code>, etc.
+     */
+    public void setShortWeekdays(String[] newShortWeekdays) {
+        shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
+        cachedHashCode = 0;
+    }
+
+    /**
+     * Gets ampm strings. For example: "AM" and "PM".
+     * @return the ampm strings.
+     */
+    public String[] getAmPmStrings() {
+        return Arrays.copyOf(ampms, ampms.length);
+    }
+
+    /**
+     * Sets ampm strings. For example: "AM" and "PM".
+     * @param newAmpms the new ampm strings.
+     */
+    public void setAmPmStrings(String[] newAmpms) {
+        ampms = Arrays.copyOf(newAmpms, newAmpms.length);
+        cachedHashCode = 0;
+    }
+
+    // Android-changed: Removed reference to TimeZoneNameProvider.
+    /**
+     * Gets time zone strings.  Use of this method is discouraged; use
+     * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
+     * instead.
+     * <p>
+     * The value returned is a
+     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
+     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
+     * entry containing the localized names for a single <code>TimeZone</code>.
+     * Each such row contains (with <code>i</code> ranging from
+     * 0..<em>n</em>-1):
+     * <ul>
+     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
+     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
+     * time</li>
+     * <li><code>zoneStrings[i][2]</code> - short name of zone in
+     * standard time</li>
+     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
+     * saving time</li>
+     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
+     * saving time</li>
+     * </ul>
+     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
+     * the {@link java.util.TimeZone TimeZone} class that are not
+     * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
+     * All other entries are localized names.  If a zone does not implement
+     * daylight saving time, the daylight saving time names should not be used.
+     * <p>
+     * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
+     * on this <code>DateFormatSymbols</code> instance, then the strings
+     * provided by that call are returned. Otherwise, the returned array
+     * contains names provided by the runtime.
+     *
+     * @return the time zone strings.
+     * @see #setZoneStrings(String[][])
+     */
+    public String[][] getZoneStrings() {
+        return getZoneStringsImpl(true);
+    }
+
+    /**
+     * Sets time zone strings.  The argument must be a
+     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
+     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
+     * entry containing the localized names for a single <code>TimeZone</code>.
+     * Each such row contains (with <code>i</code> ranging from
+     * 0..<em>n</em>-1):
+     * <ul>
+     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
+     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
+     * time</li>
+     * <li><code>zoneStrings[i][2]</code> - short name of zone in
+     * standard time</li>
+     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
+     * saving time</li>
+     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
+     * saving time</li>
+     * </ul>
+     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
+     * the {@link java.util.TimeZone TimeZone} class that are not
+     * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
+     * All other entries are localized names.
+     *
+     * @param newZoneStrings the new time zone strings.
+     * @exception IllegalArgumentException if the length of any row in
+     *    <code>newZoneStrings</code> is less than 5
+     * @exception NullPointerException if <code>newZoneStrings</code> is null
+     * @see #getZoneStrings()
+     */
+    public void setZoneStrings(String[][] newZoneStrings) {
+        String[][] aCopy = new String[newZoneStrings.length][];
+        for (int i = 0; i < newZoneStrings.length; ++i) {
+            int len = newZoneStrings[i].length;
+            if (len < 5) {
+                throw new IllegalArgumentException();
+            }
+            aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
+        }
+        zoneStrings = aCopy;
+        isZoneStringsSet = true;
+        // Android-changed: don't include zone strings in hashCode to avoid populating it.
+        // cachedHashCode = 0;
+    }
+
+    /**
+     * Gets localized date-time pattern characters. For example: 'u', 't', etc.
+     * @return the localized date-time pattern characters.
+     */
+    public String getLocalPatternChars() {
+        return localPatternChars;
+    }
+
+    /**
+     * Sets localized date-time pattern characters. For example: 'u', 't', etc.
+     * @param newLocalPatternChars the new localized date-time
+     * pattern characters.
+     */
+    public void setLocalPatternChars(String newLocalPatternChars) {
+        // Call toString() to throw an NPE in case the argument is null
+        localPatternChars = newLocalPatternChars.toString();
+        cachedHashCode = 0;
+    }
+
+    // BEGIN Android-added: Support for tiny and standalone field names.
+    String[] getTinyMonths() {
+        return tinyMonths;
+    }
+
+    String[] getStandAloneMonths() {
+        return standAloneMonths;
+    }
+
+    String[] getShortStandAloneMonths() {
+        return shortStandAloneMonths;
+    }
+
+    String[] getTinyStandAloneMonths() {
+        return tinyStandAloneMonths;
+    }
+
+    String[] getTinyWeekdays() {
+        return tinyWeekdays;
+    }
+
+    String[] getStandAloneWeekdays() {
+        return standAloneWeekdays;
+    }
+
+    String[] getShortStandAloneWeekdays() {
+        return shortStandAloneWeekdays;
+    }
+
+    String[] getTinyStandAloneWeekdays() {
+        return tinyStandAloneWeekdays;
+    }
+    // END Android-added: Support for tiny and standalone field names.
+
+    /**
+     * Overrides Cloneable
+     */
+    public Object clone()
+    {
+        try
+        {
+            DateFormatSymbols other = (DateFormatSymbols)super.clone();
+            copyMembers(this, other);
+            return other;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Override hashCode.
+     * Generates a hash code for the DateFormatSymbols object.
+     */
+    @Override
+    public int hashCode() {
+        int hashCode = cachedHashCode;
+        if (hashCode == 0) {
+            hashCode = 5;
+            hashCode = 11 * hashCode + Arrays.hashCode(eras);
+            hashCode = 11 * hashCode + Arrays.hashCode(months);
+            hashCode = 11 * hashCode + Arrays.hashCode(shortMonths);
+            hashCode = 11 * hashCode + Arrays.hashCode(weekdays);
+            hashCode = 11 * hashCode + Arrays.hashCode(shortWeekdays);
+            hashCode = 11 * hashCode + Arrays.hashCode(ampms);
+            // Android-changed: Don't include zone strings in hashCode to avoid populating it.
+            // hashCode = 11 * hashCode + Arrays.deepHashCode(getZoneStringsWrapper());
+            hashCode = 11 * hashCode + Objects.hashCode(localPatternChars);
+            cachedHashCode = hashCode;
+        }
+
+        return hashCode;
+    }
+
+    /**
+     * Override equals
+     */
+    public boolean equals(Object obj)
+    {
+        if (this == obj) return true;
+        if (obj == null || getClass() != obj.getClass()) return false;
+        DateFormatSymbols that = (DateFormatSymbols) obj;
+        // BEGIN Android-changed: Avoid populating zoneStrings just for the comparison, add fields.
+        if (!(Arrays.equals(eras, that.eras)
+                && Arrays.equals(months, that.months)
+                && Arrays.equals(shortMonths, that.shortMonths)
+                && Arrays.equals(tinyMonths, that.tinyMonths)
+                && Arrays.equals(weekdays, that.weekdays)
+                && Arrays.equals(shortWeekdays, that.shortWeekdays)
+                && Arrays.equals(tinyWeekdays, that.tinyWeekdays)
+                && Arrays.equals(standAloneMonths, that.standAloneMonths)
+                && Arrays.equals(shortStandAloneMonths, that.shortStandAloneMonths)
+                && Arrays.equals(tinyStandAloneMonths, that.tinyStandAloneMonths)
+                && Arrays.equals(standAloneWeekdays, that.standAloneWeekdays)
+                && Arrays.equals(shortStandAloneWeekdays, that.shortStandAloneWeekdays)
+                && Arrays.equals(tinyStandAloneWeekdays, that.tinyStandAloneWeekdays)
+                && Arrays.equals(ampms, that.ampms)
+                && ((localPatternChars != null
+                  && localPatternChars.equals(that.localPatternChars))
+                 || (localPatternChars == null
+                  && that.localPatternChars == null)))) {
+            return false;
+        }
+        if (!isZoneStringsSet && !that.isZoneStringsSet && Objects.equals(locale, that.locale)) {
+            return true;
+        }
+        return Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper());
+        // END Android-changed: Avoid populating zoneStrings just for the comparison, add fields.
+    }
+
+    // =======================privates===============================
+
+    /**
+     * Useful constant for defining time zone offsets.
+     */
+    static final int millisPerHour = 60*60*1000;
+
+    /**
+     * Cache to hold DateFormatSymbols instances per Locale.
+     */
+    private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
+        = new ConcurrentHashMap<>(3);
+
+    private transient int lastZoneIndex = 0;
+
+    /**
+     * Cached hash code
+     */
+    transient volatile int cachedHashCode = 0;
+
+    // Android-changed: update comment to describe local modification.
+    /**
+     * Initializes this DateFormatSymbols with the locale data. This method uses
+     * a cached DateFormatSymbols instance for the given locale if available. If
+     * there's no cached one, this method populates this objects fields from an
+     * appropriate LocaleData object. Note: zoneStrings isn't initialized in this method.
+     */
+    private void initializeData(Locale locale) {
+        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+        DateFormatSymbols dfs;
+        // Android-changed: invert cache presence check to simplify code flow.
+        if (ref != null && (dfs = ref.get()) != null) {
+            copyMembers(dfs, this);
+            return;
+        }
+
+        // BEGIN Android-changed: Use ICU data and move cache handling to getCachedInstance().
+        locale = LocaleData.mapInvalidAndNullLocales(locale);
+        LocaleData localeData = LocaleData.get(locale);
+
+        this.locale = locale;
+        eras = localeData.eras;
+        months = localeData.longMonthNames;
+        shortMonths = localeData.shortMonthNames;
+        ampms = localeData.amPm;
+        localPatternChars = patternChars;
+
+        weekdays = localeData.longWeekdayNames;
+        shortWeekdays = localeData.shortWeekdayNames;
+
+        initializeSupplementaryData(localeData);
+        // END Android-changed: Use ICU data and move cache handling to getCachedInstance().
+    }
+
+    // Android-removed: toOneBasedArray(String[])
+
+    // BEGIN Android-added: initializeSupplementaryData(LocaleData) for tiny and standalone fields.
+    private void initializeSupplementaryData(LocaleData localeData) {
+        // Tiny weekdays and months.
+        tinyMonths = localeData.tinyMonthNames;
+        tinyWeekdays = localeData.tinyWeekdayNames;
+
+        // Standalone month names.
+        standAloneMonths = localeData.longStandAloneMonthNames;
+        shortStandAloneMonths = localeData.shortStandAloneMonthNames;
+        tinyStandAloneMonths = localeData.tinyStandAloneMonthNames;
+
+        // Standalone weekdays.
+        standAloneWeekdays = localeData.longStandAloneWeekdayNames;
+        shortStandAloneWeekdays = localeData.shortStandAloneWeekdayNames;
+        tinyStandAloneWeekdays = localeData.tinyStandAloneWeekdayNames;
+    }
+    // END Android-added: initializeSupplementaryData(LocaleData) for tiny and standalone fields.
+
+    /**
+     * Package private: used by SimpleDateFormat
+     * Gets the index for the given time zone ID to obtain the time zone
+     * strings for formatting. The time zone ID is just for programmatic
+     * lookup. NOT LOCALIZED!!!
+     * @param ID the given time zone ID.
+     * @return the index of the given time zone ID.  Returns -1 if
+     * the given time zone ID can't be located in the DateFormatSymbols object.
+     * @see java.util.SimpleTimeZone
+     */
+    final int getZoneIndex(String ID) {
+        String[][] zoneStrings = getZoneStringsWrapper();
+
+        /*
+         * getZoneIndex has been re-written for performance reasons. instead of
+         * traversing the zoneStrings array every time, we cache the last used zone
+         * index
+         */
+        if (lastZoneIndex < zoneStrings.length && ID.equals(zoneStrings[lastZoneIndex][0])) {
+            return lastZoneIndex;
+        }
+
+        /* slow path, search entire list */
+        for (int index = 0; index < zoneStrings.length; index++) {
+            if (ID.equals(zoneStrings[index][0])) {
+                lastZoneIndex = index;
+                return index;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Wrapper method to the getZoneStrings(), which is called from inside
+     * the java.text package and not to mutate the returned arrays, so that
+     * it does not need to create a defensive copy.
+     */
+    final String[][] getZoneStringsWrapper() {
+        if (isSubclassObject()) {
+            return getZoneStrings();
+        } else {
+            return getZoneStringsImpl(false);
+        }
+    }
+
+    // BEGIN Android-changed: extract initialization of zoneStrings to separate method.
+    private synchronized String[][] internalZoneStrings() {
+        if (zoneStrings == null) {
+            zoneStrings = TimeZoneNames.getZoneStrings(locale);
+        }
+        return zoneStrings;
+    }
+
+    private String[][] getZoneStringsImpl(boolean needsCopy) {
+        String[][] zoneStrings = internalZoneStrings();
+        // END Android-changed: extract initialization of zoneStrings to separate method.
+
+        if (!needsCopy) {
+            return zoneStrings;
+        }
+
+        int len = zoneStrings.length;
+        String[][] aCopy = new String[len][];
+        for (int i = 0; i < len; i++) {
+            aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
+        }
+        return aCopy;
+    }
+
+    private boolean isSubclassObject() {
+        return !getClass().getName().equals("java.text.DateFormatSymbols");
+    }
+
+    /**
+     * Clones all the data members from the source DateFormatSymbols to
+     * the target DateFormatSymbols.
+     *
+     * @param src the source DateFormatSymbols.
+     * @param dst the target DateFormatSymbols.
+     */
+    private void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
+    {
+        dst.locale = src.locale;
+        dst.eras = Arrays.copyOf(src.eras, src.eras.length);
+        dst.months = Arrays.copyOf(src.months, src.months.length);
+        dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
+        dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
+        dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
+        dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
+        if (src.zoneStrings != null) {
+            dst.zoneStrings = src.getZoneStringsImpl(true);
+        } else {
+            dst.zoneStrings = null;
+        }
+        dst.localPatternChars = src.localPatternChars;
+        dst.cachedHashCode = 0;
+
+        // BEGIN Android-added: Support for tiny and standalone field names.
+        dst.tinyMonths = src.tinyMonths;
+        dst.tinyWeekdays = src.tinyWeekdays;
+
+        dst.standAloneMonths = src.standAloneMonths;
+        dst.shortStandAloneMonths = src.shortStandAloneMonths;
+        dst.tinyStandAloneMonths = src.tinyStandAloneMonths;
+
+        dst.standAloneWeekdays = src.standAloneWeekdays;
+        dst.shortStandAloneWeekdays = src.shortStandAloneWeekdays;
+        dst.tinyStandAloneWeekdays = src.tinyStandAloneWeekdays;
+        // END Android-added: Support for tiny and standalone field names.
+    }
+
+    // BEGIN Android-added: support reading non-Android serialized DFS.
+    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+
+        if (serialVersionOnStream < 1) {
+            LocaleData localeData = LocaleData.get(locale);
+            initializeSupplementaryData(localeData);
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+    }
+    // END Android-added: support reading non-Android serialized DFS.
+
+    /**
+     * Write out the default serializable data, after ensuring the
+     * <code>zoneStrings</code> field is initialized in order to make
+     * sure the backward compatibility.
+     *
+     * @since 1.6
+     */
+    private void writeObject(ObjectOutputStream stream) throws IOException {
+        // Android-changed: extract initialization of zoneStrings to separate method.
+        internalZoneStrings();
+        stream.defaultWriteObject();
+    }
+}
diff --git a/java/text/DecimalFormat.java b/java/text/DecimalFormat.java
new file mode 100644
index 0000000..a2a37b1
--- /dev/null
+++ b/java/text/DecimalFormat.java
@@ -0,0 +1,4898 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import android.icu.impl.number.DecimalFormatProperties.ParseMode;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import libcore.icu.LocaleData;
+import android.icu.math.MathContext;
+
+/**
+ * <code>DecimalFormat</code> is a concrete subclass of
+ * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
+ * features designed to make it possible to parse and format numbers in any
+ * locale, including support for Western, Arabic, and Indic digits.  It also
+ * supports different kinds of numbers, including integers (123), fixed-point
+ * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
+ * currency amounts ($123).  All of these can be localized.
+ *
+ * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
+ * default locale, call one of <code>NumberFormat</code>'s factory methods, such
+ * as <code>getInstance()</code>.  In general, do not call the
+ * <code>DecimalFormat</code> constructors directly, since the
+ * <code>NumberFormat</code> factory methods may return subclasses other than
+ * <code>DecimalFormat</code>. If you need to customize the format object, do
+ * something like this:
+ *
+ * <blockquote><pre>
+ * NumberFormat f = NumberFormat.getInstance(loc);
+ * if (f instanceof DecimalFormat) {
+ *     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
+ * }
+ * </pre></blockquote>
+ *
+ * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
+ * <em>symbols</em>.  The pattern may be set directly using
+ * <code>applyPattern()</code>, or indirectly using the API methods.  The
+ * symbols are stored in a <code>DecimalFormatSymbols</code> object.  When using
+ * the <code>NumberFormat</code> factory methods, the pattern and symbols are
+ * read from localized <code>ResourceBundle</code>s.
+ *
+ * <h3>Patterns</h3>
+ *
+ * <code>DecimalFormat</code> patterns have the following syntax:
+ * <blockquote><pre>
+ * <i>Pattern:</i>
+ *         <i>PositivePattern</i>
+ *         <i>PositivePattern</i> ; <i>NegativePattern</i>
+ * <i>PositivePattern:</i>
+ *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
+ * <i>NegativePattern:</i>
+ *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
+ * <i>Prefix:</i>
+ *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
+ * <i>Suffix:</i>
+ *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
+ * <i>Number:</i>
+ *         <i>Integer</i> <i>Exponent<sub>opt</sub></i>
+ *         <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
+ * <i>Integer:</i>
+ *         <i>MinimumInteger</i>
+ *         #
+ *         # <i>Integer</i>
+ *         # , <i>Integer</i>
+ * <i>MinimumInteger:</i>
+ *         0
+ *         0 <i>MinimumInteger</i>
+ *         0 , <i>MinimumInteger</i>
+ * <i>Fraction:</i>
+ *         <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
+ * <i>MinimumFraction:</i>
+ *         0 <i>MinimumFraction<sub>opt</sub></i>
+ * <i>OptionalFraction:</i>
+ *         # <i>OptionalFraction<sub>opt</sub></i>
+ * <i>Exponent:</i>
+ *         E <i>MinimumExponent</i>
+ * <i>MinimumExponent:</i>
+ *         0 <i>MinimumExponent<sub>opt</sub></i>
+ * </pre></blockquote>
+ *
+ * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
+ * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>.  Each
+ * subpattern has a prefix, numeric part, and suffix. The negative subpattern
+ * is optional; if absent, then the positive subpattern prefixed with the
+ * localized minus sign (<code>'-'</code> in most locales) is used as the
+ * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
+ * <code>"0.00;-0.00"</code>.  If there is an explicit negative subpattern, it
+ * serves only to specify the negative prefix and suffix; the number of digits,
+ * minimal digits, and other characteristics are all the same as the positive
+ * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
+ * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
+ *
+ * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
+ * thousands separators, decimal separators, etc. may be set to arbitrary
+ * values, and they will appear properly during formatting.  However, care must
+ * be taken that the symbols and strings do not conflict, or parsing will be
+ * unreliable.  For example, either the positive and negative prefixes or the
+ * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
+ * to distinguish positive from negative values.  (If they are identical, then
+ * <code>DecimalFormat</code> will behave as if no negative subpattern was
+ * specified.)  Another example is that the decimal separator and thousands
+ * separator should be distinct characters, or parsing will be impossible.
+ *
+ * <p>The grouping separator is commonly used for thousands, but in some
+ * countries it separates ten-thousands. The grouping size is a constant number
+ * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
+ * 1,0000,0000.  If you supply a pattern with multiple grouping characters, the
+ * interval between the last one and the end of the integer is the one that is
+ * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
+ * <code>"##,####,####"</code>.
+ *
+ * <h4>Special Pattern Characters</h4>
+ *
+ * <p>Many characters in a pattern are taken literally; they are matched during
+ * parsing and output unchanged during formatting.  Special characters, on the
+ * other hand, stand for other characters, strings, or classes of characters.
+ * They must be quoted, unless noted otherwise, if they are to appear in the
+ * prefix or suffix as literals.
+ *
+ * <p>The characters listed here are used in non-localized patterns.  Localized
+ * patterns use the corresponding characters taken from this formatter's
+ * <code>DecimalFormatSymbols</code> object instead, and these characters lose
+ * their special status.  Two exceptions are the currency sign and quote, which
+ * are not localized.
+ *
+ * <blockquote>
+ * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
+ *  location, localized, and meaning.">
+ *     <tr style="background-color: rgb(204, 204, 255);">
+ *          <th align=left>Symbol
+ *          <th align=left>Location
+ *          <th align=left>Localized?
+ *          <th align=left>Meaning
+ *     <tr valign=top>
+ *          <td><code>0</code>
+ *          <td>Number
+ *          <td>Yes
+ *          <td>Digit
+ *     <tr style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *          <td><code>#</code>
+ *          <td>Number
+ *          <td>Yes
+ *          <td>Digit, zero shows as absent
+ *     <tr valign=top>
+ *          <td><code>.</code>
+ *          <td>Number
+ *          <td>Yes
+ *          <td>Decimal separator or monetary decimal separator
+ *     <tr style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *          <td><code>-</code>
+ *          <td>Number
+ *          <td>Yes
+ *          <td>Minus sign
+ *     <tr valign=top>
+ *          <td><code>,</code>
+ *          <td>Number
+ *          <td>Yes
+ *          <td>Grouping separator
+ *     <tr style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *          <td><code>E</code>
+ *          <td>Number
+ *          <td>Yes
+ *          <td>Separates mantissa and exponent in scientific notation.
+ *              <em>Need not be quoted in prefix or suffix.</em>
+ *     <tr valign=top>
+ *          <td><code>;</code>
+ *          <td>Subpattern boundary
+ *          <td>Yes
+ *          <td>Separates positive and negative subpatterns
+ *     <tr style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *          <td><code>%</code>
+ *          <td>Prefix or suffix
+ *          <td>Yes
+ *          <td>Multiply by 100 and show as percentage
+ *     <tr valign=top>
+ *          <td><code>&#92;u2030</code>
+ *          <td>Prefix or suffix
+ *          <td>Yes
+ *          <td>Multiply by 1000 and show as per mille value
+ *     <tr style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *          <td><code>&#164;</code> (<code>&#92;u00A4</code>)
+ *          <td>Prefix or suffix
+ *          <td>No
+ *          <td>Currency sign, replaced by currency symbol.  If
+ *              doubled, replaced by international currency symbol.
+ *              If present in a pattern, the monetary decimal separator
+ *              is used instead of the decimal separator.
+ *     <tr valign=top>
+ *          <td><code>'</code>
+ *          <td>Prefix or suffix
+ *          <td>No
+ *          <td>Used to quote special characters in a prefix or suffix,
+ *              for example, <code>"'#'#"</code> formats 123 to
+ *              <code>"#123"</code>.  To create a single quote
+ *              itself, use two in a row: <code>"# o''clock"</code>.
+ * </table>
+ * </blockquote>
+ *
+ * <h4>Scientific Notation</h4>
+ *
+ * <p>Numbers in scientific notation are expressed as the product of a mantissa
+ * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3.  The
+ * mantissa is often in the range 1.0 &le; x {@literal <} 10.0, but it need not
+ * be.
+ * <code>DecimalFormat</code> can be instructed to format and parse scientific
+ * notation <em>only via a pattern</em>; there is currently no factory method
+ * that creates a scientific notation format.  In a pattern, the exponent
+ * character immediately followed by one or more digit characters indicates
+ * scientific notation.  Example: <code>"0.###E0"</code> formats the number
+ * 1234 as <code>"1.234E3"</code>.
+ *
+ * <ul>
+ * <li>The number of digit characters after the exponent character gives the
+ * minimum exponent digit count.  There is no maximum.  Negative exponents are
+ * formatted using the localized minus sign, <em>not</em> the prefix and suffix
+ * from the pattern.  This allows patterns such as <code>"0.###E0 m/s"</code>.
+ *
+ * <li>The minimum and maximum number of integer digits are interpreted
+ * together:
+ *
+ * <ul>
+ * <li>If the maximum number of integer digits is greater than their minimum number
+ * and greater than 1, it forces the exponent to be a multiple of the maximum
+ * number of integer digits, and the minimum number of integer digits to be
+ * interpreted as 1.  The most common use of this is to generate
+ * <em>engineering notation</em>, in which the exponent is a multiple of three,
+ * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
+ * formats to <code>"12.345E3"</code>, and 123456 formats to
+ * <code>"123.456E3"</code>.
+ *
+ * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
+ * exponent.  Example: 0.00123 formatted with <code>"00.###E0"</code> yields
+ * <code>"12.3E-4"</code>.
+ * </ul>
+ *
+ * <li>The number of significant digits in the mantissa is the sum of the
+ * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
+ * unaffected by the maximum integer digits.  For example, 12345 formatted with
+ * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
+ * the significant digits count to zero.  The number of significant digits
+ * does not affect parsing.
+ *
+ * <li>Exponential patterns may not contain grouping separators.
+ * </ul>
+ *
+ * <h4>Rounding</h4>
+ *
+ * <code>DecimalFormat</code> provides rounding modes defined in
+ * {@link java.math.RoundingMode} for formatting.  By default, it uses
+ * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
+ *
+ * <h4>Digits</h4>
+ *
+ * For formatting, <code>DecimalFormat</code> uses the ten consecutive
+ * characters starting with the localized zero digit defined in the
+ * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
+ * digits as well as all Unicode decimal digits, as defined by
+ * {@link Character#digit Character.digit}, are recognized.
+ *
+ * <h4>Special Values</h4>
+ *
+ * <p><code>NaN</code> is formatted as a string, which typically has a single character
+ * <code>&#92;uFFFD</code>.  This string is determined by the
+ * <code>DecimalFormatSymbols</code> object.  This is the only value for which
+ * the prefixes and suffixes are not used.
+ *
+ * <p>Infinity is formatted as a string, which typically has a single character
+ * <code>&#92;u221E</code>, with the positive or negative prefixes and suffixes
+ * applied.  The infinity string is determined by the
+ * <code>DecimalFormatSymbols</code> object.
+ *
+ * <p>Negative zero (<code>"-0"</code>) parses to
+ * <ul>
+ * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
+ * true,
+ * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
+ *     and <code>isParseIntegerOnly()</code> is true,
+ * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
+ * and <code>isParseIntegerOnly()</code> are false.
+ * </ul>
+ *
+ * <h4><a name="synchronization">Synchronization</a></h4>
+ *
+ * <p>
+ * Decimal formats are generally not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * <h4>Example</h4>
+ *
+ * <blockquote><pre>{@code
+ * <strong>// Print out a number using the localized number, integer, currency,
+ * // and percent format for each locale</strong>
+ * Locale[] locales = NumberFormat.getAvailableLocales();
+ * double myNumber = -1234.56;
+ * NumberFormat form;
+ * for (int j = 0; j < 4; ++j) {
+ *     System.out.println("FORMAT");
+ *     for (int i = 0; i < locales.length; ++i) {
+ *         if (locales[i].getCountry().length() == 0) {
+ *            continue; // Skip language-only locales
+ *         }
+ *         System.out.print(locales[i].getDisplayName());
+ *         switch (j) {
+ *         case 0:
+ *             form = NumberFormat.getInstance(locales[i]); break;
+ *         case 1:
+ *             form = NumberFormat.getIntegerInstance(locales[i]); break;
+ *         case 2:
+ *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
+ *         default:
+ *             form = NumberFormat.getPercentInstance(locales[i]); break;
+ *         }
+ *         if (form instanceof DecimalFormat) {
+ *             System.out.print(": " + ((DecimalFormat) form).toPattern());
+ *         }
+ *         System.out.print(" -> " + form.format(myNumber));
+ *         try {
+ *             System.out.println(" -> " + form.parse(form.format(myNumber)));
+ *         } catch (ParseException e) {}
+ *     }
+ * }
+ * }</pre></blockquote>
+ *
+ * @see          <a href="https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
+ * @see          NumberFormat
+ * @see          DecimalFormatSymbols
+ * @see          ParsePosition
+ * @author       Mark Davis
+ * @author       Alan Liu
+ */
+public class DecimalFormat extends NumberFormat {
+
+    // Android-note: This class is heavily modified from upstream OpenJDK.
+    // Android's version delegates most of its work to android.icu.text.DecimalFormat. This is done
+    // to avoid code duplication and to stay compatible with earlier releases that used ICU4C/ICU4J
+    // to implement DecimalFormat.
+
+    // Android-added: ICU DecimalFormat to delegate to.
+    private transient android.icu.text.DecimalFormat icuDecimalFormat;
+
+    /**
+     * Creates a DecimalFormat using the default pattern and symbols
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * This is a convenient way to obtain a
+     * DecimalFormat when internationalization is not the main concern.
+     * <p>
+     * To obtain standard formats for a given locale, use the factory methods
+     * on NumberFormat such as getNumberInstance. These factories will
+     * return the most appropriate sub-class of NumberFormat for a given
+     * locale.
+     *
+     * @see java.text.NumberFormat#getInstance
+     * @see java.text.NumberFormat#getNumberInstance
+     * @see java.text.NumberFormat#getCurrencyInstance
+     * @see java.text.NumberFormat#getPercentInstance
+     */
+    public DecimalFormat() {
+        // Get the pattern for the default locale.
+        Locale def = Locale.getDefault(Locale.Category.FORMAT);
+        // BEGIN Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter.
+        /*
+        LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def);
+        if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+            adapter = LocaleProviderAdapter.getResourceBundleBased();
+        }
+        String[] all = adapter.getLocaleResources(def).getNumberPatterns();
+        */
+        String pattern = LocaleData.get(def).numberPattern;
+        // END Android-changed: Use ICU LocaleData. Remove SPI LocaleProviderAdapter.
+
+        // Always applyPattern after the symbols are set
+        this.symbols = DecimalFormatSymbols.getInstance(def);
+        // Android-changed: initPattern() and conversion methods between ICU and Java values.
+        // applyPattern(all[0], false);
+        initPattern(pattern);
+    }
+
+
+    /**
+     * Creates a DecimalFormat using the given pattern and the symbols
+     * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * This is a convenient way to obtain a
+     * DecimalFormat when internationalization is not the main concern.
+     * <p>
+     * To obtain standard formats for a given locale, use the factory methods
+     * on NumberFormat such as getNumberInstance. These factories will
+     * return the most appropriate sub-class of NumberFormat for a given
+     * locale.
+     *
+     * @param pattern a non-localized pattern string.
+     * @exception NullPointerException if <code>pattern</code> is null
+     * @exception IllegalArgumentException if the given pattern is invalid.
+     * @see java.text.NumberFormat#getInstance
+     * @see java.text.NumberFormat#getNumberInstance
+     * @see java.text.NumberFormat#getCurrencyInstance
+     * @see java.text.NumberFormat#getPercentInstance
+     */
+    public DecimalFormat(String pattern) {
+        // Always applyPattern after the symbols are set
+        this.symbols = DecimalFormatSymbols.getInstance(Locale.getDefault(Locale.Category.FORMAT));
+        // Android-changed: initPattern() and conversion methods between ICU and Java values.
+        // applyPattern(pattern, false);
+        initPattern(pattern);
+    }
+
+
+    /**
+     * Creates a DecimalFormat using the given pattern and symbols.
+     * Use this constructor when you need to completely customize the
+     * behavior of the format.
+     * <p>
+     * To obtain standard formats for a given
+     * locale, use the factory methods on NumberFormat such as
+     * getInstance or getCurrencyInstance. If you need only minor adjustments
+     * to a standard format, you can modify the format returned by
+     * a NumberFormat factory method.
+     *
+     * @param pattern a non-localized pattern string
+     * @param symbols the set of symbols to be used
+     * @exception NullPointerException if any of the given arguments is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     * @see java.text.NumberFormat#getInstance
+     * @see java.text.NumberFormat#getNumberInstance
+     * @see java.text.NumberFormat#getCurrencyInstance
+     * @see java.text.NumberFormat#getPercentInstance
+     * @see java.text.DecimalFormatSymbols
+     */
+    public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
+        // Always applyPattern after the symbols are set
+        this.symbols = (DecimalFormatSymbols)symbols.clone();
+        // Android-changed: initPattern() and conversion methods between ICU and Java values.
+        initPattern(pattern);
+    }
+
+    // BEGIN Android-added: initPattern() and conversion methods between ICU and Java values.
+    /**
+     * Applies the pattern similarly to {@link #applyPattern(String)}, except it initializes
+     * {@link #icuDecimalFormat} in the process. This should only be called from constructors.
+     */
+    private void initPattern(String pattern) {
+        this.icuDecimalFormat =  new android.icu.text.DecimalFormat(pattern,
+                symbols.getIcuDecimalFormatSymbols());
+        // Android-changed: Compatibility mode for j.t.DecimalFormat. http://b/112355520
+        icuDecimalFormat.setParseStrictMode(ParseMode.JAVA_COMPATIBILITY);
+        updateFieldsFromIcu();
+    }
+
+    /**
+     * Update local fields indicating maximum/minimum integer/fraction digit count from the ICU
+     * DecimalFormat. This needs to be called whenever a new pattern is applied.
+     */
+    private void updateFieldsFromIcu() {
+        // Imitate behaviour of ICU4C NumberFormat that Android used up to M.
+        // If the pattern doesn't enforce a different value (some exponential
+        // patterns do), then set the maximum integer digits to 2 billion.
+        if (icuDecimalFormat.getMaximumIntegerDigits() == DOUBLE_INTEGER_DIGITS) {
+            icuDecimalFormat.setMaximumIntegerDigits(2000000000);
+        }
+        maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits();
+        minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits();
+        maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits();
+        minimumFractionDigits = icuDecimalFormat.getMinimumFractionDigits();
+    }
+
+    /**
+     * Converts between field positions used by Java/ICU.
+     * @param fp The java.text.NumberFormat.Field field position
+     * @return The android.icu.text.NumberFormat.Field field position
+     */
+    private static FieldPosition getIcuFieldPosition(FieldPosition fp) {
+        Format.Field fieldAttribute = fp.getFieldAttribute();
+        if (fieldAttribute == null) return fp;
+
+        android.icu.text.NumberFormat.Field attribute;
+        if (fieldAttribute == Field.INTEGER) {
+            attribute = android.icu.text.NumberFormat.Field.INTEGER;
+        } else if (fieldAttribute == Field.FRACTION) {
+            attribute = android.icu.text.NumberFormat.Field.FRACTION;
+        } else if (fieldAttribute == Field.DECIMAL_SEPARATOR) {
+            attribute = android.icu.text.NumberFormat.Field.DECIMAL_SEPARATOR;
+        } else if (fieldAttribute == Field.EXPONENT_SYMBOL) {
+            attribute = android.icu.text.NumberFormat.Field.EXPONENT_SYMBOL;
+        } else if (fieldAttribute == Field.EXPONENT_SIGN) {
+            attribute = android.icu.text.NumberFormat.Field.EXPONENT_SIGN;
+        } else if (fieldAttribute == Field.EXPONENT) {
+            attribute = android.icu.text.NumberFormat.Field.EXPONENT;
+        } else if (fieldAttribute == Field.GROUPING_SEPARATOR) {
+            attribute = android.icu.text.NumberFormat.Field.GROUPING_SEPARATOR;
+        } else if (fieldAttribute == Field.CURRENCY) {
+            attribute = android.icu.text.NumberFormat.Field.CURRENCY;
+        } else if (fieldAttribute == Field.PERCENT) {
+            attribute = android.icu.text.NumberFormat.Field.PERCENT;
+        } else if (fieldAttribute == Field.PERMILLE) {
+            attribute = android.icu.text.NumberFormat.Field.PERMILLE;
+        } else if (fieldAttribute == Field.SIGN) {
+            attribute = android.icu.text.NumberFormat.Field.SIGN;
+        } else {
+            throw new IllegalArgumentException("Unexpected field position attribute type.");
+        }
+
+        FieldPosition icuFieldPosition = new FieldPosition(attribute);
+        icuFieldPosition.setBeginIndex(fp.getBeginIndex());
+        icuFieldPosition.setEndIndex(fp.getEndIndex());
+        return icuFieldPosition;
+    }
+
+    /**
+     * Converts the Attribute that ICU returns in its AttributedCharacterIterator
+     * responses to the type that java uses.
+     * @param icuAttribute The AttributedCharacterIterator.Attribute field.
+     * @return Field converted to a java.text.NumberFormat.Field field.
+     */
+    private static Field toJavaFieldAttribute(AttributedCharacterIterator.Attribute icuAttribute) {
+        String name = icuAttribute.getName();
+        if (name.equals(Field.INTEGER.getName())) {
+            return Field.INTEGER;
+        }
+        if (name.equals(Field.CURRENCY.getName())) {
+            return Field.CURRENCY;
+        }
+        if (name.equals(Field.DECIMAL_SEPARATOR.getName())) {
+            return Field.DECIMAL_SEPARATOR;
+        }
+        if (name.equals(Field.EXPONENT.getName())) {
+            return Field.EXPONENT;
+        }
+        if (name.equals(Field.EXPONENT_SIGN.getName())) {
+            return Field.EXPONENT_SIGN;
+        }
+        if (name.equals(Field.EXPONENT_SYMBOL.getName())) {
+            return Field.EXPONENT_SYMBOL;
+        }
+        if (name.equals(Field.FRACTION.getName())) {
+            return Field.FRACTION;
+        }
+        if (name.equals(Field.GROUPING_SEPARATOR.getName())) {
+            return Field.GROUPING_SEPARATOR;
+        }
+        if (name.equals(Field.SIGN.getName())) {
+            return Field.SIGN;
+        }
+        if (name.equals(Field.PERCENT.getName())) {
+            return Field.PERCENT;
+        }
+        if (name.equals(Field.PERMILLE.getName())) {
+            return Field.PERMILLE;
+        }
+        throw new IllegalArgumentException("Unrecognized attribute: " + name);
+    }
+    // END Android-added: initPattern() and conversion methods between ICU and Java values.
+
+    // Overrides
+    /**
+     * Formats a number and appends the resulting text to the given string
+     * buffer.
+     * The number can be of any subclass of {@link java.lang.Number}.
+     * <p>
+     * This implementation uses the maximum precision permitted.
+     * @param number     the number to format
+     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
+     *                   text is to be appended
+     * @param pos        On input: an alignment field, if desired.
+     *                   On output: the offsets of the alignment field.
+     * @return           the value passed in as <code>toAppendTo</code>
+     * @exception        IllegalArgumentException if <code>number</code> is
+     *                   null or not an instance of <code>Number</code>.
+     * @exception        NullPointerException if <code>toAppendTo</code> or
+     *                   <code>pos</code> is null
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see              java.text.FieldPosition
+     */
+    @Override
+    public final StringBuffer format(Object number,
+                                     StringBuffer toAppendTo,
+                                     FieldPosition pos) {
+        if (number instanceof Long || number instanceof Integer ||
+                   number instanceof Short || number instanceof Byte ||
+                   number instanceof AtomicInteger ||
+                   number instanceof AtomicLong ||
+                   (number instanceof BigInteger &&
+                    ((BigInteger)number).bitLength () < 64)) {
+            return format(((Number)number).longValue(), toAppendTo, pos);
+        } else if (number instanceof BigDecimal) {
+            return format((BigDecimal)number, toAppendTo, pos);
+        } else if (number instanceof BigInteger) {
+            return format((BigInteger)number, toAppendTo, pos);
+        } else if (number instanceof Number) {
+            return format(((Number)number).doubleValue(), toAppendTo, pos);
+        } else {
+            throw new IllegalArgumentException("Cannot format given Object as a Number");
+        }
+    }
+
+    /**
+     * Formats a double to produce a string.
+     * @param number    The double to format
+     * @param result    where the text is to be appended
+     * @param fieldPosition    On input: an alignment field, if desired.
+     * On output: the offsets of the alignment field.
+     * @exception ArithmeticException if rounding is needed with rounding
+     *            mode being set to RoundingMode.UNNECESSARY
+     * @return The formatted number string
+     * @see java.text.FieldPosition
+     */
+    @Override
+    public StringBuffer format(double number, StringBuffer result,
+                               FieldPosition fieldPosition) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        // If fieldPosition is a DontCareFieldPosition instance we can
+        // try to go to fast-path code.
+        boolean tryFastPath = false;
+        if (fieldPosition == DontCareFieldPosition.INSTANCE)
+            tryFastPath = true;
+        else {
+            fieldPosition.setBeginIndex(0);
+            fieldPosition.setEndIndex(0);
+        }
+
+        if (tryFastPath) {
+            String tempResult = fastFormat(number);
+            if (tempResult != null) {
+                result.append(tempResult);
+                return result;
+            }
+        }
+
+        // if fast-path could not work, we fallback to standard code.
+        return format(number, result, fieldPosition.getFieldDelegate());
+        */
+        FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition);
+        icuDecimalFormat.format(number, result, icuFieldPosition);
+        fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex());
+        fieldPosition.setEndIndex(icuFieldPosition.getEndIndex());
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: Use ICU.
+    // Removed unused helper function that was only used from (unused on Android) code
+    // in format(double, StringBuffer, FieldPosition).
+    /*
+    /**
+     * Formats a double to produce a string.
+     * @param number    The double to format
+     * @param result    where the text is to be appended
+     * @param delegate notified of locations of sub fields
+     * @exception       ArithmeticException if rounding is needed with rounding
+     *                  mode being set to RoundingMode.UNNECESSARY
+     * @return The formatted number string
+     *
+    private StringBuffer format(double number, StringBuffer result,
+                                FieldDelegate delegate) {
+        if (Double.isNaN(number) ||
+           (Double.isInfinite(number) && multiplier == 0)) {
+            int iFieldStart = result.length();
+            result.append(symbols.getNaN());
+            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
+                               iFieldStart, result.length(), result);
+            return result;
+        }
+
+        /* Detecting whether a double is negative is easy with the exception of
+         * the value -0.0.  This is a double which has a zero mantissa (and
+         * exponent), but a negative sign bit.  It is semantically distinct from
+         * a zero with a positive sign bit, and this distinction is important
+         * to certain kinds of computations.  However, it's a little tricky to
+         * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0).  How then, you may
+         * ask, does it behave distinctly from +0.0?  Well, 1/(-0.0) ==
+         * -Infinity.  Proper detection of -0.0 is needed to deal with the
+         * issues raised by bugs 4106658, 4106667, and 4147706.  Liu 7/6/98.
+         *
+        boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
+
+        if (multiplier != 1) {
+            number *= multiplier;
+        }
+
+        if (Double.isInfinite(number)) {
+            if (isNegative) {
+                append(result, negativePrefix, delegate,
+                       getNegativePrefixFieldPositions(), Field.SIGN);
+            } else {
+                append(result, positivePrefix, delegate,
+                       getPositivePrefixFieldPositions(), Field.SIGN);
+            }
+
+            int iFieldStart = result.length();
+            result.append(symbols.getInfinity());
+            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
+                               iFieldStart, result.length(), result);
+
+            if (isNegative) {
+                append(result, negativeSuffix, delegate,
+                       getNegativeSuffixFieldPositions(), Field.SIGN);
+            } else {
+                append(result, positiveSuffix, delegate,
+                       getPositiveSuffixFieldPositions(), Field.SIGN);
+            }
+
+            return result;
+        }
+
+        if (isNegative) {
+            number = -number;
+        }
+
+        // at this point we are guaranteed a nonnegative finite number.
+        assert(number >= 0 && !Double.isInfinite(number));
+
+        synchronized(digitList) {
+            int maxIntDigits = super.getMaximumIntegerDigits();
+            int minIntDigits = super.getMinimumIntegerDigits();
+            int maxFraDigits = super.getMaximumFractionDigits();
+            int minFraDigits = super.getMinimumFractionDigits();
+
+            digitList.set(isNegative, number, useExponentialNotation ?
+                          maxIntDigits + maxFraDigits : maxFraDigits,
+                          !useExponentialNotation);
+            return subformat(result, delegate, isNegative, false,
+                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
+        }
+    }
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Format a long to produce a string.
+     * @param number    The long to format
+     * @param result    where the text is to be appended
+     * @param fieldPosition    On input: an alignment field, if desired.
+     * On output: the offsets of the alignment field.
+     * @exception       ArithmeticException if rounding is needed with rounding
+     *                  mode being set to RoundingMode.UNNECESSARY
+     * @return The formatted number string
+     * @see java.text.FieldPosition
+     */
+    @Override
+    public StringBuffer format(long number, StringBuffer result,
+                               FieldPosition fieldPosition) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        fieldPosition.setBeginIndex(0);
+        fieldPosition.setEndIndex(0);
+
+        return format(number, result, fieldPosition.getFieldDelegate());
+        */
+        FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition);
+        icuDecimalFormat.format(number, result, icuFieldPosition);
+        fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex());
+        fieldPosition.setEndIndex(icuFieldPosition.getEndIndex());
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: Use ICU.
+    // Removed unused helper function that was only used from (unused on Android) code
+    // in format(long, StringBuffer, FieldDelegate).
+    /*
+    /**
+     * Format a long to produce a string.
+     * @param number    The long to format
+     * @param result    where the text is to be appended
+     * @param delegate notified of locations of sub fields
+     * @return The formatted number string
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.FieldPosition
+     *
+    private StringBuffer format(long number, StringBuffer result,
+                               FieldDelegate delegate) {
+        boolean isNegative = (number < 0);
+        if (isNegative) {
+            number = -number;
+        }
+
+        // In general, long values always represent real finite numbers, so
+        // we don't have to check for +/- Infinity or NaN.  However, there
+        // is one case we have to be careful of:  The multiplier can push
+        // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
+        // check for this before multiplying, and if it happens we use
+        // BigInteger instead.
+        boolean useBigInteger = false;
+        if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
+            if (multiplier != 0) {
+                useBigInteger = true;
+            }
+        } else if (multiplier != 1 && multiplier != 0) {
+            long cutoff = Long.MAX_VALUE / multiplier;
+            if (cutoff < 0) {
+                cutoff = -cutoff;
+            }
+            useBigInteger = (number > cutoff);
+        }
+
+        if (useBigInteger) {
+            if (isNegative) {
+                number = -number;
+            }
+            BigInteger bigIntegerValue = BigInteger.valueOf(number);
+            return format(bigIntegerValue, result, delegate, true);
+        }
+
+        number *= multiplier;
+        if (number == 0) {
+            isNegative = false;
+        } else {
+            if (multiplier < 0) {
+                number = -number;
+                isNegative = !isNegative;
+            }
+        }
+
+        synchronized(digitList) {
+            int maxIntDigits = super.getMaximumIntegerDigits();
+            int minIntDigits = super.getMinimumIntegerDigits();
+            int maxFraDigits = super.getMaximumFractionDigits();
+            int minFraDigits = super.getMinimumFractionDigits();
+
+            digitList.set(isNegative, number,
+                     useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
+
+            return subformat(result, delegate, isNegative, true,
+                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
+        }
+    }
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Formats a BigDecimal to produce a string.
+     * @param number    The BigDecimal to format
+     * @param result    where the text is to be appended
+     * @param fieldPosition    On input: an alignment field, if desired.
+     * On output: the offsets of the alignment field.
+     * @return The formatted number string
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.FieldPosition
+     */
+    private StringBuffer format(BigDecimal number, StringBuffer result,
+                                FieldPosition fieldPosition) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        fieldPosition.setBeginIndex(0);
+        fieldPosition.setEndIndex(0);
+        return format(number, result, fieldPosition.getFieldDelegate());
+        */
+        FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition);
+        icuDecimalFormat.format(number, result, fieldPosition);
+        fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex());
+        fieldPosition.setEndIndex(icuFieldPosition.getEndIndex());
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: Use ICU.
+    // Removed unused helper function that was only used from (unused on Android) code
+    // in format(BigDecimal, StringBuffer, FieldDelegate).
+    /*
+    /**
+     * Formats a BigDecimal to produce a string.
+     * @param number    The BigDecimal to format
+     * @param result    where the text is to be appended
+     * @param delegate notified of locations of sub fields
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @return The formatted number string
+     *
+    private StringBuffer format(BigDecimal number, StringBuffer result,
+                                FieldDelegate delegate) {
+        if (multiplier != 1) {
+            number = number.multiply(getBigDecimalMultiplier());
+        }
+        boolean isNegative = number.signum() == -1;
+        if (isNegative) {
+            number = number.negate();
+        }
+
+        synchronized(digitList) {
+            int maxIntDigits = getMaximumIntegerDigits();
+            int minIntDigits = getMinimumIntegerDigits();
+            int maxFraDigits = getMaximumFractionDigits();
+            int minFraDigits = getMinimumFractionDigits();
+            int maximumDigits = maxIntDigits + maxFraDigits;
+
+            digitList.set(isNegative, number, useExponentialNotation ?
+                ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
+                maxFraDigits, !useExponentialNotation);
+
+            return subformat(result, delegate, isNegative, false,
+                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
+        }
+    }
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Format a BigInteger to produce a string.
+     * @param number    The BigInteger to format
+     * @param result    where the text is to be appended
+     * @param fieldPosition    On input: an alignment field, if desired.
+     * On output: the offsets of the alignment field.
+     * @return The formatted number string
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.FieldPosition
+     */
+    private StringBuffer format(BigInteger number, StringBuffer result,
+                               FieldPosition fieldPosition) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        fieldPosition.setBeginIndex(0);
+        fieldPosition.setEndIndex(0);
+
+        return format(number, result, fieldPosition.getFieldDelegate(), false);
+        */
+        FieldPosition icuFieldPosition = getIcuFieldPosition(fieldPosition);
+        icuDecimalFormat.format(number, result, fieldPosition);
+        fieldPosition.setBeginIndex(icuFieldPosition.getBeginIndex());
+        fieldPosition.setEndIndex(icuFieldPosition.getEndIndex());
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: Use ICU.
+    // Removed unused helper function that was only used from (unused on Android) code
+    // in format(BigInteger, StringBuffer, FieldDelegate).
+    /*
+    /**
+     * Format a BigInteger to produce a string.
+     * @param number    The BigInteger to format
+     * @param result    where the text is to be appended
+     * @param delegate notified of locations of sub fields
+     * @return The formatted number string
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.FieldPosition
+     *
+    private StringBuffer format(BigInteger number, StringBuffer result,
+                               FieldDelegate delegate, boolean formatLong) {
+        if (multiplier != 1) {
+            number = number.multiply(getBigIntegerMultiplier());
+        }
+        boolean isNegative = number.signum() == -1;
+        if (isNegative) {
+            number = number.negate();
+        }
+
+        synchronized(digitList) {
+            int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
+            if (formatLong) {
+                maxIntDigits = super.getMaximumIntegerDigits();
+                minIntDigits = super.getMinimumIntegerDigits();
+                maxFraDigits = super.getMaximumFractionDigits();
+                minFraDigits = super.getMinimumFractionDigits();
+                maximumDigits = maxIntDigits + maxFraDigits;
+            } else {
+                maxIntDigits = getMaximumIntegerDigits();
+                minIntDigits = getMinimumIntegerDigits();
+                maxFraDigits = getMaximumFractionDigits();
+                minFraDigits = getMinimumFractionDigits();
+                maximumDigits = maxIntDigits + maxFraDigits;
+                if (maximumDigits < 0) {
+                    maximumDigits = Integer.MAX_VALUE;
+                }
+            }
+
+            digitList.set(isNegative, number,
+                          useExponentialNotation ? maximumDigits : 0);
+
+            return subformat(result, delegate, isNegative, true,
+                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
+        }
+    }
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
+     * You can use the returned <code>AttributedCharacterIterator</code>
+     * to build the resulting String, as well as to determine information
+     * about the resulting String.
+     * <p>
+     * Each attribute key of the AttributedCharacterIterator will be of type
+     * <code>NumberFormat.Field</code>, with the attribute value being the
+     * same as the attribute key.
+     *
+     * @exception NullPointerException if obj is null.
+     * @exception IllegalArgumentException when the Format cannot format the
+     *            given object.
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @param obj The object to format
+     * @return AttributedCharacterIterator describing the formatted value.
+     * @since 1.4
+     */
+    @Override
+    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        CharacterIteratorFieldDelegate delegate =
+                         new CharacterIteratorFieldDelegate();
+        StringBuffer sb = new StringBuffer();
+
+        if (obj instanceof Double || obj instanceof Float) {
+            format(((Number)obj).doubleValue(), sb, delegate);
+        } else if (obj instanceof Long || obj instanceof Integer ||
+                   obj instanceof Short || obj instanceof Byte ||
+                   obj instanceof AtomicInteger || obj instanceof AtomicLong) {
+            format(((Number)obj).longValue(), sb, delegate);
+        } else if (obj instanceof BigDecimal) {
+            format((BigDecimal)obj, sb, delegate);
+        } else if (obj instanceof BigInteger) {
+            format((BigInteger)obj, sb, delegate, false);
+        } else if (obj == null) {
+            throw new NullPointerException(
+                "formatToCharacterIterator must be passed non-null object");
+        } else {
+            throw new IllegalArgumentException(
+                "Cannot format given Object as a Number");
+        }
+        return delegate.getIterator(sb.toString());
+        */
+        if (obj == null) {
+            throw new NullPointerException("object == null");
+        }
+        // Note: formatToCharacterIterator cannot be used directly because it returns attributes
+        // in terms of its own class: icu.text.NumberFormat instead of java.text.NumberFormat.
+        // http://bugs.icu-project.org/trac/ticket/11931 Proposes to use the NumberFormat constants.
+
+        AttributedCharacterIterator original = icuDecimalFormat.formatToCharacterIterator(obj);
+
+        // Extract the text out of the ICU iterator.
+        StringBuilder textBuilder = new StringBuilder(
+                original.getEndIndex() - original.getBeginIndex());
+
+        for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) {
+            textBuilder.append(original.current());
+            original.next();
+        }
+
+        AttributedString result = new AttributedString(textBuilder.toString());
+
+        for (int i = original.getBeginIndex(); i < original.getEndIndex(); i++) {
+            original.setIndex(i);
+
+            for (AttributedCharacterIterator.Attribute attribute
+                    : original.getAttributes().keySet()) {
+                    int start = original.getRunStart();
+                    int end = original.getRunLimit();
+                    Field javaAttr = toJavaFieldAttribute(attribute);
+                    result.addAttribute(javaAttr, javaAttr, start, end);
+            }
+        }
+
+        return result.getIterator();
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: "fast-path formatting logic for double", subformat(), append().
+    /*
+    // ==== Begin fast-path formating logic for double =========================
+
+    /* Fast-path formatting will be used for format(double ...) methods iff a
+     * number of conditions are met (see checkAndSetFastPathStatus()):
+     * - Only if instance properties meet the right predefined conditions.
+     * - The abs value of the double to format is <= Integer.MAX_VALUE.
+     *
+     * The basic approach is to split the binary to decimal conversion of a
+     * double value into two phases:
+     * * The conversion of the integer portion of the double.
+     * * The conversion of the fractional portion of the double
+     *   (limited to two or three digits).
+     *
+     * The isolation and conversion of the integer portion of the double is
+     * straightforward. The conversion of the fraction is more subtle and relies
+     * on some rounding properties of double to the decimal precisions in
+     * question.  Using the terminology of BigDecimal, this fast-path algorithm
+     * is applied when a double value has a magnitude less than Integer.MAX_VALUE
+     * and rounding is to nearest even and the destination format has two or
+     * three digits of *scale* (digits after the decimal point).
+     *
+     * Under a rounding to nearest even policy, the returned result is a digit
+     * string of a number in the (in this case decimal) destination format
+     * closest to the exact numerical value of the (in this case binary) input
+     * value.  If two destination format numbers are equally distant, the one
+     * with the last digit even is returned.  To compute such a correctly rounded
+     * value, some information about digits beyond the smallest returned digit
+     * position needs to be consulted.
+     *
+     * In general, a guard digit, a round digit, and a sticky *bit* are needed
+     * beyond the returned digit position.  If the discarded portion of the input
+     * is sufficiently large, the returned digit string is incremented.  In round
+     * to nearest even, this threshold to increment occurs near the half-way
+     * point between digits.  The sticky bit records if there are any remaining
+     * trailing digits of the exact input value in the new format; the sticky bit
+     * is consulted only in close to half-way rounding cases.
+     *
+     * Given the computation of the digit and bit values, rounding is then
+     * reduced to a table lookup problem.  For decimal, the even/odd cases look
+     * like this:
+     *
+     * Last   Round   Sticky
+     * 6      5       0      => 6   // exactly halfway, return even digit.
+     * 6      5       1      => 7   // a little bit more than halfway, round up.
+     * 7      5       0      => 8   // exactly halfway, round up to even.
+     * 7      5       1      => 8   // a little bit more than halfway, round up.
+     * With analogous entries for other even and odd last-returned digits.
+     *
+     * However, decimal negative powers of 5 smaller than 0.5 are *not* exactly
+     * representable as binary fraction.  In particular, 0.005 (the round limit
+     * for a two-digit scale) and 0.0005 (the round limit for a three-digit
+     * scale) are not representable. Therefore, for input values near these cases
+     * the sticky bit is known to be set which reduces the rounding logic to:
+     *
+     * Last   Round   Sticky
+     * 6      5       1      => 7   // a little bit more than halfway, round up.
+     * 7      5       1      => 8   // a little bit more than halfway, round up.
+     *
+     * In other words, if the round digit is 5, the sticky bit is known to be
+     * set.  If the round digit is something other than 5, the sticky bit is not
+     * relevant.  Therefore, some of the logic about whether or not to increment
+     * the destination *decimal* value can occur based on tests of *binary*
+     * computations of the binary input number.
+     *
+
+    /**
+     * Check validity of using fast-path for this instance. If fast-path is valid
+     * for this instance, sets fast-path state as true and initializes fast-path
+     * utility fields as needed.
+     *
+     * This method is supposed to be called rarely, otherwise that will break the
+     * fast-path performance. That means avoiding frequent changes of the
+     * properties of the instance, since for most properties, each time a change
+     * happens, a call to this method is needed at the next format call.
+     *
+     * FAST-PATH RULES:
+     *  Similar to the default DecimalFormat instantiation case.
+     *  More precisely:
+     *  - HALF_EVEN rounding mode,
+     *  - isGroupingUsed() is true,
+     *  - groupingSize of 3,
+     *  - multiplier is 1,
+     *  - Decimal separator not mandatory,
+     *  - No use of exponential notation,
+     *  - minimumIntegerDigits is exactly 1 and maximumIntegerDigits at least 10
+     *  - For number of fractional digits, the exact values found in the default case:
+     *     Currency : min = max = 2.
+     *     Decimal  : min = 0. max = 3.
+     *
+     *
+    private void checkAndSetFastPathStatus() {
+
+        boolean fastPathWasOn = isFastPath;
+
+        if ((roundingMode == RoundingMode.HALF_EVEN) &&
+            (isGroupingUsed()) &&
+            (groupingSize == 3) &&
+            (multiplier == 1) &&
+            (!decimalSeparatorAlwaysShown) &&
+            (!useExponentialNotation)) {
+
+            // The fast-path algorithm is semi-hardcoded against
+            //  minimumIntegerDigits and maximumIntegerDigits.
+            isFastPath = ((minimumIntegerDigits == 1) &&
+                          (maximumIntegerDigits >= 10));
+
+            // The fast-path algorithm is hardcoded against
+            //  minimumFractionDigits and maximumFractionDigits.
+            if (isFastPath) {
+                if (isCurrencyFormat) {
+                    if ((minimumFractionDigits != 2) ||
+                        (maximumFractionDigits != 2))
+                        isFastPath = false;
+                } else if ((minimumFractionDigits != 0) ||
+                           (maximumFractionDigits != 3))
+                    isFastPath = false;
+            }
+        } else
+            isFastPath = false;
+
+        // Since some instance properties may have changed while still falling
+        // in the fast-path case, we need to reinitialize fastPathData anyway.
+        if (isFastPath) {
+            // We need to instantiate fastPathData if not already done.
+            if (fastPathData == null)
+                fastPathData = new FastPathData();
+
+            // Sets up the locale specific constants used when formatting.
+            // '0' is our default representation of zero.
+            fastPathData.zeroDelta = symbols.getZeroDigit() - '0';
+            fastPathData.groupingChar = symbols.getGroupingSeparator();
+
+            // Sets up fractional constants related to currency/decimal pattern.
+            fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999;
+            fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d;
+
+            // Records the need for adding prefix or suffix
+            fastPathData.positiveAffixesRequired =
+                (positivePrefix.length() != 0) || (positiveSuffix.length() != 0);
+            fastPathData.negativeAffixesRequired =
+                (negativePrefix.length() != 0) || (negativeSuffix.length() != 0);
+
+            // Creates a cached char container for result, with max possible size.
+            int maxNbIntegralDigits = 10;
+            int maxNbGroups = 3;
+            int containerSize =
+                Math.max(positivePrefix.length(), negativePrefix.length()) +
+                maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits +
+                Math.max(positiveSuffix.length(), negativeSuffix.length());
+
+            fastPathData.fastPathContainer = new char[containerSize];
+
+            // Sets up prefix and suffix char arrays constants.
+            fastPathData.charsPositiveSuffix = positiveSuffix.toCharArray();
+            fastPathData.charsNegativeSuffix = negativeSuffix.toCharArray();
+            fastPathData.charsPositivePrefix = positivePrefix.toCharArray();
+            fastPathData.charsNegativePrefix = negativePrefix.toCharArray();
+
+            // Sets up fixed index positions for integral and fractional digits.
+            // Sets up decimal point in cached result container.
+            int longestPrefixLength =
+                Math.max(positivePrefix.length(), negativePrefix.length());
+            int decimalPointIndex =
+                maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
+
+            fastPathData.integralLastIndex    = decimalPointIndex - 1;
+            fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
+            fastPathData.fastPathContainer[decimalPointIndex] =
+                isCurrencyFormat ?
+                symbols.getMonetaryDecimalSeparator() :
+                symbols.getDecimalSeparator();
+
+        } else if (fastPathWasOn) {
+            // Previous state was fast-path and is no more.
+            // Resets cached array constants.
+            fastPathData.fastPathContainer = null;
+            fastPathData.charsPositiveSuffix = null;
+            fastPathData.charsNegativeSuffix = null;
+            fastPathData.charsPositivePrefix = null;
+            fastPathData.charsNegativePrefix = null;
+        }
+
+        fastPathCheckNeeded = false;
+    }
+
+    /**
+     * Returns true if rounding-up must be done on {@code scaledFractionalPartAsInt},
+     * false otherwise.
+     *
+     * This is a utility method that takes correct half-even rounding decision on
+     * passed fractional value at the scaled decimal point (2 digits for currency
+     * case and 3 for decimal case), when the approximated fractional part after
+     * scaled decimal point is exactly 0.5d.  This is done by means of exact
+     * calculations on the {@code fractionalPart} floating-point value.
+     *
+     * This method is supposed to be called by private {@code fastDoubleFormat}
+     * method only.
+     *
+     * The algorithms used for the exact calculations are :
+     *
+     * The <b><i>FastTwoSum</i></b> algorithm, from T.J.Dekker, described in the
+     * papers  "<i>A  Floating-Point   Technique  for  Extending  the  Available
+     * Precision</i>"  by Dekker, and  in "<i>Adaptive  Precision Floating-Point
+     * Arithmetic and Fast Robust Geometric Predicates</i>" from J.Shewchuk.
+     *
+     * A modified version of <b><i>Sum2S</i></b> cascaded summation described in
+     * "<i>Accurate Sum and Dot Product</i>" from Takeshi Ogita and All.  As
+     * Ogita says in this paper this is an equivalent of the Kahan-Babuska's
+     * summation algorithm because we order the terms by magnitude before summing
+     * them. For this reason we can use the <i>FastTwoSum</i> algorithm rather
+     * than the more expensive Knuth's <i>TwoSum</i>.
+     *
+     * We do this to avoid a more expensive exact "<i>TwoProduct</i>" algorithm,
+     * like those described in Shewchuk's paper above. See comments in the code
+     * below.
+     *
+     * @param  fractionalPart The  fractional value  on which  we  take rounding
+     * decision.
+     * @param scaledFractionalPartAsInt The integral part of the scaled
+     * fractional value.
+     *
+     * @return the decision that must be taken regarding half-even rounding.
+     *
+    private boolean exactRoundUp(double fractionalPart,
+                                 int scaledFractionalPartAsInt) {
+
+        /* exactRoundUp() method is called by fastDoubleFormat() only.
+         * The precondition expected to be verified by the passed parameters is :
+         * scaledFractionalPartAsInt ==
+         *     (int) (fractionalPart * fastPathData.fractionalScaleFactor).
+         * This is ensured by fastDoubleFormat() code.
+         *
+
+        /* We first calculate roundoff error made by fastDoubleFormat() on
+         * the scaled fractional part. We do this with exact calculation on the
+         * passed fractionalPart. Rounding decision will then be taken from roundoff.
+         *
+
+        /* ---- TwoProduct(fractionalPart, scale factor (i.e. 1000.0d or 100.0d)).
+         *
+         * The below is an optimized exact "TwoProduct" calculation of passed
+         * fractional part with scale factor, using Ogita's Sum2S cascaded
+         * summation adapted as Kahan-Babuska equivalent by using FastTwoSum
+         * (much faster) rather than Knuth's TwoSum.
+         *
+         * We can do this because we order the summation from smallest to
+         * greatest, so that FastTwoSum can be used without any additional error.
+         *
+         * The "TwoProduct" exact calculation needs 17 flops. We replace this by
+         * a cascaded summation of FastTwoSum calculations, each involving an
+         * exact multiply by a power of 2.
+         *
+         * Doing so saves overall 4 multiplications and 1 addition compared to
+         * using traditional "TwoProduct".
+         *
+         * The scale factor is either 100 (currency case) or 1000 (decimal case).
+         * - when 1000, we replace it by (1024 - 16 - 8) = 1000.
+         * - when 100,  we replace it by (128  - 32 + 4) =  100.
+         * Every multiplication by a power of 2 (1024, 128, 32, 16, 8, 4) is exact.
+         *
+         *
+        double approxMax;    // Will always be positive.
+        double approxMedium; // Will always be negative.
+        double approxMin;
+
+        double fastTwoSumApproximation = 0.0d;
+        double fastTwoSumRoundOff = 0.0d;
+        double bVirtual = 0.0d;
+
+        if (isCurrencyFormat) {
+            // Scale is 100 = 128 - 32 + 4.
+            // Multiply by 2**n is a shift. No roundoff. No error.
+            approxMax    = fractionalPart * 128.00d;
+            approxMedium = - (fractionalPart * 32.00d);
+            approxMin    = fractionalPart * 4.00d;
+        } else {
+            // Scale is 1000 = 1024 - 16 - 8.
+            // Multiply by 2**n is a shift. No roundoff. No error.
+            approxMax    = fractionalPart * 1024.00d;
+            approxMedium = - (fractionalPart * 16.00d);
+            approxMin    = - (fractionalPart * 8.00d);
+        }
+
+        // Shewchuk/Dekker's FastTwoSum(approxMedium, approxMin).
+        assert(-approxMedium >= Math.abs(approxMin));
+        fastTwoSumApproximation = approxMedium + approxMin;
+        bVirtual = fastTwoSumApproximation - approxMedium;
+        fastTwoSumRoundOff = approxMin - bVirtual;
+        double approxS1 = fastTwoSumApproximation;
+        double roundoffS1 = fastTwoSumRoundOff;
+
+        // Shewchuk/Dekker's FastTwoSum(approxMax, approxS1);
+        assert(approxMax >= Math.abs(approxS1));
+        fastTwoSumApproximation = approxMax + approxS1;
+        bVirtual = fastTwoSumApproximation - approxMax;
+        fastTwoSumRoundOff = approxS1 - bVirtual;
+        double roundoff1000 = fastTwoSumRoundOff;
+        double approx1000 = fastTwoSumApproximation;
+        double roundoffTotal = roundoffS1 + roundoff1000;
+
+        // Shewchuk/Dekker's FastTwoSum(approx1000, roundoffTotal);
+        assert(approx1000 >= Math.abs(roundoffTotal));
+        fastTwoSumApproximation = approx1000 + roundoffTotal;
+        bVirtual = fastTwoSumApproximation - approx1000;
+
+        // Now we have got the roundoff for the scaled fractional
+        double scaledFractionalRoundoff = roundoffTotal - bVirtual;
+
+        // ---- TwoProduct(fractionalPart, scale (i.e. 1000.0d or 100.0d)) end.
+
+        /* ---- Taking the rounding decision
+         *
+         * We take rounding decision based on roundoff and half-even rounding
+         * rule.
+         *
+         * The above TwoProduct gives us the exact roundoff on the approximated
+         * scaled fractional, and we know that this approximation is exactly
+         * 0.5d, since that has already been tested by the caller
+         * (fastDoubleFormat).
+         *
+         * Decision comes first from the sign of the calculated exact roundoff.
+         * - Since being exact roundoff, it cannot be positive with a scaled
+         *   fractional less than 0.5d, as well as negative with a scaled
+         *   fractional greater than 0.5d. That leaves us with following 3 cases.
+         * - positive, thus scaled fractional == 0.500....0fff ==> round-up.
+         * - negative, thus scaled fractional == 0.499....9fff ==> don't round-up.
+         * - is zero,  thus scaled fractioanl == 0.5 ==> half-even rounding applies :
+         *    we round-up only if the integral part of the scaled fractional is odd.
+         *
+         *
+        if (scaledFractionalRoundoff > 0.0) {
+            return true;
+        } else if (scaledFractionalRoundoff < 0.0) {
+            return false;
+        } else if ((scaledFractionalPartAsInt & 1) != 0) {
+            return true;
+        }
+
+        return false;
+
+        // ---- Taking the rounding decision end
+    }
+
+    /**
+     * Collects integral digits from passed {@code number}, while setting
+     * grouping chars as needed. Updates {@code firstUsedIndex} accordingly.
+     *
+     * Loops downward starting from {@code backwardIndex} position (inclusive).
+     *
+     * @param number  The int value from which we collect digits.
+     * @param digitsBuffer The char array container where digits and grouping chars
+     *  are stored.
+     * @param backwardIndex the position from which we start storing digits in
+     *  digitsBuffer.
+     *
+     *
+    private void collectIntegralDigits(int number,
+                                       char[] digitsBuffer,
+                                       int backwardIndex) {
+        int index = backwardIndex;
+        int q;
+        int r;
+        while (number > 999) {
+            // Generates 3 digits per iteration.
+            q = number / 1000;
+            r = number - (q << 10) + (q << 4) + (q << 3); // -1024 +16 +8 = 1000.
+            number = q;
+
+            digitsBuffer[index--] = DigitArrays.DigitOnes1000[r];
+            digitsBuffer[index--] = DigitArrays.DigitTens1000[r];
+            digitsBuffer[index--] = DigitArrays.DigitHundreds1000[r];
+            digitsBuffer[index--] = fastPathData.groupingChar;
+        }
+
+        // Collects last 3 or less digits.
+        digitsBuffer[index] = DigitArrays.DigitOnes1000[number];
+        if (number > 9) {
+            digitsBuffer[--index]  = DigitArrays.DigitTens1000[number];
+            if (number > 99)
+                digitsBuffer[--index]   = DigitArrays.DigitHundreds1000[number];
+        }
+
+        fastPathData.firstUsedIndex = index;
+    }
+
+    /**
+     * Collects the 2 (currency) or 3 (decimal) fractional digits from passed
+     * {@code number}, starting at {@code startIndex} position
+     * inclusive.  There is no punctuation to set here (no grouping chars).
+     * Updates {@code fastPathData.lastFreeIndex} accordingly.
+     *
+     *
+     * @param number  The int value from which we collect digits.
+     * @param digitsBuffer The char array container where digits are stored.
+     * @param startIndex the position from which we start storing digits in
+     *  digitsBuffer.
+     *
+     *
+    private void collectFractionalDigits(int number,
+                                         char[] digitsBuffer,
+                                         int startIndex) {
+        int index = startIndex;
+
+        char digitOnes = DigitArrays.DigitOnes1000[number];
+        char digitTens = DigitArrays.DigitTens1000[number];
+
+        if (isCurrencyFormat) {
+            // Currency case. Always collects fractional digits.
+            digitsBuffer[index++] = digitTens;
+            digitsBuffer[index++] = digitOnes;
+        } else if (number != 0) {
+            // Decimal case. Hundreds will always be collected
+            digitsBuffer[index++] = DigitArrays.DigitHundreds1000[number];
+
+            // Ending zeros won't be collected.
+            if (digitOnes != '0') {
+                digitsBuffer[index++] = digitTens;
+                digitsBuffer[index++] = digitOnes;
+            } else if (digitTens != '0')
+                digitsBuffer[index++] = digitTens;
+
+        } else
+            // This is decimal pattern and fractional part is zero.
+            // We must remove decimal point from result.
+            index--;
+
+        fastPathData.lastFreeIndex = index;
+    }
+
+    /**
+     * Internal utility.
+     * Adds the passed {@code prefix} and {@code suffix} to {@code container}.
+     *
+     * @param container  Char array container which to prepend/append the
+     *  prefix/suffix.
+     * @param prefix     Char sequence to prepend as a prefix.
+     * @param suffix     Char sequence to append as a suffix.
+     *
+     *
+    //    private void addAffixes(boolean isNegative, char[] container) {
+    private void addAffixes(char[] container, char[] prefix, char[] suffix) {
+
+        // We add affixes only if needed (affix length > 0).
+        int pl = prefix.length;
+        int sl = suffix.length;
+        if (pl != 0) prependPrefix(prefix, pl, container);
+        if (sl != 0) appendSuffix(suffix, sl, container);
+
+    }
+
+    /**
+     * Prepends the passed {@code prefix} chars to given result
+     * {@code container}.  Updates {@code fastPathData.firstUsedIndex}
+     * accordingly.
+     *
+     * @param prefix The prefix characters to prepend to result.
+     * @param len The number of chars to prepend.
+     * @param container Char array container which to prepend the prefix
+     *
+    private void prependPrefix(char[] prefix,
+                               int len,
+                               char[] container) {
+
+        fastPathData.firstUsedIndex -= len;
+        int startIndex = fastPathData.firstUsedIndex;
+
+        // If prefix to prepend is only 1 char long, just assigns this char.
+        // If prefix is less or equal 4, we use a dedicated algorithm that
+        //  has shown to run faster than System.arraycopy.
+        // If more than 4, we use System.arraycopy.
+        if (len == 1)
+            container[startIndex] = prefix[0];
+        else if (len <= 4) {
+            int dstLower = startIndex;
+            int dstUpper = dstLower + len - 1;
+            int srcUpper = len - 1;
+            container[dstLower] = prefix[0];
+            container[dstUpper] = prefix[srcUpper];
+
+            if (len > 2)
+                container[++dstLower] = prefix[1];
+            if (len == 4)
+                container[--dstUpper] = prefix[2];
+        } else
+            System.arraycopy(prefix, 0, container, startIndex, len);
+    }
+
+    /**
+     * Appends the passed {@code suffix} chars to given result
+     * {@code container}.  Updates {@code fastPathData.lastFreeIndex}
+     * accordingly.
+     *
+     * @param suffix The suffix characters to append to result.
+     * @param len The number of chars to append.
+     * @param container Char array container which to append the suffix
+     *
+    private void appendSuffix(char[] suffix,
+                              int len,
+                              char[] container) {
+
+        int startIndex = fastPathData.lastFreeIndex;
+
+        // If suffix to append is only 1 char long, just assigns this char.
+        // If suffix is less or equal 4, we use a dedicated algorithm that
+        //  has shown to run faster than System.arraycopy.
+        // If more than 4, we use System.arraycopy.
+        if (len == 1)
+            container[startIndex] = suffix[0];
+        else if (len <= 4) {
+            int dstLower = startIndex;
+            int dstUpper = dstLower + len - 1;
+            int srcUpper = len - 1;
+            container[dstLower] = suffix[0];
+            container[dstUpper] = suffix[srcUpper];
+
+            if (len > 2)
+                container[++dstLower] = suffix[1];
+            if (len == 4)
+                container[--dstUpper] = suffix[2];
+        } else
+            System.arraycopy(suffix, 0, container, startIndex, len);
+
+        fastPathData.lastFreeIndex += len;
+    }
+
+    /**
+     * Converts digit chars from {@code digitsBuffer} to current locale.
+     *
+     * Must be called before adding affixes since we refer to
+     * {@code fastPathData.firstUsedIndex} and {@code fastPathData.lastFreeIndex},
+     * and do not support affixes (for speed reason).
+     *
+     * We loop backward starting from last used index in {@code fastPathData}.
+     *
+     * @param digitsBuffer The char array container where the digits are stored.
+     *
+    private void localizeDigits(char[] digitsBuffer) {
+
+        // We will localize only the digits, using the groupingSize,
+        // and taking into account fractional part.
+
+        // First take into account fractional part.
+        int digitsCounter =
+            fastPathData.lastFreeIndex - fastPathData.fractionalFirstIndex;
+
+        // The case when there is no fractional digits.
+        if (digitsCounter < 0)
+            digitsCounter = groupingSize;
+
+        // Only the digits remains to localize.
+        for (int cursor = fastPathData.lastFreeIndex - 1;
+             cursor >= fastPathData.firstUsedIndex;
+             cursor--) {
+            if (digitsCounter != 0) {
+                // This is a digit char, we must localize it.
+                digitsBuffer[cursor] += fastPathData.zeroDelta;
+                digitsCounter--;
+            } else {
+                // Decimal separator or grouping char. Reinit counter only.
+                digitsCounter = groupingSize;
+            }
+        }
+    }
+
+    /**
+     * This is the main entry point for the fast-path format algorithm.
+     *
+     * At this point we are sure to be in the expected conditions to run it.
+     * This algorithm builds the formatted result and puts it in the dedicated
+     * {@code fastPathData.fastPathContainer}.
+     *
+     * @param d the double value to be formatted.
+     * @param negative Flag precising if {@code d} is negative.
+     *
+    private void fastDoubleFormat(double d,
+                                  boolean negative) {
+
+        char[] container = fastPathData.fastPathContainer;
+
+        /*
+         * The principle of the algorithm is to :
+         * - Break the passed double into its integral and fractional parts
+         *    converted into integers.
+         * - Then decide if rounding up must be applied or not by following
+         *    the half-even rounding rule, first using approximated scaled
+         *    fractional part.
+         * - For the difficult cases (approximated scaled fractional part
+         *    being exactly 0.5d), we refine the rounding decision by calling
+         *    exactRoundUp utility method that both calculates the exact roundoff
+         *    on the approximation and takes correct rounding decision.
+         * - We round-up the fractional part if needed, possibly propagating the
+         *    rounding to integral part if we meet a "all-nine" case for the
+         *    scaled fractional part.
+         * - We then collect digits from the resulting integral and fractional
+         *   parts, also setting the required grouping chars on the fly.
+         * - Then we localize the collected digits if needed, and
+         * - Finally prepend/append prefix/suffix if any is needed.
+         *
+
+        // Exact integral part of d.
+        int integralPartAsInt = (int) d;
+
+        // Exact fractional part of d (since we subtract it's integral part).
+        double exactFractionalPart = d - (double) integralPartAsInt;
+
+        // Approximated scaled fractional part of d (due to multiplication).
+        double scaledFractional =
+            exactFractionalPart * fastPathData.fractionalScaleFactor;
+
+        // Exact integral part of scaled fractional above.
+        int fractionalPartAsInt = (int) scaledFractional;
+
+        // Exact fractional part of scaled fractional above.
+        scaledFractional = scaledFractional - (double) fractionalPartAsInt;
+
+        // Only when scaledFractional is exactly 0.5d do we have to do exact
+        // calculations and take fine-grained rounding decision, since
+        // approximated results above may lead to incorrect decision.
+        // Otherwise comparing against 0.5d (strictly greater or less) is ok.
+        boolean roundItUp = false;
+        if (scaledFractional >= 0.5d) {
+            if (scaledFractional == 0.5d)
+                // Rounding need fine-grained decision.
+                roundItUp = exactRoundUp(exactFractionalPart, fractionalPartAsInt);
+            else
+                roundItUp = true;
+
+            if (roundItUp) {
+                // Rounds up both fractional part (and also integral if needed).
+                if (fractionalPartAsInt < fastPathData.fractionalMaxIntBound) {
+                    fractionalPartAsInt++;
+                } else {
+                    // Propagates rounding to integral part since "all nines" case.
+                    fractionalPartAsInt = 0;
+                    integralPartAsInt++;
+                }
+            }
+        }
+
+        // Collecting digits.
+        collectFractionalDigits(fractionalPartAsInt, container,
+                                fastPathData.fractionalFirstIndex);
+        collectIntegralDigits(integralPartAsInt, container,
+                              fastPathData.integralLastIndex);
+
+        // Localizing digits.
+        if (fastPathData.zeroDelta != 0)
+            localizeDigits(container);
+
+        // Adding prefix and suffix.
+        if (negative) {
+            if (fastPathData.negativeAffixesRequired)
+                addAffixes(container,
+                           fastPathData.charsNegativePrefix,
+                           fastPathData.charsNegativeSuffix);
+        } else if (fastPathData.positiveAffixesRequired)
+            addAffixes(container,
+                       fastPathData.charsPositivePrefix,
+                       fastPathData.charsPositiveSuffix);
+    }
+
+    /**
+     * A fast-path shortcut of format(double) to be called by NumberFormat, or by
+     * format(double, ...) public methods.
+     *
+     * If instance can be applied fast-path and passed double is not NaN or
+     * Infinity, is in the integer range, we call {@code fastDoubleFormat}
+     * after changing {@code d} to its positive value if necessary.
+     *
+     * Otherwise returns null by convention since fast-path can't be exercized.
+     *
+     * @param d The double value to be formatted
+     *
+     * @return the formatted result for {@code d} as a string.
+     *
+    String fastFormat(double d) {
+        // (Re-)Evaluates fast-path status if needed.
+        if (fastPathCheckNeeded)
+            checkAndSetFastPathStatus();
+
+        if (!isFastPath )
+            // DecimalFormat instance is not in a fast-path state.
+            return null;
+
+        if (!Double.isFinite(d))
+            // Should not use fast-path for Infinity and NaN.
+            return null;
+
+        // Extracts and records sign of double value, possibly changing it
+        // to a positive one, before calling fastDoubleFormat().
+        boolean negative = false;
+        if (d < 0.0d) {
+            negative = true;
+            d = -d;
+        } else if (d == 0.0d) {
+            negative = (Math.copySign(1.0d, d) == -1.0d);
+            d = +0.0d;
+        }
+
+        if (d > MAX_INT_AS_DOUBLE)
+            // Filters out values that are outside expected fast-path range
+            return null;
+        else
+            fastDoubleFormat(d, negative);
+
+        // Returns a new string from updated fastPathContainer.
+        return new String(fastPathData.fastPathContainer,
+                          fastPathData.firstUsedIndex,
+                          fastPathData.lastFreeIndex - fastPathData.firstUsedIndex);
+
+    }
+
+    // ======== End fast-path formating logic for double =========================
+
+    /**
+     * Complete the formatting of a finite number.  On entry, the digitList must
+     * be filled in with the correct digits.
+     *
+    private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
+                                   boolean isNegative, boolean isInteger,
+                                   int maxIntDigits, int minIntDigits,
+                                   int maxFraDigits, int minFraDigits) {
+        // NOTE: This isn't required anymore because DigitList takes care of this.
+        //
+        //  // The negative of the exponent represents the number of leading
+        //  // zeros between the decimal and the first non-zero digit, for
+        //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
+        //  // is more than the maximum fraction digits, then we have an underflow
+        //  // for the printed representation.  We recognize this here and set
+        //  // the DigitList representation to zero in this situation.
+        //
+        //  if (-digitList.decimalAt >= getMaximumFractionDigits())
+        //  {
+        //      digitList.count = 0;
+        //  }
+
+        char zero = symbols.getZeroDigit();
+        int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
+        char grouping = symbols.getGroupingSeparator();
+        char decimal = isCurrencyFormat ?
+            symbols.getMonetaryDecimalSeparator() :
+            symbols.getDecimalSeparator();
+
+        /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
+         * format as zero.  This allows sensible computations and preserves
+         * relations such as signum(1/x) = signum(x), where x is +Infinity or
+         * -Infinity.  Prior to this fix, we always formatted zero values as if
+         * they were positive.  Liu 7/6/98.
+         *
+        if (digitList.isZero()) {
+            digitList.decimalAt = 0; // Normalize
+        }
+
+        if (isNegative) {
+            append(result, negativePrefix, delegate,
+                   getNegativePrefixFieldPositions(), Field.SIGN);
+        } else {
+            append(result, positivePrefix, delegate,
+                   getPositivePrefixFieldPositions(), Field.SIGN);
+        }
+
+        if (useExponentialNotation) {
+            int iFieldStart = result.length();
+            int iFieldEnd = -1;
+            int fFieldStart = -1;
+
+            // Minimum integer digits are handled in exponential format by
+            // adjusting the exponent.  For example, 0.01234 with 3 minimum
+            // integer digits is "123.4E-4".
+
+            // Maximum integer digits are interpreted as indicating the
+            // repeating range.  This is useful for engineering notation, in
+            // which the exponent is restricted to a multiple of 3.  For
+            // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
+            // If maximum integer digits are > 1 and are larger than
+            // minimum integer digits, then minimum integer digits are
+            // ignored.
+            int exponent = digitList.decimalAt;
+            int repeat = maxIntDigits;
+            int minimumIntegerDigits = minIntDigits;
+            if (repeat > 1 && repeat > minIntDigits) {
+                // A repeating range is defined; adjust to it as follows.
+                // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
+                // -3,-4,-5=>-6, etc. This takes into account that the
+                // exponent we have here is off by one from what we expect;
+                // it is for the format 0.MMMMMx10^n.
+                if (exponent >= 1) {
+                    exponent = ((exponent - 1) / repeat) * repeat;
+                } else {
+                    // integer division rounds towards 0
+                    exponent = ((exponent - repeat) / repeat) * repeat;
+                }
+                minimumIntegerDigits = 1;
+            } else {
+                // No repeating range is defined; use minimum integer digits.
+                exponent -= minimumIntegerDigits;
+            }
+
+            // We now output a minimum number of digits, and more if there
+            // are more digits, up to the maximum number of digits.  We
+            // place the decimal point after the "integer" digits, which
+            // are the first (decimalAt - exponent) digits.
+            int minimumDigits = minIntDigits + minFraDigits;
+            if (minimumDigits < 0) {    // overflow?
+                minimumDigits = Integer.MAX_VALUE;
+            }
+
+            // The number of integer digits is handled specially if the number
+            // is zero, since then there may be no digits.
+            int integerDigits = digitList.isZero() ? minimumIntegerDigits :
+                    digitList.decimalAt - exponent;
+            if (minimumDigits < integerDigits) {
+                minimumDigits = integerDigits;
+            }
+            int totalDigits = digitList.count;
+            if (minimumDigits > totalDigits) {
+                totalDigits = minimumDigits;
+            }
+            boolean addedDecimalSeparator = false;
+
+            for (int i=0; i<totalDigits; ++i) {
+                if (i == integerDigits) {
+                    // Record field information for caller.
+                    iFieldEnd = result.length();
+
+                    result.append(decimal);
+                    addedDecimalSeparator = true;
+
+                    // Record field information for caller.
+                    fFieldStart = result.length();
+                }
+                result.append((i < digitList.count) ?
+                              (char)(digitList.digits[i] + zeroDelta) :
+                              zero);
+            }
+
+            if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
+                // Record field information for caller.
+                iFieldEnd = result.length();
+
+                result.append(decimal);
+                addedDecimalSeparator = true;
+
+                // Record field information for caller.
+                fFieldStart = result.length();
+            }
+
+            // Record field information
+            if (iFieldEnd == -1) {
+                iFieldEnd = result.length();
+            }
+            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
+                               iFieldStart, iFieldEnd, result);
+            if (addedDecimalSeparator) {
+                delegate.formatted(Field.DECIMAL_SEPARATOR,
+                                   Field.DECIMAL_SEPARATOR,
+                                   iFieldEnd, fFieldStart, result);
+            }
+            if (fFieldStart == -1) {
+                fFieldStart = result.length();
+            }
+            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
+                               fFieldStart, result.length(), result);
+
+            // The exponent is output using the pattern-specified minimum
+            // exponent digits.  There is no maximum limit to the exponent
+            // digits, since truncating the exponent would result in an
+            // unacceptable inaccuracy.
+            int fieldStart = result.length();
+
+            result.append(symbols.getExponentSeparator());
+
+            delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
+                               fieldStart, result.length(), result);
+
+            // For zero values, we force the exponent to zero.  We
+            // must do this here, and not earlier, because the value
+            // is used to determine integer digit count above.
+            if (digitList.isZero()) {
+                exponent = 0;
+            }
+
+            boolean negativeExponent = exponent < 0;
+            if (negativeExponent) {
+                exponent = -exponent;
+                fieldStart = result.length();
+                result.append(symbols.getMinusSign());
+                delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
+                                   fieldStart, result.length(), result);
+            }
+            digitList.set(negativeExponent, exponent);
+
+            int eFieldStart = result.length();
+
+            for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
+                result.append(zero);
+            }
+            for (int i=0; i<digitList.decimalAt; ++i) {
+                result.append((i < digitList.count) ?
+                          (char)(digitList.digits[i] + zeroDelta) : zero);
+            }
+            delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
+                               result.length(), result);
+        } else {
+            int iFieldStart = result.length();
+
+            // Output the integer portion.  Here 'count' is the total
+            // number of integer digits we will display, including both
+            // leading zeros required to satisfy getMinimumIntegerDigits,
+            // and actual digits present in the number.
+            int count = minIntDigits;
+            int digitIndex = 0; // Index into digitList.fDigits[]
+            if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
+                count = digitList.decimalAt;
+            }
+
+            // Handle the case where getMaximumIntegerDigits() is smaller
+            // than the real number of integer digits.  If this is so, we
+            // output the least significant max integer digits.  For example,
+            // the value 1997 printed with 2 max integer digits is just "97".
+            if (count > maxIntDigits) {
+                count = maxIntDigits;
+                digitIndex = digitList.decimalAt - count;
+            }
+
+            int sizeBeforeIntegerPart = result.length();
+            for (int i=count-1; i>=0; --i) {
+                if (i < digitList.decimalAt && digitIndex < digitList.count) {
+                    // Output a real digit
+                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
+                } else {
+                    // Output a leading zero
+                    result.append(zero);
+                }
+
+                // Output grouping separator if necessary.  Don't output a
+                // grouping separator if i==0 though; that's at the end of
+                // the integer part.
+                if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
+                    (i % groupingSize == 0)) {
+                    int gStart = result.length();
+                    result.append(grouping);
+                    delegate.formatted(Field.GROUPING_SEPARATOR,
+                                       Field.GROUPING_SEPARATOR, gStart,
+                                       result.length(), result);
+                }
+            }
+
+            // Determine whether or not there are any printable fractional
+            // digits.  If we've used up the digits we know there aren't.
+            boolean fractionPresent = (minFraDigits > 0) ||
+                (!isInteger && digitIndex < digitList.count);
+
+            // If there is no fraction present, and we haven't printed any
+            // integer digits, then print a zero.  Otherwise we won't print
+            // _any_ digits, and we won't be able to parse this string.
+            if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
+                result.append(zero);
+            }
+
+            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
+                               iFieldStart, result.length(), result);
+
+            // Output the decimal separator if we always do so.
+            int sStart = result.length();
+            if (decimalSeparatorAlwaysShown || fractionPresent) {
+                result.append(decimal);
+            }
+
+            if (sStart != result.length()) {
+                delegate.formatted(Field.DECIMAL_SEPARATOR,
+                                   Field.DECIMAL_SEPARATOR,
+                                   sStart, result.length(), result);
+            }
+            int fFieldStart = result.length();
+
+            for (int i=0; i < maxFraDigits; ++i) {
+                // Here is where we escape from the loop.  We escape if we've
+                // output the maximum fraction digits (specified in the for
+                // expression above).
+                // We also stop when we've output the minimum digits and either:
+                // we have an integer, so there is no fractional stuff to
+                // display, or we're out of significant digits.
+                if (i >= minFraDigits &&
+                    (isInteger || digitIndex >= digitList.count)) {
+                    break;
+                }
+
+                // Output leading fractional zeros. These are zeros that come
+                // after the decimal but before any significant digits. These
+                // are only output if abs(number being formatted) < 1.0.
+                if (-1-i > (digitList.decimalAt-1)) {
+                    result.append(zero);
+                    continue;
+                }
+
+                // Output a digit, if we have any precision left, or a
+                // zero if we don't.  We don't want to output noise digits.
+                if (!isInteger && digitIndex < digitList.count) {
+                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
+                } else {
+                    result.append(zero);
+                }
+            }
+
+            // Record field information for caller.
+            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
+                               fFieldStart, result.length(), result);
+        }
+
+        if (isNegative) {
+            append(result, negativeSuffix, delegate,
+                   getNegativeSuffixFieldPositions(), Field.SIGN);
+        } else {
+            append(result, positiveSuffix, delegate,
+                   getPositiveSuffixFieldPositions(), Field.SIGN);
+        }
+
+        return result;
+    }
+
+    /**
+     * Appends the String <code>string</code> to <code>result</code>.
+     * <code>delegate</code> is notified of all  the
+     * <code>FieldPosition</code>s in <code>positions</code>.
+     * <p>
+     * If one of the <code>FieldPosition</code>s in <code>positions</code>
+     * identifies a <code>SIGN</code> attribute, it is mapped to
+     * <code>signAttribute</code>. This is used
+     * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
+     * attribute as necessary.
+     * <p>
+     * This is used by <code>subformat</code> to add the prefix/suffix.
+     *
+    private void append(StringBuffer result, String string,
+                        FieldDelegate delegate,
+                        FieldPosition[] positions,
+                        Format.Field signAttribute) {
+        int start = result.length();
+
+        if (string.length() > 0) {
+            result.append(string);
+            for (int counter = 0, max = positions.length; counter < max;
+                 counter++) {
+                FieldPosition fp = positions[counter];
+                Format.Field attribute = fp.getFieldAttribute();
+
+                if (attribute == Field.SIGN) {
+                    attribute = signAttribute;
+                }
+                delegate.formatted(attribute, attribute,
+                                   start + fp.getBeginIndex(),
+                                   start + fp.getEndIndex(), result);
+            }
+        }
+    }
+    */
+    // END Android-removed: "fast-path formatting logic for double", subformat(), append().
+
+    /**
+     * Parses text from a string to produce a <code>Number</code>.
+     * <p>
+     * The method attempts to parse text starting at the index given by
+     * <code>pos</code>.
+     * If parsing succeeds, then the index of <code>pos</code> is updated
+     * to the index after the last character used (parsing does not necessarily
+     * use all characters up to the end of the string), and the parsed
+     * number is returned. The updated <code>pos</code> can be used to
+     * indicate the starting point for the next call to this method.
+     * If an error occurs, then the index of <code>pos</code> is not
+     * changed, the error index of <code>pos</code> is set to the index of
+     * the character where the error occurred, and null is returned.
+     * <p>
+     * The subclass returned depends on the value of {@link #isParseBigDecimal}
+     * as well as on the string being parsed.
+     * <ul>
+     *   <li>If <code>isParseBigDecimal()</code> is false (the default),
+     *       most integer values are returned as <code>Long</code>
+     *       objects, no matter how they are written: <code>"17"</code> and
+     *       <code>"17.000"</code> both parse to <code>Long(17)</code>.
+     *       Values that cannot fit into a <code>Long</code> are returned as
+     *       <code>Double</code>s. This includes values with a fractional part,
+     *       infinite values, <code>NaN</code>, and the value -0.0.
+     *       <code>DecimalFormat</code> does <em>not</em> decide whether to
+     *       return a <code>Double</code> or a <code>Long</code> based on the
+     *       presence of a decimal separator in the source string. Doing so
+     *       would prevent integers that overflow the mantissa of a double,
+     *       such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
+     *       parsed accurately.
+     *       <p>
+     *       Callers may use the <code>Number</code> methods
+     *       <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
+     *       the type they want.
+     *   <li>If <code>isParseBigDecimal()</code> is true, values are returned
+     *       as <code>BigDecimal</code> objects. The values are the ones
+     *       constructed by {@link java.math.BigDecimal#BigDecimal(String)}
+     *       for corresponding strings in locale-independent format. The
+     *       special cases negative and positive infinity and NaN are returned
+     *       as <code>Double</code> instances holding the values of the
+     *       corresponding <code>Double</code> constants.
+     * </ul>
+     * <p>
+     * <code>DecimalFormat</code> parses all Unicode characters that represent
+     * decimal digits, as defined by <code>Character.digit()</code>. In
+     * addition, <code>DecimalFormat</code> also recognizes as digits the ten
+     * consecutive characters starting with the localized zero digit defined in
+     * the <code>DecimalFormatSymbols</code> object.
+     *
+     * @param text the string to be parsed
+     * @param pos  A <code>ParsePosition</code> object with index and error
+     *             index information as described above.
+     * @return     the parsed value, or <code>null</code> if the parse fails
+     * @exception  NullPointerException if <code>text</code> or
+     *             <code>pos</code> is null.
+     */
+    @Override
+    public Number parse(String text, ParsePosition pos) {
+        // BEGIN Android-changed: Use ICU.
+        // Return early if the parse position is bogus.
+        /*
+        // special case NaN
+        if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
+            pos.index = pos.index + symbols.getNaN().length();
+            return new Double(Double.NaN);
+        }
+
+        boolean[] status = new boolean[STATUS_LENGTH];
+        if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
+            return null;
+        }
+
+        // special case INFINITY
+        if (status[STATUS_INFINITE]) {
+            if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
+                return new Double(Double.POSITIVE_INFINITY);
+            } else {
+                return new Double(Double.NEGATIVE_INFINITY);
+            }
+        }
+
+        if (multiplier == 0) {
+            if (digitList.isZero()) {
+                return new Double(Double.NaN);
+            } else if (status[STATUS_POSITIVE]) {
+                return new Double(Double.POSITIVE_INFINITY);
+            } else {
+                return new Double(Double.NEGATIVE_INFINITY);
+            }
+        }
+
+        if (isParseBigDecimal()) {
+            BigDecimal bigDecimalResult = digitList.getBigDecimal();
+
+            if (multiplier != 1) {
+                try {
+                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
+                }
+                catch (ArithmeticException e) {  // non-terminating decimal expansion
+                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
+                }
+            }
+
+            if (!status[STATUS_POSITIVE]) {
+                bigDecimalResult = bigDecimalResult.negate();
+            }
+            return bigDecimalResult;
+        } else {
+            boolean gotDouble = true;
+            boolean gotLongMinimum = false;
+            double  doubleResult = 0.0;
+            long    longResult = 0;
+
+            // Finally, have DigitList parse the digits into a value.
+            if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
+                gotDouble = false;
+                longResult = digitList.getLong();
+                if (longResult < 0) {  // got Long.MIN_VALUE
+                    gotLongMinimum = true;
+                }
+            } else {
+                doubleResult = digitList.getDouble();
+            }
+
+            // Divide by multiplier. We have to be careful here not to do
+            // unneeded conversions between double and long.
+            if (multiplier != 1) {
+                if (gotDouble) {
+                    doubleResult /= multiplier;
+                } else {
+                    // Avoid converting to double if we can
+                    if (longResult % multiplier == 0) {
+                        longResult /= multiplier;
+                    } else {
+                        doubleResult = ((double)longResult) / multiplier;
+                        gotDouble = true;
+                    }
+                }
+            }
+
+            if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
+                doubleResult = -doubleResult;
+                longResult = -longResult;
+            }
+
+            // At this point, if we divided the result by the multiplier, the
+            // result may fit into a long.  We check for this case and return
+            // a long if possible.
+            // We must do this AFTER applying the negative (if appropriate)
+            // in order to handle the case of LONG_MIN; otherwise, if we do
+            // this with a positive value -LONG_MIN, the double is > 0, but
+            // the long is < 0. We also must retain a double in the case of
+            // -0.0, which will compare as == to a long 0 cast to a double
+            // (bug 4162852).
+            if (multiplier != 1 && gotDouble) {
+                longResult = (long)doubleResult;
+                gotDouble = ((doubleResult != (double)longResult) ||
+                            (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
+                            !isParseIntegerOnly();
+            }
+
+            return gotDouble ?
+                (Number)new Double(doubleResult) : (Number)new Long(longResult);
+        }
+        */
+        if (pos.index < 0 || pos.index >= text.length()) {
+            return null;
+        }
+
+        // This might return android.icu.math.BigDecimal, java.math.BigInteger or a primitive type.
+        Number number = icuDecimalFormat.parse(text, pos);
+        if (number == null) {
+            return null;
+        }
+        if (isParseBigDecimal()) {
+            if (number instanceof Long) {
+                return new BigDecimal(number.longValue());
+            }
+            if ((number instanceof Double) && !((Double) number).isInfinite()
+                    && !((Double) number).isNaN()) {
+                return new BigDecimal(number.toString());
+            }
+            if ((number instanceof Double) &&
+                    (((Double) number).isNaN() || ((Double) number).isInfinite())) {
+                return number;
+            }
+            if (number instanceof android.icu.math.BigDecimal) {
+                return ((android.icu.math.BigDecimal) number).toBigDecimal();
+            }
+        }
+        if ((number instanceof android.icu.math.BigDecimal) || (number instanceof BigInteger)) {
+            return number.doubleValue();
+        }
+        if (isParseIntegerOnly() && number.equals(new Double(-0.0))) {
+            return 0L;
+        }
+        return number;
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: Unused private helpers.
+    /*
+    /**
+     * Return a BigInteger multiplier.
+     *
+    private BigInteger getBigIntegerMultiplier() {
+        if (bigIntegerMultiplier == null) {
+            bigIntegerMultiplier = BigInteger.valueOf(multiplier);
+        }
+        return bigIntegerMultiplier;
+    }
+    private transient BigInteger bigIntegerMultiplier;
+
+    /**
+     * Return a BigDecimal multiplier.
+     *
+    private BigDecimal getBigDecimalMultiplier() {
+        if (bigDecimalMultiplier == null) {
+            bigDecimalMultiplier = new BigDecimal(multiplier);
+        }
+        return bigDecimalMultiplier;
+    }
+    private transient BigDecimal bigDecimalMultiplier;
+
+    private static final int STATUS_INFINITE = 0;
+    private static final int STATUS_POSITIVE = 1;
+    private static final int STATUS_LENGTH   = 2;
+
+    /**
+     * Parse the given text into a number.  The text is parsed beginning at
+     * parsePosition, until an unparseable character is seen.
+     * @param text The string to parse.
+     * @param parsePosition The position at which to being parsing.  Upon
+     * return, the first unparseable character.
+     * @param digits The DigitList to set to the parsed value.
+     * @param isExponent If true, parse an exponent.  This means no
+     * infinite values and integer only.
+     * @param status Upon return contains boolean status flags indicating
+     * whether the value was infinite and whether it was positive.
+     *
+    private final boolean subparse(String text, ParsePosition parsePosition,
+                   String positivePrefix, String negativePrefix,
+                   DigitList digits, boolean isExponent,
+                   boolean status[]) {
+        int position = parsePosition.index;
+        int oldStart = parsePosition.index;
+        int backup;
+        boolean gotPositive, gotNegative;
+
+        // check for positivePrefix; take longest
+        gotPositive = text.regionMatches(position, positivePrefix, 0,
+                                         positivePrefix.length());
+        gotNegative = text.regionMatches(position, negativePrefix, 0,
+                                         negativePrefix.length());
+
+        if (gotPositive && gotNegative) {
+            if (positivePrefix.length() > negativePrefix.length()) {
+                gotNegative = false;
+            } else if (positivePrefix.length() < negativePrefix.length()) {
+                gotPositive = false;
+            }
+        }
+
+        if (gotPositive) {
+            position += positivePrefix.length();
+        } else if (gotNegative) {
+            position += negativePrefix.length();
+        } else {
+            parsePosition.errorIndex = position;
+            return false;
+        }
+
+        // process digits or Inf, find decimal position
+        status[STATUS_INFINITE] = false;
+        if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
+                          symbols.getInfinity().length())) {
+            position += symbols.getInfinity().length();
+            status[STATUS_INFINITE] = true;
+        } else {
+            // We now have a string of digits, possibly with grouping symbols,
+            // and decimal points.  We want to process these into a DigitList.
+            // We don't want to put a bunch of leading zeros into the DigitList
+            // though, so we keep track of the location of the decimal point,
+            // put only significant digits into the DigitList, and adjust the
+            // exponent as needed.
+
+            digits.decimalAt = digits.count = 0;
+            char zero = symbols.getZeroDigit();
+            char decimal = isCurrencyFormat ?
+                symbols.getMonetaryDecimalSeparator() :
+                symbols.getDecimalSeparator();
+            char grouping = symbols.getGroupingSeparator();
+            String exponentString = symbols.getExponentSeparator();
+            boolean sawDecimal = false;
+            boolean sawExponent = false;
+            boolean sawDigit = false;
+            int exponent = 0; // Set to the exponent value, if any
+
+            // We have to track digitCount ourselves, because digits.count will
+            // pin when the maximum allowable digits is reached.
+            int digitCount = 0;
+
+            backup = -1;
+            for (; position < text.length(); ++position) {
+                char ch = text.charAt(position);
+
+                /* We recognize all digit ranges, not only the Latin digit range
+                 * '0'..'9'.  We do so by using the Character.digit() method,
+                 * which converts a valid Unicode digit to the range 0..9.
+                 *
+                 * The character 'ch' may be a digit.  If so, place its value
+                 * from 0 to 9 in 'digit'.  First try using the locale digit,
+                 * which may or MAY NOT be a standard Unicode digit range.  If
+                 * this fails, try using the standard Unicode digit ranges by
+                 * calling Character.digit().  If this also fails, digit will
+                 * have a value outside the range 0..9.
+                 *
+                int digit = ch - zero;
+                if (digit < 0 || digit > 9) {
+                    digit = Character.digit(ch, 10);
+                }
+
+                if (digit == 0) {
+                    // Cancel out backup setting (see grouping handler below)
+                    backup = -1; // Do this BEFORE continue statement below!!!
+                    sawDigit = true;
+
+                    // Handle leading zeros
+                    if (digits.count == 0) {
+                        // Ignore leading zeros in integer part of number.
+                        if (!sawDecimal) {
+                            continue;
+                        }
+
+                        // If we have seen the decimal, but no significant
+                        // digits yet, then we account for leading zeros by
+                        // decrementing the digits.decimalAt into negative
+                        // values.
+                        --digits.decimalAt;
+                    } else {
+                        ++digitCount;
+                        digits.append((char)(digit + '0'));
+                    }
+                } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
+                    sawDigit = true;
+                    ++digitCount;
+                    digits.append((char)(digit + '0'));
+
+                    // Cancel out backup setting (see grouping handler below)
+                    backup = -1;
+                } else if (!isExponent && ch == decimal) {
+                    // If we're only parsing integers, or if we ALREADY saw the
+                    // decimal, then don't parse this one.
+                    if (isParseIntegerOnly() || sawDecimal) {
+                        break;
+                    }
+                    digits.decimalAt = digitCount; // Not digits.count!
+                    sawDecimal = true;
+                } else if (!isExponent && ch == grouping && isGroupingUsed()) {
+                    if (sawDecimal) {
+                        break;
+                    }
+                    // Ignore grouping characters, if we are using them, but
+                    // require that they be followed by a digit.  Otherwise
+                    // we backup and reprocess them.
+                    backup = position;
+                } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
+                             && !sawExponent) {
+                    // Process the exponent by recursively calling this method.
+                     ParsePosition pos = new ParsePosition(position + exponentString.length());
+                    boolean[] stat = new boolean[STATUS_LENGTH];
+                    DigitList exponentDigits = new DigitList();
+
+                    if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
+                        exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
+                        position = pos.index; // Advance past the exponent
+                        exponent = (int)exponentDigits.getLong();
+                        if (!stat[STATUS_POSITIVE]) {
+                            exponent = -exponent;
+                        }
+                        sawExponent = true;
+                    }
+                    break; // Whether we fail or succeed, we exit this loop
+                } else {
+                    break;
+                }
+            }
+
+            if (backup != -1) {
+                position = backup;
+            }
+
+            // If there was no decimal point we have an integer
+            if (!sawDecimal) {
+                digits.decimalAt = digitCount; // Not digits.count!
+            }
+
+            // Adjust for exponent, if any
+            digits.decimalAt += exponent;
+
+            // If none of the text string was recognized.  For example, parse
+            // "x" with pattern "#0.00" (return index and error index both 0)
+            // parse "$" with pattern "$#0.00". (return index 0 and error
+            // index 1).
+            if (!sawDigit && digitCount == 0) {
+                parsePosition.index = oldStart;
+                parsePosition.errorIndex = oldStart;
+                return false;
+            }
+        }
+
+        // check for suffix
+        if (!isExponent) {
+            if (gotPositive) {
+                gotPositive = text.regionMatches(position,positiveSuffix,0,
+                                                 positiveSuffix.length());
+            }
+            if (gotNegative) {
+                gotNegative = text.regionMatches(position,negativeSuffix,0,
+                                                 negativeSuffix.length());
+            }
+
+        // if both match, take longest
+        if (gotPositive && gotNegative) {
+            if (positiveSuffix.length() > negativeSuffix.length()) {
+                gotNegative = false;
+            } else if (positiveSuffix.length() < negativeSuffix.length()) {
+                gotPositive = false;
+            }
+        }
+
+        // fail if neither or both
+        if (gotPositive == gotNegative) {
+            parsePosition.errorIndex = position;
+            return false;
+        }
+
+        parsePosition.index = position +
+            (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
+        } else {
+            parsePosition.index = position;
+        }
+
+        status[STATUS_POSITIVE] = gotPositive;
+        if (parsePosition.index == oldStart) {
+            parsePosition.errorIndex = position;
+            return false;
+        }
+        return true;
+    }
+    */
+    // END Android-removed: Unused private helpers.
+
+    /**
+     * Returns a copy of the decimal format symbols, which is generally not
+     * changed by the programmer or user.
+     * @return a copy of the desired DecimalFormatSymbols
+     * @see java.text.DecimalFormatSymbols
+     */
+    public DecimalFormatSymbols getDecimalFormatSymbols() {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        try {
+            // don't allow multiple references
+            return (DecimalFormatSymbols) symbols.clone();
+        } catch (Exception foo) {
+            return null; // should never happen
+        }
+        */
+        return DecimalFormatSymbols.fromIcuInstance(icuDecimalFormat.getDecimalFormatSymbols());
+        // END Android-changed: Use ICU.
+    }
+
+
+    /**
+     * Sets the decimal format symbols, which is generally not changed
+     * by the programmer or user.
+     * @param newSymbols desired DecimalFormatSymbols
+     * @see java.text.DecimalFormatSymbols
+     */
+    public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
+        try {
+            // don't allow multiple references
+            symbols = (DecimalFormatSymbols) newSymbols.clone();
+            // BEGIN Android-changed: Use ICU.
+            /*
+            expandAffixes();
+            fastPathCheckNeeded = true;
+            */
+            icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols());
+            // END Android-changed: Use ICU.
+        } catch (Exception foo) {
+            // should never happen
+        }
+    }
+
+    /**
+     * Get the positive prefix.
+     * <P>Examples: +123, $123, sFr123
+     *
+     * @return the positive prefix
+     */
+    public String getPositivePrefix () {
+        // Android-changed: Use ICU.
+        // return positivePrefix;
+        return icuDecimalFormat.getPositivePrefix();
+    }
+
+    /**
+     * Set the positive prefix.
+     * <P>Examples: +123, $123, sFr123
+     *
+     * @param newValue the new positive prefix
+     */
+    public void setPositivePrefix (String newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        positivePrefix = newValue;
+        posPrefixPattern = null;
+        positivePrefixFieldPositions = null;
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setPositivePrefix(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: private helper getPositivePrefixFieldPositions().
+    /*
+    /**
+     * Returns the FieldPositions of the fields in the prefix used for
+     * positive numbers. This is not used if the user has explicitly set
+     * a positive prefix via <code>setPositivePrefix</code>. This is
+     * lazily created.
+     *
+     * @return FieldPositions in positive prefix
+     *
+    private FieldPosition[] getPositivePrefixFieldPositions() {
+        if (positivePrefixFieldPositions == null) {
+            if (posPrefixPattern != null) {
+                positivePrefixFieldPositions = expandAffix(posPrefixPattern);
+            } else {
+                positivePrefixFieldPositions = EmptyFieldPositionArray;
+            }
+        }
+        return positivePrefixFieldPositions;
+    }
+    */
+    // END Android-removed: private helper getPositivePrefixFieldPositions().
+
+    /**
+     * Get the negative prefix.
+     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
+     *
+     * @return the negative prefix
+     */
+    public String getNegativePrefix () {
+        // Android-changed: Use ICU.
+        // return negativePrefix;
+        return icuDecimalFormat.getNegativePrefix();
+    }
+
+    /**
+     * Set the negative prefix.
+     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
+     *
+     * @param newValue the new negative prefix
+     */
+    public void setNegativePrefix (String newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        negativePrefix = newValue;
+        negPrefixPattern = null;
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setNegativePrefix(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: private helper getNegativePrefixFieldPositions().
+    /*
+    /**
+     * Returns the FieldPositions of the fields in the prefix used for
+     * negative numbers. This is not used if the user has explicitly set
+     * a negative prefix via <code>setNegativePrefix</code>. This is
+     * lazily created.
+     *
+     * @return FieldPositions in positive prefix
+     *
+    private FieldPosition[] getNegativePrefixFieldPositions() {
+        if (negativePrefixFieldPositions == null) {
+            if (negPrefixPattern != null) {
+                negativePrefixFieldPositions = expandAffix(negPrefixPattern);
+            } else {
+                negativePrefixFieldPositions = EmptyFieldPositionArray;
+            }
+        }
+        return negativePrefixFieldPositions;
+    }
+    */
+    // END Android-removed: private helper getNegativePrefixFieldPositions().
+
+    /**
+     * Get the positive suffix.
+     * <P>Example: 123%
+     *
+     * @return the positive suffix
+     */
+    public String getPositiveSuffix () {
+        // Android-changed: Use ICU.
+        // return positiveSuffix;
+        return icuDecimalFormat.getPositiveSuffix();
+    }
+
+    /**
+     * Set the positive suffix.
+     * <P>Example: 123%
+     *
+     * @param newValue the new positive suffix
+     */
+    public void setPositiveSuffix (String newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        positiveSuffix = newValue;
+        posSuffixPattern = null;
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setPositiveSuffix(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: private helper getPositiveSuffixFieldPositions().
+    /*
+    /**
+     * Returns the FieldPositions of the fields in the suffix used for
+     * positive numbers. This is not used if the user has explicitly set
+     * a positive suffix via <code>setPositiveSuffix</code>. This is
+     * lazily created.
+     *
+     * @return FieldPositions in positive prefix
+     *
+    private FieldPosition[] getPositiveSuffixFieldPositions() {
+        if (positiveSuffixFieldPositions == null) {
+            if (posSuffixPattern != null) {
+                positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
+            } else {
+                positiveSuffixFieldPositions = EmptyFieldPositionArray;
+            }
+        }
+        return positiveSuffixFieldPositions;
+    }
+    */
+    // END Android-removed: private helper getPositiveSuffixFieldPositions().
+
+    /**
+     * Get the negative suffix.
+     * <P>Examples: -123%, ($123) (with positive suffixes)
+     *
+     * @return the negative suffix
+     */
+    public String getNegativeSuffix () {
+        // Android-changed: Use ICU.
+        // return negativeSuffix;
+        return icuDecimalFormat.getNegativeSuffix();
+    }
+
+    /**
+     * Set the negative suffix.
+     * <P>Examples: 123%
+     *
+     * @param newValue the new negative suffix
+     */
+    public void setNegativeSuffix (String newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        negativeSuffix = newValue;
+        negSuffixPattern = null;
+        fastPathCheckNeeded = true;
+         */
+        icuDecimalFormat.setNegativeSuffix(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-removed: private helper getNegativeSuffixFieldPositions().
+    /*
+    /**
+     * Returns the FieldPositions of the fields in the suffix used for
+     * negative numbers. This is not used if the user has explicitly set
+     * a negative suffix via <code>setNegativeSuffix</code>. This is
+     * lazily created.
+     *
+     * @return FieldPositions in positive prefix
+     *
+    private FieldPosition[] getNegativeSuffixFieldPositions() {
+        if (negativeSuffixFieldPositions == null) {
+            if (negSuffixPattern != null) {
+                negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
+            } else {
+                negativeSuffixFieldPositions = EmptyFieldPositionArray;
+            }
+        }
+        return negativeSuffixFieldPositions;
+    }
+    */
+    // END Android-removed: private helper getNegativeSuffixFieldPositions().
+
+    /**
+     * Gets the multiplier for use in percent, per mille, and similar
+     * formats.
+     *
+     * @return the multiplier
+     * @see #setMultiplier(int)
+     */
+    public int getMultiplier () {
+        // Android-changed: Use ICU.
+        // return multiplier;
+        return icuDecimalFormat.getMultiplier();
+    }
+
+    /**
+     * Sets the multiplier for use in percent, per mille, and similar
+     * formats.
+     * For a percent format, set the multiplier to 100 and the suffixes to
+     * have '%' (for Arabic, use the Arabic percent sign).
+     * For a per mille format, set the multiplier to 1000 and the suffixes to
+     * have '&#92;u2030'.
+     *
+     * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
+     * "123" is parsed into 1.23.
+     *
+     * @param newValue the new multiplier
+     * @see #getMultiplier
+     */
+    public void setMultiplier (int newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        multiplier = newValue;
+        bigDecimalMultiplier = null;
+        bigIntegerMultiplier = null;
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setMultiplier(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setGroupingUsed(boolean newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        super.setGroupingUsed(newValue);
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setGroupingUsed(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    // BEGIN Android-added: isGroupingUsed() override delegating to ICU.
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isGroupingUsed() {
+        return icuDecimalFormat.isGroupingUsed();
+    }
+    // END Android-added: isGroupingUsed() override delegating to ICU.
+
+    /**
+     * Return the grouping size. Grouping size is the number of digits between
+     * grouping separators in the integer portion of a number.  For example,
+     * in the number "123,456.78", the grouping size is 3.
+     *
+     * @return the grouping size
+     * @see #setGroupingSize
+     * @see java.text.NumberFormat#isGroupingUsed
+     * @see java.text.DecimalFormatSymbols#getGroupingSeparator
+     */
+    public int getGroupingSize () {
+        // Android-changed: Use ICU.
+        // return groupingSize;
+        return icuDecimalFormat.getGroupingSize();
+    }
+
+    /**
+     * Set the grouping size. Grouping size is the number of digits between
+     * grouping separators in the integer portion of a number.  For example,
+     * in the number "123,456.78", the grouping size is 3.
+     * <br>
+     * The value passed in is converted to a byte, which may lose information.
+     *
+     * @param newValue the new grouping size
+     * @see #getGroupingSize
+     * @see java.text.NumberFormat#setGroupingUsed
+     * @see java.text.DecimalFormatSymbols#setGroupingSeparator
+     */
+    public void setGroupingSize (int newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        groupingSize = (byte)newValue;
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setGroupingSize(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Allows you to get the behavior of the decimal separator with integers.
+     * (The decimal separator will always appear with decimals.)
+     * <P>Example: Decimal ON: 12345 &rarr; 12345.; OFF: 12345 &rarr; 12345
+     *
+     * @return {@code true} if the decimal separator is always shown;
+     *         {@code false} otherwise
+     */
+    public boolean isDecimalSeparatorAlwaysShown() {
+        // Android-changed: Use ICU.
+        // return decimalSeparatorAlwaysShown;
+        return icuDecimalFormat.isDecimalSeparatorAlwaysShown();
+    }
+
+    /**
+     * Allows you to set the behavior of the decimal separator with integers.
+     * (The decimal separator will always appear with decimals.)
+     * <P>Example: Decimal ON: 12345 &rarr; 12345.; OFF: 12345 &rarr; 12345
+     *
+     * @param newValue {@code true} if the decimal separator is always shown;
+     *                 {@code false} otherwise
+     */
+    public void setDecimalSeparatorAlwaysShown(boolean newValue) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        decimalSeparatorAlwaysShown = newValue;
+        fastPathCheckNeeded = true;
+        */
+        icuDecimalFormat.setDecimalSeparatorAlwaysShown(newValue);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
+     * method returns <code>BigDecimal</code>. The default value is false.
+     *
+     * @return {@code true} if the parse method returns BigDecimal;
+     *         {@code false} otherwise
+     * @see #setParseBigDecimal
+     * @since 1.5
+     */
+    public boolean isParseBigDecimal() {
+        // Android-changed: Use ICU.
+        // return parseBigDecimal;
+        return icuDecimalFormat.isParseBigDecimal();
+    }
+
+    /**
+     * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
+     * method returns <code>BigDecimal</code>.
+     *
+     * @param newValue {@code true} if the parse method returns BigDecimal;
+     *                 {@code false} otherwise
+     * @see #isParseBigDecimal
+     * @since 1.5
+     */
+    public void setParseBigDecimal(boolean newValue) {
+        // Android-changed: Use ICU.
+        // parseBigDecimal = newValue;
+        icuDecimalFormat.setParseBigDecimal(newValue);
+    }
+
+    // BEGIN Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU.
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isParseIntegerOnly() {
+        return icuDecimalFormat.isParseIntegerOnly();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setParseIntegerOnly(boolean value) {
+        super.setParseIntegerOnly(value);
+        icuDecimalFormat.setParseIntegerOnly(value);
+    }
+    // END Android-added: setParseIntegerOnly()/isParseIntegerOnly() overrides delegating to ICU.
+
+    /**
+     * Standard override; no change in semantics.
+     */
+    @Override
+    public Object clone() {
+        // BEGIN Android-changed: Use ICU, remove fast path related code.
+        /*
+        DecimalFormat other = (DecimalFormat) super.clone();
+        other.symbols = (DecimalFormatSymbols) symbols.clone();
+        other.digitList = (DigitList) digitList.clone();
+
+        // Fast-path is almost stateless algorithm. The only logical state is the
+        // isFastPath flag. In addition fastPathCheckNeeded is a sentinel flag
+        // that forces recalculation of all fast-path fields when set to true.
+        //
+        // There is thus no need to clone all the fast-path fields.
+        // We just only need to set fastPathCheckNeeded to true when cloning,
+        // and init fastPathData to null as if it were a truly new instance.
+        // Every fast-path field will be recalculated (only once) at next usage of
+        // fast-path algorithm.
+        other.fastPathCheckNeeded = true;
+        other.isFastPath = false;
+        other.fastPathData = null;
+
+        return other;
+        */
+        try {
+            DecimalFormat other = (DecimalFormat) super.clone();
+            other.icuDecimalFormat = (android.icu.text.DecimalFormat) icuDecimalFormat.clone();
+            other.symbols = (DecimalFormatSymbols) symbols.clone();
+            return other;
+        } catch (Exception e) {
+            throw new InternalError();
+        }
+        // END Android-changed: Use ICU, remove fast path related code.
+    }
+
+    /**
+     * Overrides equals
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+    // BEGIN Android-changed: re-implement equals() using ICU fields.
+        /*
+        if (obj == null)
+            return false;
+        if (!super.equals(obj))
+            return false; // super does class check
+        DecimalFormat other = (DecimalFormat) obj;
+        return ((posPrefixPattern == other.posPrefixPattern &&
+                 positivePrefix.equals(other.positivePrefix))
+                || (posPrefixPattern != null &&
+                    posPrefixPattern.equals(other.posPrefixPattern)))
+            && ((posSuffixPattern == other.posSuffixPattern &&
+                 positiveSuffix.equals(other.positiveSuffix))
+                || (posSuffixPattern != null &&
+                    posSuffixPattern.equals(other.posSuffixPattern)))
+            && ((negPrefixPattern == other.negPrefixPattern &&
+                 negativePrefix.equals(other.negativePrefix))
+                || (negPrefixPattern != null &&
+                    negPrefixPattern.equals(other.negPrefixPattern)))
+            && ((negSuffixPattern == other.negSuffixPattern &&
+                 negativeSuffix.equals(other.negativeSuffix))
+                || (negSuffixPattern != null &&
+                    negSuffixPattern.equals(other.negSuffixPattern)))
+            && multiplier == other.multiplier
+            && groupingSize == other.groupingSize
+            && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
+            && parseBigDecimal == other.parseBigDecimal
+            && useExponentialNotation == other.useExponentialNotation
+            && (!useExponentialNotation ||
+                minExponentDigits == other.minExponentDigits)
+            && maximumIntegerDigits == other.maximumIntegerDigits
+            && minimumIntegerDigits == other.minimumIntegerDigits
+            && maximumFractionDigits == other.maximumFractionDigits
+            && minimumFractionDigits == other.minimumFractionDigits
+            && roundingMode == other.roundingMode
+            && symbols.equals(other.symbols);
+        */
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof DecimalFormat)) {
+            return false;
+        }
+        DecimalFormat other = (DecimalFormat) obj;
+        return icuDecimalFormat.equals(other.icuDecimalFormat)
+            && compareIcuRoundingIncrement(other.icuDecimalFormat);
+    }
+
+    private boolean compareIcuRoundingIncrement(android.icu.text.DecimalFormat other) {
+        BigDecimal increment = this.icuDecimalFormat.getRoundingIncrement();
+        if (increment != null) {
+            return (other.getRoundingIncrement() != null)
+                && increment.equals(other.getRoundingIncrement());
+        }
+        return other.getRoundingIncrement() == null;
+    }
+    // END Android-changed: re-implement equals() using ICU fields.
+
+    /**
+     * Overrides hashCode
+     */
+    @Override
+    public int hashCode() {
+        // Android-changed: use getPositivePrefix() instead of positivePrefix field.
+        // return super.hashCode() * 37 + positivePrefix.hashCode();
+        return super.hashCode() * 37 + getPositivePrefix().hashCode();
+        // just enough fields for a reasonable distribution
+    }
+
+    /**
+     * Synthesizes a pattern string that represents the current state
+     * of this Format object.
+     *
+     * @return a pattern string
+     * @see #applyPattern
+     */
+    public String toPattern() {
+        // Android-changed: use ICU.
+        // return toPattern( false );
+        return icuDecimalFormat.toPattern();
+    }
+
+    /**
+     * Synthesizes a localized pattern string that represents the current
+     * state of this Format object.
+     *
+     * @return a localized pattern string
+     * @see #applyPattern
+     */
+    public String toLocalizedPattern() {
+        // Android-changed: use ICU.
+        // return toPattern( true );
+        return icuDecimalFormat.toLocalizedPattern();
+    }
+
+    // BEGIN Android-removed: Unused private helpers.
+    /*
+    /**
+     * Expand the affix pattern strings into the expanded affix strings.  If any
+     * affix pattern string is null, do not expand it.  This method should be
+     * called any time the symbols or the affix patterns change in order to keep
+     * the expanded affix strings up to date.
+     *
+    private void expandAffixes() {
+        // Reuse one StringBuffer for better performance
+        StringBuffer buffer = new StringBuffer();
+        if (posPrefixPattern != null) {
+            positivePrefix = expandAffix(posPrefixPattern, buffer);
+            positivePrefixFieldPositions = null;
+        }
+        if (posSuffixPattern != null) {
+            positiveSuffix = expandAffix(posSuffixPattern, buffer);
+            positiveSuffixFieldPositions = null;
+        }
+        if (negPrefixPattern != null) {
+            negativePrefix = expandAffix(negPrefixPattern, buffer);
+            negativePrefixFieldPositions = null;
+        }
+        if (negSuffixPattern != null) {
+            negativeSuffix = expandAffix(negSuffixPattern, buffer);
+            negativeSuffixFieldPositions = null;
+        }
+    }
+
+    /**
+     * Expand an affix pattern into an affix string.  All characters in the
+     * pattern are literal unless prefixed by QUOTE.  The following characters
+     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
+     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
+     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
+     * currency code.  Any other character after a QUOTE represents itself.
+     * QUOTE must be followed by another character; QUOTE may not occur by
+     * itself at the end of the pattern.
+     *
+     * @param pattern the non-null, possibly empty pattern
+     * @param buffer a scratch StringBuffer; its contents will be lost
+     * @return the expanded equivalent of pattern
+     *
+    private String expandAffix(String pattern, StringBuffer buffer) {
+        buffer.setLength(0);
+        for (int i=0; i<pattern.length(); ) {
+            char c = pattern.charAt(i++);
+            if (c == QUOTE) {
+                c = pattern.charAt(i++);
+                switch (c) {
+                case CURRENCY_SIGN:
+                    if (i<pattern.length() &&
+                        pattern.charAt(i) == CURRENCY_SIGN) {
+                        ++i;
+                        buffer.append(symbols.getInternationalCurrencySymbol());
+                    } else {
+                        buffer.append(symbols.getCurrencySymbol());
+                    }
+                    continue;
+                case PATTERN_PERCENT:
+                    c = symbols.getPercent();
+                    break;
+                case PATTERN_PER_MILLE:
+                    c = symbols.getPerMill();
+                    break;
+                case PATTERN_MINUS:
+                    c = symbols.getMinusSign();
+                    break;
+                }
+            }
+            buffer.append(c);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Expand an affix pattern into an array of FieldPositions describing
+     * how the pattern would be expanded.
+     * All characters in the
+     * pattern are literal unless prefixed by QUOTE.  The following characters
+     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
+     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
+     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
+     * currency code.  Any other character after a QUOTE represents itself.
+     * QUOTE must be followed by another character; QUOTE may not occur by
+     * itself at the end of the pattern.
+     *
+     * @param pattern the non-null, possibly empty pattern
+     * @return FieldPosition array of the resulting fields.
+     *
+    private FieldPosition[] expandAffix(String pattern) {
+        ArrayList<FieldPosition> positions = null;
+        int stringIndex = 0;
+        for (int i=0; i<pattern.length(); ) {
+            char c = pattern.charAt(i++);
+            if (c == QUOTE) {
+                int field = -1;
+                Format.Field fieldID = null;
+                c = pattern.charAt(i++);
+                switch (c) {
+                case CURRENCY_SIGN:
+                    String string;
+                    if (i<pattern.length() &&
+                        pattern.charAt(i) == CURRENCY_SIGN) {
+                        ++i;
+                        string = symbols.getInternationalCurrencySymbol();
+                    } else {
+                        string = symbols.getCurrencySymbol();
+                    }
+                    if (string.length() > 0) {
+                        if (positions == null) {
+                            positions = new ArrayList<>(2);
+                        }
+                        FieldPosition fp = new FieldPosition(Field.CURRENCY);
+                        fp.setBeginIndex(stringIndex);
+                        fp.setEndIndex(stringIndex + string.length());
+                        positions.add(fp);
+                        stringIndex += string.length();
+                    }
+                    continue;
+                case PATTERN_PERCENT:
+                    c = symbols.getPercent();
+                    field = -1;
+                    fieldID = Field.PERCENT;
+                    break;
+                case PATTERN_PER_MILLE:
+                    c = symbols.getPerMill();
+                    field = -1;
+                    fieldID = Field.PERMILLE;
+                    break;
+                case PATTERN_MINUS:
+                    c = symbols.getMinusSign();
+                    field = -1;
+                    fieldID = Field.SIGN;
+                    break;
+                }
+                if (fieldID != null) {
+                    if (positions == null) {
+                        positions = new ArrayList<>(2);
+                    }
+                    FieldPosition fp = new FieldPosition(fieldID, field);
+                    fp.setBeginIndex(stringIndex);
+                    fp.setEndIndex(stringIndex + 1);
+                    positions.add(fp);
+                }
+            }
+            stringIndex++;
+        }
+        if (positions != null) {
+            return positions.toArray(EmptyFieldPositionArray);
+        }
+        return EmptyFieldPositionArray;
+    }
+
+    /**
+     * Appends an affix pattern to the given StringBuffer, quoting special
+     * characters as needed.  Uses the internal affix pattern, if that exists,
+     * or the literal affix, if the internal affix pattern is null.  The
+     * appended string will generate the same affix pattern (or literal affix)
+     * when passed to toPattern().
+     *
+     * @param buffer the affix string is appended to this
+     * @param affixPattern a pattern such as posPrefixPattern; may be null
+     * @param expAffix a corresponding expanded affix, such as positivePrefix.
+     * Ignored unless affixPattern is null.  If affixPattern is null, then
+     * expAffix is appended as a literal affix.
+     * @param localized true if the appended pattern should contain localized
+     * pattern characters; otherwise, non-localized pattern chars are appended
+     *
+    private void appendAffix(StringBuffer buffer, String affixPattern,
+                             String expAffix, boolean localized) {
+        if (affixPattern == null) {
+            appendAffix(buffer, expAffix, localized);
+        } else {
+            int i;
+            for (int pos=0; pos<affixPattern.length(); pos=i) {
+                i = affixPattern.indexOf(QUOTE, pos);
+                if (i < 0) {
+                    appendAffix(buffer, affixPattern.substring(pos), localized);
+                    break;
+                }
+                if (i > pos) {
+                    appendAffix(buffer, affixPattern.substring(pos, i), localized);
+                }
+                char c = affixPattern.charAt(++i);
+                ++i;
+                if (c == QUOTE) {
+                    buffer.append(c);
+                    // Fall through and append another QUOTE below
+                } else if (c == CURRENCY_SIGN &&
+                           i<affixPattern.length() &&
+                           affixPattern.charAt(i) == CURRENCY_SIGN) {
+                    ++i;
+                    buffer.append(c);
+                    // Fall through and append another CURRENCY_SIGN below
+                } else if (localized) {
+                    switch (c) {
+                    case PATTERN_PERCENT:
+                        c = symbols.getPercent();
+                        break;
+                    case PATTERN_PER_MILLE:
+                        c = symbols.getPerMill();
+                        break;
+                    case PATTERN_MINUS:
+                        c = symbols.getMinusSign();
+                        break;
+                    }
+                }
+                buffer.append(c);
+            }
+        }
+    }
+
+    /**
+     * Append an affix to the given StringBuffer, using quotes if
+     * there are special characters.  Single quotes themselves must be
+     * escaped in either case.
+     *
+    private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
+        boolean needQuote;
+        if (localized) {
+            needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
+                || affix.indexOf(symbols.getGroupingSeparator()) >= 0
+                || affix.indexOf(symbols.getDecimalSeparator()) >= 0
+                || affix.indexOf(symbols.getPercent()) >= 0
+                || affix.indexOf(symbols.getPerMill()) >= 0
+                || affix.indexOf(symbols.getDigit()) >= 0
+                || affix.indexOf(symbols.getPatternSeparator()) >= 0
+                || affix.indexOf(symbols.getMinusSign()) >= 0
+                || affix.indexOf(CURRENCY_SIGN) >= 0;
+        } else {
+            needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
+                || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
+                || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
+                || affix.indexOf(PATTERN_PERCENT) >= 0
+                || affix.indexOf(PATTERN_PER_MILLE) >= 0
+                || affix.indexOf(PATTERN_DIGIT) >= 0
+                || affix.indexOf(PATTERN_SEPARATOR) >= 0
+                || affix.indexOf(PATTERN_MINUS) >= 0
+                || affix.indexOf(CURRENCY_SIGN) >= 0;
+        }
+        if (needQuote) buffer.append('\'');
+        if (affix.indexOf('\'') < 0) buffer.append(affix);
+        else {
+            for (int j=0; j<affix.length(); ++j) {
+                char c = affix.charAt(j);
+                buffer.append(c);
+                if (c == '\'') buffer.append(c);
+            }
+        }
+        if (needQuote) buffer.append('\'');
+    }
+
+    /**
+     * Does the real work of generating a pattern.  *
+    private String toPattern(boolean localized) {
+        StringBuffer result = new StringBuffer();
+        for (int j = 1; j >= 0; --j) {
+            if (j == 1)
+                appendAffix(result, posPrefixPattern, positivePrefix, localized);
+            else appendAffix(result, negPrefixPattern, negativePrefix, localized);
+            int i;
+            int digitCount = useExponentialNotation
+                        ? getMaximumIntegerDigits()
+                        : Math.max(groupingSize, getMinimumIntegerDigits())+1;
+            for (i = digitCount; i > 0; --i) {
+                if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
+                    i % groupingSize == 0) {
+                    result.append(localized ? symbols.getGroupingSeparator() :
+                                  PATTERN_GROUPING_SEPARATOR);
+                }
+                result.append(i <= getMinimumIntegerDigits()
+                    ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
+                    : (localized ? symbols.getDigit() : PATTERN_DIGIT));
+            }
+            if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
+                result.append(localized ? symbols.getDecimalSeparator() :
+                              PATTERN_DECIMAL_SEPARATOR);
+            for (i = 0; i < getMaximumFractionDigits(); ++i) {
+                if (i < getMinimumFractionDigits()) {
+                    result.append(localized ? symbols.getZeroDigit() :
+                                  PATTERN_ZERO_DIGIT);
+                } else {
+                    result.append(localized ? symbols.getDigit() :
+                                  PATTERN_DIGIT);
+                }
+            }
+        if (useExponentialNotation)
+        {
+            result.append(localized ? symbols.getExponentSeparator() :
+                  PATTERN_EXPONENT);
+        for (i=0; i<minExponentDigits; ++i)
+                    result.append(localized ? symbols.getZeroDigit() :
+                                  PATTERN_ZERO_DIGIT);
+        }
+            if (j == 1) {
+                appendAffix(result, posSuffixPattern, positiveSuffix, localized);
+                if ((negSuffixPattern == posSuffixPattern && // n == p == null
+                     negativeSuffix.equals(positiveSuffix))
+                    || (negSuffixPattern != null &&
+                        negSuffixPattern.equals(posSuffixPattern))) {
+                    if ((negPrefixPattern != null && posPrefixPattern != null &&
+                         negPrefixPattern.equals("'-" + posPrefixPattern)) ||
+                        (negPrefixPattern == posPrefixPattern && // n == p == null
+                         negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
+                        break;
+                }
+                result.append(localized ? symbols.getPatternSeparator() :
+                              PATTERN_SEPARATOR);
+            } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
+        }
+        return result.toString();
+    }
+    */
+    // END Android-removed: Unused private helpers.
+
+    /**
+     * Apply the given pattern to this Format object.  A pattern is a
+     * short-hand specification for the various formatting properties.
+     * These properties can also be changed individually through the
+     * various setter methods.
+     * <p>
+     * There is no limit to integer digits set
+     * by this routine, since that is the typical end-user desire;
+     * use setMaximumInteger if you want to set a real value.
+     * For negative numbers, use a second pattern, separated by a semicolon
+     * <P>Example <code>"#,#00.0#"</code> &rarr; 1,234.56
+     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
+     * a maximum of 2 fraction digits.
+     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
+     * parentheses.
+     * <p>In negative patterns, the minimum and maximum counts are ignored;
+     * these are presumed to be set in the positive pattern.
+     *
+     * @param pattern a new pattern
+     * @exception NullPointerException if <code>pattern</code> is null
+     * @exception IllegalArgumentException if the given pattern is invalid.
+     */
+    public void applyPattern(String pattern) {
+        // Android-changed: use ICU.
+        // applyPattern(pattern, false);
+        icuDecimalFormat.applyPattern(pattern);
+        updateFieldsFromIcu();
+    }
+
+    /**
+     * Apply the given pattern to this Format object.  The pattern
+     * is assumed to be in a localized notation. A pattern is a
+     * short-hand specification for the various formatting properties.
+     * These properties can also be changed individually through the
+     * various setter methods.
+     * <p>
+     * There is no limit to integer digits set
+     * by this routine, since that is the typical end-user desire;
+     * use setMaximumInteger if you want to set a real value.
+     * For negative numbers, use a second pattern, separated by a semicolon
+     * <P>Example <code>"#,#00.0#"</code> &rarr; 1,234.56
+     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
+     * a maximum of 2 fraction digits.
+     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
+     * parentheses.
+     * <p>In negative patterns, the minimum and maximum counts are ignored;
+     * these are presumed to be set in the positive pattern.
+     *
+     * @param pattern a new pattern
+     * @exception NullPointerException if <code>pattern</code> is null
+     * @exception IllegalArgumentException if the given pattern is invalid.
+     */
+    public void applyLocalizedPattern(String pattern) {
+        // Android-changed: use ICU.
+        // applyPattern(pattern, true);
+        icuDecimalFormat.applyLocalizedPattern(pattern);
+        updateFieldsFromIcu();
+    }
+
+    // BEGIN Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly.
+    /*
+    /**
+     * Does the real work of applying a pattern.
+     *
+    private void applyPattern(String pattern, boolean localized) {
+        char zeroDigit         = PATTERN_ZERO_DIGIT;
+        char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
+        char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
+        char percent           = PATTERN_PERCENT;
+        char perMill           = PATTERN_PER_MILLE;
+        char digit             = PATTERN_DIGIT;
+        char separator         = PATTERN_SEPARATOR;
+        String exponent          = PATTERN_EXPONENT;
+        char minus             = PATTERN_MINUS;
+        if (localized) {
+            zeroDigit         = symbols.getZeroDigit();
+            groupingSeparator = symbols.getGroupingSeparator();
+            decimalSeparator  = symbols.getDecimalSeparator();
+            percent           = symbols.getPercent();
+            perMill           = symbols.getPerMill();
+            digit             = symbols.getDigit();
+            separator         = symbols.getPatternSeparator();
+            exponent          = symbols.getExponentSeparator();
+            minus             = symbols.getMinusSign();
+        }
+        boolean gotNegative = false;
+        decimalSeparatorAlwaysShown = false;
+        isCurrencyFormat = false;
+        useExponentialNotation = false;
+
+        // Two variables are used to record the subrange of the pattern
+        // occupied by phase 1.  This is used during the processing of the
+        // second pattern (the one representing negative numbers) to ensure
+        // that no deviation exists in phase 1 between the two patterns.
+        int phaseOneStart = 0;
+        int phaseOneLength = 0;
+
+        int start = 0;
+        for (int j = 1; j >= 0 && start < pattern.length(); --j) {
+            boolean inQuote = false;
+            StringBuffer prefix = new StringBuffer();
+            StringBuffer suffix = new StringBuffer();
+            int decimalPos = -1;
+            int multiplier = 1;
+            int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
+            byte groupingCount = -1;
+
+            // The phase ranges from 0 to 2.  Phase 0 is the prefix.  Phase 1 is
+            // the section of the pattern with digits, decimal separator,
+            // grouping characters.  Phase 2 is the suffix.  In phases 0 and 2,
+            // percent, per mille, and currency symbols are recognized and
+            // translated.  The separation of the characters into phases is
+            // strictly enforced; if phase 1 characters are to appear in the
+            // suffix, for example, they must be quoted.
+            int phase = 0;
+
+            // The affix is either the prefix or the suffix.
+            StringBuffer affix = prefix;
+
+            for (int pos = start; pos < pattern.length(); ++pos) {
+                char ch = pattern.charAt(pos);
+                switch (phase) {
+                case 0:
+                case 2:
+                    // Process the prefix / suffix characters
+                    if (inQuote) {
+                        // A quote within quotes indicates either the closing
+                        // quote or two quotes, which is a quote literal. That
+                        // is, we have the second quote in 'do' or 'don''t'.
+                        if (ch == QUOTE) {
+                            if ((pos+1) < pattern.length() &&
+                                pattern.charAt(pos+1) == QUOTE) {
+                                ++pos;
+                                affix.append("''"); // 'don''t'
+                            } else {
+                                inQuote = false; // 'do'
+                            }
+                            continue;
+                        }
+                    } else {
+                        // Process unquoted characters seen in prefix or suffix
+                        // phase.
+                        if (ch == digit ||
+                            ch == zeroDigit ||
+                            ch == groupingSeparator ||
+                            ch == decimalSeparator) {
+                            phase = 1;
+                            if (j == 1) {
+                                phaseOneStart = pos;
+                            }
+                            --pos; // Reprocess this character
+                            continue;
+                        } else if (ch == CURRENCY_SIGN) {
+                            // Use lookahead to determine if the currency sign
+                            // is doubled or not.
+                            boolean doubled = (pos + 1) < pattern.length() &&
+                                pattern.charAt(pos + 1) == CURRENCY_SIGN;
+                            if (doubled) { // Skip over the doubled character
+                             ++pos;
+                            }
+                            isCurrencyFormat = true;
+                            affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
+                            continue;
+                        } else if (ch == QUOTE) {
+                            // A quote outside quotes indicates either the
+                            // opening quote or two quotes, which is a quote
+                            // literal. That is, we have the first quote in 'do'
+                            // or o''clock.
+                            if (ch == QUOTE) {
+                                if ((pos+1) < pattern.length() &&
+                                    pattern.charAt(pos+1) == QUOTE) {
+                                    ++pos;
+                                    affix.append("''"); // o''clock
+                                } else {
+                                    inQuote = true; // 'do'
+                                }
+                                continue;
+                            }
+                        } else if (ch == separator) {
+                            // Don't allow separators before we see digit
+                            // characters of phase 1, and don't allow separators
+                            // in the second pattern (j == 0).
+                            if (phase == 0 || j == 0) {
+                                throw new IllegalArgumentException("Unquoted special character '" +
+                                    ch + "' in pattern \"" + pattern + '"');
+                            }
+                            start = pos + 1;
+                            pos = pattern.length();
+                            continue;
+                        }
+
+                        // Next handle characters which are appended directly.
+                        else if (ch == percent) {
+                            if (multiplier != 1) {
+                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
+                                    pattern + '"');
+                            }
+                            multiplier = 100;
+                            affix.append("'%");
+                            continue;
+                        } else if (ch == perMill) {
+                            if (multiplier != 1) {
+                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
+                                    pattern + '"');
+                            }
+                            multiplier = 1000;
+                            affix.append("'\u2030");
+                            continue;
+                        } else if (ch == minus) {
+                            affix.append("'-");
+                            continue;
+                        }
+                    }
+                    // Note that if we are within quotes, or if this is an
+                    // unquoted, non-special character, then we usually fall
+                    // through to here.
+                    affix.append(ch);
+                    break;
+
+                case 1:
+                    // Phase one must be identical in the two sub-patterns. We
+                    // enforce this by doing a direct comparison. While
+                    // processing the first sub-pattern, we just record its
+                    // length. While processing the second, we compare
+                    // characters.
+                    if (j == 1) {
+                        ++phaseOneLength;
+                    } else {
+                        if (--phaseOneLength == 0) {
+                            phase = 2;
+                            affix = suffix;
+                        }
+                        continue;
+                    }
+
+                    // Process the digits, decimal, and grouping characters. We
+                    // record five pieces of information. We expect the digits
+                    // to occur in the pattern ####0000.####, and we record the
+                    // number of left digits, zero (central) digits, and right
+                    // digits. The position of the last grouping character is
+                    // recorded (should be somewhere within the first two blocks
+                    // of characters), as is the position of the decimal point,
+                    // if any (should be in the zero digits). If there is no
+                    // decimal point, then there should be no right digits.
+                    if (ch == digit) {
+                        if (zeroDigitCount > 0) {
+                            ++digitRightCount;
+                        } else {
+                            ++digitLeftCount;
+                        }
+                        if (groupingCount >= 0 && decimalPos < 0) {
+                            ++groupingCount;
+                        }
+                    } else if (ch == zeroDigit) {
+                        if (digitRightCount > 0) {
+                            throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
+                                pattern + '"');
+                        }
+                        ++zeroDigitCount;
+                        if (groupingCount >= 0 && decimalPos < 0) {
+                            ++groupingCount;
+                        }
+                    } else if (ch == groupingSeparator) {
+                        groupingCount = 0;
+                    } else if (ch == decimalSeparator) {
+                        if (decimalPos >= 0) {
+                            throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
+                                pattern + '"');
+                        }
+                        decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
+                    } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
+                        if (useExponentialNotation) {
+                            throw new IllegalArgumentException("Multiple exponential " +
+                                "symbols in pattern \"" + pattern + '"');
+                        }
+                        useExponentialNotation = true;
+                        minExponentDigits = 0;
+
+                        // Use lookahead to parse out the exponential part
+                        // of the pattern, then jump into phase 2.
+                        pos = pos+exponent.length();
+                         while (pos < pattern.length() &&
+                               pattern.charAt(pos) == zeroDigit) {
+                            ++minExponentDigits;
+                            ++phaseOneLength;
+                            ++pos;
+                        }
+
+                        if ((digitLeftCount + zeroDigitCount) < 1 ||
+                            minExponentDigits < 1) {
+                            throw new IllegalArgumentException("Malformed exponential " +
+                                "pattern \"" + pattern + '"');
+                        }
+
+                        // Transition to phase 2
+                        phase = 2;
+                        affix = suffix;
+                        --pos;
+                        continue;
+                    } else {
+                        phase = 2;
+                        affix = suffix;
+                        --pos;
+                        --phaseOneLength;
+                        continue;
+                    }
+                    break;
+                }
+            }
+
+            // Handle patterns with no '0' pattern character. These patterns
+            // are legal, but must be interpreted.  "##.###" -> "#0.###".
+            // ".###" -> ".0##".
+            /* We allow patterns of the form "####" to produce a zeroDigitCount
+             * of zero (got that?); although this seems like it might make it
+             * possible for format() to produce empty strings, format() checks
+             * for this condition and outputs a zero digit in this situation.
+             * Having a zeroDigitCount of zero yields a minimum integer digits
+             * of zero, which allows proper round-trip patterns.  That is, we
+             * don't want "#" to become "#0" when toPattern() is called (even
+             * though that's what it really is, semantically).
+             *
+            if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
+                // Handle "###.###" and "###." and ".###"
+                int n = decimalPos;
+                if (n == 0) { // Handle ".###"
+                    ++n;
+                }
+                digitRightCount = digitLeftCount - n;
+                digitLeftCount = n - 1;
+                zeroDigitCount = 1;
+            }
+
+            // Do syntax checking on the digits.
+            if ((decimalPos < 0 && digitRightCount > 0) ||
+                (decimalPos >= 0 && (decimalPos < digitLeftCount ||
+                 decimalPos > (digitLeftCount + zeroDigitCount))) ||
+                 groupingCount == 0 || inQuote) {
+                throw new IllegalArgumentException("Malformed pattern \"" +
+                    pattern + '"');
+            }
+
+            if (j == 1) {
+                posPrefixPattern = prefix.toString();
+                posSuffixPattern = suffix.toString();
+                negPrefixPattern = posPrefixPattern;   // assume these for now
+                negSuffixPattern = posSuffixPattern;
+                int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
+                /* The effectiveDecimalPos is the position the decimal is at or
+                 * would be at if there is no decimal. Note that if decimalPos<0,
+                 * then digitTotalCount == digitLeftCount + zeroDigitCount.
+                 *
+                int effectiveDecimalPos = decimalPos >= 0 ?
+                    decimalPos : digitTotalCount;
+                setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
+                setMaximumIntegerDigits(useExponentialNotation ?
+                    digitLeftCount + getMinimumIntegerDigits() :
+                    MAXIMUM_INTEGER_DIGITS);
+                setMaximumFractionDigits(decimalPos >= 0 ?
+                    (digitTotalCount - decimalPos) : 0);
+                setMinimumFractionDigits(decimalPos >= 0 ?
+                    (digitLeftCount + zeroDigitCount - decimalPos) : 0);
+                setGroupingUsed(groupingCount > 0);
+                this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
+                this.multiplier = multiplier;
+                setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
+                    decimalPos == digitTotalCount);
+            } else {
+                negPrefixPattern = prefix.toString();
+                negSuffixPattern = suffix.toString();
+                gotNegative = true;
+            }
+        }
+
+        if (pattern.length() == 0) {
+            posPrefixPattern = posSuffixPattern = "";
+            setMinimumIntegerDigits(0);
+            setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
+            setMinimumFractionDigits(0);
+            setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
+        }
+
+        // If there was no negative pattern, or if the negative pattern is
+        // identical to the positive pattern, then prepend the minus sign to
+        // the positive pattern to form the negative pattern.
+        if (!gotNegative ||
+            (negPrefixPattern.equals(posPrefixPattern)
+             && negSuffixPattern.equals(posSuffixPattern))) {
+            negSuffixPattern = posSuffixPattern;
+            negPrefixPattern = "'-" + posPrefixPattern;
+        }
+
+        expandAffixes();
+    }
+    */
+    // END Android-removed: applyPattern(String, boolean) as apply[Localized]Pattern calls ICU directly.
+
+    /**
+     * Sets the maximum number of digits allowed in the integer portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
+     * 309 is used. Negative input values are replaced with 0.
+     * @see NumberFormat#setMaximumIntegerDigits
+     */
+    @Override
+    public void setMaximumIntegerDigits(int newValue) {
+        maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
+        super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
+            DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
+        if (minimumIntegerDigits > maximumIntegerDigits) {
+            minimumIntegerDigits = maximumIntegerDigits;
+            super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
+                DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
+        }
+        // Android-added: use ICU.
+        icuDecimalFormat.setMaximumIntegerDigits(getMaximumIntegerDigits());
+        // Android-removed: fast path related code.
+        // fastPathCheckNeeded = true;
+    }
+
+    /**
+     * Sets the minimum number of digits allowed in the integer portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
+     * 309 is used. Negative input values are replaced with 0.
+     * @see NumberFormat#setMinimumIntegerDigits
+     */
+    @Override
+    public void setMinimumIntegerDigits(int newValue) {
+        minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
+        super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
+            DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
+        if (minimumIntegerDigits > maximumIntegerDigits) {
+            maximumIntegerDigits = minimumIntegerDigits;
+            super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
+                DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
+        }
+        // Android-added: use ICU.
+        icuDecimalFormat.setMinimumIntegerDigits(getMinimumIntegerDigits());
+        // Android-removed: fast path related code.
+        // fastPathCheckNeeded = true;
+    }
+
+    /**
+     * Sets the maximum number of digits allowed in the fraction portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
+     * 340 is used. Negative input values are replaced with 0.
+     * @see NumberFormat#setMaximumFractionDigits
+     */
+    @Override
+    public void setMaximumFractionDigits(int newValue) {
+        maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
+        super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
+            DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
+        if (minimumFractionDigits > maximumFractionDigits) {
+            minimumFractionDigits = maximumFractionDigits;
+            super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
+                DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
+        }
+        // Android-added: use ICU.
+        icuDecimalFormat.setMaximumFractionDigits(getMaximumFractionDigits());
+        // Android-removed: fast path related code.
+        // fastPathCheckNeeded = true;
+    }
+
+    /**
+     * Sets the minimum number of digits allowed in the fraction portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
+     * 340 is used. Negative input values are replaced with 0.
+     * @see NumberFormat#setMinimumFractionDigits
+     */
+    @Override
+    public void setMinimumFractionDigits(int newValue) {
+        minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
+        super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
+            DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
+        if (minimumFractionDigits > maximumFractionDigits) {
+            maximumFractionDigits = minimumFractionDigits;
+            super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
+                DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
+        }
+        // Android-added: use ICU.
+        icuDecimalFormat.setMinimumFractionDigits(getMinimumFractionDigits());
+        // Android-removed: fast path related code.
+        // fastPathCheckNeeded = true;
+    }
+
+    /**
+     * Gets the maximum number of digits allowed in the integer portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of the return value and
+     * 309 is used.
+     * @see #setMaximumIntegerDigits
+     */
+    @Override
+    public int getMaximumIntegerDigits() {
+        return maximumIntegerDigits;
+    }
+
+    /**
+     * Gets the minimum number of digits allowed in the integer portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of the return value and
+     * 309 is used.
+     * @see #setMinimumIntegerDigits
+     */
+    @Override
+    public int getMinimumIntegerDigits() {
+        return minimumIntegerDigits;
+    }
+
+    /**
+     * Gets the maximum number of digits allowed in the fraction portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of the return value and
+     * 340 is used.
+     * @see #setMaximumFractionDigits
+     */
+    @Override
+    public int getMaximumFractionDigits() {
+        return maximumFractionDigits;
+    }
+
+    /**
+     * Gets the minimum number of digits allowed in the fraction portion of a
+     * number.
+     * For formatting numbers other than <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects, the lower of the return value and
+     * 340 is used.
+     * @see #setMinimumFractionDigits
+     */
+    @Override
+    public int getMinimumFractionDigits() {
+        return minimumFractionDigits;
+    }
+
+    /**
+     * Gets the currency used by this decimal format when formatting
+     * currency values.
+     * The currency is obtained by calling
+     * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
+     * on this number format's symbols.
+     *
+     * @return the currency used by this decimal format, or <code>null</code>
+     * @since 1.4
+     */
+    @Override
+    public Currency getCurrency() {
+        return symbols.getCurrency();
+    }
+
+    /**
+     * Sets the currency used by this number format when formatting
+     * currency values. This does not update the minimum or maximum
+     * number of fraction digits used by the number format.
+     * The currency is set by calling
+     * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
+     * on this number format's symbols.
+     *
+     * @param currency the new currency to be used by this decimal format
+     * @exception NullPointerException if <code>currency</code> is null
+     * @since 1.4
+     */
+    @Override
+    public void setCurrency(Currency currency) {
+        // BEGIN Android-changed: use ICU.
+        // Set the international currency symbol, and currency symbol on the DecimalFormatSymbols
+        // object and tell ICU to use that.
+        /*
+        if (currency != symbols.getCurrency()) {
+            symbols.setCurrency(currency);
+            if (isCurrencyFormat) {
+                expandAffixes();
+            }
+        }
+        */
+        if (currency != symbols.getCurrency()
+            || !currency.getSymbol().equals(symbols.getCurrencySymbol())) {
+            symbols.setCurrency(currency);
+            icuDecimalFormat.setDecimalFormatSymbols(symbols.getIcuDecimalFormatSymbols());
+            // Giving the icuDecimalFormat a new currency will cause the fractional digits to be
+            // updated. This class is specified to not touch the fraction digits, so we re-set them.
+            icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits);
+            icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits);
+        }
+        // END Android-changed: use ICU.
+        // Android-removed: fast path related code.
+        // fastPathCheckNeeded = true;
+    }
+
+    /**
+     * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
+     *
+     * @return The <code>RoundingMode</code> used for this DecimalFormat.
+     * @see #setRoundingMode(RoundingMode)
+     * @since 1.6
+     */
+    @Override
+    public RoundingMode getRoundingMode() {
+        return roundingMode;
+    }
+
+    // BEGIN Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums.
+    private static int convertRoundingMode(RoundingMode rm) {
+        switch (rm) {
+        case UP:
+            return MathContext.ROUND_UP;
+        case DOWN:
+            return MathContext.ROUND_DOWN;
+        case CEILING:
+            return MathContext.ROUND_CEILING;
+        case FLOOR:
+            return MathContext.ROUND_FLOOR;
+        case HALF_UP:
+            return MathContext.ROUND_HALF_UP;
+        case HALF_DOWN:
+            return MathContext.ROUND_HALF_DOWN;
+        case HALF_EVEN:
+            return MathContext.ROUND_HALF_EVEN;
+        case UNNECESSARY:
+            return MathContext.ROUND_UNNECESSARY;
+        }
+        throw new IllegalArgumentException("Invalid rounding mode specified");
+    }
+    // END Android-added: convertRoundingMode() to convert between Java and ICU RoundingMode enums.
+
+    /**
+     * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
+     *
+     * @param roundingMode The <code>RoundingMode</code> to be used
+     * @see #getRoundingMode()
+     * @exception NullPointerException if <code>roundingMode</code> is null.
+     * @since 1.6
+     */
+    @Override
+    public void setRoundingMode(RoundingMode roundingMode) {
+        if (roundingMode == null) {
+            throw new NullPointerException();
+        }
+
+        this.roundingMode = roundingMode;
+        // Android-changed: use ICU.
+        // digitList.setRoundingMode(roundingMode);
+        icuDecimalFormat.setRoundingMode(convertRoundingMode(roundingMode));
+        // Android-removed: fast path related code.
+        // fastPathCheckNeeded = true;
+    }
+
+    // BEGIN Android-added: Upstream code from OpenJDK 7u40 release.
+    // This method was removed in OpenJDK 8 in favor of doing equivalent work in the provider. Since
+    // Android removed support for providers for NumberFormat we keep this method around as an
+    // "Android addition".
+    /**
+     * Adjusts the minimum and maximum fraction digits to values that
+     * are reasonable for the currency's default fraction digits.
+     */
+    void adjustForCurrencyDefaultFractionDigits() {
+        Currency currency = symbols.getCurrency();
+        if (currency == null) {
+            try {
+                currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        if (currency != null) {
+            int digits = currency.getDefaultFractionDigits();
+            if (digits != -1) {
+                int oldMinDigits = getMinimumFractionDigits();
+                // Common patterns are "#.##", "#.00", "#".
+                // Try to adjust all of them in a reasonable way.
+                if (oldMinDigits == getMaximumFractionDigits()) {
+                    setMinimumFractionDigits(digits);
+                    setMaximumFractionDigits(digits);
+                } else {
+                    setMinimumFractionDigits(Math.min(digits, oldMinDigits));
+                    setMaximumFractionDigits(digits);
+                }
+            }
+        }
+    }
+    // END Android-added: Upstream code from OpenJDK 7u40 release.
+
+    // BEGIN Android-added: Custom serialization code for compatibility with RI serialization.
+    // the fields list to be serialized
+    private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("positivePrefix", String.class),
+            new ObjectStreamField("positiveSuffix", String.class),
+            new ObjectStreamField("negativePrefix", String.class),
+            new ObjectStreamField("negativeSuffix", String.class),
+            new ObjectStreamField("posPrefixPattern", String.class),
+            new ObjectStreamField("posSuffixPattern", String.class),
+            new ObjectStreamField("negPrefixPattern", String.class),
+            new ObjectStreamField("negSuffixPattern", String.class),
+            new ObjectStreamField("multiplier", int.class),
+            new ObjectStreamField("groupingSize", byte.class),
+            new ObjectStreamField("groupingUsed", boolean.class),
+            new ObjectStreamField("decimalSeparatorAlwaysShown", boolean.class),
+            new ObjectStreamField("parseBigDecimal", boolean.class),
+            new ObjectStreamField("roundingMode", RoundingMode.class),
+            new ObjectStreamField("symbols", DecimalFormatSymbols.class),
+            new ObjectStreamField("useExponentialNotation", boolean.class),
+            new ObjectStreamField("minExponentDigits", byte.class),
+            new ObjectStreamField("maximumIntegerDigits", int.class),
+            new ObjectStreamField("minimumIntegerDigits", int.class),
+            new ObjectStreamField("maximumFractionDigits", int.class),
+            new ObjectStreamField("minimumFractionDigits", int.class),
+            new ObjectStreamField("serialVersionOnStream", int.class),
+    };
+
+    private void writeObject(ObjectOutputStream stream) throws IOException, ClassNotFoundException {
+        ObjectOutputStream.PutField fields = stream.putFields();
+        fields.put("positivePrefix", icuDecimalFormat.getPositivePrefix());
+        fields.put("positiveSuffix", icuDecimalFormat.getPositiveSuffix());
+        fields.put("negativePrefix", icuDecimalFormat.getNegativePrefix());
+        fields.put("negativeSuffix", icuDecimalFormat.getNegativeSuffix());
+        fields.put("posPrefixPattern", (String) null);
+        fields.put("posSuffixPattern", (String) null);
+        fields.put("negPrefixPattern", (String) null);
+        fields.put("negSuffixPattern", (String) null);
+        fields.put("multiplier", icuDecimalFormat.getMultiplier());
+        fields.put("groupingSize", (byte) icuDecimalFormat.getGroupingSize());
+        fields.put("groupingUsed", icuDecimalFormat.isGroupingUsed());
+        fields.put("decimalSeparatorAlwaysShown", icuDecimalFormat.isDecimalSeparatorAlwaysShown());
+        fields.put("parseBigDecimal", icuDecimalFormat.isParseBigDecimal());
+        fields.put("roundingMode", roundingMode);
+        fields.put("symbols", symbols);
+        fields.put("useExponentialNotation", false);
+        fields.put("minExponentDigits", (byte) 0);
+        fields.put("maximumIntegerDigits", icuDecimalFormat.getMaximumIntegerDigits());
+        fields.put("minimumIntegerDigits", icuDecimalFormat.getMinimumIntegerDigits());
+        fields.put("maximumFractionDigits", icuDecimalFormat.getMaximumFractionDigits());
+        fields.put("minimumFractionDigits", icuDecimalFormat.getMinimumFractionDigits());
+        fields.put("serialVersionOnStream", currentSerialVersion);
+        stream.writeFields();
+    }
+    // END Android-added: Custom serialization code for compatibility with RI serialization.
+
+    /**
+     * Reads the default serializable fields from the stream and performs
+     * validations and adjustments for older serialized versions. The
+     * validations and adjustments are:
+     * <ol>
+     * <li>
+     * Verify that the superclass's digit count fields correctly reflect
+     * the limits imposed on formatting numbers other than
+     * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
+     * limits are stored in the superclass for serialization compatibility
+     * with older versions, while the limits for <code>BigInteger</code> and
+     * <code>BigDecimal</code> objects are kept in this class.
+     * If, in the superclass, the minimum or maximum integer digit count is
+     * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
+     * maximum fraction digit count is larger than
+     * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
+     * and this method throws an <code>InvalidObjectException</code>.
+     * <li>
+     * If <code>serialVersionOnStream</code> is less than 4, initialize
+     * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
+     * RoundingMode.HALF_EVEN}.  This field is new with version 4.
+     * <li>
+     * If <code>serialVersionOnStream</code> is less than 3, then call
+     * the setters for the minimum and maximum integer and fraction digits with
+     * the values of the corresponding superclass getters to initialize the
+     * fields in this class. The fields in this class are new with version 3.
+     * <li>
+     * If <code>serialVersionOnStream</code> is less than 1, indicating that
+     * the stream was written by JDK 1.1, initialize
+     * <code>useExponentialNotation</code>
+     * to false, since it was not present in JDK 1.1.
+     * <li>
+     * Set <code>serialVersionOnStream</code> to the maximum allowed value so
+     * that default serialization will work properly if this object is streamed
+     * out again.
+     * </ol>
+     *
+     * <p>Stream versions older than 2 will not have the affix pattern variables
+     * <code>posPrefixPattern</code> etc.  As a result, they will be initialized
+     * to <code>null</code>, which means the affix strings will be taken as
+     * literal values.  This is exactly what we want, since that corresponds to
+     * the pre-version-2 behavior.
+     */
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException {
+        // BEGIN Android-changed: Custom serialization code for compatibility with RI serialization.
+        /*
+        stream.defaultReadObject();
+        digitList = new DigitList();
+
+        // We force complete fast-path reinitialization when the instance is
+        // deserialized. See clone() comment on fastPathCheckNeeded.
+        fastPathCheckNeeded = true;
+        isFastPath = false;
+        fastPathData = null;
+
+        if (serialVersionOnStream < 4) {
+            setRoundingMode(RoundingMode.HALF_EVEN);
+        } else {
+            setRoundingMode(getRoundingMode());
+        }
+
+        // We only need to check the maximum counts because NumberFormat
+        // .readObject has already ensured that the maximum is greater than the
+        // minimum count.
+        if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
+            super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
+            throw new InvalidObjectException("Digit count out of range");
+        }
+        if (serialVersionOnStream < 3) {
+            setMaximumIntegerDigits(super.getMaximumIntegerDigits());
+            setMinimumIntegerDigits(super.getMinimumIntegerDigits());
+            setMaximumFractionDigits(super.getMaximumFractionDigits());
+            setMinimumFractionDigits(super.getMinimumFractionDigits());
+        }
+        if (serialVersionOnStream < 1) {
+            // Didn't have exponential fields
+            useExponentialNotation = false;
+        }
+        serialVersionOnStream = currentSerialVersion;
+        */
+        ObjectInputStream.GetField fields = stream.readFields();
+        this.symbols = (DecimalFormatSymbols) fields.get("symbols", null);
+
+        initPattern("#");
+
+        // Calling a setter method on an ICU DecimalFormat object will change the object's internal
+        // state, even if the value set is the same as the default value (ICU Ticket #13266).
+        //
+        // In an attempt to create objects that are equals() to the ones that were serialized, it's
+        // therefore assumed here that any values that are the same as the default values were the
+        // default values (ie. no setter was called to explicitly set that value).
+
+        String positivePrefix = (String) fields.get("positivePrefix", "");
+        if (!Objects.equals(positivePrefix, icuDecimalFormat.getPositivePrefix())) {
+            icuDecimalFormat.setPositivePrefix(positivePrefix);
+        }
+
+        String positiveSuffix = (String) fields.get("positiveSuffix", "");
+        if (!Objects.equals(positiveSuffix, icuDecimalFormat.getPositiveSuffix())) {
+            icuDecimalFormat.setPositiveSuffix(positiveSuffix);
+        }
+
+        String negativePrefix = (String) fields.get("negativePrefix", "-");
+        if (!Objects.equals(negativePrefix, icuDecimalFormat.getNegativePrefix())) {
+            icuDecimalFormat.setNegativePrefix(negativePrefix);
+        }
+
+        String negativeSuffix = (String) fields.get("negativeSuffix", "");
+        if (!Objects.equals(negativeSuffix, icuDecimalFormat.getNegativeSuffix())) {
+            icuDecimalFormat.setNegativeSuffix(negativeSuffix);
+        }
+
+        int multiplier = fields.get("multiplier", 1);
+        if (multiplier != icuDecimalFormat.getMultiplier()) {
+            icuDecimalFormat.setMultiplier(multiplier);
+        }
+
+        boolean groupingUsed = fields.get("groupingUsed", true);
+        if (groupingUsed != icuDecimalFormat.isGroupingUsed()) {
+            icuDecimalFormat.setGroupingUsed(groupingUsed);
+        }
+
+        int groupingSize = fields.get("groupingSize", (byte) 3);
+        if (groupingSize != icuDecimalFormat.getGroupingSize()) {
+            icuDecimalFormat.setGroupingSize(groupingSize);
+        }
+
+        boolean decimalSeparatorAlwaysShown = fields.get("decimalSeparatorAlwaysShown", false);
+        if (decimalSeparatorAlwaysShown != icuDecimalFormat.isDecimalSeparatorAlwaysShown()) {
+            icuDecimalFormat.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown);
+        }
+
+        RoundingMode roundingMode =
+                (RoundingMode) fields.get("roundingMode", RoundingMode.HALF_EVEN);
+        if (convertRoundingMode(roundingMode) != icuDecimalFormat.getRoundingMode()) {
+            setRoundingMode(roundingMode);
+        }
+
+        int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309);
+        if (maximumIntegerDigits != icuDecimalFormat.getMaximumIntegerDigits()) {
+            icuDecimalFormat.setMaximumIntegerDigits(maximumIntegerDigits);
+        }
+
+        int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309);
+        if (minimumIntegerDigits != icuDecimalFormat.getMinimumIntegerDigits()) {
+            icuDecimalFormat.setMinimumIntegerDigits(minimumIntegerDigits);
+        }
+
+        int maximumFractionDigits = fields.get("maximumFractionDigits", 340);
+        if (maximumFractionDigits != icuDecimalFormat.getMaximumFractionDigits()) {
+            icuDecimalFormat.setMaximumFractionDigits(maximumFractionDigits);
+        }
+
+        int minimumFractionDigits = fields.get("minimumFractionDigits", 340);
+        if (minimumFractionDigits != icuDecimalFormat.getMinimumFractionDigits()) {
+            icuDecimalFormat.setMinimumFractionDigits(minimumFractionDigits);
+        }
+
+        boolean parseBigDecimal = fields.get("parseBigDecimal", true);
+        if (parseBigDecimal != icuDecimalFormat.isParseBigDecimal()) {
+            icuDecimalFormat.setParseBigDecimal(parseBigDecimal);
+        }
+
+        updateFieldsFromIcu();
+
+        if (fields.get("serialVersionOnStream", 0) < 3) {
+            setMaximumIntegerDigits(super.getMaximumIntegerDigits());
+            setMinimumIntegerDigits(super.getMinimumIntegerDigits());
+            setMaximumFractionDigits(super.getMaximumFractionDigits());
+            setMinimumFractionDigits(super.getMinimumFractionDigits());
+        }
+        // END Android-changed: Custom serialization code for compatibility with RI serialization.
+    }
+
+    //----------------------------------------------------------------------
+    // INSTANCE VARIABLES
+    //----------------------------------------------------------------------
+
+    // BEGIN Android-removed: various fields now stored in icuDecimalFormat.
+    /*
+    private transient DigitList digitList = new DigitList();
+
+    /**
+     * The symbol used as a prefix when formatting positive numbers, e.g. "+".
+     *
+     * @serial
+     * @see #getPositivePrefix
+     *
+    private String  positivePrefix = "";
+
+    /**
+     * The symbol used as a suffix when formatting positive numbers.
+     * This is often an empty string.
+     *
+     * @serial
+     * @see #getPositiveSuffix
+     *
+    private String  positiveSuffix = "";
+
+    /**
+     * The symbol used as a prefix when formatting negative numbers, e.g. "-".
+     *
+     * @serial
+     * @see #getNegativePrefix
+     *
+    private String  negativePrefix = "-";
+
+    /**
+     * The symbol used as a suffix when formatting negative numbers.
+     * This is often an empty string.
+     *
+     * @serial
+     * @see #getNegativeSuffix
+     *
+    private String  negativeSuffix = "";
+
+    /**
+     * The prefix pattern for non-negative numbers.  This variable corresponds
+     * to <code>positivePrefix</code>.
+     *
+     * <p>This pattern is expanded by the method <code>expandAffix()</code> to
+     * <code>positivePrefix</code> to update the latter to reflect changes in
+     * <code>symbols</code>.  If this variable is <code>null</code> then
+     * <code>positivePrefix</code> is taken as a literal value that does not
+     * change when <code>symbols</code> changes.  This variable is always
+     * <code>null</code> for <code>DecimalFormat</code> objects older than
+     * stream version 2 restored from stream.
+     *
+     * @serial
+     * @since 1.3
+     *
+    private String posPrefixPattern;
+
+    /**
+     * The suffix pattern for non-negative numbers.  This variable corresponds
+     * to <code>positiveSuffix</code>.  This variable is analogous to
+     * <code>posPrefixPattern</code>; see that variable for further
+     * documentation.
+     *
+     * @serial
+     * @since 1.3
+     *
+    private String posSuffixPattern;
+
+    /**
+     * The prefix pattern for negative numbers.  This variable corresponds
+     * to <code>negativePrefix</code>.  This variable is analogous to
+     * <code>posPrefixPattern</code>; see that variable for further
+     * documentation.
+     *
+     * @serial
+     * @since 1.3
+     *
+    private String negPrefixPattern;
+
+    /**
+     * The suffix pattern for negative numbers.  This variable corresponds
+     * to <code>negativeSuffix</code>.  This variable is analogous to
+     * <code>posPrefixPattern</code>; see that variable for further
+     * documentation.
+     *
+     * @serial
+     * @since 1.3
+     *
+    private String negSuffixPattern;
+
+    /**
+     * The multiplier for use in percent, per mille, etc.
+     *
+     * @serial
+     * @see #getMultiplier
+     *
+    private int     multiplier = 1;
+
+    /**
+     * The number of digits between grouping separators in the integer
+     * portion of a number.  Must be greater than 0 if
+     * <code>NumberFormat.groupingUsed</code> is true.
+     *
+     * @serial
+     * @see #getGroupingSize
+     * @see java.text.NumberFormat#isGroupingUsed
+     *
+    private byte    groupingSize = 3;  // invariant, > 0 if useThousands
+
+    /**
+     * If true, forces the decimal separator to always appear in a formatted
+     * number, even if the fractional part of the number is zero.
+     *
+     * @serial
+     * @see #isDecimalSeparatorAlwaysShown
+     *
+    private boolean decimalSeparatorAlwaysShown = false;
+
+    /**
+     * If true, parse returns BigDecimal wherever possible.
+     *
+     * @serial
+     * @see #isParseBigDecimal
+     * @since 1.5
+     *
+    private boolean parseBigDecimal = false;
+
+
+    /**
+     * True if this object represents a currency format.  This determines
+     * whether the monetary decimal separator is used instead of the normal one.
+     *
+    private transient boolean isCurrencyFormat = false;
+    */
+    // END Android-removed: various fields now stored in icuDecimalFormat.
+
+    /**
+     * The <code>DecimalFormatSymbols</code> object used by this format.
+     * It contains the symbols used to format numbers, e.g. the grouping separator,
+     * decimal separator, and so on.
+     *
+     * @serial
+     * @see #setDecimalFormatSymbols
+     * @see java.text.DecimalFormatSymbols
+     */
+    private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
+
+    // BEGIN Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits.
+    /*
+    /**
+     * True to force the use of exponential (i.e. scientific) notation when formatting
+     * numbers.
+     *
+     * @serial
+     * @since 1.2
+     *
+    private boolean useExponentialNotation;  // Newly persistent in the Java 2 platform v.1.2
+
+    /**
+     * FieldPositions describing the positive prefix String. This is
+     * lazily created. Use <code>getPositivePrefixFieldPositions</code>
+     * when needed.
+     *
+    private transient FieldPosition[] positivePrefixFieldPositions;
+
+    /**
+     * FieldPositions describing the positive suffix String. This is
+     * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
+     * when needed.
+     *
+    private transient FieldPosition[] positiveSuffixFieldPositions;
+
+    /**
+     * FieldPositions describing the negative prefix String. This is
+     * lazily created. Use <code>getNegativePrefixFieldPositions</code>
+     * when needed.
+     *
+    private transient FieldPosition[] negativePrefixFieldPositions;
+
+    /**
+     * FieldPositions describing the negative suffix String. This is
+     * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
+     * when needed.
+     *
+    private transient FieldPosition[] negativeSuffixFieldPositions;
+
+    /**
+     * The minimum number of digits used to display the exponent when a number is
+     * formatted in exponential notation.  This field is ignored if
+     * <code>useExponentialNotation</code> is not true.
+     *
+     * @serial
+     * @since 1.2
+     *
+    private byte    minExponentDigits;       // Newly persistent in the Java 2 platform v.1.2
+
+
+    */
+    // END Android-removed: useExponentialNotation, *FieldPositions, minExponentDigits.
+
+    /**
+     * The maximum number of digits allowed in the integer portion of a
+     * <code>BigInteger</code> or <code>BigDecimal</code> number.
+     * <code>maximumIntegerDigits</code> must be greater than or equal to
+     * <code>minimumIntegerDigits</code>.
+     *
+     * @serial
+     * @see #getMaximumIntegerDigits
+     * @since 1.5
+     */
+    // Android-changed: removed initialization.
+    private int    maximumIntegerDigits /* = super.getMaximumIntegerDigits() */;
+
+    /**
+     * The minimum number of digits allowed in the integer portion of a
+     * <code>BigInteger</code> or <code>BigDecimal</code> number.
+     * <code>minimumIntegerDigits</code> must be less than or equal to
+     * <code>maximumIntegerDigits</code>.
+     *
+     * @serial
+     * @see #getMinimumIntegerDigits
+     * @since 1.5
+     */
+    // Android-changed: removed initialization.
+    private int    minimumIntegerDigits /* = super.getMinimumIntegerDigits() */;
+
+    /**
+     * The maximum number of digits allowed in the fractional portion of a
+     * <code>BigInteger</code> or <code>BigDecimal</code> number.
+     * <code>maximumFractionDigits</code> must be greater than or equal to
+     * <code>minimumFractionDigits</code>.
+     *
+     * @serial
+     * @see #getMaximumFractionDigits
+     * @since 1.5
+     */
+    // Android-changed: removed initialization.
+    private int    maximumFractionDigits /* = super.getMaximumFractionDigits() */;
+
+    /**
+     * The minimum number of digits allowed in the fractional portion of a
+     * <code>BigInteger</code> or <code>BigDecimal</code> number.
+     * <code>minimumFractionDigits</code> must be less than or equal to
+     * <code>maximumFractionDigits</code>.
+     *
+     * @serial
+     * @see #getMinimumFractionDigits
+     * @since 1.5
+     */
+    // Android-changed: removed initialization.
+    private int    minimumFractionDigits /* = super.getMinimumFractionDigits() */;
+
+    /**
+     * The {@link java.math.RoundingMode} used in this DecimalFormat.
+     *
+     * @serial
+     * @since 1.6
+     */
+    private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
+
+    // BEGIN Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData.
+    /*
+    // ------ DecimalFormat fields for fast-path for double algorithm  ------
+
+    /**
+     * Helper inner utility class for storing the data used in the fast-path
+     * algorithm. Almost all fields related to fast-path are encapsulated in
+     * this class.
+     *
+     * Any {@code DecimalFormat} instance has a {@code fastPathData}
+     * reference field that is null unless both the properties of the instance
+     * are such that the instance is in the "fast-path" state, and a format call
+     * has been done at least once while in this state.
+     *
+     * Almost all fields are related to the "fast-path" state only and don't
+     * change until one of the instance properties is changed.
+     *
+     * {@code firstUsedIndex} and {@code lastFreeIndex} are the only
+     * two fields that are used and modified while inside a call to
+     * {@code fastDoubleFormat}.
+     *
+     *
+    private static class FastPathData {
+        // --- Temporary fields used in fast-path, shared by several methods.
+
+        /** The first unused index at the end of the formatted result. *
+        int lastFreeIndex;
+
+        /** The first used index at the beginning of the formatted result *
+        int firstUsedIndex;
+
+        // --- State fields related to fast-path status. Changes due to a
+        //     property change only. Set by checkAndSetFastPathStatus() only.
+
+        /** Difference between locale zero and default zero representation. *
+        int  zeroDelta;
+
+        /** Locale char for grouping separator. *
+        char groupingChar;
+
+        /**  Fixed index position of last integral digit of formatted result *
+        int integralLastIndex;
+
+        /**  Fixed index position of first fractional digit of formatted result *
+        int fractionalFirstIndex;
+
+        /** Fractional constants depending on decimal|currency state *
+        double fractionalScaleFactor;
+        int fractionalMaxIntBound;
+
+
+        /** The char array buffer that will contain the formatted result *
+        char[] fastPathContainer;
+
+        /** Suffixes recorded as char array for efficiency. *
+        char[] charsPositivePrefix;
+        char[] charsNegativePrefix;
+        char[] charsPositiveSuffix;
+        char[] charsNegativeSuffix;
+        boolean positiveAffixesRequired = true;
+        boolean negativeAffixesRequired = true;
+    }
+
+    /** The format fast-path status of the instance. Logical state. *
+    private transient boolean isFastPath = false;
+
+    /** Flag stating need of check and reinit fast-path status on next format call. *
+    private transient boolean fastPathCheckNeeded = true;
+
+    /** DecimalFormat reference to its FastPathData *
+    private transient FastPathData fastPathData;
+    */
+    // END Android-removed: FastPathData, isFastPath, fastPathCheckNeeded and fastPathData.
+
+    //----------------------------------------------------------------------
+
+    static final int currentSerialVersion = 4;
+
+    // BEGIN Android-removed: serialVersionOnStream.
+
+    /**
+     * The internal serial version which says which version was written.
+     * Possible values are:
+     * <ul>
+     * <li><b>0</b> (default): versions before the Java 2 platform v1.2
+     * <li><b>1</b>: version for 1.2, which includes the two new fields
+     *      <code>useExponentialNotation</code> and
+     *      <code>minExponentDigits</code>.
+     * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
+     *      <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
+     *      <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
+     * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
+     *      <code>maximumIntegerDigits</code>,
+     *      <code>minimumIntegerDigits</code>,
+     *      <code>maximumFractionDigits</code>,
+     *      <code>minimumFractionDigits</code>, and
+     *      <code>parseBigDecimal</code>.
+     * <li><b>4</b>: version for 1.6 and later, which adds one new field:
+     *      <code>roundingMode</code>.
+     * </ul>
+     * @since 1.2
+     * @serial
+     *
+    private int serialVersionOnStream = currentSerialVersion;
+    */
+    // END Android-removed: serialVersionOnStream.
+
+    //----------------------------------------------------------------------
+    // CONSTANTS
+    //----------------------------------------------------------------------
+
+    // BEGIN Android-removed: Fast-Path for double Constants, various constants.
+    /*
+    // ------ Fast-Path for double Constants ------
+
+    /** Maximum valid integer value for applying fast-path algorithm *
+    private static final double MAX_INT_AS_DOUBLE = (double) Integer.MAX_VALUE;
+
+    /**
+     * The digit arrays used in the fast-path methods for collecting digits.
+     * Using 3 constants arrays of chars ensures a very fast collection of digits
+     *
+    private static class DigitArrays {
+        static final char[] DigitOnes1000 = new char[1000];
+        static final char[] DigitTens1000 = new char[1000];
+        static final char[] DigitHundreds1000 = new char[1000];
+
+        // initialize on demand holder class idiom for arrays of digits
+        static {
+            int tenIndex = 0;
+            int hundredIndex = 0;
+            char digitOne = '0';
+            char digitTen = '0';
+            char digitHundred = '0';
+            for (int i = 0;  i < 1000; i++ ) {
+
+                DigitOnes1000[i] = digitOne;
+                if (digitOne == '9')
+                    digitOne = '0';
+                else
+                    digitOne++;
+
+                DigitTens1000[i] = digitTen;
+                if (i == (tenIndex + 9)) {
+                    tenIndex += 10;
+                    if (digitTen == '9')
+                        digitTen = '0';
+                    else
+                        digitTen++;
+                }
+
+                DigitHundreds1000[i] = digitHundred;
+                if (i == (hundredIndex + 99)) {
+                    digitHundred++;
+                    hundredIndex += 100;
+                }
+            }
+        }
+    }
+    // ------ Fast-Path for double Constants end ------
+
+    // Constants for characters used in programmatic (unlocalized) patterns.
+    private static final char       PATTERN_ZERO_DIGIT         = '0';
+    private static final char       PATTERN_GROUPING_SEPARATOR = ',';
+    private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
+    private static final char       PATTERN_PER_MILLE          = '\u2030';
+    private static final char       PATTERN_PERCENT            = '%';
+    private static final char       PATTERN_DIGIT              = '#';
+    private static final char       PATTERN_SEPARATOR          = ';';
+    private static final String     PATTERN_EXPONENT           = "E";
+    private static final char       PATTERN_MINUS              = '-';
+
+    /**
+     * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
+     * is used in patterns and substituted with either the currency symbol,
+     * or if it is doubled, with the international currency symbol.  If the
+     * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
+     * replaced with the monetary decimal separator.
+     *
+     * The CURRENCY_SIGN is not localized.
+     *
+    private static final char       CURRENCY_SIGN = '\u00A4';
+
+    private static final char       QUOTE = '\'';
+
+    private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
+    */
+    // END Android-removed: Fast-Path for double Constants, various constants.
+
+    // Upper limit on integer and fraction digits for a Java double
+    static final int DOUBLE_INTEGER_DIGITS  = 309;
+    static final int DOUBLE_FRACTION_DIGITS = 340;
+
+    // Upper limit on integer and fraction digits for BigDecimal and BigInteger
+    static final int MAXIMUM_INTEGER_DIGITS  = Integer.MAX_VALUE;
+    static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
+
+    // Proclaim JDK 1.1 serial compatibility.
+    static final long serialVersionUID = 864413376551465018L;
+}
diff --git a/java/text/DecimalFormatSymbols.java b/java/text/DecimalFormatSymbols.java
new file mode 100644
index 0000000..a65a079
--- /dev/null
+++ b/java/text/DecimalFormatSymbols.java
@@ -0,0 +1,1158 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.util.Currency;
+import java.util.Locale;
+import libcore.icu.ICU;
+import libcore.icu.LocaleData;
+
+/**
+ * This class represents the set of symbols (such as the decimal separator,
+ * the grouping separator, and so on) needed by <code>DecimalFormat</code>
+ * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
+ * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any
+ * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
+ * your <code>DecimalFormat</code> and modify it.
+ *
+ * @see          java.util.Locale
+ * @see          DecimalFormat
+ * @author       Mark Davis
+ * @author       Alan Liu
+ */
+
+public class DecimalFormatSymbols implements Cloneable, Serializable {
+
+    // Android-changed: Removed reference to DecimalFormatSymbolsProvider, suggested getInstance().
+    /**
+     * Create a DecimalFormatSymbols object for the default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * It is recommended that the {@link #getInstance(Locale) getInstance} method is used
+     * instead.
+     * <p>This is equivalent to calling
+     * {@link #DecimalFormatSymbols(Locale)
+     *     DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     */
+    public DecimalFormatSymbols() {
+        initialize( Locale.getDefault(Locale.Category.FORMAT) );
+    }
+
+    // Android-changed: Removed reference to DecimalFormatSymbolsProvider, suggested getInstance().
+    /**
+     * Create a DecimalFormatSymbols object for the given locale.
+     * It is recommended that the {@link #getInstance(Locale) getInstance} method is used
+     * instead.
+     * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
+     * for the numbering system, the instance is initialized with the specified numbering
+     * system if the JRE implementation supports it. For example,
+     * <pre>
+     * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
+     * </pre>
+     * This may return a {@code NumberFormat} instance with the Thai numbering system,
+     * instead of the Latin numbering system.
+     *
+     * @param locale the desired locale
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public DecimalFormatSymbols( Locale locale ) {
+        initialize( locale );
+    }
+
+    // Android-changed: Removed reference to DecimalFormatSymbolsProvider.
+    /**
+     * Returns an array of all locales for which the
+     * <code>getInstance</code> methods of this class can return
+     * localized instances.
+     *
+     * @return an array of locales for which localized
+     *         <code>DecimalFormatSymbols</code> instances are available.
+     * @since 1.6
+     */
+    public static Locale[] getAvailableLocales() {
+        // Android-changed: Removed used of DecimalFormatSymbolsProvider. Switched to use ICU.
+        return ICU.getAvailableLocales();
+    }
+
+    // Android-changed: Removed reference to DecimalFormatSymbolsProvider.
+    /**
+     * Gets the <code>DecimalFormatSymbols</code> instance for the default
+     * locale.
+     * <p>This is equivalent to calling
+     * {@link #getInstance(Locale)
+     *     getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @return a <code>DecimalFormatSymbols</code> instance.
+     * @since 1.6
+     */
+    public static final DecimalFormatSymbols getInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    // Android-changed: Removed reference to DecimalFormatSymbolsProvider.
+    /**
+     * Gets the <code>DecimalFormatSymbols</code> instance for the specified
+     * locale.
+     * If the specified locale contains the {@link java.util.Locale#UNICODE_LOCALE_EXTENSION}
+     * for the numbering system, the instance is initialized with the specified numbering
+     * system if the JRE implementation supports it. For example,
+     * <pre>
+     * NumberFormat.getNumberInstance(Locale.forLanguageTag("th-TH-u-nu-thai"))
+     * </pre>
+     * This may return a {@code NumberFormat} instance with the Thai numbering system,
+     * instead of the Latin numbering system.
+     *
+     * @param locale the desired locale.
+     * @return a <code>DecimalFormatSymbols</code> instance.
+     * @exception NullPointerException if <code>locale</code> is null
+     * @since 1.6
+     */
+    public static final DecimalFormatSymbols getInstance(Locale locale) {
+        // Android-changed: Removed used of DecimalFormatSymbolsProvider.
+        return new DecimalFormatSymbols(locale);
+    }
+
+    /**
+     * Gets the character used for zero. Different for Arabic, etc.
+     *
+     * @return the character used for zero
+     */
+    public char getZeroDigit() {
+        return zeroDigit;
+    }
+
+    /**
+     * Sets the character used for zero. Different for Arabic, etc.
+     *
+     * @param zeroDigit the character used for zero
+     */
+    public void setZeroDigit(char zeroDigit) {
+        this.zeroDigit = zeroDigit;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used for thousands separator. Different for French, etc.
+     *
+     * @return the grouping separator
+     */
+    public char getGroupingSeparator() {
+        return groupingSeparator;
+    }
+
+    /**
+     * Sets the character used for thousands separator. Different for French, etc.
+     *
+     * @param groupingSeparator the grouping separator
+     */
+    public void setGroupingSeparator(char groupingSeparator) {
+        this.groupingSeparator = groupingSeparator;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used for decimal sign. Different for French, etc.
+     *
+     * @return the character used for decimal sign
+     */
+    public char getDecimalSeparator() {
+        return decimalSeparator;
+    }
+
+    /**
+     * Sets the character used for decimal sign. Different for French, etc.
+     *
+     * @param decimalSeparator the character used for decimal sign
+     */
+    public void setDecimalSeparator(char decimalSeparator) {
+        this.decimalSeparator = decimalSeparator;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used for per mille sign. Different for Arabic, etc.
+     *
+     * @return the character used for per mille sign
+     */
+    public char getPerMill() {
+        return perMill;
+    }
+
+    /**
+     * Sets the character used for per mille sign. Different for Arabic, etc.
+     *
+     * @param perMill the character used for per mille sign
+     */
+    public void setPerMill(char perMill) {
+        this.perMill = perMill;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used for percent sign. Different for Arabic, etc.
+     *
+     * @return the character used for percent sign
+     */
+    public char getPercent() {
+        return percent;
+    }
+
+    // Android-added: getPercentString() for percent signs longer than one char.
+    /**
+     * Gets the string used for percent sign. Different for Arabic, etc.
+     *
+     * @hide
+     */
+    public String getPercentString() {
+        return String.valueOf(percent);
+    }
+
+    /**
+     * Sets the character used for percent sign. Different for Arabic, etc.
+     *
+     * @param percent the character used for percent sign
+     */
+    public void setPercent(char percent) {
+        this.percent = percent;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used for a digit in a pattern.
+     *
+     * @return the character used for a digit in a pattern
+     */
+    public char getDigit() {
+        return digit;
+    }
+
+    /**
+     * Sets the character used for a digit in a pattern.
+     *
+     * @param digit the character used for a digit in a pattern
+     */
+    public void setDigit(char digit) {
+        this.digit = digit;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used to separate positive and negative subpatterns
+     * in a pattern.
+     *
+     * @return the pattern separator
+     */
+    public char getPatternSeparator() {
+        return patternSeparator;
+    }
+
+    /**
+     * Sets the character used to separate positive and negative subpatterns
+     * in a pattern.
+     *
+     * @param patternSeparator the pattern separator
+     */
+    public void setPatternSeparator(char patternSeparator) {
+        this.patternSeparator = patternSeparator;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the string used to represent infinity. Almost always left
+     * unchanged.
+     *
+     * @return the string representing infinity
+     */
+    public String getInfinity() {
+        return infinity;
+    }
+
+    /**
+     * Sets the string used to represent infinity. Almost always left
+     * unchanged.
+     *
+     * @param infinity the string representing infinity
+     */
+    public void setInfinity(String infinity) {
+        this.infinity = infinity;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the string used to represent "not a number". Almost always left
+     * unchanged.
+     *
+     * @return the string representing "not a number"
+     */
+    public String getNaN() {
+        return NaN;
+    }
+
+    /**
+     * Sets the string used to represent "not a number". Almost always left
+     * unchanged.
+     *
+     * @param NaN the string representing "not a number"
+     */
+    public void setNaN(String NaN) {
+        this.NaN = NaN;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the character used to represent minus sign. If no explicit
+     * negative format is specified, one is formed by prefixing
+     * minusSign to the positive format.
+     *
+     * @return the character representing minus sign
+     */
+    public char getMinusSign() {
+        return minusSign;
+    }
+
+
+    // Android-added: getPercentString() for percent signs longer than one char.
+    /**
+     * Gets the string used to represent minus sign. If no explicit
+     * negative format is specified, one is formed by prefixing
+     * minusSign to the positive format.
+     *
+     * @hide
+     */
+    public String getMinusSignString() {
+        return String.valueOf(minusSign);
+    }
+
+    /**
+     * Sets the character used to represent minus sign. If no explicit
+     * negative format is specified, one is formed by prefixing
+     * minusSign to the positive format.
+     *
+     * @param minusSign the character representing minus sign
+     */
+    public void setMinusSign(char minusSign) {
+        this.minusSign = minusSign;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Returns the currency symbol for the currency of these
+     * DecimalFormatSymbols in their locale.
+     *
+     * @return the currency symbol
+     * @since 1.2
+     */
+    public String getCurrencySymbol()
+    {
+        return currencySymbol;
+    }
+
+    /**
+     * Sets the currency symbol for the currency of these
+     * DecimalFormatSymbols in their locale.
+     *
+     * @param currency the currency symbol
+     * @since 1.2
+     */
+    public void setCurrencySymbol(String currency)
+    {
+        currencySymbol = currency;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Returns the ISO 4217 currency code of the currency of these
+     * DecimalFormatSymbols.
+     *
+     * @return the currency code
+     * @since 1.2
+     */
+    public String getInternationalCurrencySymbol()
+    {
+        return intlCurrencySymbol;
+    }
+
+    /**
+     * Sets the ISO 4217 currency code of the currency of these
+     * DecimalFormatSymbols.
+     * If the currency code is valid (as defined by
+     * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
+     * this also sets the currency attribute to the corresponding Currency
+     * instance and the currency symbol attribute to the currency's symbol
+     * in the DecimalFormatSymbols' locale. If the currency code is not valid,
+     * then the currency attribute is set to null and the currency symbol
+     * attribute is not modified.
+     *
+     * @param currencyCode the currency code
+     * @see #setCurrency
+     * @see #setCurrencySymbol
+     * @since 1.2
+     */
+    public void setInternationalCurrencySymbol(String currencyCode)
+    {
+        intlCurrencySymbol = currencyCode;
+        currency = null;
+        if (currencyCode != null) {
+            try {
+                currency = Currency.getInstance(currencyCode);
+                // Android-changed: get currencySymbol for locale.
+                currencySymbol = currency.getSymbol(locale);
+            } catch (IllegalArgumentException e) {
+            }
+        }
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    /**
+     * Gets the currency of these DecimalFormatSymbols. May be null if the
+     * currency symbol attribute was previously set to a value that's not
+     * a valid ISO 4217 currency code.
+     *
+     * @return the currency used, or null
+     * @since 1.4
+     */
+    public Currency getCurrency() {
+        return currency;
+    }
+
+    /**
+     * Sets the currency of these DecimalFormatSymbols.
+     * This also sets the currency symbol attribute to the currency's symbol
+     * in the DecimalFormatSymbols' locale, and the international currency
+     * symbol attribute to the currency's ISO 4217 currency code.
+     *
+     * @param currency the new currency to be used
+     * @exception NullPointerException if <code>currency</code> is null
+     * @since 1.4
+     * @see #setCurrencySymbol
+     * @see #setInternationalCurrencySymbol
+     */
+    public void setCurrency(Currency currency) {
+        if (currency == null) {
+            throw new NullPointerException();
+        }
+        this.currency = currency;
+        intlCurrencySymbol = currency.getCurrencyCode();
+        currencySymbol = currency.getSymbol(locale);
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+
+    /**
+     * Returns the monetary decimal separator.
+     *
+     * @return the monetary decimal separator
+     * @since 1.2
+     */
+    public char getMonetaryDecimalSeparator()
+    {
+        return monetarySeparator;
+    }
+
+    /**
+     * Sets the monetary decimal separator.
+     *
+     * @param sep the monetary decimal separator
+     * @since 1.2
+     */
+    public void setMonetaryDecimalSeparator(char sep)
+    {
+        monetarySeparator = sep;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+    //------------------------------------------------------------
+    // BEGIN   Package Private methods ... to be made public later
+    //------------------------------------------------------------
+
+    /**
+     * Returns the character used to separate the mantissa from the exponent.
+     */
+    char getExponentialSymbol()
+    {
+        return exponential;
+    }
+  /**
+   * Returns the string used to separate the mantissa from the exponent.
+   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
+   *
+   * @return the exponent separator string
+   * @see #setExponentSeparator(java.lang.String)
+   * @since 1.6
+   */
+    public String getExponentSeparator()
+    {
+        return exponentialSeparator;
+    }
+
+    /**
+     * Sets the character used to separate the mantissa from the exponent.
+     */
+    void setExponentialSymbol(char exp)
+    {
+        exponential = exp;
+        // Android-added: reset cachedIcuDFS.
+        cachedIcuDFS = null;
+    }
+
+  /**
+   * Sets the string used to separate the mantissa from the exponent.
+   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
+   *
+   * @param exp the exponent separator string
+   * @exception NullPointerException if <code>exp</code> is null
+   * @see #getExponentSeparator()
+   * @since 1.6
+   */
+    public void setExponentSeparator(String exp)
+    {
+        if (exp == null) {
+            throw new NullPointerException();
+        }
+        exponentialSeparator = exp;
+     }
+
+
+    //------------------------------------------------------------
+    // END     Package Private methods ... to be made public later
+    //------------------------------------------------------------
+
+    /**
+     * Standard override.
+     */
+    @Override
+    public Object clone() {
+        try {
+            return (DecimalFormatSymbols)super.clone();
+            // other fields are bit-copied
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Override equals.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) return false;
+        if (this == obj) return true;
+        if (getClass() != obj.getClass()) return false;
+        DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
+        return (zeroDigit == other.zeroDigit &&
+        groupingSeparator == other.groupingSeparator &&
+        decimalSeparator == other.decimalSeparator &&
+        percent == other.percent &&
+        perMill == other.perMill &&
+        digit == other.digit &&
+        minusSign == other.minusSign &&
+        patternSeparator == other.patternSeparator &&
+        infinity.equals(other.infinity) &&
+        NaN.equals(other.NaN) &&
+        currencySymbol.equals(other.currencySymbol) &&
+        intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
+        currency == other.currency &&
+        monetarySeparator == other.monetarySeparator &&
+        exponentialSeparator.equals(other.exponentialSeparator) &&
+        locale.equals(other.locale));
+    }
+
+    /**
+     * Override hashCode.
+     */
+    @Override
+    public int hashCode() {
+            int result = zeroDigit;
+            result = result * 37 + groupingSeparator;
+            result = result * 37 + decimalSeparator;
+            // BEGIN Android-added: more fields in hashcode calculation.
+            result = result * 37 + percent;
+            result = result * 37 + perMill;
+            result = result * 37 + digit;
+            result = result * 37 + minusSign;
+            result = result * 37 + patternSeparator;
+            result = result * 37 + infinity.hashCode();
+            result = result * 37 + NaN.hashCode();
+            result = result * 37 + currencySymbol.hashCode();
+            result = result * 37 + intlCurrencySymbol.hashCode();
+            result = result * 37 + currency.hashCode();
+            result = result * 37 + monetarySeparator;
+            result = result * 37 + exponentialSeparator.hashCode();
+            result = result * 37 + locale.hashCode();
+           // END Android-added: more fields in hashcode calculation.
+            return result;
+    }
+
+    /**
+     * Initializes the symbols from the FormatData resource bundle.
+     */
+    private void initialize( Locale locale ) {
+        this.locale = locale;
+
+        // BEGIN Android-changed: Removed use of DecimalFormatSymbolsProvider. Switched to ICU.
+        /*
+        // get resource bundle data
+        LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
+        // Avoid potential recursions
+        if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+            adapter = LocaleProviderAdapter.getResourceBundleBased();
+        }
+        Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData();
+        */
+        if (locale == null) {
+            throw new NullPointerException("locale");
+        }
+        locale = LocaleData.mapInvalidAndNullLocales(locale);
+        LocaleData localeData = LocaleData.get(locale);
+        Object[] data = new Object[3];
+        String[] values = new String[11];
+        values[0] = String.valueOf(localeData.decimalSeparator);
+        values[1] = String.valueOf(localeData.groupingSeparator);
+        values[2] = String.valueOf(localeData.patternSeparator);
+        values[3] = localeData.percent;
+        values[4] = String.valueOf(localeData.zeroDigit);
+        values[5] = "#";
+        values[6] = localeData.minusSign;
+        values[7] = localeData.exponentSeparator;
+        values[8] = localeData.perMill;
+        values[9] = localeData.infinity;
+        values[10] = localeData.NaN;
+        data[0] = values;
+        // END Android-changed: Removed use of DecimalFormatSymbolsProvider. Switched to ICU.
+
+        String[] numberElements = (String[]) data[0];
+
+        // Android-changed: Added maybeStripMarkers
+        decimalSeparator = numberElements[0].charAt(0);
+        groupingSeparator = numberElements[1].charAt(0);
+        patternSeparator = numberElements[2].charAt(0);
+        percent = maybeStripMarkers(numberElements[3], '%');
+        zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
+        digit = numberElements[5].charAt(0);
+        minusSign = maybeStripMarkers(numberElements[6], '-');
+        exponential = numberElements[7].charAt(0);
+        exponentialSeparator = numberElements[7]; //string representation new since 1.6
+        perMill = maybeStripMarkers(numberElements[8], '\u2030');
+        infinity  = numberElements[9];
+        NaN = numberElements[10];
+
+        // Try to obtain the currency used in the locale's country.
+        // Check for empty country string separately because it's a valid
+        // country ID for Locale (and used for the C locale), but not a valid
+        // ISO 3166 country code, and exceptions are expensive.
+        if (locale.getCountry().length() > 0) {
+            try {
+                currency = Currency.getInstance(locale);
+            } catch (IllegalArgumentException e) {
+                // use default values below for compatibility
+            }
+        }
+        if (currency != null) {
+            intlCurrencySymbol = currency.getCurrencyCode();
+            if (data[1] != null && data[1] == intlCurrencySymbol) {
+                currencySymbol = (String) data[2];
+            } else {
+                currencySymbol = currency.getSymbol(locale);
+                data[1] = intlCurrencySymbol;
+                data[2] = currencySymbol;
+            }
+        } else {
+            // default values
+            intlCurrencySymbol = "XXX";
+            try {
+                currency = Currency.getInstance(intlCurrencySymbol);
+            } catch (IllegalArgumentException e) {
+            }
+            currencySymbol = "\u00A4";
+        }
+        // Currently the monetary decimal separator is the same as the
+        // standard decimal separator for all locales that we support.
+        // If that changes, add a new entry to NumberElements.
+        monetarySeparator = decimalSeparator;
+    }
+
+    // Android-changed: maybeStripMarkers added in b/26207216, fixed in b/32465689.
+    /**
+     * Attempts to strip RTL, LTR and Arabic letter markers from {@code symbol}.
+     * If the string contains a single non-marker character (and any number of marker characters),
+     * then that character is returned, otherwise {@code fallback} is returned.
+     *
+     * @hide
+     */
+    // VisibleForTesting
+    public static char maybeStripMarkers(String symbol, char fallback) {
+        final int length = symbol.length();
+        if (length >= 1) {
+            boolean sawNonMarker = false;
+            char nonMarker = 0;
+            for (int i = 0; i < length; i++) {
+                final char c = symbol.charAt(i);
+                if (c == '\u200E' || c == '\u200F' || c == '\u061C') {
+                    continue;
+                }
+                if (sawNonMarker) {
+                    // More than one non-marker character.
+                    return fallback;
+                }
+                sawNonMarker = true;
+                nonMarker = c;
+            }
+            if (sawNonMarker) {
+                return nonMarker;
+            }
+        }
+        return fallback;
+    }
+
+    // BEGIN Android-added: getIcuDecimalFormatSymbols() and fromIcuInstance().
+    /**
+     * Convert an instance of this class to the ICU version so that it can be used with ICU4J.
+     * @hide
+     */
+    protected android.icu.text.DecimalFormatSymbols getIcuDecimalFormatSymbols() {
+        if (cachedIcuDFS != null) {
+            return cachedIcuDFS;
+        }
+
+        cachedIcuDFS = new android.icu.text.DecimalFormatSymbols(this.locale);
+        // Do not localize plus sign. See "Special Pattern Characters" section in DecimalFormat.
+        // http://b/67034519
+        cachedIcuDFS.setPlusSign('+');
+        cachedIcuDFS.setZeroDigit(zeroDigit);
+        cachedIcuDFS.setDigit(digit);
+        cachedIcuDFS.setDecimalSeparator(decimalSeparator);
+        cachedIcuDFS.setGroupingSeparator(groupingSeparator);
+        // {@link #setGroupingSeparator(char)} should set grouping separator for currency, but
+        // ICU has a separate API setMonetaryGroupingSeparator. Need to call it explicitly here.
+        // http://b/38021063
+        cachedIcuDFS.setMonetaryGroupingSeparator(groupingSeparator);
+        cachedIcuDFS.setPatternSeparator(patternSeparator);
+        cachedIcuDFS.setPercent(percent);
+        cachedIcuDFS.setPerMill(perMill);
+        cachedIcuDFS.setMonetaryDecimalSeparator(monetarySeparator);
+        cachedIcuDFS.setMinusSign(minusSign);
+        cachedIcuDFS.setInfinity(infinity);
+        cachedIcuDFS.setNaN(NaN);
+        cachedIcuDFS.setExponentSeparator(exponentialSeparator);
+        // j.t.DecimalFormatSymbols doesn't insert whitespace before/after currency by default.
+        // Override ICU default value to retain historic Android behavior.
+        // http://b/112127077
+        cachedIcuDFS.setPatternForCurrencySpacing(
+            android.icu.text.DecimalFormatSymbols.CURRENCY_SPC_INSERT,
+            false /* beforeCurrency */, "");
+        cachedIcuDFS.setPatternForCurrencySpacing(
+            android.icu.text.DecimalFormatSymbols.CURRENCY_SPC_INSERT,
+            true /* beforeCurrency */, "");
+
+        try {
+            cachedIcuDFS.setCurrency(
+                    android.icu.util.Currency.getInstance(currency.getCurrencyCode()));
+        } catch (NullPointerException e) {
+            currency = Currency.getInstance("XXX");
+        }
+
+        cachedIcuDFS.setCurrencySymbol(currencySymbol);
+        cachedIcuDFS.setInternationalCurrencySymbol(intlCurrencySymbol);
+
+        return cachedIcuDFS;
+    }
+
+    /**
+     * Create an instance of DecimalFormatSymbols using the ICU equivalent of this class.
+     * @hide
+     */
+    protected static DecimalFormatSymbols fromIcuInstance(
+            android.icu.text.DecimalFormatSymbols dfs) {
+        DecimalFormatSymbols result = new DecimalFormatSymbols(dfs.getLocale());
+        result.setZeroDigit(dfs.getZeroDigit());
+        result.setDigit(dfs.getDigit());
+        result.setDecimalSeparator(dfs.getDecimalSeparator());
+        result.setGroupingSeparator(dfs.getGroupingSeparator());
+        result.setPatternSeparator(dfs.getPatternSeparator());
+        result.setPercent(dfs.getPercent());
+        result.setPerMill(dfs.getPerMill());
+        result.setMonetaryDecimalSeparator(dfs.getMonetaryDecimalSeparator());
+        result.setMinusSign(dfs.getMinusSign());
+        result.setInfinity(dfs.getInfinity());
+        result.setNaN(dfs.getNaN());
+        result.setExponentSeparator(dfs.getExponentSeparator());
+
+        try {
+            if (dfs.getCurrency() != null) {
+                result.setCurrency(Currency.getInstance(dfs.getCurrency().getCurrencyCode()));
+            } else {
+                result.setCurrency(Currency.getInstance("XXX"));
+            }
+        } catch (IllegalArgumentException e) {
+            result.setCurrency(Currency.getInstance("XXX"));
+        }
+
+        result.setInternationalCurrencySymbol(dfs.getInternationalCurrencySymbol());
+        result.setCurrencySymbol(dfs.getCurrencySymbol());
+        return result;
+    }
+    // END Android-added: getIcuDecimalFormatSymbols() and fromIcuInstance().
+
+    // BEGIN Android-added: Android specific serialization code.
+    private static final ObjectStreamField[] serialPersistentFields = {
+            new ObjectStreamField("currencySymbol", String.class),
+            new ObjectStreamField("decimalSeparator", char.class),
+            new ObjectStreamField("digit", char.class),
+            new ObjectStreamField("exponential", char.class),
+            new ObjectStreamField("exponentialSeparator", String.class),
+            new ObjectStreamField("groupingSeparator", char.class),
+            new ObjectStreamField("infinity", String.class),
+            new ObjectStreamField("intlCurrencySymbol", String.class),
+            new ObjectStreamField("minusSign", char.class),
+            new ObjectStreamField("monetarySeparator", char.class),
+            new ObjectStreamField("NaN", String.class),
+            new ObjectStreamField("patternSeparator", char.class),
+            new ObjectStreamField("percent", char.class),
+            new ObjectStreamField("perMill", char.class),
+            new ObjectStreamField("serialVersionOnStream", int.class),
+            new ObjectStreamField("zeroDigit", char.class),
+            new ObjectStreamField("locale", Locale.class),
+            new ObjectStreamField("minusSignStr", String.class),
+            new ObjectStreamField("percentStr", String.class),
+    };
+
+    private void writeObject(ObjectOutputStream stream) throws IOException {
+        ObjectOutputStream.PutField fields = stream.putFields();
+        fields.put("currencySymbol", currencySymbol);
+        fields.put("decimalSeparator", getDecimalSeparator());
+        fields.put("digit", getDigit());
+        fields.put("exponential", exponentialSeparator.charAt(0));
+        fields.put("exponentialSeparator", exponentialSeparator);
+        fields.put("groupingSeparator", getGroupingSeparator());
+        fields.put("infinity", infinity);
+        fields.put("intlCurrencySymbol", intlCurrencySymbol);
+        fields.put("monetarySeparator", getMonetaryDecimalSeparator());
+        fields.put("NaN", NaN);
+        fields.put("patternSeparator", getPatternSeparator());
+        fields.put("perMill", getPerMill());
+        fields.put("serialVersionOnStream", 3);
+        fields.put("zeroDigit", getZeroDigit());
+        fields.put("locale", locale);
+
+        // Hardcode values here for backwards compatibility. These values will only be used
+        // if we're de-serializing this object on an earlier version of android.
+        fields.put("minusSign", minusSign);
+        fields.put("percent", percent);
+
+        fields.put("minusSignStr", getMinusSignString());
+        fields.put("percentStr", getPercentString());
+        stream.writeFields();
+    }
+    // END Android-added: Android specific serialization code.
+
+    /**
+     * Reads the default serializable fields, provides default values for objects
+     * in older serial versions, and initializes non-serializable fields.
+     * If <code>serialVersionOnStream</code>
+     * is less than 1, initializes <code>monetarySeparator</code> to be
+     * the same as <code>decimalSeparator</code> and <code>exponential</code>
+     * to be 'E'.
+     * If <code>serialVersionOnStream</code> is less than 2,
+     * initializes <code>locale</code>to the root locale, and initializes
+     * If <code>serialVersionOnStream</code> is less than 3, it initializes
+     * <code>exponentialSeparator</code> using <code>exponential</code>.
+     * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
+     * default serialization will work properly if this object is streamed out again.
+     * Initializes the currency from the intlCurrencySymbol field.
+     *
+     * @since JDK 1.1.6
+     */
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        // BEGIN Android-changed: Android specific serialization code.
+        ObjectInputStream.GetField fields = stream.readFields();
+        final int serialVersionOnStream = fields.get("serialVersionOnStream", 0);
+        currencySymbol = (String) fields.get("currencySymbol", "");
+        setDecimalSeparator(fields.get("decimalSeparator", '.'));
+        setDigit(fields.get("digit", '#'));
+        setGroupingSeparator(fields.get("groupingSeparator", ','));
+        infinity = (String) fields.get("infinity", "");
+        intlCurrencySymbol = (String) fields.get("intlCurrencySymbol", "");
+        NaN = (String) fields.get("NaN", "");
+        setPatternSeparator(fields.get("patternSeparator", ';'));
+
+        // Special handling for minusSign and percent. If we've serialized the string versions of
+        // these fields, use them. If not, fall back to the single character versions. This can
+        // only happen if we're de-serializing an object that was written by an older version of
+        // android (something that's strongly discouraged anyway).
+        final String minusSignStr = (String) fields.get("minusSignStr", null);
+        if (minusSignStr != null) {
+            minusSign = minusSignStr.charAt(0);
+        } else {
+            setMinusSign(fields.get("minusSign", '-'));
+        }
+        final String percentStr = (String) fields.get("percentStr", null);
+        if (percentStr != null) {
+            percent = percentStr.charAt(0);
+        } else {
+            setPercent(fields.get("percent", '%'));
+        }
+
+        setPerMill(fields.get("perMill", '\u2030'));
+        setZeroDigit(fields.get("zeroDigit", '0'));
+        locale = (Locale) fields.get("locale", null);
+        if (serialVersionOnStream == 0) {
+            setMonetaryDecimalSeparator(getDecimalSeparator());
+        } else {
+            setMonetaryDecimalSeparator(fields.get("monetarySeparator", '.'));
+        }
+
+        if (serialVersionOnStream == 0) {
+            // Prior to Java 1.1.6, the exponent separator wasn't configurable.
+            exponentialSeparator = "E";
+        } else if (serialVersionOnStream < 3) {
+            // In Javas 1.1.6 and 1.4, there was a character field "exponential".
+            setExponentSeparator(String.valueOf(fields.get("exponential", 'E')));
+        } else {
+            // In Java 6, there's a new "exponentialSeparator" field.
+            setExponentSeparator((String) fields.get("exponentialSeparator", "E"));
+        }
+
+        try {
+            currency = Currency.getInstance(intlCurrencySymbol);
+        } catch (IllegalArgumentException e) {
+            currency = null;
+        }
+        // END Android-changed: Android specific serialization code.
+    }
+
+    /**
+     * Character used for zero.
+     *
+     * @serial
+     * @see #getZeroDigit
+     */
+    private  char    zeroDigit;
+
+    /**
+     * Character used for thousands separator.
+     *
+     * @serial
+     * @see #getGroupingSeparator
+     */
+    private  char    groupingSeparator;
+
+    /**
+     * Character used for decimal sign.
+     *
+     * @serial
+     * @see #getDecimalSeparator
+     */
+    private  char    decimalSeparator;
+
+    /**
+     * Character used for per mille sign.
+     *
+     * @serial
+     * @see #getPerMill
+     */
+    private  char    perMill;
+
+    /**
+     * Character used for percent sign.
+     * @serial
+     * @see #getPercent
+     */
+    private  char    percent;
+
+    /**
+     * Character used for a digit in a pattern.
+     *
+     * @serial
+     * @see #getDigit
+     */
+    private  char    digit;
+
+    /**
+     * Character used to separate positive and negative subpatterns
+     * in a pattern.
+     *
+     * @serial
+     * @see #getPatternSeparator
+     */
+    private  char    patternSeparator;
+
+    /**
+     * String used to represent infinity.
+     * @serial
+     * @see #getInfinity
+     */
+    private  String  infinity;
+
+    /**
+     * String used to represent "not a number".
+     * @serial
+     * @see #getNaN
+     */
+    private  String  NaN;
+
+    /**
+     * Character used to represent minus sign.
+     * @serial
+     * @see #getMinusSign
+     */
+    private  char    minusSign;
+
+    /**
+     * String denoting the local currency, e.g. "$".
+     * @serial
+     * @see #getCurrencySymbol
+     */
+    private  String  currencySymbol;
+
+    /**
+     * ISO 4217 currency code denoting the local currency, e.g. "USD".
+     * @serial
+     * @see #getInternationalCurrencySymbol
+     */
+    private  String  intlCurrencySymbol;
+
+    /**
+     * The decimal separator used when formatting currency values.
+     * @serial
+     * @since JDK 1.1.6
+     * @see #getMonetaryDecimalSeparator
+     */
+    private  char    monetarySeparator; // Field new in JDK 1.1.6
+
+    /**
+     * The character used to distinguish the exponent in a number formatted
+     * in exponential notation, e.g. 'E' for a number such as "1.23E45".
+     * <p>
+     * Note that the public API provides no way to set this field,
+     * even though it is supported by the implementation and the stream format.
+     * The intent is that this will be added to the API in the future.
+     *
+     * @serial
+     * @since JDK 1.1.6
+     */
+    private  char    exponential;       // Field new in JDK 1.1.6
+
+  /**
+   * The string used to separate the mantissa from the exponent.
+   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
+   * <p>
+   * If both <code>exponential</code> and <code>exponentialSeparator</code>
+   * exist, this <code>exponentialSeparator</code> has the precedence.
+   *
+   * @serial
+   * @since 1.6
+   */
+    private  String    exponentialSeparator;       // Field new in JDK 1.6
+
+    /**
+     * The locale of these currency format symbols.
+     *
+     * @serial
+     * @since 1.4
+     */
+    private Locale locale;
+
+    // currency; only the ISO code is serialized.
+    private transient Currency currency;
+
+    // Proclaim JDK 1.1 FCS compatibility
+    static final long serialVersionUID = 5772796243397350300L;
+
+    // The internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.5
+    // - 1 for version from JDK 1.1.6, which includes two new fields:
+    //     monetarySeparator and exponential.
+    // - 2 for version from J2SE 1.4, which includes locale field.
+    // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
+    private static final int currentSerialVersion = 3;
+
+    /**
+     * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
+     * Possible values are:
+     * <ul>
+     * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
+     *
+     * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
+     *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
+     * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
+     *      new <code>locale</code> field.
+     * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
+     *      new <code>exponentialSeparator</code> field.
+     * </ul>
+     * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
+     * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
+     * is always written.
+     *
+     * @serial
+     * @since JDK 1.1.6
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+
+    // BEGIN Android-added: cache for cachedIcuDFS.
+    /**
+     * Lazily created cached instance of an ICU DecimalFormatSymbols that's equivalent to this one.
+     * This field is reset to null whenever any of the relevant fields of this class are modified
+     * and will be re-created by {@link #getIcuDecimalFormatSymbols()} as necessary.
+     */
+    private transient android.icu.text.DecimalFormatSymbols cachedIcuDFS = null;
+    // END Android-added: cache for cachedIcuDFS.
+}
diff --git a/java/text/DontCareFieldPosition.java b/java/text/DontCareFieldPosition.java
new file mode 100644
index 0000000..33c086d
--- /dev/null
+++ b/java/text/DontCareFieldPosition.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.text;
+
+/**
+ * DontCareFieldPosition defines no-op FieldDelegate. Its
+ * singleton is used for the format methods that don't take a
+ * FieldPosition.
+ */
+class DontCareFieldPosition extends FieldPosition {
+    // The singleton of DontCareFieldPosition.
+    static final FieldPosition INSTANCE = new DontCareFieldPosition();
+
+    private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
+        public void formatted(Format.Field attr, Object value, int start,
+                              int end, StringBuffer buffer) {
+        }
+        public void formatted(int fieldID, Format.Field attr, Object value,
+                              int start, int end, StringBuffer buffer) {
+        }
+    };
+
+    private DontCareFieldPosition() {
+        super(0);
+    }
+
+    Format.FieldDelegate getFieldDelegate() {
+        return noDelegate;
+    }
+}
diff --git a/java/text/EntryPair.java b/java/text/EntryPair.java
new file mode 100644
index 0000000..3d74381
--- /dev/null
+++ b/java/text/EntryPair.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+/**
+ * This is used for building contracting character tables.  entryName
+ * is the contracting character name and value is its collation
+ * order.
+ */
+final class EntryPair
+{
+    public String entryName;
+    public int value;
+    public boolean fwd;
+
+    public EntryPair(String name, int value) {
+        this(name, value, true);
+    }
+    public EntryPair(String name, int value, boolean fwd) {
+        this.entryName = name;
+        this.value = value;
+        this.fwd = fwd;
+    }
+}
diff --git a/java/text/FieldPosition.java b/java/text/FieldPosition.java
new file mode 100644
index 0000000..955221d
--- /dev/null
+++ b/java/text/FieldPosition.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+/**
+ * <code>FieldPosition</code> is a simple class used by <code>Format</code>
+ * and its subclasses to identify fields in formatted output. Fields can
+ * be identified in two ways:
+ * <ul>
+ *  <li>By an integer constant, whose names typically end with
+ *      <code>_FIELD</code>. The constants are defined in the various
+ *      subclasses of <code>Format</code>.
+ *  <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
+ *      and its friends in <code>DateFormat</code> for an example.
+ * </ul>
+ * <p>
+ * <code>FieldPosition</code> keeps track of the position of the
+ * field within the formatted output with two indices: the index
+ * of the first character of the field and the index of the last
+ * character of the field.
+ *
+ * <p>
+ * One version of the <code>format</code> method in the various
+ * <code>Format</code> classes requires a <code>FieldPosition</code>
+ * object as an argument. You use this <code>format</code> method
+ * to perform partial formatting or to get information about the
+ * formatted output (such as the position of a field).
+ *
+ * <p>
+ * If you are interested in the positions of all attributes in the
+ * formatted string use the <code>Format</code> method
+ * <code>formatToCharacterIterator</code>.
+ *
+ * @author      Mark Davis
+ * @see         java.text.Format
+ */
+public class FieldPosition {
+
+    /**
+     * Input: Desired field to determine start and end offsets for.
+     * The meaning depends on the subclass of Format.
+     */
+    int field = 0;
+
+    /**
+     * Output: End offset of field in text.
+     * If the field does not occur in the text, 0 is returned.
+     */
+    int endIndex = 0;
+
+    /**
+     * Output: Start offset of field in text.
+     * If the field does not occur in the text, 0 is returned.
+     */
+    int beginIndex = 0;
+
+    /**
+     * Desired field this FieldPosition is for.
+     */
+    private Format.Field attribute;
+
+    /**
+     * Creates a FieldPosition object for the given field.  Fields are
+     * identified by constants, whose names typically end with _FIELD,
+     * in the various subclasses of Format.
+     *
+     * @param field the field identifier
+     * @see java.text.NumberFormat#INTEGER_FIELD
+     * @see java.text.NumberFormat#FRACTION_FIELD
+     * @see java.text.DateFormat#YEAR_FIELD
+     * @see java.text.DateFormat#MONTH_FIELD
+     */
+    public FieldPosition(int field) {
+        this.field = field;
+    }
+
+    /**
+     * Creates a FieldPosition object for the given field constant. Fields are
+     * identified by constants defined in the various <code>Format</code>
+     * subclasses. This is equivalent to calling
+     * <code>new FieldPosition(attribute, -1)</code>.
+     *
+     * @param attribute Format.Field constant identifying a field
+     * @since 1.4
+     */
+    public FieldPosition(Format.Field attribute) {
+        this(attribute, -1);
+    }
+
+    /**
+     * Creates a <code>FieldPosition</code> object for the given field.
+     * The field is identified by an attribute constant from one of the
+     * <code>Field</code> subclasses as well as an integer field ID
+     * defined by the <code>Format</code> subclasses. <code>Format</code>
+     * subclasses that are aware of <code>Field</code> should give precedence
+     * to <code>attribute</code> and ignore <code>fieldID</code> if
+     * <code>attribute</code> is not null. However, older <code>Format</code>
+     * subclasses may not be aware of <code>Field</code> and rely on
+     * <code>fieldID</code>. If the field has no corresponding integer
+     * constant, <code>fieldID</code> should be -1.
+     *
+     * @param attribute Format.Field constant identifying a field
+     * @param fieldID integer constant identifying a field
+     * @since 1.4
+     */
+    public FieldPosition(Format.Field attribute, int fieldID) {
+        this.attribute = attribute;
+        this.field = fieldID;
+    }
+
+    /**
+     * Returns the field identifier as an attribute constant
+     * from one of the <code>Field</code> subclasses. May return null if
+     * the field is specified only by an integer field ID.
+     *
+     * @return Identifier for the field
+     * @since 1.4
+     */
+    public Format.Field getFieldAttribute() {
+        return attribute;
+    }
+
+    /**
+     * Retrieves the field identifier.
+     *
+     * @return the field identifier
+     */
+    public int getField() {
+        return field;
+    }
+
+    /**
+     * Retrieves the index of the first character in the requested field.
+     *
+     * @return the begin index
+     */
+    public int getBeginIndex() {
+        return beginIndex;
+    }
+
+    /**
+     * Retrieves the index of the character following the last character in the
+     * requested field.
+     *
+     * @return the end index
+     */
+    public int getEndIndex() {
+        return endIndex;
+    }
+
+    /**
+     * Sets the begin index.  For use by subclasses of Format.
+     *
+     * @param bi the begin index
+     * @since 1.2
+     */
+    public void setBeginIndex(int bi) {
+        beginIndex = bi;
+    }
+
+    /**
+     * Sets the end index.  For use by subclasses of Format.
+     *
+     * @param ei the end index
+     * @since 1.2
+     */
+    public void setEndIndex(int ei) {
+        endIndex = ei;
+    }
+
+    /**
+     * Returns a <code>Format.FieldDelegate</code> instance that is associated
+     * with the FieldPosition. When the delegate is notified of the same
+     * field the FieldPosition is associated with, the begin/end will be
+     * adjusted.
+     */
+    Format.FieldDelegate getFieldDelegate() {
+        return new Delegate();
+    }
+
+    /**
+     * Overrides equals
+     */
+    public boolean equals(Object obj)
+    {
+        if (obj == null) return false;
+        if (!(obj instanceof FieldPosition))
+            return false;
+        FieldPosition other = (FieldPosition) obj;
+        if (attribute == null) {
+            if (other.attribute != null) {
+                return false;
+            }
+        }
+        else if (!attribute.equals(other.attribute)) {
+            return false;
+        }
+        return (beginIndex == other.beginIndex
+            && endIndex == other.endIndex
+            && field == other.field);
+    }
+
+    /**
+     * Returns a hash code for this FieldPosition.
+     * @return a hash code value for this object
+     */
+    public int hashCode() {
+        return (field << 24) | (beginIndex << 16) | endIndex;
+    }
+
+    /**
+     * Return a string representation of this FieldPosition.
+     * @return  a string representation of this object
+     */
+    public String toString() {
+        return getClass().getName() +
+            "[field=" + field + ",attribute=" + attribute +
+            ",beginIndex=" + beginIndex +
+            ",endIndex=" + endIndex + ']';
+    }
+
+
+    /**
+     * Return true if the receiver wants a <code>Format.Field</code> value and
+     * <code>attribute</code> is equal to it.
+     */
+    private boolean matchesField(Format.Field attribute) {
+        if (this.attribute != null) {
+            return this.attribute.equals(attribute);
+        }
+        return false;
+    }
+
+    /**
+     * Return true if the receiver wants a <code>Format.Field</code> value and
+     * <code>attribute</code> is equal to it, or true if the receiver
+     * represents an inteter constant and <code>field</code> equals it.
+     */
+    private boolean matchesField(Format.Field attribute, int field) {
+        if (this.attribute != null) {
+            return this.attribute.equals(attribute);
+        }
+        return (field == this.field);
+    }
+
+
+    /**
+     * An implementation of FieldDelegate that will adjust the begin/end
+     * of the FieldPosition if the arguments match the field of
+     * the FieldPosition.
+     */
+    private class Delegate implements Format.FieldDelegate {
+        /**
+         * Indicates whether the field has been  encountered before. If this
+         * is true, and <code>formatted</code> is invoked, the begin/end
+         * are not updated.
+         */
+        private boolean encounteredField;
+
+        public void formatted(Format.Field attr, Object value, int start,
+                              int end, StringBuffer buffer) {
+            if (!encounteredField && matchesField(attr)) {
+                setBeginIndex(start);
+                setEndIndex(end);
+                encounteredField = (start != end);
+            }
+        }
+
+        public void formatted(int fieldID, Format.Field attr, Object value,
+                              int start, int end, StringBuffer buffer) {
+            if (!encounteredField && matchesField(attr, fieldID)) {
+                setBeginIndex(start);
+                setEndIndex(end);
+                encounteredField = (start != end);
+            }
+        }
+    }
+}
diff --git a/java/text/Format.java b/java/text/Format.java
new file mode 100644
index 0000000..74fcc37
--- /dev/null
+++ b/java/text/Format.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.Serializable;
+
+/**
+ * <code>Format</code> is an abstract base class for formatting locale-sensitive
+ * information such as dates, messages, and numbers.
+ *
+ * <p>
+ * <code>Format</code> defines the programming interface for formatting
+ * locale-sensitive objects into <code>String</code>s (the
+ * <code>format</code> method) and for parsing <code>String</code>s back
+ * into objects (the <code>parseObject</code> method).
+ *
+ * <p>
+ * Generally, a format's <code>parseObject</code> method must be able to parse
+ * any string formatted by its <code>format</code> method. However, there may
+ * be exceptional cases where this is not possible. For example, a
+ * <code>format</code> method might create two adjacent integer numbers with
+ * no separator in between, and in this case the <code>parseObject</code> could
+ * not tell which digits belong to which number.
+ *
+ * <h3>Subclassing</h3>
+ *
+ * <p>
+ * The Java Platform provides three specialized subclasses of <code>Format</code>--
+ * <code>DateFormat</code>, <code>MessageFormat</code>, and
+ * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
+ * respectively.
+ * <p>
+ * Concrete subclasses must implement three methods:
+ * <ol>
+ * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
+ * <li> <code>formatToCharacterIterator(Object obj)</code>
+ * <li> <code>parseObject(String source, ParsePosition pos)</code>
+ * </ol>
+ * These general methods allow polymorphic parsing and formatting of objects
+ * and are used, for example, by <code>MessageFormat</code>.
+ * Subclasses often also provide additional <code>format</code> methods for
+ * specific input types as well as <code>parse</code> methods for specific
+ * result types. Any <code>parse</code> method that does not take a
+ * <code>ParsePosition</code> argument should throw <code>ParseException</code>
+ * when no text in the required format is at the beginning of the input text.
+ *
+ * <p>
+ * Most subclasses will also implement the following factory methods:
+ * <ol>
+ * <li>
+ * <code>getInstance</code> for getting a useful format object appropriate
+ * for the current locale
+ * <li>
+ * <code>getInstance(Locale)</code> for getting a useful format
+ * object appropriate for the specified locale
+ * </ol>
+ * In addition, some subclasses may also implement other
+ * <code>getXxxxInstance</code> methods for more specialized control. For
+ * example, the <code>NumberFormat</code> class provides
+ * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
+ * methods for getting specialized number formatters.
+ *
+ * <p>
+ * Subclasses of <code>Format</code> that allow programmers to create objects
+ * for locales (with <code>getInstance(Locale)</code> for example)
+ * must also implement the following class method:
+ * <blockquote>
+ * <pre>
+ * public static Locale[] getAvailableLocales()
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * And finally subclasses may define a set of constants to identify the various
+ * fields in the formatted output. These constants are used to create a FieldPosition
+ * object which identifies what information is contained in the field and its
+ * position in the formatted result. These constants should be named
+ * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
+ * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
+ * friends in {@link DateFormat}.
+ *
+ * <h4><a name="synchronization">Synchronization</a></h4>
+ *
+ * <p>
+ * Formats are generally not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * @see          java.text.ParsePosition
+ * @see          java.text.FieldPosition
+ * @see          java.text.NumberFormat
+ * @see          java.text.DateFormat
+ * @see          java.text.MessageFormat
+ * @author       Mark Davis
+ */
+public abstract class Format implements Serializable, Cloneable {
+
+    private static final long serialVersionUID = -299282585814624189L;
+
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected Format() {
+    }
+
+    /**
+     * Formats an object to produce a string. This is equivalent to
+     * <blockquote>
+     * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
+     *         new StringBuffer(), new FieldPosition(0)).toString();</code>
+     * </blockquote>
+     *
+     * @param obj    The object to format
+     * @return       Formatted string.
+     * @exception IllegalArgumentException if the Format cannot format the given
+     *            object
+     */
+    public final String format (Object obj) {
+        return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
+    }
+
+    /**
+     * Formats an object and appends the resulting text to a given string
+     * buffer.
+     * If the <code>pos</code> argument identifies a field used by the format,
+     * then its indices are set to the beginning and end of the first such
+     * field encountered.
+     *
+     * @param obj    The object to format
+     * @param toAppendTo    where the text is to be appended
+     * @param pos    A <code>FieldPosition</code> identifying a field
+     *               in the formatted text
+     * @return       the string buffer passed in as <code>toAppendTo</code>,
+     *               with formatted text appended
+     * @exception NullPointerException if <code>toAppendTo</code> or
+     *            <code>pos</code> is null
+     * @exception IllegalArgumentException if the Format cannot format the given
+     *            object
+     */
+    public abstract StringBuffer format(Object obj,
+                    StringBuffer toAppendTo,
+                    FieldPosition pos);
+
+    /**
+     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
+     * You can use the returned <code>AttributedCharacterIterator</code>
+     * to build the resulting String, as well as to determine information
+     * about the resulting String.
+     * <p>
+     * Each attribute key of the AttributedCharacterIterator will be of type
+     * <code>Field</code>. It is up to each <code>Format</code> implementation
+     * to define what the legal values are for each attribute in the
+     * <code>AttributedCharacterIterator</code>, but typically the attribute
+     * key is also used as the attribute value.
+     * <p>The default implementation creates an
+     * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
+     * that support fields should override this and create an
+     * <code>AttributedCharacterIterator</code> with meaningful attributes.
+     *
+     * @exception NullPointerException if obj is null.
+     * @exception IllegalArgumentException when the Format cannot format the
+     *            given object.
+     * @param obj The object to format
+     * @return AttributedCharacterIterator describing the formatted value.
+     * @since 1.4
+     */
+    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
+        return createAttributedCharacterIterator(format(obj));
+    }
+
+    /**
+     * Parses text from a string to produce an object.
+     * <p>
+     * The method attempts to parse text starting at the index given by
+     * <code>pos</code>.
+     * If parsing succeeds, then the index of <code>pos</code> is updated
+     * to the index after the last character used (parsing does not necessarily
+     * use all characters up to the end of the string), and the parsed
+     * object is returned. The updated <code>pos</code> can be used to
+     * indicate the starting point for the next call to this method.
+     * If an error occurs, then the index of <code>pos</code> is not
+     * changed, the error index of <code>pos</code> is set to the index of
+     * the character where the error occurred, and null is returned.
+     *
+     * @param source A <code>String</code>, part of which should be parsed.
+     * @param pos A <code>ParsePosition</code> object with index and error
+     *            index information as described above.
+     * @return An <code>Object</code> parsed from the string. In case of
+     *         error, returns null.
+     * @exception NullPointerException if <code>pos</code> is null.
+     */
+    public abstract Object parseObject (String source, ParsePosition pos);
+
+    /**
+     * Parses text from the beginning of the given string to produce an object.
+     * The method may not use the entire text of the given string.
+     *
+     * @param source A <code>String</code> whose beginning should be parsed.
+     * @return An <code>Object</code> parsed from the string.
+     * @exception ParseException if the beginning of the specified string
+     *            cannot be parsed.
+     */
+    public Object parseObject(String source) throws ParseException {
+        ParsePosition pos = new ParsePosition(0);
+        Object result = parseObject(source, pos);
+        if (pos.index == 0) {
+            throw new ParseException("Format.parseObject(String) failed",
+                pos.errorIndex);
+        }
+        return result;
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     *
+     * @return a clone of this instance.
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            // will never happen
+            throw new InternalError(e);
+        }
+    }
+
+    //
+    // Convenience methods for creating AttributedCharacterIterators from
+    // different parameters.
+    //
+
+    /**
+     * Creates an <code>AttributedCharacterIterator</code> for the String
+     * <code>s</code>.
+     *
+     * @param s String to create AttributedCharacterIterator from
+     * @return AttributedCharacterIterator wrapping s
+     */
+    AttributedCharacterIterator createAttributedCharacterIterator(String s) {
+        AttributedString as = new AttributedString(s);
+
+        return as.getIterator();
+    }
+
+    /**
+     * Creates an <code>AttributedCharacterIterator</code> containing the
+     * concatenated contents of the passed in
+     * <code>AttributedCharacterIterator</code>s.
+     *
+     * @param iterators AttributedCharacterIterators used to create resulting
+     *                  AttributedCharacterIterators
+     * @return AttributedCharacterIterator wrapping passed in
+     *         AttributedCharacterIterators
+     */
+    AttributedCharacterIterator createAttributedCharacterIterator(
+                       AttributedCharacterIterator[] iterators) {
+        AttributedString as = new AttributedString(iterators);
+
+        return as.getIterator();
+    }
+
+    /**
+     * Returns an AttributedCharacterIterator with the String
+     * <code>string</code> and additional key/value pair <code>key</code>,
+     * <code>value</code>.
+     *
+     * @param string String to create AttributedCharacterIterator from
+     * @param key Key for AttributedCharacterIterator
+     * @param value Value associated with key in AttributedCharacterIterator
+     * @return AttributedCharacterIterator wrapping args
+     */
+    AttributedCharacterIterator createAttributedCharacterIterator(
+                      String string, AttributedCharacterIterator.Attribute key,
+                      Object value) {
+        AttributedString as = new AttributedString(string);
+
+        as.addAttribute(key, value);
+        return as.getIterator();
+    }
+
+    /**
+     * Creates an AttributedCharacterIterator with the contents of
+     * <code>iterator</code> and the additional attribute <code>key</code>
+     * <code>value</code>.
+     *
+     * @param iterator Initial AttributedCharacterIterator to add arg to
+     * @param key Key for AttributedCharacterIterator
+     * @param value Value associated with key in AttributedCharacterIterator
+     * @return AttributedCharacterIterator wrapping args
+     */
+    AttributedCharacterIterator createAttributedCharacterIterator(
+              AttributedCharacterIterator iterator,
+              AttributedCharacterIterator.Attribute key, Object value) {
+        AttributedString as = new AttributedString(iterator);
+
+        as.addAttribute(key, value);
+        return as.getIterator();
+    }
+
+
+    /**
+     * Defines constants that are used as attribute keys in the
+     * <code>AttributedCharacterIterator</code> returned
+     * from <code>Format.formatToCharacterIterator</code> and as
+     * field identifiers in <code>FieldPosition</code>.
+     *
+     * @since 1.4
+     */
+    public static class Field extends AttributedCharacterIterator.Attribute {
+
+        // Proclaim serial compatibility with 1.4 FCS
+        private static final long serialVersionUID = 276966692217360283L;
+
+        /**
+         * Creates a Field with the specified name.
+         *
+         * @param name Name of the attribute
+         */
+        protected Field(String name) {
+            super(name);
+        }
+    }
+
+
+    /**
+     * FieldDelegate is notified by the various <code>Format</code>
+     * implementations as they are formatting the Objects. This allows for
+     * storage of the individual sections of the formatted String for
+     * later use, such as in a <code>FieldPosition</code> or for an
+     * <code>AttributedCharacterIterator</code>.
+     * <p>
+     * Delegates should NOT assume that the <code>Format</code> will notify
+     * the delegate of fields in any particular order.
+     *
+     * @see FieldPosition#getFieldDelegate
+     * @see CharacterIteratorFieldDelegate
+     */
+    interface FieldDelegate {
+        /**
+         * Notified when a particular region of the String is formatted. This
+         * method will be invoked if there is no corresponding integer field id
+         * matching <code>attr</code>.
+         *
+         * @param attr Identifies the field matched
+         * @param value Value associated with the field
+         * @param start Beginning location of the field, will be >= 0
+         * @param end End of the field, will be >= start and <= buffer.length()
+         * @param buffer Contains current formatted value, receiver should
+         *        NOT modify it.
+         */
+        public void formatted(Format.Field attr, Object value, int start,
+                              int end, StringBuffer buffer);
+
+        /**
+         * Notified when a particular region of the String is formatted.
+         *
+         * @param fieldID Identifies the field by integer
+         * @param attr Identifies the field matched
+         * @param value Value associated with the field
+         * @param start Beginning location of the field, will be >= 0
+         * @param end End of the field, will be >= start and <= buffer.length()
+         * @param buffer Contains current formatted value, receiver should
+         *        NOT modify it.
+         */
+        public void formatted(int fieldID, Format.Field attr, Object value,
+                              int start, int end, StringBuffer buffer);
+    }
+}
diff --git a/java/text/IcuIteratorWrapper.java b/java/text/IcuIteratorWrapper.java
new file mode 100644
index 0000000..024d6d1
--- /dev/null
+++ b/java/text/IcuIteratorWrapper.java
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ */
+
+
+package java.text;
+
+/**
+ * <p>A subclass of BreakIterator whose behavior is specified using a list of rules.</p>
+ *
+ * <p>There are two kinds of rules, which are separated by semicolons: <i>substitutions</i>
+ * and <i>regular expressions.</i></p>
+ *
+ * <p>A substitution rule defines a name that can be used in place of an expression. It
+ * consists of a name, which is a string of characters contained in angle brackets, an equals
+ * sign, and an expression. (There can be no whitespace on either side of the equals sign.)
+ * To keep its syntactic meaning intact, the expression must be enclosed in parentheses or
+ * square brackets. A substitution is visible after its definition, and is filled in using
+ * simple textual substitution. Substitution definitions can contain other substitutions, as
+ * long as those substitutions have been defined first. Substitutions are generally used to
+ * make the regular expressions (which can get quite complex) shorted and easier to read.
+ * They typically define either character categories or commonly-used subexpressions.</p>
+ *
+ * <p>There is one special substitution.&nbsp; If the description defines a substitution
+ * called &quot;&lt;ignore&gt;&quot;, the expression must be a [] expression, and the
+ * expression defines a set of characters (the &quot;<em>ignore characters</em>&quot;) that
+ * will be transparent to the BreakIterator.&nbsp; A sequence of characters will break the
+ * same way it would if any ignore characters it contains are taken out.&nbsp; Break
+ * positions never occur befoer ignore characters.</p>
+ *
+ * <p>A regular expression uses a subset of the normal Unix regular-expression syntax, and
+ * defines a sequence of characters to be kept together. With one significant exception, the
+ * iterator uses a longest-possible-match algorithm when matching text to regular
+ * expressions. The iterator also treats descriptions containing multiple regular expressions
+ * as if they were ORed together (i.e., as if they were separated by |).</p>
+ *
+ * <p>The special characters recognized by the regular-expression parser are as follows:</p>
+ *
+ * <blockquote>
+ * <table border="1" width="100%">
+ * <tr>
+ * <td width="6%">*</td>
+ * <td width="94%">Specifies that the expression preceding the asterisk may occur any number
+ * of times (including not at all).</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">{}</td>
+ * <td width="94%">Encloses a sequence of characters that is optional.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">()</td>
+ * <td width="94%">Encloses a sequence of characters.&nbsp; If followed by *, the sequence
+ * repeats.&nbsp; Otherwise, the parentheses are just a grouping device and a way to delimit
+ * the ends of expressions containing |.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">|</td>
+ * <td width="94%">Separates two alternative sequences of characters.&nbsp; Either one
+ * sequence or the other, but not both, matches this expression.&nbsp; The | character can
+ * only occur inside ().</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">.</td>
+ * <td width="94%">Matches any character.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">*?</td>
+ * <td width="94%">Specifies a non-greedy asterisk.&nbsp; *? works the same way as *, except
+ * when there is overlap between the last group of characters in the expression preceding the
+ * * and the first group of characters following the *.&nbsp; When there is this kind of
+ * overlap, * will match the longest sequence of characters that match the expression before
+ * the *, and *? will match the shortest sequence of characters matching the expression
+ * before the *?.&nbsp; For example, if you have &quot;xxyxyyyxyxyxxyxyxyy&quot; in the text,
+ * &quot;x[xy]*x&quot; will match through to the last x (i.e., &quot;<strong>xxyxyyyxyxyxxyxyx</strong>yy&quot;,
+ * but &quot;x[xy]*?x&quot; will only match the first two xes (&quot;<strong>xx</strong>yxyyyxyxyxxyxyxyy&quot;).</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">[]</td>
+ * <td width="94%">Specifies a group of alternative characters.&nbsp; A [] expression will
+ * match any single character that is specified in the [] expression.&nbsp; For more on the
+ * syntax of [] expressions, see below.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">/</td>
+ * <td width="94%">Specifies where the break position should go if text matches this
+ * expression.&nbsp; (e.g., &quot;[a-z]&#42;/[:Zs:]*[1-0]&quot; will match if the iterator sees a
+ * run
+ * of letters, followed by a run of whitespace, followed by a digit, but the break position
+ * will actually go before the whitespace).&nbsp; Expressions that don't contain / put the
+ * break position at the end of the matching text.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">\</td>
+ * <td width="94%">Escape character.&nbsp; The \ itself is ignored, but causes the next
+ * character to be treated as literal character.&nbsp; This has no effect for many
+ * characters, but for the characters listed above, this deprives them of their special
+ * meaning.&nbsp; (There are no special escape sequences for Unicode characters, or tabs and
+ * newlines; these are all handled by a higher-level protocol.&nbsp; In a Java string,
+ * &quot;\n&quot; will be converted to a literal newline character by the time the
+ * regular-expression parser sees it.&nbsp; Of course, this means that \ sequences that are
+ * visible to the regexp parser must be written as \\ when inside a Java string.)&nbsp; All
+ * characters in the ASCII range except for letters, digits, and control characters are
+ * reserved characters to the parser and must be preceded by \ even if they currently don't
+ * mean anything.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">!</td>
+ * <td width="94%">If ! appears at the beginning of a regular expression, it tells the regexp
+ * parser that this expression specifies the backwards-iteration behavior of the iterator,
+ * and not its normal iteration behavior.&nbsp; This is generally only used in situations
+ * where the automatically-generated backwards-iteration brhavior doesn't produce
+ * satisfactory results and must be supplemented with extra client-specified rules.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%"><em>(all others)</em></td>
+ * <td width="94%">All other characters are treated as literal characters, which must match
+ * the corresponding character(s) in the text exactly.</td>
+ * </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p>Within a [] expression, a number of other special characters can be used to specify
+ * groups of characters:</p>
+ *
+ * <blockquote>
+ * <table border="1" width="100%">
+ * <tr>
+ * <td width="6%">-</td>
+ * <td width="94%">Specifies a range of matching characters.&nbsp; For example
+ * &quot;[a-p]&quot; matches all lowercase Latin letters from a to p (inclusive).&nbsp; The -
+ * sign specifies ranges of continuous Unicode numeric values, not ranges of characters in a
+ * language's alphabetical order: &quot;[a-z]&quot; doesn't include capital letters, nor does
+ * it include accented letters such as a-umlaut.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">::</td>
+ * <td width="94%">A pair of colons containing a one- or two-letter code matches all
+ * characters in the corresponding Unicode category.&nbsp; The two-letter codes are the same
+ * as the two-letter codes in the Unicode database (for example, &quot;[:Sc::Sm:]&quot;
+ * matches all currency symbols and all math symbols).&nbsp; Specifying a one-letter code is
+ * the same as specifying all two-letter codes that begin with that letter (for example,
+ * &quot;[:L:]&quot; matches all letters, and is equivalent to
+ * &quot;[:Lu::Ll::Lo::Lm::Lt:]&quot;).&nbsp; Anything other than a valid two-letter Unicode
+ * category code or a single letter that begins a Unicode category code is illegal within
+ * colons.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">[]</td>
+ * <td width="94%">[] expressions can nest.&nbsp; This has no effect, except when used in
+ * conjunction with the ^ token.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%">^</td>
+ * <td width="94%">Excludes the character (or the characters in the [] expression) following
+ * it from the group of characters.&nbsp; For example, &quot;[a-z^p]&quot; matches all Latin
+ * lowercase letters except p.&nbsp; &quot;[:L:^[&#92;u4e00-&#92;u9fff]]&quot; matches all letters
+ * except the Han ideographs.</td>
+ * </tr>
+ * <tr>
+ * <td width="6%"><em>(all others)</em></td>
+ * <td width="94%">All other characters are treated as literal characters.&nbsp; (For
+ * example, &quot;[aeiou]&quot; specifies just the letters a, e, i, o, and u.)</td>
+ * </tr>
+ * </table>
+ * </blockquote>
+ *
+ * <p>For a more complete explanation, see <a
+ * href="http://www.ibm.com/java/education/boundaries/boundaries.html">http://www.ibm.com/java/education/boundaries/boundaries.html</a>.
+ * &nbsp; For examples, see the resource data (which is annotated).</p>
+ *
+ * @author Richard Gillam
+ */
+class IcuIteratorWrapper extends BreakIterator {
+
+    /* The wrapped ICU implementation. Non-final for #clone() */
+    private android.icu.text.BreakIterator wrapped;
+
+    /**
+     * Constructs a IcuIteratorWrapper according to the datafile
+     * provided.
+     */
+    IcuIteratorWrapper(android.icu.text.BreakIterator iterator) {
+        wrapped = iterator;
+    }
+
+    /**
+     * Clones this iterator.
+     *
+     * @return A newly-constructed IcuIteratorWrapper with the same
+     * behavior as this one.
+     */
+    public Object clone() {
+        IcuIteratorWrapper result = (IcuIteratorWrapper) super.clone();
+        result.wrapped = (android.icu.text.BreakIterator) wrapped.clone();
+        return result;
+    }
+
+    /**
+     * Returns true if both BreakIterators are of the same class, have the same
+     * rules, and iterate over the same text.
+     */
+    public boolean equals(Object that) {
+        if (!(that instanceof IcuIteratorWrapper)) {
+            return false;
+        }
+        return wrapped.equals(((IcuIteratorWrapper) that).wrapped);
+    }
+
+    //=======================================================================
+    // BreakIterator overrides
+    //=======================================================================
+
+    /**
+     * Returns text
+     */
+    public String toString() {
+        return wrapped.toString();
+    }
+
+    /**
+     * Compute a hashcode for this BreakIterator
+     *
+     * @return A hash code
+     */
+    public int hashCode() {
+        return wrapped.hashCode();
+    }
+
+    /**
+     * Sets the current iteration position to the beginning of the text.
+     * (i.e., the CharacterIterator's starting offset).
+     *
+     * @return The offset of the beginning of the text.
+     */
+    public int first() {
+        return wrapped.first();
+    }
+
+    /**
+     * Sets the current iteration position to the end of the text.
+     * (i.e., the CharacterIterator's ending offset).
+     *
+     * @return The text's past-the-end offset.
+     */
+    public int last() {
+        return wrapped.last();
+    }
+
+    /**
+     * Advances the iterator either forward or backward the specified number of steps.
+     * Negative values move backward, and positive values move forward.  This is
+     * equivalent to repeatedly calling next() or previous().
+     *
+     * @param n The number of steps to move.  The sign indicates the direction
+     *          (negative is backwards, and positive is forwards).
+     * @return The character offset of the boundary position n boundaries away from
+     * the current one.
+     */
+    public int next(int n) {
+        return wrapped.next(n);
+    }
+
+    /**
+     * Advances the iterator to the next boundary position.
+     *
+     * @return The position of the first boundary after this one.
+     */
+    public int next() {
+        return wrapped.next();
+    }
+
+    /**
+     * Advances the iterator backwards, to the last boundary preceding this one.
+     *
+     * @return The position of the last boundary position preceding this one.
+     */
+    public int previous() {
+        return wrapped.previous();
+    }
+
+    /**
+     * Throw IllegalArgumentException unless begin <= offset < end.
+     */
+    protected static final void checkOffset(int offset, CharacterIterator text) {
+        if (offset < text.getBeginIndex() || offset > text.getEndIndex()) {
+            throw new IllegalArgumentException("offset out of bounds");
+        }
+    }
+
+    /**
+     * Sets the iterator to refer to the first boundary position following
+     * the specified position.
+     *
+     * @return The position of the first break after the current position.
+     * @offset The position from which to begin searching for a break position.
+     */
+    public int following(int offset) {
+        CharacterIterator text = getText();
+        checkOffset(offset, text);
+        return wrapped.following(offset);
+    }
+
+    /**
+     * Sets the iterator to refer to the last boundary position before the
+     * specified position.
+     *
+     * @return The position of the last boundary before the starting position.
+     * @offset The position to begin searching for a break from.
+     */
+    public int preceding(int offset) {
+        // if we start by updating the current iteration position to the
+        // position specified by the caller, we can just use previous()
+        // to carry out this operation
+        CharacterIterator text = getText();
+        checkOffset(offset, text);
+        return wrapped.preceding(offset);
+    }
+
+    /**
+     * Returns true if the specfied position is a boundary position.  As a side
+     * effect, leaves the iterator pointing to the first boundary position at
+     * or after "offset".
+     *
+     * @param offset the offset to check.
+     * @return True if "offset" is a boundary position.
+     */
+    public boolean isBoundary(int offset) {
+        CharacterIterator text = getText();
+        checkOffset(offset, text);
+        return wrapped.isBoundary(offset);
+    }
+
+    /**
+     * Returns the current iteration position.
+     *
+     * @return The current iteration position.
+     */
+    public int current() {
+        return wrapped.current();
+    }
+
+    /**
+     * Return a CharacterIterator over the text being analyzed.  This version
+     * of this method returns the actual CharacterIterator we're using internally.
+     * Changing the state of this iterator can have undefined consequences.  If
+     * you need to change it, clone it first.
+     *
+     * @return An iterator over the text being analyzed.
+     */
+    public CharacterIterator getText() {
+        return wrapped.getText();
+    }
+
+    public void setText(String newText) {
+        wrapped.setText(newText);
+    }
+
+    /**
+     * Set the iterator to analyze a new piece of text.  This function resets
+     * the current iteration position to the beginning of the text.
+     *
+     * @param newText An iterator over the text to analyze.
+     */
+    public void setText(CharacterIterator newText) {
+        newText.current();
+        wrapped.setText(newText);
+    }
+}
diff --git a/java/text/MergeCollation.java b/java/text/MergeCollation.java
new file mode 100644
index 0000000..bd541a5
--- /dev/null
+++ b/java/text/MergeCollation.java
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.util.ArrayList;
+
+/**
+ * Utility class for normalizing and merging patterns for collation.
+ * Patterns are strings of the form <entry>*, where <entry> has the
+ * form:
+ * <pattern> := <entry>*
+ * <entry> := <separator><chars>{"/"<extension>}
+ * <separator> := "=", ",", ";", "<", "&"
+ * <chars>, and <extension> are both arbitrary strings.
+ * unquoted whitespaces are ignored.
+ * 'xxx' can be used to quote characters
+ * One difference from Collator is that & is used to reset to a current
+ * point. Or, in other words, it introduces a new sequence which is to
+ * be added to the old.
+ * That is: "a < b < c < d" is the same as "a < b & b < c & c < d" OR
+ * "a < b < d & b < c"
+ * XXX: make '' be a single quote.
+ * @see PatternEntry
+ * @author             Mark Davis, Helena Shih
+ */
+
+final class MergeCollation {
+
+    /**
+     * Creates from a pattern
+     * @exception ParseException If the input pattern is incorrect.
+     */
+    public MergeCollation(String pattern) throws ParseException
+    {
+        for (int i = 0; i < statusArray.length; i++)
+            statusArray[i] = 0;
+        setPattern(pattern);
+    }
+
+    /**
+     * recovers current pattern
+     */
+    public String getPattern() {
+        return getPattern(true);
+    }
+
+    /**
+     * recovers current pattern.
+     * @param withWhiteSpace puts spacing around the entries, and \n
+     * before & and <
+     */
+    public String getPattern(boolean withWhiteSpace) {
+        StringBuffer result = new StringBuffer();
+        PatternEntry tmp = null;
+        ArrayList<PatternEntry> extList = null;
+        int i;
+        for (i = 0; i < patterns.size(); ++i) {
+            PatternEntry entry = patterns.get(i);
+            if (entry.extension.length() != 0) {
+                if (extList == null)
+                    extList = new ArrayList<>();
+                extList.add(entry);
+            } else {
+                if (extList != null) {
+                    PatternEntry last = findLastWithNoExtension(i-1);
+                    for (int j = extList.size() - 1; j >= 0 ; j--) {
+                        tmp = extList.get(j);
+                        tmp.addToBuffer(result, false, withWhiteSpace, last);
+                    }
+                    extList = null;
+                }
+                entry.addToBuffer(result, false, withWhiteSpace, null);
+            }
+        }
+        if (extList != null) {
+            PatternEntry last = findLastWithNoExtension(i-1);
+            for (int j = extList.size() - 1; j >= 0 ; j--) {
+                tmp = extList.get(j);
+                tmp.addToBuffer(result, false, withWhiteSpace, last);
+            }
+            extList = null;
+        }
+        return result.toString();
+    }
+
+    private final PatternEntry findLastWithNoExtension(int i) {
+        for (--i;i >= 0; --i) {
+            PatternEntry entry = patterns.get(i);
+            if (entry.extension.length() == 0) {
+                return entry;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * emits the pattern for collation builder.
+     * @return emits the string in the format understable to the collation
+     * builder.
+     */
+    public String emitPattern() {
+        return emitPattern(true);
+    }
+
+    /**
+     * emits the pattern for collation builder.
+     * @param withWhiteSpace puts spacing around the entries, and \n
+     * before & and <
+     * @return emits the string in the format understable to the collation
+     * builder.
+     */
+    public String emitPattern(boolean withWhiteSpace) {
+        StringBuffer result = new StringBuffer();
+        for (int i = 0; i < patterns.size(); ++i)
+        {
+            PatternEntry entry = patterns.get(i);
+            if (entry != null) {
+                entry.addToBuffer(result, true, withWhiteSpace, null);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * sets the pattern.
+     */
+    public void setPattern(String pattern) throws ParseException
+    {
+        patterns.clear();
+        addPattern(pattern);
+    }
+
+    /**
+     * adds a pattern to the current one.
+     * @param pattern the new pattern to be added
+     */
+    public void addPattern(String pattern) throws ParseException
+    {
+        if (pattern == null)
+            return;
+
+        PatternEntry.Parser parser = new PatternEntry.Parser(pattern);
+
+        PatternEntry entry = parser.next();
+        while (entry != null) {
+            fixEntry(entry);
+            entry = parser.next();
+        }
+    }
+
+    /**
+     * gets count of separate entries
+     * @return the size of pattern entries
+     */
+    public int getCount() {
+        return patterns.size();
+    }
+
+    /**
+     * gets count of separate entries
+     * @param index the offset of the desired pattern entry
+     * @return the requested pattern entry
+     */
+    public PatternEntry getItemAt(int index) {
+        return patterns.get(index);
+    }
+
+    //============================================================
+    // privates
+    //============================================================
+    ArrayList<PatternEntry> patterns = new ArrayList<>(); // a list of PatternEntries
+
+    private transient PatternEntry saveEntry = null;
+    private transient PatternEntry lastEntry = null;
+
+    // This is really used as a local variable inside fixEntry, but we cache
+    // it here to avoid newing it up every time the method is called.
+    private transient StringBuffer excess = new StringBuffer();
+
+    //
+    // When building a MergeCollation, we need to do lots of searches to see
+    // whether a given entry is already in the table.  Since we're using an
+    // array, this would make the algorithm O(N*N).  To speed things up, we
+    // use this bit array to remember whether the array contains any entries
+    // starting with each Unicode character.  If not, we can avoid the search.
+    // Using BitSet would make this easier, but it's significantly slower.
+    //
+    private transient byte[] statusArray = new byte[8192];
+    private final byte BITARRAYMASK = (byte)0x1;
+    private final int  BYTEPOWER = 3;
+    private final int  BYTEMASK = (1 << BYTEPOWER) - 1;
+
+    /*
+      If the strength is RESET, then just change the lastEntry to
+      be the current. (If the current is not in patterns, signal an error).
+      If not, then remove the current entry, and add it after lastEntry
+      (which is usually at the end).
+      */
+    private final void fixEntry(PatternEntry newEntry) throws ParseException
+    {
+        // check to see whether the new entry has the same characters as the previous
+        // entry did (this can happen when a pattern declaring a difference between two
+        // strings that are canonically equivalent is normalized).  If so, and the strength
+        // is anything other than IDENTICAL or RESET, throw an exception (you can't
+        // declare a string to be unequal to itself).       --rtg 5/24/99
+        if (lastEntry != null && newEntry.chars.equals(lastEntry.chars)
+                && newEntry.extension.equals(lastEntry.extension)) {
+            if (newEntry.strength != Collator.IDENTICAL
+                && newEntry.strength != PatternEntry.RESET) {
+                    throw new ParseException("The entries " + lastEntry + " and "
+                            + newEntry + " are adjacent in the rules, but have conflicting "
+                            + "strengths: A character can't be unequal to itself.", -1);
+            } else {
+                // otherwise, just skip this entry and behave as though you never saw it
+                return;
+            }
+        }
+
+        boolean changeLastEntry = true;
+        if (newEntry.strength != PatternEntry.RESET) {
+            int oldIndex = -1;
+
+            if ((newEntry.chars.length() == 1)) {
+
+                char c = newEntry.chars.charAt(0);
+                int statusIndex = c >> BYTEPOWER;
+                byte bitClump = statusArray[statusIndex];
+                byte setBit = (byte)(BITARRAYMASK << (c & BYTEMASK));
+
+                if (bitClump != 0 && (bitClump & setBit) != 0) {
+                    oldIndex = patterns.lastIndexOf(newEntry);
+                } else {
+                    // We're going to add an element that starts with this
+                    // character, so go ahead and set its bit.
+                    statusArray[statusIndex] = (byte)(bitClump | setBit);
+                }
+            } else {
+                oldIndex = patterns.lastIndexOf(newEntry);
+            }
+            if (oldIndex != -1) {
+                patterns.remove(oldIndex);
+            }
+
+            excess.setLength(0);
+            int lastIndex = findLastEntry(lastEntry, excess);
+
+            if (excess.length() != 0) {
+                newEntry.extension = excess + newEntry.extension;
+                if (lastIndex != patterns.size()) {
+                    lastEntry = saveEntry;
+                    changeLastEntry = false;
+                }
+            }
+            if (lastIndex == patterns.size()) {
+                patterns.add(newEntry);
+                saveEntry = newEntry;
+            } else {
+                patterns.add(lastIndex, newEntry);
+            }
+        }
+        if (changeLastEntry) {
+            lastEntry = newEntry;
+        }
+    }
+
+    private final int findLastEntry(PatternEntry entry,
+                              StringBuffer excessChars) throws ParseException
+    {
+        if (entry == null)
+            return 0;
+
+        if (entry.strength != PatternEntry.RESET) {
+            // Search backwards for string that contains this one;
+            // most likely entry is last one
+
+            int oldIndex = -1;
+            if ((entry.chars.length() == 1)) {
+                int index = entry.chars.charAt(0) >> BYTEPOWER;
+                if ((statusArray[index] &
+                    (BITARRAYMASK << (entry.chars.charAt(0) & BYTEMASK))) != 0) {
+                    oldIndex = patterns.lastIndexOf(entry);
+                }
+            } else {
+                oldIndex = patterns.lastIndexOf(entry);
+            }
+            if ((oldIndex == -1))
+                throw new ParseException("couldn't find last entry: "
+                                          + entry, oldIndex);
+            return oldIndex + 1;
+        } else {
+            int i;
+            for (i = patterns.size() - 1; i >= 0; --i) {
+                PatternEntry e = patterns.get(i);
+                if (e.chars.regionMatches(0,entry.chars,0,
+                                              e.chars.length())) {
+                    excessChars.append(entry.chars.substring(e.chars.length(),
+                                                            entry.chars.length()));
+                    break;
+                }
+            }
+            if (i == -1)
+                throw new ParseException("couldn't find: " + entry, i);
+            return i + 1;
+        }
+    }
+}
diff --git a/java/text/MessageFormat.java b/java/text/MessageFormat.java
new file mode 100644
index 0000000..4a48e9c
--- /dev/null
+++ b/java/text/MessageFormat.java
@@ -0,0 +1,1610 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.InvalidObjectException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+
+/**
+ * <code>MessageFormat</code> provides a means to produce concatenated
+ * messages in a language-neutral way. Use this to construct messages
+ * displayed for end users.
+ *
+ * <p>
+ * <code>MessageFormat</code> takes a set of objects, formats them, then
+ * inserts the formatted strings into the pattern at the appropriate places.
+ *
+ * <p>
+ * <strong>Note:</strong>
+ * <code>MessageFormat</code> differs from the other <code>Format</code>
+ * classes in that you create a <code>MessageFormat</code> object with one
+ * of its constructors (not with a <code>getInstance</code> style factory
+ * method). The factory methods aren't necessary because <code>MessageFormat</code>
+ * itself doesn't implement locale specific behavior. Any locale specific
+ * behavior is defined by the pattern that you provide as well as the
+ * subformats used for inserted arguments.
+ *
+ * <h3><a name="patterns">Patterns and Their Interpretation</a></h3>
+ *
+ * <code>MessageFormat</code> uses patterns of the following form:
+ * <blockquote><pre>
+ * <i>MessageFormatPattern:</i>
+ *         <i>String</i>
+ *         <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
+ *
+ * <i>FormatElement:</i>
+ *         { <i>ArgumentIndex</i> }
+ *         { <i>ArgumentIndex</i> , <i>FormatType</i> }
+ *         { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
+ *
+ * <i>FormatType: one of </i>
+ *         number date time choice
+ *
+ * <i>FormatStyle:</i>
+ *         short
+ *         medium
+ *         long
+ *         full
+ *         integer
+ *         currency
+ *         percent
+ *         <i>SubformatPattern</i>
+ * </pre></blockquote>
+ *
+ * <p>Within a <i>String</i>, a pair of single quotes can be used to
+ * quote any arbitrary characters except single quotes. For example,
+ * pattern string <code>"'{0}'"</code> represents string
+ * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
+ * must be represented by doubled single quotes {@code ''} throughout a
+ * <i>String</i>.  For example, pattern string <code>"'{''}'"</code> is
+ * interpreted as a sequence of <code>'{</code> (start of quoting and a
+ * left curly brace), <code>''</code> (a single quote), and
+ * <code>}'</code> (a right curly brace and end of quoting),
+ * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
+ * right curly braces): representing string <code>"{'}"</code>,
+ * <em>not</em> <code>"{}"</code>.
+ *
+ * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
+ * subformat, and subformat-dependent pattern rules apply. For example,
+ * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
+ * (<i>SubformatPattern</i> with underline) will produce a number format
+ * with the pound-sign quoted, with a result such as: {@code
+ * "$#31,45"}. Refer to each {@code Format} subclass documentation for
+ * details.
+ *
+ * <p>Any unmatched quote is treated as closed at the end of the given
+ * pattern. For example, pattern string {@code "'{0}"} is treated as
+ * pattern {@code "'{0}'"}.
+ *
+ * <p>Any curly braces within an unquoted pattern must be balanced. For
+ * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
+ * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
+ * and <code>"''{''"</code> are not.
+ *
+ * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
+ * format patterns unfortunately have shown to be somewhat confusing.
+ * In particular, it isn't always obvious to localizers whether single
+ * quotes need to be doubled or not. Make sure to inform localizers about
+ * the rules, and tell them (for example, by using comments in resource
+ * bundle source files) which strings will be processed by {@code MessageFormat}.
+ * Note that localizers may need to use single quotes in translated
+ * strings where the original version doesn't have them.
+ * </dl>
+ * <p>
+ * The <i>ArgumentIndex</i> value is a non-negative integer written
+ * using the digits {@code '0'} through {@code '9'}, and represents an index into the
+ * {@code arguments} array passed to the {@code format} methods
+ * or the result array returned by the {@code parse} methods.
+ * <p>
+ * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
+ * a {@code Format} instance for the format element. The following
+ * table shows how the values map to {@code Format} instances. Combinations not
+ * shown in the table are illegal. A <i>SubformatPattern</i> must
+ * be a valid pattern string for the {@code Format} subclass used.
+ *
+ * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
+ *    <tr>
+ *       <th id="ft" class="TableHeadingColor">FormatType
+ *       <th id="fs" class="TableHeadingColor">FormatStyle
+ *       <th id="sc" class="TableHeadingColor">Subformat Created
+ *    <tr>
+ *       <td headers="ft"><i>(none)</i>
+ *       <td headers="fs"><i>(none)</i>
+ *       <td headers="sc"><code>null</code>
+ *    <tr>
+ *       <td headers="ft" rowspan=5><code>number</code>
+ *       <td headers="fs"><i>(none)</i>
+ *       <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>integer</code>
+ *       <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>currency</code>
+ *       <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>percent</code>
+ *       <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
+ *    <tr>
+ *       <td headers="fs"><i>SubformatPattern</i>
+ *       <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
+ *    <tr>
+ *       <td headers="ft" rowspan=6><code>date</code>
+ *       <td headers="fs"><i>(none)</i>
+ *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>short</code>
+ *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>medium</code>
+ *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>long</code>
+ *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>full</code>
+ *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><i>SubformatPattern</i>
+ *       <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
+ *    <tr>
+ *       <td headers="ft" rowspan=6><code>time</code>
+ *       <td headers="fs"><i>(none)</i>
+ *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>short</code>
+ *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>medium</code>
+ *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>long</code>
+ *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><code>full</code>
+ *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
+ *    <tr>
+ *       <td headers="fs"><i>SubformatPattern</i>
+ *       <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
+ *    <tr>
+ *       <td headers="ft"><code>choice</code>
+ *       <td headers="fs"><i>SubformatPattern</i>
+ *       <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
+ * </table>
+ *
+ * <h4>Usage Information</h4>
+ *
+ * <p>
+ * Here are some examples of usage.
+ * In real internationalized programs, the message format pattern and other
+ * static strings will, of course, be obtained from resource bundles.
+ * Other parameters will be dynamically determined at runtime.
+ * <p>
+ * The first example uses the static method <code>MessageFormat.format</code>,
+ * which internally creates a <code>MessageFormat</code> for one-time use:
+ * <blockquote><pre>
+ * int planet = 7;
+ * String event = "a disturbance in the Force";
+ *
+ * String result = MessageFormat.format(
+ *     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
+ *     planet, new Date(), event);
+ * </pre></blockquote>
+ * The output is:
+ * <blockquote><pre>
+ * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
+ * </pre></blockquote>
+ *
+ * <p>
+ * The following example creates a <code>MessageFormat</code> instance that
+ * can be used repeatedly:
+ * <blockquote><pre>
+ * int fileCount = 1273;
+ * String diskName = "MyDisk";
+ * Object[] testArgs = {new Long(fileCount), diskName};
+ *
+ * MessageFormat form = new MessageFormat(
+ *     "The disk \"{1}\" contains {0} file(s).");
+ *
+ * System.out.println(form.format(testArgs));
+ * </pre></blockquote>
+ * The output with different values for <code>fileCount</code>:
+ * <blockquote><pre>
+ * The disk "MyDisk" contains 0 file(s).
+ * The disk "MyDisk" contains 1 file(s).
+ * The disk "MyDisk" contains 1,273 file(s).
+ * </pre></blockquote>
+ *
+ * <p>
+ * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
+ * to produce correct forms for singular and plural:
+ * <blockquote><pre>
+ * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
+ * double[] filelimits = {0,1,2};
+ * String[] filepart = {"no files","one file","{0,number} files"};
+ * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
+ * form.setFormatByArgumentIndex(0, fileform);
+ *
+ * int fileCount = 1273;
+ * String diskName = "MyDisk";
+ * Object[] testArgs = {new Long(fileCount), diskName};
+ *
+ * System.out.println(form.format(testArgs));
+ * </pre></blockquote>
+ * The output with different values for <code>fileCount</code>:
+ * <blockquote><pre>
+ * The disk "MyDisk" contains no files.
+ * The disk "MyDisk" contains one file.
+ * The disk "MyDisk" contains 1,273 files.
+ * </pre></blockquote>
+ *
+ * <p>
+ * You can create the <code>ChoiceFormat</code> programmatically, as in the
+ * above example, or by using a pattern. See {@link ChoiceFormat}
+ * for more information.
+ * <blockquote><pre>{@code
+ * form.applyPattern(
+ *    "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
+ * }</pre></blockquote>
+ *
+ * <p>
+ * <strong>Note:</strong> As we see above, the string produced
+ * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
+ * occurrences of '{' are used to indicate subformats, and cause recursion.
+ * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
+ * programmatically (instead of using the string patterns), then be careful not to
+ * produce a format that recurses on itself, which will cause an infinite loop.
+ * <p>
+ * When a single argument is parsed more than once in the string, the last match
+ * will be the final result of the parsing.  For example,
+ * <blockquote><pre>
+ * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
+ * Object[] objs = {new Double(3.1415)};
+ * String result = mf.format( objs );
+ * // result now equals "3.14, 3.1"
+ * objs = null;
+ * objs = mf.parse(result, new ParsePosition(0));
+ * // objs now equals {new Double(3.1)}
+ * </pre></blockquote>
+ *
+ * <p>
+ * Likewise, parsing with a {@code MessageFormat} object using patterns containing
+ * multiple occurrences of the same argument would return the last match.  For
+ * example,
+ * <blockquote><pre>
+ * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
+ * String forParsing = "x, y, z";
+ * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
+ * // result now equals {new String("z")}
+ * </pre></blockquote>
+ *
+ * <h4><a name="synchronization">Synchronization</a></h4>
+ *
+ * <p>
+ * Message formats are not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * @see          java.util.Locale
+ * @see          Format
+ * @see          NumberFormat
+ * @see          DecimalFormat
+ * @see          DecimalFormatSymbols
+ * @see          ChoiceFormat
+ * @see          DateFormat
+ * @see          SimpleDateFormat
+ *
+ * @author       Mark Davis
+ */
+
+public class MessageFormat extends Format {
+
+    private static final long serialVersionUID = 6479157306784022952L;
+
+    /**
+     * Constructs a MessageFormat for the default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale and the
+     * specified pattern.
+     * The constructor first sets the locale, then parses the pattern and
+     * creates a list of subformats for the format elements contained in it.
+     * Patterns and their interpretation are specified in the
+     * <a href="#patterns">class description</a>.
+     *
+     * @param pattern the pattern for this message format
+     * @exception IllegalArgumentException if the pattern is invalid
+     */
+    public MessageFormat(String pattern) {
+        this.locale = Locale.getDefault(Locale.Category.FORMAT);
+        applyPattern(pattern);
+    }
+
+    /**
+     * Constructs a MessageFormat for the specified locale and
+     * pattern.
+     * The constructor first sets the locale, then parses the pattern and
+     * creates a list of subformats for the format elements contained in it.
+     * Patterns and their interpretation are specified in the
+     * <a href="#patterns">class description</a>.
+     *
+     * @param pattern the pattern for this message format
+     * @param locale the locale for this message format
+     * @exception IllegalArgumentException if the pattern is invalid
+     * @since 1.4
+     */
+    public MessageFormat(String pattern, Locale locale) {
+        this.locale = locale;
+        applyPattern(pattern);
+    }
+
+    /**
+     * Sets the locale to be used when creating or comparing subformats.
+     * This affects subsequent calls
+     * <ul>
+     * <li>to the {@link #applyPattern applyPattern}
+     *     and {@link #toPattern toPattern} methods if format elements specify
+     *     a format type and therefore have the subformats created in the
+     *     <code>applyPattern</code> method, as well as
+     * <li>to the <code>format</code> and
+     *     {@link #formatToCharacterIterator formatToCharacterIterator} methods
+     *     if format elements do not specify a format type and therefore have
+     *     the subformats created in the formatting methods.
+     * </ul>
+     * Subformats that have already been created are not affected.
+     *
+     * @param locale the locale to be used when creating or comparing subformats
+     */
+    public void setLocale(Locale locale) {
+        this.locale = locale;
+    }
+
+    /**
+     * Gets the locale that's used when creating or comparing subformats.
+     *
+     * @return the locale used when creating or comparing subformats
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+
+    /**
+     * Sets the pattern used by this message format.
+     * The method parses the pattern and creates a list of subformats
+     * for the format elements contained in it.
+     * Patterns and their interpretation are specified in the
+     * <a href="#patterns">class description</a>.
+     *
+     * @param pattern the pattern for this message format
+     * @exception IllegalArgumentException if the pattern is invalid
+     */
+    @SuppressWarnings("fallthrough") // fallthrough in switch is expected, suppress it
+    public void applyPattern(String pattern) {
+            StringBuilder[] segments = new StringBuilder[4];
+            // Allocate only segments[SEG_RAW] here. The rest are
+            // allocated on demand.
+            segments[SEG_RAW] = new StringBuilder();
+
+            int part = SEG_RAW;
+            int formatNumber = 0;
+            boolean inQuote = false;
+            int braceStack = 0;
+            maxOffset = -1;
+            for (int i = 0; i < pattern.length(); ++i) {
+                char ch = pattern.charAt(i);
+                if (part == SEG_RAW) {
+                    if (ch == '\'') {
+                        if (i + 1 < pattern.length()
+                            && pattern.charAt(i+1) == '\'') {
+                            segments[part].append(ch);  // handle doubles
+                            ++i;
+                        } else {
+                            inQuote = !inQuote;
+                        }
+                    } else if (ch == '{' && !inQuote) {
+                        part = SEG_INDEX;
+                        if (segments[SEG_INDEX] == null) {
+                            segments[SEG_INDEX] = new StringBuilder();
+                        }
+                    } else {
+                        segments[part].append(ch);
+                    }
+                } else  {
+                    if (inQuote) {              // just copy quotes in parts
+                        segments[part].append(ch);
+                        if (ch == '\'') {
+                            inQuote = false;
+                        }
+                    } else {
+                        switch (ch) {
+                        case ',':
+                            if (part < SEG_MODIFIER) {
+                                if (segments[++part] == null) {
+                                    segments[part] = new StringBuilder();
+                                }
+                            } else {
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case '{':
+                            ++braceStack;
+                            segments[part].append(ch);
+                            break;
+                        case '}':
+                            if (braceStack == 0) {
+                                part = SEG_RAW;
+                                makeFormat(i, formatNumber, segments);
+                                formatNumber++;
+                                // throw away other segments
+                                segments[SEG_INDEX] = null;
+                                segments[SEG_TYPE] = null;
+                                segments[SEG_MODIFIER] = null;
+                            } else {
+                                --braceStack;
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case ' ':
+                            // Skip any leading space chars for SEG_TYPE.
+                            if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case '\'':
+                            inQuote = true;
+                            // fall through, so we keep quotes in other parts
+                        default:
+                            segments[part].append(ch);
+                            break;
+                        }
+                    }
+                }
+            }
+            if (braceStack == 0 && part != 0) {
+                maxOffset = -1;
+                throw new IllegalArgumentException("Unmatched braces in the pattern.");
+            }
+            this.pattern = segments[0].toString();
+    }
+
+
+    /**
+     * Returns a pattern representing the current state of the message format.
+     * The string is constructed from internal information and therefore
+     * does not necessarily equal the previously applied pattern.
+     *
+     * @return a pattern representing the current state of the message format
+     */
+    public String toPattern() {
+        // later, make this more extensible
+        int lastOffset = 0;
+        StringBuilder result = new StringBuilder();
+        for (int i = 0; i <= maxOffset; ++i) {
+            copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
+            lastOffset = offsets[i];
+            result.append('{').append(argumentNumbers[i]);
+            Format fmt = formats[i];
+            if (fmt == null) {
+                // do nothing, string format
+            } else if (fmt instanceof NumberFormat) {
+                if (fmt.equals(NumberFormat.getInstance(locale))) {
+                    result.append(",number");
+                } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
+                    result.append(",number,currency");
+                } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
+                    result.append(",number,percent");
+                } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
+                    result.append(",number,integer");
+                } else {
+                    if (fmt instanceof DecimalFormat) {
+                        result.append(",number,").append(((DecimalFormat)fmt).toPattern());
+                    } else if (fmt instanceof ChoiceFormat) {
+                        result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
+                    } else {
+                        // UNKNOWN
+                    }
+                }
+            } else if (fmt instanceof DateFormat) {
+                int index;
+                for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
+                    DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
+                                                               locale);
+                    if (fmt.equals(df)) {
+                        result.append(",date");
+                        break;
+                    }
+                    df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
+                                                    locale);
+                    if (fmt.equals(df)) {
+                        result.append(",time");
+                        break;
+                    }
+                }
+                if (index >= DATE_TIME_MODIFIERS.length) {
+                    if (fmt instanceof SimpleDateFormat) {
+                        result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
+                    } else {
+                        // UNKNOWN
+                    }
+                } else if (index != MODIFIER_DEFAULT) {
+                    result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
+                }
+            } else {
+                //result.append(", unknown");
+            }
+            result.append('}');
+        }
+        copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
+        return result.toString();
+    }
+
+    /**
+     * Sets the formats to use for the values passed into
+     * <code>format</code> methods or returned from <code>parse</code>
+     * methods. The indices of elements in <code>newFormats</code>
+     * correspond to the argument indices used in the previously set
+     * pattern string.
+     * The order of formats in <code>newFormats</code> thus corresponds to
+     * the order of elements in the <code>arguments</code> array passed
+     * to the <code>format</code> methods or the result array returned
+     * by the <code>parse</code> methods.
+     * <p>
+     * If an argument index is used for more than one format element
+     * in the pattern string, then the corresponding new format is used
+     * for all such format elements. If an argument index is not used
+     * for any format element in the pattern string, then the
+     * corresponding new format is ignored. If fewer formats are provided
+     * than needed, then only the formats for argument indices less
+     * than <code>newFormats.length</code> are replaced.
+     *
+     * @param newFormats the new formats to use
+     * @exception NullPointerException if <code>newFormats</code> is null
+     * @since 1.4
+     */
+    public void setFormatsByArgumentIndex(Format[] newFormats) {
+        for (int i = 0; i <= maxOffset; i++) {
+            int j = argumentNumbers[i];
+            if (j < newFormats.length) {
+                formats[i] = newFormats[j];
+            }
+        }
+    }
+
+    /**
+     * Sets the formats to use for the format elements in the
+     * previously set pattern string.
+     * The order of formats in <code>newFormats</code> corresponds to
+     * the order of format elements in the pattern string.
+     * <p>
+     * If more formats are provided than needed by the pattern string,
+     * the remaining ones are ignored. If fewer formats are provided
+     * than needed, then only the first <code>newFormats.length</code>
+     * formats are replaced.
+     * <p>
+     * Since the order of format elements in a pattern string often
+     * changes during localization, it is generally better to use the
+     * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
+     * method, which assumes an order of formats corresponding to the
+     * order of elements in the <code>arguments</code> array passed to
+     * the <code>format</code> methods or the result array returned by
+     * the <code>parse</code> methods.
+     *
+     * @param newFormats the new formats to use
+     * @exception NullPointerException if <code>newFormats</code> is null
+     */
+    public void setFormats(Format[] newFormats) {
+        int runsToCopy = newFormats.length;
+        if (runsToCopy > maxOffset + 1) {
+            runsToCopy = maxOffset + 1;
+        }
+        for (int i = 0; i < runsToCopy; i++) {
+            formats[i] = newFormats[i];
+        }
+    }
+
+    /**
+     * Sets the format to use for the format elements within the
+     * previously set pattern string that use the given argument
+     * index.
+     * The argument index is part of the format element definition and
+     * represents an index into the <code>arguments</code> array passed
+     * to the <code>format</code> methods or the result array returned
+     * by the <code>parse</code> methods.
+     * <p>
+     * If the argument index is used for more than one format element
+     * in the pattern string, then the new format is used for all such
+     * format elements. If the argument index is not used for any format
+     * element in the pattern string, then the new format is ignored.
+     *
+     * @param argumentIndex the argument index for which to use the new format
+     * @param newFormat the new format to use
+     * @since 1.4
+     */
+    public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
+        for (int j = 0; j <= maxOffset; j++) {
+            if (argumentNumbers[j] == argumentIndex) {
+                formats[j] = newFormat;
+            }
+        }
+    }
+
+    /**
+     * Sets the format to use for the format element with the given
+     * format element index within the previously set pattern string.
+     * The format element index is the zero-based number of the format
+     * element counting from the start of the pattern string.
+     * <p>
+     * Since the order of format elements in a pattern string often
+     * changes during localization, it is generally better to use the
+     * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
+     * method, which accesses format elements based on the argument
+     * index they specify.
+     *
+     * @param formatElementIndex the index of a format element within the pattern
+     * @param newFormat the format to use for the specified format element
+     * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
+     *            larger than the number of format elements in the pattern string
+     */
+    public void setFormat(int formatElementIndex, Format newFormat) {
+        // Android-added: prevent setting unused formatters.
+        if (formatElementIndex > maxOffset) {
+            // Note: maxOffset is maximum index, not the length.
+            throw new ArrayIndexOutOfBoundsException(
+                    "maxOffset=" + maxOffset + "; formatElementIndex=" + formatElementIndex);
+        }
+        formats[formatElementIndex] = newFormat;
+    }
+
+    /**
+     * Gets the formats used for the values passed into
+     * <code>format</code> methods or returned from <code>parse</code>
+     * methods. The indices of elements in the returned array
+     * correspond to the argument indices used in the previously set
+     * pattern string.
+     * The order of formats in the returned array thus corresponds to
+     * the order of elements in the <code>arguments</code> array passed
+     * to the <code>format</code> methods or the result array returned
+     * by the <code>parse</code> methods.
+     * <p>
+     * If an argument index is used for more than one format element
+     * in the pattern string, then the format used for the last such
+     * format element is returned in the array. If an argument index
+     * is not used for any format element in the pattern string, then
+     * null is returned in the array.
+     *
+     * @return the formats used for the arguments within the pattern
+     * @since 1.4
+     */
+    public Format[] getFormatsByArgumentIndex() {
+        int maximumArgumentNumber = -1;
+        for (int i = 0; i <= maxOffset; i++) {
+            if (argumentNumbers[i] > maximumArgumentNumber) {
+                maximumArgumentNumber = argumentNumbers[i];
+            }
+        }
+        Format[] resultArray = new Format[maximumArgumentNumber + 1];
+        for (int i = 0; i <= maxOffset; i++) {
+            resultArray[argumentNumbers[i]] = formats[i];
+        }
+        return resultArray;
+    }
+
+    /**
+     * Gets the formats used for the format elements in the
+     * previously set pattern string.
+     * The order of formats in the returned array corresponds to
+     * the order of format elements in the pattern string.
+     * <p>
+     * Since the order of format elements in a pattern string often
+     * changes during localization, it's generally better to use the
+     * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
+     * method, which assumes an order of formats corresponding to the
+     * order of elements in the <code>arguments</code> array passed to
+     * the <code>format</code> methods or the result array returned by
+     * the <code>parse</code> methods.
+     *
+     * @return the formats used for the format elements in the pattern
+     */
+    public Format[] getFormats() {
+        Format[] resultArray = new Format[maxOffset + 1];
+        System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
+        return resultArray;
+    }
+
+    /**
+     * Formats an array of objects and appends the <code>MessageFormat</code>'s
+     * pattern, with format elements replaced by the formatted objects, to the
+     * provided <code>StringBuffer</code>.
+     * <p>
+     * The text substituted for the individual format elements is derived from
+     * the current subformat of the format element and the
+     * <code>arguments</code> element at the format element's argument index
+     * as indicated by the first matching line of the following table. An
+     * argument is <i>unavailable</i> if <code>arguments</code> is
+     * <code>null</code> or has fewer than argumentIndex+1 elements.
+     *
+     * <table border=1 summary="Examples of subformat,argument,and formatted text">
+     *    <tr>
+     *       <th>Subformat
+     *       <th>Argument
+     *       <th>Formatted Text
+     *    <tr>
+     *       <td><i>any</i>
+     *       <td><i>unavailable</i>
+     *       <td><code>"{" + argumentIndex + "}"</code>
+     *    <tr>
+     *       <td><i>any</i>
+     *       <td><code>null</code>
+     *       <td><code>"null"</code>
+     *    <tr>
+     *       <td><code>instanceof ChoiceFormat</code>
+     *       <td><i>any</i>
+     *       <td><code>subformat.format(argument).indexOf('{') &gt;= 0 ?<br>
+     *           (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
+     *           subformat.format(argument)</code>
+     *    <tr>
+     *       <td><code>!= null</code>
+     *       <td><i>any</i>
+     *       <td><code>subformat.format(argument)</code>
+     *    <tr>
+     *       <td><code>null</code>
+     *       <td><code>instanceof Number</code>
+     *       <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
+     *    <tr>
+     *       <td><code>null</code>
+     *       <td><code>instanceof Date</code>
+     *       <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
+     *    <tr>
+     *       <td><code>null</code>
+     *       <td><code>instanceof String</code>
+     *       <td><code>argument</code>
+     *    <tr>
+     *       <td><code>null</code>
+     *       <td><i>any</i>
+     *       <td><code>argument.toString()</code>
+     * </table>
+     * <p>
+     * If <code>pos</code> is non-null, and refers to
+     * <code>Field.ARGUMENT</code>, the location of the first formatted
+     * string will be returned.
+     *
+     * @param arguments an array of objects to be formatted and substituted.
+     * @param result where text is appended.
+     * @param pos On input: an alignment field, if desired.
+     *            On output: the offsets of the alignment field.
+     * @return the string buffer passed in as {@code result}, with formatted
+     * text appended
+     * @exception IllegalArgumentException if an argument in the
+     *            <code>arguments</code> array is not of the type
+     *            expected by the format element(s) that use it.
+     */
+    public final StringBuffer format(Object[] arguments, StringBuffer result,
+                                     FieldPosition pos)
+    {
+        return subformat(arguments, result, pos, null);
+    }
+
+    /**
+     * Creates a MessageFormat with the given pattern and uses it
+     * to format the given arguments. This is equivalent to
+     * <blockquote>
+     *     <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
+     * </blockquote>
+     *
+     * @param pattern   the pattern string
+     * @param arguments object(s) to format
+     * @return the formatted string
+     * @exception IllegalArgumentException if the pattern is invalid,
+     *            or if an argument in the <code>arguments</code> array
+     *            is not of the type expected by the format element(s)
+     *            that use it.
+     */
+    public static String format(String pattern, Object ... arguments) {
+        MessageFormat temp = new MessageFormat(pattern);
+        return temp.format(arguments);
+    }
+
+    // Overrides
+    /**
+     * Formats an array of objects and appends the <code>MessageFormat</code>'s
+     * pattern, with format elements replaced by the formatted objects, to the
+     * provided <code>StringBuffer</code>.
+     * This is equivalent to
+     * <blockquote>
+     *     <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
+     * </blockquote>
+     *
+     * @param arguments an array of objects to be formatted and substituted.
+     * @param result where text is appended.
+     * @param pos On input: an alignment field, if desired.
+     *            On output: the offsets of the alignment field.
+     * @exception IllegalArgumentException if an argument in the
+     *            <code>arguments</code> array is not of the type
+     *            expected by the format element(s) that use it.
+     */
+    public final StringBuffer format(Object arguments, StringBuffer result,
+                                     FieldPosition pos)
+    {
+        return subformat((Object[]) arguments, result, pos, null);
+    }
+
+    /**
+     * Formats an array of objects and inserts them into the
+     * <code>MessageFormat</code>'s pattern, producing an
+     * <code>AttributedCharacterIterator</code>.
+     * You can use the returned <code>AttributedCharacterIterator</code>
+     * to build the resulting String, as well as to determine information
+     * about the resulting String.
+     * <p>
+     * The text of the returned <code>AttributedCharacterIterator</code> is
+     * the same that would be returned by
+     * <blockquote>
+     *     <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
+     * </blockquote>
+     * <p>
+     * In addition, the <code>AttributedCharacterIterator</code> contains at
+     * least attributes indicating where text was generated from an
+     * argument in the <code>arguments</code> array. The keys of these attributes are of
+     * type <code>MessageFormat.Field</code>, their values are
+     * <code>Integer</code> objects indicating the index in the <code>arguments</code>
+     * array of the argument from which the text was generated.
+     * <p>
+     * The attributes/value from the underlying <code>Format</code>
+     * instances that <code>MessageFormat</code> uses will also be
+     * placed in the resulting <code>AttributedCharacterIterator</code>.
+     * This allows you to not only find where an argument is placed in the
+     * resulting String, but also which fields it contains in turn.
+     *
+     * @param arguments an array of objects to be formatted and substituted.
+     * @return AttributedCharacterIterator describing the formatted value.
+     * @exception NullPointerException if <code>arguments</code> is null.
+     * @exception IllegalArgumentException if an argument in the
+     *            <code>arguments</code> array is not of the type
+     *            expected by the format element(s) that use it.
+     * @since 1.4
+     */
+    public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
+        StringBuffer result = new StringBuffer();
+        ArrayList<AttributedCharacterIterator> iterators = new ArrayList<>();
+
+        if (arguments == null) {
+            throw new NullPointerException(
+                   "formatToCharacterIterator must be passed non-null object");
+        }
+        subformat((Object[]) arguments, result, null, iterators);
+        if (iterators.size() == 0) {
+            return createAttributedCharacterIterator("");
+        }
+        return createAttributedCharacterIterator(
+                     iterators.toArray(
+                     new AttributedCharacterIterator[iterators.size()]));
+    }
+
+    /**
+     * Parses the string.
+     *
+     * <p>Caveats: The parse may fail in a number of circumstances.
+     * For example:
+     * <ul>
+     * <li>If one of the arguments does not occur in the pattern.
+     * <li>If the format of an argument loses information, such as
+     *     with a choice format where a large number formats to "many".
+     * <li>Does not yet handle recursion (where
+     *     the substituted strings contain {n} references.)
+     * <li>Will not always find a match (or the correct match)
+     *     if some part of the parse is ambiguous.
+     *     For example, if the pattern "{1},{2}" is used with the
+     *     string arguments {"a,b", "c"}, it will format as "a,b,c".
+     *     When the result is parsed, it will return {"a", "b,c"}.
+     * <li>If a single argument is parsed more than once in the string,
+     *     then the later parse wins.
+     * </ul>
+     * When the parse fails, use ParsePosition.getErrorIndex() to find out
+     * where in the string the parsing failed.  The returned error
+     * index is the starting offset of the sub-patterns that the string
+     * is comparing with.  For example, if the parsing string "AAA {0} BBB"
+     * is comparing against the pattern "AAD {0} BBB", the error index is
+     * 0. When an error occurs, the call to this method will return null.
+     * If the source is null, return an empty array.
+     *
+     * @param source the string to parse
+     * @param pos    the parse position
+     * @return an array of parsed objects
+     */
+    public Object[] parse(String source, ParsePosition pos) {
+        if (source == null) {
+            Object[] empty = {};
+            return empty;
+        }
+
+        int maximumArgumentNumber = -1;
+        for (int i = 0; i <= maxOffset; i++) {
+            if (argumentNumbers[i] > maximumArgumentNumber) {
+                maximumArgumentNumber = argumentNumbers[i];
+            }
+        }
+        Object[] resultArray = new Object[maximumArgumentNumber + 1];
+
+        int patternOffset = 0;
+        int sourceOffset = pos.index;
+        ParsePosition tempStatus = new ParsePosition(0);
+        for (int i = 0; i <= maxOffset; ++i) {
+            // match up to format
+            int len = offsets[i] - patternOffset;
+            if (len == 0 || pattern.regionMatches(patternOffset,
+                                                  source, sourceOffset, len)) {
+                sourceOffset += len;
+                patternOffset += len;
+            } else {
+                pos.errorIndex = sourceOffset;
+                return null; // leave index as is to signal error
+            }
+
+            // now use format
+            if (formats[i] == null) {   // string format
+                // if at end, use longest possible match
+                // otherwise uses first match to intervening string
+                // does NOT recursively try all possibilities
+                int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
+
+                int next;
+                if (patternOffset >= tempLength) {
+                    next = source.length();
+                }else{
+                    next = source.indexOf(pattern.substring(patternOffset, tempLength),
+                                          sourceOffset);
+                }
+
+                if (next < 0) {
+                    pos.errorIndex = sourceOffset;
+                    return null; // leave index as is to signal error
+                } else {
+                    String strValue= source.substring(sourceOffset,next);
+                    if (!strValue.equals("{"+argumentNumbers[i]+"}"))
+                        resultArray[argumentNumbers[i]]
+                            = source.substring(sourceOffset,next);
+                    sourceOffset = next;
+                }
+            } else {
+                tempStatus.index = sourceOffset;
+                resultArray[argumentNumbers[i]]
+                    = formats[i].parseObject(source,tempStatus);
+                if (tempStatus.index == sourceOffset) {
+                    pos.errorIndex = sourceOffset;
+                    return null; // leave index as is to signal error
+                }
+                sourceOffset = tempStatus.index; // update
+            }
+        }
+        int len = pattern.length() - patternOffset;
+        if (len == 0 || pattern.regionMatches(patternOffset,
+                                              source, sourceOffset, len)) {
+            pos.index = sourceOffset + len;
+        } else {
+            pos.errorIndex = sourceOffset;
+            return null; // leave index as is to signal error
+        }
+        return resultArray;
+    }
+
+    /**
+     * Parses text from the beginning of the given string to produce an object
+     * array.
+     * The method may not use the entire text of the given string.
+     * <p>
+     * See the {@link #parse(String, ParsePosition)} method for more information
+     * on message parsing.
+     *
+     * @param source A <code>String</code> whose beginning should be parsed.
+     * @return An <code>Object</code> array parsed from the string.
+     * @exception ParseException if the beginning of the specified string
+     *            cannot be parsed.
+     */
+    public Object[] parse(String source) throws ParseException {
+        ParsePosition pos  = new ParsePosition(0);
+        Object[] result = parse(source, pos);
+        if (pos.index == 0)  // unchanged, returned object is null
+            throw new ParseException("MessageFormat parse error!", pos.errorIndex);
+
+        return result;
+    }
+
+    /**
+     * Parses text from a string to produce an object array.
+     * <p>
+     * The method attempts to parse text starting at the index given by
+     * <code>pos</code>.
+     * If parsing succeeds, then the index of <code>pos</code> is updated
+     * to the index after the last character used (parsing does not necessarily
+     * use all characters up to the end of the string), and the parsed
+     * object array is returned. The updated <code>pos</code> can be used to
+     * indicate the starting point for the next call to this method.
+     * If an error occurs, then the index of <code>pos</code> is not
+     * changed, the error index of <code>pos</code> is set to the index of
+     * the character where the error occurred, and null is returned.
+     * <p>
+     * See the {@link #parse(String, ParsePosition)} method for more information
+     * on message parsing.
+     *
+     * @param source A <code>String</code>, part of which should be parsed.
+     * @param pos A <code>ParsePosition</code> object with index and error
+     *            index information as described above.
+     * @return An <code>Object</code> array parsed from the string. In case of
+     *         error, returns null.
+     * @exception NullPointerException if <code>pos</code> is null.
+     */
+    public Object parseObject(String source, ParsePosition pos) {
+        return parse(source, pos);
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     *
+     * @return a clone of this instance.
+     */
+    public Object clone() {
+        MessageFormat other = (MessageFormat) super.clone();
+
+        // clone arrays. Can't do with utility because of bug in Cloneable
+        other.formats = formats.clone(); // shallow clone
+        for (int i = 0; i < formats.length; ++i) {
+            if (formats[i] != null)
+                other.formats[i] = (Format)formats[i].clone();
+        }
+        // for primitives or immutables, shallow clone is enough
+        other.offsets = offsets.clone();
+        other.argumentNumbers = argumentNumbers.clone();
+
+        return other;
+    }
+
+    /**
+     * Equality comparison between two message format objects
+     */
+    public boolean equals(Object obj) {
+        if (this == obj)                      // quick check
+            return true;
+        if (obj == null || getClass() != obj.getClass())
+            return false;
+        MessageFormat other = (MessageFormat) obj;
+        return (maxOffset == other.maxOffset
+                && pattern.equals(other.pattern)
+                && ((locale != null && locale.equals(other.locale))
+                 || (locale == null && other.locale == null))
+                && Arrays.equals(offsets,other.offsets)
+                && Arrays.equals(argumentNumbers,other.argumentNumbers)
+                && Arrays.equals(formats,other.formats));
+    }
+
+    /**
+     * Generates a hash code for the message format object.
+     */
+    public int hashCode() {
+        return pattern.hashCode(); // enough for reasonable distribution
+    }
+
+
+    /**
+     * Defines constants that are used as attribute keys in the
+     * <code>AttributedCharacterIterator</code> returned
+     * from <code>MessageFormat.formatToCharacterIterator</code>.
+     *
+     * @since 1.4
+     */
+    public static class Field extends Format.Field {
+
+        // Proclaim serial compatibility with 1.4 FCS
+        private static final long serialVersionUID = 7899943957617360810L;
+
+        /**
+         * Creates a Field with the specified name.
+         *
+         * @param name Name of the attribute
+         */
+        protected Field(String name) {
+            super(name);
+        }
+
+        /**
+         * Resolves instances being deserialized to the predefined constants.
+         *
+         * @throws InvalidObjectException if the constant could not be
+         *         resolved.
+         * @return resolved MessageFormat.Field constant
+         */
+        protected Object readResolve() throws InvalidObjectException {
+            if (this.getClass() != MessageFormat.Field.class) {
+                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
+            }
+
+            return ARGUMENT;
+        }
+
+        //
+        // The constants
+        //
+
+        /**
+         * Constant identifying a portion of a message that was generated
+         * from an argument passed into <code>formatToCharacterIterator</code>.
+         * The value associated with the key will be an <code>Integer</code>
+         * indicating the index in the <code>arguments</code> array of the
+         * argument from which the text was generated.
+         */
+        public final static Field ARGUMENT =
+                           new Field("message argument field");
+    }
+
+    // ===========================privates============================
+
+    /**
+     * The locale to use for formatting numbers and dates.
+     * @serial
+     */
+    private Locale locale;
+
+    /**
+     * The string that the formatted values are to be plugged into.  In other words, this
+     * is the pattern supplied on construction with all of the {} expressions taken out.
+     * @serial
+     */
+    private String pattern = "";
+
+    /** The initially expected number of subformats in the format */
+    private static final int INITIAL_FORMATS = 10;
+
+    /**
+     * An array of formatters, which are used to format the arguments.
+     * @serial
+     */
+    private Format[] formats = new Format[INITIAL_FORMATS];
+
+    /**
+     * The positions where the results of formatting each argument are to be inserted
+     * into the pattern.
+     * @serial
+     */
+    private int[] offsets = new int[INITIAL_FORMATS];
+
+    /**
+     * The argument numbers corresponding to each formatter.  (The formatters are stored
+     * in the order they occur in the pattern, not in the order in which the arguments
+     * are specified.)
+     * @serial
+     */
+    private int[] argumentNumbers = new int[INITIAL_FORMATS];
+
+    /**
+     * One less than the number of entries in <code>offsets</code>.  Can also be thought of
+     * as the index of the highest-numbered element in <code>offsets</code> that is being used.
+     * All of these arrays should have the same number of elements being used as <code>offsets</code>
+     * does, and so this variable suffices to tell us how many entries are in all of them.
+     * @serial
+     */
+    private int maxOffset = -1;
+
+    /**
+     * Internal routine used by format. If <code>characterIterators</code> is
+     * non-null, AttributedCharacterIterator will be created from the
+     * subformats as necessary. If <code>characterIterators</code> is null
+     * and <code>fp</code> is non-null and identifies
+     * <code>Field.MESSAGE_ARGUMENT</code>, the location of
+     * the first replaced argument will be set in it.
+     *
+     * @exception IllegalArgumentException if an argument in the
+     *            <code>arguments</code> array is not of the type
+     *            expected by the format element(s) that use it.
+     */
+    private StringBuffer subformat(Object[] arguments, StringBuffer result,
+                                   FieldPosition fp, List<AttributedCharacterIterator> characterIterators) {
+        // note: this implementation assumes a fast substring & index.
+        // if this is not true, would be better to append chars one by one.
+        int lastOffset = 0;
+        int last = result.length();
+        for (int i = 0; i <= maxOffset; ++i) {
+            result.append(pattern.substring(lastOffset, offsets[i]));
+            lastOffset = offsets[i];
+            int argumentNumber = argumentNumbers[i];
+            if (arguments == null || argumentNumber >= arguments.length) {
+                result.append('{').append(argumentNumber).append('}');
+                continue;
+            }
+            // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
+            if (false) { // if (argRecursion == 3){
+                // prevent loop!!!
+                result.append('\uFFFD');
+            } else {
+                Object obj = arguments[argumentNumber];
+                String arg = null;
+                Format subFormatter = null;
+                if (obj == null) {
+                    arg = "null";
+                } else if (formats[i] != null) {
+                    subFormatter = formats[i];
+                    if (subFormatter instanceof ChoiceFormat) {
+                        arg = formats[i].format(obj);
+                        if (arg.indexOf('{') >= 0) {
+                            subFormatter = new MessageFormat(arg, locale);
+                            obj = arguments;
+                            arg = null;
+                        }
+                    }
+                } else if (obj instanceof Number) {
+                    // format number if can
+                    subFormatter = NumberFormat.getInstance(locale);
+                } else if (obj instanceof Date) {
+                    // format a Date if can
+                    subFormatter = DateFormat.getDateTimeInstance(
+                             DateFormat.SHORT, DateFormat.SHORT, locale);//fix
+                } else if (obj instanceof String) {
+                    arg = (String) obj;
+
+                } else {
+                    arg = obj.toString();
+                    if (arg == null) arg = "null";
+                }
+
+                // At this point we are in two states, either subFormatter
+                // is non-null indicating we should format obj using it,
+                // or arg is non-null and we should use it as the value.
+
+                if (characterIterators != null) {
+                    // If characterIterators is non-null, it indicates we need
+                    // to get the CharacterIterator from the child formatter.
+                    if (last != result.length()) {
+                        characterIterators.add(
+                            createAttributedCharacterIterator(result.substring
+                                                              (last)));
+                        last = result.length();
+                    }
+                    if (subFormatter != null) {
+                        AttributedCharacterIterator subIterator =
+                                   subFormatter.formatToCharacterIterator(obj);
+
+                        append(result, subIterator);
+                        if (last != result.length()) {
+                            characterIterators.add(
+                                         createAttributedCharacterIterator(
+                                         subIterator, Field.ARGUMENT,
+                                         Integer.valueOf(argumentNumber)));
+                            last = result.length();
+                        }
+                        arg = null;
+                    }
+                    if (arg != null && arg.length() > 0) {
+                        result.append(arg);
+                        characterIterators.add(
+                                 createAttributedCharacterIterator(
+                                 arg, Field.ARGUMENT,
+                                 Integer.valueOf(argumentNumber)));
+                        last = result.length();
+                    }
+                }
+                else {
+                    if (subFormatter != null) {
+                        arg = subFormatter.format(obj);
+                    }
+                    last = result.length();
+                    result.append(arg);
+                    if (i == 0 && fp != null && Field.ARGUMENT.equals(
+                                  fp.getFieldAttribute())) {
+                        fp.setBeginIndex(last);
+                        fp.setEndIndex(result.length());
+                    }
+                    last = result.length();
+                }
+            }
+        }
+        result.append(pattern.substring(lastOffset, pattern.length()));
+        if (characterIterators != null && last != result.length()) {
+            characterIterators.add(createAttributedCharacterIterator(
+                                   result.substring(last)));
+        }
+        return result;
+    }
+
+    /**
+     * Convenience method to append all the characters in
+     * <code>iterator</code> to the StringBuffer <code>result</code>.
+     */
+    private void append(StringBuffer result, CharacterIterator iterator) {
+        if (iterator.first() != CharacterIterator.DONE) {
+            char aChar;
+
+            result.append(iterator.first());
+            while ((aChar = iterator.next()) != CharacterIterator.DONE) {
+                result.append(aChar);
+            }
+        }
+    }
+
+    // Indices for segments
+    private static final int SEG_RAW      = 0;
+    private static final int SEG_INDEX    = 1;
+    private static final int SEG_TYPE     = 2;
+    private static final int SEG_MODIFIER = 3; // modifier or subformat
+
+    // Indices for type keywords
+    private static final int TYPE_NULL    = 0;
+    private static final int TYPE_NUMBER  = 1;
+    private static final int TYPE_DATE    = 2;
+    private static final int TYPE_TIME    = 3;
+    private static final int TYPE_CHOICE  = 4;
+
+    private static final String[] TYPE_KEYWORDS = {
+        "",
+        "number",
+        "date",
+        "time",
+        "choice"
+    };
+
+    // Indices for number modifiers
+    private static final int MODIFIER_DEFAULT  = 0; // common in number and date-time
+    private static final int MODIFIER_CURRENCY = 1;
+    private static final int MODIFIER_PERCENT  = 2;
+    private static final int MODIFIER_INTEGER  = 3;
+
+    private static final String[] NUMBER_MODIFIER_KEYWORDS = {
+        "",
+        "currency",
+        "percent",
+        "integer"
+    };
+
+    // Indices for date-time modifiers
+    private static final int MODIFIER_SHORT   = 1;
+    private static final int MODIFIER_MEDIUM  = 2;
+    private static final int MODIFIER_LONG    = 3;
+    private static final int MODIFIER_FULL    = 4;
+
+    private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
+        "",
+        "short",
+        "medium",
+        "long",
+        "full"
+    };
+
+    // Date-time style values corresponding to the date-time modifiers.
+    private static final int[] DATE_TIME_MODIFIERS = {
+        DateFormat.DEFAULT,
+        DateFormat.SHORT,
+        DateFormat.MEDIUM,
+        DateFormat.LONG,
+        DateFormat.FULL,
+    };
+
+    private void makeFormat(int position, int offsetNumber,
+                            StringBuilder[] textSegments)
+    {
+        String[] segments = new String[textSegments.length];
+        for (int i = 0; i < textSegments.length; i++) {
+            StringBuilder oneseg = textSegments[i];
+            segments[i] = (oneseg != null) ? oneseg.toString() : "";
+        }
+
+        // get the argument number
+        int argumentNumber;
+        try {
+            argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("can't parse argument number: "
+                                               + segments[SEG_INDEX], e);
+        }
+        if (argumentNumber < 0) {
+            throw new IllegalArgumentException("negative argument number: "
+                                               + argumentNumber);
+        }
+
+        // resize format information arrays if necessary
+        if (offsetNumber >= formats.length) {
+            int newLength = formats.length * 2;
+            Format[] newFormats = new Format[newLength];
+            int[] newOffsets = new int[newLength];
+            int[] newArgumentNumbers = new int[newLength];
+            System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
+            System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
+            System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
+            formats = newFormats;
+            offsets = newOffsets;
+            argumentNumbers = newArgumentNumbers;
+        }
+        int oldMaxOffset = maxOffset;
+        maxOffset = offsetNumber;
+        offsets[offsetNumber] = segments[SEG_RAW].length();
+        argumentNumbers[offsetNumber] = argumentNumber;
+
+        // now get the format
+        Format newFormat = null;
+        if (segments[SEG_TYPE].length() != 0) {
+            int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
+            switch (type) {
+            case TYPE_NULL:
+                // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
+                // are treated as "{0}".
+                break;
+
+            case TYPE_NUMBER:
+                switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
+                case MODIFIER_DEFAULT:
+                    newFormat = NumberFormat.getInstance(locale);
+                    break;
+                case MODIFIER_CURRENCY:
+                    newFormat = NumberFormat.getCurrencyInstance(locale);
+                    break;
+                case MODIFIER_PERCENT:
+                    newFormat = NumberFormat.getPercentInstance(locale);
+                    break;
+                case MODIFIER_INTEGER:
+                    newFormat = NumberFormat.getIntegerInstance(locale);
+                    break;
+                default: // DecimalFormat pattern
+                    try {
+                        newFormat = new DecimalFormat(segments[SEG_MODIFIER],
+                                                      DecimalFormatSymbols.getInstance(locale));
+                    } catch (IllegalArgumentException e) {
+                        maxOffset = oldMaxOffset;
+                        throw e;
+                    }
+                    break;
+                }
+                break;
+
+            case TYPE_DATE:
+            case TYPE_TIME:
+                int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
+                if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
+                    if (type == TYPE_DATE) {
+                        newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
+                                                               locale);
+                    } else {
+                        newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
+                                                               locale);
+                    }
+                } else {
+                    // SimpleDateFormat pattern
+                    try {
+                        newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
+                    } catch (IllegalArgumentException e) {
+                        maxOffset = oldMaxOffset;
+                        throw e;
+                    }
+                }
+                break;
+
+            case TYPE_CHOICE:
+                try {
+                    // ChoiceFormat pattern
+                    newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
+                } catch (Exception e) {
+                    maxOffset = oldMaxOffset;
+                    throw new IllegalArgumentException("Choice Pattern incorrect: "
+                                                       + segments[SEG_MODIFIER], e);
+                }
+                break;
+
+            default:
+                maxOffset = oldMaxOffset;
+                throw new IllegalArgumentException("unknown format type: " +
+                                                   segments[SEG_TYPE]);
+            }
+        }
+        formats[offsetNumber] = newFormat;
+    }
+
+    private static final int findKeyword(String s, String[] list) {
+        for (int i = 0; i < list.length; ++i) {
+            if (s.equals(list[i]))
+                return i;
+        }
+
+        // Try trimmed lowercase.
+        String ls = s.trim().toLowerCase(Locale.ROOT);
+        if (ls != s) {
+            for (int i = 0; i < list.length; ++i) {
+                if (ls.equals(list[i]))
+                    return i;
+            }
+        }
+        return -1;
+    }
+
+    private static final void copyAndFixQuotes(String source, int start, int end,
+                                               StringBuilder target) {
+        boolean quoted = false;
+
+        for (int i = start; i < end; ++i) {
+            char ch = source.charAt(i);
+            if (ch == '{') {
+                if (!quoted) {
+                    target.append('\'');
+                    quoted = true;
+                }
+                target.append(ch);
+            } else if (ch == '\'') {
+                target.append("''");
+            } else {
+                if (quoted) {
+                    target.append('\'');
+                    quoted = false;
+                }
+                target.append(ch);
+            }
+        }
+        if (quoted) {
+            target.append('\'');
+        }
+    }
+
+    /**
+     * After reading an object from the input stream, do a simple verification
+     * to maintain class invariants.
+     * @throws InvalidObjectException if the objects read from the stream is invalid.
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        boolean isValid = maxOffset >= -1
+                && formats.length > maxOffset
+                && offsets.length > maxOffset
+                && argumentNumbers.length > maxOffset;
+        if (isValid) {
+            int lastOffset = pattern.length() + 1;
+            for (int i = maxOffset; i >= 0; --i) {
+                if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
+                    isValid = false;
+                    break;
+                } else {
+                    lastOffset = offsets[i];
+                }
+            }
+        }
+        if (!isValid) {
+            throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
+        }
+    }
+}
diff --git a/java/text/Normalizer.java b/java/text/Normalizer.java
new file mode 100644
index 0000000..8c22547
--- /dev/null
+++ b/java/text/Normalizer.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *******************************************************************************
+ * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved                     *
+ *                                                                             *
+ * The original version of this source code and documentation is copyrighted   *
+ * and owned by IBM, These materials are provided under terms of a License     *
+ * Agreement between IBM and Sun. This technology is protected by multiple     *
+ * US and International patents. This notice and attribution to IBM may not    *
+ * to removed.                                                                 *
+ *******************************************************************************
+ */
+
+package java.text;
+
+/**
+ * This class provides the method <code>normalize</code> which transforms Unicode
+ * text into an equivalent composed or decomposed form, allowing for easier
+ * sorting and searching of text.
+ * The <code>normalize</code> method supports the standard normalization forms
+ * described in
+ * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">
+ * Unicode Standard Annex #15 &mdash; Unicode Normalization Forms</a>.
+ * <p>
+ * Characters with accents or other adornments can be encoded in
+ * several different ways in Unicode.  For example, take the character A-acute.
+ * In Unicode, this can be encoded as a single character (the "composed" form):
+ *
+ * <pre>
+ *      U+00C1    LATIN CAPITAL LETTER A WITH ACUTE</pre>
+ *
+ * or as two separate characters (the "decomposed" form):
+ *
+ * <pre>
+ *      U+0041    LATIN CAPITAL LETTER A
+ *      U+0301    COMBINING ACUTE ACCENT</pre>
+ *
+ * To a user of your program, however, both of these sequences should be
+ * treated as the same "user-level" character "A with acute accent".  When you
+ * are searching or comparing text, you must ensure that these two sequences are
+ * treated as equivalent.  In addition, you must handle characters with more than
+ * one accent. Sometimes the order of a character's combining accents is
+ * significant, while in other cases accent sequences in different orders are
+ * really equivalent.
+ * <p>
+ * Similarly, the string "ffi" can be encoded as three separate letters:
+ *
+ * <pre>
+ *      U+0066    LATIN SMALL LETTER F
+ *      U+0066    LATIN SMALL LETTER F
+ *      U+0069    LATIN SMALL LETTER I</pre>
+ *
+ * or as the single character
+ *
+ * <pre>
+ *      U+FB03    LATIN SMALL LIGATURE FFI</pre>
+ *
+ * The ffi ligature is not a distinct semantic character, and strictly speaking
+ * it shouldn't be in Unicode at all, but it was included for compatibility
+ * with existing character sets that already provided it.  The Unicode standard
+ * identifies such characters by giving them "compatibility" decompositions
+ * into the corresponding semantic characters.  When sorting and searching, you
+ * will often want to use these mappings.
+ * <p>
+ * The <code>normalize</code> method helps solve these problems by transforming
+ * text into the canonical composed and decomposed forms as shown in the first
+ * example above. In addition, you can have it perform compatibility
+ * decompositions so that you can treat compatibility characters the same as
+ * their equivalents.
+ * Finally, the <code>normalize</code> method rearranges accents into the
+ * proper canonical order, so that you do not have to worry about accent
+ * rearrangement on your own.
+ * <p>
+ * The W3C generally recommends to exchange texts in NFC.
+ * Note also that most legacy character encodings use only precomposed forms and
+ * often do not encode any combining marks by themselves. For conversion to such
+ * character encodings the Unicode text needs to be normalized to NFC.
+ * For more usage examples, see the Unicode Standard Annex.
+ *
+ * @since 1.6
+ */
+public final class Normalizer {
+
+   private Normalizer() {};
+
+    /**
+     * This enum provides constants of the four Unicode normalization forms
+     * that are described in
+     * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">
+     * Unicode Standard Annex #15 &mdash; Unicode Normalization Forms</a>
+     * and two methods to access them.
+     *
+     * @since 1.6
+     */
+    // BEGIN Android-changed: remove static modifier and add mapping to equivalent ICU values.
+    public enum Form {
+
+        /**
+         * Canonical decomposition.
+         */
+        NFD(android.icu.text.Normalizer.NFD),
+
+        /**
+         * Canonical decomposition, followed by canonical composition.
+         */
+        NFC(android.icu.text.Normalizer.NFC),
+
+        /**
+         * Compatibility decomposition.
+         */
+        NFKD(android.icu.text.Normalizer.NFKD),
+
+        /**
+         * Compatibility decomposition, followed by canonical composition.
+         */
+        NFKC(android.icu.text.Normalizer.NFKC);
+
+        private final android.icu.text.Normalizer.Mode icuMode;
+
+        Form(android.icu.text.Normalizer.Mode icuMode) {
+            this.icuMode = icuMode;
+        }
+    }
+    // END Android-changed: remove static modifier and add mapping to equivalent ICU values.
+
+    /**
+     * Normalize a sequence of char values.
+     * The sequence will be normalized according to the specified normalization
+     * from.
+     * @param src        The sequence of char values to normalize.
+     * @param form       The normalization form; one of
+     *                   {@link java.text.Normalizer.Form#NFC},
+     *                   {@link java.text.Normalizer.Form#NFD},
+     *                   {@link java.text.Normalizer.Form#NFKC},
+     *                   {@link java.text.Normalizer.Form#NFKD}
+     * @return The normalized String
+     * @throws NullPointerException If <code>src</code> or <code>form</code>
+     * is null.
+     */
+    public static String normalize(CharSequence src, Form form) {
+        // Android-changed: Switched to ICU.
+        return android.icu.text.Normalizer.normalize(src.toString(), form.icuMode);
+    }
+
+    /**
+     * Determines if the given sequence of char values is normalized.
+     * @param src        The sequence of char values to be checked.
+     * @param form       The normalization form; one of
+     *                   {@link java.text.Normalizer.Form#NFC},
+     *                   {@link java.text.Normalizer.Form#NFD},
+     *                   {@link java.text.Normalizer.Form#NFKC},
+     *                   {@link java.text.Normalizer.Form#NFKD}
+     * @return true if the sequence of char values is normalized;
+     * false otherwise.
+     * @throws NullPointerException If <code>src</code> or <code>form</code>
+     * is null.
+     */
+    public static boolean isNormalized(CharSequence src, Form form) {
+        // Android-changed: Switched to ICU.
+        return android.icu.text.Normalizer.isNormalized(src.toString(), form.icuMode, 0);
+    }
+}
diff --git a/java/text/NumberFormat.annotated.java b/java/text/NumberFormat.annotated.java
new file mode 100644
index 0000000..7f51005
--- /dev/null
+++ b/java/text/NumberFormat.annotated.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+
+package java.text;
+
+import java.util.Locale;
+import java.util.Currency;
+import java.math.RoundingMode;
+import java.math.BigInteger;
+import java.io.InvalidObjectException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class NumberFormat extends java.text.Format {
+
+protected NumberFormat() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer format(@libcore.util.NonNull java.lang.Object number, @libcore.util.NonNull java.lang.StringBuffer toAppendTo, @libcore.util.NonNull java.text.FieldPosition pos) { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.Object parseObject(@libcore.util.NonNull java.lang.String source, @libcore.util.NonNull java.text.ParsePosition pos) { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String format(double number) { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String format(long number) { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.lang.StringBuffer format(double number, @libcore.util.NonNull java.lang.StringBuffer toAppendTo, @libcore.util.NonNull java.text.FieldPosition pos);
+
[email protected] public abstract java.lang.StringBuffer format(long number, @libcore.util.NonNull java.lang.StringBuffer toAppendTo, @libcore.util.NonNull java.text.FieldPosition pos);
+
[email protected] public abstract java.lang.Number parse(@libcore.util.NonNull java.lang.String source, @libcore.util.NonNull java.text.ParsePosition parsePosition);
+
[email protected] public java.lang.Number parse(@libcore.util.NonNull java.lang.String source) throws java.text.ParseException { throw new RuntimeException("Stub!"); }
+
+public boolean isParseIntegerOnly() { throw new RuntimeException("Stub!"); }
+
+public void setParseIntegerOnly(boolean value) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.text.NumberFormat getInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.text.NumberFormat getInstance(@libcore.util.NonNull java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.text.NumberFormat getNumberInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.text.NumberFormat getNumberInstance(@libcore.util.NonNull java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.text.NumberFormat getIntegerInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.text.NumberFormat getIntegerInstance(@libcore.util.NonNull java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.text.NumberFormat getCurrencyInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.text.NumberFormat getCurrencyInstance(@libcore.util.NonNull java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.text.NumberFormat getPercentInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.text.NumberFormat getPercentInstance(@libcore.util.NonNull java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
+public static [email protected] Locale @libcore.util.NonNull [] getAvailableLocales() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public boolean isGroupingUsed() { throw new RuntimeException("Stub!"); }
+
+public void setGroupingUsed(boolean newValue) { throw new RuntimeException("Stub!"); }
+
+public int getMaximumIntegerDigits() { throw new RuntimeException("Stub!"); }
+
+public void setMaximumIntegerDigits(int newValue) { throw new RuntimeException("Stub!"); }
+
+public int getMinimumIntegerDigits() { throw new RuntimeException("Stub!"); }
+
+public void setMinimumIntegerDigits(int newValue) { throw new RuntimeException("Stub!"); }
+
+public int getMaximumFractionDigits() { throw new RuntimeException("Stub!"); }
+
+public void setMaximumFractionDigits(int newValue) { throw new RuntimeException("Stub!"); }
+
+public int getMinimumFractionDigits() { throw new RuntimeException("Stub!"); }
+
+public void setMinimumFractionDigits(int newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Currency getCurrency() { throw new RuntimeException("Stub!"); }
+
+public void setCurrency(@libcore.util.NonNull java.util.Currency currency) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.math.RoundingMode getRoundingMode() { throw new RuntimeException("Stub!"); }
+
+public void setRoundingMode(@libcore.util.Nullable java.math.RoundingMode roundingMode) { throw new RuntimeException("Stub!"); }
+
+public static final int FRACTION_FIELD = 1; // 0x1
+
+public static final int INTEGER_FIELD = 0; // 0x0
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class Field extends java.text.Format.Field {
+
+protected Field(@libcore.util.NonNull java.lang.String name) { super(null); throw new RuntimeException("Stub!"); }
+
[email protected] protected java.lang.Object readResolve() throws java.io.InvalidObjectException { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.text.NumberFormat.Field CURRENCY;
+static { CURRENCY = null; }
+
[email protected] public static final java.text.NumberFormat.Field DECIMAL_SEPARATOR;
+static { DECIMAL_SEPARATOR = null; }
+
[email protected] public static final java.text.NumberFormat.Field EXPONENT;
+static { EXPONENT = null; }
+
[email protected] public static final java.text.NumberFormat.Field EXPONENT_SIGN;
+static { EXPONENT_SIGN = null; }
+
[email protected] public static final java.text.NumberFormat.Field EXPONENT_SYMBOL;
+static { EXPONENT_SYMBOL = null; }
+
[email protected] public static final java.text.NumberFormat.Field FRACTION;
+static { FRACTION = null; }
+
[email protected] public static final java.text.NumberFormat.Field GROUPING_SEPARATOR;
+static { GROUPING_SEPARATOR = null; }
+
[email protected] public static final java.text.NumberFormat.Field INTEGER;
+static { INTEGER = null; }
+
[email protected] public static final java.text.NumberFormat.Field PERCENT;
+static { PERCENT = null; }
+
[email protected] public static final java.text.NumberFormat.Field PERMILLE;
+static { PERMILLE = null; }
+
[email protected] public static final java.text.NumberFormat.Field SIGN;
+static { SIGN = null; }
+}
+
+}
diff --git a/java/text/NumberFormat.java b/java/text/NumberFormat.java
new file mode 100644
index 0000000..9ad44ed
--- /dev/null
+++ b/java/text/NumberFormat.java
@@ -0,0 +1,1206 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.io.InvalidObjectException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.util.Currency;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import libcore.icu.ICU;
+import libcore.icu.LocaleData;
+
+/**
+ * <code>NumberFormat</code> is the abstract base class for all number
+ * formats. This class provides the interface for formatting and parsing
+ * numbers. <code>NumberFormat</code> also provides methods for determining
+ * which locales have number formats, and what their names are.
+ *
+ * <p>
+ * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
+ * Your code can be completely independent of the locale conventions for
+ * decimal points, thousands-separators, or even the particular decimal
+ * digits used, or whether the number format is even decimal.
+ *
+ * <p>
+ * To format a number for the current Locale, use one of the factory
+ * class methods:
+ * <blockquote>
+ * <pre>{@code
+ * myString = NumberFormat.getInstance().format(myNumber);
+ * }</pre>
+ * </blockquote>
+ * If you are formatting multiple numbers, it is
+ * more efficient to get the format and use it multiple times so that
+ * the system doesn't have to fetch the information about the local
+ * language and country conventions multiple times.
+ * <blockquote>
+ * <pre>{@code
+ * NumberFormat nf = NumberFormat.getInstance();
+ * for (int i = 0; i < myNumber.length; ++i) {
+ *     output.println(nf.format(myNumber[i]) + "; ");
+ * }
+ * }</pre>
+ * </blockquote>
+ * To format a number for a different Locale, specify it in the
+ * call to <code>getInstance</code>.
+ * <blockquote>
+ * <pre>{@code
+ * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
+ * }</pre>
+ * </blockquote>
+ * You can also use a <code>NumberFormat</code> to parse numbers:
+ * <blockquote>
+ * <pre>{@code
+ * myNumber = nf.parse(myString);
+ * }</pre>
+ * </blockquote>
+ * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
+ * normal number format. Use <code>getIntegerInstance</code> to get an
+ * integer number format. Use <code>getCurrencyInstance</code> to get the
+ * currency number format. And use <code>getPercentInstance</code> to get a
+ * format for displaying percentages. With this format, a fraction like
+ * 0.53 is displayed as 53%.
+ *
+ * <p>
+ * You can also control the display of numbers with such methods as
+ * <code>setMinimumFractionDigits</code>.
+ * If you want even more control over the format or parsing,
+ * or want to give your users more control,
+ * you can try casting the <code>NumberFormat</code> you get from the factory methods
+ * to a <code>DecimalFormat</code>. This will work for the vast majority
+ * of locales; just remember to put it in a <code>try</code> block in case you
+ * encounter an unusual one.
+ *
+ * <p>
+ * NumberFormat and DecimalFormat are designed such that some controls
+ * work for formatting and others work for parsing.  The following is
+ * the detailed description for each these control methods,
+ * <p>
+ * setParseIntegerOnly : only affects parsing, e.g.
+ * if true,  "3456.78" &rarr; 3456 (and leaves the parse position just after index 6)
+ * if false, "3456.78" &rarr; 3456.78 (and leaves the parse position just after index 8)
+ * This is independent of formatting.  If you want to not show a decimal point
+ * where there might be no digits after the decimal point, use
+ * setDecimalSeparatorAlwaysShown.
+ * <p>
+ * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
+ * there might be no digits after the decimal point, such as with a pattern
+ * like "#,##0.##", e.g.,
+ * if true,  3456.00 &rarr; "3,456."
+ * if false, 3456.00 &rarr; "3456"
+ * This is independent of parsing.  If you want parsing to stop at the decimal
+ * point, use setParseIntegerOnly.
+ *
+ * <p>
+ * You can also use forms of the <code>parse</code> and <code>format</code>
+ * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
+ * allow you to:
+ * <ul>
+ * <li> progressively parse through pieces of a string
+ * <li> align the decimal point and other areas
+ * </ul>
+ * For example, you can align numbers in two ways:
+ * <ol>
+ * <li> If you are using a monospaced font with spacing for alignment,
+ *      you can pass the <code>FieldPosition</code> in your format call, with
+ *      <code>field</code> = <code>INTEGER_FIELD</code>. On output,
+ *      <code>getEndIndex</code> will be set to the offset between the
+ *      last character of the integer and the decimal. Add
+ *      (desiredSpaceCount - getEndIndex) spaces at the front of the string.
+ *
+ * <li> If you are using proportional fonts,
+ *      instead of padding with spaces, measure the width
+ *      of the string in pixels from the start to <code>getEndIndex</code>.
+ *      Then move the pen by
+ *      (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
+ *      It also works where there is no decimal, but possibly additional
+ *      characters at the end, e.g., with parentheses in negative
+ *      numbers: "(12)" for -12.
+ * </ol>
+ *
+ * <h3><a name="synchronization">Synchronization</a></h3>
+ *
+ * <p>
+ * Number formats are generally not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * @see          DecimalFormat
+ * @see          ChoiceFormat
+ * @author       Mark Davis
+ * @author       Helena Shih
+ */
+public abstract class NumberFormat extends Format  {
+
+    /**
+     * Field constant used to construct a FieldPosition object. Signifies that
+     * the position of the integer part of a formatted number should be returned.
+     * @see java.text.FieldPosition
+     */
+    public static final int INTEGER_FIELD = 0;
+
+    /**
+     * Field constant used to construct a FieldPosition object. Signifies that
+     * the position of the fraction part of a formatted number should be returned.
+     * @see java.text.FieldPosition
+     */
+    public static final int FRACTION_FIELD = 1;
+
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected NumberFormat() {
+    }
+
+    /**
+     * Formats a number and appends the resulting text to the given string
+     * buffer.
+     * The number can be of any subclass of {@link java.lang.Number}.
+     * <p>
+     * This implementation extracts the number's value using
+     * {@link java.lang.Number#longValue()} for all integral type values that
+     * can be converted to <code>long</code> without loss of information,
+     * including <code>BigInteger</code> values with a
+     * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
+     * and {@link java.lang.Number#doubleValue()} for all other types. It
+     * then calls
+     * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
+     * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
+     * This may result in loss of magnitude information and precision for
+     * <code>BigInteger</code> and <code>BigDecimal</code> values.
+     * @param number     the number to format
+     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
+     *                   text is to be appended
+     * @param pos        On input: an alignment field, if desired.
+     *                   On output: the offsets of the alignment field.
+     * @return           the value passed in as <code>toAppendTo</code>
+     * @exception        IllegalArgumentException if <code>number</code> is
+     *                   null or not an instance of <code>Number</code>.
+     * @exception        NullPointerException if <code>toAppendTo</code> or
+     *                   <code>pos</code> is null
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see              java.text.FieldPosition
+     */
+    @Override
+    public StringBuffer format(Object number,
+                               StringBuffer toAppendTo,
+                               FieldPosition pos) {
+        if (number instanceof Long || number instanceof Integer ||
+            number instanceof Short || number instanceof Byte ||
+            number instanceof AtomicInteger || number instanceof AtomicLong ||
+            (number instanceof BigInteger &&
+             ((BigInteger)number).bitLength() < 64)) {
+            return format(((Number)number).longValue(), toAppendTo, pos);
+        } else if (number instanceof Number) {
+            return format(((Number)number).doubleValue(), toAppendTo, pos);
+        } else {
+            throw new IllegalArgumentException("Cannot format given Object as a Number");
+        }
+    }
+
+    /**
+     * Parses text from a string to produce a <code>Number</code>.
+     * <p>
+     * The method attempts to parse text starting at the index given by
+     * <code>pos</code>.
+     * If parsing succeeds, then the index of <code>pos</code> is updated
+     * to the index after the last character used (parsing does not necessarily
+     * use all characters up to the end of the string), and the parsed
+     * number is returned. The updated <code>pos</code> can be used to
+     * indicate the starting point for the next call to this method.
+     * If an error occurs, then the index of <code>pos</code> is not
+     * changed, the error index of <code>pos</code> is set to the index of
+     * the character where the error occurred, and null is returned.
+     * <p>
+     * See the {@link #parse(String, ParsePosition)} method for more information
+     * on number parsing.
+     *
+     * @param source A <code>String</code>, part of which should be parsed.
+     * @param pos A <code>ParsePosition</code> object with index and error
+     *            index information as described above.
+     * @return A <code>Number</code> parsed from the string. In case of
+     *         error, returns null.
+     * @exception NullPointerException if <code>pos</code> is null.
+     */
+    @Override
+    public final Object parseObject(String source, ParsePosition pos) {
+        return parse(source, pos);
+    }
+
+   /**
+     * Specialization of format.
+     *
+     * @param number the double number to format
+     * @return the formatted String
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.Format#format
+     */
+    public final String format(double number) {
+        // Android-removed: fast-path code.
+        return format(number, new StringBuffer(),
+                      DontCareFieldPosition.INSTANCE).toString();
+    }
+
+    // Android-removed: fastFormat method.
+
+   /**
+     * Specialization of format.
+     *
+     * @param number the long number to format
+     * @return the formatted String
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.Format#format
+     */
+    public final String format(long number) {
+        return format(number, new StringBuffer(),
+                      DontCareFieldPosition.INSTANCE).toString();
+    }
+
+   /**
+     * Specialization of format.
+     *
+     * @param number     the double number to format
+     * @param toAppendTo the StringBuffer to which the formatted text is to be
+     *                   appended
+     * @param pos        the field position
+     * @return the formatted StringBuffer
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.Format#format
+     */
+    public abstract StringBuffer format(double number,
+                                        StringBuffer toAppendTo,
+                                        FieldPosition pos);
+
+   /**
+     * Specialization of format.
+     *
+     * @param number     the long number to format
+     * @param toAppendTo the StringBuffer to which the formatted text is to be
+     *                   appended
+     * @param pos        the field position
+     * @return the formatted StringBuffer
+     * @exception        ArithmeticException if rounding is needed with rounding
+     *                   mode being set to RoundingMode.UNNECESSARY
+     * @see java.text.Format#format
+     */
+    public abstract StringBuffer format(long number,
+                                        StringBuffer toAppendTo,
+                                        FieldPosition pos);
+
+   /**
+     * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
+     * Long.MAX_VALUE] and with no decimals), otherwise a Double.
+     * If IntegerOnly is set, will stop at a decimal
+     * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
+     * after the 1).
+     * Does not throw an exception; if no object can be parsed, index is
+     * unchanged!
+     *
+     * @param source the String to parse
+     * @param parsePosition the parse position
+     * @return the parsed value
+     * @see java.text.NumberFormat#isParseIntegerOnly
+     * @see java.text.Format#parseObject
+     */
+    public abstract Number parse(String source, ParsePosition parsePosition);
+
+    /**
+     * Parses text from the beginning of the given string to produce a number.
+     * The method may not use the entire text of the given string.
+     * <p>
+     * See the {@link #parse(String, ParsePosition)} method for more information
+     * on number parsing.
+     *
+     * @param source A <code>String</code> whose beginning should be parsed.
+     * @return A <code>Number</code> parsed from the string.
+     * @exception ParseException if the beginning of the specified string
+     *            cannot be parsed.
+     */
+    public Number parse(String source) throws ParseException {
+        ParsePosition parsePosition = new ParsePosition(0);
+        Number result = parse(source, parsePosition);
+        if (parsePosition.index == 0) {
+            throw new ParseException("Unparseable number: \"" + source + "\"",
+                                     parsePosition.errorIndex);
+        }
+        return result;
+    }
+
+    /**
+     * Returns true if this format will parse numbers as integers only.
+     * For example in the English locale, with ParseIntegerOnly true, the
+     * string "1234." would be parsed as the integer value 1234 and parsing
+     * would stop at the "." character.  Of course, the exact format accepted
+     * by the parse operation is locale dependant and determined by sub-classes
+     * of NumberFormat.
+     *
+     * @return {@code true} if numbers should be parsed as integers only;
+     *         {@code false} otherwise
+     */
+    public boolean isParseIntegerOnly() {
+        return parseIntegerOnly;
+    }
+
+    /**
+     * Sets whether or not numbers should be parsed as integers only.
+     *
+     * @param value {@code true} if numbers should be parsed as integers only;
+     *              {@code false} otherwise
+     * @see #isParseIntegerOnly
+     */
+    public void setParseIntegerOnly(boolean value) {
+        parseIntegerOnly = value;
+    }
+
+    //============== Locale Stuff =====================
+
+    /**
+     * Returns a general-purpose number format for the current default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * This is the same as calling
+     * {@link #getNumberInstance() getNumberInstance()}.
+     *
+     * @return the {@code NumberFormat} instance for general-purpose number
+     * formatting
+     */
+    public final static NumberFormat getInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
+    }
+
+    /**
+     * Returns a general-purpose number format for the specified locale.
+     * This is the same as calling
+     * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
+     *
+     * @param inLocale the desired locale
+     * @return the {@code NumberFormat} instance for general-purpose number
+     * formatting
+     */
+    public static NumberFormat getInstance(Locale inLocale) {
+        return getInstance(inLocale, NUMBERSTYLE);
+    }
+
+    /**
+     * Returns a general-purpose number format for the current default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getNumberInstance(Locale)
+     *     getNumberInstance(Locale.getDefault(Locale.Category.FORMAT))}.
+     *
+     * @return the {@code NumberFormat} instance for general-purpose number
+     * formatting
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     */
+    public final static NumberFormat getNumberInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
+    }
+
+    /**
+     * Returns a general-purpose number format for the specified locale.
+     *
+     * @param inLocale the desired locale
+     * @return the {@code NumberFormat} instance for general-purpose number
+     * formatting
+     */
+    public static NumberFormat getNumberInstance(Locale inLocale) {
+        return getInstance(inLocale, NUMBERSTYLE);
+    }
+
+    /**
+     * Returns an integer number format for the current default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale. The
+     * returned number format is configured to round floating point numbers
+     * to the nearest integer using half-even rounding (see {@link
+     * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
+     * and to parse only the integer part of an input string (see {@link
+     * #isParseIntegerOnly isParseIntegerOnly}).
+     * <p>This is equivalent to calling
+     * {@link #getIntegerInstance(Locale)
+     *     getIntegerInstance(Locale.getDefault(Locale.Category.FORMAT))}.
+     *
+     * @see #getRoundingMode()
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @return a number format for integer values
+     * @since 1.4
+     */
+    public final static NumberFormat getIntegerInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
+    }
+
+    /**
+     * Returns an integer number format for the specified locale. The
+     * returned number format is configured to round floating point numbers
+     * to the nearest integer using half-even rounding (see {@link
+     * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
+     * and to parse only the integer part of an input string (see {@link
+     * #isParseIntegerOnly isParseIntegerOnly}).
+     *
+     * @param inLocale the desired locale
+     * @see #getRoundingMode()
+     * @return a number format for integer values
+     * @since 1.4
+     */
+    public static NumberFormat getIntegerInstance(Locale inLocale) {
+        return getInstance(inLocale, INTEGERSTYLE);
+    }
+
+    /**
+     * Returns a currency format for the current default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getCurrencyInstance(Locale)
+     *     getCurrencyInstance(Locale.getDefault(Locale.Category.FORMAT))}.
+     *
+     * @return the {@code NumberFormat} instance for currency formatting
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     */
+    public final static NumberFormat getCurrencyInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
+    }
+
+    /**
+     * Returns a currency format for the specified locale.
+     *
+     * @param inLocale the desired locale
+     * @return the {@code NumberFormat} instance for currency formatting
+     */
+    public static NumberFormat getCurrencyInstance(Locale inLocale) {
+        return getInstance(inLocale, CURRENCYSTYLE);
+    }
+
+    /**
+     * Returns a percentage format for the current default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>This is equivalent to calling
+     * {@link #getPercentInstance(Locale)
+     *     getPercentInstance(Locale.getDefault(Locale.Category.FORMAT))}.
+     *
+     * @return the {@code NumberFormat} instance for percentage formatting
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     */
+    public final static NumberFormat getPercentInstance() {
+        return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
+    }
+
+    /**
+     * Returns a percentage format for the specified locale.
+     *
+     * @param inLocale the desired locale
+     * @return the {@code NumberFormat} instance for percentage formatting
+     */
+    public static NumberFormat getPercentInstance(Locale inLocale) {
+        return getInstance(inLocale, PERCENTSTYLE);
+    }
+
+    // Android-removed: non-API methods getScientificInstance([Locale]).
+
+    // Android-changed: Removed reference to NumberFormatProvider.
+    /**
+     * Returns an array of all locales for which the
+     * <code>get*Instance</code> methods of this class can return
+     * localized instances.
+     *
+     * @return An array of locales for which localized
+     *         <code>NumberFormat</code> instances are available.
+     */
+    public static Locale[] getAvailableLocales() {
+        // Android-changed: Removed used of NumberFormatProvider. Switched to use ICU.
+        return ICU.getAvailableLocales();
+    }
+
+    /**
+     * Overrides hashCode.
+     */
+    @Override
+    public int hashCode() {
+        return maximumIntegerDigits * 37 + maxFractionDigits;
+        // just enough fields for a reasonable distribution
+    }
+
+    /**
+     * Overrides equals.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        NumberFormat other = (NumberFormat) obj;
+        return (maximumIntegerDigits == other.maximumIntegerDigits
+            && minimumIntegerDigits == other.minimumIntegerDigits
+            && maximumFractionDigits == other.maximumFractionDigits
+            && minimumFractionDigits == other.minimumFractionDigits
+            && groupingUsed == other.groupingUsed
+            && parseIntegerOnly == other.parseIntegerOnly);
+    }
+
+    /**
+     * Overrides Cloneable.
+     */
+    @Override
+    public Object clone() {
+        NumberFormat other = (NumberFormat) super.clone();
+        return other;
+    }
+
+    /**
+     * Returns true if grouping is used in this format. For example, in the
+     * English locale, with grouping on, the number 1234567 might be formatted
+     * as "1,234,567". The grouping separator as well as the size of each group
+     * is locale dependant and is determined by sub-classes of NumberFormat.
+     *
+     * @return {@code true} if grouping is used;
+     *         {@code false} otherwise
+     * @see #setGroupingUsed
+     */
+    public boolean isGroupingUsed() {
+        return groupingUsed;
+    }
+
+    /**
+     * Set whether or not grouping will be used in this format.
+     *
+     * @param newValue {@code true} if grouping is used;
+     *                 {@code false} otherwise
+     * @see #isGroupingUsed
+     */
+    public void setGroupingUsed(boolean newValue) {
+        groupingUsed = newValue;
+    }
+
+    /**
+     * Returns the maximum number of digits allowed in the integer portion of a
+     * number.
+     *
+     * @return the maximum number of digits
+     * @see #setMaximumIntegerDigits
+     */
+    public int getMaximumIntegerDigits() {
+        return maximumIntegerDigits;
+    }
+
+    /**
+     * Sets the maximum number of digits allowed in the integer portion of a
+     * number. maximumIntegerDigits must be &ge; minimumIntegerDigits.  If the
+     * new value for maximumIntegerDigits is less than the current value
+     * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
+     * the new value.
+     *
+     * @param newValue the maximum number of integer digits to be shown; if
+     * less than zero, then zero is used. The concrete subclass may enforce an
+     * upper limit to this value appropriate to the numeric type being formatted.
+     * @see #getMaximumIntegerDigits
+     */
+    public void setMaximumIntegerDigits(int newValue) {
+        maximumIntegerDigits = Math.max(0,newValue);
+        if (minimumIntegerDigits > maximumIntegerDigits) {
+            minimumIntegerDigits = maximumIntegerDigits;
+        }
+    }
+
+    /**
+     * Returns the minimum number of digits allowed in the integer portion of a
+     * number.
+     *
+     * @return the minimum number of digits
+     * @see #setMinimumIntegerDigits
+     */
+    public int getMinimumIntegerDigits() {
+        return minimumIntegerDigits;
+    }
+
+    /**
+     * Sets the minimum number of digits allowed in the integer portion of a
+     * number. minimumIntegerDigits must be &le; maximumIntegerDigits.  If the
+     * new value for minimumIntegerDigits exceeds the current value
+     * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
+     * the new value
+     *
+     * @param newValue the minimum number of integer digits to be shown; if
+     * less than zero, then zero is used. The concrete subclass may enforce an
+     * upper limit to this value appropriate to the numeric type being formatted.
+     * @see #getMinimumIntegerDigits
+     */
+    public void setMinimumIntegerDigits(int newValue) {
+        minimumIntegerDigits = Math.max(0,newValue);
+        if (minimumIntegerDigits > maximumIntegerDigits) {
+            maximumIntegerDigits = minimumIntegerDigits;
+        }
+    }
+
+    /**
+     * Returns the maximum number of digits allowed in the fraction portion of a
+     * number.
+     *
+     * @return the maximum number of digits.
+     * @see #setMaximumFractionDigits
+     */
+    public int getMaximumFractionDigits() {
+        return maximumFractionDigits;
+    }
+
+    /**
+     * Sets the maximum number of digits allowed in the fraction portion of a
+     * number. maximumFractionDigits must be &ge; minimumFractionDigits.  If the
+     * new value for maximumFractionDigits is less than the current value
+     * of minimumFractionDigits, then minimumFractionDigits will also be set to
+     * the new value.
+     *
+     * @param newValue the maximum number of fraction digits to be shown; if
+     * less than zero, then zero is used. The concrete subclass may enforce an
+     * upper limit to this value appropriate to the numeric type being formatted.
+     * @see #getMaximumFractionDigits
+     */
+    public void setMaximumFractionDigits(int newValue) {
+        maximumFractionDigits = Math.max(0,newValue);
+        if (maximumFractionDigits < minimumFractionDigits) {
+            minimumFractionDigits = maximumFractionDigits;
+        }
+    }
+
+    /**
+     * Returns the minimum number of digits allowed in the fraction portion of a
+     * number.
+     *
+     * @return the minimum number of digits
+     * @see #setMinimumFractionDigits
+     */
+    public int getMinimumFractionDigits() {
+        return minimumFractionDigits;
+    }
+
+    /**
+     * Sets the minimum number of digits allowed in the fraction portion of a
+     * number. minimumFractionDigits must be &le; maximumFractionDigits.  If the
+     * new value for minimumFractionDigits exceeds the current value
+     * of maximumFractionDigits, then maximumIntegerDigits will also be set to
+     * the new value
+     *
+     * @param newValue the minimum number of fraction digits to be shown; if
+     * less than zero, then zero is used. The concrete subclass may enforce an
+     * upper limit to this value appropriate to the numeric type being formatted.
+     * @see #getMinimumFractionDigits
+     */
+    public void setMinimumFractionDigits(int newValue) {
+        minimumFractionDigits = Math.max(0,newValue);
+        if (maximumFractionDigits < minimumFractionDigits) {
+            maximumFractionDigits = minimumFractionDigits;
+        }
+    }
+
+    /**
+     * Gets the currency used by this number format when formatting
+     * currency values. The initial value is derived in a locale dependent
+     * way. The returned value may be null if no valid
+     * currency could be determined and no currency has been set using
+     * {@link #setCurrency(java.util.Currency) setCurrency}.
+     * <p>
+     * The default implementation throws
+     * <code>UnsupportedOperationException</code>.
+     *
+     * @return the currency used by this number format, or <code>null</code>
+     * @exception UnsupportedOperationException if the number format class
+     * doesn't implement currency formatting
+     * @since 1.4
+     */
+    public Currency getCurrency() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Sets the currency used by this number format when formatting
+     * currency values. This does not update the minimum or maximum
+     * number of fraction digits used by the number format.
+     * <p>
+     * The default implementation throws
+     * <code>UnsupportedOperationException</code>.
+     *
+     * @param currency the new currency to be used by this number format
+     * @exception UnsupportedOperationException if the number format class
+     * doesn't implement currency formatting
+     * @exception NullPointerException if <code>currency</code> is null
+     * @since 1.4
+     */
+    public void setCurrency(Currency currency) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
+     * The default implementation of this method in NumberFormat
+     * always throws {@link java.lang.UnsupportedOperationException}.
+     * Subclasses which handle different rounding modes should override
+     * this method.
+     *
+     * @exception UnsupportedOperationException The default implementation
+     *     always throws this exception
+     * @return The <code>RoundingMode</code> used for this NumberFormat.
+     * @see #setRoundingMode(RoundingMode)
+     * @since 1.6
+     */
+    public RoundingMode getRoundingMode() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
+     * The default implementation of this method in NumberFormat always
+     * throws {@link java.lang.UnsupportedOperationException}.
+     * Subclasses which handle different rounding modes should override
+     * this method.
+     *
+     * @exception UnsupportedOperationException The default implementation
+     *     always throws this exception
+     * @exception NullPointerException if <code>roundingMode</code> is null
+     * @param roundingMode The <code>RoundingMode</code> to be used
+     * @see #getRoundingMode()
+     * @since 1.6
+     */
+    public void setRoundingMode(RoundingMode roundingMode) {
+        throw new UnsupportedOperationException();
+    }
+
+    // =======================privates===============================
+
+    private static NumberFormat getInstance(Locale desiredLocale,
+                                           int choice) {
+        // BEGIN Android-changed: Removed use of NumberFormatProvider. Switched to use ICU.
+        /*
+        LocaleProviderAdapter adapter;
+        adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class,
+                                                   desiredLocale);
+        NumberFormat numberFormat = getInstance(adapter, desiredLocale, choice);
+        if (numberFormat == null) {
+            numberFormat = getInstance(LocaleProviderAdapter.forJRE(),
+                                       desiredLocale, choice);
+        */
+        String[] numberPatterns = new String[3];
+        LocaleData data = LocaleData.get(desiredLocale);
+        numberPatterns[NUMBERSTYLE] = data.numberPattern;
+        numberPatterns[CURRENCYSTYLE] = data.currencyPattern;
+        numberPatterns[PERCENTSTYLE] = data.percentPattern;
+
+        // Note: the following lines are from NumberFormatProviderImpl upstream.
+        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
+        int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
+        DecimalFormat numberFormat = new DecimalFormat(numberPatterns[entry], symbols);
+
+        if (choice == INTEGERSTYLE) {
+            numberFormat.setMaximumFractionDigits(0);
+            numberFormat.setDecimalSeparatorAlwaysShown(false);
+            numberFormat.setParseIntegerOnly(true);
+        } else if (choice == CURRENCYSTYLE) {
+            numberFormat.adjustForCurrencyDefaultFractionDigits();
+        }
+        // END Android-changed: Removed use of NumberFormatProvider. Switched to use ICU.
+        return numberFormat;
+    }
+
+    /**
+     * First, read in the default serializable data.
+     *
+     * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
+     * the stream was written by JDK 1.1,
+     * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
+     * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
+     * since the <code>int</code> fields were not present in JDK 1.1.
+     * Finally, set serialVersionOnStream back to the maximum allowed value so that
+     * default serialization will work properly if this object is streamed out again.
+     *
+     * <p>If <code>minimumIntegerDigits</code> is greater than
+     * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
+     * is greater than <code>maximumFractionDigits</code>, then the stream data
+     * is invalid and this method throws an <code>InvalidObjectException</code>.
+     * In addition, if any of these values is negative, then this method throws
+     * an <code>InvalidObjectException</code>.
+     *
+     * @since 1.2
+     */
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+        if (serialVersionOnStream < 1) {
+            // Didn't have additional int fields, reassign to use them.
+            maximumIntegerDigits = maxIntegerDigits;
+            minimumIntegerDigits = minIntegerDigits;
+            maximumFractionDigits = maxFractionDigits;
+            minimumFractionDigits = minFractionDigits;
+        }
+        if (minimumIntegerDigits > maximumIntegerDigits ||
+            minimumFractionDigits > maximumFractionDigits ||
+            minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
+            throw new InvalidObjectException("Digit count range invalid");
+        }
+        serialVersionOnStream = currentSerialVersion;
+    }
+
+    /**
+     * Write out the default serializable data, after first setting
+     * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
+     * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
+     * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
+     * with the JDK 1.1 version of the stream format.
+     *
+     * @since 1.2
+     */
+    private void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
+                           Byte.MAX_VALUE : (byte)maximumIntegerDigits;
+        minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
+                           Byte.MAX_VALUE : (byte)minimumIntegerDigits;
+        maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
+                            Byte.MAX_VALUE : (byte)maximumFractionDigits;
+        minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
+                            Byte.MAX_VALUE : (byte)minimumFractionDigits;
+        stream.defaultWriteObject();
+    }
+
+    // Constants used by factory methods to specify a style of format.
+    private static final int NUMBERSTYLE = 0;
+    private static final int CURRENCYSTYLE = 1;
+    private static final int PERCENTSTYLE = 2;
+    // Android-changed: changed: removed SCIENTIFICSTYLE and pull down INTEGERSTYLE value.
+    //private static final int SCIENTIFICSTYLE = 3;
+    private static final int INTEGERSTYLE = 3;
+
+    /**
+     * True if the grouping (i.e. thousands) separator is used when
+     * formatting and parsing numbers.
+     *
+     * @serial
+     * @see #isGroupingUsed
+     */
+    private boolean groupingUsed = true;
+
+    /**
+     * The maximum number of digits allowed in the integer portion of a
+     * number.  <code>maxIntegerDigits</code> must be greater than or equal to
+     * <code>minIntegerDigits</code>.
+     * <p>
+     * <strong>Note:</strong> This field exists only for serialization
+     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
+     * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
+     * When writing to a stream, <code>maxIntegerDigits</code> is set to
+     * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
+     * whichever is smaller.  When reading from a stream, this field is used
+     * only if <code>serialVersionOnStream</code> is less than 1.
+     *
+     * @serial
+     * @see #getMaximumIntegerDigits
+     */
+    private byte    maxIntegerDigits = 40;
+
+    /**
+     * The minimum number of digits allowed in the integer portion of a
+     * number.  <code>minimumIntegerDigits</code> must be less than or equal to
+     * <code>maximumIntegerDigits</code>.
+     * <p>
+     * <strong>Note:</strong> This field exists only for serialization
+     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
+     * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
+     * When writing to a stream, <code>minIntegerDigits</code> is set to
+     * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
+     * whichever is smaller.  When reading from a stream, this field is used
+     * only if <code>serialVersionOnStream</code> is less than 1.
+     *
+     * @serial
+     * @see #getMinimumIntegerDigits
+     */
+    private byte    minIntegerDigits = 1;
+
+    /**
+     * The maximum number of digits allowed in the fractional portion of a
+     * number.  <code>maximumFractionDigits</code> must be greater than or equal to
+     * <code>minimumFractionDigits</code>.
+     * <p>
+     * <strong>Note:</strong> This field exists only for serialization
+     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
+     * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
+     * When writing to a stream, <code>maxFractionDigits</code> is set to
+     * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
+     * whichever is smaller.  When reading from a stream, this field is used
+     * only if <code>serialVersionOnStream</code> is less than 1.
+     *
+     * @serial
+     * @see #getMaximumFractionDigits
+     */
+    private byte    maxFractionDigits = 3;    // invariant, >= minFractionDigits
+
+    /**
+     * The minimum number of digits allowed in the fractional portion of a
+     * number.  <code>minimumFractionDigits</code> must be less than or equal to
+     * <code>maximumFractionDigits</code>.
+     * <p>
+     * <strong>Note:</strong> This field exists only for serialization
+     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
+     * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
+     * When writing to a stream, <code>minFractionDigits</code> is set to
+     * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
+     * whichever is smaller.  When reading from a stream, this field is used
+     * only if <code>serialVersionOnStream</code> is less than 1.
+     *
+     * @serial
+     * @see #getMinimumFractionDigits
+     */
+    private byte    minFractionDigits = 0;
+
+    /**
+     * True if this format will parse numbers as integers only.
+     *
+     * @serial
+     * @see #isParseIntegerOnly
+     */
+    private boolean parseIntegerOnly = false;
+
+    // new fields for 1.2.  byte is too small for integer digits.
+
+    /**
+     * The maximum number of digits allowed in the integer portion of a
+     * number.  <code>maximumIntegerDigits</code> must be greater than or equal to
+     * <code>minimumIntegerDigits</code>.
+     *
+     * @serial
+     * @since 1.2
+     * @see #getMaximumIntegerDigits
+     */
+    private int    maximumIntegerDigits = 40;
+
+    /**
+     * The minimum number of digits allowed in the integer portion of a
+     * number.  <code>minimumIntegerDigits</code> must be less than or equal to
+     * <code>maximumIntegerDigits</code>.
+     *
+     * @serial
+     * @since 1.2
+     * @see #getMinimumIntegerDigits
+     */
+    private int    minimumIntegerDigits = 1;
+
+    /**
+     * The maximum number of digits allowed in the fractional portion of a
+     * number.  <code>maximumFractionDigits</code> must be greater than or equal to
+     * <code>minimumFractionDigits</code>.
+     *
+     * @serial
+     * @since 1.2
+     * @see #getMaximumFractionDigits
+     */
+    private int    maximumFractionDigits = 3;    // invariant, >= minFractionDigits
+
+    /**
+     * The minimum number of digits allowed in the fractional portion of a
+     * number.  <code>minimumFractionDigits</code> must be less than or equal to
+     * <code>maximumFractionDigits</code>.
+     *
+     * @serial
+     * @since 1.2
+     * @see #getMinimumFractionDigits
+     */
+    private int    minimumFractionDigits = 0;
+
+    static final int currentSerialVersion = 1;
+
+    /**
+     * Describes the version of <code>NumberFormat</code> present on the stream.
+     * Possible values are:
+     * <ul>
+     * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
+     *     In this version, the <code>int</code> fields such as
+     *     <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
+     *     fields such as <code>maxIntegerDigits</code> are used instead.
+     *
+     * <li><b>1</b>: the 1.2 version of the stream format.  The values of the
+     *     <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
+     *     and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
+     *     are used instead.
+     * </ul>
+     * When streaming out a <code>NumberFormat</code>, the most recent format
+     * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
+     * is always written.
+     *
+     * @serial
+     * @since 1.2
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+
+    // Removed "implements Cloneable" clause.  Needs to update serialization
+    // ID for backward compatibility.
+    static final long serialVersionUID = -2308460125733713944L;
+
+
+    //
+    // class for AttributedCharacterIterator attributes
+    //
+    /**
+     * Defines constants that are used as attribute keys in the
+     * <code>AttributedCharacterIterator</code> returned
+     * from <code>NumberFormat.formatToCharacterIterator</code> and as
+     * field identifiers in <code>FieldPosition</code>.
+     *
+     * @since 1.4
+     */
+    public static class Field extends Format.Field {
+
+        // Proclaim serial compatibility with 1.4 FCS
+        private static final long serialVersionUID = 7494728892700160890L;
+
+        // table of all instances in this class, used by readResolve
+        private static final Map<String, Field> instanceMap = new HashMap<>(11);
+
+        /**
+         * Creates a Field instance with the specified
+         * name.
+         *
+         * @param name Name of the attribute
+         */
+        protected Field(String name) {
+            super(name);
+            if (this.getClass() == NumberFormat.Field.class) {
+                instanceMap.put(name, this);
+            }
+        }
+
+        /**
+         * Resolves instances being deserialized to the predefined constants.
+         *
+         * @throws InvalidObjectException if the constant could not be resolved.
+         * @return resolved NumberFormat.Field constant
+         */
+        @Override
+        protected Object readResolve() throws InvalidObjectException {
+            if (this.getClass() != NumberFormat.Field.class) {
+                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
+            }
+
+            Object instance = instanceMap.get(getName());
+            if (instance != null) {
+                return instance;
+            } else {
+                throw new InvalidObjectException("unknown attribute name");
+            }
+        }
+
+        /**
+         * Constant identifying the integer field.
+         */
+        public static final Field INTEGER = new Field("integer");
+
+        /**
+         * Constant identifying the fraction field.
+         */
+        public static final Field FRACTION = new Field("fraction");
+
+        /**
+         * Constant identifying the exponent field.
+         */
+        public static final Field EXPONENT = new Field("exponent");
+
+        /**
+         * Constant identifying the decimal separator field.
+         */
+        public static final Field DECIMAL_SEPARATOR =
+                            new Field("decimal separator");
+
+        /**
+         * Constant identifying the sign field.
+         */
+        public static final Field SIGN = new Field("sign");
+
+        /**
+         * Constant identifying the grouping separator field.
+         */
+        public static final Field GROUPING_SEPARATOR =
+                            new Field("grouping separator");
+
+        /**
+         * Constant identifying the exponent symbol field.
+         */
+        public static final Field EXPONENT_SYMBOL = new
+                            Field("exponent symbol");
+
+        /**
+         * Constant identifying the percent field.
+         */
+        public static final Field PERCENT = new Field("percent");
+
+        /**
+         * Constant identifying the permille field.
+         */
+        public static final Field PERMILLE = new Field("per mille");
+
+        /**
+         * Constant identifying the currency field.
+         */
+        public static final Field CURRENCY = new Field("currency");
+
+        /**
+         * Constant identifying the exponent sign field.
+         */
+        public static final Field EXPONENT_SIGN = new Field("exponent sign");
+    }
+}
diff --git a/java/text/ParseException.java b/java/text/ParseException.java
new file mode 100644
index 0000000..f9ad001
--- /dev/null
+++ b/java/text/ParseException.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+/**
+ * Signals that an error has been reached unexpectedly
+ * while parsing.
+ * @see java.lang.Exception
+ * @see java.text.Format
+ * @see java.text.FieldPosition
+ * @author      Mark Davis
+ */
+public
+class ParseException extends Exception {
+
+    private static final long serialVersionUID = 2703218443322787634L;
+
+    /**
+     * Constructs a ParseException with the specified detail message and
+     * offset.
+     * A detail message is a String that describes this particular exception.
+     *
+     * @param s the detail message
+     * @param errorOffset the position where the error is found while parsing.
+     */
+    public ParseException(String s, int errorOffset) {
+        super(s);
+        this.errorOffset = errorOffset;
+    }
+
+    /**
+     * Returns the position where the error was found.
+     *
+     * @return the position where the error was found
+     */
+    public int getErrorOffset () {
+        return errorOffset;
+    }
+
+    //============ privates ============
+    /**
+     * The zero-based character offset into the string being parsed at which
+     * the error was found during parsing.
+     * @serial
+     */
+    private int errorOffset;
+}
diff --git a/java/text/ParsePosition.java b/java/text/ParsePosition.java
new file mode 100644
index 0000000..be3ffce
--- /dev/null
+++ b/java/text/ParsePosition.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+
+/**
+ * <code>ParsePosition</code> is a simple class used by <code>Format</code>
+ * and its subclasses to keep track of the current position during parsing.
+ * The <code>parseObject</code> method in the various <code>Format</code>
+ * classes requires a <code>ParsePosition</code> object as an argument.
+ *
+ * <p>
+ * By design, as you parse through a string with different formats,
+ * you can use the same <code>ParsePosition</code>, since the index parameter
+ * records the current position.
+ *
+ * @author      Mark Davis
+ * @see         java.text.Format
+ */
+
+public class ParsePosition {
+
+    /**
+     * Input: the place you start parsing.
+     * <br>Output: position where the parse stopped.
+     * This is designed to be used serially,
+     * with each call setting index up for the next one.
+     */
+    int index = 0;
+    int errorIndex = -1;
+
+    /**
+     * Retrieve the current parse position.  On input to a parse method, this
+     * is the index of the character at which parsing will begin; on output, it
+     * is the index of the character following the last character parsed.
+     *
+     * @return the current parse position
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Set the current parse position.
+     *
+     * @param index the current parse position
+     */
+    public void setIndex(int index) {
+        this.index = index;
+    }
+
+    /**
+     * Create a new ParsePosition with the given initial index.
+     *
+     * @param index initial index
+     */
+    public ParsePosition(int index) {
+        this.index = index;
+    }
+    /**
+     * Set the index at which a parse error occurred.  Formatters
+     * should set this before returning an error code from their
+     * parseObject method.  The default value is -1 if this is not set.
+     *
+     * @param ei the index at which an error occurred
+     * @since 1.2
+     */
+    public void setErrorIndex(int ei)
+    {
+        errorIndex = ei;
+    }
+
+    /**
+     * Retrieve the index at which an error occurred, or -1 if the
+     * error index has not been set.
+     *
+     * @return the index at which an error occurred
+     * @since 1.2
+     */
+    public int getErrorIndex()
+    {
+        return errorIndex;
+    }
+
+    /**
+     * Overrides equals
+     */
+    public boolean equals(Object obj)
+    {
+        if (obj == null) return false;
+        if (!(obj instanceof ParsePosition))
+            return false;
+        ParsePosition other = (ParsePosition) obj;
+        return (index == other.index && errorIndex == other.errorIndex);
+    }
+
+    /**
+     * Returns a hash code for this ParsePosition.
+     * @return a hash code value for this object
+     */
+    public int hashCode() {
+        return (errorIndex << 16) | index;
+    }
+
+    /**
+     * Return a string representation of this ParsePosition.
+     * @return  a string representation of this object
+     */
+    public String toString() {
+        return getClass().getName() +
+            "[index=" + index +
+            ",errorIndex=" + errorIndex + ']';
+    }
+}
diff --git a/java/text/PatternEntry.java b/java/text/PatternEntry.java
new file mode 100644
index 0000000..07af4b8
--- /dev/null
+++ b/java/text/PatternEntry.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import java.lang.Character;
+
+/**
+ * Utility class for normalizing and merging patterns for collation.
+ * This is to be used with MergeCollation for adding patterns to an
+ * existing rule table.
+ * @see        MergeCollation
+ * @author     Mark Davis, Helena Shih
+ */
+
+class PatternEntry {
+    /**
+     * Gets the current extension, quoted
+     */
+    public void appendQuotedExtension(StringBuffer toAddTo) {
+        appendQuoted(extension,toAddTo);
+    }
+
+    /**
+     * Gets the current chars, quoted
+     */
+    public void appendQuotedChars(StringBuffer toAddTo) {
+        appendQuoted(chars,toAddTo);
+    }
+
+    /**
+     * WARNING this is used for searching in a Vector.
+     * Because Vector.indexOf doesn't take a comparator,
+     * this method is ill-defined and ignores strength.
+     */
+    public boolean equals(Object obj) {
+        if (obj == null) return false;
+        PatternEntry other = (PatternEntry) obj;
+        boolean result = chars.equals(other.chars);
+        return result;
+    }
+
+    public int hashCode() {
+        return chars.hashCode();
+    }
+
+    /**
+     * For debugging.
+     */
+    public String toString() {
+        StringBuffer result = new StringBuffer();
+        addToBuffer(result, true, false, null);
+        return result.toString();
+    }
+
+    /**
+     * Gets the strength of the entry.
+     */
+    final int getStrength() {
+        return strength;
+    }
+
+    /**
+     * Gets the expanding characters of the entry.
+     */
+    final String getExtension() {
+        return extension;
+    }
+
+    /**
+     * Gets the core characters of the entry.
+     */
+    final String getChars() {
+        return chars;
+    }
+
+    // ===== privates =====
+
+    void addToBuffer(StringBuffer toAddTo,
+                     boolean showExtension,
+                     boolean showWhiteSpace,
+                     PatternEntry lastEntry)
+    {
+        if (showWhiteSpace && toAddTo.length() > 0)
+            if (strength == Collator.PRIMARY || lastEntry != null)
+                toAddTo.append('\n');
+            else
+                toAddTo.append(' ');
+        if (lastEntry != null) {
+            toAddTo.append('&');
+            if (showWhiteSpace)
+                toAddTo.append(' ');
+            lastEntry.appendQuotedChars(toAddTo);
+            appendQuotedExtension(toAddTo);
+            if (showWhiteSpace)
+                toAddTo.append(' ');
+        }
+        switch (strength) {
+        case Collator.IDENTICAL: toAddTo.append('='); break;
+        case Collator.TERTIARY:  toAddTo.append(','); break;
+        case Collator.SECONDARY: toAddTo.append(';'); break;
+        case Collator.PRIMARY:   toAddTo.append('<'); break;
+        case RESET: toAddTo.append('&'); break;
+        case UNSET: toAddTo.append('?'); break;
+        }
+        if (showWhiteSpace)
+            toAddTo.append(' ');
+        appendQuoted(chars,toAddTo);
+        if (showExtension && extension.length() != 0) {
+            toAddTo.append('/');
+            appendQuoted(extension,toAddTo);
+        }
+    }
+
+    static void appendQuoted(String chars, StringBuffer toAddTo) {
+        boolean inQuote = false;
+        char ch = chars.charAt(0);
+        if (Character.isSpaceChar(ch)) {
+            inQuote = true;
+            toAddTo.append('\'');
+        } else {
+          if (PatternEntry.isSpecialChar(ch)) {
+                inQuote = true;
+                toAddTo.append('\'');
+            } else {
+                switch (ch) {
+                    case 0x0010: case '\f': case '\r':
+                    case '\t': case '\n':  case '@':
+                    inQuote = true;
+                    toAddTo.append('\'');
+                    break;
+                case '\'':
+                    inQuote = true;
+                    toAddTo.append('\'');
+                    break;
+                default:
+                    if (inQuote) {
+                        inQuote = false; toAddTo.append('\'');
+                    }
+                    break;
+                }
+           }
+        }
+        toAddTo.append(chars);
+        if (inQuote)
+            toAddTo.append('\'');
+    }
+
+    //========================================================================
+    // Parsing a pattern into a list of PatternEntries....
+    //========================================================================
+
+    PatternEntry(int strength,
+                 StringBuffer chars,
+                 StringBuffer extension)
+    {
+        this.strength = strength;
+        this.chars = chars.toString();
+        this.extension = (extension.length() > 0) ? extension.toString()
+                                                  : "";
+    }
+
+    static class Parser {
+        private String pattern;
+        private int i;
+
+        public Parser(String pattern) {
+            this.pattern = pattern;
+            this.i = 0;
+        }
+
+        public PatternEntry next() throws ParseException {
+            int newStrength = UNSET;
+
+            newChars.setLength(0);
+            newExtension.setLength(0);
+
+            boolean inChars = true;
+            boolean inQuote = false;
+        mainLoop:
+            while (i < pattern.length()) {
+                char ch = pattern.charAt(i);
+                if (inQuote) {
+                    if (ch == '\'') {
+                        inQuote = false;
+                    } else {
+                        if (newChars.length() == 0) newChars.append(ch);
+                        else if (inChars) newChars.append(ch);
+                        else newExtension.append(ch);
+                    }
+                } else switch (ch) {
+                case '=': if (newStrength != UNSET) break mainLoop;
+                    newStrength = Collator.IDENTICAL; break;
+                case ',': if (newStrength != UNSET) break mainLoop;
+                    newStrength = Collator.TERTIARY; break;
+                case ';': if (newStrength != UNSET) break mainLoop;
+                    newStrength = Collator.SECONDARY; break;
+                case '<': if (newStrength != UNSET) break mainLoop;
+                    newStrength = Collator.PRIMARY; break;
+                case '&': if (newStrength != UNSET) break mainLoop;
+                    newStrength = RESET; break;
+                case '\t':
+                case '\n':
+                case '\f':
+                case '\r':
+                case ' ': break; // skip whitespace TODO use Character
+                case '/': inChars = false; break;
+                case '\'':
+                    inQuote = true;
+                    ch = pattern.charAt(++i);
+                    if (newChars.length() == 0) newChars.append(ch);
+                    else if (inChars) newChars.append(ch);
+                    else newExtension.append(ch);
+                    break;
+                default:
+                    if (newStrength == UNSET) {
+                        throw new ParseException
+                            ("missing char (=,;<&) : " +
+                             pattern.substring(i,
+                                (i+10 < pattern.length()) ?
+                                 i+10 : pattern.length()),
+                             i);
+                    }
+                    if (PatternEntry.isSpecialChar(ch) && (inQuote == false))
+                        throw new ParseException
+                            ("Unquoted punctuation character : " + Integer.toString(ch, 16), i);
+                    if (inChars) {
+                        newChars.append(ch);
+                    } else {
+                        newExtension.append(ch);
+                    }
+                    break;
+                }
+                i++;
+            }
+            if (newStrength == UNSET)
+                return null;
+            if (newChars.length() == 0) {
+                throw new ParseException
+                    ("missing chars (=,;<&): " +
+                      pattern.substring(i,
+                          (i+10 < pattern.length()) ?
+                           i+10 : pattern.length()),
+                     i);
+            }
+
+            return new PatternEntry(newStrength, newChars, newExtension);
+        }
+
+        // We re-use these objects in order to improve performance
+        private StringBuffer newChars = new StringBuffer();
+        private StringBuffer newExtension = new StringBuffer();
+
+    }
+
+    static boolean isSpecialChar(char ch) {
+        return ((ch == '\u0020') ||
+                ((ch <= '\u002F') && (ch >= '\u0022')) ||
+                ((ch <= '\u003F') && (ch >= '\u003A')) ||
+                ((ch <= '\u0060') && (ch >= '\u005B')) ||
+                ((ch <= '\u007E') && (ch >= '\u007B')));
+    }
+
+
+    static final int RESET = -2;
+    static final int UNSET = -1;
+
+    int strength = UNSET;
+    String chars = "";
+    String extension = "";
+}
diff --git a/java/text/RuleBasedCollator.java b/java/text/RuleBasedCollator.java
new file mode 100644
index 0000000..a3234c8
--- /dev/null
+++ b/java/text/RuleBasedCollator.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import libcore.icu.CollationKeyICU;
+
+/**
+ * The <code>RuleBasedCollator</code> class is a concrete subclass of
+ * <code>Collator</code> that provides a simple, data-driven, table
+ * collator.  With this class you can create a customized table-based
+ * <code>Collator</code>.  <code>RuleBasedCollator</code> maps
+ * characters to sort keys.
+ *
+ * <p>
+ * <code>RuleBasedCollator</code> has the following restrictions
+ * for efficiency (other subclasses may be used for more complex languages) :
+ * <ol>
+ * <li>If a special collation rule controlled by a &lt;modifier&gt; is
+      specified it applies to the whole collator object.
+ * <li>All non-mentioned characters are at the end of the
+ *     collation order.
+ * </ol>
+ *
+ * <p>
+ * The collation table is composed of a list of collation rules, where each
+ * rule is of one of three forms:
+ * <pre>
+ *    &lt;modifier&gt;
+ *    &lt;relation&gt; &lt;text-argument&gt;
+ *    &lt;reset&gt; &lt;text-argument&gt;
+ * </pre>
+ * The definitions of the rule elements is as follows:
+ * <UL>
+ *    <LI><strong>Text-Argument</strong>: A text-argument is any sequence of
+ *        characters, excluding special characters (that is, common
+ *        whitespace characters [0009-000D, 0020] and rule syntax characters
+ *        [0021-002F, 003A-0040, 005B-0060, 007B-007E]). If those
+ *        characters are desired, you can put them in single quotes
+ *        (e.g. ampersand =&gt; '&amp;'). Note that unquoted white space characters
+ *        are ignored; e.g. <code>b c</code> is treated as <code>bc</code>.
+ *    <LI><strong>Modifier</strong>: There are currently two modifiers that
+ *        turn on special collation rules.
+ *        <UL>
+ *            <LI>'@' : Turns on backwards sorting of accents (secondary
+ *                      differences), as in French.
+ *            <LI>'!' : Turns on Thai/Lao vowel-consonant swapping.  If this
+ *                      rule is in force when a Thai vowel of the range
+ *                      &#92;U0E40-&#92;U0E44 precedes a Thai consonant of the range
+ *                      &#92;U0E01-&#92;U0E2E OR a Lao vowel of the range &#92;U0EC0-&#92;U0EC4
+ *                      precedes a Lao consonant of the range &#92;U0E81-&#92;U0EAE then
+ *                      the vowel is placed after the consonant for collation
+ *                      purposes.
+ *        </UL>
+ *        <p>'@' : Indicates that accents are sorted backwards, as in French.
+ *    <LI><strong>Relation</strong>: The relations are the following:
+ *        <UL>
+ *            <LI>'&lt;' : Greater, as a letter difference (primary)
+ *            <LI>';' : Greater, as an accent difference (secondary)
+ *            <LI>',' : Greater, as a case difference (tertiary)
+ *            <LI>'=' : Equal
+ *        </UL>
+ *    <LI><strong>Reset</strong>: There is a single reset
+ *        which is used primarily for contractions and expansions, but which
+ *        can also be used to add a modification at the end of a set of rules.
+ *        <p>'&amp;' : Indicates that the next rule follows the position to where
+ *            the reset text-argument would be sorted.
+ * </UL>
+ *
+ * <p>
+ * This sounds more complicated than it is in practice. For example, the
+ * following are equivalent ways of expressing the same thing:
+ * <blockquote>
+ * <pre>
+ * a &lt; b &lt; c
+ * a &lt; b &amp; b &lt; c
+ * a &lt; c &amp; a &lt; b
+ * </pre>
+ * </blockquote>
+ * Notice that the order is important, as the subsequent item goes immediately
+ * after the text-argument. The following are not equivalent:
+ * <blockquote>
+ * <pre>
+ * a &lt; b &amp; a &lt; c
+ * a &lt; c &amp; a &lt; b
+ * </pre>
+ * </blockquote>
+ * Either the text-argument must already be present in the sequence, or some
+ * initial substring of the text-argument must be present. (e.g. "a &lt; b &amp; ae &lt;
+ * e" is valid since "a" is present in the sequence before "ae" is reset). In
+ * this latter case, "ae" is not entered and treated as a single character;
+ * instead, "e" is sorted as if it were expanded to two characters: "a"
+ * followed by an "e". This difference appears in natural languages: in
+ * traditional Spanish "ch" is treated as though it contracts to a single
+ * character (expressed as "c &lt; ch &lt; d"), while in traditional German
+ * a-umlaut is treated as though it expanded to two characters
+ * (expressed as "a,A &lt; b,B ... &amp;ae;&#92;u00e3&amp;AE;&#92;u00c3").
+ * [&#92;u00e3 and &#92;u00c3 are, of course, the escape sequences for a-umlaut.]
+ * <p>
+ * <strong>Ignorable Characters</strong>
+ * <p>
+ * For ignorable characters, the first rule must start with a relation (the
+ * examples we have used above are really fragments; "a &lt; b" really should be
+ * "&lt; a &lt; b"). If, however, the first relation is not "&lt;", then all the all
+ * text-arguments up to the first "&lt;" are ignorable. For example, ", - &lt; a &lt; b"
+ * makes "-" an ignorable character, as we saw earlier in the word
+ * "black-birds". In the samples for different languages, you see that most
+ * accents are ignorable.
+ *
+ * <p><strong>Normalization and Accents</strong>
+ * <p>
+ * <code>RuleBasedCollator</code> automatically processes its rule table to
+ * include both pre-composed and combining-character versions of
+ * accented characters.  Even if the provided rule string contains only
+ * base characters and separate combining accent characters, the pre-composed
+ * accented characters matching all canonical combinations of characters from
+ * the rule string will be entered in the table.
+ * <p>
+ * This allows you to use a RuleBasedCollator to compare accented strings
+ * even when the collator is set to NO_DECOMPOSITION.  There are two caveats,
+ * however.  First, if the strings to be collated contain combining
+ * sequences that may not be in canonical order, you should set the collator to
+ * CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION to enable sorting of
+ * combining sequences.  Second, if the strings contain characters with
+ * compatibility decompositions (such as full-width and half-width forms),
+ * you must use FULL_DECOMPOSITION, since the rule tables only include
+ * canonical mappings.
+ *
+ * <p><strong>Errors</strong>
+ * <p>
+ * The following are errors:
+ * <UL>
+ *     <LI>A text-argument contains unquoted punctuation symbols
+ *        (e.g. "a &lt; b-c &lt; d").
+ *     <LI>A relation or reset character not followed by a text-argument
+ *        (e.g. "a &lt; ,b").
+ *     <LI>A reset where the text-argument (or an initial substring of the
+ *         text-argument) is not already in the sequence.
+ *         (e.g. "a &lt; b &amp; e &lt; f")
+ * </UL>
+ * If you produce one of these errors, a <code>RuleBasedCollator</code> throws
+ * a <code>ParseException</code>.
+ *
+ * <p><strong>Examples</strong>
+ * <p>Simple:     "&lt; a &lt; b &lt; c &lt; d"
+ * <p>Norwegian:  "&lt; a, A &lt; b, B &lt; c, C &lt; d, D &lt; e, E &lt; f, F
+ *                 &lt; g, G &lt; h, H &lt; i, I &lt; j, J &lt; k, K &lt; l, L
+ *                 &lt; m, M &lt; n, N &lt; o, O &lt; p, P &lt; q, Q &lt; r, R
+ *                 &lt; s, S &lt; t, T &lt; u, U &lt; v, V &lt; w, W &lt; x, X
+ *                 &lt; y, Y &lt; z, Z
+ *                 &lt; &#92;u00E6, &#92;u00C6
+ *                 &lt; &#92;u00F8, &#92;u00D8
+ *                 &lt; &#92;u00E5 = a&#92;u030A, &#92;u00C5 = A&#92;u030A;
+ *                      aa, AA"
+ *
+ * <p>
+ * To create a <code>RuleBasedCollator</code> object with specialized
+ * rules tailored to your needs, you construct the <code>RuleBasedCollator</code>
+ * with the rules contained in a <code>String</code> object. For example:
+ * <blockquote>
+ * <pre>
+ * String simple = "&lt; a&lt; b&lt; c&lt; d";
+ * RuleBasedCollator mySimple = new RuleBasedCollator(simple);
+ * </pre>
+ * </blockquote>
+ * Or:
+ * <blockquote>
+ * <pre>
+ * String Norwegian = "&lt; a, A &lt; b, B &lt; c, C &lt; d, D &lt; e, E &lt; f, F &lt; g, G &lt; h, H &lt; i, I" +
+ *                    "&lt; j, J &lt; k, K &lt; l, L &lt; m, M &lt; n, N &lt; o, O &lt; p, P &lt; q, Q &lt; r, R" +
+ *                    "&lt; s, S &lt; t, T &lt; u, U &lt; v, V &lt; w, W &lt; x, X &lt; y, Y &lt; z, Z" +
+ *                    "&lt; &#92;u00E6, &#92;u00C6" +     // Latin letter ae &amp; AE
+ *                    "&lt; &#92;u00F8, &#92;u00D8" +     // Latin letter o &amp; O with stroke
+ *                    "&lt; &#92;u00E5 = a&#92;u030A," +  // Latin letter a with ring above
+ *                    "  &#92;u00C5 = A&#92;u030A;" +  // Latin letter A with ring above
+ *                    "  aa, AA";
+ * RuleBasedCollator myNorwegian = new RuleBasedCollator(Norwegian);
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * A new collation rules string can be created by concatenating rules
+ * strings. For example, the rules returned by {@link #getRules()} could
+ * be concatenated to combine multiple <code>RuleBasedCollator</code>s.
+ *
+ * <p>
+ * The following example demonstrates how to change the order of
+ * non-spacing accents,
+ * <blockquote>
+ * <pre>
+ * // old rule
+ * String oldRules = "=&#92;u0301;&#92;u0300;&#92;u0302;&#92;u0308"    // main accents
+ *                 + ";&#92;u0327;&#92;u0303;&#92;u0304;&#92;u0305"    // main accents
+ *                 + ";&#92;u0306;&#92;u0307;&#92;u0309;&#92;u030A"    // main accents
+ *                 + ";&#92;u030B;&#92;u030C;&#92;u030D;&#92;u030E"    // main accents
+ *                 + ";&#92;u030F;&#92;u0310;&#92;u0311;&#92;u0312"    // main accents
+ *                 + "&lt; a , A ; ae, AE ; &#92;u00e6 , &#92;u00c6"
+ *                 + "&lt; b , B &lt; c, C &lt; e, E &amp; C &lt; d, D";
+ * // change the order of accent characters
+ * String addOn = "&amp; &#92;u0300 ; &#92;u0308 ; &#92;u0302";
+ * RuleBasedCollator myCollator = new RuleBasedCollator(oldRules + addOn);
+ * </pre>
+ * </blockquote>
+ *
+ * @see        Collator
+ * @see        CollationElementIterator
+ * @author     Helena Shih, Laura Werner, Richard Gillam
+ */
+public class RuleBasedCollator extends Collator{
+    // Android-added: protected constructor taking an ICU RuleBasedCollator.
+    RuleBasedCollator(android.icu.text.RuleBasedCollator wrapper) {
+        super(wrapper);
+    }
+
+    // IMPLEMENTATION NOTES:  The implementation of the collation algorithm is
+    // divided across three classes: RuleBasedCollator, RBCollationTables, and
+    // CollationElementIterator.  RuleBasedCollator contains the collator's
+    // transient state and includes the code that uses the other classes to
+    // implement comparison and sort-key building.  RuleBasedCollator also
+    // contains the logic to handle French secondary accent sorting.
+    // A RuleBasedCollator has two CollationElementIterators.  State doesn't
+    // need to be preserved in these objects between calls to compare() or
+    // getCollationKey(), but the objects persist anyway to avoid wasting extra
+    // creation time.  compare() and getCollationKey() are synchronized to ensure
+    // thread safety with this scheme.  The CollationElementIterator is responsible
+    // for generating collation elements from strings and returning one element at
+    // a time (sometimes there's a one-to-many or many-to-one mapping between
+    // characters and collation elements-- this class handles that).
+    // CollationElementIterator depends on RBCollationTables, which contains the
+    // collator's static state.  RBCollationTables contains the actual data
+    // tables specifying the collation order of characters for a particular locale
+    // or use.  It also contains the base logic that CollationElementIterator
+    // uses to map from characters to collation elements.  A single RBCollationTables
+    // object is shared among all RuleBasedCollators for the same locale, and
+    // thus by all the CollationElementIterators they create.
+
+    /**
+     * RuleBasedCollator constructor.  This takes the table rules and builds
+     * a collation table out of them.  Please see RuleBasedCollator class
+     * description for more details on the collation rule syntax.
+     * @see java.util.Locale
+     * @param rules the collation rules to build the collation table from.
+     * @exception ParseException A format exception
+     * will be thrown if the build process of the rules fails. For
+     * example, build rule "a &lt; ? &lt; d" will cause the constructor to
+     * throw the ParseException because the '?' is not quoted.
+     */
+    public RuleBasedCollator(String rules) throws ParseException {
+        // BEGIN Android-changed: Switched to ICU.
+        if (rules == null) {
+            throw new NullPointerException("rules == null");
+        }
+        try {
+            icuColl = new android.icu.text.RuleBasedCollator(rules);
+        } catch (Exception e) {
+            if (e instanceof ParseException) {
+                throw (ParseException) e;
+            }
+            /*
+             * -1 means it's not a ParseException. Maybe IOException thrown when
+             * an error occurred while reading internal data.
+             */
+            throw new ParseException(e.getMessage(), -1);
+        }
+        // END Android-changed: Switched to ICU.
+    }
+
+    // Android-removed: (String rules, int decomp) constructor and copy constructor.
+
+    // Android-changed: document that getRules() won't return rules in common case.
+    /**
+     * Gets the table-based rules for the collation object.
+     *
+     * <p>On Android, the returned string will be empty unless this instance was
+     * constructed using {@link #RuleBasedCollator(String)}.
+     *
+     * @return returns the collation rules that the table collation object
+     * was created from.
+     */
+    public String getRules()
+    {
+        // Android-changed: Switched to ICU.
+        return collAsICU().getRules();
+    }
+
+    /**
+     * Returns a CollationElementIterator for the given String.
+     *
+     * @param source the string to be collated
+     * @return a {@code CollationElementIterator} object
+     * @see java.text.CollationElementIterator
+     */
+    public CollationElementIterator getCollationElementIterator(String source) {
+        // Android-changed: Switch to ICU and check for null value.
+        if (source == null) {
+            throw new NullPointerException("source == null");
+        }
+        return new CollationElementIterator(collAsICU().getCollationElementIterator(source));
+    }
+
+    /**
+     * Returns a CollationElementIterator for the given CharacterIterator.
+     *
+     * @param source the character iterator to be collated
+     * @return a {@code CollationElementIterator} object
+     * @see java.text.CollationElementIterator
+     * @since 1.2
+     */
+    public CollationElementIterator getCollationElementIterator(
+                                                CharacterIterator source) {
+        // Android-changed: Switch to ICU and check for null value.
+       if (source == null) {
+            throw new NullPointerException("source == null");
+        }
+        return new CollationElementIterator(collAsICU().getCollationElementIterator(source));
+    }
+
+    /**
+     * Compares the character data stored in two different strings based on the
+     * collation rules.  Returns information about whether a string is less
+     * than, greater than or equal to another string in a language.
+     * This can be overriden in a subclass.
+     *
+     * @exception NullPointerException if <code>source</code> or <code>target</code> is null.
+     */
+    public synchronized int compare(String source, String target)
+    {
+        if (source == null || target == null) {
+            throw new NullPointerException();
+        }
+        // Android-changed: Switched to ICU.
+        return icuColl.compare(source, target);
+    }
+
+    /**
+     * Transforms the string into a series of characters that can be compared
+     * with CollationKey.compareTo. This overrides java.text.Collator.getCollationKey.
+     * It can be overriden in a subclass.
+     */
+    public synchronized CollationKey getCollationKey(String source)
+    {
+        // Android-changed: Switched to ICU.
+        if (source == null) {
+            return null;
+        }
+        return new CollationKeyICU(source, icuColl.getCollationKey(source));
+    }
+
+    /**
+     * Standard override; no change in semantics.
+     */
+    public Object clone() {
+        // Android-changed: remove special case for cloning.
+        return super.clone();
+    }
+
+    /**
+     * Compares the equality of two collation objects.
+     * @param obj the table-based collation object to be compared with this.
+     * @return true if the current table-based collation object is the same
+     * as the table-based collation object obj; false otherwise.
+     */
+    public boolean equals(Object obj) {
+        if (obj == null) return false;
+        // Android-changed: delegate to super class, as that already compares icuColl.
+        return super.equals(obj);
+    }
+
+    /**
+     * Generates the hash code for the table-based collation object
+     */
+    public int hashCode() {
+        // Android-changed: Switched to ICU.
+        return icuColl.hashCode();
+    }
+
+    // Android-added: collAsIcu helper method.
+    private android.icu.text.RuleBasedCollator collAsICU() {
+        return (android.icu.text.RuleBasedCollator) icuColl;
+    }
+
+    // Android-removed: private constants and fields.
+}
diff --git a/java/text/SimpleDateFormat.java b/java/text/SimpleDateFormat.java
new file mode 100644
index 0000000..ca5a504
--- /dev/null
+++ b/java/text/SimpleDateFormat.java
@@ -0,0 +1,3063 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+import android.icu.text.TimeZoneFormat;
+import android.icu.text.TimeZoneNames;
+import android.icu.util.ULocale;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.GregorianCalendar;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.SimpleTimeZone;
+import java.util.SortedMap;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import libcore.icu.LocaleData;
+
+import sun.util.calendar.CalendarUtils;
+
+import static java.text.DateFormatSymbols.*;
+
+// Android-changed: Added supported API level, removed unnecessary <br>
+// Android-changed: Clarified info about X symbol time zone parsing
+/**
+ * <code>SimpleDateFormat</code> is a concrete class for formatting and
+ * parsing dates in a locale-sensitive manner. It allows for formatting
+ * (date &rarr; text), parsing (text &rarr; date), and normalization.
+ *
+ * <p>
+ * <code>SimpleDateFormat</code> allows you to start by choosing
+ * any user-defined patterns for date-time formatting. However, you
+ * are encouraged to create a date-time formatter with either
+ * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
+ * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
+ * of these class methods can return a date/time formatter initialized
+ * with a default format pattern. You may modify the format pattern
+ * using the <code>applyPattern</code> methods as desired.
+ * For more information on using these methods, see
+ * {@link DateFormat}.
+ *
+ * <h3>Date and Time Patterns</h3>
+ * <p>
+ * Date and time formats are specified by <em>date and time pattern</em>
+ * strings.
+ * Within date and time pattern strings, unquoted letters from
+ * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
+ * <code>'z'</code> are interpreted as pattern letters representing the
+ * components of a date or time string.
+ * Text can be quoted using single quotes (<code>'</code>) to avoid
+ * interpretation.
+ * <code>"''"</code> represents a single quote.
+ * All other characters are not interpreted; they're simply copied into the
+ * output string during formatting or matched against the input string
+ * during parsing.
+ * <p>
+ * The following pattern letters are defined (all other characters from
+ * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
+ * <code>'z'</code> are reserved):
+ * <blockquote>
+ * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
+ *     <tr style="background-color: rgb(204, 204, 255);">
+ *         <th align=left>Letter
+ *         <th align=left>Date or Time Component
+ *         <th align=left>Presentation
+ *         <th align=left>Examples
+ *         <th align=left>Supported (API Levels)
+ *     <tr>
+ *         <td><code>G</code>
+ *         <td>Era designator
+ *         <td><a href="#text">Text</a>
+ *         <td><code>AD</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>y</code>
+ *         <td>Year
+ *         <td><a href="#year">Year</a>
+ *         <td><code>1996</code>; <code>96</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>Y</code>
+ *         <td>Week year
+ *         <td><a href="#year">Year</a>
+ *         <td><code>2009</code>; <code>09</code>
+ *         <td>24+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>M</code>
+ *         <td>Month in year (context sensitive)
+ *         <td><a href="#month">Month</a>
+ *         <td><code>July</code>; <code>Jul</code>; <code>07</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>L</code>
+ *         <td>Month in year (standalone form)
+ *         <td><a href="#month">Month</a>
+ *         <td><code>July</code>; <code>Jul</code>; <code>07</code>
+ *         <td>TBD</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>w</code>
+ *         <td>Week in year
+ *         <td><a href="#number">Number</a>
+ *         <td><code>27</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>W</code>
+ *         <td>Week in month
+ *         <td><a href="#number">Number</a>
+ *         <td><code>2</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>D</code>
+ *         <td>Day in year
+ *         <td><a href="#number">Number</a>
+ *         <td><code>189</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>d</code>
+ *         <td>Day in month
+ *         <td><a href="#number">Number</a>
+ *         <td><code>10</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>F</code>
+ *         <td>Day of week in month
+ *         <td><a href="#number">Number</a>
+ *         <td><code>2</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>E</code>
+ *         <td>Day name in week
+ *         <td><a href="#text">Text</a>
+ *         <td><code>Tuesday</code>; <code>Tue</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>u</code>
+ *         <td>Day number of week (1 = Monday, ..., 7 = Sunday)
+ *         <td><a href="#number">Number</a>
+ *         <td><code>1</code>
+ *         <td>24+</td>
+ *     <tr>
+ *         <td><code>a</code>
+ *         <td>Am/pm marker
+ *         <td><a href="#text">Text</a>
+ *         <td><code>PM</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>H</code>
+ *         <td>Hour in day (0-23)
+ *         <td><a href="#number">Number</a>
+ *         <td><code>0</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>k</code>
+ *         <td>Hour in day (1-24)
+ *         <td><a href="#number">Number</a>
+ *         <td><code>24</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>K</code>
+ *         <td>Hour in am/pm (0-11)
+ *         <td><a href="#number">Number</a>
+ *         <td><code>0</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>h</code>
+ *         <td>Hour in am/pm (1-12)
+ *         <td><a href="#number">Number</a>
+ *         <td><code>12</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>m</code>
+ *         <td>Minute in hour
+ *         <td><a href="#number">Number</a>
+ *         <td><code>30</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>s</code>
+ *         <td>Second in minute
+ *         <td><a href="#number">Number</a>
+ *         <td><code>55</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>S</code>
+ *         <td>Millisecond
+ *         <td><a href="#number">Number</a>
+ *         <td><code>978</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>z</code>
+ *         <td>Time zone
+ *         <td><a href="#timezone">General time zone</a>
+ *         <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
+ *         <td>1+</td>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>Z</code>
+ *         <td>Time zone
+ *         <td><a href="#rfc822timezone">RFC 822 time zone</a>
+ *         <td><code>-0800</code>
+ *         <td>1+</td>
+ *     <tr>
+ *         <td><code>X</code>
+ *         <td>Time zone
+ *         <td><a href="#iso8601timezone">ISO 8601 time zone</a>
+ *         <td><code>-08</code>; <code>-0800</code>;  <code>-08:00</code>
+ *         <td>24+</td>
+ * </table>
+ * </blockquote>
+ * Pattern letters are usually repeated, as their number determines the
+ * exact presentation:
+ * <ul>
+ * <li><strong><a name="text">Text:</a></strong>
+ *     For formatting, if the number of pattern letters is 4 or more,
+ *     the full form is used; otherwise a short or abbreviated form
+ *     is used if available.
+ *     For parsing, both forms are accepted, independent of the number
+ *     of pattern letters.</li>
+ * <li><strong><a name="number">Number:</a></strong>
+ *     For formatting, the number of pattern letters is the minimum
+ *     number of digits, and shorter numbers are zero-padded to this amount.
+ *     For parsing, the number of pattern letters is ignored unless
+ *     it's needed to separate two adjacent fields.</li>
+ * <li><strong><a name="year">Year:</a></strong>
+ *     If the formatter's {@link #getCalendar() Calendar} is the Gregorian
+ *     calendar, the following rules are applied.
+ *     <ul>
+ *     <li>For formatting, if the number of pattern letters is 2, the year
+ *         is truncated to 2 digits; otherwise it is interpreted as a
+ *         <a href="#number">number</a>.
+ *     <li>For parsing, if the number of pattern letters is more than 2,
+ *         the year is interpreted literally, regardless of the number of
+ *         digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
+ *         Jan 11, 12 A.D.
+ *     <li>For parsing with the abbreviated year pattern ("y" or "yy"),
+ *         <code>SimpleDateFormat</code> must interpret the abbreviated year
+ *         relative to some century.  It does this by adjusting dates to be
+ *         within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
+ *         instance is created. For example, using a pattern of "MM/dd/yy" and a
+ *         <code>SimpleDateFormat</code> instance created on Jan 1, 1997,  the string
+ *         "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
+ *         would be interpreted as May 4, 1964.
+ *         During parsing, only strings consisting of exactly two digits, as defined by
+ *         {@link Character#isDigit(char)}, will be parsed into the default century.
+ *         Any other numeric string, such as a one digit string, a three or more digit
+ *         string, or a two digit string that isn't all digits (for example, "-1"), is
+ *         interpreted literally.  So "01/02/3" or "01/02/003" are parsed, using the
+ *         same pattern, as Jan 2, 3 AD.  Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
+ *     </ul>
+ *     Otherwise, calendar system specific forms are applied.
+ *     For both formatting and parsing, if the number of pattern
+ *     letters is 4 or more, a calendar specific {@linkplain
+ *     Calendar#LONG long form} is used. Otherwise, a calendar
+ *     specific {@linkplain Calendar#SHORT short or abbreviated form}
+ *     is used.
+ *     <br>
+ *     If week year {@code 'Y'} is specified and the {@linkplain
+ *     #getCalendar() calendar} doesn't support any <a
+ *     href="../util/GregorianCalendar.html#week_year"> week
+ *     years</a>, the calendar year ({@code 'y'}) is used instead. The
+ *     support of week years can be tested with a call to {@link
+ *     DateFormat#getCalendar() getCalendar()}.{@link
+ *     java.util.Calendar#isWeekDateSupported()
+ *     isWeekDateSupported()}.</li>
+ * <li><strong><a name="month">Month:</a></strong>
+ *     If the number of pattern letters is 3 or more, the month is
+ *     interpreted as <a href="#text">text</a>; otherwise,
+ *     it is interpreted as a <a href="#number">number</a>.
+ *     <ul>
+ *     <li>Letter <em>M</em> produces context-sensitive month names, such as the
+ *         embedded form of names. If a {@code DateFormatSymbols} has been set
+ *         explicitly with constructor {@link #SimpleDateFormat(String,
+ *         DateFormatSymbols)} or method {@link
+ *         #setDateFormatSymbols(DateFormatSymbols)}, the month names given by
+ *         the {@code DateFormatSymbols} are used.</li>
+ *     <li>Letter <em>L</em> produces the standalone form of month names.</li>
+ *     </ul>
+ *     <br></li>
+ * <li><strong><a name="timezone">General time zone:</a></strong>
+ *     Time zones are interpreted as <a href="#text">text</a> if they have
+ *     names. For time zones representing a GMT offset value, the
+ *     following syntax is used:
+ *     <pre>
+ *     <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
+ *             <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
+ *     <i>Sign:</i> one of
+ *             <code>+ -</code>
+ *     <i>Hours:</i>
+ *             <i>Digit</i>
+ *             <i>Digit</i> <i>Digit</i>
+ *     <i>Minutes:</i>
+ *             <i>Digit</i> <i>Digit</i>
+ *     <i>Digit:</i> one of
+ *             <code>0 1 2 3 4 5 6 7 8 9</code></pre>
+ *     <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
+ *     00 and 59. The format is locale independent and digits must be taken
+ *     from the Basic Latin block of the Unicode standard.
+ *     <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
+ *     accepted.</li>
+ * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
+ *     For formatting, the RFC 822 4-digit time zone format is used:
+ *
+ *     <pre>
+ *     <i>RFC822TimeZone:</i>
+ *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
+ *     <i>TwoDigitHours:</i>
+ *             <i>Digit Digit</i></pre>
+ *     <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
+ *     are as for <a href="#timezone">general time zones</a>.
+ *
+ *     <p>For parsing, <a href="#timezone">general time zones</a> are also
+ *     accepted.
+ * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
+ *     The number of pattern letters designates the format for both formatting
+ *     and parsing as follows:
+ *     <pre>
+ *     <i>ISO8601TimeZone:</i>
+ *             <i>OneLetterISO8601TimeZone</i>
+ *             <i>TwoLetterISO8601TimeZone</i>
+ *             <i>ThreeLetterISO8601TimeZone</i>
+ *     <i>OneLetterISO8601TimeZone:</i>
+ *             <i>Sign</i> <i>TwoDigitHours</i>
+ *             {@code Z}
+ *     <i>TwoLetterISO8601TimeZone:</i>
+ *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
+ *             {@code Z}
+ *     <i>ThreeLetterISO8601TimeZone:</i>
+ *             <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
+ *             {@code Z}</pre>
+ *     Other definitions are as for <a href="#timezone">general time zones</a> or
+ *     <a href="#rfc822timezone">RFC 822 time zones</a>.
+ *
+ *     <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
+ *     produced. If the number of pattern letters is 1, any fraction of an hour
+ *     is ignored. For example, if the pattern is {@code "X"} and the time zone is
+ *     {@code "GMT+05:30"}, {@code "+05"} is produced.
+ *
+ *     <p>For parsing, the letter {@code "Z"} is parsed as the UTC time zone designator (therefore
+ *     {@code "09:30Z"} is parsed as {@code "09:30 UTC"}.
+ *     <a href="#timezone">General time zones</a> are <em>not</em> accepted.
+ *     <p>If the number of {@code "X"} pattern letters is 4 or more (e.g. {@code XXXX}), {@link
+ *     IllegalArgumentException} is thrown when constructing a {@code
+ *     SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
+ *     pattern}.
+ * </ul>
+ * <code>SimpleDateFormat</code> also supports <em>localized date and time
+ * pattern</em> strings. In these strings, the pattern letters described above
+ * may be replaced with other, locale dependent, pattern letters.
+ * <code>SimpleDateFormat</code> does not deal with the localization of text
+ * other than the pattern letters; that's up to the client of the class.
+ *
+ * <h4>Examples</h4>
+ *
+ * The following examples show how date and time patterns are interpreted in
+ * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
+ * in the U.S. Pacific Time time zone.
+ * <blockquote>
+ * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
+ *     <tr style="background-color: rgb(204, 204, 255);">
+ *         <th align=left>Date and Time Pattern
+ *         <th align=left>Result
+ *     <tr>
+ *         <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
+ *         <td><code>2001.07.04 AD at 12:08:56 PDT</code>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>"EEE, MMM d, ''yy"</code>
+ *         <td><code>Wed, Jul 4, '01</code>
+ *     <tr>
+ *         <td><code>"h:mm a"</code>
+ *         <td><code>12:08 PM</code>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>"hh 'o''clock' a, zzzz"</code>
+ *         <td><code>12 o'clock PM, Pacific Daylight Time</code>
+ *     <tr>
+ *         <td><code>"K:mm a, z"</code>
+ *         <td><code>0:08 PM, PDT</code>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
+ *         <td><code>02001.July.04 AD 12:08 PM</code>
+ *     <tr>
+ *         <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
+ *         <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>"yyMMddHHmmssZ"</code>
+ *         <td><code>010704120856-0700</code>
+ *     <tr>
+ *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
+ *         <td><code>2001-07-04T12:08:56.235-0700</code>
+ *     <tr style="background-color: rgb(238, 238, 255);">
+ *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
+ *         <td><code>2001-07-04T12:08:56.235-07:00</code>
+ *     <tr>
+ *         <td><code>"YYYY-'W'ww-u"</code>
+ *         <td><code>2001-W27-3</code>
+ * </table>
+ * </blockquote>
+ *
+ * <h4><a name="synchronization">Synchronization</a></h4>
+ *
+ * <p>
+ * Date formats are not synchronized.
+ * It is recommended to create separate format instances for each thread.
+ * If multiple threads access a format concurrently, it must be synchronized
+ * externally.
+ *
+ * @see          <a href="https://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
+ * @see          java.util.Calendar
+ * @see          java.util.TimeZone
+ * @see          DateFormat
+ * @see          DateFormatSymbols
+ * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
+ */
+public class SimpleDateFormat extends DateFormat {
+
+    // the official serial version ID which says cryptically
+    // which version we're compatible with
+    static final long serialVersionUID = 4774881970558875024L;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.3
+    // - 1 for version from JDK 1.1.4, which includes a new field
+    static final int currentSerialVersion = 1;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <ul>
+     * <li><b>0</b> or not present on stream: JDK 1.1.3.  This version
+     * has no <code>defaultCenturyStart</code> on stream.
+     * <li><b>1</b> JDK 1.1.4 or later.  This version adds
+     * <code>defaultCenturyStart</code>.
+     * </ul>
+     * When streaming out this class, the most recent format
+     * and the highest allowable <code>serialVersionOnStream</code>
+     * is written.
+     * @serial
+     * @since JDK1.1.4
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+
+    /**
+     * The pattern string of this formatter.  This is always a non-localized
+     * pattern.  May not be null.  See class documentation for details.
+     * @serial
+     */
+    private String pattern;
+
+    /**
+     * Saved numberFormat and pattern.
+     * @see SimpleDateFormat#checkNegativeNumberExpression
+     */
+    transient private NumberFormat originalNumberFormat;
+    transient private String originalNumberPattern;
+
+    /**
+     * The minus sign to be used with format and parse.
+     */
+    transient private char minusSign = '-';
+
+    /**
+     * True when a negative sign follows a number.
+     * (True as default in Arabic.)
+     */
+    transient private boolean hasFollowingMinusSign = false;
+
+    // BEGIN Android-removed: App compat for formatting pattern letter M.
+    // OpenJDK forces the standalone form of month when patterns contain pattern M only.
+    // This feature is not incorporated for app compatibility and because the feature is
+    // not documented in OpenJDK or Android.
+    /*
+    /**
+     * True if standalone form needs to be used.
+     *
+    transient private boolean forceStandaloneForm = false;
+    */
+    // END Android-removed: App compat for formatting pattern letter M.
+
+    /**
+     * The compiled pattern.
+     */
+    transient private char[] compiledPattern;
+
+    /**
+     * Tags for the compiled pattern.
+     */
+    private final static int TAG_QUOTE_ASCII_CHAR       = 100;
+    private final static int TAG_QUOTE_CHARS            = 101;
+
+    /**
+     * Locale dependent digit zero.
+     * @see #zeroPaddingNumber
+     * @see java.text.DecimalFormatSymbols#getZeroDigit
+     */
+    transient private char zeroDigit;
+
+    /**
+     * The symbols used by this formatter for week names, month names,
+     * etc.  May not be null.
+     * @serial
+     * @see java.text.DateFormatSymbols
+     */
+    private DateFormatSymbols formatData;
+
+    /**
+     * We map dates with two-digit years into the century starting at
+     * <code>defaultCenturyStart</code>, which may be any date.  May
+     * not be null.
+     * @serial
+     * @since JDK1.1.4
+     */
+    private Date defaultCenturyStart;
+
+    transient private int defaultCenturyStartYear;
+
+    private static final int MILLIS_PER_MINUTE = 60 * 1000;
+
+    // For time zones that have no names, use strings GMT+minutes and
+    // GMT-minutes. For instance, in France the time zone is GMT+60.
+    private static final String GMT = "GMT";
+
+    /**
+     * Cache NumberFormat instances with Locale key.
+     */
+    private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
+        = new ConcurrentHashMap<>(3);
+
+    /**
+     * The Locale used to instantiate this
+     * <code>SimpleDateFormat</code>. The value may be null if this object
+     * has been created by an older <code>SimpleDateFormat</code> and
+     * deserialized.
+     *
+     * @serial
+     * @since 1.6
+     */
+    private Locale locale;
+
+    /**
+     * Indicates whether this <code>SimpleDateFormat</code> should use
+     * the DateFormatSymbols. If true, the format and parse methods
+     * use the DateFormatSymbols values. If false, the format and
+     * parse methods call Calendar.getDisplayName or
+     * Calendar.getDisplayNames.
+     */
+    transient boolean useDateFormatSymbols;
+
+    // Android-added: ICU TimeZoneNames field.
+    /**
+     * ICU TimeZoneNames used to format and parse time zone names.
+     */
+    private transient TimeZoneNames timeZoneNames;
+
+    /**
+     * Constructs a <code>SimpleDateFormat</code> using the default pattern and
+     * date format symbols for the default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <b>Note:</b> This constructor may not support all locales.
+     * For full coverage, use the factory methods in the {@link DateFormat}
+     * class.
+     */
+    public SimpleDateFormat() {
+        // BEGIN Android-changed: Android has no LocaleProviderAdapter. Use ICU locale data.
+        /*
+        this("", Locale.getDefault(Locale.Category.FORMAT));
+        applyPatternImpl(LocaleProviderAdapter.getResourceBundleBased().getLocaleResources(locale)
+                         .getDateTimePattern(SHORT, SHORT, calendar));
+        */
+        this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
+        // END Android-changed: Android has no LocaleProviderAdapter. Use ICU locale data.
+    }
+
+    // BEGIN Android-added: Ctor used by DateFormat to remove use of LocaleProviderAdapter.
+    /**
+     * Constructs a <code>SimpleDateFormat</code> using the given date and time formatting styles.
+     * @param timeStyle the given date formatting style.
+     * @param dateStyle the given time formatting style.
+     * @param locale the locale whose pattern and date format symbols should be used
+     */
+    SimpleDateFormat(int timeStyle, int dateStyle, Locale locale) {
+        this(getDateTimeFormat(timeStyle, dateStyle, locale), locale);
+    }
+
+    private static String getDateTimeFormat(int timeStyle, int dateStyle, Locale locale) {
+        LocaleData localeData = LocaleData.get(locale);
+        if ((timeStyle >= 0) && (dateStyle >= 0)) {
+            Object[] dateTimeArgs = {
+                localeData.getDateFormat(dateStyle),
+                localeData.getTimeFormat(timeStyle),
+            };
+            return MessageFormat.format("{0} {1}", dateTimeArgs);
+        } else if (timeStyle >= 0) {
+            return localeData.getTimeFormat(timeStyle);
+        } else if (dateStyle >= 0) {
+            return localeData.getDateFormat(dateStyle);
+        } else {
+            throw new IllegalArgumentException("No date or time style specified");
+        }
+    }
+    // END Android-added: Ctor used by DateFormat to remove use of LocaleProviderAdapter.
+
+    /**
+     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
+     * the default date format symbols for the default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <b>Note:</b> This constructor may not support all locales.
+     * For full coverage, use the factory methods in the {@link DateFormat}
+     * class.
+     * <p>This is equivalent to calling
+     * {@link #SimpleDateFormat(String, Locale)
+     *     SimpleDateFormat(pattern, Locale.getDefault(Locale.Category.FORMAT))}.
+     *
+     * @see java.util.Locale#getDefault(java.util.Locale.Category)
+     * @see java.util.Locale.Category#FORMAT
+     * @param pattern the pattern describing the date and time format
+     * @exception NullPointerException if the given pattern is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    public SimpleDateFormat(String pattern)
+    {
+        this(pattern, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
+     * the default date format symbols for the given locale.
+     * <b>Note:</b> This constructor may not support all locales.
+     * For full coverage, use the factory methods in the {@link DateFormat}
+     * class.
+     *
+     * @param pattern the pattern describing the date and time format
+     * @param locale the locale whose date format symbols should be used
+     * @exception NullPointerException if the given pattern or locale is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    public SimpleDateFormat(String pattern, Locale locale)
+    {
+        if (pattern == null || locale == null) {
+            throw new NullPointerException();
+        }
+
+        initializeCalendar(locale);
+        this.pattern = pattern;
+        this.formatData = DateFormatSymbols.getInstanceRef(locale);
+        this.locale = locale;
+        initialize(locale);
+    }
+
+    /**
+     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
+     * date format symbols.
+     *
+     * @param pattern the pattern describing the date and time format
+     * @param formatSymbols the date format symbols to be used for formatting
+     * @exception NullPointerException if the given pattern or formatSymbols is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
+    {
+        if (pattern == null || formatSymbols == null) {
+            throw new NullPointerException();
+        }
+
+        this.pattern = pattern;
+        this.formatData = (DateFormatSymbols) formatSymbols.clone();
+        this.locale = Locale.getDefault(Locale.Category.FORMAT);
+        initializeCalendar(this.locale);
+        initialize(this.locale);
+        useDateFormatSymbols = true;
+    }
+
+    /* Initialize compiledPattern and numberFormat fields */
+    private void initialize(Locale loc) {
+        // Verify and compile the given pattern.
+        compiledPattern = compile(pattern);
+
+        /* try the cache first */
+        numberFormat = cachedNumberFormatData.get(loc);
+        if (numberFormat == null) { /* cache miss */
+            numberFormat = NumberFormat.getIntegerInstance(loc);
+            numberFormat.setGroupingUsed(false);
+
+            /* update cache */
+            cachedNumberFormatData.putIfAbsent(loc, numberFormat);
+        }
+        numberFormat = (NumberFormat) numberFormat.clone();
+
+        initializeDefaultCentury();
+    }
+
+    private void initializeCalendar(Locale loc) {
+        if (calendar == null) {
+            assert loc != null;
+            // The format object must be constructed using the symbols for this zone.
+            // However, the calendar should use the current default TimeZone.
+            // If this is not contained in the locale zone strings, then the zone
+            // will be formatted using generic GMT+/-H:MM nomenclature.
+            calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
+        }
+    }
+
+    /**
+     * Returns the compiled form of the given pattern. The syntax of
+     * the compiled pattern is:
+     * <blockquote>
+     * CompiledPattern:
+     *     EntryList
+     * EntryList:
+     *     Entry
+     *     EntryList Entry
+     * Entry:
+     *     TagField
+     *     TagField data
+     * TagField:
+     *     Tag Length
+     *     TaggedData
+     * Tag:
+     *     pattern_char_index
+     *     TAG_QUOTE_CHARS
+     * Length:
+     *     short_length
+     *     long_length
+     * TaggedData:
+     *     TAG_QUOTE_ASCII_CHAR ascii_char
+     *
+     * </blockquote>
+     *
+     * where `short_length' is an 8-bit unsigned integer between 0 and
+     * 254.  `long_length' is a sequence of an 8-bit integer 255 and a
+     * 32-bit signed integer value which is split into upper and lower
+     * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
+     * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
+     * character value. `data' depends on its Tag value.
+     * <p>
+     * If Length is short_length, Tag and short_length are packed in a
+     * single char, as illustrated below.
+     * <blockquote>
+     *     char[0] = (Tag << 8) | short_length;
+     * </blockquote>
+     *
+     * If Length is long_length, Tag and 255 are packed in the first
+     * char and a 32-bit integer, as illustrated below.
+     * <blockquote>
+     *     char[0] = (Tag << 8) | 255;
+     *     char[1] = (char) (long_length >>> 16);
+     *     char[2] = (char) (long_length & 0xffff);
+     * </blockquote>
+     * <p>
+     * If Tag is a pattern_char_index, its Length is the number of
+     * pattern characters. For example, if the given pattern is
+     * "yyyy", Tag is 1 and Length is 4, followed by no data.
+     * <p>
+     * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
+     * following the TagField. For example, if the given pattern is
+     * "'o''clock'", Length is 7 followed by a char sequence of
+     * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
+     * <p>
+     * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
+     * character in place of Length. For example, if the given pattern
+     * is "'o'", the TaggedData entry is
+     * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
+     *
+     * @exception NullPointerException if the given pattern is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    private char[] compile(String pattern) {
+        int length = pattern.length();
+        boolean inQuote = false;
+        StringBuilder compiledCode = new StringBuilder(length * 2);
+        StringBuilder tmpBuffer = null;
+        // BEGIN Android-removed: App compat for formatting pattern letter M.
+        // See forceStandaloneForm field
+        /*
+        int count = 0, tagcount = 0;
+        int lastTag = -1, prevTag = -1;
+        */
+        int count = 0;
+        int lastTag = -1;
+        // END Android-removed: App compat for formatting pattern letter M.
+
+        for (int i = 0; i < length; i++) {
+            char c = pattern.charAt(i);
+
+            if (c == '\'') {
+                // '' is treated as a single quote regardless of being
+                // in a quoted section.
+                if ((i + 1) < length) {
+                    c = pattern.charAt(i + 1);
+                    if (c == '\'') {
+                        i++;
+                        if (count != 0) {
+                            encode(lastTag, count, compiledCode);
+                            // BEGIN Android-removed: App compat for formatting pattern letter M.
+                            // See forceStandaloneForm field
+                            /*
+                            tagcount++;
+                            prevTag = lastTag;
+                            */
+                            // END Android-removed: App compat for formatting pattern letter M.
+                            lastTag = -1;
+                            count = 0;
+                        }
+                        if (inQuote) {
+                            tmpBuffer.append(c);
+                        } else {
+                            compiledCode.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
+                        }
+                        continue;
+                    }
+                }
+                if (!inQuote) {
+                    if (count != 0) {
+                        encode(lastTag, count, compiledCode);
+                        // BEGIN Android-removed: App compat for formatting pattern letter M.
+                        // See forceStandaloneForm field
+                        /*
+                        tagcount++;
+                        prevTag = lastTag;
+                        */
+                        // END Android-removed: App compat for formatting pattern letter M.
+                        lastTag = -1;
+                        count = 0;
+                    }
+                    if (tmpBuffer == null) {
+                        tmpBuffer = new StringBuilder(length);
+                    } else {
+                        tmpBuffer.setLength(0);
+                    }
+                    inQuote = true;
+                } else {
+                    int len = tmpBuffer.length();
+                    if (len == 1) {
+                        char ch = tmpBuffer.charAt(0);
+                        if (ch < 128) {
+                            compiledCode.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
+                        } else {
+                            compiledCode.append((char)(TAG_QUOTE_CHARS << 8 | 1));
+                            compiledCode.append(ch);
+                        }
+                    } else {
+                        encode(TAG_QUOTE_CHARS, len, compiledCode);
+                        compiledCode.append(tmpBuffer);
+                    }
+                    inQuote = false;
+                }
+                continue;
+            }
+            if (inQuote) {
+                tmpBuffer.append(c);
+                continue;
+            }
+            if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
+                if (count != 0) {
+                    encode(lastTag, count, compiledCode);
+                    // BEGIN Android-removed: App compat for formatting pattern letter M.
+                    // See forceStandaloneForm field
+                    /*
+                    tagcount++;
+                    prevTag = lastTag;
+                    */
+                    // END Android-removed: App compat for formatting pattern letter M.
+                    lastTag = -1;
+                    count = 0;
+                }
+                if (c < 128) {
+                    // In most cases, c would be a delimiter, such as ':'.
+                    compiledCode.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
+                } else {
+                    // Take any contiguous non-ASCII alphabet characters and
+                    // put them in a single TAG_QUOTE_CHARS.
+                    int j;
+                    for (j = i + 1; j < length; j++) {
+                        char d = pattern.charAt(j);
+                        if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
+                            break;
+                        }
+                    }
+                    compiledCode.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
+                    for (; i < j; i++) {
+                        compiledCode.append(pattern.charAt(i));
+                    }
+                    i--;
+                }
+                continue;
+            }
+
+            int tag;
+            if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
+                throw new IllegalArgumentException("Illegal pattern character " +
+                                                   "'" + c + "'");
+            }
+            if (lastTag == -1 || lastTag == tag) {
+                lastTag = tag;
+                count++;
+                continue;
+            }
+            encode(lastTag, count, compiledCode);
+            // BEGIN Android-removed: App compat for formatting pattern letter M.
+            // See forceStandaloneForm field
+            /*
+            tagcount++;
+            prevTag = lastTag;
+            */
+            // END Android-removed: App compat for formatting pattern letter M.
+            lastTag = tag;
+            count = 1;
+        }
+
+        if (inQuote) {
+            throw new IllegalArgumentException("Unterminated quote");
+        }
+
+        if (count != 0) {
+            encode(lastTag, count, compiledCode);
+            // BEGIN Android-removed: App compat for formatting pattern letter M.
+            // See forceStandaloneForm field
+            /*
+            tagcount++;
+            prevTag = lastTag;
+            */
+            // END Android-removed: App compat for formatting pattern letter M.
+        }
+
+        // Android-removed: App compat for formatting pattern letter M.
+        // See forceStandaloneForm field
+        // forceStandaloneForm = (tagcount == 1 && prevTag == PATTERN_MONTH);
+
+        // Copy the compiled pattern to a char array
+        int len = compiledCode.length();
+        char[] r = new char[len];
+        compiledCode.getChars(0, len, r, 0);
+        return r;
+    }
+
+    /**
+     * Encodes the given tag and length and puts encoded char(s) into buffer.
+     */
+    private static void encode(int tag, int length, StringBuilder buffer) {
+        if (tag == PATTERN_ISO_ZONE && length >= 4) {
+            throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
+        }
+        if (length < 255) {
+            buffer.append((char)(tag << 8 | length));
+        } else {
+            buffer.append((char)((tag << 8) | 0xff));
+            buffer.append((char)(length >>> 16));
+            buffer.append((char)(length & 0xffff));
+        }
+    }
+
+    /* Initialize the fields we use to disambiguate ambiguous years. Separate
+     * so we can call it from readObject().
+     */
+    private void initializeDefaultCentury() {
+        calendar.setTimeInMillis(System.currentTimeMillis());
+        calendar.add( Calendar.YEAR, -80 );
+        parseAmbiguousDatesAsAfter(calendar.getTime());
+    }
+
+    /* Define one-century window into which to disambiguate dates using
+     * two-digit years.
+     */
+    private void parseAmbiguousDatesAsAfter(Date startDate) {
+        defaultCenturyStart = startDate;
+        calendar.setTime(startDate);
+        defaultCenturyStartYear = calendar.get(Calendar.YEAR);
+    }
+
+    /**
+     * Sets the 100-year period 2-digit years will be interpreted as being in
+     * to begin on the date the user specifies.
+     *
+     * @param startDate During parsing, two digit years will be placed in the range
+     * <code>startDate</code> to <code>startDate + 100 years</code>.
+     * @see #get2DigitYearStart
+     * @since 1.2
+     */
+    public void set2DigitYearStart(Date startDate) {
+        parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
+    }
+
+    /**
+     * Returns the beginning date of the 100-year period 2-digit years are interpreted
+     * as being within.
+     *
+     * @return the start of the 100-year period into which two digit years are
+     * parsed
+     * @see #set2DigitYearStart
+     * @since 1.2
+     */
+    public Date get2DigitYearStart() {
+        return (Date) defaultCenturyStart.clone();
+    }
+
+    /**
+     * Formats the given <code>Date</code> into a date/time string and appends
+     * the result to the given <code>StringBuffer</code>.
+     *
+     * @param date the date-time value to be formatted into a date-time string.
+     * @param toAppendTo where the new date-time text is to be appended.
+     * @param pos the formatting position. On input: an alignment field,
+     * if desired. On output: the offsets of the alignment field.
+     * @return the formatted date-time string.
+     * @exception NullPointerException if the given {@code date} is {@code null}.
+     */
+    @Override
+    public StringBuffer format(Date date, StringBuffer toAppendTo,
+                               FieldPosition pos)
+    {
+        pos.beginIndex = pos.endIndex = 0;
+        return format(date, toAppendTo, pos.getFieldDelegate());
+    }
+
+    // Called from Format after creating a FieldDelegate
+    private StringBuffer format(Date date, StringBuffer toAppendTo,
+                                FieldDelegate delegate) {
+        // Convert input date to time field list
+        calendar.setTime(date);
+
+        boolean useDateFormatSymbols = useDateFormatSymbols();
+
+        for (int i = 0; i < compiledPattern.length; ) {
+            int tag = compiledPattern[i] >>> 8;
+            int count = compiledPattern[i++] & 0xff;
+            if (count == 255) {
+                count = compiledPattern[i++] << 16;
+                count |= compiledPattern[i++];
+            }
+
+            switch (tag) {
+            case TAG_QUOTE_ASCII_CHAR:
+                toAppendTo.append((char)count);
+                break;
+
+            case TAG_QUOTE_CHARS:
+                toAppendTo.append(compiledPattern, i, count);
+                i += count;
+                break;
+
+            default:
+                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
+                break;
+            }
+        }
+        return toAppendTo;
+    }
+
+    /**
+     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
+     * You can use the returned <code>AttributedCharacterIterator</code>
+     * to build the resulting String, as well as to determine information
+     * about the resulting String.
+     * <p>
+     * Each attribute key of the AttributedCharacterIterator will be of type
+     * <code>DateFormat.Field</code>, with the corresponding attribute value
+     * being the same as the attribute key.
+     *
+     * @exception NullPointerException if obj is null.
+     * @exception IllegalArgumentException if the Format cannot format the
+     *            given object, or if the Format's pattern string is invalid.
+     * @param obj The object to format
+     * @return AttributedCharacterIterator describing the formatted value.
+     * @since 1.4
+     */
+    @Override
+    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
+        StringBuffer sb = new StringBuffer();
+        CharacterIteratorFieldDelegate delegate = new
+                         CharacterIteratorFieldDelegate();
+
+        if (obj instanceof Date) {
+            format((Date)obj, sb, delegate);
+        }
+        else if (obj instanceof Number) {
+            format(new Date(((Number)obj).longValue()), sb, delegate);
+        }
+        else if (obj == null) {
+            throw new NullPointerException(
+                   "formatToCharacterIterator must be passed non-null object");
+        }
+        else {
+            throw new IllegalArgumentException(
+                             "Cannot format given Object as a Date");
+        }
+        return delegate.getIterator(sb.toString());
+    }
+
+    // Map index into pattern character string to Calendar field number
+    private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD = {
+        Calendar.ERA,
+        Calendar.YEAR,
+        Calendar.MONTH,
+        Calendar.DATE,
+        Calendar.HOUR_OF_DAY,
+        Calendar.HOUR_OF_DAY,
+        Calendar.MINUTE,
+        Calendar.SECOND,
+        Calendar.MILLISECOND,
+        Calendar.DAY_OF_WEEK,
+        Calendar.DAY_OF_YEAR,
+        Calendar.DAY_OF_WEEK_IN_MONTH,
+        Calendar.WEEK_OF_YEAR,
+        Calendar.WEEK_OF_MONTH,
+        Calendar.AM_PM,
+        Calendar.HOUR,
+        Calendar.HOUR,
+        Calendar.ZONE_OFFSET,
+        Calendar.ZONE_OFFSET,
+        CalendarBuilder.WEEK_YEAR,         // Pseudo Calendar field
+        CalendarBuilder.ISO_DAY_OF_WEEK,   // Pseudo Calendar field
+        Calendar.ZONE_OFFSET,
+        Calendar.MONTH,
+        // Android-added: 'c' for standalone day of week.
+        Calendar.DAY_OF_WEEK,
+        // Android-added: Support for 'b'/'B' (day period). Calendar.AM_PM is just used as a
+        // placeholder in the absence of full support for day period.
+        Calendar.AM_PM,
+        Calendar.AM_PM
+    };
+
+    // Map index into pattern character string to DateFormat field number
+    private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
+        DateFormat.ERA_FIELD,
+        DateFormat.YEAR_FIELD,
+        DateFormat.MONTH_FIELD,
+        DateFormat.DATE_FIELD,
+        DateFormat.HOUR_OF_DAY1_FIELD,
+        DateFormat.HOUR_OF_DAY0_FIELD,
+        DateFormat.MINUTE_FIELD,
+        DateFormat.SECOND_FIELD,
+        DateFormat.MILLISECOND_FIELD,
+        DateFormat.DAY_OF_WEEK_FIELD,
+        DateFormat.DAY_OF_YEAR_FIELD,
+        DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD,
+        DateFormat.WEEK_OF_YEAR_FIELD,
+        DateFormat.WEEK_OF_MONTH_FIELD,
+        DateFormat.AM_PM_FIELD,
+        DateFormat.HOUR1_FIELD,
+        DateFormat.HOUR0_FIELD,
+        DateFormat.TIMEZONE_FIELD,
+        DateFormat.TIMEZONE_FIELD,
+        DateFormat.YEAR_FIELD,
+        DateFormat.DAY_OF_WEEK_FIELD,
+        DateFormat.TIMEZONE_FIELD,
+        DateFormat.MONTH_FIELD,
+        // Android-added: 'c' for standalone day of week.
+        DateFormat.DAY_OF_WEEK_FIELD,
+        // Android-added: Support for 'b'/'B' (day period). DateFormat.AM_PM_FIELD is just used as a
+        // placeholder in the absence of full support for day period.
+        DateFormat.AM_PM_FIELD,
+        DateFormat.AM_PM_FIELD
+    };
+
+    // Maps from DecimalFormatSymbols index to Field constant
+    private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
+        Field.ERA,
+        Field.YEAR,
+        Field.MONTH,
+        Field.DAY_OF_MONTH,
+        Field.HOUR_OF_DAY1,
+        Field.HOUR_OF_DAY0,
+        Field.MINUTE,
+        Field.SECOND,
+        Field.MILLISECOND,
+        Field.DAY_OF_WEEK,
+        Field.DAY_OF_YEAR,
+        Field.DAY_OF_WEEK_IN_MONTH,
+        Field.WEEK_OF_YEAR,
+        Field.WEEK_OF_MONTH,
+        Field.AM_PM,
+        Field.HOUR1,
+        Field.HOUR0,
+        Field.TIME_ZONE,
+        Field.TIME_ZONE,
+        Field.YEAR,
+        Field.DAY_OF_WEEK,
+        Field.TIME_ZONE,
+        Field.MONTH,
+        // Android-added: 'c' for standalone day of week.
+        Field.DAY_OF_WEEK,
+        // Android-added: Support for 'b'/'B' (day period). Field.AM_PM is just used as a
+        // placeholder in the absence of full support for day period.
+        Field.AM_PM,
+        Field.AM_PM
+    };
+
+    /**
+     * Private member function that does the real date/time formatting.
+     */
+    private void subFormat(int patternCharIndex, int count,
+                           FieldDelegate delegate, StringBuffer buffer,
+                           boolean useDateFormatSymbols)
+    {
+        int     maxIntCount = Integer.MAX_VALUE;
+        String  current = null;
+        int     beginOffset = buffer.length();
+
+        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
+        int value;
+        if (field == CalendarBuilder.WEEK_YEAR) {
+            if (calendar.isWeekDateSupported()) {
+                value = calendar.getWeekYear();
+            } else {
+                // use calendar year 'y' instead
+                patternCharIndex = PATTERN_YEAR;
+                field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
+                value = calendar.get(field);
+            }
+        } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
+            value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
+        } else {
+            value = calendar.get(field);
+        }
+
+        int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
+        if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
+            current = calendar.getDisplayName(field, style, locale);
+        }
+
+        // Note: zeroPaddingNumber() assumes that maxDigits is either
+        // 2 or maxIntCount. If we make any changes to this,
+        // zeroPaddingNumber() must be fixed.
+
+        switch (patternCharIndex) {
+        case PATTERN_ERA: // 'G'
+            if (useDateFormatSymbols) {
+                String[] eras = formatData.getEras();
+                if (value < eras.length) {
+                    current = eras[value];
+                }
+            }
+            if (current == null) {
+                current = "";
+            }
+            break;
+
+        case PATTERN_WEEK_YEAR: // 'Y'
+        case PATTERN_YEAR:      // 'y'
+            if (calendar instanceof GregorianCalendar) {
+                if (count != 2) {
+                    zeroPaddingNumber(value, count, maxIntCount, buffer);
+                } else {
+                    zeroPaddingNumber(value, 2, 2, buffer);
+                } // clip 1996 to 96
+            } else {
+                if (current == null) {
+                    zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
+                                      maxIntCount, buffer);
+                }
+            }
+            break;
+
+        case PATTERN_MONTH:            // 'M' (context seinsive)
+            // BEGIN Android-changed: formatMonth() method to format using ICU data.
+            /*
+            if (useDateFormatSymbols) {
+                String[] months;
+                if (count >= 4) {
+                    months = formatData.getMonths();
+                    current = months[value];
+                } else if (count == 3) {
+                    months = formatData.getShortMonths();
+                    current = months[value];
+                }
+            } else {
+                if (count < 3) {
+                    current = null;
+                } else if (forceStandaloneForm) {
+                    current = calendar.getDisplayName(field, style | 0x8000, locale);
+                    if (current == null) {
+                        current = calendar.getDisplayName(field, style, locale);
+                    }
+                }
+            }
+            if (current == null) {
+                zeroPaddingNumber(value+1, count, maxIntCount, buffer);
+            }
+            */
+            current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
+                false /* standalone */, field, style);
+            // END Android-changed: formatMonth() method to format using ICU data.
+            break;
+
+        case PATTERN_MONTH_STANDALONE: // 'L'
+            // BEGIN Android-changed: formatMonth() method to format using ICU data.
+            /*
+            assert current == null;
+            if (locale == null) {
+                String[] months;
+                if (count >= 4) {
+                    months = formatData.getMonths();
+                    current = months[value];
+                } else if (count == 3) {
+                    months = formatData.getShortMonths();
+                    current = months[value];
+                }
+            } else {
+                if (count >= 3) {
+                    current = calendar.getDisplayName(field, style | 0x8000, locale);
+                }
+            }
+            if (current == null) {
+                zeroPaddingNumber(value+1, count, maxIntCount, buffer);
+            }
+            */
+            current = formatMonth(count, value, maxIntCount, buffer, useDateFormatSymbols,
+                   true /* standalone */, field, style);
+            // END Android-changed: formatMonth() method to format using ICU data.
+            break;
+
+        case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
+            if (current == null) {
+                if (value == 0) {
+                    zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1,
+                                      count, maxIntCount, buffer);
+                } else {
+                    zeroPaddingNumber(value, count, maxIntCount, buffer);
+                }
+            }
+            break;
+
+        case PATTERN_DAY_OF_WEEK: // 'E'
+            // BEGIN Android-removed: App compat for formatting pattern letter M.
+            // See forceStandaloneForm field
+            /*
+            if (useDateFormatSymbols) {
+                String[] weekdays;
+                if (count >= 4) {
+                    weekdays = formatData.getWeekdays();
+                    current = weekdays[value];
+                } else { // count < 4, use abbreviated form if exists
+                    weekdays = formatData.getShortWeekdays();
+                    current = weekdays[value];
+                }
+            }
+            */
+            if (current == null) {
+                current = formatWeekday(count, value, useDateFormatSymbols, false /* standalone */);
+            }
+            // END Android-removed: App compat for formatting pattern letter M.
+            break;
+
+        // BEGIN Android-added: support for 'c' (standalone day of week).
+        case PATTERN_STANDALONE_DAY_OF_WEEK: // 'c'
+            if (current == null) {
+                current = formatWeekday(count, value, useDateFormatSymbols, true /* standalone */);
+            }
+            break;
+        // END Android-added: support for 'c' (standalone day of week).
+
+        case PATTERN_AM_PM:    // 'a'
+            if (useDateFormatSymbols) {
+                String[] ampm = formatData.getAmPmStrings();
+                current = ampm[value];
+            }
+            break;
+
+        // Android-added: Ignore 'b' and 'B' introduced in CLDR 32+ pattern data. http://b/68139386
+        // Not currently supported here.
+        case PATTERN_DAY_PERIOD:
+        case PATTERN_FLEXIBLE_DAY_PERIOD:
+            current = "";
+            break;
+
+        case PATTERN_HOUR1:    // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
+            if (current == null) {
+                if (value == 0) {
+                    zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR) + 1,
+                                      count, maxIntCount, buffer);
+                } else {
+                    zeroPaddingNumber(value, count, maxIntCount, buffer);
+                }
+            }
+            break;
+
+        case PATTERN_ZONE_NAME: // 'z'
+            if (current == null) {
+                // BEGIN Android-changed: Format time zone name using ICU.
+                /*
+                if (formatData.locale == null || formatData.isZoneStringsSet) {
+                    int zoneIndex =
+                        formatData.getZoneIndex(calendar.getTimeZone().getID());
+                    if (zoneIndex == -1) {
+                        value = calendar.get(Calendar.ZONE_OFFSET) +
+                            calendar.get(Calendar.DST_OFFSET);
+                        buffer.append(ZoneInfoFile.toCustomID(value));
+                    } else {
+                        int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
+                        if (count < 4) {
+                            // Use the short name
+                            index++;
+                        }
+                        String[][] zoneStrings = formatData.getZoneStringsWrapper();
+                        buffer.append(zoneStrings[zoneIndex][index]);
+                    }
+                } else {
+                    TimeZone tz = calendar.getTimeZone();
+                    boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
+                    int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
+                    buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
+                }
+                */
+                TimeZone tz = calendar.getTimeZone();
+                boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
+                String zoneString;
+                if (formatData.isZoneStringsSet) {
+                    // DateFormatSymbols.setZoneStrings() has be used, use those values instead of
+                    // ICU code.
+                    int tzstyle = count < 4 ? TimeZone.SHORT : TimeZone.LONG;
+                    zoneString = libcore.icu.TimeZoneNames.getDisplayName(
+                            formatData.getZoneStringsWrapper(), tz.getID(), daylight, tzstyle);
+                } else {
+                    TimeZoneNames.NameType nameType;
+                    if (count < 4) {
+                        nameType = daylight
+                                ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+                                : TimeZoneNames.NameType.SHORT_STANDARD;
+                    } else {
+                        nameType = daylight
+                                ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                                : TimeZoneNames.NameType.LONG_STANDARD;
+                    }
+                    String canonicalID = android.icu.util.TimeZone.getCanonicalID(tz.getID());
+                    zoneString = getTimeZoneNames()
+                            .getDisplayName(canonicalID, nameType, calendar.getTimeInMillis());
+                }
+                if (zoneString != null) {
+                    buffer.append(zoneString);
+                } else {
+                    int offsetMillis = calendar.get(Calendar.ZONE_OFFSET) +
+                        calendar.get(Calendar.DST_OFFSET);
+                    buffer.append(TimeZone.createGmtOffsetString(true, true, offsetMillis));
+                }
+                // END Android-changed: Format time zone name using ICU.
+            }
+            break;
+
+        case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
+            // BEGIN Android-changed: Use shared code in TimeZone for zone offset string.
+            /*
+            value = (calendar.get(Calendar.ZONE_OFFSET) +
+                     calendar.get(Calendar.DST_OFFSET)) / 60000;
+
+            int width = 4;
+            if (value >= 0) {
+                buffer.append('+');
+            } else {
+                width++;
+            }
+
+            int num = (value / 60) * 100 + (value % 60);
+            CalendarUtils.sprintf0d(buffer, num, width);
+            */
+            value = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
+            final boolean includeSeparator = (count >= 4);
+            final boolean includeGmt = (count == 4);
+            buffer.append(TimeZone.createGmtOffsetString(includeGmt, includeSeparator, value));
+
+            break;
+            // END Android-changed: Use shared code in TimeZone for zone offset string.
+
+        case PATTERN_ISO_ZONE:   // 'X'
+            value = calendar.get(Calendar.ZONE_OFFSET)
+                    + calendar.get(Calendar.DST_OFFSET);
+
+            if (value == 0) {
+                buffer.append('Z');
+                break;
+            }
+
+            value /=  60000;
+            if (value >= 0) {
+                buffer.append('+');
+            } else {
+                buffer.append('-');
+                value = -value;
+            }
+
+            CalendarUtils.sprintf0d(buffer, value / 60, 2);
+            if (count == 1) {
+                break;
+            }
+
+            if (count == 3) {
+                buffer.append(':');
+            }
+            CalendarUtils.sprintf0d(buffer, value % 60, 2);
+            break;
+        // BEGIN Android-added: Better UTS#35 conformity for fractional seconds.
+        case PATTERN_MILLISECOND: // 'S'
+            // Fractional seconds must be treated specially. We must always convert the parsed
+            // value into a fractional second [0, 1) and then widen it out to the appropriate
+            // formatted size. For example, an initial value of 789 will be converted
+            // 0.789 and then become ".7" (S) or ".78" (SS) or "0.789" (SSS) or "0.7890" (SSSS)
+            // in the resulting formatted output.
+            if (current == null) {
+                value = (int) (((double) value / 1000) * Math.pow(10, count));
+                zeroPaddingNumber(value, count, count, buffer);
+            }
+            break;
+        // END Android-added: Better UTS#35 conformity for fractional seconds.
+
+        default:
+     // case PATTERN_DAY_OF_MONTH:         // 'd'
+     // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
+     // case PATTERN_MINUTE:               // 'm'
+     // case PATTERN_SECOND:               // 's'
+     // Android-removed: PATTERN_MILLISECONDS handled in an explicit case above.
+     //// case PATTERN_MILLISECOND:          // 'S'
+     // case PATTERN_DAY_OF_YEAR:          // 'D'
+     // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
+     // case PATTERN_WEEK_OF_YEAR:         // 'w'
+     // case PATTERN_WEEK_OF_MONTH:        // 'W'
+     // case PATTERN_HOUR0:                // 'K' eg, 11PM + 1 hour =>> 0 AM
+     // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' pseudo field, Monday = 1, ..., Sunday = 7
+            if (current == null) {
+                zeroPaddingNumber(value, count, maxIntCount, buffer);
+            }
+            break;
+        } // switch (patternCharIndex)
+
+        if (current != null) {
+            buffer.append(current);
+        }
+
+        int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
+        Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
+
+        delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
+    }
+
+    // BEGIN Android-added: formatWeekday() and formatMonth() methods to format using ICU data.
+    private String formatWeekday(int count, int value, boolean useDateFormatSymbols,
+                                 boolean standalone) {
+        if (useDateFormatSymbols) {
+            final String[] weekdays;
+            if (count == 4) {
+                weekdays = standalone ? formatData.getStandAloneWeekdays() : formatData.getWeekdays();
+            } else if (count == 5) {
+                weekdays =
+                        standalone ? formatData.getTinyStandAloneWeekdays() : formatData.getTinyWeekdays();
+
+            } else { // count < 4, use abbreviated form if exists
+                weekdays = standalone ? formatData.getShortStandAloneWeekdays() : formatData.getShortWeekdays();
+            }
+
+            return weekdays[value];
+        }
+
+        return null;
+    }
+
+    private String formatMonth(int count, int value, int maxIntCount, StringBuffer buffer,
+                               boolean useDateFormatSymbols, boolean standalone,
+                               int field, int style) {
+        String current = null;
+        if (useDateFormatSymbols) {
+            final String[] months;
+            if (count == 4) {
+                months = standalone ? formatData.getStandAloneMonths() : formatData.getMonths();
+            } else if (count == 5) {
+                months = standalone ? formatData.getTinyStandAloneMonths() : formatData.getTinyMonths();
+            } else if (count == 3) {
+                months = standalone ? formatData.getShortStandAloneMonths() : formatData.getShortMonths();
+            } else {
+                months = null;
+            }
+
+            if (months != null) {
+                current = months[value];
+            }
+        } else {
+            if (count < 3) {
+                current = null;
+            } else {
+                if (standalone) {
+                    style = Calendar.toStandaloneStyle(style);
+                }
+                current = calendar.getDisplayName(field, style, locale);
+            }
+        }
+
+        if (current == null) {
+            zeroPaddingNumber(value+1, count, maxIntCount, buffer);
+        }
+
+        return current;
+    }
+    // END Android-added: formatWeekday() and formatMonth() methods to format using ICU data.
+
+    /**
+     * Formats a number with the specified minimum and maximum number of digits.
+     */
+    private void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
+    {
+        // Optimization for 1, 2 and 4 digit numbers. This should
+        // cover most cases of formatting date/time related items.
+        // Note: This optimization code assumes that maxDigits is
+        // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
+        try {
+            if (zeroDigit == 0) {
+                zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
+            }
+            if (value >= 0) {
+                if (value < 100 && minDigits >= 1 && minDigits <= 2) {
+                    if (value < 10) {
+                        if (minDigits == 2) {
+                            buffer.append(zeroDigit);
+                        }
+                        buffer.append((char)(zeroDigit + value));
+                    } else {
+                        buffer.append((char)(zeroDigit + value / 10));
+                        buffer.append((char)(zeroDigit + value % 10));
+                    }
+                    return;
+                } else if (value >= 1000 && value < 10000) {
+                    if (minDigits == 4) {
+                        buffer.append((char)(zeroDigit + value / 1000));
+                        value %= 1000;
+                        buffer.append((char)(zeroDigit + value / 100));
+                        value %= 100;
+                        buffer.append((char)(zeroDigit + value / 10));
+                        buffer.append((char)(zeroDigit + value % 10));
+                        return;
+                    }
+                    if (minDigits == 2 && maxDigits == 2) {
+                        zeroPaddingNumber(value % 100, 2, 2, buffer);
+                        return;
+                    }
+                }
+            }
+        } catch (Exception e) {
+        }
+
+        numberFormat.setMinimumIntegerDigits(minDigits);
+        numberFormat.setMaximumIntegerDigits(maxDigits);
+        numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
+    }
+
+
+    /**
+     * Parses text from a string to produce a <code>Date</code>.
+     * <p>
+     * The method attempts to parse text starting at the index given by
+     * <code>pos</code>.
+     * If parsing succeeds, then the index of <code>pos</code> is updated
+     * to the index after the last character used (parsing does not necessarily
+     * use all characters up to the end of the string), and the parsed
+     * date is returned. The updated <code>pos</code> can be used to
+     * indicate the starting point for the next call to this method.
+     * If an error occurs, then the index of <code>pos</code> is not
+     * changed, the error index of <code>pos</code> is set to the index of
+     * the character where the error occurred, and null is returned.
+     *
+     * <p>This parsing operation uses the {@link DateFormat#calendar
+     * calendar} to produce a {@code Date}. All of the {@code
+     * calendar}'s date-time fields are {@linkplain Calendar#clear()
+     * cleared} before parsing, and the {@code calendar}'s default
+     * values of the date-time fields are used for any missing
+     * date-time information. For example, the year value of the
+     * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
+     * no year value is given from the parsing operation.  The {@code
+     * TimeZone} value may be overwritten, depending on the given
+     * pattern and the time zone value in {@code text}. Any {@code
+     * TimeZone} value that has previously been set by a call to
+     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
+     * to be restored for further operations.
+     *
+     * @param text  A <code>String</code>, part of which should be parsed.
+     * @param pos   A <code>ParsePosition</code> object with index and error
+     *              index information as described above.
+     * @return A <code>Date</code> parsed from the string. In case of
+     *         error, returns null.
+     * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
+     */
+    @Override
+    public Date parse(String text, ParsePosition pos) {
+        // BEGIN Android-changed: extract parseInternal() and avoid modifying timezone during parse.
+        // Make sure the timezone associated with this dateformat instance (set via
+        // {@code setTimeZone} isn't change as a side-effect of parsing a date.
+        final TimeZone tz = getTimeZone();
+        try {
+            return parseInternal(text, pos);
+        } finally {
+            setTimeZone(tz);
+        }
+    }
+
+    private Date parseInternal(String text, ParsePosition pos)
+    {
+        // END Android-changed: extract parseInternal() and avoid modifying timezone during parse.
+        checkNegativeNumberExpression();
+
+        int start = pos.index;
+        int oldStart = start;
+        int textLength = text.length();
+
+        boolean[] ambiguousYear = {false};
+
+        CalendarBuilder calb = new CalendarBuilder();
+
+        for (int i = 0; i < compiledPattern.length; ) {
+            int tag = compiledPattern[i] >>> 8;
+            int count = compiledPattern[i++] & 0xff;
+            if (count == 255) {
+                count = compiledPattern[i++] << 16;
+                count |= compiledPattern[i++];
+            }
+
+            switch (tag) {
+            case TAG_QUOTE_ASCII_CHAR:
+                if (start >= textLength || text.charAt(start) != (char)count) {
+                    pos.index = oldStart;
+                    pos.errorIndex = start;
+                    return null;
+                }
+                start++;
+                break;
+
+            case TAG_QUOTE_CHARS:
+                while (count-- > 0) {
+                    if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
+                        pos.index = oldStart;
+                        pos.errorIndex = start;
+                        return null;
+                    }
+                    start++;
+                }
+                break;
+
+            default:
+                // Peek the next pattern to determine if we need to
+                // obey the number of pattern letters for
+                // parsing. It's required when parsing contiguous
+                // digit text (e.g., "20010704") with a pattern which
+                // has no delimiters between fields, like "yyyyMMdd".
+                boolean obeyCount = false;
+
+                // In Arabic, a minus sign for a negative number is put after
+                // the number. Even in another locale, a minus sign can be
+                // put after a number using DateFormat.setNumberFormat().
+                // If both the minus sign and the field-delimiter are '-',
+                // subParse() needs to determine whether a '-' after a number
+                // in the given text is a delimiter or is a minus sign for the
+                // preceding number. We give subParse() a clue based on the
+                // information in compiledPattern.
+                boolean useFollowingMinusSignAsDelimiter = false;
+
+                if (i < compiledPattern.length) {
+                    int nextTag = compiledPattern[i] >>> 8;
+                    if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
+                          nextTag == TAG_QUOTE_CHARS)) {
+                        obeyCount = true;
+                    }
+
+                    if (hasFollowingMinusSign &&
+                        (nextTag == TAG_QUOTE_ASCII_CHAR ||
+                         nextTag == TAG_QUOTE_CHARS)) {
+                        int c;
+                        if (nextTag == TAG_QUOTE_ASCII_CHAR) {
+                            c = compiledPattern[i] & 0xff;
+                        } else {
+                            c = compiledPattern[i+1];
+                        }
+
+                        if (c == minusSign) {
+                            useFollowingMinusSignAsDelimiter = true;
+                        }
+                    }
+                }
+                start = subParse(text, start, tag, count, obeyCount,
+                                 ambiguousYear, pos,
+                                 useFollowingMinusSignAsDelimiter, calb);
+                if (start < 0) {
+                    pos.index = oldStart;
+                    return null;
+                }
+            }
+        }
+
+        // At this point the fields of Calendar have been set.  Calendar
+        // will fill in default values for missing fields when the time
+        // is computed.
+
+        pos.index = start;
+
+        Date parsedDate;
+        try {
+            parsedDate = calb.establish(calendar).getTime();
+            // If the year value is ambiguous,
+            // then the two-digit year == the default start year
+            if (ambiguousYear[0]) {
+                if (parsedDate.before(defaultCenturyStart)) {
+                    parsedDate = calb.addYear(100).establish(calendar).getTime();
+                }
+            }
+        }
+        // An IllegalArgumentException will be thrown by Calendar.getTime()
+        // if any fields are out of range, e.g., MONTH == 17.
+        catch (IllegalArgumentException e) {
+            pos.errorIndex = start;
+            pos.index = oldStart;
+            return null;
+        }
+
+        return parsedDate;
+    }
+
+    /**
+     * Private code-size reduction function used by subParse.
+     * @param text the time text being parsed.
+     * @param start where to start parsing.
+     * @param field the date field being parsed.
+     * @param data the string array to parsed.
+     * @return the new start position if matching succeeded; a negative number
+     * indicating matching failure, otherwise.
+     */
+    private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
+    {
+        int i = 0;
+        int count = data.length;
+
+        if (field == Calendar.DAY_OF_WEEK) {
+            i = 1;
+        }
+
+        // There may be multiple strings in the data[] array which begin with
+        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
+        // We keep track of the longest match, and return that.  Note that this
+        // unfortunately requires us to test all array elements.
+        int bestMatchLength = 0, bestMatch = -1;
+        for (; i<count; ++i)
+        {
+            int length = data[i].length();
+            // Always compare if we have no match yet; otherwise only compare
+            // against potentially better matches (longer strings).
+            if (length > bestMatchLength &&
+                text.regionMatches(true, start, data[i], 0, length))
+            {
+                bestMatch = i;
+                bestMatchLength = length;
+            }
+
+            // BEGIN Android-changed: Handle abbreviated fields that end with a '.'.
+            // When the input option ends with a period (usually an abbreviated form), attempt
+            // to match all chars up to that period.
+            if ((data[i].charAt(length - 1) == '.') &&
+                    ((length - 1) > bestMatchLength) &&
+                    text.regionMatches(true, start, data[i], 0, length - 1)) {
+                bestMatch = i;
+                bestMatchLength = (length - 1);
+            }
+            // END Android-changed: Handle abbreviated fields that end with a '.'.
+        }
+        if (bestMatch >= 0)
+        {
+            calb.set(field, bestMatch);
+            return start + bestMatchLength;
+        }
+        return -start;
+    }
+
+    /**
+     * Performs the same thing as matchString(String, int, int,
+     * String[]). This method takes a Map<String, Integer> instead of
+     * String[].
+     */
+    private int matchString(String text, int start, int field,
+                            Map<String,Integer> data, CalendarBuilder calb) {
+        if (data != null) {
+            // TODO: make this default when it's in the spec.
+            // BEGIN Android-changed: SortedMap instance lookup optimization in matchString().
+            // RI returns not the longest match as matchString(String[]) does. http://b/119913354
+            /*
+            if (data instanceof SortedMap) {
+                for (String name : data.keySet()) {
+            */
+            if (data instanceof NavigableMap && ((NavigableMap) data).comparator() == null) {
+                for (String name : ((NavigableMap<String, Integer>) data).descendingKeySet()) {
+            // END Android-changed: SortedMap instance lookup optimization in matchString().
+                    if (text.regionMatches(true, start, name, 0, name.length())) {
+                        calb.set(field, data.get(name));
+                        return start + name.length();
+                    }
+                }
+                return -start;
+            }
+
+            String bestMatch = null;
+
+            for (String name : data.keySet()) {
+                int length = name.length();
+                if (bestMatch == null || length > bestMatch.length()) {
+                    if (text.regionMatches(true, start, name, 0, length)) {
+                        bestMatch = name;
+                    }
+                }
+            }
+
+            if (bestMatch != null) {
+                calb.set(field, data.get(bestMatch));
+                return start + bestMatch.length();
+            }
+        }
+        return -start;
+    }
+
+    private int matchZoneString(String text, int start, String[] zoneNames) {
+        for (int i = 1; i <= 4; ++i) {
+            // Checking long and short zones [1 & 2],
+            // and long and short daylight [3 & 4].
+            String zoneName = zoneNames[i];
+            if (text.regionMatches(true, start,
+                                   zoneName, 0, zoneName.length())) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    // BEGIN Android-removed: Unused private method matchDSTString.
+    /*
+    private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
+                                   String[][] zoneStrings) {
+        int index = standardIndex + 2;
+        String zoneName  = zoneStrings[zoneIndex][index];
+        if (text.regionMatches(true, start,
+                               zoneName, 0, zoneName.length())) {
+            return true;
+        }
+        return false;
+    }
+    */
+    // END Android-removed: Unused private method matchDSTString.
+
+    // BEGIN Android-changed: Parse time zone strings using ICU TimeZoneNames.
+    // Note that this change falls back to the upstream zone names parsing code if the zoneStrings
+    // for the formatData field has been set by the user. The original code of subParseZoneString
+    // can be found in subParseZoneStringFromSymbols().
+    /**
+     * Parses the string in {@code text} (starting at {@code start}), interpreting it as a time zone
+     * name. If a time zone is found, the internal calendar is set to that timezone and the index of
+     * the first character after the time zone name is returned. Otherwise, returns {@code 0}.
+     * @return the index of the next character to parse or {@code 0} on error.
+     */
+    private int subParseZoneString(String text, int start, CalendarBuilder calb) {
+        if (formatData.isZoneStringsSet) {
+            // DateFormatSymbols.setZoneStrings() has be used, use those values instead of ICU code.
+            return subParseZoneStringFromSymbols(text, start, calb);
+        } else {
+            return subParseZoneStringFromICU(text, start, calb);
+        }
+    }
+
+    private TimeZoneNames getTimeZoneNames() {
+        if (timeZoneNames == null) {
+            timeZoneNames = TimeZoneNames.getInstance(locale);
+        }
+        return timeZoneNames;
+    }
+
+    /**
+     * The set of name types accepted when parsing time zone names.
+     */
+    private static final EnumSet<TimeZoneNames.NameType> NAME_TYPES =
+            EnumSet.of(TimeZoneNames.NameType.LONG_GENERIC, TimeZoneNames.NameType.LONG_STANDARD,
+                    TimeZoneNames.NameType.LONG_DAYLIGHT, TimeZoneNames.NameType.SHORT_GENERIC,
+                    TimeZoneNames.NameType.SHORT_STANDARD, TimeZoneNames.NameType.SHORT_DAYLIGHT);
+
+    /**
+     * Time zone name types that indicate daylight saving time.
+     */
+    private static final Set<TimeZoneNames.NameType> DST_NAME_TYPES =
+            Collections.unmodifiableSet(EnumSet.of(
+                    TimeZoneNames.NameType.LONG_DAYLIGHT, TimeZoneNames.NameType.SHORT_DAYLIGHT));
+
+    /**
+     * Parses the time zone string using the ICU4J class {@link TimeZoneNames}.
+     */
+    private int subParseZoneStringFromICU(String text, int start, CalendarBuilder calb) {
+        String currentTimeZoneID = android.icu.util.TimeZone.getCanonicalID(getTimeZone().getID());
+
+        TimeZoneNames tzNames = getTimeZoneNames();
+        TimeZoneNames.MatchInfo bestMatch = null;
+        // The MetaZones associated with the current time zone are needed in two places, both of
+        // which are avoided in some cases, so they are computed lazily.
+        Set<String> currentTzMetaZoneIds = null;
+
+        Collection<TimeZoneNames.MatchInfo> matches = tzNames.find(text, start, NAME_TYPES);
+        for (TimeZoneNames.MatchInfo match : matches) {
+            if (bestMatch == null || bestMatch.matchLength() < match.matchLength()) {
+                bestMatch = match;
+            } else if (bestMatch.matchLength() == match.matchLength()) {
+                if (currentTimeZoneID.equals(match.tzID())) {
+                    // Prefer the currently set timezone over other matches, even if they are
+                    // the same length.
+                    bestMatch = match;
+                    break;
+                } else if (match.mzID() != null) {
+                    if (currentTzMetaZoneIds == null) {
+                        currentTzMetaZoneIds =
+                                tzNames.getAvailableMetaZoneIDs(currentTimeZoneID);
+                    }
+                    if (currentTzMetaZoneIds.contains(match.mzID())) {
+                        bestMatch = match;
+                        break;
+                    }
+                }
+            }
+        }
+        if (bestMatch == null) {
+            // No match found, return error.
+            return -start;
+        }
+
+        String tzId = bestMatch.tzID();
+        if (tzId == null) {
+            if (currentTzMetaZoneIds == null) {
+                currentTzMetaZoneIds = tzNames.getAvailableMetaZoneIDs(currentTimeZoneID);
+            }
+            if (currentTzMetaZoneIds.contains(bestMatch.mzID())) {
+                tzId = currentTimeZoneID;
+            } else {
+                // Match was for a meta-zone, find the matching reference zone.
+                ULocale uLocale = ULocale.forLocale(locale);
+                String region = uLocale.getCountry();
+                if (region.length() == 0) {
+                    uLocale = ULocale.addLikelySubtags(uLocale);
+                    region = uLocale.getCountry();
+                }
+                tzId = tzNames.getReferenceZoneID(bestMatch.mzID(), region);
+            }
+        }
+
+        TimeZone newTimeZone = TimeZone.getTimeZone(tzId);
+        if (!currentTimeZoneID.equals(tzId)) {
+            setTimeZone(newTimeZone);
+        }
+
+        // Same logic as in subParseZoneStringFromSymbols, see below for details.
+        boolean isDst = DST_NAME_TYPES.contains(bestMatch.nameType());
+        int dstAmount = isDst ? newTimeZone.getDSTSavings() : 0;
+        if (!isDst || dstAmount != 0) {
+            calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount);
+        }
+
+        return bestMatch.matchLength() + start;
+    }
+
+    /**
+     * Parses the time zone string using the information in {@link #formatData}.
+     */
+    private int subParseZoneStringFromSymbols(String text, int start, CalendarBuilder calb) {
+        // END Android-changed: Parse time zone strings using ICU TimeZoneNames.
+        boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
+        TimeZone currentTimeZone = getTimeZone();
+
+        // At this point, check for named time zones by looking through
+        // the locale data from the TimeZoneNames strings.
+        // Want to be able to parse both short and long forms.
+        int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
+        TimeZone tz = null;
+        String[][] zoneStrings = formatData.getZoneStringsWrapper();
+        String[] zoneNames = null;
+        int nameIndex = 0;
+        if (zoneIndex != -1) {
+            zoneNames = zoneStrings[zoneIndex];
+            if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
+                if (nameIndex <= 2) {
+                    // Check if the standard name (abbr) and the daylight name are the same.
+                    useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
+                }
+                tz = TimeZone.getTimeZone(zoneNames[0]);
+            }
+        }
+        if (tz == null) {
+            zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
+            if (zoneIndex != -1) {
+                zoneNames = zoneStrings[zoneIndex];
+                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
+                    if (nameIndex <= 2) {
+                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
+                    }
+                    tz = TimeZone.getTimeZone(zoneNames[0]);
+                }
+            }
+        }
+
+        if (tz == null) {
+            int len = zoneStrings.length;
+            for (int i = 0; i < len; i++) {
+                zoneNames = zoneStrings[i];
+                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
+                    if (nameIndex <= 2) {
+                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
+                    }
+                    tz = TimeZone.getTimeZone(zoneNames[0]);
+                    break;
+                }
+            }
+        }
+        if (tz != null) { // Matched any ?
+            if (!tz.equals(currentTimeZone)) {
+                setTimeZone(tz);
+            }
+            // If the time zone matched uses the same name
+            // (abbreviation) for both standard and daylight time,
+            // let the time zone in the Calendar decide which one.
+            //
+            // Also if tz.getDSTSaving() returns 0 for DST, use tz to
+            // determine the local time. (6645292)
+            int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
+            if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
+                calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount);
+            }
+            return (start + zoneNames[nameIndex].length());
+        }
+        return -start;
+    }
+
+    /**
+     * Parses numeric forms of time zone offset, such as "hh:mm", and
+     * sets calb to the parsed value.
+     *
+     * @param text  the text to be parsed
+     * @param start the character position to start parsing
+     * @param sign  1: positive; -1: negative
+     * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
+     * @param colon true - colon required between hh and mm; false - no colon required
+     * @param calb  a CalendarBuilder in which the parsed value is stored
+     * @return updated parsed position, or its negative value to indicate a parsing error
+     */
+    private int subParseNumericZone(String text, int start, int sign, int count,
+                                    boolean colon, CalendarBuilder calb) {
+        int index = start;
+
+      parse:
+        try {
+            char c = text.charAt(index++);
+            // Parse hh
+            int hours;
+            if (!isDigit(c)) {
+                break parse;
+            }
+            hours = c - '0';
+            c = text.charAt(index++);
+            if (isDigit(c)) {
+                hours = hours * 10 + (c - '0');
+            } else {
+                // BEGIN Android-removed: Be more tolerant of colon. b/26426526
+                /*
+                // If no colon in RFC 822 or 'X' (ISO), two digits are
+                // required.
+                if (count > 0 || !colon) {
+                    break parse;
+                }
+                */
+                // END Android-removed: Be more tolerant of colon. b/26426526
+                --index;
+            }
+            if (hours > 23) {
+                break parse;
+            }
+            int minutes = 0;
+            if (count != 1) {
+                // Proceed with parsing mm
+                c = text.charAt(index++);
+                // BEGIN Android-changed: Be more tolerant of colon. b/26426526
+                // OpenJDK will return an error code if a : is found and colonRequired is false,
+                // this will return an error code if a : is not found and colonRequired is true.
+                //
+                //   colon       | c == ':' | OpenJDK | this
+                //   false       |  false   |   ok    |  ok
+                //   false       |  true    |  error  |  ok
+                //   true        |  false   |   ok    | error
+                //   true        |  true    |   ok    |  ok
+                /*
+                if (colon) {
+                    if (c != ':') {
+                        break parse;
+                    }
+                */
+                if (c == ':') {
+                    c = text.charAt(index++);
+                } else if (colon) {
+                    break parse;
+                }
+                // END Android-changed: Be more tolerant of colon. b/26426526
+                if (!isDigit(c)) {
+                    break parse;
+                }
+                minutes = c - '0';
+                c = text.charAt(index++);
+                if (!isDigit(c)) {
+                    break parse;
+                }
+                minutes = minutes * 10 + (c - '0');
+                if (minutes > 59) {
+                    break parse;
+                }
+            }
+            minutes += hours * 60;
+            calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
+                .set(Calendar.DST_OFFSET, 0);
+            return index;
+        } catch (IndexOutOfBoundsException e) {
+        }
+        return  1 - index; // -(index - 1)
+    }
+
+    private boolean isDigit(char c) {
+        return c >= '0' && c <= '9';
+    }
+
+    /**
+     * Private member function that converts the parsed date strings into
+     * timeFields. Returns -start (for ParsePosition) if failed.
+     * @param text the time text to be parsed.
+     * @param start where to start parsing.
+     * @param patternCharIndex the index of the pattern character.
+     * @param count the count of a pattern character.
+     * @param obeyCount if true, then the next field directly abuts this one,
+     * and we should use the count to know when to stop parsing.
+     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
+     * is true, then a two-digit year was parsed and may need to be readjusted.
+     * @param origPos origPos.errorIndex is used to return an error index
+     * at which a parse error occurred, if matching failure occurs.
+     * @return the new start position if matching succeeded; -1 indicating
+     * matching failure, otherwise. In case matching failure occurred,
+     * an error index is set to origPos.errorIndex.
+     */
+    private int subParse(String text, int start, int patternCharIndex, int count,
+                         boolean obeyCount, boolean[] ambiguousYear,
+                         ParsePosition origPos,
+                         boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
+        Number number;
+        int value = 0;
+        ParsePosition pos = new ParsePosition(0);
+        pos.index = start;
+        if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
+            // use calendar year 'y' instead
+            patternCharIndex = PATTERN_YEAR;
+        }
+        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
+
+        // If there are any spaces here, skip over them.  If we hit the end
+        // of the string, then fail.
+        for (;;) {
+            if (pos.index >= text.length()) {
+                origPos.errorIndex = start;
+                return -1;
+            }
+            char c = text.charAt(pos.index);
+            if (c != ' ' && c != '\t') {
+                break;
+            }
+            ++pos.index;
+        }
+        // Remember the actual start index
+        int actualStart = pos.index;
+
+      parsing:
+        {
+            // We handle a few special cases here where we need to parse
+            // a number value.  We handle further, more generic cases below.  We need
+            // to handle some of them here because some fields require extra processing on
+            // the parsed value.
+            if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
+                patternCharIndex == PATTERN_HOUR1 ||
+                (patternCharIndex == PATTERN_MONTH && count <= 2) ||
+                patternCharIndex == PATTERN_YEAR ||
+                patternCharIndex == PATTERN_WEEK_YEAR) {
+                // It would be good to unify this with the obeyCount logic below,
+                // but that's going to be difficult.
+                if (obeyCount) {
+                    if ((start+count) > text.length()) {
+                        break parsing;
+                    }
+                    number = numberFormat.parse(text.substring(0, start+count), pos);
+                } else {
+                    number = numberFormat.parse(text, pos);
+                }
+                if (number == null) {
+                    if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
+                        break parsing;
+                    }
+                } else {
+                    value = number.intValue();
+
+                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
+                        (((pos.index < text.length()) &&
+                         (text.charAt(pos.index) != minusSign)) ||
+                         ((pos.index == text.length()) &&
+                          (text.charAt(pos.index-1) == minusSign)))) {
+                        value = -value;
+                        pos.index--;
+                    }
+                }
+            }
+
+            boolean useDateFormatSymbols = useDateFormatSymbols();
+
+            int index;
+            switch (patternCharIndex) {
+            case PATTERN_ERA: // 'G'
+                if (useDateFormatSymbols) {
+                    if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
+                        return index;
+                    }
+                } else {
+                    Map<String, Integer> map = getDisplayNamesMap(field, locale);
+                    if ((index = matchString(text, start, field, map, calb)) > 0) {
+                        return index;
+                    }
+                }
+                break parsing;
+
+            case PATTERN_WEEK_YEAR: // 'Y'
+            case PATTERN_YEAR:      // 'y'
+                if (!(calendar instanceof GregorianCalendar)) {
+                    // calendar might have text representations for year values,
+                    // such as "\u5143" in JapaneseImperialCalendar.
+                    int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
+                    Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
+                    if (map != null) {
+                        if ((index = matchString(text, start, field, map, calb)) > 0) {
+                            return index;
+                        }
+                    }
+                    calb.set(field, value);
+                    return pos.index;
+                }
+
+                // If there are 3 or more YEAR pattern characters, this indicates
+                // that the year value is to be treated literally, without any
+                // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
+                // we made adjustments to place the 2-digit year in the proper
+                // century, for parsed strings from "00" to "99".  Any other string
+                // is treated literally:  "2250", "-1", "1", "002".
+                if (count <= 2 && (pos.index - actualStart) == 2
+                    && Character.isDigit(text.charAt(actualStart))
+                    && Character.isDigit(text.charAt(actualStart + 1))) {
+                    // Assume for example that the defaultCenturyStart is 6/18/1903.
+                    // This means that two-digit years will be forced into the range
+                    // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
+                    // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
+                    // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
+                    // other fields specify a date before 6/18, or 1903 if they specify a
+                    // date afterwards.  As a result, 03 is an ambiguous year.  All other
+                    // two-digit years are unambiguous.
+                    int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
+                    ambiguousYear[0] = value == ambiguousTwoDigitYear;
+                    value += (defaultCenturyStartYear/100)*100 +
+                        (value < ambiguousTwoDigitYear ? 100 : 0);
+                }
+                calb.set(field, value);
+                return pos.index;
+
+            case PATTERN_MONTH: // 'M'
+            // BEGIN Android-changed: extract parseMonth method.
+            /*
+                if (count <= 2) // i.e., M or MM.
+                {
+                    // Don't want to parse the month if it is a string
+                    // while pattern uses numeric style: M or MM.
+                    // [We computed 'value' above.]
+                    calb.set(Calendar.MONTH, value - 1);
+                    return pos.index;
+                }
+
+                if (useDateFormatSymbols) {
+                    // count >= 3 // i.e., MMM or MMMM
+                    // Want to be able to parse both short and long forms.
+                    // Try count == 4 first:
+                    int newStart;
+                    if ((newStart = matchString(text, start, Calendar.MONTH,
+                                                formatData.getMonths(), calb)) > 0) {
+                        return newStart;
+                    }
+                    // count == 4 failed, now try count == 3
+                    if ((index = matchString(text, start, Calendar.MONTH,
+                                             formatData.getShortMonths(), calb)) > 0) {
+                        return index;
+                    }
+                } else {
+                    Map<String, Integer> map = getDisplayNamesMap(field, locale);
+                    if ((index = matchString(text, start, field, map, calb)) > 0) {
+                        return index;
+                    }
+                }
+            */
+            {
+                final int idx = parseMonth(text, count, value, start, field, pos,
+                        useDateFormatSymbols, false /* isStandalone */, calb);
+                if (idx > 0) {
+                    return idx;
+                }
+
+                break parsing;
+            }
+
+            case PATTERN_MONTH_STANDALONE: // 'L'.
+            {
+                final int idx = parseMonth(text, count, value, start, field, pos,
+                        useDateFormatSymbols, true /* isStandalone */, calb);
+                if (idx > 0) {
+                    return idx;
+                }
+                break parsing;
+            }
+            // END Android-changed: extract parseMonth method.
+
+            case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
+                if (!isLenient()) {
+                    // Validate the hour value in non-lenient
+                    if (value < 1 || value > 24) {
+                        break parsing;
+                    }
+                }
+                // [We computed 'value' above.]
+                if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1) {
+                    value = 0;
+                }
+                calb.set(Calendar.HOUR_OF_DAY, value);
+                return pos.index;
+
+            case PATTERN_DAY_OF_WEEK:  // 'E'
+            // BEGIN Android-changed: extract parseWeekday method.
+            /*
+                {
+                    if (useDateFormatSymbols) {
+                        // Want to be able to parse both short and long forms.
+                        // Try count == 4 (DDDD) first:
+                        int newStart;
+                        if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
+                                                  formatData.getWeekdays(), calb)) > 0) {
+                            return newStart;
+                        }
+                        // DDDD failed, now try DDD
+                        if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
+                                                 formatData.getShortWeekdays(), calb)) > 0) {
+                            return index;
+                        }
+                    } else {
+                        int[] styles = { Calendar.LONG, Calendar.SHORT };
+                        for (int style : styles) {
+                            Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
+                            if ((index = matchString(text, start, field, map, calb)) > 0) {
+                                return index;
+                            }
+                        }
+                    }
+                }
+            */
+            {
+                final int idx = parseWeekday(text, start, field, useDateFormatSymbols,
+                        false /* standalone */, calb);
+                if (idx > 0) {
+                    return idx;
+                }
+                break parsing;
+            }
+            // END Android-changed: extract parseWeekday method.
+
+            // BEGIN Android-added: support for 'c' (standalone day of week).
+            case PATTERN_STANDALONE_DAY_OF_WEEK: // 'c'
+            {
+                final int idx = parseWeekday(text, start, field, useDateFormatSymbols,
+                        true /* standalone */, calb);
+                if (idx > 0) {
+                    return idx;
+                }
+
+                break parsing;
+            }
+            // END Android-added: support for 'c' (standalone day of week).
+
+            case PATTERN_AM_PM:    // 'a'
+                if (useDateFormatSymbols) {
+                    if ((index = matchString(text, start, Calendar.AM_PM,
+                                             formatData.getAmPmStrings(), calb)) > 0) {
+                        return index;
+                    }
+                } else {
+                    Map<String,Integer> map = getDisplayNamesMap(field, locale);
+                    if ((index = matchString(text, start, field, map, calb)) > 0) {
+                        return index;
+                    }
+                }
+                break parsing;
+
+            case PATTERN_HOUR1: // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
+                if (!isLenient()) {
+                    // Validate the hour value in non-lenient
+                    if (value < 1 || value > 12) {
+                        break parsing;
+                    }
+                }
+                // [We computed 'value' above.]
+                if (value == calendar.getLeastMaximum(Calendar.HOUR) + 1) {
+                    value = 0;
+                }
+                calb.set(Calendar.HOUR, value);
+                return pos.index;
+
+            case PATTERN_ZONE_NAME:  // 'z'
+            case PATTERN_ZONE_VALUE: // 'Z'
+                {
+                    int sign = 0;
+                    try {
+                        char c = text.charAt(pos.index);
+                        if (c == '+') {
+                            sign = 1;
+                        } else if (c == '-') {
+                            sign = -1;
+                        }
+                        if (sign == 0) {
+                            // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
+                            if ((c == 'G' || c == 'g')
+                                && (text.length() - start) >= GMT.length()
+                                && text.regionMatches(true, start, GMT, 0, GMT.length())) {
+                                pos.index = start + GMT.length();
+
+                                if ((text.length() - pos.index) > 0) {
+                                    c = text.charAt(pos.index);
+                                    if (c == '+') {
+                                        sign = 1;
+                                    } else if (c == '-') {
+                                        sign = -1;
+                                    }
+                                }
+
+                                if (sign == 0) {    /* "GMT" without offset */
+                                    calb.set(Calendar.ZONE_OFFSET, 0)
+                                        .set(Calendar.DST_OFFSET, 0);
+                                    return pos.index;
+                                }
+
+                                // BEGIN Android-changed: Be more tolerant of colon. b/26426526
+                                /*
+                                // Parse the rest as "hh:mm"
+                                int i = subParseNumericZone(text, ++pos.index,
+                                                            sign, 0, true, calb);
+                                */
+                                // Parse the rest as "hh[:]?mm"
+                                int i = subParseNumericZone(text, ++pos.index, sign, 0,
+                                        false, calb);
+                                // END Android-changed: Be more tolerant of colon. b/26426526
+                                if (i > 0) {
+                                    return i;
+                                }
+                                pos.index = -i;
+                            } else {
+                                // Try parsing the text as a time zone
+                                // name or abbreviation.
+                                int i = subParseZoneString(text, pos.index, calb);
+                                if (i > 0) {
+                                    return i;
+                                }
+                                pos.index = -i;
+                            }
+                        } else {
+                            // BEGIN Android-changed: Be more tolerant of colon. b/26426526
+                            // Parse the rest as "hh[:]?mm" (RFC 822)
+                            /*
+                            // Parse the rest as "hhmm" (RFC 822)
+                            int i = subParseNumericZone(text, ++pos.index,
+                                                        sign, 0, false, calb);
+                            */
+                            int i = subParseNumericZone(text, ++pos.index, sign, 0,
+                                    false, calb);
+                            // END Android-changed: Be more tolerant of colon. b/26426526
+                            if (i > 0) {
+                                return i;
+                            }
+                            pos.index = -i;
+                        }
+                    } catch (IndexOutOfBoundsException e) {
+                    }
+                }
+                break parsing;
+
+            case PATTERN_ISO_ZONE:   // 'X'
+                {
+                    if ((text.length() - pos.index) <= 0) {
+                        break parsing;
+                    }
+
+                    int sign;
+                    char c = text.charAt(pos.index);
+                    if (c == 'Z') {
+                        calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
+                        return ++pos.index;
+                    }
+
+                    // parse text as "+/-hh[[:]mm]" based on count
+                    if (c == '+') {
+                        sign = 1;
+                    } else if (c == '-') {
+                        sign = -1;
+                    } else {
+                        ++pos.index;
+                        break parsing;
+                    }
+                    int i = subParseNumericZone(text, ++pos.index, sign, count,
+                                                count == 3, calb);
+                    if (i > 0) {
+                        return i;
+                    }
+                    pos.index = -i;
+                }
+                break parsing;
+
+            default:
+         // case PATTERN_DAY_OF_MONTH:         // 'd'
+         // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
+         // case PATTERN_MINUTE:               // 'm'
+         // case PATTERN_SECOND:               // 's'
+         // case PATTERN_MILLISECOND:          // 'S'
+         // case PATTERN_DAY_OF_YEAR:          // 'D'
+         // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
+         // case PATTERN_WEEK_OF_YEAR:         // 'w'
+         // case PATTERN_WEEK_OF_MONTH:        // 'W'
+         // case PATTERN_HOUR0:                // 'K' 0-based.  eg, 11PM + 1 hour =>> 0 AM
+         // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' (pseudo field);
+
+                // Handle "generic" fields
+                // BEGIN Android-changed: Better UTS#35 conformity for fractional seconds.
+                // http://b/25863120
+                int parseStart = pos.getIndex();
+                // END Android-changed: Better UTS#35 conformity for fractional seconds.
+                if (obeyCount) {
+                    if ((start+count) > text.length()) {
+                        break parsing;
+                    }
+                    number = numberFormat.parse(text.substring(0, start+count), pos);
+                } else {
+                    number = numberFormat.parse(text, pos);
+                }
+                if (number != null) {
+                    // BEGIN Android-changed: Better UTS#35 conformity for fractional seconds.
+                    /*
+                    value = number.intValue();
+                    */
+                    if (patternCharIndex == PATTERN_MILLISECOND) {
+                        // Fractional seconds must be treated specially. We must always
+                        // normalize them to their fractional second value [0, 1) before we attempt
+                        // to parse them.
+                        //
+                        // Case 1: 11.78 seconds is 11 seconds and 780 (not 78) milliseconds.
+                        // Case 2: 11.7890567 seconds is 11 seconds and 789 (not 7890567) milliseconds.
+                        double doubleValue = number.doubleValue();
+                        int width = pos.getIndex() - parseStart;
+                        final double divisor = Math.pow(10, width);
+                        value = (int) ((doubleValue / divisor) * 1000);
+                    } else {
+                        value = number.intValue();
+                    }
+                    // END Android-changed: Better UTS#35 conformity for fractional seconds.
+
+                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
+                        (((pos.index < text.length()) &&
+                         (text.charAt(pos.index) != minusSign)) ||
+                         ((pos.index == text.length()) &&
+                          (text.charAt(pos.index-1) == minusSign)))) {
+                        value = -value;
+                        pos.index--;
+                    }
+
+                    calb.set(field, value);
+                    return pos.index;
+                }
+                break parsing;
+            }
+        }
+
+        // Parsing failed.
+        origPos.errorIndex = pos.index;
+        return -1;
+    }
+
+    // BEGIN Android-added: parseMonth and parseWeekday methods to parse using ICU data.
+    private int parseMonth(String text, int count, int value, int start,
+                           int field, ParsePosition pos, boolean useDateFormatSymbols,
+                           boolean standalone,
+                           CalendarBuilder out) {
+        if (count <= 2) // i.e., M or MM.
+        {
+            // Don't want to parse the month if it is a string
+            // while pattern uses numeric style: M or MM.
+            // [We computed 'value' above.]
+            out.set(Calendar.MONTH, value - 1);
+            return pos.index;
+        }
+
+        int index = -1;
+        if (useDateFormatSymbols) {
+            // count >= 3 // i.e., MMM or MMMM
+            // Want to be able to parse both short and long forms.
+            // Try count == 4 first:
+            if ((index = matchString(
+                    text, start, Calendar.MONTH,
+                    standalone ? formatData.getStandAloneMonths() : formatData.getMonths(),
+                    out)) > 0) {
+                return index;
+            }
+            // count == 4 failed, now try count == 3
+            if ((index = matchString(
+                    text, start, Calendar.MONTH,
+                    standalone ? formatData.getShortStandAloneMonths() : formatData.getShortMonths(),
+                    out)) > 0) {
+                return index;
+            }
+        } else {
+            Map<String, Integer> map = getDisplayNamesMap(field, locale);
+            if ((index = matchString(text, start, field, map, out)) > 0) {
+                return index;
+            }
+        }
+
+        return index;
+    }
+
+    private int parseWeekday(String text, int start, int field, boolean useDateFormatSymbols,
+                             boolean standalone, CalendarBuilder out) {
+        int index = -1;
+        if (useDateFormatSymbols) {
+            // Want to be able to parse both short and long forms.
+            // Try count == 4 (DDDD) first:
+            if ((index=matchString(
+                    text, start, Calendar.DAY_OF_WEEK,
+                    standalone ? formatData.getStandAloneWeekdays() : formatData.getWeekdays(),
+                    out)) > 0) {
+                return index;
+            }
+
+            // DDDD failed, now try DDD
+            if ((index = matchString(
+                    text, start, Calendar.DAY_OF_WEEK,
+                    standalone ? formatData.getShortStandAloneWeekdays() : formatData.getShortWeekdays(),
+                    out)) > 0) {
+                return index;
+            }
+        } else {
+            int[] styles = { Calendar.LONG, Calendar.SHORT };
+            for (int style : styles) {
+                Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
+                if ((index = matchString(text, start, field, map, out)) > 0) {
+                    return index;
+                }
+            }
+        }
+
+        return index;
+    }
+    // END Android-added: parseMonth and parseWeekday methods to parse using ICU data.
+
+    // Android-changed: Always useDateFormatSymbols() for GregorianCalendar.
+    /**
+     * Returns true if the DateFormatSymbols has been set explicitly or locale
+     * is null or calendar is Gregorian.
+     */
+    private boolean useDateFormatSymbols() {
+        // Android-changed: Always useDateFormatSymbols() for GregorianCalendar.
+        // This is for app compat. http://b/66411240#comment14
+        // return useDateFormatSymbols || locale == null;
+      return useDateFormatSymbols
+          || "java.util.GregorianCalendar".equals(calendar.getClass().getName())
+          || locale == null;
+    }
+
+    /**
+     * Translates a pattern, mapping each character in the from string to the
+     * corresponding character in the to string.
+     *
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    private String translatePattern(String pattern, String from, String to) {
+        StringBuilder result = new StringBuilder();
+        boolean inQuote = false;
+        for (int i = 0; i < pattern.length(); ++i) {
+            char c = pattern.charAt(i);
+            if (inQuote) {
+                if (c == '\'') {
+                    inQuote = false;
+                }
+            }
+            else {
+                if (c == '\'') {
+                    inQuote = true;
+                } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+                    int ci = from.indexOf(c);
+                    if (ci >= 0) {
+                        // patternChars is longer than localPatternChars due
+                        // to serialization compatibility. The pattern letters
+                        // unsupported by localPatternChars pass through.
+                        if (ci < to.length()) {
+                            c = to.charAt(ci);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("Illegal pattern " +
+                                                           " character '" +
+                                                           c + "'");
+                    }
+                }
+            }
+            result.append(c);
+        }
+        if (inQuote) {
+            throw new IllegalArgumentException("Unfinished quote in pattern");
+        }
+        return result.toString();
+    }
+
+    /**
+     * Returns a pattern string describing this date format.
+     *
+     * @return a pattern string describing this date format.
+     */
+    public String toPattern() {
+        return pattern;
+    }
+
+    /**
+     * Returns a localized pattern string describing this date format.
+     *
+     * @return a localized pattern string describing this date format.
+     */
+    public String toLocalizedPattern() {
+        return translatePattern(pattern,
+                                DateFormatSymbols.patternChars,
+                                formatData.getLocalPatternChars());
+    }
+
+    /**
+     * Applies the given pattern string to this date format.
+     *
+     * @param pattern the new date and time pattern for this date format
+     * @exception NullPointerException if the given pattern is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    public void applyPattern(String pattern)
+    {
+        applyPatternImpl(pattern);
+    }
+
+    private void applyPatternImpl(String pattern) {
+        compiledPattern = compile(pattern);
+        this.pattern = pattern;
+    }
+
+    /**
+     * Applies the given localized pattern string to this date format.
+     *
+     * @param pattern a String to be mapped to the new date and time format
+     *        pattern for this format
+     * @exception NullPointerException if the given pattern is null
+     * @exception IllegalArgumentException if the given pattern is invalid
+     */
+    public void applyLocalizedPattern(String pattern) {
+         String p = translatePattern(pattern,
+                                     formatData.getLocalPatternChars(),
+                                     DateFormatSymbols.patternChars);
+         compiledPattern = compile(p);
+         this.pattern = p;
+    }
+
+    /**
+     * Gets a copy of the date and time format symbols of this date format.
+     *
+     * @return the date and time format symbols of this date format
+     * @see #setDateFormatSymbols
+     */
+    public DateFormatSymbols getDateFormatSymbols()
+    {
+        return (DateFormatSymbols)formatData.clone();
+    }
+
+    /**
+     * Sets the date and time format symbols of this date format.
+     *
+     * @param newFormatSymbols the new date and time format symbols
+     * @exception NullPointerException if the given newFormatSymbols is null
+     * @see #getDateFormatSymbols
+     */
+    public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
+    {
+        this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
+        useDateFormatSymbols = true;
+    }
+
+    /**
+     * Creates a copy of this <code>SimpleDateFormat</code>. This also
+     * clones the format's date format symbols.
+     *
+     * @return a clone of this <code>SimpleDateFormat</code>
+     */
+    @Override
+    public Object clone() {
+        SimpleDateFormat other = (SimpleDateFormat) super.clone();
+        other.formatData = (DateFormatSymbols) formatData.clone();
+        return other;
+    }
+
+    /**
+     * Returns the hash code value for this <code>SimpleDateFormat</code> object.
+     *
+     * @return the hash code value for this <code>SimpleDateFormat</code> object.
+     */
+    @Override
+    public int hashCode()
+    {
+        return pattern.hashCode();
+        // just enough fields for a reasonable distribution
+    }
+
+    /**
+     * Compares the given object with this <code>SimpleDateFormat</code> for
+     * equality.
+     *
+     * @return true if the given object is equal to this
+     * <code>SimpleDateFormat</code>
+     */
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (!super.equals(obj)) {
+            return false; // super does class check
+        }
+        SimpleDateFormat that = (SimpleDateFormat) obj;
+        return (pattern.equals(that.pattern)
+                && formatData.equals(that.formatData));
+    }
+
+    private static final int[] REST_OF_STYLES = {
+        Calendar.SHORT_STANDALONE, Calendar.LONG_FORMAT, Calendar.LONG_STANDALONE,
+    };
+    private Map<String, Integer> getDisplayNamesMap(int field, Locale locale) {
+        Map<String, Integer> map = calendar.getDisplayNames(field, Calendar.SHORT_FORMAT, locale);
+        // Get all SHORT and LONG styles (avoid NARROW styles).
+        for (int style : REST_OF_STYLES) {
+            Map<String, Integer> m = calendar.getDisplayNames(field, style, locale);
+            if (m != null) {
+                map.putAll(m);
+            }
+        }
+        return map;
+    }
+
+    /**
+     * After reading an object from the input stream, the format
+     * pattern in the object is verified.
+     * <p>
+     * @exception InvalidObjectException if the pattern is invalid
+     */
+    private void readObject(ObjectInputStream stream)
+                         throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+
+        try {
+            compiledPattern = compile(pattern);
+        } catch (Exception e) {
+            throw new InvalidObjectException("invalid pattern");
+        }
+
+        if (serialVersionOnStream < 1) {
+            // didn't have defaultCenturyStart field
+            initializeDefaultCentury();
+        }
+        else {
+            // fill in dependent transient field
+            parseAmbiguousDatesAsAfter(defaultCenturyStart);
+        }
+        serialVersionOnStream = currentSerialVersion;
+
+        // If the deserialized object has a SimpleTimeZone, try
+        // to replace it with a ZoneInfo equivalent in order to
+        // be compatible with the SimpleTimeZone-based
+        // implementation as much as possible.
+        TimeZone tz = getTimeZone();
+        if (tz instanceof SimpleTimeZone) {
+            String id = tz.getID();
+            TimeZone zi = TimeZone.getTimeZone(id);
+            if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
+                setTimeZone(zi);
+            }
+        }
+    }
+
+    /**
+     * Analyze the negative subpattern of DecimalFormat and set/update values
+     * as necessary.
+     */
+    private void checkNegativeNumberExpression() {
+        if ((numberFormat instanceof DecimalFormat) &&
+            !numberFormat.equals(originalNumberFormat)) {
+            String numberPattern = ((DecimalFormat)numberFormat).toPattern();
+            if (!numberPattern.equals(originalNumberPattern)) {
+                hasFollowingMinusSign = false;
+
+                int separatorIndex = numberPattern.indexOf(';');
+                // If the negative subpattern is not absent, we have to analayze
+                // it in order to check if it has a following minus sign.
+                if (separatorIndex > -1) {
+                    int minusIndex = numberPattern.indexOf('-', separatorIndex);
+                    if ((minusIndex > numberPattern.lastIndexOf('0')) &&
+                        (minusIndex > numberPattern.lastIndexOf('#'))) {
+                        hasFollowingMinusSign = true;
+                        minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
+                    }
+                }
+                originalNumberPattern = numberPattern;
+            }
+            originalNumberFormat = numberFormat;
+        }
+    }
+
+}
diff --git a/java/text/StringCharacterIterator.java b/java/text/StringCharacterIterator.java
new file mode 100644
index 0000000..66b5be6
--- /dev/null
+++ b/java/text/StringCharacterIterator.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.text;
+
+/**
+ * <code>StringCharacterIterator</code> implements the
+ * <code>CharacterIterator</code> protocol for a <code>String</code>.
+ * The <code>StringCharacterIterator</code> class iterates over the
+ * entire <code>String</code>.
+ *
+ * @see CharacterIterator
+ */
+
+public final class StringCharacterIterator implements CharacterIterator
+{
+    private String text;
+    private int begin;
+    private int end;
+    // invariant: begin <= pos <= end
+    private int pos;
+
+    /**
+     * Constructs an iterator with an initial index of 0.
+     *
+     * @param text the {@code String} to be iterated over
+     */
+    public StringCharacterIterator(String text)
+    {
+        this(text, 0);
+    }
+
+    /**
+     * Constructs an iterator with the specified initial index.
+     *
+     * @param  text   The String to be iterated over
+     * @param  pos    Initial iterator position
+     */
+    public StringCharacterIterator(String text, int pos)
+    {
+    this(text, 0, text.length(), pos);
+    }
+
+    /**
+     * Constructs an iterator over the given range of the given string, with the
+     * index set at the specified position.
+     *
+     * @param  text   The String to be iterated over
+     * @param  begin  Index of the first character
+     * @param  end    Index of the character following the last character
+     * @param  pos    Initial iterator position
+     */
+    public StringCharacterIterator(String text, int begin, int end, int pos) {
+        if (text == null)
+            throw new NullPointerException();
+        this.text = text;
+
+        if (begin < 0 || begin > end || end > text.length())
+            throw new IllegalArgumentException("Invalid substring range");
+
+        if (pos < begin || pos > end)
+            throw new IllegalArgumentException("Invalid position");
+
+        this.begin = begin;
+        this.end = end;
+        this.pos = pos;
+    }
+
+    /**
+     * Reset this iterator to point to a new string.  This package-visible
+     * method is used by other java.text classes that want to avoid allocating
+     * new StringCharacterIterator objects every time their setText method
+     * is called.
+     *
+     * @param  text   The String to be iterated over
+     * @since 1.2
+     */
+    public void setText(String text) {
+        if (text == null)
+            throw new NullPointerException();
+        this.text = text;
+        this.begin = 0;
+        this.end = text.length();
+        this.pos = 0;
+    }
+
+    /**
+     * Implements CharacterIterator.first() for String.
+     * @see CharacterIterator#first
+     */
+    public char first()
+    {
+        pos = begin;
+        return current();
+    }
+
+    /**
+     * Implements CharacterIterator.last() for String.
+     * @see CharacterIterator#last
+     */
+    public char last()
+    {
+        if (end != begin) {
+            pos = end - 1;
+        } else {
+            pos = end;
+        }
+        return current();
+     }
+
+    /**
+     * Implements CharacterIterator.setIndex() for String.
+     * @see CharacterIterator#setIndex
+     */
+    public char setIndex(int p)
+    {
+    if (p < begin || p > end)
+            throw new IllegalArgumentException("Invalid index");
+        pos = p;
+        return current();
+    }
+
+    /**
+     * Implements CharacterIterator.current() for String.
+     * @see CharacterIterator#current
+     */
+    public char current()
+    {
+        if (pos >= begin && pos < end) {
+            return text.charAt(pos);
+        }
+        else {
+            return DONE;
+        }
+    }
+
+    /**
+     * Implements CharacterIterator.next() for String.
+     * @see CharacterIterator#next
+     */
+    public char next()
+    {
+        if (pos < end - 1) {
+            pos++;
+            return text.charAt(pos);
+        }
+        else {
+            pos = end;
+            return DONE;
+        }
+    }
+
+    /**
+     * Implements CharacterIterator.previous() for String.
+     * @see CharacterIterator#previous
+     */
+    public char previous()
+    {
+        if (pos > begin) {
+            pos--;
+            return text.charAt(pos);
+        }
+        else {
+            return DONE;
+        }
+    }
+
+    /**
+     * Implements CharacterIterator.getBeginIndex() for String.
+     * @see CharacterIterator#getBeginIndex
+     */
+    public int getBeginIndex()
+    {
+        return begin;
+    }
+
+    /**
+     * Implements CharacterIterator.getEndIndex() for String.
+     * @see CharacterIterator#getEndIndex
+     */
+    public int getEndIndex()
+    {
+        return end;
+    }
+
+    /**
+     * Implements CharacterIterator.getIndex() for String.
+     * @see CharacterIterator#getIndex
+     */
+    public int getIndex()
+    {
+        return pos;
+    }
+
+    /**
+     * Compares the equality of two StringCharacterIterator objects.
+     * @param obj the StringCharacterIterator object to be compared with.
+     * @return true if the given obj is the same as this
+     * StringCharacterIterator object; false otherwise.
+     */
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+            return true;
+        if (!(obj instanceof StringCharacterIterator))
+            return false;
+
+        StringCharacterIterator that = (StringCharacterIterator) obj;
+
+        if (hashCode() != that.hashCode())
+            return false;
+        if (!text.equals(that.text))
+            return false;
+        if (pos != that.pos || begin != that.begin || end != that.end)
+            return false;
+        return true;
+    }
+
+    /**
+     * Computes a hashcode for this iterator.
+     * @return A hash code
+     */
+    public int hashCode()
+    {
+        return text.hashCode() ^ pos ^ begin ^ end;
+    }
+
+    /**
+     * Creates a copy of this iterator.
+     * @return A copy of this
+     */
+    public Object clone()
+    {
+        try {
+            StringCharacterIterator other
+            = (StringCharacterIterator) super.clone();
+            return other;
+        }
+        catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+}
diff --git a/java/time/Clock.java b/java/time/Clock.java
new file mode 100644
index 0000000..b112784
--- /dev/null
+++ b/java/time/Clock.java
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+
+import java.io.Serializable;
+import java.util.Objects;
+import java.util.TimeZone;
+
+/**
+ * A clock providing access to the current instant, date and time using a time-zone.
+ * <p>
+ * Instances of this class are used to find the current instant, which can be
+ * interpreted using the stored time-zone to find the current date and time.
+ * As such, a clock can be used instead of {@link System#currentTimeMillis()}
+ * and {@link TimeZone#getDefault()}.
+ * <p>
+ * Use of a {@code Clock} is optional. All key date-time classes also have a
+ * {@code now()} factory method that uses the system clock in the default time zone.
+ * The primary purpose of this abstraction is to allow alternate clocks to be
+ * plugged in as and when required. Applications use an object to obtain the
+ * current time rather than a static method. This can simplify testing.
+ * <p>
+ * Best practice for applications is to pass a {@code Clock} into any method
+ * that requires the current instant. A dependency injection framework is one
+ * way to achieve this:
+ * <pre>
+ *  public class MyBean {
+ *    private Clock clock;  // dependency inject
+ *    ...
+ *    public void process(LocalDate eventDate) {
+ *      if (eventDate.isBefore(LocalDate.now(clock)) {
+ *        ...
+ *      }
+ *    }
+ *  }
+ * </pre>
+ * This approach allows an alternate clock, such as {@link #fixed(Instant, ZoneId) fixed}
+ * or {@link #offset(Clock, Duration) offset} to be used during testing.
+ * <p>
+ * The {@code system} factory methods provide clocks based on the best available
+ * system clock This may use {@link System#currentTimeMillis()}, or a higher
+ * resolution clock if one is available.
+ *
+ * @implSpec
+ * This abstract class must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * <p>
+ * The principal methods are defined to allow the throwing of an exception.
+ * In normal use, no exceptions will be thrown, however one possible implementation would be to
+ * obtain the time from a central time server across the network. Obviously, in this case the
+ * lookup could fail, and so the method is permitted to throw an exception.
+ * <p>
+ * The returned instants from {@code Clock} work on a time-scale that ignores leap seconds,
+ * as described in {@link Instant}. If the implementation wraps a source that provides leap
+ * second information, then a mechanism should be used to "smooth" the leap second.
+ * The Java Time-Scale mandates the use of UTC-SLS, however clock implementations may choose
+ * how accurate they are with the time-scale so long as they document how they work.
+ * Implementations are therefore not required to actually perform the UTC-SLS slew or to
+ * otherwise be aware of leap seconds.
+ * <p>
+ * Implementations should implement {@code Serializable} wherever possible and must
+ * document whether or not they do support serialization.
+ *
+ * @implNote
+ * The clock implementation provided here is based on {@link System#currentTimeMillis()}.
+ * That method provides little to no guarantee about the accuracy of the clock.
+ * Applications requiring a more accurate clock must implement this abstract class
+ * themselves using a different external clock, such as an NTP server.
+ *
+ * @since 1.8
+ */
+public abstract class Clock {
+
+    /**
+     * Obtains a clock that returns the current instant using the best available
+     * system clock, converting to date and time using the UTC time-zone.
+     * <p>
+     * This clock, rather than {@link #systemDefaultZone()}, should be used when
+     * you need the current instant without the date or time.
+     * <p>
+     * This clock is based on the best available system clock.
+     * This may use {@link System#currentTimeMillis()}, or a higher resolution
+     * clock if one is available.
+     * <p>
+     * Conversion from instant to date or time uses the {@linkplain ZoneOffset#UTC UTC time-zone}.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code system(ZoneOffset.UTC)}.
+     *
+     * @return a clock that uses the best available system clock in the UTC zone, not null
+     */
+    public static Clock systemUTC() {
+        return new SystemClock(ZoneOffset.UTC);
+    }
+
+    /**
+     * Obtains a clock that returns the current instant using the best available
+     * system clock, converting to date and time using the default time-zone.
+     * <p>
+     * This clock is based on the best available system clock.
+     * This may use {@link System#currentTimeMillis()}, or a higher resolution
+     * clock if one is available.
+     * <p>
+     * Using this method hard codes a dependency to the default time-zone into your application.
+     * It is recommended to avoid this and use a specific time-zone whenever possible.
+     * The {@link #systemUTC() UTC clock} should be used when you need the current instant
+     * without the date or time.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code system(ZoneId.systemDefault())}.
+     *
+     * @return a clock that uses the best available system clock in the default zone, not null
+     * @see ZoneId#systemDefault()
+     */
+    public static Clock systemDefaultZone() {
+        return new SystemClock(ZoneId.systemDefault());
+    }
+
+    /**
+     * Obtains a clock that returns the current instant using best available
+     * system clock.
+     * <p>
+     * This clock is based on the best available system clock.
+     * This may use {@link System#currentTimeMillis()}, or a higher resolution
+     * clock if one is available.
+     * <p>
+     * Conversion from instant to date or time uses the specified time-zone.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     *
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that uses the best available system clock in the specified zone, not null
+     */
+    public static Clock system(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return new SystemClock(zone);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains a clock that returns the current instant ticking in whole seconds
+     * using best available system clock.
+     * <p>
+     * This clock will always have the nano-of-second field set to zero.
+     * This ensures that the visible time ticks in whole seconds.
+     * The underlying clock is the best available system clock, equivalent to
+     * using {@link #system(ZoneId)}.
+     * <p>
+     * Implementations may use a caching strategy for performance reasons.
+     * As such, it is possible that the start of the second observed via this
+     * clock will be later than that observed directly via the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code tick(system(zone), Duration.ofSeconds(1))}.
+     *
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that ticks in whole seconds using the specified zone, not null
+     */
+    public static Clock tickSeconds(ZoneId zone) {
+        return new TickClock(system(zone), NANOS_PER_SECOND);
+    }
+
+    /**
+     * Obtains a clock that returns the current instant ticking in whole minutes
+     * using best available system clock.
+     * <p>
+     * This clock will always have the nano-of-second and second-of-minute fields set to zero.
+     * This ensures that the visible time ticks in whole minutes.
+     * The underlying clock is the best available system clock, equivalent to
+     * using {@link #system(ZoneId)}.
+     * <p>
+     * Implementations may use a caching strategy for performance reasons.
+     * As such, it is possible that the start of the minute observed via this
+     * clock will be later than that observed directly via the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     * It is equivalent to {@code tick(system(zone), Duration.ofMinutes(1))}.
+     *
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that ticks in whole minutes using the specified zone, not null
+     */
+    public static Clock tickMinutes(ZoneId zone) {
+        return new TickClock(system(zone), NANOS_PER_MINUTE);
+    }
+
+    /**
+     * Obtains a clock that returns instants from the specified clock truncated
+     * to the nearest occurrence of the specified duration.
+     * <p>
+     * This clock will only tick as per the specified duration. Thus, if the duration
+     * is half a second, the clock will return instants truncated to the half second.
+     * <p>
+     * The tick duration must be positive. If it has a part smaller than a whole
+     * millisecond, then the whole duration must divide into one second without
+     * leaving a remainder. All normal tick durations will match these criteria,
+     * including any multiple of hours, minutes, seconds and milliseconds, and
+     * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns.
+     * <p>
+     * A duration of zero or one nanosecond would have no truncation effect.
+     * Passing one of these will return the underlying clock.
+     * <p>
+     * Implementations may use a caching strategy for performance reasons.
+     * As such, it is possible that the start of the requested duration observed
+     * via this clock will be later than that observed directly via the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}
+     * providing that the base clock is.
+     *
+     * @param baseClock  the base clock to base the ticking clock on, not null
+     * @param tickDuration  the duration of each visible tick, not negative, not null
+     * @return a clock that ticks in whole units of the duration, not null
+     * @throws IllegalArgumentException if the duration is negative, or has a
+     *  part smaller than a whole millisecond such that the whole duration is not
+     *  divisible into one second
+     * @throws ArithmeticException if the duration is too large to be represented as nanos
+     */
+    public static Clock tick(Clock baseClock, Duration tickDuration) {
+        Objects.requireNonNull(baseClock, "baseClock");
+        Objects.requireNonNull(tickDuration, "tickDuration");
+        if (tickDuration.isNegative()) {
+            throw new IllegalArgumentException("Tick duration must not be negative");
+        }
+        long tickNanos = tickDuration.toNanos();
+        if (tickNanos % 1000_000 == 0) {
+            // ok, no fraction of millisecond
+        } else if (1000_000_000 % tickNanos == 0) {
+            // ok, divides into one second without remainder
+        } else {
+            throw new IllegalArgumentException("Invalid tick duration");
+        }
+        if (tickNanos <= 1) {
+            return baseClock;
+        }
+        return new TickClock(baseClock, tickNanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a clock that always returns the same instant.
+     * <p>
+     * This clock simply returns the specified instant.
+     * As such, it is not a clock in the conventional sense.
+     * The main use case for this is in testing, where the fixed clock ensures
+     * tests are not dependent on the current clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}.
+     *
+     * @param fixedInstant  the instant to use as the clock, not null
+     * @param zone  the time-zone to use to convert the instant to date-time, not null
+     * @return a clock that always returns the same instant, not null
+     */
+    public static Clock fixed(Instant fixedInstant, ZoneId zone) {
+        Objects.requireNonNull(fixedInstant, "fixedInstant");
+        Objects.requireNonNull(zone, "zone");
+        return new FixedClock(fixedInstant, zone);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains a clock that returns instants from the specified clock with the
+     * specified duration added
+     * <p>
+     * This clock wraps another clock, returning instants that are later by the
+     * specified duration. If the duration is negative, the instants will be
+     * earlier than the current date and time.
+     * The main use case for this is to simulate running in the future or in the past.
+     * <p>
+     * A duration of zero would have no offsetting effect.
+     * Passing zero will return the underlying clock.
+     * <p>
+     * The returned implementation is immutable, thread-safe and {@code Serializable}
+     * providing that the base clock is.
+     *
+     * @param baseClock  the base clock to add the duration to, not null
+     * @param offsetDuration  the duration to add, not null
+     * @return a clock based on the base clock with the duration added, not null
+     */
+    public static Clock offset(Clock baseClock, Duration offsetDuration) {
+        Objects.requireNonNull(baseClock, "baseClock");
+        Objects.requireNonNull(offsetDuration, "offsetDuration");
+        if (offsetDuration.equals(Duration.ZERO)) {
+            return baseClock;
+        }
+        return new OffsetClock(baseClock, offsetDuration);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor accessible by subclasses.
+     */
+    protected Clock() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the time-zone being used to create dates and times.
+     * <p>
+     * A clock will typically obtain the current instant and then convert that
+     * to a date or time using a time-zone. This method returns the time-zone used.
+     *
+     * @return the time-zone being used to interpret instants, not null
+     */
+    public abstract ZoneId getZone();
+
+    /**
+     * Returns a copy of this clock with a different time-zone.
+     * <p>
+     * A clock will typically obtain the current instant and then convert that
+     * to a date or time using a time-zone. This method returns a clock with
+     * similar properties but using a different time-zone.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a clock based on this clock with the specified time-zone, not null
+     */
+    public abstract Clock withZone(ZoneId zone);
+
+    //-------------------------------------------------------------------------
+    /**
+     * Gets the current millisecond instant of the clock.
+     * <p>
+     * This returns the millisecond-based instant, measured from 1970-01-01T00:00Z (UTC).
+     * This is equivalent to the definition of {@link System#currentTimeMillis()}.
+     * <p>
+     * Most applications should avoid this method and use {@link Instant} to represent
+     * an instant on the time-line rather than a raw millisecond value.
+     * This method is provided to allow the use of the clock in high performance use cases
+     * where the creation of an object would be unacceptable.
+     * <p>
+     * The default implementation currently calls {@link #instant}.
+     *
+     * @return the current millisecond instant from this clock, measured from
+     *  the Java epoch of 1970-01-01T00:00Z (UTC), not null
+     * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
+     */
+    public long millis() {
+        return instant().toEpochMilli();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the current instant of the clock.
+     * <p>
+     * This returns an instant representing the current instant as defined by the clock.
+     *
+     * @return the current instant from this clock, not null
+     * @throws DateTimeException if the instant cannot be obtained, not thrown by most implementations
+     */
+    public abstract Instant instant();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this clock is equal to another clock.
+     * <p>
+     * Clocks should override this method to compare equals based on
+     * their state and to meet the contract of {@link Object#equals}.
+     * If not overridden, the behavior is defined by {@link Object#equals}
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other clock
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return super.equals(obj);
+    }
+
+    /**
+     * A hash code for this clock.
+     * <p>
+     * Clocks should override this method based on
+     * their state and to meet the contract of {@link Object#hashCode}.
+     * If not overridden, the behavior is defined by {@link Object#hashCode}
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public  int hashCode() {
+        return super.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that always returns the latest time from
+     * {@link System#currentTimeMillis()}.
+     */
+    static final class SystemClock extends Clock implements Serializable {
+        private static final long serialVersionUID = 6740630888130243051L;
+        private final ZoneId zone;
+
+        SystemClock(ZoneId zone) {
+            this.zone = zone;
+        }
+        @Override
+        public ZoneId getZone() {
+            return zone;
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(this.zone)) {  // intentional NPE
+                return this;
+            }
+            return new SystemClock(zone);
+        }
+        @Override
+        public long millis() {
+            return System.currentTimeMillis();
+        }
+        @Override
+        public Instant instant() {
+            return Instant.ofEpochMilli(millis());
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof SystemClock) {
+                return zone.equals(((SystemClock) obj).zone);
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return zone.hashCode() + 1;
+        }
+        @Override
+        public String toString() {
+            return "SystemClock[" + zone + "]";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that always returns the same instant.
+     * This is typically used for testing.
+     */
+    static final class FixedClock extends Clock implements Serializable {
+       private static final long serialVersionUID = 7430389292664866958L;
+        private final Instant instant;
+        private final ZoneId zone;
+
+        FixedClock(Instant fixedInstant, ZoneId zone) {
+            this.instant = fixedInstant;
+            this.zone = zone;
+        }
+        @Override
+        public ZoneId getZone() {
+            return zone;
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(this.zone)) {  // intentional NPE
+                return this;
+            }
+            return new FixedClock(instant, zone);
+        }
+        @Override
+        public long millis() {
+            return instant.toEpochMilli();
+        }
+        @Override
+        public Instant instant() {
+            return instant;
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof FixedClock) {
+                FixedClock other = (FixedClock) obj;
+                return instant.equals(other.instant) && zone.equals(other.zone);
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return instant.hashCode() ^ zone.hashCode();
+        }
+        @Override
+        public String toString() {
+            return "FixedClock[" + instant + "," + zone + "]";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that adds an offset to an underlying clock.
+     */
+    static final class OffsetClock extends Clock implements Serializable {
+       private static final long serialVersionUID = 2007484719125426256L;
+        private final Clock baseClock;
+        private final Duration offset;
+
+        OffsetClock(Clock baseClock, Duration offset) {
+            this.baseClock = baseClock;
+            this.offset = offset;
+        }
+        @Override
+        public ZoneId getZone() {
+            return baseClock.getZone();
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(baseClock.getZone())) {  // intentional NPE
+                return this;
+            }
+            return new OffsetClock(baseClock.withZone(zone), offset);
+        }
+        @Override
+        public long millis() {
+            return Math.addExact(baseClock.millis(), offset.toMillis());
+        }
+        @Override
+        public Instant instant() {
+            return baseClock.instant().plus(offset);
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof OffsetClock) {
+                OffsetClock other = (OffsetClock) obj;
+                return baseClock.equals(other.baseClock) && offset.equals(other.offset);
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return baseClock.hashCode() ^ offset.hashCode();
+        }
+        @Override
+        public String toString() {
+            return "OffsetClock[" + baseClock + "," + offset + "]";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of a clock that adds an offset to an underlying clock.
+     */
+    static final class TickClock extends Clock implements Serializable {
+        private static final long serialVersionUID = 6504659149906368850L;
+        private final Clock baseClock;
+        private final long tickNanos;
+
+        TickClock(Clock baseClock, long tickNanos) {
+            this.baseClock = baseClock;
+            this.tickNanos = tickNanos;
+        }
+        @Override
+        public ZoneId getZone() {
+            return baseClock.getZone();
+        }
+        @Override
+        public Clock withZone(ZoneId zone) {
+            if (zone.equals(baseClock.getZone())) {  // intentional NPE
+                return this;
+            }
+            return new TickClock(baseClock.withZone(zone), tickNanos);
+        }
+        @Override
+        public long millis() {
+            long millis = baseClock.millis();
+            return millis - Math.floorMod(millis, tickNanos / 1000_000L);
+        }
+        @Override
+        public Instant instant() {
+            if ((tickNanos % 1000_000) == 0) {
+                long millis = baseClock.millis();
+                return Instant.ofEpochMilli(millis - Math.floorMod(millis, tickNanos / 1000_000L));
+            }
+            Instant instant = baseClock.instant();
+            long nanos = instant.getNano();
+            long adjust = Math.floorMod(nanos, tickNanos);
+            return instant.minusNanos(adjust);
+        }
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof TickClock) {
+                TickClock other = (TickClock) obj;
+                return baseClock.equals(other.baseClock) && tickNanos == other.tickNanos;
+            }
+            return false;
+        }
+        @Override
+        public int hashCode() {
+            return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32)));
+        }
+        @Override
+        public String toString() {
+            return "TickClock[" + baseClock + "," + Duration.ofNanos(tickNanos) + "]";
+        }
+    }
+
+}
diff --git a/java/time/DateTimeException.java b/java/time/DateTimeException.java
new file mode 100644
index 0000000..c2549fe
--- /dev/null
+++ b/java/time/DateTimeException.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+/**
+ * Exception used to indicate a problem while calculating a date-time.
+ * <p>
+ * This exception is used to indicate problems with creating, querying
+ * and manipulating date-time objects.
+ *
+ * @implSpec
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class DateTimeException extends RuntimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1632418723876261839L;
+
+    /**
+     * Constructs a new date-time exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     */
+    public DateTimeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new date-time exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param cause  the cause of the exception, may be null
+     */
+    public DateTimeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/java/time/DayOfWeek.java b/java/time/DayOfWeek.java
new file mode 100644
index 0000000..ee49f8a
--- /dev/null
+++ b/java/time/DayOfWeek.java
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.temporal.WeekFields;
+import java.util.Locale;
+
+/**
+ * A day-of-week, such as 'Tuesday'.
+ * <p>
+ * {@code DayOfWeek} is an enum representing the 7 days of the week -
+ * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday.
+ * <p>
+ * In addition to the textual enum name, each day-of-week has an {@code int} value.
+ * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
+ * It is recommended that applications use the enum rather than the {@code int} value
+ * to ensure code clarity.
+ * <p>
+ * This enum provides access to the localized textual form of the day-of-week.
+ * Some locales also assign different numeric values to the days, declaring
+ * Sunday to have the value 1, however this class provides no support for this.
+ * See {@link WeekFields} for localized week-numbering.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code DayOfWeek}.
+ * Use {@code getValue()} instead.</b>
+ * <p>
+ * This enum represents a common concept that is found in many calendar systems.
+ * As such, this enum may be used by any calendar system that has the day-of-week
+ * concept defined exactly equivalent to the ISO calendar system.
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
+
+    /**
+     * The singleton instance for the day-of-week of Monday.
+     * This has the numeric value of {@code 1}.
+     */
+    MONDAY,
+    /**
+     * The singleton instance for the day-of-week of Tuesday.
+     * This has the numeric value of {@code 2}.
+     */
+    TUESDAY,
+    /**
+     * The singleton instance for the day-of-week of Wednesday.
+     * This has the numeric value of {@code 3}.
+     */
+    WEDNESDAY,
+    /**
+     * The singleton instance for the day-of-week of Thursday.
+     * This has the numeric value of {@code 4}.
+     */
+    THURSDAY,
+    /**
+     * The singleton instance for the day-of-week of Friday.
+     * This has the numeric value of {@code 5}.
+     */
+    FRIDAY,
+    /**
+     * The singleton instance for the day-of-week of Saturday.
+     * This has the numeric value of {@code 6}.
+     */
+    SATURDAY,
+    /**
+     * The singleton instance for the day-of-week of Sunday.
+     * This has the numeric value of {@code 7}.
+     */
+    SUNDAY;
+    /**
+     * Private cache of all the constants.
+     */
+    private static final DayOfWeek[] ENUMS = DayOfWeek.values();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code DayOfWeek} from an {@code int} value.
+     * <p>
+     * {@code DayOfWeek} is an enum representing the 7 days of the week.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
+     *
+     * @param dayOfWeek  the day-of-week to represent, from 1 (Monday) to 7 (Sunday)
+     * @return the day-of-week singleton, not null
+     * @throws DateTimeException if the day-of-week is invalid
+     */
+    public static DayOfWeek of(int dayOfWeek) {
+        if (dayOfWeek < 1 || dayOfWeek > 7) {
+            throw new DateTimeException("Invalid value for DayOfWeek: " + dayOfWeek);
+        }
+        return ENUMS[dayOfWeek - 1];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code DayOfWeek} from a temporal object.
+     * <p>
+     * This obtains a day-of-week based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code DayOfWeek}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code DayOfWeek::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the day-of-week, not null
+     * @throws DateTimeException if unable to convert to a {@code DayOfWeek}
+     */
+    public static DayOfWeek from(TemporalAccessor temporal) {
+        if (temporal instanceof DayOfWeek) {
+            return (DayOfWeek) temporal;
+        }
+        try {
+            return of(temporal.get(DAY_OF_WEEK));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain DayOfWeek from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the day-of-week {@code int} value.
+     * <p>
+     * The values are numbered following the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
+     * See {@link java.time.temporal.WeekFields#dayOfWeek()} for localized week-numbering.
+     *
+     * @return the day-of-week, from 1 (Monday) to 7 (Sunday)
+     */
+    public int getValue() {
+        return ordinal() + 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation, such as 'Mon' or 'Friday'.
+     * <p>
+     * This returns the textual name used to identify the day-of-week,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+     *
+     * @param style  the length of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the day-of-week, not null
+     */
+    public String getDisplayName(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this day-of-week can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then
+     * this method returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this day-of-week, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == DAY_OF_WEEK;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This day-of-week is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
+     * range of the day-of-week, from 1 to 7, will be returned.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == DAY_OF_WEEK) {
+            return field.range();
+        }
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this day-of-week as an {@code int}.
+     * <p>
+     * This queries this day-of-week for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
+     * value of the day-of-week, from 1 to 7, will be returned.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field, within the valid range of values
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public int get(TemporalField field) {
+        if (field == DAY_OF_WEEK) {
+            return getValue();
+        }
+        return TemporalAccessor.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this day-of-week as a {@code long}.
+     * <p>
+     * This queries this day-of-week for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
+     * value of the day-of-week, from 1 to 7, will be returned.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field == DAY_OF_WEEK) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the day-of-week that is the specified number of days after this one.
+     * <p>
+     * The calculation rolls around the end of the week from Sunday to Monday.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, positive or negative
+     * @return the resulting day-of-week, not null
+     */
+    public DayOfWeek plus(long days) {
+        int amount = (int) (days % 7);
+        return ENUMS[(ordinal() + (amount + 7)) % 7];
+    }
+
+    /**
+     * Returns the day-of-week that is the specified number of days before this one.
+     * <p>
+     * The calculation rolls around the start of the year from Monday to Sunday.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, positive or negative
+     * @return the resulting day-of-week, not null
+     */
+    public DayOfWeek minus(long days) {
+        return plus(-(days % 7));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this day-of-week using the specified query.
+     * <p>
+     * This queries this day-of-week using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.precision()) {
+            return (R) DAYS;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this day-of-week.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the day-of-week changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#DAY_OF_WEEK} as the field.
+     * Note that this adjusts forwards or backwards within a Monday to Sunday week.
+     * See {@link java.time.temporal.WeekFields#dayOfWeek()} for localized week start days.
+     * See {@code TemporalAdjuster} for other adjusters with more control,
+     * such as {@code next(MONDAY)}.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisDayOfWeek.adjustInto(temporal);
+     *   temporal = temporal.with(thisDayOfWeek);
+     * </pre>
+     * <p>
+     * For example, given a date that is a Wednesday, the following are output:
+     * <pre>
+     *   dateOnWed.with(MONDAY);     // two days earlier
+     *   dateOnWed.with(TUESDAY);    // one day earlier
+     *   dateOnWed.with(WEDNESDAY);  // same date
+     *   dateOnWed.with(THURSDAY);   // one day later
+     *   dateOnWed.with(FRIDAY);     // two days later
+     *   dateOnWed.with(SATURDAY);   // three days later
+     *   dateOnWed.with(SUNDAY);     // four days later
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal.with(DAY_OF_WEEK, getValue());
+    }
+
+}
diff --git a/java/time/Duration.java b/java/time/Duration.java
new file mode 100644
index 0000000..8637c40
--- /dev/null
+++ b/java/time/Duration.java
@@ -0,0 +1,1341 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.LocalTime.SECONDS_PER_HOUR;
+import static java.time.LocalTime.SECONDS_PER_MINUTE;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A time-based amount of time, such as '34.5 seconds'.
+ * <p>
+ * This class models a quantity or amount of time in terms of seconds and nanoseconds.
+ * It can be accessed using other duration-based units, such as minutes and hours.
+ * In addition, the {@link ChronoUnit#DAYS DAYS} unit can be used and is treated as
+ * exactly equal to 24 hours, thus ignoring daylight savings effects.
+ * See {@link Period} for the date-based equivalent to this class.
+ * <p>
+ * A physical duration could be of infinite length.
+ * For practicality, the duration is stored with constraints similar to {@link Instant}.
+ * The duration uses nanosecond resolution with a maximum value of the seconds that can
+ * be held in a {@code long}. This is greater than the current estimated age of the universe.
+ * <p>
+ * The range of a duration requires the storage of a number larger than a {@code long}.
+ * To achieve this, the class stores a {@code long} representing seconds and an {@code int}
+ * representing nanosecond-of-second, which will always be between 0 and 999,999,999.
+ * The model is of a directed duration, meaning that the duration may be negative.
+ * <p>
+ * The duration is measured in "seconds", but these are not necessarily identical to
+ * the scientific "SI second" definition based on atomic clocks.
+ * This difference only impacts durations measured near a leap-second and should not affect
+ * most applications.
+ * See {@link Instant} for a discussion as to the meaning of the second and time-scales.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Duration
+        implements TemporalAmount, Comparable<Duration>, Serializable {
+
+    /**
+     * Constant for a duration of zero.
+     */
+    public static final Duration ZERO = new Duration(0, 0);
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 3078945930695997490L;
+    /**
+     * Constant for nanos per second.
+     */
+    private static final BigInteger BI_NANOS_PER_SECOND = BigInteger.valueOf(NANOS_PER_SECOND);
+    /**
+     * The pattern for parsing.
+     */
+    private static final Pattern PATTERN =
+            Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)D)?" +
+                    "(T(?:([-+]?[0-9]+)H)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)(?:[.,]([0-9]{0,9}))?S)?)?",
+                    Pattern.CASE_INSENSITIVE);
+
+    /**
+     * The number of seconds in the duration.
+     */
+    private final long seconds;
+    /**
+     * The number of nanoseconds in the duration, expressed as a fraction of the
+     * number of seconds. This is always positive, and never exceeds 999,999,999.
+     */
+    private final int nanos;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} representing a number of standard 24 hour days.
+     * <p>
+     * The seconds are calculated based on the standard definition of a day,
+     * where each day is 86400 seconds which implies a 24 hour day.
+     * The nanosecond in second field is set to zero.
+     *
+     * @param days  the number of days, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration}
+     */
+    public static Duration ofDays(long days) {
+        return create(Math.multiplyExact(days, SECONDS_PER_DAY), 0);
+    }
+
+    /**
+     * Obtains a {@code Duration} representing a number of standard hours.
+     * <p>
+     * The seconds are calculated based on the standard definition of an hour,
+     * where each hour is 3600 seconds.
+     * The nanosecond in second field is set to zero.
+     *
+     * @param hours  the number of hours, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration}
+     */
+    public static Duration ofHours(long hours) {
+        return create(Math.multiplyExact(hours, SECONDS_PER_HOUR), 0);
+    }
+
+    /**
+     * Obtains a {@code Duration} representing a number of standard minutes.
+     * <p>
+     * The seconds are calculated based on the standard definition of a minute,
+     * where each minute is 60 seconds.
+     * The nanosecond in second field is set to zero.
+     *
+     * @param minutes  the number of minutes, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration}
+     */
+    public static Duration ofMinutes(long minutes) {
+        return create(Math.multiplyExact(minutes, SECONDS_PER_MINUTE), 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} representing a number of seconds.
+     * <p>
+     * The nanosecond in second field is set to zero.
+     *
+     * @param seconds  the number of seconds, positive or negative
+     * @return a {@code Duration}, not null
+     */
+    public static Duration ofSeconds(long seconds) {
+        return create(seconds, 0);
+    }
+
+    /**
+     * Obtains a {@code Duration} representing a number of seconds and an
+     * adjustment in nanoseconds.
+     * <p>
+     * This method allows an arbitrary number of nanoseconds to be passed in.
+     * The factory will alter the values of the second and nanosecond in order
+     * to ensure that the stored nanosecond is in the range 0 to 999,999,999.
+     * For example, the following will result in the exactly the same duration:
+     * <pre>
+     *  Duration.ofSeconds(3, 1);
+     *  Duration.ofSeconds(4, -999_999_999);
+     *  Duration.ofSeconds(2, 1000_000_001);
+     * </pre>
+     *
+     * @param seconds  the number of seconds, positive or negative
+     * @param nanoAdjustment  the nanosecond adjustment to the number of seconds, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if the adjustment causes the seconds to exceed the capacity of {@code Duration}
+     */
+    public static Duration ofSeconds(long seconds, long nanoAdjustment) {
+        long secs = Math.addExact(seconds, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND));
+        int nos = (int) Math.floorMod(nanoAdjustment, NANOS_PER_SECOND);
+        return create(secs, nos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} representing a number of milliseconds.
+     * <p>
+     * The seconds and nanoseconds are extracted from the specified milliseconds.
+     *
+     * @param millis  the number of milliseconds, positive or negative
+     * @return a {@code Duration}, not null
+     */
+    public static Duration ofMillis(long millis) {
+        long secs = millis / 1000;
+        int mos = (int) (millis % 1000);
+        if (mos < 0) {
+            mos += 1000;
+            secs--;
+        }
+        return create(secs, mos * 1000_000);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} representing a number of nanoseconds.
+     * <p>
+     * The seconds and nanoseconds are extracted from the specified nanoseconds.
+     *
+     * @param nanos  the number of nanoseconds, positive or negative
+     * @return a {@code Duration}, not null
+     */
+    public static Duration ofNanos(long nanos) {
+        long secs = nanos / NANOS_PER_SECOND;
+        int nos = (int) (nanos % NANOS_PER_SECOND);
+        if (nos < 0) {
+            nos += NANOS_PER_SECOND;
+            secs--;
+        }
+        return create(secs, nos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} representing an amount in the specified unit.
+     * <p>
+     * The parameters represent the two parts of a phrase like '6 Hours'. For example:
+     * <pre>
+     *  Duration.of(3, SECONDS);
+     *  Duration.of(465, HOURS);
+     * </pre>
+     * Only a subset of units are accepted by this method.
+     * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or
+     * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception.
+     *
+     * @param amount  the amount of the duration, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the duration is measured in, must have an exact duration, not null
+     * @return a {@code Duration}, not null
+     * @throws DateTimeException if the period unit has an estimated duration
+     * @throws ArithmeticException if a numeric overflow occurs
+     */
+    public static Duration of(long amount, TemporalUnit unit) {
+        return ZERO.plus(amount, unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} from a temporal amount.
+     * <p>
+     * This obtains a duration based on the specified amount.
+     * A {@code TemporalAmount} represents an  amount of time, which may be
+     * date-based or time-based, which this factory extracts to a duration.
+     * <p>
+     * The conversion loops around the set of units from the amount and uses
+     * the {@linkplain TemporalUnit#getDuration() duration} of the unit to
+     * calculate the total {@code Duration}.
+     * Only a subset of units are accepted by this method. The unit must either
+     * have an {@linkplain TemporalUnit#isDurationEstimated() exact duration}
+     * or be {@link ChronoUnit#DAYS} which is treated as 24 hours.
+     * If any other units are found then an exception is thrown.
+     *
+     * @param amount  the temporal amount to convert, not null
+     * @return the equivalent duration, not null
+     * @throws DateTimeException if unable to convert to a {@code Duration}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Duration from(TemporalAmount amount) {
+        Objects.requireNonNull(amount, "amount");
+        Duration duration = ZERO;
+        for (TemporalUnit unit : amount.getUnits()) {
+            duration = duration.plus(amount.get(unit), unit);
+        }
+        return duration;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}.
+     * <p>
+     * This will parse a textual representation of a duration, including the
+     * string produced by {@code toString()}. The formats accepted are based
+     * on the ISO-8601 duration format {@code PnDTnHnMn.nS} with days
+     * considered to be exactly 24 hours.
+     * <p>
+     * The string starts with an optional sign, denoted by the ASCII negative
+     * or positive symbol. If negative, the whole period is negated.
+     * The ASCII letter "P" is next in upper or lower case.
+     * There are then four sections, each consisting of a number and a suffix.
+     * The sections have suffixes in ASCII of "D", "H", "M" and "S" for
+     * days, hours, minutes and seconds, accepted in upper or lower case.
+     * The suffixes must occur in order. The ASCII letter "T" must occur before
+     * the first occurrence, if any, of an hour, minute or second section.
+     * At least one of the four sections must be present, and if "T" is present
+     * there must be at least one section after the "T".
+     * The number part of each section must consist of one or more ASCII digits.
+     * The number may be prefixed by the ASCII negative or positive symbol.
+     * The number of days, hours and minutes must parse to an {@code long}.
+     * The number of seconds must parse to an {@code long} with optional fraction.
+     * The decimal point may be either a dot or a comma.
+     * The fractional part may have from zero to 9 digits.
+     * <p>
+     * The leading plus/minus sign, and negative values for other units are
+     * not part of the ISO-8601 standard.
+     * <p>
+     * Examples:
+     * <pre>
+     *    "PT20.345S" -- parses as "20.345 seconds"
+     *    "PT15M"     -- parses as "15 minutes" (where a minute is 60 seconds)
+     *    "PT10H"     -- parses as "10 hours" (where an hour is 3600 seconds)
+     *    "P2D"       -- parses as "2 days" (where a day is 24 hours or 86400 seconds)
+     *    "P2DT3H4M"  -- parses as "2 days, 3 hours and 4 minutes"
+     *    "P-6H3M"    -- parses as "-6 hours and +3 minutes"
+     *    "-P6H3M"    -- parses as "-6 hours and -3 minutes"
+     *    "-P-6H+3M"  -- parses as "+6 hours and -3 minutes"
+     * </pre>
+     *
+     * @param text  the text to parse, not null
+     * @return the parsed duration, not null
+     * @throws DateTimeParseException if the text cannot be parsed to a duration
+     */
+    public static Duration parse(CharSequence text) {
+        Objects.requireNonNull(text, "text");
+        Matcher matcher = PATTERN.matcher(text);
+        if (matcher.matches()) {
+            // check for letter T but no time sections
+            if ("T".equals(matcher.group(3)) == false) {
+                boolean negate = "-".equals(matcher.group(1));
+                String dayMatch = matcher.group(2);
+                String hourMatch = matcher.group(4);
+                String minuteMatch = matcher.group(5);
+                String secondMatch = matcher.group(6);
+                String fractionMatch = matcher.group(7);
+                if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) {
+                    long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days");
+                    long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours");
+                    long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes");
+                    long seconds = parseNumber(text, secondMatch, 1, "seconds");
+                    int nanos = parseFraction(text,  fractionMatch, seconds < 0 ? -1 : 1);
+                    try {
+                        return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos);
+                    } catch (ArithmeticException ex) {
+                        throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex);
+                    }
+                }
+            }
+        }
+        throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0);
+    }
+
+    private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) {
+        // regex limits to [-+]?[0-9]+
+        if (parsed == null) {
+            return 0;
+        }
+        try {
+            long val = Long.parseLong(parsed);
+            return Math.multiplyExact(val, multiplier);
+        } catch (NumberFormatException | ArithmeticException ex) {
+            throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex);
+        }
+    }
+
+    private static int parseFraction(CharSequence text, String parsed, int negate) {
+        // regex limits to [0-9]{0,9}
+        if (parsed == null || parsed.length() == 0) {
+            return 0;
+        }
+        try {
+            parsed = (parsed + "000000000").substring(0, 9);
+            return Integer.parseInt(parsed) * negate;
+        } catch (NumberFormatException | ArithmeticException ex) {
+            throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex);
+        }
+    }
+
+    private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) {
+        long seconds = Math.addExact(daysAsSecs, Math.addExact(hoursAsSecs, Math.addExact(minsAsSecs, secs)));
+        if (negate) {
+            return ofSeconds(seconds, nanos).negated();
+        }
+        return ofSeconds(seconds, nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Duration} representing the duration between two temporal objects.
+     * <p>
+     * This calculates the duration between two temporal objects. If the objects
+     * are of different types, then the duration is calculated based on the type
+     * of the first object. For example, if the first argument is a {@code LocalTime}
+     * then the second argument is converted to a {@code LocalTime}.
+     * <p>
+     * The specified temporal objects must support the {@link ChronoUnit#SECONDS SECONDS} unit.
+     * For full accuracy, either the {@link ChronoUnit#NANOS NANOS} unit or the
+     * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field should be supported.
+     * <p>
+     * The result of this method can be a negative period if the end is before the start.
+     * To guarantee to obtain a positive duration call {@link #abs()} on the result.
+     *
+     * @param startInclusive  the start instant, inclusive, not null
+     * @param endExclusive  the end instant, exclusive, not null
+     * @return a {@code Duration}, not null
+     * @throws DateTimeException if the seconds between the temporals cannot be obtained
+     * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
+     */
+    public static Duration between(Temporal startInclusive, Temporal endExclusive) {
+        try {
+            return ofNanos(startInclusive.until(endExclusive, NANOS));
+        } catch (DateTimeException | ArithmeticException ex) {
+            long secs = startInclusive.until(endExclusive, SECONDS);
+            long nanos;
+            try {
+                nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
+                if (secs > 0 && nanos < 0) {
+                    secs++;
+                } else if (secs < 0 && nanos > 0) {
+                    secs--;
+                }
+            } catch (DateTimeException ex2) {
+                nanos = 0;
+            }
+            return ofSeconds(secs, nanos);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Duration} using seconds and nanoseconds.
+     *
+     * @param seconds  the length of the duration in seconds, positive or negative
+     * @param nanoAdjustment  the nanosecond adjustment within the second, from 0 to 999,999,999
+     */
+    private static Duration create(long seconds, int nanoAdjustment) {
+        if ((seconds | nanoAdjustment) == 0) {
+            return ZERO;
+        }
+        return new Duration(seconds, nanoAdjustment);
+    }
+
+    /**
+     * Constructs an instance of {@code Duration} using seconds and nanoseconds.
+     *
+     * @param seconds  the length of the duration in seconds, positive or negative
+     * @param nanos  the nanoseconds within the second, from 0 to 999,999,999
+     */
+    private Duration(long seconds, int nanos) {
+        super();
+        this.seconds = seconds;
+        this.nanos = nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the value of the requested unit.
+     * <p>
+     * This returns a value for each of the two supported units,
+     * {@link ChronoUnit#SECONDS SECONDS} and {@link ChronoUnit#NANOS NANOS}.
+     * All other units throw an exception.
+     *
+     * @param unit the {@code TemporalUnit} for which to return the value
+     * @return the long value of the unit
+     * @throws DateTimeException if the unit is not supported
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    @Override
+    public long get(TemporalUnit unit) {
+        if (unit == SECONDS) {
+            return seconds;
+        } else if (unit == NANOS) {
+            return nanos;
+        } else {
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+    }
+
+    /**
+     * Gets the set of units supported by this duration.
+     * <p>
+     * The supported units are {@link ChronoUnit#SECONDS SECONDS},
+     * and {@link ChronoUnit#NANOS NANOS}.
+     * They are returned in the order seconds, nanos.
+     * <p>
+     * This set can be used in conjunction with {@link #get(TemporalUnit)}
+     * to access the entire state of the duration.
+     *
+     * @return a list containing the seconds and nanos units, not null
+     */
+    @Override
+    public List<TemporalUnit> getUnits() {
+        return DurationUnits.UNITS;
+    }
+
+    /**
+     * Private class to delay initialization of this list until needed.
+     * The circular dependency between Duration and ChronoUnit prevents
+     * the simple initialization in Duration.
+     */
+    private static class DurationUnits {
+        static final List<TemporalUnit> UNITS =
+                Collections.unmodifiableList(Arrays.<TemporalUnit>asList(SECONDS, NANOS));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this duration is zero length.
+     * <p>
+     * A {@code Duration} represents a directed distance between two points on
+     * the time-line and can therefore be positive, zero or negative.
+     * This method checks whether the length is zero.
+     *
+     * @return true if this duration has a total length equal to zero
+     */
+    public boolean isZero() {
+        return (seconds | nanos) == 0;
+    }
+
+    /**
+     * Checks if this duration is negative, excluding zero.
+     * <p>
+     * A {@code Duration} represents a directed distance between two points on
+     * the time-line and can therefore be positive, zero or negative.
+     * This method checks whether the length is less than zero.
+     *
+     * @return true if this duration has a total length less than zero
+     */
+    public boolean isNegative() {
+        return seconds < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of seconds in this duration.
+     * <p>
+     * The length of the duration is stored using two fields - seconds and nanoseconds.
+     * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to
+     * the length in seconds.
+     * The total duration is defined by calling this method and {@link #getNano()}.
+     * <p>
+     * A {@code Duration} represents a directed distance between two points on the time-line.
+     * A negative duration is expressed by the negative sign of the seconds part.
+     * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds.
+     *
+     * @return the whole seconds part of the length of the duration, positive or negative
+     */
+    public long getSeconds() {
+        return seconds;
+    }
+
+    /**
+     * Gets the number of nanoseconds within the second in this duration.
+     * <p>
+     * The length of the duration is stored using two fields - seconds and nanoseconds.
+     * The nanoseconds part is a value from 0 to 999,999,999 that is an adjustment to
+     * the length in seconds.
+     * The total duration is defined by calling this method and {@link #getSeconds()}.
+     * <p>
+     * A {@code Duration} represents a directed distance between two points on the time-line.
+     * A negative duration is expressed by the negative sign of the seconds part.
+     * A duration of -1 nanosecond is stored as -1 seconds plus 999,999,999 nanoseconds.
+     *
+     * @return the nanoseconds within the second part of the length of the duration, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified amount of seconds.
+     * <p>
+     * This returns a duration with the specified seconds, retaining the
+     * nano-of-second part of this duration.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to represent, may be negative
+     * @return a {@code Duration} based on this period with the requested seconds, not null
+     */
+    public Duration withSeconds(long seconds) {
+        return create(seconds, nanos);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified nano-of-second.
+     * <p>
+     * This returns a duration with the specified nano-of-second, retaining the
+     * seconds part of this duration.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return a {@code Duration} based on this period with the requested nano-of-second, not null
+     * @throws DateTimeException if the nano-of-second is invalid
+     */
+    public Duration withNanos(int nanoOfSecond) {
+        NANO_OF_SECOND.checkValidIntValue(nanoOfSecond);
+        return create(seconds, nanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param duration  the duration to add, positive or negative, not null
+     * @return a {@code Duration} based on this duration with the specified duration added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plus(Duration duration) {
+        return plus(duration.getSeconds(), duration.getNano());
+     }
+
+    /**
+     * Returns a copy of this duration with the specified duration added.
+     * <p>
+     * The duration amount is measured in terms of the specified unit.
+     * Only a subset of units are accepted by this method.
+     * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or
+     * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the amount is measured in, must have an exact duration, not null
+     * @return a {@code Duration} based on this duration with the specified duration added, not null
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plus(long amountToAdd, TemporalUnit unit) {
+        Objects.requireNonNull(unit, "unit");
+        if (unit == DAYS) {
+            return plus(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY), 0);
+        }
+        if (unit.isDurationEstimated()) {
+            throw new UnsupportedTemporalTypeException("Unit must not have an estimated duration");
+        }
+        if (amountToAdd == 0) {
+            return this;
+        }
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusSeconds((amountToAdd / (1000_000L * 1000)) * 1000).plusNanos((amountToAdd % (1000_000L * 1000)) * 1000);
+                case MILLIS: return plusMillis(amountToAdd);
+                case SECONDS: return plusSeconds(amountToAdd);
+            }
+            return plusSeconds(Math.multiplyExact(unit.getDuration().seconds, amountToAdd));
+        }
+        Duration duration = unit.getDuration().multipliedBy(amountToAdd);
+        return plusSeconds(duration.getSeconds()).plusNanos(duration.getNano());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration in standard 24 hour days added.
+     * <p>
+     * The number of days is multiplied by 86400 to obtain the number of seconds to add.
+     * This is based on the standard definition of a day as 24 hours.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified days added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusDays(long daysToAdd) {
+        return plus(Math.multiplyExact(daysToAdd, SECONDS_PER_DAY), 0);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in hours added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hoursToAdd  the hours to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified hours added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusHours(long hoursToAdd) {
+        return plus(Math.multiplyExact(hoursToAdd, SECONDS_PER_HOUR), 0);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in minutes added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutesToAdd  the minutes to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified minutes added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusMinutes(long minutesToAdd) {
+        return plus(Math.multiplyExact(minutesToAdd, SECONDS_PER_MINUTE), 0);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified seconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusSeconds(long secondsToAdd) {
+        return plus(secondsToAdd, 0);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in milliseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToAdd  the milliseconds to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified milliseconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusMillis(long millisToAdd) {
+        return plus(millisToAdd / 1000, (millisToAdd % 1000) * 1000_000);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToAdd  the nanoseconds to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified nanoseconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration plusNanos(long nanosToAdd) {
+        return plus(0, nanosToAdd);
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @param nanosToAdd  the nanos to add, positive or negative
+     * @return a {@code Duration} based on this duration with the specified seconds added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    private Duration plus(long secondsToAdd, long nanosToAdd) {
+        if ((secondsToAdd | nanosToAdd) == 0) {
+            return this;
+        }
+        long epochSec = Math.addExact(seconds, secondsToAdd);
+        epochSec = Math.addExact(epochSec, nanosToAdd / NANOS_PER_SECOND);
+        nanosToAdd = nanosToAdd % NANOS_PER_SECOND;
+        long nanoAdjustment = nanos + nanosToAdd;  // safe int+NANOS_PER_SECOND
+        return ofSeconds(epochSec, nanoAdjustment);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param duration  the duration to subtract, positive or negative, not null
+     * @return a {@code Duration} based on this duration with the specified duration subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minus(Duration duration) {
+        long secsToSubtract = duration.getSeconds();
+        int nanosToSubtract = duration.getNano();
+        if (secsToSubtract == Long.MIN_VALUE) {
+            return plus(Long.MAX_VALUE, -nanosToSubtract).plus(1, 0);
+        }
+        return plus(-secsToSubtract, -nanosToSubtract);
+     }
+
+    /**
+     * Returns a copy of this duration with the specified duration subtracted.
+     * <p>
+     * The duration amount is measured in terms of the specified unit.
+     * Only a subset of units are accepted by this method.
+     * The unit must either have an {@linkplain TemporalUnit#isDurationEstimated() exact duration} or
+     * be {@link ChronoUnit#DAYS} which is treated as 24 hours. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, measured in terms of the unit, positive or negative
+     * @param unit  the unit that the amount is measured in, must have an exact duration, not null
+     * @return a {@code Duration} based on this duration with the specified duration subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the specified duration in standard 24 hour days subtracted.
+     * <p>
+     * The number of days is multiplied by 86400 to obtain the number of seconds to subtract.
+     * This is based on the standard definition of a day as 24 hours.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the days to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified days subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in hours subtracted.
+     * <p>
+     * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hoursToSubtract  the hours to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified hours subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusHours(long hoursToSubtract) {
+        return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in minutes subtracted.
+     * <p>
+     * The number of hours is multiplied by 60 to obtain the number of seconds to subtract.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutesToSubtract  the minutes to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified minutes subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusMinutes(long minutesToSubtract) {
+        return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified seconds subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusSeconds(long secondsToSubtract) {
+        return (secondsToSubtract == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-secondsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in milliseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToSubtract  the milliseconds to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified milliseconds subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusMillis(long millisToSubtract) {
+        return (millisToSubtract == Long.MIN_VALUE ? plusMillis(Long.MAX_VALUE).plusMillis(1) : plusMillis(-millisToSubtract));
+    }
+
+    /**
+     * Returns a copy of this duration with the specified duration in nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToSubtract  the nanoseconds to subtract, positive or negative
+     * @return a {@code Duration} based on this duration with the specified nanoseconds subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration minusNanos(long nanosToSubtract) {
+        return (nanosToSubtract == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanosToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration multiplied by the scalar.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param multiplicand  the value to multiply the duration by, positive or negative
+     * @return a {@code Duration} based on this duration multiplied by the specified scalar, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration multipliedBy(long multiplicand) {
+        if (multiplicand == 0) {
+            return ZERO;
+        }
+        if (multiplicand == 1) {
+            return this;
+        }
+        return create(toSeconds().multiply(BigDecimal.valueOf(multiplicand)));
+     }
+
+    /**
+     * Returns a copy of this duration divided by the specified value.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param divisor  the value to divide the duration by, positive or negative, not zero
+     * @return a {@code Duration} based on this duration divided by the specified divisor, not null
+     * @throws ArithmeticException if the divisor is zero or if numeric overflow occurs
+     */
+    public Duration dividedBy(long divisor) {
+        if (divisor == 0) {
+            throw new ArithmeticException("Cannot divide by zero");
+        }
+        if (divisor == 1) {
+            return this;
+        }
+        return create(toSeconds().divide(BigDecimal.valueOf(divisor), RoundingMode.DOWN));
+     }
+
+    /**
+     * Converts this duration to the total length in seconds and
+     * fractional nanoseconds expressed as a {@code BigDecimal}.
+     *
+     * @return the total length of the duration in seconds, with a scale of 9, not null
+     */
+    private BigDecimal toSeconds() {
+        return BigDecimal.valueOf(seconds).add(BigDecimal.valueOf(nanos, 9));
+    }
+
+    /**
+     * Creates an instance of {@code Duration} from a number of seconds.
+     *
+     * @param seconds  the number of seconds, up to scale 9, positive or negative
+     * @return a {@code Duration}, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    private static Duration create(BigDecimal seconds) {
+        BigInteger nanos = seconds.movePointRight(9).toBigIntegerExact();
+        BigInteger[] divRem = nanos.divideAndRemainder(BI_NANOS_PER_SECOND);
+        if (divRem[0].bitLength() > 63) {
+            throw new ArithmeticException("Exceeds capacity of Duration: " + nanos);
+        }
+        return ofSeconds(divRem[0].longValue(), divRem[1].intValue());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this duration with the length negated.
+     * <p>
+     * This method swaps the sign of the total length of this duration.
+     * For example, {@code PT1.3S} will be returned as {@code PT-1.3S}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Duration} based on this duration with the amount negated, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration negated() {
+        return multipliedBy(-1);
+    }
+
+    /**
+     * Returns a copy of this duration with a positive length.
+     * <p>
+     * This method returns a positive duration by effectively removing the sign from any negative total length.
+     * For example, {@code PT-1.3S} will be returned as {@code PT1.3S}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Duration} based on this duration with an absolute length, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Duration abs() {
+        return isNegative() ? negated() : this;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Adds this duration to the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this duration added.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAmount)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisDuration.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisDuration);
+     * </pre>
+     * <p>
+     * The calculation will add the seconds, then nanos.
+     * Only non-zero amounts will be added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same type with the adjustment made, not null
+     * @throws DateTimeException if unable to add
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal addTo(Temporal temporal) {
+        if (seconds != 0) {
+            temporal = temporal.plus(seconds, SECONDS);
+        }
+        if (nanos != 0) {
+            temporal = temporal.plus(nanos, NANOS);
+        }
+        return temporal;
+    }
+
+    /**
+     * Subtracts this duration from the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this duration subtracted.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#minus(TemporalAmount)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisDuration.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisDuration);
+     * </pre>
+     * <p>
+     * The calculation will subtract the seconds, then nanos.
+     * Only non-zero amounts will be added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same type with the adjustment made, not null
+     * @throws DateTimeException if unable to subtract
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal subtractFrom(Temporal temporal) {
+        if (seconds != 0) {
+            temporal = temporal.minus(seconds, SECONDS);
+        }
+        if (nanos != 0) {
+            temporal = temporal.minus(nanos, NANOS);
+        }
+        return temporal;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of days in this duration.
+     * <p>
+     * This returns the total number of days in the duration by dividing the
+     * number of seconds by 86400.
+     * This is based on the standard definition of a day as 24 hours.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return the number of days in the duration, may be negative
+     */
+    public long toDays() {
+        return seconds / SECONDS_PER_DAY;
+    }
+
+    /**
+     * Gets the number of hours in this duration.
+     * <p>
+     * This returns the total number of hours in the duration by dividing the
+     * number of seconds by 3600.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return the number of hours in the duration, may be negative
+     */
+    public long toHours() {
+        return seconds / SECONDS_PER_HOUR;
+    }
+
+    /**
+     * Gets the number of minutes in this duration.
+     * <p>
+     * This returns the total number of minutes in the duration by dividing the
+     * number of seconds by 60.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return the number of minutes in the duration, may be negative
+     */
+    public long toMinutes() {
+        return seconds / SECONDS_PER_MINUTE;
+    }
+
+    /**
+     * Converts this duration to the total length in milliseconds.
+     * <p>
+     * If this duration is too large to fit in a {@code long} milliseconds, then an
+     * exception is thrown.
+     * <p>
+     * If this duration has greater than millisecond precision, then the conversion
+     * will drop any excess precision information as though the amount in nanoseconds
+     * was subject to integer division by one million.
+     *
+     * @return the total length of the duration in milliseconds
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public long toMillis() {
+        long millis = Math.multiplyExact(seconds, 1000);
+        millis = Math.addExact(millis, nanos / 1000_000);
+        return millis;
+    }
+
+    /**
+     * Converts this duration to the total length in nanoseconds expressed as a {@code long}.
+     * <p>
+     * If this duration is too large to fit in a {@code long} nanoseconds, then an
+     * exception is thrown.
+     *
+     * @return the total length of the duration in nanoseconds
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public long toNanos() {
+        long totalNanos = Math.multiplyExact(seconds, NANOS_PER_SECOND);
+        totalNanos = Math.addExact(totalNanos, nanos);
+        return totalNanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this duration to the specified {@code Duration}.
+     * <p>
+     * The comparison is based on the total length of the durations.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param otherDuration  the other duration to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(Duration otherDuration) {
+        int cmp = Long.compare(seconds, otherDuration.seconds);
+        if (cmp != 0) {
+            return cmp;
+        }
+        return nanos - otherDuration.nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this duration is equal to the specified {@code Duration}.
+     * <p>
+     * The comparison is based on the total length of the durations.
+     *
+     * @param otherDuration  the other duration, null returns false
+     * @return true if the other duration is equal to this one
+     */
+    @Override
+    public boolean equals(Object otherDuration) {
+        if (this == otherDuration) {
+            return true;
+        }
+        if (otherDuration instanceof Duration) {
+            Duration other = (Duration) otherDuration;
+            return this.seconds == other.seconds &&
+                   this.nanos == other.nanos;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this duration.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return ((int) (seconds ^ (seconds >>> 32))) + (51 * nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A string representation of this duration using ISO-8601 seconds
+     * based representation, such as {@code PT8H6M12.345S}.
+     * <p>
+     * The format of the returned string will be {@code PTnHnMnS}, where n is
+     * the relevant hours, minutes or seconds part of the duration.
+     * Any fractional seconds are placed after a decimal point i the seconds section.
+     * If a section has a zero value, it is omitted.
+     * The hours, minutes and seconds will all have the same sign.
+     * <p>
+     * Examples:
+     * <pre>
+     *    "20.345 seconds"                 -- "PT20.345S
+     *    "15 minutes" (15 * 60 seconds)   -- "PT15M"
+     *    "10 hours" (10 * 3600 seconds)   -- "PT10H"
+     *    "2 days" (2 * 86400 seconds)     -- "PT48H"
+     * </pre>
+     * Note that multiples of 24 hours are not output as days to avoid confusion
+     * with {@code Period}.
+     *
+     * @return an ISO-8601 representation of this duration, not null
+     */
+    @Override
+    public String toString() {
+        if (this == ZERO) {
+            return "PT0S";
+        }
+        long hours = seconds / SECONDS_PER_HOUR;
+        int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
+        int secs = (int) (seconds % SECONDS_PER_MINUTE);
+        StringBuilder buf = new StringBuilder(24);
+        buf.append("PT");
+        if (hours != 0) {
+            buf.append(hours).append('H');
+        }
+        if (minutes != 0) {
+            buf.append(minutes).append('M');
+        }
+        if (secs == 0 && nanos == 0 && buf.length() > 2) {
+            return buf.toString();
+        }
+        if (secs < 0 && nanos > 0) {
+            if (secs == -1) {
+                buf.append("-0");
+            } else {
+                buf.append(secs + 1);
+            }
+        } else {
+            buf.append(secs);
+        }
+        if (nanos > 0) {
+            int pos = buf.length();
+            if (secs < 0) {
+                buf.append(2 * NANOS_PER_SECOND - nanos);
+            } else {
+                buf.append(nanos + NANOS_PER_SECOND);
+            }
+            while (buf.charAt(buf.length() - 1) == '0') {
+                buf.setLength(buf.length() - 1);
+            }
+            buf.setCharAt(pos, '.');
+        }
+        buf.append('S');
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);  // identifies a Duration
+     *  out.writeLong(seconds);
+     *  out.writeInt(nanos);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.DURATION_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeLong(seconds);
+        out.writeInt(nanos);
+    }
+
+    static Duration readExternal(DataInput in) throws IOException {
+        long seconds = in.readLong();
+        int nanos = in.readInt();
+        return Duration.ofSeconds(seconds, nanos);
+    }
+
+}
diff --git a/java/time/Instant.java b/java/time/Instant.java
new file mode 100644
index 0000000..c87ac18
--- /dev/null
+++ b/java/time/Instant.java
@@ -0,0 +1,1365 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.LocalTime.SECONDS_PER_HOUR;
+import static java.time.LocalTime.SECONDS_PER_MINUTE;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * An instantaneous point on the time-line.
+ * <p>
+ * This class models a single instantaneous point on the time-line.
+ * This might be used to record event time-stamps in the application.
+ * <p>
+ * The range of an instant requires the storage of a number larger than a {@code long}.
+ * To achieve this, the class stores a {@code long} representing epoch-seconds and an
+ * {@code int} representing nanosecond-of-second, which will always be between 0 and 999,999,999.
+ * The epoch-seconds are measured from the standard Java epoch of {@code 1970-01-01T00:00:00Z}
+ * where instants after the epoch have positive values, and earlier instants have negative values.
+ * For both the epoch-second and nanosecond parts, a larger value is always later on the time-line
+ * than a smaller value.
+ *
+ * <h3>Time-scale</h3>
+ * <p>
+ * The length of the solar day is the standard way that humans measure time.
+ * This has traditionally been subdivided into 24 hours of 60 minutes of 60 seconds,
+ * forming a 86400 second day.
+ * <p>
+ * Modern timekeeping is based on atomic clocks which precisely define an SI second
+ * relative to the transitions of a Caesium atom. The length of an SI second was defined
+ * to be very close to the 86400th fraction of a day.
+ * <p>
+ * Unfortunately, as the Earth rotates the length of the day varies.
+ * In addition, over time the average length of the day is getting longer as the Earth slows.
+ * As a result, the length of a solar day in 2012 is slightly longer than 86400 SI seconds.
+ * The actual length of any given day and the amount by which the Earth is slowing
+ * are not predictable and can only be determined by measurement.
+ * The UT1 time-scale captures the accurate length of day, but is only available some
+ * time after the day has completed.
+ * <p>
+ * The UTC time-scale is a standard approach to bundle up all the additional fractions
+ * of a second from UT1 into whole seconds, known as <i>leap-seconds</i>.
+ * A leap-second may be added or removed depending on the Earth's rotational changes.
+ * As such, UTC permits a day to have 86399 SI seconds or 86401 SI seconds where
+ * necessary in order to keep the day aligned with the Sun.
+ * <p>
+ * The modern UTC time-scale was introduced in 1972, introducing the concept of whole leap-seconds.
+ * Between 1958 and 1972, the definition of UTC was complex, with minor sub-second leaps and
+ * alterations to the length of the notional second. As of 2012, discussions are underway
+ * to change the definition of UTC again, with the potential to remove leap seconds or
+ * introduce other changes.
+ * <p>
+ * Given the complexity of accurate timekeeping described above, this Java API defines
+ * its own time-scale, the <i>Java Time-Scale</i>.
+ * <p>
+ * The Java Time-Scale divides each calendar day into exactly 86400
+ * subdivisions, known as seconds.  These seconds may differ from the
+ * SI second.  It closely matches the de facto international civil time
+ * scale, the definition of which changes from time to time.
+ * <p>
+ * The Java Time-Scale has slightly different definitions for different
+ * segments of the time-line, each based on the consensus international
+ * time scale that is used as the basis for civil time. Whenever the
+ * internationally-agreed time scale is modified or replaced, a new
+ * segment of the Java Time-Scale must be defined for it.  Each segment
+ * must meet these requirements:
+ * <ul>
+ * <li>the Java Time-Scale shall closely match the underlying international
+ *  civil time scale;</li>
+ * <li>the Java Time-Scale shall exactly match the international civil
+ *  time scale at noon each day;</li>
+ * <li>the Java Time-Scale shall have a precisely-defined relationship to
+ *  the international civil time scale.</li>
+ * </ul>
+ * There are currently, as of 2013, two segments in the Java time-scale.
+ * <p>
+ * For the segment from 1972-11-03 (exact boundary discussed below) until
+ * further notice, the consensus international time scale is UTC (with
+ * leap seconds).  In this segment, the Java Time-Scale is identical to
+ * <a href="http://www.cl.cam.ac.uk/~mgk25/time/utc-sls/">UTC-SLS</a>.
+ * This is identical to UTC on days that do not have a leap second.
+ * On days that do have a leap second, the leap second is spread equally
+ * over the last 1000 seconds of the day, maintaining the appearance of
+ * exactly 86400 seconds per day.
+ * <p>
+ * For the segment prior to 1972-11-03, extending back arbitrarily far,
+ * the consensus international time scale is defined to be UT1, applied
+ * proleptically, which is equivalent to the (mean) solar time on the
+ * prime meridian (Greenwich). In this segment, the Java Time-Scale is
+ * identical to the consensus international time scale. The exact
+ * boundary between the two segments is the instant where UT1 = UTC
+ * between 1972-11-03T00:00 and 1972-11-04T12:00.
+ * <p>
+ * Implementations of the Java time-scale using the JSR-310 API are not
+ * required to provide any clock that is sub-second accurate, or that
+ * progresses monotonically or smoothly. Implementations are therefore
+ * not required to actually perform the UTC-SLS slew or to otherwise be
+ * aware of leap seconds. JSR-310 does, however, require that
+ * implementations must document the approach they use when defining a
+ * clock representing the current instant.
+ * See {@link Clock} for details on the available clocks.
+ * <p>
+ * The Java time-scale is used for all date-time classes.
+ * This includes {@code Instant}, {@code LocalDate}, {@code LocalTime}, {@code OffsetDateTime},
+ * {@code ZonedDateTime} and {@code Duration}.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Instant
+        implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable {
+
+    /**
+     * Constant for the 1970-01-01T00:00:00Z epoch instant.
+     */
+    public static final Instant EPOCH = new Instant(0, 0);
+    /**
+     * The minimum supported epoch second.
+     */
+    private static final long MIN_SECOND = -31557014167219200L;
+    /**
+     * The maximum supported epoch second.
+     */
+    private static final long MAX_SECOND = 31556889864403199L;
+    /**
+     * The minimum supported {@code Instant}, '-1000000000-01-01T00:00Z'.
+     * This could be used by an application as a "far past" instant.
+     * <p>
+     * This is one year earlier than the minimum {@code LocalDateTime}.
+     * This provides sufficient values to handle the range of {@code ZoneOffset}
+     * which affect the instant in addition to the local date-time.
+     * The value is also chosen such that the value of the year fits in
+     * an {@code int}.
+     */
+    public static final Instant MIN = Instant.ofEpochSecond(MIN_SECOND, 0);
+    /**
+     * The maximum supported {@code Instant}, '1000000000-12-31T23:59:59.999999999Z'.
+     * This could be used by an application as a "far future" instant.
+     * <p>
+     * This is one year later than the maximum {@code LocalDateTime}.
+     * This provides sufficient values to handle the range of {@code ZoneOffset}
+     * which affect the instant in addition to the local date-time.
+     * The value is also chosen such that the value of the year fits in
+     * an {@code int}.
+     */
+    public static final Instant MAX = Instant.ofEpochSecond(MAX_SECOND, 999_999_999);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -665713676816604388L;
+
+    /**
+     * The number of seconds from the epoch of 1970-01-01T00:00:00Z.
+     */
+    private final long seconds;
+    /**
+     * The number of nanoseconds, later along the time-line, from the seconds field.
+     * This is always positive, and never exceeds 999,999,999.
+     */
+    private final int nanos;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current instant from the system clock.
+     * <p>
+     * This will query the {@link Clock#systemUTC() system UTC clock} to
+     * obtain the current instant.
+     * <p>
+     * Using this method will prevent the ability to use an alternate time-source for
+     * testing because the clock is effectively hard-coded.
+     *
+     * @return the current instant using the system clock, not null
+     */
+    public static Instant now() {
+        return Clock.systemUTC().instant();
+    }
+
+    /**
+     * Obtains the current instant from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current time.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current instant, not null
+     */
+    public static Instant now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        return clock.instant();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The nanosecond field is set to zero.
+     *
+     * @param epochSecond  the number of seconds from 1970-01-01T00:00:00Z
+     * @return an instant, not null
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     */
+    public static Instant ofEpochSecond(long epochSecond) {
+        return create(epochSecond, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code Instant} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z and nanosecond fraction of second.
+     * <p>
+     * This method allows an arbitrary number of nanoseconds to be passed in.
+     * The factory will alter the values of the second and nanosecond in order
+     * to ensure that the stored nanosecond is in the range 0 to 999,999,999.
+     * For example, the following will result in the exactly the same instant:
+     * <pre>
+     *  Instant.ofEpochSecond(3, 1);
+     *  Instant.ofEpochSecond(4, -999_999_999);
+     *  Instant.ofEpochSecond(2, 1000_000_001);
+     * </pre>
+     *
+     * @param epochSecond  the number of seconds from 1970-01-01T00:00:00Z
+     * @param nanoAdjustment  the nanosecond adjustment to the number of seconds, positive or negative
+     * @return an instant, not null
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public static Instant ofEpochSecond(long epochSecond, long nanoAdjustment) {
+        long secs = Math.addExact(epochSecond, Math.floorDiv(nanoAdjustment, NANOS_PER_SECOND));
+        int nos = (int)Math.floorMod(nanoAdjustment, NANOS_PER_SECOND);
+        return create(secs, nos);
+    }
+
+    /**
+     * Obtains an instance of {@code Instant} using milliseconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The seconds and nanoseconds are extracted from the specified milliseconds.
+     *
+     * @param epochMilli  the number of milliseconds from 1970-01-01T00:00:00Z
+     * @return an instant, not null
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     */
+    public static Instant ofEpochMilli(long epochMilli) {
+        long secs = Math.floorDiv(epochMilli, 1000);
+        int mos = (int)Math.floorMod(epochMilli, 1000);
+        return create(secs, mos * 1000_000);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} from a temporal object.
+     * <p>
+     * This obtains an instant based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code Instant}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
+     * and {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} fields.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code Instant::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the instant, not null
+     * @throws DateTimeException if unable to convert to an {@code Instant}
+     */
+    public static Instant from(TemporalAccessor temporal) {
+        if (temporal instanceof Instant) {
+            return (Instant) temporal;
+        }
+        Objects.requireNonNull(temporal, "temporal");
+        try {
+            long instantSecs = temporal.getLong(INSTANT_SECONDS);
+            int nanoOfSecond = temporal.get(NANO_OF_SECOND);
+            return Instant.ofEpochSecond(instantSecs, nanoOfSecond);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain Instant from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} from a text string such as
+     * {@code 2007-12-03T10:15:30.00Z}.
+     * <p>
+     * The string must represent a valid instant in UTC and is parsed using
+     * {@link DateTimeFormatter#ISO_INSTANT}.
+     *
+     * @param text  the text to parse, not null
+     * @return the parsed instant, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static Instant parse(final CharSequence text) {
+        return DateTimeFormatter.ISO_INSTANT.parse(text, Instant::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Instant} using seconds and nanoseconds.
+     *
+     * @param seconds  the length of the duration in seconds
+     * @param nanoOfSecond  the nano-of-second, from 0 to 999,999,999
+     * @throws DateTimeException if the instant exceeds the maximum or minimum instant
+     */
+    private static Instant create(long seconds, int nanoOfSecond) {
+        if ((seconds | nanoOfSecond) == 0) {
+            return EPOCH;
+        }
+        if (seconds < MIN_SECOND || seconds > MAX_SECOND) {
+            throw new DateTimeException("Instant exceeds minimum or maximum instant");
+        }
+        return new Instant(seconds, nanoOfSecond);
+    }
+
+    /**
+     * Constructs an instance of {@code Instant} using seconds from the epoch of
+     * 1970-01-01T00:00:00Z and nanosecond fraction of second.
+     *
+     * @param epochSecond  the number of seconds from 1970-01-01T00:00:00Z
+     * @param nanos  the nanoseconds within the second, must be positive
+     */
+    private Instant(long epochSecond, int nanos) {
+        super();
+        this.seconds = epochSecond;
+        this.nanos = nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this instant can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code INSTANT_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this instant, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == INSTANT_SECONDS || field == NANO_OF_SECOND || field == MICRO_OF_SECOND || field == MILLI_OF_SECOND;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code NANOS}
+     * <li>{@code MICROS}
+     * <li>{@code MILLIS}
+     * <li>{@code SECONDS}
+     * <li>{@code MINUTES}
+     * <li>{@code HOURS}
+     * <li>{@code HALF_DAYS}
+     * <li>{@code DAYS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit.isTimeBased() || unit == DAYS;
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This instant is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override  // override for Javadoc
+    public ValueRange range(TemporalField field) {
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this instant as an {@code int}.
+     * <p>
+     * This queries this instant for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code INSTANT_SECONDS} which is too
+     * large to fit in an {@code int} and throws a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case NANO_OF_SECOND: return nanos;
+                case MICRO_OF_SECOND: return nanos / 1000;
+                case MILLI_OF_SECOND: return nanos / 1000_000;
+                case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return range(field).checkValidIntValue(field.getFrom(this), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this instant as a {@code long}.
+     * <p>
+     * This queries this instant for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case NANO_OF_SECOND: return nanos;
+                case MICRO_OF_SECOND: return nanos / 1000;
+                case MILLI_OF_SECOND: return nanos / 1000_000;
+                case INSTANT_SECONDS: return seconds;
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the number of seconds from the Java epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * The epoch second count is a simple incrementing count of seconds where
+     * second 0 is 1970-01-01T00:00:00Z.
+     * The nanosecond part of the day is returned by {@code getNanosOfSecond}.
+     *
+     * @return the seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public long getEpochSecond() {
+        return seconds;
+    }
+
+    /**
+     * Gets the number of nanoseconds, later along the time-line, from the start
+     * of the second.
+     * <p>
+     * The nanosecond-of-second value measures the total number of nanoseconds from
+     * the second returned by {@code getEpochSecond}.
+     *
+     * @return the nanoseconds within the second, always positive, never exceeds 999,999,999
+     */
+    public int getNano() {
+        return nanos;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this instant.
+     * <p>
+     * This returns an {@code Instant}, based on this one, with the instant adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return an {@code Instant} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Instant with(TemporalAdjuster adjuster) {
+        return (Instant) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified field set to a new value.
+     * <p>
+     * This returns an {@code Instant}, based on this one, with the value
+     * for the specified field changed.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND} -
+     *  Returns an {@code Instant} with the specified nano-of-second.
+     *  The epoch-second will be unchanged.
+     * <li>{@code MICRO_OF_SECOND} -
+     *  Returns an {@code Instant} with the nano-of-second replaced by the specified
+     *  micro-of-second multiplied by 1,000. The epoch-second will be unchanged.
+     * <li>{@code MILLI_OF_SECOND} -
+     *  Returns an {@code Instant} with the nano-of-second replaced by the specified
+     *  milli-of-second multiplied by 1,000,000. The epoch-second will be unchanged.
+     * <li>{@code INSTANT_SECONDS} -
+     *  Returns an {@code Instant} with the specified epoch-second.
+     *  The nano-of-second will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an {@code Instant} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Instant with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case MILLI_OF_SECOND: {
+                    int nval = (int) newValue * 1000_000;
+                    return (nval != nanos ? create(seconds, nval) : this);
+                }
+                case MICRO_OF_SECOND: {
+                    int nval = (int) newValue * 1000;
+                    return (nval != nanos ? create(seconds, nval) : this);
+                }
+                case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this);
+                case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code Instant} truncated to the specified unit.
+     * <p>
+     * Truncating the instant returns a copy of the original with fields
+     * smaller than the specified unit set to zero.
+     * The fields are calculated on the basis of using a UTC offset as seen
+     * in {@code toString}.
+     * For example, truncating with the {@link ChronoUnit#MINUTES MINUTES} unit will
+     * round down to the nearest minute, setting the seconds and nanoseconds to zero.
+     * <p>
+     * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
+     * that divides into the length of a standard day without remainder.
+     * This includes all supplied time units on {@link ChronoUnit} and
+     * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return an {@code Instant} based on this instant with the time truncated, not null
+     * @throws DateTimeException if the unit is invalid for truncation
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    public Instant truncatedTo(TemporalUnit unit) {
+        if (unit == ChronoUnit.NANOS) {
+            return this;
+        }
+        Duration unitDur = unit.getDuration();
+        if (unitDur.getSeconds() > LocalTime.SECONDS_PER_DAY) {
+            throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation");
+        }
+        long dur = unitDur.toNanos();
+        if ((LocalTime.NANOS_PER_DAY % dur) != 0) {
+            throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder");
+        }
+        long nod = (seconds % LocalTime.SECONDS_PER_DAY) * LocalTime.NANOS_PER_SECOND + nanos;
+        long result = (nod / dur) * dur;
+        return plusNanos(result - nod);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this instant with the specified amount added.
+     * <p>
+     * This returns an {@code Instant}, based on this one, with the specified amount added.
+     * The amount is typically {@link Duration} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return an {@code Instant} based on this instant with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Instant plus(TemporalAmount amountToAdd) {
+        return (Instant) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified amount added.
+     * <p>
+     * This returns an {@code Instant}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code NANOS} -
+     *  Returns a {@code Instant} with the specified number of nanoseconds added.
+     *  This is equivalent to {@link #plusNanos(long)}.
+     * <li>{@code MICROS} -
+     *  Returns a {@code Instant} with the specified number of microseconds added.
+     *  This is equivalent to {@link #plusNanos(long)} with the amount
+     *  multiplied by 1,000.
+     * <li>{@code MILLIS} -
+     *  Returns a {@code Instant} with the specified number of milliseconds added.
+     *  This is equivalent to {@link #plusNanos(long)} with the amount
+     *  multiplied by 1,000,000.
+     * <li>{@code SECONDS} -
+     *  Returns a {@code Instant} with the specified number of seconds added.
+     *  This is equivalent to {@link #plusSeconds(long)}.
+     * <li>{@code MINUTES} -
+     *  Returns a {@code Instant} with the specified number of minutes added.
+     *  This is equivalent to {@link #plusSeconds(long)} with the amount
+     *  multiplied by 60.
+     * <li>{@code HOURS} -
+     *  Returns a {@code Instant} with the specified number of hours added.
+     *  This is equivalent to {@link #plusSeconds(long)} with the amount
+     *  multiplied by 3,600.
+     * <li>{@code HALF_DAYS} -
+     *  Returns a {@code Instant} with the specified number of half-days added.
+     *  This is equivalent to {@link #plusSeconds(long)} with the amount
+     *  multiplied by 43,200 (12 hours).
+     * <li>{@code DAYS} -
+     *  Returns a {@code Instant} with the specified number of days added.
+     *  This is equivalent to {@link #plusSeconds(long)} with the amount
+     *  multiplied by 86,400 (24 hours).
+     * </ul>
+     * <p>
+     * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return an {@code Instant} based on this instant with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Instant plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
+                case MILLIS: return plusMillis(amountToAdd);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
+                case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
+                case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
+                case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this instant with the specified duration in seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified seconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant plusSeconds(long secondsToAdd) {
+        return plus(secondsToAdd, 0);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in milliseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToAdd  the milliseconds to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified milliseconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant plusMillis(long millisToAdd) {
+        return plus(millisToAdd / 1000, (millisToAdd % 1000) * 1000_000);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToAdd  the nanoseconds to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified nanoseconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant plusNanos(long nanosToAdd) {
+        return plus(0, nanosToAdd);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToAdd  the seconds to add, positive or negative
+     * @param nanosToAdd  the nanos to add, positive or negative
+     * @return an {@code Instant} based on this instant with the specified seconds added, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    private Instant plus(long secondsToAdd, long nanosToAdd) {
+        if ((secondsToAdd | nanosToAdd) == 0) {
+            return this;
+        }
+        long epochSec = Math.addExact(seconds, secondsToAdd);
+        epochSec = Math.addExact(epochSec, nanosToAdd / NANOS_PER_SECOND);
+        nanosToAdd = nanosToAdd % NANOS_PER_SECOND;
+        long nanoAdjustment = nanos + nanosToAdd;  // safe int+NANOS_PER_SECOND
+        return ofEpochSecond(epochSec, nanoAdjustment);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this instant with the specified amount subtracted.
+     * <p>
+     * This returns an {@code Instant}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Duration} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return an {@code Instant} based on this instant with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Instant minus(TemporalAmount amountToSubtract) {
+        return (Instant) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified amount subtracted.
+     * <p>
+     * This returns a {@code Instant}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return an {@code Instant} based on this instant with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Instant minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this instant with the specified duration in seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, positive or negative
+     * @return an {@code Instant} based on this instant with the specified seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant minusSeconds(long secondsToSubtract) {
+        if (secondsToSubtract == Long.MIN_VALUE) {
+            return plusSeconds(Long.MAX_VALUE).plusSeconds(1);
+        }
+        return plusSeconds(-secondsToSubtract);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in milliseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param millisToSubtract  the milliseconds to subtract, positive or negative
+     * @return an {@code Instant} based on this instant with the specified milliseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant minusMillis(long millisToSubtract) {
+        if (millisToSubtract == Long.MIN_VALUE) {
+            return plusMillis(Long.MAX_VALUE).plusMillis(1);
+        }
+        return plusMillis(-millisToSubtract);
+    }
+
+    /**
+     * Returns a copy of this instant with the specified duration in nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToSubtract  the nanoseconds to subtract, positive or negative
+     * @return an {@code Instant} based on this instant with the specified nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the maximum or minimum instant
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Instant minusNanos(long nanosToSubtract) {
+        if (nanosToSubtract == Long.MIN_VALUE) {
+            return plusNanos(Long.MAX_VALUE).plusNanos(1);
+        }
+        return plusNanos(-nanosToSubtract);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Queries this instant using the specified query.
+     * <p>
+     * This queries this instant using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        if (query == TemporalQueries.chronology() || query == TemporalQueries.zoneId() ||
+                query == TemporalQueries.zone() || query == TemporalQueries.offset() ||
+                query == TemporalQueries.localDate() || query == TemporalQueries.localTime()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this instant.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the instant changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#INSTANT_SECONDS} and
+     * {@link ChronoField#NANO_OF_SECOND} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisInstant.adjustInto(temporal);
+     *   temporal = temporal.with(thisInstant);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal.with(INSTANT_SECONDS, seconds).with(NANO_OF_SECOND, nanos);
+    }
+
+    /**
+     * Calculates the amount of time until another instant in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code Instant}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified instant.
+     * The result will be negative if the end is before the start.
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two instants.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code Instant} using {@link #from(TemporalAccessor)}.
+     * For example, the amount in days between two dates can be calculated
+     * using {@code startInstant.until(endInstant, SECONDS)}.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, SECONDS);
+     *   amount = SECONDS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS}, {@code HALF_DAYS} and {@code DAYS}
+     * are supported. Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to an {@code Instant}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this instant and the end instant
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to an {@code Instant}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        Instant end = Instant.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return nanosUntil(end);
+                case MICROS: return nanosUntil(end) / 1000;
+                case MILLIS: return Math.subtractExact(end.toEpochMilli(), toEpochMilli());
+                case SECONDS: return secondsUntil(end);
+                case MINUTES: return secondsUntil(end) / SECONDS_PER_MINUTE;
+                case HOURS: return secondsUntil(end) / SECONDS_PER_HOUR;
+                case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR);
+                case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.between(this, end);
+    }
+
+    private long nanosUntil(Instant end) {
+        long secsDiff = Math.subtractExact(end.seconds, seconds);
+        long totalNanos = Math.multiplyExact(secsDiff, NANOS_PER_SECOND);
+        return Math.addExact(totalNanos, end.nanos - nanos);
+    }
+
+    private long secondsUntil(Instant end) {
+        long secsDiff = Math.subtractExact(end.seconds, seconds);
+        long nanosDiff = end.nanos - nanos;
+        if (secsDiff > 0 && nanosDiff < 0) {
+            secsDiff--;
+        } else if (secsDiff < 0 && nanosDiff > 0) {
+            secsDiff++;
+        }
+        return secsDiff;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this instant with an offset to create an {@code OffsetDateTime}.
+     * <p>
+     * This returns an {@code OffsetDateTime} formed from this instant at the
+     * specified offset from UTC/Greenwich. An exception will be thrown if the
+     * instant is too large to fit into an offset date-time.
+     * <p>
+     * This method is equivalent to
+     * {@link OffsetDateTime#ofInstant(Instant, ZoneId) OffsetDateTime.ofInstant(this, offset)}.
+     *
+     * @param offset  the offset to combine with, not null
+     * @return the offset date-time formed from this instant and the specified offset, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public OffsetDateTime atOffset(ZoneOffset offset) {
+        return OffsetDateTime.ofInstant(this, offset);
+    }
+
+    /**
+     * Combines this instant with a time-zone to create a {@code ZonedDateTime}.
+     * <p>
+     * This returns an {@code ZonedDateTime} formed from this instant at the
+     * specified time-zone. An exception will be thrown if the instant is too
+     * large to fit into a zoned date-time.
+     * <p>
+     * This method is equivalent to
+     * {@link ZonedDateTime#ofInstant(Instant, ZoneId) ZonedDateTime.ofInstant(this, zone)}.
+     *
+     * @param zone  the zone to combine with, not null
+     * @return the zoned date-time formed from this instant and the specified zone, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public ZonedDateTime atZone(ZoneId zone) {
+        return ZonedDateTime.ofInstant(this, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this instant to the number of milliseconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * If this instant represents a point on the time-line too far in the future
+     * or past to fit in a {@code long} milliseconds, then an exception is thrown.
+     * <p>
+     * If this instant has greater than millisecond precision, then the conversion
+     * will drop any excess precision information as though the amount in nanoseconds
+     * was subject to integer division by one million.
+     *
+     * @return the number of milliseconds since the epoch of 1970-01-01T00:00:00Z
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public long toEpochMilli() {
+        if (seconds < 0 && nanos > 0) {
+            long millis = Math.multiplyExact(seconds+1, 1000);
+            long adjustment = nanos / 1000_000 - 1000;
+            return Math.addExact(millis, adjustment);
+        } else {
+            long millis = Math.multiplyExact(seconds, 1000);
+            return Math.addExact(millis, nanos / 1000_000);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this instant to the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param otherInstant  the other instant to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if otherInstant is null
+     */
+    @Override
+    public int compareTo(Instant otherInstant) {
+        int cmp = Long.compare(seconds, otherInstant.seconds);
+        if (cmp != 0) {
+            return cmp;
+        }
+        return nanos - otherInstant.nanos;
+    }
+
+    /**
+     * Checks if this instant is after the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     *
+     * @param otherInstant  the other instant to compare to, not null
+     * @return true if this instant is after the specified instant
+     * @throws NullPointerException if otherInstant is null
+     */
+    public boolean isAfter(Instant otherInstant) {
+        return compareTo(otherInstant) > 0;
+    }
+
+    /**
+     * Checks if this instant is before the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     *
+     * @param otherInstant  the other instant to compare to, not null
+     * @return true if this instant is before the specified instant
+     * @throws NullPointerException if otherInstant is null
+     */
+    public boolean isBefore(Instant otherInstant) {
+        return compareTo(otherInstant) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this instant is equal to the specified instant.
+     * <p>
+     * The comparison is based on the time-line position of the instants.
+     *
+     * @param otherInstant  the other instant, null returns false
+     * @return true if the other instant is equal to this one
+     */
+    @Override
+    public boolean equals(Object otherInstant) {
+        if (this == otherInstant) {
+            return true;
+        }
+        if (otherInstant instanceof Instant) {
+            Instant other = (Instant) otherInstant;
+            return this.seconds == other.seconds &&
+                   this.nanos == other.nanos;
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this instant.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return ((int) (seconds ^ (seconds >>> 32))) + 51 * nanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A string representation of this instant using ISO-8601 representation.
+     * <p>
+     * The format used is the same as {@link DateTimeFormatter#ISO_INSTANT}.
+     *
+     * @return an ISO-8601 representation of this instant, not null
+     */
+    @Override
+    public String toString() {
+        return DateTimeFormatter.ISO_INSTANT.format(this);
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(2);  // identifies an Instant
+     *  out.writeLong(seconds);
+     *  out.writeInt(nanos);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.INSTANT_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeLong(seconds);
+        out.writeInt(nanos);
+    }
+
+    static Instant readExternal(DataInput in) throws IOException {
+        long seconds = in.readLong();
+        int nanos = in.readInt();
+        return Instant.ofEpochSecond(seconds, nanos);
+    }
+
+}
diff --git a/java/time/LocalDate.java b/java/time/LocalDate.java
new file mode 100644
index 0000000..c23b270
--- /dev/null
+++ b/java/time/LocalDate.java
@@ -0,0 +1,2076 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Era;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03}.
+ * <p>
+ * {@code LocalDate} is an immutable date-time object that represents a date,
+ * often viewed as year-month-day. Other date fields, such as day-of-year,
+ * day-of-week and week-of-year, can also be accessed.
+ * For example, the value "2nd October 2007" can be stored in a {@code LocalDate}.
+ * <p>
+ * This class does not store or represent a time or time-zone.
+ * Instead, it is a description of the date, as used for birthdays.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalDate
+        implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
+
+    /**
+     * The minimum supported {@code LocalDate}, '-999999999-01-01'.
+     * This could be used by an application as a "far past" date.
+     */
+    public static final LocalDate MIN = LocalDate.of(Year.MIN_VALUE, 1, 1);
+    /**
+     * The maximum supported {@code LocalDate}, '+999999999-12-31'.
+     * This could be used by an application as a "far future" date.
+     */
+    public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2942565459149668126L;
+    /**
+     * The number of days in a 400 year cycle.
+     */
+    private static final int DAYS_PER_CYCLE = 146097;
+    /**
+     * The number of days from year zero to year 1970.
+     * There are five 400 year cycles from year zero to 2000.
+     * There are 7 leap years from 1970 to 2000.
+     */
+    static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
+
+    /**
+     * The year.
+     */
+    private final int year;
+    /**
+     * The month-of-year.
+     */
+    private final short month;
+    /**
+     * The day-of-month.
+     */
+    private final short day;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date using the system clock and default time-zone, not null
+     */
+    public static LocalDate now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date using the system clock, not null
+     */
+    public static LocalDate now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date, not null
+     */
+    public static LocalDate now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        // inline to avoid creating object and Instant checks
+        final Instant now = clock.instant();  // called once
+        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+        long epochSec = now.getEpochSecond() + offset.getTotalSeconds();  // overflow caught later
+        long epochDay = Math.floorDiv(epochSec, SECONDS_PER_DAY);
+        return LocalDate.ofEpochDay(epochDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a year, month and day.
+     * <p>
+     * This returns a {@code LocalDate} with the specified year, month and day-of-month.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the local date, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDate of(int year, Month month, int dayOfMonth) {
+        YEAR.checkValidValue(year);
+        Objects.requireNonNull(month, "month");
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        return create(year, month.getValue(), dayOfMonth);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDate} from a year, month and day.
+     * <p>
+     * This returns a {@code LocalDate} with the specified year, month and day-of-month.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the local date, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDate of(int year, int month, int dayOfMonth) {
+        YEAR.checkValidValue(year);
+        MONTH_OF_YEAR.checkValidValue(month);
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        return create(year, month, dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a year and day-of-year.
+     * <p>
+     * This returns a {@code LocalDate} with the specified year and day-of-year.
+     * The day-of-year must be valid for the year, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param dayOfYear  the day-of-year to represent, from 1 to 366
+     * @return the local date, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-year is invalid for the year
+     */
+    public static LocalDate ofYearDay(int year, int dayOfYear) {
+        YEAR.checkValidValue(year);
+        DAY_OF_YEAR.checkValidValue(dayOfYear);
+        boolean leap = IsoChronology.INSTANCE.isLeapYear(year);
+        if (dayOfYear == 366 && leap == false) {
+            throw new DateTimeException("Invalid date 'DayOfYear 366' as '" + year + "' is not a leap year");
+        }
+        Month moy = Month.of((dayOfYear - 1) / 31 + 1);
+        int monthEnd = moy.firstDayOfYear(leap) + moy.length(leap) - 1;
+        if (dayOfYear > monthEnd) {
+            moy = moy.plus(1);
+        }
+        int dom = dayOfYear - moy.firstDayOfYear(leap) + 1;
+        return new LocalDate(year, moy.getValue(), dom);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from the epoch day count.
+     * <p>
+     * This returns a {@code LocalDate} with the specified epoch-day.
+     * The {@link ChronoField#EPOCH_DAY EPOCH_DAY} is a simple incrementing count
+     * of days where day 0 is 1970-01-01. Negative numbers represent earlier days.
+     *
+     * @param epochDay  the Epoch Day to convert, based on the epoch 1970-01-01
+     * @return the local date, not null
+     * @throws DateTimeException if the epoch day exceeds the supported date range
+     */
+    public static LocalDate ofEpochDay(long epochDay) {
+        long zeroDay = epochDay + DAYS_0000_TO_1970;
+        // find the march-based year
+        zeroDay -= 60;  // adjust to 0000-03-01 so leap day is at end of four year cycle
+        long adjust = 0;
+        if (zeroDay < 0) {
+            // adjust negative years to positive for calculation
+            long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
+            adjust = adjustCycles * 400;
+            zeroDay += -adjustCycles * DAYS_PER_CYCLE;
+        }
+        long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
+        long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+        if (doyEst < 0) {
+            // fix estimate
+            yearEst--;
+            doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
+        }
+        yearEst += adjust;  // reset any negative year
+        int marchDoy0 = (int) doyEst;
+
+        // convert march-based values back to january-based
+        int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
+        int month = (marchMonth0 + 2) % 12 + 1;
+        int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
+        yearEst += marchMonth0 / 10;
+
+        // check year now we are certain it is correct
+        int year = YEAR.checkValidIntValue(yearEst);
+        return new LocalDate(year, month, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a temporal object.
+     * <p>
+     * This obtains a local date based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code LocalDate}.
+     * <p>
+     * The conversion uses the {@link TemporalQueries#localDate()} query, which relies
+     * on extracting the {@link ChronoField#EPOCH_DAY EPOCH_DAY} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code LocalDate::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date, not null
+     * @throws DateTimeException if unable to convert to a {@code LocalDate}
+     */
+    public static LocalDate from(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        LocalDate date = temporal.query(TemporalQueries.localDate());
+        if (date == null) {
+            throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
+        }
+        return date;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDate} from a text string such as {@code 2007-12-03}.
+     * <p>
+     * The string must represent a valid date and is parsed using
+     * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE}.
+     *
+     * @param text  the text to parse such as "2007-12-03", not null
+     * @return the parsed local date, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDate parse(CharSequence text) {
+        return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDate} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed local date, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDate parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, LocalDate::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a local date from the year, month and day fields.
+     *
+     * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 to 12, validated
+     * @param dayOfMonth  the day-of-month to represent, validated from 1 to 31
+     * @return the local date, not null
+     * @throws DateTimeException if the day-of-month is invalid for the month-year
+     */
+    private static LocalDate create(int year, int month, int dayOfMonth) {
+        if (dayOfMonth > 28) {
+            int dom = 31;
+            switch (month) {
+                case 2:
+                    dom = (IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
+                    break;
+                case 4:
+                case 6:
+                case 9:
+                case 11:
+                    dom = 30;
+                    break;
+            }
+            if (dayOfMonth > dom) {
+                if (dayOfMonth == 29) {
+                    throw new DateTimeException("Invalid date 'February 29' as '" + year + "' is not a leap year");
+                } else {
+                    throw new DateTimeException("Invalid date '" + Month.of(month).name() + " " + dayOfMonth + "'");
+                }
+            }
+        }
+        return new LocalDate(year, month, dayOfMonth);
+    }
+
+    /**
+     * Resolves the date, resolving days past the end of month.
+     *
+     * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, validated from 1 to 12
+     * @param day  the day-of-month to represent, validated from 1 to 31
+     * @return the resolved date, not null
+     */
+    private static LocalDate resolvePreviousValid(int year, int month, int day) {
+        switch (month) {
+            case 2:
+                day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
+                break;
+            case 4:
+            case 6:
+            case 9:
+            case 11:
+                day = Math.min(day, 30);
+                break;
+        }
+        return new LocalDate(year, month, day);
+    }
+
+    /**
+     * Constructor, previously validated.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, valid for year-month, from 1 to 31
+     */
+    private LocalDate(int year, int month, int dayOfMonth) {
+        this.year = year;
+        this.month = (short) month;
+        this.day = (short) dayOfMonth;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code PROLEPTIC_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalField field) {
+        return ChronoLocalDate.super.isSupported(field);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this date.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code DAYS}
+     * <li>{@code WEEKS}
+     * <li>{@code MONTHS}
+     * <li>{@code YEARS}
+     * <li>{@code DECADES}
+     * <li>{@code CENTURIES}
+     * <li>{@code MILLENNIA}
+     * <li>{@code ERAS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalUnit unit) {
+        return ChronoLocalDate.super.isSupported(unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (f.isDateBased()) {
+                switch (f) {
+                    case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+                    case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+                    case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, getMonth() == Month.FEBRUARY && isLeapYear() == false ? 4 : 5);
+                    case YEAR_OF_ERA:
+                        return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
+                }
+                return field.range();
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date as an {@code int}.
+     * <p>
+     * This queries this date for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date, except {@code EPOCH_DAY} and {@code PROLEPTIC_MONTH}
+     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return get0(field);
+        }
+        return ChronoLocalDate.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date as a {@code long}.
+     * <p>
+     * This queries this date for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == EPOCH_DAY) {
+                return toEpochDay();
+            }
+            if (field == PROLEPTIC_MONTH) {
+                return getProlepticMonth();
+            }
+            return get0(field);
+        }
+        return field.getFrom(this);
+    }
+
+    private int get0(TemporalField field) {
+        switch ((ChronoField) field) {
+            case DAY_OF_WEEK: return getDayOfWeek().getValue();
+            case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((day - 1) % 7) + 1;
+            case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
+            case DAY_OF_MONTH: return day;
+            case DAY_OF_YEAR: return getDayOfYear();
+            case EPOCH_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'EpochDay' for get() method, use getLong() instead");
+            case ALIGNED_WEEK_OF_MONTH: return ((day - 1) / 7) + 1;
+            case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
+            case MONTH_OF_YEAR: return month;
+            case PROLEPTIC_MONTH: throw new UnsupportedTemporalTypeException("Invalid field 'ProlepticMonth' for get() method, use getLong() instead");
+            case YEAR_OF_ERA: return (year >= 1 ? year : 1 - year);
+            case YEAR: return year;
+            case ERA: return (year >= 1 ? 1 : 0);
+        }
+        throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+    }
+
+    private long getProlepticMonth() {
+        return (year * 12L + month - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the ISO calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The ISO-8601 calendar system is the modern civil calendar system used today
+     * in most of the world. It is equivalent to the proleptic Gregorian calendar
+     * system, in which today's rules for leap years are applied for all time.
+     *
+     * @return the ISO chronology, not null
+     */
+    @Override
+    public IsoChronology getChronology() {
+        return IsoChronology.INSTANCE;
+    }
+
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The official ISO-8601 standard does not define eras, however {@code IsoChronology} does.
+     * It defines two eras, 'CE' from year one onwards and 'BCE' from year zero backwards.
+     * Since dates before the Julian-Gregorian cutover are not in line with history,
+     * the cutover between 'BCE' and 'CE' is also not aligned with the commonly used
+     * eras, often referred to using 'BC' and 'AD'.
+     * <p>
+     * Users of this class should typically ignore this method as it exists primarily
+     * to fulfill the {@link ChronoLocalDate} contract where it is necessary to support
+     * the Japanese calendar system.
+     * <p>
+     * The returned era will be a singleton capable of being compared with the constants
+     * in {@link IsoChronology} using the {@code ==} operator.
+     *
+     * @return the {@code IsoChronology} era constant applicable at this date, not null
+     */
+    @Override // override for Javadoc
+    public Era getEra() {
+        return ChronoLocalDate.super.getEra();
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return year;
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return month;
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return Month.of(month);
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return day;
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year, from 1 to 365, or 366 in a leap year
+     */
+    public int getDayOfYear() {
+        return getMonth().firstDayOfYear(isLeapYear()) + day - 1;
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * This method returns the enum {@link DayOfWeek} for the day-of-week.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link DayOfWeek#getValue() int value}.
+     * <p>
+     * Additional information can be obtained from the {@code DayOfWeek}.
+     * This includes textual names of the values.
+     *
+     * @return the day-of-week, not null
+     */
+    public DayOfWeek getDayOfWeek() {
+        int dow0 = (int)Math.floorMod(toEpochDay() + 3, 7);
+        return DayOfWeek.of(dow0 + 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @return true if the year is leap, false otherwise
+     */
+    @Override // override for Javadoc and performance
+    public boolean isLeapYear() {
+        return IsoChronology.INSTANCE.isLeapYear(year);
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * For example, a date in January would return 31.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        switch (month) {
+            case 2:
+                return (isLeapYear() ? 29 : 28);
+            case 4:
+            case 6:
+            case 9:
+            case 11:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    /**
+     * Returns the length of the year represented by this date.
+     * <p>
+     * This returns the length of the year in days, either 365 or 366.
+     *
+     * @return 366 if the year is leap, 365 otherwise
+     */
+    @Override // override for Javadoc and performance
+    public int lengthOfYear() {
+        return (isLeapYear() ? 366 : 365);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date.
+     * <p>
+     * This returns a {@code LocalDate}, based on this one, with the date adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the date to the last day of the month.
+     * <p>
+     * A selection of common adjustments is provided in
+     * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.
+     * These include finding the "last day of the month" and "next Wednesday".
+     * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+     * such as {@link Month} and {@link java.time.MonthDay MonthDay}.
+     * The adjuster is responsible for handling special cases, such as the varying
+     * lengths of month and leap years.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.TemporalAdjusters.*;
+     *
+     *  result = localDate.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code LocalDate} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDate with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate) {
+            return (LocalDate) adjuster;
+        }
+        return (LocalDate) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date with the specified field set to a new value.
+     * <p>
+     * This returns a {@code LocalDate}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year, month or day-of-month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code DAY_OF_WEEK} -
+     *  Returns a {@code LocalDate} with the specified day-of-week.
+     *  The date is adjusted up to 6 days forward or backward within the boundary
+     *  of a Monday to Sunday week.
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
+     *  Returns a {@code LocalDate} with the specified aligned-day-of-week.
+     *  The date is adjusted to the specified month-based aligned-day-of-week.
+     *  Aligned weeks are counted such that the first week of a given month starts
+     *  on the first day of that month.
+     *  This may cause the date to be moved up to 6 days into the following month.
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
+     *  Returns a {@code LocalDate} with the specified aligned-day-of-week.
+     *  The date is adjusted to the specified year-based aligned-day-of-week.
+     *  Aligned weeks are counted such that the first week of a given year starts
+     *  on the first day of that year.
+     *  This may cause the date to be moved up to 6 days into the following year.
+     * <li>{@code DAY_OF_MONTH} -
+     *  Returns a {@code LocalDate} with the specified day-of-month.
+     *  The month and year will be unchanged. If the day-of-month is invalid for the
+     *  year and month, then a {@code DateTimeException} is thrown.
+     * <li>{@code DAY_OF_YEAR} -
+     *  Returns a {@code LocalDate} with the specified day-of-year.
+     *  The year will be unchanged. If the day-of-year is invalid for the
+     *  year, then a {@code DateTimeException} is thrown.
+     * <li>{@code EPOCH_DAY} -
+     *  Returns a {@code LocalDate} with the specified epoch-day.
+     *  This completely replaces the date and is equivalent to {@link #ofEpochDay(long)}.
+     * <li>{@code ALIGNED_WEEK_OF_MONTH} -
+     *  Returns a {@code LocalDate} with the specified aligned-week-of-month.
+     *  Aligned weeks are counted such that the first week of a given month starts
+     *  on the first day of that month.
+     *  This adjustment moves the date in whole week chunks to match the specified week.
+     *  The result will have the same day-of-week as this date.
+     *  This may cause the date to be moved into the following month.
+     * <li>{@code ALIGNED_WEEK_OF_YEAR} -
+     *  Returns a {@code LocalDate} with the specified aligned-week-of-year.
+     *  Aligned weeks are counted such that the first week of a given year starts
+     *  on the first day of that year.
+     *  This adjustment moves the date in whole week chunks to match the specified week.
+     *  The result will have the same day-of-week as this date.
+     *  This may cause the date to be moved into the following year.
+     * <li>{@code MONTH_OF_YEAR} -
+     *  Returns a {@code LocalDate} with the specified month-of-year.
+     *  The year will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * <li>{@code PROLEPTIC_MONTH} -
+     *  Returns a {@code LocalDate} with the specified proleptic-month.
+     *  The day-of-month will be unchanged, unless it would be invalid for the new month
+     *  and year. In that case, the day-of-month is adjusted to the maximum valid value
+     *  for the new month and year.
+     * <li>{@code YEAR_OF_ERA} -
+     *  Returns a {@code LocalDate} with the specified year-of-era.
+     *  The era and month will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * <li>{@code YEAR} -
+     *  Returns a {@code LocalDate} with the specified year.
+     *  The month will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * <li>{@code ERA} -
+     *  Returns a {@code LocalDate} with the specified era.
+     *  The year-of-era and month will be unchanged. The day-of-month will also be unchanged,
+     *  unless it would be invalid for the new month and year. In that case, the
+     *  day-of-month is adjusted to the maximum valid value for the new month and year.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code LocalDate} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek().getValue());
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
+                case DAY_OF_MONTH: return withDayOfMonth((int) newValue);
+                case DAY_OF_YEAR: return withDayOfYear((int) newValue);
+                case EPOCH_DAY: return LocalDate.ofEpochDay(newValue);
+                case ALIGNED_WEEK_OF_MONTH: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_MONTH));
+                case ALIGNED_WEEK_OF_YEAR: return plusWeeks(newValue - getLong(ALIGNED_WEEK_OF_YEAR));
+                case MONTH_OF_YEAR: return withMonth((int) newValue);
+                case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
+                case YEAR_OF_ERA: return withYear((int) (year >= 1 ? newValue : 1 - newValue));
+                case YEAR: return withYear((int) newValue);
+                case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDate} with the year altered.
+     * <p>
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
+     * @return a {@code LocalDate} based on this date with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public LocalDate withYear(int year) {
+        if (this.year == year) {
+            return this;
+        }
+        YEAR.checkValidValue(year);
+        return resolvePreviousValid(year, month, day);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the month-of-year altered.
+     * <p>
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
+     * @return a {@code LocalDate} based on this date with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public LocalDate withMonth(int month) {
+        if (this.month == month) {
+            return this;
+        }
+        MONTH_OF_YEAR.checkValidValue(month);
+        return resolvePreviousValid(year, month, day);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the day-of-month altered.
+     * <p>
+     * If the resulting date is invalid, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
+     * @return a {@code LocalDate} based on this date with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public LocalDate withDayOfMonth(int dayOfMonth) {
+        if (this.day == dayOfMonth) {
+            return this;
+        }
+        return of(year, month, dayOfMonth);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the day-of-year altered.
+     * <p>
+     * If the resulting date is invalid, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
+     * @return a {@code LocalDate} based on this date with the requested day, not null
+     * @throws DateTimeException if the day-of-year value is invalid,
+     *  or if the day-of-year is invalid for the year
+     */
+    public LocalDate withDayOfYear(int dayOfYear) {
+        if (this.getDayOfYear() == dayOfYear) {
+            return this;
+        }
+        return ofYearDay(year, dayOfYear);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified amount added.
+     * <p>
+     * This returns a {@code LocalDate}, based on this one, with the specified amount added.
+     * The amount is typically {@link Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code LocalDate} based on this date with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDate plus(TemporalAmount amountToAdd) {
+        if (amountToAdd instanceof Period) {
+            Period periodToAdd = (Period) amountToAdd;
+            return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays());
+        }
+        Objects.requireNonNull(amountToAdd, "amountToAdd");
+        return (LocalDate) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date with the specified amount added.
+     * <p>
+     * This returns a {@code LocalDate}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * In some cases, adding the amount can cause the resulting date to become invalid.
+     * For example, adding one month to 31st January would result in 31st February.
+     * In cases like this, the unit is responsible for resolving the date.
+     * Typically it will choose the previous valid date, which would be the last valid
+     * day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code DAYS} -
+     *  Returns a {@code LocalDate} with the specified number of days added.
+     *  This is equivalent to {@link #plusDays(long)}.
+     * <li>{@code WEEKS} -
+     *  Returns a {@code LocalDate} with the specified number of weeks added.
+     *  This is equivalent to {@link #plusWeeks(long)} and uses a 7 day week.
+     * <li>{@code MONTHS} -
+     *  Returns a {@code LocalDate} with the specified number of months added.
+     *  This is equivalent to {@link #plusMonths(long)}.
+     *  The day-of-month will be unchanged unless it would be invalid for the new
+     *  month and year. In that case, the day-of-month is adjusted to the maximum
+     *  valid value for the new month and year.
+     * <li>{@code YEARS} -
+     *  Returns a {@code LocalDate} with the specified number of years added.
+     *  This is equivalent to {@link #plusYears(long)}.
+     *  The day-of-month will be unchanged unless it would be invalid for the new
+     *  month and year. In that case, the day-of-month is adjusted to the maximum
+     *  valid value for the new month and year.
+     * <li>{@code DECADES} -
+     *  Returns a {@code LocalDate} with the specified number of decades added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 10.
+     *  The day-of-month will be unchanged unless it would be invalid for the new
+     *  month and year. In that case, the day-of-month is adjusted to the maximum
+     *  valid value for the new month and year.
+     * <li>{@code CENTURIES} -
+     *  Returns a {@code LocalDate} with the specified number of centuries added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 100.
+     *  The day-of-month will be unchanged unless it would be invalid for the new
+     *  month and year. In that case, the day-of-month is adjusted to the maximum
+     *  valid value for the new month and year.
+     * <li>{@code MILLENNIA} -
+     *  Returns a {@code LocalDate} with the specified number of millennia added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 1,000.
+     *  The day-of-month will be unchanged unless it would be invalid for the new
+     *  month and year. In that case, the day-of-month is adjusted to the maximum
+     *  valid value for the new month and year.
+     * <li>{@code ERAS} -
+     *  Returns a {@code LocalDate} with the specified number of eras added.
+     *  Only two eras are supported so the amount must be one, zero or minus one.
+     *  If the amount is non-zero then the year is changed such that the year-of-era
+     *  is unchanged.
+     *  The day-of-month will be unchanged unless it would be invalid for the new
+     *  month and year. In that case, the day-of-month is adjusted to the maximum
+     *  valid value for the new month and year.
+     * </ul>
+     * <p>
+     * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return a {@code LocalDate} based on this date with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDate plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case DAYS: return plusDays(amountToAdd);
+                case WEEKS: return plusWeeks(amountToAdd);
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of years added.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) plus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a {@code LocalDate} based on this date with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        int newYear = YEAR.checkValidIntValue(year + yearsToAdd);  // safe overflow
+        return resolvePreviousValid(newYear, month, day);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of months added.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 plus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, may be negative
+     * @return a {@code LocalDate} based on this date with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
+            return this;
+        }
+        long monthCount = year * 12L + (month - 1);
+        long calcMonths = monthCount + monthsToAdd;  // safe overflow
+        int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12));
+        int newMonth = (int)Math.floorMod(calcMonths, 12) + 1;
+        return resolvePreviousValid(newYear, newMonth, day);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of weeks added.
+     * <p>
+     * This method adds the specified amount in weeks to the days field incrementing
+     * the month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToAdd  the weeks to add, may be negative
+     * @return a {@code LocalDate} based on this date with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusWeeks(long weeksToAdd) {
+        return plusDays(Math.multiplyExact(weeksToAdd, 7));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of days added.
+     * <p>
+     * This method adds the specified amount to the days field incrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, may be negative
+     * @return a {@code LocalDate} based on this date with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate plusDays(long daysToAdd) {
+        if (daysToAdd == 0) {
+            return this;
+        }
+        long mjDay = Math.addExact(toEpochDay(), daysToAdd);
+        return LocalDate.ofEpochDay(mjDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified amount subtracted.
+     * <p>
+     * This returns a {@code LocalDate}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code LocalDate} based on this date with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDate minus(TemporalAmount amountToSubtract) {
+        if (amountToSubtract instanceof Period) {
+            Period periodToSubtract = (Period) amountToSubtract;
+            return minusMonths(periodToSubtract.toTotalMonths()).minusDays(periodToSubtract.getDays());
+        }
+        Objects.requireNonNull(amountToSubtract, "amountToSubtract");
+        return (LocalDate) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date with the specified amount subtracted.
+     * <p>
+     * This returns a {@code LocalDate}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return a {@code LocalDate} based on this date with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDate minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of years subtracted.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years from the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) minus one year would result in the
+     * invalid date 2007-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2007-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of months subtracted.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months from the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 minus one month would result in the invalid date
+     * 2007-02-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the months to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of weeks subtracted.
+     * <p>
+     * This method subtracts the specified amount in weeks from the days field decrementing
+     * the month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2009-01-07 minus one week would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToSubtract  the weeks to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusWeeks(long weeksToSubtract) {
+        return (weeksToSubtract == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeksToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDate} with the specified number of days subtracted.
+     * <p>
+     * This method subtracts the specified amount from the days field decrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2009-01-01 minus one day would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the days to subtract, may be negative
+     * @return a {@code LocalDate} based on this date with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDate minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date using the specified query.
+     * <p>
+     * This queries this date using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.localDate()) {
+            return (R) this;
+        }
+        return ChronoLocalDate.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#EPOCH_DAY} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDate.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDate);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public Temporal adjustInto(Temporal temporal) {
+        return ChronoLocalDate.super.adjustInto(temporal);
+    }
+
+    /**
+     * Calculates the amount of time until another date in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code LocalDate}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified date.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code LocalDate} using {@link #from(TemporalAccessor)}.
+     * For example, the amount in days between two dates can be calculated
+     * using {@code startDate.until(endDate, DAYS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two dates.
+     * For example, the amount in months between 2012-06-15 and 2012-08-14
+     * will only be one month as it is one day short of two months.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MONTHS);
+     *   amount = MONTHS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS},
+     * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS}
+     * are supported. Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to a {@code LocalDate}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this date and the end date
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code LocalDate}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        LocalDate end = LocalDate.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case DAYS: return daysUntil(end);
+                case WEEKS: return daysUntil(end) / 7;
+                case MONTHS: return monthsUntil(end);
+                case YEARS: return monthsUntil(end) / 12;
+                case DECADES: return monthsUntil(end) / 120;
+                case CENTURIES: return monthsUntil(end) / 1200;
+                case MILLENNIA: return monthsUntil(end) / 12000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.between(this, end);
+    }
+
+    long daysUntil(LocalDate end) {
+        return end.toEpochDay() - toEpochDay();  // no overflow
+    }
+
+    private long monthsUntil(LocalDate end) {
+        long packed1 = getProlepticMonth() * 32L + getDayOfMonth();  // no overflow
+        long packed2 = end.getProlepticMonth() * 32L + end.getDayOfMonth();  // no overflow
+        return (packed2 - packed1) / 32;
+    }
+
+    /**
+     * Calculates the period between this date and another date as a {@code Period}.
+     * <p>
+     * This calculates the period between two dates in terms of years, months and days.
+     * The start and end points are {@code this} and the specified date.
+     * The result will be negative if the end is before the start.
+     * The negative sign will be the same in each of year, month and day.
+     * <p>
+     * The calculation is performed using the ISO calendar system.
+     * If necessary, the input date will be converted to ISO.
+     * <p>
+     * The start date is included, but the end date is not.
+     * The period is calculated by removing complete months, then calculating
+     * the remaining number of days, adjusting to ensure that both have the same sign.
+     * The number of months is then normalized into years and months based on a 12 month year.
+     * A month is considered to be complete if the end day-of-month is greater
+     * than or equal to the start day-of-month.
+     * For example, from {@code 2010-01-15} to {@code 2011-03-18} is "1 year, 2 months and 3 days".
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link Period#between(LocalDate, LocalDate)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   period = start.until(end);
+     *   period = Period.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     *
+     * @param endDateExclusive  the end date, exclusive, which may be in any chronology, not null
+     * @return the period between this date and the end date, not null
+     */
+    @Override
+    public Period until(ChronoLocalDate endDateExclusive) {
+        LocalDate end = LocalDate.from(endDateExclusive);
+        long totalMonths = end.getProlepticMonth() - this.getProlepticMonth();  // safe
+        int days = end.day - this.day;
+        if (totalMonths > 0 && days < 0) {
+            totalMonths--;
+            LocalDate calcDate = this.plusMonths(totalMonths);
+            days = (int) (end.toEpochDay() - calcDate.toEpochDay());  // safe
+        } else if (totalMonths < 0 && days > 0) {
+            totalMonths++;
+            days -= end.lengthOfMonth();
+        }
+        long years = totalMonths / 12;  // safe
+        int months = (int) (totalMonths % 12);  // safe
+        return Period.of(Math.toIntExact(years), months, days);
+    }
+
+    /**
+     * Formats this date using the specified formatter.
+     * <p>
+     * This date will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    @Override  // override for Javadoc and performance
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this date with a time to create a {@code LocalDateTime}.
+     * <p>
+     * This returns a {@code LocalDateTime} formed from this date at the specified time.
+     * All possible combinations of date and time are valid.
+     *
+     * @param time  the time to combine with, not null
+     * @return the local date-time formed from this date and the specified time, not null
+     */
+    @Override
+    public LocalDateTime atTime(LocalTime time) {
+        return LocalDateTime.of(this, time);
+    }
+
+    /**
+     * Combines this date with a time to create a {@code LocalDateTime}.
+     * <p>
+     * This returns a {@code LocalDateTime} formed from this date at the
+     * specified hour and minute.
+     * The seconds and nanosecond fields will be set to zero.
+     * The individual time fields must be within their valid range.
+     * All possible combinations of date and time are valid.
+     *
+     * @param hour  the hour-of-day to use, from 0 to 23
+     * @param minute  the minute-of-hour to use, from 0 to 59
+     * @return the local date-time formed from this date and the specified time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public LocalDateTime atTime(int hour, int minute) {
+        return atTime(LocalTime.of(hour, minute));
+    }
+
+    /**
+     * Combines this date with a time to create a {@code LocalDateTime}.
+     * <p>
+     * This returns a {@code LocalDateTime} formed from this date at the
+     * specified hour, minute and second.
+     * The nanosecond field will be set to zero.
+     * The individual time fields must be within their valid range.
+     * All possible combinations of date and time are valid.
+     *
+     * @param hour  the hour-of-day to use, from 0 to 23
+     * @param minute  the minute-of-hour to use, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local date-time formed from this date and the specified time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public LocalDateTime atTime(int hour, int minute, int second) {
+        return atTime(LocalTime.of(hour, minute, second));
+    }
+
+    /**
+     * Combines this date with a time to create a {@code LocalDateTime}.
+     * <p>
+     * This returns a {@code LocalDateTime} formed from this date at the
+     * specified hour, minute, second and nanosecond.
+     * The individual time fields must be within their valid range.
+     * All possible combinations of date and time are valid.
+     *
+     * @param hour  the hour-of-day to use, from 0 to 23
+     * @param minute  the minute-of-hour to use, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local date-time formed from this date and the specified time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public LocalDateTime atTime(int hour, int minute, int second, int nanoOfSecond) {
+        return atTime(LocalTime.of(hour, minute, second, nanoOfSecond));
+    }
+
+    /**
+     * Combines this date with an offset time to create an {@code OffsetDateTime}.
+     * <p>
+     * This returns an {@code OffsetDateTime} formed from this date at the specified time.
+     * All possible combinations of date and time are valid.
+     *
+     * @param time  the time to combine with, not null
+     * @return the offset date-time formed from this date and the specified time, not null
+     */
+    public OffsetDateTime atTime(OffsetTime time) {
+        return OffsetDateTime.of(LocalDateTime.of(this, time.toLocalTime()), time.getOffset());
+    }
+
+    /**
+     * Combines this date with the time of midnight to create a {@code LocalDateTime}
+     * at the start of this date.
+     * <p>
+     * This returns a {@code LocalDateTime} formed from this date at the time of
+     * midnight, 00:00, at the start of this date.
+     *
+     * @return the local date-time of midnight at the start of this date, not null
+     */
+    public LocalDateTime atStartOfDay() {
+        return LocalDateTime.of(this, LocalTime.MIDNIGHT);
+    }
+
+    /**
+     * Returns a zoned date-time from this date at the earliest valid time according
+     * to the rules in the time-zone.
+     * <p>
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may not be midnight.
+     * <p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, there are two valid offsets, and the earlier one is used,
+     * corresponding to the first occurrence of midnight on the date.
+     * In the case of a gap, the zoned date-time will represent the instant just after the gap.
+     * <p>
+     * If the zone ID is a {@link ZoneOffset}, then the result always has a time of midnight.
+     * <p>
+     * To convert to a specific time in a given time-zone call {@link #atTime(LocalTime)}
+     * followed by {@link LocalDateTime#atZone(ZoneId)}.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null
+     */
+    public ZonedDateTime atStartOfDay(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        // need to handle case where there is a gap from 11:30 to 00:30
+        // standard ZDT factory would result in 01:00 rather than 00:30
+        LocalDateTime ldt = atTime(LocalTime.MIDNIGHT);
+        if (zone instanceof ZoneOffset == false) {
+            ZoneRules rules = zone.getRules();
+            ZoneOffsetTransition trans = rules.getTransition(ldt);
+            if (trans != null && trans.isGap()) {
+                ldt = trans.getDateTimeAfter();
+            }
+        }
+        return ZonedDateTime.of(ldt, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long toEpochDay() {
+        long y = year;
+        long m = month;
+        long total = 0;
+        total += 365 * y;
+        if (y >= 0) {
+            total += (y + 3) / 4 - (y + 99) / 100 + (y + 399) / 400;
+        } else {
+            total -= y / -4 - y / -100 + y / -400;
+        }
+        total += ((367 * m - 362) / 12);
+        total += day - 1;
+        if (m > 2) {
+            total--;
+            if (isLeapYear() == false) {
+                total--;
+            }
+        }
+        return total - DAYS_0000_TO_1970;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date to another date.
+     * <p>
+     * The comparison is primarily based on the date, from earliest to latest.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the dates being compared are instances of {@code LocalDate},
+     * then the comparison will be entirely based on the date.
+     * If some dates being compared are in different chronologies, then the
+     * chronology is also considered, see {@link java.time.chrono.ChronoLocalDate#compareTo}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override  // override for Javadoc and performance
+    public int compareTo(ChronoLocalDate other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other);
+        }
+        return ChronoLocalDate.super.compareTo(other);
+    }
+
+    int compareTo0(LocalDate otherDate) {
+        int cmp = (year - otherDate.year);
+        if (cmp == 0) {
+            cmp = (month - otherDate.month);
+            if (cmp == 0) {
+                cmp = (day - otherDate.day);
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date is after the specified date.
+     * <p>
+     * This checks to see if this date represents a point on the
+     * local time-line after the other date.
+     * <pre>
+     *   LocalDate a = LocalDate.of(2012, 6, 30);
+     *   LocalDate b = LocalDate.of(2012, 7, 1);
+     *   a.isAfter(b) == false
+     *   a.isAfter(a) == false
+     *   b.isAfter(a) == true
+     * </pre>
+     * <p>
+     * This method only considers the position of the two dates on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
+     * but is the same approach as {@link ChronoLocalDate#timeLineOrder()}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this date is after the specified date
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isAfter(ChronoLocalDate other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other) > 0;
+        }
+        return ChronoLocalDate.super.isAfter(other);
+    }
+
+    /**
+     * Checks if this date is before the specified date.
+     * <p>
+     * This checks to see if this date represents a point on the
+     * local time-line before the other date.
+     * <pre>
+     *   LocalDate a = LocalDate.of(2012, 6, 30);
+     *   LocalDate b = LocalDate.of(2012, 7, 1);
+     *   a.isBefore(b) == true
+     *   a.isBefore(a) == false
+     *   b.isBefore(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two dates on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDate)},
+     * but is the same approach as {@link ChronoLocalDate#timeLineOrder()}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this date is before the specified date
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isBefore(ChronoLocalDate other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other) < 0;
+        }
+        return ChronoLocalDate.super.isBefore(other);
+    }
+
+    /**
+     * Checks if this date is equal to the specified date.
+     * <p>
+     * This checks to see if this date represents the same point on the
+     * local time-line as the other date.
+     * <pre>
+     *   LocalDate a = LocalDate.of(2012, 6, 30);
+     *   LocalDate b = LocalDate.of(2012, 7, 1);
+     *   a.isEqual(b) == false
+     *   a.isEqual(a) == true
+     *   b.isEqual(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two dates on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDate)}
+     * but is the same approach as {@link ChronoLocalDate#timeLineOrder()}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this date is equal to the specified date
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isEqual(ChronoLocalDate other) {
+        if (other instanceof LocalDate) {
+            return compareTo0((LocalDate) other) == 0;
+        }
+        return ChronoLocalDate.super.isEqual(other);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date is equal to another date.
+     * <p>
+     * Compares this {@code LocalDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code LocalDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalDate) {
+            return compareTo0((LocalDate) obj) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        int yearValue = year;
+        int monthValue = month;
+        int dayValue = day;
+        return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date as a {@code String}, such as {@code 2007-12-03}.
+     * <p>
+     * The output will be in the ISO-8601 format {@code uuuu-MM-dd}.
+     *
+     * @return a string representation of this date, not null
+     */
+    @Override
+    public String toString() {
+        int yearValue = year;
+        int monthValue = month;
+        int dayValue = day;
+        int absYear = Math.abs(yearValue);
+        StringBuilder buf = new StringBuilder(10);
+        if (absYear < 1000) {
+            if (yearValue < 0) {
+                buf.append(yearValue - 10000).deleteCharAt(1);
+            } else {
+                buf.append(yearValue + 10000).deleteCharAt(0);
+            }
+        } else {
+            if (yearValue > 9999) {
+                buf.append('+');
+            }
+            buf.append(yearValue);
+        }
+        return buf.append(monthValue < 10 ? "-0" : "-")
+            .append(monthValue)
+            .append(dayValue < 10 ? "-0" : "-")
+            .append(dayValue)
+            .toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(3);  // identifies a LocalDate
+     *  out.writeInt(year);
+     *  out.writeByte(month);
+     *  out.writeByte(day);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.LOCAL_DATE_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(year);
+        out.writeByte(month);
+        out.writeByte(day);
+    }
+
+    static LocalDate readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return LocalDate.of(year, month, dayOfMonth);
+    }
+
+}
diff --git a/java/time/LocalDateTime.java b/java/time/LocalDateTime.java
new file mode 100644
index 0000000..5821ffd
--- /dev/null
+++ b/java/time/LocalDateTime.java
@@ -0,0 +1,2007 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.HOURS_PER_DAY;
+import static java.time.LocalTime.MICROS_PER_DAY;
+import static java.time.LocalTime.MILLIS_PER_DAY;
+import static java.time.LocalTime.MINUTES_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_DAY;
+import static java.time.LocalTime.NANOS_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date-time without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30}.
+ * <p>
+ * {@code LocalDateTime} is an immutable date-time object that represents a date-time,
+ * often viewed as year-month-day-hour-minute-second. Other date and time fields,
+ * such as day-of-year, day-of-week and week-of-year, can also be accessed.
+ * Time is represented to nanosecond precision.
+ * For example, the value "2nd October 2007 at 13:45.30.123456789" can be
+ * stored in a {@code LocalDateTime}.
+ * <p>
+ * This class does not store or represent a time-zone.
+ * Instead, it is a description of the date, as used for birthdays, combined with
+ * the local time as seen on a wall clock.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalDateTime
+        implements Temporal, TemporalAdjuster, ChronoLocalDateTime<LocalDate>, Serializable {
+
+    /**
+     * The minimum supported {@code LocalDateTime}, '-999999999-01-01T00:00:00'.
+     * This is the local date-time of midnight at the start of the minimum date.
+     * This combines {@link LocalDate#MIN} and {@link LocalTime#MIN}.
+     * This could be used by an application as a "far past" date-time.
+     */
+    public static final LocalDateTime MIN = LocalDateTime.of(LocalDate.MIN, LocalTime.MIN);
+    /**
+     * The maximum supported {@code LocalDateTime}, '+999999999-12-31T23:59:59.999999999'.
+     * This is the local date-time just before midnight at the end of the maximum date.
+     * This combines {@link LocalDate#MAX} and {@link LocalTime#MAX}.
+     * This could be used by an application as a "far future" date-time.
+     */
+    public static final LocalDateTime MAX = LocalDateTime.of(LocalDate.MAX, LocalTime.MAX);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6207766400415563566L;
+
+    /**
+     * The date part.
+     */
+    private final LocalDate date;
+    /**
+     * The time part.
+     */
+    private final LocalTime time;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date-time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date-time.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date-time using the system clock and default time-zone, not null
+     */
+    public static LocalDateTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date-time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date-time using the system clock, not null
+     */
+    public static LocalDateTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date-time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date-time.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date-time, not null
+     */
+    public static LocalDateTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+        return ofEpochSecond(now.getEpochSecond(), now.getNano(), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour and minute, setting the second and nanosecond to zero.
+     * <p>
+     * This returns a {@code LocalDateTime} with the specified year, month,
+     * day-of-month, hour and minute.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The second and nanosecond fields will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute and second, setting the nanosecond to zero.
+     * <p>
+     * This returns a {@code LocalDateTime} with the specified year, month,
+     * day-of-month, hour, minute and second.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The nanosecond field will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute, second and nanosecond.
+     * <p>
+     * This returns a {@code LocalDateTime} with the specified year, month,
+     * day-of-month, hour, minute, second and nanosecond.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
+        return new LocalDateTime(date, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour and minute, setting the second and nanosecond to zero.
+     * <p>
+     * This returns a {@code LocalDateTime} with the specified year, month,
+     * day-of-month, hour and minute.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The second and nanosecond fields will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute and second, setting the nanosecond to zero.
+     * <p>
+     * This returns a {@code LocalDateTime} with the specified year, month,
+     * day-of-month, hour, minute and second.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * The nanosecond field will be set to zero.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from year, month,
+     * day, hour, minute, second and nanosecond.
+     * <p>
+     * This returns a {@code LocalDateTime} with the specified year, month,
+     * day-of-month, hour, minute, second and nanosecond.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local date-time, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond) {
+        LocalDate date = LocalDate.of(year, month, dayOfMonth);
+        LocalTime time = LocalTime.of(hour, minute, second, nanoOfSecond);
+        return new LocalDateTime(date, time);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a date and time.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @return the local date-time, not null
+     */
+    public static LocalDateTime of(LocalDate date, LocalTime time) {
+        Objects.requireNonNull(date, "date");
+        Objects.requireNonNull(time, "time");
+        return new LocalDateTime(date, time);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from an {@code Instant} and zone ID.
+     * <p>
+     * This creates a local date-time based on the specified instant.
+     * First, the offset from UTC/Greenwich is obtained using the zone ID and instant,
+     * which is simple as there is only one valid offset for each instant.
+     * Then, the instant and offset are used to calculate the local date-time.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, which may be an offset, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static LocalDateTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        return ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * This allows the {@link ChronoField#INSTANT_SECONDS epoch-second} field
+     * to be converted to a local date-time. This is primarily intended for
+     * low-level conversions rather than general application usage.
+     *
+     * @param epochSecond  the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     * @param nanoOfSecond  the nanosecond within the second, from 0 to 999,999,999
+     * @param offset  the zone offset, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range,
+     *  or if the nano-of-second is invalid
+     */
+    public static LocalDateTime ofEpochSecond(long epochSecond, int nanoOfSecond, ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+        long localSecond = epochSecond + offset.getTotalSeconds();  // overflow caught later
+        long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);
+        int secsOfDay = (int)Math.floorMod(localSecond, SECONDS_PER_DAY);
+        LocalDate date = LocalDate.ofEpochDay(localEpochDay);
+        LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + nanoOfSecond);
+        return new LocalDateTime(date, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a temporal object.
+     * <p>
+     * This obtains a local date-time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code LocalDateTime}.
+     * <p>
+     * The conversion extracts and combines the {@code LocalDate} and the
+     * {@code LocalTime} from the temporal object.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code LocalDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date-time, not null
+     * @throws DateTimeException if unable to convert to a {@code LocalDateTime}
+     */
+    public static LocalDateTime from(TemporalAccessor temporal) {
+        if (temporal instanceof LocalDateTime) {
+            return (LocalDateTime) temporal;
+        } else if (temporal instanceof ZonedDateTime) {
+            return ((ZonedDateTime) temporal).toLocalDateTime();
+        } else if (temporal instanceof OffsetDateTime) {
+            return ((OffsetDateTime) temporal).toLocalDateTime();
+        }
+        try {
+            LocalDate date = LocalDate.from(temporal);
+            LocalTime time = LocalTime.from(temporal);
+            return new LocalDateTime(date, time);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain LocalDateTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a text string such as {@code 2007-12-03T10:15:30}.
+     * <p>
+     * The string must represent a valid date-time and is parsed using
+     * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_DATE_TIME}.
+     *
+     * @param text  the text to parse such as "2007-12-03T10:15:30", not null
+     * @return the parsed local date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDateTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalDateTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date-time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed local date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, LocalDateTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param date  the date part of the date-time, validated not null
+     * @param time  the time part of the date-time, validated not null
+     */
+    private LocalDateTime(LocalDate date, LocalTime time) {
+        this.date = date;
+        this.time = time;
+    }
+
+    /**
+     * Returns a copy of this date-time with the new date and time, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newDate  the date of the new date-time, not null
+     * @param newTime  the time of the new date-time, not null
+     * @return the date-time, not null
+     */
+    private LocalDateTime with(LocalDate newDate, LocalTime newTime) {
+        if (date == newDate && time == newTime) {
+            return this;
+        }
+        return new LocalDateTime(newDate, newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code PROLEPTIC_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date-time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return f.isDateBased() || f.isTimeBased();
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code NANOS}
+     * <li>{@code MICROS}
+     * <li>{@code MILLIS}
+     * <li>{@code SECONDS}
+     * <li>{@code MINUTES}
+     * <li>{@code HOURS}
+     * <li>{@code HALF_DAYS}
+     * <li>{@code DAYS}
+     * <li>{@code WEEKS}
+     * <li>{@code MONTHS}
+     * <li>{@code YEARS}
+     * <li>{@code DECADES}
+     * <li>{@code CENTURIES}
+     * <li>{@code MILLENNIA}
+     * <li>{@code ERAS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalUnit unit) {
+        return ChronoLocalDateTime.super.isSupported(unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date-time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeBased() ? time.range(field) : date.range(field));
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as an {@code int}.
+     * <p>
+     * This queries this date-time for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+     * {@code EPOCH_DAY} and {@code PROLEPTIC_MONTH} which are too large to fit in
+     * an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeBased() ? time.get(field) : date.get(field));
+        }
+        return ChronoLocalDateTime.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as a {@code long}.
+     * <p>
+     * This queries this date-time for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeBased() ? time.getLong(field) : date.getLong(field));
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDate} with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    @Override
+    public LocalDate toLocalDate() {
+        return date;
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return date.getYear();
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return date.getMonthValue();
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return date.getMonth();
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return date.getDayOfMonth();
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year, from 1 to 365, or 366 in a leap year
+     */
+    public int getDayOfYear() {
+        return date.getDayOfYear();
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * This method returns the enum {@link DayOfWeek} for the day-of-week.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link DayOfWeek#getValue() int value}.
+     * <p>
+     * Additional information can be obtained from the {@code DayOfWeek}.
+     * This includes textual names of the values.
+     *
+     * @return the day-of-week, not null
+     */
+    public DayOfWeek getDayOfWeek() {
+        return date.getDayOfWeek();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    @Override
+    public LocalTime toLocalTime() {
+        return time;
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return time.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return time.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return time.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return time.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date-time.
+     * <p>
+     * This returns a {@code LocalDateTime}, based on this one, with the date-time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the date to the last day of the month.
+     * <p>
+     * A selection of common adjustments is provided in
+     * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.
+     * These include finding the "last day of the month" and "next Wednesday".
+     * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+     * such as {@link Month} and {@link java.time.MonthDay MonthDay}.
+     * The adjuster is responsible for handling special cases, such as the varying
+     * lengths of month and leap years.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.TemporalAdjusters.*;
+     *
+     *  result = localDateTime.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the date, time or offset:
+     * <pre>
+     *  result = localDateTime.with(date);
+     *  result = localDateTime.with(time);
+     * </pre>
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code LocalDateTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate) {
+            return with((LocalDate) adjuster, time);
+        } else if (adjuster instanceof LocalTime) {
+            return with(date, (LocalTime) adjuster);
+        } else if (adjuster instanceof LocalDateTime) {
+            return (LocalDateTime) adjuster;
+        }
+        return (LocalDateTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified field set to a new value.
+     * <p>
+     * This returns a {@code LocalDateTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year, month or day-of-month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalDate#with(TemporalField, long) LocalDate}
+     * or {@link LocalTime#with(TemporalField, long) LocalTime}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code LocalDateTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (f.isTimeBased()) {
+                return with(date, time.with(field, newValue));
+            } else {
+                return with(date.with(field, newValue), time);
+            }
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the year altered.
+     * <p>
+     * The time does not affect the calculation and will be the same in the result.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
+     * @return a {@code LocalDateTime} based on this date-time with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public LocalDateTime withYear(int year) {
+        return with(date.withYear(year), time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the month-of-year altered.
+     * <p>
+     * The time does not affect the calculation and will be the same in the result.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
+     * @return a {@code LocalDateTime} based on this date-time with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public LocalDateTime withMonth(int month) {
+        return with(date.withMonth(month), time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the day-of-month altered.
+     * <p>
+     * If the resulting date-time is invalid, an exception is thrown.
+     * The time does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
+     * @return a {@code LocalDateTime} based on this date-time with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public LocalDateTime withDayOfMonth(int dayOfMonth) {
+        return with(date.withDayOfMonth(dayOfMonth), time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the day-of-year altered.
+     * <p>
+     * If the resulting date-time is invalid, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
+     * @return a {@code LocalDateTime} based on this date with the requested day, not null
+     * @throws DateTimeException if the day-of-year value is invalid,
+     *  or if the day-of-year is invalid for the year
+     */
+    public LocalDateTime withDayOfYear(int dayOfYear) {
+        return with(date.withDayOfYear(dayOfYear), time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the hour-of-day altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return a {@code LocalDateTime} based on this date-time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public LocalDateTime withHour(int hour) {
+        LocalTime newTime = time.withHour(hour);
+        return with(date, newTime);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the minute-of-hour altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return a {@code LocalDateTime} based on this date-time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public LocalDateTime withMinute(int minute) {
+        LocalTime newTime = time.withMinute(minute);
+        return with(date, newTime);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the second-of-minute altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return a {@code LocalDateTime} based on this date-time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public LocalDateTime withSecond(int second) {
+        LocalTime newTime = time.withSecond(second);
+        return with(date, newTime);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the nano-of-second altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return a {@code LocalDateTime} based on this date-time with the requested nanosecond, not null
+     * @throws DateTimeException if the nano value is invalid
+     */
+    public LocalDateTime withNano(int nanoOfSecond) {
+        LocalTime newTime = time.withNano(nanoOfSecond);
+        return with(date, newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original date-time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
+     * that divides into the length of a standard day without remainder.
+     * This includes all supplied time units on {@link ChronoUnit} and
+     * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return a {@code LocalDateTime} based on this date-time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    public LocalDateTime truncatedTo(TemporalUnit unit) {
+        return with(date, time.truncatedTo(unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified amount added.
+     * <p>
+     * This returns a {@code LocalDateTime}, based on this one, with the specified amount added.
+     * The amount is typically {@link Period} or {@link Duration} but may be
+     * any other type implementing the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code LocalDateTime} based on this date-time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime plus(TemporalAmount amountToAdd) {
+        if (amountToAdd instanceof Period) {
+            Period periodToAdd = (Period) amountToAdd;
+            return with(date.plus(periodToAdd), time);
+        }
+        Objects.requireNonNull(amountToAdd, "amountToAdd");
+        return (LocalDateTime) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified amount added.
+     * <p>
+     * This returns a {@code LocalDateTime}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * Date units are added as per {@link LocalDate#plus(long, TemporalUnit)}.
+     * Time units are added as per {@link LocalTime#plus(long, TemporalUnit)} with
+     * any overflow in days added equivalent to using {@link #plusDays(long)}.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return a {@code LocalDateTime} based on this date-time with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+                case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusMinutes(amountToAdd);
+                case HOURS: return plusHours(amountToAdd);
+                case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12);  // no overflow (256 is multiple of 2)
+            }
+            return with(date.plus(amountToAdd, unit), time);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of years added.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) plus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusYears(long years) {
+        LocalDate newDate = date.plusYears(years);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of months added.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 plus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusMonths(long months) {
+        LocalDate newDate = date.plusMonths(months);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of weeks added.
+     * <p>
+     * This method adds the specified amount in weeks to the days field incrementing
+     * the month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusWeeks(long weeks) {
+        LocalDate newDate = date.plusWeeks(weeks);
+        return with(newDate, time);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of days added.
+     * <p>
+     * This method adds the specified amount to the days field incrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusDays(long days) {
+        LocalDate newDate = date.plusDays(days);
+        return with(newDate, time);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of hours added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the hours added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusHours(long hours) {
+        return plusWithOverflow(date, hours, 0, 0, 0, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of minutes added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the minutes added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusMinutes(long minutes) {
+        return plusWithOverflow(date, 0, minutes, 0, 0, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 0, 1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the nanoseconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime plusNanos(long nanos) {
+        return plusWithOverflow(date, 0, 0, 0, nanos, 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified amount subtracted.
+     * <p>
+     * This returns a {@code LocalDateTime}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Period} or {@link Duration} but may be
+     * any other type implementing the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code LocalDateTime} based on this date-time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime minus(TemporalAmount amountToSubtract) {
+        if (amountToSubtract instanceof Period) {
+            Period periodToSubtract = (Period) amountToSubtract;
+            return with(date.minus(periodToSubtract), time);
+        }
+        Objects.requireNonNull(amountToSubtract, "amountToSubtract");
+        return (LocalDateTime) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified amount subtracted.
+     * <p>
+     * This returns a {@code LocalDateTime}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return a {@code LocalDateTime} based on this date-time with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalDateTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of years subtracted.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years from the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) minus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusYears(long years) {
+        return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of months subtracted.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months from the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 minus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusMonths(long months) {
+        return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of weeks subtracted.
+     * <p>
+     * This method subtracts the specified amount in weeks from the days field decrementing
+     * the month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2009-01-07 minus one week would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusWeeks(long weeks) {
+        return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of days subtracted.
+     * <p>
+     * This method subtracts the specified amount from the days field decrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2009-01-01 minus one day would result in 2008-12-31.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusDays(long days) {
+        return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of hours subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the hours subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusHours(long hours) {
+        return plusWithOverflow(date, hours, 0, 0, 0, -1);
+   }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of minutes subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the minutes subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusMinutes(long minutes) {
+        return plusWithOverflow(date, 0, minutes, 0, 0, -1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 0, -1);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified number of nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return a {@code LocalDateTime} based on this date-time with the nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public LocalDateTime minusNanos(long nanos) {
+        return plusWithOverflow(date, 0, 0, 0, nanos, -1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalDateTime} with the specified period added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param newDate  the new date to base the calculation on, not null
+     * @param hours  the hours to add, may be negative
+     * @param minutes the minutes to add, may be negative
+     * @param seconds the seconds to add, may be negative
+     * @param nanos the nanos to add, may be negative
+     * @param sign  the sign to determine add or subtract
+     * @return the combined result, not null
+     */
+    private LocalDateTime plusWithOverflow(LocalDate newDate, long hours, long minutes, long seconds, long nanos, int sign) {
+        // 9223372036854775808 long, 2147483648 int
+        if ((hours | minutes | seconds | nanos) == 0) {
+            return with(newDate, time);
+        }
+        long totDays = nanos / NANOS_PER_DAY +             //   max/24*60*60*1B
+                seconds / SECONDS_PER_DAY +                //   max/24*60*60
+                minutes / MINUTES_PER_DAY +                //   max/24*60
+                hours / HOURS_PER_DAY;                     //   max/24
+        totDays *= sign;                                   // total max*0.4237...
+        long totNanos = nanos % NANOS_PER_DAY +                    //   max  86400000000000
+                (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND +   //   max  86400000000000
+                (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE +   //   max  86400000000000
+                (hours % HOURS_PER_DAY) * NANOS_PER_HOUR;          //   max  86400000000000
+        long curNoD = time.toNanoOfDay();                       //   max  86400000000000
+        totNanos = totNanos * sign + curNoD;                    // total 432000000000000
+        totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
+        long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
+        LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
+        return with(newDate.plusDays(totDays), newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override  // override for Javadoc
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.localDate()) {
+            return (R) date;
+        }
+        return ChronoLocalDateTime.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date and time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#EPOCH_DAY} and
+     * {@link ChronoField#NANO_OF_DAY} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDateTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDateTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public Temporal adjustInto(Temporal temporal) {
+        return ChronoLocalDateTime.super.adjustInto(temporal);
+    }
+
+    /**
+     * Calculates the amount of time until another date-time in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code LocalDateTime}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified date-time.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code LocalDateTime} using {@link #from(TemporalAccessor)}.
+     * For example, the amount in days between two date-times can be calculated
+     * using {@code startDateTime.until(endDateTime, DAYS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two date-times.
+     * For example, the amount in months between 2012-06-15T00:00 and 2012-08-14T23:59
+     * will only be one month as it is one minute short of two months.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MONTHS);
+     *   amount = MONTHS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+     * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to a {@code LocalDateTime}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this date-time and the end date-time
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code LocalDateTime}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        LocalDateTime end = LocalDateTime.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            if (unit.isTimeBased()) {
+                long amount = date.daysUntil(end.date);
+                if (amount == 0) {
+                    return time.until(end.time, unit);
+                }
+                long timePart = end.time.toNanoOfDay() - time.toNanoOfDay();
+                if (amount > 0) {
+                    amount--;  // safe
+                    timePart += NANOS_PER_DAY;  // safe
+                } else {
+                    amount++;  // safe
+                    timePart -= NANOS_PER_DAY;  // safe
+                }
+                switch ((ChronoUnit) unit) {
+                    case NANOS:
+                        amount = Math.multiplyExact(amount, NANOS_PER_DAY);
+                        break;
+                    case MICROS:
+                        amount = Math.multiplyExact(amount, MICROS_PER_DAY);
+                        timePart = timePart / 1000;
+                        break;
+                    case MILLIS:
+                        amount = Math.multiplyExact(amount, MILLIS_PER_DAY);
+                        timePart = timePart / 1_000_000;
+                        break;
+                    case SECONDS:
+                        amount = Math.multiplyExact(amount, SECONDS_PER_DAY);
+                        timePart = timePart / NANOS_PER_SECOND;
+                        break;
+                    case MINUTES:
+                        amount = Math.multiplyExact(amount, MINUTES_PER_DAY);
+                        timePart = timePart / NANOS_PER_MINUTE;
+                        break;
+                    case HOURS:
+                        amount = Math.multiplyExact(amount, HOURS_PER_DAY);
+                        timePart = timePart / NANOS_PER_HOUR;
+                        break;
+                    case HALF_DAYS:
+                        amount = Math.multiplyExact(amount, 2);
+                        timePart = timePart / (NANOS_PER_HOUR * 12);
+                        break;
+                }
+                return Math.addExact(amount, timePart);
+            }
+            LocalDate endDate = end.date;
+            if (endDate.isAfter(date) && end.time.isBefore(time)) {
+                endDate = endDate.minusDays(1);
+            } else if (endDate.isBefore(date) && end.time.isAfter(time)) {
+                endDate = endDate.plusDays(1);
+            }
+            return date.until(endDate, unit);
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this date-time using the specified formatter.
+     * <p>
+     * This date-time will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    @Override  // override for Javadoc and performance
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this date-time with an offset to create an {@code OffsetDateTime}.
+     * <p>
+     * This returns an {@code OffsetDateTime} formed from this date-time at the specified offset.
+     * All possible combinations of date-time and offset are valid.
+     *
+     * @param offset  the offset to combine with, not null
+     * @return the offset date-time formed from this date-time and the specified offset, not null
+     */
+    public OffsetDateTime atOffset(ZoneOffset offset) {
+        return OffsetDateTime.of(this, offset);
+    }
+
+    /**
+     * Combines this date-time with a time-zone to create a {@code ZonedDateTime}.
+     * <p>
+     * This returns a {@code ZonedDateTime} formed from this date-time at the
+     * specified time-zone. The result will match this date-time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, where clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, where clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     * <p>
+     * To obtain the later offset during an overlap, call
+     * {@link ZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
+     * To throw an exception when there is a gap or overlap, use
+     * {@link ZonedDateTime#ofStrict(LocalDateTime, ZoneOffset, ZoneId)}.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date-time, not null
+     */
+    @Override
+    public ZonedDateTime atZone(ZoneId zone) {
+        return ZonedDateTime.of(this, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time.
+     * <p>
+     * The comparison is primarily based on the date-time, from earliest to latest.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the date-times being compared are instances of {@code LocalDateTime},
+     * then the comparison will be entirely based on the date-time.
+     * If some dates being compared are in different chronologies, then the
+     * chronology is also considered, see {@link ChronoLocalDateTime#compareTo}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override  // override for Javadoc and performance
+    public int compareTo(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other);
+        }
+        return ChronoLocalDateTime.super.compareTo(other);
+    }
+
+    private int compareTo0(LocalDateTime other) {
+        int cmp = date.compareTo0(other.toLocalDate());
+        if (cmp == 0) {
+            cmp = time.compareTo(other.toLocalTime());
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date-time is after the specified date-time.
+     * <p>
+     * This checks to see if this date-time represents a point on the
+     * local time-line after the other date-time.
+     * <pre>
+     *   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+     *   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+     *   a.isAfter(b) == false
+     *   a.isAfter(a) == false
+     *   b.isAfter(a) == true
+     * </pre>
+     * <p>
+     * This method only considers the position of the two date-times on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+     * but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this date-time is after the specified date-time
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isAfter(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other) > 0;
+        }
+        return ChronoLocalDateTime.super.isAfter(other);
+    }
+
+    /**
+     * Checks if this date-time is before the specified date-time.
+     * <p>
+     * This checks to see if this date-time represents a point on the
+     * local time-line before the other date-time.
+     * <pre>
+     *   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+     *   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+     *   a.isBefore(b) == true
+     *   a.isBefore(a) == false
+     *   b.isBefore(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two date-times on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+     * but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this date-time is before the specified date-time
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isBefore(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other) < 0;
+        }
+        return ChronoLocalDateTime.super.isBefore(other);
+    }
+
+    /**
+     * Checks if this date-time is equal to the specified date-time.
+     * <p>
+     * This checks to see if this date-time represents the same point on the
+     * local time-line as the other date-time.
+     * <pre>
+     *   LocalDate a = LocalDateTime.of(2012, 6, 30, 12, 00);
+     *   LocalDate b = LocalDateTime.of(2012, 7, 1, 12, 00);
+     *   a.isEqual(b) == false
+     *   a.isEqual(a) == true
+     *   b.isEqual(a) == false
+     * </pre>
+     * <p>
+     * This method only considers the position of the two date-times on the local time-line.
+     * It does not take into account the chronology, or calendar system.
+     * This is different from the comparison in {@link #compareTo(ChronoLocalDateTime)},
+     * but is the same approach as {@link ChronoLocalDateTime#timeLineOrder()}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this date-time is equal to the specified date-time
+     */
+    @Override  // override for Javadoc and performance
+    public boolean isEqual(ChronoLocalDateTime<?> other) {
+        if (other instanceof LocalDateTime) {
+            return compareTo0((LocalDateTime) other) == 0;
+        }
+        return ChronoLocalDateTime.super.isEqual(other);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * Compares this {@code LocalDateTime} with another ensuring that the date-time is the same.
+     * Only objects of type {@code LocalDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalDateTime) {
+            LocalDateTime other = (LocalDateTime) obj;
+            return date.equals(other.date) && time.equals(other.time);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return date.hashCode() ^ time.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <ul>
+     * <li>{@code uuuu-MM-dd'T'HH:mm}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSS}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSS}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
+     * </ul>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    public String toString() {
+        return date.toString() + 'T' + time.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(5);  // identifies a LocalDateTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalDate">date</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.LocalTime">time</a> excluding the one byte header
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.LOCAL_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        date.writeExternal(out);
+        time.writeExternal(out);
+    }
+
+    static LocalDateTime readExternal(DataInput in) throws IOException {
+        LocalDate date = LocalDate.readExternal(in);
+        LocalTime time = LocalTime.readExternal(in);
+        return LocalDateTime.of(date, time);
+    }
+
+}
diff --git a/java/time/LocalTime.java b/java/time/LocalTime.java
new file mode 100644
index 0000000..b0b1b4d
--- /dev/null
+++ b/java/time/LocalTime.java
@@ -0,0 +1,1687 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A time without a time-zone in the ISO-8601 calendar system,
+ * such as {@code 10:15:30}.
+ * <p>
+ * {@code LocalTime} is an immutable date-time object that represents a time,
+ * often viewed as hour-minute-second.
+ * Time is represented to nanosecond precision.
+ * For example, the value "13:45.30.123456789" can be stored in a {@code LocalTime}.
+ * <p>
+ * This class does not store or represent a date or time-zone.
+ * Instead, it is a description of the local time as seen on a wall clock.
+ * It cannot represent an instant on the time-line without additional information
+ * such as an offset or time-zone.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. This API assumes that all calendar systems use the same
+ * representation, this class, for time-of-day.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class LocalTime
+        implements Temporal, TemporalAdjuster, Comparable<LocalTime>, Serializable {
+
+    /**
+     * The minimum supported {@code LocalTime}, '00:00'.
+     * This is the time of midnight at the start of the day.
+     */
+    public static final LocalTime MIN;
+    /**
+     * The maximum supported {@code LocalTime}, '23:59:59.999999999'.
+     * This is the time just before midnight at the end of the day.
+     */
+    public static final LocalTime MAX;
+    /**
+     * The time of midnight at the start of the day, '00:00'.
+     */
+    public static final LocalTime MIDNIGHT;
+    /**
+     * The time of noon in the middle of the day, '12:00'.
+     */
+    public static final LocalTime NOON;
+    /**
+     * Constants for the local time of each hour.
+     */
+    private static final LocalTime[] HOURS = new LocalTime[24];
+    static {
+        for (int i = 0; i < HOURS.length; i++) {
+            HOURS[i] = new LocalTime(i, 0, 0, 0);
+        }
+        MIDNIGHT = HOURS[0];
+        NOON = HOURS[12];
+        MIN = HOURS[0];
+        MAX = new LocalTime(23, 59, 59, 999_999_999);
+    }
+
+    /**
+     * Hours per day.
+     */
+    static final int HOURS_PER_DAY = 24;
+    /**
+     * Minutes per hour.
+     */
+    static final int MINUTES_PER_HOUR = 60;
+    /**
+     * Minutes per day.
+     */
+    static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Seconds per minute.
+     */
+    static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * Seconds per hour.
+     */
+    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Seconds per day.
+     */
+    static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Milliseconds per day.
+     */
+    static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
+    /**
+     * Microseconds per day.
+     */
+    static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
+    /**
+     * Nanos per second.
+     */
+    static final long NANOS_PER_SECOND = 1000_000_000L;
+    /**
+     * Nanos per minute.
+     */
+    static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
+    /**
+     * Nanos per hour.
+     */
+    static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Nanos per day.
+     */
+    static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6414437269572265201L;
+
+    /**
+     * The hour.
+     */
+    private final byte hour;
+    /**
+     * The minute.
+     */
+    private final byte minute;
+    /**
+     * The second.
+     */
+    private final byte second;
+    /**
+     * The nanosecond.
+     */
+    private final int nano;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current time.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current time using the system clock and default time-zone, not null
+     */
+    public static LocalTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current time using the system clock, not null
+     */
+    public static LocalTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current time.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current time, not null
+     */
+    public static LocalTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        // inline OffsetTime factory to avoid creating object and InstantProvider checks
+        final Instant now = clock.instant();  // called once
+        ZoneOffset offset = clock.getZone().getRules().getOffset(now);
+        long localSecond = now.getEpochSecond() + offset.getTotalSeconds();  // overflow caught later
+        int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
+        return ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + now.getNano());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour and minute.
+     * <p>
+     * This returns a {@code LocalTime} with the specified hour and minute.
+     * The second and nanosecond fields will be set to zero.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        if (minute == 0) {
+            return HOURS[hour];  // for performance
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        return new LocalTime(hour, minute, 0, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour, minute and second.
+     * <p>
+     * This returns a {@code LocalTime} with the specified hour, minute and second.
+     * The nanosecond field will be set to zero.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute, int second) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        if ((minute | second) == 0) {
+            return HOURS[hour];  // for performance
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        SECOND_OF_MINUTE.checkValidValue(second);
+        return new LocalTime(hour, minute, second, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from an hour, minute, second and nanosecond.
+     * <p>
+     * This returns a {@code LocalTime} with the specified hour, minute, second and nanosecond.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @return the local time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static LocalTime of(int hour, int minute, int second, int nanoOfSecond) {
+        HOUR_OF_DAY.checkValidValue(hour);
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        SECOND_OF_MINUTE.checkValidValue(second);
+        NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+        return create(hour, minute, second, nanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from a second-of-day value.
+     * <p>
+     * This returns a {@code LocalTime} with the specified second-of-day.
+     * The nanosecond field will be set to zero.
+     *
+     * @param secondOfDay  the second-of-day, from {@code 0} to {@code 24 * 60 * 60 - 1}
+     * @return the local time, not null
+     * @throws DateTimeException if the second-of-day value is invalid
+     */
+    public static LocalTime ofSecondOfDay(long secondOfDay) {
+        SECOND_OF_DAY.checkValidValue(secondOfDay);
+        int hours = (int) (secondOfDay / SECONDS_PER_HOUR);
+        secondOfDay -= hours * SECONDS_PER_HOUR;
+        int minutes = (int) (secondOfDay / SECONDS_PER_MINUTE);
+        secondOfDay -= minutes * SECONDS_PER_MINUTE;
+        return create(hours, minutes, (int) secondOfDay, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from a nanos-of-day value.
+     * <p>
+     * This returns a {@code LocalTime} with the specified nanosecond-of-day.
+     *
+     * @param nanoOfDay  the nano of day, from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}
+     * @return the local time, not null
+     * @throws DateTimeException if the nanos of day value is invalid
+     */
+    public static LocalTime ofNanoOfDay(long nanoOfDay) {
+        NANO_OF_DAY.checkValidValue(nanoOfDay);
+        int hours = (int) (nanoOfDay / NANOS_PER_HOUR);
+        nanoOfDay -= hours * NANOS_PER_HOUR;
+        int minutes = (int) (nanoOfDay / NANOS_PER_MINUTE);
+        nanoOfDay -= minutes * NANOS_PER_MINUTE;
+        int seconds = (int) (nanoOfDay / NANOS_PER_SECOND);
+        nanoOfDay -= seconds * NANOS_PER_SECOND;
+        return create(hours, minutes, seconds, (int) nanoOfDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from a temporal object.
+     * <p>
+     * This obtains a local time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code LocalTime}.
+     * <p>
+     * The conversion uses the {@link TemporalQueries#localTime()} query, which relies
+     * on extracting the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code LocalTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local time, not null
+     * @throws DateTimeException if unable to convert to a {@code LocalTime}
+     */
+    public static LocalTime from(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        LocalTime time = temporal.query(TemporalQueries.localTime());
+        if (time == null) {
+            throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
+        }
+        return time;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code LocalTime} from a text string such as {@code 10:15}.
+     * <p>
+     * The string must represent a valid time and is parsed using
+     * {@link java.time.format.DateTimeFormatter#ISO_LOCAL_TIME}.
+     *
+     * @param text  the text to parse such as "10:15:30", not null
+     * @return the parsed local time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatter.ISO_LOCAL_TIME);
+    }
+
+    /**
+     * Obtains an instance of {@code LocalTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed local time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static LocalTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, LocalTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a local time from the hour, minute, second and nanosecond fields.
+     * <p>
+     * This factory may return a cached value, but applications must not rely on this.
+     *
+     * @param hour  the hour-of-day to represent, validated from 0 to 23
+     * @param minute  the minute-of-hour to represent, validated from 0 to 59
+     * @param second  the second-of-minute to represent, validated from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, validated from 0 to 999,999,999
+     * @return the local time, not null
+     */
+    private static LocalTime create(int hour, int minute, int second, int nanoOfSecond) {
+        if ((minute | second | nanoOfSecond) == 0) {
+            return HOURS[hour];
+        }
+        return new LocalTime(hour, minute, second, nanoOfSecond);
+    }
+
+    /**
+     * Constructor, previously validated.
+     *
+     * @param hour  the hour-of-day to represent, validated from 0 to 23
+     * @param minute  the minute-of-hour to represent, validated from 0 to 59
+     * @param second  the second-of-minute to represent, validated from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, validated from 0 to 999,999,999
+     */
+    private LocalTime(int hour, int minute, int second, int nanoOfSecond) {
+        this.hour = (byte) hour;
+        this.minute = (byte) minute;
+        this.second = (byte) second;
+        this.nano = nanoOfSecond;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field.isTimeBased();
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code NANOS}
+     * <li>{@code MICROS}
+     * <li>{@code MILLIS}
+     * <li>{@code SECONDS}
+     * <li>{@code MINUTES}
+     * <li>{@code HOURS}
+     * <li>{@code HALF_DAYS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit.isTimeBased();
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override  // override for Javadoc
+    public ValueRange range(TemporalField field) {
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as an {@code int}.
+     * <p>
+     * This queries this time for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
+     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return get0(field);
+        }
+        return Temporal.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as a {@code long}.
+     * <p>
+     * This queries this time for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == NANO_OF_DAY) {
+                return toNanoOfDay();
+            }
+            if (field == MICRO_OF_DAY) {
+                return toNanoOfDay() / 1000;
+            }
+            return get0(field);
+        }
+        return field.getFrom(this);
+    }
+
+    private int get0(TemporalField field) {
+        switch ((ChronoField) field) {
+            case NANO_OF_SECOND: return nano;
+            case NANO_OF_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'NanoOfDay' for get() method, use getLong() instead");
+            case MICRO_OF_SECOND: return nano / 1000;
+            case MICRO_OF_DAY: throw new UnsupportedTemporalTypeException("Invalid field 'MicroOfDay' for get() method, use getLong() instead");
+            case MILLI_OF_SECOND: return nano / 1000_000;
+            case MILLI_OF_DAY: return (int) (toNanoOfDay() / 1000_000);
+            case SECOND_OF_MINUTE: return second;
+            case SECOND_OF_DAY: return toSecondOfDay();
+            case MINUTE_OF_HOUR: return minute;
+            case MINUTE_OF_DAY: return hour * 60 + minute;
+            case HOUR_OF_AMPM: return hour % 12;
+            case CLOCK_HOUR_OF_AMPM: int ham = hour % 12; return (ham % 12 == 0 ? 12 : ham);
+            case HOUR_OF_DAY: return hour;
+            case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour);
+            case AMPM_OF_DAY: return hour / 12;
+        }
+        throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return hour;
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return minute;
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return second;
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return nano;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this time.
+     * <p>
+     * This returns a {@code LocalTime}, based on this one, with the time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the hour field.
+     * A more complex adjuster might set the time to the last hour of the day.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code LocalTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalTime) {
+            return (LocalTime) adjuster;
+        }
+        return (LocalTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified field set to a new value.
+     * <p>
+     * This returns a {@code LocalTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the hour, minute or second.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND} -
+     *  Returns a {@code LocalTime} with the specified nano-of-second.
+     *  The hour, minute and second will be unchanged.
+     * <li>{@code NANO_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified nano-of-day.
+     *  This completely replaces the time and is equivalent to {@link #ofNanoOfDay(long)}.
+     * <li>{@code MICRO_OF_SECOND} -
+     *  Returns a {@code LocalTime} with the nano-of-second replaced by the specified
+     *  micro-of-second multiplied by 1,000.
+     *  The hour, minute and second will be unchanged.
+     * <li>{@code MICRO_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified micro-of-day.
+     *  This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)}
+     *  with the micro-of-day multiplied by 1,000.
+     * <li>{@code MILLI_OF_SECOND} -
+     *  Returns a {@code LocalTime} with the nano-of-second replaced by the specified
+     *  milli-of-second multiplied by 1,000,000.
+     *  The hour, minute and second will be unchanged.
+     * <li>{@code MILLI_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified milli-of-day.
+     *  This completely replaces the time and is equivalent to using {@link #ofNanoOfDay(long)}
+     *  with the milli-of-day multiplied by 1,000,000.
+     * <li>{@code SECOND_OF_MINUTE} -
+     *  Returns a {@code LocalTime} with the specified second-of-minute.
+     *  The hour, minute and nano-of-second will be unchanged.
+     * <li>{@code SECOND_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified second-of-day.
+     *  The nano-of-second will be unchanged.
+     * <li>{@code MINUTE_OF_HOUR} -
+     *  Returns a {@code LocalTime} with the specified minute-of-hour.
+     *  The hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code MINUTE_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified minute-of-day.
+     *  The second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code HOUR_OF_AMPM} -
+     *  Returns a {@code LocalTime} with the specified hour-of-am-pm.
+     *  The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code CLOCK_HOUR_OF_AMPM} -
+     *  Returns a {@code LocalTime} with the specified clock-hour-of-am-pm.
+     *  The AM/PM, minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code HOUR_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified hour-of-day.
+     *  The minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code CLOCK_HOUR_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified clock-hour-of-day.
+     *  The minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * <li>{@code AMPM_OF_DAY} -
+     *  Returns a {@code LocalTime} with the specified AM/PM.
+     *  The hour-of-am-pm, minute-of-hour, second-of-minute and nano-of-second will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code LocalTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case NANO_OF_SECOND: return withNano((int) newValue);
+                case NANO_OF_DAY: return LocalTime.ofNanoOfDay(newValue);
+                case MICRO_OF_SECOND: return withNano((int) newValue * 1000);
+                case MICRO_OF_DAY: return LocalTime.ofNanoOfDay(newValue * 1000);
+                case MILLI_OF_SECOND: return withNano((int) newValue * 1000_000);
+                case MILLI_OF_DAY: return LocalTime.ofNanoOfDay(newValue * 1000_000);
+                case SECOND_OF_MINUTE: return withSecond((int) newValue);
+                case SECOND_OF_DAY: return plusSeconds(newValue - toSecondOfDay());
+                case MINUTE_OF_HOUR: return withMinute((int) newValue);
+                case MINUTE_OF_DAY: return plusMinutes(newValue - (hour * 60 + minute));
+                case HOUR_OF_AMPM: return plusHours(newValue - (hour % 12));
+                case CLOCK_HOUR_OF_AMPM: return plusHours((newValue == 12 ? 0 : newValue) - (hour % 12));
+                case HOUR_OF_DAY: return withHour((int) newValue);
+                case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue));
+                case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the hour-of-day altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return a {@code LocalTime} based on this time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public LocalTime withHour(int hour) {
+        if (this.hour == hour) {
+            return this;
+        }
+        HOUR_OF_DAY.checkValidValue(hour);
+        return create(hour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the minute-of-hour altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return a {@code LocalTime} based on this time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public LocalTime withMinute(int minute) {
+        if (this.minute == minute) {
+            return this;
+        }
+        MINUTE_OF_HOUR.checkValidValue(minute);
+        return create(hour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the second-of-minute altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return a {@code LocalTime} based on this time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public LocalTime withSecond(int second) {
+        if (this.second == second) {
+            return this;
+        }
+        SECOND_OF_MINUTE.checkValidValue(second);
+        return create(hour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the nano-of-second altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return a {@code LocalTime} based on this time with the requested nanosecond, not null
+     * @throws DateTimeException if the nanos value is invalid
+     */
+    public LocalTime withNano(int nanoOfSecond) {
+        if (this.nano == nanoOfSecond) {
+            return this;
+        }
+        NANO_OF_SECOND.checkValidValue(nanoOfSecond);
+        return create(hour, minute, second, nanoOfSecond);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
+     * that divides into the length of a standard day without remainder.
+     * This includes all supplied time units on {@link ChronoUnit} and
+     * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return a {@code LocalTime} based on this time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    public LocalTime truncatedTo(TemporalUnit unit) {
+        if (unit == ChronoUnit.NANOS) {
+            return this;
+        }
+        Duration unitDur = unit.getDuration();
+        if (unitDur.getSeconds() > SECONDS_PER_DAY) {
+            throw new UnsupportedTemporalTypeException("Unit is too large to be used for truncation");
+        }
+        long dur = unitDur.toNanos();
+        if ((NANOS_PER_DAY % dur) != 0) {
+            throw new UnsupportedTemporalTypeException("Unit must divide into a standard day without remainder");
+        }
+        long nod = toNanoOfDay();
+        return ofNanoOfDay((nod / dur) * dur);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this time with the specified amount added.
+     * <p>
+     * This returns a {@code LocalTime}, based on this one, with the specified amount added.
+     * The amount is typically {@link Duration} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code LocalTime} based on this time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime plus(TemporalAmount amountToAdd) {
+        return (LocalTime) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified amount added.
+     * <p>
+     * This returns a {@code LocalTime}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code NANOS} -
+     *  Returns a {@code LocalTime} with the specified number of nanoseconds added.
+     *  This is equivalent to {@link #plusNanos(long)}.
+     * <li>{@code MICROS} -
+     *  Returns a {@code LocalTime} with the specified number of microseconds added.
+     *  This is equivalent to {@link #plusNanos(long)} with the amount
+     *  multiplied by 1,000.
+     * <li>{@code MILLIS} -
+     *  Returns a {@code LocalTime} with the specified number of milliseconds added.
+     *  This is equivalent to {@link #plusNanos(long)} with the amount
+     *  multiplied by 1,000,000.
+     * <li>{@code SECONDS} -
+     *  Returns a {@code LocalTime} with the specified number of seconds added.
+     *  This is equivalent to {@link #plusSeconds(long)}.
+     * <li>{@code MINUTES} -
+     *  Returns a {@code LocalTime} with the specified number of minutes added.
+     *  This is equivalent to {@link #plusMinutes(long)}.
+     * <li>{@code HOURS} -
+     *  Returns a {@code LocalTime} with the specified number of hours added.
+     *  This is equivalent to {@link #plusHours(long)}.
+     * <li>{@code HALF_DAYS} -
+     *  Returns a {@code LocalTime} with the specified number of half-days added.
+     *  This is equivalent to {@link #plusHours(long)} with the amount
+     *  multiplied by 12.
+     * </ul>
+     * <p>
+     * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return a {@code LocalTime} based on this time with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+                case MILLIS: return plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusMinutes(amountToAdd);
+                case HOURS: return plusHours(amountToAdd);
+                case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of hours added.
+     * <p>
+     * This adds the specified number of hours to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hoursToAdd  the hours to add, may be negative
+     * @return a {@code LocalTime} based on this time with the hours added, not null
+     */
+    public LocalTime plusHours(long hoursToAdd) {
+        if (hoursToAdd == 0) {
+            return this;
+        }
+        int newHour = ((int) (hoursToAdd % HOURS_PER_DAY) + hour + HOURS_PER_DAY) % HOURS_PER_DAY;
+        return create(newHour, minute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of minutes added.
+     * <p>
+     * This adds the specified number of minutes to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutesToAdd  the minutes to add, may be negative
+     * @return a {@code LocalTime} based on this time with the minutes added, not null
+     */
+    public LocalTime plusMinutes(long minutesToAdd) {
+        if (minutesToAdd == 0) {
+            return this;
+        }
+        int mofd = hour * MINUTES_PER_HOUR + minute;
+        int newMofd = ((int) (minutesToAdd % MINUTES_PER_DAY) + mofd + MINUTES_PER_DAY) % MINUTES_PER_DAY;
+        if (mofd == newMofd) {
+            return this;
+        }
+        int newHour = newMofd / MINUTES_PER_HOUR;
+        int newMinute = newMofd % MINUTES_PER_HOUR;
+        return create(newHour, newMinute, second, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of seconds added.
+     * <p>
+     * This adds the specified number of seconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondstoAdd  the seconds to add, may be negative
+     * @return a {@code LocalTime} based on this time with the seconds added, not null
+     */
+    public LocalTime plusSeconds(long secondstoAdd) {
+        if (secondstoAdd == 0) {
+            return this;
+        }
+        int sofd = hour * SECONDS_PER_HOUR +
+                    minute * SECONDS_PER_MINUTE + second;
+        int newSofd = ((int) (secondstoAdd % SECONDS_PER_DAY) + sofd + SECONDS_PER_DAY) % SECONDS_PER_DAY;
+        if (sofd == newSofd) {
+            return this;
+        }
+        int newHour = newSofd / SECONDS_PER_HOUR;
+        int newMinute = (newSofd / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+        int newSecond = newSofd % SECONDS_PER_MINUTE;
+        return create(newHour, newMinute, newSecond, nano);
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of nanoseconds added.
+     * <p>
+     * This adds the specified number of nanoseconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToAdd  the nanos to add, may be negative
+     * @return a {@code LocalTime} based on this time with the nanoseconds added, not null
+     */
+    public LocalTime plusNanos(long nanosToAdd) {
+        if (nanosToAdd == 0) {
+            return this;
+        }
+        long nofd = toNanoOfDay();
+        long newNofd = ((nanosToAdd % NANOS_PER_DAY) + nofd + NANOS_PER_DAY) % NANOS_PER_DAY;
+        if (nofd == newNofd) {
+            return this;
+        }
+        int newHour = (int) (newNofd / NANOS_PER_HOUR);
+        int newMinute = (int) ((newNofd / NANOS_PER_MINUTE) % MINUTES_PER_HOUR);
+        int newSecond = (int) ((newNofd / NANOS_PER_SECOND) % SECONDS_PER_MINUTE);
+        int newNano = (int) (newNofd % NANOS_PER_SECOND);
+        return create(newHour, newMinute, newSecond, newNano);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this time with the specified amount subtracted.
+     * <p>
+     * This returns a {@code LocalTime}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Duration} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code LocalTime} based on this time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime minus(TemporalAmount amountToSubtract) {
+        return (LocalTime) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified amount subtracted.
+     * <p>
+     * This returns a {@code LocalTime}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return a {@code LocalTime} based on this time with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public LocalTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of hours subtracted.
+     * <p>
+     * This subtracts the specified number of hours from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hoursToSubtract  the hours to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the hours subtracted, not null
+     */
+    public LocalTime minusHours(long hoursToSubtract) {
+        return plusHours(-(hoursToSubtract % HOURS_PER_DAY));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of minutes subtracted.
+     * <p>
+     * This subtracts the specified number of minutes from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutesToSubtract  the minutes to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the minutes subtracted, not null
+     */
+    public LocalTime minusMinutes(long minutesToSubtract) {
+        return plusMinutes(-(minutesToSubtract % MINUTES_PER_DAY));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of seconds subtracted.
+     * <p>
+     * This subtracts the specified number of seconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param secondsToSubtract  the seconds to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the seconds subtracted, not null
+     */
+    public LocalTime minusSeconds(long secondsToSubtract) {
+        return plusSeconds(-(secondsToSubtract % SECONDS_PER_DAY));
+    }
+
+    /**
+     * Returns a copy of this {@code LocalTime} with the specified number of nanoseconds subtracted.
+     * <p>
+     * This subtracts the specified number of nanoseconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanosToSubtract  the nanos to subtract, may be negative
+     * @return a {@code LocalTime} based on this time with the nanoseconds subtracted, not null
+     */
+    public LocalTime minusNanos(long nanosToSubtract) {
+        return plusNanos(-(nanosToSubtract % NANOS_PER_DAY));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this time using the specified query.
+     * <p>
+     * This queries this time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.chronology() || query == TemporalQueries.zoneId() ||
+                query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
+            return null;
+        } else if (query == TemporalQueries.localTime()) {
+            return (R) this;
+        } else if (query == TemporalQueries.localDate()) {
+            return null;
+        } else if (query == TemporalQueries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#NANO_OF_DAY} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal.with(NANO_OF_DAY, toNanoOfDay());
+    }
+
+    /**
+     * Calculates the amount of time until another time in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code LocalTime}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified time.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code LocalTime} using {@link #from(TemporalAccessor)}.
+     * For example, the amount in hours between two times can be calculated
+     * using {@code startTime.until(endTime, HOURS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two times.
+     * For example, the amount in hours between 11:30 and 13:29 will only
+     * be one hour as it is one minute short of two hours.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MINUTES);
+     *   amount = MINUTES.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end time, exclusive, which is converted to a {@code LocalTime}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this time and the end time
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code LocalTime}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        LocalTime end = LocalTime.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            long nanosUntil = end.toNanoOfDay() - toNanoOfDay();  // no overflow
+            switch ((ChronoUnit) unit) {
+                case NANOS: return nanosUntil;
+                case MICROS: return nanosUntil / 1000;
+                case MILLIS: return nanosUntil / 1000_000;
+                case SECONDS: return nanosUntil / NANOS_PER_SECOND;
+                case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
+                case HOURS: return nanosUntil / NANOS_PER_HOUR;
+                case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this time using the specified formatter.
+     * <p>
+     * This time will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this time with a date to create a {@code LocalDateTime}.
+     * <p>
+     * This returns a {@code LocalDateTime} formed from this time at the specified date.
+     * All possible combinations of date and time are valid.
+     *
+     * @param date  the date to combine with, not null
+     * @return the local date-time formed from this time and the specified date, not null
+     */
+    public LocalDateTime atDate(LocalDate date) {
+        return LocalDateTime.of(date, this);
+    }
+
+    /**
+     * Combines this time with an offset to create an {@code OffsetTime}.
+     * <p>
+     * This returns an {@code OffsetTime} formed from this time at the specified offset.
+     * All possible combinations of time and offset are valid.
+     *
+     * @param offset  the offset to combine with, not null
+     * @return the offset time formed from this time and the specified offset, not null
+     */
+    public OffsetTime atOffset(ZoneOffset offset) {
+        return OffsetTime.of(this, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Extracts the time as seconds of day,
+     * from {@code 0} to {@code 24 * 60 * 60 - 1}.
+     *
+     * @return the second-of-day equivalent to this time
+     */
+    public int toSecondOfDay() {
+        int total = hour * SECONDS_PER_HOUR;
+        total += minute * SECONDS_PER_MINUTE;
+        total += second;
+        return total;
+    }
+
+    /**
+     * Extracts the time as nanos of day,
+     * from {@code 0} to {@code 24 * 60 * 60 * 1,000,000,000 - 1}.
+     *
+     * @return the nano of day equivalent to this time
+     */
+    public long toNanoOfDay() {
+        long total = hour * NANOS_PER_HOUR;
+        total += minute * NANOS_PER_MINUTE;
+        total += second * NANOS_PER_SECOND;
+        total += nano;
+        return total;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this time to another time.
+     * <p>
+     * The comparison is based on the time-line position of the local times within a day.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(LocalTime other) {
+        int cmp = Integer.compare(hour, other.hour);
+        if (cmp == 0) {
+            cmp = Integer.compare(minute, other.minute);
+            if (cmp == 0) {
+                cmp = Integer.compare(second, other.second);
+                if (cmp == 0) {
+                    cmp = Integer.compare(nano, other.nano);
+                }
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this time is after the specified time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is after the specified time
+     * @throws NullPointerException if {@code other} is null
+     */
+    public boolean isAfter(LocalTime other) {
+        return compareTo(other) > 0;
+    }
+
+    /**
+     * Checks if this time is before the specified time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this point is before the specified time
+     * @throws NullPointerException if {@code other} is null
+     */
+    public boolean isBefore(LocalTime other) {
+        return compareTo(other) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this time is equal to another time.
+     * <p>
+     * The comparison is based on the time-line position of the time within a day.
+     * <p>
+     * Only objects of type {@code LocalTime} are compared, other types return false.
+     * To compare the date of two {@code TemporalAccessor} instances, use
+     * {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof LocalTime) {
+            LocalTime other = (LocalTime) obj;
+            return hour == other.hour && minute == other.minute &&
+                    second == other.second && nano == other.nano;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        long nod = toNanoOfDay();
+        return (int) (nod ^ (nod >>> 32));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this time as a {@code String}, such as {@code 10:15}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <ul>
+     * <li>{@code HH:mm}</li>
+     * <li>{@code HH:mm:ss}</li>
+     * <li>{@code HH:mm:ss.SSS}</li>
+     * <li>{@code HH:mm:ss.SSSSSS}</li>
+     * <li>{@code HH:mm:ss.SSSSSSSSS}</li>
+     * </ul>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this time, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(18);
+        int hourValue = hour;
+        int minuteValue = minute;
+        int secondValue = second;
+        int nanoValue = nano;
+        buf.append(hourValue < 10 ? "0" : "").append(hourValue)
+            .append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
+        if (secondValue > 0 || nanoValue > 0) {
+            buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
+            if (nanoValue > 0) {
+                buf.append('.');
+                if (nanoValue % 1000_000 == 0) {
+                    buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
+                } else if (nanoValue % 1000 == 0) {
+                    buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
+                } else {
+                    buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
+                }
+            }
+        }
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * A twos-complement value indicates the remaining values are not in the stream
+     * and should be set to zero.
+     * <pre>
+     *  out.writeByte(4);  // identifies a LocalTime
+     *  if (nano == 0) {
+     *    if (second == 0) {
+     *      if (minute == 0) {
+     *        out.writeByte(~hour);
+     *      } else {
+     *        out.writeByte(hour);
+     *        out.writeByte(~minute);
+     *      }
+     *    } else {
+     *      out.writeByte(hour);
+     *      out.writeByte(minute);
+     *      out.writeByte(~second);
+     *    }
+     *  } else {
+     *    out.writeByte(hour);
+     *    out.writeByte(minute);
+     *    out.writeByte(second);
+     *    out.writeInt(nano);
+     *  }
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.LOCAL_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        if (nano == 0) {
+            if (second == 0) {
+                if (minute == 0) {
+                    out.writeByte(~hour);
+                } else {
+                    out.writeByte(hour);
+                    out.writeByte(~minute);
+                }
+            } else {
+                out.writeByte(hour);
+                out.writeByte(minute);
+                out.writeByte(~second);
+            }
+        } else {
+            out.writeByte(hour);
+            out.writeByte(minute);
+            out.writeByte(second);
+            out.writeInt(nano);
+        }
+    }
+
+    static LocalTime readExternal(DataInput in) throws IOException {
+        int hour = in.readByte();
+        int minute = 0;
+        int second = 0;
+        int nano = 0;
+        if (hour < 0) {
+            hour = ~hour;
+        } else {
+            minute = in.readByte();
+            if (minute < 0) {
+                minute = ~minute;
+            } else {
+                second = in.readByte();
+                if (second < 0) {
+                    second = ~second;
+                } else {
+                    nano = in.readInt();
+                }
+            }
+        }
+        return LocalTime.of(hour, minute, second, nano);
+    }
+
+}
diff --git a/java/time/Month.java b/java/time/Month.java
new file mode 100644
index 0000000..57382cd
--- /dev/null
+++ b/java/time/Month.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoUnit.MONTHS;
+
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+
+/**
+ * A month-of-year, such as 'July'.
+ * <p>
+ * {@code Month} is an enum representing the 12 months of the year -
+ * January, February, March, April, May, June, July, August, September, October,
+ * November and December.
+ * <p>
+ * In addition to the textual enum name, each month-of-year has an {@code int} value.
+ * The {@code int} value follows normal usage and the ISO-8601 standard,
+ * from 1 (January) to 12 (December). It is recommended that applications use the enum
+ * rather than the {@code int} value to ensure code clarity.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code Month}.
+ * Use {@code getValue()} instead.</b>
+ * <p>
+ * This enum represents a common concept that is found in many calendar systems.
+ * As such, this enum may be used by any calendar system that has the month-of-year
+ * concept defined exactly equivalent to the ISO-8601 calendar system.
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum Month implements TemporalAccessor, TemporalAdjuster {
+
+    /**
+     * The singleton instance for the month of January with 31 days.
+     * This has the numeric value of {@code 1}.
+     */
+    JANUARY,
+    /**
+     * The singleton instance for the month of February with 28 days, or 29 in a leap year.
+     * This has the numeric value of {@code 2}.
+     */
+    FEBRUARY,
+    /**
+     * The singleton instance for the month of March with 31 days.
+     * This has the numeric value of {@code 3}.
+     */
+    MARCH,
+    /**
+     * The singleton instance for the month of April with 30 days.
+     * This has the numeric value of {@code 4}.
+     */
+    APRIL,
+    /**
+     * The singleton instance for the month of May with 31 days.
+     * This has the numeric value of {@code 5}.
+     */
+    MAY,
+    /**
+     * The singleton instance for the month of June with 30 days.
+     * This has the numeric value of {@code 6}.
+     */
+    JUNE,
+    /**
+     * The singleton instance for the month of July with 31 days.
+     * This has the numeric value of {@code 7}.
+     */
+    JULY,
+    /**
+     * The singleton instance for the month of August with 31 days.
+     * This has the numeric value of {@code 8}.
+     */
+    AUGUST,
+    /**
+     * The singleton instance for the month of September with 30 days.
+     * This has the numeric value of {@code 9}.
+     */
+    SEPTEMBER,
+    /**
+     * The singleton instance for the month of October with 31 days.
+     * This has the numeric value of {@code 10}.
+     */
+    OCTOBER,
+    /**
+     * The singleton instance for the month of November with 30 days.
+     * This has the numeric value of {@code 11}.
+     */
+    NOVEMBER,
+    /**
+     * The singleton instance for the month of December with 31 days.
+     * This has the numeric value of {@code 12}.
+     */
+    DECEMBER;
+    /**
+     * Private cache of all the constants.
+     */
+    private static final Month[] ENUMS = Month.values();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Month} from an {@code int} value.
+     * <p>
+     * {@code Month} is an enum representing the 12 months of the year.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     * The {@code int} value follows the ISO-8601 standard, from 1 (January) to 12 (December).
+     *
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @return the month-of-year, not null
+     * @throws DateTimeException if the month-of-year is invalid
+     */
+    public static Month of(int month) {
+        if (month < 1 || month > 12) {
+            throw new DateTimeException("Invalid value for MonthOfYear: " + month);
+        }
+        return ENUMS[month - 1];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Month} from a temporal object.
+     * <p>
+     * This obtains a month based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code Month}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} field.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code Month::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the month-of-year, not null
+     * @throws DateTimeException if unable to convert to a {@code Month}
+     */
+    public static Month from(TemporalAccessor temporal) {
+        if (temporal instanceof Month) {
+            return (Month) temporal;
+        }
+        try {
+            if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(MONTH_OF_YEAR));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain Month from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the month-of-year {@code int} value.
+     * <p>
+     * The values are numbered following the ISO-8601 standard,
+     * from 1 (January) to 12 (December).
+     *
+     * @return the month-of-year, from 1 (January) to 12 (December)
+     */
+    public int getValue() {
+        return ordinal() + 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation, such as 'Jan' or 'December'.
+     * <p>
+     * This returns the textual name used to identify the month-of-year,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+     *
+     * @param style  the length of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the month-of-year, not null
+     */
+    public String getDisplayName(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendText(MONTH_OF_YEAR, style).toFormatter(locale).format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this month-of-year can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then
+     * this method returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this month-of-year, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == MONTH_OF_YEAR;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This month is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+     * range of the month-of-year, from 1 to 12, will be returned.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return field.range();
+        }
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-of-year as an {@code int}.
+     * <p>
+     * This queries this month for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+     * value of the month-of-year, from 1 to 12, will be returned.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field, within the valid range of values
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public int get(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return getValue();
+        }
+        return TemporalAccessor.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-of-year as a {@code long}.
+     * <p>
+     * This queries this month for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} then the
+     * value of the month-of-year, from 1 to 12, will be returned.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the month-of-year that is the specified number of quarters after this one.
+     * <p>
+     * The calculation rolls around the end of the year from December to January.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, positive or negative
+     * @return the resulting month, not null
+     */
+    public Month plus(long months) {
+        int amount = (int) (months % 12);
+        return ENUMS[(ordinal() + (amount + 12)) % 12];
+    }
+
+    /**
+     * Returns the month-of-year that is the specified number of months before this one.
+     * <p>
+     * The calculation rolls around the start of the year from January to December.
+     * The specified period may be negative.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, positive or negative
+     * @return the resulting month, not null
+     */
+    public Month minus(long months) {
+        return plus(-(months % 12));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the length of this month in days.
+     * <p>
+     * This takes a flag to determine whether to return the length for a leap year or not.
+     * <p>
+     * February has 28 days in a standard year and 29 days in a leap year.
+     * April, June, September and November have 30 days.
+     * All other months have 31 days.
+     *
+     * @param leapYear  true if the length is required for a leap year
+     * @return the length of this month in days, from 28 to 31
+     */
+    public int length(boolean leapYear) {
+        switch (this) {
+            case FEBRUARY:
+                return (leapYear ? 29 : 28);
+            case APRIL:
+            case JUNE:
+            case SEPTEMBER:
+            case NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    /**
+     * Gets the minimum length of this month in days.
+     * <p>
+     * February has a minimum length of 28 days.
+     * April, June, September and November have 30 days.
+     * All other months have 31 days.
+     *
+     * @return the minimum length of this month in days, from 28 to 31
+     */
+    public int minLength() {
+        switch (this) {
+            case FEBRUARY:
+                return 28;
+            case APRIL:
+            case JUNE:
+            case SEPTEMBER:
+            case NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    /**
+     * Gets the maximum length of this month in days.
+     * <p>
+     * February has a maximum length of 29 days.
+     * April, June, September and November have 30 days.
+     * All other months have 31 days.
+     *
+     * @return the maximum length of this month in days, from 29 to 31
+     */
+    public int maxLength() {
+        switch (this) {
+            case FEBRUARY:
+                return 29;
+            case APRIL:
+            case JUNE:
+            case SEPTEMBER:
+            case NOVEMBER:
+                return 30;
+            default:
+                return 31;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the day-of-year corresponding to the first day of this month.
+     * <p>
+     * This returns the day-of-year that this month begins on, using the leap
+     * year flag to determine the length of February.
+     *
+     * @param leapYear  true if the length is required for a leap year
+     * @return the day of year corresponding to the first day of this month, from 1 to 336
+     */
+    public int firstDayOfYear(boolean leapYear) {
+        int leap = leapYear ? 1 : 0;
+        switch (this) {
+            case JANUARY:
+                return 1;
+            case FEBRUARY:
+                return 32;
+            case MARCH:
+                return 60 + leap;
+            case APRIL:
+                return 91 + leap;
+            case MAY:
+                return 121 + leap;
+            case JUNE:
+                return 152 + leap;
+            case JULY:
+                return 182 + leap;
+            case AUGUST:
+                return 213 + leap;
+            case SEPTEMBER:
+                return 244 + leap;
+            case OCTOBER:
+                return 274 + leap;
+            case NOVEMBER:
+                return 305 + leap;
+            case DECEMBER:
+            default:
+                return 335 + leap;
+        }
+    }
+
+    /**
+     * Gets the month corresponding to the first month of this quarter.
+     * <p>
+     * The year can be divided into four quarters.
+     * This method returns the first month of the quarter for the base month.
+     * January, February and March return January.
+     * April, May and June return April.
+     * July, August and September return July.
+     * October, November and December return October.
+     *
+     * @return the first month of the quarter corresponding to this month, not null
+     */
+    public Month firstMonthOfQuarter() {
+        return ENUMS[(ordinal() / 3) * 3];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this month-of-year using the specified query.
+     * <p>
+     * This queries this month-of-year using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.chronology()) {
+            return (R) IsoChronology.INSTANCE;
+        } else if (query == TemporalQueries.precision()) {
+            return (R) MONTHS;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this month-of-year.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the month-of-year changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#MONTH_OF_YEAR} as the field.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisMonth.adjustInto(temporal);
+     *   temporal = temporal.with(thisMonth);
+     * </pre>
+     * <p>
+     * For example, given a date in May, the following are output:
+     * <pre>
+     *   dateInMay.with(JANUARY);    // four months earlier
+     *   dateInMay.with(APRIL);      // one months earlier
+     *   dateInMay.with(MAY);        // same date
+     *   dateInMay.with(JUNE);       // one month later
+     *   dateInMay.with(DECEMBER);   // seven months later
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        return temporal.with(MONTH_OF_YEAR, getValue());
+    }
+
+}
diff --git a/java/time/MonthDay.java b/java/time/MonthDay.java
new file mode 100644
index 0000000..50bc2c8
--- /dev/null
+++ b/java/time/MonthDay.java
@@ -0,0 +1,786 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A month-day in the ISO-8601 calendar system, such as {@code --12-03}.
+ * <p>
+ * {@code MonthDay} is an immutable date-time object that represents the combination
+ * of a month and day-of-month. Any field that can be derived from a month and day,
+ * such as quarter-of-year, can be obtained.
+ * <p>
+ * This class does not store or represent a year, time or time-zone.
+ * For example, the value "December 3rd" can be stored in a {@code MonthDay}.
+ * <p>
+ * Since a {@code MonthDay} does not possess a year, the leap day of
+ * February 29th is considered valid.
+ * <p>
+ * This class implements {@link TemporalAccessor} rather than {@link Temporal}.
+ * This is because it is not possible to define whether February 29th is valid or not
+ * without external information, preventing the implementation of plus/minus.
+ * Related to this, {@code MonthDay} only provides access to query and set the fields
+ * {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH}.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class MonthDay
+        implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -939150713474957432L;
+    /**
+     * Parser.
+     */
+    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
+        .appendLiteral("--")
+        .appendValue(MONTH_OF_YEAR, 2)
+        .appendLiteral('-')
+        .appendValue(DAY_OF_MONTH, 2)
+        .toFormatter();
+
+    /**
+     * The month-of-year, not null.
+     */
+    private final int month;
+    /**
+     * The day-of-month.
+     */
+    private final int day;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current month-day from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current month-day.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current month-day using the system clock and default time-zone, not null
+     */
+    public static MonthDay now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current month-day from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current month-day.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current month-day using the system clock, not null
+     */
+    public static MonthDay now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current month-day from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current month-day.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current month-day, not null
+     */
+    public static MonthDay now(Clock clock) {
+        final LocalDate now = LocalDate.now(clock);  // called once
+        return MonthDay.of(now.getMonth(), now.getDayOfMonth());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MonthDay}.
+     * <p>
+     * The day-of-month must be valid for the month within a leap year.
+     * Hence, for February, day 29 is valid.
+     * <p>
+     * For example, passing in April and day 31 will throw an exception, as
+     * there can never be April 31st in any year. By contrast, passing in
+     * February 29th is permitted, as that month-day can sometimes be valid.
+     *
+     * @param month  the month-of-year to represent, not null
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the month-day, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month
+     */
+    public static MonthDay of(Month month, int dayOfMonth) {
+        Objects.requireNonNull(month, "month");
+        DAY_OF_MONTH.checkValidValue(dayOfMonth);
+        if (dayOfMonth > month.maxLength()) {
+            throw new DateTimeException("Illegal value for DayOfMonth field, value " + dayOfMonth +
+                    " is not valid for month " + month.name());
+        }
+        return new MonthDay(month.getValue(), dayOfMonth);
+    }
+
+    /**
+     * Obtains an instance of {@code MonthDay}.
+     * <p>
+     * The day-of-month must be valid for the month within a leap year.
+     * Hence, for month 2 (February), day 29 is valid.
+     * <p>
+     * For example, passing in month 4 (April) and day 31 will throw an exception, as
+     * there can never be April 31st in any year. By contrast, passing in
+     * February 29th is permitted, as that month-day can sometimes be valid.
+     *
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @return the month-day, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month
+     */
+    public static MonthDay of(int month, int dayOfMonth) {
+        return of(Month.of(month), dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MonthDay} from a temporal object.
+     * <p>
+     * This obtains a month-day based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code MonthDay}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
+     * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} fields.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code MonthDay::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the month-day, not null
+     * @throws DateTimeException if unable to convert to a {@code MonthDay}
+     */
+    public static MonthDay from(TemporalAccessor temporal) {
+        if (temporal instanceof MonthDay) {
+            return (MonthDay) temporal;
+        }
+        try {
+            if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MonthDay} from a text string such as {@code --12-03}.
+     * <p>
+     * The string must represent a valid month-day.
+     * The format is {@code --MM-dd}.
+     *
+     * @param text  the text to parse such as "--12-03", not null
+     * @return the parsed month-day, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static MonthDay parse(CharSequence text) {
+        return parse(text, PARSER);
+    }
+
+    /**
+     * Obtains an instance of {@code MonthDay} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a month-day.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed month-day, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static MonthDay parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, MonthDay::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor, previously validated.
+     *
+     * @param month  the month-of-year to represent, validated from 1 to 12
+     * @param dayOfMonth  the day-of-month to represent, validated from 1 to 29-31
+     */
+    private MonthDay(int month, int dayOfMonth) {
+        this.month = month;
+        this.day = dayOfMonth;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this month-day can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code YEAR}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this month-day, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == MONTH_OF_YEAR || field == DAY_OF_MONTH;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This month-day is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == MONTH_OF_YEAR) {
+            return field.range();
+        } else if (field == DAY_OF_MONTH) {
+            return ValueRange.of(1, getMonth().minLength(), getMonth().maxLength());
+        }
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-day as an {@code int}.
+     * <p>
+     * This queries this month-day for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this month-day.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this month-day as a {@code long}.
+     * <p>
+     * This queries this month-day for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this month-day.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                // alignedDOW and alignedWOM not supported because they cannot be set in with()
+                case DAY_OF_MONTH: return day;
+                case MONTH_OF_YEAR: return month;
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return month;
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return Month.of(month);
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return day;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is valid for this month-day.
+     * <p>
+     * This method checks whether this month and day and the input year form
+     * a valid date. This can only return false for February 29th.
+     *
+     * @param year  the year to validate
+     * @return true if the year is valid for this month-day
+     * @see Year#isValidMonthDay(MonthDay)
+     */
+    public boolean isValidYear(int year) {
+        return (day == 29 && month == 2 && Year.isLeap(year) == false) == false;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code MonthDay} with the month-of-year altered.
+     * <p>
+     * This returns a month-day with the specified month.
+     * If the day-of-month is invalid for the specified month, the day will
+     * be adjusted to the last valid day-of-month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the returned month-day, from 1 (January) to 12 (December)
+     * @return a {@code MonthDay} based on this month-day with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public MonthDay withMonth(int month) {
+        return with(Month.of(month));
+    }
+
+    /**
+     * Returns a copy of this {@code MonthDay} with the month-of-year altered.
+     * <p>
+     * This returns a month-day with the specified month.
+     * If the day-of-month is invalid for the specified month, the day will
+     * be adjusted to the last valid day-of-month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the returned month-day, not null
+     * @return a {@code MonthDay} based on this month-day with the requested month, not null
+     */
+    public MonthDay with(Month month) {
+        Objects.requireNonNull(month, "month");
+        if (month.getValue() == this.month) {
+            return this;
+        }
+        int day = Math.min(this.day, month.maxLength());
+        return new MonthDay(month.getValue(), day);
+    }
+
+    /**
+     * Returns a copy of this {@code MonthDay} with the day-of-month altered.
+     * <p>
+     * This returns a month-day with the specified day-of-month.
+     * If the day-of-month is invalid for the month, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the return month-day, from 1 to 31
+     * @return a {@code MonthDay} based on this month-day with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid,
+     *  or if the day-of-month is invalid for the month
+     */
+    public MonthDay withDayOfMonth(int dayOfMonth) {
+        if (dayOfMonth == this.day) {
+            return this;
+        }
+        return of(month, dayOfMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this month-day using the specified query.
+     * <p>
+     * This queries this month-day using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.chronology()) {
+            return (R) IsoChronology.INSTANCE;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this month-day.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the month and day-of-month changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#MONTH_OF_YEAR} and
+     * {@link ChronoField#DAY_OF_MONTH} as the fields.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisMonthDay.adjustInto(temporal);
+     *   temporal = temporal.with(thisMonthDay);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        temporal = temporal.with(MONTH_OF_YEAR, month);
+        return temporal.with(DAY_OF_MONTH, Math.min(temporal.range(DAY_OF_MONTH).getMaximum(), day));
+    }
+
+    /**
+     * Formats this month-day using the specified formatter.
+     * <p>
+     * This month-day will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted month-day string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this month-day with a year to create a {@code LocalDate}.
+     * <p>
+     * This returns a {@code LocalDate} formed from this month-day and the specified year.
+     * <p>
+     * A month-day of February 29th will be adjusted to February 28th in the resulting
+     * date if the year is not a leap year.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to use, from MIN_YEAR to MAX_YEAR
+     * @return the local date formed from this month-day and the specified year, not null
+     * @throws DateTimeException if the year is outside the valid range of years
+     */
+    public LocalDate atYear(int year) {
+        return LocalDate.of(year, month, isValidYear(year) ? day : 28);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this month-day to another month-day.
+     * <p>
+     * The comparison is based first on value of the month, then on the value of the day.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other month-day to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(MonthDay other) {
+        int cmp = (month - other.month);
+        if (cmp == 0) {
+            cmp = (day - other.day);
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this month-day is after the specified month-day.
+     *
+     * @param other  the other month-day to compare to, not null
+     * @return true if this is after the specified month-day
+     */
+    public boolean isAfter(MonthDay other) {
+        return compareTo(other) > 0;
+    }
+
+    /**
+     * Checks if this month-day is before the specified month-day.
+     *
+     * @param other  the other month-day to compare to, not null
+     * @return true if this point is before the specified month-day
+     */
+    public boolean isBefore(MonthDay other) {
+        return compareTo(other) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this month-day is equal to another month-day.
+     * <p>
+     * The comparison is based on the time-line position of the month-day within a year.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other month-day
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof MonthDay) {
+            MonthDay other = (MonthDay) obj;
+            return month == other.month && day == other.day;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this month-day.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return (month << 6) + day;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this month-day as a {@code String}, such as {@code --12-03}.
+     * <p>
+     * The output will be in the format {@code --MM-dd}:
+     *
+     * @return a string representation of this month-day, not null
+     */
+    @Override
+    public String toString() {
+        return new StringBuilder(10).append("--")
+            .append(month < 10 ? "0" : "").append(month)
+            .append(day < 10 ? "-0" : "-").append(day)
+            .toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(13);  // identifies a MonthDay
+     *  out.writeByte(month);
+     *  out.writeByte(day);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.MONTH_DAY_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(month);
+        out.writeByte(day);
+    }
+
+    static MonthDay readExternal(DataInput in) throws IOException {
+        byte month = in.readByte();
+        byte day = in.readByte();
+        return MonthDay.of(month, day);
+    }
+
+}
diff --git a/java/time/OffsetDateTime.java b/java/time/OffsetDateTime.java
new file mode 100644
index 0000000..c2c8e0a
--- /dev/null
+++ b/java/time/OffsetDateTime.java
@@ -0,0 +1,1947 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Comparator;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30+01:00}.
+ * <p>
+ * {@code OffsetDateTime} is an immutable representation of a date-time with an offset.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * as well as the offset from UTC/Greenwich. For example, the value
+ * "2nd October 2007 at 13:45.30.123456789 +02:00" can be stored in an {@code OffsetDateTime}.
+ * <p>
+ * {@code OffsetDateTime}, {@link java.time.ZonedDateTime} and {@link java.time.Instant} all store an instant
+ * on the time-line to nanosecond precision.
+ * {@code Instant} is the simplest, simply representing the instant.
+ * {@code OffsetDateTime} adds to the instant the offset from UTC/Greenwich, which allows
+ * the local date-time to be obtained.
+ * {@code ZonedDateTime} adds full time-zone rules.
+ * <p>
+ * It is intended that {@code ZonedDateTime} or {@code Instant} is used to model data
+ * in simpler applications. This class may be used when modeling date-time concepts in
+ * more detail, or when communicating to a database or in a network protocol.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class OffsetDateTime
+        implements Temporal, TemporalAdjuster, Comparable<OffsetDateTime>, Serializable {
+
+    /**
+     * The minimum supported {@code OffsetDateTime}, '-999999999-01-01T00:00:00+18:00'.
+     * This is the local date-time of midnight at the start of the minimum date
+     * in the maximum offset (larger offsets are earlier on the time-line).
+     * This combines {@link LocalDateTime#MIN} and {@link ZoneOffset#MAX}.
+     * This could be used by an application as a "far past" date-time.
+     */
+    public static final OffsetDateTime MIN = LocalDateTime.MIN.atOffset(ZoneOffset.MAX);
+    /**
+     * The maximum supported {@code OffsetDateTime}, '+999999999-12-31T23:59:59.999999999-18:00'.
+     * This is the local date-time just before midnight at the end of the maximum date
+     * in the minimum offset (larger negative offsets are later on the time-line).
+     * This combines {@link LocalDateTime#MAX} and {@link ZoneOffset#MIN}.
+     * This could be used by an application as a "far future" date-time.
+     */
+    public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN);
+
+    /**
+     * Gets a comparator that compares two {@code OffsetDateTime} instances
+     * based solely on the instant.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying instant.
+     *
+     * @return a comparator that compares in time-line order
+     *
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    public static Comparator<OffsetDateTime> timeLineOrder() {
+        return OffsetDateTime::compareInstant;
+    }
+
+    /**
+     * Compares this {@code OffsetDateTime} to another date-time.
+     * The comparison is based on the instant.
+     *
+     * @param datetime1  the first date-time to compare, not null
+     * @param datetime2  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    private static int compareInstant(OffsetDateTime datetime1, OffsetDateTime datetime2) {
+        if (datetime1.getOffset().equals(datetime2.getOffset())) {
+            return datetime1.toLocalDateTime().compareTo(datetime2.toLocalDateTime());
+        }
+        int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
+        if (cmp == 0) {
+            cmp = datetime1.toLocalTime().getNano() - datetime2.toLocalTime().getNano();
+        }
+        return cmp;
+    }
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2287754244819255394L;
+
+    /**
+     * The local date-time.
+     */
+    private final LocalDateTime dateTime;
+    /**
+     * The offset from UTC/Greenwich.
+     */
+    private final ZoneOffset offset;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date-time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date-time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date-time using the system clock, not null
+     */
+    public static OffsetDateTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date-time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * The offset will be calculated from the specified time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date-time using the system clock, not null
+     */
+    public static OffsetDateTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date-time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date-time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date-time, not null
+     */
+    public static OffsetDateTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        return ofInstant(now, clock.getZone().getRules().getOffset(now));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a date, time and offset.
+     * <p>
+     * This creates an offset date-time with the specified local date, time and offset.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @param offset  the zone offset, not null
+     * @return the offset date-time, not null
+     */
+    public static OffsetDateTime of(LocalDate date, LocalTime time, ZoneOffset offset) {
+        LocalDateTime dt = LocalDateTime.of(date, time);
+        return new OffsetDateTime(dt, offset);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a date-time and offset.
+     * <p>
+     * This creates an offset date-time with the specified local date-time and offset.
+     *
+     * @param dateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @return the offset date-time, not null
+     */
+    public static OffsetDateTime of(LocalDateTime dateTime, ZoneOffset offset) {
+        return new OffsetDateTime(dateTime, offset);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a year, month, day,
+     * hour, minute, second, nanosecond and offset.
+     * <p>
+     * This creates an offset date-time with the seven specified fields.
+     * <p>
+     * This method exists primarily for writing test cases.
+     * Non test-code will typically use other methods to create an offset time.
+     * {@code LocalDateTime} has five additional convenience variants of the
+     * equivalent factory method taking fewer arguments.
+     * They are not provided here to reduce the footprint of the API.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @param offset  the zone offset, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if the value of any field is out of range, or
+     *  if the day-of-month is invalid for the month-year
+     */
+    public static OffsetDateTime of(
+            int year, int month, int dayOfMonth,
+            int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) {
+        LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
+        return new OffsetDateTime(dt, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from an {@code Instant} and zone ID.
+     * <p>
+     * This creates an offset date-time with the same instant as that specified.
+     * Finding the offset from UTC/Greenwich is simple as there is only one valid
+     * offset for each instant.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, which may be an offset, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static OffsetDateTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+        return new OffsetDateTime(ldt, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a temporal object.
+     * <p>
+     * This obtains an offset date-time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code OffsetDateTime}.
+     * <p>
+     * The conversion will first obtain a {@code ZoneOffset} from the temporal object.
+     * It will then try to obtain a {@code LocalDateTime}, falling back to an {@code Instant} if necessary.
+     * The result will be the combination of {@code ZoneOffset} with either
+     * with {@code LocalDateTime} or {@code Instant}.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code OffsetDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if unable to convert to an {@code OffsetDateTime}
+     */
+    public static OffsetDateTime from(TemporalAccessor temporal) {
+        if (temporal instanceof OffsetDateTime) {
+            return (OffsetDateTime) temporal;
+        }
+        try {
+            ZoneOffset offset = ZoneOffset.from(temporal);
+            LocalDate date = temporal.query(TemporalQueries.localDate());
+            LocalTime time = temporal.query(TemporalQueries.localTime());
+            if (date != null && time != null) {
+                return OffsetDateTime.of(date, time, offset);
+            } else {
+                Instant instant = Instant.from(temporal);
+                return OffsetDateTime.ofInstant(instant, offset);
+            }
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a text string
+     * such as {@code 2007-12-03T10:15:30+01:00}.
+     * <p>
+     * The string must represent a valid date-time and is parsed using
+     * {@link java.time.format.DateTimeFormatter#ISO_OFFSET_DATE_TIME}.
+     *
+     * @param text  the text to parse such as "2007-12-03T10:15:30+01:00", not null
+     * @return the parsed offset date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetDateTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetDateTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date-time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed offset date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, OffsetDateTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param dateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     */
+    private OffsetDateTime(LocalDateTime dateTime, ZoneOffset offset) {
+        this.dateTime = Objects.requireNonNull(dateTime, "dateTime");
+        this.offset = Objects.requireNonNull(offset, "offset");
+    }
+
+    /**
+     * Returns a new date-time based on this one, returning {@code this} where possible.
+     *
+     * @param dateTime  the date-time to create with, not null
+     * @param offset  the zone offset to create with, not null
+     */
+    private OffsetDateTime with(LocalDateTime dateTime, ZoneOffset offset) {
+        if (this.dateTime == dateTime && this.offset.equals(offset)) {
+            return this;
+        }
+        return new OffsetDateTime(dateTime, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code PROLEPTIC_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * <li>{@code INSTANT_SECONDS}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date-time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code NANOS}
+     * <li>{@code MICROS}
+     * <li>{@code MILLIS}
+     * <li>{@code SECONDS}
+     * <li>{@code MINUTES}
+     * <li>{@code HOURS}
+     * <li>{@code HALF_DAYS}
+     * <li>{@code DAYS}
+     * <li>{@code WEEKS}
+     * <li>{@code MONTHS}
+     * <li>{@code YEARS}
+     * <li>{@code DECADES}
+     * <li>{@code CENTURIES}
+     * <li>{@code MILLENNIA}
+     * <li>{@code ERAS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit != FOREVER;
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date-time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return dateTime.range(field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as an {@code int}.
+     * <p>
+     * This queries this date-time for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+     * {@code EPOCH_DAY}, {@code PROLEPTIC_MONTH} and {@code INSTANT_SECONDS} which are too
+     * large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS:
+                    throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
+                case OFFSET_SECONDS:
+                    return getOffset().getTotalSeconds();
+            }
+            return dateTime.get(field);
+        }
+        return Temporal.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as a {@code long}.
+     * <p>
+     * This queries this date-time for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: return toEpochSecond();
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return dateTime.getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local date-time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring
+     * that the result has the same local date-time.
+     * <p>
+     * This method returns an object with the same {@code LocalDateTime} and the specified {@code ZoneOffset}.
+     * No calculation is needed or performed.
+     * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 2007-12-03T10:30+03:00}.
+     * <p>
+     * To take into account the difference between the offsets, and adjust the time fields,
+     * use {@link #withOffsetSameInstant}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null
+     */
+    public OffsetDateTime withOffsetSameLocal(ZoneOffset offset) {
+        return with(dateTime, offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified offset ensuring
+     * that the result is at the same instant.
+     * <p>
+     * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalDateTime}
+     * adjusted by the difference between the two offsets.
+     * This will result in the old and new objects representing the same instant.
+     * This is useful for finding the local time in a different offset.
+     * For example, if this time represents {@code 2007-12-03T10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 2007-12-03T11:30+03:00}.
+     * <p>
+     * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the requested offset, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime withOffsetSameInstant(ZoneOffset offset) {
+        if (offset.equals(this.offset)) {
+            return this;
+        }
+        int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds();
+        LocalDateTime adjusted = dateTime.plusSeconds(difference);
+        return new OffsetDateTime(adjusted, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDateTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDateTime} with the same year, month, day and time
+     * as this date-time.
+     *
+     * @return the local date-time part of this date-time, not null
+     */
+    public LocalDateTime toLocalDateTime() {
+        return dateTime;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDate} with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    public LocalDate toLocalDate() {
+        return dateTime.toLocalDate();
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return dateTime.getYear();
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return dateTime.getMonthValue();
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return dateTime.getMonth();
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return dateTime.getDayOfMonth();
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year, from 1 to 365, or 366 in a leap year
+     */
+    public int getDayOfYear() {
+        return dateTime.getDayOfYear();
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * This method returns the enum {@link DayOfWeek} for the day-of-week.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link DayOfWeek#getValue() int value}.
+     * <p>
+     * Additional information can be obtained from the {@code DayOfWeek}.
+     * This includes textual names of the values.
+     *
+     * @return the day-of-week, not null
+     */
+    public DayOfWeek getDayOfWeek() {
+        return dateTime.getDayOfWeek();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    public LocalTime toLocalTime() {
+        return dateTime.toLocalTime();
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return dateTime.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return dateTime.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return dateTime.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return dateTime.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date-time.
+     * <p>
+     * This returns an {@code OffsetDateTime}, based on this one, with the date-time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the date to the last day of the month.
+     * A selection of common adjustments is provided in
+     * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.
+     * These include finding the "last day of the month" and "next Wednesday".
+     * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+     * such as {@link Month} and {@link java.time.MonthDay MonthDay}.
+     * The adjuster is responsible for handling special cases, such as the varying
+     * lengths of month and leap years.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.TemporalAdjusters.*;
+     *
+     *  result = offsetDateTime.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate}, {@link LocalTime} and {@link ZoneOffset} implement
+     * {@code TemporalAdjuster}, thus this method can be used to change the date, time or offset:
+     * <pre>
+     *  result = offsetDateTime.with(date);
+     *  result = offsetDateTime.with(time);
+     *  result = offsetDateTime.with(offset);
+     * </pre>
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return an {@code OffsetDateTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate || adjuster instanceof LocalTime || adjuster instanceof LocalDateTime) {
+            return with(dateTime.with(adjuster), offset);
+        } else if (adjuster instanceof Instant) {
+            return ofInstant((Instant) adjuster, offset);
+        } else if (adjuster instanceof ZoneOffset) {
+            return with(dateTime, (ZoneOffset) adjuster);
+        } else if (adjuster instanceof OffsetDateTime) {
+            return (OffsetDateTime) adjuster;
+        }
+        return (OffsetDateTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified field set to a new value.
+     * <p>
+     * This returns an {@code OffsetDateTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year, month or day-of-month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.
+     * The offset and nano-of-second are unchanged.
+     * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The {@code OFFSET_SECONDS} field will return a date-time with the specified offset.
+     * The local date-time is unaltered. If the new offset value is outside the valid range
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
+     * In this case, the offset is not part of the calculation and will be unchanged.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an {@code OffsetDateTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            switch (f) {
+                case INSTANT_SECONDS: return ofInstant(Instant.ofEpochSecond(newValue, getNano()), offset);
+                case OFFSET_SECONDS: {
+                    return with(dateTime, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
+                }
+            }
+            return with(dateTime.with(field, newValue), offset);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the year altered.
+     * <p>
+     * The time and offset do not affect the calculation and will be the same in the result.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
+     * @return an {@code OffsetDateTime} based on this date-time with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public OffsetDateTime withYear(int year) {
+        return with(dateTime.withYear(year), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the month-of-year altered.
+     * <p>
+     * The time and offset do not affect the calculation and will be the same in the result.
+     * If the day-of-month is invalid for the year, it will be changed to the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
+     * @return an {@code OffsetDateTime} based on this date-time with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public OffsetDateTime withMonth(int month) {
+        return with(dateTime.withMonth(month), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the day-of-month altered.
+     * <p>
+     * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown.
+     * The time and offset do not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
+     * @return an {@code OffsetDateTime} based on this date-time with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public OffsetDateTime withDayOfMonth(int dayOfMonth) {
+        return with(dateTime.withDayOfMonth(dayOfMonth), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the day-of-year altered.
+     * <p>
+     * The time and offset do not affect the calculation and will be the same in the result.
+     * If the resulting {@code OffsetDateTime} is invalid, an exception is thrown.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
+     * @return an {@code OffsetDateTime} based on this date with the requested day, not null
+     * @throws DateTimeException if the day-of-year value is invalid,
+     *  or if the day-of-year is invalid for the year
+     */
+    public OffsetDateTime withDayOfYear(int dayOfYear) {
+        return with(dateTime.withDayOfYear(dayOfYear), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the hour-of-day altered.
+     * <p>
+     * The date and offset do not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return an {@code OffsetDateTime} based on this date-time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public OffsetDateTime withHour(int hour) {
+        return with(dateTime.withHour(hour), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the minute-of-hour altered.
+     * <p>
+     * The date and offset do not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return an {@code OffsetDateTime} based on this date-time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public OffsetDateTime withMinute(int minute) {
+        return with(dateTime.withMinute(minute), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the second-of-minute altered.
+     * <p>
+     * The date and offset do not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return an {@code OffsetDateTime} based on this date-time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public OffsetDateTime withSecond(int second) {
+        return with(dateTime.withSecond(second), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the nano-of-second altered.
+     * <p>
+     * The date and offset do not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return an {@code OffsetDateTime} based on this date-time with the requested nanosecond, not null
+     * @throws DateTimeException if the nano value is invalid
+     */
+    public OffsetDateTime withNano(int nanoOfSecond) {
+        return with(dateTime.withNano(nanoOfSecond), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original date-time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
+     * that divides into the length of a standard day without remainder.
+     * This includes all supplied time units on {@link ChronoUnit} and
+     * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    public OffsetDateTime truncatedTo(TemporalUnit unit) {
+        return with(dateTime.truncatedTo(unit), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified amount added.
+     * <p>
+     * This returns an {@code OffsetDateTime}, based on this one, with the specified amount added.
+     * The amount is typically {@link Period} or {@link Duration} but may be
+     * any other type implementing the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime plus(TemporalAmount amountToAdd) {
+        return (OffsetDateTime) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified amount added.
+     * <p>
+     * This returns an {@code OffsetDateTime}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented by
+     * {@link LocalDateTime#plus(long, TemporalUnit)}.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return with(dateTime.plus(amountToAdd, unit), offset);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of years added.
+     * <p>
+     * This method adds the specified amount to the years field in three steps:
+     * <ol>
+     * <li>Add the input years to the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) plus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusYears(long years) {
+        return with(dateTime.plusYears(years), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of months added.
+     * <p>
+     * This method adds the specified amount to the months field in three steps:
+     * <ol>
+     * <li>Add the input months to the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 plus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusMonths(long months) {
+        return with(dateTime.plusMonths(months), offset);
+    }
+
+    /**
+     * Returns a copy of this OffsetDateTime with the specified number of weeks added.
+     * <p>
+     * This method adds the specified amount in weeks to the days field incrementing
+     * the month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 plus one week would result in 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusWeeks(long weeks) {
+        return with(dateTime.plusWeeks(weeks), offset);
+    }
+
+    /**
+     * Returns a copy of this OffsetDateTime with the specified number of days added.
+     * <p>
+     * This method adds the specified amount to the days field incrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 plus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusDays(long days) {
+        return with(dateTime.plusDays(days), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of hours added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the hours added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusHours(long hours) {
+        return with(dateTime.plusHours(hours), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of minutes added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the minutes added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusMinutes(long minutes) {
+        return with(dateTime.plusMinutes(minutes), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of seconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime plusSeconds(long seconds) {
+        return with(dateTime.plusSeconds(seconds), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of nanoseconds added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds added, not null
+     * @throws DateTimeException if the unit cannot be added to this type
+     */
+    public OffsetDateTime plusNanos(long nanos) {
+        return with(dateTime.plusNanos(nanos), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified amount subtracted.
+     * <p>
+     * This returns an {@code OffsetDateTime}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Period} or {@link Duration} but may be
+     * any other type implementing the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime minus(TemporalAmount amountToSubtract) {
+        return (OffsetDateTime) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified amount subtracted.
+     * <p>
+     * This returns an {@code OffsetDateTime}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return an {@code OffsetDateTime} based on this date-time with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetDateTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of years subtracted.
+     * <p>
+     * This method subtracts the specified amount from the years field in three steps:
+     * <ol>
+     * <li>Subtract the input years from the year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2008-02-29 (leap year) minus one year would result in the
+     * invalid date 2009-02-29 (standard year). Instead of returning an invalid
+     * result, the last valid day of the month, 2009-02-28, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusYears(long years) {
+        return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of months subtracted.
+     * <p>
+     * This method subtracts the specified amount from the months field in three steps:
+     * <ol>
+     * <li>Subtract the input months from the month-of-year field</li>
+     * <li>Check if the resulting date would be invalid</li>
+     * <li>Adjust the day-of-month to the last valid day if necessary</li>
+     * </ol>
+     * <p>
+     * For example, 2007-03-31 minus one month would result in the invalid date
+     * 2007-04-31. Instead of returning an invalid result, the last valid day
+     * of the month, 2007-04-30, is selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusMonths(long months) {
+        return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of weeks subtracted.
+     * <p>
+     * This method subtracts the specified amount in weeks from the days field decrementing
+     * the month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 minus one week would result in 2009-01-07.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusWeeks(long weeks) {
+        return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of days subtracted.
+     * <p>
+     * This method subtracts the specified amount from the days field decrementing the
+     * month and year fields as necessary to ensure the result remains valid.
+     * The result is only invalid if the maximum/minimum year is exceeded.
+     * <p>
+     * For example, 2008-12-31 minus one day would result in 2009-01-01.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusDays(long days) {
+        return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of hours subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the hours subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusHours(long hours) {
+        return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of minutes subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the minutes subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusMinutes(long minutes) {
+        return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of seconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusSeconds(long seconds) {
+        return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetDateTime} with the specified number of nanoseconds subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return an {@code OffsetDateTime} based on this date-time with the nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public OffsetDateTime minusNanos(long nanos) {
+        return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) {
+            return (R) getOffset();
+        } else if (query == TemporalQueries.zoneId()) {
+            return null;
+        } else if (query == TemporalQueries.localDate()) {
+            return (R) toLocalDate();
+        } else if (query == TemporalQueries.localTime()) {
+            return (R) toLocalTime();
+        } else if (query == TemporalQueries.chronology()) {
+            return (R) IsoChronology.INSTANCE;
+        } else if (query == TemporalQueries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same offset, date
+     * and time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the offset, date and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * three times, passing {@link ChronoField#EPOCH_DAY},
+     * {@link ChronoField#NANO_OF_DAY} and {@link ChronoField#OFFSET_SECONDS} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffsetDateTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffsetDateTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        // OffsetDateTime is treated as three separate fields, not an instant
+        // this produces the most consistent set of results overall
+        // the offset is set after the date and time, as it is typically a small
+        // tweak to the result, with ZonedDateTime frequently ignoring the offset
+        return temporal
+                .with(EPOCH_DAY, toLocalDate().toEpochDay())
+                .with(NANO_OF_DAY, toLocalTime().toNanoOfDay())
+                .with(OFFSET_SECONDS, getOffset().getTotalSeconds());
+    }
+
+    /**
+     * Calculates the amount of time until another date-time in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code OffsetDateTime}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified date-time.
+     * The result will be negative if the end is before the start.
+     * For example, the amount in days between two date-times can be calculated
+     * using {@code startDateTime.until(endDateTime, DAYS)}.
+     * <p>
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code OffsetDateTime} using {@link #from(TemporalAccessor)}.
+     * If the offset differs between the two date-times, the specified
+     * end date-time is normalized to have the same offset as this date-time.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two date-times.
+     * For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
+     * will only be one month as it is one minute short of two months.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MONTHS);
+     *   amount = MONTHS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+     * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to an {@code OffsetDateTime}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this date-time and the end date-time
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to an {@code OffsetDateTime}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        OffsetDateTime end = OffsetDateTime.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            end = end.withOffsetSameInstant(offset);
+            return dateTime.until(end.dateTime, unit);
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this date-time using the specified formatter.
+     * <p>
+     * This date-time will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this date-time with a time-zone to create a {@code ZonedDateTime}
+     * ensuring that the result has the same instant.
+     * <p>
+     * This returns a {@code ZonedDateTime} formed from this date-time and the specified time-zone.
+     * This conversion will ignore the visible local date-time and use the underlying instant instead.
+     * This avoids any problems with local time-line gaps or overlaps.
+     * The result might have different values for fields such as hour, minute an even day.
+     * <p>
+     * To attempt to retain the values of the fields, use {@link #atZoneSimilarLocal(ZoneId)}.
+     * To use the offset as the zone ID, use {@link #toZonedDateTime()}.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date-time, not null
+     */
+    public ZonedDateTime atZoneSameInstant(ZoneId zone) {
+        return ZonedDateTime.ofInstant(dateTime, offset, zone);
+    }
+
+    /**
+     * Combines this date-time with a time-zone to create a {@code ZonedDateTime}
+     * trying to keep the same local date and time.
+     * <p>
+     * This returns a {@code ZonedDateTime} formed from this date-time and the specified time-zone.
+     * Where possible, the result will have the same local date-time as this object.
+     * <p>
+     * Time-zone rules, such as daylight savings, mean that not every time on the
+     * local time-line exists. If the local date-time is in a gap or overlap according to
+     * the rules then a resolver is used to determine the resultant local time and offset.
+     * This method uses {@link ZonedDateTime#ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+     * to retain the offset from this instance if possible.
+     * <p>
+     * Finer control over gaps and overlaps is available in two ways.
+     * If you simply want to use the later offset at overlaps then call
+     * {@link ZonedDateTime#withLaterOffsetAtOverlap()} immediately after this method.
+     * <p>
+     * To create a zoned date-time at the same instant irrespective of the local time-line,
+     * use {@link #atZoneSameInstant(ZoneId)}.
+     * To use the offset as the zone ID, use {@link #toZonedDateTime()}.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date and the earliest valid time for the zone, not null
+     */
+    public ZonedDateTime atZoneSimilarLocal(ZoneId zone) {
+        return ZonedDateTime.ofLocal(dateTime, zone, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code OffsetTime}.
+     * <p>
+     * This returns an offset time with the same local time and offset.
+     *
+     * @return an OffsetTime representing the time and offset, not null
+     */
+    public OffsetTime toOffsetTime() {
+        return OffsetTime.of(dateTime.toLocalTime(), offset);
+    }
+
+    /**
+     * Converts this date-time to a {@code ZonedDateTime} using the offset as the zone ID.
+     * <p>
+     * This creates the simplest possible {@code ZonedDateTime} using the offset
+     * as the zone ID.
+     * <p>
+     * To control the time-zone used, see {@link #atZoneSameInstant(ZoneId)} and
+     * {@link #atZoneSimilarLocal(ZoneId)}.
+     *
+     * @return a zoned date-time representing the same local date-time and offset, not null
+     */
+    public ZonedDateTime toZonedDateTime() {
+        return ZonedDateTime.of(dateTime, offset);
+    }
+
+    /**
+     * Converts this date-time to an {@code Instant}.
+     * <p>
+     * This returns an {@code Instant} representing the same point on the
+     * time-line as this date-time.
+     *
+     * @return an {@code Instant} representing the same instant, not null
+     */
+    public Instant toInstant() {
+        return dateTime.toInstant(offset);
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z.
+     * <p>
+     * This allows this date-time to be converted to a value of the
+     * {@link ChronoField#INSTANT_SECONDS epoch-seconds} field. This is primarily
+     * intended for low-level conversions rather than general application usage.
+     *
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    public long toEpochSecond() {
+        return dateTime.toEpochSecond(offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time.
+     * <p>
+     * The comparison is based on the instant then on the local date-time.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 2008-12-03T10:30+01:00}</li>
+     * <li>{@code 2008-12-03T11:00+01:00}</li>
+     * <li>{@code 2008-12-03T12:00+02:00}</li>
+     * <li>{@code 2008-12-03T11:30+01:00}</li>
+     * <li>{@code 2008-12-03T12:00+01:00}</li>
+     * <li>{@code 2008-12-03T12:30+01:00}</li>
+     * </ol>
+     * Values #2 and #3 represent the same instant on the time-line.
+     * When two values represent the same instant, the local date-time is compared
+     * to distinguish them. This step is needed to make the ordering
+     * consistent with {@code equals()}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(OffsetDateTime other) {
+        int cmp = compareInstant(this, other);
+        if (cmp == 0) {
+            cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
+        }
+        return cmp;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the instant of this date-time is after that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is after the instant of the specified date-time
+     */
+    public boolean isAfter(OffsetDateTime other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec > otherEpochSec ||
+            (thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is before that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is before the instant of the specified date-time
+     */
+    public boolean isBefore(OffsetDateTime other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec < otherEpochSec ||
+            (thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is equal to that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
+     * in that it only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if the instant equals the instant of the specified date-time
+     */
+    public boolean isEqual(OffsetDateTime other) {
+        return toEpochSecond() == other.toEpochSecond() &&
+                toLocalTime().getNano() == other.toLocalTime().getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * The comparison is based on the local date-time and the offset.
+     * To compare for the same instant on the time-line, use {@link #isEqual}.
+     * Only objects of type {@code OffsetDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof OffsetDateTime) {
+            OffsetDateTime other = (OffsetDateTime) obj;
+            return dateTime.equals(other.dateTime) && offset.equals(other.offset);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return dateTime.hashCode() ^ offset.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30+01:00}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <ul>
+     * <li>{@code uuuu-MM-dd'T'HH:mmXXXXX}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ssXXXXX}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSXXXXX}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li>
+     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li>
+     * </ul>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    public String toString() {
+        return dateTime.toString() + offset.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(10);  // identifies an OffsetDateTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalDateTime">datetime</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.OFFSET_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        dateTime.writeExternal(out);
+        offset.writeExternal(out);
+    }
+
+    static OffsetDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        LocalDateTime dateTime = LocalDateTime.readExternal(in);
+        ZoneOffset offset = ZoneOffset.readExternal(in);
+        return OffsetDateTime.of(dateTime, offset);
+    }
+
+}
diff --git a/java/time/OffsetTime.java b/java/time/OffsetTime.java
new file mode 100644
index 0000000..c54b926
--- /dev/null
+++ b/java/time/OffsetTime.java
@@ -0,0 +1,1411 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.NANOS_PER_HOUR;
+import static java.time.LocalTime.NANOS_PER_MINUTE;
+import static java.time.LocalTime.NANOS_PER_SECOND;
+import static java.time.LocalTime.SECONDS_PER_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A time with an offset from UTC/Greenwich in the ISO-8601 calendar system,
+ * such as {@code 10:15:30+01:00}.
+ * <p>
+ * {@code OffsetTime} is an immutable date-time object that represents a time, often
+ * viewed as hour-minute-second-offset.
+ * This class stores all time fields, to a precision of nanoseconds,
+ * as well as a zone offset.
+ * For example, the value "13:45.30.123456789+02:00" can be stored
+ * in an {@code OffsetTime}.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class OffsetTime
+        implements Temporal, TemporalAdjuster, Comparable<OffsetTime>, Serializable {
+
+    /**
+     * The minimum supported {@code OffsetTime}, '00:00:00+18:00'.
+     * This is the time of midnight at the start of the day in the maximum offset
+     * (larger offsets are earlier on the time-line).
+     * This combines {@link LocalTime#MIN} and {@link ZoneOffset#MAX}.
+     * This could be used by an application as a "far past" date.
+     */
+    public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX);
+    /**
+     * The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'.
+     * This is the time just before midnight at the end of the day in the minimum offset
+     * (larger negative offsets are later on the time-line).
+     * This combines {@link LocalTime#MAX} and {@link ZoneOffset#MIN}.
+     * This could be used by an application as a "far future" date.
+     */
+    public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN);
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 7264499704384272492L;
+
+    /**
+     * The local date-time.
+     */
+    private final LocalTime time;
+    /**
+     * The offset from UTC/Greenwich.
+     */
+    private final ZoneOffset offset;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current time using the system clock and default time-zone, not null
+     */
+    public static OffsetTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * The offset will be calculated from the specified time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current time using the system clock, not null
+     */
+    public static OffsetTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current time.
+     * The offset will be calculated from the time-zone in the clock.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current time, not null
+     */
+    public static OffsetTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        return ofInstant(now, clock.getZone().getRules().getOffset(now));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from a local time and an offset.
+     *
+     * @param time  the local time, not null
+     * @param offset  the zone offset, not null
+     * @return the offset time, not null
+     */
+    public static OffsetTime of(LocalTime time, ZoneOffset offset) {
+        return new OffsetTime(time, offset);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetTime} from an hour, minute, second and nanosecond.
+     * <p>
+     * This creates an offset time with the four specified fields.
+     * <p>
+     * This method exists primarily for writing test cases.
+     * Non test-code will typically use other methods to create an offset time.
+     * {@code LocalTime} has two additional convenience variants of the
+     * equivalent factory method taking fewer arguments.
+     * They are not provided here to reduce the footprint of the API.
+     *
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @param offset  the zone offset, not null
+     * @return the offset time, not null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    public static OffsetTime of(int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset) {
+        return new OffsetTime(LocalTime.of(hour, minute, second, nanoOfSecond), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from an {@code Instant} and zone ID.
+     * <p>
+     * This creates an offset time with the same instant as that specified.
+     * Finding the offset from UTC/Greenwich is simple as there is only one valid
+     * offset for each instant.
+     * <p>
+     * The date component of the instant is dropped during the conversion.
+     * This means that the conversion can never fail due to the instant being
+     * out of the valid range of dates.
+     *
+     * @param instant  the instant to create the time from, not null
+     * @param zone  the time-zone, which may be an offset, not null
+     * @return the offset time, not null
+     */
+    public static OffsetTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();  // overflow caught later
+        int secsOfDay = (int) Math.floorMod(localSecond, SECONDS_PER_DAY);
+        LocalTime time = LocalTime.ofNanoOfDay(secsOfDay * NANOS_PER_SECOND + instant.getNano());
+        return new OffsetTime(time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from a temporal object.
+     * <p>
+     * This obtains an offset time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code OffsetTime}.
+     * <p>
+     * The conversion extracts and combines the {@code ZoneOffset} and the
+     * {@code LocalTime} from the temporal object.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code OffsetTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the offset time, not null
+     * @throws DateTimeException if unable to convert to an {@code OffsetTime}
+     */
+    public static OffsetTime from(TemporalAccessor temporal) {
+        if (temporal instanceof OffsetTime) {
+            return (OffsetTime) temporal;
+        }
+        try {
+            LocalTime time = LocalTime.from(temporal);
+            ZoneOffset offset = ZoneOffset.from(temporal);
+            return new OffsetTime(time, offset);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code OffsetTime} from a text string such as {@code 10:15:30+01:00}.
+     * <p>
+     * The string must represent a valid time and is parsed using
+     * {@link java.time.format.DateTimeFormatter#ISO_OFFSET_TIME}.
+     *
+     * @param text  the text to parse such as "10:15:30+01:00", not null
+     * @return the parsed local time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatter.ISO_OFFSET_TIME);
+    }
+
+    /**
+     * Obtains an instance of {@code OffsetTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed offset time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static OffsetTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, OffsetTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param time  the local time, not null
+     * @param offset  the zone offset, not null
+     */
+    private OffsetTime(LocalTime time, ZoneOffset offset) {
+        this.time = Objects.requireNonNull(time, "time");
+        this.offset = Objects.requireNonNull(offset, "offset");
+    }
+
+    /**
+     * Returns a new time based on this one, returning {@code this} where possible.
+     *
+     * @param time  the time to create with, not null
+     * @param offset  the zone offset to create with, not null
+     */
+    private OffsetTime with(LocalTime time, ZoneOffset offset) {
+        if (this.time == time && this.offset.equals(offset)) {
+            return this;
+        }
+        return new OffsetTime(time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field.isTimeBased() || field == OFFSET_SECONDS;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this offset-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code NANOS}
+     * <li>{@code MICROS}
+     * <li>{@code MILLIS}
+     * <li>{@code SECONDS}
+     * <li>{@code MINUTES}
+     * <li>{@code HOURS}
+     * <li>{@code HALF_DAYS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit.isTimeBased();
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return time.range(field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as an {@code int}.
+     * <p>
+     * This queries this time for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time, except {@code NANO_OF_DAY} and {@code MICRO_OF_DAY}
+     * which are too large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return Temporal.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this time as a {@code long}.
+     * <p>
+     * This queries this time for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this time.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == OFFSET_SECONDS) {
+                return offset.getTotalSeconds();
+            }
+            return time.getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified offset ensuring
+     * that the result has the same local time.
+     * <p>
+     * This method returns an object with the same {@code LocalTime} and the specified {@code ZoneOffset}.
+     * No calculation is needed or performed.
+     * For example, if this time represents {@code 10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 10:30+03:00}.
+     * <p>
+     * To take into account the difference between the offsets, and adjust the time fields,
+     * use {@link #withOffsetSameInstant}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetTime} based on this time with the requested offset, not null
+     */
+    public OffsetTime withOffsetSameLocal(ZoneOffset offset) {
+        return offset != null && offset.equals(this.offset) ? this : new OffsetTime(time, offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified offset ensuring
+     * that the result is at the same instant on an implied day.
+     * <p>
+     * This method returns an object with the specified {@code ZoneOffset} and a {@code LocalTime}
+     * adjusted by the difference between the two offsets.
+     * This will result in the old and new objects representing the same instant on an implied day.
+     * This is useful for finding the local time in a different offset.
+     * For example, if this time represents {@code 10:30+02:00} and the offset specified is
+     * {@code +03:00}, then this method will return {@code 11:30+03:00}.
+     * <p>
+     * To change the offset without adjusting the local time use {@link #withOffsetSameLocal}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param offset  the zone offset to change to, not null
+     * @return an {@code OffsetTime} based on this time with the requested offset, not null
+     */
+    public OffsetTime withOffsetSameInstant(ZoneOffset offset) {
+        if (offset.equals(this.offset)) {
+            return this;
+        }
+        int difference = offset.getTotalSeconds() - this.offset.getTotalSeconds();
+        LocalTime adjusted = time.plusSeconds(difference);
+        return new OffsetTime(adjusted, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    public LocalTime toLocalTime() {
+        return time;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return time.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return time.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return time.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return time.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this time.
+     * <p>
+     * This returns an {@code OffsetTime}, based on this one, with the time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the hour field.
+     * A more complex adjuster might set the time to the last hour of the day.
+     * <p>
+     * The classes {@link LocalTime} and {@link ZoneOffset} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the time or offset:
+     * <pre>
+     *  result = offsetTime.with(time);
+     *  result = offsetTime.with(offset);
+     * </pre>
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return an {@code OffsetTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalTime) {
+            return with((LocalTime) adjuster, offset);
+        } else if (adjuster instanceof ZoneOffset) {
+            return with(time, (ZoneOffset) adjuster);
+        } else if (adjuster instanceof OffsetTime) {
+            return (OffsetTime) adjuster;
+        }
+        return (OffsetTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified field set to a new value.
+     * <p>
+     * This returns an {@code OffsetTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the hour, minute or second.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * The {@code OFFSET_SECONDS} field will return a time with the specified offset.
+     * The local time is unaltered. If the new offset value is outside the valid range
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalTime#with(TemporalField, long)} LocalTime}.
+     * In this case, the offset is not part of the calculation and will be unchanged.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an {@code OffsetTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            if (field == OFFSET_SECONDS) {
+                ChronoField f = (ChronoField) field;
+                return with(time, ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue)));
+            }
+            return with(time.with(field, newValue), offset);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the hour-of-day altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return an {@code OffsetTime} based on this time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public OffsetTime withHour(int hour) {
+        return with(time.withHour(hour), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the minute-of-hour altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return an {@code OffsetTime} based on this time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public OffsetTime withMinute(int minute) {
+        return with(time.withMinute(minute), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the second-of-minute altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return an {@code OffsetTime} based on this time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public OffsetTime withSecond(int second) {
+        return with(time.withSecond(second), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the nano-of-second altered.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return an {@code OffsetTime} based on this time with the requested nanosecond, not null
+     * @throws DateTimeException if the nanos value is invalid
+     */
+    public OffsetTime withNano(int nanoOfSecond) {
+        return with(time.withNano(nanoOfSecond), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
+     * that divides into the length of a standard day without remainder.
+     * This includes all supplied time units on {@link ChronoUnit} and
+     * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
+     * <p>
+     * The offset does not affect the calculation and will be the same in the result.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return an {@code OffsetTime} based on this time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    public OffsetTime truncatedTo(TemporalUnit unit) {
+        return with(time.truncatedTo(unit), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this time with the specified amount added.
+     * <p>
+     * This returns an {@code OffsetTime}, based on this one, with the specified amount added.
+     * The amount is typically {@link Duration} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return an {@code OffsetTime} based on this time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime plus(TemporalAmount amountToAdd) {
+        return (OffsetTime) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified amount added.
+     * <p>
+     * This returns an {@code OffsetTime}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented by
+     * {@link LocalTime#plus(long, TemporalUnit)}.
+     * The offset is not part of the calculation and will be unchanged in the result.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return an {@code OffsetTime} based on this time with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return with(time.plus(amountToAdd, unit), offset);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of hours added.
+     * <p>
+     * This adds the specified number of hours to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the hours added, not null
+     */
+    public OffsetTime plusHours(long hours) {
+        return with(time.plusHours(hours), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of minutes added.
+     * <p>
+     * This adds the specified number of minutes to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the minutes added, not null
+     */
+    public OffsetTime plusMinutes(long minutes) {
+        return with(time.plusMinutes(minutes), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of seconds added.
+     * <p>
+     * This adds the specified number of seconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the seconds added, not null
+     */
+    public OffsetTime plusSeconds(long seconds) {
+        return with(time.plusSeconds(seconds), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of nanoseconds added.
+     * <p>
+     * This adds the specified number of nanoseconds to this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return an {@code OffsetTime} based on this time with the nanoseconds added, not null
+     */
+    public OffsetTime plusNanos(long nanos) {
+        return with(time.plusNanos(nanos), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this time with the specified amount subtracted.
+     * <p>
+     * This returns an {@code OffsetTime}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Duration} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return an {@code OffsetTime} based on this time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime minus(TemporalAmount amountToSubtract) {
+        return (OffsetTime) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this time with the specified amount subtracted.
+     * <p>
+     * This returns an {@code OffsetTime}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return an {@code OffsetTime} based on this time with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public OffsetTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of hours subtracted.
+     * <p>
+     * This subtracts the specified number of hours from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the hours subtracted, not null
+     */
+    public OffsetTime minusHours(long hours) {
+        return with(time.minusHours(hours), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of minutes subtracted.
+     * <p>
+     * This subtracts the specified number of minutes from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the minutes subtracted, not null
+     */
+    public OffsetTime minusMinutes(long minutes) {
+        return with(time.minusMinutes(minutes), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of seconds subtracted.
+     * <p>
+     * This subtracts the specified number of seconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the seconds subtracted, not null
+     */
+    public OffsetTime minusSeconds(long seconds) {
+        return with(time.minusSeconds(seconds), offset);
+    }
+
+    /**
+     * Returns a copy of this {@code OffsetTime} with the specified number of nanoseconds subtracted.
+     * <p>
+     * This subtracts the specified number of nanoseconds from this time, returning a new time.
+     * The calculation wraps around midnight.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return an {@code OffsetTime} based on this time with the nanoseconds subtracted, not null
+     */
+    public OffsetTime minusNanos(long nanos) {
+        return with(time.minusNanos(nanos), offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this time using the specified query.
+     * <p>
+     * This queries this time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) {
+            return (R) offset;
+        } else if (query == TemporalQueries.zoneId() | query == TemporalQueries.chronology() || query == TemporalQueries.localDate()) {
+            return null;
+        } else if (query == TemporalQueries.localTime()) {
+            return (R) time;
+        } else if (query == TemporalQueries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same offset and time
+     * as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the offset and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#NANO_OF_DAY} and
+     * {@link ChronoField#OFFSET_SECONDS} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffsetTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffsetTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal
+                .with(NANO_OF_DAY, time.toNanoOfDay())
+                .with(OFFSET_SECONDS, offset.getTotalSeconds());
+    }
+
+    /**
+     * Calculates the amount of time until another time in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code OffsetTime}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified time.
+     * The result will be negative if the end is before the start.
+     * For example, the amount in hours between two times can be calculated
+     * using {@code startTime.until(endTime, HOURS)}.
+     * <p>
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code OffsetTime} using {@link #from(TemporalAccessor)}.
+     * If the offset differs between the two times, then the specified
+     * end time is normalized to have the same offset as this time.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two times.
+     * For example, the amount in hours between 11:30Z and 13:29Z will only
+     * be one hour as it is one minute short of two hours.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MINUTES);
+     *   amount = MINUTES.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end time, exclusive, which is converted to an {@code OffsetTime}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this time and the end time
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to an {@code OffsetTime}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        OffsetTime end = OffsetTime.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            long nanosUntil = end.toEpochNano() - toEpochNano();  // no overflow
+            switch ((ChronoUnit) unit) {
+                case NANOS: return nanosUntil;
+                case MICROS: return nanosUntil / 1000;
+                case MILLIS: return nanosUntil / 1000_000;
+                case SECONDS: return nanosUntil / NANOS_PER_SECOND;
+                case MINUTES: return nanosUntil / NANOS_PER_MINUTE;
+                case HOURS: return nanosUntil / NANOS_PER_HOUR;
+                case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this time using the specified formatter.
+     * <p>
+     * This time will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this time with a date to create an {@code OffsetDateTime}.
+     * <p>
+     * This returns an {@code OffsetDateTime} formed from this time and the specified date.
+     * All possible combinations of date and time are valid.
+     *
+     * @param date  the date to combine with, not null
+     * @return the offset date-time formed from this time and the specified date, not null
+     */
+    public OffsetDateTime atDate(LocalDate date) {
+        return OffsetDateTime.of(date, time, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this time to epoch nanos based on 1970-01-01Z.
+     *
+     * @return the epoch nanos value
+     */
+    private long toEpochNano() {
+        long nod = time.toNanoOfDay();
+        long offsetNanos = offset.getTotalSeconds() * NANOS_PER_SECOND;
+        return nod - offsetNanos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this {@code OffsetTime} to another time.
+     * <p>
+     * The comparison is based first on the UTC equivalent instant, then on the local time.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 10:30+01:00}</li>
+     * <li>{@code 11:00+01:00}</li>
+     * <li>{@code 12:00+02:00}</li>
+     * <li>{@code 11:30+01:00}</li>
+     * <li>{@code 12:00+01:00}</li>
+     * <li>{@code 12:30+01:00}</li>
+     * </ol>
+     * Values #2 and #3 represent the same instant on the time-line.
+     * When two values represent the same instant, the local time is compared
+     * to distinguish them. This step is needed to make the ordering
+     * consistent with {@code equals()}.
+     * <p>
+     * To compare the underlying local time of two {@code TemporalAccessor} instances,
+     * use {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param other  the other time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(OffsetTime other) {
+        if (offset.equals(other.offset)) {
+            return time.compareTo(other.time);
+        }
+        int compare = Long.compare(toEpochNano(), other.toEpochNano());
+        if (compare == 0) {
+            compare = time.compareTo(other.time);
+        }
+        return compare;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the instant of this {@code OffsetTime} is after that of the
+     * specified time applying both times to a common date.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the time. This is equivalent to converting both
+     * times to an instant using the same date and comparing the instants.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is after the instant of the specified time
+     */
+    public boolean isAfter(OffsetTime other) {
+        return toEpochNano() > other.toEpochNano();
+    }
+
+    /**
+     * Checks if the instant of this {@code OffsetTime} is before that of the
+     * specified time applying both times to a common date.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the time. This is equivalent to converting both
+     * times to an instant using the same date and comparing the instants.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is before the instant of the specified time
+     */
+    public boolean isBefore(OffsetTime other) {
+        return toEpochNano() < other.toEpochNano();
+    }
+
+    /**
+     * Checks if the instant of this {@code OffsetTime} is equal to that of the
+     * specified time applying both times to a common date.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
+     * in that it only compares the instant of the time. This is equivalent to converting both
+     * times to an instant using the same date and comparing the instants.
+     *
+     * @param other  the other time to compare to, not null
+     * @return true if this is equal to the instant of the specified time
+     */
+    public boolean isEqual(OffsetTime other) {
+        return toEpochNano() == other.toEpochNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this time is equal to another time.
+     * <p>
+     * The comparison is based on the local-time and the offset.
+     * To compare for the same instant on the time-line, use {@link #isEqual(OffsetTime)}.
+     * <p>
+     * Only objects of type {@code OffsetTime} are compared, other types return false.
+     * To compare the underlying local time of two {@code TemporalAccessor} instances,
+     * use {@link ChronoField#NANO_OF_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof OffsetTime) {
+            OffsetTime other = (OffsetTime) obj;
+            return time.equals(other.time) && offset.equals(other.offset);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return time.hashCode() ^ offset.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this time as a {@code String}, such as {@code 10:15:30+01:00}.
+     * <p>
+     * The output will be one of the following ISO-8601 formats:
+     * <ul>
+     * <li>{@code HH:mmXXXXX}</li>
+     * <li>{@code HH:mm:ssXXXXX}</li>
+     * <li>{@code HH:mm:ss.SSSXXXXX}</li>
+     * <li>{@code HH:mm:ss.SSSSSSXXXXX}</li>
+     * <li>{@code HH:mm:ss.SSSSSSSSSXXXXX}</li>
+     * </ul>
+     * The format used will be the shortest that outputs the full value of
+     * the time where the omitted parts are implied to be zero.
+     *
+     * @return a string representation of this time, not null
+     */
+    @Override
+    public String toString() {
+        return time.toString() + offset.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(9);  // identifies an OffsetTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalTime">time</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.OFFSET_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        time.writeExternal(out);
+        offset.writeExternal(out);
+    }
+
+    static OffsetTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        LocalTime time = LocalTime.readExternal(in);
+        ZoneOffset offset = ZoneOffset.readExternal(in);
+        return OffsetTime.of(time, offset);
+    }
+
+}
diff --git a/java/time/Period.java b/java/time/Period.java
new file mode 100644
index 0000000..f264994
--- /dev/null
+++ b/java/time/Period.java
@@ -0,0 +1,1075 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoPeriod;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date-based amount of time in the ISO-8601 calendar system,
+ * such as '2 years, 3 months and 4 days'.
+ * <p>
+ * This class models a quantity or amount of time in terms of years, months and days.
+ * See {@link Duration} for the time-based equivalent to this class.
+ * <p>
+ * Durations and periods differ in their treatment of daylight savings time
+ * when added to {@link ZonedDateTime}. A {@code Duration} will add an exact
+ * number of seconds, thus a duration of one day is always exactly 24 hours.
+ * By contrast, a {@code Period} will add a conceptual day, trying to maintain
+ * the local time.
+ * <p>
+ * For example, consider adding a period of one day and a duration of one day to
+ * 18:00 on the evening before a daylight savings gap. The {@code Period} will add
+ * the conceptual day and result in a {@code ZonedDateTime} at 18:00 the following day.
+ * By contrast, the {@code Duration} will add exactly 24 hours, resulting in a
+ * {@code ZonedDateTime} at 19:00 the following day (assuming a one hour DST gap).
+ * <p>
+ * The supported units of a period are {@link ChronoUnit#YEARS YEARS},
+ * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
+ * All three fields are always present, but may be set to zero.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * <p>
+ * The period is modeled as a directed amount of time, meaning that individual parts of the
+ * period may be negative.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Period
+        implements ChronoPeriod, Serializable {
+
+    /**
+     * A constant for a period of zero.
+     */
+    public static final Period ZERO = new Period(0, 0, 0);
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -3587258372562876L;
+    /**
+     * The pattern for parsing.
+     */
+    private static final Pattern PATTERN =
+            Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE);
+
+    /**
+     * The set of supported units.
+     */
+    private static final List<TemporalUnit> SUPPORTED_UNITS =
+            Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS));
+
+    /**
+     * The number of years.
+     */
+    private final int years;
+    /**
+     * The number of months.
+     */
+    private final int months;
+    /**
+     * The number of days.
+     */
+    private final int days;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} representing a number of years.
+     * <p>
+     * The resulting period will have the specified years.
+     * The months and days units will be zero.
+     *
+     * @param years  the number of years, positive or negative
+     * @return the period of years, not null
+     */
+    public static Period ofYears(int years) {
+        return create(years, 0, 0);
+    }
+
+    /**
+     * Obtains a {@code Period} representing a number of months.
+     * <p>
+     * The resulting period will have the specified months.
+     * The years and days units will be zero.
+     *
+     * @param months  the number of months, positive or negative
+     * @return the period of months, not null
+     */
+    public static Period ofMonths(int months) {
+        return create(0, months, 0);
+    }
+
+    /**
+     * Obtains a {@code Period} representing a number of weeks.
+     * <p>
+     * The resulting period will be day-based, with the amount of days
+     * equal to the number of weeks multiplied by 7.
+     * The years and months units will be zero.
+     *
+     * @param weeks  the number of weeks, positive or negative
+     * @return the period, with the input weeks converted to days, not null
+     */
+    public static Period ofWeeks(int weeks) {
+        return create(0, 0, Math.multiplyExact(weeks, 7));
+    }
+
+    /**
+     * Obtains a {@code Period} representing a number of days.
+     * <p>
+     * The resulting period will have the specified days.
+     * The years and months units will be zero.
+     *
+     * @param days  the number of days, positive or negative
+     * @return the period of days, not null
+     */
+    public static Period ofDays(int days) {
+        return create(0, 0, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} representing a number of years, months and days.
+     * <p>
+     * This creates an instance based on years, months and days.
+     *
+     * @param years  the amount of years, may be negative
+     * @param months  the amount of months, may be negative
+     * @param days  the amount of days, may be negative
+     * @return the period of years, months and days, not null
+     */
+    public static Period of(int years, int months, int days) {
+        return create(years, months, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Period} from a temporal amount.
+     * <p>
+     * This obtains a period based on the specified amount.
+     * A {@code TemporalAmount} represents an  amount of time, which may be
+     * date-based or time-based, which this factory extracts to a {@code Period}.
+     * <p>
+     * The conversion loops around the set of units from the amount and uses
+     * the {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS}
+     * and {@link ChronoUnit#DAYS DAYS} units to create a period.
+     * If any other units are found then an exception is thrown.
+     * <p>
+     * If the amount is a {@code ChronoPeriod} then it must use the ISO chronology.
+     *
+     * @param amount  the temporal amount to convert, not null
+     * @return the equivalent period, not null
+     * @throws DateTimeException if unable to convert to a {@code Period}
+     * @throws ArithmeticException if the amount of years, months or days exceeds an int
+     */
+    public static Period from(TemporalAmount amount) {
+        if (amount instanceof Period) {
+            return (Period) amount;
+        }
+        if (amount instanceof ChronoPeriod) {
+            if (IsoChronology.INSTANCE.equals(((ChronoPeriod) amount).getChronology()) == false) {
+                throw new DateTimeException("Period requires ISO chronology: " + amount);
+            }
+        }
+        Objects.requireNonNull(amount, "amount");
+        int years = 0;
+        int months = 0;
+        int days = 0;
+        for (TemporalUnit unit : amount.getUnits()) {
+            long unitAmount = amount.get(unit);
+            if (unit == ChronoUnit.YEARS) {
+                years = Math.toIntExact(unitAmount);
+            } else if (unit == ChronoUnit.MONTHS) {
+                months = Math.toIntExact(unitAmount);
+            } else if (unit == ChronoUnit.DAYS) {
+                days = Math.toIntExact(unitAmount);
+            } else {
+                throw new DateTimeException("Unit must be Years, Months or Days, but was " + unit);
+            }
+        }
+        return create(years, months, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} from a text string such as {@code PnYnMnD}.
+     * <p>
+     * This will parse the string produced by {@code toString()} which is
+     * based on the ISO-8601 period formats {@code PnYnMnD} and {@code PnW}.
+     * <p>
+     * The string starts with an optional sign, denoted by the ASCII negative
+     * or positive symbol. If negative, the whole period is negated.
+     * The ASCII letter "P" is next in upper or lower case.
+     * There are then four sections, each consisting of a number and a suffix.
+     * At least one of the four sections must be present.
+     * The sections have suffixes in ASCII of "Y", "M", "W" and "D" for
+     * years, months, weeks and days, accepted in upper or lower case.
+     * The suffixes must occur in order.
+     * The number part of each section must consist of ASCII digits.
+     * The number may be prefixed by the ASCII negative or positive symbol.
+     * The number must parse to an {@code int}.
+     * <p>
+     * The leading plus/minus sign, and negative values for other units are
+     * not part of the ISO-8601 standard. In addition, ISO-8601 does not
+     * permit mixing between the {@code PnYnMnD} and {@code PnW} formats.
+     * Any week-based input is multiplied by 7 and treated as a number of days.
+     * <p>
+     * For example, the following are valid inputs:
+     * <pre>
+     *   "P2Y"             -- Period.ofYears(2)
+     *   "P3M"             -- Period.ofMonths(3)
+     *   "P4W"             -- Period.ofWeeks(4)
+     *   "P5D"             -- Period.ofDays(5)
+     *   "P1Y2M3D"         -- Period.of(1, 2, 3)
+     *   "P1Y2M3W4D"       -- Period.of(1, 2, 25)
+     *   "P-1Y2M"          -- Period.of(-1, 2, 0)
+     *   "-P1Y2M"          -- Period.of(-1, -2, 0)
+     * </pre>
+     *
+     * @param text  the text to parse, not null
+     * @return the parsed period, not null
+     * @throws DateTimeParseException if the text cannot be parsed to a period
+     */
+    public static Period parse(CharSequence text) {
+        Objects.requireNonNull(text, "text");
+        Matcher matcher = PATTERN.matcher(text);
+        if (matcher.matches()) {
+            int negate = ("-".equals(matcher.group(1)) ? -1 : 1);
+            String yearMatch = matcher.group(2);
+            String monthMatch = matcher.group(3);
+            String weekMatch = matcher.group(4);
+            String dayMatch = matcher.group(5);
+            if (yearMatch != null || monthMatch != null || dayMatch != null || weekMatch != null) {
+                try {
+                    int years = parseNumber(text, yearMatch, negate);
+                    int months = parseNumber(text, monthMatch, negate);
+                    int weeks = parseNumber(text, weekMatch, negate);
+                    int days = parseNumber(text, dayMatch, negate);
+                    days = Math.addExact(days, Math.multiplyExact(weeks, 7));
+                    return create(years, months, days);
+                } catch (NumberFormatException ex) {
+                    throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex);
+                }
+            }
+        }
+        throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0);
+    }
+
+    private static int parseNumber(CharSequence text, String str, int negate) {
+        if (str == null) {
+            return 0;
+        }
+        int val = Integer.parseInt(str);
+        try {
+            return Math.multiplyExact(val, negate);
+        } catch (ArithmeticException ex) {
+            throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code Period} consisting of the number of years, months,
+     * and days between two dates.
+     * <p>
+     * The start date is included, but the end date is not.
+     * The period is calculated by removing complete months, then calculating
+     * the remaining number of days, adjusting to ensure that both have the same sign.
+     * The number of months is then split into years and months based on a 12 month year.
+     * A month is considered if the end day-of-month is greater than or equal to the start day-of-month.
+     * For example, from {@code 2010-01-15} to {@code 2011-03-18} is one year, two months and three days.
+     * <p>
+     * The result of this method can be a negative period if the end is before the start.
+     * The negative sign will be the same in each of year, month and day.
+     *
+     * @param startDateInclusive  the start date, inclusive, not null
+     * @param endDateExclusive  the end date, exclusive, not null
+     * @return the period between this date and the end date, not null
+     * @see ChronoLocalDate#until(ChronoLocalDate)
+     */
+    public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive) {
+        return startDateInclusive.until(endDateExclusive);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     *
+     * @param years  the amount
+     * @param months  the amount
+     * @param days  the amount
+     */
+    private static Period create(int years, int months, int days) {
+        if ((years | months | days) == 0) {
+            return ZERO;
+        }
+        return new Period(years, months, days);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param years  the amount
+     * @param months  the amount
+     * @param days  the amount
+     */
+    private Period(int years, int months, int days) {
+        this.years = years;
+        this.months = months;
+        this.days = days;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the value of the requested unit.
+     * <p>
+     * This returns a value for each of the three supported units,
+     * {@link ChronoUnit#YEARS YEARS}, {@link ChronoUnit#MONTHS MONTHS} and
+     * {@link ChronoUnit#DAYS DAYS}.
+     * All other units throw an exception.
+     *
+     * @param unit the {@code TemporalUnit} for which to return the value
+     * @return the long value of the unit
+     * @throws DateTimeException if the unit is not supported
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    @Override
+    public long get(TemporalUnit unit) {
+        if (unit == ChronoUnit.YEARS) {
+            return getYears();
+        } else if (unit == ChronoUnit.MONTHS) {
+            return getMonths();
+        } else if (unit == ChronoUnit.DAYS) {
+            return getDays();
+        } else {
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+    }
+
+    /**
+     * Gets the set of units supported by this period.
+     * <p>
+     * The supported units are {@link ChronoUnit#YEARS YEARS},
+     * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
+     * They are returned in the order years, months, days.
+     * <p>
+     * This set can be used in conjunction with {@link #get(TemporalUnit)}
+     * to access the entire state of the period.
+     *
+     * @return a list containing the years, months and days units, not null
+     */
+    @Override
+    public List<TemporalUnit> getUnits() {
+        return SUPPORTED_UNITS;
+    }
+
+    /**
+     * Gets the chronology of this period, which is the ISO calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The ISO-8601 calendar system is the modern civil calendar system used today
+     * in most of the world. It is equivalent to the proleptic Gregorian calendar
+     * system, in which today's rules for leap years are applied for all time.
+     *
+     * @return the ISO chronology, not null
+     */
+    @Override
+    public IsoChronology getChronology() {
+        return IsoChronology.INSTANCE;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if all three units of this period are zero.
+     * <p>
+     * A zero period has the value zero for the years, months and days units.
+     *
+     * @return true if this period is zero-length
+     */
+    public boolean isZero() {
+        return (this == ZERO);
+    }
+
+    /**
+     * Checks if any of the three units of this period are negative.
+     * <p>
+     * This checks whether the years, months or days units are less than zero.
+     *
+     * @return true if any unit of this period is negative
+     */
+    public boolean isNegative() {
+        return years < 0 || months < 0 || days < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the amount of years of this period.
+     * <p>
+     * This returns the years unit.
+     * <p>
+     * The months unit is not automatically normalized with the years unit.
+     * This means that a period of "15 months" is different to a period
+     * of "1 year and 3 months".
+     *
+     * @return the amount of years of this period, may be negative
+     */
+    public int getYears() {
+        return years;
+    }
+
+    /**
+     * Gets the amount of months of this period.
+     * <p>
+     * This returns the months unit.
+     * <p>
+     * The months unit is not automatically normalized with the years unit.
+     * This means that a period of "15 months" is different to a period
+     * of "1 year and 3 months".
+     *
+     * @return the amount of months of this period, may be negative
+     */
+    public int getMonths() {
+        return months;
+    }
+
+    /**
+     * Gets the amount of days of this period.
+     * <p>
+     * This returns the days unit.
+     *
+     * @return the amount of days of this period, may be negative
+     */
+    public int getDays() {
+        return days;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified amount of years.
+     * <p>
+     * This sets the amount of the years unit in a copy of this period.
+     * The months and days units are unaffected.
+     * <p>
+     * The months unit is not automatically normalized with the years unit.
+     * This means that a period of "15 months" is different to a period
+     * of "1 year and 3 months".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to represent, may be negative
+     * @return a {@code Period} based on this period with the requested years, not null
+     */
+    public Period withYears(int years) {
+        if (years == this.years) {
+            return this;
+        }
+        return create(years, months, days);
+    }
+
+    /**
+     * Returns a copy of this period with the specified amount of months.
+     * <p>
+     * This sets the amount of the months unit in a copy of this period.
+     * The years and days units are unaffected.
+     * <p>
+     * The months unit is not automatically normalized with the years unit.
+     * This means that a period of "15 months" is different to a period
+     * of "1 year and 3 months".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to represent, may be negative
+     * @return a {@code Period} based on this period with the requested months, not null
+     */
+    public Period withMonths(int months) {
+        if (months == this.months) {
+            return this;
+        }
+        return create(years, months, days);
+    }
+
+    /**
+     * Returns a copy of this period with the specified amount of days.
+     * <p>
+     * This sets the amount of the days unit in a copy of this period.
+     * The years and months units are unaffected.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to represent, may be negative
+     * @return a {@code Period} based on this period with the requested days, not null
+     */
+    public Period withDays(int days) {
+        if (days == this.days) {
+            return this;
+        }
+        return create(years, months, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified period added.
+     * <p>
+     * This operates separately on the years, months and days.
+     * No normalization is performed.
+     * <p>
+     * For example, "1 year, 6 months and 3 days" plus "2 years, 2 months and 2 days"
+     * returns "3 years, 8 months and 5 days".
+     * <p>
+     * The specified amount is typically an instance of {@code Period}.
+     * Other types are interpreted using {@link Period#from(TemporalAmount)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code Period} based on this period with the requested period added, not null
+     * @throws DateTimeException if the specified amount has a non-ISO chronology or
+     *  contains an invalid unit
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period plus(TemporalAmount amountToAdd) {
+        Period isoAmount = Period.from(amountToAdd);
+        return create(
+                Math.addExact(years, isoAmount.years),
+                Math.addExact(months, isoAmount.months),
+                Math.addExact(days, isoAmount.days));
+    }
+
+    /**
+     * Returns a copy of this period with the specified years added.
+     * <p>
+     * This adds the amount to the years unit in a copy of this period.
+     * The months and days units are unaffected.
+     * For example, "1 year, 6 months and 3 days" plus 2 years returns "3 years, 6 months and 3 days".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, positive or negative
+     * @return a {@code Period} based on this period with the specified years added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        return create(Math.toIntExact(Math.addExact(years, yearsToAdd)), months, days);
+    }
+
+    /**
+     * Returns a copy of this period with the specified months added.
+     * <p>
+     * This adds the amount to the months unit in a copy of this period.
+     * The years and days units are unaffected.
+     * For example, "1 year, 6 months and 3 days" plus 2 months returns "1 year, 8 months and 3 days".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, positive or negative
+     * @return a {@code Period} based on this period with the specified months added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
+            return this;
+        }
+        return create(years, Math.toIntExact(Math.addExact(months, monthsToAdd)), days);
+    }
+
+    /**
+     * Returns a copy of this period with the specified days added.
+     * <p>
+     * This adds the amount to the days unit in a copy of this period.
+     * The years and months units are unaffected.
+     * For example, "1 year, 6 months and 3 days" plus 2 days returns "1 year, 6 months and 5 days".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, positive or negative
+     * @return a {@code Period} based on this period with the specified days added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period plusDays(long daysToAdd) {
+        if (daysToAdd == 0) {
+            return this;
+        }
+        return create(years, months, Math.toIntExact(Math.addExact(days, daysToAdd)));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified period subtracted.
+     * <p>
+     * This operates separately on the years, months and days.
+     * No normalization is performed.
+     * <p>
+     * For example, "1 year, 6 months and 3 days" minus "2 years, 2 months and 2 days"
+     * returns "-1 years, 4 months and 1 day".
+     * <p>
+     * The specified amount is typically an instance of {@code Period}.
+     * Other types are interpreted using {@link Period#from(TemporalAmount)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code Period} based on this period with the requested period subtracted, not null
+     * @throws DateTimeException if the specified amount has a non-ISO chronology or
+     *  contains an invalid unit
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period minus(TemporalAmount amountToSubtract) {
+        Period isoAmount = Period.from(amountToSubtract);
+        return create(
+                Math.subtractExact(years, isoAmount.years),
+                Math.subtractExact(months, isoAmount.months),
+                Math.subtractExact(days, isoAmount.days));
+    }
+
+    /**
+     * Returns a copy of this period with the specified years subtracted.
+     * <p>
+     * This subtracts the amount from the years unit in a copy of this period.
+     * The months and days units are unaffected.
+     * For example, "1 year, 6 months and 3 days" minus 2 years returns "-1 years, 6 months and 3 days".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, positive or negative
+     * @return a {@code Period} based on this period with the specified years subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this period with the specified months subtracted.
+     * <p>
+     * This subtracts the amount from the months unit in a copy of this period.
+     * The years and days units are unaffected.
+     * For example, "1 year, 6 months and 3 days" minus 2 months returns "1 year, 4 months and 3 days".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the years to subtract, positive or negative
+     * @return a {@code Period} based on this period with the specified months subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this period with the specified days subtracted.
+     * <p>
+     * This subtracts the amount from the days unit in a copy of this period.
+     * The years and months units are unaffected.
+     * For example, "1 year, 6 months and 3 days" minus 2 days returns "1 year, 6 months and 1 day".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the months to subtract, positive or negative
+     * @return a {@code Period} based on this period with the specified days subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a new instance with each element in this period multiplied
+     * by the specified scalar.
+     * <p>
+     * This returns a period with each of the years, months and days units
+     * individually multiplied.
+     * For example, a period of "2 years, -3 months and 4 days" multiplied by
+     * 3 will return "6 years, -9 months and 12 days".
+     * No normalization is performed.
+     *
+     * @param scalar  the scalar to multiply by, not null
+     * @return a {@code Period} based on this period with the amounts multiplied by the scalar, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period multipliedBy(int scalar) {
+        if (this == ZERO || scalar == 1) {
+            return this;
+        }
+        return create(
+                Math.multiplyExact(years, scalar),
+                Math.multiplyExact(months, scalar),
+                Math.multiplyExact(days, scalar));
+    }
+
+    /**
+     * Returns a new instance with each amount in this period negated.
+     * <p>
+     * This returns a period with each of the years, months and days units
+     * individually negated.
+     * For example, a period of "2 years, -3 months and 4 days" will be
+     * negated to "-2 years, 3 months and -4 days".
+     * No normalization is performed.
+     *
+     * @return a {@code Period} based on this period with the amounts negated, not null
+     * @throws ArithmeticException if numeric overflow occurs, which only happens if
+     *  one of the units has the value {@code Long.MIN_VALUE}
+     */
+    public Period negated() {
+        return multipliedBy(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the years and months normalized.
+     * <p>
+     * This normalizes the years and months units, leaving the days unit unchanged.
+     * The months unit is adjusted to have an absolute value less than 11,
+     * with the years unit being adjusted to compensate. For example, a period of
+     * "1 Year and 15 months" will be normalized to "2 years and 3 months".
+     * <p>
+     * The sign of the years and months units will be the same after normalization.
+     * For example, a period of "1 year and -25 months" will be normalized to
+     * "-1 year and -1 month".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code Period} based on this period with excess months normalized to years, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    public Period normalized() {
+        long totalMonths = toTotalMonths();
+        long splitYears = totalMonths / 12;
+        int splitMonths = (int) (totalMonths % 12);  // no overflow
+        if (splitYears == years && splitMonths == months) {
+            return this;
+        }
+        return create(Math.toIntExact(splitYears), splitMonths, days);
+    }
+
+    /**
+     * Gets the total number of months in this period.
+     * <p>
+     * This returns the total number of months in the period by multiplying the
+     * number of years by 12 and adding the number of months.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return the total number of months in the period, may be negative
+     */
+    public long toTotalMonths() {
+        return years * 12L + months;  // no overflow
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Adds this period to the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period added.
+     * If the temporal has a chronology, it must be the ISO chronology.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAmount)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisPeriod);
+     * </pre>
+     * <p>
+     * The calculation operates as follows.
+     * First, the chronology of the temporal is checked to ensure it is ISO chronology or null.
+     * Second, if the months are zero, the years are added if non-zero, otherwise
+     * the combination of years and months is added if non-zero.
+     * Finally, any days are added.
+     * <p>
+     * This approach ensures that a partial period can be added to a partial date.
+     * For example, a period of years and/or months can be added to a {@code YearMonth},
+     * but a period including days cannot.
+     * The approach also adds years and months together when necessary, which ensures
+     * correct behaviour at the end of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same type with the adjustment made, not null
+     * @throws DateTimeException if unable to add
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal addTo(Temporal temporal) {
+        validateChrono(temporal);
+        if (months == 0) {
+            if (years != 0) {
+                temporal = temporal.plus(years, YEARS);
+            }
+        } else {
+            long totalMonths = toTotalMonths();
+            if (totalMonths != 0) {
+                temporal = temporal.plus(totalMonths, MONTHS);
+            }
+        }
+        if (days != 0) {
+            temporal = temporal.plus(days, DAYS);
+        }
+        return temporal;
+    }
+
+    /**
+     * Subtracts this period from the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period subtracted.
+     * If the temporal has a chronology, it must be the ISO chronology.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#minus(TemporalAmount)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisPeriod);
+     * </pre>
+     * <p>
+     * The calculation operates as follows.
+     * First, the chronology of the temporal is checked to ensure it is ISO chronology or null.
+     * Second, if the months are zero, the years are subtracted if non-zero, otherwise
+     * the combination of years and months is subtracted if non-zero.
+     * Finally, any days are subtracted.
+     * <p>
+     * This approach ensures that a partial period can be subtracted from a partial date.
+     * For example, a period of years and/or months can be subtracted from a {@code YearMonth},
+     * but a period including days cannot.
+     * The approach also subtracts years and months together when necessary, which ensures
+     * correct behaviour at the end of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same type with the adjustment made, not null
+     * @throws DateTimeException if unable to subtract
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal subtractFrom(Temporal temporal) {
+        validateChrono(temporal);
+        if (months == 0) {
+            if (years != 0) {
+                temporal = temporal.minus(years, YEARS);
+            }
+        } else {
+            long totalMonths = toTotalMonths();
+            if (totalMonths != 0) {
+                temporal = temporal.minus(totalMonths, MONTHS);
+            }
+        }
+        if (days != 0) {
+            temporal = temporal.minus(days, DAYS);
+        }
+        return temporal;
+    }
+
+    /**
+     * Validates that the temporal has the correct chronology.
+     */
+    private void validateChrono(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
+        if (temporalChrono != null && IsoChronology.INSTANCE.equals(temporalChrono) == false) {
+            throw new DateTimeException("Chronology mismatch, expected: ISO, actual: " + temporalChrono.getId());
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this period is equal to another period.
+     * <p>
+     * The comparison is based on the type {@code Period} and each of the three amounts.
+     * To be equal, the years, months and days units must be individually equal.
+     * Note that this means that a period of "15 Months" is not equal to a period
+     * of "1 Year and 3 Months".
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other period
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Period) {
+            Period other = (Period) obj;
+            return years == other.years &&
+                    months == other.months &&
+                    days == other.days;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this period.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this period as a {@code String}, such as {@code P6Y3M1D}.
+     * <p>
+     * The output will be in the ISO-8601 period format.
+     * A zero period will be represented as zero days, 'P0D'.
+     *
+     * @return a string representation of this period, not null
+     */
+    @Override
+    public String toString() {
+        if (this == ZERO) {
+            return "P0D";
+        } else {
+            StringBuilder buf = new StringBuilder();
+            buf.append('P');
+            if (years != 0) {
+                buf.append(years).append('Y');
+            }
+            if (months != 0) {
+                buf.append(months).append('M');
+            }
+            if (days != 0) {
+                buf.append(days).append('D');
+            }
+            return buf.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(14);  // identifies a Period
+     *  out.writeInt(years);
+     *  out.writeInt(months);
+     *  out.writeInt(days);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.PERIOD_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(years);
+        out.writeInt(months);
+        out.writeInt(days);
+    }
+
+    static Period readExternal(DataInput in) throws IOException {
+        int years = in.readInt();
+        int months = in.readInt();
+        int days = in.readInt();
+        return Period.of(years, months, days);
+    }
+
+}
diff --git a/java/time/Ser.java b/java/time/Ser.java
new file mode 100644
index 0000000..885b43a
--- /dev/null
+++ b/java/time/Ser.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ * @implNote
+ * This class wraps the object being serialized, and takes a byte representing the type of the class to
+ * be serialized.  This byte can also be used for versioning the serialization format.  In this case another
+ * byte flag would be used in order to specify an alternative version of the type format.
+ * For example {@code LOCAL_DATE_TYPE_VERSION_2 = 21}.
+ * <p>
+ * In order to serialize the object it writes its byte and then calls back to the appropriate class where
+ * the serialization is performed.  In order to deserialize the object it read in the type byte, switching
+ * in order to select which class to call back into.
+ * <p>
+ * The serialization format is determined on a per class basis.  In the case of field based classes each
+ * of the fields is written out with an appropriate size format in descending order of the field's size.  For
+ * example in the case of {@link LocalDate} year is written before month.  Composite classes, such as
+ * {@link LocalDateTime} are serialized as one object.
+ * <p>
+ * This class is mutable and should be created once per serialization.
+ *
+ * @serial include
+ * @since 1.8
+ */
+final class Ser implements Externalizable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -7683839454370182990L;
+
+    static final byte DURATION_TYPE = 1;
+    static final byte INSTANT_TYPE = 2;
+    static final byte LOCAL_DATE_TYPE = 3;
+    static final byte LOCAL_TIME_TYPE = 4;
+    static final byte LOCAL_DATE_TIME_TYPE = 5;
+    static final byte ZONE_DATE_TIME_TYPE = 6;
+    static final byte ZONE_REGION_TYPE = 7;
+    static final byte ZONE_OFFSET_TYPE = 8;
+    static final byte OFFSET_TIME_TYPE = 9;
+    static final byte OFFSET_DATE_TIME_TYPE = 10;
+    static final byte YEAR_TYPE = 11;
+    static final byte YEAR_MONTH_TYPE = 12;
+    static final byte MONTH_DAY_TYPE = 13;
+    static final byte PERIOD_TYPE = 14;
+
+    /** The type being serialized. */
+    private byte type;
+    /** The object being serialized. */
+    private Object object;
+
+    /**
+     * Constructor for deserialization.
+     */
+    public Ser() {
+    }
+
+    /**
+     * Creates an instance for serialization.
+     *
+     * @param type  the type
+     * @param object  the object
+     */
+    Ser(byte type, Object object) {
+        this.type = type;
+        this.object = object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to write the object.
+     * @serialData
+     *
+     * Each serializable class is mapped to a type that is the first byte
+     * in the stream.  Refer to each class {@code writeReplace}
+     * serialized form for the value of the type and sequence of values for the type.
+     * <ul>
+     * <li><a href="../../serialized-form.html#java.time.Duration">Duration.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.Instant">Instant.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.Period">Period.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.Year">Year.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime.writeReplace</a>
+     * </ul>
+     *
+     * @param out  the data stream to write to, not null
+     */
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        writeInternal(type, object, out);
+    }
+
+    static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
+        out.writeByte(type);
+        switch (type) {
+            case DURATION_TYPE:
+                ((Duration) object).writeExternal(out);
+                break;
+            case INSTANT_TYPE:
+                ((Instant) object).writeExternal(out);
+                break;
+            case LOCAL_DATE_TYPE:
+                ((LocalDate) object).writeExternal(out);
+                break;
+            case LOCAL_DATE_TIME_TYPE:
+                ((LocalDateTime) object).writeExternal(out);
+                break;
+            case LOCAL_TIME_TYPE:
+                ((LocalTime) object).writeExternal(out);
+                break;
+            case ZONE_REGION_TYPE:
+                ((ZoneRegion) object).writeExternal(out);
+                break;
+            case ZONE_OFFSET_TYPE:
+                ((ZoneOffset) object).writeExternal(out);
+                break;
+            case ZONE_DATE_TIME_TYPE:
+                ((ZonedDateTime) object).writeExternal(out);
+                break;
+            case OFFSET_TIME_TYPE:
+                ((OffsetTime) object).writeExternal(out);
+                break;
+            case OFFSET_DATE_TIME_TYPE:
+                ((OffsetDateTime) object).writeExternal(out);
+                break;
+            case YEAR_TYPE:
+                ((Year) object).writeExternal(out);
+                break;
+            case YEAR_MONTH_TYPE:
+                ((YearMonth) object).writeExternal(out);
+                break;
+            case MONTH_DAY_TYPE:
+                ((MonthDay) object).writeExternal(out);
+                break;
+            case PERIOD_TYPE:
+                ((Period) object).writeExternal(out);
+                break;
+            default:
+                throw new InvalidClassException("Unknown serialized type");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to read the object.
+     * @serialData
+     *
+     * The streamed type and parameters defined by the type's {@code writeReplace}
+     * method are read and passed to the corresponding static factory for the type
+     * to create a new instance.  That instance is returned as the de-serialized
+     * {@code Ser} object.
+     *
+     * <ul>
+     * <li><a href="../../serialized-form.html#java.time.Duration">Duration</a> - {@code Duration.ofSeconds(seconds, nanos);}
+     * <li><a href="../../serialized-form.html#java.time.Instant">Instant</a> - {@code Instant.ofEpochSecond(seconds, nanos);}
+     * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate</a> - {@code LocalDate.of(year, month, day);}
+     * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime</a> - {@code LocalDateTime.of(date, time);}
+     * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime</a> - {@code LocalTime.of(hour, minute, second, nano);}
+     * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay</a> - {@code MonthDay.of(month, day);}
+     * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime</a> - {@code OffsetTime.of(time, offset);}
+     * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime</a> - {@code OffsetDateTime.of(dateTime, offset);}
+     * <li><a href="../../serialized-form.html#java.time.Period">Period</a> - {@code Period.of(years, months, days);}
+     * <li><a href="../../serialized-form.html#java.time.Year">Year</a> - {@code Year.of(year);}
+     * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth</a> - {@code YearMonth.of(year, month);}
+     * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime</a> - {@code ZonedDateTime.ofLenient(dateTime, offset, zone);}
+     * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId</a> - {@code ZoneId.of(id);}
+     * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset</a> - {@code (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));}
+     * </ul>
+     *
+     * @param in  the data to read, not null
+     */
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        type = in.readByte();
+        object = readInternal(type, in);
+    }
+
+    static Object read(ObjectInput in) throws IOException, ClassNotFoundException {
+        byte type = in.readByte();
+        return readInternal(type, in);
+    }
+
+    private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
+        switch (type) {
+            case DURATION_TYPE: return Duration.readExternal(in);
+            case INSTANT_TYPE: return Instant.readExternal(in);
+            case LOCAL_DATE_TYPE: return LocalDate.readExternal(in);
+            case LOCAL_DATE_TIME_TYPE: return LocalDateTime.readExternal(in);
+            case LOCAL_TIME_TYPE: return LocalTime.readExternal(in);
+            case ZONE_DATE_TIME_TYPE: return ZonedDateTime.readExternal(in);
+            case ZONE_OFFSET_TYPE: return ZoneOffset.readExternal(in);
+            case ZONE_REGION_TYPE: return ZoneRegion.readExternal(in);
+            case OFFSET_TIME_TYPE: return OffsetTime.readExternal(in);
+            case OFFSET_DATE_TIME_TYPE: return OffsetDateTime.readExternal(in);
+            case YEAR_TYPE: return Year.readExternal(in);
+            case YEAR_MONTH_TYPE: return YearMonth.readExternal(in);
+            case MONTH_DAY_TYPE: return MonthDay.readExternal(in);
+            case PERIOD_TYPE: return Period.readExternal(in);
+            default:
+                throw new StreamCorruptedException("Unknown serialized type");
+        }
+    }
+
+    /**
+     * Returns the object that will replace this one.
+     *
+     * @return the read object, should never be null
+     */
+    private Object readResolve() {
+         return object;
+    }
+
+}
diff --git a/java/time/Year.java b/java/time/Year.java
new file mode 100644
index 0000000..a1d5679
--- /dev/null
+++ b/java/time/Year.java
@@ -0,0 +1,1116 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.CENTURIES;
+import static java.time.temporal.ChronoUnit.DECADES;
+import static java.time.temporal.ChronoUnit.ERAS;
+import static java.time.temporal.ChronoUnit.MILLENNIA;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.format.SignStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A year in the ISO-8601 calendar system, such as {@code 2007}.
+ * <p>
+ * {@code Year} is an immutable date-time object that represents a year.
+ * Any field that can be derived from a year can be obtained.
+ * <p>
+ * <b>Note that years in the ISO chronology only align with years in the
+ * Gregorian-Julian system for modern years. Parts of Russia did not switch to the
+ * modern Gregorian/ISO rules until 1920.
+ * As such, historical years must be treated with caution.</b>
+ * <p>
+ * This class does not store or represent a month, day, time or time-zone.
+ * For example, the value "2007" can be stored in a {@code Year}.
+ * <p>
+ * Years represented by this class follow the ISO-8601 standard and use
+ * the proleptic numbering system. Year 1 is preceded by year 0, then by year -1.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class Year
+        implements Temporal, TemporalAdjuster, Comparable<Year>, Serializable {
+
+    /**
+     * The minimum supported year, '-999,999,999'.
+     */
+    public static final int MIN_VALUE = -999_999_999;
+    /**
+     * The maximum supported year, '+999,999,999'.
+     */
+    public static final int MAX_VALUE = 999_999_999;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -23038383694477807L;
+    /**
+     * Parser.
+     */
+    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
+        .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+        .toFormatter();
+
+    /**
+     * The year being represented.
+     */
+    private final int year;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current year from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current year.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current year using the system clock and default time-zone, not null
+     */
+    public static Year now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current year from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current year.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current year using the system clock, not null
+     */
+    public static Year now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current year from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current year.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current year, not null
+     */
+    public static Year now(Clock clock) {
+        final LocalDate now = LocalDate.now(clock);  // called once
+        return Year.of(now.getYear());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Year}.
+     * <p>
+     * This method accepts a year value from the proleptic ISO calendar system.
+     * <p>
+     * The year 2AD/CE is represented by 2.<br>
+     * The year 1AD/CE is represented by 1.<br>
+     * The year 1BC/BCE is represented by 0.<br>
+     * The year 2BC/BCE is represented by -1.<br>
+     *
+     * @param isoYear  the ISO proleptic year to represent, from {@code MIN_VALUE} to {@code MAX_VALUE}
+     * @return the year, not null
+     * @throws DateTimeException if the field is invalid
+     */
+    public static Year of(int isoYear) {
+        YEAR.checkValidValue(isoYear);
+        return new Year(isoYear);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Year} from a temporal object.
+     * <p>
+     * This obtains a year based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code Year}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#YEAR year} field.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code Year::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the year, not null
+     * @throws DateTimeException if unable to convert to a {@code Year}
+     */
+    public static Year from(TemporalAccessor temporal) {
+        if (temporal instanceof Year) {
+            return (Year) temporal;
+        }
+        Objects.requireNonNull(temporal, "temporal");
+        try {
+            if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(YEAR));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain Year from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Year} from a text string such as {@code 2007}.
+     * <p>
+     * The string must represent a valid year.
+     * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
+     *
+     * @param text  the text to parse such as "2007", not null
+     * @return the parsed year, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static Year parse(CharSequence text) {
+        return parse(text, PARSER);
+    }
+
+    /**
+     * Obtains an instance of {@code Year} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a year.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed year, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static Year parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, Year::from);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @param year  the year to check
+     * @return true if the year is leap, false otherwise
+     */
+    public static boolean isLeap(long year) {
+        return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param year  the year to represent
+     */
+    private Year(int year) {
+        this.year = year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the year value.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     *
+     * @return the year, {@code MIN_VALUE} to {@code MAX_VALUE}
+     */
+    public int getValue() {
+        return year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this year can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this year, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == YEAR || field == YEAR_OF_ERA || field == ERA;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this year.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code YEARS}
+     * <li>{@code DECADES}
+     * <li>{@code CENTURIES}
+     * <li>{@code MILLENNIA}
+     * <li>{@code ERAS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS;
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This year is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == YEAR_OF_ERA) {
+            return (year <= 0 ? ValueRange.of(1, MAX_VALUE + 1) : ValueRange.of(1, MAX_VALUE));
+        }
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year as an {@code int}.
+     * <p>
+     * This queries this year for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year as a {@code long}.
+     * <p>
+     * This queries this year for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
+                case YEAR: return year;
+                case ERA: return (year < 1 ? 0 : 1);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @return true if the year is leap, false otherwise
+     */
+    public boolean isLeap() {
+        return Year.isLeap(year);
+    }
+
+    /**
+     * Checks if the month-day is valid for this year.
+     * <p>
+     * This method checks whether this year and the input month and day form
+     * a valid date.
+     *
+     * @param monthDay  the month-day to validate, null returns false
+     * @return true if the month and day are valid for this year
+     */
+    public boolean isValidMonthDay(MonthDay monthDay) {
+        return monthDay != null && monthDay.isValidYear(year);
+    }
+
+    /**
+     * Gets the length of this year in days.
+     *
+     * @return the length of this year in days, 365 or 366
+     */
+    public int length() {
+        return isLeap() ? 366 : 365;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this year.
+     * <p>
+     * This returns a {@code Year}, based on this one, with the year adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code Year} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year with(TemporalAdjuster adjuster) {
+        return (Year) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this year with the specified field set to a new value.
+     * <p>
+     * This returns a {@code Year}, based on this one, with the value
+     * for the specified field changed.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code YEAR_OF_ERA} -
+     *  Returns a {@code Year} with the specified year-of-era
+     *  The era will be unchanged.
+     * <li>{@code YEAR} -
+     *  Returns a {@code Year} with the specified year.
+     *  This completely replaces the date and is equivalent to {@link #of(int)}.
+     * <li>{@code ERA} -
+     *  Returns a {@code Year} with the specified era.
+     *  The year-of-era will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code Year} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case YEAR_OF_ERA: return Year.of((int) (year < 1 ? 1 - newValue : newValue));
+                case YEAR: return Year.of((int) newValue);
+                case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year with the specified amount added.
+     * <p>
+     * This returns a {@code Year}, based on this one, with the specified amount added.
+     * The amount is typically {@link Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code Year} based on this year with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year plus(TemporalAmount amountToAdd) {
+        return (Year) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this year with the specified amount added.
+     * <p>
+     * This returns a {@code Year}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code YEARS} -
+     *  Returns a {@code Year} with the specified number of years added.
+     *  This is equivalent to {@link #plusYears(long)}.
+     * <li>{@code DECADES} -
+     *  Returns a {@code Year} with the specified number of decades added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 10.
+     * <li>{@code CENTURIES} -
+     *  Returns a {@code Year} with the specified number of centuries added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 100.
+     * <li>{@code MILLENNIA} -
+     *  Returns a {@code Year} with the specified number of millennia added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 1,000.
+     * <li>{@code ERAS} -
+     *  Returns a {@code Year} with the specified number of eras added.
+     *  Only two eras are supported so the amount must be one, zero or minus one.
+     *  If the amount is non-zero then the year is changed such that the year-of-era
+     *  is unchanged.
+     * </ul>
+     * <p>
+     * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return a {@code Year} based on this year with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    /**
+     * Returns a copy of this {@code Year} with the specified number of years added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a {@code Year} based on this year with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public Year plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        return of(YEAR.checkValidIntValue(year + yearsToAdd));  // overflow safe
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year with the specified amount subtracted.
+     * <p>
+     * This returns a {@code Year}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code Year} based on this year with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year minus(TemporalAmount amountToSubtract) {
+        return (Year) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this year with the specified amount subtracted.
+     * <p>
+     * This returns a {@code Year}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return a {@code Year} based on this year with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Year minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    /**
+     * Returns a copy of this {@code Year} with the specified number of years subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a {@code Year} based on this year with the year subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public Year minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this year using the specified query.
+     * <p>
+     * This queries this year using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.chronology()) {
+            return (R) IsoChronology.INSTANCE;
+        } else if (query == TemporalQueries.precision()) {
+            return (R) YEARS;
+        }
+        return Temporal.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this year.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the year changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#YEAR} as the field.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisYear.adjustInto(temporal);
+     *   temporal = temporal.with(thisYear);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        return temporal.with(YEAR, year);
+    }
+
+    /**
+     * Calculates the amount of time until another year in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code Year}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified year.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code Year} using {@link #from(TemporalAccessor)}.
+     * For example, the amount in decades between two year can be calculated
+     * using {@code startYear.until(endYear, DECADES)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two years.
+     * For example, the amount in decades between 2012 and 2031
+     * will only be one decade as it is one year short of two decades.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, YEARS);
+     *   amount = YEARS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code YEARS}, {@code DECADES}, {@code CENTURIES},
+     * {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to a {@code Year}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this year and the end year
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code Year}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        Year end = Year.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            long yearsUntil = ((long) end.year) - year;  // no overflow
+            switch ((ChronoUnit) unit) {
+                case YEARS: return yearsUntil;
+                case DECADES: return yearsUntil / 10;
+                case CENTURIES: return yearsUntil / 100;
+                case MILLENNIA: return yearsUntil / 1000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this year using the specified formatter.
+     * <p>
+     * This year will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted year string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this year with a day-of-year to create a {@code LocalDate}.
+     * <p>
+     * This returns a {@code LocalDate} formed from this year and the specified day-of-year.
+     * <p>
+     * The day-of-year value 366 is only valid in a leap year.
+     *
+     * @param dayOfYear  the day-of-year to use, from 1 to 365-366
+     * @return the local date formed from this year and the specified date of year, not null
+     * @throws DateTimeException if the day of year is zero or less, 366 or greater or equal
+     *  to 366 and this is not a leap year
+     */
+    public LocalDate atDay(int dayOfYear) {
+        return LocalDate.ofYearDay(year, dayOfYear);
+    }
+
+    /**
+     * Combines this year with a month to create a {@code YearMonth}.
+     * <p>
+     * This returns a {@code YearMonth} formed from this year and the specified month.
+     * All possible combinations of year and month are valid.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atDay(day);
+     * </pre>
+     *
+     * @param month  the month-of-year to use, not null
+     * @return the year-month formed from this year and the specified month, not null
+     */
+    public YearMonth atMonth(Month month) {
+        return YearMonth.of(year, month);
+    }
+
+    /**
+     * Combines this year with a month to create a {@code YearMonth}.
+     * <p>
+     * This returns a {@code YearMonth} formed from this year and the specified month.
+     * All possible combinations of year and month are valid.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atDay(day);
+     * </pre>
+     *
+     * @param month  the month-of-year to use, from 1 (January) to 12 (December)
+     * @return the year-month formed from this year and the specified month, not null
+     * @throws DateTimeException if the month is invalid
+     */
+    public YearMonth atMonth(int month) {
+        return YearMonth.of(year, month);
+    }
+
+    /**
+     * Combines this year with a month-day to create a {@code LocalDate}.
+     * <p>
+     * This returns a {@code LocalDate} formed from this year and the specified month-day.
+     * <p>
+     * A month-day of February 29th will be adjusted to February 28th in the resulting
+     * date if the year is not a leap year.
+     *
+     * @param monthDay  the month-day to use, not null
+     * @return the local date formed from this year and the specified month-day, not null
+     */
+    public LocalDate atMonthDay(MonthDay monthDay) {
+        return monthDay.atYear(year);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this year to another year.
+     * <p>
+     * The comparison is based on the value of the year.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other year to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(Year other) {
+        return year - other.year;
+    }
+
+    /**
+     * Checks if this year is after the specified year.
+     *
+     * @param other  the other year to compare to, not null
+     * @return true if this is after the specified year
+     */
+    public boolean isAfter(Year other) {
+        return year > other.year;
+    }
+
+    /**
+     * Checks if this year is before the specified year.
+     *
+     * @param other  the other year to compare to, not null
+     * @return true if this point is before the specified year
+     */
+    public boolean isBefore(Year other) {
+        return year < other.year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this year is equal to another year.
+     * <p>
+     * The comparison is based on the time-line position of the years.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other year
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof Year) {
+            return year == ((Year) obj).year;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this year.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return year;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this year as a {@code String}.
+     *
+     * @return a string representation of this year, not null
+     */
+    @Override
+    public String toString() {
+        return Integer.toString(year);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(11);  // identifies a Year
+     *  out.writeInt(year);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.YEAR_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(year);
+    }
+
+    static Year readExternal(DataInput in) throws IOException {
+        return Year.of(in.readInt());
+    }
+
+}
diff --git a/java/time/YearMonth.java b/java/time/YearMonth.java
new file mode 100644
index 0000000..582a9d8
--- /dev/null
+++ b/java/time/YearMonth.java
@@ -0,0 +1,1244 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.CENTURIES;
+import static java.time.temporal.ChronoUnit.DECADES;
+import static java.time.temporal.ChronoUnit.ERAS;
+import static java.time.temporal.ChronoUnit.MILLENNIA;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DateTimeParseException;
+import java.time.format.SignStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A year-month in the ISO-8601 calendar system, such as {@code 2007-12}.
+ * <p>
+ * {@code YearMonth} is an immutable date-time object that represents the combination
+ * of a year and month. Any field that can be derived from a year and month, such as
+ * quarter-of-year, can be obtained.
+ * <p>
+ * This class does not store or represent a day, time or time-zone.
+ * For example, the value "October 2007" can be stored in a {@code YearMonth}.
+ * <p>
+ * The ISO-8601 calendar system is the modern civil calendar system used today
+ * in most of the world. It is equivalent to the proleptic Gregorian calendar
+ * system, in which today's rules for leap years are applied for all time.
+ * For most applications written today, the ISO-8601 rules are entirely suitable.
+ * However, any application that makes use of historical dates, and requires them
+ * to be accurate will find the ISO-8601 approach unsuitable.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class YearMonth
+        implements Temporal, TemporalAdjuster, Comparable<YearMonth>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 4183400860270640070L;
+    /**
+     * Parser.
+     */
+    private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder()
+        .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+        .appendLiteral('-')
+        .appendValue(MONTH_OF_YEAR, 2)
+        .toFormatter();
+
+    /**
+     * The year.
+     */
+    private final int year;
+    /**
+     * The month-of-year, not null.
+     */
+    private final int month;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current year-month from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current year-month.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current year-month using the system clock and default time-zone, not null
+     */
+    public static YearMonth now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current year-month from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current year-month.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current year-month using the system clock, not null
+     */
+    public static YearMonth now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current year-month from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current year-month.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current year-month, not null
+     */
+    public static YearMonth now(Clock clock) {
+        final LocalDate now = LocalDate.now(clock);  // called once
+        return YearMonth.of(now.getYear(), now.getMonth());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code YearMonth} from a year and month.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, not null
+     * @return the year-month, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public static YearMonth of(int year, Month month) {
+        Objects.requireNonNull(month, "month");
+        return of(year, month.getValue());
+    }
+
+    /**
+     * Obtains an instance of {@code YearMonth} from a year and month.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @return the year-month, not null
+     * @throws DateTimeException if either field value is invalid
+     */
+    public static YearMonth of(int year, int month) {
+        YEAR.checkValidValue(year);
+        MONTH_OF_YEAR.checkValidValue(month);
+        return new YearMonth(year, month);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code YearMonth} from a temporal object.
+     * <p>
+     * This obtains a year-month based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code YearMonth}.
+     * <p>
+     * The conversion extracts the {@link ChronoField#YEAR YEAR} and
+     * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} fields.
+     * The extraction is only permitted if the temporal object has an ISO
+     * chronology, or can be converted to a {@code LocalDate}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code YearMonth::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the year-month, not null
+     * @throws DateTimeException if unable to convert to a {@code YearMonth}
+     */
+    public static YearMonth from(TemporalAccessor temporal) {
+        if (temporal instanceof YearMonth) {
+            return (YearMonth) temporal;
+        }
+        Objects.requireNonNull(temporal, "temporal");
+        try {
+            if (IsoChronology.INSTANCE.equals(Chronology.from(temporal)) == false) {
+                temporal = LocalDate.from(temporal);
+            }
+            return of(temporal.get(YEAR), temporal.get(MONTH_OF_YEAR));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code YearMonth} from a text string such as {@code 2007-12}.
+     * <p>
+     * The string must represent a valid year-month.
+     * The format must be {@code uuuu-MM}.
+     * Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol.
+     *
+     * @param text  the text to parse such as "2007-12", not null
+     * @return the parsed year-month, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static YearMonth parse(CharSequence text) {
+        return parse(text, PARSER);
+    }
+
+    /**
+     * Obtains an instance of {@code YearMonth} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a year-month.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed year-month, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static YearMonth parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, YearMonth::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param year  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, validated from 1 (January) to 12 (December)
+     */
+    private YearMonth(int year, int month) {
+        this.year = year;
+        this.month = month;
+    }
+
+    /**
+     * Returns a copy of this year-month with the new year and month, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newYear  the year to represent, validated from MIN_YEAR to MAX_YEAR
+     * @param newMonth  the month-of-year to represent, validated not null
+     * @return the year-month, not null
+     */
+    private YearMonth with(int newYear, int newMonth) {
+        if (year == newYear && month == newMonth) {
+            return this;
+        }
+        return new YearMonth(newYear, newMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this year-month can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code PROLEPTIC_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this year-month, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == YEAR || field == MONTH_OF_YEAR ||
+                    field == PROLEPTIC_MONTH || field == YEAR_OF_ERA || field == ERA;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this year-month.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code MONTHS}
+     * <li>{@code YEARS}
+     * <li>{@code DECADES}
+     * <li>{@code CENTURIES}
+     * <li>{@code MILLENNIA}
+     * <li>{@code ERAS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit == MONTHS || unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS;
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This year-month is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field == YEAR_OF_ERA) {
+            return (getYear() <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE));
+        }
+        return Temporal.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year-month as an {@code int}.
+     * <p>
+     * This queries this year-month for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year-month, except {@code PROLEPTIC_MONTH} which is too
+     * large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    public int get(TemporalField field) {
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this year-month as a {@code long}.
+     * <p>
+     * This queries this year-month for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this year-month.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case MONTH_OF_YEAR: return month;
+                case PROLEPTIC_MONTH: return getProlepticMonth();
+                case YEAR_OF_ERA: return (year < 1 ? 1 - year : year);
+                case YEAR: return year;
+                case ERA: return (year < 1 ? 0 : 1);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    private long getProlepticMonth() {
+        return (year * 12L + month - 1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return year;
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return month;
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return Month.of(month);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @return true if the year is leap, false otherwise
+     */
+    public boolean isLeapYear() {
+        return IsoChronology.INSTANCE.isLeapYear(year);
+    }
+
+    /**
+     * Checks if the day-of-month is valid for this year-month.
+     * <p>
+     * This method checks whether this year and month and the input day form
+     * a valid date.
+     *
+     * @param dayOfMonth  the day-of-month to validate, from 1 to 31, invalid value returns false
+     * @return true if the day is valid for this year-month
+     */
+    public boolean isValidDay(int dayOfMonth) {
+        return dayOfMonth >= 1 && dayOfMonth <= lengthOfMonth();
+    }
+
+    /**
+     * Returns the length of the month, taking account of the year.
+     * <p>
+     * This returns the length of the month in days.
+     * For example, a date in January would return 31.
+     *
+     * @return the length of the month in days, from 28 to 31
+     */
+    public int lengthOfMonth() {
+        return getMonth().length(isLeapYear());
+    }
+
+    /**
+     * Returns the length of the year.
+     * <p>
+     * This returns the length of the year in days, either 365 or 366.
+     *
+     * @return 366 if the year is leap, 365 otherwise
+     */
+    public int lengthOfYear() {
+        return (isLeapYear() ? 366 : 365);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this year-month.
+     * <p>
+     * This returns a {@code YearMonth}, based on this one, with the year-month adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the year-month to the next month that
+     * Halley's comet will pass the Earth.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code YearMonth} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth with(TemporalAdjuster adjuster) {
+        return (YearMonth) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified field set to a new value.
+     * <p>
+     * This returns a {@code YearMonth}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year or month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code MONTH_OF_YEAR} -
+     *  Returns a {@code YearMonth} with the specified month-of-year.
+     *  The year will be unchanged.
+     * <li>{@code PROLEPTIC_MONTH} -
+     *  Returns a {@code YearMonth} with the specified proleptic-month.
+     *  This completely replaces the year and month of this object.
+     * <li>{@code YEAR_OF_ERA} -
+     *  Returns a {@code YearMonth} with the specified year-of-era
+     *  The month and era will be unchanged.
+     * <li>{@code YEAR} -
+     *  Returns a {@code YearMonth} with the specified year.
+     *  The month will be unchanged.
+     * <li>{@code ERA} -
+     *  Returns a {@code YearMonth} with the specified era.
+     *  The month and year-of-era will be unchanged.
+     * </ul>
+     * <p>
+     * In all cases, if the new value is outside the valid range of values for the field
+     * then a {@code DateTimeException} will be thrown.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code YearMonth} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            f.checkValidValue(newValue);
+            switch (f) {
+                case MONTH_OF_YEAR: return withMonth((int) newValue);
+                case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
+                case YEAR_OF_ERA: return withYear((int) (year < 1 ? 1 - newValue : newValue));
+                case YEAR: return withYear((int) newValue);
+                case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code YearMonth} with the year altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the returned year-month, from MIN_YEAR to MAX_YEAR
+     * @return a {@code YearMonth} based on this year-month with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public YearMonth withYear(int year) {
+        YEAR.checkValidValue(year);
+        return with(year, month);
+    }
+
+    /**
+     * Returns a copy of this {@code YearMonth} with the month-of-year altered.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the returned year-month, from 1 (January) to 12 (December)
+     * @return a {@code YearMonth} based on this year-month with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public YearMonth withMonth(int month) {
+        MONTH_OF_YEAR.checkValidValue(month);
+        return with(year, month);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year-month with the specified amount added.
+     * <p>
+     * This returns a {@code YearMonth}, based on this one, with the specified amount added.
+     * The amount is typically {@link Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code YearMonth} based on this year-month with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth plus(TemporalAmount amountToAdd) {
+        return (YearMonth) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified amount added.
+     * <p>
+     * This returns a {@code YearMonth}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * The supported fields behave as follows:
+     * <ul>
+     * <li>{@code MONTHS} -
+     *  Returns a {@code YearMonth} with the specified number of months added.
+     *  This is equivalent to {@link #plusMonths(long)}.
+     * <li>{@code YEARS} -
+     *  Returns a {@code YearMonth} with the specified number of years added.
+     *  This is equivalent to {@link #plusYears(long)}.
+     * <li>{@code DECADES} -
+     *  Returns a {@code YearMonth} with the specified number of decades added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 10.
+     * <li>{@code CENTURIES} -
+     *  Returns a {@code YearMonth} with the specified number of centuries added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 100.
+     * <li>{@code MILLENNIA} -
+     *  Returns a {@code YearMonth} with the specified number of millennia added.
+     *  This is equivalent to calling {@link #plusYears(long)} with the amount
+     *  multiplied by 1,000.
+     * <li>{@code ERAS} -
+     *  Returns a {@code YearMonth} with the specified number of eras added.
+     *  Only two eras are supported so the amount must be one, zero or minus one.
+     *  If the amount is non-zero then the year is changed such that the year-of-era
+     *  is unchanged.
+     * </ul>
+     * <p>
+     * All other {@code ChronoUnit} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return a {@code YearMonth} based on this year-month with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    /**
+     * Returns a copy of this {@code YearMonth} with the specified number of years added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a {@code YearMonth} based on this year-month with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth plusYears(long yearsToAdd) {
+        if (yearsToAdd == 0) {
+            return this;
+        }
+        int newYear = YEAR.checkValidIntValue(year + yearsToAdd);  // safe overflow
+        return with(newYear, month);
+    }
+
+    /**
+     * Returns a copy of this {@code YearMonth} with the specified number of months added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, may be negative
+     * @return a {@code YearMonth} based on this year-month with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
+            return this;
+        }
+        long monthCount = year * 12L + (month - 1);
+        long calcMonths = monthCount + monthsToAdd;  // safe overflow
+        int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcMonths, 12));
+        int newMonth = (int)Math.floorMod(calcMonths, 12) + 1;
+        return with(newYear, newMonth);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this year-month with the specified amount subtracted.
+     * <p>
+     * This returns a {@code YearMonth}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code YearMonth} based on this year-month with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth minus(TemporalAmount amountToSubtract) {
+        return (YearMonth) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this year-month with the specified amount subtracted.
+     * <p>
+     * This returns a {@code YearMonth}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return a {@code YearMonth} based on this year-month with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public YearMonth minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    /**
+     * Returns a copy of this {@code YearMonth} with the specified number of years subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a {@code YearMonth} based on this year-month with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this {@code YearMonth} with the specified number of months subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the months to subtract, may be negative
+     * @return a {@code YearMonth} based on this year-month with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public YearMonth minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this year-month using the specified query.
+     * <p>
+     * This queries this year-month using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.chronology()) {
+            return (R) IsoChronology.INSTANCE;
+        } else if (query == TemporalQueries.precision()) {
+            return (R) MONTHS;
+        }
+        return Temporal.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have this year-month.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the year and month changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#PROLEPTIC_MONTH} as the field.
+     * If the specified temporal object does not use the ISO calendar system then
+     * a {@code DateTimeException} is thrown.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisYearMonth.adjustInto(temporal);
+     *   temporal = temporal.with(thisYearMonth);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        if (Chronology.from(temporal).equals(IsoChronology.INSTANCE) == false) {
+            throw new DateTimeException("Adjustment only supported on ISO date-time");
+        }
+        return temporal.with(PROLEPTIC_MONTH, getProlepticMonth());
+    }
+
+    /**
+     * Calculates the amount of time until another year-month in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code YearMonth}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified year-month.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code YearMonth} using {@link #from(TemporalAccessor)}.
+     * For example, the amount in years between two year-months can be calculated
+     * using {@code startYearMonth.until(endYearMonth, YEARS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two year-months.
+     * For example, the amount in decades between 2012-06 and 2032-05
+     * will only be one decade as it is one month short of two decades.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MONTHS);
+     *   amount = MONTHS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to a {@code YearMonth}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this year-month and the end year-month
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code YearMonth}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        YearMonth end = YearMonth.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            long monthsUntil = end.getProlepticMonth() - getProlepticMonth();  // no overflow
+            switch ((ChronoUnit) unit) {
+                case MONTHS: return monthsUntil;
+                case YEARS: return monthsUntil / 12;
+                case DECADES: return monthsUntil / 120;
+                case CENTURIES: return monthsUntil / 1200;
+                case MILLENNIA: return monthsUntil / 12000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this year-month using the specified formatter.
+     * <p>
+     * This year-month will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted year-month string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this year-month with a day-of-month to create a {@code LocalDate}.
+     * <p>
+     * This returns a {@code LocalDate} formed from this year-month and the specified day-of-month.
+     * <p>
+     * The day-of-month value must be valid for the year-month.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atDay(day);
+     * </pre>
+     *
+     * @param dayOfMonth  the day-of-month to use, from 1 to 31
+     * @return the date formed from this year-month and the specified day, not null
+     * @throws DateTimeException if the day is invalid for the year-month
+     * @see #isValidDay(int)
+     */
+    public LocalDate atDay(int dayOfMonth) {
+        return LocalDate.of(year, month, dayOfMonth);
+    }
+
+    /**
+     * Returns a {@code LocalDate} at the end of the month.
+     * <p>
+     * This returns a {@code LocalDate} based on this year-month.
+     * The day-of-month is set to the last valid day of the month, taking
+     * into account leap years.
+     * <p>
+     * This method can be used as part of a chain to produce a date:
+     * <pre>
+     *  LocalDate date = year.atMonth(month).atEndOfMonth();
+     * </pre>
+     *
+     * @return the last valid date of this year-month, not null
+     */
+    public LocalDate atEndOfMonth() {
+        return LocalDate.of(year, month, lengthOfMonth());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this year-month to another year-month.
+     * <p>
+     * The comparison is based first on the value of the year, then on the value of the month.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other year-month to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(YearMonth other) {
+        int cmp = (year - other.year);
+        if (cmp == 0) {
+            cmp = (month - other.month);
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this year-month is after the specified year-month.
+     *
+     * @param other  the other year-month to compare to, not null
+     * @return true if this is after the specified year-month
+     */
+    public boolean isAfter(YearMonth other) {
+        return compareTo(other) > 0;
+    }
+
+    /**
+     * Checks if this year-month is before the specified year-month.
+     *
+     * @param other  the other year-month to compare to, not null
+     * @return true if this point is before the specified year-month
+     */
+    public boolean isBefore(YearMonth other) {
+        return compareTo(other) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this year-month is equal to another year-month.
+     * <p>
+     * The comparison is based on the time-line position of the year-months.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other year-month
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof YearMonth) {
+            YearMonth other = (YearMonth) obj;
+            return year == other.year && month == other.month;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this year-month.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return year ^ (month << 27);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this year-month as a {@code String}, such as {@code 2007-12}.
+     * <p>
+     * The output will be in the format {@code uuuu-MM}:
+     *
+     * @return a string representation of this year-month, not null
+     */
+    @Override
+    public String toString() {
+        int absYear = Math.abs(year);
+        StringBuilder buf = new StringBuilder(9);
+        if (absYear < 1000) {
+            if (year < 0) {
+                buf.append(year - 10000).deleteCharAt(1);
+            } else {
+                buf.append(year + 10000).deleteCharAt(0);
+            }
+        } else {
+            buf.append(year);
+        }
+        return buf.append(month < 10 ? "-0" : "-")
+            .append(month)
+            .toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(12);  // identifies a YearMonth
+     *  out.writeInt(year);
+     *  out.writeByte(month);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.YEAR_MONTH_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(year);
+        out.writeByte(month);
+    }
+
+    static YearMonth readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        byte month = in.readByte();
+        return YearMonth.of(year, month);
+    }
+
+}
diff --git a/java/time/ZoneId.java b/java/time/ZoneId.java
new file mode 100644
index 0000000..11e34e0
--- /dev/null
+++ b/java/time/ZoneId.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesException;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TimeZone;
+
+// Android-changed: removed ValueBased paragraph.
+// Android-changed: removed {@link ZoneRulesProvider}.
+/**
+ * A time-zone ID, such as {@code Europe/Paris}.
+ * <p>
+ * A {@code ZoneId} is used to identify the rules used to convert between
+ * an {@link Instant} and a {@link LocalDateTime}.
+ * There are two distinct types of ID:
+ * <ul>
+ * <li>Fixed offsets - a fully resolved offset from UTC/Greenwich, that uses
+ *  the same offset for all local date-times
+ * <li>Geographical regions - an area where a specific set of rules for finding
+ *  the offset from UTC/Greenwich apply
+ * </ul>
+ * Most fixed offsets are represented by {@link ZoneOffset}.
+ * Calling {@link #normalized()} on any {@code ZoneId} will ensure that a
+ * fixed offset ID will be represented as a {@code ZoneOffset}.
+ * <p>
+ * The actual rules, describing when and how the offset changes, are defined by {@link ZoneRules}.
+ * This class is simply an ID used to obtain the underlying rules.
+ * This approach is taken because rules are defined by governments and change
+ * frequently, whereas the ID is stable.
+ * <p>
+ * The distinction has other effects. Serializing the {@code ZoneId} will only send
+ * the ID, whereas serializing the rules sends the entire data set.
+ * Similarly, a comparison of two IDs only examines the ID, whereas
+ * a comparison of two rules examines the entire data set.
+ *
+ * <h3>Time-zone IDs</h3>
+ * The ID is unique within the system.
+ * There are three types of ID.
+ * <p>
+ * The simplest type of ID is that from {@code ZoneOffset}.
+ * This consists of 'Z' and IDs starting with '+' or '-'.
+ * <p>
+ * The next type of ID are offset-style IDs with some form of prefix,
+ * such as 'GMT+2' or 'UTC+01:00'.
+ * The recognised prefixes are 'UTC', 'GMT' and 'UT'.
+ * The offset is the suffix and will be normalized during creation.
+ * These IDs can be normalized to a {@code ZoneOffset} using {@code normalized()}.
+ * <p>
+ * The third type of ID are region-based IDs. A region-based ID must be of
+ * two or more characters, and not start with 'UTC', 'GMT', 'UT' '+' or '-'.
+ * Region-based IDs are defined by configuration.
+ * The configuration focuses on providing the lookup from the ID to the
+ * underlying {@code ZoneRules}.
+ * <p>
+ * Time-zone rules are defined by governments and change frequently.
+ * There are a number of organizations, known here as groups, that monitor
+ * time-zone changes and collate them.
+ * The default group is the IANA Time Zone Database (TZDB).
+ * Other organizations include IATA (the airline industry body) and Microsoft.
+ * <p>
+ * Each group defines its own format for the region ID it provides.
+ * The TZDB group defines IDs such as 'Europe/London' or 'America/New_York'.
+ * TZDB IDs take precedence over other groups.
+ * <p>
+ * It is strongly recommended that the group name is included in all IDs supplied by
+ * groups other than TZDB to avoid conflicts. For example, IATA airline time-zone
+ * region IDs are typically the same as the three letter airport code.
+ * However, the airport of Utrecht has the code 'UTC', which is obviously a conflict.
+ * The recommended format for region IDs from groups other than TZDB is 'group~region'.
+ * Thus if IATA data were defined, Utrecht airport would be 'IATA~UTC'.
+ *
+ * <h3>Serialization</h3>
+ * This class can be serialized and stores the string zone ID in the external form.
+ * The {@code ZoneOffset} subclass uses a dedicated format that only stores the
+ * offset from UTC/Greenwich.
+ * <p>
+ * A {@code ZoneId} can be deserialized in a Java Runtime where the ID is unknown.
+ * For example, if a server-side Java Runtime has been updated with a new zone ID, but
+ * the client-side Java Runtime has not been updated. In this case, the {@code ZoneId}
+ * object will exist, and can be queried using {@code getId}, {@code equals},
+ * {@code hashCode}, {@code toString}, {@code getDisplayName} and {@code normalized}.
+ * However, any call to {@code getRules} will fail with {@code ZoneRulesException}.
+ * This approach is designed to allow a {@link ZonedDateTime} to be loaded and
+ * queried, but not modified, on a Java Runtime with incomplete time-zone information.
+ *
+ * @implSpec
+ * This abstract class has two implementations, both of which are immutable and thread-safe.
+ * One implementation models region-based IDs, the other is {@code ZoneOffset} modelling
+ * offset-based IDs. This difference is visible in serialization.
+ *
+ * @since 1.8
+ */
+public abstract class ZoneId implements Serializable {
+
+    /**
+     * A map of zone overrides to enable the short time-zone names to be used.
+     * <p>
+     * Use of short zone IDs has been deprecated in {@code java.util.TimeZone}.
+     * This map allows the IDs to continue to be used via the
+     * {@link #of(String, Map)} factory method.
+     * <p>
+     * This map contains a mapping of the IDs that is in line with TZDB 2005r and
+     * later, where 'EST', 'MST' and 'HST' map to IDs which do not include daylight
+     * savings.
+     * <p>
+     * This maps as follows:
+     * <ul>
+     * <li>EST - -05:00</li>
+     * <li>HST - -10:00</li>
+     * <li>MST - -07:00</li>
+     * <li>ACT - Australia/Darwin</li>
+     * <li>AET - Australia/Sydney</li>
+     * <li>AGT - America/Argentina/Buenos_Aires</li>
+     * <li>ART - Africa/Cairo</li>
+     * <li>AST - America/Anchorage</li>
+     * <li>BET - America/Sao_Paulo</li>
+     * <li>BST - Asia/Dhaka</li>
+     * <li>CAT - Africa/Harare</li>
+     * <li>CNT - America/St_Johns</li>
+     * <li>CST - America/Chicago</li>
+     * <li>CTT - Asia/Shanghai</li>
+     * <li>EAT - Africa/Addis_Ababa</li>
+     * <li>ECT - Europe/Paris</li>
+     * <li>IET - America/Indiana/Indianapolis</li>
+     * <li>IST - Asia/Kolkata</li>
+     * <li>JST - Asia/Tokyo</li>
+     * <li>MIT - Pacific/Apia</li>
+     * <li>NET - Asia/Yerevan</li>
+     * <li>NST - Pacific/Auckland</li>
+     * <li>PLT - Asia/Karachi</li>
+     * <li>PNT - America/Phoenix</li>
+     * <li>PRT - America/Puerto_Rico</li>
+     * <li>PST - America/Los_Angeles</li>
+     * <li>SST - Pacific/Guadalcanal</li>
+     * <li>VST - Asia/Ho_Chi_Minh</li>
+     * </ul>
+     * The map is unmodifiable.
+     */
+    public static final Map<String, String> SHORT_IDS;
+    static {
+        Map<String, String> map = new HashMap<>(64);
+        map.put("ACT", "Australia/Darwin");
+        map.put("AET", "Australia/Sydney");
+        map.put("AGT", "America/Argentina/Buenos_Aires");
+        map.put("ART", "Africa/Cairo");
+        map.put("AST", "America/Anchorage");
+        map.put("BET", "America/Sao_Paulo");
+        map.put("BST", "Asia/Dhaka");
+        map.put("CAT", "Africa/Harare");
+        map.put("CNT", "America/St_Johns");
+        map.put("CST", "America/Chicago");
+        map.put("CTT", "Asia/Shanghai");
+        map.put("EAT", "Africa/Addis_Ababa");
+        map.put("ECT", "Europe/Paris");
+        map.put("IET", "America/Indiana/Indianapolis");
+        map.put("IST", "Asia/Kolkata");
+        map.put("JST", "Asia/Tokyo");
+        map.put("MIT", "Pacific/Apia");
+        map.put("NET", "Asia/Yerevan");
+        map.put("NST", "Pacific/Auckland");
+        map.put("PLT", "Asia/Karachi");
+        map.put("PNT", "America/Phoenix");
+        map.put("PRT", "America/Puerto_Rico");
+        map.put("PST", "America/Los_Angeles");
+        map.put("SST", "Pacific/Guadalcanal");
+        map.put("VST", "Asia/Ho_Chi_Minh");
+        map.put("EST", "-05:00");
+        map.put("MST", "-07:00");
+        map.put("HST", "-10:00");
+        SHORT_IDS = Collections.unmodifiableMap(map);
+    }
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 8352817235686L;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the system default time-zone.
+     * <p>
+     * This queries {@link TimeZone#getDefault()} to find the default time-zone
+     * and converts it to a {@code ZoneId}. If the system default time-zone is changed,
+     * then the result of this method will also change.
+     *
+     * @return the zone ID, not null
+     * @throws DateTimeException if the converted zone ID has an invalid format
+     * @throws ZoneRulesException if the converted zone region ID cannot be found
+     */
+    public static ZoneId systemDefault() {
+        return TimeZone.getDefault().toZoneId();
+    }
+
+    /**
+     * Gets the set of available zone IDs.
+     * <p>
+     * This set includes the string form of all available region-based IDs.
+     * Offset-based zone IDs are not included in the returned set.
+     * The ID can be passed to {@link #of(String)} to create a {@code ZoneId}.
+     * <p>
+     * The set of zone IDs can increase over time, although in a typical application
+     * the set of IDs is fixed. Each call to this method is thread-safe.
+     *
+     * @return a modifiable copy of the set of zone IDs, not null
+     */
+    public static Set<String> getAvailableZoneIds() {
+        return ZoneRulesProvider.getAvailableZoneIds();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneId} using its ID using a map
+     * of aliases to supplement the standard zone IDs.
+     * <p>
+     * Many users of time-zones use short abbreviations, such as PST for
+     * 'Pacific Standard Time' and PDT for 'Pacific Daylight Time'.
+     * These abbreviations are not unique, and so cannot be used as IDs.
+     * This method allows a map of string to time-zone to be setup and reused
+     * within an application.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @param aliasMap  a map of alias zone IDs (typically abbreviations) to real zone IDs, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if the zone ID has an invalid format
+     * @throws ZoneRulesException if the zone ID is a region ID that cannot be found
+     */
+    public static ZoneId of(String zoneId, Map<String, String> aliasMap) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        Objects.requireNonNull(aliasMap, "aliasMap");
+        String id = aliasMap.get(zoneId);
+        id = (id != null ? id : zoneId);
+        return of(id);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneId} from an ID ensuring that the
+     * ID is valid and available for use.
+     * <p>
+     * This method parses the ID producing a {@code ZoneId} or {@code ZoneOffset}.
+     * A {@code ZoneOffset} is returned if the ID is 'Z', or starts with '+' or '-'.
+     * The result will always be a valid ID for which {@link ZoneRules} can be obtained.
+     * <p>
+     * Parsing matches the zone ID step by step as follows.
+     * <ul>
+     * <li>If the zone ID equals 'Z', the result is {@code ZoneOffset.UTC}.
+     * <li>If the zone ID consists of a single letter, the zone ID is invalid
+     *  and {@code DateTimeException} is thrown.
+     * <li>If the zone ID starts with '+' or '-', the ID is parsed as a
+     *  {@code ZoneOffset} using {@link ZoneOffset#of(String)}.
+     * <li>If the zone ID equals 'GMT', 'UTC' or 'UT' then the result is a {@code ZoneId}
+     *  with the same ID and rules equivalent to {@code ZoneOffset.UTC}.
+     * <li>If the zone ID starts with 'UTC+', 'UTC-', 'GMT+', 'GMT-', 'UT+' or 'UT-'
+     *  then the ID is a prefixed offset-based ID. The ID is split in two, with
+     *  a two or three letter prefix and a suffix starting with the sign.
+     *  The suffix is parsed as a {@link ZoneOffset#of(String) ZoneOffset}.
+     *  The result will be a {@code ZoneId} with the specified UTC/GMT/UT prefix
+     *  and the normalized offset ID as per {@link ZoneOffset#getId()}.
+     *  The rules of the returned {@code ZoneId} will be equivalent to the
+     *  parsed {@code ZoneOffset}.
+     * <li>All other IDs are parsed as region-based zone IDs. Region IDs must
+     *  match the regular expression <code>[A-Za-z][A-Za-z0-9~/._+-]+</code>
+     *  otherwise a {@code DateTimeException} is thrown. If the zone ID is not
+     *  in the configured set of IDs, {@code ZoneRulesException} is thrown.
+     *  The detailed format of the region ID depends on the group supplying the data.
+     *  The default set of data is supplied by the IANA Time Zone Database (TZDB).
+     *  This has region IDs of the form '{area}/{city}', such as 'Europe/Paris' or 'America/New_York'.
+     *  This is compatible with most IDs from {@link java.util.TimeZone}.
+     * </ul>
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if the zone ID has an invalid format
+     * @throws ZoneRulesException if the zone ID is a region ID that cannot be found
+     */
+    public static ZoneId of(String zoneId) {
+        return of(zoneId, true);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneId} wrapping an offset.
+     * <p>
+     * If the prefix is "GMT", "UTC", or "UT" a {@code ZoneId}
+     * with the prefix and the non-zero offset is returned.
+     * If the prefix is empty {@code ""} the {@code ZoneOffset} is returned.
+     *
+     * @param prefix  the time-zone ID, not null
+     * @param offset  the offset, not null
+     * @return the zone ID, not null
+     * @throws IllegalArgumentException if the prefix is not one of
+     *     "GMT", "UTC", or "UT", or ""
+     */
+    public static ZoneId ofOffset(String prefix, ZoneOffset offset) {
+        Objects.requireNonNull(prefix, "prefix");
+        Objects.requireNonNull(offset, "offset");
+        if (prefix.length() == 0) {
+            return offset;
+        }
+
+        if (!prefix.equals("GMT") && !prefix.equals("UTC") && !prefix.equals("UT")) {
+             throw new IllegalArgumentException("prefix should be GMT, UTC or UT, is: " + prefix);
+        }
+
+        if (offset.getTotalSeconds() != 0) {
+            prefix = prefix.concat(offset.getId());
+        }
+        return new ZoneRegion(prefix, offset.getRules());
+    }
+
+    /**
+     * Parses the ID, taking a flag to indicate whether {@code ZoneRulesException}
+     * should be thrown or not, used in deserialization.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @param checkAvailable  whether to check if the zone ID is available
+     * @return the zone ID, not null
+     * @throws DateTimeException if the ID format is invalid
+     * @throws ZoneRulesException if checking availability and the ID cannot be found
+     */
+    static ZoneId of(String zoneId, boolean checkAvailable) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        if (zoneId.length() <= 1 || zoneId.startsWith("+") || zoneId.startsWith("-")) {
+            return ZoneOffset.of(zoneId);
+        } else if (zoneId.startsWith("UTC") || zoneId.startsWith("GMT")) {
+            return ofWithPrefix(zoneId, 3, checkAvailable);
+        } else if (zoneId.startsWith("UT")) {
+            return ofWithPrefix(zoneId, 2, checkAvailable);
+        }
+        return ZoneRegion.ofId(zoneId, checkAvailable);
+    }
+
+    /**
+     * Parse once a prefix is established.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @param prefixLength  the length of the prefix, 2 or 3
+     * @return the zone ID, not null
+     * @throws DateTimeException if the zone ID has an invalid format
+     */
+    private static ZoneId ofWithPrefix(String zoneId, int prefixLength, boolean checkAvailable) {
+        String prefix = zoneId.substring(0, prefixLength);
+        if (zoneId.length() == prefixLength) {
+            return ofOffset(prefix, ZoneOffset.UTC);
+        }
+        if (zoneId.charAt(prefixLength) != '+' && zoneId.charAt(prefixLength) != '-') {
+            return ZoneRegion.ofId(zoneId, checkAvailable);  // drop through to ZoneRulesProvider
+        }
+        try {
+            ZoneOffset offset = ZoneOffset.of(zoneId.substring(prefixLength));
+            if (offset == ZoneOffset.UTC) {
+                return ofOffset(prefix, offset);
+            }
+            return ofOffset(prefix, offset);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneId} from a temporal object.
+     * <p>
+     * This obtains a zone based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ZoneId}.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code ZoneId}.
+     * <p>
+     * The conversion will try to obtain the zone in a way that favours region-based
+     * zones over offset-based zones using {@link TemporalQueries#zone()}.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ZoneId::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zone ID, not null
+     * @throws DateTimeException if unable to convert to a {@code ZoneId}
+     */
+    public static ZoneId from(TemporalAccessor temporal) {
+        ZoneId obj = temporal.query(TemporalQueries.zone());
+        if (obj == null) {
+            throw new DateTimeException("Unable to obtain ZoneId from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
+        }
+        return obj;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor only accessible within the package.
+     */
+    ZoneId() {
+        if (getClass() != ZoneOffset.class && getClass() != ZoneRegion.class) {
+            throw new AssertionError("Invalid subclass");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the unique time-zone ID.
+     * <p>
+     * This ID uniquely defines this object.
+     * The format of an offset based ID is defined by {@link ZoneOffset#getId()}.
+     *
+     * @return the time-zone unique ID, not null
+     */
+    public abstract String getId();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation of the zone, such as 'British Time' or
+     * '+02:00'.
+     * <p>
+     * This returns the textual name used to identify the time-zone ID,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getId() full ID} is returned.
+     *
+     * @param style  the length of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the zone, not null
+     */
+    public String getDisplayName(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendZoneText(style).toFormatter(locale).format(toTemporal());
+    }
+
+    /**
+     * Converts this zone to a {@code TemporalAccessor}.
+     * <p>
+     * A {@code ZoneId} can be fully represented as a {@code TemporalAccessor}.
+     * However, the interface is not implemented by this class as most of the
+     * methods on the interface have no meaning to {@code ZoneId}.
+     * <p>
+     * The returned temporal has no supported fields, with the query method
+     * supporting the return of the zone using {@link TemporalQueries#zoneId()}.
+     *
+     * @return a temporal equivalent to this zone, not null
+     */
+    private TemporalAccessor toTemporal() {
+        return new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return false;
+            }
+            @Override
+            public long getLong(TemporalField field) {
+                throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == TemporalQueries.zoneId()) {
+                    return (R) ZoneId.this;
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    // Android-removed: ZoneRulesProvider related paragraph
+    /**
+     * Gets the time-zone rules for this ID allowing calculations to be performed.
+     * <p>
+     * The rules provide the functionality associated with a time-zone,
+     * such as finding the offset for a given instant or local date-time.
+     * <p>
+     * A time-zone can be invalid if it is deserialized in a Java Runtime which
+     * does not have the same rules loaded as the Java Runtime that stored it.
+     * In this case, calling this method will throw a {@code ZoneRulesException}.
+     * <p>
+     * {@link ZoneOffset} will always return a set of rules where the offset never changes.
+     *
+     * @return the rules, not null
+     * @throws ZoneRulesException if no rules are available for this ID
+     */
+    public abstract ZoneRules getRules();
+
+    /**
+     * Normalizes the time-zone ID, returning a {@code ZoneOffset} where possible.
+     * <p>
+     * The returns a normalized {@code ZoneId} that can be used in place of this ID.
+     * The result will have {@code ZoneRules} equivalent to those returned by this object,
+     * however the ID returned by {@code getId()} may be different.
+     * <p>
+     * The normalization checks if the rules of this {@code ZoneId} have a fixed offset.
+     * If they do, then the {@code ZoneOffset} equal to that offset is returned.
+     * Otherwise {@code this} is returned.
+     *
+     * @return the time-zone unique ID, not null
+     */
+    public ZoneId normalized() {
+        try {
+            ZoneRules rules = getRules();
+            if (rules.isFixedOffset()) {
+                return rules.getOffset(Instant.EPOCH);
+            }
+        } catch (ZoneRulesException ex) {
+            // invalid ZoneRegion is not important to this method
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this time-zone ID is equal to another time-zone ID.
+     * <p>
+     * The comparison is based on the ID.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other time-zone ID
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof ZoneId) {
+            ZoneId other = (ZoneId) obj;
+            return getId().equals(other.getId());
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this time-zone ID.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Outputs this zone as a {@code String}, using the ID.
+     *
+     * @return a string representation of this time-zone ID, not null
+     */
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(7);  // identifies a ZoneId (not ZoneOffset)
+     *  out.writeUTF(getId());
+     * </pre>
+     * <p>
+     * When read back in, the {@code ZoneId} will be created as though using
+     * {@link #of(String)}, but without any exception in the case where the
+     * ID has a valid format, but is not in the known set of region-based IDs.
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    // this is here for serialization Javadoc
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_REGION_TYPE, this);
+    }
+
+    abstract void write(DataOutput out) throws IOException;
+
+}
diff --git a/java/time/ZoneOffset.java b/java/time/ZoneOffset.java
new file mode 100644
index 0000000..4dfb94d
--- /dev/null
+++ b/java/time/ZoneOffset.java
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.LocalTime.MINUTES_PER_HOUR;
+import static java.time.LocalTime.SECONDS_PER_HOUR;
+import static java.time.LocalTime.SECONDS_PER_MINUTE;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneRules;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A time-zone offset from Greenwich/UTC, such as {@code +02:00}.
+ * <p>
+ * A time-zone offset is the amount of time that a time-zone differs from Greenwich/UTC.
+ * This is usually a fixed number of hours and minutes.
+ * <p>
+ * Different parts of the world have different time-zone offsets.
+ * The rules for how offsets vary by place and time of year are captured in the
+ * {@link ZoneId} class.
+ * <p>
+ * For example, Paris is one hour ahead of Greenwich/UTC in winter and two hours
+ * ahead in summer. The {@code ZoneId} instance for Paris will reference two
+ * {@code ZoneOffset} instances - a {@code +01:00} instance for winter,
+ * and a {@code +02:00} instance for summer.
+ * <p>
+ * In 2008, time-zone offsets around the world extended from -12:00 to +14:00.
+ * To prevent any problems with that range being extended, yet still provide
+ * validation, the range of offsets is restricted to -18:00 to 18:00 inclusive.
+ * <p>
+ * This class is designed for use with the ISO calendar system.
+ * The fields of hours, minutes and seconds make assumptions that are valid for the
+ * standard ISO definitions of those fields. This class may be used with other
+ * calendar systems providing the definition of the time fields matches those
+ * of the ISO calendar system.
+ * <p>
+ * Instances of {@code ZoneOffset} must be compared using {@link #equals}.
+ * Implementations may choose to cache certain common offsets, however
+ * applications must not rely on such caching.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffset
+        extends ZoneId
+        implements TemporalAccessor, TemporalAdjuster, Comparable<ZoneOffset>, Serializable {
+
+    /** Cache of time-zone offset by offset in seconds. */
+    private static final ConcurrentMap<Integer, ZoneOffset> SECONDS_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
+    /** Cache of time-zone offset by ID. */
+    private static final ConcurrentMap<String, ZoneOffset> ID_CACHE = new ConcurrentHashMap<>(16, 0.75f, 4);
+
+    /**
+     * The abs maximum seconds.
+     */
+    private static final int MAX_SECONDS = 18 * SECONDS_PER_HOUR;
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2357656521762053153L;
+
+    /**
+     * The time-zone offset for UTC, with an ID of 'Z'.
+     */
+    public static final ZoneOffset UTC = ZoneOffset.ofTotalSeconds(0);
+    /**
+     * Constant for the maximum supported offset.
+     */
+    public static final ZoneOffset MIN = ZoneOffset.ofTotalSeconds(-MAX_SECONDS);
+    /**
+     * Constant for the maximum supported offset.
+     */
+    public static final ZoneOffset MAX = ZoneOffset.ofTotalSeconds(MAX_SECONDS);
+
+    /**
+     * The total offset in seconds.
+     */
+    private final int totalSeconds;
+    /**
+     * The string form of the time-zone offset.
+     */
+    private final transient String id;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} using the ID.
+     * <p>
+     * This method parses the string ID of a {@code ZoneOffset} to
+     * return an instance. The parsing accepts all the formats generated by
+     * {@link #getId()}, plus some additional formats:
+     * <ul>
+     * <li>{@code Z} - for UTC
+     * <li>{@code +h}
+     * <li>{@code +hh}
+     * <li>{@code +hh:mm}
+     * <li>{@code -hh:mm}
+     * <li>{@code +hhmm}
+     * <li>{@code -hhmm}
+     * <li>{@code +hh:mm:ss}
+     * <li>{@code -hh:mm:ss}
+     * <li>{@code +hhmmss}
+     * <li>{@code -hhmmss}
+     * </ul>
+     * Note that &plusmn; means either the plus or minus symbol.
+     * <p>
+     * The ID of the returned offset will be normalized to one of the formats
+     * described by {@link #getId()}.
+     * <p>
+     * The maximum supported range is from +18:00 to -18:00 inclusive.
+     *
+     * @param offsetId  the offset ID, not null
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset ID is invalid
+     */
+    @SuppressWarnings("fallthrough")
+    public static ZoneOffset of(String offsetId) {
+        Objects.requireNonNull(offsetId, "offsetId");
+        // "Z" is always in the cache
+        ZoneOffset offset = ID_CACHE.get(offsetId);
+        if (offset != null) {
+            return offset;
+        }
+
+        // parse - +h, +hh, +hhmm, +hh:mm, +hhmmss, +hh:mm:ss
+        final int hours, minutes, seconds;
+        switch (offsetId.length()) {
+            case 2:
+                offsetId = offsetId.charAt(0) + "0" + offsetId.charAt(1);  // fallthru
+            case 3:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = 0;
+                seconds = 0;
+                break;
+            case 5:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 3, false);
+                seconds = 0;
+                break;
+            case 6:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 4, true);
+                seconds = 0;
+                break;
+            case 7:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 3, false);
+                seconds = parseNumber(offsetId, 5, false);
+                break;
+            case 9:
+                hours = parseNumber(offsetId, 1, false);
+                minutes = parseNumber(offsetId, 4, true);
+                seconds = parseNumber(offsetId, 7, true);
+                break;
+            default:
+                throw new DateTimeException("Invalid ID for ZoneOffset, invalid format: " + offsetId);
+        }
+        char first = offsetId.charAt(0);
+        if (first != '+' && first != '-') {
+            throw new DateTimeException("Invalid ID for ZoneOffset, plus/minus not found when expected: " + offsetId);
+        }
+        if (first == '-') {
+            return ofHoursMinutesSeconds(-hours, -minutes, -seconds);
+        } else {
+            return ofHoursMinutesSeconds(hours, minutes, seconds);
+        }
+    }
+
+    /**
+     * Parse a two digit zero-prefixed number.
+     *
+     * @param offsetId  the offset ID, not null
+     * @param pos  the position to parse, valid
+     * @param precededByColon  should this number be prefixed by a precededByColon
+     * @return the parsed number, from 0 to 99
+     */
+    private static int parseNumber(CharSequence offsetId, int pos, boolean precededByColon) {
+        if (precededByColon && offsetId.charAt(pos - 1) != ':') {
+            throw new DateTimeException("Invalid ID for ZoneOffset, colon not found when expected: " + offsetId);
+        }
+        char ch1 = offsetId.charAt(pos);
+        char ch2 = offsetId.charAt(pos + 1);
+        if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+            throw new DateTimeException("Invalid ID for ZoneOffset, non numeric characters found: " + offsetId);
+        }
+        return (ch1 - 48) * 10 + (ch2 - 48);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in hours.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHours(int hours) {
+        return ofHoursMinutesSeconds(hours, 0, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in
+     * hours and minutes.
+     * <p>
+     * The sign of the hours and minutes components must match.
+     * Thus, if the hours is negative, the minutes must be negative or zero.
+     * If the hours is zero, the minutes may be positive, negative or zero.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHoursMinutes(int hours, int minutes) {
+        return ofHoursMinutesSeconds(hours, minutes, 0);
+    }
+
+    /**
+     * Obtains an instance of {@code ZoneOffset} using an offset in
+     * hours, minutes and seconds.
+     * <p>
+     * The sign of the hours, minutes and seconds components must match.
+     * Thus, if the hours is negative, the minutes and seconds must be negative or zero.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours and seconds
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59, sign matches hours and minutes
+     * @return the zone-offset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofHoursMinutesSeconds(int hours, int minutes, int seconds) {
+        validate(hours, minutes, seconds);
+        int totalSeconds = totalSeconds(hours, minutes, seconds);
+        return ofTotalSeconds(totalSeconds);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} from a temporal object.
+     * <p>
+     * This obtains an offset based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ZoneOffset}.
+     * <p>
+     * A {@code TemporalAccessor} represents some form of date and time information.
+     * This factory converts the arbitrary temporal object to an instance of {@code ZoneOffset}.
+     * <p>
+     * The conversion uses the {@link TemporalQueries#offset()} query, which relies
+     * on extracting the {@link ChronoField#OFFSET_SECONDS OFFSET_SECONDS} field.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ZoneOffset::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zone-offset, not null
+     * @throws DateTimeException if unable to convert to an {@code ZoneOffset}
+     */
+    public static ZoneOffset from(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        ZoneOffset offset = temporal.query(TemporalQueries.offset());
+        if (offset == null) {
+            throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
+        }
+        return offset;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Validates the offset fields.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    private static void validate(int hours, int minutes, int seconds) {
+        if (hours < -18 || hours > 18) {
+            throw new DateTimeException("Zone offset hours not in valid range: value " + hours +
+                    " is not in the range -18 to 18");
+        }
+        if (hours > 0) {
+            if (minutes < 0 || seconds < 0) {
+                throw new DateTimeException("Zone offset minutes and seconds must be positive because hours is positive");
+            }
+        } else if (hours < 0) {
+            if (minutes > 0 || seconds > 0) {
+                throw new DateTimeException("Zone offset minutes and seconds must be negative because hours is negative");
+            }
+        } else if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0)) {
+            throw new DateTimeException("Zone offset minutes and seconds must have the same sign");
+        }
+        if (Math.abs(minutes) > 59) {
+            throw new DateTimeException("Zone offset minutes not in valid range: abs(value) " +
+                    Math.abs(minutes) + " is not in the range 0 to 59");
+        }
+        if (Math.abs(seconds) > 59) {
+            throw new DateTimeException("Zone offset seconds not in valid range: abs(value) " +
+                    Math.abs(seconds) + " is not in the range 0 to 59");
+        }
+        if (Math.abs(hours) == 18 && (Math.abs(minutes) > 0 || Math.abs(seconds) > 0)) {
+            throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+        }
+    }
+
+    /**
+     * Calculates the total offset in seconds.
+     *
+     * @param hours  the time-zone offset in hours, from -18 to +18
+     * @param minutes  the time-zone offset in minutes, from 0 to &plusmn;59, sign matches hours and seconds
+     * @param seconds  the time-zone offset in seconds, from 0 to &plusmn;59, sign matches hours and minutes
+     * @return the total in seconds
+     */
+    private static int totalSeconds(int hours, int minutes, int seconds) {
+        return hours * SECONDS_PER_HOUR + minutes * SECONDS_PER_MINUTE + seconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZoneOffset} specifying the total offset in seconds
+     * <p>
+     * The offset must be in the range {@code -18:00} to {@code +18:00}, which corresponds to -64800 to +64800.
+     *
+     * @param totalSeconds  the total time-zone offset in seconds, from -64800 to +64800
+     * @return the ZoneOffset, not null
+     * @throws DateTimeException if the offset is not in the required range
+     */
+    public static ZoneOffset ofTotalSeconds(int totalSeconds) {
+        if (Math.abs(totalSeconds) > MAX_SECONDS) {
+            throw new DateTimeException("Zone offset not in valid range: -18:00 to +18:00");
+        }
+        if (totalSeconds % (15 * SECONDS_PER_MINUTE) == 0) {
+            Integer totalSecs = totalSeconds;
+            ZoneOffset result = SECONDS_CACHE.get(totalSecs);
+            if (result == null) {
+                result = new ZoneOffset(totalSeconds);
+                SECONDS_CACHE.putIfAbsent(totalSecs, result);
+                result = SECONDS_CACHE.get(totalSecs);
+                ID_CACHE.putIfAbsent(result.getId(), result);
+            }
+            return result;
+        } else {
+            return new ZoneOffset(totalSeconds);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param totalSeconds  the total time-zone offset in seconds, from -64800 to +64800
+     */
+    private ZoneOffset(int totalSeconds) {
+        super();
+        this.totalSeconds = totalSeconds;
+        id = buildId(totalSeconds);
+    }
+
+    private static String buildId(int totalSeconds) {
+        if (totalSeconds == 0) {
+            return "Z";
+        } else {
+            int absTotalSeconds = Math.abs(totalSeconds);
+            StringBuilder buf = new StringBuilder();
+            int absHours = absTotalSeconds / SECONDS_PER_HOUR;
+            int absMinutes = (absTotalSeconds / SECONDS_PER_MINUTE) % MINUTES_PER_HOUR;
+            buf.append(totalSeconds < 0 ? "-" : "+")
+                .append(absHours < 10 ? "0" : "").append(absHours)
+                .append(absMinutes < 10 ? ":0" : ":").append(absMinutes);
+            int absSeconds = absTotalSeconds % SECONDS_PER_MINUTE;
+            if (absSeconds != 0) {
+                buf.append(absSeconds < 10 ? ":0" : ":").append(absSeconds);
+            }
+            return buf.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the total zone offset in seconds.
+     * <p>
+     * This is the primary way to access the offset amount.
+     * It returns the total of the hours, minutes and seconds fields as a
+     * single offset that can be added to a time.
+     *
+     * @return the total zone offset amount in seconds
+     */
+    public int getTotalSeconds() {
+        return totalSeconds;
+    }
+
+    /**
+     * Gets the normalized zone offset ID.
+     * <p>
+     * The ID is minor variation to the standard ISO-8601 formatted string
+     * for the offset. There are three formats:
+     * <ul>
+     * <li>{@code Z} - for UTC (ISO-8601)
+     * <li>{@code +hh:mm} or {@code -hh:mm} - if the seconds are zero (ISO-8601)
+     * <li>{@code +hh:mm:ss} or {@code -hh:mm:ss} - if the seconds are non-zero (not ISO-8601)
+     * </ul>
+     *
+     * @return the zone offset ID, not null
+     */
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Gets the associated time-zone rules.
+     * <p>
+     * The rules will always return this offset when queried.
+     * The implementation class is immutable, thread-safe and serializable.
+     *
+     * @return the rules, not null
+     */
+    @Override
+    public ZoneRules getRules() {
+        return ZoneRules.of(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this offset can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code OFFSET_SECONDS} field returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this offset, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == OFFSET_SECONDS;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This offset is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override  // override for Javadoc
+    public ValueRange range(TemporalField field) {
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this offset as an {@code int}.
+     * <p>
+     * This queries this offset for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code OFFSET_SECONDS} field returns the value of the offset.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field == OFFSET_SECONDS) {
+            return totalSeconds;
+        } else if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    /**
+     * Gets the value of the specified field from this offset as a {@code long}.
+     * <p>
+     * This queries this offset for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code OFFSET_SECONDS} field returns the value of the offset.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field == OFFSET_SECONDS) {
+            return totalSeconds;
+        } else if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this offset using the specified query.
+     * <p>
+     * This queries this offset using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.offset() || query == TemporalQueries.zone()) {
+            return (R) this;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same offset as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the offset changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#OFFSET_SECONDS} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisOffset.adjustInto(temporal);
+     *   temporal = temporal.with(thisOffset);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public Temporal adjustInto(Temporal temporal) {
+        return temporal.with(OFFSET_SECONDS, totalSeconds);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this offset to another offset in descending order.
+     * <p>
+     * The offsets are compared in the order that they occur for the same time
+     * of day around the world. Thus, an offset of {@code +10:00} comes before an
+     * offset of {@code +09:00} and so on down to {@code -18:00}.
+     * <p>
+     * The comparison is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, postive if greater
+     * @throws NullPointerException if {@code other} is null
+     */
+    @Override
+    public int compareTo(ZoneOffset other) {
+        return other.totalSeconds - totalSeconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this offset is equal to another offset.
+     * <p>
+     * The comparison is based on the amount of the offset in seconds.
+     * This is equivalent to a comparison by ID.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other offset
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof ZoneOffset) {
+            return totalSeconds == ((ZoneOffset) obj).totalSeconds;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this offset.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return totalSeconds;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this offset as a {@code String}, using the normalized ID.
+     *
+     * @return a string representation of this offset, not null
+     */
+    @Override
+    public String toString() {
+        return id;
+    }
+
+    // -----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(8);                  // identifies a ZoneOffset
+     *  int offsetByte = totalSeconds % 900 == 0 ? totalSeconds / 900 : 127;
+     *  out.writeByte(offsetByte);
+     *  if (offsetByte == 127) {
+     *      out.writeInt(totalSeconds);
+     *  }
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_OFFSET_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    @Override
+    void write(DataOutput out) throws IOException {
+        out.writeByte(Ser.ZONE_OFFSET_TYPE);
+        writeExternal(out);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        final int offsetSecs = totalSeconds;
+        int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+        out.writeByte(offsetByte);
+        if (offsetByte == 127) {
+            out.writeInt(offsetSecs);
+        }
+    }
+
+    static ZoneOffset readExternal(DataInput in) throws IOException {
+        int offsetByte = in.readByte();
+        return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));
+    }
+
+}
diff --git a/java/time/ZoneRegion.java b/java/time/ZoneRegion.java
new file mode 100644
index 0000000..83f0b43
--- /dev/null
+++ b/java/time/ZoneRegion.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.zone.ZoneRules;
+import java.time.zone.ZoneRulesException;
+import java.time.zone.ZoneRulesProvider;
+import java.util.Objects;
+
+/**
+ * A geographical region where the same time-zone rules apply.
+ * <p>
+ * Time-zone information is categorized as a set of rules defining when and
+ * how the offset from UTC/Greenwich changes. These rules are accessed using
+ * identifiers based on geographical regions, such as countries or states.
+ * The most common region classification is the Time Zone Database (TZDB),
+ * which defines regions such as 'Europe/Paris' and 'Asia/Tokyo'.
+ * <p>
+ * The region identifier, modeled by this class, is distinct from the
+ * underlying rules, modeled by {@link ZoneRules}.
+ * The rules are defined by governments and change frequently.
+ * By contrast, the region identifier is well-defined and long-lived.
+ * This separation also allows rules to be shared between regions if appropriate.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+final class ZoneRegion extends ZoneId implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 8386373296231747096L;
+    /**
+     * The time-zone ID, not null.
+     */
+    private final String id;
+    /**
+     * The time-zone rules, null if zone ID was loaded leniently.
+     */
+    private final transient ZoneRules rules;
+
+    /**
+     * Obtains an instance of {@code ZoneId} from an identifier.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @param checkAvailable  whether to check if the zone ID is available
+     * @return the zone ID, not null
+     * @throws DateTimeException if the ID format is invalid
+     * @throws ZoneRulesException if checking availability and the ID cannot be found
+     */
+    static ZoneRegion ofId(String zoneId, boolean checkAvailable) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        checkName(zoneId);
+        ZoneRules rules = null;
+        try {
+            // always attempt load for better behavior after deserialization
+            rules = ZoneRulesProvider.getRules(zoneId, true);
+        } catch (ZoneRulesException ex) {
+            if (checkAvailable) {
+                throw ex;
+            }
+        }
+        return new ZoneRegion(zoneId, rules);
+    }
+
+    /**
+     * Checks that the given string is a legal ZondId name.
+     *
+     * @param zoneId  the time-zone ID, not null
+     * @throws DateTimeException if the ID format is invalid
+     */
+    private static void checkName(String zoneId) {
+        int n = zoneId.length();
+        if (n < 2) {
+           throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
+        }
+        for (int i = 0; i < n; i++) {
+            char c = zoneId.charAt(i);
+            if (c >= 'a' && c <= 'z') continue;
+            if (c >= 'A' && c <= 'Z') continue;
+            if (c == '/' && i != 0) continue;
+            if (c >= '0' && c <= '9' && i != 0) continue;
+            if (c == '~' && i != 0) continue;
+            if (c == '.' && i != 0) continue;
+            if (c == '_' && i != 0) continue;
+            if (c == '+' && i != 0) continue;
+            if (c == '-' && i != 0) continue;
+            throw new DateTimeException("Invalid ID for region-based ZoneId, invalid format: " + zoneId);
+        }
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param id  the time-zone ID, not null
+     * @param rules  the rules, null for lazy lookup
+     */
+    ZoneRegion(String id, ZoneRules rules) {
+        this.id = id;
+        this.rules = rules;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public ZoneRules getRules() {
+        // additional query for group provider when null allows for possibility
+        // that the provider was updated after the ZoneId was created
+        return (rules != null ? rules : ZoneRulesProvider.getRules(id, false));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(7);  // identifies a ZoneId (not ZoneOffset)
+     *  out.writeUTF(zoneId);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_REGION_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    @Override
+    void write(DataOutput out) throws IOException {
+        out.writeByte(Ser.ZONE_REGION_TYPE);
+        writeExternal(out);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeUTF(id);
+    }
+
+    static ZoneId readExternal(DataInput in) throws IOException {
+        String id = in.readUTF();
+        return ZoneId.of(id, false);
+    }
+
+}
diff --git a/java/time/ZonedDateTime.java b/java/time/ZonedDateTime.java
new file mode 100644
index 0000000..4af3bda
--- /dev/null
+++ b/java/time/ZonedDateTime.java
@@ -0,0 +1,2248 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.chrono.ChronoZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.List;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date-time with a time-zone in the ISO-8601 calendar system,
+ * such as {@code 2007-12-03T10:15:30+01:00 Europe/Paris}.
+ * <p>
+ * {@code ZonedDateTime} is an immutable representation of a date-time with a time-zone.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * and a time-zone, with a zone offset used to handle ambiguous local date-times.
+ * For example, the value
+ * "2nd October 2007 at 13:45.30.123456789 +02:00 in the Europe/Paris time-zone"
+ * can be stored in a {@code ZonedDateTime}.
+ * <p>
+ * This class handles conversion from the local time-line of {@code LocalDateTime}
+ * to the instant time-line of {@code Instant}.
+ * The difference between the two time-lines is the offset from UTC/Greenwich,
+ * represented by a {@code ZoneOffset}.
+ * <p>
+ * Converting between the two time-lines involves calculating the offset using the
+ * {@link ZoneRules rules} accessed from the {@code ZoneId}.
+ * Obtaining the offset for an instant is simple, as there is exactly one valid
+ * offset for each instant. By contrast, obtaining the offset for a local date-time
+ * is not straightforward. There are three cases:
+ * <ul>
+ * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+ *  case applies, where there is a single valid offset for the local date-time.</li>
+ * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+ *  due to the spring daylight savings change from "winter" to "summer".
+ *  In a gap there are local date-time values with no valid offset.</li>
+ * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+ *  due to the autumn daylight savings change from "summer" to "winter".
+ *  In an overlap there are local date-time values with two valid offsets.</li>
+ * </ul>
+ * <p>
+ * Any method that converts directly or implicitly from a local date-time to an
+ * instant by obtaining the offset has the potential to be complicated.
+ * <p>
+ * For Gaps, the general strategy is that if the local date-time falls in the
+ * middle of a Gap, then the resulting zoned date-time will have a local date-time
+ * shifted forwards by the length of the Gap, resulting in a date-time in the later
+ * offset, typically "summer" time.
+ * <p>
+ * For Overlaps, the general strategy is that if the local date-time falls in the
+ * middle of an Overlap, then the previous offset will be retained. If there is no
+ * previous offset, or the previous offset is invalid, then the earlier offset is
+ * used, typically "summer" time.. Two additional methods,
+ * {@link #withEarlierOffsetAtOverlap()} and {@link #withLaterOffsetAtOverlap()},
+ * help manage the case of an overlap.
+ * <p>
+ * In terms of design, this class should be viewed primarily as the combination
+ * of a {@code LocalDateTime} and a {@code ZoneId}. The {@code ZoneOffset} is
+ * a vital, but secondary, piece of information, used to ensure that the class
+ * represents an instant, especially during a daylight savings overlap.
+ *
+ * @implSpec
+ * A {@code ZonedDateTime} holds state equivalent to three separate objects,
+ * a {@code LocalDateTime}, a {@code ZoneId} and the resolved {@code ZoneOffset}.
+ * The offset and local date-time are used to define an instant when necessary.
+ * The zone ID is used to obtain the rules for how and when the offset changes.
+ * The offset cannot be freely set, as the zone controls which offsets are valid.
+ * <p>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZonedDateTime
+        implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -6260982410461394882L;
+
+    /**
+     * The local date-time.
+     */
+    private final LocalDateTime dateTime;
+    /**
+     * The offset from UTC/Greenwich.
+     */
+    private final ZoneOffset offset;
+    /**
+     * The time-zone.
+     */
+    private final ZoneId zone;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current date-time from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date-time.
+     * The zone and offset will be set based on the time-zone in the clock.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date-time using the system clock, not null
+     */
+    public static ZonedDateTime now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current date-time from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date-time.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * The offset will be calculated from the specified time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date-time using the system clock, not null
+     */
+    public static ZonedDateTime now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current date-time from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date-time.
+     * The zone and offset will be set based on the time-zone in the clock.
+     * <p>
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date-time, not null
+     */
+    public static ZonedDateTime now(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        final Instant now = clock.instant();  // called once
+        return ofInstant(now, clock.getZone());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a local date and time.
+     * <p>
+     * This creates a zoned date-time matching the input local date and time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date time and first combined to form a local date-time.
+     * The local date-time is then resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, when clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, when clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @param zone  the time-zone, not null
+     * @return the offset date-time, not null
+     */
+    public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) {
+        return of(LocalDateTime.of(date, time), zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a local date-time.
+     * <p>
+     * This creates a zoned date-time matching the input local date-time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, when clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, when clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone) {
+        return ofLocal(localDateTime, zone, null);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a year, month, day,
+     * hour, minute, second, nanosecond and time-zone.
+     * <p>
+     * This creates a zoned date-time matching the local date-time of the seven
+     * specified fields as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, when clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, when clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     * <p>
+     * This method exists primarily for writing test cases.
+     * Non test-code will typically use other methods to create an offset time.
+     * {@code LocalDateTime} has five additional convenience variants of the
+     * equivalent factory method taking fewer arguments.
+     * They are not provided here to reduce the footprint of the API.
+     *
+     * @param year  the year to represent, from MIN_YEAR to MAX_YEAR
+     * @param month  the month-of-year to represent, from 1 (January) to 12 (December)
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 31
+     * @param hour  the hour-of-day to represent, from 0 to 23
+     * @param minute  the minute-of-hour to represent, from 0 to 59
+     * @param second  the second-of-minute to represent, from 0 to 59
+     * @param nanoOfSecond  the nano-of-second to represent, from 0 to 999,999,999
+     * @param zone  the time-zone, not null
+     * @return the offset date-time, not null
+     * @throws DateTimeException if the value of any field is out of range, or
+     *  if the day-of-month is invalid for the month-year
+     */
+    public static ZonedDateTime of(
+            int year, int month, int dayOfMonth,
+            int hour, int minute, int second, int nanoOfSecond, ZoneId zone) {
+        LocalDateTime dt = LocalDateTime.of(year, month, dayOfMonth, hour, minute, second, nanoOfSecond);
+        return ofLocal(dt, zone, null);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a local date-time
+     * using the preferred offset if possible.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, where clocks are set back, there are two valid offsets.
+     * If the preferred offset is one of the valid offsets then it is used.
+     * Otherwise the earlier valid offset is used, typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, where clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param zone  the time-zone, not null
+     * @param preferredOffset  the zone offset, null if no preference
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime ofLocal(LocalDateTime localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(zone, "zone");
+        if (zone instanceof ZoneOffset) {
+            return new ZonedDateTime(localDateTime, (ZoneOffset) zone, zone);
+        }
+        ZoneRules rules = zone.getRules();
+        List<ZoneOffset> validOffsets = rules.getValidOffsets(localDateTime);
+        ZoneOffset offset;
+        if (validOffsets.size() == 1) {
+            offset = validOffsets.get(0);
+        } else if (validOffsets.size() == 0) {
+            ZoneOffsetTransition trans = rules.getTransition(localDateTime);
+            localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
+            offset = trans.getOffsetAfter();
+        } else {
+            if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
+                offset = preferredOffset;
+            } else {
+                offset = Objects.requireNonNull(validOffsets.get(0), "offset");  // protect against bad ZoneRules
+            }
+        }
+        return new ZonedDateTime(localDateTime, offset, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from an {@code Instant}.
+     * <p>
+     * This creates a zoned date-time with the same instant as that specified.
+     * Calling {@link #toInstant()} will return an instant equal to the one used here.
+     * <p>
+     * Converting an instant to a zoned date-time is simple as there is only one valid
+     * offset for each instant.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    public static ZonedDateTime ofInstant(Instant instant, ZoneId zone) {
+        Objects.requireNonNull(instant, "instant");
+        Objects.requireNonNull(zone, "zone");
+        return create(instant.getEpochSecond(), instant.getNano(), zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from the instant formed by combining
+     * the local date-time and offset.
+     * <p>
+     * This creates a zoned date-time by {@link LocalDateTime#toInstant(ZoneOffset) combining}
+     * the {@code LocalDateTime} and {@code ZoneOffset}.
+     * This combination uniquely specifies an instant without ambiguity.
+     * <p>
+     * Converting an instant to a zoned date-time is simple as there is only one valid
+     * offset for each instant. If the valid offset is different to the offset specified,
+     * then the date-time and offset of the zoned date-time will differ from those specified.
+     * <p>
+     * If the {@code ZoneId} to be used is a {@code ZoneOffset}, this method is equivalent
+     * to {@link #of(LocalDateTime, ZoneId)}.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime ofInstant(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(offset, "offset");
+        Objects.requireNonNull(zone, "zone");
+        if (zone.getRules().isValidOffset(localDateTime, offset)) {
+            return new ZonedDateTime(localDateTime, offset, zone);
+        }
+        return create(localDateTime.toEpochSecond(offset), localDateTime.getNano(), zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} using seconds from the
+     * epoch of 1970-01-01T00:00:00Z.
+     *
+     * @param epochSecond  the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     * @param nanoOfSecond  the nanosecond within the second, from 0 to 999,999,999
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    private static ZonedDateTime create(long epochSecond, int nanoOfSecond, ZoneId zone) {
+        ZoneRules rules = zone.getRules();
+        Instant instant = Instant.ofEpochSecond(epochSecond, nanoOfSecond);  // TODO: rules should be queryable by epochSeconds
+        ZoneOffset offset = rules.getOffset(instant);
+        LocalDateTime ldt = LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, offset);
+        return new ZonedDateTime(ldt, offset, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} strictly validating the
+     * combination of local date-time, offset and zone ID.
+     * <p>
+     * This creates a zoned date-time ensuring that the offset is valid for the
+     * local date-time according to the rules of the specified zone.
+     * If the offset is invalid, an exception is thrown.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    public static ZonedDateTime ofStrict(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(offset, "offset");
+        Objects.requireNonNull(zone, "zone");
+        ZoneRules rules = zone.getRules();
+        if (rules.isValidOffset(localDateTime, offset) == false) {
+            ZoneOffsetTransition trans = rules.getTransition(localDateTime);
+            if (trans != null && trans.isGap()) {
+                // error message says daylight savings for simplicity
+                // even though there are other kinds of gaps
+                throw new DateTimeException("LocalDateTime '" + localDateTime +
+                        "' does not exist in zone '" + zone +
+                        "' due to a gap in the local time-line, typically caused by daylight savings");
+            }
+            throw new DateTimeException("ZoneOffset '" + offset + "' is not valid for LocalDateTime '" +
+                    localDateTime + "' in zone '" + zone + "'");
+        }
+        return new ZonedDateTime(localDateTime, offset, zone);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} leniently, for advanced use cases,
+     * allowing any combination of local date-time, offset and zone ID.
+     * <p>
+     * This creates a zoned date-time with no checks other than no nulls.
+     * This means that the resulting zoned date-time may have an offset that is in conflict
+     * with the zone ID.
+     * <p>
+     * This method is intended for advanced use cases.
+     * For example, consider the case where a zoned date-time with valid fields is created
+     * and then stored in a database or serialization-based store. At some later point,
+     * the object is then re-loaded. However, between those points in time, the government
+     * that defined the time-zone has changed the rules, such that the originally stored
+     * local date-time now does not occur. This method can be used to create the object
+     * in an "invalid" state, despite the change in rules.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     */
+    private static ZonedDateTime ofLenient(LocalDateTime localDateTime, ZoneOffset offset, ZoneId zone) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(offset, "offset");
+        Objects.requireNonNull(zone, "zone");
+        if (zone instanceof ZoneOffset && offset.equals(zone) == false) {
+            throw new IllegalArgumentException("ZoneId must match ZoneOffset");
+        }
+        return new ZonedDateTime(localDateTime, offset, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a temporal object.
+     * <p>
+     * This obtains a zoned date-time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ZonedDateTime}.
+     * <p>
+     * The conversion will first obtain a {@code ZoneId} from the temporal object,
+     * falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
+     * an {@code Instant}, falling back to a {@code LocalDateTime} if necessary.
+     * The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
+     * with {@code Instant} or {@code LocalDateTime}.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ZonedDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if unable to convert to an {@code ZonedDateTime}
+     */
+    public static ZonedDateTime from(TemporalAccessor temporal) {
+        if (temporal instanceof ZonedDateTime) {
+            return (ZonedDateTime) temporal;
+        }
+        try {
+            ZoneId zone = ZoneId.from(temporal);
+            if (temporal.isSupported(INSTANT_SECONDS)) {
+                long epochSecond = temporal.getLong(INSTANT_SECONDS);
+                int nanoOfSecond = temporal.get(NANO_OF_SECOND);
+                return create(epochSecond, nanoOfSecond, zone);
+            } else {
+                LocalDate date = LocalDate.from(temporal);
+                LocalTime time = LocalTime.from(temporal);
+                return of(date, time, zone);
+            }
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain ZonedDateTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a text string such as
+     * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
+     * <p>
+     * The string must represent a valid date-time and is parsed using
+     * {@link java.time.format.DateTimeFormatter#ISO_ZONED_DATE_TIME}.
+     *
+     * @param text  the text to parse such as "2007-12-03T10:15:30+01:00[Europe/Paris]", not null
+     * @return the parsed zoned date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static ZonedDateTime parse(CharSequence text) {
+        return parse(text, DateTimeFormatter.ISO_ZONED_DATE_TIME);
+    }
+
+    /**
+     * Obtains an instance of {@code ZonedDateTime} from a text string using a specific formatter.
+     * <p>
+     * The text is parsed using the formatter, returning a date-time.
+     *
+     * @param text  the text to parse, not null
+     * @param formatter  the formatter to use, not null
+     * @return the parsed zoned date-time, not null
+     * @throws DateTimeParseException if the text cannot be parsed
+     */
+    public static ZonedDateTime parse(CharSequence text, DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.parse(text, ZonedDateTime::from);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param dateTime  the date-time, validated as not null
+     * @param offset  the zone offset, validated as not null
+     * @param zone  the time-zone, validated as not null
+     */
+    private ZonedDateTime(LocalDateTime dateTime, ZoneOffset offset, ZoneId zone) {
+        this.dateTime = dateTime;
+        this.offset = offset;
+        this.zone = zone;
+    }
+
+    /**
+     * Resolves the new local date-time using this zone ID, retaining the offset if possible.
+     *
+     * @param newDateTime  the new local date-time, not null
+     * @return the zoned date-time, not null
+     */
+    private ZonedDateTime resolveLocal(LocalDateTime newDateTime) {
+        return ofLocal(newDateTime, zone, offset);
+    }
+
+    /**
+     * Resolves the new local date-time using the offset to identify the instant.
+     *
+     * @param newDateTime  the new local date-time, not null
+     * @return the zoned date-time, not null
+     */
+    private ZonedDateTime resolveInstant(LocalDateTime newDateTime) {
+        return ofInstant(newDateTime, offset, zone);
+    }
+
+    /**
+     * Resolves the offset into this zoned date-time for the with methods.
+     * <p>
+     * This typically ignores the offset, unless it can be used to switch offset in a DST overlap.
+     *
+     * @param offset  the offset, not null
+     * @return the zoned date-time, not null
+     */
+    private ZonedDateTime resolveOffset(ZoneOffset offset) {
+        if (offset.equals(this.offset) == false && zone.getRules().isValidOffset(dateTime, offset)) {
+            return new ZonedDateTime(dateTime, offset, zone);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code NANO_OF_SECOND}
+     * <li>{@code NANO_OF_DAY}
+     * <li>{@code MICRO_OF_SECOND}
+     * <li>{@code MICRO_OF_DAY}
+     * <li>{@code MILLI_OF_SECOND}
+     * <li>{@code MILLI_OF_DAY}
+     * <li>{@code SECOND_OF_MINUTE}
+     * <li>{@code SECOND_OF_DAY}
+     * <li>{@code MINUTE_OF_HOUR}
+     * <li>{@code MINUTE_OF_DAY}
+     * <li>{@code HOUR_OF_AMPM}
+     * <li>{@code CLOCK_HOUR_OF_AMPM}
+     * <li>{@code HOUR_OF_DAY}
+     * <li>{@code CLOCK_HOUR_OF_DAY}
+     * <li>{@code AMPM_OF_DAY}
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_MONTH}
+     * <li>{@code ALIGNED_DAY_OF_WEEK_IN_YEAR}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code ALIGNED_WEEK_OF_MONTH}
+     * <li>{@code ALIGNED_WEEK_OF_YEAR}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code PROLEPTIC_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * <li>{@code INSTANT_SECONDS}
+     * <li>{@code OFFSET_SECONDS}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date-time, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * If the unit is a {@link ChronoUnit} then the query is implemented here.
+     * The supported units are:
+     * <ul>
+     * <li>{@code NANOS}
+     * <li>{@code MICROS}
+     * <li>{@code MILLIS}
+     * <li>{@code SECONDS}
+     * <li>{@code MINUTES}
+     * <li>{@code HOURS}
+     * <li>{@code HALF_DAYS}
+     * <li>{@code DAYS}
+     * <li>{@code WEEKS}
+     * <li>{@code MONTHS}
+     * <li>{@code YEARS}
+     * <li>{@code DECADES}
+     * <li>{@code CENTURIES}
+     * <li>{@code MILLENNIA}
+     * <li>{@code ERAS}
+     * </ul>
+     * All other {@code ChronoUnit} instances will return false.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override  // override for Javadoc
+    public boolean isSupported(TemporalUnit unit) {
+        return ChronoZonedDateTime.super.isSupported(unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This date-time is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return
+     * appropriate range instances.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return dateTime.range(field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as an {@code int}.
+     * <p>
+     * This queries this date-time for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time, except {@code NANO_OF_DAY}, {@code MICRO_OF_DAY},
+     * {@code EPOCH_DAY}, {@code PROLEPTIC_MONTH} and {@code INSTANT_SECONDS} which are too
+     * large to fit in an {@code int} and throw a {@code DateTimeException}.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS:
+                    throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
+                case OFFSET_SECONDS:
+                    return getOffset().getTotalSeconds();
+            }
+            return dateTime.get(field);
+        }
+        return ChronoZonedDateTime.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this date-time as a {@code long}.
+     * <p>
+     * This queries this date-time for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@link #isSupported(TemporalField) supported fields} will return valid
+     * values based on this date-time.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: return toEpochSecond();
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return dateTime.getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local date-time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    @Override
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * earlier of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the earlier of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ZonedDateTime} based on this date-time with the earlier offset, not null
+     */
+    @Override
+    public ZonedDateTime withEarlierOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(dateTime);
+        if (trans != null && trans.isOverlap()) {
+            ZoneOffset earlierOffset = trans.getOffsetBefore();
+            if (earlierOffset.equals(offset) == false) {
+                return new ZonedDateTime(dateTime, earlierOffset, zone);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * later of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the later of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ZonedDateTime} based on this date-time with the later offset, not null
+     */
+    @Override
+    public ZonedDateTime withLaterOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(toLocalDateTime());
+        if (trans != null) {
+            ZoneOffset laterOffset = trans.getOffsetAfter();
+            if (laterOffset.equals(offset) == false) {
+                return new ZonedDateTime(dateTime, laterOffset, zone);
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the time-zone, such as 'Europe/Paris'.
+     * <p>
+     * This returns the zone ID. This identifies the time-zone {@link ZoneRules rules}
+     * that determine when and how the offset from UTC/Greenwich changes.
+     * <p>
+     * The zone ID may be same as the {@linkplain #getOffset() offset}.
+     * If this is true, then any future calculations, such as addition or subtraction,
+     * have no complex edge cases due to time-zone rules.
+     * See also {@link #withFixedOffsetZone()}.
+     *
+     * @return the time-zone, not null
+     */
+    @Override
+    public ZoneId getZone() {
+        return zone;
+    }
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the local date-time if possible.
+     * <p>
+     * This method changes the time-zone and retains the local date-time.
+     * The local date-time is only changed if it is invalid for the new zone,
+     * determined using the same approach as
+     * {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}.
+     * <p>
+     * To change the zone and adjust the local date-time,
+     * use {@link #withZoneSameInstant(ZoneId)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
+     */
+    @Override
+    public ZonedDateTime withZoneSameLocal(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return this.zone.equals(zone) ? this : ofLocal(dateTime, zone, offset);
+    }
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the instant.
+     * <p>
+     * This method changes the time-zone and retains the instant.
+     * This normally results in a change to the local date-time.
+     * <p>
+     * This method is based on retaining the same instant, thus gaps and overlaps
+     * in the local time-line have no effect on the result.
+     * <p>
+     * To change the offset while keeping the local time,
+     * use {@link #withZoneSameLocal(ZoneId)}.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the requested zone, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    @Override
+    public ZonedDateTime withZoneSameInstant(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return this.zone.equals(zone) ? this :
+            create(dateTime.toEpochSecond(offset), dateTime.getNano(), zone);
+    }
+
+    /**
+     * Returns a copy of this date-time with the zone ID set to the offset.
+     * <p>
+     * This returns a zoned date-time where the zone ID is the same as {@link #getOffset()}.
+     * The local date-time, offset and instant of the result will be the same as in this date-time.
+     * <p>
+     * Setting the date-time to a fixed single offset means that any future
+     * calculations, such as addition or subtraction, have no complex edge cases
+     * due to time-zone rules.
+     * This might also be useful when sending a zoned date-time across a network,
+     * as most protocols, such as ISO-8601, only handle offsets,
+     * and not region-based zone IDs.
+     * <p>
+     * This is equivalent to {@code ZonedDateTime.of(zdt.toLocalDateTime(), zdt.getOffset())}.
+     *
+     * @return a {@code ZonedDateTime} with the zone ID set to the offset, not null
+     */
+    public ZonedDateTime withFixedOffsetZone() {
+        return this.zone.equals(offset) ? this : new ZonedDateTime(dateTime, offset, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDateTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDateTime} with the same year, month, day and time
+     * as this date-time.
+     *
+     * @return the local date-time part of this date-time, not null
+     */
+    @Override  // override for return type
+    public LocalDateTime toLocalDateTime() {
+        return dateTime;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalDate} part of this date-time.
+     * <p>
+     * This returns a {@code LocalDate} with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    @Override  // override for return type
+    public LocalDate toLocalDate() {
+        return dateTime.toLocalDate();
+    }
+
+    /**
+     * Gets the year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the year.
+     * <p>
+     * The year returned by this method is proleptic as per {@code get(YEAR)}.
+     * To obtain the year-of-era, use {@code get(YEAR_OF_ERA)}.
+     *
+     * @return the year, from MIN_YEAR to MAX_YEAR
+     */
+    public int getYear() {
+        return dateTime.getYear();
+    }
+
+    /**
+     * Gets the month-of-year field from 1 to 12.
+     * <p>
+     * This method returns the month as an {@code int} from 1 to 12.
+     * Application code is frequently clearer if the enum {@link Month}
+     * is used by calling {@link #getMonth()}.
+     *
+     * @return the month-of-year, from 1 to 12
+     * @see #getMonth()
+     */
+    public int getMonthValue() {
+        return dateTime.getMonthValue();
+    }
+
+    /**
+     * Gets the month-of-year field using the {@code Month} enum.
+     * <p>
+     * This method returns the enum {@link Month} for the month.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link Month#getValue() int value}.
+     *
+     * @return the month-of-year, not null
+     * @see #getMonthValue()
+     */
+    public Month getMonth() {
+        return dateTime.getMonth();
+    }
+
+    /**
+     * Gets the day-of-month field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-month.
+     *
+     * @return the day-of-month, from 1 to 31
+     */
+    public int getDayOfMonth() {
+        return dateTime.getDayOfMonth();
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year, from 1 to 365, or 366 in a leap year
+     */
+    public int getDayOfYear() {
+        return dateTime.getDayOfYear();
+    }
+
+    /**
+     * Gets the day-of-week field, which is an enum {@code DayOfWeek}.
+     * <p>
+     * This method returns the enum {@link DayOfWeek} for the day-of-week.
+     * This avoids confusion as to what {@code int} values mean.
+     * If you need access to the primitive {@code int} value then the enum
+     * provides the {@link DayOfWeek#getValue() int value}.
+     * <p>
+     * Additional information can be obtained from the {@code DayOfWeek}.
+     * This includes textual names of the values.
+     *
+     * @return the day-of-week, not null
+     */
+    public DayOfWeek getDayOfWeek() {
+        return dateTime.getDayOfWeek();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the {@code LocalTime} part of this date-time.
+     * <p>
+     * This returns a {@code LocalTime} with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    @Override  // override for Javadoc and performance
+    public LocalTime toLocalTime() {
+        return dateTime.toLocalTime();
+    }
+
+    /**
+     * Gets the hour-of-day field.
+     *
+     * @return the hour-of-day, from 0 to 23
+     */
+    public int getHour() {
+        return dateTime.getHour();
+    }
+
+    /**
+     * Gets the minute-of-hour field.
+     *
+     * @return the minute-of-hour, from 0 to 59
+     */
+    public int getMinute() {
+        return dateTime.getMinute();
+    }
+
+    /**
+     * Gets the second-of-minute field.
+     *
+     * @return the second-of-minute, from 0 to 59
+     */
+    public int getSecond() {
+        return dateTime.getSecond();
+    }
+
+    /**
+     * Gets the nano-of-second field.
+     *
+     * @return the nano-of-second, from 0 to 999,999,999
+     */
+    public int getNano() {
+        return dateTime.getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an adjusted copy of this date-time.
+     * <p>
+     * This returns a {@code ZonedDateTime}, based on this one, with the date-time adjusted.
+     * The adjustment takes place using the specified adjuster strategy object.
+     * Read the documentation of the adjuster to understand what adjustment will be made.
+     * <p>
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the date to the last day of the month.
+     * A selection of common adjustments is provided in
+     * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.
+     * These include finding the "last day of the month" and "next Wednesday".
+     * Key date-time classes also implement the {@code TemporalAdjuster} interface,
+     * such as {@link Month} and {@link java.time.MonthDay MonthDay}.
+     * The adjuster is responsible for handling special cases, such as the varying
+     * lengths of month and leap years.
+     * <p>
+     * For example this code returns a date on the last day of July:
+     * <pre>
+     *  import static java.time.Month.*;
+     *  import static java.time.temporal.TemporalAdjusters.*;
+     *
+     *  result = zonedDateTime.with(JULY).with(lastDayOfMonth());
+     * </pre>
+     * <p>
+     * The classes {@link LocalDate} and {@link LocalTime} implement {@code TemporalAdjuster},
+     * thus this method can be used to change the date, time or offset:
+     * <pre>
+     *  result = zonedDateTime.with(date);
+     *  result = zonedDateTime.with(time);
+     * </pre>
+     * <p>
+     * {@link ZoneOffset} also implements {@code TemporalAdjuster} however using it
+     * as an argument typically has no effect. The offset of a {@code ZonedDateTime} is
+     * controlled primarily by the time-zone. As such, changing the offset does not generally
+     * make sense, because there is only one valid offset for the local date-time and zone.
+     * If the zoned date-time is in a daylight savings overlap, then the offset is used
+     * to switch between the two valid offsets. In all other cases, the offset is ignored.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalAdjuster#adjustInto(Temporal)} method on the
+     * specified adjuster passing {@code this} as the argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param adjuster the adjuster to use, not null
+     * @return a {@code ZonedDateTime} based on {@code this} with the adjustment made, not null
+     * @throws DateTimeException if the adjustment cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime with(TemporalAdjuster adjuster) {
+        // optimizations
+        if (adjuster instanceof LocalDate) {
+            return resolveLocal(LocalDateTime.of((LocalDate) adjuster, dateTime.toLocalTime()));
+        } else if (adjuster instanceof LocalTime) {
+            return resolveLocal(LocalDateTime.of(dateTime.toLocalDate(), (LocalTime) adjuster));
+        } else if (adjuster instanceof LocalDateTime) {
+            return resolveLocal((LocalDateTime) adjuster);
+        } else if (adjuster instanceof OffsetDateTime) {
+            OffsetDateTime odt = (OffsetDateTime) adjuster;
+            return ofLocal(odt.toLocalDateTime(), zone, odt.getOffset());
+        } else if (adjuster instanceof Instant) {
+            Instant instant = (Instant) adjuster;
+            return create(instant.getEpochSecond(), instant.getNano(), zone);
+        } else if (adjuster instanceof ZoneOffset) {
+            return resolveOffset((ZoneOffset) adjuster);
+        }
+        return (ZonedDateTime) adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified field set to a new value.
+     * <p>
+     * This returns a {@code ZonedDateTime}, based on this one, with the value
+     * for the specified field changed.
+     * This can be used to change any supported field, such as the year, month or day-of-month.
+     * If it is not possible to set the value, because the field is not supported or for
+     * some other reason, an exception is thrown.
+     * <p>
+     * In some cases, changing the specified field can cause the resulting date-time to become invalid,
+     * such as changing the month from 31st January to February would make the day-of-month invalid.
+     * In cases like this, the field is responsible for resolving the date. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     * <p>
+     * If the field is a {@link ChronoField} then the adjustment is implemented here.
+     * <p>
+     * The {@code INSTANT_SECONDS} field will return a date-time with the specified instant.
+     * The zone and nano-of-second are unchanged.
+     * The result will have an offset derived from the new instant and original zone.
+     * If the new instant value is outside the valid range then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The {@code OFFSET_SECONDS} field will typically be ignored.
+     * The offset of a {@code ZonedDateTime} is controlled primarily by the time-zone.
+     * As such, changing the offset does not generally make sense, because there is only
+     * one valid offset for the local date-time and zone.
+     * If the zoned date-time is in a daylight savings overlap, then the offset is used
+     * to switch between the two valid offsets. In all other cases, the offset is ignored.
+     * If the new offset value is outside the valid range then a {@code DateTimeException} will be thrown.
+     * <p>
+     * The other {@link #isSupported(TemporalField) supported fields} will behave as per
+     * the matching method on {@link LocalDateTime#with(TemporalField, long) LocalDateTime}.
+     * The zone is not part of the calculation and will be unchanged.
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the field determines
+     * whether and how to adjust the instant.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return a {@code ZonedDateTime} based on {@code this} with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            switch (f) {
+                case INSTANT_SECONDS:
+                    return create(newValue, getNano(), zone);
+                case OFFSET_SECONDS:
+                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
+                    return resolveOffset(offset);
+            }
+            return resolveLocal(dateTime.with(field, newValue));
+        }
+        return field.adjustInto(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the year altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withYear(int) changing the year} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the result, from MIN_YEAR to MAX_YEAR
+     * @return a {@code ZonedDateTime} based on this date-time with the requested year, not null
+     * @throws DateTimeException if the year value is invalid
+     */
+    public ZonedDateTime withYear(int year) {
+        return resolveLocal(dateTime.withYear(year));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the month-of-year altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withMonth(int) changing the month} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param month  the month-of-year to set in the result, from 1 (January) to 12 (December)
+     * @return a {@code ZonedDateTime} based on this date-time with the requested month, not null
+     * @throws DateTimeException if the month-of-year value is invalid
+     */
+    public ZonedDateTime withMonth(int month) {
+        return resolveLocal(dateTime.withMonth(month));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the day-of-month altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withDayOfMonth(int) changing the day-of-month} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfMonth  the day-of-month to set in the result, from 1 to 28-31
+     * @return a {@code ZonedDateTime} based on this date-time with the requested day, not null
+     * @throws DateTimeException if the day-of-month value is invalid,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public ZonedDateTime withDayOfMonth(int dayOfMonth) {
+        return resolveLocal(dateTime.withDayOfMonth(dayOfMonth));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the day-of-year altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#withDayOfYear(int) changing the day-of-year} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param dayOfYear  the day-of-year to set in the result, from 1 to 365-366
+     * @return a {@code ZonedDateTime} based on this date with the requested day, not null
+     * @throws DateTimeException if the day-of-year value is invalid,
+     *  or if the day-of-year is invalid for the year
+     */
+    public ZonedDateTime withDayOfYear(int dayOfYear) {
+        return resolveLocal(dateTime.withDayOfYear(dayOfYear));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the hour-of-day altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withHour(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hour  the hour-of-day to set in the result, from 0 to 23
+     * @return a {@code ZonedDateTime} based on this date-time with the requested hour, not null
+     * @throws DateTimeException if the hour value is invalid
+     */
+    public ZonedDateTime withHour(int hour) {
+        return resolveLocal(dateTime.withHour(hour));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the minute-of-hour altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withMinute(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minute  the minute-of-hour to set in the result, from 0 to 59
+     * @return a {@code ZonedDateTime} based on this date-time with the requested minute, not null
+     * @throws DateTimeException if the minute value is invalid
+     */
+    public ZonedDateTime withMinute(int minute) {
+        return resolveLocal(dateTime.withMinute(minute));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the second-of-minute altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withSecond(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param second  the second-of-minute to set in the result, from 0 to 59
+     * @return a {@code ZonedDateTime} based on this date-time with the requested second, not null
+     * @throws DateTimeException if the second value is invalid
+     */
+    public ZonedDateTime withSecond(int second) {
+        return resolveLocal(dateTime.withSecond(second));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the nano-of-second altered.
+     * <p>
+     * This operates on the local time-line,
+     * {@linkplain LocalDateTime#withNano(int) changing the time} of the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanoOfSecond  the nano-of-second to set in the result, from 0 to 999,999,999
+     * @return a {@code ZonedDateTime} based on this date-time with the requested nanosecond, not null
+     * @throws DateTimeException if the nano value is invalid
+     */
+    public ZonedDateTime withNano(int nanoOfSecond) {
+        return resolveLocal(dateTime.withNano(nanoOfSecond));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the time truncated.
+     * <p>
+     * Truncation returns a copy of the original date-time with fields
+     * smaller than the specified unit set to zero.
+     * For example, truncating with the {@link ChronoUnit#MINUTES minutes} unit
+     * will set the second-of-minute and nano-of-second field to zero.
+     * <p>
+     * The unit must have a {@linkplain TemporalUnit#getDuration() duration}
+     * that divides into the length of a standard day without remainder.
+     * This includes all supplied time units on {@link ChronoUnit} and
+     * {@link ChronoUnit#DAYS DAYS}. Other units throw an exception.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#truncatedTo(TemporalUnit) truncating}
+     * the underlying local date-time. This is then converted back to a
+     * {@code ZonedDateTime}, using the zone ID to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param unit  the unit to truncate to, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the time truncated, not null
+     * @throws DateTimeException if unable to truncate
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    public ZonedDateTime truncatedTo(TemporalUnit unit) {
+        return resolveLocal(dateTime.truncatedTo(unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified amount added.
+     * <p>
+     * This returns a {@code ZonedDateTime}, based on this one, with the specified amount added.
+     * The amount is typically {@link Period} or {@link Duration} but may be
+     * any other type implementing the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#addTo(Temporal)}. The amount implementation is free
+     * to implement the addition in any way it wishes, however it typically
+     * calls back to {@link #plus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount to add, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the addition made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime plus(TemporalAmount amountToAdd) {
+        if (amountToAdd instanceof Period) {
+            Period periodToAdd = (Period) amountToAdd;
+            return resolveLocal(dateTime.plus(periodToAdd));
+        }
+        Objects.requireNonNull(amountToAdd, "amountToAdd");
+        return (ZonedDateTime) amountToAdd.addTo(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified amount added.
+     * <p>
+     * This returns a {@code ZonedDateTime}, based on this one, with the amount
+     * in terms of the unit added. If it is not possible to add the amount, because the
+     * unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoUnit} then the addition is implemented here.
+     * The zone is not part of the calculation and will be unchanged in the result.
+     * The calculation for date and time units differ.
+     * <p>
+     * Date units operate on the local time-line.
+     * The period is first added to the local date-time, then converted back
+     * to a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+     * with the offset before the addition.
+     * <p>
+     * Time units operate on the instant time-line.
+     * The period is first added to the local date-time, then converted back to
+     * a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
+     * with the offset before the addition.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the argument. In this case, the unit determines
+     * whether and how to perform the addition.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the amount of the unit to add to the result, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the specified amount added, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            if (unit.isDateBased()) {
+                return resolveLocal(dateTime.plus(amountToAdd, unit));
+            } else {
+                return resolveInstant(dateTime.plus(amountToAdd, unit));
+            }
+        }
+        return unit.addTo(this, amountToAdd);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of years added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusYears(long) adding years} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusYears(long years) {
+        return resolveLocal(dateTime.plusYears(years));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of months added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusMonths(long) adding months} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusMonths(long months) {
+        return resolveLocal(dateTime.plusMonths(months));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of weeks added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusWeeks(long) adding weeks} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusWeeks(long weeks) {
+        return resolveLocal(dateTime.plusWeeks(weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of days added.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#plusDays(long) adding days} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusDays(long days) {
+        return resolveLocal(dateTime.plusDays(days));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of hours added.
+     * <p>
+     * This operates on the instant time-line, such that adding one hour will
+     * always be a duration of one hour later.
+     * This may cause the local date-time to change by an amount other than one hour.
+     * Note that this is a different approach to that used by days, months and years,
+     * thus adding one day is not the same as adding 24 hours.
+     * <p>
+     * For example, consider a time-zone where the spring DST cutover means that the
+     * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
+     * <ul>
+     * <li>Adding one hour to 00:30+02:00 will result in 01:30+02:00
+     * <li>Adding one hour to 01:30+02:00 will result in 01:30+01:00
+     * <li>Adding one hour to 01:30+01:00 will result in 02:30+01:00
+     * <li>Adding three hours to 00:30+02:00 will result in 02:30+01:00
+     * </ul>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the hours added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusHours(long hours) {
+        return resolveInstant(dateTime.plusHours(hours));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of minutes added.
+     * <p>
+     * This operates on the instant time-line, such that adding one minute will
+     * always be a duration of one minute later.
+     * This may cause the local date-time to change by an amount other than one minute.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the minutes added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusMinutes(long minutes) {
+        return resolveInstant(dateTime.plusMinutes(minutes));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of seconds added.
+     * <p>
+     * This operates on the instant time-line, such that adding one second will
+     * always be a duration of one second later.
+     * This may cause the local date-time to change by an amount other than one second.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the seconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusSeconds(long seconds) {
+        return resolveInstant(dateTime.plusSeconds(seconds));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of nanoseconds added.
+     * <p>
+     * This operates on the instant time-line, such that adding one nano will
+     * always be a duration of one nano later.
+     * This may cause the local date-time to change by an amount other than one nano.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to add, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime plusNanos(long nanos) {
+        return resolveInstant(dateTime.plusNanos(nanos));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time with the specified amount subtracted.
+     * <p>
+     * This returns a {@code ZonedDateTime}, based on this one, with the specified amount subtracted.
+     * The amount is typically {@link Period} or {@link Duration} but may be
+     * any other type implementing the {@link TemporalAmount} interface.
+     * <p>
+     * The calculation is delegated to the amount object by calling
+     * {@link TemporalAmount#subtractFrom(Temporal)}. The amount implementation is free
+     * to implement the subtraction in any way it wishes, however it typically
+     * calls back to {@link #minus(long, TemporalUnit)}. Consult the documentation
+     * of the amount implementation to determine if it can be successfully subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount to subtract, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the subtraction made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime minus(TemporalAmount amountToSubtract) {
+        if (amountToSubtract instanceof Period) {
+            Period periodToSubtract = (Period) amountToSubtract;
+            return resolveLocal(dateTime.minus(periodToSubtract));
+        }
+        Objects.requireNonNull(amountToSubtract, "amountToSubtract");
+        return (ZonedDateTime) amountToSubtract.subtractFrom(this);
+    }
+
+    /**
+     * Returns a copy of this date-time with the specified amount subtracted.
+     * <p>
+     * This returns a {@code ZonedDateTime}, based on this one, with the amount
+     * in terms of the unit subtracted. If it is not possible to subtract the amount,
+     * because the unit is not supported or for some other reason, an exception is thrown.
+     * <p>
+     * The calculation for date and time units differ.
+     * <p>
+     * Date units operate on the local time-line.
+     * The period is first subtracted from the local date-time, then converted back
+     * to a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofLocal(LocalDateTime, ZoneId, ZoneOffset)}
+     * with the offset before the subtraction.
+     * <p>
+     * Time units operate on the instant time-line.
+     * The period is first subtracted from the local date-time, then converted back to
+     * a zoned date-time using the zone ID.
+     * The conversion uses {@link #ofInstant(LocalDateTime, ZoneOffset, ZoneId)}
+     * with the offset before the subtraction.
+     * <p>
+     * This method is equivalent to {@link #plus(long, TemporalUnit)} with the amount negated.
+     * See that method for a full description of how addition, and thus subtraction, works.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the amount of the unit to subtract from the result, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return a {@code ZonedDateTime} based on this date-time with the specified amount subtracted, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public ZonedDateTime minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of years subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusYears(long) subtracting years} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param years  the years to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusYears(long years) {
+        return (years == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-years));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of months subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusMonths(long) subtracting months} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param months  the months to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusMonths(long months) {
+        return (months == Long.MIN_VALUE ? plusMonths(Long.MAX_VALUE).plusMonths(1) : plusMonths(-months));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of weeks subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusWeeks(long) subtracting weeks} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeks  the weeks to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusWeeks(long weeks) {
+        return (weeks == Long.MIN_VALUE ? plusWeeks(Long.MAX_VALUE).plusWeeks(1) : plusWeeks(-weeks));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of days subtracted.
+     * <p>
+     * This operates on the local time-line,
+     * {@link LocalDateTime#minusDays(long) subtracting days} to the local date-time.
+     * This is then converted back to a {@code ZonedDateTime}, using the zone ID
+     * to obtain the offset.
+     * <p>
+     * When converting back to {@code ZonedDateTime}, if the local date-time is in an overlap,
+     * then the offset will be retained if possible, otherwise the earlier offset will be used.
+     * If in a gap, the local date-time will be adjusted forward by the length of the gap.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param days  the days to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusDays(long days) {
+        return (days == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-days));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of hours subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one hour will
+     * always be a duration of one hour earlier.
+     * This may cause the local date-time to change by an amount other than one hour.
+     * Note that this is a different approach to that used by days, months and years,
+     * thus subtracting one day is not the same as adding 24 hours.
+     * <p>
+     * For example, consider a time-zone where the spring DST cutover means that the
+     * local times 01:00 to 01:59 occur twice changing from offset +02:00 to +01:00.
+     * <ul>
+     * <li>Subtracting one hour from 02:30+01:00 will result in 01:30+02:00
+     * <li>Subtracting one hour from 01:30+01:00 will result in 01:30+02:00
+     * <li>Subtracting one hour from 01:30+02:00 will result in 00:30+01:00
+     * <li>Subtracting three hours from 02:30+01:00 will result in 00:30+02:00
+     * </ul>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param hours  the hours to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the hours subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusHours(long hours) {
+        return (hours == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hours));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of minutes subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one minute will
+     * always be a duration of one minute earlier.
+     * This may cause the local date-time to change by an amount other than one minute.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param minutes  the minutes to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the minutes subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusMinutes(long minutes) {
+        return (minutes == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutes));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of seconds subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one second will
+     * always be a duration of one second earlier.
+     * This may cause the local date-time to change by an amount other than one second.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param seconds  the seconds to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the seconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusSeconds(long seconds) {
+        return (seconds == Long.MIN_VALUE ? plusSeconds(Long.MAX_VALUE).plusSeconds(1) : plusSeconds(-seconds));
+    }
+
+    /**
+     * Returns a copy of this {@code ZonedDateTime} with the specified number of nanoseconds subtracted.
+     * <p>
+     * This operates on the instant time-line, such that subtracting one nano will
+     * always be a duration of one nano earlier.
+     * This may cause the local date-time to change by an amount other than one nano.
+     * Note that this is a different approach to that used by days, months and years.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param nanos  the nanos to subtract, may be negative
+     * @return a {@code ZonedDateTime} based on this date-time with the nanoseconds subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    public ZonedDateTime minusNanos(long nanos) {
+        return (nanos == Long.MIN_VALUE ? plusNanos(Long.MAX_VALUE).plusNanos(1) : plusNanos(-nanos));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override  // override for Javadoc
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.localDate()) {
+            return (R) toLocalDate();
+        }
+        return ChronoZonedDateTime.super.query(query);
+    }
+
+    /**
+     * Calculates the amount of time until another date-time in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code ZonedDateTime}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified date-time.
+     * The result will be negative if the end is before the start.
+     * For example, the amount in days between two date-times can be calculated
+     * using {@code startDateTime.until(endDateTime, DAYS)}.
+     * <p>
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code ZonedDateTime} using {@link #from(TemporalAccessor)}.
+     * If the time-zone differs between the two zoned date-times, the specified
+     * end date-time is normalized to have the same zone as this date-time.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two date-times.
+     * For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z
+     * will only be one month as it is one minute short of two months.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MONTHS);
+     *   amount = MONTHS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code NANOS}, {@code MICROS}, {@code MILLIS}, {@code SECONDS},
+     * {@code MINUTES}, {@code HOURS} and {@code HALF_DAYS}, {@code DAYS},
+     * {@code WEEKS}, {@code MONTHS}, {@code YEARS}, {@code DECADES},
+     * {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS} are supported.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * The calculation for date and time units differ.
+     * <p>
+     * Date units operate on the local time-line, using the local date-time.
+     * For example, the period from noon on day 1 to noon the following day
+     * in days will always be counted as exactly one day, irrespective of whether
+     * there was a daylight savings change or not.
+     * <p>
+     * Time units operate on the instant time-line.
+     * The calculation effectively converts both zoned date-times to instants
+     * and then calculates the period between the instants.
+     * For example, the period from noon on day 1 to noon the following day
+     * in hours may be 23, 24 or 25 hours (or some other amount) depending on
+     * whether there was a daylight savings change or not.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal
+     * as the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to a {@code ZonedDateTime}, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this date-time and the end date-time
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code ZonedDateTime}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        ZonedDateTime end = ZonedDateTime.from(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            end = end.withZoneSameInstant(zone);
+            if (unit.isDateBased()) {
+                return dateTime.until(end.dateTime, unit);
+            } else {
+                return toOffsetDateTime().until(end.toOffsetDateTime(), unit);
+            }
+        }
+        return unit.between(this, end);
+    }
+
+    /**
+     * Formats this date-time using the specified formatter.
+     * <p>
+     * This date-time will be passed to the formatter to produce a string.
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    @Override  // override for Javadoc and performance
+    public String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code OffsetDateTime}.
+     * <p>
+     * This creates an offset date-time using the local date-time and offset.
+     * The zone ID is ignored.
+     *
+     * @return an offset date-time representing the same local date-time and offset, not null
+     */
+    public OffsetDateTime toOffsetDateTime() {
+        return OffsetDateTime.of(dateTime, offset);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * The comparison is based on the offset date-time and the zone.
+     * Only objects of type {@code ZonedDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ZonedDateTime) {
+            ZonedDateTime other = (ZonedDateTime) obj;
+            return dateTime.equals(other.dateTime) &&
+                offset.equals(other.offset) &&
+                zone.equals(other.zone);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return dateTime.hashCode() ^ offset.hashCode() ^ Integer.rotateLeft(zone.hashCode(), 3);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}, such as
+     * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
+     * <p>
+     * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.
+     * If the {@code ZoneId} is not the same as the offset, then the ID is output.
+     * The output is compatible with ISO-8601 if the offset and ID are the same.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override  // override for Javadoc
+    public String toString() {
+        String str = dateTime.toString() + offset.toString();
+        if (offset != zone) {
+            str += '[' + zone.toString() + ']';
+        }
+        return str;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(6);  // identifies a ZonedDateTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalDateTime">dateTime</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
+     *  // the <a href="../../serialized-form.html#java.time.ZoneId">zone ID</a> excluding the one byte header
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZONE_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        dateTime.writeExternal(out);
+        offset.writeExternal(out);
+        zone.write(out);
+    }
+
+    static ZonedDateTime readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        LocalDateTime dateTime = LocalDateTime.readExternal(in);
+        ZoneOffset offset = ZoneOffset.readExternal(in);
+        ZoneId zone = (ZoneId) Ser.read(in);
+        return ZonedDateTime.ofLenient(dateTime, offset, zone);
+    }
+
+}
diff --git a/java/time/chrono/AbstractChronology.java b/java/time/chrono/AbstractChronology.java
new file mode 100644
index 0000000..c2e91d7
--- /dev/null
+++ b/java/time/chrono/AbstractChronology.java
@@ -0,0 +1,785 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.TemporalAdjusters.nextOrSame;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAdjusters;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import sun.util.logging.PlatformLogger;
+
+/**
+ * An abstract implementation of a calendar system, used to organize and identify dates.
+ * <p>
+ * The main date and time API is built on the ISO calendar system.
+ * The chronology operates behind the scenes to represent the general concept of a calendar system.
+ * <p>
+ * See {@link Chronology} for more details.
+ *
+ * @implSpec
+ * This class is separated from the {@code Chronology} interface so that the static methods
+ * are not inherited. While {@code Chronology} can be implemented directly, it is strongly
+ * recommended to extend this abstract class instead.
+ * <p>
+ * This class must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @since 1.8
+ */
+public abstract class AbstractChronology implements Chronology {
+
+    /**
+     * ChronoLocalDate order constant.
+     */
+    static final Comparator<ChronoLocalDate> DATE_ORDER =
+        (Comparator<ChronoLocalDate> & Serializable) (date1, date2) -> {
+            return Long.compare(date1.toEpochDay(), date2.toEpochDay());
+        };
+    /**
+     * ChronoLocalDateTime order constant.
+     */
+    static final Comparator<ChronoLocalDateTime<? extends ChronoLocalDate>> DATE_TIME_ORDER =
+        (Comparator<ChronoLocalDateTime<? extends ChronoLocalDate>> & Serializable) (dateTime1, dateTime2) -> {
+            int cmp = Long.compare(dateTime1.toLocalDate().toEpochDay(), dateTime2.toLocalDate().toEpochDay());
+            if (cmp == 0) {
+                cmp = Long.compare(dateTime1.toLocalTime().toNanoOfDay(), dateTime2.toLocalTime().toNanoOfDay());
+            }
+            return cmp;
+        };
+    /**
+     * ChronoZonedDateTime order constant.
+     */
+    static final Comparator<ChronoZonedDateTime<?>> INSTANT_ORDER =
+            (Comparator<ChronoZonedDateTime<?>> & Serializable) (dateTime1, dateTime2) -> {
+                int cmp = Long.compare(dateTime1.toEpochSecond(), dateTime2.toEpochSecond());
+                if (cmp == 0) {
+                    cmp = Long.compare(dateTime1.toLocalTime().getNano(), dateTime2.toLocalTime().getNano());
+                }
+                return cmp;
+            };
+
+    /**
+     * Map of available calendars by ID.
+     */
+    private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_ID = new ConcurrentHashMap<>();
+    /**
+     * Map of available calendars by calendar type.
+     */
+    private static final ConcurrentHashMap<String, Chronology> CHRONOS_BY_TYPE = new ConcurrentHashMap<>();
+
+    /**
+     * Register a Chronology by its ID and type for lookup by {@link #of(String)}.
+     * Chronologies must not be registered until they are completely constructed.
+     * Specifically, not in the constructor of Chronology.
+     *
+     * @param chrono the chronology to register; not null
+     * @return the already registered Chronology if any, may be null
+     */
+    static Chronology registerChrono(Chronology chrono) {
+        return registerChrono(chrono, chrono.getId());
+    }
+
+    /**
+     * Register a Chronology by ID and type for lookup by {@link #of(String)}.
+     * Chronos must not be registered until they are completely constructed.
+     * Specifically, not in the constructor of Chronology.
+     *
+     * @param chrono the chronology to register; not null
+     * @param id the ID to register the chronology; not null
+     * @return the already registered Chronology if any, may be null
+     */
+    static Chronology registerChrono(Chronology chrono, String id) {
+        Chronology prev = CHRONOS_BY_ID.putIfAbsent(id, chrono);
+        if (prev == null) {
+            String type = chrono.getCalendarType();
+            if (type != null) {
+                CHRONOS_BY_TYPE.putIfAbsent(type, chrono);
+            }
+        }
+        return prev;
+    }
+
+    /**
+     * Initialization of the maps from id and type to Chronology.
+     * The ServiceLoader is used to find and register any implementations
+     * of {@link java.time.chrono.AbstractChronology} found in the bootclass loader.
+     * The built-in chronologies are registered explicitly.
+     * Calendars configured via the Thread's context classloader are local
+     * to that thread and are ignored.
+     * <p>
+     * The initialization is done only once using the registration
+     * of the IsoChronology as the test and the final step.
+     * Multiple threads may perform the initialization concurrently.
+     * Only the first registration of each Chronology is retained by the
+     * ConcurrentHashMap.
+     * @return true if the cache was initialized
+     */
+    private static boolean initCache() {
+        if (CHRONOS_BY_ID.get("ISO") == null) {
+            // Initialization is incomplete
+
+            // Register built-in Chronologies
+            registerChrono(HijrahChronology.INSTANCE);
+            registerChrono(JapaneseChronology.INSTANCE);
+            registerChrono(MinguoChronology.INSTANCE);
+            registerChrono(ThaiBuddhistChronology.INSTANCE);
+
+            // Register Chronologies from the ServiceLoader
+            @SuppressWarnings("rawtypes")
+            ServiceLoader<AbstractChronology> loader =  ServiceLoader.load(AbstractChronology.class, null);
+            for (AbstractChronology chrono : loader) {
+                String id = chrono.getId();
+                if (id.equals("ISO") || registerChrono(chrono) != null) {
+                    // Log the attempt to replace an existing Chronology
+                    PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
+                    logger.warning("Ignoring duplicate Chronology, from ServiceLoader configuration "  + id);
+                }
+            }
+
+            // finally, register IsoChronology to mark initialization is complete
+            registerChrono(IsoChronology.INSTANCE);
+            return true;
+        }
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chronology} from a locale.
+     * <p>
+     * See {@link Chronology#ofLocale(Locale)}.
+     *
+     * @param locale  the locale to use to obtain the calendar system, not null
+     * @return the calendar system associated with the locale, not null
+     * @throws java.time.DateTimeException if the locale-specified calendar cannot be found
+     */
+    static Chronology ofLocale(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        String type = locale.getUnicodeLocaleType("ca");
+        if (type == null || "iso".equals(type) || "iso8601".equals(type)) {
+            return IsoChronology.INSTANCE;
+        }
+        // Not pre-defined; lookup by the type
+        do {
+            Chronology chrono = CHRONOS_BY_TYPE.get(type);
+            if (chrono != null) {
+                return chrono;
+            }
+            // If not found, do the initialization (once) and repeat the lookup
+        } while (initCache());
+
+        // Look for a Chronology using ServiceLoader of the Thread's ContextClassLoader
+        // Application provided Chronologies must not be cached
+        @SuppressWarnings("rawtypes")
+        ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
+        for (Chronology chrono : loader) {
+            if (type.equals(chrono.getCalendarType())) {
+                return chrono;
+            }
+        }
+        throw new DateTimeException("Unknown calendar system: " + type);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chronology} from a chronology ID or
+     * calendar system type.
+     * <p>
+     * See {@link Chronology#of(String)}.
+     *
+     * @param id  the chronology ID or calendar system type, not null
+     * @return the chronology with the identifier requested, not null
+     * @throws java.time.DateTimeException if the chronology cannot be found
+     */
+    static Chronology of(String id) {
+        Objects.requireNonNull(id, "id");
+        do {
+            Chronology chrono = of0(id);
+            if (chrono != null) {
+                return chrono;
+            }
+            // If not found, do the initialization (once) and repeat the lookup
+        } while (initCache());
+
+        // Look for a Chronology using ServiceLoader of the Thread's ContextClassLoader
+        // Application provided Chronologies must not be cached
+        @SuppressWarnings("rawtypes")
+        ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
+        for (Chronology chrono : loader) {
+            if (id.equals(chrono.getId()) || id.equals(chrono.getCalendarType())) {
+                return chrono;
+            }
+        }
+        throw new DateTimeException("Unknown chronology: " + id);
+    }
+
+    /**
+     * Obtains an instance of {@code Chronology} from a chronology ID or
+     * calendar system type.
+     *
+     * @param id  the chronology ID or calendar system type, not null
+     * @return the chronology with the identifier requested, or {@code null} if not found
+     */
+    private static Chronology of0(String id) {
+        Chronology chrono = CHRONOS_BY_ID.get(id);
+        if (chrono == null) {
+            chrono = CHRONOS_BY_TYPE.get(id);
+        }
+        return chrono;
+    }
+
+    /**
+     * Returns the available chronologies.
+     * <p>
+     * Each returned {@code Chronology} is available for use in the system.
+     * The set of chronologies includes the system chronologies and
+     * any chronologies provided by the application via ServiceLoader
+     * configuration.
+     *
+     * @return the independent, modifiable set of the available chronology IDs, not null
+     */
+    static Set<Chronology> getAvailableChronologies() {
+        initCache();       // force initialization
+        HashSet<Chronology> chronos = new HashSet<>(CHRONOS_BY_ID.values());
+
+        /// Add in Chronologies from the ServiceLoader configuration
+        @SuppressWarnings("rawtypes")
+        ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class);
+        for (Chronology chrono : loader) {
+            chronos.add(chrono);
+        }
+        return chronos;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     */
+    protected AbstractChronology() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Resolves parsed {@code ChronoField} values into a date during parsing.
+     * <p>
+     * Most {@code TemporalField} implementations are resolved using the
+     * resolve method on the field. By contrast, the {@code ChronoField} class
+     * defines fields that only have meaning relative to the chronology.
+     * As such, {@code ChronoField} date fields are resolved here in the
+     * context of a specific chronology.
+     * <p>
+     * {@code ChronoField} instances are resolved by this method, which may
+     * be overridden in subclasses.
+     * <ul>
+     * <li>{@code EPOCH_DAY} - If present, this is converted to a date and
+     *  all other date fields are then cross-checked against the date.
+     * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
+     *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
+     *  then the field is validated.
+     * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
+     *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
+     *  range is not validated, in smart and strict mode it is. The {@code ERA} is
+     *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
+     *  present, and the mode is smart or lenient, then the last available era
+     *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
+     *  left untouched. If only the {@code ERA} is present, then it is left untouched.
+     * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
+     *  If all three are present, then they are combined to form a date.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is smart or strict, then the month and day are validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first day of the first month in the requested year,
+     *  then adding the difference in months, then the difference in days.
+     *  If the mode is smart, and the day-of-month is greater than the maximum for
+     *  the year-month, then the day-of-month is adjusted to the last day-of-month.
+     *  If the mode is strict, then the three fields must form a valid date.
+     * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
+     *  If both are present, then they are combined to form a date.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first day of the requested year, then adding
+     *  the difference in days.
+     *  If the mode is smart or strict, then the two fields must form a valid date.
+     * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
+     *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
+     *  If all four are present, then they are combined to form a date.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first day of the first month in the requested year, then adding
+     *  the difference in months, then the difference in weeks, then in days.
+     *  If the mode is smart or strict, then the all four fields are validated to
+     *  their outer ranges. The date is then combined in a manner equivalent to
+     *  creating a date on the first day of the requested year and month, then adding
+     *  the amount in weeks and days to reach their values. If the mode is strict,
+     *  the date is additionally validated to check that the day and week adjustment
+     *  did not change the month.
+     * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
+     *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
+     *  form a date. The approach is the same as described above for
+     *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
+     *  The day-of-week is adjusted as the next or same matching day-of-week once
+     *  the years, months and weeks have been handled.
+     * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
+     *  If all three are present, then they are combined to form a date.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first day of the requested year, then adding
+     *  the difference in weeks, then in days.
+     *  If the mode is smart or strict, then the all three fields are validated to
+     *  their outer ranges. The date is then combined in a manner equivalent to
+     *  creating a date on the first day of the requested year, then adding
+     *  the amount in weeks and days to reach their values. If the mode is strict,
+     *  the date is additionally validated to check that the day and week adjustment
+     *  did not change the year.
+     * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
+     *  If all three are present, then they are combined to form a date.
+     *  The approach is the same as described above for years and weeks in
+     *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
+     *  next or same matching day-of-week once the years and weeks have been handled.
+     * </ul>
+     * <p>
+     * The default implementation is suitable for most calendar systems.
+     * If {@link java.time.temporal.ChronoField#YEAR_OF_ERA} is found without an {@link java.time.temporal.ChronoField#ERA}
+     * then the last era in {@link #eras()} is used.
+     * The implementation assumes a 7 day week, that the first day-of-month
+     * has the value 1, that first day-of-year has the value 1, and that the
+     * first of the month and year always exists.
+     *
+     * @param fieldValues  the map of fields to values, which can be updated, not null
+     * @param resolverStyle  the requested type of resolve, not null
+     * @return the resolved date, null if insufficient information to create a date
+     * @throws java.time.DateTimeException if the date cannot be resolved, typically
+     *  because of a conflict in the input data
+     */
+    @Override
+    public ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        // check epoch-day before inventing era
+        if (fieldValues.containsKey(EPOCH_DAY)) {
+            return dateEpochDay(fieldValues.remove(EPOCH_DAY));
+        }
+
+        // fix proleptic month before inventing era
+        resolveProlepticMonth(fieldValues, resolverStyle);
+
+        // invent era if necessary to resolve year-of-era
+        ChronoLocalDate resolved = resolveYearOfEra(fieldValues, resolverStyle);
+        if (resolved != null) {
+            return resolved;
+        }
+
+        // build date
+        if (fieldValues.containsKey(YEAR)) {
+            if (fieldValues.containsKey(MONTH_OF_YEAR)) {
+                if (fieldValues.containsKey(DAY_OF_MONTH)) {
+                    return resolveYMD(fieldValues, resolverStyle);
+                }
+                if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) {
+                    if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) {
+                        return resolveYMAA(fieldValues, resolverStyle);
+                    }
+                    if (fieldValues.containsKey(DAY_OF_WEEK)) {
+                        return resolveYMAD(fieldValues, resolverStyle);
+                    }
+                }
+            }
+            if (fieldValues.containsKey(DAY_OF_YEAR)) {
+                return resolveYD(fieldValues, resolverStyle);
+            }
+            if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) {
+                if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) {
+                    return resolveYAA(fieldValues, resolverStyle);
+                }
+                if (fieldValues.containsKey(DAY_OF_WEEK)) {
+                    return resolveYAD(fieldValues, resolverStyle);
+                }
+            }
+        }
+        return null;
+    }
+
+    void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
+        if (pMonth != null) {
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                PROLEPTIC_MONTH.checkValidValue(pMonth);
+            }
+            // first day-of-month is likely to be safest for setting proleptic-month
+            // cannot add to year zero, as not all chronologies have a year zero
+            ChronoLocalDate chronoDate = dateNow()
+                    .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth);
+            addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR));
+            addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR));
+        }
+    }
+
+    ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
+        if (yoeLong != null) {
+            Long eraLong = fieldValues.remove(ERA);
+            int yoe;
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);
+            } else {
+                yoe = Math.toIntExact(yoeLong);
+            }
+            if (eraLong != null) {
+                Era eraObj = eraOf(range(ERA).checkValidIntValue(eraLong, ERA));
+                addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
+            } else {
+                if (fieldValues.containsKey(YEAR)) {
+                    int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR);
+                    ChronoLocalDate chronoDate = dateYearDay(year, 1);
+                    addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe));
+                } else if (resolverStyle == ResolverStyle.STRICT) {
+                    // do not invent era if strict
+                    // reinstate the field removed earlier, no cross-check issues
+                    fieldValues.put(YEAR_OF_ERA, yoeLong);
+                } else {
+                    List<Era> eras = eras();
+                    if (eras.isEmpty()) {
+                        addFieldValue(fieldValues, YEAR, yoe);
+                    } else {
+                        Era eraObj = eras.get(eras.size() - 1);
+                        addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe));
+                    }
+                }
+            }
+        } else if (fieldValues.containsKey(ERA)) {
+            range(ERA).checkValidValue(fieldValues.get(ERA), ERA);  // always validated
+        }
+        return null;
+    }
+
+    ChronoLocalDate resolveYMD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
+            long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
+            return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
+        }
+        int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
+        ValueRange domRange = range(DAY_OF_MONTH);
+        int dom = domRange.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
+        if (resolverStyle == ResolverStyle.SMART) {  // previous valid
+            try {
+                return date(y, moy, dom);
+            } catch (DateTimeException ex) {
+                return date(y, moy, 1).with(TemporalAdjusters.lastDayOfMonth());
+            }
+        }
+        return date(y, moy, dom);
+    }
+
+    ChronoLocalDate resolveYD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
+            return dateYearDay(y, 1).plus(days, DAYS);
+        }
+        int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
+        return dateYearDay(y, doy);  // smart is same as strict
+    }
+
+    ChronoLocalDate resolveYMAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
+            long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
+            long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1);
+            return date(y, 1, 1).plus(months, MONTHS).plus(weeks, WEEKS).plus(days, DAYS);
+        }
+        int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
+        int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
+        int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH);
+        ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7 + (ad - 1), DAYS);
+        if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) {
+            throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
+        }
+        return date;
+    }
+
+    ChronoLocalDate resolveYMAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
+            long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
+            long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
+            return resolveAligned(date(y, 1, 1), months, weeks, dow);
+        }
+        int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
+        int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH);
+        int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
+        ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow)));
+        if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) {
+            throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
+        }
+        return date;
+    }
+
+    ChronoLocalDate resolveYAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
+            long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1);
+            return dateYearDay(y, 1).plus(weeks, WEEKS).plus(days, DAYS);
+        }
+        int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
+        int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR);
+        ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7 + (ad - 1), DAYS);
+        if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) {
+            throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
+        }
+        return date;
+    }
+
+    ChronoLocalDate resolveYAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
+            long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
+            return resolveAligned(dateYearDay(y, 1), 0, weeks, dow);
+        }
+        int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR);
+        int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK);
+        ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow)));
+        if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) {
+            throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
+        }
+        return date;
+    }
+
+    ChronoLocalDate resolveAligned(ChronoLocalDate base, long months, long weeks, long dow) {
+        ChronoLocalDate date = base.plus(months, MONTHS).plus(weeks, WEEKS);
+        if (dow > 7) {
+            date = date.plus((dow - 1) / 7, WEEKS);
+            dow = ((dow - 1) % 7) + 1;
+        } else if (dow < 1) {
+            date = date.plus(Math.subtractExact(dow,  7) / 7, WEEKS);
+            dow = ((dow + 6) % 7) + 1;
+        }
+        return date.with(nextOrSame(DayOfWeek.of((int) dow)));
+    }
+
+    /**
+     * Adds a field-value pair to the map, checking for conflicts.
+     * <p>
+     * If the field is not already present, then the field-value pair is added to the map.
+     * If the field is already present and it has the same value as that specified, no action occurs.
+     * If the field is already present and it has a different value to that specified, then
+     * an exception is thrown.
+     *
+     * @param field  the field to add, not null
+     * @param value  the value to add, not null
+     * @throws java.time.DateTimeException if the field is already present with a different value
+     */
+    void addFieldValue(Map<TemporalField, Long> fieldValues, ChronoField field, long value) {
+        Long old = fieldValues.get(field);  // check first for better error message
+        if (old != null && old.longValue() != value) {
+            throw new DateTimeException("Conflict found: " + field + " " + old + " differs from " + field + " " + value);
+        }
+        fieldValues.put(field, value);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this chronology to another chronology.
+     * <p>
+     * The comparison order first by the chronology ID string, then by any
+     * additional information specific to the subclass.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @implSpec
+     * This implementation compares the chronology ID.
+     * Subclasses must compare any additional state that they store.
+     *
+     * @param other  the other chronology to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(Chronology other) {
+        return getId().compareTo(other.getId());
+    }
+
+    /**
+     * Checks if this chronology is equal to another chronology.
+     * <p>
+     * The comparison is based on the entire state of the object.
+     *
+     * @implSpec
+     * This implementation checks the type and calls
+     * {@link #compareTo(java.time.chrono.Chronology)}.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other chronology
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+           return true;
+        }
+        if (obj instanceof AbstractChronology) {
+            return compareTo((AbstractChronology) obj) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this chronology.
+     * <p>
+     * The hash code should be based on the entire state of the object.
+     *
+     * @implSpec
+     * This implementation is based on the chronology ID and class.
+     * Subclasses should add any additional state that they store.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return getClass().hashCode() ^ getId().hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this chronology as a {@code String}, using the chronology ID.
+     *
+     * @return a string representation of this chronology, not null
+     */
+    @Override
+    public String toString() {
+        return getId();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(1);  // identifies this as a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    Object writeReplace() {
+        return new Ser(Ser.CHRONO_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeUTF(getId());
+    }
+
+    static Chronology readExternal(DataInput in) throws IOException {
+        String id = in.readUTF();
+        return Chronology.of(id);
+    }
+
+}
diff --git a/java/time/chrono/ChronoLocalDate.java b/java/time/chrono/ChronoLocalDate.java
new file mode 100644
index 0000000..5848e94
--- /dev/null
+++ b/java/time/chrono/ChronoLocalDate.java
@@ -0,0 +1,799 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date without time-of-day or time-zone in an arbitrary chronology, intended
+ * for advanced globalization use cases.
+ * <p>
+ * <b>Most applications should declare method signatures, fields and variables
+ * as {@link LocalDate}, not this interface.</b>
+ * <p>
+ * A {@code ChronoLocalDate} is the abstract representation of a date where the
+ * {@code Chronology chronology}, or calendar system, is pluggable.
+ * The date is defined in terms of fields expressed by {@link TemporalField},
+ * where most common implementations are defined in {@link ChronoField}.
+ * The chronology defines how the calendar system operates and the meaning of
+ * the standard fields.
+ *
+ * <h3>When to use this interface</h3>
+ * The design of the API encourages the use of {@code LocalDate} rather than this
+ * interface, even in the case where the application needs to deal with multiple
+ * calendar systems.
+ * <p>
+ * This concept can seem surprising at first, as the natural way to globalize an
+ * application might initially appear to be to abstract the calendar system.
+ * However, as explored below, abstracting the calendar system is usually the wrong
+ * approach, resulting in logic errors and hard to find bugs.
+ * As such, it should be considered an application-wide architectural decision to choose
+ * to use this interface as opposed to {@code LocalDate}.
+ *
+ * <h3>Architectural issues to consider</h3>
+ * These are some of the points that must be considered before using this interface
+ * throughout an application.
+ * <p>
+ * 1) Applications using this interface, as opposed to using just {@code LocalDate},
+ * face a significantly higher probability of bugs. This is because the calendar system
+ * in use is not known at development time. A key cause of bugs is where the developer
+ * applies assumptions from their day-to-day knowledge of the ISO calendar system
+ * to code that is intended to deal with any arbitrary calendar system.
+ * The section below outlines how those assumptions can cause problems
+ * The primary mechanism for reducing this increased risk of bugs is a strong code review process.
+ * This should also be considered a extra cost in maintenance for the lifetime of the code.
+ * <p>
+ * 2) This interface does not enforce immutability of implementations.
+ * While the implementation notes indicate that all implementations must be immutable
+ * there is nothing in the code or type system to enforce this. Any method declared
+ * to accept a {@code ChronoLocalDate} could therefore be passed a poorly or
+ * maliciously written mutable implementation.
+ * <p>
+ * 3) Applications using this interface  must consider the impact of eras.
+ * {@code LocalDate} shields users from the concept of eras, by ensuring that {@code getYear()}
+ * returns the proleptic year. That decision ensures that developers can think of
+ * {@code LocalDate} instances as consisting of three fields - year, month-of-year and day-of-month.
+ * By contrast, users of this interface must think of dates as consisting of four fields -
+ * era, year-of-era, month-of-year and day-of-month. The extra era field is frequently
+ * forgotten, yet it is of vital importance to dates in an arbitrary calendar system.
+ * For example, in the Japanese calendar system, the era represents the reign of an Emperor.
+ * Whenever one reign ends and another starts, the year-of-era is reset to one.
+ * <p>
+ * 4) The only agreed international standard for passing a date between two systems
+ * is the ISO-8601 standard which requires the ISO calendar system. Using this interface
+ * throughout the application will inevitably lead to the requirement to pass the date
+ * across a network or component boundary, requiring an application specific protocol or format.
+ * <p>
+ * 5) Long term persistence, such as a database, will almost always only accept dates in the
+ * ISO-8601 calendar system (or the related Julian-Gregorian). Passing around dates in other
+ * calendar systems increases the complications of interacting with persistence.
+ * <p>
+ * 6) Most of the time, passing a {@code ChronoLocalDate} throughout an application
+ * is unnecessary, as discussed in the last section below.
+ *
+ * <h3>False assumptions causing bugs in multi-calendar system code</h3>
+ * As indicated above, there are many issues to consider when try to use and manipulate a
+ * date in an arbitrary calendar system. These are some of the key issues.
+ * <p>
+ * Code that queries the day-of-month and assumes that the value will never be more than
+ * 31 is invalid. Some calendar systems have more than 31 days in some months.
+ * <p>
+ * Code that adds 12 months to a date and assumes that a year has been added is invalid.
+ * Some calendar systems have a different number of months, such as 13 in the Coptic or Ethiopic.
+ * <p>
+ * Code that adds one month to a date and assumes that the month-of-year value will increase
+ * by one or wrap to the next year is invalid. Some calendar systems have a variable number
+ * of months in a year, such as the Hebrew.
+ * <p>
+ * Code that adds one month, then adds a second one month and assumes that the day-of-month
+ * will remain close to its original value is invalid. Some calendar systems have a large difference
+ * between the length of the longest month and the length of the shortest month.
+ * For example, the Coptic or Ethiopic have 12 months of 30 days and 1 month of 5 days.
+ * <p>
+ * Code that adds seven days and assumes that a week has been added is invalid.
+ * Some calendar systems have weeks of other than seven days, such as the French Revolutionary.
+ * <p>
+ * Code that assumes that because the year of {@code date1} is greater than the year of {@code date2}
+ * then {@code date1} is after {@code date2} is invalid. This is invalid for all calendar systems
+ * when referring to the year-of-era, and especially untrue of the Japanese calendar system
+ * where the year-of-era restarts with the reign of every new Emperor.
+ * <p>
+ * Code that treats month-of-year one and day-of-month one as the start of the year is invalid.
+ * Not all calendar systems start the year when the month value is one.
+ * <p>
+ * In general, manipulating a date, and even querying a date, is wide open to bugs when the
+ * calendar system is unknown at development time. This is why it is essential that code using
+ * this interface is subjected to additional code reviews. It is also why an architectural
+ * decision to avoid this interface type is usually the correct one.
+ *
+ * <h3>Using LocalDate instead</h3>
+ * The primary alternative to using this interface throughout your application is as follows.
+ * <ul>
+ * <li>Declare all method signatures referring to dates in terms of {@code LocalDate}.
+ * <li>Either store the chronology (calendar system) in the user profile or lookup
+ *  the chronology from the user locale
+ * <li>Convert the ISO {@code LocalDate} to and from the user's preferred calendar system during
+ *  printing and parsing
+ * </ul>
+ * This approach treats the problem of globalized calendar systems as a localization issue
+ * and confines it to the UI layer. This approach is in keeping with other localization
+ * issues in the java platform.
+ * <p>
+ * As discussed above, performing calculations on a date where the rules of the calendar system
+ * are pluggable requires skill and is not recommended.
+ * Fortunately, the need to perform calculations on a date in an arbitrary calendar system
+ * is extremely rare. For example, it is highly unlikely that the business rules of a library
+ * book rental scheme will allow rentals to be for one month, where meaning of the month
+ * is dependent on the user's preferred calendar system.
+ * <p>
+ * A key use case for calculations on a date in an arbitrary calendar system is producing
+ * a month-by-month calendar for display and user interaction. Again, this is a UI issue,
+ * and use of this interface solely within a few methods of the UI layer may be justified.
+ * <p>
+ * In any other part of the system, where a date must be manipulated in a calendar system
+ * other than ISO, the use case will generally specify the calendar system to use.
+ * For example, an application may need to calculate the next Islamic or Hebrew holiday
+ * which may require manipulating the date.
+ * This kind of use case can be handled as follows:
+ * <ul>
+ * <li>start from the ISO {@code LocalDate} being passed to the method
+ * <li>convert the date to the alternate calendar system, which for this use case is known
+ *  rather than arbitrary
+ * <li>perform the calculation
+ * <li>convert back to {@code LocalDate}
+ * </ul>
+ * Developers writing low-level frameworks or libraries should also avoid this interface.
+ * Instead, one of the two general purpose access interfaces should be used.
+ * Use {@link TemporalAccessor} if read-only access is required, or use {@link Temporal}
+ * if read-write access is required.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ * <p>
+ * Additional calendar systems may be added to the system.
+ * See {@link Chronology} for more details.
+ *
+ * @since 1.8
+ */
+public interface ChronoLocalDate
+        extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate> {
+
+    /**
+     * Gets a comparator that compares {@code ChronoLocalDate} in
+     * time-line order ignoring the chronology.
+     * <p>
+     * This comparator differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the position of the date on the local time-line.
+     * The underlying comparison is equivalent to comparing the epoch-day.
+     *
+     * @return a comparator that compares in time-line order ignoring the chronology
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    static Comparator<ChronoLocalDate> timeLineOrder() {
+        return AbstractChronology.DATE_ORDER;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ChronoLocalDate} from a temporal object.
+     * <p>
+     * This obtains a local date based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ChronoLocalDate}.
+     * <p>
+     * The conversion extracts and combines the chronology and the date
+     * from the temporal object. The behavior is equivalent to using
+     * {@link Chronology#date(TemporalAccessor)} with the extracted chronology.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ChronoLocalDate::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date, not null
+     * @throws DateTimeException if unable to convert to a {@code ChronoLocalDate}
+     * @see Chronology#date(TemporalAccessor)
+     */
+    static ChronoLocalDate from(TemporalAccessor temporal) {
+        if (temporal instanceof ChronoLocalDate) {
+            return (ChronoLocalDate) temporal;
+        }
+        Objects.requireNonNull(temporal, "temporal");
+        Chronology chrono = temporal.query(TemporalQueries.chronology());
+        if (chrono == null) {
+            throw new DateTimeException("Unable to obtain ChronoLocalDate from TemporalAccessor: " + temporal.getClass());
+        }
+        return chrono.date(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the chronology, not null
+     */
+    Chronology getChronology();
+
+    /**
+     * Gets the era, as defined by the chronology.
+     * <p>
+     * The era is, conceptually, the largest division of the time-line.
+     * Most calendar systems have a single epoch dividing the time-line into two eras.
+     * However, some have multiple eras, such as one for the reign of each leader.
+     * The exact meaning is determined by the {@code Chronology}.
+     * <p>
+     * All correctly implemented {@code Era} classes are singletons, thus it
+     * is valid code to write {@code date.getEra() == SomeChrono.ERA_NAME)}.
+     * <p>
+     * This default implementation uses {@link Chronology#eraOf(int)}.
+     *
+     * @return the chronology specific era constant applicable at this date, not null
+     */
+    default Era getEra() {
+        return getChronology().eraOf(get(ERA));
+    }
+
+    /**
+     * Checks if the year is a leap year, as defined by the calendar system.
+     * <p>
+     * A leap-year is a year of a longer length than normal.
+     * The exact meaning is determined by the chronology with the constraint that
+     * a leap-year must imply a year-length longer than a non leap-year.
+     * <p>
+     * This default implementation uses {@link Chronology#isLeapYear(long)}.
+     *
+     * @return true if this date is in a leap year, false otherwise
+     */
+    default boolean isLeapYear() {
+        return getChronology().isLeapYear(getLong(YEAR));
+    }
+
+    /**
+     * Returns the length of the month represented by this date, as defined by the calendar system.
+     * <p>
+     * This returns the length of the month in days.
+     *
+     * @return the length of the month in days
+     */
+    int lengthOfMonth();
+
+    /**
+     * Returns the length of the year represented by this date, as defined by the calendar system.
+     * <p>
+     * This returns the length of the year in days.
+     * <p>
+     * The default implementation uses {@link #isLeapYear()} and returns 365 or 366.
+     *
+     * @return the length of the year in days
+     */
+    default int lengthOfYear() {
+        return (isLeapYear() ? 366 : 365);
+    }
+
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if the specified field can be queried on this date.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * The set of supported fields is defined by the chronology and normally includes
+     * all {@code ChronoField} date fields.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field can be queried, false if not
+     */
+    @Override
+    default boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field.isDateBased();
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to or subtracted from this date.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * The set of supported units is defined by the chronology and normally includes
+     * all {@code ChronoUnit} date units except {@code FOREVER}.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override
+    default boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit.isDateBased();
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    // override for covariant return type
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDate with(TemporalAdjuster adjuster) {
+        return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws UnsupportedTemporalTypeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return ChronoLocalDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDate plus(TemporalAmount amount) {
+        return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return ChronoLocalDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDate minus(TemporalAmount amount) {
+        return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws UnsupportedTemporalTypeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) {
+        return ChronoLocalDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date using the specified query.
+     * <p>
+     * This queries this date using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    default <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zoneId() || query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
+            return null;
+        } else if (query == TemporalQueries.localTime()) {
+            return null;
+        } else if (query == TemporalQueries.chronology()) {
+            return (R) getChronology();
+        } else if (query == TemporalQueries.precision()) {
+            return (R) DAYS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#EPOCH_DAY} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDate.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDate);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    default Temporal adjustInto(Temporal temporal) {
+        return temporal.with(EPOCH_DAY, toEpochDay());
+    }
+
+    /**
+     * Calculates the amount of time until another date in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two {@code ChronoLocalDate}
+     * objects in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified date.
+     * The result will be negative if the end is before the start.
+     * The {@code Temporal} passed to this method is converted to a
+     * {@code ChronoLocalDate} using {@link Chronology#date(TemporalAccessor)}.
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two dates.
+     * For example, the amount in days between two dates can be calculated
+     * using {@code startDate.until(endDate, DAYS)}.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   amount = start.until(end, MONTHS);
+     *   amount = MONTHS.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * The calculation is implemented in this method for {@link ChronoUnit}.
+     * The units {@code DAYS}, {@code WEEKS}, {@code MONTHS}, {@code YEARS},
+     * {@code DECADES}, {@code CENTURIES}, {@code MILLENNIA} and {@code ERAS}
+     * should be supported by all implementations.
+     * Other {@code ChronoUnit} values will throw an exception.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal as
+     * the second argument.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endExclusive  the end date, exclusive, which is converted to a
+     *  {@code ChronoLocalDate} in the same chronology, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this date and the end date
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to a {@code ChronoLocalDate}
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc
+    long until(Temporal endExclusive, TemporalUnit unit);
+
+    /**
+     * Calculates the period between this date and another date as a {@code ChronoPeriod}.
+     * <p>
+     * This calculates the period between two dates. All supplied chronologies
+     * calculate the period using years, months and days, however the
+     * {@code ChronoPeriod} API allows the period to be represented using other units.
+     * <p>
+     * The start and end points are {@code this} and the specified date.
+     * The result will be negative if the end is before the start.
+     * The negative sign will be the same in each of year, month and day.
+     * <p>
+     * The calculation is performed using the chronology of this date.
+     * If necessary, the input date will be converted to match.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param endDateExclusive  the end date, exclusive, which may be in any chronology, not null
+     * @return the period between this date and the end date, not null
+     * @throws DateTimeException if the period cannot be calculated
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    ChronoPeriod until(ChronoLocalDate endDateExclusive);
+
+    /**
+     * Formats this date using the specified formatter.
+     * <p>
+     * This date will be passed to the formatter to produce a string.
+     * <p>
+     * The default implementation must behave as follows:
+     * <pre>
+     *  return formatter.format(this);
+     * </pre>
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    default String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this date with a time to create a {@code ChronoLocalDateTime}.
+     * <p>
+     * This returns a {@code ChronoLocalDateTime} formed from this date at the specified time.
+     * All possible combinations of date and time are valid.
+     *
+     * @param localTime  the local time to use, not null
+     * @return the local date-time formed from this date and the specified time, not null
+     */
+    @SuppressWarnings("unchecked")
+    default ChronoLocalDateTime<?> atTime(LocalTime localTime) {
+        return ChronoLocalDateTimeImpl.of(this, localTime);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date to the Epoch Day.
+     * <p>
+     * The {@link ChronoField#EPOCH_DAY Epoch Day count} is a simple
+     * incrementing count of days where day 0 is 1970-01-01 (ISO).
+     * This definition is the same for all chronologies, enabling conversion.
+     * <p>
+     * This default implementation queries the {@code EPOCH_DAY} field.
+     *
+     * @return the Epoch Day equivalent to this date
+     */
+    default long toEpochDay() {
+        return getLong(EPOCH_DAY);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date to another date, including the chronology.
+     * <p>
+     * The comparison is based first on the underlying time-line date, then
+     * on the chronology.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 2012-12-03 (ISO)}</li>
+     * <li>{@code 2012-12-04 (ISO)}</li>
+     * <li>{@code 2555-12-04 (ThaiBuddhist)}</li>
+     * <li>{@code 2012-12-05 (ISO)}</li>
+     * </ol>
+     * Values #2 and #3 represent the same date on the time-line.
+     * When two values represent the same date, the chronology ID is compared to distinguish them.
+     * This step is needed to make the ordering "consistent with equals".
+     * <p>
+     * If all the date objects being compared are in the same chronology, then the
+     * additional chronology stage is not required and only the local date is used.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     * <p>
+     * This default implementation performs the comparison defined above.
+     *
+     * @param other  the other date to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    default int compareTo(ChronoLocalDate other) {
+        int cmp = Long.compare(toEpochDay(), other.toEpochDay());
+        if (cmp == 0) {
+            cmp = getChronology().compareTo(other.getChronology());
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date is after the specified date ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code date1.toEpochDay() > date2.toEpochDay()}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this is after the specified date
+     */
+    default boolean isAfter(ChronoLocalDate other) {
+        return this.toEpochDay() > other.toEpochDay();
+    }
+
+    /**
+     * Checks if this date is before the specified date ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code date1.toEpochDay() < date2.toEpochDay()}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if this is before the specified date
+     */
+    default boolean isBefore(ChronoLocalDate other) {
+        return this.toEpochDay() < other.toEpochDay();
+    }
+
+    /**
+     * Checks if this date is equal to the specified date ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * This is equivalent to using {@code date1.toEpochDay() == date2.toEpochDay()}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day.
+     *
+     * @param other  the other date to compare to, not null
+     * @return true if the underlying date is equal to the specified date
+     */
+    default boolean isEqual(ChronoLocalDate other) {
+        return this.toEpochDay() == other.toEpochDay();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date is equal to another date, including the chronology.
+     * <p>
+     * Compares this date with another ensuring that the date and chronology are the same.
+     * <p>
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date as a {@code String}.
+     * <p>
+     * The output will include the full local date.
+     *
+     * @return the formatted date, not null
+     */
+    @Override
+    String toString();
+
+}
diff --git a/java/time/chrono/ChronoLocalDateImpl.java b/java/time/chrono/ChronoLocalDateImpl.java
new file mode 100644
index 0000000..8fe8d19
--- /dev/null
+++ b/java/time/chrono/ChronoLocalDateImpl.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A date expressed in terms of a standard year-month-day calendar system.
+ * <p>
+ * This class is used by applications seeking to handle dates in non-ISO calendar systems.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ * <p>
+ * {@code ChronoLocalDate} is built on the generic concepts of year, month and day.
+ * The calendar system, represented by a {@link java.time.chrono.Chronology}, expresses the relationship between
+ * the fields and this class allows the resulting date to be manipulated.
+ * <p>
+ * Note that not all calendar systems are suitable for use with this class.
+ * For example, the Mayan calendar uses a system that bears no relation to years, months and days.
+ * <p>
+ * The API design encourages the use of {@code LocalDate} for the majority of the application.
+ * This includes code to read and write from a persistent data store, such as a database,
+ * and to send dates and times across a network. The {@code ChronoLocalDate} instance is then used
+ * at the user interface level to deal with localized input/output.
+ *
+ * <P>Example: </p>
+ * <pre>
+ *        System.out.printf("Example()%n");
+ *        // Enumerate the list of available calendars and print today for each
+ *        Set&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
+ *        for (Chronology chrono : chronos) {
+ *            ChronoLocalDate date = chrono.dateNow();
+ *            System.out.printf("   %20s: %s%n", chrono.getID(), date.toString());
+ *        }
+ *
+ *        // Print the Hijrah date and calendar
+ *        ChronoLocalDate date = Chronology.of("Hijrah").dateNow();
+ *        int day = date.get(ChronoField.DAY_OF_MONTH);
+ *        int dow = date.get(ChronoField.DAY_OF_WEEK);
+ *        int month = date.get(ChronoField.MONTH_OF_YEAR);
+ *        int year = date.get(ChronoField.YEAR);
+ *        System.out.printf("  Today is %s %s %d-%s-%d%n", date.getChronology().getID(),
+ *                dow, day, month, year);
+
+ *        // Print today's date and the last day of the year
+ *        ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow();
+ *        ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1)
+ *                .with(ChronoField.MONTH_OF_YEAR, 1);
+ *        ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS)
+ *                .minus(1, ChronoUnit.DAYS);
+ *        System.out.printf("  Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
+ *                first, last);
+ * </pre>
+ *
+ * <h3>Adding Calendars</h3>
+ * <p> The set of calendars is extensible by defining a subclass of {@link ChronoLocalDate}
+ * to represent a date instance and an implementation of {@code Chronology}
+ * to be the factory for the ChronoLocalDate subclass.
+ * </p>
+ * <p> To permit the discovery of the additional calendar types the implementation of
+ * {@code Chronology} must be registered as a Service implementing the {@code Chronology} interface
+ * in the {@code META-INF/Services} file as per the specification of {@link java.util.ServiceLoader}.
+ * The subclass must function according to the {@code Chronology} class description and must provide its
+ * {@link java.time.chrono.Chronology#getId() chronlogy ID} and {@link Chronology#getCalendarType() calendar type}. </p>
+ *
+ * @implSpec
+ * This abstract class must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <D> the ChronoLocalDate of this date-time
+ * @since 1.8
+ */
+abstract class ChronoLocalDateImpl<D extends ChronoLocalDate>
+        implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6282433883239719096L;
+
+    /**
+     * Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology.
+     *
+     * @param chrono  the chronology to check for, not null
+     * @param temporal  a date-time to cast, not null
+     * @return the date-time checked and cast to {@code ChronoLocalDate}, not null
+     * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
+     *  or the chronology is not equal this Chronology
+     */
+    static <D extends ChronoLocalDate> D ensureValid(Chronology chrono, Temporal temporal) {
+        @SuppressWarnings("unchecked")
+        D other = (D) temporal;
+        if (chrono.equals(other.getChronology()) == false) {
+            throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId());
+        }
+        return other;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance.
+     */
+    ChronoLocalDateImpl() {
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public D with(TemporalAdjuster adjuster) {
+        return (D) ChronoLocalDate.super.with(adjuster);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public D with(TemporalField field, long value) {
+        return (D) ChronoLocalDate.super.with(field, value);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    @SuppressWarnings("unchecked")
+    public D plus(TemporalAmount amount) {
+        return (D) ChronoLocalDate.super.plus(amount);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    @SuppressWarnings("unchecked")
+    public D plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case DAYS: return plusDays(amountToAdd);
+                case WEEKS: return plusDays(Math.multiplyExact(amountToAdd, 7));
+                case MONTHS: return plusMonths(amountToAdd);
+                case YEARS: return plusYears(amountToAdd);
+                case DECADES: return plusYears(Math.multiplyExact(amountToAdd, 10));
+                case CENTURIES: return plusYears(Math.multiplyExact(amountToAdd, 100));
+                case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
+                case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        return (D) ChronoLocalDate.super.plus(amountToAdd, unit);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public D minus(TemporalAmount amount) {
+        return (D) ChronoLocalDate.super.minus(amount);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public D minus(long amountToSubtract, TemporalUnit unit) {
+        return (D) ChronoLocalDate.super.minus(amountToSubtract, unit);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified number of years added.
+     * <p>
+     * This adds the specified period in years to the date.
+     * In some cases, adding years can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToAdd  the years to add, may be negative
+     * @return a date based on this one with the years added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    abstract D plusYears(long yearsToAdd);
+
+    /**
+     * Returns a copy of this date with the specified number of months added.
+     * <p>
+     * This adds the specified period in months to the date.
+     * In some cases, adding months can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToAdd  the months to add, may be negative
+     * @return a date based on this one with the months added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    abstract D plusMonths(long monthsToAdd);
+
+    /**
+     * Returns a copy of this date with the specified number of weeks added.
+     * <p>
+     * This adds the specified period in weeks to the date.
+     * In some cases, adding weeks can cause the resulting date to become invalid.
+     * If this occurs, then other fields will be adjusted to ensure that the result is valid.
+     * <p>
+     * The default implementation uses {@link #plusDays(long)} using a 7 day week.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToAdd  the weeks to add, may be negative
+     * @return a date based on this one with the weeks added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    D plusWeeks(long weeksToAdd) {
+        return plusDays(Math.multiplyExact(weeksToAdd, 7));
+    }
+
+    /**
+     * Returns a copy of this date with the specified number of days added.
+     * <p>
+     * This adds the specified period in days to the date.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToAdd  the days to add, may be negative
+     * @return a date based on this one with the days added, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    abstract D plusDays(long daysToAdd);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the specified number of years subtracted.
+     * <p>
+     * This subtracts the specified period in years to the date.
+     * In some cases, subtracting years can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * The default implementation uses {@link #plusYears(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param yearsToSubtract  the years to subtract, may be negative
+     * @return a date based on this one with the years subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    @SuppressWarnings("unchecked")
+    D minusYears(long yearsToSubtract) {
+        return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this date with the specified number of months subtracted.
+     * <p>
+     * This subtracts the specified period in months to the date.
+     * In some cases, subtracting months can cause the resulting date to become invalid.
+     * If this occurs, then other fields, typically the day-of-month, will be adjusted to ensure
+     * that the result is valid. Typically this will select the last valid day of the month.
+     * <p>
+     * The default implementation uses {@link #plusMonths(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param monthsToSubtract  the months to subtract, may be negative
+     * @return a date based on this one with the months subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    @SuppressWarnings("unchecked")
+    D minusMonths(long monthsToSubtract) {
+        return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract));
+    }
+
+    /**
+     * Returns a copy of this date with the specified number of weeks subtracted.
+     * <p>
+     * This subtracts the specified period in weeks to the date.
+     * In some cases, subtracting weeks can cause the resulting date to become invalid.
+     * If this occurs, then other fields will be adjusted to ensure that the result is valid.
+     * <p>
+     * The default implementation uses {@link #plusWeeks(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param weeksToSubtract  the weeks to subtract, may be negative
+     * @return a date based on this one with the weeks subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    @SuppressWarnings("unchecked")
+    D minusWeeks(long weeksToSubtract) {
+        return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract));
+    }
+
+    /**
+     * Returns a copy of this date with the specified number of days subtracted.
+     * <p>
+     * This subtracts the specified period in days to the date.
+     * <p>
+     * The default implementation uses {@link #plusDays(long)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param daysToSubtract  the days to subtract, may be negative
+     * @return a date based on this one with the days subtracted, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    @SuppressWarnings("unchecked")
+    D minusDays(long daysToSubtract) {
+        return (daysToSubtract == Long.MIN_VALUE ? ((ChronoLocalDateImpl<D>)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        Objects.requireNonNull(endExclusive, "endExclusive");
+        ChronoLocalDate end = getChronology().date(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            switch ((ChronoUnit) unit) {
+                case DAYS: return daysUntil(end);
+                case WEEKS: return daysUntil(end) / 7;
+                case MONTHS: return monthsUntil(end);
+                case YEARS: return monthsUntil(end) / 12;
+                case DECADES: return monthsUntil(end) / 120;
+                case CENTURIES: return monthsUntil(end) / 1200;
+                case MILLENNIA: return monthsUntil(end) / 12000;
+                case ERAS: return end.getLong(ERA) - getLong(ERA);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+        Objects.requireNonNull(unit, "unit");
+        return unit.between(this, end);
+    }
+
+    private long daysUntil(ChronoLocalDate end) {
+        return end.toEpochDay() - toEpochDay();  // no overflow
+    }
+
+    private long monthsUntil(ChronoLocalDate end) {
+        ValueRange range = getChronology().range(MONTH_OF_YEAR);
+        if (range.getMaximum() != 12) {
+            throw new IllegalStateException("ChronoLocalDateImpl only supports Chronologies with 12 months per year");
+        }
+        long packed1 = getLong(PROLEPTIC_MONTH) * 32L + get(DAY_OF_MONTH);  // no overflow
+        long packed2 = end.getLong(PROLEPTIC_MONTH) * 32L + end.get(DAY_OF_MONTH);  // no overflow
+        return (packed2 - packed1) / 32;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoLocalDate) {
+            return compareTo((ChronoLocalDate) obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        long epDay = toEpochDay();
+        return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32)));
+    }
+
+    @Override
+    public String toString() {
+        // getLong() reduces chances of exceptions in toString()
+        long yoe = getLong(YEAR_OF_ERA);
+        long moy = getLong(MONTH_OF_YEAR);
+        long dom = getLong(DAY_OF_MONTH);
+        StringBuilder buf = new StringBuilder(30);
+        buf.append(getChronology().toString())
+                .append(" ")
+                .append(getEra())
+                .append(" ")
+                .append(yoe)
+                .append(moy < 10 ? "-0" : "-").append(moy)
+                .append(dom < 10 ? "-0" : "-").append(dom);
+        return buf.toString();
+    }
+
+}
diff --git a/java/time/chrono/ChronoLocalDateTime.java b/java/time/chrono/ChronoLocalDateTime.java
new file mode 100644
index 0000000..ce77f4d
--- /dev/null
+++ b/java/time/chrono/ChronoLocalDateTime.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.zone.ZoneRules;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone in an arbitrary chronology, intended
+ * for advanced globalization use cases.
+ * <p>
+ * <b>Most applications should declare method signatures, fields and variables
+ * as {@link LocalDateTime}, not this interface.</b>
+ * <p>
+ * A {@code ChronoLocalDateTime} is the abstract representation of a local date-time
+ * where the {@code Chronology chronology}, or calendar system, is pluggable.
+ * The date-time is defined in terms of fields expressed by {@link TemporalField},
+ * where most common implementations are defined in {@link ChronoField}.
+ * The chronology defines how the calendar system operates and the meaning of
+ * the standard fields.
+ *
+ * <h3>When to use this interface</h3>
+ * The design of the API encourages the use of {@code LocalDateTime} rather than this
+ * interface, even in the case where the application needs to deal with multiple
+ * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
+ * <p>
+ * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
+ * before using this interface.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <D> the concrete type for the date of this date-time
+ * @since 1.8
+ */
+public interface ChronoLocalDateTime<D extends ChronoLocalDate>
+        extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> {
+
+    /**
+     * Gets a comparator that compares {@code ChronoLocalDateTime} in
+     * time-line order ignoring the chronology.
+     * <p>
+     * This comparator differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date-time and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the position of the date-time on the local time-line.
+     * The underlying comparison is equivalent to comparing the epoch-day and nano-of-day.
+     *
+     * @return a comparator that compares in time-line order ignoring the chronology
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    static Comparator<ChronoLocalDateTime<?>> timeLineOrder() {
+        return AbstractChronology.DATE_TIME_ORDER;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ChronoLocalDateTime} from a temporal object.
+     * <p>
+     * This obtains a local date-time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ChronoLocalDateTime}.
+     * <p>
+     * The conversion extracts and combines the chronology and the date-time
+     * from the temporal object. The behavior is equivalent to using
+     * {@link Chronology#localDateTime(TemporalAccessor)} with the extracted chronology.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ChronoLocalDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date-time, not null
+     * @throws DateTimeException if unable to convert to a {@code ChronoLocalDateTime}
+     * @see Chronology#localDateTime(TemporalAccessor)
+     */
+    static ChronoLocalDateTime<?> from(TemporalAccessor temporal) {
+        if (temporal instanceof ChronoLocalDateTime) {
+            return (ChronoLocalDateTime<?>) temporal;
+        }
+        Objects.requireNonNull(temporal, "temporal");
+        Chronology chrono = temporal.query(TemporalQueries.chronology());
+        if (chrono == null) {
+            throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass());
+        }
+        return chrono.localDateTime(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date-time.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the chronology, not null
+     */
+    default Chronology getChronology() {
+        return toLocalDate().getChronology();
+    }
+
+    /**
+     * Gets the local date part of this date-time.
+     * <p>
+     * This returns a local date with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    D toLocalDate() ;
+
+    /**
+     * Gets the local time part of this date-time.
+     * <p>
+     * This returns a local time with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    LocalTime toLocalTime();
+
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if the specified field can be queried on this date-time.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * The set of supported fields is defined by the chronology and normally includes
+     * all {@code ChronoField} date and time fields.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field can be queried, false if not
+     */
+    @Override
+    boolean isSupported(TemporalField field);
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to or subtracted from this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * The set of supported units is defined by the chronology and normally includes
+     * all {@code ChronoUnit} units except {@code FOREVER}.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override
+    default boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit != FOREVER;
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    // override for covariant return type
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) {
+        return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoLocalDateTime<D> with(TemporalField field, long newValue);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDateTime<D> plus(TemporalAmount amount) {
+        return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoLocalDateTime<D> plus(long amountToAdd, TemporalUnit unit);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDateTime<D> minus(TemporalAmount amount) {
+        return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
+        return ChronoLocalDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    default <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zoneId() || query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
+            return null;
+        } else if (query == TemporalQueries.localTime()) {
+            return (R) toLocalTime();
+        } else if (query == TemporalQueries.chronology()) {
+            return (R) getChronology();
+        } else if (query == TemporalQueries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same date and time as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the date and time changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * twice, passing {@link ChronoField#EPOCH_DAY} and
+     * {@link ChronoField#NANO_OF_DAY} as the fields.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisLocalDateTime.adjustInto(temporal);
+     *   temporal = temporal.with(thisLocalDateTime);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    default Temporal adjustInto(Temporal temporal) {
+        return temporal
+                .with(EPOCH_DAY, toLocalDate().toEpochDay())
+                .with(NANO_OF_DAY, toLocalTime().toNanoOfDay());
+    }
+
+    /**
+     * Formats this date-time using the specified formatter.
+     * <p>
+     * This date-time will be passed to the formatter to produce a string.
+     * <p>
+     * The default implementation must behave as follows:
+     * <pre>
+     *  return formatter.format(this);
+     * </pre>
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    default String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Combines this time with a time-zone to create a {@code ChronoZonedDateTime}.
+     * <p>
+     * This returns a {@code ChronoZonedDateTime} formed from this date-time at the
+     * specified time-zone. The result will match this date-time as closely as possible.
+     * Time-zone rules, such as daylight savings, mean that not every local date-time
+     * is valid for the specified zone, thus the local date-time may be adjusted.
+     * <p>
+     * The local date-time is resolved to a single instant on the time-line.
+     * This is achieved by finding a valid offset from UTC/Greenwich for the local
+     * date-time as defined by the {@link ZoneRules rules} of the zone ID.
+     *<p>
+     * In most cases, there is only one valid offset for a local date-time.
+     * In the case of an overlap, where clocks are set back, there are two valid offsets.
+     * This method uses the earlier offset typically corresponding to "summer".
+     * <p>
+     * In the case of a gap, where clocks jump forward, there is no valid offset.
+     * Instead, the local date-time is adjusted to be later by the length of the gap.
+     * For a typical one hour daylight savings change, the local date-time will be
+     * moved one hour later into the offset typically corresponding to "summer".
+     * <p>
+     * To obtain the later offset during an overlap, call
+     * {@link ChronoZonedDateTime#withLaterOffsetAtOverlap()} on the result of this method.
+     *
+     * @param zone  the time-zone to use, not null
+     * @return the zoned date-time formed from this date-time, not null
+     */
+    ChronoZonedDateTime<D> atZone(ZoneId zone);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code Instant}.
+     * <p>
+     * This combines this local date-time and the specified offset to form
+     * an {@code Instant}.
+     * <p>
+     * This default implementation calculates from the epoch-day of the date and the
+     * second-of-day of the time.
+     *
+     * @param offset  the offset to use for the conversion, not null
+     * @return an {@code Instant} representing the same instant, not null
+     */
+    default Instant toInstant(ZoneOffset offset) {
+        return Instant.ofEpochSecond(toEpochSecond(offset), toLocalTime().getNano());
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This combines this local date-time and the specified offset to calculate the
+     * epoch-second value, which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier are negative.
+     * <p>
+     * This default implementation calculates from the epoch-day of the date and the
+     * second-of-day of the time.
+     *
+     * @param offset  the offset to use for the conversion, not null
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    default long toEpochSecond(ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        long epochDay = toLocalDate().toEpochDay();
+        long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
+        secs -= offset.getTotalSeconds();
+        return secs;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time, including the chronology.
+     * <p>
+     * The comparison is based first on the underlying time-line date-time, then
+     * on the chronology.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * For example, the following is the comparator order:
+     * <ol>
+     * <li>{@code 2012-12-03T12:00 (ISO)}</li>
+     * <li>{@code 2012-12-04T12:00 (ISO)}</li>
+     * <li>{@code 2555-12-04T12:00 (ThaiBuddhist)}</li>
+     * <li>{@code 2012-12-05T12:00 (ISO)}</li>
+     * </ol>
+     * Values #2 and #3 represent the same date-time on the time-line.
+     * When two values represent the same date-time, the chronology ID is compared to distinguish them.
+     * This step is needed to make the ordering "consistent with equals".
+     * <p>
+     * If all the date-time objects being compared are in the same chronology, then the
+     * additional chronology stage is not required and only the local date-time is used.
+     * <p>
+     * This default implementation performs the comparison defined above.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    default int compareTo(ChronoLocalDateTime<?> other) {
+        int cmp = toLocalDate().compareTo(other.toLocalDate());
+        if (cmp == 0) {
+            cmp = toLocalTime().compareTo(other.toLocalTime());
+            if (cmp == 0) {
+                cmp = getChronology().compareTo(other.getChronology());
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if this date-time is after the specified date-time ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date-time and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day
+     * and nano-of-day.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is after the specified date-time
+     */
+    default boolean isAfter(ChronoLocalDateTime<?> other) {
+        long thisEpDay = this.toLocalDate().toEpochDay();
+        long otherEpDay = other.toLocalDate().toEpochDay();
+        return thisEpDay > otherEpDay ||
+            (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() > other.toLocalTime().toNanoOfDay());
+    }
+
+    /**
+     * Checks if this date-time is before the specified date-time ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date-time and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the time-line position.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day
+     * and nano-of-day.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is before the specified date-time
+     */
+    default boolean isBefore(ChronoLocalDateTime<?> other) {
+        long thisEpDay = this.toLocalDate().toEpochDay();
+        long otherEpDay = other.toLocalDate().toEpochDay();
+        return thisEpDay < otherEpDay ||
+            (thisEpDay == otherEpDay && this.toLocalTime().toNanoOfDay() < other.toLocalTime().toNanoOfDay());
+    }
+
+    /**
+     * Checks if this date-time is equal to the specified date-time ignoring the chronology.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying date and time and not the chronology.
+     * This allows date-times in different calendar systems to be compared based
+     * on the time-line position.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-day
+     * and nano-of-day.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if the underlying date-time is equal to the specified date-time on the timeline
+     */
+    default boolean isEqual(ChronoLocalDateTime<?> other) {
+        // Do the time check first, it is cheaper than computing EPOCH day.
+        return this.toLocalTime().toNanoOfDay() == other.toLocalTime().toNanoOfDay() &&
+               this.toLocalDate().toEpochDay() == other.toLocalDate().toEpochDay();
+    }
+
+    /**
+     * Checks if this date-time is equal to another date-time, including the chronology.
+     * <p>
+     * Compares this date-time with another ensuring that the date-time and chronology are the same.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}.
+     * <p>
+     * The output will include the full local date-time.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    String toString();
+
+}
diff --git a/java/time/chrono/ChronoLocalDateTimeImpl.java b/java/time/chrono/ChronoLocalDateTimeImpl.java
new file mode 100644
index 0000000..ac5f7b4
--- /dev/null
+++ b/java/time/chrono/ChronoLocalDateTimeImpl.java
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+/**
+ * A date-time without a time-zone for the calendar neutral API.
+ * <p>
+ * {@code ChronoLocalDateTime} is an immutable date-time object that represents a date-time, often
+ * viewed as year-month-day-hour-minute-second. This object can also access other
+ * fields such as day-of-year, day-of-week and week-of-year.
+ * <p>
+ * This class stores all date and time fields, to a precision of nanoseconds.
+ * It does not store or represent a time-zone. For example, the value
+ * "2nd October 2007 at 13:45.30.123456789" can be stored in an {@code ChronoLocalDateTime}.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ * @serial
+ * @param <D> the concrete type for the date of this date-time
+ * @since 1.8
+ */
+final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate>
+        implements  ChronoLocalDateTime<D>, Temporal, TemporalAdjuster, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 4556003607393004514L;
+    /**
+     * Hours per day.
+     */
+    static final int HOURS_PER_DAY = 24;
+    /**
+     * Minutes per hour.
+     */
+    static final int MINUTES_PER_HOUR = 60;
+    /**
+     * Minutes per day.
+     */
+    static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Seconds per minute.
+     */
+    static final int SECONDS_PER_MINUTE = 60;
+    /**
+     * Seconds per hour.
+     */
+    static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Seconds per day.
+     */
+    static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
+    /**
+     * Milliseconds per day.
+     */
+    static final long MILLIS_PER_DAY = SECONDS_PER_DAY * 1000L;
+    /**
+     * Microseconds per day.
+     */
+    static final long MICROS_PER_DAY = SECONDS_PER_DAY * 1000_000L;
+    /**
+     * Nanos per second.
+     */
+    static final long NANOS_PER_SECOND = 1000_000_000L;
+    /**
+     * Nanos per minute.
+     */
+    static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
+    /**
+     * Nanos per hour.
+     */
+    static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
+    /**
+     * Nanos per day.
+     */
+    static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
+
+    /**
+     * The date part.
+     */
+    private final transient D date;
+    /**
+     * The time part.
+     */
+    private final transient LocalTime time;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ChronoLocalDateTime} from a date and time.
+     *
+     * @param date  the local date, not null
+     * @param time  the local time, not null
+     * @return the local date-time, not null
+     */
+    static <R extends ChronoLocalDate> ChronoLocalDateTimeImpl<R> of(R date, LocalTime time) {
+        return new ChronoLocalDateTimeImpl<>(date, time);
+    }
+
+    /**
+     * Casts the {@code Temporal} to {@code ChronoLocalDateTime} ensuring it bas the specified chronology.
+     *
+     * @param chrono  the chronology to check for, not null
+     * @param temporal   a date-time to cast, not null
+     * @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
+     * @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
+     *  or the chronology is not equal this Chronology
+     */
+    static <R extends ChronoLocalDate> ChronoLocalDateTimeImpl<R> ensureValid(Chronology chrono, Temporal temporal) {
+        @SuppressWarnings("unchecked")
+        ChronoLocalDateTimeImpl<R> other = (ChronoLocalDateTimeImpl<R>) temporal;
+        if (chrono.equals(other.getChronology()) == false) {
+            throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
+                    + ", actual: " + other.getChronology().getId());
+        }
+        return other;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param date  the date part of the date-time, not null
+     * @param time  the time part of the date-time, not null
+     */
+    private ChronoLocalDateTimeImpl(D date, LocalTime time) {
+        Objects.requireNonNull(date, "date");
+        Objects.requireNonNull(time, "time");
+        this.date = date;
+        this.time = time;
+    }
+
+    /**
+     * Returns a copy of this date-time with the new date and time, checking
+     * to see if a new object is in fact required.
+     *
+     * @param newDate  the date of the new date-time, not null
+     * @param newTime  the time of the new date-time, not null
+     * @return the date-time, not null
+     */
+    private ChronoLocalDateTimeImpl<D> with(Temporal newDate, LocalTime newTime) {
+        if (date == newDate && time == newTime) {
+            return this;
+        }
+        // Validate that the new Temporal is a ChronoLocalDate (and not something else)
+        D cd = ChronoLocalDateImpl.ensureValid(date.getChronology(), newDate);
+        return new ChronoLocalDateTimeImpl<>(cd, newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public D toLocalDate() {
+        return date;
+    }
+
+    @Override
+    public LocalTime toLocalTime() {
+        return time;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return f.isDateBased() || f.isTimeBased();
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeBased() ? time.range(field) : date.range(field));
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    @Override
+    public int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeBased() ? time.get(field) : date.get(field));
+        }
+        return range(field).checkValidIntValue(getLong(field), field);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            return (f.isTimeBased() ? time.getLong(field) : date.getLong(field));
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    @SuppressWarnings("unchecked")
+    @Override
+    public ChronoLocalDateTimeImpl<D> with(TemporalAdjuster adjuster) {
+        if (adjuster instanceof ChronoLocalDate) {
+            // The Chronology is checked in with(date,time)
+            return with((ChronoLocalDate) adjuster, time);
+        } else if (adjuster instanceof LocalTime) {
+            return with(date, (LocalTime) adjuster);
+        } else if (adjuster instanceof ChronoLocalDateTimeImpl) {
+            return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl<?>) adjuster);
+        }
+        return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this));
+    }
+
+    @Override
+    public ChronoLocalDateTimeImpl<D> with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (f.isTimeBased()) {
+                return with(date, time.with(field, newValue));
+            } else {
+                return with(date.with(field, newValue), time);
+            }
+        }
+        return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), field.adjustInto(this, newValue));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDateTimeImpl<D> plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            ChronoUnit f = (ChronoUnit) unit;
+            switch (f) {
+                case NANOS: return plusNanos(amountToAdd);
+                case MICROS: return plusDays(amountToAdd / MICROS_PER_DAY).plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
+                case MILLIS: return plusDays(amountToAdd / MILLIS_PER_DAY).plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000000);
+                case SECONDS: return plusSeconds(amountToAdd);
+                case MINUTES: return plusMinutes(amountToAdd);
+                case HOURS: return plusHours(amountToAdd);
+                case HALF_DAYS: return plusDays(amountToAdd / 256).plusHours((amountToAdd % 256) * 12);  // no overflow (256 is multiple of 2)
+            }
+            return with(date.plus(amountToAdd, unit), time);
+        }
+        return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), unit.addTo(this, amountToAdd));
+    }
+
+    private ChronoLocalDateTimeImpl<D> plusDays(long days) {
+        return with(date.plus(days, ChronoUnit.DAYS), time);
+    }
+
+    private ChronoLocalDateTimeImpl<D> plusHours(long hours) {
+        return plusWithOverflow(date, hours, 0, 0, 0);
+    }
+
+    private ChronoLocalDateTimeImpl<D> plusMinutes(long minutes) {
+        return plusWithOverflow(date, 0, minutes, 0, 0);
+    }
+
+    ChronoLocalDateTimeImpl<D> plusSeconds(long seconds) {
+        return plusWithOverflow(date, 0, 0, seconds, 0);
+    }
+
+    private ChronoLocalDateTimeImpl<D> plusNanos(long nanos) {
+        return plusWithOverflow(date, 0, 0, 0, nanos);
+    }
+
+    //-----------------------------------------------------------------------
+    private ChronoLocalDateTimeImpl<D> plusWithOverflow(D newDate, long hours, long minutes, long seconds, long nanos) {
+        // 9223372036854775808 long, 2147483648 int
+        if ((hours | minutes | seconds | nanos) == 0) {
+            return with(newDate, time);
+        }
+        long totDays = nanos / NANOS_PER_DAY +             //   max/24*60*60*1B
+                seconds / SECONDS_PER_DAY +                //   max/24*60*60
+                minutes / MINUTES_PER_DAY +                //   max/24*60
+                hours / HOURS_PER_DAY;                     //   max/24
+        long totNanos = nanos % NANOS_PER_DAY +                    //   max  86400000000000
+                (seconds % SECONDS_PER_DAY) * NANOS_PER_SECOND +   //   max  86400000000000
+                (minutes % MINUTES_PER_DAY) * NANOS_PER_MINUTE +   //   max  86400000000000
+                (hours % HOURS_PER_DAY) * NANOS_PER_HOUR;          //   max  86400000000000
+        long curNoD = time.toNanoOfDay();                          //   max  86400000000000
+        totNanos = totNanos + curNoD;                              // total 432000000000000
+        totDays += Math.floorDiv(totNanos, NANOS_PER_DAY);
+        long newNoD = Math.floorMod(totNanos, NANOS_PER_DAY);
+        LocalTime newTime = (newNoD == curNoD ? time : LocalTime.ofNanoOfDay(newNoD));
+        return with(newDate.plus(totDays, ChronoUnit.DAYS), newTime);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoZonedDateTime<D> atZone(ZoneId zone) {
+        return ChronoZonedDateTimeImpl.ofBest(this, zone, null);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        Objects.requireNonNull(endExclusive, "endExclusive");
+        @SuppressWarnings("unchecked")
+        ChronoLocalDateTime<D> end = (ChronoLocalDateTime<D>) getChronology().localDateTime(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            if (unit.isTimeBased()) {
+                long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
+                switch ((ChronoUnit) unit) {
+                    case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
+                    case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
+                    case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
+                    case SECONDS: amount = Math.multiplyExact(amount, SECONDS_PER_DAY); break;
+                    case MINUTES: amount = Math.multiplyExact(amount, MINUTES_PER_DAY); break;
+                    case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
+                    case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
+                }
+                return Math.addExact(amount, time.until(end.toLocalTime(), unit));
+            }
+            ChronoLocalDate endDate = end.toLocalDate();
+            if (end.toLocalTime().isBefore(time)) {
+                endDate = endDate.minus(1, ChronoUnit.DAYS);
+            }
+            return date.until(endDate, unit);
+        }
+        Objects.requireNonNull(unit, "unit");
+        return unit.between(this, end);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the ChronoLocalDateTime using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(2);              // identifies a ChronoLocalDateTime
+     *  out.writeObject(toLocalDate());
+     *  out.witeObject(toLocalTime());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(date);
+        out.writeObject(time);
+    }
+
+    static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        ChronoLocalDate date = (ChronoLocalDate) in.readObject();
+        LocalTime time = (LocalTime) in.readObject();
+        return date.atTime(time);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoLocalDateTime) {
+            return compareTo((ChronoLocalDateTime<?>) obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return toLocalDate().hashCode() ^ toLocalTime().hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return toLocalDate().toString() + 'T' + toLocalTime().toString();
+    }
+
+}
diff --git a/java/time/chrono/ChronoPeriod.java b/java/time/chrono/ChronoPeriod.java
new file mode 100644
index 0000000..0ac1d39
--- /dev/null
+++ b/java/time/chrono/ChronoPeriod.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.time.DateTimeException;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A date-based amount of time, such as '3 years, 4 months and 5 days' in an
+ * arbitrary chronology, intended for advanced globalization use cases.
+ * <p>
+ * This interface models a date-based amount of time in a calendar system.
+ * While most calendar systems use years, months and days, some do not.
+ * Therefore, this interface operates solely in terms of a set of supported
+ * units that are defined by the {@code Chronology}.
+ * The set of supported units is fixed for a given chronology.
+ * The amount of a supported unit may be set to zero.
+ * <p>
+ * The period is modeled as a directed amount of time, meaning that individual
+ * parts of the period may be negative.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @since 1.8
+ */
+public interface ChronoPeriod
+        extends TemporalAmount {
+
+    /**
+     * Obtains a {@code ChronoPeriod} consisting of amount of time between two dates.
+     * <p>
+     * The start date is included, but the end date is not.
+     * The period is calculated using {@link ChronoLocalDate#until(ChronoLocalDate)}.
+     * As such, the calculation is chronology specific.
+     * <p>
+     * The chronology of the first date is used.
+     * The chronology of the second date is ignored, with the date being converted
+     * to the target chronology system before the calculation starts.
+     * <p>
+     * The result of this method can be a negative period if the end is before the start.
+     * In most cases, the positive/negative sign will be the same in each of the supported fields.
+     *
+     * @param startDateInclusive  the start date, inclusive, specifying the chronology of the calculation, not null
+     * @param endDateExclusive  the end date, exclusive, in any chronology, not null
+     * @return the period between this date and the end date, not null
+     * @see ChronoLocalDate#until(ChronoLocalDate)
+     */
+    public static ChronoPeriod between(ChronoLocalDate startDateInclusive, ChronoLocalDate endDateExclusive) {
+        Objects.requireNonNull(startDateInclusive, "startDateInclusive");
+        Objects.requireNonNull(endDateExclusive, "endDateExclusive");
+        return startDateInclusive.until(endDateExclusive);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the value of the requested unit.
+     * <p>
+     * The supported units are chronology specific.
+     * They will typically be {@link ChronoUnit#YEARS YEARS},
+     * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
+     * Requesting an unsupported unit will throw an exception.
+     *
+     * @param unit the {@code TemporalUnit} for which to return the value
+     * @return the long value of the unit
+     * @throws DateTimeException if the unit is not supported
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    @Override
+    long get(TemporalUnit unit);
+
+    /**
+     * Gets the set of units supported by this period.
+     * <p>
+     * The supported units are chronology specific.
+     * They will typically be {@link ChronoUnit#YEARS YEARS},
+     * {@link ChronoUnit#MONTHS MONTHS} and {@link ChronoUnit#DAYS DAYS}.
+     * They are returned in order from largest to smallest.
+     * <p>
+     * This set can be used in conjunction with {@link #get(TemporalUnit)}
+     * to access the entire state of the period.
+     *
+     * @return a list containing the supported units, not null
+     */
+    @Override
+    List<TemporalUnit> getUnits();
+
+    /**
+     * Gets the chronology that defines the meaning of the supported units.
+     * <p>
+     * The period is defined by the chronology.
+     * It controls the supported units and restricts addition/subtraction
+     * to {@code ChronoLocalDate} instances of the same chronology.
+     *
+     * @return the chronology defining the period, not null
+     */
+    Chronology getChronology();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if all the supported units of this period are zero.
+     *
+     * @return true if this period is zero-length
+     */
+    default boolean isZero() {
+        for (TemporalUnit unit : getUnits()) {
+            if (get(unit) != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks if any of the supported units of this period are negative.
+     *
+     * @return true if any unit of this period is negative
+     */
+    default boolean isNegative() {
+        for (TemporalUnit unit : getUnits()) {
+            if (get(unit) < 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the specified period added.
+     * <p>
+     * If the specified amount is a {@code ChronoPeriod} then it must have
+     * the same chronology as this period. Implementations may choose to
+     * accept or reject other {@code TemporalAmount} implementations.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToAdd  the period to add, not null
+     * @return a {@code ChronoPeriod} based on this period with the requested period added, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    ChronoPeriod plus(TemporalAmount amountToAdd);
+
+    /**
+     * Returns a copy of this period with the specified period subtracted.
+     * <p>
+     * If the specified amount is a {@code ChronoPeriod} then it must have
+     * the same chronology as this period. Implementations may choose to
+     * accept or reject other {@code TemporalAmount} implementations.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param amountToSubtract  the period to subtract, not null
+     * @return a {@code ChronoPeriod} based on this period with the requested period subtracted, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    ChronoPeriod minus(TemporalAmount amountToSubtract);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a new instance with each amount in this period in this period
+     * multiplied by the specified scalar.
+     * <p>
+     * This returns a period with each supported unit individually multiplied.
+     * For example, a period of "2 years, -3 months and 4 days" multiplied by
+     * 3 will return "6 years, -9 months and 12 days".
+     * No normalization is performed.
+     *
+     * @param scalar  the scalar to multiply by, not null
+     * @return a {@code ChronoPeriod} based on this period with the amounts multiplied
+     *  by the scalar, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    ChronoPeriod multipliedBy(int scalar);
+
+    /**
+     * Returns a new instance with each amount in this period negated.
+     * <p>
+     * This returns a period with each supported unit individually negated.
+     * For example, a period of "2 years, -3 months and 4 days" will be
+     * negated to "-2 years, 3 months and -4 days".
+     * No normalization is performed.
+     *
+     * @return a {@code ChronoPeriod} based on this period with the amounts negated, not null
+     * @throws ArithmeticException if numeric overflow occurs, which only happens if
+     *  one of the units has the value {@code Long.MIN_VALUE}
+     */
+    default ChronoPeriod negated() {
+        return multipliedBy(-1);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this period with the amounts of each unit normalized.
+     * <p>
+     * The process of normalization is specific to each calendar system.
+     * For example, in the ISO calendar system, the years and months are
+     * normalized but the days are not, such that "15 months" would be
+     * normalized to "1 year and 3 months".
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ChronoPeriod} based on this period with the amounts of each
+     *  unit normalized, not null
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    ChronoPeriod normalized();
+
+    //-------------------------------------------------------------------------
+    /**
+     * Adds this period to the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period added.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#plus(TemporalAmount)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.addTo(dateTime);
+     *   dateTime = dateTime.plus(thisPeriod);
+     * </pre>
+     * <p>
+     * The specified temporal must have the same chronology as this period.
+     * This returns a temporal with the non-zero supported units added.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same type with the adjustment made, not null
+     * @throws DateTimeException if unable to add
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    Temporal addTo(Temporal temporal);
+
+    /**
+     * Subtracts this period from the specified temporal object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with this period subtracted.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#minus(TemporalAmount)}.
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = thisPeriod.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(thisPeriod);
+     * </pre>
+     * <p>
+     * The specified temporal must have the same chronology as this period.
+     * This returns a temporal with the non-zero supported units subtracted.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same type with the adjustment made, not null
+     * @throws DateTimeException if unable to subtract
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    Temporal subtractFrom(Temporal temporal);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this period is equal to another period, including the chronology.
+     * <p>
+     * Compares this period with another ensuring that the type, each amount and
+     * the chronology are the same.
+     * Note that this means that a period of "15 Months" is not equal to a period
+     * of "1 Year and 3 Months".
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other period
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this period.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this period as a {@code String}.
+     * <p>
+     * The output will include the period amounts and chronology.
+     *
+     * @return a string representation of this period, not null
+     */
+    @Override
+    String toString();
+
+}
diff --git a/java/time/chrono/ChronoPeriodImpl.java b/java/time/chrono/ChronoPeriodImpl.java
new file mode 100644
index 0000000..911144d
--- /dev/null
+++ b/java/time/chrono/ChronoPeriodImpl.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A period expressed in terms of a standard year-month-day calendar system.
+ * <p>
+ * This class is used by applications seeking to handle dates in non-ISO calendar systems.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ *
+ * @implSpec
+ * This class is immutable nad thread-safe.
+ *
+ * @since 1.8
+ */
+final class ChronoPeriodImpl
+        implements ChronoPeriod, Serializable {
+    // this class is only used by JDK chronology implementations and makes assumptions based on that fact
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 57387258289L;
+
+    /**
+     * The set of supported units.
+     */
+    private static final List<TemporalUnit> SUPPORTED_UNITS =
+            Collections.unmodifiableList(Arrays.<TemporalUnit>asList(YEARS, MONTHS, DAYS));
+
+    /**
+     * The chronology.
+     */
+    private final Chronology chrono;
+    /**
+     * The number of years.
+     */
+    final int years;
+    /**
+     * The number of months.
+     */
+    final int months;
+    /**
+     * The number of days.
+     */
+    final int days;
+
+    /**
+     * Creates an instance.
+     */
+    ChronoPeriodImpl(Chronology chrono, int years, int months, int days) {
+        Objects.requireNonNull(chrono, "chrono");
+        this.chrono = chrono;
+        this.years = years;
+        this.months = months;
+        this.days = days;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long get(TemporalUnit unit) {
+        if (unit == ChronoUnit.YEARS) {
+            return years;
+        } else if (unit == ChronoUnit.MONTHS) {
+            return months;
+        } else if (unit == ChronoUnit.DAYS) {
+            return days;
+        } else {
+            throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
+        }
+    }
+
+    @Override
+    public List<TemporalUnit> getUnits() {
+        return ChronoPeriodImpl.SUPPORTED_UNITS;
+    }
+
+    @Override
+    public Chronology getChronology() {
+        return chrono;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isZero() {
+        return years == 0 && months == 0 && days == 0;
+    }
+
+    @Override
+    public boolean isNegative() {
+        return years < 0 || months < 0 || days < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoPeriod plus(TemporalAmount amountToAdd) {
+        ChronoPeriodImpl amount = validateAmount(amountToAdd);
+        return new ChronoPeriodImpl(
+                chrono,
+                Math.addExact(years, amount.years),
+                Math.addExact(months, amount.months),
+                Math.addExact(days, amount.days));
+    }
+
+    @Override
+    public ChronoPeriod minus(TemporalAmount amountToSubtract) {
+        ChronoPeriodImpl amount = validateAmount(amountToSubtract);
+        return new ChronoPeriodImpl(
+                chrono,
+                Math.subtractExact(years, amount.years),
+                Math.subtractExact(months, amount.months),
+                Math.subtractExact(days, amount.days));
+    }
+
+    /**
+     * Obtains an instance of {@code ChronoPeriodImpl} from a temporal amount.
+     *
+     * @param amount  the temporal amount to convert, not null
+     * @return the period, not null
+     */
+    private ChronoPeriodImpl validateAmount(TemporalAmount amount) {
+        Objects.requireNonNull(amount, "amount");
+        if (amount instanceof ChronoPeriodImpl == false) {
+            throw new DateTimeException("Unable to obtain ChronoPeriod from TemporalAmount: " + amount.getClass());
+        }
+        ChronoPeriodImpl period = (ChronoPeriodImpl) amount;
+        if (chrono.equals(period.getChronology()) == false) {
+            throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + period.getChronology().getId());
+        }
+        return period;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoPeriod multipliedBy(int scalar) {
+        if (this.isZero() || scalar == 1) {
+            return this;
+        }
+        return new ChronoPeriodImpl(
+                chrono,
+                Math.multiplyExact(years, scalar),
+                Math.multiplyExact(months, scalar),
+                Math.multiplyExact(days, scalar));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoPeriod normalized() {
+        long monthRange = monthRange();
+        if (monthRange > 0) {
+            long totalMonths = years * monthRange + months;
+            long splitYears = totalMonths / monthRange;
+            int splitMonths = (int) (totalMonths % monthRange);  // no overflow
+            if (splitYears == years && splitMonths == months) {
+                return this;
+            }
+            return new ChronoPeriodImpl(chrono, Math.toIntExact(splitYears), splitMonths, days);
+
+        }
+        return this;
+    }
+
+    /**
+     * Calculates the range of months.
+     *
+     * @return the month range, -1 if not fixed range
+     */
+    private long monthRange() {
+        ValueRange startRange = chrono.range(MONTH_OF_YEAR);
+        if (startRange.isFixed() && startRange.isIntValue()) {
+            return startRange.getMaximum() - startRange.getMinimum() + 1;
+        }
+        return -1;
+    }
+
+    //-------------------------------------------------------------------------
+    @Override
+    public Temporal addTo(Temporal temporal) {
+        validateChrono(temporal);
+        if (months == 0) {
+            if (years != 0) {
+                temporal = temporal.plus(years, YEARS);
+            }
+        } else {
+            long monthRange = monthRange();
+            if (monthRange > 0) {
+                temporal = temporal.plus(years * monthRange + months, MONTHS);
+            } else {
+                if (years != 0) {
+                    temporal = temporal.plus(years, YEARS);
+                }
+                temporal = temporal.plus(months, MONTHS);
+            }
+        }
+        if (days != 0) {
+            temporal = temporal.plus(days, DAYS);
+        }
+        return temporal;
+    }
+
+
+
+    @Override
+    public Temporal subtractFrom(Temporal temporal) {
+        validateChrono(temporal);
+        if (months == 0) {
+            if (years != 0) {
+                temporal = temporal.minus(years, YEARS);
+            }
+        } else {
+            long monthRange = monthRange();
+            if (monthRange > 0) {
+                temporal = temporal.minus(years * monthRange + months, MONTHS);
+            } else {
+                if (years != 0) {
+                    temporal = temporal.minus(years, YEARS);
+                }
+                temporal = temporal.minus(months, MONTHS);
+            }
+        }
+        if (days != 0) {
+            temporal = temporal.minus(days, DAYS);
+        }
+        return temporal;
+    }
+
+    /**
+     * Validates that the temporal has the correct chronology.
+     */
+    private void validateChrono(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
+        if (temporalChrono != null && chrono.equals(temporalChrono) == false) {
+            throw new DateTimeException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + temporalChrono.getId());
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoPeriodImpl) {
+            ChronoPeriodImpl other = (ChronoPeriodImpl) obj;
+            return years == other.years && months == other.months &&
+                    days == other.days && chrono.equals(other.chrono);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return (years + Integer.rotateLeft(months, 8) + Integer.rotateLeft(days, 16)) ^ chrono.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        if (isZero()) {
+            return getChronology().toString() + " P0D";
+        } else {
+            StringBuilder buf = new StringBuilder();
+            buf.append(getChronology().toString()).append(' ').append('P');
+            if (years != 0) {
+                buf.append(years).append('Y');
+            }
+            if (months != 0) {
+                buf.append(months).append('M');
+            }
+            if (days != 0) {
+                buf.append(days).append('D');
+            }
+            return buf.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * <pre>
+     *  out.writeByte(12);  // identifies this as a ChronoPeriodImpl
+     *  out.writeUTF(getId());  // the chronology
+     *  out.writeInt(years);
+     *  out.writeInt(months);
+     *  out.writeInt(days);
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    protected Object writeReplace() {
+        return new Ser(Ser.CHRONO_PERIOD_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeUTF(chrono.getId());
+        out.writeInt(years);
+        out.writeInt(months);
+        out.writeInt(days);
+    }
+
+    static ChronoPeriodImpl readExternal(DataInput in) throws IOException {
+        Chronology chrono = Chronology.of(in.readUTF());
+        int years = in.readInt();
+        int months = in.readInt();
+        int days = in.readInt();
+        return new ChronoPeriodImpl(chrono, years, months, days);
+    }
+
+}
diff --git a/java/time/chrono/ChronoZonedDateTime.java b/java/time/chrono/ChronoZonedDateTime.java
new file mode 100644
index 0000000..cae9adc
--- /dev/null
+++ b/java/time/chrono/ChronoZonedDateTime.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.NANOS;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * A date-time with a time-zone in an arbitrary chronology,
+ * intended for advanced globalization use cases.
+ * <p>
+ * <b>Most applications should declare method signatures, fields and variables
+ * as {@link ZonedDateTime}, not this interface.</b>
+ * <p>
+ * A {@code ChronoZonedDateTime} is the abstract representation of an offset date-time
+ * where the {@code Chronology chronology}, or calendar system, is pluggable.
+ * The date-time is defined in terms of fields expressed by {@link TemporalField},
+ * where most common implementations are defined in {@link ChronoField}.
+ * The chronology defines how the calendar system operates and the meaning of
+ * the standard fields.
+ *
+ * <h3>When to use this interface</h3>
+ * The design of the API encourages the use of {@code ZonedDateTime} rather than this
+ * interface, even in the case where the application needs to deal with multiple
+ * calendar systems. The rationale for this is explored in detail in {@link ChronoLocalDate}.
+ * <p>
+ * Ensure that the discussion in {@code ChronoLocalDate} has been read and understood
+ * before using this interface.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @param <D> the concrete type for the date of this date-time
+ * @since 1.8
+ */
+public interface ChronoZonedDateTime<D extends ChronoLocalDate>
+        extends Temporal, Comparable<ChronoZonedDateTime<?>> {
+
+    /**
+     * Gets a comparator that compares {@code ChronoZonedDateTime} in
+     * time-line order ignoring the chronology.
+     * <p>
+     * This comparator differs from the comparison in {@link #compareTo} in that it
+     * only compares the underlying instant and not the chronology.
+     * This allows dates in different calendar systems to be compared based
+     * on the position of the date-time on the instant time-line.
+     * The underlying comparison is equivalent to comparing the epoch-second and nano-of-second.
+     *
+     * @return a comparator that compares in time-line order ignoring the chronology
+     * @see #isAfter
+     * @see #isBefore
+     * @see #isEqual
+     */
+    static Comparator<ChronoZonedDateTime<?>> timeLineOrder() {
+        return AbstractChronology.INSTANT_ORDER;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ChronoZonedDateTime} from a temporal object.
+     * <p>
+     * This creates a zoned date-time based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ChronoZonedDateTime}.
+     * <p>
+     * The conversion extracts and combines the chronology, date, time and zone
+     * from the temporal object. The behavior is equivalent to using
+     * {@link Chronology#zonedDateTime(TemporalAccessor)} with the extracted chronology.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ChronoZonedDateTime::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date-time, not null
+     * @throws DateTimeException if unable to convert to a {@code ChronoZonedDateTime}
+     * @see Chronology#zonedDateTime(TemporalAccessor)
+     */
+    static ChronoZonedDateTime<?> from(TemporalAccessor temporal) {
+        if (temporal instanceof ChronoZonedDateTime) {
+            return (ChronoZonedDateTime<?>) temporal;
+        }
+        Objects.requireNonNull(temporal, "temporal");
+        Chronology chrono = temporal.query(TemporalQueries.chronology());
+        if (chrono == null) {
+            throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass());
+        }
+        return chrono.zonedDateTime(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    default ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (field == INSTANT_SECONDS || field == OFFSET_SECONDS) {
+                return field.range();
+            }
+            return toLocalDateTime().range(field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    @Override
+    default int get(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS:
+                    throw new UnsupportedTemporalTypeException("Invalid field 'InstantSeconds' for get() method, use getLong() instead");
+                case OFFSET_SECONDS:
+                    return getOffset().getTotalSeconds();
+            }
+            return toLocalDateTime().get(field);
+        }
+        return Temporal.super.get(field);
+    }
+
+    @Override
+    default long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case INSTANT_SECONDS: return toEpochSecond();
+                case OFFSET_SECONDS: return getOffset().getTotalSeconds();
+            }
+            return toLocalDateTime().getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    /**
+     * Gets the local date part of this date-time.
+     * <p>
+     * This returns a local date with the same year, month and day
+     * as this date-time.
+     *
+     * @return the date part of this date-time, not null
+     */
+    default D toLocalDate() {
+        return toLocalDateTime().toLocalDate();
+    }
+
+    /**
+     * Gets the local time part of this date-time.
+     * <p>
+     * This returns a local time with the same hour, minute, second and
+     * nanosecond as this date-time.
+     *
+     * @return the time part of this date-time, not null
+     */
+    default LocalTime toLocalTime() {
+        return toLocalDateTime().toLocalTime();
+    }
+
+    /**
+     * Gets the local date-time part of this date-time.
+     * <p>
+     * This returns a local date with the same year, month and day
+     * as this date-time.
+     *
+     * @return the local date-time part of this date-time, not null
+     */
+    ChronoLocalDateTime<D> toLocalDateTime();
+
+    /**
+     * Gets the chronology of this date-time.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the chronology, not null
+     */
+    default Chronology getChronology() {
+        return toLocalDate().getChronology();
+    }
+
+    /**
+     * Gets the zone offset, such as '+01:00'.
+     * <p>
+     * This is the offset of the local date-time from UTC/Greenwich.
+     *
+     * @return the zone offset, not null
+     */
+    ZoneOffset getOffset();
+
+    /**
+     * Gets the zone ID, such as 'Europe/Paris'.
+     * <p>
+     * This returns the stored time-zone id used to determine the time-zone rules.
+     *
+     * @return the zone ID, not null
+     */
+    ZoneId getZone();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * earlier of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the earlier of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the earlier offset, not null
+     * @throws DateTimeException if no rules can be found for the zone
+     * @throws DateTimeException if no rules are valid for this date-time
+     */
+    ChronoZonedDateTime<D> withEarlierOffsetAtOverlap();
+
+    /**
+     * Returns a copy of this date-time changing the zone offset to the
+     * later of the two valid offsets at a local time-line overlap.
+     * <p>
+     * This method only has any effect when the local time-line overlaps, such as
+     * at an autumn daylight savings cutover. In this scenario, there are two
+     * valid offsets for the local date-time. Calling this method will return
+     * a zoned date-time with the later of the two selected.
+     * <p>
+     * If this method is called when it is not an overlap, {@code this}
+     * is returned.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the later offset, not null
+     * @throws DateTimeException if no rules can be found for the zone
+     * @throws DateTimeException if no rules are valid for this date-time
+     */
+    ChronoZonedDateTime<D> withLaterOffsetAtOverlap();
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the local date-time if possible.
+     * <p>
+     * This method changes the time-zone and retains the local date-time.
+     * The local date-time is only changed if it is invalid for the new zone.
+     * <p>
+     * To change the zone and adjust the local date-time,
+     * use {@link #withZoneSameInstant(ZoneId)}.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
+     */
+    ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone);
+
+    /**
+     * Returns a copy of this date-time with a different time-zone,
+     * retaining the instant.
+     * <p>
+     * This method changes the time-zone and retains the instant.
+     * This normally results in a change to the local date-time.
+     * <p>
+     * This method is based on retaining the same instant, thus gaps and overlaps
+     * in the local time-line have no effect on the result.
+     * <p>
+     * To change the offset while keeping the local time,
+     * use {@link #withZoneSameLocal(ZoneId)}.
+     *
+     * @param zone  the time-zone to change to, not null
+     * @return a {@code ChronoZonedDateTime} based on this date-time with the requested zone, not null
+     * @throws DateTimeException if the result exceeds the supported date range
+     */
+    ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone);
+
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if the specified field can be queried on this date-time.
+     * If false, then calling the {@link #range(TemporalField) range},
+     * {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
+     * methods will throw an exception.
+     * <p>
+     * The set of supported fields is defined by the chronology and normally includes
+     * all {@code ChronoField} fields.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field can be queried, false if not
+     */
+    @Override
+    boolean isSupported(TemporalField field);
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to or subtracted from this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     * <p>
+     * The set of supported units is defined by the chronology and normally includes
+     * all {@code ChronoUnit} units except {@code FOREVER}.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * Whether the unit is supported is determined by the unit.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    @Override
+    default boolean isSupported(TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return unit != FOREVER;
+        }
+        return unit != null && unit.isSupportedBy(this);
+    }
+
+    //-----------------------------------------------------------------------
+    // override for covariant return type
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoZonedDateTime<D> with(TemporalAdjuster adjuster) {
+        return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoZonedDateTime<D> with(TemporalField field, long newValue);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoZonedDateTime<D> plus(TemporalAmount amount) {
+        return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit);
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoZonedDateTime<D> minus(TemporalAmount amount) {
+        return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    default ChronoZonedDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
+        return ChronoZonedDateTimeImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this date-time using the specified query.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    default <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId()) {
+            return (R) getZone();
+        } else if (query == TemporalQueries.offset()) {
+            return (R) getOffset();
+        } else if (query == TemporalQueries.localTime()) {
+            return (R) toLocalTime();
+        } else if (query == TemporalQueries.chronology()) {
+            return (R) getChronology();
+        } else if (query == TemporalQueries.precision()) {
+            return (R) NANOS;
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    /**
+     * Formats this date-time using the specified formatter.
+     * <p>
+     * This date-time will be passed to the formatter to produce a string.
+     * <p>
+     * The default implementation must behave as follows:
+     * <pre>
+     *  return formatter.format(this);
+     * </pre>
+     *
+     * @param formatter  the formatter to use, not null
+     * @return the formatted date-time string, not null
+     * @throws DateTimeException if an error occurs during printing
+     */
+    default String format(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        return formatter.format(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Converts this date-time to an {@code Instant}.
+     * <p>
+     * This returns an {@code Instant} representing the same point on the
+     * time-line as this date-time. The calculation combines the
+     * {@linkplain #toLocalDateTime() local date-time} and
+     * {@linkplain #getOffset() offset}.
+     *
+     * @return an {@code Instant} representing the same instant, not null
+     */
+    default Instant toInstant() {
+        return Instant.ofEpochSecond(toEpochSecond(), toLocalTime().getNano());
+    }
+
+    /**
+     * Converts this date-time to the number of seconds from the epoch
+     * of 1970-01-01T00:00:00Z.
+     * <p>
+     * This uses the {@linkplain #toLocalDateTime() local date-time} and
+     * {@linkplain #getOffset() offset} to calculate the epoch-second value,
+     * which is the number of elapsed seconds from 1970-01-01T00:00:00Z.
+     * Instants on the time-line after the epoch are positive, earlier are negative.
+     *
+     * @return the number of seconds from the epoch of 1970-01-01T00:00:00Z
+     */
+    default long toEpochSecond() {
+        long epochDay = toLocalDate().toEpochDay();
+        long secs = epochDay * 86400 + toLocalTime().toSecondOfDay();
+        secs -= getOffset().getTotalSeconds();
+        return secs;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this date-time to another date-time, including the chronology.
+     * <p>
+     * The comparison is based first on the instant, then on the local date-time,
+     * then on the zone ID, then on the chronology.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     * <p>
+     * If all the date-time objects being compared are in the same chronology, then the
+     * additional chronology stage is not required.
+     * <p>
+     * This default implementation performs the comparison defined above.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    default int compareTo(ChronoZonedDateTime<?> other) {
+        int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
+        if (cmp == 0) {
+            cmp = toLocalTime().getNano() - other.toLocalTime().getNano();
+            if (cmp == 0) {
+                cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
+                if (cmp == 0) {
+                    cmp = getZone().getId().compareTo(other.getZone().getId());
+                    if (cmp == 0) {
+                        cmp = getChronology().compareTo(other.getChronology());
+                    }
+                }
+            }
+        }
+        return cmp;
+    }
+
+    /**
+     * Checks if the instant of this date-time is before that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isBefore(dateTime2.toInstant());}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-second
+     * and nano-of-second.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this point is before the specified date-time
+     */
+    default boolean isBefore(ChronoZonedDateTime<?> other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec < otherEpochSec ||
+            (thisEpochSec == otherEpochSec && toLocalTime().getNano() < other.toLocalTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is after that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} in that it
+     * only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().isAfter(dateTime2.toInstant());}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-second
+     * and nano-of-second.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if this is after the specified date-time
+     */
+    default boolean isAfter(ChronoZonedDateTime<?> other) {
+        long thisEpochSec = toEpochSecond();
+        long otherEpochSec = other.toEpochSecond();
+        return thisEpochSec > otherEpochSec ||
+            (thisEpochSec == otherEpochSec && toLocalTime().getNano() > other.toLocalTime().getNano());
+    }
+
+    /**
+     * Checks if the instant of this date-time is equal to that of the specified date-time.
+     * <p>
+     * This method differs from the comparison in {@link #compareTo} and {@link #equals}
+     * in that it only compares the instant of the date-time. This is equivalent to using
+     * {@code dateTime1.toInstant().equals(dateTime2.toInstant());}.
+     * <p>
+     * This default implementation performs the comparison based on the epoch-second
+     * and nano-of-second.
+     *
+     * @param other  the other date-time to compare to, not null
+     * @return true if the instant equals the instant of the specified date-time
+     */
+    default boolean isEqual(ChronoZonedDateTime<?> other) {
+        return toEpochSecond() == other.toEpochSecond() &&
+                toLocalTime().getNano() == other.toLocalTime().getNano();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this date-time is equal to another date-time.
+     * <p>
+     * The comparison is based on the offset date-time and the zone.
+     * To compare for the same instant on the time-line, use {@link #compareTo}.
+     * Only objects of type {@code ChronoZonedDateTime} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date-time
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this date-time.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this date-time as a {@code String}.
+     * <p>
+     * The output will include the full zoned date-time.
+     *
+     * @return a string representation of this date-time, not null
+     */
+    @Override
+    String toString();
+
+}
diff --git a/java/time/chrono/ChronoZonedDateTimeImpl.java b/java/time/chrono/ChronoZonedDateTimeImpl.java
new file mode 100644
index 0000000..abd21ee
--- /dev/null
+++ b/java/time/chrono/ChronoZonedDateTimeImpl.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoUnit.SECONDS;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalUnit;
+import java.time.zone.ZoneOffsetTransition;
+import java.time.zone.ZoneRules;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A date-time with a time-zone in the calendar neutral API.
+ * <p>
+ * {@code ZoneChronoDateTime} is an immutable representation of a date-time with a time-zone.
+ * This class stores all date and time fields, to a precision of nanoseconds,
+ * as well as a time-zone and zone offset.
+ * <p>
+ * The purpose of storing the time-zone is to distinguish the ambiguous case where
+ * the local time-line overlaps, typically as a result of the end of daylight time.
+ * Information about the local-time can be obtained using methods on the time-zone.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @serial Document the delegation of this class in the serialized-form specification.
+ * @param <D> the concrete type for the date of this date-time
+ * @since 1.8
+ */
+final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate>
+        implements ChronoZonedDateTime<D>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -5261813987200935591L;
+
+    /**
+     * The local date-time.
+     */
+    private final transient ChronoLocalDateTimeImpl<D> dateTime;
+    /**
+     * The zone offset.
+     */
+    private final transient ZoneOffset offset;
+    /**
+     * The zone ID.
+     */
+    private final transient ZoneId zone;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance from a local date-time using the preferred offset if possible.
+     *
+     * @param localDateTime  the local date-time, not null
+     * @param zone  the zone identifier, not null
+     * @param preferredOffset  the zone offset, null if no preference
+     * @return the zoned date-time, not null
+     */
+    static <R extends ChronoLocalDate> ChronoZonedDateTime<R> ofBest(
+            ChronoLocalDateTimeImpl<R> localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
+        Objects.requireNonNull(localDateTime, "localDateTime");
+        Objects.requireNonNull(zone, "zone");
+        if (zone instanceof ZoneOffset) {
+            return new ChronoZonedDateTimeImpl<>(localDateTime, (ZoneOffset) zone, zone);
+        }
+        ZoneRules rules = zone.getRules();
+        LocalDateTime isoLDT = LocalDateTime.from(localDateTime);
+        List<ZoneOffset> validOffsets = rules.getValidOffsets(isoLDT);
+        ZoneOffset offset;
+        if (validOffsets.size() == 1) {
+            offset = validOffsets.get(0);
+        } else if (validOffsets.size() == 0) {
+            ZoneOffsetTransition trans = rules.getTransition(isoLDT);
+            localDateTime = localDateTime.plusSeconds(trans.getDuration().getSeconds());
+            offset = trans.getOffsetAfter();
+        } else {
+            if (preferredOffset != null && validOffsets.contains(preferredOffset)) {
+                offset = preferredOffset;
+            } else {
+                offset = validOffsets.get(0);
+            }
+        }
+        Objects.requireNonNull(offset, "offset");  // protect against bad ZoneRules
+        return new ChronoZonedDateTimeImpl<>(localDateTime, offset, zone);
+    }
+
+    /**
+     * Obtains an instance from an instant using the specified time-zone.
+     *
+     * @param chrono  the chronology, not null
+     * @param instant  the instant, not null
+     * @param zone  the zone identifier, not null
+     * @return the zoned date-time, not null
+     */
+    static ChronoZonedDateTimeImpl<?> ofInstant(Chronology chrono, Instant instant, ZoneId zone) {
+        ZoneRules rules = zone.getRules();
+        ZoneOffset offset = rules.getOffset(instant);
+        Objects.requireNonNull(offset, "offset");  // protect against bad ZoneRules
+        LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
+        ChronoLocalDateTimeImpl<?> cldt = (ChronoLocalDateTimeImpl<?>)chrono.localDateTime(ldt);
+        return new ChronoZonedDateTimeImpl<>(cldt, offset, zone);
+    }
+
+    /**
+     * Obtains an instance from an {@code Instant}.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone to use, validated not null
+     * @return the zoned date-time, validated not null
+     */
+    @SuppressWarnings("unchecked")
+    private ChronoZonedDateTimeImpl<D> create(Instant instant, ZoneId zone) {
+        return (ChronoZonedDateTimeImpl<D>)ofInstant(getChronology(), instant, zone);
+    }
+
+    /**
+     * Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} ensuring it bas the specified chronology.
+     *
+     * @param chrono  the chronology to check for, not null
+     * @param temporal  a date-time to cast, not null
+     * @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
+     * @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
+     *  or the chronology is not equal this Chronology
+     */
+    static <R extends ChronoLocalDate> ChronoZonedDateTimeImpl<R> ensureValid(Chronology chrono, Temporal temporal) {
+        @SuppressWarnings("unchecked")
+        ChronoZonedDateTimeImpl<R> other = (ChronoZonedDateTimeImpl<R>) temporal;
+        if (chrono.equals(other.getChronology()) == false) {
+            throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
+                    + ", actual: " + other.getChronology().getId());
+        }
+        return other;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param dateTime  the date-time, not null
+     * @param offset  the zone offset, not null
+     * @param zone  the zone ID, not null
+     */
+    private ChronoZonedDateTimeImpl(ChronoLocalDateTimeImpl<D> dateTime, ZoneOffset offset, ZoneId zone) {
+        this.dateTime = Objects.requireNonNull(dateTime, "dateTime");
+        this.offset = Objects.requireNonNull(offset, "offset");
+        this.zone = Objects.requireNonNull(zone, "zone");
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ZoneOffset getOffset() {
+        return offset;
+    }
+
+    @Override
+    public ChronoZonedDateTime<D> withEarlierOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
+        if (trans != null && trans.isOverlap()) {
+            ZoneOffset earlierOffset = trans.getOffsetBefore();
+            if (earlierOffset.equals(offset) == false) {
+                return new ChronoZonedDateTimeImpl<>(dateTime, earlierOffset, zone);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ChronoZonedDateTime<D> withLaterOffsetAtOverlap() {
+        ZoneOffsetTransition trans = getZone().getRules().getTransition(LocalDateTime.from(this));
+        if (trans != null) {
+            ZoneOffset offset = trans.getOffsetAfter();
+            if (offset.equals(getOffset()) == false) {
+                return new ChronoZonedDateTimeImpl<>(dateTime, offset, zone);
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoLocalDateTime<D> toLocalDateTime() {
+        return dateTime;
+    }
+
+    @Override
+    public ZoneId getZone() {
+        return zone;
+    }
+
+    @Override
+    public ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone) {
+        return ofBest(dateTime, zone, offset);
+    }
+
+    @Override
+    public ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        return this.zone.equals(zone) ? this : create(dateTime.toInstant(offset), zone);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoZonedDateTime<D> with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            switch (f) {
+                case INSTANT_SECONDS: return plus(newValue - toEpochSecond(), SECONDS);
+                case OFFSET_SECONDS: {
+                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(f.checkValidIntValue(newValue));
+                    return create(dateTime.toInstant(offset), zone);
+                }
+            }
+            return ofBest(dateTime.with(field, newValue), zone, offset);
+        }
+        return ChronoZonedDateTimeImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ChronoZonedDateTime<D> plus(long amountToAdd, TemporalUnit unit) {
+        if (unit instanceof ChronoUnit) {
+            return with(dateTime.plus(amountToAdd, unit));
+        }
+        return ChronoZonedDateTimeImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd));   /// TODO: Generics replacement Risk!
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long until(Temporal endExclusive, TemporalUnit unit) {
+        Objects.requireNonNull(endExclusive, "endExclusive");
+        @SuppressWarnings("unchecked")
+        ChronoZonedDateTime<D> end = (ChronoZonedDateTime<D>) getChronology().zonedDateTime(endExclusive);
+        if (unit instanceof ChronoUnit) {
+            end = end.withZoneSameInstant(offset);
+            return dateTime.until(end.toLocalDateTime(), unit);
+        }
+        Objects.requireNonNull(unit, "unit");
+        return unit.between(this, end);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the ChronoZonedDateTime using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(3);                  // identifies a ChronoZonedDateTime
+     *  out.writeObject(toLocalDateTime());
+     *  out.writeObject(getOffset());
+     *  out.writeObject(getZone());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.CHRONO_ZONE_DATE_TIME_TYPE, this);
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(dateTime);
+        out.writeObject(offset);
+        out.writeObject(zone);
+    }
+
+    static ChronoZonedDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        ChronoLocalDateTime<?> dateTime = (ChronoLocalDateTime<?>) in.readObject();
+        ZoneOffset offset = (ZoneOffset) in.readObject();
+        ZoneId zone = (ZoneId) in.readObject();
+        return dateTime.atZone(offset).withZoneSameLocal(zone);
+        // TODO: ZDT uses ofLenient()
+    }
+
+    //-------------------------------------------------------------------------
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ChronoZonedDateTime) {
+            return compareTo((ChronoZonedDateTime<?>) obj) == 0;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return toLocalDateTime().hashCode() ^ getOffset().hashCode() ^ Integer.rotateLeft(getZone().hashCode(), 3);
+    }
+
+    @Override
+    public String toString() {
+        String str = toLocalDateTime().toString() + getOffset().toString();
+        if (getOffset() != getZone()) {
+            str += '[' + getZone().toString() + ']';
+        }
+        return str;
+    }
+
+
+}
diff --git a/java/time/chrono/Chronology.java b/java/time/chrono/Chronology.java
new file mode 100644
index 0000000..0b2d2e1
--- /dev/null
+++ b/java/time/chrono/Chronology.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.ResolverStyle;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A calendar system, used to organize and identify dates.
+ * <p>
+ * The main date and time API is built on the ISO calendar system.
+ * The chronology operates behind the scenes to represent the general concept of a calendar system.
+ * For example, the Japanese, Minguo, Thai Buddhist and others.
+ * <p>
+ * Most other calendar systems also operate on the shared concepts of year, month and day,
+ * linked to the cycles of the Earth around the Sun, and the Moon around the Earth.
+ * These shared concepts are defined by {@link ChronoField} and are available
+ * for use by any {@code Chronology} implementation:
+ * <pre>
+ *   LocalDate isoDate = ...
+ *   ThaiBuddhistDate thaiDate = ...
+ *   int isoYear = isoDate.get(ChronoField.YEAR);
+ *   int thaiYear = thaiDate.get(ChronoField.YEAR);
+ * </pre>
+ * As shown, although the date objects are in different calendar systems, represented by different
+ * {@code Chronology} instances, both can be queried using the same constant on {@code ChronoField}.
+ * For a full discussion of the implications of this, see {@link ChronoLocalDate}.
+ * In general, the advice is to use the known ISO-based {@code LocalDate}, rather than
+ * {@code ChronoLocalDate}.
+ * <p>
+ * While a {@code Chronology} object typically uses {@code ChronoField} and is based on
+ * an era, year-of-era, month-of-year, day-of-month model of a date, this is not required.
+ * A {@code Chronology} instance may represent a totally different kind of calendar system,
+ * such as the Mayan.
+ * <p>
+ * In practical terms, the {@code Chronology} instance also acts as a factory.
+ * The {@link #of(String)} method allows an instance to be looked up by identifier,
+ * while the {@link #ofLocale(Locale)} method allows lookup by locale.
+ * <p>
+ * The {@code Chronology} instance provides a set of methods to create {@code ChronoLocalDate} instances.
+ * The date classes are used to manipulate specific dates.
+ * <ul>
+ * <li> {@link #dateNow() dateNow()}
+ * <li> {@link #dateNow(Clock) dateNow(clock)}
+ * <li> {@link #dateNow(ZoneId) dateNow(zone)}
+ * <li> {@link #date(int, int, int) date(yearProleptic, month, day)}
+ * <li> {@link #date(Era, int, int, int) date(era, yearOfEra, month, day)}
+ * <li> {@link #dateYearDay(int, int) dateYearDay(yearProleptic, dayOfYear)}
+ * <li> {@link #dateYearDay(Era, int, int) dateYearDay(era, yearOfEra, dayOfYear)}
+ * <li> {@link #date(TemporalAccessor) date(TemporalAccessor)}
+ * </ul>
+ *
+ * <h3 id="addcalendars">Adding New Calendars</h3>
+ * The set of available chronologies can be extended by applications.
+ * Adding a new calendar system requires the writing of an implementation of
+ * {@code Chronology}, {@code ChronoLocalDate} and {@code Era}.
+ * The majority of the logic specific to the calendar system will be in the
+ * {@code ChronoLocalDate} implementation.
+ * The {@code Chronology} implementation acts as a factory.
+ * <p>
+ * To permit the discovery of additional chronologies, the {@link java.util.ServiceLoader ServiceLoader}
+ * is used. A file must be added to the {@code META-INF/services} directory with the
+ * name 'java.time.chrono.Chronology' listing the implementation classes.
+ * See the ServiceLoader for more details on service loading.
+ * For lookup by id or calendarType, the system provided calendars are found
+ * first followed by application provided calendars.
+ * <p>
+ * Each chronology must define a chronology ID that is unique within the system.
+ * If the chronology represents a calendar system defined by the
+ * CLDR specification then the calendar type is the concatenation of the
+ * CLDR type and, if applicable, the CLDR variant,
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Subclasses should be Serializable wherever possible.
+ *
+ * @since 1.8
+ */
+public interface Chronology extends Comparable<Chronology> {
+
+    /**
+     * Obtains an instance of {@code Chronology} from a temporal object.
+     * <p>
+     * This obtains a chronology based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code Chronology}.
+     * <p>
+     * The conversion will obtain the chronology using {@link TemporalQueries#chronology()}.
+     * If the specified temporal object does not have a chronology, {@link IsoChronology} is returned.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code Chronology::from}.
+     *
+     * @param temporal  the temporal to convert, not null
+     * @return the chronology, not null
+     * @throws DateTimeException if unable to convert to an {@code Chronology}
+     */
+    static Chronology from(TemporalAccessor temporal) {
+        Objects.requireNonNull(temporal, "temporal");
+        Chronology obj = temporal.query(TemporalQueries.chronology());
+        return (obj != null ? obj : IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chronology} from a locale.
+     * <p>
+     * This returns a {@code Chronology} based on the specified locale,
+     * typically returning {@code IsoChronology}. Other calendar systems
+     * are only returned if they are explicitly selected within the locale.
+     * <p>
+     * The {@link Locale} class provide access to a range of information useful
+     * for localizing an application. This includes the language and region,
+     * such as "en-GB" for English as used in Great Britain.
+     * <p>
+     * The {@code Locale} class also supports an extension mechanism that
+     * can be used to identify a calendar system. The mechanism is a form
+     * of key-value pairs, where the calendar system has the key "ca".
+     * For example, the locale "en-JP-u-ca-japanese" represents the English
+     * language as used in Japan with the Japanese calendar system.
+     * <p>
+     * This method finds the desired calendar system by in a manner equivalent
+     * to passing "ca" to {@link Locale#getUnicodeLocaleType(String)}.
+     * If the "ca" key is not present, then {@code IsoChronology} is returned.
+     * <p>
+     * Note that the behavior of this method differs from the older
+     * {@link java.util.Calendar#getInstance(Locale)} method.
+     * If that method receives a locale of "th_TH" it will return {@code BuddhistCalendar}.
+     * By contrast, this method will return {@code IsoChronology}.
+     * Passing the locale "th-TH-u-ca-buddhist" into either method will
+     * result in the Thai Buddhist calendar system and is therefore the
+     * recommended approach going forward for Thai calendar system localization.
+     * <p>
+     * A similar, but simpler, situation occurs for the Japanese calendar system.
+     * The locale "jp_JP_JP" has previously been used to access the calendar.
+     * However, unlike the Thai locale, "ja_JP_JP" is automatically converted by
+     * {@code Locale} to the modern and recommended form of "ja-JP-u-ca-japanese".
+     * Thus, there is no difference in behavior between this method and
+     * {@code Calendar#getInstance(Locale)}.
+     *
+     * @param locale  the locale to use to obtain the calendar system, not null
+     * @return the calendar system associated with the locale, not null
+     * @throws DateTimeException if the locale-specified calendar cannot be found
+     */
+    static Chronology ofLocale(Locale locale) {
+        return AbstractChronology.ofLocale(locale);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code Chronology} from a chronology ID or
+     * calendar system type.
+     * <p>
+     * This returns a chronology based on either the ID or the type.
+     * The {@link #getId() chronology ID} uniquely identifies the chronology.
+     * The {@link #getCalendarType() calendar system type} is defined by the
+     * CLDR specification.
+     * <p>
+     * The chronology may be a system chronology or a chronology
+     * provided by the application via ServiceLoader configuration.
+     * <p>
+     * Since some calendars can be customized, the ID or type typically refers
+     * to the default customization. For example, the Gregorian calendar can have multiple
+     * cutover dates from the Julian, but the lookup only provides the default cutover date.
+     *
+     * @param id  the chronology ID or calendar system type, not null
+     * @return the chronology with the identifier requested, not null
+     * @throws DateTimeException if the chronology cannot be found
+     */
+    static Chronology of(String id) {
+        return AbstractChronology.of(id);
+    }
+
+    /**
+     * Returns the available chronologies.
+     * <p>
+     * Each returned {@code Chronology} is available for use in the system.
+     * The set of chronologies includes the system chronologies and
+     * any chronologies provided by the application via ServiceLoader
+     * configuration.
+     *
+     * @return the independent, modifiable set of the available chronology IDs, not null
+     */
+    static Set<Chronology> getAvailableChronologies() {
+        return AbstractChronology.getAvailableChronologies();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology.
+     * <p>
+     * The ID uniquely identifies the {@code Chronology}.
+     * It can be used to lookup the {@code Chronology} using {@link #of(String)}.
+     *
+     * @return the chronology ID, not null
+     * @see #getCalendarType()
+     */
+    String getId();
+
+    /**
+     * Gets the calendar type of the calendar system.
+     * <p>
+     * The calendar type is an identifier defined by the CLDR and
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specifications
+     * to uniquely identification a calendar.
+     * The {@code getCalendarType} is the concatenation of the CLDR calendar type
+     * and the variant, if applicable, is appended separated by "-".
+     * The calendar type is used to lookup the {@code Chronology} using {@link #of(String)}.
+     *
+     * @return the calendar system type, null if the calendar is not defined by CLDR/LDML
+     * @see #getId()
+     */
+    String getCalendarType();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in this chronology from the era, year-of-era,
+     * month-of-year and day-of-month fields.
+     *
+     * @implSpec
+     * The default implementation combines the era and year-of-era into a proleptic
+     * year before calling {@link #date(int, int, int)}.
+     *
+     * @param era  the era of the correct type for the chronology, not null
+     * @param yearOfEra  the chronology year-of-era
+     * @param month  the chronology month-of-year
+     * @param dayOfMonth  the chronology day-of-month
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
+     */
+    default ChronoLocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in this chronology from the proleptic-year,
+     * month-of-year and day-of-month fields.
+     *
+     * @param prolepticYear  the chronology proleptic-year
+     * @param month  the chronology month-of-year
+     * @param dayOfMonth  the chronology day-of-month
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth);
+
+    /**
+     * Obtains a local date in this chronology from the era, year-of-era and
+     * day-of-year fields.
+     *
+     * @implSpec
+     * The default implementation combines the era and year-of-era into a proleptic
+     * year before calling {@link #dateYearDay(int, int)}.
+     *
+     * @param era  the era of the correct type for the chronology, not null
+     * @param yearOfEra  the chronology year-of-era
+     * @param dayOfYear  the chronology day-of-year
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
+     */
+    default ChronoLocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains a local date in this chronology from the proleptic-year and
+     * day-of-year fields.
+     *
+     * @param prolepticYear  the chronology proleptic-year
+     * @param dayOfYear  the chronology day-of-year
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear);
+
+    /**
+     * Obtains a local date in this chronology from the epoch-day.
+     * <p>
+     * The definition of {@link ChronoField#EPOCH_DAY EPOCH_DAY} is the same
+     * for all calendar systems, thus it can be used for conversion.
+     *
+     * @param epochDay  the epoch day
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    ChronoLocalDate dateEpochDay(long epochDay);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current local date in this chronology from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #dateNow(Clock)}.
+     *
+     * @return the current local date using the system clock and default time-zone, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    default ChronoLocalDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current local date in this chronology from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #dateNow(Clock)}.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current local date using the system clock, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    default ChronoLocalDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current local date in this chronology from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @implSpec
+     * The default implementation invokes {@link #date(TemporalAccessor)}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    default ChronoLocalDate dateNow(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        return date(LocalDate.now(clock));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in this chronology from another temporal object.
+     * <p>
+     * This obtains a date in this chronology based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ChronoLocalDate}.
+     * <p>
+     * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
+     * field, which is standardized across calendar systems.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code aChronology::date}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date in this chronology, not null
+     * @throws DateTimeException if unable to create the date
+     * @see ChronoLocalDate#from(TemporalAccessor)
+     */
+    ChronoLocalDate date(TemporalAccessor temporal);
+
+    /**
+     * Obtains a local date-time in this chronology from another temporal object.
+     * <p>
+     * This obtains a date-time in this chronology based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ChronoLocalDateTime}.
+     * <p>
+     * The conversion extracts and combines the {@code ChronoLocalDate} and the
+     * {@code LocalTime} from the temporal object.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * The result uses this chronology.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code aChronology::localDateTime}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the local date-time in this chronology, not null
+     * @throws DateTimeException if unable to create the date-time
+     * @see ChronoLocalDateTime#from(TemporalAccessor)
+     */
+    default ChronoLocalDateTime<? extends ChronoLocalDate> localDateTime(TemporalAccessor temporal) {
+        try {
+            return date(temporal).atTime(LocalTime.from(temporal));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain ChronoLocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    /**
+     * Obtains a {@code ChronoZonedDateTime} in this chronology from another temporal object.
+     * <p>
+     * This obtains a zoned date-time in this chronology based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ChronoZonedDateTime}.
+     * <p>
+     * The conversion will first obtain a {@code ZoneId} from the temporal object,
+     * falling back to a {@code ZoneOffset} if necessary. It will then try to obtain
+     * an {@code Instant}, falling back to a {@code ChronoLocalDateTime} if necessary.
+     * The result will be either the combination of {@code ZoneId} or {@code ZoneOffset}
+     * with {@code Instant} or {@code ChronoLocalDateTime}.
+     * Implementations are permitted to perform optimizations such as accessing
+     * those fields that are equivalent to the relevant objects.
+     * The result uses this chronology.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code aChronology::zonedDateTime}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the zoned date-time in this chronology, not null
+     * @throws DateTimeException if unable to create the date-time
+     * @see ChronoZonedDateTime#from(TemporalAccessor)
+     */
+    default ChronoZonedDateTime<? extends ChronoLocalDate> zonedDateTime(TemporalAccessor temporal) {
+        try {
+            ZoneId zone = ZoneId.from(temporal);
+            try {
+                Instant instant = Instant.from(temporal);
+                return zonedDateTime(instant, zone);
+
+            } catch (DateTimeException ex1) {
+                ChronoLocalDateTimeImpl<?> cldt = ChronoLocalDateTimeImpl.ensureValid(this, localDateTime(temporal));
+                return ChronoZonedDateTimeImpl.ofBest(cldt, zone, null);
+            }
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain ChronoZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+        }
+    }
+
+    /**
+     * Obtains a {@code ChronoZonedDateTime} in this chronology from an {@code Instant}.
+     * <p>
+     * This obtains a zoned date-time with the same instant as that specified.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    default ChronoZonedDateTime<? extends ChronoLocalDate> zonedDateTime(Instant instant, ZoneId zone) {
+        return ChronoZonedDateTimeImpl.ofInstant(this, instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * A leap-year is a year of a longer length than normal.
+     * The exact meaning is determined by the chronology according to the following constraints.
+     * <ul>
+     * <li>a leap-year must imply a year-length longer than a non leap-year.
+     * <li>a chronology that does not support the concept of a year must return false.
+     * </ul>
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    boolean isLeapYear(long prolepticYear);
+
+    /**
+     * Calculates the proleptic-year given the era and year-of-era.
+     * <p>
+     * This combines the era and year-of-era into the single proleptic-year field.
+     * <p>
+     * If the chronology makes active use of eras, such as {@code JapaneseChronology}
+     * then the year-of-era will be validated against the era.
+     * For other chronologies, validation is optional.
+     *
+     * @param era  the era of the correct type for the chronology, not null
+     * @param yearOfEra  the chronology year-of-era
+     * @return the proleptic-year
+     * @throws DateTimeException if unable to convert to a proleptic-year,
+     *  such as if the year is invalid for the era
+     * @throws ClassCastException if the {@code era} is not of the correct type for the chronology
+     */
+    int prolepticYear(Era era, int yearOfEra);
+
+    /**
+     * Creates the chronology era object from the numeric value.
+     * <p>
+     * The era is, conceptually, the largest division of the time-line.
+     * Most calendar systems have a single epoch dividing the time-line into two eras.
+     * However, some have multiple eras, such as one for the reign of each leader.
+     * The exact meaning is determined by the chronology according to the following constraints.
+     * <p>
+     * The era in use at 1970-01-01 must have the value 1.
+     * Later eras must have sequentially higher values.
+     * Earlier eras must have sequentially lower values.
+     * Each chronology must refer to an enum or similar singleton to provide the era values.
+     * <p>
+     * This method returns the singleton era of the correct type for the specified era value.
+     *
+     * @param eraValue  the era value
+     * @return the calendar system era, not null
+     * @throws DateTimeException if unable to create the era
+     */
+    Era eraOf(int eraValue);
+
+    /**
+     * Gets the list of eras for the chronology.
+     * <p>
+     * Most calendar systems have an era, within which the year has meaning.
+     * If the calendar system does not support the concept of eras, an empty
+     * list must be returned.
+     *
+     * @return the list of eras for the chronology, may be immutable, not null
+     */
+    List<Era> eras();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * <p>
+     * Note that the result only describes the minimum and maximum valid values
+     * and it is important not to read too much into them. For example, there
+     * could be values within the range that are invalid for the field.
+     * <p>
+     * This method will return a result whether or not the chronology supports the field.
+     *
+     * @param field  the field to get the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     */
+    ValueRange range(ChronoField field);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation of this chronology.
+     * <p>
+     * This returns the textual name used to identify the chronology,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     *
+     * @implSpec
+     * The default implementation behaves as though the formatter was used to
+     * format the chronology textual name.
+     *
+     * @param style  the style of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the chronology, not null
+     */
+    default String getDisplayName(TextStyle style, Locale locale) {
+        TemporalAccessor temporal = new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                return false;
+            }
+            @Override
+            public long getLong(TemporalField field) {
+                throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == TemporalQueries.chronology()) {
+                    return (R) Chronology.this;
+                }
+                return TemporalAccessor.super.query(query);
+            }
+        };
+        return new DateTimeFormatterBuilder().appendChronologyText(style).toFormatter(locale).format(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Resolves parsed {@code ChronoField} values into a date during parsing.
+     * <p>
+     * Most {@code TemporalField} implementations are resolved using the
+     * resolve method on the field. By contrast, the {@code ChronoField} class
+     * defines fields that only have meaning relative to the chronology.
+     * As such, {@code ChronoField} date fields are resolved here in the
+     * context of a specific chronology.
+     * <p>
+     * The default implementation, which explains typical resolve behaviour,
+     * is provided in {@link AbstractChronology}.
+     *
+     * @param fieldValues  the map of fields to values, which can be updated, not null
+     * @param resolverStyle  the requested type of resolve, not null
+     * @return the resolved date, null if insufficient information to create a date
+     * @throws DateTimeException if the date cannot be resolved, typically
+     *  because of a conflict in the input data
+     */
+    ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a period for this chronology based on years, months and days.
+     * <p>
+     * This returns a period tied to this chronology using the specified
+     * years, months and days.  All supplied chronologies use periods
+     * based on years, months and days, however the {@code ChronoPeriod} API
+     * allows the period to be represented using other units.
+     *
+     * @implSpec
+     * The default implementation returns an implementation class suitable
+     * for most calendar systems. It is based solely on the three units.
+     * Normalization, addition and subtraction derive the number of months
+     * in a year from the {@link #range(ChronoField)}. If the number of
+     * months within a year is fixed, then the calculation approach for
+     * addition, subtraction and normalization is slightly different.
+     * <p>
+     * If implementing an unusual calendar system that is not based on
+     * years, months and days, or where you want direct control, then
+     * the {@code ChronoPeriod} interface must be directly implemented.
+     * <p>
+     * The returned period is immutable and thread-safe.
+     *
+     * @param years  the number of years, may be negative
+     * @param months  the number of years, may be negative
+     * @param days  the number of years, may be negative
+     * @return the period in terms of this chronology, not null
+     */
+    default ChronoPeriod period(int years, int months, int days) {
+        return new ChronoPeriodImpl(this, years, months, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this chronology to another chronology.
+     * <p>
+     * The comparison order first by the chronology ID string, then by any
+     * additional information specific to the subclass.
+     * It is "consistent with equals", as defined by {@link Comparable}.
+     *
+     * @param other  the other chronology to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    int compareTo(Chronology other);
+
+    /**
+     * Checks if this chronology is equal to another chronology.
+     * <p>
+     * The comparison is based on the entire state of the object.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other chronology
+     */
+    @Override
+    boolean equals(Object obj);
+
+    /**
+     * A hash code for this chronology.
+     * <p>
+     * The hash code should be based on the entire state of the object.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    int hashCode();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this chronology as a {@code String}.
+     * <p>
+     * The format should include the entire state of the object.
+     *
+     * @return a string representation of this chronology, not null
+     */
+    @Override
+    String toString();
+
+}
diff --git a/java/time/chrono/Era.java b/java/time/chrono/Era.java
new file mode 100644
index 0000000..0e3c533
--- /dev/null
+++ b/java/time/chrono/Era.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoUnit.ERAS;
+
+import java.time.DateTimeException;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.Temporal;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+
+/**
+ * An era of the time-line.
+ * <p>
+ * Most calendar systems have a single epoch dividing the time-line into two eras.
+ * However, some calendar systems, have multiple eras, such as one for the reign
+ * of each leader.
+ * In all cases, the era is conceptually the largest division of the time-line.
+ * Each chronology defines the Era's that are known Eras and a
+ * {@link Chronology#eras Chronology.eras} to get the valid eras.
+ * <p>
+ * For example, the Thai Buddhist calendar system divides time into two eras,
+ * before and after a single date. By contrast, the Japanese calendar system
+ * has one era for the reign of each Emperor.
+ * <p>
+ * Instances of {@code Era} may be compared using the {@code ==} operator.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations must be singletons - final, immutable and thread-safe.
+ * It is recommended to use an enum whenever possible.
+ *
+ * @since 1.8
+ */
+public interface Era extends TemporalAccessor, TemporalAdjuster {
+
+    /**
+     * Gets the numeric value associated with the era as defined by the chronology.
+     * Each chronology defines the predefined Eras and methods to list the Eras
+     * of the chronology.
+     * <p>
+     * All fields, including eras, have an associated numeric value.
+     * The meaning of the numeric value for era is determined by the chronology
+     * according to these principles:
+     * <ul>
+     * <li>The era in use at the epoch 1970-01-01 (ISO) has the value 1.
+     * <li>Later eras have sequentially higher values.
+     * <li>Earlier eras have sequentially lower values, which may be negative.
+     * </ul>
+     *
+     * @return the numeric era value
+     */
+    int getValue();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this era can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns true.
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this era, false if not
+     */
+    @Override
+    default boolean isSupported(TemporalField field) {
+        if (field instanceof ChronoField) {
+            return field == ERA;
+        }
+        return field != null && field.isSupportedBy(this);
+    }
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This era is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the range.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     * <p>
+     * The default implementation must return a range for {@code ERA} from
+     * zero to one, suitable for two era calendar systems such as ISO.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    @Override  // override for Javadoc
+    default ValueRange range(TemporalField field) {
+        return TemporalAccessor.super.range(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this era as an {@code int}.
+     * <p>
+     * This queries this era for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the value of the era.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override  // override for Javadoc and performance
+    default int get(TemporalField field) {
+        if (field == ERA) {
+            return getValue();
+        }
+        return TemporalAccessor.super.get(field);
+    }
+
+    /**
+     * Gets the value of the specified field from this era as a {@code long}.
+     * <p>
+     * This queries this era for the value of the specified field.
+     * If it is not possible to return the value, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the value of the era.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument. Whether the value can be obtained,
+     * and what the value represents, is determined by the field.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    default long getLong(TemporalField field) {
+        if (field == ERA) {
+            return getValue();
+        } else if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Queries this era using the specified query.
+     * <p>
+     * This queries this era using the specified query strategy object.
+     * The {@code TemporalQuery} object defines the logic to be used to
+     * obtain the result. Read the documentation of the query to understand
+     * what the result of this method will be.
+     * <p>
+     * The result of this method is obtained by invoking the
+     * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
+     * specified query passing {@code this} as the argument.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query (defined by the query)
+     * @throws ArithmeticException if numeric overflow occurs (defined by the query)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    default <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.precision()) {
+            return (R) ERAS;
+        }
+        return TemporalAccessor.super.query(query);
+    }
+
+    /**
+     * Adjusts the specified temporal object to have the same era as this object.
+     * <p>
+     * This returns a temporal object of the same observable type as the input
+     * with the era changed to be the same as this.
+     * <p>
+     * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
+     * passing {@link ChronoField#ERA} as the field.
+     * <p>
+     * In most cases, it is clearer to reverse the calling pattern by using
+     * {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisEra.adjustInto(temporal);
+     *   temporal = temporal.with(thisEra);
+     * </pre>
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param temporal  the target object to be adjusted, not null
+     * @return the adjusted object, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    @Override
+    default Temporal adjustInto(Temporal temporal) {
+        return temporal.with(ERA, getValue());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the textual representation of this era.
+     * <p>
+     * This returns the textual name used to identify the era,
+     * suitable for presentation to the user.
+     * The parameters control the style of the returned text and the locale.
+     * <p>
+     * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
+     * <p>
+     * This default implementation is suitable for all implementations.
+     *
+     * @param style  the style of the text required, not null
+     * @param locale  the locale to use, not null
+     * @return the text value of the era, not null
+     */
+    default String getDisplayName(TextStyle style, Locale locale) {
+        return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).format(this);
+    }
+
+    // NOTE: methods to convert year-of-era/proleptic-year cannot be here as they may depend on month/day (Japanese)
+}
diff --git a/java/time/chrono/HijrahChronology.java b/java/time/chrono/HijrahChronology.java
new file mode 100644
index 0000000..e7b3554
--- /dev/null
+++ b/java/time/chrono/HijrahChronology.java
@@ -0,0 +1,1095 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+
+import sun.util.logging.PlatformLogger;
+
+/**
+ * The Hijrah calendar is a lunar calendar supporting Islamic calendars.
+ * <p>
+ * The HijrahChronology follows the rules of the Hijrah calendar system. The Hijrah
+ * calendar has several variants based on differences in when the new moon is
+ * determined to have occurred and where the observation is made.
+ * In some variants the length of each month is
+ * computed algorithmically from the astronomical data for the moon and earth and
+ * in others the length of the month is determined by an authorized sighting
+ * of the new moon. For the algorithmically based calendars the calendar
+ * can project into the future.
+ * For sighting based calendars only historical data from past
+ * sightings is available.
+ * <p>
+ * The length of each month is 29 or 30 days.
+ * Ordinary years have 354 days; leap years have 355 days.
+ *
+ * <p>
+ * CLDR and LDML identify variants:
+ * <table cellpadding="2" summary="Variants of Hijrah Calendars">
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left" >Chronology ID</th>
+ * <th class="colFirst" align="left" >Calendar Type</th>
+ * <th class="colFirst" align="left" >Locale extension, see {@link java.util.Locale}</th>
+ * <th class="colLast" align="left" >Description</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="altColor">
+ * <td>Hijrah-umalqura</td>
+ * <td>islamic-umalqura</td>
+ * <td>ca-islamic-umalqura</td>
+ * <td>Islamic - Umm Al-Qura calendar of Saudi Arabia</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>Additional variants may be available through {@link Chronology#getAvailableChronologies()}.
+ *
+ * <p>Example</p>
+ * <p>
+ * Selecting the chronology from the locale uses {@link Chronology#ofLocale}
+ * to find the Chronology based on Locale supported BCP 47 extension mechanism
+ * to request a specific calendar ("ca"). For example,
+ * </p>
+ * <pre>
+ *      Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-umalqura");
+ *      Chronology chrono = Chronology.ofLocale(locale);
+ * </pre>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @implNote
+ * Each Hijrah variant is configured individually. Each variant is defined by a
+ * property resource that defines the {@code ID}, the {@code calendar type},
+ * the start of the calendar, the alignment with the
+ * ISO calendar, and the length of each month for a range of years.
+ * The variants are identified in the {@code calendars.properties} file.
+ * The new properties are prefixed with {@code "calendars.hijrah."}:
+ * <table cellpadding="2" border="0" summary="Configuration of Hijrah Calendar Variants">
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left">Property Name</th>
+ * <th class="colFirst" align="left">Property value</th>
+ * <th class="colLast" align="left">Description </th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="altColor">
+ * <td>calendars.hijrah.{ID}</td>
+ * <td>The property resource defining the {@code {ID}} variant</td>
+ * <td>The property resource is located with the {@code calendars.properties} file</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td>calendars.hijrah.{ID}.type</td>
+ * <td>The calendar type</td>
+ * <td>LDML defines the calendar type names</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * The Hijrah property resource is a set of properties that describe the calendar.
+ * The syntax is defined by {@code java.util.Properties#load(Reader)}.
+ * <table cellpadding="2" summary="Configuration of Hijrah Calendar">
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left" > Property Name</th>
+ * <th class="colFirst" align="left" > Property value</th>
+ * <th class="colLast" align="left" > Description </th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="altColor">
+ * <td>id</td>
+ * <td>Chronology Id, for example, "Hijrah-umalqura"</td>
+ * <td>The Id of the calendar in common usage</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td>type</td>
+ * <td>Calendar type, for example, "islamic-umalqura"</td>
+ * <td>LDML defines the calendar types</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>version</td>
+ * <td>Version, for example: "1.8.0_1"</td>
+ * <td>The version of the Hijrah variant data</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td>iso-start</td>
+ * <td>ISO start date, formatted as {@code yyyy-MM-dd}, for example: "1900-04-30"</td>
+ * <td>The ISO date of the first day of the minimum Hijrah year.</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>yyyy - a numeric 4 digit year, for example "1434"</td>
+ * <td>The value is a sequence of 12 month lengths,
+ * for example: "29 30 29 30 29 30 30 30 29 30 29 29"</td>
+ * <td>The lengths of the 12 months of the year separated by whitespace.
+ * A numeric year property must be present for every year without any gaps.
+ * The month lengths must be between 29-32 inclusive.
+ * </td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * @since 1.8
+ */
+public final class HijrahChronology extends AbstractChronology implements Serializable {
+
+    /**
+     * The Hijrah Calendar id.
+     */
+    private final transient String typeId;
+    /**
+     * The Hijrah calendarType.
+     */
+    private final transient String calendarType;
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 3127340209035924785L;
+    /**
+     * Singleton instance of the Islamic Umm Al-Qura calendar of Saudi Arabia.
+     * Other Hijrah chronology variants may be available from
+     * {@link Chronology#getAvailableChronologies}.
+     */
+    public static final HijrahChronology INSTANCE;
+    /**
+     * Flag to indicate the initialization of configuration data is complete.
+     * @see #checkCalendarInit()
+     */
+    private transient volatile boolean initComplete;
+    /**
+     * Array of epoch days indexed by Hijrah Epoch month.
+     * Computed by {@link #loadCalendarData}.
+     */
+    private transient int[] hijrahEpochMonthStartDays;
+    /**
+     * The minimum epoch day of this Hijrah calendar.
+     * Computed by {@link #loadCalendarData}.
+     */
+    private transient int minEpochDay;
+    /**
+     * The maximum epoch day for which calendar data is available.
+     * Computed by {@link #loadCalendarData}.
+     */
+    private transient int maxEpochDay;
+    /**
+     * The minimum epoch month.
+     * Computed by {@link #loadCalendarData}.
+     */
+    private transient int hijrahStartEpochMonth;
+    /**
+     * The minimum length of a month.
+     * Computed by {@link #createEpochMonths}.
+     */
+    private transient int minMonthLength;
+    /**
+     * The maximum length of a month.
+     * Computed by {@link #createEpochMonths}.
+     */
+    private transient int maxMonthLength;
+    /**
+     * The minimum length of a year in days.
+     * Computed by {@link #createEpochMonths}.
+     */
+    private transient int minYearLength;
+    /**
+     * The maximum length of a year in days.
+     * Computed by {@link #createEpochMonths}.
+     */
+    private transient int maxYearLength;
+    /**
+     * A reference to the properties stored in
+     * ${java.home}/lib/calendars.properties
+     */
+    private final transient static Properties calendarProperties;
+
+    /**
+     * Prefix of property names for Hijrah calendar variants.
+     */
+    private static final String PROP_PREFIX = "calendar.hijrah.";
+    /**
+     * Suffix of property names containing the calendar type of a variant.
+     */
+    private static final String PROP_TYPE_SUFFIX = ".type";
+
+    /**
+     * Static initialization of the predefined calendars found in the
+     * lib/calendars.properties file.
+     */
+    static {
+        try {
+            calendarProperties = sun.util.calendar.BaseCalendar.getCalendarProperties();
+        } catch (IOException ioe) {
+            throw new InternalError("Can't initialize lib/calendars.properties", ioe);
+        }
+
+        try {
+            INSTANCE = new HijrahChronology("Hijrah-umalqura");
+            // Register it by its aliases
+            AbstractChronology.registerChrono(INSTANCE, "Hijrah");
+            AbstractChronology.registerChrono(INSTANCE, "islamic");
+        } catch (DateTimeException ex) {
+            // Absence of Hijrah calendar is fatal to initializing this class.
+            PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
+            logger.severe("Unable to initialize Hijrah calendar: Hijrah-umalqura", ex);
+            throw new RuntimeException("Unable to initialize Hijrah-umalqura calendar", ex.getCause());
+        }
+        registerVariants();
+    }
+
+    /**
+     * For each Hijrah variant listed, create the HijrahChronology and register it.
+     * Exceptions during initialization are logged but otherwise ignored.
+     */
+    private static void registerVariants() {
+        for (String name : calendarProperties.stringPropertyNames()) {
+            if (name.startsWith(PROP_PREFIX)) {
+                String id = name.substring(PROP_PREFIX.length());
+                if (id.indexOf('.') >= 0) {
+                    continue;   // no name or not a simple name of a calendar
+                }
+                if (id.equals(INSTANCE.getId())) {
+                    continue;           // do not duplicate the default
+                }
+                try {
+                    // Create and register the variant
+                    HijrahChronology chrono = new HijrahChronology(id);
+                    AbstractChronology.registerChrono(chrono);
+                } catch (DateTimeException ex) {
+                    // Log error and continue
+                    PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
+                    logger.severe("Unable to initialize Hijrah calendar: " + id, ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a HijrahChronology for the named variant.
+     * The resource and calendar type are retrieved from properties
+     * in the {@code calendars.properties}.
+     * The property names are {@code "calendar.hijrah." + id}
+     * and  {@code "calendar.hijrah." + id + ".type"}
+     * @param id the id of the calendar
+     * @throws DateTimeException if the calendar type is missing from the properties file.
+     * @throws IllegalArgumentException if the id is empty
+     */
+    private HijrahChronology(String id) throws DateTimeException {
+        if (id.isEmpty()) {
+            throw new IllegalArgumentException("calendar id is empty");
+        }
+        String propName = PROP_PREFIX + id + PROP_TYPE_SUFFIX;
+        String calType = calendarProperties.getProperty(propName);
+        if (calType == null || calType.isEmpty()) {
+            throw new DateTimeException("calendarType is missing or empty for: " + propName);
+        }
+        this.typeId = id;
+        this.calendarType = calType;
+    }
+
+    /**
+     * Check and ensure that the calendar data has been initialized.
+     * The initialization check is performed at the boundary between
+     * public and package methods.  If a public calls another public method
+     * a check is not necessary in the caller.
+     * The constructors of HijrahDate call {@link #getEpochDay} or
+     * {@link #getHijrahDateInfo} so every call from HijrahDate to a
+     * HijrahChronology via package private methods has been checked.
+     *
+     * @throws DateTimeException if the calendar data configuration is
+     *     malformed or IOExceptions occur loading the data
+     */
+    private void checkCalendarInit() {
+        // Keep this short so it can be inlined for performance
+        if (initComplete == false) {
+            loadCalendarData();
+            initComplete = true;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology.
+     * <p>
+     * The ID uniquely identifies the {@code Chronology}. It can be used to
+     * lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     *
+     * @return the chronology ID, non-null
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return typeId;
+    }
+
+    /**
+     * Gets the calendar type of the Islamic calendar.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     *
+     * @return the calendar system type; non-null if the calendar has
+     *    a standard type, otherwise null
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return calendarType;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in Hijrah calendar system from the
+     * era, year-of-era, month-of-year and day-of-month fields.
+     *
+     * @param era  the Hijrah era, not null
+     * @param yearOfEra  the year-of-era
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Hijrah local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code HijrahEra}
+     */
+    @Override
+    public HijrahDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in Hijrah calendar system from the
+     * proleptic-year, month-of-year and day-of-month fields.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Hijrah local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public HijrahDate date(int prolepticYear, int month, int dayOfMonth) {
+        return HijrahDate.of(this, prolepticYear, month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in Hijrah calendar system from the
+     * era, year-of-era and day-of-year fields.
+     *
+     * @param era  the Hijrah era, not null
+     * @param yearOfEra  the year-of-era
+     * @param dayOfYear  the day-of-year
+     * @return the Hijrah local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code HijrahEra}
+     */
+    @Override
+    public HijrahDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains a local date in Hijrah calendar system from the
+     * proleptic-year and day-of-year fields.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param dayOfYear  the day-of-year
+     * @return the Hijrah local date, not null
+     * @throws DateTimeException if the value of the year is out of range,
+     *  or if the day-of-year is invalid for the year
+     */
+    @Override
+    public HijrahDate dateYearDay(int prolepticYear, int dayOfYear) {
+        HijrahDate date = HijrahDate.of(this, prolepticYear, 1, 1);
+        if (dayOfYear > date.lengthOfYear()) {
+            throw new DateTimeException("Invalid dayOfYear: " + dayOfYear);
+        }
+        return date.plusDays(dayOfYear - 1);
+    }
+
+    /**
+     * Obtains a local date in the Hijrah calendar system from the epoch-day.
+     *
+     * @param epochDay  the epoch day
+     * @return the Hijrah local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public HijrahDate dateEpochDay(long epochDay) {
+        return HijrahDate.ofEpochDay(this, epochDay);
+    }
+
+    @Override
+    public HijrahDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    @Override
+    public HijrahDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    @Override
+    public HijrahDate dateNow(Clock clock) {
+        return date(LocalDate.now(clock));
+    }
+
+    @Override
+    public HijrahDate date(TemporalAccessor temporal) {
+        if (temporal instanceof HijrahDate) {
+            return (HijrahDate) temporal;
+        }
+        return HijrahDate.ofEpochDay(this, temporal.getLong(EPOCH_DAY));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoLocalDateTime<HijrahDate> localDateTime(TemporalAccessor temporal) {
+        return (ChronoLocalDateTime<HijrahDate>) super.localDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<HijrahDate> zonedDateTime(TemporalAccessor temporal) {
+        return (ChronoZonedDateTime<HijrahDate>) super.zonedDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<HijrahDate> zonedDateTime(Instant instant, ZoneId zone) {
+        return (ChronoZonedDateTime<HijrahDate>) super.zonedDateTime(instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        checkCalendarInit();
+        if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) {
+            return false;
+        }
+        int len = getYearLength((int) prolepticYear);
+        return (len > 354);
+    }
+
+    @Override
+    public int prolepticYear(Era era, int yearOfEra) {
+        if (era instanceof HijrahEra == false) {
+            throw new ClassCastException("Era must be HijrahEra");
+        }
+        return yearOfEra;
+    }
+
+    @Override
+    public HijrahEra eraOf(int eraValue) {
+        switch (eraValue) {
+            case 1:
+                return HijrahEra.AH;
+            default:
+                throw new DateTimeException("invalid Hijrah era");
+        }
+    }
+
+    @Override
+    public List<Era> eras() {
+        return Arrays.<Era>asList(HijrahEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        checkCalendarInit();
+        if (field instanceof ChronoField) {
+            ChronoField f = field;
+            switch (f) {
+                case DAY_OF_MONTH:
+                    return ValueRange.of(1, 1, getMinimumMonthLength(), getMaximumMonthLength());
+                case DAY_OF_YEAR:
+                    return ValueRange.of(1, getMaximumDayOfYear());
+                case ALIGNED_WEEK_OF_MONTH:
+                    return ValueRange.of(1, 5);
+                case YEAR:
+                case YEAR_OF_ERA:
+                    return ValueRange.of(getMinimumYear(), getMaximumYear());
+                case ERA:
+                    return ValueRange.of(1, 1);
+                default:
+                    return field.range();
+            }
+        }
+        return field.range();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override  // override for return type
+    public HijrahDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        return (HijrahDate) super.resolveDate(fieldValues, resolverStyle);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Check the validity of a year.
+     *
+     * @param prolepticYear the year to check
+     */
+    int checkValidYear(long prolepticYear) {
+        if (prolepticYear < getMinimumYear() || prolepticYear > getMaximumYear()) {
+            throw new DateTimeException("Invalid Hijrah year: " + prolepticYear);
+        }
+        return (int) prolepticYear;
+    }
+
+    void checkValidDayOfYear(int dayOfYear) {
+        if (dayOfYear < 1 || dayOfYear > getMaximumDayOfYear()) {
+            throw new DateTimeException("Invalid Hijrah day of year: " + dayOfYear);
+        }
+    }
+
+    void checkValidMonth(int month) {
+        if (month < 1 || month > 12) {
+            throw new DateTimeException("Invalid Hijrah month: " + month);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an array containing the Hijrah year, month and day
+     * computed from the epoch day.
+     *
+     * @param epochDay  the EpochDay
+     * @return int[0] = YEAR, int[1] = MONTH, int[2] = DATE
+     */
+    int[] getHijrahDateInfo(int epochDay) {
+        checkCalendarInit();    // ensure that the chronology is initialized
+        if (epochDay < minEpochDay || epochDay >= maxEpochDay) {
+            throw new DateTimeException("Hijrah date out of range");
+        }
+
+        int epochMonth = epochDayToEpochMonth(epochDay);
+        int year = epochMonthToYear(epochMonth);
+        int month = epochMonthToMonth(epochMonth);
+        int day1 = epochMonthToEpochDay(epochMonth);
+        int date = epochDay - day1; // epochDay - dayOfEpoch(year, month);
+
+        int dateInfo[] = new int[3];
+        dateInfo[0] = year;
+        dateInfo[1] = month + 1; // change to 1-based.
+        dateInfo[2] = date + 1; // change to 1-based.
+        return dateInfo;
+    }
+
+    /**
+     * Return the epoch day computed from Hijrah year, month, and day.
+     *
+     * @param prolepticYear the year to represent, 0-origin
+     * @param monthOfYear the month-of-year to represent, 1-origin
+     * @param dayOfMonth the day-of-month to represent, 1-origin
+     * @return the epoch day
+     */
+    long getEpochDay(int prolepticYear, int monthOfYear, int dayOfMonth) {
+        checkCalendarInit();    // ensure that the chronology is initialized
+        checkValidMonth(monthOfYear);
+        int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1);
+        if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) {
+            throw new DateTimeException("Invalid Hijrah date, year: " +
+                    prolepticYear +  ", month: " + monthOfYear);
+        }
+        if (dayOfMonth < 1 || dayOfMonth > getMonthLength(prolepticYear, monthOfYear)) {
+            throw new DateTimeException("Invalid Hijrah day of month: " + dayOfMonth);
+        }
+        return epochMonthToEpochDay(epochMonth) + (dayOfMonth - 1);
+    }
+
+    /**
+     * Returns day of year for the year and month.
+     *
+     * @param prolepticYear a proleptic year
+     * @param month a month, 1-origin
+     * @return the day of year, 1-origin
+     */
+    int getDayOfYear(int prolepticYear, int month) {
+        return yearMonthToDayOfYear(prolepticYear, (month - 1));
+    }
+
+    /**
+     * Returns month length for the year and month.
+     *
+     * @param prolepticYear a proleptic year
+     * @param monthOfYear a month, 1-origin.
+     * @return the length of the month
+     */
+    int getMonthLength(int prolepticYear, int monthOfYear) {
+        int epochMonth = yearToEpochMonth(prolepticYear) + (monthOfYear - 1);
+        if (epochMonth < 0 || epochMonth >= hijrahEpochMonthStartDays.length) {
+            throw new DateTimeException("Invalid Hijrah date, year: " +
+                    prolepticYear +  ", month: " + monthOfYear);
+        }
+        return epochMonthLength(epochMonth);
+    }
+
+    /**
+     * Returns year length.
+     * Note: The 12th month must exist in the data.
+     *
+     * @param prolepticYear a proleptic year
+     * @return year length in days
+     */
+    int getYearLength(int prolepticYear) {
+        return yearMonthToDayOfYear(prolepticYear, 12);
+    }
+
+    /**
+     * Return the minimum supported Hijrah year.
+     *
+     * @return the minimum
+     */
+    int getMinimumYear() {
+        return epochMonthToYear(0);
+    }
+
+    /**
+     * Return the maximum supported Hijrah ear.
+     *
+     * @return the minimum
+     */
+    int getMaximumYear() {
+        return epochMonthToYear(hijrahEpochMonthStartDays.length - 1) - 1;
+    }
+
+    /**
+     * Returns maximum day-of-month.
+     *
+     * @return maximum day-of-month
+     */
+    int getMaximumMonthLength() {
+        return maxMonthLength;
+    }
+
+    /**
+     * Returns smallest maximum day-of-month.
+     *
+     * @return smallest maximum day-of-month
+     */
+    int getMinimumMonthLength() {
+        return minMonthLength;
+    }
+
+    /**
+     * Returns maximum day-of-year.
+     *
+     * @return maximum day-of-year
+     */
+    int getMaximumDayOfYear() {
+        return maxYearLength;
+    }
+
+    /**
+     * Returns smallest maximum day-of-year.
+     *
+     * @return smallest maximum day-of-year
+     */
+    int getSmallestMaximumDayOfYear() {
+        return minYearLength;
+    }
+
+    /**
+     * Returns the epochMonth found by locating the epochDay in the table. The
+     * epochMonth is the index in the table
+     *
+     * @param epochDay
+     * @return The index of the element of the start of the month containing the
+     * epochDay.
+     */
+    private int epochDayToEpochMonth(int epochDay) {
+        // binary search
+        int ndx = Arrays.binarySearch(hijrahEpochMonthStartDays, epochDay);
+        if (ndx < 0) {
+            ndx = -ndx - 2;
+        }
+        return ndx;
+    }
+
+    /**
+     * Returns the year computed from the epochMonth
+     *
+     * @param epochMonth the epochMonth
+     * @return the Hijrah Year
+     */
+    private int epochMonthToYear(int epochMonth) {
+        return (epochMonth + hijrahStartEpochMonth) / 12;
+    }
+
+    /**
+     * Returns the epochMonth for the Hijrah Year.
+     *
+     * @param year the HijrahYear
+     * @return the epochMonth for the beginning of the year.
+     */
+    private int yearToEpochMonth(int year) {
+        return (year * 12) - hijrahStartEpochMonth;
+    }
+
+    /**
+     * Returns the Hijrah month from the epochMonth.
+     *
+     * @param epochMonth the epochMonth
+     * @return the month of the Hijrah Year
+     */
+    private int epochMonthToMonth(int epochMonth) {
+        return (epochMonth + hijrahStartEpochMonth) % 12;
+    }
+
+    /**
+     * Returns the epochDay for the start of the epochMonth.
+     *
+     * @param epochMonth the epochMonth
+     * @return the epochDay for the start of the epochMonth.
+     */
+    private int epochMonthToEpochDay(int epochMonth) {
+        return hijrahEpochMonthStartDays[epochMonth];
+
+    }
+
+    /**
+     * Returns the day of year for the requested HijrahYear and month.
+     *
+     * @param prolepticYear the Hijrah year
+     * @param month the Hijrah month
+     * @return the day of year for the start of the month of the year
+     */
+    private int yearMonthToDayOfYear(int prolepticYear, int month) {
+        int epochMonthFirst = yearToEpochMonth(prolepticYear);
+        return epochMonthToEpochDay(epochMonthFirst + month)
+                - epochMonthToEpochDay(epochMonthFirst);
+    }
+
+    /**
+     * Returns the length of the epochMonth. It is computed from the start of
+     * the following month minus the start of the requested month.
+     *
+     * @param epochMonth the epochMonth; assumed to be within range
+     * @return the length in days of the epochMonth
+     */
+    private int epochMonthLength(int epochMonth) {
+        // The very last entry in the epochMonth table is not the start of a month
+        return hijrahEpochMonthStartDays[epochMonth + 1]
+                - hijrahEpochMonthStartDays[epochMonth];
+    }
+
+    //-----------------------------------------------------------------------
+    private static final String KEY_ID = "id";
+    private static final String KEY_TYPE = "type";
+    private static final String KEY_VERSION = "version";
+    private static final String KEY_ISO_START = "iso-start";
+
+    /**
+     * Return the configuration properties from the resource.
+     * <p>
+     * The default location of the variant configuration resource is:
+     * <pre>
+     *   "$java.home/lib/" + resource-name
+     * </pre>
+     *
+     * @param resource the name of the calendar property resource
+     * @return a Properties containing the properties read from the resource.
+     * @throws Exception if access to the property resource fails
+     */
+    private static Properties readConfigProperties(final String resource) throws Exception {
+        // Android-changed: Load system resources.
+        Properties props = new Properties();
+        try (InputStream is = ClassLoader.getSystemResourceAsStream(resource)) {
+            props.load(is);
+        }
+        return props;
+    }
+
+    /**
+     * Loads and processes the Hijrah calendar properties file for this calendarType.
+     * The starting Hijrah date and the corresponding ISO date are
+     * extracted and used to calculate the epochDate offset.
+     * The version number is identified and ignored.
+     * Everything else is the data for a year with containing the length of each
+     * of 12 months.
+     *
+     * @throws DateTimeException if initialization of the calendar data from the
+     *     resource fails
+     */
+    private void loadCalendarData() {
+        try {
+            String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId);
+            Objects.requireNonNull(resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId);
+            Properties props = readConfigProperties(resourceName);
+
+            Map<Integer, int[]> years = new HashMap<>();
+            int minYear = Integer.MAX_VALUE;
+            int maxYear = Integer.MIN_VALUE;
+            String id = null;
+            String type = null;
+            String version = null;
+            int isoStart = 0;
+            for (Map.Entry<Object, Object> entry : props.entrySet()) {
+                String key = (String) entry.getKey();
+                switch (key) {
+                    case KEY_ID:
+                        id = (String)entry.getValue();
+                        break;
+                    case KEY_TYPE:
+                        type = (String)entry.getValue();
+                        break;
+                    case KEY_VERSION:
+                        version = (String)entry.getValue();
+                        break;
+                    case KEY_ISO_START: {
+                        int[] ymd = parseYMD((String) entry.getValue());
+                        isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay();
+                        break;
+                    }
+                    default:
+                        try {
+                            // Everything else is either a year or invalid
+                            int year = Integer.valueOf(key);
+                            int[] months = parseMonths((String) entry.getValue());
+                            years.put(year, months);
+                            maxYear = Math.max(maxYear, year);
+                            minYear = Math.min(minYear, year);
+                        } catch (NumberFormatException nfe) {
+                            throw new IllegalArgumentException("bad key: " + key);
+                        }
+                }
+            }
+
+            if (!getId().equals(id)) {
+                throw new IllegalArgumentException("Configuration is for a different calendar: " + id);
+            }
+            if (!getCalendarType().equals(type)) {
+                throw new IllegalArgumentException("Configuration is for a different calendar type: " + type);
+            }
+            if (version == null || version.isEmpty()) {
+                throw new IllegalArgumentException("Configuration does not contain a version");
+            }
+            if (isoStart == 0) {
+                throw new IllegalArgumentException("Configuration does not contain a ISO start date");
+            }
+
+            // Now create and validate the array of epochDays indexed by epochMonth
+            hijrahStartEpochMonth = minYear * 12;
+            minEpochDay = isoStart;
+            hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years);
+            maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1];
+
+            // Compute the min and max year length in days.
+            for (int year = minYear; year < maxYear; year++) {
+                int length = getYearLength(year);
+                minYearLength = Math.min(minYearLength, length);
+                maxYearLength = Math.max(maxYearLength, length);
+            }
+        } catch (Exception ex) {
+            // Log error and throw a DateTimeException
+            PlatformLogger logger = PlatformLogger.getLogger("java.time.chrono");
+            logger.severe("Unable to initialize Hijrah calendar proxy: " + typeId, ex);
+            throw new DateTimeException("Unable to initialize HijrahCalendar: " + typeId, ex);
+        }
+    }
+
+    /**
+     * Converts the map of year to month lengths ranging from minYear to maxYear
+     * into a linear contiguous array of epochDays. The index is the hijrahMonth
+     * computed from year and month and offset by minYear. The value of each
+     * entry is the epochDay corresponding to the first day of the month.
+     *
+     * @param minYear The minimum year for which data is provided
+     * @param maxYear The maximum year for which data is provided
+     * @param years a Map of year to the array of 12 month lengths
+     * @return array of epochDays for each month from min to max
+     */
+    private int[] createEpochMonths(int epochDay, int minYear, int maxYear, Map<Integer, int[]> years) {
+        // Compute the size for the array of dates
+        int numMonths = (maxYear - minYear + 1) * 12 + 1;
+
+        // Initialize the running epochDay as the corresponding ISO Epoch day
+        int epochMonth = 0; // index into array of epochMonths
+        int[] epochMonths = new int[numMonths];
+        minMonthLength = Integer.MAX_VALUE;
+        maxMonthLength = Integer.MIN_VALUE;
+
+        // Only whole years are valid, any zero's in the array are illegal
+        for (int year = minYear; year <= maxYear; year++) {
+            int[] months = years.get(year);// must not be gaps
+            for (int month = 0; month < 12; month++) {
+                int length = months[month];
+                epochMonths[epochMonth++] = epochDay;
+
+                if (length < 29 || length > 32) {
+                    throw new IllegalArgumentException("Invalid month length in year: " + minYear);
+                }
+                epochDay += length;
+                minMonthLength = Math.min(minMonthLength, length);
+                maxMonthLength = Math.max(maxMonthLength, length);
+            }
+        }
+
+        // Insert the final epochDay
+        epochMonths[epochMonth++] = epochDay;
+
+        if (epochMonth != epochMonths.length) {
+            throw new IllegalStateException("Did not fill epochMonths exactly: ndx = " + epochMonth
+                    + " should be " + epochMonths.length);
+        }
+
+        return epochMonths;
+    }
+
+    /**
+     * Parses the 12 months lengths from a property value for a specific year.
+     *
+     * @param line the value of a year property
+     * @return an array of int[12] containing the 12 month lengths
+     * @throws IllegalArgumentException if the number of months is not 12
+     * @throws NumberFormatException if the 12 tokens are not numbers
+     */
+    private int[] parseMonths(String line) {
+        int[] months = new int[12];
+        String[] numbers = line.split("\\s");
+        if (numbers.length != 12) {
+            throw new IllegalArgumentException("wrong number of months on line: " + Arrays.toString(numbers) + "; count: " + numbers.length);
+        }
+        for (int i = 0; i < 12; i++) {
+            try {
+                months[i] = Integer.valueOf(numbers[i]);
+            } catch (NumberFormatException nfe) {
+                throw new IllegalArgumentException("bad key: " + numbers[i]);
+            }
+        }
+        return months;
+    }
+
+    /**
+     * Parse yyyy-MM-dd into a 3 element array [yyyy, mm, dd].
+     *
+     * @param string the input string
+     * @return the 3 element array with year, month, day
+     */
+    private int[] parseYMD(String string) {
+        // yyyy-MM-dd
+        string = string.trim();
+        try {
+            if (string.charAt(4) != '-' || string.charAt(7) != '-') {
+                throw new IllegalArgumentException("date must be yyyy-MM-dd");
+            }
+            int[] ymd = new int[3];
+            ymd[0] = Integer.valueOf(string.substring(0, 4));
+            ymd[1] = Integer.valueOf(string.substring(5, 7));
+            ymd[2] = Integer.valueOf(string.substring(8, 10));
+            return ymd;
+        } catch (NumberFormatException ex) {
+            throw new IllegalArgumentException("date must be yyyy-MM-dd", ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+}
diff --git a/java/time/chrono/HijrahDate.java b/java/time/chrono/HijrahDate.java
new file mode 100644
index 0000000..de2cb13
--- /dev/null
+++ b/java/time/chrono/HijrahDate.java
@@ -0,0 +1,692 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date in the Hijrah calendar system.
+ * <p>
+ * This date operates using one of several variants of the
+ * {@linkplain HijrahChronology Hijrah calendar}.
+ * <p>
+ * The Hijrah calendar has a different total of days in a year than
+ * Gregorian calendar, and the length of each month is based on the period
+ * of a complete revolution of the moon around the earth
+ * (as between successive new moons).
+ * Refer to the {@link HijrahChronology} for details of supported variants.
+ * <p>
+ * Each HijrahDate is created bound to a particular HijrahChronology,
+ * The same chronology is propagated to each HijrahDate computed from the date.
+ * To use a different Hijrah variant, its HijrahChronology can be used
+ * to create new HijrahDate instances.
+ * Alternatively, the {@link #withVariant} method can be used to convert
+ * to a new HijrahChronology.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class HijrahDate
+        extends ChronoLocalDateImpl<HijrahDate>
+        implements ChronoLocalDate, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -5207853542612002020L;
+    /**
+     * The Chronology of this HijrahDate.
+     */
+    private final transient HijrahChronology chrono;
+    /**
+     * The proleptic year.
+     */
+    private final transient int prolepticYear;
+    /**
+     * The month-of-year.
+     */
+    private final transient int monthOfYear;
+    /**
+     * The day-of-month.
+     */
+    private final transient int dayOfMonth;
+
+    //-------------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code HijrahDate} from the Hijrah proleptic year,
+     * month-of-year and day-of-month.
+     *
+     * @param prolepticYear  the proleptic year to represent in the Hijrah calendar
+     * @param monthOfYear  the month-of-year to represent, from 1 to 12
+     * @param dayOfMonth  the day-of-month to represent, from 1 to 30
+     * @return the Hijrah date, never null
+     * @throws DateTimeException if the value of any field is out of range
+     */
+    static HijrahDate of(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
+        return new HijrahDate(chrono, prolepticYear, monthOfYear, dayOfMonth);
+    }
+
+    /**
+     * Returns a HijrahDate for the chronology and epochDay.
+     * @param chrono The Hijrah chronology
+     * @param epochDay the epoch day
+     * @return a HijrahDate for the epoch day; non-null
+     */
+    static HijrahDate ofEpochDay(HijrahChronology chrono, long epochDay) {
+        return new HijrahDate(chrono, epochDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date using the system clock and default time-zone, not null
+     */
+    public static HijrahDate now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date using the system clock, not null
+     */
+    public static HijrahDate now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date, not null
+     * @throws DateTimeException if the current date cannot be obtained
+     */
+    public static HijrahDate now(Clock clock) {
+        return HijrahDate.ofEpochDay(HijrahChronology.INSTANCE, LocalDate.now(clock).toEpochDay());
+    }
+
+    /**
+     * Obtains a {@code HijrahDate} of the Islamic Umm Al-Qura calendar
+     * from the proleptic-year, month-of-year and day-of-month fields.
+     * <p>
+     * This returns a {@code HijrahDate} with the specified fields.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param prolepticYear  the Hijrah proleptic-year
+     * @param month  the Hijrah month-of-year, from 1 to 12
+     * @param dayOfMonth  the Hijrah day-of-month, from 1 to 30
+     * @return the date in Hijrah calendar system, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static HijrahDate of(int prolepticYear, int month, int dayOfMonth) {
+        return HijrahChronology.INSTANCE.date(prolepticYear, month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a {@code HijrahDate} of the Islamic Umm Al-Qura calendar from a temporal object.
+     * <p>
+     * This obtains a date in the Hijrah calendar system based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code HijrahDate}.
+     * <p>
+     * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
+     * field, which is standardized across calendar systems.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code HijrahDate::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date in Hijrah calendar system, not null
+     * @throws DateTimeException if unable to convert to a {@code HijrahDate}
+     */
+    public static HijrahDate from(TemporalAccessor temporal) {
+        return HijrahChronology.INSTANCE.date(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructs an {@code HijrahDate} with the proleptic-year, month-of-year and
+     * day-of-month fields.
+     *
+     * @param chrono The chronology to create the date with
+     * @param prolepticYear the proleptic year
+     * @param monthOfYear the month of year
+     * @param dayOfMonth the day of month
+     */
+    private HijrahDate(HijrahChronology chrono, int prolepticYear, int monthOfYear, int dayOfMonth) {
+        // Computing the Gregorian day checks the valid ranges
+        chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
+
+        this.chrono = chrono;
+        this.prolepticYear = prolepticYear;
+        this.monthOfYear = monthOfYear;
+        this.dayOfMonth = dayOfMonth;
+    }
+
+    /**
+     * Constructs an instance with the Epoch Day.
+     *
+     * @param epochDay  the epochDay
+     */
+    private HijrahDate(HijrahChronology chrono, long epochDay) {
+        int[] dateInfo = chrono.getHijrahDateInfo((int)epochDay);
+
+        this.chrono = chrono;
+        this.prolepticYear = dateInfo[0];
+        this.monthOfYear = dateInfo[1];
+        this.dayOfMonth = dateInfo[2];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the Hijrah calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the Hijrah chronology, not null
+     */
+    @Override
+    public HijrahChronology getChronology() {
+        return chrono;
+    }
+
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The Hijrah calendar system has one era, 'AH',
+     * defined by {@link HijrahEra}.
+     *
+     * @return the era applicable at this date, not null
+     */
+    @Override
+    public HijrahEra getEra() {
+        return HijrahEra.AH;
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * Month lengths in the Hijrah calendar system vary between 29 and 30 days.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        return chrono.getMonthLength(prolepticYear, monthOfYear);
+    }
+
+    /**
+     * Returns the length of the year represented by this date.
+     * <p>
+     * This returns the length of the year in days.
+     * A Hijrah calendar system year is typically shorter than
+     * that of the ISO calendar system.
+     *
+     * @return the length of the year in days
+     */
+    @Override
+    public int lengthOfYear() {
+        return chrono.getYearLength(prolepticYear);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+                    case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+                    case ALIGNED_WEEK_OF_MONTH: return ValueRange.of(1, 5);  // TODO
+                    // TODO does the limited range of valid years cause years to
+                    // start/end part way through? that would affect range
+                }
+                return getChronology().range(f);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case DAY_OF_WEEK: return getDayOfWeek();
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return ((getDayOfWeek() - 1) % 7) + 1;
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return ((getDayOfYear() - 1) % 7) + 1;
+                case DAY_OF_MONTH: return this.dayOfMonth;
+                case DAY_OF_YEAR: return this.getDayOfYear();
+                case EPOCH_DAY: return toEpochDay();
+                case ALIGNED_WEEK_OF_MONTH: return ((dayOfMonth - 1) / 7) + 1;
+                case ALIGNED_WEEK_OF_YEAR: return ((getDayOfYear() - 1) / 7) + 1;
+                case MONTH_OF_YEAR: return monthOfYear;
+                case PROLEPTIC_MONTH: return getProlepticMonth();
+                case YEAR_OF_ERA: return prolepticYear;
+                case YEAR: return prolepticYear;
+                case ERA: return getEraValue();
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    private long getProlepticMonth() {
+        return prolepticYear * 12L + monthOfYear - 1;
+    }
+
+    @Override
+    public HijrahDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            // not using checkValidIntValue so EPOCH_DAY and PROLEPTIC_MONTH work
+            chrono.range(f).checkValidValue(newValue, f);    // TODO: validate value
+            int nvalue = (int) newValue;
+            switch (f) {
+                case DAY_OF_WEEK: return plusDays(newValue - getDayOfWeek());
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
+                case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, monthOfYear, nvalue);
+                case DAY_OF_YEAR: return plusDays(Math.min(nvalue, lengthOfYear()) - getDayOfYear());
+                case EPOCH_DAY: return new HijrahDate(chrono, newValue);
+                case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
+                case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
+                case MONTH_OF_YEAR: return resolvePreviousValid(prolepticYear, nvalue, dayOfMonth);
+                case PROLEPTIC_MONTH: return plusMonths(newValue - getProlepticMonth());
+                case YEAR_OF_ERA: return resolvePreviousValid(prolepticYear >= 1 ? nvalue : 1 - nvalue, monthOfYear, dayOfMonth);
+                case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth);
+                case ERA: return resolvePreviousValid(1 - prolepticYear, monthOfYear, dayOfMonth);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return super.with(field, newValue);
+    }
+
+    private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) {
+        int monthDays = chrono.getMonthLength(prolepticYear, month);
+        if (day > monthDays) {
+            day = monthDays;
+        }
+        return HijrahDate.of(chrono, prolepticYear, month, day);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException if unable to make the adjustment.
+     *     For example, if the adjuster requires an ISO chronology
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public  HijrahDate with(TemporalAdjuster adjuster) {
+        return super.with(adjuster);
+    }
+
+    /**
+     * Returns a {@code HijrahDate} with the Chronology requested.
+     * <p>
+     * The year, month, and day are checked against the new requested
+     * HijrahChronology.  If the chronology has a shorter month length
+     * for the month, the day is reduced to be the last day of the month.
+     *
+     * @param chronology the new HijrahChonology, non-null
+     * @return a HijrahDate with the requested HijrahChronology, non-null
+     */
+    public HijrahDate withVariant(HijrahChronology chronology) {
+        if (chrono == chronology) {
+            return this;
+        }
+        // Like resolvePreviousValid the day is constrained to stay in the same month
+        int monthDays = chronology.getDayOfYear(prolepticYear, monthOfYear);
+        return HijrahDate.of(chronology, prolepticYear, monthOfYear,(dayOfMonth > monthDays) ? monthDays : dayOfMonth );
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public HijrahDate plus(TemporalAmount amount) {
+        return super.plus(amount);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public HijrahDate minus(TemporalAmount amount) {
+        return super.minus(amount);
+    }
+
+    @Override
+    public long toEpochDay() {
+        return chrono.getEpochDay(prolepticYear, monthOfYear, dayOfMonth);
+    }
+
+    /**
+     * Gets the day-of-year field.
+     * <p>
+     * This method returns the primitive {@code int} value for the day-of-year.
+     *
+     * @return the day-of-year
+     */
+    private int getDayOfYear() {
+        return chrono.getDayOfYear(prolepticYear, monthOfYear) + dayOfMonth;
+    }
+
+    /**
+     * Gets the day-of-week value.
+     *
+     * @return the day-of-week; computed from the epochday
+     */
+    private int getDayOfWeek() {
+        int dow0 = (int)Math.floorMod(toEpochDay() + 3, 7);
+        return dow0 + 1;
+    }
+
+    /**
+     * Gets the Era of this date.
+     *
+     * @return the Era of this date; computed from epochDay
+     */
+    private int getEraValue() {
+        return (prolepticYear > 1 ? 1 : 0);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the Hijrah calendar system rules.
+     *
+     * @return true if this date is in a leap year
+     */
+    @Override
+    public boolean isLeapYear() {
+        return chrono.isLeapYear(prolepticYear);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    HijrahDate plusYears(long years) {
+        if (years == 0) {
+            return this;
+        }
+        int newYear = Math.addExact(this.prolepticYear, (int)years);
+        return resolvePreviousValid(newYear, monthOfYear, dayOfMonth);
+    }
+
+    @Override
+    HijrahDate plusMonths(long monthsToAdd) {
+        if (monthsToAdd == 0) {
+            return this;
+        }
+        long monthCount = prolepticYear * 12L + (monthOfYear - 1);
+        long calcMonths = monthCount + monthsToAdd;  // safe overflow
+        int newYear = chrono.checkValidYear(Math.floorDiv(calcMonths, 12L));
+        int newMonth = (int)Math.floorMod(calcMonths, 12L) + 1;
+        return resolvePreviousValid(newYear, newMonth, dayOfMonth);
+    }
+
+    @Override
+    HijrahDate plusWeeks(long weeksToAdd) {
+        return super.plusWeeks(weeksToAdd);
+    }
+
+    @Override
+    HijrahDate plusDays(long days) {
+        return new HijrahDate(chrono, toEpochDay() + days);
+    }
+
+    @Override
+    public HijrahDate plus(long amountToAdd, TemporalUnit unit) {
+        return super.plus(amountToAdd, unit);
+    }
+
+    @Override
+    public HijrahDate minus(long amountToSubtract, TemporalUnit unit) {
+        return super.minus(amountToSubtract, unit);
+    }
+
+    @Override
+    HijrahDate minusYears(long yearsToSubtract) {
+        return super.minusYears(yearsToSubtract);
+    }
+
+    @Override
+    HijrahDate minusMonths(long monthsToSubtract) {
+        return super.minusMonths(monthsToSubtract);
+    }
+
+    @Override
+    HijrahDate minusWeeks(long weeksToSubtract) {
+        return super.minusWeeks(weeksToSubtract);
+    }
+
+    @Override
+    HijrahDate minusDays(long daysToSubtract) {
+        return super.minusDays(daysToSubtract);
+    }
+
+    @Override        // for javadoc and covariant return type
+    @SuppressWarnings("unchecked")
+    public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
+        return (ChronoLocalDateTime<HijrahDate>)super.atTime(localTime);
+    }
+
+    @Override
+    public ChronoPeriod until(ChronoLocalDate endDate) {
+        // TODO: untested
+        HijrahDate end = getChronology().date(endDate);
+        long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear);  // safe
+        int days = end.dayOfMonth - this.dayOfMonth;
+        if (totalMonths > 0 && days < 0) {
+            totalMonths--;
+            HijrahDate calcDate = this.plusMonths(totalMonths);
+            days = (int) (end.toEpochDay() - calcDate.toEpochDay());  // safe
+        } else if (totalMonths < 0 && days > 0) {
+            totalMonths++;
+            days -= end.lengthOfMonth();
+        }
+        long years = totalMonths / 12;  // safe
+        int months = (int) (totalMonths % 12);  // safe
+        return getChronology().period(Math.toIntExact(years), months, days);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Compares this date to another date, including the chronology.
+     * <p>
+     * Compares this {@code HijrahDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code HijrahDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date and the Chronologies are equal
+     */
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof HijrahDate) {
+            HijrahDate otherDate = (HijrahDate) obj;
+            return prolepticYear == otherDate.prolepticYear
+                && this.monthOfYear == otherDate.monthOfYear
+                && this.dayOfMonth == otherDate.dayOfMonth
+                && getChronology().equals(otherDate.getChronology());
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code based only on the Chronology and the date
+     */
+    @Override  // override for performance
+    public int hashCode() {
+        int yearValue = prolepticYear;
+        int monthValue = monthOfYear;
+        int dayValue = dayOfMonth;
+        return getChronology().getId().hashCode() ^ (yearValue & 0xFFFFF800)
+                ^ ((yearValue << 11) + (monthValue << 6) + (dayValue));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(6);                 // identifies a HijrahDate
+     *  out.writeObject(chrono);          // the HijrahChronology variant
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.HIJRAH_DATE_TYPE, this);
+    }
+
+    void writeExternal(ObjectOutput out) throws IOException {
+        // HijrahChronology is implicit in the Hijrah_DATE_TYPE
+        out.writeObject(getChronology());
+        out.writeInt(get(YEAR));
+        out.writeByte(get(MONTH_OF_YEAR));
+        out.writeByte(get(DAY_OF_MONTH));
+    }
+
+    static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        HijrahChronology chrono = (HijrahChronology) in.readObject();
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return chrono.date(year, month, dayOfMonth);
+    }
+
+}
diff --git a/java/time/chrono/HijrahEra.java b/java/time/chrono/HijrahEra.java
new file mode 100644
index 0000000..4390f69
--- /dev/null
+++ b/java/time/chrono/HijrahEra.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.ERA;
+
+import java.time.DateTimeException;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalField;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+
+/**
+ * An era in the Hijrah calendar system.
+ * <p>
+ * The Hijrah calendar system has only one era covering the
+ * proleptic years greater than zero.
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code HijrahEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum HijrahEra implements Era {
+
+    /**
+     * The singleton instance for the current era, 'Anno Hegirae',
+     * which has the numeric value 1.
+     */
+    AH;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code HijrahEra} from an {@code int} value.
+     * <p>
+     * The current era, which is the only accepted value, has the value 1
+     *
+     * @param hijrahEra  the era to represent, only 1 supported
+     * @return the HijrahEra.AH singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static HijrahEra of(int hijrahEra) {
+        if (hijrahEra == 1 ) {
+            return AH;
+        } else {
+            throw new DateTimeException("Invalid era: " + hijrahEra);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era AH has the value 1.
+     *
+     * @return the era value, 1 (AH)
+     */
+    @Override
+    public int getValue() {
+        return 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This era is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the range.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     * <p>
+     * The {@code ERA} field returns a range for the one valid Hijrah era.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    @Override  // override as super would return range from 0 to 1
+    public ValueRange range(TemporalField field) {
+        if (field == ERA) {
+            return ValueRange.of(1, 1);
+        }
+        return Era.super.range(field);
+    }
+
+}
diff --git a/java/time/chrono/IsoChronology.java b/java/time/chrono/IsoChronology.java
new file mode 100644
index 0000000..a9c79ff
--- /dev/null
+++ b/java/time/chrono/IsoChronology.java
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.io.InvalidObjectException;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.Period;
+import java.time.Year;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * The ISO calendar system.
+ * <p>
+ * This chronology defines the rules of the ISO calendar system.
+ * This calendar system is based on the ISO-8601 standard, which is the
+ * <i>de facto</i> world calendar.
+ * <p>
+ * The fields are defined as follows:
+ * <ul>
+ * <li>era - There are two eras, 'Current Era' (CE) and 'Before Current Era' (BCE).
+ * <li>year-of-era - The year-of-era is the same as the proleptic-year for the current CE era.
+ *  For the BCE era before the ISO epoch the year increases from 1 upwards as time goes backwards.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ * <li>month-of-year - There are 12 months in an ISO year, numbered from 1 to 12.
+ * <li>day-of-month - There are between 28 and 31 days in each of the ISO month, numbered from 1 to 31.
+ *  Months 4, 6, 9 and 11 have 30 days, Months 1, 3, 5, 7, 8, 10 and 12 have 31 days.
+ *  Month 2 has 28 days, or 29 in a leap year.
+ * <li>day-of-year - There are 365 days in a standard ISO year and 366 in a leap year.
+ *  The days are numbered from 1 to 365 or 1 to 366.
+ * <li>leap-year - Leap years occur every 4 years, except where the year is divisble by 100 and not divisble by 400.
+ * </ul>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class IsoChronology extends AbstractChronology implements Serializable {
+
+    /**
+     * Singleton instance of the ISO chronology.
+     */
+    public static final IsoChronology INSTANCE = new IsoChronology();
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1440403870442975015L;
+
+    /**
+     * Restricted constructor.
+     */
+    private IsoChronology() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'ISO'.
+     * <p>
+     * The ID uniquely identifies the {@code Chronology}.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     *
+     * @return the chronology ID - 'ISO'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "ISO";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'iso8601'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'iso8601'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "iso8601";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an ISO local date from the era, year-of-era, month-of-year
+     * and day-of-month fields.
+     *
+     * @param era  the ISO era, not null
+     * @param yearOfEra  the ISO year-of-era
+     * @param month  the ISO month-of-year
+     * @param dayOfMonth  the ISO day-of-month
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the type of {@code era} is not {@code IsoEra}
+     */
+    @Override  // override with covariant return type
+    public LocalDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains an ISO local date from the proleptic-year, month-of-year
+     * and day-of-month fields.
+     * <p>
+     * This is equivalent to {@link LocalDate#of(int, int, int)}.
+     *
+     * @param prolepticYear  the ISO proleptic-year
+     * @param month  the ISO month-of-year
+     * @param dayOfMonth  the ISO day-of-month
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate date(int prolepticYear, int month, int dayOfMonth) {
+        return LocalDate.of(prolepticYear, month, dayOfMonth);
+    }
+
+    /**
+     * Obtains an ISO local date from the era, year-of-era and day-of-year fields.
+     *
+     * @param era  the ISO era, not null
+     * @param yearOfEra  the ISO year-of-era
+     * @param dayOfYear  the ISO day-of-year
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains an ISO local date from the proleptic-year and day-of-year fields.
+     * <p>
+     * This is equivalent to {@link LocalDate#ofYearDay(int, int)}.
+     *
+     * @param prolepticYear  the ISO proleptic-year
+     * @param dayOfYear  the ISO day-of-year
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateYearDay(int prolepticYear, int dayOfYear) {
+        return LocalDate.ofYearDay(prolepticYear, dayOfYear);
+    }
+
+    /**
+     * Obtains an ISO local date from the epoch-day.
+     * <p>
+     * This is equivalent to {@link LocalDate#ofEpochDay(long)}.
+     *
+     * @param epochDay  the epoch day
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateEpochDay(long epochDay) {
+        return LocalDate.ofEpochDay(epochDay);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an ISO local date from another date-time object.
+     * <p>
+     * This is equivalent to {@link LocalDate#from(TemporalAccessor)}.
+     *
+     * @param temporal  the date-time object to convert, not null
+     * @return the ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate date(TemporalAccessor temporal) {
+        return LocalDate.from(temporal);
+    }
+
+    /**
+     * Obtains an ISO local date-time from another date-time object.
+     * <p>
+     * This is equivalent to {@link LocalDateTime#from(TemporalAccessor)}.
+     *
+     * @param temporal  the date-time object to convert, not null
+     * @return the ISO local date-time, not null
+     * @throws DateTimeException if unable to create the date-time
+     */
+    @Override  // override with covariant return type
+    public LocalDateTime localDateTime(TemporalAccessor temporal) {
+        return LocalDateTime.from(temporal);
+    }
+
+    /**
+     * Obtains an ISO zoned date-time from another date-time object.
+     * <p>
+     * This is equivalent to {@link ZonedDateTime#from(TemporalAccessor)}.
+     *
+     * @param temporal  the date-time object to convert, not null
+     * @return the ISO zoned date-time, not null
+     * @throws DateTimeException if unable to create the date-time
+     */
+    @Override  // override with covariant return type
+    public ZonedDateTime zonedDateTime(TemporalAccessor temporal) {
+        return ZonedDateTime.from(temporal);
+    }
+
+    /**
+     * Obtains an ISO zoned date-time in this chronology from an {@code Instant}.
+     * <p>
+     * This is equivalent to {@link ZonedDateTime#ofInstant(Instant, ZoneId)}.
+     *
+     * @param instant  the instant to create the date-time from, not null
+     * @param zone  the time-zone, not null
+     * @return the zoned date-time, not null
+     * @throws DateTimeException if the result exceeds the supported range
+     */
+    @Override
+    public ZonedDateTime zonedDateTime(Instant instant, ZoneId zone) {
+        return ZonedDateTime.ofInstant(instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current ISO local date from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current ISO local date using the system clock and default time-zone, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current ISO local date from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current ISO local date using the system clock, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current ISO local date from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@link Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current ISO local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public LocalDate dateNow(Clock clock) {
+        Objects.requireNonNull(clock, "clock");
+        return date(LocalDate.now(clock));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the year is a leap year, according to the ISO proleptic
+     * calendar system rules.
+     * <p>
+     * This method applies the current rules for leap years across the whole time-line.
+     * In general, a year is a leap year if it is divisible by four without
+     * remainder. However, years divisible by 100, are not leap years, with
+     * the exception of years divisible by 400 which are.
+     * <p>
+     * For example, 1904 is a leap year it is divisible by 4.
+     * 1900 was not a leap year as it is divisible by 100, however 2000 was a
+     * leap year as it is divisible by 400.
+     * <p>
+     * The calculation is proleptic - applying the same rules into the far future and far past.
+     * This is historically inaccurate, but is correct for the ISO-8601 standard.
+     *
+     * @param prolepticYear  the ISO proleptic year to check
+     * @return true if the year is leap, false otherwise
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
+    }
+
+    @Override
+    public int prolepticYear(Era era, int yearOfEra) {
+        if (era instanceof IsoEra == false) {
+            throw new ClassCastException("Era must be IsoEra");
+        }
+        return (era == IsoEra.CE ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public IsoEra eraOf(int eraValue) {
+        return IsoEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era> eras() {
+        return Arrays.<Era>asList(IsoEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Resolves parsed {@code ChronoField} values into a date during parsing.
+     * <p>
+     * Most {@code TemporalField} implementations are resolved using the
+     * resolve method on the field. By contrast, the {@code ChronoField} class
+     * defines fields that only have meaning relative to the chronology.
+     * As such, {@code ChronoField} date fields are resolved here in the
+     * context of a specific chronology.
+     * <p>
+     * {@code ChronoField} instances on the ISO calendar system are resolved
+     * as follows.
+     * <ul>
+     * <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate}
+     *  and all other date fields are then cross-checked against the date.
+     * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
+     *  {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
+     *  then the field is validated.
+     * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they
+     *  are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA}
+     *  range is not validated, in smart and strict mode it is. The {@code ERA} is
+     *  validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
+     *  present, and the mode is smart or lenient, then the current era (CE/AD)
+     *  is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
+     *  left untouched. If only the {@code ERA} is present, then it is left untouched.
+     * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
+     *  If all three are present, then they are combined to form a {@code LocalDate}.
+     *  In all three modes, the {@code YEAR} is validated. If the mode is smart or strict,
+     *  then the month and day are validated, with the day validated from 1 to 31.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first of January in the requested year, then adding
+     *  the difference in months, then the difference in days.
+     *  If the mode is smart, and the day-of-month is greater than the maximum for
+     *  the year-month, then the day-of-month is adjusted to the last day-of-month.
+     *  If the mode is strict, then the three fields must form a valid date.
+     * <li>{@code YEAR} and {@code DAY_OF_YEAR} -
+     *  If both are present, then they are combined to form a {@code LocalDate}.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first of January in the requested year, then adding
+     *  the difference in days.
+     *  If the mode is smart or strict, then the two fields must form a valid date.
+     * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
+     *  {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} -
+     *  If all four are present, then they are combined to form a {@code LocalDate}.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first of January in the requested year, then adding
+     *  the difference in months, then the difference in weeks, then in days.
+     *  If the mode is smart or strict, then the all four fields are validated to
+     *  their outer ranges. The date is then combined in a manner equivalent to
+     *  creating a date on the first day of the requested year and month, then adding
+     *  the amount in weeks and days to reach their values. If the mode is strict,
+     *  the date is additionally validated to check that the day and week adjustment
+     *  did not change the month.
+     * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and
+     *  {@code DAY_OF_WEEK} - If all four are present, then they are combined to
+     *  form a {@code LocalDate}. The approach is the same as described above for
+     *  years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}.
+     *  The day-of-week is adjusted as the next or same matching day-of-week once
+     *  the years, months and weeks have been handled.
+     * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} -
+     *  If all three are present, then they are combined to form a {@code LocalDate}.
+     *  In all three modes, the {@code YEAR} is validated.
+     *  If the mode is lenient, then the date is combined in a manner equivalent to
+     *  creating a date on the first of January in the requested year, then adding
+     *  the difference in weeks, then in days.
+     *  If the mode is smart or strict, then the all three fields are validated to
+     *  their outer ranges. The date is then combined in a manner equivalent to
+     *  creating a date on the first day of the requested year, then adding
+     *  the amount in weeks and days to reach their values. If the mode is strict,
+     *  the date is additionally validated to check that the day and week adjustment
+     *  did not change the year.
+     * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} -
+     *  If all three are present, then they are combined to form a {@code LocalDate}.
+     *  The approach is the same as described above for years and weeks in
+     *  {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the
+     *  next or same matching day-of-week once the years and weeks have been handled.
+     * </ul>
+     *
+     * @param fieldValues  the map of fields to values, which can be updated, not null
+     * @param resolverStyle  the requested type of resolve, not null
+     * @return the resolved date, null if insufficient information to create a date
+     * @throws DateTimeException if the date cannot be resolved, typically
+     *  because of a conflict in the input data
+     */
+    @Override  // override for performance
+    public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        return (LocalDate) super.resolveDate(fieldValues, resolverStyle);
+    }
+
+    @Override  // override for better proleptic algorithm
+    void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
+        if (pMonth != null) {
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                PROLEPTIC_MONTH.checkValidValue(pMonth);
+            }
+            addFieldValue(fieldValues, MONTH_OF_YEAR, Math.floorMod(pMonth, 12) + 1);
+            addFieldValue(fieldValues, YEAR, Math.floorDiv(pMonth, 12));
+        }
+    }
+
+    @Override  // override for enhanced behaviour
+    LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
+        if (yoeLong != null) {
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                YEAR_OF_ERA.checkValidValue(yoeLong);
+            }
+            Long era = fieldValues.remove(ERA);
+            if (era == null) {
+                Long year = fieldValues.get(YEAR);
+                if (resolverStyle == ResolverStyle.STRICT) {
+                    // do not invent era if strict, but do cross-check with year
+                    if (year != null) {
+                        addFieldValue(fieldValues, YEAR, (year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
+                    } else {
+                        // reinstate the field removed earlier, no cross-check issues
+                        fieldValues.put(YEAR_OF_ERA, yoeLong);
+                    }
+                } else {
+                    // invent era
+                    addFieldValue(fieldValues, YEAR, (year == null || year > 0 ? yoeLong: Math.subtractExact(1, yoeLong)));
+                }
+            } else if (era.longValue() == 1L) {
+                addFieldValue(fieldValues, YEAR, yoeLong);
+            } else if (era.longValue() == 0L) {
+                addFieldValue(fieldValues, YEAR, Math.subtractExact(1, yoeLong));
+            } else {
+                throw new DateTimeException("Invalid value for era: " + era);
+            }
+        } else if (fieldValues.containsKey(ERA)) {
+            ERA.checkValidValue(fieldValues.get(ERA));  // always validated
+        }
+        return null;
+    }
+
+    @Override  // override for performance
+    LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
+            long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
+            return LocalDate.of(y, 1, 1).plusMonths(months).plusDays(days);
+        }
+        int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
+        int dom = DAY_OF_MONTH.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH));
+        if (resolverStyle == ResolverStyle.SMART) {  // previous valid
+            if (moy == 4 || moy == 6 || moy == 9 || moy == 11) {
+                dom = Math.min(dom, 30);
+            } else if (moy == 2) {
+                dom = Math.min(dom, Month.FEBRUARY.length(Year.isLeap(y)));
+
+            }
+        }
+        return LocalDate.of(y, moy, dom);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        return field.range();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a period for this chronology based on years, months and days.
+     * <p>
+     * This returns a period tied to the ISO chronology using the specified
+     * years, months and days. See {@link Period} for further details.
+     *
+     * @param years  the number of years, may be negative
+     * @param months  the number of years, may be negative
+     * @param days  the number of years, may be negative
+     * @return the period in terms of this chronology, not null
+     * @return the ISO period, not null
+     */
+    @Override  // override with covariant return type
+    public Period period(int years, int months, int days) {
+        return Period.of(years, months, days);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+}
diff --git a/java/time/chrono/IsoEra.java b/java/time/chrono/IsoEra.java
new file mode 100644
index 0000000..bd29969
--- /dev/null
+++ b/java/time/chrono/IsoEra.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.time.DateTimeException;
+
+/**
+ * An era in the ISO calendar system.
+ * <p>
+ * The ISO-8601 standard does not define eras.
+ * A definition has therefore been created with two eras - 'Current era' (CE) for
+ * years on or after 0001-01-01 (ISO), and 'Before current era' (BCE) for years before that.
+ *
+ * <table summary="ISO years and eras" cellpadding="2" cellspacing="3" border="0" >
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left">year-of-era</th>
+ * <th class="colFirst" align="left">era</th>
+ * <th class="colLast" align="left">proleptic-year</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="rowColor">
+ * <td>2</td><td>CE</td><td>2</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>1</td><td>CE</td><td>1</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td>1</td><td>BCE</td><td>0</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>2</td><td>BCE</td><td>-1</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code IsoEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum IsoEra implements Era {
+
+    /**
+     * The singleton instance for the era before the current one, 'Before Current Era',
+     * which has the numeric value 0.
+     */
+    BCE,
+    /**
+     * The singleton instance for the current era, 'Current Era',
+     * which has the numeric value 1.
+     */
+    CE;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code IsoEra} from an {@code int} value.
+     * <p>
+     * {@code IsoEra} is an enum representing the ISO eras of BCE/CE.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     *
+     * @param isoEra  the BCE/CE value to represent, from 0 (BCE) to 1 (CE)
+     * @return the era singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static IsoEra of(int isoEra) {
+        switch (isoEra) {
+            case 0:
+                return BCE;
+            case 1:
+                return CE;
+            default:
+                throw new DateTimeException("Invalid era: " + isoEra);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era BCE has the value 0, while the era CE has the value 1.
+     *
+     * @return the era value, from 0 (BCE) to 1 (CE)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+}
diff --git a/java/time/chrono/JapaneseChronology.java b/java/time/chrono/JapaneseChronology.java
new file mode 100644
index 0000000..034a3bc
--- /dev/null
+++ b/java/time/chrono/JapaneseChronology.java
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoField.YEAR_OF_ERA;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.Year;
+import java.time.ZoneId;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjusters;
+import java.time.temporal.TemporalField;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.LocalGregorianCalendar;
+
+/**
+ * The Japanese Imperial calendar system.
+ * <p>
+ * This chronology defines the rules of the Japanese Imperial calendar system.
+ * This calendar system is primarily used in Japan.
+ * The Japanese Imperial calendar system is the same as the ISO calendar system
+ * apart from the era-based year numbering.
+ * <p>
+ * Japan introduced the Gregorian calendar starting with Meiji 6.
+ * Only Meiji and later eras are supported;
+ * dates before Meiji 6, January 1 are not supported.
+ * <p>
+ * The supported {@code ChronoField} instances are:
+ * <ul>
+ * <li>{@code DAY_OF_WEEK}
+ * <li>{@code DAY_OF_MONTH}
+ * <li>{@code DAY_OF_YEAR}
+ * <li>{@code EPOCH_DAY}
+ * <li>{@code MONTH_OF_YEAR}
+ * <li>{@code PROLEPTIC_MONTH}
+ * <li>{@code YEAR_OF_ERA}
+ * <li>{@code YEAR}
+ * <li>{@code ERA}
+ * </ul>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class JapaneseChronology extends AbstractChronology implements Serializable {
+
+    static final LocalGregorianCalendar JCAL =
+        (LocalGregorianCalendar) CalendarSystem.forName("japanese");
+
+    // Android-changed: don't use locale to create japanese imperial calendar, as it's not generally
+    // supported on Android. Use Calendar.getJapaneseImperialInstance() instead. See .createCalendar
+    // Locale for creating a JapaneseImpericalCalendar.
+    private static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
+
+    static Calendar createCalendar() {
+        return Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), LOCALE);
+    }
+
+    /**
+     * Singleton instance for Japanese chronology.
+     */
+    public static final JapaneseChronology INSTANCE = new JapaneseChronology();
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 459996390165777884L;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restricted constructor.
+     */
+    private JapaneseChronology() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'Japanese'.
+     * <p>
+     * The ID uniquely identifies the {@code Chronology}.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     *
+     * @return the chronology ID - 'Japanese'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "Japanese";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'japanese'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'japanese'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "japanese";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in Japanese calendar system from the
+     * era, year-of-era, month-of-year and day-of-month fields.
+     * <p>
+     * The Japanese month and day-of-month are the same as those in the
+     * ISO calendar system. They are not reset when the era changes.
+     * For example:
+     * <pre>
+     *  6th Jan Showa 64 = ISO 1989-01-06
+     *  7th Jan Showa 64 = ISO 1989-01-07
+     *  8th Jan Heisei 1 = ISO 1989-01-08
+     *  9th Jan Heisei 1 = ISO 1989-01-09
+     * </pre>
+     *
+     * @param era  the Japanese era, not null
+     * @param yearOfEra  the year-of-era
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Japanese local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
+     */
+    @Override
+    public JapaneseDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+        if (era instanceof JapaneseEra == false) {
+            throw new ClassCastException("Era must be JapaneseEra");
+        }
+        return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in Japanese calendar system from the
+     * proleptic-year, month-of-year and day-of-month fields.
+     * <p>
+     * The Japanese proleptic year, month and day-of-month are the same as those
+     * in the ISO calendar system. They are not reset when the era changes.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Japanese local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public JapaneseDate date(int prolepticYear, int month, int dayOfMonth) {
+        return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
+    }
+
+    /**
+     * Obtains a local date in Japanese calendar system from the
+     * era, year-of-era and day-of-year fields.
+     * <p>
+     * The day-of-year in this factory is expressed relative to the start of the year-of-era.
+     * This definition changes the normal meaning of day-of-year only in those years
+     * where the year-of-era is reset to one due to a change in the era.
+     * For example:
+     * <pre>
+     *  6th Jan Showa 64 = day-of-year 6
+     *  7th Jan Showa 64 = day-of-year 7
+     *  8th Jan Heisei 1 = day-of-year 1
+     *  9th Jan Heisei 1 = day-of-year 2
+     * </pre>
+     *
+     * @param era  the Japanese era, not null
+     * @param yearOfEra  the year-of-era
+     * @param dayOfYear  the day-of-year
+     * @return the Japanese local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code JapaneseEra}
+     */
+    @Override
+    public JapaneseDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+        return JapaneseDate.ofYearDay((JapaneseEra) era, yearOfEra, dayOfYear);
+    }
+
+    /**
+     * Obtains a local date in Japanese calendar system from the
+     * proleptic-year and day-of-year fields.
+     * <p>
+     * The day-of-year in this factory is expressed relative to the start of the proleptic year.
+     * The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system.
+     * They are not reset when the era changes.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param dayOfYear  the day-of-year
+     * @return the Japanese local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) {
+        return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear));
+    }
+
+    /**
+     * Obtains a local date in the Japanese calendar system from the epoch-day.
+     *
+     * @param epochDay  the epoch day
+     * @return the Japanese local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public JapaneseDate dateEpochDay(long epochDay) {
+        return new JapaneseDate(LocalDate.ofEpochDay(epochDay));
+    }
+
+    @Override
+    public JapaneseDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    @Override
+    public JapaneseDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    @Override
+    public JapaneseDate dateNow(Clock clock) {
+        return date(LocalDate.now(clock));
+    }
+
+    @Override
+    public JapaneseDate date(TemporalAccessor temporal) {
+        if (temporal instanceof JapaneseDate) {
+            return (JapaneseDate) temporal;
+        }
+        return new JapaneseDate(LocalDate.from(temporal));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoLocalDateTime<JapaneseDate> localDateTime(TemporalAccessor temporal) {
+        return (ChronoLocalDateTime<JapaneseDate>)super.localDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<JapaneseDate> zonedDateTime(TemporalAccessor temporal) {
+        return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<JapaneseDate> zonedDateTime(Instant instant, ZoneId zone) {
+        return (ChronoZonedDateTime<JapaneseDate>)super.zonedDateTime(instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * Japanese calendar leap years occur exactly in line with ISO leap years.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return IsoChronology.INSTANCE.isLeapYear(prolepticYear);
+    }
+
+    @Override
+    public int prolepticYear(Era era, int yearOfEra) {
+        if (era instanceof JapaneseEra == false) {
+            throw new ClassCastException("Era must be JapaneseEra");
+        }
+
+        JapaneseEra jera = (JapaneseEra) era;
+        int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
+        if (yearOfEra == 1) {
+            return gregorianYear;
+        }
+        if (gregorianYear >= Year.MIN_VALUE && gregorianYear <= Year.MAX_VALUE) {
+            LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null);
+            jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1);
+            if (JapaneseChronology.JCAL.validate(jdate)) {
+                return gregorianYear;
+            }
+        }
+        throw new DateTimeException("Invalid yearOfEra value");
+    }
+
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+    /**
+     * Returns the calendar system era object from the given numeric value.
+     *
+     * The numeric values supported by this method are the same as the
+     * numeric values supported by {@link JapaneseEra#of(int)}.
+     *
+     * @param eraValue  the era value
+     * @return the Japanese {@code Era} for the given numeric era value
+     * @throws DateTimeException if {@code eraValue} is invalid
+     */
+    @Override
+    public JapaneseEra eraOf(int eraValue) {
+        return JapaneseEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era> eras() {
+        return Arrays.<Era>asList(JapaneseEra.values());
+    }
+
+    JapaneseEra getCurrentEra() {
+        // Assume that the last JapaneseEra is the current one.
+        JapaneseEra[] eras = JapaneseEra.values();
+        return eras[eras.length - 1];
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case ALIGNED_DAY_OF_WEEK_IN_MONTH:
+            case ALIGNED_DAY_OF_WEEK_IN_YEAR:
+            case ALIGNED_WEEK_OF_MONTH:
+            case ALIGNED_WEEK_OF_YEAR:
+                throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+            case YEAR_OF_ERA: {
+                // Android-changed: use #createCalendar() to create calendar.
+                Calendar jcal = createCalendar();
+                int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
+                return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR),
+                        jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
+                        Year.MAX_VALUE - startYear);
+            }
+            case DAY_OF_YEAR: {
+                // Android-changed: use #createCalendar() to create calendar.
+                Calendar jcal = createCalendar();
+                int fieldIndex = Calendar.DAY_OF_YEAR;
+                return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
+                        jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
+            }
+            case YEAR:
+                return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE);
+            case ERA:
+                return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue());
+            default:
+                return field.range();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Override  // override for return type
+    public JapaneseDate resolveDate(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle);
+    }
+
+    @Override  // override for special Japanese behavior
+    ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        // validate era and year-of-era
+        Long eraLong = fieldValues.get(ERA);
+        JapaneseEra era = null;
+        if (eraLong != null) {
+            era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA));  // always validated
+        }
+        Long yoeLong = fieldValues.get(YEAR_OF_ERA);
+        int yoe = 0;
+        if (yoeLong != null) {
+            yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA);  // always validated
+        }
+        // if only year-of-era and no year then invent era unless strict
+        if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) {
+            era = JapaneseEra.values()[JapaneseEra.values().length - 1];
+        }
+        // if both present, then try to create date
+        if (yoeLong != null && era != null) {
+            if (fieldValues.containsKey(MONTH_OF_YEAR)) {
+                if (fieldValues.containsKey(DAY_OF_MONTH)) {
+                    return resolveYMD(era, yoe, fieldValues, resolverStyle);
+                }
+            }
+            if (fieldValues.containsKey(DAY_OF_YEAR)) {
+                return resolveYD(era, yoe, fieldValues, resolverStyle);
+            }
+        }
+        return null;
+    }
+
+    private int prolepticYearLenient(JapaneseEra era, int yearOfEra) {
+        return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
+    }
+
+     private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map<TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
+         fieldValues.remove(ERA);
+         fieldValues.remove(YEAR_OF_ERA);
+         if (resolverStyle == ResolverStyle.LENIENT) {
+             int y = prolepticYearLenient(era, yoe);
+             long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
+             long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
+             return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
+         }
+         int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
+         int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
+         if (resolverStyle == ResolverStyle.SMART) {  // previous valid
+             if (yoe < 1) {
+                 throw new DateTimeException("Invalid YearOfEra: " + yoe);
+             }
+             int y = prolepticYearLenient(era, yoe);
+             JapaneseDate result;
+             try {
+                 result = date(y, moy, dom);
+             } catch (DateTimeException ex) {
+                 result = date(y, moy, 1).with(TemporalAdjusters.lastDayOfMonth());
+             }
+             // handle the era being changed
+             // only allow if the new date is in the same Jan-Dec as the era change
+             // determine by ensuring either original yoe or result yoe is 1
+             if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) {
+                 throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe);
+             }
+             return result;
+         }
+         return date(era, yoe, moy, dom);
+     }
+
+    private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map <TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
+        fieldValues.remove(ERA);
+        fieldValues.remove(YEAR_OF_ERA);
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            int y = prolepticYearLenient(era, yoe);
+            long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
+            return dateYearDay(y, 1).plus(days, DAYS);
+        }
+        int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
+        return dateYearDay(era, yoe, doy);  // smart is same as strict
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+}
diff --git a/java/time/chrono/JapaneseDate.java b/java/time/chrono/JapaneseDate.java
new file mode 100644
index 0000000..143c4a4
--- /dev/null
+++ b/java/time/chrono/JapaneseDate.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
+import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Calendar;
+import java.util.Objects;
+
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.LocalGregorianCalendar;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date in the Japanese Imperial calendar system.
+ * <p>
+ * This date operates using the {@linkplain JapaneseChronology Japanese Imperial calendar}.
+ * This calendar system is primarily used in Japan.
+ * <p>
+ * The Japanese Imperial calendar system is the same as the ISO calendar system
+ * apart from the era-based year numbering. The proleptic-year is defined to be
+ * equal to the ISO proleptic-year.
+ * <p>
+ * Japan introduced the Gregorian calendar starting with Meiji 6.
+ * Only Meiji and later eras are supported;
+ * dates before Meiji 6, January 1 are not supported.
+ * <p>
+ * For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".<br>
+ * Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.<br>
+ * Calling {@code japaneseDate.get(YEAR)} will return 2012.<br>
+ * Calling {@code japaneseDate.get(ERA)} will return 2, corresponding to
+ * {@code JapaneseChronology.ERA_HEISEI}.<br>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class JapaneseDate
+        extends ChronoLocalDateImpl<JapaneseDate>
+        implements ChronoLocalDate, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -305327627230580483L;
+
+    /**
+     * The underlying ISO local date.
+     */
+    private final transient LocalDate isoDate;
+    /**
+     * The JapaneseEra of this date.
+     */
+    private transient JapaneseEra era;
+    /**
+     * The Japanese imperial calendar year of this date.
+     */
+    private transient int yearOfEra;
+
+    /**
+     * The first day supported by the JapaneseChronology is Meiji 6, January 1st.
+     */
+    static final LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date using the system clock and default time-zone, not null
+     */
+    public static JapaneseDate now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current {@code JapaneseDate} from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date using the system clock, not null
+     */
+    public static JapaneseDate now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current {@code JapaneseDate} from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date, not null
+     * @throws DateTimeException if the current date cannot be obtained
+     */
+    public static JapaneseDate now(Clock clock) {
+        return new JapaneseDate(LocalDate.now(clock));
+    }
+
+    /**
+     * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
+     * system from the era, year-of-era, month-of-year and day-of-month fields.
+     * <p>
+     * This returns a {@code JapaneseDate} with the specified fields.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * <p>
+     * The Japanese month and day-of-month are the same as those in the
+     * ISO calendar system. They are not reset when the era changes.
+     * For example:
+     * <pre>
+     *  6th Jan Showa 64 = ISO 1989-01-06
+     *  7th Jan Showa 64 = ISO 1989-01-07
+     *  8th Jan Heisei 1 = ISO 1989-01-08
+     *  9th Jan Heisei 1 = ISO 1989-01-09
+     * </pre>
+     *
+     * @param era  the Japanese era, not null
+     * @param yearOfEra  the Japanese year-of-era
+     * @param month  the Japanese month-of-year, from 1 to 12
+     * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
+     * @return the date in Japanese calendar system, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year,
+     *  or if the date is not a Japanese era
+     */
+    public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
+        Objects.requireNonNull(era, "era");
+        LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
+        jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
+        if (!JapaneseChronology.JCAL.validate(jdate)) {
+            throw new DateTimeException("year, month, and day not valid for Era");
+        }
+        LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
+        return new JapaneseDate(era, yearOfEra, date);
+    }
+
+    /**
+     * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
+     * system from the proleptic-year, month-of-year and day-of-month fields.
+     * <p>
+     * This returns a {@code JapaneseDate} with the specified fields.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     * <p>
+     * The Japanese proleptic year, month and day-of-month are the same as those
+     * in the ISO calendar system. They are not reset when the era changes.
+     *
+     * @param prolepticYear  the Japanese proleptic-year
+     * @param month  the Japanese month-of-year, from 1 to 12
+     * @param dayOfMonth  the Japanese day-of-month, from 1 to 31
+     * @return the date in Japanese calendar system, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static JapaneseDate of(int prolepticYear, int month, int dayOfMonth) {
+        return new JapaneseDate(LocalDate.of(prolepticYear, month, dayOfMonth));
+    }
+
+    /**
+     * Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
+     * system from the era, year-of-era and day-of-year fields.
+     * <p>
+     * This returns a {@code JapaneseDate} with the specified fields.
+     * The day must be valid for the year, otherwise an exception will be thrown.
+     * <p>
+     * The day-of-year in this factory is expressed relative to the start of the year-of-era.
+     * This definition changes the normal meaning of day-of-year only in those years
+     * where the year-of-era is reset to one due to a change in the era.
+     * For example:
+     * <pre>
+     *  6th Jan Showa 64 = day-of-year 6
+     *  7th Jan Showa 64 = day-of-year 7
+     *  8th Jan Heisei 1 = day-of-year 1
+     *  9th Jan Heisei 1 = day-of-year 2
+     * </pre>
+     *
+     * @param era  the Japanese era, not null
+     * @param yearOfEra  the Japanese year-of-era
+     * @param dayOfYear  the chronology day-of-year, from 1 to 366
+     * @return the date in Japanese calendar system, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-year is invalid for the year
+     */
+    static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
+        Objects.requireNonNull(era, "era");
+        CalendarDate firstDay = era.getPrivateEra().getSinceDate();
+        LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
+        jdate.setEra(era.getPrivateEra());
+        if (yearOfEra == 1) {
+            jdate.setDate(yearOfEra, firstDay.getMonth(), firstDay.getDayOfMonth() + dayOfYear - 1);
+        } else {
+            jdate.setDate(yearOfEra, 1, dayOfYear);
+        }
+        JapaneseChronology.JCAL.normalize(jdate);
+        if (era.getPrivateEra() != jdate.getEra() || yearOfEra != jdate.getYear()) {
+            throw new DateTimeException("Invalid parameters");
+        }
+        LocalDate localdate = LocalDate.of(jdate.getNormalizedYear(),
+                                      jdate.getMonth(), jdate.getDayOfMonth());
+        return new JapaneseDate(era, yearOfEra, localdate);
+    }
+
+    /**
+     * Obtains a {@code JapaneseDate} from a temporal object.
+     * <p>
+     * This obtains a date in the Japanese calendar system based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code JapaneseDate}.
+     * <p>
+     * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
+     * field, which is standardized across calendar systems.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code JapaneseDate::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date in Japanese calendar system, not null
+     * @throws DateTimeException if unable to convert to a {@code JapaneseDate}
+     */
+    public static JapaneseDate from(TemporalAccessor temporal) {
+        return JapaneseChronology.INSTANCE.date(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance from an ISO date.
+     *
+     * @param isoDate  the standard local date, validated not null
+     */
+    JapaneseDate(LocalDate isoDate) {
+        if (isoDate.isBefore(MEIJI_6_ISODATE)) {
+            throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
+        }
+        LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
+        this.era = JapaneseEra.toJapaneseEra(jdate.getEra());
+        this.yearOfEra = jdate.getYear();
+        this.isoDate = isoDate;
+    }
+
+    /**
+     * Constructs a {@code JapaneseDate}. This constructor does NOT validate the given parameters,
+     * and {@code era} and {@code year} must agree with {@code isoDate}.
+     *
+     * @param era  the era, validated not null
+     * @param year  the year-of-era, validated
+     * @param isoDate  the standard local date, validated not null
+     */
+    JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
+        if (isoDate.isBefore(MEIJI_6_ISODATE)) {
+            throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
+        }
+        this.era = era;
+        this.yearOfEra = year;
+        this.isoDate = isoDate;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the Japanese calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the Japanese chronology, not null
+     */
+    @Override
+    public JapaneseChronology getChronology() {
+        return JapaneseChronology.INSTANCE;
+    }
+
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The Japanese calendar system has multiple eras defined by {@link JapaneseEra}.
+     *
+     * @return the era applicable at this date, not null
+     */
+    @Override
+    public JapaneseEra getEra() {
+        return era;
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * Month lengths match those of the ISO calendar system.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        return isoDate.lengthOfMonth();
+    }
+
+    @Override
+    public int lengthOfYear() {
+        // Android-changed: use #createCalendar() to create calendar.
+        Calendar jcal = JapaneseChronology.createCalendar();
+        jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
+        jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
+        return  jcal.getActualMaximum(Calendar.DAY_OF_YEAR);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if this date can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and
+     * {@link #get(TemporalField) get} methods will throw an exception.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The supported fields are:
+     * <ul>
+     * <li>{@code DAY_OF_WEEK}
+     * <li>{@code DAY_OF_MONTH}
+     * <li>{@code DAY_OF_YEAR}
+     * <li>{@code EPOCH_DAY}
+     * <li>{@code MONTH_OF_YEAR}
+     * <li>{@code PROLEPTIC_MONTH}
+     * <li>{@code YEAR_OF_ERA}
+     * <li>{@code YEAR}
+     * <li>{@code ERA}
+     * </ul>
+     * All other {@code ChronoField} instances will return false.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the field is supported is determined by the field.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if the field is supported on this date, false if not
+     */
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR ||
+                field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) {
+            return false;
+        }
+        // Android-changed: Apply upstream OpenJDK 9 compilation fix.
+        // Applied OpenJDK 9 change from http://hg.openjdk.java.net/jdk9/dev/jdk/rev/2b7b09c81bf1
+        // On OpenJDK 8, either version is supported and has the same behavior.
+        // return ChronoLocalDate.super.isSupported(field);
+        return super.isSupported(field);
+    }
+
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
+                    case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
+                    case YEAR_OF_ERA: {
+                        // Android-changed: use #createCalendar() to create calendar.
+                        Calendar jcal = JapaneseChronology.createCalendar();
+                        jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
+                        jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
+                        return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR));
+                    }
+                }
+                return getChronology().range(f);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            // same as ISO:
+            // DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR
+            //
+            // calendar specific fields
+            // DAY_OF_YEAR, YEAR_OF_ERA, ERA
+            switch ((ChronoField) field) {
+                case ALIGNED_DAY_OF_WEEK_IN_MONTH:
+                case ALIGNED_DAY_OF_WEEK_IN_YEAR:
+                case ALIGNED_WEEK_OF_MONTH:
+                case ALIGNED_WEEK_OF_YEAR:
+                    throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+                case YEAR_OF_ERA:
+                    return yearOfEra;
+                case ERA:
+                    return era.getValue();
+                case DAY_OF_YEAR:
+                    // Android-changed: use #createCalendar() to create calendar.
+                    Calendar jcal = JapaneseChronology.createCalendar();
+                    jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
+                    jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
+                    return jcal.get(Calendar.DAY_OF_YEAR);
+            }
+            return isoDate.getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    /**
+     * Returns a {@code LocalGregorianCalendar.Date} converted from the given {@code isoDate}.
+     *
+     * @param isoDate  the local date, not null
+     * @return a {@code LocalGregorianCalendar.Date}, not null
+     */
+    private static LocalGregorianCalendar.Date toPrivateJapaneseDate(LocalDate isoDate) {
+        LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
+        sun.util.calendar.Era sunEra = JapaneseEra.privateEraFrom(isoDate);
+        int year = isoDate.getYear();
+        if (sunEra != null) {
+            year -= sunEra.getSinceDate().getYear() - 1;
+        }
+        jdate.setEra(sunEra).setYear(year).setMonth(isoDate.getMonthValue()).setDayOfMonth(isoDate.getDayOfMonth());
+        JapaneseChronology.JCAL.normalize(jdate);
+        return jdate;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public JapaneseDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (getLong(f) == newValue) {  // getLong() validates for supported fields
+                return this;
+            }
+            switch (f) {
+                case YEAR_OF_ERA:
+                case YEAR:
+                case ERA: {
+                    int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
+                    switch (f) {
+                        case YEAR_OF_ERA:
+                            return this.withYear(nvalue);
+                        case YEAR:
+                            return with(isoDate.withYear(nvalue));
+                        case ERA: {
+                            return this.withYear(JapaneseEra.of(nvalue), yearOfEra);
+                        }
+                    }
+                }
+            }
+            // YEAR, PROLEPTIC_MONTH and others are same as ISO
+            return with(isoDate.with(field, newValue));
+        }
+        return super.with(field, newValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public  JapaneseDate with(TemporalAdjuster adjuster) {
+        return super.with(adjuster);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public JapaneseDate plus(TemporalAmount amount) {
+        return super.plus(amount);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public JapaneseDate minus(TemporalAmount amount) {
+        return super.minus(amount);
+    }
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a copy of this date with the year altered.
+     * <p>
+     * This method changes the year of the date.
+     * If the month-day is invalid for the year, then the previous valid day
+     * will be selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param era  the era to set in the result, not null
+     * @param yearOfEra  the year-of-era to set in the returned date
+     * @return a {@code JapaneseDate} based on this date with the requested year, never null
+     * @throws DateTimeException if {@code year} is invalid
+     */
+    private JapaneseDate withYear(JapaneseEra era, int yearOfEra) {
+        int year = JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra);
+        return with(isoDate.withYear(year));
+    }
+
+    /**
+     * Returns a copy of this date with the year-of-era altered.
+     * <p>
+     * This method changes the year-of-era of the date.
+     * If the month-day is invalid for the year, then the previous valid day
+     * will be selected instead.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param year  the year to set in the returned date
+     * @return a {@code JapaneseDate} based on this date with the requested year-of-era, never null
+     * @throws DateTimeException if {@code year} is invalid
+     */
+    private JapaneseDate withYear(int year) {
+        return withYear(getEra(), year);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    JapaneseDate plusYears(long years) {
+        return with(isoDate.plusYears(years));
+    }
+
+    @Override
+    JapaneseDate plusMonths(long months) {
+        return with(isoDate.plusMonths(months));
+    }
+
+    @Override
+    JapaneseDate plusWeeks(long weeksToAdd) {
+        return with(isoDate.plusWeeks(weeksToAdd));
+    }
+
+    @Override
+    JapaneseDate plusDays(long days) {
+        return with(isoDate.plusDays(days));
+    }
+
+    @Override
+    public JapaneseDate plus(long amountToAdd, TemporalUnit unit) {
+        return super.plus(amountToAdd, unit);
+    }
+
+    @Override
+    public JapaneseDate minus(long amountToAdd, TemporalUnit unit) {
+        return super.minus(amountToAdd, unit);
+    }
+
+    @Override
+    JapaneseDate minusYears(long yearsToSubtract) {
+        return super.minusYears(yearsToSubtract);
+    }
+
+    @Override
+    JapaneseDate minusMonths(long monthsToSubtract) {
+        return super.minusMonths(monthsToSubtract);
+    }
+
+    @Override
+    JapaneseDate minusWeeks(long weeksToSubtract) {
+        return super.minusWeeks(weeksToSubtract);
+    }
+
+    @Override
+    JapaneseDate minusDays(long daysToSubtract) {
+        return super.minusDays(daysToSubtract);
+    }
+
+    private JapaneseDate with(LocalDate newDate) {
+        return (newDate.equals(isoDate) ? this : new JapaneseDate(newDate));
+    }
+
+    @Override        // for javadoc and covariant return type
+    @SuppressWarnings("unchecked")
+    public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
+        return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
+    }
+
+    @Override
+    public ChronoPeriod until(ChronoLocalDate endDate) {
+        Period period = isoDate.until(endDate);
+        return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
+    }
+
+    @Override  // override for performance
+    public long toEpochDay() {
+        return isoDate.toEpochDay();
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Compares this date to another date, including the chronology.
+     * <p>
+     * Compares this {@code JapaneseDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code JapaneseDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof JapaneseDate) {
+            JapaneseDate otherDate = (JapaneseDate) obj;
+            return this.isoDate.equals(otherDate.isoDate);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code based only on the Chronology and the date
+     */
+    @Override  // override for performance
+    public int hashCode() {
+        return getChronology().getId().hashCode() ^ isoDate.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(4);                 // identifies a JapaneseDate
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.JAPANESE_DATE_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        // JapaneseChronology is implicit in the JAPANESE_DATE_TYPE
+        out.writeInt(get(YEAR));
+        out.writeByte(get(MONTH_OF_YEAR));
+        out.writeByte(get(DAY_OF_MONTH));
+    }
+
+    static JapaneseDate readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return JapaneseChronology.INSTANCE.date(year, month, dayOfMonth);
+    }
+
+}
diff --git a/java/time/chrono/JapaneseEra.java b/java/time/chrono/JapaneseEra.java
new file mode 100644
index 0000000..81805d0
--- /dev/null
+++ b/java/time/chrono/JapaneseEra.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.chrono.JapaneseDate.MEIJI_6_ISODATE;
+import static java.time.temporal.ChronoField.ERA;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.TextStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalField;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+
+import sun.util.calendar.CalendarDate;
+
+/**
+ * An era in the Japanese Imperial calendar system.
+ * <p>
+ * The Japanese government defines the official name and start date of
+ * each era. Eras are consecutive and their date ranges do not overlap,
+ * so the end date of one era is always the day before the start date
+ * of the next era.
+ * <p>
+ * The Java SE Platform supports all eras defined by the Japanese government,
+ * beginning with the Meiji era. Each era is identified in the Platform by an
+ * integer value and a name. The {@link #of(int)} and {@link #valueOf(String)}
+ * methods may be used to obtain a singleton instance of JapaneseEra for each
+ * era. The {@link #values()} method returns the singleton instances of all
+ * supported eras.
+ * <p>
+ * For convenience, this class declares a number of public static final fields
+ * that refer to singleton instances returned by the values() method.
+ *
+ * @apiNote
+ * The fields declared in this class may evolve over time, in line with the
+ * results of the {@link #values()} method. However, there is not necessarily
+ * a 1:1 correspondence between the fields and the singleton instances.
+ *
+ * @apiNote
+ * The Japanese government may announce a new era and define its start
+ * date but not its official name. In this scenario, the singleton instance
+ * that represents the new era may return a name that is not stable until
+ * the official name is defined. Developers should exercise caution when
+ * relying on the name returned by any singleton instance that does not
+ * correspond to a public static final field.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class JapaneseEra
+        implements Era, Serializable {
+
+    // The offset value to 0-based index from the era value.
+    // i.e., getValue() + ERA_OFFSET == 0-based index
+    static final int ERA_OFFSET = 2;
+
+    static final sun.util.calendar.Era[] ERA_CONFIG;
+
+    /**
+     * The singleton instance for the 'Meiji' era (1868-01-01 - 1912-07-29)
+     * which has the value -1.
+     */
+    public static final JapaneseEra MEIJI = new JapaneseEra(-1, LocalDate.of(1868, 1, 1));
+    /**
+     * The singleton instance for the 'Taisho' era (1912-07-30 - 1926-12-24)
+     * which has the value 0.
+     */
+    public static final JapaneseEra TAISHO = new JapaneseEra(0, LocalDate.of(1912, 7, 30));
+    /**
+     * The singleton instance for the 'Showa' era (1926-12-25 - 1989-01-07)
+     * which has the value 1.
+     */
+    public static final JapaneseEra SHOWA = new JapaneseEra(1, LocalDate.of(1926, 12, 25));
+    /**
+     * The singleton instance for the 'Heisei' era (1989-01-08 - 2019-04-30)
+     * which has the value 2.
+     */
+    public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+    /**
+     * The singleton instance for the 'Reiwa' era (2019-05-01 - current)
+     * which has the value 3. The end date of this era is not specified, unless
+     * the Japanese Government defines it.
+     */
+    public static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
+
+    // The number of predefined JapaneseEra constants.
+    // There may be a supplemental era defined by the property.
+    private static final int N_ERA_CONSTANTS = REIWA.getValue() + ERA_OFFSET;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 1466499369062886794L;
+
+    // array for the singleton JapaneseEra instances
+    private static final JapaneseEra[] KNOWN_ERAS;
+
+    static {
+        ERA_CONFIG = JapaneseChronology.JCAL.getEras();
+
+        KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length];
+        KNOWN_ERAS[0] = MEIJI;
+        KNOWN_ERAS[1] = TAISHO;
+        KNOWN_ERAS[2] = SHOWA;
+        KNOWN_ERAS[3] = HEISEI;
+        KNOWN_ERAS[4] = REIWA;
+        for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
+            CalendarDate date = ERA_CONFIG[i].getSinceDate();
+            LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
+            KNOWN_ERAS[i] = new JapaneseEra(i - ERA_OFFSET + 1, isoDate);
+        }
+    };
+
+    /**
+     * The era value.
+     * @serial
+     */
+    private final transient int eraValue;
+
+    // the first day of the era
+    private final transient LocalDate since;
+
+    /**
+     * Creates an instance.
+     *
+     * @param eraValue  the era value, validated
+     * @param since  the date representing the first date of the era, validated not null
+     */
+    private JapaneseEra(int eraValue, LocalDate since) {
+        this.eraValue = eraValue;
+        this.since = since;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the Sun private Era instance corresponding to this {@code JapaneseEra}.
+     *
+     * @return the Sun private Era instance for this {@code JapaneseEra}.
+     */
+    sun.util.calendar.Era getPrivateEra() {
+        return ERA_CONFIG[ordinal(eraValue)];
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code JapaneseEra} from an {@code int} value.
+      * <ul>
+      * <li>The value {@code 1} is associated with the 'Showa' era, because
+      * it contains 1970-01-01 (ISO calendar system).</li>
+      * <li>The values {@code -1} and {@code 0} are associated with two earlier
+      * eras, Meiji and Taisho, respectively.</li>
+      * <li>A value greater than {@code 1} is associated with a later era,
+      * beginning with Heisei ({@code 2}).</li>
+      * </ul>
+     * <p>
+      * Every instance of {@code JapaneseEra} that is returned from the {@link #values()}
+      * method has an int value (available via {@link Era#getValue()} which is
+      * accepted by this method.
+     *
+     * @param japaneseEra  the era to represent
+     * @return the {@code JapaneseEra} singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static JapaneseEra of(int japaneseEra) {
+        if (japaneseEra < MEIJI.eraValue || japaneseEra + ERA_OFFSET > KNOWN_ERAS.length) {
+            throw new DateTimeException("Invalid era: " + japaneseEra);
+        }
+        return KNOWN_ERAS[ordinal(japaneseEra)];
+    }
+
+    /**
+     * Returns the {@code JapaneseEra} with the name.
+     * <p>
+     * The string must match exactly the name of the era.
+     * (Extraneous whitespace characters are not permitted.)
+     *
+     * @param japaneseEra  the japaneseEra name; non-null
+     * @return the {@code JapaneseEra} singleton, never null
+     * @throws IllegalArgumentException if there is not JapaneseEra with the specified name
+     */
+    public static JapaneseEra valueOf(String japaneseEra) {
+        Objects.requireNonNull(japaneseEra, "japaneseEra");
+        for (JapaneseEra era : KNOWN_ERAS) {
+            if (era.getName().equals(japaneseEra)) {
+                return era;
+            }
+        }
+        throw new IllegalArgumentException("japaneseEra is invalid");
+    }
+
+    /**
+     * Returns an array of JapaneseEras.
+     * <p>
+     * This method may be used to iterate over the JapaneseEras as follows:
+     * <pre>
+     * for (JapaneseEra c : JapaneseEra.values())
+     *     System.out.println(c);
+     * </pre>
+     *
+     * @return an array of JapaneseEras
+     */
+    public static JapaneseEra[] values() {
+        return Arrays.copyOf(KNOWN_ERAS, KNOWN_ERAS.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param style {@inheritDoc}
+     * @param locale {@inheritDoc}
+     */
+    @Override
+    public String getDisplayName(TextStyle style, Locale locale) {
+        // If this JapaneseEra is a supplemental one, obtain the name from
+        // the era definition.
+        if (getValue() > N_ERA_CONSTANTS - ERA_OFFSET) {
+            Objects.requireNonNull(locale, "locale");
+            return style.asNormal() == TextStyle.NARROW ? getAbbreviation() : getName();
+        }
+
+        return new DateTimeFormatterBuilder()
+            .appendText(ERA, style)
+            .toFormatter(locale)
+            .withChronology(JapaneseChronology.INSTANCE)
+            .format(this == MEIJI ? MEIJI_6_ISODATE : since);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code JapaneseEra} from a date.
+     *
+     * @param date  the date, not null
+     * @return the Era singleton, never null
+     */
+    static JapaneseEra from(LocalDate date) {
+        if (date.isBefore(MEIJI_6_ISODATE)) {
+            throw new DateTimeException("JapaneseDate before Meiji 6 are not supported");
+        }
+        for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
+            JapaneseEra era = KNOWN_ERAS[i];
+            if (date.compareTo(era.since) >= 0) {
+                return era;
+            }
+        }
+        return null;
+    }
+
+    static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) {
+        for (int i = ERA_CONFIG.length - 1; i >= 0; i--) {
+            if (ERA_CONFIG[i].equals(privateEra)) {
+                return KNOWN_ERAS[i];
+            }
+        }
+        return null;
+    }
+
+    static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) {
+        for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
+            JapaneseEra era = KNOWN_ERAS[i];
+            if (isoDate.compareTo(era.since) >= 0) {
+                return ERA_CONFIG[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the index into the arrays from the Era value.
+     * the eraValue is a valid Era number, -1..2.
+     *
+     * @param eraValue  the era value to convert to the index
+     * @return the index of the current Era
+     */
+    private static int ordinal(int eraValue) {
+        return eraValue + ERA_OFFSET - 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1.
+     * Later eras are numbered from 2 ({@link #HEISEI}).
+     * Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI})).
+     *
+     * @return the era value
+     */
+    @Override
+    public int getValue() {
+        return eraValue;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * The range object expresses the minimum and maximum valid values for a field.
+     * This era is used to enhance the accuracy of the returned range.
+     * If it is not possible to return the range, because the field is not supported
+     * or for some other reason, an exception is thrown.
+     * <p>
+     * If the field is a {@link ChronoField} then the query is implemented here.
+     * The {@code ERA} field returns the range.
+     * All other {@code ChronoField} instances will throw an {@code UnsupportedTemporalTypeException}.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * Whether the range can be obtained is determined by the field.
+     * <p>
+     * The range of valid Japanese eras can change over time due to the nature
+     * of the Japanese calendar system.
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     */
+    @Override  // override as super would return range from 0 to 1
+    public ValueRange range(TemporalField field) {
+        if (field == ERA) {
+            return JapaneseChronology.INSTANCE.range(ERA);
+        }
+        return Era.super.range(field);
+    }
+
+    //-----------------------------------------------------------------------
+    String getAbbreviation() {
+        return ERA_CONFIG[ordinal(getValue())].getAbbreviation();
+    }
+
+    String getName() {
+        return ERA_CONFIG[ordinal(getValue())].getName();
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(5);        // identifies a JapaneseEra
+     *  out.writeInt(getValue());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.JAPANESE_ERA_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeByte(this.getValue());
+    }
+
+    static JapaneseEra readExternal(DataInput in) throws IOException {
+        byte eraValue = in.readByte();
+        return JapaneseEra.of(eraValue);
+    }
+
+}
diff --git a/java/time/chrono/MinguoChronology.java b/java/time/chrono/MinguoChronology.java
new file mode 100644
index 0000000..841884c
--- /dev/null
+++ b/java/time/chrono/MinguoChronology.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.io.InvalidObjectException;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * The Minguo calendar system.
+ * <p>
+ * This chronology defines the rules of the Minguo calendar system.
+ * This calendar system is primarily used in the Republic of China, often known as Taiwan.
+ * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
+ * <p>
+ * The fields are defined as follows:
+ * <ul>
+ * <li>era - There are two eras, the current 'Republic' (ERA_ROC) and the previous era (ERA_BEFORE_ROC).
+ * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
+ *  For the previous era the year increases from one as time goes backwards.
+ *  The value for the current era is equal to the ISO proleptic-year minus 1911.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ *  The value is equal to the ISO proleptic-year minus 1911.
+ * <li>month-of-year - The Minguo month-of-year exactly matches ISO.
+ * <li>day-of-month - The Minguo day-of-month exactly matches ISO.
+ * <li>day-of-year - The Minguo day-of-year exactly matches ISO.
+ * <li>leap-year - The Minguo leap-year pattern exactly matches ISO, such that the two calendars
+ *  are never out of step.
+ * </ul>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class MinguoChronology extends AbstractChronology implements Serializable {
+
+    /**
+     * Singleton instance for the Minguo chronology.
+     */
+    public static final MinguoChronology INSTANCE = new MinguoChronology();
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 1039765215346859963L;
+    /**
+     * The difference in years between ISO and Minguo.
+     */
+    static final int YEARS_DIFFERENCE = 1911;
+
+    /**
+     * Restricted constructor.
+     */
+    private MinguoChronology() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'Minguo'.
+     * <p>
+     * The ID uniquely identifies the {@code Chronology}.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     *
+     * @return the chronology ID - 'Minguo'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "Minguo";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'roc'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'roc'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "roc";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in Minguo calendar system from the
+     * era, year-of-era, month-of-year and day-of-month fields.
+     *
+     * @param era  the Minguo era, not null
+     * @param yearOfEra  the year-of-era
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Minguo local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code MinguoEra}
+     */
+    @Override
+    public MinguoDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in Minguo calendar system from the
+     * proleptic-year, month-of-year and day-of-month fields.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Minguo local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public MinguoDate date(int prolepticYear, int month, int dayOfMonth) {
+        return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
+    }
+
+    /**
+     * Obtains a local date in Minguo calendar system from the
+     * era, year-of-era and day-of-year fields.
+     *
+     * @param era  the Minguo era, not null
+     * @param yearOfEra  the year-of-era
+     * @param dayOfYear  the day-of-year
+     * @return the Minguo local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code MinguoEra}
+     */
+    @Override
+    public MinguoDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains a local date in Minguo calendar system from the
+     * proleptic-year and day-of-year fields.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param dayOfYear  the day-of-year
+     * @return the Minguo local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public MinguoDate dateYearDay(int prolepticYear, int dayOfYear) {
+        return new MinguoDate(LocalDate.ofYearDay(prolepticYear + YEARS_DIFFERENCE, dayOfYear));
+    }
+
+    /**
+     * Obtains a local date in the Minguo calendar system from the epoch-day.
+     *
+     * @param epochDay  the epoch day
+     * @return the Minguo local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public MinguoDate dateEpochDay(long epochDay) {
+        return new MinguoDate(LocalDate.ofEpochDay(epochDay));
+    }
+
+    @Override
+    public MinguoDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    @Override
+    public MinguoDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    @Override
+    public MinguoDate dateNow(Clock clock) {
+        return date(LocalDate.now(clock));
+    }
+
+    @Override
+    public MinguoDate date(TemporalAccessor temporal) {
+        if (temporal instanceof MinguoDate) {
+            return (MinguoDate) temporal;
+        }
+        return new MinguoDate(LocalDate.from(temporal));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoLocalDateTime<MinguoDate> localDateTime(TemporalAccessor temporal) {
+        return (ChronoLocalDateTime<MinguoDate>)super.localDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<MinguoDate> zonedDateTime(TemporalAccessor temporal) {
+        return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<MinguoDate> zonedDateTime(Instant instant, ZoneId zone) {
+        return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * Minguo leap years occur exactly in line with ISO leap years.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return IsoChronology.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE);
+    }
+
+    @Override
+    public int prolepticYear(Era era, int yearOfEra) {
+        if (era instanceof MinguoEra == false) {
+            throw new ClassCastException("Era must be MinguoEra");
+        }
+        return (era == MinguoEra.ROC ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public MinguoEra eraOf(int eraValue) {
+        return MinguoEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era> eras() {
+        return Arrays.<Era>asList(MinguoEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case PROLEPTIC_MONTH: {
+                ValueRange range = PROLEPTIC_MONTH.range();
+                return ValueRange.of(range.getMinimum() - YEARS_DIFFERENCE * 12L, range.getMaximum() - YEARS_DIFFERENCE * 12L);
+            }
+            case YEAR_OF_ERA: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(1, range.getMaximum() - YEARS_DIFFERENCE, -range.getMinimum() + 1 + YEARS_DIFFERENCE);
+            }
+            case YEAR: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(range.getMinimum() - YEARS_DIFFERENCE, range.getMaximum() - YEARS_DIFFERENCE);
+            }
+        }
+        return field.range();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override  // override for return type
+    public MinguoDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        return (MinguoDate) super.resolveDate(fieldValues, resolverStyle);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+}
diff --git a/java/time/chrono/MinguoDate.java b/java/time/chrono/MinguoDate.java
new file mode 100644
index 0000000..71e0a12
--- /dev/null
+++ b/java/time/chrono/MinguoDate.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.chrono.MinguoChronology.YEARS_DIFFERENCE;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date in the Minguo calendar system.
+ * <p>
+ * This date operates using the {@linkplain MinguoChronology Minguo calendar}.
+ * This calendar system is primarily used in the Republic of China, often known as Taiwan.
+ * Dates are aligned such that {@code 0001-01-01 (Minguo)} is {@code 1912-01-01 (ISO)}.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class MinguoDate
+        extends ChronoLocalDateImpl<MinguoDate>
+        implements ChronoLocalDate, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 1300372329181994526L;
+
+    /**
+     * The underlying date.
+     */
+    private final transient LocalDate isoDate;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current {@code MinguoDate} from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date using the system clock and default time-zone, not null
+     */
+    public static MinguoDate now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current {@code MinguoDate} from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date using the system clock, not null
+     */
+    public static MinguoDate now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current {@code MinguoDate} from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date, not null
+     * @throws DateTimeException if the current date cannot be obtained
+     */
+    public static MinguoDate now(Clock clock) {
+        return new MinguoDate(LocalDate.now(clock));
+    }
+
+    /**
+     * Obtains a {@code MinguoDate} representing a date in the Minguo calendar
+     * system from the proleptic-year, month-of-year and day-of-month fields.
+     * <p>
+     * This returns a {@code MinguoDate} with the specified fields.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param prolepticYear  the Minguo proleptic-year
+     * @param month  the Minguo month-of-year, from 1 to 12
+     * @param dayOfMonth  the Minguo day-of-month, from 1 to 31
+     * @return the date in Minguo calendar system, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static MinguoDate of(int prolepticYear, int month, int dayOfMonth) {
+        return new MinguoDate(LocalDate.of(prolepticYear + YEARS_DIFFERENCE, month, dayOfMonth));
+    }
+
+    /**
+     * Obtains a {@code MinguoDate} from a temporal object.
+     * <p>
+     * This obtains a date in the Minguo calendar system based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code MinguoDate}.
+     * <p>
+     * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
+     * field, which is standardized across calendar systems.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code MinguoDate::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date in Minguo calendar system, not null
+     * @throws DateTimeException if unable to convert to a {@code MinguoDate}
+     */
+    public static MinguoDate from(TemporalAccessor temporal) {
+        return MinguoChronology.INSTANCE.date(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance from an ISO date.
+     *
+     * @param isoDate  the standard local date, validated not null
+     */
+    MinguoDate(LocalDate isoDate) {
+        Objects.requireNonNull(isoDate, "isoDate");
+        this.isoDate = isoDate;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the Minguo calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the Minguo chronology, not null
+     */
+    @Override
+    public MinguoChronology getChronology() {
+        return MinguoChronology.INSTANCE;
+    }
+
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The Minguo calendar system has two eras, 'ROC' and 'BEFORE_ROC',
+     * defined by {@link MinguoEra}.
+     *
+     * @return the era applicable at this date, not null
+     */
+    @Override
+    public MinguoEra getEra() {
+        return (getProlepticYear() >= 1 ? MinguoEra.ROC : MinguoEra.BEFORE_ROC);
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * Month lengths match those of the ISO calendar system.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        return isoDate.lengthOfMonth();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH:
+                    case DAY_OF_YEAR:
+                    case ALIGNED_WEEK_OF_MONTH:
+                        return isoDate.range(field);
+                    case YEAR_OF_ERA: {
+                        ValueRange range = YEAR.range();
+                        long max = (getProlepticYear() <= 0 ? -range.getMinimum() + 1 + YEARS_DIFFERENCE : range.getMaximum() - YEARS_DIFFERENCE);
+                        return ValueRange.of(1, max);
+                    }
+                }
+                return getChronology().range(f);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case PROLEPTIC_MONTH:
+                    return getProlepticMonth();
+                case YEAR_OF_ERA: {
+                    int prolepticYear = getProlepticYear();
+                    return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
+                }
+                case YEAR:
+                    return getProlepticYear();
+                case ERA:
+                    return (getProlepticYear() >= 1 ? 1 : 0);
+            }
+            return isoDate.getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    private long getProlepticMonth() {
+        return getProlepticYear() * 12L + isoDate.getMonthValue() - 1;
+    }
+
+    private int getProlepticYear() {
+        return isoDate.getYear() - YEARS_DIFFERENCE;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public MinguoDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (getLong(f) == newValue) {
+                return this;
+            }
+            switch (f) {
+                case PROLEPTIC_MONTH:
+                    getChronology().range(f).checkValidValue(newValue, f);
+                    return plusMonths(newValue - getProlepticMonth());
+                case YEAR_OF_ERA:
+                case YEAR:
+                case ERA: {
+                    int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
+                    switch (f) {
+                        case YEAR_OF_ERA:
+                            return with(isoDate.withYear(getProlepticYear() >= 1 ? nvalue + YEARS_DIFFERENCE : (1 - nvalue)  + YEARS_DIFFERENCE));
+                        case YEAR:
+                            return with(isoDate.withYear(nvalue + YEARS_DIFFERENCE));
+                        case ERA:
+                            return with(isoDate.withYear((1 - getProlepticYear()) + YEARS_DIFFERENCE));
+                    }
+                }
+            }
+            return with(isoDate.with(field, newValue));
+        }
+        return super.with(field, newValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public  MinguoDate with(TemporalAdjuster adjuster) {
+        return super.with(adjuster);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public MinguoDate plus(TemporalAmount amount) {
+        return super.plus(amount);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public MinguoDate minus(TemporalAmount amount) {
+        return super.minus(amount);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    MinguoDate plusYears(long years) {
+        return with(isoDate.plusYears(years));
+    }
+
+    @Override
+    MinguoDate plusMonths(long months) {
+        return with(isoDate.plusMonths(months));
+    }
+
+    @Override
+    MinguoDate plusWeeks(long weeksToAdd) {
+        return super.plusWeeks(weeksToAdd);
+    }
+
+    @Override
+    MinguoDate plusDays(long days) {
+        return with(isoDate.plusDays(days));
+    }
+
+    @Override
+    public MinguoDate plus(long amountToAdd, TemporalUnit unit) {
+        return super.plus(amountToAdd, unit);
+    }
+
+    @Override
+    public MinguoDate minus(long amountToAdd, TemporalUnit unit) {
+        return super.minus(amountToAdd, unit);
+    }
+
+    @Override
+    MinguoDate minusYears(long yearsToSubtract) {
+        return super.minusYears(yearsToSubtract);
+    }
+
+    @Override
+    MinguoDate minusMonths(long monthsToSubtract) {
+        return super.minusMonths(monthsToSubtract);
+    }
+
+    @Override
+    MinguoDate minusWeeks(long weeksToSubtract) {
+        return super.minusWeeks(weeksToSubtract);
+    }
+
+    @Override
+    MinguoDate minusDays(long daysToSubtract) {
+        return super.minusDays(daysToSubtract);
+    }
+
+    private MinguoDate with(LocalDate newDate) {
+        return (newDate.equals(isoDate) ? this : new MinguoDate(newDate));
+    }
+
+    @Override        // for javadoc and covariant return type
+    @SuppressWarnings("unchecked")
+    public final ChronoLocalDateTime<MinguoDate> atTime(LocalTime localTime) {
+        return (ChronoLocalDateTime<MinguoDate>)super.atTime(localTime);
+    }
+
+    @Override
+    public ChronoPeriod until(ChronoLocalDate endDate) {
+        Period period = isoDate.until(endDate);
+        return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
+    }
+
+    @Override  // override for performance
+    public long toEpochDay() {
+        return isoDate.toEpochDay();
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Compares this date to another date, including the chronology.
+     * <p>
+     * Compares this {@code MinguoDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code MinguoDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof MinguoDate) {
+            MinguoDate otherDate = (MinguoDate) obj;
+            return this.isoDate.equals(otherDate.isoDate);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code based only on the Chronology and the date
+     */
+    @Override  // override for performance
+    public int hashCode() {
+        return getChronology().getId().hashCode() ^ isoDate.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(8);                 // identifies a MinguoDate
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.MINGUO_DATE_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        // MinguoChronology is implicit in the MINGUO_DATE_TYPE
+        out.writeInt(get(YEAR));
+        out.writeByte(get(MONTH_OF_YEAR));
+        out.writeByte(get(DAY_OF_MONTH));
+    }
+
+    static MinguoDate readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return MinguoChronology.INSTANCE.date(year, month, dayOfMonth);
+    }
+
+}
diff --git a/java/time/chrono/MinguoEra.java b/java/time/chrono/MinguoEra.java
new file mode 100644
index 0000000..fd96de1
--- /dev/null
+++ b/java/time/chrono/MinguoEra.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.time.DateTimeException;
+
+/**
+ * An era in the Minguo calendar system.
+ * <p>
+ * The Minguo calendar system has two eras.
+ * The current era, for years from 1 onwards, is known as the 'Republic of China' era.
+ * All previous years, zero or earlier in the proleptic count or one and greater
+ * in the year-of-era count, are part of the 'Before Republic of China' era.
+ *
+ * <table summary="Minguo years and eras" cellpadding="2" cellspacing="3" border="0" >
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left">year-of-era</th>
+ * <th class="colFirst" align="left">era</th>
+ * <th class="colFirst" align="left">proleptic-year</th>
+ * <th class="colLast" align="left">ISO proleptic-year</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="rowColor">
+ * <td>2</td><td>ROC</td><td>2</td><td>1913</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>1</td><td>ROC</td><td>1</td><td>1912</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td>1</td><td>BEFORE_ROC</td><td>0</td><td>1911</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>2</td><td>BEFORE_ROC</td><td>-1</td><td>1910</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code MinguoEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum MinguoEra implements Era {
+
+    /**
+     * The singleton instance for the era before the current one, 'Before Republic of China Era',
+     * which has the numeric value 0.
+     */
+    BEFORE_ROC,
+    /**
+     * The singleton instance for the current era, 'Republic of China Era',
+     * which has the numeric value 1.
+     */
+    ROC;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code MinguoEra} from an {@code int} value.
+     * <p>
+     * {@code MinguoEra} is an enum representing the Minguo eras of BEFORE_ROC/ROC.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     *
+     * @param minguoEra  the BEFORE_ROC/ROC value to represent, from 0 (BEFORE_ROC) to 1 (ROC)
+     * @return the era singleton, not null
+     * @throws DateTimeException if the value is invalid
+     */
+    public static MinguoEra of(int minguoEra) {
+        switch (minguoEra) {
+            case 0:
+                return BEFORE_ROC;
+            case 1:
+                return ROC;
+            default:
+                throw new DateTimeException("Invalid era: " + minguoEra);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era BEFORE_ROC has the value 0, while the era ROC has the value 1.
+     *
+     * @return the era value, from 0 (BEFORE_ROC) to 1 (ROC)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+}
diff --git a/java/time/chrono/Ser.java b/java/time/chrono/Ser.java
new file mode 100644
index 0000000..317a769
--- /dev/null
+++ b/java/time/chrono/Ser.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ * @implNote
+ * This class wraps the object being serialized, and takes a byte representing the type of the class to
+ * be serialized.  This byte can also be used for versioning the serialization format.  In this case another
+ * byte flag would be used in order to specify an alternative version of the type format.
+ * For example {@code CHRONO_TYPE_VERSION_2 = 21}
+ * <p>
+ * In order to serialize the object it writes its byte and then calls back to the appropriate class where
+ * the serialization is performed.  In order to deserialize the object it read in the type byte, switching
+ * in order to select which class to call back into.
+ * <p>
+ * The serialization format is determined on a per class basis.  In the case of field based classes each
+ * of the fields is written out with an appropriate size format in descending order of the field's size.  For
+ * example in the case of {@link LocalDate} year is written before month.  Composite classes, such as
+ * {@link LocalDateTime} are serialized as one object.  Enum classes are serialized using the index of their
+ * element.
+ * <p>
+ * This class is mutable and should be created once per serialization.
+ *
+ * @serial include
+ * @since 1.8
+ */
+final class Ser implements Externalizable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -6103370247208168577L;
+
+    static final byte CHRONO_TYPE = 1;
+    static final byte CHRONO_LOCAL_DATE_TIME_TYPE = 2;
+    static final byte CHRONO_ZONE_DATE_TIME_TYPE = 3;
+    static final byte JAPANESE_DATE_TYPE = 4;
+    static final byte JAPANESE_ERA_TYPE = 5;
+    static final byte HIJRAH_DATE_TYPE = 6;
+    static final byte MINGUO_DATE_TYPE = 7;
+    static final byte THAIBUDDHIST_DATE_TYPE = 8;
+    static final byte CHRONO_PERIOD_TYPE = 9;
+
+    /** The type being serialized. */
+    private byte type;
+    /** The object being serialized. */
+    private Object object;
+
+    /**
+     * Constructor for deserialization.
+     */
+    public Ser() {
+    }
+
+    /**
+     * Creates an instance for serialization.
+     *
+     * @param type  the type
+     * @param object  the object
+     */
+    Ser(byte type, Object object) {
+        this.type = type;
+        this.object = object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to write the object.
+     * @serialData
+     * Each serializable class is mapped to a type that is the first byte
+     * in the stream.  Refer to each class {@code writeReplace}
+     * serialized form for the value of the type and sequence of values for the type.
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate.writeReplace</a>
+     * </ul>
+     *
+     * @param out  the data stream to write to, not null
+     */
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        writeInternal(type, object, out);
+    }
+
+    private static void writeInternal(byte type, Object object, ObjectOutput out) throws IOException {
+        out.writeByte(type);
+        switch (type) {
+            case CHRONO_TYPE:
+                ((AbstractChronology) object).writeExternal(out);
+                break;
+            case CHRONO_LOCAL_DATE_TIME_TYPE:
+                ((ChronoLocalDateTimeImpl<?>) object).writeExternal(out);
+                break;
+            case CHRONO_ZONE_DATE_TIME_TYPE:
+                ((ChronoZonedDateTimeImpl<?>) object).writeExternal(out);
+                break;
+            case JAPANESE_DATE_TYPE:
+                ((JapaneseDate) object).writeExternal(out);
+                break;
+            case JAPANESE_ERA_TYPE:
+                ((JapaneseEra) object).writeExternal(out);
+                break;
+            case HIJRAH_DATE_TYPE:
+                ((HijrahDate) object).writeExternal(out);
+                break;
+            case MINGUO_DATE_TYPE:
+                ((MinguoDate) object).writeExternal(out);
+                break;
+            case THAIBUDDHIST_DATE_TYPE:
+                ((ThaiBuddhistDate) object).writeExternal(out);
+                break;
+            case CHRONO_PERIOD_TYPE:
+                ((ChronoPeriodImpl) object).writeExternal(out);
+                break;
+            default:
+                throw new InvalidClassException("Unknown serialized type");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to read the object.
+     * @serialData
+     * The streamed type and parameters defined by the type's {@code writeReplace}
+     * method are read and passed to the corresponding static factory for the type
+     * to create a new instance.  That instance is returned as the de-serialized
+     * {@code Ser} object.
+     *
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime</a> - date.atTime(time)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime</a> - dateTime.atZone(offset).withZoneSameLocal(zone)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate</a> - JapaneseChronology.INSTANCE.date(year, month, dayOfMonth)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra</a> - JapaneseEra.of(eraValue)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate</a> - HijrahChronology chrono.date(year, month, dayOfMonth)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate</a> - MinguoChronology.INSTANCE.date(year, month, dayOfMonth)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate</a> - ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth)
+     * </ul>
+     *
+     * @param in  the data stream to read from, not null
+     */
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        type = in.readByte();
+        object = readInternal(type, in);
+    }
+
+    static Object read(ObjectInput in) throws IOException, ClassNotFoundException {
+        byte type = in.readByte();
+        return readInternal(type, in);
+    }
+
+    private static Object readInternal(byte type, ObjectInput in) throws IOException, ClassNotFoundException {
+        switch (type) {
+            case CHRONO_TYPE: return AbstractChronology.readExternal(in);
+            case CHRONO_LOCAL_DATE_TIME_TYPE: return ChronoLocalDateTimeImpl.readExternal(in);
+            case CHRONO_ZONE_DATE_TIME_TYPE: return ChronoZonedDateTimeImpl.readExternal(in);
+            case JAPANESE_DATE_TYPE:  return JapaneseDate.readExternal(in);
+            case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
+            case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
+            case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
+            case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
+            case CHRONO_PERIOD_TYPE: return ChronoPeriodImpl.readExternal(in);
+            default: throw new StreamCorruptedException("Unknown serialized type");
+        }
+    }
+
+    /**
+     * Returns the object that will replace this one.
+     *
+     * @return the read object, should never be null
+     */
+    private Object readResolve() {
+         return object;
+    }
+
+}
diff --git a/java/time/chrono/ThaiBuddhistChronology.java b/java/time/chrono/ThaiBuddhistChronology.java
new file mode 100644
index 0000000..5b96c85
--- /dev/null
+++ b/java/time/chrono/ThaiBuddhistChronology.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.io.InvalidObjectException;
+import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.ValueRange;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * The Thai Buddhist calendar system.
+ * <p>
+ * This chronology defines the rules of the Thai Buddhist calendar system.
+ * This calendar system is primarily used in Thailand.
+ * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
+ * <p>
+ * The fields are defined as follows:
+ * <ul>
+ * <li>era - There are two eras, the current 'Buddhist' (ERA_BE) and the previous era (ERA_BEFORE_BE).
+ * <li>year-of-era - The year-of-era for the current era increases uniformly from the epoch at year one.
+ *  For the previous era the year increases from one as time goes backwards.
+ *  The value for the current era is equal to the ISO proleptic-year plus 543.
+ * <li>proleptic-year - The proleptic year is the same as the year-of-era for the
+ *  current era. For the previous era, years have zero, then negative values.
+ *  The value is equal to the ISO proleptic-year plus 543.
+ * <li>month-of-year - The ThaiBuddhist month-of-year exactly matches ISO.
+ * <li>day-of-month - The ThaiBuddhist day-of-month exactly matches ISO.
+ * <li>day-of-year - The ThaiBuddhist day-of-year exactly matches ISO.
+ * <li>leap-year - The ThaiBuddhist leap-year pattern exactly matches ISO, such that the two calendars
+ *  are never out of step.
+ * </ul>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ThaiBuddhistChronology extends AbstractChronology implements Serializable {
+
+    /**
+     * Singleton instance of the Buddhist chronology.
+     */
+    public static final ThaiBuddhistChronology INSTANCE = new ThaiBuddhistChronology();
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 2775954514031616474L;
+    /**
+     * Containing the offset to add to the ISO year.
+     */
+    static final int YEARS_DIFFERENCE = 543;
+    /**
+     * Narrow names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_NARROW_NAMES = new HashMap<>();
+    /**
+     * Short names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_SHORT_NAMES = new HashMap<>();
+    /**
+     * Full names for eras.
+     */
+    private static final HashMap<String, String[]> ERA_FULL_NAMES = new HashMap<>();
+    /**
+     * Fallback language for the era names.
+     */
+    private static final String FALLBACK_LANGUAGE = "en";
+    /**
+     * Language that has the era names.
+     */
+    private static final String TARGET_LANGUAGE = "th";
+    /**
+     * Name data.
+     */
+    static {
+        ERA_NARROW_NAMES.put(FALLBACK_LANGUAGE, new String[]{"BB", "BE"});
+        ERA_NARROW_NAMES.put(TARGET_LANGUAGE, new String[]{"BB", "BE"});
+        ERA_SHORT_NAMES.put(FALLBACK_LANGUAGE, new String[]{"B.B.", "B.E."});
+        ERA_SHORT_NAMES.put(TARGET_LANGUAGE,
+                new String[]{"\u0e1e.\u0e28.",
+                "\u0e1b\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e04\u0e23\u0e34\u0e2a\u0e15\u0e4c\u0e01\u0e32\u0e25\u0e17\u0e35\u0e48"});
+        ERA_FULL_NAMES.put(FALLBACK_LANGUAGE, new String[]{"Before Buddhist", "Budhhist Era"});
+        ERA_FULL_NAMES.put(TARGET_LANGUAGE,
+                new String[]{"\u0e1e\u0e38\u0e17\u0e18\u0e28\u0e31\u0e01\u0e23\u0e32\u0e0a",
+                "\u0e1b\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e04\u0e23\u0e34\u0e2a\u0e15\u0e4c\u0e01\u0e32\u0e25\u0e17\u0e35\u0e48"});
+    }
+
+    /**
+     * Restricted constructor.
+     */
+    private ThaiBuddhistChronology() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the ID of the chronology - 'ThaiBuddhist'.
+     * <p>
+     * The ID uniquely identifies the {@code Chronology}.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     *
+     * @return the chronology ID - 'ThaiBuddhist'
+     * @see #getCalendarType()
+     */
+    @Override
+    public String getId() {
+        return "ThaiBuddhist";
+    }
+
+    /**
+     * Gets the calendar type of the underlying calendar system - 'buddhist'.
+     * <p>
+     * The calendar type is an identifier defined by the
+     * <em>Unicode Locale Data Markup Language (LDML)</em> specification.
+     * It can be used to lookup the {@code Chronology} using {@link Chronology#of(String)}.
+     * It can also be used as part of a locale, accessible via
+     * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'.
+     *
+     * @return the calendar system type - 'buddhist'
+     * @see #getId()
+     */
+    @Override
+    public String getCalendarType() {
+        return "buddhist";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a local date in Thai Buddhist calendar system from the
+     * era, year-of-era, month-of-year and day-of-month fields.
+     *
+     * @param era  the Thai Buddhist era, not null
+     * @param yearOfEra  the year-of-era
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Thai Buddhist local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code ThaiBuddhistEra}
+     */
+    @Override
+    public ThaiBuddhistDate date(Era era, int yearOfEra, int month, int dayOfMonth) {
+        return date(prolepticYear(era, yearOfEra), month, dayOfMonth);
+    }
+
+    /**
+     * Obtains a local date in Thai Buddhist calendar system from the
+     * proleptic-year, month-of-year and day-of-month fields.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param month  the month-of-year
+     * @param dayOfMonth  the day-of-month
+     * @return the Thai Buddhist local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public ThaiBuddhistDate date(int prolepticYear, int month, int dayOfMonth) {
+        return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
+    }
+
+    /**
+     * Obtains a local date in Thai Buddhist calendar system from the
+     * era, year-of-era and day-of-year fields.
+     *
+     * @param era  the Thai Buddhist era, not null
+     * @param yearOfEra  the year-of-era
+     * @param dayOfYear  the day-of-year
+     * @return the Thai Buddhist local date, not null
+     * @throws DateTimeException if unable to create the date
+     * @throws ClassCastException if the {@code era} is not a {@code ThaiBuddhistEra}
+     */
+    @Override
+    public ThaiBuddhistDate dateYearDay(Era era, int yearOfEra, int dayOfYear) {
+        return dateYearDay(prolepticYear(era, yearOfEra), dayOfYear);
+    }
+
+    /**
+     * Obtains a local date in Thai Buddhist calendar system from the
+     * proleptic-year and day-of-year fields.
+     *
+     * @param prolepticYear  the proleptic-year
+     * @param dayOfYear  the day-of-year
+     * @return the Thai Buddhist local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override
+    public ThaiBuddhistDate dateYearDay(int prolepticYear, int dayOfYear) {
+        return new ThaiBuddhistDate(LocalDate.ofYearDay(prolepticYear - YEARS_DIFFERENCE, dayOfYear));
+    }
+
+    /**
+     * Obtains a local date in the Thai Buddhist calendar system from the epoch-day.
+     *
+     * @param epochDay  the epoch day
+     * @return the Thai Buddhist local date, not null
+     * @throws DateTimeException if unable to create the date
+     */
+    @Override  // override with covariant return type
+    public ThaiBuddhistDate dateEpochDay(long epochDay) {
+        return new ThaiBuddhistDate(LocalDate.ofEpochDay(epochDay));
+    }
+
+    @Override
+    public ThaiBuddhistDate dateNow() {
+        return dateNow(Clock.systemDefaultZone());
+    }
+
+    @Override
+    public ThaiBuddhistDate dateNow(ZoneId zone) {
+        return dateNow(Clock.system(zone));
+    }
+
+    @Override
+    public ThaiBuddhistDate dateNow(Clock clock) {
+        return date(LocalDate.now(clock));
+    }
+
+    @Override
+    public ThaiBuddhistDate date(TemporalAccessor temporal) {
+        if (temporal instanceof ThaiBuddhistDate) {
+            return (ThaiBuddhistDate) temporal;
+        }
+        return new ThaiBuddhistDate(LocalDate.from(temporal));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoLocalDateTime<ThaiBuddhistDate> localDateTime(TemporalAccessor temporal) {
+        return (ChronoLocalDateTime<ThaiBuddhistDate>)super.localDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(TemporalAccessor temporal) {
+        return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(temporal);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(Instant instant, ZoneId zone) {
+        return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(instant, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if the specified year is a leap year.
+     * <p>
+     * Thai Buddhist leap years occur exactly in line with ISO leap years.
+     * This method does not validate the year passed in, and only has a
+     * well-defined result for years in the supported range.
+     *
+     * @param prolepticYear  the proleptic-year to check, not validated for range
+     * @return true if the year is a leap year
+     */
+    @Override
+    public boolean isLeapYear(long prolepticYear) {
+        return IsoChronology.INSTANCE.isLeapYear(prolepticYear - YEARS_DIFFERENCE);
+    }
+
+    @Override
+    public int prolepticYear(Era era, int yearOfEra) {
+        if (era instanceof ThaiBuddhistEra == false) {
+            throw new ClassCastException("Era must be BuddhistEra");
+        }
+        return (era == ThaiBuddhistEra.BE ? yearOfEra : 1 - yearOfEra);
+    }
+
+    @Override
+    public ThaiBuddhistEra eraOf(int eraValue) {
+        return ThaiBuddhistEra.of(eraValue);
+    }
+
+    @Override
+    public List<Era> eras() {
+        return Arrays.<Era>asList(ThaiBuddhistEra.values());
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(ChronoField field) {
+        switch (field) {
+            case PROLEPTIC_MONTH: {
+                ValueRange range = PROLEPTIC_MONTH.range();
+                return ValueRange.of(range.getMinimum() + YEARS_DIFFERENCE * 12L, range.getMaximum() + YEARS_DIFFERENCE * 12L);
+            }
+            case YEAR_OF_ERA: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(1, -(range.getMinimum() + YEARS_DIFFERENCE) + 1, range.getMaximum() + YEARS_DIFFERENCE);
+            }
+            case YEAR: {
+                ValueRange range = YEAR.range();
+                return ValueRange.of(range.getMinimum() + YEARS_DIFFERENCE, range.getMaximum() + YEARS_DIFFERENCE);
+            }
+        }
+        return field.range();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override  // override for return type
+    public ThaiBuddhistDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
+        return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+}
diff --git a/java/time/chrono/ThaiBuddhistDate.java b/java/time/chrono/ThaiBuddhistDate.java
new file mode 100644
index 0000000..cc58cea
--- /dev/null
+++ b/java/time/chrono/ThaiBuddhistDate.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import static java.time.chrono.ThaiBuddhistChronology.YEARS_DIFFERENCE;
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Clock;
+import java.time.DateTimeException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalAdjuster;
+import java.time.temporal.TemporalAmount;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.TemporalUnit;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.time.temporal.ValueRange;
+import java.util.Objects;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A date in the Thai Buddhist calendar system.
+ * <p>
+ * This date operates using the {@linkplain ThaiBuddhistChronology Thai Buddhist calendar}.
+ * This calendar system is primarily used in Thailand.
+ * Dates are aligned such that {@code 2484-01-01 (Buddhist)} is {@code 1941-01-01 (ISO)}.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ThaiBuddhistDate
+        extends ChronoLocalDateImpl<ThaiBuddhistDate>
+        implements ChronoLocalDate, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -8722293800195731463L;
+
+    /**
+     * The underlying date.
+     */
+    private final transient LocalDate isoDate;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains the current {@code ThaiBuddhistDate} from the system clock in the default time-zone.
+     * <p>
+     * This will query the {@link Clock#systemDefaultZone() system clock} in the default
+     * time-zone to obtain the current date.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @return the current date using the system clock and default time-zone, not null
+     */
+    public static ThaiBuddhistDate now() {
+        return now(Clock.systemDefaultZone());
+    }
+
+    /**
+     * Obtains the current {@code ThaiBuddhistDate} from the system clock in the specified time-zone.
+     * <p>
+     * This will query the {@link Clock#system(ZoneId) system clock} to obtain the current date.
+     * Specifying the time-zone avoids dependence on the default time-zone.
+     * <p>
+     * Using this method will prevent the ability to use an alternate clock for testing
+     * because the clock is hard-coded.
+     *
+     * @param zone  the zone ID to use, not null
+     * @return the current date using the system clock, not null
+     */
+    public static ThaiBuddhistDate now(ZoneId zone) {
+        return now(Clock.system(zone));
+    }
+
+    /**
+     * Obtains the current {@code ThaiBuddhistDate} from the specified clock.
+     * <p>
+     * This will query the specified clock to obtain the current date - today.
+     * Using this method allows the use of an alternate clock for testing.
+     * The alternate clock may be introduced using {@linkplain Clock dependency injection}.
+     *
+     * @param clock  the clock to use, not null
+     * @return the current date, not null
+     * @throws DateTimeException if the current date cannot be obtained
+     */
+    public static ThaiBuddhistDate now(Clock clock) {
+        return new ThaiBuddhistDate(LocalDate.now(clock));
+    }
+
+    /**
+     * Obtains a {@code ThaiBuddhistDate} representing a date in the Thai Buddhist calendar
+     * system from the proleptic-year, month-of-year and day-of-month fields.
+     * <p>
+     * This returns a {@code ThaiBuddhistDate} with the specified fields.
+     * The day must be valid for the year and month, otherwise an exception will be thrown.
+     *
+     * @param prolepticYear  the Thai Buddhist proleptic-year
+     * @param month  the Thai Buddhist month-of-year, from 1 to 12
+     * @param dayOfMonth  the Thai Buddhist day-of-month, from 1 to 31
+     * @return the date in Thai Buddhist calendar system, not null
+     * @throws DateTimeException if the value of any field is out of range,
+     *  or if the day-of-month is invalid for the month-year
+     */
+    public static ThaiBuddhistDate of(int prolepticYear, int month, int dayOfMonth) {
+        return new ThaiBuddhistDate(LocalDate.of(prolepticYear - YEARS_DIFFERENCE, month, dayOfMonth));
+    }
+
+    /**
+     * Obtains a {@code ThaiBuddhistDate} from a temporal object.
+     * <p>
+     * This obtains a date in the Thai Buddhist calendar system based on the specified temporal.
+     * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
+     * which this factory converts to an instance of {@code ThaiBuddhistDate}.
+     * <p>
+     * The conversion typically uses the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
+     * field, which is standardized across calendar systems.
+     * <p>
+     * This method matches the signature of the functional interface {@link TemporalQuery}
+     * allowing it to be used as a query via method reference, {@code ThaiBuddhistDate::from}.
+     *
+     * @param temporal  the temporal object to convert, not null
+     * @return the date in Thai Buddhist calendar system, not null
+     * @throws DateTimeException if unable to convert to a {@code ThaiBuddhistDate}
+     */
+    public static ThaiBuddhistDate from(TemporalAccessor temporal) {
+        return ThaiBuddhistChronology.INSTANCE.date(temporal);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance from an ISO date.
+     *
+     * @param isoDate  the standard local date, validated not null
+     */
+    ThaiBuddhistDate(LocalDate isoDate) {
+        Objects.requireNonNull(isoDate, "isoDate");
+        this.isoDate = isoDate;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the chronology of this date, which is the Thai Buddhist calendar system.
+     * <p>
+     * The {@code Chronology} represents the calendar system in use.
+     * The era and other fields in {@link ChronoField} are defined by the chronology.
+     *
+     * @return the Thai Buddhist chronology, not null
+     */
+    @Override
+    public ThaiBuddhistChronology getChronology() {
+        return ThaiBuddhistChronology.INSTANCE;
+    }
+
+    /**
+     * Gets the era applicable at this date.
+     * <p>
+     * The Thai Buddhist calendar system has two eras, 'BE' and 'BEFORE_BE',
+     * defined by {@link ThaiBuddhistEra}.
+     *
+     * @return the era applicable at this date, not null
+     */
+    @Override
+    public ThaiBuddhistEra getEra() {
+        return (getProlepticYear() >= 1 ? ThaiBuddhistEra.BE : ThaiBuddhistEra.BEFORE_BE);
+    }
+
+    /**
+     * Returns the length of the month represented by this date.
+     * <p>
+     * This returns the length of the month in days.
+     * Month lengths match those of the ISO calendar system.
+     *
+     * @return the length of the month in days
+     */
+    @Override
+    public int lengthOfMonth() {
+        return isoDate.lengthOfMonth();
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                ChronoField f = (ChronoField) field;
+                switch (f) {
+                    case DAY_OF_MONTH:
+                    case DAY_OF_YEAR:
+                    case ALIGNED_WEEK_OF_MONTH:
+                        return isoDate.range(field);
+                    case YEAR_OF_ERA: {
+                        ValueRange range = YEAR.range();
+                        long max = (getProlepticYear() <= 0 ? -(range.getMinimum() + YEARS_DIFFERENCE) + 1 : range.getMaximum() + YEARS_DIFFERENCE);
+                        return ValueRange.of(1, max);
+                    }
+                }
+                return getChronology().range(f);
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.rangeRefinedBy(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        if (field instanceof ChronoField) {
+            switch ((ChronoField) field) {
+                case PROLEPTIC_MONTH:
+                    return getProlepticMonth();
+                case YEAR_OF_ERA: {
+                    int prolepticYear = getProlepticYear();
+                    return (prolepticYear >= 1 ? prolepticYear : 1 - prolepticYear);
+                }
+                case YEAR:
+                    return getProlepticYear();
+                case ERA:
+                    return (getProlepticYear() >= 1 ? 1 : 0);
+            }
+            return isoDate.getLong(field);
+        }
+        return field.getFrom(this);
+    }
+
+    private long getProlepticMonth() {
+        return getProlepticYear() * 12L + isoDate.getMonthValue() - 1;
+    }
+
+    private int getProlepticYear() {
+        return isoDate.getYear() + YEARS_DIFFERENCE;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public ThaiBuddhistDate with(TemporalField field, long newValue) {
+        if (field instanceof ChronoField) {
+            ChronoField f = (ChronoField) field;
+            if (getLong(f) == newValue) {
+                return this;
+            }
+            switch (f) {
+                case PROLEPTIC_MONTH:
+                    getChronology().range(f).checkValidValue(newValue, f);
+                    return plusMonths(newValue - getProlepticMonth());
+                case YEAR_OF_ERA:
+                case YEAR:
+                case ERA: {
+                    int nvalue = getChronology().range(f).checkValidIntValue(newValue, f);
+                    switch (f) {
+                        case YEAR_OF_ERA:
+                            return with(isoDate.withYear((getProlepticYear() >= 1 ? nvalue : 1 - nvalue)  - YEARS_DIFFERENCE));
+                        case YEAR:
+                            return with(isoDate.withYear(nvalue - YEARS_DIFFERENCE));
+                        case ERA:
+                            return with(isoDate.withYear((1 - getProlepticYear()) - YEARS_DIFFERENCE));
+                    }
+                }
+            }
+            return with(isoDate.with(field, newValue));
+        }
+        return super.with(field, newValue);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public  ThaiBuddhistDate with(TemporalAdjuster adjuster) {
+        return super.with(adjuster);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public ThaiBuddhistDate plus(TemporalAmount amount) {
+        return super.plus(amount);
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws DateTimeException {@inheritDoc}
+     * @throws ArithmeticException {@inheritDoc}
+     */
+    @Override
+    public ThaiBuddhistDate minus(TemporalAmount amount) {
+        return super.minus(amount);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    ThaiBuddhistDate plusYears(long years) {
+        return with(isoDate.plusYears(years));
+    }
+
+    @Override
+    ThaiBuddhistDate plusMonths(long months) {
+        return with(isoDate.plusMonths(months));
+    }
+
+    @Override
+    ThaiBuddhistDate plusWeeks(long weeksToAdd) {
+        return super.plusWeeks(weeksToAdd);
+    }
+
+    @Override
+    ThaiBuddhistDate plusDays(long days) {
+        return with(isoDate.plusDays(days));
+    }
+
+    @Override
+    public ThaiBuddhistDate plus(long amountToAdd, TemporalUnit unit) {
+        return super.plus(amountToAdd, unit);
+    }
+
+    @Override
+    public ThaiBuddhistDate minus(long amountToAdd, TemporalUnit unit) {
+        return super.minus(amountToAdd, unit);
+    }
+
+    @Override
+    ThaiBuddhistDate minusYears(long yearsToSubtract) {
+        return super.minusYears(yearsToSubtract);
+    }
+
+    @Override
+    ThaiBuddhistDate minusMonths(long monthsToSubtract) {
+        return super.minusMonths(monthsToSubtract);
+    }
+
+    @Override
+    ThaiBuddhistDate minusWeeks(long weeksToSubtract) {
+        return super.minusWeeks(weeksToSubtract);
+    }
+
+    @Override
+    ThaiBuddhistDate minusDays(long daysToSubtract) {
+        return super.minusDays(daysToSubtract);
+    }
+
+    private ThaiBuddhistDate with(LocalDate newDate) {
+        return (newDate.equals(isoDate) ? this : new ThaiBuddhistDate(newDate));
+    }
+
+    @Override        // for javadoc and covariant return type
+    @SuppressWarnings("unchecked")
+    public final ChronoLocalDateTime<ThaiBuddhistDate> atTime(LocalTime localTime) {
+        return (ChronoLocalDateTime<ThaiBuddhistDate>) super.atTime(localTime);
+    }
+
+    @Override
+    public ChronoPeriod until(ChronoLocalDate endDate) {
+        Period period = isoDate.until(endDate);
+        return getChronology().period(period.getYears(), period.getMonths(), period.getDays());
+    }
+
+    @Override  // override for performance
+    public long toEpochDay() {
+        return isoDate.toEpochDay();
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Compares this date to another date, including the chronology.
+     * <p>
+     * Compares this {@code ThaiBuddhistDate} with another ensuring that the date is the same.
+     * <p>
+     * Only objects of type {@code ThaiBuddhistDate} are compared, other types return false.
+     * To compare the dates of two {@code TemporalAccessor} instances, including dates
+     * in two different chronologies, use {@link ChronoField#EPOCH_DAY} as a comparator.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override  // override for performance
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ThaiBuddhistDate) {
+            ThaiBuddhistDate otherDate = (ThaiBuddhistDate) obj;
+            return this.isoDate.equals(otherDate.isoDate);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this date.
+     *
+     * @return a suitable hash code based only on the Chronology and the date
+     */
+    @Override  // override for performance
+    public int hashCode() {
+        return getChronology().getId().hashCode() ^ isoDate.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(10);                // identifies a ThaiBuddhistDate
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this);
+    }
+
+    void writeExternal(DataOutput out) throws IOException {
+        // ThaiBuddhistChronology is implicit in the THAIBUDDHIST_DATE_TYPE
+        out.writeInt(this.get(YEAR));
+        out.writeByte(this.get(MONTH_OF_YEAR));
+        out.writeByte(this.get(DAY_OF_MONTH));
+    }
+
+    static ThaiBuddhistDate readExternal(DataInput in) throws IOException {
+        int year = in.readInt();
+        int month = in.readByte();
+        int dayOfMonth = in.readByte();
+        return ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth);
+    }
+
+}
diff --git a/java/time/chrono/ThaiBuddhistEra.java b/java/time/chrono/ThaiBuddhistEra.java
new file mode 100644
index 0000000..e3e6e86
--- /dev/null
+++ b/java/time/chrono/ThaiBuddhistEra.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.chrono;
+
+import java.time.DateTimeException;
+
+/**
+ * An era in the Thai Buddhist calendar system.
+ * <p>
+ * The Thai Buddhist calendar system has two eras.
+ * The current era, for years from 1 onwards, is known as the 'Buddhist' era.
+ * All previous years, zero or earlier in the proleptic count or one and greater
+ * in the year-of-era count, are part of the 'Before Buddhist' era.
+ *
+ * <table summary="Buddhist years and eras" cellpadding="2" cellspacing="3" border="0" >
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left">year-of-era</th>
+ * <th class="colFirst" align="left">era</th>
+ * <th class="colFirst" align="left">proleptic-year</th>
+ * <th class="colLast" align="left">ISO proleptic-year</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="rowColor">
+ * <td>2</td><td>BE</td><td>2</td><td>-542</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>1</td><td>BE</td><td>1</td><td>-543</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td>1</td><td>BEFORE_BE</td><td>0</td><td>-544</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td>2</td><td>BEFORE_BE</td><td>-1</td><td>-545</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ * <p>
+ * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code ThaiBuddhistEra}.
+ * Use {@code getValue()} instead.</b>
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum ThaiBuddhistEra implements Era {
+
+    /**
+     * The singleton instance for the era before the current one, 'Before Buddhist Era',
+     * which has the numeric value 0.
+     */
+    BEFORE_BE,
+    /**
+     * The singleton instance for the current era, 'Buddhist Era',
+     * which has the numeric value 1.
+     */
+    BE;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code ThaiBuddhistEra} from an {@code int} value.
+     * <p>
+     * {@code ThaiBuddhistEra} is an enum representing the Thai Buddhist eras of BEFORE_BE/BE.
+     * This factory allows the enum to be obtained from the {@code int} value.
+     *
+     * @param thaiBuddhistEra  the era to represent, from 0 to 1
+     * @return the BuddhistEra singleton, never null
+     * @throws DateTimeException if the era is invalid
+     */
+    public static ThaiBuddhistEra of(int thaiBuddhistEra) {
+        switch (thaiBuddhistEra) {
+            case 0:
+                return BEFORE_BE;
+            case 1:
+                return BE;
+            default:
+                throw new DateTimeException("Invalid era: " + thaiBuddhistEra);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the numeric era {@code int} value.
+     * <p>
+     * The era BEFORE_BE has the value 0, while the era BE has the value 1.
+     *
+     * @return the era value, from 0 (BEFORE_BE) to 1 (BE)
+     */
+    @Override
+    public int getValue() {
+        return ordinal();
+    }
+
+}
diff --git a/java/time/chrono/package-info.java b/java/time/chrono/package-info.java
new file mode 100644
index 0000000..9273a77
--- /dev/null
+++ b/java/time/chrono/package-info.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * Generic API for calendar systems other than the default ISO.
+ * </p>
+ * <p>
+ * The main API is based around the calendar system defined in ISO-8601.
+ * However, there are other calendar systems, and this package provides basic support for them.
+ * The alternate calendars are provided in the {@link java.time.chrono} package.
+ * </p>
+ * <p>
+ * A calendar system is defined by the {@link java.time.chrono.Chronology} interface,
+ * while a date in a calendar system is defined by the {@link java.time.chrono.ChronoLocalDate} interface.
+ * </p>
+ * <p>
+ * It is intended that applications use the main API whenever possible, including code to read and write
+ * from a persistent data store, such as a database, and to send dates and times across a network.
+ * The "chrono" classes are then used at the user interface level to deal with localized input/output.
+ * See {@link java.time.chrono.ChronoLocalDate ChronoLocalDate}
+ * for a full discussion of the issues.
+ * </p>
+ * <p>
+ * Using non-ISO calendar systems in an application introduces significant extra complexity.
+ * Ensure that the warnings and recommendations in {@code ChronoLocalDate} have been read before
+ * working with the "chrono" interfaces.
+ * </p>
+ * <p>
+ * The supported calendar systems includes:
+ * </p>
+ * <ul>
+ * <li>{@link java.time.chrono.HijrahChronology Hijrah calendar}</li>
+ * <li>{@link java.time.chrono.JapaneseChronology Japanese calendar}</li>
+ * <li>{@link java.time.chrono.MinguoChronology Minguo calendar}</li>
+ * <li>{@link java.time.chrono.ThaiBuddhistChronology Thai Buddhist calendar}</li>
+ * </ul>
+ *
+ * <h3>Example</h3>
+ * <p>
+ * This example lists todays date for all of the available calendars.
+ * </p>
+ * <pre>
+ *   // Enumerate the list of available calendars and print todays date for each.
+ *       Set&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
+ *       for (Chronology chrono : chronos) {
+ *           ChronoLocalDate date = chrono.dateNow();
+ *           System.out.printf("   %20s: %s%n", chrono.getId(), date.toString());
+ *       }
+ * </pre>
+ *
+ * <p>
+ * This example creates and uses a date in a named non-ISO calendar system.
+ * </p>
+ * <pre>
+ *   // Print the Thai Buddhist date
+ *       ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow();
+ *       int day = now1.get(ChronoField.DAY_OF_MONTH);
+ *       int dow = now1.get(ChronoField.DAY_OF_WEEK);
+ *       int month = now1.get(ChronoField.MONTH_OF_YEAR);
+ *       int year = now1.get(ChronoField.YEAR);
+ *       System.out.printf("  Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
+ *                 dow, day, month, year);
+ *   // Print today's date and the last day of the year for the Thai Buddhist Calendar.
+ *       ChronoLocalDate first = now1
+ *                 .with(ChronoField.DAY_OF_MONTH, 1)
+ *                 .with(ChronoField.MONTH_OF_YEAR, 1);
+ *       ChronoLocalDate last = first
+ *                 .plus(1, ChronoUnit.YEARS)
+ *                 .minus(1, ChronoUnit.DAYS);
+ *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
+ *                 first, last);
+ *  </pre>
+ *
+ * <p>
+ * This example creates and uses a date in a specific ThaiBuddhist calendar system.
+ * </p>
+ * <pre>
+ *   // Print the Thai Buddhist date
+ *       ThaiBuddhistDate now1 = ThaiBuddhistDate.now();
+ *       int day = now1.get(ChronoField.DAY_OF_MONTH);
+ *       int dow = now1.get(ChronoField.DAY_OF_WEEK);
+ *       int month = now1.get(ChronoField.MONTH_OF_YEAR);
+ *       int year = now1.get(ChronoField.YEAR);
+ *       System.out.printf("  Today is %s %s %d-%s-%d%n", now1.getChronology().getId(),
+ *                 dow, day, month, year);
+ *
+ *   // Print today's date and the last day of the year for the Thai Buddhist Calendar.
+ *       ThaiBuddhistDate first = now1
+ *                 .with(ChronoField.DAY_OF_MONTH, 1)
+ *                 .with(ChronoField.MONTH_OF_YEAR, 1);
+ *       ThaiBuddhistDate last = first
+ *                 .plus(1, ChronoUnit.YEARS)
+ *                 .minus(1, ChronoUnit.DAYS);
+ *       System.out.printf("  %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(),
+ *                 first, last);
+ *  </pre>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
+ * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ * The Javadoc "@param" definition is used to summarise the null-behavior.
+ * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.chrono;
diff --git a/java/time/format/DateTimeFormatter.java b/java/time/format/DateTimeFormatter.java
new file mode 100644
index 0000000..57a0bf8
--- /dev/null
+++ b/java/time/format/DateTimeFormatter.java
@@ -0,0 +1,2165 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.io.IOException;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParseException;
+import java.text.ParsePosition;
+import java.time.DateTimeException;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeFormatterBuilder.CompositePrinterParser;
+import java.time.temporal.ChronoField;
+import java.time.temporal.IsoFields;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQuery;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Formatter for printing and parsing date-time objects.
+ * <p>
+ * This class provides the main application entry point for printing and parsing
+ * and provides common implementations of {@code DateTimeFormatter}:
+ * <ul>
+ * <li>Using predefined constants, such as {@link #ISO_LOCAL_DATE}</li>
+ * <li>Using pattern letters, such as {@code uuuu-MMM-dd}</li>
+ * <li>Using localized styles, such as {@code long} or {@code medium}</li>
+ * </ul>
+ * <p>
+ * More complex formatters are provided by
+ * {@link DateTimeFormatterBuilder DateTimeFormatterBuilder}.
+ *
+ * <p>
+ * The main date-time classes provide two methods - one for formatting,
+ * {@code format(DateTimeFormatter formatter)}, and one for parsing,
+ * {@code parse(CharSequence text, DateTimeFormatter formatter)}.
+ * <p>For example:
+ * <blockquote><pre>
+ *  LocalDate date = LocalDate.now();
+ *  String text = date.format(formatter);
+ *  LocalDate parsedDate = LocalDate.parse(text, formatter);
+ * </pre></blockquote>
+ * <p>
+ * In addition to the format, formatters can be created with desired Locale,
+ * Chronology, ZoneId, and DecimalStyle.
+ * <p>
+ * The {@link #withLocale withLocale} method returns a new formatter that
+ * overrides the locale. The locale affects some aspects of formatting and
+ * parsing. For example, the {@link #ofLocalizedDate ofLocalizedDate} provides a
+ * formatter that uses the locale specific date format.
+ * <p>
+ * The {@link #withChronology withChronology} method returns a new formatter
+ * that overrides the chronology. If overridden, the date-time value is
+ * converted to the chronology before formatting. During parsing the date-time
+ * value is converted to the chronology before it is returned.
+ * <p>
+ * The {@link #withZone withZone} method returns a new formatter that overrides
+ * the zone. If overridden, the date-time value is converted to a ZonedDateTime
+ * with the requested ZoneId before formatting. During parsing the ZoneId is
+ * applied before the value is returned.
+ * <p>
+ * The {@link #withDecimalStyle withDecimalStyle} method returns a new formatter that
+ * overrides the {@link DecimalStyle}. The DecimalStyle symbols are used for
+ * formatting and parsing.
+ * <p>
+ * Some applications may need to use the older {@link Format java.text.Format}
+ * class for formatting. The {@link #toFormat()} method returns an
+ * implementation of {@code java.text.Format}.
+ *
+ * <h3 id="predefined">Predefined Formatters</h3>
+ * <table summary="Predefined Formatters" cellpadding="2" cellspacing="3" border="0" >
+ * <thead>
+ * <tr class="tableSubHeadingColor">
+ * <th class="colFirst" align="left">Formatter</th>
+ * <th class="colFirst" align="left">Description</th>
+ * <th class="colLast" align="left">Example</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr class="rowColor">
+ * <td>{@link #ofLocalizedDate ofLocalizedDate(dateStyle)} </td>
+ * <td> Formatter with date style from the locale </td>
+ * <td> '2011-12-03'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ofLocalizedTime ofLocalizedTime(timeStyle)} </td>
+ * <td> Formatter with time style from the locale </td>
+ * <td> '10:15:30'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ofLocalizedDateTime ofLocalizedDateTime(dateTimeStyle)} </td>
+ * <td> Formatter with a style for date and time from the locale</td>
+ * <td> '3 Jun 2008 11:05:30'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ofLocalizedDateTime ofLocalizedDateTime(dateStyle,timeStyle)}
+ * </td>
+ * <td> Formatter with date and time styles from the locale </td>
+ * <td> '3 Jun 2008 11:05'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #BASIC_ISO_DATE}</td>
+ * <td>Basic ISO date </td> <td>'20111203'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_LOCAL_DATE}</td>
+ * <td> ISO Local Date </td>
+ * <td>'2011-12-03'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ISO_OFFSET_DATE}</td>
+ * <td> ISO Date with offset </td>
+ * <td>'2011-12-03+01:00'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_DATE}</td>
+ * <td> ISO Date with or without offset </td>
+ * <td> '2011-12-03+01:00'; '2011-12-03'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ISO_LOCAL_TIME}</td>
+ * <td> Time without offset </td>
+ * <td>'10:15:30'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_OFFSET_TIME}</td>
+ * <td> Time with offset </td>
+ * <td>'10:15:30+01:00'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ISO_TIME}</td>
+ * <td> Time with or without offset </td>
+ * <td>'10:15:30+01:00'; '10:15:30'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_LOCAL_DATE_TIME}</td>
+ * <td> ISO Local Date and Time </td>
+ * <td>'2011-12-03T10:15:30'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ISO_OFFSET_DATE_TIME}</td>
+ * <td> Date Time with Offset
+ * </td><td>2011-12-03T10:15:30+01:00'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_ZONED_DATE_TIME}</td>
+ * <td> Zoned Date Time </td>
+ * <td>'2011-12-03T10:15:30+01:00[Europe/Paris]'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ISO_DATE_TIME}</td>
+ * <td> Date and time with ZoneId </td>
+ * <td>'2011-12-03T10:15:30+01:00[Europe/Paris]'</td>
+ * </tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_ORDINAL_DATE}</td>
+ * <td> Year and day of year </td>
+ * <td>'2012-337'</td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #ISO_WEEK_DATE}</td>
+ * <td> Year and Week </td>
+ * <td>2012-W48-6'</td></tr>
+ * <tr class="altColor">
+ * <td> {@link #ISO_INSTANT}</td>
+ * <td> Date and Time of an Instant </td>
+ * <td>'2011-12-03T10:15:30Z' </td>
+ * </tr>
+ * <tr class="rowColor">
+ * <td> {@link #RFC_1123_DATE_TIME}</td>
+ * <td> RFC 1123 / RFC 822 </td>
+ * <td>'Tue, 3 Jun 2008 11:05:30 GMT'</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * <h3 id="patterns">Patterns for Formatting and Parsing</h3>
+ * Patterns are based on a simple sequence of letters and symbols.
+ * A pattern is used to create a Formatter using the
+ * {@link #ofPattern(String)} and {@link #ofPattern(String, Locale)} methods.
+ * For example,
+ * {@code "d MMM uuuu"} will format 2011-12-03 as '3&nbsp;Dec&nbsp;2011'.
+ * A formatter created from a pattern can be used as many times as necessary,
+ * it is immutable and is thread-safe.
+ * <p>
+ * For example:
+ * <blockquote><pre>
+ *  LocalDate date = LocalDate.now();
+ *  DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
+ *  String text = date.format(formatter);
+ *  LocalDate parsedDate = LocalDate.parse(text, formatter);
+ * </pre></blockquote>
+ * <p>
+ * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters. The
+ * following pattern letters are defined:
+ * <pre>
+ *  Symbol  Meaning                     Presentation      Examples
+ *  ------  -------                     ------------      -------
+ *   G       era                         text              AD; Anno Domini; A
+ *   u       year                        year              2004; 04
+ *   y       year-of-era                 year              2004; 04
+ *   D       day-of-year                 number            189
+ *   M/L     month-of-year               number/text       7; 07; Jul; July; J
+ *   d       day-of-month                number            10
+ *
+ *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
+ *   Y       week-based-year             year              1996; 96
+ *   w       week-of-week-based-year     number            27
+ *   W       week-of-month               number            4
+ *   E       day-of-week                 text              Tue; Tuesday; T
+ *   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
+ *   F       week-of-month               number            3
+ *
+ *   a       am-pm-of-day                text              PM
+ *   h       clock-hour-of-am-pm (1-12)  number            12
+ *   K       hour-of-am-pm (0-11)        number            0
+ *   k       clock-hour-of-am-pm (1-24)  number            0
+ *
+ *   H       hour-of-day (0-23)          number            0
+ *   m       minute-of-hour              number            30
+ *   s       second-of-minute            number            55
+ *   S       fraction-of-second          fraction          978
+ *   A       milli-of-day                number            1234
+ *   n       nano-of-second              number            987654321
+ *   N       nano-of-day                 number            1234000000
+ *
+ *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
+ *   z       time-zone name              zone-name         Pacific Standard Time; PST
+ *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
+ *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
+ *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
+ *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
+ *
+ *   p       pad next                    pad modifier      1
+ *
+ *   '       escape for text             delimiter
+ *   ''      single quote                literal           '
+ *   [       optional section start
+ *   ]       optional section end
+ *   #       reserved for future use
+ *   {       reserved for future use
+ *   }       reserved for future use
+ * </pre>
+ * <p>
+ * The count of pattern letters determines the format.
+ * <p>
+ * <b>Text</b>: The text style is determined based on the number of pattern
+ * letters used. Less than 4 pattern letters will use the
+ * {@link TextStyle#SHORT short form}. Exactly 4 pattern letters will use the
+ * {@link TextStyle#FULL full form}. Exactly 5 pattern letters will use the
+ * {@link TextStyle#NARROW narrow form}.
+ * Pattern letters 'L', 'c', and 'q' specify the stand-alone form of the text styles.
+ * <p>
+ * <b>Number</b>: If the count of letters is one, then the value is output using
+ * the minimum number of digits and without padding. Otherwise, the count of digits
+ * is used as the width of the output field, with the value zero-padded as necessary.
+ * The following pattern letters have constraints on the count of letters.
+ * Only one letter of 'c' and 'F' can be specified.
+ * Up to two letters of 'd', 'H', 'h', 'K', 'k', 'm', and 's' can be specified.
+ * Up to three letters of 'D' can be specified.
+ * <p>
+ * <b>Number/Text</b>: If the count of pattern letters is 3 or greater, use the
+ * Text rules above. Otherwise use the Number rules above.
+ * <p>
+ * <b>Fraction</b>: Outputs the nano-of-second field as a fraction-of-second.
+ * The nano-of-second value has nine digits, thus the count of pattern letters
+ * is from 1 to 9. If it is less than 9, then the nano-of-second value is
+ * truncated, with only the most significant digits being output.
+ * <p>
+ * <b>Year</b>: The count of letters determines the minimum field width below
+ * which padding is used. If the count of letters is two, then a
+ * {@link DateTimeFormatterBuilder#appendValueReduced reduced} two digit form is
+ * used. For printing, this outputs the rightmost two digits. For parsing, this
+ * will parse using the base value of 2000, resulting in a year within the range
+ * 2000 to 2099 inclusive. If the count of letters is less than four (but not
+ * two), then the sign is only output for negative years as per
+ * {@link SignStyle#NORMAL}. Otherwise, the sign is output if the pad width is
+ * exceeded, as per {@link SignStyle#EXCEEDS_PAD}.
+ * <p>
+ * <b>ZoneId</b>: This outputs the time-zone ID, such as 'Europe/Paris'. If the
+ * count of letters is two, then the time-zone ID is output. Any other count of
+ * letters throws {@code IllegalArgumentException}.
+ * <p>
+ * <b>Zone names</b>: This outputs the display name of the time-zone ID. If the
+ * count of letters is one, two or three, then the short name is output. If the
+ * count of letters is four, then the full name is output. Five or more letters
+ * throws {@code IllegalArgumentException}.
+ * <p>
+ * <b>Offset X and x</b>: This formats the offset based on the number of pattern
+ * letters. One letter outputs just the hour, such as '+01', unless the minute
+ * is non-zero in which case the minute is also output, such as '+0130'. Two
+ * letters outputs the hour and minute, without a colon, such as '+0130'. Three
+ * letters outputs the hour and minute, with a colon, such as '+01:30'. Four
+ * letters outputs the hour and minute and optional second, without a colon,
+ * such as '+013015'. Five letters outputs the hour and minute and optional
+ * second, with a colon, such as '+01:30:15'. Six or more letters throws
+ * {@code IllegalArgumentException}. Pattern letter 'X' (upper case) will output
+ * 'Z' when the offset to be output would be zero, whereas pattern letter 'x'
+ * (lower case) will output '+00', '+0000', or '+00:00'.
+ * <p>
+ * <b>Offset O</b>: This formats the localized offset based on the number of
+ * pattern letters. One letter outputs the {@linkplain TextStyle#SHORT short}
+ * form of the localized offset, which is localized offset text, such as 'GMT',
+ * with hour without leading zero, optional 2-digit minute and second if
+ * non-zero, and colon, for example 'GMT+8'. Four letters outputs the
+ * {@linkplain TextStyle#FULL full} form, which is localized offset text,
+ * such as 'GMT, with 2-digit hour and minute field, optional second field
+ * if non-zero, and colon, for example 'GMT+08:00'. Any other count of letters
+ * throws {@code IllegalArgumentException}.
+ * <p>
+ * <b>Offset Z</b>: This formats the offset based on the number of pattern
+ * letters. One, two or three letters outputs the hour and minute, without a
+ * colon, such as '+0130'. The output will be '+0000' when the offset is zero.
+ * Four letters outputs the {@linkplain TextStyle#FULL full} form of localized
+ * offset, equivalent to four letters of Offset-O. The output will be the
+ * corresponding localized offset text if the offset is zero. Five
+ * letters outputs the hour, minute, with optional second if non-zero, with
+ * colon. It outputs 'Z' if the offset is zero.
+ * Six or more letters throws {@code IllegalArgumentException}.
+ * <p>
+ * <b>Optional section</b>: The optional section markers work exactly like
+ * calling {@link DateTimeFormatterBuilder#optionalStart()} and
+ * {@link DateTimeFormatterBuilder#optionalEnd()}.
+ * <p>
+ * <b>Pad modifier</b>: Modifies the pattern that immediately follows to be
+ * padded with spaces. The pad width is determined by the number of pattern
+ * letters. This is the same as calling
+ * {@link DateTimeFormatterBuilder#padNext(int)}.
+ * <p>
+ * For example, 'ppH' outputs the hour-of-day padded on the left with spaces to
+ * a width of 2.
+ * <p>
+ * Any unrecognized letter is an error. Any non-letter character, other than
+ * '[', ']', '{', '}', '#' and the single quote will be output directly.
+ * Despite this, it is recommended to use single quotes around all characters
+ * that you want to output directly to ensure that future changes do not break
+ * your application.
+ *
+ * <h3 id="resolving">Resolving</h3>
+ * Parsing is implemented as a two-phase operation.
+ * First, the text is parsed using the layout defined by the formatter, producing
+ * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
+ * Second, the parsed data is <em>resolved</em>, by validating, combining and
+ * simplifying the various fields into more useful ones.
+ * <p>
+ * Five parsing methods are supplied by this class.
+ * Four of these perform both the parse and resolve phases.
+ * The fifth method, {@link #parseUnresolved(CharSequence, ParsePosition)},
+ * only performs the first phase, leaving the result unresolved.
+ * As such, it is essentially a low-level operation.
+ * <p>
+ * The resolve phase is controlled by two parameters, set on this class.
+ * <p>
+ * The {@link ResolverStyle} is an enum that offers three different approaches,
+ * strict, smart and lenient. The smart option is the default.
+ * It can be set using {@link #withResolverStyle(ResolverStyle)}.
+ * <p>
+ * The {@link #withResolverFields(TemporalField...)} parameter allows the
+ * set of fields that will be resolved to be filtered before resolving starts.
+ * For example, if the formatter has parsed a year, month, day-of-month
+ * and day-of-year, then there are two approaches to resolve a date:
+ * (year + month + day-of-month) and (year + day-of-year).
+ * The resolver fields allows one of the two approaches to be selected.
+ * If no resolver fields are set then both approaches must result in the same date.
+ * <p>
+ * Resolving separate fields to form a complete date and time is a complex
+ * process with behaviour distributed across a number of classes.
+ * It follows these steps:
+ * <ol>
+ * <li>The chronology is determined.
+ * The chronology of the result is either the chronology that was parsed,
+ * or if no chronology was parsed, it is the chronology set on this class,
+ * or if that is null, it is {@code IsoChronology}.
+ * <li>The {@code ChronoField} date fields are resolved.
+ * This is achieved using {@link Chronology#resolveDate(Map, ResolverStyle)}.
+ * Documentation about field resolution is located in the implementation
+ * of {@code Chronology}.
+ * <li>The {@code ChronoField} time fields are resolved.
+ * This is documented on {@link ChronoField} and is the same for all chronologies.
+ * <li>Any fields that are not {@code ChronoField} are processed.
+ * This is achieved using {@link TemporalField#resolve(Map, TemporalAccessor, ResolverStyle)}.
+ * Documentation about field resolution is located in the implementation
+ * of {@code TemporalField}.
+ * <li>The {@code ChronoField} date and time fields are re-resolved.
+ * This allows fields in step four to produce {@code ChronoField} values
+ * and have them be processed into dates and times.
+ * <li>A {@code LocalTime} is formed if there is at least an hour-of-day available.
+ * This involves providing default values for minute, second and fraction of second.
+ * <li>Any remaining unresolved fields are cross-checked against any
+ * date and/or time that was resolved. Thus, an earlier stage would resolve
+ * (year + month + day-of-month) to a date, and this stage would check that
+ * day-of-week was valid for the date.
+ * <li>If an {@linkplain #parsedExcessDays() excess number of days}
+ * was parsed then it is added to the date if a date is available.
+ * </ol>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class DateTimeFormatter {
+
+    /**
+     * The printer and/or parser to use, not null.
+     */
+    private final CompositePrinterParser printerParser;
+    /**
+     * The locale to use for formatting, not null.
+     */
+    private final Locale locale;
+    /**
+     * The symbols to use for formatting, not null.
+     */
+    private final DecimalStyle decimalStyle;
+    /**
+     * The resolver style to use, not null.
+     */
+    private final ResolverStyle resolverStyle;
+    /**
+     * The fields to use in resolving, null for all fields.
+     */
+    private final Set<TemporalField> resolverFields;
+    /**
+     * The chronology to use for formatting, null for no override.
+     */
+    private final Chronology chrono;
+    /**
+     * The zone to use for formatting, null for no override.
+     */
+    private final ZoneId zone;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a formatter using the specified pattern.
+     * <p>
+     * This method will create a formatter based on a simple
+     * <a href="#patterns">pattern of letters and symbols</a>
+     * as described in the class documentation.
+     * For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'.
+     * <p>
+     * The formatter will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
+     * This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter
+     * Alternatively use the {@link #ofPattern(String, Locale)} variant of this method.
+     * <p>
+     * The returned formatter has no override chronology or zone.
+     * It uses {@link ResolverStyle#SMART SMART} resolver style.
+     *
+     * @param pattern  the pattern to use, not null
+     * @return the formatter based on the pattern, not null
+     * @throws IllegalArgumentException if the pattern is invalid
+     * @see DateTimeFormatterBuilder#appendPattern(String)
+     */
+    public static DateTimeFormatter ofPattern(String pattern) {
+        return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
+    }
+
+    /**
+     * Creates a formatter using the specified pattern and locale.
+     * <p>
+     * This method will create a formatter based on a simple
+     * <a href="#patterns">pattern of letters and symbols</a>
+     * as described in the class documentation.
+     * For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'.
+     * <p>
+     * The formatter will use the specified locale.
+     * This can be changed using {@link DateTimeFormatter#withLocale(Locale)} on the returned formatter
+     * <p>
+     * The returned formatter has no override chronology or zone.
+     * It uses {@link ResolverStyle#SMART SMART} resolver style.
+     *
+     * @param pattern  the pattern to use, not null
+     * @param locale  the locale to use, not null
+     * @return the formatter based on the pattern, not null
+     * @throws IllegalArgumentException if the pattern is invalid
+     * @see DateTimeFormatterBuilder#appendPattern(String)
+     */
+    public static DateTimeFormatter ofPattern(String pattern, Locale locale) {
+        return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a locale specific date format for the ISO chronology.
+     * <p>
+     * This returns a formatter that will format or parse a date.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * The locale is determined from the formatter. The formatter returned directly by
+     * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
+     * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
+     * on the result of this method.
+     * <p>
+     * Note that the localized pattern is looked up lazily.
+     * This {@code DateTimeFormatter} holds the style required and the locale,
+     * looking up the pattern required on demand.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style.
+     *
+     * @param dateStyle  the formatter style to obtain, not null
+     * @return the date formatter, not null
+     */
+    public static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle) {
+        Objects.requireNonNull(dateStyle, "dateStyle");
+        return new DateTimeFormatterBuilder().appendLocalized(dateStyle, null)
+                .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
+    }
+
+    /**
+     * Returns a locale specific time format for the ISO chronology.
+     * <p>
+     * This returns a formatter that will format or parse a time.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * The locale is determined from the formatter. The formatter returned directly by
+     * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
+     * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
+     * on the result of this method.
+     * <p>
+     * Note that the localized pattern is looked up lazily.
+     * This {@code DateTimeFormatter} holds the style required and the locale,
+     * looking up the pattern required on demand.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style.
+     *
+     * @param timeStyle  the formatter style to obtain, not null
+     * @return the time formatter, not null
+     */
+    public static DateTimeFormatter ofLocalizedTime(FormatStyle timeStyle) {
+        Objects.requireNonNull(timeStyle, "timeStyle");
+        return new DateTimeFormatterBuilder().appendLocalized(null, timeStyle)
+                .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
+    }
+
+    /**
+     * Returns a locale specific date-time formatter for the ISO chronology.
+     * <p>
+     * This returns a formatter that will format or parse a date-time.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * The locale is determined from the formatter. The formatter returned directly by
+     * this method will use the {@link Locale#getDefault(Locale.Category) default FORMAT locale}.
+     * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
+     * on the result of this method.
+     * <p>
+     * Note that the localized pattern is looked up lazily.
+     * This {@code DateTimeFormatter} holds the style required and the locale,
+     * looking up the pattern required on demand.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style.
+     *
+     * @param dateTimeStyle  the formatter style to obtain, not null
+     * @return the date-time formatter, not null
+     */
+    public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateTimeStyle) {
+        Objects.requireNonNull(dateTimeStyle, "dateTimeStyle");
+        return new DateTimeFormatterBuilder().appendLocalized(dateTimeStyle, dateTimeStyle)
+                .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
+    }
+
+    /**
+     * Returns a locale specific date and time format for the ISO chronology.
+     * <p>
+     * This returns a formatter that will format or parse a date-time.
+     * The exact format pattern used varies by locale.
+     * <p>
+     * The locale is determined from the formatter. The formatter returned directly by
+     * this method will use the {@link Locale#getDefault() default FORMAT locale}.
+     * The locale can be controlled using {@link DateTimeFormatter#withLocale(Locale) withLocale(Locale)}
+     * on the result of this method.
+     * <p>
+     * Note that the localized pattern is looked up lazily.
+     * This {@code DateTimeFormatter} holds the style required and the locale,
+     * looking up the pattern required on demand.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style.
+     *
+     * @param dateStyle  the date formatter style to obtain, not null
+     * @param timeStyle  the time formatter style to obtain, not null
+     * @return the date, time or date-time formatter, not null
+     */
+    public static DateTimeFormatter ofLocalizedDateTime(FormatStyle dateStyle, FormatStyle timeStyle) {
+        Objects.requireNonNull(dateStyle, "dateStyle");
+        Objects.requireNonNull(timeStyle, "timeStyle");
+        return new DateTimeFormatterBuilder().appendLocalized(dateStyle, timeStyle)
+                .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date formatter that formats or parses a date without an
+     * offset, such as '2011-12-03'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended local date format.
+     * The format consists of:
+     * <ul>
+     * <li>Four digits or more for the {@link ChronoField#YEAR year}.
+     * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits.
+     * Years outside that range will have a prefixed positive or negative symbol.
+     * <li>A dash
+     * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A dash
+     * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
+     *  This is pre-padded by zero to ensure two digits.
+     * </ul>
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_LOCAL_DATE;
+    static {
+        ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
+                .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+                .appendLiteral('-')
+                .appendValue(MONTH_OF_YEAR, 2)
+                .appendLiteral('-')
+                .appendValue(DAY_OF_MONTH, 2)
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date formatter that formats or parses a date with an
+     * offset, such as '2011-12-03+01:00'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended offset date format.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_DATE}
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_OFFSET_DATE;
+    static {
+        ISO_OFFSET_DATE = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .append(ISO_LOCAL_DATE)
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date formatter that formats or parses a date with the
+     * offset if available, such as '2011-12-03' or '2011-12-03+01:00'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended date format.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_DATE}
+     * <li>If the offset is not available then the format is complete.
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * As this formatter has an optional element, it may be necessary to parse using
+     * {@link DateTimeFormatter#parseBest}.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_DATE;
+    static {
+        ISO_DATE = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .append(ISO_LOCAL_DATE)
+                .optionalStart()
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO time formatter that formats or parses a time without an
+     * offset, such as '10:15' or '10:15:30'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended local time format.
+     * The format consists of:
+     * <ul>
+     * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the second-of-minute is not available then the format is complete.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the nano-of-second is zero or not available then the format is complete.
+     * <li>A decimal point
+     * <li>One to nine digits for the {@link ChronoField#NANO_OF_SECOND nano-of-second}.
+     *  As many digits will be output as required.
+     * </ul>
+     * <p>
+     * The returned formatter has no override chronology or zone.
+     * It uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_LOCAL_TIME;
+    static {
+        ISO_LOCAL_TIME = new DateTimeFormatterBuilder()
+                .appendValue(HOUR_OF_DAY, 2)
+                .appendLiteral(':')
+                .appendValue(MINUTE_OF_HOUR, 2)
+                .optionalStart()
+                .appendLiteral(':')
+                .appendValue(SECOND_OF_MINUTE, 2)
+                .optionalStart()
+                .appendFraction(NANO_OF_SECOND, 0, 9, true)
+                .toFormatter(ResolverStyle.STRICT, null);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO time formatter that formats or parses a time with an
+     * offset, such as '10:15+01:00' or '10:15:30+01:00'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended offset time format.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_TIME}
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * The returned formatter has no override chronology or zone.
+     * It uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_OFFSET_TIME;
+    static {
+        ISO_OFFSET_TIME = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .append(ISO_LOCAL_TIME)
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, null);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO time formatter that formats or parses a time, with the
+     * offset if available, such as '10:15', '10:15:30' or '10:15:30+01:00'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended offset time format.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_TIME}
+     * <li>If the offset is not available then the format is complete.
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * As this formatter has an optional element, it may be necessary to parse using
+     * {@link DateTimeFormatter#parseBest}.
+     * <p>
+     * The returned formatter has no override chronology or zone.
+     * It uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_TIME;
+    static {
+        ISO_TIME = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .append(ISO_LOCAL_TIME)
+                .optionalStart()
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, null);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date-time formatter that formats or parses a date-time without
+     * an offset, such as '2011-12-03T10:15:30'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended offset date-time format.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_DATE}
+     * <li>The letter 'T'. Parsing is case insensitive.
+     * <li>The {@link #ISO_LOCAL_TIME}
+     * </ul>
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_LOCAL_DATE_TIME;
+    static {
+        ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .append(ISO_LOCAL_DATE)
+                .appendLiteral('T')
+                .append(ISO_LOCAL_TIME)
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date-time formatter that formats or parses a date-time with an
+     * offset, such as '2011-12-03T10:15:30+01:00'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended offset date-time format.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_DATE_TIME}
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_OFFSET_DATE_TIME;
+    static {
+        ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .append(ISO_LOCAL_DATE_TIME)
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO-like date-time formatter that formats or parses a date-time with
+     * offset and zone, such as '2011-12-03T10:15:30+01:00[Europe/Paris]'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * a format that extends the ISO-8601 extended offset date-time format
+     * to add the time-zone.
+     * The section in square brackets is not part of the ISO-8601 standard.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_OFFSET_DATE_TIME}
+     * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete.
+     * <li>An open square bracket '['.
+     * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard.
+     *  Parsing is case sensitive.
+     * <li>A close square bracket ']'.
+     * </ul>
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_ZONED_DATE_TIME;
+    static {
+        ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder()
+                .append(ISO_OFFSET_DATE_TIME)
+                .optionalStart()
+                .appendLiteral('[')
+                .parseCaseSensitive()
+                .appendZoneRegionId()
+                .appendLiteral(']')
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO-like date-time formatter that formats or parses a date-time with
+     * the offset and zone if available, such as '2011-12-03T10:15:30',
+     * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended local or offset date-time format, as well as the
+     * extended non-ISO form specifying the time-zone.
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_LOCAL_DATE_TIME}
+     * <li>If the offset is not available to format or parse then the format is complete.
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     * <li>If the zone ID is not available or is a {@code ZoneOffset} then the format is complete.
+     * <li>An open square bracket '['.
+     * <li>The {@link ZoneId#getId() zone ID}. This is not part of the ISO-8601 standard.
+     *  Parsing is case sensitive.
+     * <li>A close square bracket ']'.
+     * </ul>
+     * <p>
+     * As this formatter has an optional element, it may be necessary to parse using
+     * {@link DateTimeFormatter#parseBest}.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_DATE_TIME;
+    static {
+        ISO_DATE_TIME = new DateTimeFormatterBuilder()
+                .append(ISO_LOCAL_DATE_TIME)
+                .optionalStart()
+                .appendOffsetId()
+                .optionalStart()
+                .appendLiteral('[')
+                .parseCaseSensitive()
+                .appendZoneRegionId()
+                .appendLiteral(']')
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date formatter that formats or parses the ordinal date
+     * without an offset, such as '2012-337'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended ordinal date format.
+     * The format consists of:
+     * <ul>
+     * <li>Four digits or more for the {@link ChronoField#YEAR year}.
+     * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits.
+     * Years outside that range will have a prefixed positive or negative symbol.
+     * <li>A dash
+     * <li>Three digits for the {@link ChronoField#DAY_OF_YEAR day-of-year}.
+     *  This is pre-padded by zero to ensure three digits.
+     * <li>If the offset is not available to format or parse then the format is complete.
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * As this formatter has an optional element, it may be necessary to parse using
+     * {@link DateTimeFormatter#parseBest}.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_ORDINAL_DATE;
+    static {
+        ISO_ORDINAL_DATE = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+                .appendLiteral('-')
+                .appendValue(DAY_OF_YEAR, 3)
+                .optionalStart()
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date formatter that formats or parses the week-based date
+     * without an offset, such as '2012-W48-6'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 extended week-based date format.
+     * The format consists of:
+     * <ul>
+     * <li>Four digits or more for the {@link IsoFields#WEEK_BASED_YEAR week-based-year}.
+     * Years in the range 0000 to 9999 will be pre-padded by zero to ensure four digits.
+     * Years outside that range will have a prefixed positive or negative symbol.
+     * <li>A dash
+     * <li>The letter 'W'. Parsing is case insensitive.
+     * <li>Two digits for the {@link IsoFields#WEEK_OF_WEEK_BASED_YEAR week-of-week-based-year}.
+     *  This is pre-padded by zero to ensure three digits.
+     * <li>A dash
+     * <li>One digit for the {@link ChronoField#DAY_OF_WEEK day-of-week}.
+     *  The value run from Monday (1) to Sunday (7).
+     * <li>If the offset is not available to format or parse then the format is complete.
+     * <li>The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then
+     *  they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * As this formatter has an optional element, it may be necessary to parse using
+     * {@link DateTimeFormatter#parseBest}.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_WEEK_DATE;
+    static {
+        ISO_WEEK_DATE = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .appendValue(IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
+                .appendLiteral("-W")
+                .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2)
+                .appendLiteral('-')
+                .appendValue(DAY_OF_WEEK, 1)
+                .optionalStart()
+                .appendOffsetId()
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO instant formatter that formats or parses an instant in UTC,
+     * such as '2011-12-03T10:15:30Z'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 instant format.
+     * When formatting, the second-of-minute is always output.
+     * The nano-of-second outputs zero, three, six or nine digits digits as necessary.
+     * When parsing, time to at least the seconds field is required.
+     * Fractional seconds from zero to nine are parsed.
+     * The localized decimal style is not used.
+     * <p>
+     * This is a special case formatter intended to allow a human readable form
+     * of an {@link java.time.Instant}. The {@code Instant} class is designed to
+     * only represent a point in time and internally stores a value in nanoseconds
+     * from a fixed epoch of 1970-01-01Z. As such, an {@code Instant} cannot be
+     * formatted as a date or time without providing some form of time-zone.
+     * This formatter allows the {@code Instant} to be formatted, by providing
+     * a suitable conversion using {@code ZoneOffset.UTC}.
+     * <p>
+     * The format consists of:
+     * <ul>
+     * <li>The {@link #ISO_OFFSET_DATE_TIME} where the instant is converted from
+     *  {@link ChronoField#INSTANT_SECONDS} and {@link ChronoField#NANO_OF_SECOND}
+     *  using the {@code UTC} offset. Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * The returned formatter has no override chronology or zone.
+     * It uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter ISO_INSTANT;
+    static {
+        ISO_INSTANT = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .appendInstant()
+                .toFormatter(ResolverStyle.STRICT, null);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The ISO date formatter that formats or parses a date without an
+     * offset, such as '20111203'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * the ISO-8601 basic local date format.
+     * The format consists of:
+     * <ul>
+     * <li>Four digits for the {@link ChronoField#YEAR year}.
+     *  Only years in the range 0000 to 9999 are supported.
+     * <li>Two digits for the {@link ChronoField#MONTH_OF_YEAR month-of-year}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>Two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the offset is not available to format or parse then the format is complete.
+     * <li>The {@link ZoneOffset#getId() offset ID} without colons. If the offset has
+     *  seconds then they will be handled even though this is not part of the ISO-8601 standard.
+     *  Parsing is case insensitive.
+     * </ul>
+     * <p>
+     * As this formatter has an optional element, it may be necessary to parse using
+     * {@link DateTimeFormatter#parseBest}.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
+     */
+    public static final DateTimeFormatter BASIC_ISO_DATE;
+    static {
+        BASIC_ISO_DATE = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .appendValue(YEAR, 4)
+                .appendValue(MONTH_OF_YEAR, 2)
+                .appendValue(DAY_OF_MONTH, 2)
+                .optionalStart()
+                .appendOffset("+HHMMss", "Z")
+                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * The RFC-1123 date-time formatter, such as 'Tue, 3 Jun 2008 11:05:30 GMT'.
+     * <p>
+     * This returns an immutable formatter capable of formatting and parsing
+     * most of the RFC-1123 format.
+     * RFC-1123 updates RFC-822 changing the year from two digits to four.
+     * This implementation requires a four digit year.
+     * This implementation also does not handle North American or military zone
+     * names, only 'GMT' and offset amounts.
+     * <p>
+     * The format consists of:
+     * <ul>
+     * <li>If the day-of-week is not available to format or parse then jump to day-of-month.
+     * <li>Three letter {@link ChronoField#DAY_OF_WEEK day-of-week} in English.
+     * <li>A comma
+     * <li>A space
+     * <li>One or two digits for the {@link ChronoField#DAY_OF_MONTH day-of-month}.
+     * <li>A space
+     * <li>Three letter {@link ChronoField#MONTH_OF_YEAR month-of-year} in English.
+     * <li>A space
+     * <li>Four digits for the {@link ChronoField#YEAR year}.
+     *  Only years in the range 0000 to 9999 are supported.
+     * <li>A space
+     * <li>Two digits for the {@link ChronoField#HOUR_OF_DAY hour-of-day}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#MINUTE_OF_HOUR minute-of-hour}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>If the second-of-minute is not available then jump to the next space.
+     * <li>A colon
+     * <li>Two digits for the {@link ChronoField#SECOND_OF_MINUTE second-of-minute}.
+     *  This is pre-padded by zero to ensure two digits.
+     * <li>A space
+     * <li>The {@link ZoneOffset#getId() offset ID} without colons or seconds.
+     *  An offset of zero uses "GMT". North American zone names and military zone names are not handled.
+     * </ul>
+     * <p>
+     * Parsing is case insensitive.
+     * <p>
+     * The returned formatter has a chronology of ISO set to ensure dates in
+     * other calendar systems are correctly converted.
+     * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style.
+     */
+    public static final DateTimeFormatter RFC_1123_DATE_TIME;
+    static {
+        // manually code maps to ensure correct data always used
+        // (locale data can be changed by application code)
+        Map<Long, String> dow = new HashMap<>();
+        dow.put(1L, "Mon");
+        dow.put(2L, "Tue");
+        dow.put(3L, "Wed");
+        dow.put(4L, "Thu");
+        dow.put(5L, "Fri");
+        dow.put(6L, "Sat");
+        dow.put(7L, "Sun");
+        Map<Long, String> moy = new HashMap<>();
+        moy.put(1L, "Jan");
+        moy.put(2L, "Feb");
+        moy.put(3L, "Mar");
+        moy.put(4L, "Apr");
+        moy.put(5L, "May");
+        moy.put(6L, "Jun");
+        moy.put(7L, "Jul");
+        moy.put(8L, "Aug");
+        moy.put(9L, "Sep");
+        moy.put(10L, "Oct");
+        moy.put(11L, "Nov");
+        moy.put(12L, "Dec");
+        RFC_1123_DATE_TIME = new DateTimeFormatterBuilder()
+                .parseCaseInsensitive()
+                .parseLenient()
+                .optionalStart()
+                .appendText(DAY_OF_WEEK, dow)
+                .appendLiteral(", ")
+                .optionalEnd()
+                .appendValue(DAY_OF_MONTH, 1, 2, SignStyle.NOT_NEGATIVE)
+                .appendLiteral(' ')
+                .appendText(MONTH_OF_YEAR, moy)
+                .appendLiteral(' ')
+                .appendValue(YEAR, 4)  // 2 digit year not handled
+                .appendLiteral(' ')
+                .appendValue(HOUR_OF_DAY, 2)
+                .appendLiteral(':')
+                .appendValue(MINUTE_OF_HOUR, 2)
+                .optionalStart()
+                .appendLiteral(':')
+                .appendValue(SECOND_OF_MINUTE, 2)
+                .optionalEnd()
+                .appendLiteral(' ')
+                .appendOffset("+HHMM", "GMT")  // should handle UT/Z/EST/EDT/CST/CDT/MST/MDT/PST/MDT
+                .toFormatter(ResolverStyle.SMART, IsoChronology.INSTANCE);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A query that provides access to the excess days that were parsed.
+     * <p>
+     * This returns a singleton {@linkplain TemporalQuery query} that provides
+     * access to additional information from the parse. The query always returns
+     * a non-null period, with a zero period returned instead of null.
+     * <p>
+     * There are two situations where this query may return a non-zero period.
+     * <ul>
+     * <li>If the {@code ResolverStyle} is {@code LENIENT} and a time is parsed
+     *  without a date, then the complete result of the parse consists of a
+     *  {@code LocalTime} and an excess {@code Period} in days.
+     *
+     * <li>If the {@code ResolverStyle} is {@code SMART} and a time is parsed
+     *  without a date where the time is 24:00:00, then the complete result of
+     *  the parse consists of a {@code LocalTime} of 00:00:00 and an excess
+     *  {@code Period} of one day.
+     * </ul>
+     * <p>
+     * In both cases, if a complete {@code ChronoLocalDateTime} or {@code Instant}
+     * is parsed, then the excess days are added to the date part.
+     * As a result, this query will return a zero period.
+     * <p>
+     * The {@code SMART} behaviour handles the common "end of day" 24:00 value.
+     * Processing in {@code LENIENT} mode also produces the same result:
+     * <pre>
+     *  Text to parse        Parsed object                         Excess days
+     *  "2012-12-03T00:00"   LocalDateTime.of(2012, 12, 3, 0, 0)   ZERO
+     *  "2012-12-03T24:00"   LocalDateTime.of(2012, 12, 4, 0, 0)   ZERO
+     *  "00:00"              LocalTime.of(0, 0)                    ZERO
+     *  "24:00"              LocalTime.of(0, 0)                    Period.ofDays(1)
+     * </pre>
+     * The query can be used as follows:
+     * <pre>
+     *  TemporalAccessor parsed = formatter.parse(str);
+     *  LocalTime time = parsed.query(LocalTime::from);
+     *  Period extraDays = parsed.query(DateTimeFormatter.parsedExcessDays());
+     * </pre>
+     * @return a query that provides access to the excess days that were parsed
+     */
+    public static final TemporalQuery<Period> parsedExcessDays() {
+        return PARSED_EXCESS_DAYS;
+    }
+    private static final TemporalQuery<Period> PARSED_EXCESS_DAYS = t -> {
+        if (t instanceof Parsed) {
+            return ((Parsed) t).excessDays;
+        } else {
+            return Period.ZERO;
+        }
+    };
+
+    /**
+     * A query that provides access to whether a leap-second was parsed.
+     * <p>
+     * This returns a singleton {@linkplain TemporalQuery query} that provides
+     * access to additional information from the parse. The query always returns
+     * a non-null boolean, true if parsing saw a leap-second, false if not.
+     * <p>
+     * Instant parsing handles the special "leap second" time of '23:59:60'.
+     * Leap seconds occur at '23:59:60' in the UTC time-zone, but at other
+     * local times in different time-zones. To avoid this potential ambiguity,
+     * the handling of leap-seconds is limited to
+     * {@link DateTimeFormatterBuilder#appendInstant()}, as that method
+     * always parses the instant with the UTC zone offset.
+     * <p>
+     * If the time '23:59:60' is received, then a simple conversion is applied,
+     * replacing the second-of-minute of 60 with 59. This query can be used
+     * on the parse result to determine if the leap-second adjustment was made.
+     * The query will return {@code true} if it did adjust to remove the
+     * leap-second, and {@code false} if not. Note that applying a leap-second
+     * smoothing mechanism, such as UTC-SLS, is the responsibility of the
+     * application, as follows:
+     * <pre>
+     *  TemporalAccessor parsed = formatter.parse(str);
+     *  Instant instant = parsed.query(Instant::from);
+     *  if (parsed.query(DateTimeFormatter.parsedLeapSecond())) {
+     *    // validate leap-second is correct and apply correct smoothing
+     *  }
+     * </pre>
+     * @return a query that provides access to whether a leap-second was parsed
+     */
+    public static final TemporalQuery<Boolean> parsedLeapSecond() {
+        return PARSED_LEAP_SECOND;
+    }
+    private static final TemporalQuery<Boolean> PARSED_LEAP_SECOND = t -> {
+        if (t instanceof Parsed) {
+            return ((Parsed) t).leapSecond;
+        } else {
+            return Boolean.FALSE;
+        }
+    };
+
+    //-----------------------------------------------------------------------
+    /**
+     * Constructor.
+     *
+     * @param printerParser  the printer/parser to use, not null
+     * @param locale  the locale to use, not null
+     * @param decimalStyle  the DecimalStyle to use, not null
+     * @param resolverStyle  the resolver style to use, not null
+     * @param resolverFields  the fields to use during resolving, null for all fields
+     * @param chrono  the chronology to use, null for no override
+     * @param zone  the zone to use, null for no override
+     */
+    DateTimeFormatter(CompositePrinterParser printerParser,
+            Locale locale, DecimalStyle decimalStyle,
+            ResolverStyle resolverStyle, Set<TemporalField> resolverFields,
+            Chronology chrono, ZoneId zone) {
+        this.printerParser = Objects.requireNonNull(printerParser, "printerParser");
+        this.resolverFields = resolverFields;
+        this.locale = Objects.requireNonNull(locale, "locale");
+        this.decimalStyle = Objects.requireNonNull(decimalStyle, "decimalStyle");
+        this.resolverStyle = Objects.requireNonNull(resolverStyle, "resolverStyle");
+        this.chrono = chrono;
+        this.zone = zone;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the locale to be used during formatting.
+     * <p>
+     * This is used to lookup any part of the formatter needing specific
+     * localization, such as the text or localized pattern.
+     *
+     * @return the locale of this formatter, not null
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new locale.
+     * <p>
+     * This is used to lookup any part of the formatter needing specific
+     * localization, such as the text or localized pattern.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param locale  the new locale, not null
+     * @return a formatter based on this formatter with the requested locale, not null
+     */
+    public DateTimeFormatter withLocale(Locale locale) {
+        if (this.locale.equals(locale)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the DecimalStyle to be used during formatting.
+     *
+     * @return the locale of this formatter, not null
+     */
+    public DecimalStyle getDecimalStyle() {
+        return decimalStyle;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new DecimalStyle.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param decimalStyle  the new DecimalStyle, not null
+     * @return a formatter based on this formatter with the requested DecimalStyle, not null
+     */
+    public DateTimeFormatter withDecimalStyle(DecimalStyle decimalStyle) {
+        if (this.decimalStyle.equals(decimalStyle)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the overriding chronology to be used during formatting.
+     * <p>
+     * This returns the override chronology, used to convert dates.
+     * By default, a formatter has no override chronology, returning null.
+     * See {@link #withChronology(Chronology)} for more details on overriding.
+     *
+     * @return the override chronology of this formatter, null if no override
+     */
+    public Chronology getChronology() {
+        return chrono;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new override chronology.
+     * <p>
+     * This returns a formatter with similar state to this formatter but
+     * with the override chronology set.
+     * By default, a formatter has no override chronology, returning null.
+     * <p>
+     * If an override is added, then any date that is formatted or parsed will be affected.
+     * <p>
+     * When formatting, if the temporal object contains a date, then it will
+     * be converted to a date in the override chronology.
+     * Whether the temporal contains a date is determined by querying the
+     * {@link ChronoField#EPOCH_DAY EPOCH_DAY} field.
+     * Any time or zone will be retained unaltered unless overridden.
+     * <p>
+     * If the temporal object does not contain a date, but does contain one
+     * or more {@code ChronoField} date fields, then a {@code DateTimeException}
+     * is thrown. In all other cases, the override chronology is added to the temporal,
+     * replacing any previous chronology, but without changing the date/time.
+     * <p>
+     * When parsing, there are two distinct cases to consider.
+     * If a chronology has been parsed directly from the text, perhaps because
+     * {@link DateTimeFormatterBuilder#appendChronologyId()} was used, then
+     * this override chronology has no effect.
+     * If no zone has been parsed, then this override chronology will be used
+     * to interpret the {@code ChronoField} values into a date according to the
+     * date resolving rules of the chronology.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param chrono  the new chronology, null if no override
+     * @return a formatter based on this formatter with the requested override chronology, not null
+     */
+    public DateTimeFormatter withChronology(Chronology chrono) {
+        if (Objects.equals(this.chrono, chrono)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the overriding zone to be used during formatting.
+     * <p>
+     * This returns the override zone, used to convert instants.
+     * By default, a formatter has no override zone, returning null.
+     * See {@link #withZone(ZoneId)} for more details on overriding.
+     *
+     * @return the override zone of this formatter, null if no override
+     */
+    public ZoneId getZone() {
+        return zone;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new override zone.
+     * <p>
+     * This returns a formatter with similar state to this formatter but
+     * with the override zone set.
+     * By default, a formatter has no override zone, returning null.
+     * <p>
+     * If an override is added, then any instant that is formatted or parsed will be affected.
+     * <p>
+     * When formatting, if the temporal object contains an instant, then it will
+     * be converted to a zoned date-time using the override zone.
+     * Whether the temporal is an instant is determined by querying the
+     * {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS} field.
+     * If the input has a chronology then it will be retained unless overridden.
+     * If the input does not have a chronology, such as {@code Instant}, then
+     * the ISO chronology will be used.
+     * <p>
+     * If the temporal object does not contain an instant, but does contain
+     * an offset then an additional check is made. If the normalized override
+     * zone is an offset that differs from the offset of the temporal, then
+     * a {@code DateTimeException} is thrown. In all other cases, the override
+     * zone is added to the temporal, replacing any previous zone, but without
+     * changing the date/time.
+     * <p>
+     * When parsing, there are two distinct cases to consider.
+     * If a zone has been parsed directly from the text, perhaps because
+     * {@link DateTimeFormatterBuilder#appendZoneId()} was used, then
+     * this override zone has no effect.
+     * If no zone has been parsed, then this override zone will be included in
+     * the result of the parse where it can be used to build instants and date-times.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param zone  the new override zone, null if no override
+     * @return a formatter based on this formatter with the requested override zone, not null
+     */
+    public DateTimeFormatter withZone(ZoneId zone) {
+        if (Objects.equals(this.zone, zone)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the resolver style to use during parsing.
+     * <p>
+     * This returns the resolver style, used during the second phase of parsing
+     * when fields are resolved into dates and times.
+     * By default, a formatter has the {@link ResolverStyle#SMART SMART} resolver style.
+     * See {@link #withResolverStyle(ResolverStyle)} for more details.
+     *
+     * @return the resolver style of this formatter, not null
+     */
+    public ResolverStyle getResolverStyle() {
+        return resolverStyle;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new resolver style.
+     * <p>
+     * This returns a formatter with similar state to this formatter but
+     * with the resolver style set. By default, a formatter has the
+     * {@link ResolverStyle#SMART SMART} resolver style.
+     * <p>
+     * Changing the resolver style only has an effect during parsing.
+     * Parsing a text string occurs in two phases.
+     * Phase 1 is a basic text parse according to the fields added to the builder.
+     * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
+     * The resolver style is used to control how phase 2, resolving, happens.
+     * See {@code ResolverStyle} for more information on the options available.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param resolverStyle  the new resolver style, not null
+     * @return a formatter based on this formatter with the requested resolver style, not null
+     */
+    public DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle) {
+        Objects.requireNonNull(resolverStyle, "resolverStyle");
+        if (Objects.equals(this.resolverStyle, resolverStyle)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the resolver fields to use during parsing.
+     * <p>
+     * This returns the resolver fields, used during the second phase of parsing
+     * when fields are resolved into dates and times.
+     * By default, a formatter has no resolver fields, and thus returns null.
+     * See {@link #withResolverFields(Set)} for more details.
+     *
+     * @return the immutable set of resolver fields of this formatter, null if no fields
+     */
+    public Set<TemporalField> getResolverFields() {
+        return resolverFields;
+    }
+
+    /**
+     * Returns a copy of this formatter with a new set of resolver fields.
+     * <p>
+     * This returns a formatter with similar state to this formatter but with
+     * the resolver fields set. By default, a formatter has no resolver fields.
+     * <p>
+     * Changing the resolver fields only has an effect during parsing.
+     * Parsing a text string occurs in two phases.
+     * Phase 1 is a basic text parse according to the fields added to the builder.
+     * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
+     * The resolver fields are used to filter the field-value pairs between phase 1 and 2.
+     * <p>
+     * This can be used to select between two or more ways that a date or time might
+     * be resolved. For example, if the formatter consists of year, month, day-of-month
+     * and day-of-year, then there are two ways to resolve a date.
+     * Calling this method with the arguments {@link ChronoField#YEAR YEAR} and
+     * {@link ChronoField#DAY_OF_YEAR DAY_OF_YEAR} will ensure that the date is
+     * resolved using the year and day-of-year, effectively meaning that the month
+     * and day-of-month are ignored during the resolving phase.
+     * <p>
+     * In a similar manner, this method can be used to ignore secondary fields that
+     * would otherwise be cross-checked. For example, if the formatter consists of year,
+     * month, day-of-month and day-of-week, then there is only one way to resolve a
+     * date, but the parsed value for day-of-week will be cross-checked against the
+     * resolved date. Calling this method with the arguments {@link ChronoField#YEAR YEAR},
+     * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
+     * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} will ensure that the date is
+     * resolved correctly, but without any cross-check for the day-of-week.
+     * <p>
+     * In implementation terms, this method behaves as follows. The result of the
+     * parsing phase can be considered to be a map of field to value. The behavior
+     * of this method is to cause that map to be filtered between phase 1 and 2,
+     * removing all fields other than those specified as arguments to this method.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param resolverFields  the new set of resolver fields, null if no fields
+     * @return a formatter based on this formatter with the requested resolver style, not null
+     */
+    public DateTimeFormatter withResolverFields(TemporalField... resolverFields) {
+        Set<TemporalField> fields = null;
+        if (resolverFields != null) {
+            fields = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(resolverFields)));
+        }
+        if (Objects.equals(this.resolverFields, fields)) {
+            return this;
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, fields, chrono, zone);
+    }
+
+    /**
+     * Returns a copy of this formatter with a new set of resolver fields.
+     * <p>
+     * This returns a formatter with similar state to this formatter but with
+     * the resolver fields set. By default, a formatter has no resolver fields.
+     * <p>
+     * Changing the resolver fields only has an effect during parsing.
+     * Parsing a text string occurs in two phases.
+     * Phase 1 is a basic text parse according to the fields added to the builder.
+     * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
+     * The resolver fields are used to filter the field-value pairs between phase 1 and 2.
+     * <p>
+     * This can be used to select between two or more ways that a date or time might
+     * be resolved. For example, if the formatter consists of year, month, day-of-month
+     * and day-of-year, then there are two ways to resolve a date.
+     * Calling this method with the arguments {@link ChronoField#YEAR YEAR} and
+     * {@link ChronoField#DAY_OF_YEAR DAY_OF_YEAR} will ensure that the date is
+     * resolved using the year and day-of-year, effectively meaning that the month
+     * and day-of-month are ignored during the resolving phase.
+     * <p>
+     * In a similar manner, this method can be used to ignore secondary fields that
+     * would otherwise be cross-checked. For example, if the formatter consists of year,
+     * month, day-of-month and day-of-week, then there is only one way to resolve a
+     * date, but the parsed value for day-of-week will be cross-checked against the
+     * resolved date. Calling this method with the arguments {@link ChronoField#YEAR YEAR},
+     * {@link ChronoField#MONTH_OF_YEAR MONTH_OF_YEAR} and
+     * {@link ChronoField#DAY_OF_MONTH DAY_OF_MONTH} will ensure that the date is
+     * resolved correctly, but without any cross-check for the day-of-week.
+     * <p>
+     * In implementation terms, this method behaves as follows. The result of the
+     * parsing phase can be considered to be a map of field to value. The behavior
+     * of this method is to cause that map to be filtered between phase 1 and 2,
+     * removing all fields other than those specified as arguments to this method.
+     * <p>
+     * This instance is immutable and unaffected by this method call.
+     *
+     * @param resolverFields  the new set of resolver fields, null if no fields
+     * @return a formatter based on this formatter with the requested resolver style, not null
+     */
+    public DateTimeFormatter withResolverFields(Set<TemporalField> resolverFields) {
+        if (Objects.equals(this.resolverFields, resolverFields)) {
+            return this;
+        }
+        if (resolverFields != null) {
+            resolverFields = Collections.unmodifiableSet(new HashSet<>(resolverFields));
+        }
+        return new DateTimeFormatter(printerParser, locale, decimalStyle, resolverStyle, resolverFields, chrono, zone);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Formats a date-time object using this formatter.
+     * <p>
+     * This formats the date-time to a String using the rules of the formatter.
+     *
+     * @param temporal  the temporal object to format, not null
+     * @return the formatted string, not null
+     * @throws DateTimeException if an error occurs during formatting
+     */
+    public String format(TemporalAccessor temporal) {
+        StringBuilder buf = new StringBuilder(32);
+        formatTo(temporal, buf);
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Formats a date-time object to an {@code Appendable} using this formatter.
+     * <p>
+     * This outputs the formatted date-time to the specified destination.
+     * {@link Appendable} is a general purpose interface that is implemented by all
+     * key character output classes including {@code StringBuffer}, {@code StringBuilder},
+     * {@code PrintStream} and {@code Writer}.
+     * <p>
+     * Although {@code Appendable} methods throw an {@code IOException}, this method does not.
+     * Instead, any {@code IOException} is wrapped in a runtime exception.
+     *
+     * @param temporal  the temporal object to format, not null
+     * @param appendable  the appendable to format to, not null
+     * @throws DateTimeException if an error occurs during formatting
+     */
+    public void formatTo(TemporalAccessor temporal, Appendable appendable) {
+        Objects.requireNonNull(temporal, "temporal");
+        Objects.requireNonNull(appendable, "appendable");
+        try {
+            DateTimePrintContext context = new DateTimePrintContext(temporal, this);
+            if (appendable instanceof StringBuilder) {
+                printerParser.format(context, (StringBuilder) appendable);
+            } else {
+                // buffer output to avoid writing to appendable in case of error
+                StringBuilder buf = new StringBuilder(32);
+                printerParser.format(context, buf);
+                appendable.append(buf);
+            }
+        } catch (IOException ex) {
+            throw new DateTimeException(ex.getMessage(), ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Fully parses the text producing a temporal object.
+     * <p>
+     * This parses the entire text producing a temporal object.
+     * It is typically more useful to use {@link #parse(CharSequence, TemporalQuery)}.
+     * The result of this method is {@code TemporalAccessor} which has been resolved,
+     * applying basic validation checks to help ensure a valid date-time.
+     * <p>
+     * If the parse completes without reading the entire length of the text,
+     * or a problem occurs during parsing or merging, then an exception is thrown.
+     *
+     * @param text  the text to parse, not null
+     * @return the parsed temporal object, not null
+     * @throws DateTimeParseException if unable to parse the requested result
+     */
+    public TemporalAccessor parse(CharSequence text) {
+        Objects.requireNonNull(text, "text");
+        try {
+            return parseResolved0(text, null);
+        } catch (DateTimeParseException ex) {
+            throw ex;
+        } catch (RuntimeException ex) {
+            throw createError(text, ex);
+        }
+    }
+
+    /**
+     * Parses the text using this formatter, providing control over the text position.
+     * <p>
+     * This parses the text without requiring the parse to start from the beginning
+     * of the string or finish at the end.
+     * The result of this method is {@code TemporalAccessor} which has been resolved,
+     * applying basic validation checks to help ensure a valid date-time.
+     * <p>
+     * The text will be parsed from the specified start {@code ParsePosition}.
+     * The entire length of the text does not have to be parsed, the {@code ParsePosition}
+     * will be updated with the index at the end of parsing.
+     * <p>
+     * The operation of this method is slightly different to similar methods using
+     * {@code ParsePosition} on {@code java.text.Format}. That class will return
+     * errors using the error index on the {@code ParsePosition}. By contrast, this
+     * method will throw a {@link DateTimeParseException} if an error occurs, with
+     * the exception containing the error index.
+     * This change in behavior is necessary due to the increased complexity of
+     * parsing and resolving dates/times in this API.
+     * <p>
+     * If the formatter parses the same field more than once with different values,
+     * the result will be an error.
+     *
+     * @param text  the text to parse, not null
+     * @param position  the position to parse from, updated with length parsed
+     *  and the index of any error, not null
+     * @return the parsed temporal object, not null
+     * @throws DateTimeParseException if unable to parse the requested result
+     * @throws IndexOutOfBoundsException if the position is invalid
+     */
+    public TemporalAccessor parse(CharSequence text, ParsePosition position) {
+        Objects.requireNonNull(text, "text");
+        Objects.requireNonNull(position, "position");
+        try {
+            return parseResolved0(text, position);
+        } catch (DateTimeParseException | IndexOutOfBoundsException ex) {
+            throw ex;
+        } catch (RuntimeException ex) {
+            throw createError(text, ex);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Fully parses the text producing an object of the specified type.
+     * <p>
+     * Most applications should use this method for parsing.
+     * It parses the entire text to produce the required date-time.
+     * The query is typically a method reference to a {@code from(TemporalAccessor)} method.
+     * For example:
+     * <pre>
+     *  LocalDateTime dt = parser.parse(str, LocalDateTime::from);
+     * </pre>
+     * If the parse completes without reading the entire length of the text,
+     * or a problem occurs during parsing or merging, then an exception is thrown.
+     *
+     * @param <T> the type of the parsed date-time
+     * @param text  the text to parse, not null
+     * @param query  the query defining the type to parse to, not null
+     * @return the parsed date-time, not null
+     * @throws DateTimeParseException if unable to parse the requested result
+     */
+    public <T> T parse(CharSequence text, TemporalQuery<T> query) {
+        Objects.requireNonNull(text, "text");
+        Objects.requireNonNull(query, "query");
+        try {
+            return parseResolved0(text, null).query(query);
+        } catch (DateTimeParseException ex) {
+            throw ex;
+        } catch (RuntimeException ex) {
+            throw createError(text, ex);
+        }
+    }
+
+    /**
+     * Fully parses the text producing an object of one of the specified types.
+     * <p>
+     * This parse method is convenient for use when the parser can handle optional elements.
+     * For example, a pattern of 'uuuu-MM-dd HH.mm[ VV]' can be fully parsed to a {@code ZonedDateTime},
+     * or partially parsed to a {@code LocalDateTime}.
+     * The queries must be specified in order, starting from the best matching full-parse option
+     * and ending with the worst matching minimal parse option.
+     * The query is typically a method reference to a {@code from(TemporalAccessor)} method.
+     * <p>
+     * The result is associated with the first type that successfully parses.
+     * Normally, applications will use {@code instanceof} to check the result.
+     * For example:
+     * <pre>
+     *  TemporalAccessor dt = parser.parseBest(str, ZonedDateTime::from, LocalDateTime::from);
+     *  if (dt instanceof ZonedDateTime) {
+     *   ...
+     *  } else {
+     *   ...
+     *  }
+     * </pre>
+     * If the parse completes without reading the entire length of the text,
+     * or a problem occurs during parsing or merging, then an exception is thrown.
+     *
+     * @param text  the text to parse, not null
+     * @param queries  the queries defining the types to attempt to parse to,
+     *  must implement {@code TemporalAccessor}, not null
+     * @return the parsed date-time, not null
+     * @throws IllegalArgumentException if less than 2 types are specified
+     * @throws DateTimeParseException if unable to parse the requested result
+     */
+    public TemporalAccessor parseBest(CharSequence text, TemporalQuery<?>... queries) {
+        Objects.requireNonNull(text, "text");
+        Objects.requireNonNull(queries, "queries");
+        if (queries.length < 2) {
+            throw new IllegalArgumentException("At least two queries must be specified");
+        }
+        try {
+            TemporalAccessor resolved = parseResolved0(text, null);
+            for (TemporalQuery<?> query : queries) {
+                try {
+                    return (TemporalAccessor) resolved.query(query);
+                } catch (RuntimeException ex) {
+                    // continue
+                }
+            }
+            throw new DateTimeException("Unable to convert parsed text using any of the specified queries");
+        } catch (DateTimeParseException ex) {
+            throw ex;
+        } catch (RuntimeException ex) {
+            throw createError(text, ex);
+        }
+    }
+
+    private DateTimeParseException createError(CharSequence text, RuntimeException ex) {
+        String abbr;
+        if (text.length() > 64) {
+            abbr = text.subSequence(0, 64).toString() + "...";
+        } else {
+            abbr = text.toString();
+        }
+        return new DateTimeParseException("Text '" + abbr + "' could not be parsed: " + ex.getMessage(), text, 0, ex);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Parses and resolves the specified text.
+     * <p>
+     * This parses to a {@code TemporalAccessor} ensuring that the text is fully parsed.
+     *
+     * @param text  the text to parse, not null
+     * @param position  the position to parse from, updated with length parsed
+     *  and the index of any error, null if parsing whole string
+     * @return the resolved result of the parse, not null
+     * @throws DateTimeParseException if the parse fails
+     * @throws DateTimeException if an error occurs while resolving the date or time
+     * @throws IndexOutOfBoundsException if the position is invalid
+     */
+    private TemporalAccessor parseResolved0(final CharSequence text, final ParsePosition position) {
+        ParsePosition pos = (position != null ? position : new ParsePosition(0));
+        DateTimeParseContext context = parseUnresolved0(text, pos);
+        if (context == null || pos.getErrorIndex() >= 0 || (position == null && pos.getIndex() < text.length())) {
+            String abbr;
+            if (text.length() > 64) {
+                abbr = text.subSequence(0, 64).toString() + "...";
+            } else {
+                abbr = text.toString();
+            }
+            if (pos.getErrorIndex() >= 0) {
+                throw new DateTimeParseException("Text '" + abbr + "' could not be parsed at index " +
+                        pos.getErrorIndex(), text, pos.getErrorIndex());
+            } else {
+                throw new DateTimeParseException("Text '" + abbr + "' could not be parsed, unparsed text found at index " +
+                        pos.getIndex(), text, pos.getIndex());
+            }
+        }
+        return context.toResolved(resolverStyle, resolverFields);
+    }
+
+    /**
+     * Parses the text using this formatter, without resolving the result, intended
+     * for advanced use cases.
+     * <p>
+     * Parsing is implemented as a two-phase operation.
+     * First, the text is parsed using the layout defined by the formatter, producing
+     * a {@code Map} of field to value, a {@code ZoneId} and a {@code Chronology}.
+     * Second, the parsed data is <em>resolved</em>, by validating, combining and
+     * simplifying the various fields into more useful ones.
+     * This method performs the parsing stage but not the resolving stage.
+     * <p>
+     * The result of this method is {@code TemporalAccessor} which represents the
+     * data as seen in the input. Values are not validated, thus parsing a date string
+     * of '2012-00-65' would result in a temporal with three fields - year of '2012',
+     * month of '0' and day-of-month of '65'.
+     * <p>
+     * The text will be parsed from the specified start {@code ParsePosition}.
+     * The entire length of the text does not have to be parsed, the {@code ParsePosition}
+     * will be updated with the index at the end of parsing.
+     * <p>
+     * Errors are returned using the error index field of the {@code ParsePosition}
+     * instead of {@code DateTimeParseException}.
+     * The returned error index will be set to an index indicative of the error.
+     * Callers must check for errors before using the result.
+     * <p>
+     * If the formatter parses the same field more than once with different values,
+     * the result will be an error.
+     * <p>
+     * This method is intended for advanced use cases that need access to the
+     * internal state during parsing. Typical application code should use
+     * {@link #parse(CharSequence, TemporalQuery)} or the parse method on the target type.
+     *
+     * @param text  the text to parse, not null
+     * @param position  the position to parse from, updated with length parsed
+     *  and the index of any error, not null
+     * @return the parsed text, null if the parse results in an error
+     * @throws DateTimeException if some problem occurs during parsing
+     * @throws IndexOutOfBoundsException if the position is invalid
+     */
+    public TemporalAccessor parseUnresolved(CharSequence text, ParsePosition position) {
+        DateTimeParseContext context = parseUnresolved0(text, position);
+        if (context == null) {
+            return null;
+        }
+        return context.toUnresolved();
+    }
+
+    private DateTimeParseContext parseUnresolved0(CharSequence text, ParsePosition position) {
+        Objects.requireNonNull(text, "text");
+        Objects.requireNonNull(position, "position");
+        DateTimeParseContext context = new DateTimeParseContext(this);
+        int pos = position.getIndex();
+        pos = printerParser.parse(context, text, pos);
+        if (pos < 0) {
+            position.setErrorIndex(~pos);  // index not updated from input
+            return null;
+        }
+        position.setIndex(pos);  // errorIndex not updated from input
+        return context;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the formatter as a composite printer parser.
+     *
+     * @param optional  whether the printer/parser should be optional
+     * @return the printer/parser, not null
+     */
+    CompositePrinterParser toPrinterParser(boolean optional) {
+        return printerParser.withOptional(optional);
+    }
+
+    /**
+     * Returns this formatter as a {@code java.text.Format} instance.
+     * <p>
+     * The returned {@link Format} instance will format any {@link TemporalAccessor}
+     * and parses to a resolved {@link TemporalAccessor}.
+     * <p>
+     * Exceptions will follow the definitions of {@code Format}, see those methods
+     * for details about {@code IllegalArgumentException} during formatting and
+     * {@code ParseException} or null during parsing.
+     * The format does not support attributing of the returned format string.
+     *
+     * @return this formatter as a classic format instance, not null
+     */
+    public Format toFormat() {
+        return new ClassicFormat(this, null);
+    }
+
+    /**
+     * Returns this formatter as a {@code java.text.Format} instance that will
+     * parse using the specified query.
+     * <p>
+     * The returned {@link Format} instance will format any {@link TemporalAccessor}
+     * and parses to the type specified.
+     * The type must be one that is supported by {@link #parse}.
+     * <p>
+     * Exceptions will follow the definitions of {@code Format}, see those methods
+     * for details about {@code IllegalArgumentException} during formatting and
+     * {@code ParseException} or null during parsing.
+     * The format does not support attributing of the returned format string.
+     *
+     * @param parseQuery  the query defining the type to parse to, not null
+     * @return this formatter as a classic format instance, not null
+     */
+    public Format toFormat(TemporalQuery<?> parseQuery) {
+        Objects.requireNonNull(parseQuery, "parseQuery");
+        return new ClassicFormat(this, parseQuery);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a description of the underlying formatters.
+     *
+     * @return a description of this formatter, not null
+     */
+    @Override
+    public String toString() {
+        String pattern = printerParser.toString();
+        pattern = pattern.startsWith("[") ? pattern : pattern.substring(1, pattern.length() - 1);
+        return pattern;
+        // TODO: Fix tests to not depend on toString()
+//        return "DateTimeFormatter[" + locale +
+//                (chrono != null ? "," + chrono : "") +
+//                (zone != null ? "," + zone : "") +
+//                pattern + "]";
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the classic Java Format API.
+     * @serial exclude
+     */
+    @SuppressWarnings("serial")  // not actually serializable
+    static class ClassicFormat extends Format {
+        /** The formatter. */
+        private final DateTimeFormatter formatter;
+        /** The type to be parsed. */
+        private final TemporalQuery<?> parseType;
+        /** Constructor. */
+        public ClassicFormat(DateTimeFormatter formatter, TemporalQuery<?> parseType) {
+            this.formatter = formatter;
+            this.parseType = parseType;
+        }
+
+        @Override
+        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+            Objects.requireNonNull(obj, "obj");
+            Objects.requireNonNull(toAppendTo, "toAppendTo");
+            Objects.requireNonNull(pos, "pos");
+            if (obj instanceof TemporalAccessor == false) {
+                throw new IllegalArgumentException("Format target must implement TemporalAccessor");
+            }
+            pos.setBeginIndex(0);
+            pos.setEndIndex(0);
+            try {
+                formatter.formatTo((TemporalAccessor) obj, toAppendTo);
+            } catch (RuntimeException ex) {
+                throw new IllegalArgumentException(ex.getMessage(), ex);
+            }
+            return toAppendTo;
+        }
+        @Override
+        public Object parseObject(String text) throws ParseException {
+            Objects.requireNonNull(text, "text");
+            try {
+                if (parseType == null) {
+                    return formatter.parseResolved0(text, null);
+                }
+                return formatter.parse(text, parseType);
+            } catch (DateTimeParseException ex) {
+                throw new ParseException(ex.getMessage(), ex.getErrorIndex());
+            } catch (RuntimeException ex) {
+                throw (ParseException) new ParseException(ex.getMessage(), 0).initCause(ex);
+            }
+        }
+        @Override
+        public Object parseObject(String text, ParsePosition pos) {
+            Objects.requireNonNull(text, "text");
+            DateTimeParseContext context;
+            try {
+                context = formatter.parseUnresolved0(text, pos);
+            } catch (IndexOutOfBoundsException ex) {
+                if (pos.getErrorIndex() < 0) {
+                    pos.setErrorIndex(0);
+                }
+                return null;
+            }
+            if (context == null) {
+                if (pos.getErrorIndex() < 0) {
+                    pos.setErrorIndex(0);
+                }
+                return null;
+            }
+            try {
+                TemporalAccessor resolved = context.toResolved(formatter.resolverStyle, formatter.resolverFields);
+                if (parseType == null) {
+                    return resolved;
+                }
+                return resolved.query(parseType);
+            } catch (RuntimeException ex) {
+                pos.setErrorIndex(0);
+                return null;
+            }
+        }
+    }
+
+}
diff --git a/java/time/format/DateTimeFormatterBuilder.java b/java/time/format/DateTimeFormatterBuilder.java
new file mode 100644
index 0000000..736a8fc
--- /dev/null
+++ b/java/time/format/DateTimeFormatterBuilder.java
@@ -0,0 +1,4610 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights hg qreserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import android.icu.impl.ZoneMeta;
+import android.icu.text.LocaleDisplayNames;
+import android.icu.text.TimeZoneFormat;
+import android.icu.text.TimeZoneNames;
+import android.icu.util.Calendar;
+import android.icu.util.ULocale;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+import static java.time.temporal.ChronoField.YEAR;
+
+import java.lang.ref.SoftReference;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.text.ParsePosition;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.DateTimeTextProvider.LocaleStore;
+import java.time.temporal.ChronoField;
+import java.time.temporal.IsoFields;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.time.temporal.WeekFields;
+import java.time.zone.ZoneRulesProvider;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Builder to create date-time formatters.
+ * <p>
+ * This allows a {@code DateTimeFormatter} to be created.
+ * All date-time formatters are created ultimately using this builder.
+ * <p>
+ * The basic elements of date-time can all be added:
+ * <ul>
+ * <li>Value - a numeric value</li>
+ * <li>Fraction - a fractional value including the decimal place. Always use this when
+ * outputting fractions to ensure that the fraction is parsed correctly</li>
+ * <li>Text - the textual equivalent for the value</li>
+ * <li>OffsetId/Offset - the {@linkplain ZoneOffset zone offset}</li>
+ * <li>ZoneId - the {@linkplain ZoneId time-zone} id</li>
+ * <li>ZoneText - the name of the time-zone</li>
+ * <li>ChronologyId - the {@linkplain Chronology chronology} id</li>
+ * <li>ChronologyText - the name of the chronology</li>
+ * <li>Literal - a text literal</li>
+ * <li>Nested and Optional - formats can be nested or made optional</li>
+ * </ul>
+ * In addition, any of the elements may be decorated by padding, either with spaces or any other character.
+ * <p>
+ * Finally, a shorthand pattern, mostly compatible with {@code java.text.SimpleDateFormat SimpleDateFormat}
+ * can be used, see {@link #appendPattern(String)}.
+ * In practice, this simply parses the pattern and calls other methods on the builder.
+ *
+ * @implSpec
+ * This class is a mutable builder intended for use from a single thread.
+ *
+ * @since 1.8
+ */
+public final class DateTimeFormatterBuilder {
+
+    /**
+     * Query for a time-zone that is region-only.
+     */
+    private static final TemporalQuery<ZoneId> QUERY_REGION_ONLY = (temporal) -> {
+        ZoneId zone = temporal.query(TemporalQueries.zoneId());
+        return (zone != null && zone instanceof ZoneOffset == false ? zone : null);
+    };
+
+    /**
+     * The currently active builder, used by the outermost builder.
+     */
+    private DateTimeFormatterBuilder active = this;
+    /**
+     * The parent builder, null for the outermost builder.
+     */
+    private final DateTimeFormatterBuilder parent;
+    /**
+     * The list of printers that will be used.
+     */
+    private final List<DateTimePrinterParser> printerParsers = new ArrayList<>();
+    /**
+     * Whether this builder produces an optional formatter.
+     */
+    private final boolean optional;
+    /**
+     * The width to pad the next field to.
+     */
+    private int padNextWidth;
+    /**
+     * The character to pad the next field with.
+     */
+    private char padNextChar;
+    /**
+     * The index of the last variable width value parser.
+     */
+    private int valueParserIndex = -1;
+
+    /**
+     * Gets the formatting pattern for date and time styles for a locale and chronology.
+     * The locale and chronology are used to lookup the locale specific format
+     * for the requested dateStyle and/or timeStyle.
+     *
+     * @param dateStyle  the FormatStyle for the date, null for time-only pattern
+     * @param timeStyle  the FormatStyle for the time, null for date-only pattern
+     * @param chrono  the Chronology, non-null
+     * @param locale  the locale, non-null
+     * @return the locale and Chronology specific formatting pattern
+     * @throws IllegalArgumentException if both dateStyle and timeStyle are null
+     */
+    public static String getLocalizedDateTimePattern(FormatStyle dateStyle, FormatStyle timeStyle,
+            Chronology chrono, Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        Objects.requireNonNull(chrono, "chrono");
+        if (dateStyle == null && timeStyle == null) {
+            throw new IllegalArgumentException("Either dateStyle or timeStyle must be non-null");
+        }
+
+        // Android-changed: get format string from ICU.
+        // LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
+        //         .getLocaleResources(locale);
+        // String pattern = lr.getJavaTimeDateTimePattern(
+        //         convertStyle(timeStyle), convertStyle(dateStyle), chrono.getCalendarType());
+        String pattern = Calendar.getDateTimeFormatString(
+                ULocale.forLocale(locale), chrono.getCalendarType(),
+                convertStyle(dateStyle), convertStyle(timeStyle));
+        return pattern;
+    }
+
+    /**
+     * Converts the given FormatStyle to the java.text.DateFormat style.
+     *
+     * @param style  the FormatStyle style
+     * @return the int style, or -1 if style is null, indicating un-required
+     */
+    private static int convertStyle(FormatStyle style) {
+        if (style == null) {
+            return -1;
+        }
+        return style.ordinal();  // indices happen to align
+    }
+
+    /**
+     * Constructs a new instance of the builder.
+     */
+    public DateTimeFormatterBuilder() {
+        super();
+        parent = null;
+        optional = false;
+    }
+
+    /**
+     * Constructs a new instance of the builder.
+     *
+     * @param parent  the parent builder, not null
+     * @param optional  whether the formatter is optional, not null
+     */
+    private DateTimeFormatterBuilder(DateTimeFormatterBuilder parent, boolean optional) {
+        super();
+        this.parent = parent;
+        this.optional = optional;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Changes the parse style to be case sensitive for the remainder of the formatter.
+     * <p>
+     * Parsing can be case sensitive or insensitive - by default it is case sensitive.
+     * This method allows the case sensitivity setting of parsing to be changed.
+     * <p>
+     * Calling this method changes the state of the builder such that all
+     * subsequent builder method calls will parse text in case sensitive mode.
+     * See {@link #parseCaseInsensitive} for the opposite setting.
+     * The parse case sensitive/insensitive methods may be called at any point
+     * in the builder, thus the parser can swap between case parsing modes
+     * multiple times during the parse.
+     * <p>
+     * Since the default is case sensitive, this method should only be used after
+     * a previous call to {@code #parseCaseInsensitive}.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseCaseSensitive() {
+        appendInternal(SettingsParser.SENSITIVE);
+        return this;
+    }
+
+    /**
+     * Changes the parse style to be case insensitive for the remainder of the formatter.
+     * <p>
+     * Parsing can be case sensitive or insensitive - by default it is case sensitive.
+     * This method allows the case sensitivity setting of parsing to be changed.
+     * <p>
+     * Calling this method changes the state of the builder such that all
+     * subsequent builder method calls will parse text in case insensitive mode.
+     * See {@link #parseCaseSensitive()} for the opposite setting.
+     * The parse case sensitive/insensitive methods may be called at any point
+     * in the builder, thus the parser can swap between case parsing modes
+     * multiple times during the parse.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseCaseInsensitive() {
+        appendInternal(SettingsParser.INSENSITIVE);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Changes the parse style to be strict for the remainder of the formatter.
+     * <p>
+     * Parsing can be strict or lenient - by default its strict.
+     * This controls the degree of flexibility in matching the text and sign styles.
+     * <p>
+     * When used, this method changes the parsing to be strict from this point onwards.
+     * As strict is the default, this is normally only needed after calling {@link #parseLenient()}.
+     * The change will remain in force until the end of the formatter that is eventually
+     * constructed or until {@code parseLenient} is called.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseStrict() {
+        appendInternal(SettingsParser.STRICT);
+        return this;
+    }
+
+    /**
+     * Changes the parse style to be lenient for the remainder of the formatter.
+     * Note that case sensitivity is set separately to this method.
+     * <p>
+     * Parsing can be strict or lenient - by default its strict.
+     * This controls the degree of flexibility in matching the text and sign styles.
+     * Applications calling this method should typically also call {@link #parseCaseInsensitive()}.
+     * <p>
+     * When used, this method changes the parsing to be lenient from this point onwards.
+     * The change will remain in force until the end of the formatter that is eventually
+     * constructed or until {@code parseStrict} is called.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseLenient() {
+        appendInternal(SettingsParser.LENIENT);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a default value for a field to the formatter for use in parsing.
+     * <p>
+     * This appends an instruction to the builder to inject a default value
+     * into the parsed result. This is especially useful in conjunction with
+     * optional parts of the formatter.
+     * <p>
+     * For example, consider a formatter that parses the year, followed by
+     * an optional month, with a further optional day-of-month. Using such a
+     * formatter would require the calling code to check whether a full date,
+     * year-month or just a year had been parsed. This method can be used to
+     * default the month and day-of-month to a sensible value, such as the
+     * first of the month, allowing the calling code to always get a date.
+     * <p>
+     * During formatting, this method has no effect.
+     * <p>
+     * During parsing, the current state of the parse is inspected.
+     * If the specified field has no associated value, because it has not been
+     * parsed successfully at that point, then the specified value is injected
+     * into the parse result. Injection is immediate, thus the field-value pair
+     * will be visible to any subsequent elements in the formatter.
+     * As such, this method is normally called at the end of the builder.
+     *
+     * @param field  the field to default the value of, not null
+     * @param value  the value to default the field to
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder parseDefaulting(TemporalField field, long value) {
+        Objects.requireNonNull(field, "field");
+        appendInternal(new DefaultValueParser(field, value));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the value of a date-time field to the formatter using a normal
+     * output style.
+     * <p>
+     * The value of the field will be output during a format.
+     * If the value cannot be obtained then an exception will be thrown.
+     * <p>
+     * The value will be printed as per the normal format of an integer value.
+     * Only negative numbers will be signed. No padding will be added.
+     * <p>
+     * The parser for a variable width value such as this normally behaves greedily,
+     * requiring one digit, but accepting as many digits as possible.
+     * This behavior can be affected by 'adjacent value parsing'.
+     * See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
+     *
+     * @param field  the field to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendValue(TemporalField field) {
+        Objects.requireNonNull(field, "field");
+        appendValue(new NumberPrinterParser(field, 1, 19, SignStyle.NORMAL));
+        return this;
+    }
+
+    /**
+     * Appends the value of a date-time field to the formatter using a fixed
+     * width, zero-padded approach.
+     * <p>
+     * The value of the field will be output during a format.
+     * If the value cannot be obtained then an exception will be thrown.
+     * <p>
+     * The value will be zero-padded on the left. If the size of the value
+     * means that it cannot be printed within the width then an exception is thrown.
+     * If the value of the field is negative then an exception is thrown during formatting.
+     * <p>
+     * This method supports a special technique of parsing known as 'adjacent value parsing'.
+     * This technique solves the problem where a value, variable or fixed width, is followed by one or more
+     * fixed length values. The standard parser is greedy, and thus it would normally
+     * steal the digits that are needed by the fixed width value parsers that follow the
+     * variable width one.
+     * <p>
+     * No action is required to initiate 'adjacent value parsing'.
+     * When a call to {@code appendValue} is made, the builder
+     * enters adjacent value parsing setup mode. If the immediately subsequent method
+     * call or calls on the same builder are for a fixed width value, then the parser will reserve
+     * space so that the fixed width values can be parsed.
+     * <p>
+     * For example, consider {@code builder.appendValue(YEAR).appendValue(MONTH_OF_YEAR, 2);}
+     * The year is a variable width parse of between 1 and 19 digits.
+     * The month is a fixed width parse of 2 digits.
+     * Because these were appended to the same builder immediately after one another,
+     * the year parser will reserve two digits for the month to parse.
+     * Thus, the text '201106' will correctly parse to a year of 2011 and a month of 6.
+     * Without adjacent value parsing, the year would greedily parse all six digits and leave
+     * nothing for the month.
+     * <p>
+     * Adjacent value parsing applies to each set of fixed width not-negative values in the parser
+     * that immediately follow any kind of value, variable or fixed width.
+     * Calling any other append method will end the setup of adjacent value parsing.
+     * Thus, in the unlikely event that you need to avoid adjacent value parsing behavior,
+     * simply add the {@code appendValue} to another {@code DateTimeFormatterBuilder}
+     * and add that to this builder.
+     * <p>
+     * If adjacent parsing is active, then parsing must match exactly the specified
+     * number of digits in both strict and lenient modes.
+     * In addition, no positive or negative sign is permitted.
+     *
+     * @param field  the field to append, not null
+     * @param width  the width of the printed field, from 1 to 19
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the width is invalid
+     */
+    public DateTimeFormatterBuilder appendValue(TemporalField field, int width) {
+        Objects.requireNonNull(field, "field");
+        if (width < 1 || width > 19) {
+            throw new IllegalArgumentException("The width must be from 1 to 19 inclusive but was " + width);
+        }
+        NumberPrinterParser pp = new NumberPrinterParser(field, width, width, SignStyle.NOT_NEGATIVE);
+        appendValue(pp);
+        return this;
+    }
+
+    /**
+     * Appends the value of a date-time field to the formatter providing full
+     * control over formatting.
+     * <p>
+     * The value of the field will be output during a format.
+     * If the value cannot be obtained then an exception will be thrown.
+     * <p>
+     * This method provides full control of the numeric formatting, including
+     * zero-padding and the positive/negative sign.
+     * <p>
+     * The parser for a variable width value such as this normally behaves greedily,
+     * accepting as many digits as possible.
+     * This behavior can be affected by 'adjacent value parsing'.
+     * See {@link #appendValue(java.time.temporal.TemporalField, int)} for full details.
+     * <p>
+     * In strict parsing mode, the minimum number of parsed digits is {@code minWidth}
+     * and the maximum is {@code maxWidth}.
+     * In lenient parsing mode, the minimum number of parsed digits is one
+     * and the maximum is 19 (except as limited by adjacent value parsing).
+     * <p>
+     * If this method is invoked with equal minimum and maximum widths and a sign style of
+     * {@code NOT_NEGATIVE} then it delegates to {@code appendValue(TemporalField,int)}.
+     * In this scenario, the formatting and parsing behavior described there occur.
+     *
+     * @param field  the field to append, not null
+     * @param minWidth  the minimum field width of the printed field, from 1 to 19
+     * @param maxWidth  the maximum field width of the printed field, from 1 to 19
+     * @param signStyle  the positive/negative output style, not null
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the widths are invalid
+     */
+    public DateTimeFormatterBuilder appendValue(
+            TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) {
+        if (minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE) {
+            return appendValue(field, maxWidth);
+        }
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(signStyle, "signStyle");
+        if (minWidth < 1 || minWidth > 19) {
+            throw new IllegalArgumentException("The minimum width must be from 1 to 19 inclusive but was " + minWidth);
+        }
+        if (maxWidth < 1 || maxWidth > 19) {
+            throw new IllegalArgumentException("The maximum width must be from 1 to 19 inclusive but was " + maxWidth);
+        }
+        if (maxWidth < minWidth) {
+            throw new IllegalArgumentException("The maximum width must exceed or equal the minimum width but " +
+                    maxWidth + " < " + minWidth);
+        }
+        NumberPrinterParser pp = new NumberPrinterParser(field, minWidth, maxWidth, signStyle);
+        appendValue(pp);
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the reduced value of a date-time field to the formatter.
+     * <p>
+     * Since fields such as year vary by chronology, it is recommended to use the
+     * {@link #appendValueReduced(TemporalField, int, int, ChronoLocalDate)} date}
+     * variant of this method in most cases. This variant is suitable for
+     * simple fields or working with only the ISO chronology.
+     * <p>
+     * For formatting, the {@code width} and {@code maxWidth} are used to
+     * determine the number of characters to format.
+     * If they are equal then the format is fixed width.
+     * If the value of the field is within the range of the {@code baseValue} using
+     * {@code width} characters then the reduced value is formatted otherwise the value is
+     * truncated to fit {@code maxWidth}.
+     * The rightmost characters are output to match the width, left padding with zero.
+     * <p>
+     * For strict parsing, the number of characters allowed by {@code width} to {@code maxWidth} are parsed.
+     * For lenient parsing, the number of characters must be at least 1 and less than 10.
+     * If the number of digits parsed is equal to {@code width} and the value is positive,
+     * the value of the field is computed to be the first number greater than
+     * or equal to the {@code baseValue} with the same least significant characters,
+     * otherwise the value parsed is the field value.
+     * This allows a reduced value to be entered for values in range of the baseValue
+     * and width and absolute values can be entered for values outside the range.
+     * <p>
+     * For example, a base value of {@code 1980} and a width of {@code 2} will have
+     * valid values from {@code 1980} to {@code 2079}.
+     * During parsing, the text {@code "12"} will result in the value {@code 2012} as that
+     * is the value within the range where the last two characters are "12".
+     * By contrast, parsing the text {@code "1915"} will result in the value {@code 1915}.
+     *
+     * @param field  the field to append, not null
+     * @param width  the field width of the printed and parsed field, from 1 to 10
+     * @param maxWidth  the maximum field width of the printed field, from 1 to 10
+     * @param baseValue  the base value of the range of valid values
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the width or base value is invalid
+     */
+    public DateTimeFormatterBuilder appendValueReduced(TemporalField field,
+            int width, int maxWidth, int baseValue) {
+        Objects.requireNonNull(field, "field");
+        ReducedPrinterParser pp = new ReducedPrinterParser(field, width, maxWidth, baseValue, null);
+        appendValue(pp);
+        return this;
+    }
+
+    /**
+     * Appends the reduced value of a date-time field to the formatter.
+     * <p>
+     * This is typically used for formatting and parsing a two digit year.
+     * <p>
+     * The base date is used to calculate the full value during parsing.
+     * For example, if the base date is 1950-01-01 then parsed values for
+     * a two digit year parse will be in the range 1950-01-01 to 2049-12-31.
+     * Only the year would be extracted from the date, thus a base date of
+     * 1950-08-25 would also parse to the range 1950-01-01 to 2049-12-31.
+     * This behavior is necessary to support fields such as week-based-year
+     * or other calendar systems where the parsed value does not align with
+     * standard ISO years.
+     * <p>
+     * The exact behavior is as follows. Parse the full set of fields and
+     * determine the effective chronology using the last chronology if
+     * it appears more than once. Then convert the base date to the
+     * effective chronology. Then extract the specified field from the
+     * chronology-specific base date and use it to determine the
+     * {@code baseValue} used below.
+     * <p>
+     * For formatting, the {@code width} and {@code maxWidth} are used to
+     * determine the number of characters to format.
+     * If they are equal then the format is fixed width.
+     * If the value of the field is within the range of the {@code baseValue} using
+     * {@code width} characters then the reduced value is formatted otherwise the value is
+     * truncated to fit {@code maxWidth}.
+     * The rightmost characters are output to match the width, left padding with zero.
+     * <p>
+     * For strict parsing, the number of characters allowed by {@code width} to {@code maxWidth} are parsed.
+     * For lenient parsing, the number of characters must be at least 1 and less than 10.
+     * If the number of digits parsed is equal to {@code width} and the value is positive,
+     * the value of the field is computed to be the first number greater than
+     * or equal to the {@code baseValue} with the same least significant characters,
+     * otherwise the value parsed is the field value.
+     * This allows a reduced value to be entered for values in range of the baseValue
+     * and width and absolute values can be entered for values outside the range.
+     * <p>
+     * For example, a base value of {@code 1980} and a width of {@code 2} will have
+     * valid values from {@code 1980} to {@code 2079}.
+     * During parsing, the text {@code "12"} will result in the value {@code 2012} as that
+     * is the value within the range where the last two characters are "12".
+     * By contrast, parsing the text {@code "1915"} will result in the value {@code 1915}.
+     *
+     * @param field  the field to append, not null
+     * @param width  the field width of the printed and parsed field, from 1 to 10
+     * @param maxWidth  the maximum field width of the printed field, from 1 to 10
+     * @param baseDate  the base date used to calculate the base value for the range
+     *  of valid values in the parsed chronology, not null
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the width or base value is invalid
+     */
+    public DateTimeFormatterBuilder appendValueReduced(
+            TemporalField field, int width, int maxWidth, ChronoLocalDate baseDate) {
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(baseDate, "baseDate");
+        ReducedPrinterParser pp = new ReducedPrinterParser(field, width, maxWidth, 0, baseDate);
+        appendValue(pp);
+        return this;
+    }
+
+    /**
+     * Appends a fixed or variable width printer-parser handling adjacent value mode.
+     * If a PrinterParser is not active then the new PrinterParser becomes
+     * the active PrinterParser.
+     * Otherwise, the active PrinterParser is modified depending on the new PrinterParser.
+     * If the new PrinterParser is fixed width and has sign style {@code NOT_NEGATIVE}
+     * then its width is added to the active PP and
+     * the new PrinterParser is forced to be fixed width.
+     * If the new PrinterParser is variable width, the active PrinterParser is changed
+     * to be fixed width and the new PrinterParser becomes the active PP.
+     *
+     * @param pp  the printer-parser, not null
+     * @return this, for chaining, not null
+     */
+    private DateTimeFormatterBuilder appendValue(NumberPrinterParser pp) {
+        if (active.valueParserIndex >= 0) {
+            final int activeValueParser = active.valueParserIndex;
+
+            // adjacent parsing mode, update setting in previous parsers
+            NumberPrinterParser basePP = (NumberPrinterParser) active.printerParsers.get(activeValueParser);
+            if (pp.minWidth == pp.maxWidth && pp.signStyle == SignStyle.NOT_NEGATIVE) {
+                // Append the width to the subsequentWidth of the active parser
+                basePP = basePP.withSubsequentWidth(pp.maxWidth);
+                // Append the new parser as a fixed width
+                appendInternal(pp.withFixedWidth());
+                // Retain the previous active parser
+                active.valueParserIndex = activeValueParser;
+            } else {
+                // Modify the active parser to be fixed width
+                basePP = basePP.withFixedWidth();
+                // The new parser becomes the mew active parser
+                active.valueParserIndex = appendInternal(pp);
+            }
+            // Replace the modified parser with the updated one
+            active.printerParsers.set(activeValueParser, basePP);
+        } else {
+            // The new Parser becomes the active parser
+            active.valueParserIndex = appendInternal(pp);
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the fractional value of a date-time field to the formatter.
+     * <p>
+     * The fractional value of the field will be output including the
+     * preceding decimal point. The preceding value is not output.
+     * For example, the second-of-minute value of 15 would be output as {@code .25}.
+     * <p>
+     * The width of the printed fraction can be controlled. Setting the
+     * minimum width to zero will cause no output to be generated.
+     * The printed fraction will have the minimum width necessary between
+     * the minimum and maximum widths - trailing zeroes are omitted.
+     * No rounding occurs due to the maximum width - digits are simply dropped.
+     * <p>
+     * When parsing in strict mode, the number of parsed digits must be between
+     * the minimum and maximum width. When parsing in lenient mode, the minimum
+     * width is considered to be zero and the maximum is nine.
+     * <p>
+     * If the value cannot be obtained then an exception will be thrown.
+     * If the value is negative an exception will be thrown.
+     * If the field does not have a fixed set of valid values then an
+     * exception will be thrown.
+     * If the field value in the date-time to be printed is invalid it
+     * cannot be printed and an exception will be thrown.
+     *
+     * @param field  the field to append, not null
+     * @param minWidth  the minimum width of the field excluding the decimal point, from 0 to 9
+     * @param maxWidth  the maximum width of the field excluding the decimal point, from 1 to 9
+     * @param decimalPoint  whether to output the localized decimal point symbol
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the field has a variable set of valid values or
+     *  either width is invalid
+     */
+    public DateTimeFormatterBuilder appendFraction(
+            TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
+        appendInternal(new FractionPrinterParser(field, minWidth, maxWidth, decimalPoint));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the text of a date-time field to the formatter using the full
+     * text style.
+     * <p>
+     * The text of the field will be output during a format.
+     * The value must be within the valid range of the field.
+     * If the value cannot be obtained then an exception will be thrown.
+     * If the field has no textual representation, then the numeric value will be used.
+     * <p>
+     * The value will be printed as per the normal format of an integer value.
+     * Only negative numbers will be signed. No padding will be added.
+     *
+     * @param field  the field to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendText(TemporalField field) {
+        return appendText(field, TextStyle.FULL);
+    }
+
+    /**
+     * Appends the text of a date-time field to the formatter.
+     * <p>
+     * The text of the field will be output during a format.
+     * The value must be within the valid range of the field.
+     * If the value cannot be obtained then an exception will be thrown.
+     * If the field has no textual representation, then the numeric value will be used.
+     * <p>
+     * The value will be printed as per the normal format of an integer value.
+     * Only negative numbers will be signed. No padding will be added.
+     *
+     * @param field  the field to append, not null
+     * @param textStyle  the text style to use, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendText(TemporalField field, TextStyle textStyle) {
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(textStyle, "textStyle");
+        appendInternal(new TextPrinterParser(field, textStyle, DateTimeTextProvider.getInstance()));
+        return this;
+    }
+
+    /**
+     * Appends the text of a date-time field to the formatter using the specified
+     * map to supply the text.
+     * <p>
+     * The standard text outputting methods use the localized text in the JDK.
+     * This method allows that text to be specified directly.
+     * The supplied map is not validated by the builder to ensure that formatting or
+     * parsing is possible, thus an invalid map may throw an error during later use.
+     * <p>
+     * Supplying the map of text provides considerable flexibility in formatting and parsing.
+     * For example, a legacy application might require or supply the months of the
+     * year as "JNY", "FBY", "MCH" etc. These do not match the standard set of text
+     * for localized month names. Using this method, a map can be created which
+     * defines the connection between each value and the text:
+     * <pre>
+     * Map&lt;Long, String&gt; map = new HashMap&lt;&gt;();
+     * map.put(1L, "JNY");
+     * map.put(2L, "FBY");
+     * map.put(3L, "MCH");
+     * ...
+     * builder.appendText(MONTH_OF_YEAR, map);
+     * </pre>
+     * <p>
+     * Other uses might be to output the value with a suffix, such as "1st", "2nd", "3rd",
+     * or as Roman numerals "I", "II", "III", "IV".
+     * <p>
+     * During formatting, the value is obtained and checked that it is in the valid range.
+     * If text is not available for the value then it is output as a number.
+     * During parsing, the parser will match against the map of text and numeric values.
+     *
+     * @param field  the field to append, not null
+     * @param textLookup  the map from the value to the text
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendText(TemporalField field, Map<Long, String> textLookup) {
+        Objects.requireNonNull(field, "field");
+        Objects.requireNonNull(textLookup, "textLookup");
+        Map<Long, String> copy = new LinkedHashMap<>(textLookup);
+        Map<TextStyle, Map<Long, String>> map = Collections.singletonMap(TextStyle.FULL, copy);
+        final LocaleStore store = new LocaleStore(map);
+        DateTimeTextProvider provider = new DateTimeTextProvider() {
+            @Override
+            public String getText(TemporalField field, long value, TextStyle style, Locale locale) {
+                return store.getText(value, style);
+            }
+            @Override
+            public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
+                return store.getTextIterator(style);
+            }
+        };
+        appendInternal(new TextPrinterParser(field, TextStyle.FULL, provider));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends an instant using ISO-8601 to the formatter, formatting fractional
+     * digits in groups of three.
+     * <p>
+     * Instants have a fixed output format.
+     * They are converted to a date-time with a zone-offset of UTC and formatted
+     * using the standard ISO-8601 format.
+     * With this method, formatting nano-of-second outputs zero, three, six
+     * or nine digits digits as necessary.
+     * The localized decimal style is not used.
+     * <p>
+     * The instant is obtained using {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
+     * and optionally (@code NANO_OF_SECOND). The value of {@code INSTANT_SECONDS}
+     * may be outside the maximum range of {@code LocalDateTime}.
+     * <p>
+     * The {@linkplain ResolverStyle resolver style} has no effect on instant parsing.
+     * The end-of-day time of '24:00' is handled as midnight at the start of the following day.
+     * The leap-second time of '23:59:59' is handled to some degree, see
+     * {@link DateTimeFormatter#parsedLeapSecond()} for full details.
+     * <p>
+     * An alternative to this method is to format/parse the instant as a single
+     * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendInstant() {
+        appendInternal(new InstantPrinterParser(-2));
+        return this;
+    }
+
+    /**
+     * Appends an instant using ISO-8601 to the formatter with control over
+     * the number of fractional digits.
+     * <p>
+     * Instants have a fixed output format, although this method provides some
+     * control over the fractional digits. They are converted to a date-time
+     * with a zone-offset of UTC and printed using the standard ISO-8601 format.
+     * The localized decimal style is not used.
+     * <p>
+     * The {@code fractionalDigits} parameter allows the output of the fractional
+     * second to be controlled. Specifying zero will cause no fractional digits
+     * to be output. From 1 to 9 will output an increasing number of digits, using
+     * zero right-padding if necessary. The special value -1 is used to output as
+     * many digits as necessary to avoid any trailing zeroes.
+     * <p>
+     * When parsing in strict mode, the number of parsed digits must match the
+     * fractional digits. When parsing in lenient mode, any number of fractional
+     * digits from zero to nine are accepted.
+     * <p>
+     * The instant is obtained using {@link ChronoField#INSTANT_SECONDS INSTANT_SECONDS}
+     * and optionally (@code NANO_OF_SECOND). The value of {@code INSTANT_SECONDS}
+     * may be outside the maximum range of {@code LocalDateTime}.
+     * <p>
+     * The {@linkplain ResolverStyle resolver style} has no effect on instant parsing.
+     * The end-of-day time of '24:00' is handled as midnight at the start of the following day.
+     * The leap-second time of '23:59:60' is handled to some degree, see
+     * {@link DateTimeFormatter#parsedLeapSecond()} for full details.
+     * <p>
+     * An alternative to this method is to format/parse the instant as a single
+     * epoch-seconds value. That is achieved using {@code appendValue(INSTANT_SECONDS)}.
+     *
+     * @param fractionalDigits  the number of fractional second digits to format with,
+     *  from 0 to 9, or -1 to use as many digits as necessary
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendInstant(int fractionalDigits) {
+        if (fractionalDigits < -1 || fractionalDigits > 9) {
+            throw new IllegalArgumentException("The fractional digits must be from -1 to 9 inclusive but was " + fractionalDigits);
+        }
+        appendInternal(new InstantPrinterParser(fractionalDigits));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the zone offset, such as '+01:00', to the formatter.
+     * <p>
+     * This appends an instruction to format/parse the offset ID to the builder.
+     * This is equivalent to calling {@code appendOffset("+HH:MM:ss", "Z")}.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendOffsetId() {
+        appendInternal(OffsetIdPrinterParser.INSTANCE_ID_Z);
+        return this;
+    }
+
+    /**
+     * Appends the zone offset, such as '+01:00', to the formatter.
+     * <p>
+     * This appends an instruction to format/parse the offset ID to the builder.
+     * <p>
+     * During formatting, the offset is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#offset()}.
+     * It will be printed using the format defined below.
+     * If the offset cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, the offset is parsed using the format defined below.
+     * If the offset cannot be parsed then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * The format of the offset is controlled by a pattern which must be one
+     * of the following:
+     * <ul>
+     * <li>{@code +HH} - hour only, ignoring minute and second
+     * <li>{@code +HHmm} - hour, with minute if non-zero, ignoring second, no colon
+     * <li>{@code +HH:mm} - hour, with minute if non-zero, ignoring second, with colon
+     * <li>{@code +HHMM} - hour and minute, ignoring second, no colon
+     * <li>{@code +HH:MM} - hour and minute, ignoring second, with colon
+     * <li>{@code +HHMMss} - hour and minute, with second if non-zero, no colon
+     * <li>{@code +HH:MM:ss} - hour and minute, with second if non-zero, with colon
+     * <li>{@code +HHMMSS} - hour, minute and second, no colon
+     * <li>{@code +HH:MM:SS} - hour, minute and second, with colon
+     * </ul>
+     * The "no offset" text controls what text is printed when the total amount of
+     * the offset fields to be output is zero.
+     * Example values would be 'Z', '+00:00', 'UTC' or 'GMT'.
+     * Three formats are accepted for parsing UTC - the "no offset" text, and the
+     * plus and minus versions of zero defined by the pattern.
+     *
+     * @param pattern  the pattern to use, not null
+     * @param noOffsetText  the text to use when the offset is zero, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendOffset(String pattern, String noOffsetText) {
+        appendInternal(new OffsetIdPrinterParser(pattern, noOffsetText));
+        return this;
+    }
+
+    /**
+     * Appends the localized zone offset, such as 'GMT+01:00', to the formatter.
+     * <p>
+     * This appends a localized zone offset to the builder, the format of the
+     * localized offset is controlled by the specified {@link FormatStyle style}
+     * to this method:
+     * <ul>
+     * <li>{@link TextStyle#FULL full} - formats with localized offset text, such
+     * as 'GMT, 2-digit hour and minute field, optional second field if non-zero,
+     * and colon.
+     * <li>{@link TextStyle#SHORT short} - formats with localized offset text,
+     * such as 'GMT, hour without leading zero, optional 2-digit minute and
+     * second if non-zero, and colon.
+     * </ul>
+     * <p>
+     * During formatting, the offset is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#offset()}.
+     * If the offset cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, the offset is parsed using the format defined above.
+     * If the offset cannot be parsed then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * @param style  the format style to use, not null
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if style is neither {@link TextStyle#FULL
+     * full} nor {@link TextStyle#SHORT short}
+     */
+    public DateTimeFormatterBuilder appendLocalizedOffset(TextStyle style) {
+        Objects.requireNonNull(style, "style");
+        if (style != TextStyle.FULL && style != TextStyle.SHORT) {
+            throw new IllegalArgumentException("Style must be either full or short");
+        }
+        appendInternal(new LocalizedOffsetIdPrinterParser(style));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the time-zone ID, such as 'Europe/Paris' or '+02:00', to the formatter.
+     * <p>
+     * This appends an instruction to format/parse the zone ID to the builder.
+     * The zone ID is obtained in a strict manner suitable for {@code ZonedDateTime}.
+     * By contrast, {@code OffsetDateTime} does not have a zone ID suitable
+     * for use with this method, see {@link #appendZoneOrOffsetId()}.
+     * <p>
+     * During formatting, the zone is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#zoneId()}.
+     * It will be printed using the result of {@link ZoneId#getId()}.
+     * If the zone cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, the text must match a known zone or offset.
+     * There are two types of zone ID, offset-based, such as '+01:30' and
+     * region-based, such as 'Europe/London'. These are parsed differently.
+     * If the parse starts with '+', '-', 'UT', 'UTC' or 'GMT', then the parser
+     * expects an offset-based zone and will not match region-based zones.
+     * The offset ID, such as '+02:30', may be at the start of the parse,
+     * or prefixed by  'UT', 'UTC' or 'GMT'. The offset ID parsing is
+     * equivalent to using {@link #appendOffset(String, String)} using the
+     * arguments 'HH:MM:ss' and the no offset string '0'.
+     * If the parse starts with 'UT', 'UTC' or 'GMT', and the parser cannot
+     * match a following offset ID, then {@link ZoneOffset#UTC} is selected.
+     * In all other cases, the list of known region-based zones is used to
+     * find the longest available match. If no match is found, and the parse
+     * starts with 'Z', then {@code ZoneOffset.UTC} is selected.
+     * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting.
+     * <p>
+     * For example, the following will parse:
+     * <pre>
+     *   "Europe/London"           -- ZoneId.of("Europe/London")
+     *   "Z"                       -- ZoneOffset.UTC
+     *   "UT"                      -- ZoneId.of("UT")
+     *   "UTC"                     -- ZoneId.of("UTC")
+     *   "GMT"                     -- ZoneId.of("GMT")
+     *   "+01:30"                  -- ZoneOffset.of("+01:30")
+     *   "UT+01:30"                -- ZoneOffset.of("+01:30")
+     *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
+     *   "GMT+01:30"               -- ZoneOffset.of("+01:30")
+     * </pre>
+     *
+     * @return this, for chaining, not null
+     * @see #appendZoneRegionId()
+     */
+    public DateTimeFormatterBuilder appendZoneId() {
+        appendInternal(new ZoneIdPrinterParser(TemporalQueries.zoneId(), "ZoneId()"));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone region ID, such as 'Europe/Paris', to the formatter,
+     * rejecting the zone ID if it is a {@code ZoneOffset}.
+     * <p>
+     * This appends an instruction to format/parse the zone ID to the builder
+     * only if it is a region-based ID.
+     * <p>
+     * During formatting, the zone is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#zoneId()}.
+     * If the zone is a {@code ZoneOffset} or it cannot be obtained then
+     * an exception is thrown unless the section of the formatter is optional.
+     * If the zone is not an offset, then the zone will be printed using
+     * the zone ID from {@link ZoneId#getId()}.
+     * <p>
+     * During parsing, the text must match a known zone or offset.
+     * There are two types of zone ID, offset-based, such as '+01:30' and
+     * region-based, such as 'Europe/London'. These are parsed differently.
+     * If the parse starts with '+', '-', 'UT', 'UTC' or 'GMT', then the parser
+     * expects an offset-based zone and will not match region-based zones.
+     * The offset ID, such as '+02:30', may be at the start of the parse,
+     * or prefixed by  'UT', 'UTC' or 'GMT'. The offset ID parsing is
+     * equivalent to using {@link #appendOffset(String, String)} using the
+     * arguments 'HH:MM:ss' and the no offset string '0'.
+     * If the parse starts with 'UT', 'UTC' or 'GMT', and the parser cannot
+     * match a following offset ID, then {@link ZoneOffset#UTC} is selected.
+     * In all other cases, the list of known region-based zones is used to
+     * find the longest available match. If no match is found, and the parse
+     * starts with 'Z', then {@code ZoneOffset.UTC} is selected.
+     * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting.
+     * <p>
+     * For example, the following will parse:
+     * <pre>
+     *   "Europe/London"           -- ZoneId.of("Europe/London")
+     *   "Z"                       -- ZoneOffset.UTC
+     *   "UT"                      -- ZoneId.of("UT")
+     *   "UTC"                     -- ZoneId.of("UTC")
+     *   "GMT"                     -- ZoneId.of("GMT")
+     *   "+01:30"                  -- ZoneOffset.of("+01:30")
+     *   "UT+01:30"                -- ZoneOffset.of("+01:30")
+     *   "UTC+01:30"               -- ZoneOffset.of("+01:30")
+     *   "GMT+01:30"               -- ZoneOffset.of("+01:30")
+     * </pre>
+     * <p>
+     * Note that this method is identical to {@code appendZoneId()} except
+     * in the mechanism used to obtain the zone.
+     * Note also that parsing accepts offsets, whereas formatting will never
+     * produce one.
+     *
+     * @return this, for chaining, not null
+     * @see #appendZoneId()
+     */
+    public DateTimeFormatterBuilder appendZoneRegionId() {
+        appendInternal(new ZoneIdPrinterParser(QUERY_REGION_ONLY, "ZoneRegionId()"));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone ID, such as 'Europe/Paris' or '+02:00', to
+     * the formatter, using the best available zone ID.
+     * <p>
+     * This appends an instruction to format/parse the best available
+     * zone or offset ID to the builder.
+     * The zone ID is obtained in a lenient manner that first attempts to
+     * find a true zone ID, such as that on {@code ZonedDateTime}, and
+     * then attempts to find an offset, such as that on {@code OffsetDateTime}.
+     * <p>
+     * During formatting, the zone is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#zone()}.
+     * It will be printed using the result of {@link ZoneId#getId()}.
+     * If the zone cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, the text must match a known zone or offset.
+     * There are two types of zone ID, offset-based, such as '+01:30' and
+     * region-based, such as 'Europe/London'. These are parsed differently.
+     * If the parse starts with '+', '-', 'UT', 'UTC' or 'GMT', then the parser
+     * expects an offset-based zone and will not match region-based zones.
+     * The offset ID, such as '+02:30', may be at the start of the parse,
+     * or prefixed by  'UT', 'UTC' or 'GMT'. The offset ID parsing is
+     * equivalent to using {@link #appendOffset(String, String)} using the
+     * arguments 'HH:MM:ss' and the no offset string '0'.
+     * If the parse starts with 'UT', 'UTC' or 'GMT', and the parser cannot
+     * match a following offset ID, then {@link ZoneOffset#UTC} is selected.
+     * In all other cases, the list of known region-based zones is used to
+     * find the longest available match. If no match is found, and the parse
+     * starts with 'Z', then {@code ZoneOffset.UTC} is selected.
+     * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting.
+     * <p>
+     * For example, the following will parse:
+     * <pre>
+     *   "Europe/London"           -- ZoneId.of("Europe/London")
+     *   "Z"                       -- ZoneOffset.UTC
+     *   "UT"                      -- ZoneId.of("UT")
+     *   "UTC"                     -- ZoneId.of("UTC")
+     *   "GMT"                     -- ZoneId.of("GMT")
+     *   "+01:30"                  -- ZoneOffset.of("+01:30")
+     *   "UT+01:30"                -- ZoneOffset.of("UT+01:30")
+     *   "UTC+01:30"               -- ZoneOffset.of("UTC+01:30")
+     *   "GMT+01:30"               -- ZoneOffset.of("GMT+01:30")
+     * </pre>
+     * <p>
+     * Note that this method is identical to {@code appendZoneId()} except
+     * in the mechanism used to obtain the zone.
+     *
+     * @return this, for chaining, not null
+     * @see #appendZoneId()
+     */
+    public DateTimeFormatterBuilder appendZoneOrOffsetId() {
+        appendInternal(new ZoneIdPrinterParser(TemporalQueries.zone(), "ZoneOrOffsetId()"));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone name, such as 'British Summer Time', to the formatter.
+     * <p>
+     * This appends an instruction to format/parse the textual name of the zone to
+     * the builder.
+     * <p>
+     * During formatting, the zone is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#zoneId()}.
+     * If the zone is a {@code ZoneOffset} it will be printed using the
+     * result of {@link ZoneOffset#getId()}.
+     * If the zone is not an offset, the textual name will be looked up
+     * for the locale set in the {@link DateTimeFormatter}.
+     * If the temporal object being printed represents an instant, then the text
+     * will be the summer or winter time text as appropriate.
+     * If the lookup for text does not find any suitable result, then the
+     * {@link ZoneId#getId() ID} will be printed instead.
+     * If the zone cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, either the textual zone name, the zone ID or the offset
+     * is accepted. Many textual zone names are not unique, such as CST can be
+     * for both "Central Standard Time" and "China Standard Time". In this
+     * situation, the zone id will be determined by the region information from
+     * formatter's  {@link DateTimeFormatter#getLocale() locale} and the standard
+     * zone id for that area, for example, America/New_York for the America Eastern
+     * zone. The {@link #appendZoneText(TextStyle, Set)} may be used
+     * to specify a set of preferred {@link ZoneId} in this situation.
+     *
+     * @param textStyle  the text style to use, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendZoneText(TextStyle textStyle) {
+        appendInternal(new ZoneTextPrinterParser(textStyle, null));
+        return this;
+    }
+
+    /**
+     * Appends the time-zone name, such as 'British Summer Time', to the formatter.
+     * <p>
+     * This appends an instruction to format/parse the textual name of the zone to
+     * the builder.
+     * <p>
+     * During formatting, the zone is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#zoneId()}.
+     * If the zone is a {@code ZoneOffset} it will be printed using the
+     * result of {@link ZoneOffset#getId()}.
+     * If the zone is not an offset, the textual name will be looked up
+     * for the locale set in the {@link DateTimeFormatter}.
+     * If the temporal object being printed represents an instant, then the text
+     * will be the summer or winter time text as appropriate.
+     * If the lookup for text does not find any suitable result, then the
+     * {@link ZoneId#getId() ID} will be printed instead.
+     * If the zone cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, either the textual zone name, the zone ID or the offset
+     * is accepted. Many textual zone names are not unique, such as CST can be
+     * for both "Central Standard Time" and "China Standard Time". In this
+     * situation, the zone id will be determined by the region information from
+     * formatter's  {@link DateTimeFormatter#getLocale() locale} and the standard
+     * zone id for that area, for example, America/New_York for the America Eastern
+     * zone. This method also allows a set of preferred {@link ZoneId} to be
+     * specified for parsing. The matched preferred zone id will be used if the
+     * textural zone name being parsed is not unique.
+     * <p>
+     * If the zone cannot be parsed then an exception is thrown unless the
+     * section of the formatter is optional.
+     *
+     * @param textStyle  the text style to use, not null
+     * @param preferredZones  the set of preferred zone ids, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendZoneText(TextStyle textStyle,
+                                                   Set<ZoneId> preferredZones) {
+        Objects.requireNonNull(preferredZones, "preferredZones");
+        appendInternal(new ZoneTextPrinterParser(textStyle, preferredZones));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the chronology ID, such as 'ISO' or 'ThaiBuddhist', to the formatter.
+     * <p>
+     * This appends an instruction to format/parse the chronology ID to the builder.
+     * <p>
+     * During formatting, the chronology is obtained using a mechanism equivalent
+     * to querying the temporal with {@link TemporalQueries#chronology()}.
+     * It will be printed using the result of {@link Chronology#getId()}.
+     * If the chronology cannot be obtained then an exception is thrown unless the
+     * section of the formatter is optional.
+     * <p>
+     * During parsing, the chronology is parsed and must match one of the chronologies
+     * in {@link Chronology#getAvailableChronologies()}.
+     * If the chronology cannot be parsed then an exception is thrown unless the
+     * section of the formatter is optional.
+     * The parser uses the {@linkplain #parseCaseInsensitive() case sensitive} setting.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendChronologyId() {
+        appendInternal(new ChronoPrinterParser(null));
+        return this;
+    }
+
+    /**
+     * Appends the chronology name to the formatter.
+     * <p>
+     * The calendar system name will be output during a format.
+     * If the chronology cannot be obtained then an exception will be thrown.
+     *
+     * @param textStyle  the text style to use, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendChronologyText(TextStyle textStyle) {
+        Objects.requireNonNull(textStyle, "textStyle");
+        appendInternal(new ChronoPrinterParser(textStyle));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a localized date-time pattern to the formatter.
+     * <p>
+     * This appends a localized section to the builder, suitable for outputting
+     * a date, time or date-time combination. The format of the localized
+     * section is lazily looked up based on four items:
+     * <ul>
+     * <li>the {@code dateStyle} specified to this method
+     * <li>the {@code timeStyle} specified to this method
+     * <li>the {@code Locale} of the {@code DateTimeFormatter}
+     * <li>the {@code Chronology}, selecting the best available
+     * </ul>
+     * During formatting, the chronology is obtained from the temporal object
+     * being formatted, which may have been overridden by
+     * {@link DateTimeFormatter#withChronology(Chronology)}.
+     * <p>
+     * During parsing, if a chronology has already been parsed, then it is used.
+     * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)}
+     * is used, with {@code IsoChronology} as the fallback.
+     * <p>
+     * Note that this method provides similar functionality to methods on
+     * {@code DateFormat} such as {@link java.text.DateFormat#getDateTimeInstance(int, int)}.
+     *
+     * @param dateStyle  the date style to use, null means no date required
+     * @param timeStyle  the time style to use, null means no time required
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if both the date and time styles are null
+     */
+    public DateTimeFormatterBuilder appendLocalized(FormatStyle dateStyle, FormatStyle timeStyle) {
+        if (dateStyle == null && timeStyle == null) {
+            throw new IllegalArgumentException("Either the date or time style must be non-null");
+        }
+        appendInternal(new LocalizedPrinterParser(dateStyle, timeStyle));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a character literal to the formatter.
+     * <p>
+     * This character will be output during a format.
+     *
+     * @param literal  the literal to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendLiteral(char literal) {
+        appendInternal(new CharLiteralPrinterParser(literal));
+        return this;
+    }
+
+    /**
+     * Appends a string literal to the formatter.
+     * <p>
+     * This string will be output during a format.
+     * <p>
+     * If the literal is empty, nothing is added to the formatter.
+     *
+     * @param literal  the literal to append, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendLiteral(String literal) {
+        Objects.requireNonNull(literal, "literal");
+        if (literal.length() > 0) {
+            if (literal.length() == 1) {
+                appendInternal(new CharLiteralPrinterParser(literal.charAt(0)));
+            } else {
+                appendInternal(new StringLiteralPrinterParser(literal));
+            }
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends all the elements of a formatter to the builder.
+     * <p>
+     * This method has the same effect as appending each of the constituent
+     * parts of the formatter directly to this builder.
+     *
+     * @param formatter  the formatter to add, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder append(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        appendInternal(formatter.toPrinterParser(false));
+        return this;
+    }
+
+    /**
+     * Appends a formatter to the builder which will optionally format/parse.
+     * <p>
+     * This method has the same effect as appending each of the constituent
+     * parts directly to this builder surrounded by an {@link #optionalStart()} and
+     * {@link #optionalEnd()}.
+     * <p>
+     * The formatter will format if data is available for all the fields contained within it.
+     * The formatter will parse if the string matches, otherwise no error is returned.
+     *
+     * @param formatter  the formatter to add, not null
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder appendOptional(DateTimeFormatter formatter) {
+        Objects.requireNonNull(formatter, "formatter");
+        appendInternal(formatter.toPrinterParser(true));
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends the elements defined by the specified pattern to the builder.
+     * <p>
+     * All letters 'A' to 'Z' and 'a' to 'z' are reserved as pattern letters.
+     * The characters '#', '{' and '}' are reserved for future use.
+     * The characters '[' and ']' indicate optional patterns.
+     * The following pattern letters are defined:
+     * <pre>
+     *  Symbol  Meaning                     Presentation      Examples
+     *  ------  -------                     ------------      -------
+     *   G       era                         text              AD; Anno Domini; A
+     *   u       year                        year              2004; 04
+     *   y       year-of-era                 year              2004; 04
+     *   D       day-of-year                 number            189
+     *   M/L     month-of-year               number/text       7; 07; Jul; July; J
+     *   d       day-of-month                number            10
+     *
+     *   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
+     *   Y       week-based-year             year              1996; 96
+     *   w       week-of-week-based-year     number            27
+     *   W       week-of-month               number            4
+     *   E       day-of-week                 text              Tue; Tuesday; T
+     *   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
+     *   F       week-of-month               number            3
+     *
+     *   a       am-pm-of-day                text              PM
+     *   h       clock-hour-of-am-pm (1-12)  number            12
+     *   K       hour-of-am-pm (0-11)        number            0
+     *   k       clock-hour-of-am-pm (1-24)  number            0
+     *
+     *   H       hour-of-day (0-23)          number            0
+     *   m       minute-of-hour              number            30
+     *   s       second-of-minute            number            55
+     *   S       fraction-of-second          fraction          978
+     *   A       milli-of-day                number            1234
+     *   n       nano-of-second              number            987654321
+     *   N       nano-of-day                 number            1234000000
+     *
+     *   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
+     *   z       time-zone name              zone-name         Pacific Standard Time; PST
+     *   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
+     *   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
+     *   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
+     *   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;
+     *
+     *   p       pad next                    pad modifier      1
+     *
+     *   '       escape for text             delimiter
+     *   ''      single quote                literal           '
+     *   [       optional section start
+     *   ]       optional section end
+     *   #       reserved for future use
+     *   {       reserved for future use
+     *   }       reserved for future use
+     * </pre>
+     * <p>
+     * The count of pattern letters determine the format.
+     * See <a href="DateTimeFormatter.html#patterns">DateTimeFormatter</a> for a user-focused description of the patterns.
+     * The following tables define how the pattern letters map to the builder.
+     * <p>
+     * <b>Date fields</b>: Pattern letters to output a date.
+     * <pre>
+     *  Pattern  Count  Equivalent builder methods
+     *  -------  -----  --------------------------
+     *    G       1      appendText(ChronoField.ERA, TextStyle.SHORT)
+     *    GG      2      appendText(ChronoField.ERA, TextStyle.SHORT)
+     *    GGG     3      appendText(ChronoField.ERA, TextStyle.SHORT)
+     *    GGGG    4      appendText(ChronoField.ERA, TextStyle.FULL)
+     *    GGGGG   5      appendText(ChronoField.ERA, TextStyle.NARROW)
+     *
+     *    u       1      appendValue(ChronoField.YEAR, 1, 19, SignStyle.NORMAL);
+     *    uu      2      appendValueReduced(ChronoField.YEAR, 2, 2000);
+     *    uuu     3      appendValue(ChronoField.YEAR, 3, 19, SignStyle.NORMAL);
+     *    u..u    4..n   appendValue(ChronoField.YEAR, n, 19, SignStyle.EXCEEDS_PAD);
+     *    y       1      appendValue(ChronoField.YEAR_OF_ERA, 1, 19, SignStyle.NORMAL);
+     *    yy      2      appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000);
+     *    yyy     3      appendValue(ChronoField.YEAR_OF_ERA, 3, 19, SignStyle.NORMAL);
+     *    y..y    4..n   appendValue(ChronoField.YEAR_OF_ERA, n, 19, SignStyle.EXCEEDS_PAD);
+     *    Y       1      append special localized WeekFields element for numeric week-based-year
+     *    YY      2      append special localized WeekFields element for reduced numeric week-based-year 2 digits;
+     *    YYY     3      append special localized WeekFields element for numeric week-based-year (3, 19, SignStyle.NORMAL);
+     *    Y..Y    4..n   append special localized WeekFields element for numeric week-based-year (n, 19, SignStyle.EXCEEDS_PAD);
+     *
+     *    Q       1      appendValue(IsoFields.QUARTER_OF_YEAR);
+     *    QQ      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2);
+     *    QQQ     3      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.SHORT)
+     *    QQQQ    4      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.FULL)
+     *    QQQQQ   5      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.NARROW)
+     *    q       1      appendValue(IsoFields.QUARTER_OF_YEAR);
+     *    qq      2      appendValue(IsoFields.QUARTER_OF_YEAR, 2);
+     *    qqq     3      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.SHORT_STANDALONE)
+     *    qqqq    4      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.FULL_STANDALONE)
+     *    qqqqq   5      appendText(IsoFields.QUARTER_OF_YEAR, TextStyle.NARROW_STANDALONE)
+     *
+     *    M       1      appendValue(ChronoField.MONTH_OF_YEAR);
+     *    MM      2      appendValue(ChronoField.MONTH_OF_YEAR, 2);
+     *    MMM     3      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT)
+     *    MMMM    4      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
+     *    MMMMM   5      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.NARROW)
+     *    L       1      appendValue(ChronoField.MONTH_OF_YEAR);
+     *    LL      2      appendValue(ChronoField.MONTH_OF_YEAR, 2);
+     *    LLL     3      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT_STANDALONE)
+     *    LLLL    4      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL_STANDALONE)
+     *    LLLLL   5      appendText(ChronoField.MONTH_OF_YEAR, TextStyle.NARROW_STANDALONE)
+     *
+     *    w       1      append special localized WeekFields element for numeric week-of-year
+     *    ww      2      append special localized WeekFields element for numeric week-of-year, zero-padded
+     *    W       1      append special localized WeekFields element for numeric week-of-month
+     *    d       1      appendValue(ChronoField.DAY_OF_MONTH)
+     *    dd      2      appendValue(ChronoField.DAY_OF_MONTH, 2)
+     *    D       1      appendValue(ChronoField.DAY_OF_YEAR)
+     *    DD      2      appendValue(ChronoField.DAY_OF_YEAR, 2)
+     *    DDD     3      appendValue(ChronoField.DAY_OF_YEAR, 3)
+     *    F       1      appendValue(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH)
+     *    E       1      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
+     *    EE      2      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
+     *    EEE     3      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
+     *    EEEE    4      appendText(ChronoField.DAY_OF_WEEK, TextStyle.FULL)
+     *    EEEEE   5      appendText(ChronoField.DAY_OF_WEEK, TextStyle.NARROW)
+     *    e       1      append special localized WeekFields element for numeric day-of-week
+     *    ee      2      append special localized WeekFields element for numeric day-of-week, zero-padded
+     *    eee     3      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT)
+     *    eeee    4      appendText(ChronoField.DAY_OF_WEEK, TextStyle.FULL)
+     *    eeeee   5      appendText(ChronoField.DAY_OF_WEEK, TextStyle.NARROW)
+     *    c       1      append special localized WeekFields element for numeric day-of-week
+     *    ccc     3      appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT_STANDALONE)
+     *    cccc    4      appendText(ChronoField.DAY_OF_WEEK, TextStyle.FULL_STANDALONE)
+     *    ccccc   5      appendText(ChronoField.DAY_OF_WEEK, TextStyle.NARROW_STANDALONE)
+     * </pre>
+     * <p>
+     * <b>Time fields</b>: Pattern letters to output a time.
+     * <pre>
+     *  Pattern  Count  Equivalent builder methods
+     *  -------  -----  --------------------------
+     *    a       1      appendText(ChronoField.AMPM_OF_DAY, TextStyle.SHORT)
+     *    h       1      appendValue(ChronoField.CLOCK_HOUR_OF_AMPM)
+     *    hh      2      appendValue(ChronoField.CLOCK_HOUR_OF_AMPM, 2)
+     *    H       1      appendValue(ChronoField.HOUR_OF_DAY)
+     *    HH      2      appendValue(ChronoField.HOUR_OF_DAY, 2)
+     *    k       1      appendValue(ChronoField.CLOCK_HOUR_OF_DAY)
+     *    kk      2      appendValue(ChronoField.CLOCK_HOUR_OF_DAY, 2)
+     *    K       1      appendValue(ChronoField.HOUR_OF_AMPM)
+     *    KK      2      appendValue(ChronoField.HOUR_OF_AMPM, 2)
+     *    m       1      appendValue(ChronoField.MINUTE_OF_HOUR)
+     *    mm      2      appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+     *    s       1      appendValue(ChronoField.SECOND_OF_MINUTE)
+     *    ss      2      appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+     *
+     *    S..S    1..n   appendFraction(ChronoField.NANO_OF_SECOND, n, n, false)
+     *    A       1      appendValue(ChronoField.MILLI_OF_DAY)
+     *    A..A    2..n   appendValue(ChronoField.MILLI_OF_DAY, n)
+     *    n       1      appendValue(ChronoField.NANO_OF_SECOND)
+     *    n..n    2..n   appendValue(ChronoField.NANO_OF_SECOND, n)
+     *    N       1      appendValue(ChronoField.NANO_OF_DAY)
+     *    N..N    2..n   appendValue(ChronoField.NANO_OF_DAY, n)
+     * </pre>
+     * <p>
+     * <b>Zone ID</b>: Pattern letters to output {@code ZoneId}.
+     * <pre>
+     *  Pattern  Count  Equivalent builder methods
+     *  -------  -----  --------------------------
+     *    VV      2      appendZoneId()
+     *    z       1      appendZoneText(TextStyle.SHORT)
+     *    zz      2      appendZoneText(TextStyle.SHORT)
+     *    zzz     3      appendZoneText(TextStyle.SHORT)
+     *    zzzz    4      appendZoneText(TextStyle.FULL)
+     * </pre>
+     * <p>
+     * <b>Zone offset</b>: Pattern letters to output {@code ZoneOffset}.
+     * <pre>
+     *  Pattern  Count  Equivalent builder methods
+     *  -------  -----  --------------------------
+     *    O       1      appendLocalizedOffsetPrefixed(TextStyle.SHORT);
+     *    OOOO    4      appendLocalizedOffsetPrefixed(TextStyle.FULL);
+     *    X       1      appendOffset("+HHmm","Z")
+     *    XX      2      appendOffset("+HHMM","Z")
+     *    XXX     3      appendOffset("+HH:MM","Z")
+     *    XXXX    4      appendOffset("+HHMMss","Z")
+     *    XXXXX   5      appendOffset("+HH:MM:ss","Z")
+     *    x       1      appendOffset("+HHmm","+00")
+     *    xx      2      appendOffset("+HHMM","+0000")
+     *    xxx     3      appendOffset("+HH:MM","+00:00")
+     *    xxxx    4      appendOffset("+HHMMss","+0000")
+     *    xxxxx   5      appendOffset("+HH:MM:ss","+00:00")
+     *    Z       1      appendOffset("+HHMM","+0000")
+     *    ZZ      2      appendOffset("+HHMM","+0000")
+     *    ZZZ     3      appendOffset("+HHMM","+0000")
+     *    ZZZZ    4      appendLocalizedOffset(TextStyle.FULL);
+     *    ZZZZZ   5      appendOffset("+HH:MM:ss","Z")
+     * </pre>
+     * <p>
+     * <b>Modifiers</b>: Pattern letters that modify the rest of the pattern:
+     * <pre>
+     *  Pattern  Count  Equivalent builder methods
+     *  -------  -----  --------------------------
+     *    [       1      optionalStart()
+     *    ]       1      optionalEnd()
+     *    p..p    1..n   padNext(n)
+     * </pre>
+     * <p>
+     * Any sequence of letters not specified above, unrecognized letter or
+     * reserved character will throw an exception.
+     * Future versions may add to the set of patterns.
+     * It is recommended to use single quotes around all characters that you want
+     * to output directly to ensure that future changes do not break your application.
+     * <p>
+     * Note that the pattern string is similar, but not identical, to
+     * {@link java.text.SimpleDateFormat SimpleDateFormat}.
+     * The pattern string is also similar, but not identical, to that defined by the
+     * Unicode Common Locale Data Repository (CLDR/LDML).
+     * Pattern letters 'X' and 'u' are aligned with Unicode CLDR/LDML.
+     * By contrast, {@code SimpleDateFormat} uses 'u' for the numeric day of week.
+     * Pattern letters 'y' and 'Y' parse years of two digits and more than 4 digits differently.
+     * Pattern letters 'n', 'A', 'N', and 'p' are added.
+     * Number types will reject large numbers.
+     *
+     * @param pattern  the pattern to add, not null
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if the pattern is invalid
+     */
+    public DateTimeFormatterBuilder appendPattern(String pattern) {
+        Objects.requireNonNull(pattern, "pattern");
+        parsePattern(pattern);
+        return this;
+    }
+
+    private void parsePattern(String pattern) {
+        for (int pos = 0; pos < pattern.length(); pos++) {
+            char cur = pattern.charAt(pos);
+            if ((cur >= 'A' && cur <= 'Z') || (cur >= 'a' && cur <= 'z')) {
+                int start = pos++;
+                for ( ; pos < pattern.length() && pattern.charAt(pos) == cur; pos++);  // short loop
+                int count = pos - start;
+                // padding
+                if (cur == 'p') {
+                    int pad = 0;
+                    if (pos < pattern.length()) {
+                        cur = pattern.charAt(pos);
+                        if ((cur >= 'A' && cur <= 'Z') || (cur >= 'a' && cur <= 'z')) {
+                            pad = count;
+                            start = pos++;
+                            for ( ; pos < pattern.length() && pattern.charAt(pos) == cur; pos++);  // short loop
+                            count = pos - start;
+                        }
+                    }
+                    if (pad == 0) {
+                        throw new IllegalArgumentException(
+                                "Pad letter 'p' must be followed by valid pad pattern: " + pattern);
+                    }
+                    padNext(pad); // pad and continue parsing
+                }
+                // main rules
+                TemporalField field = FIELD_MAP.get(cur);
+                if (field != null) {
+                    parseField(cur, count, field);
+                } else if (cur == 'z') {
+                    if (count > 4) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    } else if (count == 4) {
+                        appendZoneText(TextStyle.FULL);
+                    } else {
+                        appendZoneText(TextStyle.SHORT);
+                    }
+                } else if (cur == 'V') {
+                    if (count != 2) {
+                        throw new IllegalArgumentException("Pattern letter count must be 2: " + cur);
+                    }
+                    appendZoneId();
+                } else if (cur == 'Z') {
+                    if (count < 4) {
+                        appendOffset("+HHMM", "+0000");
+                    } else if (count == 4) {
+                        appendLocalizedOffset(TextStyle.FULL);
+                    } else if (count == 5) {
+                        appendOffset("+HH:MM:ss","Z");
+                    } else {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                } else if (cur == 'O') {
+                    if (count == 1) {
+                        appendLocalizedOffset(TextStyle.SHORT);
+                    } else if (count == 4) {
+                        appendLocalizedOffset(TextStyle.FULL);
+                    } else {
+                        throw new IllegalArgumentException("Pattern letter count must be 1 or 4: " + cur);
+                    }
+                } else if (cur == 'X') {
+                    if (count > 5) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    appendOffset(OffsetIdPrinterParser.PATTERNS[count + (count == 1 ? 0 : 1)], "Z");
+                } else if (cur == 'x') {
+                    if (count > 5) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    String zero = (count == 1 ? "+00" : (count % 2 == 0 ? "+0000" : "+00:00"));
+                    appendOffset(OffsetIdPrinterParser.PATTERNS[count + (count == 1 ? 0 : 1)], zero);
+                } else if (cur == 'W') {
+                    // Fields defined by Locale
+                    if (count > 1) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    appendInternal(new WeekBasedFieldPrinterParser(cur, count));
+                } else if (cur == 'w') {
+                    // Fields defined by Locale
+                    if (count > 2) {
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                    }
+                    appendInternal(new WeekBasedFieldPrinterParser(cur, count));
+                } else if (cur == 'Y') {
+                    // Fields defined by Locale
+                    appendInternal(new WeekBasedFieldPrinterParser(cur, count));
+                } else {
+                    throw new IllegalArgumentException("Unknown pattern letter: " + cur);
+                }
+                pos--;
+
+            } else if (cur == '\'') {
+                // parse literals
+                int start = pos++;
+                for ( ; pos < pattern.length(); pos++) {
+                    if (pattern.charAt(pos) == '\'') {
+                        if (pos + 1 < pattern.length() && pattern.charAt(pos + 1) == '\'') {
+                            pos++;
+                        } else {
+                            break;  // end of literal
+                        }
+                    }
+                }
+                if (pos >= pattern.length()) {
+                    throw new IllegalArgumentException("Pattern ends with an incomplete string literal: " + pattern);
+                }
+                String str = pattern.substring(start + 1, pos);
+                if (str.length() == 0) {
+                    appendLiteral('\'');
+                } else {
+                    appendLiteral(str.replace("''", "'"));
+                }
+
+            } else if (cur == '[') {
+                optionalStart();
+
+            } else if (cur == ']') {
+                if (active.parent == null) {
+                    throw new IllegalArgumentException("Pattern invalid as it contains ] without previous [");
+                }
+                optionalEnd();
+
+            } else if (cur == '{' || cur == '}' || cur == '#') {
+                throw new IllegalArgumentException("Pattern includes reserved character: '" + cur + "'");
+            } else {
+                appendLiteral(cur);
+            }
+        }
+    }
+
+    @SuppressWarnings("fallthrough")
+    private void parseField(char cur, int count, TemporalField field) {
+        boolean standalone = false;
+        switch (cur) {
+            case 'u':
+            case 'y':
+                if (count == 2) {
+                    appendValueReduced(field, 2, 2, ReducedPrinterParser.BASE_DATE);
+                } else if (count < 4) {
+                    appendValue(field, count, 19, SignStyle.NORMAL);
+                } else {
+                    appendValue(field, count, 19, SignStyle.EXCEEDS_PAD);
+                }
+                break;
+            case 'c':
+                if (count == 2) {
+                    throw new IllegalArgumentException("Invalid pattern \"cc\"");
+                }
+                /*fallthrough*/
+            case 'L':
+            case 'q':
+                standalone = true;
+                /*fallthrough*/
+            case 'M':
+            case 'Q':
+            case 'E':
+            case 'e':
+                switch (count) {
+                    case 1:
+                    case 2:
+                        if (cur == 'c' || cur == 'e') {
+                            appendInternal(new WeekBasedFieldPrinterParser(cur, count));
+                        } else if (cur == 'E') {
+                            appendText(field, TextStyle.SHORT);
+                        } else {
+                            if (count == 1) {
+                                appendValue(field);
+                            } else {
+                                appendValue(field, 2);
+                            }
+                        }
+                        break;
+                    case 3:
+                        appendText(field, standalone ? TextStyle.SHORT_STANDALONE : TextStyle.SHORT);
+                        break;
+                    case 4:
+                        appendText(field, standalone ? TextStyle.FULL_STANDALONE : TextStyle.FULL);
+                        break;
+                    case 5:
+                        appendText(field, standalone ? TextStyle.NARROW_STANDALONE : TextStyle.NARROW);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'a':
+                if (count == 1) {
+                    appendText(field, TextStyle.SHORT);
+                } else {
+                    throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'G':
+                switch (count) {
+                    case 1:
+                    case 2:
+                    case 3:
+                        appendText(field, TextStyle.SHORT);
+                        break;
+                    case 4:
+                        appendText(field, TextStyle.FULL);
+                        break;
+                    case 5:
+                        appendText(field, TextStyle.NARROW);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'S':
+                appendFraction(NANO_OF_SECOND, count, count, false);
+                break;
+            case 'F':
+                if (count == 1) {
+                    appendValue(field);
+                } else {
+                    throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'd':
+            case 'h':
+            case 'H':
+            case 'k':
+            case 'K':
+            case 'm':
+            case 's':
+                if (count == 1) {
+                    appendValue(field);
+                } else if (count == 2) {
+                    appendValue(field, count);
+                } else {
+                    throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            case 'D':
+                if (count == 1) {
+                    appendValue(field);
+                } else if (count <= 3) {
+                    appendValue(field, count);
+                } else {
+                    throw new IllegalArgumentException("Too many pattern letters: " + cur);
+                }
+                break;
+            default:
+                if (count == 1) {
+                    appendValue(field);
+                } else {
+                    appendValue(field, count);
+                }
+                break;
+        }
+    }
+
+    /** Map of letters to fields. */
+    private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>();
+    static {
+        // SDF = SimpleDateFormat
+        FIELD_MAP.put('G', ChronoField.ERA);                       // SDF, LDML (different to both for 1/2 chars)
+        FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA);               // SDF, LDML
+        FIELD_MAP.put('u', ChronoField.YEAR);                      // LDML (different in SDF)
+        FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR);             // LDML (removed quarter from 310)
+        FIELD_MAP.put('q', IsoFields.QUARTER_OF_YEAR);             // LDML (stand-alone)
+        FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR);             // SDF, LDML
+        FIELD_MAP.put('L', ChronoField.MONTH_OF_YEAR);             // SDF, LDML (stand-alone)
+        FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR);               // SDF, LDML
+        FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH);              // SDF, LDML
+        FIELD_MAP.put('F', ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH);  // SDF, LDML
+        FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK);               // SDF, LDML (different to both for 1/2 chars)
+        FIELD_MAP.put('c', ChronoField.DAY_OF_WEEK);               // LDML (stand-alone)
+        FIELD_MAP.put('e', ChronoField.DAY_OF_WEEK);               // LDML (needs localized week number)
+        FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY);               // SDF, LDML
+        FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY);               // SDF, LDML
+        FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY);         // SDF, LDML
+        FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM);              // SDF, LDML
+        FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM);        // SDF, LDML
+        FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR);            // SDF, LDML
+        FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE);          // SDF, LDML
+        FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND);            // LDML (SDF uses milli-of-second number)
+        FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY);              // LDML
+        FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND);            // 310 (proposed for LDML)
+        FIELD_MAP.put('N', ChronoField.NANO_OF_DAY);               // 310 (proposed for LDML)
+        // 310 - z - time-zone names, matches LDML and SimpleDateFormat 1 to 4
+        // 310 - Z - matches SimpleDateFormat and LDML
+        // 310 - V - time-zone id, matches LDML
+        // 310 - p - prefix for padding
+        // 310 - X - matches LDML, almost matches SDF for 1, exact match 2&3, extended 4&5
+        // 310 - x - matches LDML
+        // 310 - w, W, and Y are localized forms matching LDML
+        // LDML - U - cycle year name, not supported by 310 yet
+        // LDML - l - deprecated
+        // LDML - j - not relevant
+        // LDML - g - modified-julian-day
+        // LDML - v,V - extended time-zone names
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Causes the next added printer/parser to pad to a fixed width using a space.
+     * <p>
+     * This padding will pad to a fixed width using spaces.
+     * <p>
+     * During formatting, the decorated element will be output and then padded
+     * to the specified width. An exception will be thrown during formatting if
+     * the pad width is exceeded.
+     * <p>
+     * During parsing, the padding and decorated element are parsed.
+     * If parsing is lenient, then the pad width is treated as a maximum.
+     * The padding is parsed greedily. Thus, if the decorated element starts with
+     * the pad character, it will not be parsed.
+     *
+     * @param padWidth  the pad width, 1 or greater
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if pad width is too small
+     */
+    public DateTimeFormatterBuilder padNext(int padWidth) {
+        return padNext(padWidth, ' ');
+    }
+
+    /**
+     * Causes the next added printer/parser to pad to a fixed width.
+     * <p>
+     * This padding is intended for padding other than zero-padding.
+     * Zero-padding should be achieved using the appendValue methods.
+     * <p>
+     * During formatting, the decorated element will be output and then padded
+     * to the specified width. An exception will be thrown during formatting if
+     * the pad width is exceeded.
+     * <p>
+     * During parsing, the padding and decorated element are parsed.
+     * If parsing is lenient, then the pad width is treated as a maximum.
+     * If parsing is case insensitive, then the pad character is matched ignoring case.
+     * The padding is parsed greedily. Thus, if the decorated element starts with
+     * the pad character, it will not be parsed.
+     *
+     * @param padWidth  the pad width, 1 or greater
+     * @param padChar  the pad character
+     * @return this, for chaining, not null
+     * @throws IllegalArgumentException if pad width is too small
+     */
+    public DateTimeFormatterBuilder padNext(int padWidth, char padChar) {
+        if (padWidth < 1) {
+            throw new IllegalArgumentException("The pad width must be at least one but was " + padWidth);
+        }
+        active.padNextWidth = padWidth;
+        active.padNextChar = padChar;
+        active.valueParserIndex = -1;
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Mark the start of an optional section.
+     * <p>
+     * The output of formatting can include optional sections, which may be nested.
+     * An optional section is started by calling this method and ended by calling
+     * {@link #optionalEnd()} or by ending the build process.
+     * <p>
+     * All elements in the optional section are treated as optional.
+     * During formatting, the section is only output if data is available in the
+     * {@code TemporalAccessor} for all the elements in the section.
+     * During parsing, the whole section may be missing from the parsed string.
+     * <p>
+     * For example, consider a builder setup as
+     * {@code builder.appendValue(HOUR_OF_DAY,2).optionalStart().appendValue(MINUTE_OF_HOUR,2)}.
+     * The optional section ends automatically at the end of the builder.
+     * During formatting, the minute will only be output if its value can be obtained from the date-time.
+     * During parsing, the input will be successfully parsed whether the minute is present or not.
+     *
+     * @return this, for chaining, not null
+     */
+    public DateTimeFormatterBuilder optionalStart() {
+        active.valueParserIndex = -1;
+        active = new DateTimeFormatterBuilder(active, true);
+        return this;
+    }
+
+    /**
+     * Ends an optional section.
+     * <p>
+     * The output of formatting can include optional sections, which may be nested.
+     * An optional section is started by calling {@link #optionalStart()} and ended
+     * using this method (or at the end of the builder).
+     * <p>
+     * Calling this method without having previously called {@code optionalStart}
+     * will throw an exception.
+     * Calling this method immediately after calling {@code optionalStart} has no effect
+     * on the formatter other than ending the (empty) optional section.
+     * <p>
+     * All elements in the optional section are treated as optional.
+     * During formatting, the section is only output if data is available in the
+     * {@code TemporalAccessor} for all the elements in the section.
+     * During parsing, the whole section may be missing from the parsed string.
+     * <p>
+     * For example, consider a builder setup as
+     * {@code builder.appendValue(HOUR_OF_DAY,2).optionalStart().appendValue(MINUTE_OF_HOUR,2).optionalEnd()}.
+     * During formatting, the minute will only be output if its value can be obtained from the date-time.
+     * During parsing, the input will be successfully parsed whether the minute is present or not.
+     *
+     * @return this, for chaining, not null
+     * @throws IllegalStateException if there was no previous call to {@code optionalStart}
+     */
+    public DateTimeFormatterBuilder optionalEnd() {
+        if (active.parent == null) {
+            throw new IllegalStateException("Cannot call optionalEnd() as there was no previous call to optionalStart()");
+        }
+        if (active.printerParsers.size() > 0) {
+            CompositePrinterParser cpp = new CompositePrinterParser(active.printerParsers, active.optional);
+            active = active.parent;
+            appendInternal(cpp);
+        } else {
+            active = active.parent;
+        }
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Appends a printer and/or parser to the internal list handling padding.
+     *
+     * @param pp  the printer-parser to add, not null
+     * @return the index into the active parsers list
+     */
+    private int appendInternal(DateTimePrinterParser pp) {
+        Objects.requireNonNull(pp, "pp");
+        if (active.padNextWidth > 0) {
+            if (pp != null) {
+                pp = new PadPrinterParserDecorator(pp, active.padNextWidth, active.padNextChar);
+            }
+            active.padNextWidth = 0;
+            active.padNextChar = 0;
+        }
+        active.printerParsers.add(pp);
+        active.valueParserIndex = -1;
+        return active.printerParsers.size() - 1;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Completes this builder by creating the {@code DateTimeFormatter}
+     * using the default locale.
+     * <p>
+     * This will create a formatter with the {@linkplain Locale#getDefault(Locale.Category) default FORMAT locale}.
+     * Numbers will be printed and parsed using the standard DecimalStyle.
+     * The resolver style will be {@link ResolverStyle#SMART SMART}.
+     * <p>
+     * Calling this method will end any open optional sections by repeatedly
+     * calling {@link #optionalEnd()} before creating the formatter.
+     * <p>
+     * This builder can still be used after creating the formatter if desired,
+     * although the state may have been changed by calls to {@code optionalEnd}.
+     *
+     * @return the created formatter, not null
+     */
+    public DateTimeFormatter toFormatter() {
+        return toFormatter(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Completes this builder by creating the {@code DateTimeFormatter}
+     * using the specified locale.
+     * <p>
+     * This will create a formatter with the specified locale.
+     * Numbers will be printed and parsed using the standard DecimalStyle.
+     * The resolver style will be {@link ResolverStyle#SMART SMART}.
+     * <p>
+     * Calling this method will end any open optional sections by repeatedly
+     * calling {@link #optionalEnd()} before creating the formatter.
+     * <p>
+     * This builder can still be used after creating the formatter if desired,
+     * although the state may have been changed by calls to {@code optionalEnd}.
+     *
+     * @param locale  the locale to use for formatting, not null
+     * @return the created formatter, not null
+     */
+    public DateTimeFormatter toFormatter(Locale locale) {
+        return toFormatter(locale, ResolverStyle.SMART, null);
+    }
+
+    /**
+     * Completes this builder by creating the formatter.
+     * This uses the default locale.
+     *
+     * @param resolverStyle  the resolver style to use, not null
+     * @return the created formatter, not null
+     */
+    DateTimeFormatter toFormatter(ResolverStyle resolverStyle, Chronology chrono) {
+        return toFormatter(Locale.getDefault(Locale.Category.FORMAT), resolverStyle, chrono);
+    }
+
+    /**
+     * Completes this builder by creating the formatter.
+     *
+     * @param locale  the locale to use for formatting, not null
+     * @param chrono  the chronology to use, may be null
+     * @return the created formatter, not null
+     */
+    private DateTimeFormatter toFormatter(Locale locale, ResolverStyle resolverStyle, Chronology chrono) {
+        Objects.requireNonNull(locale, "locale");
+        while (active.parent != null) {
+            optionalEnd();
+        }
+        CompositePrinterParser pp = new CompositePrinterParser(printerParsers, false);
+        return new DateTimeFormatter(pp, locale, DecimalStyle.STANDARD,
+                resolverStyle, null, chrono, null);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Strategy for formatting/parsing date-time information.
+     * <p>
+     * The printer may format any part, or the whole, of the input date-time object.
+     * Typically, a complete format is constructed from a number of smaller
+     * units, each outputting a single field.
+     * <p>
+     * The parser may parse any piece of text from the input, storing the result
+     * in the context. Typically, each individual parser will just parse one
+     * field, such as the day-of-month, storing the value in the context.
+     * Once the parse is complete, the caller will then resolve the parsed values
+     * to create the desired object, such as a {@code LocalDate}.
+     * <p>
+     * The parse position will be updated during the parse. Parsing will start at
+     * the specified index and the return value specifies the new parse position
+     * for the next parser. If an error occurs, the returned index will be negative
+     * and will have the error position encoded using the complement operator.
+     *
+     * @implSpec
+     * This interface must be implemented with care to ensure other classes operate correctly.
+     * All implementations that can be instantiated must be final, immutable and thread-safe.
+     * <p>
+     * The context is not a thread-safe object and a new instance will be created
+     * for each format that occurs. The context must not be stored in an instance
+     * variable or shared with any other threads.
+     */
+    interface DateTimePrinterParser {
+
+        /**
+         * Prints the date-time object to the buffer.
+         * <p>
+         * The context holds information to use during the format.
+         * It also contains the date-time information to be printed.
+         * <p>
+         * The buffer must not be mutated beyond the content controlled by the implementation.
+         *
+         * @param context  the context to format using, not null
+         * @param buf  the buffer to append to, not null
+         * @return false if unable to query the value from the date-time, true otherwise
+         * @throws DateTimeException if the date-time cannot be printed successfully
+         */
+        boolean format(DateTimePrintContext context, StringBuilder buf);
+
+        /**
+         * Parses text into date-time information.
+         * <p>
+         * The context holds information to use during the parse.
+         * It is also used to store the parsed date-time information.
+         *
+         * @param context  the context to use and parse into, not null
+         * @param text  the input text to parse, not null
+         * @param position  the position to start parsing at, from 0 to the text length
+         * @return the new parse position, where negative means an error with the
+         *  error position encoded using the complement ~ operator
+         * @throws NullPointerException if the context or text is null
+         * @throws IndexOutOfBoundsException if the position is invalid
+         */
+        int parse(DateTimeParseContext context, CharSequence text, int position);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Composite printer and parser.
+     */
+    static final class CompositePrinterParser implements DateTimePrinterParser {
+        private final DateTimePrinterParser[] printerParsers;
+        private final boolean optional;
+
+        CompositePrinterParser(List<DateTimePrinterParser> printerParsers, boolean optional) {
+            this(printerParsers.toArray(new DateTimePrinterParser[printerParsers.size()]), optional);
+        }
+
+        CompositePrinterParser(DateTimePrinterParser[] printerParsers, boolean optional) {
+            this.printerParsers = printerParsers;
+            this.optional = optional;
+        }
+
+        /**
+         * Returns a copy of this printer-parser with the optional flag changed.
+         *
+         * @param optional  the optional flag to set in the copy
+         * @return the new printer-parser, not null
+         */
+        public CompositePrinterParser withOptional(boolean optional) {
+            if (optional == this.optional) {
+                return this;
+            }
+            return new CompositePrinterParser(printerParsers, optional);
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            int length = buf.length();
+            if (optional) {
+                context.startOptional();
+            }
+            try {
+                for (DateTimePrinterParser pp : printerParsers) {
+                    if (pp.format(context, buf) == false) {
+                        buf.setLength(length);  // reset buffer
+                        return true;
+                    }
+                }
+            } finally {
+                if (optional) {
+                    context.endOptional();
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            if (optional) {
+                context.startOptional();
+                int pos = position;
+                for (DateTimePrinterParser pp : printerParsers) {
+                    pos = pp.parse(context, text, pos);
+                    if (pos < 0) {
+                        context.endOptional(false);
+                        return position;  // return original position
+                    }
+                }
+                context.endOptional(true);
+                return pos;
+            } else {
+                for (DateTimePrinterParser pp : printerParsers) {
+                    position = pp.parse(context, text, position);
+                    if (position < 0) {
+                        break;
+                    }
+                }
+                return position;
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder buf = new StringBuilder();
+            if (printerParsers != null) {
+                buf.append(optional ? "[" : "(");
+                for (DateTimePrinterParser pp : printerParsers) {
+                    buf.append(pp);
+                }
+                buf.append(optional ? "]" : ")");
+            }
+            return buf.toString();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Pads the output to a fixed width.
+     */
+    static final class PadPrinterParserDecorator implements DateTimePrinterParser {
+        private final DateTimePrinterParser printerParser;
+        private final int padWidth;
+        private final char padChar;
+
+        /**
+         * Constructor.
+         *
+         * @param printerParser  the printer, not null
+         * @param padWidth  the width to pad to, 1 or greater
+         * @param padChar  the pad character
+         */
+        PadPrinterParserDecorator(DateTimePrinterParser printerParser, int padWidth, char padChar) {
+            // input checked by DateTimeFormatterBuilder
+            this.printerParser = printerParser;
+            this.padWidth = padWidth;
+            this.padChar = padChar;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            int preLen = buf.length();
+            if (printerParser.format(context, buf) == false) {
+                return false;
+            }
+            int len = buf.length() - preLen;
+            if (len > padWidth) {
+                throw new DateTimeException(
+                    "Cannot print as output of " + len + " characters exceeds pad width of " + padWidth);
+            }
+            for (int i = 0; i < padWidth - len; i++) {
+                buf.insert(preLen, padChar);
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            // cache context before changed by decorated parser
+            final boolean strict = context.isStrict();
+            // parse
+            if (position > text.length()) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (position == text.length()) {
+                return ~position;  // no more characters in the string
+            }
+            int endPos = position + padWidth;
+            if (endPos > text.length()) {
+                if (strict) {
+                    return ~position;  // not enough characters in the string to meet the parse width
+                }
+                endPos = text.length();
+            }
+            int pos = position;
+            while (pos < endPos && context.charEquals(text.charAt(pos), padChar)) {
+                pos++;
+            }
+            text = text.subSequence(0, endPos);
+            int resultPos = printerParser.parse(context, text, pos);
+            if (resultPos != endPos && strict) {
+                return ~(position + pos);  // parse of decorated field didn't parse to the end
+            }
+            return resultPos;
+        }
+
+        @Override
+        public String toString() {
+            return "Pad(" + printerParser + "," + padWidth + (padChar == ' ' ? ")" : ",'" + padChar + "')");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Enumeration to apply simple parse settings.
+     */
+    static enum SettingsParser implements DateTimePrinterParser {
+        SENSITIVE,
+        INSENSITIVE,
+        STRICT,
+        LENIENT;
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            return true;  // nothing to do here
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            // using ordinals to avoid javac synthetic inner class
+            switch (ordinal()) {
+                case 0: context.setCaseSensitive(true); break;
+                case 1: context.setCaseSensitive(false); break;
+                case 2: context.setStrict(true); break;
+                case 3: context.setStrict(false); break;
+            }
+            return position;
+        }
+
+        @Override
+        public String toString() {
+            // using ordinals to avoid javac synthetic inner class
+            switch (ordinal()) {
+                case 0: return "ParseCaseSensitive(true)";
+                case 1: return "ParseCaseSensitive(false)";
+                case 2: return "ParseStrict(true)";
+                case 3: return "ParseStrict(false)";
+            }
+            throw new IllegalStateException("Unreachable");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defaults a value into the parse if not currently present.
+     */
+    static class DefaultValueParser implements DateTimePrinterParser {
+        private final TemporalField field;
+        private final long value;
+
+        DefaultValueParser(TemporalField field, long value) {
+            this.field = field;
+            this.value = value;
+        }
+
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            return true;
+        }
+
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            if (context.getParsed(field) == null) {
+                context.setParsedField(field, value, position, position);
+            }
+            return position;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a character literal.
+     */
+    static final class CharLiteralPrinterParser implements DateTimePrinterParser {
+        private final char literal;
+
+        CharLiteralPrinterParser(char literal) {
+            this.literal = literal;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            buf.append(literal);
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position == length) {
+                return ~position;
+            }
+            char ch = text.charAt(position);
+            if (ch != literal) {
+                if (context.isCaseSensitive() ||
+                        (Character.toUpperCase(ch) != Character.toUpperCase(literal) &&
+                         Character.toLowerCase(ch) != Character.toLowerCase(literal))) {
+                    return ~position;
+                }
+            }
+            return position + 1;
+        }
+
+        @Override
+        public String toString() {
+            if (literal == '\'') {
+                return "''";
+            }
+            return "'" + literal + "'";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a string literal.
+     */
+    static final class StringLiteralPrinterParser implements DateTimePrinterParser {
+        private final String literal;
+
+        StringLiteralPrinterParser(String literal) {
+            this.literal = literal;  // validated by caller
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            buf.append(literal);
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position > length || position < 0) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (context.subSequenceEquals(text, position, literal, 0, literal.length()) == false) {
+                return ~position;
+            }
+            return position + literal.length();
+        }
+
+        @Override
+        public String toString() {
+            String converted = literal.replace("'", "''");
+            return "'" + converted + "'";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints and parses a numeric date-time field with optional padding.
+     */
+    static class NumberPrinterParser implements DateTimePrinterParser {
+
+        /**
+         * Array of 10 to the power of n.
+         */
+        static final long[] EXCEED_POINTS = new long[] {
+            0L,
+            10L,
+            100L,
+            1000L,
+            10000L,
+            100000L,
+            1000000L,
+            10000000L,
+            100000000L,
+            1000000000L,
+            10000000000L,
+        };
+
+        final TemporalField field;
+        final int minWidth;
+        final int maxWidth;
+        private final SignStyle signStyle;
+        final int subsequentWidth;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to format, not null
+         * @param minWidth  the minimum field width, from 1 to 19
+         * @param maxWidth  the maximum field width, from minWidth to 19
+         * @param signStyle  the positive/negative sign style, not null
+         */
+        NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle) {
+            // validated by caller
+            this.field = field;
+            this.minWidth = minWidth;
+            this.maxWidth = maxWidth;
+            this.signStyle = signStyle;
+            this.subsequentWidth = 0;
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to format, not null
+         * @param minWidth  the minimum field width, from 1 to 19
+         * @param maxWidth  the maximum field width, from minWidth to 19
+         * @param signStyle  the positive/negative sign style, not null
+         * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater,
+         *  -1 if fixed width due to active adjacent parsing
+         */
+        protected NumberPrinterParser(TemporalField field, int minWidth, int maxWidth, SignStyle signStyle, int subsequentWidth) {
+            // validated by caller
+            this.field = field;
+            this.minWidth = minWidth;
+            this.maxWidth = maxWidth;
+            this.signStyle = signStyle;
+            this.subsequentWidth = subsequentWidth;
+        }
+
+        /**
+         * Returns a new instance with fixed width flag set.
+         *
+         * @return a new updated printer-parser, not null
+         */
+        NumberPrinterParser withFixedWidth() {
+            if (subsequentWidth == -1) {
+                return this;
+            }
+            return new NumberPrinterParser(field, minWidth, maxWidth, signStyle, -1);
+        }
+
+        /**
+         * Returns a new instance with an updated subsequent width.
+         *
+         * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater
+         * @return a new updated printer-parser, not null
+         */
+        NumberPrinterParser withSubsequentWidth(int subsequentWidth) {
+            return new NumberPrinterParser(field, minWidth, maxWidth, signStyle, this.subsequentWidth + subsequentWidth);
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Long valueLong = context.getValue(field);
+            if (valueLong == null) {
+                return false;
+            }
+            long value = getValue(context, valueLong);
+            DecimalStyle decimalStyle = context.getDecimalStyle();
+            String str = (value == Long.MIN_VALUE ? "9223372036854775808" : Long.toString(Math.abs(value)));
+            if (str.length() > maxWidth) {
+                throw new DateTimeException("Field " + field +
+                    " cannot be printed as the value " + value +
+                    " exceeds the maximum print width of " + maxWidth);
+            }
+            str = decimalStyle.convertNumberToI18N(str);
+
+            if (value >= 0) {
+                switch (signStyle) {
+                    case EXCEEDS_PAD:
+                        if (minWidth < 19 && value >= EXCEED_POINTS[minWidth]) {
+                            buf.append(decimalStyle.getPositiveSign());
+                        }
+                        break;
+                    case ALWAYS:
+                        buf.append(decimalStyle.getPositiveSign());
+                        break;
+                }
+            } else {
+                switch (signStyle) {
+                    case NORMAL:
+                    case EXCEEDS_PAD:
+                    case ALWAYS:
+                        buf.append(decimalStyle.getNegativeSign());
+                        break;
+                    case NOT_NEGATIVE:
+                        throw new DateTimeException("Field " + field +
+                            " cannot be printed as the value " + value +
+                            " cannot be negative according to the SignStyle");
+                }
+            }
+            for (int i = 0; i < minWidth - str.length(); i++) {
+                buf.append(decimalStyle.getZeroDigit());
+            }
+            buf.append(str);
+            return true;
+        }
+
+        /**
+         * Gets the value to output.
+         *
+         * @param context  the context
+         * @param value  the value of the field, not null
+         * @return the value
+         */
+        long getValue(DateTimePrintContext context, long value) {
+            return value;
+        }
+
+        /**
+         * For NumberPrinterParser, the width is fixed depending on the
+         * minWidth, maxWidth, signStyle and whether subsequent fields are fixed.
+         * @param context the context
+         * @return true if the field is fixed width
+         * @see DateTimeFormatterBuilder#appendValue(java.time.temporal.TemporalField, int)
+         */
+        boolean isFixedWidth(DateTimeParseContext context) {
+            return subsequentWidth == -1 ||
+                (subsequentWidth > 0 && minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE);
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position == length) {
+                return ~position;
+            }
+            char sign = text.charAt(position);  // IOOBE if invalid position
+            boolean negative = false;
+            boolean positive = false;
+            if (sign == context.getDecimalStyle().getPositiveSign()) {
+                if (signStyle.parse(true, context.isStrict(), minWidth == maxWidth) == false) {
+                    return ~position;
+                }
+                positive = true;
+                position++;
+            } else if (sign == context.getDecimalStyle().getNegativeSign()) {
+                if (signStyle.parse(false, context.isStrict(), minWidth == maxWidth) == false) {
+                    return ~position;
+                }
+                negative = true;
+                position++;
+            } else {
+                if (signStyle == SignStyle.ALWAYS && context.isStrict()) {
+                    return ~position;
+                }
+            }
+            int effMinWidth = (context.isStrict() || isFixedWidth(context) ? minWidth : 1);
+            int minEndPos = position + effMinWidth;
+            if (minEndPos > length) {
+                return ~position;
+            }
+            int effMaxWidth = (context.isStrict() || isFixedWidth(context) ? maxWidth : 9) + Math.max(subsequentWidth, 0);
+            long total = 0;
+            BigInteger totalBig = null;
+            int pos = position;
+            for (int pass = 0; pass < 2; pass++) {
+                int maxEndPos = Math.min(pos + effMaxWidth, length);
+                while (pos < maxEndPos) {
+                    char ch = text.charAt(pos++);
+                    int digit = context.getDecimalStyle().convertToDigit(ch);
+                    if (digit < 0) {
+                        pos--;
+                        if (pos < minEndPos) {
+                            return ~position;  // need at least min width digits
+                        }
+                        break;
+                    }
+                    if ((pos - position) > 18) {
+                        if (totalBig == null) {
+                            totalBig = BigInteger.valueOf(total);
+                        }
+                        totalBig = totalBig.multiply(BigInteger.TEN).add(BigInteger.valueOf(digit));
+                    } else {
+                        total = total * 10 + digit;
+                    }
+                }
+                if (subsequentWidth > 0 && pass == 0) {
+                    // re-parse now we know the correct width
+                    int parseLen = pos - position;
+                    effMaxWidth = Math.max(effMinWidth, parseLen - subsequentWidth);
+                    pos = position;
+                    total = 0;
+                    totalBig = null;
+                } else {
+                    break;
+                }
+            }
+            if (negative) {
+                if (totalBig != null) {
+                    if (totalBig.equals(BigInteger.ZERO) && context.isStrict()) {
+                        return ~(position - 1);  // minus zero not allowed
+                    }
+                    totalBig = totalBig.negate();
+                } else {
+                    if (total == 0 && context.isStrict()) {
+                        return ~(position - 1);  // minus zero not allowed
+                    }
+                    total = -total;
+                }
+            } else if (signStyle == SignStyle.EXCEEDS_PAD && context.isStrict()) {
+                int parseLen = pos - position;
+                if (positive) {
+                    if (parseLen <= minWidth) {
+                        return ~(position - 1);  // '+' only parsed if minWidth exceeded
+                    }
+                } else {
+                    if (parseLen > minWidth) {
+                        return ~position;  // '+' must be parsed if minWidth exceeded
+                    }
+                }
+            }
+            if (totalBig != null) {
+                if (totalBig.bitLength() > 63) {
+                    // overflow, parse 1 less digit
+                    totalBig = totalBig.divide(BigInteger.TEN);
+                    pos--;
+                }
+                return setValue(context, totalBig.longValue(), position, pos);
+            }
+            return setValue(context, total, position, pos);
+        }
+
+        /**
+         * Stores the value.
+         *
+         * @param context  the context to store into, not null
+         * @param value  the value
+         * @param errorPos  the position of the field being parsed
+         * @param successPos  the position after the field being parsed
+         * @return the new position
+         */
+        int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) {
+            return context.setParsedField(field, value, errorPos, successPos);
+        }
+
+        @Override
+        public String toString() {
+            if (minWidth == 1 && maxWidth == 19 && signStyle == SignStyle.NORMAL) {
+                return "Value(" + field + ")";
+            }
+            if (minWidth == maxWidth && signStyle == SignStyle.NOT_NEGATIVE) {
+                return "Value(" + field + "," + minWidth + ")";
+            }
+            return "Value(" + field + "," + minWidth + "," + maxWidth + "," + signStyle + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints and parses a reduced numeric date-time field.
+     */
+    static final class ReducedPrinterParser extends NumberPrinterParser {
+        /**
+         * The base date for reduced value parsing.
+         */
+        static final LocalDate BASE_DATE = LocalDate.of(2000, 1, 1);
+
+        private final int baseValue;
+        private final ChronoLocalDate baseDate;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to format, validated not null
+         * @param minWidth  the minimum field width, from 1 to 10
+         * @param maxWidth  the maximum field width, from 1 to 10
+         * @param baseValue  the base value
+         * @param baseDate  the base date
+         */
+        ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth,
+                int baseValue, ChronoLocalDate baseDate) {
+            this(field, minWidth, maxWidth, baseValue, baseDate, 0);
+            if (minWidth < 1 || minWidth > 10) {
+                throw new IllegalArgumentException("The minWidth must be from 1 to 10 inclusive but was " + minWidth);
+            }
+            if (maxWidth < 1 || maxWidth > 10) {
+                throw new IllegalArgumentException("The maxWidth must be from 1 to 10 inclusive but was " + minWidth);
+            }
+            if (maxWidth < minWidth) {
+                throw new IllegalArgumentException("Maximum width must exceed or equal the minimum width but " +
+                        maxWidth + " < " + minWidth);
+            }
+            if (baseDate == null) {
+                if (field.range().isValidValue(baseValue) == false) {
+                    throw new IllegalArgumentException("The base value must be within the range of the field");
+                }
+                if ((((long) baseValue) + EXCEED_POINTS[maxWidth]) > Integer.MAX_VALUE) {
+                    throw new DateTimeException("Unable to add printer-parser as the range exceeds the capacity of an int");
+                }
+            }
+        }
+
+        /**
+         * Constructor.
+         * The arguments have already been checked.
+         *
+         * @param field  the field to format, validated not null
+         * @param minWidth  the minimum field width, from 1 to 10
+         * @param maxWidth  the maximum field width, from 1 to 10
+         * @param baseValue  the base value
+         * @param baseDate  the base date
+         * @param subsequentWidth the subsequentWidth for this instance
+         */
+        private ReducedPrinterParser(TemporalField field, int minWidth, int maxWidth,
+                int baseValue, ChronoLocalDate baseDate, int subsequentWidth) {
+            super(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth);
+            this.baseValue = baseValue;
+            this.baseDate = baseDate;
+        }
+
+        @Override
+        long getValue(DateTimePrintContext context, long value) {
+            long absValue = Math.abs(value);
+            int baseValue = this.baseValue;
+            if (baseDate != null) {
+                Chronology chrono = Chronology.from(context.getTemporal());
+                baseValue = chrono.date(baseDate).get(field);
+            }
+            if (value >= baseValue && value < baseValue + EXCEED_POINTS[minWidth]) {
+                // Use the reduced value if it fits in minWidth
+                return absValue % EXCEED_POINTS[minWidth];
+            }
+            // Otherwise truncate to fit in maxWidth
+            return absValue % EXCEED_POINTS[maxWidth];
+        }
+
+        @Override
+        int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) {
+            int baseValue = this.baseValue;
+            if (baseDate != null) {
+                Chronology chrono = context.getEffectiveChronology();
+                baseValue = chrono.date(baseDate).get(field);
+
+                // In case the Chronology is changed later, add a callback when/if it changes
+                final long initialValue = value;
+                context.addChronoChangedListener(
+                        (_unused) ->  {
+                            /* Repeat the set of the field using the current Chronology
+                             * The success/error position is ignored because the value is
+                             * intentionally being overwritten.
+                             */
+                            setValue(context, initialValue, errorPos, successPos);
+                        });
+            }
+            int parseLen = successPos - errorPos;
+            if (parseLen == minWidth && value >= 0) {
+                long range = EXCEED_POINTS[minWidth];
+                long lastPart = baseValue % range;
+                long basePart = baseValue - lastPart;
+                if (baseValue > 0) {
+                    value = basePart + value;
+                } else {
+                    value = basePart - value;
+                }
+                if (value < baseValue) {
+                    value += range;
+                }
+            }
+            return context.setParsedField(field, value, errorPos, successPos);
+        }
+
+        /**
+         * Returns a new instance with fixed width flag set.
+         *
+         * @return a new updated printer-parser, not null
+         */
+        @Override
+        ReducedPrinterParser withFixedWidth() {
+            if (subsequentWidth == -1) {
+                return this;
+            }
+            return new ReducedPrinterParser(field, minWidth, maxWidth, baseValue, baseDate, -1);
+        }
+
+        /**
+         * Returns a new instance with an updated subsequent width.
+         *
+         * @param subsequentWidth  the width of subsequent non-negative numbers, 0 or greater
+         * @return a new updated printer-parser, not null
+         */
+        @Override
+        ReducedPrinterParser withSubsequentWidth(int subsequentWidth) {
+            return new ReducedPrinterParser(field, minWidth, maxWidth, baseValue, baseDate,
+                    this.subsequentWidth + subsequentWidth);
+        }
+
+        /**
+         * For a ReducedPrinterParser, fixed width is false if the mode is strict,
+         * otherwise it is set as for NumberPrinterParser.
+         * @param context the context
+         * @return if the field is fixed width
+         * @see DateTimeFormatterBuilder#appendValueReduced(java.time.temporal.TemporalField, int, int, int)
+         */
+        @Override
+        boolean isFixedWidth(DateTimeParseContext context) {
+           if (context.isStrict() == false) {
+               return false;
+           }
+           return super.isFixedWidth(context);
+        }
+
+        @Override
+        public String toString() {
+            return "ReducedValue(" + field + "," + minWidth + "," + maxWidth + "," + (baseDate != null ? baseDate : baseValue) + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints and parses a numeric date-time field with optional padding.
+     */
+    static final class FractionPrinterParser implements DateTimePrinterParser {
+        private final TemporalField field;
+        private final int minWidth;
+        private final int maxWidth;
+        private final boolean decimalPoint;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to output, not null
+         * @param minWidth  the minimum width to output, from 0 to 9
+         * @param maxWidth  the maximum width to output, from 0 to 9
+         * @param decimalPoint  whether to output the localized decimal point symbol
+         */
+        FractionPrinterParser(TemporalField field, int minWidth, int maxWidth, boolean decimalPoint) {
+            Objects.requireNonNull(field, "field");
+            if (field.range().isFixed() == false) {
+                throw new IllegalArgumentException("Field must have a fixed set of values: " + field);
+            }
+            if (minWidth < 0 || minWidth > 9) {
+                throw new IllegalArgumentException("Minimum width must be from 0 to 9 inclusive but was " + minWidth);
+            }
+            if (maxWidth < 1 || maxWidth > 9) {
+                throw new IllegalArgumentException("Maximum width must be from 1 to 9 inclusive but was " + maxWidth);
+            }
+            if (maxWidth < minWidth) {
+                throw new IllegalArgumentException("Maximum width must exceed or equal the minimum width but " +
+                        maxWidth + " < " + minWidth);
+            }
+            this.field = field;
+            this.minWidth = minWidth;
+            this.maxWidth = maxWidth;
+            this.decimalPoint = decimalPoint;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Long value = context.getValue(field);
+            if (value == null) {
+                return false;
+            }
+            DecimalStyle decimalStyle = context.getDecimalStyle();
+            BigDecimal fraction = convertToFraction(value);
+            if (fraction.scale() == 0) {  // scale is zero if value is zero
+                if (minWidth > 0) {
+                    if (decimalPoint) {
+                        buf.append(decimalStyle.getDecimalSeparator());
+                    }
+                    for (int i = 0; i < minWidth; i++) {
+                        buf.append(decimalStyle.getZeroDigit());
+                    }
+                }
+            } else {
+                int outputScale = Math.min(Math.max(fraction.scale(), minWidth), maxWidth);
+                fraction = fraction.setScale(outputScale, RoundingMode.FLOOR);
+                String str = fraction.toPlainString().substring(2);
+                str = decimalStyle.convertNumberToI18N(str);
+                if (decimalPoint) {
+                    buf.append(decimalStyle.getDecimalSeparator());
+                }
+                buf.append(str);
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int effectiveMin = (context.isStrict() ? minWidth : 0);
+            int effectiveMax = (context.isStrict() ? maxWidth : 9);
+            int length = text.length();
+            if (position == length) {
+                // valid if whole field is optional, invalid if minimum width
+                return (effectiveMin > 0 ? ~position : position);
+            }
+            if (decimalPoint) {
+                if (text.charAt(position) != context.getDecimalStyle().getDecimalSeparator()) {
+                    // valid if whole field is optional, invalid if minimum width
+                    return (effectiveMin > 0 ? ~position : position);
+                }
+                position++;
+            }
+            int minEndPos = position + effectiveMin;
+            if (minEndPos > length) {
+                return ~position;  // need at least min width digits
+            }
+            int maxEndPos = Math.min(position + effectiveMax, length);
+            int total = 0;  // can use int because we are only parsing up to 9 digits
+            int pos = position;
+            while (pos < maxEndPos) {
+                char ch = text.charAt(pos++);
+                int digit = context.getDecimalStyle().convertToDigit(ch);
+                if (digit < 0) {
+                    if (pos < minEndPos) {
+                        return ~position;  // need at least min width digits
+                    }
+                    pos--;
+                    break;
+                }
+                total = total * 10 + digit;
+            }
+            BigDecimal fraction = new BigDecimal(total).movePointLeft(pos - position);
+            long value = convertFromFraction(fraction);
+            return context.setParsedField(field, value, position, pos);
+        }
+
+        /**
+         * Converts a value for this field to a fraction between 0 and 1.
+         * <p>
+         * The fractional value is between 0 (inclusive) and 1 (exclusive).
+         * It can only be returned if the {@link java.time.temporal.TemporalField#range() value range} is fixed.
+         * The fraction is obtained by calculation from the field range using 9 decimal
+         * places and a rounding mode of {@link RoundingMode#FLOOR FLOOR}.
+         * The calculation is inaccurate if the values do not run continuously from smallest to largest.
+         * <p>
+         * For example, the second-of-minute value of 15 would be returned as 0.25,
+         * assuming the standard definition of 60 seconds in a minute.
+         *
+         * @param value  the value to convert, must be valid for this rule
+         * @return the value as a fraction within the range, from 0 to 1, not null
+         * @throws DateTimeException if the value cannot be converted to a fraction
+         */
+        private BigDecimal convertToFraction(long value) {
+            ValueRange range = field.range();
+            range.checkValidValue(value, field);
+            BigDecimal minBD = BigDecimal.valueOf(range.getMinimum());
+            BigDecimal rangeBD = BigDecimal.valueOf(range.getMaximum()).subtract(minBD).add(BigDecimal.ONE);
+            BigDecimal valueBD = BigDecimal.valueOf(value).subtract(minBD);
+            BigDecimal fraction = valueBD.divide(rangeBD, 9, RoundingMode.FLOOR);
+            // stripTrailingZeros bug
+            return fraction.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : fraction.stripTrailingZeros();
+        }
+
+        /**
+         * Converts a fraction from 0 to 1 for this field to a value.
+         * <p>
+         * The fractional value must be between 0 (inclusive) and 1 (exclusive).
+         * It can only be returned if the {@link java.time.temporal.TemporalField#range() value range} is fixed.
+         * The value is obtained by calculation from the field range and a rounding
+         * mode of {@link RoundingMode#FLOOR FLOOR}.
+         * The calculation is inaccurate if the values do not run continuously from smallest to largest.
+         * <p>
+         * For example, the fractional second-of-minute of 0.25 would be converted to 15,
+         * assuming the standard definition of 60 seconds in a minute.
+         *
+         * @param fraction  the fraction to convert, not null
+         * @return the value of the field, valid for this rule
+         * @throws DateTimeException if the value cannot be converted
+         */
+        private long convertFromFraction(BigDecimal fraction) {
+            ValueRange range = field.range();
+            BigDecimal minBD = BigDecimal.valueOf(range.getMinimum());
+            BigDecimal rangeBD = BigDecimal.valueOf(range.getMaximum()).subtract(minBD).add(BigDecimal.ONE);
+            BigDecimal valueBD = fraction.multiply(rangeBD).setScale(0, RoundingMode.FLOOR).add(minBD);
+            return valueBD.longValueExact();
+        }
+
+        @Override
+        public String toString() {
+            String decimal = (decimalPoint ? ",DecimalPoint" : "");
+            return "Fraction(" + field + "," + minWidth + "," + maxWidth + decimal + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses field text.
+     */
+    static final class TextPrinterParser implements DateTimePrinterParser {
+        private final TemporalField field;
+        private final TextStyle textStyle;
+        private final DateTimeTextProvider provider;
+        /**
+         * The cached number printer parser.
+         * Immutable and volatile, so no synchronization needed.
+         */
+        private volatile NumberPrinterParser numberPrinterParser;
+
+        /**
+         * Constructor.
+         *
+         * @param field  the field to output, not null
+         * @param textStyle  the text style, not null
+         * @param provider  the text provider, not null
+         */
+        TextPrinterParser(TemporalField field, TextStyle textStyle, DateTimeTextProvider provider) {
+            // validated by caller
+            this.field = field;
+            this.textStyle = textStyle;
+            this.provider = provider;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Long value = context.getValue(field);
+            if (value == null) {
+                return false;
+            }
+            String text;
+            Chronology chrono = context.getTemporal().query(TemporalQueries.chronology());
+            if (chrono == null || chrono == IsoChronology.INSTANCE) {
+                text = provider.getText(field, value, textStyle, context.getLocale());
+            } else {
+                text = provider.getText(chrono, field, value, textStyle, context.getLocale());
+            }
+            if (text == null) {
+                return numberPrinterParser().format(context, buf);
+            }
+            buf.append(text);
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence parseText, int position) {
+            int length = parseText.length();
+            if (position < 0 || position > length) {
+                throw new IndexOutOfBoundsException();
+            }
+            TextStyle style = (context.isStrict() ? textStyle : null);
+            Chronology chrono = context.getEffectiveChronology();
+            Iterator<Entry<String, Long>> it;
+            if (chrono == null || chrono == IsoChronology.INSTANCE) {
+                it = provider.getTextIterator(field, style, context.getLocale());
+            } else {
+                it = provider.getTextIterator(chrono, field, style, context.getLocale());
+            }
+            if (it != null) {
+                while (it.hasNext()) {
+                    Entry<String, Long> entry = it.next();
+                    String itText = entry.getKey();
+                    if (context.subSequenceEquals(itText, 0, parseText, position, itText.length())) {
+                        return context.setParsedField(field, entry.getValue(), position, position + itText.length());
+                    }
+                }
+                if (context.isStrict()) {
+                    return ~position;
+                }
+            }
+            return numberPrinterParser().parse(context, parseText, position);
+        }
+
+        /**
+         * Create and cache a number printer parser.
+         * @return the number printer parser for this field, not null
+         */
+        private NumberPrinterParser numberPrinterParser() {
+            if (numberPrinterParser == null) {
+                numberPrinterParser = new NumberPrinterParser(field, 1, 19, SignStyle.NORMAL);
+            }
+            return numberPrinterParser;
+        }
+
+        @Override
+        public String toString() {
+            if (textStyle == TextStyle.FULL) {
+                return "Text(" + field + ")";
+            }
+            return "Text(" + field + "," + textStyle + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses an ISO-8601 instant.
+     */
+    static final class InstantPrinterParser implements DateTimePrinterParser {
+        // days in a 400 year cycle = 146097
+        // days in a 10,000 year cycle = 146097 * 25
+        // seconds per day = 86400
+        private static final long SECONDS_PER_10000_YEARS = 146097L * 25L * 86400L;
+        private static final long SECONDS_0000_TO_1970 = ((146097L * 5L) - (30L * 365L + 7L)) * 86400L;
+        private final int fractionalDigits;
+
+        InstantPrinterParser(int fractionalDigits) {
+            this.fractionalDigits = fractionalDigits;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            // use INSTANT_SECONDS, thus this code is not bound by Instant.MAX
+            Long inSecs = context.getValue(INSTANT_SECONDS);
+            Long inNanos = null;
+            if (context.getTemporal().isSupported(NANO_OF_SECOND)) {
+                inNanos = context.getTemporal().getLong(NANO_OF_SECOND);
+            }
+            if (inSecs == null) {
+                return false;
+            }
+            long inSec = inSecs;
+            int inNano = NANO_OF_SECOND.checkValidIntValue(inNanos != null ? inNanos : 0);
+            // format mostly using LocalDateTime.toString
+            if (inSec >= -SECONDS_0000_TO_1970) {
+                // current era
+                long zeroSecs = inSec - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970;
+                long hi = Math.floorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1;
+                long lo = Math.floorMod(zeroSecs, SECONDS_PER_10000_YEARS);
+                LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC);
+                if (hi > 0) {
+                    buf.append('+').append(hi);
+                }
+                buf.append(ldt);
+                if (ldt.getSecond() == 0) {
+                    buf.append(":00");
+                }
+            } else {
+                // before current era
+                long zeroSecs = inSec + SECONDS_0000_TO_1970;
+                long hi = zeroSecs / SECONDS_PER_10000_YEARS;
+                long lo = zeroSecs % SECONDS_PER_10000_YEARS;
+                LocalDateTime ldt = LocalDateTime.ofEpochSecond(lo - SECONDS_0000_TO_1970, 0, ZoneOffset.UTC);
+                int pos = buf.length();
+                buf.append(ldt);
+                if (ldt.getSecond() == 0) {
+                    buf.append(":00");
+                }
+                if (hi < 0) {
+                    if (ldt.getYear() == -10_000) {
+                        buf.replace(pos, pos + 2, Long.toString(hi - 1));
+                    } else if (lo == 0) {
+                        buf.insert(pos, hi);
+                    } else {
+                        buf.insert(pos + 1, Math.abs(hi));
+                    }
+                }
+            }
+            // add fraction
+            if ((fractionalDigits < 0 && inNano > 0) || fractionalDigits > 0) {
+                buf.append('.');
+                int div = 100_000_000;
+                for (int i = 0; ((fractionalDigits == -1 && inNano > 0) ||
+                                    (fractionalDigits == -2 && (inNano > 0 || (i % 3) != 0)) ||
+                                    i < fractionalDigits); i++) {
+                    int digit = inNano / div;
+                    buf.append((char) (digit + '0'));
+                    inNano = inNano - (digit * div);
+                    div = div / 10;
+                }
+            }
+            buf.append('Z');
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            // new context to avoid overwriting fields like year/month/day
+            int minDigits = (fractionalDigits < 0 ? 0 : fractionalDigits);
+            int maxDigits = (fractionalDigits < 0 ? 9 : fractionalDigits);
+            CompositePrinterParser parser = new DateTimeFormatterBuilder()
+                    .append(DateTimeFormatter.ISO_LOCAL_DATE).appendLiteral('T')
+                    .appendValue(HOUR_OF_DAY, 2).appendLiteral(':')
+                    .appendValue(MINUTE_OF_HOUR, 2).appendLiteral(':')
+                    .appendValue(SECOND_OF_MINUTE, 2)
+                    .appendFraction(NANO_OF_SECOND, minDigits, maxDigits, true)
+                    .appendLiteral('Z')
+                    .toFormatter().toPrinterParser(false);
+            DateTimeParseContext newContext = context.copy();
+            int pos = parser.parse(newContext, text, position);
+            if (pos < 0) {
+                return pos;
+            }
+            // parser restricts most fields to 2 digits, so definitely int
+            // correctly parsed nano is also guaranteed to be valid
+            long yearParsed = newContext.getParsed(YEAR);
+            int month = newContext.getParsed(MONTH_OF_YEAR).intValue();
+            int day = newContext.getParsed(DAY_OF_MONTH).intValue();
+            int hour = newContext.getParsed(HOUR_OF_DAY).intValue();
+            int min = newContext.getParsed(MINUTE_OF_HOUR).intValue();
+            Long secVal = newContext.getParsed(SECOND_OF_MINUTE);
+            Long nanoVal = newContext.getParsed(NANO_OF_SECOND);
+            int sec = (secVal != null ? secVal.intValue() : 0);
+            int nano = (nanoVal != null ? nanoVal.intValue() : 0);
+            int days = 0;
+            if (hour == 24 && min == 0 && sec == 0 && nano == 0) {
+                hour = 0;
+                days = 1;
+            } else if (hour == 23 && min == 59 && sec == 60) {
+                context.setParsedLeapSecond();
+                sec = 59;
+            }
+            int year = (int) yearParsed % 10_000;
+            long instantSecs;
+            try {
+                LocalDateTime ldt = LocalDateTime.of(year, month, day, hour, min, sec, 0).plusDays(days);
+                instantSecs = ldt.toEpochSecond(ZoneOffset.UTC);
+                instantSecs += Math.multiplyExact(yearParsed / 10_000L, SECONDS_PER_10000_YEARS);
+            } catch (RuntimeException ex) {
+                return ~position;
+            }
+            int successPos = pos;
+            successPos = context.setParsedField(INSTANT_SECONDS, instantSecs, position, successPos);
+            return context.setParsedField(NANO_OF_SECOND, nano, position, successPos);
+        }
+
+        @Override
+        public String toString() {
+            return "Instant()";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses an offset ID.
+     */
+    static final class OffsetIdPrinterParser implements DateTimePrinterParser {
+        static final String[] PATTERNS = new String[] {
+            "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS",
+        };  // order used in pattern builder
+        static final OffsetIdPrinterParser INSTANCE_ID_Z = new OffsetIdPrinterParser("+HH:MM:ss", "Z");
+        static final OffsetIdPrinterParser INSTANCE_ID_ZERO = new OffsetIdPrinterParser("+HH:MM:ss", "0");
+
+        private final String noOffsetText;
+        private final int type;
+
+        /**
+         * Constructor.
+         *
+         * @param pattern  the pattern
+         * @param noOffsetText  the text to use for UTC, not null
+         */
+        OffsetIdPrinterParser(String pattern, String noOffsetText) {
+            Objects.requireNonNull(pattern, "pattern");
+            Objects.requireNonNull(noOffsetText, "noOffsetText");
+            this.type = checkPattern(pattern);
+            this.noOffsetText = noOffsetText;
+        }
+
+        private int checkPattern(String pattern) {
+            for (int i = 0; i < PATTERNS.length; i++) {
+                if (PATTERNS[i].equals(pattern)) {
+                    return i;
+                }
+            }
+            throw new IllegalArgumentException("Invalid zone offset pattern: " + pattern);
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Long offsetSecs = context.getValue(OFFSET_SECONDS);
+            if (offsetSecs == null) {
+                return false;
+            }
+            int totalSecs = Math.toIntExact(offsetSecs);
+            if (totalSecs == 0) {
+                buf.append(noOffsetText);
+            } else {
+                int absHours = Math.abs((totalSecs / 3600) % 100);  // anything larger than 99 silently dropped
+                int absMinutes = Math.abs((totalSecs / 60) % 60);
+                int absSeconds = Math.abs(totalSecs % 60);
+                int bufPos = buf.length();
+                int output = absHours;
+                buf.append(totalSecs < 0 ? "-" : "+")
+                    .append((char) (absHours / 10 + '0')).append((char) (absHours % 10 + '0'));
+                if (type >= 3 || (type >= 1 && absMinutes > 0)) {
+                    buf.append((type % 2) == 0 ? ":" : "")
+                        .append((char) (absMinutes / 10 + '0')).append((char) (absMinutes % 10 + '0'));
+                    output += absMinutes;
+                    if (type >= 7 || (type >= 5 && absSeconds > 0)) {
+                        buf.append((type % 2) == 0 ? ":" : "")
+                            .append((char) (absSeconds / 10 + '0')).append((char) (absSeconds % 10 + '0'));
+                        output += absSeconds;
+                    }
+                }
+                if (output == 0) {
+                    buf.setLength(bufPos);
+                    buf.append(noOffsetText);
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            int noOffsetLen = noOffsetText.length();
+            if (noOffsetLen == 0) {
+                if (position == length) {
+                    return context.setParsedField(OFFSET_SECONDS, 0, position, position);
+                }
+            } else {
+                if (position == length) {
+                    return ~position;
+                }
+                if (context.subSequenceEquals(text, position, noOffsetText, 0, noOffsetLen)) {
+                    return context.setParsedField(OFFSET_SECONDS, 0, position, position + noOffsetLen);
+                }
+            }
+
+            // parse normal plus/minus offset
+            char sign = text.charAt(position);  // IOOBE if invalid position
+            if (sign == '+' || sign == '-') {
+                // starts
+                int negative = (sign == '-' ? -1 : 1);
+                int[] array = new int[4];
+                array[0] = position + 1;
+                if ((parseNumber(array, 1, text, true) ||
+                        parseNumber(array, 2, text, type >=3) ||
+                        parseNumber(array, 3, text, false)) == false) {
+                    // success
+                    long offsetSecs = negative * (array[1] * 3600L + array[2] * 60L + array[3]);
+                    return context.setParsedField(OFFSET_SECONDS, offsetSecs, position, array[0]);
+                }
+            }
+            // handle special case of empty no offset text
+            if (noOffsetLen == 0) {
+                return context.setParsedField(OFFSET_SECONDS, 0, position, position + noOffsetLen);
+            }
+            return ~position;
+        }
+
+        /**
+         * Parse a two digit zero-prefixed number.
+         *
+         * @param array  the array of parsed data, 0=pos,1=hours,2=mins,3=secs, not null
+         * @param arrayIndex  the index to parse the value into
+         * @param parseText  the offset ID, not null
+         * @param required  whether this number is required
+         * @return true if an error occurred
+         */
+        private boolean parseNumber(int[] array, int arrayIndex, CharSequence parseText, boolean required) {
+            if ((type + 3) / 2 < arrayIndex) {
+                return false;  // ignore seconds/minutes
+            }
+            int pos = array[0];
+            if ((type % 2) == 0 && arrayIndex > 1) {
+                if (pos + 1 > parseText.length() || parseText.charAt(pos) != ':') {
+                    return required;
+                }
+                pos++;
+            }
+            if (pos + 2 > parseText.length()) {
+                return required;
+            }
+            char ch1 = parseText.charAt(pos++);
+            char ch2 = parseText.charAt(pos++);
+            if (ch1 < '0' || ch1 > '9' || ch2 < '0' || ch2 > '9') {
+                return required;
+            }
+            int value = (ch1 - 48) * 10 + (ch2 - 48);
+            if (value < 0 || value > 59) {
+                return required;
+            }
+            array[arrayIndex] = value;
+            array[0] = pos;
+            return false;
+        }
+
+        @Override
+        public String toString() {
+            String converted = noOffsetText.replace("'", "''");
+            return "Offset(" + PATTERNS[type] + ",'" + converted + "')";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses an offset ID.
+     */
+    static final class LocalizedOffsetIdPrinterParser implements DateTimePrinterParser {
+        private final TextStyle style;
+
+        /**
+         * Constructor.
+         *
+         * @param style  the style, not null
+         */
+        LocalizedOffsetIdPrinterParser(TextStyle style) {
+            this.style = style;
+        }
+
+        private static StringBuilder appendHMS(StringBuilder buf, int t) {
+            return buf.append((char)(t / 10 + '0'))
+                      .append((char)(t % 10 + '0'));
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Long offsetSecs = context.getValue(OFFSET_SECONDS);
+            if (offsetSecs == null) {
+                return false;
+            }
+            String gmtText = "GMT";  // TODO: get localized version of 'GMT'
+            if (gmtText != null) {
+                buf.append(gmtText);
+            }
+            int totalSecs = Math.toIntExact(offsetSecs);
+            if (totalSecs != 0) {
+                int absHours = Math.abs((totalSecs / 3600) % 100);  // anything larger than 99 silently dropped
+                int absMinutes = Math.abs((totalSecs / 60) % 60);
+                int absSeconds = Math.abs(totalSecs % 60);
+                buf.append(totalSecs < 0 ? "-" : "+");
+                if (style == TextStyle.FULL) {
+                    appendHMS(buf, absHours);
+                    buf.append(':');
+                    appendHMS(buf, absMinutes);
+                    if (absSeconds != 0) {
+                       buf.append(':');
+                       appendHMS(buf, absSeconds);
+                    }
+                } else {
+                    if (absHours >= 10) {
+                        buf.append((char)(absHours / 10 + '0'));
+                    }
+                    buf.append((char)(absHours % 10 + '0'));
+                    if (absMinutes != 0 || absSeconds != 0) {
+                        buf.append(':');
+                        appendHMS(buf, absMinutes);
+                        if (absSeconds != 0) {
+                            buf.append(':');
+                            appendHMS(buf, absSeconds);
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+
+        int getDigit(CharSequence text, int position) {
+            char c = text.charAt(position);
+            if (c < '0' || c > '9') {
+                return -1;
+            }
+            return c - '0';
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int pos = position;
+            int end = pos + text.length();
+            String gmtText = "GMT";  // TODO: get localized version of 'GMT'
+            if (gmtText != null) {
+                if (!context.subSequenceEquals(text, pos, gmtText, 0, gmtText.length())) {
+                    return ~position;
+                }
+                pos += gmtText.length();
+            }
+            // parse normal plus/minus offset
+            int negative = 0;
+            if (pos == end) {
+                return context.setParsedField(OFFSET_SECONDS, 0, position, pos);
+            }
+            char sign = text.charAt(pos);  // IOOBE if invalid position
+            if (sign == '+') {
+                negative = 1;
+            } else if (sign == '-') {
+                negative = -1;
+            } else {
+                return context.setParsedField(OFFSET_SECONDS, 0, position, pos);
+            }
+            pos++;
+            int h = 0;
+            int m = 0;
+            int s = 0;
+            if (style == TextStyle.FULL) {
+                int h1 = getDigit(text, pos++);
+                int h2 = getDigit(text, pos++);
+                if (h1 < 0 || h2 < 0 || text.charAt(pos++) != ':') {
+                    return ~position;
+                }
+                h = h1 * 10 + h2;
+                int m1 = getDigit(text, pos++);
+                int m2 = getDigit(text, pos++);
+                if (m1 < 0 || m2 < 0) {
+                    return ~position;
+                }
+                m = m1 * 10 + m2;
+                if (pos + 2 < end && text.charAt(pos) == ':') {
+                    int s1 = getDigit(text, pos + 1);
+                    int s2 = getDigit(text, pos + 2);
+                    if (s1 >= 0 && s2 >= 0) {
+                        s = s1 * 10 + s2;
+                        pos += 3;
+                    }
+                }
+            } else {
+                h = getDigit(text, pos++);
+                if (h < 0) {
+                    return ~position;
+                }
+                if (pos < end) {
+                    int h2 = getDigit(text, pos);
+                    if (h2 >=0) {
+                        h = h * 10 + h2;
+                        pos++;
+                    }
+                    if (pos + 2 < end && text.charAt(pos) == ':') {
+                        if (pos + 2 < end && text.charAt(pos) == ':') {
+                            int m1 = getDigit(text, pos + 1);
+                            int m2 = getDigit(text, pos + 2);
+                            if (m1 >= 0 && m2 >= 0) {
+                                m = m1 * 10 + m2;
+                                pos += 3;
+                                if (pos + 2 < end && text.charAt(pos) == ':') {
+                                    int s1 = getDigit(text, pos + 1);
+                                    int s2 = getDigit(text, pos + 2);
+                                    if (s1 >= 0 && s2 >= 0) {
+                                        s = s1 * 10 + s2;
+                                        pos += 3;
+                                   }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            long offsetSecs = negative * (h * 3600L + m * 60L + s);
+            return context.setParsedField(OFFSET_SECONDS, offsetSecs, position, pos);
+        }
+
+        @Override
+        public String toString() {
+            return "LocalizedOffset(" + style + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a zone ID.
+     */
+    static final class ZoneTextPrinterParser extends ZoneIdPrinterParser {
+
+        /** The text style to output. */
+        private final TextStyle textStyle;
+
+        /** The preferred zoneid map */
+        private Set<String> preferredZones;
+
+        ZoneTextPrinterParser(TextStyle textStyle, Set<ZoneId> preferredZones) {
+            super(TemporalQueries.zone(), "ZoneText(" + textStyle + ")");
+            this.textStyle = Objects.requireNonNull(textStyle, "textStyle");
+            if (preferredZones != null && preferredZones.size() != 0) {
+                this.preferredZones = new HashSet<>();
+                for (ZoneId id : preferredZones) {
+                    this.preferredZones.add(id.getId());
+                }
+            }
+        }
+
+        private static final int STD = 0;
+        private static final int DST = 1;
+        private static final int GENERIC = 2;
+
+        // BEGIN Android-added: Lists of types used by getDisplayName().
+        private static final TimeZoneNames.NameType[] TYPES = new TimeZoneNames.NameType[] {
+                TimeZoneNames.NameType.LONG_STANDARD,
+                TimeZoneNames.NameType.SHORT_STANDARD,
+                TimeZoneNames.NameType.LONG_DAYLIGHT,
+                TimeZoneNames.NameType.SHORT_DAYLIGHT,
+                TimeZoneNames.NameType.LONG_GENERIC,
+                TimeZoneNames.NameType.SHORT_GENERIC,
+        };
+
+        private static final TimeZoneNames.NameType[] FULL_TYPES = new TimeZoneNames.NameType[] {
+                TimeZoneNames.NameType.LONG_STANDARD,
+                TimeZoneNames.NameType.LONG_DAYLIGHT,
+                TimeZoneNames.NameType.LONG_GENERIC,
+        };
+
+        private static final TimeZoneNames.NameType[] SHORT_TYPES = new TimeZoneNames.NameType[] {
+                TimeZoneNames.NameType.SHORT_STANDARD,
+                TimeZoneNames.NameType.SHORT_DAYLIGHT,
+                TimeZoneNames.NameType.SHORT_GENERIC,
+        };
+        // END Android-added: Lists of types used by getDisplayName().
+
+        private static final Map<String, SoftReference<Map<Locale, String[]>>> cache =
+            new ConcurrentHashMap<>();
+
+        private String getDisplayName(String id, int type, Locale locale) {
+            if (textStyle == TextStyle.NARROW) {
+                return null;
+            }
+            String[] names;
+            SoftReference<Map<Locale, String[]>> ref = cache.get(id);
+            Map<Locale, String[]> perLocale = null;
+            if (ref == null || (perLocale = ref.get()) == null ||
+                (names = perLocale.get(locale)) == null) {
+                // BEGIN Android-changed: use ICU TimeZoneNames instead of TimeZoneNameUtility.
+                /*
+                names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
+                if (names == null) {
+                    return null;
+                }
+                names = Arrays.copyOfRange(names, 0, 7);
+                names[5] =
+                    TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.LONG, locale);
+                if (names[5] == null) {
+                    names[5] = names[0]; // use the id
+                }
+                names[6] =
+                    TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.SHORT, locale);
+                */
+                TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+                names = new String[TYPES.length + 1];
+                // Zeroth index used for id, other indexes based on NameType constant + 1.
+                names[0] = id;
+                String canonicalId = ZoneMeta.getCanonicalCLDRID(id);
+                timeZoneNames.getDisplayNames(canonicalId, TYPES, System.currentTimeMillis(),
+                        /* dest */ names, /* destoffset */ 1);
+                if (names == null) {
+                    return null;
+                }
+                if (names[1] == null || names[2] == null || names[3] == null || names[4] == null) {
+                    // Use "GMT+XX:XX" analogous to java.util.TimeZone.getDisplayName()
+                    TimeZone tz = TimeZone.getTimeZone(id);
+                    String stdString = TimeZone.createGmtOffsetString(
+                            /* includeGmt */ true, /* includeMinuteSeparator */ true,
+                            tz.getRawOffset());
+                    String dstString = TimeZone.createGmtOffsetString(
+                            /* includeGmt */ true, /* includeMinuteSeparator */ true,
+                            tz.getRawOffset() + tz.getDSTSavings());
+                    names[1] = names[1] != null ? names[1] : stdString;
+                    names[2] = names[2] != null ? names[2] : stdString;
+                    names[3] = names[3] != null ? names[3] : dstString;
+                    names[4] = names[4] != null ? names[4] : dstString;
+                }
+                if (names[5] == null) {
+                    names[5] = names[0]; // use the id
+                }
+                // END Android-changed: use ICU TimeZoneNames instead of TimeZoneNameUtility.
+                if (names[6] == null) {
+                    names[6] = names[0];
+                }
+                if (perLocale == null) {
+                    perLocale = new ConcurrentHashMap<>();
+                }
+                perLocale.put(locale, names);
+                cache.put(id, new SoftReference<>(perLocale));
+            }
+            switch (type) {
+            case STD:
+                return names[textStyle.zoneNameStyleIndex() + 1];
+            case DST:
+                return names[textStyle.zoneNameStyleIndex() + 3];
+            }
+            return names[textStyle.zoneNameStyleIndex() + 5];
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            ZoneId zone = context.getValue(TemporalQueries.zoneId());
+            if (zone == null) {
+                return false;
+            }
+            String zname = zone.getId();
+            if (!(zone instanceof ZoneOffset)) {
+                TemporalAccessor dt = context.getTemporal();
+                String name = getDisplayName(zname,
+                                             dt.isSupported(ChronoField.INSTANT_SECONDS)
+                                             ? (zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD)
+                                             : GENERIC,
+                                             context.getLocale());
+                if (name != null) {
+                    zname = name;
+                }
+            }
+            buf.append(zname);
+            return true;
+        }
+
+        // cache per instance for now
+        private final Map<Locale, Entry<Integer, SoftReference<PrefixTree>>>
+            cachedTree = new HashMap<>();
+        private final Map<Locale, Entry<Integer, SoftReference<PrefixTree>>>
+            cachedTreeCI = new HashMap<>();
+
+        @Override
+        protected PrefixTree getTree(DateTimeParseContext context) {
+            if (textStyle == TextStyle.NARROW) {
+                return super.getTree(context);
+            }
+            Locale locale = context.getLocale();
+            boolean isCaseSensitive = context.isCaseSensitive();
+            Set<String> regionIds = ZoneRulesProvider.getAvailableZoneIds();
+            int regionIdsSize = regionIds.size();
+
+            Map<Locale, Entry<Integer, SoftReference<PrefixTree>>> cached =
+                isCaseSensitive ? cachedTree : cachedTreeCI;
+
+            Entry<Integer, SoftReference<PrefixTree>> entry = null;
+            PrefixTree tree = null;
+            String[][] zoneStrings = null;
+            if ((entry = cached.get(locale)) == null ||
+                (entry.getKey() != regionIdsSize ||
+                (tree = entry.getValue().get()) == null)) {
+                tree = PrefixTree.newTree(context);
+                // BEGIN Android-changed: use ICU TimeZoneNames to get Zone names.
+                /*
+                zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
+                for (String[] names : zoneStrings) {
+                    String zid = names[0];
+                    if (!regionIds.contains(zid)) {
+                        continue;
+                    }
+                    tree.add(zid, zid);    // don't convert zid -> metazone
+                    zid = ZoneName.toZid(zid, locale);
+                    int i = textStyle == TextStyle.FULL ? 1 : 2;
+                    for (; i < names.length; i += 2) {
+                        tree.add(names[i], zid);
+                    }
+                }
+                // if we have a set of preferred zones, need a copy and
+                // add the preferred zones again to overwrite
+                if (preferredZones != null) {
+                    for (String[] names : zoneStrings) {
+                        String zid = names[0];
+                        if (!preferredZones.contains(zid) || !regionIds.contains(zid)) {
+                            continue;
+                        }
+                        int i = textStyle == TextStyle.FULL ? 1 : 2;
+                        for (; i < names.length; i += 2) {
+                            tree.add(names[i], zid);
+                       }
+                    }
+                }
+                */
+                TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+                long now = System.currentTimeMillis();
+                TimeZoneNames.NameType[] types =
+                        textStyle == TextStyle.FULL ? FULL_TYPES : SHORT_TYPES;
+                String[] names = new String[types.length];
+                for (String zid : regionIds) {
+                    tree.add(zid, zid);    // don't convert zid -> metazone
+                    zid = ZoneName.toZid(zid, locale);
+                    timeZoneNames.getDisplayNames(zid, types, now, names, 0);
+                    for (int i = 0; i < names.length; i++) {
+                        if (names[i] != null) {
+                            tree.add(names[i], zid);
+                        }
+                    }
+                }
+                // if we have a set of preferred zones, need a copy and
+                // add the preferred zones again to overwrite
+                if (preferredZones != null) {
+                    for (String zid : regionIds) {
+                        if (!preferredZones.contains(zid)) {
+                            continue;
+                        }
+                        String canonicalId = ZoneName.toZid(zid, locale);
+                        timeZoneNames.getDisplayNames(canonicalId, types, now, names, 0);
+                        for (int i = 0; i < names.length; i++) {
+                            if (names[i] != null) {
+                                tree.add(names[i], zid);
+                            }
+                        }
+                    }
+                }
+                // END Android-changed: use ICU TimeZoneNames to get Zone names.
+                cached.put(locale, new SimpleImmutableEntry<>(regionIdsSize, new SoftReference<>(tree)));
+            }
+            return tree;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a zone ID.
+     */
+    static class ZoneIdPrinterParser implements DateTimePrinterParser {
+        private final TemporalQuery<ZoneId> query;
+        private final String description;
+
+        ZoneIdPrinterParser(TemporalQuery<ZoneId> query, String description) {
+            this.query = query;
+            this.description = description;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            ZoneId zone = context.getValue(query);
+            if (zone == null) {
+                return false;
+            }
+            buf.append(zone.getId());
+            return true;
+        }
+
+        /**
+         * The cached tree to speed up parsing.
+         */
+        private static volatile Entry<Integer, PrefixTree> cachedPrefixTree;
+        private static volatile Entry<Integer, PrefixTree> cachedPrefixTreeCI;
+
+        protected PrefixTree getTree(DateTimeParseContext context) {
+            // prepare parse tree
+            Set<String> regionIds = ZoneRulesProvider.getAvailableZoneIds();
+            final int regionIdsSize = regionIds.size();
+            Entry<Integer, PrefixTree> cached = context.isCaseSensitive()
+                                                ? cachedPrefixTree : cachedPrefixTreeCI;
+            if (cached == null || cached.getKey() != regionIdsSize) {
+                synchronized (this) {
+                    cached = context.isCaseSensitive() ? cachedPrefixTree : cachedPrefixTreeCI;
+                    if (cached == null || cached.getKey() != regionIdsSize) {
+                        cached = new SimpleImmutableEntry<>(regionIdsSize, PrefixTree.newTree(regionIds, context));
+                        if (context.isCaseSensitive()) {
+                            cachedPrefixTree = cached;
+                        } else {
+                            cachedPrefixTreeCI = cached;
+                        }
+                    }
+                }
+            }
+            return cached.getValue();
+        }
+
+        /**
+         * This implementation looks for the longest matching string.
+         * For example, parsing Etc/GMT-2 will return Etc/GMC-2 rather than just
+         * Etc/GMC although both are valid.
+         */
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            int length = text.length();
+            if (position > length) {
+                throw new IndexOutOfBoundsException();
+            }
+            if (position == length) {
+                return ~position;
+            }
+
+            // handle fixed time-zone IDs
+            char nextChar = text.charAt(position);
+            if (nextChar == '+' || nextChar == '-') {
+                return parseOffsetBased(context, text, position, position, OffsetIdPrinterParser.INSTANCE_ID_Z);
+            } else if (length >= position + 2) {
+                char nextNextChar = text.charAt(position + 1);
+                if (context.charEquals(nextChar, 'U') && context.charEquals(nextNextChar, 'T')) {
+                    if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) {
+                        return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
+                    }
+                    return parseOffsetBased(context, text, position, position + 2, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
+                } else if (context.charEquals(nextChar, 'G') && length >= position + 3 &&
+                        context.charEquals(nextNextChar, 'M') && context.charEquals(text.charAt(position + 2), 'T')) {
+                    return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO);
+                }
+            }
+
+            // parse
+            PrefixTree tree = getTree(context);
+            ParsePosition ppos = new ParsePosition(position);
+            String parsedZoneId = tree.match(text, ppos);
+            if (parsedZoneId == null) {
+                if (context.charEquals(nextChar, 'Z')) {
+                    context.setParsed(ZoneOffset.UTC);
+                    return position + 1;
+                }
+                return ~position;
+            }
+            context.setParsed(ZoneId.of(parsedZoneId));
+            return ppos.getIndex();
+        }
+
+        /**
+         * Parse an offset following a prefix and set the ZoneId if it is valid.
+         * To matching the parsing of ZoneId.of the values are not normalized
+         * to ZoneOffsets.
+         *
+         * @param context the parse context
+         * @param text the input text
+         * @param prefixPos start of the prefix
+         * @param position start of text after the prefix
+         * @param parser parser for the value after the prefix
+         * @return the position after the parse
+         */
+        private int parseOffsetBased(DateTimeParseContext context, CharSequence text, int prefixPos, int position, OffsetIdPrinterParser parser) {
+            String prefix = text.toString().substring(prefixPos, position).toUpperCase();
+            if (position >= text.length()) {
+                context.setParsed(ZoneId.of(prefix));
+                return position;
+            }
+
+            // Android-added: "GMT0" is considered a valid ZoneId.
+            if (text.charAt(position) == '0' && prefix.equals("GMT")) {
+                context.setParsed(ZoneId.of("GMT0"));
+                return position + 1;
+            }
+
+            // '0' or 'Z' after prefix is not part of a valid ZoneId; use bare prefix
+            if (text.charAt(position) == '0' ||
+                context.charEquals(text.charAt(position), 'Z')) {
+                context.setParsed(ZoneId.of(prefix));
+                return position;
+            }
+
+            DateTimeParseContext newContext = context.copy();
+            int endPos = parser.parse(newContext, text, position);
+            try {
+                if (endPos < 0) {
+                    if (parser == OffsetIdPrinterParser.INSTANCE_ID_Z) {
+                        return ~prefixPos;
+                    }
+                    context.setParsed(ZoneId.of(prefix));
+                    return position;
+                }
+                int offset = (int) newContext.getParsed(OFFSET_SECONDS).longValue();
+                ZoneOffset zoneOffset = ZoneOffset.ofTotalSeconds(offset);
+                context.setParsed(ZoneId.ofOffset(prefix, zoneOffset));
+                return endPos;
+            } catch (DateTimeException dte) {
+                return ~prefixPos;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return description;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A String based prefix tree for parsing time-zone names.
+     */
+    static class PrefixTree {
+        protected String key;
+        protected String value;
+        protected char c0;    // performance optimization to avoid the
+                              // boundary check cost of key.charat(0)
+        protected PrefixTree child;
+        protected PrefixTree sibling;
+
+        private PrefixTree(String k, String v, PrefixTree child) {
+            this.key = k;
+            this.value = v;
+            this.child = child;
+            if (k.length() == 0){
+                c0 = 0xffff;
+            } else {
+                c0 = key.charAt(0);
+            }
+        }
+
+        /**
+         * Creates a new prefix parsing tree based on parse context.
+         *
+         * @param context  the parse context
+         * @return the tree, not null
+         */
+        public static PrefixTree newTree(DateTimeParseContext context) {
+            //if (!context.isStrict()) {
+            //    return new LENIENT("", null, null);
+            //}
+            if (context.isCaseSensitive()) {
+                return new PrefixTree("", null, null);
+            }
+            return new CI("", null, null);
+        }
+
+        /**
+         * Creates a new prefix parsing tree.
+         *
+         * @param keys  a set of strings to build the prefix parsing tree, not null
+         * @param context  the parse context
+         * @return the tree, not null
+         */
+        public static  PrefixTree newTree(Set<String> keys, DateTimeParseContext context) {
+            PrefixTree tree = newTree(context);
+            for (String k : keys) {
+                tree.add0(k, k);
+            }
+            return tree;
+        }
+
+        /**
+         * Clone a copy of this tree
+         */
+        public PrefixTree copyTree() {
+            PrefixTree copy = new PrefixTree(key, value, null);
+            if (child != null) {
+                copy.child = child.copyTree();
+            }
+            if (sibling != null) {
+                copy.sibling = sibling.copyTree();
+            }
+            return copy;
+        }
+
+
+        /**
+         * Adds a pair of {key, value} into the prefix tree.
+         *
+         * @param k  the key, not null
+         * @param v  the value, not null
+         * @return  true if the pair is added successfully
+         */
+        public boolean add(String k, String v) {
+            return add0(k, v);
+        }
+
+        private boolean add0(String k, String v) {
+            k = toKey(k);
+            int prefixLen = prefixLength(k);
+            if (prefixLen == key.length()) {
+                if (prefixLen < k.length()) {  // down the tree
+                    String subKey = k.substring(prefixLen);
+                    PrefixTree c = child;
+                    while (c != null) {
+                        if (isEqual(c.c0, subKey.charAt(0))) {
+                            return c.add0(subKey, v);
+                        }
+                        c = c.sibling;
+                    }
+                    // add the node as the child of the current node
+                    c = newNode(subKey, v, null);
+                    c.sibling = child;
+                    child = c;
+                    return true;
+                }
+                // have an existing <key, value> already, overwrite it
+                // if (value != null) {
+                //    return false;
+                //}
+                value = v;
+                return true;
+            }
+            // split the existing node
+            PrefixTree n1 = newNode(key.substring(prefixLen), value, child);
+            key = k.substring(0, prefixLen);
+            child = n1;
+            if (prefixLen < k.length()) {
+                PrefixTree n2 = newNode(k.substring(prefixLen), v, null);
+                child.sibling = n2;
+                value = null;
+            } else {
+                value = v;
+            }
+            return true;
+        }
+
+        /**
+         * Match text with the prefix tree.
+         *
+         * @param text  the input text to parse, not null
+         * @param off  the offset position to start parsing at
+         * @param end  the end position to stop parsing
+         * @return the resulting string, or null if no match found.
+         */
+        public String match(CharSequence text, int off, int end) {
+            if (!prefixOf(text, off, end)){
+                return null;
+            }
+            if (child != null && (off += key.length()) != end) {
+                PrefixTree c = child;
+                do {
+                    if (isEqual(c.c0, text.charAt(off))) {
+                        String found = c.match(text, off, end);
+                        if (found != null) {
+                            return found;
+                        }
+                        return value;
+                    }
+                    c = c.sibling;
+                } while (c != null);
+            }
+            return value;
+        }
+
+        /**
+         * Match text with the prefix tree.
+         *
+         * @param text  the input text to parse, not null
+         * @param pos  the position to start parsing at, from 0 to the text
+         *  length. Upon return, position will be updated to the new parse
+         *  position, or unchanged, if no match found.
+         * @return the resulting string, or null if no match found.
+         */
+        public String match(CharSequence text, ParsePosition pos) {
+            int off = pos.getIndex();
+            int end = text.length();
+            if (!prefixOf(text, off, end)){
+                return null;
+            }
+            off += key.length();
+            if (child != null && off != end) {
+                PrefixTree c = child;
+                do {
+                    if (isEqual(c.c0, text.charAt(off))) {
+                        pos.setIndex(off);
+                        String found = c.match(text, pos);
+                        if (found != null) {
+                            return found;
+                        }
+                        break;
+                    }
+                    c = c.sibling;
+                } while (c != null);
+            }
+            pos.setIndex(off);
+            return value;
+        }
+
+        protected String toKey(String k) {
+            return k;
+        }
+
+        protected PrefixTree newNode(String k, String v, PrefixTree child) {
+            return new PrefixTree(k, v, child);
+        }
+
+        protected boolean isEqual(char c1, char c2) {
+            return c1 == c2;
+        }
+
+        protected boolean prefixOf(CharSequence text, int off, int end) {
+            if (text instanceof String) {
+                return ((String)text).startsWith(key, off);
+            }
+            int len = key.length();
+            if (len > end - off) {
+                return false;
+            }
+            int off0 = 0;
+            while (len-- > 0) {
+                if (!isEqual(key.charAt(off0++), text.charAt(off++))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private int prefixLength(String k) {
+            int off = 0;
+            while (off < k.length() && off < key.length()) {
+                if (!isEqual(k.charAt(off), key.charAt(off))) {
+                    return off;
+                }
+                off++;
+            }
+            return off;
+        }
+
+        /**
+         * Case Insensitive prefix tree.
+         */
+        private static class CI extends PrefixTree {
+
+            private CI(String k, String v, PrefixTree child) {
+                super(k, v, child);
+            }
+
+            @Override
+            protected CI newNode(String k, String v, PrefixTree child) {
+                return new CI(k, v, child);
+            }
+
+            @Override
+            protected boolean isEqual(char c1, char c2) {
+                return DateTimeParseContext.charEqualsIgnoreCase(c1, c2);
+            }
+
+            @Override
+            protected boolean prefixOf(CharSequence text, int off, int end) {
+                int len = key.length();
+                if (len > end - off) {
+                    return false;
+                }
+                int off0 = 0;
+                while (len-- > 0) {
+                    if (!isEqual(key.charAt(off0++), text.charAt(off++))) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+
+        /**
+         * Lenient prefix tree. Case insensitive and ignores characters
+         * like space, underscore and slash.
+         */
+        private static class LENIENT extends CI {
+
+            private LENIENT(String k, String v, PrefixTree child) {
+                super(k, v, child);
+            }
+
+            @Override
+            protected CI newNode(String k, String v, PrefixTree child) {
+                return new LENIENT(k, v, child);
+            }
+
+            private boolean isLenientChar(char c) {
+                return c == ' ' || c == '_' || c == '/';
+            }
+
+            protected String toKey(String k) {
+                for (int i = 0; i < k.length(); i++) {
+                    if (isLenientChar(k.charAt(i))) {
+                        StringBuilder sb = new StringBuilder(k.length());
+                        sb.append(k, 0, i);
+                        i++;
+                        while (i < k.length()) {
+                            if (!isLenientChar(k.charAt(i))) {
+                                sb.append(k.charAt(i));
+                            }
+                            i++;
+                        }
+                        return sb.toString();
+                    }
+                }
+                return k;
+            }
+
+            @Override
+            public String match(CharSequence text, ParsePosition pos) {
+                int off = pos.getIndex();
+                int end = text.length();
+                int len = key.length();
+                int koff = 0;
+                while (koff < len && off < end) {
+                    if (isLenientChar(text.charAt(off))) {
+                        off++;
+                        continue;
+                    }
+                    if (!isEqual(key.charAt(koff++), text.charAt(off++))) {
+                        return null;
+                    }
+                }
+                if (koff != len) {
+                    return null;
+                }
+                if (child != null && off != end) {
+                    int off0 = off;
+                    while (off0 < end && isLenientChar(text.charAt(off0))) {
+                        off0++;
+                    }
+                    if (off0 < end) {
+                        PrefixTree c = child;
+                        do {
+                            if (isEqual(c.c0, text.charAt(off0))) {
+                                pos.setIndex(off0);
+                                String found = c.match(text, pos);
+                                if (found != null) {
+                                    return found;
+                                }
+                                break;
+                            }
+                            c = c.sibling;
+                        } while (c != null);
+                    }
+                }
+                pos.setIndex(off);
+                return value;
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a chronology.
+     */
+    static final class ChronoPrinterParser implements DateTimePrinterParser {
+        /** The text style to output, null means the ID. */
+        private final TextStyle textStyle;
+
+        ChronoPrinterParser(TextStyle textStyle) {
+            // validated by caller
+            this.textStyle = textStyle;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Chronology chrono = context.getValue(TemporalQueries.chronology());
+            if (chrono == null) {
+                return false;
+            }
+            if (textStyle == null) {
+                buf.append(chrono.getId());
+            } else {
+                buf.append(getChronologyName(chrono, context.getLocale()));
+            }
+            return true;
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            // simple looping parser to find the chronology
+            if (position < 0 || position > text.length()) {
+                throw new IndexOutOfBoundsException();
+            }
+            Set<Chronology> chronos = Chronology.getAvailableChronologies();
+            Chronology bestMatch = null;
+            int matchLen = -1;
+            for (Chronology chrono : chronos) {
+                String name;
+                if (textStyle == null) {
+                    name = chrono.getId();
+                } else {
+                    name = getChronologyName(chrono, context.getLocale());
+                }
+                int nameLen = name.length();
+                if (nameLen > matchLen && context.subSequenceEquals(text, position, name, 0, nameLen)) {
+                    bestMatch = chrono;
+                    matchLen = nameLen;
+                }
+            }
+            if (bestMatch == null) {
+                return ~position;
+            }
+            context.setParsed(bestMatch);
+            return position + matchLen;
+        }
+
+        /**
+         * Returns the chronology name of the given chrono in the given locale
+         * if available, or the chronology Id otherwise. The regular ResourceBundle
+         * search path is used for looking up the chronology name.
+         *
+         * @param chrono  the chronology, not null
+         * @param locale  the locale, not null
+         * @return the chronology name of chrono in locale, or the id if no name is available
+         * @throws NullPointerException if chrono or locale is null
+         */
+        private String getChronologyName(Chronology chrono, Locale locale) {
+            // Android-changed: Use ICU LocaleDisplayNames. http://b/28832222
+            // String key = "calendarname." + chrono.getCalendarType();
+            // String name = DateTimeTextProvider.getLocalizedResource(key, locale);
+            LocaleDisplayNames displayNames = LocaleDisplayNames.getInstance(ULocale.forLocale(locale));
+            String name = displayNames.keyValueDisplayName("calendar", chrono.getCalendarType());
+            return name != null ? name : chrono.getId();
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a localized pattern.
+     */
+    static final class LocalizedPrinterParser implements DateTimePrinterParser {
+        /** Cache of formatters. */
+        private static final ConcurrentMap<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
+
+        private final FormatStyle dateStyle;
+        private final FormatStyle timeStyle;
+
+        /**
+         * Constructor.
+         *
+         * @param dateStyle  the date style to use, may be null
+         * @param timeStyle  the time style to use, may be null
+         */
+        LocalizedPrinterParser(FormatStyle dateStyle, FormatStyle timeStyle) {
+            // validated by caller
+            this.dateStyle = dateStyle;
+            this.timeStyle = timeStyle;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            Chronology chrono = Chronology.from(context.getTemporal());
+            return formatter(context.getLocale(), chrono).toPrinterParser(false).format(context, buf);
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            Chronology chrono = context.getEffectiveChronology();
+            return formatter(context.getLocale(), chrono).toPrinterParser(false).parse(context, text, position);
+        }
+
+        /**
+         * Gets the formatter to use.
+         * <p>
+         * The formatter will be the most appropriate to use for the date and time style in the locale.
+         * For example, some locales will use the month name while others will use the number.
+         *
+         * @param locale  the locale to use, not null
+         * @param chrono  the chronology to use, not null
+         * @return the formatter, not null
+         * @throws IllegalArgumentException if the formatter cannot be found
+         */
+        private DateTimeFormatter formatter(Locale locale, Chronology chrono) {
+            String key = chrono.getId() + '|' + locale.toString() + '|' + dateStyle + timeStyle;
+            DateTimeFormatter formatter = FORMATTER_CACHE.get(key);
+            if (formatter == null) {
+                String pattern = getLocalizedDateTimePattern(dateStyle, timeStyle, chrono, locale);
+                formatter = new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale);
+                DateTimeFormatter old = FORMATTER_CACHE.putIfAbsent(key, formatter);
+                if (old != null) {
+                    formatter = old;
+                }
+            }
+            return formatter;
+        }
+
+        @Override
+        public String toString() {
+            return "Localized(" + (dateStyle != null ? dateStyle : "") + "," +
+                (timeStyle != null ? timeStyle : "") + ")";
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Prints or parses a localized pattern from a localized field.
+     * The specific formatter and parameters is not selected until the
+     * the field is to be printed or parsed.
+     * The locale is needed to select the proper WeekFields from which
+     * the field for day-of-week, week-of-month, or week-of-year is selected.
+     */
+    static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {
+        private char chr;
+        private int count;
+
+        /**
+         * Constructor.
+         *
+         * @param chr the pattern format letter that added this PrinterParser.
+         * @param count the repeat count of the format letter
+         */
+        WeekBasedFieldPrinterParser(char chr, int count) {
+            this.chr = chr;
+            this.count = count;
+        }
+
+        @Override
+        public boolean format(DateTimePrintContext context, StringBuilder buf) {
+            return printerParser(context.getLocale()).format(context, buf);
+        }
+
+        @Override
+        public int parse(DateTimeParseContext context, CharSequence text, int position) {
+            return printerParser(context.getLocale()).parse(context, text, position);
+        }
+
+        /**
+         * Gets the printerParser to use based on the field and the locale.
+         *
+         * @param locale  the locale to use, not null
+         * @return the formatter, not null
+         * @throws IllegalArgumentException if the formatter cannot be found
+         */
+        private DateTimePrinterParser printerParser(Locale locale) {
+            WeekFields weekDef = WeekFields.of(locale);
+            TemporalField field = null;
+            switch (chr) {
+                case 'Y':
+                    field = weekDef.weekBasedYear();
+                    if (count == 2) {
+                        return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0);
+                    } else {
+                        return new NumberPrinterParser(field, count, 19,
+                                (count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1);
+                    }
+                case 'e':
+                case 'c':
+                    field = weekDef.dayOfWeek();
+                    break;
+                case 'w':
+                    field = weekDef.weekOfWeekBasedYear();
+                    break;
+                case 'W':
+                    field = weekDef.weekOfMonth();
+                    break;
+                default:
+                    throw new IllegalStateException("unreachable");
+            }
+            return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(30);
+            sb.append("Localized(");
+            if (chr == 'Y') {
+                if (count == 1) {
+                    sb.append("WeekBasedYear");
+                } else if (count == 2) {
+                    sb.append("ReducedValue(WeekBasedYear,2,2,2000-01-01)");
+                } else {
+                    sb.append("WeekBasedYear,").append(count).append(",")
+                            .append(19).append(",")
+                            .append((count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD);
+                }
+            } else {
+                switch (chr) {
+                    case 'c':
+                    case 'e':
+                        sb.append("DayOfWeek");
+                        break;
+                    case 'w':
+                        sb.append("WeekOfWeekBasedYear");
+                        break;
+                    case 'W':
+                        sb.append("WeekOfMonth");
+                        break;
+                    default:
+                        break;
+                }
+                sb.append(",");
+                sb.append(count);
+            }
+            sb.append(")");
+            return sb.toString();
+        }
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Length comparator.
+     */
+    static final Comparator<String> LENGTH_SORT = new Comparator<String>() {
+        @Override
+        public int compare(String str1, String str2) {
+            return str1.length() == str2.length() ? str1.compareTo(str2) : str1.length() - str2.length();
+        }
+    };
+}
diff --git a/java/time/format/DateTimeParseContext.java b/java/time/format/DateTimeParseContext.java
new file mode 100644
index 0000000..e3ca5e9
--- /dev/null
+++ b/java/time/format/DateTimeParseContext.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import java.time.ZoneId;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Context object used during date and time parsing.
+ * <p>
+ * This class represents the current state of the parse.
+ * It has the ability to store and retrieve the parsed values and manage optional segments.
+ * It also provides key information to the parsing methods.
+ * <p>
+ * Once parsing is complete, the {@link #toUnresolved()} is used to obtain the unresolved
+ * result data. The {@link #toResolved()} is used to obtain the resolved result.
+ *
+ * @implSpec
+ * This class is a mutable context intended for use from a single thread.
+ * Usage of the class is thread-safe within standard parsing as a new instance of this class
+ * is automatically created for each parse and parsing is single-threaded
+ *
+ * @since 1.8
+ */
+final class DateTimeParseContext {
+
+    /**
+     * The formatter, not null.
+     */
+    private DateTimeFormatter formatter;
+    /**
+     * Whether to parse using case sensitively.
+     */
+    private boolean caseSensitive = true;
+    /**
+     * Whether to parse using strict rules.
+     */
+    private boolean strict = true;
+    /**
+     * The list of parsed data.
+     */
+    private final ArrayList<Parsed> parsed = new ArrayList<>();
+    /**
+     * List of Consumers<Chronology> to be notified if the Chronology changes.
+     */
+    private ArrayList<Consumer<Chronology>> chronoListeners = null;
+
+    /**
+     * Creates a new instance of the context.
+     *
+     * @param formatter  the formatter controlling the parse, not null
+     */
+    DateTimeParseContext(DateTimeFormatter formatter) {
+        super();
+        this.formatter = formatter;
+        parsed.add(new Parsed());
+    }
+
+    /**
+     * Creates a copy of this context.
+     * This retains the case sensitive and strict flags.
+     */
+    DateTimeParseContext copy() {
+        DateTimeParseContext newContext = new DateTimeParseContext(formatter);
+        newContext.caseSensitive = caseSensitive;
+        newContext.strict = strict;
+        return newContext;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the locale.
+     * <p>
+     * This locale is used to control localization in the parse except
+     * where localization is controlled by the DecimalStyle.
+     *
+     * @return the locale, not null
+     */
+    Locale getLocale() {
+        return formatter.getLocale();
+    }
+
+    /**
+     * Gets the DecimalStyle.
+     * <p>
+     * The DecimalStyle controls the numeric parsing.
+     *
+     * @return the DecimalStyle, not null
+     */
+    DecimalStyle getDecimalStyle() {
+        return formatter.getDecimalStyle();
+    }
+
+    /**
+     * Gets the effective chronology during parsing.
+     *
+     * @return the effective parsing chronology, not null
+     */
+    Chronology getEffectiveChronology() {
+        Chronology chrono = currentParsed().chrono;
+        if (chrono == null) {
+            chrono = formatter.getChronology();
+            if (chrono == null) {
+                chrono = IsoChronology.INSTANCE;
+            }
+        }
+        return chrono;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if parsing is case sensitive.
+     *
+     * @return true if parsing is case sensitive, false if case insensitive
+     */
+    boolean isCaseSensitive() {
+        return caseSensitive;
+    }
+
+    /**
+     * Sets whether the parsing is case sensitive or not.
+     *
+     * @param caseSensitive  changes the parsing to be case sensitive or not from now on
+     */
+    void setCaseSensitive(boolean caseSensitive) {
+        this.caseSensitive = caseSensitive;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Helper to compare two {@code CharSequence} instances.
+     * This uses {@link #isCaseSensitive()}.
+     *
+     * @param cs1  the first character sequence, not null
+     * @param offset1  the offset into the first sequence, valid
+     * @param cs2  the second character sequence, not null
+     * @param offset2  the offset into the second sequence, valid
+     * @param length  the length to check, valid
+     * @return true if equal
+     */
+    boolean subSequenceEquals(CharSequence cs1, int offset1, CharSequence cs2, int offset2, int length) {
+        if (offset1 + length > cs1.length() || offset2 + length > cs2.length()) {
+            return false;
+        }
+        if (isCaseSensitive()) {
+            for (int i = 0; i < length; i++) {
+                char ch1 = cs1.charAt(offset1 + i);
+                char ch2 = cs2.charAt(offset2 + i);
+                if (ch1 != ch2) {
+                    return false;
+                }
+            }
+        } else {
+            for (int i = 0; i < length; i++) {
+                char ch1 = cs1.charAt(offset1 + i);
+                char ch2 = cs2.charAt(offset2 + i);
+                if (ch1 != ch2 && Character.toUpperCase(ch1) != Character.toUpperCase(ch2) &&
+                        Character.toLowerCase(ch1) != Character.toLowerCase(ch2)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Helper to compare two {@code char}.
+     * This uses {@link #isCaseSensitive()}.
+     *
+     * @param ch1  the first character
+     * @param ch2  the second character
+     * @return true if equal
+     */
+    boolean charEquals(char ch1, char ch2) {
+        if (isCaseSensitive()) {
+            return ch1 == ch2;
+        }
+        return charEqualsIgnoreCase(ch1, ch2);
+    }
+
+    /**
+     * Compares two characters ignoring case.
+     *
+     * @param c1  the first
+     * @param c2  the second
+     * @return true if equal
+     */
+    static boolean charEqualsIgnoreCase(char c1, char c2) {
+        return c1 == c2 ||
+                Character.toUpperCase(c1) == Character.toUpperCase(c2) ||
+                Character.toLowerCase(c1) == Character.toLowerCase(c2);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if parsing is strict.
+     * <p>
+     * Strict parsing requires exact matching of the text and sign styles.
+     *
+     * @return true if parsing is strict, false if lenient
+     */
+    boolean isStrict() {
+        return strict;
+    }
+
+    /**
+     * Sets whether parsing is strict or lenient.
+     *
+     * @param strict  changes the parsing to be strict or lenient from now on
+     */
+    void setStrict(boolean strict) {
+        this.strict = strict;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Starts the parsing of an optional segment of the input.
+     */
+    void startOptional() {
+        parsed.add(currentParsed().copy());
+    }
+
+    /**
+     * Ends the parsing of an optional segment of the input.
+     *
+     * @param successful  whether the optional segment was successfully parsed
+     */
+    void endOptional(boolean successful) {
+        if (successful) {
+            parsed.remove(parsed.size() - 2);
+        } else {
+            parsed.remove(parsed.size() - 1);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the currently active temporal objects.
+     *
+     * @return the current temporal objects, not null
+     */
+    private Parsed currentParsed() {
+        return parsed.get(parsed.size() - 1);
+    }
+
+    /**
+     * Gets the unresolved result of the parse.
+     *
+     * @return the result of the parse, not null
+     */
+    Parsed toUnresolved() {
+        return currentParsed();
+    }
+
+    /**
+     * Gets the resolved result of the parse.
+     *
+     * @return the result of the parse, not null
+     */
+    TemporalAccessor toResolved(ResolverStyle resolverStyle, Set<TemporalField> resolverFields) {
+        Parsed parsed = currentParsed();
+        parsed.chrono = getEffectiveChronology();
+        parsed.zone = (parsed.zone != null ? parsed.zone : formatter.getZone());
+        return parsed.resolve(resolverStyle, resolverFields);
+    }
+
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the first value that was parsed for the specified field.
+     * <p>
+     * This searches the results of the parse, returning the first value found
+     * for the specified field. No attempt is made to derive a value.
+     * The field may have an out of range value.
+     * For example, the day-of-month might be set to 50, or the hour to 1000.
+     *
+     * @param field  the field to query from the map, null returns null
+     * @return the value mapped to the specified field, null if field was not parsed
+     */
+    Long getParsed(TemporalField field) {
+        return currentParsed().fieldValues.get(field);
+    }
+
+    /**
+     * Stores the parsed field.
+     * <p>
+     * This stores a field-value pair that has been parsed.
+     * The value stored may be out of range for the field - no checks are performed.
+     *
+     * @param field  the field to set in the field-value map, not null
+     * @param value  the value to set in the field-value map
+     * @param errorPos  the position of the field being parsed
+     * @param successPos  the position after the field being parsed
+     * @return the new position
+     */
+    int setParsedField(TemporalField field, long value, int errorPos, int successPos) {
+        Objects.requireNonNull(field, "field");
+        Long old = currentParsed().fieldValues.put(field, value);
+        return (old != null && old.longValue() != value) ? ~errorPos : successPos;
+    }
+
+    /**
+     * Stores the parsed chronology.
+     * <p>
+     * This stores the chronology that has been parsed.
+     * No validation is performed other than ensuring it is not null.
+     * <p>
+     * The list of listeners is copied and cleared so that each
+     * listener is called only once.  A listener can add itself again
+     * if it needs to be notified of future changes.
+     *
+     * @param chrono  the parsed chronology, not null
+     */
+    void setParsed(Chronology chrono) {
+        Objects.requireNonNull(chrono, "chrono");
+        currentParsed().chrono = chrono;
+        if (chronoListeners != null && !chronoListeners.isEmpty()) {
+            @SuppressWarnings({"rawtypes", "unchecked"})
+            Consumer<Chronology>[] tmp = new Consumer[1];
+            Consumer<Chronology>[] listeners = chronoListeners.toArray(tmp);
+            chronoListeners.clear();
+            for (Consumer<Chronology> l : listeners) {
+                l.accept(chrono);
+            }
+        }
+    }
+
+    /**
+     * Adds a Consumer<Chronology> to the list of listeners to be notified
+     * if the Chronology changes.
+     * @param listener a Consumer<Chronology> to be called when Chronology changes
+     */
+    void addChronoChangedListener(Consumer<Chronology> listener) {
+        if (chronoListeners == null) {
+            chronoListeners = new ArrayList<Consumer<Chronology>>();
+        }
+        chronoListeners.add(listener);
+    }
+
+    /**
+     * Stores the parsed zone.
+     * <p>
+     * This stores the zone that has been parsed.
+     * No validation is performed other than ensuring it is not null.
+     *
+     * @param zone  the parsed zone, not null
+     */
+    void setParsed(ZoneId zone) {
+        Objects.requireNonNull(zone, "zone");
+        currentParsed().zone = zone;
+    }
+
+    /**
+     * Stores the parsed leap second.
+     */
+    void setParsedLeapSecond() {
+        currentParsed().leapSecond = true;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string version of the context for debugging.
+     *
+     * @return a string representation of the context data, not null
+     */
+    @Override
+    public String toString() {
+        return currentParsed().toString();
+    }
+
+}
diff --git a/java/time/format/DateTimeParseException.java b/java/time/format/DateTimeParseException.java
new file mode 100644
index 0000000..d02ed15
--- /dev/null
+++ b/java/time/format/DateTimeParseException.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import java.time.DateTimeException;
+
+/**
+ * An exception thrown when an error occurs during parsing.
+ * <p>
+ * This exception includes the text being parsed and the error index.
+ *
+ * @implSpec
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class DateTimeParseException extends DateTimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 4304633501674722597L;
+
+    /**
+     * The text that was being parsed.
+     */
+    private final String parsedString;
+    /**
+     * The error index in the text.
+     */
+    private final int errorIndex;
+
+    /**
+     * Constructs a new exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param parsedData  the parsed text, should not be null
+     * @param errorIndex  the index in the parsed string that was invalid, should be a valid index
+     */
+    public DateTimeParseException(String message, CharSequence parsedData, int errorIndex) {
+        super(message);
+        this.parsedString = parsedData.toString();
+        this.errorIndex = errorIndex;
+    }
+
+    /**
+     * Constructs a new exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param parsedData  the parsed text, should not be null
+     * @param errorIndex  the index in the parsed string that was invalid, should be a valid index
+     * @param cause  the cause exception, may be null
+     */
+    public DateTimeParseException(String message, CharSequence parsedData, int errorIndex, Throwable cause) {
+        super(message, cause);
+        this.parsedString = parsedData.toString();
+        this.errorIndex = errorIndex;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the string that was being parsed.
+     *
+     * @return the string that was being parsed, should not be null.
+     */
+    public String getParsedString() {
+        return parsedString;
+    }
+
+    /**
+     * Returns the index where the error was found.
+     *
+     * @return the index in the parsed string that was invalid, should be a valid index
+     */
+    public int getErrorIndex() {
+        return errorIndex;
+    }
+
+}
diff --git a/java/time/format/DateTimePrintContext.java b/java/time/format/DateTimePrintContext.java
new file mode 100644
index 0000000..543a317
--- /dev/null
+++ b/java/time/format/DateTimePrintContext.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.ValueRange;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Context object used during date and time printing.
+ * <p>
+ * This class provides a single wrapper to items used in the format.
+ *
+ * @implSpec
+ * This class is a mutable context intended for use from a single thread.
+ * Usage of the class is thread-safe within standard printing as the framework creates
+ * a new instance of the class for each format and printing is single-threaded.
+ *
+ * @since 1.8
+ */
+final class DateTimePrintContext {
+
+    /**
+     * The temporal being output.
+     */
+    private TemporalAccessor temporal;
+    /**
+     * The formatter, not null.
+     */
+    private DateTimeFormatter formatter;
+    /**
+     * Whether the current formatter is optional.
+     */
+    private int optional;
+
+    /**
+     * Creates a new instance of the context.
+     *
+     * @param temporal  the temporal object being output, not null
+     * @param formatter  the formatter controlling the format, not null
+     */
+    DateTimePrintContext(TemporalAccessor temporal, DateTimeFormatter formatter) {
+        super();
+        this.temporal = adjust(temporal, formatter);
+        this.formatter = formatter;
+    }
+
+    private static TemporalAccessor adjust(final TemporalAccessor temporal, DateTimeFormatter formatter) {
+        // normal case first (early return is an optimization)
+        Chronology overrideChrono = formatter.getChronology();
+        ZoneId overrideZone = formatter.getZone();
+        if (overrideChrono == null && overrideZone == null) {
+            return temporal;
+        }
+
+        // ensure minimal change (early return is an optimization)
+        Chronology temporalChrono = temporal.query(TemporalQueries.chronology());
+        ZoneId temporalZone = temporal.query(TemporalQueries.zoneId());
+        if (Objects.equals(overrideChrono, temporalChrono)) {
+            overrideChrono = null;
+        }
+        if (Objects.equals(overrideZone, temporalZone)) {
+            overrideZone = null;
+        }
+        if (overrideChrono == null && overrideZone == null) {
+            return temporal;
+        }
+
+        // make adjustment
+        final Chronology effectiveChrono = (overrideChrono != null ? overrideChrono : temporalChrono);
+        if (overrideZone != null) {
+            // if have zone and instant, calculation is simple, defaulting chrono if necessary
+            if (temporal.isSupported(INSTANT_SECONDS)) {
+                Chronology chrono = (effectiveChrono != null ? effectiveChrono : IsoChronology.INSTANCE);
+                return chrono.zonedDateTime(Instant.from(temporal), overrideZone);
+            }
+            // block changing zone on OffsetTime, and similar problem cases
+            if (overrideZone.normalized() instanceof ZoneOffset && temporal.isSupported(OFFSET_SECONDS) &&
+                    temporal.get(OFFSET_SECONDS) != overrideZone.getRules().getOffset(Instant.EPOCH).getTotalSeconds()) {
+                throw new DateTimeException("Unable to apply override zone '" + overrideZone +
+                        "' because the temporal object being formatted has a different offset but" +
+                        " does not represent an instant: " + temporal);
+            }
+        }
+        final ZoneId effectiveZone = (overrideZone != null ? overrideZone : temporalZone);
+        final ChronoLocalDate effectiveDate;
+        if (overrideChrono != null) {
+            if (temporal.isSupported(EPOCH_DAY)) {
+                effectiveDate = effectiveChrono.date(temporal);
+            } else {
+                // check for date fields other than epoch-day, ignoring case of converting null to ISO
+                if (!(overrideChrono == IsoChronology.INSTANCE && temporalChrono == null)) {
+                    for (ChronoField f : ChronoField.values()) {
+                        if (f.isDateBased() && temporal.isSupported(f)) {
+                            throw new DateTimeException("Unable to apply override chronology '" + overrideChrono +
+                                    "' because the temporal object being formatted contains date fields but" +
+                                    " does not represent a whole date: " + temporal);
+                        }
+                    }
+                }
+                effectiveDate = null;
+            }
+        } else {
+            effectiveDate = null;
+        }
+
+        // combine available data
+        // this is a non-standard temporal that is almost a pure delegate
+        // this better handles map-like underlying temporal instances
+        return new TemporalAccessor() {
+            @Override
+            public boolean isSupported(TemporalField field) {
+                if (effectiveDate != null && field.isDateBased()) {
+                    return effectiveDate.isSupported(field);
+                }
+                return temporal.isSupported(field);
+            }
+            @Override
+            public ValueRange range(TemporalField field) {
+                if (effectiveDate != null && field.isDateBased()) {
+                    return effectiveDate.range(field);
+                }
+                return temporal.range(field);
+            }
+            @Override
+            public long getLong(TemporalField field) {
+                if (effectiveDate != null && field.isDateBased()) {
+                    return effectiveDate.getLong(field);
+                }
+                return temporal.getLong(field);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R> R query(TemporalQuery<R> query) {
+                if (query == TemporalQueries.chronology()) {
+                    return (R) effectiveChrono;
+                }
+                if (query == TemporalQueries.zoneId()) {
+                    return (R) effectiveZone;
+                }
+                if (query == TemporalQueries.precision()) {
+                    return temporal.query(query);
+                }
+                return query.queryFrom(this);
+            }
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the temporal object being output.
+     *
+     * @return the temporal object, not null
+     */
+    TemporalAccessor getTemporal() {
+        return temporal;
+    }
+
+    /**
+     * Gets the locale.
+     * <p>
+     * This locale is used to control localization in the format output except
+     * where localization is controlled by the DecimalStyle.
+     *
+     * @return the locale, not null
+     */
+    Locale getLocale() {
+        return formatter.getLocale();
+    }
+
+    /**
+     * Gets the DecimalStyle.
+     * <p>
+     * The DecimalStyle controls the localization of numeric output.
+     *
+     * @return the DecimalStyle, not null
+     */
+    DecimalStyle getDecimalStyle() {
+        return formatter.getDecimalStyle();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Starts the printing of an optional segment of the input.
+     */
+    void startOptional() {
+        this.optional++;
+    }
+
+    /**
+     * Ends the printing of an optional segment of the input.
+     */
+    void endOptional() {
+        this.optional--;
+    }
+
+    /**
+     * Gets a value using a query.
+     *
+     * @param query  the query to use, not null
+     * @return the result, null if not found and optional is true
+     * @throws DateTimeException if the type is not available and the section is not optional
+     */
+    <R> R getValue(TemporalQuery<R> query) {
+        R result = temporal.query(query);
+        if (result == null && optional == 0) {
+            throw new DateTimeException("Unable to extract value: " + temporal.getClass());
+        }
+        return result;
+    }
+
+    /**
+     * Gets the value of the specified field.
+     * <p>
+     * This will return the value for the specified field.
+     *
+     * @param field  the field to find, not null
+     * @return the value, null if not found and optional is true
+     * @throws DateTimeException if the field is not available and the section is not optional
+     */
+    Long getValue(TemporalField field) {
+        try {
+            return temporal.getLong(field);
+        } catch (DateTimeException ex) {
+            if (optional > 0) {
+                return null;
+            }
+            throw ex;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string version of the context for debugging.
+     *
+     * @return a string representation of the context, not null
+     */
+    @Override
+    public String toString() {
+        return temporal.toString();
+    }
+
+}
diff --git a/java/time/format/DateTimeTextProvider.java b/java/time/format/DateTimeTextProvider.java
new file mode 100644
index 0000000..260196a
--- /dev/null
+++ b/java/time/format/DateTimeTextProvider.java
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import android.icu.impl.ICUData;
+import android.icu.impl.ICUResourceBundle;
+import android.icu.util.UResourceBundle;
+
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.ERA;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.chrono.JapaneseChronology;
+import java.time.temporal.ChronoField;
+import java.time.temporal.IsoFields;
+import java.time.temporal.TemporalField;
+import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import sun.util.locale.provider.CalendarDataUtility;
+
+/**
+ * A provider to obtain the textual form of a date-time field.
+ *
+ * @implSpec
+ * Implementations must be thread-safe.
+ * Implementations should cache the textual information.
+ *
+ * @since 1.8
+ */
+class DateTimeTextProvider {
+
+    /** Cache. */
+    private static final ConcurrentMap<Entry<TemporalField, Locale>, Object> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
+    /** Comparator. */
+    private static final Comparator<Entry<String, Long>> COMPARATOR = new Comparator<Entry<String, Long>>() {
+        @Override
+        public int compare(Entry<String, Long> obj1, Entry<String, Long> obj2) {
+            return obj2.getKey().length() - obj1.getKey().length();  // longest to shortest
+        }
+    };
+
+    DateTimeTextProvider() {}
+
+    /**
+     * Gets the provider of text.
+     *
+     * @return the provider, not null
+     */
+    static DateTimeTextProvider getInstance() {
+        return new DateTimeTextProvider();
+    }
+
+    /**
+     * Gets the text for the specified field, locale and style
+     * for the purpose of formatting.
+     * <p>
+     * The text associated with the value is returned.
+     * The null return value should be used if there is no applicable text, or
+     * if the text would be a numeric representation of the value.
+     *
+     * @param field  the field to get text for, not null
+     * @param value  the field value to get text for, not null
+     * @param style  the style to get text for, not null
+     * @param locale  the locale to get text for, not null
+     * @return the text for the field value, null if no text found
+     */
+    public String getText(TemporalField field, long value, TextStyle style, Locale locale) {
+        Object store = findStore(field, locale);
+        if (store instanceof LocaleStore) {
+            return ((LocaleStore) store).getText(value, style);
+        }
+        return null;
+    }
+
+    /**
+     * Gets the text for the specified chrono, field, locale and style
+     * for the purpose of formatting.
+     * <p>
+     * The text associated with the value is returned.
+     * The null return value should be used if there is no applicable text, or
+     * if the text would be a numeric representation of the value.
+     *
+     * @param chrono  the Chronology to get text for, not null
+     * @param field  the field to get text for, not null
+     * @param value  the field value to get text for, not null
+     * @param style  the style to get text for, not null
+     * @param locale  the locale to get text for, not null
+     * @return the text for the field value, null if no text found
+     */
+    public String getText(Chronology chrono, TemporalField field, long value,
+                                    TextStyle style, Locale locale) {
+        if (chrono == IsoChronology.INSTANCE
+                || !(field instanceof ChronoField)) {
+            return getText(field, value, style, locale);
+        }
+
+        int fieldIndex;
+        int fieldValue;
+        if (field == ERA) {
+            fieldIndex = Calendar.ERA;
+            if (chrono == JapaneseChronology.INSTANCE) {
+                if (value == -999) {
+                    fieldValue = 0;
+                } else {
+                    fieldValue = (int) value + 2;
+                }
+            } else {
+                fieldValue = (int) value;
+            }
+        } else if (field == MONTH_OF_YEAR) {
+            fieldIndex = Calendar.MONTH;
+            fieldValue = (int) value - 1;
+        } else if (field == DAY_OF_WEEK) {
+            fieldIndex = Calendar.DAY_OF_WEEK;
+            fieldValue = (int) value + 1;
+            if (fieldValue > 7) {
+                fieldValue = Calendar.SUNDAY;
+            }
+        } else if (field == AMPM_OF_DAY) {
+            fieldIndex = Calendar.AM_PM;
+            fieldValue = (int) value;
+        } else {
+            return null;
+        }
+        return CalendarDataUtility.retrieveJavaTimeFieldValueName(
+                chrono.getCalendarType(), fieldIndex, fieldValue, style.toCalendarStyle(), locale);
+    }
+
+    /**
+     * Gets an iterator of text to field for the specified field, locale and style
+     * for the purpose of parsing.
+     * <p>
+     * The iterator must be returned in order from the longest text to the shortest.
+     * <p>
+     * The null return value should be used if there is no applicable parsable text, or
+     * if the text would be a numeric representation of the value.
+     * Text can only be parsed if all the values for that field-style-locale combination are unique.
+     *
+     * @param field  the field to get text for, not null
+     * @param style  the style to get text for, null for all parsable text
+     * @param locale  the locale to get text for, not null
+     * @return the iterator of text to field pairs, in order from longest text to shortest text,
+     *  null if the field or style is not parsable
+     */
+    public Iterator<Entry<String, Long>> getTextIterator(TemporalField field, TextStyle style, Locale locale) {
+        Object store = findStore(field, locale);
+        if (store instanceof LocaleStore) {
+            return ((LocaleStore) store).getTextIterator(style);
+        }
+        return null;
+    }
+
+    /**
+     * Gets an iterator of text to field for the specified chrono, field, locale and style
+     * for the purpose of parsing.
+     * <p>
+     * The iterator must be returned in order from the longest text to the shortest.
+     * <p>
+     * The null return value should be used if there is no applicable parsable text, or
+     * if the text would be a numeric representation of the value.
+     * Text can only be parsed if all the values for that field-style-locale combination are unique.
+     *
+     * @param chrono  the Chronology to get text for, not null
+     * @param field  the field to get text for, not null
+     * @param style  the style to get text for, null for all parsable text
+     * @param locale  the locale to get text for, not null
+     * @return the iterator of text to field pairs, in order from longest text to shortest text,
+     *  null if the field or style is not parsable
+     */
+    public Iterator<Entry<String, Long>> getTextIterator(Chronology chrono, TemporalField field,
+                                                         TextStyle style, Locale locale) {
+        if (chrono == IsoChronology.INSTANCE
+                || !(field instanceof ChronoField)) {
+            return getTextIterator(field, style, locale);
+        }
+
+        int fieldIndex;
+        switch ((ChronoField)field) {
+        case ERA:
+            fieldIndex = Calendar.ERA;
+            break;
+        case MONTH_OF_YEAR:
+            fieldIndex = Calendar.MONTH;
+            break;
+        case DAY_OF_WEEK:
+            fieldIndex = Calendar.DAY_OF_WEEK;
+            break;
+        case AMPM_OF_DAY:
+            fieldIndex = Calendar.AM_PM;
+            break;
+        default:
+            return null;
+        }
+
+        int calendarStyle = (style == null) ? Calendar.ALL_STYLES : style.toCalendarStyle();
+        Map<String, Integer> map = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+                chrono.getCalendarType(), fieldIndex, calendarStyle, locale);
+        if (map == null) {
+            return null;
+        }
+        List<Entry<String, Long>> list = new ArrayList<>(map.size());
+        switch (fieldIndex) {
+        case Calendar.ERA:
+            for (Map.Entry<String, Integer> entry : map.entrySet()) {
+                int era = entry.getValue();
+                if (chrono == JapaneseChronology.INSTANCE) {
+                    if (era == 0) {
+                        era = -999;
+                    } else {
+                        era -= 2;
+                    }
+                }
+                list.add(createEntry(entry.getKey(), (long)era));
+            }
+            break;
+        case Calendar.MONTH:
+            for (Map.Entry<String, Integer> entry : map.entrySet()) {
+                list.add(createEntry(entry.getKey(), (long)(entry.getValue() + 1)));
+            }
+            break;
+        case Calendar.DAY_OF_WEEK:
+            for (Map.Entry<String, Integer> entry : map.entrySet()) {
+                list.add(createEntry(entry.getKey(), (long)toWeekDay(entry.getValue())));
+            }
+            break;
+        default:
+            for (Map.Entry<String, Integer> entry : map.entrySet()) {
+                list.add(createEntry(entry.getKey(), (long)entry.getValue()));
+            }
+            break;
+        }
+        return list.iterator();
+    }
+
+    private Object findStore(TemporalField field, Locale locale) {
+        Entry<TemporalField, Locale> key = createEntry(field, locale);
+        Object store = CACHE.get(key);
+        if (store == null) {
+            store = createStore(field, locale);
+            CACHE.putIfAbsent(key, store);
+            store = CACHE.get(key);
+        }
+        return store;
+    }
+
+    private static int toWeekDay(int calWeekDay) {
+        if (calWeekDay == Calendar.SUNDAY) {
+            return 7;
+        } else {
+            return calWeekDay - 1;
+        }
+    }
+
+    private Object createStore(TemporalField field, Locale locale) {
+        Map<TextStyle, Map<Long, String>> styleMap = new HashMap<>();
+        if (field == ERA) {
+            for (TextStyle textStyle : TextStyle.values()) {
+                if (textStyle.isStandalone()) {
+                    // Stand-alone isn't applicable to era names.
+                    continue;
+                }
+                Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+                        "gregory", Calendar.ERA, textStyle.toCalendarStyle(), locale);
+                if (displayNames != null) {
+                    Map<Long, String> map = new HashMap<>();
+                    for (Entry<String, Integer> entry : displayNames.entrySet()) {
+                        map.put((long) entry.getValue(), entry.getKey());
+                    }
+                    if (!map.isEmpty()) {
+                        styleMap.put(textStyle, map);
+                    }
+                }
+            }
+            return new LocaleStore(styleMap);
+        }
+
+        if (field == MONTH_OF_YEAR) {
+            for (TextStyle textStyle : TextStyle.values()) {
+                Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+                        "gregory", Calendar.MONTH, textStyle.toCalendarStyle(), locale);
+                Map<Long, String> map = new HashMap<>();
+                if (displayNames != null) {
+                    for (Entry<String, Integer> entry : displayNames.entrySet()) {
+                        map.put((long) (entry.getValue() + 1), entry.getKey());
+                    }
+
+                } else {
+                    // Narrow names may have duplicated names, such as "J" for January, Jun, July.
+                    // Get names one by one in that case.
+                    for (int month = Calendar.JANUARY; month <= Calendar.DECEMBER; month++) {
+                        String name;
+                        name = CalendarDataUtility.retrieveJavaTimeFieldValueName(
+                                "gregory", Calendar.MONTH, month, textStyle.toCalendarStyle(), locale);
+                        if (name == null) {
+                            break;
+                        }
+                        map.put((long) (month + 1), name);
+                    }
+                }
+                if (!map.isEmpty()) {
+                    styleMap.put(textStyle, map);
+                }
+            }
+            return new LocaleStore(styleMap);
+        }
+
+        if (field == DAY_OF_WEEK) {
+            for (TextStyle textStyle : TextStyle.values()) {
+                Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+                        "gregory", Calendar.DAY_OF_WEEK, textStyle.toCalendarStyle(), locale);
+                Map<Long, String> map = new HashMap<>();
+                if (displayNames != null) {
+                    for (Entry<String, Integer> entry : displayNames.entrySet()) {
+                        map.put((long)toWeekDay(entry.getValue()), entry.getKey());
+                    }
+
+                } else {
+                    // Narrow names may have duplicated names, such as "S" for Sunday and Saturday.
+                    // Get names one by one in that case.
+                    for (int wday = Calendar.SUNDAY; wday <= Calendar.SATURDAY; wday++) {
+                        String name;
+                        name = CalendarDataUtility.retrieveJavaTimeFieldValueName(
+                            "gregory", Calendar.DAY_OF_WEEK, wday, textStyle.toCalendarStyle(), locale);
+                        if (name == null) {
+                            break;
+                        }
+                        map.put((long)toWeekDay(wday), name);
+                    }
+                }
+                if (!map.isEmpty()) {
+                    styleMap.put(textStyle, map);
+                }
+            }
+            return new LocaleStore(styleMap);
+        }
+
+        if (field == AMPM_OF_DAY) {
+            for (TextStyle textStyle : TextStyle.values()) {
+                if (textStyle.isStandalone()) {
+                    // Stand-alone isn't applicable to AM/PM.
+                    continue;
+                }
+                Map<String, Integer> displayNames = CalendarDataUtility.retrieveJavaTimeFieldValueNames(
+                        "gregory", Calendar.AM_PM, textStyle.toCalendarStyle(), locale);
+                if (displayNames != null) {
+                    Map<Long, String> map = new HashMap<>();
+                    for (Entry<String, Integer> entry : displayNames.entrySet()) {
+                        map.put((long) entry.getValue(), entry.getKey());
+                    }
+                    if (!map.isEmpty()) {
+                        styleMap.put(textStyle, map);
+                    }
+                }
+            }
+            return new LocaleStore(styleMap);
+        }
+
+        if (field == IsoFields.QUARTER_OF_YEAR) {
+            // BEGIN Android-changed: Use ICU resources.
+            /*
+            // The order of keys must correspond to the TextStyle.values() order.
+            final String[] keys = {
+                "QuarterNames",
+                "standalone.QuarterNames",
+                "QuarterAbbreviations",
+                "standalone.QuarterAbbreviations",
+                "QuarterNarrows",
+                "standalone.QuarterNarrows",
+            };
+            for (int i = 0; i < keys.length; i++) {
+                String[] names = getLocalizedResource(keys[i], locale);
+                if (names != null) {
+                    Map<Long, String> map = new HashMap<>();
+                    for (int q = 0; q < names.length; q++) {
+                        map.put((long) (q + 1), names[q]);
+                    }
+                    styleMap.put(TextStyle.values()[i], map);
+                }
+            }
+            */
+            ICUResourceBundle rb = (ICUResourceBundle) UResourceBundle
+                    .getBundleInstance(ICUData.ICU_BASE_NAME, locale);
+            ICUResourceBundle quartersRb = rb.getWithFallback("calendar/gregorian/quarters");
+            ICUResourceBundle formatRb = quartersRb.getWithFallback("format");
+            ICUResourceBundle standaloneRb = quartersRb.getWithFallback("stand-alone");
+            styleMap.put(TextStyle.FULL, extractQuarters(formatRb, "wide"));
+            styleMap.put(TextStyle.FULL_STANDALONE, extractQuarters(standaloneRb, "wide"));
+            styleMap.put(TextStyle.SHORT, extractQuarters(formatRb, "abbreviated"));
+            styleMap.put(TextStyle.SHORT_STANDALONE, extractQuarters(standaloneRb, "abbreviated"));
+            styleMap.put(TextStyle.NARROW, extractQuarters(formatRb, "narrow"));
+            styleMap.put(TextStyle.NARROW_STANDALONE, extractQuarters(standaloneRb, "narrow"));
+            // END Android-changed: Use ICU resources.
+            return new LocaleStore(styleMap);
+        }
+
+        return "";  // null marker for map
+    }
+
+    // BEGIN Android-added: Extracts a Map of quarter names from ICU resource bundle.
+    private static Map<Long, String> extractQuarters(ICUResourceBundle rb, String key) {
+        String[] names = rb.getWithFallback(key).getStringArray();
+        Map<Long, String> map = new HashMap<>();
+        for (int q = 0; q < names.length; q++) {
+            map.put((long) (q + 1), names[q]);
+        }
+        return map;
+    }
+    // END Android-added: Extracts a Map of quarter names from ICU resource bundle.
+
+    /**
+     * Helper method to create an immutable entry.
+     *
+     * @param text  the text, not null
+     * @param field  the field, not null
+     * @return the entry, not null
+     */
+    private static <A, B> Entry<A, B> createEntry(A text, B field) {
+        return new SimpleImmutableEntry<>(text, field);
+    }
+
+    // BEGIN Android-removed: Android uses ICU resources and has no LocaleProviderAdapter.
+    /**
+     * Returns the localized resource of the given key and locale, or null
+     * if no localized resource is available.
+     *
+     * @param key  the key of the localized resource, not null
+     * @param locale  the locale, not null
+     * @return the localized resource, or null if not available
+     * @throws NullPointerException if key or locale is null
+     */
+    // @SuppressWarnings("unchecked")
+    // static <T> T getLocalizedResource(String key, Locale locale) {
+    //     LocaleResources lr = LocaleProviderAdapter.getResourceBundleBased()
+    //                                 .getLocaleResources(locale);
+    //     ResourceBundle rb = lr.getJavaTimeFormatData();
+    //     return rb.containsKey(key) ? (T) rb.getObject(key) : null;
+    // }
+    // END Android-removed: Android uses ICU resources and has no LocaleProviderAdapter.
+
+    /**
+     * Stores the text for a single locale.
+     * <p>
+     * Some fields have a textual representation, such as day-of-week or month-of-year.
+     * These textual representations can be captured in this class for printing
+     * and parsing.
+     * <p>
+     * This class is immutable and thread-safe.
+     */
+    static final class LocaleStore {
+        /**
+         * Map of value to text.
+         */
+        private final Map<TextStyle, Map<Long, String>> valueTextMap;
+        /**
+         * Parsable data.
+         */
+        private final Map<TextStyle, List<Entry<String, Long>>> parsable;
+
+        /**
+         * Constructor.
+         *
+         * @param valueTextMap  the map of values to text to store, assigned and not altered, not null
+         */
+        LocaleStore(Map<TextStyle, Map<Long, String>> valueTextMap) {
+            this.valueTextMap = valueTextMap;
+            Map<TextStyle, List<Entry<String, Long>>> map = new HashMap<>();
+            List<Entry<String, Long>> allList = new ArrayList<>();
+            for (Map.Entry<TextStyle, Map<Long, String>> vtmEntry : valueTextMap.entrySet()) {
+                Map<String, Entry<String, Long>> reverse = new HashMap<>();
+                for (Map.Entry<Long, String> entry : vtmEntry.getValue().entrySet()) {
+                    if (reverse.put(entry.getValue(), createEntry(entry.getValue(), entry.getKey())) != null) {
+                        // TODO: BUG: this has no effect
+                        continue;  // not parsable, try next style
+                    }
+                }
+                List<Entry<String, Long>> list = new ArrayList<>(reverse.values());
+                Collections.sort(list, COMPARATOR);
+                map.put(vtmEntry.getKey(), list);
+                allList.addAll(list);
+                map.put(null, allList);
+            }
+            Collections.sort(allList, COMPARATOR);
+            this.parsable = map;
+        }
+
+        /**
+         * Gets the text for the specified field value, locale and style
+         * for the purpose of printing.
+         *
+         * @param value  the value to get text for, not null
+         * @param style  the style to get text for, not null
+         * @return the text for the field value, null if no text found
+         */
+        String getText(long value, TextStyle style) {
+            Map<Long, String> map = valueTextMap.get(style);
+            return map != null ? map.get(value) : null;
+        }
+
+        /**
+         * Gets an iterator of text to field for the specified style for the purpose of parsing.
+         * <p>
+         * The iterator must be returned in order from the longest text to the shortest.
+         *
+         * @param style  the style to get text for, null for all parsable text
+         * @return the iterator of text to field pairs, in order from longest text to shortest text,
+         *  null if the style is not parsable
+         */
+        Iterator<Entry<String, Long>> getTextIterator(TextStyle style) {
+            List<Entry<String, Long>> list = parsable.get(style);
+            return list != null ? list.iterator() : null;
+        }
+    }
+}
diff --git a/java/time/format/DecimalStyle.java b/java/time/format/DecimalStyle.java
new file mode 100644
index 0000000..484f2f2
--- /dev/null
+++ b/java/time/format/DecimalStyle.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import java.text.DecimalFormatSymbols;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Localized decimal style used in date and time formatting.
+ * <p>
+ * A significant part of dealing with dates and times is the localization.
+ * This class acts as a central point for accessing the information.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class DecimalStyle {
+
+    /**
+     * The standard set of non-localized decimal style symbols.
+     * <p>
+     * This uses standard ASCII characters for zero, positive, negative and a dot for the decimal point.
+     */
+    public static final DecimalStyle STANDARD = new DecimalStyle('0', '+', '-', '.');
+    /**
+     * The cache of DecimalStyle instances.
+     */
+    private static final ConcurrentMap<Locale, DecimalStyle> CACHE = new ConcurrentHashMap<>(16, 0.75f, 2);
+
+    /**
+     * The zero digit.
+     */
+    private final char zeroDigit;
+    /**
+     * The positive sign.
+     */
+    private final char positiveSign;
+    /**
+     * The negative sign.
+     */
+    private final char negativeSign;
+    /**
+     * The decimal separator.
+     */
+    private final char decimalSeparator;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Lists all the locales that are supported.
+     * <p>
+     * The locale 'en_US' will always be present.
+     *
+     * @return a Set of Locales for which localization is supported
+     */
+    public static Set<Locale> getAvailableLocales() {
+        Locale[] l = DecimalFormatSymbols.getAvailableLocales();
+        Set<Locale> locales = new HashSet<>(l.length);
+        Collections.addAll(locales, l);
+        return locales;
+    }
+
+    /**
+     * Obtains the DecimalStyle for the default
+     * {@link java.util.Locale.Category#FORMAT FORMAT} locale.
+     * <p>
+     * This method provides access to locale sensitive decimal style symbols.
+     * <p>
+     * This is equivalent to calling
+     * {@link #of(Locale)
+     *     of(Locale.getDefault(Locale.Category.FORMAT))}.
+     *
+     * @see java.util.Locale.Category#FORMAT
+     * @return the decimal style, not null
+     */
+    public static DecimalStyle ofDefaultLocale() {
+        return of(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Obtains the DecimalStyle for the specified locale.
+     * <p>
+     * This method provides access to locale sensitive decimal style symbols.
+     *
+     * @param locale  the locale, not null
+     * @return the decimal style, not null
+     */
+    public static DecimalStyle of(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        DecimalStyle info = CACHE.get(locale);
+        if (info == null) {
+            info = create(locale);
+            CACHE.putIfAbsent(locale, info);
+            info = CACHE.get(locale);
+        }
+        return info;
+    }
+
+    private static DecimalStyle create(Locale locale) {
+        DecimalFormatSymbols oldSymbols = DecimalFormatSymbols.getInstance(locale);
+        char zeroDigit = oldSymbols.getZeroDigit();
+        char positiveSign = '+';
+        char negativeSign = oldSymbols.getMinusSign();
+        char decimalSeparator = oldSymbols.getDecimalSeparator();
+        if (zeroDigit == '0' && negativeSign == '-' && decimalSeparator == '.') {
+            return STANDARD;
+        }
+        return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restricted constructor.
+     *
+     * @param zeroChar  the character to use for the digit of zero
+     * @param positiveSignChar  the character to use for the positive sign
+     * @param negativeSignChar  the character to use for the negative sign
+     * @param decimalPointChar  the character to use for the decimal point
+     */
+    private DecimalStyle(char zeroChar, char positiveSignChar, char negativeSignChar, char decimalPointChar) {
+        this.zeroDigit = zeroChar;
+        this.positiveSign = positiveSignChar;
+        this.negativeSign = negativeSignChar;
+        this.decimalSeparator = decimalPointChar;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents zero.
+     * <p>
+     * The character used to represent digits may vary by culture.
+     * This method specifies the zero character to use, which implies the characters for one to nine.
+     *
+     * @return the character for zero
+     */
+    public char getZeroDigit() {
+        return zeroDigit;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents zero.
+     * <p>
+     * The character used to represent digits may vary by culture.
+     * This method specifies the zero character to use, which implies the characters for one to nine.
+     *
+     * @param zeroDigit  the character for zero
+     * @return  a copy with a new character that represents zero, not null
+
+     */
+    public DecimalStyle withZeroDigit(char zeroDigit) {
+        if (zeroDigit == this.zeroDigit) {
+            return this;
+        }
+        return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents the positive sign.
+     * <p>
+     * The character used to represent a positive number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @return the character for the positive sign
+     */
+    public char getPositiveSign() {
+        return positiveSign;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents the positive sign.
+     * <p>
+     * The character used to represent a positive number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @param positiveSign  the character for the positive sign
+     * @return  a copy with a new character that represents the positive sign, not null
+     */
+    public DecimalStyle withPositiveSign(char positiveSign) {
+        if (positiveSign == this.positiveSign) {
+            return this;
+        }
+        return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents the negative sign.
+     * <p>
+     * The character used to represent a negative number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @return the character for the negative sign
+     */
+    public char getNegativeSign() {
+        return negativeSign;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents the negative sign.
+     * <p>
+     * The character used to represent a negative number may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @param negativeSign  the character for the negative sign
+     * @return  a copy with a new character that represents the negative sign, not null
+     */
+    public DecimalStyle withNegativeSign(char negativeSign) {
+        if (negativeSign == this.negativeSign) {
+            return this;
+        }
+        return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the character that represents the decimal point.
+     * <p>
+     * The character used to represent a decimal point may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @return the character for the decimal point
+     */
+    public char getDecimalSeparator() {
+        return decimalSeparator;
+    }
+
+    /**
+     * Returns a copy of the info with a new character that represents the decimal point.
+     * <p>
+     * The character used to represent a decimal point may vary by culture.
+     * This method specifies the character to use.
+     *
+     * @param decimalSeparator  the character for the decimal point
+     * @return  a copy with a new character that represents the decimal point, not null
+     */
+    public DecimalStyle withDecimalSeparator(char decimalSeparator) {
+        if (decimalSeparator == this.decimalSeparator) {
+            return this;
+        }
+        return new DecimalStyle(zeroDigit, positiveSign, negativeSign, decimalSeparator);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks whether the character is a digit, based on the currently set zero character.
+     *
+     * @param ch  the character to check
+     * @return the value, 0 to 9, of the character, or -1 if not a digit
+     */
+    int convertToDigit(char ch) {
+        int val = ch - zeroDigit;
+        return (val >= 0 && val <= 9) ? val : -1;
+    }
+
+    /**
+     * Converts the input numeric text to the internationalized form using the zero character.
+     *
+     * @param numericText  the text, consisting of digits 0 to 9, to convert, not null
+     * @return the internationalized text, not null
+     */
+    String convertNumberToI18N(String numericText) {
+        if (zeroDigit == '0') {
+            return numericText;
+        }
+        int diff = zeroDigit - '0';
+        char[] array = numericText.toCharArray();
+        for (int i = 0; i < array.length; i++) {
+            array[i] = (char) (array[i] + diff);
+        }
+        return new String(array);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this DecimalStyle is equal to another DecimalStyle.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other date
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DecimalStyle) {
+            DecimalStyle other = (DecimalStyle) obj;
+            return (zeroDigit == other.zeroDigit && positiveSign == other.positiveSign &&
+                    negativeSign == other.negativeSign && decimalSeparator == other.decimalSeparator);
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this DecimalStyle.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return zeroDigit + positiveSign + negativeSign + decimalSeparator;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing this DecimalStyle.
+     *
+     * @return a string description, not null
+     */
+    @Override
+    public String toString() {
+        return "DecimalStyle[" + zeroDigit + positiveSign + negativeSign + decimalSeparator + "]";
+    }
+
+}
diff --git a/java/time/format/FormatStyle.java b/java/time/format/FormatStyle.java
new file mode 100644
index 0000000..a5c8229
--- /dev/null
+++ b/java/time/format/FormatStyle.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+/**
+ * Enumeration of the style of a localized date, time or date-time formatter.
+ * <p>
+ * These styles are used when obtaining a date-time style from configuration.
+ * See {@link DateTimeFormatter} and {@link DateTimeFormatterBuilder} for usage.
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum FormatStyle {
+    // ordered from large to small
+
+    /**
+     * Full text style, with the most detail.
+     * For example, the format might be 'Tuesday, April 12, 1952 AD' or '3:30:42pm PST'.
+     */
+    FULL,
+    /**
+     * Long text style, with lots of detail.
+     * For example, the format might be 'January 12, 1952'.
+     */
+    LONG,
+    /**
+     * Medium text style, with some detail.
+     * For example, the format might be 'Jan 12, 1952'.
+     */
+    MEDIUM,
+    /**
+     * Short text style, typically numeric.
+     * For example, the format might be '12.13.52' or '3:30pm'.
+     */
+    SHORT;
+
+}
diff --git a/java/time/format/Parsed.java b/java/time/format/Parsed.java
new file mode 100644
index 0000000..1eb8845
--- /dev/null
+++ b/java/time/format/Parsed.java
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import static java.time.temporal.ChronoField.AMPM_OF_DAY;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.HOUR_OF_AMPM;
+import static java.time.temporal.ChronoField.HOUR_OF_DAY;
+import static java.time.temporal.ChronoField.INSTANT_SECONDS;
+import static java.time.temporal.ChronoField.MICRO_OF_DAY;
+import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
+import static java.time.temporal.ChronoField.MILLI_OF_DAY;
+import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
+import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
+import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_SECOND;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+import static java.time.temporal.ChronoField.SECOND_OF_DAY;
+import static java.time.temporal.ChronoField.SECOND_OF_MINUTE;
+
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+import java.time.chrono.Chronology;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
+import java.time.temporal.UnsupportedTemporalTypeException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A store of parsed data.
+ * <p>
+ * This class is used during parsing to collect the data. Part of the parsing process
+ * involves handling optional blocks and multiple copies of the data get created to
+ * support the necessary backtracking.
+ * <p>
+ * Once parsing is completed, this class can be used as the resultant {@code TemporalAccessor}.
+ * In most cases, it is only exposed once the fields have been resolved.
+ *
+ * @implSpec
+ * This class is a mutable context intended for use from a single thread.
+ * Usage of the class is thread-safe within standard parsing as a new instance of this class
+ * is automatically created for each parse and parsing is single-threaded
+ *
+ * @since 1.8
+ */
+final class Parsed implements TemporalAccessor {
+    // some fields are accessed using package scope from DateTimeParseContext
+
+    /**
+     * The parsed fields.
+     */
+    final Map<TemporalField, Long> fieldValues = new HashMap<>();
+    /**
+     * The parsed zone.
+     */
+    ZoneId zone;
+    /**
+     * The parsed chronology.
+     */
+    Chronology chrono;
+    /**
+     * Whether a leap-second is parsed.
+     */
+    boolean leapSecond;
+    /**
+     * The resolver style to use.
+     */
+    private ResolverStyle resolverStyle;
+    /**
+     * The resolved date.
+     */
+    private ChronoLocalDate date;
+    /**
+     * The resolved time.
+     */
+    private LocalTime time;
+    /**
+     * The excess period from time-only parsing.
+     */
+    Period excessDays = Period.ZERO;
+
+    /**
+     * Creates an instance.
+     */
+    Parsed() {
+    }
+
+    /**
+     * Creates a copy.
+     */
+    Parsed copy() {
+        // only copy fields used in parsing stage
+        Parsed cloned = new Parsed();
+        cloned.fieldValues.putAll(this.fieldValues);
+        cloned.zone = this.zone;
+        cloned.chrono = this.chrono;
+        cloned.leapSecond = this.leapSecond;
+        return cloned;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupported(TemporalField field) {
+        if (fieldValues.containsKey(field) ||
+                (date != null && date.isSupported(field)) ||
+                (time != null && time.isSupported(field))) {
+            return true;
+        }
+        return field != null && (field instanceof ChronoField == false) && field.isSupportedBy(this);
+    }
+
+    @Override
+    public long getLong(TemporalField field) {
+        Objects.requireNonNull(field, "field");
+        Long value = fieldValues.get(field);
+        if (value != null) {
+            return value;
+        }
+        if (date != null && date.isSupported(field)) {
+            return date.getLong(field);
+        }
+        if (time != null && time.isSupported(field)) {
+            return time.getLong(field);
+        }
+        if (field instanceof ChronoField) {
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        return field.getFrom(this);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zoneId()) {
+            return (R) zone;
+        } else if (query == TemporalQueries.chronology()) {
+            return (R) chrono;
+        } else if (query == TemporalQueries.localDate()) {
+            return (R) (date != null ? LocalDate.from(date) : null);
+        } else if (query == TemporalQueries.localTime()) {
+            return (R) time;
+        } else if (query == TemporalQueries.zone() || query == TemporalQueries.offset()) {
+            return query.queryFrom(this);
+        } else if (query == TemporalQueries.precision()) {
+            return null;  // not a complete date/time
+        }
+        // inline TemporalAccessor.super.query(query) as an optimization
+        // non-JDK classes are not permitted to make this optimization
+        return query.queryFrom(this);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Resolves the fields in this context.
+     *
+     * @param resolverStyle  the resolver style, not null
+     * @param resolverFields  the fields to use for resolving, null for all fields
+     * @return this, for method chaining
+     * @throws DateTimeException if resolving one field results in a value for
+     *  another field that is in conflict
+     */
+    TemporalAccessor resolve(ResolverStyle resolverStyle, Set<TemporalField> resolverFields) {
+        if (resolverFields != null) {
+            fieldValues.keySet().retainAll(resolverFields);
+        }
+        this.resolverStyle = resolverStyle;
+        resolveFields();
+        resolveTimeLenient();
+        crossCheck();
+        resolvePeriod();
+        resolveFractional();
+        resolveInstant();
+        return this;
+    }
+
+    //-----------------------------------------------------------------------
+    private void resolveFields() {
+        // resolve ChronoField
+        resolveInstantFields();
+        resolveDateFields();
+        resolveTimeFields();
+
+        // if any other fields, handle them
+        // any lenient date resolution should return epoch-day
+        if (fieldValues.size() > 0) {
+            int changedCount = 0;
+            outer:
+            while (changedCount < 50) {
+                for (Map.Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
+                    TemporalField targetField = entry.getKey();
+                    TemporalAccessor resolvedObject = targetField.resolve(fieldValues, this, resolverStyle);
+                    if (resolvedObject != null) {
+                        if (resolvedObject instanceof ChronoZonedDateTime) {
+                            ChronoZonedDateTime<?> czdt = (ChronoZonedDateTime<?>) resolvedObject;
+                            if (zone == null) {
+                                zone = czdt.getZone();
+                            } else if (zone.equals(czdt.getZone()) == false) {
+                                throw new DateTimeException("ChronoZonedDateTime must use the effective parsed zone: " + zone);
+                            }
+                            resolvedObject = czdt.toLocalDateTime();
+                        }
+                        if (resolvedObject instanceof ChronoLocalDateTime) {
+                            ChronoLocalDateTime<?> cldt = (ChronoLocalDateTime<?>) resolvedObject;
+                            updateCheckConflict(cldt.toLocalTime(), Period.ZERO);
+                            updateCheckConflict(cldt.toLocalDate());
+                            changedCount++;
+                            continue outer;  // have to restart to avoid concurrent modification
+                        }
+                        if (resolvedObject instanceof ChronoLocalDate) {
+                            updateCheckConflict((ChronoLocalDate) resolvedObject);
+                            changedCount++;
+                            continue outer;  // have to restart to avoid concurrent modification
+                        }
+                        if (resolvedObject instanceof LocalTime) {
+                            updateCheckConflict((LocalTime) resolvedObject, Period.ZERO);
+                            changedCount++;
+                            continue outer;  // have to restart to avoid concurrent modification
+                        }
+                        throw new DateTimeException("Method resolve() can only return ChronoZonedDateTime, " +
+                                "ChronoLocalDateTime, ChronoLocalDate or LocalTime");
+                    } else if (fieldValues.containsKey(targetField) == false) {
+                        changedCount++;
+                        continue outer;  // have to restart to avoid concurrent modification
+                    }
+                }
+                break;
+            }
+            if (changedCount == 50) {  // catch infinite loops
+                throw new DateTimeException("One of the parsed fields has an incorrectly implemented resolve method");
+            }
+            // if something changed then have to redo ChronoField resolve
+            if (changedCount > 0) {
+                resolveInstantFields();
+                resolveDateFields();
+                resolveTimeFields();
+            }
+        }
+    }
+
+    private void updateCheckConflict(TemporalField targetField, TemporalField changeField, Long changeValue) {
+        Long old = fieldValues.put(changeField, changeValue);
+        if (old != null && old.longValue() != changeValue.longValue()) {
+            throw new DateTimeException("Conflict found: " + changeField + " " + old +
+                    " differs from " + changeField + " " + changeValue +
+                    " while resolving  " + targetField);
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    private void resolveInstantFields() {
+        // resolve parsed instant seconds to date and time if zone available
+        if (fieldValues.containsKey(INSTANT_SECONDS)) {
+            if (zone != null) {
+                resolveInstantFields0(zone);
+            } else {
+                Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
+                if (offsetSecs != null) {
+                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
+                    resolveInstantFields0(offset);
+                }
+            }
+        }
+    }
+
+    private void resolveInstantFields0(ZoneId selectedZone) {
+        Instant instant = Instant.ofEpochSecond(fieldValues.remove(INSTANT_SECONDS));
+        ChronoZonedDateTime<?> zdt = chrono.zonedDateTime(instant, selectedZone);
+        updateCheckConflict(zdt.toLocalDate());
+        updateCheckConflict(INSTANT_SECONDS, SECOND_OF_DAY, (long) zdt.toLocalTime().toSecondOfDay());
+    }
+
+    //-----------------------------------------------------------------------
+    private void resolveDateFields() {
+        updateCheckConflict(chrono.resolveDate(fieldValues, resolverStyle));
+    }
+
+    private void updateCheckConflict(ChronoLocalDate cld) {
+        if (date != null) {
+            if (cld != null && date.equals(cld) == false) {
+                throw new DateTimeException("Conflict found: Fields resolved to two different dates: " + date + " " + cld);
+            }
+        } else if (cld != null) {
+            if (chrono.equals(cld.getChronology()) == false) {
+                throw new DateTimeException("ChronoLocalDate must use the effective parsed chronology: " + chrono);
+            }
+            date = cld;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    private void resolveTimeFields() {
+        // simplify fields
+        if (fieldValues.containsKey(CLOCK_HOUR_OF_DAY)) {
+            // lenient allows anything, smart allows 0-24, strict allows 1-24
+            long ch = fieldValues.remove(CLOCK_HOUR_OF_DAY);
+            if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
+                CLOCK_HOUR_OF_DAY.checkValidValue(ch);
+            }
+            updateCheckConflict(CLOCK_HOUR_OF_DAY, HOUR_OF_DAY, ch == 24 ? 0 : ch);
+        }
+        if (fieldValues.containsKey(CLOCK_HOUR_OF_AMPM)) {
+            // lenient allows anything, smart allows 0-12, strict allows 1-12
+            long ch = fieldValues.remove(CLOCK_HOUR_OF_AMPM);
+            if (resolverStyle == ResolverStyle.STRICT || (resolverStyle == ResolverStyle.SMART && ch != 0)) {
+                CLOCK_HOUR_OF_AMPM.checkValidValue(ch);
+            }
+            updateCheckConflict(CLOCK_HOUR_OF_AMPM, HOUR_OF_AMPM, ch == 12 ? 0 : ch);
+        }
+        if (fieldValues.containsKey(AMPM_OF_DAY) && fieldValues.containsKey(HOUR_OF_AMPM)) {
+            long ap = fieldValues.remove(AMPM_OF_DAY);
+            long hap = fieldValues.remove(HOUR_OF_AMPM);
+            if (resolverStyle == ResolverStyle.LENIENT) {
+                updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, Math.addExact(Math.multiplyExact(ap, 12), hap));
+            } else {  // STRICT or SMART
+                AMPM_OF_DAY.checkValidValue(ap);
+                HOUR_OF_AMPM.checkValidValue(ap);
+                updateCheckConflict(AMPM_OF_DAY, HOUR_OF_DAY, ap * 12 + hap);
+            }
+        }
+        if (fieldValues.containsKey(NANO_OF_DAY)) {
+            long nod = fieldValues.remove(NANO_OF_DAY);
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                NANO_OF_DAY.checkValidValue(nod);
+            }
+            updateCheckConflict(NANO_OF_DAY, HOUR_OF_DAY, nod / 3600_000_000_000L);
+            updateCheckConflict(NANO_OF_DAY, MINUTE_OF_HOUR, (nod / 60_000_000_000L) % 60);
+            updateCheckConflict(NANO_OF_DAY, SECOND_OF_MINUTE, (nod / 1_000_000_000L) % 60);
+            updateCheckConflict(NANO_OF_DAY, NANO_OF_SECOND, nod % 1_000_000_000L);
+        }
+        if (fieldValues.containsKey(MICRO_OF_DAY)) {
+            long cod = fieldValues.remove(MICRO_OF_DAY);
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                MICRO_OF_DAY.checkValidValue(cod);
+            }
+            updateCheckConflict(MICRO_OF_DAY, SECOND_OF_DAY, cod / 1_000_000L);
+            updateCheckConflict(MICRO_OF_DAY, MICRO_OF_SECOND, cod % 1_000_000L);
+        }
+        if (fieldValues.containsKey(MILLI_OF_DAY)) {
+            long lod = fieldValues.remove(MILLI_OF_DAY);
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                MILLI_OF_DAY.checkValidValue(lod);
+            }
+            updateCheckConflict(MILLI_OF_DAY, SECOND_OF_DAY, lod / 1_000);
+            updateCheckConflict(MILLI_OF_DAY, MILLI_OF_SECOND, lod % 1_000);
+        }
+        if (fieldValues.containsKey(SECOND_OF_DAY)) {
+            long sod = fieldValues.remove(SECOND_OF_DAY);
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                SECOND_OF_DAY.checkValidValue(sod);
+            }
+            updateCheckConflict(SECOND_OF_DAY, HOUR_OF_DAY, sod / 3600);
+            updateCheckConflict(SECOND_OF_DAY, MINUTE_OF_HOUR, (sod / 60) % 60);
+            updateCheckConflict(SECOND_OF_DAY, SECOND_OF_MINUTE, sod % 60);
+        }
+        if (fieldValues.containsKey(MINUTE_OF_DAY)) {
+            long mod = fieldValues.remove(MINUTE_OF_DAY);
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                MINUTE_OF_DAY.checkValidValue(mod);
+            }
+            updateCheckConflict(MINUTE_OF_DAY, HOUR_OF_DAY, mod / 60);
+            updateCheckConflict(MINUTE_OF_DAY, MINUTE_OF_HOUR, mod % 60);
+        }
+
+        // combine partial second fields strictly, leaving lenient expansion to later
+        if (fieldValues.containsKey(NANO_OF_SECOND)) {
+            long nos = fieldValues.get(NANO_OF_SECOND);
+            if (resolverStyle != ResolverStyle.LENIENT) {
+                NANO_OF_SECOND.checkValidValue(nos);
+            }
+            if (fieldValues.containsKey(MICRO_OF_SECOND)) {
+                long cos = fieldValues.remove(MICRO_OF_SECOND);
+                if (resolverStyle != ResolverStyle.LENIENT) {
+                    MICRO_OF_SECOND.checkValidValue(cos);
+                }
+                nos = cos * 1000 + (nos % 1000);
+                updateCheckConflict(MICRO_OF_SECOND, NANO_OF_SECOND, nos);
+            }
+            if (fieldValues.containsKey(MILLI_OF_SECOND)) {
+                long los = fieldValues.remove(MILLI_OF_SECOND);
+                if (resolverStyle != ResolverStyle.LENIENT) {
+                    MILLI_OF_SECOND.checkValidValue(los);
+                }
+                updateCheckConflict(MILLI_OF_SECOND, NANO_OF_SECOND, los * 1_000_000L + (nos % 1_000_000L));
+            }
+        }
+
+        // convert to time if all four fields available (optimization)
+        if (fieldValues.containsKey(HOUR_OF_DAY) && fieldValues.containsKey(MINUTE_OF_HOUR) &&
+                fieldValues.containsKey(SECOND_OF_MINUTE) && fieldValues.containsKey(NANO_OF_SECOND)) {
+            long hod = fieldValues.remove(HOUR_OF_DAY);
+            long moh = fieldValues.remove(MINUTE_OF_HOUR);
+            long som = fieldValues.remove(SECOND_OF_MINUTE);
+            long nos = fieldValues.remove(NANO_OF_SECOND);
+            resolveTime(hod, moh, som, nos);
+        }
+    }
+
+    private void resolveTimeLenient() {
+        // leniently create a time from incomplete information
+        // done after everything else as it creates information from nothing
+        // which would break updateCheckConflict(field)
+
+        if (time == null) {
+            // NANO_OF_SECOND merged with MILLI/MICRO above
+            if (fieldValues.containsKey(MILLI_OF_SECOND)) {
+                long los = fieldValues.remove(MILLI_OF_SECOND);
+                if (fieldValues.containsKey(MICRO_OF_SECOND)) {
+                    // merge milli-of-second and micro-of-second for better error message
+                    long cos = los * 1_000 + (fieldValues.get(MICRO_OF_SECOND) % 1_000);
+                    updateCheckConflict(MILLI_OF_SECOND, MICRO_OF_SECOND, cos);
+                    fieldValues.remove(MICRO_OF_SECOND);
+                    fieldValues.put(NANO_OF_SECOND, cos * 1_000L);
+                } else {
+                    // convert milli-of-second to nano-of-second
+                    fieldValues.put(NANO_OF_SECOND, los * 1_000_000L);
+                }
+            } else if (fieldValues.containsKey(MICRO_OF_SECOND)) {
+                // convert micro-of-second to nano-of-second
+                long cos = fieldValues.remove(MICRO_OF_SECOND);
+                fieldValues.put(NANO_OF_SECOND, cos * 1_000L);
+            }
+
+            // merge hour/minute/second/nano leniently
+            Long hod = fieldValues.get(HOUR_OF_DAY);
+            if (hod != null) {
+                Long moh = fieldValues.get(MINUTE_OF_HOUR);
+                Long som = fieldValues.get(SECOND_OF_MINUTE);
+                Long nos = fieldValues.get(NANO_OF_SECOND);
+
+                // check for invalid combinations that cannot be defaulted
+                if ((moh == null && (som != null || nos != null)) ||
+                        (moh != null && som == null && nos != null)) {
+                    return;
+                }
+
+                // default as necessary and build time
+                long mohVal = (moh != null ? moh : 0);
+                long somVal = (som != null ? som : 0);
+                long nosVal = (nos != null ? nos : 0);
+                resolveTime(hod, mohVal, somVal, nosVal);
+                fieldValues.remove(HOUR_OF_DAY);
+                fieldValues.remove(MINUTE_OF_HOUR);
+                fieldValues.remove(SECOND_OF_MINUTE);
+                fieldValues.remove(NANO_OF_SECOND);
+            }
+        }
+
+        // validate remaining
+        if (resolverStyle != ResolverStyle.LENIENT && fieldValues.size() > 0) {
+            for (Entry<TemporalField, Long> entry : fieldValues.entrySet()) {
+                TemporalField field = entry.getKey();
+                if (field instanceof ChronoField && field.isTimeBased()) {
+                    ((ChronoField) field).checkValidValue(entry.getValue());
+                }
+            }
+        }
+    }
+
+    private void resolveTime(long hod, long moh, long som, long nos) {
+        if (resolverStyle == ResolverStyle.LENIENT) {
+            long totalNanos = Math.multiplyExact(hod, 3600_000_000_000L);
+            totalNanos = Math.addExact(totalNanos, Math.multiplyExact(moh, 60_000_000_000L));
+            totalNanos = Math.addExact(totalNanos, Math.multiplyExact(som, 1_000_000_000L));
+            totalNanos = Math.addExact(totalNanos, nos);
+            int excessDays = (int) Math.floorDiv(totalNanos, 86400_000_000_000L);  // safe int cast
+            long nod = Math.floorMod(totalNanos, 86400_000_000_000L);
+            updateCheckConflict(LocalTime.ofNanoOfDay(nod), Period.ofDays(excessDays));
+        } else {  // STRICT or SMART
+            int mohVal = MINUTE_OF_HOUR.checkValidIntValue(moh);
+            int nosVal = NANO_OF_SECOND.checkValidIntValue(nos);
+            // handle 24:00 end of day
+            if (resolverStyle == ResolverStyle.SMART && hod == 24 && mohVal == 0 && som == 0 && nosVal == 0) {
+                updateCheckConflict(LocalTime.MIDNIGHT, Period.ofDays(1));
+            } else {
+                int hodVal = HOUR_OF_DAY.checkValidIntValue(hod);
+                int somVal = SECOND_OF_MINUTE.checkValidIntValue(som);
+                updateCheckConflict(LocalTime.of(hodVal, mohVal, somVal, nosVal), Period.ZERO);
+            }
+        }
+    }
+
+    private void resolvePeriod() {
+        // add whole days if we have both date and time
+        if (date != null && time != null && excessDays.isZero() == false) {
+            date = date.plus(excessDays);
+            excessDays = Period.ZERO;
+        }
+    }
+
+    private void resolveFractional() {
+        // ensure fractional seconds available as ChronoField requires
+        // resolveTimeLenient() will have merged MICRO_OF_SECOND/MILLI_OF_SECOND to NANO_OF_SECOND
+        if (time == null &&
+                (fieldValues.containsKey(INSTANT_SECONDS) ||
+                    fieldValues.containsKey(SECOND_OF_DAY) ||
+                    fieldValues.containsKey(SECOND_OF_MINUTE))) {
+            if (fieldValues.containsKey(NANO_OF_SECOND)) {
+                long nos = fieldValues.get(NANO_OF_SECOND);
+                fieldValues.put(MICRO_OF_SECOND, nos / 1000);
+                fieldValues.put(MILLI_OF_SECOND, nos / 1000000);
+            } else {
+                fieldValues.put(NANO_OF_SECOND, 0L);
+                fieldValues.put(MICRO_OF_SECOND, 0L);
+                fieldValues.put(MILLI_OF_SECOND, 0L);
+            }
+        }
+    }
+
+    private void resolveInstant() {
+        // add instant seconds if we have date, time and zone
+        if (date != null && time != null) {
+            if (zone != null) {
+                long instant = date.atTime(time).atZone(zone).getLong(ChronoField.INSTANT_SECONDS);
+                fieldValues.put(INSTANT_SECONDS, instant);
+            } else {
+                Long offsetSecs = fieldValues.get(OFFSET_SECONDS);
+                if (offsetSecs != null) {
+                    ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSecs.intValue());
+                    long instant = date.atTime(time).atZone(offset).getLong(ChronoField.INSTANT_SECONDS);
+                    fieldValues.put(INSTANT_SECONDS, instant);
+                }
+            }
+        }
+    }
+
+    private void updateCheckConflict(LocalTime timeToSet, Period periodToSet) {
+        if (time != null) {
+            if (time.equals(timeToSet) == false) {
+                throw new DateTimeException("Conflict found: Fields resolved to different times: " + time + " " + timeToSet);
+            }
+            if (excessDays.isZero() == false && periodToSet.isZero() == false && excessDays.equals(periodToSet) == false) {
+                throw new DateTimeException("Conflict found: Fields resolved to different excess periods: " + excessDays + " " + periodToSet);
+            } else {
+                excessDays = periodToSet;
+            }
+        } else {
+            time = timeToSet;
+            excessDays = periodToSet;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    private void crossCheck() {
+        // only cross-check date, time and date-time
+        // avoid object creation if possible
+        if (date != null) {
+            crossCheck(date);
+        }
+        if (time != null) {
+            crossCheck(time);
+            if (date != null && fieldValues.size() > 0) {
+                crossCheck(date.atTime(time));
+            }
+        }
+    }
+
+    private void crossCheck(TemporalAccessor target) {
+        for (Iterator<Entry<TemporalField, Long>> it = fieldValues.entrySet().iterator(); it.hasNext(); ) {
+            Entry<TemporalField, Long> entry = it.next();
+            TemporalField field = entry.getKey();
+            if (target.isSupported(field)) {
+                long val1;
+                try {
+                    val1 = target.getLong(field);
+                } catch (RuntimeException ex) {
+                    continue;
+                }
+                long val2 = entry.getValue();
+                if (val1 != val2) {
+                    throw new DateTimeException("Conflict found: Field " + field + " " + val1 +
+                            " differs from " + field + " " + val2 + " derived from " + target);
+                }
+                it.remove();
+            }
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(64);
+        buf.append(fieldValues).append(',').append(chrono);
+        if (zone != null) {
+            buf.append(',').append(zone);
+        }
+        if (date != null || time != null) {
+            buf.append(" resolved to ");
+            if (date != null) {
+                buf.append(date);
+                if (time != null) {
+                    buf.append('T').append(time);
+                }
+            } else {
+                buf.append(time);
+            }
+        }
+        return buf.toString();
+    }
+
+}
diff --git a/java/time/format/ResolverStyle.java b/java/time/format/ResolverStyle.java
new file mode 100644
index 0000000..313bd17
--- /dev/null
+++ b/java/time/format/ResolverStyle.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+/**
+ * Enumeration of different ways to resolve dates and times.
+ * <p>
+ * Parsing a text string occurs in two phases.
+ * Phase 1 is a basic text parse according to the fields added to the builder.
+ * Phase 2 resolves the parsed field-value pairs into date and/or time objects.
+ * This style is used to control how phase 2, resolving, happens.
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum ResolverStyle {
+
+    /**
+     * Style to resolve dates and times strictly.
+     * <p>
+     * Using strict resolution will ensure that all parsed values are within
+     * the outer range of valid values for the field. Individual fields may
+     * be further processed for strictness.
+     * <p>
+     * For example, resolving year-month and day-of-month in the ISO calendar
+     * system using strict mode will ensure that the day-of-month is valid
+     * for the year-month, rejecting invalid values.
+     */
+    STRICT,
+    /**
+     * Style to resolve dates and times in a smart, or intelligent, manner.
+     * <p>
+     * Using smart resolution will perform the sensible default for each
+     * field, which may be the same as strict, the same as lenient, or a third
+     * behavior. Individual fields will interpret this differently.
+     * <p>
+     * For example, resolving year-month and day-of-month in the ISO calendar
+     * system using smart mode will ensure that the day-of-month is from
+     * 1 to 31, converting any value beyond the last valid day-of-month to be
+     * the last valid day-of-month.
+     */
+    SMART,
+    /**
+     * Style to resolve dates and times leniently.
+     * <p>
+     * Using lenient resolution will resolve the values in an appropriate
+     * lenient manner. Individual fields will interpret this differently.
+     * <p>
+     * For example, lenient mode allows the month in the ISO calendar system
+     * to be outside the range 1 to 12.
+     * For example, month 15 is treated as being 3 months after month 12.
+     */
+    LENIENT;
+
+}
diff --git a/java/time/format/SignStyle.java b/java/time/format/SignStyle.java
new file mode 100644
index 0000000..56dfd03
--- /dev/null
+++ b/java/time/format/SignStyle.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+/**
+ * Enumeration of ways to handle the positive/negative sign.
+ * <p>
+ * The formatting engine allows the positive and negative signs of numbers
+ * to be controlled using this enum.
+ * See {@link DateTimeFormatterBuilder} for usage.
+ *
+ * @implSpec
+ * This is an immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum SignStyle {
+
+    /**
+     * Style to output the sign only if the value is negative.
+     * <p>
+     * In strict parsing, the negative sign will be accepted and the positive sign rejected.
+     * In lenient parsing, any sign will be accepted.
+     */
+    NORMAL,
+    /**
+     * Style to always output the sign, where zero will output '+'.
+     * <p>
+     * In strict parsing, the absence of a sign will be rejected.
+     * In lenient parsing, any sign will be accepted, with the absence
+     * of a sign treated as a positive number.
+     */
+    ALWAYS,
+    /**
+     * Style to never output sign, only outputting the absolute value.
+     * <p>
+     * In strict parsing, any sign will be rejected.
+     * In lenient parsing, any sign will be accepted unless the width is fixed.
+     */
+    NEVER,
+    /**
+     * Style to block negative values, throwing an exception on printing.
+     * <p>
+     * In strict parsing, any sign will be rejected.
+     * In lenient parsing, any sign will be accepted unless the width is fixed.
+     */
+    NOT_NEGATIVE,
+    /**
+     * Style to always output the sign if the value exceeds the pad width.
+     * A negative value will always output the '-' sign.
+     * <p>
+     * In strict parsing, the sign will be rejected unless the pad width is exceeded.
+     * In lenient parsing, any sign will be accepted, with the absence
+     * of a sign treated as a positive number.
+     */
+    EXCEEDS_PAD;
+
+    /**
+     * Parse helper.
+     *
+     * @param positive  true if positive sign parsed, false for negative sign
+     * @param strict  true if strict, false if lenient
+     * @param fixedWidth  true if fixed width, false if not
+     * @return
+     */
+    boolean parse(boolean positive, boolean strict, boolean fixedWidth) {
+        switch (ordinal()) {
+            case 0: // NORMAL
+                // valid if negative or (positive and lenient)
+                return !positive || !strict;
+            case 1: // ALWAYS
+            case 4: // EXCEEDS_PAD
+                return true;
+            default:
+                // valid if lenient and not fixed width
+                return !strict && !fixedWidth;
+        }
+    }
+
+}
diff --git a/java/time/format/TextStyle.java b/java/time/format/TextStyle.java
new file mode 100644
index 0000000..ed65d27
--- /dev/null
+++ b/java/time/format/TextStyle.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.format;
+
+import java.util.Calendar;
+
+/**
+ * Enumeration of the style of text formatting and parsing.
+ * <p>
+ * Text styles define three sizes for the formatted text - 'full', 'short' and 'narrow'.
+ * Each of these three sizes is available in both 'standard' and 'stand-alone' variations.
+ * <p>
+ * The difference between the three sizes is obvious in most languages.
+ * For example, in English the 'full' month is 'January', the 'short' month is 'Jan'
+ * and the 'narrow' month is 'J'. Note that the narrow size is often not unique.
+ * For example, 'January', 'June' and 'July' all have the 'narrow' text 'J'.
+ * <p>
+ * The difference between the 'standard' and 'stand-alone' forms is trickier to describe
+ * as there is no difference in English. However, in other languages there is a difference
+ * in the word used when the text is used alone, as opposed to in a complete date.
+ * For example, the word used for a month when used alone in a date picker is different
+ * to the word used for month in association with a day and year in a date.
+ *
+ * @implSpec
+ * This is immutable and thread-safe enum.
+ */
+public enum TextStyle {
+    // ordered from large to small
+    // ordered so that bit 0 of the ordinal indicates stand-alone.
+
+    /**
+     * Full text, typically the full description.
+     * For example, day-of-week Monday might output "Monday".
+     */
+    FULL(Calendar.LONG_FORMAT, 0),
+    /**
+     * Full text for stand-alone use, typically the full description.
+     * For example, day-of-week Monday might output "Monday".
+     */
+    FULL_STANDALONE(Calendar.LONG_STANDALONE, 0),
+    /**
+     * Short text, typically an abbreviation.
+     * For example, day-of-week Monday might output "Mon".
+     */
+    SHORT(Calendar.SHORT_FORMAT, 1),
+    /**
+     * Short text for stand-alone use, typically an abbreviation.
+     * For example, day-of-week Monday might output "Mon".
+     */
+    SHORT_STANDALONE(Calendar.SHORT_STANDALONE, 1),
+    /**
+     * Narrow text, typically a single letter.
+     * For example, day-of-week Monday might output "M".
+     */
+    NARROW(Calendar.NARROW_FORMAT, 1),
+    /**
+     * Narrow text for stand-alone use, typically a single letter.
+     * For example, day-of-week Monday might output "M".
+     */
+    NARROW_STANDALONE(Calendar.NARROW_STANDALONE, 1);
+
+    private final int calendarStyle;
+    private final int zoneNameStyleIndex;
+
+    private TextStyle(int calendarStyle, int zoneNameStyleIndex) {
+        this.calendarStyle = calendarStyle;
+        this.zoneNameStyleIndex = zoneNameStyleIndex;
+    }
+
+    /**
+     * Returns true if the Style is a stand-alone style.
+     * @return true if the style is a stand-alone style.
+     */
+    public boolean isStandalone() {
+        return (ordinal() & 1) == 1;
+    }
+
+    /**
+     * Returns the stand-alone style with the same size.
+     * @return the stand-alone style with the same size
+     */
+    public TextStyle asStandalone() {
+        return TextStyle.values()[ordinal()  | 1];
+    }
+
+    /**
+     * Returns the normal style with the same size.
+     *
+     * @return the normal style with the same size
+     */
+    public TextStyle asNormal() {
+        return TextStyle.values()[ordinal() & ~1];
+    }
+
+    /**
+     * Returns the {@code Calendar} style corresponding to this {@code TextStyle}.
+     *
+     * @return the corresponding {@code Calendar} style
+     */
+    int toCalendarStyle() {
+        return calendarStyle;
+    }
+
+    /**
+     * Returns the relative index value to an element of the {@link
+     * java.text.DateFormatSymbols#getZoneStrings() DateFormatSymbols.getZoneStrings()}
+     * value, 0 for long names and 1 for short names (abbreviations). Note that these values
+     * do <em>not</em> correspond to the {@link java.util.TimeZone#LONG} and {@link
+     * java.util.TimeZone#SHORT} values.
+     *
+     * @return the relative index value to time zone names array
+     */
+    int zoneNameStyleIndex() {
+        return zoneNameStyleIndex;
+    }
+}
diff --git a/java/time/format/ZoneName.java b/java/time/format/ZoneName.java
new file mode 100644
index 0000000..fe4a95a
--- /dev/null
+++ b/java/time/format/ZoneName.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.time.format;
+
+import android.icu.impl.ZoneMeta;
+import android.icu.text.TimeZoneNames;
+import android.icu.util.TimeZone;
+import android.icu.util.ULocale;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A helper class to map a zone name to metazone and back to the
+ * appropriate zone id for the particular locale.
+ * <p>
+ * The zid<->metazone mappings are based on CLDR metaZones.xml.
+ * The alias mappings are based on Link entries in tzdb data files.
+ */
+class ZoneName {
+
+    public static String toZid(String zid, Locale locale) {
+        // Android-changed: delegate to ICU.
+        TimeZoneNames tzNames = TimeZoneNames.getInstance(locale);
+        if (tzNames.getAvailableMetaZoneIDs().contains(zid)) {
+            // Compare TimeZoneFormat#getTargetRegion.
+            ULocale uLocale = ULocale.forLocale(locale);
+            String region = uLocale.getCountry();
+            if (region.length() == 0) {
+                uLocale = ULocale.addLikelySubtags(uLocale);
+                region = uLocale.getCountry();
+            }
+            zid = tzNames.getReferenceZoneID(zid, region);
+        }
+        return toZid(zid);
+    }
+
+    public static String toZid(String zid) {
+        // Android-changed: Use ICU ZoneMeta.
+        String canonicalCldrId = ZoneMeta.getCanonicalCLDRID(zid);
+        if (canonicalCldrId != null) {
+            return canonicalCldrId;
+        }
+        return zid;
+    }
+
+    // Android-removed: zidMap and aliasMap containing zone id data.
+    // Android-removed: zidToMzone, mzoneToZid, mzoneToZidL, aliases and their initialization code.
+}
diff --git a/java/time/format/package-info.java b/java/time/format/package-info.java
new file mode 100644
index 0000000..140bb6d
--- /dev/null
+++ b/java/time/format/package-info.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * Provides classes to print and parse dates and times.
+ * </p>
+ * <p>
+ * Printing and parsing is based around the
+ * {@link java.time.format.DateTimeFormatter DateTimeFormatter} class.
+ * Instances are generally obtained from
+ * {@link java.time.format.DateTimeFormatter DateTimeFormatter}, however
+ * {@link java.time.format.DateTimeFormatterBuilder DateTimeFormatterBuilder}
+ * can be used if more power is needed.
+ * </p>
+ * <p>
+ * Localization occurs by calling
+ * {@link java.time.format.DateTimeFormatter#withLocale(java.util.Locale) withLocale(Locale)}
+ * on the formatter. Further customization is possible using
+ * {@link java.time.format.DecimalStyle DecimalStyle}.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
+ * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ * The Javadoc "@param" definition is used to summarise the null-behavior.
+ * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.format;
diff --git a/java/time/package-info.java b/java/time/package-info.java
new file mode 100644
index 0000000..ea160ff
--- /dev/null
+++ b/java/time/package-info.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * The main API for dates, times, instants, and durations.
+ * </p>
+ * <p>
+ * The classes defined here represent the principle date-time concepts,
+ * including instants, durations, dates, times, time-zones and periods.
+ * They are based on the ISO calendar system, which is the <i>de facto</i> world
+ * calendar following the proleptic Gregorian rules.
+ * All the classes are immutable and thread-safe.
+ * </p>
+ * <p>
+ * Each date time instance is composed of fields that are conveniently
+ * made available by the APIs.  For lower level access to the fields refer
+ * to the {@code java.time.temporal} package.
+ * Each class includes support for printing and parsing all manner of dates and times.
+ * Refer to the {@code java.time.format} package for customization options.
+ * </p>
+ * <p>
+ * The {@code java.time.chrono} package contains the calendar neutral API
+ * {@link java.time.chrono.ChronoLocalDate ChronoLocalDate},
+ * {@link java.time.chrono.ChronoLocalDateTime ChronoLocalDateTime},
+ * {@link java.time.chrono.ChronoZonedDateTime ChronoZonedDateTime} and
+ * {@link java.time.chrono.Era Era}.
+ * This is intended for use by applications that need to use localized calendars.
+ * It is recommended that applications use the ISO-8601 date and time classes from
+ * this package across system boundaries, such as to the database or across the network.
+ * The calendar neutral API should be reserved for interactions with users.
+ * </p>
+ *
+ * <h3>Dates and Times</h3>
+ * <p>
+ * {@link java.time.Instant} is essentially a numeric timestamp.
+ * The current Instant can be retrieved from a {@link java.time.Clock}.
+ * This is useful for logging and persistence of a point in time
+ * and has in the past been associated with storing the result
+ * from {@link java.lang.System#currentTimeMillis()}.
+ * </p>
+ * <p>
+ * {@link java.time.LocalDate} stores a date without a time.
+ * This stores a date like '2010-12-03' and could be used to store a birthday.
+ * </p>
+ * <p>
+ * {@link java.time.LocalTime} stores a time without a date.
+ * This stores a time like '11:30' and could be used to store an opening or closing time.
+ * </p>
+ * <p>
+ * {@link java.time.LocalDateTime} stores a date and time.
+ * This stores a date-time like '2010-12-03T11:30'.
+ * </p>
+ * <p>
+ * {@link java.time.ZonedDateTime} stores a date and time with a time-zone.
+ * This is useful if you want to perform accurate calculations of
+ * dates and times taking into account the {@link java.time.ZoneId}, such as 'Europe/Paris'.
+ * Where possible, it is recommended to use a simpler class without a time-zone.
+ * The widespread use of time-zones tends to add considerable complexity to an application.
+ * </p>
+ *
+ * <h3>Duration and Period</h3>
+ * <p>
+ * Beyond dates and times, the API also allows the storage of periods and durations of time.
+ * A {@link java.time.Duration} is a simple measure of time along the time-line in nanoseconds.
+ * A {@link java.time.Period} expresses an amount of time in units meaningful
+ * to humans, such as years or days.
+ * </p>
+ *
+ * <h3>Additional value types</h3>
+ * <p>
+ * {@link java.time.Month} stores a month on its own.
+ * This stores a single month-of-year in isolation, such as 'DECEMBER'.
+ * </p>
+ * <p>
+ * {@link java.time.DayOfWeek} stores a day-of-week on its own.
+ * This stores a single day-of-week in isolation, such as 'TUESDAY'.
+ * </p>
+ * <p>
+ * {@link java.time.Year} stores a year on its own.
+ * This stores a single year in isolation, such as '2010'.
+ * </p>
+ * <p>
+ * {@link java.time.YearMonth} stores a year and month without a day or time.
+ * This stores a year and month, such as '2010-12' and could be used for a credit card expiry.
+ * </p>
+ * <p>
+ * {@link java.time.MonthDay} stores a month and day without a year or time.
+ * This stores a month and day-of-month, such as '--12-03' and
+ * could be used to store an annual event like a birthday without storing the year.
+ * </p>
+ * <p>
+ * {@link java.time.OffsetTime} stores a time and offset from UTC without a date.
+ * This stores a date like '11:30+01:00'.
+ * The {@link java.time.ZoneOffset ZoneOffset} is of the form '+01:00'.
+ * </p>
+ * <p>
+ * {@link java.time.OffsetDateTime} stores a date and time and offset from UTC.
+ * This stores a date-time like '2010-12-03T11:30+01:00'.
+ * This is sometimes found in XML messages and other forms of persistence,
+ * but contains less information than a full time-zone.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
+ * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ * The Javadoc "@param" definition is used to summarise the null-behavior.
+ * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ *
+ * <h3>Design notes (non normative)</h3>
+ * <p>
+ * The API has been designed to reject null early and to be clear about this behavior.
+ * A key exception is any method that takes an object and returns a boolean, for the purpose
+ * of checking or validating, will generally return false for null.
+ * </p>
+ * <p>
+ * The API is designed to be type-safe where reasonable in the main high-level API.
+ * Thus, there are separate classes for the distinct concepts of date, time and date-time,
+ * plus variants for offset and time-zone.
+ * This can seem like a lot of classes, but most applications can begin with just five date/time types.
+ * <ul>
+ * <li>{@link java.time.Instant} - a timestamp</li>
+ * <li>{@link java.time.LocalDate} - a date without a time, or any reference to an offset or time-zone</li>
+ * <li>{@link java.time.LocalTime} - a time without a date, or any reference to an offset or time-zone</li>
+ * <li>{@link java.time.LocalDateTime} - combines date and time, but still without any offset or time-zone</li>
+ * <li>{@link java.time.ZonedDateTime} - a "full" date-time with time-zone and resolved offset from UTC/Greenwich</li>
+ * </ul>
+ * <p>
+ * {@code Instant} is the closest equivalent class to {@code java.util.Date}.
+ * {@code ZonedDateTime} is the closest equivalent class to {@code java.util.GregorianCalendar}.
+ * </p>
+ * <p>
+ * Where possible, applications should use {@code LocalDate}, {@code LocalTime} and {@code LocalDateTime}
+ * to better model the domain. For example, a birthday should be stored in a code {@code LocalDate}.
+ * Bear in mind that any use of a {@linkplain java.time.ZoneId time-zone}, such as 'Europe/Paris', adds
+ * considerable complexity to a calculation.
+ * Many applications can be written only using {@code LocalDate}, {@code LocalTime} and {@code Instant},
+ * with the time-zone added at the user interface (UI) layer.
+ * </p>
+ * <p>
+ * The offset-based date-time types {@code OffsetTime} and {@code OffsetDateTime},
+ * are intended primarily for use with network protocols and database access.
+ * For example, most databases cannot automatically store a time-zone like 'Europe/Paris', but
+ * they can store an offset like '+02:00'.
+ * </p>
+ * <p>
+ * Classes are also provided for the most important sub-parts of a date, including {@code Month},
+ * {@code DayOfWeek}, {@code Year}, {@code YearMonth} and {@code MonthDay}.
+ * These can be used to model more complex date-time concepts.
+ * For example, {@code YearMonth} is useful for representing a credit card expiry.
+ * </p>
+ * <p>
+ * Note that while there are a large number of classes representing different aspects of dates,
+ * there are relatively few dealing with different aspects of time.
+ * Following type-safety to its logical conclusion would have resulted in classes for
+ * hour-minute, hour-minute-second and hour-minute-second-nanosecond.
+ * While logically pure, this was not a practical option as it would have almost tripled the
+ * number of classes due to the combinations of date and time.
+ * Thus, {@code LocalTime} is used for all precisions of time, with zeroes used to imply lower precision.
+ * </p>
+ * <p>
+ * Following full type-safety to its ultimate conclusion might also argue for a separate class
+ * for each field in date-time, such as a class for HourOfDay and another for DayOfMonth.
+ * This approach was tried, but was excessively complicated in the Java language, lacking usability.
+ * A similar problem occurs with periods.
+ * There is a case for a separate class for each period unit, such as a type for Years and a type for Minutes.
+ * However, this yields a lot of classes and a problem of type conversion.
+ * Thus, the set of date-time types provided is a compromise between purity and practicality.
+ * </p>
+ * <p>
+ * The API has a relatively large surface area in terms of number of methods.
+ * This is made manageable through the use of consistent method prefixes.
+ * <ul>
+ * <li>{@code of} - static factory method</li>
+ * <li>{@code parse} - static factory method focussed on parsing</li>
+ * <li>{@code get} - gets the value of something</li>
+ * <li>{@code is} - checks if something is true</li>
+ * <li>{@code with} - the immutable equivalent of a setter</li>
+ * <li>{@code plus} - adds an amount to an object</li>
+ * <li>{@code minus} - subtracts an amount from an object</li>
+ * <li>{@code to} - converts this object to another type</li>
+ * <li>{@code at} - combines this object with another, such as {@code date.atTime(time)}</li>
+ * </ul>
+ * <p>
+ * Multiple calendar systems is an awkward addition to the design challenges.
+ * The first principle is that most users want the standard ISO calendar system.
+ * As such, the main classes are ISO-only. The second principle is that most of those that want a
+ * non-ISO calendar system want it for user interaction, thus it is a UI localization issue.
+ * As such, date and time objects should be held as ISO objects in the data model and persistent
+ * storage, only being converted to and from a local calendar for display.
+ * The calendar system would be stored separately in the user preferences.
+ * </p>
+ * <p>
+ * There are, however, some limited use cases where users believe they need to store and use
+ * dates in arbitrary calendar systems throughout the application.
+ * This is supported by {@link java.time.chrono.ChronoLocalDate}, however it is vital to read
+ * all the associated warnings in the Javadoc of that interface before using it.
+ * In summary, applications that require general interoperation between multiple calendar systems
+ * typically need to be written in a very different way to those only using the ISO calendar,
+ * thus most applications should just use ISO and avoid {@code ChronoLocalDate}.
+ * </p>
+ * <p>
+ * The API is also designed for user extensibility, as there are many ways of calculating time.
+ * The {@linkplain java.time.temporal.TemporalField field} and {@linkplain java.time.temporal.TemporalUnit unit}
+ * API, accessed via {@link java.time.temporal.TemporalAccessor TemporalAccessor} and
+ * {@link java.time.temporal.Temporal Temporal} provide considerable flexibility to applications.
+ * In addition, the {@link java.time.temporal.TemporalQuery TemporalQuery} and
+ * {@link java.time.temporal.TemporalAdjuster TemporalAdjuster} interfaces provide day-to-day
+ * power, allowing code to read close to business requirements:
+ * </p>
+ * <pre>
+ *   LocalDate customerBirthday = customer.loadBirthdayFromDatabase();
+ *   LocalDate today = LocalDate.now();
+ *   if (customerBirthday.equals(today)) {
+ *     LocalDate specialOfferExpiryDate = today.plusWeeks(2).with(next(FRIDAY));
+ *     customer.sendBirthdaySpecialOffer(specialOfferExpiryDate);
+ *   }
+ *
+ * </pre>
+ *
+ * @since JDK1.8
+ */
+package java.time;
diff --git a/java/time/temporal/ChronoField.java b/java/time/temporal/ChronoField.java
new file mode 100644
index 0000000..b8f7cee
--- /dev/null
+++ b/java/time/temporal/ChronoField.java
@@ -0,0 +1,780 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import android.icu.text.DateTimePatternGenerator;
+import android.icu.util.ULocale;
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.Year;
+import java.time.ZoneOffset;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Chronology;
+import java.util.Locale;
+import java.util.Objects;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.ERAS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.HALF_DAYS;
+import static java.time.temporal.ChronoUnit.HOURS;
+import static java.time.temporal.ChronoUnit.MICROS;
+import static java.time.temporal.ChronoUnit.MILLIS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.NANOS;
+import static java.time.temporal.ChronoUnit.SECONDS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+/**
+ * A standard set of fields.
+ * <p>
+ * This set of fields provide field-based access to manipulate a date, time or date-time.
+ * The standard set of fields can be extended by implementing {@link TemporalField}.
+ * <p>
+ * These fields are intended to be applicable in multiple calendar systems.
+ * For example, most non-ISO calendar systems define dates as a year, month and day,
+ * just with slightly different rules.
+ * The documentation of each field explains how it operates.
+ *
+ * @implSpec
+ * This is a final, immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum ChronoField implements TemporalField {
+
+    /**
+     * The nano-of-second.
+     * <p>
+     * This counts the nanosecond within the second, from 0 to 999,999,999.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the nano-of-second handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or
+     * {@link #INSTANT_SECONDS} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should set as much precision as the
+     * object stores, using integer division to remove excess precision.
+     * For example, if the {@code TemporalAccessor} stores time to millisecond precision,
+     * then the nano-of-second must be divided by 1,000,000 before replacing the milli-of-second.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The field is resolved in combination with {@code MILLI_OF_SECOND} and {@code MICRO_OF_SECOND}.
+     */
+    NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)),
+    /**
+     * The nano-of-day.
+     * <p>
+     * This counts the nanosecond within the day, from 0 to (24 * 60 * 60 * 1,000,000,000) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the nano-of-day handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The value is split to form {@code NANO_OF_SECOND}, {@code SECOND_OF_MINUTE},
+     * {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
+     */
+    NANO_OF_DAY("NanoOfDay", NANOS, DAYS, ValueRange.of(0, 86400L * 1000_000_000L - 1)),
+    /**
+     * The micro-of-second.
+     * <p>
+     * This counts the microsecond within the second, from 0 to 999,999.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the micro-of-second handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or
+     * {@link #INSTANT_SECONDS} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The field is resolved in combination with {@code MILLI_OF_SECOND} to produce
+     * {@code NANO_OF_SECOND}.
+     */
+    MICRO_OF_SECOND("MicroOfSecond", MICROS, SECONDS, ValueRange.of(0, 999_999)),
+    /**
+     * The micro-of-day.
+     * <p>
+     * This counts the microsecond within the day, from 0 to (24 * 60 * 60 * 1,000,000) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the micro-of-day handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The value is split to form {@code MICRO_OF_SECOND}, {@code SECOND_OF_MINUTE},
+     * {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
+     */
+    MICRO_OF_DAY("MicroOfDay", MICROS, DAYS, ValueRange.of(0, 86400L * 1000_000L - 1)),
+    /**
+     * The milli-of-second.
+     * <p>
+     * This counts the millisecond within the second, from 0 to 999.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the milli-of-second handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_MINUTE}, {@link #SECOND_OF_DAY} or
+     * {@link #INSTANT_SECONDS} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_SECOND} with the value multiplied by 1,000,000.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The field is resolved in combination with {@code MICRO_OF_SECOND} to produce
+     * {@code NANO_OF_SECOND}.
+     */
+    MILLI_OF_SECOND("MilliOfSecond", MILLIS, SECONDS, ValueRange.of(0, 999)),
+    /**
+     * The milli-of-day.
+     * <p>
+     * This counts the millisecond within the day, from 0 to (24 * 60 * 60 * 1,000) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * This field is used to represent the milli-of-day handling any fraction of the second.
+     * Implementations of {@code TemporalAccessor} should provide a value for this field if
+     * they can return a value for {@link #SECOND_OF_DAY} filling unknown precision with zero.
+     * <p>
+     * When this field is used for setting a value, it should behave in the same way as
+     * setting {@link #NANO_OF_DAY} with the value multiplied by 1,000,000.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The value is split to form {@code MILLI_OF_SECOND}, {@code SECOND_OF_MINUTE},
+     * {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
+     */
+    MILLI_OF_DAY("MilliOfDay", MILLIS, DAYS, ValueRange.of(0, 86400L * 1000L - 1)),
+    /**
+     * The second-of-minute.
+     * <p>
+     * This counts the second within the minute, from 0 to 59.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     */
+    SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59), "second"),
+    /**
+     * The second-of-day.
+     * <p>
+     * This counts the second within the day, from 0 to (24 * 60 * 60) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The value is split to form {@code SECOND_OF_MINUTE}, {@code MINUTE_OF_HOUR}
+     * and {@code HOUR_OF_DAY} fields.
+     */
+    SECOND_OF_DAY("SecondOfDay", SECONDS, DAYS, ValueRange.of(0, 86400L - 1)),
+    /**
+     * The minute-of-hour.
+     * <p>
+     * This counts the minute within the hour, from 0 to 59.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     */
+    MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59), "minute"),
+    /**
+     * The minute-of-day.
+     * <p>
+     * This counts the minute within the day, from 0 to (24 * 60) - 1.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The value is split to form {@code MINUTE_OF_HOUR} and {@code HOUR_OF_DAY} fields.
+     */
+    MINUTE_OF_DAY("MinuteOfDay", MINUTES, DAYS, ValueRange.of(0, (24 * 60) - 1)),
+    /**
+     * The hour-of-am-pm.
+     * <p>
+     * This counts the hour within the AM/PM, from 0 to 11.
+     * This is the hour that would be observed on a standard 12-hour digital clock.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated from 0 to 11 in strict and smart mode.
+     * In lenient mode the value is not validated. It is combined with
+     * {@code AMPM_OF_DAY} to form {@code HOUR_OF_DAY} by multiplying
+     * the {AMPM_OF_DAY} value by 12.
+     */
+    HOUR_OF_AMPM("HourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(0, 11)),
+    /**
+     * The clock-hour-of-am-pm.
+     * <p>
+     * This counts the hour within the AM/PM, from 1 to 12.
+     * This is the hour that would be observed on a standard 12-hour analog wall clock.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated from 1 to 12 in strict mode and from
+     * 0 to 12 in smart mode. In lenient mode the value is not validated.
+     * The field is converted to an {@code HOUR_OF_AMPM} with the same value,
+     * unless the value is 12, in which case it is converted to 0.
+     */
+    CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)),
+    /**
+     * The hour-of-day.
+     * <p>
+     * This counts the hour within the day, from 0 to 23.
+     * This is the hour that would be observed on a standard 24-hour digital clock.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated in strict and smart mode but not in lenient mode.
+     * The field is combined with {@code MINUTE_OF_HOUR}, {@code SECOND_OF_MINUTE} and
+     * {@code NANO_OF_SECOND} to produce a {@code LocalTime}.
+     * In lenient mode, any excess days are added to the parsed date, or
+     * made available via {@link java.time.format.DateTimeFormatter#parsedExcessDays()}.
+     */
+    HOUR_OF_DAY("HourOfDay", HOURS, DAYS, ValueRange.of(0, 23), "hour"),
+    /**
+     * The clock-hour-of-day.
+     * <p>
+     * This counts the hour within the AM/PM, from 1 to 24.
+     * This is the hour that would be observed on a 24-hour analog wall clock.
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated from 1 to 24 in strict mode and from
+     * 0 to 24 in smart mode. In lenient mode the value is not validated.
+     * The field is converted to an {@code HOUR_OF_DAY} with the same value,
+     * unless the value is 24, in which case it is converted to 0.
+     */
+    CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)),
+    /**
+     * The am-pm-of-day.
+     * <p>
+     * This counts the AM/PM within the day, from 0 (AM) to 1 (PM).
+     * This field has the same meaning for all calendar systems.
+     * <p>
+     * When parsing this field it behaves equivalent to the following:
+     * The value is validated from 0 to 1 in strict and smart mode.
+     * In lenient mode the value is not validated. It is combined with
+     * {@code HOUR_OF_AMPM} to form {@code HOUR_OF_DAY} by multiplying
+     * the {AMPM_OF_DAY} value by 12.
+     */
+    AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1), "dayperiod"),
+    /**
+     * The day-of-week, such as Tuesday.
+     * <p>
+     * This represents the standard concept of the day of the week.
+     * In the default ISO calendar system, this has values from Monday (1) to Sunday (7).
+     * The {@link DayOfWeek} class can be used to interpret the result.
+     * <p>
+     * Most non-ISO calendar systems also define a seven day week that aligns with ISO.
+     * Those calendar systems must also use the same numbering system, from Monday (1) to
+     * Sunday (7), which allows {@code DayOfWeek} to be used.
+     * <p>
+     * Calendar systems that do not have a standard seven day week should implement this field
+     * if they have a similar concept of named or numbered days within a period similar
+     * to a week. It is recommended that the numbering starts from 1.
+     */
+    DAY_OF_WEEK("DayOfWeek", DAYS, WEEKS, ValueRange.of(1, 7), "weekday"),
+    /**
+     * The aligned day-of-week within a month.
+     * <p>
+     * This represents concept of the count of days within the period of a week
+     * where the weeks are aligned to the start of the month.
+     * This field is typically used with {@link #ALIGNED_WEEK_OF_MONTH}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-month
+     * starts on day-of-month 1, the second aligned-week starts on day-of-month 8, and so on.
+     * Within each of these aligned-weeks, the days are numbered from 1 to 7 and returned
+     * as the value of this field.
+     * As such, day-of-month 1 to 7 will have aligned-day-of-week values from 1 to 7.
+     * And day-of-month 8 to 14 will repeat this with aligned-day-of-week values from 1 to 7.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_DAY_OF_WEEK_IN_MONTH("AlignedDayOfWeekInMonth", DAYS, WEEKS, ValueRange.of(1, 7)),
+    /**
+     * The aligned day-of-week within a year.
+     * <p>
+     * This represents concept of the count of days within the period of a week
+     * where the weeks are aligned to the start of the year.
+     * This field is typically used with {@link #ALIGNED_WEEK_OF_YEAR}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-year
+     * starts on day-of-year 1, the second aligned-week starts on day-of-year 8, and so on.
+     * Within each of these aligned-weeks, the days are numbered from 1 to 7 and returned
+     * as the value of this field.
+     * As such, day-of-year 1 to 7 will have aligned-day-of-week values from 1 to 7.
+     * And day-of-year 8 to 14 will repeat this with aligned-day-of-week values from 1 to 7.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_DAY_OF_WEEK_IN_YEAR("AlignedDayOfWeekInYear", DAYS, WEEKS, ValueRange.of(1, 7)),
+    /**
+     * The day-of-month.
+     * <p>
+     * This represents the concept of the day within the month.
+     * In the default ISO calendar system, this has values from 1 to 31 in most months.
+     * April, June, September, November have days from 1 to 30, while February has days
+     * from 1 to 28, or 29 in a leap year.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * day-of-month values for users of the calendar system.
+     * Normally, this is a count of days from 1 to the length of the month.
+     */
+    DAY_OF_MONTH("DayOfMonth", DAYS, MONTHS, ValueRange.of(1, 28, 31), "day"),
+    /**
+     * The day-of-year.
+     * <p>
+     * This represents the concept of the day within the year.
+     * In the default ISO calendar system, this has values from 1 to 365 in standard
+     * years and 1 to 366 in leap years.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * day-of-year values for users of the calendar system.
+     * Normally, this is a count of days from 1 to the length of the year.
+     * <p>
+     * Note that a non-ISO calendar system may have year numbering system that changes
+     * at a different point to the natural reset in the month numbering. An example
+     * of this is the Japanese calendar system where a change of era, which resets
+     * the year number to 1, can happen on any date. The era and year reset also cause
+     * the day-of-year to be reset to 1, but not the month-of-year or day-of-month.
+     */
+    DAY_OF_YEAR("DayOfYear", DAYS, YEARS, ValueRange.of(1, 365, 366)),
+    /**
+     * The epoch-day, based on the Java epoch of 1970-01-01 (ISO).
+     * <p>
+     * This field is the sequential count of days where 1970-01-01 (ISO) is zero.
+     * Note that this uses the <i>local</i> time-line, ignoring offset and time-zone.
+     * <p>
+     * This field is strictly defined to have the same meaning in all calendar systems.
+     * This is necessary to ensure interoperation between calendars.
+     */
+    EPOCH_DAY("EpochDay", DAYS, FOREVER, ValueRange.of((long) (Year.MIN_VALUE * 365.25), (long) (Year.MAX_VALUE * 365.25))),
+    /**
+     * The aligned week within a month.
+     * <p>
+     * This represents concept of the count of weeks within the period of a month
+     * where the weeks are aligned to the start of the month.
+     * This field is typically used with {@link #ALIGNED_DAY_OF_WEEK_IN_MONTH}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-month
+     * starts on day-of-month 1, the second aligned-week starts on day-of-month 8, and so on.
+     * Thus, day-of-month values 1 to 7 are in aligned-week 1, while day-of-month values
+     * 8 to 14 are in aligned-week 2, and so on.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_WEEK_OF_MONTH("AlignedWeekOfMonth", WEEKS, MONTHS, ValueRange.of(1, 4, 5)),
+    /**
+     * The aligned week within a year.
+     * <p>
+     * This represents concept of the count of weeks within the period of a year
+     * where the weeks are aligned to the start of the year.
+     * This field is typically used with {@link #ALIGNED_DAY_OF_WEEK_IN_YEAR}.
+     * <p>
+     * For example, in a calendar systems with a seven day week, the first aligned-week-of-year
+     * starts on day-of-year 1, the second aligned-week starts on day-of-year 8, and so on.
+     * Thus, day-of-year values 1 to 7 are in aligned-week 1, while day-of-year values
+     * 8 to 14 are in aligned-week 2, and so on.
+     * <p>
+     * Calendar systems that do not have a seven day week should typically implement this
+     * field in the same way, but using the alternate week length.
+     */
+    ALIGNED_WEEK_OF_YEAR("AlignedWeekOfYear", WEEKS, YEARS, ValueRange.of(1, 53)),
+    /**
+     * The month-of-year, such as March.
+     * <p>
+     * This represents the concept of the month within the year.
+     * In the default ISO calendar system, this has values from January (1) to December (12).
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * month-of-year values for users of the calendar system.
+     * Normally, this is a count of months starting from 1.
+     */
+    MONTH_OF_YEAR("MonthOfYear", MONTHS, YEARS, ValueRange.of(1, 12), "month"),
+    /**
+     * The proleptic-month based, counting months sequentially from year 0.
+     * <p>
+     * This field is the sequential count of months where the first month
+     * in proleptic-year zero has the value zero.
+     * Later months have increasingly larger values.
+     * Earlier months have increasingly small values.
+     * There are no gaps or breaks in the sequence of months.
+     * Note that this uses the <i>local</i> time-line, ignoring offset and time-zone.
+     * <p>
+     * In the default ISO calendar system, June 2012 would have the value
+     * {@code (2012 * 12 + 6 - 1)}. This field is primarily for internal use.
+     * <p>
+     * Non-ISO calendar systems must implement this field as per the definition above.
+     * It is just a simple zero-based count of elapsed months from the start of proleptic-year 0.
+     * All calendar systems with a full proleptic-year definition will have a year zero.
+     * If the calendar system has a minimum year that excludes year zero, then one must
+     * be extrapolated in order for this method to be defined.
+     */
+    PROLEPTIC_MONTH("ProlepticMonth", MONTHS, FOREVER, ValueRange.of(Year.MIN_VALUE * 12L, Year.MAX_VALUE * 12L + 11)),
+    /**
+     * The year within the era.
+     * <p>
+     * This represents the concept of the year within the era.
+     * This field is typically used with {@link #ERA}.
+     * <p>
+     * The standard mental model for a date is based on three concepts - year, month and day.
+     * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Note that there is no reference to eras.
+     * The full model for a date requires four concepts - era, year, month and day. These map onto
+     * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Whether this field or {@code YEAR} is used depends on which mental model is being used.
+     * See {@link ChronoLocalDate} for more discussion on this topic.
+     * <p>
+     * In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'.
+     * The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value.
+     * The era 'BCE' is the previous era, and the year-of-era runs backwards.
+     * <p>
+     * For example, subtracting a year each time yield the following:<br>
+     * - year-proleptic 2  = 'CE' year-of-era 2<br>
+     * - year-proleptic 1  = 'CE' year-of-era 1<br>
+     * - year-proleptic 0  = 'BCE' year-of-era 1<br>
+     * - year-proleptic -1 = 'BCE' year-of-era 2<br>
+     * <p>
+     * Note that the ISO-8601 standard does not actually define eras.
+     * Note also that the ISO eras do not align with the well-known AD/BC eras due to the
+     * change between the Julian and Gregorian calendar systems.
+     * <p>
+     * Non-ISO calendar systems should implement this field using the most recognized
+     * year-of-era value for users of the calendar system.
+     * Since most calendar systems have only two eras, the year-of-era numbering approach
+     * will typically be the same as that used by the ISO calendar system.
+     * The year-of-era value should typically always be positive, however this is not required.
+     */
+    YEAR_OF_ERA("YearOfEra", YEARS, FOREVER, ValueRange.of(1, Year.MAX_VALUE, Year.MAX_VALUE + 1)),
+    /**
+     * The proleptic year, such as 2012.
+     * <p>
+     * This represents the concept of the year, counting sequentially and using negative numbers.
+     * The proleptic year is not interpreted in terms of the era.
+     * See {@link #YEAR_OF_ERA} for an example showing the mapping from proleptic year to year-of-era.
+     * <p>
+     * The standard mental model for a date is based on three concepts - year, month and day.
+     * These map onto the {@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Note that there is no reference to eras.
+     * The full model for a date requires four concepts - era, year, month and day. These map onto
+     * the {@code ERA}, {@code YEAR_OF_ERA}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} fields.
+     * Whether this field or {@code YEAR_OF_ERA} is used depends on which mental model is being used.
+     * See {@link ChronoLocalDate} for more discussion on this topic.
+     * <p>
+     * Non-ISO calendar systems should implement this field as follows.
+     * If the calendar system has only two eras, before and after a fixed date, then the
+     * proleptic-year value must be the same as the year-of-era value for the later era,
+     * and increasingly negative for the earlier era.
+     * If the calendar system has more than two eras, then the proleptic-year value may be
+     * defined with any appropriate value, although defining it to be the same as ISO may be
+     * the best option.
+     */
+    YEAR("Year", YEARS, FOREVER, ValueRange.of(Year.MIN_VALUE, Year.MAX_VALUE), "year"),
+    /**
+     * The era.
+     * <p>
+     * This represents the concept of the era, which is the largest division of the time-line.
+     * This field is typically used with {@link #YEAR_OF_ERA}.
+     * <p>
+     * In the default ISO calendar system, there are two eras defined, 'BCE' and 'CE'.
+     * The era 'CE' is the one currently in use and year-of-era runs from 1 to the maximum value.
+     * The era 'BCE' is the previous era, and the year-of-era runs backwards.
+     * See {@link #YEAR_OF_ERA} for a full example.
+     * <p>
+     * Non-ISO calendar systems should implement this field to define eras.
+     * The value of the era that was active on 1970-01-01 (ISO) must be assigned the value 1.
+     * Earlier eras must have sequentially smaller values.
+     * Later eras must have sequentially larger values,
+     */
+    ERA("Era", ERAS, FOREVER, ValueRange.of(0, 1), "era"),
+    /**
+     * The instant epoch-seconds.
+     * <p>
+     * This represents the concept of the sequential count of seconds where
+     * 1970-01-01T00:00Z (ISO) is zero.
+     * This field may be used with {@link #NANO_OF_SECOND} to represent the fraction of the second.
+     * <p>
+     * An {@link Instant} represents an instantaneous point on the time-line.
+     * On their own, an instant has insufficient information to allow a local date-time to be obtained.
+     * Only when paired with an offset or time-zone can the local date or time be calculated.
+     * <p>
+     * This field is strictly defined to have the same meaning in all calendar systems.
+     * This is necessary to ensure interoperation between calendars.
+     */
+    INSTANT_SECONDS("InstantSeconds", SECONDS, FOREVER, ValueRange.of(Long.MIN_VALUE, Long.MAX_VALUE)),
+    /**
+     * The offset from UTC/Greenwich.
+     * <p>
+     * This represents the concept of the offset in seconds of local time from UTC/Greenwich.
+     * <p>
+     * A {@link ZoneOffset} represents the period of time that local time differs from UTC/Greenwich.
+     * This is usually a fixed number of hours and minutes.
+     * It is equivalent to the {@link ZoneOffset#getTotalSeconds() total amount} of the offset in seconds.
+     * For example, during the winter Paris has an offset of {@code +01:00}, which is 3600 seconds.
+     * <p>
+     * This field is strictly defined to have the same meaning in all calendar systems.
+     * This is necessary to ensure interoperation between calendars.
+     */
+    OFFSET_SECONDS("OffsetSeconds", SECONDS, FOREVER, ValueRange.of(-18 * 3600, 18 * 3600));
+
+    private final String name;
+    private final TemporalUnit baseUnit;
+    private final TemporalUnit rangeUnit;
+    private final ValueRange range;
+    private final String displayNameKey;
+
+    private ChronoField(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) {
+        this.name = name;
+        this.baseUnit = baseUnit;
+        this.rangeUnit = rangeUnit;
+        this.range = range;
+        this.displayNameKey = null;
+    }
+
+    private ChronoField(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit,
+            ValueRange range, String displayNameKey) {
+        this.name = name;
+        this.baseUnit = baseUnit;
+        this.rangeUnit = rangeUnit;
+        this.range = range;
+        this.displayNameKey = displayNameKey;
+    }
+
+    @Override
+    public String getDisplayName(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        if (displayNameKey == null) {
+            return name;
+        }
+
+        // Android-changed: use ICU names.
+        DateTimePatternGenerator generator = DateTimePatternGenerator
+                .getFrozenInstance(ULocale.forLocale(locale));
+        String icuName = generator.getAppendItemName(getIcuFieldNumber(this));
+        return icuName != null && !icuName.isEmpty() ? icuName : name;
+    }
+
+    /**
+     * @return the field id according to {@link DateTimePatternGenerator} for the field.
+     */
+    private static int getIcuFieldNumber(ChronoField field) {
+        switch (field) {
+            case SECOND_OF_MINUTE:
+                return DateTimePatternGenerator.SECOND;
+            case MINUTE_OF_HOUR:
+                return DateTimePatternGenerator.MINUTE;
+            case HOUR_OF_DAY:
+                return DateTimePatternGenerator.HOUR;
+            case AMPM_OF_DAY:
+                return DateTimePatternGenerator.DAYPERIOD;
+            case DAY_OF_WEEK:
+                return DateTimePatternGenerator.WEEKDAY;
+            case DAY_OF_MONTH:
+                return DateTimePatternGenerator.DAY;
+            case MONTH_OF_YEAR:
+                return DateTimePatternGenerator.MONTH;
+            case YEAR:
+                return DateTimePatternGenerator.YEAR;
+            case ERA:
+                return DateTimePatternGenerator.ERA;
+            default:
+                throw new IllegalArgumentException("Unexpected ChronoField " + field.name());
+        }
+    }
+
+    @Override
+    public TemporalUnit getBaseUnit() {
+        return baseUnit;
+    }
+
+    @Override
+    public TemporalUnit getRangeUnit() {
+        return rangeUnit;
+    }
+
+    /**
+     * Gets the range of valid values for the field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * <p>
+     * This method returns the range of the field in the ISO-8601 calendar system.
+     * This range may be incorrect for other calendar systems.
+     * Use {@link Chronology#range(ChronoField)} to access the correct range
+     * for a different calendar system.
+     * <p>
+     * Note that the result only describes the minimum and maximum valid values
+     * and it is important not to read too much into them. For example, there
+     * could be values within the range that are invalid for the field.
+     *
+     * @return the range of valid values for the field, not null
+     */
+    @Override
+    public ValueRange range() {
+        return range;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this field represents a component of a date.
+     * <p>
+     * Fields from day-of-week to era are date-based.
+     *
+     * @return true if it is a component of a date
+     */
+    @Override
+    public boolean isDateBased() {
+        return ordinal() >= DAY_OF_WEEK.ordinal() && ordinal() <= ERA.ordinal();
+    }
+
+    /**
+     * Checks if this field represents a component of a time.
+     * <p>
+     * Fields from nano-of-second to am-pm-of-day are time-based.
+     *
+     * @return true if it is a component of a time
+     */
+    @Override
+    public boolean isTimeBased() {
+        return ordinal() < DAY_OF_WEEK.ordinal();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks that the specified value is valid for this field.
+     * <p>
+     * This validates that the value is within the outer range of valid values
+     * returned by {@link #range()}.
+     * <p>
+     * This method checks against the range of the field in the ISO-8601 calendar system.
+     * This range may be incorrect for other calendar systems.
+     * Use {@link Chronology#range(ChronoField)} to access the correct range
+     * for a different calendar system.
+     *
+     * @param value  the value to check
+     * @return the value that was passed in
+     */
+    public long checkValidValue(long value) {
+        return range().checkValidValue(value, this);
+    }
+
+    /**
+     * Checks that the specified value is valid and fits in an {@code int}.
+     * <p>
+     * This validates that the value is within the outer range of valid values
+     * returned by {@link #range()}.
+     * It also checks that all valid values are within the bounds of an {@code int}.
+     * <p>
+     * This method checks against the range of the field in the ISO-8601 calendar system.
+     * This range may be incorrect for other calendar systems.
+     * Use {@link Chronology#range(ChronoField)} to access the correct range
+     * for a different calendar system.
+     *
+     * @param value  the value to check
+     * @return the value that was passed in
+     */
+    public int checkValidIntValue(long value) {
+        return range().checkValidIntValue(value, this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupportedBy(TemporalAccessor temporal) {
+        return temporal.isSupported(this);
+    }
+
+    @Override
+    public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+        return temporal.range(this);
+    }
+
+    @Override
+    public long getFrom(TemporalAccessor temporal) {
+        return temporal.getLong(this);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+        return (R) temporal.with(this, newValue);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return name;
+    }
+
+}
diff --git a/java/time/temporal/ChronoUnit.java b/java/time/temporal/ChronoUnit.java
new file mode 100644
index 0000000..c704327
--- /dev/null
+++ b/java/time/temporal/ChronoUnit.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.Duration;
+
+/**
+ * A standard set of date periods units.
+ * <p>
+ * This set of units provide unit-based access to manipulate a date, time or date-time.
+ * The standard set of units can be extended by implementing {@link TemporalUnit}.
+ * <p>
+ * These units are intended to be applicable in multiple calendar systems.
+ * For example, most non-ISO calendar systems define units of years, months and days,
+ * just with slightly different rules.
+ * The documentation of each unit explains how it operates.
+ *
+ * @implSpec
+ * This is a final, immutable and thread-safe enum.
+ *
+ * @since 1.8
+ */
+public enum ChronoUnit implements TemporalUnit {
+
+    /**
+     * Unit that represents the concept of a nanosecond, the smallest supported unit of time.
+     * For the ISO calendar system, it is equal to the 1,000,000,000th part of the second unit.
+     */
+    NANOS("Nanos", Duration.ofNanos(1)),
+    /**
+     * Unit that represents the concept of a microsecond.
+     * For the ISO calendar system, it is equal to the 1,000,000th part of the second unit.
+     */
+    MICROS("Micros", Duration.ofNanos(1000)),
+    /**
+     * Unit that represents the concept of a millisecond.
+     * For the ISO calendar system, it is equal to the 1000th part of the second unit.
+     */
+    MILLIS("Millis", Duration.ofNanos(1000_000)),
+    /**
+     * Unit that represents the concept of a second.
+     * For the ISO calendar system, it is equal to the second in the SI system
+     * of units, except around a leap-second.
+     */
+    SECONDS("Seconds", Duration.ofSeconds(1)),
+    /**
+     * Unit that represents the concept of a minute.
+     * For the ISO calendar system, it is equal to 60 seconds.
+     */
+    MINUTES("Minutes", Duration.ofSeconds(60)),
+    /**
+     * Unit that represents the concept of an hour.
+     * For the ISO calendar system, it is equal to 60 minutes.
+     */
+    HOURS("Hours", Duration.ofSeconds(3600)),
+    /**
+     * Unit that represents the concept of half a day, as used in AM/PM.
+     * For the ISO calendar system, it is equal to 12 hours.
+     */
+    HALF_DAYS("HalfDays", Duration.ofSeconds(43200)),
+    /**
+     * Unit that represents the concept of a day.
+     * For the ISO calendar system, it is the standard day from midnight to midnight.
+     * The estimated duration of a day is {@code 24 Hours}.
+     * <p>
+     * When used with other calendar systems it must correspond to the day defined by
+     * the rising and setting of the Sun on Earth. It is not required that days begin
+     * at midnight - when converting between calendar systems, the date should be
+     * equivalent at midday.
+     */
+    DAYS("Days", Duration.ofSeconds(86400)),
+    /**
+     * Unit that represents the concept of a week.
+     * For the ISO calendar system, it is equal to 7 days.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days.
+     */
+    WEEKS("Weeks", Duration.ofSeconds(7 * 86400L)),
+    /**
+     * Unit that represents the concept of a month.
+     * For the ISO calendar system, the length of the month varies by month-of-year.
+     * The estimated duration of a month is one twelfth of {@code 365.2425 Days}.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days.
+     */
+    MONTHS("Months", Duration.ofSeconds(31556952L / 12)),
+    /**
+     * Unit that represents the concept of a year.
+     * For the ISO calendar system, it is equal to 12 months.
+     * The estimated duration of a year is {@code 365.2425 Days}.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * or months roughly equal to a year defined by the passage of the Earth around the Sun.
+     */
+    YEARS("Years", Duration.ofSeconds(31556952L)),
+    /**
+     * Unit that represents the concept of a decade.
+     * For the ISO calendar system, it is equal to 10 years.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * and is normally an integral number of years.
+     */
+    DECADES("Decades", Duration.ofSeconds(31556952L * 10L)),
+    /**
+     * Unit that represents the concept of a century.
+     * For the ISO calendar system, it is equal to 100 years.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * and is normally an integral number of years.
+     */
+    CENTURIES("Centuries", Duration.ofSeconds(31556952L * 100L)),
+    /**
+     * Unit that represents the concept of a millennium.
+     * For the ISO calendar system, it is equal to 1000 years.
+     * <p>
+     * When used with other calendar systems it must correspond to an integral number of days
+     * and is normally an integral number of years.
+     */
+    MILLENNIA("Millennia", Duration.ofSeconds(31556952L * 1000L)),
+    /**
+     * Unit that represents the concept of an era.
+     * The ISO calendar system doesn't have eras thus it is impossible to add
+     * an era to a date or date-time.
+     * The estimated duration of the era is artificially defined as {@code 1,000,000,000 Years}.
+     * <p>
+     * When used with other calendar systems there are no restrictions on the unit.
+     */
+    ERAS("Eras", Duration.ofSeconds(31556952L * 1000_000_000L)),
+    /**
+     * Artificial unit that represents the concept of forever.
+     * This is primarily used with {@link TemporalField} to represent unbounded fields
+     * such as the year or era.
+     * The estimated duration of the era is artificially defined as the largest duration
+     * supported by {@code Duration}.
+     */
+    FOREVER("Forever", Duration.ofSeconds(Long.MAX_VALUE, 999_999_999));
+
+    private final String name;
+    private final Duration duration;
+
+    private ChronoUnit(String name, Duration estimatedDuration) {
+        this.name = name;
+        this.duration = estimatedDuration;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the estimated duration of this unit in the ISO calendar system.
+     * <p>
+     * All of the units in this class have an estimated duration.
+     * Days vary due to daylight saving time, while months have different lengths.
+     *
+     * @return the estimated duration of this unit, not null
+     */
+    @Override
+    public Duration getDuration() {
+        return duration;
+    }
+
+    /**
+     * Checks if the duration of the unit is an estimate.
+     * <p>
+     * All time units in this class are considered to be accurate, while all date
+     * units in this class are considered to be estimated.
+     * <p>
+     * This definition ignores leap seconds, but considers that Days vary due to
+     * daylight saving time and months have different lengths.
+     *
+     * @return true if the duration is estimated, false if accurate
+     */
+    @Override
+    public boolean isDurationEstimated() {
+        return this.compareTo(DAYS) >= 0;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this unit is a date unit.
+     * <p>
+     * All units from days to eras inclusive are date-based.
+     * Time-based units and {@code FOREVER} return false.
+     *
+     * @return true if a date unit, false if a time unit
+     */
+    @Override
+    public boolean isDateBased() {
+        return this.compareTo(DAYS) >= 0 && this != FOREVER;
+    }
+
+    /**
+     * Checks if this unit is a time unit.
+     * <p>
+     * All units from nanos to half-days inclusive are time-based.
+     * Date-based units and {@code FOREVER} return false.
+     *
+     * @return true if a time unit, false if a date unit
+     */
+    @Override
+    public boolean isTimeBased() {
+        return this.compareTo(DAYS) < 0;
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public boolean isSupportedBy(Temporal temporal) {
+        return temporal.isSupported(this);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R extends Temporal> R addTo(R temporal, long amount) {
+        return (R) temporal.plus(amount, this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) {
+        return temporal1Inclusive.until(temporal2Exclusive, this);
+    }
+
+    //-----------------------------------------------------------------------
+    @Override
+    public String toString() {
+        return name;
+    }
+
+}
diff --git a/java/time/temporal/IsoFields.java b/java/time/temporal/IsoFields.java
new file mode 100644
index 0000000..8b6f237
--- /dev/null
+++ b/java/time/temporal/IsoFields.java
@@ -0,0 +1,725 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import android.icu.text.DateTimePatternGenerator;
+import android.icu.util.ULocale;
+
+import static java.time.DayOfWeek.THURSDAY;
+import static java.time.DayOfWeek.WEDNESDAY;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Chronology;
+import java.time.chrono.IsoChronology;
+import java.time.format.ResolverStyle;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Fields and units specific to the ISO-8601 calendar system,
+ * including quarter-of-year and week-based-year.
+ * <p>
+ * This class defines fields and units that are specific to the ISO calendar system.
+ *
+ * <h3>Quarter of year</h3>
+ * The ISO-8601 standard is based on the standard civic 12 month year.
+ * This is commonly divided into four quarters, often abbreviated as Q1, Q2, Q3 and Q4.
+ * <p>
+ * January, February and March are in Q1.
+ * April, May and June are in Q2.
+ * July, August and September are in Q3.
+ * October, November and December are in Q4.
+ * <p>
+ * The complete date is expressed using three fields:
+ * <ul>
+ * <li>{@link #DAY_OF_QUARTER DAY_OF_QUARTER} - the day within the quarter, from 1 to 90, 91 or 92
+ * <li>{@link #QUARTER_OF_YEAR QUARTER_OF_YEAR} - the week within the week-based-year
+ * <li>{@link ChronoField#YEAR YEAR} - the standard ISO year
+ * </ul>
+ *
+ * <h3>Week based years</h3>
+ * The ISO-8601 standard was originally intended as a data interchange format,
+ * defining a string format for dates and times. However, it also defines an
+ * alternate way of expressing the date, based on the concept of week-based-year.
+ * <p>
+ * The date is expressed using three fields:
+ * <ul>
+ * <li>{@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} - the standard field defining the
+ *  day-of-week from Monday (1) to Sunday (7)
+ * <li>{@link #WEEK_OF_WEEK_BASED_YEAR} - the week within the week-based-year
+ * <li>{@link #WEEK_BASED_YEAR WEEK_BASED_YEAR} - the week-based-year
+ * </ul>
+ * The week-based-year itself is defined relative to the standard ISO proleptic year.
+ * It differs from the standard year in that it always starts on a Monday.
+ * <p>
+ * The first week of a week-based-year is the first Monday-based week of the standard
+ * ISO year that has at least 4 days in the new year.
+ * <ul>
+ * <li>If January 1st is Monday then week 1 starts on January 1st
+ * <li>If January 1st is Tuesday then week 1 starts on December 31st of the previous standard year
+ * <li>If January 1st is Wednesday then week 1 starts on December 30th of the previous standard year
+ * <li>If January 1st is Thursday then week 1 starts on December 29th of the previous standard year
+ * <li>If January 1st is Friday then week 1 starts on January 4th
+ * <li>If January 1st is Saturday then week 1 starts on January 3rd
+ * <li>If January 1st is Sunday then week 1 starts on January 2nd
+ * </ul>
+ * There are 52 weeks in most week-based years, however on occasion there are 53 weeks.
+ * <p>
+ * For example:
+ *
+ * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
+ * <caption>Examples of Week based Years</caption>
+ * <tr><th>Date</th><th>Day-of-week</th><th>Field values</th></tr>
+ * <tr><th>2008-12-28</th><td>Sunday</td><td>Week 52 of week-based-year 2008</td></tr>
+ * <tr><th>2008-12-29</th><td>Monday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2008-12-31</th><td>Wednesday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2009-01-01</th><td>Thursday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2009-01-04</th><td>Sunday</td><td>Week 1 of week-based-year 2009</td></tr>
+ * <tr><th>2009-01-05</th><td>Monday</td><td>Week 2 of week-based-year 2009</td></tr>
+ * </table>
+ *
+ * @implSpec
+ * <p>
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class IsoFields {
+
+    /**
+     * The field that represents the day-of-quarter.
+     * <p>
+     * This field allows the day-of-quarter value to be queried and set.
+     * The day-of-quarter has values from 1 to 90 in Q1 of a standard year, from 1 to 91
+     * in Q1 of a leap year, from 1 to 91 in Q2 and from 1 to 92 in Q3 and Q4.
+     * <p>
+     * The day-of-quarter can only be calculated if the day-of-year, month-of-year and year
+     * are available.
+     * <p>
+     * When setting this field, the value is allowed to be partially lenient, taking any
+     * value from 1 to 92. If the quarter has less than 92 days, then day 92, and
+     * potentially day 91, is in the following quarter.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a year,
+     * quarter-of-year and day-of-quarter.
+     * <p>
+     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
+     * validated against their range of valid values. The day-of-quarter field
+     * is validated from 1 to 90, 91 or 92 depending on the year and quarter.
+     * <p>
+     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
+     * validated against their range of valid values. The day-of-quarter field is
+     * validated between 1 and 92, ignoring the actual range based on the year and quarter.
+     * If the day-of-quarter exceeds the actual range by one day, then the resulting date
+     * is one day later. If the day-of-quarter exceeds the actual range by two days,
+     * then the resulting date is two days later.
+     * <p>
+     * In {@linkplain ResolverStyle#LENIENT lenient mode}, only the year is validated
+     * against the range of valid values. The resulting date is calculated equivalent to
+     * the following three stage approach. First, create a date on the first of January
+     * in the requested year. Then take the quarter-of-year, subtract one, and add the
+     * amount in quarters to the date. Finally, take the day-of-quarter, subtract one,
+     * and add the amount in days to the date.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField DAY_OF_QUARTER = Field.DAY_OF_QUARTER;
+    /**
+     * The field that represents the quarter-of-year.
+     * <p>
+     * This field allows the quarter-of-year value to be queried and set.
+     * The quarter-of-year has values from 1 to 4.
+     * <p>
+     * The quarter-of-year can only be calculated if the month-of-year is available.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a year,
+     * quarter-of-year and day-of-quarter.
+     * See {@link #DAY_OF_QUARTER} for details.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField QUARTER_OF_YEAR = Field.QUARTER_OF_YEAR;
+    /**
+     * The field that represents the week-of-week-based-year.
+     * <p>
+     * This field allows the week of the week-based-year value to be queried and set.
+     * The week-of-week-based-year has values from 1 to 52, or 53 if the
+     * week-based-year has 53 weeks.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a
+     * week-based-year, week-of-week-based-year and day-of-week.
+     * <p>
+     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
+     * validated against their range of valid values. The week-of-week-based-year
+     * field is validated from 1 to 52 or 53 depending on the week-based-year.
+     * <p>
+     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
+     * validated against their range of valid values. The week-of-week-based-year
+     * field is validated between 1 and 53, ignoring the week-based-year.
+     * If the week-of-week-based-year is 53, but the week-based-year only has
+     * 52 weeks, then the resulting date is in week 1 of the following week-based-year.
+     * <p>
+     * In {@linkplain ResolverStyle#LENIENT lenient mode}, only the week-based-year
+     * is validated against the range of valid values. If the day-of-week is outside
+     * the range 1 to 7, then the resulting date is adjusted by a suitable number of
+     * weeks to reduce the day-of-week to the range 1 to 7. If the week-of-week-based-year
+     * value is outside the range 1 to 52, then any excess weeks are added or subtracted
+     * from the resulting date.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField WEEK_OF_WEEK_BASED_YEAR = Field.WEEK_OF_WEEK_BASED_YEAR;
+    /**
+     * The field that represents the week-based-year.
+     * <p>
+     * This field allows the week-based-year value to be queried and set.
+     * <p>
+     * The field has a range that matches {@link LocalDate#MAX} and {@link LocalDate#MIN}.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a
+     * week-based-year, week-of-week-based-year and day-of-week.
+     * See {@link #WEEK_OF_WEEK_BASED_YEAR} for details.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalField WEEK_BASED_YEAR = Field.WEEK_BASED_YEAR;
+    /**
+     * The unit that represents week-based-years for the purpose of addition and subtraction.
+     * <p>
+     * This allows a number of week-based-years to be added to, or subtracted from, a date.
+     * The unit is equal to either 52 or 53 weeks.
+     * The estimated duration of a week-based-year is the same as that of a standard ISO
+     * year at {@code 365.2425 Days}.
+     * <p>
+     * The rules for addition add the number of week-based-years to the existing value
+     * for the week-based-year field. If the resulting week-based-year only has 52 weeks,
+     * then the date will be in week 1 of the following week-based-year.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalUnit WEEK_BASED_YEARS = Unit.WEEK_BASED_YEARS;
+    /**
+     * Unit that represents the concept of a quarter-year.
+     * For the ISO calendar system, it is equal to 3 months.
+     * The estimated duration of a quarter-year is one quarter of {@code 365.2425 Days}.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalUnit QUARTER_YEARS = Unit.QUARTER_YEARS;
+
+    /**
+     * Restricted constructor.
+     */
+    private IsoFields() {
+        throw new AssertionError("Not instantiable");
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of the field.
+     */
+    private static enum Field implements TemporalField {
+        DAY_OF_QUARTER {
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return DAYS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return QUARTER_YEARS;
+            }
+            @Override
+            public ValueRange range() {
+                return ValueRange.of(1, 90, 92);
+            }
+            @Override
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(DAY_OF_YEAR) && temporal.isSupported(MONTH_OF_YEAR) &&
+                        temporal.isSupported(YEAR) && isIso(temporal);
+            }
+            @Override
+            public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: DayOfQuarter");
+                }
+                long qoy = temporal.getLong(QUARTER_OF_YEAR);
+                if (qoy == 1) {
+                    long year = temporal.getLong(YEAR);
+                    return (IsoChronology.INSTANCE.isLeapYear(year) ? ValueRange.of(1, 91) : ValueRange.of(1, 90));
+                } else if (qoy == 2) {
+                    return ValueRange.of(1, 91);
+                } else if (qoy == 3 || qoy == 4) {
+                    return ValueRange.of(1, 92);
+                } // else value not from 1 to 4, so drop through
+                return range();
+            }
+            @Override
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: DayOfQuarter");
+                }
+                int doy = temporal.get(DAY_OF_YEAR);
+                int moy = temporal.get(MONTH_OF_YEAR);
+                long year = temporal.getLong(YEAR);
+                return doy - QUARTER_DAYS[((moy - 1) / 3) + (IsoChronology.INSTANCE.isLeapYear(year) ? 4 : 0)];
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                // calls getFrom() to check if supported
+                long curValue = getFrom(temporal);
+                range().checkValidValue(newValue, this);  // leniently check from 1 to 92 TODO: check
+                return (R) temporal.with(DAY_OF_YEAR, temporal.getLong(DAY_OF_YEAR) + (newValue - curValue));
+            }
+            @Override
+            public ChronoLocalDate resolve(
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
+                Long yearLong = fieldValues.get(YEAR);
+                Long qoyLong = fieldValues.get(QUARTER_OF_YEAR);
+                if (yearLong == null || qoyLong == null) {
+                    return null;
+                }
+                int y = YEAR.checkValidIntValue(yearLong);  // always validate
+                long doq = fieldValues.get(DAY_OF_QUARTER);
+                ensureIso(partialTemporal);
+                LocalDate date;
+                if (resolverStyle == ResolverStyle.LENIENT) {
+                    date = LocalDate.of(y, 1, 1).plusMonths(Math.multiplyExact(Math.subtractExact(qoyLong, 1), 3));
+                    doq = Math.subtractExact(doq, 1);
+                } else {
+                    int qoy = QUARTER_OF_YEAR.range().checkValidIntValue(qoyLong, QUARTER_OF_YEAR);  // validated
+                    date = LocalDate.of(y, ((qoy - 1) * 3) + 1, 1);
+                    if (doq < 1 || doq > 90) {
+                        if (resolverStyle == ResolverStyle.STRICT) {
+                            rangeRefinedBy(date).checkValidValue(doq, this);  // only allow exact range
+                        } else {  // SMART
+                            range().checkValidValue(doq, this);  // allow 1-92 rolling into next quarter
+                        }
+                    }
+                    doq--;
+                }
+                fieldValues.remove(this);
+                fieldValues.remove(YEAR);
+                fieldValues.remove(QUARTER_OF_YEAR);
+                return date.plusDays(doq);
+            }
+            @Override
+            public String toString() {
+                return "DayOfQuarter";
+            }
+        },
+        QUARTER_OF_YEAR {
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return QUARTER_YEARS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return YEARS;
+            }
+            @Override
+            public ValueRange range() {
+                return ValueRange.of(1, 4);
+            }
+            @Override
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(MONTH_OF_YEAR) && isIso(temporal);
+            }
+            @Override
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: QuarterOfYear");
+                }
+                long moy = temporal.getLong(MONTH_OF_YEAR);
+                return ((moy + 2) / 3);
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                // calls getFrom() to check if supported
+                long curValue = getFrom(temporal);
+                range().checkValidValue(newValue, this);  // strictly check from 1 to 4
+                return (R) temporal.with(MONTH_OF_YEAR, temporal.getLong(MONTH_OF_YEAR) + (newValue - curValue) * 3);
+            }
+            @Override
+            public String toString() {
+                return "QuarterOfYear";
+            }
+        },
+        WEEK_OF_WEEK_BASED_YEAR {
+            @Override
+            public String getDisplayName(Locale locale) {
+                Objects.requireNonNull(locale, "locale");
+                // Android-changed: Use ICU name values.
+                DateTimePatternGenerator dateTimePatternGenerator = DateTimePatternGenerator
+                        .getFrozenInstance(ULocale.forLocale(locale));
+                String icuName = dateTimePatternGenerator
+                        .getAppendItemName(DateTimePatternGenerator.WEEK_OF_YEAR);
+                return icuName != null && !icuName.isEmpty() ? icuName : toString();
+            }
+
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return WEEKS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return WEEK_BASED_YEARS;
+            }
+            @Override
+            public ValueRange range() {
+                return ValueRange.of(1, 52, 53);
+            }
+            @Override
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(EPOCH_DAY) && isIso(temporal);
+            }
+            @Override
+            public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: WeekOfWeekBasedYear");
+                }
+                return getWeekRange(LocalDate.from(temporal));
+            }
+            @Override
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: WeekOfWeekBasedYear");
+                }
+                return getWeek(LocalDate.from(temporal));
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                // calls getFrom() to check if supported
+                range().checkValidValue(newValue, this);  // lenient range
+                return (R) temporal.plus(Math.subtractExact(newValue, getFrom(temporal)), WEEKS);
+            }
+            @Override
+            public ChronoLocalDate resolve(
+                    Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
+                Long wbyLong = fieldValues.get(WEEK_BASED_YEAR);
+                Long dowLong = fieldValues.get(DAY_OF_WEEK);
+                if (wbyLong == null || dowLong == null) {
+                    return null;
+                }
+                int wby = WEEK_BASED_YEAR.range().checkValidIntValue(wbyLong, WEEK_BASED_YEAR);  // always validate
+                long wowby = fieldValues.get(WEEK_OF_WEEK_BASED_YEAR);
+                ensureIso(partialTemporal);
+                LocalDate date = LocalDate.of(wby, 1, 4);
+                if (resolverStyle == ResolverStyle.LENIENT) {
+                    long dow = dowLong;  // unvalidated
+                    if (dow > 7) {
+                        date = date.plusWeeks((dow - 1) / 7);
+                        dow = ((dow - 1) % 7) + 1;
+                    } else if (dow < 1) {
+                        date = date.plusWeeks(Math.subtractExact(dow,  7) / 7);
+                        dow = ((dow + 6) % 7) + 1;
+                    }
+                    date = date.plusWeeks(Math.subtractExact(wowby, 1)).with(DAY_OF_WEEK, dow);
+                } else {
+                    int dow = DAY_OF_WEEK.checkValidIntValue(dowLong);  // validated
+                    if (wowby < 1 || wowby > 52) {
+                        if (resolverStyle == ResolverStyle.STRICT) {
+                            getWeekRange(date).checkValidValue(wowby, this);  // only allow exact range
+                        } else {  // SMART
+                            range().checkValidValue(wowby, this);  // allow 1-53 rolling into next year
+                        }
+                    }
+                    date = date.plusWeeks(wowby - 1).with(DAY_OF_WEEK, dow);
+                }
+                fieldValues.remove(this);
+                fieldValues.remove(WEEK_BASED_YEAR);
+                fieldValues.remove(DAY_OF_WEEK);
+                return date;
+            }
+            @Override
+            public String toString() {
+                return "WeekOfWeekBasedYear";
+            }
+        },
+        WEEK_BASED_YEAR {
+            @Override
+            public TemporalUnit getBaseUnit() {
+                return WEEK_BASED_YEARS;
+            }
+            @Override
+            public TemporalUnit getRangeUnit() {
+                return FOREVER;
+            }
+            @Override
+            public ValueRange range() {
+                return YEAR.range();
+            }
+            @Override
+            public boolean isSupportedBy(TemporalAccessor temporal) {
+                return temporal.isSupported(EPOCH_DAY) && isIso(temporal);
+            }
+            @Override
+            public long getFrom(TemporalAccessor temporal) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: WeekBasedYear");
+                }
+                return getWeekBasedYear(LocalDate.from(temporal));
+            }
+            @SuppressWarnings("unchecked")
+            @Override
+            public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+                if (isSupportedBy(temporal) == false) {
+                    throw new UnsupportedTemporalTypeException("Unsupported field: WeekBasedYear");
+                }
+                int newWby = range().checkValidIntValue(newValue, WEEK_BASED_YEAR);  // strict check
+                LocalDate date = LocalDate.from(temporal);
+                int dow = date.get(DAY_OF_WEEK);
+                int week = getWeek(date);
+                if (week == 53 && getWeekRange(newWby) == 52) {
+                    week = 52;
+                }
+                LocalDate resolved = LocalDate.of(newWby, 1, 4);  // 4th is guaranteed to be in week one
+                int days = (dow - resolved.get(DAY_OF_WEEK)) + ((week - 1) * 7);
+                resolved = resolved.plusDays(days);
+                return (R) temporal.with(resolved);
+            }
+            @Override
+            public String toString() {
+                return "WeekBasedYear";
+            }
+        };
+
+        @Override
+        public boolean isDateBased() {
+            return true;
+        }
+
+        @Override
+        public boolean isTimeBased() {
+            return false;
+        }
+
+        @Override
+        public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+            return range();
+        }
+
+        //-------------------------------------------------------------------------
+        private static final int[] QUARTER_DAYS = {0, 90, 181, 273, 0, 91, 182, 274};
+
+        private static boolean isIso(TemporalAccessor temporal) {
+            return Chronology.from(temporal).equals(IsoChronology.INSTANCE);
+        }
+
+        private static void ensureIso(TemporalAccessor temporal) {
+            if (isIso(temporal) == false) {
+                throw new DateTimeException("Resolve requires IsoChronology");
+            }
+        }
+
+        private static ValueRange getWeekRange(LocalDate date) {
+            int wby = getWeekBasedYear(date);
+            return ValueRange.of(1, getWeekRange(wby));
+        }
+
+        private static int getWeekRange(int wby) {
+            LocalDate date = LocalDate.of(wby, 1, 1);
+            // 53 weeks if standard year starts on Thursday, or Wed in a leap year
+            if (date.getDayOfWeek() == THURSDAY || (date.getDayOfWeek() == WEDNESDAY && date.isLeapYear())) {
+                return 53;
+            }
+            return 52;
+        }
+
+        private static int getWeek(LocalDate date) {
+            int dow0 = date.getDayOfWeek().ordinal();
+            int doy0 = date.getDayOfYear() - 1;
+            int doyThu0 = doy0 + (3 - dow0);  // adjust to mid-week Thursday (which is 3 indexed from zero)
+            int alignedWeek = doyThu0 / 7;
+            int firstThuDoy0 = doyThu0 - (alignedWeek * 7);
+            int firstMonDoy0 = firstThuDoy0 - 3;
+            if (firstMonDoy0 < -3) {
+                firstMonDoy0 += 7;
+            }
+            if (doy0 < firstMonDoy0) {
+                return (int) getWeekRange(date.withDayOfYear(180).minusYears(1)).getMaximum();
+            }
+            int week = ((doy0 - firstMonDoy0) / 7) + 1;
+            if (week == 53) {
+                if ((firstMonDoy0 == -3 || (firstMonDoy0 == -2 && date.isLeapYear())) == false) {
+                    week = 1;
+                }
+            }
+            return week;
+        }
+
+        private static int getWeekBasedYear(LocalDate date) {
+            int year = date.getYear();
+            int doy = date.getDayOfYear();
+            if (doy <= 3) {
+                int dow = date.getDayOfWeek().ordinal();
+                if (doy - dow < -2) {
+                    year--;
+                }
+            } else if (doy >= 363) {
+                int dow = date.getDayOfWeek().ordinal();
+                doy = doy - 363 - (date.isLeapYear() ? 1 : 0);
+                if (doy - dow >= 0) {
+                    year++;
+                }
+            }
+            return year;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implementation of the unit.
+     */
+    private static enum Unit implements TemporalUnit {
+
+        /**
+         * Unit that represents the concept of a week-based-year.
+         */
+        WEEK_BASED_YEARS("WeekBasedYears", Duration.ofSeconds(31556952L)),
+        /**
+         * Unit that represents the concept of a quarter-year.
+         */
+        QUARTER_YEARS("QuarterYears", Duration.ofSeconds(31556952L / 4));
+
+        private final String name;
+        private final Duration duration;
+
+        private Unit(String name, Duration estimatedDuration) {
+            this.name = name;
+            this.duration = estimatedDuration;
+        }
+
+        @Override
+        public Duration getDuration() {
+            return duration;
+        }
+
+        @Override
+        public boolean isDurationEstimated() {
+            return true;
+        }
+
+        @Override
+        public boolean isDateBased() {
+            return true;
+        }
+
+        @Override
+        public boolean isTimeBased() {
+            return false;
+        }
+
+        @Override
+        public boolean isSupportedBy(Temporal temporal) {
+            return temporal.isSupported(EPOCH_DAY);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R addTo(R temporal, long amount) {
+            switch (this) {
+                case WEEK_BASED_YEARS:
+                    return (R) temporal.with(WEEK_BASED_YEAR,
+                            Math.addExact(temporal.get(WEEK_BASED_YEAR), amount));
+                case QUARTER_YEARS:
+                    // no overflow (256 is multiple of 4)
+                    return (R) temporal.plus(amount / 256, YEARS)
+                            .plus((amount % 256) * 3, MONTHS);
+                default:
+                    throw new IllegalStateException("Unreachable");
+            }
+        }
+
+        @Override
+        public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) {
+            if (temporal1Inclusive.getClass() != temporal2Exclusive.getClass()) {
+                return temporal1Inclusive.until(temporal2Exclusive, this);
+            }
+            switch(this) {
+                case WEEK_BASED_YEARS:
+                    return Math.subtractExact(temporal2Exclusive.getLong(WEEK_BASED_YEAR),
+                            temporal1Inclusive.getLong(WEEK_BASED_YEAR));
+                case QUARTER_YEARS:
+                    return temporal1Inclusive.until(temporal2Exclusive, MONTHS) / 3;
+                default:
+                    throw new IllegalStateException("Unreachable");
+            }
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+}
diff --git a/java/time/temporal/JulianFields.java b/java/time/temporal/JulianFields.java
new file mode 100644
index 0000000..3270379
--- /dev/null
+++ b/java/time/temporal/JulianFields.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+
+import java.time.DateTimeException;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Chronology;
+import java.time.format.ResolverStyle;
+import java.util.Map;
+
+/**
+ * A set of date fields that provide access to Julian Days.
+ * <p>
+ * The Julian Day is a standard way of expressing date and time commonly used in the scientific community.
+ * It is expressed as a decimal number of whole days where days start at midday.
+ * This class represents variations on Julian Days that count whole days from midnight.
+ * <p>
+ * The fields are implemented relative to {@link ChronoField#EPOCH_DAY EPOCH_DAY}.
+ * The fields are supported, and can be queried and set if {@code EPOCH_DAY} is available.
+ * The fields work with all chronologies.
+ *
+ * @implSpec
+ * This is an immutable and thread-safe class.
+ *
+ * @since 1.8
+ */
+public final class JulianFields {
+
+    /**
+     * The offset from Julian to EPOCH DAY.
+     */
+    private static final long JULIAN_DAY_OFFSET = 2440588L;
+
+    /**
+     * Julian Day field.
+     * <p>
+     * This is an integer-based version of the Julian Day Number.
+     * Julian Day is a well-known system that represents the count of whole days since day 0,
+     * which is defined to be January 1, 4713 BCE in the Julian calendar, and -4713-11-24 Gregorian.
+     * The field  has "JulianDay" as 'name', and 'DAYS' as 'baseUnit'.
+     * The field always refers to the local date-time, ignoring the offset or zone.
+     * <p>
+     * For date-times, 'JULIAN_DAY.getFrom()' assumes the same value from
+     * midnight until just before the next midnight.
+     * When 'JULIAN_DAY.adjustInto()' is applied to a date-time, the time of day portion remains unaltered.
+     * 'JULIAN_DAY.adjustInto()' and 'JULIAN_DAY.getFrom()' only apply to {@code Temporal} objects that
+     * can be converted into {@link ChronoField#EPOCH_DAY}.
+     * An {@link UnsupportedTemporalTypeException} is thrown for any other type of object.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a Julian Day field.
+     * In {@linkplain ResolverStyle#STRICT strict mode} and {@linkplain ResolverStyle#SMART smart mode}
+     * the Julian Day value is validated against the range of valid values.
+     * In {@linkplain ResolverStyle#LENIENT lenient mode} no validation occurs.
+     *
+     * <h3>Astronomical and Scientific Notes</h3>
+     * The standard astronomical definition uses a fraction to indicate the time-of-day,
+     * thus 3.25 would represent the time 18:00, since days start at midday.
+     * This implementation uses an integer and days starting at midnight.
+     * The integer value for the Julian Day Number is the astronomical Julian Day value at midday
+     * of the date in question.
+     * This amounts to the astronomical Julian Day, rounded to an integer {@code JDN = floor(JD + 0.5)}.
+     *
+     * <pre>
+     *  | ISO date          |  Julian Day Number | Astronomical Julian Day |
+     *  | 1970-01-01T00:00  |         2,440,588  |         2,440,587.5     |
+     *  | 1970-01-01T06:00  |         2,440,588  |         2,440,587.75    |
+     *  | 1970-01-01T12:00  |         2,440,588  |         2,440,588.0     |
+     *  | 1970-01-01T18:00  |         2,440,588  |         2,440,588.25    |
+     *  | 1970-01-02T00:00  |         2,440,589  |         2,440,588.5     |
+     *  | 1970-01-02T06:00  |         2,440,589  |         2,440,588.75    |
+     *  | 1970-01-02T12:00  |         2,440,589  |         2,440,589.0     |
+     * </pre>
+     * <p>
+     * Julian Days are sometimes taken to imply Universal Time or UTC, but this
+     * implementation always uses the Julian Day number for the local date,
+     * regardless of the offset or time-zone.
+     */
+    public static final TemporalField JULIAN_DAY = Field.JULIAN_DAY;
+
+    /**
+     * Modified Julian Day field.
+     * <p>
+     * This is an integer-based version of the Modified Julian Day Number.
+     * Modified Julian Day (MJD) is a well-known system that counts days continuously.
+     * It is defined relative to astronomical Julian Day as  {@code MJD = JD - 2400000.5}.
+     * Each Modified Julian Day runs from midnight to midnight.
+     * The field always refers to the local date-time, ignoring the offset or zone.
+     * <p>
+     * For date-times, 'MODIFIED_JULIAN_DAY.getFrom()' assumes the same value from
+     * midnight until just before the next midnight.
+     * When 'MODIFIED_JULIAN_DAY.adjustInto()' is applied to a date-time, the time of day portion remains unaltered.
+     * 'MODIFIED_JULIAN_DAY.adjustInto()' and 'MODIFIED_JULIAN_DAY.getFrom()' only apply to {@code Temporal} objects
+     * that can be converted into {@link ChronoField#EPOCH_DAY}.
+     * An {@link UnsupportedTemporalTypeException} is thrown for any other type of object.
+     * <p>
+     * This implementation is an integer version of MJD with the decimal part rounded to floor.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a Modified Julian Day field.
+     * In {@linkplain ResolverStyle#STRICT strict mode} and {@linkplain ResolverStyle#SMART smart mode}
+     * the Modified Julian Day value is validated against the range of valid values.
+     * In {@linkplain ResolverStyle#LENIENT lenient mode} no validation occurs.
+     *
+     * <h3>Astronomical and Scientific Notes</h3>
+     * <pre>
+     *  | ISO date          | Modified Julian Day |      Decimal MJD |
+     *  | 1970-01-01T00:00  |             40,587  |       40,587.0   |
+     *  | 1970-01-01T06:00  |             40,587  |       40,587.25  |
+     *  | 1970-01-01T12:00  |             40,587  |       40,587.5   |
+     *  | 1970-01-01T18:00  |             40,587  |       40,587.75  |
+     *  | 1970-01-02T00:00  |             40,588  |       40,588.0   |
+     *  | 1970-01-02T06:00  |             40,588  |       40,588.25  |
+     *  | 1970-01-02T12:00  |             40,588  |       40,588.5   |
+     * </pre>
+     *
+     * Modified Julian Days are sometimes taken to imply Universal Time or UTC, but this
+     * implementation always uses the Modified Julian Day for the local date,
+     * regardless of the offset or time-zone.
+     */
+    public static final TemporalField MODIFIED_JULIAN_DAY = Field.MODIFIED_JULIAN_DAY;
+
+    /**
+     * Rata Die field.
+     * <p>
+     * Rata Die counts whole days continuously starting day 1 at midnight at the beginning of 0001-01-01 (ISO).
+     * The field always refers to the local date-time, ignoring the offset or zone.
+     * <p>
+     * For date-times, 'RATA_DIE.getFrom()' assumes the same value from
+     * midnight until just before the next midnight.
+     * When 'RATA_DIE.adjustInto()' is applied to a date-time, the time of day portion remains unaltered.
+     * 'RATA_DIE.adjustInto()' and 'RATA_DIE.getFrom()' only apply to {@code Temporal} objects
+     * that can be converted into {@link ChronoField#EPOCH_DAY}.
+     * An {@link UnsupportedTemporalTypeException} is thrown for any other type of object.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a Rata Die field.
+     * In {@linkplain ResolverStyle#STRICT strict mode} and {@linkplain ResolverStyle#SMART smart mode}
+     * the Rata Die value is validated against the range of valid values.
+     * In {@linkplain ResolverStyle#LENIENT lenient mode} no validation occurs.
+     */
+    public static final TemporalField RATA_DIE = Field.RATA_DIE;
+
+    /**
+     * Restricted constructor.
+     */
+    private JulianFields() {
+        throw new AssertionError("Not instantiable");
+    }
+
+    /**
+     * Implementation of JulianFields.  Each instance is a singleton.
+     */
+    private static enum Field implements TemporalField {
+        JULIAN_DAY("JulianDay", DAYS, FOREVER, JULIAN_DAY_OFFSET),
+        MODIFIED_JULIAN_DAY("ModifiedJulianDay", DAYS, FOREVER, 40587L),
+        RATA_DIE("RataDie", DAYS, FOREVER, 719163L);
+
+        private static final long serialVersionUID = -7501623920830201812L;
+
+        private final transient String name;
+        private final transient TemporalUnit baseUnit;
+        private final transient TemporalUnit rangeUnit;
+        private final transient ValueRange range;
+        private final transient long offset;
+
+        private Field(String name, TemporalUnit baseUnit, TemporalUnit rangeUnit, long offset) {
+            this.name = name;
+            this.baseUnit = baseUnit;
+            this.rangeUnit = rangeUnit;
+            this.range = ValueRange.of(-365243219162L + offset, 365241780471L + offset);
+            this.offset = offset;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public TemporalUnit getBaseUnit() {
+            return baseUnit;
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            return rangeUnit;
+        }
+
+        @Override
+        public boolean isDateBased() {
+            return true;
+        }
+
+        @Override
+        public boolean isTimeBased() {
+            return false;
+        }
+
+        @Override
+        public ValueRange range() {
+            return range;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public boolean isSupportedBy(TemporalAccessor temporal) {
+            return temporal.isSupported(EPOCH_DAY);
+        }
+
+        @Override
+        public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+            if (isSupportedBy(temporal) == false) {
+                throw new DateTimeException("Unsupported field: " + this);
+            }
+            return range();
+        }
+
+        @Override
+        public long getFrom(TemporalAccessor temporal) {
+            return temporal.getLong(EPOCH_DAY) + offset;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+            if (range().isValidValue(newValue) == false) {
+                throw new DateTimeException("Invalid value: " + name + " " + newValue);
+            }
+            return (R) temporal.with(EPOCH_DAY, Math.subtractExact(newValue, offset));
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public ChronoLocalDate resolve(
+                Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
+            long value = fieldValues.remove(this);
+            Chronology chrono = Chronology.from(partialTemporal);
+            if (resolverStyle == ResolverStyle.LENIENT) {
+                return chrono.dateEpochDay(Math.subtractExact(value, offset));
+            }
+            range().checkValidValue(value, this);
+            return chrono.dateEpochDay(value - offset);
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+}
diff --git a/java/time/temporal/Temporal.java b/java/time/temporal/Temporal.java
new file mode 100644
index 0000000..f7064aa
--- /dev/null
+++ b/java/time/temporal/Temporal.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+
+/**
+ * Framework-level interface defining read-write access to a temporal object,
+ * such as a date, time, offset or some combination of these.
+ * <p>
+ * This is the base interface type for date, time and offset objects that
+ * are complete enough to be manipulated using plus and minus.
+ * It is implemented by those classes that can provide and manipulate information
+ * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}.
+ * See {@link TemporalAccessor} for the read-only version of this interface.
+ * <p>
+ * Most date and time information can be represented as a number.
+ * These are modeled using {@code TemporalField} with the number held using
+ * a {@code long} to handle large values. Year, month and day-of-month are
+ * simple examples of fields, but they also include instant and offsets.
+ * See {@link ChronoField} for the standard set of fields.
+ * <p>
+ * Two pieces of date/time information cannot be represented by numbers,
+ * the {@linkplain java.time.chrono.Chronology chronology} and the
+ * {@linkplain java.time.ZoneId time-zone}.
+ * These can be accessed via {@link #query(TemporalQuery) queries} using
+ * the static methods defined on {@link TemporalQuery}.
+ * <p>
+ * This interface is a framework-level interface that should not be widely
+ * used in application code. Instead, applications should create and pass
+ * around instances of concrete types, such as {@code LocalDate}.
+ * There are many reasons for this, part of which is that implementations
+ * of this interface may be in calendar systems other than ISO.
+ * See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues.
+ *
+ * <h3>When to implement</h3>
+ * <p>
+ * A class should implement this interface if it meets three criteria:
+ * <ul>
+ * <li>it provides access to date/time/offset information, as per {@code TemporalAccessor}
+ * <li>the set of fields are contiguous from the largest to the smallest
+ * <li>the set of fields are complete, such that no other field is needed to define the
+ *  valid range of values for the fields that are represented
+ * </ul>
+ * <p>
+ * Four examples make this clear:
+ * <ul>
+ * <li>{@code LocalDate} implements this interface as it represents a set of fields
+ *  that are contiguous from days to forever and require no external information to determine
+ *  the validity of each date. It is therefore able to implement plus/minus correctly.
+ * <li>{@code LocalTime} implements this interface as it represents a set of fields
+ *  that are contiguous from nanos to within days and require no external information to determine
+ *  validity. It is able to implement plus/minus correctly, by wrapping around the day.
+ * <li>{@code MonthDay}, the combination of month-of-year and day-of-month, does not implement
+ *  this interface.  While the combination is contiguous, from days to months within years,
+ *  the combination does not have sufficient information to define the valid range of values
+ *  for day-of-month.  As such, it is unable to implement plus/minus correctly.
+ * <li>The combination day-of-week and day-of-month ("Friday the 13th") should not implement
+ *  this interface. It does not represent a contiguous set of fields, as days to weeks overlaps
+ *  days to months.
+ * </ul>
+ *
+ * @implSpec
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ * All implementations must be {@link Comparable}.
+ *
+ * @since 1.8
+ */
+public interface Temporal extends TemporalAccessor {
+
+    /**
+     * Checks if the specified unit is supported.
+     * <p>
+     * This checks if the specified unit can be added to, or subtracted from, this date-time.
+     * If false, then calling the {@link #plus(long, TemporalUnit)} and
+     * {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
+     *
+     * @implSpec
+     * Implementations must check and handle all units defined in {@link ChronoUnit}.
+     * If the unit is supported, then true must be returned, otherwise false must be returned.
+     * <p>
+     * If the field is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
+     * passing {@code this} as the argument.
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     *
+     * @param unit  the unit to check, null returns false
+     * @return true if the unit can be added/subtracted, false if not
+     */
+    boolean isSupported(TemporalUnit unit);
+
+    /**
+     * Returns an adjusted object of the same type as this object with the adjustment made.
+     * <p>
+     * This adjusts this date-time according to the rules of the specified adjuster.
+     * A simple adjuster might simply set the one of the fields, such as the year field.
+     * A more complex adjuster might set the date to the last day of the month.
+     * A selection of common adjustments is provided in
+     * {@link java.time.temporal.TemporalAdjusters TemporalAdjusters}.
+     * These include finding the "last day of the month" and "next Wednesday".
+     * The adjuster is responsible for handling special cases, such as the varying
+     * lengths of month and leap years.
+     * <p>
+     * Some example code indicating how and why this method is used:
+     * <pre>
+     *  date = date.with(Month.JULY);        // most key classes implement TemporalAdjuster
+     *  date = date.with(lastDayOfMonth());  // static import from Adjusters
+     *  date = date.with(next(WEDNESDAY));   // static import from Adjusters and DayOfWeek
+     * </pre>
+     *
+     * @implSpec
+     * <p>
+     * Implementations must not alter either this object or the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return adjuster.adjustInto(this);
+     * </pre>
+     *
+     * @param adjuster  the adjuster to use, not null
+     * @return an object of the same type with the specified adjustment made, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    default Temporal with(TemporalAdjuster adjuster) {
+        return adjuster.adjustInto(this);
+    }
+
+    /**
+     * Returns an object of the same type as this object with the specified field altered.
+     * <p>
+     * This returns a new object based on this one with the value for the specified field changed.
+     * For example, on a {@code LocalDate}, this could be used to set the year, month or day-of-month.
+     * The returned object will have the same observable type as this object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st January, then changing the month to February would be unclear.
+     * In cases like this, the field is responsible for resolving the result. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     *
+     * @implSpec
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then the adjustment must be performed.
+     * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.adjustInto(Temporal, long)}
+     * passing {@code this} as the first argument.
+     * <p>
+     * Implementations must not alter this object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     *
+     * @param field  the field to set in the result, not null
+     * @param newValue  the new value of the field in the result
+     * @return an object of the same type with the specified field set, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal with(TemporalField field, long newValue);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an object of the same type as this object with an amount added.
+     * <p>
+     * This adjusts this temporal, adding according to the rules of the specified amount.
+     * The amount is typically a {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface, such as {@link java.time.Duration}.
+     * <p>
+     * Some example code indicating how and why this method is used:
+     * <pre>
+     *  date = date.plus(period);                // add a Period instance
+     *  date = date.plus(duration);              // add a Duration instance
+     *  date = date.plus(workingDays(6));        // example user-written workingDays method
+     * </pre>
+     * <p>
+     * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
+     * return the same date-time.
+     *
+     * @implSpec
+     * <p>
+     * Implementations must not alter either this object or the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return amount.addTo(this);
+     * </pre>
+     *
+     * @param amount  the amount to add, not null
+     * @return an object of the same type with the specified adjustment made, not null
+     * @throws DateTimeException if the addition cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    default Temporal plus(TemporalAmount amount) {
+        return amount.addTo(this);
+    }
+
+    /**
+     * Returns an object of the same type as this object with the specified period added.
+     * <p>
+     * This method returns a new object based on this one with the specified period added.
+     * For example, on a {@code LocalDate}, this could be used to add a number of years, months or days.
+     * The returned object will have the same observable type as this object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st January, then adding one month would be unclear.
+     * In cases like this, the field is responsible for resolving the result. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     *
+     * @implSpec
+     * Implementations must check and handle all units defined in {@link ChronoUnit}.
+     * If the unit is supported, then the addition must be performed.
+     * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.addTo(Temporal, long)}
+     * passing {@code this} as the first argument.
+     * <p>
+     * Implementations must not alter this object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     *
+     * @param amountToAdd  the amount of the specified unit to add, may be negative
+     * @param unit  the unit of the amount to add, not null
+     * @return an object of the same type with the specified period added, not null
+     * @throws DateTimeException if the unit cannot be added
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal plus(long amountToAdd, TemporalUnit unit);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns an object of the same type as this object with an amount subtracted.
+     * <p>
+     * This adjusts this temporal, subtracting according to the rules of the specified amount.
+     * The amount is typically a {@link java.time.Period} but may be any other type implementing
+     * the {@link TemporalAmount} interface, such as {@link java.time.Duration}.
+     * <p>
+     * Some example code indicating how and why this method is used:
+     * <pre>
+     *  date = date.minus(period);               // subtract a Period instance
+     *  date = date.minus(duration);             // subtract a Duration instance
+     *  date = date.minus(workingDays(6));       // example user-written workingDays method
+     * </pre>
+     * <p>
+     * Note that calling {@code plus} followed by {@code minus} is not guaranteed to
+     * return the same date-time.
+     *
+     * @implSpec
+     * <p>
+     * Implementations must not alter either this object or the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return amount.subtractFrom(this);
+     * </pre>
+     *
+     * @param amount  the amount to subtract, not null
+     * @return an object of the same type with the specified adjustment made, not null
+     * @throws DateTimeException if the subtraction cannot be made
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    default Temporal minus(TemporalAmount amount) {
+        return amount.subtractFrom(this);
+    }
+
+    /**
+     * Returns an object of the same type as this object with the specified period subtracted.
+     * <p>
+     * This method returns a new object based on this one with the specified period subtracted.
+     * For example, on a {@code LocalDate}, this could be used to subtract a number of years, months or days.
+     * The returned object will have the same observable type as this object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st March, then subtracting one month would be unclear.
+     * In cases like this, the field is responsible for resolving the result. Typically it will choose
+     * the previous valid date, which would be the last valid day of February in this example.
+     *
+     * @implSpec
+     * Implementations must behave in a manor equivalent to the default method behavior.
+     * <p>
+     * Implementations must not alter this object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  return (amountToSubtract == Long.MIN_VALUE ?
+     *      plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+     * </pre>
+     *
+     * @param amountToSubtract  the amount of the specified unit to subtract, may be negative
+     * @param unit  the unit of the amount to subtract, not null
+     * @return an object of the same type with the specified period subtracted, not null
+     * @throws DateTimeException if the unit cannot be subtracted
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    default Temporal minus(long amountToSubtract, TemporalUnit unit) {
+        return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Calculates the amount of time until another temporal in terms of the specified unit.
+     * <p>
+     * This calculates the amount of time between two temporal objects
+     * in terms of a single {@code TemporalUnit}.
+     * The start and end points are {@code this} and the specified temporal.
+     * The end point is converted to be of the same type as the start point if different.
+     * The result will be negative if the end is before the start.
+     * For example, the amount in hours between two temporal objects can be
+     * calculated using {@code startTime.until(endTime, HOURS)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two temporals.
+     * For example, the amount in hours between the times 11:30 and 13:29
+     * will only be one hour as it is one minute short of two hours.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   temporal = start.until(end, unit);
+     *   temporal = unit.between(start, end);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * For example, this method allows the number of days between two dates to
+     * be calculated:
+     * <pre>
+     *  long daysBetween = start.until(end, DAYS);
+     *  // or alternatively
+     *  long daysBetween = DAYS.between(start, end);
+     * </pre>
+     *
+     * @implSpec
+     * Implementations must begin by checking to ensure that the input temporal
+     * object is of the same observable type as the implementation.
+     * They must then perform the calculation for all instances of {@link ChronoUnit}.
+     * An {@code UnsupportedTemporalTypeException} must be thrown for {@code ChronoUnit}
+     * instances that are unsupported.
+     * <p>
+     * If the unit is not a {@code ChronoUnit}, then the result of this method
+     * is obtained by invoking {@code TemporalUnit.between(Temporal, Temporal)}
+     * passing {@code this} as the first argument and the converted input temporal as
+     * the second argument.
+     * <p>
+     * In summary, implementations must behave in a manner equivalent to this pseudo-code:
+     * <pre>
+     *  // convert the end temporal to the same type as this class
+     *  if (unit instanceof ChronoUnit) {
+     *    // if unit is supported, then calculate and return result
+     *    // else throw UnsupportedTemporalTypeException for unsupported units
+     *  }
+     *  return unit.between(this, convertedEndTemporal);
+     * </pre>
+     * <p>
+     * Note that the unit's {@code between} method must only be invoked if the
+     * two temporal objects have exactly the same type evaluated by {@code getClass()}.
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     *
+     * @param endExclusive  the end temporal, exclusive, converted to be of the
+     *  same type as this object, not null
+     * @param unit  the unit to measure the amount in, not null
+     * @return the amount of time between this temporal object and the specified one
+     *  in terms of the unit; positive if the specified object is later than this one,
+     *  negative if it is earlier than this one
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to the same type as this temporal
+     * @throws UnsupportedTemporalTypeException if the unit is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    long until(Temporal endExclusive, TemporalUnit unit);
+
+}
diff --git a/java/time/temporal/TemporalAccessor.java b/java/time/temporal/TemporalAccessor.java
new file mode 100644
index 0000000..5e8b61e
--- /dev/null
+++ b/java/time/temporal/TemporalAccessor.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.util.Objects;
+
+/**
+ * Framework-level interface defining read-only access to a temporal object,
+ * such as a date, time, offset or some combination of these.
+ * <p>
+ * This is the base interface type for date, time and offset objects.
+ * It is implemented by those classes that can provide information
+ * as {@linkplain TemporalField fields} or {@linkplain TemporalQuery queries}.
+ * <p>
+ * Most date and time information can be represented as a number.
+ * These are modeled using {@code TemporalField} with the number held using
+ * a {@code long} to handle large values. Year, month and day-of-month are
+ * simple examples of fields, but they also include instant and offsets.
+ * See {@link ChronoField} for the standard set of fields.
+ * <p>
+ * Two pieces of date/time information cannot be represented by numbers,
+ * the {@linkplain java.time.chrono.Chronology chronology} and the
+ * {@linkplain java.time.ZoneId time-zone}.
+ * These can be accessed via {@linkplain #query(TemporalQuery) queries} using
+ * the static methods defined on {@link TemporalQuery}.
+ * <p>
+ * A sub-interface, {@link Temporal}, extends this definition to one that also
+ * supports adjustment and manipulation on more complete temporal objects.
+ * <p>
+ * This interface is a framework-level interface that should not be widely
+ * used in application code. Instead, applications should create and pass
+ * around instances of concrete types, such as {@code LocalDate}.
+ * There are many reasons for this, part of which is that implementations
+ * of this interface may be in calendar systems other than ISO.
+ * See {@link java.time.chrono.ChronoLocalDate} for a fuller discussion of the issues.
+ *
+ * @implSpec
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @since 1.8
+ */
+public interface TemporalAccessor {
+
+    /**
+     * Checks if the specified field is supported.
+     * <p>
+     * This checks if the date-time can be queried for the specified field.
+     * If false, then calling the {@link #range(TemporalField) range} and {@link #get(TemporalField) get}
+     * methods will throw an exception.
+     *
+     * @implSpec
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then true must be returned, otherwise false must be returned.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     *
+     * @param field  the field to check, null returns false
+     * @return true if this date-time can be queried for the field, false if not
+     */
+    boolean isSupported(TemporalField field);
+
+    /**
+     * Gets the range of valid values for the specified field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * The value of this temporal object is used to enhance the accuracy of the returned range.
+     * If the date-time cannot return the range, because the field is unsupported or for
+     * some other reason, an exception will be thrown.
+     * <p>
+     * Note that the result only describes the minimum and maximum valid values
+     * and it is important not to read too much into them. For example, there
+     * could be values within the range that are invalid for the field.
+     *
+     * @implSpec
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then the range of the field must be returned.
+     * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessorl)}
+     * passing {@code this} as the argument.
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  if (field instanceof ChronoField) {
+     *    if (isSupported(field)) {
+     *      return field.range();
+     *    }
+     *    throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+     *  }
+     *  return field.rangeRefinedBy(this);
+     * </pre>
+     *
+     * @param field  the field to query the range for, not null
+     * @return the range of valid values for the field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     */
+    default ValueRange range(TemporalField field) {
+        if (field instanceof ChronoField) {
+            if (isSupported(field)) {
+                return field.range();
+            }
+            throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
+        }
+        Objects.requireNonNull(field, "field");
+        return field.rangeRefinedBy(this);
+    }
+
+    /**
+     * Gets the value of the specified field as an {@code int}.
+     * <p>
+     * This queries the date-time for the value of the specified field.
+     * The returned value will always be within the valid range of values for the field.
+     * If the date-time cannot return the value, because the field is unsupported or for
+     * some other reason, an exception will be thrown.
+     *
+     * @implSpec
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported and has an {@code int} range, then the value of
+     * the field must be returned.
+     * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     * <p>
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  if (range(field).isIntValue()) {
+     *    return range(field).checkValidIntValue(getLong(field), field);
+     *  }
+     *  throw new UnsupportedTemporalTypeException("Invalid field " + field + " + for get() method, use getLong() instead");
+     * </pre>
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field, within the valid range of values
+     * @throws DateTimeException if a value for the field cannot be obtained or
+     *         the value is outside the range of valid values for the field
+     * @throws UnsupportedTemporalTypeException if the field is not supported or
+     *         the range of values exceeds an {@code int}
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    default int get(TemporalField field) {
+        ValueRange range = range(field);
+        if (range.isIntValue() == false) {
+            throw new UnsupportedTemporalTypeException("Invalid field " + field + " for get() method, use getLong() instead");
+        }
+        long value = getLong(field);
+        if (range.isValidValue(value) == false) {
+            throw new DateTimeException("Invalid value for " + field + " (valid values " + range + "): " + value);
+        }
+        return (int) value;
+    }
+
+    /**
+     * Gets the value of the specified field as a {@code long}.
+     * <p>
+     * This queries the date-time for the value of the specified field.
+     * The returned value may be outside the valid range of values for the field.
+     * If the date-time cannot return the value, because the field is unsupported or for
+     * some other reason, an exception will be thrown.
+     *
+     * @implSpec
+     * Implementations must check and handle all fields defined in {@link ChronoField}.
+     * If the field is supported, then the value of the field must be returned.
+     * If unsupported, then an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * If the field is not a {@code ChronoField}, then the result of this method
+     * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
+     * passing {@code this} as the argument.
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     *
+     * @param field  the field to get, not null
+     * @return the value for the field
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    long getLong(TemporalField field);
+
+    /**
+     * Queries this date-time.
+     * <p>
+     * This queries this date-time using the specified query strategy object.
+     * <p>
+     * Queries are a key tool for extracting information from date-times.
+     * They exists to externalize the process of querying, permitting different
+     * approaches, as per the strategy design pattern.
+     * Examples might be a query that checks if the date is the day before February 29th
+     * in a leap year, or calculates the number of days to your next birthday.
+     * <p>
+     * The most common query implementations are method references, such as
+     * {@code LocalDate::from} and {@code ZoneId::from}.
+     * Additional implementations are provided as static methods on {@link TemporalQuery}.
+     *
+     * @implSpec
+     * The default implementation must behave equivalent to this code:
+     * <pre>
+     *  if (query == TemporalQueries.zoneId() ||
+     *        query == TemporalQueries.chronology() || query == TemporalQueries.precision()) {
+     *    return null;
+     *  }
+     *  return query.queryFrom(this);
+     * </pre>
+     * Future versions are permitted to add further queries to the if statement.
+     * <p>
+     * All classes implementing this interface and overriding this method must call
+     * {@code TemporalAccessor.super.query(query)}. JDK classes may avoid calling
+     * super if they provide behavior equivalent to the default behaviour, however
+     * non-JDK classes may not utilize this optimization and must call {@code super}.
+     * <p>
+     * If the implementation can supply a value for one of the queries listed in the
+     * if statement of the default implementation, then it must do so.
+     * For example, an application-defined {@code HourMin} class storing the hour
+     * and minute must override this method as follows:
+     * <pre>
+     *  if (query == TemporalQueries.precision()) {
+     *    return MINUTES;
+     *  }
+     *  return TemporalAccessor.super.query(query);
+     * </pre>
+     * <p>
+     * Implementations must ensure that no observable state is altered when this
+     * read-only method is invoked.
+     *
+     * @param <R> the type of the result
+     * @param query  the query to invoke, not null
+     * @return the query result, null may be returned (defined by the query)
+     * @throws DateTimeException if unable to query
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    default <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zoneId()
+                || query == TemporalQueries.chronology()
+                || query == TemporalQueries.precision()) {
+            return null;
+        }
+        return query.queryFrom(this);
+    }
+
+}
diff --git a/java/time/temporal/TemporalAdjuster.java b/java/time/temporal/TemporalAdjuster.java
new file mode 100644
index 0000000..09b5fba
--- /dev/null
+++ b/java/time/temporal/TemporalAdjuster.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+
+/**
+ * Strategy for adjusting a temporal object.
+ * <p>
+ * Adjusters are a key tool for modifying temporal objects.
+ * They exist to externalize the process of adjustment, permitting different
+ * approaches, as per the strategy design pattern.
+ * Examples might be an adjuster that sets the date avoiding weekends, or one that
+ * sets the date to the last day of the month.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalAdjuster}.
+ * The first is to invoke the method on this interface directly.
+ * The second is to use {@link Temporal#with(TemporalAdjuster)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   temporal = thisAdjuster.adjustInto(temporal);
+ *   temporal = temporal.with(thisAdjuster);
+ * </pre>
+ * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * The {@link TemporalAdjusters} class contains a standard set of adjusters,
+ * available as static methods.
+ * These include:
+ * <ul>
+ * <li>finding the first or last day of the month
+ * <li>finding the first day of next month
+ * <li>finding the first or last day of the year
+ * <li>finding the first day of next year
+ * <li>finding the first or last day-of-week within a month, such as "first Wednesday in June"
+ * <li>finding the next or previous day-of-week, such as "next Thursday"
+ * </ul>
+ *
+ * @implSpec
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @see TemporalAdjusters
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface TemporalAdjuster {
+
+    /**
+     * Adjusts the specified temporal object.
+     * <p>
+     * This adjusts the specified temporal object using the logic
+     * encapsulated in the implementing class.
+     * Examples might be an adjuster that sets the date avoiding weekends, or one that
+     * sets the date to the last day of the month.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#with(TemporalAdjuster)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisAdjuster.adjustInto(temporal);
+     *   temporal = temporal.with(thisAdjuster);
+     * </pre>
+     * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
+     * as it is a lot clearer to read in code.
+     *
+     * @implSpec
+     * The implementation must take the input object and adjust it.
+     * The implementation defines the logic of the adjustment and is responsible for
+     * documenting that logic. It may use any method on {@code Temporal} to
+     * query the temporal object and perform the adjustment.
+     * The returned object must have the same observable type as the input object
+     * <p>
+     * The input object must not be altered.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable temporal objects.
+     * <p>
+     * The input temporal object may be in a calendar system other than ISO.
+     * Implementations may choose to document compatibility with other calendar systems,
+     * or reject non-ISO temporal objects by {@link TemporalQueries#chronology() querying the chronology}.
+     * <p>
+     * This method may be called from multiple threads in parallel.
+     * It must be thread-safe when invoked.
+     *
+     * @param temporal  the temporal object to adjust, not null
+     * @return an object of the same observable type with the adjustment made, not null
+     * @throws DateTimeException if unable to make the adjustment
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal adjustInto(Temporal temporal);
+
+}
diff --git a/java/time/temporal/TemporalAdjusters.java b/java/time/temporal/TemporalAdjusters.java
new file mode 100644
index 0000000..0180c81
--- /dev/null
+++ b/java/time/temporal/TemporalAdjusters.java
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012-2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.util.Objects;
+import java.util.function.UnaryOperator;
+
+/**
+ * Common and useful TemporalAdjusters.
+ * <p>
+ * Adjusters are a key tool for modifying temporal objects.
+ * They exist to externalize the process of adjustment, permitting different
+ * approaches, as per the strategy design pattern.
+ * Examples might be an adjuster that sets the date avoiding weekends, or one that
+ * sets the date to the last day of the month.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalAdjuster}.
+ * The first is to invoke the method on the interface directly.
+ * The second is to use {@link Temporal#with(TemporalAdjuster)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   temporal = thisAdjuster.adjustInto(temporal);
+ *   temporal = temporal.with(thisAdjuster);
+ * </pre>
+ * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * This class contains a standard set of adjusters, available as static methods.
+ * These include:
+ * <ul>
+ * <li>finding the first or last day of the month
+ * <li>finding the first day of next month
+ * <li>finding the first or last day of the year
+ * <li>finding the first day of next year
+ * <li>finding the first or last day-of-week within a month, such as "first Wednesday in June"
+ * <li>finding the next or previous day-of-week, such as "next Thursday"
+ * </ul>
+ *
+ * @implSpec
+ * All the implementations supplied by the static methods are immutable.
+ *
+ * @see TemporalAdjuster
+ * @since 1.8
+ */
+public final class TemporalAdjusters {
+
+    /**
+     * Private constructor since this is a utility class.
+     */
+    private TemporalAdjusters() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains a {@code TemporalAdjuster} that wraps a date adjuster.
+     * <p>
+     * The {@code TemporalAdjuster} is based on the low level {@code Temporal} interface.
+     * This method allows an adjustment from {@code LocalDate} to {@code LocalDate}
+     * to be wrapped to match the temporal-based interface.
+     * This is provided for convenience to make user-written adjusters simpler.
+     * <p>
+     * In general, user-written adjusters should be static constants:
+     * <pre>{@code
+     *  static TemporalAdjuster TWO_DAYS_LATER =
+     *       TemporalAdjusters.ofDateAdjuster(date -> date.plusDays(2));
+     * }</pre>
+     *
+     * @param dateBasedAdjuster  the date-based adjuster, not null
+     * @return the temporal adjuster wrapping on the date adjuster, not null
+     */
+    public static TemporalAdjuster ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster) {
+        Objects.requireNonNull(dateBasedAdjuster, "dateBasedAdjuster");
+        return (temporal) -> {
+            LocalDate input = LocalDate.from(temporal);
+            LocalDate output = dateBasedAdjuster.apply(input);
+            return temporal.with(output);
+        };
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the "first day of month" adjuster, which returns a new date set to
+     * the first day of the current month.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-01-01.<br>
+     * The input 2011-02-15 will return 2011-02-01.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_MONTH, 1);
+     * </pre>
+     *
+     * @return the first day-of-month adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfMonth() {
+        return (temporal) -> temporal.with(DAY_OF_MONTH, 1);
+    }
+
+    /**
+     * Returns the "last day of month" adjuster, which returns a new date set to
+     * the last day of the current month.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-01-31.<br>
+     * The input 2011-02-15 will return 2011-02-28.<br>
+     * The input 2012-02-15 will return 2012-02-29 (leap year).<br>
+     * The input 2011-04-15 will return 2011-04-30.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  long lastDay = temporal.range(DAY_OF_MONTH).getMaximum();
+     *  temporal.with(DAY_OF_MONTH, lastDay);
+     * </pre>
+     *
+     * @return the last day-of-month adjuster, not null
+     */
+    public static TemporalAdjuster lastDayOfMonth() {
+        return (temporal) -> temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
+    }
+
+    /**
+     * Returns the "first day of next month" adjuster, which returns a new date set to
+     * the first day of the next month.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-02-01.<br>
+     * The input 2011-02-15 will return 2011-03-01.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
+     * </pre>
+     *
+     * @return the first day of next month adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfNextMonth() {
+        return (temporal) -> temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the "first day of year" adjuster, which returns a new date set to
+     * the first day of the current year.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-01-01.<br>
+     * The input 2011-02-15 will return 2011-01-01.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_YEAR, 1);
+     * </pre>
+     *
+     * @return the first day-of-year adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfYear() {
+        return (temporal) -> temporal.with(DAY_OF_YEAR, 1);
+    }
+
+    /**
+     * Returns the "last day of year" adjuster, which returns a new date set to
+     * the last day of the current year.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2011-12-31.<br>
+     * The input 2011-02-15 will return 2011-12-31.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  long lastDay = temporal.range(DAY_OF_YEAR).getMaximum();
+     *  temporal.with(DAY_OF_YEAR, lastDay);
+     * </pre>
+     *
+     * @return the last day-of-year adjuster, not null
+     */
+    public static TemporalAdjuster lastDayOfYear() {
+        return (temporal) -> temporal.with(DAY_OF_YEAR, temporal.range(DAY_OF_YEAR).getMaximum());
+    }
+
+    /**
+     * Returns the "first day of next year" adjuster, which returns a new date set to
+     * the first day of the next year.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 will return 2012-01-01.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It is equivalent to:
+     * <pre>
+     *  temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
+     * </pre>
+     *
+     * @return the first day of next month adjuster, not null
+     */
+    public static TemporalAdjuster firstDayOfNextYear() {
+        return (temporal) -> temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the first in month adjuster, which returns a new date
+     * in the same month with the first matching day-of-week.
+     * This is used for expressions like 'first Tuesday in March'.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-12-15 for (MONDAY) will return 2011-12-05.<br>
+     * The input 2011-12-15 for (FRIDAY) will return 2011-12-02.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
+     * and the {@code DAYS} unit, and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week, not null
+     * @return the first in month adjuster, not null
+     */
+    public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) {
+        return TemporalAdjusters.dayOfWeekInMonth(1, dayOfWeek);
+    }
+
+    /**
+     * Returns the last in month adjuster, which returns a new date
+     * in the same month with the last matching day-of-week.
+     * This is used for expressions like 'last Tuesday in March'.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-12-15 for (MONDAY) will return 2011-12-26.<br>
+     * The input 2011-12-15 for (FRIDAY) will return 2011-12-30.<br>
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
+     * and the {@code DAYS} unit, and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week, not null
+     * @return the first in month adjuster, not null
+     */
+    public static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
+        return TemporalAdjusters.dayOfWeekInMonth(-1, dayOfWeek);
+    }
+
+    /**
+     * Returns the day-of-week in month adjuster, which returns a new date
+     * in the same month with the ordinal day-of-week.
+     * This is used for expressions like the 'second Tuesday in March'.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-12-15 for (1,TUESDAY) will return 2011-12-06.<br>
+     * The input 2011-12-15 for (2,TUESDAY) will return 2011-12-13.<br>
+     * The input 2011-12-15 for (3,TUESDAY) will return 2011-12-20.<br>
+     * The input 2011-12-15 for (4,TUESDAY) will return 2011-12-27.<br>
+     * The input 2011-12-15 for (5,TUESDAY) will return 2012-01-03.<br>
+     * The input 2011-12-15 for (-1,TUESDAY) will return 2011-12-27 (last in month).<br>
+     * The input 2011-12-15 for (-4,TUESDAY) will return 2011-12-06 (3 weeks before last in month).<br>
+     * The input 2011-12-15 for (-5,TUESDAY) will return 2011-11-29 (4 weeks before last in month).<br>
+     * The input 2011-12-15 for (0,TUESDAY) will return 2011-11-29 (last in previous month).<br>
+     * <p>
+     * For a positive or zero ordinal, the algorithm is equivalent to finding the first
+     * day-of-week that matches within the month and then adding a number of weeks to it.
+     * For a negative ordinal, the algorithm is equivalent to finding the last
+     * day-of-week that matches within the month and then subtracting a number of weeks to it.
+     * The ordinal number of weeks is not validated and is interpreted leniently
+     * according to this algorithm. This definition means that an ordinal of zero finds
+     * the last matching day-of-week in the previous month.
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
+     * and the {@code DAYS} unit, and assumes a seven day week.
+     *
+     * @param ordinal  the week within the month, unbounded but typically from -5 to 5
+     * @param dayOfWeek  the day-of-week, not null
+     * @return the day-of-week in month adjuster, not null
+     */
+    public static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) {
+        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
+        int dowValue = dayOfWeek.getValue();
+        if (ordinal >= 0) {
+            return (temporal) -> {
+                Temporal temp = temporal.with(DAY_OF_MONTH, 1);
+                int curDow = temp.get(DAY_OF_WEEK);
+                int dowDiff = (dowValue - curDow + 7) % 7;
+                dowDiff += (ordinal - 1L) * 7L;  // safe from overflow
+                return temp.plus(dowDiff, DAYS);
+            };
+        } else {
+            return (temporal) -> {
+                Temporal temp = temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
+                int curDow = temp.get(DAY_OF_WEEK);
+                int daysDiff = dowValue - curDow;
+                daysDiff = (daysDiff == 0 ? 0 : (daysDiff > 0 ? daysDiff - 7 : daysDiff));
+                daysDiff -= (-ordinal - 1L) * 7L;  // safe from overflow
+                return temp.plus(daysDiff, DAYS);
+            };
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns the next day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week after the date being adjusted.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-22 (seven days later).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to move the date to, not null
+     * @return the next day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster next(DayOfWeek dayOfWeek) {
+        int dowValue = dayOfWeek.getValue();
+        return (temporal) -> {
+            int calDow = temporal.get(DAY_OF_WEEK);
+            int daysDiff = calDow - dowValue;
+            return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
+        };
+    }
+
+    /**
+     * Returns the next-or-same day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week after the date being adjusted
+     * unless it is already on that day in which case the same object is returned.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to check for or move the date to, not null
+     * @return the next-or-same day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) {
+        int dowValue = dayOfWeek.getValue();
+        return (temporal) -> {
+            int calDow = temporal.get(DAY_OF_WEEK);
+            if (calDow == dowValue) {
+                return temporal;
+            }
+            int daysDiff = calDow - dowValue;
+            return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
+        };
+    }
+
+    /**
+     * Returns the previous day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week before the date being adjusted.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-08 (seven days earlier).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to move the date to, not null
+     * @return the previous day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster previous(DayOfWeek dayOfWeek) {
+        int dowValue = dayOfWeek.getValue();
+        return (temporal) -> {
+            int calDow = temporal.get(DAY_OF_WEEK);
+            int daysDiff = dowValue - calDow;
+            return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
+        };
+    }
+
+    /**
+     * Returns the previous-or-same day-of-week adjuster, which adjusts the date to the
+     * first occurrence of the specified day-of-week before the date being adjusted
+     * unless it is already on that day in which case the same object is returned.
+     * <p>
+     * The ISO calendar system behaves as follows:<br>
+     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
+     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
+     * <p>
+     * The behavior is suitable for use with most calendar systems.
+     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
+     * and assumes a seven day week.
+     *
+     * @param dayOfWeek  the day-of-week to check for or move the date to, not null
+     * @return the previous-or-same day-of-week adjuster, not null
+     */
+    public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) {
+        int dowValue = dayOfWeek.getValue();
+        return (temporal) -> {
+            int calDow = temporal.get(DAY_OF_WEEK);
+            if (calDow == dowValue) {
+                return temporal;
+            }
+            int daysDiff = dowValue - calDow;
+            return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
+        };
+    }
+
+}
diff --git a/java/time/temporal/TemporalAmount.java b/java/time/temporal/TemporalAmount.java
new file mode 100644
index 0000000..0d8b8a9
--- /dev/null
+++ b/java/time/temporal/TemporalAmount.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, 2013 Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.Period;
+import java.util.List;
+
+/**
+ * Framework-level interface defining an amount of time, such as
+ * "6 hours", "8 days" or "2 years and 3 months".
+ * <p>
+ * This is the base interface type for amounts of time.
+ * An amount is distinct from a date or time-of-day in that it is not tied
+ * to any specific point on the time-line.
+ * <p>
+ * The amount can be thought of as a {@code Map} of {@link TemporalUnit} to
+ * {@code long}, exposed via {@link #getUnits()} and {@link #get(TemporalUnit)}.
+ * A simple case might have a single unit-value pair, such as "6 hours".
+ * A more complex case may have multiple unit-value pairs, such as
+ * "7 years, 3 months and 5 days".
+ * <p>
+ * There are two common implementations.
+ * {@link Period} is a date-based implementation, storing years, months and days.
+ * {@link Duration} is a time-based implementation, storing seconds and nanoseconds,
+ * but providing some access using other duration based units such as minutes,
+ * hours and fixed 24-hour days.
+ * <p>
+ * This interface is a framework-level interface that should not be widely
+ * used in application code. Instead, applications should create and pass
+ * around instances of concrete types, such as {@code Period} and {@code Duration}.
+ *
+ * @implSpec
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @since 1.8
+ */
+public interface TemporalAmount {
+
+    /**
+     * Returns the value of the requested unit.
+     * The units returned from {@link #getUnits()} uniquely define the
+     * value of the {@code TemporalAmount}.  A value must be returned
+     * for each unit listed in {@code getUnits}.
+     *
+     * @implSpec
+     * Implementations may declare support for units not listed by {@link #getUnits()}.
+     * Typically, the implementation would define additional units
+     * as conversions for the convenience of developers.
+     *
+     * @param unit the {@code TemporalUnit} for which to return the value
+     * @return the long value of the unit
+     * @throws DateTimeException if a value for the unit cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the {@code unit} is not supported
+     */
+    long get(TemporalUnit unit);
+
+    /**
+     * Returns the list of units uniquely defining the value of this TemporalAmount.
+     * The list of {@code TemporalUnits} is defined by the implementation class.
+     * The list is a snapshot of the units at the time {@code getUnits}
+     * is called and is not mutable.
+     * The units are ordered from longest duration to the shortest duration
+     * of the unit.
+     *
+     * @implSpec
+     * The list of units completely and uniquely represents the
+     * state of the object without omissions, overlaps or duplication.
+     * The units are in order from longest duration to shortest.
+     *
+     * @return the List of {@code TemporalUnits}; not null
+     */
+    List<TemporalUnit> getUnits();
+
+    /**
+     * Adds to the specified temporal object.
+     * <p>
+     * Adds the amount to the specified temporal object using the logic
+     * encapsulated in the implementing class.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#plus(TemporalAmount)}:
+     * <pre>
+     *   // These two lines are equivalent, but the second approach is recommended
+     *   dateTime = amount.addTo(dateTime);
+     *   dateTime = dateTime.plus(adder);
+     * </pre>
+     * It is recommended to use the second approach, {@code plus(TemporalAmount)},
+     * as it is a lot clearer to read in code.
+     *
+     * @implSpec
+     * The implementation must take the input object and add to it.
+     * The implementation defines the logic of the addition and is responsible for
+     * documenting that logic. It may use any method on {@code Temporal} to
+     * query the temporal object and perform the addition.
+     * The returned object must have the same observable type as the input object
+     * <p>
+     * The input object must not be altered.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable temporal objects.
+     * <p>
+     * The input temporal object may be in a calendar system other than ISO.
+     * Implementations may choose to document compatibility with other calendar systems,
+     * or reject non-ISO temporal objects by {@link TemporalQueries#chronology() querying the chronology}.
+     * <p>
+     * This method may be called from multiple threads in parallel.
+     * It must be thread-safe when invoked.
+     *
+     * @param temporal  the temporal object to add the amount to, not null
+     * @return an object of the same observable type with the addition made, not null
+     * @throws DateTimeException if unable to add
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal addTo(Temporal temporal);
+
+    /**
+     * Subtracts this object from the specified temporal object.
+     * <p>
+     * Subtracts the amount from the specified temporal object using the logic
+     * encapsulated in the implementing class.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#minus(TemporalAmount)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   dateTime = amount.subtractFrom(dateTime);
+     *   dateTime = dateTime.minus(amount);
+     * </pre>
+     * It is recommended to use the second approach, {@code minus(TemporalAmount)},
+     * as it is a lot clearer to read in code.
+     *
+     * @implSpec
+     * The implementation must take the input object and subtract from it.
+     * The implementation defines the logic of the subtraction and is responsible for
+     * documenting that logic. It may use any method on {@code Temporal} to
+     * query the temporal object and perform the subtraction.
+     * The returned object must have the same observable type as the input object
+     * <p>
+     * The input object must not be altered.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable temporal objects.
+     * <p>
+     * The input temporal object may be in a calendar system other than ISO.
+     * Implementations may choose to document compatibility with other calendar systems,
+     * or reject non-ISO temporal objects by {@link TemporalQueries#chronology() querying the chronology}.
+     * <p>
+     * This method may be called from multiple threads in parallel.
+     * It must be thread-safe when invoked.
+     *
+     * @param temporal  the temporal object to subtract the amount from, not null
+     * @return an object of the same observable type with the subtraction made, not null
+     * @throws DateTimeException if unable to subtract
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    Temporal subtractFrom(Temporal temporal);
+}
diff --git a/java/time/temporal/TemporalField.java b/java/time/temporal/TemporalField.java
new file mode 100644
index 0000000..a82255a
--- /dev/null
+++ b/java/time/temporal/TemporalField.java
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.chrono.Chronology;
+import java.time.format.ResolverStyle;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A field of date-time, such as month-of-year or hour-of-minute.
+ * <p>
+ * Date and time is expressed using fields which partition the time-line into something
+ * meaningful for humans. Implementations of this interface represent those fields.
+ * <p>
+ * The most commonly used units are defined in {@link ChronoField}.
+ * Further fields are supplied in {@link IsoFields}, {@link WeekFields} and {@link JulianFields}.
+ * Fields can also be written by application code by implementing this interface.
+ * <p>
+ * The field works using double dispatch. Client code calls methods on a date-time like
+ * {@code LocalDateTime} which check if the field is a {@code ChronoField}.
+ * If it is, then the date-time must handle it.
+ * Otherwise, the method call is re-dispatched to the matching method in this interface.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * Implementations should be {@code Serializable} where possible.
+ * An enum is as effective implementation choice.
+ *
+ * @since 1.8
+ */
+public interface TemporalField {
+
+    /**
+     * Gets the display name for the field in the requested locale.
+     * <p>
+     * If there is no display name for the locale then a suitable default must be returned.
+     * <p>
+     * The default implementation must check the locale is not null
+     * and return {@code toString()}.
+     *
+     * @param locale  the locale to use, not null
+     * @return the display name for the locale or a suitable default, not null
+     */
+    default String getDisplayName(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        return toString();
+    }
+
+    /**
+     * Gets the unit that the field is measured in.
+     * <p>
+     * The unit of the field is the period that varies within the range.
+     * For example, in the field 'MonthOfYear', the unit is 'Months'.
+     * See also {@link #getRangeUnit()}.
+     *
+     * @return the unit defining the base unit of the field, not null
+     */
+    TemporalUnit getBaseUnit();
+
+    /**
+     * Gets the range that the field is bound by.
+     * <p>
+     * The range of the field is the period that the field varies within.
+     * For example, in the field 'MonthOfYear', the range is 'Years'.
+     * See also {@link #getBaseUnit()}.
+     * <p>
+     * The range is never null. For example, the 'Year' field is shorthand for
+     * 'YearOfForever'. It therefore has a unit of 'Years' and a range of 'Forever'.
+     *
+     * @return the unit defining the range of the field, not null
+     */
+    TemporalUnit getRangeUnit();
+
+    /**
+     * Gets the range of valid values for the field.
+     * <p>
+     * All fields can be expressed as a {@code long} integer.
+     * This method returns an object that describes the valid range for that value.
+     * This method is generally only applicable to the ISO-8601 calendar system.
+     * <p>
+     * Note that the result only describes the minimum and maximum valid values
+     * and it is important not to read too much into them. For example, there
+     * could be values within the range that are invalid for the field.
+     *
+     * @return the range of valid values for the field, not null
+     */
+    ValueRange range();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this field represents a component of a date.
+     * <p>
+     * A field is date-based if it can be derived from
+     * {@link ChronoField#EPOCH_DAY EPOCH_DAY}.
+     * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()}
+     * to return false, such as when representing a field like minute-of-week.
+     *
+     * @return true if this field is a component of a date
+     */
+    boolean isDateBased();
+
+    /**
+     * Checks if this field represents a component of a time.
+     * <p>
+     * A field is time-based if it can be derived from
+     * {@link ChronoField#NANO_OF_DAY NANO_OF_DAY}.
+     * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()}
+     * to return false, such as when representing a field like minute-of-week.
+     *
+     * @return true if this field is a component of a time
+     */
+    boolean isTimeBased();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this field is supported by the temporal object.
+     * <p>
+     * This determines whether the temporal accessor supports this field.
+     * If this returns false, then the temporal cannot be queried for this field.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#isSupported(TemporalField)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.isSupportedBy(temporal);
+     *   temporal = temporal.isSupported(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code isSupported(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should determine whether they are supported using the fields
+     * available in {@link ChronoField}.
+     *
+     * @param temporal  the temporal object to query, not null
+     * @return true if the date-time can be queried for this field, false if not
+     */
+    boolean isSupportedBy(TemporalAccessor temporal);
+
+    /**
+     * Get the range of valid values for this field using the temporal object to
+     * refine the result.
+     * <p>
+     * This uses the temporal object to find the range of valid values for the field.
+     * This is similar to {@link #range()}, however this method refines the result
+     * using the temporal. For example, if the field is {@code DAY_OF_MONTH} the
+     * {@code range} method is not accurate as there are four possible month lengths,
+     * 28, 29, 30 and 31 days. Using this method with a date allows the range to be
+     * accurate, returning just one of those four options.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#range(TemporalField)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.rangeRefinedBy(temporal);
+     *   temporal = temporal.range(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code range(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the fields
+     * available in {@link ChronoField}.
+     * If the field is not supported an {@code UnsupportedTemporalTypeException} must be thrown.
+     *
+     * @param temporal  the temporal object used to refine the result, not null
+     * @return the range of valid values for this field, not null
+     * @throws DateTimeException if the range for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported by the temporal
+     */
+    ValueRange rangeRefinedBy(TemporalAccessor temporal);
+
+    /**
+     * Gets the value of this field from the specified temporal object.
+     * <p>
+     * This queries the temporal object for the value of this field.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#getLong(TemporalField)}
+     * (or {@link TemporalAccessor#get(TemporalField)}):
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.getFrom(temporal);
+     *   temporal = temporal.getLong(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code getLong(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the fields
+     * available in {@link ChronoField}.
+     * If the field is not supported an {@code UnsupportedTemporalTypeException} must be thrown.
+     *
+     * @param temporal  the temporal object to query, not null
+     * @return the value of this field, not null
+     * @throws DateTimeException if a value for the field cannot be obtained
+     * @throws UnsupportedTemporalTypeException if the field is not supported by the temporal
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    long getFrom(TemporalAccessor temporal);
+
+    /**
+     * Returns a copy of the specified temporal object with the value of this field set.
+     * <p>
+     * This returns a new temporal object based on the specified one with the value for
+     * this field changed. For example, on a {@code LocalDate}, this could be used to
+     * set the year, month or day-of-month.
+     * The returned object has the same observable type as the specified object.
+     * <p>
+     * In some cases, changing a field is not fully defined. For example, if the target object is
+     * a date representing the 31st January, then changing the month to February would be unclear.
+     * In cases like this, the implementation is responsible for resolving the result.
+     * Typically it will choose the previous valid date, which would be the last valid
+     * day of February in this example.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#with(TemporalField, long)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisField.adjustInto(temporal);
+     *   temporal = temporal.with(thisField);
+     * </pre>
+     * It is recommended to use the second approach, {@code with(TemporalField)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the fields
+     * available in {@link ChronoField}.
+     * If the field is not supported an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * Implementations must not alter the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     *
+     * @param <R>  the type of the Temporal object
+     * @param temporal the temporal object to adjust, not null
+     * @param newValue the new value of the field
+     * @return the adjusted temporal object, not null
+     * @throws DateTimeException if the field cannot be set
+     * @throws UnsupportedTemporalTypeException if the field is not supported by the temporal
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    <R extends Temporal> R adjustInto(R temporal, long newValue);
+
+    /**
+     * Resolves this field to provide a simpler alternative or a date.
+     * <p>
+     * This method is invoked during the resolve phase of parsing.
+     * It is designed to allow application defined fields to be simplified into
+     * more standard fields, such as those on {@code ChronoField}, or into a date.
+     * <p>
+     * Applications should not normally invoke this method directly.
+     *
+     * @implSpec
+     * If an implementation represents a field that can be simplified, or
+     * combined with others, then this method must be implemented.
+     * <p>
+     * The specified map contains the current state of the parse.
+     * The map is mutable and must be mutated to resolve the field and
+     * any related fields. This method will only be invoked during parsing
+     * if the map contains this field, and implementations should therefore
+     * assume this field is present.
+     * <p>
+     * Resolving a field will consist of looking at the value of this field,
+     * and potentially other fields, and either updating the map with a
+     * simpler value, such as a {@code ChronoField}, or returning a
+     * complete {@code ChronoLocalDate}. If a resolve is successful,
+     * the code must remove all the fields that were resolved from the map,
+     * including this field.
+     * <p>
+     * For example, the {@code IsoFields} class contains the quarter-of-year
+     * and day-of-quarter fields. The implementation of this method in that class
+     * resolves the two fields plus the {@link ChronoField#YEAR YEAR} into a
+     * complete {@code LocalDate}. The resolve method will remove all three
+     * fields from the map before returning the {@code LocalDate}.
+     * <p>
+     * A partially complete temporal is used to allow the chronology and zone
+     * to be queried. In general, only the chronology will be needed.
+     * Querying items other than the zone or chronology is undefined and
+     * must not be relied on.
+     * The behavior of other methods such as {@code get}, {@code getLong},
+     * {@code range} and {@code isSupported} is unpredictable and the results undefined.
+     * <p>
+     * If resolution should be possible, but the data is invalid, the resolver
+     * style should be used to determine an appropriate level of leniency, which
+     * may require throwing a {@code DateTimeException} or {@code ArithmeticException}.
+     * If no resolution is possible, the resolve method must return null.
+     * <p>
+     * When resolving time fields, the map will be altered and null returned.
+     * When resolving date fields, the date is normally returned from the method,
+     * with the map altered to remove the resolved fields. However, it would also
+     * be acceptable for the date fields to be resolved into other {@code ChronoField}
+     * instances that can produce a date, such as {@code EPOCH_DAY}.
+     * <p>
+     * Not all {@code TemporalAccessor} implementations are accepted as return values.
+     * Implementations that call this method must accept {@code ChronoLocalDate},
+     * {@code ChronoLocalDateTime}, {@code ChronoZonedDateTime} and {@code LocalTime}.
+     * <p>
+     * The default implementation must return null.
+     *
+     * @param fieldValues  the map of fields to values, which can be updated, not null
+     * @param partialTemporal  the partially complete temporal to query for zone and
+     *  chronology; querying for other things is undefined and not recommended, not null
+     * @param resolverStyle  the requested type of resolve, not null
+     * @return the resolved temporal object; null if resolving only
+     *  changed the map, or no resolve occurred
+     * @throws ArithmeticException if numeric overflow occurs
+     * @throws DateTimeException if resolving results in an error. This must not be thrown
+     *  by querying a field on the temporal without first checking if it is supported
+     */
+    default TemporalAccessor resolve(
+            Map<TemporalField, Long> fieldValues,
+            TemporalAccessor partialTemporal,
+            ResolverStyle resolverStyle) {
+        return null;
+    }
+
+    /**
+     * Gets a descriptive name for the field.
+     * <p>
+     * The should be of the format 'BaseOfRange', such as 'MonthOfYear',
+     * unless the field has a range of {@code FOREVER}, when only
+     * the base unit is mentioned, such as 'Year' or 'Era'.
+     *
+     * @return the name of the field, not null
+     */
+    @Override
+    String toString();
+
+
+}
diff --git a/java/time/temporal/TemporalQueries.java b/java/time/temporal/TemporalQueries.java
new file mode 100644
index 0000000..6b1777a
--- /dev/null
+++ b/java/time/temporal/TemporalQueries.java
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import static java.time.temporal.ChronoField.EPOCH_DAY;
+import static java.time.temporal.ChronoField.NANO_OF_DAY;
+import static java.time.temporal.ChronoField.OFFSET_SECONDS;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.chrono.Chronology;
+
+/**
+ * Common implementations of {@code TemporalQuery}.
+ * <p>
+ * This class provides common implementations of {@link TemporalQuery}.
+ * These are defined here as they must be constants, and the definition
+ * of lambdas does not guarantee that. By assigning them once here,
+ * they become 'normal' Java constants.
+ * <p>
+ * Queries are a key tool for extracting information from temporal objects.
+ * They exist to externalize the process of querying, permitting different
+ * approaches, as per the strategy design pattern.
+ * Examples might be a query that checks if the date is the day before February 29th
+ * in a leap year, or calculates the number of days to your next birthday.
+ * <p>
+ * The {@link TemporalField} interface provides another mechanism for querying
+ * temporal objects. That interface is limited to returning a {@code long}.
+ * By contrast, queries can return any type.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalQuery}.
+ * The first is to invoke the method on this interface directly.
+ * The second is to use {@link TemporalAccessor#query(TemporalQuery)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   temporal = thisQuery.queryFrom(temporal);
+ *   temporal = temporal.query(thisQuery);
+ * </pre>
+ * It is recommended to use the second approach, {@code query(TemporalQuery)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * The most common implementations are method references, such as
+ * {@code LocalDate::from} and {@code ZoneId::from}.
+ * Additional common queries are provided to return:
+ * <ul>
+ * <li> a Chronology,
+ * <li> a LocalDate,
+ * <li> a LocalTime,
+ * <li> a ZoneOffset,
+ * <li> a precision,
+ * <li> a zone, or
+ * <li> a zoneId.
+ * </ul>
+ *
+ * @since 1.8
+ */
+public final class TemporalQueries {
+    // note that it is vital that each method supplies a constant, not a
+    // calculated value, as they will be checked for using ==
+    // it is also vital that each constant is different (due to the == checking)
+    // as such, alterations to this code must be done with care
+
+    /**
+     * Private constructor since this is a utility class.
+     */
+    private TemporalQueries() {
+    }
+
+    //-----------------------------------------------------------------------
+    // special constants should be used to extract information from a TemporalAccessor
+    // that cannot be derived in other ways
+    // Javadoc added here, so as to pretend they are more normal than they really are
+
+    /**
+     * A strict query for the {@code ZoneId}.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the zone.
+     * The zone is only returned if the date-time conceptually contains a {@code ZoneId}.
+     * It will not be returned if the date-time only conceptually has an {@code ZoneOffset}.
+     * Thus a {@link java.time.ZonedDateTime} will return the result of {@code getZone()},
+     * but an {@link java.time.OffsetDateTime} will return null.
+     * <p>
+     * In most cases, applications should use {@link #zone()} as this query is too strict.
+     * <p>
+     * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br>
+     * {@code LocalDate} returns null<br>
+     * {@code LocalTime} returns null<br>
+     * {@code LocalDateTime} returns null<br>
+     * {@code ZonedDateTime} returns the associated zone<br>
+     * {@code OffsetTime} returns null<br>
+     * {@code OffsetDateTime} returns null<br>
+     * {@code ChronoLocalDate} returns null<br>
+     * {@code ChronoLocalDateTime} returns null<br>
+     * {@code ChronoZonedDateTime} returns the associated zone<br>
+     * {@code Era} returns null<br>
+     * {@code DayOfWeek} returns null<br>
+     * {@code Month} returns null<br>
+     * {@code Year} returns null<br>
+     * {@code YearMonth} returns null<br>
+     * {@code MonthDay} returns null<br>
+     * {@code ZoneOffset} returns null<br>
+     * {@code Instant} returns null<br>
+     *
+     * @return a query that can obtain the zone ID of a temporal, not null
+     */
+    public static TemporalQuery<ZoneId> zoneId() {
+        return TemporalQueries.ZONE_ID;
+    }
+
+    /**
+     * A query for the {@code Chronology}.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the chronology.
+     * If the target {@code TemporalAccessor} represents a date, or part of a date,
+     * then it should return the chronology that the date is expressed in.
+     * As a result of this definition, objects only representing time, such as
+     * {@code LocalTime}, will return null.
+     * <p>
+     * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br>
+     * {@code LocalDate} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code LocalTime} returns null (does not represent a date)<br>
+     * {@code LocalDateTime} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code ZonedDateTime} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code OffsetTime} returns null (does not represent a date)<br>
+     * {@code OffsetDateTime} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code ChronoLocalDate} returns the associated chronology<br>
+     * {@code ChronoLocalDateTime} returns the associated chronology<br>
+     * {@code ChronoZonedDateTime} returns the associated chronology<br>
+     * {@code Era} returns the associated chronology<br>
+     * {@code DayOfWeek} returns null (shared across chronologies)<br>
+     * {@code Month} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code Year} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code YearMonth} returns {@code IsoChronology.INSTANCE}<br>
+     * {@code MonthDay} returns null {@code IsoChronology.INSTANCE}<br>
+     * {@code ZoneOffset} returns null (does not represent a date)<br>
+     * {@code Instant} returns null (does not represent a date)<br>
+     * <p>
+     * The method {@link java.time.chrono.Chronology#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code Chronology::from}.
+     * That method is equivalent to this query, except that it throws an
+     * exception if a chronology cannot be obtained.
+     *
+     * @return a query that can obtain the chronology of a temporal, not null
+     */
+    public static TemporalQuery<Chronology> chronology() {
+        return TemporalQueries.CHRONO;
+    }
+
+    /**
+     * A query for the smallest supported unit.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the time precision.
+     * If the target {@code TemporalAccessor} represents a consistent or complete date-time,
+     * date or time then this must return the smallest precision actually supported.
+     * Note that fields such as {@code NANO_OF_DAY} and {@code NANO_OF_SECOND}
+     * are defined to always return ignoring the precision, thus this is the only
+     * way to find the actual smallest supported unit.
+     * For example, were {@code GregorianCalendar} to implement {@code TemporalAccessor}
+     * it would return a precision of {@code MILLIS}.
+     * <p>
+     * The result from JDK classes implementing {@code TemporalAccessor} is as follows:<br>
+     * {@code LocalDate} returns {@code DAYS}<br>
+     * {@code LocalTime} returns {@code NANOS}<br>
+     * {@code LocalDateTime} returns {@code NANOS}<br>
+     * {@code ZonedDateTime} returns {@code NANOS}<br>
+     * {@code OffsetTime} returns {@code NANOS}<br>
+     * {@code OffsetDateTime} returns {@code NANOS}<br>
+     * {@code ChronoLocalDate} returns {@code DAYS}<br>
+     * {@code ChronoLocalDateTime} returns {@code NANOS}<br>
+     * {@code ChronoZonedDateTime} returns {@code NANOS}<br>
+     * {@code Era} returns {@code ERAS}<br>
+     * {@code DayOfWeek} returns {@code DAYS}<br>
+     * {@code Month} returns {@code MONTHS}<br>
+     * {@code Year} returns {@code YEARS}<br>
+     * {@code YearMonth} returns {@code MONTHS}<br>
+     * {@code MonthDay} returns null (does not represent a complete date or time)<br>
+     * {@code ZoneOffset} returns null (does not represent a date or time)<br>
+     * {@code Instant} returns {@code NANOS}<br>
+     *
+     * @return a query that can obtain the precision of a temporal, not null
+     */
+    public static TemporalQuery<TemporalUnit> precision() {
+        return TemporalQueries.PRECISION;
+    }
+
+    //-----------------------------------------------------------------------
+    // non-special constants are standard queries that derive information from other information
+    /**
+     * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}.
+     * <p>
+     * This queries a {@code TemporalAccessor} for the zone.
+     * It first tries to obtain the zone, using {@link #zoneId()}.
+     * If that is not found it tries to obtain the {@link #offset()}.
+     * Thus a {@link java.time.ZonedDateTime} will return the result of {@code getZone()},
+     * while an {@link java.time.OffsetDateTime} will return the result of {@code getOffset()}.
+     * <p>
+     * In most cases, applications should use this query rather than {@code #zoneId()}.
+     * <p>
+     * The method {@link ZoneId#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code ZoneId::from}.
+     * That method is equivalent to this query, except that it throws an
+     * exception if a zone cannot be obtained.
+     *
+     * @return a query that can obtain the zone ID or offset of a temporal, not null
+     */
+    public static TemporalQuery<ZoneId> zone() {
+        return TemporalQueries.ZONE;
+    }
+
+    /**
+     * A query for {@code ZoneOffset} returning null if not found.
+     * <p>
+     * This returns a {@code TemporalQuery} that can be used to query a temporal
+     * object for the offset. The query will return null if the temporal
+     * object cannot supply an offset.
+     * <p>
+     * The query implementation examines the {@link ChronoField#OFFSET_SECONDS OFFSET_SECONDS}
+     * field and uses it to create a {@code ZoneOffset}.
+     * <p>
+     * The method {@link java.time.ZoneOffset#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code ZoneOffset::from}.
+     * This query and {@code ZoneOffset::from} will return the same result if the
+     * temporal object contains an offset. If the temporal object does not contain
+     * an offset, then the method reference will throw an exception, whereas this
+     * query will return null.
+     *
+     * @return a query that can obtain the offset of a temporal, not null
+     */
+    public static TemporalQuery<ZoneOffset> offset() {
+        return TemporalQueries.OFFSET;
+    }
+
+    /**
+     * A query for {@code LocalDate} returning null if not found.
+     * <p>
+     * This returns a {@code TemporalQuery} that can be used to query a temporal
+     * object for the local date. The query will return null if the temporal
+     * object cannot supply a local date.
+     * <p>
+     * The query implementation examines the {@link ChronoField#EPOCH_DAY EPOCH_DAY}
+     * field and uses it to create a {@code LocalDate}.
+     * <p>
+     * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code LocalDate::from}.
+     * This query and {@code LocalDate::from} will return the same result if the
+     * temporal object contains a date. If the temporal object does not contain
+     * a date, then the method reference will throw an exception, whereas this
+     * query will return null.
+     *
+     * @return a query that can obtain the date of a temporal, not null
+     */
+    public static TemporalQuery<LocalDate> localDate() {
+        return TemporalQueries.LOCAL_DATE;
+    }
+
+    /**
+     * A query for {@code LocalTime} returning null if not found.
+     * <p>
+     * This returns a {@code TemporalQuery} that can be used to query a temporal
+     * object for the local time. The query will return null if the temporal
+     * object cannot supply a local time.
+     * <p>
+     * The query implementation examines the {@link ChronoField#NANO_OF_DAY NANO_OF_DAY}
+     * field and uses it to create a {@code LocalTime}.
+     * <p>
+     * The method {@link ZoneOffset#from(TemporalAccessor)} can be used as a
+     * {@code TemporalQuery} via a method reference, {@code LocalTime::from}.
+     * This query and {@code LocalTime::from} will return the same result if the
+     * temporal object contains a time. If the temporal object does not contain
+     * a time, then the method reference will throw an exception, whereas this
+     * query will return null.
+     *
+     * @return a query that can obtain the time of a temporal, not null
+     */
+    public static TemporalQuery<LocalTime> localTime() {
+        return TemporalQueries.LOCAL_TIME;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A strict query for the {@code ZoneId}.
+     */
+    static final TemporalQuery<ZoneId> ZONE_ID = (temporal) ->
+        temporal.query(TemporalQueries.ZONE_ID);
+
+    /**
+     * A query for the {@code Chronology}.
+     */
+    static final TemporalQuery<Chronology> CHRONO = (temporal) ->
+        temporal.query(TemporalQueries.CHRONO);
+
+    /**
+     * A query for the smallest supported unit.
+     */
+    static final TemporalQuery<TemporalUnit> PRECISION = (temporal) ->
+        temporal.query(TemporalQueries.PRECISION);
+
+    //-----------------------------------------------------------------------
+    /**
+     * A query for {@code ZoneOffset} returning null if not found.
+     */
+    static final TemporalQuery<ZoneOffset> OFFSET = (temporal) -> {
+        if (temporal.isSupported(OFFSET_SECONDS)) {
+            return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS));
+        }
+        return null;
+    };
+
+    /**
+     * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}.
+     */
+    static final TemporalQuery<ZoneId> ZONE = (temporal) -> {
+        ZoneId zone = temporal.query(ZONE_ID);
+        return (zone != null ? zone : temporal.query(OFFSET));
+    };
+
+    /**
+     * A query for {@code LocalDate} returning null if not found.
+     */
+    static final TemporalQuery<LocalDate> LOCAL_DATE = (temporal) -> {
+        if (temporal.isSupported(EPOCH_DAY)) {
+            return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY));
+        }
+        return null;
+    };
+
+    /**
+     * A query for {@code LocalTime} returning null if not found.
+     */
+    static final TemporalQuery<LocalTime> LOCAL_TIME = (temporal) -> {
+        if (temporal.isSupported(NANO_OF_DAY)) {
+            return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY));
+        }
+        return null;
+    };
+
+}
diff --git a/java/time/temporal/TemporalQuery.java b/java/time/temporal/TemporalQuery.java
new file mode 100644
index 0000000..9614296
--- /dev/null
+++ b/java/time/temporal/TemporalQuery.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+
+/**
+ * Strategy for querying a temporal object.
+ * <p>
+ * Queries are a key tool for extracting information from temporal objects.
+ * They exist to externalize the process of querying, permitting different
+ * approaches, as per the strategy design pattern.
+ * Examples might be a query that checks if the date is the day before February 29th
+ * in a leap year, or calculates the number of days to your next birthday.
+ * <p>
+ * The {@link TemporalField} interface provides another mechanism for querying
+ * temporal objects. That interface is limited to returning a {@code long}.
+ * By contrast, queries can return any type.
+ * <p>
+ * There are two equivalent ways of using a {@code TemporalQuery}.
+ * The first is to invoke the method on this interface directly.
+ * The second is to use {@link TemporalAccessor#query(TemporalQuery)}:
+ * <pre>
+ *   // these two lines are equivalent, but the second approach is recommended
+ *   temporal = thisQuery.queryFrom(temporal);
+ *   temporal = temporal.query(thisQuery);
+ * </pre>
+ * It is recommended to use the second approach, {@code query(TemporalQuery)},
+ * as it is a lot clearer to read in code.
+ * <p>
+ * The most common implementations are method references, such as
+ * {@code LocalDate::from} and {@code ZoneId::from}.
+ * Additional common queries are provided as static methods in {@link TemporalQueries}.
+ *
+ * @implSpec
+ * This interface places no restrictions on the mutability of implementations,
+ * however immutability is strongly recommended.
+ *
+ * @param <R> the type returned from the query
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface TemporalQuery<R> {
+
+    /**
+     * Queries the specified temporal object.
+     * <p>
+     * This queries the specified temporal object to return an object using the logic
+     * encapsulated in the implementing class.
+     * Examples might be a query that checks if the date is the day before February 29th
+     * in a leap year, or calculates the number of days to your next birthday.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link TemporalAccessor#query(TemporalQuery)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisQuery.queryFrom(temporal);
+     *   temporal = temporal.query(thisQuery);
+     * </pre>
+     * It is recommended to use the second approach, {@code query(TemporalQuery)},
+     * as it is a lot clearer to read in code.
+     *
+     * @implSpec
+     * The implementation must take the input object and query it.
+     * The implementation defines the logic of the query and is responsible for
+     * documenting that logic.
+     * It may use any method on {@code TemporalAccessor} to determine the result.
+     * The input object must not be altered.
+     * <p>
+     * The input temporal object may be in a calendar system other than ISO.
+     * Implementations may choose to document compatibility with other calendar systems,
+     * or reject non-ISO temporal objects by {@link TemporalQueries#chronology() querying the chronology}.
+     * <p>
+     * This method may be called from multiple threads in parallel.
+     * It must be thread-safe when invoked.
+     *
+     * @param temporal  the temporal object to query, not null
+     * @return the queried value, may return null to indicate not found
+     * @throws DateTimeException if unable to query
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    R queryFrom(TemporalAccessor temporal);
+
+}
diff --git a/java/time/temporal/TemporalUnit.java b/java/time/temporal/TemporalUnit.java
new file mode 100644
index 0000000..949104d
--- /dev/null
+++ b/java/time/temporal/TemporalUnit.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+import java.time.Duration;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.ChronoLocalDateTime;
+import java.time.chrono.ChronoZonedDateTime;
+
+/**
+ * A unit of date-time, such as Days or Hours.
+ * <p>
+ * Measurement of time is built on units, such as years, months, days, hours, minutes and seconds.
+ * Implementations of this interface represent those units.
+ * <p>
+ * An instance of this interface represents the unit itself, rather than an amount of the unit.
+ * See {@link Period} for a class that represents an amount in terms of the common units.
+ * <p>
+ * The most commonly used units are defined in {@link ChronoUnit}.
+ * Further units are supplied in {@link IsoFields}.
+ * Units can also be written by application code by implementing this interface.
+ * <p>
+ * The unit works using double dispatch. Client code calls methods on a date-time like
+ * {@code LocalDateTime} which check if the unit is a {@code ChronoUnit}.
+ * If it is, then the date-time must handle it.
+ * Otherwise, the method call is re-dispatched to the matching method in this interface.
+ *
+ * @implSpec
+ * This interface must be implemented with care to ensure other classes operate correctly.
+ * All implementations that can be instantiated must be final, immutable and thread-safe.
+ * It is recommended to use an enum where possible.
+ *
+ * @since 1.8
+ */
+public interface TemporalUnit {
+
+    /**
+     * Gets the duration of this unit, which may be an estimate.
+     * <p>
+     * All units return a duration measured in standard nanoseconds from this method.
+     * The duration will be positive and non-zero.
+     * For example, an hour has a duration of {@code 60 * 60 * 1,000,000,000ns}.
+     * <p>
+     * Some units may return an accurate duration while others return an estimate.
+     * For example, days have an estimated duration due to the possibility of
+     * daylight saving time changes.
+     * To determine if the duration is an estimate, use {@link #isDurationEstimated()}.
+     *
+     * @return the duration of this unit, which may be an estimate, not null
+     */
+    Duration getDuration();
+
+    /**
+     * Checks if the duration of the unit is an estimate.
+     * <p>
+     * All units have a duration, however the duration is not always accurate.
+     * For example, days have an estimated duration due to the possibility of
+     * daylight saving time changes.
+     * This method returns true if the duration is an estimate and false if it is
+     * accurate. Note that accurate/estimated ignores leap seconds.
+     *
+     * @return true if the duration is estimated, false if accurate
+     */
+    boolean isDurationEstimated();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this unit represents a component of a date.
+     * <p>
+     * A date is time-based if it can be used to imply meaning from a date.
+     * It must have a {@linkplain #getDuration() duration} that is an integral
+     * multiple of the length of a standard day.
+     * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()}
+     * to return false, such as when representing a unit like 36 hours.
+     *
+     * @return true if this unit is a component of a date
+     */
+    boolean isDateBased();
+
+    /**
+     * Checks if this unit represents a component of a time.
+     * <p>
+     * A unit is time-based if it can be used to imply meaning from a time.
+     * It must have a {@linkplain #getDuration() duration} that divides into
+     * the length of a standard day without remainder.
+     * Note that it is valid for both {@code isDateBased()} and {@code isTimeBased()}
+     * to return false, such as when representing a unit like 36 hours.
+     *
+     * @return true if this unit is a component of a time
+     */
+    boolean isTimeBased();
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this unit is supported by the specified temporal object.
+     * <p>
+     * This checks that the implementing date-time can add/subtract this unit.
+     * This can be used to avoid throwing an exception.
+     * <p>
+     * This default implementation derives the value using
+     * {@link Temporal#plus(long, TemporalUnit)}.
+     *
+     * @param temporal  the temporal object to check, not null
+     * @return true if the unit is supported
+     */
+    default boolean isSupportedBy(Temporal temporal) {
+        if (temporal instanceof LocalTime) {
+            return isTimeBased();
+        }
+        if (temporal instanceof ChronoLocalDate) {
+            return isDateBased();
+        }
+        if (temporal instanceof ChronoLocalDateTime || temporal instanceof ChronoZonedDateTime) {
+            return true;
+        }
+        try {
+            temporal.plus(1, this);
+            return true;
+        } catch (UnsupportedTemporalTypeException ex) {
+            return false;
+        } catch (RuntimeException ex) {
+            try {
+                temporal.plus(-1, this);
+                return true;
+            } catch (RuntimeException ex2) {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Returns a copy of the specified temporal object with the specified period added.
+     * <p>
+     * The period added is a multiple of this unit. For example, this method
+     * could be used to add "3 days" to a date by calling this method on the
+     * instance representing "days", passing the date and the period "3".
+     * The period to be added may be negative, which is equivalent to subtraction.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#plus(long, TemporalUnit)}:
+     * <pre>
+     *   // these two lines are equivalent, but the second approach is recommended
+     *   temporal = thisUnit.addTo(temporal);
+     *   temporal = temporal.plus(thisUnit);
+     * </pre>
+     * It is recommended to use the second approach, {@code plus(TemporalUnit)},
+     * as it is a lot clearer to read in code.
+     * <p>
+     * Implementations should perform any queries or calculations using the units
+     * available in {@link ChronoUnit} or the fields available in {@link ChronoField}.
+     * If the unit is not supported an {@code UnsupportedTemporalTypeException} must be thrown.
+     * <p>
+     * Implementations must not alter the specified temporal object.
+     * Instead, an adjusted copy of the original must be returned.
+     * This provides equivalent, safe behavior for immutable and mutable implementations.
+     *
+     * @param <R>  the type of the Temporal object
+     * @param temporal  the temporal object to adjust, not null
+     * @param amount  the amount of this unit to add, positive or negative
+     * @return the adjusted temporal object, not null
+     * @throws DateTimeException if the amount cannot be added
+     * @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal
+     */
+    <R extends Temporal> R addTo(R temporal, long amount);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Calculates the amount of time between two temporal objects.
+     * <p>
+     * This calculates the amount in terms of this unit. The start and end
+     * points are supplied as temporal objects and must be of compatible types.
+     * The implementation will convert the second type to be an instance of the
+     * first type before the calculating the amount.
+     * The result will be negative if the end is before the start.
+     * For example, the amount in hours between two temporal objects can be
+     * calculated using {@code HOURS.between(startTime, endTime)}.
+     * <p>
+     * The calculation returns a whole number, representing the number of
+     * complete units between the two temporals.
+     * For example, the amount in hours between the times 11:30 and 13:29
+     * will only be one hour as it is one minute short of two hours.
+     * <p>
+     * There are two equivalent ways of using this method.
+     * The first is to invoke this method directly.
+     * The second is to use {@link Temporal#until(Temporal, TemporalUnit)}:
+     * <pre>
+     *   // these two lines are equivalent
+     *   between = thisUnit.between(start, end);
+     *   between = start.until(end, thisUnit);
+     * </pre>
+     * The choice should be made based on which makes the code more readable.
+     * <p>
+     * For example, this method allows the number of days between two dates to
+     * be calculated:
+     * <pre>
+     *  long daysBetween = DAYS.between(start, end);
+     *  // or alternatively
+     *  long daysBetween = start.until(end, DAYS);
+     * </pre>
+     * <p>
+     * Implementations should perform any queries or calculations using the units
+     * available in {@link ChronoUnit} or the fields available in {@link ChronoField}.
+     * If the unit is not supported an {@code UnsupportedTemporalTypeException} must be thrown.
+     * Implementations must not alter the specified temporal objects.
+     *
+     * @implSpec
+     * Implementations must begin by checking to if the two temporals have the
+     * same type using {@code getClass()}. If they do not, then the result must be
+     * obtained by calling {@code temporal1Inclusive.until(temporal2Exclusive, this)}.
+     *
+     * @param temporal1Inclusive  the base temporal object, not null
+     * @param temporal2Exclusive  the other temporal object, exclusive, not null
+     * @return the amount of time between temporal1Inclusive and temporal2Exclusive
+     *  in terms of this unit; positive if temporal2Exclusive is later than
+     *  temporal1Inclusive, negative if earlier
+     * @throws DateTimeException if the amount cannot be calculated, or the end
+     *  temporal cannot be converted to the same type as the start temporal
+     * @throws UnsupportedTemporalTypeException if the unit is not supported by the temporal
+     * @throws ArithmeticException if numeric overflow occurs
+     */
+    long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets a descriptive name for the unit.
+     * <p>
+     * This should be in the plural and upper-first camel case, such as 'Days' or 'Minutes'.
+     *
+     * @return the name of this unit, not null
+     */
+    @Override
+    String toString();
+
+}
diff --git a/java/time/temporal/UnsupportedTemporalTypeException.java b/java/time/temporal/UnsupportedTemporalTypeException.java
new file mode 100644
index 0000000..e4b2b12
--- /dev/null
+++ b/java/time/temporal/UnsupportedTemporalTypeException.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2013, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.time.DateTimeException;
+
+/**
+ * UnsupportedTemporalTypeException indicates that a ChronoField or ChronoUnit is
+ * not supported for a Temporal class.
+ *
+ * @implSpec
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class UnsupportedTemporalTypeException extends DateTimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -6158898438688206006L;
+
+    /**
+     * Constructs a new UnsupportedTemporalTypeException with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     */
+    public UnsupportedTemporalTypeException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new UnsupportedTemporalTypeException with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param cause  the cause of the exception, may be null
+     */
+    public UnsupportedTemporalTypeException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/java/time/temporal/ValueRange.java b/java/time/temporal/ValueRange.java
new file mode 100644
index 0000000..4e5c2fd
--- /dev/null
+++ b/java/time/temporal/ValueRange.java
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.DateTimeException;
+
+/**
+ * The range of valid values for a date-time field.
+ * <p>
+ * All {@link TemporalField} instances have a valid range of values.
+ * For example, the ISO day-of-month runs from 1 to somewhere between 28 and 31.
+ * This class captures that valid range.
+ * <p>
+ * It is important to be aware of the limitations of this class.
+ * Only the minimum and maximum values are provided.
+ * It is possible for there to be invalid values within the outer range.
+ * For example, a weird field may have valid values of 1, 2, 4, 6, 7, thus
+ * have a range of '1 - 7', despite that fact that values 3 and 5 are invalid.
+ * <p>
+ * Instances of this class are not tied to a specific field.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ValueRange implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -7317881728594519368L;
+
+    /**
+     * The smallest minimum value.
+     */
+    private final long minSmallest;
+    /**
+     * The largest minimum value.
+     */
+    private final long minLargest;
+    /**
+     * The smallest maximum value.
+     */
+    private final long maxSmallest;
+    /**
+     * The largest maximum value.
+     */
+    private final long maxLargest;
+
+    /**
+     * Obtains a fixed value range.
+     * <p>
+     * This factory obtains a range where the minimum and maximum values are fixed.
+     * For example, the ISO month-of-year always runs from 1 to 12.
+     *
+     * @param min  the minimum value
+     * @param max  the maximum value
+     * @return the ValueRange for min, max, not null
+     * @throws IllegalArgumentException if the minimum is greater than the maximum
+     */
+    public static ValueRange of(long min, long max) {
+        if (min > max) {
+            throw new IllegalArgumentException("Minimum value must be less than maximum value");
+        }
+        return new ValueRange(min, min, max, max);
+    }
+
+    /**
+     * Obtains a variable value range.
+     * <p>
+     * This factory obtains a range where the minimum value is fixed and the maximum value may vary.
+     * For example, the ISO day-of-month always starts at 1, but ends between 28 and 31.
+     *
+     * @param min  the minimum value
+     * @param maxSmallest  the smallest maximum value
+     * @param maxLargest  the largest maximum value
+     * @return the ValueRange for min, smallest max, largest max, not null
+     * @throws IllegalArgumentException if
+     *     the minimum is greater than the smallest maximum,
+     *  or the smallest maximum is greater than the largest maximum
+     */
+    public static ValueRange of(long min, long maxSmallest, long maxLargest) {
+        return of(min, min, maxSmallest, maxLargest);
+    }
+
+    /**
+     * Obtains a fully variable value range.
+     * <p>
+     * This factory obtains a range where both the minimum and maximum value may vary.
+     *
+     * @param minSmallest  the smallest minimum value
+     * @param minLargest  the largest minimum value
+     * @param maxSmallest  the smallest maximum value
+     * @param maxLargest  the largest maximum value
+     * @return the ValueRange for smallest min, largest min, smallest max, largest max, not null
+     * @throws IllegalArgumentException if
+     *     the smallest minimum is greater than the smallest maximum,
+     *  or the smallest maximum is greater than the largest maximum
+     *  or the largest minimum is greater than the largest maximum
+     */
+    public static ValueRange of(long minSmallest, long minLargest, long maxSmallest, long maxLargest) {
+        if (minSmallest > minLargest) {
+            throw new IllegalArgumentException("Smallest minimum value must be less than largest minimum value");
+        }
+        if (maxSmallest > maxLargest) {
+            throw new IllegalArgumentException("Smallest maximum value must be less than largest maximum value");
+        }
+        if (minLargest > maxLargest) {
+            throw new IllegalArgumentException("Minimum value must be less than maximum value");
+        }
+        return new ValueRange(minSmallest, minLargest, maxSmallest, maxLargest);
+    }
+
+    /**
+     * Restrictive constructor.
+     *
+     * @param minSmallest  the smallest minimum value
+     * @param minLargest  the largest minimum value
+     * @param maxSmallest  the smallest minimum value
+     * @param maxLargest  the largest minimum value
+     */
+    private ValueRange(long minSmallest, long minLargest, long maxSmallest, long maxLargest) {
+        this.minSmallest = minSmallest;
+        this.minLargest = minLargest;
+        this.maxSmallest = maxSmallest;
+        this.maxLargest = maxLargest;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Is the value range fixed and fully known.
+     * <p>
+     * For example, the ISO day-of-month runs from 1 to between 28 and 31.
+     * Since there is uncertainty about the maximum value, the range is not fixed.
+     * However, for the month of January, the range is always 1 to 31, thus it is fixed.
+     *
+     * @return true if the set of values is fixed
+     */
+    public boolean isFixed() {
+        return minSmallest == minLargest && maxSmallest == maxLargest;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the minimum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month always starts at 1.
+     * The minimum is therefore 1.
+     *
+     * @return the minimum value for this field
+     */
+    public long getMinimum() {
+        return minSmallest;
+    }
+
+    /**
+     * Gets the largest possible minimum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month always starts at 1.
+     * The largest minimum is therefore 1.
+     *
+     * @return the largest possible minimum value for this field
+     */
+    public long getLargestMinimum() {
+        return minLargest;
+    }
+
+    /**
+     * Gets the smallest possible maximum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month runs to between 28 and 31 days.
+     * The smallest maximum is therefore 28.
+     *
+     * @return the smallest possible maximum value for this field
+     */
+    public long getSmallestMaximum() {
+        return maxSmallest;
+    }
+
+    /**
+     * Gets the maximum value that the field can take.
+     * <p>
+     * For example, the ISO day-of-month runs to between 28 and 31 days.
+     * The maximum is therefore 31.
+     *
+     * @return the maximum value for this field
+     */
+    public long getMaximum() {
+        return maxLargest;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if all values in the range fit in an {@code int}.
+     * <p>
+     * This checks that all valid values are within the bounds of an {@code int}.
+     * <p>
+     * For example, the ISO month-of-year has values from 1 to 12, which fits in an {@code int}.
+     * By comparison, ISO nano-of-day runs from 1 to 86,400,000,000,000 which does not fit in an {@code int}.
+     * <p>
+     * This implementation uses {@link #getMinimum()} and {@link #getMaximum()}.
+     *
+     * @return true if a valid value always fits in an {@code int}
+     */
+    public boolean isIntValue() {
+        return getMinimum() >= Integer.MIN_VALUE && getMaximum() <= Integer.MAX_VALUE;
+    }
+
+    /**
+     * Checks if the value is within the valid range.
+     * <p>
+     * This checks that the value is within the stored range of values.
+     *
+     * @param value  the value to check
+     * @return true if the value is valid
+     */
+    public boolean isValidValue(long value) {
+        return (value >= getMinimum() && value <= getMaximum());
+    }
+
+    /**
+     * Checks if the value is within the valid range and that all values
+     * in the range fit in an {@code int}.
+     * <p>
+     * This method combines {@link #isIntValue()} and {@link #isValidValue(long)}.
+     *
+     * @param value  the value to check
+     * @return true if the value is valid and fits in an {@code int}
+     */
+    public boolean isValidIntValue(long value) {
+        return isIntValue() && isValidValue(value);
+    }
+
+    /**
+     * Checks that the specified value is valid.
+     * <p>
+     * This validates that the value is within the valid range of values.
+     * The field is only used to improve the error message.
+     *
+     * @param value  the value to check
+     * @param field  the field being checked, may be null
+     * @return the value that was passed in
+     * @see #isValidValue(long)
+     */
+    public long checkValidValue(long value, TemporalField field) {
+        if (isValidValue(value) == false) {
+            throw new DateTimeException(genInvalidFieldMessage(field, value));
+        }
+        return value;
+    }
+
+    /**
+     * Checks that the specified value is valid and fits in an {@code int}.
+     * <p>
+     * This validates that the value is within the valid range of values and that
+     * all valid values are within the bounds of an {@code int}.
+     * The field is only used to improve the error message.
+     *
+     * @param value  the value to check
+     * @param field  the field being checked, may be null
+     * @return the value that was passed in
+     * @see #isValidIntValue(long)
+     */
+    public int checkValidIntValue(long value, TemporalField field) {
+        if (isValidIntValue(value) == false) {
+            throw new DateTimeException(genInvalidFieldMessage(field, value));
+        }
+        return (int) value;
+    }
+
+    private String genInvalidFieldMessage(TemporalField field, long value) {
+        if (field != null) {
+            return "Invalid value for " + field + " (valid values " + this + "): " + value;
+        } else {
+            return "Invalid value (valid values " + this + "): " + value;
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restore the state of an ValueRange from the stream.
+     * Check that the values are valid.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException if
+     *     the smallest minimum is greater than the smallest maximum,
+     *  or the smallest maximum is greater than the largest maximum
+     *  or the largest minimum is greater than the largest maximum
+     * @throws ClassNotFoundException if a class cannot be resolved
+     */
+    private void readObject(ObjectInputStream s)
+         throws IOException, ClassNotFoundException, InvalidObjectException
+    {
+        s.defaultReadObject();
+        if (minSmallest > minLargest) {
+            throw new InvalidObjectException("Smallest minimum value must be less than largest minimum value");
+        }
+        if (maxSmallest > maxLargest) {
+            throw new InvalidObjectException("Smallest maximum value must be less than largest maximum value");
+        }
+        if (minLargest > maxLargest) {
+            throw new InvalidObjectException("Minimum value must be less than maximum value");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this range is equal to another range.
+     * <p>
+     * The comparison is based on the four values, minimum, largest minimum,
+     * smallest maximum and maximum.
+     * Only objects of type {@code ValueRange} are compared, other types return false.
+     *
+     * @param obj  the object to check, null returns false
+     * @return true if this is equal to the other range
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (obj instanceof ValueRange) {
+            ValueRange other = (ValueRange) obj;
+           return minSmallest == other.minSmallest && minLargest == other.minLargest &&
+                   maxSmallest == other.maxSmallest && maxLargest == other.maxLargest;
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this range.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        long hash = minSmallest + minLargest << 16 + minLargest >> 48 + maxSmallest << 32 +
+            maxSmallest >> 32 + maxLargest << 48 + maxLargest >> 16;
+        return (int) (hash ^ (hash >>> 32));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Outputs this range as a {@code String}.
+     * <p>
+     * The format will be '{min}/{largestMin} - {smallestMax}/{max}',
+     * where the largestMin or smallestMax sections may be omitted, together
+     * with associated slash, if they are the same as the min or max.
+     *
+     * @return a string representation of this range, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append(minSmallest);
+        if (minSmallest != minLargest) {
+            buf.append('/').append(minLargest);
+        }
+        buf.append(" - ").append(maxSmallest);
+        if (maxSmallest != maxLargest) {
+            buf.append('/').append(maxLargest);
+        }
+        return buf.toString();
+    }
+
+}
diff --git a/java/time/temporal/WeekFields.java b/java/time/temporal/WeekFields.java
new file mode 100644
index 0000000..57f481c
--- /dev/null
+++ b/java/time/temporal/WeekFields.java
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.temporal;
+
+import android.icu.text.DateTimePatternGenerator;
+import android.icu.util.Calendar;
+import android.icu.util.ULocale;
+
+import static java.time.temporal.ChronoField.DAY_OF_MONTH;
+import static java.time.temporal.ChronoField.DAY_OF_WEEK;
+import static java.time.temporal.ChronoField.DAY_OF_YEAR;
+import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
+import static java.time.temporal.ChronoField.YEAR;
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.FOREVER;
+import static java.time.temporal.ChronoUnit.MONTHS;
+import static java.time.temporal.ChronoUnit.WEEKS;
+import static java.time.temporal.ChronoUnit.YEARS;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.chrono.ChronoLocalDate;
+import java.time.chrono.Chronology;
+import java.time.format.ResolverStyle;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Localized definitions of the day-of-week, week-of-month and week-of-year fields.
+ * <p>
+ * A standard week is seven days long, but cultures have different definitions for some
+ * other aspects of a week. This class represents the definition of the week, for the
+ * purpose of providing {@link TemporalField} instances.
+ * <p>
+ * WeekFields provides five fields,
+ * {@link #dayOfWeek()}, {@link #weekOfMonth()}, {@link #weekOfYear()},
+ * {@link #weekOfWeekBasedYear()}, and {@link #weekBasedYear()}
+ * that provide access to the values from any {@linkplain Temporal temporal object}.
+ * <p>
+ * The computations for day-of-week, week-of-month, and week-of-year are based
+ * on the  {@linkplain ChronoField#YEAR proleptic-year},
+ * {@linkplain ChronoField#MONTH_OF_YEAR month-of-year},
+ * {@linkplain ChronoField#DAY_OF_MONTH day-of-month}, and
+ * {@linkplain ChronoField#DAY_OF_WEEK ISO day-of-week} which are based on the
+ * {@linkplain ChronoField#EPOCH_DAY epoch-day} and the chronology.
+ * The values may not be aligned with the {@linkplain ChronoField#YEAR_OF_ERA year-of-Era}
+ * depending on the Chronology.
+ * <p>A week is defined by:
+ * <ul>
+ * <li>The first day-of-week.
+ * For example, the ISO-8601 standard considers Monday to be the first day-of-week.
+ * <li>The minimal number of days in the first week.
+ * For example, the ISO-8601 standard counts the first week as needing at least 4 days.
+ * </ul>
+ * Together these two values allow a year or month to be divided into weeks.
+ *
+ * <h3>Week of Month</h3>
+ * One field is used: week-of-month.
+ * The calculation ensures that weeks never overlap a month boundary.
+ * The month is divided into periods where each period starts on the defined first day-of-week.
+ * The earliest period is referred to as week 0 if it has less than the minimal number of days
+ * and week 1 if it has at least the minimal number of days.
+ *
+ * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
+ * <caption>Examples of WeekFields</caption>
+ * <tr><th>Date</th><td>Day-of-week</td>
+ *  <td>First day: Monday<br>Minimal days: 4</td><td>First day: Monday<br>Minimal days: 5</td></tr>
+ * <tr><th>2008-12-31</th><td>Wednesday</td>
+ *  <td>Week 5 of December 2008</td><td>Week 5 of December 2008</td></tr>
+ * <tr><th>2009-01-01</th><td>Thursday</td>
+ *  <td>Week 1 of January 2009</td><td>Week 0 of January 2009</td></tr>
+ * <tr><th>2009-01-04</th><td>Sunday</td>
+ *  <td>Week 1 of January 2009</td><td>Week 0 of January 2009</td></tr>
+ * <tr><th>2009-01-05</th><td>Monday</td>
+ *  <td>Week 2 of January 2009</td><td>Week 1 of January 2009</td></tr>
+ * </table>
+ *
+ * <h3>Week of Year</h3>
+ * One field is used: week-of-year.
+ * The calculation ensures that weeks never overlap a year boundary.
+ * The year is divided into periods where each period starts on the defined first day-of-week.
+ * The earliest period is referred to as week 0 if it has less than the minimal number of days
+ * and week 1 if it has at least the minimal number of days.
+ *
+ * <h3>Week Based Year</h3>
+ * Two fields are used for week-based-year, one for the
+ * {@link #weekOfWeekBasedYear() week-of-week-based-year} and one for
+ * {@link #weekBasedYear() week-based-year}.  In a week-based-year, each week
+ * belongs to only a single year.  Week 1 of a year is the first week that
+ * starts on the first day-of-week and has at least the minimum number of days.
+ * The first and last weeks of a year may contain days from the
+ * previous calendar year or next calendar year respectively.
+ *
+ * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
+ * <caption>Examples of WeekFields for week-based-year</caption>
+ * <tr><th>Date</th><td>Day-of-week</td>
+ *  <td>First day: Monday<br>Minimal days: 4</td><td>First day: Monday<br>Minimal days: 5</td></tr>
+ * <tr><th>2008-12-31</th><td>Wednesday</td>
+ *  <td>Week 1 of 2009</td><td>Week 53 of 2008</td></tr>
+ * <tr><th>2009-01-01</th><td>Thursday</td>
+ *  <td>Week 1 of 2009</td><td>Week 53 of 2008</td></tr>
+ * <tr><th>2009-01-04</th><td>Sunday</td>
+ *  <td>Week 1 of 2009</td><td>Week 53 of 2008</td></tr>
+ * <tr><th>2009-01-05</th><td>Monday</td>
+ *  <td>Week 2 of 2009</td><td>Week 1 of 2009</td></tr>
+ * </table>
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class WeekFields implements Serializable {
+    // implementation notes
+    // querying week-of-month or week-of-year should return the week value bound within the month/year
+    // however, setting the week value should be lenient (use plus/minus weeks)
+    // allow week-of-month outer range [0 to 6]
+    // allow week-of-year outer range [0 to 54]
+    // this is because callers shouldn't be expected to know the details of validity
+
+    /**
+     * The cache of rules by firstDayOfWeek plus minimalDays.
+     * Initialized first to be available for definition of ISO, etc.
+     */
+    private static final ConcurrentMap<String, WeekFields> CACHE = new ConcurrentHashMap<>(4, 0.75f, 2);
+
+    /**
+     * The ISO-8601 definition, where a week starts on Monday and the first week
+     * has a minimum of 4 days.
+     * <p>
+     * The ISO-8601 standard defines a calendar system based on weeks.
+     * It uses the week-based-year and week-of-week-based-year concepts to split
+     * up the passage of days instead of the standard year/month/day.
+     * <p>
+     * Note that the first week may start in the previous calendar year.
+     * Note also that the first few days of a calendar year may be in the
+     * week-based-year corresponding to the previous calendar year.
+     */
+    public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);
+
+    /**
+     * The common definition of a week that starts on Sunday and the first week
+     * has a minimum of 1 day.
+     * <p>
+     * Defined as starting on Sunday and with a minimum of 1 day in the month.
+     * This week definition is in use in the US and other European countries.
+     */
+    public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1);
+
+    /**
+     * The unit that represents week-based-years for the purpose of addition and subtraction.
+     * <p>
+     * This allows a number of week-based-years to be added to, or subtracted from, a date.
+     * The unit is equal to either 52 or 53 weeks.
+     * The estimated duration of a week-based-year is the same as that of a standard ISO
+     * year at {@code 365.2425 Days}.
+     * <p>
+     * The rules for addition add the number of week-based-years to the existing value
+     * for the week-based-year field retaining the week-of-week-based-year
+     * and day-of-week, unless the week number it too large for the target year.
+     * In that case, the week is set to the last week of the year
+     * with the same day-of-week.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    public static final TemporalUnit WEEK_BASED_YEARS = IsoFields.WEEK_BASED_YEARS;
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1177360819670808121L;
+
+    /**
+     * The first day-of-week.
+     */
+    private final DayOfWeek firstDayOfWeek;
+    /**
+     * The minimal number of days in the first week.
+     */
+    private final int minimalDays;
+    /**
+     * The field used to access the computed DayOfWeek.
+     */
+    private final transient TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this);
+    /**
+     * The field used to access the computed WeekOfMonth.
+     */
+    private final transient TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this);
+    /**
+     * The field used to access the computed WeekOfYear.
+     */
+    private final transient TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this);
+    /**
+     * The field that represents the week-of-week-based-year.
+     * <p>
+     * This field allows the week of the week-based-year value to be queried and set.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    private final transient TemporalField weekOfWeekBasedYear = ComputedDayOfField.ofWeekOfWeekBasedYearField(this);
+    /**
+     * The field that represents the week-based-year.
+     * <p>
+     * This field allows the week-based-year value to be queried and set.
+     * <p>
+     * This unit is an immutable and thread-safe singleton.
+     */
+    private final transient TemporalField weekBasedYear = ComputedDayOfField.ofWeekBasedYearField(this);
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance of {@code WeekFields} appropriate for a locale.
+     * <p>
+     * This will look up appropriate values from the provider of localization data.
+     *
+     * @param locale  the locale to use, not null
+     * @return the week-definition, not null
+     */
+    public static WeekFields of(Locale locale) {
+        Objects.requireNonNull(locale, "locale");
+        // Android-changed: get Week data from ICU4J
+        ULocale ulocale = ULocale.forLocale(locale);
+        String region = ULocale.getRegionForSupplementalData(ulocale, /* inferRegion */ true);
+        Calendar.WeekData weekData = Calendar.getWeekDataForRegion(region);
+        DayOfWeek dow = DayOfWeek.SUNDAY.plus(weekData.firstDayOfWeek - 1);
+        return WeekFields.of(dow, weekData.minimalDaysInFirstWeek);
+    }
+
+    /**
+     * Obtains an instance of {@code WeekFields} from the first day-of-week and minimal days.
+     * <p>
+     * The first day-of-week defines the ISO {@code DayOfWeek} that is day 1 of the week.
+     * The minimal number of days in the first week defines how many days must be present
+     * in a month or year, starting from the first day-of-week, before the week is counted
+     * as the first week. A value of 1 will count the first day of the month or year as part
+     * of the first week, whereas a value of 7 will require the whole seven days to be in
+     * the new month or year.
+     * <p>
+     * WeekFields instances are singletons; for each unique combination
+     * of {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} the
+     * the same instance will be returned.
+     *
+     * @param firstDayOfWeek  the first day of the week, not null
+     * @param minimalDaysInFirstWeek  the minimal number of days in the first week, from 1 to 7
+     * @return the week-definition, not null
+     * @throws IllegalArgumentException if the minimal days value is less than one
+     *      or greater than 7
+     */
+    public static WeekFields of(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) {
+        String key = firstDayOfWeek.toString() + minimalDaysInFirstWeek;
+        WeekFields rules = CACHE.get(key);
+        if (rules == null) {
+            rules = new WeekFields(firstDayOfWeek, minimalDaysInFirstWeek);
+            CACHE.putIfAbsent(key, rules);
+            rules = CACHE.get(key);
+        }
+        return rules;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates an instance of the definition.
+     *
+     * @param firstDayOfWeek  the first day of the week, not null
+     * @param minimalDaysInFirstWeek  the minimal number of days in the first week, from 1 to 7
+     * @throws IllegalArgumentException if the minimal days value is invalid
+     */
+    private WeekFields(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) {
+        Objects.requireNonNull(firstDayOfWeek, "firstDayOfWeek");
+        if (minimalDaysInFirstWeek < 1 || minimalDaysInFirstWeek > 7) {
+            throw new IllegalArgumentException("Minimal number of days is invalid");
+        }
+        this.firstDayOfWeek = firstDayOfWeek;
+        this.minimalDays = minimalDaysInFirstWeek;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Restore the state of a WeekFields from the stream.
+     * Check that the values are valid.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException if the serialized object has an invalid
+     *     value for firstDayOfWeek or minimalDays.
+     * @throws ClassNotFoundException if a class cannot be resolved
+     */
+    private void readObject(ObjectInputStream s)
+         throws IOException, ClassNotFoundException, InvalidObjectException
+    {
+        s.defaultReadObject();
+        if (firstDayOfWeek == null) {
+            throw new InvalidObjectException("firstDayOfWeek is null");
+        }
+
+        if (minimalDays < 1 || minimalDays > 7) {
+            throw new InvalidObjectException("Minimal number of days is invalid");
+        }
+    }
+
+    /**
+     * Return the singleton WeekFields associated with the
+     * {@code firstDayOfWeek} and {@code minimalDays}.
+     * @return the singleton WeekFields for the firstDayOfWeek and minimalDays.
+     * @throws InvalidObjectException if the serialized object has invalid
+     *     values for firstDayOfWeek or minimalDays.
+     */
+    private Object readResolve() throws InvalidObjectException {
+        try {
+            return WeekFields.of(firstDayOfWeek, minimalDays);
+        } catch (IllegalArgumentException iae) {
+            throw new InvalidObjectException("Invalid serialized WeekFields: " + iae.getMessage());
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the first day-of-week.
+     * <p>
+     * The first day-of-week varies by culture.
+     * For example, the US uses Sunday, while France and the ISO-8601 standard use Monday.
+     * This method returns the first day using the standard {@code DayOfWeek} enum.
+     *
+     * @return the first day-of-week, not null
+     */
+    public DayOfWeek getFirstDayOfWeek() {
+        return firstDayOfWeek;
+    }
+
+    /**
+     * Gets the minimal number of days in the first week.
+     * <p>
+     * The number of days considered to define the first week of a month or year
+     * varies by culture.
+     * For example, the ISO-8601 requires 4 days (more than half a week) to
+     * be present before counting the first week.
+     *
+     * @return the minimal number of days in the first week of a month or year, from 1 to 7
+     */
+    public int getMinimalDaysInFirstWeek() {
+        return minimalDays;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a field to access the day of week based on this {@code WeekFields}.
+     * <p>
+     * This is similar to {@link ChronoField#DAY_OF_WEEK} but uses values for
+     * the day-of-week based on this {@code WeekFields}.
+     * The days are numbered from 1 to 7 where the
+     * {@link #getFirstDayOfWeek() first day-of-week} is assigned the value 1.
+     * <p>
+     * For example, if the first day-of-week is Sunday, then that will have the
+     * value 1, with other days ranging from Monday as 2 to Saturday as 7.
+     * <p>
+     * In the resolving phase of parsing, a localized day-of-week will be converted
+     * to a standardized {@code ChronoField} day-of-week.
+     * The day-of-week must be in the valid range 1 to 7.
+     * Other fields in this class build dates using the standardized day-of-week.
+     *
+     * @return a field providing access to the day-of-week with localized numbering, not null
+     */
+    public TemporalField dayOfWeek() {
+        return dayOfWeek;
+    }
+
+    /**
+     * Returns a field to access the week of month based on this {@code WeekFields}.
+     * <p>
+     * This represents the concept of the count of weeks within the month where weeks
+     * start on a fixed day-of-week, such as Monday.
+     * This field is typically used with {@link WeekFields#dayOfWeek()}.
+     * <p>
+     * Week one (1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
+     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the month.
+     * Thus, week one may start up to {@code minDays} days before the start of the month.
+     * If the first week starts after the start of the month then the period before is week zero (0).
+     * <p>
+     * For example:<br>
+     * - if the 1st day of the month is a Monday, week one starts on the 1st and there is no week zero<br>
+     * - if the 2nd day of the month is a Monday, week one starts on the 2nd and the 1st is in week zero<br>
+     * - if the 4th day of the month is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero<br>
+     * - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
+     * <p>
+     * This field can be used with any calendar system.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a year,
+     * week-of-month, month-of-year and day-of-week.
+     * <p>
+     * In {@linkplain ResolverStyle#STRICT strict mode}, all four fields are
+     * validated against their range of valid values. The week-of-month field
+     * is validated to ensure that the resulting month is the month requested.
+     * <p>
+     * In {@linkplain ResolverStyle#SMART smart mode}, all four fields are
+     * validated against their range of valid values. The week-of-month field
+     * is validated from 0 to 6, meaning that the resulting date can be in a
+     * different month to that specified.
+     * <p>
+     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
+     * are validated against the range of valid values. The resulting date is calculated
+     * equivalent to the following four stage approach.
+     * First, create a date on the first day of the first week of January in the requested year.
+     * Then take the month-of-year, subtract one, and add the amount in months to the date.
+     * Then take the week-of-month, subtract one, and add the amount in weeks to the date.
+     * Finally, adjust to the correct day-of-week within the localized week.
+     *
+     * @return a field providing access to the week-of-month, not null
+     */
+    public TemporalField weekOfMonth() {
+        return weekOfMonth;
+    }
+
+    /**
+     * Returns a field to access the week of year based on this {@code WeekFields}.
+     * <p>
+     * This represents the concept of the count of weeks within the year where weeks
+     * start on a fixed day-of-week, such as Monday.
+     * This field is typically used with {@link WeekFields#dayOfWeek()}.
+     * <p>
+     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
+     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the year.
+     * Thus, week one may start up to {@code minDays} days before the start of the year.
+     * If the first week starts after the start of the year then the period before is week zero (0).
+     * <p>
+     * For example:<br>
+     * - if the 1st day of the year is a Monday, week one starts on the 1st and there is no week zero<br>
+     * - if the 2nd day of the year is a Monday, week one starts on the 2nd and the 1st is in week zero<br>
+     * - if the 4th day of the year is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero<br>
+     * - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
+     * <p>
+     * This field can be used with any calendar system.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a year,
+     * week-of-year and day-of-week.
+     * <p>
+     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
+     * validated against their range of valid values. The week-of-year field
+     * is validated to ensure that the resulting year is the year requested.
+     * <p>
+     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
+     * validated against their range of valid values. The week-of-year field
+     * is validated from 0 to 54, meaning that the resulting date can be in a
+     * different year to that specified.
+     * <p>
+     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
+     * are validated against the range of valid values. The resulting date is calculated
+     * equivalent to the following three stage approach.
+     * First, create a date on the first day of the first week in the requested year.
+     * Then take the week-of-year, subtract one, and add the amount in weeks to the date.
+     * Finally, adjust to the correct day-of-week within the localized week.
+     *
+     * @return a field providing access to the week-of-year, not null
+     */
+    public TemporalField weekOfYear() {
+        return weekOfYear;
+    }
+
+    /**
+     * Returns a field to access the week of a week-based-year based on this {@code WeekFields}.
+     * <p>
+     * This represents the concept of the count of weeks within the year where weeks
+     * start on a fixed day-of-week, such as Monday and each week belongs to exactly one year.
+     * This field is typically used with {@link WeekFields#dayOfWeek()} and
+     * {@link WeekFields#weekBasedYear()}.
+     * <p>
+     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
+     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the year.
+     * If the first week starts after the start of the year then the period before
+     * is in the last week of the previous year.
+     * <p>
+     * For example:<br>
+     * - if the 1st day of the year is a Monday, week one starts on the 1st<br>
+     * - if the 2nd day of the year is a Monday, week one starts on the 2nd and
+     *   the 1st is in the last week of the previous year<br>
+     * - if the 4th day of the year is a Monday, week one starts on the 4th and
+     *   the 1st to 3rd is in the last week of the previous year<br>
+     * - if the 5th day of the year is a Monday, week two starts on the 5th and
+     *   the 1st to 4th is in week one<br>
+     * <p>
+     * This field can be used with any calendar system.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a week-based-year,
+     * week-of-year and day-of-week.
+     * <p>
+     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
+     * validated against their range of valid values. The week-of-year field
+     * is validated to ensure that the resulting week-based-year is the
+     * week-based-year requested.
+     * <p>
+     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
+     * validated against their range of valid values. The week-of-week-based-year field
+     * is validated from 1 to 53, meaning that the resulting date can be in the
+     * following week-based-year to that specified.
+     * <p>
+     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
+     * are validated against the range of valid values. The resulting date is calculated
+     * equivalent to the following three stage approach.
+     * First, create a date on the first day of the first week in the requested week-based-year.
+     * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date.
+     * Finally, adjust to the correct day-of-week within the localized week.
+     *
+     * @return a field providing access to the week-of-week-based-year, not null
+     */
+    public TemporalField weekOfWeekBasedYear() {
+        return weekOfWeekBasedYear;
+    }
+
+    /**
+     * Returns a field to access the year of a week-based-year based on this {@code WeekFields}.
+     * <p>
+     * This represents the concept of the year where weeks start on a fixed day-of-week,
+     * such as Monday and each week belongs to exactly one year.
+     * This field is typically used with {@link WeekFields#dayOfWeek()} and
+     * {@link WeekFields#weekOfWeekBasedYear()}.
+     * <p>
+     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
+     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the year.
+     * Thus, week one may start before the start of the year.
+     * If the first week starts after the start of the year then the period before
+     * is in the last week of the previous year.
+     * <p>
+     * This field can be used with any calendar system.
+     * <p>
+     * In the resolving phase of parsing, a date can be created from a week-based-year,
+     * week-of-year and day-of-week.
+     * <p>
+     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
+     * validated against their range of valid values. The week-of-year field
+     * is validated to ensure that the resulting week-based-year is the
+     * week-based-year requested.
+     * <p>
+     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
+     * validated against their range of valid values. The week-of-week-based-year field
+     * is validated from 1 to 53, meaning that the resulting date can be in the
+     * following week-based-year to that specified.
+     * <p>
+     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
+     * are validated against the range of valid values. The resulting date is calculated
+     * equivalent to the following three stage approach.
+     * First, create a date on the first day of the first week in the requested week-based-year.
+     * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date.
+     * Finally, adjust to the correct day-of-week within the localized week.
+     *
+     * @return a field providing access to the week-based-year, not null
+     */
+    public TemporalField weekBasedYear() {
+        return weekBasedYear;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this {@code WeekFields} is equal to the specified object.
+     * <p>
+     * The comparison is based on the entire state of the rules, which is
+     * the first day-of-week and minimal days.
+     *
+     * @param object  the other rules to compare to, null returns false
+     * @return true if this is equal to the specified rules
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof WeekFields) {
+            return hashCode() == object.hashCode();
+        }
+        return false;
+    }
+
+    /**
+     * A hash code for this {@code WeekFields}.
+     *
+     * @return a suitable hash code
+     */
+    @Override
+    public int hashCode() {
+        return firstDayOfWeek.ordinal() * 7 + minimalDays;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A string representation of this {@code WeekFields} instance.
+     *
+     * @return the string representation, not null
+     */
+    @Override
+    public String toString() {
+        return "WeekFields[" + firstDayOfWeek + ',' + minimalDays + ']';
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Field type that computes DayOfWeek, WeekOfMonth, and WeekOfYear
+     * based on a WeekFields.
+     * A separate Field instance is required for each different WeekFields;
+     * combination of start of week and minimum number of days.
+     * Constructors are provided to create fields for DayOfWeek, WeekOfMonth,
+     * and WeekOfYear.
+     */
+    static class ComputedDayOfField implements TemporalField {
+
+        /**
+         * Returns a field to access the day of week,
+         * computed based on a WeekFields.
+         * <p>
+         * The WeekDefintion of the first day of the week is used with
+         * the ISO DAY_OF_WEEK field to compute week boundaries.
+         */
+        static ComputedDayOfField ofDayOfWeekField(WeekFields weekDef) {
+            return new ComputedDayOfField("DayOfWeek", weekDef, DAYS, WEEKS, DAY_OF_WEEK_RANGE);
+        }
+
+        /**
+         * Returns a field to access the week of month,
+         * computed based on a WeekFields.
+         * @see WeekFields#weekOfMonth()
+         */
+        static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) {
+            return new ComputedDayOfField("WeekOfMonth", weekDef, WEEKS, MONTHS, WEEK_OF_MONTH_RANGE);
+        }
+
+        /**
+         * Returns a field to access the week of year,
+         * computed based on a WeekFields.
+         * @see WeekFields#weekOfYear()
+         */
+        static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) {
+            return new ComputedDayOfField("WeekOfYear", weekDef, WEEKS, YEARS, WEEK_OF_YEAR_RANGE);
+        }
+
+        /**
+         * Returns a field to access the week of week-based-year,
+         * computed based on a WeekFields.
+         * @see WeekFields#weekOfWeekBasedYear()
+         */
+        static ComputedDayOfField ofWeekOfWeekBasedYearField(WeekFields weekDef) {
+            return new ComputedDayOfField("WeekOfWeekBasedYear", weekDef, WEEKS, IsoFields.WEEK_BASED_YEARS, WEEK_OF_WEEK_BASED_YEAR_RANGE);
+        }
+
+        /**
+         * Returns a field to access the week of week-based-year,
+         * computed based on a WeekFields.
+         * @see WeekFields#weekBasedYear()
+         */
+        static ComputedDayOfField ofWeekBasedYearField(WeekFields weekDef) {
+            return new ComputedDayOfField("WeekBasedYear", weekDef, IsoFields.WEEK_BASED_YEARS, FOREVER, ChronoField.YEAR.range());
+        }
+
+        /**
+         * Return a new week-based-year date of the Chronology, year, week-of-year,
+         * and dow of week.
+         * @param chrono The chronology of the new date
+         * @param yowby the year of the week-based-year
+         * @param wowby the week of the week-based-year
+         * @param dow the day of the week
+         * @return a ChronoLocalDate for the requested year, week of year, and day of week
+         */
+        private ChronoLocalDate ofWeekBasedYear(Chronology chrono,
+                int yowby, int wowby, int dow) {
+            ChronoLocalDate date = chrono.date(yowby, 1, 1);
+            int ldow = localizedDayOfWeek(date);
+            int offset = startOfWeekOffset(1, ldow);
+
+            // Clamp the week of year to keep it in the same year
+            int yearLen = date.lengthOfYear();
+            int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
+            wowby = Math.min(wowby, newYearWeek - 1);
+
+            int days = -offset + (dow - 1) + (wowby - 1) * 7;
+            return date.plus(days, DAYS);
+        }
+
+        private final String name;
+        private final WeekFields weekDef;
+        private final TemporalUnit baseUnit;
+        private final TemporalUnit rangeUnit;
+        private final ValueRange range;
+
+        private ComputedDayOfField(String name, WeekFields weekDef, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) {
+            this.name = name;
+            this.weekDef = weekDef;
+            this.baseUnit = baseUnit;
+            this.rangeUnit = rangeUnit;
+            this.range = range;
+        }
+
+        private static final ValueRange DAY_OF_WEEK_RANGE = ValueRange.of(1, 7);
+        private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 6);
+        private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 54);
+        private static final ValueRange WEEK_OF_WEEK_BASED_YEAR_RANGE = ValueRange.of(1, 52, 53);
+
+        @Override
+        public long getFrom(TemporalAccessor temporal) {
+            if (rangeUnit == WEEKS) {  // day-of-week
+                return localizedDayOfWeek(temporal);
+            } else if (rangeUnit == MONTHS) {  // week-of-month
+                return localizedWeekOfMonth(temporal);
+            } else if (rangeUnit == YEARS) {  // week-of-year
+                return localizedWeekOfYear(temporal);
+            } else if (rangeUnit == WEEK_BASED_YEARS) {
+                return localizedWeekOfWeekBasedYear(temporal);
+            } else if (rangeUnit == FOREVER) {
+                return localizedWeekBasedYear(temporal);
+            } else {
+                throw new IllegalStateException("unreachable, rangeUnit: " + rangeUnit + ", this: " + this);
+            }
+        }
+
+        private int localizedDayOfWeek(TemporalAccessor temporal) {
+            int sow = weekDef.getFirstDayOfWeek().getValue();
+            int isoDow = temporal.get(DAY_OF_WEEK);
+            return Math.floorMod(isoDow - sow, 7) + 1;
+        }
+
+        private int localizedDayOfWeek(int isoDow) {
+            int sow = weekDef.getFirstDayOfWeek().getValue();
+            return Math.floorMod(isoDow - sow, 7) + 1;
+        }
+
+        private long localizedWeekOfMonth(TemporalAccessor temporal) {
+            int dow = localizedDayOfWeek(temporal);
+            int dom = temporal.get(DAY_OF_MONTH);
+            int offset = startOfWeekOffset(dom, dow);
+            return computeWeek(offset, dom);
+        }
+
+        private long localizedWeekOfYear(TemporalAccessor temporal) {
+            int dow = localizedDayOfWeek(temporal);
+            int doy = temporal.get(DAY_OF_YEAR);
+            int offset = startOfWeekOffset(doy, dow);
+            return computeWeek(offset, doy);
+        }
+
+        /**
+         * Returns the year of week-based-year for the temporal.
+         * The year can be the previous year, the current year, or the next year.
+         * @param temporal a date of any chronology, not null
+         * @return the year of week-based-year for the date
+         */
+        private int localizedWeekBasedYear(TemporalAccessor temporal) {
+            int dow = localizedDayOfWeek(temporal);
+            int year = temporal.get(YEAR);
+            int doy = temporal.get(DAY_OF_YEAR);
+            int offset = startOfWeekOffset(doy, dow);
+            int week = computeWeek(offset, doy);
+            if (week == 0) {
+                // Day is in end of week of previous year; return the previous year
+                return year - 1;
+            } else {
+                // If getting close to end of year, use higher precision logic
+                // Check if date of year is in partial week associated with next year
+                ValueRange dayRange = temporal.range(DAY_OF_YEAR);
+                int yearLen = (int)dayRange.getMaximum();
+                int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
+                if (week >= newYearWeek) {
+                    return year + 1;
+                }
+            }
+            return year;
+        }
+
+        /**
+         * Returns the week of week-based-year for the temporal.
+         * The week can be part of the previous year, the current year,
+         * or the next year depending on the week start and minimum number
+         * of days.
+         * @param temporal  a date of any chronology
+         * @return the week of the year
+         * @see #localizedWeekBasedYear(java.time.temporal.TemporalAccessor)
+         */
+        private int localizedWeekOfWeekBasedYear(TemporalAccessor temporal) {
+            int dow = localizedDayOfWeek(temporal);
+            int doy = temporal.get(DAY_OF_YEAR);
+            int offset = startOfWeekOffset(doy, dow);
+            int week = computeWeek(offset, doy);
+            if (week == 0) {
+                // Day is in end of week of previous year
+                // Recompute from the last day of the previous year
+                ChronoLocalDate date = Chronology.from(temporal).date(temporal);
+                date = date.minus(doy, DAYS);   // Back down into previous year
+                return localizedWeekOfWeekBasedYear(date);
+            } else if (week > 50) {
+                // If getting close to end of year, use higher precision logic
+                // Check if date of year is in partial week associated with next year
+                ValueRange dayRange = temporal.range(DAY_OF_YEAR);
+                int yearLen = (int)dayRange.getMaximum();
+                int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
+                if (week >= newYearWeek) {
+                    // Overlaps with week of following year; reduce to week in following year
+                    week = week - newYearWeek + 1;
+                }
+            }
+            return week;
+        }
+
+        /**
+         * Returns an offset to align week start with a day of month or day of year.
+         *
+         * @param day  the day; 1 through infinity
+         * @param dow  the day of the week of that day; 1 through 7
+         * @return  an offset in days to align a day with the start of the first 'full' week
+         */
+        private int startOfWeekOffset(int day, int dow) {
+            // offset of first day corresponding to the day of week in first 7 days (zero origin)
+            int weekStart = Math.floorMod(day - dow, 7);
+            int offset = -weekStart;
+            if (weekStart + 1 > weekDef.getMinimalDaysInFirstWeek()) {
+                // The previous week has the minimum days in the current month to be a 'week'
+                offset = 7 - weekStart;
+            }
+            return offset;
+        }
+
+        /**
+         * Returns the week number computed from the reference day and reference dayOfWeek.
+         *
+         * @param offset the offset to align a date with the start of week
+         *     from {@link #startOfWeekOffset}.
+         * @param day  the day for which to compute the week number
+         * @return the week number where zero is used for a partial week and 1 for the first full week
+         */
+        private int computeWeek(int offset, int day) {
+            return ((7 + offset + (day - 1)) / 7);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public <R extends Temporal> R adjustInto(R temporal, long newValue) {
+            // Check the new value and get the old value of the field
+            int newVal = range.checkValidIntValue(newValue, this);  // lenient check range
+            int currentVal = temporal.get(this);
+            if (newVal == currentVal) {
+                return temporal;
+            }
+
+            if (rangeUnit == FOREVER) {     // replace year of WeekBasedYear
+                // Create a new date object with the same chronology,
+                // the desired year and the same week and dow.
+                int idow = temporal.get(weekDef.dayOfWeek);
+                int wowby = temporal.get(weekDef.weekOfWeekBasedYear);
+                return (R) ofWeekBasedYear(Chronology.from(temporal), (int)newValue, wowby, idow);
+            } else {
+                // Compute the difference and add that using the base unit of the field
+                return (R) temporal.plus(newVal - currentVal, baseUnit);
+            }
+        }
+
+        @Override
+        public ChronoLocalDate resolve(
+                Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
+            final long value = fieldValues.get(this);
+            final int newValue = Math.toIntExact(value);  // broad limit makes overflow checking lighter
+            // first convert localized day-of-week to ISO day-of-week
+            // doing this first handles case where both ISO and localized were parsed and might mismatch
+            // day-of-week is always strict as two different day-of-week values makes lenient complex
+            if (rangeUnit == WEEKS) {  // day-of-week
+                final int checkedValue = range.checkValidIntValue(value, this);  // no leniency as too complex
+                final int startDow = weekDef.getFirstDayOfWeek().getValue();
+                long isoDow = Math.floorMod((startDow - 1) + (checkedValue - 1), 7) + 1;
+                fieldValues.remove(this);
+                fieldValues.put(DAY_OF_WEEK, isoDow);
+                return null;
+            }
+
+            // can only build date if ISO day-of-week is present
+            if (fieldValues.containsKey(DAY_OF_WEEK) == false) {
+                return null;
+            }
+            int isoDow = DAY_OF_WEEK.checkValidIntValue(fieldValues.get(DAY_OF_WEEK));
+            int dow = localizedDayOfWeek(isoDow);
+
+            // build date
+            Chronology chrono = Chronology.from(partialTemporal);
+            if (fieldValues.containsKey(YEAR)) {
+                int year = YEAR.checkValidIntValue(fieldValues.get(YEAR));  // validate
+                if (rangeUnit == MONTHS && fieldValues.containsKey(MONTH_OF_YEAR)) {  // week-of-month
+                    long month = fieldValues.get(MONTH_OF_YEAR);  // not validated yet
+                    return resolveWoM(fieldValues, chrono, year, month, newValue, dow, resolverStyle);
+                }
+                if (rangeUnit == YEARS) {  // week-of-year
+                    return resolveWoY(fieldValues, chrono, year, newValue, dow, resolverStyle);
+                }
+            } else if ((rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) &&
+                    fieldValues.containsKey(weekDef.weekBasedYear) &&
+                    fieldValues.containsKey(weekDef.weekOfWeekBasedYear)) { // week-of-week-based-year and year-of-week-based-year
+                return resolveWBY(fieldValues, chrono, dow, resolverStyle);
+            }
+            return null;
+        }
+
+        private ChronoLocalDate resolveWoM(
+                Map<TemporalField, Long> fieldValues, Chronology chrono, int year, long month, long wom, int localDow, ResolverStyle resolverStyle) {
+            ChronoLocalDate date;
+            if (resolverStyle == ResolverStyle.LENIENT) {
+                date = chrono.date(year, 1, 1).plus(Math.subtractExact(month, 1), MONTHS);
+                long weeks = Math.subtractExact(wom, localizedWeekOfMonth(date));
+                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
+                date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS);
+            } else {
+                int monthValid = MONTH_OF_YEAR.checkValidIntValue(month);  // validate
+                date = chrono.date(year, monthValid, 1);
+                int womInt = range.checkValidIntValue(wom, this);  // validate
+                int weeks = (int) (womInt - localizedWeekOfMonth(date));  // safe from overflow
+                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
+                date = date.plus(weeks * 7 + days, DAYS);
+                if (resolverStyle == ResolverStyle.STRICT && date.getLong(MONTH_OF_YEAR) != month) {
+                    throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
+                }
+            }
+            fieldValues.remove(this);
+            fieldValues.remove(YEAR);
+            fieldValues.remove(MONTH_OF_YEAR);
+            fieldValues.remove(DAY_OF_WEEK);
+            return date;
+        }
+
+        private ChronoLocalDate resolveWoY(
+                Map<TemporalField, Long> fieldValues, Chronology chrono, int year, long woy, int localDow, ResolverStyle resolverStyle) {
+            ChronoLocalDate date = chrono.date(year, 1, 1);
+            if (resolverStyle == ResolverStyle.LENIENT) {
+                long weeks = Math.subtractExact(woy, localizedWeekOfYear(date));
+                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
+                date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS);
+            } else {
+                int womInt = range.checkValidIntValue(woy, this);  // validate
+                int weeks = (int) (womInt - localizedWeekOfYear(date));  // safe from overflow
+                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
+                date = date.plus(weeks * 7 + days, DAYS);
+                if (resolverStyle == ResolverStyle.STRICT && date.getLong(YEAR) != year) {
+                    throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
+                }
+            }
+            fieldValues.remove(this);
+            fieldValues.remove(YEAR);
+            fieldValues.remove(DAY_OF_WEEK);
+            return date;
+        }
+
+        private ChronoLocalDate resolveWBY(
+                Map<TemporalField, Long> fieldValues, Chronology chrono, int localDow, ResolverStyle resolverStyle) {
+            int yowby = weekDef.weekBasedYear.range().checkValidIntValue(
+                    fieldValues.get(weekDef.weekBasedYear), weekDef.weekBasedYear);
+            ChronoLocalDate date;
+            if (resolverStyle == ResolverStyle.LENIENT) {
+                date = ofWeekBasedYear(chrono, yowby, 1, localDow);
+                long wowby = fieldValues.get(weekDef.weekOfWeekBasedYear);
+                long weeks = Math.subtractExact(wowby, 1);
+                date = date.plus(weeks, WEEKS);
+            } else {
+                int wowby = weekDef.weekOfWeekBasedYear.range().checkValidIntValue(
+                        fieldValues.get(weekDef.weekOfWeekBasedYear), weekDef.weekOfWeekBasedYear);  // validate
+                date = ofWeekBasedYear(chrono, yowby, wowby, localDow);
+                if (resolverStyle == ResolverStyle.STRICT && localizedWeekBasedYear(date) != yowby) {
+                    throw new DateTimeException("Strict mode rejected resolved date as it is in a different week-based-year");
+                }
+            }
+            fieldValues.remove(this);
+            fieldValues.remove(weekDef.weekBasedYear);
+            fieldValues.remove(weekDef.weekOfWeekBasedYear);
+            fieldValues.remove(DAY_OF_WEEK);
+            return date;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String getDisplayName(Locale locale) {
+            Objects.requireNonNull(locale, "locale");
+            if (rangeUnit == YEARS) {  // only have values for week-of-year
+                // Android-changed: Use ICU name values.
+                DateTimePatternGenerator dateTimePatternGenerator = DateTimePatternGenerator
+                        .getFrozenInstance(ULocale.forLocale(locale));
+                String icuName = dateTimePatternGenerator
+                        .getAppendItemName(DateTimePatternGenerator.WEEK_OF_YEAR);
+                return icuName != null && !icuName.isEmpty() ? icuName : name;
+            }
+            return name;
+        }
+
+        @Override
+        public TemporalUnit getBaseUnit() {
+            return baseUnit;
+        }
+
+        @Override
+        public TemporalUnit getRangeUnit() {
+            return rangeUnit;
+        }
+
+        @Override
+        public boolean isDateBased() {
+            return true;
+        }
+
+        @Override
+        public boolean isTimeBased() {
+            return false;
+        }
+
+        @Override
+        public ValueRange range() {
+            return range;
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public boolean isSupportedBy(TemporalAccessor temporal) {
+            if (temporal.isSupported(DAY_OF_WEEK)) {
+                if (rangeUnit == WEEKS) {  // day-of-week
+                    return true;
+                } else if (rangeUnit == MONTHS) {  // week-of-month
+                    return temporal.isSupported(DAY_OF_MONTH);
+                } else if (rangeUnit == YEARS) {  // week-of-year
+                    return temporal.isSupported(DAY_OF_YEAR);
+                } else if (rangeUnit == WEEK_BASED_YEARS) {
+                    return temporal.isSupported(DAY_OF_YEAR);
+                } else if (rangeUnit == FOREVER) {
+                    return temporal.isSupported(YEAR);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
+            if (rangeUnit == ChronoUnit.WEEKS) {  // day-of-week
+                return range;
+            } else if (rangeUnit == MONTHS) {  // week-of-month
+                return rangeByWeek(temporal, DAY_OF_MONTH);
+            } else if (rangeUnit == YEARS) {  // week-of-year
+                return rangeByWeek(temporal, DAY_OF_YEAR);
+            } else if (rangeUnit == WEEK_BASED_YEARS) {
+                return rangeWeekOfWeekBasedYear(temporal);
+            } else if (rangeUnit == FOREVER) {
+                return YEAR.range();
+            } else {
+                throw new IllegalStateException("unreachable, rangeUnit: " + rangeUnit + ", this: " + this);
+            }
+        }
+
+        /**
+         * Map the field range to a week range
+         * @param temporal the temporal
+         * @param field the field to get the range of
+         * @return the ValueRange with the range adjusted to weeks.
+         */
+        private ValueRange rangeByWeek(TemporalAccessor temporal, TemporalField field) {
+            int dow = localizedDayOfWeek(temporal);
+            int offset = startOfWeekOffset(temporal.get(field), dow);
+            ValueRange fieldRange = temporal.range(field);
+            return ValueRange.of(computeWeek(offset, (int) fieldRange.getMinimum()),
+                    computeWeek(offset, (int) fieldRange.getMaximum()));
+        }
+
+        /**
+         * Map the field range to a week range of a week year.
+         * @param temporal  the temporal
+         * @return the ValueRange with the range adjusted to weeks.
+         */
+        private ValueRange rangeWeekOfWeekBasedYear(TemporalAccessor temporal) {
+            if (!temporal.isSupported(DAY_OF_YEAR)) {
+                return WEEK_OF_YEAR_RANGE;
+            }
+            int dow = localizedDayOfWeek(temporal);
+            int doy = temporal.get(DAY_OF_YEAR);
+            int offset = startOfWeekOffset(doy, dow);
+            int week = computeWeek(offset, doy);
+            if (week == 0) {
+                // Day is in end of week of previous year
+                // Recompute from the last day of the previous year
+                ChronoLocalDate date = Chronology.from(temporal).date(temporal);
+                date = date.minus(doy + 7, DAYS);   // Back down into previous year
+                return rangeWeekOfWeekBasedYear(date);
+            }
+            // Check if day of year is in partial week associated with next year
+            ValueRange dayRange = temporal.range(DAY_OF_YEAR);
+            int yearLen = (int)dayRange.getMaximum();
+            int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
+
+            if (week >= newYearWeek) {
+                // Overlaps with weeks of following year; recompute from a week in following year
+                ChronoLocalDate date = Chronology.from(temporal).date(temporal);
+                date = date.plus(yearLen - doy + 1 + 7, ChronoUnit.DAYS);
+                return rangeWeekOfWeekBasedYear(date);
+            }
+            return ValueRange.of(1, newYearWeek-1);
+        }
+
+        //-----------------------------------------------------------------------
+        @Override
+        public String toString() {
+            return name + "[" + weekDef.toString() + "]";
+        }
+    }
+}
diff --git a/java/time/temporal/package-info.java b/java/time/temporal/package-info.java
new file mode 100644
index 0000000..d3e9c05
--- /dev/null
+++ b/java/time/temporal/package-info.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * Access to date and time using fields and units, and date time adjusters.
+ * </p>
+ * <p>
+ * This package expands on the base package to provide additional functionality for
+ * more powerful use cases. Support is included for:
+ * </p>
+ * <ul>
+ * <li>Units of date-time, such as years, months, days and hours</li>
+ * <li>Fields of date-time, such as month-of-year, day-of-week or hour-of-day</li>
+ * <li>Date-time adjustment functions</li>
+ * <li>Different definitions of weeks</li>
+ * </ul>
+ *
+ * <h3>Fields and Units</h3>
+ * <p>
+ * Dates and times are expressed in terms of fields and units.
+ * A unit is used to measure an amount of time, such as years, days or minutes.
+ * All units implement {@link java.time.temporal.TemporalUnit}.
+ * The set of well known units is defined in {@link java.time.temporal.ChronoUnit}, such as {@code DAYS}.
+ * The unit interface is designed to allow application defined units.
+ * </p>
+ * <p>
+ * A field is used to express part of a larger date-time, such as year, month-of-year or second-of-minute.
+ * All fields implement {@link java.time.temporal.TemporalField}.
+ * The set of well known fields are defined in {@link java.time.temporal.ChronoField}, such as {@code HOUR_OF_DAY}.
+ * Additional fields are defined by {@link java.time.temporal.JulianFields}, {@link java.time.temporal.WeekFields}
+ * and {@link java.time.temporal.IsoFields}.
+ * The field interface is designed to allow application defined fields.
+ * </p>
+ * <p>
+ * This package provides tools that allow the units and fields of date and time to be accessed
+ * in a general way most suited for frameworks.
+ * {@link java.time.temporal.Temporal} provides the abstraction for date time types that support fields.
+ * Its methods support getting the value of a field, creating a new date time with the value of
+ * a field modified, and querying for additional information, typically used to extract the offset or time-zone.
+ * </p>
+ * <p>
+ * One use of fields in application code is to retrieve fields for which there is no convenience method.
+ * For example, getting the day-of-month is common enough that there is a method on {@code LocalDate}
+ * called {@code getDayOfMonth()}. However for more unusual fields it is necessary to use the field.
+ * For example, {@code date.get(ChronoField.ALIGNED_WEEK_OF_MONTH)}.
+ * The fields also provide access to the range of valid values.
+ * </p>
+ *
+ * <h3>Adjustment and Query</h3>
+ * <p>
+ * A key part of the date-time problem space is adjusting a date to a new, related value,
+ * such as the "last day of the month", or "next Wednesday".
+ * These are modeled as functions that adjust a base date-time.
+ * The functions implement {@link java.time.temporal.TemporalAdjuster} and operate on {@code Temporal}.
+ * A set of common functions are provided in {@link java.time.temporal.TemporalAdjusters}.
+ * For example, to find the first occurrence of a day-of-week after a given date, use
+ * {@link java.time.temporal.TemporalAdjusters#next(DayOfWeek)}, such as
+ * {@code date.with(next(MONDAY))}.
+ * Applications can also define adjusters by implementing {@link java.time.temporal.TemporalAdjuster}.
+ * </p>
+ * <p>
+ * The {@link java.time.temporal.TemporalAmount} interface models amounts of relative time.
+ * </p>
+ * <p>
+ * In addition to adjusting a date-time, an interface is provided to enable querying via
+ * {@link java.time.temporal.TemporalQuery}.
+ * The most common implementations of the query interface are method references.
+ * The {@code from(TemporalAccessor)} methods on major classes can all be used, such as
+ * {@code LocalDate::from} or {@code Month::from}.
+ * Further implementations are provided in {@link java.time.temporal.TemporalQueries} as static methods.
+ * Applications can also define queries by implementing {@link java.time.temporal.TemporalQuery}.
+ * </p>
+ *
+ * <h3>Weeks</h3>
+ * <p>
+ * Different locales have different definitions of the week.
+ * For example, in Europe the week typically starts on a Monday, while in the US it starts on a Sunday.
+ * The {@link java.time.temporal.WeekFields} class models this distinction.
+ * </p>
+ * <p>
+ * The ISO calendar system defines an additional week-based division of years.
+ * This defines a year based on whole Monday to Monday weeks.
+ * This is modeled in {@link java.time.temporal.IsoFields}.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
+ * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ * The Javadoc "@param" definition is used to summarise the null-behavior.
+ * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.temporal;
diff --git a/java/time/zone/IcuZoneRulesProvider.java b/java/time/zone/IcuZoneRulesProvider.java
new file mode 100644
index 0000000..5a4e37d
--- /dev/null
+++ b/java/time/zone/IcuZoneRulesProvider.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  The Android Open Source
+ * Project designates this particular file as subject to the "Classpath"
+ * exception as provided by The Android Open Source Project in the LICENSE
+ * file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package java.time.zone;
+
+import android.icu.util.AnnualTimeZoneRule;
+import android.icu.util.BasicTimeZone;
+import android.icu.util.DateTimeRule;
+import android.icu.util.InitialTimeZoneRule;
+import android.icu.util.TimeZone;
+import android.icu.util.TimeZoneRule;
+import android.icu.util.TimeZoneTransition;
+import java.time.DayOfWeek;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import libcore.util.BasicLruCache;
+
+/**
+ * A ZoneRulesProvider that generates rules from ICU4J TimeZones.
+ * This provider ensures that classes in {@link java.time} use the same time zone information
+ * as ICU4J.
+ */
+public class IcuZoneRulesProvider extends ZoneRulesProvider {
+
+    // Arbitrary upper limit to number of transitions including the final rules.
+    private static final int MAX_TRANSITIONS = 10000;
+
+    private static final int SECONDS_IN_DAY = 24 * 60 * 60;
+
+    private final BasicLruCache<String, ZoneRules> cache = new ZoneRulesCache(8);
+
+    @Override
+    protected Set<String> provideZoneIds() {
+        Set<String> zoneIds = TimeZone.getAvailableIDs(TimeZone.SystemTimeZoneType.ANY, null, null);
+        zoneIds = new HashSet<>(zoneIds);
+        // java.time assumes ZoneId that start with "GMT" fit the pattern "GMT+HH:mm:ss" which these
+        // do not. Since they are equivalent to GMT, just remove these aliases.
+        zoneIds.remove("GMT+0");
+        zoneIds.remove("GMT-0");
+        return zoneIds;
+    }
+
+    @Override
+    protected ZoneRules provideRules(String zoneId, boolean forCaching) {
+        // Ignore forCaching, as this is a static provider.
+        return cache.get(zoneId);
+    }
+
+    @Override
+    protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
+        return new TreeMap<>(
+                Collections.singletonMap(TimeZone.getTZDataVersion(),
+                        provideRules(zoneId, /* forCaching */ false)));
+    }
+
+    /*
+     * This implementation is only tested with BasicTimeZone objects and depends on
+     * implementation details of that class:
+     *
+     * 0. TimeZone.getFrozenTimeZone() always returns a BasicTimeZone object.
+     * 1. The first rule is always an InitialTimeZoneRule (guaranteed by spec).
+     * 2. AnnualTimeZoneRules are only used as "final rules".
+     * 3. The final rules are either 0 or 2 AnnualTimeZoneRules
+     * 4. The final rules have endYear set to MAX_YEAR.
+     * 5. Each transition generated by the rules changes either the raw offset, the total offset
+     *    or both.
+     * 6. There is a non-immense number of transitions for any rule before the final rules apply
+     *    (enforced via the arbitrary limit defined in MAX_TRANSITIONS).
+     *
+     * Assumptions #5 and #6 are not strictly required for this code to work, but hold for the
+     * the data and code at the time of implementation. If they were broken they would indicate
+     * an incomplete understanding of how ICU TimeZoneRules are used which would probably mean that
+     * this code needs to be updated.
+     *
+     * These assumptions are verified using the verify() method where appropriate.
+     */
+    static ZoneRules generateZoneRules(String zoneId) {
+        TimeZone timeZone = TimeZone.getFrozenTimeZone(zoneId);
+        // Assumption #0
+        verify(timeZone instanceof BasicTimeZone, zoneId,
+                "Unexpected time zone class " + timeZone.getClass());
+        BasicTimeZone tz = (BasicTimeZone) timeZone;
+        TimeZoneRule[] rules = tz.getTimeZoneRules();
+        // Assumption #1
+        InitialTimeZoneRule initial = (InitialTimeZoneRule) rules[0];
+
+        ZoneOffset baseStandardOffset = millisToOffset(initial.getRawOffset());
+        ZoneOffset baseWallOffset =
+                millisToOffset((initial.getRawOffset() + initial.getDSTSavings()));
+
+        List<ZoneOffsetTransition> standardOffsetTransitionList = new ArrayList<>();
+        List<ZoneOffsetTransition> transitionList = new ArrayList<>();
+        List<ZoneOffsetTransitionRule> lastRules = new ArrayList<>();
+
+        int preLastDstSavings = 0;
+        AnnualTimeZoneRule last1 = null;
+        AnnualTimeZoneRule last2 = null;
+
+        TimeZoneTransition transition = tz.getNextTransition(Long.MIN_VALUE, false);
+        int transitionCount = 1;
+        // This loop has two possible exit conditions (in normal operation):
+        // 1. for zones that end with a static value and have no ongoing DST changes, it will exit
+        //    via the normal condition (transition != null)
+        // 2. for zones with ongoing DST changes (represented by a "final zone" in ICU4J, and by
+        //    "last rules" in java.time) the "break transitionLoop" will be used to exit the loop.
+        transitionLoop:
+        while (transition != null) {
+            TimeZoneRule from = transition.getFrom();
+            TimeZoneRule to = transition.getTo();
+            boolean hadEffect = false;
+            if (from.getRawOffset() != to.getRawOffset()) {
+                standardOffsetTransitionList.add(new ZoneOffsetTransition(
+                        TimeUnit.MILLISECONDS.toSeconds(transition.getTime()),
+                        millisToOffset(from.getRawOffset()),
+                        millisToOffset(to.getRawOffset())));
+                hadEffect = true;
+            }
+            int fromTotalOffset = from.getRawOffset() + from.getDSTSavings();
+            int toTotalOffset = to.getRawOffset() + to.getDSTSavings();
+            if (fromTotalOffset != toTotalOffset) {
+                transitionList.add(new ZoneOffsetTransition(
+                        TimeUnit.MILLISECONDS.toSeconds(transition.getTime()),
+                        millisToOffset(fromTotalOffset),
+                        millisToOffset(toTotalOffset)));
+                hadEffect = true;
+            }
+            // Assumption #5
+            verify(hadEffect, zoneId, "Transition changed neither total nor raw offset.");
+            if (to instanceof AnnualTimeZoneRule) {
+                // The presence of an AnnualTimeZoneRule is taken as an indication of a final rule.
+                if (last1 == null) {
+                    preLastDstSavings = from.getDSTSavings();
+                    last1 = (AnnualTimeZoneRule) to;
+                    // Assumption #4
+                    verify(last1.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId,
+                            "AnnualTimeZoneRule is not permanent.");
+                } else {
+                    last2 = (AnnualTimeZoneRule) to;
+                    // Assumption #4
+                    verify(last2.getEndYear() == AnnualTimeZoneRule.MAX_YEAR, zoneId,
+                            "AnnualTimeZoneRule is not permanent.");
+
+                    // Assumption #3
+                    transition = tz.getNextTransition(transition.getTime(), false);
+                    verify(transition.getTo() == last1, zoneId,
+                            "Unexpected rule after 2 AnnualTimeZoneRules.");
+                    break transitionLoop;
+                }
+            } else {
+                // Assumption #2
+                verify(last1 == null, zoneId, "Unexpected rule after AnnualTimeZoneRule.");
+            }
+            verify(transitionCount <= MAX_TRANSITIONS, zoneId,
+                    "More than " + MAX_TRANSITIONS + " transitions.");
+            transition = tz.getNextTransition(transition.getTime(), false);
+            transitionCount++;
+        }
+        if (last1 != null) {
+            // Assumption #3
+            verify(last2 != null, zoneId, "Only one AnnualTimeZoneRule.");
+            lastRules.add(toZoneOffsetTransitionRule(last1, preLastDstSavings));
+            lastRules.add(toZoneOffsetTransitionRule(last2, last1.getDSTSavings()));
+        }
+
+        return ZoneRules.of(baseStandardOffset, baseWallOffset, standardOffsetTransitionList,
+                transitionList, lastRules);
+    }
+
+    /**
+     * Verify an assumption about the zone rules.
+     *
+     * @param check
+     *         {@code true} if the assumption holds, {@code false} otherwise.
+     * @param zoneId
+     *         Zone ID for which to check.
+     * @param message
+     *         Error description of a failed check.
+     * @throws ZoneRulesException
+     *         If and only if {@code check} is {@code false}.
+     */
+    private static void verify(boolean check, String zoneId, String message) {
+        if (!check) {
+            throw new ZoneRulesException(
+                    String.format("Failed verification of zone %s: %s", zoneId, message));
+        }
+    }
+
+    /**
+     * Transform an {@link AnnualTimeZoneRule} into an equivalent {@link ZoneOffsetTransitionRule}.
+     * This is only used for the "final rules".
+     *
+     * @param rule
+     *         The rule to transform.
+     * @param dstSavingMillisBefore
+     *         The DST offset before the first transition in milliseconds.
+     */
+    private static ZoneOffsetTransitionRule toZoneOffsetTransitionRule(
+            AnnualTimeZoneRule rule, int dstSavingMillisBefore) {
+        DateTimeRule dateTimeRule = rule.getRule();
+        // Calendar.JANUARY is 0, transform it into a proper Month.
+        Month month = Month.JANUARY.plus(dateTimeRule.getRuleMonth());
+        int dayOfMonthIndicator;
+        // Calendar.SUNDAY is 1, transform it into a proper DayOfWeek.
+        DayOfWeek dayOfWeek = DayOfWeek.SATURDAY.plus(dateTimeRule.getRuleDayOfWeek());
+        switch (dateTimeRule.getDateRuleType()) {
+            case DateTimeRule.DOM:
+                // Transition always on a specific day of the month.
+                dayOfMonthIndicator = dateTimeRule.getRuleDayOfMonth();
+                dayOfWeek = null;
+                break;
+            case DateTimeRule.DOW_GEQ_DOM:
+                // ICU representation matches java.time representation.
+                dayOfMonthIndicator = dateTimeRule.getRuleDayOfMonth();
+                break;
+            case DateTimeRule.DOW_LEQ_DOM:
+                // java.time uses a negative dayOfMonthIndicator to represent "Sun<=X" or "lastSun"
+                // rules. ICU uses this constant and the normal day. So "lastSun" in January would
+                // ruleDayOfMonth = 31 in ICU and dayOfMonthIndicator = -1 in java.time.
+                dayOfMonthIndicator = -month.maxLength() + dateTimeRule.getRuleDayOfMonth() - 1;
+                break;
+            case DateTimeRule.DOW:
+                // DOW is unspecified in the documentation and seems to never be used.
+                throw new ZoneRulesException("Date rule type DOW is unsupported");
+            default:
+                throw new ZoneRulesException(
+                        "Unexpected date rule type: " + dateTimeRule.getDateRuleType());
+        }
+        // Cast to int is save, as input is int.
+        int secondOfDay = (int) TimeUnit.MILLISECONDS.toSeconds(dateTimeRule.getRuleMillisInDay());
+        LocalTime time;
+        boolean timeEndOfDay;
+        if (secondOfDay == SECONDS_IN_DAY) {
+            time = LocalTime.MIDNIGHT;
+            timeEndOfDay = true;
+        } else {
+            time = LocalTime.ofSecondOfDay(secondOfDay);
+            timeEndOfDay = false;
+        }
+        ZoneOffsetTransitionRule.TimeDefinition timeDefinition;
+        switch (dateTimeRule.getTimeRuleType()) {
+            case DateTimeRule.WALL_TIME:
+                timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.WALL;
+                break;
+            case DateTimeRule.STANDARD_TIME:
+                timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.STANDARD;
+                break;
+            case DateTimeRule.UTC_TIME:
+                timeDefinition = ZoneOffsetTransitionRule.TimeDefinition.UTC;
+                break;
+            default:
+                throw new ZoneRulesException(
+                        "Unexpected time rule type " + dateTimeRule.getTimeRuleType());
+        }
+        ZoneOffset standardOffset = millisToOffset(rule.getRawOffset());
+        ZoneOffset offsetBefore = millisToOffset(rule.getRawOffset() + dstSavingMillisBefore);
+        ZoneOffset offsetAfter = millisToOffset(
+                rule.getRawOffset() + rule.getDSTSavings());
+        return ZoneOffsetTransitionRule.of(
+                month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefinition,
+                standardOffset, offsetBefore, offsetAfter);
+    }
+
+    private static ZoneOffset millisToOffset(int offset) {
+        // Cast to int is save, as input is int.
+        return ZoneOffset.ofTotalSeconds((int) TimeUnit.MILLISECONDS.toSeconds(offset));
+    }
+
+    private static class ZoneRulesCache extends BasicLruCache<String, ZoneRules> {
+
+        ZoneRulesCache(int maxSize) {
+            super(maxSize);
+        }
+
+        @Override
+        protected ZoneRules create(String zoneId) {
+            String canonicalId = TimeZone.getCanonicalID(zoneId);
+            if (!canonicalId.equals(zoneId)) {
+                // Return the same object as the canonical one, to avoid wasting space, but cache
+                // it under the non-cannonical name as well, to avoid future getCanonicalID calls.
+                return get(canonicalId);
+            }
+            return generateZoneRules(zoneId);
+        }
+    }
+}
diff --git a/java/time/zone/Ser.java b/java/time/zone/Ser.java
new file mode 100644
index 0000000..31c2f2d
--- /dev/null
+++ b/java/time/zone/Ser.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.StreamCorruptedException;
+import java.time.ZoneOffset;
+
+/**
+ * The shared serialization delegate for this package.
+ *
+ * @implNote
+ * This class is mutable and should be created once per serialization.
+ *
+ * @serial include
+ * @since 1.8
+ */
+final class Ser implements Externalizable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -8885321777449118786L;
+
+    /** Type for ZoneRules. */
+    static final byte ZRULES = 1;
+    /** Type for ZoneOffsetTransition. */
+    static final byte ZOT = 2;
+    /** Type for ZoneOffsetTransition. */
+    static final byte ZOTRULE = 3;
+
+    /** The type being serialized. */
+    private byte type;
+    /** The object being serialized. */
+    private Object object;
+
+    /**
+     * Constructor for deserialization.
+     */
+    public Ser() {
+    }
+
+    /**
+     * Creates an instance for serialization.
+     *
+     * @param type  the type
+     * @param object  the object
+     */
+    Ser(byte type, Object object) {
+        this.type = type;
+        this.object = object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to write the object.
+     * @serialData
+     * Each serializable class is mapped to a type that is the first byte
+     * in the stream.  Refer to each class {@code writeReplace}
+     * serialized form for the value of the type and sequence of values for the type.
+     *
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransition">ZoneOffsetTransition.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransitionRule">ZoneOffsetTransitionRule.writeReplace</a>
+     * </ul>
+     *
+     * @param out  the data stream to write to, not null
+     */
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        writeInternal(type, object, out);
+    }
+
+    static void write(Object object, DataOutput out) throws IOException {
+        writeInternal(ZRULES, object, out);
+    }
+
+    private static void writeInternal(byte type, Object object, DataOutput out) throws IOException {
+        out.writeByte(type);
+        switch (type) {
+            case ZRULES:
+                ((ZoneRules) object).writeExternal(out);
+                break;
+            case ZOT:
+                ((ZoneOffsetTransition) object).writeExternal(out);
+                break;
+            case ZOTRULE:
+                ((ZoneOffsetTransitionRule) object).writeExternal(out);
+                break;
+            default:
+                throw new InvalidClassException("Unknown serialized type");
+        }
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Implements the {@code Externalizable} interface to read the object.
+     * @serialData
+     * The streamed type and parameters defined by the type's {@code writeReplace}
+     * method are read and passed to the corresponding static factory for the type
+     * to create a new instance.  That instance is returned as the de-serialized
+     * {@code Ser} object.
+     *
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules</a>
+     * - {@code ZoneRules.of(standardTransitions, standardOffsets, savingsInstantTransitions, wallOffsets, lastRules);}
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransition">ZoneOffsetTransition</a>
+     * - {@code ZoneOffsetTransition of(LocalDateTime.ofEpochSecond(epochSecond), offsetBefore, offsetAfter);}
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransitionRule">ZoneOffsetTransitionRule</a>
+     * - {@code ZoneOffsetTransitionRule.of(month, dom, dow, time, timeEndOfDay, timeDefinition, standardOffset, offsetBefore, offsetAfter);}
+     * </ul>
+     * @param in  the data to read, not null
+     */
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        type = in.readByte();
+        object = readInternal(type, in);
+    }
+
+    static Object read(DataInput in) throws IOException, ClassNotFoundException {
+        byte type = in.readByte();
+        return readInternal(type, in);
+    }
+
+    private static Object readInternal(byte type, DataInput in) throws IOException, ClassNotFoundException {
+        switch (type) {
+            case ZRULES:
+                return ZoneRules.readExternal(in);
+            case ZOT:
+                return ZoneOffsetTransition.readExternal(in);
+            case ZOTRULE:
+                return ZoneOffsetTransitionRule.readExternal(in);
+            default:
+                throw new StreamCorruptedException("Unknown serialized type");
+        }
+    }
+
+    /**
+     * Returns the object that will replace this one.
+     *
+     * @return the read object, should never be null
+     */
+    private Object readResolve() {
+         return object;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the state to the stream.
+     *
+     * @param offset  the offset, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
+        final int offsetSecs = offset.getTotalSeconds();
+        int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+        out.writeByte(offsetByte);
+        if (offsetByte == 127) {
+            out.writeInt(offsetSecs);
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneOffset readOffset(DataInput in) throws IOException {
+        int offsetByte = in.readByte();
+        return (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the state to the stream.
+     *
+     * @param epochSec  the epoch seconds, not null
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
+        if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) {  // quarter hours between 1825 and 2300
+            int store = (int) ((epochSec + 4575744000L) / 900);
+            out.writeByte((store >>> 16) & 255);
+            out.writeByte((store >>> 8) & 255);
+            out.writeByte(store & 255);
+        } else {
+            out.writeByte(255);
+            out.writeLong(epochSec);
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the epoch seconds, not null
+     * @throws IOException if an error occurs
+     */
+    static long readEpochSec(DataInput in) throws IOException {
+        int hiByte = in.readByte() & 255;
+        if (hiByte == 255) {
+            return in.readLong();
+        } else {
+            int midByte = in.readByte() & 255;
+            int loByte = in.readByte() & 255;
+            long tot = ((hiByte << 16) + (midByte << 8) + loByte);
+            return (tot * 900) - 4575744000L;
+        }
+    }
+
+}
diff --git a/java/time/zone/ZoneOffsetTransition.java b/java/time/zone/ZoneOffsetTransition.java
new file mode 100644
index 0000000..bc9cafe
--- /dev/null
+++ b/java/time/zone/ZoneOffsetTransition.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A transition between two offsets caused by a discontinuity in the local time-line.
+ * <p>
+ * A transition between two offsets is normally the result of a daylight savings cutover.
+ * The discontinuity is normally a gap in spring and an overlap in autumn.
+ * {@code ZoneOffsetTransition} models the transition between the two offsets.
+ * <p>
+ * Gaps occur where there are local date-times that simply do not exist.
+ * An example would be when the offset changes from {@code +03:00} to {@code +04:00}.
+ * This might be described as 'the clocks will move forward one hour tonight at 1am'.
+ * <p>
+ * Overlaps occur where there are local date-times that exist twice.
+ * An example would be when the offset changes from {@code +04:00} to {@code +03:00}.
+ * This might be described as 'the clocks will move back one hour tonight at 2am'.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffsetTransition
+        implements Comparable<ZoneOffsetTransition>, Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -6946044323557704546L;
+    /**
+     * The local transition date-time at the transition.
+     */
+    private final LocalDateTime transition;
+    /**
+     * The offset before transition.
+     */
+    private final ZoneOffset offsetBefore;
+    /**
+     * The offset after transition.
+     */
+    private final ZoneOffset offsetAfter;
+
+    //-----------------------------------------------------------------------
+    /**
+     * Obtains an instance defining a transition between two offsets.
+     * <p>
+     * Applications should normally obtain an instance from {@link ZoneRules}.
+     * This factory is only intended for use when creating {@link ZoneRules}.
+     *
+     * @param transition  the transition date-time at the transition, which never
+     *  actually occurs, expressed local to the before offset, not null
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     * @return the transition, not null
+     * @throws IllegalArgumentException if {@code offsetBefore} and {@code offsetAfter}
+     *         are equal, or {@code transition.getNano()} returns non-zero value
+     */
+    public static ZoneOffsetTransition of(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        Objects.requireNonNull(transition, "transition");
+        Objects.requireNonNull(offsetBefore, "offsetBefore");
+        Objects.requireNonNull(offsetAfter, "offsetAfter");
+        if (offsetBefore.equals(offsetAfter)) {
+            throw new IllegalArgumentException("Offsets must not be equal");
+        }
+        if (transition.getNano() != 0) {
+            throw new IllegalArgumentException("Nano-of-second must be zero");
+        }
+        return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
+    }
+
+    /**
+     * Creates an instance defining a transition between two offsets.
+     *
+     * @param transition  the transition date-time with the offset before the transition, not null
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     */
+    ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        this.transition = transition;
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    /**
+     * Creates an instance from epoch-second and offsets.
+     *
+     * @param epochSecond  the transition epoch-second
+     * @param offsetBefore  the offset before the transition, not null
+     * @param offsetAfter  the offset at and after the transition, not null
+     */
+    ZoneOffsetTransition(long epochSecond, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        this.transition = LocalDateTime.ofEpochSecond(epochSecond, 0, offsetBefore);
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+     * @serialData
+     * Refer to the serialized form of
+     * <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+     * for the encoding of epoch seconds and offsets.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *   out.writeByte(2);                // identifies a ZoneOffsetTransition
+     *   out.writeEpochSec(toEpochSecond);
+     *   out.writeOffset(offsetBefore);
+     *   out.writeOffset(offsetAfter);
+     * }
+     * </pre>
+     * @return the replacing object, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZOT, this);
+    }
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        Ser.writeEpochSec(toEpochSecond(), out);
+        Ser.writeOffset(offsetBefore, out);
+        Ser.writeOffset(offsetAfter, out);
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneOffsetTransition readExternal(DataInput in) throws IOException {
+        long epochSecond = Ser.readEpochSec(in);
+        ZoneOffset before = Ser.readOffset(in);
+        ZoneOffset after = Ser.readOffset(in);
+        if (before.equals(after)) {
+            throw new IllegalArgumentException("Offsets must not be equal");
+        }
+        return new ZoneOffsetTransition(epochSecond, before, after);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the transition instant.
+     * <p>
+     * This is the instant of the discontinuity, which is defined as the first
+     * instant that the 'after' offset applies.
+     * <p>
+     * The methods {@link #getInstant()}, {@link #getDateTimeBefore()} and {@link #getDateTimeAfter()}
+     * all represent the same instant.
+     *
+     * @return the transition instant, not null
+     */
+    public Instant getInstant() {
+        return transition.toInstant(offsetBefore);
+    }
+
+    /**
+     * Gets the transition instant as an epoch second.
+     *
+     * @return the transition epoch second
+     */
+    public long toEpochSecond() {
+        return transition.toEpochSecond(offsetBefore);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Gets the local transition date-time, as would be expressed with the 'before' offset.
+     * <p>
+     * This is the date-time where the discontinuity begins expressed with the 'before' offset.
+     * At this instant, the 'after' offset is actually used, therefore the combination of this
+     * date-time and the 'before' offset will never occur.
+     * <p>
+     * The combination of the 'before' date-time and offset represents the same instant
+     * as the 'after' date-time and offset.
+     *
+     * @return the transition date-time expressed with the before offset, not null
+     */
+    public LocalDateTime getDateTimeBefore() {
+        return transition;
+    }
+
+    /**
+     * Gets the local transition date-time, as would be expressed with the 'after' offset.
+     * <p>
+     * This is the first date-time after the discontinuity, when the new offset applies.
+     * <p>
+     * The combination of the 'before' date-time and offset represents the same instant
+     * as the 'after' date-time and offset.
+     *
+     * @return the transition date-time expressed with the after offset, not null
+     */
+    public LocalDateTime getDateTimeAfter() {
+        return transition.plusSeconds(getDurationSeconds());
+    }
+
+    /**
+     * Gets the offset before the transition.
+     * <p>
+     * This is the offset in use before the instant of the transition.
+     *
+     * @return the offset before the transition, not null
+     */
+    public ZoneOffset getOffsetBefore() {
+        return offsetBefore;
+    }
+
+    /**
+     * Gets the offset after the transition.
+     * <p>
+     * This is the offset in use on and after the instant of the transition.
+     *
+     * @return the offset after the transition, not null
+     */
+    public ZoneOffset getOffsetAfter() {
+        return offsetAfter;
+    }
+
+    /**
+     * Gets the duration of the transition.
+     * <p>
+     * In most cases, the transition duration is one hour, however this is not always the case.
+     * The duration will be positive for a gap and negative for an overlap.
+     * Time-zones are second-based, so the nanosecond part of the duration will be zero.
+     *
+     * @return the duration of the transition, positive for gaps, negative for overlaps
+     */
+    public Duration getDuration() {
+        return Duration.ofSeconds(getDurationSeconds());
+    }
+
+    /**
+     * Gets the duration of the transition in seconds.
+     *
+     * @return the duration in seconds
+     */
+    private int getDurationSeconds() {
+        return getOffsetAfter().getTotalSeconds() - getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Does this transition represent a gap in the local time-line.
+     * <p>
+     * Gaps occur where there are local date-times that simply do not exist.
+     * An example would be when the offset changes from {@code +01:00} to {@code +02:00}.
+     * This might be described as 'the clocks will move forward one hour tonight at 1am'.
+     *
+     * @return true if this transition is a gap, false if it is an overlap
+     */
+    public boolean isGap() {
+        return getOffsetAfter().getTotalSeconds() > getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Does this transition represent an overlap in the local time-line.
+     * <p>
+     * Overlaps occur where there are local date-times that exist twice.
+     * An example would be when the offset changes from {@code +02:00} to {@code +01:00}.
+     * This might be described as 'the clocks will move back one hour tonight at 2am'.
+     *
+     * @return true if this transition is an overlap, false if it is a gap
+     */
+    public boolean isOverlap() {
+        return getOffsetAfter().getTotalSeconds() < getOffsetBefore().getTotalSeconds();
+    }
+
+    /**
+     * Checks if the specified offset is valid during this transition.
+     * <p>
+     * This checks to see if the given offset will be valid at some point in the transition.
+     * A gap will always return false.
+     * An overlap will return true if the offset is either the before or after offset.
+     *
+     * @param offset  the offset to check, null returns false
+     * @return true if the offset is valid during the transition
+     */
+    public boolean isValidOffset(ZoneOffset offset) {
+        return isGap() ? false : (getOffsetBefore().equals(offset) || getOffsetAfter().equals(offset));
+    }
+
+    /**
+     * Gets the valid offsets during this transition.
+     * <p>
+     * A gap will return an empty list, while an overlap will return both offsets.
+     *
+     * @return the list of valid offsets
+     */
+    List<ZoneOffset> getValidOffsets() {
+        if (isGap()) {
+            return Collections.emptyList();
+        }
+        return Arrays.asList(getOffsetBefore(), getOffsetAfter());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Compares this transition to another based on the transition instant.
+     * <p>
+     * This compares the instants of each transition.
+     * The offsets are ignored, making this order inconsistent with equals.
+     *
+     * @param transition  the transition to compare to, not null
+     * @return the comparator value, negative if less, positive if greater
+     */
+    @Override
+    public int compareTo(ZoneOffsetTransition transition) {
+        return this.getInstant().compareTo(transition.getInstant());
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this object equals another.
+     * <p>
+     * The entire state of the object is compared.
+     *
+     * @param other  the other object to compare to, null returns false
+     * @return true if equal
+     */
+    @Override
+    public boolean equals(Object other) {
+        if (other == this) {
+            return true;
+        }
+        if (other instanceof ZoneOffsetTransition) {
+            ZoneOffsetTransition d = (ZoneOffsetTransition) other;
+            return transition.equals(d.transition) &&
+                offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return transition.hashCode() ^ offsetBefore.hashCode() ^ Integer.rotateLeft(offsetAfter.hashCode(), 16);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing this object.
+     *
+     * @return a string for debugging, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("Transition[")
+            .append(isGap() ? "Gap" : "Overlap")
+            .append(" at ")
+            .append(transition)
+            .append(offsetBefore)
+            .append(" to ")
+            .append(offsetAfter)
+            .append(']');
+        return buf.toString();
+    }
+
+}
diff --git a/java/time/zone/ZoneOffsetTransitionRule.java b/java/time/zone/ZoneOffsetTransitionRule.java
new file mode 100644
index 0000000..db1a055
--- /dev/null
+++ b/java/time/zone/ZoneOffsetTransitionRule.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import static java.time.temporal.TemporalAdjusters.nextOrSame;
+import static java.time.temporal.TemporalAdjusters.previousOrSame;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.DayOfWeek;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.ZoneOffset;
+import java.time.chrono.IsoChronology;
+import java.util.Objects;
+
+/**
+ * A rule expressing how to create a transition.
+ * <p>
+ * This class allows rules for identifying future transitions to be expressed.
+ * A rule might be written in many forms:
+ * <ul>
+ * <li>the 16th March
+ * <li>the Sunday on or after the 16th March
+ * <li>the Sunday on or before the 16th March
+ * <li>the last Sunday in February
+ * </ul>
+ * These different rule types can be expressed and queried.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneOffsetTransitionRule implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 6889046316657758795L;
+
+    /**
+     * The month of the month-day of the first day of the cutover week.
+     * The actual date will be adjusted by the dowChange field.
+     */
+    private final Month month;
+    /**
+     * The day-of-month of the month-day of the cutover week.
+     * If positive, it is the start of the week where the cutover can occur.
+     * If negative, it represents the end of the week where cutover can occur.
+     * The value is the number of days from the end of the month, such that
+     * {@code -1} is the last day of the month, {@code -2} is the second
+     * to last day, and so on.
+     */
+    private final byte dom;
+    /**
+     * The cutover day-of-week, null to retain the day-of-month.
+     */
+    private final DayOfWeek dow;
+    /**
+     * The cutover time in the 'before' offset.
+     */
+    private final LocalTime time;
+    /**
+     * Whether the cutover time is midnight at the end of day.
+     */
+    private final boolean timeEndOfDay;
+    /**
+     * The definition of how the local time should be interpreted.
+     */
+    private final TimeDefinition timeDefinition;
+    /**
+     * The standard offset at the cutover.
+     */
+    private final ZoneOffset standardOffset;
+    /**
+     * The offset before the cutover.
+     */
+    private final ZoneOffset offsetBefore;
+    /**
+     * The offset after the cutover.
+     */
+    private final ZoneOffset offsetAfter;
+
+    /**
+     * Obtains an instance defining the yearly rule to create transitions between two offsets.
+     * <p>
+     * Applications should normally obtain an instance from {@link ZoneRules}.
+     * This factory is only intended for use when creating {@link ZoneRules}.
+     *
+     * @param month  the month of the month-day of the first day of the cutover week, not null
+     * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
+     *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
+     *  from -28 to 31 excluding 0
+     * @param dayOfWeek  the required day-of-week, null if the month-day should not be changed
+     * @param time  the cutover time in the 'before' offset, not null
+     * @param timeEndOfDay  whether the time is midnight at the end of day
+     * @param timeDefnition  how to interpret the cutover
+     * @param standardOffset  the standard offset in force at the cutover, not null
+     * @param offsetBefore  the offset before the cutover, not null
+     * @param offsetAfter  the offset after the cutover, not null
+     * @return the rule, not null
+     * @throws IllegalArgumentException if the day of month indicator is invalid
+     * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+     */
+    public static ZoneOffsetTransitionRule of(
+            Month month,
+            int dayOfMonthIndicator,
+            DayOfWeek dayOfWeek,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefnition,
+            ZoneOffset standardOffset,
+            ZoneOffset offsetBefore,
+            ZoneOffset offsetAfter) {
+        Objects.requireNonNull(month, "month");
+        Objects.requireNonNull(time, "time");
+        Objects.requireNonNull(timeDefnition, "timeDefnition");
+        Objects.requireNonNull(standardOffset, "standardOffset");
+        Objects.requireNonNull(offsetBefore, "offsetBefore");
+        Objects.requireNonNull(offsetAfter, "offsetAfter");
+        if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
+            throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
+        }
+        if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
+            throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
+        }
+        return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, offsetBefore, offsetAfter);
+    }
+
+    /**
+     * Creates an instance defining the yearly rule to create transitions between two offsets.
+     *
+     * @param month  the month of the month-day of the first day of the cutover week, not null
+     * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
+     *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
+     *  from -28 to 31 excluding 0
+     * @param dayOfWeek  the required day-of-week, null if the month-day should not be changed
+     * @param time  the cutover time in the 'before' offset, not null
+     * @param timeEndOfDay  whether the time is midnight at the end of day
+     * @param timeDefnition  how to interpret the cutover
+     * @param standardOffset  the standard offset in force at the cutover, not null
+     * @param offsetBefore  the offset before the cutover, not null
+     * @param offsetAfter  the offset after the cutover, not null
+     * @throws IllegalArgumentException if the day of month indicator is invalid
+     * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+     */
+    ZoneOffsetTransitionRule(
+            Month month,
+            int dayOfMonthIndicator,
+            DayOfWeek dayOfWeek,
+            LocalTime time,
+            boolean timeEndOfDay,
+            TimeDefinition timeDefnition,
+            ZoneOffset standardOffset,
+            ZoneOffset offsetBefore,
+            ZoneOffset offsetAfter) {
+        this.month = month;
+        this.dom = (byte) dayOfMonthIndicator;
+        this.dow = dayOfWeek;
+        this.time = time;
+        this.timeEndOfDay = timeEndOfDay;
+        this.timeDefinition = timeDefnition;
+        this.standardOffset = standardOffset;
+        this.offsetBefore = offsetBefore;
+        this.offsetAfter = offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+     * @serialData
+     * Refer to the serialized form of
+     * <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+     * for the encoding of epoch seconds and offsets.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *      out.writeByte(3);                // identifies a ZoneOffsetTransition
+     *      final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
+     *      final int stdOffset = standardOffset.getTotalSeconds();
+     *      final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
+     *      final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
+     *      final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
+     *      final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
+     *      final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
+     *      final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
+     *      final int dowByte = (dow == null ? 0 : dow.getValue());
+     *      int b = (month.getValue() << 28) +          // 4 bits
+     *              ((dom + 32) << 22) +                // 6 bits
+     *              (dowByte << 19) +                   // 3 bits
+     *              (timeByte << 14) +                  // 5 bits
+     *              (timeDefinition.ordinal() << 12) +  // 2 bits
+     *              (stdOffsetByte << 4) +              // 8 bits
+     *              (beforeByte << 2) +                 // 2 bits
+     *              afterByte;                          // 2 bits
+     *      out.writeInt(b);
+     *      if (timeByte == 31) {
+     *          out.writeInt(timeSecs);
+     *      }
+     *      if (stdOffsetByte == 255) {
+     *          out.writeInt(stdOffset);
+     *      }
+     *      if (beforeByte == 3) {
+     *          out.writeInt(offsetBefore.getTotalSeconds());
+     *      }
+     *      if (afterByte == 3) {
+     *          out.writeInt(offsetAfter.getTotalSeconds());
+     *      }
+     * }
+     * </pre>
+     *
+     * @return the replacing object, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZOTRULE, this);
+    }
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
+        final int stdOffset = standardOffset.getTotalSeconds();
+        final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
+        final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
+        final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
+        final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
+        final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
+        final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
+        final int dowByte = (dow == null ? 0 : dow.getValue());
+        int b = (month.getValue() << 28) +          // 4 bits
+                ((dom + 32) << 22) +                // 6 bits
+                (dowByte << 19) +                   // 3 bits
+                (timeByte << 14) +                  // 5 bits
+                (timeDefinition.ordinal() << 12) +  // 2 bits
+                (stdOffsetByte << 4) +              // 8 bits
+                (beforeByte << 2) +                 // 2 bits
+                afterByte;                          // 2 bits
+        out.writeInt(b);
+        if (timeByte == 31) {
+            out.writeInt(timeSecs);
+        }
+        if (stdOffsetByte == 255) {
+            out.writeInt(stdOffset);
+        }
+        if (beforeByte == 3) {
+            out.writeInt(offsetBefore.getTotalSeconds());
+        }
+        if (afterByte == 3) {
+            out.writeInt(offsetAfter.getTotalSeconds());
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneOffsetTransitionRule readExternal(DataInput in) throws IOException {
+        int data = in.readInt();
+        Month month = Month.of(data >>> 28);
+        int dom = ((data & (63 << 22)) >>> 22) - 32;
+        int dowByte = (data & (7 << 19)) >>> 19;
+        DayOfWeek dow = dowByte == 0 ? null : DayOfWeek.of(dowByte);
+        int timeByte = (data & (31 << 14)) >>> 14;
+        TimeDefinition defn = TimeDefinition.values()[(data & (3 << 12)) >>> 12];
+        int stdByte = (data & (255 << 4)) >>> 4;
+        int beforeByte = (data & (3 << 2)) >>> 2;
+        int afterByte = (data & 3);
+        LocalTime time = (timeByte == 31 ? LocalTime.ofSecondOfDay(in.readInt()) : LocalTime.of(timeByte % 24, 0));
+        ZoneOffset std = (stdByte == 255 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds((stdByte - 128) * 900));
+        ZoneOffset before = (beforeByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + beforeByte * 1800));
+        ZoneOffset after = (afterByte == 3 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + afterByte * 1800));
+        return ZoneOffsetTransitionRule.of(month, dom, dow, time, timeByte == 24, defn, std, before, after);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Gets the month of the transition.
+     * <p>
+     * If the rule defines an exact date then the month is the month of that date.
+     * <p>
+     * If the rule defines a week where the transition might occur, then the month
+     * if the month of either the earliest or latest possible date of the cutover.
+     *
+     * @return the month of the transition, not null
+     */
+    public Month getMonth() {
+        return month;
+    }
+
+    /**
+     * Gets the indicator of the day-of-month of the transition.
+     * <p>
+     * If the rule defines an exact date then the day is the month of that date.
+     * <p>
+     * If the rule defines a week where the transition might occur, then the day
+     * defines either the start of the end of the transition week.
+     * <p>
+     * If the value is positive, then it represents a normal day-of-month, and is the
+     * earliest possible date that the transition can be.
+     * The date may refer to 29th February which should be treated as 1st March in non-leap years.
+     * <p>
+     * If the value is negative, then it represents the number of days back from the
+     * end of the month where {@code -1} is the last day of the month.
+     * In this case, the day identified is the latest possible date that the transition can be.
+     *
+     * @return the day-of-month indicator, from -28 to 31 excluding 0
+     */
+    public int getDayOfMonthIndicator() {
+        return dom;
+    }
+
+    /**
+     * Gets the day-of-week of the transition.
+     * <p>
+     * If the rule defines an exact date then this returns null.
+     * <p>
+     * If the rule defines a week where the cutover might occur, then this method
+     * returns the day-of-week that the month-day will be adjusted to.
+     * If the day is positive then the adjustment is later.
+     * If the day is negative then the adjustment is earlier.
+     *
+     * @return the day-of-week that the transition occurs, null if the rule defines an exact date
+     */
+    public DayOfWeek getDayOfWeek() {
+        return dow;
+    }
+
+    /**
+     * Gets the local time of day of the transition which must be checked with
+     * {@link #isMidnightEndOfDay()}.
+     * <p>
+     * The time is converted into an instant using the time definition.
+     *
+     * @return the local time of day of the transition, not null
+     */
+    public LocalTime getLocalTime() {
+        return time;
+    }
+
+    /**
+     * Is the transition local time midnight at the end of day.
+     * <p>
+     * The transition may be represented as occurring at 24:00.
+     *
+     * @return whether a local time of midnight is at the start or end of the day
+     */
+    public boolean isMidnightEndOfDay() {
+        return timeEndOfDay;
+    }
+
+    /**
+     * Gets the time definition, specifying how to convert the time to an instant.
+     * <p>
+     * The local time can be converted to an instant using the standard offset,
+     * the wall offset or UTC.
+     *
+     * @return the time definition, not null
+     */
+    public TimeDefinition getTimeDefinition() {
+        return timeDefinition;
+    }
+
+    /**
+     * Gets the standard offset in force at the transition.
+     *
+     * @return the standard offset, not null
+     */
+    public ZoneOffset getStandardOffset() {
+        return standardOffset;
+    }
+
+    /**
+     * Gets the offset before the transition.
+     *
+     * @return the offset before, not null
+     */
+    public ZoneOffset getOffsetBefore() {
+        return offsetBefore;
+    }
+
+    /**
+     * Gets the offset after the transition.
+     *
+     * @return the offset after, not null
+     */
+    public ZoneOffset getOffsetAfter() {
+        return offsetAfter;
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Creates a transition instance for the specified year.
+     * <p>
+     * Calculations are performed using the ISO-8601 chronology.
+     *
+     * @param year  the year to create a transition for, not null
+     * @return the transition instance, not null
+     */
+    public ZoneOffsetTransition createTransition(int year) {
+        LocalDate date;
+        if (dom < 0) {
+            date = LocalDate.of(year, month, month.length(IsoChronology.INSTANCE.isLeapYear(year)) + 1 + dom);
+            if (dow != null) {
+                date = date.with(previousOrSame(dow));
+            }
+        } else {
+            date = LocalDate.of(year, month, dom);
+            if (dow != null) {
+                date = date.with(nextOrSame(dow));
+            }
+        }
+        if (timeEndOfDay) {
+            date = date.plusDays(1);
+        }
+        LocalDateTime localDT = LocalDateTime.of(date, time);
+        LocalDateTime transition = timeDefinition.createDateTime(localDT, standardOffset, offsetBefore);
+        return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Checks if this object equals another.
+     * <p>
+     * The entire state of the object is compared.
+     *
+     * @param otherRule  the other object to compare to, null returns false
+     * @return true if equal
+     */
+    @Override
+    public boolean equals(Object otherRule) {
+        if (otherRule == this) {
+            return true;
+        }
+        if (otherRule instanceof ZoneOffsetTransitionRule) {
+            ZoneOffsetTransitionRule other = (ZoneOffsetTransitionRule) otherRule;
+            return month == other.month && dom == other.dom && dow == other.dow &&
+                timeDefinition == other.timeDefinition &&
+                time.equals(other.time) &&
+                timeEndOfDay == other.timeEndOfDay &&
+                standardOffset.equals(other.standardOffset) &&
+                offsetBefore.equals(other.offsetBefore) &&
+                offsetAfter.equals(other.offsetAfter);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
+                (month.ordinal() << 11) + ((dom + 32) << 5) +
+                ((dow == null ? 7 : dow.ordinal()) << 2) + (timeDefinition.ordinal());
+        return hash ^ standardOffset.hashCode() ^
+                offsetBefore.hashCode() ^ offsetAfter.hashCode();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Returns a string describing this object.
+     *
+     * @return a string for debugging, not null
+     */
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder();
+        buf.append("TransitionRule[")
+            .append(offsetBefore.compareTo(offsetAfter) > 0 ? "Gap " : "Overlap ")
+            .append(offsetBefore).append(" to ").append(offsetAfter).append(", ");
+        if (dow != null) {
+            if (dom == -1) {
+                buf.append(dow.name()).append(" on or before last day of ").append(month.name());
+            } else if (dom < 0) {
+                buf.append(dow.name()).append(" on or before last day minus ").append(-dom - 1).append(" of ").append(month.name());
+            } else {
+                buf.append(dow.name()).append(" on or after ").append(month.name()).append(' ').append(dom);
+            }
+        } else {
+            buf.append(month.name()).append(' ').append(dom);
+        }
+        buf.append(" at ").append(timeEndOfDay ? "24:00" : time.toString())
+            .append(" ").append(timeDefinition)
+            .append(", standard offset ").append(standardOffset)
+            .append(']');
+        return buf.toString();
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * A definition of the way a local time can be converted to the actual
+     * transition date-time.
+     * <p>
+     * Time zone rules are expressed in one of three ways:
+     * <ul>
+     * <li>Relative to UTC</li>
+     * <li>Relative to the standard offset in force</li>
+     * <li>Relative to the wall offset (what you would see on a clock on the wall)</li>
+     * </ul>
+     */
+    public static enum TimeDefinition {
+        /** The local date-time is expressed in terms of the UTC offset. */
+        UTC,
+        /** The local date-time is expressed in terms of the wall offset. */
+        WALL,
+        /** The local date-time is expressed in terms of the standard offset. */
+        STANDARD;
+
+        /**
+         * Converts the specified local date-time to the local date-time actually
+         * seen on a wall clock.
+         * <p>
+         * This method converts using the type of this enum.
+         * The output is defined relative to the 'before' offset of the transition.
+         * <p>
+         * The UTC type uses the UTC offset.
+         * The STANDARD type uses the standard offset.
+         * The WALL type returns the input date-time.
+         * The result is intended for use with the wall-offset.
+         *
+         * @param dateTime  the local date-time, not null
+         * @param standardOffset  the standard offset, not null
+         * @param wallOffset  the wall offset, not null
+         * @return the date-time relative to the wall/before offset, not null
+         */
+        public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
+            switch (this) {
+                case UTC: {
+                    int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
+                    return dateTime.plusSeconds(difference);
+                }
+                case STANDARD: {
+                    int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
+                    return dateTime.plusSeconds(difference);
+                }
+                default:  // WALL
+                    return dateTime;
+            }
+        }
+    }
+
+}
diff --git a/java/time/zone/ZoneRules.java b/java/time/zone/ZoneRules.java
new file mode 100644
index 0000000..c3b5bba
--- /dev/null
+++ b/java/time/zone/ZoneRules.java
@@ -0,0 +1,1028 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.Year;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+// Android-changed: remove mention of ZoneRulesProvider.
+/**
+ * The rules defining how the zone offset varies for a single time-zone.
+ * <p>
+ * The rules model all the historic and future transitions for a time-zone.
+ * {@link ZoneOffsetTransition} is used for known transitions, typically historic.
+ * {@link ZoneOffsetTransitionRule} is used for future transitions that are based
+ * on the result of an algorithm.
+ * <p>
+ * The same rules may be shared internally between multiple zone IDs.
+ * <p>
+ * Serializing an instance of {@code ZoneRules} will store the entire set of rules.
+ * It does not store the zone ID as it is not part of the state of this object.
+ * <p>
+ * A rule implementation may or may not store full information about historic
+ * and future transitions, and the information stored is only as accurate as
+ * that supplied to the implementation by the rules provider.
+ * Applications should treat the data provided as representing the best information
+ * available to the implementation of this rule.
+ *
+ * @implSpec
+ * This class is immutable and thread-safe.
+ *
+ * @since 1.8
+ */
+public final class ZoneRules implements Serializable {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = 3044319355680032515L;
+    /**
+     * The last year to have its transitions cached.
+     */
+    private static final int LAST_CACHED_YEAR = 2100;
+
+    /**
+     * The transitions between standard offsets (epoch seconds), sorted.
+     */
+    private final long[] standardTransitions;
+    /**
+     * The standard offsets.
+     */
+    private final ZoneOffset[] standardOffsets;
+    /**
+     * The transitions between instants (epoch seconds), sorted.
+     */
+    private final long[] savingsInstantTransitions;
+    /**
+     * The transitions between local date-times, sorted.
+     * This is a paired array, where the first entry is the start of the transition
+     * and the second entry is the end of the transition.
+     */
+    private final LocalDateTime[] savingsLocalTransitions;
+    /**
+     * The wall offsets.
+     */
+    private final ZoneOffset[] wallOffsets;
+    /**
+     * The last rule.
+     */
+    private final ZoneOffsetTransitionRule[] lastRules;
+    /**
+     * The map of recent transitions.
+     */
+    private final transient ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache =
+                new ConcurrentHashMap<Integer, ZoneOffsetTransition[]>();
+    /**
+     * The zero-length long array.
+     */
+    private static final long[] EMPTY_LONG_ARRAY = new long[0];
+    /**
+     * The zero-length lastrules array.
+     */
+    private static final ZoneOffsetTransitionRule[] EMPTY_LASTRULES =
+        new ZoneOffsetTransitionRule[0];
+    /**
+     * The zero-length ldt array.
+     */
+    private static final LocalDateTime[] EMPTY_LDT_ARRAY = new LocalDateTime[0];
+
+    /**
+     * Obtains an instance of a ZoneRules.
+     *
+     * @param baseStandardOffset  the standard offset to use before legal rules were set, not null
+     * @param baseWallOffset  the wall offset to use before legal rules were set, not null
+     * @param standardOffsetTransitionList  the list of changes to the standard offset, not null
+     * @param transitionList  the list of transitions, not null
+     * @param lastRules  the recurring last rules, size 16 or less, not null
+     * @return the zone rules, not null
+     */
+    public static ZoneRules of(ZoneOffset baseStandardOffset,
+                               ZoneOffset baseWallOffset,
+                               List<ZoneOffsetTransition> standardOffsetTransitionList,
+                               List<ZoneOffsetTransition> transitionList,
+                               List<ZoneOffsetTransitionRule> lastRules) {
+        Objects.requireNonNull(baseStandardOffset, "baseStandardOffset");
+        Objects.requireNonNull(baseWallOffset, "baseWallOffset");
+        Objects.requireNonNull(standardOffsetTransitionList, "standardOffsetTransitionList");
+        Objects.requireNonNull(transitionList, "transitionList");
+        Objects.requireNonNull(lastRules, "lastRules");
+        return new ZoneRules(baseStandardOffset, baseWallOffset,
+                             standardOffsetTransitionList, transitionList, lastRules);
+    }
+
+    /**
+     * Obtains an instance of ZoneRules that has fixed zone rules.
+     *
+     * @param offset  the offset this fixed zone rules is based on, not null
+     * @return the zone rules, not null
+     * @see #isFixedOffset()
+     */
+    public static ZoneRules of(ZoneOffset offset) {
+        Objects.requireNonNull(offset, "offset");
+        return new ZoneRules(offset);
+    }
+
+    /**
+     * Creates an instance.
+     *
+     * @param baseStandardOffset  the standard offset to use before legal rules were set, not null
+     * @param baseWallOffset  the wall offset to use before legal rules were set, not null
+     * @param standardOffsetTransitionList  the list of changes to the standard offset, not null
+     * @param transitionList  the list of transitions, not null
+     * @param lastRules  the recurring last rules, size 16 or less, not null
+     */
+    ZoneRules(ZoneOffset baseStandardOffset,
+              ZoneOffset baseWallOffset,
+              List<ZoneOffsetTransition> standardOffsetTransitionList,
+              List<ZoneOffsetTransition> transitionList,
+              List<ZoneOffsetTransitionRule> lastRules) {
+        super();
+
+        // convert standard transitions
+
+        this.standardTransitions = new long[standardOffsetTransitionList.size()];
+
+        this.standardOffsets = new ZoneOffset[standardOffsetTransitionList.size() + 1];
+        this.standardOffsets[0] = baseStandardOffset;
+        for (int i = 0; i < standardOffsetTransitionList.size(); i++) {
+            this.standardTransitions[i] = standardOffsetTransitionList.get(i).toEpochSecond();
+            this.standardOffsets[i + 1] = standardOffsetTransitionList.get(i).getOffsetAfter();
+        }
+
+        // convert savings transitions to locals
+        List<LocalDateTime> localTransitionList = new ArrayList<>();
+        List<ZoneOffset> localTransitionOffsetList = new ArrayList<>();
+        localTransitionOffsetList.add(baseWallOffset);
+        for (ZoneOffsetTransition trans : transitionList) {
+            if (trans.isGap()) {
+                localTransitionList.add(trans.getDateTimeBefore());
+                localTransitionList.add(trans.getDateTimeAfter());
+            } else {
+                localTransitionList.add(trans.getDateTimeAfter());
+                localTransitionList.add(trans.getDateTimeBefore());
+            }
+            localTransitionOffsetList.add(trans.getOffsetAfter());
+        }
+        this.savingsLocalTransitions = localTransitionList.toArray(new LocalDateTime[localTransitionList.size()]);
+        this.wallOffsets = localTransitionOffsetList.toArray(new ZoneOffset[localTransitionOffsetList.size()]);
+
+        // convert savings transitions to instants
+        this.savingsInstantTransitions = new long[transitionList.size()];
+        for (int i = 0; i < transitionList.size(); i++) {
+            this.savingsInstantTransitions[i] = transitionList.get(i).toEpochSecond();
+        }
+
+        // last rules
+        if (lastRules.size() > 16) {
+            throw new IllegalArgumentException("Too many transition rules");
+        }
+        this.lastRules = lastRules.toArray(new ZoneOffsetTransitionRule[lastRules.size()]);
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param standardTransitions  the standard transitions, not null
+     * @param standardOffsets  the standard offsets, not null
+     * @param savingsInstantTransitions  the standard transitions, not null
+     * @param wallOffsets  the wall offsets, not null
+     * @param lastRules  the recurring last rules, size 15 or less, not null
+     */
+    private ZoneRules(long[] standardTransitions,
+                      ZoneOffset[] standardOffsets,
+                      long[] savingsInstantTransitions,
+                      ZoneOffset[] wallOffsets,
+                      ZoneOffsetTransitionRule[] lastRules) {
+        super();
+
+        this.standardTransitions = standardTransitions;
+        this.standardOffsets = standardOffsets;
+        this.savingsInstantTransitions = savingsInstantTransitions;
+        this.wallOffsets = wallOffsets;
+        this.lastRules = lastRules;
+
+        if (savingsInstantTransitions.length == 0) {
+            this.savingsLocalTransitions = EMPTY_LDT_ARRAY;
+        } else {
+            // convert savings transitions to locals
+            List<LocalDateTime> localTransitionList = new ArrayList<>();
+            for (int i = 0; i < savingsInstantTransitions.length; i++) {
+                ZoneOffset before = wallOffsets[i];
+                ZoneOffset after = wallOffsets[i + 1];
+                ZoneOffsetTransition trans = new ZoneOffsetTransition(savingsInstantTransitions[i], before, after);
+                if (trans.isGap()) {
+                    localTransitionList.add(trans.getDateTimeBefore());
+                    localTransitionList.add(trans.getDateTimeAfter());
+                } else {
+                    localTransitionList.add(trans.getDateTimeAfter());
+                    localTransitionList.add(trans.getDateTimeBefore());
+               }
+            }
+            this.savingsLocalTransitions = localTransitionList.toArray(new LocalDateTime[localTransitionList.size()]);
+        }
+    }
+
+    /**
+     * Creates an instance of ZoneRules that has fixed zone rules.
+     *
+     * @param offset  the offset this fixed zone rules is based on, not null
+     * @return the zone rules, not null
+     * @see #isFixedOffset()
+     */
+    private ZoneRules(ZoneOffset offset) {
+        this.standardOffsets = new ZoneOffset[1];
+        this.standardOffsets[0] = offset;
+        this.standardTransitions = EMPTY_LONG_ARRAY;
+        this.savingsInstantTransitions = EMPTY_LONG_ARRAY;
+        this.savingsLocalTransitions = EMPTY_LDT_ARRAY;
+        this.wallOffsets = standardOffsets;
+        this.lastRules = EMPTY_LASTRULES;
+    }
+
+    /**
+     * Defend against malicious streams.
+     *
+     * @param s the stream to read
+     * @throws InvalidObjectException always
+     */
+    private void readObject(ObjectInputStream s) throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre style="font-size:1.0em">{@code
+     *
+     *   out.writeByte(1);  // identifies a ZoneRules
+     *   out.writeInt(standardTransitions.length);
+     *   for (long trans : standardTransitions) {
+     *       Ser.writeEpochSec(trans, out);
+     *   }
+     *   for (ZoneOffset offset : standardOffsets) {
+     *       Ser.writeOffset(offset, out);
+     *   }
+     *   out.writeInt(savingsInstantTransitions.length);
+     *   for (long trans : savingsInstantTransitions) {
+     *       Ser.writeEpochSec(trans, out);
+     *   }
+     *   for (ZoneOffset offset : wallOffsets) {
+     *       Ser.writeOffset(offset, out);
+     *   }
+     *   out.writeByte(lastRules.length);
+     *   for (ZoneOffsetTransitionRule rule : lastRules) {
+     *       rule.writeExternal(out);
+     *   }
+     * }
+     * </pre>
+     * <p>
+     * Epoch second values used for offsets are encoded in a variable
+     * length form to make the common cases put fewer bytes in the stream.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *  static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
+     *     if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) {  // quarter hours between 1825 and 2300
+     *         int store = (int) ((epochSec + 4575744000L) / 900);
+     *         out.writeByte((store >>> 16) & 255);
+     *         out.writeByte((store >>> 8) & 255);
+     *         out.writeByte(store & 255);
+     *      } else {
+     *          out.writeByte(255);
+     *          out.writeLong(epochSec);
+     *      }
+     *  }
+     * }
+     * </pre>
+     * <p>
+     * ZoneOffset values are encoded in a variable length form so the
+     * common cases put fewer bytes in the stream.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *  static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
+     *     final int offsetSecs = offset.getTotalSeconds();
+     *     int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+     *     out.writeByte(offsetByte);
+     *     if (offsetByte == 127) {
+     *         out.writeInt(offsetSecs);
+     *     }
+     * }
+     *}
+     * </pre>
+     * @return the replacing object, not null
+     */
+    private Object writeReplace() {
+        return new Ser(Ser.ZRULES, this);
+    }
+
+    /**
+     * Writes the state to the stream.
+     *
+     * @param out  the output stream, not null
+     * @throws IOException if an error occurs
+     */
+    void writeExternal(DataOutput out) throws IOException {
+        out.writeInt(standardTransitions.length);
+        for (long trans : standardTransitions) {
+            Ser.writeEpochSec(trans, out);
+        }
+        for (ZoneOffset offset : standardOffsets) {
+            Ser.writeOffset(offset, out);
+        }
+        out.writeInt(savingsInstantTransitions.length);
+        for (long trans : savingsInstantTransitions) {
+            Ser.writeEpochSec(trans, out);
+        }
+        for (ZoneOffset offset : wallOffsets) {
+            Ser.writeOffset(offset, out);
+        }
+        out.writeByte(lastRules.length);
+        for (ZoneOffsetTransitionRule rule : lastRules) {
+            rule.writeExternal(out);
+        }
+    }
+
+    /**
+     * Reads the state from the stream.
+     *
+     * @param in  the input stream, not null
+     * @return the created object, not null
+     * @throws IOException if an error occurs
+     */
+    static ZoneRules readExternal(DataInput in) throws IOException, ClassNotFoundException {
+        int stdSize = in.readInt();
+        long[] stdTrans = (stdSize == 0) ? EMPTY_LONG_ARRAY
+                                         : new long[stdSize];
+        for (int i = 0; i < stdSize; i++) {
+            stdTrans[i] = Ser.readEpochSec(in);
+        }
+        ZoneOffset[] stdOffsets = new ZoneOffset[stdSize + 1];
+        for (int i = 0; i < stdOffsets.length; i++) {
+            stdOffsets[i] = Ser.readOffset(in);
+        }
+        int savSize = in.readInt();
+        long[] savTrans = (savSize == 0) ? EMPTY_LONG_ARRAY
+                                         : new long[savSize];
+        for (int i = 0; i < savSize; i++) {
+            savTrans[i] = Ser.readEpochSec(in);
+        }
+        ZoneOffset[] savOffsets = new ZoneOffset[savSize + 1];
+        for (int i = 0; i < savOffsets.length; i++) {
+            savOffsets[i] = Ser.readOffset(in);
+        }
+        int ruleSize = in.readByte();
+        ZoneOffsetTransitionRule[] rules = (ruleSize == 0) ?
+            EMPTY_LASTRULES : new ZoneOffsetTransitionRule[ruleSize];
+        for (int i = 0; i < ruleSize; i++) {
+            rules[i] = ZoneOffsetTransitionRule.readExternal(in);
+        }
+        return new ZoneRules(stdTrans, stdOffsets, savTrans, savOffsets, rules);
+    }
+
+    /**
+     * Checks of the zone rules are fixed, such that the offset never varies.
+     *
+     * @return true if the time-zone is fixed and the offset never changes
+     */
+    public boolean isFixedOffset() {
+        return savingsInstantTransitions.length == 0;
+    }
+
+    /**
+     * Gets the offset applicable at the specified instant in these rules.
+     * <p>
+     * The mapping from an instant to an offset is simple, there is only
+     * one valid offset for each instant.
+     * This method returns that offset.
+     *
+     * @param instant  the instant to find the offset for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the offset, not null
+     */
+    public ZoneOffset getOffset(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return standardOffsets[0];
+        }
+        long epochSec = instant.getEpochSecond();
+        // check if using last rules
+        if (lastRules.length > 0 &&
+                epochSec > savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
+            int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
+            ZoneOffsetTransition[] transArray = findTransitionArray(year);
+            ZoneOffsetTransition trans = null;
+            for (int i = 0; i < transArray.length; i++) {
+                trans = transArray[i];
+                if (epochSec < trans.toEpochSecond()) {
+                    return trans.getOffsetBefore();
+                }
+            }
+            return trans.getOffsetAfter();
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
+        if (index < 0) {
+            // switch negative insert position to start of matched range
+            index = -index - 2;
+        }
+        return wallOffsets[index + 1];
+    }
+
+    /**
+     * Gets a suitable offset for the specified local date-time in these rules.
+     * <p>
+     * The mapping from a local date-time to an offset is not straightforward.
+     * There are three cases:
+     * <ul>
+     * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+     *  case applies, where there is a single valid offset for the local date-time.</li>
+     * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+     *  due to the spring daylight savings change from "winter" to "summer".
+     *  In a gap there are local date-time values with no valid offset.</li>
+     * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+     *  due to the autumn daylight savings change from "summer" to "winter".
+     *  In an overlap there are local date-time values with two valid offsets.</li>
+     * </ul>
+     * Thus, for any given local date-time there can be zero, one or two valid offsets.
+     * This method returns the single offset in the Normal case, and in the Gap or Overlap
+     * case it returns the offset before the transition.
+     * <p>
+     * Since, in the case of Gap and Overlap, the offset returned is a "best" value, rather
+     * than the "correct" value, it should be treated with care. Applications that care
+     * about the correct offset should use a combination of this method,
+     * {@link #getValidOffsets(LocalDateTime)} and {@link #getTransition(LocalDateTime)}.
+     *
+     * @param localDateTime  the local date-time to query, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the best available offset for the local date-time, not null
+     */
+    public ZoneOffset getOffset(LocalDateTime localDateTime) {
+        Object info = getOffsetInfo(localDateTime);
+        if (info instanceof ZoneOffsetTransition) {
+            return ((ZoneOffsetTransition) info).getOffsetBefore();
+        }
+        return (ZoneOffset) info;
+    }
+
+    /**
+     * Gets the offset applicable at the specified local date-time in these rules.
+     * <p>
+     * The mapping from a local date-time to an offset is not straightforward.
+     * There are three cases:
+     * <ul>
+     * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+     *  case applies, where there is a single valid offset for the local date-time.</li>
+     * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+     *  due to the spring daylight savings change from "winter" to "summer".
+     *  In a gap there are local date-time values with no valid offset.</li>
+     * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+     *  due to the autumn daylight savings change from "summer" to "winter".
+     *  In an overlap there are local date-time values with two valid offsets.</li>
+     * </ul>
+     * Thus, for any given local date-time there can be zero, one or two valid offsets.
+     * This method returns that list of valid offsets, which is a list of size 0, 1 or 2.
+     * In the case where there are two offsets, the earlier offset is returned at index 0
+     * and the later offset at index 1.
+     * <p>
+     * There are various ways to handle the conversion from a {@code LocalDateTime}.
+     * One technique, using this method, would be:
+     * <pre>
+     *  List&lt;ZoneOffset&gt; validOffsets = rules.getOffset(localDT);
+     *  if (validOffsets.size() == 1) {
+     *    // Normal case: only one valid offset
+     *    zoneOffset = validOffsets.get(0);
+     *  } else {
+     *    // Gap or Overlap: determine what to do from transition (which will be non-null)
+     *    ZoneOffsetTransition trans = rules.getTransition(localDT);
+     *  }
+     * </pre>
+     * <p>
+     * In theory, it is possible for there to be more than two valid offsets.
+     * This would happen if clocks to be put back more than once in quick succession.
+     * This has never happened in the history of time-zones and thus has no special handling.
+     * However, if it were to happen, then the list would return more than 2 entries.
+     *
+     * @param localDateTime  the local date-time to query for valid offsets, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the list of valid offsets, may be immutable, not null
+     */
+    public List<ZoneOffset> getValidOffsets(LocalDateTime localDateTime) {
+        // should probably be optimized
+        Object info = getOffsetInfo(localDateTime);
+        if (info instanceof ZoneOffsetTransition) {
+            return ((ZoneOffsetTransition) info).getValidOffsets();
+        }
+        return Collections.singletonList((ZoneOffset) info);
+    }
+
+    /**
+     * Gets the offset transition applicable at the specified local date-time in these rules.
+     * <p>
+     * The mapping from a local date-time to an offset is not straightforward.
+     * There are three cases:
+     * <ul>
+     * <li>Normal, with one valid offset. For the vast majority of the year, the normal
+     *  case applies, where there is a single valid offset for the local date-time.</li>
+     * <li>Gap, with zero valid offsets. This is when clocks jump forward typically
+     *  due to the spring daylight savings change from "winter" to "summer".
+     *  In a gap there are local date-time values with no valid offset.</li>
+     * <li>Overlap, with two valid offsets. This is when clocks are set back typically
+     *  due to the autumn daylight savings change from "summer" to "winter".
+     *  In an overlap there are local date-time values with two valid offsets.</li>
+     * </ul>
+     * A transition is used to model the cases of a Gap or Overlap.
+     * The Normal case will return null.
+     * <p>
+     * There are various ways to handle the conversion from a {@code LocalDateTime}.
+     * One technique, using this method, would be:
+     * <pre>
+     *  ZoneOffsetTransition trans = rules.getTransition(localDT);
+     *  if (trans == null) {
+     *    // Gap or Overlap: determine what to do from transition
+     *  } else {
+     *    // Normal case: only one valid offset
+     *    zoneOffset = rule.getOffset(localDT);
+     *  }
+     * </pre>
+     *
+     * @param localDateTime  the local date-time to query for offset transition, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the offset transition, null if the local date-time is not in transition
+     */
+    public ZoneOffsetTransition getTransition(LocalDateTime localDateTime) {
+        Object info = getOffsetInfo(localDateTime);
+        return (info instanceof ZoneOffsetTransition ? (ZoneOffsetTransition) info : null);
+    }
+
+    private Object getOffsetInfo(LocalDateTime dt) {
+        if (savingsInstantTransitions.length == 0) {
+            return standardOffsets[0];
+        }
+        // check if using last rules
+        if (lastRules.length > 0 &&
+                dt.isAfter(savingsLocalTransitions[savingsLocalTransitions.length - 1])) {
+            ZoneOffsetTransition[] transArray = findTransitionArray(dt.getYear());
+            Object info = null;
+            for (ZoneOffsetTransition trans : transArray) {
+                info = findOffsetInfo(dt, trans);
+                if (info instanceof ZoneOffsetTransition || info.equals(trans.getOffsetBefore())) {
+                    return info;
+                }
+            }
+            return info;
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsLocalTransitions, dt);
+        if (index == -1) {
+            // before first transition
+            return wallOffsets[0];
+        }
+        if (index < 0) {
+            // switch negative insert position to start of matched range
+            index = -index - 2;
+        } else if (index < savingsLocalTransitions.length - 1 &&
+                savingsLocalTransitions[index].equals(savingsLocalTransitions[index + 1])) {
+            // handle overlap immediately following gap
+            index++;
+        }
+        if ((index & 1) == 0) {
+            // gap or overlap
+            LocalDateTime dtBefore = savingsLocalTransitions[index];
+            LocalDateTime dtAfter = savingsLocalTransitions[index + 1];
+            ZoneOffset offsetBefore = wallOffsets[index / 2];
+            ZoneOffset offsetAfter = wallOffsets[index / 2 + 1];
+            if (offsetAfter.getTotalSeconds() > offsetBefore.getTotalSeconds()) {
+                // gap
+                return new ZoneOffsetTransition(dtBefore, offsetBefore, offsetAfter);
+            } else {
+                // overlap
+                return new ZoneOffsetTransition(dtAfter, offsetBefore, offsetAfter);
+            }
+        } else {
+            // normal (neither gap or overlap)
+            return wallOffsets[index / 2 + 1];
+        }
+    }
+
+    /**
+     * Finds the offset info for a local date-time and transition.
+     *
+     * @param dt  the date-time, not null
+     * @param trans  the transition, not null
+     * @return the offset info, not null
+     */
+    private Object findOffsetInfo(LocalDateTime dt, ZoneOffsetTransition trans) {
+        LocalDateTime localTransition = trans.getDateTimeBefore();
+        if (trans.isGap()) {
+            if (dt.isBefore(localTransition)) {
+                return trans.getOffsetBefore();
+            }
+            if (dt.isBefore(trans.getDateTimeAfter())) {
+                return trans;
+            } else {
+                return trans.getOffsetAfter();
+            }
+        } else {
+            if (dt.isBefore(localTransition) == false) {
+                return trans.getOffsetAfter();
+            }
+            if (dt.isBefore(trans.getDateTimeAfter())) {
+                return trans.getOffsetBefore();
+            } else {
+                return trans;
+            }
+        }
+    }
+
+    /**
+     * Finds the appropriate transition array for the given year.
+     *
+     * @param year  the year, not null
+     * @return the transition array, not null
+     */
+    private ZoneOffsetTransition[] findTransitionArray(int year) {
+        Integer yearObj = year;  // should use Year class, but this saves a class load
+        ZoneOffsetTransition[] transArray = lastRulesCache.get(yearObj);
+        if (transArray != null) {
+            return transArray;
+        }
+        ZoneOffsetTransitionRule[] ruleArray = lastRules;
+        transArray  = new ZoneOffsetTransition[ruleArray.length];
+        for (int i = 0; i < ruleArray.length; i++) {
+            transArray[i] = ruleArray[i].createTransition(year);
+        }
+        if (year < LAST_CACHED_YEAR) {
+            lastRulesCache.putIfAbsent(yearObj, transArray);
+        }
+        return transArray;
+    }
+
+    /**
+     * Gets the standard offset for the specified instant in this zone.
+     * <p>
+     * This provides access to historic information on how the standard offset
+     * has changed over time.
+     * The standard offset is the offset before any daylight saving time is applied.
+     * This is typically the offset applicable during winter.
+     *
+     * @param instant  the instant to find the offset information for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the standard offset, not null
+     */
+    public ZoneOffset getStandardOffset(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return standardOffsets[0];
+        }
+        long epochSec = instant.getEpochSecond();
+        int index  = Arrays.binarySearch(standardTransitions, epochSec);
+        if (index < 0) {
+            // switch negative insert position to start of matched range
+            index = -index - 2;
+        }
+        return standardOffsets[index + 1];
+    }
+
+    /**
+     * Gets the amount of daylight savings in use for the specified instant in this zone.
+     * <p>
+     * This provides access to historic information on how the amount of daylight
+     * savings has changed over time.
+     * This is the difference between the standard offset and the actual offset.
+     * Typically the amount is zero during winter and one hour during summer.
+     * Time-zones are second-based, so the nanosecond part of the duration will be zero.
+     * <p>
+     * This default implementation calculates the duration from the
+     * {@link #getOffset(java.time.Instant) actual} and
+     * {@link #getStandardOffset(java.time.Instant) standard} offsets.
+     *
+     * @param instant  the instant to find the daylight savings for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the difference between the standard and actual offset, not null
+     */
+    public Duration getDaylightSavings(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return Duration.ZERO;
+        }
+        ZoneOffset standardOffset = getStandardOffset(instant);
+        ZoneOffset actualOffset = getOffset(instant);
+        return Duration.ofSeconds(actualOffset.getTotalSeconds() - standardOffset.getTotalSeconds());
+    }
+
+    /**
+     * Checks if the specified instant is in daylight savings.
+     * <p>
+     * This checks if the standard offset and the actual offset are the same
+     * for the specified instant.
+     * If they are not, it is assumed that daylight savings is in operation.
+     * <p>
+     * This default implementation compares the {@link #getOffset(java.time.Instant) actual}
+     * and {@link #getStandardOffset(java.time.Instant) standard} offsets.
+     *
+     * @param instant  the instant to find the offset information for, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the standard offset, not null
+     */
+    public boolean isDaylightSavings(Instant instant) {
+        return (getStandardOffset(instant).equals(getOffset(instant)) == false);
+    }
+
+    /**
+     * Checks if the offset date-time is valid for these rules.
+     * <p>
+     * To be valid, the local date-time must not be in a gap and the offset
+     * must match one of the valid offsets.
+     * <p>
+     * This default implementation checks if {@link #getValidOffsets(java.time.LocalDateTime)}
+     * contains the specified offset.
+     *
+     * @param localDateTime  the date-time to check, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @param offset  the offset to check, null returns false
+     * @return true if the offset date-time is valid for these rules
+     */
+    public boolean isValidOffset(LocalDateTime localDateTime, ZoneOffset offset) {
+        return getValidOffsets(localDateTime).contains(offset);
+    }
+
+    /**
+     * Gets the next transition after the specified instant.
+     * <p>
+     * This returns details of the next transition after the specified instant.
+     * For example, if the instant represents a point where "Summer" daylight savings time
+     * applies, then the method will return the transition to the next "Winter" time.
+     *
+     * @param instant  the instant to get the next transition after, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the next transition after the specified instant, null if this is after the last transition
+     */
+    public ZoneOffsetTransition nextTransition(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return null;
+        }
+        long epochSec = instant.getEpochSecond();
+        // check if using last rules
+        if (epochSec >= savingsInstantTransitions[savingsInstantTransitions.length - 1]) {
+            if (lastRules.length == 0) {
+                return null;
+            }
+            // search year the instant is in
+            int year = findYear(epochSec, wallOffsets[wallOffsets.length - 1]);
+            ZoneOffsetTransition[] transArray = findTransitionArray(year);
+            for (ZoneOffsetTransition trans : transArray) {
+                if (epochSec < trans.toEpochSecond()) {
+                    return trans;
+                }
+            }
+            // use first from following year
+            if (year < Year.MAX_VALUE) {
+                transArray = findTransitionArray(year + 1);
+                return transArray[0];
+            }
+            return null;
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
+        if (index < 0) {
+            index = -index - 1;  // switched value is the next transition
+        } else {
+            index += 1;  // exact match, so need to add one to get the next
+        }
+        return new ZoneOffsetTransition(savingsInstantTransitions[index], wallOffsets[index], wallOffsets[index + 1]);
+    }
+
+    /**
+     * Gets the previous transition before the specified instant.
+     * <p>
+     * This returns details of the previous transition after the specified instant.
+     * For example, if the instant represents a point where "summer" daylight saving time
+     * applies, then the method will return the transition from the previous "winter" time.
+     *
+     * @param instant  the instant to get the previous transition after, not null, but null
+     *  may be ignored if the rules have a single offset for all instants
+     * @return the previous transition after the specified instant, null if this is before the first transition
+     */
+    public ZoneOffsetTransition previousTransition(Instant instant) {
+        if (savingsInstantTransitions.length == 0) {
+            return null;
+        }
+        long epochSec = instant.getEpochSecond();
+        if (instant.getNano() > 0 && epochSec < Long.MAX_VALUE) {
+            epochSec += 1;  // allow rest of method to only use seconds
+        }
+
+        // check if using last rules
+        long lastHistoric = savingsInstantTransitions[savingsInstantTransitions.length - 1];
+        if (lastRules.length > 0 && epochSec > lastHistoric) {
+            // search year the instant is in
+            ZoneOffset lastHistoricOffset = wallOffsets[wallOffsets.length - 1];
+            int year = findYear(epochSec, lastHistoricOffset);
+            ZoneOffsetTransition[] transArray = findTransitionArray(year);
+            for (int i = transArray.length - 1; i >= 0; i--) {
+                if (epochSec > transArray[i].toEpochSecond()) {
+                    return transArray[i];
+                }
+            }
+            // use last from preceding year
+            int lastHistoricYear = findYear(lastHistoric, lastHistoricOffset);
+            if (--year > lastHistoricYear) {
+                transArray = findTransitionArray(year);
+                return transArray[transArray.length - 1];
+            }
+            // drop through
+        }
+
+        // using historic rules
+        int index  = Arrays.binarySearch(savingsInstantTransitions, epochSec);
+        if (index < 0) {
+            index = -index - 1;
+        }
+        if (index <= 0) {
+            return null;
+        }
+        return new ZoneOffsetTransition(savingsInstantTransitions[index - 1], wallOffsets[index - 1], wallOffsets[index]);
+    }
+
+    private int findYear(long epochSecond, ZoneOffset offset) {
+        // inline for performance
+        long localSecond = epochSecond + offset.getTotalSeconds();
+        long localEpochDay = Math.floorDiv(localSecond, 86400);
+        return LocalDate.ofEpochDay(localEpochDay).getYear();
+    }
+
+    /**
+     * Gets the complete list of fully defined transitions.
+     * <p>
+     * The complete set of transitions for this rules instance is defined by this method
+     * and {@link #getTransitionRules()}. This method returns those transitions that have
+     * been fully defined. These are typically historical, but may be in the future.
+     * <p>
+     * The list will be empty for fixed offset rules and for any time-zone where there has
+     * only ever been a single offset. The list will also be empty if the transition rules are unknown.
+     *
+     * @return an immutable list of fully defined transitions, not null
+     */
+    public List<ZoneOffsetTransition> getTransitions() {
+        List<ZoneOffsetTransition> list = new ArrayList<>();
+        for (int i = 0; i < savingsInstantTransitions.length; i++) {
+            list.add(new ZoneOffsetTransition(savingsInstantTransitions[i], wallOffsets[i], wallOffsets[i + 1]));
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /**
+     * Gets the list of transition rules for years beyond those defined in the transition list.
+     * <p>
+     * The complete set of transitions for this rules instance is defined by this method
+     * and {@link #getTransitions()}. This method returns instances of {@link ZoneOffsetTransitionRule}
+     * that define an algorithm for when transitions will occur.
+     * <p>
+     * For any given {@code ZoneRules}, this list contains the transition rules for years
+     * beyond those years that have been fully defined. These rules typically refer to future
+     * daylight saving time rule changes.
+     * <p>
+     * If the zone defines daylight savings into the future, then the list will normally
+     * be of size two and hold information about entering and exiting daylight savings.
+     * If the zone does not have daylight savings, or information about future changes
+     * is uncertain, then the list will be empty.
+     * <p>
+     * The list will be empty for fixed offset rules and for any time-zone where there is no
+     * daylight saving time. The list will also be empty if the transition rules are unknown.
+     *
+     * @return an immutable list of transition rules, not null
+     */
+    public List<ZoneOffsetTransitionRule> getTransitionRules() {
+        return Collections.unmodifiableList(Arrays.asList(lastRules));
+    }
+
+    /**
+     * Checks if this set of rules equals another.
+     * <p>
+     * Two rule sets are equal if they will always result in the same output
+     * for any given input instant or local date-time.
+     * Rules from two different groups may return false even if they are in fact the same.
+     * <p>
+     * This definition should result in implementations comparing their entire state.
+     *
+     * @param otherRules  the other rules, null returns false
+     * @return true if this rules is the same as that specified
+     */
+    @Override
+    public boolean equals(Object otherRules) {
+        if (this == otherRules) {
+           return true;
+        }
+        if (otherRules instanceof ZoneRules) {
+            ZoneRules other = (ZoneRules) otherRules;
+            return Arrays.equals(standardTransitions, other.standardTransitions) &&
+                    Arrays.equals(standardOffsets, other.standardOffsets) &&
+                    Arrays.equals(savingsInstantTransitions, other.savingsInstantTransitions) &&
+                    Arrays.equals(wallOffsets, other.wallOffsets) &&
+                    Arrays.equals(lastRules, other.lastRules);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a suitable hash code given the definition of {@code #equals}.
+     *
+     * @return the hash code
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(standardTransitions) ^
+                Arrays.hashCode(standardOffsets) ^
+                Arrays.hashCode(savingsInstantTransitions) ^
+                Arrays.hashCode(wallOffsets) ^
+                Arrays.hashCode(lastRules);
+    }
+
+    /**
+     * Returns a string describing this object.
+     *
+     * @return a string for debugging, not null
+     */
+    @Override
+    public String toString() {
+        return "ZoneRules[currentStandardOffset=" + standardOffsets[standardOffsets.length - 1] + "]";
+    }
+
+}
diff --git a/java/time/zone/ZoneRulesException.java b/java/time/zone/ZoneRulesException.java
new file mode 100644
index 0000000..2c845ca
--- /dev/null
+++ b/java/time/zone/ZoneRulesException.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.time.DateTimeException;
+
+/**
+ * Thrown to indicate a problem with time-zone configuration.
+ * <p>
+ * This exception is used to indicate a problems with the configured
+ * time-zone rules.
+ *
+ * @implSpec
+ * This class is intended for use in a single thread.
+ *
+ * @since 1.8
+ */
+public class ZoneRulesException extends DateTimeException {
+
+    /**
+     * Serialization version.
+     */
+    private static final long serialVersionUID = -1632418723876261839L;
+
+    /**
+     * Constructs a new date-time exception with the specified message.
+     *
+     * @param message  the message to use for this exception, may be null
+     */
+    public ZoneRulesException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new date-time exception with the specified message and cause.
+     *
+     * @param message  the message to use for this exception, may be null
+     * @param cause  the cause of the exception, may be null
+     */
+    public ZoneRulesException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+}
diff --git a/java/time/zone/ZoneRulesProvider.java b/java/time/zone/ZoneRulesProvider.java
new file mode 100644
index 0000000..a90727a
--- /dev/null
+++ b/java/time/zone/ZoneRulesProvider.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package java.time.zone;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NavigableMap;
+import java.util.Objects;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Provider of time-zone rules to the system.
+ * <p>
+ * This class manages the configuration of time-zone rules.
+ * The static methods provide the public API that can be used to manage the providers.
+ * The abstract methods provide the SPI that allows rules to be provided.
+ * <p>
+ * ZoneRulesProvider may be installed in an instance of the Java Platform as
+ * extension classes, that is, jar files placed into any of the usual extension
+ * directories. Installed providers are loaded using the service-provider loading
+ * facility defined by the {@link ServiceLoader} class. A ZoneRulesProvider
+ * identifies itself with a provider configuration file named
+ * {@code java.time.zone.ZoneRulesProvider} in the resource directory
+ * {@code META-INF/services}. The file should contain a line that specifies the
+ * fully qualified concrete zonerules-provider class name.
+ * Providers may also be made available by adding them to the class path or by
+ * registering themselves via {@link #registerProvider} method.
+ * <p>
+ * The Java virtual machine has a default provider that provides zone rules
+ * for the time-zones defined by IANA Time Zone Database (TZDB). If the system
+ * property {@code java.time.zone.DefaultZoneRulesProvider} is defined then
+ * it is taken to be the fully-qualified name of a concrete ZoneRulesProvider
+ * class to be loaded as the default provider, using the system class loader.
+ * If this system property is not defined, a system-default provider will be
+ * loaded to serve as the default provider.
+ * <p>
+ * Rules are looked up primarily by zone ID, as used by {@link ZoneId}.
+ * Only zone region IDs may be used, zone offset IDs are not used here.
+ * <p>
+ * Time-zone rules are political, thus the data can change at any time.
+ * Each provider will provide the latest rules for each zone ID, but they
+ * may also provide the history of how the rules changed.
+ *
+ * @implSpec
+ * This interface is a service provider that can be called by multiple threads.
+ * Implementations must be immutable and thread-safe.
+ * <p>
+ * Providers must ensure that once a rule has been seen by the application, the
+ * rule must continue to be available.
+ * <p>
+*  Providers are encouraged to implement a meaningful {@code toString} method.
+ * <p>
+ * Many systems would like to update time-zone rules dynamically without stopping the JVM.
+ * When examined in detail, this is a complex problem.
+ * Providers may choose to handle dynamic updates, however the default provider does not.
+ *
+ * @since 1.8
+ */
+public abstract class ZoneRulesProvider {
+
+    /**
+     * The set of loaded providers.
+     */
+    private static final CopyOnWriteArrayList<ZoneRulesProvider> PROVIDERS = new CopyOnWriteArrayList<>();
+    /**
+     * The lookup from zone ID to provider.
+     */
+    private static final ConcurrentMap<String, ZoneRulesProvider> ZONES = new ConcurrentHashMap<>(512, 0.75f, 2);
+
+    static {
+        // Android-changed: use a single hard-coded provider.
+        ZoneRulesProvider provider = new IcuZoneRulesProvider();
+        registerProvider(provider);
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Gets the set of available zone IDs.
+     * <p>
+     * These IDs are the string form of a {@link ZoneId}.
+     *
+     * @return a modifiable copy of the set of zone IDs, not null
+     */
+    public static Set<String> getAvailableZoneIds() {
+        return new HashSet<>(ZONES.keySet());
+    }
+
+    /**
+     * Gets the rules for the zone ID.
+     * <p>
+     * This returns the latest available rules for the zone ID.
+     * <p>
+     * This method relies on time-zone data provider files that are configured.
+     * These are loaded using a {@code ServiceLoader}.
+     * <p>
+     * The caching flag is designed to allow provider implementations to
+     * prevent the rules being cached in {@code ZoneId}.
+     * Under normal circumstances, the caching of zone rules is highly desirable
+     * as it will provide greater performance. However, there is a use case where
+     * the caching would not be desirable, see {@link #provideRules}.
+     *
+     * @param zoneId the zone ID as defined by {@code ZoneId}, not null
+     * @param forCaching whether the rules are being queried for caching,
+     * true if the returned rules will be cached by {@code ZoneId},
+     * false if they will be returned to the user without being cached in {@code ZoneId}
+     * @return the rules, null if {@code forCaching} is true and this
+     * is a dynamic provider that wants to prevent caching in {@code ZoneId},
+     * otherwise not null
+     * @throws ZoneRulesException if rules cannot be obtained for the zone ID
+     */
+    public static ZoneRules getRules(String zoneId, boolean forCaching) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        return getProvider(zoneId).provideRules(zoneId, forCaching);
+    }
+
+    /**
+     * Gets the history of rules for the zone ID.
+     * <p>
+     * Time-zones are defined by governments and change frequently.
+     * This method allows applications to find the history of changes to the
+     * rules for a single zone ID. The map is keyed by a string, which is the
+     * version string associated with the rules.
+     * <p>
+     * The exact meaning and format of the version is provider specific.
+     * The version must follow lexicographical order, thus the returned map will
+     * be order from the oldest known rules to the newest available rules.
+     * The default 'TZDB' group uses version numbering consisting of the year
+     * followed by a letter, such as '2009e' or '2012f'.
+     * <p>
+     * Implementations must provide a result for each valid zone ID, however
+     * they do not have to provide a history of rules.
+     * Thus the map will always contain one element, and will only contain more
+     * than one element if historical rule information is available.
+     *
+     * @param zoneId  the zone ID as defined by {@code ZoneId}, not null
+     * @return a modifiable copy of the history of the rules for the ID, sorted
+     *  from oldest to newest, not null
+     * @throws ZoneRulesException if history cannot be obtained for the zone ID
+     */
+    public static NavigableMap<String, ZoneRules> getVersions(String zoneId) {
+        Objects.requireNonNull(zoneId, "zoneId");
+        return getProvider(zoneId).provideVersions(zoneId);
+    }
+
+    /**
+     * Gets the provider for the zone ID.
+     *
+     * @param zoneId  the zone ID as defined by {@code ZoneId}, not null
+     * @return the provider, not null
+     * @throws ZoneRulesException if the zone ID is unknown
+     */
+    private static ZoneRulesProvider getProvider(String zoneId) {
+        ZoneRulesProvider provider = ZONES.get(zoneId);
+        if (provider == null) {
+            if (ZONES.isEmpty()) {
+                throw new ZoneRulesException("No time-zone data files registered");
+            }
+            throw new ZoneRulesException("Unknown time-zone ID: " + zoneId);
+        }
+        return provider;
+    }
+
+    //-------------------------------------------------------------------------
+    /**
+     * Registers a zone rules provider.
+     * <p>
+     * This adds a new provider to those currently available.
+     * A provider supplies rules for one or more zone IDs.
+     * A provider cannot be registered if it supplies a zone ID that has already been
+     * registered. See the notes on time-zone IDs in {@link ZoneId}, especially
+     * the section on using the concept of a "group" to make IDs unique.
+     * <p>
+     * To ensure the integrity of time-zones already created, there is no way
+     * to deregister providers.
+     *
+     * @param provider  the provider to register, not null
+     * @throws ZoneRulesException if a zone ID is already registered
+     */
+    public static void registerProvider(ZoneRulesProvider provider) {
+        Objects.requireNonNull(provider, "provider");
+        registerProvider0(provider);
+        PROVIDERS.add(provider);
+    }
+
+    /**
+     * Registers the provider.
+     *
+     * @param provider  the provider to register, not null
+     * @throws ZoneRulesException if unable to complete the registration
+     */
+    private static void registerProvider0(ZoneRulesProvider provider) {
+        for (String zoneId : provider.provideZoneIds()) {
+            Objects.requireNonNull(zoneId, "zoneId");
+            ZoneRulesProvider old = ZONES.putIfAbsent(zoneId, provider);
+            if (old != null) {
+                throw new ZoneRulesException(
+                    "Unable to register zone as one already registered with that ID: " + zoneId +
+                    ", currently loading from provider: " + provider);
+            }
+        }
+    }
+
+    /**
+     * Refreshes the rules from the underlying data provider.
+     * <p>
+     * This method allows an application to request that the providers check
+     * for any updates to the provided rules.
+     * After calling this method, the offset stored in any {@link ZonedDateTime}
+     * may be invalid for the zone ID.
+     * <p>
+     * Dynamic update of rules is a complex problem and most applications
+     * should not use this method or dynamic rules.
+     * To achieve dynamic rules, a provider implementation will have to be written
+     * as per the specification of this class.
+     * In addition, instances of {@code ZoneRules} must not be cached in the
+     * application as they will become stale. However, the boolean flag on
+     * {@link #provideRules(String, boolean)} allows provider implementations
+     * to control the caching of {@code ZoneId}, potentially ensuring that
+     * all objects in the system see the new rules.
+     * Note that there is likely to be a cost in performance of a dynamic rules
+     * provider. Note also that no dynamic rules provider is in this specification.
+     *
+     * @return true if the rules were updated
+     * @throws ZoneRulesException if an error occurs during the refresh
+     */
+    public static boolean refresh() {
+        boolean changed = false;
+        for (ZoneRulesProvider provider : PROVIDERS) {
+            changed |= provider.provideRefresh();
+        }
+        return changed;
+    }
+
+    /**
+     * Constructor.
+     */
+    protected ZoneRulesProvider() {
+    }
+
+    //-----------------------------------------------------------------------
+    /**
+     * SPI method to get the available zone IDs.
+     * <p>
+     * This obtains the IDs that this {@code ZoneRulesProvider} provides.
+     * A provider should provide data for at least one zone ID.
+     * <p>
+     * The returned zone IDs remain available and valid for the lifetime of the application.
+     * A dynamic provider may increase the set of IDs as more data becomes available.
+     *
+     * @return the set of zone IDs being provided, not null
+     * @throws ZoneRulesException if a problem occurs while providing the IDs
+     */
+    protected abstract Set<String> provideZoneIds();
+
+    /**
+     * SPI method to get the rules for the zone ID.
+     * <p>
+     * This loads the rules for the specified zone ID.
+     * The provider implementation must validate that the zone ID is valid and
+     * available, throwing a {@code ZoneRulesException} if it is not.
+     * The result of the method in the valid case depends on the caching flag.
+     * <p>
+     * If the provider implementation is not dynamic, then the result of the
+     * method must be the non-null set of rules selected by the ID.
+     * <p>
+     * If the provider implementation is dynamic, then the flag gives the option
+     * of preventing the returned rules from being cached in {@link ZoneId}.
+     * When the flag is true, the provider is permitted to return null, where
+     * null will prevent the rules from being cached in {@code ZoneId}.
+     * When the flag is false, the provider must return non-null rules.
+     *
+     * @param zoneId the zone ID as defined by {@code ZoneId}, not null
+     * @param forCaching whether the rules are being queried for caching,
+     * true if the returned rules will be cached by {@code ZoneId},
+     * false if they will be returned to the user without being cached in {@code ZoneId}
+     * @return the rules, null if {@code forCaching} is true and this
+     * is a dynamic provider that wants to prevent caching in {@code ZoneId},
+     * otherwise not null
+     * @throws ZoneRulesException if rules cannot be obtained for the zone ID
+     */
+    protected abstract ZoneRules provideRules(String zoneId, boolean forCaching);
+
+    /**
+     * SPI method to get the history of rules for the zone ID.
+     * <p>
+     * This returns a map of historical rules keyed by a version string.
+     * The exact meaning and format of the version is provider specific.
+     * The version must follow lexicographical order, thus the returned map will
+     * be order from the oldest known rules to the newest available rules.
+     * The default 'TZDB' group uses version numbering consisting of the year
+     * followed by a letter, such as '2009e' or '2012f'.
+     * <p>
+     * Implementations must provide a result for each valid zone ID, however
+     * they do not have to provide a history of rules.
+     * Thus the map will contain at least one element, and will only contain
+     * more than one element if historical rule information is available.
+     * <p>
+     * The returned versions remain available and valid for the lifetime of the application.
+     * A dynamic provider may increase the set of versions as more data becomes available.
+     *
+     * @param zoneId  the zone ID as defined by {@code ZoneId}, not null
+     * @return a modifiable copy of the history of the rules for the ID, sorted
+     *  from oldest to newest, not null
+     * @throws ZoneRulesException if history cannot be obtained for the zone ID
+     */
+    protected abstract NavigableMap<String, ZoneRules> provideVersions(String zoneId);
+
+    /**
+     * SPI method to refresh the rules from the underlying data provider.
+     * <p>
+     * This method provides the opportunity for a provider to dynamically
+     * recheck the underlying data provider to find the latest rules.
+     * This could be used to load new rules without stopping the JVM.
+     * Dynamic behavior is entirely optional and most providers do not support it.
+     * <p>
+     * This implementation returns false.
+     *
+     * @return true if the rules were updated
+     * @throws ZoneRulesException if an error occurs during the refresh
+     */
+    protected boolean provideRefresh() {
+        return false;
+    }
+
+}
diff --git a/java/time/zone/package-info.java b/java/time/zone/package-info.java
new file mode 100644
index 0000000..f50b3de
--- /dev/null
+++ b/java/time/zone/package-info.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ *  * Neither the name of JSR-310 nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * <p>
+ * Support for time-zones and their rules.
+ * </p>
+ * <p>
+ * Daylight Saving Time and Time-Zones are concepts used by Governments to alter local time.
+ * This package provides support for time-zones, their rules and the resulting
+ * gaps and overlaps in the local time-line typically caused by Daylight Saving Time.
+ * </p>
+ *
+ * <h3>Package specification</h3>
+ * <p>
+ * Unless otherwise noted, passing a null argument to a constructor or method in any class or interface
+ * in this package will cause a {@link java.lang.NullPointerException NullPointerException} to be thrown.
+ * The Javadoc "@param" definition is used to summarise the null-behavior.
+ * The "@throws {@link java.lang.NullPointerException}" is not explicitly documented in each method.
+ * </p>
+ * <p>
+ * All calculations should check for numeric overflow and throw either an {@link java.lang.ArithmeticException}
+ * or a {@link java.time.DateTimeException}.
+ * </p>
+ * @since JDK1.8
+ */
+package java.time.zone;
diff --git a/java/util/AbstractCollection.annotated.java b/java/util/AbstractCollection.annotated.java
new file mode 100644
index 0000000..529e351
--- /dev/null
+++ b/java/util/AbstractCollection.annotated.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractCollection<E> implements java.util.Collection<E> {
+
+protected AbstractCollection() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public abstract int size();
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/AbstractCollection.java b/java/util/AbstractCollection.java
new file mode 100644
index 0000000..1f7cdd9
--- /dev/null
+++ b/java/util/AbstractCollection.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the <tt>Collection</tt>
+ * interface, to minimize the effort required to implement this interface. <p>
+ *
+ * To implement an unmodifiable collection, the programmer needs only to
+ * extend this class and provide implementations for the <tt>iterator</tt> and
+ * <tt>size</tt> methods.  (The iterator returned by the <tt>iterator</tt>
+ * method must implement <tt>hasNext</tt> and <tt>next</tt>.)<p>
+ *
+ * To implement a modifiable collection, the programmer must additionally
+ * override this class's <tt>add</tt> method (which otherwise throws an
+ * <tt>UnsupportedOperationException</tt>), and the iterator returned by the
+ * <tt>iterator</tt> method must additionally implement its <tt>remove</tt>
+ * method.<p>
+ *
+ * The programmer should generally provide a void (no argument) and
+ * <tt>Collection</tt> constructor, as per the recommendation in the
+ * <tt>Collection</tt> interface specification.<p>
+ *
+ * The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if
+ * the collection being implemented admits a more efficient implementation.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @since 1.2
+ */
+
+public abstract class AbstractCollection<E> implements Collection<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractCollection() {
+    }
+
+    // Query Operations
+
+    /**
+     * Returns an iterator over the elements contained in this collection.
+     *
+     * @return an iterator over the elements contained in this collection
+     */
+    public abstract Iterator<E> iterator();
+
+    public abstract int size();
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns <tt>size() == 0</tt>.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the elements in the collection,
+     * checking each element in turn for equality with the specified element.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean contains(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext())
+                if (it.next()==null)
+                    return true;
+        } else {
+            while (it.hasNext())
+                if (o.equals(it.next()))
+                    return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns an array containing all the elements
+     * returned by this collection's iterator, in the same order, stored in
+     * consecutive elements of the array, starting with index {@code 0}.
+     * The length of the returned array is equal to the number of elements
+     * returned by the iterator, even if the size of this collection changes
+     * during iteration, as might happen if the collection permits
+     * concurrent modification during iteration.  The {@code size} method is
+     * called only as an optimization hint; the correct result is returned
+     * even if the iterator returns a different number of elements.
+     *
+     * <p>This method is equivalent to:
+     *
+     *  <pre> {@code
+     * List<E> list = new ArrayList<E>(size());
+     * for (E e : this)
+     *     list.add(e);
+     * return list.toArray();
+     * }</pre>
+     */
+    public Object[] toArray() {
+        // Estimate size of array; be prepared to see more or fewer elements
+        Object[] r = new Object[size()];
+        Iterator<E> it = iterator();
+        for (int i = 0; i < r.length; i++) {
+            if (! it.hasNext()) // fewer elements than expected
+                return Arrays.copyOf(r, i);
+            r[i] = it.next();
+        }
+        return it.hasNext() ? finishToArray(r, it) : r;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns an array containing all the elements
+     * returned by this collection's iterator in the same order, stored in
+     * consecutive elements of the array, starting with index {@code 0}.
+     * If the number of elements returned by the iterator is too large to
+     * fit into the specified array, then the elements are returned in a
+     * newly allocated array with length equal to the number of elements
+     * returned by the iterator, even if the size of this collection
+     * changes during iteration, as might happen if the collection permits
+     * concurrent modification during iteration.  The {@code size} method is
+     * called only as an optimization hint; the correct result is returned
+     * even if the iterator returns a different number of elements.
+     *
+     * <p>This method is equivalent to:
+     *
+     *  <pre> {@code
+     * List<E> list = new ArrayList<E>(size());
+     * for (E e : this)
+     *     list.add(e);
+     * return list.toArray(a);
+     * }</pre>
+     *
+     * @throws ArrayStoreException  {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        // Estimate size of array; be prepared to see more or fewer elements
+        int size = size();
+        T[] r = a.length >= size ? a :
+                  (T[])java.lang.reflect.Array
+                  .newInstance(a.getClass().getComponentType(), size);
+        Iterator<E> it = iterator();
+
+        for (int i = 0; i < r.length; i++) {
+            if (! it.hasNext()) { // fewer elements than expected
+                if (a == r) {
+                    r[i] = null; // null-terminate
+                } else if (a.length < i) {
+                    return Arrays.copyOf(r, i);
+                } else {
+                    System.arraycopy(r, 0, a, 0, i);
+                    if (a.length > i) {
+                        a[i] = null;
+                    }
+                }
+                return a;
+            }
+            r[i] = (T)it.next();
+        }
+        // more elements than expected
+        return it.hasNext() ? finishToArray(r, it) : r;
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Reallocates the array being used within toArray when the iterator
+     * returned more elements than expected, and finishes filling it from
+     * the iterator.
+     *
+     * @param r the array, replete with previously stored elements
+     * @param it the in-progress iterator over this collection
+     * @return array containing the elements in the given array, plus any
+     *         further elements returned by the iterator, trimmed to size
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
+        int i = r.length;
+        while (it.hasNext()) {
+            int cap = r.length;
+            if (i == cap) {
+                int newCap = cap + (cap >> 1) + 1;
+                // overflow-conscious code
+                if (newCap - MAX_ARRAY_SIZE > 0)
+                    newCap = hugeCapacity(cap + 1);
+                r = Arrays.copyOf(r, newCap);
+            }
+            r[i++] = (T)it.next();
+        }
+        // trim if overallocated
+        return (i == r.length) ? r : Arrays.copyOf(r, i);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError
+                ("Required array size too large");
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    // Modification Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation always throws an
+     * <tt>UnsupportedOperationException</tt>.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IllegalStateException         {@inheritDoc}
+     */
+    public boolean add(E e) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the collection looking for the
+     * specified element.  If it finds the element, it removes the element
+     * from the collection using the iterator's remove method.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by this
+     * collection's iterator method does not implement the <tt>remove</tt>
+     * method and this collection contains the specified object.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public boolean remove(Object o) {
+        Iterator<E> it = iterator();
+        if (o==null) {
+            while (it.hasNext()) {
+                if (it.next()==null) {
+                    it.remove();
+                    return true;
+                }
+            }
+        } else {
+            while (it.hasNext()) {
+                if (o.equals(it.next())) {
+                    it.remove();
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the specified collection,
+     * checking each element returned by the iterator in turn to see
+     * if it's contained in this collection.  If all elements are so
+     * contained <tt>true</tt> is returned, otherwise <tt>false</tt>.
+     *
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        for (Object e : c)
+            if (!contains(e))
+                return false;
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over the specified collection, and adds
+     * each object returned by the iterator to this collection, in turn.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> unless <tt>add</tt> is
+     * overridden (assuming the specified collection is non-empty).
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IllegalStateException         {@inheritDoc}
+     *
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        boolean modified = false;
+        for (E e : c)
+            if (add(e))
+                modified = true;
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over this collection, checking each
+     * element returned by the iterator in turn to see if it's contained
+     * in the specified collection.  If it's so contained, it's removed from
+     * this collection with the iterator's <tt>remove</tt> method.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
+     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
+     * and this collection contains one or more elements in common with the
+     * specified collection.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     *
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<?> it = iterator();
+        while (it.hasNext()) {
+            if (c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over this collection, checking each
+     * element returned by the iterator in turn to see if it's contained
+     * in the specified collection.  If it's not so contained, it's removed
+     * from this collection with the iterator's <tt>remove</tt> method.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
+     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method
+     * and this collection contains one or more elements not present in the
+     * specified collection.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     *
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            if (!c.contains(it.next())) {
+                it.remove();
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation iterates over this collection, removing each
+     * element using the <tt>Iterator.remove</tt> operation.  Most
+     * implementations will probably choose to override this method for
+     * efficiency.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by this
+     * collection's <tt>iterator</tt> method does not implement the
+     * <tt>remove</tt> method and this collection is non-empty.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     */
+    public void clear() {
+        Iterator<E> it = iterator();
+        while (it.hasNext()) {
+            it.next();
+            it.remove();
+        }
+    }
+
+
+    //  String conversion
+
+    /**
+     * Returns a string representation of this collection.  The string
+     * representation consists of a list of the collection's elements in the
+     * order they are returned by its iterator, enclosed in square brackets
+     * (<tt>"[]"</tt>).  Adjacent elements are separated by the characters
+     * <tt>", "</tt> (comma and space).  Elements are converted to strings as
+     * by {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this collection
+     */
+    public String toString() {
+        Iterator<E> it = iterator();
+        if (! it.hasNext())
+            return "[]";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('[');
+        for (;;) {
+            E e = it.next();
+            sb.append(e == this ? "(this Collection)" : e);
+            if (! it.hasNext())
+                return sb.append(']').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/java/util/AbstractList.annotated.java b/java/util/AbstractList.annotated.java
new file mode 100644
index 0000000..ed89f7b
--- /dev/null
+++ b/java/util/AbstractList.annotated.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractList<E> extends java.util.AbstractCollection<E> implements java.util.List<E> {
+
+protected AbstractList() { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract E get(int index);
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+protected void removeRange(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+protected transient int modCount = 0; // 0x0
+}
diff --git a/java/util/AbstractList.java b/java/util/AbstractList.java
new file mode 100644
index 0000000..c8c160d
--- /dev/null
+++ b/java/util/AbstractList.java
@@ -0,0 +1,942 @@
+/*
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * This class provides a skeletal implementation of the {@link List}
+ * interface to minimize the effort required to implement this interface
+ * backed by a "random access" data store (such as an array).  For sequential
+ * access data (such as a linked list), {@link AbstractSequentialList} should
+ * be used in preference to this class.
+ *
+ * <p>To implement an unmodifiable list, the programmer needs only to extend
+ * this class and provide implementations for the {@link #get(int)} and
+ * {@link List#size() size()} methods.
+ *
+ * <p>To implement a modifiable list, the programmer must additionally
+ * override the {@link #set(int, Object) set(int, E)} method (which otherwise
+ * throws an {@code UnsupportedOperationException}).  If the list is
+ * variable-size the programmer must additionally override the
+ * {@link #add(int, Object) add(int, E)} and {@link #remove(int)} methods.
+ *
+ * <p>The programmer should generally provide a void (no argument) and collection
+ * constructor, as per the recommendation in the {@link Collection} interface
+ * specification.
+ *
+ * <p>Unlike the other abstract collection implementations, the programmer does
+ * <i>not</i> have to provide an iterator implementation; the iterator and
+ * list iterator are implemented by this class, on top of the "random access"
+ * methods:
+ * {@link #get(int)},
+ * {@link #set(int, Object) set(int, E)},
+ * {@link #add(int, Object) add(int, E)} and
+ * {@link #remove(int)}.
+ *
+ * <p>The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if the
+ * collection being implemented admits a more efficient implementation.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @since 1.2
+ */
+
+public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractList() {
+    }
+
+    /**
+     * Appends the specified element to the end of this list (optional
+     * operation).
+     *
+     * <p>Lists that support this operation may place limitations on what
+     * elements may be added to this list.  In particular, some
+     * lists will refuse to add null elements, and others will impose
+     * restrictions on the type of elements that may be added.  List
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * @implSpec
+     * This implementation calls {@code add(size(), e)}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless
+     * {@link #add(int, Object) add(int, E)} is overridden.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this list
+     */
+    public boolean add(E e) {
+        add(size(), e);
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public abstract E get(int index);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E remove(int index) {
+        throw new UnsupportedOperationException();
+    }
+
+
+    // Search Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation first gets a list iterator (with
+     * {@code listIterator()}).  Then, it iterates over the list until the
+     * specified element is found or the end of the list is reached.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public int indexOf(Object o) {
+        ListIterator<E> it = listIterator();
+        if (o==null) {
+            while (it.hasNext())
+                if (it.next()==null)
+                    return it.previousIndex();
+        } else {
+            while (it.hasNext())
+                if (o.equals(it.next()))
+                    return it.previousIndex();
+        }
+        return -1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation first gets a list iterator that points to the end
+     * of the list (with {@code listIterator(size())}).  Then, it iterates
+     * backwards over the list until the specified element is found, or the
+     * beginning of the list is reached.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public int lastIndexOf(Object o) {
+        ListIterator<E> it = listIterator(size());
+        if (o==null) {
+            while (it.hasPrevious())
+                if (it.previous()==null)
+                    return it.nextIndex();
+        } else {
+            while (it.hasPrevious())
+                if (o.equals(it.previous()))
+                    return it.nextIndex();
+        }
+        return -1;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * Removes all of the elements from this list (optional operation).
+     * The list will be empty after this call returns.
+     *
+     * @implSpec
+     * This implementation calls {@code removeRange(0, size())}.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless {@code remove(int
+     * index)} or {@code removeRange(int fromIndex, int toIndex)} is
+     * overridden.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this list
+     */
+    public void clear() {
+        removeRange(0, size());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation gets an iterator over the specified collection
+     * and iterates over it, inserting the elements obtained from the
+     * iterator into this list at the appropriate position, one at a time,
+     * using {@code add(int, E)}.
+     * Many implementations will override this method for efficiency.
+     *
+     * <p>Note that this implementation throws an
+     * {@code UnsupportedOperationException} unless
+     * {@link #add(int, Object) add(int, E)} is overridden.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        rangeCheckForAdd(index);
+        boolean modified = false;
+        for (E e : c) {
+            add(index++, e);
+            modified = true;
+        }
+        return modified;
+    }
+
+
+    // Iterators
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
+     * iterator interface, relying on the backing list's {@code size()},
+     * {@code get(int)}, and {@code remove(int)} methods.
+     *
+     * <p>Note that the iterator returned by this method will throw an
+     * {@link UnsupportedOperationException} in response to its
+     * {@code remove} method unless the list's {@code remove(int)} method is
+     * overridden.
+     *
+     * <p>This implementation can be made to throw runtime exceptions in the
+     * face of concurrent modification, as described in the specification
+     * for the (protected) {@link #modCount} field.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns {@code listIterator(0)}.
+     *
+     * @see #listIterator(int)
+     */
+    public ListIterator<E> listIterator() {
+        return listIterator(0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a straightforward implementation of the
+     * {@code ListIterator} interface that extends the implementation of the
+     * {@code Iterator} interface returned by the {@code iterator()} method.
+     * The {@code ListIterator} implementation relies on the backing list's
+     * {@code get(int)}, {@code set(int, E)}, {@code add(int, E)}
+     * and {@code remove(int)} methods.
+     *
+     * <p>Note that the list iterator returned by this implementation will
+     * throw an {@link UnsupportedOperationException} in response to its
+     * {@code remove}, {@code set} and {@code add} methods unless the
+     * list's {@code remove(int)}, {@code set(int, E)}, and
+     * {@code add(int, E)} methods are overridden.
+     *
+     * <p>This implementation can be made to throw runtime exceptions in the
+     * face of concurrent modification, as described in the specification for
+     * the (protected) {@link #modCount} field.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(final int index) {
+        rangeCheckForAdd(index);
+
+        return new ListItr(index);
+    }
+
+    private class Itr implements Iterator<E> {
+        /**
+         * Index of element to be returned by subsequent call to next.
+         */
+        int cursor = 0;
+
+        /**
+         * Index of element returned by most recent call to next or
+         * previous.  Reset to -1 if this element is deleted by a call
+         * to remove.
+         */
+        int lastRet = -1;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * List should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor != size();
+        }
+
+        public E next() {
+            checkForComodification();
+            try {
+                int i = cursor;
+                E next = get(i);
+                lastRet = i;
+                cursor = i + 1;
+                return next;
+            } catch (IndexOutOfBoundsException e) {
+                checkForComodification();
+                throw new NoSuchElementException();
+            }
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                AbstractList.this.remove(lastRet);
+                if (lastRet < cursor)
+                    cursor--;
+                lastRet = -1;
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException e) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    private class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public E previous() {
+            checkForComodification();
+            try {
+                int i = cursor - 1;
+                E previous = get(i);
+                lastRet = cursor = i;
+                return previous;
+            } catch (IndexOutOfBoundsException e) {
+                checkForComodification();
+                throw new NoSuchElementException();
+            }
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor-1;
+        }
+
+        public void set(E e) {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            checkForComodification();
+
+            try {
+                AbstractList.this.set(lastRet, e);
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        public void add(E e) {
+            checkForComodification();
+
+            try {
+                int i = cursor;
+                AbstractList.this.add(i, e);
+                lastRet = -1;
+                cursor = i + 1;
+                expectedModCount = modCount;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a list that subclasses
+     * {@code AbstractList}.  The subclass stores, in private fields, the
+     * size of the subList (which can change over its lifetime), and the
+     * expected {@code modCount} value of the backing list.  There are two
+     * variants of the subclass, one of which implements {@code RandomAccess}.
+     * If this list implements {@code RandomAccess} the returned list will
+     * be an instance of the subclass that implements {@code RandomAccess}.
+     *
+     * <p>The subclass's {@code set(int, E)}, {@code get(int)},
+     * {@code add(int, E)}, {@code remove(int)}, {@code addAll(int,
+     * Collection)} and {@code removeRange(int, int)} methods all
+     * delegate to the corresponding methods on the backing abstract list,
+     * after bounds-checking the index and adjusting for the offset.  The
+     * {@code addAll(Collection c)} method merely returns {@code addAll(size,
+     * c)}.
+     *
+     * <p>The {@code listIterator(int)} method returns a "wrapper object"
+     * over a list iterator on the backing list, which is created with the
+     * corresponding method on the backing list.  The {@code iterator} method
+     * merely returns {@code listIterator()}, and the {@code size} method
+     * merely returns the subclass's {@code size} field.
+     *
+     * <p>All methods first check to see if the actual {@code modCount} of
+     * the backing list is equal to its expected value, and throw a
+     * {@code ConcurrentModificationException} if it is not.
+     *
+     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
+     *         {@code (fromIndex < 0 || toIndex > size)}
+     * @throws IllegalArgumentException if the endpoint indices are out of order
+     *         {@code (fromIndex > toIndex)}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size());
+        return (this instanceof RandomAccess ?
+                new RandomAccessSubList<>(this, fromIndex, toIndex) :
+                new SubList<>(this, fromIndex, toIndex));
+    }
+
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this list for equality.  Returns
+     * {@code true} if and only if the specified object is also a list, both
+     * lists have the same size, and all corresponding pairs of elements in
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code (e1==null ? e2==null :
+     * e1.equals(e2))}.)  In other words, two lists are defined to be
+     * equal if they contain the same elements in the same order.
+     *
+     * @implSpec
+     * This implementation first checks if the specified object is this
+     * list. If so, it returns {@code true}; if not, it checks if the
+     * specified object is a list. If not, it returns {@code false}; if so,
+     * it iterates over both lists, comparing corresponding pairs of elements.
+     * If any comparison returns {@code false}, this method returns
+     * {@code false}.  If either iterator runs out of elements before the
+     * other it returns {@code false} (as the lists are of unequal length);
+     * otherwise it returns {@code true} when the iterations complete.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        ListIterator<E> e1 = listIterator();
+        ListIterator<?> e2 = ((List<?>) o).listIterator();
+        while (e1.hasNext() && e2.hasNext()) {
+            E o1 = e1.next();
+            Object o2 = e2.next();
+            if (!(o1==null ? o2==null : o1.equals(o2)))
+                return false;
+        }
+        return !(e1.hasNext() || e2.hasNext());
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     *
+     * @implSpec
+     * This implementation uses exactly the code that is used to define the
+     * list hash function in the documentation for the {@link List#hashCode}
+     * method.
+     *
+     * @return the hash code value for this list
+     */
+    public int hashCode() {
+        int hashCode = 1;
+        for (E e : this)
+            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+        return hashCode;
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * <p>This method is called by the {@code clear} operation on this list
+     * and its subLists.  Overriding this method to take advantage of
+     * the internals of the list implementation can <i>substantially</i>
+     * improve the performance of the {@code clear} operation on this list
+     * and its subLists.
+     *
+     * @implSpec
+     * This implementation gets a list iterator positioned before
+     * {@code fromIndex}, and repeatedly calls {@code ListIterator.next}
+     * followed by {@code ListIterator.remove} until the entire range has
+     * been removed.  <b>Note: if {@code ListIterator.remove} requires linear
+     * time, this implementation requires quadratic time.</b>
+     *
+     * @param fromIndex index of first element to be removed
+     * @param toIndex index after last element to be removed
+     */
+    protected void removeRange(int fromIndex, int toIndex) {
+        ListIterator<E> it = listIterator(fromIndex);
+        for (int i=0, n=toIndex-fromIndex; i<n; i++) {
+            it.next();
+            it.remove();
+        }
+    }
+
+    /**
+     * The number of times this list has been <i>structurally modified</i>.
+     * Structural modifications are those that change the size of the
+     * list, or otherwise perturb it in such a fashion that iterations in
+     * progress may yield incorrect results.
+     *
+     * <p>This field is used by the iterator and list iterator implementation
+     * returned by the {@code iterator} and {@code listIterator} methods.
+     * If the value of this field changes unexpectedly, the iterator (or list
+     * iterator) will throw a {@code ConcurrentModificationException} in
+     * response to the {@code next}, {@code remove}, {@code previous},
+     * {@code set} or {@code add} operations.  This provides
+     * <i>fail-fast</i> behavior, rather than non-deterministic behavior in
+     * the face of concurrent modification during iteration.
+     *
+     * <p><b>Use of this field by subclasses is optional.</b> If a subclass
+     * wishes to provide fail-fast iterators (and list iterators), then it
+     * merely has to increment this field in its {@code add(int, E)} and
+     * {@code remove(int)} methods (and any other methods that it overrides
+     * that result in structural modifications to the list).  A single call to
+     * {@code add(int, E)} or {@code remove(int)} must add no more than
+     * one to this field, or the iterators (and list iterators) will throw
+     * bogus {@code ConcurrentModificationExceptions}.  If an implementation
+     * does not wish to provide fail-fast iterators, this field may be
+     * ignored.
+     */
+    protected transient int modCount = 0;
+
+    private void rangeCheckForAdd(int index) {
+        if (index < 0 || index > size())
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size();
+    }
+
+    /**
+     * An index-based split-by-two, lazily initialized Spliterator covering
+     * a List that access elements via {@link List#get}.
+     *
+     * If access results in an IndexOutOfBoundsException then a
+     * ConcurrentModificationException is thrown instead (since the list has
+     * been structurally modified while traversing).
+     *
+     * If the List is an instance of AbstractList then concurrent modification
+     * checking is performed using the AbstractList's modCount field.
+     */
+    static final class RandomAccessSpliterator<E> implements Spliterator<E> {
+
+        private final List<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+
+        // The following fields are valid if covering an AbstractList
+        private final AbstractList<E> alist;
+        private int expectedModCount; // initialized when fence set
+
+        RandomAccessSpliterator(List<E> list) {
+            assert list instanceof RandomAccess;
+
+            this.list = list;
+            this.index = 0;
+            this.fence = -1;
+
+            this.alist = list instanceof AbstractList ? (AbstractList<E>) list : null;
+            this.expectedModCount = alist != null ? alist.modCount : 0;
+        }
+
+        /** Create new spliterator covering the given  range */
+        private RandomAccessSpliterator(RandomAccessSpliterator<E> parent,
+                                int origin, int fence) {
+            this.list = parent.list;
+            this.index = origin;
+            this.fence = fence;
+
+            this.alist = parent.alist;
+            this.expectedModCount = parent.expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            List<E> lst = list;
+            if ((hi = fence) < 0) {
+                if (alist != null) {
+                    expectedModCount = alist.modCount;
+                }
+                hi = fence = lst.size();
+            }
+            return hi;
+        }
+
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                    new RandomAccessSpliterator<>(this, lo, index = mid);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                action.accept(get(list, i));
+                checkAbstractListModCount(alist, expectedModCount);
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            List<E> lst = list;
+            int hi = getFence();
+            int i = index;
+            index = hi;
+            for (; i < hi; i++) {
+                action.accept(get(lst, i));
+            }
+            checkAbstractListModCount(alist, expectedModCount);
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static <E> E get(List<E> list, int i) {
+            try {
+                return list.get(i);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        static void checkAbstractListModCount(AbstractList<?> alist, int expectedModCount) {
+            if (alist != null && alist.modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    private static class SubList<E> extends AbstractList<E> {
+        private final AbstractList<E> root;
+        private final SubList<E> parent;
+        private final int offset;
+        protected int size;
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a SubList itself.
+         */
+        public SubList(AbstractList<E> root, int fromIndex, int toIndex) {
+            this.root = root;
+            this.parent = null;
+            this.offset = fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        /**
+         * Constructs a sublist of another SubList.
+         */
+        protected SubList(SubList<E> parent, int fromIndex, int toIndex) {
+            this.root = parent.root;
+            this.parent = parent;
+            this.offset = parent.offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = root.modCount;
+        }
+
+        public E set(int index, E element) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.set(offset + index, element);
+        }
+
+        public E get(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            return root.get(offset + index);
+        }
+
+        public int size() {
+            checkForComodification();
+            return size;
+        }
+
+        public void add(int index, E element) {
+            rangeCheckForAdd(index);
+            checkForComodification();
+            root.add(offset + index, element);
+            updateSizeAndModCount(1);
+        }
+
+        public E remove(int index) {
+            Objects.checkIndex(index, size);
+            checkForComodification();
+            E result = root.remove(offset + index);
+            updateSizeAndModCount(-1);
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            checkForComodification();
+            root.removeRange(offset + fromIndex, offset + toIndex);
+            updateSizeAndModCount(fromIndex - toIndex);
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            rangeCheckForAdd(index);
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+            checkForComodification();
+            root.addAll(offset + index, c);
+            updateSizeAndModCount(cSize);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            checkForComodification();
+            rangeCheckForAdd(index);
+
+            return new ListIterator<E>() {
+                private final ListIterator<E> i =
+                        root.listIterator(offset + index);
+
+                public boolean hasNext() {
+                    return nextIndex() < size;
+                }
+
+                public E next() {
+                    if (hasNext())
+                        return i.next();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public boolean hasPrevious() {
+                    return previousIndex() >= 0;
+                }
+
+                public E previous() {
+                    if (hasPrevious())
+                        return i.previous();
+                    else
+                        throw new NoSuchElementException();
+                }
+
+                public int nextIndex() {
+                    return i.nextIndex() - offset;
+                }
+
+                public int previousIndex() {
+                    return i.previousIndex() - offset;
+                }
+
+                public void remove() {
+                    i.remove();
+                    updateSizeAndModCount(-1);
+                }
+
+                public void set(E e) {
+                    i.set(e);
+                }
+
+                public void add(E e) {
+                    i.add(e);
+                    updateSizeAndModCount(1);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList<>(this, fromIndex, toIndex);
+        }
+
+        private void rangeCheckForAdd(int index) {
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+size;
+        }
+
+        private void checkForComodification() {
+            if (root.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+        }
+
+        private void updateSizeAndModCount(int sizeChange) {
+            SubList<E> slist = this;
+            do {
+                slist.size += sizeChange;
+                slist.modCount = root.modCount;
+                slist = slist.parent;
+            } while (slist != null);
+        }
+    }
+
+    private static class RandomAccessSubList<E>
+            extends SubList<E> implements RandomAccess {
+
+        /**
+         * Constructs a sublist of an arbitrary AbstractList, which is
+         * not a RandomAccessSubList itself.
+         */
+        RandomAccessSubList(AbstractList<E> root,
+                int fromIndex, int toIndex) {
+            super(root, fromIndex, toIndex);
+        }
+
+        /**
+         * Constructs a sublist of another RandomAccessSubList.
+         */
+        RandomAccessSubList(RandomAccessSubList<E> parent,
+                int fromIndex, int toIndex) {
+            super(parent, fromIndex, toIndex);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new RandomAccessSubList<>(this, fromIndex, toIndex);
+        }
+    }
+}
diff --git a/java/util/AbstractMap.annotated.java b/java/util/AbstractMap.annotated.java
new file mode 100644
index 0000000..a0c97b0
--- /dev/null
+++ b/java/util/AbstractMap.annotated.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.Map.Entry;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractMap<K, V> implements java.util.Map<K,V> {
+
+protected AbstractMap() { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] protected java.lang.Object clone() throws java.lang.CloneNotSupportedException { throw new RuntimeException("Stub!"); }
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class SimpleEntry<K, V> implements java.util.Map.Entry<K,V>, java.io.Serializable {
+
+public SimpleEntry(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public SimpleEntry(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> entry) { throw new RuntimeException("Stub!"); }
+
[email protected] public K getKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public V getValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public V setValue(@libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class SimpleImmutableEntry<K, V> implements java.util.Map.Entry<K,V>, java.io.Serializable {
+
+public SimpleImmutableEntry(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public SimpleImmutableEntry(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> entry) { throw new RuntimeException("Stub!"); }
+
[email protected] public K getKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public V getValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public V setValue(@libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+}
+
+}
diff --git a/java/util/AbstractMap.java b/java/util/AbstractMap.java
new file mode 100644
index 0000000..948bf51
--- /dev/null
+++ b/java/util/AbstractMap.java
@@ -0,0 +1,860 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.util.Map.Entry;
+
+/**
+ * This class provides a skeletal implementation of the <tt>Map</tt>
+ * interface, to minimize the effort required to implement this interface.
+ *
+ * <p>To implement an unmodifiable map, the programmer needs only to extend this
+ * class and provide an implementation for the <tt>entrySet</tt> method, which
+ * returns a set-view of the map's mappings.  Typically, the returned set
+ * will, in turn, be implemented atop <tt>AbstractSet</tt>.  This set should
+ * not support the <tt>add</tt> or <tt>remove</tt> methods, and its iterator
+ * should not support the <tt>remove</tt> method.
+ *
+ * <p>To implement a modifiable map, the programmer must additionally override
+ * this class's <tt>put</tt> method (which otherwise throws an
+ * <tt>UnsupportedOperationException</tt>), and the iterator returned by
+ * <tt>entrySet().iterator()</tt> must additionally implement its
+ * <tt>remove</tt> method.
+ *
+ * <p>The programmer should generally provide a void (no argument) and map
+ * constructor, as per the recommendation in the <tt>Map</tt> interface
+ * specification.
+ *
+ * <p>The documentation for each non-abstract method in this class describes its
+ * implementation in detail.  Each of these methods may be overridden if the
+ * map being implemented admits a more efficient implementation.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Map
+ * @see Collection
+ * @since 1.2
+ */
+
+public abstract class AbstractMap<K,V> implements Map<K,V> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractMap() {
+    }
+
+    // Query Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns <tt>entrySet().size()</tt>.
+     */
+    public int size() {
+        return entrySet().size();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns <tt>size() == 0</tt>.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching
+     * for an entry with the specified value.  If such an entry is found,
+     * <tt>true</tt> is returned.  If the iteration terminates without
+     * finding such an entry, <tt>false</tt> is returned.  Note that this
+     * implementation requires linear time in the size of the map.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean containsValue(Object value) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (value==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getValue()==null)
+                    return true;
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (value.equals(e.getValue()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching
+     * for an entry with the specified key.  If such an entry is found,
+     * <tt>true</tt> is returned.  If the iteration terminates without
+     * finding such an entry, <tt>false</tt> is returned.  Note that this
+     * implementation requires linear time in the size of the map; many
+     * implementations will override this method.
+     *
+     * @throws ClassCastException   {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean containsKey(Object key) {
+        Iterator<Map.Entry<K,V>> i = entrySet().iterator();
+        if (key==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    return true;
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching
+     * for an entry with the specified key.  If such an entry is found,
+     * the entry's value is returned.  If the iteration terminates without
+     * finding such an entry, <tt>null</tt> is returned.  Note that this
+     * implementation requires linear time in the size of the map; many
+     * implementations will override this method.
+     *
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public V get(Object key) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (key==null) {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    return e.getValue();
+            }
+        } else {
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    return e.getValue();
+            }
+        }
+        return null;
+    }
+
+
+    // Modification Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation always throws an
+     * <tt>UnsupportedOperationException</tt>.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public V put(K key, V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt> searching for an
+     * entry with the specified key.  If such an entry is found, its value is
+     * obtained with its <tt>getValue</tt> operation, the entry is removed
+     * from the collection (and the backing map) with the iterator's
+     * <tt>remove</tt> operation, and the saved value is returned.  If the
+     * iteration terminates without finding such an entry, <tt>null</tt> is
+     * returned.  Note that this implementation requires linear time in the
+     * size of the map; many implementations will override this method.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
+     * iterator does not support the <tt>remove</tt> method and this map
+     * contains a mapping for the specified key.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     */
+    public V remove(Object key) {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        Entry<K,V> correctEntry = null;
+        if (key==null) {
+            while (correctEntry==null && i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (e.getKey()==null)
+                    correctEntry = e;
+            }
+        } else {
+            while (correctEntry==null && i.hasNext()) {
+                Entry<K,V> e = i.next();
+                if (key.equals(e.getKey()))
+                    correctEntry = e;
+            }
+        }
+
+        V oldValue = null;
+        if (correctEntry !=null) {
+            oldValue = correctEntry.getValue();
+            i.remove();
+        }
+        return oldValue;
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation iterates over the specified map's
+     * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
+     * operation once for each entry returned by the iteration.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if this map does not support
+     * the <tt>put</tt> operation and the specified map is nonempty.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation calls <tt>entrySet().clear()</tt>.
+     *
+     * <p>Note that this implementation throws an
+     * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
+     * does not support the <tt>clear</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     */
+    public void clear() {
+        entrySet().clear();
+    }
+
+
+    // Views
+
+    /**
+     * Each of these fields are initialized to contain an instance of the
+     * appropriate view the first time this view is requested.  The views are
+     * stateless, so there's no reason to create more than one of each.
+     *
+     * <p>Since there is no synchronization performed while accessing these fields,
+     * it is expected that java.util.Map view classes using these fields have
+     * no non-final fields (or any fields at all except for outer-this). Adhering
+     * to this rule would make the races on these fields benign.
+     *
+     * <p>It is also imperative that implementations read the field only once,
+     * as in:
+     *
+     * <pre> {@code
+     * public Set<K> keySet() {
+     *   Set<K> ks = keySet;  // single racy read
+     *   if (ks == null) {
+     *     ks = new KeySet();
+     *     keySet = ks;
+     *   }
+     *   return ks;
+     * }
+     *}</pre>
+     */
+    transient Set<K>        keySet;
+    transient Collection<V> values;
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a set that subclasses {@link AbstractSet}.
+     * The subclass's iterator method returns a "wrapper object" over this
+     * map's <tt>entrySet()</tt> iterator.  The <tt>size</tt> method
+     * delegates to this map's <tt>size</tt> method and the
+     * <tt>contains</tt> method delegates to this map's
+     * <tt>containsKey</tt> method.
+     *
+     * <p>The set is created the first time this method is called,
+     * and returned in response to all subsequent calls.  No synchronization
+     * is performed, so there is a slight chance that multiple calls to this
+     * method will not all return the same set.
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new AbstractSet<K>() {
+                public Iterator<K> iterator() {
+                    return new Iterator<K>() {
+                        private Iterator<Entry<K,V>> i = entrySet().iterator();
+
+                        public boolean hasNext() {
+                            return i.hasNext();
+                        }
+
+                        public K next() {
+                            return i.next().getKey();
+                        }
+
+                        public void remove() {
+                            i.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return AbstractMap.this.size();
+                }
+
+                public boolean isEmpty() {
+                    return AbstractMap.this.isEmpty();
+                }
+
+                public void clear() {
+                    AbstractMap.this.clear();
+                }
+
+                public boolean contains(Object k) {
+                    return AbstractMap.this.containsKey(k);
+                }
+            };
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * This implementation returns a collection that subclasses {@link
+     * AbstractCollection}.  The subclass's iterator method returns a
+     * "wrapper object" over this map's <tt>entrySet()</tt> iterator.
+     * The <tt>size</tt> method delegates to this map's <tt>size</tt>
+     * method and the <tt>contains</tt> method delegates to this map's
+     * <tt>containsValue</tt> method.
+     *
+     * <p>The collection is created the first time this method is called, and
+     * returned in response to all subsequent calls.  No synchronization is
+     * performed, so there is a slight chance that multiple calls to this
+     * method will not all return the same collection.
+     */
+    public Collection<V> values() {
+        Collection<V> vals = values;
+        if (vals == null) {
+            vals = new AbstractCollection<V>() {
+                public Iterator<V> iterator() {
+                    return new Iterator<V>() {
+                        private Iterator<Entry<K,V>> i = entrySet().iterator();
+
+                        public boolean hasNext() {
+                            return i.hasNext();
+                        }
+
+                        public V next() {
+                            return i.next().getValue();
+                        }
+
+                        public void remove() {
+                            i.remove();
+                        }
+                    };
+                }
+
+                public int size() {
+                    return AbstractMap.this.size();
+                }
+
+                public boolean isEmpty() {
+                    return AbstractMap.this.isEmpty();
+                }
+
+                public void clear() {
+                    AbstractMap.this.clear();
+                }
+
+                public boolean contains(Object v) {
+                    return AbstractMap.this.containsValue(v);
+                }
+            };
+            values = vals;
+        }
+        return vals;
+    }
+
+    public abstract Set<Entry<K,V>> entrySet();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * <tt>true</tt> if the given object is also a map and the two maps
+     * represent the same mappings.  More formally, two maps <tt>m1</tt> and
+     * <tt>m2</tt> represent the same mappings if
+     * <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
+     * <tt>equals</tt> method works properly across different implementations
+     * of the <tt>Map</tt> interface.
+     *
+     * @implSpec
+     * This implementation first checks if the specified object is this map;
+     * if so it returns <tt>true</tt>.  Then, it checks if the specified
+     * object is a map whose size is identical to the size of this map; if
+     * not, it returns <tt>false</tt>.  If so, it iterates over this map's
+     * <tt>entrySet</tt> collection, and checks that the specified map
+     * contains each mapping that this map contains.  If the specified map
+     * fails to contain such a mapping, <tt>false</tt> is returned.  If the
+     * iteration completes, <tt>true</tt> is returned.
+     *
+     * @param o object to be compared for equality with this map
+     * @return <tt>true</tt> if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> m = (Map<?,?>) o;
+        if (m.size() != size())
+            return false;
+
+        try {
+            Iterator<Entry<K,V>> i = entrySet().iterator();
+            while (i.hasNext()) {
+                Entry<K,V> e = i.next();
+                K key = e.getKey();
+                V value = e.getValue();
+                if (value == null) {
+                    if (!(m.get(key)==null && m.containsKey(key)))
+                        return false;
+                } else {
+                    if (!value.equals(m.get(key)))
+                        return false;
+                }
+            }
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
+     * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two maps
+     * <tt>m1</tt> and <tt>m2</tt>, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @implSpec
+     * This implementation iterates over <tt>entrySet()</tt>, calling
+     * {@link Map.Entry#hashCode hashCode()} on each element (entry) in the
+     * set, and adding up the results.
+     *
+     * @return the hash code value for this map
+     * @see Map.Entry#hashCode()
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    public int hashCode() {
+        int h = 0;
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        while (i.hasNext())
+            h += i.next().hashCode();
+        return h;
+    }
+
+    /**
+     * Returns a string representation of this map.  The string representation
+     * consists of a list of key-value mappings in the order returned by the
+     * map's <tt>entrySet</tt> view's iterator, enclosed in braces
+     * (<tt>"{}"</tt>).  Adjacent mappings are separated by the characters
+     * <tt>", "</tt> (comma and space).  Each key-value mapping is rendered as
+     * the key followed by an equals sign (<tt>"="</tt>) followed by the
+     * associated value.  Keys and values are converted to strings as by
+     * {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this map
+     */
+    public String toString() {
+        Iterator<Entry<K,V>> i = entrySet().iterator();
+        if (! i.hasNext())
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        for (;;) {
+            Entry<K,V> e = i.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == this ? "(this Map)" : key);
+            sb.append('=');
+            sb.append(value == this ? "(this Map)" : value);
+            if (! i.hasNext())
+                return sb.append('}').toString();
+            sb.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
+     * and values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    protected Object clone() throws CloneNotSupportedException {
+        AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
+        result.keySet = null;
+        result.values = null;
+        return result;
+    }
+
+    /**
+     * Utility method for SimpleEntry and SimpleImmutableEntry.
+     * Test for equality, checking for nulls.
+     *
+     * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
+     */
+    private static boolean eq(Object o1, Object o2) {
+        return o1 == null ? o2 == null : o1.equals(o2);
+    }
+
+    // Implementation Note: SimpleEntry and SimpleImmutableEntry
+    // are distinct unrelated classes, even though they share
+    // some code. Since you can't add or subtract final-ness
+    // of a field in a subclass, they can't share representations,
+    // and the amount of duplicated code is too small to warrant
+    // exposing a common abstract class.
+
+
+    /**
+     * An Entry maintaining a key and a value.  The value may be
+     * changed using the <tt>setValue</tt> method.  This class
+     * facilitates the process of building custom map
+     * implementations. For example, it may be convenient to return
+     * arrays of <tt>SimpleEntry</tt> instances in method
+     * <tt>Map.entrySet().toArray</tt>.
+     *
+     * @since 1.6
+     */
+    public static class SimpleEntry<K,V>
+        implements Entry<K,V>, java.io.Serializable
+    {
+        private static final long serialVersionUID = -8499721149061103585L;
+
+        private final K key;
+        private V value;
+
+        /**
+         * Creates an entry representing a mapping from the specified
+         * key to the specified value.
+         *
+         * @param key the key represented by this entry
+         * @param value the value represented by this entry
+         */
+        public SimpleEntry(K key, V value) {
+            this.key   = key;
+            this.value = value;
+        }
+
+        /**
+         * Creates an entry representing the same mapping as the
+         * specified entry.
+         *
+         * @param entry the entry to copy
+         */
+        public SimpleEntry(Entry<? extends K, ? extends V> entry) {
+            this.key   = entry.getKey();
+            this.value = entry.getValue();
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value corresponding to this entry.
+         *
+         * @return the value corresponding to this entry
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value.
+         *
+         * @param value new value to be stored in this entry
+         * @return the old value corresponding to the entry
+         */
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &amp;&amp;
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))</pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         * @see    #hashCode
+         */
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            return eq(key, e.getKey()) && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@link Object#hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see    #equals
+         */
+        public int hashCode() {
+            return (key   == null ? 0 :   key.hashCode()) ^
+                   (value == null ? 0 : value.hashCode());
+        }
+
+        /**
+         * Returns a String representation of this map entry.  This
+         * implementation returns the string representation of this
+         * entry's key followed by the equals character ("<tt>=</tt>")
+         * followed by the string representation of this entry's value.
+         *
+         * @return a String representation of this map entry
+         */
+        public String toString() {
+            return key + "=" + value;
+        }
+
+    }
+
+    /**
+     * An Entry maintaining an immutable key and value.  This class
+     * does not support method <tt>setValue</tt>.  This class may be
+     * convenient in methods that return thread-safe snapshots of
+     * key-value mappings.
+     *
+     * @since 1.6
+     */
+    public static class SimpleImmutableEntry<K,V>
+        implements Entry<K,V>, java.io.Serializable
+    {
+        private static final long serialVersionUID = 7138329143949025153L;
+
+        private final K key;
+        private final V value;
+
+        /**
+         * Creates an entry representing a mapping from the specified
+         * key to the specified value.
+         *
+         * @param key the key represented by this entry
+         * @param value the value represented by this entry
+         */
+        public SimpleImmutableEntry(K key, V value) {
+            this.key   = key;
+            this.value = value;
+        }
+
+        /**
+         * Creates an entry representing the same mapping as the
+         * specified entry.
+         *
+         * @param entry the entry to copy
+         */
+        public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
+            this.key   = entry.getKey();
+            this.value = entry.getValue();
+        }
+
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value corresponding to this entry.
+         *
+         * @return the value corresponding to this entry
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value (optional operation).  This implementation simply throws
+         * <tt>UnsupportedOperationException</tt>, as this class implements
+         * an <i>immutable</i> map entry.
+         *
+         * @param value new value to be stored in this entry
+         * @return (Does not return)
+         * @throws UnsupportedOperationException always
+         */
+        public V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *   (e1.getKey()==null ?
+         *    e2.getKey()==null :
+         *    e1.getKey().equals(e2.getKey()))
+         *   &amp;&amp;
+         *   (e1.getValue()==null ?
+         *    e2.getValue()==null :
+         *    e1.getValue().equals(e2.getValue()))</pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         * @see    #hashCode
+         */
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            return eq(key, e.getKey()) && eq(value, e.getValue());
+        }
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *   (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *   (e.getValue()==null ? 0 : e.getValue().hashCode())</pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@link Object#hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see    #equals
+         */
+        public int hashCode() {
+            return (key   == null ? 0 :   key.hashCode()) ^
+                   (value == null ? 0 : value.hashCode());
+        }
+
+        /**
+         * Returns a String representation of this map entry.  This
+         * implementation returns the string representation of this
+         * entry's key followed by the equals character ("<tt>=</tt>")
+         * followed by the string representation of this entry's value.
+         *
+         * @return a String representation of this map entry
+         */
+        public String toString() {
+            return key + "=" + value;
+        }
+
+    }
+
+}
diff --git a/java/util/AbstractQueue.java b/java/util/AbstractQueue.java
new file mode 100644
index 0000000..dd31ed2
--- /dev/null
+++ b/java/util/AbstractQueue.java
@@ -0,0 +1,192 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * This class provides skeletal implementations of some {@link Queue}
+ * operations. The implementations in this class are appropriate when
+ * the base implementation does <em>not</em> allow {@code null}
+ * elements.  Methods {@link #add add}, {@link #remove remove}, and
+ * {@link #element element} are based on {@link #offer offer}, {@link
+ * #poll poll}, and {@link #peek peek}, respectively, but throw
+ * exceptions instead of indicating failure via {@code false} or
+ * {@code null} returns.
+ *
+ * <p>A {@code Queue} implementation that extends this class must
+ * minimally define a method {@link Queue#offer} which does not permit
+ * insertion of {@code null} elements, along with methods {@link
+ * Queue#peek}, {@link Queue#poll}, {@link Collection#size}, and
+ * {@link Collection#iterator}.  Typically, additional methods will be
+ * overridden as well.  If these requirements cannot be met, consider
+ * instead subclassing {@link AbstractCollection}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public abstract class AbstractQueue<E>
+    extends AbstractCollection<E>
+    implements Queue<E> {
+
+    /**
+     * Constructor for use by subclasses.
+     */
+    protected AbstractQueue() {
+    }
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an {@code IllegalStateException}
+     * if no space is currently available.
+     *
+     * <p>This implementation returns {@code true} if {@code offer} succeeds,
+     * else throws an {@code IllegalStateException}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    public boolean add(E e) {
+        if (offer(e))
+            return true;
+        else
+            throw new IllegalStateException("Queue full");
+    }
+
+    /**
+     * Retrieves and removes the head of this queue.  This method differs
+     * from {@link #poll poll} only in that it throws an exception if this
+     * queue is empty.
+     *
+     * <p>This implementation returns the result of {@code poll}
+     * unless the queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    public E remove() {
+        E x = poll();
+        if (x != null)
+            return x;
+        else
+            throw new NoSuchElementException();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.  This method
+     * differs from {@link #peek peek} only in that it throws an exception if
+     * this queue is empty.
+     *
+     * <p>This implementation returns the result of {@code peek}
+     * unless the queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    public E element() {
+        E x = peek();
+        if (x != null)
+            return x;
+        else
+            throw new NoSuchElementException();
+    }
+
+    /**
+     * Removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     *
+     * <p>This implementation repeatedly invokes {@link #poll poll} until it
+     * returns {@code null}.
+     */
+    public void clear() {
+        while (poll() != null)
+            ;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this
+     * queue.  Attempts to addAll of a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * <p>This implementation iterates over the specified collection,
+     * and adds each element returned by the iterator to this
+     * queue, in turn.  A runtime exception encountered while
+     * trying to add an element (including, in particular, a
+     * {@code null} element) may result in only some of the elements
+     * having been successfully added when the associated exception is
+     * thrown.
+     *
+     * @param c collection containing elements to be added to this queue
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this queue
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this queue does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this
+     *         queue, or if the specified collection is this queue
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        boolean modified = false;
+        for (E e : c)
+            if (add(e))
+                modified = true;
+        return modified;
+    }
+
+}
diff --git a/java/util/AbstractSequentialList.annotated.java b/java/util/AbstractSequentialList.annotated.java
new file mode 100644
index 0000000..42c8127
--- /dev/null
+++ b/java/util/AbstractSequentialList.annotated.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractSequentialList<E> extends java.util.AbstractList<E> {
+
+protected AbstractSequentialList() { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public abstract java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index);
+}
diff --git a/java/util/AbstractSequentialList.java b/java/util/AbstractSequentialList.java
new file mode 100644
index 0000000..36a91da
--- /dev/null
+++ b/java/util/AbstractSequentialList.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the <tt>List</tt>
+ * interface to minimize the effort required to implement this interface
+ * backed by a "sequential access" data store (such as a linked list).  For
+ * random access data (such as an array), <tt>AbstractList</tt> should be used
+ * in preference to this class.<p>
+ *
+ * This class is the opposite of the <tt>AbstractList</tt> class in the sense
+ * that it implements the "random access" methods (<tt>get(int index)</tt>,
+ * <tt>set(int index, E element)</tt>, <tt>add(int index, E element)</tt> and
+ * <tt>remove(int index)</tt>) on top of the list's list iterator, instead of
+ * the other way around.<p>
+ *
+ * To implement a list the programmer needs only to extend this class and
+ * provide implementations for the <tt>listIterator</tt> and <tt>size</tt>
+ * methods.  For an unmodifiable list, the programmer need only implement the
+ * list iterator's <tt>hasNext</tt>, <tt>next</tt>, <tt>hasPrevious</tt>,
+ * <tt>previous</tt> and <tt>index</tt> methods.<p>
+ *
+ * For a modifiable list the programmer should additionally implement the list
+ * iterator's <tt>set</tt> method.  For a variable-size list the programmer
+ * should additionally implement the list iterator's <tt>remove</tt> and
+ * <tt>add</tt> methods.<p>
+ *
+ * The programmer should generally provide a void (no argument) and collection
+ * constructor, as per the recommendation in the <tt>Collection</tt> interface
+ * specification.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see List
+ * @see AbstractList
+ * @see AbstractCollection
+ * @since 1.2
+ */
+
+public abstract class AbstractSequentialList<E> extends AbstractList<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractSequentialList() {
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it gets
+     * the element using <tt>ListIterator.next</tt> and returns it.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        try {
+            return listIterator(index).next();
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element (optional operation).
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it gets
+     * the current element using <tt>ListIterator.next</tt> and replaces it
+     * with <tt>ListIterator.set</tt>.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator does not
+     * implement the <tt>set</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        try {
+            ListIterator<E> e = listIterator(index);
+            E oldVal = e.next();
+            e.set(element);
+            return oldVal;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list
+     * (optional operation).  Shifts the element currently at that position
+     * (if any) and any subsequent elements to the right (adds one to their
+     * indices).
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it
+     * inserts the specified element with <tt>ListIterator.add</tt>.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator does not
+     * implement the <tt>add</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        try {
+            listIterator(index).add(element);
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list (optional
+     * operation).  Shifts any subsequent elements to the left (subtracts one
+     * from their indices).  Returns the element that was removed from the
+     * list.
+     *
+     * <p>This implementation first gets a list iterator pointing to the
+     * indexed element (with <tt>listIterator(index)</tt>).  Then, it removes
+     * the element with <tt>ListIterator.remove</tt>.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator does not
+     * implement the <tt>remove</tt> operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public E remove(int index) {
+        try {
+            ListIterator<E> e = listIterator(index);
+            E outCast = e.next();
+            e.remove();
+            return outCast;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+
+    // Bulk Operations
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list at the specified position (optional operation).  Shifts the
+     * element currently at that position (if any) and any subsequent
+     * elements to the right (increases their indices).  The new elements
+     * will appear in this list in the order that they are returned by the
+     * specified collection's iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.  (Note that this will occur if the specified
+     * collection is this list, and it's nonempty.)
+     *
+     * <p>This implementation gets an iterator over the specified collection and
+     * a list iterator over this list pointing to the indexed element (with
+     * <tt>listIterator(index)</tt>).  Then, it iterates over the specified
+     * collection, inserting the elements obtained from the iterator into this
+     * list, one at a time, using <tt>ListIterator.add</tt> followed by
+     * <tt>ListIterator.next</tt> (to skip over the added element).
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the list iterator returned by
+     * the <tt>listIterator</tt> method does not implement the <tt>add</tt>
+     * operation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     * @throws IndexOutOfBoundsException     {@inheritDoc}
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        try {
+            boolean modified = false;
+            ListIterator<E> e1 = listIterator(index);
+            Iterator<? extends E> e2 = c.iterator();
+            while (e2.hasNext()) {
+                e1.add(e2.next());
+                modified = true;
+            }
+            return modified;
+        } catch (NoSuchElementException exc) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+    }
+
+
+    // Iterators
+
+    /**
+     * Returns an iterator over the elements in this list (in proper
+     * sequence).<p>
+     *
+     * This implementation merely returns a list iterator over the list.
+     *
+     * @return an iterator over the elements in this list (in proper sequence)
+     */
+    public Iterator<E> iterator() {
+        return listIterator();
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * @param  index index of first element to be returned from the list
+     *         iterator (by a call to the <code>next</code> method)
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence)
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public abstract ListIterator<E> listIterator(int index);
+}
diff --git a/java/util/AbstractSet.annotated.java b/java/util/AbstractSet.annotated.java
new file mode 100644
index 0000000..2281ee0
--- /dev/null
+++ b/java/util/AbstractSet.annotated.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class AbstractSet<E> extends java.util.AbstractCollection<E> implements java.util.Set<E> {
+
+protected AbstractSet() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/AbstractSet.java b/java/util/AbstractSet.java
new file mode 100644
index 0000000..b3fe0dc
--- /dev/null
+++ b/java/util/AbstractSet.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class provides a skeletal implementation of the <tt>Set</tt>
+ * interface to minimize the effort required to implement this
+ * interface. <p>
+ *
+ * The process of implementing a set by extending this class is identical
+ * to that of implementing a Collection by extending AbstractCollection,
+ * except that all of the methods and constructors in subclasses of this
+ * class must obey the additional constraints imposed by the <tt>Set</tt>
+ * interface (for instance, the add method must not permit addition of
+ * multiple instances of an object to a set).<p>
+ *
+ * Note that this class does not override any of the implementations from
+ * the <tt>AbstractCollection</tt> class.  It merely adds implementations
+ * for <tt>equals</tt> and <tt>hashCode</tt>.<p>
+ *
+ * This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see AbstractCollection
+ * @see Set
+ * @since 1.2
+ */
+
+public abstract class AbstractSet<E> extends AbstractCollection<E> implements Set<E> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected AbstractSet() {
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.  This ensures that the <tt>equals</tt> method works
+     * properly across different implementations of the <tt>Set</tt>
+     * interface.<p>
+     *
+     * This implementation first checks if the specified object is this
+     * set; if so it returns <tt>true</tt>.  Then, it checks if the
+     * specified object is a set whose size is identical to the size of
+     * this set; if not, it returns false.  If so, it returns
+     * <tt>containsAll((Collection) o)</tt>.
+     *
+     * @param o object to be compared for equality with this set
+     * @return <tt>true</tt> if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        if (c.size() != size())
+            return false;
+        try {
+            return containsAll(c);
+        } catch (ClassCastException unused)   {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the hash code value for this set.  The hash code of a set is
+     * defined to be the sum of the hash codes of the elements in the set,
+     * where the hash code of a <tt>null</tt> element is defined to be zero.
+     * This ensures that <tt>s1.equals(s2)</tt> implies that
+     * <tt>s1.hashCode()==s2.hashCode()</tt> for any two sets <tt>s1</tt>
+     * and <tt>s2</tt>, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * <p>This implementation iterates over the set, calling the
+     * <tt>hashCode</tt> method on each element in the set, and adding up
+     * the results.
+     *
+     * @return the hash code value for this set
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    public int hashCode() {
+        int h = 0;
+        Iterator<E> i = iterator();
+        while (i.hasNext()) {
+            E obj = i.next();
+            if (obj != null)
+                h += obj.hashCode();
+        }
+        return h;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection (optional operation).  If the specified
+     * collection is also a set, this operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     *
+     * <p>This implementation determines which is the smaller of this set
+     * and the specified collection, by invoking the <tt>size</tt>
+     * method on each.  If this set has fewer elements, then the
+     * implementation iterates over this set, checking each element
+     * returned by the iterator in turn to see if it is contained in
+     * the specified collection.  If it is so contained, it is removed
+     * from this set with the iterator's <tt>remove</tt> method.  If
+     * the specified collection has fewer elements, then the
+     * implementation iterates over the specified collection, removing
+     * from this set each element returned by the iterator, using this
+     * set's <tt>remove</tt> method.
+     *
+     * <p>Note that this implementation will throw an
+     * <tt>UnsupportedOperationException</tt> if the iterator returned by the
+     * <tt>iterator</tt> method does not implement the <tt>remove</tt> method.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the <tt>removeAll</tt> operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        boolean modified = false;
+
+        if (size() > c.size()) {
+            for (Iterator<?> i = c.iterator(); i.hasNext(); )
+                modified |= remove(i.next());
+        } else {
+            for (Iterator<?> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+        }
+        return modified;
+    }
+
+}
diff --git a/java/util/ArrayDeque.annotated.java b/java/util/ArrayDeque.annotated.java
new file mode 100644
index 0000000..014b99c
--- /dev/null
+++ b/java/util/ArrayDeque.annotated.java
@@ -0,0 +1,113 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Josh Bloch of Google Inc. and released to the public domain,
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ArrayDeque<@libcore.util.NonNull E> extends java.util.AbstractCollection<E> implements java.util.Deque<E>, java.lang.Cloneable, java.io.Serializable {
+
+public ArrayDeque() { throw new RuntimeException("Stub!"); }
+
+public ArrayDeque(int numElements) { throw new RuntimeException("Stub!"); }
+
+public ArrayDeque(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void addFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void addLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E getFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E getLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekLast() { throw new RuntimeException("Stub!"); }
+
+public boolean removeFirstOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean removeLastOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offer(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove() { throw new RuntimeException("Stub!"); }
+
[email protected] public E poll() { throw new RuntimeException("Stub!"); }
+
[email protected] public E element() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peek() { throw new RuntimeException("Stub!"); }
+
+public void push(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E pop() { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> descendingIterator() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ArrayDeque<@libcore.util.NullFromTypeParam E> clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/ArrayDeque.java b/java/util/ArrayDeque.java
new file mode 100644
index 0000000..b1fb41e
--- /dev/null
+++ b/java/util/ArrayDeque.java
@@ -0,0 +1,997 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Josh Bloch of Google Inc. and released to the public domain,
+ * as explained at http://creativecommons.org/publicdomain/zero/1.0/.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * Resizable-array implementation of the {@link Deque} interface.  Array
+ * deques have no capacity restrictions; they grow as necessary to support
+ * usage.  They are not thread-safe; in the absence of external
+ * synchronization, they do not support concurrent access by multiple threads.
+ * Null elements are prohibited.  This class is likely to be faster than
+ * {@link Stack} when used as a stack, and faster than {@link LinkedList}
+ * when used as a queue.
+ *
+ * <p>Most {@code ArrayDeque} operations run in amortized constant time.
+ * Exceptions include
+ * {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence},
+ * {@link #removeLastOccurrence removeLastOccurrence},
+ * {@link #contains contains},
+ * {@link #iterator iterator.remove()},
+ * and the bulk operations, all of which run in linear time.
+ *
+ * <p>The iterators returned by this class's {@link #iterator() iterator}
+ * method are <em>fail-fast</em>: If the deque is modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will generally throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the
+ * future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @since   1.6
+ * @param <E> the type of elements held in this deque
+ */
+public class ArrayDeque<E> extends AbstractCollection<E>
+                           implements Deque<E>, Cloneable, Serializable
+{
+    /**
+     * The array in which the elements of the deque are stored.
+     * The capacity of the deque is the length of this array, which is
+     * always a power of two. The array is never allowed to become
+     * full, except transiently within an addX method where it is
+     * resized (see doubleCapacity) immediately upon becoming full,
+     * thus avoiding head and tail wrapping around to equal each
+     * other.  We also guarantee that all array cells not holding
+     * deque elements are always null.
+     */
+    transient Object[] elements; // non-private to simplify nested class access
+
+    /**
+     * The index of the element at the head of the deque (which is the
+     * element that would be removed by remove() or pop()); or an
+     * arbitrary number equal to tail if the deque is empty.
+     */
+    transient int head;
+
+    /**
+     * The index at which the next element would be added to the tail
+     * of the deque (via addLast(E), add(E), or push(E)).
+     */
+    transient int tail;
+
+    /**
+     * The minimum capacity that we'll use for a newly created deque.
+     * Must be a power of 2.
+     */
+    private static final int MIN_INITIAL_CAPACITY = 8;
+
+    // ******  Array allocation and resizing utilities ******
+
+    /**
+     * Allocates empty array to hold the given number of elements.
+     *
+     * @param numElements  the number of elements to hold
+     */
+    private void allocateElements(int numElements) {
+        int initialCapacity = MIN_INITIAL_CAPACITY;
+        // Find the best power of two to hold elements.
+        // Tests "<=" because arrays aren't kept full.
+        if (numElements >= initialCapacity) {
+            initialCapacity = numElements;
+            initialCapacity |= (initialCapacity >>>  1);
+            initialCapacity |= (initialCapacity >>>  2);
+            initialCapacity |= (initialCapacity >>>  4);
+            initialCapacity |= (initialCapacity >>>  8);
+            initialCapacity |= (initialCapacity >>> 16);
+            initialCapacity++;
+
+            if (initialCapacity < 0)    // Too many elements, must back off
+                initialCapacity >>>= 1; // Good luck allocating 2^30 elements
+        }
+        elements = new Object[initialCapacity];
+    }
+
+    /**
+     * Doubles the capacity of this deque.  Call only when full, i.e.,
+     * when head and tail have wrapped around to become equal.
+     */
+    private void doubleCapacity() {
+        assert head == tail;
+        int p = head;
+        int n = elements.length;
+        int r = n - p; // number of elements to the right of p
+        int newCapacity = n << 1;
+        if (newCapacity < 0)
+            throw new IllegalStateException("Sorry, deque too big");
+        Object[] a = new Object[newCapacity];
+        System.arraycopy(elements, p, a, 0, r);
+        System.arraycopy(elements, 0, a, r, p);
+        // Android-added: Clear old array instance that's about to become eligible for GC.
+        // This ensures that array elements can be eligible for garbage collection even
+        // before the array itself is recognized as being eligible; the latter might
+        // take a while in some GC implementations, if the array instance is longer lived
+        // (its liveness rarely checked) than some of its contents.
+        Arrays.fill(elements, null);
+        elements = a;
+        head = 0;
+        tail = n;
+    }
+
+    /**
+     * Constructs an empty array deque with an initial capacity
+     * sufficient to hold 16 elements.
+     */
+    public ArrayDeque() {
+        elements = new Object[16];
+    }
+
+    /**
+     * Constructs an empty array deque with an initial capacity
+     * sufficient to hold the specified number of elements.
+     *
+     * @param numElements  lower bound on initial capacity of the deque
+     */
+    public ArrayDeque(int numElements) {
+        allocateElements(numElements);
+    }
+
+    /**
+     * Constructs a deque containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.  (The first element returned by the collection's
+     * iterator becomes the first element, or <i>front</i> of the
+     * deque.)
+     *
+     * @param c the collection whose elements are to be placed into the deque
+     * @throws NullPointerException if the specified collection is null
+     */
+    public ArrayDeque(Collection<? extends E> c) {
+        allocateElements(c.size());
+        addAll(c);
+    }
+
+    // The main insertion and extraction methods are addFirst,
+    // addLast, pollFirst, pollLast. The other methods are defined in
+    // terms of these.
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     *
+     * @param e the element to add
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addFirst(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        elements[head = (head - 1) & (elements.length - 1)] = e;
+        if (head == tail)
+            doubleCapacity();
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addLast(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        elements[tail] = e;
+        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
+            doubleCapacity();
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerFirst(E e) {
+        addFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerLast(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        E x = pollFirst();
+        if (x == null)
+            throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        E x = pollLast();
+        if (x == null)
+            throw new NoSuchElementException();
+        return x;
+    }
+
+    public E pollFirst() {
+        final Object[] elements = this.elements;
+        final int h = head;
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[h];
+        // Element is null if deque empty
+        if (result != null) {
+            elements[h] = null; // Must null out slot
+            head = (h + 1) & (elements.length - 1);
+        }
+        return result;
+    }
+
+    public E pollLast() {
+        final Object[] elements = this.elements;
+        final int t = (tail - 1) & (elements.length - 1);
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[t];
+        if (result != null) {
+            elements[t] = null;
+            tail = t;
+        }
+        return result;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[head];
+        if (result == null)
+            throw new NoSuchElementException();
+        return result;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        @SuppressWarnings("unchecked")
+        E result = (E) elements[(tail - 1) & (elements.length - 1)];
+        if (result == null)
+            throw new NoSuchElementException();
+        return result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public E peekFirst() {
+        // elements[head] is null if deque empty
+        return (E) elements[head];
+    }
+
+    @SuppressWarnings("unchecked")
+    public E peekLast() {
+        return (E) elements[(tail - 1) & (elements.length - 1)];
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this
+     * deque (when traversing the deque from head to tail).
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        if (o != null) {
+            int mask = elements.length - 1;
+            int i = head;
+            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
+                if (o.equals(x)) {
+                    delete(i);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the last occurrence of the specified element in this
+     * deque (when traversing the deque from head to tail).
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     */
+    public boolean removeLastOccurrence(Object o) {
+        if (o != null) {
+            int mask = elements.length - 1;
+            int i = (tail - 1) & mask;
+            for (Object x; (x = elements[i]) != null; i = (i - 1) & mask) {
+                if (o.equals(x)) {
+                    delete(i);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    // *** Queue methods ***
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     *
+     * <p>This method is equivalent to {@link #offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque.
+     *
+     * This method differs from {@link #poll poll} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    public E poll() {
+        return pollFirst();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque.  This method differs from {@link #peek peek} only in
+     * that it throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque, or returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    public E peek() {
+        return peekFirst();
+    }
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque.  In other
+     * words, inserts the element at the front of this deque.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @throws NullPointerException if the specified element is null
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * Pops an element from the stack represented by this deque.  In other
+     * words, removes and returns the first element of this deque.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this deque (which is the top
+     *         of the stack represented by this deque)
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    private void checkInvariants() {
+        assert elements[tail] == null;
+        assert head == tail ? elements[head] == null :
+            (elements[head] != null &&
+             elements[(tail - 1) & (elements.length - 1)] != null);
+        assert elements[(head - 1) & (elements.length - 1)] == null;
+    }
+
+    /**
+     * Removes the element at the specified position in the elements array,
+     * adjusting head and tail as necessary.  This can result in motion of
+     * elements backwards or forwards in the array.
+     *
+     * <p>This method is called delete rather than remove to emphasize
+     * that its semantics differ from those of {@link List#remove(int)}.
+     *
+     * @return true if elements moved backwards
+     */
+    boolean delete(int i) {
+        checkInvariants();
+        final Object[] elements = this.elements;
+        final int mask = elements.length - 1;
+        final int h = head;
+        final int t = tail;
+        final int front = (i - h) & mask;
+        final int back  = (t - i) & mask;
+
+        // Invariant: head <= i < tail mod circularity
+        if (front >= ((t - h) & mask))
+            throw new ConcurrentModificationException();
+
+        // Optimize for least element motion
+        if (front < back) {
+            if (h <= i) {
+                System.arraycopy(elements, h, elements, h + 1, front);
+            } else { // Wrap around
+                System.arraycopy(elements, 0, elements, 1, i);
+                elements[0] = elements[mask];
+                System.arraycopy(elements, h, elements, h + 1, mask - h);
+            }
+            elements[h] = null;
+            head = (h + 1) & mask;
+            return false;
+        } else {
+            if (i < t) { // Copy the null tail as well
+                System.arraycopy(elements, i + 1, elements, i, back);
+                tail = t - 1;
+            } else { // Wrap around
+                System.arraycopy(elements, i + 1, elements, i, mask - i);
+                elements[mask] = elements[0];
+                System.arraycopy(elements, 1, elements, 0, t);
+                tail = (t - 1) & mask;
+            }
+            return true;
+        }
+    }
+
+    // *** Collection Methods ***
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        return (tail - head) & (elements.length - 1);
+    }
+
+    /**
+     * Returns {@code true} if this deque contains no elements.
+     *
+     * @return {@code true} if this deque contains no elements
+     */
+    public boolean isEmpty() {
+        return head == tail;
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque.  The elements
+     * will be ordered from first (head) to last (tail).  This is the same
+     * order that elements would be dequeued (via successive calls to
+     * {@link #remove} or popped (via successive calls to {@link #pop}).
+     *
+     * @return an iterator over the elements in this deque
+     */
+    public Iterator<E> iterator() {
+        return new DeqIterator();
+    }
+
+    public Iterator<E> descendingIterator() {
+        return new DescendingIterator();
+    }
+
+    private class DeqIterator implements Iterator<E> {
+        /**
+         * Index of element to be returned by subsequent call to next.
+         */
+        private int cursor = head;
+
+        /**
+         * Tail recorded at construction (also in remove), to stop
+         * iterator and also to check for comodification.
+         */
+        private int fence = tail;
+
+        /**
+         * Index of element returned by most recent call to next.
+         * Reset to -1 if element is deleted by a call to remove.
+         */
+        private int lastRet = -1;
+
+        public boolean hasNext() {
+            return cursor != fence;
+        }
+
+        public E next() {
+            if (cursor == fence)
+                throw new NoSuchElementException();
+            @SuppressWarnings("unchecked")
+            E result = (E) elements[cursor];
+            // This check doesn't catch all possible comodifications,
+            // but does catch the ones that corrupt traversal
+            if (tail != fence || result == null)
+                throw new ConcurrentModificationException();
+            lastRet = cursor;
+            cursor = (cursor + 1) & (elements.length - 1);
+            return result;
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (delete(lastRet)) { // if left-shifted, undo increment in next()
+                cursor = (cursor - 1) & (elements.length - 1);
+                fence = tail;
+            }
+            lastRet = -1;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            Object[] a = elements;
+            int m = a.length - 1, f = fence, i = cursor;
+            cursor = f;
+            while (i != f) {
+                @SuppressWarnings("unchecked") E e = (E)a[i];
+                i = (i + 1) & m;
+                // Android-note: This uses a different heuristic for detecting
+                // concurrent modification exceptions than next(). As such, this is a less
+                // precise test.
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                action.accept(e);
+            }
+        }
+    }
+
+    /**
+     * This class is nearly a mirror-image of DeqIterator, using tail
+     * instead of head for initial cursor, and head instead of tail
+     * for fence.
+     */
+    private class DescendingIterator implements Iterator<E> {
+        private int cursor = tail;
+        private int fence = head;
+        private int lastRet = -1;
+
+        public boolean hasNext() {
+            return cursor != fence;
+        }
+
+        public E next() {
+            if (cursor == fence)
+                throw new NoSuchElementException();
+            cursor = (cursor - 1) & (elements.length - 1);
+            @SuppressWarnings("unchecked")
+            E result = (E) elements[cursor];
+            if (head != fence || result == null)
+                throw new ConcurrentModificationException();
+            lastRet = cursor;
+            return result;
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (!delete(lastRet)) {
+                cursor = (cursor + 1) & (elements.length - 1);
+                fence = head;
+            }
+            lastRet = -1;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            int mask = elements.length - 1;
+            int i = head;
+            for (Object x; (x = elements[i]) != null; i = (i + 1) & mask) {
+                if (o.equals(x))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque contained the specified element
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Removes all of the elements from this deque.
+     * The deque will be empty after this call returns.
+     */
+    public void clear() {
+        int h = head;
+        int t = tail;
+        if (h != t) { // clear all cells
+            head = tail = 0;
+            int i = h;
+            int mask = elements.length - 1;
+            do {
+                elements[i] = null;
+                i = (i + 1) & mask;
+            } while (i != t);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    public Object[] toArray() {
+        final int head = this.head;
+        final int tail = this.tail;
+        boolean wrap = (tail < head);
+        int end = wrap ? tail + elements.length : tail;
+        Object[] a = Arrays.copyOfRange(elements, head, end);
+        if (wrap)
+            System.arraycopy(elements, 0, a, elements.length - head, tail);
+        return a;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque in
+     * proper sequence (from first to last element); the runtime type of the
+     * returned array is that of the specified array.  If the deque fits in
+     * the specified array, it is returned therein.  Otherwise, a new array
+     * is allocated with the runtime type of the specified array and the
+     * size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final int head = this.head;
+        final int tail = this.tail;
+        boolean wrap = (tail < head);
+        int size = (tail - head) + (wrap ? elements.length : 0);
+        int firstLeg = size - (wrap ? tail : 0);
+        int len = a.length;
+        if (size > len) {
+            a = (T[]) Arrays.copyOfRange(elements, head, head + size,
+                                         a.getClass());
+        } else {
+            System.arraycopy(elements, head, a, 0, firstLeg);
+            if (size < len)
+                a[size] = null;
+        }
+        if (wrap)
+            System.arraycopy(elements, 0, a, firstLeg, tail);
+        return a;
+    }
+
+    // *** Object methods ***
+
+    /**
+     * Returns a copy of this deque.
+     *
+     * @return a copy of this deque
+     */
+    public ArrayDeque<E> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ArrayDeque<E> result = (ArrayDeque<E>) super.clone();
+            result.elements = Arrays.copyOf(elements, elements.length);
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+    }
+
+    private static final long serialVersionUID = 2340985798034038923L;
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The current size ({@code int}) of the deque,
+     * followed by all of its elements (each an object reference) in
+     * first-to-last order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        s.defaultWriteObject();
+
+        // Write out size
+        s.writeInt(size());
+
+        // Write out elements in order.
+        int mask = elements.length - 1;
+        for (int i = head; i != tail; i = (i + 1) & mask)
+            s.writeObject(elements[i]);
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in size and allocate array
+        int size = s.readInt();
+        allocateElements(size);
+        head = 0;
+        tail = size;
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < size; i++)
+            elements[i] = s.readObject();
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#NONNULL}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new DeqSpliterator<>(this, -1, -1);
+    }
+
+    static final class DeqSpliterator<E> implements Spliterator<E> {
+        private final ArrayDeque<E> deq;
+        private int fence;  // -1 until first use
+        private int index;  // current index, modified on traverse/split
+
+        /** Creates new spliterator covering the given array and range. */
+        DeqSpliterator(ArrayDeque<E> deq, int origin, int fence) {
+            this.deq = deq;
+            this.index = origin;
+            this.fence = fence;
+        }
+
+        private int getFence() { // force initialization
+            int t;
+            if ((t = fence) < 0) {
+                t = fence = deq.tail;
+                index = deq.head;
+            }
+            return t;
+        }
+
+        public DeqSpliterator<E> trySplit() {
+            int t = getFence(), h = index, n = deq.elements.length;
+            if (h != t && ((h + 1) & (n - 1)) != t) {
+                if (h > t)
+                    t += n;
+                int m = ((h + t) >>> 1) & (n - 1);
+                return new DeqSpliterator<E>(deq, h, index = m);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> consumer) {
+            if (consumer == null)
+                throw new NullPointerException();
+            Object[] a = deq.elements;
+            int m = a.length - 1, f = getFence(), i = index;
+            index = f;
+            while (i != f) {
+                @SuppressWarnings("unchecked") E e = (E)a[i];
+                i = (i + 1) & m;
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                consumer.accept(e);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> consumer) {
+            if (consumer == null)
+                throw new NullPointerException();
+            Object[] a = deq.elements;
+            int m = a.length - 1, f = getFence(), i = index;
+            if (i != f) {
+                @SuppressWarnings("unchecked") E e = (E)a[i];
+                index = (i + 1) & m;
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                consumer.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() {
+            int n = getFence() - index;
+            if (n < 0)
+                n += deq.elements.length;
+            return (long) n;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED |
+                Spliterator.NONNULL | Spliterator.SUBSIZED;
+        }
+    }
+
+}
diff --git a/java/util/ArrayList.annotated.java b/java/util/ArrayList.annotated.java
new file mode 100644
index 0000000..255c4be
--- /dev/null
+++ b/java/util/ArrayList.annotated.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ArrayList<E> extends java.util.AbstractList<E> implements java.util.List<E>, java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
+
+public ArrayList(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public ArrayList() { throw new RuntimeException("Stub!"); }
+
+public ArrayList(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void trimToSize() { throw new RuntimeException("Stub!"); }
+
+public void ensureCapacity(int minCapacity) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+// TODO: Make param and return types @Nullable T @NonNull [] once metalava supports TYPE_USE.
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+protected void removeRange(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+public boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/ArrayList.java b/java/util/ArrayList.java
new file mode 100644
index 0000000..20c623a
--- /dev/null
+++ b/java/util/ArrayList.java
@@ -0,0 +1,1476 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+/**
+ * Resizable-array implementation of the <tt>List</tt> interface.  Implements
+ * all optional list operations, and permits all elements, including
+ * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
+ * this class provides methods to manipulate the size of the array that is
+ * used internally to store the list.  (This class is roughly equivalent to
+ * <tt>Vector</tt>, except that it is unsynchronized.)
+ *
+ * <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
+ * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
+ * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
+ * that is, adding n elements requires O(n) time.  All of the other operations
+ * run in linear time (roughly speaking).  The constant factor is low compared
+ * to that for the <tt>LinkedList</tt> implementation.
+ *
+ * <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
+ * the size of the array used to store the elements in the list.  It is always
+ * at least as large as the list size.  As elements are added to an ArrayList,
+ * its capacity grows automatically.  The details of the growth policy are not
+ * specified beyond the fact that adding an element has constant amortized
+ * time cost.
+ *
+ * <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
+ * before adding a large number of elements using the <tt>ensureCapacity</tt>
+ * operation.  This may reduce the amount of incremental reallocation.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
+ * and at least one of the threads modifies the list structurally, it
+ * <i>must</i> be synchronized externally.  (A structural modification is
+ * any operation that adds or deletes one or more elements, or explicitly
+ * resizes the backing array; merely setting the value of an element is not
+ * a structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the list.
+ *
+ * If no such object exists, the list should be "wrapped" using the
+ * {@link Collections#synchronizedList Collections.synchronizedList}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the list:<pre>
+ *   List list = Collections.synchronizedList(new ArrayList(...));</pre>
+ *
+ * <p><a name="fail-fast">
+ * The iterators returned by this class's {@link #iterator() iterator} and
+ * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
+ * if the list is structurally modified at any time after the iterator is
+ * created, in any way except through the iterator's own
+ * {@link ListIterator#remove() remove} or
+ * {@link ListIterator#add(Object) add} methods, the iterator will throw a
+ * {@link ConcurrentModificationException}.  Thus, in the face of
+ * concurrent modification, the iterator fails quickly and cleanly, rather
+ * than risking arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:  <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     List
+ * @see     LinkedList
+ * @see     Vector
+ * @since   1.2
+ */
+// Android-changed: Inlined methods; CME in iterators; throw AIOOBE when toIndex < fromIndex.
+/*
+ * - AOSP commit 3be987f0f18648b3c532c8b89d09505e18594241
+ *   Inline for improved performance:
+ *   - checkForComodification
+ *   - elementData()
+ *   - rangeCheck()
+ *   - rangeCheckForAdd()
+ * - AOSP commit b10b2a3ab693cfd6156d06ffe4e00ce69b9c9194
+ *   Fix ConcurrentModificationException in ArrayList iterators.
+ * - AOSP commit a68b1a5ba82ef8cc19aafdce7d9c7f9631943f84
+ *   Throw AIOOBE when toIndex < fromIndex.
+ */
+public class ArrayList<E> extends AbstractList<E>
+        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
+{
+    private static final long serialVersionUID = 8683452581122892189L;
+
+    /**
+     * Default initial capacity.
+     */
+    private static final int DEFAULT_CAPACITY = 10;
+
+    /**
+     * Shared empty array instance used for empty instances.
+     */
+    private static final Object[] EMPTY_ELEMENTDATA = {};
+
+    /**
+     * Shared empty array instance used for default sized empty instances. We
+     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
+     * first element is added.
+     */
+    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
+
+    /**
+     * The array buffer into which the elements of the ArrayList are stored.
+     * The capacity of the ArrayList is the length of this array buffer. Any
+     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
+     * will be expanded to DEFAULT_CAPACITY when the first element is added.
+     */
+    // Android-note: Also accessed from java.util.Collections
+    transient Object[] elementData; // non-private to simplify nested class access
+
+    /**
+     * The size of the ArrayList (the number of elements it contains).
+     *
+     * @serial
+     */
+    private int size;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public ArrayList(int initialCapacity) {
+        if (initialCapacity > 0) {
+            this.elementData = new Object[initialCapacity];
+        } else if (initialCapacity == 0) {
+            this.elementData = EMPTY_ELEMENTDATA;
+        } else {
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        }
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of ten.
+     */
+    public ArrayList() {
+        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection whose elements are to be placed into this list
+     * @throws NullPointerException if the specified collection is null
+     */
+    public ArrayList(Collection<? extends E> c) {
+        elementData = c.toArray();
+        if ((size = elementData.length) != 0) {
+            // c.toArray might (incorrectly) not return Object[] (see 6260652)
+            if (elementData.getClass() != Object[].class)
+                elementData = Arrays.copyOf(elementData, size, Object[].class);
+        } else {
+            // replace with empty array.
+            this.elementData = EMPTY_ELEMENTDATA;
+        }
+    }
+
+    /**
+     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
+     * list's current size.  An application can use this operation to minimize
+     * the storage of an <tt>ArrayList</tt> instance.
+     */
+    public void trimToSize() {
+        modCount++;
+        if (size < elementData.length) {
+            elementData = (size == 0)
+              ? EMPTY_ELEMENTDATA
+              : Arrays.copyOf(elementData, size);
+        }
+    }
+
+    /**
+     * Increases the capacity of this <tt>ArrayList</tt> instance, if
+     * necessary, to ensure that it can hold at least the number of elements
+     * specified by the minimum capacity argument.
+     *
+     * @param   minCapacity   the desired minimum capacity
+     */
+    public void ensureCapacity(int minCapacity) {
+        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
+            // any size if not default element table
+            ? 0
+            // larger than default for default empty table. It's already
+            // supposed to be at default size.
+            : DEFAULT_CAPACITY;
+
+        if (minCapacity > minExpand) {
+            ensureExplicitCapacity(minCapacity);
+        }
+    }
+
+    private void ensureCapacityInternal(int minCapacity) {
+        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
+            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
+        }
+
+        ensureExplicitCapacity(minCapacity);
+    }
+
+    private void ensureExplicitCapacity(int minCapacity) {
+        modCount++;
+
+        // overflow-conscious code
+        if (minCapacity - elementData.length > 0)
+            grow(minCapacity);
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity to ensure that it can hold at least the
+     * number of elements specified by the minimum capacity argument.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    private void grow(int minCapacity) {
+        // overflow-conscious code
+        int oldCapacity = elementData.length;
+        int newCapacity = oldCapacity + (oldCapacity >> 1);
+        if (newCapacity - minCapacity < 0)
+            newCapacity = minCapacity;
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        // minCapacity is usually close to size, so this is a win:
+        elementData = Arrays.copyOf(elementData, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this list contains no elements.
+     *
+     * @return <tt>true</tt> if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this list contains the specified element.
+     * More formally, returns <tt>true</tt> if and only if this list contains
+     * at least one element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return <tt>true</tt> if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the lowest index <tt>i</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     */
+    public int indexOf(Object o) {
+        if (o == null) {
+            for (int i = 0; i < size; i++)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = 0; i < size; i++)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the highest index <tt>i</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     */
+    public int lastIndexOf(Object o) {
+        if (o == null) {
+            for (int i = size-1; i >= 0; i--)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = size-1; i >= 0; i--)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
+     * elements themselves are not copied.)
+     *
+     * @return a clone of this <tt>ArrayList</tt> instance
+     */
+    public Object clone() {
+        try {
+            ArrayList<?> v = (ArrayList<?>) super.clone();
+            v.elementData = Arrays.copyOf(elementData, size);
+            v.modCount = 0;
+            return v;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list in
+     *         proper sequence
+     */
+    public Object[] toArray() {
+        return Arrays.copyOf(elementData, size);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in proper
+     * sequence (from first to last element); the runtime type of the returned
+     * array is that of the specified array.  If the list fits in the
+     * specified array, it is returned therein.  Otherwise, a new array is
+     * allocated with the runtime type of the specified array and the size of
+     * this list.
+     *
+     * <p>If the list fits in the specified array with room to spare
+     * (i.e., the array has more elements than the list), the element in
+     * the array immediately following the end of the collection is set to
+     * <tt>null</tt>.  (This is useful in determining the length of the
+     * list <i>only</i> if the caller knows that the list does not contain
+     * any null elements.)
+     *
+     * @param a the array into which the elements of the list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size)
+            // Make a new array of a's runtime type, but my contents:
+            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
+        System.arraycopy(elementData, 0, a, 0, size);
+        if (a.length > size)
+            a[size] = null;
+        return a;
+    }
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param  index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        if (index >= size)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        return (E) elementData[index];
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with
+     * the specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        if (index >= size)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        E oldValue = (E) elementData[index];
+        elementData[index] = element;
+        return oldValue;
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param e element to be appended to this list
+     * @return <tt>true</tt> (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        ensureCapacityInternal(size + 1);  // Increments modCount!!
+        elementData[size++] = e;
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this
+     * list. Shifts the element currently at that position (if any) and
+     * any subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        if (index > size || index < 0)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        ensureCapacityInternal(size + 1);  // Increments modCount!!
+        System.arraycopy(elementData, index, elementData, index + 1,
+                         size - index);
+        elementData[index] = element;
+        size++;
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).
+     *
+     * @param index the index of the element to be removed
+     * @return the element that was removed from the list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        if (index >= size)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        modCount++;
+        E oldValue = (E) elementData[index];
+
+        int numMoved = size - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--size] = null; // clear to let GC do its work
+
+        return oldValue;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If the list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * <tt>i</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
+     * (if such an element exists).  Returns <tt>true</tt> if this list
+     * contained the specified element (or equivalently, if this list
+     * changed as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return <tt>true</tt> if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        if (o == null) {
+            for (int index = 0; index < size; index++)
+                if (elementData[index] == null) {
+                    fastRemove(index);
+                    return true;
+                }
+        } else {
+            for (int index = 0; index < size; index++)
+                if (o.equals(elementData[index])) {
+                    fastRemove(index);
+                    return true;
+                }
+        }
+        return false;
+    }
+
+    /*
+     * Private remove method that skips bounds checking and does not
+     * return the value removed.
+     */
+    private void fastRemove(int index) {
+        modCount++;
+        int numMoved = size - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--size] = null; // clear to let GC do its work
+    }
+
+    /**
+     * Removes all of the elements from this list.  The list will
+     * be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+
+        // clear to let GC do its work
+        for (int i = 0; i < size; i++)
+            elementData[i] = null;
+
+        size = 0;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the
+     * specified collection's Iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the operation
+     * is in progress.  (This implies that the behavior of this call is
+     * undefined if the specified collection is this list, and this
+     * list is nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return <tt>true</tt> if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityInternal(size + numNew);  // Increments modCount
+        System.arraycopy(a, 0, elementData, size, numNew);
+        size += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in the list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c collection containing elements to be added to this list
+     * @return <tt>true</tt> if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        if (index > size || index < 0)
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityInternal(size + numNew);  // Increments modCount
+
+        int numMoved = size - index;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index, elementData, index + numNew,
+                             numMoved);
+
+        System.arraycopy(a, 0, elementData, index, numNew);
+        size += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * @throws IndexOutOfBoundsException if {@code fromIndex} or
+     *         {@code toIndex} is out of range
+     *         ({@code fromIndex < 0 ||
+     *          fromIndex >= size() ||
+     *          toIndex > size() ||
+     *          toIndex < fromIndex})
+     */
+    protected void removeRange(int fromIndex, int toIndex) {
+        // Android-changed: Throw an IOOBE if toIndex < fromIndex as documented.
+        // All the other cases (negative indices, or indices greater than the size
+        // will be thrown by System#arrayCopy.
+        if (toIndex < fromIndex) {
+            throw new IndexOutOfBoundsException("toIndex < fromIndex");
+        }
+
+        modCount++;
+        int numMoved = size - toIndex;
+        System.arraycopy(elementData, toIndex, elementData, fromIndex,
+                         numMoved);
+
+        // clear to let GC do its work
+        int newSize = size - (toIndex-fromIndex);
+        for (int i = newSize; i < size; i++) {
+            elementData[i] = null;
+        }
+        size = newSize;
+    }
+
+    /**
+     * Constructs an IndexOutOfBoundsException detail message.
+     * Of the many possible refactorings of the error handling code,
+     * this "outlining" performs best with both server and client VMs.
+     */
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size;
+    }
+
+    /**
+     * Removes from this list all of its elements that are contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see Collection#contains(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return batchRemove(c, false);
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection.  In other words, removes from this list all
+     * of its elements that are not contained in the specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see Collection#contains(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        Objects.requireNonNull(c);
+        return batchRemove(c, true);
+    }
+
+    private boolean batchRemove(Collection<?> c, boolean complement) {
+        final Object[] elementData = this.elementData;
+        int r = 0, w = 0;
+        boolean modified = false;
+        try {
+            for (; r < size; r++)
+                if (c.contains(elementData[r]) == complement)
+                    elementData[w++] = elementData[r];
+        } finally {
+            // Preserve behavioral compatibility with AbstractCollection,
+            // even if c.contains() throws.
+            if (r != size) {
+                System.arraycopy(elementData, r,
+                                 elementData, w,
+                                 size - r);
+                w += size - r;
+            }
+            if (w != size) {
+                // clear to let GC do its work
+                for (int i = w; i < size; i++)
+                    elementData[i] = null;
+                modCount += size - w;
+                size = w;
+                modified = true;
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
+     * is, serialize it).
+     *
+     * @serialData The length of the array backing the <tt>ArrayList</tt>
+     *             instance is emitted (int), followed by all of its elements
+     *             (each an <tt>Object</tt>) in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException{
+        // Write out element count, and any hidden stuff
+        int expectedModCount = modCount;
+        s.defaultWriteObject();
+
+        // Write out size as capacity for behavioural compatibility with clone()
+        s.writeInt(size);
+
+        // Write out all elements in the proper order.
+        for (int i=0; i<size; i++) {
+            s.writeObject(elementData[i]);
+        }
+
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        elementData = EMPTY_ELEMENTDATA;
+
+        // Read in size, and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in capacity
+        s.readInt(); // ignored
+
+        if (size > 0) {
+            // be like clone(), allocate array based upon size not capacity
+            ensureCapacityInternal(size);
+
+            Object[] a = elementData;
+            // Read in all elements in the proper order.
+            for (int i=0; i<size; i++) {
+                a[i] = s.readObject();
+            }
+        }
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(int index) {
+        if (index < 0 || index > size)
+            throw new IndexOutOfBoundsException("Index: "+index);
+        return new ListItr(index);
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @see #listIterator(int)
+     */
+    public ListIterator<E> listIterator() {
+        return new ListItr(0);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * An optimized version of AbstractList.Itr
+     */
+    private class Itr implements Iterator<E> {
+        // Android-changed: Add "limit" field to detect end of iteration.
+        // The "limit" of this iterator. This is the size of the list at the time the
+        // iterator was created. Adding & removing elements will invalidate the iteration
+        // anyway (and cause next() to throw) so saving this value will guarantee that the
+        // value of hasNext() remains stable and won't flap between true and false when elements
+        // are added and removed from the list.
+        protected int limit = ArrayList.this.size;
+
+        int cursor;       // index of next element to return
+        int lastRet = -1; // index of last element returned; -1 if no such
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor < limit;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int i = cursor;
+            if (i >= limit)
+                throw new NoSuchElementException();
+            Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length)
+                throw new ConcurrentModificationException();
+            cursor = i + 1;
+            return (E) elementData[lastRet = i];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            try {
+                ArrayList.this.remove(lastRet);
+                cursor = lastRet;
+                lastRet = -1;
+                expectedModCount = modCount;
+                limit--;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> consumer) {
+            Objects.requireNonNull(consumer);
+            final int size = ArrayList.this.size;
+            int i = cursor;
+            if (i >= size) {
+                return;
+            }
+            final Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length) {
+                throw new ConcurrentModificationException();
+            }
+            while (i != size && modCount == expectedModCount) {
+                consumer.accept((E) elementData[i++]);
+            }
+            // update once at end of iteration to reduce heap write traffic
+            cursor = i;
+            lastRet = i - 1;
+
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * An optimized version of AbstractList.ListItr
+     */
+    private class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            super();
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E previous() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            int i = cursor - 1;
+            if (i < 0)
+                throw new NoSuchElementException();
+            Object[] elementData = ArrayList.this.elementData;
+            if (i >= elementData.length)
+                throw new ConcurrentModificationException();
+            cursor = i;
+            return (E) elementData[lastRet = i];
+        }
+
+        public void set(E e) {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            try {
+                ArrayList.this.set(lastRet, e);
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        public void add(E e) {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            try {
+                int i = cursor;
+                ArrayList.this.add(i, e);
+                cursor = i + 1;
+                lastRet = -1;
+                expectedModCount = modCount;
+                limit++;
+            } catch (IndexOutOfBoundsException ex) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a view of the portion of this list between the specified
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
+     * empty.)  The returned list is backed by this list, so non-structural
+     * changes in the returned list are reflected in this list, and vice-versa.
+     * The returned list supports all of the optional list operations.
+     *
+     * <p>This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a list can be used as a range operation by passing a subList view
+     * instead of a whole list.  For example, the following idiom
+     * removes a range of elements from a list:
+     * <pre>
+     *      list.subList(from, to).clear();
+     * </pre>
+     * Similar idioms may be constructed for {@link #indexOf(Object)} and
+     * {@link #lastIndexOf(Object)}, and all of the algorithms in the
+     * {@link Collections} class can be applied to a subList.
+     *
+     * <p>The semantics of the list returned by this method become undefined if
+     * the backing list (i.e., this list) is <i>structurally modified</i> in
+     * any way other than via the returned list.  (Structural modifications are
+     * those that change the size of this list, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        subListRangeCheck(fromIndex, toIndex, size);
+        return new SubList(this, 0, fromIndex, toIndex);
+    }
+
+    static void subListRangeCheck(int fromIndex, int toIndex, int size) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+        if (toIndex > size)
+            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                               ") > toIndex(" + toIndex + ")");
+    }
+
+    private class SubList extends AbstractList<E> implements RandomAccess {
+        private final AbstractList<E> parent;
+        private final int parentOffset;
+        private final int offset;
+        int size;
+
+        SubList(AbstractList<E> parent,
+                int offset, int fromIndex, int toIndex) {
+            this.parent = parent;
+            this.parentOffset = fromIndex;
+            this.offset = offset + fromIndex;
+            this.size = toIndex - fromIndex;
+            this.modCount = ArrayList.this.modCount;
+        }
+
+        public E set(int index, E e) {
+            if (index < 0 || index >= this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            E oldValue = (E) ArrayList.this.elementData[offset + index];
+            ArrayList.this.elementData[offset + index] = e;
+            return oldValue;
+        }
+
+        public E get(int index) {
+            if (index < 0 || index >= this.size)
+              throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            return (E) ArrayList.this.elementData[offset + index];
+        }
+
+        public int size() {
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            return this.size;
+        }
+
+        public void add(int index, E e) {
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            parent.add(parentOffset + index, e);
+            this.modCount = parent.modCount;
+            this.size++;
+        }
+
+        public E remove(int index) {
+            if (index < 0 || index >= this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            E result = parent.remove(parentOffset + index);
+            this.modCount = parent.modCount;
+            this.size--;
+            return result;
+        }
+
+        protected void removeRange(int fromIndex, int toIndex) {
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            parent.removeRange(parentOffset + fromIndex,
+                               parentOffset + toIndex);
+            this.modCount = parent.modCount;
+            this.size -= toIndex - fromIndex;
+        }
+
+        public boolean addAll(Collection<? extends E> c) {
+            return addAll(this.size, c);
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            int cSize = c.size();
+            if (cSize==0)
+                return false;
+
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            parent.addAll(parentOffset + index, c);
+            this.modCount = parent.modCount;
+            this.size += cSize;
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            return listIterator();
+        }
+
+        public ListIterator<E> listIterator(final int index) {
+            if (ArrayList.this.modCount != this.modCount)
+                throw new ConcurrentModificationException();
+            if (index < 0 || index > this.size)
+                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+            final int offset = this.offset;
+
+            return new ListIterator<E>() {
+                int cursor = index;
+                int lastRet = -1;
+                int expectedModCount = ArrayList.this.modCount;
+
+                public boolean hasNext() {
+                    return cursor != SubList.this.size;
+                }
+
+                @SuppressWarnings("unchecked")
+                public E next() {
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+                    int i = cursor;
+                    if (i >= SubList.this.size)
+                        throw new NoSuchElementException();
+                    Object[] elementData = ArrayList.this.elementData;
+                    if (offset + i >= elementData.length)
+                        throw new ConcurrentModificationException();
+                    cursor = i + 1;
+                    return (E) elementData[offset + (lastRet = i)];
+                }
+
+                public boolean hasPrevious() {
+                    return cursor != 0;
+                }
+
+                @SuppressWarnings("unchecked")
+                public E previous() {
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+                    int i = cursor - 1;
+                    if (i < 0)
+                        throw new NoSuchElementException();
+                    Object[] elementData = ArrayList.this.elementData;
+                    if (offset + i >= elementData.length)
+                        throw new ConcurrentModificationException();
+                    cursor = i;
+                    return (E) elementData[offset + (lastRet = i)];
+                }
+
+                @SuppressWarnings("unchecked")
+                public void forEachRemaining(Consumer<? super E> consumer) {
+                    Objects.requireNonNull(consumer);
+                    final int size = SubList.this.size;
+                    int i = cursor;
+                    if (i >= size) {
+                        return;
+                    }
+                    final Object[] elementData = ArrayList.this.elementData;
+                    if (offset + i >= elementData.length) {
+                        throw new ConcurrentModificationException();
+                    }
+                    while (i != size && modCount == expectedModCount) {
+                        consumer.accept((E) elementData[offset + (i++)]);
+                    }
+                    // update once at end of iteration to reduce heap write traffic
+                    lastRet = cursor = i;
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+                }
+
+                public int nextIndex() {
+                    return cursor;
+                }
+
+                public int previousIndex() {
+                    return cursor - 1;
+                }
+
+                public void remove() {
+                    if (lastRet < 0)
+                        throw new IllegalStateException();
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+
+                    try {
+                        SubList.this.remove(lastRet);
+                        cursor = lastRet;
+                        lastRet = -1;
+                        expectedModCount = ArrayList.this.modCount;
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                public void set(E e) {
+                    if (lastRet < 0)
+                        throw new IllegalStateException();
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+
+                    try {
+                        ArrayList.this.set(offset + lastRet, e);
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+
+                public void add(E e) {
+                    if (expectedModCount != ArrayList.this.modCount)
+                        throw new ConcurrentModificationException();
+
+                    try {
+                        int i = cursor;
+                        SubList.this.add(i, e);
+                        cursor = i + 1;
+                        lastRet = -1;
+                        expectedModCount = ArrayList.this.modCount;
+                    } catch (IndexOutOfBoundsException ex) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            subListRangeCheck(fromIndex, toIndex, size);
+            return new SubList(this, offset, fromIndex, toIndex);
+        }
+
+        private String outOfBoundsMsg(int index) {
+            return "Index: "+index+", Size: "+this.size;
+        }
+
+        public Spliterator<E> spliterator() {
+            if (modCount != ArrayList.this.modCount)
+                throw new ConcurrentModificationException();
+            return new ArrayListSpliterator<E>(ArrayList.this, offset,
+                                               offset + this.size, this.modCount);
+        }
+    }
+
+    @Override
+    public void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        @SuppressWarnings("unchecked")
+        final E[] elementData = (E[]) this.elementData;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            action.accept(elementData[i]);
+        }
+        // Android-note:
+        // Iterator will not throw a CME if we add something while iterating over the *last* element
+        // forEach will throw a CME in this case.
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new ArrayListSpliterator<>(this, 0, -1, 0);
+    }
+
+    /** Index-based split-by-two, lazily initialized Spliterator */
+    static final class ArrayListSpliterator<E> implements Spliterator<E> {
+
+        /*
+         * If ArrayLists were immutable, or structurally immutable (no
+         * adds, removes, etc), we could implement their spliterators
+         * with Arrays.spliterator. Instead we detect as much
+         * interference during traversal as practical without
+         * sacrificing much performance. We rely primarily on
+         * modCounts. These are not guaranteed to detect concurrency
+         * violations, and are sometimes overly conservative about
+         * within-thread interference, but detect enough problems to
+         * be worthwhile in practice. To carry this out, we (1) lazily
+         * initialize fence and expectedModCount until the latest
+         * point that we need to commit to the state we are checking
+         * against; thus improving precision.  (This doesn't apply to
+         * SubLists, that create spliterators with current non-lazy
+         * values).  (2) We perform only a single
+         * ConcurrentModificationException check at the end of forEach
+         * (the most performance-sensitive method). When using forEach
+         * (as opposed to iterators), we can normally only detect
+         * interference after actions, not before. Further
+         * CME-triggering checks apply to all other possible
+         * violations of assumptions for example null or too-small
+         * elementData array given its size(), that could only have
+         * occurred due to interference.  This allows the inner loop
+         * of forEach to run without any further checks, and
+         * simplifies lambda-resolution. While this does entail a
+         * number of checks, note that in the common case of
+         * list.stream().forEach(a), no checks or other computation
+         * occur anywhere other than inside forEach itself.  The other
+         * less-often-used methods cannot take advantage of most of
+         * these streamlinings.
+         */
+
+        private final ArrayList<E> list;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+        private int expectedModCount; // initialized when fence set
+
+        /** Create new spliterator covering the given  range */
+        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
+                             int expectedModCount) {
+            this.list = list; // OK if null unless traversed
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi; // (a specialized variant appears in method forEach)
+            ArrayList<E> lst;
+            if ((hi = fence) < 0) {
+                if ((lst = list) == null)
+                    hi = fence = 0;
+                else {
+                    expectedModCount = lst.modCount;
+                    hi = fence = lst.size;
+                }
+            }
+            return hi;
+        }
+
+        public ArrayListSpliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null : // divide range in half unless too small
+                new ArrayListSpliterator<E>(list, lo, index = mid,
+                                            expectedModCount);
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), i = index;
+            if (i < hi) {
+                index = i + 1;
+                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
+                action.accept(e);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi, mc; // hoist accesses and checks from loop
+            ArrayList<E> lst; Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((lst = list) != null && (a = lst.elementData) != null) {
+                if ((hi = fence) < 0) {
+                    mc = lst.modCount;
+                    hi = lst.size;
+                }
+                else
+                    mc = expectedModCount;
+                if ((i = index) >= 0 && (index = hi) <= a.length) {
+                    for (; i < hi; ++i) {
+                        @SuppressWarnings("unchecked") E e = (E) a[i];
+                        action.accept(e);
+                    }
+                    if (lst.modCount == mc)
+                        return;
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    @Override
+    public boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        // figure out which elements are to be removed
+        // any exception thrown from the filter predicate at this stage
+        // will leave the collection unmodified
+        int removeCount = 0;
+        final BitSet removeSet = new BitSet(size);
+        final int expectedModCount = modCount;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            @SuppressWarnings("unchecked")
+            final E element = (E) elementData[i];
+            if (filter.test(element)) {
+                removeSet.set(i);
+                removeCount++;
+            }
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+
+        // shift surviving elements left over the spaces left by removed elements
+        final boolean anyToRemove = removeCount > 0;
+        if (anyToRemove) {
+            final int newSize = size - removeCount;
+            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
+                i = removeSet.nextClearBit(i);
+                elementData[j] = elementData[i];
+            }
+            for (int k=newSize; k < size; k++) {
+                elementData[k] = null;  // Let gc do its work
+            }
+            this.size = newSize;
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+            modCount++;
+        }
+
+        return anyToRemove;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final int expectedModCount = modCount;
+        final int size = this.size;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            elementData[i] = operator.apply((E) elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void sort(Comparator<? super E> c) {
+        final int expectedModCount = modCount;
+        Arrays.sort((E[]) elementData, 0, size, c);
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+}
diff --git a/java/util/ArrayPrefixHelpers.java b/java/util/ArrayPrefixHelpers.java
new file mode 100644
index 0000000..87c04d1
--- /dev/null
+++ b/java/util/ArrayPrefixHelpers.java
@@ -0,0 +1,706 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * ForkJoin tasks to perform Arrays.parallelPrefix operations.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ */
+class ArrayPrefixHelpers {
+    private ArrayPrefixHelpers() {} // non-instantiable
+
+    /*
+     * Parallel prefix (aka cumulate, scan) task classes
+     * are based loosely on Guy Blelloch's original
+     * algorithm (http://www.cs.cmu.edu/~scandal/alg/scan.html):
+     *  Keep dividing by two to threshold segment size, and then:
+     *   Pass 1: Create tree of partial sums for each segment
+     *   Pass 2: For each segment, cumulate with offset of left sibling
+     *
+     * This version improves performance within FJ framework mainly by
+     * allowing the second pass of ready left-hand sides to proceed
+     * even if some right-hand side first passes are still executing.
+     * It also combines first and second pass for leftmost segment,
+     * and skips the first pass for rightmost segment (whose result is
+     * not needed for second pass).  It similarly manages to avoid
+     * requiring that users supply an identity basis for accumulations
+     * by tracking those segments/subtasks for which the first
+     * existing element is used as base.
+     *
+     * Managing this relies on ORing some bits in the pendingCount for
+     * phases/states: CUMULATE, SUMMED, and FINISHED. CUMULATE is the
+     * main phase bit. When false, segments compute only their sum.
+     * When true, they cumulate array elements. CUMULATE is set at
+     * root at beginning of second pass and then propagated down. But
+     * it may also be set earlier for subtrees with lo==0 (the left
+     * spine of tree). SUMMED is a one bit join count. For leafs, it
+     * is set when summed. For internal nodes, it becomes true when
+     * one child is summed.  When the second child finishes summing,
+     * we then moves up tree to trigger the cumulate phase. FINISHED
+     * is also a one bit join count. For leafs, it is set when
+     * cumulated. For internal nodes, it becomes true when one child
+     * is cumulated.  When the second child finishes cumulating, it
+     * then moves up tree, completing at the root.
+     *
+     * To better exploit locality and reduce overhead, the compute
+     * method loops starting with the current task, moving if possible
+     * to one of its subtasks rather than forking.
+     *
+     * As usual for this sort of utility, there are 4 versions, that
+     * are simple copy/paste/adapt variants of each other.  (The
+     * double and int versions differ from long version solely by
+     * replacing "long" (with case-matching)).
+     */
+
+    // see above
+    static final int CUMULATE = 1;
+    static final int SUMMED   = 2;
+    static final int FINISHED = 4;
+
+    /** The smallest subtask array partition size to use as threshold */
+    static final int MIN_PARTITION = 16;
+
+    static final class CumulateTask<T> extends CountedCompleter<Void> {
+        final T[] array;
+        final BinaryOperator<T> function;
+        CumulateTask<T> left, right;
+        T in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public CumulateTask(CumulateTask<T> parent,
+                            BinaryOperator<T> function,
+                            T[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        CumulateTask(CumulateTask<T> parent, BinaryOperator<T> function,
+                     T[] array, int origin, int fence, int threshold,
+                     int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final BinaryOperator<T> fn;
+            final T[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            CumulateTask<T> t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    CumulateTask<T> lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new CumulateTask<T>(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new CumulateTask<T>(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        T pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            T lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.apply(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    T sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.apply(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.apply(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (CumulateTask<T> par;;) {             // propagate
+                        @SuppressWarnings("unchecked") CumulateTask<T> partmp
+                            = (CumulateTask<T>)t.getCompleter();
+                        if ((par = partmp) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; CumulateTask<T> lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                T lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.apply(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = 5293554502939613543L;
+    }
+
+    static final class LongCumulateTask extends CountedCompleter<Void> {
+        final long[] array;
+        final LongBinaryOperator function;
+        LongCumulateTask left, right;
+        long in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public LongCumulateTask(LongCumulateTask parent,
+                                LongBinaryOperator function,
+                                long[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        LongCumulateTask(LongCumulateTask parent, LongBinaryOperator function,
+                         long[] array, int origin, int fence, int threshold,
+                         int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final LongBinaryOperator fn;
+            final long[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            LongCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    LongCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new LongCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new LongCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        long pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            long lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsLong(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    long sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsLong(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsLong(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (LongCumulateTask par;;) {            // propagate
+                        if ((par = (LongCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; LongCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                long lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsLong(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = -5074099945909284273L;
+    }
+
+    static final class DoubleCumulateTask extends CountedCompleter<Void> {
+        final double[] array;
+        final DoubleBinaryOperator function;
+        DoubleCumulateTask left, right;
+        double in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public DoubleCumulateTask(DoubleCumulateTask parent,
+                                  DoubleBinaryOperator function,
+                                  double[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        DoubleCumulateTask(DoubleCumulateTask parent, DoubleBinaryOperator function,
+                           double[] array, int origin, int fence, int threshold,
+                           int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final DoubleBinaryOperator fn;
+            final double[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            DoubleCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    DoubleCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new DoubleCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new DoubleCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        double pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            double lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsDouble(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    double sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsDouble(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsDouble(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (DoubleCumulateTask par;;) {            // propagate
+                        if ((par = (DoubleCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; DoubleCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                double lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsDouble(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = -586947823794232033L;
+    }
+
+    static final class IntCumulateTask extends CountedCompleter<Void> {
+        final int[] array;
+        final IntBinaryOperator function;
+        IntCumulateTask left, right;
+        int in, out;
+        final int lo, hi, origin, fence, threshold;
+
+        /** Root task constructor */
+        public IntCumulateTask(IntCumulateTask parent,
+                               IntBinaryOperator function,
+                               int[] array, int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.lo = this.origin = lo; this.hi = this.fence = hi;
+            int p;
+            this.threshold =
+                (p = (hi - lo) / (ForkJoinPool.getCommonPoolParallelism() << 3))
+                <= MIN_PARTITION ? MIN_PARTITION : p;
+        }
+
+        /** Subtask constructor */
+        IntCumulateTask(IntCumulateTask parent, IntBinaryOperator function,
+                        int[] array, int origin, int fence, int threshold,
+                        int lo, int hi) {
+            super(parent);
+            this.function = function; this.array = array;
+            this.origin = origin; this.fence = fence;
+            this.threshold = threshold;
+            this.lo = lo; this.hi = hi;
+        }
+
+        public final void compute() {
+            final IntBinaryOperator fn;
+            final int[] a;
+            if ((fn = this.function) == null || (a = this.array) == null)
+                throw new NullPointerException();    // hoist checks
+            int th = threshold, org = origin, fnc = fence, l, h;
+            IntCumulateTask t = this;
+            outer: while ((l = t.lo) >= 0 && (h = t.hi) <= a.length) {
+                if (h - l > th) {
+                    IntCumulateTask lt = t.left, rt = t.right, f;
+                    if (lt == null) {                // first pass
+                        int mid = (l + h) >>> 1;
+                        f = rt = t.right =
+                            new IntCumulateTask(t, fn, a, org, fnc, th, mid, h);
+                        t = lt = t.left =
+                            new IntCumulateTask(t, fn, a, org, fnc, th, l, mid);
+                    }
+                    else {                           // possibly refork
+                        int pin = t.in;
+                        lt.in = pin;
+                        f = t = null;
+                        if (rt != null) {
+                            int lout = lt.out;
+                            rt.in = (l == org ? lout :
+                                     fn.applyAsInt(pin, lout));
+                            for (int c;;) {
+                                if (((c = rt.getPendingCount()) & CUMULATE) != 0)
+                                    break;
+                                if (rt.compareAndSetPendingCount(c, c|CUMULATE)){
+                                    t = rt;
+                                    break;
+                                }
+                            }
+                        }
+                        for (int c;;) {
+                            if (((c = lt.getPendingCount()) & CUMULATE) != 0)
+                                break;
+                            if (lt.compareAndSetPendingCount(c, c|CUMULATE)) {
+                                if (t != null)
+                                    f = t;
+                                t = lt;
+                                break;
+                            }
+                        }
+                        if (t == null)
+                            break;
+                    }
+                    if (f != null)
+                        f.fork();
+                }
+                else {
+                    int state; // Transition to sum, cumulate, or both
+                    for (int b;;) {
+                        if (((b = t.getPendingCount()) & FINISHED) != 0)
+                            break outer;                      // already done
+                        state = ((b & CUMULATE) != 0 ? FINISHED :
+                                 (l > org) ? SUMMED : (SUMMED|FINISHED));
+                        if (t.compareAndSetPendingCount(b, b|state))
+                            break;
+                    }
+
+                    int sum;
+                    if (state != SUMMED) {
+                        int first;
+                        if (l == org) {                       // leftmost; no in
+                            sum = a[org];
+                            first = org + 1;
+                        }
+                        else {
+                            sum = t.in;
+                            first = l;
+                        }
+                        for (int i = first; i < h; ++i)       // cumulate
+                            a[i] = sum = fn.applyAsInt(sum, a[i]);
+                    }
+                    else if (h < fnc) {                       // skip rightmost
+                        sum = a[l];
+                        for (int i = l + 1; i < h; ++i)       // sum only
+                            sum = fn.applyAsInt(sum, a[i]);
+                    }
+                    else
+                        sum = t.in;
+                    t.out = sum;
+                    for (IntCumulateTask par;;) {            // propagate
+                        if ((par = (IntCumulateTask)t.getCompleter()) == null) {
+                            if ((state & FINISHED) != 0)      // enable join
+                                t.quietlyComplete();
+                            break outer;
+                        }
+                        int b = par.getPendingCount();
+                        if ((b & state & FINISHED) != 0)
+                            t = par;                          // both done
+                        else if ((b & state & SUMMED) != 0) { // both summed
+                            int nextState; IntCumulateTask lt, rt;
+                            if ((lt = par.left) != null &&
+                                (rt = par.right) != null) {
+                                int lout = lt.out;
+                                par.out = (rt.hi == fnc ? lout :
+                                           fn.applyAsInt(lout, rt.out));
+                            }
+                            int refork = (((b & CUMULATE) == 0 &&
+                                           par.lo == org) ? CUMULATE : 0);
+                            if ((nextState = b|state|refork) == b ||
+                                par.compareAndSetPendingCount(b, nextState)) {
+                                state = SUMMED;               // drop finished
+                                t = par;
+                                if (refork != 0)
+                                    par.fork();
+                            }
+                        }
+                        else if (par.compareAndSetPendingCount(b, b|state))
+                            break outer;                      // sib not ready
+                    }
+                }
+            }
+        }
+        private static final long serialVersionUID = 3731755594596840961L;
+    }
+}
diff --git a/java/util/Arrays.annotated.java b/java/util/Arrays.annotated.java
new file mode 100644
index 0000000..99dec24
--- /dev/null
+++ b/java/util/Arrays.annotated.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.stream.Stream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.DoubleStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Arrays {
+
+Arrays() { throw new RuntimeException("Stub!"); }
+
+public static void sort(int @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(int @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(long @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(long @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(short @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(short @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(char @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(char @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(byte @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(float @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(float @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void sort(double @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort(double @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(byte @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(char @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(char @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(short @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(short @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(int @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(int @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(long @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(long @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(float @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(float @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(double @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSort(double @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> void parallelSort(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> void parallelSort(T @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelSort(T @libcore.util.NonNull [] a, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelSort(T @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> cmp) { throw new RuntimeException("Stub!"); }
+
+public static void sort([email protected] Object @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+public static void sort([email protected] Object @libcore.util.NonNull [] a, int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+public static <T> void sort(T @libcore.util.NonNull [] a, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> void sort(T @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelPrefix(T @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.BinaryOperator<@libcore.util.NullFromTypeParam T> op) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelPrefix(T @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.BinaryOperator<@libcore.util.NullFromTypeParam T> op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(long @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.LongBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(long @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.LongBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(double @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.DoubleBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(double @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.DoubleBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(int @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static void parallelPrefix(int @libcore.util.NonNull [] array, int fromIndex, int toIndex, @libcore.util.NonNull java.util.function.IntBinaryOperator op) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(long @libcore.util.NonNull [] a, long key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(long @libcore.util.NonNull [] a, int fromIndex, int toIndex, long key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(int @libcore.util.NonNull [] a, int key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(int @libcore.util.NonNull [] a, int fromIndex, int toIndex, int key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(short @libcore.util.NonNull [] a, short key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(short @libcore.util.NonNull [] a, int fromIndex, int toIndex, short key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(char @libcore.util.NonNull [] a, char key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(char @libcore.util.NonNull [] a, int fromIndex, int toIndex, char key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(byte @libcore.util.NonNull [] a, byte key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex, byte key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(double @libcore.util.NonNull [] a, double key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(double @libcore.util.NonNull [] a, int fromIndex, int toIndex, double key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(float @libcore.util.NonNull [] a, float key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch(float @libcore.util.NonNull [] a, int fromIndex, int toIndex, float key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch([email protected] Object @libcore.util.NonNull [] a, @libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public static int binarySearch([email protected] Object @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(T @libcore.util.NonNull [] a, @libcore.util.NullFromTypeParam T key, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(T @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.NullFromTypeParam T key, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(long @libcore.util.Nullable [] a, long @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(int @libcore.util.Nullable [] a, int @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(short @libcore.util.Nullable [] a, short @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(char @libcore.util.Nullable [] a, char @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(byte @libcore.util.Nullable [] a, byte @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(boolean @libcore.util.Nullable [] a, boolean @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(double @libcore.util.Nullable [] a, double @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(float @libcore.util.Nullable [] a, float @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static boolean equals([email protected] Object @libcore.util.Nullable [] a, [email protected] Object @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
+public static void fill(long @libcore.util.NonNull [] a, long val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(long @libcore.util.NonNull [] a, int fromIndex, int toIndex, long val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(int @libcore.util.NonNull [] a, int val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(int @libcore.util.NonNull [] a, int fromIndex, int toIndex, int val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(short @libcore.util.NonNull [] a, short val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(short @libcore.util.NonNull [] a, int fromIndex, int toIndex, short val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(char @libcore.util.NonNull [] a, char val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(char @libcore.util.NonNull [] a, int fromIndex, int toIndex, char val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(byte @libcore.util.NonNull [] a, byte val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(byte @libcore.util.NonNull [] a, int fromIndex, int toIndex, byte val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(boolean @libcore.util.NonNull [] a, boolean val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(boolean @libcore.util.NonNull [] a, int fromIndex, int toIndex, boolean val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(double @libcore.util.NonNull [] a, double val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(double @libcore.util.NonNull [] a, int fromIndex, int toIndex, double val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(float @libcore.util.NonNull [] a, float val) { throw new RuntimeException("Stub!"); }
+
+public static void fill(float @libcore.util.NonNull [] a, int fromIndex, int toIndex, float val) { throw new RuntimeException("Stub!"); }
+
+public static void fill([email protected] Object @libcore.util.NonNull [] a, @libcore.util.Nullable java.lang.Object val) { throw new RuntimeException("Stub!"); }
+
+public static void fill([email protected] Object @libcore.util.NonNull [] a, int fromIndex, int toIndex, @libcore.util.Nullable java.lang.Object val) { throw new RuntimeException("Stub!"); }
+
+public static <T> T @libcore.util.NonNull [] copyOf(T @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static <T, U> T @libcore.util.NonNull [] copyOf(U @libcore.util.NonNull [] original, int newLength, @libcore.util.NonNull java.lang.Class<? extends T[]> newType) { throw new RuntimeException("Stub!"); }
+
+public static byte @libcore.util.NonNull [] copyOf(byte @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static short @libcore.util.NonNull [] copyOf(short @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static int @libcore.util.NonNull [] copyOf(int @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static long @libcore.util.NonNull [] copyOf(long @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static char @libcore.util.NonNull [] copyOf(char @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static float @libcore.util.NonNull [] copyOf(float @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static double @libcore.util.NonNull [] copyOf(double @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static boolean @libcore.util.NonNull [] copyOf(boolean @libcore.util.NonNull [] original, int newLength) { throw new RuntimeException("Stub!"); }
+
+public static <T> T @libcore.util.NonNull [] copyOfRange(T @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static <T, U> T @libcore.util.NonNull [] copyOfRange(U @libcore.util.NonNull [] original, int from, int to, @libcore.util.NonNull java.lang.Class<? extends T[]> newType) { throw new RuntimeException("Stub!"); }
+
+public static byte @libcore.util.NonNull [] copyOfRange(byte @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static short @libcore.util.NonNull [] copyOfRange(short @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static int @libcore.util.NonNull [] copyOfRange(int @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static long @libcore.util.NonNull [] copyOfRange(long @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static char @libcore.util.NonNull [] copyOfRange(char @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static float @libcore.util.NonNull [] copyOfRange(float @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static double @libcore.util.NonNull [] copyOfRange(double @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
+public static boolean @libcore.util.NonNull [] copyOfRange(boolean @libcore.util.NonNull [] original, int from, int to) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> asList(T @libcore.util.NonNull ... a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(long @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(int @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(short @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(char @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(byte @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(boolean @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(float @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(double @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static int deepHashCode([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static boolean deepEquals([email protected] Object @libcore.util.Nullable [] a1, [email protected] Object @libcore.util.Nullable [] a2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(long @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(int @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(short @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(char @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(byte @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(boolean @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(float @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(double @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String deepToString([email protected] Object @libcore.util.Nullable [] a) { throw new RuntimeException("Stub!"); }
+
+public static <T> void setAll(T @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntFunction<? extends @libcore.util.NullFromTypeParam T> generator) { throw new RuntimeException("Stub!"); }
+
+public static <T> void parallelSetAll(T @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntFunction<? extends @libcore.util.NullFromTypeParam T> generator) { throw new RuntimeException("Stub!"); }
+
+public static void setAll(int @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntUnaryOperator generator) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSetAll(int @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntUnaryOperator generator) { throw new RuntimeException("Stub!"); }
+
+public static void setAll(long @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToLongFunction generator) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSetAll(long @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToLongFunction generator) { throw new RuntimeException("Stub!"); }
+
+public static void setAll(double @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToDoubleFunction generator) { throw new RuntimeException("Stub!"); }
+
+public static void parallelSetAll(double @libcore.util.NonNull [] array, @libcore.util.NonNull java.util.function.IntToDoubleFunction generator) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Spliterator<@libcore.util.NullFromTypeParam T> spliterator(T @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Spliterator<@libcore.util.NullFromTypeParam T> spliterator(T @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfInt spliterator(int @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfInt spliterator(int @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfLong spliterator(long @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfLong spliterator(long @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfDouble spliterator(double @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Spliterator.OfDouble spliterator(double @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.stream.Stream<@libcore.util.NullFromTypeParam T> stream(T @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.stream.Stream<@libcore.util.NullFromTypeParam T> stream(T @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.IntStream stream(int @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.IntStream stream(int @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.LongStream stream(long @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.LongStream stream(long @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.stream.DoubleStream stream(double @libcore.util.NonNull [] array, int startInclusive, int endExclusive) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Arrays.java b/java/util/Arrays.java
new file mode 100644
index 0000000..6da3e5d
--- /dev/null
+++ b/java/util/Arrays.java
@@ -0,0 +1,5046 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.UnaryOperator;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class contains various methods for manipulating arrays (such as
+ * sorting and searching). This class also contains a static factory
+ * that allows arrays to be viewed as lists.
+ *
+ * <p>The methods in this class all throw a {@code NullPointerException},
+ * if the specified array reference is null, except where noted.
+ *
+ * <p>The documentation for the methods contained in this class includes
+ * briefs description of the <i>implementations</i>. Such descriptions should
+ * be regarded as <i>implementation notes</i>, rather than parts of the
+ * <i>specification</i>. Implementors should feel free to substitute other
+ * algorithms, so long as the specification itself is adhered to. (For
+ * example, the algorithm used by {@code sort(Object[])} does not have to be
+ * a MergeSort, but it does have to be <i>stable</i>.)
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @author Neal Gafter
+ * @author John Rose
+ * @since  1.2
+ */
+public class Arrays {
+
+    /**
+     * The minimum array length below which a parallel sorting
+     * algorithm will not further partition the sorting task. Using
+     * smaller sizes typically results in memory contention across
+     * tasks that makes parallel speedups unlikely.
+     * @hide
+     */
+    // Android-changed: Make MIN_ARRAY_SORT_GRAN public and @hide (used by harmony ArraysTest)
+    public static final int MIN_ARRAY_SORT_GRAN = 1 << 13;
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Arrays() {}
+
+    /**
+     * A comparator that implements the natural ordering of a group of
+     * mutually comparable elements. May be used when a supplied
+     * comparator is null. To simplify code-sharing within underlying
+     * implementations, the compare method only declares type Object
+     * for its second argument.
+     *
+     * Arrays class implementor's note: It is an empirical matter
+     * whether ComparableTimSort offers any performance benefit over
+     * TimSort used with this comparator.  If not, you are better off
+     * deleting or bypassing ComparableTimSort.  There is currently no
+     * empirical case for separating them for parallel sorting, so all
+     * public Object parallelSort methods use the same comparator
+     * based implementation.
+     */
+    static final class NaturalOrder implements Comparator<Object> {
+        @SuppressWarnings("unchecked")
+        public int compare(Object first, Object second) {
+            return ((Comparable<Object>)first).compareTo(second);
+        }
+        static final NaturalOrder INSTANCE = new NaturalOrder();
+    }
+
+    /**
+     * Checks that {@code fromIndex} and {@code toIndex} are in
+     * the range and throws an exception if they aren't.
+     */
+    private static void rangeCheck(int arrayLength, int fromIndex, int toIndex) {
+        if (fromIndex > toIndex) {
+            throw new IllegalArgumentException(
+                    "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+        }
+        if (fromIndex < 0) {
+            throw new ArrayIndexOutOfBoundsException(fromIndex);
+        }
+        if (toIndex > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(toIndex);
+        }
+    }
+
+    /*
+     * Sorting methods. Note that all public "sort" methods take the
+     * same form: Performing argument checks if necessary, and then
+     * expanding arguments into those required for the internal
+     * implementation methods residing in other package-private
+     * classes (except for legacyMergeSort, included in this class).
+     */
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(int[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(long[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(short[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(char[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(byte[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(float[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     */
+    public static void sort(double[] a) {
+        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending order. The range
+     * to be sorted extends from the index {@code fromIndex}, inclusive, to
+     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+     * the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * <p>Implementation note: The sorting algorithm is a Dual-Pivot Quicksort
+     * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+     * offers O(n log(n)) performance on many data sets that cause other
+     * quicksorts to degrade to quadratic performance, and is typically
+     * faster than traditional (one-pivot) Quicksort implementations.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     */
+    public static void sort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1);
+        else
+            new ArraysParallelSortHelpers.FJByte.Sorter
+                (null, a, new byte[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(byte[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
+        else
+            new ArraysParallelSortHelpers.FJByte.Sorter
+                (null, a, new byte[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJChar.Sorter
+                (null, a, new char[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+      @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(char[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJChar.Sorter
+                (null, a, new char[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJShort.Sorter
+                (null, a, new short[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(short[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJShort.Sorter
+                (null, a, new short[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJInt.Sorter
+                (null, a, new int[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(int[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJInt.Sorter
+                (null, a, new int[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJLong.Sorter
+                (null, a, new long[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(long[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJLong.Sorter
+                (null, a, new long[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJFloat.Sorter
+                (null, a, new float[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all float
+     * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Float#compareTo}: {@code -0.0f} is treated as less than value
+     * {@code 0.0f} and {@code Float.NaN} is considered greater than any
+     * other value and all {@code Float.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(float[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJFloat.Sorter
+                (null, a, new float[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array into ascending numerical order.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJDouble.Sorter
+                (null, a, new double[n], 0, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the array into ascending numerical order.
+     * The range to be sorted extends from the index {@code fromIndex},
+     * inclusive, to the index {@code toIndex}, exclusive. If
+     * {@code fromIndex == toIndex}, the range to be sorted is empty.
+     *
+     * <p>The {@code <} relation does not provide a total order on all double
+     * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN}
+     * value compares neither less than, greater than, nor equal to any value,
+     * even itself. This method uses the total order imposed by the method
+     * {@link Double#compareTo}: {@code -0.0d} is treated as less than value
+     * {@code 0.0d} and {@code Double.NaN} is considered greater than any
+     * other value and all {@code Double.NaN} values are considered equal.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element, inclusive, to be sorted
+     * @param toIndex the index of the last element, exclusive, to be sorted
+     *
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > a.length}
+     *
+     * @since 1.8
+     */
+    public static void parallelSort(double[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJDouble.Sorter
+                (null, a, new double[n], fromIndex, n, 0,
+                 ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     *
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> void parallelSort(T[] a) {
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>>
+    void parallelSort(T[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke();
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a
+     * working space no greater than the size of the original array. The
+     * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to
+     * execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link java.util.Comparator} contract
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, Comparator<? super T> cmp) {
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = a.length, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, 0, n, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * @implNote The sorting algorithm is a parallel sort-merge that breaks the
+     * array into sub-arrays that are themselves sorted and then merged. When
+     * the sub-array length reaches a minimum granularity, the sub-array is
+     * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort}
+     * method. If the length of the specified array is less than the minimum
+     * granularity, then it is sorted using the appropriate {@link
+     * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working
+     * space no greater than the size of the specified range of the original
+     * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is
+     * used to execute any parallel tasks.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param cmp the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     *
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> void parallelSort(T[] a, int fromIndex, int toIndex,
+                                        Comparator<? super T> cmp) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        if (cmp == null)
+            cmp = NaturalOrder.INSTANCE;
+        int n = toIndex - fromIndex, p, g;
+        if (n <= MIN_ARRAY_SORT_GRAN ||
+            (p = ForkJoinPool.getCommonPoolParallelism()) == 1)
+            TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0);
+        else
+            new ArraysParallelSortHelpers.FJObject.Sorter<T>
+                (null, a,
+                 (T[])Array.newInstance(a.getClass().getComponentType(), n),
+                 fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ?
+                 MIN_ARRAY_SORT_GRAN : g, cmp).invoke();
+    }
+
+    /*
+     * Sorting of complex type arrays.
+     */
+
+    // Android-removed: LegacyMergeSort class (unused on Android).
+
+    /**
+     * Sorts the specified array of objects into ascending order, according
+     * to the {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the array must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the array must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)} must
+     * not throw a {@code ClassCastException} for any elements {@code e1}
+     * and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param a the array to be sorted
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers)
+     * @throws IllegalArgumentException (optional) if the natural
+     *         ordering of the array elements is found to violate the
+     *         {@link Comparable} contract
+     */
+    public static void sort(Object[] a) {
+        // Android-removed: LegacyMergeSort support
+        // if (LegacyMergeSort.userRequested)
+        //     legacyMergeSort(a);
+        // else
+            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+
+    /**
+     * Sorts the specified range of the specified array of objects into
+     * ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its
+     * elements.  The range to be sorted extends from index
+     * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive.
+     * (If {@code fromIndex==toIndex}, the range to be sorted is empty.)  All
+     * elements in this range must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in this range must be <i>mutually
+     * comparable</i> (that is, {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the natural ordering of the array elements is
+     *         found to violate the {@link Comparable} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     */
+    public static void sort(Object[] a, int fromIndex, int toIndex) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        // Android-removed: LegacyMergeSort support
+        // if (LegacyMergeSort.userRequested)
+        //     legacyMergeSort(a, fromIndex, toIndex);
+        // else
+            ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0);
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+
+    /**
+     * Tuning parameter: list size at or below which insertion sort will be
+     * used in preference to mergesort.
+     * To be removed in a future release.
+     */
+    private static final int INSERTIONSORT_THRESHOLD = 7;
+
+    /**
+     * Src is the source array that starts at index 0
+     * Dest is the (possibly larger) array destination with a possible offset
+     * low is the index in dest to start sorting
+     * high is the end index in dest to end sorting
+     * off is the offset to generate corresponding low, high in src
+     * To be removed in a future release.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static void mergeSort(Object[] src,
+                                  Object[] dest,
+                                  int low,
+                                  int high,
+                                  int off) {
+        int length = high - low;
+
+        // Insertion sort on smallest arrays
+        if (length < INSERTIONSORT_THRESHOLD) {
+            for (int i=low; i<high; i++)
+                for (int j=i; j>low &&
+                         ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
+                    swap(dest, j, j-1);
+            return;
+        }
+
+        // Recursively sort halves of dest into src
+        int destLow  = low;
+        int destHigh = high;
+        low  += off;
+        high += off;
+        int mid = (low + high) >>> 1;
+        mergeSort(dest, src, low, mid, -off);
+        mergeSort(dest, src, mid, high, -off);
+
+        // If list is already sorted, just copy from src to dest.  This is an
+        // optimization that results in faster sorts for nearly ordered lists.
+        if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
+            System.arraycopy(src, low, dest, destLow, length);
+            return;
+        }
+
+        // Merge sorted halves (now in src) into dest
+        for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
+            if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
+                dest[i] = src[p++];
+            else
+                dest[i] = src[q++];
+        }
+    }
+
+    /**
+     * Swaps x[a] with x[b].
+     */
+    private static void swap(Object[] x, int a, int b) {
+        Object t = x[a];
+        x[a] = x[b];
+        x[b] = t;
+    }
+
+    /**
+     * Sorts the specified array of objects according to the order induced by
+     * the specified comparator.  All elements in the array must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the array).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link Comparator} contract
+     */
+    public static <T> void sort(T[] a, Comparator<? super T> c) {
+        if (c == null) {
+            sort(a);
+        } else {
+        // Android-removed: LegacyMergeSort support
+            // if (LegacyMergeSort.userRequested)
+            //     legacyMergeSort(a, c);
+            // else
+                TimSort.sort(a, 0, a.length, c, null, 0, 0);
+        }
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+
+    /**
+     * Sorts the specified range of the specified array of objects according
+     * to the order induced by the specified comparator.  The range to be
+     * sorted extends from index {@code fromIndex}, inclusive, to index
+     * {@code toIndex}, exclusive.  (If {@code fromIndex==toIndex}, the
+     * range to be sorted is empty.)  All elements in the range must be
+     * <i>mutually comparable</i> by the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the range).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>Implementation note: This implementation is a stable, adaptive,
+     * iterative mergesort that requires far fewer than n lg(n) comparisons
+     * when the input array is partially sorted, while offering the
+     * performance of a traditional mergesort when the input array is
+     * randomly ordered.  If the input array is nearly sorted, the
+     * implementation requires approximately n comparisons.  Temporary
+     * storage requirements vary from a small constant for nearly sorted
+     * input arrays to n/2 object references for randomly ordered input
+     * arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param <T> the class of the objects to be sorted
+     * @param a the array to be sorted
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        sorted
+     * @param toIndex the index of the last element (exclusive) to be sorted
+     * @param c the comparator to determine the order of the array.  A
+     *        {@code null} value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator.
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex} or
+     *         (optional) if the comparator is found to violate the
+     *         {@link Comparator} contract
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or
+     *         {@code toIndex > a.length}
+     */
+    public static <T> void sort(T[] a, int fromIndex, int toIndex,
+                                Comparator<? super T> c) {
+        if (c == null) {
+            sort(a, fromIndex, toIndex);
+        } else {
+            rangeCheck(a.length, fromIndex, toIndex);
+            // Android-removed: LegacyMergeSort support
+            // if (LegacyMergeSort.userRequested)
+            //     legacyMergeSort(a, fromIndex, toIndex, c);
+            // else
+                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
+        }
+    }
+
+    // Android-removed: legacyMergeSort() (unused on Android)
+    // Android-removed: mergeSort() (unused on Android)
+
+    // Parallel prefix
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param <T> the class of the objects in the array
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.CumulateTask<>
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(Object[], BinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static <T> void parallelPrefix(T[] array, int fromIndex,
+                                          int toIndex, BinaryOperator<T> op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.CumulateTask<>
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(long[] array, LongBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.LongCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(long[], LongBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(long[] array, int fromIndex,
+                                      int toIndex, LongBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.LongCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition,
+     * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * <p> Because floating-point operations may not be strictly associative,
+     * the returned result may not be identical to the value that would be
+     * obtained if the operation was performed sequentially.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free function to perform the cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(double[] array, DoubleBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.DoubleCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(double[], DoubleBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(double[] array, int fromIndex,
+                                      int toIndex, DoubleBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.DoubleCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    /**
+     * Cumulates, in parallel, each element of the given array in place,
+     * using the supplied function. For example if the array initially
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
+     * Parallel prefix computation is usually more efficient than
+     * sequential loops for large arrays.
+     *
+     * @param array the array, which is modified in-place by this method
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(int[] array, IntBinaryOperator op) {
+        Objects.requireNonNull(op);
+        if (array.length > 0)
+            new ArrayPrefixHelpers.IntCumulateTask
+                    (null, op, array, 0, array.length).invoke();
+    }
+
+    /**
+     * Performs {@link #parallelPrefix(int[], IntBinaryOperator)}
+     * for the given subrange of the array.
+     *
+     * @param array the array
+     * @param fromIndex the index of the first element, inclusive
+     * @param toIndex the index of the last element, exclusive
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
+     * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *     if {@code fromIndex < 0} or {@code toIndex > array.length}
+     * @throws NullPointerException if the specified array or function is null
+     * @since 1.8
+     */
+    public static void parallelPrefix(int[] array, int fromIndex,
+                                      int toIndex, IntBinaryOperator op) {
+        Objects.requireNonNull(op);
+        rangeCheck(array.length, fromIndex, toIndex);
+        if (fromIndex < toIndex)
+            new ArrayPrefixHelpers.IntCumulateTask
+                    (null, op, array, fromIndex, toIndex).invoke();
+    }
+
+    // Searching
+
+    /**
+     * Searches the specified array of longs for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(long[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(long[] a, long key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of longs for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(long[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(long[] a, int fromIndex, int toIndex,
+                                   long key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(long[] a, int fromIndex, int toIndex,
+                                     long key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            long midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of ints for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(int[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(int[] a, int key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of ints for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(int[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(int[] a, int fromIndex, int toIndex,
+                                   int key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(int[] a, int fromIndex, int toIndex,
+                                     int key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            int midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of shorts for the specified value using
+     * the binary search algorithm.  The array must be sorted
+     * (as by the {@link #sort(short[])} method) prior to making this call.  If
+     * it is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(short[] a, short key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of shorts for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(short[], int, int)} method)
+     * prior to making this call.  If
+     * it is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(short[] a, int fromIndex, int toIndex,
+                                   short key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(short[] a, int fromIndex, int toIndex,
+                                     short key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            short midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of chars for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(char[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(char[] a, char key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of chars for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(char[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(char[] a, int fromIndex, int toIndex,
+                                   char key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(char[] a, int fromIndex, int toIndex,
+                                     char key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            char midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of bytes for the specified value using the
+     * binary search algorithm.  The array must be sorted (as
+     * by the {@link #sort(byte[])} method) prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(byte[] a, byte key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of bytes for the specified value using the
+     * binary search algorithm.
+     * The range must be sorted (as
+     * by the {@link #sort(byte[], int, int)} method)
+     * prior to making this call.  If it
+     * is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(byte[] a, int fromIndex, int toIndex,
+                                   byte key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(byte[] a, int fromIndex, int toIndex,
+                                     byte key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            byte midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;
+            else if (midVal > key)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of doubles for the specified value using
+     * the binary search algorithm.  The array must be sorted
+     * (as by the {@link #sort(double[])} method) prior to making this call.
+     * If it is not sorted, the results are undefined.  If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.  This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(double[] a, double key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of doubles for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(double[], int, int)} method)
+     * prior to making this call.
+     * If it is not sorted, the results are undefined.  If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found.  This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(double[] a, int fromIndex, int toIndex,
+                                   double key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(double[] a, int fromIndex, int toIndex,
+                                     double key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            double midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;  // Neither val is NaN, thisVal is smaller
+            else if (midVal > key)
+                high = mid - 1; // Neither val is NaN, thisVal is larger
+            else {
+                long midBits = Double.doubleToLongBits(midVal);
+                long keyBits = Double.doubleToLongBits(key);
+                if (midBits == keyBits)     // Values are equal
+                    return mid;             // Key found
+                else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
+                    low = mid + 1;
+                else                        // (0.0, -0.0) or (NaN, !NaN)
+                    high = mid - 1;
+            }
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array of floats for the specified value using
+     * the binary search algorithm. The array must be sorted
+     * (as by the {@link #sort(float[])} method) prior to making this call. If
+     * it is not sorted, the results are undefined. If the array contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found. This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key. Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     */
+    public static int binarySearch(float[] a, float key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array of floats for the specified value using
+     * the binary search algorithm.
+     * The range must be sorted
+     * (as by the {@link #sort(float[], int, int)} method)
+     * prior to making this call. If
+     * it is not sorted, the results are undefined. If the range contains
+     * multiple elements with the specified value, there is no guarantee which
+     * one will be found. This method considers all NaN values to be
+     * equivalent and equal.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>. The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key. Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(float[] a, int fromIndex, int toIndex,
+                                   float key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(float[] a, int fromIndex, int toIndex,
+                                     float key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            float midVal = a[mid];
+
+            if (midVal < key)
+                low = mid + 1;  // Neither val is NaN, thisVal is smaller
+            else if (midVal > key)
+                high = mid - 1; // Neither val is NaN, thisVal is larger
+            else {
+                int midBits = Float.floatToIntBits(midVal);
+                int keyBits = Float.floatToIntBits(key);
+                if (midBits == keyBits)     // Values are equal
+                    return mid;             // Key found
+                else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN)
+                    low = mid + 1;
+                else                        // (0.0, -0.0) or (NaN, !NaN)
+                    high = mid - 1;
+            }
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array for the specified object using the binary
+     * search algorithm. The array must be sorted into ascending order
+     * according to the
+     * {@linkplain Comparable natural ordering}
+     * of its elements (as by the
+     * {@link #sort(Object[])} method) prior to making this call.
+     * If it is not sorted, the results are undefined.
+     * (If the array contains elements that are not mutually comparable (for
+     * example, strings and integers), it <i>cannot</i> be sorted according
+     * to the natural ordering of its elements, hence results are undefined.)
+     * If the array contains multiple
+     * elements equal to the specified object, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the search key is not comparable to the
+     *         elements of the array.
+     */
+    public static int binarySearch(Object[] a, Object key) {
+        return binarySearch0(a, 0, a.length, key);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array for the specified object using the binary
+     * search algorithm.
+     * The range must be sorted into ascending order
+     * according to the
+     * {@linkplain Comparable natural ordering}
+     * of its elements (as by the
+     * {@link #sort(Object[], int, int)} method) prior to making this
+     * call.  If it is not sorted, the results are undefined.
+     * (If the range contains elements that are not mutually comparable (for
+     * example, strings and integers), it <i>cannot</i> be sorted according
+     * to the natural ordering of its elements, hence results are undefined.)
+     * If the range contains multiple
+     * elements equal to the specified object, there is no guarantee which
+     * one will be found.
+     *
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the search key is not comparable to the
+     *         elements of the array within the specified range.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static int binarySearch(Object[] a, int fromIndex, int toIndex,
+                                   Object key) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key);
+    }
+
+    // Like public version, but without range checks.
+    private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
+                                     Object key) {
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            @SuppressWarnings("rawtypes")
+            Comparable midVal = (Comparable)a[mid];
+            @SuppressWarnings("unchecked")
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    /**
+     * Searches the specified array for the specified object using the binary
+     * search algorithm.  The array must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(Object[], Comparator) sort(T[], Comparator)}
+     * method) prior to making this call.  If it is
+     * not sorted, the results are undefined.
+     * If the array contains multiple
+     * elements equal to the specified object, there is no guarantee which one
+     * will be found.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array to be searched
+     * @param key the value to be searched for
+     * @param c the comparator by which the array is ordered.  A
+     *        <tt>null</tt> value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @return index of the search key, if it is contained in the array;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element greater than the key, or <tt>a.length</tt> if all
+     *         elements in the array are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the array contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not comparable to the
+     *         elements of the array using this comparator.
+     */
+    public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) {
+        return binarySearch0(a, 0, a.length, key, c);
+    }
+
+    /**
+     * Searches a range of
+     * the specified array for the specified object using the binary
+     * search algorithm.
+     * The range must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(Object[], int, int, Comparator)
+     * sort(T[], int, int, Comparator)}
+     * method) prior to making this call.
+     * If it is not sorted, the results are undefined.
+     * If the range contains multiple elements equal to the specified object,
+     * there is no guarantee which one will be found.
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array to be searched
+     * @param fromIndex the index of the first element (inclusive) to be
+     *          searched
+     * @param toIndex the index of the last element (exclusive) to be searched
+     * @param key the value to be searched for
+     * @param c the comparator by which the array is ordered.  A
+     *        <tt>null</tt> value indicates that the elements'
+     *        {@linkplain Comparable natural ordering} should be used.
+     * @return index of the search key, if it is contained in the array
+     *         within the specified range;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the array: the index of the first
+     *         element in the range greater than the key,
+     *         or <tt>toIndex</tt> if all
+     *         elements in the range are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the range contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not comparable to the
+     *         elements in the range using this comparator.
+     * @throws IllegalArgumentException
+     *         if {@code fromIndex > toIndex}
+     * @throws ArrayIndexOutOfBoundsException
+     *         if {@code fromIndex < 0 or toIndex > a.length}
+     * @since 1.6
+     */
+    public static <T> int binarySearch(T[] a, int fromIndex, int toIndex,
+                                       T key, Comparator<? super T> c) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        return binarySearch0(a, fromIndex, toIndex, key, c);
+    }
+
+    // Like public version, but without range checks.
+    private static <T> int binarySearch0(T[] a, int fromIndex, int toIndex,
+                                         T key, Comparator<? super T> c) {
+        if (c == null) {
+            return binarySearch0(a, fromIndex, toIndex, key);
+        }
+        int low = fromIndex;
+        int high = toIndex - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = a[mid];
+            int cmp = c.compare(midVal, key);
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found.
+    }
+
+    // Equality Testing
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of longs are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(long[] a, long[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of ints are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(int[] a, int[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of shorts are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(short[] a, short a2[]) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of chars are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(char[] a, char[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of bytes are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(byte[] a, byte[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of booleans are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(boolean[] a, boolean[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (a[i] != a2[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of doubles are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * Two doubles <tt>d1</tt> and <tt>d2</tt> are considered equal if:
+     * <pre>    <tt>new Double(d1).equals(new Double(d2))</tt></pre>
+     * (Unlike the <tt>==</tt> operator, this method considers
+     * <tt>NaN</tt> equals to itself, and 0.0d unequal to -0.0d.)
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     * @see Double#equals(Object)
+     */
+    public static boolean equals(double[] a, double[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (Double.doubleToLongBits(a[i])!=Double.doubleToLongBits(a2[i]))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of floats are
+     * <i>equal</i> to one another.  Two arrays are considered equal if both
+     * arrays contain the same number of elements, and all corresponding pairs
+     * of elements in the two arrays are equal.  In other words, two arrays
+     * are equal if they contain the same elements in the same order.  Also,
+     * two array references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * Two floats <tt>f1</tt> and <tt>f2</tt> are considered equal if:
+     * <pre>    <tt>new Float(f1).equals(new Float(f2))</tt></pre>
+     * (Unlike the <tt>==</tt> operator, this method considers
+     * <tt>NaN</tt> equals to itself, and 0.0f unequal to -0.0f.)
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     * @see Float#equals(Object)
+     */
+    public static boolean equals(float[] a, float[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++)
+            if (Float.floatToIntBits(a[i])!=Float.floatToIntBits(a2[i]))
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays of Objects are
+     * <i>equal</i> to one another.  The two arrays are considered equal if
+     * both arrays contain the same number of elements, and all corresponding
+     * pairs of elements in the two arrays are equal.  Two objects <tt>e1</tt>
+     * and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
+     * : e1.equals(e2))</tt>.  In other words, the two arrays are equal if
+     * they contain the same elements in the same order.  Also, two array
+     * references are considered equal if both are <tt>null</tt>.<p>
+     *
+     * @param a one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     */
+    public static boolean equals(Object[] a, Object[] a2) {
+        if (a==a2)
+            return true;
+        if (a==null || a2==null)
+            return false;
+
+        int length = a.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i=0; i<length; i++) {
+            Object o1 = a[i];
+            Object o2 = a2[i];
+            if (!(o1==null ? o2==null : o1.equals(o2)))
+                return false;
+        }
+
+        return true;
+    }
+
+    // Filling
+
+    /**
+     * Assigns the specified long value to each element of the specified array
+     * of longs.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(long[] a, long val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified long value to each element of the specified
+     * range of the specified array of longs.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(long[] a, int fromIndex, int toIndex, long val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified int value to each element of the specified array
+     * of ints.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(int[] a, int val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified int value to each element of the specified
+     * range of the specified array of ints.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(int[] a, int fromIndex, int toIndex, int val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified short value to each element of the specified array
+     * of shorts.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(short[] a, short val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified short value to each element of the specified
+     * range of the specified array of shorts.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(short[] a, int fromIndex, int toIndex, short val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified char value to each element of the specified array
+     * of chars.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(char[] a, char val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified char value to each element of the specified
+     * range of the specified array of chars.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(char[] a, int fromIndex, int toIndex, char val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified byte value to each element of the specified array
+     * of bytes.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(byte[] a, byte val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified byte value to each element of the specified
+     * range of the specified array of bytes.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(byte[] a, int fromIndex, int toIndex, byte val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified boolean value to each element of the specified
+     * array of booleans.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(boolean[] a, boolean val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified boolean value to each element of the specified
+     * range of the specified array of booleans.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(boolean[] a, int fromIndex, int toIndex,
+                            boolean val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified double value to each element of the specified
+     * array of doubles.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(double[] a, double val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified double value to each element of the specified
+     * range of the specified array of doubles.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(double[] a, int fromIndex, int toIndex,double val){
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified float value to each element of the specified array
+     * of floats.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     */
+    public static void fill(float[] a, float val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified float value to each element of the specified
+     * range of the specified array of floats.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     */
+    public static void fill(float[] a, int fromIndex, int toIndex, float val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified Object reference to each element of the specified
+     * array of Objects.
+     *
+     * @param a the array to be filled
+     * @param val the value to be stored in all elements of the array
+     * @throws ArrayStoreException if the specified value is not of a
+     *         runtime type that can be stored in the specified array
+     */
+    public static void fill(Object[] a, Object val) {
+        for (int i = 0, len = a.length; i < len; i++)
+            a[i] = val;
+    }
+
+    /**
+     * Assigns the specified Object reference to each element of the specified
+     * range of the specified array of Objects.  The range to be filled
+     * extends from index <tt>fromIndex</tt>, inclusive, to index
+     * <tt>toIndex</tt>, exclusive.  (If <tt>fromIndex==toIndex</tt>, the
+     * range to be filled is empty.)
+     *
+     * @param a the array to be filled
+     * @param fromIndex the index of the first element (inclusive) to be
+     *        filled with the specified value
+     * @param toIndex the index of the last element (exclusive) to be
+     *        filled with the specified value
+     * @param val the value to be stored in all elements of the array
+     * @throws IllegalArgumentException if <tt>fromIndex &gt; toIndex</tt>
+     * @throws ArrayIndexOutOfBoundsException if <tt>fromIndex &lt; 0</tt> or
+     *         <tt>toIndex &gt; a.length</tt>
+     * @throws ArrayStoreException if the specified value is not of a
+     *         runtime type that can be stored in the specified array
+     */
+    public static void fill(Object[] a, int fromIndex, int toIndex, Object val) {
+        rangeCheck(a.length, fromIndex, toIndex);
+        for (int i = fromIndex; i < toIndex; i++)
+            a[i] = val;
+    }
+
+    // Cloning
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>null</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] copyOf(T[] original, int newLength) {
+        return (T[]) copyOf(original, newLength, original.getClass());
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with nulls (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>null</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     * The resulting array is of the class <tt>newType</tt>.
+     *
+     * @param <U> the class of the objects in the original array
+     * @param <T> the class of the objects in the returned array
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @param newType the class of the copy to be returned
+     * @return a copy of the original array, truncated or padded with nulls
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws ArrayStoreException if an element copied from
+     *     <tt>original</tt> is not of a runtime type that can be stored in
+     *     an array of class <tt>newType</tt>
+     * @since 1.6
+     */
+    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
+        @SuppressWarnings("unchecked")
+        T[] copy = ((Object)newType == (Object)Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>(byte)0</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static byte[] copyOf(byte[] original, int newLength) {
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>(short)0</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static short[] copyOf(short[] original, int newLength) {
+        short[] copy = new short[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static int[] copyOf(int[] original, int newLength) {
+        int[] copy = new int[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0L</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static long[] copyOf(long[] original, int newLength) {
+        long[] copy = new long[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with null characters (if necessary)
+     * so the copy has the specified length.  For all indices that are valid
+     * in both the original array and the copy, the two arrays will contain
+     * identical values.  For any indices that are valid in the copy but not
+     * the original, the copy will contain <tt>'\\u000'</tt>.  Such indices
+     * will exist if and only if the specified length is greater than that of
+     * the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with null characters
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static char[] copyOf(char[] original, int newLength) {
+        char[] copy = new char[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0f</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static float[] copyOf(float[] original, int newLength) {
+        float[] copy = new float[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with zeros (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>0d</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with zeros
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static double[] copyOf(double[] original, int newLength) {
+        double[] copy = new double[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified array, truncating or padding with <tt>false</tt> (if necessary)
+     * so the copy has the specified length.  For all indices that are
+     * valid in both the original array and the copy, the two arrays will
+     * contain identical values.  For any indices that are valid in the
+     * copy but not the original, the copy will contain <tt>false</tt>.
+     * Such indices will exist if and only if the specified length
+     * is greater than that of the original array.
+     *
+     * @param original the array to be copied
+     * @param newLength the length of the copy to be returned
+     * @return a copy of the original array, truncated or padded with false elements
+     *     to obtain the specified length
+     * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static boolean[] copyOf(boolean[] original, int newLength) {
+        boolean[] copy = new boolean[newLength];
+        System.arraycopy(original, 0, copy, 0,
+                         Math.min(original.length, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>null</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     * <p>
+     * The resulting array is of exactly the same class as the original array.
+     *
+     * @param <T> the class of the objects in the array
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with nulls to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] copyOfRange(T[] original, int from, int to) {
+        return copyOfRange(original, from, to, (Class<? extends T[]>) original.getClass());
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>null</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     * The resulting array is of the class <tt>newType</tt>.
+     *
+     * @param <U> the class of the objects in the original array
+     * @param <T> the class of the objects in the returned array
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @param newType the class of the copy to be returned
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with nulls to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @throws ArrayStoreException if an element copied from
+     *     <tt>original</tt> is not of a runtime type that can be stored in
+     *     an array of class <tt>newType</tt>.
+     * @since 1.6
+     */
+    public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        @SuppressWarnings("unchecked")
+        T[] copy = ((Object)newType == (Object)Object[].class)
+            ? (T[]) new Object[newLength]
+            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>(byte)0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static byte[] copyOfRange(byte[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        byte[] copy = new byte[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>(short)0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static short[] copyOfRange(short[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        short[] copy = new short[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static int[] copyOfRange(int[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        int[] copy = new int[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0L</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static long[] copyOfRange(long[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        long[] copy = new long[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>'\\u000'</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with null characters to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static char[] copyOfRange(char[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        char[] copy = new char[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0f</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static float[] copyOfRange(float[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        float[] copy = new float[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>0d</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with zeros to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static double[] copyOfRange(double[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        double[] copy = new double[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    /**
+     * Copies the specified range of the specified array into a new array.
+     * The initial index of the range (<tt>from</tt>) must lie between zero
+     * and <tt>original.length</tt>, inclusive.  The value at
+     * <tt>original[from]</tt> is placed into the initial element of the copy
+     * (unless <tt>from == original.length</tt> or <tt>from == to</tt>).
+     * Values from subsequent elements in the original array are placed into
+     * subsequent elements in the copy.  The final index of the range
+     * (<tt>to</tt>), which must be greater than or equal to <tt>from</tt>,
+     * may be greater than <tt>original.length</tt>, in which case
+     * <tt>false</tt> is placed in all elements of the copy whose index is
+     * greater than or equal to <tt>original.length - from</tt>.  The length
+     * of the returned array will be <tt>to - from</tt>.
+     *
+     * @param original the array from which a range is to be copied
+     * @param from the initial index of the range to be copied, inclusive
+     * @param to the final index of the range to be copied, exclusive.
+     *     (This index may lie outside the array.)
+     * @return a new array containing the specified range from the original array,
+     *     truncated or padded with false elements to obtain the required length
+     * @throws ArrayIndexOutOfBoundsException if {@code from < 0}
+     *     or {@code from > original.length}
+     * @throws IllegalArgumentException if <tt>from &gt; to</tt>
+     * @throws NullPointerException if <tt>original</tt> is null
+     * @since 1.6
+     */
+    public static boolean[] copyOfRange(boolean[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        boolean[] copy = new boolean[newLength];
+        System.arraycopy(original, from, copy, 0,
+                         Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    // Misc
+
+    /**
+     * Returns a fixed-size list backed by the specified array.  (Changes to
+     * the returned list "write through" to the array.)  This method acts
+     * as bridge between array-based and collection-based APIs, in
+     * combination with {@link Collection#toArray}.  The returned list is
+     * serializable and implements {@link RandomAccess}.
+     *
+     * <p>This method also provides a convenient way to create a fixed-size
+     * list initialized to contain several elements:
+     * <pre>
+     *     List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
+     * </pre>
+     *
+     * @param <T> the class of the objects in the array
+     * @param a the array by which the list will be backed
+     * @return a list view of the specified array
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public static <T> List<T> asList(T... a) {
+        return new ArrayList<>(a);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ArrayList<E> extends AbstractList<E>
+        implements RandomAccess, java.io.Serializable
+    {
+        private static final long serialVersionUID = -2764017481108945198L;
+        private final E[] a;
+
+        ArrayList(E[] array) {
+            a = Objects.requireNonNull(array);
+        }
+
+        @Override
+        public int size() {
+            return a.length;
+        }
+
+        @Override
+        public Object[] toArray() {
+            return a.clone();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            if (a.length < size)
+                return Arrays.copyOf(this.a, size,
+                                     (Class<? extends T[]>) a.getClass());
+            System.arraycopy(this.a, 0, a, 0, size);
+            if (a.length > size)
+                a[size] = null;
+            return a;
+        }
+
+        @Override
+        public E get(int index) {
+            return a[index];
+        }
+
+        @Override
+        public E set(int index, E element) {
+            E oldValue = a[index];
+            a[index] = element;
+            return oldValue;
+        }
+
+        @Override
+        public int indexOf(Object o) {
+            E[] a = this.a;
+            if (o == null) {
+                for (int i = 0; i < a.length; i++)
+                    if (a[i] == null)
+                        return i;
+            } else {
+                for (int i = 0; i < a.length; i++)
+                    if (o.equals(a[i]))
+                        return i;
+            }
+            return -1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return indexOf(o) != -1;
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return Spliterators.spliterator(a, Spliterator.ORDERED);
+        }
+
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            for (E e : a) {
+                action.accept(e);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            E[] a = this.a;
+            for (int i = 0; i < a.length; i++) {
+                a[i] = operator.apply(a[i]);
+            }
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            Arrays.sort(a, c);
+        }
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>long</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Long}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(long a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (long element : a) {
+            int elementHash = (int)(element ^ (element >>> 32));
+            result = 31 * result + elementHash;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two non-null <tt>int</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Integer}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(int a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (int element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>short</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Short}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(short a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (short element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>char</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Character}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(char a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (char element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>byte</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Byte}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(byte a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (byte element : a)
+            result = 31 * result + element;
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>boolean</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Boolean}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(boolean a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (boolean element : a)
+            result = 31 * result + (element ? 1231 : 1237);
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>float</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Float}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(float a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (float element : a)
+            result = 31 * result + Float.floatToIntBits(element);
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.
+     * For any two <tt>double</tt> arrays <tt>a</tt> and <tt>b</tt>
+     * such that <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is the same value that would be
+     * obtained by invoking the {@link List#hashCode() <tt>hashCode</tt>}
+     * method on a {@link List} containing a sequence of {@link Double}
+     * instances representing the elements of <tt>a</tt> in the same order.
+     * If <tt>a</tt> is <tt>null</tt>, this method returns 0.
+     *
+     * @param a the array whose hash value to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @since 1.5
+     */
+    public static int hashCode(double a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+        for (double element : a) {
+            long bits = Double.doubleToLongBits(element);
+            result = 31 * result + (int)(bits ^ (bits >>> 32));
+        }
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the contents of the specified array.  If
+     * the array contains other arrays as elements, the hash code is based on
+     * their identities rather than their contents.  It is therefore
+     * acceptable to invoke this method on an array that contains itself as an
+     * element,  either directly or indirectly through one or more levels of
+     * arrays.
+     *
+     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
+     * <tt>Arrays.equals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
+     *
+     * <p>The value returned by this method is equal to the value that would
+     * be returned by <tt>Arrays.asList(a).hashCode()</tt>, unless <tt>a</tt>
+     * is <tt>null</tt>, in which case <tt>0</tt> is returned.
+     *
+     * @param a the array whose content-based hash code to compute
+     * @return a content-based hash code for <tt>a</tt>
+     * @see #deepHashCode(Object[])
+     * @since 1.5
+     */
+    public static int hashCode(Object a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+
+        for (Object element : a)
+            result = 31 * result + (element == null ? 0 : element.hashCode());
+
+        return result;
+    }
+
+    /**
+     * Returns a hash code based on the "deep contents" of the specified
+     * array.  If the array contains other arrays as elements, the
+     * hash code is based on their contents and so on, ad infinitum.
+     * It is therefore unacceptable to invoke this method on an array that
+     * contains itself as an element, either directly or indirectly through
+     * one or more levels of arrays.  The behavior of such an invocation is
+     * undefined.
+     *
+     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
+     * <tt>Arrays.deepEquals(a, b)</tt>, it is also the case that
+     * <tt>Arrays.deepHashCode(a) == Arrays.deepHashCode(b)</tt>.
+     *
+     * <p>The computation of the value returned by this method is similar to
+     * that of the value returned by {@link List#hashCode()} on a list
+     * containing the same elements as <tt>a</tt> in the same order, with one
+     * difference: If an element <tt>e</tt> of <tt>a</tt> is itself an array,
+     * its hash code is computed not by calling <tt>e.hashCode()</tt>, but as
+     * by calling the appropriate overloading of <tt>Arrays.hashCode(e)</tt>
+     * if <tt>e</tt> is an array of a primitive type, or as by calling
+     * <tt>Arrays.deepHashCode(e)</tt> recursively if <tt>e</tt> is an array
+     * of a reference type.  If <tt>a</tt> is <tt>null</tt>, this method
+     * returns 0.
+     *
+     * @param a the array whose deep-content-based hash code to compute
+     * @return a deep-content-based hash code for <tt>a</tt>
+     * @see #hashCode(Object[])
+     * @since 1.5
+     */
+    public static int deepHashCode(Object a[]) {
+        if (a == null)
+            return 0;
+
+        int result = 1;
+
+        for (Object element : a) {
+            int elementHash = 0;
+            // BEGIN Android-changed: getComponentType() is faster than instanceof()
+            if (element != null) {
+                Class<?> cl = element.getClass().getComponentType();
+                if (cl == null)
+                    elementHash = element.hashCode();
+                else if (element instanceof Object[])
+                    elementHash = deepHashCode((Object[]) element);
+                else if (cl == byte.class)
+                    elementHash = hashCode((byte[]) element);
+                else if (cl == short.class)
+                    elementHash = hashCode((short[]) element);
+                else if (cl == int.class)
+                    elementHash = hashCode((int[]) element);
+                else if (cl == long.class)
+                    elementHash = hashCode((long[]) element);
+                else if (cl == char.class)
+                    elementHash = hashCode((char[]) element);
+                else if (cl == float.class)
+                    elementHash = hashCode((float[]) element);
+                else if (cl == double.class)
+                    elementHash = hashCode((double[]) element);
+                else if (cl == boolean.class)
+                    elementHash = hashCode((boolean[]) element);
+                else
+                    elementHash = element.hashCode();
+            }
+            // END Android-changed: getComponentType() is faster than instanceof()
+            result = 31 * result + elementHash;
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns <tt>true</tt> if the two specified arrays are <i>deeply
+     * equal</i> to one another.  Unlike the {@link #equals(Object[],Object[])}
+     * method, this method is appropriate for use with nested arrays of
+     * arbitrary depth.
+     *
+     * <p>Two array references are considered deeply equal if both
+     * are <tt>null</tt>, or if they refer to arrays that contain the same
+     * number of elements and all corresponding pairs of elements in the two
+     * arrays are deeply equal.
+     *
+     * <p>Two possibly <tt>null</tt> elements <tt>e1</tt> and <tt>e2</tt> are
+     * deeply equal if any of the following conditions hold:
+     * <ul>
+     *    <li> <tt>e1</tt> and <tt>e2</tt> are both arrays of object reference
+     *         types, and <tt>Arrays.deepEquals(e1, e2) would return true</tt>
+     *    <li> <tt>e1</tt> and <tt>e2</tt> are arrays of the same primitive
+     *         type, and the appropriate overloading of
+     *         <tt>Arrays.equals(e1, e2)</tt> would return true.
+     *    <li> <tt>e1 == e2</tt>
+     *    <li> <tt>e1.equals(e2)</tt> would return true.
+     * </ul>
+     * Note that this definition permits <tt>null</tt> elements at any depth.
+     *
+     * <p>If either of the specified arrays contain themselves as elements
+     * either directly or indirectly through one or more levels of arrays,
+     * the behavior of this method is undefined.
+     *
+     * @param a1 one array to be tested for equality
+     * @param a2 the other array to be tested for equality
+     * @return <tt>true</tt> if the two arrays are equal
+     * @see #equals(Object[],Object[])
+     * @see Objects#deepEquals(Object, Object)
+     * @since 1.5
+     */
+    public static boolean deepEquals(Object[] a1, Object[] a2) {
+        if (a1 == a2)
+            return true;
+        if (a1 == null || a2==null)
+            return false;
+        int length = a1.length;
+        if (a2.length != length)
+            return false;
+
+        for (int i = 0; i < length; i++) {
+            Object e1 = a1[i];
+            Object e2 = a2[i];
+
+            if (e1 == e2)
+                continue;
+            if (e1 == null)
+                return false;
+
+            // Figure out whether the two elements are equal
+            boolean eq = deepEquals0(e1, e2);
+
+            if (!eq)
+                return false;
+        }
+        return true;
+    }
+
+    static boolean deepEquals0(Object e1, Object e2) {
+        assert e1 != null;
+        boolean eq;
+        if (e1 instanceof Object[] && e2 instanceof Object[])
+            eq = deepEquals ((Object[]) e1, (Object[]) e2);
+        else if (e1 instanceof byte[] && e2 instanceof byte[])
+            eq = equals((byte[]) e1, (byte[]) e2);
+        else if (e1 instanceof short[] && e2 instanceof short[])
+            eq = equals((short[]) e1, (short[]) e2);
+        else if (e1 instanceof int[] && e2 instanceof int[])
+            eq = equals((int[]) e1, (int[]) e2);
+        else if (e1 instanceof long[] && e2 instanceof long[])
+            eq = equals((long[]) e1, (long[]) e2);
+        else if (e1 instanceof char[] && e2 instanceof char[])
+            eq = equals((char[]) e1, (char[]) e2);
+        else if (e1 instanceof float[] && e2 instanceof float[])
+            eq = equals((float[]) e1, (float[]) e2);
+        else if (e1 instanceof double[] && e2 instanceof double[])
+            eq = equals((double[]) e1, (double[]) e2);
+        else if (e1 instanceof boolean[] && e2 instanceof boolean[])
+            eq = equals((boolean[]) e1, (boolean[]) e2);
+        else
+            eq = e1.equals(e2);
+        return eq;
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(long)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(long[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(int)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt> is
+     * <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(int[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(short)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(short[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(char)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(char[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements
+     * are separated by the characters <tt>", "</tt> (a comma followed
+     * by a space).  Elements are converted to strings as by
+     * <tt>String.valueOf(byte)</tt>.  Returns <tt>"null"</tt> if
+     * <tt>a</tt> is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(byte[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(boolean)</tt>.  Returns <tt>"null"</tt> if
+     * <tt>a</tt> is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(boolean[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(float)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(float[] a) {
+        if (a == null)
+            return "null";
+
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * The string representation consists of a list of the array's elements,
+     * enclosed in square brackets (<tt>"[]"</tt>).  Adjacent elements are
+     * separated by the characters <tt>", "</tt> (a comma followed by a
+     * space).  Elements are converted to strings as by
+     * <tt>String.valueOf(double)</tt>.  Returns <tt>"null"</tt> if <tt>a</tt>
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @since 1.5
+     */
+    public static String toString(double[] a) {
+        if (a == null)
+            return "null";
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(a[i]);
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the contents of the specified array.
+     * If the array contains other arrays as elements, they are converted to
+     * strings by the {@link Object#toString} method inherited from
+     * <tt>Object</tt>, which describes their <i>identities</i> rather than
+     * their contents.
+     *
+     * <p>The value returned by this method is equal to the value that would
+     * be returned by <tt>Arrays.asList(a).toString()</tt>, unless <tt>a</tt>
+     * is <tt>null</tt>, in which case <tt>"null"</tt> is returned.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @see #deepToString(Object[])
+     * @since 1.5
+     */
+    public static String toString(Object[] a) {
+        if (a == null)
+            return "null";
+
+        int iMax = a.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(String.valueOf(a[i]));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(", ");
+        }
+    }
+
+    /**
+     * Returns a string representation of the "deep contents" of the specified
+     * array.  If the array contains other arrays as elements, the string
+     * representation contains their contents and so on.  This method is
+     * designed for converting multidimensional arrays to strings.
+     *
+     * <p>The string representation consists of a list of the array's
+     * elements, enclosed in square brackets (<tt>"[]"</tt>).  Adjacent
+     * elements are separated by the characters <tt>", "</tt> (a comma
+     * followed by a space).  Elements are converted to strings as by
+     * <tt>String.valueOf(Object)</tt>, unless they are themselves
+     * arrays.
+     *
+     * <p>If an element <tt>e</tt> is an array of a primitive type, it is
+     * converted to a string as by invoking the appropriate overloading of
+     * <tt>Arrays.toString(e)</tt>.  If an element <tt>e</tt> is an array of a
+     * reference type, it is converted to a string as by invoking
+     * this method recursively.
+     *
+     * <p>To avoid infinite recursion, if the specified array contains itself
+     * as an element, or contains an indirect reference to itself through one
+     * or more levels of arrays, the self-reference is converted to the string
+     * <tt>"[...]"</tt>.  For example, an array containing only a reference
+     * to itself would be rendered as <tt>"[[...]]"</tt>.
+     *
+     * <p>This method returns <tt>"null"</tt> if the specified array
+     * is <tt>null</tt>.
+     *
+     * @param a the array whose string representation to return
+     * @return a string representation of <tt>a</tt>
+     * @see #toString(Object[])
+     * @since 1.5
+     */
+    public static String deepToString(Object[] a) {
+        if (a == null)
+            return "null";
+
+        int bufLen = 20 * a.length;
+        if (a.length != 0 && bufLen <= 0)
+            bufLen = Integer.MAX_VALUE;
+        StringBuilder buf = new StringBuilder(bufLen);
+        deepToString(a, buf, new HashSet<Object[]>());
+        return buf.toString();
+    }
+
+    private static void deepToString(Object[] a, StringBuilder buf,
+                                     Set<Object[]> dejaVu) {
+        if (a == null) {
+            buf.append("null");
+            return;
+        }
+        int iMax = a.length - 1;
+        if (iMax == -1) {
+            buf.append("[]");
+            return;
+        }
+
+        dejaVu.add(a);
+        buf.append('[');
+        for (int i = 0; ; i++) {
+
+            Object element = a[i];
+            if (element == null) {
+                buf.append("null");
+            } else {
+                Class<?> eClass = element.getClass();
+
+                if (eClass.isArray()) {
+                    if (eClass == byte[].class)
+                        buf.append(toString((byte[]) element));
+                    else if (eClass == short[].class)
+                        buf.append(toString((short[]) element));
+                    else if (eClass == int[].class)
+                        buf.append(toString((int[]) element));
+                    else if (eClass == long[].class)
+                        buf.append(toString((long[]) element));
+                    else if (eClass == char[].class)
+                        buf.append(toString((char[]) element));
+                    else if (eClass == float[].class)
+                        buf.append(toString((float[]) element));
+                    else if (eClass == double[].class)
+                        buf.append(toString((double[]) element));
+                    else if (eClass == boolean[].class)
+                        buf.append(toString((boolean[]) element));
+                    else { // element is an array of object references
+                        if (dejaVu.contains(element))
+                            buf.append("[...]");
+                        else
+                            deepToString((Object[])element, buf, dejaVu);
+                    }
+                } else {  // element is non-null and not an array
+                    buf.append(element.toString());
+                }
+            }
+            if (i == iMax)
+                break;
+            buf.append(", ");
+        }
+        buf.append(']');
+        dejaVu.remove(a);
+    }
+
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void setAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.apply(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param <T> type of elements of the array
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsInt(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     * value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(int[] array, IntUnaryOperator generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsInt(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsLong(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(long[] array, IntToLongFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsLong(i); });
+    }
+
+    /**
+     * Set all elements of the specified array, using the provided
+     * generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, it is relayed to
+     * the caller and the array is left in an indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void setAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        for (int i = 0; i < array.length; i++)
+            array[i] = generator.applyAsDouble(i);
+    }
+
+    /**
+     * Set all elements of the specified array, in parallel, using the
+     * provided generator function to compute each element.
+     *
+     * <p>If the generator function throws an exception, an unchecked exception
+     * is thrown from {@code parallelSetAll} and the array is left in an
+     * indeterminate state.
+     *
+     * @param array array to be initialized
+     * @param generator a function accepting an index and producing the desired
+     *        value for that position
+     * @throws NullPointerException if the generator is null
+     * @since 1.8
+     */
+    public static void parallelSetAll(double[] array, IntToDoubleFunction generator) {
+        Objects.requireNonNull(generator);
+        IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsDouble(i); });
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static <T> Spliterator<T> spliterator(T[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param <T> type of elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Spliterator<T> spliterator(T[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfInt} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfInt spliterator(int[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfInt} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfLong} covering all of the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return the spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfLong spliterator(long[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfLong} covering the specified range of the
+     * specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfDouble} covering all of the specified
+     * array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a spliterator for the array elements
+     * @since 1.8
+     */
+    public static Spliterator.OfDouble spliterator(double[] array) {
+        return Spliterators.spliterator(array,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a {@link Spliterator.OfDouble} covering the specified range of
+     * the specified array.
+     *
+     * <p>The spliterator reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#IMMUTABLE}.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a spliterator for the array elements
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive) {
+        return Spliterators.spliterator(array, startInclusive, endExclusive,
+                                        Spliterator.ORDERED | Spliterator.IMMUTABLE);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified array as its
+     * source.
+     *
+     * @param <T> The type of the array elements
+     * @param array The array, assumed to be unmodified during use
+     * @return a {@code Stream} for the array
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link Stream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param <T> the type of the array elements
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code Stream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return an {@code IntStream} for the array
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link IntStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return an {@code IntStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static IntStream stream(int[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code LongStream} for the array
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link LongStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code LongStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static LongStream stream(long[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified array as its
+     * source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @return a {@code DoubleStream} for the array
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array) {
+        return stream(array, 0, array.length);
+    }
+
+    /**
+     * Returns a sequential {@link DoubleStream} with the specified range of the
+     * specified array as its source.
+     *
+     * @param array the array, assumed to be unmodified during use
+     * @param startInclusive the first index to cover, inclusive
+     * @param endExclusive index immediately past the last index to cover
+     * @return a {@code DoubleStream} for the array range
+     * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is
+     *         negative, {@code endExclusive} is less than
+     *         {@code startInclusive}, or {@code endExclusive} is greater than
+     *         the array size
+     * @since 1.8
+     */
+    public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) {
+        return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false);
+    }
+}
diff --git a/java/util/ArraysParallelSortHelpers.java b/java/util/ArraysParallelSortHelpers.java
new file mode 100644
index 0000000..8fa2262
--- /dev/null
+++ b/java/util/ArraysParallelSortHelpers.java
@@ -0,0 +1,1010 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.concurrent.RecursiveAction;
+import java.util.concurrent.CountedCompleter;
+
+/**
+ * Helper utilities for the parallel sort methods in Arrays.parallelSort.
+ *
+ * For each primitive type, plus Object, we define a static class to
+ * contain the Sorter and Merger implementations for that type:
+ *
+ * Sorter classes based mainly on CilkSort
+ * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:
+ * Basic algorithm:
+ * if array size is small, just use a sequential quicksort (via Arrays.sort)
+ *         Otherwise:
+ *         1. Break array in half.
+ *         2. For each half,
+ *             a. break the half in half (i.e., quarters),
+ *             b. sort the quarters
+ *             c. merge them together
+ *         3. merge together the two halves.
+ *
+ * One reason for splitting in quarters is that this guarantees that
+ * the final sort is in the main array, not the workspace array.
+ * (workspace and main swap roles on each subsort step.)  Leaf-level
+ * sorts use the associated sequential sort.
+ *
+ * Merger classes perform merging for Sorter.  They are structured
+ * such that if the underlying sort is stable (as is true for
+ * TimSort), then so is the full sort.  If big enough, they split the
+ * largest of the two partitions in half, find the greatest point in
+ * smaller partition less than the beginning of the second half of
+ * larger via binary search; and then merge in parallel the two
+ * partitions.  In part to ensure tasks are triggered in
+ * stability-preserving order, the current CountedCompleter design
+ * requires some little tasks to serve as place holders for triggering
+ * completion tasks.  These classes (EmptyCompleter and Relay) don't
+ * need to keep track of the arrays, and are never themselves forked,
+ * so don't hold any task state.
+ *
+ * The primitive class versions (FJByte... FJDouble) are
+ * identical to each other except for type declarations.
+ *
+ * The base sequential sorts rely on non-public versions of TimSort,
+ * ComparableTimSort, and DualPivotQuicksort sort methods that accept
+ * temp workspace array slices that we will have already allocated, so
+ * avoids redundant allocation. (Except for DualPivotQuicksort byte[]
+ * sort, that does not ever use a workspace array.)
+ */
+/*package*/ class ArraysParallelSortHelpers {
+
+    /*
+     * Style note: The task classes have a lot of parameters, that are
+     * stored as task fields and copied to local variables and used in
+     * compute() methods, We pack these into as few lines as possible,
+     * and hoist consistency checks among them before main loops, to
+     * reduce distraction.
+     */
+
+    /**
+     * A placeholder task for Sorters, used for the lowest
+     * quartile task, that does not need to maintain array state.
+     */
+    static final class EmptyCompleter extends CountedCompleter<Void> {
+        static final long serialVersionUID = 2446542900576103244L;
+        EmptyCompleter(CountedCompleter<?> p) { super(p); }
+        public final void compute() { }
+    }
+
+    /**
+     * A trigger for secondary merge of two merges
+     */
+    static final class Relay extends CountedCompleter<Void> {
+        static final long serialVersionUID = 2446542900576103244L;
+        final CountedCompleter<?> task;
+        Relay(CountedCompleter<?> task) {
+            super(null, 1);
+            this.task = task;
+        }
+        public final void compute() { }
+        public final void onCompletion(CountedCompleter<?> t) {
+            task.compute();
+        }
+    }
+
+    /** Object + Comparator support class */
+    static final class FJObject {
+        static final class Sorter<T> extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final T[] a, w;
+            final int base, size, wbase, gran;
+            Comparator<? super T> comparator;
+            Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size,
+                   int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger<T>(s, w, a, wb, h,
+                                                       wb+h, n-h, b, g, c));
+                    Relay rc = new Relay(new Merger<T>(fc, a, w, b+h, q,
+                                                       b+u, n-u, wb+h, g, c));
+                    new Sorter<T>(rc, a, w, b+u, n-u, wb+u, g, c).fork();
+                    new Sorter<T>(rc, a, w, b+h, q, wb+h, g, c).fork();;
+                    Relay bc = new Relay(new Merger<T>(fc, a, w, b, q,
+                                                       b+q, h-q, wb, g, c));
+                    new Sorter<T>(bc, a, w, b+q, h-q, wb+q, g, c).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                TimSort.sort(a, b, b + n, c, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger<T> extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final T[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Comparator<? super T> comparator;
+            Merger(CountedCompleter<?> par, T[] a, T[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran,
+                   Comparator<? super T> comparator) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+                this.comparator = comparator;
+            }
+
+            public final void compute() {
+                Comparator<? super T> c = this.comparator;
+                T[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0 ||
+                    c == null)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        T split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (c.compare(split, a[rm + rb]) <= 0)
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        T split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (c.compare(split, a[lm + lb]) <= 0)
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger<T> m = new Merger<T>(this, a, w, lb + lh, ln - lh,
+                                                rb + rh, rn - rh,
+                                                k + lh + rh, g, c);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    T t, al, ar;
+                    if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+
+                tryComplete();
+            }
+
+        }
+    } // FJObject
+
+    /** byte support class */
+    static final class FJByte {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final byte[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, byte[] a, byte[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                byte[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final byte[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, byte[] a, byte[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                byte[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        byte split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        byte split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    byte t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJByte
+
+    /** char support class */
+    static final class FJChar {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final char[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, char[] a, char[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                char[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final char[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, char[] a, char[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                char[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        char split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        char split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    char t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJChar
+
+    /** short support class */
+    static final class FJShort {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final short[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, short[] a, short[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                short[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final short[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, short[] a, short[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                short[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        short split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        short split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    short t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJShort
+
+    /** int support class */
+    static final class FJInt {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final int[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, int[] a, int[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                int[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final int[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, int[] a, int[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                int[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        int split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        int split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    int t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJInt
+
+    /** long support class */
+    static final class FJLong {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final long[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, long[] a, long[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                long[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final long[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, long[] a, long[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                long[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        long split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        long split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    long t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJLong
+
+    /** float support class */
+    static final class FJFloat {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final float[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, float[] a, float[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                float[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final float[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, float[] a, float[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                float[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        float split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        float split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    float t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJFloat
+
+    /** double support class */
+    static final class FJDouble {
+        static final class Sorter extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final double[] a, w;
+            final int base, size, wbase, gran;
+            Sorter(CountedCompleter<?> par, double[] a, double[] w, int base,
+                   int size, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w; this.base = base; this.size = size;
+                this.wbase = wbase; this.gran = gran;
+            }
+            public final void compute() {
+                CountedCompleter<?> s = this;
+                double[] a = this.a, w = this.w; // localize all params
+                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
+                while (n > g) {
+                    int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
+                    Relay fc = new Relay(new Merger(s, w, a, wb, h,
+                                                    wb+h, n-h, b, g));
+                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
+                                                    b+u, n-u, wb+h, g));
+                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
+                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
+                    Relay bc = new Relay(new Merger(fc, a, w, b, q,
+                                                    b+q, h-q, wb, g));
+                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
+                    s = new EmptyCompleter(bc);
+                    n = q;
+                }
+                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
+                s.tryComplete();
+            }
+        }
+
+        static final class Merger extends CountedCompleter<Void> {
+            static final long serialVersionUID = 2446542900576103244L;
+            final double[] a, w; // main and workspace arrays
+            final int lbase, lsize, rbase, rsize, wbase, gran;
+            Merger(CountedCompleter<?> par, double[] a, double[] w,
+                   int lbase, int lsize, int rbase,
+                   int rsize, int wbase, int gran) {
+                super(par);
+                this.a = a; this.w = w;
+                this.lbase = lbase; this.lsize = lsize;
+                this.rbase = rbase; this.rsize = rsize;
+                this.wbase = wbase; this.gran = gran;
+            }
+
+            public final void compute() {
+                double[] a = this.a, w = this.w; // localize all params
+                int lb = this.lbase, ln = this.lsize, rb = this.rbase,
+                    rn = this.rsize, k = this.wbase, g = this.gran;
+                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
+                    throw new IllegalStateException(); // hoist checks
+                for (int lh, rh;;) {  // split larger, find point in smaller
+                    if (ln >= rn) {
+                        if (ln <= g)
+                            break;
+                        rh = rn;
+                        double split = a[(lh = ln >>> 1) + lb];
+                        for (int lo = 0; lo < rh; ) {
+                            int rm = (lo + rh) >>> 1;
+                            if (split <= a[rm + rb])
+                                rh = rm;
+                            else
+                                lo = rm + 1;
+                        }
+                    }
+                    else {
+                        if (rn <= g)
+                            break;
+                        lh = ln;
+                        double split = a[(rh = rn >>> 1) + rb];
+                        for (int lo = 0; lo < lh; ) {
+                            int lm = (lo + lh) >>> 1;
+                            if (split <= a[lm + lb])
+                                lh = lm;
+                            else
+                                lo = lm + 1;
+                        }
+                    }
+                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,
+                                          rb + rh, rn - rh,
+                                          k + lh + rh, g);
+                    rn = rh;
+                    ln = lh;
+                    addToPendingCount(1);
+                    m.fork();
+                }
+
+                int lf = lb + ln, rf = rb + rn; // index bounds
+                while (lb < lf && rb < rf) {
+                    double t, al, ar;
+                    if ((al = a[lb]) <= (ar = a[rb])) {
+                        lb++; t = al;
+                    }
+                    else {
+                        rb++; t = ar;
+                    }
+                    w[k++] = t;
+                }
+                if (rb < rf)
+                    System.arraycopy(a, rb, w, k, rf - rb);
+                else if (lb < lf)
+                    System.arraycopy(a, lb, w, k, lf - lb);
+                tryComplete();
+            }
+        }
+    } // FJDouble
+
+}
diff --git a/java/util/Base64.java b/java/util/Base64.java
new file mode 100644
index 0000000..be98fad
--- /dev/null
+++ b/java/util/Base64.java
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.FilterOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * This class consists exclusively of static methods for obtaining
+ * encoders and decoders for the Base64 encoding scheme. The
+ * implementation of this class supports the following types of Base64
+ * as specified in
+ * <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> and
+ * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
+ *
+ * <ul>
+ * <li><a name="basic"><b>Basic</b></a>
+ * <p> Uses "The Base64 Alphabet" as specified in Table 1 of
+ *     RFC 4648 and RFC 2045 for encoding and decoding operation.
+ *     The encoder does not add any line feed (line separator)
+ *     character. The decoder rejects data that contains characters
+ *     outside the base64 alphabet.</p></li>
+ *
+ * <li><a name="url"><b>URL and Filename safe</b></a>
+ * <p> Uses the "URL and Filename safe Base64 Alphabet" as specified
+ *     in Table 2 of RFC 4648 for encoding and decoding. The
+ *     encoder does not add any line feed (line separator) character.
+ *     The decoder rejects data that contains characters outside the
+ *     base64 alphabet.</p></li>
+ *
+ * <li><a name="mime"><b>MIME</b></a>
+ * <p> Uses the "The Base64 Alphabet" as specified in Table 1 of
+ *     RFC 2045 for encoding and decoding operation. The encoded output
+ *     must be represented in lines of no more than 76 characters each
+ *     and uses a carriage return {@code '\r'} followed immediately by
+ *     a linefeed {@code '\n'} as the line separator. No line separator
+ *     is added to the end of the encoded output. All line separators
+ *     or other characters not found in the base64 alphabet table are
+ *     ignored in decoding operation.</p></li>
+ * </ul>
+ *
+ * <p> Unless otherwise noted, passing a {@code null} argument to a
+ * method of this class will cause a {@link java.lang.NullPointerException
+ * NullPointerException} to be thrown.
+ *
+ * @author  Xueming Shen
+ * @since   1.8
+ */
+
+public class Base64 {
+
+    private Base64() {}
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#basic">Basic</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getEncoder() {
+         return Encoder.RFC4648;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#url">URL and Filename safe</a> type base64
+     * encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getUrlEncoder() {
+         return Encoder.RFC4648_URLSAFE;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#mime">MIME</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 encoder.
+     */
+    public static Encoder getMimeEncoder() {
+        return Encoder.RFC2045;
+    }
+
+    /**
+     * Returns a {@link Encoder} that encodes using the
+     * <a href="#mime">MIME</a> type base64 encoding scheme
+     * with specified line length and line separators.
+     *
+     * @param   lineLength
+     *          the length of each output line (rounded down to nearest multiple
+     *          of 4). If {@code lineLength <= 0} the output will not be separated
+     *          in lines
+     * @param   lineSeparator
+     *          the line separator for each output line
+     *
+     * @return  A Base64 encoder.
+     *
+     * @throws  IllegalArgumentException if {@code lineSeparator} includes any
+     *          character of "The Base64 Alphabet" as specified in Table 1 of
+     *          RFC 2045.
+     */
+    public static Encoder getMimeEncoder(int lineLength, byte[] lineSeparator) {
+         Objects.requireNonNull(lineSeparator);
+         int[] base64 = Decoder.fromBase64;
+         for (byte b : lineSeparator) {
+             if (base64[b & 0xff] != -1)
+                 throw new IllegalArgumentException(
+                     "Illegal base64 line separator character 0x" + Integer.toString(b, 16));
+         }
+         if (lineLength <= 0) {
+             return Encoder.RFC4648;
+         }
+         return new Encoder(false, lineSeparator, lineLength >> 2 << 2, true);
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#basic">Basic</a> type base64 encoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getDecoder() {
+         return Decoder.RFC4648;
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#url">URL and Filename safe</a> type base64
+     * encoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getUrlDecoder() {
+         return Decoder.RFC4648_URLSAFE;
+    }
+
+    /**
+     * Returns a {@link Decoder} that decodes using the
+     * <a href="#mime">MIME</a> type base64 decoding scheme.
+     *
+     * @return  A Base64 decoder.
+     */
+    public static Decoder getMimeDecoder() {
+         return Decoder.RFC2045;
+    }
+
+    /**
+     * This class implements an encoder for encoding byte data using
+     * the Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
+     *
+     * <p> Instances of {@link Encoder} class are safe for use by
+     * multiple concurrent threads.
+     *
+     * <p> Unless otherwise noted, passing a {@code null} argument to
+     * a method of this class will cause a
+     * {@link java.lang.NullPointerException NullPointerException} to
+     * be thrown.
+     *
+     * @see     Decoder
+     * @since   1.8
+     */
+    public static class Encoder {
+
+        private final byte[] newline;
+        private final int linemax;
+        private final boolean isURL;
+        private final boolean doPadding;
+
+        private Encoder(boolean isURL, byte[] newline, int linemax, boolean doPadding) {
+            this.isURL = isURL;
+            this.newline = newline;
+            this.linemax = linemax;
+            this.doPadding = doPadding;
+        }
+
+        /**
+         * This array is a lookup table that translates 6-bit positive integer
+         * index values into their "Base64 Alphabet" equivalents as specified
+         * in "Table 1: The Base64 Alphabet" of RFC 2045 (and RFC 4648).
+         */
+        private static final char[] toBase64 = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+        };
+
+        /**
+         * It's the lookup table for "URL and Filename safe Base64" as specified
+         * in Table 2 of the RFC 4648, with the '+' and '/' changed to '-' and
+         * '_'. This table is used when BASE64_URL is specified.
+         */
+        private static final char[] toBase64URL = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
+        };
+
+        private static final int MIMELINEMAX = 76;
+        private static final byte[] CRLF = new byte[] {'\r', '\n'};
+
+        static final Encoder RFC4648 = new Encoder(false, null, -1, true);
+        static final Encoder RFC4648_URLSAFE = new Encoder(true, null, -1, true);
+        static final Encoder RFC2045 = new Encoder(false, CRLF, MIMELINEMAX, true);
+
+        private final int outLength(int srclen) {
+            int len = 0;
+            if (doPadding) {
+                len = 4 * ((srclen + 2) / 3);
+            } else {
+                int n = srclen % 3;
+                len = 4 * (srclen / 3) + (n == 0 ? 0 : n + 1);
+            }
+            if (linemax > 0)                                  // line separators
+                len += (len - 1) / linemax * newline.length;
+            return len;
+        }
+
+        /**
+         * Encodes all bytes from the specified byte array into a newly-allocated
+         * byte array using the {@link Base64} encoding scheme. The returned byte
+         * array is of the length of the resulting bytes.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @return  A newly-allocated byte array containing the resulting
+         *          encoded bytes.
+         */
+        public byte[] encode(byte[] src) {
+            int len = outLength(src.length);          // dst array size
+            byte[] dst = new byte[len];
+            int ret = encode0(src, 0, src.length, dst);
+            if (ret != dst.length)
+                 return Arrays.copyOf(dst, ret);
+            return dst;
+        }
+
+        /**
+         * Encodes all bytes from the specified byte array using the
+         * {@link Base64} encoding scheme, writing the resulting bytes to the
+         * given output byte array, starting at offset 0.
+         *
+         * <p> It is the responsibility of the invoker of this method to make
+         * sure the output byte array {@code dst} has enough space for encoding
+         * all bytes from the input byte array. No bytes will be written to the
+         * output byte array if the output byte array is not big enough.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @param   dst
+         *          the output byte array
+         * @return  The number of bytes written to the output byte array
+         *
+         * @throws  IllegalArgumentException if {@code dst} does not have enough
+         *          space for encoding all input bytes.
+         */
+        public int encode(byte[] src, byte[] dst) {
+            int len = outLength(src.length);         // dst array size
+            if (dst.length < len)
+                throw new IllegalArgumentException(
+                    "Output byte array is too small for encoding all input bytes");
+            return encode0(src, 0, src.length, dst);
+        }
+
+        /**
+         * Encodes the specified byte array into a String using the {@link Base64}
+         * encoding scheme.
+         *
+         * <p> This method first encodes all input bytes into a base64 encoded
+         * byte array and then constructs a new String by using the encoded byte
+         * array and the {@link java.nio.charset.StandardCharsets#ISO_8859_1
+         * ISO-8859-1} charset.
+         *
+         * <p> In other words, an invocation of this method has exactly the same
+         * effect as invoking
+         * {@code new String(encode(src), StandardCharsets.ISO_8859_1)}.
+         *
+         * @param   src
+         *          the byte array to encode
+         * @return  A String containing the resulting Base64 encoded characters
+         */
+        @SuppressWarnings("deprecation")
+        public String encodeToString(byte[] src) {
+            byte[] encoded = encode(src);
+            return new String(encoded, 0, 0, encoded.length);
+        }
+
+        /**
+         * Encodes all remaining bytes from the specified byte buffer into
+         * a newly-allocated ByteBuffer using the {@link Base64} encoding
+         * scheme.
+         *
+         * Upon return, the source buffer's position will be updated to
+         * its limit; its limit will not have been changed. The returned
+         * output buffer's position will be zero and its limit will be the
+         * number of resulting encoded bytes.
+         *
+         * @param   buffer
+         *          the source ByteBuffer to encode
+         * @return  A newly-allocated byte buffer containing the encoded bytes.
+         */
+        public ByteBuffer encode(ByteBuffer buffer) {
+            int len = outLength(buffer.remaining());
+            byte[] dst = new byte[len];
+            int ret = 0;
+            if (buffer.hasArray()) {
+                ret = encode0(buffer.array(),
+                              buffer.arrayOffset() + buffer.position(),
+                              buffer.arrayOffset() + buffer.limit(),
+                              dst);
+                buffer.position(buffer.limit());
+            } else {
+                byte[] src = new byte[buffer.remaining()];
+                buffer.get(src);
+                ret = encode0(src, 0, src.length, dst);
+            }
+            if (ret != dst.length)
+                 dst = Arrays.copyOf(dst, ret);
+            return ByteBuffer.wrap(dst);
+        }
+
+        /**
+         * Wraps an output stream for encoding byte data using the {@link Base64}
+         * encoding scheme.
+         *
+         * <p> It is recommended to promptly close the returned output stream after
+         * use, during which it will flush all possible leftover bytes to the underlying
+         * output stream. Closing the returned output stream will close the underlying
+         * output stream.
+         *
+         * @param   os
+         *          the output stream.
+         * @return  the output stream for encoding the byte data into the
+         *          specified Base64 encoded format
+         */
+        public OutputStream wrap(OutputStream os) {
+            Objects.requireNonNull(os);
+            return new EncOutputStream(os, isURL ? toBase64URL : toBase64,
+                                       newline, linemax, doPadding);
+        }
+
+        /**
+         * Returns an encoder instance that encodes equivalently to this one,
+         * but without adding any padding character at the end of the encoded
+         * byte data.
+         *
+         * <p> The encoding scheme of this encoder instance is unaffected by
+         * this invocation. The returned encoder instance should be used for
+         * non-padding encoding operation.
+         *
+         * @return an equivalent encoder that encodes without adding any
+         *         padding character at the end
+         */
+        public Encoder withoutPadding() {
+            if (!doPadding)
+                return this;
+            return new Encoder(isURL, newline, linemax, false);
+        }
+
+        private int encode0(byte[] src, int off, int end, byte[] dst) {
+            char[] base64 = isURL ? toBase64URL : toBase64;
+            int sp = off;
+            int slen = (end - off) / 3 * 3;
+            int sl = off + slen;
+            if (linemax > 0 && slen  > linemax / 4 * 3)
+                slen = linemax / 4 * 3;
+            int dp = 0;
+            while (sp < sl) {
+                int sl0 = Math.min(sp + slen, sl);
+                for (int sp0 = sp, dp0 = dp ; sp0 < sl0; ) {
+                    int bits = (src[sp0++] & 0xff) << 16 |
+                               (src[sp0++] & 0xff) <<  8 |
+                               (src[sp0++] & 0xff);
+                    dst[dp0++] = (byte)base64[(bits >>> 18) & 0x3f];
+                    dst[dp0++] = (byte)base64[(bits >>> 12) & 0x3f];
+                    dst[dp0++] = (byte)base64[(bits >>> 6)  & 0x3f];
+                    dst[dp0++] = (byte)base64[bits & 0x3f];
+                }
+                int dlen = (sl0 - sp) / 3 * 4;
+                dp += dlen;
+                sp = sl0;
+                if (dlen == linemax && sp < end) {
+                    for (byte b : newline){
+                        dst[dp++] = b;
+                    }
+                }
+            }
+            if (sp < end) {               // 1 or 2 leftover bytes
+                int b0 = src[sp++] & 0xff;
+                dst[dp++] = (byte)base64[b0 >> 2];
+                if (sp == end) {
+                    dst[dp++] = (byte)base64[(b0 << 4) & 0x3f];
+                    if (doPadding) {
+                        dst[dp++] = '=';
+                        dst[dp++] = '=';
+                    }
+                } else {
+                    int b1 = src[sp++] & 0xff;
+                    dst[dp++] = (byte)base64[(b0 << 4) & 0x3f | (b1 >> 4)];
+                    dst[dp++] = (byte)base64[(b1 << 2) & 0x3f];
+                    if (doPadding) {
+                        dst[dp++] = '=';
+                    }
+                }
+            }
+            return dp;
+        }
+    }
+
+    /**
+     * This class implements a decoder for decoding byte data using the
+     * Base64 encoding scheme as specified in RFC 4648 and RFC 2045.
+     *
+     * <p> The Base64 padding character {@code '='} is accepted and
+     * interpreted as the end of the encoded byte data, but is not
+     * required. So if the final unit of the encoded byte data only has
+     * two or three Base64 characters (without the corresponding padding
+     * character(s) padded), they are decoded as if followed by padding
+     * character(s). If there is a padding character present in the
+     * final unit, the correct number of padding character(s) must be
+     * present, otherwise {@code IllegalArgumentException} (
+     * {@code IOException} when reading from a Base64 stream) is thrown
+     * during decoding.
+     *
+     * <p> Instances of {@link Decoder} class are safe for use by
+     * multiple concurrent threads.
+     *
+     * <p> Unless otherwise noted, passing a {@code null} argument to
+     * a method of this class will cause a
+     * {@link java.lang.NullPointerException NullPointerException} to
+     * be thrown.
+     *
+     * @see     Encoder
+     * @since   1.8
+     */
+    public static class Decoder {
+
+        private final boolean isURL;
+        private final boolean isMIME;
+
+        private Decoder(boolean isURL, boolean isMIME) {
+            this.isURL = isURL;
+            this.isMIME = isMIME;
+        }
+
+        /**
+         * Lookup table for decoding unicode characters drawn from the
+         * "Base64 Alphabet" (as specified in Table 1 of RFC 2045) into
+         * their 6-bit positive integer equivalents.  Characters that
+         * are not in the Base64 alphabet but fall within the bounds of
+         * the array are encoded to -1.
+         *
+         */
+        private static final int[] fromBase64 = new int[256];
+        static {
+            Arrays.fill(fromBase64, -1);
+            for (int i = 0; i < Encoder.toBase64.length; i++)
+                fromBase64[Encoder.toBase64[i]] = i;
+            fromBase64['='] = -2;
+        }
+
+        /**
+         * Lookup table for decoding "URL and Filename safe Base64 Alphabet"
+         * as specified in Table2 of the RFC 4648.
+         */
+        private static final int[] fromBase64URL = new int[256];
+
+        static {
+            Arrays.fill(fromBase64URL, -1);
+            for (int i = 0; i < Encoder.toBase64URL.length; i++)
+                fromBase64URL[Encoder.toBase64URL[i]] = i;
+            fromBase64URL['='] = -2;
+        }
+
+        static final Decoder RFC4648         = new Decoder(false, false);
+        static final Decoder RFC4648_URLSAFE = new Decoder(true, false);
+        static final Decoder RFC2045         = new Decoder(false, true);
+
+        /**
+         * Decodes all bytes from the input byte array using the {@link Base64}
+         * encoding scheme, writing the results into a newly-allocated output
+         * byte array. The returned byte array is of the length of the resulting
+         * bytes.
+         *
+         * @param   src
+         *          the byte array to decode
+         *
+         * @return  A newly-allocated byte array containing the decoded bytes.
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme
+         */
+        public byte[] decode(byte[] src) {
+            byte[] dst = new byte[outLength(src, 0, src.length)];
+            int ret = decode0(src, 0, src.length, dst);
+            if (ret != dst.length) {
+                dst = Arrays.copyOf(dst, ret);
+            }
+            return dst;
+        }
+
+        /**
+         * Decodes a Base64 encoded String into a newly-allocated byte array
+         * using the {@link Base64} encoding scheme.
+         *
+         * <p> An invocation of this method has exactly the same effect as invoking
+         * {@code decode(src.getBytes(StandardCharsets.ISO_8859_1))}
+         *
+         * @param   src
+         *          the string to decode
+         *
+         * @return  A newly-allocated byte array containing the decoded bytes.
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme
+         */
+        public byte[] decode(String src) {
+            return decode(src.getBytes(StandardCharsets.ISO_8859_1));
+        }
+
+        /**
+         * Decodes all bytes from the input byte array using the {@link Base64}
+         * encoding scheme, writing the results into the given output byte array,
+         * starting at offset 0.
+         *
+         * <p> It is the responsibility of the invoker of this method to make
+         * sure the output byte array {@code dst} has enough space for decoding
+         * all bytes from the input byte array. No bytes will be be written to
+         * the output byte array if the output byte array is not big enough.
+         *
+         * <p> If the input byte array is not in valid Base64 encoding scheme
+         * then some bytes may have been written to the output byte array before
+         * IllegalargumentException is thrown.
+         *
+         * @param   src
+         *          the byte array to decode
+         * @param   dst
+         *          the output byte array
+         *
+         * @return  The number of bytes written to the output byte array
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme, or {@code dst}
+         *          does not have enough space for decoding all input bytes.
+         */
+        public int decode(byte[] src, byte[] dst) {
+            int len = outLength(src, 0, src.length);
+            if (dst.length < len)
+                throw new IllegalArgumentException(
+                    "Output byte array is too small for decoding all input bytes");
+            return decode0(src, 0, src.length, dst);
+        }
+
+        /**
+         * Decodes all bytes from the input byte buffer using the {@link Base64}
+         * encoding scheme, writing the results into a newly-allocated ByteBuffer.
+         *
+         * <p> Upon return, the source buffer's position will be updated to
+         * its limit; its limit will not have been changed. The returned
+         * output buffer's position will be zero and its limit will be the
+         * number of resulting decoded bytes
+         *
+         * <p> {@code IllegalArgumentException} is thrown if the input buffer
+         * is not in valid Base64 encoding scheme. The position of the input
+         * buffer will not be advanced in this case.
+         *
+         * @param   buffer
+         *          the ByteBuffer to decode
+         *
+         * @return  A newly-allocated byte buffer containing the decoded bytes
+         *
+         * @throws  IllegalArgumentException
+         *          if {@code src} is not in valid Base64 scheme.
+         */
+        public ByteBuffer decode(ByteBuffer buffer) {
+            int pos0 = buffer.position();
+            try {
+                byte[] src;
+                int sp, sl;
+                if (buffer.hasArray()) {
+                    src = buffer.array();
+                    sp = buffer.arrayOffset() + buffer.position();
+                    sl = buffer.arrayOffset() + buffer.limit();
+                    buffer.position(buffer.limit());
+                } else {
+                    src = new byte[buffer.remaining()];
+                    buffer.get(src);
+                    sp = 0;
+                    sl = src.length;
+                }
+                byte[] dst = new byte[outLength(src, sp, sl)];
+                return ByteBuffer.wrap(dst, 0, decode0(src, sp, sl, dst));
+            } catch (IllegalArgumentException iae) {
+                buffer.position(pos0);
+                throw iae;
+            }
+        }
+
+        /**
+         * Returns an input stream for decoding {@link Base64} encoded byte stream.
+         *
+         * <p> The {@code read}  methods of the returned {@code InputStream} will
+         * throw {@code IOException} when reading bytes that cannot be decoded.
+         *
+         * <p> Closing the returned input stream will close the underlying
+         * input stream.
+         *
+         * @param   is
+         *          the input stream
+         *
+         * @return  the input stream for decoding the specified Base64 encoded
+         *          byte stream
+         */
+        public InputStream wrap(InputStream is) {
+            Objects.requireNonNull(is);
+            return new DecInputStream(is, isURL ? fromBase64URL : fromBase64, isMIME);
+        }
+
+        private int outLength(byte[] src, int sp, int sl) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int paddings = 0;
+            int len = sl - sp;
+            if (len == 0)
+                return 0;
+            if (len < 2) {
+                if (isMIME && base64[0] == -1)
+                    return 0;
+                throw new IllegalArgumentException(
+                    "Input byte[] should at least have 2 bytes for base64 bytes");
+            }
+            if (isMIME) {
+                // scan all bytes to fill out all non-alphabet. a performance
+                // trade-off of pre-scan or Arrays.copyOf
+                int n = 0;
+                while (sp < sl) {
+                    int b = src[sp++] & 0xff;
+                    if (b == '=') {
+                        len -= (sl - sp + 1);
+                        break;
+                    }
+                    if ((b = base64[b]) == -1)
+                        n++;
+                }
+                len -= n;
+            } else {
+                if (src[sl - 1] == '=') {
+                    paddings++;
+                    if (src[sl - 2] == '=')
+                        paddings++;
+                }
+            }
+            if (paddings == 0 && (len & 0x3) !=  0)
+                paddings = 4 - (len & 0x3);
+            return 3 * ((len + 3) / 4) - paddings;
+        }
+
+        private int decode0(byte[] src, int sp, int sl, byte[] dst) {
+            int[] base64 = isURL ? fromBase64URL : fromBase64;
+            int dp = 0;
+            int bits = 0;
+            int shiftto = 18;       // pos of first byte of 4-byte atom
+            while (sp < sl) {
+                int b = src[sp++] & 0xff;
+                if ((b = base64[b]) < 0) {
+                    if (b == -2) {         // padding byte '='
+                        // =     shiftto==18 unnecessary padding
+                        // x=    shiftto==12 a dangling single x
+                        // x     to be handled together with non-padding case
+                        // xx=   shiftto==6&&sp==sl missing last =
+                        // xx=y  shiftto==6 last is not =
+                        if (shiftto == 6 && (sp == sl || src[sp++] != '=') ||
+                            shiftto == 18) {
+                            throw new IllegalArgumentException(
+                                "Input byte array has wrong 4-byte ending unit");
+                        }
+                        break;
+                    }
+                    if (isMIME)    // skip if for rfc2045
+                        continue;
+                    else
+                        throw new IllegalArgumentException(
+                            "Illegal base64 character " +
+                            Integer.toString(src[sp - 1], 16));
+                }
+                bits |= (b << shiftto);
+                shiftto -= 6;
+                if (shiftto < 0) {
+                    dst[dp++] = (byte)(bits >> 16);
+                    dst[dp++] = (byte)(bits >>  8);
+                    dst[dp++] = (byte)(bits);
+                    shiftto = 18;
+                    bits = 0;
+                }
+            }
+            // reached end of byte array or hit padding '=' characters.
+            if (shiftto == 6) {
+                dst[dp++] = (byte)(bits >> 16);
+            } else if (shiftto == 0) {
+                dst[dp++] = (byte)(bits >> 16);
+                dst[dp++] = (byte)(bits >>  8);
+            } else if (shiftto == 12) {
+                // dangling single "x", incorrectly encoded.
+                throw new IllegalArgumentException(
+                    "Last unit does not have enough valid bits");
+            }
+            // anything left is invalid, if is not MIME.
+            // if MIME, ignore all non-base64 character
+            while (sp < sl) {
+                if (isMIME && base64[src[sp++]] < 0)
+                    continue;
+                throw new IllegalArgumentException(
+                    "Input byte array has incorrect ending byte at " + sp);
+            }
+            return dp;
+        }
+    }
+
+    /*
+     * An output stream for encoding bytes into the Base64.
+     */
+    private static class EncOutputStream extends FilterOutputStream {
+
+        private int leftover = 0;
+        private int b0, b1, b2;
+        private boolean closed = false;
+
+        private final char[] base64;    // byte->base64 mapping
+        private final byte[] newline;   // line separator, if needed
+        private final int linemax;
+        private final boolean doPadding;// whether or not to pad
+        private int linepos = 0;
+
+        EncOutputStream(OutputStream os, char[] base64,
+                        byte[] newline, int linemax, boolean doPadding) {
+            super(os);
+            this.base64 = base64;
+            this.newline = newline;
+            this.linemax = linemax;
+            this.doPadding = doPadding;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            byte[] buf = new byte[1];
+            buf[0] = (byte)(b & 0xff);
+            write(buf, 0, 1);
+        }
+
+        private void checkNewline() throws IOException {
+            if (linepos == linemax) {
+                out.write(newline);
+                linepos = 0;
+            }
+        }
+
+        @Override
+        public void write(byte[] b, int off, int len) throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            // Android-changed: Upstream fix to avoid overflow.
+            // This upstream fix is from beyond OpenJDK8u121-b13. http://b/62368386
+            // if (off < 0 || len < 0 || off + len > b.length)
+            if (off < 0 || len < 0 || len > b.length - off)
+                throw new ArrayIndexOutOfBoundsException();
+            if (len == 0)
+                return;
+            if (leftover != 0) {
+                if (leftover == 1) {
+                    b1 = b[off++] & 0xff;
+                    len--;
+                    if (len == 0) {
+                        leftover++;
+                        return;
+                    }
+                }
+                b2 = b[off++] & 0xff;
+                len--;
+                checkNewline();
+                out.write(base64[b0 >> 2]);
+                out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
+                out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]);
+                out.write(base64[b2 & 0x3f]);
+                linepos += 4;
+            }
+            int nBits24 = len / 3;
+            leftover = len - (nBits24 * 3);
+            while (nBits24-- > 0) {
+                checkNewline();
+                int bits = (b[off++] & 0xff) << 16 |
+                           (b[off++] & 0xff) <<  8 |
+                           (b[off++] & 0xff);
+                out.write(base64[(bits >>> 18) & 0x3f]);
+                out.write(base64[(bits >>> 12) & 0x3f]);
+                out.write(base64[(bits >>> 6)  & 0x3f]);
+                out.write(base64[bits & 0x3f]);
+                linepos += 4;
+           }
+            if (leftover == 1) {
+                b0 = b[off++] & 0xff;
+            } else if (leftover == 2) {
+                b0 = b[off++] & 0xff;
+                b1 = b[off++] & 0xff;
+            }
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                if (leftover == 1) {
+                    checkNewline();
+                    out.write(base64[b0 >> 2]);
+                    out.write(base64[(b0 << 4) & 0x3f]);
+                    if (doPadding) {
+                        out.write('=');
+                        out.write('=');
+                    }
+                } else if (leftover == 2) {
+                    checkNewline();
+                    out.write(base64[b0 >> 2]);
+                    out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
+                    out.write(base64[(b1 << 2) & 0x3f]);
+                    if (doPadding) {
+                       out.write('=');
+                    }
+                }
+                leftover = 0;
+                out.close();
+            }
+        }
+    }
+
+    /*
+     * An input stream for decoding Base64 bytes
+     */
+    private static class DecInputStream extends InputStream {
+
+        private final InputStream is;
+        private final boolean isMIME;
+        private final int[] base64;      // base64 -> byte mapping
+        private int bits = 0;            // 24-bit buffer for decoding
+        private int nextin = 18;         // next available "off" in "bits" for input;
+                                         // -> 18, 12, 6, 0
+        private int nextout = -8;        // next available "off" in "bits" for output;
+                                         // -> 8, 0, -8 (no byte for output)
+        private boolean eof = false;
+        private boolean closed = false;
+
+        DecInputStream(InputStream is, int[] base64, boolean isMIME) {
+            this.is = is;
+            this.base64 = base64;
+            this.isMIME = isMIME;
+        }
+
+        private byte[] sbBuf = new byte[1];
+
+        @Override
+        public int read() throws IOException {
+            return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            if (eof && nextout < 0)    // eof and no leftover
+                return -1;
+            if (off < 0 || len < 0 || len > b.length - off)
+                throw new IndexOutOfBoundsException();
+            int oldOff = off;
+            if (nextout >= 0) {       // leftover output byte(s) in bits buf
+                do {
+                    if (len == 0)
+                        return off - oldOff;
+                    b[off++] = (byte)(bits >> nextout);
+                    len--;
+                    nextout -= 8;
+                } while (nextout >= 0);
+                bits = 0;
+            }
+            while (len > 0) {
+                int v = is.read();
+                if (v == -1) {
+                    eof = true;
+                    if (nextin != 18) {
+                        if (nextin == 12)
+                            throw new IOException("Base64 stream has one un-decoded dangling byte.");
+                        // treat ending xx/xxx without padding character legal.
+                        // same logic as v == '=' below
+                        b[off++] = (byte)(bits >> (16));
+                        len--;
+                        if (nextin == 0) {           // only one padding byte
+                            if (len == 0) {          // no enough output space
+                                bits >>= 8;          // shift to lowest byte
+                                nextout = 0;
+                            } else {
+                                b[off++] = (byte) (bits >>  8);
+                            }
+                        }
+                    }
+                    if (off == oldOff)
+                        return -1;
+                    else
+                        return off - oldOff;
+                }
+                if (v == '=') {                  // padding byte(s)
+                    // =     shiftto==18 unnecessary padding
+                    // x=    shiftto==12 dangling x, invalid unit
+                    // xx=   shiftto==6 && missing last '='
+                    // xx=y  or last is not '='
+                    if (nextin == 18 || nextin == 12 ||
+                        nextin == 6 && is.read() != '=') {
+                        throw new IOException("Illegal base64 ending sequence:" + nextin);
+                    }
+                    b[off++] = (byte)(bits >> (16));
+                    len--;
+                    if (nextin == 0) {           // only one padding byte
+                        if (len == 0) {          // no enough output space
+                            bits >>= 8;          // shift to lowest byte
+                            nextout = 0;
+                        } else {
+                            b[off++] = (byte) (bits >>  8);
+                        }
+                    }
+                    eof = true;
+                    break;
+                }
+                if ((v = base64[v]) == -1) {
+                    if (isMIME)                 // skip if for rfc2045
+                        continue;
+                    else
+                        throw new IOException("Illegal base64 character " +
+                            Integer.toString(v, 16));
+                }
+                bits |= (v << nextin);
+                if (nextin == 0) {
+                    nextin = 18;    // clear for next
+                    nextout = 16;
+                    while (nextout >= 0) {
+                        b[off++] = (byte)(bits >> nextout);
+                        len--;
+                        nextout -= 8;
+                        if (len == 0 && nextout >= 0) {  // don't clean "bits"
+                            return off - oldOff;
+                        }
+                    }
+                    bits = 0;
+                } else {
+                    nextin -= 6;
+                }
+            }
+            return off - oldOff;
+        }
+
+        @Override
+        public int available() throws IOException {
+            if (closed)
+                throw new IOException("Stream is closed");
+            return is.available();   // TBD:
+        }
+
+        @Override
+        public void close() throws IOException {
+            if (!closed) {
+                closed = true;
+                is.close();
+            }
+        }
+    }
+}
diff --git a/java/util/BitSet.java b/java/util/BitSet.java
new file mode 100644
index 0000000..261a77c
--- /dev/null
+++ b/java/util/BitSet.java
@@ -0,0 +1,1248 @@
+/*
+ * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.LongBuffer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * This class implements a vector of bits that grows as needed. Each
+ * component of the bit set has a {@code boolean} value. The
+ * bits of a {@code BitSet} are indexed by nonnegative integers.
+ * Individual indexed bits can be examined, set, or cleared. One
+ * {@code BitSet} may be used to modify the contents of another
+ * {@code BitSet} through logical AND, logical inclusive OR, and
+ * logical exclusive OR operations.
+ *
+ * <p>By default, all bits in the set initially have the value
+ * {@code false}.
+ *
+ * <p>Every bit set has a current size, which is the number of bits
+ * of space currently in use by the bit set. Note that the size is
+ * related to the implementation of a bit set, so it may change with
+ * implementation. The length of a bit set relates to logical length
+ * of a bit set and is defined independently of implementation.
+ *
+ * <p>Unless otherwise noted, passing a null parameter to any of the
+ * methods in a {@code BitSet} will result in a
+ * {@code NullPointerException}.
+ *
+ * <p>A {@code BitSet} is not safe for multithreaded use without
+ * external synchronization.
+ *
+ * @author  Arthur van Hoff
+ * @author  Michael McCloskey
+ * @author  Martin Buchholz
+ * @since   JDK1.0
+ */
+public class BitSet implements Cloneable, java.io.Serializable {
+    /*
+     * BitSets are packed into arrays of "words."  Currently a word is
+     * a long, which consists of 64 bits, requiring 6 address bits.
+     * The choice of word size is determined purely by performance concerns.
+     */
+    private final static int ADDRESS_BITS_PER_WORD = 6;
+    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
+    private final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
+
+    /* Used to shift left or right for a partial word mask */
+    private static final long WORD_MASK = 0xffffffffffffffffL;
+
+    /**
+     * @serialField bits long[]
+     *
+     * The bits in this BitSet.  The ith bit is stored in bits[i/64] at
+     * bit position i % 64 (where bit position 0 refers to the least
+     * significant bit and 63 refers to the most significant bit).
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("bits", long[].class),
+    };
+
+    /**
+     * The internal field corresponding to the serialField "bits".
+     */
+    private long[] words;
+
+    /**
+     * The number of words in the logical size of this BitSet.
+     */
+    private transient int wordsInUse = 0;
+
+    /**
+     * Whether the size of "words" is user-specified.  If so, we assume
+     * the user knows what he's doing and try harder to preserve it.
+     */
+    private transient boolean sizeIsSticky = false;
+
+    /* use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 7997698588986878753L;
+
+    /**
+     * Given a bit index, return word index containing it.
+     */
+    private static int wordIndex(int bitIndex) {
+        return bitIndex >> ADDRESS_BITS_PER_WORD;
+    }
+
+    /**
+     * Every public method must preserve these invariants.
+     */
+    private void checkInvariants() {
+        assert(wordsInUse == 0 || words[wordsInUse - 1] != 0);
+        assert(wordsInUse >= 0 && wordsInUse <= words.length);
+        assert(wordsInUse == words.length || words[wordsInUse] == 0);
+    }
+
+    /**
+     * Sets the field wordsInUse to the logical size in words of the bit set.
+     * WARNING:This method assumes that the number of words actually in use is
+     * less than or equal to the current value of wordsInUse!
+     */
+    private void recalculateWordsInUse() {
+        // Traverse the bitset until a used word is found
+        int i;
+        for (i = wordsInUse-1; i >= 0; i--)
+            if (words[i] != 0)
+                break;
+
+        wordsInUse = i+1; // The new logical size
+    }
+
+    /**
+     * Creates a new bit set. All bits are initially {@code false}.
+     */
+    public BitSet() {
+        initWords(BITS_PER_WORD);
+        sizeIsSticky = false;
+    }
+
+    /**
+     * Creates a bit set whose initial size is large enough to explicitly
+     * represent bits with indices in the range {@code 0} through
+     * {@code nbits-1}. All bits are initially {@code false}.
+     *
+     * @param  nbits the initial size of the bit set
+     * @throws NegativeArraySizeException if the specified initial size
+     *         is negative
+     */
+    public BitSet(int nbits) {
+        // nbits can't be negative; size 0 is OK
+        if (nbits < 0)
+            throw new NegativeArraySizeException("nbits < 0: " + nbits);
+
+        initWords(nbits);
+        sizeIsSticky = true;
+    }
+
+    private void initWords(int nbits) {
+        words = new long[wordIndex(nbits-1) + 1];
+    }
+
+    /**
+     * Creates a bit set using words as the internal representation.
+     * The last word (if there is one) must be non-zero.
+     */
+    private BitSet(long[] words) {
+        this.words = words;
+        this.wordsInUse = words.length;
+        checkInvariants();
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given long array.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * longs.length}.
+     *
+     * <p>This method is equivalent to
+     * {@code BitSet.valueOf(LongBuffer.wrap(longs))}.
+     *
+     * @param longs a long array containing a little-endian representation
+     *        of a sequence of bits to be used as the initial bits of the
+     *        new bit set
+     * @return a {@code BitSet} containing all the bits in the long array
+     * @since 1.7
+     */
+    public static BitSet valueOf(long[] longs) {
+        int n;
+        for (n = longs.length; n > 0 && longs[n - 1] == 0; n--)
+            ;
+        return new BitSet(Arrays.copyOf(longs, n));
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given long
+     * buffer between its position and limit.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * lb.remaining()}.
+     *
+     * <p>The long buffer is not modified by this method, and no
+     * reference to the buffer is retained by the bit set.
+     *
+     * @param lb a long buffer containing a little-endian representation
+     *        of a sequence of bits between its position and limit, to be
+     *        used as the initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the buffer in the
+     *         specified range
+     * @since 1.7
+     */
+    public static BitSet valueOf(LongBuffer lb) {
+        lb = lb.slice();
+        int n;
+        for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--)
+            ;
+        long[] words = new long[n];
+        lb.get(words);
+        return new BitSet(words);
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given byte array.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+     * <br>for all {@code n <  8 * bytes.length}.
+     *
+     * <p>This method is equivalent to
+     * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}.
+     *
+     * @param bytes a byte array containing a little-endian
+     *        representation of a sequence of bits to be used as the
+     *        initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the byte array
+     * @since 1.7
+     */
+    public static BitSet valueOf(byte[] bytes) {
+        return BitSet.valueOf(ByteBuffer.wrap(bytes));
+    }
+
+    /**
+     * Returns a new bit set containing all the bits in the given byte
+     * buffer between its position and limit.
+     *
+     * <p>More precisely,
+     * <br>{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)}
+     * <br>for all {@code n < 8 * bb.remaining()}.
+     *
+     * <p>The byte buffer is not modified by this method, and no
+     * reference to the buffer is retained by the bit set.
+     *
+     * @param bb a byte buffer containing a little-endian representation
+     *        of a sequence of bits between its position and limit, to be
+     *        used as the initial bits of the new bit set
+     * @return a {@code BitSet} containing all the bits in the buffer in the
+     *         specified range
+     * @since 1.7
+     */
+    public static BitSet valueOf(ByteBuffer bb) {
+        bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN);
+        int n;
+        for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--)
+            ;
+        long[] words = new long[(n + 7) / 8];
+        bb.limit(n);
+        int i = 0;
+        while (bb.remaining() >= 8)
+            words[i++] = bb.getLong();
+        for (int remaining = bb.remaining(), j = 0; j < remaining; j++)
+            words[i] |= (bb.get() & 0xffL) << (8 * j);
+        return new BitSet(words);
+    }
+
+    /**
+     * Returns a new byte array containing all the bits in this bit set.
+     *
+     * <p>More precisely, if
+     * <br>{@code byte[] bytes = s.toByteArray();}
+     * <br>then {@code bytes.length == (s.length()+7)/8} and
+     * <br>{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)}
+     * <br>for all {@code n < 8 * bytes.length}.
+     *
+     * @return a byte array containing a little-endian representation
+     *         of all the bits in this bit set
+     * @since 1.7
+    */
+    public byte[] toByteArray() {
+        int n = wordsInUse;
+        if (n == 0)
+            return new byte[0];
+        int len = 8 * (n-1);
+        for (long x = words[n - 1]; x != 0; x >>>= 8)
+            len++;
+        byte[] bytes = new byte[len];
+        ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
+        for (int i = 0; i < n - 1; i++)
+            bb.putLong(words[i]);
+        for (long x = words[n - 1]; x != 0; x >>>= 8)
+            bb.put((byte) (x & 0xff));
+        return bytes;
+    }
+
+    /**
+     * Returns a new long array containing all the bits in this bit set.
+     *
+     * <p>More precisely, if
+     * <br>{@code long[] longs = s.toLongArray();}
+     * <br>then {@code longs.length == (s.length()+63)/64} and
+     * <br>{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)}
+     * <br>for all {@code n < 64 * longs.length}.
+     *
+     * @return a long array containing a little-endian representation
+     *         of all the bits in this bit set
+     * @since 1.7
+    */
+    public long[] toLongArray() {
+        return Arrays.copyOf(words, wordsInUse);
+    }
+
+    /**
+     * Ensures that the BitSet can hold enough words.
+     * @param wordsRequired the minimum acceptable number of words.
+     */
+    private void ensureCapacity(int wordsRequired) {
+        if (words.length < wordsRequired) {
+            // Allocate larger of doubled size or required size
+            int request = Math.max(2 * words.length, wordsRequired);
+            words = Arrays.copyOf(words, request);
+            sizeIsSticky = false;
+        }
+    }
+
+    /**
+     * Ensures that the BitSet can accommodate a given wordIndex,
+     * temporarily violating the invariants.  The caller must
+     * restore the invariants before returning to the user,
+     * possibly using recalculateWordsInUse().
+     * @param wordIndex the index to be accommodated.
+     */
+    private void expandTo(int wordIndex) {
+        int wordsRequired = wordIndex+1;
+        if (wordsInUse < wordsRequired) {
+            ensureCapacity(wordsRequired);
+            wordsInUse = wordsRequired;
+        }
+    }
+
+    /**
+     * Checks that fromIndex ... toIndex is a valid range of bit indices.
+     */
+    private static void checkRange(int fromIndex, int toIndex) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+        if (toIndex < 0)
+            throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
+        if (fromIndex > toIndex)
+            throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
+                                                " > toIndex: " + toIndex);
+    }
+
+    /**
+     * Sets the bit at the specified index to the complement of its
+     * current value.
+     *
+     * @param  bitIndex the index of the bit to flip
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public void flip(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        expandTo(wordIndex);
+
+        words[wordIndex] ^= (1L << bitIndex);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets each bit from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to the complement of its current
+     * value.
+     *
+     * @param  fromIndex index of the first bit to flip
+     * @param  toIndex index after the last bit to flip
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void flip(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        int startWordIndex = wordIndex(fromIndex);
+        int endWordIndex   = wordIndex(toIndex - 1);
+        expandTo(endWordIndex);
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] ^= (firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] ^= firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] ^= WORD_MASK;
+
+            // Handle last word
+            words[endWordIndex] ^= lastWordMask;
+        }
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bit at the specified index to {@code true}.
+     *
+     * @param  bitIndex a bit index
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  JDK1.0
+     */
+    public void set(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        expandTo(wordIndex);
+
+        words[wordIndex] |= (1L << bitIndex); // Restores invariants
+
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bit at the specified index to the specified value.
+     *
+     * @param  bitIndex a bit index
+     * @param  value a boolean value to set
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public void set(int bitIndex, boolean value) {
+        if (value)
+            set(bitIndex);
+        else
+            clear(bitIndex);
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to {@code true}.
+     *
+     * @param  fromIndex index of the first bit to be set
+     * @param  toIndex index after the last bit to be set
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void set(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        // Increase capacity if necessary
+        int startWordIndex = wordIndex(fromIndex);
+        int endWordIndex   = wordIndex(toIndex - 1);
+        expandTo(endWordIndex);
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] |= (firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] |= firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] = WORD_MASK;
+
+            // Handle last word (restores invariants)
+            words[endWordIndex] |= lastWordMask;
+        }
+
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to the specified value.
+     *
+     * @param  fromIndex index of the first bit to be set
+     * @param  toIndex index after the last bit to be set
+     * @param  value value to set the selected bits to
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void set(int fromIndex, int toIndex, boolean value) {
+        if (value)
+            set(fromIndex, toIndex);
+        else
+            clear(fromIndex, toIndex);
+    }
+
+    /**
+     * Sets the bit specified by the index to {@code false}.
+     *
+     * @param  bitIndex the index of the bit to be cleared
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  JDK1.0
+     */
+    public void clear(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        int wordIndex = wordIndex(bitIndex);
+        if (wordIndex >= wordsInUse)
+            return;
+
+        words[wordIndex] &= ~(1L << bitIndex);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+     * specified {@code toIndex} (exclusive) to {@code false}.
+     *
+     * @param  fromIndex index of the first bit to be cleared
+     * @param  toIndex index after the last bit to be cleared
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public void clear(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        if (fromIndex == toIndex)
+            return;
+
+        int startWordIndex = wordIndex(fromIndex);
+        if (startWordIndex >= wordsInUse)
+            return;
+
+        int endWordIndex = wordIndex(toIndex - 1);
+        if (endWordIndex >= wordsInUse) {
+            toIndex = length();
+            endWordIndex = wordsInUse - 1;
+        }
+
+        long firstWordMask = WORD_MASK << fromIndex;
+        long lastWordMask  = WORD_MASK >>> -toIndex;
+        if (startWordIndex == endWordIndex) {
+            // Case 1: One word
+            words[startWordIndex] &= ~(firstWordMask & lastWordMask);
+        } else {
+            // Case 2: Multiple words
+            // Handle first word
+            words[startWordIndex] &= ~firstWordMask;
+
+            // Handle intermediate words, if any
+            for (int i = startWordIndex+1; i < endWordIndex; i++)
+                words[i] = 0;
+
+            // Handle last word
+            words[endWordIndex] &= ~lastWordMask;
+        }
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Sets all of the bits in this BitSet to {@code false}.
+     *
+     * @since 1.4
+     */
+    public void clear() {
+        while (wordsInUse > 0)
+            words[--wordsInUse] = 0;
+    }
+
+    /**
+     * Returns the value of the bit with the specified index. The value
+     * is {@code true} if the bit with the index {@code bitIndex}
+     * is currently set in this {@code BitSet}; otherwise, the result
+     * is {@code false}.
+     *
+     * @param  bitIndex   the bit index
+     * @return the value of the bit with the specified index
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     */
+    public boolean get(int bitIndex) {
+        if (bitIndex < 0)
+            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+        checkInvariants();
+
+        int wordIndex = wordIndex(bitIndex);
+        return (wordIndex < wordsInUse)
+            && ((words[wordIndex] & (1L << bitIndex)) != 0);
+    }
+
+    /**
+     * Returns a new {@code BitSet} composed of bits from this {@code BitSet}
+     * from {@code fromIndex} (inclusive) to {@code toIndex} (exclusive).
+     *
+     * @param  fromIndex index of the first bit to include
+     * @param  toIndex index after the last bit to include
+     * @return a new {@code BitSet} from a range of this {@code BitSet}
+     * @throws IndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         or {@code toIndex} is negative, or {@code fromIndex} is
+     *         larger than {@code toIndex}
+     * @since  1.4
+     */
+    public BitSet get(int fromIndex, int toIndex) {
+        checkRange(fromIndex, toIndex);
+
+        checkInvariants();
+
+        int len = length();
+
+        // If no set bits in range return empty bitset
+        if (len <= fromIndex || fromIndex == toIndex)
+            return new BitSet(0);
+
+        // An optimization
+        if (toIndex > len)
+            toIndex = len;
+
+        BitSet result = new BitSet(toIndex - fromIndex);
+        int targetWords = wordIndex(toIndex - fromIndex - 1) + 1;
+        int sourceIndex = wordIndex(fromIndex);
+        boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0);
+
+        // Process all words but the last word
+        for (int i = 0; i < targetWords - 1; i++, sourceIndex++)
+            result.words[i] = wordAligned ? words[sourceIndex] :
+                (words[sourceIndex] >>> fromIndex) |
+                (words[sourceIndex+1] << -fromIndex);
+
+        // Process the last word
+        long lastWordMask = WORD_MASK >>> -toIndex;
+        result.words[targetWords - 1] =
+            ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK)
+            ? /* straddles source words */
+            ((words[sourceIndex] >>> fromIndex) |
+             (words[sourceIndex+1] & lastWordMask) << -fromIndex)
+            :
+            ((words[sourceIndex] & lastWordMask) >>> fromIndex);
+
+        // Set wordsInUse correctly
+        result.wordsInUse = targetWords;
+        result.recalculateWordsInUse();
+        result.checkInvariants();
+
+        return result;
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code true}
+     * that occurs on or after the specified starting index. If no such
+     * bit exists then {@code -1} is returned.
+     *
+     * <p>To iterate over the {@code true} bits in a {@code BitSet},
+     * use the following loop:
+     *
+     *  <pre> {@code
+     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+     *     // operate on index i here
+     *     if (i == Integer.MAX_VALUE) {
+     *         break; // or (i+1) would overflow
+     *     }
+     * }}</pre>
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the next set bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public int nextSetBit(int fromIndex) {
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return -1;
+
+        long word = words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            if (++u == wordsInUse)
+                return -1;
+            word = words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the first bit that is set to {@code false}
+     * that occurs on or after the specified starting index.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the next clear bit
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @since  1.4
+     */
+    public int nextClearBit(int fromIndex) {
+        // Neither spec nor implementation handle bitsets of maximal length.
+        // See 4816253.
+        if (fromIndex < 0)
+            throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return fromIndex;
+
+        long word = ~words[u] & (WORD_MASK << fromIndex);
+
+        while (true) {
+            if (word != 0)
+                return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
+            if (++u == wordsInUse)
+                return wordsInUse * BITS_PER_WORD;
+            word = ~words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the nearest bit that is set to {@code true}
+     * that occurs on or before the specified starting index.
+     * If no such bit exists, or if {@code -1} is given as the
+     * starting index, then {@code -1} is returned.
+     *
+     * <p>To iterate over the {@code true} bits in a {@code BitSet},
+     * use the following loop:
+     *
+     *  <pre> {@code
+     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
+     *     // operate on index i here
+     * }}</pre>
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the previous set bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is less
+     *         than {@code -1}
+     * @since  1.7
+     */
+    public int previousSetBit(int fromIndex) {
+        if (fromIndex < 0) {
+            if (fromIndex == -1)
+                return -1;
+            throw new IndexOutOfBoundsException(
+                "fromIndex < -1: " + fromIndex);
+        }
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return length() - 1;
+
+        long word = words[u] & (WORD_MASK >>> -(fromIndex+1));
+
+        while (true) {
+            if (word != 0)
+                return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word);
+            if (u-- == 0)
+                return -1;
+            word = words[u];
+        }
+    }
+
+    /**
+     * Returns the index of the nearest bit that is set to {@code false}
+     * that occurs on or before the specified starting index.
+     * If no such bit exists, or if {@code -1} is given as the
+     * starting index, then {@code -1} is returned.
+     *
+     * @param  fromIndex the index to start checking from (inclusive)
+     * @return the index of the previous clear bit, or {@code -1} if there
+     *         is no such bit
+     * @throws IndexOutOfBoundsException if the specified index is less
+     *         than {@code -1}
+     * @since  1.7
+     */
+    public int previousClearBit(int fromIndex) {
+        if (fromIndex < 0) {
+            if (fromIndex == -1)
+                return -1;
+            throw new IndexOutOfBoundsException(
+                "fromIndex < -1: " + fromIndex);
+        }
+
+        checkInvariants();
+
+        int u = wordIndex(fromIndex);
+        if (u >= wordsInUse)
+            return fromIndex;
+
+        long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1));
+
+        while (true) {
+            if (word != 0)
+                return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word);
+            if (u-- == 0)
+                return -1;
+            word = ~words[u];
+        }
+    }
+
+    /**
+     * Returns the "logical size" of this {@code BitSet}: the index of
+     * the highest set bit in the {@code BitSet} plus one. Returns zero
+     * if the {@code BitSet} contains no set bits.
+     *
+     * @return the logical size of this {@code BitSet}
+     * @since  1.2
+     */
+    public int length() {
+        if (wordsInUse == 0)
+            return 0;
+
+        return BITS_PER_WORD * (wordsInUse - 1) +
+            (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1]));
+    }
+
+    /**
+     * Returns true if this {@code BitSet} contains no bits that are set
+     * to {@code true}.
+     *
+     * @return boolean indicating whether this {@code BitSet} is empty
+     * @since  1.4
+     */
+    public boolean isEmpty() {
+        return wordsInUse == 0;
+    }
+
+    /**
+     * Returns true if the specified {@code BitSet} has any bits set to
+     * {@code true} that are also set to {@code true} in this {@code BitSet}.
+     *
+     * @param  set {@code BitSet} to intersect with
+     * @return boolean indicating whether this {@code BitSet} intersects
+     *         the specified {@code BitSet}
+     * @since  1.4
+     */
+    public boolean intersects(BitSet set) {
+        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+            if ((words[i] & set.words[i]) != 0)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns the number of bits set to {@code true} in this {@code BitSet}.
+     *
+     * @return the number of bits set to {@code true} in this {@code BitSet}
+     * @since  1.4
+     */
+    public int cardinality() {
+        int sum = 0;
+        for (int i = 0; i < wordsInUse; i++)
+            sum += Long.bitCount(words[i]);
+        return sum;
+    }
+
+    /**
+     * Performs a logical <b>AND</b> of this target bit set with the
+     * argument bit set. This bit set is modified so that each bit in it
+     * has the value {@code true} if and only if it both initially
+     * had the value {@code true} and the corresponding bit in the
+     * bit set argument also had the value {@code true}.
+     *
+     * @param set a bit set
+     */
+    public void and(BitSet set) {
+        if (this == set)
+            return;
+
+        while (wordsInUse > set.wordsInUse)
+            words[--wordsInUse] = 0;
+
+        // Perform logical AND on words in common
+        for (int i = 0; i < wordsInUse; i++)
+            words[i] &= set.words[i];
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Performs a logical <b>OR</b> of this bit set with the bit set
+     * argument. This bit set is modified so that a bit in it has the
+     * value {@code true} if and only if it either already had the
+     * value {@code true} or the corresponding bit in the bit set
+     * argument has the value {@code true}.
+     *
+     * @param set a bit set
+     */
+    public void or(BitSet set) {
+        if (this == set)
+            return;
+
+        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+        if (wordsInUse < set.wordsInUse) {
+            ensureCapacity(set.wordsInUse);
+            wordsInUse = set.wordsInUse;
+        }
+
+        // Perform logical OR on words in common
+        for (int i = 0; i < wordsInCommon; i++)
+            words[i] |= set.words[i];
+
+        // Copy any remaining words
+        if (wordsInCommon < set.wordsInUse)
+            System.arraycopy(set.words, wordsInCommon,
+                             words, wordsInCommon,
+                             wordsInUse - wordsInCommon);
+
+        // recalculateWordsInUse() is unnecessary
+        checkInvariants();
+    }
+
+    /**
+     * Performs a logical <b>XOR</b> of this bit set with the bit set
+     * argument. This bit set is modified so that a bit in it has the
+     * value {@code true} if and only if one of the following
+     * statements holds:
+     * <ul>
+     * <li>The bit initially has the value {@code true}, and the
+     *     corresponding bit in the argument has the value {@code false}.
+     * <li>The bit initially has the value {@code false}, and the
+     *     corresponding bit in the argument has the value {@code true}.
+     * </ul>
+     *
+     * @param  set a bit set
+     */
+    public void xor(BitSet set) {
+        int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+        if (wordsInUse < set.wordsInUse) {
+            ensureCapacity(set.wordsInUse);
+            wordsInUse = set.wordsInUse;
+        }
+
+        // Perform logical XOR on words in common
+        for (int i = 0; i < wordsInCommon; i++)
+            words[i] ^= set.words[i];
+
+        // Copy any remaining words
+        if (wordsInCommon < set.wordsInUse)
+            System.arraycopy(set.words, wordsInCommon,
+                             words, wordsInCommon,
+                             set.wordsInUse - wordsInCommon);
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Clears all of the bits in this {@code BitSet} whose corresponding
+     * bit is set in the specified {@code BitSet}.
+     *
+     * @param  set the {@code BitSet} with which to mask this
+     *         {@code BitSet}
+     * @since  1.2
+     */
+    public void andNot(BitSet set) {
+        // Perform logical (a & !b) on words in common
+        for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+            words[i] &= ~set.words[i];
+
+        recalculateWordsInUse();
+        checkInvariants();
+    }
+
+    /**
+     * Returns the hash code value for this bit set. The hash code depends
+     * only on which bits are set within this {@code BitSet}.
+     *
+     * <p>The hash code is defined to be the result of the following
+     * calculation:
+     *  <pre> {@code
+     * public int hashCode() {
+     *     long h = 1234;
+     *     long[] words = toLongArray();
+     *     for (int i = words.length; --i >= 0; )
+     *         h ^= words[i] * (i + 1);
+     *     return (int)((h >> 32) ^ h);
+     * }}</pre>
+     * Note that the hash code changes if the set of bits is altered.
+     *
+     * @return the hash code value for this bit set
+     */
+    public int hashCode() {
+        long h = 1234;
+        for (int i = wordsInUse; --i >= 0; )
+            h ^= words[i] * (i + 1);
+
+        return (int)((h >> 32) ^ h);
+    }
+
+    /**
+     * Returns the number of bits of space actually in use by this
+     * {@code BitSet} to represent bit values.
+     * The maximum element in the set is the size - 1st element.
+     *
+     * @return the number of bits currently in this bit set
+     */
+    public int size() {
+        return words.length * BITS_PER_WORD;
+    }
+
+    /**
+     * Compares this object against the specified object.
+     * The result is {@code true} if and only if the argument is
+     * not {@code null} and is a {@code Bitset} object that has
+     * exactly the same set of bits set to {@code true} as this bit
+     * set. That is, for every nonnegative {@code int} index {@code k},
+     * <pre>((BitSet)obj).get(k) == this.get(k)</pre>
+     * must be true. The current sizes of the two bit sets are not compared.
+     *
+     * @param  obj the object to compare with
+     * @return {@code true} if the objects are the same;
+     *         {@code false} otherwise
+     * @see    #size()
+     */
+    public boolean equals(Object obj) {
+        if (!(obj instanceof BitSet))
+            return false;
+        if (this == obj)
+            return true;
+
+        BitSet set = (BitSet) obj;
+
+        checkInvariants();
+        set.checkInvariants();
+
+        if (wordsInUse != set.wordsInUse)
+            return false;
+
+        // Check words in use by both BitSets
+        for (int i = 0; i < wordsInUse; i++)
+            if (words[i] != set.words[i])
+                return false;
+
+        return true;
+    }
+
+    /**
+     * Cloning this {@code BitSet} produces a new {@code BitSet}
+     * that is equal to it.
+     * The clone of the bit set is another bit set that has exactly the
+     * same bits set to {@code true} as this bit set.
+     *
+     * @return a clone of this bit set
+     * @see    #size()
+     */
+    public Object clone() {
+        if (! sizeIsSticky)
+            trimToSize();
+
+        try {
+            BitSet result = (BitSet) super.clone();
+            result.words = words.clone();
+            result.checkInvariants();
+            return result;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Attempts to reduce internal storage used for the bits in this bit set.
+     * Calling this method may, but is not required to, affect the value
+     * returned by a subsequent call to the {@link #size()} method.
+     */
+    private void trimToSize() {
+        if (wordsInUse != words.length) {
+            words = Arrays.copyOf(words, wordsInUse);
+            checkInvariants();
+        }
+    }
+
+    /**
+     * Save the state of the {@code BitSet} instance to a stream (i.e.,
+     * serialize it).
+     */
+    private void writeObject(ObjectOutputStream s)
+        throws IOException {
+
+        checkInvariants();
+
+        if (! sizeIsSticky)
+            trimToSize();
+
+        ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("bits", words);
+        s.writeFields();
+    }
+
+    /**
+     * Reconstitute the {@code BitSet} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+        words = (long[]) fields.get("bits", null);
+
+        // Assume maximum length then find real length
+        // because recalculateWordsInUse assumes maintenance
+        // or reduction in logical size
+        wordsInUse = words.length;
+        recalculateWordsInUse();
+        sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic
+        checkInvariants();
+    }
+
+    /**
+     * Returns a string representation of this bit set. For every index
+     * for which this {@code BitSet} contains a bit in the set
+     * state, the decimal representation of that index is included in
+     * the result. Such indices are listed in order from lowest to
+     * highest, separated by ",&nbsp;" (a comma and a space) and
+     * surrounded by braces, resulting in the usual mathematical
+     * notation for a set of integers.
+     *
+     * <p>Example:
+     * <pre>
+     * BitSet drPepper = new BitSet();</pre>
+     * Now {@code drPepper.toString()} returns "{@code {}}".
+     * <pre>
+     * drPepper.set(2);</pre>
+     * Now {@code drPepper.toString()} returns "{@code {2}}".
+     * <pre>
+     * drPepper.set(4);
+     * drPepper.set(10);</pre>
+     * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}".
+     *
+     * @return a string representation of this bit set
+     */
+    public String toString() {
+        checkInvariants();
+
+        int numBits = (wordsInUse > 128) ?
+            cardinality() : wordsInUse * BITS_PER_WORD;
+        StringBuilder b = new StringBuilder(6*numBits + 2);
+        b.append('{');
+
+        int i = nextSetBit(0);
+        if (i != -1) {
+            b.append(i);
+            while (true) {
+                if (++i < 0) break;
+                if ((i = nextSetBit(i)) < 0) break;
+                int endOfRun = nextClearBit(i);
+                do { b.append(", ").append(i); }
+                while (++i != endOfRun);
+            }
+        }
+
+        b.append('}');
+        return b.toString();
+    }
+
+    /**
+     * Returns a stream of indices for which this {@code BitSet}
+     * contains a bit in the set state. The indices are returned
+     * in order, from lowest to highest. The size of the stream
+     * is the number of bits in the set state, equal to the value
+     * returned by the {@link #cardinality()} method.
+     *
+     * <p>The bit set must remain constant during the execution of the
+     * terminal stream operation.  Otherwise, the result of the terminal
+     * stream operation is undefined.
+     *
+     * @return a stream of integers representing set indices
+     * @since 1.8
+     */
+    public IntStream stream() {
+        class BitSetIterator implements PrimitiveIterator.OfInt {
+            int next = nextSetBit(0);
+
+            @Override
+            public boolean hasNext() {
+                return next != -1;
+            }
+
+            @Override
+            public int nextInt() {
+                if (next != -1) {
+                    int ret = next;
+                    next = nextSetBit(next+1);
+                    return ret;
+                } else {
+                    throw new NoSuchElementException();
+                }
+            }
+        }
+
+        return StreamSupport.intStream(
+                () -> Spliterators.spliterator(
+                        new BitSetIterator(), cardinality(),
+                        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
+                Spliterator.SIZED | Spliterator.SUBSIZED |
+                        Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
+                false);
+    }
+}
diff --git a/java/util/Calendar.annotated.java b/java/util/Calendar.annotated.java
new file mode 100644
index 0000000..73efc29
--- /dev/null
+++ b/java/util/Calendar.annotated.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+
+package java.util;
+
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.time.Instant;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public abstract class Calendar implements java.io.Serializable, java.lang.Cloneable, java.lang.Comparable<java.util.Calendar> {
+
+protected Calendar() { throw new RuntimeException("Stub!"); }
+
+protected Calendar(@libcore.util.NonNull java.util.TimeZone zone, @libcore.util.NonNull java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance(@libcore.util.NonNull java.util.TimeZone zone) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance(@libcore.util.NonNull java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Calendar getInstance(@libcore.util.NonNull java.util.TimeZone zone, @libcore.util.NonNull java.util.Locale aLocale) { throw new RuntimeException("Stub!"); }
+
+public static synchronized [email protected] Locale @libcore.util.NonNull [] getAvailableLocales() { throw new RuntimeException("Stub!"); }
+
+protected abstract void computeTime();
+
+protected abstract void computeFields();
+
[email protected] public final java.util.Date getTime() { throw new RuntimeException("Stub!"); }
+
+public final void setTime(@libcore.util.NonNull java.util.Date date) { throw new RuntimeException("Stub!"); }
+
+public long getTimeInMillis() { throw new RuntimeException("Stub!"); }
+
+public void setTimeInMillis(long millis) { throw new RuntimeException("Stub!"); }
+
+public int get(int field) { throw new RuntimeException("Stub!"); }
+
+protected final int internalGet(int field) { throw new RuntimeException("Stub!"); }
+
+public void set(int field, int value) { throw new RuntimeException("Stub!"); }
+
+public final void set(int year, int month, int date) { throw new RuntimeException("Stub!"); }
+
+public final void set(int year, int month, int date, int hourOfDay, int minute) { throw new RuntimeException("Stub!"); }
+
+public final void set(int year, int month, int date, int hourOfDay, int minute, int second) { throw new RuntimeException("Stub!"); }
+
+public final void clear() { throw new RuntimeException("Stub!"); }
+
+public final void clear(int field) { throw new RuntimeException("Stub!"); }
+
+public final boolean isSet(int field) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getDisplayName(int field, int style, @libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map<[email protected] String, [email protected] Integer> getDisplayNames(int field, int style, @libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+protected void complete() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.Set<[email protected] String> getAvailableCalendarTypes() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getCalendarType() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean before(@libcore.util.Nullable java.lang.Object when) { throw new RuntimeException("Stub!"); }
+
+public boolean after(@libcore.util.Nullable java.lang.Object when) { throw new RuntimeException("Stub!"); }
+
+public int compareTo(@libcore.util.NonNull java.util.Calendar anotherCalendar) { throw new RuntimeException("Stub!"); }
+
+public abstract void add(int field, int amount);
+
+public abstract void roll(int field, boolean up);
+
+public void roll(int field, int amount) { throw new RuntimeException("Stub!"); }
+
+public void setTimeZone(@libcore.util.NonNull java.util.TimeZone value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.TimeZone getTimeZone() { throw new RuntimeException("Stub!"); }
+
+public void setLenient(boolean lenient) { throw new RuntimeException("Stub!"); }
+
+public boolean isLenient() { throw new RuntimeException("Stub!"); }
+
+public void setFirstDayOfWeek(int value) { throw new RuntimeException("Stub!"); }
+
+public int getFirstDayOfWeek() { throw new RuntimeException("Stub!"); }
+
+public void setMinimalDaysInFirstWeek(int value) { throw new RuntimeException("Stub!"); }
+
+public int getMinimalDaysInFirstWeek() { throw new RuntimeException("Stub!"); }
+
+public boolean isWeekDateSupported() { throw new RuntimeException("Stub!"); }
+
+public int getWeekYear() { throw new RuntimeException("Stub!"); }
+
+public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { throw new RuntimeException("Stub!"); }
+
+public int getWeeksInWeekYear() { throw new RuntimeException("Stub!"); }
+
+public abstract int getMinimum(int field);
+
+public abstract int getMaximum(int field);
+
+public abstract int getGreatestMinimum(int field);
+
+public abstract int getLeastMaximum(int field);
+
+public int getActualMinimum(int field) { throw new RuntimeException("Stub!"); }
+
+public int getActualMaximum(int field) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.time.Instant toInstant() { throw new RuntimeException("Stub!"); }
+
+public static final int ALL_STYLES = 0; // 0x0
+
+public static final int AM = 0; // 0x0
+
+public static final int AM_PM = 9; // 0x9
+
+public static final int APRIL = 3; // 0x3
+
+public static final int AUGUST = 7; // 0x7
+
+public static final int DATE = 5; // 0x5
+
+public static final int DAY_OF_MONTH = 5; // 0x5
+
+public static final int DAY_OF_WEEK = 7; // 0x7
+
+public static final int DAY_OF_WEEK_IN_MONTH = 8; // 0x8
+
+public static final int DAY_OF_YEAR = 6; // 0x6
+
+public static final int DECEMBER = 11; // 0xb
+
+public static final int DST_OFFSET = 16; // 0x10
+
+public static final int ERA = 0; // 0x0
+
+public static final int FEBRUARY = 1; // 0x1
+
+public static final int FIELD_COUNT = 17; // 0x11
+
+public static final int FRIDAY = 6; // 0x6
+
+public static final int HOUR = 10; // 0xa
+
+public static final int HOUR_OF_DAY = 11; // 0xb
+
+public static final int JANUARY = 0; // 0x0
+
+public static final int JULY = 6; // 0x6
+
+public static final int JUNE = 5; // 0x5
+
+public static final int LONG = 2; // 0x2
+
+public static final int LONG_FORMAT = 2; // 0x2
+
+public static final int LONG_STANDALONE = 32770; // 0x8002
+
+public static final int MARCH = 2; // 0x2
+
+public static final int MAY = 4; // 0x4
+
+public static final int MILLISECOND = 14; // 0xe
+
+public static final int MINUTE = 12; // 0xc
+
+public static final int MONDAY = 2; // 0x2
+
+public static final int MONTH = 2; // 0x2
+
+public static final int NARROW_FORMAT = 4; // 0x4
+
+public static final int NARROW_STANDALONE = 32772; // 0x8004
+
+public static final int NOVEMBER = 10; // 0xa
+
+public static final int OCTOBER = 9; // 0x9
+
+public static final int PM = 1; // 0x1
+
+public static final int SATURDAY = 7; // 0x7
+
+public static final int SECOND = 13; // 0xd
+
+public static final int SEPTEMBER = 8; // 0x8
+
+public static final int SHORT = 1; // 0x1
+
+public static final int SHORT_FORMAT = 1; // 0x1
+
+public static final int SHORT_STANDALONE = 32769; // 0x8001
+
+public static final int SUNDAY = 1; // 0x1
+
+public static final int THURSDAY = 5; // 0x5
+
+public static final int TUESDAY = 3; // 0x3
+
+public static final int UNDECIMBER = 12; // 0xc
+
+public static final int WEDNESDAY = 4; // 0x4
+
+public static final int WEEK_OF_MONTH = 4; // 0x4
+
+public static final int WEEK_OF_YEAR = 3; // 0x3
+
+public static final int YEAR = 1; // 0x1
+
+public static final int ZONE_OFFSET = 15; // 0xf
+
+protected boolean areFieldsSet;
+
+protected int @libcore.util.NonNull [] fields;
+
+protected boolean @libcore.util.NonNull [] isSet;
+
+protected boolean isTimeSet;
+
+protected long time;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static class Builder {
+
+public Builder() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setInstant(long instant) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setInstant(@libcore.util.NonNull java.util.Date instant) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder set(int field, int value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setFields(int @libcore.util.NonNull ... fieldValuePairs) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setDate(int year, int month, int dayOfMonth) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setTimeOfDay(int hourOfDay, int minute, int second) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setTimeZone(@libcore.util.NonNull java.util.TimeZone zone) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setLenient(boolean lenient) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setCalendarType(@libcore.util.NonNull java.lang.String type) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setLocale(@libcore.util.NonNull java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar.Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Calendar build() { throw new RuntimeException("Stub!"); }
+}
+
+}
diff --git a/java/util/Calendar.java b/java/util/Calendar.java
new file mode 100644
index 0000000..3a0343b
--- /dev/null
+++ b/java/util/Calendar.java
@@ -0,0 +1,3595 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.security.AccessControlContext;
+import java.security.PermissionCollection;
+import java.security.ProtectionDomain;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.time.Instant;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import libcore.icu.LocaleData;
+import sun.util.locale.provider.CalendarDataUtility;
+
+/**
+ * The <code>Calendar</code> class is an abstract class that provides methods
+ * for converting between a specific instant in time and a set of {@link
+ * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
+ * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
+ * manipulating the calendar fields, such as getting the date of the next
+ * week. An instant in time can be represented by a millisecond value that is
+ * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
+ * 00:00:00.000 GMT (Gregorian).
+ *
+ * <p>The class also provides additional fields and methods for
+ * implementing a concrete calendar system outside the package. Those
+ * fields and methods are defined as <code>protected</code>.
+ *
+ * <p>
+ * Like other locale-sensitive classes, <code>Calendar</code> provides a
+ * class method, <code>getInstance</code>, for getting a generally useful
+ * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
+ * returns a <code>Calendar</code> object whose
+ * calendar fields have been initialized with the current date and time:
+ * <blockquote>
+ * <pre>
+ *     Calendar rightNow = Calendar.getInstance();
+ * </pre>
+ * </blockquote>
+ *
+ * <p>A <code>Calendar</code> object can produce all the calendar field values
+ * needed to implement the date-time formatting for a particular language and
+ * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
+ * <code>Calendar</code> defines the range of values returned by
+ * certain calendar fields, as well as their meaning.  For example,
+ * the first month of the calendar system has value <code>MONTH ==
+ * JANUARY</code> for all calendars.  Other values are defined by the
+ * concrete subclass, such as <code>ERA</code>.  See individual field
+ * documentation and subclass documentation for details.
+ *
+ * <h3>Getting and Setting Calendar Field Values</h3>
+ *
+ * <p>The calendar field values can be set by calling the <code>set</code>
+ * methods. Any field values set in a <code>Calendar</code> will not be
+ * interpreted until it needs to calculate its time value (milliseconds from
+ * the Epoch) or values of the calendar fields. Calling the
+ * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
+ * <code>add</code> and <code>roll</code> involves such calculation.
+ *
+ * <h4>Leniency</h4>
+ *
+ * <p><code>Calendar</code> has two modes for interpreting the calendar
+ * fields, <em>lenient</em> and <em>non-lenient</em>.  When a
+ * <code>Calendar</code> is in lenient mode, it accepts a wider range of
+ * calendar field values than it produces.  When a <code>Calendar</code>
+ * recomputes calendar field values for return by <code>get()</code>, all of
+ * the calendar fields are normalized. For example, a lenient
+ * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
+ * <code>DAY_OF_MONTH == 32</code> as February 1.
+
+ * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
+ * exception if there is any inconsistency in its calendar fields. For
+ * example, a <code>GregorianCalendar</code> always produces
+ * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
+ * non-lenient <code>GregorianCalendar</code> throws an exception upon
+ * calculating its time or calendar field values if any out-of-range field
+ * value has been set.
+ *
+ * <h4><a name="first_week">First Week</a></h4>
+ *
+ * <code>Calendar</code> defines a locale-specific seven day week using two
+ * parameters: the first day of the week and the minimal days in first week
+ * (from 1 to 7).  These numbers are taken from the locale resource data when a
+ * <code>Calendar</code> is constructed.  They may also be specified explicitly
+ * through the methods for setting their values.
+ *
+ * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
+ * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
+ * first week of the month or year as a reference point.  The first week of a
+ * month or year is defined as the earliest seven day period beginning on
+ * <code>getFirstDayOfWeek()</code> and containing at least
+ * <code>getMinimalDaysInFirstWeek()</code> days of that month or year.  Weeks
+ * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
+ * it.  Note that the normalized numbering returned by <code>get()</code> may be
+ * different.  For example, a specific <code>Calendar</code> subclass may
+ * designate the week before week 1 of a year as week <code><i>n</i></code> of
+ * the previous year.
+ *
+ * <h4>Calendar Fields Resolution</h4>
+ *
+ * When computing a date and time from the calendar fields, there
+ * may be insufficient information for the computation (such as only
+ * year and month with no day of month), or there may be inconsistent
+ * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
+ * 1996 is actually a Monday). <code>Calendar</code> will resolve
+ * calendar field values to determine the date and time in the
+ * following way.
+ *
+ * <p><a name="resolution">If there is any conflict in calendar field values,
+ * <code>Calendar</code> gives priorities to calendar fields that have been set
+ * more recently.</a> The following are the default combinations of the
+ * calendar fields. The most recent combination, as determined by the
+ * most recently set single field, will be used.
+ *
+ * <p><a name="date_resolution">For the date fields</a>:
+ * <blockquote>
+ * <pre>
+ * YEAR + MONTH + DAY_OF_MONTH
+ * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ * YEAR + DAY_OF_YEAR
+ * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
+ * </pre></blockquote>
+ *
+ * <a name="time_resolution">For the time of day fields</a>:
+ * <blockquote>
+ * <pre>
+ * HOUR_OF_DAY
+ * AM_PM + HOUR
+ * </pre></blockquote>
+ *
+ * <p>If there are any calendar fields whose values haven't been set in the selected
+ * field combination, <code>Calendar</code> uses their default values. The default
+ * value of each field may vary by concrete calendar systems. For example, in
+ * <code>GregorianCalendar</code>, the default of a field is the same as that
+ * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
+ * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
+ *
+ * <p>
+ * <strong>Note:</strong> There are certain possible ambiguities in
+ * interpretation of certain singular times, which are resolved in the
+ * following ways:
+ * <ol>
+ *     <li> 23:59 is the last minute of the day and 00:00 is the first
+ *          minute of the next day. Thus, 23:59 on Dec 31, 1999 &lt; 00:00 on
+ *          Jan 1, 2000 &lt; 00:01 on Jan 1, 2000.
+ *
+ *     <li> Although historically not precise, midnight also belongs to "am",
+ *          and noon belongs to "pm", so on the same day,
+ *          12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
+ * </ol>
+ *
+ * <p>
+ * The date or time format strings are not part of the definition of a
+ * calendar, as those must be modifiable or overridable by the user at
+ * runtime. Use {@link DateFormat}
+ * to format dates.
+ *
+ * <h4>Field Manipulation</h4>
+ *
+ * The calendar fields can be changed using three methods:
+ * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.
+ *
+ * <p><strong><code>set(f, value)</code></strong> changes calendar field
+ * <code>f</code> to <code>value</code>.  In addition, it sets an
+ * internal member variable to indicate that calendar field <code>f</code> has
+ * been changed. Although calendar field <code>f</code> is changed immediately,
+ * the calendar's time value in milliseconds is not recomputed until the next call to
+ * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
+ * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
+ * <code>set()</code> do not trigger multiple, unnecessary
+ * computations. As a result of changing a calendar field using
+ * <code>set()</code>, other calendar fields may also change, depending on the
+ * calendar field, the calendar field value, and the calendar system. In addition,
+ * <code>get(f)</code> will not necessarily return <code>value</code> set by
+ * the call to the <code>set</code> method
+ * after the calendar fields have been recomputed. The specifics are determined by
+ * the concrete calendar class.</p>
+ *
+ * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
+ * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
+ * Calendar.SEPTEMBER)</code> sets the date to September 31,
+ * 1999. This is a temporary internal representation that resolves to
+ * October 1, 1999 if <code>getTime()</code>is then called. However, a
+ * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
+ * <code>getTime()</code> sets the date to September 30, 1999, since
+ * no recomputation occurs after <code>set()</code> itself.</p>
+ *
+ * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
+ * to field <code>f</code>.  This is equivalent to calling <code>set(f,
+ * get(f) + delta)</code> with two adjustments:</p>
+ *
+ * <blockquote>
+ *   <p><strong>Add rule 1</strong>. The value of field <code>f</code>
+ *   after the call minus the value of field <code>f</code> before the
+ *   call is <code>delta</code>, modulo any overflow that has occurred in
+ *   field <code>f</code>. Overflow occurs when a field value exceeds its
+ *   range and, as a result, the next larger field is incremented or
+ *   decremented and the field value is adjusted back into its range.</p>
+ *
+ *   <p><strong>Add rule 2</strong>. If a smaller field is expected to be
+ *   invariant, but it is impossible for it to be equal to its
+ *   prior value because of changes in its minimum or maximum after field
+ *   <code>f</code> is changed or other constraints, such as time zone
+ *   offset changes, then its value is adjusted to be as close
+ *   as possible to its expected value. A smaller field represents a
+ *   smaller unit of time. <code>HOUR</code> is a smaller field than
+ *   <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+ *   that are not expected to be invariant. The calendar system
+ *   determines what fields are expected to be invariant.</p>
+ * </blockquote>
+ *
+ * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
+ * an immediate recomputation of the calendar's milliseconds and all
+ * fields.</p>
+ *
+ * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
+ * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
+ * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
+ * 1</strong> sets the <code>MONTH</code> field to September, since
+ * adding 13 months to August gives September of the next year. Since
+ * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
+ * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
+ * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
+ * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
+ * rule 2, since it is expected to change when the month changes in a
+ * <code>GregorianCalendar</code>.</p>
+ *
+ * <p><strong><code>roll(f, delta)</code></strong> adds
+ * <code>delta</code> to field <code>f</code> without changing larger
+ * fields. This is equivalent to calling <code>add(f, delta)</code> with
+ * the following adjustment:</p>
+ *
+ * <blockquote>
+ *   <p><strong>Roll rule</strong>. Larger fields are unchanged after the
+ *   call. A larger field represents a larger unit of
+ *   time. <code>DAY_OF_MONTH</code> is a larger field than
+ *   <code>HOUR</code>.</p>
+ * </blockquote>
+ *
+ * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
+ *
+ * <p><strong>Usage model</strong>. To motivate the behavior of
+ * <code>add()</code> and <code>roll()</code>, consider a user interface
+ * component with increment and decrement buttons for the month, day, and
+ * year, and an underlying <code>GregorianCalendar</code>. If the
+ * interface reads January 31, 1999 and the user presses the month
+ * increment button, what should it read? If the underlying
+ * implementation uses <code>set()</code>, it might read March 3, 1999. A
+ * better result would be February 28, 1999. Furthermore, if the user
+ * presses the month increment button again, it should read March 31,
+ * 1999, not March 28, 1999. By saving the original date and using either
+ * <code>add()</code> or <code>roll()</code>, depending on whether larger
+ * fields should be affected, the user interface can behave as most users
+ * will intuitively expect.</p>
+ *
+ * @see          java.lang.System#currentTimeMillis()
+ * @see          Date
+ * @see          GregorianCalendar
+ * @see          TimeZone
+ * @see          java.text.DateFormat
+ * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
+ * @since JDK1.1
+ */
+public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
+
+    // Data flow in Calendar
+    // ---------------------
+
+    // The current time is represented in two ways by Calendar: as UTC
+    // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
+    // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
+    // millis from the fields, and vice versa.  The data needed to do this
+    // conversion is encapsulated by a TimeZone object owned by the Calendar.
+    // The data provided by the TimeZone object may also be overridden if the
+    // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
+    // keeps track of what information was most recently set by the caller, and
+    // uses that to compute any other information as needed.
+
+    // If the user sets the fields using set(), the data flow is as follows.
+    // This is implemented by the Calendar subclass's computeTime() method.
+    // During this process, certain fields may be ignored.  The disambiguation
+    // algorithm for resolving which fields to pay attention to is described
+    // in the class documentation.
+
+    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+    //           |
+    //           | Using Calendar-specific algorithm
+    //           V
+    //   local standard millis
+    //           |
+    //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
+    //           V
+    //   UTC millis (in time data member)
+
+    // If the user sets the UTC millis using setTime() or setTimeInMillis(),
+    // the data flow is as follows.  This is implemented by the Calendar
+    // subclass's computeFields() method.
+
+    //   UTC millis (in time data member)
+    //           |
+    //           | Using TimeZone getOffset()
+    //           V
+    //   local standard millis
+    //           |
+    //           | Using Calendar-specific algorithm
+    //           V
+    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
+
+    // In general, a round trip from fields, through local and UTC millis, and
+    // back out to fields is made when necessary.  This is implemented by the
+    // complete() method.  Resolving a partial set of fields into a UTC millis
+    // value allows all remaining fields to be generated from that value.  If
+    // the Calendar is lenient, the fields are also renormalized to standard
+    // ranges when they are regenerated.
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
+     * value; see subclass documentation.
+     *
+     * @see GregorianCalendar#AD
+     * @see GregorianCalendar#BC
+     */
+    public final static int ERA = 0;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * year. This is a calendar-specific value; see subclass documentation.
+     */
+    public final static int YEAR = 1;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * month. This is a calendar-specific value. The first month of
+     * the year in the Gregorian and Julian calendars is
+     * <code>JANUARY</code> which is 0; the last depends on the number
+     * of months in a year.
+     *
+     * @see #JANUARY
+     * @see #FEBRUARY
+     * @see #MARCH
+     * @see #APRIL
+     * @see #MAY
+     * @see #JUNE
+     * @see #JULY
+     * @see #AUGUST
+     * @see #SEPTEMBER
+     * @see #OCTOBER
+     * @see #NOVEMBER
+     * @see #DECEMBER
+     * @see #UNDECIMBER
+     */
+    public final static int MONTH = 2;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * week number within the current year.  The first week of the year, as
+     * defined by <code>getFirstDayOfWeek()</code> and
+     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
+     * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
+     * the year.
+     *
+     * @see #getFirstDayOfWeek
+     * @see #getMinimalDaysInFirstWeek
+     */
+    public final static int WEEK_OF_YEAR = 3;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * week number within the current month.  The first week of the month, as
+     * defined by <code>getFirstDayOfWeek()</code> and
+     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
+     * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
+     * the month.
+     *
+     * @see #getFirstDayOfWeek
+     * @see #getMinimalDaysInFirstWeek
+     */
+    public final static int WEEK_OF_MONTH = 4;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
+     * The first day of the month has value 1.
+     *
+     * @see #DAY_OF_MONTH
+     */
+    public final static int DATE = 5;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * day of the month. This is a synonym for <code>DATE</code>.
+     * The first day of the month has value 1.
+     *
+     * @see #DATE
+     */
+    public final static int DAY_OF_MONTH = 5;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the day
+     * number within the current year.  The first day of the year has value 1.
+     */
+    public final static int DAY_OF_YEAR = 6;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the day
+     * of the week.  This field takes values <code>SUNDAY</code>,
+     * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
+     * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
+     *
+     * @see #SUNDAY
+     * @see #MONDAY
+     * @see #TUESDAY
+     * @see #WEDNESDAY
+     * @see #THURSDAY
+     * @see #FRIDAY
+     * @see #SATURDAY
+     */
+    public final static int DAY_OF_WEEK = 7;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * ordinal number of the day of the week within the current month. Together
+     * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
+     * within a month.  Unlike <code>WEEK_OF_MONTH</code> and
+     * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
+     * <code>getFirstDayOfWeek()</code> or
+     * <code>getMinimalDaysInFirstWeek()</code>.  <code>DAY_OF_MONTH 1</code>
+     * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
+     * 1</code>; <code>8</code> through <code>14</code> correspond to
+     * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
+     * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
+     * <code>DAY_OF_WEEK_IN_MONTH 1</code>.  Negative values count back from the
+     * end of the month, so the last Sunday of a month is specified as
+     * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>.  Because
+     * negative values count backward they will usually be aligned differently
+     * within the month than positive values.  For example, if a month has 31
+     * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
+     * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
+     *
+     * @see #DAY_OF_WEEK
+     * @see #WEEK_OF_MONTH
+     */
+    public final static int DAY_OF_WEEK_IN_MONTH = 8;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating
+     * whether the <code>HOUR</code> is before or after noon.
+     * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
+     *
+     * @see #AM
+     * @see #PM
+     * @see #HOUR
+     */
+    public final static int AM_PM = 9;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * hour of the morning or afternoon. <code>HOUR</code> is used for the
+     * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
+     * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
+     *
+     * @see #AM_PM
+     * @see #HOUR_OF_DAY
+     */
+    public final static int HOUR = 10;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
+     * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
+     *
+     * @see #HOUR
+     */
+    public final static int HOUR_OF_DAY = 11;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * minute within the hour.
+     * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
+     */
+    public final static int MINUTE = 12;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * second within the minute.
+     * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
+     */
+    public final static int SECOND = 13;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * millisecond within the second.
+     * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
+     */
+    public final static int MILLISECOND = 14;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code>
+     * indicating the raw offset from GMT in milliseconds.
+     * <p>
+     * This field reflects the correct GMT offset value of the time
+     * zone of this <code>Calendar</code> if the
+     * <code>TimeZone</code> implementation subclass supports
+     * historical GMT offset changes.
+     */
+    public final static int ZONE_OFFSET = 15;
+
+    /**
+     * Field number for <code>get</code> and <code>set</code> indicating the
+     * daylight saving offset in milliseconds.
+     * <p>
+     * This field reflects the correct daylight saving offset value of
+     * the time zone of this <code>Calendar</code> if the
+     * <code>TimeZone</code> implementation subclass supports
+     * historical Daylight Saving Time schedule changes.
+     */
+    public final static int DST_OFFSET = 16;
+
+    /**
+     * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
+     * Field numbers range from <code>0..FIELD_COUNT-1</code>.
+     */
+    public final static int FIELD_COUNT = 17;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Sunday.
+     */
+    public final static int SUNDAY = 1;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Monday.
+     */
+    public final static int MONDAY = 2;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Tuesday.
+     */
+    public final static int TUESDAY = 3;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Wednesday.
+     */
+    public final static int WEDNESDAY = 4;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Thursday.
+     */
+    public final static int THURSDAY = 5;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Friday.
+     */
+    public final static int FRIDAY = 6;
+
+    /**
+     * Value of the {@link #DAY_OF_WEEK} field indicating
+     * Saturday.
+     */
+    public final static int SATURDAY = 7;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * first month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int JANUARY = 0;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * second month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int FEBRUARY = 1;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * third month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int MARCH = 2;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * fourth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int APRIL = 3;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * fifth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int MAY = 4;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * sixth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int JUNE = 5;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * seventh month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int JULY = 6;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * eighth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int AUGUST = 7;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * ninth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int SEPTEMBER = 8;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * tenth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int OCTOBER = 9;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * eleventh month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int NOVEMBER = 10;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * twelfth month of the year in the Gregorian and Julian calendars.
+     */
+    public final static int DECEMBER = 11;
+
+    /**
+     * Value of the {@link #MONTH} field indicating the
+     * thirteenth month of the year. Although <code>GregorianCalendar</code>
+     * does not use this value, lunar calendars do.
+     */
+    public final static int UNDECIMBER = 12;
+
+    /**
+     * Value of the {@link #AM_PM} field indicating the
+     * period of the day from midnight to just before noon.
+     */
+    public final static int AM = 0;
+
+    /**
+     * Value of the {@link #AM_PM} field indicating the
+     * period of the day from noon to just before midnight.
+     */
+    public final static int PM = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating names in all styles, such as
+     * "January" and "Jan".
+     *
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @see #SHORT_STANDALONE
+     * @see #LONG_STANDALONE
+     * @see #SHORT
+     * @see #LONG
+     * @since 1.6
+     */
+    public static final int ALL_STYLES = 0;
+
+    static final int STANDALONE_MASK = 0x8000;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} equivalent to {@link #SHORT_FORMAT}.
+     *
+     * @see #SHORT_STANDALONE
+     * @see #LONG
+     * @since 1.6
+     */
+    public static final int SHORT = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} equivalent to {@link #LONG_FORMAT}.
+     *
+     * @see #LONG_STANDALONE
+     * @see #SHORT
+     * @since 1.6
+     */
+    public static final int LONG = 2;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a narrow name used for format. Narrow names
+     * are typically single character strings, such as "M" for Monday.
+     *
+     * @see #NARROW_STANDALONE
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @since 1.8
+     */
+    public static final int NARROW_FORMAT = 4;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a narrow name independently. Narrow names
+     * are typically single character strings, such as "M" for Monday.
+     *
+     * @see #NARROW_FORMAT
+     * @see #SHORT_STANDALONE
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int NARROW_STANDALONE = NARROW_FORMAT | STANDALONE_MASK;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a short name used for format.
+     *
+     * @see #SHORT_STANDALONE
+     * @see #LONG_FORMAT
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int SHORT_FORMAT = 1;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a long name used for format.
+     *
+     * @see #LONG_STANDALONE
+     * @see #SHORT_FORMAT
+     * @see #SHORT_STANDALONE
+     * @since 1.8
+     */
+    public static final int LONG_FORMAT = 2;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a short name used independently,
+     * such as a month abbreviation as calendar headers.
+     *
+     * @see #SHORT_FORMAT
+     * @see #LONG_FORMAT
+     * @see #LONG_STANDALONE
+     * @since 1.8
+     */
+    public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK;
+
+    /**
+     * A style specifier for {@link #getDisplayName(int, int, Locale)
+     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
+     * getDisplayNames} indicating a long name used independently,
+     * such as a month name as calendar headers.
+     *
+     * @see #LONG_FORMAT
+     * @see #SHORT_FORMAT
+     * @see #SHORT_STANDALONE
+     * @since 1.8
+     */
+    public static final int LONG_STANDALONE = LONG | STANDALONE_MASK;
+
+    // Internal notes:
+    // Calendar contains two kinds of time representations: current "time" in
+    // milliseconds, and a set of calendar "fields" representing the current time.
+    // The two representations are usually in sync, but can get out of sync
+    // as follows.
+    // 1. Initially, no fields are set, and the time is invalid.
+    // 2. If the time is set, all fields are computed and in sync.
+    // 3. If a single field is set, the time is invalid.
+    // Recomputation of the time and fields happens when the object needs
+    // to return a result to the user, or use a result for a computation.
+
+    /**
+     * The calendar field values for the currently set time for this calendar.
+     * This is an array of <code>FIELD_COUNT</code> integers, with index values
+     * <code>ERA</code> through <code>DST_OFFSET</code>.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected int           fields[];
+
+    /**
+     * The flags which tell if a specified calendar field for the calendar is set.
+     * A new object has no fields set.  After the first call to a method
+     * which generates the fields, they all remain set after that.
+     * This is an array of <code>FIELD_COUNT</code> booleans, with index values
+     * <code>ERA</code> through <code>DST_OFFSET</code>.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       isSet[];
+
+    /**
+     * Pseudo-time-stamps which specify when each field was set. There
+     * are two special values, UNSET and COMPUTED. Values from
+     * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
+     */
+    transient private int   stamp[];
+
+    /**
+     * The currently set time for this calendar, expressed in milliseconds after
+     * January 1, 1970, 0:00:00 GMT.
+     * @see #isTimeSet
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected long          time;
+
+    /**
+     * True if then the value of <code>time</code> is valid.
+     * The time is made invalid by a change to an item of <code>field[]</code>.
+     * @see #time
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       isTimeSet;
+
+    /**
+     * True if <code>fields[]</code> are in sync with the currently set time.
+     * If false, then the next attempt to get the value of a field will
+     * force a recomputation of all fields from the current value of
+     * <code>time</code>.
+     * @serial
+     */
+    @SuppressWarnings("ProtectedField")
+    protected boolean       areFieldsSet;
+
+    /**
+     * True if all fields have been set.
+     * @serial
+     */
+    transient boolean       areAllFieldsSet;
+
+    /**
+     * <code>True</code> if this calendar allows out-of-range field values during computation
+     * of <code>time</code> from <code>fields[]</code>.
+     * @see #setLenient
+     * @see #isLenient
+     * @serial
+     */
+    private boolean         lenient = true;
+
+    /**
+     * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
+     * uses the time zone data to translate between locale and GMT time.
+     * @serial
+     */
+    private TimeZone        zone;
+
+    /**
+     * <code>True</code> if zone references to a shared TimeZone object.
+     */
+    transient private boolean sharedZone = false;
+
+    /**
+     * The first day of the week, with possible values <code>SUNDAY</code>,
+     * <code>MONDAY</code>, etc.  This is a locale-dependent value.
+     * @serial
+     */
+    private int             firstDayOfWeek;
+
+    /**
+     * The number of days required for the first week in a month or year,
+     * with possible values from 1 to 7.  This is a locale-dependent value.
+     * @serial
+     */
+    private int             minimalDaysInFirstWeek;
+
+    /**
+     * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
+     * of a Locale.
+     */
+    private static final ConcurrentMap<Locale, int[]> cachedLocaleData
+        = new ConcurrentHashMap<>(3);
+
+    // Special values of stamp[]
+    /**
+     * The corresponding fields[] has no value.
+     */
+    private static final int        UNSET = 0;
+
+    /**
+     * The value of the corresponding fields[] has been calculated internally.
+     */
+    private static final int        COMPUTED = 1;
+
+    /**
+     * The value of the corresponding fields[] has been set externally. Stamp
+     * values which are greater than 1 represents the (pseudo) time when the
+     * corresponding fields[] value was set.
+     */
+    private static final int        MINIMUM_USER_STAMP = 2;
+
+    /**
+     * The mask value that represents all of the fields.
+     */
+    static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
+
+    /**
+     * The next available value for <code>stamp[]</code>, an internal array.
+     * This actually should not be written out to the stream, and will probably
+     * be removed from the stream in the near future.  In the meantime,
+     * a value of <code>MINIMUM_USER_STAMP</code> should be used.
+     * @serial
+     */
+    private int             nextStamp = MINIMUM_USER_STAMP;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.5
+    // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
+    //     as well as compatible values for other fields.  This is a
+    //     transitional format.
+    // - 2 (not implemented yet) a future version, in which fields[],
+    //     areFieldsSet, and isTimeSet become transient, and isSet[] is
+    //     removed. In JDK 1.1.6 we write a format compatible with version 2.
+    static final int        currentSerialVersion = 1;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <dl>
+     * <dt><b>0</b> or not present on stream</dt>
+     * <dd>
+     * JDK 1.1.5 or earlier.
+     * </dd>
+     * <dt><b>1</b></dt>
+     * <dd>
+     * JDK 1.1.6 or later.  Writes a correct 'time' value
+     * as well as compatible values for other fields.  This is a
+     * transitional format.
+     * </dd>
+     * </dl>
+     * When streaming out this class, the most recent format
+     * and the highest allowable <code>serialVersionOnStream</code>
+     * is written.
+     * @serial
+     * @since JDK1.1.6
+     */
+    private int             serialVersionOnStream = currentSerialVersion;
+
+    // Proclaim serialization compatibility with JDK 1.1
+    static final long       serialVersionUID = -1807547505821590642L;
+
+    // Mask values for calendar fields
+    @SuppressWarnings("PointlessBitwiseExpression")
+    final static int ERA_MASK           = (1 << ERA);
+    final static int YEAR_MASK          = (1 << YEAR);
+    final static int MONTH_MASK         = (1 << MONTH);
+    final static int WEEK_OF_YEAR_MASK  = (1 << WEEK_OF_YEAR);
+    final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
+    final static int DAY_OF_MONTH_MASK  = (1 << DAY_OF_MONTH);
+    final static int DATE_MASK          = DAY_OF_MONTH_MASK;
+    final static int DAY_OF_YEAR_MASK   = (1 << DAY_OF_YEAR);
+    final static int DAY_OF_WEEK_MASK   = (1 << DAY_OF_WEEK);
+    final static int DAY_OF_WEEK_IN_MONTH_MASK  = (1 << DAY_OF_WEEK_IN_MONTH);
+    final static int AM_PM_MASK         = (1 << AM_PM);
+    final static int HOUR_MASK          = (1 << HOUR);
+    final static int HOUR_OF_DAY_MASK   = (1 << HOUR_OF_DAY);
+    final static int MINUTE_MASK        = (1 << MINUTE);
+    final static int SECOND_MASK        = (1 << SECOND);
+    final static int MILLISECOND_MASK   = (1 << MILLISECOND);
+    final static int ZONE_OFFSET_MASK   = (1 << ZONE_OFFSET);
+    final static int DST_OFFSET_MASK    = (1 << DST_OFFSET);
+
+    /**
+     * {@code Calendar.Builder} is used for creating a {@code Calendar} from
+     * various date-time parameters.
+     *
+     * <p>There are two ways to set a {@code Calendar} to a date-time value. One
+     * is to set the instant parameter to a millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>. The other is to set individual
+     * field parameters, such as {@link Calendar#YEAR YEAR}, to their desired
+     * values. These two ways can't be mixed. Trying to set both the instant and
+     * individual fields will cause an {@link IllegalStateException} to be
+     * thrown. However, it is permitted to override previous values of the
+     * instant or field parameters.
+     *
+     * <p>If no enough field parameters are given for determining date and/or
+     * time, calendar specific default values are used when building a
+     * {@code Calendar}. For example, if the {@link Calendar#YEAR YEAR} value
+     * isn't given for the Gregorian calendar, 1970 will be used. If there are
+     * any conflicts among field parameters, the <a
+     * href="Calendar.html#resolution"> resolution rules</a> are applied.
+     * Therefore, the order of field setting matters.
+     *
+     * <p>In addition to the date-time parameters,
+     * the {@linkplain #setLocale(Locale) locale},
+     * {@linkplain #setTimeZone(TimeZone) time zone},
+     * {@linkplain #setWeekDefinition(int, int) week definition}, and
+     * {@linkplain #setLenient(boolean) leniency mode} parameters can be set.
+     *
+     * <p><b>Examples</b>
+     * <p>The following are sample usages. Sample code assumes that the
+     * {@code Calendar} constants are statically imported.
+     *
+     * <p>The following code produces a {@code Calendar} with date 2012-12-31
+     * (Gregorian) because Monday is the first day of a week with the <a
+     * href="GregorianCalendar.html#iso8601_compatible_setting"> ISO 8601
+     * compatible week parameters</a>.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
+     *                        .setWeekDate(2013, 1, MONDAY).build();</pre>
+     * <p>The following code produces a Japanese {@code Calendar} with date
+     * 1989-01-08 (Gregorian), assuming that the default {@link Calendar#ERA ERA}
+     * is <em>Heisei</em> that started on that day.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("japanese")
+     *                        .setFields(YEAR, 1, DAY_OF_YEAR, 1).build();</pre>
+     *
+     * @since 1.8
+     * @see Calendar#getInstance(TimeZone, Locale)
+     * @see Calendar#fields
+     */
+    public static class Builder {
+        private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR
+        private static final int WEEK_YEAR = FIELD_COUNT;
+
+        private long instant;
+        // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined
+        private int[] fields;
+        // Pseudo timestamp starting from MINIMUM_USER_STAMP.
+        // (COMPUTED is used to indicate that the instant has been set.)
+        private int nextStamp;
+        // maxFieldIndex keeps the max index of fields which have been set.
+        // (WEEK_YEAR is never included.)
+        private int maxFieldIndex;
+        private String type;
+        private TimeZone zone;
+        private boolean lenient = true;
+        private Locale locale;
+        private int firstDayOfWeek, minimalDaysInFirstWeek;
+
+        /**
+         * Constructs a {@code Calendar.Builder}.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the instant parameter to the given {@code instant} value that is
+         * a millisecond offset from <a href="Calendar.html#Epoch">the
+         * Epoch</a>.
+         *
+         * @param instant a millisecond offset from the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public Builder setInstant(long instant) {
+            if (fields != null) {
+                throw new IllegalStateException();
+            }
+            this.instant = instant;
+            nextStamp = COMPUTED;
+            return this;
+        }
+
+        /**
+         * Sets the instant parameter to the {@code instant} value given by a
+         * {@link Date}. This method is equivalent to a call to
+         * {@link #setInstant(long) setInstant(instant.getTime())}.
+         *
+         * @param instant a {@code Date} representing a millisecond offset from
+         *                the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException  if {@code instant} is {@code null}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public Builder setInstant(Date instant) {
+            return setInstant(instant.getTime()); // NPE if instant == null
+        }
+
+        /**
+         * Sets the {@code field} parameter to the given {@code value}.
+         * {@code field} is an index to the {@link Calendar#fields}, such as
+         * {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH}. Field value validation is
+         * not performed in this method. Any out of range values are either
+         * normalized in lenient mode or detected as an invalid value in
+         * non-lenient mode when building a {@code Calendar}.
+         *
+         * @param field an index to the {@code Calendar} fields
+         * @param value the field value
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code field} is invalid
+         * @throws IllegalStateException if the instant value has already been set,
+         *                      or if fields have been set too many
+         *                      (approximately {@link Integer#MAX_VALUE}) times.
+         * @see Calendar#set(int, int)
+         */
+        public Builder set(int field, int value) {
+            // Note: WEEK_YEAR can't be set with this method.
+            if (field < 0 || field >= FIELD_COUNT) {
+                throw new IllegalArgumentException("field is invalid");
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            allocateFields();
+            internalSet(field, value);
+            return this;
+        }
+
+        // Android-changed: fix typo in example code.
+        /**
+         * Sets field parameters to their values given by
+         * {@code fieldValuePairs} that are pairs of a field and its value.
+         * For example,
+         * <pre>
+         *   setFields(Calendar.YEAR, 2013,
+         *             Calendar.MONTH, Calendar.DECEMBER,
+         *             Calendar.DAY_OF_MONTH, 23);</pre>
+         * is equivalent to the sequence of the following
+         * {@link #set(int, int) set} calls:
+         * <pre>
+         *   set(Calendar.YEAR, 2013)
+         *   .set(Calendar.MONTH, Calendar.DECEMBER)
+         *   .set(Calendar.DAY_OF_MONTH, 23);</pre>
+         *
+         * @param fieldValuePairs field-value pairs
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code fieldValuePairs} is {@code null}
+         * @throws IllegalArgumentException if any of fields are invalid,
+         *             or if {@code fieldValuePairs.length} is an odd number.
+         * @throws IllegalStateException    if the instant value has been set,
+         *             or if fields have been set too many (approximately
+         *             {@link Integer#MAX_VALUE}) times.
+         */
+        public Builder setFields(int... fieldValuePairs) {
+            int len = fieldValuePairs.length;
+            if ((len % 2) != 0) {
+                throw new IllegalArgumentException();
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            if ((nextStamp + len / 2) < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            allocateFields();
+            for (int i = 0; i < len; ) {
+                int field = fieldValuePairs[i++];
+                // Note: WEEK_YEAR can't be set with this method.
+                if (field < 0 || field >= FIELD_COUNT) {
+                    throw new IllegalArgumentException("field is invalid");
+                }
+                internalSet(field, fieldValuePairs[i++]);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the date field parameters to the values given by {@code year},
+         * {@code month}, and {@code dayOfMonth}. This method is equivalent to
+         * a call to:
+         * <pre>
+         *   setFields(Calendar.YEAR, year,
+         *             Calendar.MONTH, month,
+         *             Calendar.DAY_OF_MONTH, dayOfMonth);</pre>
+         *
+         * @param year       the {@link Calendar#YEAR YEAR} value
+         * @param month      the {@link Calendar#MONTH MONTH} value
+         *                   (the month numbering is <em>0-based</em>).
+         * @param dayOfMonth the {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setDate(int year, int month, int dayOfMonth) {
+            return setFields(YEAR, year, MONTH, month, DAY_OF_MONTH, dayOfMonth);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, and {@code second}. This method is
+         * equivalent to a call to:
+         * <pre>
+         *   setTimeOfDay(hourOfDay, minute, second, 0);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setTimeOfDay(int hourOfDay, int minute, int second) {
+            return setTimeOfDay(hourOfDay, minute, second, 0);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, {@code second}, and
+         * {@code millis}. This method is equivalent to a call to:
+         * <pre>
+         *   setFields(Calendar.HOUR_OF_DAY, hourOfDay,
+         *             Calendar.MINUTE, minute,
+         *             Calendar.SECOND, second,
+         *             Calendar.MILLISECOND, millis);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @param millis    the {@link Calendar#MILLISECOND MILLISECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public Builder setTimeOfDay(int hourOfDay, int minute, int second, int millis) {
+            return setFields(HOUR_OF_DAY, hourOfDay, MINUTE, minute,
+                             SECOND, second, MILLISECOND, millis);
+        }
+
+        /**
+         * Sets the week-based date parameters to the values with the given
+         * date specifiers - week year, week of year, and day of week.
+         *
+         * <p>If the specified calendar doesn't support week dates, the
+         * {@link #build() build} method will throw an {@link IllegalArgumentException}.
+         *
+         * @param weekYear   the week year
+         * @param weekOfYear the week number based on {@code weekYear}
+         * @param dayOfWeek  the day of week value: one of the constants
+         *     for the {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} field:
+         *     {@link Calendar#SUNDAY SUNDAY}, ..., {@link Calendar#SATURDAY SATURDAY}.
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setWeekDate(int, int, int)
+         * @see Calendar#isWeekDateSupported()
+         */
+        public Builder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+            allocateFields();
+            internalSet(WEEK_YEAR, weekYear);
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(DAY_OF_WEEK, dayOfWeek);
+            return this;
+        }
+
+        /**
+         * Sets the time zone parameter to the given {@code zone}. If no time
+         * zone parameter is given to this {@code Caledar.Builder}, the
+         * {@linkplain TimeZone#getDefault() default
+         * <code>TimeZone</code>} will be used in the {@link #build() build}
+         * method.
+         *
+         * @param zone the {@link TimeZone}
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code zone} is {@code null}
+         * @see Calendar#setTimeZone(TimeZone)
+         */
+        public Builder setTimeZone(TimeZone zone) {
+            if (zone == null) {
+                throw new NullPointerException();
+            }
+            this.zone = zone;
+            return this;
+        }
+
+        /**
+         * Sets the lenient mode parameter to the value given by {@code lenient}.
+         * If no lenient parameter is given to this {@code Calendar.Builder},
+         * lenient mode will be used in the {@link #build() build} method.
+         *
+         * @param lenient {@code true} for lenient mode;
+         *                {@code false} for non-lenient mode
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setLenient(boolean)
+         */
+        public Builder setLenient(boolean lenient) {
+            this.lenient = lenient;
+            return this;
+        }
+
+        /**
+         * Sets the calendar type parameter to the given {@code type}. The
+         * calendar type given by this method has precedence over any explicit
+         * or implicit calendar type given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * <p>In addition to the available calendar types returned by the
+         * {@link Calendar#getAvailableCalendarTypes() Calendar.getAvailableCalendarTypes}
+         * method, {@code "gregorian"} and {@code "iso8601"} as aliases of
+         * {@code "gregory"} can be used with this method.
+         *
+         * @param type the calendar type
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code type} is {@code null}
+         * @throws IllegalArgumentException if {@code type} is unknown
+         * @throws IllegalStateException if another calendar type has already been set
+         * @see Calendar#getCalendarType()
+         * @see Calendar#getAvailableCalendarTypes()
+         */
+        public Builder setCalendarType(String type) {
+            if (type.equals("gregorian")) { // NPE if type == null
+                type = "gregory";
+            }
+            if (!Calendar.getAvailableCalendarTypes().contains(type)
+                    && !type.equals("iso8601")) {
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            if (this.type == null) {
+                this.type = type;
+            } else {
+                if (!this.type.equals(type)) {
+                    throw new IllegalStateException("calendar type override");
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Sets the locale parameter to the given {@code locale}. If no locale
+         * is given to this {@code Calendar.Builder}, the {@linkplain
+         * Locale#getDefault(Locale.Category) default <code>Locale</code>}
+         * for {@link Locale.Category#FORMAT} will be used.
+         *
+         * <p>If no calendar type is explicitly given by a call to the
+         * {@link #setCalendarType(String) setCalendarType} method,
+         * the {@code Locale} value is used to determine what type of
+         * {@code Calendar} to be built.
+         *
+         * <p>If no week definition parameters are explicitly given by a call to
+         * the {@link #setWeekDefinition(int,int) setWeekDefinition} method, the
+         * {@code Locale}'s default values are used.
+         *
+         * @param locale the {@link Locale}
+         * @throws NullPointerException if {@code locale} is {@code null}
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#getInstance(Locale)
+         */
+        public Builder setLocale(Locale locale) {
+            if (locale == null) {
+                throw new NullPointerException();
+            }
+            this.locale = locale;
+            return this;
+        }
+
+        /**
+         * Sets the week definition parameters to the values given by
+         * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are
+         * used to determine the <a href="Calendar.html#First_Week">first
+         * week</a> of a year. The parameters given by this method have
+         * precedence over the default values given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * @param firstDayOfWeek the first day of a week; one of
+         *                       {@link Calendar#SUNDAY} to {@link Calendar#SATURDAY}
+         * @param minimalDaysInFirstWeek the minimal number of days in the first
+         *                               week (1..7)
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code firstDayOfWeek} or
+         *                                  {@code minimalDaysInFirstWeek} is invalid
+         * @see Calendar#getFirstDayOfWeek()
+         * @see Calendar#getMinimalDaysInFirstWeek()
+         */
+        public Builder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) {
+            if (!isValidWeekParameter(firstDayOfWeek)
+                    || !isValidWeekParameter(minimalDaysInFirstWeek)) {
+                throw new IllegalArgumentException();
+            }
+            this.firstDayOfWeek = firstDayOfWeek;
+            this.minimalDaysInFirstWeek = minimalDaysInFirstWeek;
+            return this;
+        }
+
+        /**
+         * Returns a {@code Calendar} built from the parameters set by the
+         * setter methods. The calendar type given by the {@link #setCalendarType(String)
+         * setCalendarType} method or the {@linkplain #setLocale(Locale) locale} is
+         * used to determine what {@code Calendar} to be created. If no explicit
+         * calendar type is given, the locale's default calendar is created.
+         *
+         * <p>If the calendar type is {@code "iso8601"}, the
+         * {@linkplain GregorianCalendar#setGregorianChange(Date) Gregorian change date}
+         * of a {@link GregorianCalendar} is set to {@code Date(Long.MIN_VALUE)}
+         * to be the <em>proleptic</em> Gregorian calendar. Its week definition
+         * parameters are also set to be <a
+         * href="GregorianCalendar.html#iso8601_compatible_setting">compatible
+         * with the ISO 8601 standard</a>. Note that the
+         * {@link GregorianCalendar#getCalendarType() getCalendarType} method of
+         * a {@code GregorianCalendar} created with {@code "iso8601"} returns
+         * {@code "gregory"}.
+         *
+         * <p>The default values are used for locale and time zone if these
+         * parameters haven't been given explicitly.
+         *
+         * <p>Any out of range field values are either normalized in lenient
+         * mode or detected as an invalid value in non-lenient mode.
+         *
+         * @return a {@code Calendar} built with parameters of this {@code
+         *         Calendar.Builder}
+         * @throws IllegalArgumentException if the calendar type is unknown, or
+         *             if any invalid field values are given in non-lenient mode, or
+         *             if a week date is given for the calendar type that doesn't
+         *             support week dates.
+         * @see Calendar#getInstance(TimeZone, Locale)
+         * @see Locale#getDefault(Locale.Category)
+         * @see TimeZone#getDefault()
+         */
+        public Calendar build() {
+            if (locale == null) {
+                locale = Locale.getDefault();
+            }
+            if (zone == null) {
+                zone = TimeZone.getDefault();
+            }
+            Calendar cal;
+            if (type == null) {
+                type = locale.getUnicodeLocaleType("ca");
+            }
+            if (type == null) {
+                // BEGIN Android-changed: don't switch to buddhist calendar based on locale.
+                // See http://b/35138741
+                /*
+                if (locale.getCountry() == "TH"
+                        && locale.getLanguage() == "th") {
+                    type = "buddhist";
+                } else {
+                    type = "gregory";
+                }
+                */
+                type = "gregory";
+                // END Android-changed: don't switch to buddhist calendar based on locale.
+            }
+            switch (type) {
+            case "gregory":
+                cal = new GregorianCalendar(zone, locale, true);
+                break;
+            case "iso8601":
+                GregorianCalendar gcal = new GregorianCalendar(zone, locale, true);
+                // make gcal a proleptic Gregorian
+                gcal.setGregorianChange(new Date(Long.MIN_VALUE));
+                // and week definition to be compatible with ISO 8601
+                setWeekDefinition(MONDAY, 4);
+                cal = gcal;
+                break;
+// BEGIN Android-changed: removed support for "buddhist" and "japanese".
+//            case "buddhist":
+//                cal = new BuddhistCalendar(zone, locale);
+//                cal.clear();
+//                break;
+//            case "japanese":
+//                cal = new JapaneseImperialCalendar(zone, locale, true);
+//                break;
+// END Android-changed: removed support for "buddhist" and "japanese".
+            default:
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            cal.setLenient(lenient);
+            if (firstDayOfWeek != 0) {
+                cal.setFirstDayOfWeek(firstDayOfWeek);
+                cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+            }
+            if (isInstantSet()) {
+                cal.setTimeInMillis(instant);
+                cal.complete();
+                return cal;
+            }
+
+            if (fields != null) {
+                boolean weekDate = isSet(WEEK_YEAR)
+                                       && fields[WEEK_YEAR] > fields[YEAR];
+                if (weekDate && !cal.isWeekDateSupported()) {
+                    throw new IllegalArgumentException("week date is unsupported by " + type);
+                }
+
+                // Set the fields from the min stamp to the max stamp so that
+                // the fields resolution works in the Calendar.
+                for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
+                    for (int index = 0; index <= maxFieldIndex; index++) {
+                        if (fields[index] == stamp) {
+                            cal.set(index, fields[NFIELDS + index]);
+                            break;
+                        }
+                    }
+                }
+
+                if (weekDate) {
+                    int weekOfYear = isSet(WEEK_OF_YEAR) ? fields[NFIELDS + WEEK_OF_YEAR] : 1;
+                    int dayOfWeek = isSet(DAY_OF_WEEK)
+                                    ? fields[NFIELDS + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
+                    cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
+                }
+                cal.complete();
+            }
+
+            return cal;
+        }
+
+        private void allocateFields() {
+            if (fields == null) {
+                fields = new int[NFIELDS * 2];
+                nextStamp = MINIMUM_USER_STAMP;
+                maxFieldIndex = -1;
+            }
+        }
+
+        private void internalSet(int field, int value) {
+            fields[field] = nextStamp++;
+            if (nextStamp < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            fields[NFIELDS + field] = value;
+            if (field > maxFieldIndex && field < WEEK_YEAR) {
+                maxFieldIndex = field;
+            }
+        }
+
+        private boolean isInstantSet() {
+            return nextStamp == COMPUTED;
+        }
+
+        private boolean isSet(int index) {
+            return fields != null && fields[index] > UNSET;
+        }
+
+        private boolean isValidWeekParameter(int value) {
+            return value > 0 && value <= 7;
+        }
+    }
+
+    /**
+     * Constructs a Calendar with the default time zone
+     * and the default {@link java.util.Locale.Category#FORMAT FORMAT}
+     * locale.
+     * @see     TimeZone#getDefault
+     */
+    protected Calendar()
+    {
+        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
+        sharedZone = true;
+    }
+
+    /**
+     * Constructs a calendar with the specified time zone and locale.
+     *
+     * @param zone the time zone to use
+     * @param aLocale the locale for the week data
+     */
+    protected Calendar(TimeZone zone, Locale aLocale)
+    {
+        // BEGIN Android-added: Allow aLocale == null
+        // http://b/16938922.
+        //
+        // TODO: This is for backwards compatibility only. Seems like a better idea to throw
+        // here. We should add a targetSdkVersion based check and throw for this case.
+        if (aLocale == null) {
+            aLocale = Locale.getDefault();
+        }
+        // END Android-added: Allow aLocale == null
+        fields = new int[FIELD_COUNT];
+        isSet = new boolean[FIELD_COUNT];
+        stamp = new int[FIELD_COUNT];
+
+        this.zone = zone;
+        setWeekCountData(aLocale);
+    }
+
+    /**
+     * Gets a calendar using the default time zone and locale. The
+     * <code>Calendar</code> returned is based on the current time
+     * in the default time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @return a Calendar.
+     */
+    public static Calendar getInstance()
+    {
+        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets a calendar using the specified time zone and default locale.
+     * The <code>Calendar</code> returned is based on the current time
+     * in the given time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @param zone the time zone to use
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(TimeZone zone)
+    {
+        return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Gets a calendar using the default time zone and specified locale.
+     * The <code>Calendar</code> returned is based on the current time
+     * in the default time zone with the given locale.
+     *
+     * @param aLocale the locale for the week data
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(Locale aLocale)
+    {
+        return createCalendar(TimeZone.getDefault(), aLocale);
+    }
+
+    /**
+     * Gets a calendar with the specified time zone and locale.
+     * The <code>Calendar</code> returned is based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the time zone to use
+     * @param aLocale the locale for the week data
+     * @return a Calendar.
+     */
+    public static Calendar getInstance(TimeZone zone,
+                                       Locale aLocale)
+    {
+        return createCalendar(zone, aLocale);
+    }
+
+    // BEGIN Android-added: add getJapaneseImperialInstance()
+    /**
+     * Create a Japanese Imperial Calendar.
+     * @hide
+     */
+    public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) {
+        return new JapaneseImperialCalendar(zone, aLocale);
+    }
+    // END Android-added: add getJapaneseImperialInstance()
+
+    private static Calendar createCalendar(TimeZone zone,
+                                           Locale aLocale)
+    {
+        // BEGIN Android-changed: only support GregorianCalendar here
+        return new GregorianCalendar(zone, aLocale);
+        // END Android-changed: only support GregorianCalendar here
+    }
+
+    /**
+     * Returns an array of all locales for which the <code>getInstance</code>
+     * methods of this class can return localized instances.
+     * The array returned must contain at least a <code>Locale</code>
+     * instance equal to {@link java.util.Locale#US Locale.US}.
+     *
+     * @return An array of locales for which localized
+     *         <code>Calendar</code> instances are available.
+     */
+    public static synchronized Locale[] getAvailableLocales()
+    {
+        return DateFormat.getAvailableLocales();
+    }
+
+    /**
+     * Converts the current calendar field values in {@link #fields fields[]}
+     * to the millisecond time value
+     * {@link #time}.
+     *
+     * @see #complete()
+     * @see #computeFields()
+     */
+    protected abstract void computeTime();
+
+    /**
+     * Converts the current millisecond time value {@link #time}
+     * to calendar field values in {@link #fields fields[]}.
+     * This allows you to sync up the calendar field values with
+     * a new time that is set for the calendar.  The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * {@link #complete()} method.
+     *
+     * @see #computeTime()
+     */
+    protected abstract void computeFields();
+
+    /**
+     * Returns a <code>Date</code> object representing this
+     * <code>Calendar</code>'s time value (millisecond offset from the <a
+     * href="#Epoch">Epoch</a>").
+     *
+     * @return a <code>Date</code> representing the time value.
+     * @see #setTime(Date)
+     * @see #getTimeInMillis()
+     */
+    public final Date getTime() {
+        return new Date(getTimeInMillis());
+    }
+
+    /**
+     * Sets this Calendar's time with the given <code>Date</code>.
+     * <p>
+     * Note: Calling <code>setTime()</code> with
+     * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
+     * may yield incorrect field values from <code>get()</code>.
+     *
+     * @param date the given Date.
+     * @see #getTime()
+     * @see #setTimeInMillis(long)
+     */
+    public final void setTime(Date date) {
+        setTimeInMillis(date.getTime());
+    }
+
+    /**
+     * Returns this Calendar's time value in milliseconds.
+     *
+     * @return the current time as UTC milliseconds from the epoch.
+     * @see #getTime()
+     * @see #setTimeInMillis(long)
+     */
+    public long getTimeInMillis() {
+        if (!isTimeSet) {
+            updateTime();
+        }
+        return time;
+    }
+
+    /**
+     * Sets this Calendar's current time from the given long value.
+     *
+     * @param millis the new time in UTC milliseconds from the epoch.
+     * @see #setTime(Date)
+     * @see #getTimeInMillis()
+     */
+    public void setTimeInMillis(long millis) {
+        // If we don't need to recalculate the calendar field values,
+        // do nothing.
+// BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+//        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
+//            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
+        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) {
+// END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+
+            return;
+        }
+        time = millis;
+        isTimeSet = true;
+        areFieldsSet = false;
+        computeFields();
+        areAllFieldsSet = areFieldsSet = true;
+    }
+
+    /**
+     * Returns the value of the given calendar field. In lenient mode,
+     * all calendar fields are normalized. In non-lenient mode, all
+     * calendar fields are validated and this method throws an
+     * exception if any calendar fields have out-of-range values. The
+     * normalization and validation are handled by the
+     * {@link #complete()} method, which process is calendar
+     * system dependent.
+     *
+     * @param field the given calendar field.
+     * @return the value for the given calendar field.
+     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #set(int,int)
+     * @see #complete()
+     */
+    public int get(int field)
+    {
+        complete();
+        return internalGet(field);
+    }
+
+    /**
+     * Returns the value of the given calendar field. This method does
+     * not involve normalization or validation of the field value.
+     *
+     * @param field the given calendar field.
+     * @return the value for the given calendar field.
+     * @see #get(int)
+     */
+    protected final int internalGet(int field)
+    {
+        return fields[field];
+    }
+
+    /**
+     * Sets the value of the given calendar field. This method does
+     * not affect any setting state of the field in this
+     * <code>Calendar</code> instance.
+     *
+     * @throws IndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #areFieldsSet
+     * @see #isTimeSet
+     * @see #areAllFieldsSet
+     * @see #set(int,int)
+     */
+    final void internalSet(int field, int value)
+    {
+        fields[field] = value;
+    }
+
+    /**
+     * Sets the given calendar field to the given value. The value is not
+     * interpreted by this method regardless of the leniency mode.
+     *
+     * @param field the given calendar field.
+     * @param value the value to be set for the given calendar field.
+     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
+     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * in non-lenient mode.
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     * @see #get(int)
+     */
+    public void set(int field, int value)
+    {
+        // If the fields are partially normalized, calculate all the
+        // fields before changing any fields.
+        if (areFieldsSet && !areAllFieldsSet) {
+            computeFields();
+        }
+        internalSet(field, value);
+        isTimeSet = false;
+        areFieldsSet = false;
+        isSet[field] = true;
+        stamp[field] = nextStamp++;
+        if (nextStamp == Integer.MAX_VALUE) {
+            adjustStamp();
+        }
+    }
+
+    /**
+     * Sets the values for the calendar fields <code>YEAR</code>,
+     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
+     * Previous values of other calendar fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field.
+     * @param month the value used to set the <code>MONTH</code> calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+    }
+
+    /**
+     * Sets the values for the calendar fields <code>YEAR</code>,
+     * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
+     * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
+     * Previous values of other fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field.
+     * @param month the value used to set the <code>MONTH</code> calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date, int hourOfDay, int minute)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+        set(HOUR_OF_DAY, hourOfDay);
+        set(MINUTE, minute);
+    }
+
+    /**
+     * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
+     * <code>DAY_OF_MONTH</code>, <code>HOUR_OF_DAY</code>, <code>MINUTE</code>, and
+     * <code>SECOND</code>.
+     * Previous values of other fields are retained.  If this is not desired,
+     * call {@link #clear()} first.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field.
+     * @param month the value used to set the <code>MONTH</code> calendar field.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field.
+     * @param second the value used to set the <code>SECOND</code> calendar field.
+     * @see #set(int,int)
+     * @see #set(int,int,int)
+     * @see #set(int,int,int,int,int)
+     */
+    public final void set(int year, int month, int date, int hourOfDay, int minute,
+                          int second)
+    {
+        set(YEAR, year);
+        set(MONTH, month);
+        set(DATE, date);
+        set(HOUR_OF_DAY, hourOfDay);
+        set(MINUTE, minute);
+        set(SECOND, second);
+    }
+
+    /**
+     * Sets all the calendar field values and the time value
+     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
+     * this <code>Calendar</code> undefined. This means that {@link
+     * #isSet(int) isSet()} will return <code>false</code> for all the
+     * calendar fields, and the date and time calculations will treat
+     * the fields as if they had never been set. A
+     * <code>Calendar</code> implementation class may use its specific
+     * default field values for date/time calculations. For example,
+     * <code>GregorianCalendar</code> uses 1970 if the
+     * <code>YEAR</code> field value is undefined.
+     *
+     * @see #clear(int)
+     */
+    public final void clear()
+    {
+        for (int i = 0; i < fields.length; ) {
+            stamp[i] = fields[i] = 0; // UNSET == 0
+            isSet[i++] = false;
+        }
+        areAllFieldsSet = areFieldsSet = false;
+        isTimeSet = false;
+    }
+
+    /**
+     * Sets the given calendar field value and the time value
+     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
+     * this <code>Calendar</code> undefined. This means that {@link
+     * #isSet(int) isSet(field)} will return <code>false</code>, and
+     * the date and time calculations will treat the field as if it
+     * had never been set. A <code>Calendar</code> implementation
+     * class may use the field's specific default value for date and
+     * time calculations.
+     *
+     * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
+     * fields are handled independently and the <a
+     * href="#time_resolution">the resolution rule for the time of
+     * day</a> is applied. Clearing one of the fields doesn't reset
+     * the hour of day value of this <code>Calendar</code>. Use {@link
+     * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
+     * value.
+     *
+     * @param field the calendar field to be cleared.
+     * @see #clear()
+     */
+    public final void clear(int field)
+    {
+        fields[field] = 0;
+        stamp[field] = UNSET;
+        isSet[field] = false;
+
+        areAllFieldsSet = areFieldsSet = false;
+        isTimeSet = false;
+    }
+
+    /**
+     * Determines if the given calendar field has a value set,
+     * including cases that the value has been set by internal fields
+     * calculations triggered by a <code>get</code> method call.
+     *
+     * @param field the calendar field to test
+     * @return <code>true</code> if the given calendar field has a value set;
+     * <code>false</code> otherwise.
+     */
+    public final boolean isSet(int field)
+    {
+        return stamp[field] != UNSET;
+    }
+
+    /**
+     * Returns the string representation of the calendar
+     * <code>field</code> value in the given <code>style</code> and
+     * <code>locale</code>.  If no string representation is
+     * applicable, <code>null</code> is returned. This method calls
+     * {@link Calendar#get(int) get(field)} to get the calendar
+     * <code>field</code> value if the string representation is
+     * applicable to the given calendar <code>field</code>.
+     *
+     * <p>For example, if this <code>Calendar</code> is a
+     * <code>GregorianCalendar</code> and its date is 2005-01-01, then
+     * the string representation of the {@link #MONTH} field would be
+     * "January" in the long style in an English locale or "Jan" in
+     * the short style. However, no string representation would be
+     * available for the {@link #DAY_OF_MONTH} field, and this method
+     * would return <code>null</code>.
+     *
+     * <p>The default implementation supports the calendar fields for
+     * which a {@link DateFormatSymbols} has names in the given
+     * <code>locale</code>.
+     *
+     * @param field
+     *        the calendar field for which the string representation
+     *        is returned
+     * @param style
+     *        the style applied to the string representation; one of {@link
+     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
+     *        {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
+     *        {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}.
+     * @param locale
+     *        the locale for the string representation
+     *        (any calendar types specified by {@code locale} are ignored)
+     * @return the string representation of the given
+     *        {@code field} in the given {@code style}, or
+     *        {@code null} if no string representation is
+     *        applicable.
+     * @exception IllegalArgumentException
+     *        if {@code field} or {@code style} is invalid,
+     *        or if this {@code Calendar} is non-lenient and any
+     *        of the calendar fields have invalid values
+     * @exception NullPointerException
+     *        if {@code locale} is null
+     * @since 1.6
+     */
+    public String getDisplayName(int field, int style, Locale locale) {
+        // BEGIN Android-changed: Treat ALL_STYLES as SHORT
+        // Android has traditionally treated ALL_STYLES as SHORT, even though
+        // it's not documented to be a valid value for style.
+        if (style == ALL_STYLES) {
+            style = SHORT;
+        }
+        // END Android-changed: Treat ALL_STYLES as SHORT
+        if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
+                            ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+
+        String calendarType = getCalendarType();
+        int fieldValue = get(field);
+        // the standalone and narrow styles are supported only through CalendarDataProviders.
+        if (isStandaloneStyle(style) || isNarrowFormatStyle(style)) {
+            String val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                    field, fieldValue,
+                                                                    style, locale);
+            // Perform fallback here to follow the CLDR rules
+            if (val == null) {
+                if (isNarrowFormatStyle(style)) {
+                    val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                     field, fieldValue,
+                                                                     toStandaloneStyle(style),
+                                                                     locale);
+                } else if (isStandaloneStyle(style)) {
+                    val = CalendarDataUtility.retrieveFieldValueName(calendarType,
+                                                                     field, fieldValue,
+                                                                     getBaseStyle(style),
+                                                                     locale);
+                }
+            }
+            return val;
+        }
+
+        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
+        String[] strings = getFieldStrings(field, style, symbols);
+        if (strings != null) {
+            if (fieldValue < strings.length) {
+                return strings[fieldValue];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a {@code Map} containing all names of the calendar
+     * {@code field} in the given {@code style} and
+     * {@code locale} and their corresponding field values. For
+     * example, if this {@code Calendar} is a {@link
+     * GregorianCalendar}, the returned map would contain "Jan" to
+     * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
+     * {@linkplain #SHORT short} style in an English locale.
+     *
+     * <p>Narrow names may not be unique due to use of single characters,
+     * such as "S" for Sunday and Saturday. In that case narrow names are not
+     * included in the returned {@code Map}.
+     *
+     * <p>The values of other calendar fields may be taken into
+     * account to determine a set of display names. For example, if
+     * this {@code Calendar} is a lunisolar calendar system and
+     * the year value given by the {@link #YEAR} field has a leap
+     * month, this method would return month names containing the leap
+     * month name, and month names are mapped to their values specific
+     * for the year.
+     *
+     * <p>The default implementation supports display names contained in
+     * a {@link DateFormatSymbols}. For example, if {@code field}
+     * is {@link #MONTH} and {@code style} is {@link
+     * #ALL_STYLES}, this method returns a {@code Map} containing
+     * all strings returned by {@link DateFormatSymbols#getShortMonths()}
+     * and {@link DateFormatSymbols#getMonths()}.
+     *
+     * @param field
+     *        the calendar field for which the display names are returned
+     * @param style
+     *        the style applied to the string representation; one of {@link
+     *        #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE},
+     *        {@link #LONG_FORMAT} ({@link #LONG}), {@link #LONG_STANDALONE},
+     *        {@link #NARROW_FORMAT}, or {@link #NARROW_STANDALONE}
+     * @param locale
+     *        the locale for the display names
+     * @return a {@code Map} containing all display names in
+     *        {@code style} and {@code locale} and their
+     *        field values, or {@code null} if no display names
+     *        are defined for {@code field}
+     * @exception IllegalArgumentException
+     *        if {@code field} or {@code style} is invalid,
+     *        or if this {@code Calendar} is non-lenient and any
+     *        of the calendar fields have invalid values
+     * @exception NullPointerException
+     *        if {@code locale} is null
+     * @since 1.6
+     */
+    public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
+                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+        // Android-added: Add complete() here to fix leniency, see http://b/35382060
+        complete();
+
+        String calendarType = getCalendarType();
+        if (style == ALL_STYLES || isStandaloneStyle(style) || isNarrowFormatStyle(style)) {
+            Map<String, Integer> map;
+            map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field, style, locale);
+
+            // Perform fallback here to follow the CLDR rules
+            if (map == null) {
+                if (isNarrowFormatStyle(style)) {
+                    map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
+                                                                      toStandaloneStyle(style), locale);
+                } else if (style != ALL_STYLES) {
+                    map = CalendarDataUtility.retrieveFieldValueNames(calendarType, field,
+                                                                      getBaseStyle(style), locale);
+                }
+            }
+            return map;
+        }
+
+        // SHORT or LONG
+        return getDisplayNamesImpl(field, style, locale);
+    }
+
+    private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
+        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
+        String[] strings = getFieldStrings(field, style, symbols);
+        if (strings != null) {
+            Map<String,Integer> names = new HashMap<>();
+            for (int i = 0; i < strings.length; i++) {
+                if (strings[i].length() == 0) {
+                    continue;
+                }
+                names.put(strings[i], i);
+            }
+            return names;
+        }
+        return null;
+    }
+
+    boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
+                                   Locale locale, int fieldMask) {
+        int baseStyle = getBaseStyle(style); // Ignore the standalone mask
+        if (field < 0 || field >= fields.length ||
+            baseStyle < minStyle || baseStyle > maxStyle) {
+            throw new IllegalArgumentException();
+        }
+        // BEGIN Android-added: Check for invalid baseStyle == 3
+        // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used.
+        if (baseStyle == 3) {
+            throw new IllegalArgumentException();
+        }
+        // END Android-added: Check for invalid baseStyle == 3
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        return isFieldSet(fieldMask, field);
+    }
+
+    private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
+        int baseStyle = getBaseStyle(style); // ignore the standalone mask
+
+        // DateFormatSymbols doesn't support any narrow names.
+        if (baseStyle == NARROW_FORMAT) {
+            return null;
+        }
+
+        String[] strings = null;
+        switch (field) {
+        case ERA:
+            strings = symbols.getEras();
+            break;
+
+        case MONTH:
+            strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths();
+            break;
+
+        case DAY_OF_WEEK:
+            strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
+            break;
+
+        case AM_PM:
+            strings = symbols.getAmPmStrings();
+            break;
+        }
+        return strings;
+    }
+
+    /**
+     * Fills in any unset fields in the calendar fields. First, the {@link
+     * #computeTime()} method is called if the time value (millisecond offset
+     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
+     * calendar field values. Then, the {@link #computeFields()} method is
+     * called to calculate all calendar field values.
+     */
+    protected void complete()
+    {
+        if (!isTimeSet) {
+            updateTime();
+        }
+        if (!areFieldsSet || !areAllFieldsSet) {
+            computeFields(); // fills in unset fields
+            areAllFieldsSet = areFieldsSet = true;
+        }
+    }
+
+    /**
+     * Returns whether the value of the specified calendar field has been set
+     * externally by calling one of the setter methods rather than by the
+     * internal time calculation.
+     *
+     * @return <code>true</code> if the field has been set externally,
+     * <code>false</code> otherwise.
+     * @exception IndexOutOfBoundsException if the specified
+     *                <code>field</code> is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #selectFields()
+     * @see #setFieldsComputed(int)
+     */
+    final boolean isExternallySet(int field) {
+        return stamp[field] >= MINIMUM_USER_STAMP;
+    }
+
+    /**
+     * Returns a field mask (bit mask) indicating all calendar fields that
+     * have the state of externally or internally set.
+     *
+     * @return a bit mask indicating set state fields
+     */
+    final int getSetStateFields() {
+        int mask = 0;
+        for (int i = 0; i < fields.length; i++) {
+            if (stamp[i] != UNSET) {
+                mask |= 1 << i;
+            }
+        }
+        return mask;
+    }
+
+    /**
+     * Sets the state of the specified calendar fields to
+     * <em>computed</em>. This state means that the specified calendar fields
+     * have valid values that have been set by internal time calculation
+     * rather than by calling one of the setter methods.
+     *
+     * @param fieldMask the field to be marked as computed.
+     * @exception IndexOutOfBoundsException if the specified
+     *                <code>field</code> is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #isExternallySet(int)
+     * @see #selectFields()
+     */
+    final void setFieldsComputed(int fieldMask) {
+        if (fieldMask == ALL_FIELDS) {
+            for (int i = 0; i < fields.length; i++) {
+                stamp[i] = COMPUTED;
+                isSet[i] = true;
+            }
+            areFieldsSet = areAllFieldsSet = true;
+        } else {
+            for (int i = 0; i < fields.length; i++) {
+                if ((fieldMask & 1) == 1) {
+                    stamp[i] = COMPUTED;
+                    isSet[i] = true;
+                } else {
+                    if (areAllFieldsSet && !isSet[i]) {
+                        areAllFieldsSet = false;
+                    }
+                }
+                fieldMask >>>= 1;
+            }
+        }
+    }
+
+    /**
+     * Sets the state of the calendar fields that are <em>not</em> specified
+     * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
+     * specifies all the calendar fields, then the state of this
+     * <code>Calendar</code> becomes that all the calendar fields are in sync
+     * with the time value (millisecond offset from the Epoch).
+     *
+     * @param fieldMask the field mask indicating which calendar fields are in
+     * sync with the time value.
+     * @exception IndexOutOfBoundsException if the specified
+     *                <code>field</code> is out of range
+     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
+     * @see #isExternallySet(int)
+     * @see #selectFields()
+     */
+    final void setFieldsNormalized(int fieldMask) {
+        if (fieldMask != ALL_FIELDS) {
+            for (int i = 0; i < fields.length; i++) {
+                if ((fieldMask & 1) == 0) {
+                    stamp[i] = fields[i] = 0; // UNSET == 0
+                    isSet[i] = false;
+                }
+                fieldMask >>= 1;
+            }
+        }
+
+        // Some or all of the fields are in sync with the
+        // milliseconds, but the stamp values are not normalized yet.
+        areFieldsSet = true;
+        areAllFieldsSet = false;
+    }
+
+    /**
+     * Returns whether the calendar fields are partially in sync with the time
+     * value or fully in sync but not stamp values are not normalized yet.
+     */
+    final boolean isPartiallyNormalized() {
+        return areFieldsSet && !areAllFieldsSet;
+    }
+
+    /**
+     * Returns whether the calendar fields are fully in sync with the time
+     * value.
+     */
+    final boolean isFullyNormalized() {
+        return areFieldsSet && areAllFieldsSet;
+    }
+
+    /**
+     * Marks this Calendar as not sync'd.
+     */
+    final void setUnnormalized() {
+        areFieldsSet = areAllFieldsSet = false;
+    }
+
+    /**
+     * Returns whether the specified <code>field</code> is on in the
+     * <code>fieldMask</code>.
+     */
+    static boolean isFieldSet(int fieldMask, int field) {
+        return (fieldMask & (1 << field)) != 0;
+    }
+
+    /**
+     * Returns a field mask indicating which calendar field values
+     * to be used to calculate the time value. The calendar fields are
+     * returned as a bit mask, each bit of which corresponds to a field, i.e.,
+     * the mask value of <code>field</code> is <code>(1 &lt;&lt;
+     * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
+     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
+     * equal to
+     * <code>(1&lt;&lt;YEAR)|(1&lt;&lt;MONTH)|(1&lt;&lt;DAY_OF_MONTH))</code>.
+     *
+     * <p>This method supports the calendar fields resolution as described in
+     * the class description. If the bit mask for a given field is on and its
+     * field has not been set (i.e., <code>isSet(field)</code> is
+     * <code>false</code>), then the default value of the field has to be
+     * used, which case means that the field has been selected because the
+     * selected combination involves the field.
+     *
+     * @return a bit mask of selected fields
+     * @see #isExternallySet(int)
+     */
+    final int selectFields() {
+        // This implementation has been taken from the GregorianCalendar class.
+
+        // The YEAR field must always be used regardless of its SET
+        // state because YEAR is a mandatory field to determine the date
+        // and the default value (EPOCH_YEAR) may change through the
+        // normalization process.
+        int fieldMask = YEAR_MASK;
+
+        if (stamp[ERA] != UNSET) {
+            fieldMask |= ERA_MASK;
+        }
+        // Find the most recent group of fields specifying the day within
+        // the year.  These may be any of the following combinations:
+        //   MONTH + DAY_OF_MONTH
+        //   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+        //   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+        //   DAY_OF_YEAR
+        //   WEEK_OF_YEAR + DAY_OF_WEEK
+        // We look for the most recent of the fields in each group to determine
+        // the age of the group.  For groups involving a week-related field such
+        // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
+        // week-related field and the DAY_OF_WEEK must be set for the group as a
+        // whole to be considered.  (See bug 4153860 - liu 7/24/98.)
+        int dowStamp = stamp[DAY_OF_WEEK];
+        int monthStamp = stamp[MONTH];
+        int domStamp = stamp[DAY_OF_MONTH];
+        int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
+        int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
+        int doyStamp = stamp[DAY_OF_YEAR];
+        int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
+
+        int bestStamp = domStamp;
+        if (womStamp > bestStamp) {
+            bestStamp = womStamp;
+        }
+        if (dowimStamp > bestStamp) {
+            bestStamp = dowimStamp;
+        }
+        if (doyStamp > bestStamp) {
+            bestStamp = doyStamp;
+        }
+        if (woyStamp > bestStamp) {
+            bestStamp = woyStamp;
+        }
+
+        /* No complete combination exists.  Look for WEEK_OF_MONTH,
+         * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone.  Treat DAY_OF_WEEK alone
+         * as DAY_OF_WEEK_IN_MONTH.
+         */
+        if (bestStamp == UNSET) {
+            womStamp = stamp[WEEK_OF_MONTH];
+            dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
+            woyStamp = stamp[WEEK_OF_YEAR];
+            bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
+
+            /* Treat MONTH alone or no fields at all as DAY_OF_MONTH.  This may
+             * result in bestStamp = domStamp = UNSET if no fields are set,
+             * which indicates DAY_OF_MONTH.
+             */
+            if (bestStamp == UNSET) {
+                bestStamp = domStamp = monthStamp;
+            }
+        }
+
+        if (bestStamp == domStamp ||
+           (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
+           (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
+            fieldMask |= MONTH_MASK;
+            if (bestStamp == domStamp) {
+                fieldMask |= DAY_OF_MONTH_MASK;
+            } else {
+                assert (bestStamp == womStamp || bestStamp == dowimStamp);
+                if (dowStamp != UNSET) {
+                    fieldMask |= DAY_OF_WEEK_MASK;
+                }
+                if (womStamp == dowimStamp) {
+                    // When they are equal, give the priority to
+                    // WEEK_OF_MONTH for compatibility.
+                    if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
+                        fieldMask |= WEEK_OF_MONTH_MASK;
+                    } else {
+                        fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
+                    }
+                } else {
+                    if (bestStamp == womStamp) {
+                        fieldMask |= WEEK_OF_MONTH_MASK;
+                    } else {
+                        assert (bestStamp == dowimStamp);
+                        if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
+                            fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
+                        }
+                    }
+                }
+            }
+        } else {
+            assert (bestStamp == doyStamp || bestStamp == woyStamp ||
+                    bestStamp == UNSET);
+            if (bestStamp == doyStamp) {
+                fieldMask |= DAY_OF_YEAR_MASK;
+            } else {
+                assert (bestStamp == woyStamp);
+                if (dowStamp != UNSET) {
+                    fieldMask |= DAY_OF_WEEK_MASK;
+                }
+                fieldMask |= WEEK_OF_YEAR_MASK;
+            }
+        }
+
+        // Find the best set of fields specifying the time of day.  There
+        // are only two possibilities here; the HOUR_OF_DAY or the
+        // AM_PM and the HOUR.
+        int hourOfDayStamp = stamp[HOUR_OF_DAY];
+        int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
+        bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
+
+        // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
+        if (bestStamp == UNSET) {
+            bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
+        }
+
+        // Hours
+        if (bestStamp != UNSET) {
+            if (bestStamp == hourOfDayStamp) {
+                fieldMask |= HOUR_OF_DAY_MASK;
+            } else {
+                fieldMask |= HOUR_MASK;
+                if (stamp[AM_PM] != UNSET) {
+                    fieldMask |= AM_PM_MASK;
+                }
+            }
+        }
+        if (stamp[MINUTE] != UNSET) {
+            fieldMask |= MINUTE_MASK;
+        }
+        if (stamp[SECOND] != UNSET) {
+            fieldMask |= SECOND_MASK;
+        }
+        if (stamp[MILLISECOND] != UNSET) {
+            fieldMask |= MILLISECOND_MASK;
+        }
+        if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
+                fieldMask |= ZONE_OFFSET_MASK;
+        }
+        if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
+            fieldMask |= DST_OFFSET_MASK;
+        }
+
+        return fieldMask;
+    }
+
+    int getBaseStyle(int style) {
+        return style & ~STANDALONE_MASK;
+    }
+
+    // BEGIN Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat
+    /**
+     * @hide
+     */
+    public static int toStandaloneStyle(int style) {
+    // END Android-changed: Make toStandaloneStyle() public to use in java.text.SimpleDateFormat
+        return style | STANDALONE_MASK;
+    }
+
+    private boolean isStandaloneStyle(int style) {
+        return (style & STANDALONE_MASK) != 0;
+    }
+
+    private boolean isNarrowStyle(int style) {
+        return style == NARROW_FORMAT || style == NARROW_STANDALONE;
+    }
+
+    private boolean isNarrowFormatStyle(int style) {
+        return style == NARROW_FORMAT;
+    }
+
+    /**
+     * Returns the pseudo-time-stamp for two fields, given their
+     * individual pseudo-time-stamps.  If either of the fields
+     * is unset, then the aggregate is unset.  Otherwise, the
+     * aggregate is the later of the two stamps.
+     */
+    private static int aggregateStamp(int stamp_a, int stamp_b) {
+        if (stamp_a == UNSET || stamp_b == UNSET) {
+            return UNSET;
+        }
+        return (stamp_a > stamp_b) ? stamp_a : stamp_b;
+    }
+
+    /**
+     * Returns an unmodifiable {@code Set} containing all calendar types
+     * supported by {@code Calendar} in the runtime environment. The available
+     * calendar types can be used for the <a
+     * href="Locale.html#def_locale_extension">Unicode locale extensions</a>.
+     * The {@code Set} returned contains at least {@code "gregory"}. The
+     * calendar types don't include aliases, such as {@code "gregorian"} for
+     * {@code "gregory"}.
+     *
+     * @return an unmodifiable {@code Set} containing all available calendar types
+     * @since 1.8
+     * @see #getCalendarType()
+     * @see Calendar.Builder#setCalendarType(String)
+     * @see Locale#getUnicodeLocaleType(String)
+     */
+    public static Set<String> getAvailableCalendarTypes() {
+        return AvailableCalendarTypes.SET;
+    }
+
+    private static class AvailableCalendarTypes {
+        private static final Set<String> SET;
+        static {
+            Set<String> set = new HashSet<>(3);
+            set.add("gregory");
+            // Android-changed: removed "buddhist" and "japanese".
+            // set.add("buddhist");
+            // set.add("japanese");
+            SET = Collections.unmodifiableSet(set);
+        }
+        private AvailableCalendarTypes() {
+        }
+    }
+
+    /**
+     * Returns the calendar type of this {@code Calendar}. Calendar types are
+     * defined by the <em>Unicode Locale Data Markup Language (LDML)</em>
+     * specification.
+     *
+     * <p>The default implementation of this method returns the class name of
+     * this {@code Calendar} instance. Any subclasses that implement
+     * LDML-defined calendar systems should override this method to return
+     * appropriate calendar types.
+     *
+     * @return the LDML-defined calendar type or the class name of this
+     *         {@code Calendar} instance
+     * @since 1.8
+     * @see <a href="Locale.html#def_extensions">Locale extensions</a>
+     * @see Locale.Builder#setLocale(Locale)
+     * @see Locale.Builder#setUnicodeLocaleKeyword(String, String)
+     */
+    public String getCalendarType() {
+        return this.getClass().getName();
+    }
+
+    /**
+     * Compares this <code>Calendar</code> to the specified
+     * <code>Object</code>.  The result is <code>true</code> if and only if
+     * the argument is a <code>Calendar</code> object of the same calendar
+     * system that represents the same time value (millisecond offset from the
+     * <a href="#Epoch">Epoch</a>) under the same
+     * <code>Calendar</code> parameters as this object.
+     *
+     * <p>The <code>Calendar</code> parameters are the values represented
+     * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
+     * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
+     * methods. If there is any difference in those parameters
+     * between the two <code>Calendar</code>s, this method returns
+     * <code>false</code>.
+     *
+     * <p>Use the {@link #compareTo(Calendar) compareTo} method to
+     * compare only the time values.
+     *
+     * @param obj the object to compare with.
+     * @return <code>true</code> if this object is equal to <code>obj</code>;
+     * <code>false</code> otherwise.
+     */
+    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        try {
+            Calendar that = (Calendar)obj;
+            return compareTo(getMillisOf(that)) == 0 &&
+                lenient == that.lenient &&
+                firstDayOfWeek == that.firstDayOfWeek &&
+                minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
+                zone.equals(that.zone);
+        } catch (Exception e) {
+            // Note: GregorianCalendar.computeTime throws
+            // IllegalArgumentException if the ERA value is invalid
+            // even it's in lenient mode.
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code for this calendar.
+     *
+     * @return a hash code value for this object.
+     * @since 1.2
+     */
+    @Override
+    public int hashCode() {
+        // 'otheritems' represents the hash code for the previous versions.
+        int otheritems = (lenient ? 1 : 0)
+            | (firstDayOfWeek << 1)
+            | (minimalDaysInFirstWeek << 4)
+            | (zone.hashCode() << 7);
+        long t = getMillisOf(this);
+        return (int) t ^ (int)(t >> 32) ^ otheritems;
+    }
+
+    /**
+     * Returns whether this <code>Calendar</code> represents a time
+     * before the time represented by the specified
+     * <code>Object</code>. This method is equivalent to:
+     * <pre>{@code
+     *         compareTo(when) < 0
+     * }</pre>
+     * if and only if <code>when</code> is a <code>Calendar</code>
+     * instance. Otherwise, the method returns <code>false</code>.
+     *
+     * @param when the <code>Object</code> to be compared
+     * @return <code>true</code> if the time of this
+     * <code>Calendar</code> is before the time represented by
+     * <code>when</code>; <code>false</code> otherwise.
+     * @see     #compareTo(Calendar)
+     */
+    public boolean before(Object when) {
+        return when instanceof Calendar
+            && compareTo((Calendar)when) < 0;
+    }
+
+    /**
+     * Returns whether this <code>Calendar</code> represents a time
+     * after the time represented by the specified
+     * <code>Object</code>. This method is equivalent to:
+     * <pre>{@code
+     *         compareTo(when) > 0
+     * }</pre>
+     * if and only if <code>when</code> is a <code>Calendar</code>
+     * instance. Otherwise, the method returns <code>false</code>.
+     *
+     * @param when the <code>Object</code> to be compared
+     * @return <code>true</code> if the time of this <code>Calendar</code> is
+     * after the time represented by <code>when</code>; <code>false</code>
+     * otherwise.
+     * @see     #compareTo(Calendar)
+     */
+    public boolean after(Object when) {
+        return when instanceof Calendar
+            && compareTo((Calendar)when) > 0;
+    }
+
+    /**
+     * Compares the time values (millisecond offsets from the <a
+     * href="#Epoch">Epoch</a>) represented by two
+     * <code>Calendar</code> objects.
+     *
+     * @param anotherCalendar the <code>Calendar</code> to be compared.
+     * @return the value <code>0</code> if the time represented by the argument
+     * is equal to the time represented by this <code>Calendar</code>; a value
+     * less than <code>0</code> if the time of this <code>Calendar</code> is
+     * before the time represented by the argument; and a value greater than
+     * <code>0</code> if the time of this <code>Calendar</code> is after the
+     * time represented by the argument.
+     * @exception NullPointerException if the specified <code>Calendar</code> is
+     *            <code>null</code>.
+     * @exception IllegalArgumentException if the time value of the
+     * specified <code>Calendar</code> object can't be obtained due to
+     * any invalid calendar values.
+     * @since   1.5
+     */
+    @Override
+    public int compareTo(Calendar anotherCalendar) {
+        return compareTo(getMillisOf(anotherCalendar));
+    }
+
+    /**
+     * Adds or subtracts the specified amount of time to the given calendar field,
+     * based on the calendar's rules. For example, to subtract 5 days from
+     * the current time of the calendar, you can achieve it by calling:
+     * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @see #roll(int,int)
+     * @see #set(int,int)
+     */
+    abstract public void add(int field, int amount);
+
+    /**
+     * Adds or subtracts (up/down) a single unit of time on the given time
+     * field without changing larger fields. For example, to roll the current
+     * date up by one day, you can achieve it by calling:
+     * <p>roll(Calendar.DATE, true).
+     * When rolling on the year or Calendar.YEAR field, it will roll the year
+     * value in the range between 1 and the value returned by calling
+     * <code>getMaximum(Calendar.YEAR)</code>.
+     * When rolling on the month or Calendar.MONTH field, other fields like
+     * date might conflict and, need to be changed. For instance,
+     * rolling the month on the date 01/31/96 will result in 02/29/96.
+     * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
+     * roll the hour value in the range between 0 and 23, which is zero-based.
+     *
+     * @param field the time field.
+     * @param up indicates if the value of the specified time field is to be
+     * rolled up or rolled down. Use true if rolling up, false otherwise.
+     * @see Calendar#add(int,int)
+     * @see Calendar#set(int,int)
+     */
+    abstract public void roll(int field, boolean up);
+
+    /**
+     * Adds the specified (signed) amount to the specified calendar field
+     * without changing larger fields.  A negative amount means to roll
+     * down.
+     *
+     * <p>NOTE:  This default implementation on <code>Calendar</code> just repeatedly calls the
+     * version of {@link #roll(int,boolean) roll()} that rolls by one unit.  This may not
+     * always do the right thing.  For example, if the <code>DAY_OF_MONTH</code> field is 31,
+     * rolling through February will leave it set to 28.  The <code>GregorianCalendar</code>
+     * version of this function takes care of this problem.  Other subclasses
+     * should also provide overrides of this function that do the right thing.
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to the calendar <code>field</code>.
+     * @since 1.2
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    public void roll(int field, int amount)
+    {
+        while (amount > 0) {
+            roll(field, true);
+            amount--;
+        }
+        while (amount < 0) {
+            roll(field, false);
+            amount++;
+        }
+    }
+
+    /**
+     * Sets the time zone with the given time zone value.
+     *
+     * @param value the given time zone.
+     */
+    public void setTimeZone(TimeZone value)
+    {
+        zone = value;
+        sharedZone = false;
+        /* Recompute the fields from the time using the new zone.  This also
+         * works if isTimeSet is false (after a call to set()).  In that case
+         * the time will be computed from the fields using the new zone, then
+         * the fields will get recomputed from that.  Consider the sequence of
+         * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
+         * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
+         * generally, a call to setTimeZone() affects calls to set() BEFORE AND
+         * AFTER it up to the next call to complete().
+         */
+        areAllFieldsSet = areFieldsSet = false;
+    }
+
+    /**
+     * Gets the time zone.
+     *
+     * @return the time zone object associated with this calendar.
+     */
+    public TimeZone getTimeZone()
+    {
+        // If the TimeZone object is shared by other Calendar instances, then
+        // create a clone.
+        if (sharedZone) {
+            zone = (TimeZone) zone.clone();
+            sharedZone = false;
+        }
+        return zone;
+    }
+
+    /**
+     * Returns the time zone (without cloning).
+     */
+    TimeZone getZone() {
+        return zone;
+    }
+
+    /**
+     * Sets the sharedZone flag to <code>shared</code>.
+     */
+    void setZoneShared(boolean shared) {
+        sharedZone = shared;
+    }
+
+    /**
+     * Specifies whether or not date/time interpretation is to be lenient.  With
+     * lenient interpretation, a date such as "February 942, 1996" will be
+     * treated as being equivalent to the 941st day after February 1, 1996.
+     * With strict (non-lenient) interpretation, such dates will cause an exception to be
+     * thrown. The default is lenient.
+     *
+     * @param lenient <code>true</code> if the lenient mode is to be turned
+     * on; <code>false</code> if it is to be turned off.
+     * @see #isLenient()
+     * @see java.text.DateFormat#setLenient
+     */
+    public void setLenient(boolean lenient)
+    {
+        this.lenient = lenient;
+    }
+
+    /**
+     * Tells whether date/time interpretation is to be lenient.
+     *
+     * @return <code>true</code> if the interpretation mode of this calendar is lenient;
+     * <code>false</code> otherwise.
+     * @see #setLenient(boolean)
+     */
+    public boolean isLenient()
+    {
+        return lenient;
+    }
+
+    /**
+     * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
+     * <code>MONDAY</code> in France.
+     *
+     * @param value the given first day of the week.
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public void setFirstDayOfWeek(int value)
+    {
+        if (firstDayOfWeek == value) {
+            return;
+        }
+        firstDayOfWeek = value;
+        invalidateWeekFields();
+    }
+
+    /**
+     * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
+     * <code>MONDAY</code> in France.
+     *
+     * @return the first day of the week.
+     * @see #setFirstDayOfWeek(int)
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public int getFirstDayOfWeek()
+    {
+        return firstDayOfWeek;
+    }
+
+    /**
+     * Sets what the minimal days required in the first week of the year are;
+     * For example, if the first week is defined as one that contains the first
+     * day of the first month of a year, call this method with value 1. If it
+     * must be a full week, use value 7.
+     *
+     * @param value the given minimal days required in the first week
+     * of the year.
+     * @see #getMinimalDaysInFirstWeek()
+     */
+    public void setMinimalDaysInFirstWeek(int value)
+    {
+        if (minimalDaysInFirstWeek == value) {
+            return;
+        }
+        minimalDaysInFirstWeek = value;
+        invalidateWeekFields();
+    }
+
+    /**
+     * Gets what the minimal days required in the first week of the year are;
+     * e.g., if the first week is defined as one that contains the first day
+     * of the first month of a year, this method returns 1. If
+     * the minimal days required must be a full week, this method
+     * returns 7.
+     *
+     * @return the minimal days required in the first week of the year.
+     * @see #setMinimalDaysInFirstWeek(int)
+     */
+    public int getMinimalDaysInFirstWeek()
+    {
+        return minimalDaysInFirstWeek;
+    }
+
+    /**
+     * Returns whether this {@code Calendar} supports week dates.
+     *
+     * <p>The default implementation of this method returns {@code false}.
+     *
+     * @return {@code true} if this {@code Calendar} supports week dates;
+     *         {@code false} otherwise.
+     * @see #getWeekYear()
+     * @see #setWeekDate(int,int,int)
+     * @see #getWeeksInWeekYear()
+     * @since 1.7
+     */
+    public boolean isWeekDateSupported() {
+        return false;
+    }
+
+    /**
+     * Returns the week year represented by this {@code Calendar}. The
+     * week year is in sync with the week cycle. The {@linkplain
+     * #getFirstDayOfWeek() first day of the first week} is the first
+     * day of the week year.
+     *
+     * <p>The default implementation of this method throws an
+     * {@link UnsupportedOperationException}.
+     *
+     * @return the week year of this {@code Calendar}
+     * @exception UnsupportedOperationException
+     *            if any week year numbering isn't supported
+     *            in this {@code Calendar}.
+     * @see #isWeekDateSupported()
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    public int getWeekYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Sets the date of this {@code Calendar} with the the given date
+     * specifiers - week year, week of year, and day of week.
+     *
+     * <p>Unlike the {@code set} method, all of the calendar fields
+     * and {@code time} values are calculated upon return.
+     *
+     * <p>If {@code weekOfYear} is out of the valid week-of-year range
+     * in {@code weekYear}, the {@code weekYear} and {@code
+     * weekOfYear} values are adjusted in lenient mode, or an {@code
+     * IllegalArgumentException} is thrown in non-lenient mode.
+     *
+     * <p>The default implementation of this method throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @param weekYear   the week year
+     * @param weekOfYear the week number based on {@code weekYear}
+     * @param dayOfWeek  the day of week value: one of the constants
+     *                   for the {@link #DAY_OF_WEEK} field: {@link
+     *                   #SUNDAY}, ..., {@link #SATURDAY}.
+     * @exception IllegalArgumentException
+     *            if any of the given date specifiers is invalid
+     *            or any of the calendar fields are inconsistent
+     *            with the given date specifiers in non-lenient mode
+     * @exception UnsupportedOperationException
+     *            if any week year numbering isn't supported in this
+     *            {@code Calendar}.
+     * @see #isWeekDateSupported()
+     * @see #getFirstDayOfWeek()
+     * @see #getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the number of weeks in the week year represented by this
+     * {@code Calendar}.
+     *
+     * <p>The default implementation of this method throws an
+     * {@code UnsupportedOperationException}.
+     *
+     * @return the number of weeks in the week year.
+     * @exception UnsupportedOperationException
+     *            if any week year numbering isn't supported in this
+     *            {@code Calendar}.
+     * @see #WEEK_OF_YEAR
+     * @see #isWeekDateSupported()
+     * @see #getWeekYear()
+     * @see #getActualMaximum(int)
+     * @since 1.7
+     */
+    public int getWeeksInWeekYear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * <code>Calendar</code> instance. The minimum value is defined as
+     * the smallest value returned by the {@link #get(int) get} method
+     * for any possible time value.  The minimum value depends on
+     * calendar system specific parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getMinimum(int field);
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * <code>Calendar</code> instance. The maximum value is defined as
+     * the largest value returned by the {@link #get(int) get} method
+     * for any possible time value. The maximum value depends on
+     * calendar system specific parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getMaximum(int field);
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this <code>Calendar</code> instance. The highest minimum
+     * value is defined as the largest value returned by {@link
+     * #getActualMinimum(int)} for any possible time value. The
+     * greatest minimum value depends on calendar system specific
+     * parameters of the instance.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getGreatestMinimum(int field);
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this <code>Calendar</code> instance. The lowest maximum
+     * value is defined as the smallest value returned by {@link
+     * #getActualMaximum(int)} for any possible time value. The least
+     * maximum value depends on calendar system specific parameters of
+     * the instance. For example, a <code>Calendar</code> for the
+     * Gregorian calendar system returns 28 for the
+     * <code>DAY_OF_MONTH</code> field, because the 28th is the last
+     * day of the shortest month of this calendar, February in a
+     * common year.
+     *
+     * @param field the calendar field.
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    abstract public int getLeastMaximum(int field);
+
+    /**
+     * Returns the minimum value that the specified calendar field
+     * could have, given the time value of this <code>Calendar</code>.
+     *
+     * <p>The default implementation of this method uses an iterative
+     * algorithm to determine the actual minimum value for the
+     * calendar field. Subclasses should, if possible, override this
+     * with a more efficient implementation - in many cases, they can
+     * simply return <code>getMinimum()</code>.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given calendar field for the time
+     * value of this <code>Calendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     * @since 1.2
+     */
+    public int getActualMinimum(int field) {
+        int fieldValue = getGreatestMinimum(field);
+        int endValue = getMinimum(field);
+
+        // if we know that the minimum value is always the same, just return it
+        if (fieldValue == endValue) {
+            return fieldValue;
+        }
+
+        // clone the calendar so we don't mess with the real one, and set it to
+        // accept anything for the field values
+        Calendar work = (Calendar)this.clone();
+        work.setLenient(true);
+
+        // now try each value from getLeastMaximum() to getMaximum() one by one until
+        // we get a value that normalizes to another value.  The last value that
+        // normalizes to itself is the actual minimum for the current date
+        int result = fieldValue;
+
+        do {
+            work.set(field, fieldValue);
+            if (work.get(field) != fieldValue) {
+                break;
+            } else {
+                result = fieldValue;
+                fieldValue--;
+            }
+        } while (fieldValue >= endValue);
+
+        return result;
+    }
+
+    /**
+     * Returns the maximum value that the specified calendar field
+     * could have, given the time value of this
+     * <code>Calendar</code>. For example, the actual maximum value of
+     * the <code>MONTH</code> field is 12 in some years, and 13 in
+     * other years in the Hebrew calendar system.
+     *
+     * <p>The default implementation of this method uses an iterative
+     * algorithm to determine the actual maximum value for the
+     * calendar field. Subclasses should, if possible, override this
+     * with a more efficient implementation.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given calendar field for the time
+     * value of this <code>Calendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @since 1.2
+     */
+    public int getActualMaximum(int field) {
+        int fieldValue = getLeastMaximum(field);
+        int endValue = getMaximum(field);
+
+        // if we know that the maximum value is always the same, just return it.
+        if (fieldValue == endValue) {
+            return fieldValue;
+        }
+
+        // clone the calendar so we don't mess with the real one, and set it to
+        // accept anything for the field values.
+        Calendar work = (Calendar)this.clone();
+        work.setLenient(true);
+
+        // if we're counting weeks, set the day of the week to Sunday.  We know the
+        // last week of a month or year will contain the first day of the week.
+        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) {
+            work.set(DAY_OF_WEEK, firstDayOfWeek);
+        }
+
+        // now try each value from getLeastMaximum() to getMaximum() one by one until
+        // we get a value that normalizes to another value.  The last value that
+        // normalizes to itself is the actual maximum for the current date
+        int result = fieldValue;
+
+        do {
+            work.set(field, fieldValue);
+            if (work.get(field) != fieldValue) {
+                break;
+            } else {
+                result = fieldValue;
+                fieldValue++;
+            }
+        } while (fieldValue <= endValue);
+
+        return result;
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     *
+     * @return a copy of this object.
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            Calendar other = (Calendar) super.clone();
+
+            other.fields = new int[FIELD_COUNT];
+            other.isSet = new boolean[FIELD_COUNT];
+            other.stamp = new int[FIELD_COUNT];
+            for (int i = 0; i < FIELD_COUNT; i++) {
+                other.fields[i] = fields[i];
+                other.stamp[i] = stamp[i];
+                other.isSet[i] = isSet[i];
+            }
+            other.zone = (TimeZone) zone.clone();
+            return other;
+        }
+        catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    private static final String[] FIELD_NAME = {
+        "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
+        "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
+        "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
+        "DST_OFFSET"
+    };
+
+    /**
+     * Returns the name of the specified calendar field.
+     *
+     * @param field the calendar field
+     * @return the calendar field name
+     * @exception IndexOutOfBoundsException if <code>field</code> is negative,
+     * equal to or greater then <code>FIELD_COUNT</code>.
+     */
+    static String getFieldName(int field) {
+        return FIELD_NAME[field];
+    }
+
+    /**
+     * Return a string representation of this calendar. This method
+     * is intended to be used only for debugging purposes, and the
+     * format of the returned string may vary between implementations.
+     * The returned string may be empty but may not be <code>null</code>.
+     *
+     * @return  a string representation of this calendar.
+     */
+    @Override
+    public String toString() {
+        // NOTE: BuddhistCalendar.toString() interprets the string
+        // produced by this method so that the Gregorian year number
+        // is substituted by its B.E. year value. It relies on
+        // "...,YEAR=<year>,..." or "...,YEAR=?,...".
+        StringBuilder buffer = new StringBuilder(800);
+        buffer.append(getClass().getName()).append('[');
+        appendValue(buffer, "time", isTimeSet, time);
+        buffer.append(",areFieldsSet=").append(areFieldsSet);
+        buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
+        buffer.append(",lenient=").append(lenient);
+        buffer.append(",zone=").append(zone);
+        appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
+        appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
+        for (int i = 0; i < FIELD_COUNT; ++i) {
+            buffer.append(',');
+            appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
+        }
+        buffer.append(']');
+        return buffer.toString();
+    }
+
+    // =======================privates===============================
+
+    private static void appendValue(StringBuilder sb, String item, boolean valid, long value) {
+        sb.append(item).append('=');
+        if (valid) {
+            sb.append(value);
+        } else {
+            sb.append('?');
+        }
+    }
+
+    /**
+     * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
+     * They are used to figure out the week count for a specific date for
+     * a given locale. These must be set when a Calendar is constructed.
+     * @param desiredLocale the given locale.
+     */
+    private void setWeekCountData(Locale desiredLocale)
+    {
+        /* try to get the Locale data from the cache */
+        int[] data = cachedLocaleData.get(desiredLocale);
+        if (data == null) {  /* cache miss */
+            data = new int[2];
+            // BEGIN Android-changed: Use ICU4C to get week data.
+            // data[0] = CalendarDataUtility.retrieveFirstDayOfWeek(desiredLocale);
+            // data[1] = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(desiredLocale);
+            LocaleData localeData = LocaleData.get(desiredLocale);
+            data[0] = localeData.firstDayOfWeek.intValue();
+            data[1] = localeData.minimalDaysInFirstWeek.intValue();
+            // END Android-changed: Use ICU4C to get week data.
+            cachedLocaleData.putIfAbsent(desiredLocale, data);
+        }
+        firstDayOfWeek = data[0];
+        minimalDaysInFirstWeek = data[1];
+    }
+
+    /**
+     * Recomputes the time and updates the status fields isTimeSet
+     * and areFieldsSet.  Callers should check isTimeSet and only
+     * call this method if isTimeSet is false.
+     */
+    private void updateTime() {
+        computeTime();
+        // The areFieldsSet and areAllFieldsSet values are no longer
+        // controlled here (as of 1.5).
+        isTimeSet = true;
+    }
+
+    private int compareTo(long t) {
+        long thisTime = getMillisOf(this);
+        return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
+    }
+
+    private static long getMillisOf(Calendar calendar) {
+        if (calendar.isTimeSet) {
+            return calendar.time;
+        }
+        Calendar cal = (Calendar) calendar.clone();
+        cal.setLenient(true);
+        return cal.getTimeInMillis();
+    }
+
+    /**
+     * Adjusts the stamp[] values before nextStamp overflow. nextStamp
+     * is set to the next stamp value upon the return.
+     */
+    private void adjustStamp() {
+        int max = MINIMUM_USER_STAMP;
+        int newStamp = MINIMUM_USER_STAMP;
+
+        for (;;) {
+            int min = Integer.MAX_VALUE;
+            for (int i = 0; i < stamp.length; i++) {
+                int v = stamp[i];
+                if (v >= newStamp && min > v) {
+                    min = v;
+                }
+                if (max < v) {
+                    max = v;
+                }
+            }
+            if (max != min && min == Integer.MAX_VALUE) {
+                break;
+            }
+            for (int i = 0; i < stamp.length; i++) {
+                if (stamp[i] == min) {
+                    stamp[i] = newStamp;
+                }
+            }
+            newStamp++;
+            if (min == max) {
+                break;
+            }
+        }
+        nextStamp = newStamp;
+    }
+
+    /**
+     * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
+     * new parameter value if they have been calculated internally.
+     */
+    private void invalidateWeekFields()
+    {
+        if (stamp[WEEK_OF_MONTH] != COMPUTED &&
+            stamp[WEEK_OF_YEAR] != COMPUTED) {
+            return;
+        }
+
+        // We have to check the new values of these fields after changing
+        // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
+        // have been changed, then set the new values. (4822110)
+        Calendar cal = (Calendar) clone();
+        cal.setLenient(true);
+        cal.clear(WEEK_OF_MONTH);
+        cal.clear(WEEK_OF_YEAR);
+
+        if (stamp[WEEK_OF_MONTH] == COMPUTED) {
+            int weekOfMonth = cal.get(WEEK_OF_MONTH);
+            if (fields[WEEK_OF_MONTH] != weekOfMonth) {
+                fields[WEEK_OF_MONTH] = weekOfMonth;
+            }
+        }
+
+        if (stamp[WEEK_OF_YEAR] == COMPUTED) {
+            int weekOfYear = cal.get(WEEK_OF_YEAR);
+            if (fields[WEEK_OF_YEAR] != weekOfYear) {
+                fields[WEEK_OF_YEAR] = weekOfYear;
+            }
+        }
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * Ideally, <code>Calendar</code> would only write out its state data and
+     * the current time, and not write any field data out, such as
+     * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
+     * and <code>isSet[]</code>.  <code>nextStamp</code> also should not be part
+     * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
+     * shipped. To be compatible with JDK 1.1, we will always have to write out
+     * the field values and state flags.  However, <code>nextStamp</code> can be
+     * removed from the serialization stream; this will probably happen in the
+     * near future.
+     */
+    private synchronized void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        // Try to compute the time correctly, for the future (stream
+        // version 2) in which we don't write out fields[] or isSet[].
+        if (!isTimeSet) {
+            try {
+                updateTime();
+            }
+            catch (IllegalArgumentException e) {}
+        }
+
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+        // Write out the 1.1 FCS object.
+        stream.defaultWriteObject();
+    }
+
+    private static class CalendarAccessControlContext {
+        private static final AccessControlContext INSTANCE;
+        static {
+            RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
+            PermissionCollection perms = perm.newPermissionCollection();
+            perms.add(perm);
+            INSTANCE = new AccessControlContext(new ProtectionDomain[] {
+                                                    new ProtectionDomain(null, perms)
+                                                });
+        }
+        private CalendarAccessControlContext() {
+        }
+    }
+
+    /**
+     * Reconstitutes this object from a stream (i.e., deserialize it).
+     */
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        final ObjectInputStream input = stream;
+        input.defaultReadObject();
+
+        stamp = new int[FIELD_COUNT];
+
+        // Starting with version 2 (not implemented yet), we expect that
+        // fields[], isSet[], isTimeSet, and areFieldsSet may not be
+        // streamed out anymore.  We expect 'time' to be correct.
+        if (serialVersionOnStream >= 2)
+        {
+            isTimeSet = true;
+            if (fields == null) {
+                fields = new int[FIELD_COUNT];
+            }
+            if (isSet == null) {
+                isSet = new boolean[FIELD_COUNT];
+            }
+        }
+        else if (serialVersionOnStream >= 0)
+        {
+            for (int i=0; i<FIELD_COUNT; ++i) {
+                stamp[i] = isSet[i] ? COMPUTED : UNSET;
+            }
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+
+        // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+
+        // If the deserialized object has a SimpleTimeZone, try to
+        // replace it with a ZoneInfo equivalent (as of 1.4) in order
+        // to be compatible with the SimpleTimeZone-based
+        // implementation as much as possible.
+        if (zone instanceof SimpleTimeZone) {
+            String id = zone.getID();
+            TimeZone tz = TimeZone.getTimeZone(id);
+            if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
+                zone = tz;
+            }
+        }
+    }
+
+    /**
+     * Converts this object to an {@link Instant}.
+     * <p>
+     * The conversion creates an {@code Instant} that represents the
+     * same point on the time-line as this {@code Calendar}.
+     *
+     * @return the instant representing the same point on the time-line
+     * @since 1.8
+     */
+    public final Instant toInstant() {
+        return Instant.ofEpochMilli(getTimeInMillis());
+    }
+}
diff --git a/java/util/Collection.annotated.java b/java/util/Collection.annotated.java
new file mode 100644
index 0000000..d2f425f
--- /dev/null
+++ b/java/util/Collection.annotated.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Collection<E> extends java.lang.Iterable<E> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public [email protected] Object @libcore.util.NonNull [] toArray();
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public default boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public void clear();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public default java.util.stream.Stream<@libcore.util.NullFromTypeParam E> stream() { throw new RuntimeException("Stub!"); }
+
[email protected] public default java.util.stream.Stream<@libcore.util.NullFromTypeParam E> parallelStream() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Collection.java b/java/util/Collection.java
new file mode 100644
index 0000000..2ae8872
--- /dev/null
+++ b/java/util/Collection.java
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+/**
+ * The root interface in the <i>collection hierarchy</i>.  A collection
+ * represents a group of objects, known as its <i>elements</i>.  Some
+ * collections allow duplicate elements and others do not.  Some are ordered
+ * and others unordered.  The JDK does not provide any <i>direct</i>
+ * implementations of this interface: it provides implementations of more
+ * specific subinterfaces like <tt>Set</tt> and <tt>List</tt>.  This interface
+ * is typically used to pass collections around and manipulate them where
+ * maximum generality is desired.
+ *
+ * <p><i>Bags</i> or <i>multisets</i> (unordered collections that may contain
+ * duplicate elements) should implement this interface directly.
+ *
+ * <p>All general-purpose <tt>Collection</tt> implementation classes (which
+ * typically implement <tt>Collection</tt> indirectly through one of its
+ * subinterfaces) should provide two "standard" constructors: a void (no
+ * arguments) constructor, which creates an empty collection, and a
+ * constructor with a single argument of type <tt>Collection</tt>, which
+ * creates a new collection with the same elements as its argument.  In
+ * effect, the latter constructor allows the user to copy any collection,
+ * producing an equivalent collection of the desired implementation type.
+ * There is no way to enforce this convention (as interfaces cannot contain
+ * constructors) but all of the general-purpose <tt>Collection</tt>
+ * implementations in the Java platform libraries comply.
+ *
+ * <p>The "destructive" methods contained in this interface, that is, the
+ * methods that modify the collection on which they operate, are specified to
+ * throw <tt>UnsupportedOperationException</tt> if this collection does not
+ * support the operation.  If this is the case, these methods may, but are not
+ * required to, throw an <tt>UnsupportedOperationException</tt> if the
+ * invocation would have no effect on the collection.  For example, invoking
+ * the {@link #addAll(Collection)} method on an unmodifiable collection may,
+ * but is not required to, throw the exception if the collection to be added
+ * is empty.
+ *
+ * <p><a name="optional-restrictions">
+ * Some collection implementations have restrictions on the elements that
+ * they may contain.</a>  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the collection may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <p>It is up to each collection to determine its own synchronization
+ * policy.  In the absence of a stronger guarantee by the
+ * implementation, undefined behavior may result from the invocation
+ * of any method on a collection that is being mutated by another
+ * thread; this includes direct invocations, passing the collection to
+ * a method that might perform invocations, and using an existing
+ * iterator to examine the collection.
+ *
+ * <p>Many methods in Collections Framework interfaces are defined in
+ * terms of the {@link Object#equals(Object) equals} method.  For example,
+ * the specification for the {@link #contains(Object) contains(Object o)}
+ * method says: "returns <tt>true</tt> if and only if this collection
+ * contains at least one element <tt>e</tt> such that
+ * <tt>(o==null ? e==null : o.equals(e))</tt>."  This specification should
+ * <i>not</i> be construed to imply that invoking <tt>Collection.contains</tt>
+ * with a non-null argument <tt>o</tt> will cause <tt>o.equals(e)</tt> to be
+ * invoked for any element <tt>e</tt>.  Implementations are free to implement
+ * optimizations whereby the <tt>equals</tt> invocation is avoided, for
+ * example, by first comparing the hash codes of the two elements.  (The
+ * {@link Object#hashCode()} specification guarantees that two objects with
+ * unequal hash codes cannot be equal.)  More generally, implementations of
+ * the various Collections Framework interfaces are free to take advantage of
+ * the specified behavior of underlying {@link Object} methods wherever the
+ * implementor deems it appropriate.
+ *
+ * <p>Some collection operations which perform recursive traversal of the
+ * collection may fail with an exception for self-referential instances where
+ * the collection directly or indirectly contains itself. This includes the
+ * {@code clone()}, {@code equals()}, {@code hashCode()} and {@code toString()}
+ * methods. Implementations may optionally handle the self-referential scenario,
+ * however most current implementations do not do so.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @implSpec
+ * The default method implementations (inherited or otherwise) do not apply any
+ * synchronization protocol.  If a {@code Collection} implementation has a
+ * specific synchronization protocol, then it must override default
+ * implementations to apply that protocol.
+ *
+ * @param <E> the type of elements in this collection
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Set
+ * @see     List
+ * @see     Map
+ * @see     SortedSet
+ * @see     SortedMap
+ * @see     HashSet
+ * @see     TreeSet
+ * @see     ArrayList
+ * @see     LinkedList
+ * @see     Vector
+ * @see     Collections
+ * @see     Arrays
+ * @see     AbstractCollection
+ * @since 1.2
+ */
+
+public interface Collection<E> extends Iterable<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this collection.  If this collection
+     * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
+     * <tt>Integer.MAX_VALUE</tt>.
+     *
+     * @return the number of elements in this collection
+     */
+    int size();
+
+    /**
+     * Returns <tt>true</tt> if this collection contains no elements.
+     *
+     * @return <tt>true</tt> if this collection contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns <tt>true</tt> if this collection contains the specified element.
+     * More formally, returns <tt>true</tt> if and only if this collection
+     * contains at least one element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this collection is to be tested
+     * @return <tt>true</tt> if this collection contains the specified
+     *         element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     *         (<a href="#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this collection.  There are no
+     * guarantees concerning the order in which the elements are returned
+     * (unless this collection is an instance of some class that provides a
+     * guarantee).
+     *
+     * @return an <tt>Iterator</tt> over the elements in this collection
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this collection.
+     * If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this collection.  (In other words, this method must
+     * allocate a new array even if this collection is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this collection
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this collection;
+     * the runtime type of the returned array is that of the specified array.
+     * If the collection fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this collection.
+     *
+     * <p>If this collection fits in the specified array with room to spare
+     * (i.e., the array has more elements than this collection), the element
+     * in the array immediately following the end of the collection is set to
+     * <tt>null</tt>.  (This is useful in determining the length of this
+     * collection <i>only</i> if the caller knows that this collection does
+     * not contain any <tt>null</tt> elements.)
+     *
+     * <p>If this collection makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements in
+     * the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose <tt>x</tt> is a collection known to contain only strings.
+     * The following code can be used to dump the collection into a newly
+     * allocated array of <tt>String</tt>:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that <tt>toArray(new Object[0])</tt> is identical in function to
+     * <tt>toArray()</tt>.
+     *
+     * @param <T> the runtime type of the array to contain the collection
+     * @param a the array into which the elements of this collection are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all of the elements in this collection
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this collection
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+    // Modification Operations
+
+    /**
+     * Ensures that this collection contains the specified element (optional
+     * operation).  Returns <tt>true</tt> if this collection changed as a
+     * result of the call.  (Returns <tt>false</tt> if this collection does
+     * not permit duplicates and already contains the specified element.)<p>
+     *
+     * Collections that support this operation may place limitations on what
+     * elements may be added to this collection.  In particular, some
+     * collections will refuse to add <tt>null</tt> elements, and others will
+     * impose restrictions on the type of elements that may be added.
+     * Collection classes should clearly specify in their documentation any
+     * restrictions on what elements may be added.<p>
+     *
+     * If a collection refuses to add a particular element for any reason
+     * other than that it already contains the element, it <i>must</i> throw
+     * an exception (rather than returning <tt>false</tt>).  This preserves
+     * the invariant that a collection always contains the specified element
+     * after this call returns.
+     *
+     * @param e element whose presence in this collection is to be ensured
+     * @return <tt>true</tt> if this collection changed as a result of the
+     *         call
+     * @throws UnsupportedOperationException if the <tt>add</tt> operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this collection
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     * @throws IllegalArgumentException if some property of the element
+     *         prevents it from being added to this collection
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to insertion restrictions
+     */
+    boolean add(E e);
+
+    /**
+     * Removes a single instance of the specified element from this
+     * collection, if it is present (optional operation).  More formally,
+     * removes an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if
+     * this collection contains one or more such elements.  Returns
+     * <tt>true</tt> if this collection contained the specified element (or
+     * equivalently, if this collection changed as a result of the call).
+     *
+     * @param o element to be removed from this collection, if present
+     * @return <tt>true</tt> if an element was removed as a result of this call
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         collection does not permit null elements
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
+     *         is not supported by this collection
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Operations
+
+    /**
+     * Returns <tt>true</tt> if this collection contains all of the elements
+     * in the specified collection.
+     *
+     * @param  c collection to be checked for containment in this collection
+     * @return <tt>true</tt> if this collection contains all of the elements
+     *         in the specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this collection does not permit null
+     *         elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null.
+     * @see    #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Adds all of the elements in the specified collection to this collection
+     * (optional operation).  The behavior of this operation is undefined if
+     * the specified collection is modified while the operation is in progress.
+     * (This implies that the behavior of this call is undefined if the
+     * specified collection is this collection, and this collection is
+     * nonempty.)
+     *
+     * @param c collection containing elements to be added to this collection
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @throws UnsupportedOperationException if the <tt>addAll</tt> operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this collection
+     * @throws NullPointerException if the specified collection contains a
+     *         null element and this collection does not permit null elements,
+     *         or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this
+     *         collection
+     * @throws IllegalStateException if not all the elements can be added at
+     *         this time due to insertion restrictions
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Removes all of this collection's elements that are also contained in the
+     * specified collection (optional operation).  After this call returns,
+     * this collection will contain no elements in common with the specified
+     * collection.
+     *
+     * @param c collection containing elements to be removed from this collection
+     * @return <tt>true</tt> if this collection changed as a result of the
+     *         call
+     * @throws UnsupportedOperationException if the <tt>removeAll</tt> method
+     *         is not supported by this collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in this collection are incompatible with the specified
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this collection contains one or more
+     *         null elements and the specified collection does not support
+     *         null elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements of this collection that satisfy the given
+     * predicate.  Errors or runtime exceptions thrown during iteration or by
+     * the predicate are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation traverses all elements of the collection using
+     * its {@link #iterator}.  Each matching element is removed using
+     * {@link Iterator#remove()}.  If the collection's iterator does not
+     * support removal then an {@code UnsupportedOperationException} will be
+     * thrown on the first matching element.
+     *
+     * @param filter a predicate which returns {@code true} for elements to be
+     *        removed
+     * @return {@code true} if any elements were removed
+     * @throws NullPointerException if the specified filter is null
+     * @throws UnsupportedOperationException if elements cannot be removed
+     *         from this collection.  Implementations may throw this exception if a
+     *         matching element cannot be removed or if, in general, removal is not
+     *         supported.
+     * @since 1.8
+     */
+    default boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        boolean removed = false;
+        final Iterator<E> each = iterator();
+        while (each.hasNext()) {
+            if (filter.test(each.next())) {
+                each.remove();
+                removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Retains only the elements in this collection that are contained in the
+     * specified collection (optional operation).  In other words, removes from
+     * this collection all of its elements that are not contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be retained in this collection
+     * @return <tt>true</tt> if this collection changed as a result of the call
+     * @throws UnsupportedOperationException if the <tt>retainAll</tt> operation
+     *         is not supported by this collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in this collection are incompatible with the specified
+     *         collection
+     *         (<a href="#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this collection contains one or more
+     *         null elements and the specified collection does not permit null
+     *         elements
+     *         (<a href="#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements from this collection (optional operation).
+     * The collection will be empty after this method returns.
+     *
+     * @throws UnsupportedOperationException if the <tt>clear</tt> operation
+     *         is not supported by this collection
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this collection for equality. <p>
+     *
+     * While the <tt>Collection</tt> interface adds no stipulations to the
+     * general contract for the <tt>Object.equals</tt>, programmers who
+     * implement the <tt>Collection</tt> interface "directly" (in other words,
+     * create a class that is a <tt>Collection</tt> but is not a <tt>Set</tt>
+     * or a <tt>List</tt>) must exercise care if they choose to override the
+     * <tt>Object.equals</tt>.  It is not necessary to do so, and the simplest
+     * course of action is to rely on <tt>Object</tt>'s implementation, but
+     * the implementor may wish to implement a "value comparison" in place of
+     * the default "reference comparison."  (The <tt>List</tt> and
+     * <tt>Set</tt> interfaces mandate such value comparisons.)<p>
+     *
+     * The general contract for the <tt>Object.equals</tt> method states that
+     * equals must be symmetric (in other words, <tt>a.equals(b)</tt> if and
+     * only if <tt>b.equals(a)</tt>).  The contracts for <tt>List.equals</tt>
+     * and <tt>Set.equals</tt> state that lists are only equal to other lists,
+     * and sets to other sets.  Thus, a custom <tt>equals</tt> method for a
+     * collection class that implements neither the <tt>List</tt> nor
+     * <tt>Set</tt> interface must return <tt>false</tt> when this collection
+     * is compared to any list or set.  (By the same logic, it is not possible
+     * to write a class that correctly implements both the <tt>Set</tt> and
+     * <tt>List</tt> interfaces.)
+     *
+     * @param o object to be compared for equality with this collection
+     * @return <tt>true</tt> if the specified object is equal to this
+     * collection
+     *
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     * @see List#equals(Object)
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this collection.  While the
+     * <tt>Collection</tt> interface adds no stipulations to the general
+     * contract for the <tt>Object.hashCode</tt> method, programmers should
+     * take note that any class that overrides the <tt>Object.equals</tt>
+     * method must also override the <tt>Object.hashCode</tt> method in order
+     * to satisfy the general contract for the <tt>Object.hashCode</tt> method.
+     * In particular, <tt>c1.equals(c2)</tt> implies that
+     * <tt>c1.hashCode()==c2.hashCode()</tt>.
+     *
+     * @return the hash code value for this collection
+     *
+     * @see Object#hashCode()
+     * @see Object#equals(Object)
+     */
+    int hashCode();
+
+    /**
+     * Creates a {@link Spliterator} over the elements in this collection.
+     *
+     * Implementations should document characteristic values reported by the
+     * spliterator.  Such characteristic values are not required to be reported
+     * if the spliterator reports {@link Spliterator#SIZED} and this collection
+     * contains no elements.
+     *
+     * <p>The default implementation should be overridden by subclasses that
+     * can return a more efficient spliterator.  In order to
+     * preserve expected laziness behavior for the {@link #stream()} and
+     * {@link #parallelStream()}} methods, spliterators should either have the
+     * characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>.
+     * If none of these is practical, the overriding class should describe the
+     * spliterator's documented policy of binding and structural interference,
+     * and should override the {@link #stream()} and {@link #parallelStream()}
+     * methods to create streams using a {@code Supplier} of the spliterator,
+     * as in:
+     * <pre>{@code
+     *     Stream<E> s = StreamSupport.stream(() -> spliterator(), spliteratorCharacteristics)
+     * }</pre>
+     * <p>These requirements ensure that streams produced by the
+     * {@link #stream()} and {@link #parallelStream()} methods will reflect the
+     * contents of the collection as of initiation of the terminal stream
+     * operation.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the collections's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the collection's iterator.
+     * <p>
+     * The created {@code Spliterator} reports {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>If a spliterator covers no elements then the reporting of additional
+     * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
+     * does not aid clients to control, specialize or simplify computation.
+     * However, this does enable shared use of an immutable and empty
+     * spliterator instance (see {@link Spliterators#emptySpliterator()}) for
+     * empty collections, and enables clients to determine if such a spliterator
+     * covers no elements.
+     *
+     * @return a {@code Spliterator} over the elements in this collection
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, 0);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} with this collection as its source.
+     *
+     * <p>This method should be overridden when the {@link #spliterator()}
+     * method cannot return a spliterator that is {@code IMMUTABLE},
+     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
+     * for details.)
+     *
+     * @implSpec
+     * The default implementation creates a sequential {@code Stream} from the
+     * collection's {@code Spliterator}.
+     *
+     * @return a sequential {@code Stream} over the elements in this collection
+     * @since 1.8
+     */
+    default Stream<E> stream() {
+        return StreamSupport.stream(spliterator(), false);
+    }
+
+    /**
+     * Returns a possibly parallel {@code Stream} with this collection as its
+     * source.  It is allowable for this method to return a sequential stream.
+     *
+     * <p>This method should be overridden when the {@link #spliterator()}
+     * method cannot return a spliterator that is {@code IMMUTABLE},
+     * {@code CONCURRENT}, or <em>late-binding</em>. (See {@link #spliterator()}
+     * for details.)
+     *
+     * @implSpec
+     * The default implementation creates a parallel {@code Stream} from the
+     * collection's {@code Spliterator}.
+     *
+     * @return a possibly parallel {@code Stream} over the elements in this
+     * collection
+     * @since 1.8
+     */
+    default Stream<E> parallelStream() {
+        return StreamSupport.stream(spliterator(), true);
+    }
+}
diff --git a/java/util/Collections.annotated.java b/java/util/Collections.annotated.java
new file mode 100644
index 0000000..3e3e636
--- /dev/null
+++ b/java/util/Collections.annotated.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.stream.Stream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Collections {
+
+Collections() { throw new RuntimeException("Stub!"); }
+
+public static <T extends java.lang.Comparable<? super T>> void sort(@libcore.util.NonNull java.util.List<@libcore.util.NonNull T> list) { throw new RuntimeException("Stub!"); }
+
+public static <T> void sort(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam T> list, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(@libcore.util.NonNull java.util.List<? extends @libcore.util.NonNull java.lang.Comparable<? super T>> list, @libcore.util.NonNull T key) { throw new RuntimeException("Stub!"); }
+
+public static <T> int binarySearch(@libcore.util.NonNull java.util.List<? extends @libcore.util.NullFromTypeParam T> list, @libcore.util.NullFromTypeParam T key, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
+public static void reverse(@libcore.util.NonNull java.util.List<?> list) { throw new RuntimeException("Stub!"); }
+
+public static void shuffle(@libcore.util.NonNull java.util.List<?> list) { throw new RuntimeException("Stub!"); }
+
+public static void shuffle(@libcore.util.NonNull java.util.List<?> list, @libcore.util.NonNull java.util.Random rnd) { throw new RuntimeException("Stub!"); }
+
+public static void swap(@libcore.util.NonNull java.util.List<?> list, int i, int j) { throw new RuntimeException("Stub!"); }
+
+public static <T> void fill(@libcore.util.NonNull java.util.List<? super @libcore.util.NullFromTypeParam T> list, @libcore.util.NullFromTypeParam T obj) { throw new RuntimeException("Stub!"); }
+
+public static <T> void copy(@libcore.util.NonNull java.util.List<? super @libcore.util.NullFromTypeParam T> dest, @libcore.util.NonNull java.util.List<? extends @libcore.util.NullFromTypeParam T> src) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T min(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NonNull T> coll) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T min(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam T> coll, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> comp) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T extends java.lang.Object & java.lang.Comparable<? super T>> T max(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NonNull T> coll) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T max(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam T> coll, @libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam T> comp) { throw new RuntimeException("Stub!"); }
+
+public static void rotate(@libcore.util.NonNull java.util.List<?> list, int distance) { throw new RuntimeException("Stub!"); }
+
+public static <T> boolean replaceAll(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam T> list, @libcore.util.NullFromTypeParam T oldVal, @libcore.util.NullFromTypeParam T newVal) { throw new RuntimeException("Stub!"); }
+
+public static int indexOfSubList(@libcore.util.NonNull java.util.List<?> source, @libcore.util.NonNull java.util.List<?> target) { throw new RuntimeException("Stub!"); }
+
+public static int lastIndexOfSubList(@libcore.util.NonNull java.util.List<?> source, @libcore.util.NonNull java.util.List<?> target) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Collection<@libcore.util.NullFromTypeParam T> unmodifiableCollection(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Set<@libcore.util.NullFromTypeParam T> unmodifiableSet(@libcore.util.NonNull java.util.Set<? extends @libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.SortedSet<@libcore.util.NullFromTypeParam T> unmodifiableSortedSet(@libcore.util.NonNull java.util.SortedSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.NavigableSet<@libcore.util.NullFromTypeParam T> unmodifiableNavigableSet(@libcore.util.NonNull java.util.NavigableSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> unmodifiableList(@libcore.util.NonNull java.util.List<? extends @libcore.util.NullFromTypeParam T> list) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> unmodifiableMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> unmodifiableSortedMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> unmodifiableNavigableMap(@libcore.util.NonNull java.util.NavigableMap<@libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam  V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Collection<@libcore.util.NullFromTypeParam T> synchronizedCollection(@libcore.util.NonNull java.util.Collection<@libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Set<@libcore.util.NullFromTypeParam T> synchronizedSet(@libcore.util.NonNull java.util.Set<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.SortedSet<@libcore.util.NullFromTypeParam T> synchronizedSortedSet(@libcore.util.NonNull java.util.SortedSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.NavigableSet<@libcore.util.NullFromTypeParam T> synchronizedNavigableSet(@libcore.util.NonNull java.util.NavigableSet<@libcore.util.NullFromTypeParam T> s) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> synchronizedList(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam T> list) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> synchronizedMap(@libcore.util.NonNull java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> synchronizedSortedMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> synchronizedNavigableMap(@libcore.util.NonNull java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Collection<@libcore.util.NullFromTypeParam E> checkedCollection(@libcore.util.NonNull java.util.Collection<@libcore.util.NullFromTypeParam E> c, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Queue<@libcore.util.NullFromTypeParam E> checkedQueue(@libcore.util.NonNull java.util.Queue<@libcore.util.NullFromTypeParam E> queue, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NullFromTypeParam E> checkedSet(@libcore.util.NonNull java.util.Set<@libcore.util.NullFromTypeParam E> s, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.SortedSet<@libcore.util.NullFromTypeParam E> checkedSortedSet(@libcore.util.NonNull java.util.SortedSet<@libcore.util.NullFromTypeParam E> s, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.NavigableSet<@libcore.util.NullFromTypeParam E> checkedNavigableSet(@libcore.util.NonNull java.util.NavigableSet<@libcore.util.NullFromTypeParam E> s, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NullFromTypeParam E> checkedList(@libcore.util.NonNull java.util.List<@libcore.util.NullFromTypeParam E> list, @libcore.util.NonNull java.lang.Class<E> type) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> checkedMap(@libcore.util.NonNull java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m, @libcore.util.NonNull java.lang.Class<K> keyType, @libcore.util.NonNull java.lang.Class<V> valueType) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> checkedSortedMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m, @libcore.util.NonNull java.lang.Class<K> keyType, @libcore.util.NonNull java.lang.Class<V> valueType) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> checkedNavigableMap(@libcore.util.NonNull java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> m, @libcore.util.NonNull java.lang.Class<K> keyType, @libcore.util.NonNull java.lang.Class<V> valueType) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Iterator<@libcore.util.NullFromTypeParam T> emptyIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.ListIterator<@libcore.util.NullFromTypeParam T> emptyListIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Enumeration<@libcore.util.NullFromTypeParam T> emptyEnumeration() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <T> java.util.Set<@libcore.util.NullFromTypeParam T> emptySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.SortedSet<@libcore.util.NullFromTypeParam E> emptySortedSet() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.NavigableSet<@libcore.util.NullFromTypeParam E> emptyNavigableSet() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <T> java.util.List<@libcore.util.NullFromTypeParam T> emptyList() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> emptyMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <K, V> java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> emptySortedMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final <K, V> java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> emptyNavigableMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Set<@libcore.util.NullFromTypeParam T> singleton(@libcore.util.NullFromTypeParam T o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> singletonList(@libcore.util.NullFromTypeParam T o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Map<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> singletonMap(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.List<@libcore.util.NullFromTypeParam T> nCopies(int n, @libcore.util.NullFromTypeParam T o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Comparator<@libcore.util.NonNull T> reverseOrder() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Comparator<@libcore.util.NullFromTypeParam T> reverseOrder(@libcore.util.Nullable java.util.Comparator<@libcore.util.NullFromTypeParam T> cmp) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Enumeration<@libcore.util.NullFromTypeParam T> enumeration(@libcore.util.NonNull java.util.Collection<@libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.ArrayList<@libcore.util.NullFromTypeParam T> list(@libcore.util.NonNull java.util.Enumeration<@libcore.util.NullFromTypeParam T> e) { throw new RuntimeException("Stub!"); }
+
+public static int frequency(@libcore.util.NonNull java.util.Collection<?> c, @libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public static boolean disjoint(@libcore.util.NonNull java.util.Collection<?> c1, @libcore.util.NonNull java.util.Collection<?> c2) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static <T> boolean addAll(@libcore.util.NonNull java.util.Collection<? super @libcore.util.NullFromTypeParam T> c, T @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NullFromTypeParam E> newSetFromMap(@libcore.util.NonNull java.util.Map<@libcore.util.NullFromTypeParam E, @libcore.util.NonNull java.lang.Boolean> map) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> java.util.Queue<@libcore.util.NullFromTypeParam T> asLifoQueue(@libcore.util.NonNull java.util.Deque<@libcore.util.NullFromTypeParam T> deque) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.util.List EMPTY_LIST;
+static { EMPTY_LIST = null; }
+
[email protected] public static final java.util.Map EMPTY_MAP;
+static { EMPTY_MAP = null; }
+
[email protected] public static final java.util.Set EMPTY_SET;
+static { EMPTY_SET = null; }
+}
diff --git a/java/util/Collections.java b/java/util/Collections.java
new file mode 100644
index 0000000..58ad86f
--- /dev/null
+++ b/java/util/Collections.java
@@ -0,0 +1,5621 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import dalvik.system.VMRuntime;
+
+/**
+ * This class consists exclusively of static methods that operate on or return
+ * collections.  It contains polymorphic algorithms that operate on
+ * collections, "wrappers", which return a new collection backed by a
+ * specified collection, and a few other odds and ends.
+ *
+ * <p>The methods of this class all throw a <tt>NullPointerException</tt>
+ * if the collections or class objects provided to them are null.
+ *
+ * <p>The documentation for the polymorphic algorithms contained in this class
+ * generally includes a brief description of the <i>implementation</i>.  Such
+ * descriptions should be regarded as <i>implementation notes</i>, rather than
+ * parts of the <i>specification</i>.  Implementors should feel free to
+ * substitute other algorithms, so long as the specification itself is adhered
+ * to.  (For example, the algorithm used by <tt>sort</tt> does not have to be
+ * a mergesort, but it does have to be <i>stable</i>.)
+ *
+ * <p>The "destructive" algorithms contained in this class, that is, the
+ * algorithms that modify the collection on which they operate, are specified
+ * to throw <tt>UnsupportedOperationException</tt> if the collection does not
+ * support the appropriate mutation primitive(s), such as the <tt>set</tt>
+ * method.  These algorithms may, but are not required to, throw this
+ * exception if an invocation would have no effect on the collection.  For
+ * example, invoking the <tt>sort</tt> method on an unmodifiable list that is
+ * already sorted may or may not throw <tt>UnsupportedOperationException</tt>.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     Set
+ * @see     List
+ * @see     Map
+ * @since   1.2
+ */
+
+public class Collections {
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Collections() {
+    }
+
+    // Algorithms
+
+    /*
+     * Tuning parameters for algorithms - Many of the List algorithms have
+     * two implementations, one of which is appropriate for RandomAccess
+     * lists, the other for "sequential."  Often, the random access variant
+     * yields better performance on small sequential access lists.  The
+     * tuning parameters below determine the cutoff point for what constitutes
+     * a "small" sequential access list for each algorithm.  The values below
+     * were empirically determined to work well for LinkedList. Hopefully
+     * they should be reasonable for other sequential access List
+     * implementations.  Those doing performance work on this code would
+     * do well to validate the values of these parameters from time to time.
+     * (The first word of each tuning parameter name is the algorithm to which
+     * it applies.)
+     */
+    private static final int BINARYSEARCH_THRESHOLD   = 5000;
+    private static final int REVERSE_THRESHOLD        =   18;
+    private static final int SHUFFLE_THRESHOLD        =    5;
+    private static final int FILL_THRESHOLD           =   25;
+    private static final int ROTATE_THRESHOLD         =  100;
+    private static final int COPY_THRESHOLD           =   10;
+    private static final int REPLACEALL_THRESHOLD     =   11;
+    private static final int INDEXOFSUBLIST_THRESHOLD =   35;
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts the specified list into ascending order, according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     * All elements in the list must implement the {@link Comparable}
+     * interface.  Furthermore, all elements in the list must be
+     * <i>mutually comparable</i> (that is, {@code e1.compareTo(e2)}
+     * must not throw a {@code ClassCastException} for any elements
+     * {@code e1} and {@code e2} in the list).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>The specified list must be modifiable, but need not be resizable.
+     *
+     * @implNote
+     * This implementation defers to the {@link List#sort(Comparator)}
+     * method using the specified list and a {@code null} comparator.
+     * Do not call this method from {@code List.sort()} since that can lead
+     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
+     * backwards compatibility behavior where this method was implemented
+     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
+     * {@link ListIterator#set(Object)}.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be sorted.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and integers).
+     * @throws UnsupportedOperationException if the specified list's
+     *         list-iterator does not support the {@code set} operation.
+     * @throws IllegalArgumentException (optional) if the implementation
+     *         detects that the natural ordering of the list elements is
+     *         found to violate the {@link Comparable} contract
+     * @see List#sort(Comparator)
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> void sort(List<T> list) {
+        // Android-changed: List.sort() vs. Collections.sort() app compat.
+        // Call sort(list, null) here to be consistent with that method's
+        // (changed on Android) behavior.
+        // list.sort(null);
+        sort(list, null);
+    }
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts the specified list according to the order induced by the
+     * specified comparator.  All elements in the list must be <i>mutually
+     * comparable</i> using the specified comparator (that is,
+     * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
+     * for any elements {@code e1} and {@code e2} in the list).
+     *
+     * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
+     * not be reordered as a result of the sort.
+     *
+     * <p>The specified list must be modifiable, but need not be resizable.
+     *
+     * @implNote
+     * This implementation defers to the {@link List#sort(Comparator)}
+     * method using the specified list and comparator.
+     * Do not call this method from {@code List.sort()} since that can lead
+     * to infinite recursion. Apps targeting APIs {@code <= 25} observe
+     * backwards compatibility behavior where this method was implemented
+     * on top of {@link List#toArray()}, {@link ListIterator#next()} and
+     * {@link ListIterator#set(Object)}.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be sorted.
+     * @param  c the comparator to determine the order of the list.  A
+     *        {@code null} value indicates that the elements' <i>natural
+     *        ordering</i> should be used.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator.
+     * @throws UnsupportedOperationException if the specified list's
+     *         list-iterator does not support the {@code set} operation.
+     * @throws IllegalArgumentException (optional) if the comparator is
+     *         found to violate the {@link Comparator} contract
+     * @see List#sort(Comparator)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T> void sort(List<T> list, Comparator<? super T> c) {
+        // BEGIN Android-changed: List.sort() vs. Collections.sort() app compat.
+        // list.sort(c);
+        int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+        if (targetSdkVersion > 25) {
+            list.sort(c);
+        } else {
+            // Compatibility behavior for API <= 25. http://b/33482884
+            if (list.getClass() == ArrayList.class) {
+                Arrays.sort((T[]) ((ArrayList) list).elementData, 0, list.size(), c);
+                return;
+            }
+
+            Object[] a = list.toArray();
+            Arrays.sort(a, (Comparator) c);
+            ListIterator<T> i = list.listIterator();
+            for (int j = 0; j < a.length; j++) {
+                i.next();
+                i.set((T) a[j]);
+            }
+        }
+        // END Android-changed: List.sort() vs. Collections.sort() app compat.
+    }
+
+
+    /**
+     * Searches the specified list for the specified object using the binary
+     * search algorithm.  The list must be sorted into ascending order
+     * according to the {@linkplain Comparable natural ordering} of its
+     * elements (as by the {@link #sort(List)} method) prior to making this
+     * call.  If it is not sorted, the results are undefined.  If the list
+     * contains multiple elements equal to the specified object, there is no
+     * guarantee which one will be found.
+     *
+     * <p>This method runs in log(n) time for a "random access" list (which
+     * provides near-constant-time positional access).  If the specified list
+     * does not implement the {@link RandomAccess} interface and is large,
+     * this method will do an iterator-based binary search that performs
+     * O(n) link traversals and O(log n) element comparisons.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be searched.
+     * @param  key the key to be searched for.
+     * @return the index of the search key, if it is contained in the list;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the list: the index of the first
+     *         element greater than the key, or <tt>list.size()</tt> if all
+     *         elements in the list are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> (for example, strings and
+     *         integers), or the search key is not mutually comparable
+     *         with the elements of the list.
+     */
+    public static <T>
+    int binarySearch(List<? extends Comparable<? super T>> list, T key) {
+        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
+            return Collections.indexedBinarySearch(list, key);
+        else
+            return Collections.iteratorBinarySearch(list, key);
+    }
+
+    private static <T>
+    int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
+        int low = 0;
+        int high = list.size()-1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Comparable<? super T> midVal = list.get(mid);
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    private static <T>
+    int iteratorBinarySearch(List<? extends Comparable<? super T>> list, T key)
+    {
+        int low = 0;
+        int high = list.size()-1;
+        ListIterator<? extends Comparable<? super T>> i = list.listIterator();
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Comparable<? super T> midVal = get(i, mid);
+            int cmp = midVal.compareTo(key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    /**
+     * Gets the ith element from the given list by repositioning the specified
+     * list listIterator.
+     */
+    private static <T> T get(ListIterator<? extends T> i, int index) {
+        T obj = null;
+        int pos = i.nextIndex();
+        if (pos <= index) {
+            do {
+                obj = i.next();
+            } while (pos++ < index);
+        } else {
+            do {
+                obj = i.previous();
+            } while (--pos > index);
+        }
+        return obj;
+    }
+
+    /**
+     * Searches the specified list for the specified object using the binary
+     * search algorithm.  The list must be sorted into ascending order
+     * according to the specified comparator (as by the
+     * {@link #sort(List, Comparator) sort(List, Comparator)}
+     * method), prior to making this call.  If it is
+     * not sorted, the results are undefined.  If the list contains multiple
+     * elements equal to the specified object, there is no guarantee which one
+     * will be found.
+     *
+     * <p>This method runs in log(n) time for a "random access" list (which
+     * provides near-constant-time positional access).  If the specified list
+     * does not implement the {@link RandomAccess} interface and is large,
+     * this method will do an iterator-based binary search that performs
+     * O(n) link traversals and O(log n) element comparisons.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be searched.
+     * @param  key the key to be searched for.
+     * @param  c the comparator by which the list is ordered.
+     *         A <tt>null</tt> value indicates that the elements'
+     *         {@linkplain Comparable natural ordering} should be used.
+     * @return the index of the search key, if it is contained in the list;
+     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
+     *         <i>insertion point</i> is defined as the point at which the
+     *         key would be inserted into the list: the index of the first
+     *         element greater than the key, or <tt>list.size()</tt> if all
+     *         elements in the list are less than the specified key.  Note
+     *         that this guarantees that the return value will be &gt;= 0 if
+     *         and only if the key is found.
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator,
+     *         or the search key is not mutually comparable with the
+     *         elements of the list using this comparator.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c) {
+        if (c==null)
+            return binarySearch((List<? extends Comparable<? super T>>) list, key);
+
+        if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
+            return Collections.indexedBinarySearch(list, key, c);
+        else
+            return Collections.iteratorBinarySearch(list, key, c);
+    }
+
+    private static <T> int indexedBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
+        int low = 0;
+        int high = l.size()-1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = l.get(mid);
+            int cmp = c.compare(midVal, key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    private static <T> int iteratorBinarySearch(List<? extends T> l, T key, Comparator<? super T> c) {
+        int low = 0;
+        int high = l.size()-1;
+        ListIterator<? extends T> i = l.listIterator();
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            T midVal = get(i, mid);
+            int cmp = c.compare(midVal, key);
+
+            if (cmp < 0)
+                low = mid + 1;
+            else if (cmp > 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -(low + 1);  // key not found
+    }
+
+    /**
+     * Reverses the order of the elements in the specified list.<p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  list the list whose elements are to be reversed.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void reverse(List<?> list) {
+        int size = list.size();
+        if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
+                swap(list, i, j);
+        } else {
+            // instead of using a raw type here, it's possible to capture
+            // the wildcard but it will require a call to a supplementary
+            // private method
+            ListIterator fwd = list.listIterator();
+            ListIterator rev = list.listIterator(size);
+            for (int i=0, mid=list.size()>>1; i<mid; i++) {
+                Object tmp = fwd.next();
+                fwd.set(rev.previous());
+                rev.set(tmp);
+            }
+        }
+    }
+
+    /**
+     * Randomly permutes the specified list using a default source of
+     * randomness.  All permutations occur with approximately equal
+     * likelihood.
+     *
+     * <p>The hedge "approximately" is used in the foregoing description because
+     * default source of randomness is only approximately an unbiased source
+     * of independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm would choose permutations with perfect
+     * uniformity.
+     *
+     * <p>This implementation traverses the list backwards, from the last
+     * element up to the second, repeatedly swapping a randomly selected element
+     * into the "current position".  Elements are randomly selected from the
+     * portion of the list that runs from the first element to the current
+     * position, inclusive.
+     *
+     * <p>This method runs in linear time.  If the specified list does not
+     * implement the {@link RandomAccess} interface and is large, this
+     * implementation dumps the specified list into an array before shuffling
+     * it, and dumps the shuffled array back into the list.  This avoids the
+     * quadratic behavior that would result from shuffling a "sequential
+     * access" list in place.
+     *
+     * @param  list the list to be shuffled.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     */
+    public static void shuffle(List<?> list) {
+        Random rnd = r;
+        if (rnd == null)
+            r = rnd = new Random(); // harmless race.
+        shuffle(list, rnd);
+    }
+
+    private static Random r;
+
+    /**
+     * Randomly permute the specified list using the specified source of
+     * randomness.  All permutations occur with equal likelihood
+     * assuming that the source of randomness is fair.<p>
+     *
+     * This implementation traverses the list backwards, from the last element
+     * up to the second, repeatedly swapping a randomly selected element into
+     * the "current position".  Elements are randomly selected from the
+     * portion of the list that runs from the first element to the current
+     * position, inclusive.<p>
+     *
+     * This method runs in linear time.  If the specified list does not
+     * implement the {@link RandomAccess} interface and is large, this
+     * implementation dumps the specified list into an array before shuffling
+     * it, and dumps the shuffled array back into the list.  This avoids the
+     * quadratic behavior that would result from shuffling a "sequential
+     * access" list in place.
+     *
+     * @param  list the list to be shuffled.
+     * @param  rnd the source of randomness to use to shuffle the list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the <tt>set</tt> operation.
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void shuffle(List<?> list, Random rnd) {
+        int size = list.size();
+        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=size; i>1; i--)
+                swap(list, i-1, rnd.nextInt(i));
+        } else {
+            Object arr[] = list.toArray();
+
+            // Shuffle array
+            for (int i=size; i>1; i--)
+                swap(arr, i-1, rnd.nextInt(i));
+
+            // Dump array back into list
+            // instead of using a raw type here, it's possible to capture
+            // the wildcard but it will require a call to a supplementary
+            // private method
+            ListIterator it = list.listIterator();
+            for (int i=0; i<arr.length; i++) {
+                it.next();
+                it.set(arr[i]);
+            }
+        }
+    }
+
+    /**
+     * Swaps the elements at the specified positions in the specified list.
+     * (If the specified positions are equal, invoking this method leaves
+     * the list unchanged.)
+     *
+     * @param list The list in which to swap elements.
+     * @param i the index of one element to be swapped.
+     * @param j the index of the other element to be swapped.
+     * @throws IndexOutOfBoundsException if either <tt>i</tt> or <tt>j</tt>
+     *         is out of range (i &lt; 0 || i &gt;= list.size()
+     *         || j &lt; 0 || j &gt;= list.size()).
+     * @since 1.4
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static void swap(List<?> list, int i, int j) {
+        // instead of using a raw type here, it's possible to capture
+        // the wildcard but it will require a call to a supplementary
+        // private method
+        final List l = list;
+        l.set(i, l.set(j, l.get(i)));
+    }
+
+    /**
+     * Swaps the two specified elements in the specified array.
+     */
+    private static void swap(Object[] arr, int i, int j) {
+        Object tmp = arr[i];
+        arr[i] = arr[j];
+        arr[j] = tmp;
+    }
+
+    /**
+     * Replaces all of the elements of the specified list with the specified
+     * element. <p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be filled with the specified element.
+     * @param  obj The element with which to fill the specified list.
+     * @throws UnsupportedOperationException if the specified list or its
+     *         list-iterator does not support the <tt>set</tt> operation.
+     */
+    public static <T> void fill(List<? super T> list, T obj) {
+        int size = list.size();
+
+        if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
+            for (int i=0; i<size; i++)
+                list.set(i, obj);
+        } else {
+            ListIterator<? super T> itr = list.listIterator();
+            for (int i=0; i<size; i++) {
+                itr.next();
+                itr.set(obj);
+            }
+        }
+    }
+
+    /**
+     * Copies all of the elements from one list into another.  After the
+     * operation, the index of each copied element in the destination list
+     * will be identical to its index in the source list.  The destination
+     * list must be at least as long as the source list.  If it is longer, the
+     * remaining elements in the destination list are unaffected. <p>
+     *
+     * This method runs in linear time.
+     *
+     * @param  <T> the class of the objects in the lists
+     * @param  dest The destination list.
+     * @param  src The source list.
+     * @throws IndexOutOfBoundsException if the destination list is too small
+     *         to contain the entire source List.
+     * @throws UnsupportedOperationException if the destination list's
+     *         list-iterator does not support the <tt>set</tt> operation.
+     */
+    public static <T> void copy(List<? super T> dest, List<? extends T> src) {
+        int srcSize = src.size();
+        if (srcSize > dest.size())
+            throw new IndexOutOfBoundsException("Source does not fit in dest");
+
+        if (srcSize < COPY_THRESHOLD ||
+            (src instanceof RandomAccess && dest instanceof RandomAccess)) {
+            for (int i=0; i<srcSize; i++)
+                dest.set(i, src.get(i));
+        } else {
+            ListIterator<? super T> di=dest.listIterator();
+            ListIterator<? extends T> si=src.listIterator();
+            for (int i=0; i<srcSize; i++) {
+                di.next();
+                di.set(si.next());
+            }
+        }
+    }
+
+    /**
+     * Returns the minimum element of the given collection, according to the
+     * <i>natural ordering</i> of its elements.  All elements in the
+     * collection must implement the <tt>Comparable</tt> interface.
+     * Furthermore, all elements in the collection must be <i>mutually
+     * comparable</i> (that is, <tt>e1.compareTo(e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose minimum element is to be determined.
+     * @return the minimum element of the given collection, according
+     *         to the <i>natural ordering</i> of its elements.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (next.compareTo(candidate) < 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the minimum element of the given collection, according to the
+     * order induced by the specified comparator.  All elements in the
+     * collection must be <i>mutually comparable</i> by the specified
+     * comparator (that is, <tt>comp.compare(e1, e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose minimum element is to be determined.
+     * @param  comp the comparator with which to determine the minimum element.
+     *         A <tt>null</tt> value indicates that the elements' <i>natural
+     *         ordering</i> should be used.
+     * @return the minimum element of the given collection, according
+     *         to the specified comparator.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator.
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
+        if (comp==null)
+            return (T)min((Collection) coll);
+
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (comp.compare(next, candidate) < 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the maximum element of the given collection, according to the
+     * <i>natural ordering</i> of its elements.  All elements in the
+     * collection must implement the <tt>Comparable</tt> interface.
+     * Furthermore, all elements in the collection must be <i>mutually
+     * comparable</i> (that is, <tt>e1.compareTo(e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose maximum element is to be determined.
+     * @return the maximum element of the given collection, according
+     *         to the <i>natural ordering</i> of its elements.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> (for example, strings and
+     *         integers).
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (next.compareTo(candidate) > 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Returns the maximum element of the given collection, according to the
+     * order induced by the specified comparator.  All elements in the
+     * collection must be <i>mutually comparable</i> by the specified
+     * comparator (that is, <tt>comp.compare(e1, e2)</tt> must not throw a
+     * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and
+     * <tt>e2</tt> in the collection).<p>
+     *
+     * This method iterates over the entire collection, hence it requires
+     * time proportional to the size of the collection.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  coll the collection whose maximum element is to be determined.
+     * @param  comp the comparator with which to determine the maximum element.
+     *         A <tt>null</tt> value indicates that the elements' <i>natural
+     *        ordering</i> should be used.
+     * @return the maximum element of the given collection, according
+     *         to the specified comparator.
+     * @throws ClassCastException if the collection contains elements that are
+     *         not <i>mutually comparable</i> using the specified comparator.
+     * @throws NoSuchElementException if the collection is empty.
+     * @see Comparable
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp) {
+        if (comp==null)
+            return (T)max((Collection) coll);
+
+        Iterator<? extends T> i = coll.iterator();
+        T candidate = i.next();
+
+        while (i.hasNext()) {
+            T next = i.next();
+            if (comp.compare(next, candidate) > 0)
+                candidate = next;
+        }
+        return candidate;
+    }
+
+    /**
+     * Rotates the elements in the specified list by the specified distance.
+     * After calling this method, the element at index <tt>i</tt> will be
+     * the element previously at index <tt>(i - distance)</tt> mod
+     * <tt>list.size()</tt>, for all values of <tt>i</tt> between <tt>0</tt>
+     * and <tt>list.size()-1</tt>, inclusive.  (This method has no effect on
+     * the size of the list.)
+     *
+     * <p>For example, suppose <tt>list</tt> comprises<tt> [t, a, n, k, s]</tt>.
+     * After invoking <tt>Collections.rotate(list, 1)</tt> (or
+     * <tt>Collections.rotate(list, -4)</tt>), <tt>list</tt> will comprise
+     * <tt>[s, t, a, n, k]</tt>.
+     *
+     * <p>Note that this method can usefully be applied to sublists to
+     * move one or more elements within a list while preserving the
+     * order of the remaining elements.  For example, the following idiom
+     * moves the element at index <tt>j</tt> forward to position
+     * <tt>k</tt> (which must be greater than or equal to <tt>j</tt>):
+     * <pre>
+     *     Collections.rotate(list.subList(j, k+1), -1);
+     * </pre>
+     * To make this concrete, suppose <tt>list</tt> comprises
+     * <tt>[a, b, c, d, e]</tt>.  To move the element at index <tt>1</tt>
+     * (<tt>b</tt>) forward two positions, perform the following invocation:
+     * <pre>
+     *     Collections.rotate(l.subList(1, 4), -1);
+     * </pre>
+     * The resulting list is <tt>[a, c, d, b, e]</tt>.
+     *
+     * <p>To move more than one element forward, increase the absolute value
+     * of the rotation distance.  To move elements backward, use a positive
+     * shift distance.
+     *
+     * <p>If the specified list is small or implements the {@link
+     * RandomAccess} interface, this implementation exchanges the first
+     * element into the location it should go, and then repeatedly exchanges
+     * the displaced element into the location it should go until a displaced
+     * element is swapped into the first element.  If necessary, the process
+     * is repeated on the second and successive elements, until the rotation
+     * is complete.  If the specified list is large and doesn't implement the
+     * <tt>RandomAccess</tt> interface, this implementation breaks the
+     * list into two sublist views around index <tt>-distance mod size</tt>.
+     * Then the {@link #reverse(List)} method is invoked on each sublist view,
+     * and finally it is invoked on the entire list.  For a more complete
+     * description of both algorithms, see Section 2.3 of Jon Bentley's
+     * <i>Programming Pearls</i> (Addison-Wesley, 1986).
+     *
+     * @param list the list to be rotated.
+     * @param distance the distance to rotate the list.  There are no
+     *        constraints on this value; it may be zero, negative, or
+     *        greater than <tt>list.size()</tt>.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     * @since 1.4
+     */
+    public static void rotate(List<?> list, int distance) {
+        if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
+            rotate1(list, distance);
+        else
+            rotate2(list, distance);
+    }
+
+    private static <T> void rotate1(List<T> list, int distance) {
+        int size = list.size();
+        if (size == 0)
+            return;
+        distance = distance % size;
+        if (distance < 0)
+            distance += size;
+        if (distance == 0)
+            return;
+
+        for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
+            T displaced = list.get(cycleStart);
+            int i = cycleStart;
+            do {
+                i += distance;
+                if (i >= size)
+                    i -= size;
+                displaced = list.set(i, displaced);
+                nMoved ++;
+            } while (i != cycleStart);
+        }
+    }
+
+    private static void rotate2(List<?> list, int distance) {
+        int size = list.size();
+        if (size == 0)
+            return;
+        int mid =  -distance % size;
+        if (mid < 0)
+            mid += size;
+        if (mid == 0)
+            return;
+
+        reverse(list.subList(0, mid));
+        reverse(list.subList(mid, size));
+        reverse(list);
+    }
+
+    /**
+     * Replaces all occurrences of one specified value in a list with another.
+     * More formally, replaces with <tt>newVal</tt> each element <tt>e</tt>
+     * in <tt>list</tt> such that
+     * <tt>(oldVal==null ? e==null : oldVal.equals(e))</tt>.
+     * (This method has no effect on the size of the list.)
+     *
+     * @param  <T> the class of the objects in the list
+     * @param list the list in which replacement is to occur.
+     * @param oldVal the old value to be replaced.
+     * @param newVal the new value with which <tt>oldVal</tt> is to be
+     *        replaced.
+     * @return <tt>true</tt> if <tt>list</tt> contained one or more elements
+     *         <tt>e</tt> such that
+     *         <tt>(oldVal==null ?  e==null : oldVal.equals(e))</tt>.
+     * @throws UnsupportedOperationException if the specified list or
+     *         its list-iterator does not support the <tt>set</tt> operation.
+     * @since  1.4
+     */
+    public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) {
+        boolean result = false;
+        int size = list.size();
+        if (size < REPLACEALL_THRESHOLD || list instanceof RandomAccess) {
+            if (oldVal==null) {
+                for (int i=0; i<size; i++) {
+                    if (list.get(i)==null) {
+                        list.set(i, newVal);
+                        result = true;
+                    }
+                }
+            } else {
+                for (int i=0; i<size; i++) {
+                    if (oldVal.equals(list.get(i))) {
+                        list.set(i, newVal);
+                        result = true;
+                    }
+                }
+            }
+        } else {
+            ListIterator<T> itr=list.listIterator();
+            if (oldVal==null) {
+                for (int i=0; i<size; i++) {
+                    if (itr.next()==null) {
+                        itr.set(newVal);
+                        result = true;
+                    }
+                }
+            } else {
+                for (int i=0; i<size; i++) {
+                    if (oldVal.equals(itr.next())) {
+                        itr.set(newVal);
+                        result = true;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the starting position of the first occurrence of the specified
+     * target list within the specified source list, or -1 if there is no
+     * such occurrence.  More formally, returns the lowest index <tt>i</tt>
+     * such that {@code source.subList(i, i+target.size()).equals(target)},
+     * or -1 if there is no such index.  (Returns -1 if
+     * {@code target.size() > source.size()})
+     *
+     * <p>This implementation uses the "brute force" technique of scanning
+     * over the source list, looking for a match with the target at each
+     * location in turn.
+     *
+     * @param source the list in which to search for the first occurrence
+     *        of <tt>target</tt>.
+     * @param target the list to search for as a subList of <tt>source</tt>.
+     * @return the starting position of the first occurrence of the specified
+     *         target list within the specified source list, or -1 if there
+     *         is no such occurrence.
+     * @since  1.4
+     */
+    public static int indexOfSubList(List<?> source, List<?> target) {
+        int sourceSize = source.size();
+        int targetSize = target.size();
+        int maxCandidate = sourceSize - targetSize;
+
+        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
+            (source instanceof RandomAccess&&target instanceof RandomAccess)) {
+        nextCand:
+            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
+                for (int i=0, j=candidate; i<targetSize; i++, j++)
+                    if (!eq(target.get(i), source.get(j)))
+                        continue nextCand;  // Element mismatch, try next cand
+                return candidate;  // All elements of candidate matched target
+            }
+        } else {  // Iterator version of above algorithm
+            ListIterator<?> si = source.listIterator();
+        nextCand:
+            for (int candidate = 0; candidate <= maxCandidate; candidate++) {
+                ListIterator<?> ti = target.listIterator();
+                for (int i=0; i<targetSize; i++) {
+                    if (!eq(ti.next(), si.next())) {
+                        // Back up source iterator to next candidate
+                        for (int j=0; j<i; j++)
+                            si.previous();
+                        continue nextCand;
+                    }
+                }
+                return candidate;
+            }
+        }
+        return -1;  // No candidate matched the target
+    }
+
+    /**
+     * Returns the starting position of the last occurrence of the specified
+     * target list within the specified source list, or -1 if there is no such
+     * occurrence.  More formally, returns the highest index <tt>i</tt>
+     * such that {@code source.subList(i, i+target.size()).equals(target)},
+     * or -1 if there is no such index.  (Returns -1 if
+     * {@code target.size() > source.size()})
+     *
+     * <p>This implementation uses the "brute force" technique of iterating
+     * over the source list, looking for a match with the target at each
+     * location in turn.
+     *
+     * @param source the list in which to search for the last occurrence
+     *        of <tt>target</tt>.
+     * @param target the list to search for as a subList of <tt>source</tt>.
+     * @return the starting position of the last occurrence of the specified
+     *         target list within the specified source list, or -1 if there
+     *         is no such occurrence.
+     * @since  1.4
+     */
+    public static int lastIndexOfSubList(List<?> source, List<?> target) {
+        int sourceSize = source.size();
+        int targetSize = target.size();
+        int maxCandidate = sourceSize - targetSize;
+
+        if (sourceSize < INDEXOFSUBLIST_THRESHOLD ||
+            source instanceof RandomAccess) {   // Index access version
+        nextCand:
+            for (int candidate = maxCandidate; candidate >= 0; candidate--) {
+                for (int i=0, j=candidate; i<targetSize; i++, j++)
+                    if (!eq(target.get(i), source.get(j)))
+                        continue nextCand;  // Element mismatch, try next cand
+                return candidate;  // All elements of candidate matched target
+            }
+        } else {  // Iterator version of above algorithm
+            if (maxCandidate < 0)
+                return -1;
+            ListIterator<?> si = source.listIterator(maxCandidate);
+        nextCand:
+            for (int candidate = maxCandidate; candidate >= 0; candidate--) {
+                ListIterator<?> ti = target.listIterator();
+                for (int i=0; i<targetSize; i++) {
+                    if (!eq(ti.next(), si.next())) {
+                        if (candidate != 0) {
+                            // Back up source iterator to next candidate
+                            for (int j=0; j<=i+1; j++)
+                                si.previous();
+                        }
+                        continue nextCand;
+                    }
+                }
+                return candidate;
+            }
+        }
+        return -1;  // No candidate matched the target
+    }
+
+
+    // Unmodifiable Wrappers
+
+    /**
+     * Returns an unmodifiable view of the specified collection.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * collections.  Query operations on the returned collection "read through"
+     * to the specified collection, and attempts to modify the returned
+     * collection, whether direct or via its iterator, result in an
+     * <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned collection does <i>not</i> pass the hashCode and equals
+     * operations through to the backing collection, but relies on
+     * <tt>Object</tt>'s <tt>equals</tt> and <tt>hashCode</tt> methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection for which an unmodifiable view is to be
+     *         returned.
+     * @return an unmodifiable view of the specified collection.
+     */
+    public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c) {
+        return new UnmodifiableCollection<>(c);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableCollection<E> implements Collection<E>, Serializable {
+        private static final long serialVersionUID = 1820017752578914078L;
+
+        final Collection<? extends E> c;
+
+        UnmodifiableCollection(Collection<? extends E> c) {
+            if (c==null)
+                throw new NullPointerException();
+            this.c = c;
+        }
+
+        public int size()                   {return c.size();}
+        public boolean isEmpty()            {return c.isEmpty();}
+        public boolean contains(Object o)   {return c.contains(o);}
+        public Object[] toArray()           {return c.toArray();}
+        public <T> T[] toArray(T[] a)       {return c.toArray(a);}
+        public String toString()            {return c.toString();}
+
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private final Iterator<? extends E> i = c.iterator();
+
+                public boolean hasNext() {return i.hasNext();}
+                public E next()          {return i.next();}
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    // Use backing collection version
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public boolean add(E e) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean containsAll(Collection<?> coll) {
+            return c.containsAll(coll);
+        }
+        public boolean addAll(Collection<? extends E> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean removeAll(Collection<?> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public boolean retainAll(Collection<?> coll) {
+            throw new UnsupportedOperationException();
+        }
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            c.forEach(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Spliterator<E> spliterator() {
+            return (Spliterator<E>)c.spliterator();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Stream<E> stream() {
+            return (Stream<E>)c.stream();
+        }
+        @SuppressWarnings("unchecked")
+        @Override
+        public Stream<E> parallelStream() {
+            return (Stream<E>)c.parallelStream();
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified set.  This method allows
+     * modules to provide users with "read-only" access to internal sets.
+     * Query operations on the returned set "read through" to the specified
+     * set, and attempts to modify the returned set, whether direct or via its
+     * iterator, result in an <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned set will be serializable if the specified set
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the set for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified set.
+     */
+    public static <T> Set<T> unmodifiableSet(Set<? extends T> s) {
+        return new UnmodifiableSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSet<E> extends UnmodifiableCollection<E>
+                                 implements Set<E>, Serializable {
+        private static final long serialVersionUID = -9215047833775013803L;
+
+        UnmodifiableSet(Set<? extends E> s)     {super(s);}
+        public boolean equals(Object o) {return o == this || c.equals(o);}
+        public int hashCode()           {return c.hashCode();}
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified sorted set.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * sorted sets.  Query operations on the returned sorted set "read
+     * through" to the specified sorted set.  Attempts to modify the returned
+     * sorted set, whether direct, via its iterator, or via its
+     * <tt>subSet</tt>, <tt>headSet</tt>, or <tt>tailSet</tt> views, result in
+     * an <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned sorted set will be serializable if the specified sorted set
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param s the sorted set for which an unmodifiable view is to be
+     *        returned.
+     * @return an unmodifiable view of the specified sorted set.
+     */
+    public static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s) {
+        return new UnmodifiableSortedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSortedSet<E>
+                             extends UnmodifiableSet<E>
+                             implements SortedSet<E>, Serializable {
+        private static final long serialVersionUID = -4929149591599911165L;
+        private final SortedSet<E> ss;
+
+        UnmodifiableSortedSet(SortedSet<E> s) {super(s); ss = s;}
+
+        public Comparator<? super E> comparator() {return ss.comparator();}
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return new UnmodifiableSortedSet<>(ss.subSet(fromElement,toElement));
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return new UnmodifiableSortedSet<>(ss.headSet(toElement));
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return new UnmodifiableSortedSet<>(ss.tailSet(fromElement));
+        }
+
+        public E first()                   {return ss.first();}
+        public E last()                    {return ss.last();}
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified navigable set.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * navigable sets.  Query operations on the returned navigable set "read
+     * through" to the specified navigable set.  Attempts to modify the returned
+     * navigable set, whether direct, via its iterator, or via its
+     * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param s the navigable set for which an unmodifiable view is to be
+     *        returned
+     * @return an unmodifiable view of the specified navigable set
+     * @since 1.8
+     */
+    public static <T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s) {
+        return new UnmodifiableNavigableSet<>(s);
+    }
+
+    /**
+     * Wraps a navigable set and disables all of the mutative operations.
+     *
+     * @param <E> type of elements
+     * @serial include
+     */
+    static class UnmodifiableNavigableSet<E>
+                             extends UnmodifiableSortedSet<E>
+                             implements NavigableSet<E>, Serializable {
+
+        private static final long serialVersionUID = -6027448201786391929L;
+
+        /**
+         * A singleton empty unmodifiable navigable set used for
+         * {@link #emptyNavigableSet()}.
+         *
+         * @param <E> type of elements, if there were any, and bounds
+         */
+        private static class EmptyNavigableSet<E> extends UnmodifiableNavigableSet<E>
+            implements Serializable {
+            private static final long serialVersionUID = -6291252904449939134L;
+
+            public EmptyNavigableSet() {
+                super(new TreeSet<E>());
+            }
+
+            private Object readResolve()        { return EMPTY_NAVIGABLE_SET; }
+        }
+
+        @SuppressWarnings("rawtypes")
+        private static final NavigableSet<?> EMPTY_NAVIGABLE_SET =
+                new EmptyNavigableSet<>();
+
+        /**
+         * The instance we are protecting.
+         */
+        private final NavigableSet<E> ns;
+
+        UnmodifiableNavigableSet(NavigableSet<E> s)         {super(s); ns = s;}
+
+        public E lower(E e)                             { return ns.lower(e); }
+        public E floor(E e)                             { return ns.floor(e); }
+        public E ceiling(E e)                         { return ns.ceiling(e); }
+        public E higher(E e)                           { return ns.higher(e); }
+        public E pollFirst()     { throw new UnsupportedOperationException(); }
+        public E pollLast()      { throw new UnsupportedOperationException(); }
+        public NavigableSet<E> descendingSet()
+                 { return new UnmodifiableNavigableSet<>(ns.descendingSet()); }
+        public Iterator<E> descendingIterator()
+                                         { return descendingSet().iterator(); }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.subSet(fromElement, fromInclusive, toElement, toInclusive));
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.headSet(toElement, inclusive));
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return new UnmodifiableNavigableSet<>(
+                ns.tailSet(fromElement, inclusive));
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified list.  This method allows
+     * modules to provide users with "read-only" access to internal
+     * lists.  Query operations on the returned list "read through" to the
+     * specified list, and attempts to modify the returned list, whether
+     * direct or via its iterator, result in an
+     * <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned list will be serializable if the specified list
+     * is serializable. Similarly, the returned list will implement
+     * {@link RandomAccess} if the specified list does.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified list.
+     */
+    public static <T> List<T> unmodifiableList(List<? extends T> list) {
+        return (list instanceof RandomAccess ?
+                new UnmodifiableRandomAccessList<>(list) :
+                new UnmodifiableList<>(list));
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableList<E> extends UnmodifiableCollection<E>
+                                  implements List<E> {
+        private static final long serialVersionUID = -283967356065247728L;
+
+        final List<? extends E> list;
+
+        UnmodifiableList(List<? extends E> list) {
+            super(list);
+            this.list = list;
+        }
+
+        public boolean equals(Object o) {return o == this || list.equals(o);}
+        public int hashCode()           {return list.hashCode();}
+
+        public E get(int index) {return list.get(index);}
+        public E set(int index, E element) {
+            throw new UnsupportedOperationException();
+        }
+        public void add(int index, E element) {
+            throw new UnsupportedOperationException();
+        }
+        public E remove(int index) {
+            throw new UnsupportedOperationException();
+        }
+        public int indexOf(Object o)            {return list.indexOf(o);}
+        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
+        public boolean addAll(int index, Collection<? extends E> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public ListIterator<E> listIterator()   {return listIterator(0);}
+
+        public ListIterator<E> listIterator(final int index) {
+            return new ListIterator<E>() {
+                private final ListIterator<? extends E> i
+                    = list.listIterator(index);
+
+                public boolean hasNext()     {return i.hasNext();}
+                public E next()              {return i.next();}
+                public boolean hasPrevious() {return i.hasPrevious();}
+                public E previous()          {return i.previous();}
+                public int nextIndex()       {return i.nextIndex();}
+                public int previousIndex()   {return i.previousIndex();}
+
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+                public void set(E e) {
+                    throw new UnsupportedOperationException();
+                }
+                public void add(E e) {
+                    throw new UnsupportedOperationException();
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new UnmodifiableList<>(list.subList(fromIndex, toIndex));
+        }
+
+        /**
+         * UnmodifiableRandomAccessList instances are serialized as
+         * UnmodifiableList instances to allow them to be deserialized
+         * in pre-1.4 JREs (which do not have UnmodifiableRandomAccessList).
+         * This method inverts the transformation.  As a beneficial
+         * side-effect, it also grafts the RandomAccess marker onto
+         * UnmodifiableList instances that were serialized in pre-1.4 JREs.
+         *
+         * Note: Unfortunately, UnmodifiableRandomAccessList instances
+         * serialized in 1.4.1 and deserialized in 1.4 will become
+         * UnmodifiableList instances, as this method was missing in 1.4.
+         */
+        private Object readResolve() {
+            return (list instanceof RandomAccess
+                    ? new UnmodifiableRandomAccessList<>(list)
+                    : this);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableRandomAccessList<E> extends UnmodifiableList<E>
+                                              implements RandomAccess
+    {
+        UnmodifiableRandomAccessList(List<? extends E> list) {
+            super(list);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new UnmodifiableRandomAccessList<>(
+                list.subList(fromIndex, toIndex));
+        }
+
+        private static final long serialVersionUID = -2542308836966382001L;
+
+        /**
+         * Allows instances to be deserialized in pre-1.4 JREs (which do
+         * not have UnmodifiableRandomAccessList).  UnmodifiableList has
+         * a readResolve method that inverts this transformation upon
+         * deserialization.
+         */
+        private Object writeReplace() {
+            return new UnmodifiableList<>(list);
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified map.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * maps.  Query operations on the returned map "read through"
+     * to the specified map, and attempts to modify the returned
+     * map, whether direct or via its collection views, result in an
+     * <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned map will be serializable if the specified map
+     * is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map for which an unmodifiable view is to be returned.
+     * @return an unmodifiable view of the specified map.
+     */
+    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {
+        return new UnmodifiableMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {
+        private static final long serialVersionUID = -1034234728574286014L;
+
+        private final Map<? extends K, ? extends V> m;
+
+        UnmodifiableMap(Map<? extends K, ? extends V> m) {
+            if (m==null)
+                throw new NullPointerException();
+            this.m = m;
+        }
+
+        public int size()                        {return m.size();}
+        public boolean isEmpty()                 {return m.isEmpty();}
+        public boolean containsKey(Object key)   {return m.containsKey(key);}
+        public boolean containsValue(Object val) {return m.containsValue(val);}
+        public V get(Object key)                 {return m.get(key);}
+
+        public V put(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+        public V remove(Object key) {
+            throw new UnsupportedOperationException();
+        }
+        public void putAll(Map<? extends K, ? extends V> m) {
+            throw new UnsupportedOperationException();
+        }
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            if (keySet==null)
+                keySet = unmodifiableSet(m.keySet());
+            return keySet;
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = new UnmodifiableEntrySet<>(m.entrySet());
+            return entrySet;
+        }
+
+        public Collection<V> values() {
+            if (values==null)
+                values = unmodifiableCollection(m.values());
+            return values;
+        }
+
+        public boolean equals(Object o) {return o == this || m.equals(o);}
+        public int hashCode()           {return m.hashCode();}
+        public String toString()        {return m.toString();}
+
+        // Override default methods in Map
+        @Override
+        @SuppressWarnings("unchecked")
+        public V getOrDefault(Object k, V defaultValue) {
+            // Safe cast as we don't change the value
+            return ((Map<K, V>)m).getOrDefault(k, defaultValue);
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * We need this class in addition to UnmodifiableSet as
+         * Map.Entries themselves permit modification of the backing Map
+         * via their setValue operation.  This class is subtle: there are
+         * many possible attacks that must be thwarted.
+         *
+         * @serial include
+         */
+        static class UnmodifiableEntrySet<K,V>
+            extends UnmodifiableSet<Map.Entry<K,V>> {
+            private static final long serialVersionUID = 7854390611657943733L;
+
+            @SuppressWarnings({"unchecked", "rawtypes"})
+            UnmodifiableEntrySet(Set<? extends Map.Entry<? extends K, ? extends V>> s) {
+                // Need to cast to raw in order to work around a limitation in the type system
+                super((Set)s);
+            }
+
+            static <K, V> Consumer<Map.Entry<K, V>> entryConsumer(Consumer<? super Entry<K, V>> action) {
+                return e -> action.accept(new UnmodifiableEntry<>(e));
+            }
+
+            public void forEach(Consumer<? super Entry<K, V>> action) {
+                Objects.requireNonNull(action);
+                c.forEach(entryConsumer(action));
+            }
+
+            static final class UnmodifiableEntrySetSpliterator<K, V>
+                    implements Spliterator<Entry<K,V>> {
+                final Spliterator<Map.Entry<K, V>> s;
+
+                UnmodifiableEntrySetSpliterator(Spliterator<Entry<K, V>> s) {
+                    this.s = s;
+                }
+
+                @Override
+                public boolean tryAdvance(Consumer<? super Entry<K, V>> action) {
+                    Objects.requireNonNull(action);
+                    return s.tryAdvance(entryConsumer(action));
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super Entry<K, V>> action) {
+                    Objects.requireNonNull(action);
+                    s.forEachRemaining(entryConsumer(action));
+                }
+
+                @Override
+                public Spliterator<Entry<K, V>> trySplit() {
+                    Spliterator<Entry<K, V>> split = s.trySplit();
+                    return split == null
+                           ? null
+                           : new UnmodifiableEntrySetSpliterator<>(split);
+                }
+
+                @Override
+                public long estimateSize() {
+                    return s.estimateSize();
+                }
+
+                @Override
+                public long getExactSizeIfKnown() {
+                    return s.getExactSizeIfKnown();
+                }
+
+                @Override
+                public int characteristics() {
+                    return s.characteristics();
+                }
+
+                @Override
+                public boolean hasCharacteristics(int characteristics) {
+                    return s.hasCharacteristics(characteristics);
+                }
+
+                @Override
+                public Comparator<? super Entry<K, V>> getComparator() {
+                    return s.getComparator();
+                }
+            }
+
+            @SuppressWarnings("unchecked")
+            public Spliterator<Entry<K,V>> spliterator() {
+                return new UnmodifiableEntrySetSpliterator<>(
+                        (Spliterator<Map.Entry<K, V>>) c.spliterator());
+            }
+
+            @Override
+            public Stream<Entry<K,V>> stream() {
+                return StreamSupport.stream(spliterator(), false);
+            }
+
+            @Override
+            public Stream<Entry<K,V>> parallelStream() {
+                return StreamSupport.stream(spliterator(), true);
+            }
+
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new Iterator<Map.Entry<K,V>>() {
+                    private final Iterator<? extends Map.Entry<? extends K, ? extends V>> i = c.iterator();
+
+                    public boolean hasNext() {
+                        return i.hasNext();
+                    }
+                    public Map.Entry<K,V> next() {
+                        return new UnmodifiableEntry<>(i.next());
+                    }
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                    // Android-note: Oversight of Iterator.forEachRemaining().
+                    // This seems pretty inconsistent. Unlike other subclasses,
+                    // we aren't delegating to the subclass iterator here.
+                    // Seems like an oversight. http://b/110351017
+                };
+            }
+
+            @SuppressWarnings("unchecked")
+            public Object[] toArray() {
+                Object[] a = c.toArray();
+                for (int i=0; i<a.length; i++)
+                    a[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>)a[i]);
+                return a;
+            }
+
+            @SuppressWarnings("unchecked")
+            public <T> T[] toArray(T[] a) {
+                // We don't pass a to c.toArray, to avoid window of
+                // vulnerability wherein an unscrupulous multithreaded client
+                // could get his hands on raw (unwrapped) Entries from c.
+                Object[] arr = c.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
+
+                for (int i=0; i<arr.length; i++)
+                    arr[i] = new UnmodifiableEntry<>((Map.Entry<? extends K, ? extends V>)arr[i]);
+
+                if (arr.length > a.length)
+                    return (T[])arr;
+
+                System.arraycopy(arr, 0, a, 0, arr.length);
+                if (a.length > arr.length)
+                    a[arr.length] = null;
+                return a;
+            }
+
+            /**
+             * This method is overridden to protect the backing set against
+             * an object with a nefarious equals function that senses
+             * that the equality-candidate is Map.Entry and calls its
+             * setValue method.
+             */
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                return c.contains(
+                    new UnmodifiableEntry<>((Map.Entry<?,?>) o));
+            }
+
+            /**
+             * The next two methods are overridden to protect against
+             * an unscrupulous List whose contains(Object o) method senses
+             * when o is a Map.Entry, and calls o.setValue.
+             */
+            public boolean containsAll(Collection<?> coll) {
+                for (Object e : coll) {
+                    if (!contains(e)) // Invokes safe contains() above
+                        return false;
+                }
+                return true;
+            }
+            public boolean equals(Object o) {
+                if (o == this)
+                    return true;
+
+                if (!(o instanceof Set))
+                    return false;
+                Set<?> s = (Set<?>) o;
+                if (s.size() != c.size())
+                    return false;
+                return containsAll(s); // Invokes safe containsAll() above
+            }
+
+            /**
+             * This "wrapper class" serves two purposes: it prevents
+             * the client from modifying the backing Map, by short-circuiting
+             * the setValue method, and it protects the backing Map against
+             * an ill-behaved Map.Entry that attempts to modify another
+             * Map Entry when asked to perform an equality check.
+             */
+            private static class UnmodifiableEntry<K,V> implements Map.Entry<K,V> {
+                private Map.Entry<? extends K, ? extends V> e;
+
+                UnmodifiableEntry(Map.Entry<? extends K, ? extends V> e)
+                        {this.e = Objects.requireNonNull(e);}
+
+                public K getKey()        {return e.getKey();}
+                public V getValue()      {return e.getValue();}
+                public V setValue(V value) {
+                    throw new UnsupportedOperationException();
+                }
+                public int hashCode()    {return e.hashCode();}
+                public boolean equals(Object o) {
+                    if (this == o)
+                        return true;
+                    if (!(o instanceof Map.Entry))
+                        return false;
+                    Map.Entry<?,?> t = (Map.Entry<?,?>)o;
+                    return eq(e.getKey(),   t.getKey()) &&
+                           eq(e.getValue(), t.getValue());
+                }
+                public String toString() {return e.toString();}
+            }
+        }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified sorted map.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * sorted maps.  Query operations on the returned sorted map "read through"
+     * to the specified sorted map.  Attempts to modify the returned
+     * sorted map, whether direct, via its collection views, or via its
+     * <tt>subMap</tt>, <tt>headMap</tt>, or <tt>tailMap</tt> views, result in
+     * an <tt>UnsupportedOperationException</tt>.<p>
+     *
+     * The returned sorted map will be serializable if the specified sorted map
+     * is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the sorted map for which an unmodifiable view is to be
+     *        returned.
+     * @return an unmodifiable view of the specified sorted map.
+     */
+    public static <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K, ? extends V> m) {
+        return new UnmodifiableSortedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableSortedMap<K,V>
+          extends UnmodifiableMap<K,V>
+          implements SortedMap<K,V>, Serializable {
+        private static final long serialVersionUID = -8806743815996713206L;
+
+        private final SortedMap<K, ? extends V> sm;
+
+        UnmodifiableSortedMap(SortedMap<K, ? extends V> m) {super(m); sm = m; }
+        public Comparator<? super K> comparator()   { return sm.comparator(); }
+        public SortedMap<K,V> subMap(K fromKey, K toKey)
+             { return new UnmodifiableSortedMap<>(sm.subMap(fromKey, toKey)); }
+        public SortedMap<K,V> headMap(K toKey)
+                     { return new UnmodifiableSortedMap<>(sm.headMap(toKey)); }
+        public SortedMap<K,V> tailMap(K fromKey)
+                   { return new UnmodifiableSortedMap<>(sm.tailMap(fromKey)); }
+        public K firstKey()                           { return sm.firstKey(); }
+        public K lastKey()                             { return sm.lastKey(); }
+    }
+
+    /**
+     * Returns an unmodifiable view of the specified navigable map.  This method
+     * allows modules to provide users with "read-only" access to internal
+     * navigable maps.  Query operations on the returned navigable map "read
+     * through" to the specified navigable map.  Attempts to modify the returned
+     * navigable map, whether direct, via its collection views, or via its
+     * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
+     * an {@code UnsupportedOperationException}.<p>
+     *
+     * The returned navigable map will be serializable if the specified
+     * navigable map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the navigable map for which an unmodifiable view is to be
+     *        returned
+     * @return an unmodifiable view of the specified navigable map
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> unmodifiableNavigableMap(NavigableMap<K, ? extends V> m) {
+        return new UnmodifiableNavigableMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class UnmodifiableNavigableMap<K,V>
+          extends UnmodifiableSortedMap<K,V>
+          implements NavigableMap<K,V>, Serializable {
+        private static final long serialVersionUID = -4858195264774772197L;
+
+        /**
+         * A class for the {@link EMPTY_NAVIGABLE_MAP} which needs readResolve
+         * to preserve singleton property.
+         *
+         * @param <K> type of keys, if there were any, and of bounds
+         * @param <V> type of values, if there were any
+         */
+        private static class EmptyNavigableMap<K,V> extends UnmodifiableNavigableMap<K,V>
+            implements Serializable {
+
+            private static final long serialVersionUID = -2239321462712562324L;
+
+            EmptyNavigableMap()                       { super(new TreeMap<K,V>()); }
+
+            @Override
+            public NavigableSet<K> navigableKeySet()
+                                                { return emptyNavigableSet(); }
+
+            private Object readResolve()        { return EMPTY_NAVIGABLE_MAP; }
+        }
+
+        /**
+         * Singleton for {@link emptyNavigableMap()} which is also immutable.
+         */
+        private static final EmptyNavigableMap<?,?> EMPTY_NAVIGABLE_MAP =
+            new EmptyNavigableMap<>();
+
+        /**
+         * The instance we wrap and protect.
+         */
+        private final NavigableMap<K, ? extends V> nm;
+
+        UnmodifiableNavigableMap(NavigableMap<K, ? extends V> m)
+                                                            {super(m); nm = m;}
+
+        public K lowerKey(K key)                   { return nm.lowerKey(key); }
+        public K floorKey(K key)                   { return nm.floorKey(key); }
+        public K ceilingKey(K key)               { return nm.ceilingKey(key); }
+        public K higherKey(K key)                 { return nm.higherKey(key); }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> lowerEntry(K key) {
+            Entry<K,V> lower = (Entry<K, V>) nm.lowerEntry(key);
+            return (null != lower)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(lower)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> floorEntry(K key) {
+            Entry<K,V> floor = (Entry<K, V>) nm.floorEntry(key);
+            return (null != floor)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(floor)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> ceilingEntry(K key) {
+            Entry<K,V> ceiling = (Entry<K, V>) nm.ceilingEntry(key);
+            return (null != ceiling)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(ceiling)
+                : null;
+        }
+
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> higherEntry(K key) {
+            Entry<K,V> higher = (Entry<K, V>) nm.higherEntry(key);
+            return (null != higher)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(higher)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> firstEntry() {
+            Entry<K,V> first = (Entry<K, V>) nm.firstEntry();
+            return (null != first)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(first)
+                : null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public Entry<K, V> lastEntry() {
+            Entry<K,V> last = (Entry<K, V>) nm.lastEntry();
+            return (null != last)
+                ? new UnmodifiableEntrySet.UnmodifiableEntry<>(last)
+                : null;
+        }
+
+        public Entry<K, V> pollFirstEntry()
+                                 { throw new UnsupportedOperationException(); }
+        public Entry<K, V> pollLastEntry()
+                                 { throw new UnsupportedOperationException(); }
+        public NavigableMap<K, V> descendingMap()
+                       { return unmodifiableNavigableMap(nm.descendingMap()); }
+        public NavigableSet<K> navigableKeySet()
+                     { return unmodifiableNavigableSet(nm.navigableKeySet()); }
+        public NavigableSet<K> descendingKeySet()
+                    { return unmodifiableNavigableSet(nm.descendingKeySet()); }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            return unmodifiableNavigableMap(
+                nm.subMap(fromKey, fromInclusive, toKey, toInclusive));
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive)
+             { return unmodifiableNavigableMap(nm.headMap(toKey, inclusive)); }
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive)
+           { return unmodifiableNavigableMap(nm.tailMap(fromKey, inclusive)); }
+    }
+
+    // Synch Wrappers
+
+    /**
+     * Returns a synchronized (thread-safe) collection backed by the specified
+     * collection.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing collection is accomplished
+     * through the returned collection.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * collection when traversing it via {@link Iterator}, {@link Spliterator}
+     * or {@link Stream}:
+     * <pre>
+     *  Collection c = Collections.synchronizedCollection(myCollection);
+     *     ...
+     *  synchronized (c) {
+     *      Iterator i = c.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *         foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned collection does <i>not</i> pass the {@code hashCode}
+     * and {@code equals} operations through to the backing collection, but
+     * relies on {@code Object}'s equals and hashCode methods.  This is
+     * necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.<p>
+     *
+     * The returned collection will be serializable if the specified collection
+     * is serializable.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param  c the collection to be "wrapped" in a synchronized collection.
+     * @return a synchronized view of the specified collection.
+     */
+    public static <T> Collection<T> synchronizedCollection(Collection<T> c) {
+        return new SynchronizedCollection<>(c);
+    }
+
+    static <T> Collection<T> synchronizedCollection(Collection<T> c, Object mutex) {
+        return new SynchronizedCollection<>(c, mutex);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedCollection<E> implements Collection<E>, Serializable {
+        private static final long serialVersionUID = 3053995032091335093L;
+
+        final Collection<E> c;  // Backing Collection
+        final Object mutex;     // Object on which to synchronize
+
+        SynchronizedCollection(Collection<E> c) {
+            this.c = Objects.requireNonNull(c);
+            mutex = this;
+        }
+
+        SynchronizedCollection(Collection<E> c, Object mutex) {
+            this.c = Objects.requireNonNull(c);
+            this.mutex = Objects.requireNonNull(mutex);
+        }
+
+        public int size() {
+            synchronized (mutex) {return c.size();}
+        }
+        public boolean isEmpty() {
+            synchronized (mutex) {return c.isEmpty();}
+        }
+        public boolean contains(Object o) {
+            synchronized (mutex) {return c.contains(o);}
+        }
+        public Object[] toArray() {
+            synchronized (mutex) {return c.toArray();}
+        }
+        public <T> T[] toArray(T[] a) {
+            synchronized (mutex) {return c.toArray(a);}
+        }
+
+        public Iterator<E> iterator() {
+            return c.iterator(); // Must be manually synched by user!
+        }
+
+        public boolean add(E e) {
+            synchronized (mutex) {return c.add(e);}
+        }
+        public boolean remove(Object o) {
+            synchronized (mutex) {return c.remove(o);}
+        }
+
+        public boolean containsAll(Collection<?> coll) {
+            synchronized (mutex) {return c.containsAll(coll);}
+        }
+        public boolean addAll(Collection<? extends E> coll) {
+            synchronized (mutex) {return c.addAll(coll);}
+        }
+        public boolean removeAll(Collection<?> coll) {
+            synchronized (mutex) {return c.removeAll(coll);}
+        }
+        public boolean retainAll(Collection<?> coll) {
+            synchronized (mutex) {return c.retainAll(coll);}
+        }
+        public void clear() {
+            synchronized (mutex) {c.clear();}
+        }
+        public String toString() {
+            synchronized (mutex) {return c.toString();}
+        }
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> consumer) {
+            synchronized (mutex) {c.forEach(consumer);}
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            synchronized (mutex) {return c.removeIf(filter);}
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return c.spliterator(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> stream() {
+            return c.stream(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> parallelStream() {
+            return c.parallelStream(); // Must be manually synched by user!
+        }
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            synchronized (mutex) {s.defaultWriteObject();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) set backed by the specified
+     * set.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing set is accomplished
+     * through the returned set.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * set when iterating over it:
+     * <pre>
+     *  Set s = Collections.synchronizedSet(new HashSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned set will be serializable if the specified set is
+     * serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the set to be "wrapped" in a synchronized set.
+     * @return a synchronized view of the specified set.
+     */
+    public static <T> Set<T> synchronizedSet(Set<T> s) {
+        return new SynchronizedSet<>(s);
+    }
+
+    static <T> Set<T> synchronizedSet(Set<T> s, Object mutex) {
+        return new SynchronizedSet<>(s, mutex);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSet<E>
+          extends SynchronizedCollection<E>
+          implements Set<E> {
+        private static final long serialVersionUID = 487447009682186044L;
+
+        SynchronizedSet(Set<E> s) {
+            super(s);
+        }
+        SynchronizedSet(Set<E> s, Object mutex) {
+            super(s, mutex);
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return c.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return c.hashCode();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) sorted set backed by the specified
+     * sorted set.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing sorted set is accomplished
+     * through the returned sorted set (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * sorted set when iterating over it or any of its <tt>subSet</tt>,
+     * <tt>headSet</tt>, or <tt>tailSet</tt> views.
+     * <pre>
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  SortedSet s = Collections.synchronizedSortedSet(new TreeSet());
+     *  SortedSet s2 = s.headSet(foo);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned sorted set will be serializable if the specified
+     * sorted set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the sorted set to be "wrapped" in a synchronized sorted set.
+     * @return a synchronized view of the specified sorted set.
+     */
+    public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) {
+        return new SynchronizedSortedSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSortedSet<E>
+        extends SynchronizedSet<E>
+        implements SortedSet<E>
+    {
+        private static final long serialVersionUID = 8695801310862127406L;
+
+        private final SortedSet<E> ss;
+
+        SynchronizedSortedSet(SortedSet<E> s) {
+            super(s);
+            ss = s;
+        }
+        SynchronizedSortedSet(SortedSet<E> s, Object mutex) {
+            super(s, mutex);
+            ss = s;
+        }
+
+        public Comparator<? super E> comparator() {
+            synchronized (mutex) {return ss.comparator();}
+        }
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedSortedSet<>(
+                    ss.subSet(fromElement, toElement), mutex);
+            }
+        }
+        public SortedSet<E> headSet(E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedSortedSet<>(ss.headSet(toElement), mutex);
+            }
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            synchronized (mutex) {
+               return new SynchronizedSortedSet<>(ss.tailSet(fromElement),mutex);
+            }
+        }
+
+        public E first() {
+            synchronized (mutex) {return ss.first();}
+        }
+        public E last() {
+            synchronized (mutex) {return ss.last();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) navigable set backed by the
+     * specified navigable set.  In order to guarantee serial access, it is
+     * critical that <strong>all</strong> access to the backing navigable set is
+     * accomplished through the returned navigable set (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * navigable set when iterating over it or any of its {@code subSet},
+     * {@code headSet}, or {@code tailSet} views.
+     * <pre>
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *      ...
+     *  synchronized (s) {
+     *      Iterator i = s.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  NavigableSet s = Collections.synchronizedNavigableSet(new TreeSet());
+     *  NavigableSet s2 = s.headSet(foo, true);
+     *      ...
+     *  synchronized (s) {  // Note: s, not s2!!!
+     *      Iterator i = s2.iterator(); // Must be in the synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param  s the navigable set to be "wrapped" in a synchronized navigable
+     * set
+     * @return a synchronized view of the specified navigable set
+     * @since 1.8
+     */
+    public static <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s) {
+        return new SynchronizedNavigableSet<>(s);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedNavigableSet<E>
+        extends SynchronizedSortedSet<E>
+        implements NavigableSet<E>
+    {
+        private static final long serialVersionUID = -5505529816273629798L;
+
+        private final NavigableSet<E> ns;
+
+        SynchronizedNavigableSet(NavigableSet<E> s) {
+            super(s);
+            ns = s;
+        }
+
+        SynchronizedNavigableSet(NavigableSet<E> s, Object mutex) {
+            super(s, mutex);
+            ns = s;
+        }
+        public E lower(E e)      { synchronized (mutex) {return ns.lower(e);} }
+        public E floor(E e)      { synchronized (mutex) {return ns.floor(e);} }
+        public E ceiling(E e)  { synchronized (mutex) {return ns.ceiling(e);} }
+        public E higher(E e)    { synchronized (mutex) {return ns.higher(e);} }
+        public E pollFirst()  { synchronized (mutex) {return ns.pollFirst();} }
+        public E pollLast()    { synchronized (mutex) {return ns.pollLast();} }
+
+        public NavigableSet<E> descendingSet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.descendingSet(), mutex);
+            }
+        }
+
+        public Iterator<E> descendingIterator()
+                 { synchronized (mutex) { return descendingSet().iterator(); } }
+
+        public NavigableSet<E> subSet(E fromElement, E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.subSet(fromElement, true, toElement, false), mutex);
+            }
+        }
+        public NavigableSet<E> headSet(E toElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.headSet(toElement, false), mutex);
+            }
+        }
+        public NavigableSet<E> tailSet(E fromElement) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, true), mutex);
+            }
+        }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), mutex);
+            }
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.headSet(toElement, inclusive), mutex);
+            }
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(ns.tailSet(fromElement, inclusive), mutex);
+            }
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) list backed by the specified
+     * list.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing list is accomplished
+     * through the returned list.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * list when iterating over it:
+     * <pre>
+     *  List list = Collections.synchronizedList(new ArrayList());
+     *      ...
+     *  synchronized (list) {
+     *      Iterator i = list.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned list will be serializable if the specified list is
+     * serializable.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param  list the list to be "wrapped" in a synchronized list.
+     * @return a synchronized view of the specified list.
+     */
+    public static <T> List<T> synchronizedList(List<T> list) {
+        return (list instanceof RandomAccess ?
+                new SynchronizedRandomAccessList<>(list) :
+                new SynchronizedList<>(list));
+    }
+
+    static <T> List<T> synchronizedList(List<T> list, Object mutex) {
+        return (list instanceof RandomAccess ?
+                new SynchronizedRandomAccessList<>(list, mutex) :
+                new SynchronizedList<>(list, mutex));
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedList<E>
+        extends SynchronizedCollection<E>
+        implements List<E> {
+        private static final long serialVersionUID = -7754090372962971524L;
+
+        final List<E> list;
+
+        SynchronizedList(List<E> list) {
+            super(list);
+            this.list = list;
+        }
+        SynchronizedList(List<E> list, Object mutex) {
+            super(list, mutex);
+            this.list = list;
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return list.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return list.hashCode();}
+        }
+
+        public E get(int index) {
+            synchronized (mutex) {return list.get(index);}
+        }
+        public E set(int index, E element) {
+            synchronized (mutex) {return list.set(index, element);}
+        }
+        public void add(int index, E element) {
+            synchronized (mutex) {list.add(index, element);}
+        }
+        public E remove(int index) {
+            synchronized (mutex) {return list.remove(index);}
+        }
+
+        public int indexOf(Object o) {
+            synchronized (mutex) {return list.indexOf(o);}
+        }
+        public int lastIndexOf(Object o) {
+            synchronized (mutex) {return list.lastIndexOf(o);}
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            synchronized (mutex) {return list.addAll(index, c);}
+        }
+
+        public ListIterator<E> listIterator() {
+            return list.listIterator(); // Must be manually synched by user
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            return list.listIterator(index); // Must be manually synched by user
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (mutex) {
+                return new SynchronizedList<>(list.subList(fromIndex, toIndex),
+                                            mutex);
+            }
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            synchronized (mutex) {list.replaceAll(operator);}
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+            synchronized (mutex) {list.sort(c);}
+        }
+
+        /**
+         * SynchronizedRandomAccessList instances are serialized as
+         * SynchronizedList instances to allow them to be deserialized
+         * in pre-1.4 JREs (which do not have SynchronizedRandomAccessList).
+         * This method inverts the transformation.  As a beneficial
+         * side-effect, it also grafts the RandomAccess marker onto
+         * SynchronizedList instances that were serialized in pre-1.4 JREs.
+         *
+         * Note: Unfortunately, SynchronizedRandomAccessList instances
+         * serialized in 1.4.1 and deserialized in 1.4 will become
+         * SynchronizedList instances, as this method was missing in 1.4.
+         */
+        private Object readResolve() {
+            return (list instanceof RandomAccess
+                    ? new SynchronizedRandomAccessList<>(list)
+                    : this);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedRandomAccessList<E>
+        extends SynchronizedList<E>
+        implements RandomAccess {
+
+        SynchronizedRandomAccessList(List<E> list) {
+            super(list);
+        }
+
+        SynchronizedRandomAccessList(List<E> list, Object mutex) {
+            super(list, mutex);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (mutex) {
+                return new SynchronizedRandomAccessList<>(
+                    list.subList(fromIndex, toIndex), mutex);
+            }
+        }
+
+        private static final long serialVersionUID = 1530674583602358482L;
+
+        /**
+         * Allows instances to be deserialized in pre-1.4 JREs (which do
+         * not have SynchronizedRandomAccessList).  SynchronizedList has
+         * a readResolve method that inverts this transformation upon
+         * deserialization.
+         */
+        private Object writeReplace() {
+            return new SynchronizedList<>(list);
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) map backed by the specified
+     * map.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing map is accomplished
+     * through the returned map.<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * map when iterating over any of its collection views:
+     * <pre>
+     *  Map m = Collections.synchronizedMap(new HashMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the map to be "wrapped" in a synchronized map.
+     * @return a synchronized view of the specified map.
+     */
+    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
+        return new SynchronizedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SynchronizedMap<K,V>
+        implements Map<K,V>, Serializable {
+        private static final long serialVersionUID = 1978198479659022715L;
+
+        private final Map<K,V> m;     // Backing Map
+        final Object      mutex;        // Object on which to synchronize
+
+        SynchronizedMap(Map<K,V> m) {
+            this.m = Objects.requireNonNull(m);
+            mutex = this;
+        }
+
+        SynchronizedMap(Map<K,V> m, Object mutex) {
+            this.m = m;
+            this.mutex = mutex;
+        }
+
+        public int size() {
+            synchronized (mutex) {return m.size();}
+        }
+        public boolean isEmpty() {
+            synchronized (mutex) {return m.isEmpty();}
+        }
+        public boolean containsKey(Object key) {
+            synchronized (mutex) {return m.containsKey(key);}
+        }
+        public boolean containsValue(Object value) {
+            synchronized (mutex) {return m.containsValue(value);}
+        }
+        public V get(Object key) {
+            synchronized (mutex) {return m.get(key);}
+        }
+
+        public V put(K key, V value) {
+            synchronized (mutex) {return m.put(key, value);}
+        }
+        public V remove(Object key) {
+            synchronized (mutex) {return m.remove(key);}
+        }
+        public void putAll(Map<? extends K, ? extends V> map) {
+            synchronized (mutex) {m.putAll(map);}
+        }
+        public void clear() {
+            synchronized (mutex) {m.clear();}
+        }
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            synchronized (mutex) {
+                if (keySet==null)
+                    keySet = new SynchronizedSet<>(m.keySet(), mutex);
+                return keySet;
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            synchronized (mutex) {
+                if (entrySet==null)
+                    entrySet = new SynchronizedSet<>(m.entrySet(), mutex);
+                return entrySet;
+            }
+        }
+
+        public Collection<V> values() {
+            synchronized (mutex) {
+                if (values==null)
+                    values = new SynchronizedCollection<>(m.values(), mutex);
+                return values;
+            }
+        }
+
+        public boolean equals(Object o) {
+            if (this == o)
+                return true;
+            synchronized (mutex) {return m.equals(o);}
+        }
+        public int hashCode() {
+            synchronized (mutex) {return m.hashCode();}
+        }
+        public String toString() {
+            synchronized (mutex) {return m.toString();}
+        }
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object k, V defaultValue) {
+            synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
+        }
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            synchronized (mutex) {m.forEach(action);}
+        }
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            synchronized (mutex) {m.replaceAll(function);}
+        }
+        @Override
+        public V putIfAbsent(K key, V value) {
+            synchronized (mutex) {return m.putIfAbsent(key, value);}
+        }
+        @Override
+        public boolean remove(Object key, Object value) {
+            synchronized (mutex) {return m.remove(key, value);}
+        }
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            synchronized (mutex) {return m.replace(key, oldValue, newValue);}
+        }
+        @Override
+        public V replace(K key, V value) {
+            synchronized (mutex) {return m.replace(key, value);}
+        }
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
+        }
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
+        }
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.compute(key, remappingFunction);}
+        }
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            synchronized (mutex) {return m.merge(key, value, remappingFunction);}
+        }
+
+        private void writeObject(ObjectOutputStream s) throws IOException {
+            synchronized (mutex) {s.defaultWriteObject();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) sorted map backed by the specified
+     * sorted map.  In order to guarantee serial access, it is critical that
+     * <strong>all</strong> access to the backing sorted map is accomplished
+     * through the returned sorted map (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * sorted map when iterating over any of its collection views, or the
+     * collections views of any of its <tt>subMap</tt>, <tt>headMap</tt> or
+     * <tt>tailMap</tt> views.
+     * <pre>
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  SortedMap m = Collections.synchronizedSortedMap(new TreeMap());
+     *  SortedMap m2 = m.subMap(foo, bar);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned sorted map will be serializable if the specified
+     * sorted map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the sorted map to be "wrapped" in a synchronized sorted map.
+     * @return a synchronized view of the specified sorted map.
+     */
+    public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m) {
+        return new SynchronizedSortedMap<>(m);
+    }
+
+    /**
+     * @serial include
+     */
+    static class SynchronizedSortedMap<K,V>
+        extends SynchronizedMap<K,V>
+        implements SortedMap<K,V>
+    {
+        private static final long serialVersionUID = -8798146769416483793L;
+
+        private final SortedMap<K,V> sm;
+
+        SynchronizedSortedMap(SortedMap<K,V> m) {
+            super(m);
+            sm = m;
+        }
+        SynchronizedSortedMap(SortedMap<K,V> m, Object mutex) {
+            super(m, mutex);
+            sm = m;
+        }
+
+        public Comparator<? super K> comparator() {
+            synchronized (mutex) {return sm.comparator();}
+        }
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedSortedMap<>(
+                    sm.subMap(fromKey, toKey), mutex);
+            }
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedSortedMap<>(sm.headMap(toKey), mutex);
+            }
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            synchronized (mutex) {
+               return new SynchronizedSortedMap<>(sm.tailMap(fromKey),mutex);
+            }
+        }
+
+        public K firstKey() {
+            synchronized (mutex) {return sm.firstKey();}
+        }
+        public K lastKey() {
+            synchronized (mutex) {return sm.lastKey();}
+        }
+    }
+
+    /**
+     * Returns a synchronized (thread-safe) navigable map backed by the
+     * specified navigable map.  In order to guarantee serial access, it is
+     * critical that <strong>all</strong> access to the backing navigable map is
+     * accomplished through the returned navigable map (or its views).<p>
+     *
+     * It is imperative that the user manually synchronize on the returned
+     * navigable map when iterating over any of its collection views, or the
+     * collections views of any of its {@code subMap}, {@code headMap} or
+     * {@code tailMap} views.
+     * <pre>
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *      ...
+     *  Set s = m.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not s!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * or:
+     * <pre>
+     *  NavigableMap m = Collections.synchronizedNavigableMap(new TreeMap());
+     *  NavigableMap m2 = m.subMap(foo, true, bar, false);
+     *      ...
+     *  Set s2 = m2.keySet();  // Needn't be in synchronized block
+     *      ...
+     *  synchronized (m) {  // Synchronizing on m, not m2 or s2!
+     *      Iterator i = s.iterator(); // Must be in synchronized block
+     *      while (i.hasNext())
+     *          foo(i.next());
+     *  }
+     * </pre>
+     * Failure to follow this advice may result in non-deterministic behavior.
+     *
+     * <p>The returned navigable map will be serializable if the specified
+     * navigable map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param  m the navigable map to be "wrapped" in a synchronized navigable
+     *              map
+     * @return a synchronized view of the specified navigable map.
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m) {
+        return new SynchronizedNavigableMap<>(m);
+    }
+
+    /**
+     * A synchronized NavigableMap.
+     *
+     * @serial include
+     */
+    static class SynchronizedNavigableMap<K,V>
+        extends SynchronizedSortedMap<K,V>
+        implements NavigableMap<K,V>
+    {
+        private static final long serialVersionUID = 699392247599746807L;
+
+        private final NavigableMap<K,V> nm;
+
+        SynchronizedNavigableMap(NavigableMap<K,V> m) {
+            super(m);
+            nm = m;
+        }
+        SynchronizedNavigableMap(NavigableMap<K,V> m, Object mutex) {
+            super(m, mutex);
+            nm = m;
+        }
+
+        public Entry<K, V> lowerEntry(K key)
+                        { synchronized (mutex) { return nm.lowerEntry(key); } }
+        public K lowerKey(K key)
+                          { synchronized (mutex) { return nm.lowerKey(key); } }
+        public Entry<K, V> floorEntry(K key)
+                        { synchronized (mutex) { return nm.floorEntry(key); } }
+        public K floorKey(K key)
+                          { synchronized (mutex) { return nm.floorKey(key); } }
+        public Entry<K, V> ceilingEntry(K key)
+                      { synchronized (mutex) { return nm.ceilingEntry(key); } }
+        public K ceilingKey(K key)
+                        { synchronized (mutex) { return nm.ceilingKey(key); } }
+        public Entry<K, V> higherEntry(K key)
+                       { synchronized (mutex) { return nm.higherEntry(key); } }
+        public K higherKey(K key)
+                         { synchronized (mutex) { return nm.higherKey(key); } }
+        public Entry<K, V> firstEntry()
+                           { synchronized (mutex) { return nm.firstEntry(); } }
+        public Entry<K, V> lastEntry()
+                            { synchronized (mutex) { return nm.lastEntry(); } }
+        public Entry<K, V> pollFirstEntry()
+                       { synchronized (mutex) { return nm.pollFirstEntry(); } }
+        public Entry<K, V> pollLastEntry()
+                        { synchronized (mutex) { return nm.pollLastEntry(); } }
+
+        public NavigableMap<K, V> descendingMap() {
+            synchronized (mutex) {
+                return
+                    new SynchronizedNavigableMap<>(nm.descendingMap(), mutex);
+            }
+        }
+
+        public NavigableSet<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(nm.navigableKeySet(), mutex);
+            }
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            synchronized (mutex) {
+                return new SynchronizedNavigableSet<>(nm.descendingKeySet(), mutex);
+            }
+        }
+
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.subMap(fromKey, true, toKey, false), mutex);
+            }
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(nm.headMap(toKey, false), mutex);
+            }
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            synchronized (mutex) {
+        return new SynchronizedNavigableMap<>(nm.tailMap(fromKey, true),mutex);
+            }
+        }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.subMap(fromKey, fromInclusive, toKey, toInclusive), mutex);
+            }
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                        nm.headMap(toKey, inclusive), mutex);
+            }
+        }
+
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+            synchronized (mutex) {
+                return new SynchronizedNavigableMap<>(
+                    nm.tailMap(fromKey, inclusive), mutex);
+            }
+        }
+    }
+
+    // Dynamically typesafe collection wrappers
+
+    /**
+     * Returns a dynamically typesafe view of the specified collection.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a collection
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the collection takes place through the view, it is
+     * <i>guaranteed</i> that the collection cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>The generics mechanism in the language provides compile-time
+     * (static) type checking, but it is possible to defeat this mechanism
+     * with unchecked casts.  Usually this is not a problem, as the compiler
+     * issues warnings on all such unchecked operations.  There are, however,
+     * times when static type checking alone is not sufficient.  For example,
+     * suppose a collection is passed to a third-party library and it is
+     * imperative that the library code not corrupt the collection by
+     * inserting an element of the wrong type.
+     *
+     * <p>Another use of dynamically typesafe views is debugging.  Suppose a
+     * program fails with a {@code ClassCastException}, indicating that an
+     * incorrectly typed element was put into a parameterized collection.
+     * Unfortunately, the exception can occur at any time after the erroneous
+     * element is inserted, so it typically provides little or no information
+     * as to the real source of the problem.  If the problem is reproducible,
+     * one can quickly determine its source by temporarily modifying the
+     * program to wrap the collection with a dynamically typesafe view.
+     * For example, this declaration:
+     *  <pre> {@code
+     *     Collection<String> c = new HashSet<>();
+     * }</pre>
+     * may be replaced temporarily by this one:
+     *  <pre> {@code
+     *     Collection<String> c = Collections.checkedCollection(
+     *         new HashSet<>(), String.class);
+     * }</pre>
+     * Running the program again will cause it to fail at the point where
+     * an incorrectly typed element is inserted into the collection, clearly
+     * identifying the source of the problem.  Once the problem is fixed, the
+     * modified declaration may be reverted back to the original.
+     *
+     * <p>The returned collection does <i>not</i> pass the hashCode and equals
+     * operations through to the backing collection, but relies on
+     * {@code Object}'s {@code equals} and {@code hashCode} methods.  This
+     * is necessary to preserve the contracts of these operations in the case
+     * that the backing collection is a set or a list.
+     *
+     * <p>The returned collection will be serializable if the specified
+     * collection is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned collection permits insertion of null elements
+     * whenever the backing collection does.
+     *
+     * @param <E> the class of the objects in the collection
+     * @param c the collection for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code c} is permitted to hold
+     * @return a dynamically typesafe view of the specified collection
+     * @since 1.5
+     */
+    public static <E> Collection<E> checkedCollection(Collection<E> c,
+                                                      Class<E> type) {
+        return new CheckedCollection<>(c, type);
+    }
+
+    @SuppressWarnings("unchecked")
+    static <T> T[] zeroLengthArray(Class<T> type) {
+        return (T[]) Array.newInstance(type, 0);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedCollection<E> implements Collection<E>, Serializable {
+        private static final long serialVersionUID = 1578914078182001775L;
+
+        final Collection<E> c;
+        final Class<E> type;
+
+        @SuppressWarnings("unchecked")
+        E typeCheck(Object o) {
+            if (o != null && !type.isInstance(o))
+                throw new ClassCastException(badElementMsg(o));
+            return (E) o;
+        }
+
+        private String badElementMsg(Object o) {
+            return "Attempt to insert " + o.getClass() +
+                " element into collection with element type " + type;
+        }
+
+        CheckedCollection(Collection<E> c, Class<E> type) {
+            this.c = Objects.requireNonNull(c, "c");
+            this.type = Objects.requireNonNull(type, "type");
+        }
+
+        public int size()                 { return c.size(); }
+        public boolean isEmpty()          { return c.isEmpty(); }
+        public boolean contains(Object o) { return c.contains(o); }
+        public Object[] toArray()         { return c.toArray(); }
+        public <T> T[] toArray(T[] a)     { return c.toArray(a); }
+        public String toString()          { return c.toString(); }
+        public boolean remove(Object o)   { return c.remove(o); }
+        public void clear()               {        c.clear(); }
+
+        public boolean containsAll(Collection<?> coll) {
+            return c.containsAll(coll);
+        }
+        public boolean removeAll(Collection<?> coll) {
+            return c.removeAll(coll);
+        }
+        public boolean retainAll(Collection<?> coll) {
+            return c.retainAll(coll);
+        }
+
+        public Iterator<E> iterator() {
+            // JDK-6363904 - unwrapped iterator could be typecast to
+            // ListIterator with unsafe set()
+            final Iterator<E> it = c.iterator();
+            return new Iterator<E>() {
+                public boolean hasNext() { return it.hasNext(); }
+                public E next()          { return it.next(); }
+                public void remove()     {        it.remove(); }};
+            // Android-note: Oversight of Iterator.forEachRemaining().
+            // http://b/110351017
+        }
+
+        public boolean add(E e)          { return c.add(typeCheck(e)); }
+
+        private E[] zeroLengthElementArray; // Lazily initialized
+
+        private E[] zeroLengthElementArray() {
+            return zeroLengthElementArray != null ? zeroLengthElementArray :
+                (zeroLengthElementArray = zeroLengthArray(type));
+        }
+
+        @SuppressWarnings("unchecked")
+        Collection<E> checkedCopyOf(Collection<? extends E> coll) {
+            Object[] a;
+            try {
+                E[] z = zeroLengthElementArray();
+                a = coll.toArray(z);
+                // Defend against coll violating the toArray contract
+                if (a.getClass() != z.getClass())
+                    a = Arrays.copyOf(a, a.length, z.getClass());
+            } catch (ArrayStoreException ignore) {
+                // To get better and consistent diagnostics,
+                // we call typeCheck explicitly on each element.
+                // We call clone() to defend against coll retaining a
+                // reference to the returned array and storing a bad
+                // element into it after it has been type checked.
+                a = coll.toArray().clone();
+                for (Object o : a)
+                    typeCheck(o);
+            }
+            // A slight abuse of the type system, but safe here.
+            return (Collection<E>) Arrays.asList(a);
+        }
+
+        public boolean addAll(Collection<? extends E> coll) {
+            // Doing things this way insulates us from concurrent changes
+            // in the contents of coll and provides all-or-nothing
+            // semantics (which we wouldn't get if we type-checked each
+            // element as we added it)
+            return c.addAll(checkedCopyOf(coll));
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {c.forEach(action);}
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return c.removeIf(filter);
+        }
+        @Override
+        public Spliterator<E> spliterator() {return c.spliterator();}
+        @Override
+        public Stream<E> stream()           {return c.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return c.parallelStream();}
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified queue.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a queue contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the queue
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * queue cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned queue will be serializable if the specified queue
+     * is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned queue permits insertion of {@code null} elements
+     * whenever the backing queue does.
+     *
+     * @param <E> the class of the objects in the queue
+     * @param queue the queue for which a dynamically typesafe view is to be
+     *             returned
+     * @param type the type of element that {@code queue} is permitted to hold
+     * @return a dynamically typesafe view of the specified queue
+     * @since 1.8
+     */
+    public static <E> Queue<E> checkedQueue(Queue<E> queue, Class<E> type) {
+        return new CheckedQueue<>(queue, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedQueue<E>
+        extends CheckedCollection<E>
+        implements Queue<E>, Serializable
+    {
+        private static final long serialVersionUID = 1433151992604707767L;
+        final Queue<E> queue;
+
+        CheckedQueue(Queue<E> queue, Class<E> elementType) {
+            super(queue, elementType);
+            this.queue = queue;
+        }
+
+        public E element()              {return queue.element();}
+        public boolean equals(Object o) {return o == this || c.equals(o);}
+        public int hashCode()           {return c.hashCode();}
+        public E peek()                 {return queue.peek();}
+        public E poll()                 {return queue.poll();}
+        public E remove()               {return queue.remove();}
+        public boolean offer(E e)       {return queue.offer(typeCheck(e));}
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified set.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a set contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the set
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * set cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned set will be serializable if the specified set is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned set permits insertion of null elements whenever
+     * the backing set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified set
+     * @since 1.5
+     */
+    public static <E> Set<E> checkedSet(Set<E> s, Class<E> type) {
+        return new CheckedSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSet<E> extends CheckedCollection<E>
+                                 implements Set<E>, Serializable
+    {
+        private static final long serialVersionUID = 4694047833775013803L;
+
+        CheckedSet(Set<E> s, Class<E> elementType) { super(s, elementType); }
+
+        public boolean equals(Object o) { return o == this || c.equals(o); }
+        public int hashCode()           { return c.hashCode(); }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified sorted set.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a sorted set
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the sorted set takes place through the view, it is
+     * <i>guaranteed</i> that the sorted set cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned sorted set will be serializable if the specified sorted
+     * set is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned sorted set permits insertion of null elements
+     * whenever the backing sorted set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the sorted set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified sorted set
+     * @since 1.5
+     */
+    public static <E> SortedSet<E> checkedSortedSet(SortedSet<E> s,
+                                                    Class<E> type) {
+        return new CheckedSortedSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSortedSet<E> extends CheckedSet<E>
+        implements SortedSet<E>, Serializable
+    {
+        private static final long serialVersionUID = 1599911165492914959L;
+
+        private final SortedSet<E> ss;
+
+        CheckedSortedSet(SortedSet<E> s, Class<E> type) {
+            super(s, type);
+            ss = s;
+        }
+
+        public Comparator<? super E> comparator() { return ss.comparator(); }
+        public E first()                   { return ss.first(); }
+        public E last()                    { return ss.last(); }
+
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return checkedSortedSet(ss.subSet(fromElement,toElement), type);
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return checkedSortedSet(ss.headSet(toElement), type);
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return checkedSortedSet(ss.tailSet(fromElement), type);
+        }
+    }
+
+/**
+     * Returns a dynamically typesafe view of the specified navigable set.
+     * Any attempt to insert an element of the wrong type will result in an
+     * immediate {@link ClassCastException}.  Assuming a navigable set
+     * contains no incorrectly typed elements prior to the time a
+     * dynamically typesafe view is generated, and that all subsequent
+     * access to the navigable set takes place through the view, it is
+     * <em>guaranteed</em> that the navigable set cannot contain an incorrectly
+     * typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned navigable set will be serializable if the specified
+     * navigable set is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned navigable set permits insertion of null elements
+     * whenever the backing sorted set does.
+     *
+     * @param <E> the class of the objects in the set
+     * @param s the navigable set for which a dynamically typesafe view is to be
+     *          returned
+     * @param type the type of element that {@code s} is permitted to hold
+     * @return a dynamically typesafe view of the specified navigable set
+     * @since 1.8
+     */
+    public static <E> NavigableSet<E> checkedNavigableSet(NavigableSet<E> s,
+                                                    Class<E> type) {
+        return new CheckedNavigableSet<>(s, type);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedNavigableSet<E> extends CheckedSortedSet<E>
+        implements NavigableSet<E>, Serializable
+    {
+        private static final long serialVersionUID = -5429120189805438922L;
+
+        private final NavigableSet<E> ns;
+
+        CheckedNavigableSet(NavigableSet<E> s, Class<E> type) {
+            super(s, type);
+            ns = s;
+        }
+
+        public E lower(E e)                             { return ns.lower(e); }
+        public E floor(E e)                             { return ns.floor(e); }
+        public E ceiling(E e)                         { return ns.ceiling(e); }
+        public E higher(E e)                           { return ns.higher(e); }
+        public E pollFirst()                         { return ns.pollFirst(); }
+        public E pollLast()                            {return ns.pollLast(); }
+        public NavigableSet<E> descendingSet()
+                      { return checkedNavigableSet(ns.descendingSet(), type); }
+        public Iterator<E> descendingIterator()
+            {return checkedNavigableSet(ns.descendingSet(), type).iterator(); }
+
+        public NavigableSet<E> subSet(E fromElement, E toElement) {
+            return checkedNavigableSet(ns.subSet(fromElement, true, toElement, false), type);
+        }
+        public NavigableSet<E> headSet(E toElement) {
+            return checkedNavigableSet(ns.headSet(toElement, false), type);
+        }
+        public NavigableSet<E> tailSet(E fromElement) {
+            return checkedNavigableSet(ns.tailSet(fromElement, true), type);
+        }
+
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
+            return checkedNavigableSet(ns.subSet(fromElement, fromInclusive, toElement, toInclusive), type);
+        }
+
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return checkedNavigableSet(ns.headSet(toElement, inclusive), type);
+        }
+
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return checkedNavigableSet(ns.tailSet(fromElement, inclusive), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified list.
+     * Any attempt to insert an element of the wrong type will result in
+     * an immediate {@link ClassCastException}.  Assuming a list contains
+     * no incorrectly typed elements prior to the time a dynamically typesafe
+     * view is generated, and that all subsequent access to the list
+     * takes place through the view, it is <i>guaranteed</i> that the
+     * list cannot contain an incorrectly typed element.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned list will be serializable if the specified list
+     * is serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned list permits insertion of null elements whenever
+     * the backing list does.
+     *
+     * @param <E> the class of the objects in the list
+     * @param list the list for which a dynamically typesafe view is to be
+     *             returned
+     * @param type the type of element that {@code list} is permitted to hold
+     * @return a dynamically typesafe view of the specified list
+     * @since 1.5
+     */
+    public static <E> List<E> checkedList(List<E> list, Class<E> type) {
+        return (list instanceof RandomAccess ?
+                new CheckedRandomAccessList<>(list, type) :
+                new CheckedList<>(list, type));
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedList<E>
+        extends CheckedCollection<E>
+        implements List<E>
+    {
+        private static final long serialVersionUID = 65247728283967356L;
+        final List<E> list;
+
+        CheckedList(List<E> list, Class<E> type) {
+            super(list, type);
+            this.list = list;
+        }
+
+        public boolean equals(Object o)  { return o == this || list.equals(o); }
+        public int hashCode()            { return list.hashCode(); }
+        public E get(int index)          { return list.get(index); }
+        public E remove(int index)       { return list.remove(index); }
+        public int indexOf(Object o)     { return list.indexOf(o); }
+        public int lastIndexOf(Object o) { return list.lastIndexOf(o); }
+
+        public E set(int index, E element) {
+            return list.set(index, typeCheck(element));
+        }
+
+        public void add(int index, E element) {
+            list.add(index, typeCheck(element));
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            return list.addAll(index, checkedCopyOf(c));
+        }
+        public ListIterator<E> listIterator()   { return listIterator(0); }
+
+        public ListIterator<E> listIterator(final int index) {
+            final ListIterator<E> i = list.listIterator(index);
+
+            return new ListIterator<E>() {
+                public boolean hasNext()     { return i.hasNext(); }
+                public E next()              { return i.next(); }
+                public boolean hasPrevious() { return i.hasPrevious(); }
+                public E previous()          { return i.previous(); }
+                public int nextIndex()       { return i.nextIndex(); }
+                public int previousIndex()   { return i.previousIndex(); }
+                public void remove()         {        i.remove(); }
+
+                public void set(E e) {
+                    i.set(typeCheck(e));
+                }
+
+                public void add(E e) {
+                    i.add(typeCheck(e));
+                }
+
+                @Override
+                public void forEachRemaining(Consumer<? super E> action) {
+                    i.forEachRemaining(action);
+                }
+            };
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new CheckedList<>(list.subList(fromIndex, toIndex), type);
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @throws ClassCastException if the class of an element returned by the
+         *         operator prevents it from being added to this collection. The
+         *         exception may be thrown after some elements of the list have
+         *         already been replaced.
+         */
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+            list.replaceAll(e -> typeCheck(operator.apply(e)));
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            list.sort(c);
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedRandomAccessList<E> extends CheckedList<E>
+                                            implements RandomAccess
+    {
+        private static final long serialVersionUID = 1638200125423088369L;
+
+        CheckedRandomAccessList(List<E> list, Class<E> type) {
+            super(list, type);
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            return new CheckedRandomAccessList<>(
+                    list.subList(fromIndex, toIndex), type);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <i>guaranteed</i> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.5
+     */
+    public static <K, V> Map<K, V> checkedMap(Map<K, V> m,
+                                              Class<K> keyType,
+                                              Class<V> valueType) {
+        return new CheckedMap<>(m, keyType, valueType);
+    }
+
+
+    /**
+     * @serial include
+     */
+    private static class CheckedMap<K,V>
+        implements Map<K,V>, Serializable
+    {
+        private static final long serialVersionUID = 5742860141034234728L;
+
+        private final Map<K, V> m;
+        final Class<K> keyType;
+        final Class<V> valueType;
+
+        private void typeCheck(Object key, Object value) {
+            if (key != null && !keyType.isInstance(key))
+                throw new ClassCastException(badKeyMsg(key));
+
+            if (value != null && !valueType.isInstance(value))
+                throw new ClassCastException(badValueMsg(value));
+        }
+
+        private BiFunction<? super K, ? super V, ? extends V> typeCheck(
+                BiFunction<? super K, ? super V, ? extends V> func) {
+            Objects.requireNonNull(func);
+            return (k, v) -> {
+                V newValue = func.apply(k, v);
+                typeCheck(k, newValue);
+                return newValue;
+            };
+        }
+
+        private String badKeyMsg(Object key) {
+            return "Attempt to insert " + key.getClass() +
+                    " key into map with key type " + keyType;
+        }
+
+        private String badValueMsg(Object value) {
+            return "Attempt to insert " + value.getClass() +
+                    " value into map with value type " + valueType;
+        }
+
+        CheckedMap(Map<K, V> m, Class<K> keyType, Class<V> valueType) {
+            this.m = Objects.requireNonNull(m);
+            this.keyType = Objects.requireNonNull(keyType);
+            this.valueType = Objects.requireNonNull(valueType);
+        }
+
+        public int size()                      { return m.size(); }
+        public boolean isEmpty()               { return m.isEmpty(); }
+        public boolean containsKey(Object key) { return m.containsKey(key); }
+        public boolean containsValue(Object v) { return m.containsValue(v); }
+        public V get(Object key)               { return m.get(key); }
+        public V remove(Object key)            { return m.remove(key); }
+        public void clear()                    { m.clear(); }
+        public Set<K> keySet()                 { return m.keySet(); }
+        public Collection<V> values()          { return m.values(); }
+        public boolean equals(Object o)        { return o == this || m.equals(o); }
+        public int hashCode()                  { return m.hashCode(); }
+        public String toString()               { return m.toString(); }
+
+        public V put(K key, V value) {
+            typeCheck(key, value);
+            return m.put(key, value);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void putAll(Map<? extends K, ? extends V> t) {
+            // Satisfy the following goals:
+            // - good diagnostics in case of type mismatch
+            // - all-or-nothing semantics
+            // - protection from malicious t
+            // - correct behavior if t is a concurrent map
+            Object[] entries = t.entrySet().toArray();
+            List<Map.Entry<K,V>> checked = new ArrayList<>(entries.length);
+            for (Object o : entries) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object k = e.getKey();
+                Object v = e.getValue();
+                typeCheck(k, v);
+                checked.add(
+                        new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v));
+            }
+            for (Map.Entry<K,V> e : checked)
+                m.put(e.getKey(), e.getValue());
+        }
+
+        private transient Set<Map.Entry<K,V>> entrySet;
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = new CheckedEntrySet<>(m.entrySet(), valueType);
+            return entrySet;
+        }
+
+        // Override default methods in Map
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            m.forEach(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            m.replaceAll(typeCheck(function));
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            typeCheck(key, value);
+            return m.putIfAbsent(key, value);
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            return m.remove(key, value);
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            typeCheck(key, newValue);
+            return m.replace(key, oldValue, newValue);
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            typeCheck(key, value);
+            return m.replace(key, value);
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            Objects.requireNonNull(mappingFunction);
+            return m.computeIfAbsent(key, k -> {
+                V value = mappingFunction.apply(k);
+                typeCheck(k, value);
+                return value;
+            });
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return m.computeIfPresent(key, typeCheck(remappingFunction));
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            return m.compute(key, typeCheck(remappingFunction));
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            Objects.requireNonNull(remappingFunction);
+            return m.merge(key, value, (v1, v2) -> {
+                V newValue = remappingFunction.apply(v1, v2);
+                typeCheck(null, newValue);
+                return newValue;
+            });
+        }
+
+        /**
+         * We need this class in addition to CheckedSet as Map.Entry permits
+         * modification of the backing Map via the setValue operation.  This
+         * class is subtle: there are many possible attacks that must be
+         * thwarted.
+         *
+         * @serial exclude
+         */
+        static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> {
+            private final Set<Map.Entry<K,V>> s;
+            private final Class<V> valueType;
+
+            CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) {
+                this.s = s;
+                this.valueType = valueType;
+            }
+
+            public int size()        { return s.size(); }
+            public boolean isEmpty() { return s.isEmpty(); }
+            public String toString() { return s.toString(); }
+            public int hashCode()    { return s.hashCode(); }
+            public void clear()      {        s.clear(); }
+
+            public boolean add(Map.Entry<K, V> e) {
+                throw new UnsupportedOperationException();
+            }
+            public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) {
+                throw new UnsupportedOperationException();
+            }
+
+            public Iterator<Map.Entry<K,V>> iterator() {
+                final Iterator<Map.Entry<K, V>> i = s.iterator();
+                final Class<V> valueType = this.valueType;
+
+                return new Iterator<Map.Entry<K,V>>() {
+                    public boolean hasNext() { return i.hasNext(); }
+                    public void remove()     { i.remove(); }
+
+                    public Map.Entry<K,V> next() {
+                        return checkedEntry(i.next(), valueType);
+                    }
+                    // Android-note: Oversight of Iterator.forEachRemaining().
+                    // http://b/110351017
+                };
+            }
+
+            // Android-changed: Ignore IsInstanceOfClass warning. b/73288967, b/73344263.
+            // @SuppressWarnings("unchecked")
+            @SuppressWarnings({ "unchecked", "IsInstanceOfClass" })
+            public Object[] toArray() {
+                Object[] source = s.toArray();
+
+                /*
+                 * Ensure that we don't get an ArrayStoreException even if
+                 * s.toArray returns an array of something other than Object
+                 */
+                Object[] dest = (CheckedEntry.class.isInstance(
+                    source.getClass().getComponentType()) ? source :
+                                 new Object[source.length]);
+
+                for (int i = 0; i < source.length; i++)
+                    dest[i] = checkedEntry((Map.Entry<K,V>)source[i],
+                                           valueType);
+                return dest;
+            }
+
+            @SuppressWarnings("unchecked")
+            public <T> T[] toArray(T[] a) {
+                // We don't pass a to s.toArray, to avoid window of
+                // vulnerability wherein an unscrupulous multithreaded client
+                // could get his hands on raw (unwrapped) Entries from s.
+                T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
+
+                for (int i=0; i<arr.length; i++)
+                    arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i],
+                                              valueType);
+                if (arr.length > a.length)
+                    return arr;
+
+                System.arraycopy(arr, 0, a, 0, arr.length);
+                if (a.length > arr.length)
+                    a[arr.length] = null;
+                return a;
+            }
+
+            /**
+             * This method is overridden to protect the backing set against
+             * an object with a nefarious equals function that senses
+             * that the equality-candidate is Map.Entry and calls its
+             * setValue method.
+             */
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                return s.contains(
+                    (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
+            }
+
+            /**
+             * The bulk collection methods are overridden to protect
+             * against an unscrupulous collection whose contains(Object o)
+             * method senses when o is a Map.Entry, and calls o.setValue.
+             */
+            public boolean containsAll(Collection<?> c) {
+                for (Object o : c)
+                    if (!contains(o)) // Invokes safe contains() above
+                        return false;
+                return true;
+            }
+
+            public boolean remove(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                return s.remove(new AbstractMap.SimpleImmutableEntry
+                                <>((Map.Entry<?,?>)o));
+            }
+
+            public boolean removeAll(Collection<?> c) {
+                return batchRemove(c, false);
+            }
+            public boolean retainAll(Collection<?> c) {
+                return batchRemove(c, true);
+            }
+            private boolean batchRemove(Collection<?> c, boolean complement) {
+                Objects.requireNonNull(c);
+                boolean modified = false;
+                Iterator<Map.Entry<K,V>> it = iterator();
+                while (it.hasNext()) {
+                    if (c.contains(it.next()) != complement) {
+                        it.remove();
+                        modified = true;
+                    }
+                }
+                return modified;
+            }
+
+            public boolean equals(Object o) {
+                if (o == this)
+                    return true;
+                if (!(o instanceof Set))
+                    return false;
+                Set<?> that = (Set<?>) o;
+                return that.size() == s.size()
+                    && containsAll(that); // Invokes safe containsAll() above
+            }
+
+            static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e,
+                                                            Class<T> valueType) {
+                return new CheckedEntry<>(e, valueType);
+            }
+
+            /**
+             * This "wrapper class" serves two purposes: it prevents
+             * the client from modifying the backing Map, by short-circuiting
+             * the setValue method, and it protects the backing Map against
+             * an ill-behaved Map.Entry that attempts to modify another
+             * Map.Entry when asked to perform an equality check.
+             */
+            private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> {
+                private final Map.Entry<K, V> e;
+                private final Class<T> valueType;
+
+                CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) {
+                    this.e = Objects.requireNonNull(e);
+                    this.valueType = Objects.requireNonNull(valueType);
+                }
+
+                public K getKey()        { return e.getKey(); }
+                public V getValue()      { return e.getValue(); }
+                public int hashCode()    { return e.hashCode(); }
+                public String toString() { return e.toString(); }
+
+                public V setValue(V value) {
+                    if (value != null && !valueType.isInstance(value))
+                        throw new ClassCastException(badValueMsg(value));
+                    return e.setValue(value);
+                }
+
+                private String badValueMsg(Object value) {
+                    return "Attempt to insert " + value.getClass() +
+                        " value into map with value type " + valueType;
+                }
+
+                public boolean equals(Object o) {
+                    if (o == this)
+                        return true;
+                    if (!(o instanceof Map.Entry))
+                        return false;
+                    return e.equals(new AbstractMap.SimpleImmutableEntry
+                                    <>((Map.Entry<?,?>)o));
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified sorted map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <i>guaranteed</i> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.5
+     */
+    public static <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K, V> m,
+                                                        Class<K> keyType,
+                                                        Class<V> valueType) {
+        return new CheckedSortedMap<>(m, keyType, valueType);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedSortedMap<K,V> extends CheckedMap<K,V>
+        implements SortedMap<K,V>, Serializable
+    {
+        private static final long serialVersionUID = 1599671320688067438L;
+
+        private final SortedMap<K, V> sm;
+
+        CheckedSortedMap(SortedMap<K, V> m,
+                         Class<K> keyType, Class<V> valueType) {
+            super(m, keyType, valueType);
+            sm = m;
+        }
+
+        public Comparator<? super K> comparator() { return sm.comparator(); }
+        public K firstKey()                       { return sm.firstKey(); }
+        public K lastKey()                        { return sm.lastKey(); }
+
+        public SortedMap<K,V> subMap(K fromKey, K toKey) {
+            return checkedSortedMap(sm.subMap(fromKey, toKey),
+                                    keyType, valueType);
+        }
+        public SortedMap<K,V> headMap(K toKey) {
+            return checkedSortedMap(sm.headMap(toKey), keyType, valueType);
+        }
+        public SortedMap<K,V> tailMap(K fromKey) {
+            return checkedSortedMap(sm.tailMap(fromKey), keyType, valueType);
+        }
+    }
+
+    /**
+     * Returns a dynamically typesafe view of the specified navigable map.
+     * Any attempt to insert a mapping whose key or value have the wrong
+     * type will result in an immediate {@link ClassCastException}.
+     * Similarly, any attempt to modify the value currently associated with
+     * a key will result in an immediate {@link ClassCastException},
+     * whether the modification is attempted directly through the map
+     * itself, or through a {@link Map.Entry} instance obtained from the
+     * map's {@link Map#entrySet() entry set} view.
+     *
+     * <p>Assuming a map contains no incorrectly typed keys or values
+     * prior to the time a dynamically typesafe view is generated, and
+     * that all subsequent access to the map takes place through the view
+     * (or one of its collection views), it is <em>guaranteed</em> that the
+     * map cannot contain an incorrectly typed key or value.
+     *
+     * <p>A discussion of the use of dynamically typesafe views may be
+     * found in the documentation for the {@link #checkedCollection
+     * checkedCollection} method.
+     *
+     * <p>The returned map will be serializable if the specified map is
+     * serializable.
+     *
+     * <p>Since {@code null} is considered to be a value of any reference
+     * type, the returned map permits insertion of null keys or values
+     * whenever the backing map does.
+     *
+     * @param <K> type of map keys
+     * @param <V> type of map values
+     * @param m the map for which a dynamically typesafe view is to be
+     *          returned
+     * @param keyType the type of key that {@code m} is permitted to hold
+     * @param valueType the type of value that {@code m} is permitted to hold
+     * @return a dynamically typesafe view of the specified map
+     * @since 1.8
+     */
+    public static <K,V> NavigableMap<K,V> checkedNavigableMap(NavigableMap<K, V> m,
+                                                        Class<K> keyType,
+                                                        Class<V> valueType) {
+        return new CheckedNavigableMap<>(m, keyType, valueType);
+    }
+
+    /**
+     * @serial include
+     */
+    static class CheckedNavigableMap<K,V> extends CheckedSortedMap<K,V>
+        implements NavigableMap<K,V>, Serializable
+    {
+        private static final long serialVersionUID = -4852462692372534096L;
+
+        private final NavigableMap<K, V> nm;
+
+        CheckedNavigableMap(NavigableMap<K, V> m,
+                         Class<K> keyType, Class<V> valueType) {
+            super(m, keyType, valueType);
+            nm = m;
+        }
+
+        public Comparator<? super K> comparator()   { return nm.comparator(); }
+        public K firstKey()                           { return nm.firstKey(); }
+        public K lastKey()                             { return nm.lastKey(); }
+
+        public Entry<K, V> lowerEntry(K key) {
+            Entry<K,V> lower = nm.lowerEntry(key);
+            return (null != lower)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(lower, valueType)
+                : null;
+        }
+
+        public K lowerKey(K key)                   { return nm.lowerKey(key); }
+
+        public Entry<K, V> floorEntry(K key) {
+            Entry<K,V> floor = nm.floorEntry(key);
+            return (null != floor)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(floor, valueType)
+                : null;
+        }
+
+        public K floorKey(K key)                   { return nm.floorKey(key); }
+
+        public Entry<K, V> ceilingEntry(K key) {
+            Entry<K,V> ceiling = nm.ceilingEntry(key);
+            return (null != ceiling)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(ceiling, valueType)
+                : null;
+        }
+
+        public K ceilingKey(K key)               { return nm.ceilingKey(key); }
+
+        public Entry<K, V> higherEntry(K key) {
+            Entry<K,V> higher = nm.higherEntry(key);
+            return (null != higher)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(higher, valueType)
+                : null;
+        }
+
+        public K higherKey(K key)                 { return nm.higherKey(key); }
+
+        public Entry<K, V> firstEntry() {
+            Entry<K,V> first = nm.firstEntry();
+            return (null != first)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(first, valueType)
+                : null;
+        }
+
+        public Entry<K, V> lastEntry() {
+            Entry<K,V> last = nm.lastEntry();
+            return (null != last)
+                ? new CheckedMap.CheckedEntrySet.CheckedEntry<>(last, valueType)
+                : null;
+        }
+
+        public Entry<K, V> pollFirstEntry() {
+            Entry<K,V> entry = nm.pollFirstEntry();
+            return (null == entry)
+                ? null
+                : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType);
+        }
+
+        public Entry<K, V> pollLastEntry() {
+            Entry<K,V> entry = nm.pollLastEntry();
+            return (null == entry)
+                ? null
+                : new CheckedMap.CheckedEntrySet.CheckedEntry<>(entry, valueType);
+        }
+
+        public NavigableMap<K, V> descendingMap() {
+            return checkedNavigableMap(nm.descendingMap(), keyType, valueType);
+        }
+
+        public NavigableSet<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            return checkedNavigableSet(nm.navigableKeySet(), keyType);
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return checkedNavigableSet(nm.descendingKeySet(), keyType);
+        }
+
+        @Override
+        public NavigableMap<K,V> subMap(K fromKey, K toKey) {
+            return checkedNavigableMap(nm.subMap(fromKey, true, toKey, false),
+                                    keyType, valueType);
+        }
+
+        @Override
+        public NavigableMap<K,V> headMap(K toKey) {
+            return checkedNavigableMap(nm.headMap(toKey, false), keyType, valueType);
+        }
+
+        @Override
+        public NavigableMap<K,V> tailMap(K fromKey) {
+            return checkedNavigableMap(nm.tailMap(fromKey, true), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
+            return checkedNavigableMap(nm.subMap(fromKey, fromInclusive, toKey, toInclusive), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> headMap(K toKey, boolean inclusive) {
+            return checkedNavigableMap(nm.headMap(toKey, inclusive), keyType, valueType);
+        }
+
+        public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
+            return checkedNavigableMap(nm.tailMap(fromKey, inclusive), keyType, valueType);
+        }
+    }
+
+    // Empty collections
+
+    /**
+     * Returns an iterator that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Iterator#hasNext hasNext} always returns {@code
+     * false}.</li>
+     * <li>{@link Iterator#next next} always throws {@link
+     * NoSuchElementException}.</li>
+     * <li>{@link Iterator#remove remove} always throws {@link
+     * IllegalStateException}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param <T> type of elements, if there were any, in the iterator
+     * @return an empty iterator
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Iterator<T> emptyIterator() {
+        return (Iterator<T>) EmptyIterator.EMPTY_ITERATOR;
+    }
+
+    private static class EmptyIterator<E> implements Iterator<E> {
+        static final EmptyIterator<Object> EMPTY_ITERATOR
+            = new EmptyIterator<>();
+
+        public boolean hasNext() { return false; }
+        public E next() { throw new NoSuchElementException(); }
+        public void remove() { throw new IllegalStateException(); }
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+    }
+
+    /**
+     * Returns a list iterator that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Iterator#hasNext hasNext} and {@link
+     * ListIterator#hasPrevious hasPrevious} always return {@code
+     * false}.</li>
+     * <li>{@link Iterator#next next} and {@link ListIterator#previous
+     * previous} always throw {@link NoSuchElementException}.</li>
+     * <li>{@link Iterator#remove remove} and {@link ListIterator#set
+     * set} always throw {@link IllegalStateException}.</li>
+     * <li>{@link ListIterator#add add} always throws {@link
+     * UnsupportedOperationException}.</li>
+     * <li>{@link ListIterator#nextIndex nextIndex} always returns
+     * {@code 0}.</li>
+     * <li>{@link ListIterator#previousIndex previousIndex} always
+     * returns {@code -1}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param <T> type of elements, if there were any, in the iterator
+     * @return an empty list iterator
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> ListIterator<T> emptyListIterator() {
+        return (ListIterator<T>) EmptyListIterator.EMPTY_ITERATOR;
+    }
+
+    private static class EmptyListIterator<E>
+        extends EmptyIterator<E>
+        implements ListIterator<E>
+    {
+        static final EmptyListIterator<Object> EMPTY_ITERATOR
+            = new EmptyListIterator<>();
+
+        public boolean hasPrevious() { return false; }
+        public E previous() { throw new NoSuchElementException(); }
+        public int nextIndex()     { return 0; }
+        public int previousIndex() { return -1; }
+        public void set(E e) { throw new IllegalStateException(); }
+        public void add(E e) { throw new UnsupportedOperationException(); }
+    }
+
+    /**
+     * Returns an enumeration that has no elements.  More precisely,
+     *
+     * <ul>
+     * <li>{@link Enumeration#hasMoreElements hasMoreElements} always
+     * returns {@code false}.</li>
+     * <li> {@link Enumeration#nextElement nextElement} always throws
+     * {@link NoSuchElementException}.</li>
+     * </ul>
+     *
+     * <p>Implementations of this method are permitted, but not
+     * required, to return the same object from multiple invocations.
+     *
+     * @param  <T> the class of the objects in the enumeration
+     * @return an empty enumeration
+     * @since 1.7
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Enumeration<T> emptyEnumeration() {
+        return (Enumeration<T>) EmptyEnumeration.EMPTY_ENUMERATION;
+    }
+
+    private static class EmptyEnumeration<E> implements Enumeration<E> {
+        static final EmptyEnumeration<Object> EMPTY_ENUMERATION
+            = new EmptyEnumeration<>();
+
+        public boolean hasMoreElements() { return false; }
+        public E nextElement() { throw new NoSuchElementException(); }
+    }
+
+    /**
+     * The empty set (immutable).  This set is serializable.
+     *
+     * @see #emptySet()
+     */
+    @SuppressWarnings("rawtypes")
+    public static final Set EMPTY_SET = new EmptySet<>();
+
+    /**
+     * Returns an empty set (immutable).  This set is serializable.
+     * Unlike the like-named field, this method is parameterized.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty set:
+     * <pre>
+     *     Set&lt;String&gt; s = Collections.emptySet();
+     * </pre>
+     * @implNote Implementations of this method need not create a separate
+     * {@code Set} object for each call.  Using this method is likely to have
+     * comparable cost to using the like-named field.  (Unlike this method, the
+     * field does not provide type safety.)
+     *
+     * @param  <T> the class of the objects in the set
+     * @return the empty set
+     *
+     * @see #EMPTY_SET
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <T> Set<T> emptySet() {
+        return (Set<T>) EMPTY_SET;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptySet<E>
+        extends AbstractSet<E>
+        implements Serializable
+    {
+        private static final long serialVersionUID = 1582296315990362920L;
+
+        public Iterator<E> iterator() { return emptyIterator(); }
+
+        public int size() {return 0;}
+        public boolean isEmpty() {return true;}
+
+        public boolean contains(Object obj) {return false;}
+        public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
+
+        public Object[] toArray() { return new Object[0]; }
+
+        public <T> T[] toArray(T[] a) {
+            if (a.length > 0)
+                a[0] = null;
+            return a;
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return false;
+        }
+        @Override
+        public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
+
+        // Preserves singleton property
+        private Object readResolve() {
+            return EMPTY_SET;
+        }
+    }
+
+    /**
+     * Returns an empty sorted set (immutable).  This set is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty
+     * sorted set:
+     * <pre> {@code
+     *     SortedSet<String> s = Collections.emptySortedSet();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code SortedSet} object for each call.
+     *
+     * @param <E> type of elements, if there were any, in the set
+     * @return the empty sorted set
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> SortedSet<E> emptySortedSet() {
+        return (SortedSet<E>) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET;
+    }
+
+    /**
+     * Returns an empty navigable set (immutable).  This set is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty
+     * navigable set:
+     * <pre> {@code
+     *     NavigableSet<String> s = Collections.emptyNavigableSet();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not
+     * create a separate {@code NavigableSet} object for each call.
+     *
+     * @param <E> type of elements, if there were any, in the set
+     * @return the empty navigable set
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> NavigableSet<E> emptyNavigableSet() {
+        return (NavigableSet<E>) UnmodifiableNavigableSet.EMPTY_NAVIGABLE_SET;
+    }
+
+    /**
+     * The empty list (immutable).  This list is serializable.
+     *
+     * @see #emptyList()
+     */
+    @SuppressWarnings("rawtypes")
+    public static final List EMPTY_LIST = new EmptyList<>();
+
+    /**
+     * Returns an empty list (immutable).  This list is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty list:
+     * <pre>
+     *     List&lt;String&gt; s = Collections.emptyList();
+     * </pre>
+     *
+     * @implNote
+     * Implementations of this method need not create a separate <tt>List</tt>
+     * object for each call.   Using this method is likely to have comparable
+     * cost to using the like-named field.  (Unlike this method, the field does
+     * not provide type safety.)
+     *
+     * @param <T> type of elements, if there were any, in the list
+     * @return an empty immutable list
+     *
+     * @see #EMPTY_LIST
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <T> List<T> emptyList() {
+        return (List<T>) EMPTY_LIST;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptyList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable {
+        private static final long serialVersionUID = 8842843931221139166L;
+
+        public Iterator<E> iterator() {
+            return emptyIterator();
+        }
+        public ListIterator<E> listIterator() {
+            return emptyListIterator();
+        }
+
+        public int size() {return 0;}
+        public boolean isEmpty() {return true;}
+
+        public boolean contains(Object obj) {return false;}
+        public boolean containsAll(Collection<?> c) { return c.isEmpty(); }
+
+        public Object[] toArray() { return new Object[0]; }
+
+        public <T> T[] toArray(T[] a) {
+            if (a.length > 0)
+                a[0] = null;
+            return a;
+        }
+
+        public E get(int index) {
+            throw new IndexOutOfBoundsException("Index: "+index);
+        }
+
+        public boolean equals(Object o) {
+            return (o instanceof List) && ((List<?>)o).isEmpty();
+        }
+
+        public int hashCode() { return 1; }
+
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            Objects.requireNonNull(filter);
+            return false;
+        }
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            Objects.requireNonNull(operator);
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+        }
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); }
+
+        // Preserves singleton property
+        private Object readResolve() {
+            return EMPTY_LIST;
+        }
+    }
+
+    /**
+     * The empty map (immutable).  This map is serializable.
+     *
+     * @see #emptyMap()
+     * @since 1.3
+     */
+    @SuppressWarnings("rawtypes")
+    public static final Map EMPTY_MAP = new EmptyMap<>();
+
+    /**
+     * Returns an empty map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre>
+     *     Map&lt;String, Date&gt; s = Collections.emptyMap();
+     * </pre>
+     * @implNote Implementations of this method need not create a separate
+     * {@code Map} object for each call.  Using this method is likely to have
+     * comparable cost to using the like-named field.  (Unlike this method, the
+     * field does not provide type safety.)
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty map
+     * @see #EMPTY_MAP
+     * @since 1.5
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> Map<K,V> emptyMap() {
+        return (Map<K,V>) EMPTY_MAP;
+    }
+
+    /**
+     * Returns an empty sorted map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre> {@code
+     *     SortedMap<String, Date> s = Collections.emptySortedMap();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code SortedMap} object for each call.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty sorted map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> SortedMap<K,V> emptySortedMap() {
+        return (SortedMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
+    }
+
+    /**
+     * Returns an empty navigable map (immutable).  This map is serializable.
+     *
+     * <p>This example illustrates the type-safe way to obtain an empty map:
+     * <pre> {@code
+     *     NavigableMap<String, Date> s = Collections.emptyNavigableMap();
+     * }</pre>
+     *
+     * @implNote Implementations of this method need not create a separate
+     * {@code NavigableMap} object for each call.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @return an empty navigable map
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static final <K,V> NavigableMap<K,V> emptyNavigableMap() {
+        return (NavigableMap<K,V>) UnmodifiableNavigableMap.EMPTY_NAVIGABLE_MAP;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class EmptyMap<K,V>
+        extends AbstractMap<K,V>
+        implements Serializable
+    {
+        private static final long serialVersionUID = 6428348081105594320L;
+
+        public int size()                          {return 0;}
+        public boolean isEmpty()                   {return true;}
+        public boolean containsKey(Object key)     {return false;}
+        public boolean containsValue(Object value) {return false;}
+        public V get(Object key)                   {return null;}
+        public Set<K> keySet()                     {return emptySet();}
+        public Collection<V> values()              {return emptySet();}
+        public Set<Map.Entry<K,V>> entrySet()      {return emptySet();}
+
+        public boolean equals(Object o) {
+            return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
+        }
+
+        public int hashCode()                      {return 0;}
+
+        // Override default methods in Map
+        @Override
+        @SuppressWarnings("unchecked")
+        public V getOrDefault(Object k, V defaultValue) {
+            return defaultValue;
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            Objects.requireNonNull(action);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            Objects.requireNonNull(function);
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Preserves singleton property
+        private Object readResolve() {
+            return EMPTY_MAP;
+        }
+    }
+
+    // Singleton collections
+
+    /**
+     * Returns an immutable set containing only the specified object.
+     * The returned set is serializable.
+     *
+     * @param  <T> the class of the objects in the set
+     * @param o the sole object to be stored in the returned set.
+     * @return an immutable set containing only the specified object.
+     */
+    public static <T> Set<T> singleton(T o) {
+        return new SingletonSet<>(o);
+    }
+
+    static <E> Iterator<E> singletonIterator(final E e) {
+        return new Iterator<E>() {
+            private boolean hasNext = true;
+            public boolean hasNext() {
+                return hasNext;
+            }
+            public E next() {
+                if (hasNext) {
+                    hasNext = false;
+                    return e;
+                }
+                throw new NoSuchElementException();
+            }
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public void forEachRemaining(Consumer<? super E> action) {
+                Objects.requireNonNull(action);
+                if (hasNext) {
+                    action.accept(e);
+                    hasNext = false;
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates a {@code Spliterator} with only the specified element
+     *
+     * @param <T> Type of elements
+     * @return A singleton {@code Spliterator}
+     */
+    static <T> Spliterator<T> singletonSpliterator(final T element) {
+        return new Spliterator<T>() {
+            long est = 1;
+
+            @Override
+            public Spliterator<T> trySplit() {
+                return null;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> consumer) {
+                Objects.requireNonNull(consumer);
+                if (est > 0) {
+                    est--;
+                    consumer.accept(element);
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> consumer) {
+                tryAdvance(consumer);
+            }
+
+            @Override
+            public long estimateSize() {
+                return est;
+            }
+
+            @Override
+            public int characteristics() {
+                int value = (element != null) ? Spliterator.NONNULL : 0;
+
+                return value | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE |
+                       Spliterator.DISTINCT | Spliterator.ORDERED;
+            }
+        };
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonSet<E>
+        extends AbstractSet<E>
+        implements Serializable
+    {
+        private static final long serialVersionUID = 3193687207550431679L;
+
+        private final E element;
+
+        SingletonSet(E e) {element = e;}
+
+        public Iterator<E> iterator() {
+            return singletonIterator(element);
+        }
+
+        public int size() {return 1;}
+
+        public boolean contains(Object o) {return eq(o, element);}
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return singletonSpliterator(element);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    /**
+     * Returns an immutable list containing only the specified object.
+     * The returned list is serializable.
+     *
+     * @param  <T> the class of the objects in the list
+     * @param o the sole object to be stored in the returned list.
+     * @return an immutable list containing only the specified object.
+     * @since 1.3
+     */
+    public static <T> List<T> singletonList(T o) {
+        return new SingletonList<>(o);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable {
+
+        private static final long serialVersionUID = 3093736618740652951L;
+
+        private final E element;
+
+        SingletonList(E obj)                {element = obj;}
+
+        public Iterator<E> iterator() {
+            return singletonIterator(element);
+        }
+
+        public int size()                   {return 1;}
+
+        public boolean contains(Object obj) {return eq(obj, element);}
+
+        public E get(int index) {
+            if (index != 0)
+              throw new IndexOutOfBoundsException("Index: "+index+", Size: 1");
+            return element;
+        }
+
+        // Override default methods for Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            action.accept(element);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw new UnsupportedOperationException();
+        }
+        @Override
+        public void sort(Comparator<? super E> c) {
+        }
+        @Override
+        public Spliterator<E> spliterator() {
+            return singletonSpliterator(element);
+        }
+    }
+
+    /**
+     * Returns an immutable map, mapping only the specified key to the
+     * specified value.  The returned map is serializable.
+     *
+     * @param <K> the class of the map keys
+     * @param <V> the class of the map values
+     * @param key the sole key to be stored in the returned map.
+     * @param value the value to which the returned map maps <tt>key</tt>.
+     * @return an immutable map containing only the specified key-value
+     *         mapping.
+     * @since 1.3
+     */
+    public static <K,V> Map<K,V> singletonMap(K key, V value) {
+        return new SingletonMap<>(key, value);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SingletonMap<K,V>
+          extends AbstractMap<K,V>
+          implements Serializable {
+        private static final long serialVersionUID = -6979724477215052911L;
+
+        private final K k;
+        private final V v;
+
+        SingletonMap(K key, V value) {
+            k = key;
+            v = value;
+        }
+
+        public int size()                                           {return 1;}
+        public boolean isEmpty()                                {return false;}
+        public boolean containsKey(Object key)             {return eq(key, k);}
+        public boolean containsValue(Object value)       {return eq(value, v);}
+        public V get(Object key)              {return (eq(key, k) ? v : null);}
+
+        private transient Set<K> keySet;
+        private transient Set<Map.Entry<K,V>> entrySet;
+        private transient Collection<V> values;
+
+        public Set<K> keySet() {
+            if (keySet==null)
+                keySet = singleton(k);
+            return keySet;
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            if (entrySet==null)
+                entrySet = Collections.<Map.Entry<K,V>>singleton(
+                    new SimpleImmutableEntry<>(k, v));
+            return entrySet;
+        }
+
+        public Collection<V> values() {
+            if (values==null)
+                values = singleton(v);
+            return values;
+        }
+
+        // Override default methods in Map
+        @Override
+        public V getOrDefault(Object key, V defaultValue) {
+            return eq(key, k) ? v : defaultValue;
+        }
+
+        @Override
+        public void forEach(BiConsumer<? super K, ? super V> action) {
+            action.accept(k, v);
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfAbsent(K key,
+                Function<? super K, ? extends V> mappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V computeIfPresent(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V compute(K key,
+                BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public V merge(K key, V value,
+                BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    // Miscellaneous
+
+    /**
+     * Returns an immutable list consisting of <tt>n</tt> copies of the
+     * specified object.  The newly allocated data object is tiny (it contains
+     * a single reference to the data object).  This method is useful in
+     * combination with the <tt>List.addAll</tt> method to grow lists.
+     * The returned list is serializable.
+     *
+     * @param  <T> the class of the object to copy and of the objects
+     *         in the returned list.
+     * @param  n the number of elements in the returned list.
+     * @param  o the element to appear repeatedly in the returned list.
+     * @return an immutable list consisting of <tt>n</tt> copies of the
+     *         specified object.
+     * @throws IllegalArgumentException if {@code n < 0}
+     * @see    List#addAll(Collection)
+     * @see    List#addAll(int, Collection)
+     */
+    public static <T> List<T> nCopies(int n, T o) {
+        if (n < 0)
+            throw new IllegalArgumentException("List length = " + n);
+        return new CopiesList<>(n, o);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class CopiesList<E>
+        extends AbstractList<E>
+        implements RandomAccess, Serializable
+    {
+        private static final long serialVersionUID = 2739099268398711800L;
+
+        final int n;
+        final E element;
+
+        CopiesList(int n, E e) {
+            assert n >= 0;
+            this.n = n;
+            element = e;
+        }
+
+        public int size() {
+            return n;
+        }
+
+        public boolean contains(Object obj) {
+            return n != 0 && eq(obj, element);
+        }
+
+        public int indexOf(Object o) {
+            return contains(o) ? 0 : -1;
+        }
+
+        public int lastIndexOf(Object o) {
+            return contains(o) ? n - 1 : -1;
+        }
+
+        public E get(int index) {
+            if (index < 0 || index >= n)
+                throw new IndexOutOfBoundsException("Index: "+index+
+                                                    ", Size: "+n);
+            return element;
+        }
+
+        public Object[] toArray() {
+            final Object[] a = new Object[n];
+            if (element != null)
+                Arrays.fill(a, 0, n, element);
+            return a;
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final int n = this.n;
+            if (a.length < n) {
+                a = (T[])java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), n);
+                if (element != null)
+                    Arrays.fill(a, 0, n, element);
+            } else {
+                Arrays.fill(a, 0, n, element);
+                if (a.length > n)
+                    a[n] = null;
+            }
+            return a;
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            if (fromIndex < 0)
+                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+            if (toIndex > n)
+                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+            if (fromIndex > toIndex)
+                throw new IllegalArgumentException("fromIndex(" + fromIndex +
+                                                   ") > toIndex(" + toIndex + ")");
+            return new CopiesList<>(toIndex - fromIndex, element);
+        }
+
+        // Override default methods in Collection
+        @Override
+        public Stream<E> stream() {
+            return IntStream.range(0, n).mapToObj(i -> element);
+        }
+
+        @Override
+        public Stream<E> parallelStream() {
+            return IntStream.range(0, n).parallel().mapToObj(i -> element);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return stream().spliterator();
+        }
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse of the <em>natural
+     * ordering</em> on a collection of objects that implement the
+     * {@code Comparable} interface.  (The natural ordering is the ordering
+     * imposed by the objects' own {@code compareTo} method.)  This enables a
+     * simple idiom for sorting (or maintaining) collections (or arrays) of
+     * objects that implement the {@code Comparable} interface in
+     * reverse-natural-order.  For example, suppose {@code a} is an array of
+     * strings. Then: <pre>
+     *          Arrays.sort(a, Collections.reverseOrder());
+     * </pre> sorts the array in reverse-lexicographic (alphabetical) order.<p>
+     *
+     * The returned comparator is serializable.
+     *
+     * @param  <T> the class of the objects compared by the comparator
+     * @return A comparator that imposes the reverse of the <i>natural
+     *         ordering</i> on a collection of objects that implement
+     *         the <tt>Comparable</tt> interface.
+     * @see Comparable
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Comparator<T> reverseOrder() {
+        return (Comparator<T>) ReverseComparator.REVERSE_ORDER;
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ReverseComparator
+        implements Comparator<Comparable<Object>>, Serializable {
+
+        private static final long serialVersionUID = 7207038068494060240L;
+
+        static final ReverseComparator REVERSE_ORDER
+            = new ReverseComparator();
+
+        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
+            return c2.compareTo(c1);
+        }
+
+        private Object readResolve() { return Collections.reverseOrder(); }
+
+        @Override
+        public Comparator<Comparable<Object>> reversed() {
+            return Comparator.naturalOrder();
+        }
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse ordering of the specified
+     * comparator.  If the specified comparator is {@code null}, this method is
+     * equivalent to {@link #reverseOrder()} (in other words, it returns a
+     * comparator that imposes the reverse of the <em>natural ordering</em> on
+     * a collection of objects that implement the Comparable interface).
+     *
+     * <p>The returned comparator is serializable (assuming the specified
+     * comparator is also serializable or {@code null}).
+     *
+     * @param <T> the class of the objects compared by the comparator
+     * @param cmp a comparator who's ordering is to be reversed by the returned
+     * comparator or {@code null}
+     * @return A comparator that imposes the reverse ordering of the
+     *         specified comparator.
+     * @since 1.5
+     */
+    public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
+        if (cmp == null)
+            return reverseOrder();
+
+        if (cmp instanceof ReverseComparator2)
+            return ((ReverseComparator2<T>)cmp).cmp;
+
+        return new ReverseComparator2<>(cmp);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class ReverseComparator2<T> implements Comparator<T>,
+        Serializable
+    {
+        private static final long serialVersionUID = 4374092139857L;
+
+        /**
+         * The comparator specified in the static factory.  This will never
+         * be null, as the static factory returns a ReverseComparator
+         * instance if its argument is null.
+         *
+         * @serial
+         */
+        final Comparator<T> cmp;
+
+        ReverseComparator2(Comparator<T> cmp) {
+            assert cmp != null;
+            this.cmp = cmp;
+        }
+
+        public int compare(T t1, T t2) {
+            return cmp.compare(t2, t1);
+        }
+
+        public boolean equals(Object o) {
+            return (o == this) ||
+                (o instanceof ReverseComparator2 &&
+                 cmp.equals(((ReverseComparator2)o).cmp));
+        }
+
+        public int hashCode() {
+            return cmp.hashCode() ^ Integer.MIN_VALUE;
+        }
+
+        @Override
+        public Comparator<T> reversed() {
+            return cmp;
+        }
+    }
+
+    /**
+     * Returns an enumeration over the specified collection.  This provides
+     * interoperability with legacy APIs that require an enumeration
+     * as input.
+     *
+     * @param  <T> the class of the objects in the collection
+     * @param c the collection for which an enumeration is to be returned.
+     * @return an enumeration over the specified collection.
+     * @see Enumeration
+     */
+    public static <T> Enumeration<T> enumeration(final Collection<T> c) {
+        return new Enumeration<T>() {
+            private final Iterator<T> i = c.iterator();
+
+            public boolean hasMoreElements() {
+                return i.hasNext();
+            }
+
+            public T nextElement() {
+                return i.next();
+            }
+        };
+    }
+
+    /**
+     * Returns an array list containing the elements returned by the
+     * specified enumeration in the order they are returned by the
+     * enumeration.  This method provides interoperability between
+     * legacy APIs that return enumerations and new APIs that require
+     * collections.
+     *
+     * @param <T> the class of the objects returned by the enumeration
+     * @param e enumeration providing elements for the returned
+     *          array list
+     * @return an array list containing the elements returned
+     *         by the specified enumeration.
+     * @since 1.4
+     * @see Enumeration
+     * @see ArrayList
+     */
+    public static <T> ArrayList<T> list(Enumeration<T> e) {
+        ArrayList<T> l = new ArrayList<>();
+        while (e.hasMoreElements())
+            l.add(e.nextElement());
+        return l;
+    }
+
+    /**
+     * Returns true if the specified arguments are equal, or both null.
+     *
+     * NB: Do not replace with Object.equals until JDK-8015417 is resolved.
+     */
+    static boolean eq(Object o1, Object o2) {
+        return o1==null ? o2==null : o1.equals(o2);
+    }
+
+    /**
+     * Returns the number of elements in the specified collection equal to the
+     * specified object.  More formally, returns the number of elements
+     * <tt>e</tt> in the collection such that
+     * <tt>(o == null ? e == null : o.equals(e))</tt>.
+     *
+     * @param c the collection in which to determine the frequency
+     *     of <tt>o</tt>
+     * @param o the object whose frequency is to be determined
+     * @return the number of elements in {@code c} equal to {@code o}
+     * @throws NullPointerException if <tt>c</tt> is null
+     * @since 1.5
+     */
+    public static int frequency(Collection<?> c, Object o) {
+        int result = 0;
+        if (o == null) {
+            for (Object e : c)
+                if (e == null)
+                    result++;
+        } else {
+            for (Object e : c)
+                if (o.equals(e))
+                    result++;
+        }
+        return result;
+    }
+
+    /**
+     * Returns {@code true} if the two specified collections have no
+     * elements in common.
+     *
+     * <p>Care must be exercised if this method is used on collections that
+     * do not comply with the general contract for {@code Collection}.
+     * Implementations may elect to iterate over either collection and test
+     * for containment in the other collection (or to perform any equivalent
+     * computation).  If either collection uses a nonstandard equality test
+     * (as does a {@link SortedSet} whose ordering is not <em>compatible with
+     * equals</em>, or the key set of an {@link IdentityHashMap}), both
+     * collections must use the same nonstandard equality test, or the
+     * result of this method is undefined.
+     *
+     * <p>Care must also be exercised when using collections that have
+     * restrictions on the elements that they may contain. Collection
+     * implementations are allowed to throw exceptions for any operation
+     * involving elements they deem ineligible. For absolute safety the
+     * specified collections should contain only elements which are
+     * eligible elements for both collections.
+     *
+     * <p>Note that it is permissible to pass the same collection in both
+     * parameters, in which case the method will return {@code true} if and
+     * only if the collection is empty.
+     *
+     * @param c1 a collection
+     * @param c2 a collection
+     * @return {@code true} if the two specified collections have no
+     * elements in common.
+     * @throws NullPointerException if either collection is {@code null}.
+     * @throws NullPointerException if one collection contains a {@code null}
+     * element and {@code null} is not an eligible element for the other collection.
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if one collection contains an element that is
+     * of a type which is ineligible for the other collection.
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.5
+     */
+    public static boolean disjoint(Collection<?> c1, Collection<?> c2) {
+        // The collection to be used for contains(). Preference is given to
+        // the collection who's contains() has lower O() complexity.
+        Collection<?> contains = c2;
+        // The collection to be iterated. If the collections' contains() impl
+        // are of different O() complexity, the collection with slower
+        // contains() will be used for iteration. For collections who's
+        // contains() are of the same complexity then best performance is
+        // achieved by iterating the smaller collection.
+        Collection<?> iterate = c1;
+
+        // Performance optimization cases. The heuristics:
+        //   1. Generally iterate over c1.
+        //   2. If c1 is a Set then iterate over c2.
+        //   3. If either collection is empty then result is always true.
+        //   4. Iterate over the smaller Collection.
+        if (c1 instanceof Set) {
+            // Use c1 for contains as a Set's contains() is expected to perform
+            // better than O(N/2)
+            iterate = c2;
+            contains = c1;
+        } else if (!(c2 instanceof Set)) {
+            // Both are mere Collections. Iterate over smaller collection.
+            // Example: If c1 contains 3 elements and c2 contains 50 elements and
+            // assuming contains() requires ceiling(N/2) comparisons then
+            // checking for all c1 elements in c2 would require 75 comparisons
+            // (3 * ceiling(50/2)) vs. checking all c2 elements in c1 requiring
+            // 100 comparisons (50 * ceiling(3/2)).
+            int c1size = c1.size();
+            int c2size = c2.size();
+            if (c1size == 0 || c2size == 0) {
+                // At least one collection is empty. Nothing will match.
+                return true;
+            }
+
+            if (c1size > c2size) {
+                iterate = c2;
+                contains = c1;
+            }
+        }
+
+        for (Object e : iterate) {
+            if (contains.contains(e)) {
+               // Found a common element. Collections are not disjoint.
+                return false;
+            }
+        }
+
+        // No common elements were found.
+        return true;
+    }
+
+    /**
+     * Adds all of the specified elements to the specified collection.
+     * Elements to be added may be specified individually or as an array.
+     * The behavior of this convenience method is identical to that of
+     * <tt>c.addAll(Arrays.asList(elements))</tt>, but this method is likely
+     * to run significantly faster under most implementations.
+     *
+     * <p>When elements are specified individually, this method provides a
+     * convenient way to add a few elements to an existing collection:
+     * <pre>
+     *     Collections.addAll(flavors, "Peaches 'n Plutonium", "Rocky Racoon");
+     * </pre>
+     *
+     * @param  <T> the class of the elements to add and of the collection
+     * @param c the collection into which <tt>elements</tt> are to be inserted
+     * @param elements the elements to insert into <tt>c</tt>
+     * @return <tt>true</tt> if the collection changed as a result of the call
+     * @throws UnsupportedOperationException if <tt>c</tt> does not support
+     *         the <tt>add</tt> operation
+     * @throws NullPointerException if <tt>elements</tt> contains one or more
+     *         null values and <tt>c</tt> does not permit null elements, or
+     *         if <tt>c</tt> or <tt>elements</tt> are <tt>null</tt>
+     * @throws IllegalArgumentException if some property of a value in
+     *         <tt>elements</tt> prevents it from being added to <tt>c</tt>
+     * @see Collection#addAll(Collection)
+     * @since 1.5
+     */
+    @SafeVarargs
+    public static <T> boolean addAll(Collection<? super T> c, T... elements) {
+        boolean result = false;
+        for (T element : elements)
+            result |= c.add(element);
+        return result;
+    }
+
+    /**
+     * Returns a set backed by the specified map.  The resulting set displays
+     * the same ordering, concurrency, and performance characteristics as the
+     * backing map.  In essence, this factory method provides a {@link Set}
+     * implementation corresponding to any {@link Map} implementation.  There
+     * is no need to use this method on a {@link Map} implementation that
+     * already has a corresponding {@link Set} implementation (such as {@link
+     * HashMap} or {@link TreeMap}).
+     *
+     * <p>Each method invocation on the set returned by this method results in
+     * exactly one method invocation on the backing map or its <tt>keySet</tt>
+     * view, with one exception.  The <tt>addAll</tt> method is implemented
+     * as a sequence of <tt>put</tt> invocations on the backing map.
+     *
+     * <p>The specified map must be empty at the time this method is invoked,
+     * and should not be accessed directly after this method returns.  These
+     * conditions are ensured if the map is created empty, passed directly
+     * to this method, and no reference to the map is retained, as illustrated
+     * in the following code fragment:
+     * <pre>
+     *    Set&lt;Object&gt; weakHashSet = Collections.newSetFromMap(
+     *        new WeakHashMap&lt;Object, Boolean&gt;());
+     * </pre>
+     *
+     * @param <E> the class of the map keys and of the objects in the
+     *        returned set
+     * @param map the backing map
+     * @return the set backed by the map
+     * @throws IllegalArgumentException if <tt>map</tt> is not empty
+     * @since 1.6
+     */
+    public static <E> Set<E> newSetFromMap(Map<E, Boolean> map) {
+        return new SetFromMap<>(map);
+    }
+
+    /**
+     * @serial include
+     */
+    private static class SetFromMap<E> extends AbstractSet<E>
+        implements Set<E>, Serializable
+    {
+        private final Map<E, Boolean> m;  // The backing map
+        private transient Set<E> s;       // Its keySet
+
+        SetFromMap(Map<E, Boolean> map) {
+            if (!map.isEmpty())
+                throw new IllegalArgumentException("Map is non-empty");
+            m = map;
+            s = map.keySet();
+        }
+
+        public void clear()               {        m.clear(); }
+        public int size()                 { return m.size(); }
+        public boolean isEmpty()          { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o)   { return m.remove(o) != null; }
+        public boolean add(E e) { return m.put(e, Boolean.TRUE) == null; }
+        public Iterator<E> iterator()     { return s.iterator(); }
+        public Object[] toArray()         { return s.toArray(); }
+        public <T> T[] toArray(T[] a)     { return s.toArray(a); }
+        public String toString()          { return s.toString(); }
+        public int hashCode()             { return s.hashCode(); }
+        public boolean equals(Object o)   { return o == this || s.equals(o); }
+        public boolean containsAll(Collection<?> c) {return s.containsAll(c);}
+        public boolean removeAll(Collection<?> c)   {return s.removeAll(c);}
+        public boolean retainAll(Collection<?> c)   {return s.retainAll(c);}
+        // addAll is the only inherited implementation
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {
+            s.forEach(action);
+        }
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return s.removeIf(filter);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {return s.spliterator();}
+        @Override
+        public Stream<E> stream()           {return s.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return s.parallelStream();}
+
+        private static final long serialVersionUID = 2454657854757543876L;
+
+        private void readObject(java.io.ObjectInputStream stream)
+            throws IOException, ClassNotFoundException
+        {
+            stream.defaultReadObject();
+            s = m.keySet();
+        }
+    }
+
+    /**
+     * Returns a view of a {@link Deque} as a Last-in-first-out (Lifo)
+     * {@link Queue}. Method <tt>add</tt> is mapped to <tt>push</tt>,
+     * <tt>remove</tt> is mapped to <tt>pop</tt> and so on. This
+     * view can be useful when you would like to use a method
+     * requiring a <tt>Queue</tt> but you need Lifo ordering.
+     *
+     * <p>Each method invocation on the queue returned by this method
+     * results in exactly one method invocation on the backing deque, with
+     * one exception.  The {@link Queue#addAll addAll} method is
+     * implemented as a sequence of {@link Deque#addFirst addFirst}
+     * invocations on the backing deque.
+     *
+     * @param  <T> the class of the objects in the deque
+     * @param deque the deque
+     * @return the queue
+     * @since  1.6
+     */
+    public static <T> Queue<T> asLifoQueue(Deque<T> deque) {
+        return new AsLIFOQueue<>(deque);
+    }
+
+    /**
+     * @serial include
+     */
+    static class AsLIFOQueue<E> extends AbstractQueue<E>
+        implements Queue<E>, Serializable {
+        private static final long serialVersionUID = 1802017725587941708L;
+        private final Deque<E> q;
+        AsLIFOQueue(Deque<E> q)           { this.q = q; }
+        public boolean add(E e)           { q.addFirst(e); return true; }
+        public boolean offer(E e)         { return q.offerFirst(e); }
+        public E poll()                   { return q.pollFirst(); }
+        public E remove()                 { return q.removeFirst(); }
+        public E peek()                   { return q.peekFirst(); }
+        public E element()                { return q.getFirst(); }
+        public void clear()               {        q.clear(); }
+        public int size()                 { return q.size(); }
+        public boolean isEmpty()          { return q.isEmpty(); }
+        public boolean contains(Object o) { return q.contains(o); }
+        public boolean remove(Object o)   { return q.remove(o); }
+        public Iterator<E> iterator()     { return q.iterator(); }
+        public Object[] toArray()         { return q.toArray(); }
+        public <T> T[] toArray(T[] a)     { return q.toArray(a); }
+        public String toString()          { return q.toString(); }
+        public boolean containsAll(Collection<?> c) {return q.containsAll(c);}
+        public boolean removeAll(Collection<?> c)   {return q.removeAll(c);}
+        public boolean retainAll(Collection<?> c)   {return q.retainAll(c);}
+        // We use inherited addAll; forwarding addAll would be wrong
+
+        // Override default methods in Collection
+        @Override
+        public void forEach(Consumer<? super E> action) {q.forEach(action);}
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            return q.removeIf(filter);
+        }
+        @Override
+        public Spliterator<E> spliterator() {return q.spliterator();}
+        @Override
+        public Stream<E> stream()           {return q.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return q.parallelStream();}
+    }
+}
diff --git a/java/util/ComparableTimSort.java b/java/util/ComparableTimSort.java
new file mode 100644
index 0000000..36c8d90
--- /dev/null
+++ b/java/util/ComparableTimSort.java
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2009 Google Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This is a near duplicate of {@link TimSort}, modified for use with
+ * arrays of objects that implement {@link Comparable}, instead of using
+ * explicit comparators.
+ *
+ * <p>If you are using an optimizing VM, you may find that ComparableTimSort
+ * offers no performance benefit over TimSort in conjunction with a
+ * comparator that simply returns {@code ((Comparable)first).compareTo(Second)}.
+ * If this is the case, you are better off deleting ComparableTimSort to
+ * eliminate the code duplication.  (See Arrays.java for details.)
+ *
+ * @author Josh Bloch
+ */
+class ComparableTimSort {
+    /**
+     * This is the minimum sized sequence that will be merged.  Shorter
+     * sequences will be lengthened by calling binarySort.  If the entire
+     * array is less than this length, no merges will be performed.
+     *
+     * This constant should be a power of two.  It was 64 in Tim Peter's C
+     * implementation, but 32 was empirically determined to work better in
+     * this implementation.  In the unlikely event that you set this constant
+     * to be a number that's not a power of two, you'll need to change the
+     * {@link #minRunLength} computation.
+     *
+     * If you decrease this constant, you must change the stackLen
+     * computation in the TimSort constructor, or you risk an
+     * ArrayOutOfBounds exception.  See listsort.txt for a discussion
+     * of the minimum stack length required as a function of the length
+     * of the array being sorted and the minimum merge sequence length.
+     */
+    private static final int MIN_MERGE = 32;
+
+    /**
+     * The array being sorted.
+     */
+    private final Object[] a;
+
+    /**
+     * When we get into galloping mode, we stay there until both runs win less
+     * often than MIN_GALLOP consecutive times.
+     */
+    private static final int  MIN_GALLOP = 7;
+
+    /**
+     * This controls when we get *into* galloping mode.  It is initialized
+     * to MIN_GALLOP.  The mergeLo and mergeHi methods nudge it higher for
+     * random data, and lower for highly structured data.
+     */
+    private int minGallop = MIN_GALLOP;
+
+    /**
+     * Maximum initial size of tmp array, which is used for merging.  The array
+     * can grow to accommodate demand.
+     *
+     * Unlike Tim's original C version, we do not allocate this much storage
+     * when sorting smaller arrays.  This change was required for performance.
+     */
+    private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
+
+    /**
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
+     */
+    private Object[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
+
+    /**
+     * A stack of pending runs yet to be merged.  Run i starts at
+     * address base[i] and extends for len[i] elements.  It's always
+     * true (so long as the indices are in bounds) that:
+     *
+     *     runBase[i] + runLen[i] == runBase[i + 1]
+     *
+     * so we could cut the storage for this, but it's a minor amount,
+     * and keeping all the info explicit simplifies the code.
+     */
+    private int stackSize = 0;  // Number of pending runs on stack
+    private final int[] runBase;
+    private final int[] runLen;
+
+    /**
+     * Creates a TimSort instance to maintain the state of an ongoing sort.
+     *
+     * @param a the array to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private ComparableTimSort(Object[] a, Object[] work, int workBase, int workLen) {
+        this.a = a;
+
+        // Allocate temp storage (which may be increased later if necessary)
+        int len = a.length;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            tmp = new Object[tlen];
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
+
+        /*
+         * Allocate runs-to-be-merged stack (which cannot be expanded).  The
+         * stack length requirements are described in listsort.txt.  The C
+         * version always uses the same stack length (85), but this was
+         * measured to be too expensive when sorting "mid-sized" arrays (e.g.,
+         * 100 elements) in Java.  Therefore, we use smaller (but sufficiently
+         * large) stack lengths for smaller arrays.  The "magic numbers" in the
+         * computation below must be changed if MIN_MERGE is decreased.  See
+         * the MIN_MERGE declaration above for more information.
+         * The maximum value of 49 allows for an array up to length
+         * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+         * increasing scenario. More explanations are given in section 4 of:
+         * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
+         */
+        int stackLen = (len <    120  ?  5 :
+                        len <   1542  ? 10 :
+                        len < 119151  ? 24 : 49);
+        runBase = new int[stackLen];
+        runLen = new int[stackLen];
+    }
+
+    /*
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
+     */
+
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
+        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
+
+        int nRemaining  = hi - lo;
+        if (nRemaining < 2)
+            return;  // Arrays of size 0 and 1 are always sorted
+
+        // If array is small, do a "mini-TimSort" with no merges
+        if (nRemaining < MIN_MERGE) {
+            int initRunLen = countRunAndMakeAscending(a, lo, hi);
+            binarySort(a, lo, hi, lo + initRunLen);
+            return;
+        }
+
+        /**
+         * March over the array once, left to right, finding natural runs,
+         * extending short natural runs to minRun elements, and merging runs
+         * to maintain stack invariant.
+         */
+        ComparableTimSort ts = new ComparableTimSort(a, work, workBase, workLen);
+        int minRun = minRunLength(nRemaining);
+        do {
+            // Identify next run
+            int runLen = countRunAndMakeAscending(a, lo, hi);
+
+            // If run is short, extend to min(minRun, nRemaining)
+            if (runLen < minRun) {
+                int force = nRemaining <= minRun ? nRemaining : minRun;
+                binarySort(a, lo, lo + force, lo + runLen);
+                runLen = force;
+            }
+
+            // Push run onto pending-run stack, and maybe merge
+            ts.pushRun(lo, runLen);
+            ts.mergeCollapse();
+
+            // Advance to find next run
+            lo += runLen;
+            nRemaining -= runLen;
+        } while (nRemaining != 0);
+
+        // Merge all remaining runs to complete sort
+        assert lo == hi;
+        ts.mergeForceCollapse();
+        assert ts.stackSize == 1;
+    }
+
+    /**
+     * Sorts the specified portion of the specified array using a binary
+     * insertion sort.  This is the best method for sorting small numbers
+     * of elements.  It requires O(n log n) compares, but O(n^2) data
+     * movement (worst case).
+     *
+     * If the initial part of the specified range is already sorted,
+     * this method can take advantage of it: the method assumes that the
+     * elements from index {@code lo}, inclusive, to {@code start},
+     * exclusive are already sorted.
+     *
+     * @param a the array in which a range is to be sorted
+     * @param lo the index of the first element in the range to be sorted
+     * @param hi the index after the last element in the range to be sorted
+     * @param start the index of the first element in the range that is
+     *        not already known to be sorted ({@code lo <= start <= hi})
+     */
+    @SuppressWarnings({"fallthrough", "rawtypes", "unchecked"})
+    private static void binarySort(Object[] a, int lo, int hi, int start) {
+        assert lo <= start && start <= hi;
+        if (start == lo)
+            start++;
+        for ( ; start < hi; start++) {
+            Comparable pivot = (Comparable) a[start];
+
+            // Set left (and right) to the index where a[start] (pivot) belongs
+            int left = lo;
+            int right = start;
+            assert left <= right;
+            /*
+             * Invariants:
+             *   pivot >= all in [lo, left).
+             *   pivot <  all in [right, start).
+             */
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+                if (pivot.compareTo(a[mid]) < 0)
+                    right = mid;
+                else
+                    left = mid + 1;
+            }
+            assert left == right;
+
+            /*
+             * The invariants still hold: pivot >= all in [lo, left) and
+             * pivot < all in [left, start), so pivot belongs at left.  Note
+             * that if there are elements equal to pivot, left points to the
+             * first slot after them -- that's why this sort is stable.
+             * Slide elements over to make room for pivot.
+             */
+            int n = start - left;  // The number of elements to move
+            // Switch is just an optimization for arraycopy in default case
+            switch (n) {
+                case 2:  a[left + 2] = a[left + 1];
+                case 1:  a[left + 1] = a[left];
+                         break;
+                default: System.arraycopy(a, left, a, left + 1, n);
+            }
+            a[left] = pivot;
+        }
+    }
+
+    /**
+     * Returns the length of the run beginning at the specified position in
+     * the specified array and reverses the run if it is descending (ensuring
+     * that the run will always be ascending when the method returns).
+     *
+     * A run is the longest ascending sequence with:
+     *
+     *    a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
+     *
+     * or the longest descending sequence with:
+     *
+     *    a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
+     *
+     * For its intended use in a stable mergesort, the strictness of the
+     * definition of "descending" is needed so that the call can safely
+     * reverse a descending sequence without violating stability.
+     *
+     * @param a the array in which a run is to be counted and possibly reversed
+     * @param lo index of the first element in the run
+     * @param hi index after the last element that may be contained in the run.
+              It is required that {@code lo < hi}.
+     * @return  the length of the run beginning at the specified position in
+     *          the specified array
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
+        assert lo < hi;
+        int runHi = lo + 1;
+        if (runHi == hi)
+            return 1;
+
+        // Find end of run, and reverse range if descending
+        if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0) { // Descending
+            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) < 0)
+                runHi++;
+            reverseRange(a, lo, runHi);
+        } else {                              // Ascending
+            while (runHi < hi && ((Comparable) a[runHi]).compareTo(a[runHi - 1]) >= 0)
+                runHi++;
+        }
+
+        return runHi - lo;
+    }
+
+    /**
+     * Reverse the specified range of the specified array.
+     *
+     * @param a the array in which a range is to be reversed
+     * @param lo the index of the first element in the range to be reversed
+     * @param hi the index after the last element in the range to be reversed
+     */
+    private static void reverseRange(Object[] a, int lo, int hi) {
+        hi--;
+        while (lo < hi) {
+            Object t = a[lo];
+            a[lo++] = a[hi];
+            a[hi--] = t;
+        }
+    }
+
+    /**
+     * Returns the minimum acceptable run length for an array of the specified
+     * length. Natural runs shorter than this will be extended with
+     * {@link #binarySort}.
+     *
+     * Roughly speaking, the computation is:
+     *
+     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
+     *  Else if n is an exact power of 2, return MIN_MERGE/2.
+     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
+     *   is close to, but strictly less than, an exact power of 2.
+     *
+     * For the rationale, see listsort.txt.
+     *
+     * @param n the length of the array to be sorted
+     * @return the length of the minimum run to be merged
+     */
+    private static int minRunLength(int n) {
+        assert n >= 0;
+        int r = 0;      // Becomes 1 if any 1 bits are shifted off
+        while (n >= MIN_MERGE) {
+            r |= (n & 1);
+            n >>= 1;
+        }
+        return n + r;
+    }
+
+    /**
+     * Pushes the specified run onto the pending-run stack.
+     *
+     * @param runBase index of the first element in the run
+     * @param runLen  the number of elements in the run
+     */
+    private void pushRun(int runBase, int runLen) {
+        this.runBase[stackSize] = runBase;
+        this.runLen[stackSize] = runLen;
+        stackSize++;
+    }
+
+    /**
+     * Examines the stack of runs waiting to be merged and merges adjacent runs
+     * until the stack invariants are reestablished:
+     *
+     *     1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
+     *     2. runLen[i - 2] > runLen[i - 1]
+     *
+     * This method is called each time a new run is pushed onto the stack,
+     * so the invariants are guaranteed to hold for i < stackSize upon
+     * entry to the method.
+     */
+    private void mergeCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {
+                if (runLen[n - 1] < runLen[n + 1])
+                    n--;
+                mergeAt(n);
+            } else if (runLen[n] <= runLen[n + 1]) {
+                mergeAt(n);
+            } else {
+                break; // Invariant is established
+            }
+        }
+    }
+
+    /**
+     * Merges all runs on the stack until only one remains.  This method is
+     * called once, to complete the sort.
+     */
+    private void mergeForceCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n - 1] < runLen[n + 1])
+                n--;
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges the two runs at stack indices i and i+1.  Run i must be
+     * the penultimate or antepenultimate run on the stack.  In other words,
+     * i must be equal to stackSize-2 or stackSize-3.
+     *
+     * @param i stack index of the first of the two runs to merge
+     */
+    @SuppressWarnings("unchecked")
+    private void mergeAt(int i) {
+        assert stackSize >= 2;
+        assert i >= 0;
+        assert i == stackSize - 2 || i == stackSize - 3;
+
+        int base1 = runBase[i];
+        int len1 = runLen[i];
+        int base2 = runBase[i + 1];
+        int len2 = runLen[i + 1];
+        assert len1 > 0 && len2 > 0;
+        assert base1 + len1 == base2;
+
+        /*
+         * Record the length of the combined runs; if i is the 3rd-last
+         * run now, also slide over the last run (which isn't involved
+         * in this merge).  The current run (i+1) goes away in any case.
+         */
+        runLen[i] = len1 + len2;
+        if (i == stackSize - 3) {
+            runBase[i + 1] = runBase[i + 2];
+            runLen[i + 1] = runLen[i + 2];
+        }
+        stackSize--;
+
+        /*
+         * Find where the first element of run2 goes in run1. Prior elements
+         * in run1 can be ignored (because they're already in place).
+         */
+        int k = gallopRight((Comparable<Object>) a[base2], a, base1, len1, 0);
+        assert k >= 0;
+        base1 += k;
+        len1 -= k;
+        if (len1 == 0)
+            return;
+
+        /*
+         * Find where the last element of run1 goes in run2. Subsequent elements
+         * in run2 can be ignored (because they're already in place).
+         */
+        len2 = gallopLeft((Comparable<Object>) a[base1 + len1 - 1], a,
+                base2, len2, len2 - 1);
+        assert len2 >= 0;
+        if (len2 == 0)
+            return;
+
+        // Merge remaining runs, using tmp array with min(len1, len2) elements
+        if (len1 <= len2)
+            mergeLo(base1, len1, base2, len2);
+        else
+            mergeHi(base1, len1, base2, len2);
+    }
+
+    /**
+     * Locates the position at which to insert the specified key into the
+     * specified sorted range; if the range contains an element equal to key,
+     * returns the index of the leftmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] < key <= a[b + k],
+     *    pretending that a[b - 1] is minus infinity and a[b + n] is infinity.
+     *    In other words, key belongs at index b + k; or in other words,
+     *    the first k elements of a should precede key, and the last n - k
+     *    should follow it.
+     */
+    private static int gallopLeft(Comparable<Object> key, Object[] a,
+            int base, int len, int hint) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int lastOfs = 0;
+        int ofs = 1;
+        if (key.compareTo(a[base + hint]) > 0) {
+            // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && key.compareTo(a[base + hint + ofs]) > 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            lastOfs += hint;
+            ofs += hint;
+        } else { // key <= a[base + hint]
+            // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs]
+            final int maxOfs = hint + 1;
+            while (ofs < maxOfs && key.compareTo(a[base + hint - ofs]) <= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere
+         * to the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (key.compareTo(a[base + m]) > 0)
+                lastOfs = m + 1;  // a[base + m] < key
+            else
+                ofs = m;          // key <= a[base + m]
+        }
+        assert lastOfs == ofs;    // so a[base + ofs - 1] < key <= a[base + ofs]
+        return ofs;
+    }
+
+    /**
+     * Like gallopLeft, except that if the range contains an element equal to
+     * key, gallopRight returns the index after the rightmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] <= key < a[b + k]
+     */
+    private static int gallopRight(Comparable<Object> key, Object[] a,
+            int base, int len, int hint) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int ofs = 1;
+        int lastOfs = 0;
+        if (key.compareTo(a[base + hint]) < 0) {
+            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
+            int maxOfs = hint + 1;
+            while (ofs < maxOfs && key.compareTo(a[base + hint - ofs]) < 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        } else { // a[b + hint] <= key
+            // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && key.compareTo(a[base + hint + ofs]) >= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            lastOfs += hint;
+            ofs += hint;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
+         * the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (key.compareTo(a[base + m]) < 0)
+                ofs = m;          // key < a[b + m]
+            else
+                lastOfs = m + 1;  // a[b + m] <= key
+        }
+        assert lastOfs == ofs;    // so a[b + ofs - 1] <= key < a[b + ofs]
+        return ofs;
+    }
+
+    /**
+     * Merges two adjacent runs in place, in a stable fashion.  The first
+     * element of the first run must be greater than the first element of the
+     * second run (a[base1] > a[base2]), and the last element of the first run
+     * (a[base1 + len1-1]) must be greater than all elements of the second run.
+     *
+     * For performance, this method should be called only when len1 <= len2;
+     * its twin, mergeHi should be called if len1 >= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeLo(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy first run into temp array
+        Object[] a = this.a; // For performance
+        Object[] tmp = ensureCapacity(len1);
+
+        int cursor1 = tmpBase; // Indexes into tmp array
+        int cursor2 = base2;   // Indexes int a
+        int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
+
+        // Move first element of second run and deal with degenerate cases
+        a[dest++] = a[cursor2++];
+        if (--len2 == 0) {
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+            return;
+        }
+        if (len1 == 1) {
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
+            return;
+        }
+
+        int minGallop = this.minGallop;  // Use local variable for performance
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run starts
+             * winning consistently.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                if (((Comparable) a[cursor2]).compareTo(tmp[cursor1]) < 0) {
+                    a[dest++] = a[cursor2++];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 0)
+                        break outer;
+                } else {
+                    a[dest++] = tmp[cursor1++];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                count1 = gallopRight((Comparable) a[cursor2], tmp, cursor1, len1, 0);
+                if (count1 != 0) {
+                    System.arraycopy(tmp, cursor1, a, dest, count1);
+                    dest += count1;
+                    cursor1 += count1;
+                    len1 -= count1;
+                    if (len1 <= 1)  // len1 == 1 || len1 == 0
+                        break outer;
+                }
+                a[dest++] = a[cursor2++];
+                if (--len2 == 0)
+                    break outer;
+
+                count2 = gallopLeft((Comparable) tmp[cursor1], a, cursor2, len2, 0);
+                if (count2 != 0) {
+                    System.arraycopy(a, cursor2, a, dest, count2);
+                    dest += count2;
+                    cursor2 += count2;
+                    len2 -= count2;
+                    if (len2 == 0)
+                        break outer;
+                }
+                a[dest++] = tmp[cursor1++];
+                if (--len1 == 1)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len1 == 1) {
+            assert len2 > 0;
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
+        } else if (len1 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len2 == 0;
+            assert len1 > 1;
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+        }
+    }
+
+    /**
+     * Like mergeLo, except that this method should be called only if
+     * len1 >= len2; mergeLo should be called if len1 <= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    private void mergeHi(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy second run into temp array
+        Object[] a = this.a; // For performance
+        Object[] tmp = ensureCapacity(len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
+
+        int cursor1 = base1 + len1 - 1;  // Indexes into a
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
+        int dest = base2 + len2 - 1;     // Indexes into a
+
+        // Move last element of first run and deal with degenerate cases
+        a[dest--] = a[cursor1--];
+        if (--len1 == 0) {
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+            return;
+        }
+        if (len2 == 1) {
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];
+            return;
+        }
+
+        int minGallop = this.minGallop;  // Use local variable for performance
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run
+             * appears to win consistently.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                if (((Comparable) tmp[cursor2]).compareTo(a[cursor1]) < 0) {
+                    a[dest--] = a[cursor1--];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 0)
+                        break outer;
+                } else {
+                    a[dest--] = tmp[cursor2--];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                count1 = len1 - gallopRight((Comparable) tmp[cursor2], a, base1, len1, len1 - 1);
+                if (count1 != 0) {
+                    dest -= count1;
+                    cursor1 -= count1;
+                    len1 -= count1;
+                    System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
+                    if (len1 == 0)
+                        break outer;
+                }
+                a[dest--] = tmp[cursor2--];
+                if (--len2 == 1)
+                    break outer;
+
+                count2 = len2 - gallopLeft((Comparable) a[cursor1], tmp, tmpBase, len2, len2 - 1);
+                if (count2 != 0) {
+                    dest -= count2;
+                    cursor2 -= count2;
+                    len2 -= count2;
+                    System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
+                    if (len2 <= 1)
+                        break outer; // len2 == 1 || len2 == 0
+                }
+                a[dest--] = a[cursor1--];
+                if (--len1 == 0)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len2 == 1) {
+            assert len1 > 0;
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge
+        } else if (len2 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len1 == 0;
+            assert len2 > 0;
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+        }
+    }
+
+    /**
+     * Ensures that the external array tmp has at least the specified
+     * number of elements, increasing its size if necessary.  The size
+     * increases exponentially to ensure amortized linear time complexity.
+     *
+     * @param minCapacity the minimum required capacity of the tmp array
+     * @return tmp, whether or not it grew
+     */
+    private Object[]  ensureCapacity(int minCapacity) {
+        if (tmpLen < minCapacity) {
+            // Compute smallest power of 2 > minCapacity
+            int newSize = minCapacity;
+            newSize |= newSize >> 1;
+            newSize |= newSize >> 2;
+            newSize |= newSize >> 4;
+            newSize |= newSize >> 8;
+            newSize |= newSize >> 16;
+            newSize++;
+
+            if (newSize < 0) // Not bloody likely!
+                newSize = minCapacity;
+            else
+                newSize = Math.min(newSize, a.length >>> 1);
+
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            Object[] newArray = new Object[newSize];
+            tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
+        }
+        return tmp;
+    }
+
+}
diff --git a/java/util/Comparator.java b/java/util/Comparator.java
new file mode 100644
index 0000000..ecf8d64
--- /dev/null
+++ b/java/util/Comparator.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.Function;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.Comparators;
+
+/**
+ * A comparison function, which imposes a <i>total ordering</i> on some
+ * collection of objects.  Comparators can be passed to a sort method (such
+ * as {@link Collections#sort(List,Comparator) Collections.sort} or {@link
+ * Arrays#sort(Object[],Comparator) Arrays.sort}) to allow precise control
+ * over the sort order.  Comparators can also be used to control the order of
+ * certain data structures (such as {@link SortedSet sorted sets} or {@link
+ * SortedMap sorted maps}), or to provide an ordering for collections of
+ * objects that don't have a {@link Comparable natural ordering}.<p>
+ *
+ * The ordering imposed by a comparator <tt>c</tt> on a set of elements
+ * <tt>S</tt> is said to be <i>consistent with equals</i> if and only if
+ * <tt>c.compare(e1, e2)==0</tt> has the same boolean value as
+ * <tt>e1.equals(e2)</tt> for every <tt>e1</tt> and <tt>e2</tt> in
+ * <tt>S</tt>.<p>
+ *
+ * Caution should be exercised when using a comparator capable of imposing an
+ * ordering inconsistent with equals to order a sorted set (or sorted map).
+ * Suppose a sorted set (or sorted map) with an explicit comparator <tt>c</tt>
+ * is used with elements (or keys) drawn from a set <tt>S</tt>.  If the
+ * ordering imposed by <tt>c</tt> on <tt>S</tt> is inconsistent with equals,
+ * the sorted set (or sorted map) will behave "strangely."  In particular the
+ * sorted set (or sorted map) will violate the general contract for set (or
+ * map), which is defined in terms of <tt>equals</tt>.<p>
+ *
+ * For example, suppose one adds two elements {@code a} and {@code b} such that
+ * {@code (a.equals(b) && c.compare(a, b) != 0)}
+ * to an empty {@code TreeSet} with comparator {@code c}.
+ * The second {@code add} operation will return
+ * true (and the size of the tree set will increase) because {@code a} and
+ * {@code b} are not equivalent from the tree set's perspective, even though
+ * this is contrary to the specification of the
+ * {@link Set#add Set.add} method.<p>
+ *
+ * Note: It is generally a good idea for comparators to also implement
+ * <tt>java.io.Serializable</tt>, as they may be used as ordering methods in
+ * serializable data structures (like {@link TreeSet}, {@link TreeMap}).  In
+ * order for the data structure to serialize successfully, the comparator (if
+ * provided) must implement <tt>Serializable</tt>.<p>
+ *
+ * For the mathematically inclined, the <i>relation</i> that defines the
+ * <i>imposed ordering</i> that a given comparator <tt>c</tt> imposes on a
+ * given set of objects <tt>S</tt> is:<pre>
+ *       {(x, y) such that c.compare(x, y) &lt;= 0}.
+ * </pre> The <i>quotient</i> for this total order is:<pre>
+ *       {(x, y) such that c.compare(x, y) == 0}.
+ * </pre>
+ *
+ * It follows immediately from the contract for <tt>compare</tt> that the
+ * quotient is an <i>equivalence relation</i> on <tt>S</tt>, and that the
+ * imposed ordering is a <i>total order</i> on <tt>S</tt>.  When we say that
+ * the ordering imposed by <tt>c</tt> on <tt>S</tt> is <i>consistent with
+ * equals</i>, we mean that the quotient for the ordering is the equivalence
+ * relation defined by the objects' {@link Object#equals(Object)
+ * equals(Object)} method(s):<pre>
+ *     {(x, y) such that x.equals(y)}. </pre>
+ *
+ * <p>Unlike {@code Comparable}, a comparator may optionally permit
+ * comparison of null arguments, while maintaining the requirements for
+ * an equivalence relation.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <T> the type of objects that may be compared by this comparator
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Comparable
+ * @see java.io.Serializable
+ * @since 1.2
+ */
+@FunctionalInterface
+public interface Comparator<T> {
+    /**
+     * Compares its two arguments for order.  Returns a negative integer,
+     * zero, or a positive integer as the first argument is less than, equal
+     * to, or greater than the second.<p>
+     *
+     * In the foregoing description, the notation
+     * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
+     * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
+     * <tt>0</tt>, or <tt>1</tt> according to whether the value of
+     * <i>expression</i> is negative, zero or positive.<p>
+     *
+     * The implementor must ensure that <tt>sgn(compare(x, y)) ==
+     * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
+     * implies that <tt>compare(x, y)</tt> must throw an exception if and only
+     * if <tt>compare(y, x)</tt> throws an exception.)<p>
+     *
+     * The implementor must also ensure that the relation is transitive:
+     * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
+     * <tt>compare(x, z)&gt;0</tt>.<p>
+     *
+     * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
+     * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
+     * <tt>z</tt>.<p>
+     *
+     * It is generally the case, but <i>not</i> strictly required that
+     * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
+     * any comparator that violates this condition should clearly indicate
+     * this fact.  The recommended language is "Note: this comparator
+     * imposes orderings that are inconsistent with equals."
+     *
+     * @param o1 the first object to be compared.
+     * @param o2 the second object to be compared.
+     * @return a negative integer, zero, or a positive integer as the
+     *         first argument is less than, equal to, or greater than the
+     *         second.
+     * @throws NullPointerException if an argument is null and this
+     *         comparator does not permit null arguments
+     * @throws ClassCastException if the arguments' types prevent them from
+     *         being compared by this comparator.
+     */
+    int compare(T o1, T o2);
+
+    /**
+     * Indicates whether some other object is &quot;equal to&quot; this
+     * comparator.  This method must obey the general contract of
+     * {@link Object#equals(Object)}.  Additionally, this method can return
+     * <tt>true</tt> <i>only</i> if the specified object is also a comparator
+     * and it imposes the same ordering as this comparator.  Thus,
+     * <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1,
+     * o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference
+     * <tt>o1</tt> and <tt>o2</tt>.<p>
+     *
+     * Note that it is <i>always</i> safe <i>not</i> to override
+     * <tt>Object.equals(Object)</tt>.  However, overriding this method may,
+     * in some cases, improve performance by allowing programs to determine
+     * that two distinct comparators impose the same order.
+     *
+     * @param   obj   the reference object with which to compare.
+     * @return  <code>true</code> only if the specified object is also
+     *          a comparator and it imposes the same ordering as this
+     *          comparator.
+     * @see Object#equals(Object)
+     * @see Object#hashCode()
+     */
+    boolean equals(Object obj);
+
+    /**
+     * Returns a comparator that imposes the reverse ordering of this
+     * comparator.
+     *
+     * @return a comparator that imposes the reverse ordering of this
+     *         comparator.
+     * @since 1.8
+     */
+    default Comparator<T> reversed() {
+        return Collections.reverseOrder(this);
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with another comparator.
+     * If this {@code Comparator} considers two elements equal, i.e.
+     * {@code compare(a, b) == 0}, {@code other} is used to determine the order.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is also serializable.
+     *
+     * @apiNote
+     * For example, to sort a collection of {@code String} based on the length
+     * and then case-insensitive natural ordering, the comparator can be
+     * composed using following code,
+     *
+     * <pre>{@code
+     *     Comparator<String> cmp = Comparator.comparingInt(String::length)
+     *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
+     * }</pre>
+     *
+     * @param  other the other comparator to be used when this comparator
+     *         compares two objects that are equal.
+     * @return a lexicographic-order comparator composed of this and then the
+     *         other comparator
+     * @throws NullPointerException if the argument is null.
+     * @since 1.8
+     */
+    default Comparator<T> thenComparing(Comparator<? super T> other) {
+        Objects.requireNonNull(other);
+        return (Comparator<T> & Serializable) (c1, c2) -> {
+            int res = compare(c1, c2);
+            return (res != 0) ? res : other.compare(c1, c2);
+        };
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a key to be compared with the given {@code Comparator}.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparing(keyExtractor, cmp))}.
+     *
+     * @param  <U>  the type of the sort key
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  keyComparator the {@code Comparator} used to compare the sort key
+     * @return a lexicographic-order comparator composed of this comparator
+     *         and then comparing on the key extracted by the keyExtractor function
+     * @throws NullPointerException if either argument is null.
+     * @see #comparing(Function, Comparator)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <U> Comparator<T> thenComparing(
+            Function<? super T, ? extends U> keyExtractor,
+            Comparator<? super U> keyComparator)
+    {
+        return thenComparing(comparing(keyExtractor, keyComparator));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code Comparable} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparing(keyExtractor))}.
+     *
+     * @param  <U>  the type of the {@link Comparable} sort key
+     * @param  keyExtractor the function used to extract the {@link
+     *         Comparable} sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@link Comparable} sort key.
+     * @throws NullPointerException if the argument is null.
+     * @see #comparing(Function)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
+            Function<? super T, ? extends U> keyExtractor)
+    {
+        return thenComparing(comparing(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code int} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingInt(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the integer sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code int} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingInt(ToIntFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
+        return thenComparing(comparingInt(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code long} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingLong(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the long sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code long} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingLong(ToLongFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
+        return thenComparing(comparingLong(keyExtractor));
+    }
+
+    /**
+     * Returns a lexicographic-order comparator with a function that
+     * extracts a {@code double} sort key.
+     *
+     * @implSpec This default implementation behaves as if {@code
+     *           thenComparing(comparingDouble(keyExtractor))}.
+     *
+     * @param  keyExtractor the function used to extract the double sort key
+     * @return a lexicographic-order comparator composed of this and then the
+     *         {@code double} sort key
+     * @throws NullPointerException if the argument is null.
+     * @see #comparingDouble(ToDoubleFunction)
+     * @see #thenComparing(Comparator)
+     * @since 1.8
+     */
+    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+        return thenComparing(comparingDouble(keyExtractor));
+    }
+
+    /**
+     * Returns a comparator that imposes the reverse of the <em>natural
+     * ordering</em>.
+     *
+     * <p>The returned comparator is serializable and throws {@link
+     * NullPointerException} when comparing {@code null}.
+     *
+     * @param  <T> the {@link Comparable} type of element to be compared
+     * @return a comparator that imposes the reverse of the <i>natural
+     *         ordering</i> on {@code Comparable} objects.
+     * @see Comparable
+     * @since 1.8
+     */
+    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
+        return Collections.reverseOrder();
+    }
+
+    /**
+     * Returns a comparator that compares {@link Comparable} objects in natural
+     * order.
+     *
+     * <p>The returned comparator is serializable and throws {@link
+     * NullPointerException} when comparing {@code null}.
+     *
+     * @param  <T> the {@link Comparable} type of element to be compared
+     * @return a comparator that imposes the <i>natural ordering</i> on {@code
+     *         Comparable} objects.
+     * @see Comparable
+     * @since 1.8
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
+        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
+    }
+
+    /**
+     * Returns a null-friendly comparator that considers {@code null} to be
+     * less than non-null. When both are {@code null}, they are considered
+     * equal. If both are non-null, the specified {@code Comparator} is used
+     * to determine the order. If the specified comparator is {@code null},
+     * then the returned comparator considers all non-null values to be equal.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is serializable.
+     *
+     * @param  <T> the type of the elements to be compared
+     * @param  comparator a {@code Comparator} for comparing non-null values
+     * @return a comparator that considers {@code null} to be less than
+     *         non-null, and compares non-null objects with the supplied
+     *         {@code Comparator}.
+     * @since 1.8
+     */
+    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
+        return new Comparators.NullComparator<>(true, comparator);
+    }
+
+    /**
+     * Returns a null-friendly comparator that considers {@code null} to be
+     * greater than non-null. When both are {@code null}, they are considered
+     * equal. If both are non-null, the specified {@code Comparator} is used
+     * to determine the order. If the specified comparator is {@code null},
+     * then the returned comparator considers all non-null values to be equal.
+     *
+     * <p>The returned comparator is serializable if the specified comparator
+     * is serializable.
+     *
+     * @param  <T> the type of the elements to be compared
+     * @param  comparator a {@code Comparator} for comparing non-null values
+     * @return a comparator that considers {@code null} to be greater than
+     *         non-null, and compares non-null objects with the supplied
+     *         {@code Comparator}.
+     * @since 1.8
+     */
+    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
+        return new Comparators.NullComparator<>(false, comparator);
+    }
+
+    /**
+     * Accepts a function that extracts a sort key from a type {@code T}, and
+     * returns a {@code Comparator<T>} that compares by that sort key using
+     * the specified {@link Comparator}.
+      *
+     * <p>The returned comparator is serializable if the specified function
+     * and comparator are both serializable.
+     *
+     * @apiNote
+     * For example, to obtain a {@code Comparator} that compares {@code
+     * Person} objects by their last name ignoring case differences,
+     *
+     * <pre>{@code
+     *     Comparator<Person> cmp = Comparator.comparing(
+     *             Person::getLastName,
+     *             String.CASE_INSENSITIVE_ORDER);
+     * }</pre>
+     *
+     * @param  <T> the type of element to be compared
+     * @param  <U> the type of the sort key
+     * @param  keyExtractor the function used to extract the sort key
+     * @param  keyComparator the {@code Comparator} used to compare the sort key
+     * @return a comparator that compares by an extracted key using the
+     *         specified {@code Comparator}
+     * @throws NullPointerException if either argument is null
+     * @since 1.8
+     */
+    public static <T, U> Comparator<T> comparing(
+            Function<? super T, ? extends U> keyExtractor,
+            Comparator<? super U> keyComparator)
+    {
+        Objects.requireNonNull(keyExtractor);
+        Objects.requireNonNull(keyComparator);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
+                                              keyExtractor.apply(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@link java.lang.Comparable
+     * Comparable} sort key from a type {@code T}, and returns a {@code
+     * Comparator<T>} that compares by that sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @apiNote
+     * For example, to obtain a {@code Comparator} that compares {@code
+     * Person} objects by their last name,
+     *
+     * <pre>{@code
+     *     Comparator<Person> byLastName = Comparator.comparing(Person::getLastName);
+     * }</pre>
+     *
+     * @param  <T> the type of element to be compared
+     * @param  <U> the type of the {@code Comparable} sort key
+     * @param  keyExtractor the function used to extract the {@link
+     *         Comparable} sort key
+     * @return a comparator that compares by an extracted key
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
+            Function<? super T, ? extends U> keyExtractor)
+    {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
+    }
+
+    /**
+     * Accepts a function that extracts an {@code int} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the integer sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@code long} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function is
+     * also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the long sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
+    }
+
+    /**
+     * Accepts a function that extracts a {@code double} sort key from a type
+     * {@code T}, and returns a {@code Comparator<T>} that compares by that
+     * sort key.
+     *
+     * <p>The returned comparator is serializable if the specified function
+     * is also serializable.
+     *
+     * @param  <T> the type of element to be compared
+     * @param  keyExtractor the function used to extract the double sort key
+     * @return a comparator that compares by an extracted key
+     * @see #comparing(Function)
+     * @throws NullPointerException if the argument is null
+     * @since 1.8
+     */
+    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+        Objects.requireNonNull(keyExtractor);
+        return (Comparator<T> & Serializable)
+            (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
+    }
+}
diff --git a/java/util/Comparators.java b/java/util/Comparators.java
new file mode 100644
index 0000000..ee80679
--- /dev/null
+++ b/java/util/Comparators.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Package private supporting class for {@link Comparator}.
+ */
+class Comparators {
+    private Comparators() {
+        throw new AssertionError("no instances");
+    }
+
+    /**
+     * Compares {@link Comparable} objects in natural order.
+     *
+     * @see Comparable
+     */
+    enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
+        INSTANCE;
+
+        @Override
+        public int compare(Comparable<Object> c1, Comparable<Object> c2) {
+            return c1.compareTo(c2);
+        }
+
+        @Override
+        public Comparator<Comparable<Object>> reversed() {
+            return Comparator.reverseOrder();
+        }
+    }
+
+    /**
+     * Null-friendly comparators
+     */
+    final static class NullComparator<T> implements Comparator<T>, Serializable {
+        private static final long serialVersionUID = -7569533591570686392L;
+        private final boolean nullFirst;
+        // if null, non-null Ts are considered equal
+        private final Comparator<T> real;
+
+        @SuppressWarnings("unchecked")
+        NullComparator(boolean nullFirst, Comparator<? super T> real) {
+            this.nullFirst = nullFirst;
+            this.real = (Comparator<T>) real;
+        }
+
+        @Override
+        public int compare(T a, T b) {
+            if (a == null) {
+                return (b == null) ? 0 : (nullFirst ? -1 : 1);
+            } else if (b == null) {
+                return nullFirst ? 1: -1;
+            } else {
+                return (real == null) ? 0 : real.compare(a, b);
+            }
+        }
+
+        @Override
+        public Comparator<T> thenComparing(Comparator<? super T> other) {
+            Objects.requireNonNull(other);
+            return new NullComparator<>(nullFirst, real == null ? other : real.thenComparing(other));
+        }
+
+        @Override
+        public Comparator<T> reversed() {
+            return new NullComparator<>(!nullFirst, real == null ? null : real.reversed());
+        }
+    }
+}
diff --git a/java/util/ConcurrentModificationException.java b/java/util/ConcurrentModificationException.java
new file mode 100644
index 0000000..7e65d2a
--- /dev/null
+++ b/java/util/ConcurrentModificationException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This exception may be thrown by methods that have detected concurrent
+ * modification of an object when such modification is not permissible.
+ * <p>
+ * For example, it is not generally permissible for one thread to modify a Collection
+ * while another thread is iterating over it.  In general, the results of the
+ * iteration are undefined under these circumstances.  Some Iterator
+ * implementations (including those of all the general purpose collection implementations
+ * provided by the JRE) may choose to throw this exception if this behavior is
+ * detected.  Iterators that do this are known as <i>fail-fast</i> iterators,
+ * as they fail quickly and cleanly, rather that risking arbitrary,
+ * non-deterministic behavior at an undetermined time in the future.
+ * <p>
+ * Note that this exception does not always indicate that an object has
+ * been concurrently modified by a <i>different</i> thread.  If a single
+ * thread issues a sequence of method invocations that violates the
+ * contract of an object, the object may throw this exception.  For
+ * example, if a thread modifies a collection directly while it is
+ * iterating over the collection with a fail-fast iterator, the iterator
+ * will throw this exception.
+ *
+ * <p>Note that fail-fast behavior cannot be guaranteed as it is, generally
+ * speaking, impossible to make any hard guarantees in the presence of
+ * unsynchronized concurrent modification.  Fail-fast operations
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>{@code ConcurrentModificationException}
+ * should be used only to detect bugs.</i>
+ *
+ * @author  Josh Bloch
+ * @see     Collection
+ * @see     Iterator
+ * @see     Spliterator
+ * @see     ListIterator
+ * @see     Vector
+ * @see     LinkedList
+ * @see     HashSet
+ * @see     Hashtable
+ * @see     TreeMap
+ * @see     AbstractList
+ * @since   1.2
+ */
+public class ConcurrentModificationException extends RuntimeException {
+    private static final long serialVersionUID = -3666751008965953603L;
+
+    /**
+     * Constructs a ConcurrentModificationException with no
+     * detail message.
+     */
+    public ConcurrentModificationException() {
+    }
+
+    /**
+     * Constructs a {@code ConcurrentModificationException} with the
+     * specified detail message.
+     *
+     * @param message the detail message pertaining to this exception.
+     */
+    public ConcurrentModificationException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A {@code null} value is
+     *         permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since  1.7
+     */
+    public ConcurrentModificationException(Throwable cause) {
+        super(cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * <p>Note that the detail message associated with <code>cause</code> is
+     * <i>not</i> automatically incorporated in this exception's detail
+     * message.
+     *
+     * @param  message the detail message (which is saved for later retrieval
+     *         by the {@link Throwable#getMessage()} method).
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).  (A {@code null} value
+     *         is permitted, and indicates that the cause is nonexistent or
+     *         unknown.)
+     * @since 1.7
+     */
+    public ConcurrentModificationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/java/util/Currency.java b/java/util/Currency.java
new file mode 100644
index 0000000..94629c7
--- /dev/null
+++ b/java/util/Currency.java
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import libcore.icu.ICU;
+
+// BEGIN Android-changed: Removed docs about superseding runtime currency data.
+// Doing so via a properties file is not supported on Android.
+/**
+ * Represents a currency. Currencies are identified by their ISO 4217 currency
+ * codes. Visit the <a href="http://www.iso.org/iso/home/standards/currency_codes.htm">
+ * ISO web site</a> for more information.
+ * <p>
+ * The class is designed so that there's never more than one
+ * <code>Currency</code> instance for any given currency. Therefore, there's
+ * no public constructor. You obtain a <code>Currency</code> instance using
+ * the <code>getInstance</code> methods.
+ *
+ * @since 1.4
+ */
+// END Android-changed: Removed docs about superseding runtime currency data.
+public final class Currency implements Serializable {
+
+    private static final long serialVersionUID = -158308464356906721L;
+
+    /**
+     * ISO 4217 currency code for this currency.
+     *
+     * @serial
+     */
+    private final String currencyCode;
+
+    // BEGIN Android-changed: Use ICU.
+    // We do not keep track of defaultFractionDigits and numericCode separately.
+    /*
+    /**
+     * Default fraction digits for this currency.
+     * Set from currency data tables.
+     *
+    transient private final int defaultFractionDigits;
+
+    /**
+     * ISO 4217 numeric code for this currency.
+     * Set from currency data tables.
+     *
+    transient private final int numericCode;
+    */
+    private transient final android.icu.util.Currency icuCurrency;
+    // END Android-changed: Use ICU.
+
+
+    // class data: instance map
+
+    private static ConcurrentMap<String, Currency> instances = new ConcurrentHashMap<>(7);
+    private static HashSet<Currency> available;
+
+    // BEGIN Android-removed: Use ICU.
+    // We don't need any of these static fields nor the static initializer.
+    /*
+    // Class data: currency data obtained from currency.data file.
+    // Purpose:
+    // - determine valid country codes
+    // - determine valid currency codes
+    // - map country codes to currency codes
+    // - obtain default fraction digits for currency codes
+    //
+    // sc = special case; dfd = default fraction digits
+    // Simple countries are those where the country code is a prefix of the
+    // currency code, and there are no known plans to change the currency.
+    //
+    // table formats:
+    // - mainTable:
+    //   - maps country code to 32-bit int
+    //   - 26*26 entries, corresponding to [A-Z]*[A-Z]
+    //   - \u007F -> not valid country
+    //   - bits 20-31: unused
+    //   - bits 10-19: numeric code (0 to 1023)
+    //   - bit 9: 1 - special case, bits 0-4 indicate which one
+    //            0 - simple country, bits 0-4 indicate final char of currency code
+    //   - bits 5-8: fraction digits for simple countries, 0 for special cases
+    //   - bits 0-4: final char for currency code for simple country, or ID of special case
+    // - special case IDs:
+    //   - 0: country has no currency
+    //   - other: index into sc* arrays + 1
+    // - scCutOverTimes: cut-over time in millis as returned by
+    //   System.currentTimeMillis for special case countries that are changing
+    //   currencies; Long.MAX_VALUE for countries that are not changing currencies
+    // - scOldCurrencies: old currencies for special case countries
+    // - scNewCurrencies: new currencies for special case countries that are
+    //   changing currencies; null for others
+    // - scOldCurrenciesDFD: default fraction digits for old currencies
+    // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
+    //   countries that are not changing currencies
+    // - otherCurrencies: concatenation of all currency codes that are not the
+    //   main currency of a simple country, separated by "-"
+    // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
+
+    static int formatVersion;
+    static int dataVersion;
+    static int[] mainTable;
+    static long[] scCutOverTimes;
+    static String[] scOldCurrencies;
+    static String[] scNewCurrencies;
+    static int[] scOldCurrenciesDFD;
+    static int[] scNewCurrenciesDFD;
+    static int[] scOldCurrenciesNumericCode;
+    static int[] scNewCurrenciesNumericCode;
+    static String otherCurrencies;
+    static int[] otherCurrenciesDFD;
+    static int[] otherCurrenciesNumericCode;
+
+    // handy constants - must match definitions in GenerateCurrencyData
+    // magic number
+    private static final int MAGIC_NUMBER = 0x43757244;
+    // number of characters from A to Z
+    private static final int A_TO_Z = ('Z' - 'A') + 1;
+    // entry for invalid country codes
+    private static final int INVALID_COUNTRY_ENTRY = 0x0000007F;
+    // entry for countries without currency
+    private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x00000200;
+    // mask for simple case country entries
+    private static final int SIMPLE_CASE_COUNTRY_MASK = 0x00000000;
+    // mask for simple case country entry final character
+    private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x0000001F;
+    // mask for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x000001E0;
+    // shift count for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
+    // maximum number for simple case country entry default currency digits
+    private static final int SIMPLE_CASE_COUNTRY_MAX_DEFAULT_DIGITS = 9;
+    // mask for special case country entries
+    private static final int SPECIAL_CASE_COUNTRY_MASK = 0x00000200;
+    // mask for special case country index
+    private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x0000001F;
+    // delta from entry index component in main table to index into special case tables
+    private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
+    // mask for distinguishing simple and special case countries
+    private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
+    // mask for the numeric code of the currency
+    private static final int NUMERIC_CODE_MASK = 0x000FFC00;
+    // shift count for the numeric code of the currency
+    private static final int NUMERIC_CODE_SHIFT = 10;
+
+    // Currency data format version
+    private static final int VALID_FORMAT_VERSION = 2;
+
+    static {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                String homeDir = System.getProperty("java.home");
+                try {
+                    String dataFile = homeDir + File.separator +
+                            "lib" + File.separator + "currency.data";
+                    try (DataInputStream dis = new DataInputStream(
+                             new BufferedInputStream(
+                             new FileInputStream(dataFile)))) {
+                        if (dis.readInt() != MAGIC_NUMBER) {
+                            throw new InternalError("Currency data is possibly corrupted");
+                        }
+                        formatVersion = dis.readInt();
+                        if (formatVersion != VALID_FORMAT_VERSION) {
+                            throw new InternalError("Currency data format is incorrect");
+                        }
+                        dataVersion = dis.readInt();
+                        mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
+                        int scCount = dis.readInt();
+                        scCutOverTimes = readLongArray(dis, scCount);
+                        scOldCurrencies = readStringArray(dis, scCount);
+                        scNewCurrencies = readStringArray(dis, scCount);
+                        scOldCurrenciesDFD = readIntArray(dis, scCount);
+                        scNewCurrenciesDFD = readIntArray(dis, scCount);
+                        scOldCurrenciesNumericCode = readIntArray(dis, scCount);
+                        scNewCurrenciesNumericCode = readIntArray(dis, scCount);
+                        int ocCount = dis.readInt();
+                        otherCurrencies = dis.readUTF();
+                        otherCurrenciesDFD = readIntArray(dis, ocCount);
+                        otherCurrenciesNumericCode = readIntArray(dis, ocCount);
+                    }
+                } catch (IOException e) {
+                    throw new InternalError(e);
+                }
+
+                // look for the properties file for overrides
+                String propsFile = System.getProperty("java.util.currency.data");
+                if (propsFile == null) {
+                    propsFile = homeDir + File.separator + "lib" +
+                        File.separator + "currency.properties";
+                }
+                try {
+                    File propFile = new File(propsFile);
+                    if (propFile.exists()) {
+                        Properties props = new Properties();
+                        try (FileReader fr = new FileReader(propFile)) {
+                            props.load(fr);
+                        }
+                        Set<String> keys = props.stringPropertyNames();
+                        Pattern propertiesPattern =
+                            Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*" +
+                                "(\\d+)\\s*,?\\s*(\\d{4}-\\d{2}-\\d{2}T\\d{2}:" +
+                                "\\d{2}:\\d{2})?");
+                        for (String key : keys) {
+                           replaceCurrencyData(propertiesPattern,
+                               key.toUpperCase(Locale.ROOT),
+                               props.getProperty(key).toUpperCase(Locale.ROOT));
+                        }
+                    }
+                } catch (IOException e) {
+                    info("currency.properties is ignored because of an IOException", e);
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Constants for retrieving localized names from the name providers.
+     *
+    private static final int SYMBOL = 0;
+    private static final int DISPLAYNAME = 1;
+    */
+    // END Android-removed: Use ICU.
+
+    /**
+     * Constructs a <code>Currency</code> instance. The constructor is private
+     * so that we can insure that there's never more than one instance for a
+     * given currency.
+     */
+    // BEGIN Android-changed: Use ICU.
+    // We do not keep track of defaultFractionDigits and numericCode separately.
+    /*
+    private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
+        this.currencyCode = currencyCode;
+        this.defaultFractionDigits = defaultFractionDigits;
+        this.numericCode = numericCode;
+    }
+    */
+    private Currency(android.icu.util.Currency icuCurrency) {
+        this.icuCurrency = icuCurrency;
+        this.currencyCode = icuCurrency.getCurrencyCode();
+    }
+    // END Android-changed: Use ICU.
+
+    /**
+     * Returns the <code>Currency</code> instance for the given currency code.
+     *
+     * @param currencyCode the ISO 4217 code of the currency
+     * @return the <code>Currency</code> instance for the given currency code
+     * @exception NullPointerException if <code>currencyCode</code> is null
+     * @exception IllegalArgumentException if <code>currencyCode</code> is not
+     * a supported ISO 4217 code.
+     */
+    public static Currency getInstance(String currencyCode) {
+        // BEGIN Android-changed: Use ICU.
+        // Upstream uses a private static helper method, implemented differently.
+        Currency instance = instances.get(currencyCode);
+        if (instance != null) {
+            return instance;
+        }
+        android.icu.util.Currency icuInstance =
+                  android.icu.util.Currency.getInstance(currencyCode);
+        if (icuInstance == null) {
+            return null;
+        }
+        Currency currencyVal = new Currency(icuInstance);
+        // END Android-changed: Use ICU.
+        instance = instances.putIfAbsent(currencyCode, currencyVal);
+        return (instance != null ? instance : currencyVal);
+    }
+
+    /**
+     * Returns the <code>Currency</code> instance for the country of the
+     * given locale. The language and variant components of the locale
+     * are ignored. The result may vary over time, as countries change their
+     * currencies. For example, for the original member countries of the
+     * European Monetary Union, the method returns the old national currencies
+     * until December 31, 2001, and the Euro from January 1, 2002, local time
+     * of the respective countries.
+     * <p>
+     * The method returns <code>null</code> for territories that don't
+     * have a currency, such as Antarctica.
+     *
+     * @param locale the locale for whose country a <code>Currency</code>
+     * instance is needed
+     * @return the <code>Currency</code> instance for the country of the given
+     * locale, or {@code null}
+     * @exception NullPointerException if <code>locale</code> or its country
+     * code is {@code null}
+     * @exception IllegalArgumentException if the country of the given {@code locale}
+     * is not a supported ISO 3166 country code.
+     */
+    public static Currency getInstance(Locale locale) {
+        String country = locale.getCountry();
+        if (country == null) {
+            throw new NullPointerException();
+        }
+
+        // BEGIN Android-changed: Use ICU.
+        /*
+        if (country.length() != 2) {
+            throw new IllegalArgumentException();
+        }
+
+        char char1 = country.charAt(0);
+        char char2 = country.charAt(1);
+        int tableEntry = getMainTableEntry(char1, char2);
+        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                    && tableEntry != INVALID_COUNTRY_ENTRY) {
+            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
+            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+            StringBuilder sb = new StringBuilder(country);
+            sb.append(finalChar);
+            return getInstance(sb.toString(), defaultFractionDigits, numericCode);
+        } else {
+            // special cases
+            if (tableEntry == INVALID_COUNTRY_ENTRY) {
+                throw new IllegalArgumentException();
+            }
+            if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
+                return null;
+            } else {
+                int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
+                if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
+                    return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
+                        scOldCurrenciesNumericCode[index]);
+                } else {
+                    return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
+                        scNewCurrenciesNumericCode[index]);
+                }
+            }
+        }
+        */
+        android.icu.util.Currency icuInstance =
+                android.icu.util.Currency.getInstance(locale);
+        String variant = locale.getVariant();
+        if (!variant.isEmpty() && (variant.equals("EURO") || variant.equals("HK") ||
+                variant.equals("PREEURO"))) {
+            country = country + "_" + variant;
+        }
+        String currencyCode = ICU.getCurrencyCode(country);
+        if (currencyCode == null) {
+            throw new IllegalArgumentException("Unsupported ISO 3166 country: " + locale);
+        }
+        if (icuInstance == null || icuInstance.getCurrencyCode().equals("XXX")) {
+            return null;
+        }
+        return getInstance(currencyCode);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Gets the set of available currencies.  The returned set of currencies
+     * contains all of the available currencies, which may include currencies
+     * that represent obsolete ISO 4217 codes.  The set can be modified
+     * without affecting the available currencies in the runtime.
+     *
+     * @return the set of available currencies.  If there is no currency
+     *    available in the runtime, the returned set is empty.
+     * @since 1.7
+     */
+    public static Set<Currency> getAvailableCurrencies() {
+        synchronized(Currency.class) {
+            if (available == null) {
+                // BEGIN Android-changed: Use ICU.
+                /*
+                available = new HashSet<>(256);
+
+                // Add simple currencies first
+                for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
+                    for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
+                        int tableEntry = getMainTableEntry(c1, c2);
+                        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
+                             && tableEntry != INVALID_COUNTRY_ENTRY) {
+                            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
+                            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
+                            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
+                            StringBuilder sb = new StringBuilder();
+                            sb.append(c1);
+                            sb.append(c2);
+                            sb.append(finalChar);
+                            available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
+                        }
+                    }
+                }
+
+                // Now add other currencies
+                StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
+                while (st.hasMoreElements()) {
+                    available.add(getInstance((String)st.nextElement()));
+                }
+                */
+                available = new HashSet<>();
+                Set<android.icu.util.Currency> icuAvailableCurrencies
+                        = android.icu.util.Currency.getAvailableCurrencies();
+                for (android.icu.util.Currency icuCurrency : icuAvailableCurrencies) {
+                    Currency currency = getInstance(icuCurrency.getCurrencyCode());
+                    if (currency == null) {
+                        currency = new Currency(icuCurrency);
+                        instances.put(currency.currencyCode, currency);
+                    }
+                    available.add(currency);
+                }
+                // END Android-changed: Use ICU.
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        Set<Currency> result = (Set<Currency>) available.clone();
+        return result;
+    }
+
+    /**
+     * Gets the ISO 4217 currency code of this currency.
+     *
+     * @return the ISO 4217 currency code of this currency.
+     */
+    public String getCurrencyCode() {
+        return currencyCode;
+    }
+
+    /**
+     * Gets the symbol of this currency for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, for the US Dollar, the symbol is "$" if the default
+     * locale is the US, while for other locales it may be "US$". If no
+     * symbol can be determined, the ISO 4217 currency code is returned.
+     * <p>
+     * This is equivalent to calling
+     * {@link #getSymbol(Locale)
+     *     getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}.
+     *
+     * @return the symbol of this currency for the default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     */
+    public String getSymbol() {
+        return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Gets the symbol of this currency for the specified locale.
+     * For example, for the US Dollar, the symbol is "$" if the specified
+     * locale is the US, while for other locales it may be "US$". If no
+     * symbol can be determined, the ISO 4217 currency code is returned.
+     *
+     * @param locale the locale for which a display name for this currency is
+     * needed
+     * @return the symbol of this currency for the specified locale
+     * @exception NullPointerException if <code>locale</code> is null
+     */
+    public String getSymbol(Locale locale) {
+        // BEGIN Android-changed: Use ICU.
+        /*
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
+        String symbol = pool.getLocalizedObject(
+                                CurrencyNameGetter.INSTANCE,
+                                locale, currencyCode, SYMBOL);
+        if (symbol != null) {
+            return symbol;
+        }
+
+        // use currency code as symbol of last resort
+        return currencyCode;
+        */
+        if (locale == null) {
+            throw new NullPointerException("locale == null");
+        }
+        return icuCurrency.getSymbol(locale);
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Gets the default number of fraction digits used with this currency.
+     * For example, the default number of fraction digits for the Euro is 2,
+     * while for the Japanese Yen it's 0.
+     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
+     * -1 is returned.
+     *
+     * @return the default number of fraction digits used with this currency
+     */
+    public int getDefaultFractionDigits() {
+        // BEGIN Android-changed: Use ICU.
+        // return defaultFractionDigits;
+        if (icuCurrency.getCurrencyCode().equals("XXX")) {
+            return -1;
+        }
+        return icuCurrency.getDefaultFractionDigits();
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns the ISO 4217 numeric code of this currency.
+     *
+     * @return the ISO 4217 numeric code of this currency
+     * @since 1.7
+     */
+    public int getNumericCode() {
+        // Android-changed: Use ICU.
+        // return numericCode;
+        return icuCurrency.getNumericCode();
+    }
+
+    /**
+     * Gets the name that is suitable for displaying this currency for
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * If there is no suitable display name found
+     * for the default locale, the ISO 4217 currency code is returned.
+     * <p>
+     * This is equivalent to calling
+     * {@link #getDisplayName(Locale)
+     *     getDisplayName(Locale.getDefault(Locale.Category.DISPLAY))}.
+     *
+     * @return the display name of this currency for the default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @since 1.7
+     */
+    public String getDisplayName() {
+        return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Gets the name that is suitable for displaying this currency for
+     * the specified locale.  If there is no suitable display name found
+     * for the specified locale, the ISO 4217 currency code is returned.
+     *
+     * @param locale the locale for which a display name for this currency is
+     * needed
+     * @return the display name of this currency for the specified locale
+     * @exception NullPointerException if <code>locale</code> is null
+     * @since 1.7
+     */
+    public String getDisplayName(Locale locale) {
+        // Android-changed: Use ICU.
+        /*
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
+        String result = pool.getLocalizedObject(
+                                CurrencyNameGetter.INSTANCE,
+                                locale, currencyCode, DISPLAYNAME);
+        if (result != null) {
+            return result;
+        }
+
+        // use currency code as symbol of last resort
+        return currencyCode;
+        */
+        return icuCurrency.getDisplayName(Objects.requireNonNull(locale));
+    }
+
+    /**
+     * Returns the ISO 4217 currency code of this currency.
+     *
+     * @return the ISO 4217 currency code of this currency
+     */
+    @Override
+    public String toString() {
+        // Android-changed: Use ICU.
+        // return currencyCode;
+        return icuCurrency.toString();
+    }
+
+    /**
+     * Resolves instances being deserialized to a single instance per currency.
+     */
+    private Object readResolve() {
+        return getInstance(currencyCode);
+    }
+
+    // Android-removed: Use ICU.
+    // Removed a bunch of private helper methods that are unused on Android.
+}
diff --git a/java/util/Date.java b/java/util/Date.java
new file mode 100644
index 0000000..f7a576d
--- /dev/null
+++ b/java/util/Date.java
@@ -0,0 +1,1394 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.text.DateFormat;
+import java.time.LocalDate;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.lang.ref.SoftReference;
+import java.time.Instant;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+
+/**
+ * The class <code>Date</code> represents a specific instant
+ * in time, with millisecond precision.
+ * <p>
+ * Prior to JDK&nbsp;1.1, the class <code>Date</code> had two additional
+ * functions.  It allowed the interpretation of dates as year, month, day, hour,
+ * minute, and second values.  It also allowed the formatting and parsing
+ * of date strings.  Unfortunately, the API for these functions was not
+ * amenable to internationalization.  As of JDK&nbsp;1.1, the
+ * <code>Calendar</code> class should be used to convert between dates and time
+ * fields and the <code>DateFormat</code> class should be used to format and
+ * parse date strings.
+ * The corresponding methods in <code>Date</code> are deprecated.
+ * <p>
+ * Although the <code>Date</code> class is intended to reflect
+ * coordinated universal time (UTC), it may not do so exactly,
+ * depending on the host environment of the Java Virtual Machine.
+ * Nearly all modern operating systems assume that 1&nbsp;day&nbsp;=
+ * 24&nbsp;&times;&nbsp;60&nbsp;&times;&nbsp;60&nbsp;= 86400 seconds
+ * in all cases. In UTC, however, about once every year or two there
+ * is an extra second, called a "leap second." The leap
+ * second is always added as the last second of the day, and always
+ * on December 31 or June 30. For example, the last minute of the
+ * year 1995 was 61 seconds long, thanks to an added leap second.
+ * Most computer clocks are not accurate enough to be able to reflect
+ * the leap-second distinction.
+ * <p>
+ * Some computer standards are defined in terms of Greenwich mean
+ * time (GMT), which is equivalent to universal time (UT).  GMT is
+ * the "civil" name for the standard; UT is the
+ * "scientific" name for the same standard. The
+ * distinction between UTC and UT is that UTC is based on an atomic
+ * clock and UT is based on astronomical observations, which for all
+ * practical purposes is an invisibly fine hair to split. Because the
+ * earth's rotation is not uniform (it slows down and speeds up
+ * in complicated ways), UT does not always flow uniformly. Leap
+ * seconds are introduced as needed into UTC so as to keep UTC within
+ * 0.9 seconds of UT1, which is a version of UT with certain
+ * corrections applied. There are other time and date systems as
+ * well; for example, the time scale used by the satellite-based
+ * global positioning system (GPS) is synchronized to UTC but is
+ * <i>not</i> adjusted for leap seconds. An interesting source of
+ * further information is the U.S. Naval Observatory, particularly
+ * the Directorate of Time at:
+ * <blockquote><pre>
+ *     <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
+ * </pre></blockquote>
+ * <p>
+ * and their definitions of "Systems of Time" at:
+ * <blockquote><pre>
+ *     <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
+ * </pre></blockquote>
+ * <p>
+ * In all methods of class <code>Date</code> that accept or return
+ * year, month, date, hours, minutes, and seconds values, the
+ * following representations are used:
+ * <ul>
+ * <li>A year <i>y</i> is represented by the integer
+ *     <i>y</i>&nbsp;<code>-&nbsp;1900</code>.
+ * <li>A month is represented by an integer from 0 to 11; 0 is January,
+ *     1 is February, and so forth; thus 11 is December.
+ * <li>A date (day of month) is represented by an integer from 1 to 31
+ *     in the usual manner.
+ * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
+ *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1
+ *     p.m. is hour 12.
+ * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
+ * <li>A second is represented by an integer from 0 to 61; the values 60 and
+ *     61 occur only for leap seconds and even then only in Java
+ *     implementations that actually track leap seconds correctly. Because
+ *     of the manner in which leap seconds are currently introduced, it is
+ *     extremely unlikely that two leap seconds will occur in the same
+ *     minute, but this specification follows the date and time conventions
+ *     for ISO C.
+ * </ul>
+ * <p>
+ * In all cases, arguments given to methods for these purposes need
+ * not fall within the indicated ranges; for example, a date may be
+ * specified as January 32 and is interpreted as meaning February 1.
+ *
+ * @author  James Gosling
+ * @author  Arthur van Hoff
+ * @author  Alan Liu
+ * @see     java.text.DateFormat
+ * @see     java.util.Calendar
+ * @see     java.util.TimeZone
+ * @since   JDK1.0
+ */
+public class Date
+    implements java.io.Serializable, Cloneable, Comparable<Date>
+{
+    private static final BaseCalendar gcal =
+                                CalendarSystem.getGregorianCalendar();
+    private static BaseCalendar jcal;
+
+    private transient long fastTime;
+
+    /*
+     * If cdate is null, then fastTime indicates the time in millis.
+     * If cdate.isNormalized() is true, then fastTime and cdate are in
+     * synch. Otherwise, fastTime is ignored, and cdate indicates the
+     * time.
+     */
+    private transient BaseCalendar.Date cdate;
+
+    // Initialized just before the value is used. See parse().
+    private static int defaultCenturyStart;
+
+    /* use serialVersionUID from modified java.util.Date for
+     * interoperability with JDK1.1. The Date was modified to write
+     * and read only the UTC time.
+     */
+    private static final long serialVersionUID = 7523967970034938905L;
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the time at which it was allocated, measured to the
+     * nearest millisecond.
+     *
+     * @see     java.lang.System#currentTimeMillis()
+     */
+    public Date() {
+        this(System.currentTimeMillis());
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it to
+     * represent the specified number of milliseconds since the
+     * standard base time known as "the epoch", namely January 1,
+     * 1970, 00:00:00 GMT.
+     *
+     * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
+     * @see     java.lang.System#currentTimeMillis()
+     */
+    public Date(long date) {
+        fastTime = date;
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents midnight, local time, at the beginning of the day
+     * specified by the <code>year</code>, <code>month</code>, and
+     * <code>date</code> arguments.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date)</code>
+     * or <code>GregorianCalendar(year + 1900, month, date)</code>.
+     */
+    @Deprecated
+    public Date(int year, int month, int date) {
+        this(year, month, date, 0, 0, 0);
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the instant at the start of the minute specified by
+     * the <code>year</code>, <code>month</code>, <code>date</code>,
+     * <code>hrs</code>, and <code>min</code> arguments, in the local
+     * time zone.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date,
+     * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
+     * month, date, hrs, min)</code>.
+     */
+    @Deprecated
+    public Date(int year, int month, int date, int hrs, int min) {
+        this(year, month, date, hrs, min, 0);
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the instant at the start of the second specified
+     * by the <code>year</code>, <code>month</code>, <code>date</code>,
+     * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
+     * in the local time zone.
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @param   sec     the seconds between 0-59.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date,
+     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
+     * month, date, hrs, min, sec)</code>.
+     */
+    @Deprecated
+    public Date(int year, int month, int date, int hrs, int min, int sec) {
+        int y = year + 1900;
+        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
+        if (month >= 12) {
+            y += month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y += CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        BaseCalendar cal = getCalendarSystem(y);
+        cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
+        cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
+        getTimeImpl();
+        cdate = null;
+    }
+
+    /**
+     * Allocates a <code>Date</code> object and initializes it so that
+     * it represents the date and time indicated by the string
+     * <code>s</code>, which is interpreted as if by the
+     * {@link Date#parse} method.
+     *
+     * @param   s   a string representation of the date.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#parse(java.lang.String)
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.parse(String s)</code>.
+     */
+    @Deprecated
+    public Date(String s) {
+        this(parse(s));
+    }
+
+    /**
+     * Return a copy of this object.
+     */
+    public Object clone() {
+        Date d = null;
+        try {
+            d = (Date)super.clone();
+            if (cdate != null) {
+                d.cdate = (BaseCalendar.Date) cdate.clone();
+            }
+        } catch (CloneNotSupportedException e) {} // Won't happen
+        return d;
+    }
+
+    /**
+     * Determines the date and time based on the arguments. The
+     * arguments are interpreted as a year, month, day of the month,
+     * hour of the day, minute within the hour, and second within the
+     * minute, exactly as for the <tt>Date</tt> constructor with six
+     * arguments, except that the arguments are interpreted relative
+     * to UTC rather than to the local time zone. The time indicated is
+     * returned represented as the distance, measured in milliseconds,
+     * of that time from the epoch (00:00:00 GMT on January 1, 1970).
+     *
+     * @param   year    the year minus 1900.
+     * @param   month   the month between 0-11.
+     * @param   date    the day of the month between 1-31.
+     * @param   hrs     the hours between 0-23.
+     * @param   min     the minutes between 0-59.
+     * @param   sec     the seconds between 0-59.
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
+     *          the date and time specified by the arguments.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(year + 1900, month, date,
+     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
+     * month, date, hrs, min, sec)</code>, using a UTC
+     * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
+     */
+    @Deprecated
+    public static long UTC(int year, int month, int date,
+                           int hrs, int min, int sec) {
+        int y = year + 1900;
+        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
+        if (month >= 12) {
+            y += month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y += CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        int m = month + 1;
+        BaseCalendar cal = getCalendarSystem(y);
+        BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
+        udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
+
+        // Use a Date instance to perform normalization. Its fastTime
+        // is the UTC value after the normalization.
+        Date d = new Date(0);
+        d.normalize(udate);
+        return d.fastTime;
+    }
+
+    /**
+     * Attempts to interpret the string <tt>s</tt> as a representation
+     * of a date and time. If the attempt is successful, the time
+     * indicated is returned represented as the distance, measured in
+     * milliseconds, of that time from the epoch (00:00:00 GMT on
+     * January 1, 1970). If the attempt fails, an
+     * <tt>IllegalArgumentException</tt> is thrown.
+     * <p>
+     * It accepts many syntaxes; in particular, it recognizes the IETF
+     * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
+     * understands the continental U.S. time-zone abbreviations, but for
+     * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
+     * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
+     * meridian). If no time zone is specified, the local time zone is
+     * assumed. GMT and UTC are considered equivalent.
+     * <p>
+     * The string <tt>s</tt> is processed from left to right, looking for
+     * data of interest. Any material in <tt>s</tt> that is within the
+     * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
+     * Parentheses may be nested. Otherwise, the only characters permitted
+     * within <tt>s</tt> are these ASCII characters:
+     * <blockquote><pre>
+     * abcdefghijklmnopqrstuvwxyz
+     * ABCDEFGHIJKLMNOPQRSTUVWXYZ
+     * 0123456789,+-:/</pre></blockquote>
+     * and whitespace characters.<p>
+     * A consecutive sequence of decimal digits is treated as a decimal
+     * number:<ul>
+     * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
+     *     has already been recognized, then the number is a time-zone
+     *     offset. If the number is less than 24, it is an offset measured
+     *     in hours. Otherwise, it is regarded as an offset in minutes,
+     *     expressed in 24-hour time format without punctuation. A
+     *     preceding <tt>-</tt> means a westward offset. Time zone offsets
+     *     are always relative to UTC (Greenwich). Thus, for example,
+     *     <tt>-5</tt> occurring in the string would mean "five hours west
+     *     of Greenwich" and <tt>+0430</tt> would mean "four hours and
+     *     thirty minutes east of Greenwich." It is permitted for the
+     *     string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
+     *     redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
+     * <li>The number is regarded as a year number if one of the
+     *     following conditions is true:
+     * <ul>
+     *     <li>The number is equal to or greater than 70 and followed by a
+     *         space, comma, slash, or end of string
+     *     <li>The number is less than 70, and both a month and a day of
+     *         the month have already been recognized</li>
+     * </ul>
+     *     If the recognized year number is less than 100, it is
+     *     interpreted as an abbreviated year relative to a century of
+     *     which dates are within 80 years before and 19 years after
+     *     the time when the Date class is initialized.
+     *     After adjusting the year number, 1900 is subtracted from
+     *     it. For example, if the current year is 1999 then years in
+     *     the range 19 to 99 are assumed to mean 1919 to 1999, while
+     *     years from 0 to 18 are assumed to mean 2000 to 2018.  Note
+     *     that this is slightly different from the interpretation of
+     *     years less than 100 that is used in {@link java.text.SimpleDateFormat}.
+     * <li>If the number is followed by a colon, it is regarded as an hour,
+     *     unless an hour has already been recognized, in which case it is
+     *     regarded as a minute.
+     * <li>If the number is followed by a slash, it is regarded as a month
+     *     (it is decreased by 1 to produce a number in the range <tt>0</tt>
+     *     to <tt>11</tt>), unless a month has already been recognized, in
+     *     which case it is regarded as a day of the month.
+     * <li>If the number is followed by whitespace, a comma, a hyphen, or
+     *     end of string, then if an hour has been recognized but not a
+     *     minute, it is regarded as a minute; otherwise, if a minute has
+     *     been recognized but not a second, it is regarded as a second;
+     *     otherwise, it is regarded as a day of the month. </ul><p>
+     * A consecutive sequence of letters is regarded as a word and treated
+     * as follows:<ul>
+     * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
+     *     the parse fails if an hour has not been recognized or is less
+     *     than <tt>1</tt> or greater than <tt>12</tt>).
+     * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
+     *     to the hour (but the parse fails if an hour has not been
+     *     recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
+     * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
+     *     WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
+     *     case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
+     *     <tt>Thurs</tt> are ignored.
+     * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
+     *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
+     *     OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
+     *     considering them in the order given here, is recognized as
+     *     specifying a month and is converted to a number (<tt>0</tt> to
+     *     <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
+     *     <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
+     *     is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
+     * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
+     *     case, is treated as referring to UTC.
+     * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
+     *     ignoring case, is recognized as referring to the time zone in
+     *     North America that is five, six, seven, or eight hours west of
+     *     Greenwich, respectively. Any word that matches <tt>EDT, CDT,
+     *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
+     *     referring to the same time zone, respectively, during daylight
+     *     saving time.</ul><p>
+     * Once the entire string s has been scanned, it is converted to a time
+     * result in one of two ways. If a time zone or time-zone offset has been
+     * recognized, then the year, month, day of month, hour, minute, and
+     * second are interpreted in UTC and then the time-zone offset is
+     * applied. Otherwise, the year, month, day of month, hour, minute, and
+     * second are interpreted in the local time zone.
+     *
+     * @param   s   a string to be parsed as a date.
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by the string argument.
+     * @see     java.text.DateFormat
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.parse(String s)</code>.
+     */
+    @Deprecated
+    public static long parse(String s) {
+        int year = Integer.MIN_VALUE;
+        int mon = -1;
+        int mday = -1;
+        int hour = -1;
+        int min = -1;
+        int sec = -1;
+        int millis = -1;
+        int c = -1;
+        int i = 0;
+        int n = -1;
+        int wst = -1;
+        int tzoffset = -1;
+        int prevc = 0;
+    syntax:
+        {
+            if (s == null)
+                break syntax;
+            int limit = s.length();
+            while (i < limit) {
+                c = s.charAt(i);
+                i++;
+                if (c <= ' ' || c == ',')
+                    continue;
+                if (c == '(') { // skip comments
+                    int depth = 1;
+                    while (i < limit) {
+                        c = s.charAt(i);
+                        i++;
+                        if (c == '(') depth++;
+                        else if (c == ')')
+                            if (--depth <= 0)
+                                break;
+                    }
+                    continue;
+                }
+                if ('0' <= c && c <= '9') {
+                    n = c - '0';
+                    while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
+                        n = n * 10 + c - '0';
+                        i++;
+                    }
+                    if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
+                        // BEGIN Android-changed: Android specific time zone logic
+
+                        if (tzoffset != 0 && tzoffset != -1)
+                            break syntax;
+
+                        // timezone offset
+                        if (n < 24) {
+                            n = n * 60; // EG. "GMT-3"
+
+                            // Support for Timezones of the form GMT-3:30. We look for an ':" and
+                            // parse the number following it as loosely as the original hours
+                            // section (i.e, no range or validity checks).
+                            int minutesPart = 0;
+                            if (i < limit && (s.charAt(i) == ':')) {
+                                i++;
+                                while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
+                                    minutesPart = (minutesPart * 10) + (c - '0');
+                                    i++;
+                                }
+                            }
+
+                            n += minutesPart;
+                        } else {
+                            n = (n % 100) + ((n / 100) * 60); // eg "GMT-0430"
+                        }
+
+                        if (prevc == '+')   // plus means east of GMT
+                            n = -n;
+                        // END Android-changed: Android specific time zone logic
+
+                        tzoffset = n;
+                    } else if (n >= 70)
+                        if (year != Integer.MIN_VALUE)
+                            break syntax;
+                        else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
+                            // year = n < 1900 ? n : n - 1900;
+                            year = n;
+                        else
+                            break syntax;
+                    else if (c == ':')
+                        if (hour < 0)
+                            hour = (byte) n;
+                        else if (min < 0)
+                            min = (byte) n;
+                        else
+                            break syntax;
+                    else if (c == '/')
+                        if (mon < 0)
+                            mon = (byte) (n - 1);
+                        else if (mday < 0)
+                            mday = (byte) n;
+                        else
+                            break syntax;
+                    else if (i < limit && c != ',' && c > ' ' && c != '-')
+                        break syntax;
+                    else if (hour >= 0 && min < 0)
+                        min = (byte) n;
+                    else if (min >= 0 && sec < 0)
+                        sec = (byte) n;
+                    else if (mday < 0)
+                        mday = (byte) n;
+                    // Handle two-digit years < 70 (70-99 handled above).
+                    else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
+                        year = n;
+                    else
+                        break syntax;
+                    prevc = 0;
+                } else if (c == '/' || c == ':' || c == '+' || c == '-')
+                    prevc = c;
+                else {
+                    int st = i - 1;
+                    while (i < limit) {
+                        c = s.charAt(i);
+                        if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
+                            break;
+                        i++;
+                    }
+                    if (i <= st + 1)
+                        break syntax;
+                    int k;
+                    for (k = wtb.length; --k >= 0;)
+                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
+                            int action = ttb[k];
+                            if (action != 0) {
+                                if (action == 1) {  // pm
+                                    if (hour > 12 || hour < 1)
+                                        break syntax;
+                                    else if (hour < 12)
+                                        hour += 12;
+                                } else if (action == 14) {  // am
+                                    if (hour > 12 || hour < 1)
+                                        break syntax;
+                                    else if (hour == 12)
+                                        hour = 0;
+                                } else if (action <= 13) {  // month!
+                                    if (mon < 0)
+                                        mon = (byte) (action - 2);
+                                    else
+                                        break syntax;
+                                } else {
+                                    tzoffset = action - 10000;
+                                }
+                            }
+                            break;
+                        }
+                    if (k < 0)
+                        break syntax;
+                    prevc = 0;
+                }
+            }
+            if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
+                break syntax;
+            // Parse 2-digit years within the correct default century.
+            if (year < 100) {
+                synchronized (Date.class) {
+                    if (defaultCenturyStart == 0) {
+                        defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
+                    }
+                }
+                year += (defaultCenturyStart / 100) * 100;
+                if (year < defaultCenturyStart) year += 100;
+            }
+            if (sec < 0)
+                sec = 0;
+            if (min < 0)
+                min = 0;
+            if (hour < 0)
+                hour = 0;
+            BaseCalendar cal = getCalendarSystem(year);
+            if (tzoffset == -1)  { // no time zone specified, have to use local
+                BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
+                ldate.setDate(year, mon + 1, mday);
+                ldate.setTimeOfDay(hour, min, sec, 0);
+                return cal.getTime(ldate);
+            }
+            BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
+            udate.setDate(year, mon + 1, mday);
+            udate.setTimeOfDay(hour, min, sec, 0);
+            return cal.getTime(udate) + tzoffset * (60 * 1000);
+        }
+        // syntax error
+        throw new IllegalArgumentException();
+    }
+    private final static String wtb[] = {
+        "am", "pm",
+        "monday", "tuesday", "wednesday", "thursday", "friday",
+        "saturday", "sunday",
+        "january", "february", "march", "april", "may", "june",
+        "july", "august", "september", "october", "november", "december",
+        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
+        "mst", "mdt", "pst", "pdt"
+    };
+    private final static int ttb[] = {
+        14, 1, 0, 0, 0, 0, 0, 0, 0,
+        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+        10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
+        10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
+        10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
+        10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
+        10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
+    };
+
+    /**
+     * Returns a value that is the result of subtracting 1900 from the
+     * year that contains or begins with the instant in time represented
+     * by this <code>Date</code> object, as interpreted in the local
+     * time zone.
+     *
+     * @return  the year represented by this date, minus 1900.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
+     */
+    @Deprecated
+    public int getYear() {
+        return normalize().getYear() - 1900;
+    }
+
+    /**
+     * Sets the year of this <tt>Date</tt> object to be the specified
+     * value plus 1900. This <code>Date</code> object is modified so
+     * that it represents a point in time within the specified year,
+     * with the month, date, hour, minute, and second the same as
+     * before, as interpreted in the local time zone. (Of course, if
+     * the date was February 29, for example, and the year is set to a
+     * non-leap year, then the new date will be treated as if it were
+     * on March 1.)
+     *
+     * @param   year    the year value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
+     */
+    @Deprecated
+    public void setYear(int year) {
+        getCalendarDate().setNormalizedYear(year + 1900);
+    }
+
+    /**
+     * Returns a number representing the month that contains or begins
+     * with the instant in time represented by this <tt>Date</tt> object.
+     * The value returned is between <code>0</code> and <code>11</code>,
+     * with the value <code>0</code> representing January.
+     *
+     * @return  the month represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
+     */
+    @Deprecated
+    public int getMonth() {
+        return normalize().getMonth() - 1; // adjust 1-based to 0-based
+    }
+
+    /**
+     * Sets the month of this date to the specified value. This
+     * <tt>Date</tt> object is modified so that it represents a point
+     * in time within the specified month, with the year, date, hour,
+     * minute, and second the same as before, as interpreted in the
+     * local time zone. If the date was October 31, for example, and
+     * the month is set to June, then the new date will be treated as
+     * if it were on July 1, because June has only 30 days.
+     *
+     * @param   month   the month value between 0-11.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
+     */
+    @Deprecated
+    public void setMonth(int month) {
+        int y = 0;
+        if (month >= 12) {
+            y = month / 12;
+            month %= 12;
+        } else if (month < 0) {
+            y = CalendarUtils.floorDivide(month, 12);
+            month = CalendarUtils.mod(month, 12);
+        }
+        BaseCalendar.Date d = getCalendarDate();
+        if (y != 0) {
+            d.setNormalizedYear(d.getNormalizedYear() + y);
+        }
+        d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
+    }
+
+    /**
+     * Returns the day of the month represented by this <tt>Date</tt> object.
+     * The value returned is between <code>1</code> and <code>31</code>
+     * representing the day of the month that contains or begins with the
+     * instant in time represented by this <tt>Date</tt> object, as
+     * interpreted in the local time zone.
+     *
+     * @return  the day of the month represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
+     */
+    @Deprecated
+    // Android-removed stray @deprecated tag.
+    public int getDate() {
+        return normalize().getDayOfMonth();
+    }
+
+    /**
+     * Sets the day of the month of this <tt>Date</tt> object to the
+     * specified value. This <tt>Date</tt> object is modified so that
+     * it represents a point in time within the specified day of the
+     * month, with the year, month, hour, minute, and second the same
+     * as before, as interpreted in the local time zone. If the date
+     * was April 30, for example, and the date is set to 31, then it
+     * will be treated as if it were on May 1, because April has only
+     * 30 days.
+     *
+     * @param   date   the day of the month value between 1-31.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
+     */
+    @Deprecated
+    public void setDate(int date) {
+        getCalendarDate().setDayOfMonth(date);
+    }
+
+    /**
+     * Returns the day of the week represented by this date. The
+     * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
+     * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
+     * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
+     * represents the day of the week that contains or begins with
+     * the instant in time represented by this <tt>Date</tt> object,
+     * as interpreted in the local time zone.
+     *
+     * @return  the day of the week represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
+     */
+    @Deprecated
+    public int getDay() {
+        return normalize().getDayOfWeek() - BaseCalendar.SUNDAY;
+    }
+
+    /**
+     * Returns the hour represented by this <tt>Date</tt> object. The
+     * returned value is a number (<tt>0</tt> through <tt>23</tt>)
+     * representing the hour within the day that contains or begins
+     * with the instant in time represented by this <tt>Date</tt>
+     * object, as interpreted in the local time zone.
+     *
+     * @return  the hour represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
+     */
+    @Deprecated
+    public int getHours() {
+        return normalize().getHours();
+    }
+
+    /**
+     * Sets the hour of this <tt>Date</tt> object to the specified value.
+     * This <tt>Date</tt> object is modified so that it represents a point
+     * in time within the specified hour of the day, with the year, month,
+     * date, minute, and second the same as before, as interpreted in the
+     * local time zone.
+     *
+     * @param   hours   the hour value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
+     */
+    @Deprecated
+    public void setHours(int hours) {
+        getCalendarDate().setHours(hours);
+    }
+
+    /**
+     * Returns the number of minutes past the hour represented by this date,
+     * as interpreted in the local time zone.
+     * The value returned is between <code>0</code> and <code>59</code>.
+     *
+     * @return  the number of minutes past the hour represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
+     */
+    @Deprecated
+    public int getMinutes() {
+        return normalize().getMinutes();
+    }
+
+    /**
+     * Sets the minutes of this <tt>Date</tt> object to the specified value.
+     * This <tt>Date</tt> object is modified so that it represents a point
+     * in time within the specified minute of the hour, with the year, month,
+     * date, hour, and second the same as before, as interpreted in the
+     * local time zone.
+     *
+     * @param   minutes   the value of the minutes.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
+     */
+    @Deprecated
+    public void setMinutes(int minutes) {
+        getCalendarDate().setMinutes(minutes);
+    }
+
+    /**
+     * Returns the number of seconds past the minute represented by this date.
+     * The value returned is between <code>0</code> and <code>61</code>. The
+     * values <code>60</code> and <code>61</code> can only occur on those
+     * Java Virtual Machines that take leap seconds into account.
+     *
+     * @return  the number of seconds past the minute represented by this date.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
+     */
+    @Deprecated
+    public int getSeconds() {
+        return normalize().getSeconds();
+    }
+
+    /**
+     * Sets the seconds of this <tt>Date</tt> to the specified value.
+     * This <tt>Date</tt> object is modified so that it represents a
+     * point in time within the specified second of the minute, with
+     * the year, month, date, hour, and minute the same as before, as
+     * interpreted in the local time zone.
+     *
+     * @param   seconds   the seconds value.
+     * @see     java.util.Calendar
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
+     */
+    @Deprecated
+    public void setSeconds(int seconds) {
+        getCalendarDate().setSeconds(seconds);
+    }
+
+    /**
+     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     * represented by this <tt>Date</tt> object.
+     *
+     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
+     *          represented by this date.
+     */
+    public long getTime() {
+        return getTimeImpl();
+    }
+
+    private final long getTimeImpl() {
+        if (cdate != null && !cdate.isNormalized()) {
+            normalize();
+        }
+        return fastTime;
+    }
+
+    /**
+     * Sets this <code>Date</code> object to represent a point in time that is
+     * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
+     *
+     * @param   time   the number of milliseconds.
+     */
+    public void setTime(long time) {
+        fastTime = time;
+        cdate = null;
+    }
+
+    /**
+     * Tests if this date is before the specified date.
+     *
+     * @param   when   a date.
+     * @return  <code>true</code> if and only if the instant of time
+     *            represented by this <tt>Date</tt> object is strictly
+     *            earlier than the instant represented by <tt>when</tt>;
+     *          <code>false</code> otherwise.
+     * @exception NullPointerException if <code>when</code> is null.
+     */
+    public boolean before(Date when) {
+        return getMillisOf(this) < getMillisOf(when);
+    }
+
+    /**
+     * Tests if this date is after the specified date.
+     *
+     * @param   when   a date.
+     * @return  <code>true</code> if and only if the instant represented
+     *          by this <tt>Date</tt> object is strictly later than the
+     *          instant represented by <tt>when</tt>;
+     *          <code>false</code> otherwise.
+     * @exception NullPointerException if <code>when</code> is null.
+     */
+    public boolean after(Date when) {
+        return getMillisOf(this) > getMillisOf(when);
+    }
+
+    /**
+     * Compares two dates for equality.
+     * The result is <code>true</code> if and only if the argument is
+     * not <code>null</code> and is a <code>Date</code> object that
+     * represents the same point in time, to the millisecond, as this object.
+     * <p>
+     * Thus, two <code>Date</code> objects are equal if and only if the
+     * <code>getTime</code> method returns the same <code>long</code>
+     * value for both.
+     *
+     * @param   obj   the object to compare with.
+     * @return  <code>true</code> if the objects are the same;
+     *          <code>false</code> otherwise.
+     * @see     java.util.Date#getTime()
+     */
+    public boolean equals(Object obj) {
+        return obj instanceof Date && getTime() == ((Date) obj).getTime();
+    }
+
+    /**
+     * Returns the millisecond value of this <code>Date</code> object
+     * without affecting its internal state.
+     */
+    static final long getMillisOf(Date date) {
+        if (date.cdate == null || date.cdate.isNormalized()) {
+            return date.fastTime;
+        }
+        BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
+        return gcal.getTime(d);
+    }
+
+    /**
+     * Compares two Dates for ordering.
+     *
+     * @param   anotherDate   the <code>Date</code> to be compared.
+     * @return  the value <code>0</code> if the argument Date is equal to
+     *          this Date; a value less than <code>0</code> if this Date
+     *          is before the Date argument; and a value greater than
+     *      <code>0</code> if this Date is after the Date argument.
+     * @since   1.2
+     * @exception NullPointerException if <code>anotherDate</code> is null.
+     */
+    public int compareTo(Date anotherDate) {
+        long thisTime = getMillisOf(this);
+        long anotherTime = getMillisOf(anotherDate);
+        return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
+    }
+
+    /**
+     * Returns a hash code value for this object. The result is the
+     * exclusive OR of the two halves of the primitive <tt>long</tt>
+     * value returned by the {@link Date#getTime}
+     * method. That is, the hash code is the value of the expression:
+     * <blockquote><pre>{@code
+     * (int)(this.getTime()^(this.getTime() >>> 32))
+     * }</pre></blockquote>
+     *
+     * @return  a hash code value for this object.
+     */
+    public int hashCode() {
+        long ht = this.getTime();
+        return (int) ht ^ (int) (ht >> 32);
+    }
+
+    /**
+     * Converts this <code>Date</code> object to a <code>String</code>
+     * of the form:
+     * <blockquote><pre>
+     * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
+     * where:<ul>
+     * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
+     *     Thu, Fri, Sat</tt>).
+     * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
+     *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
+     * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
+     *     <tt>31</tt>), as two decimal digits.
+     * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
+     *     <tt>23</tt>), as two decimal digits.
+     * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
+     *     <tt>59</tt>), as two decimal digits.
+     * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
+     *     <tt>61</tt>, as two decimal digits.
+     * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
+     *     time). Standard time zone abbreviations include those
+     *     recognized by the method <tt>parse</tt>. If time zone
+     *     information is not available, then <tt>zzz</tt> is empty -
+     *     that is, it consists of no characters at all.
+     * <li><tt>yyyy</tt> is the year, as four decimal digits.
+     * </ul>
+     *
+     * @return  a string representation of this date.
+     * @see     java.util.Date#toLocaleString()
+     * @see     java.util.Date#toGMTString()
+     */
+    public String toString() {
+        // "EEE MMM dd HH:mm:ss zzz yyyy";
+        BaseCalendar.Date date = normalize();
+        StringBuilder sb = new StringBuilder(28);
+        int index = date.getDayOfWeek();
+        if (index == BaseCalendar.SUNDAY) {
+            index = 8;
+        }
+        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
+        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
+        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
+
+        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
+        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
+        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
+        TimeZone zi = date.getZone();
+        if (zi != null) {
+            sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
+        } else {
+            sb.append("GMT");
+        }
+        sb.append(' ').append(date.getYear());  // yyyy
+        return sb.toString();
+    }
+
+    /**
+     * Converts the given name to its 3-letter abbreviation (e.g.,
+     * "monday" -> "Mon") and stored the abbreviation in the given
+     * <code>StringBuilder</code>.
+     */
+    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
+        sb.append(Character.toUpperCase(name.charAt(0)));
+        sb.append(name.charAt(1)).append(name.charAt(2));
+        return sb;
+    }
+
+    /**
+     * Creates a string representation of this <tt>Date</tt> object in an
+     * implementation-dependent form. The intent is that the form should
+     * be familiar to the user of the Java application, wherever it may
+     * happen to be running. The intent is comparable to that of the
+     * "<code>%c</code>" format supported by the <code>strftime()</code>
+     * function of ISO&nbsp;C.
+     *
+     * @return  a string representation of this date, using the locale
+     *          conventions.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#toString()
+     * @see     java.util.Date#toGMTString()
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.format(Date date)</code>.
+     */
+    @Deprecated
+    public String toLocaleString() {
+        DateFormat formatter = DateFormat.getDateTimeInstance();
+        return formatter.format(this);
+    }
+
+    /**
+     * Creates a string representation of this <tt>Date</tt> object of
+     * the form:
+     * <blockquote><pre>
+     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
+     * where:<ul>
+     * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
+     *     as one or two decimal digits.
+     * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
+     *     Aug, Sep, Oct, Nov, Dec</tt>).
+     * <li><i>yyyy</i> is the year, as four decimal digits.
+     * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
+     *     as two decimal digits.
+     * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
+     *     <tt>59</tt>), as two decimal digits.
+     * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
+     *     <tt>61</tt>), as two decimal digits.
+     * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
+     *     Greenwich Mean Time.
+     * </ul><p>
+     * The result does not depend on the local time zone.
+     *
+     * @return  a string representation of this date, using the Internet GMT
+     *          conventions.
+     * @see     java.text.DateFormat
+     * @see     java.util.Date#toString()
+     * @see     java.util.Date#toLocaleString()
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>DateFormat.format(Date date)</code>, using a
+     * GMT <code>TimeZone</code>.
+     */
+    @Deprecated
+    public String toGMTString() {
+        // d MMM yyyy HH:mm:ss 'GMT'
+        long t = getTime();
+        BaseCalendar cal = getCalendarSystem(t);
+        BaseCalendar.Date date =
+            (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
+        StringBuilder sb = new StringBuilder(32);
+        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
+        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
+        sb.append(date.getYear()).append(' ');                            // yyyy
+        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
+        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
+        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
+        sb.append(" GMT");                                                // ' GMT'
+        return sb.toString();
+    }
+
+    /**
+     * Returns the offset, measured in minutes, for the local time zone
+     * relative to UTC that is appropriate for the time represented by
+     * this <code>Date</code> object.
+     * <p>
+     * For example, in Massachusetts, five time zones west of Greenwich:
+     * <blockquote><pre>
+     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
+     * because on February 14, 1996, standard time (Eastern Standard Time)
+     * is in use, which is offset five hours from UTC; but:
+     * <blockquote><pre>
+     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
+     * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
+     * is in use, which is offset only four hours from UTC.<p>
+     * This method produces the same result as if it computed:
+     * <blockquote><pre>
+     * (this.getTime() - UTC(this.getYear(),
+     *                       this.getMonth(),
+     *                       this.getDate(),
+     *                       this.getHours(),
+     *                       this.getMinutes(),
+     *                       this.getSeconds())) / (60 * 1000)
+     * </pre></blockquote>
+     *
+     * @return  the time-zone offset, in minutes, for the current time zone.
+     * @see     java.util.Calendar#ZONE_OFFSET
+     * @see     java.util.Calendar#DST_OFFSET
+     * @see     java.util.TimeZone#getDefault
+     * @deprecated As of JDK version 1.1,
+     * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
+     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
+     */
+    @Deprecated
+    public int getTimezoneOffset() {
+        int zoneOffset;
+        if (cdate == null) {
+            // Android-changed: Android specific time zone logic
+            GregorianCalendar cal = new GregorianCalendar(fastTime);
+            zoneOffset = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET));
+        } else {
+            normalize();
+            zoneOffset = cdate.getZoneOffset();
+        }
+        return -zoneOffset/60000;  // convert to minutes
+    }
+
+    private final BaseCalendar.Date getCalendarDate() {
+        if (cdate == null) {
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
+                                                            TimeZone.getDefaultRef());
+        }
+        return cdate;
+    }
+
+    private final BaseCalendar.Date normalize() {
+        if (cdate == null) {
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
+                                                            TimeZone.getDefaultRef());
+            return cdate;
+        }
+
+        // Normalize cdate with the TimeZone in cdate first. This is
+        // required for the compatible behavior.
+        if (!cdate.isNormalized()) {
+            cdate = normalize(cdate);
+        }
+
+        // If the default TimeZone has changed, then recalculate the
+        // fields with the new TimeZone.
+        TimeZone tz = TimeZone.getDefaultRef();
+        if (tz != cdate.getZone()) {
+            cdate.setZone(tz);
+            CalendarSystem cal = getCalendarSystem(cdate);
+            cal.getCalendarDate(fastTime, cdate);
+        }
+        return cdate;
+    }
+
+    // fastTime and the returned data are in sync upon return.
+    private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
+        int y = date.getNormalizedYear();
+        int m = date.getMonth();
+        int d = date.getDayOfMonth();
+        int hh = date.getHours();
+        int mm = date.getMinutes();
+        int ss = date.getSeconds();
+        int ms = date.getMillis();
+        TimeZone tz = date.getZone();
+
+        // If the specified year can't be handled using a long value
+        // in milliseconds, GregorianCalendar is used for full
+        // compatibility with underflow and overflow. This is required
+        // by some JCK tests. The limits are based max year values -
+        // years that can be represented by max values of d, hh, mm,
+        // ss and ms. Also, let GregorianCalendar handle the default
+        // cutover year so that we don't need to worry about the
+        // transition here.
+        if (y == 1582 || y > 280000000 || y < -280000000) {
+            if (tz == null) {
+                tz = TimeZone.getTimeZone("GMT");
+            }
+            GregorianCalendar gc = new GregorianCalendar(tz);
+            gc.clear();
+            gc.set(GregorianCalendar.MILLISECOND, ms);
+            gc.set(y, m-1, d, hh, mm, ss);
+            fastTime = gc.getTimeInMillis();
+            BaseCalendar cal = getCalendarSystem(fastTime);
+            date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
+            return date;
+        }
+
+        BaseCalendar cal = getCalendarSystem(y);
+        if (cal != getCalendarSystem(date)) {
+            date = (BaseCalendar.Date) cal.newCalendarDate(tz);
+            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
+        }
+        // Perform the GregorianCalendar-style normalization.
+        fastTime = cal.getTime(date);
+
+        // In case the normalized date requires the other calendar
+        // system, we need to recalculate it using the other one.
+        BaseCalendar ncal = getCalendarSystem(fastTime);
+        if (ncal != cal) {
+            date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
+            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
+            fastTime = ncal.getTime(date);
+        }
+        return date;
+    }
+
+    /**
+     * Returns the Gregorian or Julian calendar system to use with the
+     * given date. Use Gregorian from October 15, 1582.
+     *
+     * @param year normalized calendar year (not -1900)
+     * @return the CalendarSystem to use for the specified date
+     */
+    private static final BaseCalendar getCalendarSystem(int year) {
+        if (year >= 1582) {
+            return gcal;
+        }
+        return getJulianCalendar();
+    }
+
+    private static final BaseCalendar getCalendarSystem(long utc) {
+        // Quickly check if the time stamp given by `utc' is the Epoch
+        // or later. If it's before 1970, we convert the cutover to
+        // local time to compare.
+        if (utc >= 0
+            || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
+                        - TimeZone.getDefaultRef().getOffset(utc)) {
+            return gcal;
+        }
+        return getJulianCalendar();
+    }
+
+    private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
+        if (jcal == null) {
+            return gcal;
+        }
+        if (cdate.getEra() != null) {
+            return jcal;
+        }
+        return gcal;
+    }
+
+    synchronized private static final BaseCalendar getJulianCalendar() {
+        if (jcal == null) {
+            jcal = (BaseCalendar) CalendarSystem.forName("julian");
+        }
+        return jcal;
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * @serialData The value returned by <code>getTime()</code>
+     *             is emitted (long).  This represents the offset from
+     *             January 1, 1970, 00:00:00 GMT in milliseconds.
+     */
+    private void writeObject(ObjectOutputStream s)
+         throws IOException
+    {
+        s.writeLong(getTimeImpl());
+    }
+
+    /**
+     * Reconstitute this object from a stream (i.e., deserialize it).
+     */
+    private void readObject(ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+        fastTime = s.readLong();
+    }
+
+    /**
+     * Obtains an instance of {@code Date} from an {@code Instant} object.
+     * <p>
+     * {@code Instant} uses a precision of nanoseconds, whereas {@code Date}
+     * uses a precision of milliseconds.  The conversion will trancate any
+     * excess precision information as though the amount in nanoseconds was
+     * subject to integer division by one million.
+     * <p>
+     * {@code Instant} can store points on the time-line further in the future
+     * and further in the past than {@code Date}. In this scenario, this method
+     * will throw an exception.
+     *
+     * @param instant  the instant to convert
+     * @return a {@code Date} representing the same point on the time-line as
+     *  the provided instant
+     * @exception NullPointerException if {@code instant} is null.
+     * @exception IllegalArgumentException if the instant is too large to
+     *  represent as a {@code Date}
+     * @since 1.8
+     */
+    public static Date from(Instant instant) {
+        try {
+            return new Date(instant.toEpochMilli());
+        } catch (ArithmeticException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+    }
+
+    /**
+     * Converts this {@code Date} object to an {@code Instant}.
+     * <p>
+     * The conversion creates an {@code Instant} that represents the same
+     * point on the time-line as this {@code Date}.
+     *
+     * @return an instant representing the same point on the time-line as
+     *  this {@code Date} object
+     * @since 1.8
+     */
+    public Instant toInstant() {
+        return Instant.ofEpochMilli(getTime());
+    }
+}
diff --git a/java/util/Deque.annotated.java b/java/util/Deque.annotated.java
new file mode 100644
index 0000000..d93d5a2
--- /dev/null
+++ b/java/util/Deque.annotated.java
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Deque<E> extends java.util.Queue<E> {
+
+public void addFirst(@libcore.util.NullFromTypeParam E e);
+
+public void addLast(@libcore.util.NullFromTypeParam E e);
+
+public boolean offerFirst(@libcore.util.NullFromTypeParam E e);
+
+public boolean offerLast(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E removeFirst();
+
[email protected] public E removeLast();
+
[email protected] public E pollFirst();
+
[email protected] public E pollLast();
+
[email protected] public E getFirst();
+
[email protected] public E getLast();
+
[email protected] public E peekFirst();
+
[email protected] public E peekLast();
+
+public boolean removeFirstOccurrence(@libcore.util.Nullable java.lang.Object o);
+
+public boolean removeLastOccurrence(@libcore.util.Nullable java.lang.Object o);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean offer(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E remove();
+
[email protected] public E poll();
+
[email protected] public E element();
+
[email protected] public E peek();
+
+public void push(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E pop();
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
+public int size();
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> descendingIterator();
+}
diff --git a/java/util/Deque.java b/java/util/Deque.java
new file mode 100644
index 0000000..3d79952
--- /dev/null
+++ b/java/util/Deque.java
@@ -0,0 +1,580 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// Android-changed: removed link to collections framework docs
+/**
+ * A linear collection that supports element insertion and removal at
+ * both ends.  The name <i>deque</i> is short for "double ended queue"
+ * and is usually pronounced "deck".  Most {@code Deque}
+ * implementations place no fixed limits on the number of elements
+ * they may contain, but this interface supports capacity-restricted
+ * deques as well as those with no fixed size limit.
+ *
+ * <p>This interface defines methods to access the elements at both
+ * ends of the deque.  Methods are provided to insert, remove, and
+ * examine the element.  Each of these methods exists in two forms:
+ * one throws an exception if the operation fails, the other returns a
+ * special value (either {@code null} or {@code false}, depending on
+ * the operation).  The latter form of the insert operation is
+ * designed specifically for use with capacity-restricted
+ * {@code Deque} implementations; in most implementations, insert
+ * operations cannot fail.
+ *
+ * <p>The twelve methods described above are summarized in the
+ * following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of Deque methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>First Element (Head)</b></td>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Last Element (Tail)</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link Deque#addFirst addFirst(e)}</td>
+ *    <td>{@link Deque#offerFirst offerFirst(e)}</td>
+ *    <td>{@link Deque#addLast addLast(e)}</td>
+ *    <td>{@link Deque#offerLast offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link Deque#removeFirst removeFirst()}</td>
+ *    <td>{@link Deque#pollFirst pollFirst()}</td>
+ *    <td>{@link Deque#removeLast removeLast()}</td>
+ *    <td>{@link Deque#pollLast pollLast()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link Deque#getFirst getFirst()}</td>
+ *    <td>{@link Deque#peekFirst peekFirst()}</td>
+ *    <td>{@link Deque#getLast getLast()}</td>
+ *    <td>{@link Deque#peekLast peekLast()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>This interface extends the {@link Queue} interface.  When a deque is
+ * used as a queue, FIFO (First-In-First-Out) behavior results.  Elements are
+ * added at the end of the deque and removed from the beginning.  The methods
+ * inherited from the {@code Queue} interface are precisely equivalent to
+ * {@code Deque} methods as indicated in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of Queue and Deque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER> <b>{@code Queue} Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code Deque} Method</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#add add(e)}</td>
+ *    <td>{@link #addLast addLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#offer offer(e)}</td>
+ *    <td>{@link #offerLast offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#remove remove()}</td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#poll poll()}</td>
+ *    <td>{@link #pollFirst pollFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#element element()}</td>
+ *    <td>{@link #getFirst getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link java.util.Queue#peek peek()}</td>
+ *    <td>{@link #peek peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This
+ * interface should be used in preference to the legacy {@link Stack} class.
+ * When a deque is used as a stack, elements are pushed and popped from the
+ * beginning of the deque.  Stack methods are precisely equivalent to
+ * {@code Deque} methods as indicated in the table below:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of Stack and Deque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER> <b>Stack Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code Deque} Method</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #push push(e)}</td>
+ *    <td>{@link #addFirst addFirst(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #pop pop()}</td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #peek peek()}</td>
+ *    <td>{@link #peekFirst peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Note that the {@link #peek peek} method works equally well when
+ * a deque is used as a queue or a stack; in either case, elements are
+ * drawn from the beginning of the deque.
+ *
+ * <p>This interface provides two methods to remove interior
+ * elements, {@link #removeFirstOccurrence removeFirstOccurrence} and
+ * {@link #removeLastOccurrence removeLastOccurrence}.
+ *
+ * <p>Unlike the {@link List} interface, this interface does not
+ * provide support for indexed access to elements.
+ *
+ * <p>While {@code Deque} implementations are not strictly required
+ * to prohibit the insertion of null elements, they are strongly
+ * encouraged to do so.  Users of any {@code Deque} implementations
+ * that do allow null elements are strongly encouraged <i>not</i> to
+ * take advantage of the ability to insert nulls.  This is so because
+ * {@code null} is used as a special return value by various methods
+ * to indicated that the deque is empty.
+ *
+ * <p>{@code Deque} implementations generally do not define
+ * element-based versions of the {@code equals} and {@code hashCode}
+ * methods, but instead inherit the identity-based versions from class
+ * {@code Object}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @since  1.6
+ * @param <E> the type of elements held in this deque
+ */
+public interface Deque<E> extends Queue<E> {
+    // Android-changed: fix framework docs link to "Collection#optional-restrictions"
+    // Several occurrences of the link have been fixed throughout.
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use method {@link #offerFirst}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void addFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use method {@link #offerLast}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void addLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * this method is generally preferable to the {@link #addFirst} method,
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * this method is generally preferable to the {@link #addLast} method,
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerLast(E e);
+
+    /**
+     * Retrieves and removes the first element of this deque.  This method
+     * differs from {@link #pollFirst pollFirst} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E removeFirst();
+
+    /**
+     * Retrieves and removes the last element of this deque.  This method
+     * differs from {@link #pollLast pollLast} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * @return the tail of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E removeLast();
+
+    /**
+     * Retrieves and removes the first element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E pollFirst();
+
+    /**
+     * Retrieves and removes the last element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the tail of this deque, or {@code null} if this deque is empty
+     */
+    E pollLast();
+
+    /**
+     * Retrieves, but does not remove, the first element of this deque.
+     *
+     * This method differs from {@link #peekFirst peekFirst} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E getFirst();
+
+    /**
+     * Retrieves, but does not remove, the last element of this deque.
+     * This method differs from {@link #peekLast peekLast} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * @return the tail of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E getLast();
+
+    /**
+     * Retrieves, but does not remove, the first element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E peekFirst();
+
+    /**
+     * Retrieves, but does not remove, the last element of this deque,
+     * or returns {@code null} if this deque is empty.
+     *
+     * @return the tail of this deque, or {@code null} if this deque is empty
+     */
+    E peekLast();
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeFirstOccurrence(Object o);
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeLastOccurrence(Object o);
+
+    // *** Queue methods ***
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted deque, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted deque, this method is
+     * generally preferable to the {@link #add} method, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * <p>This method is equivalent to {@link #offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e);
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque).
+     * This method differs from {@link #poll poll} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst()}.
+     *
+     * @return the first element of this deque, or {@code null} if
+     *         this deque is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque).
+     * This method differs from {@link #peek peek} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst()}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque), or
+     * returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst()}.
+     *
+     * @return the head of the queue represented by this deque, or
+     *         {@code null} if this deque is empty
+     */
+    E peek();
+
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque (in other
+     * words, at the head of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void push(E e);
+
+    /**
+     * Pops an element from the stack represented by this deque.  In other
+     * words, removes and returns the first element of this deque.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this deque (which is the top
+     *         of the stack represented by this deque)
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E pop();
+
+
+    // *** Collection methods ***
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code Objects.equals(o, e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this deque is to be tested
+     * @return {@code true} if this deque contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         deque does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    int size();
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * @return an iterator over the elements in this deque in reverse
+     * sequence
+     */
+    Iterator<E> descendingIterator();
+
+}
diff --git a/java/util/Dictionary.java b/java/util/Dictionary.java
new file mode 100644
index 0000000..4c4574b
--- /dev/null
+++ b/java/util/Dictionary.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * The <code>Dictionary</code> class is the abstract parent of any
+ * class, such as <code>Hashtable</code>, which maps keys to values.
+ * Every key and every value is an object. In any one <tt>Dictionary</tt>
+ * object, every key is associated with at most one value. Given a
+ * <tt>Dictionary</tt> and a key, the associated element can be looked up.
+ * Any non-<code>null</code> object can be used as a key and as a value.
+ * <p>
+ * As a rule, the <code>equals</code> method should be used by
+ * implementations of this class to decide if two keys are the same.
+ * <p>
+ * <strong>NOTE: This class is obsolete.  New implementations should
+ * implement the Map interface, rather than extending this class.</strong>
+ *
+ * @author  unascribed
+ * @see     java.util.Map
+ * @see     java.lang.Object#equals(java.lang.Object)
+ * @see     java.lang.Object#hashCode()
+ * @see     java.util.Hashtable
+ * @since   JDK1.0
+ */
+public abstract
+class Dictionary<K,V> {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public Dictionary() {
+    }
+
+    /**
+     * Returns the number of entries (distinct keys) in this dictionary.
+     *
+     * @return  the number of keys in this dictionary.
+     */
+    abstract public int size();
+
+    /**
+     * Tests if this dictionary maps no keys to value. The general contract
+     * for the <tt>isEmpty</tt> method is that the result is true if and only
+     * if this dictionary contains no entries.
+     *
+     * @return  <code>true</code> if this dictionary maps no keys to values;
+     *          <code>false</code> otherwise.
+     */
+    abstract public boolean isEmpty();
+
+    /**
+     * Returns an enumeration of the keys in this dictionary. The general
+     * contract for the keys method is that an <tt>Enumeration</tt> object
+     * is returned that will generate all the keys for which this dictionary
+     * contains entries.
+     *
+     * @return  an enumeration of the keys in this dictionary.
+     * @see     java.util.Dictionary#elements()
+     * @see     java.util.Enumeration
+     */
+    abstract public Enumeration<K> keys();
+
+    /**
+     * Returns an enumeration of the values in this dictionary. The general
+     * contract for the <tt>elements</tt> method is that an
+     * <tt>Enumeration</tt> is returned that will generate all the elements
+     * contained in entries in this dictionary.
+     *
+     * @return  an enumeration of the values in this dictionary.
+     * @see     java.util.Dictionary#keys()
+     * @see     java.util.Enumeration
+     */
+    abstract public Enumeration<V> elements();
+
+    /**
+     * Returns the value to which the key is mapped in this dictionary.
+     * The general contract for the <tt>isEmpty</tt> method is that if this
+     * dictionary contains an entry for the specified key, the associated
+     * value is returned; otherwise, <tt>null</tt> is returned.
+     *
+     * @return  the value to which the key is mapped in this dictionary;
+     * @param   key   a key in this dictionary.
+     *          <code>null</code> if the key is not mapped to any value in
+     *          this dictionary.
+     * @exception NullPointerException if the <tt>key</tt> is <tt>null</tt>.
+     * @see     java.util.Dictionary#put(java.lang.Object, java.lang.Object)
+     */
+    abstract public V get(Object key);
+
+    /**
+     * Maps the specified <code>key</code> to the specified
+     * <code>value</code> in this dictionary. Neither the key nor the
+     * value can be <code>null</code>.
+     * <p>
+     * If this dictionary already contains an entry for the specified
+     * <tt>key</tt>, the value already in this dictionary for that
+     * <tt>key</tt> is returned, after modifying the entry to contain the
+     *  new element. <p>If this dictionary does not already have an entry
+     *  for the specified <tt>key</tt>, an entry is created for the
+     *  specified <tt>key</tt> and <tt>value</tt>, and <tt>null</tt> is
+     *  returned.
+     * <p>
+     * The <code>value</code> can be retrieved by calling the
+     * <code>get</code> method with a <code>key</code> that is equal to
+     * the original <code>key</code>.
+     *
+     * @param      key     the hashtable key.
+     * @param      value   the value.
+     * @return     the previous value to which the <code>key</code> was mapped
+     *             in this dictionary, or <code>null</code> if the key did not
+     *             have a previous mapping.
+     * @exception  NullPointerException  if the <code>key</code> or
+     *               <code>value</code> is <code>null</code>.
+     * @see        java.lang.Object#equals(java.lang.Object)
+     * @see        java.util.Dictionary#get(java.lang.Object)
+     */
+    abstract public V put(K key, V value);
+
+    /**
+     * Removes the <code>key</code> (and its corresponding
+     * <code>value</code>) from this dictionary. This method does nothing
+     * if the <code>key</code> is not in this dictionary.
+     *
+     * @param   key   the key that needs to be removed.
+     * @return  the value to which the <code>key</code> had been mapped in this
+     *          dictionary, or <code>null</code> if the key did not have a
+     *          mapping.
+     * @exception NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    abstract public V remove(Object key);
+}
diff --git a/java/util/DoubleSummaryStatistics.java b/java/util/DoubleSummaryStatistics.java
new file mode 100644
index 0000000..222d967
--- /dev/null
+++ b/java/util/DoubleSummaryStatistics.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.DoubleConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of doubles with:
+ * <pre> {@code
+ * DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new,
+ *                                                      DoubleSummaryStatistics::accept,
+ *                                                      DoubleSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code DoubleSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * DoubleSummaryStatistics stats = people.stream()
+ *     .collect(Collectors.summarizingDouble(Person::getWeight));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their weights.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingDouble(java.util.function.ToDoubleFunction)
+ * Collectors.toDoubleStatistics()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ * @since 1.8
+ */
+public class DoubleSummaryStatistics implements DoubleConsumer {
+    private long count;
+    private double sum;
+    private double sumCompensation; // Low order bits of sum
+    private double simpleSum; // Used to compute right sum for non-finite inputs
+    private double min = Double.POSITIVE_INFINITY;
+    private double max = Double.NEGATIVE_INFINITY;
+
+    /**
+     * Construct an empty instance with zero count, zero sum,
+     * {@code Double.POSITIVE_INFINITY} min, {@code Double.NEGATIVE_INFINITY}
+     * max and zero average.
+     */
+    public DoubleSummaryStatistics() { }
+
+    /**
+     * Records another value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(double value) {
+        ++count;
+        simpleSum += value;
+        sumWithCompensation(value);
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code DoubleSummaryStatistics} into this
+     * one.
+     *
+     * @param other another {@code DoubleSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(DoubleSummaryStatistics other) {
+        count += other.count;
+        simpleSum += other.simpleSum;
+        sumWithCompensation(other.sum);
+        sumWithCompensation(other.sumCompensation);
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Incorporate a new double value using Kahan summation /
+     * compensated summation.
+     */
+    private void sumWithCompensation(double value) {
+        double tmp = value - sumCompensation;
+        double velvel = sum + tmp; // Little wolf of rounding error
+        sumCompensation = (velvel - sum) - tmp;
+        sum = velvel;
+    }
+
+    /**
+     * Return the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * If any recorded value is a NaN or the sum is at any point a NaN
+     * then the sum will be NaN.
+     *
+     * <p> The value of a floating-point sum is a function both of the
+     * input values as well as the order of addition operations. The
+     * order of addition operations of this method is intentionally
+     * not defined to allow for implementation flexibility to improve
+     * the speed and accuracy of the computed result.
+     *
+     * In particular, this method may be implemented using compensated
+     * summation or other technique to reduce the error bound in the
+     * numerical sum compared to a simple summation of {@code double}
+     * values.
+     *
+     * @apiNote Values sorted by increasing absolute magnitude tend to yield
+     * more accurate results.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final double getSum() {
+        // Better error bounds to add both terms as the final sum
+        double tmp =  sum + sumCompensation;
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            // If the compensated sum is spuriously NaN from
+            // accumulating one or more same-signed infinite values,
+            // return the correctly-signed infinity stored in
+            // simpleSum.
+            return simpleSum;
+        else
+            return tmp;
+    }
+
+    /**
+     * Returns the minimum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
+     * recorded. Unlike the numerical comparison operators, this method
+     * considers negative zero to be strictly smaller than positive zero.
+     *
+     * @return the minimum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.POSITIVE_INFINITY} if no values were
+     * recorded
+     */
+    public final double getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
+     * recorded. Unlike the numerical comparison operators, this method
+     * considers negative zero to be strictly smaller than positive zero.
+     *
+     * @return the maximum recorded value, {@code Double.NaN} if any recorded
+     * value was NaN or {@code Double.NEGATIVE_INFINITY} if no values were
+     * recorded
+     */
+    public final double getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no
+     * values have been recorded.
+     *
+     * If any recorded value is a NaN or the sum is at any point a NaN
+     * then the average will be code NaN.
+     *
+     * <p>The average returned can vary depending upon the order in
+     * which values are recorded.
+     *
+     * This method may be implemented using compensated summation or
+     * other technique to reduce the error bound in the {@link #getSum
+     * numerical sum} used to compute the average.
+     *
+     * @apiNote Values sorted by increasing absolute magnitude tend to yield
+     * more accurate results.
+     *
+     * @return the arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? getSum() / getCount() : 0.0d;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    @Override
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%f, min=%f, average=%f, max=%f}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/java/util/DualPivotQuicksort.java b/java/util/DualPivotQuicksort.java
new file mode 100644
index 0000000..4682dde
--- /dev/null
+++ b/java/util/DualPivotQuicksort.java
@@ -0,0 +1,3078 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class implements the Dual-Pivot Quicksort algorithm by
+ * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
+ *
+ * All exposed methods are package-private, designed to be invoked
+ * from public methods (in class Arrays) after performing any
+ * necessary array bounds checks and expanding parameters into the
+ * required forms.
+ *
+ * @author Vladimir Yaroslavskiy
+ * @author Jon Bentley
+ * @author Josh Bloch
+ *
+ * @version 2011.02.11 m765.827.12i:5\7pm
+ * @since 1.7
+ */
+final class DualPivotQuicksort {
+
+    /**
+     * Prevents instantiation.
+     */
+    private DualPivotQuicksort() {}
+
+    /*
+     * Tuning parameters.
+     */
+
+    /**
+     * The maximum number of runs in merge sort.
+     */
+    private static final int MAX_RUN_COUNT = 67;
+
+    /**
+     * The maximum length of run in merge sort.
+     */
+    private static final int MAX_RUN_LENGTH = 33;
+
+    /**
+     * If the length of an array to be sorted is less than this
+     * constant, Quicksort is used in preference to merge sort.
+     */
+    private static final int QUICKSORT_THRESHOLD = 286;
+
+    /**
+     * If the length of an array to be sorted is less than this
+     * constant, insertion sort is used in preference to Quicksort.
+     */
+    private static final int INSERTION_SORT_THRESHOLD = 47;
+
+    /**
+     * If the length of a byte array to be sorted is greater than this
+     * constant, counting sort is used in preference to insertion sort.
+     */
+    private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29;
+
+    /**
+     * If the length of a short or char array to be sorted is greater
+     * than this constant, counting sort is used in preference to Quicksort.
+     */
+    private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200;
+
+    /*
+     * Sorting methods for seven primitive types.
+     */
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(int[] a, int left, int right,
+                     int[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    int t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        int[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new int[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            int[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(int[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    int ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    int a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                int last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            int pivot1 = a[e2];
+            int pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                int ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    int ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            int pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                int ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(long[] a, int left, int right,
+                     long[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    long t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        long[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new long[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            long[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(long[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    long ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    long a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                long last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            long pivot1 = a[e2];
+            long pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                long ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    long ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            long pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                long ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(short[] a, int left, int right,
+                     short[] work, int workBase, int workLen) {
+        // Use counting sort on large arrays
+        if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+            int[] count = new int[NUM_SHORT_VALUES];
+
+            for (int i = left - 1; ++i <= right;
+                count[a[i] - Short.MIN_VALUE]++
+            );
+            for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
+                while (count[--i] == 0);
+                short value = (short) (i + Short.MIN_VALUE);
+                int s = count[i];
+
+                do {
+                    a[--k] = value;
+                } while (--s > 0);
+            }
+        } else { // Use Dual-Pivot Quicksort on small arrays
+            doSort(a, left, right, work, workBase, workLen);
+        }
+    }
+
+    /** The number of distinct short values. */
+    private static final int NUM_SHORT_VALUES = 1 << 16;
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(short[] a, int left, int right,
+                               short[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    short t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        short[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new short[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            short[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(short[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    short ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    short a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                short last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            short pivot1 = a[e2];
+            short pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                short ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    short ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            short pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                short ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(char[] a, int left, int right,
+                     char[] work, int workBase, int workLen) {
+        // Use counting sort on large arrays
+        if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+            int[] count = new int[NUM_CHAR_VALUES];
+
+            for (int i = left - 1; ++i <= right;
+                count[a[i]]++
+            );
+            for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
+                while (count[--i] == 0);
+                char value = (char) i;
+                int s = count[i];
+
+                do {
+                    a[--k] = value;
+                } while (--s > 0);
+            }
+        } else { // Use Dual-Pivot Quicksort on small arrays
+            doSort(a, left, right, work, workBase, workLen);
+        }
+    }
+
+    /** The number of distinct char values. */
+    private static final int NUM_CHAR_VALUES = 1 << 16;
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(char[] a, int left, int right,
+                               char[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    char t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        char[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new char[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            char[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(char[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    char ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    char a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                char last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            char pivot1 = a[e2];
+            char pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                char ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    char ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = pivot1;
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            char pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                char ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = pivot;
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /** The number of distinct byte values. */
+    private static final int NUM_BYTE_VALUES = 1 << 8;
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     */
+    static void sort(byte[] a, int left, int right) {
+        // Use counting sort on large arrays
+        if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
+            int[] count = new int[NUM_BYTE_VALUES];
+
+            for (int i = left - 1; ++i <= right;
+                count[a[i] - Byte.MIN_VALUE]++
+            );
+            for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) {
+                while (count[--i] == 0);
+                byte value = (byte) (i + Byte.MIN_VALUE);
+                int s = count[i];
+
+                do {
+                    a[--k] = value;
+                } while (--s > 0);
+            }
+        } else { // Use insertion sort on small arrays
+            for (int i = left, j = i; i < right; j = ++i) {
+                byte ai = a[i + 1];
+                while (ai < a[j]) {
+                    a[j + 1] = a[j];
+                    if (j-- == left) {
+                        break;
+                    }
+                }
+                a[j + 1] = ai;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(float[] a, int left, int right,
+                     float[] work, int workBase, int workLen) {
+        /*
+         * Phase 1: Move NaNs to the end of the array.
+         */
+        while (left <= right && Float.isNaN(a[right])) {
+            --right;
+        }
+        for (int k = right; --k >= left; ) {
+            float ak = a[k];
+            if (ak != ak) { // a[k] is NaN
+                a[k] = a[right];
+                a[right] = ak;
+                --right;
+            }
+        }
+
+        /*
+         * Phase 2: Sort everything except NaNs (which are already in place).
+         */
+        doSort(a, left, right, work, workBase, workLen);
+
+        /*
+         * Phase 3: Place negative zeros before positive zeros.
+         */
+        int hi = right;
+
+        /*
+         * Find the first zero, or first positive, or last negative element.
+         */
+        while (left < hi) {
+            int middle = (left + hi) >>> 1;
+            float middleValue = a[middle];
+
+            if (middleValue < 0.0f) {
+                left = middle + 1;
+            } else {
+                hi = middle;
+            }
+        }
+
+        /*
+         * Skip the last negative value (if any) or all leading negative zeros.
+         */
+        while (left <= right && Float.floatToRawIntBits(a[left]) < 0) {
+            ++left;
+        }
+
+        /*
+         * Move negative zeros to the beginning of the sub-range.
+         *
+         * Partitioning:
+         *
+         * +----------------------------------------------------+
+         * |   < 0.0   |   -0.0   |   0.0   |   ?  ( >= 0.0 )   |
+         * +----------------------------------------------------+
+         *              ^          ^         ^
+         *              |          |         |
+         *             left        p         k
+         *
+         * Invariants:
+         *
+         *   all in (*,  left)  <  0.0
+         *   all in [left,  p) == -0.0
+         *   all in [p,     k) ==  0.0
+         *   all in [k, right] >=  0.0
+         *
+         * Pointer k is the first index of ?-part.
+         */
+        for (int k = left, p = left - 1; ++k <= right; ) {
+            float ak = a[k];
+            if (ak != 0.0f) {
+                break;
+            }
+            if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f
+                a[k] = 0.0f;
+                a[++p] = -0.0f;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(float[] a, int left, int right,
+                               float[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    float t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        float[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new float[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            float[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(float[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    float ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    float a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                float last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { float t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { float t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            float pivot1 = a[e2];
+            float pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                float ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    float ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = a[great];
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            float pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                float ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = a[great];
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array using the given
+     * workspace array slice if possible for merging
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    static void sort(double[] a, int left, int right,
+                     double[] work, int workBase, int workLen) {
+        /*
+         * Phase 1: Move NaNs to the end of the array.
+         */
+        while (left <= right && Double.isNaN(a[right])) {
+            --right;
+        }
+        for (int k = right; --k >= left; ) {
+            double ak = a[k];
+            if (ak != ak) { // a[k] is NaN
+                a[k] = a[right];
+                a[right] = ak;
+                --right;
+            }
+        }
+
+        /*
+         * Phase 2: Sort everything except NaNs (which are already in place).
+         */
+        doSort(a, left, right, work, workBase, workLen);
+
+        /*
+         * Phase 3: Place negative zeros before positive zeros.
+         */
+        int hi = right;
+
+        /*
+         * Find the first zero, or first positive, or last negative element.
+         */
+        while (left < hi) {
+            int middle = (left + hi) >>> 1;
+            double middleValue = a[middle];
+
+            if (middleValue < 0.0d) {
+                left = middle + 1;
+            } else {
+                hi = middle;
+            }
+        }
+
+        /*
+         * Skip the last negative value (if any) or all leading negative zeros.
+         */
+        while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) {
+            ++left;
+        }
+
+        /*
+         * Move negative zeros to the beginning of the sub-range.
+         *
+         * Partitioning:
+         *
+         * +----------------------------------------------------+
+         * |   < 0.0   |   -0.0   |   0.0   |   ?  ( >= 0.0 )   |
+         * +----------------------------------------------------+
+         *              ^          ^         ^
+         *              |          |         |
+         *             left        p         k
+         *
+         * Invariants:
+         *
+         *   all in (*,  left)  <  0.0
+         *   all in [left,  p) == -0.0
+         *   all in [p,     k) ==  0.0
+         *   all in [k, right] >=  0.0
+         *
+         * Pointer k is the first index of ?-part.
+         */
+        for (int k = left, p = left - 1; ++k <= right; ) {
+            double ak = a[k];
+            if (ak != 0.0d) {
+                break;
+            }
+            if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d
+                a[k] = 0.0d;
+                a[++p] = -0.0d;
+            }
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private static void doSort(double[] a, int left, int right,
+                               double[] work, int workBase, int workLen) {
+        // Use Quicksort on small arrays
+        if (right - left < QUICKSORT_THRESHOLD) {
+            sort(a, left, right, true);
+            return;
+        }
+
+        /*
+         * Index run[i] is the start of i-th run
+         * (ascending or descending sequence).
+         */
+        int[] run = new int[MAX_RUN_COUNT + 1];
+        int count = 0; run[0] = left;
+
+        // Check if the array is nearly sorted
+        for (int k = left; k < right; run[count] = k) {
+            if (a[k] < a[k + 1]) { // ascending
+                while (++k <= right && a[k - 1] <= a[k]);
+            } else if (a[k] > a[k + 1]) { // descending
+                while (++k <= right && a[k - 1] >= a[k]);
+                for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) {
+                    double t = a[lo]; a[lo] = a[hi]; a[hi] = t;
+                }
+            } else { // equal
+                for (int m = MAX_RUN_LENGTH; ++k <= right && a[k - 1] == a[k]; ) {
+                    if (--m == 0) {
+                        sort(a, left, right, true);
+                        return;
+                    }
+                }
+            }
+
+            /*
+             * The array is not highly structured,
+             * use Quicksort instead of merge sort.
+             */
+            if (++count == MAX_RUN_COUNT) {
+                sort(a, left, right, true);
+                return;
+            }
+        }
+
+        // Check special cases
+        // Implementation note: variable "right" is increased by 1.
+        if (run[count] == right++) { // The last run contains one element
+            run[++count] = right;
+        } else if (count == 1) { // The array is already sorted
+            return;
+        }
+
+        // Determine alternation base for merge
+        byte odd = 0;
+        for (int n = 1; (n <<= 1) < count; odd ^= 1);
+
+        // Use or create temporary array b for merging
+        double[] b;                 // temp array; alternates with a
+        int ao, bo;              // array offsets from 'left'
+        int blen = right - left; // space needed for b
+        if (work == null || workLen < blen || workBase + blen > work.length) {
+            work = new double[blen];
+            workBase = 0;
+        }
+        if (odd == 0) {
+            System.arraycopy(a, left, work, workBase, blen);
+            b = a;
+            bo = 0;
+            a = work;
+            ao = workBase - left;
+        } else {
+            b = work;
+            ao = 0;
+            bo = workBase - left;
+        }
+
+        // Merging
+        for (int last; count > 1; count = last) {
+            for (int k = (last = 0) + 2; k <= count; k += 2) {
+                int hi = run[k], mi = run[k - 1];
+                for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) {
+                    if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) {
+                        b[i + bo] = a[p++ + ao];
+                    } else {
+                        b[i + bo] = a[q++ + ao];
+                    }
+                }
+                run[++last] = hi;
+            }
+            if ((count & 1) != 0) {
+                for (int i = right, lo = run[count - 1]; --i >= lo;
+                    b[i + bo] = a[i + ao]
+                );
+                run[++last] = right;
+            }
+            double[] t = a; a = b; b = t;
+            int o = ao; ao = bo; bo = o;
+        }
+    }
+
+    /**
+     * Sorts the specified range of the array by Dual-Pivot Quicksort.
+     *
+     * @param a the array to be sorted
+     * @param left the index of the first element, inclusive, to be sorted
+     * @param right the index of the last element, inclusive, to be sorted
+     * @param leftmost indicates if this part is the leftmost in the range
+     */
+    private static void sort(double[] a, int left, int right, boolean leftmost) {
+        int length = right - left + 1;
+
+        // Use insertion sort on tiny arrays
+        if (length < INSERTION_SORT_THRESHOLD) {
+            if (leftmost) {
+                /*
+                 * Traditional (without sentinel) insertion sort,
+                 * optimized for server VM, is used in case of
+                 * the leftmost part.
+                 */
+                for (int i = left, j = i; i < right; j = ++i) {
+                    double ai = a[i + 1];
+                    while (ai < a[j]) {
+                        a[j + 1] = a[j];
+                        if (j-- == left) {
+                            break;
+                        }
+                    }
+                    a[j + 1] = ai;
+                }
+            } else {
+                /*
+                 * Skip the longest ascending sequence.
+                 */
+                do {
+                    if (left >= right) {
+                        return;
+                    }
+                } while (a[++left] >= a[left - 1]);
+
+                /*
+                 * Every element from adjoining part plays the role
+                 * of sentinel, therefore this allows us to avoid the
+                 * left range check on each iteration. Moreover, we use
+                 * the more optimized algorithm, so called pair insertion
+                 * sort, which is faster (in the context of Quicksort)
+                 * than traditional implementation of insertion sort.
+                 */
+                for (int k = left; ++left <= right; k = ++left) {
+                    double a1 = a[k], a2 = a[left];
+
+                    if (a1 < a2) {
+                        a2 = a1; a1 = a[left];
+                    }
+                    while (a1 < a[--k]) {
+                        a[k + 2] = a[k];
+                    }
+                    a[++k + 1] = a1;
+
+                    while (a2 < a[--k]) {
+                        a[k + 1] = a[k];
+                    }
+                    a[k + 1] = a2;
+                }
+                double last = a[right];
+
+                while (last < a[--right]) {
+                    a[right + 1] = a[right];
+                }
+                a[right + 1] = last;
+            }
+            return;
+        }
+
+        // Inexpensive approximation of length / 7
+        int seventh = (length >> 3) + (length >> 6) + 1;
+
+        /*
+         * Sort five evenly spaced elements around (and including) the
+         * center element in the range. These elements will be used for
+         * pivot selection as described below. The choice for spacing
+         * these elements was empirically determined to work well on
+         * a wide variety of inputs.
+         */
+        int e3 = (left + right) >>> 1; // The midpoint
+        int e2 = e3 - seventh;
+        int e1 = e2 - seventh;
+        int e4 = e3 + seventh;
+        int e5 = e4 + seventh;
+
+        // Sort these elements using insertion sort
+        if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+
+        if (a[e3] < a[e2]) { double t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+            if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+        }
+        if (a[e4] < a[e3]) { double t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+            if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+            }
+        }
+        if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+            if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+                if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+                    if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+                }
+            }
+        }
+
+        // Pointers
+        int less  = left;  // The index of the first element of center part
+        int great = right; // The index before the first element of right part
+
+        if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) {
+            /*
+             * Use the second and fourth of the five sorted elements as pivots.
+             * These values are inexpensive approximations of the first and
+             * second terciles of the array. Note that pivot1 <= pivot2.
+             */
+            double pivot1 = a[e2];
+            double pivot2 = a[e4];
+
+            /*
+             * The first and the last elements to be sorted are moved to the
+             * locations formerly occupied by the pivots. When partitioning
+             * is complete, the pivots are swapped back into their final
+             * positions, and excluded from subsequent sorting.
+             */
+            a[e2] = a[left];
+            a[e4] = a[right];
+
+            /*
+             * Skip elements, which are less or greater than pivot values.
+             */
+            while (a[++less] < pivot1);
+            while (a[--great] > pivot2);
+
+            /*
+             * Partitioning:
+             *
+             *   left part           center part                   right part
+             * +--------------------------------------------------------------+
+             * |  < pivot1  |  pivot1 <= && <= pivot2  |    ?    |  > pivot2  |
+             * +--------------------------------------------------------------+
+             *               ^                          ^       ^
+             *               |                          |       |
+             *              less                        k     great
+             *
+             * Invariants:
+             *
+             *              all in (left, less)   < pivot1
+             *    pivot1 <= all in [less, k)     <= pivot2
+             *              all in (great, right) > pivot2
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            outer:
+            for (int k = less - 1; ++k <= great; ) {
+                double ak = a[k];
+                if (ak < pivot1) { // Move a[k] to left part
+                    a[k] = a[less];
+                    /*
+                     * Here and below we use "a[i] = b; i++;" instead
+                     * of "a[i++] = b;" due to performance issue.
+                     */
+                    a[less] = ak;
+                    ++less;
+                } else if (ak > pivot2) { // Move a[k] to right part
+                    while (a[great] > pivot2) {
+                        if (great-- == k) {
+                            break outer;
+                        }
+                    }
+                    if (a[great] < pivot1) { // a[great] <= pivot2
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // pivot1 <= a[great] <= pivot2
+                        a[k] = a[great];
+                    }
+                    /*
+                     * Here and below we use "a[i] = b; i--;" instead
+                     * of "a[i--] = b;" due to performance issue.
+                     */
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            // Swap pivots into their final positions
+            a[left]  = a[less  - 1]; a[less  - 1] = pivot1;
+            a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+            // Sort left and right parts recursively, excluding known pivots
+            sort(a, left, less - 2, leftmost);
+            sort(a, great + 2, right, false);
+
+            /*
+             * If center part is too large (comprises > 4/7 of the array),
+             * swap internal pivot values to ends.
+             */
+            if (less < e1 && e5 < great) {
+                /*
+                 * Skip elements, which are equal to pivot values.
+                 */
+                while (a[less] == pivot1) {
+                    ++less;
+                }
+
+                while (a[great] == pivot2) {
+                    --great;
+                }
+
+                /*
+                 * Partitioning:
+                 *
+                 *   left part         center part                  right part
+                 * +----------------------------------------------------------+
+                 * | == pivot1 |  pivot1 < && < pivot2  |    ?    | == pivot2 |
+                 * +----------------------------------------------------------+
+                 *              ^                        ^       ^
+                 *              |                        |       |
+                 *             less                      k     great
+                 *
+                 * Invariants:
+                 *
+                 *              all in (*,  less) == pivot1
+                 *     pivot1 < all in [less,  k)  < pivot2
+                 *              all in (great, *) == pivot2
+                 *
+                 * Pointer k is the first index of ?-part.
+                 */
+                outer:
+                for (int k = less - 1; ++k <= great; ) {
+                    double ak = a[k];
+                    if (ak == pivot1) { // Move a[k] to left part
+                        a[k] = a[less];
+                        a[less] = ak;
+                        ++less;
+                    } else if (ak == pivot2) { // Move a[k] to right part
+                        while (a[great] == pivot2) {
+                            if (great-- == k) {
+                                break outer;
+                            }
+                        }
+                        if (a[great] == pivot1) { // a[great] < pivot2
+                            a[k] = a[less];
+                            /*
+                             * Even though a[great] equals to pivot1, the
+                             * assignment a[less] = pivot1 may be incorrect,
+                             * if a[great] and pivot1 are floating-point zeros
+                             * of different signs. Therefore in float and
+                             * double sorting methods we have to use more
+                             * accurate assignment a[less] = a[great].
+                             */
+                            a[less] = a[great];
+                            ++less;
+                        } else { // pivot1 < a[great] < pivot2
+                            a[k] = a[great];
+                        }
+                        a[great] = ak;
+                        --great;
+                    }
+                }
+            }
+
+            // Sort center part recursively
+            sort(a, less, great, false);
+
+        } else { // Partitioning with one pivot
+            /*
+             * Use the third of the five sorted elements as pivot.
+             * This value is inexpensive approximation of the median.
+             */
+            double pivot = a[e3];
+
+            /*
+             * Partitioning degenerates to the traditional 3-way
+             * (or "Dutch National Flag") schema:
+             *
+             *   left part    center part              right part
+             * +-------------------------------------------------+
+             * |  < pivot  |   == pivot   |     ?    |  > pivot  |
+             * +-------------------------------------------------+
+             *              ^              ^        ^
+             *              |              |        |
+             *             less            k      great
+             *
+             * Invariants:
+             *
+             *   all in (left, less)   < pivot
+             *   all in [less, k)     == pivot
+             *   all in (great, right) > pivot
+             *
+             * Pointer k is the first index of ?-part.
+             */
+            for (int k = less; k <= great; ++k) {
+                if (a[k] == pivot) {
+                    continue;
+                }
+                double ak = a[k];
+                if (ak < pivot) { // Move a[k] to left part
+                    a[k] = a[less];
+                    a[less] = ak;
+                    ++less;
+                } else { // a[k] > pivot - Move a[k] to right part
+                    while (a[great] > pivot) {
+                        --great;
+                    }
+                    if (a[great] < pivot) { // a[great] <= pivot
+                        a[k] = a[less];
+                        a[less] = a[great];
+                        ++less;
+                    } else { // a[great] == pivot
+                        /*
+                         * Even though a[great] equals to pivot, the
+                         * assignment a[k] = pivot may be incorrect,
+                         * if a[great] and pivot are floating-point
+                         * zeros of different signs. Therefore in float
+                         * and double sorting methods we have to use
+                         * more accurate assignment a[k] = a[great].
+                         */
+                        a[k] = a[great];
+                    }
+                    a[great] = ak;
+                    --great;
+                }
+            }
+
+            /*
+             * Sort left and right parts recursively.
+             * All elements from center part are equal
+             * and, therefore, already sorted.
+             */
+            sort(a, left, less - 1, leftmost);
+            sort(a, great + 1, right, false);
+        }
+    }
+}
diff --git a/java/util/DuplicateFormatFlagsException.java b/java/util/DuplicateFormatFlagsException.java
new file mode 100644
index 0000000..0dcdf37
--- /dev/null
+++ b/java/util/DuplicateFormatFlagsException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when duplicate flags are provided in the format
+ * specifier.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class DuplicateFormatFlagsException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 18890531L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain a duplicate flag.
+     */
+    public DuplicateFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains a duplicate flag.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    public String getMessage() {
+        return String.format("Flags = '%s'", flags);
+    }
+}
diff --git a/java/util/EmptyStackException.java b/java/util/EmptyStackException.java
new file mode 100644
index 0000000..1f1e878
--- /dev/null
+++ b/java/util/EmptyStackException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by methods in the <code>Stack</code> class to indicate
+ * that the stack is empty.
+ *
+ * @author  Jonathan Payne
+ * @see     java.util.Stack
+ * @since   JDK1.0
+ */
+public
+class EmptyStackException extends RuntimeException {
+    private static final long serialVersionUID = 5084686378493302095L;
+
+    /**
+     * Constructs a new <code>EmptyStackException</code> with <tt>null</tt>
+     * as its error message string.
+     */
+    public EmptyStackException() {
+    }
+}
diff --git a/java/util/EnumMap.java b/java/util/EnumMap.java
new file mode 100644
index 0000000..cd1c5fe
--- /dev/null
+++ b/java/util/EnumMap.java
@@ -0,0 +1,813 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.Map.Entry;
+
+/**
+ * A specialized {@link Map} implementation for use with enum type keys.  All
+ * of the keys in an enum map must come from a single enum type that is
+ * specified, explicitly or implicitly, when the map is created.  Enum maps
+ * are represented internally as arrays.  This representation is extremely
+ * compact and efficient.
+ *
+ * <p>Enum maps are maintained in the <i>natural order</i> of their keys
+ * (the order in which the enum constants are declared).  This is reflected
+ * in the iterators returned by the collections views ({@link #keySet()},
+ * {@link #entrySet()}, and {@link #values()}).
+ *
+ * <p>Iterators returned by the collection views are <i>weakly consistent</i>:
+ * they will never throw {@link ConcurrentModificationException} and they may
+ * or may not show the effects of any modifications to the map that occur while
+ * the iteration is in progress.
+ *
+ * <p>Null keys are not permitted.  Attempts to insert a null key will
+ * throw {@link NullPointerException}.  Attempts to test for the
+ * presence of a null key or to remove one will, however, function properly.
+ * Null values are permitted.
+
+ * <P>Like most collection implementations <tt>EnumMap</tt> is not
+ * synchronized. If multiple threads access an enum map concurrently, and at
+ * least one of the threads modifies the map, it should be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the enum map.  If no such object exists,
+ * the map should be "wrapped" using the {@link Collections#synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access:
+ *
+ * <pre>
+ *     Map&lt;EnumKey, V&gt; m
+ *         = Collections.synchronizedMap(new EnumMap&lt;EnumKey, V&gt;(...));
+ * </pre>
+ *
+ * <p>Implementation note: All basic operations execute in constant time.
+ * They are likely (though not guaranteed) to be faster than their
+ * {@link HashMap} counterparts.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @see EnumSet
+ * @since 1.5
+ */
+public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
+    implements java.io.Serializable, Cloneable
+{
+    /**
+     * The <tt>Class</tt> object for the enum type of all the keys of this map.
+     *
+     * @serial
+     */
+    private final Class<K> keyType;
+
+    /**
+     * All of the values comprising K.  (Cached for performance.)
+     */
+    private transient K[] keyUniverse;
+
+    /**
+     * Array representation of this map.  The ith element is the value
+     * to which universe[i] is currently mapped, or null if it isn't
+     * mapped to anything, or NULL if it's mapped to null.
+     */
+    private transient Object[] vals;
+
+    /**
+     * The number of mappings in this map.
+     */
+    private transient int size = 0;
+
+    /**
+     * Distinguished non-null value for representing null values.
+     */
+    private static final Object NULL = new Object() {
+        public int hashCode() {
+            return 0;
+        }
+
+        public String toString() {
+            return "java.util.EnumMap.NULL";
+        }
+    };
+
+    private Object maskNull(Object value) {
+        return (value == null ? NULL : value);
+    }
+
+    @SuppressWarnings("unchecked")
+    private V unmaskNull(Object value) {
+        return (V)(value == NULL ? null : value);
+    }
+
+    private static final Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
+
+    /**
+     * Creates an empty enum map with the specified key type.
+     *
+     * @param keyType the class object of the key type for this enum map
+     * @throws NullPointerException if <tt>keyType</tt> is null
+     */
+    public EnumMap(Class<K> keyType) {
+        this.keyType = keyType;
+        keyUniverse = getKeyUniverse(keyType);
+        vals = new Object[keyUniverse.length];
+    }
+
+    /**
+     * Creates an enum map with the same key type as the specified enum
+     * map, initially containing the same mappings (if any).
+     *
+     * @param m the enum map from which to initialize this enum map
+     * @throws NullPointerException if <tt>m</tt> is null
+     */
+    public EnumMap(EnumMap<K, ? extends V> m) {
+        keyType = m.keyType;
+        keyUniverse = m.keyUniverse;
+        vals = m.vals.clone();
+        size = m.size;
+    }
+
+    /**
+     * Creates an enum map initialized from the specified map.  If the
+     * specified map is an <tt>EnumMap</tt> instance, this constructor behaves
+     * identically to {@link #EnumMap(EnumMap)}.  Otherwise, the specified map
+     * must contain at least one mapping (in order to determine the new
+     * enum map's key type).
+     *
+     * @param m the map from which to initialize this enum map
+     * @throws IllegalArgumentException if <tt>m</tt> is not an
+     *     <tt>EnumMap</tt> instance and contains no mappings
+     * @throws NullPointerException if <tt>m</tt> is null
+     */
+    public EnumMap(Map<K, ? extends V> m) {
+        if (m instanceof EnumMap) {
+            EnumMap<K, ? extends V> em = (EnumMap<K, ? extends V>) m;
+            keyType = em.keyType;
+            keyUniverse = em.keyUniverse;
+            vals = em.vals.clone();
+            size = em.size;
+        } else {
+            if (m.isEmpty())
+                throw new IllegalArgumentException("Specified map is empty");
+            keyType = m.keySet().iterator().next().getDeclaringClass();
+            keyUniverse = getKeyUniverse(keyType);
+            vals = new Object[keyUniverse.length];
+            putAll(m);
+        }
+    }
+
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value the value whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to this value
+     */
+    public boolean containsValue(Object value) {
+        value = maskNull(value);
+
+        for (Object val : vals)
+            if (value.equals(val))
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key the key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     *            key
+     */
+    public boolean containsKey(Object key) {
+        return isValidKey(key) && vals[((Enum<?>)key).ordinal()] != null;
+    }
+
+    private boolean containsMapping(Object key, Object value) {
+        return isValidKey(key) &&
+            maskNull(value).equals(vals[((Enum<?>)key).ordinal()]);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key == k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     */
+    public V get(Object key) {
+        return (isValidKey(key) ?
+                unmaskNull(vals[((Enum<?>)key).ordinal()]) : null);
+    }
+
+    // Modification Operations
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key the key with which the specified value is to be associated
+     * @param value the value to be associated with the specified key
+     *
+     * @return the previous value associated with specified key, or
+     *     <tt>null</tt> if there was no mapping for key.  (A <tt>null</tt>
+     *     return can also indicate that the map previously associated
+     *     <tt>null</tt> with the specified key.)
+     * @throws NullPointerException if the specified key is null
+     */
+    public V put(K key, V value) {
+        typeCheck(key);
+
+        int index = key.ordinal();
+        Object oldValue = vals[index];
+        vals[index] = maskNull(value);
+        if (oldValue == null)
+            size++;
+        return unmaskNull(oldValue);
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key the key whose mapping is to be removed from the map
+     * @return the previous value associated with specified key, or
+     *     <tt>null</tt> if there was no entry for key.  (A <tt>null</tt>
+     *     return can also indicate that the map previously associated
+     *     <tt>null</tt> with the specified key.)
+     */
+    public V remove(Object key) {
+        if (!isValidKey(key))
+            return null;
+        int index = ((Enum<?>)key).ordinal();
+        Object oldValue = vals[index];
+        vals[index] = null;
+        if (oldValue != null)
+            size--;
+        return unmaskNull(oldValue);
+    }
+
+    private boolean removeMapping(Object key, Object value) {
+        if (!isValidKey(key))
+            return false;
+        int index = ((Enum<?>)key).ordinal();
+        if (maskNull(value).equals(vals[index])) {
+            vals[index] = null;
+            size--;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if key is of the proper type to be a key in this
+     * enum map.
+     */
+    private boolean isValidKey(Object key) {
+        if (key == null)
+            return false;
+
+        // Cheaper than instanceof Enum followed by getDeclaringClass
+        Class<?> keyClass = key.getClass();
+        return keyClass == keyType || keyClass.getSuperclass() == keyType;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m the mappings to be stored in this map
+     * @throws NullPointerException the specified map is null, or if
+     *     one or more keys in the specified map are null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        if (m instanceof EnumMap) {
+            EnumMap<?, ?> em = (EnumMap<?, ?>)m;
+            if (em.keyType != keyType) {
+                if (em.isEmpty())
+                    return;
+                throw new ClassCastException(em.keyType + " != " + keyType);
+            }
+
+            for (int i = 0; i < keyUniverse.length; i++) {
+                Object emValue = em.vals[i];
+                if (emValue != null) {
+                    if (vals[i] == null)
+                        size++;
+                    vals[i] = emValue;
+                }
+            }
+        } else {
+            super.putAll(m);
+        }
+    }
+
+    /**
+     * Removes all mappings from this map.
+     */
+    public void clear() {
+        Arrays.fill(vals, null);
+        size = 0;
+    }
+
+    // Views
+
+    /**
+     * This field is initialized to contain an instance of the entry set
+     * view the first time this view is requested.  The view is stateless,
+     * so there's no reason to create more than one.
+     */
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The returned set obeys the general contract outlined in
+     * {@link Map#keySet()}.  The set's iterator will return the keys
+     * in their natural order (the order in which the enum constants
+     * are declared).
+     *
+     * @return a set view of the keys contained in this enum map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            EnumMap.this.remove(o);
+            return size != oldSize;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The returned collection obeys the general contract outlined in
+     * {@link Map#values()}.  The collection's iterator will return the
+     * values in the order their corresponding keys appear in map,
+     * which is their natural order (the order in which the enum constants
+     * are declared).
+     *
+     * @return a collection view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public boolean remove(Object o) {
+            o = maskNull(o);
+
+            for (int i = 0; i < vals.length; i++) {
+                if (o.equals(vals[i])) {
+                    vals[i] = null;
+                    size--;
+                    return true;
+                }
+            }
+            return false;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The returned set obeys the general contract outlined in
+     * {@link Map#keySet()}.  The set's iterator will return the
+     * mappings in the order their keys appear in map, which is their
+     * natural order (the order in which the enum constants are declared).
+     *
+     * @return a set view of the mappings contained in this enum map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        if (es != null)
+            return es;
+        else
+            return entrySet = new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return containsMapping(entry.getKey(), entry.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return removeMapping(entry.getKey(), entry.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public void clear() {
+            EnumMap.this.clear();
+        }
+        public Object[] toArray() {
+            return fillEntryArray(new Object[size]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int size = size();
+            if (a.length < size)
+                a = (T[])java.lang.reflect.Array
+                    .newInstance(a.getClass().getComponentType(), size);
+            if (a.length > size)
+                a[size] = null;
+            return (T[]) fillEntryArray(a);
+        }
+        private Object[] fillEntryArray(Object[] a) {
+            int j = 0;
+            for (int i = 0; i < vals.length; i++)
+                if (vals[i] != null)
+                    a[j++] = new AbstractMap.SimpleEntry<>(
+                        keyUniverse[i], unmaskNull(vals[i]));
+            return a;
+        }
+    }
+
+    private abstract class EnumMapIterator<T> implements Iterator<T> {
+        // Lower bound on index of next element to return
+        int index = 0;
+
+        // Index of last returned element, or -1 if none
+        int lastReturnedIndex = -1;
+
+        public boolean hasNext() {
+            while (index < vals.length && vals[index] == null)
+                index++;
+            return index != vals.length;
+        }
+
+        public void remove() {
+            checkLastReturnedIndex();
+
+            if (vals[lastReturnedIndex] != null) {
+                vals[lastReturnedIndex] = null;
+                size--;
+            }
+            lastReturnedIndex = -1;
+        }
+
+        private void checkLastReturnedIndex() {
+            if (lastReturnedIndex < 0)
+                throw new IllegalStateException();
+        }
+    }
+
+    private class KeyIterator extends EnumMapIterator<K> {
+        public K next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedIndex = index++;
+            return keyUniverse[lastReturnedIndex];
+        }
+    }
+
+    private class ValueIterator extends EnumMapIterator<V> {
+        public V next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedIndex = index++;
+            return unmaskNull(vals[lastReturnedIndex]);
+        }
+    }
+
+    private class EntryIterator extends EnumMapIterator<Map.Entry<K,V>> {
+        private Entry lastReturnedEntry;
+
+        public Map.Entry<K,V> next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturnedEntry = new Entry(index++);
+            return lastReturnedEntry;
+        }
+
+        public void remove() {
+            lastReturnedIndex =
+                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+            super.remove();
+            lastReturnedEntry.index = lastReturnedIndex;
+            lastReturnedEntry = null;
+        }
+
+        private class Entry implements Map.Entry<K,V> {
+            private int index;
+
+            private Entry(int index) {
+                this.index = index;
+            }
+
+            public K getKey() {
+                checkIndexForEntryUse();
+                return keyUniverse[index];
+            }
+
+            public V getValue() {
+                checkIndexForEntryUse();
+                return unmaskNull(vals[index]);
+            }
+
+            public V setValue(V value) {
+                checkIndexForEntryUse();
+                V oldValue = unmaskNull(vals[index]);
+                vals[index] = maskNull(value);
+                return oldValue;
+            }
+
+            public boolean equals(Object o) {
+                if (index < 0)
+                    return o == this;
+
+                if (!(o instanceof Map.Entry))
+                    return false;
+
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                V ourValue = unmaskNull(vals[index]);
+                Object hisValue = e.getValue();
+                return (e.getKey() == keyUniverse[index] &&
+                        (ourValue == hisValue ||
+                         (ourValue != null && ourValue.equals(hisValue))));
+            }
+
+            public int hashCode() {
+                if (index < 0)
+                    return super.hashCode();
+
+                return entryHashCode(index);
+            }
+
+            public String toString() {
+                if (index < 0)
+                    return super.toString();
+
+                return keyUniverse[index] + "="
+                    + unmaskNull(vals[index]);
+            }
+
+            private void checkIndexForEntryUse() {
+                if (index < 0)
+                    throw new IllegalStateException("Entry was removed");
+            }
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * <tt>true</tt> if the given object is also a map and the two maps
+     * represent the same mappings, as specified in the {@link
+     * Map#equals(Object)} contract.
+     *
+     * @param o the object to be compared for equality with this map
+     * @return <tt>true</tt> if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o instanceof EnumMap)
+            return equals((EnumMap<?,?>)o);
+        if (!(o instanceof Map))
+            return false;
+
+        Map<?,?> m = (Map<?,?>)o;
+        if (size != m.size())
+            return false;
+
+        for (int i = 0; i < keyUniverse.length; i++) {
+            if (null != vals[i]) {
+                K key = keyUniverse[i];
+                V value = unmaskNull(vals[i]);
+                if (null == value) {
+                    if (!((null == m.get(key)) && m.containsKey(key)))
+                       return false;
+                } else {
+                   if (!value.equals(m.get(key)))
+                      return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
+    private boolean equals(EnumMap<?,?> em) {
+        if (em.keyType != keyType)
+            return size == 0 && em.size == 0;
+
+        // Key types match, compare each value
+        for (int i = 0; i < keyUniverse.length; i++) {
+            Object ourValue =    vals[i];
+            Object hisValue = em.vals[i];
+            if (hisValue != ourValue &&
+                (hisValue == null || !hisValue.equals(ourValue)))
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map.
+     */
+    public int hashCode() {
+        int h = 0;
+
+        for (int i = 0; i < keyUniverse.length; i++) {
+            if (null != vals[i]) {
+                h += entryHashCode(i);
+            }
+        }
+
+        return h;
+    }
+
+    private int entryHashCode(int index) {
+        return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
+    }
+
+    /**
+     * Returns a shallow copy of this enum map.  (The values themselves
+     * are not cloned.
+     *
+     * @return a shallow copy of this enum map
+     */
+    @SuppressWarnings("unchecked")
+    public EnumMap<K, V> clone() {
+        EnumMap<K, V> result = null;
+        try {
+            result = (EnumMap<K, V>) super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+        result.vals = result.vals.clone();
+        result.entrySet = null;
+        return result;
+    }
+
+    /**
+     * Throws an exception if e is not of the correct type for this enum set.
+     */
+    private void typeCheck(K key) {
+        Class<?> keyClass = key.getClass();
+        if (keyClass != keyType && keyClass.getSuperclass() != keyType)
+            throw new ClassCastException(keyClass + " != " + keyType);
+    }
+
+    /**
+     * Returns all of the values comprising K.
+     * The result is uncloned, cached, and shared by all callers.
+     */
+    private static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return keyType.getEnumConstantsShared();
+    }
+
+    private static final long serialVersionUID = 458661240069192865L;
+
+    /**
+     * Save the state of the <tt>EnumMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>size</i> of the enum map (the number of key-value
+     *             mappings) is emitted (int), followed by the key (Object)
+     *             and value (Object) for each key-value mapping represented
+     *             by the enum map.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException
+    {
+        // Write out the key type and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        int entriesToBeWritten = size;
+        for (int i = 0; entriesToBeWritten > 0; i++) {
+            if (null != vals[i]) {
+                s.writeObject(keyUniverse[i]);
+                s.writeObject(unmaskNull(vals[i]));
+                entriesToBeWritten--;
+            }
+        }
+    }
+
+    /**
+     * Reconstitute the <tt>EnumMap</tt> instance from a stream (i.e.,
+     * deserialize it).
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException
+    {
+        // Read in the key type and any hidden stuff
+        s.defaultReadObject();
+
+        keyUniverse = getKeyUniverse(keyType);
+        vals = new Object[keyUniverse.length];
+
+        // Read in size (number of Mappings)
+        int size = s.readInt();
+
+        // Read the keys and values, and put the mappings in the HashMap
+        for (int i = 0; i < size; i++) {
+            K key = (K) s.readObject();
+            V value = (V) s.readObject();
+            put(key, value);
+        }
+    }
+}
diff --git a/java/util/EnumSet.java b/java/util/EnumSet.java
new file mode 100644
index 0000000..95e0124
--- /dev/null
+++ b/java/util/EnumSet.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A specialized {@link Set} implementation for use with enum types.  All of
+ * the elements in an enum set must come from a single enum type that is
+ * specified, explicitly or implicitly, when the set is created.  Enum sets
+ * are represented internally as bit vectors.  This representation is
+ * extremely compact and efficient. The space and time performance of this
+ * class should be good enough to allow its use as a high-quality, typesafe
+ * alternative to traditional <tt>int</tt>-based "bit flags."  Even bulk
+ * operations (such as <tt>containsAll</tt> and <tt>retainAll</tt>) should
+ * run very quickly if their argument is also an enum set.
+ *
+ * <p>The iterator returned by the <tt>iterator</tt> method traverses the
+ * elements in their <i>natural order</i> (the order in which the enum
+ * constants are declared).  The returned iterator is <i>weakly
+ * consistent</i>: it will never throw {@link ConcurrentModificationException}
+ * and it may or may not show the effects of any modifications to the set that
+ * occur while the iteration is in progress.
+ *
+ * <p>Null elements are not permitted.  Attempts to insert a null element
+ * will throw {@link NullPointerException}.  Attempts to test for the
+ * presence of a null element or to remove one will, however, function
+ * properly.
+ *
+ * <P>Like most collection implementations, <tt>EnumSet</tt> is not
+ * synchronized.  If multiple threads access an enum set concurrently, and at
+ * least one of the threads modifies the set, it should be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the enum set.  If no such object exists,
+ * the set should be "wrapped" using the {@link Collections#synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access:
+ *
+ * <pre>
+ * Set&lt;MyEnum&gt; s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
+ * </pre>
+ *
+ * <p>Implementation note: All basic operations execute in constant time.
+ * They are likely (though not guaranteed) to be much faster than their
+ * {@link HashSet} counterparts.  Even bulk operations execute in
+ * constant time if their argument is also an enum set.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @see EnumMap
+ * @serial exclude
+ */
+public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
+    implements Cloneable, java.io.Serializable
+{
+    /**
+     * The class of all the elements of this set.
+     */
+    final Class<E> elementType;
+
+    /**
+     * All of the values comprising T.  (Cached for performance.)
+     */
+    final Enum<?>[] universe;
+
+    private static Enum<?>[] ZERO_LENGTH_ENUM_ARRAY = new Enum<?>[0];
+
+    EnumSet(Class<E>elementType, Enum<?>[] universe) {
+        this.elementType = elementType;
+        this.universe    = universe;
+    }
+
+    /**
+     * Creates an empty enum set with the specified element type.
+     *
+     * @param <E> The class of the elements in the set
+     * @param elementType the class object of the element type for this enum
+     *     set
+     * @return An empty enum set of the specified type.
+     * @throws NullPointerException if <tt>elementType</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
+        Enum<?>[] universe = getUniverse(elementType);
+        if (universe == null)
+            throw new ClassCastException(elementType + " not an enum");
+
+        if (universe.length <= 64)
+            return new RegularEnumSet<>(elementType, universe);
+        else
+            return new JumboEnumSet<>(elementType, universe);
+    }
+
+    /**
+     * Creates an enum set containing all of the elements in the specified
+     * element type.
+     *
+     * @param <E> The class of the elements in the set
+     * @param elementType the class object of the element type for this enum
+     *     set
+     * @return An enum set containing all the elements in the specified type.
+     * @throws NullPointerException if <tt>elementType</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType) {
+        EnumSet<E> result = noneOf(elementType);
+        result.addAll();
+        return result;
+    }
+
+    /**
+     * Adds all of the elements from the appropriate enum type to this enum
+     * set, which is empty prior to the call.
+     */
+    abstract void addAll();
+
+    /**
+     * Creates an enum set with the same element type as the specified enum
+     * set, initially containing the same elements (if any).
+     *
+     * @param <E> The class of the elements in the set
+     * @param s the enum set from which to initialize this enum set
+     * @return A copy of the specified enum set.
+     * @throws NullPointerException if <tt>s</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> copyOf(EnumSet<E> s) {
+        return s.clone();
+    }
+
+    /**
+     * Creates an enum set initialized from the specified collection.  If
+     * the specified collection is an <tt>EnumSet</tt> instance, this static
+     * factory method behaves identically to {@link #copyOf(EnumSet)}.
+     * Otherwise, the specified collection must contain at least one element
+     * (in order to determine the new enum set's element type).
+     *
+     * @param <E> The class of the elements in the collection
+     * @param c the collection from which to initialize this enum set
+     * @return An enum set initialized from the given collection.
+     * @throws IllegalArgumentException if <tt>c</tt> is not an
+     *     <tt>EnumSet</tt> instance and contains no elements
+     * @throws NullPointerException if <tt>c</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> copyOf(Collection<E> c) {
+        if (c instanceof EnumSet) {
+            return ((EnumSet<E>)c).clone();
+        } else {
+            if (c.isEmpty())
+                throw new IllegalArgumentException("Collection is empty");
+            Iterator<E> i = c.iterator();
+            E first = i.next();
+            EnumSet<E> result = EnumSet.of(first);
+            while (i.hasNext())
+                result.add(i.next());
+            return result;
+        }
+    }
+
+    /**
+     * Creates an enum set with the same element type as the specified enum
+     * set, initially containing all the elements of this type that are
+     * <i>not</i> contained in the specified set.
+     *
+     * @param <E> The class of the elements in the enum set
+     * @param s the enum set from whose complement to initialize this enum set
+     * @return The complement of the specified set in this set
+     * @throws NullPointerException if <tt>s</tt> is null
+     */
+    public static <E extends Enum<E>> EnumSet<E> complementOf(EnumSet<E> s) {
+        EnumSet<E> result = copyOf(s);
+        result.complement();
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified element.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the specified element and of the set
+     * @param e the element that this set is to contain initially
+     * @throws NullPointerException if <tt>e</tt> is null
+     * @return an enum set initially containing the specified element
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e) {
+        EnumSet<E> result = noneOf(e.getDeclaringClass());
+        result.add(e);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @param e4 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4) {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        result.add(e4);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     *
+     * Overloadings of this method exist to initialize an enum set with
+     * one through five elements.  A sixth overloading is provided that
+     * uses the varargs feature.  This overloading may be used to create
+     * an enum set initially containing an arbitrary number of elements, but
+     * is likely to run slower than the overloadings that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param e1 an element that this set is to contain initially
+     * @param e2 another element that this set is to contain initially
+     * @param e3 another element that this set is to contain initially
+     * @param e4 another element that this set is to contain initially
+     * @param e5 another element that this set is to contain initially
+     * @throws NullPointerException if any parameters are null
+     * @return an enum set initially containing the specified elements
+     */
+    public static <E extends Enum<E>> EnumSet<E> of(E e1, E e2, E e3, E e4,
+                                                    E e5)
+    {
+        EnumSet<E> result = noneOf(e1.getDeclaringClass());
+        result.add(e1);
+        result.add(e2);
+        result.add(e3);
+        result.add(e4);
+        result.add(e5);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing the specified elements.
+     * This factory, whose parameter list uses the varargs feature, may
+     * be used to create an enum set initially containing an arbitrary
+     * number of elements, but it is likely to run slower than the overloadings
+     * that do not use varargs.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param first an element that the set is to contain initially
+     * @param rest the remaining elements the set is to contain initially
+     * @throws NullPointerException if any of the specified elements are null,
+     *     or if <tt>rest</tt> is null
+     * @return an enum set initially containing the specified elements
+     */
+    @SafeVarargs
+    public static <E extends Enum<E>> EnumSet<E> of(E first, E... rest) {
+        EnumSet<E> result = noneOf(first.getDeclaringClass());
+        result.add(first);
+        for (E e : rest)
+            result.add(e);
+        return result;
+    }
+
+    /**
+     * Creates an enum set initially containing all of the elements in the
+     * range defined by the two specified endpoints.  The returned set will
+     * contain the endpoints themselves, which may be identical but must not
+     * be out of order.
+     *
+     * @param <E> The class of the parameter elements and of the set
+     * @param from the first element in the range
+     * @param to the last element in the range
+     * @throws NullPointerException if {@code from} or {@code to} are null
+     * @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
+     * @return an enum set initially containing all of the elements in the
+     *         range defined by the two specified endpoints
+     */
+    public static <E extends Enum<E>> EnumSet<E> range(E from, E to) {
+        if (from.compareTo(to) > 0)
+            throw new IllegalArgumentException(from + " > " + to);
+        EnumSet<E> result = noneOf(from.getDeclaringClass());
+        result.addRange(from, to);
+        return result;
+    }
+
+    /**
+     * Adds the specified range to this enum set, which is empty prior
+     * to the call.
+     */
+    abstract void addRange(E from, E to);
+
+    /**
+     * Returns a copy of this set.
+     *
+     * @return a copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public EnumSet<E> clone() {
+        try {
+            return (EnumSet<E>) super.clone();
+        } catch(CloneNotSupportedException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Complements the contents of this enum set.
+     */
+    abstract void complement();
+
+    /**
+     * Throws an exception if e is not of the correct type for this enum set.
+     */
+    final void typeCheck(E e) {
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            throw new ClassCastException(eClass + " != " + elementType);
+    }
+
+    /**
+     * Returns all of the values comprising E.
+     * The result is uncloned, cached, and shared by all callers.
+     */
+    private static <E extends Enum<E>> E[] getUniverse(Class<E> elementType) {
+        // Android-changed: Use getEnumConstantsShared directly instead of going
+        // through SharedSecrets.
+        return elementType.getEnumConstantsShared();
+    }
+
+    /**
+     * This class is used to serialize all EnumSet instances, regardless of
+     * implementation type.  It captures their "logical contents" and they
+     * are reconstructed using public static factories.  This is necessary
+     * to ensure that the existence of a particular implementation type is
+     * an implementation detail.
+     *
+     * @serial include
+     */
+    private static class SerializationProxy <E extends Enum<E>>
+        implements java.io.Serializable
+    {
+        /**
+         * The element type of this enum set.
+         *
+         * @serial
+         */
+        private final Class<E> elementType;
+
+        /**
+         * The elements contained in this enum set.
+         *
+         * @serial
+         */
+        private final Enum<?>[] elements;
+
+        SerializationProxy(EnumSet<E> set) {
+            elementType = set.elementType;
+            elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
+        }
+
+        // instead of cast to E, we should perhaps use elementType.cast()
+        // to avoid injection of forged stream, but it will slow the implementation
+        @SuppressWarnings("unchecked")
+        private Object readResolve() {
+            EnumSet<E> result = EnumSet.noneOf(elementType);
+            for (Enum<?> e : elements)
+                result.add((E)e);
+            return result;
+        }
+
+        private static final long serialVersionUID = 362491234563181265L;
+    }
+
+    Object writeReplace() {
+        return new SerializationProxy<>(this);
+    }
+
+    // readObject method for the serialization proxy pattern
+    // See Effective Java, Second Ed., Item 78.
+    private void readObject(java.io.ObjectInputStream stream)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+}
diff --git a/java/util/Enumeration.java b/java/util/Enumeration.java
new file mode 100644
index 0000000..8aebb5c
--- /dev/null
+++ b/java/util/Enumeration.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An object that implements the Enumeration interface generates a
+ * series of elements, one at a time. Successive calls to the
+ * <code>nextElement</code> method return successive elements of the
+ * series.
+ * <p>
+ * For example, to print all elements of a <tt>Vector&lt;E&gt;</tt> <i>v</i>:
+ * <pre>
+ *   for (Enumeration&lt;E&gt; e = v.elements(); e.hasMoreElements();)
+ *       System.out.println(e.nextElement());</pre>
+ * <p>
+ * Methods are provided to enumerate through the elements of a
+ * vector, the keys of a hashtable, and the values in a hashtable.
+ * Enumerations are also used to specify the input streams to a
+ * <code>SequenceInputStream</code>.
+ * <p>
+ * NOTE: The functionality of this interface is duplicated by the Iterator
+ * interface.  In addition, Iterator adds an optional remove operation, and
+ * has shorter method names.  New implementations should consider using
+ * Iterator in preference to Enumeration.
+ *
+ * @see     java.util.Iterator
+ * @see     java.io.SequenceInputStream
+ * @see     java.util.Enumeration#nextElement()
+ * @see     java.util.Hashtable
+ * @see     java.util.Hashtable#elements()
+ * @see     java.util.Hashtable#keys()
+ * @see     java.util.Vector
+ * @see     java.util.Vector#elements()
+ *
+ * @author  Lee Boynton
+ * @since   JDK1.0
+ */
+public interface Enumeration<E> {
+    /**
+     * Tests if this enumeration contains more elements.
+     *
+     * @return  <code>true</code> if and only if this enumeration object
+     *           contains at least one more element to provide;
+     *          <code>false</code> otherwise.
+     */
+    boolean hasMoreElements();
+
+    /**
+     * Returns the next element of this enumeration if this enumeration
+     * object has at least one more element to provide.
+     *
+     * @return     the next element of this enumeration.
+     * @exception  NoSuchElementException  if no more elements exist.
+     */
+    E nextElement();
+}
diff --git a/java/util/EventListener.java b/java/util/EventListener.java
new file mode 100644
index 0000000..1daf446
--- /dev/null
+++ b/java/util/EventListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A tagging interface that all event listener interfaces must extend.
+ * @since JDK1.1
+ */
+public interface EventListener {
+}
diff --git a/java/util/EventListenerProxy.java b/java/util/EventListenerProxy.java
new file mode 100644
index 0000000..c982367
--- /dev/null
+++ b/java/util/EventListenerProxy.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An abstract wrapper class for an {@code EventListener} class
+ * which associates a set of additional parameters with the listener.
+ * Subclasses must provide the storage and accessor methods
+ * for the additional arguments or parameters.
+ * <p>
+ * For example, a bean which supports named properties
+ * would have a two argument method signature for adding
+ * a {@code PropertyChangeListener} for a property:
+ * <pre>
+ * public void addPropertyChangeListener(String propertyName,
+ *                                       PropertyChangeListener listener)
+ * </pre>
+ * If the bean also implemented the zero argument get listener method:
+ * <pre>
+ * public PropertyChangeListener[] getPropertyChangeListeners()
+ * </pre>
+ * then the array may contain inner {@code PropertyChangeListeners}
+ * which are also {@code PropertyChangeListenerProxy} objects.
+ * <p>
+ * If the calling method is interested in retrieving the named property
+ * then it would have to test the element to see if it is a proxy class.
+ *
+ * @since 1.4
+ */
+public abstract class EventListenerProxy<T extends EventListener>
+        implements EventListener {
+
+    private final T listener;
+
+    /**
+     * Creates a proxy for the specified listener.
+     *
+     * @param listener  the listener object
+     */
+    public EventListenerProxy(T listener) {
+        this.listener = listener;
+    }
+
+    /**
+     * Returns the listener associated with the proxy.
+     *
+     * @return  the listener associated with the proxy
+     */
+    public T getListener() {
+        return this.listener;
+    }
+}
diff --git a/java/util/EventObject.java b/java/util/EventObject.java
new file mode 100644
index 0000000..3bccae1
--- /dev/null
+++ b/java/util/EventObject.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>
+ * The root class from which all event state objects shall be derived.
+ * <p>
+ * All Events are constructed with a reference to the object, the "source",
+ * that is logically deemed to be the object upon which the Event in question
+ * initially occurred upon.
+ *
+ * @since JDK1.1
+ */
+
+public class EventObject implements java.io.Serializable {
+
+    private static final long serialVersionUID = 5516075349620653480L;
+
+    /**
+     * The object on which the Event initially occurred.
+     */
+    protected transient Object  source;
+
+    /**
+     * Constructs a prototypical Event.
+     *
+     * @param    source    The object on which the Event initially occurred.
+     * @exception  IllegalArgumentException  if source is null.
+     */
+    public EventObject(Object source) {
+        if (source == null)
+            throw new IllegalArgumentException("null source");
+
+        this.source = source;
+    }
+
+    /**
+     * The object on which the Event initially occurred.
+     *
+     * @return   The object on which the Event initially occurred.
+     */
+    public Object getSource() {
+        return source;
+    }
+
+    /**
+     * Returns a String representation of this EventObject.
+     *
+     * @return  A a String representation of this EventObject.
+     */
+    public String toString() {
+        return getClass().getName() + "[source=" + source + "]";
+    }
+}
diff --git a/java/util/FormatFlagsConversionMismatchException.java b/java/util/FormatFlagsConversionMismatchException.java
new file mode 100644
index 0000000..58f593e
--- /dev/null
+++ b/java/util/FormatFlagsConversionMismatchException.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a conversion and flag are incompatible.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class FormatFlagsConversionMismatchException
+    extends IllegalFormatException
+{
+    private static final long serialVersionUID = 19120414L;
+
+    private String f;
+
+    private char c;
+
+    /**
+     * Constructs an instance of this class with the specified flag
+     * and conversion.
+     *
+     * @param  f
+     *         The flag
+     *
+     * @param  c
+     *         The conversion
+     */
+    public FormatFlagsConversionMismatchException(String f, char c) {
+        if (f == null)
+            throw new NullPointerException();
+        this.f = f;
+        this.c = c;
+    }
+
+    /**
+     * Returns the incompatible flag.
+     *
+     * @return  The flag
+     */
+     public String getFlags() {
+        return f;
+    }
+
+    /**
+     * Returns the incompatible conversion.
+     *
+     * @return  The conversion
+     */
+    public char getConversion() {
+        return c;
+    }
+
+    public String getMessage() {
+        return "Conversion = " + c + ", Flags = " + f;
+    }
+}
diff --git a/java/util/Formattable.java b/java/util/Formattable.java
new file mode 100644
index 0000000..f7e1e50
--- /dev/null
+++ b/java/util/Formattable.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+
+/**
+ * The <tt>Formattable</tt> interface must be implemented by any class that
+ * needs to perform custom formatting using the <tt>'s'</tt> conversion
+ * specifier of {@link java.util.Formatter}.  This interface allows basic
+ * control for formatting arbitrary objects.
+ *
+ * For example, the following class prints out different representations of a
+ * stock's name depending on the flags and length constraints:
+ *
+ * {@code
+ *   import java.nio.CharBuffer;
+ *   import java.util.Formatter;
+ *   import java.util.Formattable;
+ *   import java.util.Locale;
+ *   import static java.util.FormattableFlags.*;
+ *
+ *  ...
+ *
+ *   public class StockName implements Formattable {
+ *       private String symbol, companyName, frenchCompanyName;
+ *       public StockName(String symbol, String companyName,
+ *                        String frenchCompanyName) {
+ *           ...
+ *       }
+ *
+ *       ...
+ *
+ *       public void formatTo(Formatter fmt, int f, int width, int precision) {
+ *           StringBuilder sb = new StringBuilder();
+ *
+ *           // decide form of name
+ *           String name = companyName;
+ *           if (fmt.locale().equals(Locale.FRANCE))
+ *               name = frenchCompanyName;
+ *           boolean alternate = (f & ALTERNATE) == ALTERNATE;
+ *           boolean usesymbol = alternate || (precision != -1 && precision < 10);
+ *           String out = (usesymbol ? symbol : name);
+ *
+ *           // apply precision
+ *           if (precision == -1 || out.length() < precision) {
+ *               // write it all
+ *               sb.append(out);
+ *           } else {
+ *               sb.append(out.substring(0, precision - 1)).append('*');
+ *           }
+ *
+ *           // apply width and justification
+ *           int len = sb.length();
+ *           if (len < width)
+ *               for (int i = 0; i < width - len; i++)
+ *                   if ((f & LEFT_JUSTIFY) == LEFT_JUSTIFY)
+ *                       sb.append(' ');
+ *                   else
+ *                       sb.insert(0, ' ');
+ *
+ *           fmt.format(sb.toString());
+ *       }
+ *
+ *       public String toString() {
+ *           return String.format("%s - %s", symbol, companyName);
+ *       }
+ *   }
+ * }
+ *
+ * <p> When used in conjunction with the {@link java.util.Formatter}, the above
+ * class produces the following output for various format strings.
+ *
+ * {@code
+ *   Formatter fmt = new Formatter();
+ *   StockName sn = new StockName("HUGE", "Huge Fruit, Inc.",
+ *                                "Fruit Titanesque, Inc.");
+ *   fmt.format("%s", sn);                   //   -> "Huge Fruit, Inc."
+ *   fmt.format("%s", sn.toString());        //   -> "HUGE - Huge Fruit, Inc."
+ *   fmt.format("%#s", sn);                  //   -> "HUGE"
+ *   fmt.format("%-10.8s", sn);              //   -> "HUGE      "
+ *   fmt.format("%.12s", sn);                //   -> "Huge Fruit,*"
+ *   fmt.format(Locale.FRANCE, "%25s", sn);  //   -> "   Fruit Titanesque, Inc."
+ * }
+ *
+ * <p> Formattables are not necessarily safe for multithreaded access.  Thread
+ * safety is optional and may be enforced by classes that extend and implement
+ * this interface.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to
+ * any method in this interface will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since  1.5
+ */
+public interface Formattable {
+
+    /**
+     * Formats the object using the provided {@link Formatter formatter}.
+     *
+     * @param  formatter
+     *         The {@link Formatter formatter}.  Implementing classes may call
+     *         {@link Formatter#out() formatter.out()} or {@link
+     *         Formatter#locale() formatter.locale()} to obtain the {@link
+     *         Appendable} or {@link Locale} used by this
+     *         <tt>formatter</tt> respectively.
+     *
+     * @param  flags
+     *         The flags modify the output format.  The value is interpreted as
+     *         a bitmask.  Any combination of the following flags may be set:
+     *         {@link FormattableFlags#LEFT_JUSTIFY}, {@link
+     *         FormattableFlags#UPPERCASE}, and {@link
+     *         FormattableFlags#ALTERNATE}.  If no flags are set, the default
+     *         formatting of the implementing class will apply.
+     *
+     * @param  width
+     *         The minimum number of characters to be written to the output.
+     *         If the length of the converted value is less than the
+     *         <tt>width</tt> then the output will be padded by
+     *         <tt>'&nbsp;&nbsp;'</tt> until the total number of characters
+     *         equals width.  The padding is at the beginning by default.  If
+     *         the {@link FormattableFlags#LEFT_JUSTIFY} flag is set then the
+     *         padding will be at the end.  If <tt>width</tt> is <tt>-1</tt>
+     *         then there is no minimum.
+     *
+     * @param  precision
+     *         The maximum number of characters to be written to the output.
+     *         The precision is applied before the width, thus the output will
+     *         be truncated to <tt>precision</tt> characters even if the
+     *         <tt>width</tt> is greater than the <tt>precision</tt>.  If
+     *         <tt>precision</tt> is <tt>-1</tt> then there is no explicit
+     *         limit on the number of characters.
+     *
+     * @throws  IllegalFormatException
+     *          If any of the parameters are invalid.  For specification of all
+     *          possible formatting errors, see the <a
+     *          href="../util/Formatter.html#detail">Details</a> section of the
+     *          formatter class specification.
+     */
+    void formatTo(Formatter formatter, int flags, int width, int precision);
+}
diff --git a/java/util/FormattableFlags.java b/java/util/FormattableFlags.java
new file mode 100644
index 0000000..11a10dd
--- /dev/null
+++ b/java/util/FormattableFlags.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * FomattableFlags are passed to the {@link Formattable#formatTo
+ * Formattable.formatTo()} method and modify the output format for {@linkplain
+ * Formattable Formattables}.  Implementations of {@link Formattable} are
+ * responsible for interpreting and validating any flags.
+ *
+ * @since  1.5
+ */
+public class FormattableFlags {
+
+    // Explicit instantiation of this class is prohibited.
+    private FormattableFlags() {}
+
+    /**
+     * Left-justifies the output.  Spaces (<tt>'&#92;u0020'</tt>) will be added
+     * at the end of the converted value as required to fill the minimum width
+     * of the field.  If this flag is not set then the output will be
+     * right-justified.
+     *
+     * <p> This flag corresponds to <tt>'-'</tt> (<tt>'&#92;u002d'</tt>) in
+     * the format specifier.
+     */
+    public static final int LEFT_JUSTIFY = 1<<0; // '-'
+
+    /**
+     * Converts the output to upper case according to the rules of the
+     * {@linkplain java.util.Locale locale} given during creation of the
+     * <tt>formatter</tt> argument of the {@link Formattable#formatTo
+     * formatTo()} method.  The output should be equivalent the following
+     * invocation of {@link String#toUpperCase(java.util.Locale)}
+     *
+     * <pre>
+     *     out.toUpperCase() </pre>
+     *
+     * <p> This flag corresponds to <tt>'S'</tt> (<tt>'&#92;u0053'</tt>) in
+     * the format specifier.
+     */
+    public static final int UPPERCASE = 1<<1;    // 'S'
+
+    /**
+     * Requires the output to use an alternate form.  The definition of the
+     * form is specified by the <tt>Formattable</tt>.
+     *
+     * <p> This flag corresponds to <tt>'#'</tt> (<tt>'&#92;u0023'</tt>) in
+     * the format specifier.
+     */
+    public static final int ALTERNATE = 1<<2;    // '#'
+}
diff --git a/java/util/Formatter.java b/java/util/Formatter.java
new file mode 100644
index 0000000..0b0c095
--- /dev/null
+++ b/java/util/Formatter.java
@@ -0,0 +1,4808 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.Flushable;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+import java.text.DateFormatSymbols;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.time.DateTimeException;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoField;
+import java.time.temporal.TemporalAccessor;
+import java.time.temporal.TemporalQueries;
+
+import libcore.icu.LocaleData;
+import sun.misc.FpUtils;
+import sun.misc.DoubleConsts;
+import sun.misc.FormattedFloatingDecimal;
+
+// Android-changed: Use localized exponent separator for %e.
+/**
+ * An interpreter for printf-style format strings.  This class provides support
+ * for layout justification and alignment, common formats for numeric, string,
+ * and date/time data, and locale-specific output.  Common Java types such as
+ * {@code byte}, {@link java.math.BigDecimal BigDecimal}, and {@link Calendar}
+ * are supported.  Limited formatting customization for arbitrary user types is
+ * provided through the {@link Formattable} interface.
+ *
+ * <p> Formatters are not necessarily safe for multithreaded access.  Thread
+ * safety is optional and is the responsibility of users of methods in this
+ * class.
+ *
+ * <p> Formatted printing for the Java language is heavily inspired by C's
+ * {@code printf}.  Although the format strings are similar to C, some
+ * customizations have been made to accommodate the Java language and exploit
+ * some of its features.  Also, Java formatting is more strict than C's; for
+ * example, if a conversion is incompatible with a flag, an exception will be
+ * thrown.  In C inapplicable flags are silently ignored.  The format strings
+ * are thus intended to be recognizable to C programmers but not necessarily
+ * completely compatible with those in C.
+ *
+ * <p> Examples of expected usage:
+ *
+ * <blockquote><pre>
+ *   StringBuilder sb = new StringBuilder();
+ *   // Send all output to the Appendable object sb
+ *   Formatter formatter = new Formatter(sb, Locale.US);
+ *
+ *   // Explicit argument indices may be used to re-order output.
+ *   formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
+ *   // -&gt; " d  c  b  a"
+ *
+ *   // Optional locale as the first argument can be used to get
+ *   // locale-specific formatting of numbers.  The precision and width can be
+ *   // given to round and align the value.
+ *   formatter.format(Locale.FRANCE, "e = %+10.4f", Math.E);
+ *   // -&gt; "e =    +2,7183"
+ *
+ *   // The '(' numeric flag may be used to format negative numbers with
+ *   // parentheses rather than a minus sign.  Group separators are
+ *   // automatically inserted.
+ *   formatter.format("Amount gained or lost since last statement: $ %(,.2f",
+ *                    balanceDelta);
+ *   // -&gt; "Amount gained or lost since last statement: $ (6,217.58)"
+ * </pre></blockquote>
+ *
+ * <p> Convenience methods for common formatting requests exist as illustrated
+ * by the following invocations:
+ *
+ * <blockquote><pre>
+ *   // Writes a formatted string to System.out.
+ *   System.out.format("Local time: %tT", Calendar.getInstance());
+ *   // -&gt; "Local time: 13:34:18"
+ *
+ *   // Writes formatted output to System.err.
+ *   System.err.printf("Unable to open file '%1$s': %2$s",
+ *                     fileName, exception.getMessage());
+ *   // -&gt; "Unable to open file 'food': No such file or directory"
+ * </pre></blockquote>
+ *
+ * <p> Like C's {@code sprintf(3)}, Strings may be formatted using the static
+ * method {@link String#format(String,Object...) String.format}:
+ *
+ * <blockquote><pre>
+ *   // Format a string containing a date.
+ *   import java.util.Calendar;
+ *   import java.util.GregorianCalendar;
+ *   import static java.util.Calendar.*;
+ *
+ *   Calendar c = new GregorianCalendar(1995, MAY, 23);
+ *   String s = String.format("Duke's Birthday: %1$tb %1$te, %1$tY", c);
+ *   // -&gt; s == "Duke's Birthday: May 23, 1995"
+ * </pre></blockquote>
+ *
+ * <h3><a name="org">Organization</a></h3>
+ *
+ * <p> This specification is divided into two sections.  The first section, <a
+ * href="#summary">Summary</a>, covers the basic formatting concepts.  This
+ * section is intended for users who want to get started quickly and are
+ * familiar with formatted printing in other programming languages.  The second
+ * section, <a href="#detail">Details</a>, covers the specific implementation
+ * details.  It is intended for users who want more precise specification of
+ * formatting behavior.
+ *
+ * <h3><a name="summary">Summary</a></h3>
+ *
+ * <p> This section is intended to provide a brief overview of formatting
+ * concepts.  For precise behavioral details, refer to the <a
+ * href="#detail">Details</a> section.
+ *
+ * <h4><a name="syntax">Format String Syntax</a></h4>
+ *
+ * <p> Every method which produces formatted output requires a <i>format
+ * string</i> and an <i>argument list</i>.  The format string is a {@link
+ * String} which may contain fixed text and one or more embedded <i>format
+ * specifiers</i>.  Consider the following example:
+ *
+ * <blockquote><pre>
+ *   Calendar c = ...;
+ *   String s = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ * </pre></blockquote>
+ *
+ * This format string is the first argument to the {@code format} method.  It
+ * contains three format specifiers "{@code %1$tm}", "{@code %1$te}", and
+ * "{@code %1$tY}" which indicate how the arguments should be processed and
+ * where they should be inserted in the text.  The remaining portions of the
+ * format string are fixed text including {@code "Dukes Birthday: "} and any
+ * other spaces or punctuation.
+ *
+ * The argument list consists of all arguments passed to the method after the
+ * format string.  In the above example, the argument list is of size one and
+ * consists of the {@link java.util.Calendar Calendar} object {@code c}.
+ *
+ * <ul>
+ *
+ * <li> The format specifiers for general, character, and numeric types have
+ * the following syntax:
+ *
+ * <blockquote><pre>
+ *   %[argument_index$][flags][width][.precision]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>argument_index</i> is a decimal integer indicating the
+ * position of the argument in the argument list.  The first argument is
+ * referenced by "{@code 1$}", the second by "{@code 2$}", etc.
+ *
+ * <p> The optional <i>flags</i> is a set of characters that modify the output
+ * format.  The set of valid flags depends on the conversion.
+ *
+ * <p> The optional <i>width</i> is a positive decimal integer indicating
+ * the minimum number of characters to be written to the output.
+ *
+ * <p> The optional <i>precision</i> is a non-negative decimal integer usually
+ * used to restrict the number of characters.  The specific behavior depends on
+ * the conversion.
+ *
+ * <p> The required <i>conversion</i> is a character indicating how the
+ * argument should be formatted.  The set of valid conversions for a given
+ * argument depends on the argument's data type.
+ *
+ * <li> The format specifiers for types which are used to represents dates and
+ * times have the following syntax:
+ *
+ * <blockquote><pre>
+ *   %[argument_index$][flags][width]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>argument_index</i>, <i>flags</i> and <i>width</i> are
+ * defined as above.
+ *
+ * <p> The required <i>conversion</i> is a two character sequence.  The first
+ * character is {@code 't'} or {@code 'T'}.  The second character indicates
+ * the format to be used.  These characters are similar to but not completely
+ * identical to those defined by GNU {@code date} and POSIX
+ * {@code strftime(3c)}.
+ *
+ * <li> The format specifiers which do not correspond to arguments have the
+ * following syntax:
+ *
+ * <blockquote><pre>
+ *   %[flags][width]conversion
+ * </pre></blockquote>
+ *
+ * <p> The optional <i>flags</i> and <i>width</i> is defined as above.
+ *
+ * <p> The required <i>conversion</i> is a character indicating content to be
+ * inserted in the output.
+ *
+ * </ul>
+ *
+ * <h4> Conversions </h4>
+ *
+ * <p> Conversions are divided into the following categories:
+ *
+ * <ol>
+ *
+ * <li> <b>General</b> - may be applied to any argument
+ * type
+ *
+ * <li> <b>Character</b> - may be applied to basic types which represent
+ * Unicode characters: {@code char}, {@link Character}, {@code byte}, {@link
+ * Byte}, {@code short}, and {@link Short}. This conversion may also be
+ * applied to the types {@code int} and {@link Integer} when {@link
+ * Character#isValidCodePoint} returns {@code true}
+ *
+ * <li> <b>Numeric</b>
+ *
+ * <ol>
+ *
+ * <li> <b>Integral</b> - may be applied to Java integral types: {@code byte},
+ * {@link Byte}, {@code short}, {@link Short}, {@code int} and {@link
+ * Integer}, {@code long}, {@link Long}, and {@link java.math.BigInteger
+ * BigInteger} (but not {@code char} or {@link Character})
+ *
+ * <li><b>Floating Point</b> - may be applied to Java floating-point types:
+ * {@code float}, {@link Float}, {@code double}, {@link Double}, and {@link
+ * java.math.BigDecimal BigDecimal}
+ *
+ * </ol>
+ *
+ * <li> <b>Date/Time</b> - may be applied to Java types which are capable of
+ * encoding a date or time: {@code long}, {@link Long}, {@link Calendar},
+ * {@link Date} and {@link TemporalAccessor TemporalAccessor}
+ *
+ * <li> <b>Percent</b> - produces a literal {@code '%'}
+ * (<tt>'&#92;u0025'</tt>)
+ *
+ * <li> <b>Line Separator</b> - produces the platform-specific line separator
+ *
+ * </ol>
+ *
+ * <p> The following table summarizes the supported conversions.  Conversions
+ * denoted by an upper-case character (i.e. {@code 'B'}, {@code 'H'},
+ * {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'}, {@code 'G'},
+ * {@code 'A'}, and {@code 'T'}) are the same as those for the corresponding
+ * lower-case conversion characters except that the result is converted to
+ * upper case according to the rules of the prevailing {@link java.util.Locale
+ * Locale}.  The result is equivalent to the following invocation of {@link
+ * String#toUpperCase()}
+ *
+ * <pre>
+ *    out.toUpperCase() </pre>
+ *
+ * <table cellpadding=5 summary="genConv">
+ *
+ * <tr><th valign="bottom"> Conversion
+ *     <th valign="bottom"> Argument Category
+ *     <th valign="bottom"> Description
+ *
+ * <tr><td valign="top"> {@code 'b'}, {@code 'B'}
+ *     <td valign="top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code false}".  If <i>arg</i> is a {@code boolean} or {@link
+ *     Boolean}, then the result is the string returned by {@link
+ *     String#valueOf(boolean) String.valueOf(arg)}.  Otherwise, the result is
+ *     "true".
+ *
+ * <tr><td valign="top"> {@code 'h'}, {@code 'H'}
+ *     <td valign="top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code null}".  Otherwise, the result is obtained by invoking
+ *     {@code Integer.toHexString(arg.hashCode())}.
+ *
+ * <tr><td valign="top"> {@code 's'}, {@code 'S'}
+ *     <td valign="top"> general
+ *     <td> If the argument <i>arg</i> is {@code null}, then the result is
+ *     "{@code null}".  If <i>arg</i> implements {@link Formattable}, then
+ *     {@link Formattable#formatTo arg.formatTo} is invoked. Otherwise, the
+ *     result is obtained by invoking {@code arg.toString()}.
+ *
+ * <tr><td valign="top">{@code 'c'}, {@code 'C'}
+ *     <td valign="top"> character
+ *     <td> The result is a Unicode character
+ *
+ * <tr><td valign="top">{@code 'd'}
+ *     <td valign="top"> integral
+ *     <td> The result is formatted as a decimal integer
+ *
+ * <tr><td valign="top">{@code 'o'}
+ *     <td valign="top"> integral
+ *     <td> The result is formatted as an octal integer
+ *
+ * <tr><td valign="top">{@code 'x'}, {@code 'X'}
+ *     <td valign="top"> integral
+ *     <td> The result is formatted as a hexadecimal integer
+ *
+ * <tr><td valign="top">{@code 'e'}, {@code 'E'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted as a decimal number in computerized
+ *     scientific notation
+ *
+ * <tr><td valign="top">{@code 'f'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted as a decimal number
+ *
+ * <tr><td valign="top">{@code 'g'}, {@code 'G'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted using computerized scientific notation or
+ *     decimal format, depending on the precision and the value after rounding.
+ *
+ * <tr><td valign="top">{@code 'a'}, {@code 'A'}
+ *     <td valign="top"> floating point
+ *     <td> The result is formatted as a hexadecimal floating-point number with
+ *     a significand and an exponent. This conversion is <b>not</b> supported
+ *     for the {@code BigDecimal} type despite the latter's being in the
+ *     <i>floating point</i> argument category.
+ *
+ * <tr><td valign="top">{@code 't'}, {@code 'T'}
+ *     <td valign="top"> date/time
+ *     <td> Prefix for date and time conversion characters.  See <a
+ *     href="#dt">Date/Time Conversions</a>.
+ *
+ * <tr><td valign="top">{@code '%'}
+ *     <td valign="top"> percent
+ *     <td> The result is a literal {@code '%'} (<tt>'&#92;u0025'</tt>)
+ *
+ * <tr><td valign="top">{@code 'n'}
+ *     <td valign="top"> line separator
+ *     <td> The result is the platform-specific line separator
+ *
+ * </table>
+ *
+ * <p> Any characters not explicitly defined as conversions are illegal and are
+ * reserved for future extensions.
+ *
+ * <h4><a name="dt">Date/Time Conversions</a></h4>
+ *
+ * <p> The following date and time conversion suffix characters are defined for
+ * the {@code 't'} and {@code 'T'} conversions.  The types are similar to but
+ * not completely identical to those defined by GNU {@code date} and POSIX
+ * {@code strftime(3c)}.  Additional conversion types are provided to access
+ * Java-specific functionality (e.g. {@code 'L'} for milliseconds within the
+ * second).
+ *
+ * <p> The following conversion characters are used for formatting times:
+ *
+ * <table cellpadding=5 summary="time">
+ *
+ * <tr><td valign="top"> {@code 'H'}
+ *     <td> Hour of the day for the 24-hour clock, formatted as two digits with
+ *     a leading zero as necessary i.e. {@code 00 - 23}.
+ *
+ * <tr><td valign="top">{@code 'I'}
+ *     <td> Hour for the 12-hour clock, formatted as two digits with a leading
+ *     zero as necessary, i.e.  {@code 01 - 12}.
+ *
+ * <tr><td valign="top">{@code 'k'}
+ *     <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
+ *
+ * <tr><td valign="top">{@code 'l'}
+ *     <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.
+ *
+ * <tr><td valign="top">{@code 'M'}
+ *     <td> Minute within the hour formatted as two digits with a leading zero
+ *     as necessary, i.e.  {@code 00 - 59}.
+ *
+ * <tr><td valign="top">{@code 'S'}
+ *     <td> Seconds within the minute, formatted as two digits with a leading
+ *     zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
+ *     value required to support leap seconds).
+ *
+ * <tr><td valign="top">{@code 'L'}
+ *     <td> Millisecond within the second formatted as three digits with
+ *     leading zeros as necessary, i.e. {@code 000 - 999}.
+ *
+ * <tr><td valign="top">{@code 'N'}
+ *     <td> Nanosecond within the second, formatted as nine digits with leading
+ *     zeros as necessary, i.e. {@code 000000000 - 999999999}.
+ *
+ * <tr><td valign="top">{@code 'p'}
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ *     in lower case, e.g."{@code am}" or "{@code pm}". Use of the conversion
+ *     prefix {@code 'T'} forces this output to upper case.
+ *
+ * <tr><td valign="top">{@code 'z'}
+ *     <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;822</a>
+ *     style numeric time zone offset from GMT, e.g. {@code -0800}.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.
+ *
+ * <tr><td valign="top">{@code 'Z'}
+ *     <td> A string representing the abbreviation for the time zone.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the  time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.  The Formatter's locale will
+ *     supersede the locale of the argument (if any).
+ *
+ * <tr><td valign="top">{@code 's'}
+ *     <td> Seconds since the beginning of the epoch starting at 1 January 1970
+ *     {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
+ *     {@code Long.MAX_VALUE/1000}.
+ *
+ * <tr><td valign="top">{@code 'Q'}
+ *     <td> Milliseconds since the beginning of the epoch starting at 1 January
+ *     1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
+ *     {@code Long.MAX_VALUE}.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting dates:
+ *
+ * <table cellpadding=5 summary="date">
+ *
+ * <tr><td valign="top">{@code 'B'}
+ *     <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ *     full month name}, e.g. {@code "January"}, {@code "February"}.
+ *
+ * <tr><td valign="top">{@code 'b'}
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getShortMonths abbreviated month name},
+ *     e.g. {@code "Jan"}, {@code "Feb"}.
+ *
+ * <tr><td valign="top">{@code 'h'}
+ *     <td> Same as {@code 'b'}.
+ *
+ * <tr><td valign="top">{@code 'A'}
+ *     <td> Locale-specific full name of the {@linkplain
+ *     java.text.DateFormatSymbols#getWeekdays day of the week},
+ *     e.g. {@code "Sunday"}, {@code "Monday"}
+ *
+ * <tr><td valign="top">{@code 'a'}
+ *     <td> Locale-specific short name of the {@linkplain
+ *     java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ *     e.g. {@code "Sun"}, {@code "Mon"}
+ *
+ * <tr><td valign="top">{@code 'C'}
+ *     <td> Four-digit year divided by {@code 100}, formatted as two digits
+ *     with leading zero as necessary, i.e. {@code 00 - 99}
+ *
+ * <tr><td valign="top">{@code 'Y'}
+ *     <td> Year, formatted as at least four digits with leading zeros as
+ *     necessary, e.g. {@code 0092} equals {@code 92} CE for the Gregorian
+ *     calendar.
+ *
+ * <tr><td valign="top">{@code 'y'}
+ *     <td> Last two digits of the year, formatted with leading zeros as
+ *     necessary, i.e. {@code 00 - 99}.
+ *
+ * <tr><td valign="top">{@code 'j'}
+ *     <td> Day of year, formatted as three digits with leading zeros as
+ *     necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
+ *
+ * <tr><td valign="top">{@code 'm'}
+ *     <td> Month, formatted as two digits with leading zeros as necessary,
+ *     i.e. {@code 01 - 13}.
+ *
+ * <tr><td valign="top">{@code 'd'}
+ *     <td> Day of month, formatted as two digits with leading zeros as
+ *     necessary, i.e. {@code 01 - 31}
+ *
+ * <tr><td valign="top">{@code 'e'}
+ *     <td> Day of month, formatted as two digits, i.e. {@code 1 - 31}.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ * <table cellpadding=5 summary="composites">
+ *
+ * <tr><td valign="top">{@code 'R'}
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
+ *
+ * <tr><td valign="top">{@code 'T'}
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
+ *
+ * <tr><td valign="top">{@code 'r'}
+ *     <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS %Tp"}.
+ *     The location of the morning or afternoon marker ({@code '%Tp'}) may be
+ *     locale-dependent.
+ *
+ * <tr><td valign="top">{@code 'D'}
+ *     <td> Date formatted as {@code "%tm/%td/%ty"}.
+ *
+ * <tr><td valign="top">{@code 'F'}
+ *     <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a>
+ *     complete date formatted as {@code "%tY-%tm-%td"}.
+ *
+ * <tr><td valign="top">{@code 'c'}
+ *     <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
+ *     e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
+ *
+ * </table>
+ *
+ * <p> Any characters not explicitly defined as date/time conversion suffixes
+ * are illegal and are reserved for future extensions.
+ *
+ * <h4> Flags </h4>
+ *
+ * <p> The following table summarizes the supported flags.  <i>y</i> means the
+ * flag is supported for the indicated argument types.
+ *
+ * <table cellpadding=5 summary="genConv">
+ *
+ * <tr><th valign="bottom"> Flag <th valign="bottom"> General
+ *     <th valign="bottom"> Character <th valign="bottom"> Integral
+ *     <th valign="bottom"> Floating Point
+ *     <th valign="bottom"> Date/Time
+ *     <th valign="bottom"> Description
+ *
+ * <tr><td> '-' <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td> The result will be left-justified.
+ *
+ * <tr><td> '#' <td align="center" valign="top"> y<sup>1</sup>
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>3</sup>
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result should use a conversion-dependent alternate form
+ *
+ * <tr><td> '+' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>4</sup>
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result will always include a sign
+ *
+ * <tr><td> '&nbsp;&nbsp;' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>4</sup>
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result will include a leading space for positive values
+ *
+ * <tr><td> '0' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> y
+ *     <td align="center" valign="top"> -
+ *     <td> The result will be zero-padded
+ *
+ * <tr><td> ',' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>2</sup>
+ *     <td align="center" valign="top"> y<sup>5</sup>
+ *     <td align="center" valign="top"> -
+ *     <td> The result will include locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getGroupingSeparator grouping separators}
+ *
+ * <tr><td> '(' <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> -
+ *     <td align="center" valign="top"> y<sup>4</sup>
+ *     <td align="center" valign="top"> y<sup>5</sup>
+ *     <td align="center"> -
+ *     <td> The result will enclose negative numbers in parentheses
+ *
+ * </table>
+ *
+ * <p> <sup>1</sup> Depends on the definition of {@link Formattable}.
+ *
+ * <p> <sup>2</sup> For {@code 'd'} conversion only.
+ *
+ * <p> <sup>3</sup> For {@code 'o'}, {@code 'x'}, and {@code 'X'}
+ * conversions only.
+ *
+ * <p> <sup>4</sup> For {@code 'd'}, {@code 'o'}, {@code 'x'}, and
+ * {@code 'X'} conversions applied to {@link java.math.BigInteger BigInteger}
+ * or {@code 'd'} applied to {@code byte}, {@link Byte}, {@code short}, {@link
+ * Short}, {@code int} and {@link Integer}, {@code long}, and {@link Long}.
+ *
+ * <p> <sup>5</sup> For {@code 'e'}, {@code 'E'}, {@code 'f'},
+ * {@code 'g'}, and {@code 'G'} conversions only.
+ *
+ * <p> Any characters not explicitly defined as flags are illegal and are
+ * reserved for future extensions.
+ *
+ * <h4> Width </h4>
+ *
+ * <p> The width is the minimum number of characters to be written to the
+ * output.  For the line separator conversion, width is not applicable; if it
+ * is provided, an exception will be thrown.
+ *
+ * <h4> Precision </h4>
+ *
+ * <p> For general argument types, the precision is the maximum number of
+ * characters to be written to the output.
+ *
+ * <p> For the floating-point conversions {@code 'a'}, {@code 'A'}, {@code 'e'},
+ * {@code 'E'}, and {@code 'f'} the precision is the number of digits after the
+ * radix point.  If the conversion is {@code 'g'} or {@code 'G'}, then the
+ * precision is the total number of digits in the resulting magnitude after
+ * rounding.
+ *
+ * <p> For character, integral, and date/time argument types and the percent
+ * and line separator conversions, the precision is not applicable; if a
+ * precision is provided, an exception will be thrown.
+ *
+ * <h4> Argument Index </h4>
+ *
+ * <p> The argument index is a decimal integer indicating the position of the
+ * argument in the argument list.  The first argument is referenced by
+ * "{@code 1$}", the second by "{@code 2$}", etc.
+ *
+ * <p> Another way to reference arguments by position is to use the
+ * {@code '<'} (<tt>'&#92;u003c'</tt>) flag, which causes the argument for
+ * the previous format specifier to be re-used.  For example, the following two
+ * statements would produce identical strings:
+ *
+ * <blockquote><pre>
+ *   Calendar c = ...;
+ *   String s1 = String.format("Duke's Birthday: %1$tm %1$te,%1$tY", c);
+ *
+ *   String s2 = String.format("Duke's Birthday: %1$tm %&lt;te,%&lt;tY", c);
+ * </pre></blockquote>
+ *
+ * <hr>
+ * <h3><a name="detail">Details</a></h3>
+ *
+ * <p> This section is intended to provide behavioral details for formatting,
+ * including conditions and exceptions, supported data types, localization, and
+ * interactions between flags, conversions, and data types.  For an overview of
+ * formatting concepts, refer to the <a href="#summary">Summary</a>
+ *
+ * <p> Any characters not explicitly defined as conversions, date/time
+ * conversion suffixes, or flags are illegal and are reserved for
+ * future extensions.  Use of such a character in a format string will
+ * cause an {@link UnknownFormatConversionException} or {@link
+ * UnknownFormatFlagsException} to be thrown.
+ *
+ * <p> If the format specifier contains a width or precision with an invalid
+ * value or which is otherwise unsupported, then a {@link
+ * IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
+ * respectively will be thrown.
+ *
+ * <p> If a format specifier contains a conversion character that is not
+ * applicable to the corresponding argument, then an {@link
+ * IllegalFormatConversionException} will be thrown.
+ *
+ * <p> All specified exceptions may be thrown by any of the {@code format}
+ * methods of {@code Formatter} as well as by any {@code format} convenience
+ * methods such as {@link String#format(String,Object...) String.format} and
+ * {@link java.io.PrintStream#printf(String,Object...) PrintStream.printf}.
+ *
+ * <p> Conversions denoted by an upper-case character (i.e. {@code 'B'},
+ * {@code 'H'}, {@code 'S'}, {@code 'C'}, {@code 'X'}, {@code 'E'},
+ * {@code 'G'}, {@code 'A'}, and {@code 'T'}) are the same as those for the
+ * corresponding lower-case conversion characters except that the result is
+ * converted to upper case according to the rules of the prevailing {@link
+ * java.util.Locale Locale}.  The result is equivalent to the following
+ * invocation of {@link String#toUpperCase()}
+ *
+ * <pre>
+ *    out.toUpperCase() </pre>
+ *
+ * <h4><a name="dgen">General</a></h4>
+ *
+ * <p> The following general conversions may be applied to any argument type:
+ *
+ * <table cellpadding=5 summary="dgConv">
+ *
+ * <tr><td valign="top"> {@code 'b'}
+ *     <td valign="top"> <tt>'&#92;u0062'</tt>
+ *     <td> Produces either "{@code true}" or "{@code false}" as returned by
+ *     {@link Boolean#toString(boolean)}.
+ *
+ *     <p> If the argument is {@code null}, then the result is
+ *     "{@code false}".  If the argument is a {@code boolean} or {@link
+ *     Boolean}, then the result is the string returned by {@link
+ *     String#valueOf(boolean) String.valueOf()}.  Otherwise, the result is
+ *     "{@code true}".
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'B'}
+ *     <td valign="top"> <tt>'&#92;u0042'</tt>
+ *     <td> The upper-case variant of {@code 'b'}.
+ *
+ * <tr><td valign="top"> {@code 'h'}
+ *     <td valign="top"> <tt>'&#92;u0068'</tt>
+ *     <td> Produces a string representing the hash code value of the object.
+ *
+ *     <p> If the argument, <i>arg</i> is {@code null}, then the
+ *     result is "{@code null}".  Otherwise, the result is obtained
+ *     by invoking {@code Integer.toHexString(arg.hashCode())}.
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'H'}
+ *     <td valign="top"> <tt>'&#92;u0048'</tt>
+ *     <td> The upper-case variant of {@code 'h'}.
+ *
+ * <tr><td valign="top"> {@code 's'}
+ *     <td valign="top"> <tt>'&#92;u0073'</tt>
+ *     <td> Produces a string.
+ *
+ *     <p> If the argument is {@code null}, then the result is
+ *     "{@code null}".  If the argument implements {@link Formattable}, then
+ *     its {@link Formattable#formatTo formatTo} method is invoked.
+ *     Otherwise, the result is obtained by invoking the argument's
+ *     {@code toString()} method.
+ *
+ *     <p> If the {@code '#'} flag is given and the argument is not a {@link
+ *     Formattable} , then a {@link FormatFlagsConversionMismatchException}
+ *     will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'S'}
+ *     <td valign="top"> <tt>'&#92;u0053'</tt>
+ *     <td> The upper-case variant of {@code 's'}.
+ *
+ * </table>
+ *
+ * <p> The following <a name="dFlags">flags</a> apply to general conversions:
+ *
+ * <table cellpadding=5 summary="dFlags">
+ *
+ * <tr><td valign="top"> {@code '-'}
+ *     <td valign="top"> <tt>'&#92;u002d'</tt>
+ *     <td> Left justifies the output.  Spaces (<tt>'&#92;u0020'</tt>) will be
+ *     added at the end of the converted value as required to fill the minimum
+ *     width of the field.  If the width is not provided, then a {@link
+ *     MissingFormatWidthException} will be thrown.  If this flag is not given
+ *     then the output will be right-justified.
+ *
+ * <tr><td valign="top"> {@code '#'}
+ *     <td valign="top"> <tt>'&#92;u0023'</tt>
+ *     <td> Requires the output use an alternate form.  The definition of the
+ *     form is specified by the conversion.
+ *
+ * </table>
+ *
+ * <p> The <a name="genWidth">width</a> is the minimum number of characters to
+ * be written to the
+ * output.  If the length of the converted value is less than the width then
+ * the output will be padded by <tt>'&nbsp;&nbsp;'</tt> (<tt>'&#92;u0020'</tt>)
+ * until the total number of characters equals the width.  The padding is on
+ * the left by default.  If the {@code '-'} flag is given, then the padding
+ * will be on the right.  If the width is not specified then there is no
+ * minimum.
+ *
+ * <p> The precision is the maximum number of characters to be written to the
+ * output.  The precision is applied before the width, thus the output will be
+ * truncated to {@code precision} characters even if the width is greater than
+ * the precision.  If the precision is not specified then there is no explicit
+ * limit on the number of characters.
+ *
+ * <h4><a name="dchar">Character</a></h4>
+ *
+ * This conversion may be applied to {@code char} and {@link Character}.  It
+ * may also be applied to the types {@code byte}, {@link Byte},
+ * {@code short}, and {@link Short}, {@code int} and {@link Integer} when
+ * {@link Character#isValidCodePoint} returns {@code true}.  If it returns
+ * {@code false} then an {@link IllegalFormatCodePointException} will be
+ * thrown.
+ *
+ * <table cellpadding=5 summary="charConv">
+ *
+ * <tr><td valign="top"> {@code 'c'}
+ *     <td valign="top"> <tt>'&#92;u0063'</tt>
+ *     <td> Formats the argument as a Unicode character as described in <a
+ *     href="../lang/Character.html#unicode">Unicode Character
+ *     Representation</a>.  This may be more than one 16-bit {@code char} in
+ *     the case where the argument represents a supplementary character.
+ *
+ *     <p> If the {@code '#'} flag is given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'C'}
+ *     <td valign="top"> <tt>'&#92;u0043'</tt>
+ *     <td> The upper-case variant of {@code 'c'}.
+ *
+ * </table>
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The width is defined as for <a href="#genWidth">General conversions</a>.
+ *
+ * <p> The precision is not applicable.  If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <h4><a name="dnum">Numeric</a></h4>
+ *
+ * <p> Numeric conversions are divided into the following categories:
+ *
+ * <ol>
+ *
+ * <li> <a href="#dnint"><b>Byte, Short, Integer, and Long</b></a>
+ *
+ * <li> <a href="#dnbint"><b>BigInteger</b></a>
+ *
+ * <li> <a href="#dndec"><b>Float and Double</b></a>
+ *
+ * <li> <a href="#dnbdec"><b>BigDecimal</b></a>
+ *
+ * </ol>
+ *
+ * <p> Numeric types will be formatted according to the following algorithm:
+ *
+ * <p><b><a name="L10nAlgorithm"> Number Localization Algorithm</a></b>
+ *
+ * <p> After digits are obtained for the integer part, fractional part, and
+ * exponent (as appropriate for the data type), the following transformation
+ * is applied:
+ *
+ * <ol>
+ *
+ * <li> Each digit character <i>d</i> in the string is replaced by a
+ * locale-specific digit computed relative to the current locale's
+ * {@linkplain java.text.DecimalFormatSymbols#getZeroDigit() zero digit}
+ * <i>z</i>; that is <i>d&nbsp;-&nbsp;</i> {@code '0'}
+ * <i>&nbsp;+&nbsp;z</i>.
+ *
+ * <li> If a decimal separator is present, a locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getDecimalSeparator decimal separator} is
+ * substituted.
+ *
+ * <li> If the {@code ','} (<tt>'&#92;u002c'</tt>)
+ * <a name="L10nGroup">flag</a> is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getGroupingSeparator grouping separator} is
+ * inserted by scanning the integer part of the string from least significant
+ * to most significant digits and inserting a separator at intervals defined by
+ * the locale's {@linkplain java.text.DecimalFormat#getGroupingSize() grouping
+ * size}.
+ *
+ * <li> If the {@code '0'} flag is given, then the locale-specific {@linkplain
+ * java.text.DecimalFormatSymbols#getZeroDigit() zero digits} are inserted
+ * after the sign character, if any, and before the first non-zero digit, until
+ * the length of the string is equal to the requested field width.
+ *
+ * <li> If the value is negative and the {@code '('} flag is given, then a
+ * {@code '('} (<tt>'&#92;u0028'</tt>) is prepended and a {@code ')'}
+ * (<tt>'&#92;u0029'</tt>) is appended.
+ *
+ * <li> If the value is negative (or floating-point negative zero) and
+ * {@code '('} flag is not given, then a {@code '-'} (<tt>'&#92;u002d'</tt>)
+ * is prepended.
+ *
+ * <li> If the {@code '+'} flag is given and the value is positive or zero (or
+ * floating-point positive zero), then a {@code '+'} (<tt>'&#92;u002b'</tt>)
+ * will be prepended.
+ *
+ * </ol>
+ *
+ * <p> If the value is NaN or positive infinity the literal strings "NaN" or
+ * "Infinity" respectively, will be output.  If the value is negative infinity,
+ * then the output will be "(Infinity)" if the {@code '('} flag is given
+ * otherwise the output will be "-Infinity".  These values are not localized.
+ *
+ * <p><a name="dnint"><b> Byte, Short, Integer, and Long </b></a>
+ *
+ * <p> The following conversions may be applied to {@code byte}, {@link Byte},
+ * {@code short}, {@link Short}, {@code int} and {@link Integer},
+ * {@code long}, and {@link Long}.
+ *
+ * <table cellpadding=5 summary="IntConv">
+ *
+ * <tr><td valign="top"> {@code 'd'}
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
+ *     <td> Formats the argument as a decimal integer. The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> If the {@code '0'} flag is given and the value is negative, then
+ *     the zero padding will occur after the sign.
+ *
+ *     <p> If the {@code '#'} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'o'}
+ *     <td valign="top"> <tt>'&#92;u006f'</tt>
+ *     <td> Formats the argument as an integer in base eight.  No localization
+ *     is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be an unsigned value
+ *     generated by adding 2<sup>n</sup> to the value where {@code n} is the
+ *     number of bits in the type as returned by the static {@code SIZE} field
+ *     in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ *     {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ *     classes as appropriate.
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code '0'}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded
+ *     with leading zeros to the field width following any indication of sign.
+ *
+ *     <p> If {@code '('}, {@code '+'}, '&nbsp;&nbsp;', or {@code ','} flags
+ *     are given then a {@link FormatFlagsConversionMismatchException} will be
+ *     thrown.
+ *
+ * <tr><td valign="top"> {@code 'x'}
+ *     <td valign="top"> <tt>'&#92;u0078'</tt>
+ *     <td> Formats the argument as an integer in base sixteen. No
+ *     localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be an unsigned value
+ *     generated by adding 2<sup>n</sup> to the value where {@code n} is the
+ *     number of bits in the type as returned by the static {@code SIZE} field
+ *     in the {@linkplain Byte#SIZE Byte}, {@linkplain Short#SIZE Short},
+ *     {@linkplain Integer#SIZE Integer}, or {@linkplain Long#SIZE Long}
+ *     classes as appropriate.
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code "0x"}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded to
+ *     the field width with leading zeros after the radix indicator or sign (if
+ *     present).
+ *
+ *     <p> If {@code '('}, <tt>'&nbsp;&nbsp;'</tt>, {@code '+'}, or
+ *     {@code ','} flags are given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'X'}
+ *     <td valign="top"> <tt>'&#92;u0058'</tt>
+ *     <td> The upper-case variant of {@code 'x'}.  The entire string
+ *     representing the number will be converted to {@linkplain
+ *     String#toUpperCase upper case} including the {@code 'x'} (if any) and
+ *     all hexadecimal digits {@code 'a'} - {@code 'f'}
+ *     (<tt>'&#92;u0061'</tt> -  <tt>'&#92;u0066'</tt>).
+ *
+ * </table>
+ *
+ * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
+ * both the {@code '#'} and the {@code '0'} flags are given, then result will
+ * contain the radix indicator ({@code '0'} for octal and {@code "0x"} or
+ * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ * <p> If the {@code '-'} flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ * <p> The following <a name="intFlags">flags</a> apply to numeric integral
+ * conversions:
+ *
+ * <table cellpadding=5 summary="intFlags">
+ *
+ * <tr><td valign="top"> {@code '+'}
+ *     <td valign="top"> <tt>'&#92;u002b'</tt>
+ *     <td> Requires the output to include a positive sign for all positive
+ *     numbers.  If this flag is not given then only negative values will
+ *     include a sign.
+ *
+ *     <p> If both the {@code '+'} and <tt>'&nbsp;&nbsp;'</tt> flags are given
+ *     then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><td valign="top"> <tt>'&nbsp;&nbsp;'</tt>
+ *     <td valign="top"> <tt>'&#92;u0020'</tt>
+ *     <td> Requires the output to include a single extra space
+ *     (<tt>'&#92;u0020'</tt>) for non-negative values.
+ *
+ *     <p> If both the {@code '+'} and <tt>'&nbsp;&nbsp;'</tt> flags are given
+ *     then an {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code '0'}
+ *     <td valign="top"> <tt>'&#92;u0030'</tt>
+ *     <td> Requires the output to be padded with leading {@linkplain
+ *     java.text.DecimalFormatSymbols#getZeroDigit zeros} to the minimum field
+ *     width following any sign or radix indicator except when converting NaN
+ *     or infinity.  If the width is not provided, then a {@link
+ *     MissingFormatWidthException} will be thrown.
+ *
+ *     <p> If both the {@code '-'} and {@code '0'} flags are given then an
+ *     {@link IllegalFormatFlagsException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code ','}
+ *     <td valign="top"> <tt>'&#92;u002c'</tt>
+ *     <td> Requires the output to include the locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getGroupingSeparator group separators} as
+ *     described in the <a href="#L10nGroup">"group" section</a> of the
+ *     localization algorithm.
+ *
+ * <tr><td valign="top"> {@code '('}
+ *     <td valign="top"> <tt>'&#92;u0028'</tt>
+ *     <td> Requires the output to prepend a {@code '('}
+ *     (<tt>'&#92;u0028'</tt>) and append a {@code ')'}
+ *     (<tt>'&#92;u0029'</tt>) to negative values.
+ *
+ * </table>
+ *
+ * <p> If no <a name="intdFlags">flags</a> are given the default formatting is
+ * as follows:
+ *
+ * <ul>
+ *
+ * <li> The output is right-justified within the {@code width}
+ *
+ * <li> Negative numbers begin with a {@code '-'} (<tt>'&#92;u002d'</tt>)
+ *
+ * <li> Positive numbers and zero do not include a sign or extra leading
+ * space
+ *
+ * <li> No grouping separators are included
+ *
+ * </ul>
+ *
+ * <p> The <a name="intWidth">width</a> is the minimum number of characters to
+ * be written to the output.  This includes any signs, digits, grouping
+ * separators, radix indicator, and parentheses.  If the length of the
+ * converted value is less than the width then the output will be padded by
+ * spaces (<tt>'&#92;u0020'</tt>) until the total number of characters equals
+ * width.  The padding is on the left by default.  If {@code '-'} flag is
+ * given then the padding will be on the right.  If width is not specified then
+ * there is no minimum.
+ *
+ * <p> The precision is not applicable.  If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <p><a name="dnbint"><b> BigInteger </b></a>
+ *
+ * <p> The following conversions may be applied to {@link
+ * java.math.BigInteger}.
+ *
+ * <table cellpadding=5 summary="BIntConv">
+ *
+ * <tr><td valign="top"> {@code 'd'}
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
+ *     <td> Requires the output to be formatted as a decimal integer. The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> If the {@code '#'} flag is given {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'o'}
+ *     <td valign="top"> <tt>'&#92;u006f'</tt>
+ *     <td> Requires the output to be formatted as an integer in base eight.
+ *     No localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be a signed value
+ *     beginning with {@code '-'} (<tt>'&#92;u002d'</tt>).  Signed output is
+ *     allowed for this type because unlike the primitive types it is not
+ *     possible to create an unsigned equivalent without assuming an explicit
+ *     data-type size.
+ *
+ *     <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
+ *     then the result will begin with {@code '+'} (<tt>'&#92;u002b'</tt>).
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with {@code '0'} prefix.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded
+ *     with leading zeros to the field width following any indication of sign.
+ *
+ *     <p> If the {@code ','} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'x'}
+ *     <td valign="top"> <tt>'&#92;u0078'</tt>
+ *     <td> Requires the output to be formatted as an integer in base
+ *     sixteen.  No localization is applied.
+ *
+ *     <p> If <i>x</i> is negative then the result will be a signed value
+ *     beginning with {@code '-'} (<tt>'&#92;u002d'</tt>).  Signed output is
+ *     allowed for this type because unlike the primitive types it is not
+ *     possible to create an unsigned equivalent without assuming an explicit
+ *     data-type size.
+ *
+ *     <p> If <i>x</i> is positive or zero and the {@code '+'} flag is given
+ *     then the result will begin with {@code '+'} (<tt>'&#92;u002b'</tt>).
+ *
+ *     <p> If the {@code '#'} flag is given then the output will always begin
+ *     with the radix indicator {@code "0x"}.
+ *
+ *     <p> If the {@code '0'} flag is given then the output will be padded to
+ *     the field width with leading zeros after the radix indicator or sign (if
+ *     present).
+ *
+ *     <p> If the {@code ','} flag is given then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'X'}
+ *     <td valign="top"> <tt>'&#92;u0058'</tt>
+ *     <td> The upper-case variant of {@code 'x'}.  The entire string
+ *     representing the number will be converted to {@linkplain
+ *     String#toUpperCase upper case} including the {@code 'x'} (if any) and
+ *     all hexadecimal digits {@code 'a'} - {@code 'f'}
+ *     (<tt>'&#92;u0061'</tt> - <tt>'&#92;u0066'</tt>).
+ *
+ * </table>
+ *
+ * <p> If the conversion is {@code 'o'}, {@code 'x'}, or {@code 'X'} and
+ * both the {@code '#'} and the {@code '0'} flags are given, then result will
+ * contain the base indicator ({@code '0'} for octal and {@code "0x"} or
+ * {@code "0X"} for hexadecimal), some number of zeros (based on the width),
+ * and the value.
+ *
+ * <p> If the {@code '0'} flag is given and the value is negative, then the
+ * zero padding will occur after the sign.
+ *
+ * <p> If the {@code '-'} flag is not given, then the space padding will occur
+ * before the sign.
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.  The <a href="#intdFlags">default behavior</a> when no flags are
+ * given is the same as for Byte, Short, Integer, and Long.
+ *
+ * <p> The specification of <a href="#intWidth">width</a> is the same as
+ * defined for Byte, Short, Integer, and Long.
+ *
+ * <p> The precision is not applicable.  If precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <p><a name="dndec"><b> Float and Double</b></a>
+ *
+ * <p> The following conversions may be applied to {@code float}, {@link
+ * Float}, {@code double} and {@link Double}.
+ *
+ * <table cellpadding=5 summary="floatConv">
+ *
+ * <tr><td valign="top"> {@code 'e'}
+ *     <td valign="top"> <tt>'&#92;u0065'</tt>
+ *     <td> Requires the output to be formatted using <a
+ *     name="scientific">computerized scientific notation</a>.  The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <p> If <i>m</i> is NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.  These values are not
+ *     localized.
+ *
+ *     <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
+ *     will be {@code "+00"}.
+ *
+ *     <p> Otherwise, the result is a string that represents the sign and
+ *     magnitude (absolute value) of the argument.  The formatting of the sign
+ *     is described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
+ *     &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+ *     mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
+ *     that 1 &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the
+ *     integer part of <i>a</i>, as a single decimal digit, followed by the
+ *     decimal separator followed by decimal digits representing the fractional
+ *     part of <i>a</i>, followed by the lower-case locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getExponentSeparator exponent separator}
+ *     (e.g. {@code 'e'}), followed by the sign of the exponent, followed
+ *     by a representation of <i>n</i> as a decimal integer, as produced by the
+ *     method {@link Long#toString(long, int)}, and zero-padded to include at
+ *     least two digits.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}. If the precision is less
+ *     than the number of digits which would appear after the decimal point in
+ *     the string returned by {@link Float#toString(float)} or {@link
+ *     Double#toString(double)} respectively, then the value will be rounded
+ *     using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     Float#toString(float)} or {@link Double#toString(double)} as
+ *     appropriate.
+ *
+ *     <p>If the {@code ','} flag is given, then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'E'}
+ *     <td valign="top"> <tt>'&#92;u0045'</tt>
+ *     <td> The upper-case variant of {@code 'e'}.  The exponent symbol
+ *     will be the upper-case locale-specific {@linkplain
+ *     java.text.DecimalFormatSymbols#getExponentSeparator exponent separator}
+ *     (e.g. {@code 'E'}).
+ *
+ * <tr><td valign="top"> {@code 'g'}
+ *     <td valign="top"> <tt>'&#92;u0067'</tt>
+ *     <td> Requires the output to be formatted in general scientific notation
+ *     as described below. The <a href="#L10nAlgorithm">localization
+ *     algorithm</a> is applied.
+ *
+ *     <p> After rounding for the precision, the formatting of the resulting
+ *     magnitude <i>m</i> depends on its value.
+ *
+ *     <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
+ *     than 10<sup>precision</sup> then it is represented in <i><a
+ *     href="#decimal">decimal format</a></i>.
+ *
+ *     <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
+ *     10<sup>precision</sup>, then it is represented in <i><a
+ *     href="#scientific">computerized scientific notation</a></i>.
+ *
+ *     <p> The total number of significant digits in <i>m</i> is equal to the
+ *     precision.  If the precision is not specified, then the default value is
+ *     {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ *     {@code 1}.
+ *
+ *     <p> If the {@code '#'} flag is given then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'G'}
+ *     <td valign="top"> <tt>'&#92;u0047'</tt>
+ *     <td> The upper-case variant of {@code 'g'}.
+ *
+ * <tr><td valign="top"> {@code 'f'}
+ *     <td valign="top"> <tt>'&#92;u0066'</tt>
+ *     <td> Requires the output to be formatted using <a name="decimal">decimal
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
+ *     applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument.  The formatting of the sign is
+ *     described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> If <i>m</i> NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.  These values are not
+ *     localized.
+ *
+ *     <p> The magnitude is formatted as the integer part of <i>m</i>, with no
+ *     leading zeroes, followed by the decimal separator followed by one or
+ *     more decimal digits representing the fractional part of <i>m</i>.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}. If the precision is less
+ *     than the number of digits which would appear after the decimal point in
+ *     the string returned by {@link Float#toString(float)} or {@link
+ *     Double#toString(double)} respectively, then the value will be rounded
+ *     using the {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     Float#toString(float)} or {@link Double#toString(double)} as
+ *     appropriate.
+ *
+ * <tr><td valign="top"> {@code 'a'}
+ *     <td valign="top"> <tt>'&#92;u0061'</tt>
+ *     <td> Requires the output to be formatted in hexadecimal exponential
+ *     form.  No localization is applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument <i>x</i>.
+ *
+ *     <p> If <i>x</i> is negative or a negative-zero value then the result
+ *     will begin with {@code '-'} (<tt>'&#92;u002d'</tt>).
+ *
+ *     <p> If <i>x</i> is positive or a positive-zero value and the
+ *     {@code '+'} flag is given then the result will begin with {@code '+'}
+ *     (<tt>'&#92;u002b'</tt>).
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <ul>
+ *
+ *     <li> If the value is NaN or infinite, the literal strings "NaN" or
+ *     "Infinity", respectively, will be output.
+ *
+ *     <li> If <i>m</i> is zero then it is represented by the string
+ *     {@code "0x0.0p0"}.
+ *
+ *     <li> If <i>m</i> is a {@code double} value with a normalized
+ *     representation then substrings are used to represent the significand and
+ *     exponent fields.  The significand is represented by the characters
+ *     {@code "0x1."} followed by the hexadecimal representation of the rest
+ *     of the significand as a fraction.  The exponent is represented by
+ *     {@code 'p'} (<tt>'&#92;u0070'</tt>) followed by a decimal string of the
+ *     unbiased exponent as if produced by invoking {@link
+ *     Integer#toString(int) Integer.toString} on the exponent value.  If the
+ *     precision is specified, the value is rounded to the given number of
+ *     hexadecimal digits.
+ *
+ *     <li> If <i>m</i> is a {@code double} value with a subnormal
+ *     representation then, unless the precision is specified to be in the range
+ *     1 through 12, inclusive, the significand is represented by the characters
+ *     {@code '0x0.'} followed by the hexadecimal representation of the rest of
+ *     the significand as a fraction, and the exponent represented by
+ *     {@code 'p-1022'}.  If the precision is in the interval
+ *     [1,&nbsp;12], the subnormal value is normalized such that it
+ *     begins with the characters {@code '0x1.'}, rounded to the number of
+ *     hexadecimal digits of precision, and the exponent adjusted
+ *     accordingly.  Note that there must be at least one nonzero digit in a
+ *     subnormal significand.
+ *
+ *     </ul>
+ *
+ *     <p> If the {@code '('} or {@code ','} flags are given, then a {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'A'}
+ *     <td valign="top"> <tt>'&#92;u0041'</tt>
+ *     <td> The upper-case variant of {@code 'a'}.  The entire string
+ *     representing the number will be converted to upper case including the
+ *     {@code 'x'} (<tt>'&#92;u0078'</tt>) and {@code 'p'}
+ *     (<tt>'&#92;u0070'</tt> and all hexadecimal digits {@code 'a'} -
+ *     {@code 'f'} (<tt>'&#92;u0061'</tt> - <tt>'&#92;u0066'</tt>).
+ *
+ * </table>
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ * <p> If the {@code '#'} flag is given, then the decimal separator will
+ * always be present.
+ *
+ * <p> If no <a name="floatdFlags">flags</a> are given the default formatting
+ * is as follows:
+ *
+ * <ul>
+ *
+ * <li> The output is right-justified within the {@code width}
+ *
+ * <li> Negative numbers begin with a {@code '-'}
+ *
+ * <li> Positive numbers and positive zero do not include a sign or extra
+ * leading space
+ *
+ * <li> No grouping separators are included
+ *
+ * <li> The decimal separator will only appear if a digit follows it
+ *
+ * </ul>
+ *
+ * <p> The <a name="floatDWidth">width</a> is the minimum number of characters
+ * to be written to the output.  This includes any signs, digits, grouping
+ * separators, decimal separators, exponential symbol, radix indicator,
+ * parentheses, and strings representing infinity and NaN as applicable.  If
+ * the length of the converted value is less than the width then the output
+ * will be padded by spaces (<tt>'&#92;u0020'</tt>) until the total number of
+ * characters equals width.  The padding is on the left by default.  If the
+ * {@code '-'} flag is given then the padding will be on the right.  If width
+ * is not specified then there is no minimum.
+ *
+ * <p> If the <a name="floatDPrec">conversion</a> is {@code 'e'},
+ * {@code 'E'} or {@code 'f'}, then the precision is the number of digits
+ * after the decimal separator.  If the precision is not specified, then it is
+ * assumed to be {@code 6}.
+ *
+ * <p> If the conversion is {@code 'g'} or {@code 'G'}, then the precision is
+ * the total number of significant digits in the resulting magnitude after
+ * rounding.  If the precision is not specified, then the default value is
+ * {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ * {@code 1}.
+ *
+ * <p> If the conversion is {@code 'a'} or {@code 'A'}, then the precision
+ * is the number of hexadecimal digits after the radix point.  If the
+ * precision is not provided, then all of the digits as returned by {@link
+ * Double#toHexString(double)} will be output.
+ *
+ * <p><a name="dnbdec"><b> BigDecimal </b></a>
+ *
+ * <p> The following conversions may be applied {@link java.math.BigDecimal
+ * BigDecimal}.
+ *
+ * <table cellpadding=5 summary="floatConv">
+ *
+ * <tr><td valign="top"> {@code 'e'}
+ *     <td valign="top"> <tt>'&#92;u0065'</tt>
+ *     <td> Requires the output to be formatted using <a
+ *     name="bscientific">computerized scientific notation</a>.  The <a
+ *     href="#L10nAlgorithm">localization algorithm</a> is applied.
+ *
+ *     <p> The formatting of the magnitude <i>m</i> depends upon its value.
+ *
+ *     <p> If <i>m</i> is positive-zero or negative-zero, then the exponent
+ *     will be {@code "+00"}.
+ *
+ *     <p> Otherwise, the result is a string that represents the sign and
+ *     magnitude (absolute value) of the argument.  The formatting of the sign
+ *     is described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> Let <i>n</i> be the unique integer such that 10<sup><i>n</i></sup>
+ *     &lt;= <i>m</i> &lt; 10<sup><i>n</i>+1</sup>; then let <i>a</i> be the
+ *     mathematically exact quotient of <i>m</i> and 10<sup><i>n</i></sup> so
+ *     that 1 &lt;= <i>a</i> &lt; 10. The magnitude is then represented as the
+ *     integer part of <i>a</i>, as a single decimal digit, followed by the
+ *     decimal separator followed by decimal digits representing the fractional
+ *     part of <i>a</i>, followed by the exponent symbol {@code 'e'}
+ *     (<tt>'&#92;u0065'</tt>), followed by the sign of the exponent, followed
+ *     by a representation of <i>n</i> as a decimal integer, as produced by the
+ *     method {@link Long#toString(long, int)}, and zero-padded to include at
+ *     least two digits.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision.  If the precision is not
+ *     specified then the default value is {@code 6}.  If the precision is
+ *     less than the number of digits to the right of the decimal point then
+ *     the value will be rounded using the
+ *     {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     BigDecimal#toString()}.
+ *
+ *     <p> If the {@code ','} flag is given, then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'E'}
+ *     <td valign="top"> <tt>'&#92;u0045'</tt>
+ *     <td> The upper-case variant of {@code 'e'}.  The exponent symbol
+ *     will be {@code 'E'} (<tt>'&#92;u0045'</tt>).
+ *
+ * <tr><td valign="top"> {@code 'g'}
+ *     <td valign="top"> <tt>'&#92;u0067'</tt>
+ *     <td> Requires the output to be formatted in general scientific notation
+ *     as described below. The <a href="#L10nAlgorithm">localization
+ *     algorithm</a> is applied.
+ *
+ *     <p> After rounding for the precision, the formatting of the resulting
+ *     magnitude <i>m</i> depends on its value.
+ *
+ *     <p> If <i>m</i> is greater than or equal to 10<sup>-4</sup> but less
+ *     than 10<sup>precision</sup> then it is represented in <i><a
+ *     href="#bdecimal">decimal format</a></i>.
+ *
+ *     <p> If <i>m</i> is less than 10<sup>-4</sup> or greater than or equal to
+ *     10<sup>precision</sup>, then it is represented in <i><a
+ *     href="#bscientific">computerized scientific notation</a></i>.
+ *
+ *     <p> The total number of significant digits in <i>m</i> is equal to the
+ *     precision.  If the precision is not specified, then the default value is
+ *     {@code 6}.  If the precision is {@code 0}, then it is taken to be
+ *     {@code 1}.
+ *
+ *     <p> If the {@code '#'} flag is given then an {@link
+ *     FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <tr><td valign="top"> {@code 'G'}
+ *     <td valign="top"> <tt>'&#92;u0047'</tt>
+ *     <td> The upper-case variant of {@code 'g'}.
+ *
+ * <tr><td valign="top"> {@code 'f'}
+ *     <td valign="top"> <tt>'&#92;u0066'</tt>
+ *     <td> Requires the output to be formatted using <a name="bdecimal">decimal
+ *     format</a>.  The <a href="#L10nAlgorithm">localization algorithm</a> is
+ *     applied.
+ *
+ *     <p> The result is a string that represents the sign and magnitude
+ *     (absolute value) of the argument.  The formatting of the sign is
+ *     described in the <a href="#L10nAlgorithm">localization
+ *     algorithm</a>. The formatting of the magnitude <i>m</i> depends upon its
+ *     value.
+ *
+ *     <p> The magnitude is formatted as the integer part of <i>m</i>, with no
+ *     leading zeroes, followed by the decimal separator followed by one or
+ *     more decimal digits representing the fractional part of <i>m</i>.
+ *
+ *     <p> The number of digits in the result for the fractional part of
+ *     <i>m</i> or <i>a</i> is equal to the precision. If the precision is not
+ *     specified then the default value is {@code 6}.  If the precision is
+ *     less than the number of digits to the right of the decimal point
+ *     then the value will be rounded using the
+ *     {@linkplain java.math.BigDecimal#ROUND_HALF_UP round half up
+ *     algorithm}.  Otherwise, zeros may be appended to reach the precision.
+ *     For a canonical representation of the value, use {@link
+ *     BigDecimal#toString()}.
+ *
+ * </table>
+ *
+ * <p> All <a href="#intFlags">flags</a> defined for Byte, Short, Integer, and
+ * Long apply.
+ *
+ * <p> If the {@code '#'} flag is given, then the decimal separator will
+ * always be present.
+ *
+ * <p> The <a href="#floatdFlags">default behavior</a> when no flags are
+ * given is the same as for Float and Double.
+ *
+ * <p> The specification of <a href="#floatDWidth">width</a> and <a
+ * href="#floatDPrec">precision</a> is the same as defined for Float and
+ * Double.
+ *
+ * <h4><a name="ddt">Date/Time</a></h4>
+ *
+ * <p> This conversion may be applied to {@code long}, {@link Long}, {@link
+ * Calendar}, {@link Date} and {@link TemporalAccessor TemporalAccessor}
+ *
+ * <table cellpadding=5 summary="DTConv">
+ *
+ * <tr><td valign="top"> {@code 't'}
+ *     <td valign="top"> <tt>'&#92;u0074'</tt>
+ *     <td> Prefix for date and time conversion characters.
+ * <tr><td valign="top"> {@code 'T'}
+ *     <td valign="top"> <tt>'&#92;u0054'</tt>
+ *     <td> The upper-case variant of {@code 't'}.
+ *
+ * </table>
+ *
+ * <p> The following date and time conversion character suffixes are defined
+ * for the {@code 't'} and {@code 'T'} conversions.  The types are similar to
+ * but not completely identical to those defined by GNU {@code date} and
+ * POSIX {@code strftime(3c)}.  Additional conversion types are provided to
+ * access Java-specific functionality (e.g. {@code 'L'} for milliseconds
+ * within the second).
+ *
+ * <p> The following conversion characters are used for formatting times:
+ *
+ * <table cellpadding=5 summary="time">
+ *
+ * <tr><td valign="top"> {@code 'H'}
+ *     <td valign="top"> <tt>'&#92;u0048'</tt>
+ *     <td> Hour of the day for the 24-hour clock, formatted as two digits with
+ *     a leading zero as necessary i.e. {@code 00 - 23}. {@code 00}
+ *     corresponds to midnight.
+ *
+ * <tr><td valign="top">{@code 'I'}
+ *     <td valign="top"> <tt>'&#92;u0049'</tt>
+ *     <td> Hour for the 12-hour clock, formatted as two digits with a leading
+ *     zero as necessary, i.e.  {@code 01 - 12}.  {@code 01} corresponds to
+ *     one o'clock (either morning or afternoon).
+ *
+ * <tr><td valign="top">{@code 'k'}
+ *     <td valign="top"> <tt>'&#92;u006b'</tt>
+ *     <td> Hour of the day for the 24-hour clock, i.e. {@code 0 - 23}.
+ *     {@code 0} corresponds to midnight.
+ *
+ * <tr><td valign="top">{@code 'l'}
+ *     <td valign="top"> <tt>'&#92;u006c'</tt>
+ *     <td> Hour for the 12-hour clock, i.e. {@code 1 - 12}.  {@code 1}
+ *     corresponds to one o'clock (either morning or afternoon).
+ *
+ * <tr><td valign="top">{@code 'M'}
+ *     <td valign="top"> <tt>'&#92;u004d'</tt>
+ *     <td> Minute within the hour formatted as two digits with a leading zero
+ *     as necessary, i.e.  {@code 00 - 59}.
+ *
+ * <tr><td valign="top">{@code 'S'}
+ *     <td valign="top"> <tt>'&#92;u0053'</tt>
+ *     <td> Seconds within the minute, formatted as two digits with a leading
+ *     zero as necessary, i.e. {@code 00 - 60} ("{@code 60}" is a special
+ *     value required to support leap seconds).
+ *
+ * <tr><td valign="top">{@code 'L'}
+ *     <td valign="top"> <tt>'&#92;u004c'</tt>
+ *     <td> Millisecond within the second formatted as three digits with
+ *     leading zeros as necessary, i.e. {@code 000 - 999}.
+ *
+ * <tr><td valign="top">{@code 'N'}
+ *     <td valign="top"> <tt>'&#92;u004e'</tt>
+ *     <td> Nanosecond within the second, formatted as nine digits with leading
+ *     zeros as necessary, i.e. {@code 000000000 - 999999999}.  The precision
+ *     of this value is limited by the resolution of the underlying operating
+ *     system or hardware.
+ *
+ * <tr><td valign="top">{@code 'p'}
+ *     <td valign="top"> <tt>'&#92;u0070'</tt>
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getAmPmStrings morning or afternoon} marker
+ *     in lower case, e.g."{@code am}" or "{@code pm}".  Use of the
+ *     conversion prefix {@code 'T'} forces this output to upper case.  (Note
+ *     that {@code 'p'} produces lower-case output.  This is different from
+ *     GNU {@code date} and POSIX {@code strftime(3c)} which produce
+ *     upper-case output.)
+ *
+ * <tr><td valign="top">{@code 'z'}
+ *     <td valign="top"> <tt>'&#92;u007a'</tt>
+ *     <td> <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC&nbsp;822</a>
+ *     style numeric time zone offset from GMT, e.g. {@code -0800}.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.
+ *
+ * <tr><td valign="top">{@code 'Z'}
+ *     <td valign="top"> <tt>'&#92;u005a'</tt>
+ *     <td> A string representing the abbreviation for the time zone.  This
+ *     value will be adjusted as necessary for Daylight Saving Time.  For
+ *     {@code long}, {@link Long}, and {@link Date} the time zone used is
+ *     the {@linkplain TimeZone#getDefault() default time zone} for this
+ *     instance of the Java virtual machine.  The Formatter's locale will
+ *     supersede the locale of the argument (if any).
+ *
+ * <tr><td valign="top">{@code 's'}
+ *     <td valign="top"> <tt>'&#92;u0073'</tt>
+ *     <td> Seconds since the beginning of the epoch starting at 1 January 1970
+ *     {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE/1000} to
+ *     {@code Long.MAX_VALUE/1000}.
+ *
+ * <tr><td valign="top">{@code 'Q'}
+ *     <td valign="top"> <tt>'&#92;u004f'</tt>
+ *     <td> Milliseconds since the beginning of the epoch starting at 1 January
+ *     1970 {@code 00:00:00} UTC, i.e. {@code Long.MIN_VALUE} to
+ *     {@code Long.MAX_VALUE}. The precision of this value is limited by
+ *     the resolution of the underlying operating system or hardware.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting dates:
+ *
+ * <table cellpadding=5 summary="date">
+ *
+ * <tr><td valign="top">{@code 'B'}
+ *     <td valign="top"> <tt>'&#92;u0042'</tt>
+ *     <td> Locale-specific {@linkplain java.text.DateFormatSymbols#getMonths
+ *     full month name}, e.g. {@code "January"}, {@code "February"}.
+ *
+ * <tr><td valign="top">{@code 'b'}
+ *     <td valign="top"> <tt>'&#92;u0062'</tt>
+ *     <td> Locale-specific {@linkplain
+ *     java.text.DateFormatSymbols#getShortMonths abbreviated month name},
+ *     e.g. {@code "Jan"}, {@code "Feb"}.
+ *
+ * <tr><td valign="top">{@code 'h'}
+ *     <td valign="top"> <tt>'&#92;u0068'</tt>
+ *     <td> Same as {@code 'b'}.
+ *
+ * <tr><td valign="top">{@code 'A'}
+ *     <td valign="top"> <tt>'&#92;u0041'</tt>
+ *     <td> Locale-specific full name of the {@linkplain
+ *     java.text.DateFormatSymbols#getWeekdays day of the week},
+ *     e.g. {@code "Sunday"}, {@code "Monday"}
+ *
+ * <tr><td valign="top">{@code 'a'}
+ *     <td valign="top"> <tt>'&#92;u0061'</tt>
+ *     <td> Locale-specific short name of the {@linkplain
+ *     java.text.DateFormatSymbols#getShortWeekdays day of the week},
+ *     e.g. {@code "Sun"}, {@code "Mon"}
+ *
+ * <tr><td valign="top">{@code 'C'}
+ *     <td valign="top"> <tt>'&#92;u0043'</tt>
+ *     <td> Four-digit year divided by {@code 100}, formatted as two digits
+ *     with leading zero as necessary, i.e. {@code 00 - 99}
+ *
+ * <tr><td valign="top">{@code 'Y'}
+ *     <td valign="top"> <tt>'&#92;u0059'</tt> <td> Year, formatted to at least
+ *     four digits with leading zeros as necessary, e.g. {@code 0092} equals
+ *     {@code 92} CE for the Gregorian calendar.
+ *
+ * <tr><td valign="top">{@code 'y'}
+ *     <td valign="top"> <tt>'&#92;u0079'</tt>
+ *     <td> Last two digits of the year, formatted with leading zeros as
+ *     necessary, i.e. {@code 00 - 99}.
+ *
+ * <tr><td valign="top">{@code 'j'}
+ *     <td valign="top"> <tt>'&#92;u006a'</tt>
+ *     <td> Day of year, formatted as three digits with leading zeros as
+ *     necessary, e.g. {@code 001 - 366} for the Gregorian calendar.
+ *     {@code 001} corresponds to the first day of the year.
+ *
+ * <tr><td valign="top">{@code 'm'}
+ *     <td valign="top"> <tt>'&#92;u006d'</tt>
+ *     <td> Month, formatted as two digits with leading zeros as necessary,
+ *     i.e. {@code 01 - 13}, where "{@code 01}" is the first month of the
+ *     year and ("{@code 13}" is a special value required to support lunar
+ *     calendars).
+ *
+ * <tr><td valign="top">{@code 'd'}
+ *     <td valign="top"> <tt>'&#92;u0064'</tt>
+ *     <td> Day of month, formatted as two digits with leading zeros as
+ *     necessary, i.e. {@code 01 - 31}, where "{@code 01}" is the first day
+ *     of the month.
+ *
+ * <tr><td valign="top">{@code 'e'}
+ *     <td valign="top"> <tt>'&#92;u0065'</tt>
+ *     <td> Day of month, formatted as two digits, i.e. {@code 1 - 31} where
+ *     "{@code 1}" is the first day of the month.
+ *
+ * </table>
+ *
+ * <p> The following conversion characters are used for formatting common
+ * date/time compositions.
+ *
+ * <table cellpadding=5 summary="composites">
+ *
+ * <tr><td valign="top">{@code 'R'}
+ *     <td valign="top"> <tt>'&#92;u0052'</tt>
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM"}
+ *
+ * <tr><td valign="top">{@code 'T'}
+ *     <td valign="top"> <tt>'&#92;u0054'</tt>
+ *     <td> Time formatted for the 24-hour clock as {@code "%tH:%tM:%tS"}.
+ *
+ * <tr><td valign="top">{@code 'r'}
+ *     <td valign="top"> <tt>'&#92;u0072'</tt>
+ *     <td> Time formatted for the 12-hour clock as {@code "%tI:%tM:%tS
+ *     %Tp"}.  The location of the morning or afternoon marker
+ *     ({@code '%Tp'}) may be locale-dependent.
+ *
+ * <tr><td valign="top">{@code 'D'}
+ *     <td valign="top"> <tt>'&#92;u0044'</tt>
+ *     <td> Date formatted as {@code "%tm/%td/%ty"}.
+ *
+ * <tr><td valign="top">{@code 'F'}
+ *     <td valign="top"> <tt>'&#92;u0046'</tt>
+ *     <td> <a href="http://www.w3.org/TR/NOTE-datetime">ISO&nbsp;8601</a>
+ *     complete date formatted as {@code "%tY-%tm-%td"}.
+ *
+ * <tr><td valign="top">{@code 'c'}
+ *     <td valign="top"> <tt>'&#92;u0063'</tt>
+ *     <td> Date and time formatted as {@code "%ta %tb %td %tT %tZ %tY"},
+ *     e.g. {@code "Sun Jul 20 16:17:00 EDT 1969"}.
+ *
+ * </table>
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If the {@code '#'} flag is given, then a {@link
+ * FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The width is the minimum number of characters to
+ * be written to the output.  If the length of the converted value is less than
+ * the {@code width} then the output will be padded by spaces
+ * (<tt>'&#92;u0020'</tt>) until the total number of characters equals width.
+ * The padding is on the left by default.  If the {@code '-'} flag is given
+ * then the padding will be on the right.  If width is not specified then there
+ * is no minimum.
+ *
+ * <p> The precision is not applicable.  If the precision is specified then an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * <h4><a name="dper">Percent</a></h4>
+ *
+ * <p> The conversion does not correspond to any argument.
+ *
+ * <table cellpadding=5 summary="DTConv">
+ *
+ * <tr><td valign="top">{@code '%'}
+ *     <td> The result is a literal {@code '%'} (<tt>'&#92;u0025'</tt>)
+ *
+ * <p> The width is the minimum number of characters to
+ * be written to the output including the {@code '%'}.  If the length of the
+ * converted value is less than the {@code width} then the output will be
+ * padded by spaces (<tt>'&#92;u0020'</tt>) until the total number of
+ * characters equals width.  The padding is on the left.  If width is not
+ * specified then just the {@code '%'} is output.
+ *
+ * <p> The {@code '-'} flag defined for <a href="#dFlags">General
+ * conversions</a> applies.  If any other flags are provided, then a
+ * {@link FormatFlagsConversionMismatchException} will be thrown.
+ *
+ * <p> The precision is not applicable.  If the precision is specified an
+ * {@link IllegalFormatPrecisionException} will be thrown.
+ *
+ * </table>
+ *
+ * <h4><a name="dls">Line Separator</a></h4>
+ *
+ * <p> The conversion does not correspond to any argument.
+ *
+ * <table cellpadding=5 summary="DTConv">
+ *
+ * <tr><td valign="top">{@code 'n'}
+ *     <td> the platform-specific line separator as returned by {@link
+ *     System#getProperty System.getProperty("line.separator")}.
+ *
+ * </table>
+ *
+ * <p> Flags, width, and precision are not applicable.  If any are provided an
+ * {@link IllegalFormatFlagsException}, {@link IllegalFormatWidthException},
+ * and {@link IllegalFormatPrecisionException}, respectively will be thrown.
+ *
+ * <h4><a name="dpos">Argument Index</a></h4>
+ *
+ * <p> Format specifiers can reference arguments in three ways:
+ *
+ * <ul>
+ *
+ * <li> <i>Explicit indexing</i> is used when the format specifier contains an
+ * argument index.  The argument index is a decimal integer indicating the
+ * position of the argument in the argument list.  The first argument is
+ * referenced by "{@code 1$}", the second by "{@code 2$}", etc.  An argument
+ * may be referenced more than once.
+ *
+ * <p> For example:
+ *
+ * <blockquote><pre>
+ *   formatter.format("%4$s %3$s %2$s %1$s %4$s %3$s %2$s %1$s",
+ *                    "a", "b", "c", "d")
+ *   // -&gt; "d c b a d c b a"
+ * </pre></blockquote>
+ *
+ * <li> <i>Relative indexing</i> is used when the format specifier contains a
+ * {@code '<'} (<tt>'&#92;u003c'</tt>) flag which causes the argument for
+ * the previous format specifier to be re-used.  If there is no previous
+ * argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ * <blockquote><pre>
+ *    formatter.format("%s %s %&lt;s %&lt;s", "a", "b", "c", "d")
+ *    // -&gt; "a b b b"
+ *    // "c" and "d" are ignored because they are not referenced
+ * </pre></blockquote>
+ *
+ * <li> <i>Ordinary indexing</i> is used when the format specifier contains
+ * neither an argument index nor a {@code '<'} flag.  Each format specifier
+ * which uses ordinary indexing is assigned a sequential implicit index into
+ * argument list which is independent of the indices used by explicit or
+ * relative indexing.
+ *
+ * <blockquote><pre>
+ *   formatter.format("%s %s %s %s", "a", "b", "c", "d")
+ *   // -&gt; "a b c d"
+ * </pre></blockquote>
+ *
+ * </ul>
+ *
+ * <p> It is possible to have a format string which uses all forms of indexing,
+ * for example:
+ *
+ * <blockquote><pre>
+ *   formatter.format("%2$s %s %&lt;s %s", "a", "b", "c", "d")
+ *   // -&gt; "b a a b"
+ *   // "c" and "d" are ignored because they are not referenced
+ * </pre></blockquote>
+ *
+ * <p> The maximum number of arguments is limited by the maximum dimension of a
+ * Java array as defined by
+ * <cite>The Java&trade; Virtual Machine Specification</cite>.
+ * If the argument index is does not correspond to an
+ * available argument, then a {@link MissingFormatArgumentException} is thrown.
+ *
+ * <p> If there are more arguments than format specifiers, the extra arguments
+ * are ignored.
+ *
+ * <p> Unless otherwise specified, passing a {@code null} argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @author  Iris Clark
+ * @since 1.5
+ */
+public final class Formatter implements Closeable, Flushable {
+    private Appendable a;
+    private final Locale l;
+
+    private IOException lastException;
+
+    private final char zero;
+    private static double scaleUp;
+
+    // 1 (sign) + 19 (max # sig digits) + 1 ('.') + 1 ('e') + 1 (sign)
+    // + 3 (max # exp digits) + 4 (error) = 30
+    private static final int MAX_FD_CHARS = 30;
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws UnsupportedEncodingException  if the charset is not supported
+     */
+    private static Charset toCharset(String csn)
+        throws UnsupportedEncodingException
+    {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            // UnsupportedEncodingException should be thrown
+            throw new UnsupportedEncodingException(csn);
+        }
+    }
+
+    private static final Appendable nonNullAppendable(Appendable a) {
+        if (a == null)
+            return new StringBuilder();
+
+        return a;
+    }
+
+    /* Private constructors */
+    private Formatter(Locale l, Appendable a) {
+        this.a = a;
+        this.l = l;
+        this.zero = getZero(l);
+    }
+
+    private Formatter(Charset charset, Locale l, File file)
+        throws FileNotFoundException
+    {
+        this(l,
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), charset)));
+    }
+
+    /**
+     * Constructs a new formatter.
+     *
+     * <p> The destination of the formatted output is a {@link StringBuilder}
+     * which may be retrieved by invoking {@link #out out()} and whose
+     * current content may be converted into a string by invoking {@link
+     * #toString toString()}.  The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     */
+    public Formatter() {
+        this(Locale.getDefault(Locale.Category.FORMAT), new StringBuilder());
+    }
+
+    /**
+     * Constructs a new formatter with the specified destination.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  a
+     *         Destination for the formatted output.  If {@code a} is
+     *         {@code null} then a {@link StringBuilder} will be created.
+     */
+    public Formatter(Appendable a) {
+        this(Locale.getDefault(Locale.Category.FORMAT), nonNullAppendable(a));
+    }
+
+    /**
+     * Constructs a new formatter with the specified locale.
+     *
+     * <p> The destination of the formatted output is a {@link StringBuilder}
+     * which may be retrieved by invoking {@link #out out()} and whose current
+     * content may be converted into a string by invoking {@link #toString
+     * toString()}.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     */
+    public Formatter(Locale l) {
+        this(l, new StringBuilder());
+    }
+
+    /**
+     * Constructs a new formatter with the specified destination and locale.
+     *
+     * @param  a
+     *         Destination for the formatted output.  If {@code a} is
+     *         {@code null} then a {@link StringBuilder} will be created.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     */
+    public Formatter(Appendable a, Locale l) {
+        this(l, nonNullAppendable(a));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     */
+    public Formatter(String fileName) throws FileNotFoundException {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name and charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(String fileName, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(fileName, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file name, charset, and
+     * locale.
+     *
+     * @param  fileName
+     *         The name of the file to use as the destination of this
+     *         formatter.  If the file exists then it will be truncated to
+     *         zero size; otherwise, a new file will be created.  The output
+     *         will be written to the file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file name does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(fileName)} denies write
+     *          access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(String fileName, String csn, Locale l)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), l, new File(fileName));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     */
+    public Formatter(File file) throws FileNotFoundException {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file and charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(File file, String csn)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(file, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified file, charset, and
+     * locale.
+     *
+     * @param  file
+     *         The file to use as the destination of this formatter.  If the
+     *         file exists then it will be truncated to zero size; otherwise,
+     *         a new file will be created.  The output will be written to the
+     *         file and is buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  FileNotFoundException
+     *          If the given file object does not denote an existing, writable
+     *          regular file and a new regular file of that name cannot be
+     *          created, or if some other error occurs while opening or
+     *          creating the file
+     *
+     * @throws  SecurityException
+     *          If a security manager is present and {@link
+     *          SecurityManager#checkWrite checkWrite(file.getPath())} denies
+     *          write access to the file
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(File file, String csn, Locale l)
+        throws FileNotFoundException, UnsupportedEncodingException
+    {
+        this(toCharset(csn), l, file);
+    }
+
+    /**
+     * Constructs a new formatter with the specified print stream.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * <p> Characters are written to the given {@link java.io.PrintStream
+     * PrintStream} object and are therefore encoded using that object's
+     * charset.
+     *
+     * @param  ps
+     *         The stream to use as the destination of this formatter.
+     */
+    public Formatter(PrintStream ps) {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             (Appendable)Objects.requireNonNull(ps));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream.
+     *
+     * <p> The charset used is the {@linkplain
+     * java.nio.charset.Charset#defaultCharset() default charset} for this
+     * instance of the Java virtual machine.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     */
+    public Formatter(OutputStream os) {
+        this(Locale.getDefault(Locale.Category.FORMAT),
+             new BufferedWriter(new OutputStreamWriter(os)));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream and
+     * charset.
+     *
+     * <p> The locale used is the {@linkplain
+     * Locale#getDefault(Locale.Category) default locale} for
+     * {@linkplain Locale.Category#FORMAT formatting} for this instance of the Java
+     * virtual machine.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(OutputStream os, String csn)
+        throws UnsupportedEncodingException
+    {
+        this(os, csn, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new formatter with the specified output stream, charset,
+     * and locale.
+     *
+     * @param  os
+     *         The output stream to use as the destination of this formatter.
+     *         The output will be buffered.
+     *
+     * @param  csn
+     *         The name of a supported {@linkplain java.nio.charset.Charset
+     *         charset}
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.
+     *
+     * @throws  UnsupportedEncodingException
+     *          If the named charset is not supported
+     */
+    public Formatter(OutputStream os, String csn, Locale l)
+        throws UnsupportedEncodingException
+    {
+        this(l, new BufferedWriter(new OutputStreamWriter(os, csn)));
+    }
+
+    private static char getZero(Locale l) {
+        if ((l != null) && !l.equals(Locale.US)) {
+            DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+            return dfs.getZeroDigit();
+        } else {
+            return '0';
+        }
+    }
+
+    /**
+     * Returns the locale set by the construction of this formatter.
+     *
+     * <p> The {@link #format(java.util.Locale,String,Object...) format} method
+     * for this object which has a locale argument does not change this value.
+     *
+     * @return  {@code null} if no localization is applied, otherwise a
+     *          locale
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public Locale locale() {
+        ensureOpen();
+        return l;
+    }
+
+    /**
+     * Returns the destination for the output.
+     *
+     * @return  The destination for the output
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public Appendable out() {
+        ensureOpen();
+        return a;
+    }
+
+    /**
+     * Returns the result of invoking {@code toString()} on the destination
+     * for the output.  For example, the following code formats text into a
+     * {@link StringBuilder} then retrieves the resultant string:
+     *
+     * <blockquote><pre>
+     *   Formatter f = new Formatter();
+     *   f.format("Last reboot at %tc", lastRebootDate);
+     *   String s = f.toString();
+     *   // -&gt; s == "Last reboot at Sat Jan 01 00:00:00 PST 2000"
+     * </pre></blockquote>
+     *
+     * <p> An invocation of this method behaves in exactly the same way as the
+     * invocation
+     *
+     * <pre>
+     *     out().toString() </pre>
+     *
+     * <p> Depending on the specification of {@code toString} for the {@link
+     * Appendable}, the returned string may or may not contain the characters
+     * written to the destination.  For instance, buffers typically return
+     * their contents in {@code toString()}, but streams cannot since the
+     * data is discarded.
+     *
+     * @return  The result of invoking {@code toString()} on the destination
+     *          for the output
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public String toString() {
+        ensureOpen();
+        return a.toString();
+    }
+
+    /**
+     * Flushes this formatter.  If the destination implements the {@link
+     * java.io.Flushable} interface, its {@code flush} method will be invoked.
+     *
+     * <p> Flushing a formatter writes any buffered output in the destination
+     * to the underlying stream.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     */
+    public void flush() {
+        ensureOpen();
+        if (a instanceof Flushable) {
+            try {
+                ((Flushable)a).flush();
+            } catch (IOException ioe) {
+                lastException = ioe;
+            }
+        }
+    }
+
+    /**
+     * Closes this formatter.  If the destination implements the {@link
+     * java.io.Closeable} interface, its {@code close} method will be invoked.
+     *
+     * <p> Closing a formatter allows it to release resources it may be holding
+     * (such as open files).  If the formatter is already closed, then invoking
+     * this method has no effect.
+     *
+     * <p> Attempting to invoke any methods except {@link #ioException()} in
+     * this formatter after it has been closed will result in a {@link
+     * FormatterClosedException}.
+     */
+    public void close() {
+        if (a == null)
+            return;
+        try {
+            if (a instanceof Closeable)
+                ((Closeable)a).close();
+        } catch (IOException ioe) {
+            lastException = ioe;
+        } finally {
+            a = null;
+        }
+    }
+
+    private void ensureOpen() {
+        if (a == null)
+            throw new FormatterClosedException();
+    }
+
+    /**
+     * Returns the {@code IOException} last thrown by this formatter's {@link
+     * Appendable}.
+     *
+     * <p> If the destination's {@code append()} method never throws
+     * {@code IOException}, then this method will always return {@code null}.
+     *
+     * @return  The last exception thrown by the Appendable or {@code null} if
+     *          no such exception exists.
+     */
+    public IOException ioException() {
+        return lastException;
+    }
+
+    /**
+     * Writes a formatted string to this object's destination using the
+     * specified format string and arguments.  The locale used is the one
+     * defined during the construction of this formatter.
+     *
+     * @param  format
+     *         A format string as described in <a href="#syntax">Format string
+     *         syntax</a>.
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @throws  IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a href="#detail">Details</a>
+     *          section of the formatter class specification.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     *
+     * @return  This formatter
+     */
+    public Formatter format(String format, Object ... args) {
+        return format(l, format, args);
+    }
+
+    /**
+     * Writes a formatted string to this object's destination using the
+     * specified locale, format string, and arguments.
+     *
+     * @param  l
+     *         The {@linkplain java.util.Locale locale} to apply during
+     *         formatting.  If {@code l} is {@code null} then no localization
+     *         is applied.  This does not change this object's locale that was
+     *         set during construction.
+     *
+     * @param  format
+     *         A format string as described in <a href="#syntax">Format string
+     *         syntax</a>
+     *
+     * @param  args
+     *         Arguments referenced by the format specifiers in the format
+     *         string.  If there are more arguments than format specifiers, the
+     *         extra arguments are ignored.  The maximum number of arguments is
+     *         limited by the maximum dimension of a Java array as defined by
+     *         <cite>The Java&trade; Virtual Machine Specification</cite>.
+     *
+     * @throws  IllegalFormatException
+     *          If a format string contains an illegal syntax, a format
+     *          specifier that is incompatible with the given arguments,
+     *          insufficient arguments given the format string, or other
+     *          illegal conditions.  For specification of all possible
+     *          formatting errors, see the <a href="#detail">Details</a>
+     *          section of the formatter class specification.
+     *
+     * @throws  FormatterClosedException
+     *          If this formatter has been closed by invoking its {@link
+     *          #close()} method
+     *
+     * @return  This formatter
+     */
+    public Formatter format(Locale l, String format, Object ... args) {
+        ensureOpen();
+
+        // index of last argument referenced
+        int last = -1;
+        // last ordinary index
+        int lasto = -1;
+
+        FormatString[] fsa = parse(format);
+        for (int i = 0; i < fsa.length; i++) {
+            FormatString fs = fsa[i];
+            int index = fs.index();
+            try {
+                switch (index) {
+                case -2:  // fixed string, "%n", or "%%"
+                    fs.print(null, l);
+                    break;
+                case -1:  // relative index
+                    if (last < 0 || (args != null && last > args.length - 1))
+                        throw new MissingFormatArgumentException(fs.toString());
+                    fs.print((args == null ? null : args[last]), l);
+                    break;
+                case 0:  // ordinary index
+                    lasto++;
+                    last = lasto;
+                    if (args != null && lasto > args.length - 1)
+                        throw new MissingFormatArgumentException(fs.toString());
+                    fs.print((args == null ? null : args[lasto]), l);
+                    break;
+                default:  // explicit index
+                    last = index - 1;
+                    if (args != null && last > args.length - 1)
+                        throw new MissingFormatArgumentException(fs.toString());
+                    fs.print((args == null ? null : args[last]), l);
+                    break;
+                }
+            } catch (IOException x) {
+                lastException = x;
+            }
+        }
+        return this;
+    }
+
+    // BEGIN Android-changed: changed parse() to manual parsing instead of regex.
+    /**
+     * Finds format specifiers in the format string.
+     */
+    private FormatString[] parse(String s) {
+        ArrayList<FormatString> al = new ArrayList<>();
+        for (int i = 0, len = s.length(); i < len; ) {
+            int nextPercent = s.indexOf('%', i);
+            if (s.charAt(i) != '%') {
+                // This is plain-text part, find the maximal plain-text
+                // sequence and store it.
+                int plainTextStart = i;
+                int plainTextEnd = (nextPercent == -1) ? len: nextPercent;
+                al.add(new FixedString(s.substring(plainTextStart,
+                                                   plainTextEnd)));
+                i = plainTextEnd;
+            } else {
+                // We have a format specifier
+                FormatSpecifierParser fsp = new FormatSpecifierParser(s, i + 1);
+                al.add(fsp.getFormatSpecifier());
+                i = fsp.getEndIdx();
+            }
+        }
+        return al.toArray(new FormatString[al.size()]);
+    }
+
+    /**
+     * Parses the format specifier.
+     * %[argument_index$][flags][width][.precision][t]conversion
+     */
+    private class FormatSpecifierParser {
+        private final String format;
+        private int cursor;
+        private FormatSpecifier fs;
+
+        private String index;
+        private String flags;
+        private String width;
+        private String precision;
+        private String tT;
+        private String conv;
+
+        private static final String FLAGS = ",-(+# 0<";
+
+        public FormatSpecifierParser(String format, int startIdx) {
+            this.format = format;
+            cursor = startIdx;
+            // Index
+            if (nextIsInt()) {
+                String nint = nextInt();
+                if (peek() == '$') {
+                    index = nint;
+                    advance();
+                } else if (nint.charAt(0) == '0') {
+                    // This is a flag, skip to parsing flags.
+                    back(nint.length());
+                } else {
+                    // This is the width, skip to parsing precision.
+                    width = nint;
+                }
+            }
+            // Flags
+            flags = "";
+            while (width == null && FLAGS.indexOf(peek()) >= 0) {
+                flags += advance();
+            }
+            // Width
+            if (width == null && nextIsInt()) {
+                width = nextInt();
+            }
+            // Precision
+            if (peek() == '.') {
+                advance();
+                if (!nextIsInt()) {
+                    throw new IllegalFormatPrecisionException(peek());
+                }
+                precision = nextInt();
+            }
+            // tT
+            if (peek() == 't' || peek() == 'T') {
+                tT = String.valueOf(advance());
+            }
+            // Conversion
+            conv = String.valueOf(advance());
+
+            fs = new FormatSpecifier(index, flags, width, precision, tT, conv);
+        }
+
+        private String nextInt() {
+            int strBegin = cursor;
+            while (nextIsInt()) {
+                advance();
+            }
+            return format.substring(strBegin, cursor);
+        }
+
+        private boolean nextIsInt() {
+            return !isEnd() && Character.isDigit(peek());
+        }
+
+        private char peek() {
+            if (isEnd()) {
+                throw new UnknownFormatConversionException("End of String");
+            }
+            return format.charAt(cursor);
+        }
+
+        private char advance() {
+            if (isEnd()) {
+                throw new UnknownFormatConversionException("End of String");
+            }
+            return format.charAt(cursor++);
+        }
+
+        private void back(int len) {
+            cursor -= len;
+        }
+
+        private boolean isEnd() {
+            return cursor == format.length();
+        }
+
+        public FormatSpecifier getFormatSpecifier() {
+            return fs;
+        }
+
+        public int getEndIdx() {
+            return cursor;
+        }
+    }
+    // END Android-changed: changed parse() to manual parsing instead of regex.
+
+    private interface FormatString {
+        int index();
+        void print(Object arg, Locale l) throws IOException;
+        String toString();
+    }
+
+    private class FixedString implements FormatString {
+        private String s;
+        FixedString(String s) { this.s = s; }
+        public int index() { return -2; }
+        public void print(Object arg, Locale l)
+            throws IOException { a.append(s); }
+        public String toString() { return s; }
+    }
+
+    /**
+     * Enum for {@code BigDecimal} formatting.
+     */
+    public enum BigDecimalLayoutForm {
+        /**
+         * Format the {@code BigDecimal} in computerized scientific notation.
+         */
+        SCIENTIFIC,
+
+        /**
+         * Format the {@code BigDecimal} as a decimal number.
+         */
+        DECIMAL_FLOAT
+    };
+
+    private class FormatSpecifier implements FormatString {
+        private int index = -1;
+        private Flags f = Flags.NONE;
+        private int width;
+        private int precision;
+        private boolean dt = false;
+        private char c;
+
+        private int index(String s) {
+            if (s != null) {
+                try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
+                    // index = Integer.parseInt(s.substring(0, s.length() - 1));
+                    index = Integer.parseInt(s);
+                } catch (NumberFormatException x) {
+                    assert(false);
+                }
+            } else {
+                index = 0;
+            }
+            return index;
+        }
+
+        public int index() {
+            return index;
+        }
+
+        private Flags flags(String s) {
+            f = Flags.parse(s);
+            if (f.contains(Flags.PREVIOUS))
+                index = -1;
+            return f;
+        }
+
+        Flags flags() {
+            return f;
+        }
+
+        private int width(String s) {
+            width = -1;
+            if (s != null) {
+                try {
+                    width  = Integer.parseInt(s);
+                    if (width < 0)
+                        throw new IllegalFormatWidthException(width);
+                } catch (NumberFormatException x) {
+                    assert(false);
+                }
+            }
+            return width;
+        }
+
+        int width() {
+            return width;
+        }
+
+        private int precision(String s) {
+            precision = -1;
+            if (s != null) {
+                try {
+                    // Android-changed: FormatSpecifierParser passes in correct String.
+                    // precision = Integer.parseInt(s.substring(1));
+                    precision = Integer.parseInt(s);
+                    if (precision < 0)
+                        throw new IllegalFormatPrecisionException(precision);
+                } catch (NumberFormatException x) {
+                    assert(false);
+                }
+            }
+            return precision;
+        }
+
+        int precision() {
+            return precision;
+        }
+
+        private char conversion(String s) {
+            c = s.charAt(0);
+            if (!dt) {
+                if (!Conversion.isValid(c))
+                    throw new UnknownFormatConversionException(String.valueOf(c));
+                if (Character.isUpperCase(c))
+                    f.add(Flags.UPPERCASE);
+                c = Character.toLowerCase(c);
+                if (Conversion.isText(c))
+                    index = -2;
+            }
+            return c;
+        }
+
+        private char conversion() {
+            return c;
+        }
+
+        // BEGIN Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+        FormatSpecifier(String indexStr, String flagsStr, String widthStr,
+                        String precisionStr, String tTStr, String convStr) {
+            int idx = 1;
+
+            index(indexStr);
+            flags(flagsStr);
+            width(widthStr);
+            precision(precisionStr);
+
+            if (tTStr != null) {
+                dt = true;
+                if (tTStr.equals("T"))
+                    f.add(Flags.UPPERCASE);
+            }
+
+            conversion(convStr);
+        // END Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+            if (dt)
+                checkDateTime();
+            else if (Conversion.isGeneral(c))
+                checkGeneral();
+            else if (Conversion.isCharacter(c))
+                checkCharacter();
+            else if (Conversion.isInteger(c))
+                checkInteger();
+            else if (Conversion.isFloat(c))
+                checkFloat();
+            else if (Conversion.isText(c))
+                checkText();
+            else
+                throw new UnknownFormatConversionException(String.valueOf(c));
+        }
+
+        public void print(Object arg, Locale l) throws IOException {
+            if (dt) {
+                printDateTime(arg, l);
+                return;
+            }
+            switch(c) {
+            case Conversion.DECIMAL_INTEGER:
+            case Conversion.OCTAL_INTEGER:
+            case Conversion.HEXADECIMAL_INTEGER:
+                printInteger(arg, l);
+                break;
+            case Conversion.SCIENTIFIC:
+            case Conversion.GENERAL:
+            case Conversion.DECIMAL_FLOAT:
+            case Conversion.HEXADECIMAL_FLOAT:
+                printFloat(arg, l);
+                break;
+            case Conversion.CHARACTER:
+            case Conversion.CHARACTER_UPPER:
+                printCharacter(arg);
+                break;
+            case Conversion.BOOLEAN:
+                printBoolean(arg);
+                break;
+            case Conversion.STRING:
+                printString(arg, l);
+                break;
+            case Conversion.HASHCODE:
+                printHashCode(arg);
+                break;
+            case Conversion.LINE_SEPARATOR:
+                a.append(System.lineSeparator());
+                break;
+            case Conversion.PERCENT_SIGN:
+                a.append('%');
+                break;
+            default:
+                assert false;
+            }
+        }
+
+        private void printInteger(Object arg, Locale l) throws IOException {
+            if (arg == null)
+                print("null");
+            else if (arg instanceof Byte)
+                print(((Byte)arg).byteValue(), l);
+            else if (arg instanceof Short)
+                print(((Short)arg).shortValue(), l);
+            else if (arg instanceof Integer)
+                print(((Integer)arg).intValue(), l);
+            else if (arg instanceof Long)
+                print(((Long)arg).longValue(), l);
+            else if (arg instanceof BigInteger)
+                print(((BigInteger)arg), l);
+            else
+                failConversion(c, arg);
+        }
+
+        private void printFloat(Object arg, Locale l) throws IOException {
+            if (arg == null)
+                print("null");
+            else if (arg instanceof Float)
+                print(((Float)arg).floatValue(), l);
+            else if (arg instanceof Double)
+                print(((Double)arg).doubleValue(), l);
+            else if (arg instanceof BigDecimal)
+                print(((BigDecimal)arg), l);
+            else
+                failConversion(c, arg);
+        }
+
+        private void printDateTime(Object arg, Locale l) throws IOException {
+            if (arg == null) {
+                print("null");
+                return;
+            }
+            Calendar cal = null;
+
+            // Instead of Calendar.setLenient(true), perhaps we should
+            // wrap the IllegalArgumentException that might be thrown?
+            if (arg instanceof Long) {
+                // Note that the following method uses an instance of the
+                // default time zone (TimeZone.getDefaultRef().
+                cal = Calendar.getInstance(l == null ? Locale.US : l);
+                cal.setTimeInMillis((Long)arg);
+            } else if (arg instanceof Date) {
+                // Note that the following method uses an instance of the
+                // default time zone (TimeZone.getDefaultRef().
+                cal = Calendar.getInstance(l == null ? Locale.US : l);
+                cal.setTime((Date)arg);
+            } else if (arg instanceof Calendar) {
+                cal = (Calendar) ((Calendar) arg).clone();
+                cal.setLenient(true);
+            } else if (arg instanceof TemporalAccessor) {
+                print((TemporalAccessor) arg, c, l);
+                return;
+            } else {
+                failConversion(c, arg);
+            }
+            // Use the provided locale so that invocations of
+            // localizedMagnitude() use optimizations for null.
+            print(cal, c, l);
+        }
+
+        private void printCharacter(Object arg) throws IOException {
+            if (arg == null) {
+                print("null");
+                return;
+            }
+            String s = null;
+            if (arg instanceof Character) {
+                s = ((Character)arg).toString();
+            } else if (arg instanceof Byte) {
+                byte i = ((Byte)arg).byteValue();
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else if (arg instanceof Short) {
+                short i = ((Short)arg).shortValue();
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else if (arg instanceof Integer) {
+                int i = ((Integer)arg).intValue();
+                if (Character.isValidCodePoint(i))
+                    s = new String(Character.toChars(i));
+                else
+                    throw new IllegalFormatCodePointException(i);
+            } else {
+                failConversion(c, arg);
+            }
+            print(s);
+        }
+
+        private void printString(Object arg, Locale l) throws IOException {
+            if (arg instanceof Formattable) {
+                Formatter fmt = Formatter.this;
+                if (fmt.locale() != l)
+                    fmt = new Formatter(fmt.out(), l);
+                ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision);
+            } else {
+                if (f.contains(Flags.ALTERNATE))
+                    failMismatch(Flags.ALTERNATE, 's');
+                if (arg == null)
+                    print("null");
+                else
+                    print(arg.toString());
+            }
+        }
+
+        private void printBoolean(Object arg) throws IOException {
+            String s;
+            if (arg != null)
+                s = ((arg instanceof Boolean)
+                     ? ((Boolean)arg).toString()
+                     : Boolean.toString(true));
+            else
+                s = Boolean.toString(false);
+            print(s);
+        }
+
+        private void printHashCode(Object arg) throws IOException {
+            String s = (arg == null
+                        ? "null"
+                        : Integer.toHexString(arg.hashCode()));
+            print(s);
+        }
+
+        private void print(String s) throws IOException {
+            if (precision != -1 && precision < s.length())
+                s = s.substring(0, precision);
+            if (f.contains(Flags.UPPERCASE)) {
+                // Android-changed: Use provided locale instead of default, if it is non-null.
+                // s = s.toUpperCase();
+                s = s.toUpperCase(l != null ? l : Locale.getDefault());
+            }
+            a.append(justify(s));
+        }
+
+        private String justify(String s) {
+            if (width == -1)
+                return s;
+            StringBuilder sb = new StringBuilder();
+            boolean pad = f.contains(Flags.LEFT_JUSTIFY);
+            int sp = width - s.length();
+            if (!pad)
+                for (int i = 0; i < sp; i++) sb.append(' ');
+            sb.append(s);
+            if (pad)
+                for (int i = 0; i < sp; i++) sb.append(' ');
+            return sb.toString();
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder("%");
+            // Flags.UPPERCASE is set internally for legal conversions.
+            Flags dupf = f.dup().remove(Flags.UPPERCASE);
+            sb.append(dupf.toString());
+            if (index > 0)
+                sb.append(index).append('$');
+            if (width != -1)
+                sb.append(width);
+            if (precision != -1)
+                sb.append('.').append(precision);
+            if (dt)
+                sb.append(f.contains(Flags.UPPERCASE) ? 'T' : 't');
+            sb.append(f.contains(Flags.UPPERCASE)
+                      ? Character.toUpperCase(c) : c);
+            return sb.toString();
+        }
+
+        private void checkGeneral() {
+            if ((c == Conversion.BOOLEAN || c == Conversion.HASHCODE)
+                && f.contains(Flags.ALTERNATE))
+                failMismatch(Flags.ALTERNATE, c);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+            checkBadFlags(Flags.PLUS, Flags.LEADING_SPACE, Flags.ZERO_PAD,
+                          Flags.GROUP, Flags.PARENTHESES);
+        }
+
+        private void checkDateTime() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            if (!DateTime.isValid(c))
+                throw new UnknownFormatConversionException("t" + c);
+            checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
+                          Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+        }
+
+        private void checkCharacter() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            checkBadFlags(Flags.ALTERNATE, Flags.PLUS, Flags.LEADING_SPACE,
+                          Flags.ZERO_PAD, Flags.GROUP, Flags.PARENTHESES);
+            // '-' requires a width
+            if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                throw new MissingFormatWidthException(toString());
+        }
+
+        private void checkInteger() {
+            checkNumeric();
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+
+            if (c == Conversion.DECIMAL_INTEGER)
+                checkBadFlags(Flags.ALTERNATE);
+            else if (c == Conversion.OCTAL_INTEGER)
+                checkBadFlags(Flags.GROUP);
+            else
+                checkBadFlags(Flags.GROUP);
+        }
+
+        private void checkBadFlags(Flags ... badFlags) {
+            for (int i = 0; i < badFlags.length; i++)
+                if (f.contains(badFlags[i]))
+                    failMismatch(badFlags[i], c);
+        }
+
+        private void checkFloat() {
+            checkNumeric();
+            if (c == Conversion.DECIMAL_FLOAT) {
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                checkBadFlags(Flags.PARENTHESES, Flags.GROUP);
+            } else if (c == Conversion.SCIENTIFIC) {
+                checkBadFlags(Flags.GROUP);
+            } else if (c == Conversion.GENERAL) {
+                checkBadFlags(Flags.ALTERNATE);
+            }
+        }
+
+        private void checkNumeric() {
+            if (width != -1 && width < 0)
+                throw new IllegalFormatWidthException(width);
+
+            if (precision != -1 && precision < 0)
+                throw new IllegalFormatPrecisionException(precision);
+
+            // '-' and '0' require a width
+            if (width == -1
+                && (f.contains(Flags.LEFT_JUSTIFY) || f.contains(Flags.ZERO_PAD)))
+                throw new MissingFormatWidthException(toString());
+
+            // bad combination
+            if ((f.contains(Flags.PLUS) && f.contains(Flags.LEADING_SPACE))
+                || (f.contains(Flags.LEFT_JUSTIFY) && f.contains(Flags.ZERO_PAD)))
+                throw new IllegalFormatFlagsException(f.toString());
+        }
+
+        private void checkText() {
+            if (precision != -1)
+                throw new IllegalFormatPrecisionException(precision);
+            switch (c) {
+            case Conversion.PERCENT_SIGN:
+                if (f.valueOf() != Flags.LEFT_JUSTIFY.valueOf()
+                    && f.valueOf() != Flags.NONE.valueOf())
+                    throw new IllegalFormatFlagsException(f.toString());
+                // '-' requires a width
+                if (width == -1 && f.contains(Flags.LEFT_JUSTIFY))
+                    throw new MissingFormatWidthException(toString());
+                break;
+            case Conversion.LINE_SEPARATOR:
+                if (width != -1)
+                    throw new IllegalFormatWidthException(width);
+                if (f.valueOf() != Flags.NONE.valueOf())
+                    throw new IllegalFormatFlagsException(f.toString());
+                break;
+            default:
+                assert false;
+            }
+        }
+
+        private void print(byte value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 8);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(short value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 16);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(int value, Locale l) throws IOException {
+            long v = value;
+            if (value < 0
+                && (c == Conversion.OCTAL_INTEGER
+                    || c == Conversion.HEXADECIMAL_INTEGER)) {
+                v += (1L << 32);
+                assert v >= 0 : v;
+            }
+            print(v, l);
+        }
+
+        private void print(long value, Locale l) throws IOException {
+
+            StringBuilder sb = new StringBuilder();
+
+            if (c == Conversion.DECIMAL_INTEGER) {
+                boolean neg = value < 0;
+                char[] va;
+                if (value < 0)
+                    va = Long.toString(value, 10).substring(1).toCharArray();
+                else
+                    va = Long.toString(value, 10).toCharArray();
+
+                // leading sign indicator
+                leadingSign(sb, neg);
+
+                // the value
+                localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l);
+
+                // trailing sign indicator
+                trailingSign(sb, neg);
+            } else if (c == Conversion.OCTAL_INTEGER) {
+                checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
+                              Flags.PLUS);
+                String s = Long.toOctalString(value);
+                int len = (f.contains(Flags.ALTERNATE)
+                           ? s.length() + 1
+                           : s.length());
+
+                // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE))
+                    sb.append('0');
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - len; i++) sb.append('0');
+                sb.append(s);
+            } else if (c == Conversion.HEXADECIMAL_INTEGER) {
+                checkBadFlags(Flags.PARENTHESES, Flags.LEADING_SPACE,
+                              Flags.PLUS);
+                String s = Long.toHexString(value);
+                int len = (f.contains(Flags.ALTERNATE)
+                           ? s.length() + 2
+                           : s.length());
+
+                // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE))
+                    sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - len; i++) sb.append('0');
+                if (f.contains(Flags.UPPERCASE))
+                    s = s.toUpperCase();
+                sb.append(s);
+            }
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        // neg := val < 0
+        private StringBuilder leadingSign(StringBuilder sb, boolean neg) {
+            if (!neg) {
+                if (f.contains(Flags.PLUS)) {
+                    sb.append('+');
+                } else if (f.contains(Flags.LEADING_SPACE)) {
+                    sb.append(' ');
+                }
+            } else {
+                if (f.contains(Flags.PARENTHESES))
+                    sb.append('(');
+                else
+                    sb.append('-');
+            }
+            return sb;
+        }
+
+        // neg := val < 0
+        private StringBuilder trailingSign(StringBuilder sb, boolean neg) {
+            if (neg && f.contains(Flags.PARENTHESES))
+                sb.append(')');
+            return sb;
+        }
+
+        private void print(BigInteger value, Locale l) throws IOException {
+            StringBuilder sb = new StringBuilder();
+            boolean neg = value.signum() == -1;
+            BigInteger v = value.abs();
+
+            // leading sign indicator
+            leadingSign(sb, neg);
+
+            // the value
+            if (c == Conversion.DECIMAL_INTEGER) {
+                char[] va = v.toString().toCharArray();
+                localizedMagnitude(sb, va, f, adjustWidth(width, f, neg), l);
+            } else if (c == Conversion.OCTAL_INTEGER) {
+                String s = v.toString(8);
+
+                int len = s.length() + sb.length();
+                if (neg && f.contains(Flags.PARENTHESES))
+                    len++;
+
+                // apply ALTERNATE (radix indicator for octal) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE)) {
+                    len++;
+                    sb.append('0');
+                }
+                if (f.contains(Flags.ZERO_PAD)) {
+                    for (int i = 0; i < width - len; i++)
+                        sb.append('0');
+                }
+                sb.append(s);
+            } else if (c == Conversion.HEXADECIMAL_INTEGER) {
+                String s = v.toString(16);
+
+                int len = s.length() + sb.length();
+                if (neg && f.contains(Flags.PARENTHESES))
+                    len++;
+
+                // apply ALTERNATE (radix indicator for hex) before ZERO_PAD
+                if (f.contains(Flags.ALTERNATE)) {
+                    len += 2;
+                    sb.append(f.contains(Flags.UPPERCASE) ? "0X" : "0x");
+                }
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - len; i++)
+                        sb.append('0');
+                if (f.contains(Flags.UPPERCASE))
+                    s = s.toUpperCase();
+                sb.append(s);
+            }
+
+            // trailing sign indicator
+            trailingSign(sb, (value.signum() == -1));
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        private void print(float value, Locale l) throws IOException {
+            print((double) value, l);
+        }
+
+        private void print(double value, Locale l) throws IOException {
+            StringBuilder sb = new StringBuilder();
+            boolean neg = Double.compare(value, 0.0) == -1;
+
+            if (!Double.isNaN(value)) {
+                double v = Math.abs(value);
+
+                // leading sign indicator
+                leadingSign(sb, neg);
+
+                // the value
+                if (!Double.isInfinite(v))
+                    print(sb, v, l, f, c, precision, neg);
+                else
+                    sb.append(f.contains(Flags.UPPERCASE)
+                              ? "INFINITY" : "Infinity");
+
+                // trailing sign indicator
+                trailingSign(sb, neg);
+            } else {
+                sb.append(f.contains(Flags.UPPERCASE) ? "NAN" : "NaN");
+            }
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        // !Double.isInfinite(value) && !Double.isNaN(value)
+        private void print(StringBuilder sb, double value, Locale l,
+                           Flags f, char c, int precision, boolean neg)
+            throws IOException
+        {
+            if (c == Conversion.SCIENTIFIC) {
+                // Create a new FormattedFloatingDecimal with the desired
+                // precision.
+                int prec = (precision == -1 ? 6 : precision);
+
+                FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.SCIENTIFIC);
+
+                char[] mant = addZeros(fd.getMantissa(), prec);
+
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant = addDot(mant);
+
+                char[] exp = (value == 0.0)
+                    ? new char[] {'+','0','0'} : fd.getExponent();
+
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width - exp.length - 1, f, neg);
+                localizedMagnitude(sb, mant, f, newW, l);
+
+                // BEGIN Android-changed: Use localized exponent separator for %e.
+                Locale separatorLocale = (l != null) ? l : Locale.getDefault();
+                LocaleData localeData = LocaleData.get(separatorLocale);
+                sb.append(f.contains(Flags.UPPERCASE) ?
+                        localeData.exponentSeparator.toUpperCase(separatorLocale) :
+                        localeData.exponentSeparator.toLowerCase(separatorLocale));
+                // END Android-changed: Use localized exponent separator for %e.
+
+                Flags flags = f.dup().remove(Flags.GROUP);
+                char sign = exp[0];
+                assert(sign == '+' || sign == '-');
+                sb.append(sign);
+
+                char[] tmp = new char[exp.length - 1];
+                System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
+                sb.append(localizedMagnitude(null, tmp, flags, -1, l));
+            } else if (c == Conversion.DECIMAL_FLOAT) {
+                // Create a new FormattedFloatingDecimal with the desired
+                // precision.
+                int prec = (precision == -1 ? 6 : precision);
+
+                FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.DECIMAL_FLOAT);
+
+                char[] mant = addZeros(fd.getMantissa(), prec);
+
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant = addDot(mant);
+
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width, f, neg);
+                localizedMagnitude(sb, mant, f, newW, l);
+            } else if (c == Conversion.GENERAL) {
+                int prec = precision;
+                if (precision == -1)
+                    prec = 6;
+                else if (precision == 0)
+                    prec = 1;
+
+                char[] exp;
+                char[] mant;
+                int expRounded;
+                if (value == 0.0) {
+                    exp = null;
+                    mant = new char[] {'0'};
+                    expRounded = 0;
+                } else {
+                    FormattedFloatingDecimal fd
+                        = FormattedFloatingDecimal.valueOf(value, prec,
+                          FormattedFloatingDecimal.Form.GENERAL);
+                    exp = fd.getExponent();
+                    mant = fd.getMantissa();
+                    expRounded = fd.getExponentRounded();
+                }
+
+                if (exp != null) {
+                    prec -= 1;
+                } else {
+                    prec -= expRounded + 1;
+                }
+
+                mant = addZeros(mant, prec);
+                // If the precision is zero and the '#' flag is set, add the
+                // requested decimal point.
+                if (f.contains(Flags.ALTERNATE) && (prec == 0))
+                    mant = addDot(mant);
+
+                int newW = width;
+                if (width != -1) {
+                    if (exp != null)
+                        newW = adjustWidth(width - exp.length - 1, f, neg);
+                    else
+                        newW = adjustWidth(width, f, neg);
+                }
+                localizedMagnitude(sb, mant, f, newW, l);
+
+                if (exp != null) {
+                    sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
+
+                    Flags flags = f.dup().remove(Flags.GROUP);
+                    char sign = exp[0];
+                    assert(sign == '+' || sign == '-');
+                    sb.append(sign);
+
+                    char[] tmp = new char[exp.length - 1];
+                    System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
+                    sb.append(localizedMagnitude(null, tmp, flags, -1, l));
+                }
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                int prec = precision;
+                if (precision == -1)
+                    // assume that we want all of the digits
+                    prec = 0;
+                else if (precision == 0)
+                    prec = 1;
+
+                String s = hexDouble(value, prec);
+
+                char[] va;
+                boolean upper = f.contains(Flags.UPPERCASE);
+                sb.append(upper ? "0X" : "0x");
+
+                if (f.contains(Flags.ZERO_PAD))
+                    for (int i = 0; i < width - s.length() - 2; i++)
+                        sb.append('0');
+
+                int idx = s.indexOf('p');
+                va = s.substring(0, idx).toCharArray();
+                if (upper) {
+                    String tmp = new String(va);
+                    // don't localize hex
+                    tmp = tmp.toUpperCase(Locale.US);
+                    va = tmp.toCharArray();
+                }
+                sb.append(prec != 0 ? addZeros(va, prec) : va);
+                sb.append(upper ? 'P' : 'p');
+                sb.append(s.substring(idx+1));
+            }
+        }
+
+        // Add zeros to the requested precision.
+        private char[] addZeros(char[] v, int prec) {
+            // Look for the dot.  If we don't find one, the we'll need to add
+            // it before we add the zeros.
+            int i;
+            for (i = 0; i < v.length; i++) {
+                if (v[i] == '.')
+                    break;
+            }
+            boolean needDot = false;
+            if (i == v.length) {
+                needDot = true;
+            }
+
+            // Determine existing precision.
+            int outPrec = v.length - i - (needDot ? 0 : 1);
+            assert (outPrec <= prec);
+            if (outPrec == prec)
+                return v;
+
+            // Create new array with existing contents.
+            char[] tmp
+                = new char[v.length + prec - outPrec + (needDot ? 1 : 0)];
+            System.arraycopy(v, 0, tmp, 0, v.length);
+
+            // Add dot if previously determined to be necessary.
+            int start = v.length;
+            if (needDot) {
+                tmp[v.length] = '.';
+                start++;
+            }
+
+            // Add zeros.
+            for (int j = start; j < tmp.length; j++)
+                tmp[j] = '0';
+
+            return tmp;
+        }
+
+        // Method assumes that d > 0.
+        private String hexDouble(double d, int prec) {
+            // Let Double.toHexString handle simple cases
+            if(!Double.isFinite(d) || d == 0.0 || prec == 0 || prec >= 13)
+                // remove "0x"
+                return Double.toHexString(d).substring(2);
+            else {
+                assert(prec >= 1 && prec <= 12);
+
+                int exponent  = Math.getExponent(d);
+                boolean subnormal
+                    = (exponent == DoubleConsts.MIN_EXPONENT - 1);
+
+                // If this is subnormal input so normalize (could be faster to
+                // do as integer operation).
+                if (subnormal) {
+                    scaleUp = Math.scalb(1.0, 54);
+                    d *= scaleUp;
+                    // Calculate the exponent.  This is not just exponent + 54
+                    // since the former is not the normalized exponent.
+                    exponent = Math.getExponent(d);
+                    assert exponent >= DoubleConsts.MIN_EXPONENT &&
+                        exponent <= DoubleConsts.MAX_EXPONENT: exponent;
+                }
+
+                int precision = 1 + prec*4;
+                int shiftDistance
+                    =  DoubleConsts.SIGNIFICAND_WIDTH - precision;
+                assert(shiftDistance >= 1 && shiftDistance < DoubleConsts.SIGNIFICAND_WIDTH);
+
+                long doppel = Double.doubleToLongBits(d);
+                // Deterime the number of bits to keep.
+                long newSignif
+                    = (doppel & (DoubleConsts.EXP_BIT_MASK
+                                 | DoubleConsts.SIGNIF_BIT_MASK))
+                                     >> shiftDistance;
+                // Bits to round away.
+                long roundingBits = doppel & ~(~0L << shiftDistance);
+
+                // To decide how to round, look at the low-order bit of the
+                // working significand, the highest order discarded bit (the
+                // round bit) and whether any of the lower order discarded bits
+                // are nonzero (the sticky bit).
+
+                boolean leastZero = (newSignif & 0x1L) == 0L;
+                boolean round
+                    = ((1L << (shiftDistance - 1) ) & roundingBits) != 0L;
+                boolean sticky  = shiftDistance > 1 &&
+                    (~(1L<< (shiftDistance - 1)) & roundingBits) != 0;
+                if((leastZero && round && sticky) || (!leastZero && round)) {
+                    newSignif++;
+                }
+
+                long signBit = doppel & DoubleConsts.SIGN_BIT_MASK;
+                newSignif = signBit | (newSignif << shiftDistance);
+                double result = Double.longBitsToDouble(newSignif);
+
+                if (Double.isInfinite(result) ) {
+                    // Infinite result generated by rounding
+                    return "1.0p1024";
+                } else {
+                    String res = Double.toHexString(result).substring(2);
+                    if (!subnormal)
+                        return res;
+                    else {
+                        // Create a normalized subnormal string.
+                        int idx = res.indexOf('p');
+                        if (idx == -1) {
+                            // No 'p' character in hex string.
+                            assert false;
+                            return null;
+                        } else {
+                            // Get exponent and append at the end.
+                            String exp = res.substring(idx + 1);
+                            int iexp = Integer.parseInt(exp) -54;
+                            return res.substring(0, idx) + "p"
+                                + Integer.toString(iexp);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void print(BigDecimal value, Locale l) throws IOException {
+            if (c == Conversion.HEXADECIMAL_FLOAT)
+                failConversion(c, value);
+            StringBuilder sb = new StringBuilder();
+            boolean neg = value.signum() == -1;
+            BigDecimal v = value.abs();
+            // leading sign indicator
+            leadingSign(sb, neg);
+
+            // the value
+            print(sb, v, l, f, c, precision, neg);
+
+            // trailing sign indicator
+            trailingSign(sb, neg);
+
+            // justify based on width
+            a.append(justify(sb.toString()));
+        }
+
+        // value > 0
+        private void print(StringBuilder sb, BigDecimal value, Locale l,
+                           Flags f, char c, int precision, boolean neg)
+            throws IOException
+        {
+            if (c == Conversion.SCIENTIFIC) {
+                // Create a new BigDecimal with the desired precision.
+                int prec = (precision == -1 ? 6 : precision);
+                int scale = value.scale();
+                int origPrec = value.precision();
+                int nzeros = 0;
+                int compPrec;
+
+                if (prec > origPrec - 1) {
+                    compPrec = origPrec;
+                    nzeros = prec - (origPrec - 1);
+                } else {
+                    compPrec = prec + 1;
+                }
+
+                MathContext mc = new MathContext(compPrec);
+                BigDecimal v
+                    = new BigDecimal(value.unscaledValue(), scale, mc);
+
+                BigDecimalLayout bdl
+                    = new BigDecimalLayout(v.unscaledValue(), v.scale(),
+                                           BigDecimalLayoutForm.SCIENTIFIC);
+
+                char[] mant = bdl.mantissa();
+
+                // Add a decimal point if necessary.  The mantissa may not
+                // contain a decimal point if the scale is zero (the internal
+                // representation has no fractional part) or the original
+                // precision is one. Append a decimal point if '#' is set or if
+                // we require zero padding to get to the requested precision.
+                if ((origPrec == 1 || !bdl.hasDot())
+                    && (nzeros > 0 || (f.contains(Flags.ALTERNATE))))
+                    mant = addDot(mant);
+
+                // Add trailing zeros in the case precision is greater than
+                // the number of available digits after the decimal separator.
+                mant = trailingZeros(mant, nzeros);
+
+                char[] exp = bdl.exponent();
+                int newW = width;
+                if (width != -1)
+                    newW = adjustWidth(width - exp.length - 1, f, neg);
+                localizedMagnitude(sb, mant, f, newW, l);
+
+                sb.append(f.contains(Flags.UPPERCASE) ? 'E' : 'e');
+
+                Flags flags = f.dup().remove(Flags.GROUP);
+                char sign = exp[0];
+                assert(sign == '+' || sign == '-');
+                sb.append(exp[0]);
+
+                char[] tmp = new char[exp.length - 1];
+                System.arraycopy(exp, 1, tmp, 0, exp.length - 1);
+                sb.append(localizedMagnitude(null, tmp, flags, -1, l));
+            } else if (c == Conversion.DECIMAL_FLOAT) {
+                // Create a new BigDecimal with the desired precision.
+                int prec = (precision == -1 ? 6 : precision);
+                int scale = value.scale();
+
+                if (scale > prec) {
+                    // more "scale" digits than the requested "precision"
+                    int compPrec = value.precision();
+                    if (compPrec <= scale) {
+                        // case of 0.xxxxxx
+                        value = value.setScale(prec, RoundingMode.HALF_UP);
+                    } else {
+                        compPrec -= (scale - prec);
+                        value = new BigDecimal(value.unscaledValue(),
+                                               scale,
+                                               new MathContext(compPrec));
+                    }
+                }
+                BigDecimalLayout bdl = new BigDecimalLayout(
+                                           value.unscaledValue(),
+                                           value.scale(),
+                                           BigDecimalLayoutForm.DECIMAL_FLOAT);
+
+                char mant[] = bdl.mantissa();
+                int nzeros = (bdl.scale() < prec ? prec - bdl.scale() : 0);
+
+                // Add a decimal point if necessary.  The mantissa may not
+                // contain a decimal point if the scale is zero (the internal
+                // representation has no fractional part).  Append a decimal
+                // point if '#' is set or we require zero padding to get to the
+                // requested precision.
+                if (bdl.scale() == 0 && (f.contains(Flags.ALTERNATE) || nzeros > 0))
+                    mant = addDot(bdl.mantissa());
+
+                // Add trailing zeros if the precision is greater than the
+                // number of available digits after the decimal separator.
+                mant = trailingZeros(mant, nzeros);
+
+                localizedMagnitude(sb, mant, f, adjustWidth(width, f, neg), l);
+            } else if (c == Conversion.GENERAL) {
+                int prec = precision;
+                if (precision == -1)
+                    prec = 6;
+                else if (precision == 0)
+                    prec = 1;
+
+                BigDecimal tenToTheNegFour = BigDecimal.valueOf(1, 4);
+                BigDecimal tenToThePrec = BigDecimal.valueOf(1, -prec);
+                if ((value.equals(BigDecimal.ZERO))
+                    || ((value.compareTo(tenToTheNegFour) != -1)
+                        && (value.compareTo(tenToThePrec) == -1))) {
+
+                    int e = - value.scale()
+                        + (value.unscaledValue().toString().length() - 1);
+
+                    // xxx.yyy
+                    //   g precision (# sig digits) = #x + #y
+                    //   f precision = #y
+                    //   exponent = #x - 1
+                    // => f precision = g precision - exponent - 1
+                    // 0.000zzz
+                    //   g precision (# sig digits) = #z
+                    //   f precision = #0 (after '.') + #z
+                    //   exponent = - #0 (after '.') - 1
+                    // => f precision = g precision - exponent - 1
+                    prec = prec - e - 1;
+
+                    print(sb, value, l, f, Conversion.DECIMAL_FLOAT, prec,
+                          neg);
+                } else {
+                    print(sb, value, l, f, Conversion.SCIENTIFIC, prec - 1, neg);
+                }
+            } else if (c == Conversion.HEXADECIMAL_FLOAT) {
+                // This conversion isn't supported.  The error should be
+                // reported earlier.
+                assert false;
+            }
+        }
+
+        private class BigDecimalLayout {
+            private StringBuilder mant;
+            private StringBuilder exp;
+            private boolean dot = false;
+            private int scale;
+
+            public BigDecimalLayout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
+                layout(intVal, scale, form);
+            }
+
+            public boolean hasDot() {
+                return dot;
+            }
+
+            public int scale() {
+                return scale;
+            }
+
+            // char[] with canonical string representation
+            public char[] layoutChars() {
+                StringBuilder sb = new StringBuilder(mant);
+                if (exp != null) {
+                    sb.append('E');
+                    sb.append(exp);
+                }
+                return toCharArray(sb);
+            }
+
+            public char[] mantissa() {
+                return toCharArray(mant);
+            }
+
+            // The exponent will be formatted as a sign ('+' or '-') followed
+            // by the exponent zero-padded to include at least two digits.
+            public char[] exponent() {
+                return toCharArray(exp);
+            }
+
+            private char[] toCharArray(StringBuilder sb) {
+                if (sb == null)
+                    return null;
+                char[] result = new char[sb.length()];
+                sb.getChars(0, result.length, result, 0);
+                return result;
+            }
+
+            private void layout(BigInteger intVal, int scale, BigDecimalLayoutForm form) {
+                char coeff[] = intVal.toString().toCharArray();
+                this.scale = scale;
+
+                // Construct a buffer, with sufficient capacity for all cases.
+                // If E-notation is needed, length will be: +1 if negative, +1
+                // if '.' needed, +2 for "E+", + up to 10 for adjusted
+                // exponent.  Otherwise it could have +1 if negative, plus
+                // leading "0.00000"
+                mant = new StringBuilder(coeff.length + 14);
+
+                if (scale == 0) {
+                    int len = coeff.length;
+                    if (len > 1) {
+                        mant.append(coeff[0]);
+                        if (form == BigDecimalLayoutForm.SCIENTIFIC) {
+                            mant.append('.');
+                            dot = true;
+                            mant.append(coeff, 1, len - 1);
+                            exp = new StringBuilder("+");
+                            if (len < 10)
+                                exp.append("0").append(len - 1);
+                            else
+                                exp.append(len - 1);
+                        } else {
+                            mant.append(coeff, 1, len - 1);
+                        }
+                    } else {
+                        mant.append(coeff);
+                        if (form == BigDecimalLayoutForm.SCIENTIFIC)
+                            exp = new StringBuilder("+00");
+                    }
+                    return;
+                }
+                long adjusted = -(long) scale + (coeff.length - 1);
+                if (form == BigDecimalLayoutForm.DECIMAL_FLOAT) {
+                    // count of padding zeros
+                    int pad = scale - coeff.length;
+                    if (pad >= 0) {
+                        // 0.xxx form
+                        mant.append("0.");
+                        dot = true;
+                        for (; pad > 0 ; pad--) mant.append('0');
+                        mant.append(coeff);
+                    } else {
+                        if (-pad < coeff.length) {
+                            // xx.xx form
+                            mant.append(coeff, 0, -pad);
+                            mant.append('.');
+                            dot = true;
+                            mant.append(coeff, -pad, scale);
+                        } else {
+                            // xx form
+                            mant.append(coeff, 0, coeff.length);
+                            for (int i = 0; i < -scale; i++)
+                                mant.append('0');
+                            this.scale = 0;
+                        }
+                    }
+                } else {
+                    // x.xxx form
+                    mant.append(coeff[0]);
+                    if (coeff.length > 1) {
+                        mant.append('.');
+                        dot = true;
+                        mant.append(coeff, 1, coeff.length-1);
+                    }
+                    exp = new StringBuilder();
+                    if (adjusted != 0) {
+                        long abs = Math.abs(adjusted);
+                        // require sign
+                        exp.append(adjusted < 0 ? '-' : '+');
+                        if (abs < 10)
+                            exp.append('0');
+                        exp.append(abs);
+                    } else {
+                        exp.append("+00");
+                    }
+                }
+            }
+        }
+
+        private int adjustWidth(int width, Flags f, boolean neg) {
+            int newW = width;
+            if (newW != -1 && neg && f.contains(Flags.PARENTHESES))
+                newW--;
+            return newW;
+        }
+
+        // Add a '.' to th mantissa if required
+        private char[] addDot(char[] mant) {
+            char[] tmp = mant;
+            tmp = new char[mant.length + 1];
+            System.arraycopy(mant, 0, tmp, 0, mant.length);
+            tmp[tmp.length - 1] = '.';
+            return tmp;
+        }
+
+        // Add trailing zeros in the case precision is greater than the number
+        // of available digits after the decimal separator.
+        private char[] trailingZeros(char[] mant, int nzeros) {
+            char[] tmp = mant;
+            if (nzeros > 0) {
+                tmp = new char[mant.length + nzeros];
+                System.arraycopy(mant, 0, tmp, 0, mant.length);
+                for (int i = mant.length; i < tmp.length; i++)
+                    tmp[i] = '0';
+            }
+            return tmp;
+        }
+
+        private void print(Calendar t, char c, Locale l)  throws IOException
+        {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+
+            // justify based on width
+            String s = justify(sb.toString());
+            if (f.contains(Flags.UPPERCASE))
+                s = s.toUpperCase();
+
+            a.append(s);
+        }
+
+        private Appendable print(StringBuilder sb, Calendar t, char c,
+                                 Locale l)
+            throws IOException
+        {
+            if (sb == null)
+                sb = new StringBuilder();
+            switch (c) {
+            case DateTime.HOUR_OF_DAY_0: // 'H' (00 - 23)
+            case DateTime.HOUR_0:        // 'I' (01 - 12)
+            case DateTime.HOUR_OF_DAY:   // 'k' (0 - 23) -- like H
+            case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                int i = t.get(Calendar.HOUR_OF_DAY);
+                if (c == DateTime.HOUR_0 || c == DateTime.HOUR)
+                    i = (i == 0 || i == 12 ? 12 : i % 12);
+                Flags flags = (c == DateTime.HOUR_OF_DAY_0
+                               || c == DateTime.HOUR_0
+                               ? Flags.ZERO_PAD
+                               : Flags.NONE);
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.MINUTE:      { // 'M' (00 - 59)
+                int i = t.get(Calendar.MINUTE);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                int i = t.get(Calendar.MILLISECOND) * 1000000;
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 9, l));
+                break;
+            }
+            case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                int i = t.get(Calendar.MILLISECOND);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                break;
+            }
+            case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                long i = t.getTimeInMillis();
+                Flags flags = Flags.NONE;
+                sb.append(localizedMagnitude(null, i, flags, width, l));
+                break;
+            }
+            case DateTime.AM_PM:       { // 'p' (am or pm)
+                // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                String[] ampm = { "AM", "PM" };
+                if (l != null && l != Locale.US) {
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                    ampm = dfs.getAmPmStrings();
+                }
+                String s = ampm[t.get(Calendar.AM_PM)];
+                sb.append(s.toLowerCase(l != null ? l : Locale.US));
+                break;
+            }
+            case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                long i = t.getTimeInMillis() / 1000;
+                Flags flags = Flags.NONE;
+                sb.append(localizedMagnitude(null, i, flags, width, l));
+                break;
+            }
+            case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                int i = t.get(Calendar.SECOND);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                int i = t.get(Calendar.ZONE_OFFSET) + t.get(Calendar.DST_OFFSET);
+                boolean neg = i < 0;
+                sb.append(neg ? '-' : '+');
+                if (neg)
+                    i = -i;
+                int min = i / 60000;
+                // combine minute and hour into a single integer
+                int offset = (min / 60) * 100 + (min % 60);
+                Flags flags = Flags.ZERO_PAD;
+
+                sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                break;
+            }
+            case DateTime.ZONE:        { // 'Z' (symbol)
+                TimeZone tz = t.getTimeZone();
+                sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0),
+                                           TimeZone.SHORT,
+                                            (l == null) ? Locale.US : l));
+                break;
+            }
+
+            // Date
+            case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+            case DateTime.NAME_OF_DAY:          { // 'A'
+                int i = t.get(Calendar.DAY_OF_WEEK);
+                Locale lt = ((l == null) ? Locale.US : l);
+                DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                if (c == DateTime.NAME_OF_DAY)
+                    sb.append(dfs.getWeekdays()[i]);
+                else
+                    sb.append(dfs.getShortWeekdays()[i]);
+                break;
+            }
+            case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+            case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+            case DateTime.NAME_OF_MONTH:        { // 'B'
+                int i = t.get(Calendar.MONTH);
+                Locale lt = ((l == null) ? Locale.US : l);
+                DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                if (c == DateTime.NAME_OF_MONTH)
+                    sb.append(dfs.getMonths()[i]);
+                else
+                    sb.append(dfs.getShortMonths()[i]);
+                break;
+            }
+            case DateTime.CENTURY:                // 'C' (00 - 99)
+            case DateTime.YEAR_2:                 // 'y' (00 - 99)
+            case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                int i = t.get(Calendar.YEAR);
+                int size = 2;
+                switch (c) {
+                case DateTime.CENTURY:
+                    i /= 100;
+                    break;
+                case DateTime.YEAR_2:
+                    i %= 100;
+                    break;
+                case DateTime.YEAR_4:
+                    size = 4;
+                    break;
+                }
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, size, l));
+                break;
+            }
+            case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+            case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                int i = t.get(Calendar.DATE);
+                Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                               ? Flags.ZERO_PAD
+                               : Flags.NONE);
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+            case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                int i = t.get(Calendar.DAY_OF_YEAR);
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 3, l));
+                break;
+            }
+            case DateTime.MONTH:                { // 'm' (01 - 12)
+                int i = t.get(Calendar.MONTH) + 1;
+                Flags flags = Flags.ZERO_PAD;
+                sb.append(localizedMagnitude(null, i, flags, 2, l));
+                break;
+            }
+
+            // Composites
+            case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+            case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                char sep = ':';
+                print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                print(sb, t, DateTime.MINUTE, l);
+                if (c == DateTime.TIME) {
+                    sb.append(sep);
+                    print(sb, t, DateTime.SECOND, l);
+                }
+                break;
+            }
+            case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                char sep = ':';
+                print(sb, t, DateTime.HOUR_0, l).append(sep);
+                print(sb, t, DateTime.MINUTE, l).append(sep);
+                print(sb, t, DateTime.SECOND, l).append(' ');
+                // this may be in wrong place for some locales
+                StringBuilder tsb = new StringBuilder();
+                print(tsb, t, DateTime.AM_PM, l);
+                sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
+                break;
+            }
+            case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                char sep = ' ';
+                print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(sb, t, DateTime.TIME, l).append(sep);
+                print(sb, t, DateTime.ZONE, l).append(sep);
+                print(sb, t, DateTime.YEAR_4, l);
+                break;
+            }
+            case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                char sep = '/';
+                print(sb, t, DateTime.MONTH, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                print(sb, t, DateTime.YEAR_2, l);
+                break;
+            }
+            case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                char sep = '-';
+                print(sb, t, DateTime.YEAR_4, l).append(sep);
+                print(sb, t, DateTime.MONTH, l).append(sep);
+                print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                break;
+            }
+            default:
+                assert false;
+            }
+            return sb;
+        }
+
+        private void print(TemporalAccessor t, char c, Locale l)  throws IOException {
+            StringBuilder sb = new StringBuilder();
+            print(sb, t, c, l);
+            // justify based on width
+            String s = justify(sb.toString());
+            if (f.contains(Flags.UPPERCASE))
+                s = s.toUpperCase();
+            a.append(s);
+        }
+
+        private Appendable print(StringBuilder sb, TemporalAccessor t, char c,
+                                 Locale l) throws IOException {
+            if (sb == null)
+                sb = new StringBuilder();
+            try {
+                switch (c) {
+                case DateTime.HOUR_OF_DAY_0: {  // 'H' (00 - 23)
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_OF_DAY: {   // 'k' (0 - 23) -- like H
+                    int i = t.get(ChronoField.HOUR_OF_DAY);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.HOUR_0:      {  // 'I' (01 - 12)
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.ZERO_PAD, 2, l));
+                    break;
+                }
+                case DateTime.HOUR:        { // 'l' (1 - 12) -- like I
+                    int i = t.get(ChronoField.CLOCK_HOUR_OF_AMPM);
+                    sb.append(localizedMagnitude(null, i, Flags.NONE, 2, l));
+                    break;
+                }
+                case DateTime.MINUTE:      { // 'M' (00 - 59)
+                    int i = t.get(ChronoField.MINUTE_OF_HOUR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.NANOSECOND:  { // 'N' (000000000 - 999999999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND) * 1000000;
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 9, l));
+                    break;
+                }
+                case DateTime.MILLISECOND: { // 'L' (000 - 999)
+                    int i = t.get(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MILLISECOND_SINCE_EPOCH: { // 'Q' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS) * 1000L +
+                             t.getLong(ChronoField.MILLI_OF_SECOND);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.AM_PM:       { // 'p' (am or pm)
+                    // Calendar.AM = 0, Calendar.PM = 1, LocaleElements defines upper
+                    String[] ampm = { "AM", "PM" };
+                    if (l != null && l != Locale.US) {
+                        DateFormatSymbols dfs = DateFormatSymbols.getInstance(l);
+                        ampm = dfs.getAmPmStrings();
+                    }
+                    String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
+                    sb.append(s.toLowerCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
+                    long i = t.getLong(ChronoField.INSTANT_SECONDS);
+                    Flags flags = Flags.NONE;
+                    sb.append(localizedMagnitude(null, i, flags, width, l));
+                    break;
+                }
+                case DateTime.SECOND:      { // 'S' (00 - 60 - leap second)
+                    int i = t.get(ChronoField.SECOND_OF_MINUTE);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.ZONE_NUMERIC: { // 'z' ({-|+}####) - ls minus?
+                    int i = t.get(ChronoField.OFFSET_SECONDS);
+                    boolean neg = i < 0;
+                    sb.append(neg ? '-' : '+');
+                    if (neg)
+                        i = -i;
+                    int min = i / 60;
+                    // combine minute and hour into a single integer
+                    int offset = (min / 60) * 100 + (min % 60);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, offset, flags, 4, l));
+                    break;
+                }
+                case DateTime.ZONE:        { // 'Z' (symbol)
+                    ZoneId zid = t.query(TemporalQueries.zone());
+                    if (zid == null) {
+                        throw new IllegalFormatConversionException(c, t.getClass());
+                    }
+                    if (!(zid instanceof ZoneOffset) &&
+                        t.isSupported(ChronoField.INSTANT_SECONDS)) {
+                        Instant instant = Instant.from(t);
+                        sb.append(TimeZone.getTimeZone(zid.getId())
+                                          .getDisplayName(zid.getRules().isDaylightSavings(instant),
+                                                          TimeZone.SHORT,
+                                                          (l == null) ? Locale.US : l));
+                        break;
+                    }
+                    sb.append(zid.getId());
+                    break;
+                }
+                // Date
+                case DateTime.NAME_OF_DAY_ABBREV:     // 'a'
+                case DateTime.NAME_OF_DAY:          { // 'A'
+                    int i = t.get(ChronoField.DAY_OF_WEEK) % 7 + 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_DAY)
+                        sb.append(dfs.getWeekdays()[i]);
+                    else
+                        sb.append(dfs.getShortWeekdays()[i]);
+                    break;
+                }
+                case DateTime.NAME_OF_MONTH_ABBREV:   // 'b'
+                case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
+                case DateTime.NAME_OF_MONTH:        { // 'B'
+                    int i = t.get(ChronoField.MONTH_OF_YEAR) - 1;
+                    Locale lt = ((l == null) ? Locale.US : l);
+                    DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
+                    if (c == DateTime.NAME_OF_MONTH)
+                        sb.append(dfs.getMonths()[i]);
+                    else
+                        sb.append(dfs.getShortMonths()[i]);
+                    break;
+                }
+                case DateTime.CENTURY:                // 'C' (00 - 99)
+                case DateTime.YEAR_2:                 // 'y' (00 - 99)
+                case DateTime.YEAR_4:               { // 'Y' (0000 - 9999)
+                    int i = t.get(ChronoField.YEAR_OF_ERA);
+                    int size = 2;
+                    switch (c) {
+                    case DateTime.CENTURY:
+                        i /= 100;
+                        break;
+                    case DateTime.YEAR_2:
+                        i %= 100;
+                        break;
+                    case DateTime.YEAR_4:
+                        size = 4;
+                        break;
+                    }
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, size, l));
+                    break;
+                }
+                case DateTime.DAY_OF_MONTH_0:         // 'd' (01 - 31)
+                case DateTime.DAY_OF_MONTH:         { // 'e' (1 - 31) -- like d
+                    int i = t.get(ChronoField.DAY_OF_MONTH);
+                    Flags flags = (c == DateTime.DAY_OF_MONTH_0
+                                   ? Flags.ZERO_PAD
+                                   : Flags.NONE);
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+                case DateTime.DAY_OF_YEAR:          { // 'j' (001 - 366)
+                    int i = t.get(ChronoField.DAY_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 3, l));
+                    break;
+                }
+                case DateTime.MONTH:                { // 'm' (01 - 12)
+                    int i = t.get(ChronoField.MONTH_OF_YEAR);
+                    Flags flags = Flags.ZERO_PAD;
+                    sb.append(localizedMagnitude(null, i, flags, 2, l));
+                    break;
+                }
+
+                // Composites
+                case DateTime.TIME:         // 'T' (24 hour hh:mm:ss - %tH:%tM:%tS)
+                case DateTime.TIME_24_HOUR:    { // 'R' (hh:mm same as %H:%M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_OF_DAY_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l);
+                    if (c == DateTime.TIME) {
+                        sb.append(sep);
+                        print(sb, t, DateTime.SECOND, l);
+                    }
+                    break;
+                }
+                case DateTime.TIME_12_HOUR:    { // 'r' (hh:mm:ss [AP]M)
+                    char sep = ':';
+                    print(sb, t, DateTime.HOUR_0, l).append(sep);
+                    print(sb, t, DateTime.MINUTE, l).append(sep);
+                    print(sb, t, DateTime.SECOND, l).append(' ');
+                    // this may be in wrong place for some locales
+                    StringBuilder tsb = new StringBuilder();
+                    print(tsb, t, DateTime.AM_PM, l);
+                    sb.append(tsb.toString().toUpperCase(l != null ? l : Locale.US));
+                    break;
+                }
+                case DateTime.DATE_TIME:    { // 'c' (Sat Nov 04 12:02:33 EST 1999)
+                    char sep = ' ';
+                    print(sb, t, DateTime.NAME_OF_DAY_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.NAME_OF_MONTH_ABBREV, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.TIME, l).append(sep);
+                    print(sb, t, DateTime.ZONE, l).append(sep);
+                    print(sb, t, DateTime.YEAR_4, l);
+                    break;
+                }
+                case DateTime.DATE:            { // 'D' (mm/dd/yy)
+                    char sep = '/';
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l).append(sep);
+                    print(sb, t, DateTime.YEAR_2, l);
+                    break;
+                }
+                case DateTime.ISO_STANDARD_DATE: { // 'F' (%Y-%m-%d)
+                    char sep = '-';
+                    print(sb, t, DateTime.YEAR_4, l).append(sep);
+                    print(sb, t, DateTime.MONTH, l).append(sep);
+                    print(sb, t, DateTime.DAY_OF_MONTH_0, l);
+                    break;
+                }
+                default:
+                    assert false;
+                }
+            } catch (DateTimeException x) {
+                throw new IllegalFormatConversionException(c, t.getClass());
+            }
+            return sb;
+        }
+
+        // -- Methods to support throwing exceptions --
+
+        private void failMismatch(Flags f, char c) {
+            String fs = f.toString();
+            throw new FormatFlagsConversionMismatchException(fs, c);
+        }
+
+        private void failConversion(char c, Object arg) {
+            throw new IllegalFormatConversionException(c, arg.getClass());
+        }
+
+        private char getZero(Locale l) {
+            if ((l != null) &&  !l.equals(locale())) {
+                DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                return dfs.getZeroDigit();
+            }
+            return zero;
+        }
+
+        private StringBuilder
+            localizedMagnitude(StringBuilder sb, long value, Flags f,
+                               int width, Locale l)
+        {
+            char[] va = Long.toString(value, 10).toCharArray();
+            return localizedMagnitude(sb, va, f, width, l);
+        }
+
+        private StringBuilder
+            localizedMagnitude(StringBuilder sb, char[] value, Flags f,
+                               int width, Locale l)
+        {
+            if (sb == null)
+                sb = new StringBuilder();
+            int begin = sb.length();
+
+            char zero = getZero(l);
+
+            // determine localized grouping separator and size
+            char grpSep = '\0';
+            int  grpSize = -1;
+            char decSep = '\0';
+
+            int len = value.length;
+            int dot = len;
+            for (int j = 0; j < len; j++) {
+                if (value[j] == '.') {
+                    dot = j;
+                    break;
+                }
+            }
+
+            if (dot < len) {
+                if (l == null || l.equals(Locale.US)) {
+                    decSep  = '.';
+                } else {
+                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                    decSep  = dfs.getDecimalSeparator();
+                }
+            }
+
+            if (f.contains(Flags.GROUP)) {
+                if (l == null || l.equals(Locale.US)) {
+                    grpSep = ',';
+                    grpSize = 3;
+                } else {
+                    DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
+                    grpSep = dfs.getGroupingSeparator();
+                    DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
+                    grpSize = df.getGroupingSize();
+                    // BEGIN Android-changed: Fix division by zero if group separator is not clear.
+                    // http://b/33245708
+                    // Some locales have a group separator but also patterns without groups.
+                    // If we do not clear the group separator in these cases a divide by zero
+                    // is thrown when determining where to place the separators.
+                    if (!df.isGroupingUsed() || df.getGroupingSize() == 0) {
+                        grpSep = '\0';
+                    }
+                    // END Android-changed: Fix division by zero if group separator is not clear.
+                }
+            }
+
+            // localize the digits inserting group separators as necessary
+            for (int j = 0; j < len; j++) {
+                if (j == dot) {
+                    sb.append(decSep);
+                    // no more group separators after the decimal separator
+                    grpSep = '\0';
+                    continue;
+                }
+
+                char c = value[j];
+                sb.append((char) ((c - '0') + zero));
+                if (grpSep != '\0' && j != dot - 1 && ((dot - j) % grpSize == 1))
+                    sb.append(grpSep);
+            }
+
+            // apply zero padding
+            len = sb.length();
+            if (width != -1 && f.contains(Flags.ZERO_PAD))
+                for (int k = 0; k < width - len; k++)
+                    sb.insert(begin, zero);
+
+            return sb;
+        }
+    }
+
+    private static class Flags {
+        private int flags;
+
+        static final Flags NONE          = new Flags(0);      // ''
+
+        // duplicate declarations from Formattable.java
+        static final Flags LEFT_JUSTIFY  = new Flags(1<<0);   // '-'
+        static final Flags UPPERCASE     = new Flags(1<<1);   // '^'
+        static final Flags ALTERNATE     = new Flags(1<<2);   // '#'
+
+        // numerics
+        static final Flags PLUS          = new Flags(1<<3);   // '+'
+        static final Flags LEADING_SPACE = new Flags(1<<4);   // ' '
+        static final Flags ZERO_PAD      = new Flags(1<<5);   // '0'
+        static final Flags GROUP         = new Flags(1<<6);   // ','
+        static final Flags PARENTHESES   = new Flags(1<<7);   // '('
+
+        // indexing
+        static final Flags PREVIOUS      = new Flags(1<<8);   // '<'
+
+        private Flags(int f) {
+            flags = f;
+        }
+
+        public int valueOf() {
+            return flags;
+        }
+
+        public boolean contains(Flags f) {
+            return (flags & f.valueOf()) == f.valueOf();
+        }
+
+        public Flags dup() {
+            return new Flags(flags);
+        }
+
+        private Flags add(Flags f) {
+            flags |= f.valueOf();
+            return this;
+        }
+
+        public Flags remove(Flags f) {
+            flags &= ~f.valueOf();
+            return this;
+        }
+
+        public static Flags parse(String s) {
+            char[] ca = s.toCharArray();
+            Flags f = new Flags(0);
+            for (int i = 0; i < ca.length; i++) {
+                Flags v = parse(ca[i]);
+                if (f.contains(v))
+                    throw new DuplicateFormatFlagsException(v.toString());
+                f.add(v);
+            }
+            return f;
+        }
+
+        // parse those flags which may be provided by users
+        private static Flags parse(char c) {
+            switch (c) {
+            case '-': return LEFT_JUSTIFY;
+            case '#': return ALTERNATE;
+            case '+': return PLUS;
+            case ' ': return LEADING_SPACE;
+            case '0': return ZERO_PAD;
+            case ',': return GROUP;
+            case '(': return PARENTHESES;
+            case '<': return PREVIOUS;
+            default:
+                throw new UnknownFormatFlagsException(String.valueOf(c));
+            }
+        }
+
+        // Returns a string representation of the current {@code Flags}.
+        public static String toString(Flags f) {
+            return f.toString();
+        }
+
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            if (contains(LEFT_JUSTIFY))  sb.append('-');
+            if (contains(UPPERCASE))     sb.append('^');
+            if (contains(ALTERNATE))     sb.append('#');
+            if (contains(PLUS))          sb.append('+');
+            if (contains(LEADING_SPACE)) sb.append(' ');
+            if (contains(ZERO_PAD))      sb.append('0');
+            if (contains(GROUP))         sb.append(',');
+            if (contains(PARENTHESES))   sb.append('(');
+            if (contains(PREVIOUS))      sb.append('<');
+            return sb.toString();
+        }
+    }
+
+    private static class Conversion {
+        // Byte, Short, Integer, Long, BigInteger
+        // (and associated primitives due to autoboxing)
+        static final char DECIMAL_INTEGER     = 'd';
+        static final char OCTAL_INTEGER       = 'o';
+        static final char HEXADECIMAL_INTEGER = 'x';
+        static final char HEXADECIMAL_INTEGER_UPPER = 'X';
+
+        // Float, Double, BigDecimal
+        // (and associated primitives due to autoboxing)
+        static final char SCIENTIFIC          = 'e';
+        static final char SCIENTIFIC_UPPER    = 'E';
+        static final char GENERAL             = 'g';
+        static final char GENERAL_UPPER       = 'G';
+        static final char DECIMAL_FLOAT       = 'f';
+        static final char HEXADECIMAL_FLOAT   = 'a';
+        static final char HEXADECIMAL_FLOAT_UPPER = 'A';
+
+        // Character, Byte, Short, Integer
+        // (and associated primitives due to autoboxing)
+        static final char CHARACTER           = 'c';
+        static final char CHARACTER_UPPER     = 'C';
+
+        // java.util.Date, java.util.Calendar, long
+        static final char DATE_TIME           = 't';
+        static final char DATE_TIME_UPPER     = 'T';
+
+        // if (arg.TYPE != boolean) return boolean
+        // if (arg != null) return true; else return false;
+        static final char BOOLEAN             = 'b';
+        static final char BOOLEAN_UPPER       = 'B';
+        // if (arg instanceof Formattable) arg.formatTo()
+        // else arg.toString();
+        static final char STRING              = 's';
+        static final char STRING_UPPER        = 'S';
+        // arg.hashCode()
+        static final char HASHCODE            = 'h';
+        static final char HASHCODE_UPPER      = 'H';
+
+        static final char LINE_SEPARATOR      = 'n';
+        static final char PERCENT_SIGN        = '%';
+
+        static boolean isValid(char c) {
+            return (isGeneral(c) || isInteger(c) || isFloat(c) || isText(c)
+                    || c == 't' || isCharacter(c));
+        }
+
+        // Returns true iff the Conversion is applicable to all objects.
+        static boolean isGeneral(char c) {
+            switch (c) {
+            case BOOLEAN:
+            case BOOLEAN_UPPER:
+            case STRING:
+            case STRING_UPPER:
+            case HASHCODE:
+            case HASHCODE_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion is applicable to character.
+        static boolean isCharacter(char c) {
+            switch (c) {
+            case CHARACTER:
+            case CHARACTER_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion is an integer type.
+        static boolean isInteger(char c) {
+            switch (c) {
+            case DECIMAL_INTEGER:
+            case OCTAL_INTEGER:
+            case HEXADECIMAL_INTEGER:
+            case HEXADECIMAL_INTEGER_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion is a floating-point type.
+        static boolean isFloat(char c) {
+            switch (c) {
+            case SCIENTIFIC:
+            case SCIENTIFIC_UPPER:
+            case GENERAL:
+            case GENERAL_UPPER:
+            case DECIMAL_FLOAT:
+            case HEXADECIMAL_FLOAT:
+            case HEXADECIMAL_FLOAT_UPPER:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        // Returns true iff the Conversion does not require an argument
+        static boolean isText(char c) {
+            switch (c) {
+            case LINE_SEPARATOR:
+            case PERCENT_SIGN:
+                return true;
+            default:
+                return false;
+            }
+        }
+    }
+
+    private static class DateTime {
+        static final char HOUR_OF_DAY_0 = 'H'; // (00 - 23)
+        static final char HOUR_0        = 'I'; // (01 - 12)
+        static final char HOUR_OF_DAY   = 'k'; // (0 - 23) -- like H
+        static final char HOUR          = 'l'; // (1 - 12) -- like I
+        static final char MINUTE        = 'M'; // (00 - 59)
+        static final char NANOSECOND    = 'N'; // (000000000 - 999999999)
+        static final char MILLISECOND   = 'L'; // jdk, not in gnu (000 - 999)
+        static final char MILLISECOND_SINCE_EPOCH = 'Q'; // (0 - 99...?)
+        static final char AM_PM         = 'p'; // (am or pm)
+        static final char SECONDS_SINCE_EPOCH = 's'; // (0 - 99...?)
+        static final char SECOND        = 'S'; // (00 - 60 - leap second)
+        static final char TIME          = 'T'; // (24 hour hh:mm:ss)
+        static final char ZONE_NUMERIC  = 'z'; // (-1200 - +1200) - ls minus?
+        static final char ZONE          = 'Z'; // (symbol)
+
+        // Date
+        static final char NAME_OF_DAY_ABBREV    = 'a'; // 'a'
+        static final char NAME_OF_DAY           = 'A'; // 'A'
+        static final char NAME_OF_MONTH_ABBREV  = 'b'; // 'b'
+        static final char NAME_OF_MONTH         = 'B'; // 'B'
+        static final char CENTURY               = 'C'; // (00 - 99)
+        static final char DAY_OF_MONTH_0        = 'd'; // (01 - 31)
+        static final char DAY_OF_MONTH          = 'e'; // (1 - 31) -- like d
+// *    static final char ISO_WEEK_OF_YEAR_2    = 'g'; // cross %y %V
+// *    static final char ISO_WEEK_OF_YEAR_4    = 'G'; // cross %Y %V
+        static final char NAME_OF_MONTH_ABBREV_X  = 'h'; // -- same b
+        static final char DAY_OF_YEAR           = 'j'; // (001 - 366)
+        static final char MONTH                 = 'm'; // (01 - 12)
+// *    static final char DAY_OF_WEEK_1         = 'u'; // (1 - 7) Monday
+// *    static final char WEEK_OF_YEAR_SUNDAY   = 'U'; // (0 - 53) Sunday+
+// *    static final char WEEK_OF_YEAR_MONDAY_01 = 'V'; // (01 - 53) Monday+
+// *    static final char DAY_OF_WEEK_0         = 'w'; // (0 - 6) Sunday
+// *    static final char WEEK_OF_YEAR_MONDAY   = 'W'; // (00 - 53) Monday
+        static final char YEAR_2                = 'y'; // (00 - 99)
+        static final char YEAR_4                = 'Y'; // (0000 - 9999)
+
+        // Composites
+        static final char TIME_12_HOUR  = 'r'; // (hh:mm:ss [AP]M)
+        static final char TIME_24_HOUR  = 'R'; // (hh:mm same as %H:%M)
+// *    static final char LOCALE_TIME   = 'X'; // (%H:%M:%S) - parse format?
+        static final char DATE_TIME             = 'c';
+                                            // (Sat Nov 04 12:02:33 EST 1999)
+        static final char DATE                  = 'D'; // (mm/dd/yy)
+        static final char ISO_STANDARD_DATE     = 'F'; // (%Y-%m-%d)
+// *    static final char LOCALE_DATE           = 'x'; // (mm/dd/yy)
+
+        static boolean isValid(char c) {
+            switch (c) {
+            case HOUR_OF_DAY_0:
+            case HOUR_0:
+            case HOUR_OF_DAY:
+            case HOUR:
+            case MINUTE:
+            case NANOSECOND:
+            case MILLISECOND:
+            case MILLISECOND_SINCE_EPOCH:
+            case AM_PM:
+            case SECONDS_SINCE_EPOCH:
+            case SECOND:
+            case TIME:
+            case ZONE_NUMERIC:
+            case ZONE:
+
+            // Date
+            case NAME_OF_DAY_ABBREV:
+            case NAME_OF_DAY:
+            case NAME_OF_MONTH_ABBREV:
+            case NAME_OF_MONTH:
+            case CENTURY:
+            case DAY_OF_MONTH_0:
+            case DAY_OF_MONTH:
+// *        case ISO_WEEK_OF_YEAR_2:
+// *        case ISO_WEEK_OF_YEAR_4:
+            case NAME_OF_MONTH_ABBREV_X:
+            case DAY_OF_YEAR:
+            case MONTH:
+// *        case DAY_OF_WEEK_1:
+// *        case WEEK_OF_YEAR_SUNDAY:
+// *        case WEEK_OF_YEAR_MONDAY_01:
+// *        case DAY_OF_WEEK_0:
+// *        case WEEK_OF_YEAR_MONDAY:
+            case YEAR_2:
+            case YEAR_4:
+
+            // Composites
+            case TIME_12_HOUR:
+            case TIME_24_HOUR:
+// *        case LOCALE_TIME:
+            case DATE_TIME:
+            case DATE:
+            case ISO_STANDARD_DATE:
+// *        case LOCALE_DATE:
+                return true;
+            default:
+                return false;
+            }
+        }
+    }
+}
diff --git a/java/util/FormatterClosedException.java b/java/util/FormatterClosedException.java
new file mode 100644
index 0000000..b0aa872
--- /dev/null
+++ b/java/util/FormatterClosedException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the formatter has been closed.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class FormatterClosedException extends IllegalStateException {
+
+    private static final long serialVersionUID = 18111216L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public FormatterClosedException() { }
+}
diff --git a/java/util/GregorianCalendar.java b/java/util/GregorianCalendar.java
new file mode 100644
index 0000000..1d8c87b
--- /dev/null
+++ b/java/util/GregorianCalendar.java
@@ -0,0 +1,3468 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoField;
+import libcore.util.ZoneInfo;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+import sun.util.calendar.JulianCalendar;
+
+/**
+ * <code>GregorianCalendar</code> is a concrete subclass of
+ * <code>Calendar</code> and provides the standard calendar system
+ * used by most of the world.
+ *
+ * <p> <code>GregorianCalendar</code> is a hybrid calendar that
+ * supports both the Julian and Gregorian calendar systems with the
+ * support of a single discontinuity, which corresponds by default to
+ * the Gregorian date when the Gregorian calendar was instituted
+ * (October 15, 1582 in some countries, later in others).  The cutover
+ * date may be changed by the caller by calling {@link
+ * #setGregorianChange(Date) setGregorianChange()}.
+ *
+ * <p>
+ * Historically, in those countries which adopted the Gregorian calendar first,
+ * October 4, 1582 (Julian) was thus followed by October 15, 1582 (Gregorian). This calendar models
+ * this correctly.  Before the Gregorian cutover, <code>GregorianCalendar</code>
+ * implements the Julian calendar.  The only difference between the Gregorian
+ * and the Julian calendar is the leap year rule. The Julian calendar specifies
+ * leap years every four years, whereas the Gregorian calendar omits century
+ * years which are not divisible by 400.
+ *
+ * <p>
+ * <code>GregorianCalendar</code> implements <em>proleptic</em> Gregorian and
+ * Julian calendars. That is, dates are computed by extrapolating the current
+ * rules indefinitely far backward and forward in time. As a result,
+ * <code>GregorianCalendar</code> may be used for all years to generate
+ * meaningful and consistent results. However, dates obtained using
+ * <code>GregorianCalendar</code> are historically accurate only from March 1, 4
+ * AD onward, when modern Julian calendar rules were adopted.  Before this date,
+ * leap year rules were applied irregularly, and before 45 BC the Julian
+ * calendar did not even exist.
+ *
+ * <p>
+ * Prior to the institution of the Gregorian calendar, New Year's Day was
+ * March 25. To avoid confusion, this calendar always uses January 1. A manual
+ * adjustment may be made if desired for dates that are prior to the Gregorian
+ * changeover and which fall between January 1 and March 24.
+ *
+ * <h3><a name="week_and_year">Week Of Year and Week Year</a></h3>
+ *
+ * <p>Values calculated for the {@link Calendar#WEEK_OF_YEAR
+ * WEEK_OF_YEAR} field range from 1 to 53. The first week of a
+ * calendar year is the earliest seven day period starting on {@link
+ * Calendar#getFirstDayOfWeek() getFirstDayOfWeek()} that contains at
+ * least {@link Calendar#getMinimalDaysInFirstWeek()
+ * getMinimalDaysInFirstWeek()} days from that year. It thus depends
+ * on the values of {@code getMinimalDaysInFirstWeek()}, {@code
+ * getFirstDayOfWeek()}, and the day of the week of January 1. Weeks
+ * between week 1 of one year and week 1 of the following year
+ * (exclusive) are numbered sequentially from 2 to 52 or 53 (except
+ * for year(s) involved in the Julian-Gregorian transition).
+ *
+ * <p>The {@code getFirstDayOfWeek()} and {@code
+ * getMinimalDaysInFirstWeek()} values are initialized using
+ * locale-dependent resources when constructing a {@code
+ * GregorianCalendar}. <a name="iso8601_compatible_setting">The week
+ * determination is compatible</a> with the ISO 8601 standard when {@code
+ * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+ * getMinimalDaysInFirstWeek()} is 4, which values are used in locales
+ * where the standard is preferred. These values can explicitly be set by
+ * calling {@link Calendar#setFirstDayOfWeek(int) setFirstDayOfWeek()} and
+ * {@link Calendar#setMinimalDaysInFirstWeek(int)
+ * setMinimalDaysInFirstWeek()}.
+ *
+ * <p>A <a name="week_year"><em>week year</em></a> is in sync with a
+ * {@code WEEK_OF_YEAR} cycle. All weeks between the first and last
+ * weeks (inclusive) have the same <em>week year</em> value.
+ * Therefore, the first and last days of a week year may have
+ * different calendar year values.
+ *
+ * <p>For example, January 1, 1998 is a Thursday. If {@code
+ * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+ * getMinimalDaysInFirstWeek()} is 4 (ISO 8601 standard compatible
+ * setting), then week 1 of 1998 starts on December 29, 1997, and ends
+ * on January 4, 1998. The week year is 1998 for the last three days
+ * of calendar year 1997. If, however, {@code getFirstDayOfWeek()} is
+ * {@code SUNDAY}, then week 1 of 1998 starts on January 4, 1998, and
+ * ends on January 10, 1998; the first three days of 1998 then are
+ * part of week 53 of 1997 and their week year is 1997.
+ *
+ * <h4>Week Of Month</h4>
+ *
+ * <p>Values calculated for the <code>WEEK_OF_MONTH</code> field range from 0
+ * to 6.  Week 1 of a month (the days with <code>WEEK_OF_MONTH =
+ * 1</code>) is the earliest set of at least
+ * <code>getMinimalDaysInFirstWeek()</code> contiguous days in that month,
+ * ending on the day before <code>getFirstDayOfWeek()</code>.  Unlike
+ * week 1 of a year, week 1 of a month may be shorter than 7 days, need
+ * not start on <code>getFirstDayOfWeek()</code>, and will not include days of
+ * the previous month.  Days of a month before week 1 have a
+ * <code>WEEK_OF_MONTH</code> of 0.
+ *
+ * <p>For example, if <code>getFirstDayOfWeek()</code> is <code>SUNDAY</code>
+ * and <code>getMinimalDaysInFirstWeek()</code> is 4, then the first week of
+ * January 1998 is Sunday, January 4 through Saturday, January 10.  These days
+ * have a <code>WEEK_OF_MONTH</code> of 1.  Thursday, January 1 through
+ * Saturday, January 3 have a <code>WEEK_OF_MONTH</code> of 0.  If
+ * <code>getMinimalDaysInFirstWeek()</code> is changed to 3, then January 1
+ * through January 3 have a <code>WEEK_OF_MONTH</code> of 1.
+ *
+ * <h4>Default Fields Values</h4>
+ *
+ * <p>The <code>clear</code> method sets calendar field(s)
+ * undefined. <code>GregorianCalendar</code> uses the following
+ * default value for each calendar field if its value is undefined.
+ *
+ * <table cellpadding="0" cellspacing="3" border="0"
+ *        summary="GregorianCalendar default field values"
+ *        style="text-align: left; width: 66%;">
+ *   <tbody>
+ *     <tr>
+ *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
+ *           text-align: center;">Field<br>
+ *       </th>
+ *       <th style="vertical-align: top; background-color: rgb(204, 204, 255);
+ *           text-align: center;">Default Value<br>
+ *       </th>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>ERA<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>AD<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>YEAR<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>1970<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>JANUARY<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>DAY_OF_MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>1<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>DAY_OF_WEEK<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>the first day of week<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>WEEK_OF_MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: top; background-color: rgb(238, 238, 255);">
+ *              <code>0<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: top;">
+ *              <code>DAY_OF_WEEK_IN_MONTH<br></code>
+ *       </td>
+ *       <td style="vertical-align: top;">
+ *              <code>1<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>AM_PM<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle; background-color: rgb(238, 238, 255);">
+ *              <code>AM<br></code>
+ *       </td>
+ *     </tr>
+ *     <tr>
+ *       <td style="vertical-align: middle;">
+ *              <code>HOUR, HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND<br></code>
+ *       </td>
+ *       <td style="vertical-align: middle;">
+ *              <code>0<br></code>
+ *       </td>
+ *     </tr>
+ *   </tbody>
+ * </table>
+ * <br>Default values are not applicable for the fields not listed above.
+ *
+ * <p>
+ * <strong>Example:</strong>
+ * <blockquote>
+ * <pre>
+ * // get the supported ids for GMT-08:00 (Pacific Standard Time)
+ * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
+ * // if no ids were returned, something is wrong. get out.
+ * if (ids.length == 0)
+ *     System.exit(0);
+ *
+ *  // begin output
+ * System.out.println("Current Time");
+ *
+ * // create a Pacific Standard Time time zone
+ * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
+ *
+ * // set up rules for Daylight Saving Time
+ * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ *
+ * // create a GregorianCalendar with the Pacific Daylight time zone
+ * // and the current date and time
+ * Calendar calendar = new GregorianCalendar(pdt);
+ * Date trialTime = new Date();
+ * calendar.setTime(trialTime);
+ *
+ * // print out a bunch of interesting things
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
+ * System.out.println("DST_OFFSET: "
+ *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
+
+ * System.out.println("Current Time, with hour reset to 3");
+ * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
+ * calendar.set(Calendar.HOUR, 3);
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
+ * System.out.println("DST_OFFSET: "
+ *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
+ * </pre>
+ * </blockquote>
+ *
+ * @see          TimeZone
+ * @author David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ * @since JDK1.1
+ */
+public class GregorianCalendar extends Calendar {
+    /*
+     * Implementation Notes
+     *
+     * The epoch is the number of days or milliseconds from some defined
+     * starting point. The epoch for java.util.Date is used here; that is,
+     * milliseconds from January 1, 1970 (Gregorian), midnight UTC.  Other
+     * epochs which are used are January 1, year 1 (Gregorian), which is day 1
+     * of the Gregorian calendar, and December 30, year 0 (Gregorian), which is
+     * day 1 of the Julian calendar.
+     *
+     * We implement the proleptic Julian and Gregorian calendars.  This means we
+     * implement the modern definition of the calendar even though the
+     * historical usage differs.  For example, if the Gregorian change is set
+     * to new Date(Long.MIN_VALUE), we have a pure Gregorian calendar which
+     * labels dates preceding the invention of the Gregorian calendar in 1582 as
+     * if the calendar existed then.
+     *
+     * Likewise, with the Julian calendar, we assume a consistent
+     * 4-year leap year rule, even though the historical pattern of
+     * leap years is irregular, being every 3 years from 45 BCE
+     * through 9 BCE, then every 4 years from 8 CE onwards, with no
+     * leap years in-between.  Thus date computations and functions
+     * such as isLeapYear() are not intended to be historically
+     * accurate.
+     */
+
+//////////////////
+// Class Variables
+//////////////////
+
+    /**
+     * Value of the <code>ERA</code> field indicating
+     * the period before the common era (before Christ), also known as BCE.
+     * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
+     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
+     *
+     * @see #ERA
+     */
+    public static final int BC = 0;
+
+    /**
+     * Value of the {@link #ERA} field indicating
+     * the period before the common era, the same value as {@link #BC}.
+     *
+     * @see #CE
+     */
+    static final int BCE = 0;
+
+    /**
+     * Value of the <code>ERA</code> field indicating
+     * the common era (Anno Domini), also known as CE.
+     * The sequence of years at the transition from <code>BC</code> to <code>AD</code> is
+     * ..., 2 BC, 1 BC, 1 AD, 2 AD,...
+     *
+     * @see #ERA
+     */
+    public static final int AD = 1;
+
+    /**
+     * Value of the {@link #ERA} field indicating
+     * the common era, the same value as {@link #AD}.
+     *
+     * @see #BCE
+     */
+    static final int CE = 1;
+
+    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
+    private static final int EPOCH_YEAR     = 1970;
+
+    static final int MONTH_LENGTH[]
+        = {31,28,31,30,31,30,31,31,30,31,30,31}; // 0-based
+    static final int LEAP_MONTH_LENGTH[]
+        = {31,29,31,30,31,30,31,31,30,31,30,31}; // 0-based
+
+    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
+    // into ints, they must be longs in order to prevent arithmetic overflow
+    // when performing (bug 4173516).
+    private static final int  ONE_SECOND = 1000;
+    private static final int  ONE_MINUTE = 60*ONE_SECOND;
+    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
+    private static final long ONE_DAY    = 24*ONE_HOUR;
+    private static final long ONE_WEEK   = 7*ONE_DAY;
+
+    /*
+     * <pre>
+     *                            Greatest       Least
+     * Field name        Minimum   Minimum     Maximum     Maximum
+     * ----------        -------   -------     -------     -------
+     * ERA                     0         0           1           1
+     * YEAR                    1         1   292269054   292278994
+     * MONTH                   0         0          11          11
+     * WEEK_OF_YEAR            1         1          52*         53
+     * WEEK_OF_MONTH           0         0           4*          6
+     * DAY_OF_MONTH            1         1          28*         31
+     * DAY_OF_YEAR             1         1         365*        366
+     * DAY_OF_WEEK             1         1           7           7
+     * DAY_OF_WEEK_IN_MONTH   -1        -1           4*          6
+     * AM_PM                   0         0           1           1
+     * HOUR                    0         0          11          11
+     * HOUR_OF_DAY             0         0          23          23
+     * MINUTE                  0         0          59          59
+     * SECOND                  0         0          59          59
+     * MILLISECOND             0         0         999         999
+     * ZONE_OFFSET        -13:00    -13:00       14:00       14:00
+     * DST_OFFSET           0:00      0:00        0:20        2:00
+     * </pre>
+     * *: depends on the Gregorian change date
+     */
+    static final int MIN_VALUES[] = {
+        BCE,            // ERA
+        1,              // YEAR
+        JANUARY,        // MONTH
+        1,              // WEEK_OF_YEAR
+        0,              // WEEK_OF_MONTH
+        1,              // DAY_OF_MONTH
+        1,              // DAY_OF_YEAR
+        SUNDAY,         // DAY_OF_WEEK
+        1,              // DAY_OF_WEEK_IN_MONTH
+        AM,             // AM_PM
+        0,              // HOUR
+        0,              // HOUR_OF_DAY
+        0,              // MINUTE
+        0,              // SECOND
+        0,              // MILLISECOND
+        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
+        0               // DST_OFFSET
+    };
+    static final int LEAST_MAX_VALUES[] = {
+        CE,             // ERA
+        292269054,      // YEAR
+        DECEMBER,       // MONTH
+        52,             // WEEK_OF_YEAR
+        4,              // WEEK_OF_MONTH
+        28,             // DAY_OF_MONTH
+        365,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        4,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
+    };
+    static final int MAX_VALUES[] = {
+        CE,             // ERA
+        292278994,      // YEAR
+        DECEMBER,       // MONTH
+        53,             // WEEK_OF_YEAR
+        6,              // WEEK_OF_MONTH
+        31,             // DAY_OF_MONTH
+        366,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        6,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        2*ONE_HOUR      // DST_OFFSET (double summer time)
+    };
+
+    // Proclaim serialization compatibility with JDK 1.1
+    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
+    static final long serialVersionUID = -8125100834729963327L;
+
+    // Reference to the sun.util.calendar.Gregorian instance (singleton).
+    private static final Gregorian gcal =
+                                CalendarSystem.getGregorianCalendar();
+
+    // Reference to the JulianCalendar instance (singleton), set as needed. See
+    // getJulianCalendarSystem().
+    private static JulianCalendar jcal;
+
+    // JulianCalendar eras. See getJulianCalendarSystem().
+    private static Era[] jeras;
+
+    // The default value of gregorianCutover.
+    static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
+
+/////////////////////
+// Instance Variables
+/////////////////////
+
+    /**
+     * The point at which the Gregorian calendar rules are used, measured in
+     * milliseconds from the standard epoch.  Default is October 15, 1582
+     * (Gregorian) 00:00:00 UTC or -12219292800000L.  For this value, October 4,
+     * 1582 (Julian) is followed by October 15, 1582 (Gregorian).  This
+     * corresponds to Julian day number 2299161.
+     * @serial
+     */
+    private long gregorianCutover = DEFAULT_GREGORIAN_CUTOVER;
+
+    /**
+     * The fixed date of the gregorianCutover.
+     */
+    private transient long gregorianCutoverDate =
+        (((DEFAULT_GREGORIAN_CUTOVER + 1)/ONE_DAY) - 1) + EPOCH_OFFSET; // == 577736
+
+    /**
+     * The normalized year of the gregorianCutover in Gregorian, with
+     * 0 representing 1 BCE, -1 representing 2 BCE, etc.
+     */
+    private transient int gregorianCutoverYear = 1582;
+
+    /**
+     * The normalized year of the gregorianCutover in Julian, with 0
+     * representing 1 BCE, -1 representing 2 BCE, etc.
+     */
+    private transient int gregorianCutoverYearJulian = 1582;
+
+    /**
+     * gdate always has a sun.util.calendar.Gregorian.Date instance to
+     * avoid overhead of creating it. The assumption is that most
+     * applications will need only Gregorian calendar calculations.
+     */
+    private transient BaseCalendar.Date gdate;
+
+    /**
+     * Reference to either gdate or a JulianCalendar.Date
+     * instance. After calling complete(), this value is guaranteed to
+     * be set.
+     */
+    private transient BaseCalendar.Date cdate;
+
+    /**
+     * The CalendarSystem used to calculate the date in cdate. After
+     * calling complete(), this value is guaranteed to be set and
+     * consistent with the cdate value.
+     */
+    private transient BaseCalendar calsys;
+
+    /**
+     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
+     * the GMT offset value and zoneOffsets[1] gets the DST saving
+     * value.
+     */
+    private transient int[] zoneOffsets;
+
+    /**
+     * Temporary storage for saving original fields[] values in
+     * non-lenient mode.
+     */
+    private transient int[] originalFields;
+
+///////////////
+// Constructors
+///////////////
+
+    /**
+     * Constructs a default <code>GregorianCalendar</code> using the current time
+     * in the default time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     */
+    public GregorianCalendar() {
+        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
+        setZoneShared(true);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> based on the current time
+     * in the given time zone with the default
+     * {@link Locale.Category#FORMAT FORMAT} locale.
+     *
+     * @param zone the given time zone.
+     */
+    public GregorianCalendar(TimeZone zone) {
+        this(zone, Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> based on the current time
+     * in the default time zone with the given locale.
+     *
+     * @param aLocale the given locale.
+     */
+    public GregorianCalendar(Locale aLocale) {
+        this(TimeZone.getDefaultRef(), aLocale);
+        setZoneShared(true);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the given time zone.
+     * @param aLocale the given locale.
+     */
+    public GregorianCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
+        setTimeInMillis(System.currentTimeMillis());
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> with the given date set
+     * in the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth) {
+        this(year, month, dayOfMonth, 0, 0, 0, 0);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
+     * in the calendar.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field
+     * in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+                             int minute) {
+        this(year, month, dayOfMonth, hourOfDay, minute, 0, 0);
+    }
+
+    /**
+     * Constructs a GregorianCalendar with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
+     * in the calendar.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field
+     * in the calendar.
+     * @param second the value used to set the <code>SECOND</code> calendar field
+     * in the calendar.
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth, int hourOfDay,
+                             int minute, int second) {
+        this(year, month, dayOfMonth, hourOfDay, minute, second, 0);
+    }
+
+    /**
+     * Constructs a <code>GregorianCalendar</code> with the given date
+     * and time set for the default time zone with the default locale.
+     *
+     * @param year the value used to set the <code>YEAR</code> calendar field in the calendar.
+     * @param month the value used to set the <code>MONTH</code> calendar field in the calendar.
+     * Month value is 0-based. e.g., 0 for January.
+     * @param dayOfMonth the value used to set the <code>DAY_OF_MONTH</code> calendar field in the calendar.
+     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field
+     * in the calendar.
+     * @param minute the value used to set the <code>MINUTE</code> calendar field
+     * in the calendar.
+     * @param second the value used to set the <code>SECOND</code> calendar field
+     * in the calendar.
+     * @param millis the value used to set the <code>MILLISECOND</code> calendar field
+     */
+    GregorianCalendar(int year, int month, int dayOfMonth,
+                      int hourOfDay, int minute, int second, int millis) {
+        super();
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+        this.set(YEAR, year);
+        this.set(MONTH, month);
+        this.set(DAY_OF_MONTH, dayOfMonth);
+
+        // Set AM_PM and HOUR here to set their stamp values before
+        // setting HOUR_OF_DAY (6178071).
+        if (hourOfDay >= 12 && hourOfDay <= 23) {
+            // If hourOfDay is a valid PM hour, set the correct PM values
+            // so that it won't throw an exception in case it's set to
+            // non-lenient later.
+            this.internalSet(AM_PM, PM);
+            this.internalSet(HOUR, hourOfDay - 12);
+        } else {
+            // The default value for AM_PM is AM.
+            // We don't care any out of range value here for leniency.
+            this.internalSet(HOUR, hourOfDay);
+        }
+        // The stamp values of AM_PM and HOUR must be COMPUTED. (6440854)
+        setFieldsComputed(HOUR_MASK|AM_PM_MASK);
+
+        this.set(HOUR_OF_DAY, hourOfDay);
+        this.set(MINUTE, minute);
+        this.set(SECOND, second);
+        // should be changed to set() when this constructor is made
+        // public.
+        this.internalSet(MILLISECOND, millis);
+    }
+
+    /**
+     * Constructs an empty GregorianCalendar.
+     *
+     * @param zone    the given time zone
+     * @param locale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    GregorianCalendar(TimeZone zone, Locale locale, boolean flag) {
+        super(zone, locale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+    }
+
+    // BEGIN Android-added
+    GregorianCalendar(long milliseconds) {
+        this();
+        setTimeInMillis(milliseconds);
+    }
+    // END Android-added
+
+/////////////////
+// Public methods
+/////////////////
+
+    /**
+     * Sets the <code>GregorianCalendar</code> change date. This is the point when the switch
+     * from Julian dates to Gregorian dates occurred. Default is October 15,
+     * 1582 (Gregorian). Previous to this, dates will be in the Julian calendar.
+     * <p>
+     * To obtain a pure Julian calendar, set the change date to
+     * <code>Date(Long.MAX_VALUE)</code>.  To obtain a pure Gregorian calendar,
+     * set the change date to <code>Date(Long.MIN_VALUE)</code>.
+     *
+     * @param date the given Gregorian cutover date.
+     */
+    public void setGregorianChange(Date date) {
+        long cutoverTime = date.getTime();
+        if (cutoverTime == gregorianCutover) {
+            return;
+        }
+        // Before changing the cutover date, make sure to have the
+        // time of this calendar.
+        complete();
+        setGregorianChange(cutoverTime);
+    }
+
+    private void setGregorianChange(long cutoverTime) {
+        gregorianCutover = cutoverTime;
+        gregorianCutoverDate = CalendarUtils.floorDivide(cutoverTime, ONE_DAY)
+                                + EPOCH_OFFSET;
+
+        // To provide the "pure" Julian calendar as advertised.
+        // Strictly speaking, the last millisecond should be a
+        // Gregorian date. However, the API doc specifies that setting
+        // the cutover date to Long.MAX_VALUE will make this calendar
+        // a pure Julian calendar. (See 4167995)
+        if (cutoverTime == Long.MAX_VALUE) {
+            gregorianCutoverDate++;
+        }
+
+        BaseCalendar.Date d = getGregorianCutoverDate();
+
+        // Set the cutover year (in the Gregorian year numbering)
+        gregorianCutoverYear = d.getYear();
+
+        BaseCalendar julianCal = getJulianCalendarSystem();
+        d = (BaseCalendar.Date) julianCal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        julianCal.getCalendarDateFromFixedDate(d, gregorianCutoverDate - 1);
+        gregorianCutoverYearJulian = d.getNormalizedYear();
+
+        if (time < gregorianCutover) {
+            // The field values are no longer valid under the new
+            // cutover date.
+            setUnnormalized();
+        }
+    }
+
+    /**
+     * Gets the Gregorian Calendar change date.  This is the point when the
+     * switch from Julian dates to Gregorian dates occurred. Default is
+     * October 15, 1582 (Gregorian). Previous to this, dates will be in the Julian
+     * calendar.
+     *
+     * @return the Gregorian cutover date for this <code>GregorianCalendar</code> object.
+     */
+    public final Date getGregorianChange() {
+        return new Date(gregorianCutover);
+    }
+
+    /**
+     * Determines if the given year is a leap year. Returns <code>true</code> if
+     * the given year is a leap year. To specify BC year numbers,
+     * <code>1 - year number</code> must be given. For example, year BC 4 is
+     * specified as -3.
+     *
+     * @param year the given year.
+     * @return <code>true</code> if the given year is a leap year; <code>false</code> otherwise.
+     */
+    public boolean isLeapYear(int year) {
+        if ((year & 3) != 0) {
+            return false;
+        }
+
+        if (year > gregorianCutoverYear) {
+            return (year%100 != 0) || (year%400 == 0); // Gregorian
+        }
+        if (year < gregorianCutoverYearJulian) {
+            return true; // Julian
+        }
+        boolean gregorian;
+        // If the given year is the Gregorian cutover year, we need to
+        // determine which calendar system to be applied to February in the year.
+        if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+            BaseCalendar.Date d = getCalendarDate(gregorianCutoverDate); // Gregorian
+            gregorian = d.getMonth() < BaseCalendar.MARCH;
+        } else {
+            gregorian = year == gregorianCutoverYear;
+        }
+        return gregorian ? (year%100 != 0) || (year%400 == 0) : true;
+    }
+
+    /**
+     * Returns {@code "gregory"} as the calendar type.
+     *
+     * @return {@code "gregory"}
+     * @since 1.8
+     */
+    @Override
+    public String getCalendarType() {
+        return "gregory";
+    }
+
+    /**
+     * Compares this <code>GregorianCalendar</code> to the specified
+     * <code>Object</code>. The result is <code>true</code> if and
+     * only if the argument is a <code>GregorianCalendar</code> object
+     * that represents the same time value (millisecond offset from
+     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
+     * <code>Calendar</code> parameters and Gregorian change date as
+     * this object.
+     *
+     * @param obj the object to compare with.
+     * @return <code>true</code> if this object is equal to <code>obj</code>;
+     * <code>false</code> otherwise.
+     * @see Calendar#compareTo(Calendar)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        return obj instanceof GregorianCalendar &&
+            super.equals(obj) &&
+            gregorianCutover == ((GregorianCalendar)obj).gregorianCutover;
+    }
+
+    /**
+     * Generates the hash code for this <code>GregorianCalendar</code> object.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() ^ (int)gregorianCutoverDate;
+    }
+
+    /**
+     * Adds the specified (signed) amount of time to the given calendar field,
+     * based on the calendar's rules.
+     *
+     * <p><em>Add rule 1</em>. The value of <code>field</code>
+     * after the call minus the value of <code>field</code> before the
+     * call is <code>amount</code>, modulo any overflow that has occurred in
+     * <code>field</code>. Overflow occurs when a field value exceeds its
+     * range and, as a result, the next larger field is incremented or
+     * decremented and the field value is adjusted back into its range.</p>
+     *
+     * <p><em>Add rule 2</em>. If a smaller field is expected to be
+     * invariant, but it is impossible for it to be equal to its
+     * prior value because of changes in its minimum or maximum after
+     * <code>field</code> is changed, then its value is adjusted to be as close
+     * as possible to its expected value. A smaller field represents a
+     * smaller unit of time. <code>HOUR</code> is a smaller field than
+     * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+     * that are not expected to be invariant. The calendar system
+     * determines what fields are expected to be invariant.</p>
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     */
+    @Override
+    public void add(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;   // Do nothing!
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        if (field == YEAR) {
+            int year = internalGet(YEAR);
+            if (internalGetEra() == CE) {
+                year += amount;
+                if (year > 0) {
+                    set(YEAR, year);
+                } else { // year <= 0
+                    set(YEAR, 1 - year);
+                    // if year == 0, you get 1 BCE.
+                    set(ERA, BCE);
+                }
+            }
+            else { // era == BCE
+                year -= amount;
+                if (year > 0) {
+                    set(YEAR, year);
+                } else { // year <= 0
+                    set(YEAR, 1 - year);
+                    // if year == 0, you get 1 CE
+                    set(ERA, CE);
+                }
+            }
+            pinDayOfMonth();
+        } else if (field == MONTH) {
+            int month = internalGet(MONTH) + amount;
+            int year = internalGet(YEAR);
+            int y_amount;
+
+            if (month >= 0) {
+                y_amount = month/12;
+            } else {
+                y_amount = (month+1)/12 - 1;
+            }
+            if (y_amount != 0) {
+                if (internalGetEra() == CE) {
+                    year += y_amount;
+                    if (year > 0) {
+                        set(YEAR, year);
+                    } else { // year <= 0
+                        set(YEAR, 1 - year);
+                        // if year == 0, you get 1 BCE
+                        set(ERA, BCE);
+                    }
+                }
+                else { // era == BCE
+                    year -= y_amount;
+                    if (year > 0) {
+                        set(YEAR, year);
+                    } else { // year <= 0
+                        set(YEAR, 1 - year);
+                        // if year == 0, you get 1 CE
+                        set(ERA, CE);
+                    }
+                }
+            }
+
+            if (month >= 0) {
+                set(MONTH,  month % 12);
+            } else {
+                // month < 0
+                month %= 12;
+                if (month < 0) {
+                    month += 12;
+                }
+                set(MONTH, JANUARY + month);
+            }
+            pinDayOfMonth();
+        } else if (field == ERA) {
+            int era = internalGet(ERA) + amount;
+            if (era < 0) {
+                era = 0;
+            }
+            if (era > 1) {
+                era = 1;
+            }
+            set(ERA, era);
+        } else {
+            long delta = amount;
+            long timeOfDay = 0;
+            switch (field) {
+            // Handle the time fields here. Convert the given
+            // amount to milliseconds and call setTimeInMillis.
+            case HOUR:
+            case HOUR_OF_DAY:
+                delta *= 60 * 60 * 1000;        // hours to minutes
+                break;
+
+            case MINUTE:
+                delta *= 60 * 1000;             // minutes to seconds
+                break;
+
+            case SECOND:
+                delta *= 1000;                  // seconds to milliseconds
+                break;
+
+            case MILLISECOND:
+                break;
+
+            // Handle week, day and AM_PM fields which involves
+            // time zone offset change adjustment. Convert the
+            // given amount to the number of days.
+            case WEEK_OF_YEAR:
+            case WEEK_OF_MONTH:
+            case DAY_OF_WEEK_IN_MONTH:
+                delta *= 7;
+                break;
+
+            case DAY_OF_MONTH: // synonym of DATE
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                break;
+
+            case AM_PM:
+                // Convert the amount to the number of days (delta)
+                // and +12 or -12 hours (timeOfDay).
+                delta = amount / 2;
+                timeOfDay = 12 * (amount % 2);
+                break;
+            }
+
+            // The time fields don't require time zone offset change
+            // adjustment.
+            if (field >= HOUR) {
+                setTimeInMillis(time + delta);
+                return;
+            }
+
+            // The rest of the fields (week, day or AM_PM fields)
+            // require time zone offset (both GMT and DST) change
+            // adjustment.
+
+            // Translate the current time to the fixed date and time
+            // of the day.
+            long fd = getCurrentFixedDate();
+            timeOfDay += internalGet(HOUR_OF_DAY);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(MINUTE);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(SECOND);
+            timeOfDay *= 1000;
+            timeOfDay += internalGet(MILLISECOND);
+            if (timeOfDay >= ONE_DAY) {
+                fd++;
+                timeOfDay -= ONE_DAY;
+            } else if (timeOfDay < 0) {
+                fd--;
+                timeOfDay += ONE_DAY;
+            }
+
+            fd += delta; // fd is the expected fixed date after the calculation
+            // BEGIN Android-changed: time zone related calculation via helper methods
+            // Calculate the time in the UTC time zone.
+            long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+            // Neither of the time zone related fields are relevant because they have not been
+            // set since the call to complete() above.
+            int tzMask = 0;
+
+            // Adjust the time to account for zone and daylight savings time offset.
+            long millis = adjustForZoneAndDaylightSavingsTime(tzMask, utcTime, getZone());
+
+            // Update the time and recompute the fields.
+            setTimeInMillis(millis);
+            // END Android-changed: time zone related calculation via helper methods
+        }
+    }
+
+    /**
+     * Adds or subtracts (up/down) a single unit of time on the given time
+     * field without changing larger fields.
+     * <p>
+     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
+     * originally set to December 31, 1999. Calling {@link #roll(int,boolean) roll(Calendar.MONTH, true)}
+     * sets the calendar to January 31, 1999.  The <code>YEAR</code> field is unchanged
+     * because it is a larger field than <code>MONTH</code>.</p>
+     *
+     * @param up indicates if the value of the specified calendar field is to be
+     * rolled up or rolled down. Use <code>true</code> if rolling up, <code>false</code> otherwise.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    @Override
+    public void roll(int field, boolean up) {
+        roll(field, up ? +1 : -1);
+    }
+
+    /**
+     * Adds a signed amount to the specified calendar field without changing larger fields.
+     * A negative roll amount means to subtract from field without changing
+     * larger fields. If the specified amount is 0, this method performs nothing.
+     *
+     * <p>This method calls {@link #complete()} before adding the
+     * amount so that all the calendar fields are normalized. If there
+     * is any calendar field having an out-of-range value in non-lenient mode, then an
+     * <code>IllegalArgumentException</code> is thrown.
+     *
+     * <p>
+     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
+     * originally set to August 31, 1999. Calling <code>roll(Calendar.MONTH,
+     * 8)</code> sets the calendar to April 30, <strong>1999</strong>. Using a
+     * <code>GregorianCalendar</code>, the <code>DAY_OF_MONTH</code> field cannot
+     * be 31 in the month April. <code>DAY_OF_MONTH</code> is set to the closest possible
+     * value, 30. The <code>YEAR</code> field maintains the value of 1999 because it
+     * is a larger field than <code>MONTH</code>.
+     * <p>
+     * <em>Example</em>: Consider a <code>GregorianCalendar</code>
+     * originally set to Sunday June 6, 1999. Calling
+     * <code>roll(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
+     * Tuesday June 1, 1999, whereas calling
+     * <code>add(Calendar.WEEK_OF_MONTH, -1)</code> sets the calendar to
+     * Sunday May 30, 1999. This is because the roll rule imposes an
+     * additional constraint: The <code>MONTH</code> must not change when the
+     * <code>WEEK_OF_MONTH</code> is rolled. Taken together with add rule 1,
+     * the resultant date must be between Tuesday June 1 and Saturday June
+     * 5. According to add rule 2, the <code>DAY_OF_WEEK</code>, an invariant
+     * when changing the <code>WEEK_OF_MONTH</code>, is set to Tuesday, the
+     * closest possible value to Sunday (where Sunday is the first day of the
+     * week).</p>
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to <code>field</code>.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     * @since 1.2
+     */
+    @Override
+    public void roll(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        int min = getMinimum(field);
+        int max = getMaximum(field);
+
+        switch (field) {
+        case AM_PM:
+        case ERA:
+        case YEAR:
+        case MINUTE:
+        case SECOND:
+        case MILLISECOND:
+            // These fields are handled simply, since they have fixed minima
+            // and maxima.  The field DAY_OF_MONTH is almost as simple.  Other
+            // fields are complicated, since the range within they must roll
+            // varies depending on the date.
+            break;
+
+        case HOUR:
+        case HOUR_OF_DAY:
+            {
+                int unit = max + 1; // 12 or 24 hours
+                int h = internalGet(field);
+                int nh = (h + amount) % unit;
+                if (nh < 0) {
+                    nh += unit;
+                }
+                time += ONE_HOUR * (nh - h);
+
+                // The day might have changed, which could happen if
+                // the daylight saving time transition brings it to
+                // the next day, although it's very unlikely. But we
+                // have to make sure not to change the larger fields.
+                CalendarDate d = calsys.getCalendarDate(time, getZone());
+                if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
+                    d.setDate(internalGet(YEAR),
+                              internalGet(MONTH) + 1,
+                              internalGet(DAY_OF_MONTH));
+                    if (field == HOUR) {
+                        assert (internalGet(AM_PM) == PM);
+                        d.addHours(+12); // restore PM
+                    }
+                    time = calsys.getTime(d);
+                }
+                int hourOfDay = d.getHours();
+                internalSet(field, hourOfDay % unit);
+                if (field == HOUR) {
+                    internalSet(HOUR_OF_DAY, hourOfDay);
+                } else {
+                    internalSet(AM_PM, hourOfDay / 12);
+                    internalSet(HOUR, hourOfDay % 12);
+                }
+
+                // Time zone offset and/or daylight saving might have changed.
+                int zoneOffset = d.getZoneOffset();
+                int saving = d.getDaylightSaving();
+                internalSet(ZONE_OFFSET, zoneOffset - saving);
+                internalSet(DST_OFFSET, saving);
+                return;
+            }
+
+        case MONTH:
+            // Rolling the month involves both pinning the final value to [0, 11]
+            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
+            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    int mon = (internalGet(MONTH) + amount) % 12;
+                    if (mon < 0) {
+                        mon += 12;
+                    }
+                    set(MONTH, mon);
+
+                    // Keep the day of month in the range.  We don't want to spill over
+                    // into the next month; e.g., we don't want jan31 + 1 mo -> feb31 ->
+                    // mar3.
+                    int monthLen = monthLength(mon);
+                    if (internalGet(DAY_OF_MONTH) > monthLen) {
+                        set(DAY_OF_MONTH, monthLen);
+                    }
+                } else {
+                    // We need to take care of different lengths in
+                    // year and month due to the cutover.
+                    int yearLength = getActualMaximum(MONTH) + 1;
+                    int mon = (internalGet(MONTH) + amount) % yearLength;
+                    if (mon < 0) {
+                        mon += yearLength;
+                    }
+                    set(MONTH, mon);
+                    int monthLen = getActualMaximum(DAY_OF_MONTH);
+                    if (internalGet(DAY_OF_MONTH) > monthLen) {
+                        set(DAY_OF_MONTH, monthLen);
+                    }
+                }
+                return;
+            }
+
+        case WEEK_OF_YEAR:
+            {
+                int y = cdate.getNormalizedYear();
+                max = getActualMaximum(WEEK_OF_YEAR);
+                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                int woy = internalGet(WEEK_OF_YEAR);
+                int value = woy + amount;
+                if (!isCutoverYear(y)) {
+                    int weekYear = getWeekYear();
+                    if (weekYear == y) {
+                        // If the new value is in between min and max
+                        // (exclusive), then we can use the value.
+                        if (value > min && value < max) {
+                            set(WEEK_OF_YEAR, value);
+                            return;
+                        }
+                        long fd = getCurrentFixedDate();
+                        // Make sure that the min week has the current DAY_OF_WEEK
+                        // in the calendar year
+                        long day1 = fd - (7 * (woy - min));
+                        if (calsys.getYearFromFixedDate(day1) != y) {
+                            min++;
+                        }
+
+                        // Make sure the same thing for the max week
+                        fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+                        if (calsys.getYearFromFixedDate(fd) != y) {
+                            max--;
+                        }
+                    } else {
+                        // When WEEK_OF_YEAR and YEAR are out of sync,
+                        // adjust woy and amount to stay in the calendar year.
+                        if (weekYear > y) {
+                            if (amount < 0) {
+                                amount++;
+                            }
+                            woy = max;
+                        } else {
+                            if (amount > 0) {
+                                amount -= woy - max;
+                            }
+                            woy = min;
+                        }
+                    }
+                    set(field, getRolledValue(woy, amount, min, max));
+                    return;
+                }
+
+                // Handle cutover here.
+                long fd = getCurrentFixedDate();
+                BaseCalendar cal;
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    cal = getCutoverCalendarSystem();
+                } else if (y == gregorianCutoverYear) {
+                    cal = gcal;
+                } else {
+                    cal = getJulianCalendarSystem();
+                }
+                long day1 = fd - (7 * (woy - min));
+                // Make sure that the min week has the current DAY_OF_WEEK
+                if (cal.getYearFromFixedDate(day1) != y) {
+                    min++;
+                }
+
+                // Make sure the same thing for the max week
+                fd += 7 * (max - woy);
+                cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+                if (cal.getYearFromFixedDate(fd) != y) {
+                    max--;
+                }
+                // value: the new WEEK_OF_YEAR which must be converted
+                // to month and day of month.
+                value = getRolledValue(woy, amount, min, max) - 1;
+                BaseCalendar.Date d = getCalendarDate(day1 + value * 7);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case WEEK_OF_MONTH:
+            {
+                boolean isCutoverYear = isCutoverYear(cdate.getNormalizedYear());
+                // dow: relative day of week from first day of week
+                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
+                if (dow < 0) {
+                    dow += 7;
+                }
+
+                long fd = getCurrentFixedDate();
+                long month1;     // fixed date of the first day (usually 1) of the month
+                int monthLength; // actual month length
+                if (isCutoverYear) {
+                    month1 = getFixedDateMonth1(cdate, fd);
+                    monthLength = actualMonthLength();
+                } else {
+                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
+                    monthLength = calsys.getMonthLength(cdate);
+                }
+
+                // the first day of week of the month.
+                long monthDay1st = BaseCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
+                                                                           getFirstDayOfWeek());
+                // if the week has enough days to form a week, the
+                // week starts from the previous month.
+                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
+                    monthDay1st -= 7;
+                }
+                max = getActualMaximum(field);
+
+                // value: the new WEEK_OF_MONTH value
+                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
+
+                // nfd: fixed date of the rolled date
+                long nfd = monthDay1st + value * 7 + dow;
+
+                // Unlike WEEK_OF_YEAR, we need to change day of week if the
+                // nfd is out of the month.
+                if (nfd < month1) {
+                    nfd = month1;
+                } else if (nfd >= (month1 + monthLength)) {
+                    nfd = month1 + monthLength - 1;
+                }
+                int dayOfMonth;
+                if (isCutoverYear) {
+                    // If we are in the cutover year, convert nfd to
+                    // its calendar date and use dayOfMonth.
+                    BaseCalendar.Date d = getCalendarDate(nfd);
+                    dayOfMonth = d.getDayOfMonth();
+                } else {
+                    dayOfMonth = (int)(nfd - month1) + 1;
+                }
+                set(DAY_OF_MONTH, dayOfMonth);
+                return;
+            }
+
+        case DAY_OF_MONTH:
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    max = calsys.getMonthLength(cdate);
+                    break;
+                }
+
+                // Cutover year handling
+                long fd = getCurrentFixedDate();
+                long month1 = getFixedDateMonth1(cdate, fd);
+                // It may not be a regular month. Convert the date and range to
+                // the relative values, perform the roll, and
+                // convert the result back to the rolled date.
+                int value = getRolledValue((int)(fd - month1), amount, 0, actualMonthLength() - 1);
+                BaseCalendar.Date d = getCalendarDate(month1 + value);
+                assert d.getMonth()-1 == internalGet(MONTH);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_YEAR:
+            {
+                max = getActualMaximum(field);
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    break;
+                }
+
+                // Handle cutover here.
+                long fd = getCurrentFixedDate();
+                long jan1 = fd - internalGet(DAY_OF_YEAR) + 1;
+                int value = getRolledValue((int)(fd - jan1) + 1, amount, min, max);
+                BaseCalendar.Date d = getCalendarDate(jan1 + value - 1);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK:
+            {
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    // If the week of year is in the same year, we can
+                    // just change DAY_OF_WEEK.
+                    int weekOfYear = internalGet(WEEK_OF_YEAR);
+                    if (weekOfYear > 1 && weekOfYear < 52) {
+                        set(WEEK_OF_YEAR, weekOfYear); // update stamp[WEEK_OF_YEAR]
+                        max = SATURDAY;
+                        break;
+                    }
+                }
+
+                // We need to handle it in a different way around year
+                // boundaries and in the cutover year. Note that
+                // changing era and year values violates the roll
+                // rule: not changing larger calendar fields...
+                amount %= 7;
+                if (amount == 0) {
+                    return;
+                }
+                long fd = getCurrentFixedDate();
+                long dowFirst = BaseCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
+                fd += amount;
+                if (fd < dowFirst) {
+                    fd += 7;
+                } else if (fd >= dowFirst + 7) {
+                    fd -= 7;
+                }
+                BaseCalendar.Date d = getCalendarDate(fd);
+                set(ERA, (d.getNormalizedYear() <= 0 ? BCE : CE));
+                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                min = 1; // after normalized, min should be 1.
+                if (!isCutoverYear(cdate.getNormalizedYear())) {
+                    int dom = internalGet(DAY_OF_MONTH);
+                    int monthLength = calsys.getMonthLength(cdate);
+                    int lastDays = monthLength % 7;
+                    max = monthLength / 7;
+                    int x = (dom - 1) % 7;
+                    if (x < lastDays) {
+                        max++;
+                    }
+                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                    break;
+                }
+
+                // Cutover year handling
+                long fd = getCurrentFixedDate();
+                long month1 = getFixedDateMonth1(cdate, fd);
+                int monthLength = actualMonthLength();
+                int lastDays = monthLength % 7;
+                max = monthLength / 7;
+                int x = (int)(fd - month1) % 7;
+                if (x < lastDays) {
+                    max++;
+                }
+                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
+                fd = month1 + value * 7 + x;
+                BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+                BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                cal.getCalendarDateFromFixedDate(d, fd);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+        }
+
+        set(field, getRolledValue(internalGet(field), amount, min, max));
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * <code>GregorianCalendar</code> instance. The minimum value is
+     * defined as the smallest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getMinimum(int field) {
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * <code>GregorianCalendar</code> instance. The maximum value is
+     * defined as the largest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getMaximum(int field) {
+        switch (field) {
+        case MONTH:
+        case DAY_OF_MONTH:
+        case DAY_OF_YEAR:
+        case WEEK_OF_YEAR:
+        case WEEK_OF_MONTH:
+        case DAY_OF_WEEK_IN_MONTH:
+        case YEAR:
+            {
+                // On or after Gregorian 200-3-1, Julian and Gregorian
+                // calendar dates are the same or Gregorian dates are
+                // larger (i.e., there is a "gap") after 300-3-1.
+                if (gregorianCutoverYear > 200) {
+                    break;
+                }
+                // There might be "overlapping" dates.
+                GregorianCalendar gc = (GregorianCalendar) clone();
+                gc.setLenient(true);
+                gc.setTimeInMillis(gregorianCutover);
+                int v1 = gc.getActualMaximum(field);
+                gc.setTimeInMillis(gregorianCutover-1);
+                int v2 = gc.getActualMaximum(field);
+                return Math.max(MAX_VALUES[field], Math.max(v1, v2));
+            }
+        }
+        return MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The highest
+     * minimum value is defined as the largest value returned by
+     * {@link #getActualMinimum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getGreatestMinimum(int field) {
+        if (field == DAY_OF_MONTH) {
+            BaseCalendar.Date d = getGregorianCutoverDate();
+            long mon1 = getFixedDateMonth1(d, gregorianCutoverDate);
+            d = getCalendarDate(mon1);
+            return Math.max(MIN_VALUES[field], d.getDayOfMonth());
+        }
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The lowest
+     * maximum value is defined as the smallest value returned by
+     * {@link #getActualMaximum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    @Override
+    public int getLeastMaximum(int field) {
+        switch (field) {
+        case MONTH:
+        case DAY_OF_MONTH:
+        case DAY_OF_YEAR:
+        case WEEK_OF_YEAR:
+        case WEEK_OF_MONTH:
+        case DAY_OF_WEEK_IN_MONTH:
+        case YEAR:
+            {
+                GregorianCalendar gc = (GregorianCalendar) clone();
+                gc.setLenient(true);
+                gc.setTimeInMillis(gregorianCutover);
+                int v1 = gc.getActualMaximum(field);
+                gc.setTimeInMillis(gregorianCutover-1);
+                int v2 = gc.getActualMaximum(field);
+                return Math.min(LEAST_MAX_VALUES[field], Math.min(v1, v2));
+            }
+        }
+        return LEAST_MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the minimum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * <p>For example, if the Gregorian change date is January 10,
+     * 1970 and the date of this <code>GregorianCalendar</code> is
+     * January 20, 1970, the actual minimum value of the
+     * <code>DAY_OF_MONTH</code> field is 10 because the previous date
+     * of January 10, 1970 is December 27, 1996 (in the Julian
+     * calendar). Therefore, December 28, 1969 to January 9, 1970
+     * don't exist.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given field for the time value of
+     * this <code>GregorianCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     * @since 1.2
+     */
+    @Override
+    public int getActualMinimum(int field) {
+        if (field == DAY_OF_MONTH) {
+            GregorianCalendar gc = getNormalizedCalendar();
+            int year = gc.cdate.getNormalizedYear();
+            if (year == gregorianCutoverYear || year == gregorianCutoverYearJulian) {
+                long month1 = getFixedDateMonth1(gc.cdate, gc.calsys.getFixedDate(gc.cdate));
+                BaseCalendar.Date d = getCalendarDate(month1);
+                return d.getDayOfMonth();
+            }
+        }
+        return getMinimum(field);
+    }
+
+    /**
+     * Returns the maximum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * {@link #getGregorianChange() getGregorianChange} and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     * For example, if the date of this instance is February 1, 2004,
+     * the actual maximum value of the <code>DAY_OF_MONTH</code> field
+     * is 29 because 2004 is a leap year, and if the date of this
+     * instance is February 1, 2005, it's 28.
+     *
+     * <p>This method calculates the maximum value of {@link
+     * Calendar#WEEK_OF_YEAR WEEK_OF_YEAR} based on the {@link
+     * Calendar#YEAR YEAR} (calendar year) value, not the <a
+     * href="#week_year">week year</a>. Call {@link
+     * #getWeeksInWeekYear()} to get the maximum value of {@code
+     * WEEK_OF_YEAR} in the week year of this {@code GregorianCalendar}.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given field for the time value of
+     * this <code>GregorianCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @since 1.2
+     */
+    @Override
+    public int getActualMaximum(int field) {
+        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
+            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
+            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
+        if ((fieldsForFixedMax & (1<<field)) != 0) {
+            return getMaximum(field);
+        }
+
+        GregorianCalendar gc = getNormalizedCalendar();
+        BaseCalendar.Date date = gc.cdate;
+        BaseCalendar cal = gc.calsys;
+        int normalizedYear = date.getNormalizedYear();
+
+        int value = -1;
+        switch (field) {
+        case MONTH:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    value = DECEMBER;
+                    break;
+                }
+
+                // January 1 of the next year may or may not exist.
+                long nextJan1;
+                do {
+                    nextJan1 = gcal.getFixedDate(++normalizedYear, BaseCalendar.JANUARY, 1, null);
+                } while (nextJan1 < gregorianCutoverDate);
+                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                cal.getCalendarDateFromFixedDate(d, nextJan1 - 1);
+                value = d.getMonth() - 1;
+            }
+            break;
+
+        case DAY_OF_MONTH:
+            {
+                value = cal.getMonthLength(date);
+                if (!gc.isCutoverYear(normalizedYear) || date.getDayOfMonth() == value) {
+                    break;
+                }
+
+                // Handle cutover year.
+                long fd = gc.getCurrentFixedDate();
+                if (fd >= gregorianCutoverDate) {
+                    break;
+                }
+                int monthLength = gc.actualMonthLength();
+                long monthEnd = gc.getFixedDateMonth1(gc.cdate, fd) + monthLength - 1;
+                // Convert the fixed date to its calendar date.
+                BaseCalendar.Date d = gc.getCalendarDate(monthEnd);
+                value = d.getDayOfMonth();
+            }
+            break;
+
+        case DAY_OF_YEAR:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    value = cal.getYearLength(date);
+                    break;
+                }
+
+                // Handle cutover year.
+                long jan1;
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    BaseCalendar cocal = gc.getCutoverCalendarSystem();
+                    jan1 = cocal.getFixedDate(normalizedYear, 1, 1, null);
+                } else if (normalizedYear == gregorianCutoverYearJulian) {
+                    jan1 = cal.getFixedDate(normalizedYear, 1, 1, null);
+                } else {
+                    jan1 = gregorianCutoverDate;
+                }
+                // January 1 of the next year may or may not exist.
+                long nextJan1 = gcal.getFixedDate(++normalizedYear, 1, 1, null);
+                if (nextJan1 < gregorianCutoverDate) {
+                    nextJan1 = gregorianCutoverDate;
+                }
+                assert jan1 <= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
+                                                date.getDayOfMonth(), date);
+                assert nextJan1 >= cal.getFixedDate(date.getNormalizedYear(), date.getMonth(),
+                                                date.getDayOfMonth(), date);
+                value = (int)(nextJan1 - jan1);
+            }
+            break;
+
+        case WEEK_OF_YEAR:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    // Get the day of week of January 1 of the year
+                    CalendarDate d = cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getYear(), BaseCalendar.JANUARY, 1);
+                    int dayOfWeek = cal.getDayOfWeek(d);
+                    // Normalize the day of week with the firstDayOfWeek value
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    value = 52;
+                    int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
+                    if ((magic == 6) ||
+                        (date.isLeapYear() && (magic == 5 || magic == 12))) {
+                        value++;
+                    }
+                    break;
+                }
+
+                if (gc == this) {
+                    gc = (GregorianCalendar) gc.clone();
+                }
+                int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
+                gc.set(DAY_OF_YEAR, maxDayOfYear);
+                value = gc.get(WEEK_OF_YEAR);
+                if (internalGet(YEAR) != gc.getWeekYear()) {
+                    gc.set(DAY_OF_YEAR, maxDayOfYear - 7);
+                    value = gc.get(WEEK_OF_YEAR);
+                }
+            }
+            break;
+
+        case WEEK_OF_MONTH:
+            {
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    CalendarDate d = cal.newCalendarDate(null);
+                    d.setDate(date.getYear(), date.getMonth(), 1);
+                    int dayOfWeek = cal.getDayOfWeek(d);
+                    int monthLength = cal.getMonthLength(d);
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
+                    value = 3;
+                    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
+                        value++;
+                    }
+                    monthLength -= nDaysFirstWeek + 7 * 3;
+                    if (monthLength > 0) {
+                        value++;
+                        if (monthLength > 7) {
+                            value++;
+                        }
+                    }
+                    break;
+                }
+
+                // Cutover year handling
+                if (gc == this) {
+                    gc = (GregorianCalendar) gc.clone();
+                }
+                int y = gc.internalGet(YEAR);
+                int m = gc.internalGet(MONTH);
+                do {
+                    value = gc.get(WEEK_OF_MONTH);
+                    gc.add(WEEK_OF_MONTH, +1);
+                } while (gc.get(YEAR) == y && gc.get(MONTH) == m);
+            }
+            break;
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                // may be in the Gregorian cutover month
+                int ndays, dow1;
+                int dow = date.getDayOfWeek();
+                if (!gc.isCutoverYear(normalizedYear)) {
+                    BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                    ndays = cal.getMonthLength(d);
+                    d.setDayOfMonth(1);
+                    cal.normalize(d);
+                    dow1 = d.getDayOfWeek();
+                } else {
+                    // Let a cloned GregorianCalendar take care of the cutover cases.
+                    if (gc == this) {
+                        gc = (GregorianCalendar) clone();
+                    }
+                    ndays = gc.actualMonthLength();
+                    gc.set(DAY_OF_MONTH, gc.getActualMinimum(DAY_OF_MONTH));
+                    dow1 = gc.get(DAY_OF_WEEK);
+                }
+                int x = dow - dow1;
+                if (x < 0) {
+                    x += 7;
+                }
+                ndays -= x;
+                value = (ndays + 6) / 7;
+            }
+            break;
+
+        case YEAR:
+            /* The year computation is no different, in principle, from the
+             * others, however, the range of possible maxima is large.  In
+             * addition, the way we know we've exceeded the range is different.
+             * For these reasons, we use the special case code below to handle
+             * this field.
+             *
+             * The actual maxima for YEAR depend on the type of calendar:
+             *
+             *     Gregorian = May 17, 292275056 BCE - Aug 17, 292278994 CE
+             *     Julian    = Dec  2, 292269055 BCE - Jan  3, 292272993 CE
+             *     Hybrid    = Dec  2, 292269055 BCE - Aug 17, 292278994 CE
+             *
+             * We know we've exceeded the maximum when either the month, date,
+             * time, or era changes in response to setting the year.  We don't
+             * check for month, date, and time here because the year and era are
+             * sufficient to detect an invalid year setting.  NOTE: If code is
+             * added to check the month and date in the future for some reason,
+             * Feb 29 must be allowed to shift to Mar 1 when setting the year.
+             */
+            {
+                if (gc == this) {
+                    gc = (GregorianCalendar) clone();
+                }
+
+                // Calculate the millisecond offset from the beginning
+                // of the year of this calendar and adjust the max
+                // year value if we are beyond the limit in the max
+                // year.
+                long current = gc.getYearOffsetInMillis();
+
+                if (gc.internalGetEra() == CE) {
+                    gc.setTimeInMillis(Long.MAX_VALUE);
+                    value = gc.get(YEAR);
+                    long maxEnd = gc.getYearOffsetInMillis();
+                    if (current > maxEnd) {
+                        value--;
+                    }
+                } else {
+                    CalendarSystem mincal = gc.getTimeInMillis() >= gregorianCutover ?
+                        gcal : getJulianCalendarSystem();
+                    CalendarDate d = mincal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    long maxEnd = (cal.getDayOfYear(d) - 1) * 24 + d.getHours();
+                    maxEnd *= 60;
+                    maxEnd += d.getMinutes();
+                    maxEnd *= 60;
+                    maxEnd += d.getSeconds();
+                    maxEnd *= 1000;
+                    maxEnd += d.getMillis();
+                    value = d.getYear();
+                    if (value <= 0) {
+                        assert mincal == gcal;
+                        value = 1 - value;
+                    }
+                    if (current < maxEnd) {
+                        value--;
+                    }
+                }
+            }
+            break;
+
+        default:
+            throw new ArrayIndexOutOfBoundsException(field);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the millisecond offset from the beginning of this
+     * year. This Calendar object must have been normalized.
+     */
+    private long getYearOffsetInMillis() {
+        long t = (internalGet(DAY_OF_YEAR) - 1) * 24;
+        t += internalGet(HOUR_OF_DAY);
+        t *= 60;
+        t += internalGet(MINUTE);
+        t *= 60;
+        t += internalGet(SECOND);
+        t *= 1000;
+        return t + internalGet(MILLISECOND) -
+            (internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET));
+    }
+
+    @Override
+    public Object clone()
+    {
+        GregorianCalendar other = (GregorianCalendar) super.clone();
+
+        other.gdate = (BaseCalendar.Date) gdate.clone();
+        if (cdate != null) {
+            if (cdate != gdate) {
+                other.cdate = (BaseCalendar.Date) cdate.clone();
+            } else {
+                other.cdate = other.gdate;
+            }
+        }
+        other.originalFields = null;
+        other.zoneOffsets = null;
+        return other;
+    }
+
+    @Override
+    public TimeZone getTimeZone() {
+        TimeZone zone = super.getTimeZone();
+        // To share the zone by CalendarDates
+        gdate.setZone(zone);
+        if (cdate != null && cdate != gdate) {
+            cdate.setZone(zone);
+        }
+        return zone;
+    }
+
+    @Override
+    public void setTimeZone(TimeZone zone) {
+        super.setTimeZone(zone);
+        // To share the zone by CalendarDates
+        gdate.setZone(zone);
+        if (cdate != null && cdate != gdate) {
+            cdate.setZone(zone);
+        }
+    }
+
+    /**
+     * Returns {@code true} indicating this {@code GregorianCalendar}
+     * supports week dates.
+     *
+     * @return {@code true} (always)
+     * @see #getWeekYear()
+     * @see #setWeekDate(int,int,int)
+     * @see #getWeeksInWeekYear()
+     * @since 1.7
+     */
+    @Override
+    public final boolean isWeekDateSupported() {
+        return true;
+    }
+
+    /**
+     * Returns the <a href="#week_year">week year</a> represented by this
+     * {@code GregorianCalendar}. The dates in the weeks between 1 and the
+     * maximum week number of the week year have the same week year value
+     * that may be one year before or after the {@link Calendar#YEAR YEAR}
+     * (calendar year) value.
+     *
+     * <p>This method calls {@link Calendar#complete()} before
+     * calculating the week year.
+     *
+     * @return the week year represented by this {@code GregorianCalendar}.
+     *         If the {@link Calendar#ERA ERA} value is {@link #BC}, the year is
+     *         represented by 0 or a negative number: BC 1 is 0, BC 2
+     *         is -1, BC 3 is -2, and so on.
+     * @throws IllegalArgumentException
+     *         if any of the calendar fields is invalid in non-lenient mode.
+     * @see #isWeekDateSupported()
+     * @see #getWeeksInWeekYear()
+     * @see Calendar#getFirstDayOfWeek()
+     * @see Calendar#getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    @Override
+    public int getWeekYear() {
+        int year = get(YEAR); // implicitly calls complete()
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+
+        // Fast path for the Gregorian calendar years that are never
+        // affected by the Julian-Gregorian transition
+        if (year > gregorianCutoverYear + 1) {
+            int weekOfYear = internalGet(WEEK_OF_YEAR);
+            if (internalGet(MONTH) == JANUARY) {
+                if (weekOfYear >= 52) {
+                    --year;
+                }
+            } else {
+                if (weekOfYear == 1) {
+                    ++year;
+                }
+            }
+            return year;
+        }
+
+        // General (slow) path
+        int dayOfYear = internalGet(DAY_OF_YEAR);
+        int maxDayOfYear = getActualMaximum(DAY_OF_YEAR);
+        int minimalDays = getMinimalDaysInFirstWeek();
+
+        // Quickly check the possibility of year adjustments before
+        // cloning this GregorianCalendar.
+        if (dayOfYear > minimalDays && dayOfYear < (maxDayOfYear - 6)) {
+            return year;
+        }
+
+        // Create a clone to work on the calculation
+        GregorianCalendar cal = (GregorianCalendar) clone();
+        cal.setLenient(true);
+        // Use GMT so that intermediate date calculations won't
+        // affect the time of day fields.
+        cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+        // Go to the first day of the year, which is usually January 1.
+        cal.set(DAY_OF_YEAR, 1);
+        cal.complete();
+
+        // Get the first day of the first day-of-week in the year.
+        int delta = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
+        if (delta != 0) {
+            if (delta < 0) {
+                delta += 7;
+            }
+            cal.add(DAY_OF_YEAR, delta);
+        }
+        int minDayOfYear = cal.get(DAY_OF_YEAR);
+        if (dayOfYear < minDayOfYear) {
+            if (minDayOfYear <= minimalDays) {
+                --year;
+            }
+        } else {
+            cal.set(YEAR, year + 1);
+            cal.set(DAY_OF_YEAR, 1);
+            cal.complete();
+            int del = getFirstDayOfWeek() - cal.get(DAY_OF_WEEK);
+            if (del != 0) {
+                if (del < 0) {
+                    del += 7;
+                }
+                cal.add(DAY_OF_YEAR, del);
+            }
+            minDayOfYear = cal.get(DAY_OF_YEAR) - 1;
+            if (minDayOfYear == 0) {
+                minDayOfYear = 7;
+            }
+            if (minDayOfYear >= minimalDays) {
+                int days = maxDayOfYear - dayOfYear + 1;
+                if (days <= (7 - minDayOfYear)) {
+                    ++year;
+                }
+            }
+        }
+        return year;
+    }
+
+    /**
+     * Sets this {@code GregorianCalendar} to the date given by the
+     * date specifiers - <a href="#week_year">{@code weekYear}</a>,
+     * {@code weekOfYear}, and {@code dayOfWeek}. {@code weekOfYear}
+     * follows the <a href="#week_and_year">{@code WEEK_OF_YEAR}
+     * numbering</a>.  The {@code dayOfWeek} value must be one of the
+     * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} values: {@link
+     * Calendar#SUNDAY SUNDAY} to {@link Calendar#SATURDAY SATURDAY}.
+     *
+     * <p>Note that the numeric day-of-week representation differs from
+     * the ISO 8601 standard, and that the {@code weekOfYear}
+     * numbering is compatible with the standard when {@code
+     * getFirstDayOfWeek()} is {@code MONDAY} and {@code
+     * getMinimalDaysInFirstWeek()} is 4.
+     *
+     * <p>Unlike the {@code set} method, all of the calendar fields
+     * and the instant of time value are calculated upon return.
+     *
+     * <p>If {@code weekOfYear} is out of the valid week-of-year
+     * range in {@code weekYear}, the {@code weekYear}
+     * and {@code weekOfYear} values are adjusted in lenient
+     * mode, or an {@code IllegalArgumentException} is thrown in
+     * non-lenient mode.
+     *
+     * @param weekYear    the week year
+     * @param weekOfYear  the week number based on {@code weekYear}
+     * @param dayOfWeek   the day of week value: one of the constants
+     *                    for the {@link #DAY_OF_WEEK DAY_OF_WEEK} field:
+     *                    {@link Calendar#SUNDAY SUNDAY}, ...,
+     *                    {@link Calendar#SATURDAY SATURDAY}.
+     * @exception IllegalArgumentException
+     *            if any of the given date specifiers is invalid,
+     *            or if any of the calendar fields are inconsistent
+     *            with the given date specifiers in non-lenient mode
+     * @see GregorianCalendar#isWeekDateSupported()
+     * @see Calendar#getFirstDayOfWeek()
+     * @see Calendar#getMinimalDaysInFirstWeek()
+     * @since 1.7
+     */
+    @Override
+    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+        if (dayOfWeek < SUNDAY || dayOfWeek > SATURDAY) {
+            throw new IllegalArgumentException("invalid dayOfWeek: " + dayOfWeek);
+        }
+
+        // To avoid changing the time of day fields by date
+        // calculations, use a clone with the GMT time zone.
+        GregorianCalendar gc = (GregorianCalendar) clone();
+        gc.setLenient(true);
+        int era = gc.get(ERA);
+        gc.clear();
+        gc.setTimeZone(TimeZone.getTimeZone("GMT"));
+        gc.set(ERA, era);
+        gc.set(YEAR, weekYear);
+        gc.set(WEEK_OF_YEAR, 1);
+        gc.set(DAY_OF_WEEK, getFirstDayOfWeek());
+        int days = dayOfWeek - getFirstDayOfWeek();
+        if (days < 0) {
+            days += 7;
+        }
+        days += 7 * (weekOfYear - 1);
+        if (days != 0) {
+            gc.add(DAY_OF_YEAR, days);
+        } else {
+            gc.complete();
+        }
+
+        if (!isLenient() &&
+            (gc.getWeekYear() != weekYear
+             || gc.internalGet(WEEK_OF_YEAR) != weekOfYear
+             || gc.internalGet(DAY_OF_WEEK) != dayOfWeek)) {
+            throw new IllegalArgumentException();
+        }
+
+        set(ERA, gc.internalGet(ERA));
+        set(YEAR, gc.internalGet(YEAR));
+        set(MONTH, gc.internalGet(MONTH));
+        set(DAY_OF_MONTH, gc.internalGet(DAY_OF_MONTH));
+
+        // to avoid throwing an IllegalArgumentException in
+        // non-lenient, set WEEK_OF_YEAR internally
+        internalSet(WEEK_OF_YEAR, weekOfYear);
+        complete();
+    }
+
+    /**
+     * Returns the number of weeks in the <a href="#week_year">week year</a>
+     * represented by this {@code GregorianCalendar}.
+     *
+     * <p>For example, if this {@code GregorianCalendar}'s date is
+     * December 31, 2008 with <a href="#iso8601_compatible_setting">the ISO
+     * 8601 compatible setting</a>, this method will return 53 for the
+     * period: December 29, 2008 to January 3, 2010 while {@link
+     * #getActualMaximum(int) getActualMaximum(WEEK_OF_YEAR)} will return
+     * 52 for the period: December 31, 2007 to December 28, 2008.
+     *
+     * @return the number of weeks in the week year.
+     * @see Calendar#WEEK_OF_YEAR
+     * @see #getWeekYear()
+     * @see #getActualMaximum(int)
+     * @since 1.7
+     */
+    @Override
+    public int getWeeksInWeekYear() {
+        GregorianCalendar gc = getNormalizedCalendar();
+        int weekYear = gc.getWeekYear();
+        if (weekYear == gc.internalGet(YEAR)) {
+            return gc.getActualMaximum(WEEK_OF_YEAR);
+        }
+
+        // Use the 2nd week for calculating the max of WEEK_OF_YEAR
+        if (gc == this) {
+            gc = (GregorianCalendar) gc.clone();
+        }
+        gc.setWeekDate(weekYear, 2, internalGet(DAY_OF_WEEK));
+        return gc.getActualMaximum(WEEK_OF_YEAR);
+    }
+
+/////////////////////////////
+// Time => Fields computation
+/////////////////////////////
+
+    /**
+     * The fixed date corresponding to gdate. If the value is
+     * Long.MIN_VALUE, the fixed date value is unknown. Currently,
+     * Julian calendar dates are not cached.
+     */
+    transient private long cachedFixedDate = Long.MIN_VALUE;
+
+    /**
+     * Converts the time value (millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
+     * The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * <code>complete</code> method.
+     *
+     * @see Calendar#complete
+     */
+    @Override
+    protected void computeFields() {
+        int mask;
+        if (isPartiallyNormalized()) {
+            // Determine which calendar fields need to be computed.
+            mask = getSetStateFields();
+            int fieldMask = ~mask & ALL_FIELDS;
+            // We have to call computTime in case calsys == null in
+            // order to set calsys and cdate. (6263644)
+            if (fieldMask != 0 || calsys == null) {
+                mask |= computeFields(fieldMask,
+                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
+                assert mask == ALL_FIELDS;
+            }
+        } else {
+            mask = ALL_FIELDS;
+            computeFields(mask, 0);
+        }
+        // After computing all the fields, set the field state to `COMPUTED'.
+        setFieldsComputed(mask);
+    }
+
+    /**
+     * This computeFields implements the conversion from UTC
+     * (millisecond offset from the Epoch) to calendar
+     * field values. fieldMask specifies which fields to change the
+     * setting state to COMPUTED, although all fields are set to
+     * the correct values. This is required to fix 4685354.
+     *
+     * @param fieldMask a bit mask to specify which fields to change
+     * the setting state.
+     * @param tzMask a bit mask to specify which time zone offset
+     * fields to be used for time calculations
+     * @return a new field mask that indicates what field values have
+     * actually been set.
+     */
+    private int computeFields(int fieldMask, int tzMask) {
+        int zoneOffset = 0;
+        TimeZone tz = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (tz instanceof ZoneInfo) {
+                // BEGIN Android-changed: use libcore.util.ZoneInfo
+                // The method name to get offsets differs from sun.util.calendar.ZoneInfo
+                // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+                ZoneInfo zoneInfo = (ZoneInfo) tz;
+                zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets);
+                // END Android-changed: use libcore.util.ZoneInfo
+            } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
+        }
+
+        // By computing time and zoneOffset separately, we can take
+        // the wider range of time+zoneOffset than the previous
+        // implementation.
+        long fixedDate = zoneOffset / ONE_DAY;
+        int timeOfDay = zoneOffset % (int)ONE_DAY;
+        fixedDate += time / ONE_DAY;
+        timeOfDay += (int) (time % ONE_DAY);
+        if (timeOfDay >= ONE_DAY) {
+            timeOfDay -= ONE_DAY;
+            ++fixedDate;
+        } else {
+            while (timeOfDay < 0) {
+                timeOfDay += ONE_DAY;
+                --fixedDate;
+            }
+        }
+        fixedDate += EPOCH_OFFSET;
+
+        int era = CE;
+        int year;
+        if (fixedDate >= gregorianCutoverDate) {
+            // Handle Gregorian dates.
+            assert cachedFixedDate == Long.MIN_VALUE || gdate.isNormalized()
+                        : "cache control: not normalized";
+            assert cachedFixedDate == Long.MIN_VALUE ||
+                   gcal.getFixedDate(gdate.getNormalizedYear(),
+                                          gdate.getMonth(),
+                                          gdate.getDayOfMonth(), gdate)
+                                == cachedFixedDate
+                        : "cache control: inconsictency" +
+                          ", cachedFixedDate=" + cachedFixedDate +
+                          ", computed=" +
+                          gcal.getFixedDate(gdate.getNormalizedYear(),
+                                                 gdate.getMonth(),
+                                                 gdate.getDayOfMonth(),
+                                                 gdate) +
+                          ", date=" + gdate;
+
+            // See if we can use gdate to avoid date calculation.
+            if (fixedDate != cachedFixedDate) {
+                gcal.getCalendarDateFromFixedDate(gdate, fixedDate);
+                cachedFixedDate = fixedDate;
+            }
+
+            year = gdate.getYear();
+            if (year <= 0) {
+                year = 1 - year;
+                era = BCE;
+            }
+            calsys = gcal;
+            cdate = gdate;
+            assert cdate.getDayOfWeek() > 0 : "dow="+cdate.getDayOfWeek()+", date="+cdate;
+        } else {
+            // Handle Julian calendar dates.
+            calsys = getJulianCalendarSystem();
+            cdate = (BaseCalendar.Date) jcal.newCalendarDate(getZone());
+            jcal.getCalendarDateFromFixedDate(cdate, fixedDate);
+            Era e = cdate.getEra();
+            if (e == jeras[0]) {
+                era = BCE;
+            }
+            year = cdate.getYear();
+        }
+
+        // Always set the ERA and YEAR values.
+        internalSet(ERA, era);
+        internalSet(YEAR, year);
+        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
+
+        int month =  cdate.getMonth() - 1; // 0-based
+        int dayOfMonth = cdate.getDayOfMonth();
+
+        // Set the basic date fields.
+        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
+            != 0) {
+            internalSet(MONTH, month);
+            internalSet(DAY_OF_MONTH, dayOfMonth);
+            internalSet(DAY_OF_WEEK, cdate.getDayOfWeek());
+            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
+        }
+
+        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
+            if (timeOfDay != 0) {
+                int hours = timeOfDay / ONE_HOUR;
+                internalSet(HOUR_OF_DAY, hours);
+                internalSet(AM_PM, hours / 12); // Assume AM == 0
+                internalSet(HOUR, hours % 12);
+                int r = timeOfDay % ONE_HOUR;
+                internalSet(MINUTE, r / ONE_MINUTE);
+                r %= ONE_MINUTE;
+                internalSet(SECOND, r / ONE_SECOND);
+                internalSet(MILLISECOND, r % ONE_SECOND);
+            } else {
+                internalSet(HOUR_OF_DAY, 0);
+                internalSet(AM_PM, AM);
+                internalSet(HOUR, 0);
+                internalSet(MINUTE, 0);
+                internalSet(SECOND, 0);
+                internalSet(MILLISECOND, 0);
+            }
+            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
+        }
+
+        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
+            internalSet(ZONE_OFFSET, zoneOffsets[0]);
+            internalSet(DST_OFFSET, zoneOffsets[1]);
+            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        }
+
+        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
+            int normalizedYear = cdate.getNormalizedYear();
+            long fixedDateJan1 = calsys.getFixedDate(normalizedYear, 1, 1, cdate);
+            int dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            long fixedDateMonth1 = fixedDate - dayOfMonth + 1;
+            int cutoverGap = 0;
+            int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
+            int relativeDayOfMonth = dayOfMonth - 1;
+
+            // If we are in the cutover year, we need some special handling.
+            if (normalizedYear == cutoverYear) {
+                // Need to take care of the "missing" days.
+                if (gregorianCutoverYearJulian <= gregorianCutoverYear) {
+                    // We need to find out where we are. The cutover
+                    // gap could even be more than one year.  (One
+                    // year difference in ~48667 years.)
+                    fixedDateJan1 = getFixedDateJan1(cdate, fixedDate);
+                    if (fixedDate >= gregorianCutoverDate) {
+                        fixedDateMonth1 = getFixedDateMonth1(cdate, fixedDate);
+                    }
+                }
+                int realDayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+                cutoverGap = dayOfYear - realDayOfYear;
+                dayOfYear = realDayOfYear;
+                relativeDayOfMonth = (int)(fixedDate - fixedDateMonth1);
+            }
+            internalSet(DAY_OF_YEAR, dayOfYear);
+            internalSet(DAY_OF_WEEK_IN_MONTH, relativeDayOfMonth / 7 + 1);
+
+            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
+
+            // The spec is to calculate WEEK_OF_YEAR in the
+            // ISO8601-style. This creates problems, though.
+            if (weekOfYear == 0) {
+                // If the date belongs to the last week of the
+                // previous year, use the week number of "12/31" of
+                // the "previous" year. Again, if the previous year is
+                // the Gregorian cutover year, we need to take care of
+                // it.  Usually the previous day of January 1 is
+                // December 31, which is not always true in
+                // GregorianCalendar.
+                long fixedDec31 = fixedDateJan1 - 1;
+                long prevJan1  = fixedDateJan1 - 365;
+                if (normalizedYear > (cutoverYear + 1)) {
+                    if (CalendarUtils.isGregorianLeapYear(normalizedYear - 1)) {
+                        --prevJan1;
+                    }
+                } else if (normalizedYear <= gregorianCutoverYearJulian) {
+                    if (CalendarUtils.isJulianLeapYear(normalizedYear - 1)) {
+                        --prevJan1;
+                    }
+                } else {
+                    BaseCalendar calForJan1 = calsys;
+                    //int prevYear = normalizedYear - 1;
+                    int prevYear = getCalendarDate(fixedDec31).getNormalizedYear();
+                    if (prevYear == gregorianCutoverYear) {
+                        calForJan1 = getCutoverCalendarSystem();
+                        if (calForJan1 == jcal) {
+                            prevJan1 = calForJan1.getFixedDate(prevYear,
+                                                               BaseCalendar.JANUARY,
+                                                               1,
+                                                               null);
+                        } else {
+                            prevJan1 = gregorianCutoverDate;
+                            calForJan1 = gcal;
+                        }
+                    } else if (prevYear <= gregorianCutoverYearJulian) {
+                        calForJan1 = getJulianCalendarSystem();
+                        prevJan1 = calForJan1.getFixedDate(prevYear,
+                                                           BaseCalendar.JANUARY,
+                                                           1,
+                                                           null);
+                    }
+                }
+                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
+            } else {
+                if (normalizedYear > gregorianCutoverYear ||
+                    normalizedYear < (gregorianCutoverYearJulian - 1)) {
+                    // Regular years
+                    if (weekOfYear >= 52) {
+                        long nextJan1 = fixedDateJan1 + 365;
+                        if (cdate.isLeapYear()) {
+                            nextJan1++;
+                        }
+                        long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                  getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                            // The first days forms a week in which the date is included.
+                            weekOfYear = 1;
+                        }
+                    }
+                } else {
+                    BaseCalendar calForJan1 = calsys;
+                    int nextYear = normalizedYear + 1;
+                    if (nextYear == (gregorianCutoverYearJulian + 1) &&
+                        nextYear < gregorianCutoverYear) {
+                        // In case the gap is more than one year.
+                        nextYear = gregorianCutoverYear;
+                    }
+                    if (nextYear == gregorianCutoverYear) {
+                        calForJan1 = getCutoverCalendarSystem();
+                    }
+
+                    long nextJan1;
+                    if (nextYear > gregorianCutoverYear
+                        || gregorianCutoverYearJulian == gregorianCutoverYear
+                        || nextYear == gregorianCutoverYearJulian) {
+                        nextJan1 = calForJan1.getFixedDate(nextYear,
+                                                           BaseCalendar.JANUARY,
+                                                           1,
+                                                           null);
+                    } else {
+                        nextJan1 = gregorianCutoverDate;
+                        calForJan1 = gcal;
+                    }
+
+                    long nextJan1st = BaseCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                              getFirstDayOfWeek());
+                    int ndays = (int)(nextJan1st - nextJan1);
+                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                        // The first days forms a week in which the date is included.
+                        weekOfYear = 1;
+                    }
+                }
+            }
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
+            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the number of weeks in a period between fixedDay1 and
+     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
+     * is applied to calculate the number of weeks.
+     *
+     * @param fixedDay1 the fixed date of the first day of the period
+     * @param fixedDate the fixed date of the last day of the period
+     * @return the number of weeks of the given period
+     */
+    private int getWeekNumber(long fixedDay1, long fixedDate) {
+        // We can always use `gcal' since Julian and Gregorian are the
+        // same thing for this calculation.
+        long fixedDay1st = Gregorian.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
+                                                                getFirstDayOfWeek());
+        int ndays = (int)(fixedDay1st - fixedDay1);
+        assert ndays <= 7;
+        if (ndays >= getMinimalDaysInFirstWeek()) {
+            fixedDay1st -= 7;
+        }
+        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
+        if (normalizedDayOfPeriod >= 0) {
+            return normalizedDayOfPeriod / 7 + 1;
+        }
+        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
+    }
+
+    /**
+     * Converts calendar field values to the time value (millisecond
+     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
+     *
+     * @exception IllegalArgumentException if any calendar fields are invalid.
+     */
+    @Override
+    protected void computeTime() {
+        // In non-lenient mode, perform brief checking of calendar
+        // fields which have been set externally. Through this
+        // checking, the field values are stored in originalFields[]
+        // to see if any of them are normalized later.
+        if (!isLenient()) {
+            if (originalFields == null) {
+                originalFields = new int[FIELD_COUNT];
+            }
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                int value = internalGet(field);
+                if (isExternallySet(field)) {
+                    // Quick validation for any out of range values
+                    if (value < getMinimum(field) || value > getMaximum(field)) {
+                        throw new IllegalArgumentException(getFieldName(field));
+                    }
+                }
+                originalFields[field] = value;
+            }
+        }
+
+        // Let the super class determine which calendar fields to be
+        // used to calculate the time.
+        int fieldMask = selectFields();
+
+        // The year defaults to the epoch start. We don't check
+        // fieldMask for YEAR because YEAR is a mandatory field to
+        // determine the date.
+        int year = isSet(YEAR) ? internalGet(YEAR) : EPOCH_YEAR;
+
+        int era = internalGetEra();
+        if (era == BCE) {
+            year = 1 - year;
+        } else if (era != CE) {
+            // Even in lenient mode we disallow ERA values other than CE & BCE.
+            // (The same normalization rule as add()/roll() could be
+            // applied here in lenient mode. But this checking is kept
+            // unchanged for compatibility as of 1.5.)
+            throw new IllegalArgumentException("Invalid era");
+        }
+
+        // If year is 0 or negative, we need to set the ERA value later.
+        if (year <= 0 && !isSet(ERA)) {
+            fieldMask |= ERA_MASK;
+            setFieldsComputed(ERA_MASK);
+        }
+
+        // Calculate the time of day. We rely on the convention that
+        // an UNSET field has 0.
+        long timeOfDay = 0;
+        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
+            timeOfDay += (long) internalGet(HOUR_OF_DAY);
+        } else {
+            timeOfDay += internalGet(HOUR);
+            // The default value of AM_PM is 0 which designates AM.
+            if (isFieldSet(fieldMask, AM_PM)) {
+                timeOfDay += 12 * internalGet(AM_PM);
+            }
+        }
+        timeOfDay *= 60;
+        timeOfDay += internalGet(MINUTE);
+        timeOfDay *= 60;
+        timeOfDay += internalGet(SECOND);
+        timeOfDay *= 1000;
+        timeOfDay += internalGet(MILLISECOND);
+
+        // Convert the time of day to the number of days and the
+        // millisecond offset from midnight.
+        long fixedDate = timeOfDay / ONE_DAY;
+        timeOfDay %= ONE_DAY;
+        while (timeOfDay < 0) {
+            timeOfDay += ONE_DAY;
+            --fixedDate;
+        }
+
+        // Calculate the fixed date since January 1, 1 (Gregorian).
+        calculateFixedDate: {
+            long gfd, jfd;
+            if (year > gregorianCutoverYear && year > gregorianCutoverYearJulian) {
+                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
+                if (gfd >= gregorianCutoverDate) {
+                    fixedDate = gfd;
+                    break calculateFixedDate;
+                }
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+            } else if (year < gregorianCutoverYear && year < gregorianCutoverYearJulian) {
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+                if (jfd < gregorianCutoverDate) {
+                    fixedDate = jfd;
+                    break calculateFixedDate;
+                }
+                gfd = jfd;
+            } else {
+                jfd = fixedDate + getFixedDate(getJulianCalendarSystem(), year, fieldMask);
+                gfd = fixedDate + getFixedDate(gcal, year, fieldMask);
+            }
+
+            // Now we have to determine which calendar date it is.
+
+            // If the date is relative from the beginning of the year
+            // in the Julian calendar, then use jfd;
+            if (isFieldSet(fieldMask, DAY_OF_YEAR) || isFieldSet(fieldMask, WEEK_OF_YEAR)) {
+                if (gregorianCutoverYear == gregorianCutoverYearJulian) {
+                    fixedDate = jfd;
+                    break calculateFixedDate;
+                } else if (year == gregorianCutoverYear) {
+                    fixedDate = gfd;
+                    break calculateFixedDate;
+                }
+            }
+
+            if (gfd >= gregorianCutoverDate) {
+                if (jfd >= gregorianCutoverDate) {
+                    fixedDate = gfd;
+                } else {
+                    // The date is in an "overlapping" period. No way
+                    // to disambiguate it. Determine it using the
+                    // previous date calculation.
+                    if (calsys == gcal || calsys == null) {
+                        fixedDate = gfd;
+                    } else {
+                        fixedDate = jfd;
+                    }
+                }
+            } else {
+                if (jfd < gregorianCutoverDate) {
+                    fixedDate = jfd;
+                } else {
+                    // The date is in a "missing" period.
+                    if (!isLenient()) {
+                        throw new IllegalArgumentException("the specified date doesn't exist");
+                    }
+                    // Take the Julian date for compatibility, which
+                    // will produce a Gregorian date.
+                    fixedDate = jfd;
+                }
+            }
+        }
+
+        // millis represents local wall-clock time in milliseconds.
+        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+        // Compute the time zone offset and DST offset.  There are two potential
+        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
+        // for discussion purposes here.
+        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
+        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
+        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+        //    We assume standard time.
+        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
+        //    can be in standard or DST.  Both are valid representations (the rep
+        //    jumps from 1:59:59 DST to 1:00:00 Std).
+        //    Again, we assume standard time.
+        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+        // or DST_OFFSET fields; then we use those fields.
+        TimeZone zone = getZone();
+        // BEGIN Android-changed: time zone related calculation via helper methods
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+
+        millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone);
+        // END Android-changed: time zone related calculation via helper methods
+
+        // Set this calendar's time in milliseconds
+        time = millis;
+
+        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
+
+        if (!isLenient()) {
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                if (!isExternallySet(field)) {
+                    continue;
+                }
+                if (originalFields[field] != internalGet(field)) {
+                    String s = originalFields[field] + " -> " + internalGet(field);
+                    // Restore the original field values
+                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
+                    throw new IllegalArgumentException(getFieldName(field) + ": " + s);
+                }
+            }
+        }
+        setFieldsNormalized(mask);
+    }
+
+    // BEGIN Android-added: helper methods for time zone related calculation
+    /**
+     * Calculates the time in milliseconds that this calendar represents using the UTC time,
+     * timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
+     * of what fields were explicitly set on the calendar.
+     *
+     * <p>A time is represented as the number of milliseconds since
+     * <i>1st January 1970 00:00:00.000 UTC</i>.
+     *
+     * <p>This uses the terms {@link SimpleTimeZone#STANDARD_TIME standard time},
+     * {@link SimpleTimeZone#WALL_TIME} wall time} and {@link SimpleTimeZone#UTC_TIME UTC time} as
+     * used in {@link SimpleTimeZone}. Specifically:
+     *
+     * <dl>
+     * <dt><b>UTC time</b></dt>
+     * <dd>This is the time within the UTC time zone. UTC does not support DST so the UTC time,
+     * standard time and wall time are all identical within the UTC time zone.</dd>
+     * <dt><b>standard time</b></dt>
+     * <dd>This is the local time within the time zone and is not affected by DST.</dd>
+     * <dt><b>wall time</b></dt>
+     * <dd>This is the local time within the time zone as shown on a wall clock. If the time zone
+     * supports DST then it will be the same as <b>standard time</b> when outside DST and it will
+     * differ (usually be an hour later) when inside DST. This is what the fields on the Calendar
+     * represent.</dd>
+     * </dl>
+     *
+     * <p>The {@code utcTimeInMillis} value supplied was calculated as if the fields represented
+     * a standard time in the {@code UTC} time zone. It is the value that would be returned by
+     * {@link #getTimeInMillis()} when called on this calendar if it was in UTC time zone. e.g. If
+     * the calendar was set to say <i>2014 March 19th 13:27.53 -08:00</i> then the value of
+     * {@code utcTimeInMillis} would be the value of {@link #getTimeInMillis()} when called on a
+     * calendar set to <i>2014 March 19th 13:27.53 -00:00</i>, note the time zone offset is set to
+     * 0.
+     *
+     * <p>To adjust from a UTC time in millis to the standard time in millis we must
+     * <em>subtract</em> the offset from UTC. e.g. given an offset of UTC-08:00, to convert
+     * "14:00 UTC" to "14:00 UTC-08:00" we must subtract -08:00 (i.e. add 8 hours). Another way to
+     * think about it is that 8 hours has to elapse after 14:00 UTC before it is 14:00 UTC-08:00.
+     *
+     * <p>As the zone offset can depend on the time and we cannot calculate the time properly until
+     * we know the time there is a bit of a catch-22. So, what this does is use the
+     * {@link TimeZone#getRawOffset() raw offset} to calculate a ballpark standard time and then
+     * uses that value to retrieve the appropriate zone and DST offsets from the time zone. They
+     * are then used to make the final wall time calculation.
+     *
+     * <p>The DST offset will need clearing if the standard time is not a valid wall clock. See
+     * {@link #adjustDstOffsetForInvalidWallClock(long, TimeZone, int)} for more information.
+     *
+     * @param tzMask the set of time zone related fields, i.e. {@link #ZONE_OFFSET_MASK} and
+     * {@link #DST_OFFSET_MASK}
+     * @param utcTimeInMillis the time in millis, calculated assuming the time zone was GMT.
+     * @param zone the actual time zone.
+     * @return the UTC time in millis after adjusting for zone and DST offset.
+     */
+    private long adjustForZoneAndDaylightSavingsTime(
+            int tzMask, long utcTimeInMillis, TimeZone zone) {
+
+        // The following don't actually need to be initialized because they are always set before
+        // they are used but the compiler cannot detect that.
+        int zoneOffset = 0;
+        int dstOffset = 0;
+
+        // If either of the ZONE_OFFSET or DST_OFFSET fields are not set then get the information
+        // from the TimeZone.
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            if (zoneOffsets == null) {
+                zoneOffsets = new int[2];
+            }
+            int gmtOffset = isFieldSet(tzMask, ZONE_OFFSET) ?
+                                internalGet(ZONE_OFFSET) : zone.getRawOffset();
+
+            // Calculate the standard time (no DST) in the supplied zone. This is a ballpark figure
+            // and not used in the final calculation as the offset used here may not be the same as
+            // the actual offset the time zone requires be used for this time. This is to handle
+            // situations like Honolulu, where its raw offset changed from GMT-10:30 to GMT-10:00
+            // in 1947. The TimeZone always uses a raw offset of -10:00 but will return -10:30
+            // for dates before the change over.
+            long standardTimeInZone = utcTimeInMillis - gmtOffset;
+
+            // Retrieve the correct zone and DST offsets from the time zone.
+            if (zone instanceof ZoneInfo) {
+                // Android-changed: libcore ZoneInfo uses different method to get offsets.
+                ZoneInfo zoneInfo = (ZoneInfo) zone;
+                zoneInfo.getOffsetsByUtcTime(standardTimeInZone, zoneOffsets);
+            } else {
+                zone.getOffsets(standardTimeInZone, zoneOffsets);
+            }
+            zoneOffset = zoneOffsets[0];
+            dstOffset = zoneOffsets[1];
+
+            // If necessary adjust the DST offset to handle an invalid wall clock sensibly.
+            dstOffset = adjustDstOffsetForInvalidWallClock(standardTimeInZone, zone, dstOffset);
+        }
+
+        // If either ZONE_OFFSET of DST_OFFSET fields are set then get the information from the
+        // fields, potentially overriding information from the TimeZone.
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffset = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                dstOffset = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        long standardTimeInZone = utcTimeInMillis - zoneOffset;
+        return standardTimeInZone - dstOffset;
+    }
+
+    /**
+     * If the supplied millis is in daylight savings time (DST) and is the result of an invalid
+     * wall clock then adjust the DST offset to ensure sensible behavior.
+     *
+     * <p>When transitioning into DST, i.e. when the clocks spring forward (usually by one hour)
+     * there is a wall clock period that is invalid, it literally doesn't exist. e.g. If clocks
+     * go forward one hour at 02:00 on 9th March 2014 (standard time) then the wall time of
+     * 02:00-02:59:59.999 is not a valid. The wall clock jumps straight from 01:59:59.999 to
+     * 03:00. The following table shows the relationship between the time in millis, the standard
+     * time and the wall time at the point of transitioning into DST. As can be seen there is no
+     * 02:00 in the wall time.
+     *
+     * <pre>
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 .....
+     * Wall Time      - ...... 01:00 ..... 03:00 ..... 04:00 .....
+     *                                       ^
+     *                                 02:00 missing
+     * </pre>
+     *
+     * <p>The calendar fields represent wall time. If the user sets the fields on the calendar so
+     * that it is in that invalid period then this code attempts to do something sensible. It
+     * treats 02:MM:SS.SSS as if it is {@code 01:MM:SS.SSS + 1 hour}. That makes sense from both
+     * the input calendar fields perspective and from the time in millis perspective. Of course the
+     * result of that is that when the time is formatted in that time zone that the time is
+     * actually 03:MM:SS.SSS.
+     *
+     * <pre>
+     * Wall Time      - ...... 01:00 ..... <b>02:00 .....</b> 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h ..... <b> x+2h .....</b>  x+2h .....  x+3h .....
+     * </pre>
+     *
+     * <p>The way that works is as follows. First the standard time is calculated and the DST
+     * offset is determined. Then if the time is in DST (the DST offset is not 0) but it was not in
+     * DST an hour earlier (or however long the DST offset is) then it must be in that invalid
+     * period, in which case set the DST offset to 0. That is then subtracted from the time in
+     * millis to produce the correct result. The following diagram illustrates the process.
+     *
+     * <pre>
+     * Standard Time  - ...... 01:00 ..... 02:00 ..... 03:00 ..... 04:00 .....
+     * Time In Millis - ......  x+1h .....  x+2h .....  x+3h .....  x+4h .....
+     * DST Offset     - ......    0h .....    1h .....    1h .....    1h .....
+     * Adjusted DST   - ......    0h .....    <b>0h</b> .....    1h .....    1h .....
+     * Adjusted Time  - ......  x+1h .....  x+2h .....  <b>x+2h</b> .....  <b>x+3h</b> .....
+     * </pre>
+     *
+     * @return the adjusted DST offset.
+     */
+    private int adjustDstOffsetForInvalidWallClock(
+            long standardTimeInZone, TimeZone zone, int dstOffset) {
+
+        if (dstOffset != 0) {
+            // If applying the DST offset produces a time that is outside DST then it must be
+            // an invalid wall clock so clear the DST offset to avoid that happening.
+            if (!zone.inDaylightTime(new Date(standardTimeInZone - dstOffset))) {
+                dstOffset = 0;
+            }
+        }
+        return dstOffset;
+    }
+    // END Android-added: helper methods for time zone related calculation
+
+    /**
+     * Computes the fixed date under either the Gregorian or the
+     * Julian calendar, using the given year and the specified calendar fields.
+     *
+     * @param cal the CalendarSystem to be used for the date calculation
+     * @param year the normalized year number, with 0 indicating the
+     * year 1 BCE, -1 indicating 2 BCE, etc.
+     * @param fieldMask the calendar fields to be used for the date calculation
+     * @return the fixed date
+     * @see Calendar#selectFields
+     */
+    private long getFixedDate(BaseCalendar cal, int year, int fieldMask) {
+        int month = JANUARY;
+        if (isFieldSet(fieldMask, MONTH)) {
+            // No need to check if MONTH has been set (no isSet(MONTH)
+            // call) since its unset value happens to be JANUARY (0).
+            month = internalGet(MONTH);
+
+            // If the month is out of range, adjust it into range
+            if (month > DECEMBER) {
+                year += month / 12;
+                month %= 12;
+            } else if (month < JANUARY) {
+                int[] rem = new int[1];
+                year += CalendarUtils.floorDivide(month, 12, rem);
+                month = rem[0];
+            }
+        }
+
+        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
+        // the first day of either `month' or January in 'year'.
+        long fixedDate = cal.getFixedDate(year, month + 1, 1,
+                                          cal == gcal ? gdate : null);
+        if (isFieldSet(fieldMask, MONTH)) {
+            // Month-based calculations
+            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
+                // We are on the first day of the month. Just add the
+                // offset if DAY_OF_MONTH is set. If the isSet call
+                // returns false, that means DAY_OF_MONTH has been
+                // selected just because of the selected
+                // combination. We don't need to add any since the
+                // default value is the 1st.
+                if (isSet(DAY_OF_MONTH)) {
+                    // To avoid underflow with DAY_OF_MONTH-1, add
+                    // DAY_OF_MONTH, then subtract 1.
+                    fixedDate += internalGet(DAY_OF_MONTH);
+                    fixedDate--;
+                }
+            } else {
+                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
+                    long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                  getFirstDayOfWeek());
+                    // If we have enough days in the first week, then
+                    // move to the previous week.
+                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                        firstDayOfWeek -= 7;
+                    }
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                 internalGet(DAY_OF_WEEK));
+                    }
+                    // In lenient mode, we treat days of the previous
+                    // months as a part of the specified
+                    // WEEK_OF_MONTH. See 4633646.
+                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
+                } else {
+                    int dayOfWeek;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        dayOfWeek = internalGet(DAY_OF_WEEK);
+                    } else {
+                        dayOfWeek = getFirstDayOfWeek();
+                    }
+                    // We are basing this on the day-of-week-in-month.  The only
+                    // trickiness occurs if the day-of-week-in-month is
+                    // negative.
+                    int dowim;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
+                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
+                    } else {
+                        dowim = 1;
+                    }
+                    if (dowim >= 0) {
+                        fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
+                                                                            dayOfWeek);
+                    } else {
+                        // Go to the first day of the next week of
+                        // the specified week boundary.
+                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
+                        // Then, get the day of week date on or before the last date.
+                        fixedDate = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
+                                                                            dayOfWeek);
+                    }
+                }
+            }
+        } else {
+            if (year == gregorianCutoverYear && cal == gcal
+                && fixedDate < gregorianCutoverDate
+                && gregorianCutoverYear != gregorianCutoverYearJulian) {
+                // January 1 of the year doesn't exist.  Use
+                // gregorianCutoverDate as the first day of the
+                // year.
+                fixedDate = gregorianCutoverDate;
+            }
+            // We are on the first day of the year.
+            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
+                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
+                fixedDate += internalGet(DAY_OF_YEAR);
+                fixedDate--;
+            } else {
+                long firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                              getFirstDayOfWeek());
+                // If we have enough days in the first week, then move
+                // to the previous week.
+                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                    firstDayOfWeek -= 7;
+                }
+                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                    int dayOfWeek = internalGet(DAY_OF_WEEK);
+                    if (dayOfWeek != getFirstDayOfWeek()) {
+                        firstDayOfWeek = BaseCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                 dayOfWeek);
+                    }
+                }
+                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
+            }
+        }
+
+        return fixedDate;
+    }
+
+    /**
+     * Returns this object if it's normalized (all fields and time are
+     * in sync). Otherwise, a cloned object is returned after calling
+     * complete() in lenient mode.
+     */
+    private GregorianCalendar getNormalizedCalendar() {
+        GregorianCalendar gc;
+        if (isFullyNormalized()) {
+            gc = this;
+        } else {
+            // Create a clone and normalize the calendar fields
+            gc = (GregorianCalendar) this.clone();
+            gc.setLenient(true);
+            gc.complete();
+        }
+        return gc;
+    }
+
+    /**
+     * Returns the Julian calendar system instance (singleton). 'jcal'
+     * and 'jeras' are set upon the return.
+     */
+    private static synchronized BaseCalendar getJulianCalendarSystem() {
+        if (jcal == null) {
+            jcal = (JulianCalendar) CalendarSystem.forName("julian");
+            jeras = jcal.getEras();
+        }
+        return jcal;
+    }
+
+    /**
+     * Returns the calendar system for dates before the cutover date
+     * in the cutover year. If the cutover date is January 1, the
+     * method returns Gregorian. Otherwise, Julian.
+     */
+    private BaseCalendar getCutoverCalendarSystem() {
+        if (gregorianCutoverYearJulian < gregorianCutoverYear) {
+            return gcal;
+        }
+        return getJulianCalendarSystem();
+    }
+
+    /**
+     * Determines if the specified year (normalized) is the Gregorian
+     * cutover year. This object must have been normalized.
+     */
+    private boolean isCutoverYear(int normalizedYear) {
+        int cutoverYear = (calsys == gcal) ? gregorianCutoverYear : gregorianCutoverYearJulian;
+        return normalizedYear == cutoverYear;
+    }
+
+    /**
+     * Returns the fixed date of the first day of the year (usually
+     * January 1) before the specified date.
+     *
+     * @param date the date for which the first day of the year is
+     * calculated. The date has to be in the cut-over year (Gregorian
+     * or Julian).
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateJan1(BaseCalendar.Date date, long fixedDate) {
+        assert date.getNormalizedYear() == gregorianCutoverYear ||
+            date.getNormalizedYear() == gregorianCutoverYearJulian;
+        if (gregorianCutoverYear != gregorianCutoverYearJulian) {
+            if (fixedDate >= gregorianCutoverDate) {
+                // Dates before the cutover date don't exist
+                // in the same (Gregorian) year. So, no
+                // January 1 exists in the year. Use the
+                // cutover date as the first day of the year.
+                return gregorianCutoverDate;
+            }
+        }
+        // January 1 of the normalized year should exist.
+        BaseCalendar juliancal = getJulianCalendarSystem();
+        return juliancal.getFixedDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1, null);
+    }
+
+    /**
+     * Returns the fixed date of the first date of the month (usually
+     * the 1st of the month) before the specified date.
+     *
+     * @param date the date for which the first day of the month is
+     * calculated. The date has to be in the cut-over year (Gregorian
+     * or Julian).
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateMonth1(BaseCalendar.Date date, long fixedDate) {
+        assert date.getNormalizedYear() == gregorianCutoverYear ||
+            date.getNormalizedYear() == gregorianCutoverYearJulian;
+        BaseCalendar.Date gCutover = getGregorianCutoverDate();
+        if (gCutover.getMonth() == BaseCalendar.JANUARY
+            && gCutover.getDayOfMonth() == 1) {
+            // The cutover happened on January 1.
+            return fixedDate - date.getDayOfMonth() + 1;
+        }
+
+        long fixedDateMonth1;
+        // The cutover happened sometime during the year.
+        if (date.getMonth() == gCutover.getMonth()) {
+            // The cutover happened in the month.
+            BaseCalendar.Date jLastDate = getLastJulianDate();
+            if (gregorianCutoverYear == gregorianCutoverYearJulian
+                && gCutover.getMonth() == jLastDate.getMonth()) {
+                // The "gap" fits in the same month.
+                fixedDateMonth1 = jcal.getFixedDate(date.getNormalizedYear(),
+                                                    date.getMonth(),
+                                                    1,
+                                                    null);
+            } else {
+                // Use the cutover date as the first day of the month.
+                fixedDateMonth1 = gregorianCutoverDate;
+            }
+        } else {
+            // The cutover happened before the month.
+            fixedDateMonth1 = fixedDate - date.getDayOfMonth() + 1;
+        }
+
+        return fixedDateMonth1;
+    }
+
+    /**
+     * Returns a CalendarDate produced from the specified fixed date.
+     *
+     * @param fd the fixed date
+     */
+    private BaseCalendar.Date getCalendarDate(long fd) {
+        BaseCalendar cal = (fd >= gregorianCutoverDate) ? gcal : getJulianCalendarSystem();
+        BaseCalendar.Date d = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        cal.getCalendarDateFromFixedDate(d, fd);
+        return d;
+    }
+
+    /**
+     * Returns the Gregorian cutover date as a BaseCalendar.Date. The
+     * date is a Gregorian date.
+     */
+    private BaseCalendar.Date getGregorianCutoverDate() {
+        return getCalendarDate(gregorianCutoverDate);
+    }
+
+    /**
+     * Returns the day before the Gregorian cutover date as a
+     * BaseCalendar.Date. The date is a Julian date.
+     */
+    private BaseCalendar.Date getLastJulianDate() {
+        return getCalendarDate(gregorianCutoverDate - 1);
+    }
+
+    /**
+     * Returns the length of the specified month in the specified
+     * year. The year number must be normalized.
+     *
+     * @see #isLeapYear(int)
+     */
+    private int monthLength(int month, int year) {
+        return isLeapYear(year) ? LEAP_MONTH_LENGTH[month] : MONTH_LENGTH[month];
+    }
+
+    /**
+     * Returns the length of the specified month in the year provided
+     * by internalGet(YEAR).
+     *
+     * @see #isLeapYear(int)
+     */
+    private int monthLength(int month) {
+        int year = internalGet(YEAR);
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+        return monthLength(month, year);
+    }
+
+    private int actualMonthLength() {
+        int year = cdate.getNormalizedYear();
+        if (year != gregorianCutoverYear && year != gregorianCutoverYearJulian) {
+            return calsys.getMonthLength(cdate);
+        }
+        BaseCalendar.Date date = (BaseCalendar.Date) cdate.clone();
+        long fd = calsys.getFixedDate(date);
+        long month1 = getFixedDateMonth1(date, fd);
+        long next1 = month1 + calsys.getMonthLength(date);
+        if (next1 < gregorianCutoverDate) {
+            return (int)(next1 - month1);
+        }
+        if (cdate != gdate) {
+            date = (BaseCalendar.Date) gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        }
+        gcal.getCalendarDateFromFixedDate(date, next1);
+        next1 = getFixedDateMonth1(date, next1);
+        return (int)(next1 - month1);
+    }
+
+    /**
+     * Returns the length (in days) of the specified year. The year
+     * must be normalized.
+     */
+    private int yearLength(int year) {
+        return isLeapYear(year) ? 366 : 365;
+    }
+
+    /**
+     * Returns the length (in days) of the year provided by
+     * internalGet(YEAR).
+     */
+    private int yearLength() {
+        int year = internalGet(YEAR);
+        if (internalGetEra() == BCE) {
+            year = 1 - year;
+        }
+        return yearLength(year);
+    }
+
+    /**
+     * After adjustments such as add(MONTH), add(YEAR), we don't want the
+     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
+     * 3, we want it to go to Feb 28.  Adjustments which might run into this
+     * problem call this method to retain the proper month.
+     */
+    private void pinDayOfMonth() {
+        int year = internalGet(YEAR);
+        int monthLen;
+        if (year > gregorianCutoverYear || year < gregorianCutoverYearJulian) {
+            monthLen = monthLength(internalGet(MONTH));
+        } else {
+            GregorianCalendar gc = getNormalizedCalendar();
+            monthLen = gc.getActualMaximum(DAY_OF_MONTH);
+        }
+        int dom = internalGet(DAY_OF_MONTH);
+        if (dom > monthLen) {
+            set(DAY_OF_MONTH, monthLen);
+        }
+    }
+
+    /**
+     * Returns the fixed date value of this object. The time value and
+     * calendar fields must be in synch.
+     */
+    private long getCurrentFixedDate() {
+        return (calsys == gcal) ? cachedFixedDate : calsys.getFixedDate(cdate);
+    }
+
+    /**
+     * Returns the new value after 'roll'ing the specified value and amount.
+     */
+    private static int getRolledValue(int value, int amount, int min, int max) {
+        assert value >= min && value <= max;
+        int range = max - min + 1;
+        amount %= range;
+        int n = value + amount;
+        if (n > max) {
+            n -= range;
+        } else if (n < min) {
+            n += range;
+        }
+        assert n >= min && n <= max;
+        return n;
+    }
+
+    /**
+     * Returns the ERA.  We need a special method for this because the
+     * default ERA is CE, but a zero (unset) ERA is BCE.
+     */
+    private int internalGetEra() {
+        return isSet(ERA) ? internalGet(ERA) : CE;
+    }
+
+    /**
+     * Updates internal state.
+     */
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        if (gdate == null) {
+            gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+            cachedFixedDate = Long.MIN_VALUE;
+        }
+        setGregorianChange(gregorianCutover);
+    }
+
+    /**
+     * Converts this object to a {@code ZonedDateTime} that represents
+     * the same point on the time-line as this {@code GregorianCalendar}.
+     * <p>
+     * Since this object supports a Julian-Gregorian cutover date and
+     * {@code ZonedDateTime} does not, it is possible that the resulting year,
+     * month and day will have different values.  The result will represent the
+     * correct date in the ISO calendar system, which will also be the same value
+     * for Modified Julian Days.
+     *
+     * @return a zoned date-time representing the same point on the time-line
+     *  as this gregorian calendar
+     * @since 1.8
+     */
+    public ZonedDateTime toZonedDateTime() {
+        return ZonedDateTime.ofInstant(Instant.ofEpochMilli(getTimeInMillis()),
+                                       getTimeZone().toZoneId());
+    }
+
+    /**
+     * Obtains an instance of {@code GregorianCalendar} with the default locale
+     * from a {@code ZonedDateTime} object.
+     * <p>
+     * Since {@code ZonedDateTime} does not support a Julian-Gregorian cutover
+     * date and uses ISO calendar system, the return GregorianCalendar is a pure
+     * Gregorian calendar and uses ISO 8601 standard for week definitions,
+     * which has {@code MONDAY} as the {@link Calendar#getFirstDayOfWeek()
+     * FirstDayOfWeek} and {@code 4} as the value of the
+     * {@link Calendar#getMinimalDaysInFirstWeek() MinimalDaysInFirstWeek}.
+     * <p>
+     * {@code ZoneDateTime} can store points on the time-line further in the
+     * future and further in the past than {@code GregorianCalendar}. In this
+     * scenario, this method will throw an {@code IllegalArgumentException}
+     * exception.
+     *
+     * @param zdt  the zoned date-time object to convert
+     * @return  the gregorian calendar representing the same point on the
+     *  time-line as the zoned date-time provided
+     * @exception NullPointerException if {@code zdt} is null
+     * @exception IllegalArgumentException if the zoned date-time is too
+     * large to represent as a {@code GregorianCalendar}
+     * @since 1.8
+     */
+    public static GregorianCalendar from(ZonedDateTime zdt) {
+        GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone(zdt.getZone()));
+        cal.setGregorianChange(new Date(Long.MIN_VALUE));
+        cal.setFirstDayOfWeek(MONDAY);
+        cal.setMinimalDaysInFirstWeek(4);
+        try {
+            cal.setTimeInMillis(Math.addExact(Math.multiplyExact(zdt.toEpochSecond(), 1000),
+                                              zdt.get(ChronoField.MILLI_OF_SECOND)));
+        } catch (ArithmeticException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return cal;
+    }
+}
diff --git a/java/util/HashMap.annotated.java b/java/util/HashMap.annotated.java
new file mode 100644
index 0000000..3bcc489
--- /dev/null
+++ b/java/util/HashMap.annotated.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class HashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V>, java.lang.Cloneable, java.io.Serializable {
+
+public HashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public HashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public HashMap() { throw new RuntimeException("Stub!"); }
+
+public HashMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K, ? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public V getOrDefault(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable V defaultValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public V putIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public boolean replace(@libcore.util.NullFromTypeParam K key, @libcore.util.Nullable V oldValue, @libcore.util.NullFromTypeParam V newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public V replace(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V computeIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NullFromTypeParam K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public V computeIfPresent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public V compute(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/HashMap.java b/java/util/HashMap.java
new file mode 100644
index 0000000..2c01f6f
--- /dev/null
+++ b/java/util/HashMap.java
@@ -0,0 +1,2391 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Hash table based implementation of the <tt>Map</tt> interface.  This
+ * implementation provides all of the optional map operations, and permits
+ * <tt>null</tt> values and the <tt>null</tt> key.  (The <tt>HashMap</tt>
+ * class is roughly equivalent to <tt>Hashtable</tt>, except that it is
+ * unsynchronized and permits nulls.)  This class makes no guarantees as to
+ * the order of the map; in particular, it does not guarantee that the order
+ * will remain constant over time.
+ *
+ * <p>This implementation provides constant-time performance for the basic
+ * operations (<tt>get</tt> and <tt>put</tt>), assuming the hash function
+ * disperses the elements properly among the buckets.  Iteration over
+ * collection views requires time proportional to the "capacity" of the
+ * <tt>HashMap</tt> instance (the number of buckets) plus its size (the number
+ * of key-value mappings).  Thus, it's very important not to set the initial
+ * capacity too high (or the load factor too low) if iteration performance is
+ * important.
+ *
+ * <p>An instance of <tt>HashMap</tt> has two parameters that affect its
+ * performance: <i>initial capacity</i> and <i>load factor</i>.  The
+ * <i>capacity</i> is the number of buckets in the hash table, and the initial
+ * capacity is simply the capacity at the time the hash table is created.  The
+ * <i>load factor</i> is a measure of how full the hash table is allowed to
+ * get before its capacity is automatically increased.  When the number of
+ * entries in the hash table exceeds the product of the load factor and the
+ * current capacity, the hash table is <i>rehashed</i> (that is, internal data
+ * structures are rebuilt) so that the hash table has approximately twice the
+ * number of buckets.
+ *
+ * <p>As a general rule, the default load factor (.75) offers a good
+ * tradeoff between time and space costs.  Higher values decrease the
+ * space overhead but increase the lookup cost (reflected in most of
+ * the operations of the <tt>HashMap</tt> class, including
+ * <tt>get</tt> and <tt>put</tt>).  The expected number of entries in
+ * the map and its load factor should be taken into account when
+ * setting its initial capacity, so as to minimize the number of
+ * rehash operations.  If the initial capacity is greater than the
+ * maximum number of entries divided by the load factor, no rehash
+ * operations will ever occur.
+ *
+ * <p>If many mappings are to be stored in a <tt>HashMap</tt>
+ * instance, creating it with a sufficiently large capacity will allow
+ * the mappings to be stored more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table.  Note that using
+ * many keys with the same {@code hashCode()} is a sure way to slow
+ * down performance of any hash table. To ameliorate impact, when keys
+ * are {@link Comparable}, this class may use comparison order among
+ * keys to help break ties.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a hash map concurrently, and at least one of
+ * the threads modifies the map structurally, it <i>must</i> be
+ * synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more mappings; merely changing the value
+ * associated with a key that an instance already contains is not a
+ * structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new HashMap(...));</pre>
+ *
+ * <p>The iterators returned by all of this class's "collection view methods"
+ * are <i>fail-fast</i>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, the iterator will throw a
+ * {@link ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the
+ * future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Doug Lea
+ * @author  Josh Bloch
+ * @author  Arthur van Hoff
+ * @author  Neal Gafter
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     TreeMap
+ * @see     Hashtable
+ * @since   1.2
+ */
+public class HashMap<K,V> extends AbstractMap<K,V>
+    implements Map<K,V>, Cloneable, Serializable {
+
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /*
+     * Implementation notes.
+     *
+     * This map usually acts as a binned (bucketed) hash table, but
+     * when bins get too large, they are transformed into bins of
+     * TreeNodes, each structured similarly to those in
+     * java.util.TreeMap. Most methods try to use normal bins, but
+     * relay to TreeNode methods when applicable (simply by checking
+     * instanceof a node).  Bins of TreeNodes may be traversed and
+     * used like any others, but additionally support faster lookup
+     * when overpopulated. However, since the vast majority of bins in
+     * normal use are not overpopulated, checking for existence of
+     * tree bins may be delayed in the course of table methods.
+     *
+     * Tree bins (i.e., bins whose elements are all TreeNodes) are
+     * ordered primarily by hashCode, but in the case of ties, if two
+     * elements are of the same "class C implements Comparable<C>",
+     * type then their compareTo method is used for ordering. (We
+     * conservatively check generic types via reflection to validate
+     * this -- see method comparableClassFor).  The added complexity
+     * of tree bins is worthwhile in providing worst-case O(log n)
+     * operations when keys either have distinct hashes or are
+     * orderable, Thus, performance degrades gracefully under
+     * accidental or malicious usages in which hashCode() methods
+     * return values that are poorly distributed, as well as those in
+     * which many keys share a hashCode, so long as they are also
+     * Comparable. (If neither of these apply, we may waste about a
+     * factor of two in time and space compared to taking no
+     * precautions. But the only known cases stem from poor user
+     * programming practices that are already so slow that this makes
+     * little difference.)
+     *
+     * Because TreeNodes are about twice the size of regular nodes, we
+     * use them only when bins contain enough nodes to warrant use
+     * (see TREEIFY_THRESHOLD). And when they become too small (due to
+     * removal or resizing) they are converted back to plain bins.  In
+     * usages with well-distributed user hashCodes, tree bins are
+     * rarely used.  Ideally, under random hashCodes, the frequency of
+     * nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average for the default resizing
+     * threshold of 0.75, although with a large variance because of
+     * resizing granularity. Ignoring variance, the expected
+     * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
+     * factorial(k)). The first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * The root of a tree bin is normally its first node.  However,
+     * sometimes (currently only upon Iterator.remove), the root might
+     * be elsewhere, but can be recovered following parent links
+     * (method TreeNode.root()).
+     *
+     * All applicable internal methods accept a hash code as an
+     * argument (as normally supplied from a public method), allowing
+     * them to call each other without recomputing user hashCodes.
+     * Most internal methods also accept a "tab" argument, that is
+     * normally the current table, but may be a new or old one when
+     * resizing or converting.
+     *
+     * When bin lists are treeified, split, or untreeified, we keep
+     * them in the same relative access/traversal order (i.e., field
+     * Node.next) to better preserve locality, and to slightly
+     * simplify handling of splits and traversals that invoke
+     * iterator.remove. When using comparators on insertion, to keep a
+     * total ordering (or as close as is required here) across
+     * rebalancings, we compare classes and identityHashCodes as
+     * tie-breakers.
+     *
+     * The use and transitions among plain vs tree modes is
+     * complicated by the existence of subclass LinkedHashMap. See
+     * below for hook methods defined to be invoked upon insertion,
+     * removal and access that allow LinkedHashMap internals to
+     * otherwise remain independent of these mechanics. (This also
+     * requires that a map instance be passed to some utility methods
+     * that may create new nodes.)
+     *
+     * The concurrent-programming-like SSA-based coding style helps
+     * avoid aliasing errors amid all of the twisty pointer operations.
+     */
+
+    /**
+     * The default initial capacity - MUST be a power of two.
+     */
+    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     */
+    static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2 and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
+     * between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Basic hash bin node, used for most entries.  (See below for
+     * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
+     */
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        V value;
+        Node<K,V> next;
+
+        Node(int hash, K key, V value, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        public final K getKey()        { return key; }
+        public final V getValue()      { return value; }
+        public final String toString() { return key + "=" + value; }
+
+        public final int hashCode() {
+            return Objects.hashCode(key) ^ Objects.hashCode(value);
+        }
+
+        public final V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public final boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                if (Objects.equals(key, e.getKey()) &&
+                    Objects.equals(value, e.getValue()))
+                    return true;
+            }
+            return false;
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
+
+    /**
+     * Computes key.hashCode() and spreads (XORs) higher bits of hash
+     * to lower.  Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int hash(Object key) {
+        int h;
+        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /**
+     * Returns a power of two size for the given target capacity.
+     */
+    static final int tableSizeFor(int cap) {
+        int n = cap - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The table, initialized on first use, and resized as
+     * necessary. When allocated, length is always a power of two.
+     * (We also tolerate length zero in some operations to allow
+     * bootstrapping mechanics that are currently not needed.)
+     */
+    transient Node<K,V>[] table;
+
+    /**
+     * Holds cached entrySet(). Note that AbstractMap fields are used
+     * for keySet() and values().
+     */
+    transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * The number of key-value mappings contained in this map.
+     */
+    transient int size;
+
+    /**
+     * The number of times this HashMap has been structurally modified
+     * Structural modifications are those that change the number of mappings in
+     * the HashMap or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the HashMap fail-fast.  (See ConcurrentModificationException).
+     */
+    transient int modCount;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     *
+     * @serial
+     */
+    // (The javadoc description is true upon serialization.
+    // Additionally, if the table array has not been allocated, this
+    // field holds the initial array capacity, or zero signifying
+    // DEFAULT_INITIAL_CAPACITY.)
+    int threshold;
+
+    /**
+     * The load factor for the hash table.
+     *
+     * @serial
+     */
+    final float loadFactor;
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and load factor.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public HashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal initial capacity: " +
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal load factor: " +
+                                               loadFactor);
+        this.loadFactor = loadFactor;
+        this.threshold = tableSizeFor(initialCapacity);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public HashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public HashMap() {
+        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
+    }
+
+    /**
+     * Constructs a new <tt>HashMap</tt> with the same mappings as the
+     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified <tt>Map</tt>.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     */
+    public HashMap(Map<? extends K, ? extends V> m) {
+        this.loadFactor = DEFAULT_LOAD_FACTOR;
+        putMapEntries(m, false);
+    }
+
+    /**
+     * Implements Map.putAll and Map constructor
+     *
+     * @param m the map
+     * @param evict false when initially constructing this map, else
+     * true (relayed to method afterNodeInsertion).
+     */
+    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
+        int s = m.size();
+        if (s > 0) {
+            if (table == null) { // pre-size
+                float ft = ((float)s / loadFactor) + 1.0F;
+                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
+                         (int)ft : MAXIMUM_CAPACITY);
+                if (t > threshold)
+                    threshold = tableSizeFor(t);
+            }
+            else if (s > threshold)
+                resize();
+            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                putVal(hash(key), key, value, false, evict);
+            }
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     *
+     * @return <tt>true</tt> if this map contains no key-value mappings
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    public V get(Object key) {
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? null : e.value;
+    }
+
+    /**
+     * Implements Map.get and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @return the node, or null if none
+     */
+    final Node<K,V> getNode(int hash, Object key) {
+        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (first = tab[(n - 1) & hash]) != null) {
+            if (first.hash == hash && // always check first node
+                ((k = first.key) == key || (key != null && key.equals(k))))
+                return first;
+            if ((e = first.next) != null) {
+                if (first instanceof TreeNode)
+                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param   key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map contains a mapping for the specified
+     * key.
+     */
+    public boolean containsKey(Object key) {
+        return getNode(hash(key), key) != null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V put(K key, V value) {
+        return putVal(hash(key), key, value, false, true);
+    }
+
+    /**
+     * Implements Map.put and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to put
+     * @param onlyIfAbsent if true, don't change existing value
+     * @param evict if false, the table is in creation mode.
+     * @return previous value, or null if none
+     */
+    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
+                   boolean evict) {
+        Node<K,V>[] tab; Node<K,V> p; int n, i;
+        if ((tab = table) == null || (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((p = tab[i = (n - 1) & hash]) == null)
+            tab[i] = newNode(hash, key, value, null);
+        else {
+            Node<K,V> e; K k;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                e = p;
+            else if (p instanceof TreeNode)
+                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
+            else {
+                for (int binCount = 0; ; ++binCount) {
+                    if ((e = p.next) == null) {
+                        p.next = newNode(hash, key, value, null);
+                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
+                            treeifyBin(tab, hash);
+                        break;
+                    }
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        break;
+                    p = e;
+                }
+            }
+            if (e != null) { // existing mapping for key
+                V oldValue = e.value;
+                if (!onlyIfAbsent || oldValue == null)
+                    e.value = value;
+                afterNodeAccess(e);
+                return oldValue;
+            }
+        }
+        ++modCount;
+        if (++size > threshold)
+            resize();
+        afterNodeInsertion(evict);
+        return null;
+    }
+
+    /**
+     * Initializes or doubles table size.  If null, allocates in
+     * accord with initial capacity target held in field threshold.
+     * Otherwise, because we are using power-of-two expansion, the
+     * elements from each bin must either stay at same index, or move
+     * with a power of two offset in the new table.
+     *
+     * @return the table
+     */
+    final Node<K,V>[] resize() {
+        Node<K,V>[] oldTab = table;
+        int oldCap = (oldTab == null) ? 0 : oldTab.length;
+        int oldThr = threshold;
+        int newCap, newThr = 0;
+        if (oldCap > 0) {
+            if (oldCap >= MAXIMUM_CAPACITY) {
+                threshold = Integer.MAX_VALUE;
+                return oldTab;
+            }
+            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
+                     oldCap >= DEFAULT_INITIAL_CAPACITY)
+                newThr = oldThr << 1; // double threshold
+        }
+        else if (oldThr > 0) // initial capacity was placed in threshold
+            newCap = oldThr;
+        else {               // zero initial threshold signifies using defaults
+            newCap = DEFAULT_INITIAL_CAPACITY;
+            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
+        }
+        if (newThr == 0) {
+            float ft = (float)newCap * loadFactor;
+            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
+                      (int)ft : Integer.MAX_VALUE);
+        }
+        threshold = newThr;
+        @SuppressWarnings({"rawtypes","unchecked"})
+            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+        table = newTab;
+        if (oldTab != null) {
+            for (int j = 0; j < oldCap; ++j) {
+                Node<K,V> e;
+                if ((e = oldTab[j]) != null) {
+                    oldTab[j] = null;
+                    if (e.next == null)
+                        newTab[e.hash & (newCap - 1)] = e;
+                    else if (e instanceof TreeNode)
+                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
+                    else { // preserve order
+                        Node<K,V> loHead = null, loTail = null;
+                        Node<K,V> hiHead = null, hiTail = null;
+                        Node<K,V> next;
+                        do {
+                            next = e.next;
+                            if ((e.hash & oldCap) == 0) {
+                                if (loTail == null)
+                                    loHead = e;
+                                else
+                                    loTail.next = e;
+                                loTail = e;
+                            }
+                            else {
+                                if (hiTail == null)
+                                    hiHead = e;
+                                else
+                                    hiTail.next = e;
+                                hiTail = e;
+                            }
+                        } while ((e = next) != null);
+                        if (loTail != null) {
+                            loTail.next = null;
+                            newTab[j] = loHead;
+                        }
+                        if (hiTail != null) {
+                            hiTail.next = null;
+                            newTab[j + oldCap] = hiHead;
+                        }
+                    }
+                }
+            }
+        }
+        return newTab;
+    }
+
+    /**
+     * Replaces all linked nodes in bin at index for given hash unless
+     * table is too small, in which case resizes instead.
+     */
+    final void treeifyBin(Node<K,V>[] tab, int hash) {
+        int n, index; Node<K,V> e;
+        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
+            resize();
+        else if ((e = tab[index = (n - 1) & hash]) != null) {
+            TreeNode<K,V> hd = null, tl = null;
+            do {
+                TreeNode<K,V> p = replacementTreeNode(e, null);
+                if (tl == null)
+                    hd = p;
+                else {
+                    p.prev = tl;
+                    tl.next = p;
+                }
+                tl = p;
+            } while ((e = e.next) != null);
+            if ((tab[index] = hd) != null)
+                hd.treeify(tab);
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        putMapEntries(m, true);
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @param  key key whose mapping is to be removed from the map
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V remove(Object key) {
+        Node<K,V> e;
+        return (e = removeNode(hash(key), key, null, false, true)) == null ?
+            null : e.value;
+    }
+
+    /**
+     * Implements Map.remove and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to match if matchValue, else ignored
+     * @param matchValue if true only remove if value is equal
+     * @param movable if false do not move other nodes while removing
+     * @return the node, or null if none
+     */
+    final Node<K,V> removeNode(int hash, Object key, Object value,
+                               boolean matchValue, boolean movable) {
+        Node<K,V>[] tab; Node<K,V> p; int n, index;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (p = tab[index = (n - 1) & hash]) != null) {
+            Node<K,V> node = null, e; K k; V v;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                node = p;
+            else if ((e = p.next) != null) {
+                if (p instanceof TreeNode)
+                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
+                else {
+                    do {
+                        if (e.hash == hash &&
+                            ((k = e.key) == key ||
+                             (key != null && key.equals(k)))) {
+                            node = e;
+                            break;
+                        }
+                        p = e;
+                    } while ((e = e.next) != null);
+                }
+            }
+            if (node != null && (!matchValue || (v = node.value) == value ||
+                                 (value != null && value.equals(v)))) {
+                if (node instanceof TreeNode)
+                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
+                else if (node == p)
+                    tab[index] = node.next;
+                else
+                    p.next = node.next;
+                ++modCount;
+                --size;
+                afterNodeRemoval(node);
+                return node;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        Node<K,V>[] tab;
+        modCount++;
+        if ((tab = table) != null && size > 0) {
+            size = 0;
+            for (int i = 0; i < tab.length; ++i)
+                tab[i] = null;
+        }
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value
+     */
+    public boolean containsValue(Object value) {
+        Node<K,V>[] tab; V v;
+        if ((tab = table) != null && size > 0) {
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    if ((v = e.value) == value ||
+                        (value != null && value.equals(v)))
+                        return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    final class KeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<K> iterator()     { return new KeyIterator(); }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator() {
+            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super K> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.key);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    final class Values extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<V> iterator()     { return new ValueIterator(); }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super V> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.value);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
+    }
+
+    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                // Android-changed: Detect changes to modCount early.
+                for (int i = 0; (i < tab.length && modCount == mc); ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // Overrides of JDK8 Map extension methods
+
+    @Override
+    public V getOrDefault(Object key, V defaultValue) {
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
+    }
+
+    @Override
+    public V putIfAbsent(K key, V value) {
+        return putVal(hash(key), key, value, true, true);
+    }
+
+    @Override
+    public boolean remove(Object key, Object value) {
+        return removeNode(hash(key), key, value, true, true) != null;
+    }
+
+    @Override
+    public boolean replace(K key, V oldValue, V newValue) {
+        Node<K,V> e; V v;
+        if ((e = getNode(hash(key), key)) != null &&
+            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
+            e.value = newValue;
+            afterNodeAccess(e);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public V replace(K key, V value) {
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) != null) {
+            V oldValue = e.value;
+            e.value = value;
+            afterNodeAccess(e);
+            return oldValue;
+        }
+        return null;
+    }
+
+    @Override
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (mappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+            V oldValue;
+            if (old != null && (oldValue = old.value) != null) {
+                afterNodeAccess(old);
+                return oldValue;
+            }
+        }
+        V v = mappingFunction.apply(key);
+        if (v == null) {
+            return null;
+        } else if (old != null) {
+            old.value = v;
+            afterNodeAccess(old);
+            return v;
+        }
+        else if (t != null)
+            t.putTreeVal(this, tab, hash, key, v);
+        else {
+            tab[i] = newNode(hash, key, v, first);
+            if (binCount >= TREEIFY_THRESHOLD - 1)
+                treeifyBin(tab, hash);
+        }
+        ++modCount;
+        ++size;
+        afterNodeInsertion(true);
+        return v;
+    }
+
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        Node<K,V> e; V oldValue;
+        int hash = hash(key);
+        if ((e = getNode(hash, key)) != null &&
+            (oldValue = e.value) != null) {
+            V v = remappingFunction.apply(key, oldValue);
+            if (v != null) {
+                e.value = v;
+                afterNodeAccess(e);
+                return v;
+            }
+            else
+                removeNode(hash, key, null, false, true);
+        }
+        return null;
+    }
+
+    @Override
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        V oldValue = (old == null) ? null : old.value;
+        V v = remappingFunction.apply(key, oldValue);
+        if (old != null) {
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+        }
+        else if (v != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, v);
+            else {
+                tab[i] = newNode(hash, key, v, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return v;
+    }
+
+    @Override
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (value == null)
+            throw new NullPointerException();
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        if (old != null) {
+            V v;
+            if (old.value != null)
+                v = remappingFunction.apply(old.value, value);
+            else
+                v = value;
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+            return v;
+        }
+        if (value != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, value);
+            else {
+                tab[i] = newNode(hash, key, value, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return value;
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Node<K,V>[] tab;
+        if (action == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (int i = 0; (i < tab.length && mc == modCount); ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                    action.accept(e.key, e.value);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Node<K,V>[] tab;
+        if (function == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    e.value = function.apply(e.key, e.value);
+                }
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Cloning and serialization
+
+    /**
+     * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
+     * values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object clone() {
+        HashMap<K,V> result;
+        try {
+            result = (HashMap<K,V>)super.clone();
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+        result.reinitialize();
+        result.putMapEntries(this, false);
+        return result;
+    }
+
+    // These methods are also used when serializing HashSets
+    final float loadFactor() { return loadFactor; }
+    final int capacity() {
+        return (table != null) ? table.length :
+            (threshold > 0) ? threshold :
+            DEFAULT_INITIAL_CAPACITY;
+    }
+
+    /**
+     * Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>capacity</i> of the HashMap (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> (an int, the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping.  The key-value mappings are
+     *             emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws IOException {
+        int buckets = capacity();
+        // Write out the threshold, loadfactor, and any hidden stuff
+        s.defaultWriteObject();
+        s.writeInt(buckets);
+        s.writeInt(size);
+        internalWriteEntries(s);
+    }
+
+    /**
+     * Reconstitute the {@code HashMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws IOException, ClassNotFoundException {
+        // Read in the threshold (ignored), loadfactor, and any hidden stuff
+        s.defaultReadObject();
+        reinitialize();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        s.readInt();                // Read and ignore number of buckets
+        int mappings = s.readInt(); // Read number of mappings (size)
+        if (mappings < 0)
+            throw new InvalidObjectException("Illegal mappings count: " +
+                                             mappings);
+        else if (mappings > 0) { // (if zero, use defaults)
+            // Size the table using given load factor only if within
+            // range of 0.25...4.0
+            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
+            float fc = (float)mappings / lf + 1.0f;
+            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
+                       DEFAULT_INITIAL_CAPACITY :
+                       (fc >= MAXIMUM_CAPACITY) ?
+                       MAXIMUM_CAPACITY :
+                       tableSizeFor((int)fc));
+            float ft = (float)cap * lf;
+            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
+                         (int)ft : Integer.MAX_VALUE);
+            @SuppressWarnings({"rawtypes","unchecked"})
+                Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+            table = tab;
+
+            // Read the keys and values, and put the mappings in the HashMap
+            for (int i = 0; i < mappings; i++) {
+                @SuppressWarnings("unchecked")
+                    K key = (K) s.readObject();
+                @SuppressWarnings("unchecked")
+                    V value = (V) s.readObject();
+                putVal(hash(key), key, value, false, false);
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // iterators
+
+    abstract class HashIterator {
+        Node<K,V> next;        // next entry to return
+        Node<K,V> current;     // current entry
+        int expectedModCount;  // for fast-fail
+        int index;             // current slot
+
+        HashIterator() {
+            expectedModCount = modCount;
+            Node<K,V>[] t = table;
+            current = next = null;
+            index = 0;
+            if (t != null && size > 0) { // advance to first entry
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final Node<K,V> nextNode() {
+            Node<K,V>[] t;
+            Node<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            if ((next = (current = e).next) == null && (t = table) != null) {
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            K key = p.key;
+            removeNode(hash(key), key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class KeyIterator extends HashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().key; }
+    }
+
+    final class ValueIterator extends HashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class EntryIterator extends HashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+    /* ------------------------------------------------------------ */
+    // spliterators
+
+    static class HashMapSpliterator<K,V> {
+        final HashMap<K,V> map;
+        Node<K,V> current;          // current node
+        int index;                  // current index, modified on advance/split
+        int fence;                  // one past last index
+        int est;                    // size estimate
+        int expectedModCount;       // for comodification checks
+
+        HashMapSpliterator(HashMap<K,V> m, int origin,
+                           int fence, int est,
+                           int expectedModCount) {
+            this.map = m;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                HashMap<K,V> m = map;
+                est = m.size;
+                expectedModCount = m.modCount;
+                Node<K,V>[] tab = m.table;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new KeySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p.key);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        K k = current.key;
+                        current = current.next;
+                        action.accept(k);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p.value);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        V v = current.value;
+                        current = current.next;
+                        action.accept(v);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0);
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends HashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid || current != null) ? null :
+                new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            HashMap<K,V> m = map;
+            Node<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = (tab == null) ? 0 : tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
+                current = null;
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        action.accept(p);
+                        p = p.next;
+                    }
+                } while (p != null || i < hi);
+                if (m.modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Node<K,V> e = current;
+                        current = current.next;
+                        action.accept(e);
+                        if (map.modCount != expectedModCount)
+                            throw new ConcurrentModificationException();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // LinkedHashMap support
+
+
+    /*
+     * The following package-protected methods are designed to be
+     * overridden by LinkedHashMap, but not by any other subclass.
+     * Nearly all other internal methods are also package-protected
+     * but are declared final, so can be used by LinkedHashMap, view
+     * classes, and HashSet.
+     */
+
+    // Create a regular (non-tree) node
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
+        return new Node<>(hash, key, value, next);
+    }
+
+    // For conversion from TreeNodes to plain nodes
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        return new Node<>(p.hash, p.key, p.value, next);
+    }
+
+    // Create a tree bin node
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        return new TreeNode<>(hash, key, value, next);
+    }
+
+    // For treeifyBin
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        return new TreeNode<>(p.hash, p.key, p.value, next);
+    }
+
+    /**
+     * Reset to initial default state.  Called by clone and readObject.
+     */
+    void reinitialize() {
+        table = null;
+        entrySet = null;
+        keySet = null;
+        values = null;
+        modCount = 0;
+        threshold = 0;
+        size = 0;
+    }
+
+    // Callbacks to allow LinkedHashMap post-actions
+    void afterNodeAccess(Node<K,V> p) { }
+    void afterNodeInsertion(boolean evict) { }
+    void afterNodeRemoval(Node<K,V> p) { }
+
+    // Called only from writeObject, to ensure compatible ordering.
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        Node<K,V>[] tab;
+        if (size > 0 && (tab = table) != null) {
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    s.writeObject(e.key);
+                    s.writeObject(e.value);
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Tree bins
+
+    /**
+     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
+     * extends Node) so can be used as extension of either regular or
+     * linked node.
+     */
+    static final class TreeNode<K,V> extends LinkedHashMap.LinkedHashMapEntry<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+        TreeNode(int hash, K key, V val, Node<K,V> next) {
+            super(hash, key, val, next);
+        }
+
+        /**
+         * Returns root of tree containing this node.
+         */
+        final TreeNode<K,V> root() {
+            for (TreeNode<K,V> r = this, p;;) {
+                if ((p = r.parent) == null)
+                    return r;
+                r = p;
+            }
+        }
+
+        /**
+         * Ensures that the given root is the first node of its bin.
+         */
+        static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
+            int n;
+            if (root != null && tab != null && (n = tab.length) > 0) {
+                int index = (n - 1) & root.hash;
+                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
+                if (root != first) {
+                    Node<K,V> rn;
+                    tab[index] = root;
+                    TreeNode<K,V> rp = root.prev;
+                    if ((rn = root.next) != null)
+                        ((TreeNode<K,V>)rn).prev = rp;
+                    if (rp != null)
+                        rp.next = rn;
+                    if (first != null)
+                        first.prev = root;
+                    root.next = first;
+                    root.prev = null;
+                }
+                assert checkInvariants(root);
+            }
+        }
+
+        /**
+         * Finds the node starting at root p with the given hash and key.
+         * The kc argument caches comparableClassFor(key) upon first use
+         * comparing keys.
+         */
+        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
+            TreeNode<K,V> p = this;
+            do {
+                int ph, dir; K pk;
+                TreeNode<K,V> pl = p.left, pr = p.right, q;
+                if ((ph = p.hash) > h)
+                    p = pl;
+                else if (ph < h)
+                    p = pr;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if (pl == null)
+                    p = pr;
+                else if (pr == null)
+                    p = pl;
+                else if ((kc != null ||
+                          (kc = comparableClassFor(k)) != null) &&
+                         (dir = compareComparables(kc, k, pk)) != 0)
+                    p = (dir < 0) ? pl : pr;
+                else if ((q = pr.find(h, k, kc)) != null)
+                    return q;
+                else
+                    p = pl;
+            } while (p != null);
+            return null;
+        }
+
+        /**
+         * Calls find for root node.
+         */
+        final TreeNode<K,V> getTreeNode(int h, Object k) {
+            return ((parent != null) ? root() : this).find(h, k, null);
+        }
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Forms tree of the nodes linked from this node.
+         * @return root of tree
+         */
+        final void treeify(Node<K,V>[] tab) {
+            TreeNode<K,V> root = null;
+            for (TreeNode<K,V> x = this, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (root == null) {
+                    x.parent = null;
+                    x.red = false;
+                    root = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = root;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            root = balanceInsertion(root, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            moveRootToFront(tab, root);
+        }
+
+        /**
+         * Returns a list of non-TreeNodes replacing those linked from
+         * this node.
+         */
+        final Node<K,V> untreeify(HashMap<K,V> map) {
+            Node<K,V> hd = null, tl = null;
+            for (Node<K,V> q = this; q != null; q = q.next) {
+                Node<K,V> p = map.replacementNode(q, null);
+                if (tl == null)
+                    hd = p;
+                else
+                    tl.next = p;
+                tl = p;
+            }
+            return hd;
+        }
+
+        /**
+         * Tree version of putVal.
+         */
+        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
+                                       int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            TreeNode<K,V> root = (parent != null) ? root() : this;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.find(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.find(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    Node<K,V> xpn = xp.next;
+                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    xp.next = x;
+                    x.parent = x.prev = xp;
+                    if (xpn != null)
+                        ((TreeNode<K,V>)xpn).prev = x;
+                    moveRootToFront(tab, balanceInsertion(root, x));
+                    return null;
+                }
+            }
+        }
+
+        /**
+         * Removes the given node, that must be present before this call.
+         * This is messier than typical red-black deletion code because we
+         * cannot swap the contents of an interior node with a leaf
+         * successor that is pinned by "next" pointers that are accessible
+         * independently during traversal. So instead we swap the tree
+         * linkages. If the current tree appears to have too few nodes,
+         * the bin is converted back to a plain bin. (The test triggers
+         * somewhere between 2 and 6 nodes, depending on tree structure).
+         */
+        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
+                                  boolean movable) {
+            int n;
+            if (tab == null || (n = tab.length) == 0)
+                return;
+            int index = (n - 1) & hash;
+            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
+            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
+            if (pred == null)
+                tab[index] = first = succ;
+            else
+                pred.next = succ;
+            if (succ != null)
+                succ.prev = pred;
+            if (first == null)
+                return;
+            if (root.parent != null)
+                root = root.root();
+            if (root == null || root.right == null ||
+                (rl = root.left) == null || rl.left == null) {
+                tab[index] = first.untreeify(map);  // too small
+                return;
+            }
+            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
+            if (pl != null && pr != null) {
+                TreeNode<K,V> s = pr, sl;
+                while ((sl = s.left) != null) // find successor
+                    s = sl;
+                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                TreeNode<K,V> sr = s.right;
+                TreeNode<K,V> pp = p.parent;
+                if (s == pr) { // p was s's direct parent
+                    p.parent = s;
+                    s.right = p;
+                }
+                else {
+                    TreeNode<K,V> sp = s.parent;
+                    if ((p.parent = sp) != null) {
+                        if (s == sp.left)
+                            sp.left = p;
+                        else
+                            sp.right = p;
+                    }
+                    if ((s.right = pr) != null)
+                        pr.parent = s;
+                }
+                p.left = null;
+                if ((p.right = sr) != null)
+                    sr.parent = p;
+                if ((s.left = pl) != null)
+                    pl.parent = s;
+                if ((s.parent = pp) == null)
+                    root = s;
+                else if (p == pp.left)
+                    pp.left = s;
+                else
+                    pp.right = s;
+                if (sr != null)
+                    replacement = sr;
+                else
+                    replacement = p;
+            }
+            else if (pl != null)
+                replacement = pl;
+            else if (pr != null)
+                replacement = pr;
+            else
+                replacement = p;
+            if (replacement != p) {
+                TreeNode<K,V> pp = replacement.parent = p.parent;
+                if (pp == null)
+                    root = replacement;
+                else if (p == pp.left)
+                    pp.left = replacement;
+                else
+                    pp.right = replacement;
+                p.left = p.right = p.parent = null;
+            }
+
+            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
+
+            if (replacement == p) {  // detach
+                TreeNode<K,V> pp = p.parent;
+                p.parent = null;
+                if (pp != null) {
+                    if (p == pp.left)
+                        pp.left = null;
+                    else if (p == pp.right)
+                        pp.right = null;
+                }
+            }
+            if (movable)
+                moveRootToFront(tab, r);
+        }
+
+        /**
+         * Splits nodes in a tree bin into lower and upper tree bins,
+         * or untreeifies if now too small. Called only from resize;
+         * see above discussion about split bits and indices.
+         *
+         * @param map the map
+         * @param tab the table for recording bin heads
+         * @param index the index of the table being split
+         * @param bit the bit of hash to split on
+         */
+        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
+            TreeNode<K,V> b = this;
+            // Relink into lo and hi lists, preserving order
+            TreeNode<K,V> loHead = null, loTail = null;
+            TreeNode<K,V> hiHead = null, hiTail = null;
+            int lc = 0, hc = 0;
+            for (TreeNode<K,V> e = b, next; e != null; e = next) {
+                next = (TreeNode<K,V>)e.next;
+                e.next = null;
+                if ((e.hash & bit) == 0) {
+                    if ((e.prev = loTail) == null)
+                        loHead = e;
+                    else
+                        loTail.next = e;
+                    loTail = e;
+                    ++lc;
+                }
+                else {
+                    if ((e.prev = hiTail) == null)
+                        hiHead = e;
+                    else
+                        hiTail.next = e;
+                    hiTail = e;
+                    ++hc;
+                }
+            }
+
+            if (loHead != null) {
+                if (lc <= UNTREEIFY_THRESHOLD)
+                    tab[index] = loHead.untreeify(map);
+                else {
+                    tab[index] = loHead;
+                    if (hiHead != null) // (else is already treeified)
+                        loHead.treeify(tab);
+                }
+            }
+            if (hiHead != null) {
+                if (hc <= UNTREEIFY_THRESHOLD)
+                    tab[index + bit] = hiHead.untreeify(map);
+                else {
+                    tab[index + bit] = hiHead;
+                    if (loHead != null)
+                        hiHead.treeify(tab);
+                }
+            }
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;)  {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Recursive invariant check
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+    }
+
+}
diff --git a/java/util/HashSet.annotated.java b/java/util/HashSet.annotated.java
new file mode 100644
index 0000000..c099118
--- /dev/null
+++ b/java/util/HashSet.annotated.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class HashSet<E> extends java.util.AbstractSet<E> implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
+
+public HashSet() { throw new RuntimeException("Stub!"); }
+
+public HashSet(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public HashSet(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public HashSet(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/HashSet.java b/java/util/HashSet.java
new file mode 100644
index 0000000..f9b09ee
--- /dev/null
+++ b/java/util/HashSet.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.InvalidObjectException;
+
+/**
+ * This class implements the <tt>Set</tt> interface, backed by a hash table
+ * (actually a <tt>HashMap</tt> instance).  It makes no guarantees as to the
+ * iteration order of the set; in particular, it does not guarantee that the
+ * order will remain constant over time.  This class permits the <tt>null</tt>
+ * element.
+ *
+ * <p>This class offers constant time performance for the basic operations
+ * (<tt>add</tt>, <tt>remove</tt>, <tt>contains</tt> and <tt>size</tt>),
+ * assuming the hash function disperses the elements properly among the
+ * buckets.  Iterating over this set requires time proportional to the sum of
+ * the <tt>HashSet</tt> instance's size (the number of elements) plus the
+ * "capacity" of the backing <tt>HashMap</tt> instance (the number of
+ * buckets).  Thus, it's very important not to set the initial capacity too
+ * high (or the load factor too low) if iteration performance is important.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a hash set concurrently, and at least one of
+ * the threads modifies the set, it <i>must</i> be synchronized externally.
+ * This is typically accomplished by synchronizing on some object that
+ * naturally encapsulates the set.
+ *
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSet Collections.synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set:<pre>
+ *   Set s = Collections.synchronizedSet(new HashSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's <tt>iterator</tt> method are
+ * <i>fail-fast</i>: if the set is modified at any time after the iterator is
+ * created, in any way except through the iterator's own <tt>remove</tt>
+ * method, the Iterator throws a {@link ConcurrentModificationException}.
+ * Thus, in the face of concurrent modification, the iterator fails quickly
+ * and cleanly, rather than risking arbitrary, non-deterministic behavior at
+ * an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Collection
+ * @see     Set
+ * @see     TreeSet
+ * @see     HashMap
+ * @since   1.2
+ */
+
+public class HashSet<E>
+    extends AbstractSet<E>
+    implements Set<E>, Cloneable, java.io.Serializable
+{
+    static final long serialVersionUID = -5024744406713321676L;
+
+    private transient HashMap<E,Object> map;
+
+    // Dummy value to associate with an Object in the backing Map
+    private static final Object PRESENT = new Object();
+
+    /**
+     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
+     * default initial capacity (16) and load factor (0.75).
+     */
+    public HashSet() {
+        map = new HashMap<>();
+    }
+
+    /**
+     * Constructs a new set containing the elements in the specified
+     * collection.  The <tt>HashMap</tt> is created with default load factor
+     * (0.75) and an initial capacity sufficient to contain the elements in
+     * the specified collection.
+     *
+     * @param c the collection whose elements are to be placed into this set
+     * @throws NullPointerException if the specified collection is null
+     */
+    public HashSet(Collection<? extends E> c) {
+        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
+     * the specified initial capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hash map
+     * @param      loadFactor        the load factor of the hash map
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive
+     */
+    public HashSet(int initialCapacity, float loadFactor) {
+        map = new HashMap<>(initialCapacity, loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
+     * the specified initial capacity and default load factor (0.75).
+     *
+     * @param      initialCapacity   the initial capacity of the hash table
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero
+     */
+    public HashSet(int initialCapacity) {
+        map = new HashMap<>(initialCapacity);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set.  (This package private
+     * constructor is only used by LinkedHashSet.) The backing
+     * HashMap instance is a LinkedHashMap with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hash map
+     * @param      loadFactor        the load factor of the hash map
+     * @param      dummy             ignored (distinguishes this
+     *             constructor from other int, float constructor.)
+     * @throws     IllegalArgumentException if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive
+     */
+    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
+        map = new LinkedHashMap<>(initialCapacity, loadFactor);
+    }
+
+    /**
+     * Returns an iterator over the elements in this set.  The elements
+     * are returned in no particular order.
+     *
+     * @return an Iterator over the elements in this set
+     * @see ConcurrentModificationException
+     */
+    public Iterator<E> iterator() {
+        return map.keySet().iterator();
+    }
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     * More formally, returns <tt>true</tt> if and only if this set
+     * contains an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return map.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element <tt>e</tt> to this set if
+     * this set contains no element <tt>e2</tt> such that
+     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns <tt>false</tt>.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if this set did not already contain the specified
+     * element
+     */
+    public boolean add(E e) {
+        return map.put(e, PRESENT)==null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element <tt>e</tt> such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
+     * if this set contains such an element.  Returns <tt>true</tt> if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return <tt>true</tt> if the set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return map.remove(o)==PRESENT;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns a shallow copy of this <tt>HashSet</tt> instance: the elements
+     * themselves are not cloned.
+     *
+     * @return a shallow copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        try {
+            HashSet<E> newSet = (HashSet<E>) super.clone();
+            newSet.map = (HashMap<E, Object>) map.clone();
+            return newSet;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Save the state of this <tt>HashSet</tt> instance to a stream (that is,
+     * serialize it).
+     *
+     * @serialData The capacity of the backing <tt>HashMap</tt> instance
+     *             (int), and its load factor (float) are emitted, followed by
+     *             the size of the set (the number of elements it contains)
+     *             (int), followed by all of its elements (each an Object) in
+     *             no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden serialization magic
+        s.defaultWriteObject();
+
+        // Write out HashMap capacity and load factor
+        s.writeInt(map.capacity());
+        s.writeFloat(map.loadFactor());
+
+        // Write out size
+        s.writeInt(map.size());
+
+        // Write out all elements in the proper order.
+        for (E e : map.keySet())
+            s.writeObject(e);
+    }
+
+    /**
+     * Reconstitute the <tt>HashSet</tt> instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden serialization magic
+        s.defaultReadObject();
+
+        // Read capacity and verify non-negative.
+        int capacity = s.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Illegal capacity: " +
+                                             capacity);
+        }
+
+        // Read load factor and verify positive and non NaN.
+        float loadFactor = s.readFloat();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+            throw new InvalidObjectException("Illegal load factor: " +
+                                             loadFactor);
+        }
+
+        // Read size and verify non-negative.
+        int size = s.readInt();
+        if (size < 0) {
+            throw new InvalidObjectException("Illegal size: " +
+                                             size);
+        }
+
+        // Set the capacity according to the size and load factor ensuring that
+        // the HashMap is at least 25% full but clamping to maximum capacity.
+        capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
+                HashMap.MAXIMUM_CAPACITY);
+
+        // Create backing HashMap
+        map = (((HashSet<?>)this) instanceof LinkedHashSet ?
+               new LinkedHashMap<E,Object>(capacity, loadFactor) :
+               new HashMap<E,Object>(capacity, loadFactor));
+
+        // Read in all elements in the proper order.
+        for (int i=0; i<size; i++) {
+            @SuppressWarnings("unchecked")
+                E e = (E) s.readObject();
+            map.put(e, PRESENT);
+        }
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#DISTINCT}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
+    }
+}
diff --git a/java/util/Hashtable.java b/java/util/Hashtable.java
new file mode 100644
index 0000000..4c76a74
--- /dev/null
+++ b/java/util/Hashtable.java
@@ -0,0 +1,1432 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * This class implements a hash table, which maps keys to values. Any
+ * non-<code>null</code> object can be used as a key or as a value. <p>
+ *
+ * To successfully store and retrieve objects from a hashtable, the
+ * objects used as keys must implement the <code>hashCode</code>
+ * method and the <code>equals</code> method. <p>
+ *
+ * An instance of <code>Hashtable</code> has two parameters that affect its
+ * performance: <i>initial capacity</i> and <i>load factor</i>.  The
+ * <i>capacity</i> is the number of <i>buckets</i> in the hash table, and the
+ * <i>initial capacity</i> is simply the capacity at the time the hash table
+ * is created.  Note that the hash table is <i>open</i>: in the case of a "hash
+ * collision", a single bucket stores multiple entries, which must be searched
+ * sequentially.  The <i>load factor</i> is a measure of how full the hash
+ * table is allowed to get before its capacity is automatically increased.
+ * The initial capacity and load factor parameters are merely hints to
+ * the implementation.  The exact details as to when and whether the rehash
+ * method is invoked are implementation-dependent.<p>
+ *
+ * Generally, the default load factor (.75) offers a good tradeoff between
+ * time and space costs.  Higher values decrease the space overhead but
+ * increase the time cost to look up an entry (which is reflected in most
+ * <tt>Hashtable</tt> operations, including <tt>get</tt> and <tt>put</tt>).<p>
+ *
+ * The initial capacity controls a tradeoff between wasted space and the
+ * need for <code>rehash</code> operations, which are time-consuming.
+ * No <code>rehash</code> operations will <i>ever</i> occur if the initial
+ * capacity is greater than the maximum number of entries the
+ * <tt>Hashtable</tt> will contain divided by its load factor.  However,
+ * setting the initial capacity too high can waste space.<p>
+ *
+ * If many entries are to be made into a <code>Hashtable</code>,
+ * creating it with a sufficiently large capacity may allow the
+ * entries to be inserted more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table. <p>
+ *
+ * This example creates a hashtable of numbers. It uses the names of
+ * the numbers as keys:
+ * <pre>   {@code
+ *   Hashtable<String, Integer> numbers
+ *     = new Hashtable<String, Integer>();
+ *   numbers.put("one", 1);
+ *   numbers.put("two", 2);
+ *   numbers.put("three", 3);}</pre>
+ *
+ * <p>To retrieve a number, use the following code:
+ * <pre>   {@code
+ *   Integer n = numbers.get("two");
+ *   if (n != null) {
+ *     System.out.println("two = " + n);
+ *   }}</pre>
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <em>fail-fast</em>: if the Hashtable is structurally modified at any time
+ * after the iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ * The Enumerations returned by Hashtable's keys and elements methods are
+ * <em>not</em> fail-fast.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>As of the Java 2 platform v1.2, this class was retrofitted to
+ * implement the {@link Map} interface, making it a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ *
+ * Java Collections Framework</a>.  Unlike the new collection
+ * implementations, {@code Hashtable} is synchronized.  If a
+ * thread-safe implementation is not needed, it is recommended to use
+ * {@link HashMap} in place of {@code Hashtable}.  If a thread-safe
+ * highly-concurrent implementation is desired, then it is recommended
+ * to use {@link java.util.concurrent.ConcurrentHashMap} in place of
+ * {@code Hashtable}.
+ *
+ * @author  Arthur van Hoff
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see     Object#equals(java.lang.Object)
+ * @see     Object#hashCode()
+ * @see     Hashtable#rehash()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @since JDK1.0
+ */
+public class Hashtable<K,V>
+    extends Dictionary<K,V>
+    implements Map<K,V>, Cloneable, java.io.Serializable {
+
+    /**
+     * The hash table data.
+     */
+    private transient HashtableEntry<?,?>[] table;
+
+    /**
+     * The total number of entries in the hash table.
+     */
+    private transient int count;
+
+    /**
+     * The table is rehashed when its size exceeds this threshold.  (The
+     * value of this field is (int)(capacity * loadFactor).)
+     *
+     * @serial
+     */
+    private int threshold;
+
+    /**
+     * The load factor for the hashtable.
+     *
+     * @serial
+     */
+    private float loadFactor;
+
+    /**
+     * The number of times this Hashtable has been structurally modified
+     * Structural modifications are those that change the number of entries in
+     * the Hashtable or otherwise modify its internal structure (e.g.,
+     * rehash).  This field is used to make iterators on Collection-views of
+     * the Hashtable fail-fast.  (See ConcurrentModificationException).
+     */
+    private transient int modCount = 0;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 1421746759512286392L;
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial
+     * capacity and the specified load factor.
+     *
+     * @param      initialCapacity   the initial capacity of the hashtable.
+     * @param      loadFactor        the load factor of the hashtable.
+     * @exception  IllegalArgumentException  if the initial capacity is less
+     *             than zero, or if the load factor is nonpositive.
+     */
+    public Hashtable(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load: "+loadFactor);
+
+        if (initialCapacity==0)
+            initialCapacity = 1;
+        this.loadFactor = loadFactor;
+        table = new HashtableEntry<?,?>[initialCapacity];
+        // Android-changed: Ignore loadFactor when calculating threshold from initialCapacity
+        // threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+        threshold = (int)Math.min(initialCapacity, MAX_ARRAY_SIZE + 1);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with the specified initial capacity
+     * and default load factor (0.75).
+     *
+     * @param     initialCapacity   the initial capacity of the hashtable.
+     * @exception IllegalArgumentException if the initial capacity is less
+     *              than zero.
+     */
+    public Hashtable(int initialCapacity) {
+        this(initialCapacity, 0.75f);
+    }
+
+    /**
+     * Constructs a new, empty hashtable with a default initial capacity (11)
+     * and load factor (0.75).
+     */
+    public Hashtable() {
+        this(11, 0.75f);
+    }
+
+    /**
+     * Constructs a new hashtable with the same mappings as the given
+     * Map.  The hashtable is created with an initial capacity sufficient to
+     * hold the mappings in the given Map and a default load factor (0.75).
+     *
+     * @param t the map whose mappings are to be placed in this map.
+     * @throws NullPointerException if the specified map is null.
+     * @since   1.2
+     */
+    public Hashtable(Map<? extends K, ? extends V> t) {
+        this(Math.max(2*t.size(), 11), 0.75f);
+        putAll(t);
+    }
+
+    /**
+     * Returns the number of keys in this hashtable.
+     *
+     * @return  the number of keys in this hashtable.
+     */
+    public synchronized int size() {
+        return count;
+    }
+
+    /**
+     * Tests if this hashtable maps no keys to values.
+     *
+     * @return  <code>true</code> if this hashtable maps no keys to values;
+     *          <code>false</code> otherwise.
+     */
+    public synchronized boolean isEmpty() {
+        return count == 0;
+    }
+
+    /**
+     * Returns an enumeration of the keys in this hashtable.
+     *
+     * @return  an enumeration of the keys in this hashtable.
+     * @see     Enumeration
+     * @see     #elements()
+     * @see     #keySet()
+     * @see     Map
+     */
+    public synchronized Enumeration<K> keys() {
+        return this.<K>getEnumeration(KEYS);
+    }
+
+    /**
+     * Returns an enumeration of the values in this hashtable.
+     * Use the Enumeration methods on the returned object to fetch the elements
+     * sequentially.
+     *
+     * @return  an enumeration of the values in this hashtable.
+     * @see     java.util.Enumeration
+     * @see     #keys()
+     * @see     #values()
+     * @see     Map
+     */
+    public synchronized Enumeration<V> elements() {
+        return this.<V>getEnumeration(VALUES);
+    }
+
+    /**
+     * Tests if some key maps into the specified value in this hashtable.
+     * This operation is more expensive than the {@link #containsKey
+     * containsKey} method.
+     *
+     * <p>Note that this method is identical in functionality to
+     * {@link #containsValue containsValue}, (which is part of the
+     * {@link Map} interface in the collections framework).
+     *
+     * @param      value   a value to search for
+     * @return     <code>true</code> if and only if some key maps to the
+     *             <code>value</code> argument in this hashtable as
+     *             determined by the <tt>equals</tt> method;
+     *             <code>false</code> otherwise.
+     * @exception  NullPointerException  if the value is <code>null</code>
+     */
+    public synchronized boolean contains(Object value) {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        HashtableEntry<?,?> tab[] = table;
+        for (int i = tab.length ; i-- > 0 ;) {
+            for (HashtableEntry<?,?> e = tab[i] ; e != null ; e = e.next) {
+                if (e.value.equals(value)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if this hashtable maps one or more keys to this value.
+     *
+     * <p>Note that this method is identical in functionality to {@link
+     * #contains contains} (which predates the {@link Map} interface).
+     *
+     * @param value value whose presence in this hashtable is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException  if the value is <code>null</code>
+     * @since 1.2
+     */
+    public boolean containsValue(Object value) {
+        return contains(value);
+    }
+
+    /**
+     * Tests if the specified object is a key in this hashtable.
+     *
+     * @param   key   possible key
+     * @return  <code>true</code> if and only if the specified object
+     *          is a key in this hashtable, as determined by the
+     *          <tt>equals</tt> method; <code>false</code> otherwise.
+     * @throws  NullPointerException  if the key is <code>null</code>
+     * @see     #contains(Object)
+     */
+    public synchronized boolean containsKey(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key.equals(k))},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * @param key the key whose associated value is to be returned
+     * @return the value to which the specified key is mapped, or
+     *         {@code null} if this map contains no mapping for the key
+     * @throws NullPointerException if the specified key is null
+     * @see     #put(Object, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized V get(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                return (V)e.value;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity of and internally reorganizes this
+     * hashtable, in order to accommodate and access its entries more
+     * efficiently.  This method is called automatically when the
+     * number of keys in the hashtable exceeds this hashtable's capacity
+     * and load factor.
+     */
+    @SuppressWarnings("unchecked")
+    protected void rehash() {
+        int oldCapacity = table.length;
+        HashtableEntry<?,?>[] oldMap = table;
+
+        // overflow-conscious code
+        int newCapacity = (oldCapacity << 1) + 1;
+        if (newCapacity - MAX_ARRAY_SIZE > 0) {
+            if (oldCapacity == MAX_ARRAY_SIZE)
+                // Keep running with MAX_ARRAY_SIZE buckets
+                return;
+            newCapacity = MAX_ARRAY_SIZE;
+        }
+        HashtableEntry<?,?>[] newMap = new HashtableEntry<?,?>[newCapacity];
+
+        modCount++;
+        threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
+        table = newMap;
+
+        for (int i = oldCapacity ; i-- > 0 ;) {
+            for (HashtableEntry<K,V> old = (HashtableEntry<K,V>)oldMap[i] ; old != null ; ) {
+                HashtableEntry<K,V> e = old;
+                old = old.next;
+
+                int index = (e.hash & 0x7FFFFFFF) % newCapacity;
+                e.next = (HashtableEntry<K,V>)newMap[index];
+                newMap[index] = e;
+            }
+        }
+    }
+
+    private void addEntry(int hash, K key, V value, int index) {
+        modCount++;
+
+        HashtableEntry<?,?> tab[] = table;
+        if (count >= threshold) {
+            // Rehash the table if the threshold is exceeded
+            rehash();
+
+            tab = table;
+            hash = key.hashCode();
+            index = (hash & 0x7FFFFFFF) % tab.length;
+        }
+
+        // Creates the new entry.
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>) tab[index];
+        tab[index] = new HashtableEntry<>(hash, key, value, e);
+        count++;
+    }
+
+    /**
+     * Maps the specified <code>key</code> to the specified
+     * <code>value</code> in this hashtable. Neither the key nor the
+     * value can be <code>null</code>. <p>
+     *
+     * The value can be retrieved by calling the <code>get</code> method
+     * with a key that is equal to the original key.
+     *
+     * @param      key     the hashtable key
+     * @param      value   the value
+     * @return     the previous value of the specified key in this hashtable,
+     *             or <code>null</code> if it did not have one
+     * @exception  NullPointerException  if the key or value is
+     *               <code>null</code>
+     * @see     Object#equals(Object)
+     * @see     #get(Object)
+     */
+    public synchronized V put(K key, V value) {
+        // Make sure the value is not null
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        // Makes sure the key is not already in the hashtable.
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
+        for(; entry != null ; entry = entry.next) {
+            if ((entry.hash == hash) && entry.key.equals(key)) {
+                V old = entry.value;
+                entry.value = value;
+                return old;
+            }
+        }
+
+        addEntry(hash, key, value, index);
+        return null;
+    }
+
+    /**
+     * Removes the key (and its corresponding value) from this
+     * hashtable. This method does nothing if the key is not in the hashtable.
+     *
+     * @param   key   the key that needs to be removed
+     * @return  the value to which the key had been mapped in this hashtable,
+     *          or <code>null</code> if the key did not have a mapping
+     * @throws  NullPointerException  if the key is <code>null</code>
+     */
+    public synchronized V remove(Object key) {
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for(HashtableEntry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                modCount++;
+                if (prev != null) {
+                    prev.next = e.next;
+                } else {
+                    tab[index] = e.next;
+                }
+                count--;
+                V oldValue = e.value;
+                e.value = null;
+                return oldValue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this hashtable.
+     * These mappings will replace any mappings that this hashtable had for any
+     * of the keys currently in the specified map.
+     *
+     * @param t mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     * @since 1.2
+     */
+    public synchronized void putAll(Map<? extends K, ? extends V> t) {
+        for (Map.Entry<? extends K, ? extends V> e : t.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Clears this hashtable so that it contains no keys.
+     */
+    public synchronized void clear() {
+        HashtableEntry<?,?> tab[] = table;
+        modCount++;
+        for (int index = tab.length; --index >= 0; )
+            tab[index] = null;
+        count = 0;
+    }
+
+    /**
+     * Creates a shallow copy of this hashtable. All the structure of the
+     * hashtable itself is copied, but the keys and values are not cloned.
+     * This is a relatively expensive operation.
+     *
+     * @return  a clone of the hashtable
+     */
+    public synchronized Object clone() {
+        try {
+            Hashtable<?,?> t = (Hashtable<?,?>)super.clone();
+            t.table = new HashtableEntry<?,?>[table.length];
+            for (int i = table.length ; i-- > 0 ; ) {
+                t.table[i] = (table[i] != null)
+                    ? (HashtableEntry<?,?>) table[i].clone() : null;
+            }
+            t.keySet = null;
+            t.entrySet = null;
+            t.values = null;
+            t.modCount = 0;
+            return t;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns a string representation of this <tt>Hashtable</tt> object
+     * in the form of a set of entries, enclosed in braces and separated
+     * by the ASCII characters "<tt>,&nbsp;</tt>" (comma and space). Each
+     * entry is rendered as the key, an equals sign <tt>=</tt>, and the
+     * associated element, where the <tt>toString</tt> method is used to
+     * convert the key and element to strings.
+     *
+     * @return  a string representation of this hashtable
+     */
+    public synchronized String toString() {
+        int max = size() - 1;
+        if (max == -1)
+            return "{}";
+
+        StringBuilder sb = new StringBuilder();
+        Iterator<Map.Entry<K,V>> it = entrySet().iterator();
+
+        sb.append('{');
+        for (int i = 0; ; i++) {
+            Map.Entry<K,V> e = it.next();
+            K key = e.getKey();
+            V value = e.getValue();
+            sb.append(key   == this ? "(this Map)" : key.toString());
+            sb.append('=');
+            sb.append(value == this ? "(this Map)" : value.toString());
+
+            if (i == max)
+                return sb.append('}').toString();
+            sb.append(", ");
+        }
+    }
+
+
+    private <T> Enumeration<T> getEnumeration(int type) {
+        if (count == 0) {
+            return Collections.emptyEnumeration();
+        } else {
+            return new Enumerator<>(type, false);
+        }
+    }
+
+    private <T> Iterator<T> getIterator(int type) {
+        if (count == 0) {
+            return Collections.emptyIterator();
+        } else {
+            return new Enumerator<>(type, true);
+        }
+    }
+
+    // Views
+
+    /**
+     * Each of these fields are initialized to contain an instance of the
+     * appropriate view the first time this view is requested.  The views are
+     * stateless, so there's no reason to create more than one of each.
+     */
+    private transient volatile Set<K> keySet;
+    private transient volatile Set<Map.Entry<K,V>> entrySet;
+    private transient volatile Collection<V> values;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     *
+     * @since 1.2
+     */
+    public Set<K> keySet() {
+        if (keySet == null)
+            keySet = Collections.synchronizedSet(new KeySet(), this);
+        return keySet;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return getIterator(KEYS);
+        }
+        public int size() {
+            return count;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            return Hashtable.this.remove(o) != null;
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @since 1.2
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        if (entrySet==null)
+            entrySet = Collections.synchronizedSet(new EntrySet(), this);
+        return entrySet;
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return getIterator(ENTRIES);
+        }
+
+        public boolean add(Map.Entry<K,V> o) {
+            return super.add(o);
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            Object key = entry.getKey();
+            HashtableEntry<?,?>[] tab = table;
+            int hash = key.hashCode();
+            int index = (hash & 0x7FFFFFFF) % tab.length;
+
+            for (HashtableEntry<?,?> e = tab[index]; e != null; e = e.next)
+                if (e.hash==hash && e.equals(entry))
+                    return true;
+            return false;
+        }
+
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+            Object key = entry.getKey();
+            HashtableEntry<?,?>[] tab = table;
+            int hash = key.hashCode();
+            int index = (hash & 0x7FFFFFFF) % tab.length;
+
+            @SuppressWarnings("unchecked")
+            HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+            for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+                if (e.hash==hash && e.equals(entry)) {
+                    modCount++;
+                    if (prev != null)
+                        prev.next = e.next;
+                    else
+                        tab[index] = e.next;
+
+                    count--;
+                    e.value = null;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int size() {
+            return count;
+        }
+
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @since 1.2
+     */
+    public Collection<V> values() {
+        if (values==null)
+            values = Collections.synchronizedCollection(new ValueCollection(),
+                                                        this);
+        return values;
+    }
+
+    private class ValueCollection extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return getIterator(VALUES);
+        }
+        public int size() {
+            return count;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public void clear() {
+            Hashtable.this.clear();
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified Object with this Map for equality,
+     * as per the definition in the Map interface.
+     *
+     * @param  o object to be compared for equality with this hashtable
+     * @return true if the specified Object is equal to this Map
+     * @see Map#equals(Object)
+     * @since 1.2
+     */
+    public synchronized boolean equals(Object o) {
+        if (o == this)
+            return true;
+
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> t = (Map<?,?>) o;
+        if (t.size() != size())
+            return false;
+
+        try {
+            Iterator<Map.Entry<K,V>> i = entrySet().iterator();
+            while (i.hasNext()) {
+                Map.Entry<K,V> e = i.next();
+                K key = e.getKey();
+                V value = e.getValue();
+                if (value == null) {
+                    if (!(t.get(key)==null && t.containsKey(key)))
+                        return false;
+                } else {
+                    if (!value.equals(t.get(key)))
+                        return false;
+                }
+            }
+        } catch (ClassCastException unused)   {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this Map as per the definition in the
+     * Map interface.
+     *
+     * @see Map#hashCode()
+     * @since 1.2
+     */
+    public synchronized int hashCode() {
+        /*
+         * This code detects the recursion caused by computing the hash code
+         * of a self-referential hash table and prevents the stack overflow
+         * that would otherwise result.  This allows certain 1.1-era
+         * applets with self-referential hash tables to work.  This code
+         * abuses the loadFactor field to do double-duty as a hashCode
+         * in progress flag, so as not to worsen the space performance.
+         * A negative load factor indicates that hash code computation is
+         * in progress.
+         */
+        int h = 0;
+        if (count == 0 || loadFactor < 0)
+            return h;  // Returns zero
+
+        loadFactor = -loadFactor;  // Mark hashCode computation in progress
+        HashtableEntry<?,?>[] tab = table;
+        for (HashtableEntry<?,?> entry : tab) {
+            while (entry != null) {
+                h += entry.hashCode();
+                entry = entry.next;
+            }
+        }
+
+        loadFactor = -loadFactor;  // Mark hashCode computation complete
+
+        return h;
+    }
+
+    @Override
+    public synchronized V getOrDefault(Object key, V defaultValue) {
+        V result = get(key);
+        return (null == result) ? defaultValue : result;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);     // explicit check required in case
+                                            // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<?, ?>[] tab = table;
+        for (HashtableEntry<?, ?> entry : tab) {
+            while (entry != null) {
+                action.accept((K)entry.key, (V)entry.value);
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);     // explicit check required in case
+                                              // table is empty.
+        final int expectedModCount = modCount;
+
+        HashtableEntry<K, V>[] tab = (HashtableEntry<K, V>[])table;
+        for (HashtableEntry<K, V> entry : tab) {
+            while (entry != null) {
+                entry.value = Objects.requireNonNull(
+                    function.apply(entry.key, entry.value));
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @Override
+    public synchronized V putIfAbsent(K key, V value) {
+        Objects.requireNonNull(value);
+
+        // Makes sure the key is not already in the hashtable.
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> entry = (HashtableEntry<K,V>)tab[index];
+        for (; entry != null; entry = entry.next) {
+            if ((entry.hash == hash) && entry.key.equals(key)) {
+                V old = entry.value;
+                if (old == null) {
+                    entry.value = value;
+                }
+                return old;
+            }
+        }
+
+        addEntry(hash, key, value, index);
+        return null;
+    }
+
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        Objects.requireNonNull(value);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
+                modCount++;
+                if (prev != null) {
+                    prev.next = e.next;
+                } else {
+                    tab[index] = e.next;
+                }
+                count--;
+                e.value = null;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized boolean replace(K key, V oldValue, V newValue) {
+        Objects.requireNonNull(oldValue);
+        Objects.requireNonNull(newValue);
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                if (e.value.equals(oldValue)) {
+                    e.value = newValue;
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public synchronized V replace(K key, V value) {
+        Objects.requireNonNull(value);
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                V oldValue = e.value;
+                e.value = value;
+                return oldValue;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (; e != null; e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                // Hashtable not accept null value
+                return e.value;
+            }
+        }
+
+        V newValue = mappingFunction.apply(key);
+        if (newValue != null) {
+            addEntry(hash, key, newValue, index);
+        }
+
+        return newValue;
+    }
+
+    @Override
+    public synchronized V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                V newValue = remappingFunction.apply(key, e.value);
+                if (newValue == null) {
+                    modCount++;
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && Objects.equals(e.key, key)) {
+                V newValue = remappingFunction.apply(key, e.value);
+                if (newValue == null) {
+                    modCount++;
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+
+        V newValue = remappingFunction.apply(key, null);
+        if (newValue != null) {
+            addEntry(hash, key, newValue, index);
+        }
+
+        return newValue;
+    }
+
+    @Override
+    public synchronized V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+
+        HashtableEntry<?,?> tab[] = table;
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        @SuppressWarnings("unchecked")
+        HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        for (HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+            if (e.hash == hash && e.key.equals(key)) {
+                V newValue = remappingFunction.apply(e.value, value);
+                if (newValue == null) {
+                    modCount++;
+                    if (prev != null) {
+                        prev.next = e.next;
+                    } else {
+                        tab[index] = e.next;
+                    }
+                    count--;
+                } else {
+                    e.value = newValue;
+                }
+                return newValue;
+            }
+        }
+
+        if (value != null) {
+            addEntry(hash, key, value, index);
+        }
+
+        return value;
+    }
+
+    /**
+     * Save the state of the Hashtable to a stream (i.e., serialize it).
+     *
+     * @serialData The <i>capacity</i> of the Hashtable (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> of the Hashtable (the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping represented by the Hashtable
+     *             The key-value mappings are emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws IOException {
+        HashtableEntry<Object, Object> entryStack = null;
+
+        synchronized (this) {
+            // Write out the threshold and loadFactor
+            s.defaultWriteObject();
+
+            // Write out the length and count of elements
+            s.writeInt(table.length);
+            s.writeInt(count);
+
+            // Stack copies of the entries in the table
+            for (int index = 0; index < table.length; index++) {
+                HashtableEntry<?,?> entry = table[index];
+
+                while (entry != null) {
+                    entryStack =
+                        new HashtableEntry<>(0, entry.key, entry.value, entryStack);
+                    entry = entry.next;
+                }
+            }
+        }
+
+        // Write out the key/value objects from the stacked entries
+        while (entryStack != null) {
+            s.writeObject(entryStack.key);
+            s.writeObject(entryStack.value);
+            entryStack = entryStack.next;
+        }
+    }
+
+    /**
+     * Reconstitute the Hashtable from a stream (i.e., deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+         throws IOException, ClassNotFoundException
+    {
+        // Read in the threshold and loadFactor
+        s.defaultReadObject();
+
+        // Validate loadFactor (ignore threshold - it will be re-computed)
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new StreamCorruptedException("Illegal Load: " + loadFactor);
+
+        // Read the original length of the array and number of elements
+        int origlength = s.readInt();
+        int elements = s.readInt();
+
+        // Validate # of elements
+        if (elements < 0)
+            throw new StreamCorruptedException("Illegal # of Elements: " + elements);
+
+        // Clamp original length to be more than elements / loadFactor
+        // (this is the invariant enforced with auto-growth)
+        origlength = Math.max(origlength, (int)(elements / loadFactor) + 1);
+
+        // Compute new length with a bit of room 5% + 3 to grow but
+        // no larger than the clamped original length.  Make the length
+        // odd if it's large enough, this helps distribute the entries.
+        // Guard against the length ending up zero, that's not valid.
+        int length = (int)((elements + elements / 20) / loadFactor) + 3;
+        if (length > elements && (length & 1) == 0)
+            length--;
+        length = Math.min(length, origlength);
+        table = new HashtableEntry<?,?>[length];
+        threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
+        count = 0;
+
+        // Read the number of elements and then all the key/value objects
+        for (; elements > 0; elements--) {
+            @SuppressWarnings("unchecked")
+                K key = (K)s.readObject();
+            @SuppressWarnings("unchecked")
+                V value = (V)s.readObject();
+            // sync is eliminated for performance
+            reconstitutionPut(table, key, value);
+        }
+    }
+
+    /**
+     * The put method used by readObject. This is provided because put
+     * is overridable and should not be called in readObject since the
+     * subclass will not yet be initialized.
+     *
+     * <p>This differs from the regular put method in several ways. No
+     * checking for rehashing is necessary since the number of elements
+     * initially in the table is known. The modCount is not incremented and
+     * there's no synchronization because we are creating a new instance.
+     * Also, no return value is needed.
+     */
+    private void reconstitutionPut(HashtableEntry<?,?>[] tab, K key, V value)
+        throws StreamCorruptedException
+    {
+        if (value == null) {
+            throw new java.io.StreamCorruptedException();
+        }
+        // Makes sure the key is not already in the hashtable.
+        // This should not happen in deserialized version.
+        int hash = key.hashCode();
+        int index = (hash & 0x7FFFFFFF) % tab.length;
+        for (HashtableEntry<?,?> e = tab[index] ; e != null ; e = e.next) {
+            if ((e.hash == hash) && e.key.equals(key)) {
+                throw new java.io.StreamCorruptedException();
+            }
+        }
+        // Creates the new entry.
+        @SuppressWarnings("unchecked")
+            HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+        tab[index] = new HashtableEntry<>(hash, key, value, e);
+        count++;
+    }
+
+    /**
+     * Hashtable bucket collision list entry
+     */
+    // BEGIN Android-changed: Renamed Entry -> HashtableEntry.
+    // Code references to "HashTable.Entry" must mean Map.Entry
+    //
+    // This mirrors the corresponding rename of LinkedHashMap's
+    // Entry->LinkedHashMapEntry.
+    //
+    // This is for source compatibility with earlier versions of Android.
+    // Otherwise, it would hide Map.Entry which would break compilation
+    // of code like:
+    //
+    // Hashtable.Entry<K, V> entry = hashtable.entrySet().iterator.next();
+    //
+    // To compile, that code snippet's "HashtableMap.Entry" must
+    // mean java.util.Map.Entry which is the compile time type of
+    // entrySet()'s elements.
+    //
+    private static class HashtableEntry<K,V> implements Map.Entry<K,V> {
+    // END Android-changed: Renamed Entry -> HashtableEntry.
+        final int hash;
+        final K key;
+        V value;
+        HashtableEntry<K,V> next;
+
+        protected HashtableEntry(int hash, K key, V value, HashtableEntry<K,V> next) {
+            this.hash = hash;
+            this.key =  key;
+            this.value = value;
+            this.next = next;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected Object clone() {
+            return new HashtableEntry<>(hash, key, value,
+                                  (next==null ? null : (HashtableEntry<K,V>) next.clone()));
+        }
+
+        // Map.Entry Ops
+
+        public K getKey() {
+            return key;
+        }
+
+        public V getValue() {
+            return value;
+        }
+
+        public V setValue(V value) {
+            if (value == null)
+                throw new NullPointerException();
+
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+
+            return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
+               (value==null ? e.getValue()==null : value.equals(e.getValue()));
+        }
+
+        public int hashCode() {
+            return hash ^ Objects.hashCode(value);
+        }
+
+        public String toString() {
+            return key.toString()+"="+value.toString();
+        }
+    }
+
+    // Types of Enumerations/Iterations
+    private static final int KEYS = 0;
+    private static final int VALUES = 1;
+    private static final int ENTRIES = 2;
+
+    /**
+     * A hashtable enumerator class.  This class implements both the
+     * Enumeration and Iterator interfaces, but individual instances
+     * can be created with the Iterator methods disabled.  This is necessary
+     * to avoid unintentionally increasing the capabilities granted a user
+     * by passing an Enumeration.
+     */
+    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
+        HashtableEntry<?,?>[] table = Hashtable.this.table;
+        int index = table.length;
+        HashtableEntry<?,?> entry;
+        HashtableEntry<?,?> lastReturned;
+        int type;
+
+        /**
+         * Indicates whether this Enumerator is serving as an Iterator
+         * or an Enumeration.  (true -> Iterator).
+         */
+        boolean iterator;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * Hashtable should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        protected int expectedModCount = modCount;
+
+        Enumerator(int type, boolean iterator) {
+            this.type = type;
+            this.iterator = iterator;
+        }
+
+        public boolean hasMoreElements() {
+            HashtableEntry<?,?> e = entry;
+            int i = index;
+            HashtableEntry<?,?>[] t = table;
+            /* Use locals for faster loop iteration */
+            while (e == null && i > 0) {
+                e = t[--i];
+            }
+            entry = e;
+            index = i;
+            return e != null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public T nextElement() {
+            HashtableEntry<?,?> et = entry;
+            int i = index;
+            HashtableEntry<?,?>[] t = table;
+            /* Use locals for faster loop iteration */
+            while (et == null && i > 0) {
+                et = t[--i];
+            }
+            entry = et;
+            index = i;
+            if (et != null) {
+                HashtableEntry<?,?> e = lastReturned = entry;
+                entry = e.next;
+                return type == KEYS ? (T)e.key : (type == VALUES ? (T)e.value : (T)e);
+            }
+            throw new NoSuchElementException("Hashtable Enumerator");
+        }
+
+        // Iterator methods
+        public boolean hasNext() {
+            return hasMoreElements();
+        }
+
+        public T next() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return nextElement();
+        }
+
+        public void remove() {
+            if (!iterator)
+                throw new UnsupportedOperationException();
+            if (lastReturned == null)
+                throw new IllegalStateException("Hashtable Enumerator");
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            synchronized(Hashtable.this) {
+                HashtableEntry<?,?>[] tab = Hashtable.this.table;
+                int index = (lastReturned.hash & 0x7FFFFFFF) % tab.length;
+
+                @SuppressWarnings("unchecked")
+                HashtableEntry<K,V> e = (HashtableEntry<K,V>)tab[index];
+                for(HashtableEntry<K,V> prev = null; e != null; prev = e, e = e.next) {
+                    if (e == lastReturned) {
+                        modCount++;
+                        expectedModCount++;
+                        if (prev == null)
+                            tab[index] = e.next;
+                        else
+                            prev.next = e.next;
+                        count--;
+                        lastReturned = null;
+                        return;
+                    }
+                }
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+}
diff --git a/java/util/IdentityHashMap.java b/java/util/IdentityHashMap.java
new file mode 100644
index 0000000..9dc0c26
--- /dev/null
+++ b/java/util/IdentityHashMap.java
@@ -0,0 +1,1597 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+/**
+ * This class implements the <tt>Map</tt> interface with a hash table, using
+ * reference-equality in place of object-equality when comparing keys (and
+ * values).  In other words, in an <tt>IdentityHashMap</tt>, two keys
+ * <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
+ * <tt>(k1==k2)</tt>.  (In normal <tt>Map</tt> implementations (like
+ * <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
+ * if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
+ *
+ * <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
+ * implementation!  While this class implements the <tt>Map</tt> interface, it
+ * intentionally violates <tt>Map's</tt> general contract, which mandates the
+ * use of the <tt>equals</tt> method when comparing objects.  This class is
+ * designed for use only in the rare cases wherein reference-equality
+ * semantics are required.</b>
+ *
+ * <p>A typical use of this class is <i>topology-preserving object graph
+ * transformations</i>, such as serialization or deep-copying.  To perform such
+ * a transformation, a program must maintain a "node table" that keeps track
+ * of all the object references that have already been processed.  The node
+ * table must not equate distinct objects even if they happen to be equal.
+ * Another typical use of this class is to maintain <i>proxy objects</i>.  For
+ * example, a debugging facility might wish to maintain a proxy object for
+ * each object in the program being debugged.
+ *
+ * <p>This class provides all of the optional map operations, and permits
+ * <tt>null</tt> values and the <tt>null</tt> key.  This class makes no
+ * guarantees as to the order of the map; in particular, it does not guarantee
+ * that the order will remain constant over time.
+ *
+ * <p>This class provides constant-time performance for the basic
+ * operations (<tt>get</tt> and <tt>put</tt>), assuming the system
+ * identity hash function ({@link System#identityHashCode(Object)})
+ * disperses elements properly among the buckets.
+ *
+ * <p>This class has one tuning parameter (which affects performance but not
+ * semantics): <i>expected maximum size</i>.  This parameter is the maximum
+ * number of key-value mappings that the map is expected to hold.  Internally,
+ * this parameter is used to determine the number of buckets initially
+ * comprising the hash table.  The precise relationship between the expected
+ * maximum size and the number of buckets is unspecified.
+ *
+ * <p>If the size of the map (the number of key-value mappings) sufficiently
+ * exceeds the expected maximum size, the number of buckets is increased.
+ * Increasing the number of buckets ("rehashing") may be fairly expensive, so
+ * it pays to create identity hash maps with a sufficiently large expected
+ * maximum size.  On the other hand, iteration over collection views requires
+ * time proportional to the number of buckets in the hash table, so it
+ * pays not to set the expected maximum size too high if you are especially
+ * concerned with iteration performance or memory usage.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access an identity hash map concurrently, and at
+ * least one of the threads modifies the map structurally, it <i>must</i>
+ * be synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more mappings; merely changing the value
+ * associated with a key that an instance already contains is not a
+ * structural modification.)  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the
+ * collections returned by all of this class's "collection view
+ * methods" are <i>fail-fast</i>: if the map is structurally modified
+ * at any time after the iterator is created, in any way except
+ * through the iterator's own <tt>remove</tt> method, the iterator
+ * will throw a {@link ConcurrentModificationException}.  Thus, in the
+ * face of concurrent modification, the iterator fails quickly and
+ * cleanly, rather than risking arbitrary, non-deterministic behavior
+ * at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness: <i>fail-fast iterators should be used only
+ * to detect bugs.</i>
+ *
+ * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
+ * as described for example in texts by Sedgewick and Knuth.  The array
+ * alternates holding keys and values.  (This has better locality for large
+ * tables than does using separate arrays.)  For many JRE implementations
+ * and operation mixes, this class will yield better performance than
+ * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @see     System#identityHashCode(Object)
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @author  Doug Lea and Josh Bloch
+ * @since   1.4
+ */
+
+public class IdentityHashMap<K,V>
+    extends AbstractMap<K,V>
+    implements Map<K,V>, java.io.Serializable, Cloneable
+{
+    /**
+     * The initial capacity used by the no-args constructor.
+     * MUST be a power of two.  The value 32 corresponds to the
+     * (specified) expected maximum size of 21, given a load factor
+     * of 2/3.
+     */
+    private static final int DEFAULT_CAPACITY = 32;
+
+    /**
+     * The minimum capacity, used if a lower value is implicitly specified
+     * by either of the constructors with arguments.  The value 4 corresponds
+     * to an expected maximum size of 2, given a load factor of 2/3.
+     * MUST be a power of two.
+     */
+    private static final int MINIMUM_CAPACITY = 4;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<29.
+     *
+     * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
+     * because it has to have at least one slot with the key == null
+     * in order to avoid infinite loops in get(), put(), remove()
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 29;
+
+    /**
+     * The table, resized as necessary. Length MUST always be a power of two.
+     */
+    transient Object[] table; // non-private to simplify nested class access
+
+    /**
+     * The number of key-value mappings contained in this identity hash map.
+     *
+     * @serial
+     */
+    int size;
+
+    /**
+     * The number of modifications, to support fast-fail iterators
+     */
+    transient int modCount;
+
+    /**
+     * Value representing null keys inside tables.
+     */
+    static final Object NULL_KEY = new Object();
+
+    /**
+     * Use NULL_KEY for key if it is null.
+     */
+    private static Object maskNull(Object key) {
+        return (key == null ? NULL_KEY : key);
+    }
+
+    /**
+     * Returns internal representation of null key back to caller as null.
+     */
+    static final Object unmaskNull(Object key) {
+        return (key == NULL_KEY ? null : key);
+    }
+
+    /**
+     * Constructs a new, empty identity hash map with a default expected
+     * maximum size (21).
+     */
+    public IdentityHashMap() {
+        init(DEFAULT_CAPACITY);
+    }
+
+    /**
+     * Constructs a new, empty map with the specified expected maximum size.
+     * Putting more than the expected number of key-value mappings into
+     * the map may cause the internal data structure to grow, which may be
+     * somewhat time-consuming.
+     *
+     * @param expectedMaxSize the expected maximum size of the map
+     * @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative
+     */
+    public IdentityHashMap(int expectedMaxSize) {
+        if (expectedMaxSize < 0)
+            throw new IllegalArgumentException("expectedMaxSize is negative: "
+                                               + expectedMaxSize);
+        init(capacity(expectedMaxSize));
+    }
+
+    /**
+     * Returns the appropriate capacity for the given expected maximum size.
+     * Returns the smallest power of two between MINIMUM_CAPACITY and
+     * MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
+     * expectedMaxSize)/2, if such a number exists.  Otherwise returns
+     * MAXIMUM_CAPACITY.
+     */
+    private static int capacity(int expectedMaxSize) {
+        // assert expectedMaxSize >= 0;
+        return
+            (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
+            (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
+            Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
+    }
+
+    /**
+     * Initializes object to be an empty map with the specified initial
+     * capacity, which is assumed to be a power of two between
+     * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
+     */
+    private void init(int initCapacity) {
+        // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
+        // assert initCapacity >= MINIMUM_CAPACITY;
+        // assert initCapacity <= MAXIMUM_CAPACITY;
+
+        table = new Object[2 * initCapacity];
+    }
+
+    /**
+     * Constructs a new identity hash map containing the keys-value mappings
+     * in the specified map.
+     *
+     * @param m the map whose mappings are to be placed into this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public IdentityHashMap(Map<? extends K, ? extends V> m) {
+        // Allow for a bit of growth
+        this((int) ((1 + m.size()) * 1.1));
+        putAll(m);
+    }
+
+    /**
+     * Returns the number of key-value mappings in this identity hash map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this identity hash map contains no key-value
+     * mappings.
+     *
+     * @return <tt>true</tt> if this identity hash map contains no key-value
+     *         mappings
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns index for Object x.
+     */
+    private static int hash(Object x, int length) {
+        int h = System.identityHashCode(x);
+        // Multiply by -127, and left-shift to use least bit as part of hash
+        return ((h << 1) - (h << 8)) & (length - 1);
+    }
+
+    /**
+     * Circularly traverses table of size len.
+     */
+    private static int nextKeyIndex(int i, int len) {
+        return (i + 2 < len ? i + 2 : 0);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key == k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    @SuppressWarnings("unchecked")
+    public V get(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return (V) tab[i + 1];
+            if (item == null)
+                return null;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Tests whether the specified object reference is a key in this identity
+     * hash map.
+     *
+     * @param   key   possible key
+     * @return  <code>true</code> if the specified object reference is a key
+     *          in this map
+     * @see     #containsValue(Object)
+     */
+    public boolean containsKey(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return true;
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Tests whether the specified object reference is a value in this identity
+     * hash map.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified object reference
+     * @see     #containsKey(Object)
+     */
+    public boolean containsValue(Object value) {
+        Object[] tab = table;
+        for (int i = 1; i < tab.length; i += 2)
+            if (tab[i] == value && tab[i - 1] != null)
+                return true;
+
+        return false;
+    }
+
+    /**
+     * Tests if the specified key-value mapping is in the map.
+     *
+     * @param   key   possible key
+     * @param   value possible value
+     * @return  <code>true</code> if and only if the specified key-value
+     *          mapping is in the map
+     */
+    private boolean containsMapping(Object key, Object value) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+        while (true) {
+            Object item = tab[i];
+            if (item == k)
+                return tab[i + 1] == value;
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Associates the specified value with the specified key in this identity
+     * hash map.  If the map previously contained a mapping for the key, the
+     * old value is replaced.
+     *
+     * @param key the key with which the specified value is to be associated
+     * @param value the value to be associated with the specified key
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     * @see     Object#equals(Object)
+     * @see     #get(Object)
+     * @see     #containsKey(Object)
+     */
+    public V put(K key, V value) {
+        final Object k = maskNull(key);
+
+        retryAfterResize: for (;;) {
+            final Object[] tab = table;
+            final int len = tab.length;
+            int i = hash(k, len);
+
+            for (Object item; (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                if (item == k) {
+                    @SuppressWarnings("unchecked")
+                        V oldValue = (V) tab[i + 1];
+                    tab[i + 1] = value;
+                    return oldValue;
+                }
+            }
+
+            final int s = size + 1;
+            // Use optimized form of 3 * s.
+            // Next capacity is len, 2 * current capacity.
+            if (s + (s << 1) > len && resize(len))
+                continue retryAfterResize;
+
+            modCount++;
+            tab[i] = k;
+            tab[i + 1] = value;
+            size = s;
+            return null;
+        }
+    }
+
+    /**
+     * Resizes the table if necessary to hold given capacity.
+     *
+     * @param newCapacity the new capacity, must be a power of two.
+     * @return whether a resize did in fact take place
+     */
+    private boolean resize(int newCapacity) {
+        // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
+        int newLength = newCapacity * 2;
+
+        Object[] oldTable = table;
+        int oldLength = oldTable.length;
+        if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
+            if (size == MAXIMUM_CAPACITY - 1)
+                throw new IllegalStateException("Capacity exhausted.");
+            return false;
+        }
+        if (oldLength >= newLength)
+            return false;
+
+        Object[] newTable = new Object[newLength];
+
+        for (int j = 0; j < oldLength; j += 2) {
+            Object key = oldTable[j];
+            if (key != null) {
+                Object value = oldTable[j+1];
+                oldTable[j] = null;
+                oldTable[j+1] = null;
+                int i = hash(key, newLength);
+                while (newTable[i] != null)
+                    i = nextKeyIndex(i, newLength);
+                newTable[i] = key;
+                newTable[i + 1] = value;
+            }
+        }
+        table = newTable;
+        return true;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for
+     * any of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        int n = m.size();
+        if (n == 0)
+            return;
+        if (n > size)
+            resize(capacity(n)); // conservatively pre-expand
+
+        for (Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Removes the mapping for this key from this map if present.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V remove(Object key) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        while (true) {
+            Object item = tab[i];
+            if (item == k) {
+                modCount++;
+                size--;
+                @SuppressWarnings("unchecked")
+                    V oldValue = (V) tab[i + 1];
+                tab[i + 1] = null;
+                tab[i] = null;
+                closeDeletion(i);
+                return oldValue;
+            }
+            if (item == null)
+                return null;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Removes the specified key-value mapping from the map if it is present.
+     *
+     * @param   key   possible key
+     * @param   value possible value
+     * @return  <code>true</code> if and only if the specified key-value
+     *          mapping was in the map
+     */
+    private boolean removeMapping(Object key, Object value) {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        while (true) {
+            Object item = tab[i];
+            if (item == k) {
+                if (tab[i + 1] != value)
+                    return false;
+                modCount++;
+                size--;
+                tab[i] = null;
+                tab[i + 1] = null;
+                closeDeletion(i);
+                return true;
+            }
+            if (item == null)
+                return false;
+            i = nextKeyIndex(i, len);
+        }
+    }
+
+    /**
+     * Rehash all possibly-colliding entries following a
+     * deletion. This preserves the linear-probe
+     * collision properties required by get, put, etc.
+     *
+     * @param d the index of a newly empty deleted slot
+     */
+    private void closeDeletion(int d) {
+        // Adapted from Knuth Section 6.4 Algorithm R
+        Object[] tab = table;
+        int len = tab.length;
+
+        // Look for items to swap into newly vacated slot
+        // starting at index immediately following deletion,
+        // and continuing until a null slot is seen, indicating
+        // the end of a run of possibly-colliding keys.
+        Object item;
+        for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
+             i = nextKeyIndex(i, len) ) {
+            // The following test triggers if the item at slot i (which
+            // hashes to be at slot r) should take the spot vacated by d.
+            // If so, we swap it in, and then continue with d now at the
+            // newly vacated i.  This process will terminate when we hit
+            // the null slot at the end of this run.
+            // The test is messy because we are using a circular table.
+            int r = hash(item, len);
+            if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
+                tab[d] = item;
+                tab[d + 1] = tab[i + 1];
+                tab[i] = null;
+                tab[i + 1] = null;
+                d = i;
+            }
+        }
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i++)
+            tab[i] = null;
+        size = 0;
+    }
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * <tt>true</tt> if the given object is also a map and the two maps
+     * represent identical object-reference mappings.  More formally, this
+     * map is equal to another map <tt>m</tt> if and only if
+     * <tt>this.entrySet().equals(m.entrySet())</tt>.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of this map it is
+     * possible that the symmetry and transitivity requirements of the
+     * <tt>Object.equals</tt> contract may be violated if this map is compared
+     * to a normal map.  However, the <tt>Object.equals</tt> contract is
+     * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
+     *
+     * @param  o object to be compared for equality with this map
+     * @return <tt>true</tt> if the specified object is equal to this map
+     * @see Object#equals(Object)
+     */
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        } else if (o instanceof IdentityHashMap) {
+            IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) o;
+            if (m.size() != size)
+                return false;
+
+            Object[] tab = m.table;
+            for (int i = 0; i < tab.length; i+=2) {
+                Object k = tab[i];
+                if (k != null && !containsMapping(k, tab[i + 1]))
+                    return false;
+            }
+            return true;
+        } else if (o instanceof Map) {
+            Map<?,?> m = (Map<?,?>)o;
+            return entrySet().equals(m.entrySet());
+        } else {
+            return false;  // o is not a Map
+        }
+    }
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
+     * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
+     * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
+     * required by the general contract of {@link Object#hashCode}.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of the
+     * <tt>Map.Entry</tt> instances in the set returned by this map's
+     * <tt>entrySet</tt> method, it is possible that the contractual
+     * requirement of <tt>Object.hashCode</tt> mentioned in the previous
+     * paragraph will be violated if one of the two objects being compared is
+     * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
+     *
+     * @return the hash code value for this map
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    public int hashCode() {
+        int result = 0;
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i +=2) {
+            Object key = tab[i];
+            if (key != null) {
+                Object k = unmaskNull(key);
+                result += System.identityHashCode(k) ^
+                          System.identityHashCode(tab[i + 1]);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns a shallow copy of this identity hash map: the keys and values
+     * themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    public Object clone() {
+        try {
+            IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) super.clone();
+            m.entrySet = null;
+            m.table = table.clone();
+            return m;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
+        int index = (size != 0 ? 0 : table.length); // current slot.
+        int expectedModCount = modCount; // to support fast-fail
+        int lastReturnedIndex = -1;      // to allow remove()
+        boolean indexValid; // To avoid unnecessary next computation
+        Object[] traversalTable = table; // reference to main table or copy
+
+        public boolean hasNext() {
+            Object[] tab = traversalTable;
+            for (int i = index; i < tab.length; i+=2) {
+                Object key = tab[i];
+                if (key != null) {
+                    index = i;
+                    return indexValid = true;
+                }
+            }
+            index = tab.length;
+            return false;
+        }
+
+        protected int nextIndex() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (!indexValid && !hasNext())
+                throw new NoSuchElementException();
+
+            indexValid = false;
+            lastReturnedIndex = index;
+            index += 2;
+            return lastReturnedIndex;
+        }
+
+        public void remove() {
+            if (lastReturnedIndex == -1)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            expectedModCount = ++modCount;
+            int deletedSlot = lastReturnedIndex;
+            lastReturnedIndex = -1;
+            // back up index to revisit new contents after deletion
+            index = deletedSlot;
+            indexValid = false;
+
+            // Removal code proceeds as in closeDeletion except that
+            // it must catch the rare case where an element already
+            // seen is swapped into a vacant slot that will be later
+            // traversed by this iterator. We cannot allow future
+            // next() calls to return it again.  The likelihood of
+            // this occurring under 2/3 load factor is very slim, but
+            // when it does happen, we must make a copy of the rest of
+            // the table to use for the rest of the traversal. Since
+            // this can only happen when we are near the end of the table,
+            // even in these rare cases, this is not very expensive in
+            // time or space.
+
+            Object[] tab = traversalTable;
+            int len = tab.length;
+
+            int d = deletedSlot;
+            Object key = tab[d];
+            tab[d] = null;        // vacate the slot
+            tab[d + 1] = null;
+
+            // If traversing a copy, remove in real table.
+            // We can skip gap-closure on copy.
+            if (tab != IdentityHashMap.this.table) {
+                IdentityHashMap.this.remove(key);
+                expectedModCount = modCount;
+                return;
+            }
+
+            size--;
+
+            Object item;
+            for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
+                 i = nextKeyIndex(i, len)) {
+                int r = hash(item, len);
+                // See closeDeletion for explanation of this conditional
+                if ((i < r && (r <= d || d <= i)) ||
+                    (r <= d && d <= i)) {
+
+                    // If we are about to swap an already-seen element
+                    // into a slot that may later be returned by next(),
+                    // then clone the rest of table for use in future
+                    // next() calls. It is OK that our copy will have
+                    // a gap in the "wrong" place, since it will never
+                    // be used for searching anyway.
+
+                    if (i < deletedSlot && d >= deletedSlot &&
+                        traversalTable == IdentityHashMap.this.table) {
+                        int remaining = len - deletedSlot;
+                        Object[] newTable = new Object[remaining];
+                        System.arraycopy(tab, deletedSlot,
+                                         newTable, 0, remaining);
+                        traversalTable = newTable;
+                        index = 0;
+                    }
+
+                    tab[d] = item;
+                    tab[d + 1] = tab[i + 1];
+                    tab[i] = null;
+                    tab[i + 1] = null;
+                    d = i;
+                }
+            }
+        }
+    }
+
+    private class KeyIterator extends IdentityHashMapIterator<K> {
+        @SuppressWarnings("unchecked")
+        public K next() {
+            return (K) unmaskNull(traversalTable[nextIndex()]);
+        }
+    }
+
+    private class ValueIterator extends IdentityHashMapIterator<V> {
+        @SuppressWarnings("unchecked")
+        public V next() {
+            return (V) traversalTable[nextIndex() + 1];
+        }
+    }
+
+    private class EntryIterator
+        extends IdentityHashMapIterator<Map.Entry<K,V>>
+    {
+        private Entry lastReturnedEntry;
+
+        public Map.Entry<K,V> next() {
+            lastReturnedEntry = new Entry(nextIndex());
+            return lastReturnedEntry;
+        }
+
+        public void remove() {
+            lastReturnedIndex =
+                ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
+            super.remove();
+            lastReturnedEntry.index = lastReturnedIndex;
+            lastReturnedEntry = null;
+        }
+
+        private class Entry implements Map.Entry<K,V> {
+            private int index;
+
+            private Entry(int index) {
+                this.index = index;
+            }
+
+            @SuppressWarnings("unchecked")
+            public K getKey() {
+                checkIndexForEntryUse();
+                return (K) unmaskNull(traversalTable[index]);
+            }
+
+            @SuppressWarnings("unchecked")
+            public V getValue() {
+                checkIndexForEntryUse();
+                return (V) traversalTable[index+1];
+            }
+
+            @SuppressWarnings("unchecked")
+            public V setValue(V value) {
+                checkIndexForEntryUse();
+                V oldValue = (V) traversalTable[index+1];
+                traversalTable[index+1] = value;
+                // if shadowing, force into main table
+                if (traversalTable != IdentityHashMap.this.table)
+                    put((K) traversalTable[index], value);
+                return oldValue;
+            }
+
+            public boolean equals(Object o) {
+                if (index < 0)
+                    return super.equals(o);
+
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                return (e.getKey() == unmaskNull(traversalTable[index]) &&
+                       e.getValue() == traversalTable[index+1]);
+            }
+
+            public int hashCode() {
+                if (lastReturnedIndex < 0)
+                    return super.hashCode();
+
+                return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
+                       System.identityHashCode(traversalTable[index+1]));
+            }
+
+            public String toString() {
+                if (index < 0)
+                    return super.toString();
+
+                return (unmaskNull(traversalTable[index]) + "="
+                        + traversalTable[index+1]);
+            }
+
+            private void checkIndexForEntryUse() {
+                if (index < 0)
+                    throw new IllegalStateException("Entry was removed");
+            }
+        }
+    }
+
+    // Views
+
+    /**
+     * This field is initialized to contain an instance of the entry set
+     * view the first time this view is requested.  The view is stateless,
+     * so there's no reason to create more than one.
+     */
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns an identity-based set view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress, the results of the iteration are
+     * undefined.  The set supports element removal, which removes the
+     * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
+     * <tt>clear</tt> methods.  It does not support the <tt>add</tt> or
+     * <tt>addAll</tt> methods.
+     *
+     * <p><b>While the object returned by this method implements the
+     * <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general
+     * contract.  Like its backing map, the set returned by this method
+     * defines element equality as reference-equality rather than
+     * object-equality.  This affects the behavior of its <tt>contains</tt>,
+     * <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
+     * <tt>hashCode</tt> methods.</b>
+     *
+     * <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
+     * only if the specified object is a set containing exactly the same
+     * object references as the returned set.  The symmetry and transitivity
+     * requirements of the <tt>Object.equals</tt> contract may be violated if
+     * the set returned by this method is compared to a normal set.  However,
+     * the <tt>Object.equals</tt> contract is guaranteed to hold among sets
+     * returned by this method.</b>
+     *
+     * <p>The <tt>hashCode</tt> method of the returned set returns the sum of
+     * the <i>identity hashcodes</i> of the elements in the set, rather than
+     * the sum of their hashcodes.  This is mandated by the change in the
+     * semantics of the <tt>equals</tt> method, in order to enforce the
+     * general contract of the <tt>Object.hashCode</tt> method among sets
+     * returned by this method.
+     *
+     * @return an identity-based set view of the keys contained in this map
+     * @see Object#equals(Object)
+     * @see System#identityHashCode(Object)
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+        public boolean remove(Object o) {
+            int oldSize = size;
+            IdentityHashMap.this.remove(o);
+            return size != oldSize;
+        }
+        /*
+         * Must revert from AbstractSet's impl to AbstractCollection's, as
+         * the former contains an optimization that results in incorrect
+         * behavior when c is a smaller "normal" (non-identity-based) Set.
+         */
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            for (Iterator<K> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        public int hashCode() {
+            int result = 0;
+            for (K key : this)
+                result += System.identityHashCode(key);
+            return result;
+        }
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                Object key;
+                if ((key = tab[si]) != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) unmaskNull(key); // unmask key
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<K> spliterator() {
+            return new KeySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress,
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> methods.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> methods.
+     *
+     * <p><b>While the object returned by this method implements the
+     * <tt>Collection</tt> interface, it does <i>not</i> obey
+     * <tt>Collection's</tt> general contract.  Like its backing map,
+     * the collection returned by this method defines element equality as
+     * reference-equality rather than object-equality.  This affects the
+     * behavior of its <tt>contains</tt>, <tt>remove</tt> and
+     * <tt>containsAll</tt> methods.</b>
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+        public int size() {
+            return size;
+        }
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+        public boolean remove(Object o) {
+            for (Iterator<V> i = iterator(); i.hasNext(); ) {
+                if (i.next() == o) {
+                    i.remove();
+                    return true;
+                }
+            }
+            return false;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                if (tab[si] != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) tab[si+1]; // copy value
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * Each element in the returned set is a reference-equality-based
+     * <tt>Map.Entry</tt>.  The set is backed by the map, so changes
+     * to the map are reflected in the set, and vice-versa.  If the
+     * map is modified while an iteration over the set is in progress,
+     * the results of the iteration are undefined.  The set supports
+     * element removal, which removes the corresponding mapping from
+     * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
+     * methods.  It does not support the <tt>add</tt> or
+     * <tt>addAll</tt> methods.
+     *
+     * <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set
+     * returned by this method define key and value equality as
+     * reference-equality rather than object-equality.  This affects the
+     * behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these
+     * <tt>Map.Entry</tt> objects.  A reference-equality based <tt>Map.Entry
+     * e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
+     * <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &amp;&amp;
+     * e.getValue()==o.getValue()</tt>.  To accommodate these equals
+     * semantics, the <tt>hashCode</tt> method returns
+     * <tt>System.identityHashCode(e.getKey()) ^
+     * System.identityHashCode(e.getValue())</tt>.
+     *
+     * <p><b>Owing to the reference-equality-based semantics of the
+     * <tt>Map.Entry</tt> instances in the set returned by this method,
+     * it is possible that the symmetry and transitivity requirements of
+     * the {@link Object#equals(Object)} contract may be violated if any of
+     * the entries in the set is compared to a normal map entry, or if
+     * the set returned by this method is compared to a set of normal map
+     * entries (such as would be returned by a call to this method on a normal
+     * map).  However, the <tt>Object.equals</tt> contract is guaranteed to
+     * hold among identity-based map entries, and among sets of such entries.
+     * </b>
+     *
+     * @return a set view of the identity-mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        if (es != null)
+            return es;
+        else
+            return entrySet = new EntrySet();
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return containsMapping(entry.getKey(), entry.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+            return removeMapping(entry.getKey(), entry.getValue());
+        }
+        public int size() {
+            return size;
+        }
+        public void clear() {
+            IdentityHashMap.this.clear();
+        }
+        /*
+         * Must revert from AbstractSet's impl to AbstractCollection's, as
+         * the former contains an optimization that results in incorrect
+         * behavior when c is a smaller "normal" (non-identity-based) Set.
+         */
+        public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
+            boolean modified = false;
+            for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
+                if (c.contains(i.next())) {
+                    i.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public Object[] toArray() {
+            return toArray(new Object[0]);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            int expectedModCount = modCount;
+            int size = size();
+            if (a.length < size)
+                a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+            Object[] tab = table;
+            int ti = 0;
+            for (int si = 0; si < tab.length; si += 2) {
+                Object key;
+                if ((key = tab[si]) != null) { // key present ?
+                    // more elements than expected -> concurrent modification from other thread
+                    if (ti >= size) {
+                        throw new ConcurrentModificationException();
+                    }
+                    a[ti++] = (T) new AbstractMap.SimpleEntry<>(unmaskNull(key), tab[si + 1]);
+                }
+            }
+            // fewer elements than expected or concurrent modification from other thread detected
+            if (ti < size || expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+            // final null marker as per spec
+            if (ti < a.length) {
+                a[ti] = null;
+            }
+            return a;
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+
+    private static final long serialVersionUID = 8188218128353913216L;
+
+    /**
+     * Saves the state of the <tt>IdentityHashMap</tt> instance to a stream
+     * (i.e., serializes it).
+     *
+     * @serialData The <i>size</i> of the HashMap (the number of key-value
+     *          mappings) (<tt>int</tt>), followed by the key (Object) and
+     *          value (Object) for each key-value mapping represented by the
+     *          IdentityHashMap.  The key-value mappings are emitted in no
+     *          particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException  {
+        // Write out and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        Object[] tab = table;
+        for (int i = 0; i < tab.length; i += 2) {
+            Object key = tab[i];
+            if (key != null) {
+                s.writeObject(unmaskNull(key));
+                s.writeObject(tab[i + 1]);
+            }
+        }
+    }
+
+    /**
+     * Reconstitutes the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
+     * deserializes it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException  {
+        // Read in any hidden stuff
+        s.defaultReadObject();
+
+        // Read in size (number of Mappings)
+        int size = s.readInt();
+        if (size < 0)
+            throw new java.io.StreamCorruptedException
+                ("Illegal mappings count: " + size);
+        init(capacity(size));
+
+        // Read the keys and values, and put the mappings in the table
+        for (int i=0; i<size; i++) {
+            @SuppressWarnings("unchecked")
+                K key = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+                V value = (V) s.readObject();
+            putForCreate(key, value);
+        }
+    }
+
+    /**
+     * The put method for readObject.  It does not resize the table,
+     * update modCount, etc.
+     */
+    private void putForCreate(K key, V value)
+        throws java.io.StreamCorruptedException
+    {
+        Object k = maskNull(key);
+        Object[] tab = table;
+        int len = tab.length;
+        int i = hash(k, len);
+
+        Object item;
+        while ( (item = tab[i]) != null) {
+            if (item == k)
+                throw new java.io.StreamCorruptedException();
+            i = nextKeyIndex(i, len);
+        }
+        tab[i] = k;
+        tab[i + 1] = value;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                action.accept((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        Object[] t = table;
+        for (int index = 0; index < t.length; index += 2) {
+            Object k = t[index];
+            if (k != null) {
+                t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);
+            }
+
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    /**
+     * Similar form as array-based Spliterators, but skips blank elements,
+     * and guestimates size as decreasing by half per split.
+     */
+    static class IdentityHashMapSpliterator<K,V> {
+        final IdentityHashMap<K,V> map;
+        int index;             // current index, modified on advance/split
+        int fence;             // -1 until first use; then one past last index
+        int est;               // size estimate
+        int expectedModCount;  // initialized when fence set
+
+        IdentityHashMapSpliterator(IdentityHashMap<K,V> map, int origin,
+                                   int fence, int est, int expectedModCount) {
+            this.map = map;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                est = map.size;
+                expectedModCount = map.modCount;
+                hi = fence = map.table.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(map, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc; Object key;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    if ((key = a[i]) != null)
+                        action.accept((K)unmaskNull(key));
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                index += 2;
+                if (key != null) {
+                    action.accept((K)unmaskNull(key));
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    if (a[i] != null) {
+                        @SuppressWarnings("unchecked") V v = (V)a[i+1];
+                        action.accept(v);
+                    }
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                @SuppressWarnings("unchecked") V v = (V)a[index+1];
+                index += 2;
+                if (key != null) {
+                    action.accept(v);
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0);
+        }
+
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends IdentityHashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
+            return (lo >= mid) ? null :
+                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int i, hi, mc;
+            IdentityHashMap<K,V> m; Object[] a;
+            if ((m = map) != null && (a = m.table) != null &&
+                (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
+                for (; i < hi; i += 2) {
+                    Object key = a[i];
+                    if (key != null) {
+                        @SuppressWarnings("unchecked") K k =
+                            (K)unmaskNull(key);
+                        @SuppressWarnings("unchecked") V v = (V)a[i+1];
+                        action.accept
+                            (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+
+                    }
+                }
+                if (m.modCount == expectedModCount)
+                    return;
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            Object[] a = map.table;
+            int hi = getFence();
+            while (index < hi) {
+                Object key = a[index];
+                @SuppressWarnings("unchecked") V v = (V)a[index+1];
+                index += 2;
+                if (key != null) {
+                    @SuppressWarnings("unchecked") K k =
+                        (K)unmaskNull(key);
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                    if (map.modCount != expectedModCount)
+                        throw new ConcurrentModificationException();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
+        }
+    }
+
+}
diff --git a/java/util/IllegalFormatCodePointException.java b/java/util/IllegalFormatCodePointException.java
new file mode 100644
index 0000000..02add44
--- /dev/null
+++ b/java/util/IllegalFormatCodePointException.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a character with an invalid Unicode code
+ * point as defined by {@link Character#isValidCodePoint} is passed to the
+ * {@link Formatter}.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatCodePointException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19080630L;
+
+    private int c;
+
+    /**
+     * Constructs an instance of this class with the specified illegal code
+     * point as defined by {@link Character#isValidCodePoint}.
+     *
+     * @param  c
+     *         The illegal Unicode code point
+     */
+    public IllegalFormatCodePointException(int c) {
+        this.c = c;
+    }
+
+    /**
+     * Returns the illegal code point as defined by {@link
+     * Character#isValidCodePoint}.
+     *
+     * @return  The illegal Unicode code point
+     */
+    public int getCodePoint() {
+        return c;
+    }
+
+    public String getMessage() {
+        return String.format("Code point = %#x", c);
+    }
+}
diff --git a/java/util/IllegalFormatConversionException.java b/java/util/IllegalFormatConversionException.java
new file mode 100644
index 0000000..a9b006f
--- /dev/null
+++ b/java/util/IllegalFormatConversionException.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the argument corresponding to the format
+ * specifier is of an incompatible type.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatConversionException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 17000126L;
+
+    private char c;
+    private Class<?> arg;
+
+    /**
+     * Constructs an instance of this class with the mismatched conversion and
+     * the corresponding argument class.
+     *
+     * @param  c
+     *         Inapplicable conversion
+     *
+     * @param  arg
+     *         Class of the mismatched argument
+     */
+    public IllegalFormatConversionException(char c, Class<?> arg) {
+        if (arg == null)
+            throw new NullPointerException();
+        this.c = c;
+        this.arg = arg;
+    }
+
+    /**
+     * Returns the inapplicable conversion.
+     *
+     * @return  The inapplicable conversion
+     */
+    public char getConversion() {
+        return c;
+    }
+
+    /**
+     * Returns the class of the mismatched argument.
+     *
+     * @return   The class of the mismatched argument
+     */
+    public Class<?> getArgumentClass() {
+        return arg;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return String.format("%c != %s", c, arg.getName());
+    }
+}
diff --git a/java/util/IllegalFormatException.java b/java/util/IllegalFormatException.java
new file mode 100644
index 0000000..8f1d926
--- /dev/null
+++ b/java/util/IllegalFormatException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when a format string contains an illegal syntax
+ * or a format specifier that is incompatible with the given arguments.  Only
+ * explicit subtypes of this exception which correspond to specific errors
+ * should be instantiated.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatException extends IllegalArgumentException {
+
+    private static final long serialVersionUID = 18830826L;
+
+    // package-private to prevent explicit instantiation
+    IllegalFormatException() { }
+}
diff --git a/java/util/IllegalFormatFlagsException.java b/java/util/IllegalFormatFlagsException.java
new file mode 100644
index 0000000..6b8223a
--- /dev/null
+++ b/java/util/IllegalFormatFlagsException.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an illegal combination flags is given.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatFlagsException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 790824L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain an illegal combination
+     */
+    public IllegalFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains an illegal combination.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    public String getMessage() {
+        return "Flags = '" + flags + "'";
+    }
+}
diff --git a/java/util/IllegalFormatPrecisionException.java b/java/util/IllegalFormatPrecisionException.java
new file mode 100644
index 0000000..41cbbb7
--- /dev/null
+++ b/java/util/IllegalFormatPrecisionException.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the precision is a negative value other than
+ * <tt>-1</tt>, the conversion does not support a precision, or the value is
+ * otherwise unsupported.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatPrecisionException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 18711008L;
+
+    private int p;
+
+    /**
+     * Constructs an instance of this class with the specified precision.
+     *
+     * @param  p
+     *         The precision
+     */
+    public IllegalFormatPrecisionException(int p) {
+        this.p = p;
+    }
+
+    /**
+     * Returns the precision
+     *
+     * @return  The precision
+     */
+    public int getPrecision() {
+        return p;
+    }
+
+    public String getMessage() {
+        return Integer.toString(p);
+    }
+}
diff --git a/java/util/IllegalFormatWidthException.java b/java/util/IllegalFormatWidthException.java
new file mode 100644
index 0000000..08ae47d
--- /dev/null
+++ b/java/util/IllegalFormatWidthException.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the format width is a negative value other
+ * than <tt>-1</tt> or is otherwise unsupported.
+ *
+ * @since 1.5
+ */
+public class IllegalFormatWidthException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 16660902L;
+
+    private int w;
+
+    /**
+     * Constructs an instance of this class with the specified width.
+     *
+     * @param  w
+     *         The width
+     */
+    public IllegalFormatWidthException(int w) {
+        this.w = w;
+    }
+
+    /**
+     * Returns the width
+     *
+     * @return  The width
+     */
+    public int getWidth() {
+        return w;
+    }
+
+    public String getMessage() {
+        return Integer.toString(w);
+    }
+}
diff --git a/java/util/IllformedLocaleException.java b/java/util/IllformedLocaleException.java
new file mode 100644
index 0000000..5c0c4da
--- /dev/null
+++ b/java/util/IllformedLocaleException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *******************************************************************************
+ * Copyright (C) 2009-2010, International Business Machines Corporation and    *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+
+package java.util;
+
+/**
+ * Thrown by methods in {@link Locale} and {@link Locale.Builder} to
+ * indicate that an argument is not a well-formed BCP 47 tag.
+ *
+ * @see Locale
+ * @since 1.7
+ */
+public class IllformedLocaleException extends RuntimeException {
+
+    private static final long serialVersionUID = -5245986824925681401L;
+
+    private int _errIdx = -1;
+
+    /**
+     * Constructs a new <code>IllformedLocaleException</code> with no
+     * detail message and -1 as the error index.
+     */
+    public IllformedLocaleException() {
+        super();
+    }
+
+    /**
+     * Constructs a new <code>IllformedLocaleException</code> with the
+     * given message and -1 as the error index.
+     *
+     * @param message the message
+     */
+    public IllformedLocaleException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new <code>IllformedLocaleException</code> with the
+     * given message and the error index.  The error index is the approximate
+     * offset from the start of the ill-formed value to the point where the
+     * parse first detected an error.  A negative error index value indicates
+     * either the error index is not applicable or unknown.
+     *
+     * @param message the message
+     * @param errorIndex the index
+     */
+    public IllformedLocaleException(String message, int errorIndex) {
+        super(message + ((errorIndex < 0) ? "" : " [at index " + errorIndex + "]"));
+        _errIdx = errorIndex;
+    }
+
+    /**
+     * Returns the index where the error was found. A negative value indicates
+     * either the error index is not applicable or unknown.
+     *
+     * @return the error index
+     */
+    public int getErrorIndex() {
+        return _errIdx;
+    }
+}
diff --git a/java/util/ImmutableCollections.java b/java/util/ImmutableCollections.java
new file mode 100644
index 0000000..2bc0cc1
--- /dev/null
+++ b/java/util/ImmutableCollections.java
@@ -0,0 +1,964 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * Container class for immutable collections. Not part of the public API.
+ * Mainly for namespace management and shared infrastructure.
+ *
+ * Serial warnings are suppressed throughout because all implementation
+ * classes use a serial proxy and thus have no need to declare serialVersionUID.
+ */
+@SuppressWarnings("serial")
+class ImmutableCollections {
+    /**
+     * A "salt" value used for randomizing iteration order. This is initialized once
+     * and stays constant for the lifetime of the JVM. It need not be truly random, but
+     * it needs to vary sufficiently from one run to the next so that iteration order
+     * will vary between JVM runs.
+     */
+    static final int SALT;
+    static {
+        long nt = System.nanoTime();
+        SALT = (int)((nt >>> 32) ^ nt);
+    }
+
+    /** No instances. */
+    private ImmutableCollections() { }
+
+    /**
+     * The reciprocal of load factor. Given a number of elements
+     * to store, multiply by this factor to get the table size.
+     */
+    static final int EXPAND_FACTOR = 2;
+
+    static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+
+    // ---------- List Implementations ----------
+
+    abstract static class AbstractImmutableList<E> extends AbstractList<E>
+                                                implements RandomAccess, Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public boolean addAll(int index, Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public void    replaceAll(UnaryOperator<E> operator) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+        @Override public void    sort(Comparator<? super E> c) { throw uoe(); }
+    }
+
+    static final class List0<E> extends AbstractImmutableList<E> {
+        private static final List0<?> INSTANCE = new List0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> List0<T> instance() {
+            return (List0<T>) INSTANCE;
+        }
+
+        private List0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
+            return null;                  // but the compiler doesn't know this
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 1;
+        }
+    }
+
+    static final class List1<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+
+        List1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 1);
+            return e0;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0);
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + e0.hashCode();
+        }
+    }
+
+    static final class List2<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E e0;
+        @Stable
+        private final E e1;
+
+        List2(E e0, E e1) {
+            this.e0 = Objects.requireNonNull(e0);
+            this.e1 = Objects.requireNonNull(e1);
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, 2);
+            if (index == 0) {
+                return e0;
+            } else { // index == 1
+                return e1;
+            }
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 31 + e0.hashCode();
+            return 31 * hash + e1.hashCode();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, e0, e1);
+        }
+    }
+
+    static final class ListN<E> extends AbstractImmutableList<E> {
+        @Stable
+        private final E[] elements;
+
+        @SafeVarargs
+        ListN(E... input) {
+            // copy and check manually to avoid TOCTOU
+            @SuppressWarnings("unchecked")
+            E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
+            for (int i = 0; i < input.length; i++) {
+                tmp[i] = Objects.requireNonNull(input[i]);
+            }
+            this.elements = tmp;
+        }
+
+        @Override
+        public int size() {
+            return elements.length;
+        }
+
+        @Override
+        public E get(int index) {
+            Objects.checkIndex(index, elements.length);
+            return elements[index];
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            for (E e : elements) {
+                if (o.equals(e)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 1;
+            for (E e : elements) {
+                hash = 31 * hash + e.hashCode();
+            }
+            return hash;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_LIST, elements);
+        }
+    }
+
+    // ---------- Set Implementations ----------
+
+    abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
+        @Override public boolean add(E e) { throw uoe(); }
+        @Override public boolean addAll(Collection<? extends E> c) { throw uoe(); }
+        @Override public void    clear() { throw uoe(); }
+        @Override public boolean remove(Object o) { throw uoe(); }
+        @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
+        @Override public boolean removeIf(Predicate<? super E> filter) { throw uoe(); }
+        @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
+    }
+
+    static final class Set0<E> extends AbstractImmutableSet<E> {
+        private static final Set0<?> INSTANCE = new Set0<>();
+
+        @SuppressWarnings("unchecked")
+        static <T> Set0<T> instance() {
+            return (Set0<T>) INSTANCE;
+        }
+
+        private Set0() { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsAll(Collection<?> o) {
+            return o.isEmpty(); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Set1<E> extends AbstractImmutableSet<E> {
+        @Stable
+        private final E e0;
+
+        Set1(E e0) {
+            this.e0 = Objects.requireNonNull(e0);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0); // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return Collections.singletonIterator(e0);
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0);
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode();
+        }
+    }
+
+    static final class Set2<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E e0;
+        @Stable
+        final E e1;
+
+        Set2(E e0, E e1) {
+            if (e0.equals(Objects.requireNonNull(e1))) { // implicit nullcheck of e0
+                throw new IllegalArgumentException("duplicate element: " + e0);
+            }
+
+            if (SALT >= 0) {
+                this.e0 = e0;
+                this.e1 = e1;
+            } else {
+                this.e0 = e1;
+                this.e1 = e0;
+            }
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return o.equals(e0) || o.equals(e1); // implicit nullcheck of o
+        }
+
+        @Override
+        public int hashCode() {
+            return e0.hashCode() + e1.hashCode();
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return idx < 2;
+                }
+
+                @Override
+                public E next() {
+                    if (idx == 0) {
+                        idx = 1;
+                        return e0;
+                    } else if (idx == 1) {
+                        idx = 2;
+                        return e1;
+                    } else {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_SET, e0, e1);
+        }
+    }
+
+    /**
+     * An array-based Set implementation. The element array must be strictly
+     * larger than the size (the number of contained elements) so that at
+     * least one null is always present.
+     * @param <E> the element type
+     */
+    static final class SetN<E> extends AbstractImmutableSet<E> {
+        @Stable
+        final E[] elements;
+        @Stable
+        final int size;
+
+        @SafeVarargs
+        @SuppressWarnings("unchecked")
+        SetN(E... input) {
+            size = input.length; // implicit nullcheck of input
+
+            elements = (E[])new Object[EXPAND_FACTOR * input.length];
+            for (int i = 0; i < input.length; i++) {
+                E e = input[i];
+                int idx = probe(e); // implicit nullcheck of e
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate element: " + e);
+                } else {
+                    elements[-(idx + 1)] = e;
+                }
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Iterator<E>() {
+                private int idx = 0;
+
+                @Override
+                public boolean hasNext() {
+                    while (idx < elements.length) {
+                        if (elements[idx] != null)
+                            return true;
+                        idx++;
+                    }
+                    return false;
+                }
+
+                @Override
+                public E next() {
+                    if (! hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+                    return elements[idx++];
+                }
+            };
+        }
+
+        @Override
+        public int hashCode() {
+            int h = 0;
+            for (E e : elements) {
+                if (e != null) {
+                    h += e.hashCode();
+                }
+            }
+            return h;
+        }
+
+        // returns index at which element is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pe
+        private int probe(Object pe) {
+            int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
+            while (true) {
+                E ee = elements[idx];
+                if (ee == null) {
+                    return -idx - 1;
+                } else if (pe.equals(ee)) {
+                    return idx;
+                } else if (++idx == elements.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[size];
+            int dest = 0;
+            for (Object o : elements) {
+                if (o != null) {
+                    array[dest++] = o;
+                }
+            }
+            return new CollSer(CollSer.IMM_SET, array);
+        }
+    }
+
+    // ---------- Map Implementations ----------
+
+    abstract static class AbstractImmutableMap<K,V> extends AbstractMap<K,V> implements Serializable {
+        @Override public void clear() { throw uoe(); }
+        @Override public V compute(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V computeIfAbsent(K key, Function<? super K,? extends V> mf) { throw uoe(); }
+        @Override public V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf) { throw uoe(); }
+        @Override public V put(K key, V value) { throw uoe(); }
+        @Override public void putAll(Map<? extends K,? extends V> m) { throw uoe(); }
+        @Override public V putIfAbsent(K key, V value) { throw uoe(); }
+        @Override public V remove(Object key) { throw uoe(); }
+        @Override public boolean remove(Object key, Object value) { throw uoe(); }
+        @Override public V replace(K key, V value) { throw uoe(); }
+        @Override public boolean replace(K key, V oldValue, V newValue) { throw uoe(); }
+        @Override public void replaceAll(BiFunction<? super K,? super V,? extends V> f) { throw uoe(); }
+    }
+
+    static final class Map0<K,V> extends AbstractImmutableMap<K,V> {
+        private static final Map0<?,?> INSTANCE = new Map0<>();
+
+        @SuppressWarnings("unchecked")
+        static <K,V> Map0<K,V> instance() {
+            return (Map0<K,V>) INSTANCE;
+        }
+
+        private Map0() { }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of();
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            Objects.requireNonNull(o);
+            return false;
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP);
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+    }
+
+    static final class Map1<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        private final K k0;
+        @Stable
+        private final V v0;
+
+        Map1(K k0, V v0) {
+            this.k0 = Objects.requireNonNull(k0);
+            this.v0 = Objects.requireNonNull(v0);
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return Set.of(new KeyValueHolder<>(k0, v0));
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return o.equals(k0); // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            return o.equals(v0); // implicit nullcheck of o
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            return new CollSer(CollSer.IMM_MAP, k0, v0);
+        }
+
+        @Override
+        public int hashCode() {
+            return k0.hashCode() ^ v0.hashCode();
+        }
+    }
+
+    /**
+     * An array-based Map implementation. There is a single array "table" that
+     * contains keys and values interleaved: table[0] is kA, table[1] is vA,
+     * table[2] is kB, table[3] is vB, etc. The table size must be even. It must
+     * also be strictly larger than the size (the number of key-value pairs contained
+     * in the map) so that at least one null key is always present.
+     * @param <K> the key type
+     * @param <V> the value type
+     */
+    static final class MapN<K,V> extends AbstractImmutableMap<K,V> {
+        @Stable
+        final Object[] table; // pairs of key, value
+        @Stable
+        final int size; // number of pairs
+
+        MapN(Object... input) {
+            if ((input.length & 1) != 0) { // implicit nullcheck of input
+                throw new InternalError("length is odd");
+            }
+            size = input.length >> 1;
+
+            int len = EXPAND_FACTOR * input.length;
+            len = (len + 1) & ~1; // ensure table is even length
+            table = new Object[len];
+
+            for (int i = 0; i < input.length; i += 2) {
+                @SuppressWarnings("unchecked")
+                    K k = Objects.requireNonNull((K)input[i]);
+                @SuppressWarnings("unchecked")
+                    V v = Objects.requireNonNull((V)input[i+1]);
+                int idx = probe(k);
+                if (idx >= 0) {
+                    throw new IllegalArgumentException("duplicate key: " + k);
+                } else {
+                    int dest = -(idx + 1);
+                    table[dest] = k;
+                    table[dest+1] = v;
+                }
+            }
+        }
+
+        @Override
+        public boolean containsKey(Object o) {
+            return probe(o) >= 0; // implicit nullcheck of o
+        }
+
+        @Override
+        public boolean containsValue(Object o) {
+            for (int i = 1; i < table.length; i += 2) {
+                Object v = table[i];
+                if (v != null && o.equals(v)) { // implicit nullcheck of o
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 0;
+            for (int i = 0; i < table.length; i += 2) {
+                Object k = table[i];
+                if (k != null) {
+                    hash += k.hashCode() ^ table[i + 1].hashCode();
+                }
+            }
+            return hash;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public V get(Object o) {
+            int i = probe(o);
+            if (i >= 0) {
+                return (V)table[i+1];
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public int size() {
+            return size;
+        }
+
+        @Override
+        public Set<Map.Entry<K,V>> entrySet() {
+            return new AbstractSet<Map.Entry<K,V>>() {
+                @Override
+                public int size() {
+                    return MapN.this.size;
+                }
+
+                @Override
+                public Iterator<Map.Entry<K,V>> iterator() {
+                    return new Iterator<Map.Entry<K,V>>() {
+                        int idx = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            while (idx < table.length) {
+                                if (table[idx] != null)
+                                    return true;
+                                idx += 2;
+                            }
+                            return false;
+                        }
+
+                        @Override
+                        public Map.Entry<K,V> next() {
+                            if (hasNext()) {
+                                @SuppressWarnings("unchecked")
+                                Map.Entry<K,V> e =
+                                    new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
+                                idx += 2;
+                                return e;
+                            } else {
+                                throw new NoSuchElementException();
+                            }
+                        }
+                    };
+                }
+            };
+        }
+
+        // returns index at which the probe key is present; or if absent,
+        // (-i - 1) where i is location where element should be inserted.
+        // Callers are relying on this method to perform an implicit nullcheck
+        // of pk.
+        private int probe(Object pk) {
+            int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1;
+            while (true) {
+                @SuppressWarnings("unchecked")
+                K ek = (K)table[idx];
+                if (ek == null) {
+                    return -idx - 1;
+                } else if (pk.equals(ek)) {
+                    return idx;
+                } else if ((idx += 2) == table.length) {
+                    idx = 0;
+                }
+            }
+        }
+
+        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException("not serial proxy");
+        }
+
+        private Object writeReplace() {
+            Object[] array = new Object[2 * size];
+            int len = table.length;
+            int dest = 0;
+            for (int i = 0; i < len; i += 2) {
+                if (table[i] != null) {
+                    array[dest++] = table[i];
+                    array[dest++] = table[i+1];
+                }
+            }
+            return new CollSer(CollSer.IMM_MAP, array);
+        }
+    }
+}
+
+// ---------- Serialization Proxy ----------
+
+/**
+ * A unified serialization proxy class for the immutable collections.
+ *
+ * @serial
+ * @since 9
+ */
+final class CollSer implements Serializable {
+    private static final long serialVersionUID = 6309168927139932177L;
+
+    static final int IMM_LIST = 1;
+    static final int IMM_SET = 2;
+    static final int IMM_MAP = 3;
+
+    /**
+     * Indicates the type of collection that is serialized.
+     * The low order 8 bits have the value 1 for an immutable
+     * {@code List}, 2 for an immutable {@code Set}, and 3 for
+     * an immutable {@code Map}. Any other value causes an
+     * {@link InvalidObjectException} to be thrown. The high
+     * order 24 bits are zero when an instance is serialized,
+     * and they are ignored when an instance is deserialized.
+     * They can thus be used by future implementations without
+     * causing compatibility issues.
+     *
+     * <p>The tag value also determines the interpretation of the
+     * transient {@code Object[] array} field.
+     * For {@code List} and {@code Set}, the array's length is the size
+     * of the collection, and the array contains the elements of the collection.
+     * Null elements are not allowed. For {@code Set}, duplicate elements
+     * are not allowed.
+     *
+     * <p>For {@code Map}, the array's length is twice the number of mappings
+     * present in the map. The array length is necessarily even.
+     * The array contains a succession of key and value pairs:
+     * {@code k1, v1, k2, v2, ..., kN, vN.} Nulls are not allowed,
+     * and duplicate keys are not allowed.
+     *
+     * @serial
+     * @since 9
+     */
+    private final int tag;
+
+    /**
+     * @serial
+     * @since 9
+     */
+    private transient Object[] array;
+
+    CollSer(int t, Object... a) {
+        tag = t;
+        array = a;
+    }
+
+    /**
+     * Reads objects from the stream and stores them
+     * in the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param ois the ObjectInputStream from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     * @throws InvalidObjectException if the count is negative
+     * @since 9
+     */
+    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+        ois.defaultReadObject();
+        int len = ois.readInt();
+
+        if (len < 0) {
+            throw new InvalidObjectException("negative length " + len);
+        }
+
+        Object[] a = new Object[len];
+        for (int i = 0; i < len; i++) {
+            a[i] = ois.readObject();
+        }
+
+        array = a;
+    }
+
+    /**
+     * Writes objects to the stream from
+     * the transient {@code Object[] array} field.
+     *
+     * @serialData
+     * A nonnegative int, indicating the count of objects,
+     * followed by that many objects.
+     *
+     * @param oos the ObjectOutputStream to which data is written
+     * @throws IOException if an I/O error occurs
+     * @since 9
+     */
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeInt(array.length);
+        for (int i = 0; i < array.length; i++) {
+            oos.writeObject(array[i]);
+        }
+    }
+
+    /**
+     * Creates and returns an immutable collection from this proxy class.
+     * The instance returned is created as if by calling one of the
+     * static factory methods for
+     * <a href="List.html#immutable">List</a>,
+     * <a href="Map.html#immutable">Map</a>, or
+     * <a href="Set.html#immutable">Set</a>.
+     * This proxy class is the serial form for all immutable collection instances,
+     * regardless of implementation type. This is necessary to ensure that the
+     * existence of any particular implementation type is kept out of the
+     * serialized form.
+     *
+     * @return a collection created from this proxy object
+     * @throws InvalidObjectException if the tag value is illegal or if an exception
+     *         is thrown during creation of the collection
+     * @throws ObjectStreamException if another serialization error has occurred
+     * @since 9
+     */
+    private Object readResolve() throws ObjectStreamException {
+        try {
+            if (array == null) {
+                throw new InvalidObjectException("null array");
+            }
+
+            // use low order 8 bits to indicate "kind"
+            // ignore high order 24 bits
+            switch (tag & 0xff) {
+                case IMM_LIST:
+                    return List.of(array);
+                case IMM_SET:
+                    return Set.of(array);
+                case IMM_MAP:
+                    if (array.length == 0) {
+                        return ImmutableCollections.Map0.instance();
+                    } else if (array.length == 2) {
+                        return new ImmutableCollections.Map1<>(array[0], array[1]);
+                    } else {
+                        return new ImmutableCollections.MapN<>(array);
+                    }
+                default:
+                    throw new InvalidObjectException(String.format("invalid flags 0x%x", tag));
+            }
+        } catch (NullPointerException|IllegalArgumentException ex) {
+            InvalidObjectException ioe = new InvalidObjectException("invalid object");
+            ioe.initCause(ex);
+            throw ioe;
+        }
+    }
+}
diff --git a/java/util/InputMismatchException.java b/java/util/InputMismatchException.java
new file mode 100644
index 0000000..e4d1ce3
--- /dev/null
+++ b/java/util/InputMismatchException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by a <code>Scanner</code> to indicate that the token
+ * retrieved does not match the pattern for the expected type, or
+ * that the token is out of range for the expected type.
+ *
+ * @author  unascribed
+ * @see     java.util.Scanner
+ * @since   1.5
+ */
+public
+class InputMismatchException extends NoSuchElementException {
+    private static final long serialVersionUID = 8811230760997066428L;
+
+    /**
+     * Constructs an <code>InputMismatchException</code> with <tt>null</tt>
+     * as its error message string.
+     */
+    public InputMismatchException() {
+        super();
+    }
+
+    /**
+     * Constructs an <code>InputMismatchException</code>, saving a reference
+     * to the error message string <tt>s</tt> for later retrieval by the
+     * <tt>getMessage</tt> method.
+     *
+     * @param   s   the detail message.
+     */
+    public InputMismatchException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/IntSummaryStatistics.java b/java/util/IntSummaryStatistics.java
new file mode 100644
index 0000000..f93436e
--- /dev/null
+++ b/java/util/IntSummaryStatistics.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of ints with:
+ * <pre> {@code
+ * IntSummaryStatistics stats = intStream.collect(IntSummaryStatistics::new,
+ *                                                IntSummaryStatistics::accept,
+ *                                                IntSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code IntSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector) reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * IntSummaryStatistics stats = people.stream()
+ *                                    .collect(Collectors.summarizingInt(Person::getDependents));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their number of dependents.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingInt(java.util.function.ToIntFunction)
+ * Collectors.toIntStatistics()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the sum.
+ * @since 1.8
+ */
+public class IntSummaryStatistics implements IntConsumer {
+    private long count;
+    private long sum;
+    private int min = Integer.MAX_VALUE;
+    private int max = Integer.MIN_VALUE;
+
+    /**
+     * Construct an empty instance with zero count, zero sum,
+     * {@code Integer.MAX_VALUE} min, {@code Integer.MIN_VALUE} max and zero
+     * average.
+     */
+    public IntSummaryStatistics() { }
+
+    /**
+     * Records a new value into the summary information
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(int value) {
+        ++count;
+        sum += value;
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code IntSummaryStatistics} into this one.
+     *
+     * @param other another {@code IntSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(IntSummaryStatistics other) {
+        count += other.count;
+        sum += other.sum;
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Returns the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final long getSum() {
+        return sum;
+    }
+
+    /**
+     * Returns the minimum value recorded, or {@code Integer.MAX_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the minimum value, or {@code Integer.MAX_VALUE} if none
+     */
+    public final int getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum value recorded, or {@code Integer.MIN_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the maximum value, or {@code Integer.MIN_VALUE} if none
+     */
+    public final int getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/java/util/InvalidPropertiesFormatException.java b/java/util/InvalidPropertiesFormatException.java
new file mode 100644
index 0000000..bacab3d
--- /dev/null
+++ b/java/util/InvalidPropertiesFormatException.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.NotSerializableException;
+import java.io.IOException;
+
+/**
+ * Thrown to indicate that an operation could not complete because
+ * the input did not conform to the appropriate XML document type
+ * for a collection of properties, as per the {@link Properties}
+ * specification.<p>
+ *
+ * Note, that although InvalidPropertiesFormatException inherits Serializable
+ * interface from Exception, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @see     Properties
+ * @since   1.5
+ * @serial exclude
+ */
+
+public class InvalidPropertiesFormatException extends IOException {
+
+    private static final long serialVersionUID = 7763056076009360219L;
+
+    /**
+     * Constructs an InvalidPropertiesFormatException with the specified
+     * cause.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPropertiesFormatException(Throwable cause) {
+        super(cause==null ? null : cause.toString());
+        this.initCause(cause);
+    }
+
+   /**
+    * Constructs an InvalidPropertiesFormatException with the specified
+    * detail message.
+    *
+    * @param   message   the detail message. The detail message is saved for
+    *          later retrieval by the {@link Throwable#getMessage()} method.
+    */
+    public InvalidPropertiesFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Throws NotSerializableException, since InvalidPropertiesFormatException
+     * objects are not intended to be serializable.
+     */
+    private void writeObject(java.io.ObjectOutputStream out)
+        throws NotSerializableException
+    {
+        throw new NotSerializableException("Not serializable.");
+    }
+
+    /**
+     * Throws NotSerializableException, since InvalidPropertiesFormatException
+     * objects are not intended to be serializable.
+     */
+    private void readObject(java.io.ObjectInputStream in)
+        throws NotSerializableException
+    {
+        throw new NotSerializableException("Not serializable.");
+    }
+
+}
diff --git a/java/util/Iterator.annotated.java b/java/util/Iterator.annotated.java
new file mode 100644
index 0000000..b4f4522
--- /dev/null
+++ b/java/util/Iterator.annotated.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+public interface Iterator<E> {
+
+  public boolean hasNext();
+  public @libcore.util.NullFromTypeParam E next();
+  public default void remove() { throw new RuntimeException("Stub!"); }
+  public default void forEachRemaining(@libcore.util.NonNull Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Iterator.java b/java/util/Iterator.java
new file mode 100644
index 0000000..7d2daf8
--- /dev/null
+++ b/java/util/Iterator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * An iterator over a collection.  {@code Iterator} takes the place of
+ * {@link Enumeration} in the Java Collections Framework.  Iterators
+ * differ from enumerations in two ways:
+ *
+ * <ul>
+ *      <li> Iterators allow the caller to remove elements from the
+ *           underlying collection during the iteration with well-defined
+ *           semantics.
+ *      <li> Method names have been improved.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements returned by this iterator
+ *
+ * @author  Josh Bloch
+ * @see Collection
+ * @see ListIterator
+ * @see Iterable
+ * @since 1.2
+ */
+public interface Iterator<E> {
+    /**
+     * Returns {@code true} if the iteration has more elements.
+     * (In other words, returns {@code true} if {@link #next} would
+     * return an element rather than throwing an exception.)
+     *
+     * @return {@code true} if the iteration has more elements
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next element in the iteration.
+     *
+     * @return the next element in the iteration
+     * @throws NoSuchElementException if the iteration has no more elements
+     */
+    E next();
+
+    /**
+     * Removes from the underlying collection the last element returned
+     * by this iterator (optional operation).  This method can be called
+     * only once per call to {@link #next}.  The behavior of an iterator
+     * is unspecified if the underlying collection is modified while the
+     * iteration is in progress in any way other than by calling this
+     * method.
+     *
+     * @implSpec
+     * The default implementation throws an instance of
+     * {@link UnsupportedOperationException} and performs no other action.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *         operation is not supported by this iterator
+     *
+     * @throws IllegalStateException if the {@code next} method has not
+     *         yet been called, or the {@code remove} method has already
+     *         been called after the last call to the {@code next}
+     *         method
+     */
+    default void remove() {
+        throw new UnsupportedOperationException("remove");
+    }
+
+    /**
+     * Performs the given action for each remaining element until all elements
+     * have been processed or the action throws an exception.  Actions are
+     * performed in the order of iteration, if that order is specified.
+     * Exceptions thrown by the action are relayed to the caller.
+     *
+     * @implSpec
+     * <p>The default implementation behaves as if:
+     * <pre>{@code
+     *     while (hasNext())
+     *         action.accept(next());
+     * }</pre>
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     * @since 1.8
+     */
+    default void forEachRemaining(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        while (hasNext())
+            action.accept(next());
+    }
+}
diff --git a/java/util/JapaneseImperialCalendar.java b/java/util/JapaneseImperialCalendar.java
new file mode 100644
index 0000000..f0512c5
--- /dev/null
+++ b/java/util/JapaneseImperialCalendar.java
@@ -0,0 +1,2380 @@
+/*
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import sun.util.locale.provider.CalendarDataUtility;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.CalendarDate;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.Era;
+import sun.util.calendar.Gregorian;
+import sun.util.calendar.LocalGregorianCalendar;
+
+/**
+ * <code>JapaneseImperialCalendar</code> implements a Japanese
+ * calendar system in which the imperial era-based year numbering is
+ * supported from the Meiji era. The following are the eras supported
+ * by this calendar system.
+ * <pre><tt>
+ * ERA value   Era name    Since (in Gregorian)
+ * ------------------------------------------------------
+ *     0       N/A         N/A
+ *     1       Meiji       1868-01-01 midnight local time
+ *     2       Taisho      1912-07-30 midnight local time
+ *     3       Showa       1926-12-25 midnight local time
+ *     4       Heisei      1989-01-08 midnight local time
+ *     5       Reiwa       2019-05-01 midnight local time
+ * ------------------------------------------------------
+ * </tt></pre>
+ *
+ * <p><code>ERA</code> value 0 specifies the years before Meiji and
+ * the Gregorian year values are used. Unlike {@link
+ * GregorianCalendar}, the Julian to Gregorian transition is not
+ * supported because it doesn't make any sense to the Japanese
+ * calendar systems used before Meiji. To represent the years before
+ * Gregorian year 1, 0 and negative values are used. The Japanese
+ * Imperial rescripts and government decrees don't specify how to deal
+ * with time differences for applying the era transitions. This
+ * calendar implementation assumes local time for all transitions.
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.6
+ */
+class JapaneseImperialCalendar extends Calendar {
+    /*
+     * Implementation Notes
+     *
+     * This implementation uses
+     * sun.util.calendar.LocalGregorianCalendar to perform most of the
+     * calendar calculations. LocalGregorianCalendar is configurable
+     * and reads <JRE_HOME>/lib/calendars.properties at the start-up.
+     */
+
+    /**
+     * The ERA constant designating the era before Meiji.
+     */
+    public static final int BEFORE_MEIJI = 0;
+
+    /**
+     * The ERA constant designating the Meiji era.
+     */
+    public static final int MEIJI = 1;
+
+    /**
+     * The ERA constant designating the Taisho era.
+     */
+    public static final int TAISHO = 2;
+
+    /**
+     * The ERA constant designating the Showa era.
+     */
+    public static final int SHOWA = 3;
+
+    /**
+     * The ERA constant designating the Heisei era.
+     */
+    public static final int HEISEI = 4;
+
+    // Android-changed: Integrate OpenJDK support for Japanese Era Reiwa.
+    /**
+     * The ERA constant designating the Reiwa era.
+     */
+    public static final int REIWA = 5;
+
+    private static final int EPOCH_OFFSET   = 719163; // Fixed date of January 1, 1970 (Gregorian)
+    private static final int EPOCH_YEAR     = 1970;
+
+    // Useful millisecond constants.  Although ONE_DAY and ONE_WEEK can fit
+    // into ints, they must be longs in order to prevent arithmetic overflow
+    // when performing (bug 4173516).
+    private static final int  ONE_SECOND = 1000;
+    private static final int  ONE_MINUTE = 60*ONE_SECOND;
+    private static final int  ONE_HOUR   = 60*ONE_MINUTE;
+    private static final long ONE_DAY    = 24*ONE_HOUR;
+    private static final long ONE_WEEK   = 7*ONE_DAY;
+
+    // Reference to the sun.util.calendar.LocalGregorianCalendar instance (singleton).
+    private static final LocalGregorianCalendar jcal
+        = (LocalGregorianCalendar) CalendarSystem.forName("japanese");
+
+    // Gregorian calendar instance. This is required because era
+    // transition dates are given in Gregorian dates.
+    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
+
+    // The Era instance representing "before Meiji".
+    private static final Era BEFORE_MEIJI_ERA = new Era("BeforeMeiji", "BM", Long.MIN_VALUE, false);
+
+    // Imperial eras. The sun.util.calendar.LocalGregorianCalendar
+    // doesn't have an Era representing before Meiji, which is
+    // inconvenient for a Calendar. So, era[0] is a reference to
+    // BEFORE_MEIJI_ERA.
+    private static final Era[] eras;
+
+    // Fixed date of the first date of each era.
+    private static final long[] sinceFixedDates;
+
+    // The current era
+    private static final int currentEra;
+
+    /*
+     * <pre>
+     *                                 Greatest       Least
+     * Field name             Minimum   Minimum     Maximum     Maximum
+     * ----------             -------   -------     -------     -------
+     * ERA                          0         0           1           1
+     * YEAR                -292275055         1           ?           ?
+     * MONTH                        0         0          11          11
+     * WEEK_OF_YEAR                 1         1          52*         53
+     * WEEK_OF_MONTH                0         0           4*          6
+     * DAY_OF_MONTH                 1         1          28*         31
+     * DAY_OF_YEAR                  1         1         365*        366
+     * DAY_OF_WEEK                  1         1           7           7
+     * DAY_OF_WEEK_IN_MONTH        -1        -1           4*          6
+     * AM_PM                        0         0           1           1
+     * HOUR                         0         0          11          11
+     * HOUR_OF_DAY                  0         0          23          23
+     * MINUTE                       0         0          59          59
+     * SECOND                       0         0          59          59
+     * MILLISECOND                  0         0         999         999
+     * ZONE_OFFSET             -13:00    -13:00       14:00       14:00
+     * DST_OFFSET                0:00      0:00        0:20        2:00
+     * </pre>
+     * *: depends on eras
+     */
+    static final int MIN_VALUES[] = {
+        0,              // ERA
+        -292275055,     // YEAR
+        JANUARY,        // MONTH
+        1,              // WEEK_OF_YEAR
+        0,              // WEEK_OF_MONTH
+        1,              // DAY_OF_MONTH
+        1,              // DAY_OF_YEAR
+        SUNDAY,         // DAY_OF_WEEK
+        1,              // DAY_OF_WEEK_IN_MONTH
+        AM,             // AM_PM
+        0,              // HOUR
+        0,              // HOUR_OF_DAY
+        0,              // MINUTE
+        0,              // SECOND
+        0,              // MILLISECOND
+        -13*ONE_HOUR,   // ZONE_OFFSET (UNIX compatibility)
+        0               // DST_OFFSET
+    };
+    static final int LEAST_MAX_VALUES[] = {
+        0,              // ERA (initialized later)
+        0,              // YEAR (initialized later)
+        JANUARY,        // MONTH (Showa 64 ended in January.)
+        0,              // WEEK_OF_YEAR (Showa 1 has only 6 days which could be 0 weeks.)
+        4,              // WEEK_OF_MONTH
+        28,             // DAY_OF_MONTH
+        0,              // DAY_OF_YEAR (initialized later)
+        SATURDAY,       // DAY_OF_WEEK
+        4,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        20*ONE_MINUTE   // DST_OFFSET (historical least maximum)
+    };
+    static final int MAX_VALUES[] = {
+        0,              // ERA
+        292278994,      // YEAR
+        DECEMBER,       // MONTH
+        53,             // WEEK_OF_YEAR
+        6,              // WEEK_OF_MONTH
+        31,             // DAY_OF_MONTH
+        366,            // DAY_OF_YEAR
+        SATURDAY,       // DAY_OF_WEEK
+        6,              // DAY_OF_WEEK_IN
+        PM,             // AM_PM
+        11,             // HOUR
+        23,             // HOUR_OF_DAY
+        59,             // MINUTE
+        59,             // SECOND
+        999,            // MILLISECOND
+        14*ONE_HOUR,    // ZONE_OFFSET
+        2*ONE_HOUR      // DST_OFFSET (double summer time)
+    };
+
+    // Proclaim serialization compatibility with JDK 1.6
+    private static final long serialVersionUID = -3364572813905467929L;
+
+    static {
+        Era[] es = jcal.getEras();
+        int length = es.length + 1;
+        eras = new Era[length];
+        sinceFixedDates = new long[length];
+
+        // eras[BEFORE_MEIJI] and sinceFixedDate[BEFORE_MEIJI] are the
+        // same as Gregorian.
+        int index = BEFORE_MEIJI;
+        // Android-removed: Zygote could initialize this class when system has outdated time.
+        // int current = index;
+        sinceFixedDates[index] = gcal.getFixedDate(BEFORE_MEIJI_ERA.getSinceDate());
+        eras[index++] = BEFORE_MEIJI_ERA;
+        for (Era e : es) {
+            // Android-removed: Zygote could initialize this class when system has outdated time.
+            // Android hard-code the current era. Unlike upstream, Android does not add the new era
+            // in the code until the new era arrives. Thus, Android can't have newer era than the
+            // real world. currentEra is the latest Era that Android knows about.
+            // if(e.getSince(TimeZone.NO_TIMEZONE) < System.currentTimeMillis()) {
+            //     current = index;
+            // }
+            CalendarDate d = e.getSinceDate();
+            sinceFixedDates[index] = gcal.getFixedDate(d);
+            eras[index++] = e;
+        }
+        // Android-changed: Zygote could initialize this class when system has outdated time.
+        // currentEra = current;
+        currentEra = REIWA;
+
+        LEAST_MAX_VALUES[ERA] = MAX_VALUES[ERA] = eras.length - 1;
+
+        // Calculate the least maximum year and least day of Year
+        // values. The following code assumes that there's at most one
+        // era transition in a Gregorian year.
+        int year = Integer.MAX_VALUE;
+        int dayOfYear = Integer.MAX_VALUE;
+        CalendarDate date = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        for (int i = 1; i < eras.length; i++) {
+            long fd = sinceFixedDates[i];
+            CalendarDate transitionDate = eras[i].getSinceDate();
+            date.setDate(transitionDate.getYear(), BaseCalendar.JANUARY, 1);
+            long fdd = gcal.getFixedDate(date);
+            if (fd != fdd) {
+                dayOfYear = Math.min((int)(fd - fdd) + 1, dayOfYear);
+            }
+            date.setDate(transitionDate.getYear(), BaseCalendar.DECEMBER, 31);
+            fdd = gcal.getFixedDate(date);
+            if (fd != fdd) {
+                dayOfYear = Math.min((int)(fdd - fd) + 1, dayOfYear);
+            }
+            LocalGregorianCalendar.Date lgd = getCalendarDate(fd - 1);
+            int y = lgd.getYear();
+            // Unless the first year starts from January 1, the actual
+            // max value could be one year short. For example, if it's
+            // Showa 63 January 8, 63 is the actual max value since
+            // Showa 64 January 8 doesn't exist.
+            if (!(lgd.getMonth() == BaseCalendar.JANUARY && lgd.getDayOfMonth() == 1)) {
+                y--;
+            }
+            year = Math.min(y, year);
+        }
+        LEAST_MAX_VALUES[YEAR] = year; // Max year could be smaller than this value.
+        LEAST_MAX_VALUES[DAY_OF_YEAR] = dayOfYear;
+    }
+
+    /**
+     * jdate always has a sun.util.calendar.LocalGregorianCalendar.Date instance to
+     * avoid overhead of creating it for each calculation.
+     */
+    private transient LocalGregorianCalendar.Date jdate;
+
+    /**
+     * Temporary int[2] to get time zone offsets. zoneOffsets[0] gets
+     * the GMT offset value and zoneOffsets[1] gets the daylight saving
+     * value.
+     */
+    private transient int[] zoneOffsets;
+
+    /**
+     * Temporary storage for saving original fields[] values in
+     * non-lenient mode.
+     */
+    private transient int[] originalFields;
+
+    /**
+     * Constructs a <code>JapaneseImperialCalendar</code> based on the current time
+     * in the given time zone with the given locale.
+     *
+     * @param zone the given time zone.
+     * @param aLocale the given locale.
+     */
+    JapaneseImperialCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+        jdate = jcal.newCalendarDate(zone);
+        setTimeInMillis(System.currentTimeMillis());
+    }
+
+    /**
+     * Constructs an "empty" {@code JapaneseImperialCalendar}.
+     *
+     * @param zone    the given time zone
+     * @param aLocale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    JapaneseImperialCalendar(TimeZone zone, Locale aLocale, boolean flag) {
+        super(zone, aLocale);
+        jdate = jcal.newCalendarDate(zone);
+    }
+
+    /**
+     * Returns {@code "japanese"} as the calendar type of this {@code
+     * JapaneseImperialCalendar}.
+     *
+     * @return {@code "japanese"}
+     */
+    @Override
+    public String getCalendarType() {
+        return "japanese";
+    }
+
+    /**
+     * Compares this <code>JapaneseImperialCalendar</code> to the specified
+     * <code>Object</code>. The result is <code>true</code> if and
+     * only if the argument is a <code>JapaneseImperialCalendar</code> object
+     * that represents the same time value (millisecond offset from
+     * the <a href="Calendar.html#Epoch">Epoch</a>) under the same
+     * <code>Calendar</code> parameters.
+     *
+     * @param obj the object to compare with.
+     * @return <code>true</code> if this object is equal to <code>obj</code>;
+     * <code>false</code> otherwise.
+     * @see Calendar#compareTo(Calendar)
+     */
+    public boolean equals(Object obj) {
+        return obj instanceof JapaneseImperialCalendar &&
+            super.equals(obj);
+    }
+
+    /**
+     * Generates the hash code for this
+     * <code>JapaneseImperialCalendar</code> object.
+     */
+    public int hashCode() {
+        return super.hashCode() ^ jdate.hashCode();
+    }
+
+    /**
+     * Adds the specified (signed) amount of time to the given calendar field,
+     * based on the calendar's rules.
+     *
+     * <p><em>Add rule 1</em>. The value of <code>field</code>
+     * after the call minus the value of <code>field</code> before the
+     * call is <code>amount</code>, modulo any overflow that has occurred in
+     * <code>field</code>. Overflow occurs when a field value exceeds its
+     * range and, as a result, the next larger field is incremented or
+     * decremented and the field value is adjusted back into its range.</p>
+     *
+     * <p><em>Add rule 2</em>. If a smaller field is expected to be
+     * invariant, but it is impossible for it to be equal to its
+     * prior value because of changes in its minimum or maximum after
+     * <code>field</code> is changed, then its value is adjusted to be as close
+     * as possible to its expected value. A smaller field represents a
+     * smaller unit of time. <code>HOUR</code> is a smaller field than
+     * <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
+     * that are not expected to be invariant. The calendar system
+     * determines what fields are expected to be invariant.</p>
+     *
+     * @param field the calendar field.
+     * @param amount the amount of date or time to be added to the field.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     */
+    public void add(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;   // Do nothing!
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        if (field == YEAR) {
+            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+            d.addYear(amount);
+            pinDayOfMonth(d);
+            set(ERA, getEraIndex(d));
+            set(YEAR, d.getYear());
+            set(MONTH, d.getMonth() - 1);
+            set(DAY_OF_MONTH, d.getDayOfMonth());
+        } else if (field == MONTH) {
+            LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+            d.addMonth(amount);
+            pinDayOfMonth(d);
+            set(ERA, getEraIndex(d));
+            set(YEAR, d.getYear());
+            set(MONTH, d.getMonth() - 1);
+            set(DAY_OF_MONTH, d.getDayOfMonth());
+        } else if (field == ERA) {
+            int era = internalGet(ERA) + amount;
+            if (era < 0) {
+                era = 0;
+            } else if (era > eras.length - 1) {
+                era = eras.length - 1;
+            }
+            set(ERA, era);
+        } else {
+            long delta = amount;
+            long timeOfDay = 0;
+            switch (field) {
+            // Handle the time fields here. Convert the given
+            // amount to milliseconds and call setTimeInMillis.
+            case HOUR:
+            case HOUR_OF_DAY:
+                delta *= 60 * 60 * 1000;        // hours to milliseconds
+                break;
+
+            case MINUTE:
+                delta *= 60 * 1000;             // minutes to milliseconds
+                break;
+
+            case SECOND:
+                delta *= 1000;                  // seconds to milliseconds
+                break;
+
+            case MILLISECOND:
+                break;
+
+            // Handle week, day and AM_PM fields which involves
+            // time zone offset change adjustment. Convert the
+            // given amount to the number of days.
+            case WEEK_OF_YEAR:
+            case WEEK_OF_MONTH:
+            case DAY_OF_WEEK_IN_MONTH:
+                delta *= 7;
+                break;
+
+            case DAY_OF_MONTH: // synonym of DATE
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                break;
+
+            case AM_PM:
+                // Convert the amount to the number of days (delta)
+                // and +12 or -12 hours (timeOfDay).
+                delta = amount / 2;
+                timeOfDay = 12 * (amount % 2);
+                break;
+            }
+
+            // The time fields don't require time zone offset change
+            // adjustment.
+            if (field >= HOUR) {
+                setTimeInMillis(time + delta);
+                return;
+            }
+
+            // The rest of the fields (week, day or AM_PM fields)
+            // require time zone offset (both GMT and DST) change
+            // adjustment.
+
+            // Translate the current time to the fixed date and time
+            // of the day.
+            long fd = cachedFixedDate;
+            timeOfDay += internalGet(HOUR_OF_DAY);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(MINUTE);
+            timeOfDay *= 60;
+            timeOfDay += internalGet(SECOND);
+            timeOfDay *= 1000;
+            timeOfDay += internalGet(MILLISECOND);
+            if (timeOfDay >= ONE_DAY) {
+                fd++;
+                timeOfDay -= ONE_DAY;
+            } else if (timeOfDay < 0) {
+                fd--;
+                timeOfDay += ONE_DAY;
+            }
+
+            fd += delta; // fd is the expected fixed date after the calculation
+            int zoneOffset = internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
+            setTimeInMillis((fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay - zoneOffset);
+            zoneOffset -= internalGet(ZONE_OFFSET) + internalGet(DST_OFFSET);
+            // If the time zone offset has changed, then adjust the difference.
+            if (zoneOffset != 0) {
+                setTimeInMillis(time + zoneOffset);
+                long fd2 = cachedFixedDate;
+                // If the adjustment has changed the date, then take
+                // the previous one.
+                if (fd2 != fd) {
+                    setTimeInMillis(time - zoneOffset);
+                }
+            }
+        }
+    }
+
+    public void roll(int field, boolean up) {
+        roll(field, up ? +1 : -1);
+    }
+
+    /**
+     * Adds a signed amount to the specified calendar field without changing larger fields.
+     * A negative roll amount means to subtract from field without changing
+     * larger fields. If the specified amount is 0, this method performs nothing.
+     *
+     * <p>This method calls {@link #complete()} before adding the
+     * amount so that all the calendar fields are normalized. If there
+     * is any calendar field having an out-of-range value in non-lenient mode, then an
+     * <code>IllegalArgumentException</code> is thrown.
+     *
+     * @param field the calendar field.
+     * @param amount the signed amount to add to <code>field</code>.
+     * @exception IllegalArgumentException if <code>field</code> is
+     * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or unknown,
+     * or if any calendar fields have out-of-range values in
+     * non-lenient mode.
+     * @see #roll(int,boolean)
+     * @see #add(int,int)
+     * @see #set(int,int)
+     */
+    public void roll(int field, int amount) {
+        // If amount == 0, do nothing even the given field is out of
+        // range. This is tested by JCK.
+        if (amount == 0) {
+            return;
+        }
+
+        if (field < 0 || field >= ZONE_OFFSET) {
+            throw new IllegalArgumentException();
+        }
+
+        // Sync the time and calendar fields.
+        complete();
+
+        int min = getMinimum(field);
+        int max = getMaximum(field);
+
+        switch (field) {
+        case ERA:
+        case AM_PM:
+        case MINUTE:
+        case SECOND:
+        case MILLISECOND:
+            // These fields are handled simply, since they have fixed
+            // minima and maxima. Other fields are complicated, since
+            // the range within they must roll varies depending on the
+            // date, a time zone and the era transitions.
+            break;
+
+        case HOUR:
+        case HOUR_OF_DAY:
+            {
+                int unit = max + 1; // 12 or 24 hours
+                int h = internalGet(field);
+                int nh = (h + amount) % unit;
+                if (nh < 0) {
+                    nh += unit;
+                }
+                time += ONE_HOUR * (nh - h);
+
+                // The day might have changed, which could happen if
+                // the daylight saving time transition brings it to
+                // the next day, although it's very unlikely. But we
+                // have to make sure not to change the larger fields.
+                CalendarDate d = jcal.getCalendarDate(time, getZone());
+                if (internalGet(DAY_OF_MONTH) != d.getDayOfMonth()) {
+                    d.setEra(jdate.getEra());
+                    d.setDate(internalGet(YEAR),
+                              internalGet(MONTH) + 1,
+                              internalGet(DAY_OF_MONTH));
+                    if (field == HOUR) {
+                        assert (internalGet(AM_PM) == PM);
+                        d.addHours(+12); // restore PM
+                    }
+                    time = jcal.getTime(d);
+                }
+                int hourOfDay = d.getHours();
+                internalSet(field, hourOfDay % unit);
+                if (field == HOUR) {
+                    internalSet(HOUR_OF_DAY, hourOfDay);
+                } else {
+                    internalSet(AM_PM, hourOfDay / 12);
+                    internalSet(HOUR, hourOfDay % 12);
+                }
+
+                // Time zone offset and/or daylight saving might have changed.
+                int zoneOffset = d.getZoneOffset();
+                int saving = d.getDaylightSaving();
+                internalSet(ZONE_OFFSET, zoneOffset - saving);
+                internalSet(DST_OFFSET, saving);
+                return;
+            }
+
+        case YEAR:
+            min = getActualMinimum(field);
+            max = getActualMaximum(field);
+            break;
+
+        case MONTH:
+            // Rolling the month involves both pinning the final value to [0, 11]
+            // and adjusting the DAY_OF_MONTH if necessary.  We only adjust the
+            // DAY_OF_MONTH if, after updating the MONTH field, it is illegal.
+            // E.g., <jan31>.roll(MONTH, 1) -> <feb28> or <feb29>.
+            {
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int year = jdate.getYear();
+                    if (year == getMaximum(YEAR)) {
+                        CalendarDate jd = jcal.getCalendarDate(time, getZone());
+                        CalendarDate d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                        max = d.getMonth() - 1;
+                        int n = getRolledValue(internalGet(field), amount, min, max);
+                        if (n == max) {
+                            // To avoid overflow, use an equivalent year.
+                            jd.addYear(-400);
+                            jd.setMonth(n + 1);
+                            if (jd.getDayOfMonth() > d.getDayOfMonth()) {
+                                jd.setDayOfMonth(d.getDayOfMonth());
+                                jcal.normalize(jd);
+                            }
+                            if (jd.getDayOfMonth() == d.getDayOfMonth()
+                                && jd.getTimeOfDay() > d.getTimeOfDay()) {
+                                jd.setMonth(n + 1);
+                                jd.setDayOfMonth(d.getDayOfMonth() - 1);
+                                jcal.normalize(jd);
+                                // Month may have changed by the normalization.
+                                n = jd.getMonth() - 1;
+                            }
+                            set(DAY_OF_MONTH, jd.getDayOfMonth());
+                        }
+                        set(MONTH, n);
+                    } else if (year == getMinimum(YEAR)) {
+                        CalendarDate jd = jcal.getCalendarDate(time, getZone());
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        min = d.getMonth() - 1;
+                        int n = getRolledValue(internalGet(field), amount, min, max);
+                        if (n == min) {
+                            // To avoid underflow, use an equivalent year.
+                            jd.addYear(+400);
+                            jd.setMonth(n + 1);
+                            if (jd.getDayOfMonth() < d.getDayOfMonth()) {
+                                jd.setDayOfMonth(d.getDayOfMonth());
+                                jcal.normalize(jd);
+                            }
+                            if (jd.getDayOfMonth() == d.getDayOfMonth()
+                                && jd.getTimeOfDay() < d.getTimeOfDay()) {
+                                jd.setMonth(n + 1);
+                                jd.setDayOfMonth(d.getDayOfMonth() + 1);
+                                jcal.normalize(jd);
+                                // Month may have changed by the normalization.
+                                n = jd.getMonth() - 1;
+                            }
+                            set(DAY_OF_MONTH, jd.getDayOfMonth());
+                        }
+                        set(MONTH, n);
+                    } else {
+                        int mon = (internalGet(MONTH) + amount) % 12;
+                        if (mon < 0) {
+                            mon += 12;
+                        }
+                        set(MONTH, mon);
+
+                        // Keep the day of month in the range.  We
+                        // don't want to spill over into the next
+                        // month; e.g., we don't want jan31 + 1 mo ->
+                        // feb31 -> mar3.
+                        int monthLen = monthLength(mon);
+                        if (internalGet(DAY_OF_MONTH) > monthLen) {
+                            set(DAY_OF_MONTH, monthLen);
+                        }
+                    }
+                } else {
+                    int eraIndex = getEraIndex(jdate);
+                    CalendarDate transition = null;
+                    if (jdate.getYear() == 1) {
+                        transition = eras[eraIndex].getSinceDate();
+                        min = transition.getMonth() - 1;
+                    } else {
+                        if (eraIndex < eras.length - 1) {
+                            transition = eras[eraIndex + 1].getSinceDate();
+                            if (transition.getYear() == jdate.getNormalizedYear()) {
+                                max = transition.getMonth() - 1;
+                                if (transition.getDayOfMonth() == 1) {
+                                    max--;
+                                }
+                            }
+                        }
+                    }
+
+                    if (min == max) {
+                        // The year has only one month. No need to
+                        // process further. (Showa Gan-nen (year 1)
+                        // and the last year have only one month.)
+                        return;
+                    }
+                    int n = getRolledValue(internalGet(field), amount, min, max);
+                    set(MONTH, n);
+                    if (n == min) {
+                        if (!(transition.getMonth() == BaseCalendar.JANUARY
+                              && transition.getDayOfMonth() == 1)) {
+                            if (jdate.getDayOfMonth() < transition.getDayOfMonth()) {
+                                set(DAY_OF_MONTH, transition.getDayOfMonth());
+                            }
+                        }
+                    } else if (n == max && (transition.getMonth() - 1 == n)) {
+                        int dom = transition.getDayOfMonth();
+                        if (jdate.getDayOfMonth() >= dom) {
+                            set(DAY_OF_MONTH, dom - 1);
+                        }
+                    }
+                }
+                return;
+            }
+
+        case WEEK_OF_YEAR:
+            {
+                int y = jdate.getNormalizedYear();
+                max = getActualMaximum(WEEK_OF_YEAR);
+                set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK)); // update stamp[field]
+                int woy = internalGet(WEEK_OF_YEAR);
+                int value = woy + amount;
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int year = jdate.getYear();
+                    if (year == getMaximum(YEAR)) {
+                        max = getActualMaximum(WEEK_OF_YEAR);
+                    } else if (year == getMinimum(YEAR)) {
+                        min = getActualMinimum(WEEK_OF_YEAR);
+                        max = getActualMaximum(WEEK_OF_YEAR);
+                        if (value > min && value < max) {
+                            set(WEEK_OF_YEAR, value);
+                            return;
+                        }
+
+                    }
+                    // If the new value is in between min and max
+                    // (exclusive), then we can use the value.
+                    if (value > min && value < max) {
+                        set(WEEK_OF_YEAR, value);
+                        return;
+                    }
+                    long fd = cachedFixedDate;
+                    // Make sure that the min week has the current DAY_OF_WEEK
+                    long day1 = fd - (7 * (woy - min));
+                    if (year != getMinimum(YEAR)) {
+                        if (gcal.getYearFromFixedDate(day1) != y) {
+                            min++;
+                        }
+                    } else {
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        if (day1 < jcal.getFixedDate(d)) {
+                            min++;
+                        }
+                    }
+
+                    // Make sure the same thing for the max week
+                    fd += 7 * (max - internalGet(WEEK_OF_YEAR));
+                    if (gcal.getYearFromFixedDate(fd) != y) {
+                        max--;
+                    }
+                    break;
+                }
+
+                // Handle transition here.
+                long fd = cachedFixedDate;
+                long day1 = fd - (7 * (woy - min));
+                // Make sure that the min week has the current DAY_OF_WEEK
+                LocalGregorianCalendar.Date d = getCalendarDate(day1);
+                if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
+                    min++;
+                }
+
+                // Make sure the same thing for the max week
+                fd += 7 * (max - woy);
+                jcal.getCalendarDateFromFixedDate(d, fd);
+                if (!(d.getEra() == jdate.getEra() && d.getYear() == jdate.getYear())) {
+                    max--;
+                }
+                // value: the new WEEK_OF_YEAR which must be converted
+                // to month and day of month.
+                value = getRolledValue(woy, amount, min, max) - 1;
+                d = getCalendarDate(day1 + value * 7);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case WEEK_OF_MONTH:
+            {
+                boolean isTransitionYear = isTransitionYear(jdate.getNormalizedYear());
+                // dow: relative day of week from the first day of week
+                int dow = internalGet(DAY_OF_WEEK) - getFirstDayOfWeek();
+                if (dow < 0) {
+                    dow += 7;
+                }
+
+                long fd = cachedFixedDate;
+                long month1;     // fixed date of the first day (usually 1) of the month
+                int monthLength; // actual month length
+                if (isTransitionYear) {
+                    month1 = getFixedDateMonth1(jdate, fd);
+                    monthLength = actualMonthLength();
+                } else {
+                    month1 = fd - internalGet(DAY_OF_MONTH) + 1;
+                    monthLength = jcal.getMonthLength(jdate);
+                }
+
+                // the first day of week of the month.
+                long monthDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(month1 + 6,
+                                                                                     getFirstDayOfWeek());
+                // if the week has enough days to form a week, the
+                // week starts from the previous month.
+                if ((int)(monthDay1st - month1) >= getMinimalDaysInFirstWeek()) {
+                    monthDay1st -= 7;
+                }
+                max = getActualMaximum(field);
+
+                // value: the new WEEK_OF_MONTH value
+                int value = getRolledValue(internalGet(field), amount, 1, max) - 1;
+
+                // nfd: fixed date of the rolled date
+                long nfd = monthDay1st + value * 7 + dow;
+
+                // Unlike WEEK_OF_YEAR, we need to change day of week if the
+                // nfd is out of the month.
+                if (nfd < month1) {
+                    nfd = month1;
+                } else if (nfd >= (month1 + monthLength)) {
+                    nfd = month1 + monthLength - 1;
+                }
+                set(DAY_OF_MONTH, (int)(nfd - month1) + 1);
+                return;
+            }
+
+        case DAY_OF_MONTH:
+            {
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    max = jcal.getMonthLength(jdate);
+                    break;
+                }
+
+                // TODO: Need to change the spec to be usable DAY_OF_MONTH rolling...
+
+                // Transition handling. We can't change year and era
+                // values here due to the Calendar roll spec!
+                long month1 = getFixedDateMonth1(jdate, cachedFixedDate);
+
+                // It may not be a regular month. Convert the date and range to
+                // the relative values, perform the roll, and
+                // convert the result back to the rolled date.
+                int value = getRolledValue((int)(cachedFixedDate - month1), amount,
+                                           0, actualMonthLength() - 1);
+                LocalGregorianCalendar.Date d = getCalendarDate(month1 + value);
+                assert getEraIndex(d) == internalGetEra()
+                    && d.getYear() == internalGet(YEAR) && d.getMonth()-1 == internalGet(MONTH);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_YEAR:
+            {
+                max = getActualMaximum(field);
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    break;
+                }
+
+                // Handle transition. We can't change year and era values
+                // here due to the Calendar roll spec.
+                int value = getRolledValue(internalGet(DAY_OF_YEAR), amount, min, max);
+                long jan0 = cachedFixedDate - internalGet(DAY_OF_YEAR);
+                LocalGregorianCalendar.Date d = getCalendarDate(jan0 + value);
+                assert getEraIndex(d) == internalGetEra() && d.getYear() == internalGet(YEAR);
+                set(MONTH, d.getMonth() - 1);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK:
+            {
+                int normalizedYear = jdate.getNormalizedYear();
+                if (!isTransitionYear(normalizedYear) && !isTransitionYear(normalizedYear - 1)) {
+                    // If the week of year is in the same year, we can
+                    // just change DAY_OF_WEEK.
+                    int weekOfYear = internalGet(WEEK_OF_YEAR);
+                    if (weekOfYear > 1 && weekOfYear < 52) {
+                        set(WEEK_OF_YEAR, internalGet(WEEK_OF_YEAR));
+                        max = SATURDAY;
+                        break;
+                    }
+                }
+
+                // We need to handle it in a different way around year
+                // boundaries and in the transition year. Note that
+                // changing era and year values violates the roll
+                // rule: not changing larger calendar fields...
+                amount %= 7;
+                if (amount == 0) {
+                    return;
+                }
+                long fd = cachedFixedDate;
+                long dowFirst = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fd, getFirstDayOfWeek());
+                fd += amount;
+                if (fd < dowFirst) {
+                    fd += 7;
+                } else if (fd >= dowFirst + 7) {
+                    fd -= 7;
+                }
+                LocalGregorianCalendar.Date d = getCalendarDate(fd);
+                set(ERA, getEraIndex(d));
+                set(d.getYear(), d.getMonth() - 1, d.getDayOfMonth());
+                return;
+            }
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                min = 1; // after having normalized, min should be 1.
+                if (!isTransitionYear(jdate.getNormalizedYear())) {
+                    int dom = internalGet(DAY_OF_MONTH);
+                    int monthLength = jcal.getMonthLength(jdate);
+                    int lastDays = monthLength % 7;
+                    max = monthLength / 7;
+                    int x = (dom - 1) % 7;
+                    if (x < lastDays) {
+                        max++;
+                    }
+                    set(DAY_OF_WEEK, internalGet(DAY_OF_WEEK));
+                    break;
+                }
+
+                // Transition year handling.
+                long fd = cachedFixedDate;
+                long month1 = getFixedDateMonth1(jdate, fd);
+                int monthLength = actualMonthLength();
+                int lastDays = monthLength % 7;
+                max = monthLength / 7;
+                int x = (int)(fd - month1) % 7;
+                if (x < lastDays) {
+                    max++;
+                }
+                int value = getRolledValue(internalGet(field), amount, min, max) - 1;
+                fd = month1 + value * 7 + x;
+                LocalGregorianCalendar.Date d = getCalendarDate(fd);
+                set(DAY_OF_MONTH, d.getDayOfMonth());
+                return;
+            }
+        }
+
+        set(field, getRolledValue(internalGet(field), amount, min, max));
+    }
+
+    @Override
+    public String getDisplayName(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
+                                    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+
+        int fieldValue = get(field);
+
+        // "GanNen" is supported only in the LONG style.
+        if (field == YEAR
+            && (getBaseStyle(style) != LONG || fieldValue != 1 || get(ERA) == 0)) {
+            return null;
+        }
+
+        String name = CalendarDataUtility.retrieveFieldValueName(getCalendarType(), field,
+                                                                 fieldValue, style, locale);
+        // If the ERA value is null, then
+        // try to get its name or abbreviation from the Era instance.
+        if (name == null && field == ERA && fieldValue < eras.length) {
+            Era era = eras[fieldValue];
+            name = (style == SHORT) ? era.getAbbreviation() : era.getName();
+        }
+        return name;
+    }
+
+    @Override
+    public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
+        if (!checkDisplayNameParams(field, style, ALL_STYLES, NARROW_FORMAT, locale,
+                                    ERA_MASK|YEAR_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
+            return null;
+        }
+        Map<String, Integer> names;
+        names = CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale);
+        // If strings[] has fewer than eras[], get more names from eras[].
+        if (names != null) {
+            if (field == ERA) {
+                int size = names.size();
+                if (style == ALL_STYLES) {
+                    Set<Integer> values = new HashSet<>();
+                    // count unique era values
+                    for (String key : names.keySet()) {
+                        values.add(names.get(key));
+                    }
+                    size = values.size();
+                }
+                if (size < eras.length) {
+                    int baseStyle = getBaseStyle(style);
+                    for (int i = size; i < eras.length; i++) {
+                        Era era = eras[i];
+                        if (baseStyle == ALL_STYLES || baseStyle == SHORT
+                                || baseStyle == NARROW_FORMAT) {
+                            names.put(era.getAbbreviation(), i);
+                        }
+                        if (baseStyle == ALL_STYLES || baseStyle == LONG) {
+                            names.put(era.getName(), i);
+                        }
+                    }
+                }
+            }
+        }
+        return names;
+    }
+
+    /**
+     * Returns the minimum value for the given calendar field of this
+     * <code>Calendar</code> instance. The minimum value is
+     * defined as the smallest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the minimum value for the given calendar field.
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getMinimum(int field) {
+        return MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the maximum value for the given calendar field of this
+     * <code>GregorianCalendar</code> instance. The maximum value is
+     * defined as the largest value returned by the {@link
+     * Calendar#get(int) get} method for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getMaximum(int field) {
+        switch (field) {
+        case YEAR:
+            {
+                // The value should depend on the time zone of this calendar.
+                LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                     getZone());
+                return Math.max(LEAST_MAX_VALUES[YEAR], d.getYear());
+            }
+        }
+        return MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the highest minimum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The highest
+     * minimum value is defined as the largest value returned by
+     * {@link #getActualMinimum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field.
+     * @return the highest minimum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getGreatestMinimum(int field) {
+        return field == YEAR ? 1 : MIN_VALUES[field];
+    }
+
+    /**
+     * Returns the lowest maximum value for the given calendar field
+     * of this <code>GregorianCalendar</code> instance. The lowest
+     * maximum value is defined as the smallest value returned by
+     * {@link #getActualMaximum(int)} for any possible time value,
+     * taking into consideration the current values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the lowest maximum value for the given calendar field.
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getActualMinimum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getLeastMaximum(int field) {
+        switch (field) {
+        case YEAR:
+            {
+                return Math.min(LEAST_MAX_VALUES[YEAR], getMaximum(YEAR));
+            }
+        }
+        return LEAST_MAX_VALUES[field];
+    }
+
+    /**
+     * Returns the minimum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and {@link Calendar#getTimeZone() getTimeZone} methods.
+     *
+     * @param field the calendar field
+     * @return the minimum of the given field for the time value of
+     * this <code>JapaneseImperialCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMaximum(int)
+     */
+    public int getActualMinimum(int field) {
+        if (!isFieldSet(YEAR_MASK|MONTH_MASK|WEEK_OF_YEAR_MASK, field)) {
+            return getMinimum(field);
+        }
+
+        int value = 0;
+        JapaneseImperialCalendar jc = getNormalizedCalendar();
+        // Get a local date which includes time of day and time zone,
+        // which are missing in jc.jdate.
+        LocalGregorianCalendar.Date jd = jcal.getCalendarDate(jc.getTimeInMillis(),
+                                                              getZone());
+        int eraIndex = getEraIndex(jd);
+        switch (field) {
+        case YEAR:
+            {
+                if (eraIndex > BEFORE_MEIJI) {
+                    value = 1;
+                    long since = eras[eraIndex].getSince(getZone());
+                    CalendarDate d = jcal.getCalendarDate(since, getZone());
+                    // Use the same year in jd to take care of leap
+                    // years. i.e., both jd and d must agree on leap
+                    // or common years.
+                    jd.setYear(d.getYear());
+                    jcal.normalize(jd);
+                    assert jd.isLeapYear() == d.isLeapYear();
+                    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
+                        value++;
+                    }
+                } else {
+                    value = getMinimum(field);
+                    CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                    // Use an equvalent year of d.getYear() if
+                    // possible. Otherwise, ignore the leap year and
+                    // common year difference.
+                    int y = d.getYear();
+                    if (y > 400) {
+                        y -= 400;
+                    }
+                    jd.setYear(y);
+                    jcal.normalize(jd);
+                    if (getYearOffsetInMillis(jd) < getYearOffsetInMillis(d)) {
+                        value++;
+                    }
+                }
+            }
+            break;
+
+        case MONTH:
+            {
+                // In Before Meiji and Meiji, January is the first month.
+                if (eraIndex > MEIJI && jd.getYear() == 1) {
+                    long since = eras[eraIndex].getSince(getZone());
+                    CalendarDate d = jcal.getCalendarDate(since, getZone());
+                    value = d.getMonth() - 1;
+                    if (jd.getDayOfMonth() < d.getDayOfMonth()) {
+                        value++;
+                    }
+                }
+            }
+            break;
+
+        case WEEK_OF_YEAR:
+            {
+                value = 1;
+                CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                // shift 400 years to avoid underflow
+                d.addYear(+400);
+                jcal.normalize(d);
+                jd.setEra(d.getEra());
+                jd.setYear(d.getYear());
+                jcal.normalize(jd);
+
+                long jan1 = jcal.getFixedDate(d);
+                long fd = jcal.getFixedDate(jd);
+                int woy = getWeekNumber(jan1, fd);
+                long day1 = fd - (7 * (woy - 1));
+                if ((day1 < jan1) ||
+                    (day1 == jan1 &&
+                     jd.getTimeOfDay() < d.getTimeOfDay())) {
+                    value++;
+                }
+            }
+            break;
+        }
+        return value;
+    }
+
+    /**
+     * Returns the maximum value that this calendar field could have,
+     * taking into consideration the given time value and the current
+     * values of the
+     * {@link Calendar#getFirstDayOfWeek() getFirstDayOfWeek},
+     * {@link Calendar#getMinimalDaysInFirstWeek() getMinimalDaysInFirstWeek},
+     * and
+     * {@link Calendar#getTimeZone() getTimeZone} methods.
+     * For example, if the date of this instance is Heisei 16February 1,
+     * the actual maximum value of the <code>DAY_OF_MONTH</code> field
+     * is 29 because Heisei 16 is a leap year, and if the date of this
+     * instance is Heisei 17 February 1, it's 28.
+     *
+     * @param field the calendar field
+     * @return the maximum of the given field for the time value of
+     * this <code>JapaneseImperialCalendar</code>
+     * @see #getMinimum(int)
+     * @see #getMaximum(int)
+     * @see #getGreatestMinimum(int)
+     * @see #getLeastMaximum(int)
+     * @see #getActualMinimum(int)
+     */
+    public int getActualMaximum(int field) {
+        final int fieldsForFixedMax = ERA_MASK|DAY_OF_WEEK_MASK|HOUR_MASK|AM_PM_MASK|
+            HOUR_OF_DAY_MASK|MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK|
+            ZONE_OFFSET_MASK|DST_OFFSET_MASK;
+        if ((fieldsForFixedMax & (1<<field)) != 0) {
+            return getMaximum(field);
+        }
+
+        JapaneseImperialCalendar jc = getNormalizedCalendar();
+        LocalGregorianCalendar.Date date = jc.jdate;
+        int normalizedYear = date.getNormalizedYear();
+
+        int value = -1;
+        switch (field) {
+        case MONTH:
+            {
+                value = DECEMBER;
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    // TODO: there may be multiple transitions in a year.
+                    int eraIndex = getEraIndex(date);
+                    if (date.getYear() != 1) {
+                        eraIndex++;
+                        assert eraIndex < eras.length;
+                    }
+                    long transition = sinceFixedDates[eraIndex];
+                    long fd = jc.cachedFixedDate;
+                    if (fd < transition) {
+                        LocalGregorianCalendar.Date ldate
+                            = (LocalGregorianCalendar.Date) date.clone();
+                        jcal.getCalendarDateFromFixedDate(ldate, transition - 1);
+                        value = ldate.getMonth() - 1;
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                         getZone());
+                    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
+                        value = d.getMonth() - 1;
+                    }
+                }
+            }
+            break;
+
+        case DAY_OF_MONTH:
+            value = jcal.getMonthLength(date);
+            break;
+
+        case DAY_OF_YEAR:
+            {
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    // Handle transition year.
+                    // TODO: there may be multiple transitions in a year.
+                    int eraIndex = getEraIndex(date);
+                    if (date.getYear() != 1) {
+                        eraIndex++;
+                        assert eraIndex < eras.length;
+                    }
+                    long transition = sinceFixedDates[eraIndex];
+                    long fd = jc.cachedFixedDate;
+                    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
+                    if (fd < transition) {
+                        value = (int)(transition - gcal.getFixedDate(d));
+                    } else {
+                        d.addYear(+1);
+                        value = (int)(gcal.getFixedDate(d) - transition);
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                         getZone());
+                    if (date.getEra() == d.getEra() && date.getYear() == d.getYear()) {
+                        long fd = jcal.getFixedDate(d);
+                        long jan1 = getFixedDateJan1(d, fd);
+                        value = (int)(fd - jan1) + 1;
+                    } else if (date.getYear() == getMinimum(YEAR)) {
+                        CalendarDate d1 = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        long fd1 = jcal.getFixedDate(d1);
+                        d1.addYear(1);
+                        d1.setMonth(BaseCalendar.JANUARY).setDayOfMonth(1);
+                        jcal.normalize(d1);
+                        long fd2 = jcal.getFixedDate(d1);
+                        value = (int)(fd2 - fd1);
+                    } else {
+                        value = jcal.getYearLength(date);
+                    }
+                }
+            }
+            break;
+
+        case WEEK_OF_YEAR:
+            {
+                if (!isTransitionYear(date.getNormalizedYear())) {
+                    LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                          getZone());
+                    if (date.getEra() == jd.getEra() && date.getYear() == jd.getYear()) {
+                        long fd = jcal.getFixedDate(jd);
+                        long jan1 = getFixedDateJan1(jd, fd);
+                        value = getWeekNumber(jan1, fd);
+                    } else if (date.getEra() == null && date.getYear() == getMinimum(YEAR)) {
+                        CalendarDate d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                        // shift 400 years to avoid underflow
+                        d.addYear(+400);
+                        jcal.normalize(d);
+                        jd.setEra(d.getEra());
+                        jd.setDate(d.getYear() + 1, BaseCalendar.JANUARY, 1);
+                        jcal.normalize(jd);
+                        long jan1 = jcal.getFixedDate(d);
+                        long nextJan1 = jcal.getFixedDate(jd);
+                        long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                            getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek()) {
+                            nextJan1st -= 7;
+                        }
+                        value = getWeekNumber(jan1, nextJan1st);
+                    } else {
+                        // Get the day of week of January 1 of the year
+                        CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                        d.setDate(date.getNormalizedYear(), BaseCalendar.JANUARY, 1);
+                        int dayOfWeek = gcal.getDayOfWeek(d);
+                        // Normalize the day of week with the firstDayOfWeek value
+                        dayOfWeek -= getFirstDayOfWeek();
+                        if (dayOfWeek < 0) {
+                            dayOfWeek += 7;
+                        }
+                        value = 52;
+                        int magic = dayOfWeek + getMinimalDaysInFirstWeek() - 1;
+                        if ((magic == 6) ||
+                            (date.isLeapYear() && (magic == 5 || magic == 12))) {
+                            value++;
+                        }
+                    }
+                    break;
+                }
+
+                if (jc == this) {
+                    jc = (JapaneseImperialCalendar) jc.clone();
+                }
+                int max = getActualMaximum(DAY_OF_YEAR);
+                jc.set(DAY_OF_YEAR, max);
+                value = jc.get(WEEK_OF_YEAR);
+                if (value == 1 && max > 7) {
+                    jc.add(WEEK_OF_YEAR, -1);
+                    value = jc.get(WEEK_OF_YEAR);
+                }
+            }
+            break;
+
+        case WEEK_OF_MONTH:
+            {
+                LocalGregorianCalendar.Date jd = jcal.getCalendarDate(Long.MAX_VALUE,
+                                                                      getZone());
+                if (!(date.getEra() == jd.getEra() && date.getYear() == jd.getYear())) {
+                    CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+                    d.setDate(date.getNormalizedYear(), date.getMonth(), 1);
+                    int dayOfWeek = gcal.getDayOfWeek(d);
+                    int monthLength = gcal.getMonthLength(d);
+                    dayOfWeek -= getFirstDayOfWeek();
+                    if (dayOfWeek < 0) {
+                        dayOfWeek += 7;
+                    }
+                    int nDaysFirstWeek = 7 - dayOfWeek; // # of days in the first week
+                    value = 3;
+                    if (nDaysFirstWeek >= getMinimalDaysInFirstWeek()) {
+                        value++;
+                    }
+                    monthLength -= nDaysFirstWeek + 7 * 3;
+                    if (monthLength > 0) {
+                        value++;
+                        if (monthLength > 7) {
+                            value++;
+                        }
+                    }
+                } else {
+                    long fd = jcal.getFixedDate(jd);
+                    long month1 = fd - jd.getDayOfMonth() + 1;
+                    value = getWeekNumber(month1, fd);
+                }
+            }
+            break;
+
+        case DAY_OF_WEEK_IN_MONTH:
+            {
+                int ndays, dow1;
+                int dow = date.getDayOfWeek();
+                BaseCalendar.Date d = (BaseCalendar.Date) date.clone();
+                ndays = jcal.getMonthLength(d);
+                d.setDayOfMonth(1);
+                jcal.normalize(d);
+                dow1 = d.getDayOfWeek();
+                int x = dow - dow1;
+                if (x < 0) {
+                    x += 7;
+                }
+                ndays -= x;
+                value = (ndays + 6) / 7;
+            }
+            break;
+
+        case YEAR:
+            {
+                CalendarDate jd = jcal.getCalendarDate(jc.getTimeInMillis(), getZone());
+                CalendarDate d;
+                int eraIndex = getEraIndex(date);
+                if (eraIndex == eras.length - 1) {
+                    d = jcal.getCalendarDate(Long.MAX_VALUE, getZone());
+                    value = d.getYear();
+                    // Use an equivalent year for the
+                    // getYearOffsetInMillis call to avoid overflow.
+                    if (value > 400) {
+                        jd.setYear(value - 400);
+                    }
+                } else {
+                    d = jcal.getCalendarDate(eras[eraIndex + 1].getSince(getZone()) - 1,
+                                             getZone());
+                    value = d.getYear();
+                    // Use the same year as d.getYear() to be
+                    // consistent with leap and common years.
+                    jd.setYear(value);
+                }
+                jcal.normalize(jd);
+                if (getYearOffsetInMillis(jd) > getYearOffsetInMillis(d)) {
+                    value--;
+                }
+            }
+            break;
+
+        default:
+            throw new ArrayIndexOutOfBoundsException(field);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the millisecond offset from the beginning of the
+     * year. In the year for Long.MIN_VALUE, it's a pseudo value
+     * beyond the limit. The given CalendarDate object must have been
+     * normalized before calling this method.
+     */
+    private long getYearOffsetInMillis(CalendarDate date) {
+        long t = (jcal.getDayOfYear(date) - 1) * ONE_DAY;
+        return t + date.getTimeOfDay() - date.getZoneOffset();
+    }
+
+    public Object clone() {
+        JapaneseImperialCalendar other = (JapaneseImperialCalendar) super.clone();
+
+        other.jdate = (LocalGregorianCalendar.Date) jdate.clone();
+        other.originalFields = null;
+        other.zoneOffsets = null;
+        return other;
+    }
+
+    public TimeZone getTimeZone() {
+        TimeZone zone = super.getTimeZone();
+        // To share the zone by the CalendarDate
+        jdate.setZone(zone);
+        return zone;
+    }
+
+    public void setTimeZone(TimeZone zone) {
+        super.setTimeZone(zone);
+        // To share the zone by the CalendarDate
+        jdate.setZone(zone);
+    }
+
+    /**
+     * The fixed date corresponding to jdate. If the value is
+     * Long.MIN_VALUE, the fixed date value is unknown.
+     */
+    transient private long cachedFixedDate = Long.MIN_VALUE;
+
+    /**
+     * Converts the time value (millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>) to calendar field values.
+     * The time is <em>not</em>
+     * recomputed first; to recompute the time, then the fields, call the
+     * <code>complete</code> method.
+     *
+     * @see Calendar#complete
+     */
+    protected void computeFields() {
+        int mask = 0;
+        if (isPartiallyNormalized()) {
+            // Determine which calendar fields need to be computed.
+            mask = getSetStateFields();
+            int fieldMask = ~mask & ALL_FIELDS;
+            if (fieldMask != 0 || cachedFixedDate == Long.MIN_VALUE) {
+                mask |= computeFields(fieldMask,
+                                      mask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK));
+                assert mask == ALL_FIELDS;
+            }
+        } else {
+            // Specify all fields
+            mask = ALL_FIELDS;
+            computeFields(mask, 0);
+        }
+        // After computing all the fields, set the field state to `COMPUTED'.
+        setFieldsComputed(mask);
+    }
+
+    /**
+     * This computeFields implements the conversion from UTC
+     * (millisecond offset from the Epoch) to calendar
+     * field values. fieldMask specifies which fields to change the
+     * setting state to COMPUTED, although all fields are set to
+     * the correct values. This is required to fix 4685354.
+     *
+     * @param fieldMask a bit mask to specify which fields to change
+     * the setting state.
+     * @param tzMask a bit mask to specify which time zone offset
+     * fields to be used for time calculations
+     * @return a new field mask that indicates what field values have
+     * actually been set.
+     */
+    private int computeFields(int fieldMask, int tzMask) {
+        int zoneOffset = 0;
+        TimeZone tz = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            // BEGIN Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (tz instanceof ZoneInfo) {
+            //     zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
+            if (tz instanceof libcore.util.ZoneInfo) {
+                zoneOffset = ((libcore.util.ZoneInfo)tz).getOffsetsByUtcTime(time, zoneOffsets);
+            // END Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            } else {
+                zoneOffset = tz.getOffset(time);
+                zoneOffsets[0] = tz.getRawOffset();
+                zoneOffsets[1] = zoneOffset - zoneOffsets[0];
+            }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+            zoneOffset = zoneOffsets[0] + zoneOffsets[1];
+        }
+
+        // By computing time and zoneOffset separately, we can take
+        // the wider range of time+zoneOffset than the previous
+        // implementation.
+        long fixedDate = zoneOffset / ONE_DAY;
+        int timeOfDay = zoneOffset % (int)ONE_DAY;
+        fixedDate += time / ONE_DAY;
+        timeOfDay += (int) (time % ONE_DAY);
+        if (timeOfDay >= ONE_DAY) {
+            timeOfDay -= ONE_DAY;
+            ++fixedDate;
+        } else {
+            while (timeOfDay < 0) {
+                timeOfDay += ONE_DAY;
+                --fixedDate;
+            }
+        }
+        fixedDate += EPOCH_OFFSET;
+
+        // See if we can use jdate to avoid date calculation.
+        if (fixedDate != cachedFixedDate || fixedDate < 0) {
+            jcal.getCalendarDateFromFixedDate(jdate, fixedDate);
+            cachedFixedDate = fixedDate;
+        }
+        int era = getEraIndex(jdate);
+        int year = jdate.getYear();
+
+        // Always set the ERA and YEAR values.
+        internalSet(ERA, era);
+        internalSet(YEAR, year);
+        int mask = fieldMask | (ERA_MASK|YEAR_MASK);
+
+        int month =  jdate.getMonth() - 1; // 0-based
+        int dayOfMonth = jdate.getDayOfMonth();
+
+        // Set the basic date fields.
+        if ((fieldMask & (MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK))
+            != 0) {
+            internalSet(MONTH, month);
+            internalSet(DAY_OF_MONTH, dayOfMonth);
+            internalSet(DAY_OF_WEEK, jdate.getDayOfWeek());
+            mask |= MONTH_MASK|DAY_OF_MONTH_MASK|DAY_OF_WEEK_MASK;
+        }
+
+        if ((fieldMask & (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                          |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK)) != 0) {
+            if (timeOfDay != 0) {
+                int hours = timeOfDay / ONE_HOUR;
+                internalSet(HOUR_OF_DAY, hours);
+                internalSet(AM_PM, hours / 12); // Assume AM == 0
+                internalSet(HOUR, hours % 12);
+                int r = timeOfDay % ONE_HOUR;
+                internalSet(MINUTE, r / ONE_MINUTE);
+                r %= ONE_MINUTE;
+                internalSet(SECOND, r / ONE_SECOND);
+                internalSet(MILLISECOND, r % ONE_SECOND);
+            } else {
+                internalSet(HOUR_OF_DAY, 0);
+                internalSet(AM_PM, AM);
+                internalSet(HOUR, 0);
+                internalSet(MINUTE, 0);
+                internalSet(SECOND, 0);
+                internalSet(MILLISECOND, 0);
+            }
+            mask |= (HOUR_OF_DAY_MASK|AM_PM_MASK|HOUR_MASK
+                     |MINUTE_MASK|SECOND_MASK|MILLISECOND_MASK);
+        }
+
+        if ((fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) != 0) {
+            internalSet(ZONE_OFFSET, zoneOffsets[0]);
+            internalSet(DST_OFFSET, zoneOffsets[1]);
+            mask |= (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        }
+
+        if ((fieldMask & (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK
+                          |WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK)) != 0) {
+            int normalizedYear = jdate.getNormalizedYear();
+            // If it's a year of an era transition, we need to handle
+            // irregular year boundaries.
+            boolean transitionYear = isTransitionYear(jdate.getNormalizedYear());
+            int dayOfYear;
+            long fixedDateJan1;
+            if (transitionYear) {
+                fixedDateJan1 = getFixedDateJan1(jdate, fixedDate);
+                dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            } else if (normalizedYear == MIN_VALUES[YEAR]) {
+                CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+                fixedDateJan1 = jcal.getFixedDate(dx);
+                dayOfYear = (int)(fixedDate - fixedDateJan1) + 1;
+            } else {
+                dayOfYear = (int) jcal.getDayOfYear(jdate);
+                fixedDateJan1 = fixedDate - dayOfYear + 1;
+            }
+            long fixedDateMonth1 = transitionYear ?
+                getFixedDateMonth1(jdate, fixedDate) : fixedDate - dayOfMonth + 1;
+
+            internalSet(DAY_OF_YEAR, dayOfYear);
+            internalSet(DAY_OF_WEEK_IN_MONTH, (dayOfMonth - 1) / 7 + 1);
+
+            int weekOfYear = getWeekNumber(fixedDateJan1, fixedDate);
+
+            // The spec is to calculate WEEK_OF_YEAR in the
+            // ISO8601-style. This creates problems, though.
+            if (weekOfYear == 0) {
+                // If the date belongs to the last week of the
+                // previous year, use the week number of "12/31" of
+                // the "previous" year. Again, if the previous year is
+                // a transition year, we need to take care of it.
+                // Usually the previous day of the first day of a year
+                // is December 31, which is not always true in the
+                // Japanese imperial calendar system.
+                long fixedDec31 = fixedDateJan1 - 1;
+                long prevJan1;
+                LocalGregorianCalendar.Date d = getCalendarDate(fixedDec31);
+                if (!(transitionYear || isTransitionYear(d.getNormalizedYear()))) {
+                    prevJan1 = fixedDateJan1 - 365;
+                    if (d.isLeapYear()) {
+                        --prevJan1;
+                    }
+                } else if (transitionYear) {
+                    if (jdate.getYear() == 1) {
+                        // As of Reiwa (since Meiji) there's no case
+                        // that there are multiple transitions in a
+                        // year.  Historically there was such
+                        // case. There might be such case again in the
+                        // future.
+                        if (era > REIWA) {
+                            CalendarDate pd = eras[era - 1].getSinceDate();
+                            if (normalizedYear == pd.getYear()) {
+                                d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
+                            }
+                        } else {
+                            d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
+                        }
+                        jcal.normalize(d);
+                        prevJan1 = jcal.getFixedDate(d);
+                    } else {
+                        prevJan1 = fixedDateJan1 - 365;
+                        if (d.isLeapYear()) {
+                            --prevJan1;
+                        }
+                    }
+                } else {
+                    CalendarDate cd = eras[getEraIndex(jdate)].getSinceDate();
+                    d.setMonth(cd.getMonth()).setDayOfMonth(cd.getDayOfMonth());
+                    jcal.normalize(d);
+                    prevJan1 = jcal.getFixedDate(d);
+                }
+                weekOfYear = getWeekNumber(prevJan1, fixedDec31);
+            } else {
+                if (!transitionYear) {
+                    // Regular years
+                    if (weekOfYear >= 52) {
+                        long nextJan1 = fixedDateJan1 + 365;
+                        if (jdate.isLeapYear()) {
+                            nextJan1++;
+                        }
+                        long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                            getFirstDayOfWeek());
+                        int ndays = (int)(nextJan1st - nextJan1);
+                        if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                            // The first days forms a week in which the date is included.
+                            weekOfYear = 1;
+                        }
+                    }
+                } else {
+                    LocalGregorianCalendar.Date d = (LocalGregorianCalendar.Date) jdate.clone();
+                    long nextJan1;
+                    if (jdate.getYear() == 1) {
+                        d.addYear(+1);
+                        d.setMonth(LocalGregorianCalendar.JANUARY).setDayOfMonth(1);
+                        nextJan1 = jcal.getFixedDate(d);
+                    } else {
+                        int nextEraIndex = getEraIndex(d) + 1;
+                        CalendarDate cd = eras[nextEraIndex].getSinceDate();
+                        d.setEra(eras[nextEraIndex]);
+                        d.setDate(1, cd.getMonth(), cd.getDayOfMonth());
+                        jcal.normalize(d);
+                        nextJan1 = jcal.getFixedDate(d);
+                    }
+                    long nextJan1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(nextJan1 + 6,
+                                                                                        getFirstDayOfWeek());
+                    int ndays = (int)(nextJan1st - nextJan1);
+                    if (ndays >= getMinimalDaysInFirstWeek() && fixedDate >= (nextJan1st - 7)) {
+                        // The first days forms a week in which the date is included.
+                        weekOfYear = 1;
+                    }
+                }
+            }
+            internalSet(WEEK_OF_YEAR, weekOfYear);
+            internalSet(WEEK_OF_MONTH, getWeekNumber(fixedDateMonth1, fixedDate));
+            mask |= (DAY_OF_YEAR_MASK|WEEK_OF_YEAR_MASK|WEEK_OF_MONTH_MASK|DAY_OF_WEEK_IN_MONTH_MASK);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the number of weeks in a period between fixedDay1 and
+     * fixedDate. The getFirstDayOfWeek-getMinimalDaysInFirstWeek rule
+     * is applied to calculate the number of weeks.
+     *
+     * @param fixedDay1 the fixed date of the first day of the period
+     * @param fixedDate the fixed date of the last day of the period
+     * @return the number of weeks of the given period
+     */
+    private int getWeekNumber(long fixedDay1, long fixedDate) {
+        // We can always use `jcal' since Julian and Gregorian are the
+        // same thing for this calculation.
+        long fixedDay1st = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDay1 + 6,
+                                                                             getFirstDayOfWeek());
+        int ndays = (int)(fixedDay1st - fixedDay1);
+        assert ndays <= 7;
+        if (ndays >= getMinimalDaysInFirstWeek()) {
+            fixedDay1st -= 7;
+        }
+        int normalizedDayOfPeriod = (int)(fixedDate - fixedDay1st);
+        if (normalizedDayOfPeriod >= 0) {
+            return normalizedDayOfPeriod / 7 + 1;
+        }
+        return CalendarUtils.floorDivide(normalizedDayOfPeriod, 7) + 1;
+    }
+
+    /**
+     * Converts calendar field values to the time value (millisecond
+     * offset from the <a href="Calendar.html#Epoch">Epoch</a>).
+     *
+     * @exception IllegalArgumentException if any calendar fields are invalid.
+     */
+    protected void computeTime() {
+        // In non-lenient mode, perform brief checking of calendar
+        // fields which have been set externally. Through this
+        // checking, the field values are stored in originalFields[]
+        // to see if any of them are normalized later.
+        if (!isLenient()) {
+            if (originalFields == null) {
+                originalFields = new int[FIELD_COUNT];
+            }
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                int value = internalGet(field);
+                if (isExternallySet(field)) {
+                    // Quick validation for any out of range values
+                    if (value < getMinimum(field) || value > getMaximum(field)) {
+                        throw new IllegalArgumentException(getFieldName(field));
+                    }
+                }
+                originalFields[field] = value;
+            }
+        }
+
+        // Let the super class determine which calendar fields to be
+        // used to calculate the time.
+        int fieldMask = selectFields();
+
+        int year;
+        int era;
+
+        if (isSet(ERA)) {
+            era = internalGet(ERA);
+            year = isSet(YEAR) ? internalGet(YEAR) : 1;
+        } else {
+            if (isSet(YEAR)) {
+                era = currentEra;
+                year = internalGet(YEAR);
+            } else {
+                // Equivalent to 1970 (Gregorian)
+                era = SHOWA;
+                year = 45;
+            }
+        }
+
+        // Calculate the time of day. We rely on the convention that
+        // an UNSET field has 0.
+        long timeOfDay = 0;
+        if (isFieldSet(fieldMask, HOUR_OF_DAY)) {
+            timeOfDay += (long) internalGet(HOUR_OF_DAY);
+        } else {
+            timeOfDay += internalGet(HOUR);
+            // The default value of AM_PM is 0 which designates AM.
+            if (isFieldSet(fieldMask, AM_PM)) {
+                timeOfDay += 12 * internalGet(AM_PM);
+            }
+        }
+        timeOfDay *= 60;
+        timeOfDay += internalGet(MINUTE);
+        timeOfDay *= 60;
+        timeOfDay += internalGet(SECOND);
+        timeOfDay *= 1000;
+        timeOfDay += internalGet(MILLISECOND);
+
+        // Convert the time of day to the number of days and the
+        // millisecond offset from midnight.
+        long fixedDate = timeOfDay / ONE_DAY;
+        timeOfDay %= ONE_DAY;
+        while (timeOfDay < 0) {
+            timeOfDay += ONE_DAY;
+            --fixedDate;
+        }
+
+        // Calculate the fixed date since January 1, 1 (Gregorian).
+        fixedDate += getFixedDate(era, year, fieldMask);
+
+        // millis represents local wall-clock time in milliseconds.
+        long millis = (fixedDate - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
+
+        // Compute the time zone offset and DST offset.  There are two potential
+        // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
+        // for discussion purposes here.
+        // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
+        //    can be in standard or in DST depending.  However, 2:00 am is an invalid
+        //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
+        //    We assume standard time.
+        // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
+        //    can be in standard or DST.  Both are valid representations (the rep
+        //    jumps from 1:59:59 DST to 1:00:00 Std).
+        //    Again, we assume standard time.
+        // We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
+        // or DST_OFFSET fields; then we use those fields.
+        TimeZone zone = getZone();
+        if (zoneOffsets == null) {
+            zoneOffsets = new int[2];
+        }
+        int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
+        if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
+            // Android-changed: Android doesn't have sun.util.calendar.ZoneInfo.
+            // if (zone instanceof ZoneInfo) {
+            //     ((ZoneInfo)zone).getOffsetsByWall(millis, zoneOffsets);
+            // } else {
+                zone.getOffsets(millis - zone.getRawOffset(), zoneOffsets);
+            // }
+        }
+        if (tzMask != 0) {
+            if (isFieldSet(tzMask, ZONE_OFFSET)) {
+                zoneOffsets[0] = internalGet(ZONE_OFFSET);
+            }
+            if (isFieldSet(tzMask, DST_OFFSET)) {
+                zoneOffsets[1] = internalGet(DST_OFFSET);
+            }
+        }
+
+        // Adjust the time zone offset values to get the UTC time.
+        millis -= zoneOffsets[0] + zoneOffsets[1];
+
+        // Set this calendar's time in milliseconds
+        time = millis;
+
+        int mask = computeFields(fieldMask | getSetStateFields(), tzMask);
+
+        if (!isLenient()) {
+            for (int field = 0; field < FIELD_COUNT; field++) {
+                if (!isExternallySet(field)) {
+                    continue;
+                }
+                if (originalFields[field] != internalGet(field)) {
+                    int wrongValue = internalGet(field);
+                    // Restore the original field values
+                    System.arraycopy(originalFields, 0, fields, 0, fields.length);
+                    throw new IllegalArgumentException(getFieldName(field) + "=" + wrongValue
+                                                       + ", expected " + originalFields[field]);
+                }
+            }
+        }
+        setFieldsNormalized(mask);
+    }
+
+    /**
+     * Computes the fixed date under either the Gregorian or the
+     * Julian calendar, using the given year and the specified calendar fields.
+     *
+     * @param era era index
+     * @param year the normalized year number, with 0 indicating the
+     * year 1 BCE, -1 indicating 2 BCE, etc.
+     * @param fieldMask the calendar fields to be used for the date calculation
+     * @return the fixed date
+     * @see Calendar#selectFields
+     */
+    private long getFixedDate(int era, int year, int fieldMask) {
+        int month = JANUARY;
+        int firstDayOfMonth = 1;
+        if (isFieldSet(fieldMask, MONTH)) {
+            // No need to check if MONTH has been set (no isSet(MONTH)
+            // call) since its unset value happens to be JANUARY (0).
+            month = internalGet(MONTH);
+
+            // If the month is out of range, adjust it into range.
+            if (month > DECEMBER) {
+                year += month / 12;
+                month %= 12;
+            } else if (month < JANUARY) {
+                int[] rem = new int[1];
+                year += CalendarUtils.floorDivide(month, 12, rem);
+                month = rem[0];
+            }
+        } else {
+            if (year == 1 && era != 0) {
+                CalendarDate d = eras[era].getSinceDate();
+                month = d.getMonth() - 1;
+                firstDayOfMonth = d.getDayOfMonth();
+            }
+        }
+
+        // Adjust the base date if year is the minimum value.
+        if (year == MIN_VALUES[YEAR]) {
+            CalendarDate dx = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+            int m = dx.getMonth() - 1;
+            if (month < m) {
+                month = m;
+            }
+            if (month == m) {
+                firstDayOfMonth = dx.getDayOfMonth();
+            }
+        }
+
+        LocalGregorianCalendar.Date date = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        date.setEra(era > 0 ? eras[era] : null);
+        date.setDate(year, month + 1, firstDayOfMonth);
+        jcal.normalize(date);
+
+        // Get the fixed date since Jan 1, 1 (Gregorian). We are on
+        // the first day of either `month' or January in 'year'.
+        long fixedDate = jcal.getFixedDate(date);
+
+        if (isFieldSet(fieldMask, MONTH)) {
+            // Month-based calculations
+            if (isFieldSet(fieldMask, DAY_OF_MONTH)) {
+                // We are on the "first day" of the month (which may
+                // not be 1). Just add the offset if DAY_OF_MONTH is
+                // set. If the isSet call returns false, that means
+                // DAY_OF_MONTH has been selected just because of the
+                // selected combination. We don't need to add any
+                // since the default value is the "first day".
+                if (isSet(DAY_OF_MONTH)) {
+                    // To avoid underflow with DAY_OF_MONTH-firstDayOfMonth, add
+                    // DAY_OF_MONTH, then subtract firstDayOfMonth.
+                    fixedDate += internalGet(DAY_OF_MONTH);
+                    fixedDate -= firstDayOfMonth;
+                }
+            } else {
+                if (isFieldSet(fieldMask, WEEK_OF_MONTH)) {
+                    long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                            getFirstDayOfWeek());
+                    // If we have enough days in the first week, then
+                    // move to the previous week.
+                    if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                        firstDayOfWeek -= 7;
+                    }
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                           internalGet(DAY_OF_WEEK));
+                    }
+                    // In lenient mode, we treat days of the previous
+                    // months as a part of the specified
+                    // WEEK_OF_MONTH. See 4633646.
+                    fixedDate = firstDayOfWeek + 7 * (internalGet(WEEK_OF_MONTH) - 1);
+                } else {
+                    int dayOfWeek;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                        dayOfWeek = internalGet(DAY_OF_WEEK);
+                    } else {
+                        dayOfWeek = getFirstDayOfWeek();
+                    }
+                    // We are basing this on the day-of-week-in-month.  The only
+                    // trickiness occurs if the day-of-week-in-month is
+                    // negative.
+                    int dowim;
+                    if (isFieldSet(fieldMask, DAY_OF_WEEK_IN_MONTH)) {
+                        dowim = internalGet(DAY_OF_WEEK_IN_MONTH);
+                    } else {
+                        dowim = 1;
+                    }
+                    if (dowim >= 0) {
+                        fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + (7 * dowim) - 1,
+                                                                                      dayOfWeek);
+                    } else {
+                        // Go to the first day of the next week of
+                        // the specified week boundary.
+                        int lastDate = monthLength(month, year) + (7 * (dowim + 1));
+                        // Then, get the day of week date on or before the last date.
+                        fixedDate = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + lastDate - 1,
+                                                                                      dayOfWeek);
+                    }
+                }
+            }
+        } else {
+            // We are on the first day of the year.
+            if (isFieldSet(fieldMask, DAY_OF_YEAR)) {
+                if (isTransitionYear(date.getNormalizedYear())) {
+                    fixedDate = getFixedDateJan1(date, fixedDate);
+                }
+                // Add the offset, then subtract 1. (Make sure to avoid underflow.)
+                fixedDate += internalGet(DAY_OF_YEAR);
+                fixedDate--;
+            } else {
+                long firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(fixedDate + 6,
+                                                                                        getFirstDayOfWeek());
+                // If we have enough days in the first week, then move
+                // to the previous week.
+                if ((firstDayOfWeek - fixedDate) >= getMinimalDaysInFirstWeek()) {
+                    firstDayOfWeek -= 7;
+                }
+                if (isFieldSet(fieldMask, DAY_OF_WEEK)) {
+                    int dayOfWeek = internalGet(DAY_OF_WEEK);
+                    if (dayOfWeek != getFirstDayOfWeek()) {
+                        firstDayOfWeek = LocalGregorianCalendar.getDayOfWeekDateOnOrBefore(firstDayOfWeek + 6,
+                                                                                           dayOfWeek);
+                    }
+                }
+                fixedDate = firstDayOfWeek + 7 * ((long)internalGet(WEEK_OF_YEAR) - 1);
+            }
+        }
+        return fixedDate;
+    }
+
+    /**
+     * Returns the fixed date of the first day of the year (usually
+     * January 1) before the specified date.
+     *
+     * @param date the date for which the first day of the year is
+     * calculated. The date has to be in the cut-over year.
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateJan1(LocalGregorianCalendar.Date date, long fixedDate) {
+        Era era = date.getEra();
+        if (date.getEra() != null && date.getYear() == 1) {
+            for (int eraIndex = getEraIndex(date); eraIndex > 0; eraIndex--) {
+                CalendarDate d = eras[eraIndex].getSinceDate();
+                long fd = gcal.getFixedDate(d);
+                // There might be multiple era transitions in a year.
+                if (fd > fixedDate) {
+                    continue;
+                }
+                return fd;
+            }
+        }
+        CalendarDate d = gcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        d.setDate(date.getNormalizedYear(), Gregorian.JANUARY, 1);
+        return gcal.getFixedDate(d);
+    }
+
+    /**
+     * Returns the fixed date of the first date of the month (usually
+     * the 1st of the month) before the specified date.
+     *
+     * @param date the date for which the first day of the month is
+     * calculated. The date must be in the era transition year.
+     * @param fixedDate the fixed date representation of the date
+     */
+    private long getFixedDateMonth1(LocalGregorianCalendar.Date date,
+                                          long fixedDate) {
+        int eraIndex = getTransitionEraIndex(date);
+        if (eraIndex != -1) {
+            long transition = sinceFixedDates[eraIndex];
+            // If the given date is on or after the transition date, then
+            // return the transition date.
+            if (transition <= fixedDate) {
+                return transition;
+            }
+        }
+
+        // Otherwise, we can use the 1st day of the month.
+        return fixedDate - date.getDayOfMonth() + 1;
+    }
+
+    /**
+     * Returns a LocalGregorianCalendar.Date produced from the specified fixed date.
+     *
+     * @param fd the fixed date
+     */
+    private static LocalGregorianCalendar.Date getCalendarDate(long fd) {
+        LocalGregorianCalendar.Date d = jcal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        jcal.getCalendarDateFromFixedDate(d, fd);
+        return d;
+    }
+
+    /**
+     * Returns the length of the specified month in the specified
+     * Gregorian year. The year number must be normalized.
+     *
+     * @see GregorianCalendar#isLeapYear(int)
+     */
+    private int monthLength(int month, int gregorianYear) {
+        return CalendarUtils.isGregorianLeapYear(gregorianYear) ?
+            GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
+    }
+
+    /**
+     * Returns the length of the specified month in the year provided
+     * by internalGet(YEAR).
+     *
+     * @see GregorianCalendar#isLeapYear(int)
+     */
+    private int monthLength(int month) {
+        assert jdate.isNormalized();
+        return jdate.isLeapYear() ?
+            GregorianCalendar.LEAP_MONTH_LENGTH[month] : GregorianCalendar.MONTH_LENGTH[month];
+    }
+
+    private int actualMonthLength() {
+        int length = jcal.getMonthLength(jdate);
+        int eraIndex = getTransitionEraIndex(jdate);
+        if (eraIndex == -1) {
+            long transitionFixedDate = sinceFixedDates[eraIndex];
+            CalendarDate d = eras[eraIndex].getSinceDate();
+            if (transitionFixedDate <= cachedFixedDate) {
+                length -= d.getDayOfMonth() - 1;
+            } else {
+                length = d.getDayOfMonth() - 1;
+            }
+        }
+        return length;
+    }
+
+    /**
+     * Returns the index to the new era if the given date is in a
+     * transition month.  For example, if the give date is Heisei 1
+     * (1989) January 20, then the era index for Heisei is
+     * returned. Likewise, if the given date is Showa 64 (1989)
+     * January 3, then the era index for Heisei is returned. If the
+     * given date is not in any transition month, then -1 is returned.
+     */
+    private static int getTransitionEraIndex(LocalGregorianCalendar.Date date) {
+        int eraIndex = getEraIndex(date);
+        CalendarDate transitionDate = eras[eraIndex].getSinceDate();
+        if (transitionDate.getYear() == date.getNormalizedYear() &&
+            transitionDate.getMonth() == date.getMonth()) {
+            return eraIndex;
+        }
+        if (eraIndex < eras.length - 1) {
+            transitionDate = eras[++eraIndex].getSinceDate();
+            if (transitionDate.getYear() == date.getNormalizedYear() &&
+                transitionDate.getMonth() == date.getMonth()) {
+                return eraIndex;
+            }
+        }
+        return -1;
+    }
+
+    private boolean isTransitionYear(int normalizedYear) {
+        for (int i = eras.length - 1; i > 0; i--) {
+            int transitionYear = eras[i].getSinceDate().getYear();
+            if (normalizedYear == transitionYear) {
+                return true;
+            }
+            if (normalizedYear > transitionYear) {
+                break;
+            }
+        }
+        return false;
+    }
+
+    private static int getEraIndex(LocalGregorianCalendar.Date date) {
+        Era era = date.getEra();
+        for (int i = eras.length - 1; i > 0; i--) {
+            if (eras[i] == era) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Returns this object if it's normalized (all fields and time are
+     * in sync). Otherwise, a cloned object is returned after calling
+     * complete() in lenient mode.
+     */
+    private JapaneseImperialCalendar getNormalizedCalendar() {
+        JapaneseImperialCalendar jc;
+        if (isFullyNormalized()) {
+            jc = this;
+        } else {
+            // Create a clone and normalize the calendar fields
+            jc = (JapaneseImperialCalendar) this.clone();
+            jc.setLenient(true);
+            jc.complete();
+        }
+        return jc;
+    }
+
+    /**
+     * After adjustments such as add(MONTH), add(YEAR), we don't want the
+     * month to jump around.  E.g., we don't want Jan 31 + 1 month to go to Mar
+     * 3, we want it to go to Feb 28.  Adjustments which might run into this
+     * problem call this method to retain the proper month.
+     */
+    private void pinDayOfMonth(LocalGregorianCalendar.Date date) {
+        int year = date.getYear();
+        int dom = date.getDayOfMonth();
+        if (year != getMinimum(YEAR)) {
+            date.setDayOfMonth(1);
+            jcal.normalize(date);
+            int monthLength = jcal.getMonthLength(date);
+            if (dom > monthLength) {
+                date.setDayOfMonth(monthLength);
+            } else {
+                date.setDayOfMonth(dom);
+            }
+            jcal.normalize(date);
+        } else {
+            LocalGregorianCalendar.Date d = jcal.getCalendarDate(Long.MIN_VALUE, getZone());
+            LocalGregorianCalendar.Date realDate = jcal.getCalendarDate(time, getZone());
+            long tod = realDate.getTimeOfDay();
+            // Use an equivalent year.
+            realDate.addYear(+400);
+            realDate.setMonth(date.getMonth());
+            realDate.setDayOfMonth(1);
+            jcal.normalize(realDate);
+            int monthLength = jcal.getMonthLength(realDate);
+            if (dom > monthLength) {
+                realDate.setDayOfMonth(monthLength);
+            } else {
+                if (dom < d.getDayOfMonth()) {
+                    realDate.setDayOfMonth(d.getDayOfMonth());
+                } else {
+                    realDate.setDayOfMonth(dom);
+                }
+            }
+            if (realDate.getDayOfMonth() == d.getDayOfMonth() && tod < d.getTimeOfDay()) {
+                realDate.setDayOfMonth(Math.min(dom + 1, monthLength));
+            }
+            // restore the year.
+            date.setDate(year, realDate.getMonth(), realDate.getDayOfMonth());
+            // Don't normalize date here so as not to cause underflow.
+        }
+    }
+
+    /**
+     * Returns the new value after 'roll'ing the specified value and amount.
+     */
+    private static int getRolledValue(int value, int amount, int min, int max) {
+        assert value >= min && value <= max;
+        int range = max - min + 1;
+        amount %= range;
+        int n = value + amount;
+        if (n > max) {
+            n -= range;
+        } else if (n < min) {
+            n += range;
+        }
+        assert n >= min && n <= max;
+        return n;
+    }
+
+    /**
+     * Returns the ERA.  We need a special method for this because the
+     * default ERA is the current era, but a zero (unset) ERA means before Meiji.
+     */
+    private int internalGetEra() {
+        return isSet(ERA) ? internalGet(ERA) : currentEra;
+    }
+
+    /**
+     * Updates internal state.
+     */
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();
+        if (jdate == null) {
+            jdate = jcal.newCalendarDate(getZone());
+            cachedFixedDate = Long.MIN_VALUE;
+        }
+    }
+}
diff --git a/java/util/JumboEnumSet.java b/java/util/JumboEnumSet.java
new file mode 100644
index 0000000..6798511
--- /dev/null
+++ b/java/util/JumboEnumSet.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Private implementation class for EnumSet, for "jumbo" enum types
+ * (i.e., those with more than 64 elements).
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @serial exclude
+ */
+class JumboEnumSet<E extends Enum<E>> extends EnumSet<E> {
+    private static final long serialVersionUID = 334349849919042784L;
+
+    /**
+     * Bit vector representation of this set.  The ith bit of the jth
+     * element of this array represents the  presence of universe[64*j +i]
+     * in this set.
+     */
+    private long elements[];
+
+    // Redundant - maintained for performance
+    private int size = 0;
+
+    JumboEnumSet(Class<E>elementType, Enum<?>[] universe) {
+        super(elementType, universe);
+        elements = new long[(universe.length + 63) >>> 6];
+    }
+
+    void addRange(E from, E to) {
+        int fromIndex = from.ordinal() >>> 6;
+        int toIndex = to.ordinal() >>> 6;
+
+        if (fromIndex == toIndex) {
+            elements[fromIndex] = (-1L >>>  (from.ordinal() - to.ordinal() - 1))
+                            << from.ordinal();
+        } else {
+            elements[fromIndex] = (-1L << from.ordinal());
+            for (int i = fromIndex + 1; i < toIndex; i++)
+                elements[i] = -1;
+            elements[toIndex] = -1L >>> (63 - to.ordinal());
+        }
+        size = to.ordinal() - from.ordinal() + 1;
+    }
+
+    void addAll() {
+        for (int i = 0; i < elements.length; i++)
+            elements[i] = -1;
+        elements[elements.length - 1] >>>= -universe.length;
+        size = universe.length;
+    }
+
+    void complement() {
+        for (int i = 0; i < elements.length; i++)
+            elements[i] = ~elements[i];
+        elements[elements.length - 1] &= (-1L >>> -universe.length);
+        size = universe.length - size;
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set.  The
+     * iterator traverses the elements in their <i>natural order</i> (which is
+     * the order in which the enum constants are declared). The returned
+     * Iterator is a "weakly consistent" iterator that will never throw {@link
+     * ConcurrentModificationException}.
+     *
+     * @return an iterator over the elements contained in this set
+     */
+    public Iterator<E> iterator() {
+        return new EnumSetIterator<>();
+    }
+
+    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
+        /**
+         * A bit vector representing the elements in the current "word"
+         * of the set not yet returned by this iterator.
+         */
+        long unseen;
+
+        /**
+         * The index corresponding to unseen in the elements array.
+         */
+        int unseenIndex = 0;
+
+        /**
+         * The bit representing the last element returned by this iterator
+         * but not removed, or zero if no such element exists.
+         */
+        long lastReturned = 0;
+
+        /**
+         * The index corresponding to lastReturned in the elements array.
+         */
+        int lastReturnedIndex = 0;
+
+        EnumSetIterator() {
+            unseen = elements[0];
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (unseen == 0 && unseenIndex < elements.length - 1)
+                unseen = elements[++unseenIndex];
+            return unseen != 0;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (!hasNext())
+                throw new NoSuchElementException();
+            lastReturned = unseen & -unseen;
+            lastReturnedIndex = unseenIndex;
+            unseen -= lastReturned;
+            return (E) universe[(lastReturnedIndex << 6)
+                                + Long.numberOfTrailingZeros(lastReturned)];
+        }
+
+        @Override
+        public void remove() {
+            if (lastReturned == 0)
+                throw new IllegalStateException();
+            final long oldElements = elements[lastReturnedIndex];
+            elements[lastReturnedIndex] &= ~lastReturned;
+            if (oldElements != elements[lastReturnedIndex]) {
+                size--;
+            }
+            lastReturned = 0;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     *
+     * @param e element to be checked for containment in this collection
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        int eOrdinal = ((Enum<?>)e).ordinal();
+        return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
+    }
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if the set changed as a result of the call
+     *
+     * @throws NullPointerException if <tt>e</tt> is null
+     */
+    public boolean add(E e) {
+        typeCheck(e);
+
+        int eOrdinal = e.ordinal();
+        int eWordNum = eOrdinal >>> 6;
+
+        long oldElements = elements[eWordNum];
+        elements[eWordNum] |= (1L << eOrdinal);
+        boolean result = (elements[eWordNum] != oldElements);
+        if (result)
+            size++;
+        return result;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     *
+     * @param e element to be removed from this set, if present
+     * @return <tt>true</tt> if the set contained the specified element
+     */
+    public boolean remove(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+        int eOrdinal = ((Enum<?>)e).ordinal();
+        int eWordNum = eOrdinal >>> 6;
+
+        long oldElements = elements[eWordNum];
+        elements[eWordNum] &= ~(1L << eOrdinal);
+        boolean result = (elements[eWordNum] != oldElements);
+        if (result)
+            size--;
+        return result;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns <tt>true</tt> if this set contains all of the elements
+     * in the specified collection.
+     *
+     * @param c collection to be checked for containment in this set
+     * @return <tt>true</tt> if this set contains all of the elements
+     *        in the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean containsAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.containsAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return es.isEmpty();
+
+        for (int i = 0; i < elements.length; i++)
+            if ((es.elements[i] & ~elements[i]) != 0)
+                return false;
+        return true;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection whose elements are to be added to this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection or any of
+     *     its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.addAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            if (es.isEmpty())
+                return false;
+            else
+                throw new ClassCastException(
+                    es.elementType + " != " + elementType);
+        }
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] |= es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.
+     *
+     * @param c elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.removeAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return false;
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] &= ~es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.
+     *
+     * @param c elements to be retained in this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (!(c instanceof JumboEnumSet))
+            return super.retainAll(c);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            boolean changed = (size != 0);
+            clear();
+            return changed;
+        }
+
+        for (int i = 0; i < elements.length; i++)
+            elements[i] &= es.elements[i];
+        return recalculateSize();
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        Arrays.fill(elements, 0);
+        size = 0;
+    }
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.
+     *
+     * @param o object to be compared for equality with this set
+     * @return <tt>true</tt> if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof JumboEnumSet))
+            return super.equals(o);
+
+        JumboEnumSet<?> es = (JumboEnumSet<?>)o;
+        if (es.elementType != elementType)
+            return size == 0 && es.size == 0;
+
+        return Arrays.equals(es.elements, elements);
+    }
+
+    /**
+     * Recalculates the size of the set.  Returns true if it's changed.
+     */
+    private boolean recalculateSize() {
+        int oldSize = size;
+        size = 0;
+        for (long elt : elements)
+            size += Long.bitCount(elt);
+
+        return size != oldSize;
+    }
+
+    public EnumSet<E> clone() {
+        JumboEnumSet<E> result = (JumboEnumSet<E>) super.clone();
+        result.elements = result.elements.clone();
+        return result;
+    }
+}
diff --git a/java/util/KeyValueHolder.java b/java/util/KeyValueHolder.java
new file mode 100644
index 0000000..3b7250e
--- /dev/null
+++ b/java/util/KeyValueHolder.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.vm.annotation.Stable;
+
+/**
+ * An immutable container for a key and a value, suitable for use
+ * in creating and populating {@code Map} instances.
+ *
+ * <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
+ * class; use of identity-sensitive operations (including reference equality
+ * ({@code ==}), identity hash code, or synchronization) on instances of
+ * {@code KeyValueHolder} may have unpredictable results and should be avoided.
+ *
+ * @apiNote
+ * This class is not public. Instances can be created using the
+ * {@link Map#entry Map.entry(k, v)} factory method, which is public.
+ *
+ * <p>This class differs from AbstractMap.SimpleImmutableEntry in the following ways:
+ * it is not serializable, it is final, and its key and value must be non-null.
+ *
+ * @param <K> the key type
+ * @param <V> the value type
+ *
+ * @see Map#ofEntries Map.ofEntries()
+ * @since 9
+ */
+final class KeyValueHolder<K,V> implements Map.Entry<K,V> {
+    @Stable
+    final K key;
+    @Stable
+    final V value;
+
+    KeyValueHolder(K k, V v) {
+        key = Objects.requireNonNull(k);
+        value = Objects.requireNonNull(v);
+    }
+
+    /**
+     * Gets the key from this holder.
+     *
+     * @return the key
+     */
+    @Override
+    public K getKey() {
+        return key;
+    }
+
+    /**
+     * Gets the value from this holder.
+     *
+     * @return the value
+     */
+    @Override
+    public V getValue() {
+        return value;
+    }
+
+    /**
+     * Throws {@link UnsupportedOperationException}.
+     *
+     * @param value ignored
+     * @return never returns normally
+     */
+    @Override
+    public V setValue(V value) {
+        throw new UnsupportedOperationException("not supported");
+    }
+
+    /**
+     * Compares the specified object with this entry for equality.
+     * Returns {@code true} if the given object is also a map entry and
+     * the two entries' keys and values are equal. Note that key and
+     * value are non-null, so equals() can be called safely on them.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Map.Entry))
+            return false;
+        Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+        return key.equals(e.getKey()) && value.equals(e.getValue());
+    }
+
+    /**
+     * Returns the hash code value for this map entry. The hash code
+     * is {@code key.hashCode() ^ value.hashCode()}. Note that key and
+     * value are non-null, so hashCode() can be called safely on them.
+     */
+    @Override
+    public int hashCode() {
+        return key.hashCode() ^ value.hashCode();
+    }
+
+    /**
+     * Returns a String representation of this map entry.  This
+     * implementation returns the string representation of this
+     * entry's key followed by the equals character ("{@code =}")
+     * followed by the string representation of this entry's value.
+     *
+     * @return a String representation of this map entry
+     */
+    @Override
+    public String toString() {
+        return key + "=" + value;
+    }
+}
diff --git a/java/util/LinkedHashMap.annotated.java b/java/util/LinkedHashMap.annotated.java
new file mode 100644
index 0000000..9f494b6
--- /dev/null
+++ b/java/util/LinkedHashMap.annotated.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class LinkedHashMap<K, V> extends java.util.HashMap<K,V> implements java.util.Map<K,V> {
+
+public LinkedHashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap() { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap(java.util.Map<? extends K, ? extends V> m) { throw new RuntimeException("Stub!"); }
+
+public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public V get(java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public V getOrDefault(java.lang.Object key, V defaultValue) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.util.Map.Entry<K,V> eldest() { throw new RuntimeException("Stub!"); }
+
+protected boolean removeEldestEntry(java.util.Map.Entry<K,V> eldest) { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<K> keySet() { throw new RuntimeException("Stub!"); }
+
+public java.util.Collection<V> values() { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.util.Map.Entry<K,V>> entrySet() { throw new RuntimeException("Stub!"); }
+
+public void forEach(java.util.function.BiConsumer<? super K,? super V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(java.util.function.BiFunction<? super K,? super V,? extends V> function) { throw new RuntimeException("Stub!"); }
+}
+
diff --git a/java/util/LinkedHashMap.java b/java/util/LinkedHashMap.java
new file mode 100644
index 0000000..9d3815f
--- /dev/null
+++ b/java/util/LinkedHashMap.java
@@ -0,0 +1,794 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.io.IOException;
+
+// Android-added: Note about spliterator order b/33945212 in Android N
+/**
+ * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
+ * with predictable iteration order.  This implementation differs from
+ * <tt>HashMap</tt> in that it maintains a doubly-linked list running through
+ * all of its entries.  This linked list defines the iteration ordering,
+ * which is normally the order in which keys were inserted into the map
+ * (<i>insertion-order</i>).  Note that insertion order is not affected
+ * if a key is <i>re-inserted</i> into the map.  (A key <tt>k</tt> is
+ * reinserted into a map <tt>m</tt> if <tt>m.put(k, v)</tt> is invoked when
+ * <tt>m.containsKey(k)</tt> would return <tt>true</tt> immediately prior to
+ * the invocation.)
+ *
+ * <p>This implementation spares its clients from the unspecified, generally
+ * chaotic ordering provided by {@link HashMap} (and {@link Hashtable}),
+ * without incurring the increased cost associated with {@link TreeMap}.  It
+ * can be used to produce a copy of a map that has the same order as the
+ * original, regardless of the original map's implementation:
+ * <pre>
+ *     void foo(Map m) {
+ *         Map copy = new LinkedHashMap(m);
+ *         ...
+ *     }
+ * </pre>
+ * This technique is particularly useful if a module takes a map on input,
+ * copies it, and later returns results whose order is determined by that of
+ * the copy.  (Clients generally appreciate having things returned in the same
+ * order they were presented.)
+ *
+ * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
+ * provided to create a linked hash map whose order of iteration is the order
+ * in which its entries were last accessed, from least-recently accessed to
+ * most-recently (<i>access-order</i>).  This kind of map is well-suited to
+ * building LRU caches.  Invoking the {@code put}, {@code putIfAbsent},
+ * {@code get}, {@code getOrDefault}, {@code compute}, {@code computeIfAbsent},
+ * {@code computeIfPresent}, or {@code merge} methods results
+ * in an access to the corresponding entry (assuming it exists after the
+ * invocation completes). The {@code replace} methods only result in an access
+ * of the entry if the value is replaced.  The {@code putAll} method generates one
+ * entry access for each mapping in the specified map, in the order that
+ * key-value mappings are provided by the specified map's entry set iterator.
+ * <i>No other methods generate entry accesses.</i>  In particular, operations
+ * on collection-views do <i>not</i> affect the order of iteration of the
+ * backing map.
+ *
+ * <p>The {@link #removeEldestEntry(Map.Entry)} method may be overridden to
+ * impose a policy for removing stale mappings automatically when new mappings
+ * are added to the map.
+ *
+ * <p>This class provides all of the optional <tt>Map</tt> operations, and
+ * permits null elements.  Like <tt>HashMap</tt>, it provides constant-time
+ * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
+ * <tt>remove</tt>), assuming the hash function disperses elements
+ * properly among the buckets.  Performance is likely to be just slightly
+ * below that of <tt>HashMap</tt>, due to the added expense of maintaining the
+ * linked list, with one exception: Iteration over the collection-views
+ * of a <tt>LinkedHashMap</tt> requires time proportional to the <i>size</i>
+ * of the map, regardless of its capacity.  Iteration over a <tt>HashMap</tt>
+ * is likely to be more expensive, requiring time proportional to its
+ * <i>capacity</i>.
+ *
+ * <p>A linked hash map has two parameters that affect its performance:
+ * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
+ * as for <tt>HashMap</tt>.  Note, however, that the penalty for choosing an
+ * excessively high value for initial capacity is less severe for this class
+ * than for <tt>HashMap</tt>, as iteration times for this class are unaffected
+ * by capacity.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked hash map concurrently, and at least
+ * one of the threads modifies the map structurally, it <em>must</em> be
+ * synchronized externally.  This is typically accomplished by
+ * synchronizing on some object that naturally encapsulates the map.
+ *
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map:<pre>
+ *   Map m = Collections.synchronizedMap(new LinkedHashMap(...));</pre>
+ *
+ * A structural modification is any operation that adds or deletes one or more
+ * mappings or, in the case of access-ordered linked hash maps, affects
+ * iteration order.  In insertion-ordered linked hash maps, merely changing
+ * the value associated with a key that is already contained in the map is not
+ * a structural modification.  <strong>In access-ordered linked hash maps,
+ * merely querying the map with <tt>get</tt> is a structural modification.
+ * </strong>)
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the collections
+ * returned by all of this class's collection view methods are
+ * <em>fail-fast</em>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are
+ * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+ * <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
+ * <em>Note</em>: The implementation of these spliterators in Android Nougat
+ * (API levels 24 and 25) uses the wrong order (inconsistent with the
+ * iterators, which use the correct order), despite reporting
+ * {@link Spliterator#ORDERED}. You may use the following code fragments
+ * to obtain a correctly ordered Spliterator on API level 24 and 25:
+ * <ul>
+ *     <li>For a Collection view {@code c = lhm.keySet()},
+ *         {@code c = lhm.entrySet()} or {@code c = lhm.values()}, use
+ *         {@code java.util.Spliterators.spliterator(c, c.spliterator().characteristics())}
+ *         instead of {@code c.spliterator()}.
+ *     <li>Instead of {@code c.stream()} or {@code c.parallelStream()}, use
+ *         {@code java.util.stream.StreamSupport.stream(spliterator, false)}
+ *         to construct a (nonparallel) {@link java.util.stream.Stream} from
+ *         such a {@code Spliterator}.
+ * </ul>
+ * Note that these workarounds are only suggested where {@code lhm} is a
+ * {@code LinkedHashMap}.
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @implNote
+ * The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are created from
+ * the iterators of the corresponding collections.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Map
+ * @see     HashMap
+ * @see     TreeMap
+ * @see     Hashtable
+ * @since   1.4
+ */
+public class LinkedHashMap<K,V>
+    extends HashMap<K,V>
+    implements Map<K,V>
+{
+
+    /*
+     * Implementation note.  A previous version of this class was
+     * internally structured a little differently. Because superclass
+     * HashMap now uses trees for some of its nodes, class
+     * LinkedHashMap.Entry is now treated as intermediary node class
+     * that can also be converted to tree form.
+     *
+     // BEGIN Android-changed
+     * LinkedHashMapEntry should not be renamed. Specifically, for
+     * source compatibility with earlier versions of Android, this
+     * nested class must not be named "Entry". Otherwise, it would
+     * hide Map.Entry which would break compilation of code like:
+     *
+     * LinkedHashMap.Entry<K, V> entry = map.entrySet().iterator.next()
+     *
+     * To compile, that code snippet's "LinkedHashMap.Entry" must
+     * mean java.util.Map.Entry which is the compile time type of
+     * entrySet()'s elements.
+     // END Android-changed
+     *
+     * The changes in node classes also require using two fields
+     * (head, tail) rather than a pointer to a header node to maintain
+     * the doubly-linked before/after list. This class also
+     * previously used a different style of callback methods upon
+     * access, insertion, and removal.
+     */
+
+    /**
+     * HashMap.Node subclass for normal LinkedHashMap entries.
+     */
+    static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
+        LinkedHashMapEntry<K,V> before, after;
+        LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
+            super(hash, key, value, next);
+        }
+    }
+
+    private static final long serialVersionUID = 3801124242820219131L;
+
+    /**
+     * The head (eldest) of the doubly linked list.
+     */
+    transient LinkedHashMapEntry<K,V> head;
+
+    /**
+     * The tail (youngest) of the doubly linked list.
+     */
+    transient LinkedHashMapEntry<K,V> tail;
+
+    /**
+     * The iteration ordering method for this linked hash map: <tt>true</tt>
+     * for access-order, <tt>false</tt> for insertion-order.
+     *
+     * @serial
+     */
+    final boolean accessOrder;
+
+    // internal utilities
+
+    // link at the end of list
+    private void linkNodeLast(LinkedHashMapEntry<K,V> p) {
+        LinkedHashMapEntry<K,V> last = tail;
+        tail = p;
+        if (last == null)
+            head = p;
+        else {
+            p.before = last;
+            last.after = p;
+        }
+    }
+
+    // apply src's links to dst
+    private void transferLinks(LinkedHashMapEntry<K,V> src,
+                               LinkedHashMapEntry<K,V> dst) {
+        LinkedHashMapEntry<K,V> b = dst.before = src.before;
+        LinkedHashMapEntry<K,V> a = dst.after = src.after;
+        if (b == null)
+            head = dst;
+        else
+            b.after = dst;
+        if (a == null)
+            tail = dst;
+        else
+            a.before = dst;
+    }
+
+    // overrides of HashMap hook methods
+
+    void reinitialize() {
+        super.reinitialize();
+        head = tail = null;
+    }
+
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
+        LinkedHashMapEntry<K,V> p =
+            new LinkedHashMapEntry<K,V>(hash, key, value, e);
+        linkNodeLast(p);
+        return p;
+    }
+
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMapEntry<K,V> q = (LinkedHashMapEntry<K,V>)p;
+        LinkedHashMapEntry<K,V> t =
+            new LinkedHashMapEntry<K,V>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
+        linkNodeLast(p);
+        return p;
+    }
+
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMapEntry<K,V> q = (LinkedHashMapEntry<K,V>)p;
+        TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    void afterNodeRemoval(Node<K,V> e) { // unlink
+        LinkedHashMapEntry<K,V> p =
+            (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
+        p.before = p.after = null;
+        if (b == null)
+            head = a;
+        else
+            b.after = a;
+        if (a == null)
+            tail = b;
+        else
+            a.before = b;
+    }
+
+    void afterNodeInsertion(boolean evict) { // possibly remove eldest
+        LinkedHashMapEntry<K,V> first;
+        if (evict && (first = head) != null && removeEldestEntry(first)) {
+            K key = first.key;
+            removeNode(hash(key), key, null, false, true);
+        }
+    }
+
+    void afterNodeAccess(Node<K,V> e) { // move node to last
+        LinkedHashMapEntry<K,V> last;
+        if (accessOrder && (last = tail) != e) {
+            LinkedHashMapEntry<K,V> p =
+                (LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
+            p.after = null;
+            if (b == null)
+                head = a;
+            else
+                b.after = a;
+            if (a != null)
+                a.before = b;
+            else
+                last = b;
+            if (last == null)
+                head = p;
+            else {
+                p.before = last;
+                last.after = p;
+            }
+            tail = p;
+            ++modCount;
+        }
+    }
+
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        for (LinkedHashMapEntry<K,V> e = head; e != null; e = e.after) {
+            s.writeObject(e.key);
+            s.writeObject(e.value);
+        }
+    }
+
+    /**
+     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
+     * with the specified initial capacity and load factor.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public LinkedHashMap(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor);
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
+     * with the specified initial capacity and a default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public LinkedHashMap(int initialCapacity) {
+        super(initialCapacity);
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
+     * with the default initial capacity (16) and load factor (0.75).
+     */
+    public LinkedHashMap() {
+        super();
+        accessOrder = false;
+    }
+
+    /**
+     * Constructs an insertion-ordered <tt>LinkedHashMap</tt> instance with
+     * the same mappings as the specified map.  The <tt>LinkedHashMap</tt>
+     * instance is created with a default load factor (0.75) and an initial
+     * capacity sufficient to hold the mappings in the specified map.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public LinkedHashMap(Map<? extends K, ? extends V> m) {
+        super();
+        accessOrder = false;
+        putMapEntries(m, false);
+    }
+
+    /**
+     * Constructs an empty <tt>LinkedHashMap</tt> instance with the
+     * specified initial capacity, load factor and ordering mode.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @param  accessOrder     the ordering mode - <tt>true</tt> for
+     *         access-order, <tt>false</tt> for insertion-order
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public LinkedHashMap(int initialCapacity,
+                         float loadFactor,
+                         boolean accessOrder) {
+        super(initialCapacity, loadFactor);
+        this.accessOrder = accessOrder;
+    }
+
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value
+     */
+    public boolean containsValue(Object value) {
+        for (LinkedHashMapEntry<K,V> e = head; e != null; e = e.after) {
+            V v = e.value;
+            if (v == value || (value != null && value.equals(v)))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     */
+    public V get(Object key) {
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) == null)
+            return null;
+        if (accessOrder)
+            afterNodeAccess(e);
+        return e.value;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+       Node<K,V> e;
+       if ((e = getNode(hash(key), key)) == null)
+           return defaultValue;
+       if (accessOrder)
+           afterNodeAccess(e);
+       return e.value;
+   }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void clear() {
+        super.clear();
+        head = tail = null;
+    }
+
+    // Android-added: eldest(), for internal use in LRU caches
+    /**
+     * Returns the eldest entry in the map, or {@code null} if the map is empty.
+     * @hide
+     */
+    public Map.Entry<K, V> eldest() {
+        return head;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map should remove its eldest entry.
+     * This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
+     * inserting a new entry into the map.  It provides the implementor
+     * with the opportunity to remove the eldest entry each time a new one
+     * is added.  This is useful if the map represents a cache: it allows
+     * the map to reduce memory consumption by deleting stale entries.
+     *
+     * <p>Sample use: this override will allow the map to grow up to 100
+     * entries and then delete the eldest entry each time a new entry is
+     * added, maintaining a steady state of 100 entries.
+     * <pre>
+     *     private static final int MAX_ENTRIES = 100;
+     *
+     *     protected boolean removeEldestEntry(Map.Entry eldest) {
+     *        return size() &gt; MAX_ENTRIES;
+     *     }
+     * </pre>
+     *
+     * <p>This method typically does not modify the map in any way,
+     * instead allowing the map to modify itself as directed by its
+     * return value.  It <i>is</i> permitted for this method to modify
+     * the map directly, but if it does so, it <i>must</i> return
+     * <tt>false</tt> (indicating that the map should not attempt any
+     * further modification).  The effects of returning <tt>true</tt>
+     * after modifying the map from within this method are unspecified.
+     *
+     * <p>This implementation merely returns <tt>false</tt> (so that this
+     * map acts like a normal map - the eldest element is never removed).
+     *
+     * @param    eldest The least recently inserted entry in the map, or if
+     *           this is an access-ordered map, the least recently accessed
+     *           entry.  This is the entry that will be removed it this
+     *           method returns <tt>true</tt>.  If the map was empty prior
+     *           to the <tt>put</tt> or <tt>putAll</tt> invocation resulting
+     *           in this invocation, this will be the entry that was just
+     *           inserted; in other words, if the map contains a single
+     *           entry, the eldest entry is also the newest.
+     * @return   <tt>true</tt> if the eldest entry should be removed
+     *           from the map; <tt>false</tt> if it should be retained.
+     */
+    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
+        return false;
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new LinkedKeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    final class LinkedKeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<K> iterator() {
+            return new LinkedKeyIterator();
+        }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator()  {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (LinkedHashMapEntry<K,V> e = head; (e != null && modCount == mc); e = e.after)
+                action.accept(e.key);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new LinkedValues();
+            values = vs;
+        }
+        return vs;
+    }
+
+    final class LinkedValues extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<V> iterator() {
+            return new LinkedValueIterator();
+        }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED);
+        }
+        public final void forEach(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (LinkedHashMapEntry<K,V> e = head; (e != null && modCount == mc); e = e.after)
+                action.accept(e.value);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
+    }
+
+    final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new LinkedEntryIterator();
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            // Android-changed: Detect changes to modCount early.
+            for (LinkedHashMapEntry<K,V> e = head; (e != null && mc == modCount); e = e.after)
+                action.accept(e);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    // Map overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android-changed: Detect changes to modCount early.
+        for (LinkedHashMapEntry<K,V> e = head; modCount == mc && e != null; e = e.after)
+            action.accept(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        // Android-changed: Detect changes to modCount early.
+        for (LinkedHashMapEntry<K,V> e = head; modCount == mc && e != null; e = e.after)
+            e.value = function.apply(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    // Iterators
+
+    abstract class LinkedHashIterator {
+        LinkedHashMapEntry<K,V> next;
+        LinkedHashMapEntry<K,V> current;
+        int expectedModCount;
+
+        LinkedHashIterator() {
+            next = head;
+            expectedModCount = modCount;
+            current = null;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final LinkedHashMapEntry<K,V> nextNode() {
+            LinkedHashMapEntry<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            current = e;
+            next = e.after;
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            K key = p.key;
+            removeNode(hash(key), key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class LinkedKeyIterator extends LinkedHashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().getKey(); }
+    }
+
+    final class LinkedValueIterator extends LinkedHashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class LinkedEntryIterator extends LinkedHashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+
+}
diff --git a/java/util/LinkedHashSet.java b/java/util/LinkedHashSet.java
new file mode 100644
index 0000000..08606cf
--- /dev/null
+++ b/java/util/LinkedHashSet.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>Hash table and linked list implementation of the <tt>Set</tt> interface,
+ * with predictable iteration order.  This implementation differs from
+ * <tt>HashSet</tt> in that it maintains a doubly-linked list running through
+ * all of its entries.  This linked list defines the iteration ordering,
+ * which is the order in which elements were inserted into the set
+ * (<i>insertion-order</i>).  Note that insertion order is <i>not</i> affected
+ * if an element is <i>re-inserted</i> into the set.  (An element <tt>e</tt>
+ * is reinserted into a set <tt>s</tt> if <tt>s.add(e)</tt> is invoked when
+ * <tt>s.contains(e)</tt> would return <tt>true</tt> immediately prior to
+ * the invocation.)
+ *
+ * <p>This implementation spares its clients from the unspecified, generally
+ * chaotic ordering provided by {@link HashSet}, without incurring the
+ * increased cost associated with {@link TreeSet}.  It can be used to
+ * produce a copy of a set that has the same order as the original, regardless
+ * of the original set's implementation:
+ * <pre>
+ *     void foo(Set s) {
+ *         Set copy = new LinkedHashSet(s);
+ *         ...
+ *     }
+ * </pre>
+ * This technique is particularly useful if a module takes a set on input,
+ * copies it, and later returns results whose order is determined by that of
+ * the copy.  (Clients generally appreciate having things returned in the same
+ * order they were presented.)
+ *
+ * <p>This class provides all of the optional <tt>Set</tt> operations, and
+ * permits null elements.  Like <tt>HashSet</tt>, it provides constant-time
+ * performance for the basic operations (<tt>add</tt>, <tt>contains</tt> and
+ * <tt>remove</tt>), assuming the hash function disperses elements
+ * properly among the buckets.  Performance is likely to be just slightly
+ * below that of <tt>HashSet</tt>, due to the added expense of maintaining the
+ * linked list, with one exception: Iteration over a <tt>LinkedHashSet</tt>
+ * requires time proportional to the <i>size</i> of the set, regardless of
+ * its capacity.  Iteration over a <tt>HashSet</tt> is likely to be more
+ * expensive, requiring time proportional to its <i>capacity</i>.
+ *
+ * <p>A linked hash set has two parameters that affect its performance:
+ * <i>initial capacity</i> and <i>load factor</i>.  They are defined precisely
+ * as for <tt>HashSet</tt>.  Note, however, that the penalty for choosing an
+ * excessively high value for initial capacity is less severe for this class
+ * than for <tt>HashSet</tt>, as iteration times for this class are unaffected
+ * by capacity.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked hash set concurrently, and at least
+ * one of the threads modifies the set, it <em>must</em> be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the set.
+ *
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSet Collections.synchronizedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set: <pre>
+ *   Set s = Collections.synchronizedSet(new LinkedHashSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's <tt>iterator</tt> method are
+ * <em>fail-fast</em>: if the set is modified at any time after the iterator
+ * is created, in any way except through the iterator's own <tt>remove</tt>
+ * method, the iterator will throw a {@link ConcurrentModificationException}.
+ * Thus, in the face of concurrent modification, the iterator fails quickly
+ * and cleanly, rather than risking arbitrary, non-deterministic behavior at
+ * an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see     Object#hashCode()
+ * @see     Collection
+ * @see     Set
+ * @see     HashSet
+ * @see     TreeSet
+ * @see     Hashtable
+ * @since   1.4
+ */
+
+public class LinkedHashSet<E>
+    extends HashSet<E>
+    implements Set<E>, Cloneable, java.io.Serializable {
+
+    private static final long serialVersionUID = -2851667679971038690L;
+
+    /**
+     * Constructs a new, empty linked hash set with the specified initial
+     * capacity and load factor.
+     *
+     * @param      initialCapacity the initial capacity of the linked hash set
+     * @param      loadFactor      the load factor of the linked hash set
+     * @throws     IllegalArgumentException  if the initial capacity is less
+     *               than zero, or if the load factor is nonpositive
+     */
+    public LinkedHashSet(int initialCapacity, float loadFactor) {
+        super(initialCapacity, loadFactor, true);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param   initialCapacity   the initial capacity of the LinkedHashSet
+     * @throws  IllegalArgumentException if the initial capacity is less
+     *              than zero
+     */
+    public LinkedHashSet(int initialCapacity) {
+        super(initialCapacity, .75f, true);
+    }
+
+    /**
+     * Constructs a new, empty linked hash set with the default initial
+     * capacity (16) and load factor (0.75).
+     */
+    public LinkedHashSet() {
+        super(16, .75f, true);
+    }
+
+    /**
+     * Constructs a new linked hash set with the same elements as the
+     * specified collection.  The linked hash set is created with an initial
+     * capacity sufficient to hold the elements in the specified collection
+     * and the default load factor (0.75).
+     *
+     * @param c  the collection whose elements are to be placed into
+     *           this set
+     * @throws NullPointerException if the specified collection is null
+     */
+    public LinkedHashSet(Collection<? extends E> c) {
+        super(Math.max(2*c.size(), 11), .75f, true);
+        addAll(c);
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, and {@code ORDERED}.  Implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
+    }
+}
diff --git a/java/util/LinkedList.annotated.java b/java/util/LinkedList.annotated.java
new file mode 100644
index 0000000..f85afd1
--- /dev/null
+++ b/java/util/LinkedList.annotated.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class LinkedList<E> extends java.util.AbstractSequentialList<E> implements java.util.List<E>, java.util.Deque<E>, java.lang.Cloneable, java.io.Serializable {
+
+public LinkedList() { throw new RuntimeException("Stub!"); }
+
+public LinkedList(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public E getFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E getLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E removeLast() { throw new RuntimeException("Stub!"); }
+
+public void addFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void addLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public E peek() { throw new RuntimeException("Stub!"); }
+
[email protected] public E element() { throw new RuntimeException("Stub!"); }
+
[email protected] public E poll() { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove() { throw new RuntimeException("Stub!"); }
+
+public boolean offer(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerFirst(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean offerLast(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E peekLast() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollFirst() { throw new RuntimeException("Stub!"); }
+
[email protected] public E pollLast() { throw new RuntimeException("Stub!"); }
+
+public void push(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
[email protected] public E pop() { throw new RuntimeException("Stub!"); }
+
+public boolean removeFirstOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean removeLastOccurrence(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> descendingIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/LinkedList.java b/java/util/LinkedList.java
new file mode 100644
index 0000000..60f4c41
--- /dev/null
+++ b/java/util/LinkedList.java
@@ -0,0 +1,1262 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * Doubly-linked list implementation of the {@code List} and {@code Deque}
+ * interfaces.  Implements all optional list operations, and permits all
+ * elements (including {@code null}).
+ *
+ * <p>All of the operations perform as could be expected for a doubly-linked
+ * list.  Operations that index into the list will traverse the list from
+ * the beginning or the end, whichever is closer to the specified index.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a linked list concurrently, and at least
+ * one of the threads modifies the list structurally, it <i>must</i> be
+ * synchronized externally.  (A structural modification is any operation
+ * that adds or deletes one or more elements; merely setting the value of
+ * an element is not a structural modification.)  This is typically
+ * accomplished by synchronizing on some object that naturally
+ * encapsulates the list.
+ *
+ * If no such object exists, the list should be "wrapped" using the
+ * {@link Collections#synchronizedList Collections.synchronizedList}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the list:<pre>
+ *   List list = Collections.synchronizedList(new LinkedList(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} and
+ * {@code listIterator} methods are <i>fail-fast</i>: if the list is
+ * structurally modified at any time after the iterator is created, in
+ * any way except through the Iterator's own {@code remove} or
+ * {@code add} methods, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than
+ * risking arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @see     List
+ * @see     ArrayList
+ * @since 1.2
+ * @param <E> the type of elements held in this collection
+ */
+
+public class LinkedList<E>
+    extends AbstractSequentialList<E>
+    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
+{
+    transient int size = 0;
+
+    /**
+     * Pointer to first node.
+     * Invariant: (first == null && last == null) ||
+     *            (first.prev == null && first.item != null)
+     */
+    transient Node<E> first;
+
+    /**
+     * Pointer to last node.
+     * Invariant: (first == null && last == null) ||
+     *            (last.next == null && last.item != null)
+     */
+    transient Node<E> last;
+
+    /**
+     * Constructs an empty list.
+     */
+    public LinkedList() {
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param  c the collection whose elements are to be placed into this list
+     * @throws NullPointerException if the specified collection is null
+     */
+    public LinkedList(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> f = first;
+        final Node<E> newNode = new Node<>(null, e, f);
+        first = newNode;
+        if (f == null)
+            last = newNode;
+        else
+            f.prev = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Links e as last element.
+     */
+    void linkLast(E e) {
+        final Node<E> l = last;
+        final Node<E> newNode = new Node<>(l, e, null);
+        last = newNode;
+        if (l == null)
+            first = newNode;
+        else
+            l.next = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Inserts element e before non-null Node succ.
+     */
+    void linkBefore(E e, Node<E> succ) {
+        // assert succ != null;
+        final Node<E> pred = succ.prev;
+        final Node<E> newNode = new Node<>(pred, e, succ);
+        succ.prev = newNode;
+        if (pred == null)
+            first = newNode;
+        else
+            pred.next = newNode;
+        size++;
+        modCount++;
+    }
+
+    /**
+     * Unlinks non-null first node f.
+     */
+    private E unlinkFirst(Node<E> f) {
+        // assert f == first && f != null;
+        final E element = f.item;
+        final Node<E> next = f.next;
+        f.item = null;
+        f.next = null; // help GC
+        first = next;
+        if (next == null)
+            last = null;
+        else
+            next.prev = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Unlinks non-null last node l.
+     */
+    private E unlinkLast(Node<E> l) {
+        // assert l == last && l != null;
+        final E element = l.item;
+        final Node<E> prev = l.prev;
+        l.item = null;
+        l.prev = null; // help GC
+        last = prev;
+        if (prev == null)
+            first = null;
+        else
+            prev.next = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Unlinks non-null node x.
+     */
+    E unlink(Node<E> x) {
+        // assert x != null;
+        final E element = x.item;
+        final Node<E> next = x.next;
+        final Node<E> prev = x.prev;
+
+        if (prev == null) {
+            first = next;
+        } else {
+            prev.next = next;
+            x.prev = null;
+        }
+
+        if (next == null) {
+            last = prev;
+        } else {
+            next.prev = prev;
+            x.next = null;
+        }
+
+        x.item = null;
+        size--;
+        modCount++;
+        return element;
+    }
+
+    /**
+     * Returns the first element in this list.
+     *
+     * @return the first element in this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E getFirst() {
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return f.item;
+    }
+
+    /**
+     * Returns the last element in this list.
+     *
+     * @return the last element in this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E getLast() {
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return l.item;
+    }
+
+    /**
+     * Removes and returns the first element from this list.
+     *
+     * @return the first element from this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E removeFirst() {
+        final Node<E> f = first;
+        if (f == null)
+            throw new NoSuchElementException();
+        return unlinkFirst(f);
+    }
+
+    /**
+     * Removes and returns the last element from this list.
+     *
+     * @return the last element from this list
+     * @throws NoSuchElementException if this list is empty
+     */
+    public E removeLast() {
+        final Node<E> l = last;
+        if (l == null)
+            throw new NoSuchElementException();
+        return unlinkLast(l);
+    }
+
+    /**
+     * Inserts the specified element at the beginning of this list.
+     *
+     * @param e the element to add
+     */
+    public void addFirst(E e) {
+        linkFirst(e);
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @param e the element to add
+     */
+    public void addLast(E e) {
+        linkLast(e);
+    }
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) != -1;
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        linkLast(e);
+        return true;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If this list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * {@code i} such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list
+     * changed as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        } else {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item)) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the specified
+     * collection's iterator.  The behavior of this operation is undefined if
+     * the specified collection is modified while the operation is in
+     * progress.  (Note that this will occur if the specified collection is
+     * this list, and it's nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        return addAll(size, c);
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in the list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param index index at which to insert the first element
+     *              from the specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        checkPositionIndex(index);
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        if (numNew == 0)
+            return false;
+
+        Node<E> pred, succ;
+        if (index == size) {
+            succ = null;
+            pred = last;
+        } else {
+            succ = node(index);
+            pred = succ.prev;
+        }
+
+        for (Object o : a) {
+            @SuppressWarnings("unchecked") E e = (E) o;
+            Node<E> newNode = new Node<>(pred, e, null);
+            if (pred == null)
+                first = newNode;
+            else
+                pred.next = newNode;
+            pred = newNode;
+        }
+
+        if (succ == null) {
+            last = pred;
+        } else {
+            pred.next = succ;
+            succ.prev = pred;
+        }
+
+        size += numNew;
+        modCount++;
+        return true;
+    }
+
+    /**
+     * Removes all of the elements from this list.
+     * The list will be empty after this call returns.
+     */
+    public void clear() {
+        // Clearing all of the links between nodes is "unnecessary", but:
+        // - helps a generational GC if the discarded nodes inhabit
+        //   more than one generation
+        // - is sure to free memory even if there is a reachable Iterator
+        for (Node<E> x = first; x != null; ) {
+            Node<E> next = x.next;
+            x.item = null;
+            x.next = null;
+            x.prev = null;
+            x = next;
+        }
+        first = last = null;
+        size = 0;
+        modCount++;
+    }
+
+
+    // Positional Access Operations
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        checkElementIndex(index);
+        return node(index).item;
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        checkElementIndex(index);
+        Node<E> x = node(index);
+        E oldVal = x.item;
+        x.item = element;
+        return oldVal;
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this list.
+     * Shifts the element currently at that position (if any) and any
+     * subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        checkPositionIndex(index);
+
+        if (index == size)
+            linkLast(element);
+        else
+            linkBefore(element, node(index));
+    }
+
+    /**
+     * Removes the element at the specified position in this list.  Shifts any
+     * subsequent elements to the left (subtracts one from their indices).
+     * Returns the element that was removed from the list.
+     *
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        checkElementIndex(index);
+        return unlink(node(index));
+    }
+
+    /**
+     * Tells if the argument is the index of an existing element.
+     */
+    private boolean isElementIndex(int index) {
+        return index >= 0 && index < size;
+    }
+
+    /**
+     * Tells if the argument is the index of a valid position for an
+     * iterator or an add operation.
+     */
+    private boolean isPositionIndex(int index) {
+        return index >= 0 && index <= size;
+    }
+
+    /**
+     * Constructs an IndexOutOfBoundsException detail message.
+     * Of the many possible refactorings of the error handling code,
+     * this "outlining" performs best with both server and client VMs.
+     */
+    private String outOfBoundsMsg(int index) {
+        return "Index: "+index+", Size: "+size;
+    }
+
+    private void checkElementIndex(int index) {
+        if (!isElementIndex(index))
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    private void checkPositionIndex(int index) {
+        if (!isPositionIndex(index))
+            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
+    }
+
+    /**
+     * Returns the (non-null) Node at the specified element index.
+     */
+    Node<E> node(int index) {
+        // assert isElementIndex(index);
+
+        if (index < (size >> 1)) {
+            Node<E> x = first;
+            for (int i = 0; i < index; i++)
+                x = x.next;
+            return x;
+        } else {
+            Node<E> x = last;
+            for (int i = size - 1; i > index; i--)
+                x = x.prev;
+            return x;
+        }
+    }
+
+    // Search Operations
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     */
+    public int indexOf(Object o) {
+        int index = 0;
+        if (o == null) {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (x.item == null)
+                    return index;
+                index++;
+            }
+        } else {
+            for (Node<E> x = first; x != null; x = x.next) {
+                if (o.equals(x.item))
+                    return index;
+                index++;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     */
+    public int lastIndexOf(Object o) {
+        int index = size;
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                index--;
+                if (x.item == null)
+                    return index;
+            }
+        } else {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                index--;
+                if (o.equals(x.item))
+                    return index;
+            }
+        }
+        return -1;
+    }
+
+    // Queue operations.
+
+    /**
+     * Retrieves, but does not remove, the head (first element) of this list.
+     *
+     * @return the head of this list, or {@code null} if this list is empty
+     * @since 1.5
+     */
+    public E peek() {
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
+    }
+
+    /**
+     * Retrieves, but does not remove, the head (first element) of this list.
+     *
+     * @return the head of this list
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.5
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    /**
+     * Retrieves and removes the head (first element) of this list.
+     *
+     * @return the head of this list, or {@code null} if this list is empty
+     * @since 1.5
+     */
+    public E poll() {
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
+    }
+
+    /**
+     * Retrieves and removes the head (first element) of this list.
+     *
+     * @return the head of this list
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.5
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    /**
+     * Adds the specified element as the tail (last element) of this list.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @since 1.5
+     */
+    public boolean offer(E e) {
+        return add(e);
+    }
+
+    // Deque operations
+    /**
+     * Inserts the specified element at the front of this list.
+     *
+     * @param e the element to insert
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @since 1.6
+     */
+    public boolean offerFirst(E e) {
+        addFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this list.
+     *
+     * @param e the element to insert
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @since 1.6
+     */
+    public boolean offerLast(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * Retrieves, but does not remove, the first element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the first element of this list, or {@code null}
+     *         if this list is empty
+     * @since 1.6
+     */
+    public E peekFirst() {
+        final Node<E> f = first;
+        return (f == null) ? null : f.item;
+     }
+
+    /**
+     * Retrieves, but does not remove, the last element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the last element of this list, or {@code null}
+     *         if this list is empty
+     * @since 1.6
+     */
+    public E peekLast() {
+        final Node<E> l = last;
+        return (l == null) ? null : l.item;
+    }
+
+    /**
+     * Retrieves and removes the first element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the first element of this list, or {@code null} if
+     *     this list is empty
+     * @since 1.6
+     */
+    public E pollFirst() {
+        final Node<E> f = first;
+        return (f == null) ? null : unlinkFirst(f);
+    }
+
+    /**
+     * Retrieves and removes the last element of this list,
+     * or returns {@code null} if this list is empty.
+     *
+     * @return the last element of this list, or {@code null} if
+     *     this list is empty
+     * @since 1.6
+     */
+    public E pollLast() {
+        final Node<E> l = last;
+        return (l == null) ? null : unlinkLast(l);
+    }
+
+    /**
+     * Pushes an element onto the stack represented by this list.  In other
+     * words, inserts the element at the front of this list.
+     *
+     * <p>This method is equivalent to {@link #addFirst}.
+     *
+     * @param e the element to push
+     * @since 1.6
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * Pops an element from the stack represented by this list.  In other
+     * words, removes and returns the first element of this list.
+     *
+     * <p>This method is equivalent to {@link #removeFirst()}.
+     *
+     * @return the element at the front of this list (which is the top
+     *         of the stack represented by this list)
+     * @throws NoSuchElementException if this list is empty
+     * @since 1.6
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this
+     * list (when traversing the list from head to tail).  If the list
+     * does not contain the element, it is unchanged.
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if the list contained the specified element
+     * @since 1.6
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        return remove(o);
+    }
+
+    /**
+     * Removes the last occurrence of the specified element in this
+     * list (when traversing the list from head to tail).  If the list
+     * does not contain the element, it is unchanged.
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if the list contained the specified element
+     * @since 1.6
+     */
+    public boolean removeLastOccurrence(Object o) {
+        if (o == null) {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (x.item == null) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        } else {
+            for (Node<E> x = last; x != null; x = x.prev) {
+                if (o.equals(x.item)) {
+                    unlink(x);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a list-iterator of the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * Obeys the general contract of {@code List.listIterator(int)}.<p>
+     *
+     * The list-iterator is <i>fail-fast</i>: if the list is structurally
+     * modified at any time after the Iterator is created, in any way except
+     * through the list-iterator's own {@code remove} or {@code add}
+     * methods, the list-iterator will throw a
+     * {@code ConcurrentModificationException}.  Thus, in the face of
+     * concurrent modification, the iterator fails quickly and cleanly, rather
+     * than risking arbitrary, non-deterministic behavior at an undetermined
+     * time in the future.
+     *
+     * @param index index of the first element to be returned from the
+     *              list-iterator (by a call to {@code next})
+     * @return a ListIterator of the elements in this list (in proper
+     *         sequence), starting at the specified position in the list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @see List#listIterator(int)
+     */
+    public ListIterator<E> listIterator(int index) {
+        checkPositionIndex(index);
+        return new ListItr(index);
+    }
+
+    private class ListItr implements ListIterator<E> {
+        private Node<E> lastReturned;
+        private Node<E> next;
+        private int nextIndex;
+        private int expectedModCount = modCount;
+
+        ListItr(int index) {
+            // assert isPositionIndex(index);
+            next = (index == size) ? null : node(index);
+            nextIndex = index;
+        }
+
+        public boolean hasNext() {
+            return nextIndex < size;
+        }
+
+        public E next() {
+            checkForComodification();
+            if (!hasNext())
+                throw new NoSuchElementException();
+
+            lastReturned = next;
+            next = next.next;
+            nextIndex++;
+            return lastReturned.item;
+        }
+
+        public boolean hasPrevious() {
+            return nextIndex > 0;
+        }
+
+        public E previous() {
+            checkForComodification();
+            if (!hasPrevious())
+                throw new NoSuchElementException();
+
+            lastReturned = next = (next == null) ? last : next.prev;
+            nextIndex--;
+            return lastReturned.item;
+        }
+
+        public int nextIndex() {
+            return nextIndex;
+        }
+
+        public int previousIndex() {
+            return nextIndex - 1;
+        }
+
+        public void remove() {
+            checkForComodification();
+            if (lastReturned == null)
+                throw new IllegalStateException();
+
+            Node<E> lastNext = lastReturned.next;
+            unlink(lastReturned);
+            if (next == lastReturned)
+                next = lastNext;
+            else
+                nextIndex--;
+            lastReturned = null;
+            expectedModCount++;
+        }
+
+        public void set(E e) {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            checkForComodification();
+            lastReturned.item = e;
+        }
+
+        public void add(E e) {
+            checkForComodification();
+            lastReturned = null;
+            if (next == null)
+                linkLast(e);
+            else
+                linkBefore(e, next);
+            nextIndex++;
+            expectedModCount++;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            while (modCount == expectedModCount && nextIndex < size) {
+                action.accept(next.item);
+                lastReturned = next;
+                next = next.next;
+                nextIndex++;
+            }
+            checkForComodification();
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    private static class Node<E> {
+        E item;
+        Node<E> next;
+        Node<E> prev;
+
+        Node(Node<E> prev, E element, Node<E> next) {
+            this.item = element;
+            this.next = next;
+            this.prev = prev;
+        }
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingIterator();
+    }
+
+    /**
+     * Adapter to provide descending iterators via ListItr.previous
+     */
+    private class DescendingIterator implements Iterator<E> {
+        private final ListItr itr = new ListItr(size());
+        public boolean hasNext() {
+            return itr.hasPrevious();
+        }
+        public E next() {
+            return itr.previous();
+        }
+        public void remove() {
+            itr.remove();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private LinkedList<E> superClone() {
+        try {
+            return (LinkedList<E>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this {@code LinkedList}. (The elements
+     * themselves are not cloned.)
+     *
+     * @return a shallow copy of this {@code LinkedList} instance
+     */
+    public Object clone() {
+        LinkedList<E> clone = superClone();
+
+        // Put clone into "virgin" state
+        clone.first = clone.last = null;
+        clone.size = 0;
+        clone.modCount = 0;
+
+        // Initialize clone with our elements
+        for (Node<E> x = first; x != null; x = x.next)
+            clone.add(x.item);
+
+        return clone;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list
+     *         in proper sequence
+     */
+    public Object[] toArray() {
+        Object[] result = new Object[size];
+        int i = 0;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
+        return result;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If the list fits in the specified array with room to spare (i.e.,
+     * the array has more elements than the list), the element in the array
+     * immediately following the end of the list is set to {@code null}.
+     * (This is useful in determining the length of the list <i>only</i> if
+     * the caller knows that the list does not contain any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a list known to contain only strings.
+     * The following code can be used to dump the list into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a.length < size)
+            a = (T[])java.lang.reflect.Array.newInstance(
+                                a.getClass().getComponentType(), size);
+        int i = 0;
+        Object[] result = a;
+        for (Node<E> x = first; x != null; x = x.next)
+            result[i++] = x.item;
+
+        if (a.length > size)
+            a[size] = null;
+
+        return a;
+    }
+
+    private static final long serialVersionUID = 876323262645176354L;
+
+    /**
+     * Saves the state of this {@code LinkedList} instance to a stream
+     * (that is, serializes it).
+     *
+     * @serialData The size of the list (the number of elements it
+     *             contains) is emitted (int), followed by all of its
+     *             elements (each an Object) in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden serialization magic
+        s.defaultWriteObject();
+
+        // Write out size
+        s.writeInt(size);
+
+        // Write out all elements in the proper order.
+        for (Node<E> x = first; x != null; x = x.next)
+            s.writeObject(x.item);
+    }
+
+    /**
+     * Reconstitutes this {@code LinkedList} instance from a stream
+     * (that is, deserializes it).
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden serialization magic
+        s.defaultReadObject();
+
+        // Read in size
+        int size = s.readInt();
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < size; i++)
+            linkLast((E)s.readObject());
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}
+     * and implements {@code trySplit} to permit limited parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new LLSpliterator<E>(this, -1, 0);
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LLSpliterator<E> implements Spliterator<E> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedList<E> list; // null OK unless traversed
+        Node<E> current;      // current node; null until initialized
+        int est;              // size estimate; -1 until first needed
+        int expectedModCount; // initialized when est set
+        int batch;            // batch size for splits
+
+        LLSpliterator(LinkedList<E> list, int est, int expectedModCount) {
+            this.list = list;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getEst() {
+            int s; // force initialization
+            final LinkedList<E> lst;
+            if ((s = est) < 0) {
+                if ((lst = list) == null)
+                    s = est = 0;
+                else {
+                    expectedModCount = lst.modCount;
+                    current = lst.first;
+                    s = est = lst.size;
+                }
+            }
+            return s;
+        }
+
+        public long estimateSize() { return (long) getEst(); }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            int s = getEst();
+            if (s > 1 && (p = current) != null) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
+                current = p;
+                batch = j;
+                est = s - j;
+                return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p; int n;
+            if (action == null) throw new NullPointerException();
+            if ((n = getEst()) > 0 && (p = current) != null) {
+                current = null;
+                est = 0;
+                do {
+                    E e = p.item;
+                    p = p.next;
+                    action.accept(e);
+                } while (p != null && --n > 0);
+            }
+            if (list.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            if (getEst() > 0 && (p = current) != null) {
+                --est;
+                E e = p.item;
+                current = p.next;
+                action.accept(e);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+}
diff --git a/java/util/List.annotated.java b/java/util/List.annotated.java
new file mode 100644
index 0000000..2ef4a6f
--- /dev/null
+++ b/java/util/List.annotated.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface List<E> extends java.util.Collection<E> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public [email protected] Object @libcore.util.NonNull [] toArray();
+
+// TODO: Make param and return types @Nullable T @NonNull [] once metalava supports TYPE_USE.
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public default void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public default void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void clear();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public E get(int index);
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element);
+
+public void add(int index, @libcore.util.NullFromTypeParam E element);
+
[email protected] public E remove(int index);
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o);
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator();
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index);
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex);
+
[email protected] public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <E> java.util.List<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/List.java b/java/util/List.java
new file mode 100644
index 0000000..1b9deb3
--- /dev/null
+++ b/java/util/List.java
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.UnaryOperator;
+
+// Android-removed: removed link to collections framework docs
+/**
+ * An ordered collection (also known as a <i>sequence</i>).  The user of this
+ * interface has precise control over where in the list each element is
+ * inserted.  The user can access elements by their integer index (position in
+ * the list), and search for elements in the list.<p>
+ *
+ * Unlike sets, lists typically allow duplicate elements.  More formally,
+ * lists typically allow pairs of elements {@code e1} and {@code e2}
+ * such that {@code e1.equals(e2)}, and they typically allow multiple
+ * null elements if they allow null elements at all.  It is not inconceivable
+ * that someone might wish to implement a list that prohibits duplicates, by
+ * throwing runtime exceptions when the user attempts to insert them, but we
+ * expect this usage to be rare.<p>
+ *
+ * The {@code List} interface places additional stipulations, beyond those
+ * specified in the {@code Collection} interface, on the contracts of the
+ * {@code iterator}, {@code add}, {@code remove}, {@code equals}, and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
+ * also included here for convenience.<p>
+ *
+ * The {@code List} interface provides four methods for positional (indexed)
+ * access to list elements.  Lists (like Java arrays) are zero based.  Note
+ * that these operations may execute in time proportional to the index value
+ * for some implementations (the {@code LinkedList} class, for
+ * example). Thus, iterating over the elements in a list is typically
+ * preferable to indexing through it if the caller does not know the
+ * implementation.<p>
+ *
+ * The {@code List} interface provides a special iterator, called a
+ * {@code ListIterator}, that allows element insertion and replacement, and
+ * bidirectional access in addition to the normal operations that the
+ * {@code Iterator} interface provides.  A method is provided to obtain a
+ * list iterator that starts at a specified position in the list.<p>
+ *
+ * The {@code List} interface provides two methods to search for a specified
+ * object.  From a performance standpoint, these methods should be used with
+ * caution.  In many implementations they will perform costly linear
+ * searches.<p>
+ *
+ * The {@code List} interface provides two methods to efficiently insert and
+ * remove multiple elements at an arbitrary point in the list.<p>
+ *
+ * Note: While it is permissible for lists to contain themselves as elements,
+ * extreme caution is advised: the {@code equals} and {@code hashCode}
+ * methods are no longer well defined on such a list.
+ *
+ * <p>Some list implementations have restrictions on the elements that
+ * they may contain.  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the list may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <h2><a id="immutable">Immutable List Static Factory Methods</a></h2>
+ * <p>The {@link List#of(Object...) List.of()} static factory methods
+ * provide a convenient way to create immutable lists. The {@code List}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added, removed,
+ * or replaced. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable,
+ * this may cause the List's contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>The order of elements in the list is the same as the order of the
+ * provided arguments, or of the elements in the provided array.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * @param <E> the type of elements in this list
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see Set
+ * @see ArrayList
+ * @see LinkedList
+ * @see Vector
+ * @see Arrays#asList(Object[])
+ * @see Collections#nCopies(int, Object)
+ * @see Collections#EMPTY_LIST
+ * @see AbstractList
+ * @see AbstractSequentialList
+ * @since 1.2
+ */
+
+public interface List<E> extends Collection<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this list.  If this list contains
+     * more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this list
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this list in proper
+     * sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must
+     * allocate a new array even if this list is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this list in proper
+     *         sequence
+     * @see Arrays#asList(Object[])
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If the list fits in the specified array with room to spare (i.e.,
+     * the array has more elements than the list), the element in the array
+     * immediately following the end of the list is set to {@code null}.
+     * (This is useful in determining the length of the list <i>only</i> if
+     * the caller knows that the list does not contain any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a list known to contain only strings.
+     * The following code can be used to dump the list into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre>{@code
+     *     String[] y = x.toArray(new String[0]);
+     * }</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of this list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+
+    // Modification Operations
+
+    /**
+     * Appends the specified element to the end of this list (optional
+     * operation).
+     *
+     * <p>Lists that support this operation may place limitations on what
+     * elements may be added to this list.  In particular, some
+     * lists will refuse to add null elements, and others will impose
+     * restrictions on the type of elements that may be added.  List
+     * classes should clearly specify in their documentation any restrictions
+     * on what elements may be added.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this list
+     */
+    boolean add(E e);
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present (optional operation).  If this list does not contain
+     * the element, it is unchanged.  More formally, removes the element with
+     * the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list changed
+     * as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this list
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Modification Operations
+
+    /**
+     * Returns {@code true} if this list contains all of the elements of the
+     * specified collection.
+     *
+     * @param  c collection to be checked for containment in this list
+     * @return {@code true} if this list contains all of the elements of the
+     *         specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         list
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this list, in the order that they are returned by the specified
+     * collection's iterator (optional operation).  The behavior of this
+     * operation is undefined if the specified collection is modified while
+     * the operation is in progress.  (Note that this will occur if the
+     * specified collection is this list, and it's nonempty.)
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list at the specified position (optional operation).  Shifts the
+     * element currently at that position (if any) and any subsequent
+     * elements to the right (increases their indices).  The new elements
+     * will appear in this list in the order that they are returned by the
+     * specified collection's iterator.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.  (Note that this will occur if the specified
+     * collection is this list, and it's nonempty.)
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of the specified
+     *         collection prevents it from being added to this list
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this list does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    boolean addAll(int index, Collection<? extends E> c);
+
+    /**
+     * Removes from this list all of its elements that are contained in the
+     * specified collection (optional operation).
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection (optional operation).  In other words, removes
+     * from this list all of its elements that are not contained in the
+     * specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Replaces each element of this list with the result of applying the
+     * operator to that element.  Errors or runtime exceptions thrown by
+     * the operator are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code list}:
+     * <pre>{@code
+     *     final ListIterator<E> li = list.listIterator();
+     *     while (li.hasNext()) {
+     *         li.set(operator.apply(li.next()));
+     *     }
+     * }</pre>
+     *
+     * If the list's list-iterator does not support the {@code set} operation
+     * then an {@code UnsupportedOperationException} will be thrown when
+     * replacing the first element.
+     *
+     * @param operator the operator to apply to each element
+     * @throws UnsupportedOperationException if this list is unmodifiable.
+     *         Implementations may throw this exception if an element
+     *         cannot be replaced or if, in general, modification is not
+     *         supported
+     * @throws NullPointerException if the specified operator is null or
+     *         if the operator result is a null value and this list does
+     *         not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final ListIterator<E> li = this.listIterator();
+        while (li.hasNext()) {
+            li.set(operator.apply(li.next()));
+        }
+    }
+
+    // Android-added: List.sort() vs. Collections.sort() app compat.
+    // Added a warning in the documentation.
+    // Collections.sort() calls List.sort() for apps targeting API version >= 26
+    // (Android Oreo) but the other way around for app targeting <= 25 (Nougat).
+    /**
+     * Sorts this list according to the order induced by the specified
+     * {@link Comparator}.
+     *
+     * <p>All elements in this list must be <i>mutually comparable</i> using the
+     * specified comparator (that is, {@code c.compare(e1, e2)} must not throw
+     * a {@code ClassCastException} for any elements {@code e1} and {@code e2}
+     * in the list).
+     *
+     * <p>If the specified comparator is {@code null} then all elements in this
+     * list must implement the {@link Comparable} interface and the elements'
+     * {@linkplain Comparable natural ordering} should be used.
+     *
+     * <p>This list must be modifiable, but need not be resizable.
+     *
+     * <p>For apps running on and targeting Android versions greater than
+     * Nougat (API level {@code > 25}), {@link Collections#sort(List)}
+     * delegates to this method. Such apps must not call
+     * {@link Collections#sort(List)} from this method. Instead, prefer
+     * not overriding this method at all. If you must override it, consider
+     * this implementation:
+     * <pre>
+     * &#064;Override
+     * public void sort(Comparator&lt;? super E&gt; c) {
+     *   Object[] elements = toArray();
+     *   Arrays.sort(elements, c);
+     *   ListIterator&lt;E&gt; iterator = (ListIterator&lt;Object&gt;) listIterator();
+     *   for (Object element : elements) {
+     *     iterator.next();
+     *     iterator.set((E) element);
+     *   }
+     * }
+     * </pre>
+     *
+     * @implSpec
+     * The default implementation obtains an array containing all elements in
+     * this list, sorts the array, and iterates over this list resetting each
+     * element from the corresponding position in the array. (This avoids the
+     * n<sup>2</sup> log(n) performance that would result from attempting
+     * to sort a linked list in place.)
+     *
+     * @implNote
+     * This implementation is a stable, adaptive, iterative mergesort that
+     * requires far fewer than n lg(n) comparisons when the input array is
+     * partially sorted, while offering the performance of a traditional
+     * mergesort when the input array is randomly ordered.  If the input array
+     * is nearly sorted, the implementation requires approximately n
+     * comparisons.  Temporary storage requirements vary from a small constant
+     * for nearly sorted input arrays to n/2 object references for randomly
+     * ordered input arrays.
+     *
+     * <p>The implementation takes equal advantage of ascending and
+     * descending order in its input array, and can take advantage of
+     * ascending and descending order in different parts of the same
+     * input array.  It is well-suited to merging two or more sorted arrays:
+     * simply concatenate the arrays and sort the resulting array.
+     *
+     * <p>The implementation was adapted from Tim Peters's list sort for Python
+     * (<a href="http://svn.python.org/projects/python/trunk/Objects/listsort.txt">
+     * TimSort</a>).  It uses techniques from Peter McIlroy's "Optimistic
+     * Sorting and Information Theoretic Complexity", in Proceedings of the
+     * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474,
+     * January 1993.
+     *
+     * @param c the {@code Comparator} used to compare list elements.
+     *          A {@code null} value indicates that the elements'
+     *          {@linkplain Comparable natural ordering} should be used
+     * @throws ClassCastException if the list contains elements that are not
+     *         <i>mutually comparable</i> using the specified comparator
+     * @throws UnsupportedOperationException if the list's list-iterator does
+     *         not support the {@code set} operation
+     * @throws IllegalArgumentException
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     *         if the comparator is found to violate the {@link Comparator}
+     *         contract
+     * @since 1.8
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    default void sort(Comparator<? super E> c) {
+        Object[] a = this.toArray();
+        Arrays.sort(a, (Comparator) c);
+        ListIterator<E> i = this.listIterator();
+        for (Object e : a) {
+            i.next();
+            i.set((E) e);
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list (optional operation).
+     * The list will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this list
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this list for equality.  Returns
+     * {@code true} if and only if the specified object is also a list, both
+     * lists have the same size, and all corresponding pairs of elements in
+     * the two lists are <i>equal</i>.  (Two elements {@code e1} and
+     * {@code e2} are <i>equal</i> if {@code Objects.equals(e1, e2)}.)
+     * In other words, two lists are defined to be
+     * equal if they contain the same elements in the same order.  This
+     * definition ensures that the equals method works properly across
+     * different implementations of the {@code List} interface.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this list.  The hash code of a list
+     * is defined to be the result of the following calculation:
+     * <pre>{@code
+     *     int hashCode = 1;
+     *     for (E e : list)
+     *         hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
+     * }</pre>
+     * This ensures that {@code list1.equals(list2)} implies that
+     * {@code list1.hashCode()==list2.hashCode()} for any two lists,
+     * {@code list1} and {@code list2}, as required by the general
+     * contract of {@link Object#hashCode}.
+     *
+     * @return the hash code value for this list
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    int hashCode();
+
+
+    // Positional Access Operations
+
+    /**
+     * Returns the element at the specified position in this list.
+     *
+     * @param index index of the element to return
+     * @return the element at the specified position in this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E get(int index);
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element (optional operation).
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws UnsupportedOperationException if the {@code set} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and
+     *         this list does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E set(int index, E element);
+
+    /**
+     * Inserts the specified element at the specified position in this list
+     * (optional operation).  Shifts the element currently at that position
+     * (if any) and any subsequent elements to the right (adds one to their
+     * indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this list
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws NullPointerException if the specified element is null and
+     *         this list does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    void add(int index, E element);
+
+    /**
+     * Removes the element at the specified position in this list (optional
+     * operation).  Shifts any subsequent elements to the left (subtracts one
+     * from their indices).  Returns the element that was removed from the
+     * list.
+     *
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    E remove(int index);
+
+
+    // Search Operations
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    int indexOf(Object o);
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this list, or -1 if this list does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * {@code Objects.equals(o, get(i))},
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this list, or -1 if this list does not contain the element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this list
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         list does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    int lastIndexOf(Object o);
+
+
+    // List Iterators
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence)
+     */
+    ListIterator<E> listIterator();
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * @param index index of the first element to be returned from the
+     *        list iterator (by a call to {@link ListIterator#next next})
+     * @return a list iterator over the elements in this list (in proper
+     *         sequence), starting at the specified position in the list
+     * @throws IndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    ListIterator<E> listIterator(int index);
+
+    // View
+
+    /**
+     * Returns a view of the portion of this list between the specified
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.  (If
+     * {@code fromIndex} and {@code toIndex} are equal, the returned list is
+     * empty.)  The returned list is backed by this list, so non-structural
+     * changes in the returned list are reflected in this list, and vice-versa.
+     * The returned list supports all of the optional list operations supported
+     * by this list.<p>
+     *
+     * This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a list can be used as a range operation by passing a subList view
+     * instead of a whole list.  For example, the following idiom
+     * removes a range of elements from a list:
+     * <pre>{@code
+     *      list.subList(from, to).clear();
+     * }</pre>
+     * Similar idioms may be constructed for {@code indexOf} and
+     * {@code lastIndexOf}, and all of the algorithms in the
+     * {@code Collections} class can be applied to a subList.<p>
+     *
+     * The semantics of the list returned by this method become undefined if
+     * the backing list (i.e., this list) is <i>structurally modified</i> in
+     * any way other than via the returned list.  (Structural modifications are
+     * those that change the size of this list, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this list
+     * @throws IndexOutOfBoundsException for an illegal endpoint index value
+     *         ({@code fromIndex < 0 || toIndex > size ||
+     *         fromIndex > toIndex})
+     */
+    List<E> subList(int fromIndex, int toIndex);
+
+    /**
+     * Creates a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Implementations should document the
+     * reporting of additional characteristic values.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * spliterator as follows:
+     * <ul>
+     * <li>If the list is an instance of {@link RandomAccess} then the default
+     *     implementation creates a spliterator that traverses elements by
+     *     invoking the method {@link List#get}.  If such invocation results or
+     *     would result in an {@code IndexOutOfBoundsException} then the
+     *     spliterator will <em>fail-fast</em> and throw a
+     *     {@code ConcurrentModificationException}.
+     *     If the list is also an instance of {@link AbstractList} then the
+     *     spliterator will use the list's {@link AbstractList#modCount modCount}
+     *     field to provide additional <em>fail-fast</em> behavior.
+     * <li>Otherwise, the default implementation creates a spliterator from the
+     *     list's {@code Iterator}.  The spliterator inherits the
+     *     <em>fail-fast</em> of the list's iterator.
+     * </ul>
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        if (this instanceof RandomAccess) {
+            return new AbstractList.RandomAccessSpliterator<>(this);
+        } else {
+            return Spliterators.spliterator(this, Spliterator.ORDERED);
+        }
+    }
+
+    /**
+     * Returns an immutable list containing zero elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @return an empty {@code List}
+     *
+     * @since 9
+     */
+    static <E> List<E> of() {
+        return ImmutableCollections.List0.instance();
+    }
+
+    /**
+     * Returns an immutable list containing one element.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the single element
+     * @return a {@code List} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1) {
+        return new ImmutableCollections.List1<>(e1);
+    }
+
+    /**
+     * Returns an immutable list containing two elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2) {
+        return new ImmutableCollections.List2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable list containing three elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable list containing four elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable list containing five elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable list containing six elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6);
+    }
+
+    /**
+     * Returns an immutable list containing seven elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7);
+    }
+
+    /**
+     * Returns an immutable list containing eight elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable list containing nine elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable list containing ten elements.
+     *
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
+                                                e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable list containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting list will be the component type of the array, and the size of
+     * the list will be equal to the length of the array. To create a list with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     List<String[]> list = List.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link List#of(Object) List.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param elements the elements to be contained in the list
+     * @return a {@code List} containing the specified elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> List<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.List0.instance();
+            case 1:
+                return new ImmutableCollections.List1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.List2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.ListN<>(elements);
+        }
+    }
+}
diff --git a/java/util/ListIterator.java b/java/util/ListIterator.java
new file mode 100644
index 0000000..6ad98fe
--- /dev/null
+++ b/java/util/ListIterator.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * An iterator for lists that allows the programmer
+ * to traverse the list in either direction, modify
+ * the list during iteration, and obtain the iterator's
+ * current position in the list. A {@code ListIterator}
+ * has no current element; its <I>cursor position</I> always
+ * lies between the element that would be returned by a call
+ * to {@code previous()} and the element that would be
+ * returned by a call to {@code next()}.
+ * An iterator for a list of length {@code n} has {@code n+1} possible
+ * cursor positions, as illustrated by the carets ({@code ^}) below:
+ * <PRE>
+ *                      Element(0)   Element(1)   Element(2)   ... Element(n-1)
+ * cursor positions:  ^            ^            ^            ^                  ^
+ * </PRE>
+ * Note that the {@link #remove} and {@link #set(Object)} methods are
+ * <i>not</i> defined in terms of the cursor position;  they are defined to
+ * operate on the last element returned by a call to {@link #next} or
+ * {@link #previous()}.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @author  Josh Bloch
+ * @see Collection
+ * @see List
+ * @see Iterator
+ * @see Enumeration
+ * @see List#listIterator()
+ * @since   1.2
+ */
+public interface ListIterator<E> extends Iterator<E> {
+    // Query Operations
+
+    /**
+     * Returns {@code true} if this list iterator has more elements when
+     * traversing the list in the forward direction. (In other words,
+     * returns {@code true} if {@link #next} would return an element rather
+     * than throwing an exception.)
+     *
+     * @return {@code true} if the list iterator has more elements when
+     *         traversing the list in the forward direction
+     */
+    boolean hasNext();
+
+    /**
+     * Returns the next element in the list and advances the cursor position.
+     * This method may be called repeatedly to iterate through the list,
+     * or intermixed with calls to {@link #previous} to go back and forth.
+     * (Note that alternating calls to {@code next} and {@code previous}
+     * will return the same element repeatedly.)
+     *
+     * @return the next element in the list
+     * @throws NoSuchElementException if the iteration has no next element
+     */
+    E next();
+
+    /**
+     * Returns {@code true} if this list iterator has more elements when
+     * traversing the list in the reverse direction.  (In other words,
+     * returns {@code true} if {@link #previous} would return an element
+     * rather than throwing an exception.)
+     *
+     * @return {@code true} if the list iterator has more elements when
+     *         traversing the list in the reverse direction
+     */
+    boolean hasPrevious();
+
+    /**
+     * Returns the previous element in the list and moves the cursor
+     * position backwards.  This method may be called repeatedly to
+     * iterate through the list backwards, or intermixed with calls to
+     * {@link #next} to go back and forth.  (Note that alternating calls
+     * to {@code next} and {@code previous} will return the same
+     * element repeatedly.)
+     *
+     * @return the previous element in the list
+     * @throws NoSuchElementException if the iteration has no previous
+     *         element
+     */
+    E previous();
+
+    /**
+     * Returns the index of the element that would be returned by a
+     * subsequent call to {@link #next}. (Returns list size if the list
+     * iterator is at the end of the list.)
+     *
+     * @return the index of the element that would be returned by a
+     *         subsequent call to {@code next}, or list size if the list
+     *         iterator is at the end of the list
+     */
+    int nextIndex();
+
+    /**
+     * Returns the index of the element that would be returned by a
+     * subsequent call to {@link #previous}. (Returns -1 if the list
+     * iterator is at the beginning of the list.)
+     *
+     * @return the index of the element that would be returned by a
+     *         subsequent call to {@code previous}, or -1 if the list
+     *         iterator is at the beginning of the list
+     */
+    int previousIndex();
+
+
+    // Modification Operations
+
+    /**
+     * Removes from the list the last element that was returned by {@link
+     * #next} or {@link #previous} (optional operation).  This call can
+     * only be made once per call to {@code next} or {@code previous}.
+     * It can be made only if {@link #add} has not been
+     * called after the last call to {@code next} or {@code previous}.
+     *
+     * @throws UnsupportedOperationException if the {@code remove}
+     *         operation is not supported by this list iterator
+     * @throws IllegalStateException if neither {@code next} nor
+     *         {@code previous} have been called, or {@code remove} or
+     *         {@code add} have been called after the last call to
+     *         {@code next} or {@code previous}
+     */
+    void remove();
+
+    /**
+     * Replaces the last element returned by {@link #next} or
+     * {@link #previous} with the specified element (optional operation).
+     * This call can be made only if neither {@link #remove} nor {@link
+     * #add} have been called after the last call to {@code next} or
+     * {@code previous}.
+     *
+     * @param e the element with which to replace the last element returned by
+     *          {@code next} or {@code previous}
+     * @throws UnsupportedOperationException if the {@code set} operation
+     *         is not supported by this list iterator
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws IllegalArgumentException if some aspect of the specified
+     *         element prevents it from being added to this list
+     * @throws IllegalStateException if neither {@code next} nor
+     *         {@code previous} have been called, or {@code remove} or
+     *         {@code add} have been called after the last call to
+     *         {@code next} or {@code previous}
+     */
+    void set(E e);
+
+    /**
+     * Inserts the specified element into the list (optional operation).
+     * The element is inserted immediately before the element that
+     * would be returned by {@link #next}, if any, and after the element
+     * that would be returned by {@link #previous}, if any.  (If the
+     * list contains no elements, the new element becomes the sole element
+     * on the list.)  The new element is inserted before the implicit
+     * cursor: a subsequent call to {@code next} would be unaffected, and a
+     * subsequent call to {@code previous} would return the new element.
+     * (This call increases by one the value that would be returned by a
+     * call to {@code nextIndex} or {@code previousIndex}.)
+     *
+     * @param e the element to insert
+     * @throws UnsupportedOperationException if the {@code add} method is
+     *         not supported by this list iterator
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this list
+     * @throws IllegalArgumentException if some aspect of this element
+     *         prevents it from being added to this list
+     */
+    void add(E e);
+}
diff --git a/java/util/ListResourceBundle.java b/java/util/ListResourceBundle.java
new file mode 100644
index 0000000..99090ca
--- /dev/null
+++ b/java/util/ListResourceBundle.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import sun.util.ResourceBundleEnumeration;
+
+/**
+ * <code>ListResourceBundle</code> is an abstract subclass of
+ * <code>ResourceBundle</code> that manages resources for a locale
+ * in a convenient and easy to use list. See <code>ResourceBundle</code> for
+ * more information about resource bundles in general.
+ *
+ * <P>
+ * Subclasses must override <code>getContents</code> and provide an array,
+ * where each item in the array is a pair of objects.
+ * The first element of each pair is the key, which must be a
+ * <code>String</code>, and the second element is the value associated with
+ * that key.
+ *
+ * <p>
+ * The following <a name="sample">example</a> shows two members of a resource
+ * bundle family with the base name "MyResources".
+ * "MyResources" is the default member of the bundle family, and
+ * "MyResources_fr" is the French member.
+ * These members are based on <code>ListResourceBundle</code>
+ * (a related <a href="PropertyResourceBundle.html#sample">example</a> shows
+ * how you can add a bundle to this family that's based on a properties file).
+ * The keys in this example are of the form "s1" etc. The actual
+ * keys are entirely up to your choice, so long as they are the same as
+ * the keys you use in your program to retrieve the objects from the bundle.
+ * Keys are case-sensitive.
+ * <blockquote>
+ * <pre>
+ *
+ * public class MyResources extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *         // LOCALIZE THIS
+ *             {"s1", "The disk \"{1}\" contains {0}."},  // MessageFormat pattern
+ *             {"s2", "1"},                               // location of {0} in pattern
+ *             {"s3", "My Disk"},                         // sample disk name
+ *             {"s4", "no files"},                        // first ChoiceFormat choice
+ *             {"s5", "one file"},                        // second ChoiceFormat choice
+ *             {"s6", "{0,number} files"},                // third ChoiceFormat choice
+ *             {"s7", "3 Mar 96"},                        // sample date
+ *             {"s8", new Dimension(1,5)}                 // real object, not just string
+ *         // END OF MATERIAL TO LOCALIZE
+ *         };
+ *     }
+ * }
+ *
+ * public class MyResources_fr extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *         // LOCALIZE THIS
+ *             {"s1", "Le disque \"{1}\" {0}."},          // MessageFormat pattern
+ *             {"s2", "1"},                               // location of {0} in pattern
+ *             {"s3", "Mon disque"},                      // sample disk name
+ *             {"s4", "ne contient pas de fichiers"},     // first ChoiceFormat choice
+ *             {"s5", "contient un fichier"},             // second ChoiceFormat choice
+ *             {"s6", "contient {0,number} fichiers"},    // third ChoiceFormat choice
+ *             {"s7", "3 mars 1996"},                     // sample date
+ *             {"s8", new Dimension(1,3)}                 // real object, not just string
+ *         // END OF MATERIAL TO LOCALIZE
+ *         };
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code ListResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the methods in this class are thread-safe.
+ *
+ * @see ResourceBundle
+ * @see PropertyResourceBundle
+ * @since JDK1.1
+ */
+public abstract class ListResourceBundle extends ResourceBundle {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public ListResourceBundle() {
+    }
+
+    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
+    public final Object handleGetObject(String key) {
+        // lazily load the lookup hashtable.
+        if (lookup == null) {
+            loadLookup();
+        }
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        return lookup.get(key); // this class ignores locales
+    }
+
+    /**
+     * Returns an <code>Enumeration</code> of the keys contained in
+     * this <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     * @see #keySet()
+     */
+    public Enumeration<String> getKeys() {
+        // lazily load the lookup hashtable.
+        if (lookup == null) {
+            loadLookup();
+        }
+
+        ResourceBundle parent = this.parent;
+        return new ResourceBundleEnumeration(lookup.keySet(),
+                (parent != null) ? parent.getKeys() : null);
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained
+     * <em>only</em> in this <code>ResourceBundle</code>.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *         <code>ResourceBundle</code>
+     * @since 1.6
+     * @see #keySet()
+     */
+    protected Set<String> handleKeySet() {
+        if (lookup == null) {
+            loadLookup();
+        }
+        return lookup.keySet();
+    }
+
+    /**
+     * Returns an array in which each item is a pair of objects in an
+     * <code>Object</code> array. The first element of each pair is
+     * the key, which must be a <code>String</code>, and the second
+     * element is the value associated with that key.  See the class
+     * description for details.
+     *
+     * @return an array of an <code>Object</code> array representing a
+     * key-value pair.
+     */
+    abstract protected Object[][] getContents();
+
+    // ==================privates====================
+
+    /**
+     * We lazily load the lookup hashtable.  This function does the
+     * loading.
+     */
+    private synchronized void loadLookup() {
+        if (lookup != null)
+            return;
+
+        Object[][] contents = getContents();
+        HashMap<String,Object> temp = new HashMap<>(contents.length);
+        for (int i = 0; i < contents.length; ++i) {
+            // key must be non-null String, value must be non-null
+            String key = (String) contents[i][0];
+            Object value = contents[i][1];
+            if (key == null || value == null) {
+                throw new NullPointerException();
+            }
+            temp.put(key, value);
+        }
+        lookup = temp;
+    }
+
+    // Android-changed: Fix unsafe publication http://b/31467561
+    // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+    // was: private Map<String,Object> lookup = null;
+    private volatile Map<String,Object> lookup = null;
+}
diff --git a/java/util/Locale.annotated.java b/java/util/Locale.annotated.java
new file mode 100644
index 0000000..d8aad03
--- /dev/null
+++ b/java/util/Locale.annotated.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+
+package java.util;
+
+import java.text.MessageFormat;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Locale implements java.lang.Cloneable, java.io.Serializable {
+
+public Locale(java.lang.String language, java.lang.String country, java.lang.String variant) { throw new RuntimeException("Stub!"); }
+
+public Locale(java.lang.String language, java.lang.String country) { throw new RuntimeException("Stub!"); }
+
+public Locale(java.lang.String language) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale getDefault() { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale getDefault(java.util.Locale.Category category) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale initDefault() { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setDefault(java.util.Locale newLocale) { throw new RuntimeException("Stub!"); }
+
+public static synchronized void setDefault(java.util.Locale.Category category, java.util.Locale newLocale) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale[] getAvailableLocales() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String[] getISOCountries() { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String[] getISOLanguages() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getLanguage() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getScript() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getCountry() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getVariant() { throw new RuntimeException("Stub!"); }
+
+public boolean hasExtensions() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale stripExtensions() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getExtension(char key) { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.Character> getExtensionKeys() { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.String> getUnicodeLocaleAttributes() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getUnicodeLocaleType(java.lang.String key) { throw new RuntimeException("Stub!"); }
+
+public java.util.Set<java.lang.String> getUnicodeLocaleKeys() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toLanguageTag() { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale forLanguageTag(java.lang.String languageTag) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getISO3Language() throws java.util.MissingResourceException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getISO3Country() throws java.util.MissingResourceException { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayLanguage() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayLanguage(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayScript() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayScript(java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayCountry() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayCountry(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayVariant() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayVariant(java.util.Locale inLocale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayName() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getDisplayName(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static java.lang.String adjustLanguageCode(java.lang.String languageCode) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.util.Locale> locales, java.util.Locale.FilteringMode mode) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale> filter(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.util.Locale> locales) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.lang.String> tags, java.util.Locale.FilteringMode mode) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.lang.String> filterTags(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.lang.String> tags) { throw new RuntimeException("Stub!"); }
+
+public static java.util.Locale lookup(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.util.Locale> locales) { throw new RuntimeException("Stub!"); }
+
+public static java.lang.String lookupTag(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Collection<java.lang.String> tags) { throw new RuntimeException("Stub!"); }
+
+public static final java.util.Locale CANADA;
+static { CANADA = null; }
+
+public static final java.util.Locale CANADA_FRENCH;
+static { CANADA_FRENCH = null; }
+
+public static final java.util.Locale CHINA;
+static { CHINA = null; }
+
+public static final java.util.Locale CHINESE;
+static { CHINESE = null; }
+
+public static final java.util.Locale ENGLISH;
+static { ENGLISH = null; }
+
+public static final java.util.Locale FRANCE;
+static { FRANCE = null; }
+
+public static final java.util.Locale FRENCH;
+static { FRENCH = null; }
+
+public static final java.util.Locale GERMAN;
+static { GERMAN = null; }
+
+public static final java.util.Locale GERMANY;
+static { GERMANY = null; }
+
+public static final java.util.Locale ITALIAN;
+static { ITALIAN = null; }
+
+public static final java.util.Locale ITALY;
+static { ITALY = null; }
+
+public static final java.util.Locale JAPAN;
+static { JAPAN = null; }
+
+public static final java.util.Locale JAPANESE;
+static { JAPANESE = null; }
+
+public static final java.util.Locale KOREA;
+static { KOREA = null; }
+
+public static final java.util.Locale KOREAN;
+static { KOREAN = null; }
+
+public static final java.util.Locale PRC;
+static { PRC = null; }
+
+public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x'
+
+public static final java.util.Locale ROOT;
+static { ROOT = null; }
+
+public static final java.util.Locale SIMPLIFIED_CHINESE;
+static { SIMPLIFIED_CHINESE = null; }
+
+public static final java.util.Locale TAIWAN;
+static { TAIWAN = null; }
+
+public static final java.util.Locale TRADITIONAL_CHINESE;
+static { TRADITIONAL_CHINESE = null; }
+
+public static final java.util.Locale UK;
+static { UK = null; }
+
+public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u'
+
+public static final java.util.Locale US;
+static { US = null; }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static final class Builder {
+
+public Builder() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setLocale(java.util.Locale locale) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setLanguageTag(java.lang.String languageTag) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setLanguage(java.lang.String language) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setScript(java.lang.String script) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setRegion(java.lang.String region) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setVariant(java.lang.String variant) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setExtension(char key, java.lang.String value) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String key, java.lang.String type) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String attribute) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String attribute) { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder clear() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale.Builder clearExtensions() { throw new RuntimeException("Stub!"); }
+
+public java.util.Locale build() { throw new RuntimeException("Stub!"); }
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static enum Category {
+DISPLAY,
+FORMAT;
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static enum FilteringMode {
+AUTOSELECT_FILTERING,
+EXTENDED_FILTERING,
+IGNORE_EXTENDED_RANGES,
+MAP_EXTENDED_RANGES,
+REJECT_EXTENDED_RANGES;
+}
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static final class LanguageRange {
+
+public LanguageRange(java.lang.String range) { throw new RuntimeException("Stub!"); }
+
+public LanguageRange(java.lang.String range, double weight) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getRange() { throw new RuntimeException("Stub!"); }
+
+public double getWeight() { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String ranges) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale.LanguageRange> parse(java.lang.String ranges, java.util.Map<java.lang.String, java.util.List<java.lang.String>> map) { throw new RuntimeException("Stub!"); }
+
+public static java.util.List<java.util.Locale.LanguageRange> mapEquivalents(java.util.List<java.util.Locale.LanguageRange> priorityList, java.util.Map<java.lang.String, java.util.List<java.lang.String>> map) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static final double MAX_WEIGHT = 1.0;
+
+public static final double MIN_WEIGHT = 0.0;
+}
+
+}
+
diff --git a/java/util/Locale.java b/java/util/Locale.java
new file mode 100644
index 0000000..1ce4a20
--- /dev/null
+++ b/java/util/Locale.java
@@ -0,0 +1,3772 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import com.android.icu.util.LocaleNative;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.text.MessageFormat;
+import libcore.icu.ICU;
+
+import sun.util.locale.BaseLocale;
+import sun.util.locale.InternalLocaleBuilder;
+import sun.util.locale.LanguageTag;
+import sun.util.locale.LocaleExtensions;
+import sun.util.locale.LocaleMatcher;
+import sun.util.locale.LocaleObjectCache;
+import sun.util.locale.LocaleSyntaxException;
+import sun.util.locale.LocaleUtils;
+import sun.util.locale.ParseStatus;
+
+// Android-added: documentation about ICU data & warning of default locale.
+/**
+ * A <code>Locale</code> object represents a specific geographical, political,
+ * or cultural region. An operation that requires a <code>Locale</code> to perform
+ * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
+ * to tailor information for the user. For example, displaying a number
+ * is a locale-sensitive operation&mdash; the number should be formatted
+ * according to the customs and conventions of the user's native country,
+ * region, or culture.
+ *
+ * <p> The {@code Locale} class implements IETF BCP 47 which is composed of
+ * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 "Matching of Language
+ * Tags"</a> and <a href="http://tools.ietf.org/html/rfc5646">RFC 5646 "Tags
+ * for Identifying Languages"</a> with support for the LDML (UTS#35, "Unicode
+ * Locale Data Markup Language") BCP 47-compatible extensions for locale data
+ * exchange.
+ *
+ * <p> A <code>Locale</code> object logically consists of the fields
+ * described below.
+ *
+ * <dl>
+ *   <dt><a name="def_language"><b>language</b></a></dt>
+ *
+ *   <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
+ *   language subtags up to 8 alpha letters (for future enhancements).
+ *   When a language has both an alpha-2 code and an alpha-3 code, the
+ *   alpha-2 code must be used.  You can find a full list of valid
+ *   language codes in the IANA Language Subtag Registry (search for
+ *   "Type: language").  The language field is case insensitive, but
+ *   <code>Locale</code> always canonicalizes to lower case.</dd>
+ *
+ *   <dd>Well-formed language values have the form
+ *   <code>[a-zA-Z]{2,8}</code>.  Note that this is not the the full
+ *   BCP47 language production, since it excludes extlang.  They are
+ *   not needed since modern three-letter language codes replace
+ *   them.</dd>
+ *
+ *   <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd>
+ *
+ *   <dt><a name="def_script"><b>script</b></a></dt>
+ *
+ *   <dd>ISO 15924 alpha-4 script code.  You can find a full list of
+ *   valid script codes in the IANA Language Subtag Registry (search
+ *   for "Type: script").  The script field is case insensitive, but
+ *   <code>Locale</code> always canonicalizes to title case (the first
+ *   letter is upper case and the rest of the letters are lower
+ *   case).</dd>
+ *
+ *   <dd>Well-formed script values have the form
+ *   <code>[a-zA-Z]{4}</code></dd>
+ *
+ *   <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd>
+ *
+ *   <dt><a name="def_region"><b>country (region)</b></a></dt>
+ *
+ *   <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
+ *   You can find a full list of valid country and region codes in the
+ *   IANA Language Subtag Registry (search for "Type: region").  The
+ *   country (region) field is case insensitive, but
+ *   <code>Locale</code> always canonicalizes to upper case.</dd>
+ *
+ *   <dd>Well-formed country/region values have
+ *   the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd>
+ *
+ *   <dd>Example: "US" (United States), "FR" (France), "029"
+ *   (Caribbean)</dd>
+ *
+ *   <dt><a name="def_variant"><b>variant</b></a></dt>
+ *
+ *   <dd>Any arbitrary value used to indicate a variation of a
+ *   <code>Locale</code>.  Where there are two or more variant values
+ *   each indicating its own semantics, these values should be ordered
+ *   by importance, with most important first, separated by
+ *   underscore('_').  The variant field is case sensitive.</dd>
+ *
+ *   <dd>Note: IETF BCP 47 places syntactic restrictions on variant
+ *   subtags.  Also BCP 47 subtags are strictly used to indicate
+ *   additional variations that define a language or its dialects that
+ *   are not covered by any combinations of language, script and
+ *   region subtags.  You can find a full list of valid variant codes
+ *   in the IANA Language Subtag Registry (search for "Type: variant").
+ *
+ *   <p>However, the variant field in <code>Locale</code> has
+ *   historically been used for any kind of variation, not just
+ *   language variations.  For example, some supported variants
+ *   available in Java SE Runtime Environments indicate alternative
+ *   cultural behaviors such as calendar type or number script.  In
+ *   BCP 47 this kind of information, which does not identify the
+ *   language, is supported by extension subtags or private use
+ *   subtags.</dd>
+ *
+ *   <dd>Well-formed variant values have the form <code>SUBTAG
+ *   (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
+ *   [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
+ *   uses hyphen ('-') as a delimiter, this is more lenient).</dd>
+ *
+ *   <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd>
+ *
+ *   <dt><a name="def_extensions"><b>extensions</b></a></dt>
+ *
+ *   <dd>A map from single character keys to string values, indicating
+ *   extensions apart from language identification.  The extensions in
+ *   <code>Locale</code> implement the semantics and syntax of BCP 47
+ *   extension subtags and private use subtags. The extensions are
+ *   case insensitive, but <code>Locale</code> canonicalizes all
+ *   extension keys and values to lower case. Note that extensions
+ *   cannot have empty values.</dd>
+ *
+ *   <dd>Well-formed keys are single characters from the set
+ *   <code>[0-9a-zA-Z]</code>.  Well-formed values have the form
+ *   <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
+ *   <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
+ *   <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
+ *   single-character subtags).</dd>
+ *
+ *   <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
+ *   key="x"/value="java-1-7"</dd>
+ * </dl>
+ *
+ * <b>Note:</b> Although BCP 47 requires field values to be registered
+ * in the IANA Language Subtag Registry, the <code>Locale</code> class
+ * does not provide any validation features.  The <code>Builder</code>
+ * only checks if an individual field satisfies the syntactic
+ * requirement (is well-formed), but does not validate the value
+ * itself.  See {@link Builder} for details.
+ *
+ * <h3><a name="def_locale_extension">Unicode locale/language extension</a></h3>
+ *
+ * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
+ * attributes and keywords to override or refine the default behavior
+ * associated with a locale.  A keyword is represented by a pair of
+ * key and type.  For example, "nu-thai" indicates that Thai local
+ * digits (value:"thai") should be used for formatting numbers
+ * (key:"nu").
+ *
+ * <p>The keywords are mapped to a BCP 47 extension value using the
+ * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}).  The above
+ * example, "nu-thai", becomes the extension "u-nu-thai".code
+ *
+ * <p>Thus, when a <code>Locale</code> object contains Unicode locale
+ * attributes and keywords,
+ * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
+ * String representing this information, for example, "nu-thai".  The
+ * <code>Locale</code> class also provides {@link
+ * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
+ * {@link #getUnicodeLocaleType} which allow you to access Unicode
+ * locale attributes and key/type pairs directly.  When represented as
+ * a string, the Unicode Locale Extension lists attributes
+ * alphabetically, followed by key/type sequences with keys listed
+ * alphabetically (the order of subtags comprising a key's type is
+ * fixed when the type is defined)
+ *
+ * <p>A well-formed locale key has the form
+ * <code>[0-9a-zA-Z]{2}</code>.  A well-formed locale type has the
+ * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
+ * can be empty, or a series of subtags 3-8 alphanums in length).  A
+ * well-formed locale attribute has the form
+ * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
+ * form as a locale type subtag).
+ *
+ * <p>The Unicode locale extension specifies optional behavior in
+ * locale-sensitive services.  Although the LDML specification defines
+ * various keys and values, actual locale-sensitive service
+ * implementations in a Java Runtime Environment might not support any
+ * particular Unicode locale attributes or key/type pairs.
+ *
+ * <h4>Creating a Locale</h4>
+ *
+ * <p>There are several different ways to create a <code>Locale</code>
+ * object.
+ *
+ * <h5>Builder</h5>
+ *
+ * <p>Using {@link Builder} you can construct a <code>Locale</code> object
+ * that conforms to BCP 47 syntax.
+ *
+ * <h5>Constructors</h5>
+ *
+ * <p>The <code>Locale</code> class provides three constructors:
+ * <blockquote>
+ * <pre>
+ *     {@link #Locale(String language)}
+ *     {@link #Locale(String language, String country)}
+ *     {@link #Locale(String language, String country, String variant)}
+ * </pre>
+ * </blockquote>
+ * These constructors allow you to create a <code>Locale</code> object
+ * with language, country and variant, but you cannot specify
+ * script or extensions.
+ *
+ * <h5>Factory Methods</h5>
+ *
+ * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
+ * object for a well-formed BCP 47 language tag.
+ *
+ * <h5>Locale Constants</h5>
+ *
+ * <p>The <code>Locale</code> class provides a number of convenient constants
+ * that you can use to create <code>Locale</code> objects for commonly used
+ * locales. For example, the following creates a <code>Locale</code> object
+ * for the United States:
+ * <blockquote>
+ * <pre>
+ *     Locale.US
+ * </pre>
+ * </blockquote>
+ *
+ * <h4><a name="LocaleMatching">Locale Matching</a></h4>
+ *
+ * <p>If an application or a system is internationalized and provides localized
+ * resources for multiple locales, it sometimes needs to find one or more
+ * locales (or language tags) which meet each user's specific preferences. Note
+ * that a term "language tag" is used interchangeably with "locale" in this
+ * locale matching documentation.
+ *
+ * <p>In order to do matching a user's preferred locales to a set of language
+ * tags, <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
+ * Language Tags</a> defines two mechanisms: filtering and lookup.
+ * <em>Filtering</em> is used to get all matching locales, whereas
+ * <em>lookup</em> is to choose the best matching locale.
+ * Matching is done case-insensitively. These matching mechanisms are described
+ * in the following sections.
+ *
+ * <p>A user's preference is called a <em>Language Priority List</em> and is
+ * expressed as a list of language ranges. There are syntactically two types of
+ * language ranges: basic and extended. See
+ * {@link Locale.LanguageRange Locale.LanguageRange} for details.
+ *
+ * <h5>Filtering</h5>
+ *
+ * <p>The filtering operation returns all matching language tags. It is defined
+ * in RFC 4647 as follows:
+ * "In filtering, each language range represents the least specific language
+ * tag (that is, the language tag with fewest number of subtags) that is an
+ * acceptable match. All of the language tags in the matching set of tags will
+ * have an equal or greater number of subtags than the language range. Every
+ * non-wildcard subtag in the language range will appear in every one of the
+ * matching language tags."
+ *
+ * <p>There are two types of filtering: filtering for basic language ranges
+ * (called "basic filtering") and filtering for extended language ranges
+ * (called "extended filtering"). They may return different results by what
+ * kind of language ranges are included in the given Language Priority List.
+ * {@link Locale.FilteringMode} is a parameter to specify how filtering should
+ * be done.
+ *
+ * <h5>Lookup</h5>
+ *
+ * <p>The lookup operation returns the best matching language tags. It is
+ * defined in RFC 4647 as follows:
+ * "By contrast with filtering, each language range represents the most
+ * specific tag that is an acceptable match.  The first matching tag found,
+ * according to the user's priority, is considered the closest match and is the
+ * item returned."
+ *
+ * <p>For example, if a Language Priority List consists of two language ranges,
+ * {@code "zh-Hant-TW"} and {@code "en-US"}, in prioritized order, lookup
+ * method progressively searches the language tags below in order to find the
+ * best matching language tag.
+ * <blockquote>
+ * <pre>
+ *    1. zh-Hant-TW
+ *    2. zh-Hant
+ *    3. zh
+ *    4. en-US
+ *    5. en
+ * </pre>
+ * </blockquote>
+ * If there is a language tag which matches completely to a language range
+ * above, the language tag is returned.
+ *
+ * <p>{@code "*"} is the special language range, and it is ignored in lookup.
+ *
+ * <p>If multiple language tags match as a result of the subtag {@code '*'}
+ * included in a language range, the first matching language tag returned by
+ * an {@link Iterator} over a {@link Collection} of language tags is treated as
+ * the best matching one.
+ *
+ * <h4>Use of Locale</h4>
+ *
+ * <p>Once you've created a <code>Locale</code> you can query it for information
+ * about itself. Use <code>getCountry</code> to get the country (or region)
+ * code and <code>getLanguage</code> to get the language code.
+ * You can use <code>getDisplayCountry</code> to get the
+ * name of the country suitable for displaying to the user. Similarly,
+ * you can use <code>getDisplayLanguage</code> to get the name of
+ * the language suitable for displaying to the user. Interestingly,
+ * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
+ * and have two versions: one that uses the default
+ * {@link Locale.Category#DISPLAY DISPLAY} locale and one
+ * that uses the locale specified as an argument.
+ *
+ * <p>The Java Platform provides a number of classes that perform locale-sensitive
+ * operations. For example, the <code>NumberFormat</code> class formats
+ * numbers, currency, and percentages in a locale-sensitive manner. Classes
+ * such as <code>NumberFormat</code> have several convenience methods
+ * for creating a default object of that type. For example, the
+ * <code>NumberFormat</code> class provides these three convenience methods
+ * for creating a default <code>NumberFormat</code> object:
+ * <blockquote>
+ * <pre>
+ *     NumberFormat.getInstance()
+ *     NumberFormat.getCurrencyInstance()
+ *     NumberFormat.getPercentInstance()
+ * </pre>
+ * </blockquote>
+ * Each of these methods has two variants; one with an explicit locale
+ * and one without; the latter uses the default
+ * {@link Locale.Category#FORMAT FORMAT} locale:
+ * <blockquote>
+ * <pre>
+ *     NumberFormat.getInstance(myLocale)
+ *     NumberFormat.getCurrencyInstance(myLocale)
+ *     NumberFormat.getPercentInstance(myLocale)
+ * </pre>
+ * </blockquote>
+ * A <code>Locale</code> is the mechanism for identifying the kind of object
+ * (<code>NumberFormat</code>) that you would like to get. The locale is
+ * <STRONG>just</STRONG> a mechanism for identifying objects,
+ * <STRONG>not</STRONG> a container for the objects themselves.
+ *
+ * <h4>Compatibility</h4>
+ *
+ * <p>In order to maintain compatibility with existing usage, Locale's
+ * constructors retain their behavior prior to the Java Runtime
+ * Environment version 1.7.  The same is largely true for the
+ * <code>toString</code> method. Thus Locale objects can continue to
+ * be used as they were. In particular, clients who parse the output
+ * of toString into language, country, and variant fields can continue
+ * to do so (although this is strongly discouraged), although the
+ * variant field will have additional information in it if script or
+ * extensions are present.
+ *
+ * <p>In addition, BCP 47 imposes syntax restrictions that are not
+ * imposed by Locale's constructors. This means that conversions
+ * between some Locales and BCP 47 language tags cannot be made without
+ * losing information. Thus <code>toLanguageTag</code> cannot
+ * represent the state of locales whose language, country, or variant
+ * do not conform to BCP 47.
+ *
+ * <p>Because of these issues, it is recommended that clients migrate
+ * away from constructing non-conforming locales and use the
+ * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
+ * Clients desiring a string representation of the complete locale can
+ * then always rely on <code>toLanguageTag</code> for this purpose.
+ *
+ * <h5><a name="special_cases_constructor">Special cases</a></h5>
+ *
+ * <p>For compatibility reasons, two
+ * non-conforming locales are treated as special cases.  These are
+ * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
+ * in BCP 47 since the variants are too short. To ease migration to BCP 47,
+ * these are treated specially during construction.  These two cases (and only
+ * these) cause a constructor to generate an extension, all other values behave
+ * exactly as they did prior to Java 7.
+ *
+ * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
+ * Japan together with the Japanese Imperial calendar. This is now
+ * representable using a Unicode locale extension, by specifying the
+ * Unicode locale key <tt>ca</tt> (for "calendar") and type
+ * <tt>japanese</tt>. When the Locale constructor is called with the
+ * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
+ * automatically added.
+ *
+ * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
+ * Thailand together with Thai digits. This is also now representable using
+ * a Unicode locale extension, by specifying the Unicode locale key
+ * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
+ * constructor is called with the arguments "th", "TH", "TH", the
+ * extension "u-nu-thai" is automatically added.
+ *
+ * <h5>Serialization</h5>
+ *
+ * <p>During serialization, writeObject writes all fields to the output
+ * stream, including extensions.
+ *
+ * <p>During deserialization, readResolve adds extensions as described
+ * in <a href="#special_cases_constructor">Special Cases</a>, only
+ * for the two cases th_TH_TH and ja_JP_JP.
+ *
+ * <h5>Legacy language codes</h5>
+ *
+ * <p>Locale's constructor has always converted three language codes to
+ * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
+ * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
+ * <tt>in</tt>.  This continues to be the case, in order to not break
+ * backwards compatibility.
+ *
+ * <p>The APIs added in 1.7 map between the old and new language codes,
+ * maintaining the old codes internal to Locale (so that
+ * <code>getLanguage</code> and <code>toString</code> reflect the old
+ * code), but using the new codes in the BCP 47 language tag APIs (so
+ * that <code>toLanguageTag</code> reflects the new one). This
+ * preserves the equivalence between Locales no matter which code or
+ * API is used to construct them. Java's default resource bundle
+ * lookup mechanism also implements this mapping, so that resources
+ * can be named using either convention, see {@link ResourceBundle.Control}.
+ *
+ * <h5>Three-letter language/country(region) codes</h5>
+ *
+ * <p>The Locale constructors have always specified that the language
+ * and the country param be two characters in length, although in
+ * practice they have accepted any length.  The specification has now
+ * been relaxed to allow language codes of two to eight characters and
+ * country (region) codes of two to three characters, and in
+ * particular, three-letter language codes and three-digit region
+ * codes as specified in the IANA Language Subtag Registry.  For
+ * compatibility, the implementation still does not impose a length
+ * constraint.
+ *
+ * <a name="locale_data"></a><h4>Locale data</h4>
+ * <p>Note that locale data comes solely from ICU. User-supplied locale service providers (using
+ * the {@code java.text.spi} or {@code java.util.spi} mechanisms) are not supported.
+ *
+ * <p>Here are the versions of ICU (and the corresponding CLDR and Unicode versions) used in
+ * various Android releases:
+ * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+ * <tr><td>Android 1.5 (Cupcake)/Android 1.6 (Donut)/Android 2.0 (Eclair)</td>
+ *     <td>ICU 3.8</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-5">CLDR 1.5</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr>
+ * <tr><td>Android 2.2 (Froyo)</td>
+ *     <td>ICU 4.2</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-7">CLDR 1.7</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr>
+ * <tr><td>Android 2.3 (Gingerbread)/Android 3.0 (Honeycomb)</td>
+ *     <td>ICU 4.4</td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-8">CLDR 1.8</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr>
+ * <tr><td>Android 4.0 (Ice Cream Sandwich)</td>
+ *     <td><a href="http://site.icu-project.org/download/46">ICU 4.6</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.1 (Jelly Bean)</td>
+ *     <td><a href="http://site.icu-project.org/download/48">ICU 4.8</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-2-0">CLDR 2.0</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.3 (Jelly Bean MR2)</td>
+ *     <td><a href="http://site.icu-project.org/download/50">ICU 50</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-22-1">CLDR 22.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 4.4 (KitKat)</td>
+ *     <td><a href="http://site.icu-project.org/download/51">ICU 51</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-23">CLDR 23</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 5.0 (Lollipop)</td>
+ *     <td><a href="http://site.icu-project.org/download/53">ICU 53</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-25">CLDR 25</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3</a></td></tr>
+ * <tr><td>Android 6.0 (Marshmallow)</td>
+ *     <td><a href="http://site.icu-project.org/download/55">ICU 55.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-27">CLDR 27.0.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode7.0.0/">Unicode 7.0</a></td></tr>
+ * <tr><td>Android 7.0 (Nougat)</td>
+ *     <td><a href="http://site.icu-project.org/download/56">ICU 56.1</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-28">CLDR 28</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode8.0.0/">Unicode 8.0</a></td></tr>
+ * <tr><td>Android 8.0 (Oreo)</td>
+ *     <td><a href="http://site.icu-project.org/download/58">ICU 58.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-30">CLDR 30.0.3</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a></td></tr>
+ * <tr><td>Android 9.0 (Pie)</td>
+ *     <td><a href="http://site.icu-project.org/download/60">ICU 60.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-32">CLDR 32.0.1</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode10.0.0/">Unicode 10.0</a></td></tr>
+ * <tr><td>Android 10.0 (Q)</td>
+ *     <td><a href="http://site.icu-project.org/download/63">ICU 63.2</a></td>
+ *     <td><a href="http://cldr.unicode.org/index/downloads/cldr-34">CLDR 34</a></td>
+ *     <td><a href="http://www.unicode.org/versions/Unicode11.0.0/">Unicode 11.0</a></td></tr>
+ * </table>
+ *
+ * <a name="default_locale"></a><h4>Be wary of the default locale</h3>
+ * <p>Note that there are many convenience methods that automatically use the default locale, but
+ * using them may lead to subtle bugs.
+ *
+ * <p>The default locale is appropriate for tasks that involve presenting data to the user. In
+ * this case, you want to use the user's date/time formats, number
+ * formats, rules for conversion to lowercase, and so on. In this case, it's safe to use the
+ * convenience methods.
+ *
+ * <p>The default locale is <i>not</i> appropriate for machine-readable output. The best choice
+ * there is usually {@code Locale.US}&nbsp;&ndash; this locale is guaranteed to be available on all
+ * devices, and the fact that it has no surprising special cases and is frequently used (especially
+ * for computer-computer communication) means that it tends to be the most efficient choice too.
+ *
+ * <p>A common mistake is to implicitly use the default locale when producing output meant to be
+ * machine-readable. This tends to work on the developer's test devices (especially because so many
+ * developers use en_US), but fails when run on a device whose user is in a more complex locale.
+ *
+ * <p>For example, if you're formatting integers some locales will use non-ASCII decimal
+ * digits. As another example, if you're formatting floating-point numbers some locales will use
+ * {@code ','} as the decimal point and {@code '.'} for digit grouping. That's correct for
+ * human-readable output, but likely to cause problems if presented to another
+ * computer ({@link Double#parseDouble} can't parse such a number, for example).
+ * You should also be wary of the {@link String#toLowerCase} and
+ * {@link String#toUpperCase} overloads that don't take a {@code Locale}: in Turkey, for example,
+ * the characters {@code 'i'} and {@code 'I'} won't be converted to {@code 'I'} and {@code 'i'}.
+ * This is the correct behavior for Turkish text (such as user input), but inappropriate for, say,
+ * HTTP headers.
+ *
+ * @see Builder
+ * @see ResourceBundle
+ * @see java.text.Format
+ * @see java.text.NumberFormat
+ * @see java.text.Collator
+ * @author Mark Davis
+ * @since 1.1
+ */
+public final class Locale implements Cloneable, Serializable {
+
+    static private final  Cache LOCALECACHE = new Cache();
+
+    /** Useful constant for language.
+     */
+    static public final Locale ENGLISH = createConstant("en", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale FRENCH = createConstant("fr", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale GERMAN = createConstant("de", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale ITALIAN = createConstant("it", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale JAPANESE = createConstant("ja", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale KOREAN = createConstant("ko", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale CHINESE = createConstant("zh", "");
+
+    /** Useful constant for language.
+     */
+    static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
+
+    /** Useful constant for language.
+     */
+    static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
+
+    /** Useful constant for country.
+     */
+    static public final Locale FRANCE = createConstant("fr", "FR");
+
+    /** Useful constant for country.
+     */
+    static public final Locale GERMANY = createConstant("de", "DE");
+
+    /** Useful constant for country.
+     */
+    static public final Locale ITALY = createConstant("it", "IT");
+
+    /** Useful constant for country.
+     */
+    static public final Locale JAPAN = createConstant("ja", "JP");
+
+    /** Useful constant for country.
+     */
+    static public final Locale KOREA = createConstant("ko", "KR");
+
+    /** Useful constant for country.
+     */
+    static public final Locale CHINA = SIMPLIFIED_CHINESE;
+
+    /** Useful constant for country.
+     */
+    static public final Locale PRC = SIMPLIFIED_CHINESE;
+
+    /** Useful constant for country.
+     */
+    static public final Locale TAIWAN = TRADITIONAL_CHINESE;
+
+    /** Useful constant for country.
+     */
+    static public final Locale UK = createConstant("en", "GB");
+
+    /** Useful constant for country.
+     */
+    static public final Locale US = createConstant("en", "US");
+
+    /** Useful constant for country.
+     */
+    static public final Locale CANADA = createConstant("en", "CA");
+
+    /** Useful constant for country.
+     */
+    static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
+
+    // Android-added: (internal only): ISO 639-3 generic code for undetermined languages.
+    private static final String UNDETERMINED_LANGUAGE = "und";
+
+    /**
+     * Useful constant for the root locale.  The root locale is the locale whose
+     * language, country, and variant are empty ("") strings.  This is regarded
+     * as the base locale of all locales, and is used as the language/country
+     * neutral locale for the locale sensitive operations.
+     *
+     * @since 1.6
+     */
+    static public final Locale ROOT = createConstant("", "");
+
+    /**
+     * The key for the private use extension ('x').
+     *
+     * @see #getExtension(char)
+     * @see Builder#setExtension(char, String)
+     * @since 1.7
+     */
+    static public final char PRIVATE_USE_EXTENSION = 'x';
+
+    /**
+     * The key for Unicode locale extension ('u').
+     *
+     * @see #getExtension(char)
+     * @see Builder#setExtension(char, String)
+     * @since 1.7
+     */
+    static public final char UNICODE_LOCALE_EXTENSION = 'u';
+
+    /** serialization ID
+     */
+    static final long serialVersionUID = 9149081749638150636L;
+
+    /**
+     * Display types for retrieving localized names from the name providers.
+     */
+    private static final int DISPLAY_LANGUAGE = 0;
+    private static final int DISPLAY_COUNTRY  = 1;
+    private static final int DISPLAY_VARIANT  = 2;
+    private static final int DISPLAY_SCRIPT   = 3;
+
+    /**
+     * Private constructor used by getInstance method
+     */
+    private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
+        this.baseLocale = baseLocale;
+        this.localeExtensions = extensions;
+    }
+
+    /**
+     * Construct a locale from language, country and variant.
+     * This constructor normalizes the language value to lowercase and
+     * the country value to uppercase.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard; some of the language codes it defines
+     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
+     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
+     * API on Locale will return only the OLD codes.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
+     * see <a href="#special_cases_constructor">Special Cases</a> for more information.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the <code>Locale</code> class description about
+     * valid language values.
+     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
+     * See the <code>Locale</code> class description about valid country values.
+     * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
+     * See the <code>Locale</code> class description for the details.
+     * @exception NullPointerException thrown if any argument is null.
+     */
+    public Locale(String language, String country, String variant) {
+        if (language== null || country == null || variant == null) {
+            throw new NullPointerException();
+        }
+        baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
+        localeExtensions = getCompatibilityExtensions(language, "", country, variant);
+    }
+
+    /**
+     * Construct a locale from language and country.
+     * This constructor normalizes the language value to lowercase and
+     * the country value to uppercase.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard; some of the language codes it defines
+     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
+     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
+     * API on Locale will return only the OLD codes.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the <code>Locale</code> class description about
+     * valid language values.
+     * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
+     * See the <code>Locale</code> class description about valid country values.
+     * @exception NullPointerException thrown if either argument is null.
+     */
+    public Locale(String language, String country) {
+        this(language, country, "");
+    }
+
+    /**
+     * Construct a locale from a language code.
+     * This constructor normalizes the language value to lowercase.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard; some of the language codes it defines
+     * (specifically "iw", "ji", and "in") have changed.  This constructor accepts both the
+     * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
+     * API on Locale will return only the OLD codes.
+     * <li>For backward compatibility reasons, this constructor does not make
+     * any syntactic checks on the input.
+     * </ul>
+     *
+     * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
+     * up to 8 characters in length.  See the <code>Locale</code> class description about
+     * valid language values.
+     * @exception NullPointerException thrown if argument is null.
+     * @since 1.4
+     */
+    public Locale(String language) {
+        this(language, "", "");
+    }
+
+    /**
+     * This method must be called only for creating the Locale.*
+     * constants due to making shortcuts.
+     */
+    private static Locale createConstant(String lang, String country) {
+        BaseLocale base = BaseLocale.createInstance(lang, country);
+        return getInstance(base, null);
+    }
+
+    /**
+     * Returns a <code>Locale</code> constructed from the given
+     * <code>language</code>, <code>country</code> and
+     * <code>variant</code>. If the same <code>Locale</code> instance
+     * is available in the cache, then that instance is
+     * returned. Otherwise, a new <code>Locale</code> instance is
+     * created and cached.
+     *
+     * @param language lowercase 2 to 8 language code.
+     * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code.
+     * @param variant vendor and browser specific code. See class description.
+     * @return the <code>Locale</code> instance requested
+     * @exception NullPointerException if any argument is null.
+     */
+    static Locale getInstance(String language, String country, String variant) {
+        return getInstance(language, "", country, variant, null);
+    }
+
+    static Locale getInstance(String language, String script, String country,
+                                      String variant, LocaleExtensions extensions) {
+        if (language== null || script == null || country == null || variant == null) {
+            throw new NullPointerException();
+        }
+
+        if (extensions == null) {
+            extensions = getCompatibilityExtensions(language, script, country, variant);
+        }
+
+        BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant);
+        return getInstance(baseloc, extensions);
+    }
+
+    static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
+        LocaleKey key = new LocaleKey(baseloc, extensions);
+        return LOCALECACHE.get(key);
+    }
+
+    private static class Cache extends LocaleObjectCache<LocaleKey, Locale> {
+        private Cache() {
+        }
+
+        @Override
+        protected Locale createObject(LocaleKey key) {
+            return new Locale(key.base, key.exts);
+        }
+    }
+
+    private static final class LocaleKey {
+        private final BaseLocale base;
+        private final LocaleExtensions exts;
+        private final int hash;
+
+        private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
+            base = baseLocale;
+            exts = extensions;
+
+            // Calculate the hash value here because it's always used.
+            int h = base.hashCode();
+            if (exts != null) {
+                h ^= exts.hashCode();
+            }
+            hash = h;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof LocaleKey)) {
+                return false;
+            }
+            LocaleKey other = (LocaleKey)obj;
+            if (hash != other.hash || !base.equals(other.base)) {
+                return false;
+            }
+            if (exts == null) {
+                return other.exts == null;
+            }
+            return exts.equals(other.exts);
+        }
+
+        @Override
+        public int hashCode() {
+            return hash;
+        }
+    }
+
+    /**
+     * Gets the current value of the default locale for this instance
+     * of the Java Virtual Machine.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup
+     * based on the host environment. It is used by many locale-sensitive
+     * methods if no locale is explicitly specified.
+     * It can be changed using the
+     * {@link #setDefault(java.util.Locale) setDefault} method.
+     *
+     * @return the default locale for this instance of the Java Virtual Machine
+     */
+    public static Locale getDefault() {
+        // do not synchronize this method - see 4071298
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        // return defaultLocale;
+        return NoImagePreloadHolder.defaultLocale;
+    }
+
+    /**
+     * Gets the current value of the default locale for the specified Category
+     * for this instance of the Java Virtual Machine.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup based
+     * on the host environment. It is used by many locale-sensitive methods
+     * if no locale is explicitly specified. It can be changed using the
+     * setDefault(Locale.Category, Locale) method.
+     *
+     * @param category - the specified category to get the default locale
+     * @throws NullPointerException - if category is null
+     * @return the default locale for the specified Category for this instance
+     *     of the Java Virtual Machine
+     * @see #setDefault(Locale.Category, Locale)
+     * @since 1.7
+     */
+    public static Locale getDefault(Locale.Category category) {
+        // do not synchronize this method - see 4071298
+        switch (category) {
+        case DISPLAY:
+            if (defaultDisplayLocale == null) {
+                synchronized(Locale.class) {
+                    if (defaultDisplayLocale == null) {
+                        defaultDisplayLocale = initDefault(category);
+                    }
+                }
+            }
+            return defaultDisplayLocale;
+        case FORMAT:
+            if (defaultFormatLocale == null) {
+                synchronized(Locale.class) {
+                    if (defaultFormatLocale == null) {
+                        defaultFormatLocale = initDefault(category);
+                    }
+                }
+            }
+            return defaultFormatLocale;
+        default:
+            assert false: "Unknown Category";
+        }
+        return getDefault();
+    }
+
+    /**
+     * @hide visible for testing.
+     */
+    // Android-changed: Make initDefault() @hide public for testing.
+    // private static Locale initDefault() {
+    public static Locale initDefault() {
+        // BEGIN Android-added: In initDefault(), prioritize user.locale.
+        // user.locale gets priority
+        final String languageTag = System.getProperty("user.locale", "");
+        if (!languageTag.isEmpty()) {
+            return Locale.forLanguageTag(languageTag);
+        }
+        // END Android-added: In initDefault(), prioritize user.locale.
+
+        // BEGIN Android-changed: Short-circuit legacy security code.
+        // Use System.getProperty(name, default) instead of
+        // AccessController.doPrivileged(new GetPropertyAction(name, default)).
+        String language, region, script, country, variant;
+        language = System.getProperty("user.language", "en");
+        // for compatibility, check for old user.region property
+        region = System.getProperty("user.region");
+        if (region != null) {
+            // region can be of form country, country_variant, or _variant
+            int i = region.indexOf('_');
+            if (i >= 0) {
+                country = region.substring(0, i);
+                variant = region.substring(i + 1);
+            } else {
+                country = region;
+                variant = "";
+            }
+            script = "";
+        } else {
+            script = System.getProperty("user.script", "");
+            country = System.getProperty("user.country", "");
+            variant = System.getProperty("user.variant", "");
+        }
+        // END Android-changed: Short-circuit legacy security code.
+
+        return getInstance(language, script, country, variant, null);
+    }
+
+    private static Locale initDefault(Locale.Category category) {
+        // Android-added: Add NoImagePreloadHolder to allow compile-time initialization.
+        final Locale defaultLocale = NoImagePreloadHolder.defaultLocale;
+        // BEGIN Android-changed: Short-circuit legacy security code.
+        /*
+        return getInstance(
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
+            null);
+        */
+        return getInstance(
+            System.getProperty(category.languageKey, defaultLocale.getLanguage()),
+            System.getProperty(category.scriptKey, defaultLocale.getScript()),
+            System.getProperty(category.countryKey, defaultLocale.getCountry()),
+            System.getProperty(category.variantKey, defaultLocale.getVariant()),
+            null);
+        // END Android-changed: Short-circuit legacy security code.
+    }
+
+    /**
+     * Sets the default locale for this instance of the Java Virtual Machine.
+     * This does not affect the host locale.
+     * <p>
+     * If there is a security manager, its <code>checkPermission</code>
+     * method is called with a <code>PropertyPermission("user.language", "write")</code>
+     * permission before the default locale is changed.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup
+     * based on the host environment. It is used by many locale-sensitive
+     * methods if no locale is explicitly specified.
+     * <p>
+     * Since changing the default locale may affect many different areas
+     * of functionality, this method should only be used if the caller
+     * is prepared to reinitialize locale-sensitive code running
+     * within the same Java Virtual Machine.
+     * <p>
+     * By setting the default locale with this method, all of the default
+     * locales for each Category are also set to the specified default locale.
+     *
+     * @throws SecurityException
+     *        if a security manager exists and its
+     *        <code>checkPermission</code> method doesn't allow the operation.
+     * @throws NullPointerException if <code>newLocale</code> is null
+     * @param newLocale the new default locale
+     * @see SecurityManager#checkPermission
+     * @see java.util.PropertyPermission
+     */
+    public static synchronized void setDefault(Locale newLocale) {
+        setDefault(Category.DISPLAY, newLocale);
+        setDefault(Category.FORMAT, newLocale);
+        // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+        // defaultLocale = newLocale;
+        NoImagePreloadHolder.defaultLocale = newLocale;
+        // Android-added: Keep ICU state in sync with java.util.
+        ICU.setDefaultLocale(newLocale.toLanguageTag());
+    }
+
+    /**
+     * Sets the default locale for the specified Category for this instance
+     * of the Java Virtual Machine. This does not affect the host locale.
+     * <p>
+     * If there is a security manager, its checkPermission method is called
+     * with a PropertyPermission("user.language", "write") permission before
+     * the default locale is changed.
+     * <p>
+     * The Java Virtual Machine sets the default locale during startup based
+     * on the host environment. It is used by many locale-sensitive methods
+     * if no locale is explicitly specified.
+     * <p>
+     * Since changing the default locale may affect many different areas of
+     * functionality, this method should only be used if the caller is
+     * prepared to reinitialize locale-sensitive code running within the
+     * same Java Virtual Machine.
+     * <p>
+     *
+     * @param category - the specified category to set the default locale
+     * @param newLocale - the new default locale
+     * @throws SecurityException - if a security manager exists and its
+     *     checkPermission method doesn't allow the operation.
+     * @throws NullPointerException - if category and/or newLocale is null
+     * @see SecurityManager#checkPermission(java.security.Permission)
+     * @see PropertyPermission
+     * @see #getDefault(Locale.Category)
+     * @since 1.7
+     */
+    public static synchronized void setDefault(Locale.Category category,
+        Locale newLocale) {
+        if (category == null)
+            throw new NullPointerException("Category cannot be NULL");
+        if (newLocale == null)
+            throw new NullPointerException("Can't set default locale to NULL");
+
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) sm.checkPermission(new PropertyPermission
+                        ("user.language", "write"));
+        switch (category) {
+        case DISPLAY:
+            defaultDisplayLocale = newLocale;
+            break;
+        case FORMAT:
+            defaultFormatLocale = newLocale;
+            break;
+        default:
+            assert false: "Unknown Category";
+        }
+    }
+
+    // Android-changed: Removed documentation references to LocaleServiceProvider.
+    /**
+     * Returns an array of all installed locales.
+     *
+     * @return An array of installed locales.
+     */
+    public static Locale[] getAvailableLocales() {
+        // Android-changed: Use ICU.
+        // return LocaleServiceProviderPool.getAllAvailableLocales();
+        return ICU.getAvailableLocales();
+    }
+
+    /**
+     * Returns a list of all 2-letter country codes defined in ISO 3166.
+     * Can be used to create Locales.
+     * <p>
+     * <b>Note:</b> The <code>Locale</code> class also supports other codes for
+     * country (region), such as 3-letter numeric UN M.49 area codes.
+     * Therefore, the list returned by this method does not contain ALL valid
+     * codes that can be used to create Locales.
+     *
+     * @return An array of ISO 3166 two-letter country codes.
+     */
+    public static String[] getISOCountries() {
+        // Android-changed: Use ICU.
+        /*
+        if (isoCountries == null) {
+            isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
+        }
+        String[] result = new String[isoCountries.length];
+        System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
+        return result;
+        */
+        return ICU.getISOCountries();
+    }
+
+    /**
+     * Returns a list of all 2-letter language codes defined in ISO 639.
+     * Can be used to create Locales.
+     * <p>
+     * <b>Note:</b>
+     * <ul>
+     * <li>ISO 639 is not a stable standard&mdash; some languages' codes have changed.
+     * The list this function returns includes both the new and the old codes for the
+     * languages whose codes have changed.
+     * <li>The <code>Locale</code> class also supports language codes up to
+     * 8 characters in length.  Therefore, the list returned by this method does
+     * not contain ALL valid codes that can be used to create Locales.
+     * </ul>
+     *
+     * @return Am array of ISO 639 two-letter language codes.
+     */
+    public static String[] getISOLanguages() {
+        // Android-changed: Use ICU.
+        /*
+        if (isoLanguages == null) {
+            isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
+        }
+        String[] result = new String[isoLanguages.length];
+        System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
+        return result;
+        */
+        return ICU.getISOLanguages();
+    }
+
+    // Android-removed: Use ICU.
+    // Private helper method getISO2Table(), unused on Android.
+    /*
+    private static String[] getISO2Table(String table) {
+        int len = table.length() / 5;
+        String[] isoTable = new String[len];
+        for (int i = 0, j = 0; i < len; i++, j += 5) {
+            isoTable[i] = table.substring(j, j + 2);
+        }
+        return isoTable;
+    }
+    */
+
+    /**
+     * Returns the language code of this Locale.
+     *
+     * <p><b>Note:</b> ISO 639 is not a stable standard&mdash; some languages' codes have changed.
+     * Locale's constructor recognizes both the new and the old codes for the languages
+     * whose codes have changed, but this function always returns the old code.  If you
+     * want to check for a specific language whose code has changed, don't do
+     * <pre>
+     * if (locale.getLanguage().equals("he")) // BAD!
+     *    ...
+     * </pre>
+     * Instead, do
+     * <pre>
+     * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
+     *    ...
+     * </pre>
+     * @return The language code, or the empty string if none is defined.
+     * @see #getDisplayLanguage
+     */
+    public String getLanguage() {
+        return baseLocale.getLanguage();
+    }
+
+    /**
+     * Returns the script for this locale, which should
+     * either be the empty string or an ISO 15924 4-letter script
+     * code. The first letter is uppercase and the rest are
+     * lowercase, for example, 'Latn', 'Cyrl'.
+     *
+     * @return The script code, or the empty string if none is defined.
+     * @see #getDisplayScript
+     * @since 1.7
+     */
+    public String getScript() {
+        return baseLocale.getScript();
+    }
+
+    /**
+     * Returns the country/region code for this locale, which should
+     * either be the empty string, an uppercase ISO 3166 2-letter code,
+     * or a UN M.49 3-digit code.
+     *
+     * @return The country/region code, or the empty string if none is defined.
+     * @see #getDisplayCountry
+     */
+    public String getCountry() {
+        return baseLocale.getRegion();
+    }
+
+    /**
+     * Returns the variant code for this locale.
+     *
+     * @return The variant code, or the empty string if none is defined.
+     * @see #getDisplayVariant
+     */
+    public String getVariant() {
+        return baseLocale.getVariant();
+    }
+
+    /**
+     * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
+     * extensions</a>.
+     *
+     * @return {@code true} if this {@code Locale} has any extensions
+     * @since 1.8
+     */
+    public boolean hasExtensions() {
+        return localeExtensions != null;
+    }
+
+    /**
+     * Returns a copy of this {@code Locale} with no <a href="#def_extensions">
+     * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}
+     * is returned.
+     *
+     * @return a copy of this {@code Locale} with no extensions, or {@code this}
+     *         if {@code this} has no extensions
+     * @since 1.8
+     */
+    public Locale stripExtensions() {
+        return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;
+    }
+
+    /**
+     * Returns the extension (or private use) value associated with
+     * the specified key, or null if there is no extension
+     * associated with the key. To be well-formed, the key must be one
+     * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
+     * for example 'z' and 'Z' represent the same extension.
+     *
+     * @param key the extension key
+     * @return The extension, or null if this locale defines no
+     * extension for the specified key.
+     * @throws IllegalArgumentException if key is not well-formed
+     * @see #PRIVATE_USE_EXTENSION
+     * @see #UNICODE_LOCALE_EXTENSION
+     * @since 1.7
+     */
+    public String getExtension(char key) {
+        if (!LocaleExtensions.isValidKey(key)) {
+            throw new IllegalArgumentException("Ill-formed extension key: " + key);
+        }
+        return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;
+    }
+
+    /**
+     * Returns the set of extension keys associated with this locale, or the
+     * empty set if it has no extensions. The returned set is unmodifiable.
+     * The keys will all be lower-case.
+     *
+     * @return The set of extension keys, or the empty set if this locale has
+     * no extensions.
+     * @since 1.7
+     */
+    public Set<Character> getExtensionKeys() {
+        if (!hasExtensions()) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getKeys();
+    }
+
+    /**
+     * Returns the set of unicode locale attributes associated with
+     * this locale, or the empty set if it has no attributes. The
+     * returned set is unmodifiable.
+     *
+     * @return The set of attributes.
+     * @since 1.7
+     */
+    public Set<String> getUnicodeLocaleAttributes() {
+        if (!hasExtensions()) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getUnicodeLocaleAttributes();
+    }
+
+    /**
+     * Returns the Unicode locale type associated with the specified Unicode locale key
+     * for this locale. Returns the empty string for keys that are defined with no type.
+     * Returns null if the key is not defined. Keys are case-insensitive. The key must
+     * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
+     * thrown.
+     *
+     * @param key the Unicode locale key
+     * @return The Unicode locale type associated with the key, or null if the
+     * locale does not define the key.
+     * @throws IllegalArgumentException if the key is not well-formed
+     * @throws NullPointerException if <code>key</code> is null
+     * @since 1.7
+     */
+    public String getUnicodeLocaleType(String key) {
+        if (!isUnicodeExtensionKey(key)) {
+            throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
+        }
+        return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null;
+    }
+
+    /**
+     * Returns the set of Unicode locale keys defined by this locale, or the empty set if
+     * this locale has none.  The returned set is immutable.  Keys are all lower case.
+     *
+     * @return The set of Unicode locale keys, or the empty set if this locale has
+     * no Unicode locale keywords.
+     * @since 1.7
+     */
+    public Set<String> getUnicodeLocaleKeys() {
+        if (localeExtensions == null) {
+            return Collections.emptySet();
+        }
+        return localeExtensions.getUnicodeLocaleKeys();
+    }
+
+    /**
+     * Package locale method returning the Locale's BaseLocale,
+     * used by ResourceBundle
+     * @return base locale of this Locale
+     */
+    BaseLocale getBaseLocale() {
+        return baseLocale;
+    }
+
+    /**
+     * Package private method returning the Locale's LocaleExtensions,
+     * used by ResourceBundle.
+     * @return locale exnteions of this Locale,
+     *         or {@code null} if no extensions are defined
+     */
+     LocaleExtensions getLocaleExtensions() {
+         return localeExtensions;
+     }
+
+    /**
+     * Returns a string representation of this <code>Locale</code>
+     * object, consisting of language, country, variant, script,
+     * and extensions as below:
+     * <blockquote>
+     * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
+     * </blockquote>
+     *
+     * Language is always lower case, country is always upper case, script is always title
+     * case, and extensions are always lower case.  Extensions and private use subtags
+     * will be in canonical order as explained in {@link #toLanguageTag}.
+     *
+     * <p>When the locale has neither script nor extensions, the result is the same as in
+     * Java 6 and prior.
+     *
+     * <p>If both the language and country fields are missing, this function will return
+     * the empty string, even if the variant, script, or extensions field is present (you
+     * can't have a locale with just a variant, the variant must accompany a well-formed
+     * language or country code).
+     *
+     * <p>If script or extensions are present and variant is missing, no underscore is
+     * added before the "#".
+     *
+     * <p>This behavior is designed to support debugging and to be compatible with
+     * previous uses of <code>toString</code> that expected language, country, and variant
+     * fields only.  To represent a Locale as a String for interchange purposes, use
+     * {@link #toLanguageTag}.
+     *
+     * <p>Examples: <ul>
+     * <li><tt>en</tt></li>
+     * <li><tt>de_DE</tt></li>
+     * <li><tt>_GB</tt></li>
+     * <li><tt>en_US_WIN</tt></li>
+     * <li><tt>de__POSIX</tt></li>
+     * <li><tt>zh_CN_#Hans</tt></li>
+     * <li><tt>zh_TW_#Hant-x-java</tt></li>
+     * <li><tt>th_TH_TH_#u-nu-thai</tt></li></ul>
+     *
+     * @return A string representation of the Locale, for debugging.
+     * @see #getDisplayName
+     * @see #toLanguageTag
+     */
+    @Override
+    public final String toString() {
+        boolean l = (baseLocale.getLanguage().length() != 0);
+        boolean s = (baseLocale.getScript().length() != 0);
+        boolean r = (baseLocale.getRegion().length() != 0);
+        boolean v = (baseLocale.getVariant().length() != 0);
+        boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
+
+        StringBuilder result = new StringBuilder(baseLocale.getLanguage());
+        if (r || (l && (v || s || e))) {
+            result.append('_')
+                .append(baseLocale.getRegion()); // This may just append '_'
+        }
+        if (v && (l || r)) {
+            result.append('_')
+                .append(baseLocale.getVariant());
+        }
+
+        if (s && (l || r)) {
+            result.append("_#")
+                .append(baseLocale.getScript());
+        }
+
+        if (e && (l || r)) {
+            result.append('_');
+            if (!s) {
+                result.append('#');
+            }
+            result.append(localeExtensions.getID());
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Returns a well-formed IETF BCP 47 language tag representing
+     * this locale.
+     *
+     * <p>If this <code>Locale</code> has a language, country, or
+     * variant that does not satisfy the IETF BCP 47 language tag
+     * syntax requirements, this method handles these fields as
+     * described below:
+     *
+     * <p><b>Language:</b> If language is empty, or not <a
+     * href="#def_language" >well-formed</a> (for example "a" or
+     * "e2"), it will be emitted as "und" (Undetermined).
+     *
+     * <p><b>Country:</b> If country is not <a
+     * href="#def_region">well-formed</a> (for example "12" or "USA"),
+     * it will be omitted.
+     *
+     * <p><b>Variant:</b> If variant <b>is</b> <a
+     * href="#def_variant">well-formed</a>, each sub-segment
+     * (delimited by '-' or '_') is emitted as a subtag.  Otherwise:
+     * <ul>
+     *
+     * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
+     * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
+     * ill-formed sub-segment and all following will be appended to
+     * the private use subtag.  The first appended subtag will be
+     * "lvariant", followed by the sub-segments in order, separated by
+     * hyphen. For example, "x-lvariant-WIN",
+     * "Oracle-x-lvariant-JDK-Standard-Edition".
+     *
+     * <li>if any sub-segment does not match
+     * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
+     * and the problematic sub-segment and all following sub-segments
+     * will be omitted.  If the remainder is non-empty, it will be
+     * emitted as a private use subtag as above (even if the remainder
+     * turns out to be well-formed).  For example,
+     * "Solaris_isjustthecoolestthing" is emitted as
+     * "x-lvariant-Solaris", not as "solaris".</li></ul>
+     *
+     * <p><b>Special Conversions:</b> Java supports some old locale
+     * representations, including deprecated ISO language codes,
+     * for compatibility. This method performs the following
+     * conversions:
+     * <ul>
+     *
+     * <li>Deprecated ISO language codes "iw", "ji", and "in" are
+     * converted to "he", "yi", and "id", respectively.
+     *
+     * <li>A locale with language "no", country "NO", and variant
+     * "NY", representing Norwegian Nynorsk (Norway), is converted
+     * to a language tag "nn-NO".</li></ul>
+     *
+     * <p><b>Note:</b> Although the language tag created by this
+     * method is well-formed (satisfies the syntax requirements
+     * defined by the IETF BCP 47 specification), it is not
+     * necessarily a valid BCP 47 language tag.  For example,
+     * <pre>
+     *   new Locale("xx", "YY").toLanguageTag();</pre>
+     *
+     * will return "xx-YY", but the language subtag "xx" and the
+     * region subtag "YY" are invalid because they are not registered
+     * in the IANA Language Subtag Registry.
+     *
+     * @return a BCP47 language tag representing the locale
+     * @see #forLanguageTag(String)
+     * @since 1.7
+     */
+    public String toLanguageTag() {
+        if (languageTag != null) {
+            return languageTag;
+        }
+
+        LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
+        StringBuilder buf = new StringBuilder();
+
+        String subtag = tag.getLanguage();
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.canonicalizeLanguage(subtag));
+        }
+
+        subtag = tag.getScript();
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeScript(subtag));
+        }
+
+        subtag = tag.getRegion();
+        if (subtag.length() > 0) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeRegion(subtag));
+        }
+
+        List<String>subtags = tag.getVariants();
+        for (String s : subtags) {
+            buf.append(LanguageTag.SEP);
+            // preserve casing
+            buf.append(s);
+        }
+
+        subtags = tag.getExtensions();
+        for (String s : subtags) {
+            buf.append(LanguageTag.SEP);
+            buf.append(LanguageTag.canonicalizeExtension(s));
+        }
+
+        subtag = tag.getPrivateuse();
+        if (subtag.length() > 0) {
+            if (buf.length() > 0) {
+                buf.append(LanguageTag.SEP);
+            }
+            buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
+            // preserve casing
+            buf.append(subtag);
+        }
+
+        String langTag = buf.toString();
+        synchronized (this) {
+            if (languageTag == null) {
+                languageTag = langTag;
+            }
+        }
+        return languageTag;
+    }
+
+    /**
+     * Returns a locale for the specified IETF BCP 47 language tag string.
+     *
+     * <p>If the specified language tag contains any ill-formed subtags,
+     * the first such subtag and all following subtags are ignored.  Compare
+     * to {@link Locale.Builder#setLanguageTag} which throws an exception
+     * in this case.
+     *
+     * <p>The following <b>conversions</b> are performed:<ul>
+     *
+     * <li>The language code "und" is mapped to language "".
+     *
+     * <li>The language codes "he", "yi", and "id" are mapped to "iw",
+     * "ji", and "in" respectively. (This is the same canonicalization
+     * that's done in Locale's constructors.)
+     *
+     * <li>The portion of a private use subtag prefixed by "lvariant",
+     * if any, is removed and appended to the variant field in the
+     * result locale (without case normalization).  If it is then
+     * empty, the private use subtag is discarded:
+     *
+     * <pre>
+     *     Locale loc;
+     *     loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
+     *     loc.getVariant(); // returns "POSIX"
+     *     loc.getExtension('x'); // returns null
+     *
+     *     loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
+     *     loc.getVariant(); // returns "POSIX_Abc_Def"
+     *     loc.getExtension('x'); // returns "urp"
+     * </pre>
+     *
+     * <li>When the languageTag argument contains an extlang subtag,
+     * the first such subtag is used as the language, and the primary
+     * language subtag and other extlang subtags are ignored:
+     *
+     * <pre>
+     *     Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
+     *     Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
+     * </pre>
+     *
+     * <li>Case is normalized except for variant tags, which are left
+     * unchanged.  Language is normalized to lower case, script to
+     * title case, country to upper case, and extensions to lower
+     * case.
+     *
+     * <li>If, after processing, the locale would exactly match either
+     * ja_JP_JP or th_TH_TH with no extensions, the appropriate
+     * extensions are added as though the constructor had been called:
+     *
+     * <pre>
+     *    Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
+     *    // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
+     *    Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
+     *    // returns "th-TH-u-nu-thai-x-lvariant-TH"
+     * </pre></ul>
+     *
+     * <p>This implements the 'Language-Tag' production of BCP47, and
+     * so supports grandfathered (regular and irregular) as well as
+     * private use language tags.  Stand alone private use tags are
+     * represented as empty language and extension 'x-whatever',
+     * and grandfathered tags are converted to their canonical replacements
+     * where they exist.
+     *
+     * <p>Grandfathered tags with canonical replacements are as follows:
+     *
+     * <table summary="Grandfathered tags with canonical replacements">
+     * <tbody align="center">
+     * <tr><th>grandfathered tag</th><th>&nbsp;</th><th>modern replacement</th></tr>
+     * <tr><td>art-lojban</td><td>&nbsp;</td><td>jbo</td></tr>
+     * <tr><td>i-ami</td><td>&nbsp;</td><td>ami</td></tr>
+     * <tr><td>i-bnn</td><td>&nbsp;</td><td>bnn</td></tr>
+     * <tr><td>i-hak</td><td>&nbsp;</td><td>hak</td></tr>
+     * <tr><td>i-klingon</td><td>&nbsp;</td><td>tlh</td></tr>
+     * <tr><td>i-lux</td><td>&nbsp;</td><td>lb</td></tr>
+     * <tr><td>i-navajo</td><td>&nbsp;</td><td>nv</td></tr>
+     * <tr><td>i-pwn</td><td>&nbsp;</td><td>pwn</td></tr>
+     * <tr><td>i-tao</td><td>&nbsp;</td><td>tao</td></tr>
+     * <tr><td>i-tay</td><td>&nbsp;</td><td>tay</td></tr>
+     * <tr><td>i-tsu</td><td>&nbsp;</td><td>tsu</td></tr>
+     * <tr><td>no-bok</td><td>&nbsp;</td><td>nb</td></tr>
+     * <tr><td>no-nyn</td><td>&nbsp;</td><td>nn</td></tr>
+     * <tr><td>sgn-BE-FR</td><td>&nbsp;</td><td>sfb</td></tr>
+     * <tr><td>sgn-BE-NL</td><td>&nbsp;</td><td>vgt</td></tr>
+     * <tr><td>sgn-CH-DE</td><td>&nbsp;</td><td>sgg</td></tr>
+     * <tr><td>zh-guoyu</td><td>&nbsp;</td><td>cmn</td></tr>
+     * <tr><td>zh-hakka</td><td>&nbsp;</td><td>hak</td></tr>
+     * <tr><td>zh-min-nan</td><td>&nbsp;</td><td>nan</td></tr>
+     * <tr><td>zh-xiang</td><td>&nbsp;</td><td>hsn</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>Grandfathered tags with no modern replacement will be
+     * converted as follows:
+     *
+     * <table summary="Grandfathered tags with no modern replacement">
+     * <tbody align="center">
+     * <tr><th>grandfathered tag</th><th>&nbsp;</th><th>converts to</th></tr>
+     * <tr><td>cel-gaulish</td><td>&nbsp;</td><td>xtg-x-cel-gaulish</td></tr>
+     * <tr><td>en-GB-oed</td><td>&nbsp;</td><td>en-GB-x-oed</td></tr>
+     * <tr><td>i-default</td><td>&nbsp;</td><td>en-x-i-default</td></tr>
+     * <tr><td>i-enochian</td><td>&nbsp;</td><td>und-x-i-enochian</td></tr>
+     * <tr><td>i-mingo</td><td>&nbsp;</td><td>see-x-i-mingo</td></tr>
+     * <tr><td>zh-min</td><td>&nbsp;</td><td>nan-x-zh-min</td></tr>
+     * </tbody>
+     * </table>
+     *
+     * <p>For a list of all grandfathered tags, see the
+     * IANA Language Subtag Registry (search for "Type: grandfathered").
+     *
+     * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
+     * and <code>forLanguageTag</code> will round-trip.
+     *
+     * @param languageTag the language tag
+     * @return The locale that best represents the language tag.
+     * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
+     * @see #toLanguageTag()
+     * @see java.util.Locale.Builder#setLanguageTag(String)
+     * @since 1.7
+     */
+    public static Locale forLanguageTag(String languageTag) {
+        LanguageTag tag = LanguageTag.parse(languageTag, null);
+        InternalLocaleBuilder bldr = new InternalLocaleBuilder();
+        bldr.setLanguageTag(tag);
+        BaseLocale base = bldr.getBaseLocale();
+        LocaleExtensions exts = bldr.getLocaleExtensions();
+        if (exts == null && base.getVariant().length() > 0) {
+            exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
+                                              base.getRegion(), base.getVariant());
+        }
+        return getInstance(base, exts);
+    }
+
+    /**
+     * Returns a three-letter abbreviation of this locale's language.
+     * If the language matches an ISO 639-1 two-letter code, the
+     * corresponding ISO 639-2/T three-letter lowercase code is
+     * returned.  The ISO 639-2 language codes can be found on-line,
+     * see "Codes for the Representation of Names of Languages Part 2:
+     * Alpha-3 Code".  If the locale specifies a three-letter
+     * language, the language is returned as is.  If the locale does
+     * not specify a language the empty string is returned.
+     *
+     * @return A three-letter abbreviation of this locale's language.
+     * @exception MissingResourceException Throws MissingResourceException if
+     * three-letter language abbreviation is not available for this locale.
+     */
+    public String getISO3Language() throws MissingResourceException {
+        String lang = baseLocale.getLanguage();
+        if (lang.length() == 3) {
+            return lang;
+        }
+        // BEGIN Android-added: app compat: Use "" as ISO3 for empty languages.
+        else if (lang.isEmpty()) {
+            return "";
+        }
+        // END Android-added: app compat: Use "" as ISO3 for empty languages.
+
+        // BEGIN Android-changed: Use ICU.
+        // String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
+        // if (language3 == null) {
+        String language3 = ICU.getISO3Language(lang);
+        if (!lang.isEmpty() && language3.isEmpty()) {
+        // END Android-changed: Use ICU.
+            throw new MissingResourceException("Couldn't find 3-letter language code for "
+                    + lang, "FormatData_" + toString(), "ShortLanguage");
+        }
+        return language3;
+    }
+
+    /**
+     * Returns a three-letter abbreviation for this locale's country.
+     * If the country matches an ISO 3166-1 alpha-2 code, the
+     * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
+     * If the locale doesn't specify a country, this will be the empty
+     * string.
+     *
+     * <p>The ISO 3166-1 codes can be found on-line.
+     *
+     * @return A three-letter abbreviation of this locale's country.
+     * @exception MissingResourceException Throws MissingResourceException if the
+     * three-letter country abbreviation is not available for this locale.
+     */
+    public String getISO3Country() throws MissingResourceException {
+        // BEGIN Android-changed: Use ICU. Also, use "" as ISO3 for missing regions.
+        // String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
+        // if (country3 == null) {
+        final String region = baseLocale.getRegion();
+        // Note that this will return an UN.M49 region code
+        if (region.length() == 3) {
+            return baseLocale.getRegion();
+        } else if (region.isEmpty()) {
+            return "";
+        }
+
+        // Prefix "en-" because ICU doesn't really care about what the language is.
+        String country3 = ICU.getISO3Country("en-" + region);
+        if (!region.isEmpty() && country3.isEmpty()) {
+        // END Android-changed: Use ICU. Also, use "" as ISO3 for missing regions.
+            throw new MissingResourceException("Couldn't find 3-letter country code for "
+                    + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
+        }
+        return country3;
+    }
+
+    // Android-removed: Use ICU.
+    // getISO3Code() is unused on Android.
+    /*
+    private static String getISO3Code(String iso2Code, String table) {
+        int codeLength = iso2Code.length();
+        if (codeLength == 0) {
+            return "";
+        }
+
+        int tableLength = table.length();
+        int index = tableLength;
+        if (codeLength == 2) {
+            char c1 = iso2Code.charAt(0);
+            char c2 = iso2Code.charAt(1);
+            for (index = 0; index < tableLength; index += 5) {
+                if (table.charAt(index) == c1
+                    && table.charAt(index + 1) == c2) {
+                    break;
+                }
+            }
+        }
+        return index < tableLength ? table.substring(index + 2, index + 5) : null;
+    }
+    */
+
+    /**
+     * Returns a name for the locale's language that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, if the locale is fr_FR and the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
+     * getDisplayLanguage() will return "anglais".
+     * If the name returned cannot be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale,
+     * (say, we don't have a Japanese name for Croatian),
+     * this function falls back on the English name, and uses the ISO code as a last-resort
+     * value.  If the locale doesn't specify a language, this function returns the empty string.
+     *
+     * @return The name of the display language.
+     */
+    public final String getDisplayLanguage() {
+        return getDisplayLanguage(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    // Use ICU; documentation; backwards compatibility hacks; added private helper methods.
+    /*
+    /**
+     * Returns a name for the locale's language that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized according to inLocale.
+     * For example, if the locale is fr_FR and inLocale
+     * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
+     * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
+     * If the name returned cannot be localized according to inLocale,
+     * (say, we don't have a Japanese name for Croatian),
+     * this function falls back on the English name, and finally
+     * on the ISO code as a last-resort value.  If the locale doesn't specify a language,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display language.
+     * @return The name of the display language appropriate to the given locale.
+     * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
+     *
+    public String getDisplayLanguage(Locale inLocale) {
+        return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
+    }
+    */
+    /**
+     * Returns the name of this locale's language, localized to {@code locale}.
+     * If the language name is unknown, the language code is returned.
+     */
+    public String getDisplayLanguage(Locale locale) {
+        String languageCode = baseLocale.getLanguage();
+        if (languageCode.isEmpty()) {
+            return "";
+        }
+
+        // Hacks for backward compatibility.
+        //
+        // Our language tag will contain "und" if the languageCode is invalid
+        // or missing. ICU will then return "langue indéterminée" or the equivalent
+        // display language for the indeterminate language code.
+        //
+        // Sigh... ugh... and what not.
+        final String normalizedLanguage = normalizeAndValidateLanguage(
+                languageCode, false /* strict */);
+        if (UNDETERMINED_LANGUAGE.equals(normalizedLanguage)) {
+            return languageCode;
+        }
+
+        // TODO: We need a new hack or a complete fix for http://b/8049507 --- We would
+        // cover the frameworks' tracks when they were using "tl" instead of "fil".
+        String result = LocaleNative.getDisplayLanguage(this, locale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayLanguage(this, Locale.getDefault());
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateLanguage(String language, boolean strict) {
+        if (language == null || language.isEmpty()) {
+            return "";
+        }
+
+        final String lowercaseLanguage = language.toLowerCase(Locale.ROOT);
+        if (!isValidBcp47Alpha(lowercaseLanguage, 2, 3)) {
+            if (strict) {
+                throw new IllformedLocaleException("Invalid language: " + language);
+            } else {
+                return UNDETERMINED_LANGUAGE;
+            }
+        }
+
+        return lowercaseLanguage;
+    }
+
+    /*
+     * Checks whether a given string is an ASCII alphanumeric string.
+     */
+    private static boolean isAsciiAlphaNum(String string) {
+        for (int i = 0; i < string.length(); i++) {
+            final char character = string.charAt(i);
+            if (!(character >= 'a' && character <= 'z' ||
+                    character >= 'A' && character <= 'Z' ||
+                    character >= '0' && character <= '9')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the the locale's script that is appropriate for display to
+     * the user. If possible, the name will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.  Returns
+     * the empty string if this locale doesn't specify a script code.
+     *
+     * @return the display name of the script code for the current default
+     *     {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @since 1.7
+     */
+    public String getDisplayScript() {
+        return getDisplayScript(getDefault(Category.DISPLAY));
+    }
+
+    /**
+     * Returns a name for the locale's script that is appropriate
+     * for display to the user. If possible, the name will be
+     * localized for the given locale. Returns the empty string if
+     * this locale doesn't specify a script code.
+     *
+     * @param inLocale The locale for which to retrieve the display script.
+     * @return the display name of the script code for the current default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
+     * @since 1.7
+     */
+    public String getDisplayScript(Locale inLocale) {
+        // BEGIN Android-changed: Use ICU.
+        // return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
+        String scriptCode = baseLocale.getScript();
+        if (scriptCode.isEmpty()) {
+            return "";
+        }
+
+        String result = LocaleNative.getDisplayScript(this, inLocale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayScript(this, Locale.getDefault(Category.DISPLAY));
+        }
+
+        return result;
+        // END Android-changed: Use ICU.
+    }
+
+    /**
+     * Returns a name for the locale's country that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.
+     * For example, if the locale is fr_FR and the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale
+     * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
+     * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
+     * getDisplayCountry() will return "Etats-Unis".
+     * If the name returned cannot be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale,
+     * (say, we don't have a Japanese name for Croatia),
+     * this function falls back on the English name, and uses the ISO code as a last-resort
+     * value.  If the locale doesn't specify a country, this function returns the empty string.
+     *
+     * @return The name of the country appropriate to the locale.
+     */
+    public final String getDisplayCountry() {
+        return getDisplayCountry(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    // Use ICU; documentation; added private helper methods.
+    /*
+    /**
+     * Returns a name for the locale's country that is appropriate for display to the
+     * user.
+     * If possible, the name returned will be localized according to inLocale.
+     * For example, if the locale is fr_FR and inLocale
+     * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
+     * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
+     * If the name returned cannot be localized according to inLocale.
+     * (say, we don't have a Japanese name for Croatia),
+     * this function falls back on the English name, and finally
+     * on the ISO code as a last-resort value.  If the locale doesn't specify a country,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display country.
+     * @return The name of the country appropriate to the given locale.
+     * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
+     *
+    public String getDisplayCountry(Locale inLocale) {
+        return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
+    }
+
+    private String getDisplayString(String code, Locale inLocale, int type) {
+        if (code.length() == 0) {
+            return "";
+        }
+
+        if (inLocale == null) {
+            throw new NullPointerException();
+        }
+
+        LocaleServiceProviderPool pool =
+            LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
+        String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
+        String result = pool.getLocalizedObject(
+                                LocaleNameGetter.INSTANCE,
+                                inLocale, key, type, code);
+            if (result != null) {
+                return result;
+            }
+
+        return code;
+    }
+    */
+    /**
+     * Returns the name of this locale's country, localized to {@code locale}.
+     * Returns the empty string if this locale does not correspond to a specific
+     * country.
+     */
+    public String getDisplayCountry(Locale locale) {
+        String countryCode = baseLocale.getRegion();
+        if (countryCode.isEmpty()) {
+            return "";
+        }
+
+        final String normalizedRegion = normalizeAndValidateRegion(
+                countryCode, false /* strict */);
+        if (normalizedRegion.isEmpty()) {
+            return countryCode;
+        }
+
+        String result = LocaleNative.getDisplayCountry(this, locale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayCountry(this, Locale.getDefault());
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateRegion(String region, boolean strict) {
+        if (region == null || region.isEmpty()) {
+            return "";
+        }
+
+        final String uppercaseRegion = region.toUpperCase(Locale.ROOT);
+        if (!isValidBcp47Alpha(uppercaseRegion, 2, 2) &&
+                !isUnM49AreaCode(uppercaseRegion)) {
+            if (strict) {
+                throw new IllformedLocaleException("Invalid region: " + region);
+            } else {
+                return "";
+            }
+        }
+
+        return uppercaseRegion;
+    }
+
+    private static boolean isValidBcp47Alpha(String string, int lowerBound, int upperBound) {
+        final int length = string.length();
+        if (length < lowerBound || length > upperBound) {
+            return false;
+        }
+
+        for (int i = 0; i < length; ++i) {
+            final char character = string.charAt(i);
+            if (!(character >= 'a' && character <= 'z' ||
+                    character >= 'A' && character <= 'Z')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * A UN M.49 is a 3 digit numeric code.
+     */
+    private static boolean isUnM49AreaCode(String code) {
+        if (code.length() != 3) {
+            return false;
+        }
+
+        for (int i = 0; i < 3; ++i) {
+            final char character = code.charAt(i);
+            if (!(character >= '0' && character <= '9')) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale's variant code that is appropriate for display to the
+     * user.  If possible, the name will be localized for the default
+     * {@link Locale.Category#DISPLAY DISPLAY} locale.  If the locale
+     * doesn't specify a variant code, this function returns the empty string.
+     *
+     * @return The name of the display variant code appropriate to the locale.
+     */
+    public final String getDisplayVariant() {
+        return getDisplayVariant(getDefault(Category.DISPLAY));
+    }
+
+    /**
+     * Returns a name for the locale's variant code that is appropriate for display to the
+     * user.  If possible, the name will be localized for inLocale.  If the locale
+     * doesn't specify a variant code, this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display variant code.
+     * @return The name of the display variant code appropriate to the given locale.
+     * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
+     */
+    public String getDisplayVariant(Locale inLocale) {
+// BEGIN Android-changed: Documentation and behavior of getDisplay*().
+// Use ICU; added private helper methods.
+/*
+        if (baseLocale.getVariant().length() == 0)
+            return "";
+
+        LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
+
+        String names[] = getDisplayVariantArray(inLocale);
+
+        // Get the localized patterns for formatting a list, and use
+        // them to format the list.
+        return formatList(names,
+                          lr.getLocaleName("ListPattern"),
+                          lr.getLocaleName("ListCompositionPattern"));
+    }
+*/
+        String variantCode = baseLocale.getVariant();
+        if (variantCode.isEmpty()) {
+            return "";
+        }
+
+        try {
+            normalizeAndValidateVariant(variantCode);
+        } catch (IllformedLocaleException ilfe) {
+            return variantCode;
+        }
+
+        String result = LocaleNative.getDisplayVariant(this, inLocale);
+        if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+            result = LocaleNative.getDisplayVariant(this, Locale.getDefault());
+        }
+
+        // The "old style" locale constructors allow us to pass in variants that aren't
+        // valid BCP-47 variant subtags. When that happens, toLanguageTag will not emit
+        // them. Note that we know variantCode.length() > 0 due to the isEmpty check at
+        // the beginning of this function.
+        if (result.isEmpty()) {
+            return variantCode;
+        }
+        return result;
+    }
+
+    private static String normalizeAndValidateVariant(String variant) {
+        if (variant == null || variant.isEmpty()) {
+            return "";
+        }
+
+        // Note that unlike extensions, we canonicalize to lower case alphabets
+        // and underscores instead of hyphens.
+        final String normalizedVariant = variant.replace('-', '_');
+        String[] subTags = normalizedVariant.split("_");
+
+        for (String subTag : subTags) {
+            if (!isValidVariantSubtag(subTag)) {
+                throw new IllformedLocaleException("Invalid variant: " + variant);
+            }
+        }
+
+        return normalizedVariant;
+    }
+
+    private static boolean isValidVariantSubtag(String subTag) {
+        // The BCP-47 spec states that :
+        // - Subtags can be between [5, 8] alphanumeric chars in length.
+        // - Subtags that start with a number are allowed to be 4 chars in length.
+        if (subTag.length() >= 5 && subTag.length() <= 8) {
+            if (isAsciiAlphaNum(subTag)) {
+                return true;
+            }
+        } else if (subTag.length() == 4) {
+            final char firstChar = subTag.charAt(0);
+            if ((firstChar >= '0' && firstChar <= '9') && isAsciiAlphaNum(subTag)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+// END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Returns a name for the locale that is appropriate for display to the
+     * user. This will be the values returned by getDisplayLanguage(),
+     * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
+     * into a single string. The the non-empty values are used in order,
+     * with the second and subsequent names in parentheses.  For example:
+     * <blockquote>
+     * language (script, country, variant)<br>
+     * language (country)<br>
+     * language (variant)<br>
+     * script (country)<br>
+     * country<br>
+     * </blockquote>
+     * depending on which fields are specified in the locale.  If the
+     * language, script, country, and variant fields are all empty,
+     * this function returns the empty string.
+     *
+     * @return The name of the locale appropriate to display.
+     */
+    public final String getDisplayName() {
+        return getDisplayName(getDefault(Category.DISPLAY));
+    }
+
+    // BEGIN Android-changed: Documentation and behavior of getDisplay*().
+    /*
+    /**
+     * Returns a name for the locale that is appropriate for display
+     * to the user.  This will be the values returned by
+     * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
+     * and getDisplayVariant() assembled into a single string.
+     * The non-empty values are used in order,
+     * with the second and subsequent names in parentheses.  For example:
+     * <blockquote>
+     * language (script, country, variant)<br>
+     * language (country)<br>
+     * language (variant)<br>
+     * script (country)<br>
+     * country<br>
+     * </blockquote>
+     * depending on which fields are specified in the locale.  If the
+     * language, script, country, and variant fields are all empty,
+     * this function returns the empty string.
+     *
+     * @param inLocale The locale for which to retrieve the display name.
+     * @return The name of the locale appropriate to display.
+     * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
+     *
+    public String getDisplayName(Locale inLocale) {
+        LocaleResources lr =  LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
+
+        String languageName = getDisplayLanguage(inLocale);
+        String scriptName = getDisplayScript(inLocale);
+        String countryName = getDisplayCountry(inLocale);
+        String[] variantNames = getDisplayVariantArray(inLocale);
+
+        // Get the localized patterns for formatting a display name.
+        String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
+        String listPattern = lr.getLocaleName("ListPattern");
+        String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
+
+        // The display name consists of a main name, followed by qualifiers.
+        // Typically, the format is "MainName (Qualifier, Qualifier)" but this
+        // depends on what pattern is stored in the display locale.
+        String   mainName       = null;
+        String[] qualifierNames = null;
+
+        // The main name is the language, or if there is no language, the script,
+        // then if no script, the country. If there is no language/script/country
+        // (an anomalous situation) then the display name is simply the variant's
+        // display name.
+        if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
+            if (variantNames.length == 0) {
+                return "";
+            } else {
+                return formatList(variantNames, listPattern, listCompositionPattern);
+            }
+        }
+        ArrayList<String> names = new ArrayList<>(4);
+        if (languageName.length() != 0) {
+            names.add(languageName);
+        }
+        if (scriptName.length() != 0) {
+            names.add(scriptName);
+        }
+        if (countryName.length() != 0) {
+            names.add(countryName);
+        }
+        if (variantNames.length != 0) {
+            names.addAll(Arrays.asList(variantNames));
+        }
+
+        // The first one in the main name
+        mainName = names.get(0);
+
+        // Others are qualifiers
+        int numNames = names.size();
+        qualifierNames = (numNames > 1) ?
+                names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
+
+        // Create an array whose first element is the number of remaining
+        // elements.  This serves as a selector into a ChoiceFormat pattern from
+        // the resource.  The second and third elements are the main name and
+        // the qualifier; if there are no qualifiers, the third element is
+        // unused by the format pattern.
+        Object[] displayNames = {
+            new Integer(qualifierNames.length != 0 ? 2 : 1),
+            mainName,
+            // We could also just call formatList() and have it handle the empty
+            // list case, but this is more efficient, and we want it to be
+            // efficient since all the language-only locales will not have any
+            // qualifiers.
+            qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
+        };
+
+        if (displayNamePattern != null) {
+            return new MessageFormat(displayNamePattern).format(displayNames);
+        }
+        else {
+            // If we cannot get the message format pattern, then we use a simple
+            // hard-coded pattern.  This should not occur in practice unless the
+            // installation is missing some core files (FormatData etc.).
+            StringBuilder result = new StringBuilder();
+            result.append((String)displayNames[1]);
+            if (displayNames.length > 2) {
+                result.append(" (");
+                result.append((String)displayNames[2]);
+                result.append(')');
+            }
+            return result.toString();
+        }
+    }
+    */
+    /**
+     * Returns this locale's language name, country name, and variant, localized
+     * to {@code locale}. The exact output form depends on whether this locale
+     * corresponds to a specific language, script, country and variant.
+     *
+     * <p>For example:
+     * <ul>
+     * <li>{@code new Locale("en").getDisplayName(Locale.US)} -> {@code English}
+     * <li>{@code new Locale("en", "US").getDisplayName(Locale.US)} -> {@code English (United States)}
+     * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.US)} -> {@code English (United States,Computer)}
+     * <li>{@code Locale.forLanguageTag("zh-Hant-CN").getDisplayName(Locale.US)} -> {@code Chinese (Traditional Han,China)}
+     * <li>{@code new Locale("en").getDisplayName(Locale.FRANCE)} -> {@code anglais}
+     * <li>{@code new Locale("en", "US").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis)}
+     * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis,informatique)}.
+     * </ul>
+     */
+    public String getDisplayName(Locale locale) {
+        int count = 0;
+        StringBuilder buffer = new StringBuilder();
+        String languageCode = baseLocale.getLanguage();
+        if (!languageCode.isEmpty()) {
+            String displayLanguage = getDisplayLanguage(locale);
+            buffer.append(displayLanguage.isEmpty() ? languageCode : displayLanguage);
+            ++count;
+        }
+        String scriptCode = baseLocale.getScript();
+        if (!scriptCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            }
+            String displayScript = getDisplayScript(locale);
+            buffer.append(displayScript.isEmpty() ? scriptCode : displayScript);
+            ++count;
+        }
+        String countryCode = baseLocale.getRegion();
+        if (!countryCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            } else if (count == 2) {
+                buffer.append(",");
+            }
+            String displayCountry = getDisplayCountry(locale);
+            buffer.append(displayCountry.isEmpty() ? countryCode : displayCountry);
+            ++count;
+        }
+        String variantCode = baseLocale.getVariant();
+        if (!variantCode.isEmpty()) {
+            if (count == 1) {
+                buffer.append(" (");
+            } else if (count == 2 || count == 3) {
+                buffer.append(",");
+            }
+            String displayVariant = getDisplayVariant(locale);
+            buffer.append(displayVariant.isEmpty() ? variantCode : displayVariant);
+            ++count;
+        }
+        if (count > 1) {
+            buffer.append(")");
+        }
+        return buffer.toString();
+    }
+    // END Android-changed: Documentation and behavior of getDisplay*().
+
+    /**
+     * Overrides Cloneable.
+     */
+    @Override
+    public Object clone()
+    {
+        try {
+            Locale that = (Locale)super.clone();
+            return that;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Override hashCode.
+     * Since Locales are often used in hashtables, caches the value
+     * for speed.
+     */
+    @Override
+    public int hashCode() {
+        int hc = hashCodeValue;
+        if (hc == 0) {
+            hc = baseLocale.hashCode();
+            if (localeExtensions != null) {
+                hc ^= localeExtensions.hashCode();
+            }
+            hashCodeValue = hc;
+        }
+        return hc;
+    }
+
+    // Overrides
+
+    /**
+     * Returns true if this Locale is equal to another object.  A Locale is
+     * deemed equal to another Locale with identical language, script, country,
+     * variant and extensions, and unequal to all other objects.
+     *
+     * @return true if this Locale is equal to the specified object.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)                      // quick check
+            return true;
+        if (!(obj instanceof Locale))
+            return false;
+        BaseLocale otherBase = ((Locale)obj).baseLocale;
+        if (!baseLocale.equals(otherBase)) {
+            return false;
+        }
+        if (localeExtensions == null) {
+            return ((Locale)obj).localeExtensions == null;
+        }
+        return localeExtensions.equals(((Locale)obj).localeExtensions);
+    }
+
+    // ================= privates =====================================
+
+    private transient BaseLocale baseLocale;
+    private transient LocaleExtensions localeExtensions;
+
+    /**
+     * Calculated hashcode
+     */
+    private transient volatile int hashCodeValue = 0;
+
+    // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+    // private volatile static Locale defaultLocale = initDefault();
+    private static class NoImagePreloadHolder {
+        public volatile static Locale defaultLocale = initDefault();
+    }
+    private volatile static Locale defaultDisplayLocale = null;
+    private volatile static Locale defaultFormatLocale = null;
+
+    private transient volatile String languageTag;
+
+    // BEGIN Android-removed: Private helper getDisplayVariantArray() unused on Android.
+    /*
+    /**
+     * Return an array of the display names of the variant.
+     * @param bundle the ResourceBundle to use to get the display names
+     * @return an array of display names, possible of zero length.
+     *
+    private String[] getDisplayVariantArray(Locale inLocale) {
+        // Split the variant name into tokens separated by '_'.
+        StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
+        String[] names = new String[tokenizer.countTokens()];
+
+        // For each variant token, lookup the display name.  If
+        // not found, use the variant name itself.
+        for (int i=0; i<names.length; ++i) {
+            names[i] = getDisplayString(tokenizer.nextToken(),
+                                inLocale, DISPLAY_VARIANT);
+        }
+
+        return names;
+    }
+    */
+    // END Android-removed: Private helper getDisplayVariantArray() unused on Android.
+
+    /**
+     * Format a list using given pattern strings.
+     * If either of the patterns is null, then a the list is
+     * formatted by concatenation with the delimiter ','.
+     * @param stringList the list of strings to be formatted.
+     * @param listPattern should create a MessageFormat taking 0-3 arguments
+     * and formatting them into a list.
+     * @param listCompositionPattern should take 2 arguments
+     * and is used by composeList.
+     * @return a string representing the list.
+     */
+    private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
+        // If we have no list patterns, compose the list in a simple,
+        // non-localized way.
+        if (listPattern == null || listCompositionPattern == null) {
+            StringBuilder result = new StringBuilder();
+            for (int i = 0; i < stringList.length; ++i) {
+                if (i > 0) {
+                    result.append(',');
+                }
+                result.append(stringList[i]);
+            }
+            return result.toString();
+        }
+
+        // Compose the list down to three elements if necessary
+        if (stringList.length > 3) {
+            MessageFormat format = new MessageFormat(listCompositionPattern);
+            stringList = composeList(format, stringList);
+        }
+
+        // Rebuild the argument list with the list length as the first element
+        Object[] args = new Object[stringList.length + 1];
+        System.arraycopy(stringList, 0, args, 1, stringList.length);
+        args[0] = new Integer(stringList.length);
+
+        // Format it using the pattern in the resource
+        MessageFormat format = new MessageFormat(listPattern);
+        return format.format(args);
+    }
+
+    /**
+     * Given a list of strings, return a list shortened to three elements.
+     * Shorten it by applying the given format to the first two elements
+     * recursively.
+     * @param format a format which takes two arguments
+     * @param list a list of strings
+     * @return if the list is three elements or shorter, the same list;
+     * otherwise, a new list of three elements.
+     */
+    private static String[] composeList(MessageFormat format, String[] list) {
+        if (list.length <= 3) return list;
+
+        // Use the given format to compose the first two elements into one
+        String[] listItems = { list[0], list[1] };
+        String newItem = format.format(listItems);
+
+        // Form a new list one element shorter
+        String[] newList = new String[list.length-1];
+        System.arraycopy(list, 2, newList, 1, newList.length-1);
+        newList[0] = newItem;
+
+        // Recurse
+        return composeList(format, newList);
+    }
+
+    // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
+    // avoid its class loading.
+    private static boolean isUnicodeExtensionKey(String s) {
+        // 2alphanum
+        return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
+    }
+
+    /**
+     * @serialField language    String
+     *      language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
+     * @serialField country     String
+     *      country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
+     * @serialField variant     String
+     *      variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
+     * @serialField hashcode    int
+     *      deprecated, for forward compatibility only
+     * @serialField script      String
+     *      script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
+     * @serialField extensions  String
+     *      canonical representation of extensions, that is,
+     *      BCP47 extensions in alphabetical order followed by
+     *      BCP47 private use subtags, all in lower case letters
+     *      separated by HYPHEN-MINUS characters.
+     *      (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
+     *      <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("language", String.class),
+        new ObjectStreamField("country", String.class),
+        new ObjectStreamField("variant", String.class),
+        new ObjectStreamField("hashcode", int.class),
+        new ObjectStreamField("script", String.class),
+        new ObjectStreamField("extensions", String.class),
+    };
+
+    /**
+     * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.
+     * @param out the <code>ObjectOutputStream</code> to write
+     * @throws IOException
+     * @since 1.7
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        ObjectOutputStream.PutField fields = out.putFields();
+        fields.put("language", baseLocale.getLanguage());
+        fields.put("script", baseLocale.getScript());
+        fields.put("country", baseLocale.getRegion());
+        fields.put("variant", baseLocale.getVariant());
+        fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
+        fields.put("hashcode", -1); // place holder just for backward support
+        out.writeFields();
+    }
+
+    /**
+     * Deserializes this <code>Locale</code>.
+     * @param in the <code>ObjectInputStream</code> to read
+     * @throws IOException
+     * @throws ClassNotFoundException
+     * @throws IllformedLocaleException
+     * @since 1.7
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        ObjectInputStream.GetField fields = in.readFields();
+        String language = (String)fields.get("language", "");
+        String script = (String)fields.get("script", "");
+        String country = (String)fields.get("country", "");
+        String variant = (String)fields.get("variant", "");
+        String extStr = (String)fields.get("extensions", "");
+        baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
+        // Android-changed: Handle null for backwards compatible deserialization. http://b/26387905
+        // if (extStr.length() > 0) {
+        if (extStr != null && extStr.length() > 0) {
+            try {
+                InternalLocaleBuilder bldr = new InternalLocaleBuilder();
+                bldr.setExtensions(extStr);
+                localeExtensions = bldr.getLocaleExtensions();
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage());
+            }
+        } else {
+            localeExtensions = null;
+        }
+    }
+
+    /**
+     * Returns a cached <code>Locale</code> instance equivalent to
+     * the deserialized <code>Locale</code>. When serialized
+     * language, country and variant fields read from the object data stream
+     * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
+     * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
+     * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
+     * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>
+     * for more information.
+     *
+     * @return an instance of <code>Locale</code> equivalent to
+     * the deserialized <code>Locale</code>.
+     * @throws java.io.ObjectStreamException
+     */
+    private Object readResolve() throws java.io.ObjectStreamException {
+        return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
+                baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
+    }
+
+    private static volatile String[] isoLanguages = null;
+
+    private static volatile String[] isoCountries = null;
+
+    private static String convertOldISOCodes(String language) {
+        // we accept both the old and the new ISO codes for the languages whose ISO
+        // codes have changed, but we always store the OLD code, for backward compatibility
+        language = LocaleUtils.toLowerString(language).intern();
+        if (language == "he") {
+            return "iw";
+        } else if (language == "yi") {
+            return "ji";
+        } else if (language == "id") {
+            return "in";
+        } else {
+            return language;
+        }
+    }
+
+    private static LocaleExtensions getCompatibilityExtensions(String language,
+                                                               String script,
+                                                               String country,
+                                                               String variant) {
+        LocaleExtensions extensions = null;
+        // Special cases for backward compatibility support
+        if (LocaleUtils.caseIgnoreMatch(language, "ja")
+                && script.length() == 0
+                && LocaleUtils.caseIgnoreMatch(country, "jp")
+                && "JP".equals(variant)) {
+            // ja_JP_JP -> u-ca-japanese (calendar = japanese)
+            extensions = LocaleExtensions.CALENDAR_JAPANESE;
+        } else if (LocaleUtils.caseIgnoreMatch(language, "th")
+                && script.length() == 0
+                && LocaleUtils.caseIgnoreMatch(country, "th")
+                && "TH".equals(variant)) {
+            // th_TH_TH -> u-nu-thai (numbersystem = thai)
+            extensions = LocaleExtensions.NUMBER_THAI;
+        }
+        return extensions;
+    }
+
+    // Android-removed: Drop nested private class LocaleNameGetter.
+    /*
+    /**
+     * Obtains a localized locale names from a LocaleNameProvider
+     * implementation.
+     *
+    private static class LocaleNameGetter
+        implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
+        private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
+
+        @Override
+        public String getObject(LocaleNameProvider localeNameProvider,
+                                Locale locale,
+                                String key,
+                                Object... params) {
+            assert params.length == 2;
+            int type = (Integer)params[0];
+            String code = (String)params[1];
+
+            switch(type) {
+            case DISPLAY_LANGUAGE:
+                return localeNameProvider.getDisplayLanguage(code, locale);
+            case DISPLAY_COUNTRY:
+                return localeNameProvider.getDisplayCountry(code, locale);
+            case DISPLAY_VARIANT:
+                return localeNameProvider.getDisplayVariant(code, locale);
+            case DISPLAY_SCRIPT:
+                return localeNameProvider.getDisplayScript(code, locale);
+            default:
+                assert false; // shouldn't happen
+            }
+
+            return null;
+        }
+    }
+    */
+
+    // BEGIN Android-added: adjustLanguageCode(), for internal use only.
+    /** @hide for internal use only. */
+    public static String adjustLanguageCode(String languageCode) {
+        String adjusted = languageCode.toLowerCase(Locale.US);
+        // Map new language codes to the obsolete language
+        // codes so the correct resource bundles will be used.
+        if (languageCode.equals("he")) {
+            adjusted = "iw";
+        } else if (languageCode.equals("id")) {
+            adjusted = "in";
+        } else if (languageCode.equals("yi")) {
+            adjusted = "ji";
+        }
+
+        return adjusted;
+    }
+    // END Android-added: adjustLanguageCode(), for internal use only.
+
+    /**
+     * Enum for locale categories.  These locale categories are used to get/set
+     * the default locale for the specific functionality represented by the
+     * category.
+     *
+     * @see #getDefault(Locale.Category)
+     * @see #setDefault(Locale.Category, Locale)
+     * @since 1.7
+     */
+    public enum Category {
+
+        /**
+         * Category used to represent the default locale for
+         * displaying user interfaces.
+         */
+        DISPLAY("user.language.display",
+                "user.script.display",
+                "user.country.display",
+                "user.variant.display"),
+
+        /**
+         * Category used to represent the default locale for
+         * formatting dates, numbers, and/or currencies.
+         */
+        FORMAT("user.language.format",
+               "user.script.format",
+               "user.country.format",
+               "user.variant.format");
+
+        Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
+            this.languageKey = languageKey;
+            this.scriptKey = scriptKey;
+            this.countryKey = countryKey;
+            this.variantKey = variantKey;
+        }
+
+        final String languageKey;
+        final String scriptKey;
+        final String countryKey;
+        final String variantKey;
+    }
+
+    /**
+     * <code>Builder</code> is used to build instances of <code>Locale</code>
+     * from values configured by the setters.  Unlike the <code>Locale</code>
+     * constructors, the <code>Builder</code> checks if a value configured by a
+     * setter satisfies the syntax requirements defined by the <code>Locale</code>
+     * class.  A <code>Locale</code> object created by a <code>Builder</code> is
+     * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
+     * without losing information.
+     *
+     * <p><b>Note:</b> The <code>Locale</code> class does not provide any
+     * syntactic restrictions on variant, while BCP 47 requires each variant
+     * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
+     * alphanumerics.  The method <code>setVariant</code> throws
+     * <code>IllformedLocaleException</code> for a variant that does not satisfy
+     * this restriction. If it is necessary to support such a variant, use a
+     * Locale constructor.  However, keep in mind that a <code>Locale</code>
+     * object created this way might lose the variant information when
+     * transformed to a BCP 47 language tag.
+     *
+     * <p>The following example shows how to create a <code>Locale</code> object
+     * with the <code>Builder</code>.
+     * <blockquote>
+     * <pre>
+     *     Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
+     * </pre>
+     * </blockquote>
+     *
+     * <p>Builders can be reused; <code>clear()</code> resets all
+     * fields to their default values.
+     *
+     * @see Locale#forLanguageTag
+     * @since 1.7
+     */
+    public static final class Builder {
+        private final InternalLocaleBuilder localeBuilder;
+
+        /**
+         * Constructs an empty Builder. The default value of all
+         * fields, extensions, and private use information is the
+         * empty string.
+         */
+        public Builder() {
+            localeBuilder = new InternalLocaleBuilder();
+        }
+
+        /**
+         * Resets the <code>Builder</code> to match the provided
+         * <code>locale</code>.  Existing state is discarded.
+         *
+         * <p>All fields of the locale must be well-formed, see {@link Locale}.
+         *
+         * <p>Locales with any ill-formed fields cause
+         * <code>IllformedLocaleException</code> to be thrown, except for the
+         * following three cases which are accepted for compatibility
+         * reasons:<ul>
+         * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
+         * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
+         * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
+         *
+         * @param locale the locale
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>locale</code> has
+         * any ill-formed fields.
+         * @throws NullPointerException if <code>locale</code> is null.
+         */
+        public Builder setLocale(Locale locale) {
+            try {
+                localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Resets the Builder to match the provided IETF BCP 47
+         * language tag.  Discards the existing state.  Null and the
+         * empty string cause the builder to be reset, like {@link
+         * #clear}.  Grandfathered tags (see {@link
+         * Locale#forLanguageTag}) are converted to their canonical
+         * form before being processed.  Otherwise, the language tag
+         * must be well-formed (see {@link Locale}) or an exception is
+         * thrown (unlike <code>Locale.forLanguageTag</code>, which
+         * just discards ill-formed and following portions of the
+         * tag).
+         *
+         * @param languageTag the language tag
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
+         * @see Locale#forLanguageTag(String)
+         */
+        public Builder setLanguageTag(String languageTag) {
+            ParseStatus sts = new ParseStatus();
+            LanguageTag tag = LanguageTag.parse(languageTag, sts);
+            if (sts.isError()) {
+                throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
+            }
+            localeBuilder.setLanguageTag(tag);
+            return this;
+        }
+
+        /**
+         * Sets the language.  If <code>language</code> is the empty string or
+         * null, the language in this <code>Builder</code> is removed.  Otherwise,
+         * the language must be <a href="./Locale.html#def_language">well-formed</a>
+         * or an exception is thrown.
+         *
+         * <p>The typical language value is a two or three-letter language
+         * code as defined in ISO639.
+         *
+         * @param language the language
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>language</code> is ill-formed
+         */
+        public Builder setLanguage(String language) {
+            try {
+                localeBuilder.setLanguage(language);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the script. If <code>script</code> is null or the empty string,
+         * the script in this <code>Builder</code> is removed.
+         * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
+         * exception is thrown.
+         *
+         * <p>The typical script value is a four-letter script code as defined by ISO 15924.
+         *
+         * @param script the script
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>script</code> is ill-formed
+         */
+        public Builder setScript(String script) {
+            try {
+                localeBuilder.setScript(script);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the region.  If region is null or the empty string, the region
+         * in this <code>Builder</code> is removed.  Otherwise,
+         * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
+         * exception is thrown.
+         *
+         * <p>The typical region value is a two-letter ISO 3166 code or a
+         * three-digit UN M.49 area code.
+         *
+         * <p>The country value in the <code>Locale</code> created by the
+         * <code>Builder</code> is always normalized to upper case.
+         *
+         * @param region the region
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>region</code> is ill-formed
+         */
+        public Builder setRegion(String region) {
+            try {
+                localeBuilder.setRegion(region);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the variant.  If variant is null or the empty string, the
+         * variant in this <code>Builder</code> is removed.  Otherwise, it
+         * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
+         * subtags, or an exception is thrown.
+         *
+         * <p><b>Note:</b> This method checks if <code>variant</code>
+         * satisfies the IETF BCP 47 variant subtag's syntax requirements,
+         * and normalizes the value to lowercase letters.  However,
+         * the <code>Locale</code> class does not impose any syntactic
+         * restriction on variant, and the variant value in
+         * <code>Locale</code> is case sensitive.  To set such a variant,
+         * use a Locale constructor.
+         *
+         * @param variant the variant
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>variant</code> is ill-formed
+         */
+        public Builder setVariant(String variant) {
+            try {
+                localeBuilder.setVariant(variant);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the extension for the given key. If the value is null or the
+         * empty string, the extension is removed.  Otherwise, the extension
+         * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
+         * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
+         * Setting a value for this key replaces any existing Unicode locale key/type
+         * pairs with those defined in the extension.
+         *
+         * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
+         * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
+         * well-formed, the value for this key needs only to have subtags of one to
+         * eight alphanumeric characters, not two to eight as in the general case.
+         *
+         * @param key the extension key
+         * @param value the extension value
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>key</code> is illegal
+         * or <code>value</code> is ill-formed
+         * @see #setUnicodeLocaleKeyword(String, String)
+         */
+        public Builder setExtension(char key, String value) {
+            try {
+                localeBuilder.setExtension(key, value);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the Unicode locale keyword type for the given key.  If the type
+         * is null, the Unicode keyword is removed.  Otherwise, the key must be
+         * non-null and both key and type must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p>Keys and types are converted to lower case.
+         *
+         * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
+         * replaces all Unicode locale keywords with those defined in the
+         * extension.
+         *
+         * @param key the Unicode locale key
+         * @param type the Unicode locale type
+         * @return This builder.
+         * @throws IllformedLocaleException if <code>key</code> or <code>type</code>
+         * is ill-formed
+         * @throws NullPointerException if <code>key</code> is null
+         * @see #setExtension(char, String)
+         */
+        public Builder setUnicodeLocaleKeyword(String key, String type) {
+            try {
+                localeBuilder.setUnicodeLocaleKeyword(key, type);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Adds a unicode locale attribute, if not already present, otherwise
+         * has no effect.  The attribute must not be null and must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * @param attribute the attribute
+         * @return This builder.
+         * @throws NullPointerException if <code>attribute</code> is null
+         * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
+         * @see #setExtension(char, String)
+         */
+        public Builder addUnicodeLocaleAttribute(String attribute) {
+            try {
+                localeBuilder.addUnicodeLocaleAttribute(attribute);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Removes a unicode locale attribute, if present, otherwise has no
+         * effect.  The attribute must not be null and must be <a
+         * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
+         * is thrown.
+         *
+         * <p>Attribute comparision for removal is case-insensitive.
+         *
+         * @param attribute the attribute
+         * @return This builder.
+         * @throws NullPointerException if <code>attribute</code> is null
+         * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
+         * @see #setExtension(char, String)
+         */
+        public Builder removeUnicodeLocaleAttribute(String attribute) {
+            // BEGIN Android-added: removeUnicodeLocaleAttribute(null) is documented to throw NPE.
+            // This could probably be contributed back to upstream. http://b/110752069
+            if (attribute == null) {
+                throw new NullPointerException("attribute == null");
+            }
+            // END Android-added: removeUnicodeLocaleAttribute(null) is documented to throw NPE.
+
+            try {
+                localeBuilder.removeUnicodeLocaleAttribute(attribute);
+            } catch (LocaleSyntaxException e) {
+                throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
+            }
+            return this;
+        }
+
+        /**
+         * Resets the builder to its initial, empty state.
+         *
+         * @return This builder.
+         */
+        public Builder clear() {
+            localeBuilder.clear();
+            return this;
+        }
+
+        /**
+         * Resets the extensions to their initial, empty state.
+         * Language, script, region and variant are unchanged.
+         *
+         * @return This builder.
+         * @see #setExtension(char, String)
+         */
+        public Builder clearExtensions() {
+            localeBuilder.clearExtensions();
+            return this;
+        }
+
+        /**
+         * Returns an instance of <code>Locale</code> created from the fields set
+         * on this builder.
+         *
+         * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
+         * when constructing a Locale. (Grandfathered tags are handled in
+         * {@link #setLanguageTag}.)
+         *
+         * @return A Locale.
+         */
+        public Locale build() {
+            BaseLocale baseloc = localeBuilder.getBaseLocale();
+            LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
+            if (extensions == null && baseloc.getVariant().length() > 0) {
+                extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
+                        baseloc.getRegion(), baseloc.getVariant());
+            }
+            return Locale.getInstance(baseloc, extensions);
+        }
+    }
+
+    /**
+     * This enum provides constants to select a filtering mode for locale
+     * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
+     * Matching of Language Tags</a> for details.
+     *
+     * <p>As an example, think of two Language Priority Lists each of which
+     * includes only one language range and a set of following language tags:
+     *
+     * <pre>
+     *    de (German)
+     *    de-DE (German, Germany)
+     *    de-Deva (German, in Devanagari script)
+     *    de-Deva-DE (German, in Devanagari script, Germany)
+     *    de-DE-1996 (German, Germany, orthography of 1996)
+     *    de-Latn-DE (German, in Latin script, Germany)
+     *    de-Latn-DE-1996 (German, in Latin script, Germany, orthography of 1996)
+     * </pre>
+     *
+     * The filtering method will behave as follows:
+     *
+     * <table cellpadding=2 summary="Filtering method behavior">
+     * <tr>
+     * <th>Filtering Mode</th>
+     * <th>Language Priority List: {@code "de-DE"}</th>
+     * <th>Language Priority List: {@code "de-*-DE"}</th>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#AUTOSELECT_FILTERING AUTOSELECT_FILTERING}
+     * </td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"}.
+     * </td>
+     * <td valign=top>
+     * Performs <em>extended</em> filtering and returns {@code "de-DE"},
+     * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and
+     * {@code "de-Latn-DE-1996"}.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#EXTENDED_FILTERING EXTENDED_FILTERING}
+     * </td>
+     * <td valign=top>
+     * Performs <em>extended</em> filtering and returns {@code "de-DE"},
+     * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and
+     * {@code "de-Latn-DE-1996"}.
+     * </td>
+     * <td valign=top>Same as above.</td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#IGNORE_EXTENDED_RANGES IGNORE_EXTENDED_RANGES}
+     * </td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"}.
+     * </td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code null} because
+     * nothing matches.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#MAP_EXTENDED_RANGES MAP_EXTENDED_RANGES}
+     * </td>
+     * <td valign=top>Same as above.</td>
+     * <td valign=top>
+     * Performs <em>basic</em> filtering and returns {@code "de-DE"} and
+     * {@code "de-DE-1996"} because {@code "de-*-DE"} is mapped to
+     * {@code "de-DE"}.
+     * </td>
+     * </tr>
+     * <tr>
+     * <td valign=top>
+     * {@link FilteringMode#REJECT_EXTENDED_RANGES REJECT_EXTENDED_RANGES}
+     * </td>
+     * <td valign=top>Same as above.</td>
+     * <td valign=top>
+     * Throws {@link IllegalArgumentException} because {@code "de-*-DE"} is
+     * not a valid basic language range.
+     * </td>
+     * </tr>
+     * </table>
+     *
+     * @see #filter(List, Collection, FilteringMode)
+     * @see #filterTags(List, Collection, FilteringMode)
+     *
+     * @since 1.8
+     */
+    public static enum FilteringMode {
+        /**
+         * Specifies automatic filtering mode based on the given Language
+         * Priority List consisting of language ranges. If all of the ranges
+         * are basic, basic filtering is selected. Otherwise, extended
+         * filtering is selected.
+         */
+        AUTOSELECT_FILTERING,
+
+        /**
+         * Specifies extended filtering.
+         */
+        EXTENDED_FILTERING,
+
+        /**
+         * Specifies basic filtering: Note that any extended language ranges
+         * included in the given Language Priority List are ignored.
+         */
+        IGNORE_EXTENDED_RANGES,
+
+        /**
+         * Specifies basic filtering: If any extended language ranges are
+         * included in the given Language Priority List, they are mapped to the
+         * basic language range. Specifically, a language range starting with a
+         * subtag {@code "*"} is treated as a language range {@code "*"}. For
+         * example, {@code "*-US"} is treated as {@code "*"}. If {@code "*"} is
+         * not the first subtag, {@code "*"} and extra {@code "-"} are removed.
+         * For example, {@code "ja-*-JP"} is mapped to {@code "ja-JP"}.
+         */
+        MAP_EXTENDED_RANGES,
+
+        /**
+         * Specifies basic filtering: If any extended language ranges are
+         * included in the given Language Priority List, the list is rejected
+         * and the filtering method throws {@link IllegalArgumentException}.
+         */
+        REJECT_EXTENDED_RANGES
+    };
+
+    /**
+     * This class expresses a <em>Language Range</em> defined in
+     * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
+     * Language Tags</a>. A language range is an identifier which is used to
+     * select language tag(s) meeting specific requirements by using the
+     * mechanisms described in <a href="Locale.html#LocaleMatching">Locale
+     * Matching</a>. A list which represents a user's preferences and consists
+     * of language ranges is called a <em>Language Priority List</em>.
+     *
+     * <p>There are two types of language ranges: basic and extended. In RFC
+     * 4647, the syntax of language ranges is expressed in
+     * <a href="http://tools.ietf.org/html/rfc4234">ABNF</a> as follows:
+     * <blockquote>
+     * <pre>
+     *     basic-language-range    = (1*8ALPHA *("-" 1*8alphanum)) / "*"
+     *     extended-language-range = (1*8ALPHA / "*")
+     *                               *("-" (1*8alphanum / "*"))
+     *     alphanum                = ALPHA / DIGIT
+     * </pre>
+     * </blockquote>
+     * For example, {@code "en"} (English), {@code "ja-JP"} (Japanese, Japan),
+     * {@code "*"} (special language range which matches any language tag) are
+     * basic language ranges, whereas {@code "*-CH"} (any languages,
+     * Switzerland), {@code "es-*"} (Spanish, any regions), and
+     * {@code "zh-Hant-*"} (Traditional Chinese, any regions) are extended
+     * language ranges.
+     *
+     * @see #filter
+     * @see #filterTags
+     * @see #lookup
+     * @see #lookupTag
+     *
+     * @since 1.8
+     */
+    public static final class LanguageRange {
+
+       /**
+        * A constant holding the maximum value of weight, 1.0, which indicates
+        * that the language range is a good fit for the user.
+        */
+        public static final double MAX_WEIGHT = 1.0;
+
+       /**
+        * A constant holding the minimum value of weight, 0.0, which indicates
+        * that the language range is not a good fit for the user.
+        */
+        public static final double MIN_WEIGHT = 0.0;
+
+        private final String range;
+        private final double weight;
+
+        private volatile int hash = 0;
+
+        /**
+         * Constructs a {@code LanguageRange} using the given {@code range}.
+         * Note that no validation is done against the IANA Language Subtag
+         * Registry at time of construction.
+         *
+         * <p>This is equivalent to {@code LanguageRange(range, MAX_WEIGHT)}.
+         *
+         * @param range a language range
+         * @throws NullPointerException if the given {@code range} is
+         *     {@code null}
+         */
+        public LanguageRange(String range) {
+            this(range, MAX_WEIGHT);
+        }
+
+        /**
+         * Constructs a {@code LanguageRange} using the given {@code range} and
+         * {@code weight}. Note that no validation is done against the IANA
+         * Language Subtag Registry at time of construction.
+         *
+         * @param range  a language range
+         * @param weight a weight value between {@code MIN_WEIGHT} and
+         *     {@code MAX_WEIGHT}
+         * @throws NullPointerException if the given {@code range} is
+         *     {@code null}
+         * @throws IllegalArgumentException if the given {@code weight} is less
+         *     than {@code MIN_WEIGHT} or greater than {@code MAX_WEIGHT}
+         */
+        public LanguageRange(String range, double weight) {
+            if (range == null) {
+                throw new NullPointerException();
+            }
+            if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {
+                throw new IllegalArgumentException("weight=" + weight);
+            }
+
+            range = range.toLowerCase();
+
+            // Do syntax check.
+            boolean isIllFormed = false;
+            String[] subtags = range.split("-");
+            if (isSubtagIllFormed(subtags[0], true)
+                || range.endsWith("-")) {
+                isIllFormed = true;
+            } else {
+                for (int i = 1; i < subtags.length; i++) {
+                    if (isSubtagIllFormed(subtags[i], false)) {
+                        isIllFormed = true;
+                        break;
+                    }
+                }
+            }
+            if (isIllFormed) {
+                throw new IllegalArgumentException("range=" + range);
+            }
+
+            this.range = range;
+            this.weight = weight;
+        }
+
+        private static boolean isSubtagIllFormed(String subtag,
+                                                 boolean isFirstSubtag) {
+            if (subtag.equals("") || subtag.length() > 8) {
+                return true;
+            } else if (subtag.equals("*")) {
+                return false;
+            }
+            char[] charArray = subtag.toCharArray();
+            if (isFirstSubtag) { // ALPHA
+                for (char c : charArray) {
+                    if (c < 'a' || c > 'z') {
+                        return true;
+                    }
+                }
+            } else { // ALPHA / DIGIT
+                for (char c : charArray) {
+                    if (c < '0' || (c > '9' && c < 'a') || c > 'z') {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Returns the language range of this {@code LanguageRange}.
+         *
+         * @return the language range.
+         */
+        public String getRange() {
+            return range;
+        }
+
+        /**
+         * Returns the weight of this {@code LanguageRange}.
+         *
+         * @return the weight value.
+         */
+        public double getWeight() {
+            return weight;
+        }
+
+        /**
+         * Parses the given {@code ranges} to generate a Language Priority List.
+         *
+         * <p>This method performs a syntactic check for each language range in
+         * the given {@code ranges} but doesn't do validation using the IANA
+         * Language Subtag Registry.
+         *
+         * <p>The {@code ranges} to be given can take one of the following
+         * forms:
+         *
+         * <pre>
+         *   "Accept-Language: ja,en;q=0.4"  (weighted list with Accept-Language prefix)
+         *   "ja,en;q=0.4"                   (weighted list)
+         *   "ja,en"                         (prioritized list)
+         * </pre>
+         *
+         * In a weighted list, each language range is given a weight value.
+         * The weight value is identical to the "quality value" in
+         * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616</a>, and it
+         * expresses how much the user prefers  the language. A weight value is
+         * specified after a corresponding language range followed by
+         * {@code ";q="}, and the default weight value is {@code MAX_WEIGHT}
+         * when it is omitted.
+         *
+         * <p>Unlike a weighted list, language ranges in a prioritized list
+         * are sorted in the descending order based on its priority. The first
+         * language range has the highest priority and meets the user's
+         * preference most.
+         *
+         * <p>In either case, language ranges are sorted in descending order in
+         * the Language Priority List based on priority or weight. If a
+         * language range appears in the given {@code ranges} more than once,
+         * only the first one is included on the Language Priority List.
+         *
+         * <p>The returned list consists of language ranges from the given
+         * {@code ranges} and their equivalents found in the IANA Language
+         * Subtag Registry. For example, if the given {@code ranges} is
+         * {@code "Accept-Language: iw,en-us;q=0.7,en;q=0.3"}, the elements in
+         * the list to be returned are:
+         *
+         * <pre>
+         *  <b>Range</b>                                   <b>Weight</b>
+         *    "iw" (older tag for Hebrew)             1.0
+         *    "he" (new preferred code for Hebrew)    1.0
+         *    "en-us" (English, United States)        0.7
+         *    "en" (English)                          0.3
+         * </pre>
+         *
+         * Two language ranges, {@code "iw"} and {@code "he"}, have the same
+         * highest priority in the list. By adding {@code "he"} to the user's
+         * Language Priority List, locale-matching method can find Hebrew as a
+         * matching locale (or language tag) even if the application or system
+         * offers only {@code "he"} as a supported locale (or language tag).
+         *
+         * @param ranges a list of comma-separated language ranges or a list of
+         *     language ranges in the form of the "Accept-Language" header
+         *     defined in <a href="http://tools.ietf.org/html/rfc2616">RFC
+         *     2616</a>
+         * @return a Language Priority List consisting of language ranges
+         *     included in the given {@code ranges} and their equivalent
+         *     language ranges if available. The list is modifiable.
+         * @throws NullPointerException if {@code ranges} is null
+         * @throws IllegalArgumentException if a language range or a weight
+         *     found in the given {@code ranges} is ill-formed
+         */
+        public static List<LanguageRange> parse(String ranges) {
+            return LocaleMatcher.parse(ranges);
+        }
+
+        /**
+         * Parses the given {@code ranges} to generate a Language Priority
+         * List, and then customizes the list using the given {@code map}.
+         * This method is equivalent to
+         * {@code mapEquivalents(parse(ranges), map)}.
+         *
+         * @param ranges a list of comma-separated language ranges or a list
+         *     of language ranges in the form of the "Accept-Language" header
+         *     defined in <a href="http://tools.ietf.org/html/rfc2616">RFC
+         *     2616</a>
+         * @param map a map containing information to customize language ranges
+         * @return a Language Priority List with customization. The list is
+         *     modifiable.
+         * @throws NullPointerException if {@code ranges} is null
+         * @throws IllegalArgumentException if a language range or a weight
+         *     found in the given {@code ranges} is ill-formed
+         * @see #parse(String)
+         * @see #mapEquivalents
+         */
+        public static List<LanguageRange> parse(String ranges,
+                                                Map<String, List<String>> map) {
+            return mapEquivalents(parse(ranges), map);
+        }
+
+        /**
+         * Generates a new customized Language Priority List using the given
+         * {@code priorityList} and {@code map}. If the given {@code map} is
+         * empty, this method returns a copy of the given {@code priorityList}.
+         *
+         * <p>In the map, a key represents a language range whereas a value is
+         * a list of equivalents of it. {@code '*'} cannot be used in the map.
+         * Each equivalent language range has the same weight value as its
+         * original language range.
+         *
+         * <pre>
+         *  An example of map:
+         *    <b>Key</b>                            <b>Value</b>
+         *      "zh" (Chinese)                 "zh",
+         *                                     "zh-Hans"(Simplified Chinese)
+         *      "zh-HK" (Chinese, Hong Kong)   "zh-HK"
+         *      "zh-TW" (Chinese, Taiwan)      "zh-TW"
+         * </pre>
+         *
+         * The customization is performed after modification using the IANA
+         * Language Subtag Registry.
+         *
+         * <p>For example, if a user's Language Priority List consists of five
+         * language ranges ({@code "zh"}, {@code "zh-CN"}, {@code "en"},
+         * {@code "zh-TW"}, and {@code "zh-HK"}), the newly generated Language
+         * Priority List which is customized using the above map example will
+         * consists of {@code "zh"}, {@code "zh-Hans"}, {@code "zh-CN"},
+         * {@code "zh-Hans-CN"}, {@code "en"}, {@code "zh-TW"}, and
+         * {@code "zh-HK"}.
+         *
+         * <p>{@code "zh-HK"} and {@code "zh-TW"} aren't converted to
+         * {@code "zh-Hans-HK"} nor {@code "zh-Hans-TW"} even if they are
+         * included in the Language Priority List. In this example, mapping
+         * is used to clearly distinguish Simplified Chinese and Traditional
+         * Chinese.
+         *
+         * <p>If the {@code "zh"}-to-{@code "zh"} mapping isn't included in the
+         * map, a simple replacement will be performed and the customized list
+         * won't include {@code "zh"} and {@code "zh-CN"}.
+         *
+         * @param priorityList user's Language Priority List
+         * @param map a map containing information to customize language ranges
+         * @return a new Language Priority List with customization. The list is
+         *     modifiable.
+         * @throws NullPointerException if {@code priorityList} is {@code null}
+         * @see #parse(String, Map)
+         */
+        public static List<LanguageRange> mapEquivalents(
+                                              List<LanguageRange>priorityList,
+                                              Map<String, List<String>> map) {
+            return LocaleMatcher.mapEquivalents(priorityList, map);
+        }
+
+        /**
+         * Returns a hash code value for the object.
+         *
+         * @return  a hash code value for this object.
+         */
+        @Override
+        public int hashCode() {
+            if (hash == 0) {
+                int result = 17;
+                result = 37*result + range.hashCode();
+                long bitsWeight = Double.doubleToLongBits(weight);
+                result = 37*result + (int)(bitsWeight ^ (bitsWeight >>> 32));
+                hash = result;
+            }
+            return hash;
+        }
+
+        /**
+         * Compares this object to the specified object. The result is true if
+         * and only if the argument is not {@code null} and is a
+         * {@code LanguageRange} object that contains the same {@code range}
+         * and {@code weight} values as this object.
+         *
+         * @param obj the object to compare with
+         * @return  {@code true} if this object's {@code range} and
+         *     {@code weight} are the same as the {@code obj}'s; {@code false}
+         *     otherwise.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof LanguageRange)) {
+                return false;
+            }
+            LanguageRange other = (LanguageRange)obj;
+            return hash == other.hash
+                   && range.equals(other.range)
+                   && weight == other.weight;
+        }
+    }
+
+    /**
+     * Returns a list of matching {@code Locale} instances using the filtering
+     * mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @param mode filtering mode
+     * @return a list of {@code Locale} instances for matching language tags
+     *     sorted in descending order based on priority or weight, or an empty
+     *     list if nothing matches. The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code locales}
+     *     is {@code null}
+     * @throws IllegalArgumentException if one or more extended language ranges
+     *     are included in the given list when
+     *     {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified
+     *
+     * @since 1.8
+     */
+    public static List<Locale> filter(List<LanguageRange> priorityList,
+                                      Collection<Locale> locales,
+                                      FilteringMode mode) {
+        return LocaleMatcher.filter(priorityList, locales, mode);
+    }
+
+    /**
+     * Returns a list of matching {@code Locale} instances using the filtering
+     * mechanism defined in RFC 4647. This is equivalent to
+     * {@link #filter(List, Collection, FilteringMode)} when {@code mode} is
+     * {@link FilteringMode#AUTOSELECT_FILTERING}.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @return a list of {@code Locale} instances for matching language tags
+     *     sorted in descending order based on priority or weight, or an empty
+     *     list if nothing matches. The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code locales}
+     *     is {@code null}
+     *
+     * @since 1.8
+     */
+    public static List<Locale> filter(List<LanguageRange> priorityList,
+                                      Collection<Locale> locales) {
+        return filter(priorityList, locales, FilteringMode.AUTOSELECT_FILTERING);
+    }
+
+    /**
+     * Returns a list of matching languages tags using the basic filtering
+     * mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tags
+     * @param mode filtering mode
+     * @return a list of matching language tags sorted in descending order
+     *     based on priority or weight, or an empty list if nothing matches.
+     *     The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     * @throws IllegalArgumentException if one or more extended language ranges
+     *     are included in the given list when
+     *     {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified
+     *
+     * @since 1.8
+     */
+    public static List<String> filterTags(List<LanguageRange> priorityList,
+                                          Collection<String> tags,
+                                          FilteringMode mode) {
+        return LocaleMatcher.filterTags(priorityList, tags, mode);
+    }
+
+    /**
+     * Returns a list of matching languages tags using the basic filtering
+     * mechanism defined in RFC 4647. This is equivalent to
+     * {@link #filterTags(List, Collection, FilteringMode)} when {@code mode}
+     * is {@link FilteringMode#AUTOSELECT_FILTERING}.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tags
+     * @return a list of matching language tags sorted in descending order
+     *     based on priority or weight, or an empty list if nothing matches.
+     *     The list is modifiable.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static List<String> filterTags(List<LanguageRange> priorityList,
+                                          Collection<String> tags) {
+        return filterTags(priorityList, tags, FilteringMode.AUTOSELECT_FILTERING);
+    }
+
+    /**
+     * Returns a {@code Locale} instance for the best-matching language
+     * tag using the lookup mechanism defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param locales {@code Locale} instances used for matching
+     * @return the best matching <code>Locale</code> instance chosen based on
+     *     priority or weight, or {@code null} if nothing matches.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static Locale lookup(List<LanguageRange> priorityList,
+                                Collection<Locale> locales) {
+        return LocaleMatcher.lookup(priorityList, locales);
+    }
+
+    /**
+     * Returns the best-matching language tag using the lookup mechanism
+     * defined in RFC 4647.
+     *
+     * @param priorityList user's Language Priority List in which each language
+     *     tag is sorted in descending order based on priority or weight
+     * @param tags language tangs used for matching
+     * @return the best matching language tag chosen based on priority or
+     *     weight, or {@code null} if nothing matches.
+     * @throws NullPointerException if {@code priorityList} or {@code tags} is
+     *     {@code null}
+     *
+     * @since 1.8
+     */
+    public static String lookupTag(List<LanguageRange> priorityList,
+                                   Collection<String> tags) {
+        return LocaleMatcher.lookupTag(priorityList, tags);
+    }
+
+}
diff --git a/java/util/LongSummaryStatistics.java b/java/util/LongSummaryStatistics.java
new file mode 100644
index 0000000..085aa29
--- /dev/null
+++ b/java/util/LongSummaryStatistics.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.Collector;
+
+/**
+ * A state object for collecting statistics such as count, min, max, sum, and
+ * average.
+ *
+ * <p>This class is designed to work with (though does not require)
+ * {@linkplain java.util.stream streams}. For example, you can compute
+ * summary statistics on a stream of longs with:
+ * <pre> {@code
+ * LongSummaryStatistics stats = longStream.collect(LongSummaryStatistics::new,
+ *                                                  LongSummaryStatistics::accept,
+ *                                                  LongSummaryStatistics::combine);
+ * }</pre>
+ *
+ * <p>{@code LongSummaryStatistics} can be used as a
+ * {@linkplain java.util.stream.Stream#collect(Collector)} reduction}
+ * target for a {@linkplain java.util.stream.Stream stream}. For example:
+ *
+ * <pre> {@code
+ * LongSummaryStatistics stats = people.stream()
+ *                                     .collect(Collectors.summarizingLong(Person::getAge));
+ *}</pre>
+ *
+ * This computes, in a single pass, the count of people, as well as the minimum,
+ * maximum, sum, and average of their ages.
+ *
+ * @implNote This implementation is not thread safe. However, it is safe to use
+ * {@link java.util.stream.Collectors#summarizingLong(java.util.function.ToLongFunction)
+ * Collectors.toLongStatistics()} on a parallel stream, because the parallel
+ * implementation of {@link java.util.stream.Stream#collect Stream.collect()}
+ * provides the necessary partitioning, isolation, and merging of results for
+ * safe and efficient parallel execution.
+ *
+ * <p>This implementation does not check for overflow of the sum.
+ * @since 1.8
+ */
+public class LongSummaryStatistics implements LongConsumer, IntConsumer {
+    private long count;
+    private long sum;
+    private long min = Long.MAX_VALUE;
+    private long max = Long.MIN_VALUE;
+
+    /**
+     * Construct an empty instance with zero count, zero sum,
+     * {@code Long.MAX_VALUE} min, {@code Long.MIN_VALUE} max and zero
+     * average.
+     */
+    public LongSummaryStatistics() { }
+
+    /**
+     * Records a new {@code int} value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(int value) {
+        accept((long) value);
+    }
+
+    /**
+     * Records a new {@code long} value into the summary information.
+     *
+     * @param value the input value
+     */
+    @Override
+    public void accept(long value) {
+        ++count;
+        sum += value;
+        min = Math.min(min, value);
+        max = Math.max(max, value);
+    }
+
+    /**
+     * Combines the state of another {@code LongSummaryStatistics} into this
+     * one.
+     *
+     * @param other another {@code LongSummaryStatistics}
+     * @throws NullPointerException if {@code other} is null
+     */
+    public void combine(LongSummaryStatistics other) {
+        count += other.count;
+        sum += other.sum;
+        min = Math.min(min, other.min);
+        max = Math.max(max, other.max);
+    }
+
+    /**
+     * Returns the count of values recorded.
+     *
+     * @return the count of values
+     */
+    public final long getCount() {
+        return count;
+    }
+
+    /**
+     * Returns the sum of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return the sum of values, or zero if none
+     */
+    public final long getSum() {
+        return sum;
+    }
+
+    /**
+     * Returns the minimum value recorded, or {@code Long.MAX_VALUE} if no
+     * values have been recorded.
+     *
+     * @return the minimum value, or {@code Long.MAX_VALUE} if none
+     */
+    public final long getMin() {
+        return min;
+    }
+
+    /**
+     * Returns the maximum value recorded, or {@code Long.MIN_VALUE} if no
+     * values have been recorded
+     *
+     * @return the maximum value, or {@code Long.MIN_VALUE} if none
+     */
+    public final long getMax() {
+        return max;
+    }
+
+    /**
+     * Returns the arithmetic mean of values recorded, or zero if no values have been
+     * recorded.
+     *
+     * @return The arithmetic mean of values, or zero if none
+     */
+    public final double getAverage() {
+        return getCount() > 0 ? (double) getSum() / getCount() : 0.0d;
+    }
+
+    @Override
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     */
+    public String toString() {
+        return String.format(
+            "%s{count=%d, sum=%d, min=%d, average=%f, max=%d}",
+            this.getClass().getSimpleName(),
+            getCount(),
+            getSum(),
+            getMin(),
+            getAverage(),
+            getMax());
+    }
+}
diff --git a/java/util/Map.annotated.java b/java/util/Map.annotated.java
new file mode 100644
index 0000000..c19add2
--- /dev/null
+++ b/java/util/Map.annotated.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.function.Function;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Map<K, V> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key);
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value);
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key);
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value);
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key);
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m);
+
+public void clear();
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet();
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values();
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public default V getOrDefault(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable V defaultValue) { throw new RuntimeException("Stub!"); }
+
+public default void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public default void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V putIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public default boolean remove(@libcore.util.Nullable java.lang.Object key, @libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+public default boolean replace(@libcore.util.NullFromTypeParam K key, @libcore.util.Nullable V oldValue, @libcore.util.NullFromTypeParam V newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V replace(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V computeIfAbsent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NullFromTypeParam K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V computeIfPresent(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V compute(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public default V merge(@libcore.util.NullFromTypeParam K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> of(@libcore.util.NonNull K k1, @libcore.util.NonNull V v1, @libcore.util.NonNull K k2, @libcore.util.NonNull V v2, @libcore.util.NonNull K k3, @libcore.util.NonNull V v3, @libcore.util.NonNull K k4, @libcore.util.NonNull V v4, @libcore.util.NonNull K k5, @libcore.util.NonNull V v5, @libcore.util.NonNull K k6, @libcore.util.NonNull V v6, @libcore.util.NonNull K k7, @libcore.util.NonNull V v7, @libcore.util.NonNull K k8, @libcore.util.NonNull V v8, @libcore.util.NonNull K k9, @libcore.util.NonNull V v9, @libcore.util.NonNull K k10, @libcore.util.NonNull V v10) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <K, V>  java.util.Map<@libcore.util.NonNull K, @libcore.util.NonNull V> ofEntries(@libcore.util.NonNull java.util.Map.Entry<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V>... entries) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V>  java.util.Map.Entry<@libcore.util.NonNull K, @libcore.util.NonNull V> entry(@libcore.util.NonNull K k, @libcore.util.NonNull V v) { throw new RuntimeException("Stub!"); }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static interface Entry<K, V> {
+
[email protected] public K getKey();
+
[email protected] public V getValue();
+
[email protected] public V setValue(@libcore.util.NullFromTypeParam V value);
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public static <K extends java.lang.Comparable<? super K>, V> java.util.Comparator<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.Nullable V>> comparingByKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V extends java.lang.Comparable<? super V>> java.util.Comparator<[email protected] Entry<@libcore.util.Nullable K, @libcore.util.NonNull V>> comparingByValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Comparator<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.Nullable V>> comparingByKey(@libcore.util.NonNull java.util.Comparator<? super @libcore.util.NullFromTypeParam K> cmp) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <K, V> java.util.Comparator<[email protected] Entry<@libcore.util.Nullable K, @libcore.util.NullFromTypeParam V>> comparingByValue(@libcore.util.NonNull java.util.Comparator<? super @libcore.util.NullFromTypeParam V> cmp) { throw new RuntimeException("Stub!"); }
+}
+
+}
diff --git a/java/util/Map.java b/java/util/Map.java
new file mode 100644
index 0000000..ed365ec
--- /dev/null
+++ b/java/util/Map.java
@@ -0,0 +1,1656 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.io.Serializable;
+
+// Android-changed: removed link to collections framework docs
+/**
+ * An object that maps keys to values.  A map cannot contain duplicate keys;
+ * each key can map to at most one value.
+ *
+ * <p>This interface takes the place of the {@code Dictionary} class, which
+ * was a totally abstract class rather than an interface.
+ *
+ * <p>The {@code Map} interface provides three <i>collection views</i>, which
+ * allow a map's contents to be viewed as a set of keys, collection of values,
+ * or set of key-value mappings.  The <i>order</i> of a map is defined as
+ * the order in which the iterators on the map's collection views return their
+ * elements.  Some map implementations, like the {@code TreeMap} class, make
+ * specific guarantees as to their order; others, like the {@code HashMap}
+ * class, do not.
+ *
+ * <p>Note: great care must be exercised if mutable objects are used as map
+ * keys.  The behavior of a map is not specified if the value of an object is
+ * changed in a manner that affects {@code equals} comparisons while the
+ * object is a key in the map.  A special case of this prohibition is that it
+ * is not permissible for a map to contain itself as a key.  While it is
+ * permissible for a map to contain itself as a value, extreme caution is
+ * advised: the {@code equals} and {@code hashCode} methods are no longer
+ * well defined on such a map.
+ *
+ * <p>All general-purpose map implementation classes should provide two
+ * "standard" constructors: a void (no arguments) constructor which creates an
+ * empty map, and a constructor with a single argument of type {@code Map},
+ * which creates a new map with the same key-value mappings as its argument.
+ * In effect, the latter constructor allows the user to copy any map,
+ * producing an equivalent map of the desired class.  There is no way to
+ * enforce this recommendation (as interfaces cannot contain constructors) but
+ * all of the general-purpose map implementations in the JDK comply.
+ *
+ * <p>The "destructive" methods contained in this interface, that is, the
+ * methods that modify the map on which they operate, are specified to throw
+ * {@code UnsupportedOperationException} if this map does not support the
+ * operation.  If this is the case, these methods may, but are not required
+ * to, throw an {@code UnsupportedOperationException} if the invocation would
+ * have no effect on the map.  For example, invoking the {@link #putAll(Map)}
+ * method on an unmodifiable map may, but is not required to, throw the
+ * exception if the map whose mappings are to be "superimposed" is empty.
+ *
+ * <p>Some map implementations have restrictions on the keys and values they
+ * may contain.  For example, some implementations prohibit null keys and
+ * values, and some have restrictions on the types of their keys.  Attempting
+ * to insert an ineligible key or value throws an unchecked exception,
+ * typically {@code NullPointerException} or {@code ClassCastException}.
+ * Attempting to query the presence of an ineligible key or value may throw an
+ * exception, or it may simply return false; some implementations will exhibit
+ * the former behavior and some will exhibit the latter.  More generally,
+ * attempting an operation on an ineligible key or value whose completion
+ * would not result in the insertion of an ineligible element into the map may
+ * throw an exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <p>Many methods in Collections Framework interfaces are defined
+ * in terms of the {@link Object#equals(Object) equals} method.  For
+ * example, the specification for the {@link #containsKey(Object)
+ * containsKey(Object key)} method says: "returns {@code true} if and
+ * only if this map contains a mapping for a key {@code k} such that
+ * {@code (key==null ? k==null : key.equals(k))}." This specification should
+ * <i>not</i> be construed to imply that invoking {@code Map.containsKey}
+ * with a non-null argument {@code key} will cause {@code key.equals(k)} to
+ * be invoked for any key {@code k}.  Implementations are free to
+ * implement optimizations whereby the {@code equals} invocation is avoided,
+ * for example, by first comparing the hash codes of the two keys.  (The
+ * {@link Object#hashCode()} specification guarantees that two objects with
+ * unequal hash codes cannot be equal.)  More generally, implementations of
+ * the various Collections Framework interfaces are free to take advantage of
+ * the specified behavior of underlying {@link Object} methods wherever the
+ * implementor deems it appropriate.
+ *
+ * <p>Some map operations which perform recursive traversal of the map may fail
+ * with an exception for self-referential instances where the map directly or
+ * indirectly contains itself. This includes the {@code clone()},
+ * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
+ * Implementations may optionally handle the self-referential scenario, however
+ * most current implementations do not do so.
+ *
+ * <h2><a id="immutable">Immutable Map Static Factory Methods</a></h2>
+ * <p>The {@link Map#of() Map.of()} and
+ * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()}
+ * static factory methods provide a convenient way to create immutable maps.
+ * The {@code Map}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Keys and values cannot be added,
+ * removed, or updated. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained keys or values are themselves mutable, this may cause the
+ * Map to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} keys and values. Attempts to create them with
+ * {@code null} keys or values result in {@code NullPointerException}.
+ * <li>They are serializable if all keys and values are serializable.
+ * <li>They reject duplicate keys at creation time. Duplicate keys
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of mappings is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see HashMap
+ * @see TreeMap
+ * @see Hashtable
+ * @see SortedMap
+ * @see Collection
+ * @see Set
+ * @since 1.2
+ */
+// Android-changed: fix doc links to Collection#optional-restrictions
+public interface Map<K, V> {
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.  If the
+     * map contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @return {@code true} if this map contains no key-value mappings
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.  More formally, returns {@code true} if and only if
+     * this map contains a mapping for a key {@code k} such that
+     * {@code Objects.equals(key, k)}.  (There can be
+     * at most one such mapping.)
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified
+     *         key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean containsKey(Object key);
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  More formally, returns {@code true} if and only if
+     * this map contains at least one mapping to a value {@code v} such that
+     * {@code Objects.equals(value, v)}.  This operation
+     * will probably require time linear in the map size for most
+     * implementations of the {@code Map} interface.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws ClassCastException if the value is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified value is null and this
+     *         map does not permit null values
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean containsValue(Object value);
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that
+     * {@code Objects.equals(key, k)},
+     * then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>If this map permits null values, then a return value of
+     * {@code null} does not <i>necessarily</i> indicate that the map
+     * contains no mapping for the key; it's also possible that the map
+     * explicitly maps the key to {@code null}.  The {@link #containsKey
+     * containsKey} operation may be used to distinguish these two cases.
+     *
+     * @param key the key whose associated value is to be returned
+     * @return the value to which the specified key is mapped, or
+     *         {@code null} if this map contains no mapping for the key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    V get(Object key);
+
+    // Modification Operations
+
+    /**
+     * Associates the specified value with the specified key in this map
+     * (optional operation).  If the map previously contained a mapping for
+     * the key, the old value is replaced by the specified value.  (A map
+     * {@code m} is said to contain a mapping for a key {@code k} if and only
+     * if {@link #containsKey(Object) m.containsKey(k)} would return
+     * {@code true}.)
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key},
+     *         if the implementation supports {@code null} values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V put(K key, V value);
+
+    /**
+     * Removes the mapping for a key from this map if it is present
+     * (optional operation).   More formally, if this map contains a mapping
+     * from key {@code k} to value {@code v} such that
+     * {@code Objects.equals(key, k)}, that mapping
+     * is removed.  (The map can contain at most one such mapping.)
+     *
+     * <p>Returns the value to which this map previously associated the key,
+     * or {@code null} if the map contained no mapping for the key.
+     *
+     * <p>If this map permits null values, then a return value of
+     * {@code null} does not <i>necessarily</i> indicate that the map
+     * contained no mapping for the key; it's also possible that the map
+     * explicitly mapped the key to {@code null}.
+     *
+     * <p>The map will not contain a mapping for the specified key once the
+     * call returns.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the key is of an inappropriate type for
+     *         this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this
+     *         map does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    V remove(Object key);
+
+
+    // Bulk Operations
+
+    /**
+     * Copies all of the mappings from the specified map to this map
+     * (optional operation).  The effect of this call is equivalent to that
+     * of calling {@link #put(Object,Object) put(k, v)} on this map once
+     * for each mapping from key {@code k} to value {@code v} in the
+     * specified map.  The behavior of this operation is undefined if the
+     * specified map is modified while the operation is in progress.
+     *
+     * @param m mappings to be stored in this map
+     * @throws UnsupportedOperationException if the {@code putAll} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of a key or value in the
+     *         specified map prevents it from being stored in this map
+     * @throws NullPointerException if the specified map is null, or if
+     *         this map does not permit null keys or values, and the
+     *         specified map contains null keys or values
+     * @throws IllegalArgumentException if some property of a key or value in
+     *         the specified map prevents it from being stored in this map
+     */
+    void putAll(Map<? extends K, ? extends V> m);
+
+    /**
+     * Removes all of the mappings from this map (optional operation).
+     * The map will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} operation
+     *         is not supported by this map
+     */
+    void clear();
+
+
+    // Views
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a collection view of the values contained in this map
+     */
+    Collection<V> values();
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    Set<Map.Entry<K, V>> entrySet();
+
+    /**
+     * A map entry (key-value pair).  The {@code Map.entrySet} method returns
+     * a collection-view of the map, whose elements are of this class.  The
+     * <i>only</i> way to obtain a reference to a map entry is from the
+     * iterator of this collection-view.  These {@code Map.Entry} objects are
+     * valid <i>only</i> for the duration of the iteration; more formally,
+     * the behavior of a map entry is undefined if the backing map has been
+     * modified after the entry was returned by the iterator, except through
+     * the {@code setValue} operation on the map entry.
+     *
+     * @see Map#entrySet()
+     * @since 1.2
+     */
+    interface Entry<K, V> {
+        /**
+         * Returns the key corresponding to this entry.
+         *
+         * @return the key corresponding to this entry
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        K getKey();
+
+        /**
+         * Returns the value corresponding to this entry.  If the mapping
+         * has been removed from the backing map (by the iterator's
+         * {@code remove} operation), the results of this call are undefined.
+         *
+         * @return the value corresponding to this entry
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        V getValue();
+
+        /**
+         * Replaces the value corresponding to this entry with the specified
+         * value (optional operation).  (Writes through to the map.)  The
+         * behavior of this call is undefined if the mapping has already been
+         * removed from the map (by the iterator's {@code remove} operation).
+         *
+         * @param value new value to be stored in this entry
+         * @return old value corresponding to the entry
+         * @throws UnsupportedOperationException if the {@code put} operation
+         *         is not supported by the backing map
+         * @throws ClassCastException if the class of the specified value
+         *         prevents it from being stored in the backing map
+         * @throws NullPointerException if the backing map does not permit
+         *         null values, and the specified value is null
+         * @throws IllegalArgumentException if some property of this value
+         *         prevents it from being stored in the backing map
+         * @throws IllegalStateException implementations may, but are not
+         *         required to, throw this exception if the entry has been
+         *         removed from the backing map.
+         */
+        V setValue(V value);
+
+        /**
+         * Compares the specified object with this entry for equality.
+         * Returns {@code true} if the given object is also a map entry and
+         * the two entries represent the same mapping.  More formally, two
+         * entries {@code e1} and {@code e2} represent the same mapping
+         * if<pre>
+         *     (e1.getKey()==null ?
+         *      e2.getKey()==null : e1.getKey().equals(e2.getKey()))  &amp;&amp;
+         *     (e1.getValue()==null ?
+         *      e2.getValue()==null : e1.getValue().equals(e2.getValue()))
+         * </pre>
+         * This ensures that the {@code equals} method works properly across
+         * different implementations of the {@code Map.Entry} interface.
+         *
+         * @param o object to be compared for equality with this map entry
+         * @return {@code true} if the specified object is equal to this map
+         *         entry
+         */
+        boolean equals(Object o);
+
+        /**
+         * Returns the hash code value for this map entry.  The hash code
+         * of a map entry {@code e} is defined to be: <pre>
+         *     (e.getKey()==null   ? 0 : e.getKey().hashCode()) ^
+         *     (e.getValue()==null ? 0 : e.getValue().hashCode())
+         * </pre>
+         * This ensures that {@code e1.equals(e2)} implies that
+         * {@code e1.hashCode()==e2.hashCode()} for any two Entries
+         * {@code e1} and {@code e2}, as required by the general
+         * contract of {@code Object.hashCode}.
+         *
+         * @return the hash code value for this map entry
+         * @see Object#hashCode()
+         * @see Object#equals(Object)
+         * @see #equals(Object)
+         */
+        int hashCode();
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} in natural order on key.
+         *
+         * <p>The returned comparator is serializable and throws {@link
+         * NullPointerException} when comparing an entry with a null key.
+         *
+         * @param  <K> the {@link Comparable} type of then map keys
+         * @param  <V> the type of the map values
+         * @return a comparator that compares {@link Map.Entry} in natural order on key.
+         * @see Comparable
+         * @since 1.8
+         */
+        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} in natural order on value.
+         *
+         * <p>The returned comparator is serializable and throws {@link
+         * NullPointerException} when comparing an entry with null values.
+         *
+         * @param <K> the type of the map keys
+         * @param <V> the {@link Comparable} type of the map values
+         * @return a comparator that compares {@link Map.Entry} in natural order on value.
+         * @see Comparable
+         * @since 1.8
+         */
+        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} by key using the given
+         * {@link Comparator}.
+         *
+         * <p>The returned comparator is serializable if the specified comparator
+         * is also serializable.
+         *
+         * @param  <K> the type of the map keys
+         * @param  <V> the type of the map values
+         * @param  cmp the key {@link Comparator}
+         * @return a comparator that compares {@link Map.Entry} by the key.
+         * @since 1.8
+         */
+        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
+            Objects.requireNonNull(cmp);
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
+        }
+
+        /**
+         * Returns a comparator that compares {@link Map.Entry} by value using the given
+         * {@link Comparator}.
+         *
+         * <p>The returned comparator is serializable if the specified comparator
+         * is also serializable.
+         *
+         * @param  <K> the type of the map keys
+         * @param  <V> the type of the map values
+         * @param  cmp the value {@link Comparator}
+         * @return a comparator that compares {@link Map.Entry} by the value.
+         * @since 1.8
+         */
+        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
+            Objects.requireNonNull(cmp);
+            return (Comparator<Map.Entry<K, V>> & Serializable)
+                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
+        }
+    }
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this map for equality.  Returns
+     * {@code true} if the given object is also a map and the two maps
+     * represent the same mappings.  More formally, two maps {@code m1} and
+     * {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This ensures that the
+     * {@code equals} method works properly across different implementations
+     * of the {@code Map} interface.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this map.  The hash code of a map is
+     * defined to be the sum of the hash codes of each entry in the map's
+     * {@code entrySet()} view.  This ensures that {@code m1.equals(m2)}
+     * implies that {@code m1.hashCode()==m2.hashCode()} for any two maps
+     * {@code m1} and {@code m2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @return the hash code value for this map
+     * @see Map.Entry#hashCode()
+     * @see Object#equals(Object)
+     * @see #equals(Object)
+     */
+    int hashCode();
+
+    // Defaultable methods
+
+    /**
+     * Returns the value to which the specified key is mapped, or
+     * {@code defaultValue} if this map contains no mapping for the key.
+     *
+     * @implSpec
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the default mapping of the key
+     * @return the value to which the specified key is mapped, or
+     * {@code defaultValue} if this map contains no mapping for the key
+     * @throws ClassCastException if the key is of an inappropriate type for
+     * this map
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     * does not permit null keys
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (((v = get(key)) != null) || containsKey(key))
+            ? v
+            : defaultValue;
+    }
+
+    /**
+     * Performs the given action for each entry in this map until all entries
+     * have been processed or the action throws an exception.   Unless
+     * otherwise specified by the implementing class, actions are performed in
+     * the order of entry set iteration (if an iteration order is specified.)
+     * Exceptions thrown by the action are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     action.accept(entry.getKey(), entry.getValue());
+     * }</pre>
+     *
+     * The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param action The action to be performed for each entry
+     * @throws NullPointerException if the specified action is null
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+            action.accept(k, v);
+        }
+    }
+
+    /**
+     * Replaces each entry's value with the result of invoking the given
+     * function on that entry until all entries have been processed or the
+     * function throws an exception.  Exceptions thrown by the function are
+     * relayed to the caller.
+     *
+     * @implSpec
+     * <p>The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K, V> entry : map.entrySet())
+     *     entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param function the function to apply to each entry
+     * @throws UnsupportedOperationException if the {@code set} operation
+     * is not supported by this map's entry set iterator.
+     * @throws ClassCastException if the class of a replacement value
+     * prevents it from being stored in this map
+     * @throws NullPointerException if the specified function is null, or the
+     * specified replacement value is null, and this map does not permit null
+     * values
+     * @throws ClassCastException if a replacement value is of an inappropriate
+     *         type for this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if function or a replacement value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of a replacement value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ConcurrentModificationException if an entry is found to be
+     * removed during iteration
+     * @since 1.8
+     */
+    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        for (Map.Entry<K, V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+
+            // ise thrown from function is not a cme.
+            v = function.apply(k, v);
+
+            try {
+                entry.setValue(v);
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                throw new ConcurrentModificationException(ise);
+            }
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}) associates it with the given value and returns
+     * {@code null}, else returns the current value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code
+     * map}:
+     *
+     * <pre> {@code
+     * V v = map.get(key);
+     * if (v == null)
+     *     v = map.put(key, value);
+     *
+     * return v;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V putIfAbsent(K key, V value) {
+        V v = get(key);
+        if (v == null) {
+            v = put(key, value);
+        }
+
+        return v;
+    }
+
+    /**
+     * Removes the entry for the specified key only if it is currently
+     * mapped to the specified value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.remove(key);
+     *     return true;
+     * } else
+     *     return false;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default boolean remove(Object key, Object value) {
+        Object curValue = get(key);
+        if (!Objects.equals(curValue, value) ||
+            (curValue == null && !containsKey(key))) {
+            return false;
+        }
+        remove(key);
+        return true;
+    }
+
+    /**
+     * Replaces the entry for the specified key only if currently
+     * mapped to the specified value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+     *     map.put(key, newValue);
+     *     return true;
+     * } else
+     *     return false;
+     * }</pre>
+     *
+     * The default implementation does not throw NullPointerException
+     * for maps that do not support null values if oldValue is null unless
+     * newValue is also null.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of a specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if a specified key or newValue is null,
+     *         and this map does not permit null keys or values
+     * @throws NullPointerException if oldValue is null and this map does not
+     *         permit null values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of a specified key
+     *         or value prevents it from being stored in this map
+     * @since 1.8
+     */
+    default boolean replace(K key, V oldValue, V newValue) {
+        Object curValue = get(key);
+        if (!Objects.equals(curValue, oldValue) ||
+            (curValue == null && !containsKey(key))) {
+            return false;
+        }
+        put(key, newValue);
+        return true;
+    }
+
+    /**
+     * Replaces the entry for the specified key only if it is
+     * currently mapped to some value.
+     *
+     * @implSpec
+     * The default implementation is equivalent to, for this {@code map}:
+     *
+     * <pre> {@code
+     * if (map.containsKey(key)) {
+     *     return map.put(key, value);
+     * } else
+     *     return null;
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     * @since 1.8
+     */
+    default V replace(K key, V value) {
+        V curValue;
+        if (((curValue = get(key)) != null) || containsKey(key)) {
+            curValue = put(key, value);
+        }
+        return curValue;
+    }
+
+    /**
+     * If the specified key is not already associated with a value (or is mapped
+     * to {@code null}), attempts to compute its value using the given mapping
+     * function and enters it into this map unless {@code null}.
+     *
+     * <p>If the mapping function returns {@code null}, no mapping is recorded.
+     * If the mapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and no mapping is recorded.  The most
+     * common usage is to construct a new object serving as an initial
+     * mapped value or memoized result, as in:
+     *
+     * <pre> {@code
+     * map.computeIfAbsent(key, k -> new Value(f(k)));
+     * }</pre>
+     *
+     * <p>Or to implement a multi-value map, {@code Map<K,Collection<V>>},
+     * supporting multiple values per key:
+     *
+     * <pre> {@code
+     * map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);
+     * }</pre>
+     *
+     * <p>The mapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to the following steps for this
+     * {@code map}, then returning the current value or {@code null} if now
+     * absent:
+     *
+     * <pre> {@code
+     * if (map.get(key) == null) {
+     *     V newValue = mappingFunction.apply(key);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * mapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * mapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * mapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the mapping function is applied once atomically only if the value
+     * is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the mapping function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the mappingFunction
+     *         is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V computeIfAbsent(K key,
+            Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V v;
+        if ((v = get(key)) == null) {
+            V newValue;
+            if ((newValue = mappingFunction.apply(key)) != null) {
+                put(key, newValue);
+                return newValue;
+            }
+        }
+
+        return v;
+    }
+
+    /**
+     * If the value for the specified key is present and non-null, attempts to
+     * compute a new mapping given the key and its current mapped value.
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed.
+     * If the remapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if now absent:
+     *
+     * <pre> {@code
+     * if (map.get(key) != null) {
+     *     V oldValue = map.get(key);
+     *     V newValue = remappingFunction.apply(key, oldValue);
+     *     if (newValue != null)
+     *         map.put(key, newValue);
+     *     else
+     *         map.remove(key);
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the remapping function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the
+     *         remappingFunction is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V computeIfPresent(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V oldValue;
+        if ((oldValue = get(key)) != null) {
+            V newValue = remappingFunction.apply(key, oldValue);
+            if (newValue != null) {
+                put(key, newValue);
+                return newValue;
+            } else {
+                remove(key);
+                return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its current
+     * mapped value (or {@code null} if there is no current mapping). For
+     * example, to either create or append a {@code String} msg to a value
+     * mapping:
+     *
+     * <pre> {@code
+     * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
+     * (Method {@link #merge merge()} is often simpler to use for such purposes.)
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed
+     * (or remains absent if initially absent).  If the remapping function
+     * itself throws an (unchecked) exception, the exception is rethrown, and
+     * the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if absent:
+     *
+     * <pre> {@code
+     * V oldValue = map.get(key);
+     * V newValue = remappingFunction.apply(key, oldValue);
+     * if (oldValue != null) {
+     *    if (newValue != null)
+     *       map.put(key, newValue);
+     *    else
+     *       map.remove(key);
+     * } else {
+     *    if (newValue != null)
+     *       map.put(key, newValue);
+     *    else
+     *       return null;
+     * }
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the remapping function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null and
+     *         this map does not support null keys, or the
+     *         remappingFunction is null
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @since 1.8
+     */
+    default V compute(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        V oldValue = get(key);
+
+        V newValue = remappingFunction.apply(key, oldValue);
+        if (newValue == null) {
+            // delete mapping
+            if (oldValue != null || containsKey(key)) {
+                // something to remove
+                remove(key);
+                return null;
+            } else {
+                // nothing to do. Leave things as they were.
+                return null;
+            }
+        } else {
+            // add or replace old mapping
+            put(key, newValue);
+            return newValue;
+        }
+    }
+
+    /**
+     * If the specified key is not already associated with a value or is
+     * associated with null, associates it with the given non-null value.
+     * Otherwise, replaces the associated value with the results of the given
+     * remapping function, or removes if the result is {@code null}. This
+     * method may be of use when combining multiple mapped values for a key.
+     * For example, to either create or append a {@code String msg} to a
+     * value mapping:
+     *
+     * <pre> {@code
+     * map.merge(key, msg, String::concat)
+     * }</pre>
+     *
+     * <p>If the remapping function returns {@code null}, the mapping is removed.
+     * If the remapping function itself throws an (unchecked) exception, the
+     * exception is rethrown, and the current mapping is left unchanged.
+     *
+     * <p>The remapping function should not modify this map during computation.
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}, then returning the current value or
+     * {@code null} if absent:
+     *
+     * <pre> {@code
+     * V oldValue = map.get(key);
+     * V newValue = (oldValue == null) ? value :
+     *              remappingFunction.apply(oldValue, value);
+     * if (newValue == null)
+     *     map.remove(key);
+     * else
+     *     map.put(key, newValue);
+     * }</pre>
+     *
+     * <p>The default implementation makes no guarantees about detecting if the
+     * remapping function modifies this map during computation and, if
+     * appropriate, reporting an error. Non-concurrent implementations should
+     * override this method and, on a best-effort basis, throw a
+     * {@code ConcurrentModificationException} if it is detected that the
+     * remapping function modifies this map during computation. Concurrent
+     * implementations should override this method and, on a best-effort basis,
+     * throw an {@code IllegalStateException} if it is detected that the
+     * remapping function modifies this map during computation and as a result
+     * computation would never complete.
+     *
+     * <p>The default implementation makes no guarantees about synchronization
+     * or atomicity properties of this method. Any implementation providing
+     * atomicity guarantees must override this method and document its
+     * concurrency properties. In particular, all implementations of
+     * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+     * whether the remapping function is applied once atomically only if the
+     * value is not present.
+     *
+     * @param key key with which the resulting value is to be associated
+     * @param value the non-null value to be merged with the existing value
+     *        associated with the key or, if no existing value or a null value
+     *        is associated with the key, to be associated with the key
+     * @param remappingFunction the remapping function to recompute a value if
+     *        present
+     * @return the new value associated with the specified key, or null if no
+     *         value is associated with the key
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key is null and this map
+     *         does not support null keys or the value or remappingFunction is
+     *         null
+     * @since 1.8
+     */
+    default V merge(K key, V value,
+            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        V oldValue = get(key);
+        V newValue = (oldValue == null) ? value :
+                   remappingFunction.apply(oldValue, value);
+        if (newValue == null) {
+            remove(key);
+        } else {
+            put(key, newValue);
+        }
+        return newValue;
+    }
+
+    /**
+     * Returns an immutable map containing zero mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @return an empty {@code Map}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of() {
+        return ImmutableCollections.Map0.instance();
+    }
+
+    /**
+     * Returns an immutable map containing a single mapping.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the mapping's key
+     * @param v1 the mapping's value
+     * @return a {@code Map} containing the specified mapping
+     * @throws NullPointerException if the key or the value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1) {
+        return new ImmutableCollections.Map1<>(k1, v1);
+    }
+
+    /**
+     * Returns an immutable map containing two mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if the keys are duplicates
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
+    }
+
+    /**
+     * Returns an immutable map containing three mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
+    }
+
+    /**
+     * Returns an immutable map containing four mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
+    }
+
+    /**
+     * Returns an immutable map containing five mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
+    }
+
+    /**
+     * Returns an immutable map containing six mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6);
+    }
+
+    /**
+     * Returns an immutable map containing seven mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7);
+    }
+
+    /**
+     * Returns an immutable map containing eight mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8);
+    }
+
+    /**
+     * Returns an immutable map containing nine mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9);
+    }
+
+    /**
+     * Returns an immutable map containing ten mappings.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param k1 the first mapping's key
+     * @param v1 the first mapping's value
+     * @param k2 the second mapping's key
+     * @param v2 the second mapping's value
+     * @param k3 the third mapping's key
+     * @param v3 the third mapping's value
+     * @param k4 the fourth mapping's key
+     * @param v4 the fourth mapping's value
+     * @param k5 the fifth mapping's key
+     * @param v5 the fifth mapping's value
+     * @param k6 the sixth mapping's key
+     * @param v6 the sixth mapping's value
+     * @param k7 the seventh mapping's key
+     * @param v7 the seventh mapping's value
+     * @param k8 the eighth mapping's key
+     * @param v8 the eighth mapping's value
+     * @param k9 the ninth mapping's key
+     * @param v9 the ninth mapping's value
+     * @param k10 the tenth mapping's key
+     * @param v10 the tenth mapping's value
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any key or value is {@code null}
+     *
+     * @since 9
+     */
+    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
+                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
+        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
+                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
+    }
+
+    /**
+     * Returns an immutable map containing keys and values extracted from the given entries.
+     * The entries themselves are not stored in the map.
+     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
+     * For example,
+     *
+     * <pre>{@code
+     *     import static java.util.Map.entry;
+     *
+     *     Map<Integer,String> map = Map.ofEntries(
+     *         entry(1, "a"),
+     *         entry(2, "b"),
+     *         entry(3, "c"),
+     *         ...
+     *         entry(26, "z"));
+     * }</pre>
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param entries {@code Map.Entry}s containing the keys and values from which the map is populated
+     * @return a {@code Map} containing the specified mappings
+     * @throws IllegalArgumentException if there are any duplicate keys
+     * @throws NullPointerException if any entry, key, or value is {@code null}, or if
+     *         the {@code entries} array is {@code null}
+     *
+     * @see Map#entry Map.entry()
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
+        if (entries.length == 0) { // implicit null check of entries
+            return ImmutableCollections.Map0.instance();
+        } else if (entries.length == 1) {
+            return new ImmutableCollections.Map1<>(entries[0].getKey(),
+                                                   entries[0].getValue());
+        } else {
+            Object[] kva = new Object[entries.length << 1];
+            int a = 0;
+            for (Entry<? extends K, ? extends V> entry : entries) {
+                kva[a++] = entry.getKey();
+                kva[a++] = entry.getValue();
+            }
+            return new ImmutableCollections.MapN<>(kva);
+        }
+    }
+
+    /**
+     * Returns an immutable {@link Entry} containing the given key and value.
+     * These entries are suitable for populating {@code Map} instances using the
+     * {@link Map#ofEntries Map.ofEntries()} method.
+     * The {@code Entry} instances created by this method have the following characteristics:
+     *
+     * <ul>
+     * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
+     * key or value result in {@code NullPointerException}.
+     * <li>They are immutable. Calls to {@link Entry#setValue Entry.setValue()}
+     * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
+     * <li>They are not serializable.
+     * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+     * Callers should make no assumptions about the identity of the returned instances.
+     * This method is free to create new instances or reuse existing ones. Therefore,
+     * identity-sensitive operations on these instances (reference equality ({@code ==}),
+     * identity hash code, and synchronization) are unreliable and should be avoided.
+     * </ul>
+     *
+     * @apiNote
+     * For a serializable {@code Entry}, see {@link AbstractMap.SimpleEntry} or
+     * {@link AbstractMap.SimpleImmutableEntry}.
+     *
+     * @param <K> the key's type
+     * @param <V> the value's type
+     * @param k the key
+     * @param v the value
+     * @return an {@code Entry} containing the specified key and value
+     * @throws NullPointerException if the key or value is {@code null}
+     *
+     * @see Map#ofEntries Map.ofEntries()
+     * @since 9
+     */
+    static <K, V> Entry<K, V> entry(K k, V v) {
+        // KeyValueHolder checks for nulls
+        return new KeyValueHolder<>(k, v);
+    }
+}
diff --git a/java/util/MissingFormatArgumentException.java b/java/util/MissingFormatArgumentException.java
new file mode 100644
index 0000000..79b04a3
--- /dev/null
+++ b/java/util/MissingFormatArgumentException.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when there is a format specifier which does not
+ * have a corresponding argument or if an argument index refers to an argument
+ * that does not exist.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class MissingFormatArgumentException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19190115L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the unmatched format
+     * specifier.
+     *
+     * @param  s
+     *         Format specifier which does not have a corresponding argument
+     */
+    public MissingFormatArgumentException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the unmatched format specifier.
+     *
+     * @return  The unmatched format specifier
+     */
+    public String getFormatSpecifier() {
+        return s;
+    }
+
+    public String getMessage() {
+        return "Format specifier '" + s + "'";
+    }
+}
diff --git a/java/util/MissingFormatWidthException.java b/java/util/MissingFormatWidthException.java
new file mode 100644
index 0000000..9650fe2
--- /dev/null
+++ b/java/util/MissingFormatWidthException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when the format width is required.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class MissingFormatWidthException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 15560123L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the specified format
+     * specifier.
+     *
+     * @param  s
+     *         The format specifier which does not have a width
+     */
+    public MissingFormatWidthException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the format specifier which does not have a width.
+     *
+     * @return  The format specifier which does not have a width
+     */
+    public String getFormatSpecifier() {
+        return s;
+    }
+
+    public String getMessage() {
+        return s;
+    }
+}
diff --git a/java/util/MissingResourceException.java b/java/util/MissingResourceException.java
new file mode 100644
index 0000000..4586480
--- /dev/null
+++ b/java/util/MissingResourceException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+/**
+ * Signals that a resource is missing.
+ * @see java.lang.Exception
+ * @see ResourceBundle
+ * @author      Mark Davis
+ * @since       JDK1.1
+ */
+public
+class MissingResourceException extends RuntimeException {
+
+    /**
+     * Constructs a MissingResourceException with the specified information.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     * @param className the name of the resource class
+     * @param key the key for the missing resource.
+     */
+    public MissingResourceException(String s, String className, String key) {
+        super(s);
+        this.className = className;
+        this.key = key;
+    }
+
+    /**
+     * Constructs a <code>MissingResourceException</code> with
+     * <code>message</code>, <code>className</code>, <code>key</code>,
+     * and <code>cause</code>. This constructor is package private for
+     * use by <code>ResourceBundle.getBundle</code>.
+     *
+     * @param message
+     *        the detail message
+     * @param className
+     *        the name of the resource class
+     * @param key
+     *        the key for the missing resource.
+     * @param cause
+     *        the cause (which is saved for later retrieval by the
+     *        {@link Throwable.getCause()} method). (A null value is
+     *        permitted, and indicates that the cause is nonexistent
+     *        or unknown.)
+     */
+    MissingResourceException(String message, String className, String key, Throwable cause) {
+        super(message, cause);
+        this.className = className;
+        this.key = key;
+    }
+
+    /**
+     * Gets parameter passed by constructor.
+     *
+     * @return the name of the resource class
+     */
+    public String getClassName() {
+        return className;
+    }
+
+    /**
+     * Gets parameter passed by constructor.
+     *
+     * @return the key for the missing resource
+     */
+    public String getKey() {
+        return key;
+    }
+
+    //============ privates ============
+
+    // serialization compatibility with JDK1.1
+    private static final long serialVersionUID = -4876345176062000401L;
+
+    /**
+     * The class name of the resource bundle requested by the user.
+     * @serial
+     */
+    private String className;
+
+    /**
+     * The name of the specific resource requested by the user.
+     * @serial
+     */
+    private String key;
+}
diff --git a/java/util/NavigableMap.annotated.java b/java/util/NavigableMap.annotated.java
new file mode 100644
index 0000000..e3f4afb
--- /dev/null
+++ b/java/util/NavigableMap.annotated.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface NavigableMap<K, V> extends java.util.SortedMap<K,V> {
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lowerEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K lowerKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> floorEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K floorKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> ceilingEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K ceilingKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> higherEntry(@libcore.util.NullFromTypeParam K key);
+
[email protected] public K higherKey(@libcore.util.NullFromTypeParam K key);
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> firstEntry();
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lastEntry();
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollFirstEntry();
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollLastEntry();
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> descendingMap();
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> navigableKeySet();
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> descendingKeySet();
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, boolean fromInclusive, @libcore.util.NullFromTypeParam K toKey, boolean toInclusive);
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey, boolean inclusive);
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey, boolean inclusive);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, @libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey);
+}
diff --git a/java/util/NavigableMap.java b/java/util/NavigableMap.java
new file mode 100644
index 0000000..66b57c7
--- /dev/null
+++ b/java/util/NavigableMap.java
@@ -0,0 +1,426 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link SortedMap} extended with navigation methods returning the
+ * closest matches for given search targets. Methods
+ * {@link #lowerEntry}, {@link #floorEntry}, {@link #ceilingEntry},
+ * and {@link #higherEntry} return {@code Map.Entry} objects
+ * associated with keys respectively less than, less than or equal,
+ * greater than or equal, and greater than a given key, returning
+ * {@code null} if there is no such key.  Similarly, methods
+ * {@link #lowerKey}, {@link #floorKey}, {@link #ceilingKey}, and
+ * {@link #higherKey} return only the associated keys. All of these
+ * methods are designed for locating, not traversing entries.
+ *
+ * <p>A {@code NavigableMap} may be accessed and traversed in either
+ * ascending or descending key order.  The {@link #descendingMap}
+ * method returns a view of the map with the senses of all relational
+ * and directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones.  Methods
+ * {@link #subMap(Object, boolean, Object, boolean) subMap(K, boolean, K, boolean)},
+ * {@link #headMap(Object, boolean) headMap(K, boolean)}, and
+ * {@link #tailMap(Object, boolean) tailMap(K, boolean)}
+ * differ from the like-named {@code SortedMap} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive.  Submaps of any {@code NavigableMap}
+ * must implement the {@code NavigableMap} interface.
+ *
+ * <p>This interface additionally defines methods {@link #firstEntry},
+ * {@link #pollFirstEntry}, {@link #lastEntry}, and
+ * {@link #pollLastEntry} that return and/or remove the least and
+ * greatest mappings, if any exist, else returning {@code null}.
+ *
+ * <p>Implementations of entry-returning methods are expected to
+ * return {@code Map.Entry} pairs representing snapshots of mappings
+ * at the time they were produced, and thus generally do <em>not</em>
+ * support the optional {@code Entry.setValue} method. Note however
+ * that it is possible to change mappings in the associated map using
+ * method {@code put}.
+ *
+ * <p>Methods
+ * {@link #subMap(Object, Object) subMap(K, K)},
+ * {@link #headMap(Object) headMap(K)}, and
+ * {@link #tailMap(Object) tailMap(K)}
+ * are specified to return {@code SortedMap} to allow existing
+ * implementations of {@code SortedMap} to be compatibly retrofitted to
+ * implement {@code NavigableMap}, but extensions and implementations
+ * of this interface are encouraged to override these methods to return
+ * {@code NavigableMap}.  Similarly,
+ * {@link #keySet()} can be overridden to return {@link NavigableSet}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface NavigableMap<K,V> extends SortedMap<K,V> {
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * strictly less than the given key, or {@code null} if there is
+     * no such key.
+     *
+     * @param key the key
+     * @return an entry with the greatest key less than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> lowerEntry(K key);
+
+    /**
+     * Returns the greatest key strictly less than the given key, or
+     * {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the greatest key less than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K lowerKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * less than or equal to the given key, or {@code null} if there
+     * is no such key.
+     *
+     * @param key the key
+     * @return an entry with the greatest key less than or equal to
+     *         {@code key}, or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> floorEntry(K key);
+
+    /**
+     * Returns the greatest key less than or equal to the given key,
+     * or {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the greatest key less than or equal to {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K floorKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * greater than or equal to the given key, or {@code null} if
+     * there is no such key.
+     *
+     * @param key the key
+     * @return an entry with the least key greater than or equal to
+     *         {@code key}, or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> ceilingEntry(K key);
+
+    /**
+     * Returns the least key greater than or equal to the given key,
+     * or {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the least key greater than or equal to {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K ceilingKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * strictly greater than the given key, or {@code null} if there
+     * is no such key.
+     *
+     * @param key the key
+     * @return an entry with the least key greater than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    Map.Entry<K,V> higherEntry(K key);
+
+    /**
+     * Returns the least key strictly greater than the given key, or
+     * {@code null} if there is no such key.
+     *
+     * @param key the key
+     * @return the least key greater than {@code key},
+     *         or {@code null} if there is no such key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map does not permit null keys
+     */
+    K higherKey(K key);
+
+    /**
+     * Returns a key-value mapping associated with the least
+     * key in this map, or {@code null} if the map is empty.
+     *
+     * @return an entry with the least key,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> firstEntry();
+
+    /**
+     * Returns a key-value mapping associated with the greatest
+     * key in this map, or {@code null} if the map is empty.
+     *
+     * @return an entry with the greatest key,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> lastEntry();
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the least key in this map, or {@code null} if the map is empty.
+     *
+     * @return the removed first entry of this map,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> pollFirstEntry();
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the greatest key in this map, or {@code null} if the map is empty.
+     *
+     * @return the removed last entry of this map,
+     *         or {@code null} if this map is empty
+     */
+    Map.Entry<K,V> pollLastEntry();
+
+    /**
+     * Returns a reverse order view of the mappings contained in this map.
+     * The descending map is backed by this map, so changes to the map are
+     * reflected in the descending map, and vice-versa.  If either map is
+     * modified while an iteration over a collection view of either map
+     * is in progress (except through the iterator's own {@code remove}
+     * operation), the results of the iteration are undefined.
+     *
+     * <p>The returned map has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code m.descendingMap().descendingMap()} returns a
+     * view of {@code m} essentially equivalent to {@code m}.
+     *
+     * @return a reverse order view of this map
+     */
+    NavigableMap<K,V> descendingMap();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress (except through the iterator's own {@code
+     * remove} operation), the results of the iteration are undefined.  The
+     * set supports element removal, which removes the corresponding mapping
+     * from the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
+     * It does not support the {@code add} or {@code addAll} operations.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> navigableKeySet();
+
+    /**
+     * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in descending order.
+     * The set is backed by the map, so changes to the map are reflected in
+     * the set, and vice-versa.  If the map is modified while an iteration
+     * over the set is in progress (except through the iterator's own {@code
+     * remove} operation), the results of the iteration are undefined.  The
+     * set supports element removal, which removes the corresponding mapping
+     * from the map, via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear} operations.
+     * It does not support the {@code add} or {@code addAll} operations.
+     *
+     * @return a reverse order navigable set view of the keys in this map
+     */
+    NavigableSet<K> descendingKeySet();
+
+    /**
+     * Returns a view of the portion of this map whose keys range from
+     * {@code fromKey} to {@code toKey}.  If {@code fromKey} and
+     * {@code toKey} are equal, the returned map is empty unless
+     * {@code fromInclusive} and {@code toInclusive} are both true.  The
+     * returned map is backed by this map, so changes in the returned map are
+     * reflected in this map, and vice-versa.  The returned map supports all
+     * optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside of its range, or to construct a
+     * submap either of whose endpoints lie outside its range.
+     *
+     * @param fromKey low endpoint of the keys in the returned map
+     * @param fromInclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @param toKey high endpoint of the keys in the returned map
+     * @param toInclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys range from
+     *         {@code fromKey} to {@code toKey}
+     * @throws ClassCastException if {@code fromKey} and {@code toKey}
+     *         cannot be compared to one another using this map's comparator
+     *         (or, if the map has no comparator, using natural ordering).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} or {@code toKey}
+     *         cannot be compared to keys currently in the map.
+     * @throws NullPointerException if {@code fromKey} or {@code toKey}
+     *         is null and this map does not permit null keys
+     * @throws IllegalArgumentException if {@code fromKey} is greater than
+     *         {@code toKey}; or if this map itself has a restricted
+     *         range, and {@code fromKey} or {@code toKey} lies
+     *         outside the bounds of the range
+     */
+    NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                             K toKey,   boolean toInclusive);
+
+    /**
+     * Returns a view of the portion of this map whose keys are less than (or
+     * equal to, if {@code inclusive} is true) {@code toKey}.  The returned
+     * map is backed by this map, so changes in the returned map are reflected
+     * in this map, and vice-versa.  The returned map supports all optional
+     * map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param toKey high endpoint of the keys in the returned map
+     * @param inclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys are less than
+     *         (or equal to, if {@code inclusive} is true) {@code toKey}
+     * @throws ClassCastException if {@code toKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code toKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code toKey} lies outside the
+     *         bounds of the range
+     */
+    NavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+    /**
+     * Returns a view of the portion of this map whose keys are greater than (or
+     * equal to, if {@code inclusive} is true) {@code fromKey}.  The returned
+     * map is backed by this map, so changes in the returned map are reflected
+     * in this map, and vice-versa.  The returned map supports all optional
+     * map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint of the keys in the returned map
+     * @param inclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this map whose keys are greater than
+     *         (or equal to, if {@code inclusive} is true) {@code fromKey}
+     * @throws ClassCastException if {@code fromKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code fromKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code fromKey} lies outside the
+     *         bounds of the range
+     */
+    NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code subMap(fromKey, true, toKey, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code headMap(toKey, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> headMap(K toKey);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code tailMap(fromKey, true)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedMap<K,V> tailMap(K fromKey);
+}
diff --git a/java/util/NavigableSet.java b/java/util/NavigableSet.java
new file mode 100644
index 0000000..71d8dba
--- /dev/null
+++ b/java/util/NavigableSet.java
@@ -0,0 +1,323 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Josh Bloch with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+package java.util;
+
+/**
+ * A {@link SortedSet} extended with navigation methods reporting
+ * closest matches for given search targets. Methods {@link #lower},
+ * {@link #floor}, {@link #ceiling}, and {@link #higher} return elements
+ * respectively less than, less than or equal, greater than or equal,
+ * and greater than a given element, returning {@code null} if there
+ * is no such element.
+ *
+ * <p>A {@code NavigableSet} may be accessed and traversed in either
+ * ascending or descending order.  The {@link #descendingSet} method
+ * returns a view of the set with the senses of all relational and
+ * directional methods inverted. The performance of ascending
+ * operations and views is likely to be faster than that of descending
+ * ones.  This interface additionally defines methods {@link
+ * #pollFirst} and {@link #pollLast} that return and remove the lowest
+ * and highest element, if one exists, else returning {@code null}.
+ * Methods
+ * {@link #subSet(Object, boolean, Object, boolean) subSet(E, boolean, E, boolean)},
+ * {@link #headSet(Object, boolean) headSet(E, boolean)}, and
+ * {@link #tailSet(Object, boolean) tailSet(E, boolean)}
+ * differ from the like-named {@code SortedSet} methods in accepting
+ * additional arguments describing whether lower and upper bounds are
+ * inclusive versus exclusive.  Subsets of any {@code NavigableSet}
+ * must implement the {@code NavigableSet} interface.
+ *
+ * <p>The return values of navigation methods may be ambiguous in
+ * implementations that permit {@code null} elements. However, even
+ * in this case the result can be disambiguated by checking
+ * {@code contains(null)}. To avoid such issues, implementations of
+ * this interface are encouraged to <em>not</em> permit insertion of
+ * {@code null} elements. (Note that sorted sets of {@link
+ * Comparable} elements intrinsically do not permit {@code null}.)
+ *
+ * <p>Methods
+ * {@link #subSet(Object, Object) subSet(E, E)},
+ * {@link #headSet(Object) headSet(E)}, and
+ * {@link #tailSet(Object) tailSet(E)}
+ * are specified to return {@code SortedSet} to allow existing
+ * implementations of {@code SortedSet} to be compatibly retrofitted to
+ * implement {@code NavigableSet}, but extensions and implementations
+ * of this interface are encouraged to override these methods to return
+ * {@code NavigableSet}.
+ *
+ * @author Doug Lea
+ * @author Josh Bloch
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public interface NavigableSet<E> extends SortedSet<E> {
+    /**
+     * Returns the greatest element in this set strictly less than the
+     * given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the greatest element less than {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E lower(E e);
+
+    /**
+     * Returns the greatest element in this set less than or equal to
+     * the given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the greatest element less than or equal to {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E floor(E e);
+
+    /**
+     * Returns the least element in this set greater than or equal to
+     * the given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the least element greater than or equal to {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E ceiling(E e);
+
+    /**
+     * Returns the least element in this set strictly greater than the
+     * given element, or {@code null} if there is no such element.
+     *
+     * @param e the value to match
+     * @return the least element greater than {@code e},
+     *         or {@code null} if there is no such element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set does not permit null elements
+     */
+    E higher(E e);
+
+    /**
+     * Retrieves and removes the first (lowest) element,
+     * or returns {@code null} if this set is empty.
+     *
+     * @return the first element, or {@code null} if this set is empty
+     */
+    E pollFirst();
+
+    /**
+     * Retrieves and removes the last (highest) element,
+     * or returns {@code null} if this set is empty.
+     *
+     * @return the last element, or {@code null} if this set is empty
+     */
+    E pollLast();
+
+    /**
+     * Returns an iterator over the elements in this set, in ascending order.
+     *
+     * @return an iterator over the elements in this set, in ascending order
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns a reverse order view of the elements contained in this set.
+     * The descending set is backed by this set, so changes to the set are
+     * reflected in the descending set, and vice-versa.  If either set is
+     * modified while an iteration over either set is in progress (except
+     * through the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.
+     *
+     * <p>The returned set has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code s.descendingSet().descendingSet()} returns a
+     * view of {@code s} essentially equivalent to {@code s}.
+     *
+     * @return a reverse order view of this set
+     */
+    NavigableSet<E> descendingSet();
+
+    /**
+     * Returns an iterator over the elements in this set, in descending order.
+     * Equivalent in effect to {@code descendingSet().iterator()}.
+     *
+     * @return an iterator over the elements in this set, in descending order
+     */
+    Iterator<E> descendingIterator();
+
+    /**
+     * Returns a view of the portion of this set whose elements range from
+     * {@code fromElement} to {@code toElement}.  If {@code fromElement} and
+     * {@code toElement} are equal, the returned set is empty unless {@code
+     * fromInclusive} and {@code toInclusive} are both true.  The returned set
+     * is backed by this set, so changes in the returned set are reflected in
+     * this set, and vice-versa.  The returned set supports all optional set
+     * operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint of the returned set
+     * @param fromInclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @param toElement high endpoint of the returned set
+     * @param toInclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements range from
+     *         {@code fromElement}, inclusive, to {@code toElement}, exclusive
+     * @throws ClassCastException if {@code fromElement} and
+     *         {@code toElement} cannot be compared to one another using this
+     *         set's comparator (or, if the set has no comparator, using
+     *         natural ordering).  Implementations may, but are not required
+     *         to, throw this exception if {@code fromElement} or
+     *         {@code toElement} cannot be compared to elements currently in
+     *         the set.
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set does
+     *         not permit null elements
+     * @throws IllegalArgumentException if {@code fromElement} is
+     *         greater than {@code toElement}; or if this set itself
+     *         has a restricted range, and {@code fromElement} or
+     *         {@code toElement} lies outside the bounds of the range.
+     */
+    NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                           E toElement,   boolean toInclusive);
+
+    /**
+     * Returns a view of the portion of this set whose elements are less than
+     * (or equal to, if {@code inclusive} is true) {@code toElement}.  The
+     * returned set is backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set supports all
+     * optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param toElement high endpoint of the returned set
+     * @param inclusive {@code true} if the high endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements are less than
+     *         (or equal to, if {@code inclusive} is true) {@code toElement}
+     * @throws ClassCastException if {@code toElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code toElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code toElement} lies outside the
+     *         bounds of the range
+     */
+    NavigableSet<E> headSet(E toElement, boolean inclusive);
+
+    /**
+     * Returns a view of the portion of this set whose elements are greater
+     * than (or equal to, if {@code inclusive} is true) {@code fromElement}.
+     * The returned set is backed by this set, so changes in the returned set
+     * are reflected in this set, and vice-versa.  The returned set supports
+     * all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an {@code IllegalArgumentException}
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint of the returned set
+     * @param inclusive {@code true} if the low endpoint
+     *        is to be included in the returned view
+     * @return a view of the portion of this set whose elements are greater
+     *         than or equal to {@code fromElement}
+     * @throws ClassCastException if {@code fromElement} is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if {@code fromElement} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromElement} cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and {@code fromElement} lies outside the
+     *         bounds of the range
+     */
+    NavigableSet<E> tailSet(E fromElement, boolean inclusive);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code subSet(fromElement, true, toElement, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> subSet(E fromElement, E toElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code headSet(toElement, false)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> headSet(E toElement);
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Equivalent to {@code tailSet(fromElement, true)}.
+     *
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    SortedSet<E> tailSet(E fromElement);
+}
diff --git a/java/util/NoSuchElementException.java b/java/util/NoSuchElementException.java
new file mode 100644
index 0000000..15e1aad
--- /dev/null
+++ b/java/util/NoSuchElementException.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Thrown by various accessor methods to indicate that the element being requested
+ * does not exist.
+ *
+ * @author  unascribed
+ * @see     java.util.Enumeration#nextElement()
+ * @see     java.util.Iterator#next()
+ * @since   JDK1.0
+ */
+public
+class NoSuchElementException extends RuntimeException {
+    private static final long serialVersionUID = 6769829250639411880L;
+
+    /**
+     * Constructs a <code>NoSuchElementException</code> with <tt>null</tt>
+     * as its error message string.
+     */
+    public NoSuchElementException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>NoSuchElementException</code>, saving a reference
+     * to the error message string <tt>s</tt> for later retrieval by the
+     * <tt>getMessage</tt> method.
+     *
+     * @param   s   the detail message.
+     */
+    public NoSuchElementException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/Objects.annotated.java b/java/util/Objects.annotated.java
new file mode 100644
index 0000000..ee1b692
--- /dev/null
+++ b/java/util/Objects.annotated.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.util.function.Supplier;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Objects {
+
+Objects() { throw new RuntimeException("Stub!"); }
+
+public static boolean equals(@libcore.util.Nullable java.lang.Object a, @libcore.util.Nullable java.lang.Object b) { throw new RuntimeException("Stub!"); }
+
+public static boolean deepEquals(@libcore.util.Nullable java.lang.Object a, @libcore.util.Nullable java.lang.Object b) { throw new RuntimeException("Stub!"); }
+
+public static int hashCode(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public static int hash([email protected] Object @libcore.util.Nullable ... values) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String toString(@libcore.util.Nullable java.lang.Object o, @libcore.util.NonNull java.lang.String nullDefault) { throw new RuntimeException("Stub!"); }
+
+public static <T> int compare(@libcore.util.NullFromTypeParam T a, @libcore.util.NullFromTypeParam T b, @libcore.util.NonNull java.util.Comparator<? super @libcore.util.NullFromTypeParam T> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNull(@libcore.util.Nullable T obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNull(@libcore.util.Nullable T obj, @libcore.util.NonNull java.lang.String message) { throw new RuntimeException("Stub!"); }
+
+public static boolean isNull(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public static boolean nonNull(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNullElse(@libcore.util.Nullable T obj, @libcore.util.NonNull T defaultObj) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNullElseGet(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<? extends @libcore.util.NonNull T> supplier) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <T> T requireNonNull(@libcore.util.Nullable T obj, @libcore.util.NonNull java.util.function.Supplier<@libcore.util.NonNull java.lang.String> messageSupplier) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Objects.java b/java/util/Objects.java
new file mode 100644
index 0000000..1f76487
--- /dev/null
+++ b/java/util/Objects.java
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import jdk.internal.util.Preconditions;
+
+import java.util.function.Supplier;
+
+/**
+ * This class consists of {@code static} utility methods for operating
+ * on objects, or checking certain conditions before operation.  These utilities
+ * include {@code null}-safe or {@code null}-tolerant methods for computing the
+ * hash code of an object, returning a string for an object, comparing two
+ * objects, and checking if indexes or sub-range values are out-of-bounds.
+ *
+ * @apiNote
+ * Static methods such as {@link Objects#checkIndex},
+ * {@link Objects#checkFromToIndex}, and {@link Objects#checkFromIndexSize} are
+ * provided for the convenience of checking if values corresponding to indexes
+ * and sub-ranges are out-of-bounds.
+ * Variations of these static methods support customization of the runtime
+ * exception, and corresponding exception detail message, that is thrown when
+ * values are out-of-bounds.  Such methods accept a functional interface
+ * argument, instances of {@code BiFunction}, that maps out-of-bound values to a
+ * runtime exception.  Care should be taken when using such methods in
+ * combination with an argument that is a lambda expression, method reference or
+ * class that capture values.  In such cases the cost of capture, related to
+ * functional interface allocation, may exceed the cost of checking bounds.
+ *
+ * @since 1.7
+ */
+public final class Objects {
+    private Objects() {
+        throw new AssertionError("No java.util.Objects instances for you!");
+    }
+
+    /**
+     * Returns {@code true} if the arguments are equal to each other
+     * and {@code false} otherwise.
+     * Consequently, if both arguments are {@code null}, {@code true}
+     * is returned and if exactly one argument is {@code null}, {@code
+     * false} is returned.  Otherwise, equality is determined by using
+     * the {@link Object#equals equals} method of the first
+     * argument.
+     *
+     * @param a an object
+     * @param b an object to be compared with {@code a} for equality
+     * @return {@code true} if the arguments are equal to each other
+     * and {@code false} otherwise
+     * @see Object#equals(Object)
+     */
+    public static boolean equals(Object a, Object b) {
+        return (a == b) || (a != null && a.equals(b));
+    }
+
+   /**
+    * Returns {@code true} if the arguments are deeply equal to each other
+    * and {@code false} otherwise.
+    *
+    * Two {@code null} values are deeply equal.  If both arguments are
+    * arrays, the algorithm in {@link Arrays#deepEquals(Object[],
+    * Object[]) Arrays.deepEquals} is used to determine equality.
+    * Otherwise, equality is determined by using the {@link
+    * Object#equals equals} method of the first argument.
+    *
+    * @param a an object
+    * @param b an object to be compared with {@code a} for deep equality
+    * @return {@code true} if the arguments are deeply equal to each other
+    * and {@code false} otherwise
+    * @see Arrays#deepEquals(Object[], Object[])
+    * @see Objects#equals(Object, Object)
+    */
+    public static boolean deepEquals(Object a, Object b) {
+        if (a == b)
+            return true;
+        else if (a == null || b == null)
+            return false;
+        else
+            return Arrays.deepEquals0(a, b);
+    }
+
+    /**
+     * Returns the hash code of a non-{@code null} argument and 0 for
+     * a {@code null} argument.
+     *
+     * @param o an object
+     * @return the hash code of a non-{@code null} argument and 0 for
+     * a {@code null} argument
+     * @see Object#hashCode
+     */
+    public static int hashCode(Object o) {
+        return o != null ? o.hashCode() : 0;
+    }
+
+   /**
+    * Generates a hash code for a sequence of input values. The hash
+    * code is generated as if all the input values were placed into an
+    * array, and that array were hashed by calling {@link
+    * Arrays#hashCode(Object[])}.
+    *
+    * <p>This method is useful for implementing {@link
+    * Object#hashCode()} on objects containing multiple fields. For
+    * example, if an object that has three fields, {@code x}, {@code
+    * y}, and {@code z}, one could write:
+    *
+    * <blockquote><pre>
+    * &#064;Override public int hashCode() {
+    *     return Objects.hash(x, y, z);
+    * }
+    * </pre></blockquote>
+    *
+    * <b>Warning: When a single object reference is supplied, the returned
+    * value does not equal the hash code of that object reference.</b> This
+    * value can be computed by calling {@link #hashCode(Object)}.
+    *
+    * @param values the values to be hashed
+    * @return a hash value of the sequence of input values
+    * @see Arrays#hashCode(Object[])
+    * @see List#hashCode
+    */
+    public static int hash(Object... values) {
+        return Arrays.hashCode(values);
+    }
+
+    /**
+     * Returns the result of calling {@code toString} for a non-{@code
+     * null} argument and {@code "null"} for a {@code null} argument.
+     *
+     * @param o an object
+     * @return the result of calling {@code toString} for a non-{@code
+     * null} argument and {@code "null"} for a {@code null} argument
+     * @see Object#toString
+     * @see String#valueOf(Object)
+     */
+    public static String toString(Object o) {
+        return String.valueOf(o);
+    }
+
+    /**
+     * Returns the result of calling {@code toString} on the first
+     * argument if the first argument is not {@code null} and returns
+     * the second argument otherwise.
+     *
+     * @param o an object
+     * @param nullDefault string to return if the first argument is
+     *        {@code null}
+     * @return the result of calling {@code toString} on the first
+     * argument if it is not {@code null} and the second argument
+     * otherwise.
+     * @see Objects#toString(Object)
+     */
+    public static String toString(Object o, String nullDefault) {
+        return (o != null) ? o.toString() : nullDefault;
+    }
+
+    /**
+     * Returns 0 if the arguments are identical and {@code
+     * c.compare(a, b)} otherwise.
+     * Consequently, if both arguments are {@code null} 0
+     * is returned.
+     *
+     * <p>Note that if one of the arguments is {@code null}, a {@code
+     * NullPointerException} may or may not be thrown depending on
+     * what ordering policy, if any, the {@link Comparator Comparator}
+     * chooses to have for {@code null} values.
+     *
+     * @param <T> the type of the objects being compared
+     * @param a an object
+     * @param b an object to be compared with {@code a}
+     * @param c the {@code Comparator} to compare the first two arguments
+     * @return 0 if the arguments are identical and {@code
+     * c.compare(a, b)} otherwise.
+     * @see Comparable
+     * @see Comparator
+     */
+    public static <T> int compare(T a, T b, Comparator<? super T> c) {
+        return (a == b) ? 0 :  c.compare(a, b);
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null}. This
+     * method is designed primarily for doing parameter validation in methods
+     * and constructors, as demonstrated below:
+     * <blockquote><pre>
+     * public Foo(Bar bar) {
+     *     this.bar = Objects.requireNonNull(bar);
+     * }
+     * </pre></blockquote>
+     *
+     * @param obj the object reference to check for nullity
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     */
+    public static <T> T requireNonNull(T obj) {
+        if (obj == null)
+            throw new NullPointerException();
+        return obj;
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null} and
+     * throws a customized {@link NullPointerException} if it is. This method
+     * is designed primarily for doing parameter validation in methods and
+     * constructors with multiple parameters, as demonstrated below:
+     * <blockquote><pre>
+     * public Foo(Bar bar, Baz baz) {
+     *     this.bar = Objects.requireNonNull(bar, "bar must not be null");
+     *     this.baz = Objects.requireNonNull(baz, "baz must not be null");
+     * }
+     * </pre></blockquote>
+     *
+     * @param obj     the object reference to check for nullity
+     * @param message detail message to be used in the event that a {@code
+     *                NullPointerException} is thrown
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     */
+    public static <T> T requireNonNull(T obj, String message) {
+        if (obj == null)
+            throw new NullPointerException(message);
+        return obj;
+    }
+
+    /**
+     * Returns {@code true} if the provided reference is {@code null} otherwise
+     * returns {@code false}.
+     *
+     * @apiNote This method exists to be used as a
+     * {@link java.util.function.Predicate}, {@code filter(Objects::isNull)}
+     *
+     * @param obj a reference to be checked against {@code null}
+     * @return {@code true} if the provided reference is {@code null} otherwise
+     * {@code false}
+     *
+     * @see java.util.function.Predicate
+     * @since 1.8
+     */
+    public static boolean isNull(Object obj) {
+        return obj == null;
+    }
+
+    /**
+     * Returns {@code true} if the provided reference is non-{@code null}
+     * otherwise returns {@code false}.
+     *
+     * @apiNote This method exists to be used as a
+     * {@link java.util.function.Predicate}, {@code filter(Objects::nonNull)}
+     *
+     * @param obj a reference to be checked against {@code null}
+     * @return {@code true} if the provided reference is non-{@code null}
+     * otherwise {@code false}
+     *
+     * @see java.util.function.Predicate
+     * @since 1.8
+     */
+    public static boolean nonNull(Object obj) {
+        return obj != null;
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and
+     * otherwise returns the non-{@code null} second argument.
+     *
+     * @param obj an object
+     * @param defaultObj a non-{@code null} object to return if the first argument
+     *                   is {@code null}
+     * @param <T> the type of the reference
+     * @return the first argument if it is non-{@code null} and
+     *        otherwise the second argument if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        {@code defaultObj} is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElse(T obj, T defaultObj) {
+        return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
+    }
+
+    /**
+     * Returns the first argument if it is non-{@code null} and otherwise
+     * returns the non-{@code null} value of {@code supplier.get()}.
+     *
+     * @param obj an object
+     * @param supplier of a non-{@code null} object to return if the first argument
+     *                 is {@code null}
+     * @param <T> the type of the first argument and return type
+     * @return the first argument if it is non-{@code null} and otherwise
+     *         the value from {@code supplier.get()} if it is non-{@code null}
+     * @throws NullPointerException if both {@code obj} is null and
+     *        either the {@code supplier} is {@code null} or
+     *        the {@code supplier.get()} value is {@code null}
+     * @since 9
+     */
+    public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier) {
+        return (obj != null) ? obj
+                : requireNonNull(requireNonNull(supplier, "supplier").get(), "supplier.get()");
+    }
+
+    /**
+     * Checks that the specified object reference is not {@code null} and
+     * throws a customized {@link NullPointerException} if it is.
+     *
+     * <p>Unlike the method {@link #requireNonNull(Object, String)},
+     * this method allows creation of the message to be deferred until
+     * after the null check is made. While this may confer a
+     * performance advantage in the non-null case, when deciding to
+     * call this method care should be taken that the costs of
+     * creating the message supplier are less than the cost of just
+     * creating the string message directly.
+     *
+     * @param obj     the object reference to check for nullity
+     * @param messageSupplier supplier of the detail message to be
+     * used in the event that a {@code NullPointerException} is thrown
+     * @param <T> the type of the reference
+     * @return {@code obj} if not {@code null}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @since 1.8
+     */
+    public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
+        if (obj == null)
+            throw new NullPointerException(messageSupplier == null ?
+                                           null : messageSupplier.get());
+        return obj;
+    }
+
+    /**
+     * Checks if the {@code index} is within the bounds of the range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The {@code index} is defined to be out-of-bounds if any of the
+     * following inequalities is true:
+     * <ul>
+     *  <li>{@code index < 0}</li>
+     *  <li>{@code index >= length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param index the index
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code index} if it is within bounds of the range
+     * @throws IndexOutOfBoundsException if the {@code index} is out-of-bounds
+     * @since 9
+     */
+    // Android-removed: @ForceInline is an unsupported attribute.
+    //@ForceInline
+    public static
+    int checkIndex(int index, int length) {
+        return Preconditions.checkIndex(index, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code toIndex} (exclusive) is within the bounds of range from {@code 0}
+     * (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code fromIndex > toIndex}</li>
+     *  <li>{@code toIndex > length}</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-range
+     * @param toIndex the upper-bound (exclusive) of the sub-range
+     * @param length the upper-bound (exclusive) the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromToIndex(int fromIndex, int toIndex, int length) {
+        return Preconditions.checkFromToIndex(fromIndex, toIndex, length, null);
+    }
+
+    /**
+     * Checks if the sub-range from {@code fromIndex} (inclusive) to
+     * {@code fromIndex + size} (exclusive) is within the bounds of range from
+     * {@code 0} (inclusive) to {@code length} (exclusive).
+     *
+     * <p>The sub-range is defined to be out-of-bounds if any of the following
+     * inequalities is true:
+     * <ul>
+     *  <li>{@code fromIndex < 0}</li>
+     *  <li>{@code size < 0}</li>
+     *  <li>{@code fromIndex + size > length}, taking into account integer overflow</li>
+     *  <li>{@code length < 0}, which is implied from the former inequalities</li>
+     * </ul>
+     *
+     * @param fromIndex the lower-bound (inclusive) of the sub-interval
+     * @param size the size of the sub-range
+     * @param length the upper-bound (exclusive) of the range
+     * @return {@code fromIndex} if the sub-range within bounds of the range
+     * @throws IndexOutOfBoundsException if the sub-range is out-of-bounds
+     * @since 9
+     */
+    public static
+    int checkFromIndexSize(int fromIndex, int size, int length) {
+        return Preconditions.checkFromIndexSize(fromIndex, size, length, null);
+    }
+
+}
diff --git a/java/util/Observable.java b/java/util/Observable.java
new file mode 100644
index 0000000..be01640
--- /dev/null
+++ b/java/util/Observable.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * This class represents an observable object, or "data"
+ * in the model-view paradigm. It can be subclassed to represent an
+ * object that the application wants to have observed.
+ * <p>
+ * An observable object can have one or more observers. An observer
+ * may be any object that implements interface <tt>Observer</tt>. After an
+ * observable instance changes, an application calling the
+ * <code>Observable</code>'s <code>notifyObservers</code> method
+ * causes all of its observers to be notified of the change by a call
+ * to their <code>update</code> method.
+ * <p>
+ * The order in which notifications will be delivered is unspecified.
+ * The default implementation provided in the Observable class will
+ * notify Observers in the order in which they registered interest, but
+ * subclasses may change this order, use no guaranteed order, deliver
+ * notifications on separate threads, or may guarantee that their
+ * subclass follows this order, as they choose.
+ * <p>
+ * Note that this notification mechanism has nothing to do with threads
+ * and is completely separate from the <tt>wait</tt> and <tt>notify</tt>
+ * mechanism of class <tt>Object</tt>.
+ * <p>
+ * When an observable object is newly created, its set of observers is
+ * empty. Two observers are considered the same if and only if the
+ * <tt>equals</tt> method returns true for them.
+ *
+ * @author  Chris Warth
+ * @see     java.util.Observable#notifyObservers()
+ * @see     java.util.Observable#notifyObservers(java.lang.Object)
+ * @see     java.util.Observer
+ * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+ * @since   JDK1.0
+ */
+public class Observable {
+    private boolean changed = false;
+    private Vector<Observer> obs;
+
+    /** Construct an Observable with zero Observers. */
+
+    public Observable() {
+        obs = new Vector<>();
+    }
+
+    /**
+     * Adds an observer to the set of observers for this object, provided
+     * that it is not the same as some observer already in the set.
+     * The order in which notifications will be delivered to multiple
+     * observers is not specified. See the class comment.
+     *
+     * @param   o   an observer to be added.
+     * @throws NullPointerException   if the parameter o is null.
+     */
+    public synchronized void addObserver(Observer o) {
+        if (o == null)
+            throw new NullPointerException();
+        if (!obs.contains(o)) {
+            obs.addElement(o);
+        }
+    }
+
+    /**
+     * Deletes an observer from the set of observers of this object.
+     * Passing <CODE>null</CODE> to this method will have no effect.
+     * @param   o   the observer to be deleted.
+     */
+    public synchronized void deleteObserver(Observer o) {
+        obs.removeElement(o);
+    }
+
+    /**
+     * If this object has changed, as indicated by the
+     * <code>hasChanged</code> method, then notify all of its observers
+     * and then call the <code>clearChanged</code> method to
+     * indicate that this object has no longer changed.
+     * <p>
+     * Each observer has its <code>update</code> method called with two
+     * arguments: this observable object and <code>null</code>. In other
+     * words, this method is equivalent to:
+     * <blockquote><tt>
+     * notifyObservers(null)</tt></blockquote>
+     *
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#hasChanged()
+     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+     */
+    public void notifyObservers() {
+        notifyObservers(null);
+    }
+
+    /**
+     * If this object has changed, as indicated by the
+     * <code>hasChanged</code> method, then notify all of its observers
+     * and then call the <code>clearChanged</code> method to indicate
+     * that this object has no longer changed.
+     * <p>
+     * Each observer has its <code>update</code> method called with two
+     * arguments: this observable object and the <code>arg</code> argument.
+     *
+     * @param   arg   any object.
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#hasChanged()
+     * @see     java.util.Observer#update(java.util.Observable, java.lang.Object)
+     */
+    public void notifyObservers(Object arg) {
+        /*
+         * a temporary array buffer, used as a snapshot of the state of
+         * current Observers.
+         */
+        Object[] arrLocal;
+
+        synchronized (this) {
+            /* We don't want the Observer doing callbacks into
+             * arbitrary code while holding its own Monitor.
+             * The code where we extract each Observable from
+             * the Vector and store the state of the Observer
+             * needs synchronization, but notifying observers
+             * does not (should not).  The worst result of any
+             * potential race-condition here is that:
+             * 1) a newly-added Observer will miss a
+             *   notification in progress
+             * 2) a recently unregistered Observer will be
+             *   wrongly notified when it doesn't care
+             */
+            // Android-changed: Call out to hasChanged() to figure out if something changes.
+            // Upstream code avoids calling the nonfinal hasChanged() from the synchronized block,
+            // but that would break compatibility for apps that override that method.
+            // if (!changed)
+            if (!hasChanged())
+                return;
+            arrLocal = obs.toArray();
+            clearChanged();
+        }
+
+        for (int i = arrLocal.length-1; i>=0; i--)
+            ((Observer)arrLocal[i]).update(this, arg);
+    }
+
+    /**
+     * Clears the observer list so that this object no longer has any observers.
+     */
+    public synchronized void deleteObservers() {
+        obs.removeAllElements();
+    }
+
+    /**
+     * Marks this <tt>Observable</tt> object as having been changed; the
+     * <tt>hasChanged</tt> method will now return <tt>true</tt>.
+     */
+    protected synchronized void setChanged() {
+        changed = true;
+    }
+
+    /**
+     * Indicates that this object has no longer changed, or that it has
+     * already notified all of its observers of its most recent change,
+     * so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
+     * This method is called automatically by the
+     * <code>notifyObservers</code> methods.
+     *
+     * @see     java.util.Observable#notifyObservers()
+     * @see     java.util.Observable#notifyObservers(java.lang.Object)
+     */
+    protected synchronized void clearChanged() {
+        changed = false;
+    }
+
+    /**
+     * Tests if this object has changed.
+     *
+     * @return  <code>true</code> if and only if the <code>setChanged</code>
+     *          method has been called more recently than the
+     *          <code>clearChanged</code> method on this object;
+     *          <code>false</code> otherwise.
+     * @see     java.util.Observable#clearChanged()
+     * @see     java.util.Observable#setChanged()
+     */
+    public synchronized boolean hasChanged() {
+        return changed;
+    }
+
+    /**
+     * Returns the number of observers of this <tt>Observable</tt> object.
+     *
+     * @return  the number of observers of this object.
+     */
+    public synchronized int countObservers() {
+        return obs.size();
+    }
+}
diff --git a/java/util/Observer.java b/java/util/Observer.java
new file mode 100644
index 0000000..ef64e14
--- /dev/null
+++ b/java/util/Observer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+/**
+ * A class can implement the <code>Observer</code> interface when it
+ * wants to be informed of changes in observable objects.
+ *
+ * @author  Chris Warth
+ * @see     java.util.Observable
+ * @since   JDK1.0
+ */
+public interface Observer {
+    /**
+     * This method is called whenever the observed object is changed. An
+     * application calls an <tt>Observable</tt> object's
+     * <code>notifyObservers</code> method to have all the object's
+     * observers notified of the change.
+     *
+     * @param   o     the observable object.
+     * @param   arg   an argument passed to the <code>notifyObservers</code>
+     *                 method.
+     */
+    void update(Observable o, Object arg);
+}
diff --git a/java/util/Optional.java b/java/util/Optional.java
new file mode 100644
index 0000000..bce8ff9
--- /dev/null
+++ b/java/util/Optional.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a non-null value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code get()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(java.lang.Object) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class Optional<T> {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final Optional<?> EMPTY = new Optional<>();
+
+    /**
+     * If non-null, the value; if null, indicates no value is present
+     */
+    private final T value;
+
+    /**
+     * Constructs an empty instance.
+     *
+     * @implNote Generally only one empty instance, {@link Optional#EMPTY},
+     * should exist per VM.
+     */
+    private Optional() {
+        this.value = null;
+    }
+
+    /**
+     * Returns an empty {@code Optional} instance.  No value is present for this
+     * Optional.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     * @param <T> Type of the non-existent value
+     * @return an empty {@code Optional}
+     */
+    public static<T> Optional<T> empty() {
+        @SuppressWarnings("unchecked")
+        Optional<T> t = (Optional<T>) EMPTY;
+        return t;
+    }
+
+    /**
+     * Constructs an instance with the value present.
+     *
+     * @param value the non-null value to be present
+     * @throws NullPointerException if value is null
+     */
+    private Optional(T value) {
+        this.value = Objects.requireNonNull(value);
+    }
+
+    /**
+     * Returns an {@code Optional} with the specified present non-null value.
+     *
+     * @param <T> the class of the value
+     * @param value the value to be present, which must be non-null
+     * @return an {@code Optional} with the value present
+     * @throws NullPointerException if value is null
+     */
+    public static <T> Optional<T> of(T value) {
+        return new Optional<>(value);
+    }
+
+    /**
+     * Returns an {@code Optional} describing the specified value, if non-null,
+     * otherwise returns an empty {@code Optional}.
+     *
+     * @param <T> the class of the value
+     * @param value the possibly-null value to describe
+     * @return an {@code Optional} with a present value if the specified value
+     * is non-null, otherwise an empty {@code Optional}
+     */
+    public static <T> Optional<T> ofNullable(T value) {
+        return value == null ? empty() : of(value);
+    }
+
+    /**
+     * If a value is present in this {@code Optional}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the non-null value held by this {@code Optional}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see Optional#isPresent()
+     */
+    public T get() {
+        if (value == null) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return value != null;
+    }
+
+    /**
+     * If a value is present, invoke the specified consumer with the value,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(Consumer<? super T> consumer) {
+        if (value != null)
+            consumer.accept(value);
+    }
+
+    /**
+     * If a value is present, and the value matches the given predicate,
+     * return an {@code Optional} describing the value, otherwise return an
+     * empty {@code Optional}.
+     *
+     * @param predicate a predicate to apply to the value, if present
+     * @return an {@code Optional} describing the value of this {@code Optional}
+     * if a value is present and the value matches the given predicate,
+     * otherwise an empty {@code Optional}
+     * @throws NullPointerException if the predicate is null
+     */
+    public Optional<T> filter(Predicate<? super T> predicate) {
+        Objects.requireNonNull(predicate);
+        if (!isPresent())
+            return this;
+        else
+            return predicate.test(value) ? this : empty();
+    }
+
+    /**
+     * If a value is present, apply the provided mapping function to it,
+     * and if the result is non-null, return an {@code Optional} describing the
+     * result.  Otherwise return an empty {@code Optional}.
+     *
+     * @apiNote This method supports post-processing on optional values, without
+     * the need to explicitly check for a return status.  For example, the
+     * following code traverses a stream of file names, selects one that has
+     * not yet been processed, and then opens that file, returning an
+     * {@code Optional<FileInputStream>}:
+     *
+     * <pre>{@code
+     *     Optional<FileInputStream> fis =
+     *         names.stream().filter(name -> !isProcessedYet(name))
+     *                       .findFirst()
+     *                       .map(name -> new FileInputStream(name));
+     * }</pre>
+     *
+     * Here, {@code findFirst} returns an {@code Optional<String>}, and then
+     * {@code map} returns an {@code Optional<FileInputStream>} for the desired
+     * file if one exists.
+     *
+     * @param <U> The type of the result of the mapping function
+     * @param mapper a mapping function to apply to the value, if present
+     * @return an {@code Optional} describing the result of applying a mapping
+     * function to the value of this {@code Optional}, if a value is present,
+     * otherwise an empty {@code Optional}
+     * @throws NullPointerException if the mapping function is null
+     */
+    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        if (!isPresent())
+            return empty();
+        else {
+            return Optional.ofNullable(mapper.apply(value));
+        }
+    }
+
+    /**
+     * If a value is present, apply the provided {@code Optional}-bearing
+     * mapping function to it, return that result, otherwise return an empty
+     * {@code Optional}.  This method is similar to {@link #map(Function)},
+     * but the provided mapper is one whose result is already an {@code Optional},
+     * and if invoked, {@code flatMap} does not wrap it with an additional
+     * {@code Optional}.
+     *
+     * @param <U> The type parameter to the {@code Optional} returned by
+     * @param mapper a mapping function to apply to the value, if present
+     *           the mapping function
+     * @return the result of applying an {@code Optional}-bearing mapping
+     * function to the value of this {@code Optional}, if a value is present,
+     * otherwise an empty {@code Optional}
+     * @throws NullPointerException if the mapping function is null or returns
+     * a null result
+     */
+    public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
+        Objects.requireNonNull(mapper);
+        if (!isPresent())
+            return empty();
+        else {
+            return Objects.requireNonNull(mapper.apply(value));
+        }
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present, may
+     * be null
+     * @return the value, if present, otherwise {@code other}
+     */
+    public T orElse(T other) {
+        return value != null ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code Supplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.get()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public T orElseGet(Supplier<? extends T> other) {
+        return value != null ? value : other.get();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
+        if (value != null) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this Optional. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code Optional} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code equals()}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof Optional)) {
+            return false;
+        }
+
+        Optional<?> other = (Optional<?>) obj;
+        return Objects.equals(value, other.value);
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(value);
+    }
+
+    /**
+     * Returns a non-empty string representation of this Optional suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present Optionals must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return value != null
+            ? String.format("Optional[%s]", value)
+            : "Optional.empty";
+    }
+}
diff --git a/java/util/OptionalDouble.java b/java/util/OptionalDouble.java
new file mode 100644
index 0000000..7112df1
--- /dev/null
+++ b/java/util/OptionalDouble.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a {@code double} value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code getAsDouble()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(double) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.DoubleConsumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class OptionalDouble {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalDouble EMPTY = new OptionalDouble();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final double value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote generally only one empty instance, {@link OptionalDouble#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalDouble() {
+        this.isPresent = false;
+        this.value = Double.NaN;
+    }
+
+    /**
+     * Returns an empty {@code OptionalDouble} instance.  No value is present for this
+     * OptionalDouble.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalDouble}.
+     */
+    public static OptionalDouble empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the value present.
+     *
+     * @param value the double value to be present.
+     */
+    private OptionalDouble(double value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Return an {@code OptionalDouble} with the specified value present.
+     *
+     * @param value the value to be present
+     * @return an {@code OptionalDouble} with the value present
+     */
+    public static OptionalDouble of(double value) {
+        return new OptionalDouble(value);
+    }
+
+    /**
+     * If a value is present in this {@code OptionalDouble}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the value held by this {@code OptionalDouble}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see OptionalDouble#isPresent()
+     */
+    public double getAsDouble() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * Have the specified consumer accept the value if a value is present,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(DoubleConsumer consumer) {
+        if (isPresent)
+            consumer.accept(value);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public double orElse(double other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code DoubleSupplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.getAsDouble()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public double orElseGet(DoubleSupplier other) {
+        return isPresent ? value : other.getAsDouble();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public<X extends Throwable> double orElseThrow(Supplier<X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this OptionalDouble. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalDouble} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code Double.compare() == 0}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof OptionalDouble)) {
+            return false;
+        }
+
+        OptionalDouble other = (OptionalDouble) obj;
+        return (isPresent && other.isPresent)
+               ? Double.compare(value, other.value) == 0
+               : isPresent == other.isPresent;
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Double.hashCode(value) : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present instances must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? String.format("OptionalDouble[%s]", value)
+                : "OptionalDouble.empty";
+    }
+}
diff --git a/java/util/OptionalInt.java b/java/util/OptionalInt.java
new file mode 100644
index 0000000..61cac03
--- /dev/null
+++ b/java/util/OptionalInt.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a {@code int} value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code getAsInt()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(int) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.IntConsumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class OptionalInt {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalInt EMPTY = new OptionalInt();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final int value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote Generally only one empty instance, {@link OptionalInt#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalInt() {
+        this.isPresent = false;
+        this.value = 0;
+    }
+
+    /**
+     * Returns an empty {@code OptionalInt} instance.  No value is present for this
+     * OptionalInt.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalInt}
+     */
+    public static OptionalInt empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the value present.
+     *
+     * @param value the int value to be present
+     */
+    private OptionalInt(int value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Return an {@code OptionalInt} with the specified value present.
+     *
+     * @param value the value to be present
+     * @return an {@code OptionalInt} with the value present
+     */
+    public static OptionalInt of(int value) {
+        return new OptionalInt(value);
+    }
+
+    /**
+     * If a value is present in this {@code OptionalInt}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the value held by this {@code OptionalInt}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see OptionalInt#isPresent()
+     */
+    public int getAsInt() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * Have the specified consumer accept the value if a value is present,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(IntConsumer consumer) {
+        if (isPresent)
+            consumer.accept(value);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public int orElse(int other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code IntSupplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.getAsInt()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public int orElseGet(IntSupplier other) {
+        return isPresent ? value : other.getAsInt();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public<X extends Throwable> int orElseThrow(Supplier<X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this OptionalInt. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalInt} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code ==}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof OptionalInt)) {
+            return false;
+        }
+
+        OptionalInt other = (OptionalInt) obj;
+        return (isPresent && other.isPresent)
+                ? value == other.value
+                : isPresent == other.isPresent;
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Integer.hashCode(value) : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present instances must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? String.format("OptionalInt[%s]", value)
+                : "OptionalInt.empty";
+    }
+}
diff --git a/java/util/OptionalLong.java b/java/util/OptionalLong.java
new file mode 100644
index 0000000..b337d83
--- /dev/null
+++ b/java/util/OptionalLong.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+// Android-changed: removed ValueBased paragraph.
+/**
+ * A container object which may or may not contain a {@code long} value.
+ * If a value is present, {@code isPresent()} will return {@code true} and
+ * {@code getAsLong()} will return the value.
+ *
+ * <p>Additional methods that depend on the presence or absence of a contained
+ * value are provided, such as {@link #orElse(long) orElse()}
+ * (return a default value if value not present) and
+ * {@link #ifPresent(java.util.function.LongConsumer) ifPresent()} (execute a block
+ * of code if the value is present).
+ *
+ * @since 1.8
+ */
+public final class OptionalLong {
+    /**
+     * Common instance for {@code empty()}.
+     */
+    private static final OptionalLong EMPTY = new OptionalLong();
+
+    /**
+     * If true then the value is present, otherwise indicates no value is present
+     */
+    private final boolean isPresent;
+    private final long value;
+
+    /**
+     * Construct an empty instance.
+     *
+     * @implNote generally only one empty instance, {@link OptionalLong#EMPTY},
+     * should exist per VM.
+     */
+    private OptionalLong() {
+        this.isPresent = false;
+        this.value = 0;
+    }
+
+    /**
+     * Returns an empty {@code OptionalLong} instance.  No value is present for this
+     * OptionalLong.
+     *
+     * @apiNote Though it may be tempting to do so, avoid testing if an object
+     * is empty by comparing with {@code ==} against instances returned by
+     * {@code Option.empty()}. There is no guarantee that it is a singleton.
+     * Instead, use {@link #isPresent()}.
+     *
+     *  @return an empty {@code OptionalLong}.
+     */
+    public static OptionalLong empty() {
+        return EMPTY;
+    }
+
+    /**
+     * Construct an instance with the value present.
+     *
+     * @param value the long value to be present
+     */
+    private OptionalLong(long value) {
+        this.isPresent = true;
+        this.value = value;
+    }
+
+    /**
+     * Return an {@code OptionalLong} with the specified value present.
+     *
+     * @param value the value to be present
+     * @return an {@code OptionalLong} with the value present
+     */
+    public static OptionalLong of(long value) {
+        return new OptionalLong(value);
+    }
+
+    /**
+     * If a value is present in this {@code OptionalLong}, returns the value,
+     * otherwise throws {@code NoSuchElementException}.
+     *
+     * @return the value held by this {@code OptionalLong}
+     * @throws NoSuchElementException if there is no value present
+     *
+     * @see OptionalLong#isPresent()
+     */
+    public long getAsLong() {
+        if (!isPresent) {
+            throw new NoSuchElementException("No value present");
+        }
+        return value;
+    }
+
+    /**
+     * Return {@code true} if there is a value present, otherwise {@code false}.
+     *
+     * @return {@code true} if there is a value present, otherwise {@code false}
+     */
+    public boolean isPresent() {
+        return isPresent;
+    }
+
+    /**
+     * Have the specified consumer accept the value if a value is present,
+     * otherwise do nothing.
+     *
+     * @param consumer block to be executed if a value is present
+     * @throws NullPointerException if value is present and {@code consumer} is
+     * null
+     */
+    public void ifPresent(LongConsumer consumer) {
+        if (isPresent)
+            consumer.accept(value);
+    }
+
+    /**
+     * Return the value if present, otherwise return {@code other}.
+     *
+     * @param other the value to be returned if there is no value present
+     * @return the value, if present, otherwise {@code other}
+     */
+    public long orElse(long other) {
+        return isPresent ? value : other;
+    }
+
+    /**
+     * Return the value if present, otherwise invoke {@code other} and return
+     * the result of that invocation.
+     *
+     * @param other a {@code LongSupplier} whose result is returned if no value
+     * is present
+     * @return the value if present otherwise the result of {@code other.getAsLong()}
+     * @throws NullPointerException if value is not present and {@code other} is
+     * null
+     */
+    public long orElseGet(LongSupplier other) {
+        return isPresent ? value : other.getAsLong();
+    }
+
+    /**
+     * Return the contained value, if present, otherwise throw an exception
+     * to be created by the provided supplier.
+     *
+     * @apiNote A method reference to the exception constructor with an empty
+     * argument list can be used as the supplier. For example,
+     * {@code IllegalStateException::new}
+     *
+     * @param <X> Type of the exception to be thrown
+     * @param exceptionSupplier The supplier which will return the exception to
+     * be thrown
+     * @return the present value
+     * @throws X if there is no value present
+     * @throws NullPointerException if no value is present and
+     * {@code exceptionSupplier} is null
+     */
+    public<X extends Throwable> long orElseThrow(Supplier<X> exceptionSupplier) throws X {
+        if (isPresent) {
+            return value;
+        } else {
+            throw exceptionSupplier.get();
+        }
+    }
+
+    /**
+     * Indicates whether some other object is "equal to" this OptionalLong. The
+     * other object is considered equal if:
+     * <ul>
+     * <li>it is also an {@code OptionalLong} and;
+     * <li>both instances have no value present or;
+     * <li>the present values are "equal to" each other via {@code ==}.
+     * </ul>
+     *
+     * @param obj an object to be tested for equality
+     * @return {code true} if the other object is "equal to" this object
+     * otherwise {@code false}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (!(obj instanceof OptionalLong)) {
+            return false;
+        }
+
+        OptionalLong other = (OptionalLong) obj;
+        return (isPresent && other.isPresent)
+                ? value == other.value
+                : isPresent == other.isPresent;
+    }
+
+    /**
+     * Returns the hash code value of the present value, if any, or 0 (zero) if
+     * no value is present.
+     *
+     * @return hash code value of the present value or 0 if no value is present
+     */
+    @Override
+    public int hashCode() {
+        return isPresent ? Long.hashCode(value) : 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * Returns a non-empty string representation of this object suitable for
+     * debugging. The exact presentation format is unspecified and may vary
+     * between implementations and versions.
+     *
+     * @implSpec If a value is present the result must include its string
+     * representation in the result. Empty and present instances must be
+     * unambiguously differentiable.
+     *
+     * @return the string representation of this instance
+     */
+    @Override
+    public String toString() {
+        return isPresent
+                ? String.format("OptionalLong[%s]", value)
+                : "OptionalLong.empty";
+    }
+}
diff --git a/java/util/PrimitiveIterator.java b/java/util/PrimitiveIterator.java
new file mode 100644
index 0000000..2bc864a
--- /dev/null
+++ b/java/util/PrimitiveIterator.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * A base type for primitive specializations of {@code Iterator}.  Specialized
+ * subtypes are provided for {@link OfInt int}, {@link OfLong long}, and
+ * {@link OfDouble double} values.
+ *
+ * <p>The specialized subtype default implementations of {@link Iterator#next}
+ * and {@link Iterator#forEachRemaining(java.util.function.Consumer)} box
+ * primitive values to instances of their corresponding wrapper class.  Such
+ * boxing may offset any advantages gained when using the primitive
+ * specializations.  To avoid boxing, the corresponding primitive-based methods
+ * should be used.  For example, {@link PrimitiveIterator.OfInt#nextInt()} and
+ * {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
+ * should be used in preference to {@link PrimitiveIterator.OfInt#next()} and
+ * {@link PrimitiveIterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
+ *
+ * <p>Iteration of primitive values using boxing-based methods
+ * {@link Iterator#next next()} and
+ * {@link Iterator#forEachRemaining(java.util.function.Consumer) forEachRemaining()},
+ * does not affect the order in which the values, transformed to boxed values,
+ * are encountered.
+ *
+ * @implNote
+ * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
+ * is set to {@code true} then diagnostic warnings are reported if boxing of
+ * primitive values occur when operating on primitive subtype specializations.
+ *
+ * @param <T> the type of elements returned by this PrimitiveIterator.  The
+ *        type must be a wrapper type for a primitive type, such as
+ *        {@code Integer} for the primitive {@code int} type.
+ * @param <T_CONS> the type of primitive consumer.  The type must be a
+ *        primitive specialization of {@link java.util.function.Consumer} for
+ *        {@code T}, such as {@link java.util.function.IntConsumer} for
+ *        {@code Integer}.
+ *
+ * @since 1.8
+ */
+public interface PrimitiveIterator<T, T_CONS> extends Iterator<T> {
+
+    /**
+     * Performs the given action for each remaining element, in the order
+     * elements occur when iterating, until all elements have been processed
+     * or the action throws an exception.  Errors or runtime exceptions
+     * thrown by the action are relayed to the caller.
+     *
+     * @param action The action to be performed for each element
+     * @throws NullPointerException if the specified action is null
+     */
+    @SuppressWarnings("overloads")
+    void forEachRemaining(T_CONS action);
+
+    /**
+     * An Iterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public static interface OfInt extends PrimitiveIterator<Integer, IntConsumer> {
+
+        /**
+         * Returns the next {@code int} element in the iteration.
+         *
+         * @return the next {@code int} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        int nextInt();
+
+        /**
+         * Performs the given action for each remaining element until all elements
+         * have been processed or the action throws an exception.  Actions are
+         * performed in the order of iteration, if that order is specified.
+         * Exceptions thrown by the action are relayed to the caller.
+         *
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextInt());
+         * }</pre>
+         *
+         * @param action The action to be performed for each element
+         * @throws NullPointerException if the specified action is null
+         */
+        default void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextInt());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextInt()}, and returns that boxed result.
+         */
+        @Override
+        default Integer next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+            return nextInt();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to {@link #forEachRemaining};
+         * otherwise the action is adapted to an instance of
+         * {@code IntConsumer}, by boxing the argument of {@code IntConsumer},
+         * and then passed to {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                forEachRemaining((IntConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.forEachRemainingInt(action::accept)");
+                forEachRemaining((IntConsumer) action::accept);
+            }
+        }
+
+    }
+
+    /**
+     * An Iterator specialized for {@code long} values.
+     * @since 1.8
+     */
+    public static interface OfLong extends PrimitiveIterator<Long, LongConsumer> {
+
+        /**
+         * Returns the next {@code long} element in the iteration.
+         *
+         * @return the next {@code long} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        long nextLong();
+
+        /**
+         * Performs the given action for each remaining element until all elements
+         * have been processed or the action throws an exception.  Actions are
+         * performed in the order of iteration, if that order is specified.
+         * Exceptions thrown by the action are relayed to the caller.
+         *
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextLong());
+         * }</pre>
+         *
+         * @param action The action to be performed for each element
+         * @throws NullPointerException if the specified action is null
+         */
+        default void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextLong());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextLong()}, and returns that boxed result.
+         */
+        @Override
+        default Long next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.nextLong()");
+            return nextLong();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to {@link #forEachRemaining};
+         * otherwise the action is adapted to an instance of
+         * {@code LongConsumer}, by boxing the argument of {@code LongConsumer},
+         * and then passed to {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                forEachRemaining((LongConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfLong.forEachRemainingLong(action::accept)");
+                forEachRemaining((LongConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * An Iterator specialized for {@code double} values.
+     * @since 1.8
+     */
+    public static interface OfDouble extends PrimitiveIterator<Double, DoubleConsumer> {
+
+        /**
+         * Returns the next {@code double} element in the iteration.
+         *
+         * @return the next {@code double} element in the iteration
+         * @throws NoSuchElementException if the iteration has no more elements
+         */
+        double nextDouble();
+
+        /**
+         * Performs the given action for each remaining element until all elements
+         * have been processed or the action throws an exception.  Actions are
+         * performed in the order of iteration, if that order is specified.
+         * Exceptions thrown by the action are relayed to the caller.
+         *
+         * @implSpec
+         * <p>The default implementation behaves as if:
+         * <pre>{@code
+         *     while (hasNext())
+         *         action.accept(nextDouble());
+         * }</pre>
+         *
+         * @param action The action to be performed for each element
+         * @throws NullPointerException if the specified action is null
+         */
+        default void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+            while (hasNext())
+                action.accept(nextDouble());
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * The default implementation boxes the result of calling
+         * {@link #nextDouble()}, and returns that boxed result.
+         */
+        @Override
+        default Double next() {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.nextLong()");
+            return nextDouble();
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #forEachRemaining}; otherwise the action is adapted to
+         * an instance of {@code DoubleConsumer}, by boxing the argument of
+         * {@code DoubleConsumer}, and then passed to
+         * {@link #forEachRemaining}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                forEachRemaining((DoubleConsumer) action);
+            }
+            else {
+                // The method reference action::accept is never null
+                Objects.requireNonNull(action);
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfDouble.forEachRemainingDouble(action::accept)");
+                forEachRemaining((DoubleConsumer) action::accept);
+            }
+        }
+    }
+}
diff --git a/java/util/PriorityQueue.java b/java/util/PriorityQueue.java
new file mode 100644
index 0000000..7c929bd
--- /dev/null
+++ b/java/util/PriorityQueue.java
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+
+/**
+ * An unbounded priority {@linkplain Queue queue} based on a priority heap.
+ * The elements of the priority queue are ordered according to their
+ * {@linkplain Comparable natural ordering}, or by a {@link Comparator}
+ * provided at queue construction time, depending on which constructor is
+ * used.  A priority queue does not permit {@code null} elements.
+ * A priority queue relying on natural ordering also does not permit
+ * insertion of non-comparable objects (doing so may result in
+ * {@code ClassCastException}).
+ *
+ * <p>The <em>head</em> of this queue is the <em>least</em> element
+ * with respect to the specified ordering.  If multiple elements are
+ * tied for least value, the head is one of those elements -- ties are
+ * broken arbitrarily.  The queue retrieval operations {@code poll},
+ * {@code remove}, {@code peek}, and {@code element} access the
+ * element at the head of the queue.
+ *
+ * <p>A priority queue is unbounded, but has an internal
+ * <i>capacity</i> governing the size of an array used to store the
+ * elements on the queue.  It is always at least as large as the queue
+ * size.  As elements are added to a priority queue, its capacity
+ * grows automatically.  The details of the growth policy are not
+ * specified.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the priority queue in any particular order. If you need ordered
+ * traversal, consider using {@code Arrays.sort(pq.toArray())}.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * Multiple threads should not access a {@code PriorityQueue}
+ * instance concurrently if any of the threads modifies the queue.
+ * Instead, use the thread-safe {@link
+ * java.util.concurrent.PriorityBlockingQueue} class.
+ *
+ * <p>Implementation note: this implementation provides
+ * O(log(n)) time for the enqueuing and dequeuing methods
+ * ({@code offer}, {@code poll}, {@code remove()} and {@code add});
+ * linear time for the {@code remove(Object)} and {@code contains(Object)}
+ * methods; and constant time for the retrieval methods
+ * ({@code peek}, {@code element}, and {@code size}).
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.5
+ * @author Josh Bloch, Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class PriorityQueue<E> extends AbstractQueue<E>
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = -7720805057305804111L;
+
+    private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+    /**
+     * Priority queue represented as a balanced binary heap: the two
+     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
+     * priority queue is ordered by comparator, or by the elements'
+     * natural ordering, if comparator is null: For each node n in the
+     * heap and each descendant d of n, n <= d.  The element with the
+     * lowest value is in queue[0], assuming the queue is nonempty.
+     */
+    transient Object[] queue; // non-private to simplify nested class access
+
+    /**
+     * The number of elements in the priority queue.
+     */
+    int size;
+
+    /**
+     * The comparator, or null if priority queue uses elements'
+     * natural ordering.
+     */
+    private final Comparator<? super E> comparator;
+
+    /**
+     * The number of times this priority queue has been
+     * <i>structurally modified</i>.  See AbstractList for gory details.
+     */
+    transient int modCount;     // non-private to simplify nested class access
+
+    /**
+     * Creates a {@code PriorityQueue} with the default initial
+     * capacity (11) that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     */
+    public PriorityQueue() {
+        this(DEFAULT_INITIAL_CAPACITY, null);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the specified initial
+     * capacity that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityQueue(int initialCapacity) {
+        this(initialCapacity, null);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the default initial capacity and
+     * whose elements are ordered according to the specified comparator.
+     *
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @since 1.8
+     */
+    public PriorityQueue(Comparator<? super E> comparator) {
+        this(DEFAULT_INITIAL_CAPACITY, comparator);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} with the specified initial capacity
+     * that orders its elements according to the specified comparator.
+     *
+     * @param  initialCapacity the initial capacity for this priority queue
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @throws IllegalArgumentException if {@code initialCapacity} is
+     *         less than 1
+     */
+    public PriorityQueue(int initialCapacity,
+                         Comparator<? super E> comparator) {
+        // Note: This restriction of at least one is not actually needed,
+        // but continues for 1.5 compatibility
+        if (initialCapacity < 1)
+            throw new IllegalArgumentException();
+        this.queue = new Object[initialCapacity];
+        this.comparator = comparator;
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified collection.  If the specified collection is an instance of
+     * a {@link SortedSet} or is another {@code PriorityQueue}, this
+     * priority queue will be ordered according to the same ordering.
+     * Otherwise, this priority queue will be ordered according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @param  c the collection whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified collection
+     *         cannot be compared to one another according to the priority
+     *         queue's ordering
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    @SuppressWarnings("unchecked")
+    public PriorityQueue(Collection<? extends E> c) {
+        if (c instanceof SortedSet<?>) {
+            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
+            this.comparator = (Comparator<? super E>) ss.comparator();
+            initElementsFromCollection(ss);
+        }
+        else if (c instanceof PriorityQueue<?>) {
+            PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
+            this.comparator = (Comparator<? super E>) pq.comparator();
+            initFromPriorityQueue(pq);
+        }
+        else {
+            this.comparator = null;
+            initFromCollection(c);
+        }
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified priority queue.  This priority queue will be
+     * ordered according to the same ordering as the given priority
+     * queue.
+     *
+     * @param  c the priority queue whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of {@code c} cannot be
+     *         compared to one another according to {@code c}'s
+     *         ordering
+     * @throws NullPointerException if the specified priority queue or any
+     *         of its elements are null
+     */
+    @SuppressWarnings("unchecked")
+    public PriorityQueue(PriorityQueue<? extends E> c) {
+        this.comparator = (Comparator<? super E>) c.comparator();
+        initFromPriorityQueue(c);
+    }
+
+    /**
+     * Creates a {@code PriorityQueue} containing the elements in the
+     * specified sorted set.   This priority queue will be ordered
+     * according to the same ordering as the given sorted set.
+     *
+     * @param  c the sorted set whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified sorted
+     *         set cannot be compared to one another according to the
+     *         sorted set's ordering
+     * @throws NullPointerException if the specified sorted set or any
+     *         of its elements are null
+     */
+    @SuppressWarnings("unchecked")
+    public PriorityQueue(SortedSet<? extends E> c) {
+        this.comparator = (Comparator<? super E>) c.comparator();
+        initElementsFromCollection(c);
+    }
+
+    private void initFromPriorityQueue(PriorityQueue<? extends E> c) {
+        if (c.getClass() == PriorityQueue.class) {
+            this.queue = c.toArray();
+            this.size = c.size();
+        } else {
+            initFromCollection(c);
+        }
+    }
+
+    private void initElementsFromCollection(Collection<? extends E> c) {
+        Object[] a = c.toArray();
+        // If c.toArray incorrectly doesn't return Object[], copy it.
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf(a, a.length, Object[].class);
+        int len = a.length;
+        if (len == 1 || this.comparator != null)
+            for (Object e : a)
+                if (e == null)
+                    throw new NullPointerException();
+        this.queue = a;
+        this.size = a.length;
+    }
+
+    /**
+     * Initializes queue array with elements from the given Collection.
+     *
+     * @param c the collection
+     */
+    private void initFromCollection(Collection<? extends E> c) {
+        initElementsFromCollection(c);
+        heapify();
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Increases the capacity of the array.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    private void grow(int minCapacity) {
+        int oldCapacity = queue.length;
+        // Double size if small; else grow by 50%
+        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
+                                         (oldCapacity + 2) :
+                                         (oldCapacity >> 1));
+        // overflow-conscious code
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        queue = Arrays.copyOf(queue, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with elements currently in this priority queue
+     *         according to the priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with elements currently in this priority queue
+     *         according to the priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        modCount++;
+        int i = size;
+        if (i >= queue.length)
+            grow(i + 1);
+        size = i + 1;
+        if (i == 0)
+            queue[0] = e;
+        else
+            siftUp(i, e);
+        return true;
+    }
+
+    @SuppressWarnings("unchecked")
+    public E peek() {
+        return (size == 0) ? null : (E) queue[0];
+    }
+
+    private int indexOf(Object o) {
+        if (o != null) {
+            for (int i = 0; i < size; i++)
+                if (o.equals(queue[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.  Returns {@code true} if and only if this queue contained
+     * the specified element (or equivalently, if this queue changed as a
+     * result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        int i = indexOf(o);
+        if (i == -1)
+            return false;
+        else {
+            removeAt(i);
+            return true;
+        }
+    }
+
+    /**
+     * Version of remove using reference equality, not equals.
+     * Needed by iterator.remove.
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if removed
+     */
+    boolean removeEq(Object o) {
+        for (int i = 0; i < size; i++) {
+            if (o == queue[i]) {
+                removeAt(i);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o) >= 0;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return Arrays.copyOf(queue, size);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If the queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than the queue), the element in
+     * the array immediately following the end of the collection is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final int size = this.size;
+        if (a.length < size)
+            // Make a new array of a's runtime type, but my contents:
+            return (T[]) Arrays.copyOf(queue, size, a.getClass());
+        System.arraycopy(queue, 0, a, 0, size);
+        if (a.length > size)
+            a[size] = null;
+        return a;
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue. The iterator
+     * does not return the elements in any particular order.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private final class Itr implements Iterator<E> {
+        /**
+         * Index (into queue array) of element to be returned by
+         * subsequent call to next.
+         */
+        private int cursor;
+
+        /**
+         * Index of element returned by most recent call to next,
+         * unless that element came from the forgetMeNot list.
+         * Set to -1 if element is deleted by a call to remove.
+         */
+        private int lastRet = -1;
+
+        /**
+         * A queue of elements that were moved from the unvisited portion of
+         * the heap into the visited portion as a result of "unlucky" element
+         * removals during the iteration.  (Unlucky element removals are those
+         * that require a siftup instead of a siftdown.)  We must visit all of
+         * the elements in this list to complete the iteration.  We do this
+         * after we've completed the "normal" iteration.
+         *
+         * We expect that most iterations, even those involving removals,
+         * will not need to store elements in this field.
+         */
+        private ArrayDeque<E> forgetMeNot;
+
+        /**
+         * Element returned by the most recent call to next iff that
+         * element was drawn from the forgetMeNot list.
+         */
+        private E lastRetElt;
+
+        /**
+         * The modCount value that the iterator believes that the backing
+         * Queue should have.  If this expectation is violated, the iterator
+         * has detected concurrent modification.
+         */
+        private int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            return cursor < size ||
+                (forgetMeNot != null && !forgetMeNot.isEmpty());
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (expectedModCount != modCount)
+                throw new ConcurrentModificationException();
+            if (cursor < size)
+                return (E) queue[lastRet = cursor++];
+            if (forgetMeNot != null) {
+                lastRet = -1;
+                lastRetElt = forgetMeNot.poll();
+                if (lastRetElt != null)
+                    return lastRetElt;
+            }
+            throw new NoSuchElementException();
+        }
+
+        public void remove() {
+            if (expectedModCount != modCount)
+                throw new ConcurrentModificationException();
+            if (lastRet != -1) {
+                E moved = PriorityQueue.this.removeAt(lastRet);
+                lastRet = -1;
+                if (moved == null)
+                    cursor--;
+                else {
+                    if (forgetMeNot == null)
+                        forgetMeNot = new ArrayDeque<>();
+                    forgetMeNot.add(moved);
+                }
+            } else if (lastRetElt != null) {
+                PriorityQueue.this.removeEq(lastRetElt);
+                lastRetElt = null;
+            } else {
+                throw new IllegalStateException();
+            }
+            expectedModCount = modCount;
+        }
+    }
+
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Removes all of the elements from this priority queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        for (int i = 0; i < size; i++)
+            queue[i] = null;
+        size = 0;
+    }
+
+    @SuppressWarnings("unchecked")
+    public E poll() {
+        if (size == 0)
+            return null;
+        int s = --size;
+        modCount++;
+        E result = (E) queue[0];
+        E x = (E) queue[s];
+        queue[s] = null;
+        if (s != 0)
+            siftDown(0, x);
+        return result;
+    }
+
+    /**
+     * Removes the ith element from queue.
+     *
+     * Normally this method leaves the elements at up to i-1,
+     * inclusive, untouched.  Under these circumstances, it returns
+     * null.  Occasionally, in order to maintain the heap invariant,
+     * it must swap a later element of the list with one earlier than
+     * i.  Under these circumstances, this method returns the element
+     * that was previously at the end of the list and is now at some
+     * position before i. This fact is used by iterator.remove so as to
+     * avoid missing traversing elements.
+     */
+    @SuppressWarnings("unchecked")
+    E removeAt(int i) {
+        // assert i >= 0 && i < size;
+        modCount++;
+        int s = --size;
+        if (s == i) // removed last element
+            queue[i] = null;
+        else {
+            E moved = (E) queue[s];
+            queue[s] = null;
+            siftDown(i, moved);
+            if (queue[i] == moved) {
+                siftUp(i, moved);
+                if (queue[i] != moved)
+                    return moved;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * promoting x up the tree until it is greater than or equal to
+     * its parent, or is the root.
+     *
+     * To simplify and speed up coercions and comparisons. the
+     * Comparable and Comparator versions are separated into different
+     * methods that are otherwise identical. (Similarly for siftDown.)
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     */
+    private void siftUp(int k, E x) {
+        if (comparator != null)
+            siftUpUsingComparator(k, x);
+        else
+            siftUpComparable(k, x);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftUpComparable(int k, E x) {
+        Comparable<? super E> key = (Comparable<? super E>) x;
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = queue[parent];
+            if (key.compareTo((E) e) >= 0)
+                break;
+            queue[k] = e;
+            k = parent;
+        }
+        queue[k] = key;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftUpUsingComparator(int k, E x) {
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = queue[parent];
+            if (comparator.compare(x, (E) e) >= 0)
+                break;
+            queue[k] = e;
+            k = parent;
+        }
+        queue[k] = x;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * demoting x down the tree repeatedly until it is less than or
+     * equal to its children or is a leaf.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     */
+    private void siftDown(int k, E x) {
+        if (comparator != null)
+            siftDownUsingComparator(k, x);
+        else
+            siftDownComparable(k, x);
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftDownComparable(int k, E x) {
+        Comparable<? super E> key = (Comparable<? super E>)x;
+        int half = size >>> 1;        // loop while a non-leaf
+        while (k < half) {
+            int child = (k << 1) + 1; // assume left child is least
+            Object c = queue[child];
+            int right = child + 1;
+            if (right < size &&
+                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
+                c = queue[child = right];
+            if (key.compareTo((E) c) <= 0)
+                break;
+            queue[k] = c;
+            k = child;
+        }
+        queue[k] = key;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void siftDownUsingComparator(int k, E x) {
+        int half = size >>> 1;
+        while (k < half) {
+            int child = (k << 1) + 1;
+            Object c = queue[child];
+            int right = child + 1;
+            if (right < size &&
+                comparator.compare((E) c, (E) queue[right]) > 0)
+                c = queue[child = right];
+            if (comparator.compare(x, (E) c) <= 0)
+                break;
+            queue[k] = c;
+            k = child;
+        }
+        queue[k] = x;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    @SuppressWarnings("unchecked")
+    private void heapify() {
+        for (int i = (size >>> 1) - 1; i >= 0; i--)
+            siftDown(i, (E) queue[i]);
+    }
+
+    /**
+     * Returns the comparator used to order the elements in this
+     * queue, or {@code null} if this queue is sorted according to
+     * the {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @return the comparator used to order this queue, or
+     *         {@code null} if this queue is sorted according to the
+     *         natural ordering of its elements
+     */
+    public Comparator<? super E> comparator() {
+        return comparator;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @serialData The length of the array backing the instance is
+     *             emitted (int), followed by all of its elements
+     *             (each an {@code Object}) in the proper order.
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out element count, and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out array length, for compatibility with 1.5 version
+        s.writeInt(Math.max(2, size + 1));
+
+        // Write out all elements in the "proper order".
+        for (int i = 0; i < size; i++)
+            s.writeObject(queue[i]);
+    }
+
+    /**
+     * Reconstitutes the {@code PriorityQueue} instance from a stream
+     * (that is, deserializes it).
+     *
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in size, and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in (and discard) array length
+        s.readInt();
+
+        queue = new Object[size];
+
+        // Read in all elements.
+        for (int i = 0; i < size; i++)
+            queue[i] = s.readObject();
+
+        // Elements are guaranteed to be in "proper order", but the
+        // spec has never explained what that might be.
+        heapify();
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public final Spliterator<E> spliterator() {
+        return new PriorityQueueSpliterator<>(this, 0, -1, 0);
+    }
+
+    static final class PriorityQueueSpliterator<E> implements Spliterator<E> {
+        /*
+         * This is very similar to ArrayList Spliterator, except for
+         * extra null checks.
+         */
+        private final PriorityQueue<E> pq;
+        private int index;            // current index, modified on advance/split
+        private int fence;            // -1 until first use
+        private int expectedModCount; // initialized when fence set
+
+        /** Creates new spliterator covering the given range. */
+        PriorityQueueSpliterator(PriorityQueue<E> pq, int origin, int fence,
+                                 int expectedModCount) {
+            this.pq = pq;
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize fence to size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                expectedModCount = pq.modCount;
+                hi = fence = pq.size;
+            }
+            return hi;
+        }
+
+        public PriorityQueueSpliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new PriorityQueueSpliterator<>(pq, lo, index = mid,
+                                               expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi, mc; // hoist accesses and checks from loop
+            PriorityQueue<E> q; Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((q = pq) != null && (a = q.queue) != null) {
+                if ((hi = fence) < 0) {
+                    mc = q.modCount;
+                    hi = q.size;
+                }
+                else
+                    mc = expectedModCount;
+                if ((i = index) >= 0 && (index = hi) <= a.length) {
+                    for (E e;; ++i) {
+                        if (i < hi) {
+                            if ((e = (E) a[i]) == null) // must be CME
+                                break;
+                            action.accept(e);
+                        }
+                        else if (q.modCount != mc)
+                            break;
+                        else
+                            return;
+                    }
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int hi = getFence(), lo = index;
+            if (lo >= 0 && lo < hi) {
+                index = lo + 1;
+                @SuppressWarnings("unchecked") E e = (E)pq.queue[lo];
+                if (e == null)
+                    throw new ConcurrentModificationException();
+                action.accept(e);
+                if (pq.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL;
+        }
+    }
+}
diff --git a/java/util/Properties.java b/java/util/Properties.java
new file mode 100644
index 0000000..b413abb
--- /dev/null
+++ b/java/util/Properties.java
@@ -0,0 +1,1232 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.OutputStreamWriter;
+import java.io.BufferedWriter;
+
+// Android-removed: Dead native2ascii links.
+// These links are also gone in OpenJDK 9.
+/**
+ * The {@code Properties} class represents a persistent set of
+ * properties. The {@code Properties} can be saved to a stream
+ * or loaded from a stream. Each key and its corresponding value in
+ * the property list is a string.
+ * <p>
+ * A property list can contain another property list as its
+ * "defaults"; this second property list is searched if
+ * the property key is not found in the original property list.
+ * <p>
+ * Because {@code Properties} inherits from {@code Hashtable}, the
+ * {@code put} and {@code putAll} methods can be applied to a
+ * {@code Properties} object.  Their use is strongly discouraged as they
+ * allow the caller to insert entries whose keys or values are not
+ * {@code Strings}.  The {@code setProperty} method should be used
+ * instead.  If the {@code store} or {@code save} method is called
+ * on a "compromised" {@code Properties} object that contains a
+ * non-{@code String} key or value, the call will fail. Similarly,
+ * the call to the {@code propertyNames} or {@code list} method
+ * will fail if it is called on a "compromised" {@code Properties}
+ * object that contains a non-{@code String} key.
+ *
+ * <p>
+ * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
+ * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
+ * methods load and store properties from and to a character based stream
+ * in a simple line-oriented format specified below.
+ *
+ * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
+ * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
+ * methods work the same way as the load(Reader)/store(Writer, String) pair, except
+ * the input/output stream is encoded in ISO 8859-1 character encoding.
+ * Characters that cannot be directly represented in this encoding can be written using
+ * Unicode escapes as defined in section 3.3 of
+ * <cite>The Java&trade; Language Specification</cite>;
+ * only a single 'u' character is allowed in an escape
+ * sequence. The native2ascii tool can be used to convert property files to and
+ * from other character encodings.
+ *
+ * <p> The {@link #loadFromXML(InputStream)} and {@link
+ * #storeToXML(OutputStream, String, String)} methods load and store properties
+ * in a simple XML format.  By default the UTF-8 character encoding is used,
+ * however a specific encoding may be specified if required. Implementations
+ * are required to support UTF-8 and UTF-16 and may support other encodings.
+ * An XML properties document has the following DOCTYPE declaration:
+ *
+ * <pre>
+ * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+ * </pre>
+ * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
+ * <i>not</i> accessed when exporting or importing properties; it merely
+ * serves as a string to uniquely identify the DTD, which is:
+ * <pre>
+ *    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
+ *
+ *    &lt;!-- DTD for properties --&gt;
+ *
+ *    &lt;!ELEMENT properties ( comment?, entry* ) &gt;
+ *
+ *    &lt;!ATTLIST properties version CDATA #FIXED "1.0"&gt;
+ *
+ *    &lt;!ELEMENT comment (#PCDATA) &gt;
+ *
+ *    &lt;!ELEMENT entry (#PCDATA) &gt;
+ *
+ *    &lt;!ATTLIST entry key CDATA #REQUIRED&gt;
+ * </pre>
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * <tt>Properties</tt> object without the need for external synchronization.
+ *
+ * @author  Arthur van Hoff
+ * @author  Michael McCloskey
+ * @author  Xueming Shen
+ * @since   JDK1.0
+ */
+public
+class Properties extends Hashtable<Object,Object> {
+    /**
+     * use serialVersionUID from JDK 1.1.X for interoperability
+     */
+     private static final long serialVersionUID = 4112578634029874840L;
+
+    /**
+     * A property list that contains default values for any keys not
+     * found in this property list.
+     *
+     * @serial
+     */
+    protected Properties defaults;
+
+    /**
+     * Creates an empty property list with no default values.
+     */
+    public Properties() {
+        this(null);
+    }
+
+    /**
+     * Creates an empty property list with the specified defaults.
+     *
+     * @param   defaults   the defaults.
+     */
+    public Properties(Properties defaults) {
+        this.defaults = defaults;
+    }
+
+    /**
+     * Calls the <tt>Hashtable</tt> method {@code put}. Provided for
+     * parallelism with the <tt>getProperty</tt> method. Enforces use of
+     * strings for property keys and values. The value returned is the
+     * result of the <tt>Hashtable</tt> call to {@code put}.
+     *
+     * @param key the key to be placed into this property list.
+     * @param value the value corresponding to <tt>key</tt>.
+     * @return     the previous value of the specified key in this property
+     *             list, or {@code null} if it did not have one.
+     * @see #getProperty
+     * @since    1.2
+     */
+    public synchronized Object setProperty(String key, String value) {
+        return put(key, value);
+    }
+
+
+    /**
+     * Reads a property list (key and element pairs) from the input
+     * character stream in a simple line-oriented format.
+     * <p>
+     * Properties are processed in terms of lines. There are two
+     * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
+     * A natural line is defined as a line of
+     * characters that is terminated either by a set of line terminator
+     * characters ({@code \n} or {@code \r} or {@code \r\n})
+     * or by the end of the stream. A natural line may be either a blank line,
+     * a comment line, or hold all or some of a key-element pair. A logical
+     * line holds all the data of a key-element pair, which may be spread
+     * out across several adjacent natural lines by escaping
+     * the line terminator sequence with a backslash character
+     * {@code \}.  Note that a comment line cannot be extended
+     * in this manner; every natural line that is a comment must have
+     * its own comment indicator, as described below. Lines are read from
+     * input until the end of the stream is reached.
+     *
+     * <p>
+     * A natural line that contains only white space characters is
+     * considered blank and is ignored.  A comment line has an ASCII
+     * {@code '#'} or {@code '!'} as its first non-white
+     * space character; comment lines are also ignored and do not
+     * encode key-element information.  In addition to line
+     * terminators, this format considers the characters space
+     * ({@code ' '}, {@code '\u005Cu0020'}), tab
+     * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed
+     * ({@code '\f'}, {@code '\u005Cu000C'}) to be white
+     * space.
+     *
+     * <p>
+     * If a logical line is spread across several natural lines, the
+     * backslash escaping the line terminator sequence, the line
+     * terminator sequence, and any white space at the start of the
+     * following line have no affect on the key or element values.
+     * The remainder of the discussion of key and element parsing
+     * (when loading) will assume all the characters constituting
+     * the key and element appear on a single natural line after
+     * line continuation characters have been removed.  Note that
+     * it is <i>not</i> sufficient to only examine the character
+     * preceding a line terminator sequence to decide if the line
+     * terminator is escaped; there must be an odd number of
+     * contiguous backslashes for the line terminator to be escaped.
+     * Since the input is processed from left to right, a
+     * non-zero even number of 2<i>n</i> contiguous backslashes
+     * before a line terminator (or elsewhere) encodes <i>n</i>
+     * backslashes after escape processing.
+     *
+     * <p>
+     * The key contains all of the characters in the line starting
+     * with the first non-white space character and up to, but not
+     * including, the first unescaped {@code '='},
+     * {@code ':'}, or white space character other than a line
+     * terminator. All of these key termination characters may be
+     * included in the key by escaping them with a preceding backslash
+     * character; for example,<p>
+     *
+     * {@code \:\=}<p>
+     *
+     * would be the two-character key {@code ":="}.  Line
+     * terminator characters can be included using {@code \r} and
+     * {@code \n} escape sequences.  Any white space after the
+     * key is skipped; if the first non-white space character after
+     * the key is {@code '='} or {@code ':'}, then it is
+     * ignored and any white space characters after it are also
+     * skipped.  All remaining characters on the line become part of
+     * the associated element string; if there are no remaining
+     * characters, the element is the empty string
+     * {@code ""}.  Once the raw character sequences
+     * constituting the key and element are identified, escape
+     * processing is performed as described above.
+     *
+     * <p>
+     * As an example, each of the following three lines specifies the key
+     * {@code "Truth"} and the associated element value
+     * {@code "Beauty"}:
+     * <pre>
+     * Truth = Beauty
+     *  Truth:Beauty
+     * Truth                    :Beauty
+     * </pre>
+     * As another example, the following three lines specify a single
+     * property:
+     * <pre>
+     * fruits                           apple, banana, pear, \
+     *                                  cantaloupe, watermelon, \
+     *                                  kiwi, mango
+     * </pre>
+     * The key is {@code "fruits"} and the associated element is:
+     * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
+     * Note that a space appears before each {@code \} so that a space
+     * will appear after each comma in the final result; the {@code \},
+     * line terminator, and leading white space on the continuation line are
+     * merely discarded and are <i>not</i> replaced by one or more other
+     * characters.
+     * <p>
+     * As a third example, the line:
+     * <pre>cheeses
+     * </pre>
+     * specifies that the key is {@code "cheeses"} and the associated
+     * element is the empty string {@code ""}.
+     * <p>
+     * <a name="unicodeescapes"></a>
+     * Characters in keys and elements can be represented in escape
+     * sequences similar to those used for character and string literals
+     * (see sections 3.3 and 3.10.6 of
+     * <cite>The Java&trade; Language Specification</cite>).
+     *
+     * The differences from the character escape sequences and Unicode
+     * escapes used for characters and strings are:
+     *
+     * <ul>
+     * <li> Octal escapes are not recognized.
+     *
+     * <li> The character sequence {@code \b} does <i>not</i>
+     * represent a backspace character.
+     *
+     * <li> The method does not treat a backslash character,
+     * {@code \}, before a non-valid escape character as an
+     * error; the backslash is silently dropped.  For example, in a
+     * Java string the sequence {@code "\z"} would cause a
+     * compile time error.  In contrast, this method silently drops
+     * the backslash.  Therefore, this method treats the two character
+     * sequence {@code "\b"} as equivalent to the single
+     * character {@code 'b'}.
+     *
+     * <li> Escapes are not necessary for single and double quotes;
+     * however, by the rule above, single and double quote characters
+     * preceded by a backslash still yield single and double quote
+     * characters, respectively.
+     *
+     * <li> Only a single 'u' character is allowed in a Unicode escape
+     * sequence.
+     *
+     * </ul>
+     * <p>
+     * The specified stream remains open after this method returns.
+     *
+     * @param   reader   the input character stream.
+     * @throws  IOException  if an error occurred when reading from the
+     *          input stream.
+     * @throws  IllegalArgumentException if a malformed Unicode escape
+     *          appears in the input.
+     * @since   1.6
+     */
+    public synchronized void load(Reader reader) throws IOException {
+        load0(new LineReader(reader));
+    }
+
+    /**
+     * Reads a property list (key and element pairs) from the input
+     * byte stream. The input stream is in a simple line-oriented
+     * format as specified in
+     * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
+     * the ISO 8859-1 character encoding; that is each byte is one Latin1
+     * character. Characters not in Latin1, and certain special characters,
+     * are represented in keys and elements using Unicode escapes as defined in
+     * section 3.3 of
+     * <cite>The Java&trade; Language Specification</cite>.
+     * <p>
+     * The specified stream remains open after this method returns.
+     *
+     * @param      inStream   the input stream.
+     * @exception  IOException  if an error occurred when reading from the
+     *             input stream.
+     * @throws     IllegalArgumentException if the input stream contains a
+     *             malformed Unicode escape sequence.
+     * @since 1.2
+     */
+    public synchronized void load(InputStream inStream) throws IOException {
+        load0(new LineReader(inStream));
+    }
+
+    private void load0 (LineReader lr) throws IOException {
+        char[] convtBuf = new char[1024];
+        int limit;
+        int keyLen;
+        int valueStart;
+        char c;
+        boolean hasSep;
+        boolean precedingBackslash;
+
+        while ((limit = lr.readLine()) >= 0) {
+            c = 0;
+            keyLen = 0;
+            valueStart = limit;
+            hasSep = false;
+
+            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
+            precedingBackslash = false;
+            while (keyLen < limit) {
+                c = lr.lineBuf[keyLen];
+                //need check if escaped.
+                if ((c == '=' ||  c == ':') && !precedingBackslash) {
+                    valueStart = keyLen + 1;
+                    hasSep = true;
+                    break;
+                // Android-changed: Treat all whitespace the same. http://b/25998006
+                // } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
+                } else if (Character.isWhitespace(c) && !precedingBackslash) {
+                    valueStart = keyLen + 1;
+                    break;
+                }
+                if (c == '\\') {
+                    precedingBackslash = !precedingBackslash;
+                } else {
+                    precedingBackslash = false;
+                }
+                keyLen++;
+            }
+            while (valueStart < limit) {
+                c = lr.lineBuf[valueStart];
+                // Android-changed: Treat all whitespace the same. http://b/25998006
+                // if (c != ' ' && c != '\t' &&  c != '\f') {
+                if (!Character.isWhitespace(c)) {
+                    if (!hasSep && (c == '=' ||  c == ':')) {
+                        hasSep = true;
+                    } else {
+                        break;
+                    }
+                }
+                valueStart++;
+            }
+            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
+            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
+            put(key, value);
+        }
+    }
+
+    /* Read in a "logical line" from an InputStream/Reader, skip all comment
+     * and blank lines and filter out those leading whitespace characters
+     * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
+     * Method returns the char length of the "logical line" and stores
+     * the line in "lineBuf".
+     */
+    class LineReader {
+        public LineReader(InputStream inStream) {
+            this.inStream = inStream;
+            inByteBuf = new byte[8192];
+        }
+
+        public LineReader(Reader reader) {
+            this.reader = reader;
+            inCharBuf = new char[8192];
+        }
+
+        byte[] inByteBuf;
+        char[] inCharBuf;
+        char[] lineBuf = new char[1024];
+        int inLimit = 0;
+        int inOff = 0;
+        InputStream inStream;
+        Reader reader;
+
+        int readLine() throws IOException {
+            int len = 0;
+            char c = 0;
+
+            boolean skipWhiteSpace = true;
+            boolean isCommentLine = false;
+            boolean isNewLine = true;
+            boolean appendedLineBegin = false;
+            boolean precedingBackslash = false;
+            boolean skipLF = false;
+
+            while (true) {
+                if (inOff >= inLimit) {
+                    inLimit = (inStream==null)?reader.read(inCharBuf)
+                                              :inStream.read(inByteBuf);
+                    inOff = 0;
+                    if (inLimit <= 0) {
+                        if (len == 0 || isCommentLine) {
+                            return -1;
+                        }
+                        if (precedingBackslash) {
+                            len--;
+                        }
+                        return len;
+                    }
+                }
+                if (inStream != null) {
+                    //The line below is equivalent to calling a
+                    //ISO8859-1 decoder.
+                    c = (char) (0xff & inByteBuf[inOff++]);
+                } else {
+                    c = inCharBuf[inOff++];
+                }
+                if (skipLF) {
+                    skipLF = false;
+                    if (c == '\n') {
+                        continue;
+                    }
+                }
+                if (skipWhiteSpace) {
+                    // Android-changed: Treat all whitespace the same. http://b/25998006
+                    // if (c == ' ' || c == '\t' || c == '\f') {
+                    if (Character.isWhitespace(c)) {
+                        continue;
+                    }
+                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
+                        continue;
+                    }
+                    skipWhiteSpace = false;
+                    appendedLineBegin = false;
+                }
+                if (isNewLine) {
+                    isNewLine = false;
+                    if (c == '#' || c == '!') {
+                        isCommentLine = true;
+                        continue;
+                    }
+                }
+
+                if (c != '\n' && c != '\r') {
+                    lineBuf[len++] = c;
+                    if (len == lineBuf.length) {
+                        int newLength = lineBuf.length * 2;
+                        if (newLength < 0) {
+                            newLength = Integer.MAX_VALUE;
+                        }
+                        char[] buf = new char[newLength];
+                        System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
+                        lineBuf = buf;
+                    }
+                    //flip the preceding backslash flag
+                    if (c == '\\') {
+                        precedingBackslash = !precedingBackslash;
+                    } else {
+                        precedingBackslash = false;
+                    }
+                }
+                else {
+                    // reached EOL
+                    if (isCommentLine || len == 0) {
+                        isCommentLine = false;
+                        isNewLine = true;
+                        skipWhiteSpace = true;
+                        len = 0;
+                        continue;
+                    }
+                    if (inOff >= inLimit) {
+                        inLimit = (inStream==null)
+                                  ?reader.read(inCharBuf)
+                                  :inStream.read(inByteBuf);
+                        inOff = 0;
+                        if (inLimit <= 0) {
+                            if (precedingBackslash) {
+                                len--;
+                            }
+                            return len;
+                        }
+                    }
+                    if (precedingBackslash) {
+                        len -= 1;
+                        //skip the leading whitespace characters in following line
+                        skipWhiteSpace = true;
+                        appendedLineBegin = true;
+                        precedingBackslash = false;
+                        if (c == '\r') {
+                            skipLF = true;
+                        }
+                    } else {
+                        return len;
+                    }
+                }
+            }
+        }
+    }
+
+    /*
+     * Converts encoded &#92;uxxxx to unicode chars
+     * and changes special saved chars to their original forms
+     */
+    private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
+        if (convtBuf.length < len) {
+            int newLen = len * 2;
+            if (newLen < 0) {
+                newLen = Integer.MAX_VALUE;
+            }
+            convtBuf = new char[newLen];
+        }
+        char aChar;
+        char[] out = convtBuf;
+        int outLen = 0;
+        int end = off + len;
+
+        while (off < end) {
+            aChar = in[off++];
+            if (aChar == '\\') {
+                aChar = in[off++];
+                if(aChar == 'u') {
+                    // Read the xxxx
+                    int value=0;
+                    for (int i=0; i<4; i++) {
+                        aChar = in[off++];
+                        switch (aChar) {
+                          case '0': case '1': case '2': case '3': case '4':
+                          case '5': case '6': case '7': case '8': case '9':
+                             value = (value << 4) + aChar - '0';
+                             break;
+                          case 'a': case 'b': case 'c':
+                          case 'd': case 'e': case 'f':
+                             value = (value << 4) + 10 + aChar - 'a';
+                             break;
+                          case 'A': case 'B': case 'C':
+                          case 'D': case 'E': case 'F':
+                             value = (value << 4) + 10 + aChar - 'A';
+                             break;
+                          default:
+                              throw new IllegalArgumentException(
+                                           "Malformed \\uxxxx encoding.");
+                        }
+                     }
+                    out[outLen++] = (char)value;
+                } else {
+                    if (aChar == 't') aChar = '\t';
+                    else if (aChar == 'r') aChar = '\r';
+                    else if (aChar == 'n') aChar = '\n';
+                    else if (aChar == 'f') aChar = '\f';
+                    out[outLen++] = aChar;
+                }
+            } else {
+                out[outLen++] = aChar;
+            }
+        }
+        return new String (out, 0, outLen);
+    }
+
+    /*
+     * Converts unicodes to encoded &#92;uxxxx and escapes
+     * special characters with a preceding slash
+     */
+    private String saveConvert(String theString,
+                               boolean escapeSpace,
+                               boolean escapeUnicode) {
+        int len = theString.length();
+        int bufLen = len * 2;
+        if (bufLen < 0) {
+            bufLen = Integer.MAX_VALUE;
+        }
+        StringBuffer outBuffer = new StringBuffer(bufLen);
+
+        for(int x=0; x<len; x++) {
+            char aChar = theString.charAt(x);
+            // Handle common case first, selecting largest block that
+            // avoids the specials below
+            if ((aChar > 61) && (aChar < 127)) {
+                if (aChar == '\\') {
+                    outBuffer.append('\\'); outBuffer.append('\\');
+                    continue;
+                }
+                outBuffer.append(aChar);
+                continue;
+            }
+            switch(aChar) {
+                case ' ':
+                    if (x == 0 || escapeSpace)
+                        outBuffer.append('\\');
+                    outBuffer.append(' ');
+                    break;
+                case '\t':outBuffer.append('\\'); outBuffer.append('t');
+                          break;
+                case '\n':outBuffer.append('\\'); outBuffer.append('n');
+                          break;
+                case '\r':outBuffer.append('\\'); outBuffer.append('r');
+                          break;
+                case '\f':outBuffer.append('\\'); outBuffer.append('f');
+                          break;
+                case '=': // Fall through
+                case ':': // Fall through
+                case '#': // Fall through
+                case '!':
+                    outBuffer.append('\\'); outBuffer.append(aChar);
+                    break;
+                default:
+                    if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
+                        outBuffer.append('\\');
+                        outBuffer.append('u');
+                        outBuffer.append(toHex((aChar >> 12) & 0xF));
+                        outBuffer.append(toHex((aChar >>  8) & 0xF));
+                        outBuffer.append(toHex((aChar >>  4) & 0xF));
+                        outBuffer.append(toHex( aChar        & 0xF));
+                    } else {
+                        outBuffer.append(aChar);
+                    }
+            }
+        }
+        return outBuffer.toString();
+    }
+
+    private static void writeComments(BufferedWriter bw, String comments)
+        throws IOException {
+        bw.write("#");
+        int len = comments.length();
+        int current = 0;
+        int last = 0;
+        char[] uu = new char[6];
+        uu[0] = '\\';
+        uu[1] = 'u';
+        while (current < len) {
+            char c = comments.charAt(current);
+            if (c > '\u00ff' || c == '\n' || c == '\r') {
+                if (last != current)
+                    bw.write(comments.substring(last, current));
+                if (c > '\u00ff') {
+                    uu[2] = toHex((c >> 12) & 0xf);
+                    uu[3] = toHex((c >>  8) & 0xf);
+                    uu[4] = toHex((c >>  4) & 0xf);
+                    uu[5] = toHex( c        & 0xf);
+                    bw.write(new String(uu));
+                } else {
+                    bw.newLine();
+                    if (c == '\r' &&
+                        current != len - 1 &&
+                        comments.charAt(current + 1) == '\n') {
+                        current++;
+                    }
+                    if (current == len - 1 ||
+                        (comments.charAt(current + 1) != '#' &&
+                        comments.charAt(current + 1) != '!'))
+                        bw.write("#");
+                }
+                last = current + 1;
+            }
+            current++;
+        }
+        if (last != current)
+            bw.write(comments.substring(last, current));
+        bw.newLine();
+    }
+
+    /**
+     * Calls the {@code store(OutputStream out, String comments)} method
+     * and suppresses IOExceptions that were thrown.
+     *
+     * @deprecated This method does not throw an IOException if an I/O error
+     * occurs while saving the property list.  The preferred way to save a
+     * properties list is via the {@code store(OutputStream out,
+     * String comments)} method or the
+     * {@code storeToXML(OutputStream os, String comment)} method.
+     *
+     * @param   out      an output stream.
+     * @param   comments   a description of the property list.
+     * @exception  ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not
+     *             {@code Strings}.
+     */
+    @Deprecated
+    public void save(OutputStream out, String comments)  {
+        try {
+            store(out, comments);
+        } catch (IOException e) {
+        }
+    }
+
+    /**
+     * Writes this property list (key and element pairs) in this
+     * {@code Properties} table to the output character stream in a
+     * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
+     * method.
+     * <p>
+     * Properties from the defaults table of this {@code Properties}
+     * table (if any) are <i>not</i> written out by this method.
+     * <p>
+     * If the comments argument is not null, then an ASCII {@code #}
+     * character, the comments string, and a line separator are first written
+     * to the output stream. Thus, the {@code comments} can serve as an
+     * identifying comment. Any one of a line feed ('\n'), a carriage
+     * return ('\r'), or a carriage return followed immediately by a line feed
+     * in comments is replaced by a line separator generated by the {@code Writer}
+     * and if the next character in comments is not character {@code #} or
+     * character {@code !} then an ASCII {@code #} is written out
+     * after that line separator.
+     * <p>
+     * Next, a comment line is always written, consisting of an ASCII
+     * {@code #} character, the current date and time (as if produced
+     * by the {@code toString} method of {@code Date} for the
+     * current time), and a line separator as generated by the {@code Writer}.
+     * <p>
+     * Then every entry in this {@code Properties} table is
+     * written out, one per line. For each entry the key string is
+     * written, then an ASCII {@code =}, then the associated
+     * element string. For the key, all space characters are
+     * written with a preceding {@code \} character.  For the
+     * element, leading space characters, but not embedded or trailing
+     * space characters, are written with a preceding {@code \}
+     * character. The key and element characters {@code #},
+     * {@code !}, {@code =}, and {@code :} are written
+     * with a preceding backslash to ensure that they are properly loaded.
+     * <p>
+     * After the entries have been written, the output stream is flushed.
+     * The output stream remains open after this method returns.
+     * <p>
+     *
+     * @param   writer      an output character stream writer.
+     * @param   comments   a description of the property list.
+     * @exception  IOException if writing this property list to the specified
+     *             output stream throws an <tt>IOException</tt>.
+     * @exception  ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not {@code Strings}.
+     * @exception  NullPointerException  if {@code writer} is null.
+     * @since 1.6
+     */
+    public void store(Writer writer, String comments)
+        throws IOException
+    {
+        store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
+                                                 : new BufferedWriter(writer),
+               comments,
+               false);
+    }
+
+    /**
+     * Writes this property list (key and element pairs) in this
+     * {@code Properties} table to the output stream in a format suitable
+     * for loading into a {@code Properties} table using the
+     * {@link #load(InputStream) load(InputStream)} method.
+     * <p>
+     * Properties from the defaults table of this {@code Properties}
+     * table (if any) are <i>not</i> written out by this method.
+     * <p>
+     * This method outputs the comments, properties keys and values in
+     * the same format as specified in
+     * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
+     * with the following differences:
+     * <ul>
+     * <li>The stream is written using the ISO 8859-1 character encoding.
+     *
+     * <li>Characters not in Latin-1 in the comments are written as
+     * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode
+     * hexadecimal value <i>xxxx</i>.
+     *
+     * <li>Characters less than {@code \u005Cu0020} and characters greater
+     * than {@code \u005Cu007E} in property keys or values are written
+     * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal
+     * value <i>xxxx</i>.
+     * </ul>
+     * <p>
+     * After the entries have been written, the output stream is flushed.
+     * The output stream remains open after this method returns.
+     * <p>
+     * @param   out      an output stream.
+     * @param   comments   a description of the property list.
+     * @exception  IOException if writing this property list to the specified
+     *             output stream throws an <tt>IOException</tt>.
+     * @exception  ClassCastException  if this {@code Properties} object
+     *             contains any keys or values that are not {@code Strings}.
+     * @exception  NullPointerException  if {@code out} is null.
+     * @since 1.2
+     */
+    public void store(OutputStream out, String comments)
+        throws IOException
+    {
+        store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
+               comments,
+               true);
+    }
+
+    private void store0(BufferedWriter bw, String comments, boolean escUnicode)
+        throws IOException
+    {
+        if (comments != null) {
+            writeComments(bw, comments);
+        }
+        bw.write("#" + new Date().toString());
+        bw.newLine();
+        synchronized (this) {
+            for (Enumeration<?> e = keys(); e.hasMoreElements();) {
+                String key = (String)e.nextElement();
+                String val = (String)get(key);
+                key = saveConvert(key, true, escUnicode);
+                /* No need to escape embedded and trailing spaces for value, hence
+                 * pass false to flag.
+                 */
+                val = saveConvert(val, false, escUnicode);
+                bw.write(key + "=" + val);
+                bw.newLine();
+            }
+        }
+        bw.flush();
+    }
+
+    /**
+     * Loads all of the properties represented by the XML document on the
+     * specified input stream into this properties table.
+     *
+     * <p>The XML document must have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     * Furthermore, the document must satisfy the properties DTD described
+     * above.
+     *
+     * <p> An implementation is required to read XML documents that use the
+     * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may
+     * support additional encodings.
+     *
+     * <p>The specified stream is closed after this method returns.
+     *
+     * @param in the input stream from which to read the XML document.
+     * @throws IOException if reading from the specified input stream
+     *         results in an <tt>IOException</tt>.
+     * @throws java.io.UnsupportedEncodingException if the document's encoding
+     *         declaration can be read and it specifies an encoding that is not
+     *         supported
+     * @throws InvalidPropertiesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     * @throws NullPointerException if {@code in} is null.
+     * @see    #storeToXML(OutputStream, String, String)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 1.5
+     */
+    public synchronized void loadFromXML(InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        // Android-changed: Keep OpenJDK7u40's XmlUtils.
+        // XmlSupport's system property based XmlPropertiesProvider
+        // selection does not make sense on Android and has too many
+        // dependencies on classes that are not available on Android.
+        //
+        // XmlSupport.load(this, Objects.requireNonNull(in));
+        XMLUtils.load(this, Objects.requireNonNull(in));
+        in.close();
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table.
+     *
+     * <p> An invocation of this method of the form <tt>props.storeToXML(os,
+     * comment)</tt> behaves in exactly the same way as the invocation
+     * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @param comment a description of the property list, or {@code null}
+     *        if no comment is desired.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws NullPointerException if {@code os} is null.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not
+     *         {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @since 1.5
+     */
+    public void storeToXML(OutputStream os, String comment)
+        throws IOException
+    {
+        storeToXML(os, comment, "UTF-8");
+    }
+
+    /**
+     * Emits an XML document representing all of the properties contained
+     * in this table, using the specified encoding.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>
+     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
+     * </pre>
+     *
+     * <p>If the specified comment is {@code null} then no comment
+     * will be stored in the document.
+     *
+     * <p> An implementation is required to support writing of XML documents
+     * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
+     * implementation may support additional encodings.
+     *
+     * <p>The specified stream remains open after this method returns.
+     *
+     * @param os        the output stream on which to emit the XML document.
+     * @param comment   a description of the property list, or {@code null}
+     *                  if no comment is desired.
+     * @param  encoding the name of a supported
+     *                  <a href="../lang/package-summary.html#charenc">
+     *                  character encoding</a>
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws java.io.UnsupportedEncodingException if the encoding is not
+     *         supported by the implementation.
+     * @throws NullPointerException if {@code os} is {@code null},
+     *         or if {@code encoding} is {@code null}.
+     * @throws ClassCastException  if this {@code Properties} object
+     *         contains any keys or values that are not
+     *         {@code Strings}.
+     * @see    #loadFromXML(InputStream)
+     * @see    <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+     *         Encoding in Entities</a>
+     * @since 1.5
+     */
+    public void storeToXML(OutputStream os, String comment, String encoding)
+        throws IOException
+    {
+        // Android-changed: Keep OpenJDK7u40's XmlUtils.
+        // XmlSupport's system property based XmlPropertiesProvider
+        // selection does not make sense on Android and has too many
+        // dependencies on classes that are not available on Android.
+        //
+        // XmlSupport.save(this, Objects.requireNonNull(os), comment,
+        //                Objects.requireNonNull(encoding));
+        XMLUtils.save(this, Objects.requireNonNull(os), comment,
+                       Objects.requireNonNull(encoding));
+    }
+
+    /**
+     * Searches for the property with the specified key in this property list.
+     * If the key is not found in this property list, the default property list,
+     * and its defaults, recursively, are then checked. The method returns
+     * {@code null} if the property is not found.
+     *
+     * @param   key   the property key.
+     * @return  the value in this property list with the specified key value.
+     * @see     #setProperty
+     * @see     #defaults
+     */
+    public String getProperty(String key) {
+        Object oval = super.get(key);
+        String sval = (oval instanceof String) ? (String)oval : null;
+        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
+    }
+
+    /**
+     * Searches for the property with the specified key in this property list.
+     * If the key is not found in this property list, the default property list,
+     * and its defaults, recursively, are then checked. The method returns the
+     * default value argument if the property is not found.
+     *
+     * @param   key            the hashtable key.
+     * @param   defaultValue   a default value.
+     *
+     * @return  the value in this property list with the specified key value.
+     * @see     #setProperty
+     * @see     #defaults
+     */
+    public String getProperty(String key, String defaultValue) {
+        String val = getProperty(key);
+        return (val == null) ? defaultValue : val;
+    }
+
+    /**
+     * Returns an enumeration of all the keys in this property list,
+     * including distinct keys in the default property list if a key
+     * of the same name has not already been found from the main
+     * properties list.
+     *
+     * @return  an enumeration of all the keys in this property list, including
+     *          the keys in the default property list.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     * @see     java.util.Enumeration
+     * @see     java.util.Properties#defaults
+     * @see     #stringPropertyNames
+     */
+    public Enumeration<?> propertyNames() {
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        return h.keys();
+    }
+
+    /**
+     * Returns a set of keys in this property list where
+     * the key and its corresponding value are strings,
+     * including distinct keys in the default property list if a key
+     * of the same name has not already been found from the main
+     * properties list.  Properties whose key or value is not
+     * of type <tt>String</tt> are omitted.
+     * <p>
+     * The returned set is not backed by the <tt>Properties</tt> object.
+     * Changes to this <tt>Properties</tt> are not reflected in the set,
+     * or vice versa.
+     *
+     * @return  a set of keys in this property list where
+     *          the key and its corresponding value are strings,
+     *          including the keys in the default property list.
+     * @see     java.util.Properties#defaults
+     * @since   1.6
+     */
+    public Set<String> stringPropertyNames() {
+        Hashtable<String, String> h = new Hashtable<>();
+        enumerateStringProperties(h);
+        return h.keySet();
+    }
+
+    /**
+     * Prints this property list out to the specified output stream.
+     * This method is useful for debugging.
+     *
+     * @param   out   an output stream.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     */
+    public void list(PrintStream out) {
+        out.println("-- listing properties --");
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
+            String key = e.nextElement();
+            String val = (String)h.get(key);
+            if (val.length() > 40) {
+                val = val.substring(0, 37) + "...";
+            }
+            out.println(key + "=" + val);
+        }
+    }
+
+    /**
+     * Prints this property list out to the specified output stream.
+     * This method is useful for debugging.
+     *
+     * @param   out   an output stream.
+     * @throws  ClassCastException if any key in this property list
+     *          is not a string.
+     * @since   JDK1.1
+     */
+    /*
+     * Rather than use an anonymous inner class to share common code, this
+     * method is duplicated in order to ensure that a non-1.1 compiler can
+     * compile this file.
+     */
+    public void list(PrintWriter out) {
+        out.println("-- listing properties --");
+        Hashtable<String,Object> h = new Hashtable<>();
+        enumerate(h);
+        for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
+            String key = e.nextElement();
+            String val = (String)h.get(key);
+            if (val.length() > 40) {
+                val = val.substring(0, 37) + "...";
+            }
+            out.println(key + "=" + val);
+        }
+    }
+
+    /**
+     * Enumerates all key/value pairs in the specified hashtable.
+     * @param h the hashtable
+     * @throws ClassCastException if any of the property keys
+     *         is not of String type.
+     */
+    private synchronized void enumerate(Hashtable<String,Object> h) {
+        if (defaults != null) {
+            defaults.enumerate(h);
+        }
+        for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
+            String key = (String)e.nextElement();
+            h.put(key, get(key));
+        }
+    }
+
+    /**
+     * Enumerates all key/value pairs in the specified hashtable
+     * and omits the property if the key or value is not a string.
+     * @param h the hashtable
+     */
+    private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
+        if (defaults != null) {
+            defaults.enumerateStringProperties(h);
+        }
+        for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
+            Object k = e.nextElement();
+            Object v = get(k);
+            if (k instanceof String && v instanceof String) {
+                h.put((String) k, (String) v);
+            }
+        }
+    }
+
+    /**
+     * Convert a nibble to a hex character
+     * @param   nibble  the nibble to convert.
+     */
+    private static char toHex(int nibble) {
+        return hexDigit[(nibble & 0xF)];
+    }
+
+    /** A table of hex digits */
+    private static final char[] hexDigit = {
+        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
+    };
+
+    // Android-removed: Keep OpenJDK7u40's XmlUtils.
+    // XmlSupport's system property based XmlPropertiesProvider
+    // selection does not make sense on Android and has too many
+    // dependencies on classes that are not available on Android.
+    /*
+    /**
+     * Supporting class for loading/storing properties in XML format.
+     *
+     * <p> The {@code load} and {@code store} methods defined here delegate to a
+     * system-wide {@code XmlPropertiesProvider}. On first invocation of either
+     * method then the system-wide provider is located as follows: </p>
+     *
+     * <ol>
+     *   <li> If the system property {@code sun.util.spi.XmlPropertiesProvider}
+     *   is defined then it is taken to be the full-qualified name of a concrete
+     *   provider class. The class is loaded with the system class loader as the
+     *   initiating loader. If it cannot be loaded or instantiated using a zero
+     *   argument constructor then an unspecified error is thrown. </li>
+     *
+     *   <li> If the system property is not defined then the service-provider
+     *   loading facility defined by the {@link ServiceLoader} class is used to
+     *   locate a provider with the system class loader as the initiating
+     *   loader and {@code sun.util.spi.XmlPropertiesProvider} as the service
+     *   type. If this process fails then an unspecified error is thrown. If
+     *   there is more than one service provider installed then it is
+     *   not specified as to which provider will be used. </li>
+     *
+     *   <li> If the provider is not found by the above means then a system
+     *   default provider will be instantiated and used. </li>
+     * </ol>
+     *
+    private static class XmlSupport {
+
+        private static XmlPropertiesProvider loadProviderFromProperty(ClassLoader cl) {
+            String cn = System.getProperty("sun.util.spi.XmlPropertiesProvider");
+            if (cn == null)
+                return null;
+            try {
+                Class<?> c = Class.forName(cn, true, cl);
+                return (XmlPropertiesProvider)c.newInstance();
+            } catch (ClassNotFoundException |
+                     IllegalAccessException |
+                     InstantiationException x) {
+                throw new ServiceConfigurationError(null, x);
+            }
+        }
+
+        private static XmlPropertiesProvider loadProviderAsService(ClassLoader cl) {
+            Iterator<XmlPropertiesProvider> iterator =
+                 ServiceLoader.load(XmlPropertiesProvider.class, cl).iterator();
+            return iterator.hasNext() ? iterator.next() : null;
+        }
+
+        private static XmlPropertiesProvider loadProvider() {
+            return AccessController.doPrivileged(
+                new PrivilegedAction<XmlPropertiesProvider>() {
+                    public XmlPropertiesProvider run() {
+                        ClassLoader cl = ClassLoader.getSystemClassLoader();
+                        XmlPropertiesProvider provider = loadProviderFromProperty(cl);
+                        if (provider != null)
+                            return provider;
+                        provider = loadProviderAsService(cl);
+                        if (provider != null)
+                            return provider;
+                        return new jdk.internal.util.xml.BasicXmlPropertiesProvider();
+                }});
+        }
+
+        private static final XmlPropertiesProvider PROVIDER = loadProvider();
+
+        static void load(Properties props, InputStream in)
+            throws IOException, InvalidPropertiesFormatException
+        {
+            PROVIDER.load(props, in);
+        }
+
+        static void save(Properties props, OutputStream os, String comment,
+                         String encoding)
+            throws IOException
+        {
+            PROVIDER.store(props, os, comment, encoding);
+        }
+    }
+    */
+}
diff --git a/java/util/PropertyPermission.java b/java/util/PropertyPermission.java
new file mode 100644
index 0000000..ac7b521
--- /dev/null
+++ b/java/util/PropertyPermission.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.security.*;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+public final class PropertyPermission extends BasicPermission {
+
+    public PropertyPermission(String name, String actions) { super("", ""); }
+}
diff --git a/java/util/PropertyResourceBundle.java b/java/util/PropertyResourceBundle.java
new file mode 100644
index 0000000..23c3ffe
--- /dev/null
+++ b/java/util/PropertyResourceBundle.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ */
+
+package java.util;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.IOException;
+import sun.util.ResourceBundleEnumeration;
+
+/**
+ * <code>PropertyResourceBundle</code> is a concrete subclass of
+ * <code>ResourceBundle</code> that manages resources for a locale
+ * using a set of static strings from a property file. See
+ * {@link ResourceBundle ResourceBundle} for more information about resource
+ * bundles.
+ *
+ * <p>
+ * Unlike other types of resource bundle, you don't subclass
+ * <code>PropertyResourceBundle</code>.  Instead, you supply properties
+ * files containing the resource data.  <code>ResourceBundle.getBundle</code>
+ * will automatically look for the appropriate properties file and create a
+ * <code>PropertyResourceBundle</code> that refers to it. See
+ * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
+ * for a complete description of the search and instantiation strategy.
+ *
+ * <p>
+ * The following <a name="sample">example</a> shows a member of a resource
+ * bundle family with the base name "MyResources".
+ * The text defines the bundle "MyResources_de",
+ * the German member of the bundle family.
+ * This member is based on <code>PropertyResourceBundle</code>, and the text
+ * therefore is the content of the file "MyResources_de.properties"
+ * (a related <a href="ListResourceBundle.html#sample">example</a> shows
+ * how you can add bundles to this family that are implemented as subclasses
+ * of <code>ListResourceBundle</code>).
+ * The keys in this example are of the form "s1" etc. The actual
+ * keys are entirely up to your choice, so long as they are the same as
+ * the keys you use in your program to retrieve the objects from the bundle.
+ * Keys are case-sensitive.
+ * <blockquote>
+ * <pre>
+ * # MessageFormat pattern
+ * s1=Die Platte \"{1}\" enth&auml;lt {0}.
+ *
+ * # location of {0} in pattern
+ * s2=1
+ *
+ * # sample disk name
+ * s3=Meine Platte
+ *
+ * # first ChoiceFormat choice
+ * s4=keine Dateien
+ *
+ * # second ChoiceFormat choice
+ * s5=eine Datei
+ *
+ * # third ChoiceFormat choice
+ * s6={0,number} Dateien
+ *
+ * # sample date
+ * s7=3. M&auml;rz 1996
+ * </pre>
+ * </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code PropertyResourceBundle} subclass must be
+ * thread-safe if it's simultaneously used by multiple threads. The default
+ * implementations of the non-abstract methods in this class are thread-safe.
+ *
+ * <p>
+ * <strong>Note:</strong> PropertyResourceBundle can be constructed either
+ * from an InputStream or a Reader, which represents a property file.
+ * Constructing a PropertyResourceBundle instance from an InputStream requires
+ * that the input stream be encoded in ISO-8859-1.  In that case, characters
+ * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
+ * as defined in section 3.3 of
+ * <cite>The Java&trade; Language Specification</cite>
+ * whereas the other constructor which takes a Reader does not have that limitation.
+ *
+ * @see ResourceBundle
+ * @see ListResourceBundle
+ * @see Properties
+ * @since JDK1.1
+ */
+public class PropertyResourceBundle extends ResourceBundle {
+    /**
+     * Creates a property resource bundle from an {@link java.io.InputStream
+     * InputStream}.  The property file read with this constructor
+     * must be encoded in ISO-8859-1.
+     *
+     * @param stream an InputStream that represents a property file
+     *        to read from.
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if <code>stream</code> is null
+     * @throws IllegalArgumentException if {@code stream} contains a
+     *     malformed Unicode escape sequence.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public PropertyResourceBundle (InputStream stream) throws IOException {
+        Properties properties = new Properties();
+        properties.load(stream);
+        lookup = new HashMap(properties);
+    }
+
+    /**
+     * Creates a property resource bundle from a {@link java.io.Reader
+     * Reader}.  Unlike the constructor
+     * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
+     * there is no limitation as to the encoding of the input property file.
+     *
+     * @param reader a Reader that represents a property file to
+     *        read from.
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if <code>reader</code> is null
+     * @throws IllegalArgumentException if a malformed Unicode escape sequence appears
+     *     from {@code reader}.
+     * @since 1.6
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public PropertyResourceBundle (Reader reader) throws IOException {
+        Properties properties = new Properties();
+        properties.load(reader);
+        lookup = new HashMap(properties);
+    }
+
+    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
+    public Object handleGetObject(String key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        return lookup.get(key);
+    }
+
+    /**
+     * Returns an <code>Enumeration</code> of the keys contained in
+     * this <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     * @see #keySet()
+     */
+    public Enumeration<String> getKeys() {
+        ResourceBundle parent = this.parent;
+        return new ResourceBundleEnumeration(lookup.keySet(),
+                (parent != null) ? parent.getKeys() : null);
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained
+     * <em>only</em> in this <code>ResourceBundle</code>.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *         <code>ResourceBundle</code>
+     * @since 1.6
+     * @see #keySet()
+     */
+    protected Set<String> handleKeySet() {
+        return lookup.keySet();
+    }
+
+    // ==================privates====================
+
+    // Android-changed: Fix unsafe publication http://b/31467561
+    // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+    // was: private Map<String,Object> lookup;
+    private final Map<String,Object> lookup;
+}
diff --git a/java/util/Queue.annotated.java b/java/util/Queue.annotated.java
new file mode 100644
index 0000000..33c666a
--- /dev/null
+++ b/java/util/Queue.annotated.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Queue<E> extends java.util.Collection<E> {
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean offer(@libcore.util.NullFromTypeParam E e);
+
[email protected] public E remove();
+
[email protected] public E poll();
+
[email protected] public E element();
+
[email protected] public E peek();
+}
diff --git a/java/util/Queue.java b/java/util/Queue.java
new file mode 100644
index 0000000..cbdc205
--- /dev/null
+++ b/java/util/Queue.java
@@ -0,0 +1,209 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A collection designed for holding elements prior to processing.
+ * Besides basic {@link java.util.Collection Collection} operations,
+ * queues provide additional insertion, extraction, and inspection
+ * operations.  Each of these methods exists in two forms: one throws
+ * an exception if the operation fails, the other returns a special
+ * value (either {@code null} or {@code false}, depending on the
+ * operation).  The latter form of the insert operation is designed
+ * specifically for use with capacity-restricted {@code Queue}
+ * implementations; in most implementations, insert operations cannot
+ * fail.
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of Queue methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Returns special value</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link Queue#add add(e)}</td>
+ *    <td>{@link Queue#offer offer(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link Queue#remove remove()}</td>
+ *    <td>{@link Queue#poll poll()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link Queue#element element()}</td>
+ *    <td>{@link Queue#peek peek()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Queues typically, but do not necessarily, order elements in a
+ * FIFO (first-in-first-out) manner.  Among the exceptions are
+ * priority queues, which order elements according to a supplied
+ * comparator, or the elements' natural ordering, and LIFO queues (or
+ * stacks) which order the elements LIFO (last-in-first-out).
+ * Whatever the ordering used, the <em>head</em> of the queue is that
+ * element which would be removed by a call to {@link #remove() } or
+ * {@link #poll()}.  In a FIFO queue, all new elements are inserted at
+ * the <em>tail</em> of the queue. Other kinds of queues may use
+ * different placement rules.  Every {@code Queue} implementation
+ * must specify its ordering properties.
+ *
+ * <p>The {@link #offer offer} method inserts an element if possible,
+ * otherwise returning {@code false}.  This differs from the {@link
+ * java.util.Collection#add Collection.add} method, which can fail to
+ * add an element only by throwing an unchecked exception.  The
+ * {@code offer} method is designed for use when failure is a normal,
+ * rather than exceptional occurrence, for example, in fixed-capacity
+ * (or &quot;bounded&quot;) queues.
+ *
+ * <p>The {@link #remove()} and {@link #poll()} methods remove and
+ * return the head of the queue.
+ * Exactly which element is removed from the queue is a
+ * function of the queue's ordering policy, which differs from
+ * implementation to implementation. The {@code remove()} and
+ * {@code poll()} methods differ only in their behavior when the
+ * queue is empty: the {@code remove()} method throws an exception,
+ * while the {@code poll()} method returns {@code null}.
+ *
+ * <p>The {@link #element()} and {@link #peek()} methods return, but do
+ * not remove, the head of the queue.
+ *
+ * <p>The {@code Queue} interface does not define the <i>blocking queue
+ * methods</i>, which are common in concurrent programming.  These methods,
+ * which wait for elements to appear or for space to become available, are
+ * defined in the {@link java.util.concurrent.BlockingQueue} interface, which
+ * extends this interface.
+ *
+ * <p>{@code Queue} implementations generally do not allow insertion
+ * of {@code null} elements, although some implementations, such as
+ * {@link LinkedList}, do not prohibit insertion of {@code null}.
+ * Even in the implementations that permit it, {@code null} should
+ * not be inserted into a {@code Queue}, as {@code null} is also
+ * used as a special return value by the {@code poll} method to
+ * indicate that the queue contains no elements.
+ *
+ * <p>{@code Queue} implementations generally do not define
+ * element-based versions of methods {@code equals} and
+ * {@code hashCode} but instead inherit the identity based versions
+ * from class {@code Object}, because element-based equality is not
+ * always well-defined for queues with the same elements but different
+ * ordering properties.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface Queue<E> extends Collection<E> {
+    /**
+     * Inserts the specified element into this queue if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an {@code IllegalStateException}
+     * if no space is currently available.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions.
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to {@link #add}, which can fail to insert an element only
+     * by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null and
+     *         this queue does not permit null elements
+     * @throws IllegalArgumentException if some property of this element
+     *         prevents it from being added to this queue
+     */
+    boolean offer(E e);
+
+    /**
+     * Retrieves and removes the head of this queue.  This method differs
+     * from {@link #poll poll} only in that it throws an exception if this
+     * queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of this queue,
+     * or returns {@code null} if this queue is empty.
+     *
+     * @return the head of this queue, or {@code null} if this queue is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue.  This method
+     * differs from {@link #peek peek} only in that it throws an exception
+     * if this queue is empty.
+     *
+     * @return the head of this queue
+     * @throws NoSuchElementException if this queue is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of this queue,
+     * or returns {@code null} if this queue is empty.
+     *
+     * @return the head of this queue, or {@code null} if this queue is empty
+     */
+    E peek();
+}
diff --git a/java/util/Random.java b/java/util/Random.java
new file mode 100644
index 0000000..1061b59
--- /dev/null
+++ b/java/util/Random.java
@@ -0,0 +1,1227 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import java.io.*;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
+import sun.misc.Unsafe;
+
+/**
+ * An instance of this class is used to generate a stream of
+ * pseudorandom numbers. The class uses a 48-bit seed, which is
+ * modified using a linear congruential formula. (See Donald Knuth,
+ * <i>The Art of Computer Programming, Volume 2</i>, Section 3.2.1.)
+ * <p>
+ * If two instances of {@code Random} are created with the same
+ * seed, and the same sequence of method calls is made for each, they
+ * will generate and return identical sequences of numbers. In order to
+ * guarantee this property, particular algorithms are specified for the
+ * class {@code Random}. Java implementations must use all the algorithms
+ * shown here for the class {@code Random}, for the sake of absolute
+ * portability of Java code. However, subclasses of class {@code Random}
+ * are permitted to use other algorithms, so long as they adhere to the
+ * general contracts for all the methods.
+ * <p>
+ * The algorithms implemented by class {@code Random} use a
+ * {@code protected} utility method that on each invocation can supply
+ * up to 32 pseudorandomly generated bits.
+ * <p>
+ * Many applications will find the method {@link Math#random} simpler to use.
+ *
+ * <p>Instances of {@code java.util.Random} are threadsafe.
+ * However, the concurrent use of the same {@code java.util.Random}
+ * instance across threads may encounter contention and consequent
+ * poor performance. Consider instead using
+ * {@link java.util.concurrent.ThreadLocalRandom} in multithreaded
+ * designs.
+ *
+ * <p>Instances of {@code java.util.Random} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom} to
+ * get a cryptographically secure pseudo-random number generator for use
+ * by security-sensitive applications.
+ *
+ * @author  Frank Yellin
+ * @since   1.0
+ */
+public
+class Random implements java.io.Serializable {
+    /** use serialVersionUID from JDK 1.1 for interoperability */
+    static final long serialVersionUID = 3905348978240129619L;
+
+    /**
+     * The internal state associated with this pseudorandom number generator.
+     * (The specs for the methods in this class describe the ongoing
+     * computation of this value.)
+     */
+    private final AtomicLong seed;
+
+    private static final long multiplier = 0x5DEECE66DL;
+    private static final long addend = 0xBL;
+    private static final long mask = (1L << 48) - 1;
+
+    private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+
+    // IllegalArgumentException messages
+    static final String BadBound = "bound must be positive";
+    static final String BadRange = "bound must be greater than origin";
+    static final String BadSize  = "size must be non-negative";
+
+    /**
+     * Creates a new random number generator. This constructor sets
+     * the seed of the random number generator to a value very likely
+     * to be distinct from any other invocation of this constructor.
+     */
+    public Random() {
+        this(seedUniquifier() ^ System.nanoTime());
+    }
+
+    private static long seedUniquifier() {
+        // L'Ecuyer, "Tables of Linear Congruential Generators of
+        // Different Sizes and Good Lattice Structure", 1999
+        for (;;) {
+            long current = seedUniquifier.get();
+            long next = current * 181783497276652981L;
+            if (seedUniquifier.compareAndSet(current, next))
+                return next;
+        }
+    }
+
+    private static final AtomicLong seedUniquifier
+        = new AtomicLong(8682522807148012L);
+
+    /**
+     * Creates a new random number generator using a single {@code long} seed.
+     * The seed is the initial value of the internal state of the pseudorandom
+     * number generator which is maintained by method {@link #next}.
+     *
+     * <p>The invocation {@code new Random(seed)} is equivalent to:
+     *  <pre> {@code
+     * Random rnd = new Random();
+     * rnd.setSeed(seed);}</pre>
+     *
+     * @param seed the initial seed
+     * @see   #setSeed(long)
+     */
+    public Random(long seed) {
+        if (getClass() == Random.class)
+            this.seed = new AtomicLong(initialScramble(seed));
+        else {
+            // subclass might have overriden setSeed
+            this.seed = new AtomicLong();
+            setSeed(seed);
+        }
+    }
+
+    private static long initialScramble(long seed) {
+        return (seed ^ multiplier) & mask;
+    }
+
+    /**
+     * Sets the seed of this random number generator using a single
+     * {@code long} seed. The general contract of {@code setSeed} is
+     * that it alters the state of this random number generator object
+     * so as to be in exactly the same state as if it had just been
+     * created with the argument {@code seed} as a seed. The method
+     * {@code setSeed} is implemented by class {@code Random} by
+     * atomically updating the seed to
+     *  <pre>{@code (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)}</pre>
+     * and clearing the {@code haveNextNextGaussian} flag used by {@link
+     * #nextGaussian}.
+     *
+     * <p>The implementation of {@code setSeed} by class {@code Random}
+     * happens to use only 48 bits of the given seed. In general, however,
+     * an overriding method may use all 64 bits of the {@code long}
+     * argument as a seed value.
+     *
+     * @param seed the initial seed
+     */
+    synchronized public void setSeed(long seed) {
+        this.seed.set(initialScramble(seed));
+        haveNextNextGaussian = false;
+    }
+
+    /**
+     * Generates the next pseudorandom number. Subclasses should
+     * override this, as this is used by all other methods.
+     *
+     * <p>The general contract of {@code next} is that it returns an
+     * {@code int} value and if the argument {@code bits} is between
+     * {@code 1} and {@code 32} (inclusive), then that many low-order
+     * bits of the returned value will be (approximately) independently
+     * chosen bit values, each of which is (approximately) equally
+     * likely to be {@code 0} or {@code 1}. The method {@code next} is
+     * implemented by class {@code Random} by atomically updating the seed to
+     *  <pre>{@code (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1)}</pre>
+     * and returning
+     *  <pre>{@code (int)(seed >>> (48 - bits))}.</pre>
+     *
+     * This is a linear congruential pseudorandom number generator, as
+     * defined by D. H. Lehmer and described by Donald E. Knuth in
+     * <i>The Art of Computer Programming,</i> Volume 3:
+     * <i>Seminumerical Algorithms</i>, section 3.2.1.
+     *
+     * @param  bits random bits
+     * @return the next pseudorandom value from this random number
+     *         generator's sequence
+     * @since  1.1
+     */
+    protected int next(int bits) {
+        long oldseed, nextseed;
+        AtomicLong seed = this.seed;
+        do {
+            oldseed = seed.get();
+            nextseed = (oldseed * multiplier + addend) & mask;
+        } while (!seed.compareAndSet(oldseed, nextseed));
+        return (int)(nextseed >>> (48 - bits));
+    }
+
+    /**
+     * Generates random bytes and places them into a user-supplied
+     * byte array.  The number of random bytes produced is equal to
+     * the length of the byte array.
+     *
+     * <p>The method {@code nextBytes} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public void nextBytes(byte[] bytes) {
+     *   for (int i = 0; i < bytes.length; )
+     *     for (int rnd = nextInt(), n = Math.min(bytes.length - i, 4);
+     *          n-- > 0; rnd >>= 8)
+     *       bytes[i++] = (byte)rnd;
+     * }}</pre>
+     *
+     * @param  bytes the byte array to fill with random bytes
+     * @throws NullPointerException if the byte array is null
+     * @since  1.1
+     */
+    public void nextBytes(byte[] bytes) {
+        for (int i = 0, len = bytes.length; i < len; )
+            for (int rnd = nextInt(),
+                     n = Math.min(len - i, Integer.SIZE/Byte.SIZE);
+                 n-- > 0; rnd >>= Byte.SIZE)
+                bytes[i++] = (byte)rnd;
+    }
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        long r = nextLong();
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = nextLong() >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = nextLong();
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * For the unbounded case: uses nextInt().
+     * For the bounded case with representable range: uses nextInt(int bound)
+     * For the bounded case with unrepresentable range: uses nextInt()
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final int internalNextInt(int origin, int bound) {
+        if (origin < bound) {
+            int n = bound - origin;
+            if (n > 0) {
+                return nextInt(n) + origin;
+            }
+            else {  // range not representable as int
+                int r;
+                do {
+                    r = nextInt();
+                } while (r < origin || r >= bound);
+                return r;
+            }
+        }
+        else {
+            return nextInt();
+        }
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = nextDouble();
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code int}
+     * value from this random number generator's sequence. The general
+     * contract of {@code nextInt} is that one {@code int} value is
+     * pseudorandomly generated and returned. All 2<sup>32</sup> possible
+     * {@code int} values are produced with (approximately) equal probability.
+     *
+     * <p>The method {@code nextInt} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public int nextInt() {
+     *   return next(32);
+     * }}</pre>
+     *
+     * @return the next pseudorandom, uniformly distributed {@code int}
+     *         value from this random number generator's sequence
+     */
+    public int nextInt() {
+        return next(32);
+    }
+
+    /**
+     * Returns a pseudorandom, uniformly distributed {@code int} value
+     * between 0 (inclusive) and the specified value (exclusive), drawn from
+     * this random number generator's sequence.  The general contract of
+     * {@code nextInt} is that one {@code int} value in the specified range
+     * is pseudorandomly generated and returned.  All {@code bound} possible
+     * {@code int} values are produced with (approximately) equal
+     * probability.  The method {@code nextInt(int bound)} is implemented by
+     * class {@code Random} as if by:
+     *  <pre> {@code
+     * public int nextInt(int bound) {
+     *   if (bound <= 0)
+     *     throw new IllegalArgumentException("bound must be positive");
+     *
+     *   if ((bound & -bound) == bound)  // i.e., bound is a power of 2
+     *     return (int)((bound * (long)next(31)) >> 31);
+     *
+     *   int bits, val;
+     *   do {
+     *       bits = next(31);
+     *       val = bits % bound;
+     *   } while (bits - val + (bound-1) < 0);
+     *   return val;
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the next method is only approximately an unbiased source of
+     * independently chosen bits.  If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code int}
+     * values from the stated range with perfect uniformity.
+     * <p>
+     * The algorithm is slightly tricky.  It rejects values that would result
+     * in an uneven distribution (due to the fact that 2^31 is not divisible
+     * by n). The probability of a value being rejected depends on n.  The
+     * worst case is n=2^30+1, for which the probability of a reject is 1/2,
+     * and the expected number of iterations before the loop terminates is 2.
+     * <p>
+     * The algorithm treats the case where n is a power of two specially: it
+     * returns the correct number of high-order bits from the underlying
+     * pseudo-random number generator.  In the absence of special treatment,
+     * the correct number of <i>low-order</i> bits would be returned.  Linear
+     * congruential pseudo-random number generators such as the one
+     * implemented by this class are known to have short periods in the
+     * sequence of values of their low-order bits.  Thus, this special case
+     * greatly increases the length of the sequence of values returned by
+     * successive calls to this method if n is a small power of two.
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return the next pseudorandom, uniformly distributed {@code int}
+     *         value between zero (inclusive) and {@code bound} (exclusive)
+     *         from this random number generator's sequence
+     * @throws IllegalArgumentException if bound is not positive
+     * @since 1.2
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
+
+        int r = next(31);
+        int m = bound - 1;
+        if ((bound & m) == 0)  // i.e., bound is a power of 2
+            r = (int)((bound * (long)r) >> 31);
+        else {
+            for (int u = r;
+                 u - (r = u % bound) + m < 0;
+                 u = next(31))
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code long}
+     * value from this random number generator's sequence. The general
+     * contract of {@code nextLong} is that one {@code long} value is
+     * pseudorandomly generated and returned.
+     *
+     * <p>The method {@code nextLong} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public long nextLong() {
+     *   return ((long)next(32) << 32) + next(32);
+     * }}</pre>
+     *
+     * Because class {@code Random} uses a seed with only 48 bits,
+     * this algorithm will not return all possible {@code long} values.
+     *
+     * @return the next pseudorandom, uniformly distributed {@code long}
+     *         value from this random number generator's sequence
+     */
+    public long nextLong() {
+        // it's okay that the bottom word remains signed.
+        return ((long)(next(32)) << 32) + next(32);
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed
+     * {@code boolean} value from this random number generator's
+     * sequence. The general contract of {@code nextBoolean} is that one
+     * {@code boolean} value is pseudorandomly generated and returned.  The
+     * values {@code true} and {@code false} are produced with
+     * (approximately) equal probability.
+     *
+     * <p>The method {@code nextBoolean} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public boolean nextBoolean() {
+     *   return next(1) != 0;
+     * }}</pre>
+     *
+     * @return the next pseudorandom, uniformly distributed
+     *         {@code boolean} value from this random number generator's
+     *         sequence
+     * @since 1.2
+     */
+    public boolean nextBoolean() {
+        return next(1) != 0;
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed {@code float}
+     * value between {@code 0.0} and {@code 1.0} from this random
+     * number generator's sequence.
+     *
+     * <p>The general contract of {@code nextFloat} is that one
+     * {@code float} value, chosen (approximately) uniformly from the
+     * range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), is
+     * pseudorandomly generated and returned. All 2<sup>24</sup> possible
+     * {@code float} values of the form <i>m&nbsp;x&nbsp;</i>2<sup>-24</sup>,
+     * where <i>m</i> is a positive integer less than 2<sup>24</sup>, are
+     * produced with (approximately) equal probability.
+     *
+     * <p>The method {@code nextFloat} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public float nextFloat() {
+     *   return next(24) / ((float)(1 << 24));
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the next method is only approximately an unbiased source of
+     * independently chosen bits. If it were a perfect source of randomly
+     * chosen bits, then the algorithm shown would choose {@code float}
+     * values from the stated range with perfect uniformity.<p>
+     * [In early versions of Java, the result was incorrectly calculated as:
+     *  <pre> {@code
+     *   return next(30) / ((float)(1 << 30));}</pre>
+     * This might seem to be equivalent, if not better, but in fact it
+     * introduced a slight nonuniformity because of the bias in the rounding
+     * of floating-point numbers: it was slightly more likely that the
+     * low-order bit of the significand would be 0 than that it would be 1.]
+     *
+     * @return the next pseudorandom, uniformly distributed {@code float}
+     *         value between {@code 0.0} and {@code 1.0} from this
+     *         random number generator's sequence
+     */
+    public float nextFloat() {
+        return next(24) / ((float)(1 << 24));
+    }
+
+    /**
+     * Returns the next pseudorandom, uniformly distributed
+     * {@code double} value between {@code 0.0} and
+     * {@code 1.0} from this random number generator's sequence.
+     *
+     * <p>The general contract of {@code nextDouble} is that one
+     * {@code double} value, chosen (approximately) uniformly from the
+     * range {@code 0.0d} (inclusive) to {@code 1.0d} (exclusive), is
+     * pseudorandomly generated and returned.
+     *
+     * <p>The method {@code nextDouble} is implemented by class {@code Random}
+     * as if by:
+     *  <pre> {@code
+     * public double nextDouble() {
+     *   return (((long)next(26) << 27) + next(27))
+     *     / (double)(1L << 53);
+     * }}</pre>
+     *
+     * <p>The hedge "approximately" is used in the foregoing description only
+     * because the {@code next} method is only approximately an unbiased
+     * source of independently chosen bits. If it were a perfect source of
+     * randomly chosen bits, then the algorithm shown would choose
+     * {@code double} values from the stated range with perfect uniformity.
+     * <p>[In early versions of Java, the result was incorrectly calculated as:
+     *  <pre> {@code
+     *   return (((long)next(27) << 27) + next(27))
+     *     / (double)(1L << 54);}</pre>
+     * This might seem to be equivalent, if not better, but in fact it
+     * introduced a large nonuniformity because of the bias in the rounding
+     * of floating-point numbers: it was three times as likely that the
+     * low-order bit of the significand would be 0 than that it would be 1!
+     * This nonuniformity probably doesn't matter much in practice, but we
+     * strive for perfection.]
+     *
+     * @return the next pseudorandom, uniformly distributed {@code double}
+     *         value between {@code 0.0} and {@code 1.0} from this
+     *         random number generator's sequence
+     * @see Math#random
+     */
+    public double nextDouble() {
+        return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
+    }
+
+    private double nextNextGaussian;
+    private boolean haveNextNextGaussian = false;
+
+    /**
+     * Returns the next pseudorandom, Gaussian ("normally") distributed
+     * {@code double} value with mean {@code 0.0} and standard
+     * deviation {@code 1.0} from this random number generator's sequence.
+     * <p>
+     * The general contract of {@code nextGaussian} is that one
+     * {@code double} value, chosen from (approximately) the usual
+     * normal distribution with mean {@code 0.0} and standard deviation
+     * {@code 1.0}, is pseudorandomly generated and returned.
+     *
+     * <p>The method {@code nextGaussian} is implemented by class
+     * {@code Random} as if by a threadsafe version of the following:
+     *  <pre> {@code
+     * private double nextNextGaussian;
+     * private boolean haveNextNextGaussian = false;
+     *
+     * public double nextGaussian() {
+     *   if (haveNextNextGaussian) {
+     *     haveNextNextGaussian = false;
+     *     return nextNextGaussian;
+     *   } else {
+     *     double v1, v2, s;
+     *     do {
+     *       v1 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+     *       v2 = 2 * nextDouble() - 1;   // between -1.0 and 1.0
+     *       s = v1 * v1 + v2 * v2;
+     *     } while (s >= 1 || s == 0);
+     *     double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+     *     nextNextGaussian = v2 * multiplier;
+     *     haveNextNextGaussian = true;
+     *     return v1 * multiplier;
+     *   }
+     * }}</pre>
+     * This uses the <i>polar method</i> of G. E. P. Box, M. E. Muller, and
+     * G. Marsaglia, as described by Donald E. Knuth in <i>The Art of
+     * Computer Programming</i>, Volume 3: <i>Seminumerical Algorithms</i>,
+     * section 3.4.1, subsection C, algorithm P. Note that it generates two
+     * independent values at the cost of only one call to {@code StrictMath.log}
+     * and one call to {@code StrictMath.sqrt}.
+     *
+     * @return the next pseudorandom, Gaussian ("normally") distributed
+     *         {@code double} value with mean {@code 0.0} and
+     *         standard deviation {@code 1.0} from this random number
+     *         generator's sequence
+     */
+    synchronized public double nextGaussian() {
+        // See Knuth, ACP, Section 3.4.1 Algorithm C.
+        if (haveNextNextGaussian) {
+            haveNextNextGaussian = false;
+            return nextNextGaussian;
+        } else {
+            double v1, v2, s;
+            do {
+                v1 = 2 * nextDouble() - 1; // between -1 and 1
+                v2 = 2 * nextDouble() - 1; // between -1 and 1
+                s = v1 * v1 + v2 * v2;
+            } while (s >= 1 || s == 0);
+            double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+            nextNextGaussian = v2 * multiplier;
+            haveNextNextGaussian = true;
+            return v1 * multiplier;
+        }
+    }
+
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the method {@link #nextInt()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, streamSize, Integer.MAX_VALUE, 0),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values.
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the method {@link #nextInt()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     * @since 1.8
+     */
+    public IntStream ints() {
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values, each conforming to the given
+     * origin (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the following method with the origin and bound:
+     * <pre> {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code int} value is generated as if it's the result of
+     * calling the following method with the origin and bound:
+     * <pre> {@code
+     * int nextInt(int origin, int bound) {
+     *   int n = bound - origin;
+     *   if (n > 0) {
+     *     return nextInt(n) + origin;
+     *   }
+     *   else {  // range not representable as int
+     *     int r;
+     *     do {
+     *       r = nextInt();
+     *     } while (r < origin || r >= bound);
+     *     return r;
+     *   }
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.intStream
+                (new RandomIntsSpliterator
+                         (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values.
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the method {@link #nextLong()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, streamSize, Long.MAX_VALUE, 0L),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code long}
+     * values.
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the method {@link #nextLong()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     * @since 1.8
+     */
+    public LongStream longs() {
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long}, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code long} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * long nextLong(long origin, long bound) {
+     *   long r = nextLong();
+     *   long n = bound - origin, m = n - 1;
+     *   if ((n & m) == 0L)  // power of two
+     *     r = (r & m) + origin;
+     *   else if (n > 0L) {  // reject over-represented candidates
+     *     for (long u = r >>> 1;            // ensure nonnegative
+     *          u + m - (r = u % n) < 0L;    // rejection check
+     *          u = nextLong() >>> 1) // retry
+     *         ;
+     *     r += origin;
+     *   }
+     *   else {              // range not representable as long
+     *     while (r < origin || r >= bound)
+     *       r = nextLong();
+     *   }
+     *   return r;
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.longStream
+                (new RandomLongsSpliterator
+                         (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the method {@link #nextDouble()}.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the method {@link #nextDouble()}.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     * @since 1.8
+     */
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+                 false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}</pre>
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * <p>A pseudorandom {@code double} value is generated as if it's the result
+     * of calling the following method with the origin and bound:
+     * <pre> {@code
+     * double nextDouble(double origin, double bound) {
+     *   double r = nextDouble();
+     *   r = r * (bound - origin) + origin;
+     *   if (r >= bound) // correct for rounding
+     *     r = Math.nextDown(bound);
+     *   return r;
+     * }}</pre>
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    static final class RandomIntsSpliterator implements Spliterator.OfInt {
+        final Random rng;
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(Random rng, long index, long fence,
+                              int origin, int bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomIntsSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                int o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    static final class RandomLongsSpliterator implements Spliterator.OfLong {
+        final Random rng;
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(Random rng, long index, long fence,
+                               long origin, long bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomLongsSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                long o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+        final Random rng;
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(Random rng, long index, long fence,
+                                 double origin, double bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomDoublesSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                double o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Serializable fields for Random.
+     *
+     * @serialField    seed long
+     *              seed for random computations
+     * @serialField    nextNextGaussian double
+     *              next Gaussian to be returned
+     * @serialField      haveNextNextGaussian boolean
+     *              nextNextGaussian is valid
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("seed", Long.TYPE),
+        new ObjectStreamField("nextNextGaussian", Double.TYPE),
+        new ObjectStreamField("haveNextNextGaussian", Boolean.TYPE)
+    };
+
+    /**
+     * Reconstitute the {@code Random} instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        ObjectInputStream.GetField fields = s.readFields();
+
+        // The seed is read in as {@code long} for
+        // historical reasons, but it is converted to an AtomicLong.
+        long seedVal = fields.get("seed", -1L);
+        if (seedVal < 0)
+          throw new java.io.StreamCorruptedException(
+                              "Random: invalid seed");
+        resetSeed(seedVal);
+        nextNextGaussian = fields.get("nextNextGaussian", 0.0);
+        haveNextNextGaussian = fields.get("haveNextNextGaussian", false);
+    }
+
+    /**
+     * Save the {@code Random} instance to a stream.
+     */
+    synchronized private void writeObject(ObjectOutputStream s)
+        throws IOException {
+
+        // set the values of the Serializable fields
+        ObjectOutputStream.PutField fields = s.putFields();
+
+        // The seed is serialized as a long for historical reasons.
+        fields.put("seed", seed.get());
+        fields.put("nextNextGaussian", nextNextGaussian);
+        fields.put("haveNextNextGaussian", haveNextNextGaussian);
+
+        // save them
+        s.writeFields();
+    }
+
+    // Support for resetting seed while deserializing
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final long seedOffset;
+    static {
+        try {
+            seedOffset = unsafe.objectFieldOffset
+                (Random.class.getDeclaredField("seed"));
+        } catch (Exception ex) { throw new Error(ex); }
+    }
+    private void resetSeed(long seedVal) {
+        unsafe.putObjectVolatile(this, seedOffset, new AtomicLong(seedVal));
+    }
+}
diff --git a/java/util/RandomAccess.java b/java/util/RandomAccess.java
new file mode 100644
index 0000000..09ce29e
--- /dev/null
+++ b/java/util/RandomAccess.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Marker interface used by <tt>List</tt> implementations to indicate that
+ * they support fast (generally constant time) random access.  The primary
+ * purpose of this interface is to allow generic algorithms to alter their
+ * behavior to provide good performance when applied to either random or
+ * sequential access lists.
+ *
+ * <p>The best algorithms for manipulating random access lists (such as
+ * <tt>ArrayList</tt>) can produce quadratic behavior when applied to
+ * sequential access lists (such as <tt>LinkedList</tt>).  Generic list
+ * algorithms are encouraged to check whether the given list is an
+ * <tt>instanceof</tt> this interface before applying an algorithm that would
+ * provide poor performance if it were applied to a sequential access list,
+ * and to alter their behavior if necessary to guarantee acceptable
+ * performance.
+ *
+ * <p>It is recognized that the distinction between random and sequential
+ * access is often fuzzy.  For example, some <tt>List</tt> implementations
+ * provide asymptotically linear access times if they get huge, but constant
+ * access times in practice.  Such a <tt>List</tt> implementation
+ * should generally implement this interface.  As a rule of thumb, a
+ * <tt>List</tt> implementation should implement this interface if,
+ * for typical instances of the class, this loop:
+ * <pre>
+ *     for (int i=0, n=list.size(); i &lt; n; i++)
+ *         list.get(i);
+ * </pre>
+ * runs faster than this loop:
+ * <pre>
+ *     for (Iterator i=list.iterator(); i.hasNext(); )
+ *         i.next();
+ * </pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.4
+ */
+public interface RandomAccess {
+}
diff --git a/java/util/RegularEnumSet.java b/java/util/RegularEnumSet.java
new file mode 100644
index 0000000..31a63f1
--- /dev/null
+++ b/java/util/RegularEnumSet.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Private implementation class for EnumSet, for "regular sized" enum types
+ * (i.e., those with 64 or fewer enum constants).
+ *
+ * @author Josh Bloch
+ * @since 1.5
+ * @serial exclude
+ */
+class RegularEnumSet<E extends Enum<E>> extends EnumSet<E> {
+    private static final long serialVersionUID = 3411599620347842686L;
+    /**
+     * Bit vector representation of this set.  The 2^k bit indicates the
+     * presence of universe[k] in this set.
+     */
+    private long elements = 0L;
+
+    RegularEnumSet(Class<E>elementType, Enum<?>[] universe) {
+        super(elementType, universe);
+    }
+
+    void addRange(E from, E to) {
+        elements = (-1L >>>  (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
+    }
+
+    void addAll() {
+        if (universe.length != 0)
+            elements = -1L >>> -universe.length;
+    }
+
+    void complement() {
+        if (universe.length != 0) {
+            elements = ~elements;
+            elements &= -1L >>> -universe.length;  // Mask unused bits
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set.  The
+     * iterator traverses the elements in their <i>natural order</i> (which is
+     * the order in which the enum constants are declared). The returned
+     * Iterator is a "snapshot" iterator that will never throw {@link
+     * ConcurrentModificationException}; the elements are traversed as they
+     * existed when this call was invoked.
+     *
+     * @return an iterator over the elements contained in this set
+     */
+    public Iterator<E> iterator() {
+        return new EnumSetIterator<>();
+    }
+
+    private class EnumSetIterator<E extends Enum<E>> implements Iterator<E> {
+        /**
+         * A bit vector representing the elements in the set not yet
+         * returned by this iterator.
+         */
+        long unseen;
+
+        /**
+         * The bit representing the last element returned by this iterator
+         * but not removed, or zero if no such element exists.
+         */
+        long lastReturned = 0;
+
+        EnumSetIterator() {
+            unseen = elements;
+        }
+
+        public boolean hasNext() {
+            return unseen != 0;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (unseen == 0)
+                throw new NoSuchElementException();
+            lastReturned = unseen & -unseen;
+            unseen -= lastReturned;
+            return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
+        }
+
+        public void remove() {
+            if (lastReturned == 0)
+                throw new IllegalStateException();
+            elements &= ~lastReturned;
+            lastReturned = 0;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return Long.bitCount(elements);
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains no elements.
+     *
+     * @return <tt>true</tt> if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return elements == 0;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this set contains the specified element.
+     *
+     * @param e element to be checked for containment in this collection
+     * @return <tt>true</tt> if this set contains the specified element
+     */
+    public boolean contains(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        return (elements & (1L << ((Enum<?>)e).ordinal())) != 0;
+    }
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     *
+     * @param e element to be added to this set
+     * @return <tt>true</tt> if the set changed as a result of the call
+     *
+     * @throws NullPointerException if <tt>e</tt> is null
+     */
+    public boolean add(E e) {
+        typeCheck(e);
+
+        long oldElements = elements;
+        elements |= (1L << ((Enum<?>)e).ordinal());
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     *
+     * @param e element to be removed from this set, if present
+     * @return <tt>true</tt> if the set contained the specified element
+     */
+    public boolean remove(Object e) {
+        if (e == null)
+            return false;
+        Class<?> eClass = e.getClass();
+        if (eClass != elementType && eClass.getSuperclass() != elementType)
+            return false;
+
+        long oldElements = elements;
+        elements &= ~(1L << ((Enum<?>)e).ordinal());
+        return elements != oldElements;
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns <tt>true</tt> if this set contains all of the elements
+     * in the specified collection.
+     *
+     * @param c collection to be checked for containment in this set
+     * @return <tt>true</tt> if this set contains all of the elements
+     *        in the specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean containsAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.containsAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return es.isEmpty();
+
+        return (es.elements & ~elements) == 0;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection whose elements are to be added to this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *     of its elements are null
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.addAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            if (es.isEmpty())
+                return false;
+            else
+                throw new ClassCastException(
+                    es.elementType + " != " + elementType);
+        }
+
+        long oldElements = elements;
+        elements |= es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.
+     *
+     * @param c elements to be removed from this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.removeAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType)
+            return false;
+
+        long oldElements = elements;
+        elements &= ~es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.
+     *
+     * @param c elements to be retained in this set
+     * @return <tt>true</tt> if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (!(c instanceof RegularEnumSet))
+            return super.retainAll(c);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)c;
+        if (es.elementType != elementType) {
+            boolean changed = (elements != 0);
+            elements = 0;
+            return changed;
+        }
+
+        long oldElements = elements;
+        elements &= es.elements;
+        return elements != oldElements;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        elements = 0;
+    }
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * <tt>true</tt> if the given object is also a set, the two sets have
+     * the same size, and every member of the given set is contained in
+     * this set.
+     *
+     * @param o object to be compared for equality with this set
+     * @return <tt>true</tt> if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        if (!(o instanceof RegularEnumSet))
+            return super.equals(o);
+
+        RegularEnumSet<?> es = (RegularEnumSet<?>)o;
+        if (es.elementType != elementType)
+            return elements == 0 && es.elements == 0;
+        return es.elements == elements;
+    }
+}
diff --git a/java/util/ResourceBundle.java b/java/util/ResourceBundle.java
new file mode 100644
index 0000000..dd07452
--- /dev/null
+++ b/java/util/ResourceBundle.java
@@ -0,0 +1,3000 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
+ *
+ * The original version of this source code and documentation
+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
+ * subsidiary of IBM. These materials are provided under terms
+ * of a License Agreement between Taligent and Sun. This technology
+ * is protected by multiple US and International patents.
+ *
+ * This notice and attribution to Taligent may not be removed.
+ * Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.net.JarURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.jar.JarEntry;
+
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+import sun.util.locale.BaseLocale;
+import sun.util.locale.LocaleObjectCache;
+
+
+// Android-removed: Support for ResourceBundleControlProvider.
+// Removed references to ResourceBundleControlProvider from the documentation.
+// The service provider interface ResourceBundleControlProvider is not
+// available on Android.
+/**
+ *
+ * Resource bundles contain locale-specific objects.  When your program needs a
+ * locale-specific resource, a <code>String</code> for example, your program can
+ * load it from the resource bundle that is appropriate for the current user's
+ * locale. In this way, you can write program code that is largely independent
+ * of the user's locale isolating most, if not all, of the locale-specific
+ * information in resource bundles.
+ *
+ * <p>
+ * This allows you to write programs that can:
+ * <UL>
+ * <LI> be easily localized, or translated, into different languages
+ * <LI> handle multiple locales at once
+ * <LI> be easily modified later to support even more locales
+ * </UL>
+ *
+ * <P>
+ * Resource bundles belong to families whose members share a common base
+ * name, but whose names also have additional components that identify
+ * their locales. For example, the base name of a family of resource
+ * bundles might be "MyResources". The family should have a default
+ * resource bundle which simply has the same name as its family -
+ * "MyResources" - and will be used as the bundle of last resort if a
+ * specific locale is not supported. The family can then provide as
+ * many locale-specific members as needed, for example a German one
+ * named "MyResources_de".
+ *
+ * <P>
+ * Each resource bundle in a family contains the same items, but the items have
+ * been translated for the locale represented by that resource bundle.
+ * For example, both "MyResources" and "MyResources_de" may have a
+ * <code>String</code> that's used on a button for canceling operations.
+ * In "MyResources" the <code>String</code> may contain "Cancel" and in
+ * "MyResources_de" it may contain "Abbrechen".
+ *
+ * <P>
+ * If there are different resources for different countries, you
+ * can make specializations: for example, "MyResources_de_CH" contains objects for
+ * the German language (de) in Switzerland (CH). If you want to only
+ * modify some of the resources
+ * in the specialization, you can do so.
+ *
+ * <P>
+ * When your program needs a locale-specific object, it loads
+ * the <code>ResourceBundle</code> class using the
+ * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
+ * method:
+ * <blockquote>
+ * <pre>
+ * ResourceBundle myResources =
+ *      ResourceBundle.getBundle("MyResources", currentLocale);
+ * </pre>
+ * </blockquote>
+ *
+ * <P>
+ * Resource bundles contain key/value pairs. The keys uniquely
+ * identify a locale-specific object in the bundle. Here's an
+ * example of a <code>ListResourceBundle</code> that contains
+ * two key/value pairs:
+ * <blockquote>
+ * <pre>
+ * public class MyResources extends ListResourceBundle {
+ *     protected Object[][] getContents() {
+ *         return new Object[][] {
+ *             // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
+ *             {"OkKey", "OK"},
+ *             {"CancelKey", "Cancel"},
+ *             // END OF MATERIAL TO LOCALIZE
+ *        };
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ * Keys are always <code>String</code>s.
+ * In this example, the keys are "OkKey" and "CancelKey".
+ * In the above example, the values
+ * are also <code>String</code>s--"OK" and "Cancel"--but
+ * they don't have to be. The values can be any type of object.
+ *
+ * <P>
+ * You retrieve an object from resource bundle using the appropriate
+ * getter method. Because "OkKey" and "CancelKey"
+ * are both strings, you would use <code>getString</code> to retrieve them:
+ * <blockquote>
+ * <pre>
+ * button1 = new Button(myResources.getString("OkKey"));
+ * button2 = new Button(myResources.getString("CancelKey"));
+ * </pre>
+ * </blockquote>
+ * The getter methods all require the key as an argument and return
+ * the object if found. If the object is not found, the getter method
+ * throws a <code>MissingResourceException</code>.
+ *
+ * <P>
+ * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
+ * a method for getting string arrays, <code>getStringArray</code>,
+ * as well as a generic <code>getObject</code> method for any other
+ * type of object. When using <code>getObject</code>, you'll
+ * have to cast the result to the appropriate type. For example:
+ * <blockquote>
+ * <pre>
+ * int[] myIntegers = (int[]) myResources.getObject("intList");
+ * </pre>
+ * </blockquote>
+ *
+ * <P>
+ * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
+ * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
+ * that provide a fairly simple way to create resources.
+ * As you saw briefly in a previous example, <code>ListResourceBundle</code>
+ * manages its resource as a list of key/value pairs.
+ * <code>PropertyResourceBundle</code> uses a properties file to manage
+ * its resources.
+ *
+ * <p>
+ * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
+ * do not suit your needs, you can write your own <code>ResourceBundle</code>
+ * subclass.  Your subclasses must override two methods: <code>handleGetObject</code>
+ * and <code>getKeys()</code>.
+ *
+ * <p>
+ * The implementation of a {@code ResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the non-abstract methods in this class, and the methods in the direct
+ * known concrete subclasses {@code ListResourceBundle} and
+ * {@code PropertyResourceBundle} are thread-safe.
+ *
+ * <h3>ResourceBundle.Control</h3>
+ *
+ * The {@link ResourceBundle.Control} class provides information necessary
+ * to perform the bundle loading process by the <code>getBundle</code>
+ * factory methods that take a <code>ResourceBundle.Control</code>
+ * instance. You can implement your own subclass in order to enable
+ * non-standard resource bundle formats, change the search strategy, or
+ * define caching parameters. Refer to the descriptions of the class and the
+ * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
+ * factory method for details.
+ *
+ * <h3>Cache Management</h3>
+ *
+ * Resource bundle instances created by the <code>getBundle</code> factory
+ * methods are cached by default, and the factory methods return the same
+ * resource bundle instance multiple times if it has been
+ * cached. <code>getBundle</code> clients may clear the cache, manage the
+ * lifetime of cached resource bundle instances using time-to-live values,
+ * or specify not to cache resource bundle instances. Refer to the
+ * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
+ * Control) <code>getBundle</code> factory method}, {@link
+ * #clearCache(ClassLoader) clearCache}, {@link
+ * Control#getTimeToLive(String, Locale)
+ * ResourceBundle.Control.getTimeToLive}, and {@link
+ * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
+ * long) ResourceBundle.Control.needsReload} for details.
+ *
+ * <h3>Example</h3>
+ *
+ * The following is a very simple example of a <code>ResourceBundle</code>
+ * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
+ * resources you would probably use a <code>Map</code>).
+ * Notice that you don't need to supply a value if
+ * a "parent-level" <code>ResourceBundle</code> handles the same
+ * key with the same value (as for the okKey below).
+ * <blockquote>
+ * <pre>
+ * // default (English language, United States)
+ * public class MyResources extends ResourceBundle {
+ *     public Object handleGetObject(String key) {
+ *         if (key.equals("okKey")) return "Ok";
+ *         if (key.equals("cancelKey")) return "Cancel";
+ *         return null;
+ *     }
+ *
+ *     public Enumeration&lt;String&gt; getKeys() {
+ *         return Collections.enumeration(keySet());
+ *     }
+ *
+ *     // Overrides handleKeySet() so that the getKeys() implementation
+ *     // can rely on the keySet() value.
+ *     protected Set&lt;String&gt; handleKeySet() {
+ *         return new HashSet&lt;String&gt;(Arrays.asList("okKey", "cancelKey"));
+ *     }
+ * }
+ *
+ * // German language
+ * public class MyResources_de extends MyResources {
+ *     public Object handleGetObject(String key) {
+ *         // don't need okKey, since parent level handles it.
+ *         if (key.equals("cancelKey")) return "Abbrechen";
+ *         return null;
+ *     }
+ *
+ *     protected Set&lt;String&gt; handleKeySet() {
+ *         return new HashSet&lt;String&gt;(Arrays.asList("cancelKey"));
+ *     }
+ * }
+ * </pre>
+ * </blockquote>
+ * You do not have to restrict yourself to using a single family of
+ * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
+ * exception messages, <code>ExceptionResources</code>
+ * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
+ * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
+ * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
+ *
+ * @see ListResourceBundle
+ * @see PropertyResourceBundle
+ * @see MissingResourceException
+ * @since JDK1.1
+ */
+public abstract class ResourceBundle {
+
+    /** initial size of the bundle cache */
+    private static final int INITIAL_CACHE_SIZE = 32;
+
+    /** constant indicating that no resource bundle exists */
+    private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
+            public Enumeration<String> getKeys() { return null; }
+            protected Object handleGetObject(String key) { return null; }
+            public String toString() { return "NONEXISTENT_BUNDLE"; }
+        };
+
+
+    /**
+     * The cache is a map from cache keys (with bundle base name, locale, and
+     * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
+     * BundleReference.
+     *
+     * The cache is a ConcurrentMap, allowing the cache to be searched
+     * concurrently by multiple threads.  This will also allow the cache keys
+     * to be reclaimed along with the ClassLoaders they reference.
+     *
+     * This variable would be better named "cache", but we keep the old
+     * name for compatibility with some workarounds for bug 4212439.
+     */
+    private static final ConcurrentMap<CacheKey, BundleReference> cacheList
+        = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
+
+    /**
+     * Queue for reference objects referring to class loaders or bundles.
+     */
+    private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+
+    /**
+     * Returns the base name of this bundle, if known, or {@code null} if unknown.
+     *
+     * If not null, then this is the value of the {@code baseName} parameter
+     * that was passed to the {@code ResourceBundle.getBundle(...)} method
+     * when the resource bundle was loaded.
+     *
+     * @return The base name of the resource bundle, as provided to and expected
+     * by the {@code ResourceBundle.getBundle(...)} methods.
+     *
+     * @see #getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader)
+     *
+     * @since 1.8
+     */
+    public String getBaseBundleName() {
+        return name;
+    }
+
+    /**
+     * The parent bundle of this bundle.
+     * The parent bundle is searched by {@link #getObject getObject}
+     * when this bundle does not contain a particular resource.
+     */
+    protected ResourceBundle parent = null;
+
+    /**
+     * The locale for this bundle.
+     */
+    private Locale locale = null;
+
+    /**
+     * The base bundle name for this bundle.
+     */
+    private String name;
+
+    /**
+     * The flag indicating this bundle has expired in the cache.
+     */
+    private volatile boolean expired;
+
+    /**
+     * The back link to the cache key. null if this bundle isn't in
+     * the cache (yet) or has expired.
+     */
+    private volatile CacheKey cacheKey;
+
+    /**
+     * A Set of the keys contained only in this ResourceBundle.
+     */
+    private volatile Set<String> keySet;
+
+    // Android-removed: Support for ResourceBundleControlProvider.
+    /*
+    private static final List<ResourceBundleControlProvider> providers;
+
+    static {
+        List<ResourceBundleControlProvider> list = null;
+        ServiceLoader<ResourceBundleControlProvider> serviceLoaders
+                = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class);
+        for (ResourceBundleControlProvider provider : serviceLoaders) {
+            if (list == null) {
+                list = new ArrayList<>();
+            }
+            list.add(provider);
+        }
+        providers = list;
+    }
+    */
+
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public ResourceBundle() {
+    }
+
+    /**
+     * Gets a string for the given key from this resource bundle or one of its parents.
+     * Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
+     * </blockquote>
+     *
+     * @param key the key for the desired string
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @exception ClassCastException if the object found for the given key is not a string
+     * @return the string for the given key
+     */
+    public final String getString(String key) {
+        return (String) getObject(key);
+    }
+
+    /**
+     * Gets a string array for the given key from this resource bundle or one of its parents.
+     * Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
+     * </blockquote>
+     *
+     * @param key the key for the desired string array
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @exception ClassCastException if the object found for the given key is not a string array
+     * @return the string array for the given key
+     */
+    public final String[] getStringArray(String key) {
+        return (String[]) getObject(key);
+    }
+
+    /**
+     * Gets an object for the given key from this resource bundle or one of its parents.
+     * This method first tries to obtain the object from this resource bundle using
+     * {@link #handleGetObject(java.lang.String) handleGetObject}.
+     * If not successful, and the parent resource bundle is not null,
+     * it calls the parent's <code>getObject</code> method.
+     * If still not successful, it throws a MissingResourceException.
+     *
+     * @param key the key for the desired object
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @exception MissingResourceException if no object for the given key can be found
+     * @return the object for the given key
+     */
+    public final Object getObject(String key) {
+        Object obj = handleGetObject(key);
+        if (obj == null) {
+            if (parent != null) {
+                obj = parent.getObject(key);
+            }
+            if (obj == null) {
+                throw new MissingResourceException("Can't find resource for bundle "
+                                                   +this.getClass().getName()
+                                                   +", key "+key,
+                                                   this.getClass().getName(),
+                                                   key);
+            }
+        }
+        return obj;
+    }
+
+    /**
+     * Returns the locale of this resource bundle. This method can be used after a
+     * call to getBundle() to determine whether the resource bundle returned really
+     * corresponds to the requested locale or is a fallback.
+     *
+     * @return the locale of this resource bundle
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+    /*
+     * Automatic determination of the ClassLoader to be used to load
+     * resources on behalf of the client.
+     */
+    private static ClassLoader getLoader(Class<?> caller) {
+        ClassLoader cl = caller == null ? null : caller.getClassLoader();
+        if (cl == null) {
+            // When the caller's loader is the boot class loader, cl is null
+            // here. In that case, ClassLoader.getSystemClassLoader() may
+            // return the same class loader that the application is
+            // using. We therefore use a wrapper ClassLoader to create a
+            // separate scope for bundles loaded on behalf of the Java
+            // runtime so that these bundles cannot be returned from the
+            // cache to the application (5048280).
+            cl = RBClassLoader.INSTANCE;
+        }
+        return cl;
+    }
+
+    /**
+     * A wrapper of ClassLoader.getSystemClassLoader().
+     */
+    private static class RBClassLoader extends ClassLoader {
+        private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
+                    new PrivilegedAction<RBClassLoader>() {
+                        public RBClassLoader run() {
+                            return new RBClassLoader();
+                        }
+                    });
+        private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
+
+        private RBClassLoader() {
+        }
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            if (loader != null) {
+                return loader.loadClass(name);
+            }
+            return Class.forName(name);
+        }
+        public URL getResource(String name) {
+            if (loader != null) {
+                return loader.getResource(name);
+            }
+            return ClassLoader.getSystemResource(name);
+        }
+        public InputStream getResourceAsStream(String name) {
+            if (loader != null) {
+                return loader.getResourceAsStream(name);
+            }
+            return ClassLoader.getSystemResourceAsStream(name);
+        }
+    }
+
+    /**
+     * Sets the parent bundle of this bundle.
+     * The parent bundle is searched by {@link #getObject getObject}
+     * when this bundle does not contain a particular resource.
+     *
+     * @param parent this bundle's parent bundle.
+     */
+    protected void setParent(ResourceBundle parent) {
+        assert parent != NONEXISTENT_BUNDLE;
+        this.parent = parent;
+    }
+
+    /**
+     * Key used for cached resource bundles.  The key checks the base
+     * name, the locale, and the class loader to determine if the
+     * resource is a match to the requested one. The loader may be
+     * null, but the base name and the locale must have a non-null
+     * value.
+     */
+    private static class CacheKey implements Cloneable {
+        // These three are the actual keys for lookup in Map.
+        private String name;
+        private Locale locale;
+        private LoaderReference loaderRef;
+
+        // bundle format which is necessary for calling
+        // Control.needsReload().
+        private String format;
+
+        // These time values are in CacheKey so that NONEXISTENT_BUNDLE
+        // doesn't need to be cloned for caching.
+
+        // The time when the bundle has been loaded
+        private volatile long loadTime;
+
+        // The time when the bundle expires in the cache, or either
+        // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
+        private volatile long expirationTime;
+
+        // Placeholder for an error report by a Throwable
+        private Throwable cause;
+
+        // Hash code value cache to avoid recalculating the hash code
+        // of this instance.
+        private int hashCodeCache;
+
+        CacheKey(String baseName, Locale locale, ClassLoader loader) {
+            this.name = baseName;
+            this.locale = locale;
+            if (loader == null) {
+                this.loaderRef = null;
+            } else {
+                loaderRef = new LoaderReference(loader, referenceQueue, this);
+            }
+            calculateHashCode();
+        }
+
+        String getName() {
+            return name;
+        }
+
+        CacheKey setName(String baseName) {
+            if (!this.name.equals(baseName)) {
+                this.name = baseName;
+                calculateHashCode();
+            }
+            return this;
+        }
+
+        Locale getLocale() {
+            return locale;
+        }
+
+        CacheKey setLocale(Locale locale) {
+            if (!this.locale.equals(locale)) {
+                this.locale = locale;
+                calculateHashCode();
+            }
+            return this;
+        }
+
+        ClassLoader getLoader() {
+            return (loaderRef != null) ? loaderRef.get() : null;
+        }
+
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            try {
+                final CacheKey otherEntry = (CacheKey)other;
+                //quick check to see if they are not equal
+                if (hashCodeCache != otherEntry.hashCodeCache) {
+                    return false;
+                }
+                //are the names the same?
+                if (!name.equals(otherEntry.name)) {
+                    return false;
+                }
+                // are the locales the same?
+                if (!locale.equals(otherEntry.locale)) {
+                    return false;
+                }
+                //are refs (both non-null) or (both null)?
+                if (loaderRef == null) {
+                    return otherEntry.loaderRef == null;
+                }
+                ClassLoader loader = loaderRef.get();
+                return (otherEntry.loaderRef != null)
+                        // with a null reference we can no longer find
+                        // out which class loader was referenced; so
+                        // treat it as unequal
+                        && (loader != null)
+                        && (loader == otherEntry.loaderRef.get());
+            } catch (    NullPointerException | ClassCastException e) {
+            }
+            return false;
+        }
+
+        public int hashCode() {
+            return hashCodeCache;
+        }
+
+        private void calculateHashCode() {
+            hashCodeCache = name.hashCode() << 3;
+            hashCodeCache ^= locale.hashCode();
+            ClassLoader loader = getLoader();
+            if (loader != null) {
+                hashCodeCache ^= loader.hashCode();
+            }
+        }
+
+        public Object clone() {
+            try {
+                CacheKey clone = (CacheKey) super.clone();
+                if (loaderRef != null) {
+                    clone.loaderRef = new LoaderReference(loaderRef.get(),
+                                                          referenceQueue, clone);
+                }
+                // Clear the reference to a Throwable
+                clone.cause = null;
+                return clone;
+            } catch (CloneNotSupportedException e) {
+                //this should never happen
+                throw new InternalError(e);
+            }
+        }
+
+        String getFormat() {
+            return format;
+        }
+
+        void setFormat(String format) {
+            this.format = format;
+        }
+
+        private void setCause(Throwable cause) {
+            if (this.cause == null) {
+                this.cause = cause;
+            } else {
+                // Override the cause if the previous one is
+                // ClassNotFoundException.
+                if (this.cause instanceof ClassNotFoundException) {
+                    this.cause = cause;
+                }
+            }
+        }
+
+        private Throwable getCause() {
+            return cause;
+        }
+
+        public String toString() {
+            String l = locale.toString();
+            if (l.length() == 0) {
+                if (locale.getVariant().length() != 0) {
+                    l = "__" + locale.getVariant();
+                } else {
+                    l = "\"\"";
+                }
+            }
+            return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader()
+                + "(format=" + format + ")]";
+        }
+    }
+
+    /**
+     * The common interface to get a CacheKey in LoaderReference and
+     * BundleReference.
+     */
+    private static interface CacheKeyReference {
+        public CacheKey getCacheKey();
+    }
+
+    /**
+     * References to class loaders are weak references, so that they can be
+     * garbage collected when nobody else is using them. The ResourceBundle
+     * class has no reason to keep class loaders alive.
+     */
+    private static class LoaderReference extends WeakReference<ClassLoader>
+                                         implements CacheKeyReference {
+        private CacheKey cacheKey;
+
+        LoaderReference(ClassLoader referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * References to bundles are soft references so that they can be garbage
+     * collected when they have no hard references.
+     */
+    private static class BundleReference extends SoftReference<ResourceBundle>
+                                         implements CacheKeyReference {
+        private CacheKey cacheKey;
+
+        BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
+            super(referent, q);
+            cacheKey = key;
+        }
+
+        public CacheKey getCacheKey() {
+            return cacheKey;
+        }
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name, the default locale,
+     * and the caller's class loader. Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
+     * </blockquote>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.
+     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
+     * for a complete description of the search and instantiation strategy.
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified class name
+     * @exception java.lang.NullPointerException
+     *     if <code>baseName</code> is <code>null</code>
+     * @exception MissingResourceException
+     *     if no resource bundle for the specified base name can be found
+     * @return a resource bundle for the given base name and the default locale
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName)
+    {
+        return getBundleImpl(baseName, Locale.getDefault(),
+                             getLoader(Reflection.getCallerClass()),
+                             getDefaultControl(baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, the
+     * default locale and the specified control. Calling this method
+     * is equivalent to calling
+     * <pre>
+     * getBundle(baseName, Locale.getDefault(),
+     *           this.getClass().getClassLoader(), control),
+     * </pre>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.  See {@link
+     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
+     * complete description of the resource bundle loading process with a
+     * <code>ResourceBundle.Control</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified class
+     *        name
+     * @param control
+     *        the control which gives information for the resource bundle
+     *        loading process
+     * @return a resource bundle for the given base name and the default
+     *        locale
+     * @exception NullPointerException
+     *        if <code>baseName</code> or <code>control</code> is
+     *        <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @exception IllegalArgumentException
+     *        if the given <code>control</code> doesn't perform properly
+     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *        Note that validation of <code>control</code> is performed as
+     *        needed.
+     * @since 1.6
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName,
+                                                 Control control) {
+        return getBundleImpl(baseName, Locale.getDefault(),
+                             getLoader(Reflection.getCallerClass()),
+                             control);
+    }
+
+    /**
+     * Gets a resource bundle using the specified base name and locale,
+     * and the caller's class loader. Calling this method is equivalent to calling
+     * <blockquote>
+     * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
+     * </blockquote>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.
+     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
+     * for a complete description of the search and instantiation strategy.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified class name
+     * @param locale
+     *        the locale for which a resource bundle is desired
+     * @exception NullPointerException
+     *        if <code>baseName</code> or <code>locale</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @return a resource bundle for the given base name and locale
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName,
+                                                 Locale locale)
+    {
+        return getBundleImpl(baseName, locale,
+                             getLoader(Reflection.getCallerClass()),
+                             getDefaultControl(baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, target
+     * locale and control, and the caller's class loader. Calling this
+     * method is equivalent to calling
+     * <pre>
+     * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
+     *           control),
+     * </pre>
+     * except that <code>getClassLoader()</code> is run with the security
+     * privileges of <code>ResourceBundle</code>.  See {@link
+     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
+     * complete description of the resource bundle loading process with a
+     * <code>ResourceBundle.Control</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified
+     *        class name
+     * @param targetLocale
+     *        the locale for which a resource bundle is desired
+     * @param control
+     *        the control which gives information for the resource
+     *        bundle loading process
+     * @return a resource bundle for the given base name and a
+     *        <code>Locale</code> in <code>locales</code>
+     * @exception NullPointerException
+     *        if <code>baseName</code>, <code>locales</code> or
+     *        <code>control</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name in any
+     *        of the <code>locales</code> can be found.
+     * @exception IllegalArgumentException
+     *        if the given <code>control</code> doesn't perform properly
+     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *        Note that validation of <code>control</code> is performed as
+     *        needed.
+     * @since 1.6
+     */
+    @CallerSensitive
+    public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
+                                                 Control control) {
+        return getBundleImpl(baseName, targetLocale,
+                             getLoader(Reflection.getCallerClass()),
+                             control);
+    }
+
+    // Android-removed: Support for ResourceBundleControlProvider.
+    // Removed documentation referring to that SPI.
+    /**
+     * Gets a resource bundle using the specified base name, locale, and class
+     * loader.
+     *
+     * <p>This method behaves the same as calling
+     * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
+     * default instance of {@link Control}.
+     *
+     * <p><code>getBundle</code> uses the base name, the specified locale, and
+     * the default locale (obtained from {@link java.util.Locale#getDefault()
+     * Locale.getDefault}) to generate a sequence of <a
+     * name="candidates"><em>candidate bundle names</em></a>.  If the specified
+     * locale's language, script, country, and variant are all empty strings,
+     * then the base name is the only candidate bundle name.  Otherwise, a list
+     * of candidate locales is generated from the attribute values of the
+     * specified locale (language, script, country and variant) and appended to
+     * the base name.  Typically, this will look like the following:
+     *
+     * <pre>
+     *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
+     *     baseName + "_" + language + "_" + script + "_" + country
+     *     baseName + "_" + language + "_" + script
+     *     baseName + "_" + language + "_" + country + "_" + variant
+     *     baseName + "_" + language + "_" + country
+     *     baseName + "_" + language
+     * </pre>
+     *
+     * <p>Candidate bundle names where the final component is an empty string
+     * are omitted, along with the underscore.  For example, if country is an
+     * empty string, the second and the fifth candidate bundle names above
+     * would be omitted.  Also, if script is an empty string, the candidate names
+     * including script are omitted.  For example, a locale with language "de"
+     * and variant "JAVA" will produce candidate names with base name
+     * "MyResource" below.
+     *
+     * <pre>
+     *     MyResource_de__JAVA
+     *     MyResource_de
+     * </pre>
+     *
+     * In the case that the variant contains one or more underscores ('_'), a
+     * sequence of bundle names generated by truncating the last underscore and
+     * the part following it is inserted after a candidate bundle name with the
+     * original variant.  For example, for a locale with language "en", script
+     * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
+     * "MyResource", the list of candidate bundle names below is generated:
+     *
+     * <pre>
+     * MyResource_en_Latn_US_WINDOWS_VISTA
+     * MyResource_en_Latn_US_WINDOWS
+     * MyResource_en_Latn_US
+     * MyResource_en_Latn
+     * MyResource_en_US_WINDOWS_VISTA
+     * MyResource_en_US_WINDOWS
+     * MyResource_en_US
+     * MyResource_en
+     * </pre>
+     *
+     * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
+     * candidate bundle names contains extra names, or the order of bundle names
+     * is slightly modified.  See the description of the default implementation
+     * of {@link Control#getCandidateLocales(String, Locale)
+     * getCandidateLocales} for details.</blockquote>
+     *
+     * <p><code>getBundle</code> then iterates over the candidate bundle names
+     * to find the first one for which it can <em>instantiate</em> an actual
+     * resource bundle. It uses the default controls' {@link Control#getFormats
+     * getFormats} method, which generates two bundle names for each generated
+     * name, the first a class name and the second a properties file name. For
+     * each candidate bundle name, it attempts to create a resource bundle:
+     *
+     * <ul><li>First, it attempts to load a class using the generated class name.
+     * If such a class can be found and loaded using the specified class
+     * loader, is assignment compatible with ResourceBundle, is accessible from
+     * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
+     * new instance of this class and uses it as the <em>result resource
+     * bundle</em>.
+     *
+     * <li>Otherwise, <code>getBundle</code> attempts to locate a property
+     * resource file using the generated properties file name.  It generates a
+     * path name from the candidate bundle name by replacing all "." characters
+     * with "/" and appending the string ".properties".  It attempts to find a
+     * "resource" with this name using {@link
+     * java.lang.ClassLoader#getResource(java.lang.String)
+     * ClassLoader.getResource}.  (Note that a "resource" in the sense of
+     * <code>getResource</code> has nothing to do with the contents of a
+     * resource bundle, it is just a container of data, such as a file.)  If it
+     * finds a "resource", it attempts to create a new {@link
+     * PropertyResourceBundle} instance from its contents.  If successful, this
+     * instance becomes the <em>result resource bundle</em>.  </ul>
+     *
+     * <p>This continues until a result resource bundle is instantiated or the
+     * list of candidate bundle names is exhausted.  If no matching resource
+     * bundle is found, the default control's {@link Control#getFallbackLocale
+     * getFallbackLocale} method is called, which returns the current default
+     * locale.  A new sequence of candidate locale names is generated using this
+     * locale and and searched again, as above.
+     *
+     * <p>If still no result bundle is found, the base name alone is looked up. If
+     * this still fails, a <code>MissingResourceException</code> is thrown.
+     *
+     * <p><a name="parent_chain"> Once a result resource bundle has been found,
+     * its <em>parent chain</em> is instantiated</a>.  If the result bundle already
+     * has a parent (perhaps because it was returned from a cache) the chain is
+     * complete.
+     *
+     * <p>Otherwise, <code>getBundle</code> examines the remainder of the
+     * candidate locale list that was used during the pass that generated the
+     * result resource bundle.  (As before, candidate bundle names where the
+     * final component is an empty string are omitted.)  When it comes to the
+     * end of the candidate list, it tries the plain bundle name.  With each of the
+     * candidate bundle names it attempts to instantiate a resource bundle (first
+     * looking for a class and then a properties file, as described above).
+     *
+     * <p>Whenever it succeeds, it calls the previously instantiated resource
+     * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
+     * with the new resource bundle.  This continues until the list of names
+     * is exhausted or the current bundle already has a non-null parent.
+     *
+     * <p>Once the parent chain is complete, the bundle is returned.
+     *
+     * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
+     * bundles and might return the same resource bundle instance multiple times.
+     *
+     * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
+     * qualified class name. However, for compatibility with earlier versions,
+     * Sun's Java SE Runtime Environments do not verify this, and so it is
+     * possible to access <code>PropertyResourceBundle</code>s by specifying a
+     * path name (using "/") instead of a fully qualified class name (using
+     * ".").
+     *
+     * <p><a name="default_behavior_example">
+     * <strong>Example:</strong></a>
+     * <p>
+     * The following class and property files are provided:
+     * <pre>
+     *     MyResources.class
+     *     MyResources.properties
+     *     MyResources_fr.properties
+     *     MyResources_fr_CH.class
+     *     MyResources_fr_CH.properties
+     *     MyResources_en.properties
+     *     MyResources_es_ES.class
+     * </pre>
+     *
+     * The contents of all files are valid (that is, public non-abstract
+     * subclasses of <code>ResourceBundle</code> for the ".class" files,
+     * syntactically correct ".properties" files).  The default locale is
+     * <code>Locale("en", "GB")</code>.
+     *
+     * <p>Calling <code>getBundle</code> with the locale arguments below will
+     * instantiate resource bundles as follows:
+     *
+     * <table summary="getBundle() locale to resource bundle mapping">
+     * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
+     * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
+     * </table>
+     *
+     * <p>The file MyResources_fr_CH.properties is never used because it is
+     * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
+     * is also hidden by MyResources.class.
+     *
+     * @param baseName the base name of the resource bundle, a fully qualified class name
+     * @param locale the locale for which a resource bundle is desired
+     * @param loader the class loader from which to load the resource bundle
+     * @return a resource bundle for the given base name and locale
+     * @exception java.lang.NullPointerException
+     *        if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @since 1.2
+     */
+    public static ResourceBundle getBundle(String baseName, Locale locale,
+                                           ClassLoader loader)
+    {
+        if (loader == null) {
+            throw new NullPointerException();
+        }
+        return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName));
+    }
+
+    /**
+     * Returns a resource bundle using the specified base name, target
+     * locale, class loader and control. Unlike the {@linkplain
+     * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
+     * factory methods with no <code>control</code> argument}, the given
+     * <code>control</code> specifies how to locate and instantiate resource
+     * bundles. Conceptually, the bundle loading process with the given
+     * <code>control</code> is performed in the following steps.
+     *
+     * <ol>
+     * <li>This factory method looks up the resource bundle in the cache for
+     * the specified <code>baseName</code>, <code>targetLocale</code> and
+     * <code>loader</code>.  If the requested resource bundle instance is
+     * found in the cache and the time-to-live periods of the instance and
+     * all of its parent instances have not expired, the instance is returned
+     * to the caller. Otherwise, this factory method proceeds with the
+     * loading process below.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getFormats(String)
+     * control.getFormats} method is called to get resource bundle formats
+     * to produce bundle or resource names. The strings
+     * <code>"java.class"</code> and <code>"java.properties"</code>
+     * designate class-based and {@linkplain PropertyResourceBundle
+     * property}-based resource bundles, respectively. Other strings
+     * starting with <code>"java."</code> are reserved for future extensions
+     * and must not be used for application-defined formats. Other strings
+     * designate application-defined formats.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
+     * Locale) control.getCandidateLocales} method is called with the target
+     * locale to get a list of <em>candidate <code>Locale</code>s</em> for
+     * which resource bundles are searched.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
+     * String, ClassLoader, boolean) control.newBundle} method is called to
+     * instantiate a <code>ResourceBundle</code> for the base bundle name, a
+     * candidate locale, and a format. (Refer to the note on the cache
+     * lookup below.) This step is iterated over all combinations of the
+     * candidate locales and formats until the <code>newBundle</code> method
+     * returns a <code>ResourceBundle</code> instance or the iteration has
+     * used up all the combinations. For example, if the candidate locales
+     * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
+     * <code>Locale("")</code> and the formats are <code>"java.class"</code>
+     * and <code>"java.properties"</code>, then the following is the
+     * sequence of locale-format combinations to be used to call
+     * <code>control.newBundle</code>.
+     *
+     * <table style="width: 50%; text-align: left; margin-left: 40px;"
+     *  border="0" cellpadding="2" cellspacing="2" summary="locale-format combinations for newBundle">
+     * <tbody>
+     * <tr>
+     * <td
+     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>Locale</code><br>
+     * </td>
+     * <td
+     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>format</code><br>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code><br>
+     * </td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code><br>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code><br>
+     * </td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code><br>
+     * </td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
+     * </tr>
+     * <tr>
+     * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code></td>
+     * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
+     * </tr>
+     * </tbody>
+     * </table>
+     * </li>
+     *
+     * <li>If the previous step has found no resource bundle, proceed to
+     * Step 6. If a bundle has been found that is a base bundle (a bundle
+     * for <code>Locale("")</code>), and the candidate locale list only contained
+     * <code>Locale("")</code>, return the bundle to the caller. If a bundle
+     * has been found that is a base bundle, but the candidate locale list
+     * contained locales other than Locale(""), put the bundle on hold and
+     * proceed to Step 6. If a bundle has been found that is not a base
+     * bundle, proceed to Step 7.</li>
+     *
+     * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
+     * Locale) control.getFallbackLocale} method is called to get a fallback
+     * locale (alternative to the current target locale) to try further
+     * finding a resource bundle. If the method returns a non-null locale,
+     * it becomes the next target locale and the loading process starts over
+     * from Step 3. Otherwise, if a base bundle was found and put on hold in
+     * a previous Step 5, it is returned to the caller now. Otherwise, a
+     * MissingResourceException is thrown.</li>
+     *
+     * <li>At this point, we have found a resource bundle that's not the
+     * base bundle. If this bundle set its parent during its instantiation,
+     * it is returned to the caller. Otherwise, its <a
+     * href="./ResourceBundle.html#parent_chain">parent chain</a> is
+     * instantiated based on the list of candidate locales from which it was
+     * found. Finally, the bundle is returned to the caller.</li>
+     * </ol>
+     *
+     * <p>During the resource bundle loading process above, this factory
+     * method looks up the cache before calling the {@link
+     * Control#newBundle(String, Locale, String, ClassLoader, boolean)
+     * control.newBundle} method.  If the time-to-live period of the
+     * resource bundle found in the cache has expired, the factory method
+     * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
+     * String, ClassLoader, ResourceBundle, long) control.needsReload}
+     * method to determine whether the resource bundle needs to be reloaded.
+     * If reloading is required, the factory method calls
+     * <code>control.newBundle</code> to reload the resource bundle.  If
+     * <code>control.newBundle</code> returns <code>null</code>, the factory
+     * method puts a dummy resource bundle in the cache as a mark of
+     * nonexistent resource bundles in order to avoid lookup overhead for
+     * subsequent requests. Such dummy resource bundles are under the same
+     * expiration control as specified by <code>control</code>.
+     *
+     * <p>All resource bundles loaded are cached by default. Refer to
+     * {@link Control#getTimeToLive(String,Locale)
+     * control.getTimeToLive} for details.
+     *
+     * <p>The following is an example of the bundle loading process with the
+     * default <code>ResourceBundle.Control</code> implementation.
+     *
+     * <p>Conditions:
+     * <ul>
+     * <li>Base bundle name: <code>foo.bar.Messages</code>
+     * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
+     * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
+     * <li>Available resource bundles:
+     * <code>foo/bar/Messages_fr.properties</code> and
+     * <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p>First, <code>getBundle</code> tries loading a resource bundle in
+     * the following sequence.
+     *
+     * <ul>
+     * <li>class <code>foo.bar.Messages_it_IT</code>
+     * <li>file <code>foo/bar/Messages_it_IT.properties</code>
+     * <li>class <code>foo.bar.Messages_it</code></li>
+     * <li>file <code>foo/bar/Messages_it.properties</code></li>
+     * <li>class <code>foo.bar.Messages</code></li>
+     * <li>file <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p>At this point, <code>getBundle</code> finds
+     * <code>foo/bar/Messages.properties</code>, which is put on hold
+     * because it's the base bundle.  <code>getBundle</code> calls {@link
+     * Control#getFallbackLocale(String, Locale)
+     * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
+     * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
+     * tries loading a bundle in the following sequence.
+     *
+     * <ul>
+     * <li>class <code>foo.bar.Messages_fr</code></li>
+     * <li>file <code>foo/bar/Messages_fr.properties</code></li>
+     * <li>class <code>foo.bar.Messages</code></li>
+     * <li>file <code>foo/bar/Messages.properties</code></li>
+     * </ul>
+     *
+     * <p><code>getBundle</code> finds
+     * <code>foo/bar/Messages_fr.properties</code> and creates a
+     * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
+     * sets up its parent chain from the list of the candidate locales.  Only
+     * <code>foo/bar/Messages.properties</code> is found in the list and
+     * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
+     * that becomes the parent of the instance for
+     * <code>foo/bar/Messages_fr.properties</code>.
+     *
+     * @param baseName
+     *        the base name of the resource bundle, a fully qualified
+     *        class name
+     * @param targetLocale
+     *        the locale for which a resource bundle is desired
+     * @param loader
+     *        the class loader from which to load the resource bundle
+     * @param control
+     *        the control which gives information for the resource
+     *        bundle loading process
+     * @return a resource bundle for the given base name and locale
+     * @exception NullPointerException
+     *        if <code>baseName</code>, <code>targetLocale</code>,
+     *        <code>loader</code>, or <code>control</code> is
+     *        <code>null</code>
+     * @exception MissingResourceException
+     *        if no resource bundle for the specified base name can be found
+     * @exception IllegalArgumentException
+     *        if the given <code>control</code> doesn't perform properly
+     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
+     *        Note that validation of <code>control</code> is performed as
+     *        needed.
+     * @since 1.6
+     */
+    public static ResourceBundle getBundle(String baseName, Locale targetLocale,
+                                           ClassLoader loader, Control control) {
+        if (loader == null || control == null) {
+            throw new NullPointerException();
+        }
+        return getBundleImpl(baseName, targetLocale, loader, control);
+    }
+
+    private static Control getDefaultControl(String baseName) {
+        // Android-removed: Support for ResourceBundleControlProvider.
+        /*
+        if (providers != null) {
+            for (ResourceBundleControlProvider provider : providers) {
+                Control control = provider.getControl(baseName);
+                if (control != null) {
+                    return control;
+                }
+            }
+        }
+        */
+        return Control.INSTANCE;
+    }
+
+    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
+                                                ClassLoader loader, Control control) {
+        if (locale == null || control == null) {
+            throw new NullPointerException();
+        }
+
+        // We create a CacheKey here for use by this call. The base
+        // name and loader will never change during the bundle loading
+        // process. We have to make sure that the locale is set before
+        // using it as a cache key.
+        CacheKey cacheKey = new CacheKey(baseName, locale, loader);
+        ResourceBundle bundle = null;
+
+        // Quick lookup of the cache.
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef != null) {
+            bundle = bundleRef.get();
+            bundleRef = null;
+        }
+
+        // If this bundle and all of its parents are valid (not expired),
+        // then return this bundle. If any of the bundles is expired, we
+        // don't call control.needsReload here but instead drop into the
+        // complete loading process below.
+        if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
+            return bundle;
+        }
+
+        // No valid bundle was found in the cache, so we need to load the
+        // resource bundle and its parents.
+
+        boolean isKnownControl = (control == Control.INSTANCE) ||
+                                   (control instanceof SingleFormatControl);
+        List<String> formats = control.getFormats(baseName);
+        if (!isKnownControl && !checkList(formats)) {
+            throw new IllegalArgumentException("Invalid Control: getFormats");
+        }
+
+        ResourceBundle baseBundle = null;
+        for (Locale targetLocale = locale;
+             targetLocale != null;
+             targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
+            List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
+            if (!isKnownControl && !checkList(candidateLocales)) {
+                throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
+            }
+
+            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
+
+            // If the loaded bundle is the base bundle and exactly for the
+            // requested locale or the only candidate locale, then take the
+            // bundle as the resulting one. If the loaded bundle is the base
+            // bundle, it's put on hold until we finish processing all
+            // fallback locales.
+            if (isValidBundle(bundle)) {
+                boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
+                if (!isBaseBundle || bundle.locale.equals(locale)
+                    || (candidateLocales.size() == 1
+                        && bundle.locale.equals(candidateLocales.get(0)))) {
+                    break;
+                }
+
+                // If the base bundle has been loaded, keep the reference in
+                // baseBundle so that we can avoid any redundant loading in case
+                // the control specify not to cache bundles.
+                if (isBaseBundle && baseBundle == null) {
+                    baseBundle = bundle;
+                }
+            }
+        }
+
+        if (bundle == null) {
+            if (baseBundle == null) {
+                throwMissingResourceException(baseName, locale, cacheKey.getCause());
+            }
+            bundle = baseBundle;
+        }
+
+        return bundle;
+    }
+
+    /**
+     * Checks if the given <code>List</code> is not null, not empty,
+     * not having null in its elements.
+     */
+    private static boolean checkList(List<?> a) {
+        boolean valid = (a != null && !a.isEmpty());
+        if (valid) {
+            int size = a.size();
+            for (int i = 0; valid && i < size; i++) {
+                valid = (a.get(i) != null);
+            }
+        }
+        return valid;
+    }
+
+    private static ResourceBundle findBundle(CacheKey cacheKey,
+                                             List<Locale> candidateLocales,
+                                             List<String> formats,
+                                             int index,
+                                             Control control,
+                                             ResourceBundle baseBundle) {
+        Locale targetLocale = candidateLocales.get(index);
+        ResourceBundle parent = null;
+        if (index != candidateLocales.size() - 1) {
+            parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
+                                control, baseBundle);
+        } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
+            return baseBundle;
+        }
+
+        // Before we do the real loading work, see whether we need to
+        // do some housekeeping: If references to class loaders or
+        // resource bundles have been nulled out, remove all related
+        // information from the cache.
+        Object ref;
+        while ((ref = referenceQueue.poll()) != null) {
+            cacheList.remove(((CacheKeyReference)ref).getCacheKey());
+        }
+
+        // flag indicating the resource bundle has expired in the cache
+        boolean expiredBundle = false;
+
+        // First, look up the cache to see if it's in the cache, without
+        // attempting to load bundle.
+        cacheKey.setLocale(targetLocale);
+        ResourceBundle bundle = findBundleInCache(cacheKey, control);
+        if (isValidBundle(bundle)) {
+            expiredBundle = bundle.expired;
+            if (!expiredBundle) {
+                // If its parent is the one asked for by the candidate
+                // locales (the runtime lookup path), we can take the cached
+                // one. (If it's not identical, then we'd have to check the
+                // parent's parents to be consistent with what's been
+                // requested.)
+                if (bundle.parent == parent) {
+                    return bundle;
+                }
+                // Otherwise, remove the cached one since we can't keep
+                // the same bundles having different parents.
+                BundleReference bundleRef = cacheList.get(cacheKey);
+                if (bundleRef != null && bundleRef.get() == bundle) {
+                    cacheList.remove(cacheKey, bundleRef);
+                }
+            }
+        }
+
+        if (bundle != NONEXISTENT_BUNDLE) {
+            CacheKey constKey = (CacheKey) cacheKey.clone();
+
+            try {
+                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+                if (bundle != null) {
+                    if (bundle.parent == null) {
+                        bundle.setParent(parent);
+                    }
+                    bundle.locale = targetLocale;
+                    bundle = putBundleInCache(cacheKey, bundle, control);
+                    return bundle;
+                }
+
+                // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
+                // instance for the locale.
+                putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
+            } finally {
+                if (constKey.getCause() instanceof InterruptedException) {
+                    Thread.currentThread().interrupt();
+                }
+            }
+        }
+        return parent;
+    }
+
+    private static ResourceBundle loadBundle(CacheKey cacheKey,
+                                             List<String> formats,
+                                             Control control,
+                                             boolean reload) {
+
+        // Here we actually load the bundle in the order of formats
+        // specified by the getFormats() value.
+        Locale targetLocale = cacheKey.getLocale();
+
+        ResourceBundle bundle = null;
+        int size = formats.size();
+        for (int i = 0; i < size; i++) {
+            String format = formats.get(i);
+            try {
+                bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
+                                           cacheKey.getLoader(), reload);
+            } catch (LinkageError error) {
+                // We need to handle the LinkageError case due to
+                // inconsistent case-sensitivity in ClassLoader.
+                // See 6572242 for details.
+                cacheKey.setCause(error);
+            } catch (Exception cause) {
+                cacheKey.setCause(cause);
+            }
+            if (bundle != null) {
+                // Set the format in the cache key so that it can be
+                // used when calling needsReload later.
+                cacheKey.setFormat(format);
+                bundle.name = cacheKey.getName();
+                bundle.locale = targetLocale;
+                // Bundle provider might reuse instances. So we should make
+                // sure to clear the expired flag here.
+                bundle.expired = false;
+                break;
+            }
+        }
+
+        return bundle;
+    }
+
+    private static boolean isValidBundle(ResourceBundle bundle) {
+        return bundle != null && bundle != NONEXISTENT_BUNDLE;
+    }
+
+    /**
+     * Determines whether any of resource bundles in the parent chain,
+     * including the leaf, have expired.
+     */
+    private static boolean hasValidParentChain(ResourceBundle bundle) {
+        long now = System.currentTimeMillis();
+        while (bundle != null) {
+            if (bundle.expired) {
+                return false;
+            }
+            CacheKey key = bundle.cacheKey;
+            if (key != null) {
+                long expirationTime = key.expirationTime;
+                if (expirationTime >= 0 && expirationTime <= now) {
+                    return false;
+                }
+            }
+            bundle = bundle.parent;
+        }
+        return true;
+    }
+
+    /**
+     * Throw a MissingResourceException with proper message
+     */
+    private static void throwMissingResourceException(String baseName,
+                                                      Locale locale,
+                                                      Throwable cause) {
+        // If the cause is a MissingResourceException, avoid creating
+        // a long chain. (6355009)
+        if (cause instanceof MissingResourceException) {
+            cause = null;
+        }
+        throw new MissingResourceException("Can't find bundle for base name "
+                                           + baseName + ", locale " + locale,
+                                           baseName + "_" + locale, // className
+                                           "",                      // key
+                                           cause);
+    }
+
+    /**
+     * Finds a bundle in the cache. Any expired bundles are marked as
+     * `expired' and removed from the cache upon return.
+     *
+     * @param cacheKey the key to look up the cache
+     * @param control the Control to be used for the expiration control
+     * @return the cached bundle, or null if the bundle is not found in the
+     * cache or its parent has expired. <code>bundle.expire</code> is true
+     * upon return if the bundle in the cache has expired.
+     */
+    private static ResourceBundle findBundleInCache(CacheKey cacheKey,
+                                                    Control control) {
+        BundleReference bundleRef = cacheList.get(cacheKey);
+        if (bundleRef == null) {
+            return null;
+        }
+        ResourceBundle bundle = bundleRef.get();
+        if (bundle == null) {
+            return null;
+        }
+        ResourceBundle p = bundle.parent;
+        assert p != NONEXISTENT_BUNDLE;
+        // If the parent has expired, then this one must also expire. We
+        // check only the immediate parent because the actual loading is
+        // done from the root (base) to leaf (child) and the purpose of
+        // checking is to propagate expiration towards the leaf. For
+        // example, if the requested locale is ja_JP_JP and there are
+        // bundles for all of the candidates in the cache, we have a list,
+        //
+        // base <- ja <- ja_JP <- ja_JP_JP
+        //
+        // If ja has expired, then it will reload ja and the list becomes a
+        // tree.
+        //
+        // base <- ja (new)
+        //  "   <- ja (expired) <- ja_JP <- ja_JP_JP
+        //
+        // When looking up ja_JP in the cache, it finds ja_JP in the cache
+        // which references to the expired ja. Then, ja_JP is marked as
+        // expired and removed from the cache. This will be propagated to
+        // ja_JP_JP.
+        //
+        // Now, it's possible, for example, that while loading new ja_JP,
+        // someone else has started loading the same bundle and finds the
+        // base bundle has expired. Then, what we get from the first
+        // getBundle call includes the expired base bundle. However, if
+        // someone else didn't start its loading, we wouldn't know if the
+        // base bundle has expired at the end of the loading process. The
+        // expiration control doesn't guarantee that the returned bundle and
+        // its parents haven't expired.
+        //
+        // We could check the entire parent chain to see if there's any in
+        // the chain that has expired. But this process may never end. An
+        // extreme case would be that getTimeToLive returns 0 and
+        // needsReload always returns true.
+        if (p != null && p.expired) {
+            assert bundle != NONEXISTENT_BUNDLE;
+            bundle.expired = true;
+            bundle.cacheKey = null;
+            cacheList.remove(cacheKey, bundleRef);
+            bundle = null;
+        } else {
+            CacheKey key = bundleRef.getCacheKey();
+            long expirationTime = key.expirationTime;
+            if (!bundle.expired && expirationTime >= 0 &&
+                expirationTime <= System.currentTimeMillis()) {
+                // its TTL period has expired.
+                if (bundle != NONEXISTENT_BUNDLE) {
+                    // Synchronize here to call needsReload to avoid
+                    // redundant concurrent calls for the same bundle.
+                    synchronized (bundle) {
+                        expirationTime = key.expirationTime;
+                        if (!bundle.expired && expirationTime >= 0 &&
+                            expirationTime <= System.currentTimeMillis()) {
+                            try {
+                                bundle.expired = control.needsReload(key.getName(),
+                                                                     key.getLocale(),
+                                                                     key.getFormat(),
+                                                                     key.getLoader(),
+                                                                     bundle,
+                                                                     key.loadTime);
+                            } catch (Exception e) {
+                                cacheKey.setCause(e);
+                            }
+                            if (bundle.expired) {
+                                // If the bundle needs to be reloaded, then
+                                // remove the bundle from the cache, but
+                                // return the bundle with the expired flag
+                                // on.
+                                bundle.cacheKey = null;
+                                cacheList.remove(cacheKey, bundleRef);
+                            } else {
+                                // Update the expiration control info. and reuse
+                                // the same bundle instance
+                                setExpirationTime(key, control);
+                            }
+                        }
+                    }
+                } else {
+                    // We just remove NONEXISTENT_BUNDLE from the cache.
+                    cacheList.remove(cacheKey, bundleRef);
+                    bundle = null;
+                }
+            }
+        }
+        return bundle;
+    }
+
+    /**
+     * Put a new bundle in the cache.
+     *
+     * @param cacheKey the key for the resource bundle
+     * @param bundle the resource bundle to be put in the cache
+     * @return the ResourceBundle for the cacheKey; if someone has put
+     * the bundle before this call, the one found in the cache is
+     * returned.
+     */
+    private static ResourceBundle putBundleInCache(CacheKey cacheKey,
+                                                   ResourceBundle bundle,
+                                                   Control control) {
+        setExpirationTime(cacheKey, control);
+        if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
+            CacheKey key = (CacheKey) cacheKey.clone();
+            BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
+            bundle.cacheKey = key;
+
+            // Put the bundle in the cache if it's not been in the cache.
+            BundleReference result = cacheList.putIfAbsent(key, bundleRef);
+
+            // If someone else has put the same bundle in the cache before
+            // us and it has not expired, we should use the one in the cache.
+            if (result != null) {
+                ResourceBundle rb = result.get();
+                if (rb != null && !rb.expired) {
+                    // Clear the back link to the cache key
+                    bundle.cacheKey = null;
+                    bundle = rb;
+                    // Clear the reference in the BundleReference so that
+                    // it won't be enqueued.
+                    bundleRef.clear();
+                } else {
+                    // Replace the invalid (garbage collected or expired)
+                    // instance with the valid one.
+                    cacheList.put(key, bundleRef);
+                }
+            }
+        }
+        return bundle;
+    }
+
+    private static void setExpirationTime(CacheKey cacheKey, Control control) {
+        long ttl = control.getTimeToLive(cacheKey.getName(),
+                                         cacheKey.getLocale());
+        if (ttl >= 0) {
+            // If any expiration time is specified, set the time to be
+            // expired in the cache.
+            long now = System.currentTimeMillis();
+            cacheKey.loadTime = now;
+            cacheKey.expirationTime = now + ttl;
+        } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
+            cacheKey.expirationTime = ttl;
+        } else {
+            throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
+        }
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded
+     * using the caller's class loader.
+     *
+     * @since 1.6
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    @CallerSensitive
+    public static final void clearCache() {
+        clearCache(getLoader(Reflection.getCallerClass()));
+    }
+
+    /**
+     * Removes all resource bundles from the cache that have been loaded
+     * using the given class loader.
+     *
+     * @param loader the class loader
+     * @exception NullPointerException if <code>loader</code> is null
+     * @since 1.6
+     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
+     */
+    public static final void clearCache(ClassLoader loader) {
+        if (loader == null) {
+            throw new NullPointerException();
+        }
+        Set<CacheKey> set = cacheList.keySet();
+        for (CacheKey key : set) {
+            if (key.getLoader() == loader) {
+                set.remove(key);
+            }
+        }
+    }
+
+    /**
+     * Gets an object for the given key from this resource bundle.
+     * Returns null if this resource bundle does not contain an
+     * object for the given key.
+     *
+     * @param key the key for the desired object
+     * @exception NullPointerException if <code>key</code> is <code>null</code>
+     * @return the object for the given key, or null
+     */
+    protected abstract Object handleGetObject(String key);
+
+    /**
+     * Returns an enumeration of the keys.
+     *
+     * @return an <code>Enumeration</code> of the keys contained in
+     *         this <code>ResourceBundle</code> and its parent bundles.
+     */
+    public abstract Enumeration<String> getKeys();
+
+    /**
+     * Determines whether the given <code>key</code> is contained in
+     * this <code>ResourceBundle</code> or its parent bundles.
+     *
+     * @param key
+     *        the resource <code>key</code>
+     * @return <code>true</code> if the given <code>key</code> is
+     *        contained in this <code>ResourceBundle</code> or its
+     *        parent bundles; <code>false</code> otherwise.
+     * @exception NullPointerException
+     *         if <code>key</code> is <code>null</code>
+     * @since 1.6
+     */
+    public boolean containsKey(String key) {
+        if (key == null) {
+            throw new NullPointerException();
+        }
+        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
+            if (rb.handleKeySet().contains(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns a <code>Set</code> of all keys contained in this
+     * <code>ResourceBundle</code> and its parent bundles.
+     *
+     * @return a <code>Set</code> of all keys contained in this
+     *         <code>ResourceBundle</code> and its parent bundles.
+     * @since 1.6
+     */
+    public Set<String> keySet() {
+        Set<String> keys = new HashSet<>();
+        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
+            keys.addAll(rb.handleKeySet());
+        }
+        return keys;
+    }
+
+    /**
+     * Returns a <code>Set</code> of the keys contained <em>only</em>
+     * in this <code>ResourceBundle</code>.
+     *
+     * <p>The default implementation returns a <code>Set</code> of the
+     * keys returned by the {@link #getKeys() getKeys} method except
+     * for the ones for which the {@link #handleGetObject(String)
+     * handleGetObject} method returns <code>null</code>. Once the
+     * <code>Set</code> has been created, the value is kept in this
+     * <code>ResourceBundle</code> in order to avoid producing the
+     * same <code>Set</code> in subsequent calls. Subclasses can
+     * override this method for faster handling.
+     *
+     * @return a <code>Set</code> of the keys contained only in this
+     *        <code>ResourceBundle</code>
+     * @since 1.6
+     */
+    protected Set<String> handleKeySet() {
+        if (keySet == null) {
+            synchronized (this) {
+                if (keySet == null) {
+                    Set<String> keys = new HashSet<>();
+                    Enumeration<String> enumKeys = getKeys();
+                    while (enumKeys.hasMoreElements()) {
+                        String key = enumKeys.nextElement();
+                        if (handleGetObject(key) != null) {
+                            keys.add(key);
+                        }
+                    }
+                    keySet = keys;
+                }
+            }
+        }
+        return keySet;
+    }
+
+
+
+    /**
+     * <code>ResourceBundle.Control</code> defines a set of callback methods
+     * that are invoked by the {@link ResourceBundle#getBundle(String,
+     * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
+     * methods during the bundle loading process. In other words, a
+     * <code>ResourceBundle.Control</code> collaborates with the factory
+     * methods for loading resource bundles. The default implementation of
+     * the callback methods provides the information necessary for the
+     * factory methods to perform the <a
+     * href="./ResourceBundle.html#default_behavior">default behavior</a>.
+     *
+     * <p>In addition to the callback methods, the {@link
+     * #toBundleName(String, Locale) toBundleName} and {@link
+     * #toResourceName(String, String) toResourceName} methods are defined
+     * primarily for convenience in implementing the callback
+     * methods. However, the <code>toBundleName</code> method could be
+     * overridden to provide different conventions in the organization and
+     * packaging of localized resources.  The <code>toResourceName</code>
+     * method is <code>final</code> to avoid use of wrong resource and class
+     * name separators.
+     *
+     * <p>Two factory methods, {@link #getControl(List)} and {@link
+     * #getNoFallbackControl(List)}, provide
+     * <code>ResourceBundle.Control</code> instances that implement common
+     * variations of the default bundle loading process.
+     *
+     * <p>The formats returned by the {@link Control#getFormats(String)
+     * getFormats} method and candidate locales returned by the {@link
+     * ResourceBundle.Control#getCandidateLocales(String, Locale)
+     * getCandidateLocales} method must be consistent in all
+     * <code>ResourceBundle.getBundle</code> invocations for the same base
+     * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
+     * may return unintended bundles. For example, if only
+     * <code>"java.class"</code> is returned by the <code>getFormats</code>
+     * method for the first call to <code>ResourceBundle.getBundle</code>
+     * and only <code>"java.properties"</code> for the second call, then the
+     * second call will return the class-based one that has been cached
+     * during the first call.
+     *
+     * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
+     * if it's simultaneously used by multiple threads.
+     * <code>ResourceBundle.getBundle</code> does not synchronize to call
+     * the <code>ResourceBundle.Control</code> methods. The default
+     * implementations of the methods are thread-safe.
+     *
+     * <p>Applications can specify <code>ResourceBundle.Control</code>
+     * instances returned by the <code>getControl</code> factory methods or
+     * created from a subclass of <code>ResourceBundle.Control</code> to
+     * customize the bundle loading process. The following are examples of
+     * changing the default bundle loading process.
+     *
+     * <p><b>Example 1</b>
+     *
+     * <p>The following code lets <code>ResourceBundle.getBundle</code> look
+     * up only properties-based resources.
+     *
+     * <pre>
+     * import java.util.*;
+     * import static java.util.ResourceBundle.Control.*;
+     * ...
+     * ResourceBundle bundle =
+     *   ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
+     *                            ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
+     * </pre>
+     *
+     * Given the resource bundles in the <a
+     * href="./ResourceBundle.html#default_behavior_example">example</a> in
+     * the <code>ResourceBundle.getBundle</code> description, this
+     * <code>ResourceBundle.getBundle</code> call loads
+     * <code>MyResources_fr_CH.properties</code> whose parent is
+     * <code>MyResources_fr.properties</code> whose parent is
+     * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
+     * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
+     *
+     * <p><b>Example 2</b>
+     *
+     * <p>The following is an example of loading XML-based bundles
+     * using {@link Properties#loadFromXML(java.io.InputStream)
+     * Properties.loadFromXML}.
+     *
+     * <pre>
+     * ResourceBundle rb = ResourceBundle.getBundle("Messages",
+     *     new ResourceBundle.Control() {
+     *         public List&lt;String&gt; getFormats(String baseName) {
+     *             if (baseName == null)
+     *                 throw new NullPointerException();
+     *             return Arrays.asList("xml");
+     *         }
+     *         public ResourceBundle newBundle(String baseName,
+     *                                         Locale locale,
+     *                                         String format,
+     *                                         ClassLoader loader,
+     *                                         boolean reload)
+     *                          throws IllegalAccessException,
+     *                                 InstantiationException,
+     *                                 IOException {
+     *             if (baseName == null || locale == null
+     *                   || format == null || loader == null)
+     *                 throw new NullPointerException();
+     *             ResourceBundle bundle = null;
+     *             if (format.equals("xml")) {
+     *                 String bundleName = toBundleName(baseName, locale);
+     *                 String resourceName = toResourceName(bundleName, format);
+     *                 InputStream stream = null;
+     *                 if (reload) {
+     *                     URL url = loader.getResource(resourceName);
+     *                     if (url != null) {
+     *                         URLConnection connection = url.openConnection();
+     *                         if (connection != null) {
+     *                             // Disable caches to get fresh data for
+     *                             // reloading.
+     *                             connection.setUseCaches(false);
+     *                             stream = connection.getInputStream();
+     *                         }
+     *                     }
+     *                 } else {
+     *                     stream = loader.getResourceAsStream(resourceName);
+     *                 }
+     *                 if (stream != null) {
+     *                     BufferedInputStream bis = new BufferedInputStream(stream);
+     *                     bundle = new XMLResourceBundle(bis);
+     *                     bis.close();
+     *                 }
+     *             }
+     *             return bundle;
+     *         }
+     *     });
+     *
+     * ...
+     *
+     * private static class XMLResourceBundle extends ResourceBundle {
+     *     private Properties props;
+     *     XMLResourceBundle(InputStream stream) throws IOException {
+     *         props = new Properties();
+     *         props.loadFromXML(stream);
+     *     }
+     *     protected Object handleGetObject(String key) {
+     *         return props.getProperty(key);
+     *     }
+     *     public Enumeration&lt;String&gt; getKeys() {
+     *         ...
+     *     }
+     * }
+     * </pre>
+     *
+     * @since 1.6
+     */
+    public static class Control {
+        /**
+         * The default format <code>List</code>, which contains the strings
+         * <code>"java.class"</code> and <code>"java.properties"</code>, in
+         * this order. This <code>List</code> is {@linkplain
+         * Collections#unmodifiableList(List) unmodifiable}.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_DEFAULT
+            = Collections.unmodifiableList(Arrays.asList("java.class",
+                                                         "java.properties"));
+
+        /**
+         * The class-only format <code>List</code> containing
+         * <code>"java.class"</code>. This <code>List</code> is {@linkplain
+         * Collections#unmodifiableList(List) unmodifiable}.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_CLASS
+            = Collections.unmodifiableList(Arrays.asList("java.class"));
+
+        /**
+         * The properties-only format <code>List</code> containing
+         * <code>"java.properties"</code>. This <code>List</code> is
+         * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
+         *
+         * @see #getFormats(String)
+         */
+        public static final List<String> FORMAT_PROPERTIES
+            = Collections.unmodifiableList(Arrays.asList("java.properties"));
+
+        /**
+         * The time-to-live constant for not caching loaded resource bundle
+         * instances.
+         *
+         * @see #getTimeToLive(String, Locale)
+         */
+        public static final long TTL_DONT_CACHE = -1;
+
+        /**
+         * The time-to-live constant for disabling the expiration control
+         * for loaded resource bundle instances in the cache.
+         *
+         * @see #getTimeToLive(String, Locale)
+         */
+        public static final long TTL_NO_EXPIRATION_CONTROL = -2;
+
+        private static final Control INSTANCE = new Control();
+
+        /**
+         * Sole constructor. (For invocation by subclass constructors,
+         * typically implicit.)
+         */
+        protected Control() {
+        }
+
+        /**
+         * Returns a <code>ResourceBundle.Control</code> in which the {@link
+         * #getFormats(String) getFormats} method returns the specified
+         * <code>formats</code>. The <code>formats</code> must be equal to
+         * one of {@link Control#FORMAT_PROPERTIES}, {@link
+         * Control#FORMAT_CLASS} or {@link
+         * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
+         * instances returned by this method are singletons and thread-safe.
+         *
+         * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
+         * instantiating the <code>ResourceBundle.Control</code> class,
+         * except that this method returns a singleton.
+         *
+         * @param formats
+         *        the formats to be returned by the
+         *        <code>ResourceBundle.Control.getFormats</code> method
+         * @return a <code>ResourceBundle.Control</code> supporting the
+         *        specified <code>formats</code>
+         * @exception NullPointerException
+         *        if <code>formats</code> is <code>null</code>
+         * @exception IllegalArgumentException
+         *        if <code>formats</code> is unknown
+         */
+        public static final Control getControl(List<String> formats) {
+            if (formats.equals(Control.FORMAT_PROPERTIES)) {
+                return SingleFormatControl.PROPERTIES_ONLY;
+            }
+            if (formats.equals(Control.FORMAT_CLASS)) {
+                return SingleFormatControl.CLASS_ONLY;
+            }
+            if (formats.equals(Control.FORMAT_DEFAULT)) {
+                return Control.INSTANCE;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        /**
+         * Returns a <code>ResourceBundle.Control</code> in which the {@link
+         * #getFormats(String) getFormats} method returns the specified
+         * <code>formats</code> and the {@link
+         * Control#getFallbackLocale(String, Locale) getFallbackLocale}
+         * method returns <code>null</code>. The <code>formats</code> must
+         * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
+         * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
+         * <code>ResourceBundle.Control</code> instances returned by this
+         * method are singletons and thread-safe.
+         *
+         * @param formats
+         *        the formats to be returned by the
+         *        <code>ResourceBundle.Control.getFormats</code> method
+         * @return a <code>ResourceBundle.Control</code> supporting the
+         *        specified <code>formats</code> with no fallback
+         *        <code>Locale</code> support
+         * @exception NullPointerException
+         *        if <code>formats</code> is <code>null</code>
+         * @exception IllegalArgumentException
+         *        if <code>formats</code> is unknown
+         */
+        public static final Control getNoFallbackControl(List<String> formats) {
+            if (formats.equals(Control.FORMAT_DEFAULT)) {
+                return NoFallbackControl.NO_FALLBACK;
+            }
+            if (formats.equals(Control.FORMAT_PROPERTIES)) {
+                return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
+            }
+            if (formats.equals(Control.FORMAT_CLASS)) {
+                return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
+            }
+            throw new IllegalArgumentException();
+        }
+
+        /**
+         * Returns a <code>List</code> of <code>String</code>s containing
+         * formats to be used to load resource bundles for the given
+         * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
+         * factory method tries to load resource bundles with formats in the
+         * order specified by the list. The list returned by this method
+         * must have at least one <code>String</code>. The predefined
+         * formats are <code>"java.class"</code> for class-based resource
+         * bundles and <code>"java.properties"</code> for {@linkplain
+         * PropertyResourceBundle properties-based} ones. Strings starting
+         * with <code>"java."</code> are reserved for future extensions and
+         * must not be used by application-defined formats.
+         *
+         * <p>It is not a requirement to return an immutable (unmodifiable)
+         * <code>List</code>.  However, the returned <code>List</code> must
+         * not be mutated after it has been returned by
+         * <code>getFormats</code>.
+         *
+         * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
+         * that the <code>ResourceBundle.getBundle</code> factory method
+         * looks up first class-based resource bundles, then
+         * properties-based ones.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully qualified class
+         *        name
+         * @return a <code>List</code> of <code>String</code>s containing
+         *        formats for loading resource bundles.
+         * @exception NullPointerException
+         *        if <code>baseName</code> is null
+         * @see #FORMAT_DEFAULT
+         * @see #FORMAT_CLASS
+         * @see #FORMAT_PROPERTIES
+         */
+        public List<String> getFormats(String baseName) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return FORMAT_DEFAULT;
+        }
+
+        /**
+         * Returns a <code>List</code> of <code>Locale</code>s as candidate
+         * locales for <code>baseName</code> and <code>locale</code>. This
+         * method is called by the <code>ResourceBundle.getBundle</code>
+         * factory method each time the factory method tries finding a
+         * resource bundle for a target <code>Locale</code>.
+         *
+         * <p>The sequence of the candidate locales also corresponds to the
+         * runtime resource lookup path (also known as the <I>parent
+         * chain</I>), if the corresponding resource bundles for the
+         * candidate locales exist and their parents are not defined by
+         * loaded resource bundles themselves.  The last element of the list
+         * must be a {@linkplain Locale#ROOT root locale} if it is desired to
+         * have the base bundle as the terminal of the parent chain.
+         *
+         * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
+         * root locale), a <code>List</code> containing only the root
+         * <code>Locale</code> must be returned. In this case, the
+         * <code>ResourceBundle.getBundle</code> factory method loads only
+         * the base bundle as the resulting resource bundle.
+         *
+         * <p>It is not a requirement to return an immutable (unmodifiable)
+         * <code>List</code>. However, the returned <code>List</code> must not
+         * be mutated after it has been returned by
+         * <code>getCandidateLocales</code>.
+         *
+         * <p>The default implementation returns a <code>List</code> containing
+         * <code>Locale</code>s using the rules described below.  In the
+         * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
+         * respectively represent non-empty language, script, country, and
+         * variant.  For example, [<em>L</em>, <em>C</em>] represents a
+         * <code>Locale</code> that has non-empty values only for language and
+         * country.  The form <em>L</em>("xx") represents the (non-empty)
+         * language value is "xx".  For all cases, <code>Locale</code>s whose
+         * final component values are empty strings are omitted.
+         *
+         * <ol><li>For an input <code>Locale</code> with an empty script value,
+         * append candidate <code>Locale</code>s by omitting the final component
+         * one by one as below:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>] </li>
+         * <li> [<em>L</em>, <em>C</em>] </li>
+         * <li> [<em>L</em>] </li>
+         * <li> <code>Locale.ROOT</code> </li>
+         * </ul></li>
+         *
+         * <li>For an input <code>Locale</code> with a non-empty script value,
+         * append candidate <code>Locale</code>s by omitting the final component
+         * up to language, then append candidates generated from the
+         * <code>Locale</code> with country and variant restored:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>For an input <code>Locale</code> with a variant value consisting
+         * of multiple subtags separated by underscore, generate candidate
+         * <code>Locale</code>s by omitting the variant subtags one by one, then
+         * insert them after every occurrence of <code> Locale</code>s with the
+         * full variant value in the original list.  For example, if the
+         * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
+         *
+         * <ul>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>, <em>S</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]</li>
+         * <li> [<em>L</em>, <em>C</em>]</li>
+         * <li> [<em>L</em>]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>Special cases for Chinese.  When an input <code>Locale</code> has the
+         * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
+         * "Hant" (Traditional) might be supplied, depending on the country.
+         * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
+         * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
+         * or "TW" (Taiwan), "Hant" is supplied.  For all other countries or when the country
+         * is empty, no script is supplied.  For example, for <code>Locale("zh", "CN")
+         * </code>, the candidate list will be:
+         * <ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * For <code>Locale("zh", "TW")</code>, the candidate list will be:
+         * <ul>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]</li>
+         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]</li>
+         * <li> [<em>L</em>("zh")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul></li>
+         *
+         * <li>Special cases for Norwegian.  Both <code>Locale("no", "NO",
+         * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
+         * Nynorsk.  When a locale's language is "nn", the standard candidate
+         * list is generated up to [<em>L</em>("nn")], and then the following
+         * candidates are added:
+         *
+         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
+         * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
+         * followed.
+         *
+         * <p>Also, Java treats the language "no" as a synonym of Norwegian
+         * Bokm&#xE5;l "nb".  Except for the single case <code>Locale("no",
+         * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
+         * has language "no" or "nb", candidate <code>Locale</code>s with
+         * language code "no" and "nb" are interleaved, first using the
+         * requested language, then using its synonym. For example,
+         * <code>Locale("nb", "NO", "POSIX")</code> generates the following
+         * candidate list:
+         *
+         * <ul>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+         * <li> [<em>L</em>("nb")]</li>
+         * <li> [<em>L</em>("no")]</li>
+         * <li> <code>Locale.ROOT</code></li>
+         * </ul>
+         *
+         * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
+         * except that locales with "no" would appear before the corresponding
+         * locales with "nb".</li>
+         * </ol>
+         *
+         * <p>The default implementation uses an {@link ArrayList} that
+         * overriding implementations may modify before returning it to the
+         * caller. However, a subclass must not modify it after it has
+         * been returned by <code>getCandidateLocales</code>.
+         *
+         * <p>For example, if the given <code>baseName</code> is "Messages"
+         * and the given <code>locale</code> is
+         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then a
+         * <code>List</code> of <code>Locale</code>s:
+         * <pre>
+         *     Locale("ja", "", "XX")
+         *     Locale("ja")
+         *     Locale.ROOT
+         * </pre>
+         * is returned. And if the resource bundles for the "ja" and
+         * "" <code>Locale</code>s are found, then the runtime resource
+         * lookup path (parent chain) is:
+         * <pre>{@code
+         *     Messages_ja -> Messages
+         * }</pre>
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which a resource bundle is desired
+         * @return a <code>List</code> of candidate
+         *        <code>Locale</code>s for the given <code>locale</code>
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code> is
+         *        <code>null</code>
+         */
+        public List<Locale> getCandidateLocales(String baseName, Locale locale) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
+        }
+
+        private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
+
+        private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
+            protected List<Locale> createObject(BaseLocale base) {
+                String language = base.getLanguage();
+                String script = base.getScript();
+                String region = base.getRegion();
+                String variant = base.getVariant();
+
+                // Special handling for Norwegian
+                boolean isNorwegianBokmal = false;
+                boolean isNorwegianNynorsk = false;
+                if (language.equals("no")) {
+                    if (region.equals("NO") && variant.equals("NY")) {
+                        variant = "";
+                        isNorwegianNynorsk = true;
+                    } else {
+                        isNorwegianBokmal = true;
+                    }
+                }
+                if (language.equals("nb") || isNorwegianBokmal) {
+                    List<Locale> tmpList = getDefaultList("nb", script, region, variant);
+                    // Insert a locale replacing "nb" with "no" for every list entry
+                    List<Locale> bokmalList = new LinkedList<>();
+                    for (Locale l : tmpList) {
+                        bokmalList.add(l);
+                        if (l.getLanguage().length() == 0) {
+                            break;
+                        }
+                        bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
+                                l.getVariant(), null));
+                    }
+                    return bokmalList;
+                } else if (language.equals("nn") || isNorwegianNynorsk) {
+                    // Insert no_NO_NY, no_NO, no after nn
+                    List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
+                    int idx = nynorskList.size() - 1;
+                    nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
+                    nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
+                    nynorskList.add(idx++, Locale.getInstance("no", "", ""));
+                    return nynorskList;
+                }
+                // Special handling for Chinese
+                else if (language.equals("zh")) {
+                    if (script.length() == 0 && region.length() > 0) {
+                        // Supply script for users who want to use zh_Hans/zh_Hant
+                        // as bundle names (recommended for Java7+)
+                        switch (region) {
+                        case "TW":
+                        case "HK":
+                        case "MO":
+                            script = "Hant";
+                            break;
+                        case "CN":
+                        case "SG":
+                            script = "Hans";
+                            break;
+                        }
+                    } else if (script.length() > 0 && region.length() == 0) {
+                        // Supply region(country) for users who still package Chinese
+                        // bundles using old convension.
+                        switch (script) {
+                        case "Hans":
+                            region = "CN";
+                            break;
+                        case "Hant":
+                            region = "TW";
+                            break;
+                        }
+                    }
+                }
+
+                return getDefaultList(language, script, region, variant);
+            }
+
+            private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
+                List<String> variants = null;
+
+                if (variant.length() > 0) {
+                    variants = new LinkedList<>();
+                    int idx = variant.length();
+                    while (idx != -1) {
+                        variants.add(variant.substring(0, idx));
+                        idx = variant.lastIndexOf('_', --idx);
+                    }
+                }
+
+                List<Locale> list = new LinkedList<>();
+
+                if (variants != null) {
+                    for (String v : variants) {
+                        list.add(Locale.getInstance(language, script, region, v, null));
+                    }
+                }
+                if (region.length() > 0) {
+                    list.add(Locale.getInstance(language, script, region, "", null));
+                }
+                if (script.length() > 0) {
+                    list.add(Locale.getInstance(language, script, "", "", null));
+
+                    // With script, after truncating variant, region and script,
+                    // start over without script.
+                    if (variants != null) {
+                        for (String v : variants) {
+                            list.add(Locale.getInstance(language, "", region, v, null));
+                        }
+                    }
+                    if (region.length() > 0) {
+                        list.add(Locale.getInstance(language, "", region, "", null));
+                    }
+                }
+                if (language.length() > 0) {
+                    list.add(Locale.getInstance(language, "", "", "", null));
+                }
+                // Add root locale at the end
+                list.add(Locale.ROOT);
+
+                return list;
+            }
+        }
+
+        /**
+         * Returns a <code>Locale</code> to be used as a fallback locale for
+         * further resource bundle searches by the
+         * <code>ResourceBundle.getBundle</code> factory method. This method
+         * is called from the factory method every time when no resulting
+         * resource bundle has been found for <code>baseName</code> and
+         * <code>locale</code>, where locale is either the parameter for
+         * <code>ResourceBundle.getBundle</code> or the previous fallback
+         * locale returned by this method.
+         *
+         * <p>The method returns <code>null</code> if no further fallback
+         * search is desired.
+         *
+         * <p>The default implementation returns the {@linkplain
+         * Locale#getDefault() default <code>Locale</code>} if the given
+         * <code>locale</code> isn't the default one.  Otherwise,
+         * <code>null</code> is returned.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name for which
+         *        <code>ResourceBundle.getBundle</code> has been
+         *        unable to find any resource bundles (except for the
+         *        base bundle)
+         * @param locale
+         *        the <code>Locale</code> for which
+         *        <code>ResourceBundle.getBundle</code> has been
+         *        unable to find any resource bundles (except for the
+         *        base bundle)
+         * @return a <code>Locale</code> for the fallback search,
+         *        or <code>null</code> if no further fallback search
+         *        is desired.
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code>
+         *        is <code>null</code>
+         */
+        public Locale getFallbackLocale(String baseName, Locale locale) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            Locale defaultLocale = Locale.getDefault();
+            return locale.equals(defaultLocale) ? null : defaultLocale;
+        }
+
+        /**
+         * Instantiates a resource bundle for the given bundle name of the
+         * given format and locale, using the given class loader if
+         * necessary. This method returns <code>null</code> if there is no
+         * resource bundle available for the given parameters. If a resource
+         * bundle can't be instantiated due to an unexpected error, the
+         * error must be reported by throwing an <code>Error</code> or
+         * <code>Exception</code> rather than simply returning
+         * <code>null</code>.
+         *
+         * <p>If the <code>reload</code> flag is <code>true</code>, it
+         * indicates that this method is being called because the previously
+         * loaded resource bundle has expired.
+         *
+         * <p>The default implementation instantiates a
+         * <code>ResourceBundle</code> as follows.
+         *
+         * <ul>
+         *
+         * <li>The bundle name is obtained by calling {@link
+         * #toBundleName(String, Locale) toBundleName(baseName,
+         * locale)}.</li>
+         *
+         * <li>If <code>format</code> is <code>"java.class"</code>, the
+         * {@link Class} specified by the bundle name is loaded by calling
+         * {@link ClassLoader#loadClass(String)}. Then, a
+         * <code>ResourceBundle</code> is instantiated by calling {@link
+         * Class#newInstance()}.  Note that the <code>reload</code> flag is
+         * ignored for loading class-based resource bundles in this default
+         * implementation.</li>
+         *
+         * <li>If <code>format</code> is <code>"java.properties"</code>,
+         * {@link #toResourceName(String, String) toResourceName(bundlename,
+         * "properties")} is called to get the resource name.
+         * If <code>reload</code> is <code>true</code>, {@link
+         * ClassLoader#getResource(String) load.getResource} is called
+         * to get a {@link URL} for creating a {@link
+         * URLConnection}. This <code>URLConnection</code> is used to
+         * {@linkplain URLConnection#setUseCaches(boolean) disable the
+         * caches} of the underlying resource loading layers,
+         * and to {@linkplain URLConnection#getInputStream() get an
+         * <code>InputStream</code>}.
+         * Otherwise, {@link ClassLoader#getResourceAsStream(String)
+         * loader.getResourceAsStream} is called to get an {@link
+         * InputStream}. Then, a {@link
+         * PropertyResourceBundle} is constructed with the
+         * <code>InputStream</code>.</li>
+         *
+         * <li>If <code>format</code> is neither <code>"java.class"</code>
+         * nor <code>"java.properties"</code>, an
+         * <code>IllegalArgumentException</code> is thrown.</li>
+         *
+         * </ul>
+         *
+         * @param baseName
+         *        the base bundle name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which the resource bundle should be
+         *        instantiated
+         * @param format
+         *        the resource bundle format to be loaded
+         * @param loader
+         *        the <code>ClassLoader</code> to use to load the bundle
+         * @param reload
+         *        the flag to indicate bundle reloading; <code>true</code>
+         *        if reloading an expired resource bundle,
+         *        <code>false</code> otherwise
+         * @return the resource bundle instance,
+         *        or <code>null</code> if none could be found.
+         * @exception NullPointerException
+         *        if <code>bundleName</code>, <code>locale</code>,
+         *        <code>format</code>, or <code>loader</code> is
+         *        <code>null</code>, or if <code>null</code> is returned by
+         *        {@link #toBundleName(String, Locale) toBundleName}
+         * @exception IllegalArgumentException
+         *        if <code>format</code> is unknown, or if the resource
+         *        found for the given parameters contains malformed data.
+         * @exception ClassCastException
+         *        if the loaded class cannot be cast to <code>ResourceBundle</code>
+         * @exception IllegalAccessException
+         *        if the class or its nullary constructor is not
+         *        accessible.
+         * @exception InstantiationException
+         *        if the instantiation of a class fails for some other
+         *        reason.
+         * @exception ExceptionInInitializerError
+         *        if the initialization provoked by this method fails.
+         * @exception SecurityException
+         *        If a security manager is present and creation of new
+         *        instances is denied. See {@link Class#newInstance()}
+         *        for details.
+         * @exception IOException
+         *        if an error occurred when reading resources using
+         *        any I/O operations
+         */
+        public ResourceBundle newBundle(String baseName, Locale locale, String format,
+                                        ClassLoader loader, boolean reload)
+                    throws IllegalAccessException, InstantiationException, IOException {
+            String bundleName = toBundleName(baseName, locale);
+            ResourceBundle bundle = null;
+            if (format.equals("java.class")) {
+                try {
+                    @SuppressWarnings("unchecked")
+                    Class<? extends ResourceBundle> bundleClass
+                        = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
+
+                    // If the class isn't a ResourceBundle subclass, throw a
+                    // ClassCastException.
+                    if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
+                        bundle = bundleClass.newInstance();
+                    } else {
+                        throw new ClassCastException(bundleClass.getName()
+                                     + " cannot be cast to ResourceBundle");
+                    }
+                } catch (ClassNotFoundException e) {
+                }
+            } else if (format.equals("java.properties")) {
+                final String resourceName = toResourceName0(bundleName, "properties");
+                if (resourceName == null) {
+                    return bundle;
+                }
+                final ClassLoader classLoader = loader;
+                final boolean reloadFlag = reload;
+                InputStream stream = null;
+                try {
+                    stream = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<InputStream>() {
+                            public InputStream run() throws IOException {
+                                InputStream is = null;
+                                if (reloadFlag) {
+                                    URL url = classLoader.getResource(resourceName);
+                                    if (url != null) {
+                                        URLConnection connection = url.openConnection();
+                                        if (connection != null) {
+                                            // Disable caches to get fresh data for
+                                            // reloading.
+                                            connection.setUseCaches(false);
+                                            is = connection.getInputStream();
+                                        }
+                                    }
+                                } else {
+                                    is = classLoader.getResourceAsStream(resourceName);
+                                }
+                                return is;
+                            }
+                        });
+                } catch (PrivilegedActionException e) {
+                    throw (IOException) e.getException();
+                }
+                if (stream != null) {
+                    try {
+                        // Android-changed: Use UTF-8 for property based resources. b/26879578
+                        // bundle = new PropertyResourceBundle(stream);
+                        bundle = new PropertyResourceBundle(
+                                new InputStreamReader(stream, StandardCharsets.UTF_8));
+                    } finally {
+                        stream.close();
+                    }
+                }
+            } else {
+                throw new IllegalArgumentException("unknown format: " + format);
+            }
+            return bundle;
+        }
+
+        /**
+         * Returns the time-to-live (TTL) value for resource bundles that
+         * are loaded under this
+         * <code>ResourceBundle.Control</code>. Positive time-to-live values
+         * specify the number of milliseconds a bundle can remain in the
+         * cache without being validated against the source data from which
+         * it was constructed. The value 0 indicates that a bundle must be
+         * validated each time it is retrieved from the cache. {@link
+         * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
+         * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
+         * that loaded resource bundles are put in the cache with no
+         * expiration control.
+         *
+         * <p>The expiration affects only the bundle loading process by the
+         * <code>ResourceBundle.getBundle</code> factory method.  That is,
+         * if the factory method finds a resource bundle in the cache that
+         * has expired, the factory method calls the {@link
+         * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
+         * long) needsReload} method to determine whether the resource
+         * bundle needs to be reloaded. If <code>needsReload</code> returns
+         * <code>true</code>, the cached resource bundle instance is removed
+         * from the cache. Otherwise, the instance stays in the cache,
+         * updated with the new TTL value returned by this method.
+         *
+         * <p>All cached resource bundles are subject to removal from the
+         * cache due to memory constraints of the runtime environment.
+         * Returning a large positive value doesn't mean to lock loaded
+         * resource bundles in the cache.
+         *
+         * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
+         *
+         * @param baseName
+         *        the base name of the resource bundle for which the
+         *        expiration value is specified.
+         * @param locale
+         *        the locale of the resource bundle for which the
+         *        expiration value is specified.
+         * @return the time (0 or a positive millisecond offset from the
+         *        cached time) to get loaded bundles expired in the cache,
+         *        {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
+         *        expiration control, or {@link #TTL_DONT_CACHE} to disable
+         *        caching.
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code> is
+         *        <code>null</code>
+         */
+        public long getTimeToLive(String baseName, Locale locale) {
+            if (baseName == null || locale == null) {
+                throw new NullPointerException();
+            }
+            return TTL_NO_EXPIRATION_CONTROL;
+        }
+
+        /**
+         * Determines if the expired <code>bundle</code> in the cache needs
+         * to be reloaded based on the loading time given by
+         * <code>loadTime</code> or some other criteria. The method returns
+         * <code>true</code> if reloading is required; <code>false</code>
+         * otherwise. <code>loadTime</code> is a millisecond offset since
+         * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
+         * Epoch</a>.
+         *
+         * The calling <code>ResourceBundle.getBundle</code> factory method
+         * calls this method on the <code>ResourceBundle.Control</code>
+         * instance used for its current invocation, not on the instance
+         * used in the invocation that originally loaded the resource
+         * bundle.
+         *
+         * <p>The default implementation compares <code>loadTime</code> and
+         * the last modified time of the source data of the resource
+         * bundle. If it's determined that the source data has been modified
+         * since <code>loadTime</code>, <code>true</code> is
+         * returned. Otherwise, <code>false</code> is returned. This
+         * implementation assumes that the given <code>format</code> is the
+         * same string as its file suffix if it's not one of the default
+         * formats, <code>"java.class"</code> or
+         * <code>"java.properties"</code>.
+         *
+         * @param baseName
+         *        the base bundle name of the resource bundle, a
+         *        fully qualified class name
+         * @param locale
+         *        the locale for which the resource bundle
+         *        should be instantiated
+         * @param format
+         *        the resource bundle format to be loaded
+         * @param loader
+         *        the <code>ClassLoader</code> to use to load the bundle
+         * @param bundle
+         *        the resource bundle instance that has been expired
+         *        in the cache
+         * @param loadTime
+         *        the time when <code>bundle</code> was loaded and put
+         *        in the cache
+         * @return <code>true</code> if the expired bundle needs to be
+         *        reloaded; <code>false</code> otherwise.
+         * @exception NullPointerException
+         *        if <code>baseName</code>, <code>locale</code>,
+         *        <code>format</code>, <code>loader</code>, or
+         *        <code>bundle</code> is <code>null</code>
+         */
+        public boolean needsReload(String baseName, Locale locale,
+                                   String format, ClassLoader loader,
+                                   ResourceBundle bundle, long loadTime) {
+            if (bundle == null) {
+                throw new NullPointerException();
+            }
+            if (format.equals("java.class") || format.equals("java.properties")) {
+                format = format.substring(5);
+            }
+            boolean result = false;
+            try {
+                String resourceName = toResourceName0(toBundleName(baseName, locale), format);
+                if (resourceName == null) {
+                    return result;
+                }
+                URL url = loader.getResource(resourceName);
+                if (url != null) {
+                    long lastModified = 0;
+                    URLConnection connection = url.openConnection();
+                    if (connection != null) {
+                        // disable caches to get the correct data
+                        connection.setUseCaches(false);
+                        if (connection instanceof JarURLConnection) {
+                            JarEntry ent = ((JarURLConnection)connection).getJarEntry();
+                            if (ent != null) {
+                                lastModified = ent.getTime();
+                                if (lastModified == -1) {
+                                    lastModified = 0;
+                                }
+                            }
+                        } else {
+                            lastModified = connection.getLastModified();
+                        }
+                    }
+                    result = lastModified >= loadTime;
+                }
+            } catch (NullPointerException npe) {
+                throw npe;
+            } catch (Exception e) {
+                // ignore other exceptions
+            }
+            return result;
+        }
+
+        /**
+         * Converts the given <code>baseName</code> and <code>locale</code>
+         * to the bundle name. This method is called from the default
+         * implementation of the {@link #newBundle(String, Locale, String,
+         * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
+         * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
+         * methods.
+         *
+         * <p>This implementation returns the following value:
+         * <pre>
+         *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
+         * </pre>
+         * where <code>language</code>, <code>script</code>, <code>country</code>,
+         * and <code>variant</code> are the language, script, country, and variant
+         * values of <code>locale</code>, respectively. Final component values that
+         * are empty Strings are omitted along with the preceding '_'.  When the
+         * script is empty, the script value is omitted along with the preceding '_'.
+         * If all of the values are empty strings, then <code>baseName</code>
+         * is returned.
+         *
+         * <p>For example, if <code>baseName</code> is
+         * <code>"baseName"</code> and <code>locale</code> is
+         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then
+         * <code>"baseName_ja_&thinsp;_XX"</code> is returned. If the given
+         * locale is <code>Locale("en")</code>, then
+         * <code>"baseName_en"</code> is returned.
+         *
+         * <p>Overriding this method allows applications to use different
+         * conventions in the organization and packaging of localized
+         * resources.
+         *
+         * @param baseName
+         *        the base name of the resource bundle, a fully
+         *        qualified class name
+         * @param locale
+         *        the locale for which a resource bundle should be
+         *        loaded
+         * @return the bundle name for the resource bundle
+         * @exception NullPointerException
+         *        if <code>baseName</code> or <code>locale</code>
+         *        is <code>null</code>
+         */
+        public String toBundleName(String baseName, Locale locale) {
+            if (locale == Locale.ROOT) {
+                return baseName;
+            }
+
+            String language = locale.getLanguage();
+            String script = locale.getScript();
+            String country = locale.getCountry();
+            String variant = locale.getVariant();
+
+            if (language == "" && country == "" && variant == "") {
+                return baseName;
+            }
+
+            StringBuilder sb = new StringBuilder(baseName);
+            sb.append('_');
+            if (script != "") {
+                if (variant != "") {
+                    sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
+                } else if (country != "") {
+                    sb.append(language).append('_').append(script).append('_').append(country);
+                } else {
+                    sb.append(language).append('_').append(script);
+                }
+            } else {
+                if (variant != "") {
+                    sb.append(language).append('_').append(country).append('_').append(variant);
+                } else if (country != "") {
+                    sb.append(language).append('_').append(country);
+                } else {
+                    sb.append(language);
+                }
+            }
+            return sb.toString();
+
+        }
+
+        /**
+         * Converts the given <code>bundleName</code> to the form required
+         * by the {@link ClassLoader#getResource ClassLoader.getResource}
+         * method by replacing all occurrences of <code>'.'</code> in
+         * <code>bundleName</code> with <code>'/'</code> and appending a
+         * <code>'.'</code> and the given file <code>suffix</code>. For
+         * example, if <code>bundleName</code> is
+         * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
+         * is <code>"properties"</code>, then
+         * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
+         *
+         * @param bundleName
+         *        the bundle name
+         * @param suffix
+         *        the file type suffix
+         * @return the converted resource name
+         * @exception NullPointerException
+         *         if <code>bundleName</code> or <code>suffix</code>
+         *         is <code>null</code>
+         */
+        public final String toResourceName(String bundleName, String suffix) {
+            StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
+            sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
+            return sb.toString();
+        }
+
+        private String toResourceName0(String bundleName, String suffix) {
+            // application protocol check
+            if (bundleName.contains("://")) {
+                return null;
+            } else {
+                return toResourceName(bundleName, suffix);
+            }
+        }
+    }
+
+    private static class SingleFormatControl extends Control {
+        private static final Control PROPERTIES_ONLY
+            = new SingleFormatControl(FORMAT_PROPERTIES);
+
+        private static final Control CLASS_ONLY
+            = new SingleFormatControl(FORMAT_CLASS);
+
+        private final List<String> formats;
+
+        protected SingleFormatControl(List<String> formats) {
+            this.formats = formats;
+        }
+
+        public List<String> getFormats(String baseName) {
+            if (baseName == null) {
+                throw new NullPointerException();
+            }
+            return formats;
+        }
+    }
+
+    private static final class NoFallbackControl extends SingleFormatControl {
+        private static final Control NO_FALLBACK
+            = new NoFallbackControl(FORMAT_DEFAULT);
+
+        private static final Control PROPERTIES_ONLY_NO_FALLBACK
+            = new NoFallbackControl(FORMAT_PROPERTIES);
+
+        private static final Control CLASS_ONLY_NO_FALLBACK
+            = new NoFallbackControl(FORMAT_CLASS);
+
+        protected NoFallbackControl(List<String> formats) {
+            super(formats);
+        }
+
+        public Locale getFallbackLocale(String baseName, Locale locale) {
+            if (baseName == null || locale == null) {
+                throw new NullPointerException();
+            }
+            return null;
+        }
+    }
+}
diff --git a/java/util/Scanner.java b/java/util/Scanner.java
new file mode 100644
index 0000000..15ad8e8
--- /dev/null
+++ b/java/util/Scanner.java
@@ -0,0 +1,2644 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.util.regex.*;
+import java.io.*;
+import java.math.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.charset.*;
+import java.text.*;
+import java.util.Locale;
+
+import sun.misc.LRUCache;
+
+/**
+ * A simple text scanner which can parse primitive types and strings using
+ * regular expressions.
+ *
+ * <p>A <code>Scanner</code> breaks its input into tokens using a
+ * delimiter pattern, which by default matches whitespace. The resulting
+ * tokens may then be converted into values of different types using the
+ * various <tt>next</tt> methods.
+ *
+ * <p>For example, this code allows a user to read a number from
+ * <tt>System.in</tt>:
+ * <blockquote><pre>{@code
+ *     Scanner sc = new Scanner(System.in);
+ *     int i = sc.nextInt();
+ * }</pre></blockquote>
+ *
+ * <p>As another example, this code allows <code>long</code> types to be
+ * assigned from entries in a file <code>myNumbers</code>:
+ * <blockquote><pre>{@code
+ *      Scanner sc = new Scanner(new File("myNumbers"));
+ *      while (sc.hasNextLong()) {
+ *          long aLong = sc.nextLong();
+ *      }
+ * }</pre></blockquote>
+ *
+ * <p>The scanner can also use delimiters other than whitespace. This
+ * example reads several items in from a string:
+ * <blockquote><pre>{@code
+ *     String input = "1 fish 2 fish red fish blue fish";
+ *     Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
+ *     System.out.println(s.nextInt());
+ *     System.out.println(s.nextInt());
+ *     System.out.println(s.next());
+ *     System.out.println(s.next());
+ *     s.close();
+ * }</pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>{@code
+ *     1
+ *     2
+ *     red
+ *     blue
+ * }</pre></blockquote>
+ *
+ * <p>The same output can be generated with this code, which uses a regular
+ * expression to parse all four tokens at once:
+ * <blockquote><pre>{@code
+ *     String input = "1 fish 2 fish red fish blue fish";
+ *     Scanner s = new Scanner(input);
+ *     s.findInLine("(\\d+) fish (\\d+) fish (\\w+) fish (\\w+)");
+ *     MatchResult result = s.match();
+ *     for (int i=1; i<=result.groupCount(); i++)
+ *         System.out.println(result.group(i));
+ *     s.close();
+ * }</pre></blockquote>
+ *
+ * <p>The <a name="default-delimiter">default whitespace delimiter</a> used
+ * by a scanner is as recognized by {@link java.lang.Character}.{@link
+ * java.lang.Character#isWhitespace(char) isWhitespace}. The {@link #reset}
+ * method will reset the value of the scanner's delimiter to the default
+ * whitespace delimiter regardless of whether it was previously changed.
+ *
+ * <p>A scanning operation may block waiting for input.
+ *
+ * <p>The {@link #next} and {@link #hasNext} methods and their
+ * primitive-type companion methods (such as {@link #nextInt} and
+ * {@link #hasNextInt}) first skip any input that matches the delimiter
+ * pattern, and then attempt to return the next token. Both <tt>hasNext</tt>
+ * and <tt>next</tt> methods may block waiting for further input.  Whether a
+ * <tt>hasNext</tt> method blocks has no connection to whether or not its
+ * associated <tt>next</tt> method will block.
+ *
+ * <p> The {@link #findInLine}, {@link #findWithinHorizon}, and {@link #skip}
+ * methods operate independently of the delimiter pattern. These methods will
+ * attempt to match the specified pattern with no regard to delimiters in the
+ * input and thus can be used in special circumstances where delimiters are
+ * not relevant. These methods may block waiting for more input.
+ *
+ * <p>When a scanner throws an {@link InputMismatchException}, the scanner
+ * will not pass the token that caused the exception, so that it may be
+ * retrieved or skipped via some other method.
+ *
+ * <p>Depending upon the type of delimiting pattern, empty tokens may be
+ * returned. For example, the pattern <tt>"\\s+"</tt> will return no empty
+ * tokens since it matches multiple instances of the delimiter. The delimiting
+ * pattern <tt>"\\s"</tt> could return empty tokens since it only passes one
+ * space at a time.
+ *
+ * <p> A scanner can read text from any object which implements the {@link
+ * java.lang.Readable} interface.  If an invocation of the underlying
+ * readable's {@link java.lang.Readable#read} method throws an {@link
+ * java.io.IOException} then the scanner assumes that the end of the input
+ * has been reached.  The most recent <tt>IOException</tt> thrown by the
+ * underlying readable can be retrieved via the {@link #ioException} method.
+ *
+ * <p>When a <code>Scanner</code> is closed, it will close its input source
+ * if the source implements the {@link java.io.Closeable} interface.
+ *
+ * <p>A <code>Scanner</code> is not safe for multithreaded use without
+ * external synchronization.
+ *
+ * <p>Unless otherwise mentioned, passing a <code>null</code> parameter into
+ * any method of a <code>Scanner</code> will cause a
+ * <code>NullPointerException</code> to be thrown.
+ *
+ * <p>A scanner will default to interpreting numbers as decimal unless a
+ * different radix has been set by using the {@link #useRadix} method. The
+ * {@link #reset} method will reset the value of the scanner's radix to
+ * <code>10</code> regardless of whether it was previously changed.
+ *
+ * <h3> <a name="localized-numbers">Localized numbers</a> </h3>
+ *
+ * <p> An instance of this class is capable of scanning numbers in the standard
+ * formats as well as in the formats of the scanner's locale. A scanner's
+ * <a name="initial-locale">initial locale </a>is the value returned by the {@link
+ * java.util.Locale#getDefault(Locale.Category)
+ * Locale.getDefault(Locale.Category.FORMAT)} method; it may be changed via the {@link
+ * #useLocale} method. The {@link #reset} method will reset the value of the
+ * scanner's locale to the initial locale regardless of whether it was
+ * previously changed.
+ *
+ * <p>The localized formats are defined in terms of the following parameters,
+ * which for a particular locale are taken from that locale's {@link
+ * java.text.DecimalFormat DecimalFormat} object, <tt>df</tt>, and its and
+ * {@link java.text.DecimalFormatSymbols DecimalFormatSymbols} object,
+ * <tt>dfs</tt>.
+ *
+ * <blockquote><dl>
+ *     <dt><i>LocalGroupSeparator&nbsp;&nbsp;</i>
+ *         <dd>The character used to separate thousands groups,
+ *         <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *         java.text.DecimalFormatSymbols#getGroupingSeparator
+ *         getGroupingSeparator()}
+ *     <dt><i>LocalDecimalSeparator&nbsp;&nbsp;</i>
+ *         <dd>The character used for the decimal point,
+ *     <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *     java.text.DecimalFormatSymbols#getDecimalSeparator
+ *     getDecimalSeparator()}
+ *     <dt><i>LocalPositivePrefix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears before a positive number (may
+ *         be empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *         java.text.DecimalFormat#getPositivePrefix
+ *         getPositivePrefix()}
+ *     <dt><i>LocalPositiveSuffix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears after a positive number (may be
+ *         empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *         java.text.DecimalFormat#getPositiveSuffix
+ *         getPositiveSuffix()}
+ *     <dt><i>LocalNegativePrefix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears before a negative number (may
+ *         be empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *         java.text.DecimalFormat#getNegativePrefix
+ *         getNegativePrefix()}
+ *     <dt><i>LocalNegativeSuffix&nbsp;&nbsp;</i>
+ *         <dd>The string that appears after a negative number (may be
+ *         empty), <i>i.e.,</i>&nbsp;<tt>df.</tt>{@link
+ *     java.text.DecimalFormat#getNegativeSuffix
+ *     getNegativeSuffix()}
+ *     <dt><i>LocalNaN&nbsp;&nbsp;</i>
+ *         <dd>The string that represents not-a-number for
+ *         floating-point values,
+ *         <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *         java.text.DecimalFormatSymbols#getNaN
+ *         getNaN()}
+ *     <dt><i>LocalInfinity&nbsp;&nbsp;</i>
+ *         <dd>The string that represents infinity for floating-point
+ *         values, <i>i.e.,</i>&nbsp;<tt>dfs.</tt>{@link
+ *         java.text.DecimalFormatSymbols#getInfinity
+ *         getInfinity()}
+ * </dl></blockquote>
+ *
+ * <h4> <a name="number-syntax">Number syntax</a> </h4>
+ *
+ * <p> The strings that can be parsed as numbers by an instance of this class
+ * are specified in terms of the following regular-expression grammar, where
+ * Rmax is the highest digit in the radix being used (for example, Rmax is 9 in base 10).
+ *
+ * <dl>
+ *   <dt><i>NonAsciiDigit</i>:
+ *       <dd>A non-ASCII character c for which
+ *            {@link java.lang.Character#isDigit Character.isDigit}<tt>(c)</tt>
+ *                        returns&nbsp;true
+ *
+ *   <dt><i>Non0Digit</i>:
+ *       <dd><tt>[1-</tt><i>Rmax</i><tt>] | </tt><i>NonASCIIDigit</i>
+ *
+ *   <dt><i>Digit</i>:
+ *       <dd><tt>[0-</tt><i>Rmax</i><tt>] | </tt><i>NonASCIIDigit</i>
+ *
+ *   <dt><i>GroupedNumeral</i>:
+ *       <dd><tt>(&nbsp;</tt><i>Non0Digit</i>
+ *                   <i>Digit</i><tt>?
+ *                   </tt><i>Digit</i><tt>?</tt>
+ *       <dd>&nbsp;&nbsp;&nbsp;&nbsp;<tt>(&nbsp;</tt><i>LocalGroupSeparator</i>
+ *                         <i>Digit</i>
+ *                         <i>Digit</i>
+ *                         <i>Digit</i><tt> )+ )</tt>
+ *
+ *   <dt><i>Numeral</i>:
+ *       <dd><tt>( ( </tt><i>Digit</i><tt>+ )
+ *               | </tt><i>GroupedNumeral</i><tt> )</tt>
+ *
+ *   <dt><a name="Integer-regex"><i>Integer</i>:</a>
+ *       <dd><tt>( [-+]? ( </tt><i>Numeral</i><tt>
+ *                               ) )</tt>
+ *       <dd><tt>| </tt><i>LocalPositivePrefix</i> <i>Numeral</i>
+ *                      <i>LocalPositiveSuffix</i>
+ *       <dd><tt>| </tt><i>LocalNegativePrefix</i> <i>Numeral</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *
+ *   <dt><i>DecimalNumeral</i>:
+ *       <dd><i>Numeral</i>
+ *       <dd><tt>| </tt><i>Numeral</i>
+ *                 <i>LocalDecimalSeparator</i>
+ *                 <i>Digit</i><tt>*</tt>
+ *       <dd><tt>| </tt><i>LocalDecimalSeparator</i>
+ *                 <i>Digit</i><tt>+</tt>
+ *
+ *   <dt><i>Exponent</i>:
+ *       <dd><tt>( [eE] [+-]? </tt><i>Digit</i><tt>+ )</tt>
+ *
+ *   <dt><a name="Decimal-regex"><i>Decimal</i>:</a>
+ *       <dd><tt>( [-+]? </tt><i>DecimalNumeral</i>
+ *                         <i>Exponent</i><tt>? )</tt>
+ *       <dd><tt>| </tt><i>LocalPositivePrefix</i>
+ *                 <i>DecimalNumeral</i>
+ *                 <i>LocalPositiveSuffix</i>
+ *                 <i>Exponent</i><tt>?</tt>
+ *       <dd><tt>| </tt><i>LocalNegativePrefix</i>
+ *                 <i>DecimalNumeral</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *                 <i>Exponent</i><tt>?</tt>
+ *
+ *   <dt><i>HexFloat</i>:
+ *       <dd><tt>[-+]? 0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+
+ *                 ([pP][-+]?[0-9]+)?</tt>
+ *
+ *   <dt><i>NonNumber</i>:
+ *       <dd><tt>NaN
+ *                          | </tt><i>LocalNan</i><tt>
+ *                          | Infinity
+ *                          | </tt><i>LocalInfinity</i>
+ *
+ *   <dt><i>SignedNonNumber</i>:
+ *       <dd><tt>( [-+]? </tt><i>NonNumber</i><tt> )</tt>
+ *       <dd><tt>| </tt><i>LocalPositivePrefix</i>
+ *                 <i>NonNumber</i>
+ *                 <i>LocalPositiveSuffix</i>
+ *       <dd><tt>| </tt><i>LocalNegativePrefix</i>
+ *                 <i>NonNumber</i>
+ *                 <i>LocalNegativeSuffix</i>
+ *
+ *   <dt><a name="Float-regex"><i>Float</i></a>:
+ *       <dd><i>Decimal</i>
+ *           <tt>| </tt><i>HexFloat</i>
+ *           <tt>| </tt><i>SignedNonNumber</i>
+ *
+ * </dl>
+ * <p>Whitespace is not significant in the above regular expressions.
+ *
+ * @since   1.5
+ */
+public final class Scanner implements Iterator<String>, Closeable {
+
+    // Internal buffer used to hold input
+    private CharBuffer buf;
+
+    // Size of internal character buffer
+    private static final int BUFFER_SIZE = 1024; // change to 1024;
+
+    // The index into the buffer currently held by the Scanner
+    private int position;
+
+    // Internal matcher used for finding delimiters
+    private Matcher matcher;
+
+    // Pattern used to delimit tokens
+    private Pattern delimPattern;
+
+    // Pattern found in last hasNext operation
+    private Pattern hasNextPattern;
+
+    // Position after last hasNext operation
+    private int hasNextPosition;
+
+    // Result after last hasNext operation
+    private String hasNextResult;
+
+    // The input source
+    private Readable source;
+
+    // Boolean is true if source is done
+    private boolean sourceClosed = false;
+
+    // Boolean indicating more input is required
+    private boolean needInput = false;
+
+    // Boolean indicating if a delim has been skipped this operation
+    private boolean skipped = false;
+
+    // A store of a position that the scanner may fall back to
+    private int savedScannerPosition = -1;
+
+    // A cache of the last primitive type scanned
+    private Object typeCache = null;
+
+    // Boolean indicating if a match result is available
+    private boolean matchValid = false;
+
+    // Boolean indicating if this scanner has been closed
+    private boolean closed = false;
+
+    // The current radix used by this scanner
+    private int radix = 10;
+
+    // The default radix for this scanner
+    private int defaultRadix = 10;
+
+    // The locale used by this scanner
+    private Locale locale = null;
+
+    // A cache of the last few recently used Patterns
+    private LRUCache<String,Pattern> patternCache =
+    new LRUCache<String,Pattern>(7) {
+        protected Pattern create(String s) {
+            return Pattern.compile(s);
+        }
+        protected boolean hasName(Pattern p, String s) {
+            return p.pattern().equals(s);
+        }
+    };
+
+    // A holder of the last IOException encountered
+    private IOException lastException;
+
+    // A pattern for java whitespace
+    private static Pattern WHITESPACE_PATTERN = Pattern.compile(
+                                                "\\p{javaWhitespace}+");
+
+    // A pattern for any token
+    private static Pattern FIND_ANY_PATTERN = Pattern.compile("(?s).*");
+
+    // A pattern for non-ASCII digits
+    private static Pattern NON_ASCII_DIGIT = Pattern.compile(
+        "[\\p{javaDigit}&&[^0-9]]");
+
+    // Fields and methods to support scanning primitive types
+
+    /**
+     * Locale dependent values used to scan numbers
+     */
+    private String groupSeparator = "\\,";
+    private String decimalSeparator = "\\.";
+    private String nanString = "NaN";
+    private String infinityString = "Infinity";
+    private String positivePrefix = "";
+    private String negativePrefix = "\\-";
+    private String positiveSuffix = "";
+    private String negativeSuffix = "";
+
+    /**
+     * Fields and an accessor method to match booleans
+     */
+    private static volatile Pattern boolPattern;
+    private static final String BOOLEAN_PATTERN = "true|false";
+    private static Pattern boolPattern() {
+        Pattern bp = boolPattern;
+        if (bp == null)
+            boolPattern = bp = Pattern.compile(BOOLEAN_PATTERN,
+                                          Pattern.CASE_INSENSITIVE);
+        return bp;
+    }
+
+    /**
+     * Fields and methods to match bytes, shorts, ints, and longs
+     */
+    private Pattern integerPattern;
+    private String digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+    private String non0Digit = "[\\p{javaDigit}&&[^0]]";
+    private int SIMPLE_GROUP_INDEX = 5;
+    private String buildIntegerPatternString() {
+        String radixDigits = digits.substring(0, radix);
+        // \\p{javaDigit} is not guaranteed to be appropriate
+        // here but what can we do? The final authority will be
+        // whatever parse method is invoked, so ultimately the
+        // Scanner will do the right thing
+        String digit = "((?i)["+radixDigits+"]|\\p{javaDigit})";
+        // BEGIN Android-changed: Support non-decimal starting digits.
+        // Ie., in addition to 1-9, a-z are also valid radix digits.
+        /*
+        String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        */
+        String non0RadixDigits = "((?i)[" + digits.substring(1, radix) + "]|(" + non0Digit + "))";
+        String groupedNumeral = "("+non0RadixDigits+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        // END Android-changed: Support non-decimal starting digits.
+        // digit++ is the possessive form which is necessary for reducing
+        // backtracking that would otherwise cause unacceptable performance
+        String numeral = "(("+ digit+"++)|"+groupedNumeral+")";
+        String javaStyleInteger = "([-+]?(" + numeral + "))";
+        String negativeInteger = negativePrefix + numeral + negativeSuffix;
+        String positiveInteger = positivePrefix + numeral + positiveSuffix;
+        return "("+ javaStyleInteger + ")|(" +
+            positiveInteger + ")|(" +
+            negativeInteger + ")";
+    }
+    private Pattern integerPattern() {
+        if (integerPattern == null) {
+            integerPattern = patternCache.forName(buildIntegerPatternString());
+        }
+        return integerPattern;
+    }
+
+    /**
+     * Fields and an accessor method to match line separators
+     */
+    private static volatile Pattern separatorPattern;
+    private static volatile Pattern linePattern;
+    private static final String LINE_SEPARATOR_PATTERN =
+                                           "\r\n|[\n\r\u2028\u2029\u0085]";
+    private static final String LINE_PATTERN = ".*("+LINE_SEPARATOR_PATTERN+")|.+$";
+
+    private static Pattern separatorPattern() {
+        Pattern sp = separatorPattern;
+        if (sp == null)
+            separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
+        return sp;
+    }
+
+    private static Pattern linePattern() {
+        Pattern lp = linePattern;
+        if (lp == null)
+            linePattern = lp = Pattern.compile(LINE_PATTERN);
+        return lp;
+    }
+
+    /**
+     * Fields and methods to match floats and doubles
+     */
+    private Pattern floatPattern;
+    private Pattern decimalPattern;
+    private void buildFloatAndDecimalPattern() {
+        // \\p{javaDigit} may not be perfect, see above
+        String digit = "([0-9]|(\\p{javaDigit}))";
+        String exponent = "([eE][+-]?"+digit+"+)?";
+        String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
+                                groupSeparator+digit+digit+digit+")+)";
+        // Once again digit++ is used for performance, as above
+        String numeral = "(("+digit+"++)|"+groupedNumeral+")";
+        String decimalNumeral = "("+numeral+"|"+numeral +
+            decimalSeparator + digit + "*+|"+ decimalSeparator +
+            digit + "++)";
+        String nonNumber = "(NaN|"+nanString+"|Infinity|"+
+                               infinityString+")";
+        String positiveFloat = "(" + positivePrefix + decimalNumeral +
+                            positiveSuffix + exponent + ")";
+        String negativeFloat = "(" + negativePrefix + decimalNumeral +
+                            negativeSuffix + exponent + ")";
+        String decimal = "(([-+]?" + decimalNumeral + exponent + ")|"+
+            positiveFloat + "|" + negativeFloat + ")";
+        String hexFloat =
+            "[-+]?0[xX][0-9a-fA-F]*\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?";
+        String positiveNonNumber = "(" + positivePrefix + nonNumber +
+                            positiveSuffix + ")";
+        String negativeNonNumber = "(" + negativePrefix + nonNumber +
+                            negativeSuffix + ")";
+        String signedNonNumber = "(([-+]?"+nonNumber+")|" +
+                                 positiveNonNumber + "|" +
+                                 negativeNonNumber + ")";
+        floatPattern = Pattern.compile(decimal + "|" + hexFloat + "|" +
+                                       signedNonNumber);
+        decimalPattern = Pattern.compile(decimal);
+    }
+    private Pattern floatPattern() {
+        if (floatPattern == null) {
+            buildFloatAndDecimalPattern();
+        }
+        return floatPattern;
+    }
+    private Pattern decimalPattern() {
+        if (decimalPattern == null) {
+            buildFloatAndDecimalPattern();
+        }
+        return decimalPattern;
+    }
+
+    // Constructors
+
+    /**
+     * Constructs a <code>Scanner</code> that returns values scanned
+     * from the specified source delimited by the specified pattern.
+     *
+     * @param source A character source implementing the Readable interface
+     * @param pattern A delimiting pattern
+     */
+    private Scanner(Readable source, Pattern pattern) {
+        assert source != null : "source should not be null";
+        assert pattern != null : "pattern should not be null";
+        this.source = source;
+        delimPattern = pattern;
+        buf = CharBuffer.allocate(BUFFER_SIZE);
+        buf.limit(0);
+        matcher = delimPattern.matcher(buf);
+        matcher.useTransparentBounds(true);
+        matcher.useAnchoringBounds(false);
+        useLocale(Locale.getDefault(Locale.Category.FORMAT));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified source.
+     *
+     * @param  source A character source implementing the {@link Readable}
+     *         interface
+     */
+    public Scanner(Readable source) {
+        this(Objects.requireNonNull(source, "source"), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source An input stream to be scanned
+     */
+    public Scanner(InputStream source) {
+        this(new InputStreamReader(source), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified input stream. Bytes from the stream are converted
+     * into characters using the specified charset.
+     *
+     * @param  source An input stream to be scanned
+     * @param charsetName The encoding type used to convert bytes from the
+     *        stream into characters to be scanned
+     * @throws IllegalArgumentException if the specified character set
+     *         does not exist
+     */
+    public Scanner(InputStream source, String charsetName) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), toCharset(charsetName)),
+             WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Returns a charset object for the given charset name.
+     * @throws NullPointerException          is csn is null
+     * @throws IllegalArgumentException      if the charset is not supported
+     */
+    private static Charset toCharset(String csn) {
+        Objects.requireNonNull(csn, "charsetName");
+        try {
+            return Charset.forName(csn);
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException e) {
+            // IllegalArgumentException should be thrown
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    private static Readable makeReadable(InputStream source, Charset charset) {
+        return new InputStreamReader(source, charset);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source A file to be scanned
+     * @throws FileNotFoundException if source is not found
+     */
+    public Scanner(File source) throws FileNotFoundException {
+        this((ReadableByteChannel)(new FileInputStream(source).getChannel()));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A file to be scanned
+     * @param charsetName The encoding type used to convert bytes from the file
+     *        into characters to be scanned
+     * @throws FileNotFoundException if source is not found
+     * @throws IllegalArgumentException if the specified encoding is
+     *         not found
+     */
+    public Scanner(File source, String charsetName)
+        throws FileNotFoundException
+    {
+        this(Objects.requireNonNull(source), toDecoder(charsetName));
+    }
+
+    private Scanner(File source, CharsetDecoder dec)
+        throws FileNotFoundException
+    {
+        this(makeReadable((ReadableByteChannel)(new FileInputStream(source).getChannel()), dec));
+    }
+
+    private static CharsetDecoder toDecoder(String charsetName) {
+        // Android-changed: Throw an IAE instead of an NPE.
+        // Objects.requireNonNull(charsetName, "charsetName");
+        if (charsetName == null) {
+            throw new IllegalArgumentException("charsetName == null");
+        }
+        try {
+            return Charset.forName(charsetName).newDecoder();
+        } catch (IllegalCharsetNameException|UnsupportedCharsetException unused) {
+            throw new IllegalArgumentException(charsetName);
+        }
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source,
+                                         CharsetDecoder dec) {
+        return Channels.newReader(source, dec, -1);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     *
+     * @since   1.7
+     */
+    public Scanner(Path source)
+        throws IOException
+    {
+        this(Files.newInputStream(source));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified file. Bytes from the file are converted into
+     * characters using the specified charset.
+     *
+     * @param   source
+     *          the path to the file to be scanned
+     * @param   charsetName
+     *          The encoding type used to convert bytes from the file
+     *          into characters to be scanned
+     * @throws  IOException
+     *          if an I/O error occurs opening source
+     * @throws  IllegalArgumentException
+     *          if the specified encoding is not found
+     * @since   1.7
+     */
+    public Scanner(Path source, String charsetName) throws IOException {
+        this(Objects.requireNonNull(source), toCharset(charsetName));
+    }
+
+    private Scanner(Path source, Charset charset)  throws IOException {
+        this(makeReadable(Files.newInputStream(source), charset));
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified string.
+     *
+     * @param  source A string to scan
+     */
+    public Scanner(String source) {
+        this(new StringReader(source), WHITESPACE_PATTERN);
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the underlying platform's
+     * {@linkplain java.nio.charset.Charset#defaultCharset() default charset}.
+     *
+     * @param  source A channel to scan
+     */
+    public Scanner(ReadableByteChannel source) {
+        this(makeReadable(Objects.requireNonNull(source, "source")),
+             WHITESPACE_PATTERN);
+    }
+
+    private static Readable makeReadable(ReadableByteChannel source) {
+        return makeReadable(source, Charset.defaultCharset().newDecoder());
+    }
+
+    /**
+     * Constructs a new <code>Scanner</code> that produces values scanned
+     * from the specified channel. Bytes from the source are converted into
+     * characters using the specified charset.
+     *
+     * @param  source A channel to scan
+     * @param charsetName The encoding type used to convert bytes from the
+     *        channel into characters to be scanned
+     * @throws IllegalArgumentException if the specified character set
+     *         does not exist
+     */
+    public Scanner(ReadableByteChannel source, String charsetName) {
+        this(makeReadable(Objects.requireNonNull(source, "source"), toDecoder(charsetName)),
+             WHITESPACE_PATTERN);
+    }
+
+    // Private primitives used to support scanning
+
+    private void saveState() {
+        savedScannerPosition = position;
+    }
+
+    private void revertState() {
+        this.position = savedScannerPosition;
+        savedScannerPosition = -1;
+        skipped = false;
+    }
+
+    private boolean revertState(boolean b) {
+        this.position = savedScannerPosition;
+        savedScannerPosition = -1;
+        skipped = false;
+        return b;
+    }
+
+    private void cacheResult() {
+        hasNextResult = matcher.group();
+        hasNextPosition = matcher.end();
+        hasNextPattern = matcher.pattern();
+    }
+
+    private void cacheResult(String result) {
+        hasNextResult = result;
+        hasNextPosition = matcher.end();
+        hasNextPattern = matcher.pattern();
+    }
+
+    // Clears both regular cache and type cache
+    private void clearCaches() {
+        hasNextPattern = null;
+        typeCache = null;
+    }
+
+    // Also clears both the regular cache and the type cache
+    private String getCachedResult() {
+        position = hasNextPosition;
+        hasNextPattern = null;
+        typeCache = null;
+        return hasNextResult;
+    }
+
+    // Also clears both the regular cache and the type cache
+    private void useTypeCache() {
+        if (closed)
+            throw new IllegalStateException("Scanner closed");
+        position = hasNextPosition;
+        hasNextPattern = null;
+        typeCache = null;
+    }
+
+    // Tries to read more input. May block.
+    private void readInput() {
+        if (buf.limit() == buf.capacity())
+            makeSpace();
+
+        // Prepare to receive data
+        int p = buf.position();
+        buf.position(buf.limit());
+        buf.limit(buf.capacity());
+
+        int n = 0;
+        try {
+            n = source.read(buf);
+        } catch (IOException ioe) {
+            lastException = ioe;
+            n = -1;
+        }
+
+        if (n == -1) {
+            sourceClosed = true;
+            needInput = false;
+        }
+
+        if (n > 0)
+            needInput = false;
+
+        // Restore current position and limit for reading
+        buf.limit(buf.position());
+        buf.position(p);
+        // Android-added: reset() the matcher after reading.
+        // The matcher implementation eagerly calls toString() so we'll have
+        // to update its input whenever the buffer limit, position etc. changes.
+        matcher.reset(buf);
+    }
+
+    // After this method is called there will either be an exception
+    // or else there will be space in the buffer
+    private boolean makeSpace() {
+        clearCaches();
+        int offset = savedScannerPosition == -1 ?
+            position : savedScannerPosition;
+        buf.position(offset);
+        // Gain space by compacting buffer
+        if (offset > 0) {
+            buf.compact();
+            translateSavedIndexes(offset);
+            position -= offset;
+            buf.flip();
+            return true;
+        }
+        // Gain space by growing buffer
+        int newSize = buf.capacity() * 2;
+        CharBuffer newBuf = CharBuffer.allocate(newSize);
+        newBuf.put(buf);
+        newBuf.flip();
+        translateSavedIndexes(offset);
+        position -= offset;
+        buf = newBuf;
+        matcher.reset(buf);
+        return true;
+    }
+
+    // When a buffer compaction/reallocation occurs the saved indexes must
+    // be modified appropriately
+    private void translateSavedIndexes(int offset) {
+        if (savedScannerPosition != -1)
+            savedScannerPosition -= offset;
+    }
+
+    // If we are at the end of input then NoSuchElement;
+    // If there is still input left then InputMismatch
+    private void throwFor() {
+        skipped = false;
+        if ((sourceClosed) && (position == buf.limit()))
+            throw new NoSuchElementException();
+        else
+            throw new InputMismatchException();
+    }
+
+    // Returns true if a complete token or partial token is in the buffer.
+    // It is not necessary to find a complete token since a partial token
+    // means that there will be another token with or without more input.
+    private boolean hasTokenInBuffer() {
+        matchValid = false;
+        matcher.usePattern(delimPattern);
+        matcher.region(position, buf.limit());
+
+        // Skip delims first
+        if (matcher.lookingAt())
+            position = matcher.end();
+
+        // If we are sitting at the end, no more tokens in buffer
+        if (position == buf.limit())
+            return false;
+
+        return true;
+    }
+
+    /*
+     * Returns a "complete token" that matches the specified pattern
+     *
+     * A token is complete if surrounded by delims; a partial token
+     * is prefixed by delims but not postfixed by them
+     *
+     * The position is advanced to the end of that complete token
+     *
+     * Pattern == null means accept any token at all
+     *
+     * Triple return:
+     * 1. valid string means it was found
+     * 2. null with needInput=false means we won't ever find it
+     * 3. null with needInput=true means try again after readInput
+     */
+    private String getCompleteTokenInBuffer(Pattern pattern) {
+        matchValid = false;
+
+        // Skip delims first
+        matcher.usePattern(delimPattern);
+        if (!skipped) { // Enforcing only one skip of leading delims
+            matcher.region(position, buf.limit());
+            if (matcher.lookingAt()) {
+                // If more input could extend the delimiters then we must wait
+                // for more input
+                if (matcher.hitEnd() && !sourceClosed) {
+                    needInput = true;
+                    return null;
+                }
+                // The delims were whole and the matcher should skip them
+                skipped = true;
+                position = matcher.end();
+            }
+        }
+
+        // If we are sitting at the end, no more tokens in buffer
+        if (position == buf.limit()) {
+            if (sourceClosed)
+                return null;
+            needInput = true;
+            return null;
+        }
+
+        // Must look for next delims. Simply attempting to match the
+        // pattern at this point may find a match but it might not be
+        // the first longest match because of missing input, or it might
+        // match a partial token instead of the whole thing.
+
+        // Then look for next delims
+        matcher.region(position, buf.limit());
+        boolean foundNextDelim = matcher.find();
+        if (foundNextDelim && (matcher.end() == position)) {
+            // Zero length delimiter match; we should find the next one
+            // using the automatic advance past a zero length match;
+            // Otherwise we have just found the same one we just skipped
+            foundNextDelim = matcher.find();
+        }
+        if (foundNextDelim) {
+            // In the rare case that more input could cause the match
+            // to be lost and there is more input coming we must wait
+            // for more input. Note that hitting the end is okay as long
+            // as the match cannot go away. It is the beginning of the
+            // next delims we want to be sure about, we don't care if
+            // they potentially extend further.
+            if (matcher.requireEnd() && !sourceClosed) {
+                needInput = true;
+                return null;
+            }
+            int tokenEnd = matcher.start();
+            // There is a complete token.
+            if (pattern == null) {
+                // Must continue with match to provide valid MatchResult
+                pattern = FIND_ANY_PATTERN;
+            }
+            //  Attempt to match against the desired pattern
+            matcher.usePattern(pattern);
+            matcher.region(position, tokenEnd);
+            if (matcher.matches()) {
+                String s = matcher.group();
+                position = matcher.end();
+                return s;
+            } else { // Complete token but it does not match
+                return null;
+            }
+        }
+
+        // If we can't find the next delims but no more input is coming,
+        // then we can treat the remainder as a whole token
+        if (sourceClosed) {
+            if (pattern == null) {
+                // Must continue with match to provide valid MatchResult
+                pattern = FIND_ANY_PATTERN;
+            }
+            // Last token; Match the pattern here or throw
+            matcher.usePattern(pattern);
+            matcher.region(position, buf.limit());
+            if (matcher.matches()) {
+                String s = matcher.group();
+                position = matcher.end();
+                return s;
+            }
+            // Last piece does not match
+            return null;
+        }
+
+        // There is a partial token in the buffer; must read more
+        // to complete it
+        needInput = true;
+        return null;
+    }
+
+    // Finds the specified pattern in the buffer up to horizon.
+    // Returns a match for the specified input pattern.
+    private String findPatternInBuffer(Pattern pattern, int horizon) {
+        matchValid = false;
+        matcher.usePattern(pattern);
+        int bufferLimit = buf.limit();
+        int horizonLimit = -1;
+        int searchLimit = bufferLimit;
+        if (horizon > 0) {
+            horizonLimit = position + horizon;
+            if (horizonLimit < bufferLimit)
+                searchLimit = horizonLimit;
+        }
+        matcher.region(position, searchLimit);
+        if (matcher.find()) {
+            if (matcher.hitEnd() && (!sourceClosed)) {
+                // The match may be longer if didn't hit horizon or real end
+                if (searchLimit != horizonLimit) {
+                     // Hit an artificial end; try to extend the match
+                    needInput = true;
+                    return null;
+                }
+                // The match could go away depending on what is next
+                if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
+                    // Rare case: we hit the end of input and it happens
+                    // that it is at the horizon and the end of input is
+                    // required for the match.
+                    needInput = true;
+                    return null;
+                }
+            }
+            // Did not hit end, or hit real end, or hit horizon
+            position = matcher.end();
+            return matcher.group();
+        }
+
+        if (sourceClosed)
+            return null;
+
+        // If there is no specified horizon, or if we have not searched
+        // to the specified horizon yet, get more input
+        if ((horizon == 0) || (searchLimit != horizonLimit))
+            needInput = true;
+        return null;
+    }
+
+    // Returns a match for the specified input pattern anchored at
+    // the current position
+    private String matchPatternInBuffer(Pattern pattern) {
+        matchValid = false;
+        matcher.usePattern(pattern);
+        matcher.region(position, buf.limit());
+        if (matcher.lookingAt()) {
+            if (matcher.hitEnd() && (!sourceClosed)) {
+                // Get more input and try again
+                needInput = true;
+                return null;
+            }
+            position = matcher.end();
+            return matcher.group();
+        }
+
+        if (sourceClosed)
+            return null;
+
+        // Read more to find pattern
+        needInput = true;
+        return null;
+    }
+
+    // Throws if the scanner is closed
+    private void ensureOpen() {
+        if (closed)
+            throw new IllegalStateException("Scanner closed");
+    }
+
+    // Public methods
+
+    /**
+     * Closes this scanner.
+     *
+     * <p> If this scanner has not yet been closed then if its underlying
+     * {@linkplain java.lang.Readable readable} also implements the {@link
+     * java.io.Closeable} interface then the readable's <tt>close</tt> method
+     * will be invoked.  If this scanner is already closed then invoking this
+     * method will have no effect.
+     *
+     * <p>Attempting to perform search operations after a scanner has
+     * been closed will result in an {@link IllegalStateException}.
+     *
+     */
+    public void close() {
+        if (closed)
+            return;
+        if (source instanceof Closeable) {
+            try {
+                ((Closeable)source).close();
+            } catch (IOException ioe) {
+                lastException = ioe;
+            }
+        }
+        sourceClosed = true;
+        source = null;
+        closed = true;
+    }
+
+    /**
+     * Returns the <code>IOException</code> last thrown by this
+     * <code>Scanner</code>'s underlying <code>Readable</code>. This method
+     * returns <code>null</code> if no such exception exists.
+     *
+     * @return the last exception thrown by this scanner's readable
+     */
+    public IOException ioException() {
+        return lastException;
+    }
+
+    /**
+     * Returns the <code>Pattern</code> this <code>Scanner</code> is currently
+     * using to match delimiters.
+     *
+     * @return this scanner's delimiting pattern.
+     */
+    public Pattern delimiter() {
+        return delimPattern;
+    }
+
+    /**
+     * Sets this scanner's delimiting pattern to the specified pattern.
+     *
+     * @param pattern A delimiting pattern
+     * @return this scanner
+     */
+    public Scanner useDelimiter(Pattern pattern) {
+        delimPattern = pattern;
+        return this;
+    }
+
+    /**
+     * Sets this scanner's delimiting pattern to a pattern constructed from
+     * the specified <code>String</code>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>useDelimiter(pattern)</tt> behaves in exactly the same way as the
+     * invocation <tt>useDelimiter(Pattern.compile(pattern))</tt>.
+     *
+     * <p> Invoking the {@link #reset} method will set the scanner's delimiter
+     * to the <a href= "#default-delimiter">default</a>.
+     *
+     * @param pattern A string specifying a delimiting pattern
+     * @return this scanner
+     */
+    public Scanner useDelimiter(String pattern) {
+        delimPattern = patternCache.forName(pattern);
+        return this;
+    }
+
+    /**
+     * Returns this scanner's locale.
+     *
+     * <p>A scanner's locale affects many elements of its default
+     * primitive matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * @return this scanner's locale
+     */
+    public Locale locale() {
+        return this.locale;
+    }
+
+    /**
+     * Sets this scanner's locale to the specified locale.
+     *
+     * <p>A scanner's locale affects many elements of its default
+     * primitive matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * <p>Invoking the {@link #reset} method will set the scanner's locale to
+     * the <a href= "#initial-locale">initial locale</a>.
+     *
+     * @param locale A string specifying the locale to use
+     * @return this scanner
+     */
+    public Scanner useLocale(Locale locale) {
+        if (locale.equals(this.locale))
+            return this;
+
+        this.locale = locale;
+        DecimalFormat df =
+            (DecimalFormat)NumberFormat.getNumberInstance(locale);
+        DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale);
+
+        // These must be literalized to avoid collision with regex
+        // metacharacters such as dot or parenthesis
+        groupSeparator =   "\\" + dfs.getGroupingSeparator();
+        decimalSeparator = "\\" + dfs.getDecimalSeparator();
+
+        // Quoting the nonzero length locale-specific things
+        // to avoid potential conflict with metacharacters
+        nanString = "\\Q" + dfs.getNaN() + "\\E";
+        infinityString = "\\Q" + dfs.getInfinity() + "\\E";
+        positivePrefix = df.getPositivePrefix();
+        if (positivePrefix.length() > 0)
+            positivePrefix = "\\Q" + positivePrefix + "\\E";
+        negativePrefix = df.getNegativePrefix();
+        if (negativePrefix.length() > 0)
+            negativePrefix = "\\Q" + negativePrefix + "\\E";
+        positiveSuffix = df.getPositiveSuffix();
+        if (positiveSuffix.length() > 0)
+            positiveSuffix = "\\Q" + positiveSuffix + "\\E";
+        negativeSuffix = df.getNegativeSuffix();
+        if (negativeSuffix.length() > 0)
+            negativeSuffix = "\\Q" + negativeSuffix + "\\E";
+
+        // Force rebuilding and recompilation of locale dependent
+        // primitive patterns
+        integerPattern = null;
+        floatPattern = null;
+
+        return this;
+    }
+
+    /**
+     * Returns this scanner's default radix.
+     *
+     * <p>A scanner's radix affects elements of its default
+     * number matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * @return the default radix of this scanner
+     */
+    public int radix() {
+        return this.defaultRadix;
+    }
+
+    /**
+     * Sets this scanner's default radix to the specified radix.
+     *
+     * <p>A scanner's radix affects elements of its default
+     * number matching regular expressions; see
+     * <a href= "#localized-numbers">localized numbers</a> above.
+     *
+     * <p>If the radix is less than <code>Character.MIN_RADIX</code>
+     * or greater than <code>Character.MAX_RADIX</code>, then an
+     * <code>IllegalArgumentException</code> is thrown.
+     *
+     * <p>Invoking the {@link #reset} method will set the scanner's radix to
+     * <code>10</code>.
+     *
+     * @param radix The radix to use when scanning numbers
+     * @return this scanner
+     * @throws IllegalArgumentException if radix is out of range
+     */
+    public Scanner useRadix(int radix) {
+        if ((radix < Character.MIN_RADIX) || (radix > Character.MAX_RADIX))
+            throw new IllegalArgumentException("radix:"+radix);
+
+        if (this.defaultRadix == radix)
+            return this;
+        this.defaultRadix = radix;
+        // Force rebuilding and recompilation of radix dependent patterns
+        integerPattern = null;
+        return this;
+    }
+
+    // The next operation should occur in the specified radix but
+    // the default is left untouched.
+    private void setRadix(int radix) {
+        // BEGIN Android-added: Complain loudly if a bogus radix is being set.
+        if (radix > Character.MAX_RADIX) {
+            throw new IllegalArgumentException("radix == " + radix);
+        }
+        // END Android-added: Complain loudly if a bogus radix is being set.
+
+        if (this.radix != radix) {
+            // Force rebuilding and recompilation of radix dependent patterns
+            integerPattern = null;
+            this.radix = radix;
+        }
+    }
+
+    /**
+     * Returns the match result of the last scanning operation performed
+     * by this scanner. This method throws <code>IllegalStateException</code>
+     * if no match has been performed, or if the last match was
+     * not successful.
+     *
+     * <p>The various <code>next</code>methods of <code>Scanner</code>
+     * make a match result available if they complete without throwing an
+     * exception. For instance, after an invocation of the {@link #nextInt}
+     * method that returned an int, this method returns a
+     * <code>MatchResult</code> for the search of the
+     * <a href="#Integer-regex"><i>Integer</i></a> regular expression
+     * defined above. Similarly the {@link #findInLine},
+     * {@link #findWithinHorizon}, and {@link #skip} methods will make a
+     * match available if they succeed.
+     *
+     * @return a match result for the last match operation
+     * @throws IllegalStateException  If no match result is available
+     */
+    public MatchResult match() {
+        if (!matchValid)
+            throw new IllegalStateException("No match result available");
+        return matcher.toMatchResult();
+    }
+
+    /**
+     * <p>Returns the string representation of this <code>Scanner</code>. The
+     * string representation of a <code>Scanner</code> contains information
+     * that may be useful for debugging. The exact format is unspecified.
+     *
+     * @return  The string representation of this scanner
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("java.util.Scanner");
+        sb.append("[delimiters=" + delimPattern + "]");
+        sb.append("[position=" + position + "]");
+        sb.append("[match valid=" + matchValid + "]");
+        sb.append("[need input=" + needInput + "]");
+        sb.append("[source closed=" + sourceClosed + "]");
+        sb.append("[skipped=" + skipped + "]");
+        sb.append("[group separator=" + groupSeparator + "]");
+        sb.append("[decimal separator=" + decimalSeparator + "]");
+        sb.append("[positive prefix=" + positivePrefix + "]");
+        sb.append("[negative prefix=" + negativePrefix + "]");
+        sb.append("[positive suffix=" + positiveSuffix + "]");
+        sb.append("[negative suffix=" + negativeSuffix + "]");
+        sb.append("[NaN string=" + nanString + "]");
+        sb.append("[infinity string=" + infinityString + "]");
+        return sb.toString();
+    }
+
+    /**
+     * Returns true if this scanner has another token in its input.
+     * This method may block while waiting for input to scan.
+     * The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner has another token
+     * @throws IllegalStateException if this scanner is closed
+     * @see java.util.Iterator
+     */
+    public boolean hasNext() {
+        ensureOpen();
+        saveState();
+        while (!sourceClosed) {
+            if (hasTokenInBuffer())
+                return revertState(true);
+            readInput();
+        }
+        boolean result = hasTokenInBuffer();
+        return revertState(result);
+    }
+
+    /**
+     * Finds and returns the next complete token from this scanner.
+     * A complete token is preceded and followed by input that matches
+     * the delimiter pattern. This method may block while waiting for input
+     * to scan, even if a previous invocation of {@link #hasNext} returned
+     * <code>true</code>.
+     *
+     * @return the next token
+     * @throws NoSuchElementException if no more tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     * @see java.util.Iterator
+     */
+    public String next() {
+        ensureOpen();
+        clearCaches();
+
+        while (true) {
+            String token = getCompleteTokenInBuffer(null);
+            if (token != null) {
+                matchValid = true;
+                skipped = false;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                throwFor();
+        }
+    }
+
+    /**
+     * The remove operation is not supported by this implementation of
+     * <code>Iterator</code>.
+     *
+     * @throws UnsupportedOperationException if this method is invoked.
+     * @see java.util.Iterator
+     */
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns true if the next token matches the pattern constructed from the
+     * specified string. The scanner does not advance past any input.
+     *
+     * <p> An invocation of this method of the form <tt>hasNext(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>hasNext(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to scan
+     * @return true if and only if this scanner has another token matching
+     *         the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNext(String pattern)  {
+        return hasNext(patternCache.forName(pattern));
+    }
+
+    /**
+     * Returns the next token if it matches the pattern constructed from the
+     * specified string.  If the match is successful, the scanner advances
+     * past the input that matched the pattern.
+     *
+     * <p> An invocation of this method of the form <tt>next(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>next(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to scan
+     * @return the next token
+     * @throws NoSuchElementException if no such tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String next(String pattern)  {
+        return next(patternCache.forName(pattern));
+    }
+
+    /**
+     * Returns true if the next complete token matches the specified pattern.
+     * A complete token is prefixed and postfixed by input that matches
+     * the delimiter pattern. This method may block while waiting for input.
+     * The scanner does not advance past any input.
+     *
+     * @param pattern the pattern to scan for
+     * @return true if and only if this scanner has another token matching
+     *         the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNext(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        hasNextPattern = null;
+        saveState();
+
+        while (true) {
+            if (getCompleteTokenInBuffer(pattern) != null) {
+                matchValid = true;
+                cacheResult();
+                return revertState(true);
+            }
+            if (needInput)
+                readInput();
+            else
+                return revertState(false);
+        }
+    }
+
+    /**
+     * Returns the next token if it matches the specified pattern. This
+     * method may block while waiting for input to scan, even if a previous
+     * invocation of {@link #hasNext(Pattern)} returned <code>true</code>.
+     * If the match is successful, the scanner advances past the input that
+     * matched the pattern.
+     *
+     * @param pattern the pattern to scan for
+     * @return the next token
+     * @throws NoSuchElementException if no more tokens are available
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String next(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+
+        // Did we already find this pattern?
+        if (hasNextPattern == pattern)
+            return getCachedResult();
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = getCompleteTokenInBuffer(pattern);
+            if (token != null) {
+                matchValid = true;
+                skipped = false;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                throwFor();
+        }
+    }
+
+    /**
+     * Returns true if there is another line in the input of this scanner.
+     * This method may block while waiting for input. The scanner does not
+     * advance past any input.
+     *
+     * @return true if and only if this scanner has another line of input
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLine() {
+        saveState();
+
+        String result = findWithinHorizon(linePattern(), 0);
+        if (result != null) {
+            MatchResult mr = this.match();
+            String lineSep = mr.group(1);
+            if (lineSep != null) {
+                result = result.substring(0, result.length() -
+                                          lineSep.length());
+                cacheResult(result);
+
+            } else {
+                cacheResult();
+            }
+        }
+        revertState();
+        return (result != null);
+    }
+
+    /**
+     * Advances this scanner past the current line and returns the input
+     * that was skipped.
+     *
+     * This method returns the rest of the current line, excluding any line
+     * separator at the end. The position is set to the beginning of the next
+     * line.
+     *
+     * <p>Since this method continues to search through the input looking
+     * for a line separator, it may buffer all of the input searching for
+     * the line to skip if no line separators are present.
+     *
+     * @return the line that was skipped
+     * @throws NoSuchElementException if no line was found
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String nextLine() {
+        if (hasNextPattern == linePattern())
+            return getCachedResult();
+        clearCaches();
+
+        String result = findWithinHorizon(linePattern, 0);
+        if (result == null)
+            throw new NoSuchElementException("No line found");
+        MatchResult mr = this.match();
+        String lineSep = mr.group(1);
+        if (lineSep != null)
+            result = result.substring(0, result.length() - lineSep.length());
+        if (result == null)
+            throw new NoSuchElementException();
+        else
+            return result;
+    }
+
+    // Public methods that ignore delimiters
+
+    /**
+     * Attempts to find the next occurrence of a pattern constructed from the
+     * specified string, ignoring delimiters.
+     *
+     * <p>An invocation of this method of the form <tt>findInLine(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>findInLine(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to search for
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String findInLine(String pattern) {
+        return findInLine(patternCache.forName(pattern));
+    }
+
+    /**
+     * Attempts to find the next occurrence of the specified pattern ignoring
+     * delimiters. If the pattern is found before the next line separator, the
+     * scanner advances past the input that matched and returns the string that
+     * matched the pattern.
+     * If no such pattern is detected in the input up to the next line
+     * separator, then <code>null</code> is returned and the scanner's
+     * position is unchanged. This method may block waiting for input that
+     * matches the pattern.
+     *
+     * <p>Since this method continues to search through the input looking
+     * for the specified pattern, it may buffer all of the input searching for
+     * the desired token if no line separators are present.
+     *
+     * @param pattern the pattern to scan for
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public String findInLine(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        clearCaches();
+        // Expand buffer to include the next newline or end of input
+        int endPosition = 0;
+        saveState();
+        while (true) {
+            String token = findPatternInBuffer(separatorPattern(), 0);
+            if (token != null) {
+                endPosition = matcher.start();
+                break; // up to next newline
+            }
+            if (needInput) {
+                readInput();
+            } else {
+                endPosition = buf.limit();
+                break; // up to end of input
+            }
+        }
+        revertState();
+        int horizonForLine = endPosition - position;
+        // If there is nothing between the current pos and the next
+        // newline simply return null, invoking findWithinHorizon
+        // with "horizon=0" will scan beyond the line bound.
+        if (horizonForLine == 0)
+            return null;
+        // Search for the pattern
+        return findWithinHorizon(pattern, horizonForLine);
+    }
+
+    /**
+     * Attempts to find the next occurrence of a pattern constructed from the
+     * specified string, ignoring delimiters.
+     *
+     * <p>An invocation of this method of the form
+     * <tt>findWithinHorizon(pattern)</tt> behaves in exactly the same way as
+     * the invocation
+     * <tt>findWithinHorizon(Pattern.compile(pattern, horizon))</tt>.
+     *
+     * @param pattern a string specifying the pattern to search for
+     * @param horizon the search horizon
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if horizon is negative
+     */
+    public String findWithinHorizon(String pattern, int horizon) {
+        return findWithinHorizon(patternCache.forName(pattern), horizon);
+    }
+
+    /**
+     * Attempts to find the next occurrence of the specified pattern.
+     *
+     * <p>This method searches through the input up to the specified
+     * search horizon, ignoring delimiters. If the pattern is found the
+     * scanner advances past the input that matched and returns the string
+     * that matched the pattern. If no such pattern is detected then the
+     * null is returned and the scanner's position remains unchanged. This
+     * method may block waiting for input that matches the pattern.
+     *
+     * <p>A scanner will never search more than <code>horizon</code> code
+     * points beyond its current position. Note that a match may be clipped
+     * by the horizon; that is, an arbitrary match result may have been
+     * different if the horizon had been larger. The scanner treats the
+     * horizon as a transparent, non-anchoring bound (see {@link
+     * Matcher#useTransparentBounds} and {@link Matcher#useAnchoringBounds}).
+     *
+     * <p>If horizon is <code>0</code>, then the horizon is ignored and
+     * this method continues to search through the input looking for the
+     * specified pattern without bound. In this case it may buffer all of
+     * the input searching for the pattern.
+     *
+     * <p>If horizon is negative, then an IllegalArgumentException is
+     * thrown.
+     *
+     * @param pattern the pattern to scan for
+     * @param horizon the search horizon
+     * @return the text that matched the specified pattern
+     * @throws IllegalStateException if this scanner is closed
+     * @throws IllegalArgumentException if horizon is negative
+     */
+    public String findWithinHorizon(Pattern pattern, int horizon) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        if (horizon < 0)
+            throw new IllegalArgumentException("horizon < 0");
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = findPatternInBuffer(pattern, horizon);
+            if (token != null) {
+                matchValid = true;
+                return token;
+            }
+            if (needInput)
+                readInput();
+            else
+                break; // up to end of input
+        }
+        return null;
+    }
+
+    /**
+     * Skips input that matches the specified pattern, ignoring delimiters.
+     * This method will skip input if an anchored match of the specified
+     * pattern succeeds.
+     *
+     * <p>If a match to the specified pattern is not found at the
+     * current position, then no input is skipped and a
+     * <tt>NoSuchElementException</tt> is thrown.
+     *
+     * <p>Since this method seeks to match the specified pattern starting at
+     * the scanner's current position, patterns that can match a lot of
+     * input (".*", for example) may cause the scanner to buffer a large
+     * amount of input.
+     *
+     * <p>Note that it is possible to skip something without risking a
+     * <code>NoSuchElementException</code> by using a pattern that can
+     * match nothing, e.g., <code>sc.skip("[ \t]*")</code>.
+     *
+     * @param pattern a string specifying the pattern to skip over
+     * @return this scanner
+     * @throws NoSuchElementException if the specified pattern is not found
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public Scanner skip(Pattern pattern) {
+        ensureOpen();
+        if (pattern == null)
+            throw new NullPointerException();
+        clearCaches();
+
+        // Search for the pattern
+        while (true) {
+            String token = matchPatternInBuffer(pattern);
+            if (token != null) {
+                matchValid = true;
+                position = matcher.end();
+                return this;
+            }
+            if (needInput)
+                readInput();
+            else
+                throw new NoSuchElementException();
+        }
+    }
+
+    /**
+     * Skips input that matches a pattern constructed from the specified
+     * string.
+     *
+     * <p> An invocation of this method of the form <tt>skip(pattern)</tt>
+     * behaves in exactly the same way as the invocation
+     * <tt>skip(Pattern.compile(pattern))</tt>.
+     *
+     * @param pattern a string specifying the pattern to skip over
+     * @return this scanner
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public Scanner skip(String pattern) {
+        return skip(patternCache.forName(pattern));
+    }
+
+    // Convenience methods for scanning primitives
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a boolean value using a case insensitive pattern
+     * created from the string "true|false".  The scanner does not
+     * advance past the input that matched.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         boolean value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBoolean()  {
+        return hasNext(boolPattern());
+    }
+
+    /**
+     * Scans the next token of the input into a boolean value and returns
+     * that value. This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid boolean value.
+     * If the match is successful, the scanner advances past the input that
+     * matched.
+     *
+     * @return the boolean scanned from the input
+     * @throws InputMismatchException if the next token is not a valid boolean
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean nextBoolean()  {
+        clearCaches();
+        return Boolean.parseBoolean(next(boolPattern()));
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a byte value in the default radix using the
+     * {@link #nextByte} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         byte value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextByte() {
+        return hasNextByte(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a byte value in the specified radix using the
+     * {@link #nextByte} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as a byte value
+     * @return true if and only if this scanner's next token is a valid
+     *         byte value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextByte(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Byte.parseByte(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>byte</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextByte()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextByte(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>byte</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public byte nextByte() {
+         return nextByte(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>byte</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid byte value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>byte</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Byte#parseByte(String, int) Byte.parseByte} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as a byte value
+     * @return the <tt>byte</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public byte nextByte(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Byte)
+            && this.radix == radix) {
+            byte val = ((Byte)typeCache).byteValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next byte
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Byte.parseByte(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a short value in the default radix using the
+     * {@link #nextShort} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         short value in the default radix
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextShort() {
+        return hasNextShort(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a short value in the specified radix using the
+     * {@link #nextShort} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as a short value
+     * @return true if and only if this scanner's next token is a valid
+     *         short value in the specified radix
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextShort(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Short.parseShort(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>short</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextShort()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextShort(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>short</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public short nextShort() {
+        return nextShort(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>short</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid short value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>short</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Short#parseShort(String, int) Short.parseShort} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as a short value
+     * @return the <tt>short</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public short nextShort(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Short)
+            && this.radix == radix) {
+            short val = ((Short)typeCache).shortValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next short
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Short.parseShort(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as an int value in the default radix using the
+     * {@link #nextInt} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         int value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextInt() {
+        return hasNextInt(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as an int value in the specified radix using the
+     * {@link #nextInt} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return true if and only if this scanner's next token is a valid
+     *         int value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextInt(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Integer.parseInt(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * The integer token must be stripped of prefixes, group separators,
+     * and suffixes, non ascii digits must be converted into ascii digits
+     * before parse will accept it.
+     */
+    private String processIntegerToken(String token) {
+        String result = token.replaceAll(""+groupSeparator, "");
+        boolean isNegative = false;
+        int preLen = negativePrefix.length();
+        if ((preLen > 0) && result.startsWith(negativePrefix)) {
+            isNegative = true;
+            result = result.substring(preLen);
+        }
+        int sufLen = negativeSuffix.length();
+        if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
+            isNegative = true;
+            result = result.substring(result.length() - sufLen,
+                                      result.length());
+        }
+        if (isNegative)
+            result = "-" + result;
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as an <tt>int</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextInt()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextInt(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>int</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public int nextInt() {
+        return nextInt(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as an <tt>int</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid int value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into an <tt>int</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Integer#parseInt(String, int) Integer.parseInt} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return the <tt>int</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public int nextInt(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Integer)
+            && this.radix == radix) {
+            int val = ((Integer)typeCache).intValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next int
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Integer.parseInt(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a long value in the default radix using the
+     * {@link #nextLong} method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         long value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLong() {
+        return hasNextLong(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a long value in the specified radix using the
+     * {@link #nextLong} method. The scanner does not advance past any input.
+     *
+     * @param radix the radix used to interpret the token as a long value
+     * @return true if and only if this scanner's next token is a valid
+     *         long value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextLong(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = Long.parseLong(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>long</tt>.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextLong()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextLong(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>long</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public long nextLong() {
+        return nextLong(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>long</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid long value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>long</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Long#parseLong(String, int) Long.parseLong} with the
+     * specified radix.
+     *
+     * @param radix the radix used to interpret the token as an int value
+     * @return the <tt>long</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public long nextLong(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Long)
+            && this.radix == radix) {
+            long val = ((Long)typeCache).longValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return Long.parseLong(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * The float token must be stripped of prefixes, group separators,
+     * and suffixes, non ascii digits must be converted into ascii digits
+     * before parseFloat will accept it.
+     *
+     * If there are non-ascii digits in the token these digits must
+     * be processed before the token is passed to parseFloat.
+     */
+    private String processFloatToken(String token) {
+        String result = token.replaceAll(groupSeparator, "");
+        if (!decimalSeparator.equals("\\."))
+            result = result.replaceAll(decimalSeparator, ".");
+        boolean isNegative = false;
+        int preLen = negativePrefix.length();
+        if ((preLen > 0) && result.startsWith(negativePrefix)) {
+            isNegative = true;
+            result = result.substring(preLen);
+        }
+        int sufLen = negativeSuffix.length();
+        if ((sufLen > 0) && result.endsWith(negativeSuffix)) {
+            isNegative = true;
+            result = result.substring(result.length() - sufLen,
+                                      result.length());
+        }
+        if (result.equals(nanString))
+            result = "NaN";
+        if (result.equals(infinityString))
+            result = "Infinity";
+        // BEGIN Android-added: Match the infinity symbol.
+        if (result.equals("\u221E"))
+            result = "Infinity";
+        // END Android-added: Match the infinity symbol.
+        if (isNegative)
+            result = "-" + result;
+
+        // Translate non-ASCII digits
+        Matcher m = NON_ASCII_DIGIT.matcher(result);
+        if (m.find()) {
+            StringBuilder inASCII = new StringBuilder();
+            for (int i=0; i<result.length(); i++) {
+                char nextChar = result.charAt(i);
+                if (Character.isDigit(nextChar)) {
+                    int d = Character.digit(nextChar, 10);
+                    if (d != -1)
+                        inASCII.append(d);
+                    else
+                        inASCII.append(nextChar);
+                } else {
+                    inASCII.append(nextChar);
+                }
+            }
+            result = inASCII.toString();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a float value using the {@link #nextFloat}
+     * method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         float value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextFloat() {
+        setRadix(10);
+        boolean result = hasNext(floatPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = Float.valueOf(Float.parseFloat(s));
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>float</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid float value as
+     * described below. If the translation is successful, the scanner advances
+     * past the input that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Float-regex"><i>Float</i></a> regular expression defined above
+     * then the token is converted into a <tt>float</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Float#parseFloat Float.parseFloat}. If the token matches
+     * the localized NaN or infinity strings, then either "Nan" or "Infinity"
+     * is passed to {@link Float#parseFloat(String) Float.parseFloat} as
+     * appropriate.
+     *
+     * @return the <tt>float</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Float</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public float nextFloat() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Float)) {
+            float val = ((Float)typeCache).floatValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        try {
+            return Float.parseFloat(processFloatToken(next(floatPattern())));
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a double value using the {@link #nextDouble}
+     * method. The scanner does not advance past any input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         double value
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextDouble() {
+        setRadix(10);
+        boolean result = hasNext(floatPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = Double.valueOf(Double.parseDouble(s));
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a <tt>double</tt>.
+     * This method will throw <code>InputMismatchException</code>
+     * if the next token cannot be translated into a valid double value.
+     * If the translation is successful, the scanner advances past the input
+     * that matched.
+     *
+     * <p> If the next token matches the <a
+     * href="#Float-regex"><i>Float</i></a> regular expression defined above
+     * then the token is converted into a <tt>double</tt> value as if by
+     * removing all locale specific prefixes, group separators, and locale
+     * specific suffixes, then mapping non-ASCII digits into ASCII
+     * digits via {@link Character#digit Character.digit}, prepending a
+     * negative sign (-) if the locale specific negative prefixes and suffixes
+     * were present, and passing the resulting string to
+     * {@link Double#parseDouble Double.parseDouble}. If the token matches
+     * the localized NaN or infinity strings, then either "Nan" or "Infinity"
+     * is passed to {@link Double#parseDouble(String) Double.parseDouble} as
+     * appropriate.
+     *
+     * @return the <tt>double</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Float</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public double nextDouble() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof Double)) {
+            double val = ((Double)typeCache).doubleValue();
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        // Search for next float
+        try {
+            return Double.parseDouble(processFloatToken(next(floatPattern())));
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    // Convenience methods for scanning multi precision numbers
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a <code>BigInteger</code> in the default radix using the
+     * {@link #nextBigInteger} method. The scanner does not advance past any
+     * input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         <code>BigInteger</code>
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigInteger() {
+        return hasNextBigInteger(defaultRadix);
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a <code>BigInteger</code> in the specified radix using
+     * the {@link #nextBigInteger} method. The scanner does not advance past
+     * any input.
+     *
+     * @param radix the radix used to interpret the token as an integer
+     * @return true if and only if this scanner's next token is a valid
+     *         <code>BigInteger</code>
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigInteger(int radix) {
+        setRadix(radix);
+        boolean result = hasNext(integerPattern());
+        if (result) { // Cache it
+            try {
+                String s = (matcher.group(SIMPLE_GROUP_INDEX) == null) ?
+                    processIntegerToken(hasNextResult) :
+                    hasNextResult;
+                typeCache = new BigInteger(s, radix);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigInteger
+     * BigInteger}.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>nextBigInteger()</tt> behaves in exactly the same way as the
+     * invocation <tt>nextBigInteger(radix)</tt>, where <code>radix</code>
+     * is the default radix of this scanner.
+     *
+     * @return the <tt>BigInteger</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigInteger nextBigInteger() {
+        return nextBigInteger(defaultRadix);
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigInteger
+     * BigInteger}.
+     *
+     * <p> If the next token matches the <a
+     * href="#Integer-regex"><i>Integer</i></a> regular expression defined
+     * above then the token is converted into a <tt>BigInteger</tt> value as if
+     * by removing all group separators, mapping non-ASCII digits into ASCII
+     * digits via the {@link Character#digit Character.digit}, and passing the
+     * resulting string to the {@link
+     * java.math.BigInteger#BigInteger(java.lang.String)
+     * BigInteger(String, int)} constructor with the specified radix.
+     *
+     * @param radix the radix used to interpret the token
+     * @return the <tt>BigInteger</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Integer</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigInteger nextBigInteger(int radix) {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof BigInteger)
+            && this.radix == radix) {
+            BigInteger val = (BigInteger)typeCache;
+            useTypeCache();
+            return val;
+        }
+        setRadix(radix);
+        clearCaches();
+        // Search for next int
+        try {
+            String s = next(integerPattern());
+            if (matcher.group(SIMPLE_GROUP_INDEX) == null)
+                s = processIntegerToken(s);
+            return new BigInteger(s, radix);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Returns true if the next token in this scanner's input can be
+     * interpreted as a <code>BigDecimal</code> using the
+     * {@link #nextBigDecimal} method. The scanner does not advance past any
+     * input.
+     *
+     * @return true if and only if this scanner's next token is a valid
+     *         <code>BigDecimal</code>
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public boolean hasNextBigDecimal() {
+        setRadix(10);
+        boolean result = hasNext(decimalPattern());
+        if (result) { // Cache it
+            try {
+                String s = processFloatToken(hasNextResult);
+                typeCache = new BigDecimal(s);
+            } catch (NumberFormatException nfe) {
+                result = false;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Scans the next token of the input as a {@link java.math.BigDecimal
+     * BigDecimal}.
+     *
+     * <p> If the next token matches the <a
+     * href="#Decimal-regex"><i>Decimal</i></a> regular expression defined
+     * above then the token is converted into a <tt>BigDecimal</tt> value as if
+     * by removing all group separators, mapping non-ASCII digits into ASCII
+     * digits via the {@link Character#digit Character.digit}, and passing the
+     * resulting string to the {@link
+     * java.math.BigDecimal#BigDecimal(java.lang.String) BigDecimal(String)}
+     * constructor.
+     *
+     * @return the <tt>BigDecimal</tt> scanned from the input
+     * @throws InputMismatchException
+     *         if the next token does not match the <i>Decimal</i>
+     *         regular expression, or is out of range
+     * @throws NoSuchElementException if the input is exhausted
+     * @throws IllegalStateException if this scanner is closed
+     */
+    public BigDecimal nextBigDecimal() {
+        // Check cached result
+        if ((typeCache != null) && (typeCache instanceof BigDecimal)) {
+            BigDecimal val = (BigDecimal)typeCache;
+            useTypeCache();
+            return val;
+        }
+        setRadix(10);
+        clearCaches();
+        // Search for next float
+        try {
+            String s = processFloatToken(next(decimalPattern()));
+            return new BigDecimal(s);
+        } catch (NumberFormatException nfe) {
+            position = matcher.start(); // don't skip bad token
+            throw new InputMismatchException(nfe.getMessage());
+        }
+    }
+
+    /**
+     * Resets this scanner.
+     *
+     * <p> Resetting a scanner discards all of its explicit state
+     * information which may have been changed by invocations of {@link
+     * #useDelimiter}, {@link #useLocale}, or {@link #useRadix}.
+     *
+     * <p> An invocation of this method of the form
+     * <tt>scanner.reset()</tt> behaves in exactly the same way as the
+     * invocation
+     *
+     * <blockquote><pre>{@code
+     *   scanner.useDelimiter("\\p{javaWhitespace}+")
+     *          .useLocale(Locale.getDefault(Locale.Category.FORMAT))
+     *          .useRadix(10);
+     * }</pre></blockquote>
+     *
+     * @return this scanner
+     *
+     * @since 1.6
+     */
+    public Scanner reset() {
+        delimPattern = WHITESPACE_PATTERN;
+        useLocale(Locale.getDefault(Locale.Category.FORMAT));
+        useRadix(10);
+        clearCaches();
+        return this;
+    }
+}
diff --git a/java/util/ServiceConfigurationError.java b/java/util/ServiceConfigurationError.java
new file mode 100644
index 0000000..e0335f6
--- /dev/null
+++ b/java/util/ServiceConfigurationError.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+
+/**
+ * Error thrown when something goes wrong while loading a service provider.
+ *
+ * <p> This error will be thrown in the following situations:
+ *
+ * <ul>
+ *
+ *   <li> The format of a provider-configuration file violates the <a
+ *   href="ServiceLoader.html#format">specification</a>; </li>
+ *
+ *   <li> An {@link java.io.IOException IOException} occurs while reading a
+ *   provider-configuration file; </li>
+ *
+ *   <li> A concrete provider class named in a provider-configuration file
+ *   cannot be found; </li>
+ *
+ *   <li> A concrete provider class is not a subclass of the service class;
+ *   </li>
+ *
+ *   <li> A concrete provider class cannot be instantiated; or
+ *
+ *   <li> Some other kind of error occurs. </li>
+ *
+ * </ul>
+ *
+ *
+ * @author Mark Reinhold
+ * @since 1.6
+ */
+
+public class ServiceConfigurationError
+    extends Error
+{
+
+    private static final long serialVersionUID = 74132770414881L;
+
+    /**
+     * Constructs a new instance with the specified message.
+     *
+     * @param  msg  The message, or <tt>null</tt> if there is no message
+     *
+     */
+    public ServiceConfigurationError(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Constructs a new instance with the specified message and cause.
+     *
+     * @param  msg  The message, or <tt>null</tt> if there is no message
+     *
+     * @param  cause  The cause, or <tt>null</tt> if the cause is nonexistent
+     *                or unknown
+     */
+    public ServiceConfigurationError(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
+}
diff --git a/java/util/ServiceLoader.java b/java/util/ServiceLoader.java
new file mode 100644
index 0000000..44582e7
--- /dev/null
+++ b/java/util/ServiceLoader.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+
+/**
+ * A simple service-provider loading facility.
+ *
+ * <p> A <i>service</i> is a well-known set of interfaces and (usually
+ * abstract) classes.  A <i>service provider</i> is a specific implementation
+ * of a service.  The classes in a provider typically implement the interfaces
+ * and subclass the classes defined in the service itself.  Service providers
+ * can be installed in an implementation of the Java platform in the form of
+ * extensions, that is, jar files placed into any of the usual extension
+ * directories.  Providers can also be made available by adding them to the
+ * application's class path or by some other platform-specific means.
+ *
+ * <p> For the purpose of loading, a service is represented by a single type,
+ * that is, a single interface or abstract class.  (A concrete class can be
+ * used, but this is not recommended.)  A provider of a given service contains
+ * one or more concrete classes that extend this <i>service type</i> with data
+ * and code specific to the provider.  The <i>provider class</i> is typically
+ * not the entire provider itself but rather a proxy which contains enough
+ * information to decide whether the provider is able to satisfy a particular
+ * request together with code that can create the actual provider on demand.
+ * The details of provider classes tend to be highly service-specific; no
+ * single class or interface could possibly unify them, so no such type is
+ * defined here.  The only requirement enforced by this facility is that
+ * provider classes must have a zero-argument constructor so that they can be
+ * instantiated during loading.
+ *
+ * <p><a name="format"> A service provider is identified by placing a
+ * <i>provider-configuration file</i> in the resource directory
+ * <tt>META-INF/services</tt>.</a>  The file's name is the fully-qualified <a
+ * href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
+ * The file contains a list of fully-qualified binary names of concrete
+ * provider classes, one per line.  Space and tab characters surrounding each
+ * name, as well as blank lines, are ignored.  The comment character is
+ * <tt>'#'</tt> (<tt>'&#92;u0023'</tt>,
+ * <font style="font-size:smaller;">NUMBER SIGN</font>); on
+ * each line all characters following the first comment character are ignored.
+ * The file must be encoded in UTF-8.
+ *
+ * <p> If a particular concrete provider class is named in more than one
+ * configuration file, or is named in the same configuration file more than
+ * once, then the duplicates are ignored.  The configuration file naming a
+ * particular provider need not be in the same jar file or other distribution
+ * unit as the provider itself.  The provider must be accessible from the same
+ * class loader that was initially queried to locate the configuration file;
+ * note that this is not necessarily the class loader from which the file was
+ * actually loaded.
+ *
+ * <p> Providers are located and instantiated lazily, that is, on demand.  A
+ * service loader maintains a cache of the providers that have been loaded so
+ * far.  Each invocation of the {@link #iterator iterator} method returns an
+ * iterator that first yields all of the elements of the cache, in
+ * instantiation order, and then lazily locates and instantiates any remaining
+ * providers, adding each one to the cache in turn.  The cache can be cleared
+ * via the {@link #reload reload} method.
+ *
+ * <p> Service loaders always execute in the security context of the caller.
+ * Trusted system code should typically invoke the methods in this class, and
+ * the methods of the iterators which they return, from within a privileged
+ * security context.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ *
+ *
+ * <p><span style="font-weight: bold; padding-right: 1em">Example</span>
+ * Suppose we have a service type <tt>com.example.CodecSet</tt> which is
+ * intended to represent sets of encoder/decoder pairs for some protocol.  In
+ * this case it is an abstract class with two abstract methods:
+ *
+ * <blockquote><pre>
+ * public abstract Encoder getEncoder(String encodingName);
+ * public abstract Decoder getDecoder(String encodingName);</pre></blockquote>
+ *
+ * Each method returns an appropriate object or <tt>null</tt> if the provider
+ * does not support the given encoding.  Typical providers support more than
+ * one encoding.
+ *
+ * <p> If <tt>com.example.impl.StandardCodecs</tt> is an implementation of the
+ * <tt>CodecSet</tt> service then its jar file also contains a file named
+ *
+ * <blockquote><pre>
+ * META-INF/services/com.example.CodecSet</pre></blockquote>
+ *
+ * <p> This file contains the single line:
+ *
+ * <blockquote><pre>
+ * com.example.impl.StandardCodecs    # Standard codecs</pre></blockquote>
+ *
+ * <p> The <tt>CodecSet</tt> class creates and saves a single service instance
+ * at initialization:
+ *
+ * <blockquote><pre>
+ * private static ServiceLoader&lt;CodecSet&gt; codecSetLoader
+ *     = ServiceLoader.load(CodecSet.class);</pre></blockquote>
+ *
+ * <p> To locate an encoder for a given encoding name it defines a static
+ * factory method which iterates through the known and available providers,
+ * returning only when it has located a suitable encoder or has run out of
+ * providers.
+ *
+ * <blockquote><pre>
+ * public static Encoder getEncoder(String encodingName) {
+ *     for (CodecSet cp : codecSetLoader) {
+ *         Encoder enc = cp.getEncoder(encodingName);
+ *         if (enc != null)
+ *             return enc;
+ *     }
+ *     return null;
+ * }</pre></blockquote>
+ *
+ * <p> A <tt>getDecoder</tt> method is defined similarly.
+ *
+ *
+ * <p><span style="font-weight: bold; padding-right: 1em">Usage Note</span> If
+ * the class path of a class loader that is used for provider loading includes
+ * remote network URLs then those URLs will be dereferenced in the process of
+ * searching for provider-configuration files.
+ *
+ * <p> This activity is normal, although it may cause puzzling entries to be
+ * created in web-server logs.  If a web server is not configured correctly,
+ * however, then this activity may cause the provider-loading algorithm to fail
+ * spuriously.
+ *
+ * <p> A web server should return an HTTP 404 (Not Found) response when a
+ * requested resource does not exist.  Sometimes, however, web servers are
+ * erroneously configured to return an HTTP 200 (OK) response along with a
+ * helpful HTML error page in such cases.  This will cause a {@link
+ * ServiceConfigurationError} to be thrown when this class attempts to parse
+ * the HTML page as a provider-configuration file.  The best solution to this
+ * problem is to fix the misconfigured web server to return the correct
+ * response code (HTTP 404) along with the HTML error page.
+ *
+ * @param  <S>
+ *         The type of the service to be loaded by this loader
+ *
+ * @author Mark Reinhold
+ * @since 1.6
+ */
+
+public final class ServiceLoader<S>
+    implements Iterable<S>
+{
+
+    private static final String PREFIX = "META-INF/services/";
+
+    // The class or interface representing the service being loaded
+    private final Class<S> service;
+
+    // The class loader used to locate, load, and instantiate providers
+    private final ClassLoader loader;
+
+    // The access control context taken when the ServiceLoader is created
+    // Android-changed: do not use legacy security code.
+    // private final AccessControlContext acc;
+
+    // Cached providers, in instantiation order
+    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
+
+    // The current lazy-lookup iterator
+    private LazyIterator lookupIterator;
+
+    /**
+     * Clear this loader's provider cache so that all providers will be
+     * reloaded.
+     *
+     * <p> After invoking this method, subsequent invocations of the {@link
+     * #iterator() iterator} method will lazily look up and instantiate
+     * providers from scratch, just as is done by a newly-created loader.
+     *
+     * <p> This method is intended for use in situations in which new providers
+     * can be installed into a running Java virtual machine.
+     */
+    public void reload() {
+        providers.clear();
+        lookupIterator = new LazyIterator(service, loader);
+    }
+
+    private ServiceLoader(Class<S> svc, ClassLoader cl) {
+        service = Objects.requireNonNull(svc, "Service interface cannot be null");
+        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
+        // Android-changed: Do not use legacy security code.
+        // On Android, System.getSecurityManager() is always null.
+        // acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
+        reload();
+    }
+
+    private static void fail(Class<?> service, String msg, Throwable cause)
+        throws ServiceConfigurationError
+    {
+        throw new ServiceConfigurationError(service.getName() + ": " + msg,
+                                            cause);
+    }
+
+    private static void fail(Class<?> service, String msg)
+        throws ServiceConfigurationError
+    {
+        throw new ServiceConfigurationError(service.getName() + ": " + msg);
+    }
+
+    private static void fail(Class<?> service, URL u, int line, String msg)
+        throws ServiceConfigurationError
+    {
+        fail(service, u + ":" + line + ": " + msg);
+    }
+
+    // Parse a single line from the given configuration file, adding the name
+    // on the line to the names list.
+    //
+    private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
+                          List<String> names)
+        throws IOException, ServiceConfigurationError
+    {
+        String ln = r.readLine();
+        if (ln == null) {
+            return -1;
+        }
+        int ci = ln.indexOf('#');
+        if (ci >= 0) ln = ln.substring(0, ci);
+        ln = ln.trim();
+        int n = ln.length();
+        if (n != 0) {
+            if ((ln.indexOf(' ') >= 0) || (ln.indexOf('\t') >= 0))
+                fail(service, u, lc, "Illegal configuration-file syntax");
+            int cp = ln.codePointAt(0);
+            if (!Character.isJavaIdentifierStart(cp))
+                fail(service, u, lc, "Illegal provider-class name: " + ln);
+            for (int i = Character.charCount(cp); i < n; i += Character.charCount(cp)) {
+                cp = ln.codePointAt(i);
+                if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
+                    fail(service, u, lc, "Illegal provider-class name: " + ln);
+            }
+            if (!providers.containsKey(ln) && !names.contains(ln))
+                names.add(ln);
+        }
+        return lc + 1;
+    }
+
+    // Parse the content of the given URL as a provider-configuration file.
+    //
+    // @param  service
+    //         The service type for which providers are being sought;
+    //         used to construct error detail strings
+    //
+    // @param  u
+    //         The URL naming the configuration file to be parsed
+    //
+    // @return A (possibly empty) iterator that will yield the provider-class
+    //         names in the given configuration file that are not yet members
+    //         of the returned set
+    //
+    // @throws ServiceConfigurationError
+    //         If an I/O error occurs while reading from the given URL, or
+    //         if a configuration-file format error is detected
+    //
+    private Iterator<String> parse(Class<?> service, URL u)
+        throws ServiceConfigurationError
+    {
+        InputStream in = null;
+        BufferedReader r = null;
+        ArrayList<String> names = new ArrayList<>();
+        try {
+            in = u.openStream();
+            r = new BufferedReader(new InputStreamReader(in, "utf-8"));
+            int lc = 1;
+            while ((lc = parseLine(service, u, r, lc, names)) >= 0);
+        } catch (IOException x) {
+            fail(service, "Error reading configuration file", x);
+        } finally {
+            try {
+                if (r != null) r.close();
+                if (in != null) in.close();
+            } catch (IOException y) {
+                fail(service, "Error closing configuration file", y);
+            }
+        }
+        return names.iterator();
+    }
+
+    // Private inner class implementing fully-lazy provider lookup
+    //
+    private class LazyIterator
+        implements Iterator<S>
+    {
+
+        Class<S> service;
+        ClassLoader loader;
+        Enumeration<URL> configs = null;
+        Iterator<String> pending = null;
+        String nextName = null;
+
+        private LazyIterator(Class<S> service, ClassLoader loader) {
+            this.service = service;
+            this.loader = loader;
+        }
+
+        private boolean hasNextService() {
+            if (nextName != null) {
+                return true;
+            }
+            if (configs == null) {
+                try {
+                    String fullName = PREFIX + service.getName();
+                    if (loader == null)
+                        configs = ClassLoader.getSystemResources(fullName);
+                    else
+                        configs = loader.getResources(fullName);
+                } catch (IOException x) {
+                    fail(service, "Error locating configuration files", x);
+                }
+            }
+            while ((pending == null) || !pending.hasNext()) {
+                if (!configs.hasMoreElements()) {
+                    return false;
+                }
+                pending = parse(service, configs.nextElement());
+            }
+            nextName = pending.next();
+            return true;
+        }
+
+        private S nextService() {
+            if (!hasNextService())
+                throw new NoSuchElementException();
+            String cn = nextName;
+            nextName = null;
+            Class<?> c = null;
+            try {
+                c = Class.forName(cn, false, loader);
+            } catch (ClassNotFoundException x) {
+                fail(service,
+                     // Android-changed: Let the ServiceConfigurationError have a cause.
+                     "Provider " + cn + " not found", x);
+                     // "Provider " + cn + " not found");
+            }
+            if (!service.isAssignableFrom(c)) {
+                // Android-changed: Let the ServiceConfigurationError have a cause.
+                ClassCastException cce = new ClassCastException(
+                        service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
+                fail(service,
+                     "Provider " + cn  + " not a subtype", cce);
+                // fail(service,
+                //        "Provider " + cn  + " not a subtype");
+            }
+            try {
+                S p = service.cast(c.newInstance());
+                providers.put(cn, p);
+                return p;
+            } catch (Throwable x) {
+                fail(service,
+                     "Provider " + cn + " could not be instantiated",
+                     x);
+            }
+            throw new Error();          // This cannot happen
+        }
+
+        public boolean hasNext() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return hasNextService();
+            /*
+            } else {
+                PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
+                    public Boolean run() { return hasNextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
+        public S next() {
+            // Android-changed: do not use legacy security code
+            /* if (acc == null) { */
+                return nextService();
+            /*
+            } else {
+                PrivilegedAction<S> action = new PrivilegedAction<S>() {
+                    public S run() { return nextService(); }
+                };
+                return AccessController.doPrivileged(action, acc);
+            }
+            */
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+    }
+
+    /**
+     * Lazily loads the available providers of this loader's service.
+     *
+     * <p> The iterator returned by this method first yields all of the
+     * elements of the provider cache, in instantiation order.  It then lazily
+     * loads and instantiates any remaining providers, adding each one to the
+     * cache in turn.
+     *
+     * <p> To achieve laziness the actual work of parsing the available
+     * provider-configuration files and instantiating providers must be done by
+     * the iterator itself.  Its {@link java.util.Iterator#hasNext hasNext} and
+     * {@link java.util.Iterator#next next} methods can therefore throw a
+     * {@link ServiceConfigurationError} if a provider-configuration file
+     * violates the specified format, or if it names a provider class that
+     * cannot be found and instantiated, or if the result of instantiating the
+     * class is not assignable to the service type, or if any other kind of
+     * exception or error is thrown as the next provider is located and
+     * instantiated.  To write robust code it is only necessary to catch {@link
+     * ServiceConfigurationError} when using a service iterator.
+     *
+     * <p> If such an error is thrown then subsequent invocations of the
+     * iterator will make a best effort to locate and instantiate the next
+     * available provider, but in general such recovery cannot be guaranteed.
+     *
+     * <blockquote style="font-size: smaller; line-height: 1.2"><span
+     * style="padding-right: 1em; font-weight: bold">Design Note</span>
+     * Throwing an error in these cases may seem extreme.  The rationale for
+     * this behavior is that a malformed provider-configuration file, like a
+     * malformed class file, indicates a serious problem with the way the Java
+     * virtual machine is configured or is being used.  As such it is
+     * preferable to throw an error rather than try to recover or, even worse,
+     * fail silently.</blockquote>
+     *
+     * <p> The iterator returned by this method does not support removal.
+     * Invoking its {@link java.util.Iterator#remove() remove} method will
+     * cause an {@link UnsupportedOperationException} to be thrown.
+     *
+     * @implNote When adding providers to the cache, the {@link #iterator
+     * Iterator} processes resources in the order that the {@link
+     * java.lang.ClassLoader#getResources(java.lang.String)
+     * ClassLoader.getResources(String)} method finds the service configuration
+     * files.
+     *
+     * @return  An iterator that lazily loads providers for this loader's
+     *          service
+     */
+    public Iterator<S> iterator() {
+        return new Iterator<S>() {
+
+            Iterator<Map.Entry<String,S>> knownProviders
+                = providers.entrySet().iterator();
+
+            public boolean hasNext() {
+                if (knownProviders.hasNext())
+                    return true;
+                return lookupIterator.hasNext();
+            }
+
+            public S next() {
+                if (knownProviders.hasNext())
+                    return knownProviders.next().getValue();
+                return lookupIterator.next();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+
+        };
+    }
+
+    /**
+     * Creates a new service loader for the given service type and class
+     * loader.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @param  loader
+     *         The class loader to be used to load provider-configuration files
+     *         and provider classes, or <tt>null</tt> if the system class
+     *         loader (or, failing that, the bootstrap class loader) is to be
+     *         used
+     *
+     * @return A new service loader
+     */
+    public static <S> ServiceLoader<S> load(Class<S> service,
+                                            ClassLoader loader)
+    {
+        return new ServiceLoader<>(service, loader);
+    }
+
+    /**
+     * Creates a new service loader for the given service type, using the
+     * current thread's {@linkplain java.lang.Thread#getContextClassLoader
+     * context class loader}.
+     *
+     * <p> An invocation of this convenience method of the form
+     *
+     * <blockquote><pre>
+     * ServiceLoader.load(<i>service</i>)</pre></blockquote>
+     *
+     * is equivalent to
+     *
+     * <blockquote><pre>
+     * ServiceLoader.load(<i>service</i>,
+     *                    Thread.currentThread().getContextClassLoader())</pre></blockquote>
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     */
+    public static <S> ServiceLoader<S> load(Class<S> service) {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        return ServiceLoader.load(service, cl);
+    }
+
+    /**
+     * Creates a new service loader for the given service type, using the
+     * extension class loader.
+     *
+     * <p> This convenience method simply locates the extension class loader,
+     * call it <tt><i>extClassLoader</i></tt>, and then returns
+     *
+     * <blockquote><pre>
+     * ServiceLoader.load(<i>service</i>, <i>extClassLoader</i>)</pre></blockquote>
+     *
+     * <p> If the extension class loader cannot be found then the system class
+     * loader is used; if there is no system class loader then the bootstrap
+     * class loader is used.
+     *
+     * <p> This method is intended for use when only installed providers are
+     * desired.  The resulting service will only find and load providers that
+     * have been installed into the current Java virtual machine; providers on
+     * the application's class path will be ignored.
+     *
+     * @param  <S> the class of the service type
+     *
+     * @param  service
+     *         The interface or abstract class representing the service
+     *
+     * @return A new service loader
+     */
+    public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
+        ClassLoader cl = ClassLoader.getSystemClassLoader();
+        ClassLoader prev = null;
+        while (cl != null) {
+            prev = cl;
+            cl = cl.getParent();
+        }
+        return ServiceLoader.load(service, prev);
+    }
+
+    // BEGIN Android-added: loadFromSystemProperty(), for internal use.
+    // Instantiates a class from a system property (used elsewhere in libcore).
+    /**
+     * Internal API to support built-in SPIs that check a system property first.
+     * Returns an instance specified by a property with the class' binary name, or null if
+     * no such property is set.
+     * @hide
+     */
+    public static <S> S loadFromSystemProperty(final Class<S> service) {
+        try {
+            final String className = System.getProperty(service.getName());
+            if (className != null) {
+                Class<?> c = ClassLoader.getSystemClassLoader().loadClass(className);
+                return (S) c.newInstance();
+            }
+            return null;
+        } catch (Exception e) {
+            throw new Error(e);
+        }
+    }
+    // END Android-added: loadFromSystemProperty(), for internal use.
+
+    /**
+     * Returns a string describing this service.
+     *
+     * @return  A descriptive string
+     */
+    public String toString() {
+        return "java.util.ServiceLoader[" + service.getName() + "]";
+    }
+
+}
diff --git a/java/util/Set.annotated.java b/java/util/Set.annotated.java
new file mode 100644
index 0000000..bae8bdd
--- /dev/null
+++ b/java/util/Set.annotated.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface Set<E> extends java.util.Collection<E> {
+
+public int size();
+
+public boolean isEmpty();
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o);
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator();
+
+public [email protected] Object @libcore.util.NonNull [] toArray();
+
+// TODO: Make param and return types @Nullable T @NonNull [] once metalava supports TYPE_USE.
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a);
+
+public boolean add(@libcore.util.NullFromTypeParam E e);
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o);
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c);
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c);
+
+public void clear();
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o);
+
+public int hashCode();
+
[email protected] public default java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of() { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9) { throw new RuntimeException("Stub!"); }
+
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(@libcore.util.NonNull E e1, @libcore.util.NonNull E e2, @libcore.util.NonNull E e3, @libcore.util.NonNull E e4, @libcore.util.NonNull E e5, @libcore.util.NonNull E e6, @libcore.util.NonNull E e7, @libcore.util.NonNull E e8, @libcore.util.NonNull E e9, @libcore.util.NonNull E e10) { throw new RuntimeException("Stub!"); }
+
[email protected]
[email protected] public static <E> java.util.Set<@libcore.util.NonNull E> of(E @libcore.util.NonNull ... elements) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/Set.java b/java/util/Set.java
new file mode 100644
index 0000000..0499ea3
--- /dev/null
+++ b/java/util/Set.java
@@ -0,0 +1,703 @@
+/*
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A collection that contains no duplicate elements.  More formally, sets
+ * contain no pair of elements {@code e1} and {@code e2} such that
+ * {@code e1.equals(e2)}, and at most one null element.  As implied by
+ * its name, this interface models the mathematical <i>set</i> abstraction.
+ *
+ * <p>The {@code Set} interface places additional stipulations, beyond those
+ * inherited from the {@code Collection} interface, on the contracts of all
+ * constructors and on the contracts of the {@code add}, {@code equals} and
+ * {@code hashCode} methods.  Declarations for other inherited methods are
+ * also included here for convenience.  (The specifications accompanying these
+ * declarations have been tailored to the {@code Set} interface, but they do
+ * not contain any additional stipulations.)
+ *
+ * <p>The additional stipulation on constructors is, not surprisingly,
+ * that all constructors must create a set that contains no duplicate elements
+ * (as defined above).
+ *
+ * <p>Note: Great care must be exercised if mutable objects are used as set
+ * elements.  The behavior of a set is not specified if the value of an object
+ * is changed in a manner that affects {@code equals} comparisons while the
+ * object is an element in the set.  A special case of this prohibition is
+ * that it is not permissible for a set to contain itself as an element.
+ *
+ * <p>Some set implementations have restrictions on the elements that
+ * they may contain.  For example, some implementations prohibit null elements,
+ * and some have restrictions on the types of their elements.  Attempting to
+ * add an ineligible element throws an unchecked exception, typically
+ * {@code NullPointerException} or {@code ClassCastException}.  Attempting
+ * to query the presence of an ineligible element may throw an exception,
+ * or it may simply return false; some implementations will exhibit the former
+ * behavior and some will exhibit the latter.  More generally, attempting an
+ * operation on an ineligible element whose completion would not result in
+ * the insertion of an ineligible element into the set may throw an
+ * exception or it may succeed, at the option of the implementation.
+ * Such exceptions are marked as "optional" in the specification for this
+ * interface.
+ *
+ * <h2><a id="immutable">Immutable Set Static Factory Methods</a></h2>
+ * <p>The {@link Set#of(Object...) Set.of()} static factory methods
+ * provide a convenient way to create immutable sets. The {@code Set}
+ * instances created by these methods have the following characteristics:
+ *
+ * <ul>
+ * <li>They are <em>structurally immutable</em>. Elements cannot be added or
+ * removed. Calling any mutator method will always cause
+ * {@code UnsupportedOperationException} to be thrown.
+ * However, if the contained elements are themselves mutable, this may cause the
+ * Set to behave inconsistently or its contents to appear to change.
+ * <li>They disallow {@code null} elements. Attempts to create them with
+ * {@code null} elements result in {@code NullPointerException}.
+ * <li>They are serializable if all elements are serializable.
+ * <li>They reject duplicate elements at creation time. Duplicate elements
+ * passed to a static factory method result in {@code IllegalArgumentException}.
+ * <li>The iteration order of set elements is unspecified and is subject to change.
+ * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
+ * Callers should make no assumptions about the identity of the returned instances.
+ * Factories are free to create new instances or reuse existing ones. Therefore,
+ * identity-sensitive operations on these instances (reference equality ({@code ==}),
+ * identity hash code, and synchronization) are unreliable and should be avoided.
+ * <li>They are serialized as specified on the
+ * <a href="{@docRoot}/serialized-form.html#java.util.CollSer">Serialized Form</a>
+ * page.
+ * </ul>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @author  Neal Gafter
+ * @see Collection
+ * @see List
+ * @see SortedSet
+ * @see HashSet
+ * @see TreeSet
+ * @see AbstractSet
+ * @see Collections#singleton(java.lang.Object)
+ * @see Collections#EMPTY_SET
+ * @since 1.2
+ */
+
+public interface Set<E> extends Collection<E> {
+    // Query Operations
+
+    /**
+     * Returns the number of elements in this set (its cardinality).  If this
+     * set contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns an iterator over the elements in this set.  The elements are
+     * returned in no particular order (unless this set is an instance of some
+     * class that provides a guarantee).
+     *
+     * @return an iterator over the elements in this set
+     */
+    Iterator<E> iterator();
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of {@code String}:
+     *
+     * <pre>
+     *     String[] y = x.toArray(new String[0]);</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    <T> T[] toArray(T[] a);
+
+
+    // Modification Operations
+
+    /**
+     * Adds the specified element to this set if it is not already present
+     * (optional operation).  More formally, adds the specified element
+     * {@code e} to this set if the set contains no element {@code e2}
+     * such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.  In combination with the
+     * restriction on constructors, this ensures that sets never contain
+     * duplicate elements.
+     *
+     * <p>The stipulation above does not imply that sets must accept all
+     * elements; sets may refuse to add any particular element, including
+     * {@code null}, and throw an exception, as described in the
+     * specification for {@link Collection#add Collection.add}.
+     * Individual set implementations should clearly document any
+     * restrictions on the elements that they may contain.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     * @throws UnsupportedOperationException if the {@code add} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this set
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * @throws IllegalArgumentException if some property of the specified element
+     *         prevents it from being added to this set
+     */
+    boolean add(E e);
+
+
+    /**
+     * Removes the specified element from this set if it is present
+     * (optional operation).  More formally, removes an element {@code e}
+     * such that
+     * {@code Objects.equals(o, e)}, if
+     * this set contains such an element.  Returns {@code true} if this set
+     * contained the element (or equivalently, if this set changed as a
+     * result of the call).  (This set will not contain the element once the
+     * call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if the type of the specified element
+     *         is incompatible with this set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null and this
+     *         set does not permit null elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this set
+     */
+    boolean remove(Object o);
+
+
+    // Bulk Operations
+
+    /**
+     * Returns {@code true} if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns {@code true} if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements of the
+     *         specified collection
+     * @throws ClassCastException if the types of one or more elements
+     *         in the specified collection are incompatible with this
+     *         set
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this set does not permit null
+     *         elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see    #contains(Object)
+     */
+    boolean containsAll(Collection<?> c);
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present (optional operation).  If the specified
+     * collection is also a set, the {@code addAll} operation effectively
+     * modifies this set so that its value is the <i>union</i> of the two
+     * sets.  The behavior of this operation is undefined if the specified
+     * collection is modified while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     *
+     * @throws UnsupportedOperationException if the {@code addAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of the
+     *         specified collection prevents it from being added to this set
+     * @throws NullPointerException if the specified collection contains one
+     *         or more null elements and this set does not permit null
+     *         elements, or if the specified collection is null
+     * @throws IllegalArgumentException if some property of an element of the
+     *         specified collection prevents it from being added to this set
+     * @see #add(Object)
+     */
+    boolean addAll(Collection<? extends E> c);
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection (optional operation).  In other words, removes
+     * from this set all of its elements that are not contained in the
+     * specified collection.  If the specified collection is also a set, this
+     * operation effectively modifies this set so that its value is the
+     * <i>intersection</i> of the two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code retainAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    boolean retainAll(Collection<?> c);
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection (optional operation).  If the specified
+     * collection is also a set, this operation effectively modifies this
+     * set so that its value is the <i>asymmetric set difference</i> of
+     * the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws UnsupportedOperationException if the {@code removeAll} operation
+     *         is not supported by this set
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     * @see #contains(Object)
+     */
+    boolean removeAll(Collection<?> c);
+
+    /**
+     * Removes all of the elements from this set (optional operation).
+     * The set will be empty after this call returns.
+     *
+     * @throws UnsupportedOperationException if the {@code clear} method
+     *         is not supported by this set
+     */
+    void clear();
+
+
+    // Comparison and hashing
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the specified object is also a set, the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).  This definition ensures that the
+     * equals method works properly across different implementations of the
+     * set interface.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    boolean equals(Object o);
+
+    /**
+     * Returns the hash code value for this set.  The hash code of a set is
+     * defined to be the sum of the hash codes of the elements in the set,
+     * where the hash code of a {@code null} element is defined to be zero.
+     * This ensures that {@code s1.equals(s2)} implies that
+     * {@code s1.hashCode()==s2.hashCode()} for any two sets {@code s1}
+     * and {@code s2}, as required by the general contract of
+     * {@link Object#hashCode}.
+     *
+     * @return the hash code value for this set
+     * @see Object#equals(Object)
+     * @see Set#equals(Object)
+     */
+    int hashCode();
+
+    /**
+     * Creates a {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#DISTINCT}.
+     * Implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * <p>
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return Spliterators.spliterator(this, Spliterator.DISTINCT);
+    }
+
+    /**
+     * Returns an immutable set containing zero elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @return an empty {@code Set}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of() {
+        return ImmutableCollections.Set0.instance();
+    }
+
+    /**
+     * Returns an immutable set containing one element.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the single element
+     * @return a {@code Set} containing the specified element
+     * @throws NullPointerException if the element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1) {
+        return new ImmutableCollections.Set1<>(e1);
+    }
+
+    /**
+     * Returns an immutable set containing two elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if the elements are duplicates
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2) {
+        return new ImmutableCollections.Set2<>(e1, e2);
+    }
+
+    /**
+     * Returns an immutable set containing three elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3);
+    }
+
+    /**
+     * Returns an immutable set containing four elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4);
+    }
+
+    /**
+     * Returns an immutable set containing five elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5);
+    }
+
+    /**
+     * Returns an immutable set containing six elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6);
+    }
+
+    /**
+     * Returns an immutable set containing seven elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7);
+    }
+
+    /**
+     * Returns an immutable set containing eight elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8);
+    }
+
+    /**
+     * Returns an immutable set containing nine elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9);
+    }
+
+    /**
+     * Returns an immutable set containing ten elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param e1 the first element
+     * @param e2 the second element
+     * @param e3 the third element
+     * @param e4 the fourth element
+     * @param e5 the fifth element
+     * @param e6 the sixth element
+     * @param e7 the seventh element
+     * @param e8 the eighth element
+     * @param e9 the ninth element
+     * @param e10 the tenth element
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null}
+     *
+     * @since 9
+     */
+    static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
+        return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
+                                               e6, e7, e8, e9, e10);
+    }
+
+    /**
+     * Returns an immutable set containing an arbitrary number of elements.
+     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     *
+     * @apiNote
+     * This method also accepts a single array as an argument. The element type of
+     * the resulting set will be the component type of the array, and the size of
+     * the set will be equal to the length of the array. To create a set with
+     * a single element that is an array, do the following:
+     *
+     * <pre>{@code
+     *     String[] array = ... ;
+     *     Set<String[]> list = Set.<String[]>of(array);
+     * }</pre>
+     *
+     * This will cause the {@link Set#of(Object) Set.of(E)} method
+     * to be invoked instead.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param elements the elements to be contained in the set
+     * @return a {@code Set} containing the specified elements
+     * @throws IllegalArgumentException if there are any duplicate elements
+     * @throws NullPointerException if an element is {@code null} or if the array is {@code null}
+     *
+     * @since 9
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    static <E> Set<E> of(E... elements) {
+        switch (elements.length) { // implicit null check of elements
+            case 0:
+                return ImmutableCollections.Set0.instance();
+            case 1:
+                return new ImmutableCollections.Set1<>(elements[0]);
+            case 2:
+                return new ImmutableCollections.Set2<>(elements[0], elements[1]);
+            default:
+                return new ImmutableCollections.SetN<>(elements);
+        }
+    }
+}
diff --git a/java/util/SimpleTimeZone.java b/java/util/SimpleTimeZone.java
new file mode 100644
index 0000000..ef70b96
--- /dev/null
+++ b/java/util/SimpleTimeZone.java
@@ -0,0 +1,1706 @@
+/*
+ * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.IOException;
+import sun.util.calendar.CalendarSystem;
+import sun.util.calendar.CalendarUtils;
+import sun.util.calendar.BaseCalendar;
+import sun.util.calendar.Gregorian;
+
+/**
+ * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
+ * that represents a time zone for use with a Gregorian calendar.
+ * The class holds an offset from GMT, called <em>raw offset</em>, and start
+ * and end rules for a daylight saving time schedule.  Since it only holds
+ * single values for each, it cannot handle historical changes in the offset
+ * from GMT and the daylight saving schedule, except that the {@link
+ * #setStartYear setStartYear} method can specify the year when the daylight
+ * saving time schedule starts in effect.
+ * <p>
+ * To construct a <code>SimpleTimeZone</code> with a daylight saving time
+ * schedule, the schedule can be described with a set of rules,
+ * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
+ * starts or ends is specified by a combination of <em>month</em>,
+ * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
+ * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
+ * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
+ * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
+ * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
+ * are as follows.
+ *
+ * <ul>
+ * <li><b>Exact day of month</b><br>
+ * To specify an exact day of month, set the <em>month</em> and
+ * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
+ * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
+ * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
+ *
+ * <li><b>Day of week on or after day of month</b><br>
+ * To specify a day of week on or after an exact day of month, set the
+ * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
+ * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
+ * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
+ * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
+ * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
+ * Calendar#SUNDAY SUNDAY}.</li>
+ *
+ * <li><b>Day of week on or before day of month</b><br>
+ * To specify a day of the week on or before an exact day of the month, set
+ * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
+ * example, to specify the last Wednesday on or before the 21st of March, set
+ * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
+ * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
+ *
+ * <li><b>Last day-of-week of month</b><br>
+ * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
+ * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
+ * -1. For example, to specify the last Sunday of October, set <em>month</em>
+ * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
+ * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1.  </li>
+ *
+ * </ul>
+ * The time of the day at which daylight saving time starts or ends is
+ * specified by a millisecond value within the day. There are three kinds of
+ * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
+ * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
+ * saving time ends
+ * at 2:00 am in the wall clock time, it can be specified by 7200000
+ * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
+ * for an <em>end-rule</em> means the same thing as the daylight time.
+ * <p>
+ * The following are examples of parameters for constructing time zone objects.
+ * <pre><code>
+ *      // Base GMT offset: -8:00
+ *      // DST starts:      at 2:00am in standard time
+ *      //                  on the first Sunday in April
+ *      // DST ends:        at 2:00am in daylight time
+ *      //                  on the last Sunday in October
+ *      // Save:            1 hour
+ *      SimpleTimeZone(-28800000,
+ *                     "America/Los_Angeles",
+ *                     Calendar.APRIL, 1, -Calendar.SUNDAY,
+ *                     7200000,
+ *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
+ *                     7200000,
+ *                     3600000)
+ *
+ *      // Base GMT offset: +1:00
+ *      // DST starts:      at 1:00am in UTC time
+ *      //                  on the last Sunday in March
+ *      // DST ends:        at 1:00am in UTC time
+ *      //                  on the last Sunday in October
+ *      // Save:            1 hour
+ *      SimpleTimeZone(3600000,
+ *                     "Europe/Paris",
+ *                     Calendar.MARCH, -1, Calendar.SUNDAY,
+ *                     3600000, SimpleTimeZone.UTC_TIME,
+ *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
+ *                     3600000, SimpleTimeZone.UTC_TIME,
+ *                     3600000)
+ * </code></pre>
+ * These parameter rules are also applicable to the set rule methods, such as
+ * <code>setStartRule</code>.
+ *
+ * @since 1.1
+ * @see      Calendar
+ * @see      GregorianCalendar
+ * @see      TimeZone
+ * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
+ */
+
+public class SimpleTimeZone extends TimeZone {
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from GMT
+     * and time zone ID with no daylight saving time schedule.
+     *
+     * @param rawOffset  The base time zone offset in milliseconds to GMT.
+     * @param ID         The time zone name that is given to this instance.
+     */
+    public SimpleTimeZone(int rawOffset, String ID)
+    {
+        this.rawOffset = rawOffset;
+        setID (ID);
+        dstSavings = millisPerHour; // In case user sets rules later
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * Both <code>startTime</code> and <code>endTime</code> are specified to be
+     * represented in the wall clock time. The amount of daylight saving is
+     * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
+     * equivalent to:
+     * <pre><code>
+     *     SimpleTimeZone(rawOffset,
+     *                    ID,
+     *                    startMonth,
+     *                    startDay,
+     *                    startDayOfWeek,
+     *                    startTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    endMonth,
+     *                    endDay,
+     *                    endDayOfWeek,
+     *                    endTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    3600000)
+     * </code></pre>
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
+     *                        for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time (in milliseconds within the day), which is local
+     *                        standard time in this case.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
+     * parameters are out of range for the start or end rule
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek, int startTime,
+                          int endMonth, int endDay, int endDayOfWeek, int endTime)
+    {
+        this(rawOffset, ID,
+             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
+             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
+             millisPerHour);
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * Both <code>startTime</code> and <code>endTime</code> are assumed to be
+     * represented in the wall clock time. This constructor is equivalent to:
+     * <pre><code>
+     *     SimpleTimeZone(rawOffset,
+     *                    ID,
+     *                    startMonth,
+     *                    startDay,
+     *                    startDayOfWeek,
+     *                    startTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    endMonth,
+     *                    endDay,
+     *                    endDayOfWeek,
+     *                    endTime,
+     *                    SimpleTimeZone.{@link #WALL_TIME},
+     *                    dstSavings)
+     * </code></pre>
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        which is local daylight time in this case.
+     * @param dstSavings      The amount of time in milliseconds saved during
+     *                        daylight saving time.
+     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
+     * parameters are out of range for the start or end rule
+     * @since 1.2
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek, int startTime,
+                          int endMonth, int endDay, int endDayOfWeek, int endTime,
+                          int dstSavings)
+    {
+        this(rawOffset, ID,
+             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
+             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
+             dstSavings);
+    }
+
+    /**
+     * Constructs a SimpleTimeZone with the given base time zone offset from
+     * GMT, time zone ID, and rules for starting and ending the daylight
+     * time.
+     * This constructor takes the full set of the start and end rules
+     * parameters, including modes of <code>startTime</code> and
+     * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
+     * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
+     * time}.
+     *
+     * @param rawOffset       The given base time zone offset from GMT.
+     * @param ID              The time zone ID which is given to this object.
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in the time mode
+     *                        specified by <code>startTimeMode</code>.
+     * @param startTimeMode   The mode of the start time specified by startTime.
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in time time mode
+     *                        specified by <code>endTimeMode</code>.
+     * @param endTimeMode     The mode of the end time specified by endTime
+     * @param dstSavings      The amount of time in milliseconds saved during
+     *                        daylight saving time.
+     *
+     * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
+     * time parameters are out of range for the start or end rule, or if a time mode
+     * value is invalid.
+     *
+     * @see #WALL_TIME
+     * @see #STANDARD_TIME
+     * @see #UTC_TIME
+     *
+     * @since 1.4
+     */
+    public SimpleTimeZone(int rawOffset, String ID,
+                          int startMonth, int startDay, int startDayOfWeek,
+                          int startTime, int startTimeMode,
+                          int endMonth, int endDay, int endDayOfWeek,
+                          int endTime, int endTimeMode,
+                          int dstSavings) {
+
+        setID(ID);
+        this.rawOffset      = rawOffset;
+        this.startMonth     = startMonth;
+        this.startDay       = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime      = startTime;
+        this.startTimeMode  = startTimeMode;
+        this.endMonth       = endMonth;
+        this.endDay         = endDay;
+        this.endDayOfWeek   = endDayOfWeek;
+        this.endTime        = endTime;
+        this.endTimeMode    = endTimeMode;
+        this.dstSavings     = dstSavings;
+
+        // this.useDaylight is set by decodeRules
+        decodeRules();
+        if (dstSavings <= 0) {
+            throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
+        }
+    }
+
+    /**
+     * Sets the daylight saving time starting year.
+     *
+     * @param year  The daylight saving starting year.
+     */
+    public void setStartYear(int year)
+    {
+        startYear = year;
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time start rule. For example, if daylight saving
+     * time starts on the first Sunday in April at 2 am in local wall clock
+     * time, you can set the start rule by calling:
+     * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     *                        See the class description for the special cases of this parameter.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
+     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
+     */
+    public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
+    {
+        this.startMonth = startMonth;
+        this.startDay = startDay;
+        this.startDayOfWeek = startDayOfWeek;
+        this.startTime = startTime;
+        startTimeMode = WALL_TIME;
+        decodeStartRule();
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time start rule to a fixed date within a month.
+     * This method is equivalent to:
+     * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     *                        See the class description for the special cases of this parameter.
+     * @exception IllegalArgumentException if the <code>startMonth</code>,
+     * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setStartRule(int startMonth, int startDay, int startTime) {
+        setStartRule(startMonth, startDay, 0, startTime);
+    }
+
+    /**
+     * Sets the daylight saving time start rule to a weekday before or after the given date within
+     * a month, e.g., the first Monday on or after the 8th.
+     *
+     * @param startMonth      The daylight saving time starting month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 0 for January).
+     * @param startDay        The day of the month on which the daylight saving time starts.
+     * @param startDayOfWeek  The daylight saving time starting day-of-week.
+     * @param startTime       The daylight saving time starting time in local wall clock
+     *                        time, which is local standard time in this case.
+     * @param after           If true, this rule selects the first <code>dayOfWeek</code> on or
+     *                        <em>after</em> <code>dayOfMonth</code>.  If false, this rule
+     *                        selects the last <code>dayOfWeek</code> on or <em>before</em>
+     *                        <code>dayOfMonth</code>.
+     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
+     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
+                             int startTime, boolean after)
+    {
+        // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
+        if (after) {
+            setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
+        } else {
+            setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
+        }
+    }
+
+    /**
+     * Sets the daylight saving time end rule. For example, if daylight saving time
+     * ends on the last Sunday in October at 2 am in wall clock time,
+     * you can set the end rule by calling:
+     * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     *                        See the class description for the special cases of this parameter.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     *                        See the class description for the special cases of this parameter.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
+     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
+     */
+    public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
+                           int endTime)
+    {
+        this.endMonth = endMonth;
+        this.endDay = endDay;
+        this.endDayOfWeek = endDayOfWeek;
+        this.endTime = endTime;
+        this.endTimeMode = WALL_TIME;
+        decodeEndRule();
+        invalidateCache();
+    }
+
+    /**
+     * Sets the daylight saving time end rule to a fixed date within a month.
+     * This method is equivalent to:
+     * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
+     * or <code>endTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setEndRule(int endMonth, int endDay, int endTime)
+    {
+        setEndRule(endMonth, endDay, 0, endTime);
+    }
+
+    /**
+     * Sets the daylight saving time end rule to a weekday before or after the given date within
+     * a month, e.g., the first Monday on or after the 8th.
+     *
+     * @param endMonth        The daylight saving time ending month. Month is
+     *                        a {@link Calendar#MONTH MONTH} field
+     *                        value (0-based. e.g., 9 for October).
+     * @param endDay          The day of the month on which the daylight saving time ends.
+     * @param endDayOfWeek    The daylight saving time ending day-of-week.
+     * @param endTime         The daylight saving ending time in local wall clock time,
+     *                        (in milliseconds within the day) which is local daylight
+     *                        time in this case.
+     * @param after           If true, this rule selects the first <code>endDayOfWeek</code> on
+     *                        or <em>after</em> <code>endDay</code>.  If false, this rule
+     *                        selects the last <code>endDayOfWeek</code> on or before
+     *                        <code>endDay</code> of the month.
+     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
+     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
+     * @since 1.2
+     */
+    public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
+    {
+        if (after) {
+            setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
+        } else {
+            setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
+        }
+    }
+
+    /**
+     * Returns the offset of this time zone from UTC at the given
+     * time. If daylight saving time is in effect at the given time,
+     * the offset value is adjusted with the amount of daylight
+     * saving.
+     *
+     * @param date the time at which the time zone offset is found
+     * @return the amount of time in milliseconds to add to UTC to get
+     * local time.
+     * @since 1.4
+     */
+    public int getOffset(long date) {
+        return getOffsets(date, null);
+    }
+
+    /**
+     * @see TimeZone#getOffsets
+     */
+    int getOffsets(long date, int[] offsets) {
+        int offset = rawOffset;
+
+      computeOffset:
+        if (useDaylight) {
+            synchronized (this) {
+                if (cacheStart != 0) {
+                    if (date >= cacheStart && date < cacheEnd) {
+                        offset += dstSavings;
+                        break computeOffset;
+                    }
+                }
+            }
+            BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
+                gcal : (BaseCalendar) CalendarSystem.forName("julian");
+            BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+            // Get the year in local time
+            cal.getCalendarDate(date + rawOffset, cdate);
+            int year = cdate.getNormalizedYear();
+            if (year >= startYear) {
+                // Clear time elements for the transition calculations
+                cdate.setTimeOfDay(0, 0, 0, 0);
+                offset = getOffset(cal, cdate, year, date);
+            }
+        }
+
+        if (offsets != null) {
+            offsets[0] = rawOffset;
+            offsets[1] = offset - rawOffset;
+        }
+        return offset;
+    }
+
+   /**
+     * Returns the difference in milliseconds between local time and
+     * UTC, taking into account both the raw offset and the effect of
+     * daylight saving, for the specified date and time.  This method
+     * assumes that the start and end month are distinct.  It also
+     * uses a default {@link GregorianCalendar} object as its
+     * underlying calendar, such as for determining leap years.  Do
+     * not use the result of this method with a calendar other than a
+     * default <code>GregorianCalendar</code>.
+     *
+     * <p><em>Note:  In general, clients should use
+     * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
+     * instead of calling this method.</em>
+     *
+     * @param era       The era of the given date.
+     * @param year      The year in the given date.
+     * @param month     The month in the given date. Month is 0-based. e.g.,
+     *                  0 for January.
+     * @param day       The day-in-month of the given date.
+     * @param dayOfWeek The day-of-week of the given date.
+     * @param millis    The milliseconds in day in <em>standard</em> local time.
+     * @return          The milliseconds to add to UTC to get local time.
+     * @exception       IllegalArgumentException the <code>era</code>,
+     *                  <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
+     *                  or <code>millis</code> parameters are out of range
+     */
+    public int getOffset(int era, int year, int month, int day, int dayOfWeek,
+                         int millis)
+    {
+        if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
+            throw new IllegalArgumentException("Illegal era " + era);
+        }
+
+        int y = year;
+        if (era == GregorianCalendar.BC) {
+            // adjust y with the GregorianCalendar-style year numbering.
+            y = 1 - y;
+        }
+
+        // If the year isn't representable with the 64-bit long
+        // integer in milliseconds, convert the year to an
+        // equivalent year. This is required to pass some JCK test cases
+        // which are actually useless though because the specified years
+        // can't be supported by the Java time system.
+        if (y >= 292278994) {
+            y = 2800 + y % 2800;
+        } else if (y <= -292269054) {
+            // y %= 28 also produces an equivalent year, but positive
+            // year numbers would be convenient to use the UNIX cal
+            // command.
+            y = (int) CalendarUtils.mod((long) y, 28);
+        }
+
+        // convert year to its 1-based month value
+        int m = month + 1;
+
+        // First, calculate time as a Gregorian date.
+        BaseCalendar cal = gcal;
+        BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+        cdate.setDate(y, m, day);
+        long time = cal.getTime(cdate); // normalize cdate
+        time += millis - rawOffset; // UTC time
+
+        // If the time value represents a time before the default
+        // Gregorian cutover, recalculate time using the Julian
+        // calendar system. For the Julian calendar system, the
+        // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
+        // 1, 2 ... which is different from the GregorianCalendar
+        // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
+        if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
+            cal = (BaseCalendar) CalendarSystem.forName("julian");
+            cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
+            cdate.setNormalizedDate(y, m, day);
+            time = cal.getTime(cdate) + millis - rawOffset;
+        }
+
+        if ((cdate.getNormalizedYear() != y)
+            || (cdate.getMonth() != m)
+            || (cdate.getDayOfMonth() != day)
+            // The validation should be cdate.getDayOfWeek() ==
+            // dayOfWeek. However, we don't check dayOfWeek for
+            // compatibility.
+            || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
+            || (millis < 0 || millis >= (24*60*60*1000))) {
+            throw new IllegalArgumentException();
+        }
+
+        if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
+            return rawOffset;
+        }
+
+        return getOffset(cal, cdate, y, time);
+    }
+
+    private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
+        synchronized (this) {
+            if (cacheStart != 0) {
+                if (time >= cacheStart && time < cacheEnd) {
+                    return rawOffset + dstSavings;
+                }
+                if (year == cacheYear) {
+                    return rawOffset;
+                }
+            }
+        }
+
+        long start = getStart(cal, cdate, year);
+        long end = getEnd(cal, cdate, year);
+        int offset = rawOffset;
+        if (start <= end) {
+            if (time >= start && time < end) {
+                offset += dstSavings;
+            }
+            synchronized (this) {
+                cacheYear = year;
+                cacheStart = start;
+                cacheEnd = end;
+            }
+        } else {
+            if (time < end) {
+                // TODO: support Gregorian cutover. The previous year
+                // may be in the other calendar system.
+                start = getStart(cal, cdate, year - 1);
+                if (time >= start) {
+                    offset += dstSavings;
+                }
+            } else if (time >= start) {
+                // TODO: support Gregorian cutover. The next year
+                // may be in the other calendar system.
+                end = getEnd(cal, cdate, year + 1);
+                if (time < end) {
+                    offset += dstSavings;
+                }
+            }
+            if (start <= end) {
+                synchronized (this) {
+                    // The start and end transitions are in multiple years.
+                    cacheYear = (long) startYear - 1;
+                    cacheStart = start;
+                    cacheEnd = end;
+                }
+            }
+        }
+        return offset;
+    }
+
+    private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
+        int time = startTime;
+        if (startTimeMode != UTC_TIME) {
+            time -= rawOffset;
+        }
+        return getTransition(cal, cdate, startMode, year, startMonth, startDay,
+                             startDayOfWeek, time);
+    }
+
+    private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
+        int time = endTime;
+        if (endTimeMode != UTC_TIME) {
+            time -= rawOffset;
+        }
+        if (endTimeMode == WALL_TIME) {
+            time -= dstSavings;
+        }
+        return getTransition(cal, cdate, endMode, year, endMonth, endDay,
+                                        endDayOfWeek, time);
+    }
+
+    private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
+                               int mode, int year, int month, int dayOfMonth,
+                               int dayOfWeek, int timeOfDay) {
+        cdate.setNormalizedYear(year);
+        cdate.setMonth(month + 1);
+        switch (mode) {
+        case DOM_MODE:
+            cdate.setDayOfMonth(dayOfMonth);
+            break;
+
+        case DOW_IN_MONTH_MODE:
+            cdate.setDayOfMonth(1);
+            if (dayOfMonth < 0) {
+                cdate.setDayOfMonth(cal.getMonthLength(cdate));
+            }
+            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
+            break;
+
+        case DOW_GE_DOM_MODE:
+            cdate.setDayOfMonth(dayOfMonth);
+            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
+            break;
+
+        case DOW_LE_DOM_MODE:
+            cdate.setDayOfMonth(dayOfMonth);
+            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
+            break;
+        }
+        return cal.getTime(cdate) + timeOfDay;
+    }
+
+    /**
+     * Gets the GMT offset for this time zone.
+     * @return the GMT offset value in milliseconds
+     * @see #setRawOffset
+     */
+    public int getRawOffset()
+    {
+        // The given date will be taken into account while
+        // we have the historical time zone data in place.
+        return rawOffset;
+    }
+
+    /**
+     * Sets the base time zone offset to GMT.
+     * This is the offset to add to UTC to get local time.
+     * @see #getRawOffset
+     */
+    public void setRawOffset(int offsetMillis)
+    {
+        this.rawOffset = offsetMillis;
+    }
+
+    /**
+     * Sets the amount of time in milliseconds that the clock is advanced
+     * during daylight saving time.
+     * @param millisSavedDuringDST the number of milliseconds the time is
+     * advanced with respect to standard time when the daylight saving time rules
+     * are in effect. A positive number, typically one hour (3600000).
+     * @see #getDSTSavings
+     * @since 1.2
+     */
+    public void setDSTSavings(int millisSavedDuringDST) {
+        if (millisSavedDuringDST <= 0) {
+            throw new IllegalArgumentException("Illegal daylight saving value: "
+                                               + millisSavedDuringDST);
+        }
+        dstSavings = millisSavedDuringDST;
+    }
+
+    /**
+     * Returns the amount of time in milliseconds that the clock is
+     * advanced during daylight saving time.
+     *
+     * @return the number of milliseconds the time is advanced with
+     * respect to standard time when the daylight saving rules are in
+     * effect, or 0 (zero) if this time zone doesn't observe daylight
+     * saving time.
+     *
+     * @see #setDSTSavings
+     * @since 1.2
+     */
+    public int getDSTSavings() {
+        return useDaylight ? dstSavings : 0;
+    }
+
+    /**
+     * Queries if this time zone uses daylight saving time.
+     * @return true if this time zone uses daylight saving time;
+     * false otherwise.
+     */
+    public boolean useDaylightTime()
+    {
+        return useDaylight;
+    }
+
+    /**
+     * Returns {@code true} if this {@code SimpleTimeZone} observes
+     * Daylight Saving Time. This method is equivalent to {@link
+     * #useDaylightTime()}.
+     *
+     * @return {@code true} if this {@code SimpleTimeZone} observes
+     * Daylight Saving Time; {@code false} otherwise.
+     * @since 1.7
+     */
+    @Override
+    public boolean observesDaylightTime() {
+        return useDaylightTime();
+    }
+
+    /**
+     * Queries if the given date is in daylight saving time.
+     * @return true if daylight saving time is in effective at the
+     * given date; false otherwise.
+     */
+    public boolean inDaylightTime(Date date)
+    {
+        return (getOffset(date.getTime()) != rawOffset);
+    }
+
+    /**
+     * Returns a clone of this <code>SimpleTimeZone</code> instance.
+     * @return a clone of this instance.
+     */
+    public Object clone()
+    {
+        return super.clone();
+    }
+
+    /**
+     * Generates the hash code for the SimpleDateFormat object.
+     * @return the hash code for this object
+     */
+    public synchronized int hashCode()
+    {
+        return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
+            endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
+    }
+
+    /**
+     * Compares the equality of two <code>SimpleTimeZone</code> objects.
+     *
+     * @param obj  The <code>SimpleTimeZone</code> object to be compared with.
+     * @return     True if the given <code>obj</code> is the same as this
+     *             <code>SimpleTimeZone</code> object; false otherwise.
+     */
+    public boolean equals(Object obj)
+    {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SimpleTimeZone)) {
+            return false;
+        }
+
+        SimpleTimeZone that = (SimpleTimeZone) obj;
+
+        return getID().equals(that.getID()) &&
+            hasSameRules(that);
+    }
+
+    /**
+     * Returns <code>true</code> if this zone has the same rules and offset as another zone.
+     * @param other the TimeZone object to be compared with
+     * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
+     * same rules and offset as this one
+     * @since 1.2
+     */
+    public boolean hasSameRules(TimeZone other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof SimpleTimeZone)) {
+            return false;
+        }
+        SimpleTimeZone that = (SimpleTimeZone) other;
+        return rawOffset == that.rawOffset &&
+            useDaylight == that.useDaylight &&
+            (!useDaylight
+             // Only check rules if using DST
+             || (dstSavings == that.dstSavings &&
+                 startMode == that.startMode &&
+                 startMonth == that.startMonth &&
+                 startDay == that.startDay &&
+                 startDayOfWeek == that.startDayOfWeek &&
+                 startTime == that.startTime &&
+                 startTimeMode == that.startTimeMode &&
+                 endMode == that.endMode &&
+                 endMonth == that.endMonth &&
+                 endDay == that.endDay &&
+                 endDayOfWeek == that.endDayOfWeek &&
+                 endTime == that.endTime &&
+                 endTimeMode == that.endTimeMode &&
+                 startYear == that.startYear));
+    }
+
+    /**
+     * Returns a string representation of this time zone.
+     * @return a string representation of this time zone.
+     */
+    public String toString() {
+        return getClass().getName() +
+            "[id=" + getID() +
+            ",offset=" + rawOffset +
+            ",dstSavings=" + dstSavings +
+            ",useDaylight=" + useDaylight +
+            ",startYear=" + startYear +
+            ",startMode=" + startMode +
+            ",startMonth=" + startMonth +
+            ",startDay=" + startDay +
+            ",startDayOfWeek=" + startDayOfWeek +
+            ",startTime=" + startTime +
+            ",startTimeMode=" + startTimeMode +
+            ",endMode=" + endMode +
+            ",endMonth=" + endMonth +
+            ",endDay=" + endDay +
+            ",endDayOfWeek=" + endDayOfWeek +
+            ",endTime=" + endTime +
+            ",endTimeMode=" + endTimeMode + ']';
+    }
+
+    // =======================privates===============================
+
+    /**
+     * The month in which daylight saving time starts.  This value must be
+     * between <code>Calendar.JANUARY</code> and
+     * <code>Calendar.DECEMBER</code> inclusive.  This value must not equal
+     * <code>endMonth</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startMonth;
+
+    /**
+     * This field has two possible interpretations:
+     * <dl>
+     * <dt><code>startMode == DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>startDay</code> indicates the day of the month of
+     * <code>startMonth</code> on which daylight
+     * saving time starts, from 1 to 28, 30, or 31, depending on the
+     * <code>startMonth</code>.
+     * </dd>
+     * <dt><code>startMode != DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
+     * month <code>startMonth</code> daylight
+     * saving time starts on.  For example, a value of +1 and a
+     * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
+     * first Sunday of <code>startMonth</code>.  Likewise, +2 would indicate the
+     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
+     * </dd>
+     * </dl>
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startDay;
+
+    /**
+     * The day of the week on which daylight saving time starts.  This value
+     * must be between <code>Calendar.SUNDAY</code> and
+     * <code>Calendar.SATURDAY</code> inclusive.
+     * <p>If <code>useDaylight</code> is false or
+     * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
+     * @serial
+     */
+    private int startDayOfWeek;
+
+    /**
+     * The time in milliseconds after midnight at which daylight saving
+     * time starts.  This value is expressed as wall time, standard time,
+     * or UTC time, depending on the setting of <code>startTimeMode</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startTime;
+
+    /**
+     * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
+     * @serial
+     * @since 1.3
+     */
+    private int startTimeMode;
+
+    /**
+     * The month in which daylight saving time ends.  This value must be
+     * between <code>Calendar.JANUARY</code> and
+     * <code>Calendar.UNDECIMBER</code>.  This value must not equal
+     * <code>startMonth</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int endMonth;
+
+    /**
+     * This field has two possible interpretations:
+     * <dl>
+     * <dt><code>endMode == DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>endDay</code> indicates the day of the month of
+     * <code>endMonth</code> on which daylight
+     * saving time ends, from 1 to 28, 30, or 31, depending on the
+     * <code>endMonth</code>.
+     * </dd>
+     * <dt><code>endMode != DOW_IN_MONTH</code></dt>
+     * <dd>
+     * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
+     * month <code>endMonth</code> daylight
+     * saving time ends on.  For example, a value of +1 and a
+     * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
+     * first Sunday of <code>endMonth</code>.  Likewise, +2 would indicate the
+     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
+     * </dd>
+     * </dl>
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int endDay;
+
+    /**
+     * The day of the week on which daylight saving time ends.  This value
+     * must be between <code>Calendar.SUNDAY</code> and
+     * <code>Calendar.SATURDAY</code> inclusive.
+     * <p>If <code>useDaylight</code> is false or
+     * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
+     * @serial
+     */
+    private int endDayOfWeek;
+
+    /**
+     * The time in milliseconds after midnight at which daylight saving
+     * time ends.  This value is expressed as wall time, standard time,
+     * or UTC time, depending on the setting of <code>endTimeMode</code>.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int endTime;
+
+    /**
+     * The format of endTime, either <code>WALL_TIME</code>,
+     * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
+     * @serial
+     * @since 1.3
+     */
+    private int endTimeMode;
+
+    /**
+     * The year in which daylight saving time is first observed.  This is an {@link GregorianCalendar#AD AD}
+     * value.  If this value is less than 1 then daylight saving time is observed
+     * for all <code>AD</code> years.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     */
+    private int startYear;
+
+    /**
+     * The offset in milliseconds between this zone and GMT.  Negative offsets
+     * are to the west of Greenwich.  To obtain local <em>standard</em> time,
+     * add the offset to GMT time.  To obtain local wall time it may also be
+     * necessary to add <code>dstSavings</code>.
+     * @serial
+     */
+    private int rawOffset;
+
+    /**
+     * A boolean value which is true if and only if this zone uses daylight
+     * saving time.  If this value is false, several other fields are ignored.
+     * @serial
+     */
+    private boolean useDaylight=false; // indicate if this time zone uses DST
+
+    private static final int millisPerHour = 60*60*1000;
+    private static final int millisPerDay  = 24*millisPerHour;
+
+    /**
+     * This field was serialized in JDK 1.1, so we have to keep it that way
+     * to maintain serialization compatibility. However, there's no need to
+     * recreate the array each time we create a new time zone.
+     * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
+     * 31, 31, 30, 31, 30, 31}.  This is ignored as of the Java 2 platform v1.2, however, it must
+     * be streamed out for compatibility with JDK 1.1.
+     */
+    private final byte monthLength[] = staticMonthLength;
+    private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+    private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
+
+    /**
+     * Variables specifying the mode of the start rule.  Takes the following
+     * values:
+     * <dl>
+     * <dt><code>DOM_MODE</code></dt>
+     * <dd>
+     * Exact day of week; e.g., March 1.
+     * </dd>
+     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
+     * <dd>
+     * Day of week in month; e.g., last Sunday in March.
+     * </dd>
+     * <dt><code>DOW_GE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week after day of month; e.g., Sunday on or after March 15.
+     * </dd>
+     * <dt><code>DOW_LE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week before day of month; e.g., Sunday on or before March 15.
+     * </dd>
+     * </dl>
+     * The setting of this field affects the interpretation of the
+     * <code>startDay</code> field.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int startMode;
+
+    /**
+     * Variables specifying the mode of the end rule.  Takes the following
+     * values:
+     * <dl>
+     * <dt><code>DOM_MODE</code></dt>
+     * <dd>
+     * Exact day of week; e.g., March 1.
+     * </dd>
+     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
+     * <dd>
+     * Day of week in month; e.g., last Sunday in March.
+     * </dd>
+     * <dt><code>DOW_GE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week after day of month; e.g., Sunday on or after March 15.
+     * </dd>
+     * <dt><code>DOW_LE_DOM_MODE</code></dt>
+     * <dd>
+     * Day of week before day of month; e.g., Sunday on or before March 15.
+     * </dd>
+     * </dl>
+     * The setting of this field affects the interpretation of the
+     * <code>endDay</code> field.
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int endMode;
+
+    /**
+     * A positive value indicating the amount of time saved during DST in
+     * milliseconds.
+     * Typically one hour (3600000); sometimes 30 minutes (1800000).
+     * <p>If <code>useDaylight</code> is false, this value is ignored.
+     * @serial
+     * @since 1.1.4
+     */
+    private int dstSavings;
+
+    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
+
+    /**
+     * Cache values representing a single period of daylight saving
+     * time. When the cache values are valid, cacheStart is the start
+     * time (inclusive) of daylight saving time and cacheEnd is the
+     * end time (exclusive).
+     *
+     * cacheYear has a year value if both cacheStart and cacheEnd are
+     * in the same year. cacheYear is set to startYear - 1 if
+     * cacheStart and cacheEnd are in different years. cacheStart is 0
+     * if the cache values are void. cacheYear is a long to support
+     * Integer.MIN_VALUE - 1 (JCK requirement).
+     */
+    private transient long cacheYear;
+    private transient long cacheStart;
+    private transient long cacheEnd;
+
+    /**
+     * Constants specifying values of startMode and endMode.
+     */
+    private static final int DOM_MODE          = 1; // Exact day of month, "Mar 1"
+    private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
+    private static final int DOW_GE_DOM_MODE   = 3; // Day of week after day of month, "Sun>=15"
+    private static final int DOW_LE_DOM_MODE   = 4; // Day of week before day of month, "Sun<=21"
+
+    /**
+     * Constant for a mode of start or end time specified as wall clock
+     * time.  Wall clock time is standard time for the onset rule, and
+     * daylight time for the end rule.
+     * @since 1.4
+     */
+    public static final int WALL_TIME = 0; // Zero for backward compatibility
+
+    /**
+     * Constant for a mode of start or end time specified as standard time.
+     * @since 1.4
+     */
+    public static final int STANDARD_TIME = 1;
+
+    /**
+     * Constant for a mode of start or end time specified as UTC. European
+     * Union rules are specified as UTC time, for example.
+     * @since 1.4
+     */
+    public static final int UTC_TIME = 2;
+
+    // Proclaim compatibility with 1.1
+    static final long serialVersionUID = -403250971215465050L;
+
+    // the internal serial version which says which version was written
+    // - 0 (default) for version up to JDK 1.1.3
+    // - 1 for version from JDK 1.1.4, which includes 3 new fields
+    // - 2 for JDK 1.3, which includes 2 new fields
+    static final int currentSerialVersion = 2;
+
+    /**
+     * The version of the serialized data on the stream.  Possible values:
+     * <dl>
+     * <dt><b>0</b> or not present on stream</dt>
+     * <dd>
+     * JDK 1.1.3 or earlier.
+     * </dd>
+     * <dt><b>1</b></dt>
+     * <dd>
+     * JDK 1.1.4 or later.  Includes three new fields: <code>startMode</code>,
+     * <code>endMode</code>, and <code>dstSavings</code>.
+     * </dd>
+     * <dt><b>2</b></dt>
+     * <dd>
+     * JDK 1.3 or later.  Includes two new fields: <code>startTimeMode</code>
+     * and <code>endTimeMode</code>.
+     * </dd>
+     * </dl>
+     * When streaming out this class, the most recent format
+     * and the highest allowable <code>serialVersionOnStream</code>
+     * is written.
+     * @serial
+     * @since 1.1.4
+     */
+    private int serialVersionOnStream = currentSerialVersion;
+
+    synchronized private void invalidateCache() {
+        cacheYear = startYear - 1;
+        cacheStart = cacheEnd = 0;
+    }
+
+    //----------------------------------------------------------------------
+    // Rule representation
+    //
+    // We represent the following flavors of rules:
+    //       5        the fifth of the month
+    //       lastSun  the last Sunday in the month
+    //       lastMon  the last Monday in the month
+    //       Sun>=8   first Sunday on or after the eighth
+    //       Sun<=25  last Sunday on or before the 25th
+    // This is further complicated by the fact that we need to remain
+    // backward compatible with the 1.1 FCS.  Finally, we need to minimize
+    // API changes.  In order to satisfy these requirements, we support
+    // three representation systems, and we translate between them.
+    //
+    // INTERNAL REPRESENTATION
+    // This is the format SimpleTimeZone objects take after construction or
+    // streaming in is complete.  Rules are represented directly, using an
+    // unencoded format.  We will discuss the start rule only below; the end
+    // rule is analogous.
+    //   startMode      Takes on enumerated values DAY_OF_MONTH,
+    //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
+    //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
+    //                  value indicating which DOW, such as +1 for first,
+    //                  +2 for second, -1 for last, etc.
+    //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
+    //
+    // ENCODED REPRESENTATION
+    // This is the format accepted by the constructor and by setStartRule()
+    // and setEndRule().  It uses various combinations of positive, negative,
+    // and zero values to encode the different rules.  This representation
+    // allows us to specify all the different rule flavors without altering
+    // the API.
+    //   MODE              startMonth    startDay    startDayOfWeek
+    //   DOW_IN_MONTH_MODE >=0           !=0         >0
+    //   DOM_MODE          >=0           >0          ==0
+    //   DOW_GE_DOM_MODE   >=0           >0          <0
+    //   DOW_LE_DOM_MODE   >=0           <0          <0
+    //   (no DST)          don't care    ==0         don't care
+    //
+    // STREAMED REPRESENTATION
+    // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
+    // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
+    // flag useDaylight.  When we stream an object out, we translate into an
+    // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
+    // and used by 1.1 code.  Following that, we write out the full
+    // representation separately so that contemporary code can recognize and
+    // parse it.  The full representation is written in a "packed" format,
+    // consisting of a version number, a length, and an array of bytes.  Future
+    // versions of this class may specify different versions.  If they wish to
+    // include additional data, they should do so by storing them after the
+    // packed representation below.
+    //----------------------------------------------------------------------
+
+    /**
+     * Given a set of encoded rules in startDay and startDayOfMonth, decode
+     * them and set the startMode appropriately.  Do the same for endDay and
+     * endDayOfMonth.  Upon entry, the day of week variables may be zero or
+     * negative, in order to indicate special modes.  The day of month
+     * variables may also be negative.  Upon exit, the mode variables will be
+     * set, and the day of week and day of month variables will be positive.
+     * This method also recognizes a startDay or endDay of zero as indicating
+     * no DST.
+     */
+    private void decodeRules()
+    {
+        decodeStartRule();
+        decodeEndRule();
+    }
+
+    /**
+     * Decode the start rule and validate the parameters.  The parameters are
+     * expected to be in encoded form, which represents the various rule modes
+     * by negating or zeroing certain values.  Representation formats are:
+     * <p>
+     * <pre>
+     *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
+     *            ------------  -----  --------  --------  ----------
+     * month       0..11        same    same      same     don't care
+     * day        -5..5         1..31   1..31    -1..-31   0
+     * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
+     * time        0..ONEDAY    same    same      same     don't care
+     * </pre>
+     * The range for month does not include UNDECIMBER since this class is
+     * really specific to GregorianCalendar, which does not use that month.
+     * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
+     * end rule is an exclusive limit point.  That is, the range of times that
+     * are in DST include those >= the start and < the end.  For this reason,
+     * it should be possible to specify an end of ONEDAY in order to include the
+     * entire day.  Although this is equivalent to time 0 of the following day,
+     * it's not always possible to specify that, for example, on December 31.
+     * While arguably the start range should still be 0..ONEDAY-1, we keep
+     * the start and end ranges the same for consistency.
+     */
+    private void decodeStartRule() {
+        useDaylight = (startDay != 0) && (endDay != 0);
+        if (startDay != 0) {
+            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
+                throw new IllegalArgumentException(
+                        "Illegal start month " + startMonth);
+            }
+            if (startTime < 0 || startTime > millisPerDay) {
+                throw new IllegalArgumentException(
+                        "Illegal start time " + startTime);
+            }
+            if (startDayOfWeek == 0) {
+                startMode = DOM_MODE;
+            } else {
+                if (startDayOfWeek > 0) {
+                    startMode = DOW_IN_MONTH_MODE;
+                } else {
+                    startDayOfWeek = -startDayOfWeek;
+                    if (startDay > 0) {
+                        startMode = DOW_GE_DOM_MODE;
+                    } else {
+                        startDay = -startDay;
+                        startMode = DOW_LE_DOM_MODE;
+                    }
+                }
+                if (startDayOfWeek > Calendar.SATURDAY) {
+                    throw new IllegalArgumentException(
+                           "Illegal start day of week " + startDayOfWeek);
+                }
+            }
+            if (startMode == DOW_IN_MONTH_MODE) {
+                if (startDay < -5 || startDay > 5) {
+                    throw new IllegalArgumentException(
+                            "Illegal start day of week in month " + startDay);
+                }
+            } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
+                throw new IllegalArgumentException(
+                        "Illegal start day " + startDay);
+            }
+        }
+    }
+
+    /**
+     * Decode the end rule and validate the parameters.  This method is exactly
+     * analogous to decodeStartRule().
+     * @see decodeStartRule
+     */
+    private void decodeEndRule() {
+        useDaylight = (startDay != 0) && (endDay != 0);
+        if (endDay != 0) {
+            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
+                throw new IllegalArgumentException(
+                        "Illegal end month " + endMonth);
+            }
+            if (endTime < 0 || endTime > millisPerDay) {
+                throw new IllegalArgumentException(
+                        "Illegal end time " + endTime);
+            }
+            if (endDayOfWeek == 0) {
+                endMode = DOM_MODE;
+            } else {
+                if (endDayOfWeek > 0) {
+                    endMode = DOW_IN_MONTH_MODE;
+                } else {
+                    endDayOfWeek = -endDayOfWeek;
+                    if (endDay > 0) {
+                        endMode = DOW_GE_DOM_MODE;
+                    } else {
+                        endDay = -endDay;
+                        endMode = DOW_LE_DOM_MODE;
+                    }
+                }
+                if (endDayOfWeek > Calendar.SATURDAY) {
+                    throw new IllegalArgumentException(
+                           "Illegal end day of week " + endDayOfWeek);
+                }
+            }
+            if (endMode == DOW_IN_MONTH_MODE) {
+                if (endDay < -5 || endDay > 5) {
+                    throw new IllegalArgumentException(
+                            "Illegal end day of week in month " + endDay);
+                }
+            } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
+                throw new IllegalArgumentException(
+                        "Illegal end day " + endDay);
+            }
+        }
+    }
+
+    /**
+     * Make rules compatible to 1.1 FCS code.  Since 1.1 FCS code only understands
+     * day-of-week-in-month rules, we must modify other modes of rules to their
+     * approximate equivalent in 1.1 FCS terms.  This method is used when streaming
+     * out objects of this class.  After it is called, the rules will be modified,
+     * with a possible loss of information.  startMode and endMode will NOT be
+     * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
+     * since the rule modification is only intended to be temporary.
+     */
+    private void makeRulesCompatible()
+    {
+        switch (startMode) {
+        case DOM_MODE:
+            startDay = 1 + (startDay / 7);
+            startDayOfWeek = Calendar.SUNDAY;
+            break;
+
+        case DOW_GE_DOM_MODE:
+            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
+            // that is, Sun>=1 == firstSun.
+            if (startDay != 1) {
+                startDay = 1 + (startDay / 7);
+            }
+            break;
+
+        case DOW_LE_DOM_MODE:
+            if (startDay >= 30) {
+                startDay = -1;
+            } else {
+                startDay = 1 + (startDay / 7);
+            }
+            break;
+        }
+
+        switch (endMode) {
+        case DOM_MODE:
+            endDay = 1 + (endDay / 7);
+            endDayOfWeek = Calendar.SUNDAY;
+            break;
+
+        case DOW_GE_DOM_MODE:
+            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
+            // that is, Sun>=1 == firstSun.
+            if (endDay != 1) {
+                endDay = 1 + (endDay / 7);
+            }
+            break;
+
+        case DOW_LE_DOM_MODE:
+            if (endDay >= 30) {
+                endDay = -1;
+            } else {
+                endDay = 1 + (endDay / 7);
+            }
+            break;
+        }
+
+        /*
+         * Adjust the start and end times to wall time.  This works perfectly
+         * well unless it pushes into the next or previous day.  If that
+         * happens, we attempt to adjust the day rule somewhat crudely.  The day
+         * rules have been forced into DOW_IN_MONTH mode already, so we change
+         * the day of week to move forward or back by a day.  It's possible to
+         * make a more refined adjustment of the original rules first, but in
+         * most cases this extra effort will go to waste once we adjust the day
+         * rules anyway.
+         */
+        switch (startTimeMode) {
+        case UTC_TIME:
+            startTime += rawOffset;
+            break;
+        }
+        while (startTime < 0) {
+            startTime += millisPerDay;
+            startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
+        }
+        while (startTime >= millisPerDay) {
+            startTime -= millisPerDay;
+            startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
+        }
+
+        switch (endTimeMode) {
+        case UTC_TIME:
+            endTime += rawOffset + dstSavings;
+            break;
+        case STANDARD_TIME:
+            endTime += dstSavings;
+        }
+        while (endTime < 0) {
+            endTime += millisPerDay;
+            endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
+        }
+        while (endTime >= millisPerDay) {
+            endTime -= millisPerDay;
+            endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
+        }
+    }
+
+    /**
+     * Pack the start and end rules into an array of bytes.  Only pack
+     * data which is not preserved by makeRulesCompatible.
+     */
+    private byte[] packRules()
+    {
+        byte[] rules = new byte[6];
+        rules[0] = (byte)startDay;
+        rules[1] = (byte)startDayOfWeek;
+        rules[2] = (byte)endDay;
+        rules[3] = (byte)endDayOfWeek;
+
+        // As of serial version 2, include time modes
+        rules[4] = (byte)startTimeMode;
+        rules[5] = (byte)endTimeMode;
+
+        return rules;
+    }
+
+    /**
+     * Given an array of bytes produced by packRules, interpret them
+     * as the start and end rules.
+     */
+    private void unpackRules(byte[] rules)
+    {
+        startDay       = rules[0];
+        startDayOfWeek = rules[1];
+        endDay         = rules[2];
+        endDayOfWeek   = rules[3];
+
+        // As of serial version 2, include time modes
+        if (rules.length >= 6) {
+            startTimeMode = rules[4];
+            endTimeMode   = rules[5];
+        }
+    }
+
+    /**
+     * Pack the start and end times into an array of bytes.  This is required
+     * as of serial version 2.
+     */
+    private int[] packTimes() {
+        int[] times = new int[2];
+        times[0] = startTime;
+        times[1] = endTime;
+        return times;
+    }
+
+    /**
+     * Unpack the start and end times from an array of bytes.  This is required
+     * as of serial version 2.
+     */
+    private void unpackTimes(int[] times) {
+        startTime = times[0];
+        endTime = times[1];
+    }
+
+    /**
+     * Save the state of this object to a stream (i.e., serialize it).
+     *
+     * @serialData We write out two formats, a JDK 1.1 compatible format, using
+     * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
+     * by the full rules, in packed format, in the optional section.  The
+     * optional section will be ignored by JDK 1.1 code upon stream in.
+     * <p> Contents of the optional section: The length of a byte array is
+     * emitted (int); this is 4 as of this release. The byte array of the given
+     * length is emitted. The contents of the byte array are the true values of
+     * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
+     * <code>endDay</code>, and <code>endDayOfWeek</code>.  The values of these
+     * fields in the required section are approximate values suited to the rule
+     * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
+     * JDK 1.1.
+     */
+    private void writeObject(ObjectOutputStream stream)
+         throws IOException
+    {
+        // Construct a binary rule
+        byte[] rules = packRules();
+        int[] times = packTimes();
+
+        // Convert to 1.1 FCS rules.  This step may cause us to lose information.
+        makeRulesCompatible();
+
+        // Write out the 1.1 FCS rules
+        stream.defaultWriteObject();
+
+        // Write out the binary rules in the optional data area of the stream.
+        stream.writeInt(rules.length);
+        stream.write(rules);
+        stream.writeObject(times);
+
+        // Recover the original rules.  This recovers the information lost
+        // by makeRulesCompatible.
+        unpackRules(rules);
+        unpackTimes(times);
+    }
+
+    /**
+     * Reconstitute this object from a stream (i.e., deserialize it).
+     *
+     * We handle both JDK 1.1
+     * binary formats and full formats with a packed byte array.
+     */
+    private void readObject(ObjectInputStream stream)
+         throws IOException, ClassNotFoundException
+    {
+        stream.defaultReadObject();
+
+        if (serialVersionOnStream < 1) {
+            // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
+            // startDayOfWeek and endDayOfWeek were usually uninitialized.  We can't do
+            // too much, so we assume SUNDAY, which actually works most of the time.
+            if (startDayOfWeek == 0) {
+                startDayOfWeek = Calendar.SUNDAY;
+            }
+            if (endDayOfWeek == 0) {
+                endDayOfWeek = Calendar.SUNDAY;
+            }
+
+            // The variables dstSavings, startMode, and endMode are post-1.1, so they
+            // won't be present if we're reading from a 1.1 stream.  Fix them up.
+            startMode = endMode = DOW_IN_MONTH_MODE;
+            dstSavings = millisPerHour;
+        } else {
+            // For 1.1.4, in addition to the 3 new instance variables, we also
+            // store the actual rules (which have not be made compatible with 1.1)
+            // in the optional area.  Read them in here and parse them.
+            int length = stream.readInt();
+            byte[] rules = new byte[length];
+            stream.readFully(rules);
+            unpackRules(rules);
+        }
+
+        if (serialVersionOnStream >= 2) {
+            int[] times = (int[]) stream.readObject();
+            unpackTimes(times);
+        }
+
+        serialVersionOnStream = currentSerialVersion;
+    }
+}
diff --git a/java/util/SortedMap.annotated.java b/java/util/SortedMap.annotated.java
new file mode 100644
index 0000000..9d68839
--- /dev/null
+++ b/java/util/SortedMap.annotated.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public interface SortedMap<K, V> extends java.util.Map<K,V> {
+
[email protected] public java.util.Comparator<? super @libcore.util.NullFromTypeParam K> comparator();
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, @libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey);
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey);
+
[email protected] public K firstKey();
+
[email protected] public K lastKey();
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet();
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values();
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet();
+}
diff --git a/java/util/SortedMap.java b/java/util/SortedMap.java
new file mode 100644
index 0000000..7f98152
--- /dev/null
+++ b/java/util/SortedMap.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link Map} that further provides a <em>total ordering</em> on its keys.
+ * The map is ordered according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} typically
+ * provided at sorted map creation time.  This order is reflected when
+ * iterating over the sorted map's collection views (returned by the
+ * {@code entrySet}, {@code keySet} and {@code values} methods).
+ * Several additional operations are provided to take advantage of the
+ * ordering.  (This interface is the map analogue of {@link SortedSet}.)
+ *
+ * <p>All keys inserted into a sorted map must implement the {@code Comparable}
+ * interface (or be accepted by the specified comparator).  Furthermore, all
+ * such keys must be <em>mutually comparable</em>: {@code k1.compareTo(k2)} (or
+ * {@code comparator.compare(k1, k2)}) must not throw a
+ * {@code ClassCastException} for any keys {@code k1} and {@code k2} in
+ * the sorted map.  Attempts to violate this restriction will cause the
+ * offending method or constructor invocation to throw a
+ * {@code ClassCastException}.
+ *
+ * <p>Note that the ordering maintained by a sorted map (whether or not an
+ * explicit comparator is provided) must be <em>consistent with equals</em> if
+ * the sorted map is to correctly implement the {@code Map} interface.  (See
+ * the {@code Comparable} interface or {@code Comparator} interface for a
+ * precise definition of <em>consistent with equals</em>.)  This is so because
+ * the {@code Map} interface is defined in terms of the {@code equals}
+ * operation, but a sorted map performs all key comparisons using its
+ * {@code compareTo} (or {@code compare}) method, so two keys that are
+ * deemed equal by this method are, from the standpoint of the sorted map,
+ * equal.  The behavior of a tree map <em>is</em> well-defined even if its
+ * ordering is inconsistent with equals; it just fails to obey the general
+ * contract of the {@code Map} interface.
+ *
+ * <p>All general-purpose sorted map implementation classes should provide four
+ * "standard" constructors. It is not possible to enforce this recommendation
+ * though as required constructors cannot be specified by interfaces. The
+ * expected "standard" constructors for all sorted map implementations are:
+ * <ol>
+ *   <li>A void (no arguments) constructor, which creates an empty sorted map
+ *   sorted according to the natural ordering of its keys.</li>
+ *   <li>A constructor with a single argument of type {@code Comparator}, which
+ *   creates an empty sorted map sorted according to the specified comparator.</li>
+ *   <li>A constructor with a single argument of type {@code Map}, which creates
+ *   a new map with the same key-value mappings as its argument, sorted
+ *   according to the keys' natural ordering.</li>
+ *   <li>A constructor with a single argument of type {@code SortedMap}, which
+ *   creates a new sorted map with the same key-value mappings and the same
+ *   ordering as the input sorted map.</li>
+ * </ol>
+ *
+ * <p><strong>Note</strong>: several methods return submaps with restricted key
+ * ranges. Such ranges are <em>half-open</em>, that is, they include their low
+ * endpoint but not their high endpoint (where applicable).  If you need a
+ * <em>closed range</em> (which includes both endpoints), and the key type
+ * allows for calculation of the successor of a given key, merely request
+ * the subrange from {@code lowEndpoint} to
+ * {@code successor(highEndpoint)}.  For example, suppose that {@code m}
+ * is a map whose keys are strings.  The following idiom obtains a view
+ * containing all of the key-value mappings in {@code m} whose keys are
+ * between {@code low} and {@code high}, inclusive:<pre>
+ *   SortedMap&lt;String, V&gt; sub = m.subMap(low, high+"\0");</pre>
+ *
+ * A similar technique can be used to generate an <em>open range</em>
+ * (which contains neither endpoint).  The following idiom obtains a
+ * view containing all of the key-value mappings in {@code m} whose keys
+ * are between {@code low} and {@code high}, exclusive:<pre>
+ *   SortedMap&lt;String, V&gt; sub = m.subMap(low+"\0", high);</pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch
+ * @see Map
+ * @see TreeMap
+ * @see SortedSet
+ * @see Comparator
+ * @see Comparable
+ * @see Collection
+ * @see ClassCastException
+ * @since 1.2
+ */
+
+public interface SortedMap<K,V> extends Map<K,V> {
+    /**
+     * Returns the comparator used to order the keys in this map, or
+     * {@code null} if this map uses the {@linkplain Comparable
+     * natural ordering} of its keys.
+     *
+     * @return the comparator used to order the keys in this map,
+     *         or {@code null} if this map uses the natural ordering
+     *         of its keys
+     */
+    Comparator<? super K> comparator();
+
+    /**
+     * Returns a view of the portion of this map whose keys range from
+     * {@code fromKey}, inclusive, to {@code toKey}, exclusive.  (If
+     * {@code fromKey} and {@code toKey} are equal, the returned map
+     * is empty.)  The returned map is backed by this map, so changes
+     * in the returned map are reflected in this map, and vice-versa.
+     * The returned map supports all optional map operations that this
+     * map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint (inclusive) of the keys in the returned map
+     * @param toKey high endpoint (exclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys range from
+     *         {@code fromKey}, inclusive, to {@code toKey}, exclusive
+     * @throws ClassCastException if {@code fromKey} and {@code toKey}
+     *         cannot be compared to one another using this map's comparator
+     *         (or, if the map has no comparator, using natural ordering).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} or {@code toKey}
+     *         cannot be compared to keys currently in the map.
+     * @throws NullPointerException if {@code fromKey} or {@code toKey}
+     *         is null and this map does not permit null keys
+     * @throws IllegalArgumentException if {@code fromKey} is greater than
+     *         {@code toKey}; or if this map itself has a restricted
+     *         range, and {@code fromKey} or {@code toKey} lies
+     *         outside the bounds of the range
+     */
+    SortedMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * Returns a view of the portion of this map whose keys are
+     * strictly less than {@code toKey}.  The returned map is backed
+     * by this map, so changes in the returned map are reflected in
+     * this map, and vice-versa.  The returned map supports all
+     * optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param toKey high endpoint (exclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys are strictly
+     *         less than {@code toKey}
+     * @throws ClassCastException if {@code toKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code toKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code toKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code toKey} is null and
+     *         this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code toKey} lies outside the
+     *         bounds of the range
+     */
+    SortedMap<K,V> headMap(K toKey);
+
+    /**
+     * Returns a view of the portion of this map whose keys are
+     * greater than or equal to {@code fromKey}.  The returned map is
+     * backed by this map, so changes in the returned map are
+     * reflected in this map, and vice-versa.  The returned map
+     * supports all optional map operations that this map supports.
+     *
+     * <p>The returned map will throw an {@code IllegalArgumentException}
+     * on an attempt to insert a key outside its range.
+     *
+     * @param fromKey low endpoint (inclusive) of the keys in the returned map
+     * @return a view of the portion of this map whose keys are greater
+     *         than or equal to {@code fromKey}
+     * @throws ClassCastException if {@code fromKey} is not compatible
+     *         with this map's comparator (or, if the map has no comparator,
+     *         if {@code fromKey} does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if {@code fromKey} cannot be compared to keys
+     *         currently in the map.
+     * @throws NullPointerException if {@code fromKey} is null and
+     *         this map does not permit null keys
+     * @throws IllegalArgumentException if this map itself has a
+     *         restricted range, and {@code fromKey} lies outside the
+     *         bounds of the range
+     */
+    SortedMap<K,V> tailMap(K fromKey);
+
+    /**
+     * Returns the first (lowest) key currently in this map.
+     *
+     * @return the first (lowest) key currently in this map
+     * @throws NoSuchElementException if this map is empty
+     */
+    K firstKey();
+
+    /**
+     * Returns the last (highest) key currently in this map.
+     *
+     * @return the last (highest) key currently in this map
+     * @throws NoSuchElementException if this map is empty
+     */
+    K lastKey();
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * @return a set view of the keys contained in this map, sorted in
+     *         ascending order
+     */
+    Set<K> keySet();
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection's iterator returns the values in ascending order
+     * of the corresponding keys.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return a collection view of the values contained in this map,
+     *         sorted in ascending key order
+     */
+    Collection<V> values();
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set's iterator returns the entries in ascending key order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     *
+     * @return a set view of the mappings contained in this map,
+     *         sorted in ascending key order
+     */
+    Set<Map.Entry<K, V>> entrySet();
+}
diff --git a/java/util/SortedSet.java b/java/util/SortedSet.java
new file mode 100644
index 0000000..3ea9329
--- /dev/null
+++ b/java/util/SortedSet.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link Set} that further provides a <i>total ordering</i> on its elements.
+ * The elements are ordered using their {@linkplain Comparable natural
+ * ordering}, or by a {@link Comparator} typically provided at sorted
+ * set creation time.  The set's iterator will traverse the set in
+ * ascending element order. Several additional operations are provided
+ * to take advantage of the ordering.  (This interface is the set
+ * analogue of {@link SortedMap}.)
+ *
+ * <p>All elements inserted into a sorted set must implement the <tt>Comparable</tt>
+ * interface (or be accepted by the specified comparator).  Furthermore, all
+ * such elements must be <i>mutually comparable</i>: <tt>e1.compareTo(e2)</tt>
+ * (or <tt>comparator.compare(e1, e2)</tt>) must not throw a
+ * <tt>ClassCastException</tt> for any elements <tt>e1</tt> and <tt>e2</tt> in
+ * the sorted set.  Attempts to violate this restriction will cause the
+ * offending method or constructor invocation to throw a
+ * <tt>ClassCastException</tt>.
+ *
+ * <p>Note that the ordering maintained by a sorted set (whether or not an
+ * explicit comparator is provided) must be <i>consistent with equals</i> if
+ * the sorted set is to correctly implement the <tt>Set</tt> interface.  (See
+ * the <tt>Comparable</tt> interface or <tt>Comparator</tt> interface for a
+ * precise definition of <i>consistent with equals</i>.)  This is so because
+ * the <tt>Set</tt> interface is defined in terms of the <tt>equals</tt>
+ * operation, but a sorted set performs all element comparisons using its
+ * <tt>compareTo</tt> (or <tt>compare</tt>) method, so two elements that are
+ * deemed equal by this method are, from the standpoint of the sorted set,
+ * equal.  The behavior of a sorted set <i>is</i> well-defined even if its
+ * ordering is inconsistent with equals; it just fails to obey the general
+ * contract of the <tt>Set</tt> interface.
+ *
+ * <p>All general-purpose sorted set implementation classes should
+ * provide four "standard" constructors: 1) A void (no arguments)
+ * constructor, which creates an empty sorted set sorted according to
+ * the natural ordering of its elements.  2) A constructor with a
+ * single argument of type <tt>Comparator</tt>, which creates an empty
+ * sorted set sorted according to the specified comparator.  3) A
+ * constructor with a single argument of type <tt>Collection</tt>,
+ * which creates a new sorted set with the same elements as its
+ * argument, sorted according to the natural ordering of the elements.
+ * 4) A constructor with a single argument of type <tt>SortedSet</tt>,
+ * which creates a new sorted set with the same elements and the same
+ * ordering as the input sorted set.  There is no way to enforce this
+ * recommendation, as interfaces cannot contain constructors.
+ *
+ * <p>Note: several methods return subsets with restricted ranges.
+ * Such ranges are <i>half-open</i>, that is, they include their low
+ * endpoint but not their high endpoint (where applicable).
+ * If you need a <i>closed range</i> (which includes both endpoints), and
+ * the element type allows for calculation of the successor of a given
+ * value, merely request the subrange from <tt>lowEndpoint</tt> to
+ * <tt>successor(highEndpoint)</tt>.  For example, suppose that <tt>s</tt>
+ * is a sorted set of strings.  The following idiom obtains a view
+ * containing all of the strings in <tt>s</tt> from <tt>low</tt> to
+ * <tt>high</tt>, inclusive:<pre>
+ *   SortedSet&lt;String&gt; sub = s.subSet(low, high+"\0");</pre>
+ *
+ * A similar technique can be used to generate an <i>open range</i> (which
+ * contains neither endpoint).  The following idiom obtains a view
+ * containing all of the Strings in <tt>s</tt> from <tt>low</tt> to
+ * <tt>high</tt>, exclusive:<pre>
+ *   SortedSet&lt;String&gt; sub = s.subSet(low+"\0", high);</pre>
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see Set
+ * @see TreeSet
+ * @see SortedMap
+ * @see Collection
+ * @see Comparable
+ * @see Comparator
+ * @see ClassCastException
+ * @since 1.2
+ */
+
+public interface SortedSet<E> extends Set<E> {
+    /**
+     * Returns the comparator used to order the elements in this set,
+     * or <tt>null</tt> if this set uses the {@linkplain Comparable
+     * natural ordering} of its elements.
+     *
+     * @return the comparator used to order the elements in this set,
+     *         or <tt>null</tt> if this set uses the natural ordering
+     *         of its elements
+     */
+    Comparator<? super E> comparator();
+
+    /**
+     * Returns a view of the portion of this set whose elements range
+     * from <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>,
+     * exclusive.  (If <tt>fromElement</tt> and <tt>toElement</tt> are
+     * equal, the returned set is empty.)  The returned set is backed
+     * by this set, so changes in the returned set are reflected in
+     * this set, and vice-versa.  The returned set supports all
+     * optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an <tt>IllegalArgumentException</tt>
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint (inclusive) of the returned set
+     * @param toElement high endpoint (exclusive) of the returned set
+     * @return a view of the portion of this set whose elements range from
+     *         <tt>fromElement</tt>, inclusive, to <tt>toElement</tt>, exclusive
+     * @throws ClassCastException if <tt>fromElement</tt> and
+     *         <tt>toElement</tt> cannot be compared to one another using this
+     *         set's comparator (or, if the set has no comparator, using
+     *         natural ordering).  Implementations may, but are not required
+     *         to, throw this exception if <tt>fromElement</tt> or
+     *         <tt>toElement</tt> cannot be compared to elements currently in
+     *         the set.
+     * @throws NullPointerException if <tt>fromElement</tt> or
+     *         <tt>toElement</tt> is null and this set does not permit null
+     *         elements
+     * @throws IllegalArgumentException if <tt>fromElement</tt> is
+     *         greater than <tt>toElement</tt>; or if this set itself
+     *         has a restricted range, and <tt>fromElement</tt> or
+     *         <tt>toElement</tt> lies outside the bounds of the range
+     */
+    SortedSet<E> subSet(E fromElement, E toElement);
+
+    /**
+     * Returns a view of the portion of this set whose elements are
+     * strictly less than <tt>toElement</tt>.  The returned set is
+     * backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set
+     * supports all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an <tt>IllegalArgumentException</tt>
+     * on an attempt to insert an element outside its range.
+     *
+     * @param toElement high endpoint (exclusive) of the returned set
+     * @return a view of the portion of this set whose elements are strictly
+     *         less than <tt>toElement</tt>
+     * @throws ClassCastException if <tt>toElement</tt> is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if <tt>toElement</tt> does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if <tt>toElement</tt> cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if <tt>toElement</tt> is null and
+     *         this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and <tt>toElement</tt> lies outside the
+     *         bounds of the range
+     */
+    SortedSet<E> headSet(E toElement);
+
+    /**
+     * Returns a view of the portion of this set whose elements are
+     * greater than or equal to <tt>fromElement</tt>.  The returned
+     * set is backed by this set, so changes in the returned set are
+     * reflected in this set, and vice-versa.  The returned set
+     * supports all optional set operations that this set supports.
+     *
+     * <p>The returned set will throw an <tt>IllegalArgumentException</tt>
+     * on an attempt to insert an element outside its range.
+     *
+     * @param fromElement low endpoint (inclusive) of the returned set
+     * @return a view of the portion of this set whose elements are greater
+     *         than or equal to <tt>fromElement</tt>
+     * @throws ClassCastException if <tt>fromElement</tt> is not compatible
+     *         with this set's comparator (or, if the set has no comparator,
+     *         if <tt>fromElement</tt> does not implement {@link Comparable}).
+     *         Implementations may, but are not required to, throw this
+     *         exception if <tt>fromElement</tt> cannot be compared to elements
+     *         currently in the set.
+     * @throws NullPointerException if <tt>fromElement</tt> is null
+     *         and this set does not permit null elements
+     * @throws IllegalArgumentException if this set itself has a
+     *         restricted range, and <tt>fromElement</tt> lies outside the
+     *         bounds of the range
+     */
+    SortedSet<E> tailSet(E fromElement);
+
+    /**
+     * Returns the first (lowest) element currently in this set.
+     *
+     * @return the first (lowest) element currently in this set
+     * @throws NoSuchElementException if this set is empty
+     */
+    E first();
+
+    /**
+     * Returns the last (highest) element currently in this set.
+     *
+     * @return the last (highest) element currently in this set
+     * @throws NoSuchElementException if this set is empty
+     */
+    E last();
+
+    /**
+     * Creates a {@code Spliterator} over the elements in this sorted set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}.
+     * Implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) must be {@code null} if
+     * the sorted set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator must be the same as or impose the
+     * same total ordering as the sorted set's comparator.
+     *
+     * @implSpec
+     * The default implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the sorted set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.  The
+     * spliterator's comparator is the same as the sorted set's comparator.
+     * <p>
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SIZED}.
+     *
+     * @implNote
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this sorted set
+     * @since 1.8
+     */
+    @Override
+    default Spliterator<E> spliterator() {
+        return new Spliterators.IteratorSpliterator<E>(
+                this, Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED) {
+            @Override
+            public Comparator<? super E> getComparator() {
+                return SortedSet.this.comparator();
+            }
+        };
+    }
+}
diff --git a/java/util/Spliterator.java b/java/util/Spliterator.java
new file mode 100644
index 0000000..35322b3
--- /dev/null
+++ b/java/util/Spliterator.java
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * An object for traversing and partitioning elements of a source.  The source
+ * of elements covered by a Spliterator could be, for example, an array, a
+ * {@link Collection}, an IO channel, or a generator function.
+ *
+ * <p>A Spliterator may traverse elements individually ({@link
+ * #tryAdvance tryAdvance()}) or sequentially in bulk
+ * ({@link #forEachRemaining forEachRemaining()}).
+ *
+ * <p>A Spliterator may also partition off some of its elements (using
+ * {@link #trySplit}) as another Spliterator, to be used in
+ * possibly-parallel operations.  Operations using a Spliterator that
+ * cannot split, or does so in a highly imbalanced or inefficient
+ * manner, are unlikely to benefit from parallelism.  Traversal
+ * and splitting exhaust elements; each Spliterator is useful for only a single
+ * bulk computation.
+ *
+ * <p>A Spliterator also reports a set of {@link #characteristics()} of its
+ * structure, source, and elements from among {@link #ORDERED},
+ * {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED}, {@link #NONNULL},
+ * {@link #IMMUTABLE}, {@link #CONCURRENT}, and {@link #SUBSIZED}. These may
+ * be employed by Spliterator clients to control, specialize or simplify
+ * computation.  For example, a Spliterator for a {@link Collection} would
+ * report {@code SIZED}, a Spliterator for a {@link Set} would report
+ * {@code DISTINCT}, and a Spliterator for a {@link SortedSet} would also
+ * report {@code SORTED}.  Characteristics are reported as a simple unioned bit
+ * set.
+ *
+ * Some characteristics additionally constrain method behavior; for example if
+ * {@code ORDERED}, traversal methods must conform to their documented ordering.
+ * New characteristics may be defined in the future, so implementors should not
+ * assign meanings to unlisted values.
+ *
+ * <p><a name="binding">A Spliterator that does not report {@code IMMUTABLE} or
+ * {@code CONCURRENT} is expected to have a documented policy concerning:
+ * when the spliterator <em>binds</em> to the element source; and detection of
+ * structural interference of the element source detected after binding.</a>  A
+ * <em>late-binding</em> Spliterator binds to the source of elements at the
+ * point of first traversal, first split, or first query for estimated size,
+ * rather than at the time the Spliterator is created.  A Spliterator that is
+ * not <em>late-binding</em> binds to the source of elements at the point of
+ * construction or first invocation of any method.  Modifications made to the
+ * source prior to binding are reflected when the Spliterator is traversed.
+ * After binding a Spliterator should, on a best-effort basis, throw
+ * {@link ConcurrentModificationException} if structural interference is
+ * detected.  Spliterators that do this are called <em>fail-fast</em>.  The
+ * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a
+ * Spliterator may optimize traversal and check for structural interference
+ * after all elements have been traversed, rather than checking per-element and
+ * failing immediately.
+ *
+ * <p>Spliterators can provide an estimate of the number of remaining elements
+ * via the {@link #estimateSize} method.  Ideally, as reflected in characteristic
+ * {@link #SIZED}, this value corresponds exactly to the number of elements
+ * that would be encountered in a successful traversal.  However, even when not
+ * exactly known, an estimated value value may still be useful to operations
+ * being performed on the source, such as helping to determine whether it is
+ * preferable to split further or traverse the remaining elements sequentially.
+ *
+ * <p>Despite their obvious utility in parallel algorithms, spliterators are not
+ * expected to be thread-safe; instead, implementations of parallel algorithms
+ * using spliterators should ensure that the spliterator is only used by one
+ * thread at a time.  This is generally easy to attain via <em>serial
+ * thread-confinement</em>, which often is a natural consequence of typical
+ * parallel algorithms that work by recursive decomposition.  A thread calling
+ * {@link #trySplit()} may hand over the returned Spliterator to another thread,
+ * which in turn may traverse or further split that Spliterator.  The behaviour
+ * of splitting and traversal is undefined if two or more threads operate
+ * concurrently on the same spliterator.  If the original thread hands a
+ * spliterator off to another thread for processing, it is best if that handoff
+ * occurs before any elements are consumed with {@link #tryAdvance(Consumer)
+ * tryAdvance()}, as certain guarantees (such as the accuracy of
+ * {@link #estimateSize()} for {@code SIZED} spliterators) are only valid before
+ * traversal has begun.
+ *
+ * <p>Primitive subtype specializations of {@code Spliterator} are provided for
+ * {@link OfInt int}, {@link OfLong long}, and {@link OfDouble double} values.
+ * The subtype default implementations of
+ * {@link Spliterator#tryAdvance(java.util.function.Consumer)}
+ * and {@link Spliterator#forEachRemaining(java.util.function.Consumer)} box
+ * primitive values to instances of their corresponding wrapper class.  Such
+ * boxing may undermine any performance advantages gained by using the primitive
+ * specializations.  To avoid boxing, the corresponding primitive-based methods
+ * should be used.  For example,
+ * {@link Spliterator.OfInt#tryAdvance(java.util.function.IntConsumer)}
+ * and {@link Spliterator.OfInt#forEachRemaining(java.util.function.IntConsumer)}
+ * should be used in preference to
+ * {@link Spliterator.OfInt#tryAdvance(java.util.function.Consumer)} and
+ * {@link Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)}.
+ * Traversal of primitive values using boxing-based methods
+ * {@link #tryAdvance tryAdvance()} and
+ * {@link #forEachRemaining(java.util.function.Consumer) forEachRemaining()}
+ * does not affect the order in which the values, transformed to boxed values,
+ * are encountered.
+ *
+ * @apiNote
+ * <p>Spliterators, like {@code Iterator}s, are for traversing the elements of
+ * a source.  The {@code Spliterator} API was designed to support efficient
+ * parallel traversal in addition to sequential traversal, by supporting
+ * decomposition as well as single-element iteration.  In addition, the
+ * protocol for accessing elements via a Spliterator is designed to impose
+ * smaller per-element overhead than {@code Iterator}, and to avoid the inherent
+ * race involved in having separate methods for {@code hasNext()} and
+ * {@code next()}.
+ *
+ * <p>For mutable sources, arbitrary and non-deterministic behavior may occur if
+ * the source is structurally interfered with (elements added, replaced, or
+ * removed) between the time that the Spliterator binds to its data source and
+ * the end of traversal.  For example, such interference will produce arbitrary,
+ * non-deterministic results when using the {@code java.util.stream} framework.
+ *
+ * <p>Structural interference of a source can be managed in the following ways
+ * (in approximate order of decreasing desirability):
+ * <ul>
+ * <li>The source cannot be structurally interfered with.
+ * <br>For example, an instance of
+ * {@link java.util.concurrent.CopyOnWriteArrayList} is an immutable source.
+ * A Spliterator created from the source reports a characteristic of
+ * {@code IMMUTABLE}.</li>
+ * <li>The source manages concurrent modifications.
+ * <br>For example, a key set of a {@link java.util.concurrent.ConcurrentHashMap}
+ * is a concurrent source.  A Spliterator created from the source reports a
+ * characteristic of {@code CONCURRENT}.</li>
+ * <li>The mutable source provides a late-binding and fail-fast Spliterator.
+ * <br>Late binding narrows the window during which interference can affect
+ * the calculation; fail-fast detects, on a best-effort basis, that structural
+ * interference has occurred after traversal has commenced and throws
+ * {@link ConcurrentModificationException}.  For example, {@link ArrayList},
+ * and many other non-concurrent {@code Collection} classes in the JDK, provide
+ * a late-binding, fail-fast spliterator.</li>
+ * <li>The mutable source provides a non-late-binding but fail-fast Spliterator.
+ * <br>The source increases the likelihood of throwing
+ * {@code ConcurrentModificationException} since the window of potential
+ * interference is larger.</li>
+ * <li>The mutable source provides a late-binding and non-fail-fast Spliterator.
+ * <br>The source risks arbitrary, non-deterministic behavior after traversal
+ * has commenced since interference is not detected.
+ * </li>
+ * <li>The mutable source provides a non-late-binding and non-fail-fast
+ * Spliterator.
+ * <br>The source increases the risk of arbitrary, non-deterministic behavior
+ * since non-detected interference may occur after construction.
+ * </li>
+ * </ul>
+ *
+ * <p><b>Example.</b> Here is a class (not a very useful one, except
+ * for illustration) that maintains an array in which the actual data
+ * are held in even locations, and unrelated tag data are held in odd
+ * locations. Its Spliterator ignores the tags.
+ *
+ * <pre> {@code
+ * class TaggedArray<T> {
+ *   private final Object[] elements; // immutable after construction
+ *   TaggedArray(T[] data, Object[] tags) {
+ *     int size = data.length;
+ *     if (tags.length != size) throw new IllegalArgumentException();
+ *     this.elements = new Object[2 * size];
+ *     for (int i = 0, j = 0; i < size; ++i) {
+ *       elements[j++] = data[i];
+ *       elements[j++] = tags[i];
+ *     }
+ *   }
+ *
+ *   public Spliterator<T> spliterator() {
+ *     return new TaggedArraySpliterator<>(elements, 0, elements.length);
+ *   }
+ *
+ *   static class TaggedArraySpliterator<T> implements Spliterator<T> {
+ *     private final Object[] array;
+ *     private int origin; // current index, advanced on split or traversal
+ *     private final int fence; // one past the greatest index
+ *
+ *     TaggedArraySpliterator(Object[] array, int origin, int fence) {
+ *       this.array = array; this.origin = origin; this.fence = fence;
+ *     }
+ *
+ *     public void forEachRemaining(Consumer<? super T> action) {
+ *       for (; origin < fence; origin += 2)
+ *         action.accept((T) array[origin]);
+ *     }
+ *
+ *     public boolean tryAdvance(Consumer<? super T> action) {
+ *       if (origin < fence) {
+ *         action.accept((T) array[origin]);
+ *         origin += 2;
+ *         return true;
+ *       }
+ *       else // cannot advance
+ *         return false;
+ *     }
+ *
+ *     public Spliterator<T> trySplit() {
+ *       int lo = origin; // divide range in half
+ *       int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
+ *       if (lo < mid) { // split out left half
+ *         origin = mid; // reset this Spliterator's origin
+ *         return new TaggedArraySpliterator<>(array, lo, mid);
+ *       }
+ *       else       // too small to split
+ *         return null;
+ *     }
+ *
+ *     public long estimateSize() {
+ *       return (long)((fence - origin) / 2);
+ *     }
+ *
+ *     public int characteristics() {
+ *       return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>As an example how a parallel computation framework, such as the
+ * {@code java.util.stream} package, would use Spliterator in a parallel
+ * computation, here is one way to implement an associated parallel forEach,
+ * that illustrates the primary usage idiom of splitting off subtasks until
+ * the estimated amount of work is small enough to perform
+ * sequentially. Here we assume that the order of processing across
+ * subtasks doesn't matter; different (forked) tasks may further split
+ * and process elements concurrently in undetermined order.  This
+ * example uses a {@link java.util.concurrent.CountedCompleter};
+ * similar usages apply to other parallel task constructions.
+ *
+ * <pre>{@code
+ * static <T> void parEach(TaggedArray<T> a, Consumer<T> action) {
+ *   Spliterator<T> s = a.spliterator();
+ *   long targetBatchSize = s.estimateSize() / (ForkJoinPool.getCommonPoolParallelism() * 8);
+ *   new ParEach(null, s, action, targetBatchSize).invoke();
+ * }
+ *
+ * static class ParEach<T> extends CountedCompleter<Void> {
+ *   final Spliterator<T> spliterator;
+ *   final Consumer<T> action;
+ *   final long targetBatchSize;
+ *
+ *   ParEach(ParEach<T> parent, Spliterator<T> spliterator,
+ *           Consumer<T> action, long targetBatchSize) {
+ *     super(parent);
+ *     this.spliterator = spliterator; this.action = action;
+ *     this.targetBatchSize = targetBatchSize;
+ *   }
+ *
+ *   public void compute() {
+ *     Spliterator<T> sub;
+ *     while (spliterator.estimateSize() > targetBatchSize &&
+ *            (sub = spliterator.trySplit()) != null) {
+ *       addToPendingCount(1);
+ *       new ParEach<>(this, sub, action, targetBatchSize).fork();
+ *     }
+ *     spliterator.forEachRemaining(action);
+ *     propagateCompletion();
+ *   }
+ * }}</pre>
+ *
+ * @implNote
+ * If the boolean system property {@code org.openjdk.java.util.stream.tripwire}
+ * is set to {@code true} then diagnostic warnings are reported if boxing of
+ * primitive values occur when operating on primitive subtype specializations.
+ *
+ * @param <T> the type of elements returned by this Spliterator
+ *
+ * @see Collection
+ * @since 1.8
+ */
+public interface Spliterator<T> {
+    /**
+     * If a remaining element exists, performs the given action on it,
+     * returning {@code true}; else returns {@code false}.  If this
+     * Spliterator is {@link #ORDERED} the action is performed on the
+     * next element in encounter order.  Exceptions thrown by the
+     * action are relayed to the caller.
+     *
+     * @param action The action
+     * @return {@code false} if no remaining elements existed
+     * upon entry to this method, else {@code true}.
+     * @throws NullPointerException if the specified action is null
+     */
+    boolean tryAdvance(Consumer<? super T> action);
+
+    /**
+     * Performs the given action for each remaining element, sequentially in
+     * the current thread, until all elements have been processed or the action
+     * throws an exception.  If this Spliterator is {@link #ORDERED}, actions
+     * are performed in encounter order.  Exceptions thrown by the action
+     * are relayed to the caller.
+     *
+     * @implSpec
+     * The default implementation repeatedly invokes {@link #tryAdvance} until
+     * it returns {@code false}.  It should be overridden whenever possible.
+     *
+     * @param action The action
+     * @throws NullPointerException if the specified action is null
+     */
+    default void forEachRemaining(Consumer<? super T> action) {
+        do { } while (tryAdvance(action));
+    }
+
+    /**
+     * If this spliterator can be partitioned, returns a Spliterator
+     * covering elements, that will, upon return from this method, not
+     * be covered by this Spliterator.
+     *
+     * <p>If this Spliterator is {@link #ORDERED}, the returned Spliterator
+     * must cover a strict prefix of the elements.
+     *
+     * <p>Unless this Spliterator covers an infinite number of elements,
+     * repeated calls to {@code trySplit()} must eventually return {@code null}.
+     * Upon non-null return:
+     * <ul>
+     * <li>the value reported for {@code estimateSize()} before splitting,
+     * must, after splitting, be greater than or equal to {@code estimateSize()}
+     * for this and the returned Spliterator; and</li>
+     * <li>if this Spliterator is {@code SUBSIZED}, then {@code estimateSize()}
+     * for this spliterator before splitting must be equal to the sum of
+     * {@code estimateSize()} for this and the returned Spliterator after
+     * splitting.</li>
+     * </ul>
+     *
+     * <p>This method may return {@code null} for any reason,
+     * including emptiness, inability to split after traversal has
+     * commenced, data structure constraints, and efficiency
+     * considerations.
+     *
+     * @apiNote
+     * An ideal {@code trySplit} method efficiently (without
+     * traversal) divides its elements exactly in half, allowing
+     * balanced parallel computation.  Many departures from this ideal
+     * remain highly effective; for example, only approximately
+     * splitting an approximately balanced tree, or for a tree in
+     * which leaf nodes may contain either one or two elements,
+     * failing to further split these nodes.  However, large
+     * deviations in balance and/or overly inefficient {@code
+     * trySplit} mechanics typically result in poor parallel
+     * performance.
+     *
+     * @return a {@code Spliterator} covering some portion of the
+     * elements, or {@code null} if this spliterator cannot be split
+     */
+    Spliterator<T> trySplit();
+
+    /**
+     * Returns an estimate of the number of elements that would be
+     * encountered by a {@link #forEachRemaining} traversal, or returns {@link
+     * Long#MAX_VALUE} if infinite, unknown, or too expensive to compute.
+     *
+     * <p>If this Spliterator is {@link #SIZED} and has not yet been partially
+     * traversed or split, or this Spliterator is {@link #SUBSIZED} and has
+     * not yet been partially traversed, this estimate must be an accurate
+     * count of elements that would be encountered by a complete traversal.
+     * Otherwise, this estimate may be arbitrarily inaccurate, but must decrease
+     * as specified across invocations of {@link #trySplit}.
+     *
+     * @apiNote
+     * Even an inexact estimate is often useful and inexpensive to compute.
+     * For example, a sub-spliterator of an approximately balanced binary tree
+     * may return a value that estimates the number of elements to be half of
+     * that of its parent; if the root Spliterator does not maintain an
+     * accurate count, it could estimate size to be the power of two
+     * corresponding to its maximum depth.
+     *
+     * @return the estimated size, or {@code Long.MAX_VALUE} if infinite,
+     *         unknown, or too expensive to compute.
+     */
+    long estimateSize();
+
+    /**
+     * Convenience method that returns {@link #estimateSize()} if this
+     * Spliterator is {@link #SIZED}, else {@code -1}.
+     * @implSpec
+     * The default implementation returns the result of {@code estimateSize()}
+     * if the Spliterator reports a characteristic of {@code SIZED}, and
+     * {@code -1} otherwise.
+     *
+     * @return the exact size, if known, else {@code -1}.
+     */
+    default long getExactSizeIfKnown() {
+        return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
+    }
+
+    /**
+     * Returns a set of characteristics of this Spliterator and its
+     * elements. The result is represented as ORed values from {@link
+     * #ORDERED}, {@link #DISTINCT}, {@link #SORTED}, {@link #SIZED},
+     * {@link #NONNULL}, {@link #IMMUTABLE}, {@link #CONCURRENT},
+     * {@link #SUBSIZED}.  Repeated calls to {@code characteristics()} on
+     * a given spliterator, prior to or in-between calls to {@code trySplit},
+     * should always return the same result.
+     *
+     * <p>If a Spliterator reports an inconsistent set of
+     * characteristics (either those returned from a single invocation
+     * or across multiple invocations), no guarantees can be made
+     * about any computation using this Spliterator.
+     *
+     * @apiNote The characteristics of a given spliterator before splitting
+     * may differ from the characteristics after splitting.  For specific
+     * examples see the characteristic values {@link #SIZED}, {@link #SUBSIZED}
+     * and {@link #CONCURRENT}.
+     *
+     * @return a representation of characteristics
+     */
+    int characteristics();
+
+    /**
+     * Returns {@code true} if this Spliterator's {@link
+     * #characteristics} contain all of the given characteristics.
+     *
+     * @implSpec
+     * The default implementation returns true if the corresponding bits
+     * of the given characteristics are set.
+     *
+     * @param characteristics the characteristics to check for
+     * @return {@code true} if all the specified characteristics are present,
+     * else {@code false}
+     */
+    default boolean hasCharacteristics(int characteristics) {
+        return (characteristics() & characteristics) == characteristics;
+    }
+
+    /**
+     * If this Spliterator's source is {@link #SORTED} by a {@link Comparator},
+     * returns that {@code Comparator}. If the source is {@code SORTED} in
+     * {@linkplain Comparable natural order}, returns {@code null}.  Otherwise,
+     * if the source is not {@code SORTED}, throws {@link IllegalStateException}.
+     *
+     * @implSpec
+     * The default implementation always throws {@link IllegalStateException}.
+     *
+     * @return a Comparator, or {@code null} if the elements are sorted in the
+     * natural order.
+     * @throws IllegalStateException if the spliterator does not report
+     *         a characteristic of {@code SORTED}.
+     */
+    default Comparator<? super T> getComparator() {
+        throw new IllegalStateException();
+    }
+
+    /**
+     * Characteristic value signifying that an encounter order is defined for
+     * elements. If so, this Spliterator guarantees that method
+     * {@link #trySplit} splits a strict prefix of elements, that method
+     * {@link #tryAdvance} steps by one element in prefix order, and that
+     * {@link #forEachRemaining} performs actions in encounter order.
+     *
+     * <p>A {@link Collection} has an encounter order if the corresponding
+     * {@link Collection#iterator} documents an order. If so, the encounter
+     * order is the same as the documented order. Otherwise, a collection does
+     * not have an encounter order.
+     *
+     * @apiNote Encounter order is guaranteed to be ascending index order for
+     * any {@link List}. But no order is guaranteed for hash-based collections
+     * such as {@link HashSet}. Clients of a Spliterator that reports
+     * {@code ORDERED} are expected to preserve ordering constraints in
+     * non-commutative parallel computations.
+     */
+    public static final int ORDERED    = 0x00000010;
+
+    /**
+     * Characteristic value signifying that, for each pair of
+     * encountered elements {@code x, y}, {@code !x.equals(y)}. This
+     * applies for example, to a Spliterator based on a {@link Set}.
+     */
+    public static final int DISTINCT   = 0x00000001;
+
+    /**
+     * Characteristic value signifying that encounter order follows a defined
+     * sort order. If so, method {@link #getComparator()} returns the associated
+     * Comparator, or {@code null} if all elements are {@link Comparable} and
+     * are sorted by their natural ordering.
+     *
+     * <p>A Spliterator that reports {@code SORTED} must also report
+     * {@code ORDERED}.
+     *
+     * @apiNote The spliterators for {@code Collection} classes in the JDK that
+     * implement {@link NavigableSet} or {@link SortedSet} report {@code SORTED}.
+     */
+    public static final int SORTED     = 0x00000004;
+
+    /**
+     * Characteristic value signifying that the value returned from
+     * {@code estimateSize()} prior to traversal or splitting represents a
+     * finite size that, in the absence of structural source modification,
+     * represents an exact count of the number of elements that would be
+     * encountered by a complete traversal.
+     *
+     * @apiNote Most Spliterators for Collections, that cover all elements of a
+     * {@code Collection} report this characteristic. Sub-spliterators, such as
+     * those for {@link HashSet}, that cover a sub-set of elements and
+     * approximate their reported size do not.
+     */
+    public static final int SIZED      = 0x00000040;
+
+    /**
+     * Characteristic value signifying that the source guarantees that
+     * encountered elements will not be {@code null}. (This applies,
+     * for example, to most concurrent collections, queues, and maps.)
+     */
+    public static final int NONNULL    = 0x00000100;
+
+    /**
+     * Characteristic value signifying that the element source cannot be
+     * structurally modified; that is, elements cannot be added, replaced, or
+     * removed, so such changes cannot occur during traversal. A Spliterator
+     * that does not report {@code IMMUTABLE} or {@code CONCURRENT} is expected
+     * to have a documented policy (for example throwing
+     * {@link ConcurrentModificationException}) concerning structural
+     * interference detected during traversal.
+     */
+    public static final int IMMUTABLE  = 0x00000400;
+
+    /**
+     * Characteristic value signifying that the element source may be safely
+     * concurrently modified (allowing additions, replacements, and/or removals)
+     * by multiple threads without external synchronization. If so, the
+     * Spliterator is expected to have a documented policy concerning the impact
+     * of modifications during traversal.
+     *
+     * <p>A top-level Spliterator should not report both {@code CONCURRENT} and
+     * {@code SIZED}, since the finite size, if known, may change if the source
+     * is concurrently modified during traversal. Such a Spliterator is
+     * inconsistent and no guarantees can be made about any computation using
+     * that Spliterator. Sub-spliterators may report {@code SIZED} if the
+     * sub-split size is known and additions or removals to the source are not
+     * reflected when traversing.
+     *
+     * @apiNote Most concurrent collections maintain a consistency policy
+     * guaranteeing accuracy with respect to elements present at the point of
+     * Spliterator construction, but possibly not reflecting subsequent
+     * additions or removals.
+     */
+    public static final int CONCURRENT = 0x00001000;
+
+    /**
+     * Characteristic value signifying that all Spliterators resulting from
+     * {@code trySplit()} will be both {@link #SIZED} and {@link #SUBSIZED}.
+     * (This means that all child Spliterators, whether direct or indirect, will
+     * be {@code SIZED}.)
+     *
+     * <p>A Spliterator that does not report {@code SIZED} as required by
+     * {@code SUBSIZED} is inconsistent and no guarantees can be made about any
+     * computation using that Spliterator.
+     *
+     * @apiNote Some spliterators, such as the top-level spliterator for an
+     * approximately balanced binary tree, will report {@code SIZED} but not
+     * {@code SUBSIZED}, since it is common to know the size of the entire tree
+     * but not the exact sizes of subtrees.
+     */
+    public static final int SUBSIZED = 0x00004000;
+
+    /**
+     * A Spliterator specialized for primitive values.
+     *
+     * @param <T> the type of elements returned by this Spliterator.  The
+     * type must be a wrapper type for a primitive type, such as {@code Integer}
+     * for the primitive {@code int} type.
+     * @param <T_CONS> the type of primitive consumer.  The type must be a
+     * primitive specialization of {@link java.util.function.Consumer} for
+     * {@code T}, such as {@link java.util.function.IntConsumer} for
+     * {@code Integer}.
+     * @param <T_SPLITR> the type of primitive Spliterator.  The type must be
+     * a primitive specialization of Spliterator for {@code T}, such as
+     * {@link Spliterator.OfInt} for {@code Integer}.
+     *
+     * @see Spliterator.OfInt
+     * @see Spliterator.OfLong
+     * @see Spliterator.OfDouble
+     * @since 1.8
+     */
+    public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends Spliterator<T> {
+        @Override
+        T_SPLITR trySplit();
+
+        /**
+         * If a remaining element exists, performs the given action on it,
+         * returning {@code true}; else returns {@code false}.  If this
+         * Spliterator is {@link #ORDERED} the action is performed on the
+         * next element in encounter order.  Exceptions thrown by the
+         * action are relayed to the caller.
+         *
+         * @param action The action
+         * @return {@code false} if no remaining elements existed
+         * upon entry to this method, else {@code true}.
+         * @throws NullPointerException if the specified action is null
+         */
+        @SuppressWarnings("overloads")
+        boolean tryAdvance(T_CONS action);
+
+        /**
+         * Performs the given action for each remaining element, sequentially in
+         * the current thread, until all elements have been processed or the
+         * action throws an exception.  If this Spliterator is {@link #ORDERED},
+         * actions are performed in encounter order.  Exceptions thrown by the
+         * action are relayed to the caller.
+         *
+         * @implSpec
+         * The default implementation repeatedly invokes {@link #tryAdvance}
+         * until it returns {@code false}.  It should be overridden whenever
+         * possible.
+         *
+         * @param action The action
+         * @throws NullPointerException if the specified action is null
+         */
+        @SuppressWarnings("overloads")
+        default void forEachRemaining(T_CONS action) {
+            do { } while (tryAdvance(action));
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
+
+        @Override
+        OfInt trySplit();
+
+        @Override
+        boolean tryAdvance(IntConsumer action);
+
+        @Override
+        default void forEachRemaining(IntConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.IntConsumer)}; otherwise
+         * the action is adapted to an instance of {@code IntConsumer}, by
+         * boxing the argument of {@code IntConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.IntConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                return tryAdvance((IntConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
+                return tryAdvance((IntConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code IntConsumer} then it is cast
+         * to {@code IntConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.IntConsumer)}; otherwise
+         * the action is adapted to an instance of {@code IntConsumer}, by
+         * boxing the argument of {@code IntConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.IntConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Integer> action) {
+            if (action instanceof IntConsumer) {
+                forEachRemaining((IntConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
+                forEachRemaining((IntConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code long} values.
+     * @since 1.8
+     */
+    public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
+
+        @Override
+        OfLong trySplit();
+
+        @Override
+        boolean tryAdvance(LongConsumer action);
+
+        @Override
+        default void forEachRemaining(LongConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.LongConsumer)}; otherwise
+         * the action is adapted to an instance of {@code LongConsumer}, by
+         * boxing the argument of {@code LongConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.LongConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                return tryAdvance((LongConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)");
+                return tryAdvance((LongConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code LongConsumer} then it is cast
+         * to {@code LongConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.LongConsumer)}; otherwise
+         * the action is adapted to an instance of {@code LongConsumer}, by
+         * boxing the argument of {@code LongConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.LongConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Long> action) {
+            if (action instanceof LongConsumer) {
+                forEachRemaining((LongConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)");
+                forEachRemaining((LongConsumer) action::accept);
+            }
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code double} values.
+     * @since 1.8
+     */
+    public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
+
+        @Override
+        OfDouble trySplit();
+
+        @Override
+        boolean tryAdvance(DoubleConsumer action);
+
+        @Override
+        default void forEachRemaining(DoubleConsumer action) {
+            do { } while (tryAdvance(action));
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #tryAdvance(java.util.function.DoubleConsumer)}; otherwise
+         * the action is adapted to an instance of {@code DoubleConsumer}, by
+         * boxing the argument of {@code DoubleConsumer}, and then passed to
+         * {@link #tryAdvance(java.util.function.DoubleConsumer)}.
+         */
+        @Override
+        default boolean tryAdvance(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                return tryAdvance((DoubleConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)");
+                return tryAdvance((DoubleConsumer) action::accept);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec
+         * If the action is an instance of {@code DoubleConsumer} then it is
+         * cast to {@code DoubleConsumer} and passed to
+         * {@link #forEachRemaining(java.util.function.DoubleConsumer)};
+         * otherwise the action is adapted to an instance of
+         * {@code DoubleConsumer}, by boxing the argument of
+         * {@code DoubleConsumer}, and then passed to
+         * {@link #forEachRemaining(java.util.function.DoubleConsumer)}.
+         */
+        @Override
+        default void forEachRemaining(Consumer<? super Double> action) {
+            if (action instanceof DoubleConsumer) {
+                forEachRemaining((DoubleConsumer) action);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(),
+                                  "{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)");
+                forEachRemaining((DoubleConsumer) action::accept);
+            }
+        }
+    }
+}
diff --git a/java/util/Spliterators.java b/java/util/Spliterators.java
new file mode 100644
index 0000000..79c0ef3
--- /dev/null
+++ b/java/util/Spliterators.java
@@ -0,0 +1,2124 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Static classes and methods for operating on or creating instances of
+ * {@link Spliterator} and its primitive specializations
+ * {@link Spliterator.OfInt}, {@link Spliterator.OfLong}, and
+ * {@link Spliterator.OfDouble}.
+ *
+ * @see Spliterator
+ * @since 1.8
+ */
+public final class Spliterators {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private Spliterators() {}
+
+    // Empty spliterators
+
+    /**
+     * Creates an empty {@code Spliterator}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @param <T> Type of elements
+     * @return An empty spliterator
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Spliterator<T> emptySpliterator() {
+        return (Spliterator<T>) EMPTY_SPLITERATOR;
+    }
+
+    private static final Spliterator<Object> EMPTY_SPLITERATOR =
+            new EmptySpliterator.OfRef<>();
+
+    /**
+     * Creates an empty {@code Spliterator.OfInt}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfInt emptyIntSpliterator() {
+        return EMPTY_INT_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfInt EMPTY_INT_SPLITERATOR =
+            new EmptySpliterator.OfInt();
+
+    /**
+     * Creates an empty {@code Spliterator.OfLong}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfLong emptyLongSpliterator() {
+        return EMPTY_LONG_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfLong EMPTY_LONG_SPLITERATOR =
+            new EmptySpliterator.OfLong();
+
+    /**
+     * Creates an empty {@code Spliterator.OfDouble}
+     *
+     * <p>The empty spliterator reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#SUBSIZED}.  Calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return An empty spliterator
+     */
+    public static Spliterator.OfDouble emptyDoubleSpliterator() {
+        return EMPTY_DOUBLE_SPLITERATOR;
+    }
+
+    private static final Spliterator.OfDouble EMPTY_DOUBLE_SPLITERATOR =
+            new EmptySpliterator.OfDouble();
+
+    // Array-based spliterators
+
+    /**
+     * Creates a {@code Spliterator} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(Object[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param <T> Type of elements
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(Object[])
+     */
+    public static <T> Spliterator<T> spliterator(Object[] array,
+                                                 int additionalCharacteristics) {
+        return new ArraySpliterator<>(Objects.requireNonNull(array),
+                                      additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} covering a range of elements of a given
+     * array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(Object[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param <T> Type of elements
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(Object[], int, int)
+     */
+    public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex,
+                                                 int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(int[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(int[])
+     */
+    public static Spliterator.OfInt spliterator(int[] array,
+                                                int additionalCharacteristics) {
+        return new IntArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(int[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(int[], int, int)
+     */
+    public static Spliterator.OfInt spliterator(int[] array, int fromIndex, int toIndex,
+                                                int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new IntArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(long[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(long[])
+     */
+    public static Spliterator.OfLong spliterator(long[] array,
+                                                 int additionalCharacteristics) {
+        return new LongArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(long[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report.  (For example, if it is
+     * known the array will not be further modified, specify {@code IMMUTABLE};
+     * if the array data is considered to have an an encounter order, specify
+     * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
+     * often be used instead, which returns a spliterator that reports
+     * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(long[], int, int)
+     */
+    public static Spliterator.OfLong spliterator(long[] array, int fromIndex, int toIndex,
+                                                 int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new LongArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} covering the elements of a given array,
+     * using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(double[])}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report; it is common to
+     * additionally specify {@code IMMUTABLE} and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @see Arrays#spliterator(double[])
+     */
+    public static Spliterator.OfDouble spliterator(double[] array,
+                                                   int additionalCharacteristics) {
+        return new DoubleArraySpliterator(Objects.requireNonNull(array), additionalCharacteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} covering a range of elements of a
+     * given array, using a customized set of spliterator characteristics.
+     *
+     * <p>This method is provided as an implementation convenience for
+     * Spliterators which store portions of their elements in arrays, and need
+     * fine control over Spliterator characteristics.  Most other situations in
+     * which a Spliterator for an array is needed should use
+     * {@link Arrays#spliterator(double[], int, int)}.
+     *
+     * <p>The returned spliterator always reports the characteristics
+     * {@code SIZED} and {@code SUBSIZED}.  The caller may provide additional
+     * characteristics for the spliterator to report.  (For example, if it is
+     * known the array will not be further modified, specify {@code IMMUTABLE};
+     * if the array data is considered to have an an encounter order, specify
+     * {@code ORDERED}).  The method {@link Arrays#spliterator(long[], int, int)} can
+     * often be used instead, which returns a spliterator that reports
+     * {@code SIZED}, {@code SUBSIZED}, {@code IMMUTABLE}, and {@code ORDERED}.
+     *
+     * @param array The array, assumed to be unmodified during use
+     * @param fromIndex The least index (inclusive) to cover
+     * @param toIndex One past the greatest index to cover
+     * @param additionalCharacteristics Additional spliterator characteristics
+     *        of this spliterator's source or elements beyond {@code SIZED} and
+     *        {@code SUBSIZED} which are are always reported
+     * @return A spliterator for an array
+     * @throws NullPointerException if the given array is {@code null}
+     * @throws ArrayIndexOutOfBoundsException if {@code fromIndex} is negative,
+     *         {@code toIndex} is less than {@code fromIndex}, or
+     *         {@code toIndex} is greater than the array size
+     * @see Arrays#spliterator(double[], int, int)
+     */
+    public static Spliterator.OfDouble spliterator(double[] array, int fromIndex, int toIndex,
+                                                   int additionalCharacteristics) {
+        checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
+        return new DoubleArraySpliterator(array, fromIndex, toIndex, additionalCharacteristics);
+    }
+
+    /**
+     * Validate inclusive start index and exclusive end index against the length
+     * of an array.
+     * @param arrayLength The length of the array
+     * @param origin The inclusive start index
+     * @param fence The exclusive end index
+     * @throws ArrayIndexOutOfBoundsException if the start index is greater than
+     * the end index, if the start index is negative, or the end index is
+     * greater than the array length
+     */
+    private static void checkFromToBounds(int arrayLength, int origin, int fence) {
+        if (origin > fence) {
+            throw new ArrayIndexOutOfBoundsException(
+                    "origin(" + origin + ") > fence(" + fence + ")");
+        }
+        if (origin < 0) {
+            throw new ArrayIndexOutOfBoundsException(origin);
+        }
+        if (fence > arrayLength) {
+            throw new ArrayIndexOutOfBoundsException(fence);
+        }
+    }
+
+    // Iterator-based spliterators
+
+    /**
+     * Creates a {@code Spliterator} using the given collection's
+     * {@link java.util.Collection#iterator()} as the source of elements, and
+     * reporting its {@link java.util.Collection#size()} as its initial size.
+     *
+     * <p>The spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the collection's iterator, and
+     * implements {@code trySplit} to permit limited parallelism.
+     *
+     * @param <T> Type of elements
+     * @param c The collection
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given collection is {@code null}
+     */
+    public static <T> Spliterator<T> spliterator(Collection<? extends T> c,
+                                                 int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(c),
+                                         characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} using a given {@code Iterator}
+     * as the source of elements, and with a given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param <T> Type of elements
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static <T> Spliterator<T> spliterator(Iterator<? extends T> iterator,
+                                                 long size,
+                                                 int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(iterator), size,
+                                         characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator} using a given {@code Iterator}
+     * as the source of elements, with no initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param <T> Type of elements
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static <T> Spliterator<T> spliteratorUnknownSize(Iterator<? extends T> iterator,
+                                                            int characteristics) {
+        return new IteratorSpliterator<>(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} using a given
+     * {@code IntStream.IntIterator} as the source of elements, and with a given
+     * initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}.
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfInt spliterator(PrimitiveIterator.OfInt iterator,
+                                                long size,
+                                                int characteristics) {
+        return new IntIteratorSpliterator(Objects.requireNonNull(iterator),
+                                          size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfInt} using a given
+     * {@code IntStream.IntIterator} as the source of elements, with no initial
+     * size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfInt spliteratorUnknownSize(PrimitiveIterator.OfInt iterator,
+                                                           int characteristics) {
+        return new IntIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} using a given
+     * {@code LongStream.LongIterator} as the source of elements, and with a
+     * given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}.
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfLong spliterator(PrimitiveIterator.OfLong iterator,
+                                                 long size,
+                                                 int characteristics) {
+        return new LongIteratorSpliterator(Objects.requireNonNull(iterator),
+                                           size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfLong} using a given
+     * {@code LongStream.LongIterator} as the source of elements, with no
+     * initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfLong spliteratorUnknownSize(PrimitiveIterator.OfLong iterator,
+                                                            int characteristics) {
+        return new LongIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} using a given
+     * {@code DoubleStream.DoubleIterator} as the source of elements, and with a
+     * given initially reported size.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned, or the initially reported
+     * size is not equal to the actual number of elements in the source.
+     *
+     * @param iterator The iterator for the source
+     * @param size The number of elements in the source, to be reported as
+     *        initial {@code estimateSize}
+     * @param characteristics Characteristics of this spliterator's source or
+     *        elements.  The characteristics {@code SIZED} and {@code SUBSIZED}
+     *        are additionally reported unless {@code CONCURRENT} is supplied.
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfDouble spliterator(PrimitiveIterator.OfDouble iterator,
+                                                   long size,
+                                                   int characteristics) {
+        return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator),
+                                             size, characteristics);
+    }
+
+    /**
+     * Creates a {@code Spliterator.OfDouble} using a given
+     * {@code DoubleStream.DoubleIterator} as the source of elements, with no
+     * initial size estimate.
+     *
+     * <p>The spliterator is not
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>, inherits
+     * the <em>fail-fast</em> properties of the iterator, and implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>Traversal of elements should be accomplished through the spliterator.
+     * The behaviour of splitting and traversal is undefined if the iterator is
+     * operated on after the spliterator is returned.
+     *
+     * @param iterator The iterator for the source
+     * @param characteristics Characteristics of this spliterator's source
+     *        or elements ({@code SIZED} and {@code SUBSIZED}, if supplied, are
+     *        ignored and are not reported.)
+     * @return A spliterator from an iterator
+     * @throws NullPointerException if the given iterator is {@code null}
+     */
+    public static Spliterator.OfDouble spliteratorUnknownSize(PrimitiveIterator.OfDouble iterator,
+                                                              int characteristics) {
+        return new DoubleIteratorSpliterator(Objects.requireNonNull(iterator), characteristics);
+    }
+
+    // Iterators from Spliterators
+
+    /**
+     * Creates an {@code Iterator} from a {@code Spliterator}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param <T> Type of elements
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static<T> Iterator<T> iterator(Spliterator<? extends T> spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements Iterator<T>, Consumer<T> {
+            boolean valueReady = false;
+            T nextElement;
+
+            @Override
+            public void accept(T t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public T next() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfInt} from a
+     * {@code Spliterator.OfInt}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfInt iterator(Spliterator.OfInt spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfInt, IntConsumer {
+            boolean valueReady = false;
+            int nextElement;
+
+            @Override
+            public void accept(int t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public int nextInt() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfLong} from a
+     * {@code Spliterator.OfLong}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfLong iterator(Spliterator.OfLong spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfLong, LongConsumer {
+            boolean valueReady = false;
+            long nextElement;
+
+            @Override
+            public void accept(long t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public long nextLong() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    /**
+     * Creates an {@code PrimitiveIterator.OfDouble} from a
+     * {@code Spliterator.OfDouble}.
+     *
+     * <p>Traversal of elements should be accomplished through the iterator.
+     * The behaviour of traversal is undefined if the spliterator is operated
+     * after the iterator is returned.
+     *
+     * @param spliterator The spliterator
+     * @return An iterator
+     * @throws NullPointerException if the given spliterator is {@code null}
+     */
+    public static PrimitiveIterator.OfDouble iterator(Spliterator.OfDouble spliterator) {
+        Objects.requireNonNull(spliterator);
+        class Adapter implements PrimitiveIterator.OfDouble, DoubleConsumer {
+            boolean valueReady = false;
+            double nextElement;
+
+            @Override
+            public void accept(double t) {
+                valueReady = true;
+                nextElement = t;
+            }
+
+            @Override
+            public boolean hasNext() {
+                if (!valueReady)
+                    spliterator.tryAdvance(this);
+                return valueReady;
+            }
+
+            @Override
+            public double nextDouble() {
+                if (!valueReady && !hasNext())
+                    throw new NoSuchElementException();
+                else {
+                    valueReady = false;
+                    return nextElement;
+                }
+            }
+        }
+
+        return new Adapter();
+    }
+
+    // Implementations
+
+    private static abstract class EmptySpliterator<T, S extends Spliterator<T>, C> {
+
+        EmptySpliterator() { }
+
+        public S trySplit() {
+            return null;
+        }
+
+        public boolean tryAdvance(C consumer) {
+            Objects.requireNonNull(consumer);
+            return false;
+        }
+
+        public void forEachRemaining(C consumer) {
+            Objects.requireNonNull(consumer);
+        }
+
+        public long estimateSize() {
+            return 0;
+        }
+
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        private static final class OfRef<T>
+                extends EmptySpliterator<T, Spliterator<T>, Consumer<? super T>>
+                implements Spliterator<T> {
+            OfRef() { }
+        }
+
+        private static final class OfInt
+                extends EmptySpliterator<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt() { }
+        }
+
+        private static final class OfLong
+                extends EmptySpliterator<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong() { }
+        }
+
+        private static final class OfDouble
+                extends EmptySpliterator<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble() { }
+        }
+    }
+
+    // Array-based spliterators
+
+    /**
+     * A Spliterator designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code Object[]} array.
+     */
+    static final class ArraySpliterator<T> implements Spliterator<T> {
+        /**
+         * The array, explicitly typed as Object[]. Unlike in some other
+         * classes (see for example CR 6260652), we do not need to
+         * screen arguments to ensure they are exactly of type Object[]
+         * so long as no methods write into the array or serialize it,
+         * which we ensure here by defining this class as final.
+         */
+        private final Object[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         * of this spliterator's source or elements beyond {@code SIZED} and
+         * {@code SUBSIZED} which are are always reported
+         */
+        public ArraySpliterator(Object[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         * of this spliterator's source or elements beyond {@code SIZED} and
+         * {@code SUBSIZED} which are are always reported
+         */
+        public ArraySpliterator(Object[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new ArraySpliterator<>(array, lo, index = mid, characteristics);
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            Object[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept((T)a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                @SuppressWarnings("unchecked") T e = (T) array[index++];
+                action.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfInt designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class IntArraySpliterator implements Spliterator.OfInt {
+        private final int[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public IntArraySpliterator(int[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public IntArraySpliterator(int[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfInt trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new IntArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            int[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfLong designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class LongArraySpliterator implements Spliterator.OfLong {
+        private final long[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public LongArraySpliterator(long[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public LongArraySpliterator(long[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfLong trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new LongArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            long[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfDouble designed for use by sources that traverse and split
+     * elements maintained in an unmodifiable {@code int[]} array.
+     */
+    static final class DoubleArraySpliterator implements Spliterator.OfDouble {
+        private final double[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int characteristics;
+
+        /**
+         * Creates a spliterator covering all of the given array.
+         * @param array the array, assumed to be unmodified during use
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public DoubleArraySpliterator(double[] array, int additionalCharacteristics) {
+            this(array, 0, array.length, additionalCharacteristics);
+        }
+
+        /**
+         * Creates a spliterator covering the given array and range
+         * @param array the array, assumed to be unmodified during use
+         * @param origin the least index (inclusive) to cover
+         * @param fence one past the greatest index to cover
+         * @param additionalCharacteristics Additional spliterator characteristics
+         *        of this spliterator's source or elements beyond {@code SIZED} and
+         *        {@code SUBSIZED} which are are always reported
+         */
+        public DoubleArraySpliterator(double[] array, int origin, int fence, int additionalCharacteristics) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfDouble trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new DoubleArraySpliterator(array, lo, index = mid, characteristics);
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            double[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i]); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++]);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    //
+
+    /**
+     * An abstract {@code Spliterator} that implements {@code trySplit} to
+     * permit limited parallelism.
+     *
+     * <p>An extending class need only
+     * implement {@link #tryAdvance(java.util.function.Consumer) tryAdvance}.
+     * The extending class should override
+     * {@link #forEachRemaining(java.util.function.Consumer) forEach} if it can
+     * provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(Iterator, long, int)}.  Depending on the
+     * circumstances using an iterator may be easier or more convenient than
+     * extending this class, such as when there is already an iterator
+     * available to use.
+     *
+     * @see #spliterator(Iterator, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractSpliterator<T> implements Spliterator<T> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * additionalCharacteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingConsumer<T> implements Consumer<T> {
+            Object value;
+
+            @Override
+            public void accept(T value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator<T> trySplit() {
+            /*
+             * Split into arrays of arithmetically increasing batch
+             * sizes.  This will only improve parallel performance if
+             * per-element Consumer actions are more costly than
+             * transferring them into an array.  The use of an
+             * arithmetic progression in split sizes provides overhead
+             * vs parallelism bounds that do not particularly favor or
+             * penalize cases of lightweight vs heavyweight element
+             * operations, across combinations of #elements vs #cores,
+             * whether or not either are known.  We generate
+             * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
+             * potential speedup.
+             */
+            HoldingConsumer<T> holder = new HoldingConsumer<>();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new ArraySpliterator<>(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfInt} that implements {@code trySplit} to
+     * permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.IntConsumer)}
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.IntConsumer)} forEach} if it
+     * can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfInt, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfInt, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractIntSpliterator implements Spliterator.OfInt {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractIntSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingIntConsumer implements IntConsumer {
+            int value;
+
+            @Override
+            public void accept(int value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfInt trySplit() {
+            HoldingIntConsumer holder = new HoldingIntConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                int[] a = new int[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new IntArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfLong} that implements {@code trySplit}
+     * to permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.LongConsumer)}
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.LongConsumer)} forEach} if it
+     * can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfLong, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfLong, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractLongSpliterator implements Spliterator.OfLong {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractLongSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingLongConsumer implements LongConsumer {
+            long value;
+
+            @Override
+            public void accept(long value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfLong trySplit() {
+            HoldingLongConsumer holder = new HoldingLongConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                long[] a = new long[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new LongArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * An abstract {@code Spliterator.OfDouble} that implements
+     * {@code trySplit} to permit limited parallelism.
+     *
+     * <p>To implement a spliterator an extending class need only
+     * implement {@link #tryAdvance(java.util.function.DoubleConsumer)}
+     * tryAdvance}.  The extending class should override
+     * {@link #forEachRemaining(java.util.function.DoubleConsumer)} forEach} if
+     * it can provide a more performant implementation.
+     *
+     * @apiNote
+     * This class is a useful aid for creating a spliterator when it is not
+     * possible or difficult to efficiently partition elements in a manner
+     * allowing balanced parallel computation.
+     *
+     * <p>An alternative to using this class, that also permits limited
+     * parallelism, is to create a spliterator from an iterator
+     * (see {@link #spliterator(java.util.PrimitiveIterator.OfDouble, long, int)}.
+     * Depending on the circumstances using an iterator may be easier or more
+     * convenient than extending this class. For example, if there is already an
+     * iterator available to use then there is no need to extend this class.
+     *
+     * @see #spliterator(java.util.PrimitiveIterator.OfDouble, long, int)
+     * @since 1.8
+     */
+    public static abstract class AbstractDoubleSpliterator implements Spliterator.OfDouble {
+        static final int MAX_BATCH = AbstractSpliterator.MAX_BATCH;
+        static final int BATCH_UNIT = AbstractSpliterator.BATCH_UNIT;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator reporting the given estimated size and
+         * characteristics.
+         *
+         * @param est the estimated size of this spliterator if known, otherwise
+         *        {@code Long.MAX_VALUE}.
+         * @param additionalCharacteristics properties of this spliterator's
+         *        source or elements.  If {@code SIZED} is reported then this
+         *        spliterator will additionally report {@code SUBSIZED}.
+         */
+        protected AbstractDoubleSpliterator(long est, int additionalCharacteristics) {
+            this.est = est;
+            this.characteristics = ((additionalCharacteristics & Spliterator.SIZED) != 0)
+                                   ? additionalCharacteristics | Spliterator.SUBSIZED
+                                   : additionalCharacteristics;
+        }
+
+        static final class HoldingDoubleConsumer implements DoubleConsumer {
+            double value;
+
+            @Override
+            public void accept(double value) {
+                this.value = value;
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * This implementation permits limited parallelism.
+         */
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            HoldingDoubleConsumer holder = new HoldingDoubleConsumer();
+            long s = est;
+            if (s > 1 && tryAdvance(holder)) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                double[] a = new double[n];
+                int j = 0;
+                do { a[j] = holder.value; } while (++j < n && tryAdvance(holder));
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new DoubleArraySpliterator(a, 0, j, characteristics());
+            }
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the estimated size as reported when
+         * created and, if the estimate size is known, decreases in size when
+         * split.
+         */
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec
+         * This implementation returns the characteristics as reported when
+         * created.
+         */
+        @Override
+        public int characteristics() {
+            return characteristics;
+        }
+    }
+
+    // Iterator-based Spliterators
+
+    /**
+     * A Spliterator using a given Iterator for element
+     * operations. The spliterator implements {@code trySplit} to
+     * permit limited parallelism.
+     */
+    static class IteratorSpliterator<T> implements Spliterator<T> {
+        static final int BATCH_UNIT = 1 << 10;  // batch array size increment
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        private final Collection<? extends T> collection; // null OK
+        private Iterator<? extends T> it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given given
+         * collection's {@link java.util.Collection#iterator()) for traversal,
+         * and reporting its {@link java.util.Collection#size()) as its initial
+         * size.
+         *
+         * @param c the collection
+         * @param characteristics properties of this spliterator's
+         *        source or elements.
+         */
+        public IteratorSpliterator(Collection<? extends T> collection, int characteristics) {
+            this.collection = collection;
+            this.it = null;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IteratorSpliterator(Iterator<? extends T> iterator, long size, int characteristics) {
+            this.collection = null;
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IteratorSpliterator(Iterator<? extends T> iterator, int characteristics) {
+            this.collection = null;
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            /*
+             * Split into arrays of arithmetically increasing batch
+             * sizes.  This will only improve parallel performance if
+             * per-element Consumer actions are more costly than
+             * transferring them into an array.  The use of an
+             * arithmetic progression in split sizes provides overhead
+             * vs parallelism bounds that do not particularly favor or
+             * penalize cases of lightweight vs heavyweight element
+             * operations, across combinations of #elements vs #cores,
+             * whether or not either are known.  We generate
+             * O(sqrt(#elements)) splits, allowing O(sqrt(#cores))
+             * potential speedup.
+             */
+            Iterator<? extends T> i;
+            long s;
+            if ((i = it) == null) {
+                i = it = collection.iterator();
+                s = est = (long) collection.size();
+            }
+            else
+                s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                Object[] a = new Object[n];
+                int j = 0;
+                do { a[j] = i.next(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new ArraySpliterator<>(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            if (action == null) throw new NullPointerException();
+            Iterator<? extends T> i;
+            if ((i = it) == null) {
+                i = it = collection.iterator();
+                est = (long)collection.size();
+            }
+            i.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            if (action == null) throw new NullPointerException();
+            if (it == null) {
+                it = collection.iterator();
+                est = (long) collection.size();
+            }
+            if (it.hasNext()) {
+                action.accept(it.next());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            if (it == null) {
+                it = collection.iterator();
+                return est = (long)collection.size();
+            }
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
+     * A Spliterator.OfInt using a given IntStream.IntIterator for element
+     * operations. The spliterator implements {@code trySplit} to
+     * permit limited parallelism.
+     */
+    static final class IntIteratorSpliterator implements Spliterator.OfInt {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private PrimitiveIterator.OfInt it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public IntIteratorSpliterator(PrimitiveIterator.OfInt iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfInt trySplit() {
+            PrimitiveIterator.OfInt i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                int[] a = new int[n];
+                int j = 0;
+                do { a[j] = i.nextInt(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new IntArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextInt());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    static final class LongIteratorSpliterator implements Spliterator.OfLong {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private PrimitiveIterator.OfLong it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public LongIteratorSpliterator(PrimitiveIterator.OfLong iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfLong trySplit() {
+            PrimitiveIterator.OfLong i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                long[] a = new long[n];
+                int j = 0;
+                do { a[j] = i.nextLong(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new LongArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextLong());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+
+    static final class DoubleIteratorSpliterator implements Spliterator.OfDouble {
+        static final int BATCH_UNIT = IteratorSpliterator.BATCH_UNIT;
+        static final int MAX_BATCH = IteratorSpliterator.MAX_BATCH;
+        private PrimitiveIterator.OfDouble it;
+        private final int characteristics;
+        private long est;             // size estimate
+        private int batch;            // batch size for splits
+
+        /**
+         * Creates a spliterator using the given iterator
+         * for traversal, and reporting the given initial size
+         * and characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param size the number of elements in the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, long size, int characteristics) {
+            this.it = iterator;
+            this.est = size;
+            this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0
+                                   ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED
+                                   : characteristics;
+        }
+
+        /**
+         * Creates a spliterator using the given iterator for a
+         * source of unknown size, reporting the given
+         * characteristics.
+         *
+         * @param iterator the iterator for the source
+         * @param characteristics properties of this spliterator's
+         * source or elements.
+         */
+        public DoubleIteratorSpliterator(PrimitiveIterator.OfDouble iterator, int characteristics) {
+            this.it = iterator;
+            this.est = Long.MAX_VALUE;
+            this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+        }
+
+        @Override
+        public OfDouble trySplit() {
+            PrimitiveIterator.OfDouble i = it;
+            long s = est;
+            if (s > 1 && i.hasNext()) {
+                int n = batch + BATCH_UNIT;
+                if (n > s)
+                    n = (int) s;
+                if (n > MAX_BATCH)
+                    n = MAX_BATCH;
+                double[] a = new double[n];
+                int j = 0;
+                do { a[j] = i.nextDouble(); } while (++j < n && i.hasNext());
+                batch = j;
+                if (est != Long.MAX_VALUE)
+                    est -= j;
+                return new DoubleArraySpliterator(a, 0, j, characteristics);
+            }
+            return null;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            if (action == null) throw new NullPointerException();
+            it.forEachRemaining(action);
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            if (action == null) throw new NullPointerException();
+            if (it.hasNext()) {
+                action.accept(it.nextDouble());
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() {
+            return est;
+        }
+
+        @Override
+        public int characteristics() { return characteristics; }
+
+        @Override
+        public Comparator<? super Double> getComparator() {
+            if (hasCharacteristics(Spliterator.SORTED))
+                return null;
+            throw new IllegalStateException();
+        }
+    }
+}
diff --git a/java/util/SplittableRandom.java b/java/util/SplittableRandom.java
new file mode 100644
index 0000000..579102a
--- /dev/null
+++ b/java/util/SplittableRandom.java
@@ -0,0 +1,996 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A generator of uniform pseudorandom values applicable for use in
+ * (among other contexts) isolated parallel computations that may
+ * generate subtasks. Class {@code SplittableRandom} supports methods for
+ * producing pseudorandom numbers of type {@code int}, {@code long},
+ * and {@code double} with similar usages as for class
+ * {@link java.util.Random} but differs in the following ways:
+ *
+ * <ul>
+ *
+ * <li>Series of generated values pass the DieHarder suite testing
+ * independence and uniformity properties of random number generators.
+ * (Most recently validated with <a
+ * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
+ * 3.31.1</a>.) These tests validate only the methods for certain
+ * types and ranges, but similar properties are expected to hold, at
+ * least approximately, for others as well. The <em>period</em>
+ * (length of any series of generated values before it repeats) is at
+ * least 2<sup>64</sup>.
+ *
+ * <li>Method {@link #split} constructs and returns a new
+ * SplittableRandom instance that shares no mutable state with the
+ * current instance. However, with very high probability, the
+ * values collectively generated by the two objects have the same
+ * statistical properties as if the same quantity of values were
+ * generated by a single thread using a single {@code
+ * SplittableRandom} object.
+ *
+ * <li>Instances of SplittableRandom are <em>not</em> thread-safe.
+ * They are designed to be split, not shared, across threads. For
+ * example, a {@link java.util.concurrent.ForkJoinTask
+ * fork/join-style} computation using random numbers might include a
+ * construction of the form {@code new
+ * Subtask(aSplittableRandom.split()).fork()}.
+ *
+ * <li>This class provides additional methods for generating random
+ * streams, that employ the above techniques when used in {@code
+ * stream.parallel()} mode.
+ *
+ * </ul>
+ *
+ * <p>Instances of {@code SplittableRandom} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom}
+ * in security-sensitive applications. Additionally,
+ * default-constructed instances do not use a cryptographically random
+ * seed unless the {@linkplain System#getProperty system property}
+ * {@code java.util.secureRandomSeed} is set to {@code true}.
+ *
+ * @author  Guy Steele
+ * @author  Doug Lea
+ * @since   1.8
+ */
+public final class SplittableRandom {
+
+    /*
+     * Implementation Overview.
+     *
+     * This algorithm was inspired by the "DotMix" algorithm by
+     * Leiserson, Schardl, and Sukha "Deterministic Parallel
+     * Random-Number Generation for Dynamic-Multithreading Platforms",
+     * PPoPP 2012, as well as those in "Parallel random numbers: as
+     * easy as 1, 2, 3" by Salmon, Morae, Dror, and Shaw, SC 2011.  It
+     * differs mainly in simplifying and cheapening operations.
+     *
+     * The primary update step (method nextSeed()) is to add a
+     * constant ("gamma") to the current (64 bit) seed, forming a
+     * simple sequence.  The seed and the gamma values for any two
+     * SplittableRandom instances are highly likely to be different.
+     *
+     * Methods nextLong, nextInt, and derivatives do not return the
+     * sequence (seed) values, but instead a hash-like bit-mix of
+     * their bits, producing more independently distributed sequences.
+     * For nextLong, the mix64 function is based on David Stafford's
+     * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
+     * "Mix13" variant of the "64-bit finalizer" function in Austin
+     * Appleby's MurmurHash3 algorithm (see
+     * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32
+     * function is based on Stafford's Mix04 mix function, but returns
+     * the upper 32 bits cast as int.
+     *
+     * The split operation uses the current generator to form the seed
+     * and gamma for another SplittableRandom.  To conservatively
+     * avoid potential correlations between seed and value generation,
+     * gamma selection (method mixGamma) uses different
+     * (Murmurhash3's) mix constants.  To avoid potential weaknesses
+     * in bit-mixing transformations, we restrict gammas to odd values
+     * with at least 24 0-1 or 1-0 bit transitions.  Rather than
+     * rejecting candidates with too few or too many bits set, method
+     * mixGamma flips some bits (which has the effect of mapping at
+     * most 4 to any given gamma value).  This reduces the effective
+     * set of 64bit odd gamma values by about 2%, and serves as an
+     * automated screening for sequence constant selection that is
+     * left as an empirical decision in some other hashing and crypto
+     * algorithms.
+     *
+     * The resulting generator thus transforms a sequence in which
+     * (typically) many bits change on each step, with an inexpensive
+     * mixer with good (but less than cryptographically secure)
+     * avalanching.
+     *
+     * The default (no-argument) constructor, in essence, invokes
+     * split() for a common "defaultGen" SplittableRandom.  Unlike
+     * other cases, this split must be performed in a thread-safe
+     * manner, so we use an AtomicLong to represent the seed rather
+     * than use an explicit SplittableRandom. To bootstrap the
+     * defaultGen, we start off using a seed based on current time
+     * unless the java.util.secureRandomSeed property is set. This
+     * serves as a slimmed-down (and insecure) variant of SecureRandom
+     * that also avoids stalls that may occur when using /dev/random.
+     *
+     * It is a relatively simple matter to apply the basic design here
+     * to use 128 bit seeds. However, emulating 128bit arithmetic and
+     * carrying around twice the state add more overhead than appears
+     * warranted for current usages.
+     *
+     * File organization: First the non-public methods that constitute
+     * the main algorithm, then the main public methods, followed by
+     * some custom spliterator classes needed for stream methods.
+     */
+
+    /**
+     * The golden ratio scaled to 64bits, used as the initial gamma
+     * value for (unsplit) SplittableRandoms.
+     */
+    private static final long GOLDEN_GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The least non-zero value returned by nextDouble(). This value
+     * is scaled by a random value of 53 bits to produce a result.
+     */
+    private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53);
+
+    /**
+     * The seed. Updated only via method nextSeed.
+     */
+    private long seed;
+
+    /**
+     * The step value.
+     */
+    private final long gamma;
+
+    /**
+     * Internal constructor used by all others except default constructor.
+     */
+    private SplittableRandom(long seed, long gamma) {
+        this.seed = seed;
+        this.gamma = gamma;
+    }
+
+    /**
+     * Computes Stafford variant 13 of 64bit mix function.
+     */
+    private static long mix64(long z) {
+        z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
+        z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
+        return z ^ (z >>> 31);
+    }
+
+    /**
+     * Returns the 32 high bits of Stafford variant 4 mix64 function as int.
+     */
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L;
+        return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32);
+    }
+
+    /**
+     * Returns the gamma value to use for a new split instance.
+     */
+    private static long mixGamma(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants
+        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+        z = (z ^ (z >>> 33)) | 1L;                  // force to be odd
+        int n = Long.bitCount(z ^ (z >>> 1));       // ensure enough transitions
+        return (n < 24) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
+    }
+
+    /**
+     * Adds gamma to seed.
+     */
+    private long nextSeed() {
+        return seed += gamma;
+    }
+
+    // IllegalArgumentException messages
+    static final String BAD_BOUND = "bound must be positive";
+    static final String BAD_RANGE = "bound must be greater than origin";
+    static final String BAD_SIZE  = "size must be non-negative";
+
+    /**
+     * The seed generator for default constructors.
+     */
+    private static final AtomicLong defaultGen
+        = new AtomicLong(mix64(System.currentTimeMillis()) ^
+                         mix64(System.nanoTime()));
+
+    // at end of <clinit> to survive static initialization circularity
+    static {
+        if (java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return Boolean.getBoolean("java.util.secureRandomSeed");
+                }})) {
+            byte[] seedBytes = java.security.SecureRandom.getSeed(8);
+            long s = (long)seedBytes[0] & 0xffL;
+            for (int i = 1; i < 8; ++i)
+                s = (s << 8) | ((long)seedBytes[i] & 0xffL);
+            defaultGen.set(s);
+        }
+    }
+
+    /*
+     * Internal versions of nextX methods used by streams, as well as
+     * the public nextX(origin, bound) methods.  These exist mainly to
+     * avoid the need for multiple versions of stream spliterators
+     * across the different exported forms of streams.
+     */
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        /*
+         * Four Cases:
+         *
+         * 1. If the arguments indicate unbounded form, act as
+         * nextLong().
+         *
+         * 2. If the range is an exact power of two, apply the
+         * associated bit mask.
+         *
+         * 3. If the range is positive, loop to avoid potential bias
+         * when the implicit nextLong() bound (2<sup>64</sup>) is not
+         * evenly divisible by the range. The loop rejects candidates
+         * computed from otherwise over-represented values.  The
+         * expected number of iterations under an ideal generator
+         * varies from 1 to 2, depending on the bound. The loop itself
+         * takes an unlovable form. Because the first candidate is
+         * already available, we need a break-in-the-middle
+         * construction, which is concisely but cryptically performed
+         * within the while-condition of a body-less for loop.
+         *
+         * 4. Otherwise, the range cannot be represented as a positive
+         * long.  The loop repeatedly generates unbounded longs until
+         * obtaining a candidate meeting constraints (with an expected
+         * number of iterations of less than two).
+         */
+
+        long r = mix64(nextSeed());
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = mix64(nextSeed()) >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = mix64(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * Exactly the same as long version, except for types.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final int internalNextInt(int origin, int bound) {
+        int r = mix32(nextSeed());
+        if (origin < bound) {
+            int n = bound - origin, m = n - 1;
+            if ((n & m) == 0)
+                r = (r & m) + origin;
+            else if (n > 0) {
+                for (int u = r >>> 1;
+                     u + m - (r = u % n) < 0;
+                     u = mix32(nextSeed()) >>> 1)
+                    ;
+                r += origin;
+            }
+            else {
+                while (r < origin || r >= bound)
+                    r = mix32(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = (nextLong() >>> 11) * DOUBLE_UNIT;
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /* ---------------- public methods ---------------- */
+
+    /**
+     * Creates a new SplittableRandom instance using the specified
+     * initial seed. SplittableRandom instances created with the same
+     * seed in the same program generate identical sequences of values.
+     *
+     * @param seed the initial seed
+     */
+    public SplittableRandom(long seed) {
+        this(seed, GOLDEN_GAMMA);
+    }
+
+    /**
+     * Creates a new SplittableRandom instance that is likely to
+     * generate sequences of values that are statistically independent
+     * of those of any other instances in the current program; and
+     * may, and typically does, vary across program invocations.
+     */
+    public SplittableRandom() { // emulate defaultGen.split()
+        long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA);
+        this.seed = mix64(s);
+        this.gamma = mixGamma(s + GOLDEN_GAMMA);
+    }
+
+    /**
+     * Constructs and returns a new SplittableRandom instance that
+     * shares no mutable state with this instance. However, with very
+     * high probability, the set of values collectively generated by
+     * the two objects has the same statistical properties as if the
+     * same quantity of values were generated by a single thread using
+     * a single SplittableRandom object.  Either or both of the two
+     * objects may be further split using the {@code split()} method,
+     * and the same expected statistical properties apply to the
+     * entire set of generators constructed by such recursive
+     * splitting.
+     *
+     * @return the new SplittableRandom instance
+     */
+    public SplittableRandom split() {
+        return new SplittableRandom(nextLong(), mixGamma(nextSeed()));
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value.
+     *
+     * @return a pseudorandom {@code int} value
+     */
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code int} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        // Specialize internalNextInt for origin 0
+        int r = mix32(nextSeed());
+        int m = bound - 1;
+        if ((bound & m) == 0) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (int u = r >>> 1;
+                 u + m - (r = u % bound) < 0;
+                 u = mix32(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code int} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public int nextInt(int origin, int bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextInt(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value.
+     *
+     * @return a pseudorandom {@code long} value
+     */
+    public long nextLong() {
+        return mix64(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code long} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public long nextLong(long bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        // Specialize internalNextLong for origin 0
+        long r = mix64(nextSeed());
+        long m = bound - 1;
+        if ((bound & m) == 0L) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (long u = r >>> 1;
+                 u + m - (r = u % bound) < 0L;
+                 u = mix64(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code long} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public long nextLong(long origin, long bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextLong(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and one (exclusive)
+     */
+    public double nextDouble() {
+        return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between 0.0
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public double nextDouble(double bound) {
+        if (!(bound > 0.0))
+            throw new IllegalArgumentException(BAD_BOUND);
+        double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
+        return (result < bound) ?  result : // correct for rounding
+            Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between the specified
+     * origin (inclusive) and bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code double} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public double nextDouble(double origin, double bound) {
+        if (!(origin < bound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextDouble(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code boolean} value.
+     *
+     * @return a pseudorandom {@code boolean} value
+     */
+    public boolean nextBoolean() {
+        return mix32(nextSeed()) < 0;
+    }
+
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values from this generator and/or
+     * one split from it.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, streamSize, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values from this generator and/or one split from it.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     */
+    public IntStream ints() {
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code long} values from this generator and/or
+     * one split from it.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, streamSize, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values from this generator and/or one split from it.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     */
+    public LongStream longs() {
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values from this generator and/or one split
+     * from it; each value is between zero (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values from this generator and/or one split from it; each value
+     * is between zero (inclusive) and one (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     */
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values from this generator and/or one split
+     * from it; each value conforms to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values from this generator and/or one split from it; each value
+     * conforms to the given origin (inclusive) and bound (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    private static final class RandomIntsSpliterator
+            implements Spliterator.OfInt {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(SplittableRandom rng, long index, long fence,
+                              int origin, int bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomIntsSpliterator(rng.split(), i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                SplittableRandom r = rng;
+                int o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    private static final class RandomLongsSpliterator
+            implements Spliterator.OfLong {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(SplittableRandom rng, long index, long fence,
+                               long origin, long bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomLongsSpliterator(rng.split(), i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                SplittableRandom r = rng;
+                long o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    private static final class RandomDoublesSpliterator
+            implements Spliterator.OfDouble {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(SplittableRandom rng, long index, long fence,
+                                 double origin, double bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomDoublesSpliterator(rng.split(), i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                SplittableRandom r = rng;
+                double o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+}
diff --git a/java/util/Stack.java b/java/util/Stack.java
new file mode 100644
index 0000000..ebea11e
--- /dev/null
+++ b/java/util/Stack.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * The <code>Stack</code> class represents a last-in-first-out
+ * (LIFO) stack of objects. It extends class <tt>Vector</tt> with five
+ * operations that allow a vector to be treated as a stack. The usual
+ * <tt>push</tt> and <tt>pop</tt> operations are provided, as well as a
+ * method to <tt>peek</tt> at the top item on the stack, a method to test
+ * for whether the stack is <tt>empty</tt>, and a method to <tt>search</tt>
+ * the stack for an item and discover how far it is from the top.
+ * <p>
+ * When a stack is first created, it contains no items.
+ *
+ * <p>A more complete and consistent set of LIFO stack operations is
+ * provided by the {@link Deque} interface and its implementations, which
+ * should be used in preference to this class.  For example:
+ * <pre>   {@code
+ *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
+ *
+ * @author  Jonathan Payne
+ * @since   JDK1.0
+ */
+public
+class Stack<E> extends Vector<E> {
+    /**
+     * Creates an empty Stack.
+     */
+    public Stack() {
+    }
+
+    /**
+     * Pushes an item onto the top of this stack. This has exactly
+     * the same effect as:
+     * <blockquote><pre>
+     * addElement(item)</pre></blockquote>
+     *
+     * @param   item   the item to be pushed onto this stack.
+     * @return  the <code>item</code> argument.
+     * @see     java.util.Vector#addElement
+     */
+    public E push(E item) {
+        addElement(item);
+
+        return item;
+    }
+
+    /**
+     * Removes the object at the top of this stack and returns that
+     * object as the value of this function.
+     *
+     * @return  The object at the top of this stack (the last item
+     *          of the <tt>Vector</tt> object).
+     * @throws  EmptyStackException  if this stack is empty.
+     */
+    public synchronized E pop() {
+        E       obj;
+        int     len = size();
+
+        obj = peek();
+        removeElementAt(len - 1);
+
+        return obj;
+    }
+
+    /**
+     * Looks at the object at the top of this stack without removing it
+     * from the stack.
+     *
+     * @return  the object at the top of this stack (the last item
+     *          of the <tt>Vector</tt> object).
+     * @throws  EmptyStackException  if this stack is empty.
+     */
+    public synchronized E peek() {
+        int     len = size();
+
+        if (len == 0)
+            throw new EmptyStackException();
+        return elementAt(len - 1);
+    }
+
+    /**
+     * Tests if this stack is empty.
+     *
+     * @return  <code>true</code> if and only if this stack contains
+     *          no items; <code>false</code> otherwise.
+     */
+    public boolean empty() {
+        return size() == 0;
+    }
+
+    /**
+     * Returns the 1-based position where an object is on this stack.
+     * If the object <tt>o</tt> occurs as an item in this stack, this
+     * method returns the distance from the top of the stack of the
+     * occurrence nearest the top of the stack; the topmost item on the
+     * stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
+     * method is used to compare <tt>o</tt> to the
+     * items in this stack.
+     *
+     * @param   o   the desired object.
+     * @return  the 1-based position from the top of the stack where
+     *          the object is located; the return value <code>-1</code>
+     *          indicates that the object is not on the stack.
+     */
+    public synchronized int search(Object o) {
+        int i = lastIndexOf(o);
+
+        if (i >= 0) {
+            return size() - i;
+        }
+        return -1;
+    }
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = 1224463164541339165L;
+}
diff --git a/java/util/StringJoiner.java b/java/util/StringJoiner.java
new file mode 100644
index 0000000..b6ba84c
--- /dev/null
+++ b/java/util/StringJoiner.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+/**
+ * {@code StringJoiner} is used to construct a sequence of characters separated
+ * by a delimiter and optionally starting with a supplied prefix
+ * and ending with a supplied suffix.
+ * <p>
+ * Prior to adding something to the {@code StringJoiner}, its
+ * {@code sj.toString()} method will, by default, return {@code prefix + suffix}.
+ * However, if the {@code setEmptyValue} method is called, the {@code emptyValue}
+ * supplied will be returned instead. This can be used, for example, when
+ * creating a string using set notation to indicate an empty set, i.e.
+ * <code>"{}"</code>, where the {@code prefix} is <code>"{"</code>, the
+ * {@code suffix} is <code>"}"</code> and nothing has been added to the
+ * {@code StringJoiner}.
+ *
+ * @apiNote
+ * <p>The String {@code "[George:Sally:Fred]"} may be constructed as follows:
+ *
+ * <pre> {@code
+ * StringJoiner sj = new StringJoiner(":", "[", "]");
+ * sj.add("George").add("Sally").add("Fred");
+ * String desiredString = sj.toString();
+ * }</pre>
+ * <p>
+ * A {@code StringJoiner} may be employed to create formatted output from a
+ * {@link java.util.stream.Stream} using
+ * {@link java.util.stream.Collectors#joining(CharSequence)}. For example:
+ *
+ * <pre> {@code
+ * List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
+ * String commaSeparatedNumbers = numbers.stream()
+ *     .map(i -> i.toString())
+ *     .collect(Collectors.joining(", "));
+ * }</pre>
+ *
+ * @see java.util.stream.Collectors#joining(CharSequence)
+ * @see java.util.stream.Collectors#joining(CharSequence, CharSequence, CharSequence)
+ * @since  1.8
+*/
+public final class StringJoiner {
+    private final String prefix;
+    private final String delimiter;
+    private final String suffix;
+
+    /*
+     * StringBuilder value -- at any time, the characters constructed from the
+     * prefix, the added element separated by the delimiter, but without the
+     * suffix, so that we can more easily add elements without having to jigger
+     * the suffix each time.
+     */
+    private StringBuilder value;
+
+    /*
+     * By default, the string consisting of prefix+suffix, returned by
+     * toString(), or properties of value, when no elements have yet been added,
+     * i.e. when it is empty.  This may be overridden by the user to be some
+     * other value including the empty String.
+     */
+    private String emptyValue;
+
+    /**
+     * Constructs a {@code StringJoiner} with no characters in it, with no
+     * {@code prefix} or {@code suffix}, and a copy of the supplied
+     * {@code delimiter}.
+     * If no characters are added to the {@code StringJoiner} and methods
+     * accessing the value of it are invoked, it will not return a
+     * {@code prefix} or {@code suffix} (or properties thereof) in the result,
+     * unless {@code setEmptyValue} has first been called.
+     *
+     * @param  delimiter the sequence of characters to be used between each
+     *         element added to the {@code StringJoiner} value
+     * @throws NullPointerException if {@code delimiter} is {@code null}
+     */
+    public StringJoiner(CharSequence delimiter) {
+        this(delimiter, "", "");
+    }
+
+    /**
+     * Constructs a {@code StringJoiner} with no characters in it using copies
+     * of the supplied {@code prefix}, {@code delimiter} and {@code suffix}.
+     * If no characters are added to the {@code StringJoiner} and methods
+     * accessing the string value of it are invoked, it will return the
+     * {@code prefix + suffix} (or properties thereof) in the result, unless
+     * {@code setEmptyValue} has first been called.
+     *
+     * @param  delimiter the sequence of characters to be used between each
+     *         element added to the {@code StringJoiner}
+     * @param  prefix the sequence of characters to be used at the beginning
+     * @param  suffix the sequence of characters to be used at the end
+     * @throws NullPointerException if {@code prefix}, {@code delimiter}, or
+     *         {@code suffix} is {@code null}
+     */
+    public StringJoiner(CharSequence delimiter,
+                        CharSequence prefix,
+                        CharSequence suffix) {
+        Objects.requireNonNull(prefix, "The prefix must not be null");
+        Objects.requireNonNull(delimiter, "The delimiter must not be null");
+        Objects.requireNonNull(suffix, "The suffix must not be null");
+        // make defensive copies of arguments
+        this.prefix = prefix.toString();
+        this.delimiter = delimiter.toString();
+        this.suffix = suffix.toString();
+        this.emptyValue = this.prefix + this.suffix;
+    }
+
+    /**
+     * Sets the sequence of characters to be used when determining the string
+     * representation of this {@code StringJoiner} and no elements have been
+     * added yet, that is, when it is empty.  A copy of the {@code emptyValue}
+     * parameter is made for this purpose. Note that once an add method has been
+     * called, the {@code StringJoiner} is no longer considered empty, even if
+     * the element(s) added correspond to the empty {@code String}.
+     *
+     * @param  emptyValue the characters to return as the value of an empty
+     *         {@code StringJoiner}
+     * @return this {@code StringJoiner} itself so the calls may be chained
+     * @throws NullPointerException when the {@code emptyValue} parameter is
+     *         {@code null}
+     */
+    public StringJoiner setEmptyValue(CharSequence emptyValue) {
+        this.emptyValue = Objects.requireNonNull(emptyValue,
+            "The empty value must not be null").toString();
+        return this;
+    }
+
+    /**
+     * Returns the current value, consisting of the {@code prefix}, the values
+     * added so far separated by the {@code delimiter}, and the {@code suffix},
+     * unless no elements have been added in which case, the
+     * {@code prefix + suffix} or the {@code emptyValue} characters are returned
+     *
+     * @return the string representation of this {@code StringJoiner}
+     */
+    @Override
+    public String toString() {
+        if (value == null) {
+            return emptyValue;
+        } else {
+            if (suffix.equals("")) {
+                return value.toString();
+            } else {
+                int initialLength = value.length();
+                String result = value.append(suffix).toString();
+                // reset value to pre-append initialLength
+                value.setLength(initialLength);
+                return result;
+            }
+        }
+    }
+
+    /**
+     * Adds a copy of the given {@code CharSequence} value as the next
+     * element of the {@code StringJoiner} value. If {@code newElement} is
+     * {@code null}, then {@code "null"} is added.
+     *
+     * @param  newElement The element to add
+     * @return a reference to this {@code StringJoiner}
+     */
+    public StringJoiner add(CharSequence newElement) {
+        prepareBuilder().append(newElement);
+        return this;
+    }
+
+    /**
+     * Adds the contents of the given {@code StringJoiner} without prefix and
+     * suffix as the next element if it is non-empty. If the given {@code
+     * StringJoiner} is empty, the call has no effect.
+     *
+     * <p>A {@code StringJoiner} is empty if {@link #add(CharSequence) add()}
+     * has never been called, and if {@code merge()} has never been called
+     * with a non-empty {@code StringJoiner} argument.
+     *
+     * <p>If the other {@code StringJoiner} is using a different delimiter,
+     * then elements from the other {@code StringJoiner} are concatenated with
+     * that delimiter and the result is appended to this {@code StringJoiner}
+     * as a single element.
+     *
+     * @param other The {@code StringJoiner} whose contents should be merged
+     *              into this one
+     * @throws NullPointerException if the other {@code StringJoiner} is null
+     * @return This {@code StringJoiner}
+     */
+    public StringJoiner merge(StringJoiner other) {
+        Objects.requireNonNull(other);
+        if (other.value != null) {
+            final int length = other.value.length();
+            // lock the length so that we can seize the data to be appended
+            // before initiate copying to avoid interference, especially when
+            // merge 'this'
+            StringBuilder builder = prepareBuilder();
+            builder.append(other.value, other.prefix.length(), length);
+        }
+        return this;
+    }
+
+    private StringBuilder prepareBuilder() {
+        if (value != null) {
+            value.append(delimiter);
+        } else {
+            value = new StringBuilder().append(prefix);
+        }
+        return value;
+    }
+
+    /**
+     * Returns the length of the {@code String} representation
+     * of this {@code StringJoiner}. Note that if
+     * no add methods have been called, then the length of the {@code String}
+     * representation (either {@code prefix + suffix} or {@code emptyValue})
+     * will be returned. The value should be equivalent to
+     * {@code toString().length()}.
+     *
+     * @return the length of the current value of {@code StringJoiner}
+     */
+    public int length() {
+        // Remember that we never actually append the suffix unless we return
+        // the full (present) value or some sub-string or length of it, so that
+        // we can add on more if we need to.
+        return (value != null ? value.length() + suffix.length() :
+                emptyValue.length());
+    }
+}
diff --git a/java/util/StringTokenizer.java b/java/util/StringTokenizer.java
new file mode 100644
index 0000000..1540c1a
--- /dev/null
+++ b/java/util/StringTokenizer.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.*;
+
+/**
+ * The string tokenizer class allows an application to break a
+ * string into tokens. The tokenization method is much simpler than
+ * the one used by the <code>StreamTokenizer</code> class. The
+ * <code>StringTokenizer</code> methods do not distinguish among
+ * identifiers, numbers, and quoted strings, nor do they recognize
+ * and skip comments.
+ * <p>
+ * The set of delimiters (the characters that separate tokens) may
+ * be specified either at creation time or on a per-token basis.
+ * <p>
+ * An instance of <code>StringTokenizer</code> behaves in one of two
+ * ways, depending on whether it was created with the
+ * <code>returnDelims</code> flag having the value <code>true</code>
+ * or <code>false</code>:
+ * <ul>
+ * <li>If the flag is <code>false</code>, delimiter characters serve to
+ *     separate tokens. A token is a maximal sequence of consecutive
+ *     characters that are not delimiters.
+ * <li>If the flag is <code>true</code>, delimiter characters are themselves
+ *     considered to be tokens. A token is thus either one delimiter
+ *     character, or a maximal sequence of consecutive characters that are
+ *     not delimiters.
+ * </ul><p>
+ * A <tt>StringTokenizer</tt> object internally maintains a current
+ * position within the string to be tokenized. Some operations advance this
+ * current position past the characters processed.<p>
+ * A token is returned by taking a substring of the string that was used to
+ * create the <tt>StringTokenizer</tt> object.
+ * <p>
+ * The following is one example of the use of the tokenizer. The code:
+ * <blockquote><pre>
+ *     StringTokenizer st = new StringTokenizer("this is a test");
+ *     while (st.hasMoreTokens()) {
+ *         System.out.println(st.nextToken());
+ *     }
+ * </pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>
+ *     this
+ *     is
+ *     a
+ *     test
+ * </pre></blockquote>
+ *
+ * <p>
+ * <tt>StringTokenizer</tt> is a legacy class that is retained for
+ * compatibility reasons although its use is discouraged in new code. It is
+ * recommended that anyone seeking this functionality use the <tt>split</tt>
+ * method of <tt>String</tt> or the java.util.regex package instead.
+ * <p>
+ * The following example illustrates how the <tt>String.split</tt>
+ * method can be used to break up a string into its basic tokens:
+ * <blockquote><pre>
+ *     String[] result = "this is a test".split("\\s");
+ *     for (int x=0; x&lt;result.length; x++)
+ *         System.out.println(result[x]);
+ * </pre></blockquote>
+ * <p>
+ * prints the following output:
+ * <blockquote><pre>
+ *     this
+ *     is
+ *     a
+ *     test
+ * </pre></blockquote>
+ *
+ * @author  unascribed
+ * @see     java.io.StreamTokenizer
+ * @since   JDK1.0
+ */
+public
+class StringTokenizer implements Enumeration<Object> {
+    private int currentPosition;
+    private int newPosition;
+    private int maxPosition;
+    private String str;
+    private String delimiters;
+    private boolean retDelims;
+    private boolean delimsChanged;
+
+    /**
+     * maxDelimCodePoint stores the value of the delimiter character with the
+     * highest value. It is used to optimize the detection of delimiter
+     * characters.
+     *
+     * It is unlikely to provide any optimization benefit in the
+     * hasSurrogates case because most string characters will be
+     * smaller than the limit, but we keep it so that the two code
+     * paths remain similar.
+     */
+    private int maxDelimCodePoint;
+
+    /**
+     * If delimiters include any surrogates (including surrogate
+     * pairs), hasSurrogates is true and the tokenizer uses the
+     * different code path. This is because String.indexOf(int)
+     * doesn't handle unpaired surrogates as a single character.
+     */
+    private boolean hasSurrogates = false;
+
+    /**
+     * When hasSurrogates is true, delimiters are converted to code
+     * points and isDelimiter(int) is used to determine if the given
+     * codepoint is a delimiter.
+     */
+    private int[] delimiterCodePoints;
+
+    /**
+     * Set maxDelimCodePoint to the highest char in the delimiter set.
+     */
+    private void setMaxDelimCodePoint() {
+        if (delimiters == null) {
+            maxDelimCodePoint = 0;
+            return;
+        }
+
+        int m = 0;
+        int c;
+        int count = 0;
+        for (int i = 0; i < delimiters.length(); i += Character.charCount(c)) {
+            c = delimiters.charAt(i);
+            if (c >= Character.MIN_HIGH_SURROGATE && c <= Character.MAX_LOW_SURROGATE) {
+                c = delimiters.codePointAt(i);
+                hasSurrogates = true;
+            }
+            if (m < c)
+                m = c;
+            count++;
+        }
+        maxDelimCodePoint = m;
+
+        if (hasSurrogates) {
+            delimiterCodePoints = new int[count];
+            for (int i = 0, j = 0; i < count; i++, j += Character.charCount(c)) {
+                c = delimiters.codePointAt(j);
+                delimiterCodePoints[i] = c;
+            }
+        }
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. All
+     * characters in the <code>delim</code> argument are the delimiters
+     * for separating tokens.
+     * <p>
+     * If the <code>returnDelims</code> flag is <code>true</code>, then
+     * the delimiter characters are also returned as tokens. Each
+     * delimiter is returned as a string of length one. If the flag is
+     * <code>false</code>, the delimiter characters are skipped and only
+     * serve as separators between tokens.
+     * <p>
+     * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
+     * not throw an exception. However, trying to invoke other methods on the
+     * resulting <tt>StringTokenizer</tt> may result in a
+     * <tt>NullPointerException</tt>.
+     *
+     * @param   str            a string to be parsed.
+     * @param   delim          the delimiters.
+     * @param   returnDelims   flag indicating whether to return the delimiters
+     *                         as tokens.
+     * @exception NullPointerException if str is <CODE>null</CODE>
+     */
+    public StringTokenizer(String str, String delim, boolean returnDelims) {
+        currentPosition = 0;
+        newPosition = -1;
+        delimsChanged = false;
+        this.str = str;
+        maxPosition = str.length();
+        delimiters = delim;
+        retDelims = returnDelims;
+        setMaxDelimCodePoint();
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. The
+     * characters in the <code>delim</code> argument are the delimiters
+     * for separating tokens. Delimiter characters themselves will not
+     * be treated as tokens.
+     * <p>
+     * Note that if <tt>delim</tt> is <tt>null</tt>, this constructor does
+     * not throw an exception. However, trying to invoke other methods on the
+     * resulting <tt>StringTokenizer</tt> may result in a
+     * <tt>NullPointerException</tt>.
+     *
+     * @param   str     a string to be parsed.
+     * @param   delim   the delimiters.
+     * @exception NullPointerException if str is <CODE>null</CODE>
+     */
+    public StringTokenizer(String str, String delim) {
+        this(str, delim, false);
+    }
+
+    /**
+     * Constructs a string tokenizer for the specified string. The
+     * tokenizer uses the default delimiter set, which is
+     * <code>"&nbsp;&#92;t&#92;n&#92;r&#92;f"</code>: the space character,
+     * the tab character, the newline character, the carriage-return character,
+     * and the form-feed character. Delimiter characters themselves will
+     * not be treated as tokens.
+     *
+     * @param   str   a string to be parsed.
+     * @exception NullPointerException if str is <CODE>null</CODE>
+     */
+    public StringTokenizer(String str) {
+        this(str, " \t\n\r\f", false);
+    }
+
+    /**
+     * Skips delimiters starting from the specified position. If retDelims
+     * is false, returns the index of the first non-delimiter character at or
+     * after startPos. If retDelims is true, startPos is returned.
+     */
+    private int skipDelimiters(int startPos) {
+        if (delimiters == null)
+            throw new NullPointerException();
+
+        int position = startPos;
+        while (!retDelims && position < maxPosition) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c > maxDelimCodePoint) || (delimiters.indexOf(c) < 0))
+                    break;
+                position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c > maxDelimCodePoint) || !isDelimiter(c)) {
+                    break;
+                }
+                position += Character.charCount(c);
+            }
+        }
+        return position;
+    }
+
+    /**
+     * Skips ahead from startPos and returns the index of the next delimiter
+     * character encountered, or maxPosition if no such delimiter is found.
+     */
+    private int scanToken(int startPos) {
+        int position = startPos;
+        while (position < maxPosition) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
+                    break;
+                position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c <= maxDelimCodePoint) && isDelimiter(c))
+                    break;
+                position += Character.charCount(c);
+            }
+        }
+        if (retDelims && (startPos == position)) {
+            if (!hasSurrogates) {
+                char c = str.charAt(position);
+                if ((c <= maxDelimCodePoint) && (delimiters.indexOf(c) >= 0))
+                    position++;
+            } else {
+                int c = str.codePointAt(position);
+                if ((c <= maxDelimCodePoint) && isDelimiter(c))
+                    position += Character.charCount(c);
+            }
+        }
+        return position;
+    }
+
+    private boolean isDelimiter(int codePoint) {
+        for (int i = 0; i < delimiterCodePoints.length; i++) {
+            if (delimiterCodePoints[i] == codePoint) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests if there are more tokens available from this tokenizer's string.
+     * If this method returns <tt>true</tt>, then a subsequent call to
+     * <tt>nextToken</tt> with no argument will successfully return a token.
+     *
+     * @return  <code>true</code> if and only if there is at least one token
+     *          in the string after the current position; <code>false</code>
+     *          otherwise.
+     */
+    public boolean hasMoreTokens() {
+        /*
+         * Temporarily store this position and use it in the following
+         * nextToken() method only if the delimiters haven't been changed in
+         * that nextToken() invocation.
+         */
+        newPosition = skipDelimiters(currentPosition);
+        return (newPosition < maxPosition);
+    }
+
+    /**
+     * Returns the next token from this string tokenizer.
+     *
+     * @return     the next token from this string tokenizer.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     */
+    public String nextToken() {
+        /*
+         * If next position already computed in hasMoreElements() and
+         * delimiters have changed between the computation and this invocation,
+         * then use the computed value.
+         */
+
+        currentPosition = (newPosition >= 0 && !delimsChanged) ?
+            newPosition : skipDelimiters(currentPosition);
+
+        /* Reset these anyway */
+        delimsChanged = false;
+        newPosition = -1;
+
+        if (currentPosition >= maxPosition)
+            throw new NoSuchElementException();
+        int start = currentPosition;
+        currentPosition = scanToken(currentPosition);
+        return str.substring(start, currentPosition);
+    }
+
+    /**
+     * Returns the next token in this string tokenizer's string. First,
+     * the set of characters considered to be delimiters by this
+     * <tt>StringTokenizer</tt> object is changed to be the characters in
+     * the string <tt>delim</tt>. Then the next token in the string
+     * after the current position is returned. The current position is
+     * advanced beyond the recognized token.  The new delimiter set
+     * remains the default after this call.
+     *
+     * @param      delim   the new delimiters.
+     * @return     the next token, after switching to the new delimiter set.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     * @exception NullPointerException if delim is <CODE>null</CODE>
+     */
+    public String nextToken(String delim) {
+        delimiters = delim;
+
+        /* delimiter string specified, so set the appropriate flag. */
+        delimsChanged = true;
+
+        setMaxDelimCodePoint();
+        return nextToken();
+    }
+
+    /**
+     * Returns the same value as the <code>hasMoreTokens</code>
+     * method. It exists so that this class can implement the
+     * <code>Enumeration</code> interface.
+     *
+     * @return  <code>true</code> if there are more tokens;
+     *          <code>false</code> otherwise.
+     * @see     java.util.Enumeration
+     * @see     java.util.StringTokenizer#hasMoreTokens()
+     */
+    public boolean hasMoreElements() {
+        return hasMoreTokens();
+    }
+
+    /**
+     * Returns the same value as the <code>nextToken</code> method,
+     * except that its declared return value is <code>Object</code> rather than
+     * <code>String</code>. It exists so that this class can implement the
+     * <code>Enumeration</code> interface.
+     *
+     * @return     the next token in the string.
+     * @exception  NoSuchElementException  if there are no more tokens in this
+     *               tokenizer's string.
+     * @see        java.util.Enumeration
+     * @see        java.util.StringTokenizer#nextToken()
+     */
+    public Object nextElement() {
+        return nextToken();
+    }
+
+    /**
+     * Calculates the number of times that this tokenizer's
+     * <code>nextToken</code> method can be called before it generates an
+     * exception. The current position is not advanced.
+     *
+     * @return  the number of tokens remaining in the string using the current
+     *          delimiter set.
+     * @see     java.util.StringTokenizer#nextToken()
+     */
+    public int countTokens() {
+        int count = 0;
+        int currpos = currentPosition;
+        while (currpos < maxPosition) {
+            currpos = skipDelimiters(currpos);
+            if (currpos >= maxPosition)
+                break;
+            currpos = scanToken(currpos);
+            count++;
+        }
+        return count;
+    }
+}
diff --git a/java/util/TimSort.java b/java/util/TimSort.java
new file mode 100644
index 0000000..ea0d58f
--- /dev/null
+++ b/java/util/TimSort.java
@@ -0,0 +1,941 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2009 Google Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A stable, adaptive, iterative mergesort that requires far fewer than
+ * n lg(n) comparisons when running on partially sorted arrays, while
+ * offering performance comparable to a traditional mergesort when run
+ * on random arrays.  Like all proper mergesorts, this sort is stable and
+ * runs O(n log n) time (worst case).  In the worst case, this sort requires
+ * temporary storage space for n/2 object references; in the best case,
+ * it requires only a small constant amount of space.
+ *
+ * This implementation was adapted from Tim Peters's list sort for
+ * Python, which is described in detail here:
+ *
+ *   http://svn.python.org/projects/python/trunk/Objects/listsort.txt
+ *
+ * Tim's C code may be found here:
+ *
+ *   http://svn.python.org/projects/python/trunk/Objects/listobject.c
+ *
+ * The underlying techniques are described in this paper (and may have
+ * even earlier origins):
+ *
+ *  "Optimistic Sorting and Information Theoretic Complexity"
+ *  Peter McIlroy
+ *  SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms),
+ *  pp 467-474, Austin, Texas, 25-27 January 1993.
+ *
+ * While the API to this class consists solely of static methods, it is
+ * (privately) instantiable; a TimSort instance holds the state of an ongoing
+ * sort, assuming the input array is large enough to warrant the full-blown
+ * TimSort. Small arrays are sorted in place, using a binary insertion sort.
+ *
+ * @author Josh Bloch
+ */
+class TimSort<T> {
+    /**
+     * This is the minimum sized sequence that will be merged.  Shorter
+     * sequences will be lengthened by calling binarySort.  If the entire
+     * array is less than this length, no merges will be performed.
+     *
+     * This constant should be a power of two.  It was 64 in Tim Peter's C
+     * implementation, but 32 was empirically determined to work better in
+     * this implementation.  In the unlikely event that you set this constant
+     * to be a number that's not a power of two, you'll need to change the
+     * {@link #minRunLength} computation.
+     *
+     * If you decrease this constant, you must change the stackLen
+     * computation in the TimSort constructor, or you risk an
+     * ArrayOutOfBounds exception.  See listsort.txt for a discussion
+     * of the minimum stack length required as a function of the length
+     * of the array being sorted and the minimum merge sequence length.
+     */
+    private static final int MIN_MERGE = 32;
+
+    /**
+     * The array being sorted.
+     */
+    private final T[] a;
+
+    /**
+     * The comparator for this sort.
+     */
+    private final Comparator<? super T> c;
+
+    /**
+     * When we get into galloping mode, we stay there until both runs win less
+     * often than MIN_GALLOP consecutive times.
+     */
+    private static final int  MIN_GALLOP = 7;
+
+    /**
+     * This controls when we get *into* galloping mode.  It is initialized
+     * to MIN_GALLOP.  The mergeLo and mergeHi methods nudge it higher for
+     * random data, and lower for highly structured data.
+     */
+    private int minGallop = MIN_GALLOP;
+
+    /**
+     * Maximum initial size of tmp array, which is used for merging.  The array
+     * can grow to accommodate demand.
+     *
+     * Unlike Tim's original C version, we do not allocate this much storage
+     * when sorting smaller arrays.  This change was required for performance.
+     */
+    private static final int INITIAL_TMP_STORAGE_LENGTH = 256;
+
+    /**
+     * Temp storage for merges. A workspace array may optionally be
+     * provided in constructor, and if so will be used as long as it
+     * is big enough.
+     */
+    private T[] tmp;
+    private int tmpBase; // base of tmp array slice
+    private int tmpLen;  // length of tmp array slice
+
+    /**
+     * A stack of pending runs yet to be merged.  Run i starts at
+     * address base[i] and extends for len[i] elements.  It's always
+     * true (so long as the indices are in bounds) that:
+     *
+     *     runBase[i] + runLen[i] == runBase[i + 1]
+     *
+     * so we could cut the storage for this, but it's a minor amount,
+     * and keeping all the info explicit simplifies the code.
+     */
+    private int stackSize = 0;  // Number of pending runs on stack
+    private final int[] runBase;
+    private final int[] runLen;
+
+    /**
+     * Creates a TimSort instance to maintain the state of an ongoing sort.
+     *
+     * @param a the array to be sorted
+     * @param c the comparator to determine the order of the sort
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     */
+    private TimSort(T[] a, Comparator<? super T> c, T[] work, int workBase, int workLen) {
+        this.a = a;
+        this.c = c;
+
+        // Allocate temp storage (which may be increased later if necessary)
+        int len = a.length;
+        int tlen = (len < 2 * INITIAL_TMP_STORAGE_LENGTH) ?
+            len >>> 1 : INITIAL_TMP_STORAGE_LENGTH;
+        if (work == null || workLen < tlen || workBase + tlen > work.length) {
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), tlen);
+            tmp = newArray;
+            tmpBase = 0;
+            tmpLen = tlen;
+        }
+        else {
+            tmp = work;
+            tmpBase = workBase;
+            tmpLen = workLen;
+        }
+
+        /*
+         * Allocate runs-to-be-merged stack (which cannot be expanded).  The
+         * stack length requirements are described in listsort.txt.  The C
+         * version always uses the same stack length (85), but this was
+         * measured to be too expensive when sorting "mid-sized" arrays (e.g.,
+         * 100 elements) in Java.  Therefore, we use smaller (but sufficiently
+         * large) stack lengths for smaller arrays.  The "magic numbers" in the
+         * computation below must be changed if MIN_MERGE is decreased.  See
+         * the MIN_MERGE declaration above for more information.
+         * The maximum value of 49 allows for an array up to length
+         * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+         * increasing scenario. More explanations are given in section 4 of:
+         * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
+         */
+        int stackLen = (len <    120  ?  5 :
+                        len <   1542  ? 10 :
+                        len < 119151  ? 24 : 49);
+        runBase = new int[stackLen];
+        runLen = new int[stackLen];
+    }
+
+    /*
+     * The next method (package private and static) constitutes the
+     * entire API of this class.
+     */
+
+    /**
+     * Sorts the given range, using the given workspace array slice
+     * for temp storage when possible. This method is designed to be
+     * invoked from public methods (in class Arrays) after performing
+     * any necessary array bounds checks and expanding parameters into
+     * the required forms.
+     *
+     * @param a the array to be sorted
+     * @param lo the index of the first element, inclusive, to be sorted
+     * @param hi the index of the last element, exclusive, to be sorted
+     * @param c the comparator to use
+     * @param work a workspace array (slice)
+     * @param workBase origin of usable space in work array
+     * @param workLen usable size of work array
+     * @since 1.8
+     */
+    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
+                         T[] work, int workBase, int workLen) {
+        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
+
+        int nRemaining  = hi - lo;
+        if (nRemaining < 2)
+            return;  // Arrays of size 0 and 1 are always sorted
+
+        // If array is small, do a "mini-TimSort" with no merges
+        if (nRemaining < MIN_MERGE) {
+            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
+            binarySort(a, lo, hi, lo + initRunLen, c);
+            return;
+        }
+
+        /**
+         * March over the array once, left to right, finding natural runs,
+         * extending short natural runs to minRun elements, and merging runs
+         * to maintain stack invariant.
+         */
+        TimSort<T> ts = new TimSort<>(a, c, work, workBase, workLen);
+        int minRun = minRunLength(nRemaining);
+        do {
+            // Identify next run
+            int runLen = countRunAndMakeAscending(a, lo, hi, c);
+
+            // If run is short, extend to min(minRun, nRemaining)
+            if (runLen < minRun) {
+                int force = nRemaining <= minRun ? nRemaining : minRun;
+                binarySort(a, lo, lo + force, lo + runLen, c);
+                runLen = force;
+            }
+
+            // Push run onto pending-run stack, and maybe merge
+            ts.pushRun(lo, runLen);
+            ts.mergeCollapse();
+
+            // Advance to find next run
+            lo += runLen;
+            nRemaining -= runLen;
+        } while (nRemaining != 0);
+
+        // Merge all remaining runs to complete sort
+        assert lo == hi;
+        ts.mergeForceCollapse();
+        assert ts.stackSize == 1;
+    }
+
+    /**
+     * Sorts the specified portion of the specified array using a binary
+     * insertion sort.  This is the best method for sorting small numbers
+     * of elements.  It requires O(n log n) compares, but O(n^2) data
+     * movement (worst case).
+     *
+     * If the initial part of the specified range is already sorted,
+     * this method can take advantage of it: the method assumes that the
+     * elements from index {@code lo}, inclusive, to {@code start},
+     * exclusive are already sorted.
+     *
+     * @param a the array in which a range is to be sorted
+     * @param lo the index of the first element in the range to be sorted
+     * @param hi the index after the last element in the range to be sorted
+     * @param start the index of the first element in the range that is
+     *        not already known to be sorted ({@code lo <= start <= hi})
+     * @param c comparator to used for the sort
+     */
+    @SuppressWarnings("fallthrough")
+    private static <T> void binarySort(T[] a, int lo, int hi, int start,
+                                       Comparator<? super T> c) {
+        assert lo <= start && start <= hi;
+        if (start == lo)
+            start++;
+        for ( ; start < hi; start++) {
+            T pivot = a[start];
+
+            // Set left (and right) to the index where a[start] (pivot) belongs
+            int left = lo;
+            int right = start;
+            assert left <= right;
+            /*
+             * Invariants:
+             *   pivot >= all in [lo, left).
+             *   pivot <  all in [right, start).
+             */
+            while (left < right) {
+                int mid = (left + right) >>> 1;
+                if (c.compare(pivot, a[mid]) < 0)
+                    right = mid;
+                else
+                    left = mid + 1;
+            }
+            assert left == right;
+
+            /*
+             * The invariants still hold: pivot >= all in [lo, left) and
+             * pivot < all in [left, start), so pivot belongs at left.  Note
+             * that if there are elements equal to pivot, left points to the
+             * first slot after them -- that's why this sort is stable.
+             * Slide elements over to make room for pivot.
+             */
+            int n = start - left;  // The number of elements to move
+            // Switch is just an optimization for arraycopy in default case
+            switch (n) {
+                case 2:  a[left + 2] = a[left + 1];
+                case 1:  a[left + 1] = a[left];
+                         break;
+                default: System.arraycopy(a, left, a, left + 1, n);
+            }
+            a[left] = pivot;
+        }
+    }
+
+    /**
+     * Returns the length of the run beginning at the specified position in
+     * the specified array and reverses the run if it is descending (ensuring
+     * that the run will always be ascending when the method returns).
+     *
+     * A run is the longest ascending sequence with:
+     *
+     *    a[lo] <= a[lo + 1] <= a[lo + 2] <= ...
+     *
+     * or the longest descending sequence with:
+     *
+     *    a[lo] >  a[lo + 1] >  a[lo + 2] >  ...
+     *
+     * For its intended use in a stable mergesort, the strictness of the
+     * definition of "descending" is needed so that the call can safely
+     * reverse a descending sequence without violating stability.
+     *
+     * @param a the array in which a run is to be counted and possibly reversed
+     * @param lo index of the first element in the run
+     * @param hi index after the last element that may be contained in the run.
+              It is required that {@code lo < hi}.
+     * @param c the comparator to used for the sort
+     * @return  the length of the run beginning at the specified position in
+     *          the specified array
+     */
+    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
+                                                    Comparator<? super T> c) {
+        assert lo < hi;
+        int runHi = lo + 1;
+        if (runHi == hi)
+            return 1;
+
+        // Find end of run, and reverse range if descending
+        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
+            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
+                runHi++;
+            reverseRange(a, lo, runHi);
+        } else {                              // Ascending
+            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
+                runHi++;
+        }
+
+        return runHi - lo;
+    }
+
+    /**
+     * Reverse the specified range of the specified array.
+     *
+     * @param a the array in which a range is to be reversed
+     * @param lo the index of the first element in the range to be reversed
+     * @param hi the index after the last element in the range to be reversed
+     */
+    private static void reverseRange(Object[] a, int lo, int hi) {
+        hi--;
+        while (lo < hi) {
+            Object t = a[lo];
+            a[lo++] = a[hi];
+            a[hi--] = t;
+        }
+    }
+
+    /**
+     * Returns the minimum acceptable run length for an array of the specified
+     * length. Natural runs shorter than this will be extended with
+     * {@link #binarySort}.
+     *
+     * Roughly speaking, the computation is:
+     *
+     *  If n < MIN_MERGE, return n (it's too small to bother with fancy stuff).
+     *  Else if n is an exact power of 2, return MIN_MERGE/2.
+     *  Else return an int k, MIN_MERGE/2 <= k <= MIN_MERGE, such that n/k
+     *   is close to, but strictly less than, an exact power of 2.
+     *
+     * For the rationale, see listsort.txt.
+     *
+     * @param n the length of the array to be sorted
+     * @return the length of the minimum run to be merged
+     */
+    private static int minRunLength(int n) {
+        assert n >= 0;
+        int r = 0;      // Becomes 1 if any 1 bits are shifted off
+        while (n >= MIN_MERGE) {
+            r |= (n & 1);
+            n >>= 1;
+        }
+        return n + r;
+    }
+
+    /**
+     * Pushes the specified run onto the pending-run stack.
+     *
+     * @param runBase index of the first element in the run
+     * @param runLen  the number of elements in the run
+     */
+    private void pushRun(int runBase, int runLen) {
+        this.runBase[stackSize] = runBase;
+        this.runLen[stackSize] = runLen;
+        stackSize++;
+    }
+
+    /**
+     * Examines the stack of runs waiting to be merged and merges adjacent runs
+     * until the stack invariants are reestablished:
+     *
+     *     1. runLen[i - 3] > runLen[i - 2] + runLen[i - 1]
+     *     2. runLen[i - 2] > runLen[i - 1]
+     *
+     * This method is called each time a new run is pushed onto the stack,
+     * so the invariants are guaranteed to hold for i < stackSize upon
+     * entry to the method.
+     */
+    private void mergeCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n-1] <= runLen[n] + runLen[n+1]) {
+                if (runLen[n - 1] < runLen[n + 1])
+                    n--;
+                mergeAt(n);
+            } else if (runLen[n] <= runLen[n + 1]) {
+                mergeAt(n);
+            } else {
+                break; // Invariant is established
+            }
+        }
+    }
+
+    /**
+     * Merges all runs on the stack until only one remains.  This method is
+     * called once, to complete the sort.
+     */
+    private void mergeForceCollapse() {
+        while (stackSize > 1) {
+            int n = stackSize - 2;
+            if (n > 0 && runLen[n - 1] < runLen[n + 1])
+                n--;
+            mergeAt(n);
+        }
+    }
+
+    /**
+     * Merges the two runs at stack indices i and i+1.  Run i must be
+     * the penultimate or antepenultimate run on the stack.  In other words,
+     * i must be equal to stackSize-2 or stackSize-3.
+     *
+     * @param i stack index of the first of the two runs to merge
+     */
+    private void mergeAt(int i) {
+        assert stackSize >= 2;
+        assert i >= 0;
+        assert i == stackSize - 2 || i == stackSize - 3;
+
+        int base1 = runBase[i];
+        int len1 = runLen[i];
+        int base2 = runBase[i + 1];
+        int len2 = runLen[i + 1];
+        assert len1 > 0 && len2 > 0;
+        assert base1 + len1 == base2;
+
+        /*
+         * Record the length of the combined runs; if i is the 3rd-last
+         * run now, also slide over the last run (which isn't involved
+         * in this merge).  The current run (i+1) goes away in any case.
+         */
+        runLen[i] = len1 + len2;
+        if (i == stackSize - 3) {
+            runBase[i + 1] = runBase[i + 2];
+            runLen[i + 1] = runLen[i + 2];
+        }
+        stackSize--;
+
+        /*
+         * Find where the first element of run2 goes in run1. Prior elements
+         * in run1 can be ignored (because they're already in place).
+         */
+        int k = gallopRight(a[base2], a, base1, len1, 0, c);
+        assert k >= 0;
+        base1 += k;
+        len1 -= k;
+        if (len1 == 0)
+            return;
+
+        /*
+         * Find where the last element of run1 goes in run2. Subsequent elements
+         * in run2 can be ignored (because they're already in place).
+         */
+        len2 = gallopLeft(a[base1 + len1 - 1], a, base2, len2, len2 - 1, c);
+        assert len2 >= 0;
+        if (len2 == 0)
+            return;
+
+        // Merge remaining runs, using tmp array with min(len1, len2) elements
+        if (len1 <= len2)
+            mergeLo(base1, len1, base2, len2);
+        else
+            mergeHi(base1, len1, base2, len2);
+    }
+
+    /**
+     * Locates the position at which to insert the specified key into the
+     * specified sorted range; if the range contains an element equal to key,
+     * returns the index of the leftmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @param c the comparator used to order the range, and to search
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] < key <= a[b + k],
+     *    pretending that a[b - 1] is minus infinity and a[b + n] is infinity.
+     *    In other words, key belongs at index b + k; or in other words,
+     *    the first k elements of a should precede key, and the last n - k
+     *    should follow it.
+     */
+    private static <T> int gallopLeft(T key, T[] a, int base, int len, int hint,
+                                      Comparator<? super T> c) {
+        assert len > 0 && hint >= 0 && hint < len;
+        int lastOfs = 0;
+        int ofs = 1;
+        if (c.compare(key, a[base + hint]) > 0) {
+            // Gallop right until a[base+hint+lastOfs] < key <= a[base+hint+ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) > 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            lastOfs += hint;
+            ofs += hint;
+        } else { // key <= a[base + hint]
+            // Gallop left until a[base+hint-ofs] < key <= a[base+hint-lastOfs]
+            final int maxOfs = hint + 1;
+            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) <= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to base
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[base+lastOfs] < key <= a[base+ofs], so key belongs somewhere
+         * to the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[base + lastOfs - 1] < key <= a[base + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (c.compare(key, a[base + m]) > 0)
+                lastOfs = m + 1;  // a[base + m] < key
+            else
+                ofs = m;          // key <= a[base + m]
+        }
+        assert lastOfs == ofs;    // so a[base + ofs - 1] < key <= a[base + ofs]
+        return ofs;
+    }
+
+    /**
+     * Like gallopLeft, except that if the range contains an element equal to
+     * key, gallopRight returns the index after the rightmost equal element.
+     *
+     * @param key the key whose insertion point to search for
+     * @param a the array in which to search
+     * @param base the index of the first element in the range
+     * @param len the length of the range; must be > 0
+     * @param hint the index at which to begin the search, 0 <= hint < n.
+     *     The closer hint is to the result, the faster this method will run.
+     * @param c the comparator used to order the range, and to search
+     * @return the int k,  0 <= k <= n such that a[b + k - 1] <= key < a[b + k]
+     */
+    private static <T> int gallopRight(T key, T[] a, int base, int len,
+                                       int hint, Comparator<? super T> c) {
+        assert len > 0 && hint >= 0 && hint < len;
+
+        int ofs = 1;
+        int lastOfs = 0;
+        if (c.compare(key, a[base + hint]) < 0) {
+            // Gallop left until a[b+hint - ofs] <= key < a[b+hint - lastOfs]
+            int maxOfs = hint + 1;
+            while (ofs < maxOfs && c.compare(key, a[base + hint - ofs]) < 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            int tmp = lastOfs;
+            lastOfs = hint - ofs;
+            ofs = hint - tmp;
+        } else { // a[b + hint] <= key
+            // Gallop right until a[b+hint + lastOfs] <= key < a[b+hint + ofs]
+            int maxOfs = len - hint;
+            while (ofs < maxOfs && c.compare(key, a[base + hint + ofs]) >= 0) {
+                lastOfs = ofs;
+                ofs = (ofs << 1) + 1;
+                if (ofs <= 0)   // int overflow
+                    ofs = maxOfs;
+            }
+            if (ofs > maxOfs)
+                ofs = maxOfs;
+
+            // Make offsets relative to b
+            lastOfs += hint;
+            ofs += hint;
+        }
+        assert -1 <= lastOfs && lastOfs < ofs && ofs <= len;
+
+        /*
+         * Now a[b + lastOfs] <= key < a[b + ofs], so key belongs somewhere to
+         * the right of lastOfs but no farther right than ofs.  Do a binary
+         * search, with invariant a[b + lastOfs - 1] <= key < a[b + ofs].
+         */
+        lastOfs++;
+        while (lastOfs < ofs) {
+            int m = lastOfs + ((ofs - lastOfs) >>> 1);
+
+            if (c.compare(key, a[base + m]) < 0)
+                ofs = m;          // key < a[b + m]
+            else
+                lastOfs = m + 1;  // a[b + m] <= key
+        }
+        assert lastOfs == ofs;    // so a[b + ofs - 1] <= key < a[b + ofs]
+        return ofs;
+    }
+
+    /**
+     * Merges two adjacent runs in place, in a stable fashion.  The first
+     * element of the first run must be greater than the first element of the
+     * second run (a[base1] > a[base2]), and the last element of the first run
+     * (a[base1 + len1-1]) must be greater than all elements of the second run.
+     *
+     * For performance, this method should be called only when len1 <= len2;
+     * its twin, mergeHi should be called if len1 >= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    private void mergeLo(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy first run into temp array
+        T[] a = this.a; // For performance
+        T[] tmp = ensureCapacity(len1);
+        int cursor1 = tmpBase; // Indexes into tmp array
+        int cursor2 = base2;   // Indexes int a
+        int dest = base1;      // Indexes int a
+        System.arraycopy(a, base1, tmp, cursor1, len1);
+
+        // Move first element of second run and deal with degenerate cases
+        a[dest++] = a[cursor2++];
+        if (--len2 == 0) {
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+            return;
+        }
+        if (len1 == 1) {
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
+            return;
+        }
+
+        Comparator<? super T> c = this.c;  // Use local variable for performance
+        int minGallop = this.minGallop;    //  "    "       "     "      "
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run starts
+             * winning consistently.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                if (c.compare(a[cursor2], tmp[cursor1]) < 0) {
+                    a[dest++] = a[cursor2++];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 0)
+                        break outer;
+                } else {
+                    a[dest++] = tmp[cursor1++];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 1 && len2 > 0;
+                count1 = gallopRight(a[cursor2], tmp, cursor1, len1, 0, c);
+                if (count1 != 0) {
+                    System.arraycopy(tmp, cursor1, a, dest, count1);
+                    dest += count1;
+                    cursor1 += count1;
+                    len1 -= count1;
+                    if (len1 <= 1) // len1 == 1 || len1 == 0
+                        break outer;
+                }
+                a[dest++] = a[cursor2++];
+                if (--len2 == 0)
+                    break outer;
+
+                count2 = gallopLeft(tmp[cursor1], a, cursor2, len2, 0, c);
+                if (count2 != 0) {
+                    System.arraycopy(a, cursor2, a, dest, count2);
+                    dest += count2;
+                    cursor2 += count2;
+                    len2 -= count2;
+                    if (len2 == 0)
+                        break outer;
+                }
+                a[dest++] = tmp[cursor1++];
+                if (--len1 == 1)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len1 == 1) {
+            assert len2 > 0;
+            System.arraycopy(a, cursor2, a, dest, len2);
+            a[dest + len2] = tmp[cursor1]; //  Last elt of run 1 to end of merge
+        } else if (len1 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len2 == 0;
+            assert len1 > 1;
+            System.arraycopy(tmp, cursor1, a, dest, len1);
+        }
+    }
+
+    /**
+     * Like mergeLo, except that this method should be called only if
+     * len1 >= len2; mergeLo should be called if len1 <= len2.  (Either method
+     * may be called if len1 == len2.)
+     *
+     * @param base1 index of first element in first run to be merged
+     * @param len1  length of first run to be merged (must be > 0)
+     * @param base2 index of first element in second run to be merged
+     *        (must be aBase + aLen)
+     * @param len2  length of second run to be merged (must be > 0)
+     */
+    private void mergeHi(int base1, int len1, int base2, int len2) {
+        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
+
+        // Copy second run into temp array
+        T[] a = this.a; // For performance
+        T[] tmp = ensureCapacity(len2);
+        int tmpBase = this.tmpBase;
+        System.arraycopy(a, base2, tmp, tmpBase, len2);
+
+        int cursor1 = base1 + len1 - 1;  // Indexes into a
+        int cursor2 = tmpBase + len2 - 1; // Indexes into tmp array
+        int dest = base2 + len2 - 1;     // Indexes into a
+
+        // Move last element of first run and deal with degenerate cases
+        a[dest--] = a[cursor1--];
+        if (--len1 == 0) {
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+            return;
+        }
+        if (len2 == 1) {
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];
+            return;
+        }
+
+        Comparator<? super T> c = this.c;  // Use local variable for performance
+        int minGallop = this.minGallop;    //  "    "       "     "      "
+    outer:
+        while (true) {
+            int count1 = 0; // Number of times in a row that first run won
+            int count2 = 0; // Number of times in a row that second run won
+
+            /*
+             * Do the straightforward thing until (if ever) one run
+             * appears to win consistently.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                if (c.compare(tmp[cursor2], a[cursor1]) < 0) {
+                    a[dest--] = a[cursor1--];
+                    count1++;
+                    count2 = 0;
+                    if (--len1 == 0)
+                        break outer;
+                } else {
+                    a[dest--] = tmp[cursor2--];
+                    count2++;
+                    count1 = 0;
+                    if (--len2 == 1)
+                        break outer;
+                }
+            } while ((count1 | count2) < minGallop);
+
+            /*
+             * One run is winning so consistently that galloping may be a
+             * huge win. So try that, and continue galloping until (if ever)
+             * neither run appears to be winning consistently anymore.
+             */
+            do {
+                assert len1 > 0 && len2 > 1;
+                count1 = len1 - gallopRight(tmp[cursor2], a, base1, len1, len1 - 1, c);
+                if (count1 != 0) {
+                    dest -= count1;
+                    cursor1 -= count1;
+                    len1 -= count1;
+                    System.arraycopy(a, cursor1 + 1, a, dest + 1, count1);
+                    if (len1 == 0)
+                        break outer;
+                }
+                a[dest--] = tmp[cursor2--];
+                if (--len2 == 1)
+                    break outer;
+
+                count2 = len2 - gallopLeft(a[cursor1], tmp, tmpBase, len2, len2 - 1, c);
+                if (count2 != 0) {
+                    dest -= count2;
+                    cursor2 -= count2;
+                    len2 -= count2;
+                    System.arraycopy(tmp, cursor2 + 1, a, dest + 1, count2);
+                    if (len2 <= 1)  // len2 == 1 || len2 == 0
+                        break outer;
+                }
+                a[dest--] = a[cursor1--];
+                if (--len1 == 0)
+                    break outer;
+                minGallop--;
+            } while (count1 >= MIN_GALLOP | count2 >= MIN_GALLOP);
+            if (minGallop < 0)
+                minGallop = 0;
+            minGallop += 2;  // Penalize for leaving gallop mode
+        }  // End of "outer" loop
+        this.minGallop = minGallop < 1 ? 1 : minGallop;  // Write back to field
+
+        if (len2 == 1) {
+            assert len1 > 0;
+            dest -= len1;
+            cursor1 -= len1;
+            System.arraycopy(a, cursor1 + 1, a, dest + 1, len1);
+            a[dest] = tmp[cursor2];  // Move first elt of run2 to front of merge
+        } else if (len2 == 0) {
+            throw new IllegalArgumentException(
+                "Comparison method violates its general contract!");
+        } else {
+            assert len1 == 0;
+            assert len2 > 0;
+            System.arraycopy(tmp, tmpBase, a, dest - (len2 - 1), len2);
+        }
+    }
+
+    /**
+     * Ensures that the external array tmp has at least the specified
+     * number of elements, increasing its size if necessary.  The size
+     * increases exponentially to ensure amortized linear time complexity.
+     *
+     * @param minCapacity the minimum required capacity of the tmp array
+     * @return tmp, whether or not it grew
+     */
+    private T[] ensureCapacity(int minCapacity) {
+        if (tmpLen < minCapacity) {
+            // Compute smallest power of 2 > minCapacity
+            int newSize = minCapacity;
+            newSize |= newSize >> 1;
+            newSize |= newSize >> 2;
+            newSize |= newSize >> 4;
+            newSize |= newSize >> 8;
+            newSize |= newSize >> 16;
+            newSize++;
+
+            if (newSize < 0) // Not bloody likely!
+                newSize = minCapacity;
+            else
+                newSize = Math.min(newSize, a.length >>> 1);
+
+            @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
+            T[] newArray = (T[])java.lang.reflect.Array.newInstance
+                (a.getClass().getComponentType(), newSize);
+            tmp = newArray;
+            tmpLen = newSize;
+            tmpBase = 0;
+        }
+        return tmp;
+    }
+}
diff --git a/java/util/TimeZone.java b/java/util/TimeZone.java
new file mode 100644
index 0000000..cf5e5f8
--- /dev/null
+++ b/java/util/TimeZone.java
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
+ *
+ *   The original version of this source code and documentation is copyrighted
+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
+ * materials are provided under terms of a License Agreement between Taligent
+ * and Sun. This technology is protected by multiple US and International
+ * patents. This notice and attribution to Taligent may not be removed.
+ *   Taligent is a registered trademark of Taligent, Inc.
+ *
+ */
+
+package java.util;
+
+import android.icu.text.TimeZoneNames;
+import java.io.IOException;
+import java.io.Serializable;
+import java.time.ZoneId;
+import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import libcore.io.IoUtils;
+import libcore.timezone.ZoneInfoDb;
+
+import dalvik.system.RuntimeHooks;
+
+/**
+ * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
+ * savings.
+ *
+ * <p>
+ * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
+ * which creates a <code>TimeZone</code> based on the time zone where the program
+ * is running. For example, for a program running in Japan, <code>getDefault</code>
+ * creates a <code>TimeZone</code> object based on Japanese Standard Time.
+ *
+ * <p>
+ * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
+ * along with a time zone ID. For instance, the time zone ID for the
+ * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
+ * U.S. Pacific Time <code>TimeZone</code> object with:
+ * <blockquote><pre>
+ * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ * </pre></blockquote>
+ * You can use the <code>getAvailableIDs</code> method to iterate through
+ * all the supported time zone IDs. You can then choose a
+ * supported ID to get a <code>TimeZone</code>.
+ * If the time zone you want is not represented by one of the
+ * supported IDs, then a custom time zone ID can be specified to
+ * produce a TimeZone. The syntax of a custom time zone ID is:
+ *
+ * <blockquote><pre>
+ * <a name="CustomID"><i>CustomID:</i></a>
+ *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
+ *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
+ *         <code>GMT</code> <i>Sign</i> <i>Hours</i>
+ * <i>Sign:</i> one of
+ *         <code>+ -</code>
+ * <i>Hours:</i>
+ *         <i>Digit</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Minutes:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Digit:</i> one of
+ *         <code>0 1 2 3 4 5 6 7 8 9</code>
+ * </pre></blockquote>
+ *
+ * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
+ * between 00 to 59.  For example, "GMT+10" and "GMT+0010" mean ten
+ * hours and ten minutes ahead of GMT, respectively.
+ * <p>
+ * The format is locale independent and digits must be taken from the
+ * Basic Latin block of the Unicode standard. No daylight saving time
+ * transition schedule can be specified with a custom time zone ID. If
+ * the specified string doesn't match the syntax, <code>"GMT"</code>
+ * is used.
+ * <p>
+ * When creating a <code>TimeZone</code>, the specified custom time
+ * zone ID is normalized in the following syntax:
+ * <blockquote><pre>
+ * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
+ *         <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
+ * <i>Sign:</i> one of
+ *         <code>+ -</code>
+ * <i>TwoDigitHours:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Minutes:</i>
+ *         <i>Digit</i> <i>Digit</i>
+ * <i>Digit:</i> one of
+ *         <code>0 1 2 3 4 5 6 7 8 9</code>
+ * </pre></blockquote>
+ * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
+ *
+ * <h3>Three-letter time zone IDs</h3>
+ *
+ * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
+ * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
+ * use is deprecated</strong> because the same abbreviation is often used
+ * for multiple time zones (for example, "CST" could be U.S. "Central Standard
+ * Time" and "China Standard Time"), and the Java platform can then only
+ * recognize one of them.
+ *
+ *
+ * @see          Calendar
+ * @see          GregorianCalendar
+ * @see          SimpleTimeZone
+ * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
+ * @since        JDK1.1
+ */
+abstract public class TimeZone implements Serializable, Cloneable {
+    /**
+     * Sole constructor.  (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    public TimeZone() {
+    }
+
+    /**
+     * A style specifier for <code>getDisplayName()</code> indicating
+     * a short name, such as "PST."
+     * @see #LONG
+     * @since 1.2
+     */
+    public static final int SHORT = 0;
+
+    /**
+     * A style specifier for <code>getDisplayName()</code> indicating
+     * a long name, such as "Pacific Standard Time."
+     * @see #SHORT
+     * @since 1.2
+     */
+    public static final int LONG  = 1;
+
+    // Android-changed: Use a preload holder to allow compile-time initialization of TimeZone and
+    // dependents.
+    private static class NoImagePreloadHolder {
+        public static final Pattern CUSTOM_ZONE_ID_PATTERN = Pattern.compile("^GMT[-+](\\d{1,2})(:?(\\d\\d))?$");
+    }
+
+    // Proclaim serialization compatibility with JDK 1.1
+    static final long serialVersionUID = 3581463369166924961L;
+
+    // Android-changed: common timezone instances.
+    private static final TimeZone GMT = new SimpleTimeZone(0, "GMT");
+    private static final TimeZone UTC = new SimpleTimeZone(0, "UTC");
+
+    /**
+     * Gets the time zone offset, for current date, modified in case of
+     * daylight savings. This is the offset to add to UTC to get local time.
+     * <p>
+     * This method returns a historically correct offset if an
+     * underlying <code>TimeZone</code> implementation subclass
+     * supports historical Daylight Saving Time schedule and GMT
+     * offset changes.
+     *
+     * @param era the era of the given date.
+     * @param year the year in the given date.
+     * @param month the month in the given date.
+     * Month is 0-based. e.g., 0 for January.
+     * @param day the day-in-month of the given date.
+     * @param dayOfWeek the day-of-week of the given date.
+     * @param milliseconds the milliseconds in day in <em>standard</em>
+     * local time.
+     *
+     * @return the offset in milliseconds to add to GMT to get local time.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     */
+    public abstract int getOffset(int era, int year, int month, int day,
+                                  int dayOfWeek, int milliseconds);
+
+    /**
+     * Returns the offset of this time zone from UTC at the specified
+     * date. If Daylight Saving Time is in effect at the specified
+     * date, the offset value is adjusted with the amount of daylight
+     * saving.
+     * <p>
+     * This method returns a historically correct offset value if an
+     * underlying TimeZone implementation subclass supports historical
+     * Daylight Saving Time schedule and GMT offset changes.
+     *
+     * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
+     * @return the amount of time in milliseconds to add to UTC to get local time.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     * @since 1.4
+     */
+    public int getOffset(long date) {
+        if (inDaylightTime(new Date(date))) {
+            return getRawOffset() + getDSTSavings();
+        }
+        return getRawOffset();
+    }
+
+    /**
+     * Gets the raw GMT offset and the amount of daylight saving of this
+     * time zone at the given time.
+     * @param date the milliseconds (since January 1, 1970,
+     * 00:00:00.000 GMT) at which the time zone offset and daylight
+     * saving amount are found
+     * @param offsets an array of int where the raw GMT offset
+     * (offset[0]) and daylight saving amount (offset[1]) are stored,
+     * or null if those values are not needed. The method assumes that
+     * the length of the given array is two or larger.
+     * @return the total amount of the raw GMT offset and daylight
+     * saving at the specified date.
+     *
+     * @see Calendar#ZONE_OFFSET
+     * @see Calendar#DST_OFFSET
+     */
+    int getOffsets(long date, int[] offsets) {
+        int rawoffset = getRawOffset();
+        int dstoffset = 0;
+        if (inDaylightTime(new Date(date))) {
+            dstoffset = getDSTSavings();
+        }
+        if (offsets != null) {
+            offsets[0] = rawoffset;
+            offsets[1] = dstoffset;
+        }
+        return rawoffset + dstoffset;
+    }
+
+    /**
+     * Sets the base time zone offset to GMT.
+     * This is the offset to add to UTC to get local time.
+     * <p>
+     * If an underlying <code>TimeZone</code> implementation subclass
+     * supports historical GMT offset changes, the specified GMT
+     * offset is set as the latest GMT offset and the difference from
+     * the known latest GMT offset value is used to adjust all
+     * historical GMT offset values.
+     *
+     * @param offsetMillis the given base time zone offset to GMT.
+     */
+    abstract public void setRawOffset(int offsetMillis);
+
+    /**
+     * Returns the amount of time in milliseconds to add to UTC to get
+     * standard time in this time zone. Because this value is not
+     * affected by daylight saving time, it is called <I>raw
+     * offset</I>.
+     * <p>
+     * If an underlying <code>TimeZone</code> implementation subclass
+     * supports historical GMT offset changes, the method returns the
+     * raw offset value of the current date. In Honolulu, for example,
+     * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
+     * this method always returns -36000000 milliseconds (i.e., -10
+     * hours).
+     *
+     * @return the amount of raw offset time in milliseconds to add to UTC.
+     * @see Calendar#ZONE_OFFSET
+     */
+    public abstract int getRawOffset();
+
+    /**
+     * Gets the ID of this time zone.
+     * @return the ID of this time zone.
+     */
+    public String getID()
+    {
+        return ID;
+    }
+
+    /**
+     * Sets the time zone ID. This does not change any other data in
+     * the time zone object.
+     * @param ID the new time zone ID.
+     */
+    public void setID(String ID)
+    {
+        if (ID == null) {
+            throw new NullPointerException();
+        }
+        this.ID = ID;
+    }
+
+    /**
+     * Returns a long standard time name of this {@code TimeZone} suitable for
+     * presentation to the user in the default locale.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(false, {@link #LONG},
+     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
+     * </pre></blockquote>
+     *
+     * @return the human-readable name of this time zone in the default locale.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     * @see Locale#getDefault(Locale.Category)
+     * @see Locale.Category
+     */
+    public final String getDisplayName() {
+        return getDisplayName(false, LONG,
+                              Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Returns a long standard time name of this {@code TimeZone} suitable for
+     * presentation to the user in the specified {@code locale}.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(false, {@link #LONG}, locale)
+     * </pre></blockquote>
+     *
+     * @param locale the locale in which to supply the display name.
+     * @return the human-readable name of this time zone in the given locale.
+     * @exception NullPointerException if {@code locale} is {@code null}.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     */
+    public final String getDisplayName(Locale locale) {
+        return getDisplayName(false, LONG, locale);
+    }
+
+    /**
+     * Returns a name in the specified {@code style} of this {@code TimeZone}
+     * suitable for presentation to the user in the default locale. If the
+     * specified {@code daylight} is {@code true}, a Daylight Saving Time name
+     * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
+     * Time). Otherwise, a Standard Time name is returned.
+     *
+     * <p>This method is equivalent to:
+     * <blockquote><pre>
+     * getDisplayName(daylight, style,
+     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
+     * </pre></blockquote>
+     *
+     * @param daylight {@code true} specifying a Daylight Saving Time name, or
+     *                 {@code false} specifying a Standard Time name
+     * @param style either {@link #LONG} or {@link #SHORT}
+     * @return the human-readable name of this time zone in the default locale.
+     * @exception IllegalArgumentException if {@code style} is invalid.
+     * @since 1.2
+     * @see #getDisplayName(boolean, int, Locale)
+     * @see Locale#getDefault(Locale.Category)
+     * @see Locale.Category
+     * @see java.text.DateFormatSymbols#getZoneStrings()
+     */
+    public final String getDisplayName(boolean daylight, int style) {
+        return getDisplayName(daylight, style,
+                              Locale.getDefault(Locale.Category.DISPLAY));
+    }
+
+    /**
+     * Returns the {@link #SHORT short} or {@link #LONG long} name of this time
+     * zone with either standard or daylight time, as written in {@code locale}.
+     * If the name is not available, the result is in the format
+     * {@code GMT[+-]hh:mm}.
+     *
+     * @param daylightTime true for daylight time, false for standard time.
+     * @param style either {@link TimeZone#LONG} or {@link TimeZone#SHORT}.
+     * @param locale the display locale.
+     */
+    public String getDisplayName(boolean daylightTime, int style, Locale locale) {
+        // BEGIN Android-changed: implement using android.icu.text.TimeZoneNames
+        TimeZoneNames.NameType nameType;
+        switch (style) {
+            case SHORT:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+                        : TimeZoneNames.NameType.SHORT_STANDARD;
+                break;
+            case LONG:
+                nameType = daylightTime
+                        ? TimeZoneNames.NameType.LONG_DAYLIGHT
+                        : TimeZoneNames.NameType.LONG_STANDARD;
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal style: " + style);
+        }
+        String canonicalID = android.icu.util.TimeZone.getCanonicalID(getID());
+        if (canonicalID != null) {
+            TimeZoneNames names = TimeZoneNames.getInstance(locale);
+            long now = System.currentTimeMillis();
+            String displayName = names.getDisplayName(canonicalID, nameType, now);
+            if (displayName != null) {
+                return displayName;
+            }
+        }
+
+        // We get here if this is a custom timezone or ICU doesn't have name data for the specific
+        // style and locale.
+        int offsetMillis = getRawOffset();
+        if (daylightTime) {
+            offsetMillis += getDSTSavings();
+        }
+        return createGmtOffsetString(true /* includeGmt */, true /* includeMinuteSeparator */,
+                offsetMillis);
+        // END Android-changed: implement using android.icu.text.TimeZoneNames
+    }
+
+    // BEGIN Android-added: utility method to format an offset as a GMT offset string.
+    /**
+     * Returns a string representation of an offset from UTC.
+     *
+     * <p>The format is "[GMT](+|-)HH[:]MM". The output is not localized.
+     *
+     * @param includeGmt true to include "GMT", false to exclude
+     * @param includeMinuteSeparator true to include the separator between hours and minutes, false
+     *     to exclude.
+     * @param offsetMillis the offset from UTC
+     *
+     * @hide used internally by SimpleDateFormat
+     */
+    public static String createGmtOffsetString(boolean includeGmt,
+            boolean includeMinuteSeparator, int offsetMillis) {
+        int offsetMinutes = offsetMillis / 60000;
+        char sign = '+';
+        if (offsetMinutes < 0) {
+            sign = '-';
+            offsetMinutes = -offsetMinutes;
+        }
+        StringBuilder builder = new StringBuilder(9);
+        if (includeGmt) {
+            builder.append("GMT");
+        }
+        builder.append(sign);
+        appendNumber(builder, 2, offsetMinutes / 60);
+        if (includeMinuteSeparator) {
+            builder.append(':');
+        }
+        appendNumber(builder, 2, offsetMinutes % 60);
+        return builder.toString();
+    }
+
+    private static void appendNumber(StringBuilder builder, int count, int value) {
+        String string = Integer.toString(value);
+        for (int i = 0; i < count - string.length(); i++) {
+            builder.append('0');
+        }
+        builder.append(string);
+    }
+    // END Android-added: utility method to format an offset as a GMT offset string.
+
+    /**
+     * Returns the amount of time to be added to local standard time
+     * to get local wall clock time.
+     *
+     * <p>The default implementation returns 3600000 milliseconds
+     * (i.e., one hour) if a call to {@link #useDaylightTime()}
+     * returns {@code true}. Otherwise, 0 (zero) is returned.
+     *
+     * <p>If an underlying {@code TimeZone} implementation subclass
+     * supports historical and future Daylight Saving Time schedule
+     * changes, this method returns the amount of saving time of the
+     * last known Daylight Saving Time rule that can be a future
+     * prediction.
+     *
+     * <p>If the amount of saving time at any given time stamp is
+     * required, construct a {@link Calendar} with this {@code
+     * TimeZone} and the time stamp, and call {@link Calendar#get(int)
+     * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
+     *
+     * @return the amount of saving time in milliseconds
+     * @since 1.4
+     * @see #inDaylightTime(Date)
+     * @see #getOffset(long)
+     * @see #getOffset(int,int,int,int,int,int)
+     * @see Calendar#ZONE_OFFSET
+     */
+    public int getDSTSavings() {
+        if (useDaylightTime()) {
+            return 3600000;
+        }
+        return 0;
+    }
+
+    /**
+     * Queries if this {@code TimeZone} uses Daylight Saving Time.
+     *
+     * <p>If an underlying {@code TimeZone} implementation subclass
+     * supports historical and future Daylight Saving Time schedule
+     * changes, this method refers to the last known Daylight Saving Time
+     * rule that can be a future prediction and may not be the same as
+     * the current rule. Consider calling {@link #observesDaylightTime()}
+     * if the current rule should also be taken into account.
+     *
+     * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
+     *         {@code false}, otherwise.
+     * @see #inDaylightTime(Date)
+     * @see Calendar#DST_OFFSET
+     */
+    public abstract boolean useDaylightTime();
+
+    /**
+     * Returns {@code true} if this {@code TimeZone} is currently in
+     * Daylight Saving Time, or if a transition from Standard Time to
+     * Daylight Saving Time occurs at any future time.
+     *
+     * <p>The default implementation returns {@code true} if
+     * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
+     * returns {@code true}.
+     *
+     * @return {@code true} if this {@code TimeZone} is currently in
+     * Daylight Saving Time, or if a transition from Standard Time to
+     * Daylight Saving Time occurs at any future time; {@code false}
+     * otherwise.
+     * @since 1.7
+     * @see #useDaylightTime()
+     * @see #inDaylightTime(Date)
+     * @see Calendar#DST_OFFSET
+     */
+    public boolean observesDaylightTime() {
+        return useDaylightTime() || inDaylightTime(new Date());
+    }
+
+    /**
+     * Queries if the given {@code date} is in Daylight Saving Time in
+     * this time zone.
+     *
+     * @param date the given Date.
+     * @return {@code true} if the given date is in Daylight Saving Time,
+     *         {@code false}, otherwise.
+     */
+    abstract public boolean inDaylightTime(Date date);
+
+    /**
+     * Gets the <code>TimeZone</code> for the given ID.
+     *
+     * @param id the ID for a <code>TimeZone</code>, either an abbreviation
+     * such as "PST", a full name such as "America/Los_Angeles", or a custom
+     * ID such as "GMT-8:00". Note that the support of abbreviations is
+     * for JDK 1.1.x compatibility only and full names should be used.
+     *
+     * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
+     * cannot be understood.
+     */
+    // Android-changed: param s/ID/id; use ZoneInfoDb instead of ZoneInfo class.
+    public static synchronized TimeZone getTimeZone(String id) {
+        if (id == null) {
+            throw new NullPointerException("id == null");
+        }
+
+        // Special cases? These can clone an existing instance.
+        if (id.length() == 3) {
+            if (id.equals("GMT")) {
+                return (TimeZone) GMT.clone();
+            }
+            if (id.equals("UTC")) {
+                return (TimeZone) UTC.clone();
+            }
+        }
+
+        // In the database?
+        TimeZone zone = null;
+        try {
+            zone = ZoneInfoDb.getInstance().makeTimeZone(id);
+        } catch (IOException ignored) {
+        }
+
+        // Custom time zone?
+        if (zone == null && id.length() > 3 && id.startsWith("GMT")) {
+            zone = getCustomTimeZone(id);
+        }
+
+        // We never return null; on failure we return the equivalent of "GMT".
+        return (zone != null) ? zone : (TimeZone) GMT.clone();
+    }
+
+    /**
+     * Gets the {@code TimeZone} for the given {@code zoneId}.
+     *
+     * @param zoneId a {@link ZoneId} from which the time zone ID is obtained
+     * @return the specified {@code TimeZone}, or the GMT zone if the given ID
+     *         cannot be understood.
+     * @throws NullPointerException if {@code zoneId} is {@code null}
+     * @since 1.8
+     */
+    public static TimeZone getTimeZone(ZoneId zoneId) {
+        String tzid = zoneId.getId(); // throws an NPE if null
+        char c = tzid.charAt(0);
+        if (c == '+' || c == '-') {
+            tzid = "GMT" + tzid;
+        } else if (c == 'Z' && tzid.length() == 1) {
+            tzid = "UTC";
+        }
+        return getTimeZone(tzid);
+    }
+
+    /**
+     * Converts this {@code TimeZone} object to a {@code ZoneId}.
+     *
+     * @return a {@code ZoneId} representing the same time zone as this
+     *         {@code TimeZone}
+     * @since 1.8
+     */
+    public ZoneId toZoneId() {
+        // Android-changed: don't support "old mapping"
+        return ZoneId.of(getID(), ZoneId.SHORT_IDS);
+    }
+
+    /**
+     * Returns a new SimpleTimeZone for an ID of the form "GMT[+|-]hh[[:]mm]", or null.
+     */
+    private static TimeZone getCustomTimeZone(String id) {
+        Matcher m = NoImagePreloadHolder.CUSTOM_ZONE_ID_PATTERN.matcher(id);
+        if (!m.matches()) {
+            return null;
+        }
+
+        int hour;
+        int minute = 0;
+        try {
+            hour = Integer.parseInt(m.group(1));
+            if (m.group(3) != null) {
+                minute = Integer.parseInt(m.group(3));
+            }
+        } catch (NumberFormatException impossible) {
+            throw new AssertionError(impossible);
+        }
+
+        if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
+            return null;
+        }
+
+        char sign = id.charAt(3);
+        int raw = (hour * 3600000) + (minute * 60000);
+        if (sign == '-') {
+            raw = -raw;
+        }
+
+        String cleanId = String.format(Locale.ROOT, "GMT%c%02d:%02d", sign, hour, minute);
+
+        return new SimpleTimeZone(raw, cleanId);
+    }
+
+    /**
+     * Gets the available IDs according to the given time zone offset in milliseconds.
+     *
+     * @param rawOffset the given time zone GMT offset in milliseconds.
+     * @return an array of IDs, where the time zone for that ID has
+     * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
+     * both have GMT-07:00, but differ in daylight saving behavior.
+     * @see #getRawOffset()
+     */
+    public static synchronized String[] getAvailableIDs(int rawOffset) {
+        return ZoneInfoDb.getInstance().getAvailableIDs(rawOffset);
+    }
+
+    /**
+     * Gets all the available IDs supported.
+     * @return an array of IDs.
+     */
+    public static synchronized String[] getAvailableIDs() {
+        return ZoneInfoDb.getInstance().getAvailableIDs();
+    }
+
+    /**
+     * Gets the platform defined TimeZone ID.
+     **/
+    private static native String getSystemTimeZoneID(String javaHome,
+                                                     String country);
+
+    /**
+     * Gets the custom time zone ID based on the GMT offset of the
+     * platform. (e.g., "GMT+08:00")
+     */
+    private static native String getSystemGMTOffsetID();
+
+    /**
+     * Gets the default <code>TimeZone</code> for this host.
+     * The source of the default <code>TimeZone</code>
+     * may vary with implementation.
+     * @return a default <code>TimeZone</code>.
+     * @see #setDefault
+     */
+    public static TimeZone getDefault() {
+        return (TimeZone) getDefaultRef().clone();
+    }
+
+    /**
+     * Returns the reference to the default TimeZone object. This
+     * method doesn't create a clone.
+     */
+    static synchronized TimeZone getDefaultRef() {
+        if (defaultTimeZone == null) {
+            Supplier<String> tzGetter = RuntimeHooks.getTimeZoneIdSupplier();
+            String zoneName = (tzGetter != null) ? tzGetter.get() : null;
+            if (zoneName != null) {
+                zoneName = zoneName.trim();
+            }
+            if (zoneName == null || zoneName.isEmpty()) {
+                try {
+                    // On the host, we can find the configured timezone here.
+                    zoneName = IoUtils.readFileAsString("/etc/timezone");
+                } catch (IOException ex) {
+                    // "vogar --mode device" can end up here.
+                    // TODO: give libcore access to Android system properties and read "persist.sys.timezone".
+                    zoneName = "GMT";
+                }
+            }
+            defaultTimeZone = TimeZone.getTimeZone(zoneName);
+        }
+        return defaultTimeZone;
+    }
+
+    /**
+     * Sets the {@code TimeZone} that is returned by the {@code getDefault}
+     * method. {@code timeZone} is cached. If {@code timeZone} is null, the cached
+     * default {@code TimeZone} is cleared. This method doesn't change the value
+     * of the {@code user.timezone} property.
+     *
+     * @param timeZone the new default {@code TimeZone}, or null
+     * @see #getDefault
+     */
+    // Android-changed: s/zone/timeZone, synchronized, removed mention of SecurityException
+    public synchronized static void setDefault(TimeZone timeZone)
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new PropertyPermission
+                    ("user.timezone", "write"));
+        }
+        defaultTimeZone = timeZone != null ? (TimeZone) timeZone.clone() : null;
+        // Android-changed: notify ICU4J of changed default TimeZone.
+        android.icu.util.TimeZone.setICUDefault(null);
+    }
+
+    /**
+     * Returns true if this zone has the same rule and offset as another zone.
+     * That is, if this zone differs only in ID, if at all.  Returns false
+     * if the other zone is null.
+     * @param other the <code>TimeZone</code> object to be compared with
+     * @return true if the other zone is not null and is the same as this one,
+     * with the possible exception of the ID
+     * @since 1.2
+     */
+    public boolean hasSameRules(TimeZone other) {
+        return other != null && getRawOffset() == other.getRawOffset() &&
+            useDaylightTime() == other.useDaylightTime();
+    }
+
+    /**
+     * Creates a copy of this <code>TimeZone</code>.
+     *
+     * @return a clone of this <code>TimeZone</code>
+     */
+    public Object clone()
+    {
+        try {
+            TimeZone other = (TimeZone) super.clone();
+            other.ID = ID;
+            return other;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * The null constant as a TimeZone.
+     */
+    static final TimeZone NO_TIMEZONE = null;
+
+    // =======================privates===============================
+
+    /**
+     * The string identifier of this <code>TimeZone</code>.  This is a
+     * programmatic identifier used internally to look up <code>TimeZone</code>
+     * objects from the system table and also to map them to their localized
+     * display names.  <code>ID</code> values are unique in the system
+     * table but may not be for dynamically created zones.
+     * @serial
+     */
+    private String           ID;
+    private static volatile TimeZone defaultTimeZone;
+}
diff --git a/java/util/Timer.java b/java/util/Timer.java
new file mode 100644
index 0000000..487db0d
--- /dev/null
+++ b/java/util/Timer.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * A facility for threads to schedule tasks for future execution in a
+ * background thread.  Tasks may be scheduled for one-time execution, or for
+ * repeated execution at regular intervals.
+ *
+ * <p>Corresponding to each <tt>Timer</tt> object is a single background
+ * thread that is used to execute all of the timer's tasks, sequentially.
+ * Timer tasks should complete quickly.  If a timer task takes excessive time
+ * to complete, it "hogs" the timer's task execution thread.  This can, in
+ * turn, delay the execution of subsequent tasks, which may "bunch up" and
+ * execute in rapid succession when (and if) the offending task finally
+ * completes.
+ *
+ * <p>After the last live reference to a <tt>Timer</tt> object goes away
+ * <i>and</i> all outstanding tasks have completed execution, the timer's task
+ * execution thread terminates gracefully (and becomes subject to garbage
+ * collection).  However, this can take arbitrarily long to occur.  By
+ * default, the task execution thread does not run as a <i>daemon thread</i>,
+ * so it is capable of keeping an application from terminating.  If a caller
+ * wants to terminate a timer's task execution thread rapidly, the caller
+ * should invoke the timer's <tt>cancel</tt> method.
+ *
+ * <p>If the timer's task execution thread terminates unexpectedly, for
+ * example, because its <tt>stop</tt> method is invoked, any further
+ * attempt to schedule a task on the timer will result in an
+ * <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
+ * method had been invoked.
+ *
+ * <p>This class is thread-safe: multiple threads can share a single
+ * <tt>Timer</tt> object without the need for external synchronization.
+ *
+ * <p>This class does <i>not</i> offer real-time guarantees: it schedules
+ * tasks using the <tt>Object.wait(long)</tt> method.
+ *
+ * <p>Java 5.0 introduced the {@code java.util.concurrent} package and
+ * one of the concurrency utilities therein is the {@link
+ * java.util.concurrent.ScheduledThreadPoolExecutor
+ * ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
+ * executing tasks at a given rate or delay.  It is effectively a more
+ * versatile replacement for the {@code Timer}/{@code TimerTask}
+ * combination, as it allows multiple service threads, accepts various
+ * time units, and doesn't require subclassing {@code TimerTask} (just
+ * implement {@code Runnable}).  Configuring {@code
+ * ScheduledThreadPoolExecutor} with one thread makes it equivalent to
+ * {@code Timer}.
+ *
+ * <p>Implementation note: This class scales to large numbers of concurrently
+ * scheduled tasks (thousands should present no problem).  Internally,
+ * it uses a binary heap to represent its task queue, so the cost to schedule
+ * a task is O(log n), where n is the number of concurrently scheduled tasks.
+ *
+ * <p>Implementation note: All constructors start a timer thread.
+ *
+ * @author  Josh Bloch
+ * @see     TimerTask
+ * @see     Object#wait(long)
+ * @since   1.3
+ */
+
+public class Timer {
+    /**
+     * The timer task queue.  This data structure is shared with the timer
+     * thread.  The timer produces tasks, via its various schedule calls,
+     * and the timer thread consumes, executing timer tasks as appropriate,
+     * and removing them from the queue when they're obsolete.
+     */
+    // Android-added: @ReachabilitySensitive
+    // Otherwise the finalizer may cancel the Timer in the middle of a
+    // sched() call.
+    @ReachabilitySensitive
+    private final TaskQueue queue = new TaskQueue();
+
+    /**
+     * The timer thread.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final TimerThread thread = new TimerThread(queue);
+
+    /**
+     * This object causes the timer's task execution thread to exit
+     * gracefully when there are no live references to the Timer object and no
+     * tasks in the timer queue.  It is used in preference to a finalizer on
+     * Timer as such a finalizer would be susceptible to a subclass's
+     * finalizer forgetting to call it.
+     */
+    private final Object threadReaper = new Object() {
+        protected void finalize() throws Throwable {
+            synchronized(queue) {
+                thread.newTasksMayBeScheduled = false;
+                queue.notify(); // In case queue is empty.
+            }
+        }
+    };
+
+    /**
+     * This ID is used to generate thread names.
+     */
+    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
+    private static int serialNumber() {
+        return nextSerialNumber.getAndIncrement();
+    }
+
+    /**
+     * Creates a new timer.  The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     */
+    public Timer() {
+        this("Timer-" + serialNumber());
+    }
+
+    /**
+     * Creates a new timer whose associated thread may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     * A daemon thread is called for if the timer will be used to
+     * schedule repeating "maintenance activities", which must be
+     * performed as long as the application is running, but should not
+     * prolong the lifetime of the application.
+     *
+     * @param isDaemon true if the associated thread should run as a daemon.
+     */
+    public Timer(boolean isDaemon) {
+        this("Timer-" + serialNumber(), isDaemon);
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name.
+     * The associated thread does <i>not</i>
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @throws NullPointerException if {@code name} is null
+     * @since 1.5
+     */
+    public Timer(String name) {
+        thread.setName(name);
+        thread.start();
+    }
+
+    /**
+     * Creates a new timer whose associated thread has the specified name,
+     * and may be specified to
+     * {@linkplain Thread#setDaemon run as a daemon}.
+     *
+     * @param name the name of the associated thread
+     * @param isDaemon true if the associated thread should run as a daemon
+     * @throws NullPointerException if {@code name} is null
+     * @since 1.5
+     */
+    public Timer(String name, boolean isDaemon) {
+        thread.setName(name);
+        thread.setDaemon(isDaemon);
+        thread.start();
+    }
+
+    /**
+     * Schedules the specified task for execution after the specified delay.
+     *
+     * @param task  task to be scheduled.
+     * @param delay delay in milliseconds before task is to be executed.
+     * @throws IllegalArgumentException if <tt>delay</tt> is negative, or
+     *         <tt>delay + System.currentTimeMillis()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void schedule(TimerTask task, long delay) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        sched(task, System.currentTimeMillis()+delay, 0);
+    }
+
+    /**
+     * Schedules the specified task for execution at the specified time.  If
+     * the time is in the past, the task is scheduled for immediate execution.
+     *
+     * @param task task to be scheduled.
+     * @param time time at which task is to be executed.
+     * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code time} is null
+     */
+    public void schedule(TimerTask task, Date time) {
+        sched(task, time.getTime(), 0);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code delay < 0}, or
+     *         {@code delay + System.currentTimeMillis() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void schedule(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-delay execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-delay execution, each execution is scheduled relative to
+     * the actual execution time of the previous execution.  If an execution
+     * is delayed for any reason (such as garbage collection or other
+     * background activity), subsequent executions will be delayed as well.
+     * In the long run, the frequency of execution will generally be slightly
+     * lower than the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).  As a
+     * consequence of the above, if the scheduled first time is in the past,
+     * it is scheduled for immediate execution.
+     *
+     * <p>Fixed-delay execution is appropriate for recurring activities
+     * that require "smoothness."  In other words, it is appropriate for
+     * activities where it is more important to keep the frequency accurate
+     * in the short run than in the long run.  This includes most animation
+     * tasks, such as blinking a cursor at regular intervals.  It also includes
+     * tasks wherein regular activity is performed in response to human
+     * input, such as automatically repeating a character as long as a key
+     * is held down.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code firstTime} is null
+     */
+    public void schedule(TimerTask task, Date firstTime, long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), -period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning after the specified delay.  Subsequent executions take place
+     * at approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param delay  delay in milliseconds before task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code delay < 0}, or
+     *         {@code delay + System.currentTimeMillis() < 0}, or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
+        if (delay < 0)
+            throw new IllegalArgumentException("Negative delay.");
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, System.currentTimeMillis()+delay, period);
+    }
+
+    /**
+     * Schedules the specified task for repeated <i>fixed-rate execution</i>,
+     * beginning at the specified time. Subsequent executions take place at
+     * approximately regular intervals, separated by the specified period.
+     *
+     * <p>In fixed-rate execution, each execution is scheduled relative to the
+     * scheduled execution time of the initial execution.  If an execution is
+     * delayed for any reason (such as garbage collection or other background
+     * activity), two or more executions will occur in rapid succession to
+     * "catch up."  In the long run, the frequency of execution will be
+     * exactly the reciprocal of the specified period (assuming the system
+     * clock underlying <tt>Object.wait(long)</tt> is accurate).  As a
+     * consequence of the above, if the scheduled first time is in the past,
+     * then any "missed" executions will be scheduled for immediate "catch up"
+     * execution.
+     *
+     * <p>Fixed-rate execution is appropriate for recurring activities that
+     * are sensitive to <i>absolute</i> time, such as ringing a chime every
+     * hour on the hour, or running scheduled maintenance every day at a
+     * particular time.  It is also appropriate for recurring activities
+     * where the total time to perform a fixed number of executions is
+     * important, such as a countdown timer that ticks once every second for
+     * ten seconds.  Finally, fixed-rate execution is appropriate for
+     * scheduling multiple repeating timer tasks that must remain synchronized
+     * with respect to one another.
+     *
+     * @param task   task to be scheduled.
+     * @param firstTime First time at which task is to be executed.
+     * @param period time in milliseconds between successive task executions.
+     * @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
+     *         {@code period <= 0}
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} or {@code firstTime} is null
+     */
+    public void scheduleAtFixedRate(TimerTask task, Date firstTime,
+                                    long period) {
+        if (period <= 0)
+            throw new IllegalArgumentException("Non-positive period.");
+        sched(task, firstTime.getTime(), period);
+    }
+
+    /**
+     * Schedule the specified timer task for execution at the specified
+     * time with the specified period, in milliseconds.  If period is
+     * positive, the task is scheduled for repeated execution; if period is
+     * zero, the task is scheduled for one-time execution. Time is specified
+     * in Date.getTime() format.  This method checks timer state, task state,
+     * and initial execution time, but not period.
+     *
+     * @throws IllegalArgumentException if <tt>time</tt> is negative.
+     * @throws IllegalStateException if task was already scheduled or
+     *         cancelled, timer was cancelled, or timer thread terminated.
+     * @throws NullPointerException if {@code task} is null
+     */
+    private void sched(TimerTask task, long time, long period) {
+        if (time < 0)
+            throw new IllegalArgumentException("Illegal execution time.");
+
+        // Constrain value of period sufficiently to prevent numeric
+        // overflow while still being effectively infinitely large.
+        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
+            period >>= 1;
+
+        synchronized(queue) {
+            if (!thread.newTasksMayBeScheduled)
+                throw new IllegalStateException("Timer already cancelled.");
+
+            synchronized(task.lock) {
+                if (task.state != TimerTask.VIRGIN)
+                    throw new IllegalStateException(
+                        "Task already scheduled or cancelled");
+                task.nextExecutionTime = time;
+                task.period = period;
+                task.state = TimerTask.SCHEDULED;
+            }
+
+            queue.add(task);
+            if (queue.getMin() == task)
+                queue.notify();
+        }
+    }
+
+    /**
+     * Terminates this timer, discarding any currently scheduled tasks.
+     * Does not interfere with a currently executing task (if it exists).
+     * Once a timer has been terminated, its execution thread terminates
+     * gracefully, and no more tasks may be scheduled on it.
+     *
+     * <p>Note that calling this method from within the run method of a
+     * timer task that was invoked by this timer absolutely guarantees that
+     * the ongoing task execution is the last task execution that will ever
+     * be performed by this timer.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     */
+    public void cancel() {
+        synchronized(queue) {
+            thread.newTasksMayBeScheduled = false;
+            queue.clear();
+            queue.notify();  // In case queue was already empty.
+        }
+    }
+
+    /**
+     * Removes all cancelled tasks from this timer's task queue.  <i>Calling
+     * this method has no effect on the behavior of the timer</i>, but
+     * eliminates the references to the cancelled tasks from the queue.
+     * If there are no external references to these tasks, they become
+     * eligible for garbage collection.
+     *
+     * <p>Most programs will have no need to call this method.
+     * It is designed for use by the rare application that cancels a large
+     * number of tasks.  Calling this method trades time for space: the
+     * runtime of the method may be proportional to n + c log n, where n
+     * is the number of tasks in the queue and c is the number of cancelled
+     * tasks.
+     *
+     * <p>Note that it is permissible to call this method from within a
+     * a task scheduled on this timer.
+     *
+     * @return the number of tasks removed from the queue.
+     * @since 1.5
+     */
+     public int purge() {
+         int result = 0;
+
+         synchronized(queue) {
+             for (int i = queue.size(); i > 0; i--) {
+                 if (queue.get(i).state == TimerTask.CANCELLED) {
+                     queue.quickRemove(i);
+                     result++;
+                 }
+             }
+
+             if (result != 0)
+                 queue.heapify();
+         }
+
+         return result;
+     }
+}
+
+/**
+ * This "helper class" implements the timer's task execution thread, which
+ * waits for tasks on the timer queue, executions them when they fire,
+ * reschedules repeating tasks, and removes cancelled tasks and spent
+ * non-repeating tasks from the queue.
+ */
+class TimerThread extends Thread {
+    /**
+     * This flag is set to false by the reaper to inform us that there
+     * are no more live references to our Timer object.  Once this flag
+     * is true and there are no more tasks in our queue, there is no
+     * work left for us to do, so we terminate gracefully.  Note that
+     * this field is protected by queue's monitor!
+     */
+    boolean newTasksMayBeScheduled = true;
+
+    /**
+     * Our Timer's queue.  We store this reference in preference to
+     * a reference to the Timer so the reference graph remains acyclic.
+     * Otherwise, the Timer would never be garbage-collected and this
+     * thread would never go away.
+     */
+    private TaskQueue queue;
+
+    TimerThread(TaskQueue queue) {
+        this.queue = queue;
+    }
+
+    public void run() {
+        try {
+            mainLoop();
+        } finally {
+            // Someone killed this Thread, behave as if Timer cancelled
+            synchronized(queue) {
+                newTasksMayBeScheduled = false;
+                queue.clear();  // Eliminate obsolete references
+            }
+        }
+    }
+
+    /**
+     * The main timer loop.  (See class comment.)
+     */
+    private void mainLoop() {
+        while (true) {
+            try {
+                TimerTask task;
+                boolean taskFired;
+                synchronized(queue) {
+                    // Wait for queue to become non-empty
+                    while (queue.isEmpty() && newTasksMayBeScheduled)
+                        queue.wait();
+                    if (queue.isEmpty())
+                        break; // Queue is empty and will forever remain; die
+
+                    // Queue nonempty; look at first evt and do the right thing
+                    long currentTime, executionTime;
+                    task = queue.getMin();
+                    synchronized(task.lock) {
+                        if (task.state == TimerTask.CANCELLED) {
+                            queue.removeMin();
+                            continue;  // No action required, poll queue again
+                        }
+                        currentTime = System.currentTimeMillis();
+                        executionTime = task.nextExecutionTime;
+                        if (taskFired = (executionTime<=currentTime)) {
+                            if (task.period == 0) { // Non-repeating, remove
+                                queue.removeMin();
+                                task.state = TimerTask.EXECUTED;
+                            } else { // Repeating task, reschedule
+                                queue.rescheduleMin(
+                                  task.period<0 ? currentTime   - task.period
+                                                : executionTime + task.period);
+                            }
+                        }
+                    }
+                    if (!taskFired) // Task hasn't yet fired; wait
+                        queue.wait(executionTime - currentTime);
+                }
+                if (taskFired)  // Task fired; run it, holding no locks
+                    task.run();
+            } catch(InterruptedException e) {
+            }
+        }
+    }
+}
+
+/**
+ * This class represents a timer task queue: a priority queue of TimerTasks,
+ * ordered on nextExecutionTime.  Each Timer object has one of these, which it
+ * shares with its TimerThread.  Internally this class uses a heap, which
+ * offers log(n) performance for the add, removeMin and rescheduleMin
+ * operations, and constant time performance for the getMin operation.
+ */
+class TaskQueue {
+    /**
+     * Priority queue represented as a balanced binary heap: the two children
+     * of queue[n] are queue[2*n] and queue[2*n+1].  The priority queue is
+     * ordered on the nextExecutionTime field: The TimerTask with the lowest
+     * nextExecutionTime is in queue[1] (assuming the queue is nonempty).  For
+     * each node n in the heap, and each descendant of n, d,
+     * n.nextExecutionTime <= d.nextExecutionTime.
+     */
+    private TimerTask[] queue = new TimerTask[128];
+
+    /**
+     * The number of tasks in the priority queue.  (The tasks are stored in
+     * queue[1] up to queue[size]).
+     */
+    private int size = 0;
+
+    /**
+     * Returns the number of tasks currently on the queue.
+     */
+    int size() {
+        return size;
+    }
+
+    /**
+     * Adds a new task to the priority queue.
+     */
+    void add(TimerTask task) {
+        // Grow backing store if necessary
+        if (size + 1 == queue.length)
+            queue = Arrays.copyOf(queue, 2*queue.length);
+
+        queue[++size] = task;
+        fixUp(size);
+    }
+
+    /**
+     * Return the "head task" of the priority queue.  (The head task is an
+     * task with the lowest nextExecutionTime.)
+     */
+    TimerTask getMin() {
+        return queue[1];
+    }
+
+    /**
+     * Return the ith task in the priority queue, where i ranges from 1 (the
+     * head task, which is returned by getMin) to the number of tasks on the
+     * queue, inclusive.
+     */
+    TimerTask get(int i) {
+        return queue[i];
+    }
+
+    /**
+     * Remove the head task from the priority queue.
+     */
+    void removeMin() {
+        queue[1] = queue[size];
+        queue[size--] = null;  // Drop extra reference to prevent memory leak
+        fixDown(1);
+    }
+
+    /**
+     * Removes the ith element from queue without regard for maintaining
+     * the heap invariant.  Recall that queue is one-based, so
+     * 1 <= i <= size.
+     */
+    void quickRemove(int i) {
+        assert i <= size;
+
+        queue[i] = queue[size];
+        queue[size--] = null;  // Drop extra ref to prevent memory leak
+    }
+
+    /**
+     * Sets the nextExecutionTime associated with the head task to the
+     * specified value, and adjusts priority queue accordingly.
+     */
+    void rescheduleMin(long newTime) {
+        queue[1].nextExecutionTime = newTime;
+        fixDown(1);
+    }
+
+    /**
+     * Returns true if the priority queue contains no elements.
+     */
+    boolean isEmpty() {
+        return size==0;
+    }
+
+    /**
+     * Removes all elements from the priority queue.
+     */
+    void clear() {
+        // Null out task references to prevent memory leak
+        for (int i=1; i<=size; i++)
+            queue[i] = null;
+
+        size = 0;
+    }
+
+    /**
+     * Establishes the heap invariant (described above) assuming the heap
+     * satisfies the invariant except possibly for the leaf-node indexed by k
+     * (which may have a nextExecutionTime less than its parent's).
+     *
+     * This method functions by "promoting" queue[k] up the hierarchy
+     * (by swapping it with its parent) repeatedly until queue[k]'s
+     * nextExecutionTime is greater than or equal to that of its parent.
+     */
+    private void fixUp(int k) {
+        while (k > 1) {
+            int j = k >> 1;
+            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the subtree
+     * rooted at k, which is assumed to satisfy the heap invariant except
+     * possibly for node k itself (which may have a nextExecutionTime greater
+     * than its children's).
+     *
+     * This method functions by "demoting" queue[k] down the hierarchy
+     * (by swapping it with its smaller child) repeatedly until queue[k]'s
+     * nextExecutionTime is less than or equal to those of its children.
+     */
+    private void fixDown(int k) {
+        int j;
+        while ((j = k << 1) <= size && j > 0) {
+            if (j < size &&
+                queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
+                j++; // j indexes smallest kid
+            if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
+                break;
+            TimerTask tmp = queue[j];  queue[j] = queue[k]; queue[k] = tmp;
+            k = j;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    void heapify() {
+        for (int i = size/2; i >= 1; i--)
+            fixDown(i);
+    }
+}
diff --git a/java/util/TimerTask.java b/java/util/TimerTask.java
new file mode 100644
index 0000000..5750486
--- /dev/null
+++ b/java/util/TimerTask.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A task that can be scheduled for one-time or repeated execution by a Timer.
+ *
+ * @author  Josh Bloch
+ * @see     Timer
+ * @since   1.3
+ */
+
+public abstract class TimerTask implements Runnable {
+    /**
+     * This object is used to control access to the TimerTask internals.
+     */
+    final Object lock = new Object();
+
+    /**
+     * The state of this task, chosen from the constants below.
+     */
+    int state = VIRGIN;
+
+    /**
+     * This task has not yet been scheduled.
+     */
+    static final int VIRGIN = 0;
+
+    /**
+     * This task is scheduled for execution.  If it is a non-repeating task,
+     * it has not yet been executed.
+     */
+    static final int SCHEDULED   = 1;
+
+    /**
+     * This non-repeating task has already executed (or is currently
+     * executing) and has not been cancelled.
+     */
+    static final int EXECUTED    = 2;
+
+    /**
+     * This task has been cancelled (with a call to TimerTask.cancel).
+     */
+    static final int CANCELLED   = 3;
+
+    /**
+     * Next execution time for this task in the format returned by
+     * System.currentTimeMillis, assuming this task is scheduled for execution.
+     * For repeating tasks, this field is updated prior to each task execution.
+     */
+    long nextExecutionTime;
+
+    /**
+     * Period in milliseconds for repeating tasks.  A positive value indicates
+     * fixed-rate execution.  A negative value indicates fixed-delay execution.
+     * A value of 0 indicates a non-repeating task.
+     */
+    long period = 0;
+
+    /**
+     * Creates a new timer task.
+     */
+    protected TimerTask() {
+    }
+
+    /**
+     * The action to be performed by this timer task.
+     */
+    public abstract void run();
+
+    /**
+     * Cancels this timer task.  If the task has been scheduled for one-time
+     * execution and has not yet run, or has not yet been scheduled, it will
+     * never run.  If the task has been scheduled for repeated execution, it
+     * will never run again.  (If the task is running when this call occurs,
+     * the task will run to completion, but will never run again.)
+     *
+     * <p>Note that calling this method from within the <tt>run</tt> method of
+     * a repeating timer task absolutely guarantees that the timer task will
+     * not run again.
+     *
+     * <p>This method may be called repeatedly; the second and subsequent
+     * calls have no effect.
+     *
+     * @return true if this task is scheduled for one-time execution and has
+     *         not yet run, or this task is scheduled for repeated execution.
+     *         Returns false if the task was scheduled for one-time execution
+     *         and has already run, or if the task was never scheduled, or if
+     *         the task was already cancelled.  (Loosely speaking, this method
+     *         returns <tt>true</tt> if it prevents one or more scheduled
+     *         executions from taking place.)
+     */
+    public boolean cancel() {
+        synchronized(lock) {
+            boolean result = (state == SCHEDULED);
+            state = CANCELLED;
+            return result;
+        }
+    }
+
+    /**
+     * Returns the <i>scheduled</i> execution time of the most recent
+     * <i>actual</i> execution of this task.  (If this method is invoked
+     * while task execution is in progress, the return value is the scheduled
+     * execution time of the ongoing task execution.)
+     *
+     * <p>This method is typically invoked from within a task's run method, to
+     * determine whether the current execution of the task is sufficiently
+     * timely to warrant performing the scheduled activity:
+     * <pre>{@code
+     *   public void run() {
+     *       if (System.currentTimeMillis() - scheduledExecutionTime() >=
+     *           MAX_TARDINESS)
+     *               return;  // Too late; skip this execution.
+     *       // Perform the task
+     *   }
+     * }</pre>
+     * This method is typically <i>not</i> used in conjunction with
+     * <i>fixed-delay execution</i> repeating tasks, as their scheduled
+     * execution times are allowed to drift over time, and so are not terribly
+     * significant.
+     *
+     * @return the time at which the most recent execution of this task was
+     *         scheduled to occur, in the format returned by Date.getTime().
+     *         The return value is undefined if the task has yet to commence
+     *         its first execution.
+     * @see Date#getTime()
+     */
+    public long scheduledExecutionTime() {
+        synchronized(lock) {
+            return (period < 0 ? nextExecutionTime + period
+                               : nextExecutionTime - period);
+        }
+    }
+}
diff --git a/java/util/TooManyListenersException.java b/java/util/TooManyListenersException.java
new file mode 100644
index 0000000..134dea8
--- /dev/null
+++ b/java/util/TooManyListenersException.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * <p>
+ * The <code> TooManyListenersException </code> Exception is used as part of
+ * the Java Event model to annotate and implement a unicast special case of
+ * a multicast Event Source.
+ * </p>
+ * <p>
+ * The presence of a "throws TooManyListenersException" clause on any given
+ * concrete implementation of the normally multicast "void addXyzEventListener"
+ * event listener registration pattern is used to annotate that interface as
+ * implementing a unicast Listener special case, that is, that one and only
+ * one Listener may be registered on the particular event listener source
+ * concurrently.
+ * </p>
+ *
+ * @see java.util.EventObject
+ * @see java.util.EventListener
+ *
+ * @author Laurence P. G. Cable
+ * @since  JDK1.1
+ */
+
+public class TooManyListenersException extends Exception {
+    private static final long serialVersionUID = 5074640544770687831L;
+
+    /**
+     * Constructs a TooManyListenersException with no detail message.
+     * A detail message is a String that describes this particular exception.
+     */
+
+    public TooManyListenersException() {
+        super();
+    }
+
+    /**
+     * Constructs a TooManyListenersException with the specified detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the detail message
+     */
+
+    public TooManyListenersException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/TreeMap.annotated.java b/java/util/TreeMap.annotated.java
new file mode 100644
index 0000000..87f1f20
--- /dev/null
+++ b/java/util/TreeMap.annotated.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class TreeMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.NavigableMap<K,V>, java.lang.Cloneable, java.io.Serializable {
+
+public TreeMap() { throw new RuntimeException("Stub!"); }
+
+public TreeMap(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam K> comparator) { throw new RuntimeException("Stub!"); }
+
+public TreeMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public TreeMap(@libcore.util.NonNull java.util.SortedMap<@libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Comparator<? super @libcore.util.NullFromTypeParam K> comparator() { throw new RuntimeException("Stub!"); }
+
[email protected] public K firstKey() { throw new RuntimeException("Stub!"); }
+
[email protected] public K lastKey() { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> map) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> firstEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lastEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollFirstEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> pollLastEntry() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> lowerEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K lowerKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> floorEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K floorKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> ceilingEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K ceilingKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Map.Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> higherEntry(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public K higherKey(@libcore.util.NullFromTypeParam K key) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> navigableKeySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableSet<@libcore.util.NullFromTypeParam K> descendingKeySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> descendingMap() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, boolean fromInclusive, @libcore.util.NullFromTypeParam K toKey, boolean toInclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey, boolean inclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.NavigableMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey, boolean inclusive) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> subMap(@libcore.util.NullFromTypeParam K fromKey, @libcore.util.NullFromTypeParam K toKey) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> headMap(@libcore.util.NullFromTypeParam K toKey) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.SortedMap<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V> tailMap(@libcore.util.NullFromTypeParam K fromKey) { throw new RuntimeException("Stub!"); }
+
+public boolean replace(@libcore.util.NullFromTypeParam K key, @libcore.util.Nullable V oldValue, @libcore.util.NullFromTypeParam V newValue) { throw new RuntimeException("Stub!"); }
+
[email protected] public V replace(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/TreeMap.java b/java/util/TreeMap.java
new file mode 100644
index 0000000..20d98bc
--- /dev/null
+++ b/java/util/TreeMap.java
@@ -0,0 +1,3049 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.Serializable;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+/**
+ * A Red-Black tree based {@link NavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This implementation provides guaranteed log(n) time cost for the
+ * {@code containsKey}, {@code get}, {@code put} and {@code remove}
+ * operations.  Algorithms are adaptations of those in Cormen, Leiserson, and
+ * Rivest's <em>Introduction to Algorithms</em>.
+ *
+ * <p>Note that the ordering maintained by a tree map, like any sorted map, and
+ * whether or not an explicit comparator is provided, must be <em>consistent
+ * with {@code equals}</em> if this sorted map is to correctly implement the
+ * {@code Map} interface.  (See {@code Comparable} or {@code Comparator} for a
+ * precise definition of <em>consistent with equals</em>.)  This is so because
+ * the {@code Map} interface is defined in terms of the {@code equals}
+ * operation, but a sorted map performs all key comparisons using its {@code
+ * compareTo} (or {@code compare}) method, so two keys that are deemed equal by
+ * this method are, from the standpoint of the sorted map, equal.  The behavior
+ * of a sorted map <em>is</em> well-defined even if its ordering is
+ * inconsistent with {@code equals}; it just fails to obey the general contract
+ * of the {@code Map} interface.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a map concurrently, and at least one of the
+ * threads modifies the map structurally, it <em>must</em> be synchronized
+ * externally.  (A structural modification is any operation that adds or
+ * deletes one or more mappings; merely changing the value associated
+ * with an existing key is not a structural modification.)  This is
+ * typically accomplished by synchronizing on some object that naturally
+ * encapsulates the map.
+ * If no such object exists, the map should be "wrapped" using the
+ * {@link Collections#synchronizedSortedMap Collections.synchronizedSortedMap}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the map: <pre>
+ *   SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));</pre>
+ *
+ * <p>The iterators returned by the {@code iterator} method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <em>fail-fast</em>: if the map is structurally modified at any time after
+ * the iterator is created, in any way except through the iterator's own
+ * {@code remove} method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <em>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</em>
+ *
+ * <p>All {@code Map.Entry} pairs returned by methods in this class
+ * and its views represent snapshots of mappings at the time they were
+ * produced. They do <strong>not</strong> support the {@code Entry.setValue}
+ * method. (Note however that it is possible to change mappings in the
+ * associated map using {@code put}.)
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author  Josh Bloch and Doug Lea
+ * @see Map
+ * @see HashMap
+ * @see Hashtable
+ * @see Comparable
+ * @see Comparator
+ * @see Collection
+ * @since 1.2
+ */
+
+public class TreeMap<K,V>
+    extends AbstractMap<K,V>
+    implements NavigableMap<K,V>, Cloneable, java.io.Serializable
+{
+    /**
+     * The comparator used to maintain order in this tree map, or
+     * null if it uses the natural ordering of its keys.
+     *
+     * @serial
+     */
+    private final Comparator<? super K> comparator;
+
+    private transient TreeMapEntry<K,V> root;
+
+    /**
+     * The number of entries in the tree
+     */
+    private transient int size = 0;
+
+    /**
+     * The number of structural modifications to the tree.
+     */
+    private transient int modCount = 0;
+
+    /**
+     * Constructs a new, empty tree map, using the natural ordering of its
+     * keys.  All keys inserted into the map must implement the {@link
+     * Comparable} interface.  Furthermore, all such keys must be
+     * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
+     * a {@code ClassCastException} for any keys {@code k1} and
+     * {@code k2} in the map.  If the user attempts to put a key into the
+     * map that violates this constraint (for example, the user attempts to
+     * put a string key into a map whose keys are integers), the
+     * {@code put(Object key, Object value)} call will throw a
+     * {@code ClassCastException}.
+     */
+    public TreeMap() {
+        comparator = null;
+    }
+
+    /**
+     * Constructs a new, empty tree map, ordered according to the given
+     * comparator.  All keys inserted into the map must be <em>mutually
+     * comparable</em> by the given comparator: {@code comparator.compare(k1,
+     * k2)} must not throw a {@code ClassCastException} for any keys
+     * {@code k1} and {@code k2} in the map.  If the user attempts to put
+     * a key into the map that violates this constraint, the {@code put(Object
+     * key, Object value)} call will throw a
+     * {@code ClassCastException}.
+     *
+     * @param comparator the comparator that will be used to order this map.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the keys will be used.
+     */
+    public TreeMap(Comparator<? super K> comparator) {
+        this.comparator = comparator;
+    }
+
+    /**
+     * Constructs a new tree map containing the same mappings as the given
+     * map, ordered according to the <em>natural ordering</em> of its keys.
+     * All keys inserted into the new map must implement the {@link
+     * Comparable} interface.  Furthermore, all such keys must be
+     * <em>mutually comparable</em>: {@code k1.compareTo(k2)} must not throw
+     * a {@code ClassCastException} for any keys {@code k1} and
+     * {@code k2} in the map.  This method runs in n*log(n) time.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws ClassCastException if the keys in m are not {@link Comparable},
+     *         or are not mutually comparable
+     * @throws NullPointerException if the specified map is null
+     */
+    public TreeMap(Map<? extends K, ? extends V> m) {
+        comparator = null;
+        putAll(m);
+    }
+
+    /**
+     * Constructs a new tree map containing the same mappings and
+     * using the same ordering as the specified sorted map.  This
+     * method runs in linear time.
+     *
+     * @param  m the sorted map whose mappings are to be placed in this map,
+     *         and whose comparator is to be used to sort this map
+     * @throws NullPointerException if the specified map is null
+     */
+    public TreeMap(SortedMap<K, ? extends V> m) {
+        comparator = m.comparator();
+        try {
+            buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
+        } catch (java.io.IOException cannotHappen) {
+        } catch (ClassNotFoundException cannotHappen) {
+        }
+    }
+
+
+    // Query Operations
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @return the number of key-value mappings in this map
+     */
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the
+     *         specified key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public boolean containsKey(Object key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  More formally, returns {@code true} if and only if
+     * this map contains at least one mapping to a value {@code v} such
+     * that {@code (value==null ? v==null : value.equals(v))}.  This
+     * operation will probably require time linear in the map size for
+     * most implementations.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if a mapping to {@code value} exists;
+     *         {@code false} otherwise
+     * @since 1.2
+     */
+    public boolean containsValue(Object value) {
+        for (TreeMapEntry<K,V> e = getFirstEntry(); e != null; e = successor(e))
+            if (valEquals(value, e.value))
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key} compares
+     * equal to {@code k} according to the map's ordering, then this
+     * method returns {@code v}; otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <em>necessarily</em>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V get(Object key) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        return (p==null ? null : p.value);
+    }
+
+    public Comparator<? super K> comparator() {
+        return comparator;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K firstKey() {
+        return key(getFirstEntry());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K lastKey() {
+        return key(getLastEntry());
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings replace any mappings that this map had for any
+     * of the keys currently in the specified map.
+     *
+     * @param  map mappings to be stored in this map
+     * @throws ClassCastException if the class of a key or value in
+     *         the specified map prevents it from being stored in this map
+     * @throws NullPointerException if the specified map is null or
+     *         the specified map contains a null key and this map does not
+     *         permit null keys
+     */
+    public void putAll(Map<? extends K, ? extends V> map) {
+        int mapSize = map.size();
+        if (size==0 && mapSize!=0 && map instanceof SortedMap) {
+            Comparator<?> c = ((SortedMap<?,?>)map).comparator();
+            if (c == comparator || (c != null && c.equals(comparator))) {
+                ++modCount;
+                try {
+                    buildFromSorted(mapSize, map.entrySet().iterator(),
+                                    null, null);
+                } catch (java.io.IOException cannotHappen) {
+                } catch (ClassNotFoundException cannotHappen) {
+                }
+                return;
+            }
+        }
+        super.putAll(map);
+    }
+
+    /**
+     * Returns this map's entry for the given key, or {@code null} if the map
+     * does not contain an entry for the key.
+     *
+     * @return this map's entry for the given key, or {@code null} if the map
+     *         does not contain an entry for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    final TreeMapEntry<K,V> getEntry(Object key) {
+        // Offload comparator-based version for sake of performance
+        if (comparator != null)
+            return getEntryUsingComparator(key);
+        if (key == null)
+            throw new NullPointerException();
+        @SuppressWarnings("unchecked")
+            Comparable<? super K> k = (Comparable<? super K>) key;
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = k.compareTo(p.key);
+            if (cmp < 0)
+                p = p.left;
+            else if (cmp > 0)
+                p = p.right;
+            else
+                return p;
+        }
+        return null;
+    }
+
+    /**
+     * Version of getEntry using comparator. Split off from getEntry
+     * for performance. (This is not worth doing for most methods,
+     * that are less dependent on comparator performance, but is
+     * worthwhile here.)
+     */
+    final TreeMapEntry<K,V> getEntryUsingComparator(Object key) {
+        @SuppressWarnings("unchecked")
+            K k = (K) key;
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            TreeMapEntry<K,V> p = root;
+            while (p != null) {
+                int cmp = cpr.compare(k, p.key);
+                if (cmp < 0)
+                    p = p.left;
+                else if (cmp > 0)
+                    p = p.right;
+                else
+                    return p;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry corresponding to the specified key; if no such entry
+     * exists, returns the entry for the least key greater than the specified
+     * key; if no such entry exists (i.e., the greatest key in the Tree is less
+     * than the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getCeilingEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp < 0) {
+                if (p.left != null)
+                    p = p.left;
+                else
+                    return p;
+            } else if (cmp > 0) {
+                if (p.right != null) {
+                    p = p.right;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.right) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            } else
+                return p;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry corresponding to the specified key; if no such entry
+     * exists, returns the entry for the greatest key less than the specified
+     * key; if no such entry exists, returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getFloorEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp > 0) {
+                if (p.right != null)
+                    p = p.right;
+                else
+                    return p;
+            } else if (cmp < 0) {
+                if (p.left != null) {
+                    p = p.left;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.left) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            } else
+                return p;
+
+        }
+        return null;
+    }
+
+    /**
+     * Gets the entry for the least key greater than the specified
+     * key; if no such entry exists, returns the entry for the least
+     * key greater than the specified key; if no such entry exists
+     * returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getHigherEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp < 0) {
+                if (p.left != null)
+                    p = p.left;
+                else
+                    return p;
+            } else {
+                if (p.right != null) {
+                    p = p.right;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.right) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the entry for the greatest key less than the specified key; if
+     * no such entry exists (i.e., the least key in the Tree is greater than
+     * the specified key), returns {@code null}.
+     */
+    final TreeMapEntry<K,V> getLowerEntry(K key) {
+        TreeMapEntry<K,V> p = root;
+        while (p != null) {
+            int cmp = compare(key, p.key);
+            if (cmp > 0) {
+                if (p.right != null)
+                    p = p.right;
+                else
+                    return p;
+            } else {
+                if (p.left != null) {
+                    p = p.left;
+                } else {
+                    TreeMapEntry<K,V> parent = p.parent;
+                    TreeMapEntry<K,V> ch = p;
+                    while (parent != null && ch == parent.left) {
+                        ch = parent;
+                        parent = parent.parent;
+                    }
+                    return parent;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     *
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V put(K key, V value) {
+        TreeMapEntry<K,V> t = root;
+        if (t == null) {
+            compare(key, key); // type (and possibly null) check
+
+            root = new TreeMapEntry<>(key, value, null);
+            size = 1;
+            modCount++;
+            return null;
+        }
+        int cmp;
+        TreeMapEntry<K,V> parent;
+        // split comparator and comparable paths
+        Comparator<? super K> cpr = comparator;
+        if (cpr != null) {
+            do {
+                parent = t;
+                cmp = cpr.compare(key, t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else
+                    return t.setValue(value);
+            } while (t != null);
+        }
+        else {
+            if (key == null)
+                throw new NullPointerException();
+            @SuppressWarnings("unchecked")
+                Comparable<? super K> k = (Comparable<? super K>) key;
+            do {
+                parent = t;
+                cmp = k.compareTo(t.key);
+                if (cmp < 0)
+                    t = t.left;
+                else if (cmp > 0)
+                    t = t.right;
+                else
+                    return t.setValue(value);
+            } while (t != null);
+        }
+        TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
+        if (cmp < 0)
+            parent.left = e;
+        else
+            parent.right = e;
+        fixAfterInsertion(e);
+        size++;
+        modCount++;
+        return null;
+    }
+
+    /**
+     * Removes the mapping for this key from this TreeMap if present.
+     *
+     * @param  key key for which mapping should be removed
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with {@code key}.)
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     */
+    public V remove(Object key) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p == null)
+            return null;
+
+        V oldValue = p.value;
+        deleteEntry(p);
+        return oldValue;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        modCount++;
+        size = 0;
+        root = null;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code TreeMap} instance. (The keys and
+     * values themselves are not cloned.)
+     *
+     * @return a shallow copy of this map
+     */
+    public Object clone() {
+        TreeMap<?,?> clone;
+        try {
+            clone = (TreeMap<?,?>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+
+        // Put clone into "virgin" state (except for comparator)
+        clone.root = null;
+        clone.size = 0;
+        clone.modCount = 0;
+        clone.entrySet = null;
+        clone.navigableKeySet = null;
+        clone.descendingMap = null;
+
+        // Initialize clone with our mappings
+        try {
+            clone.buildFromSorted(size, entrySet().iterator(), null, null);
+        } catch (java.io.IOException cannotHappen) {
+        } catch (ClassNotFoundException cannotHappen) {
+        }
+
+        return clone;
+    }
+
+    // NavigableMap API methods
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> firstEntry() {
+        return exportEntry(getFirstEntry());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> lastEntry() {
+        return exportEntry(getLastEntry());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> pollFirstEntry() {
+        TreeMapEntry<K,V> p = getFirstEntry();
+        Map.Entry<K,V> result = exportEntry(p);
+        if (p != null)
+            deleteEntry(p);
+        return result;
+    }
+
+    /**
+     * @since 1.6
+     */
+    public Map.Entry<K,V> pollLastEntry() {
+        TreeMapEntry<K,V> p = getLastEntry();
+        Map.Entry<K,V> result = exportEntry(p);
+        if (p != null)
+            deleteEntry(p);
+        return result;
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> lowerEntry(K key) {
+        return exportEntry(getLowerEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K lowerKey(K key) {
+        return keyOrNull(getLowerEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> floorEntry(K key) {
+        return exportEntry(getFloorEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K floorKey(K key) {
+        return keyOrNull(getFloorEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> ceilingEntry(K key) {
+        return exportEntry(getCeilingEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K ceilingKey(K key) {
+        return keyOrNull(getCeilingEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public Map.Entry<K,V> higherEntry(K key) {
+        return exportEntry(getHigherEntry(key));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @since 1.6
+     */
+    public K higherKey(K key) {
+        return keyOrNull(getHigherEntry(key));
+    }
+
+    // Views
+
+    /**
+     * Fields initialized to contain an instance of the entry set view
+     * the first time this view is requested.  Views are stateless, so
+     * there's no reason to create more than one.
+     */
+    private transient EntrySet entrySet;
+    private transient KeySet<K> navigableKeySet;
+    private transient NavigableMap<K,V> descendingMap;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED}
+     * and {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     */
+    public Set<K> keySet() {
+        return navigableKeySet();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<K> navigableKeySet() {
+        KeySet<K> nks = navigableKeySet;
+        return (nks != null) ? nks : (navigableKeySet = new KeySet<>(this));
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<K> descendingKeySet() {
+        return descendingMap().navigableKeySet();
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     *
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collection's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#ORDERED}
+     * with an encounter order that is ascending order of the corresponding
+     * keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own {@code remove} operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     *
+     * <p>The set's iterator returns the entries in ascending key order. The
+     * sets's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending key
+     * order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own {@code remove} operation, or through the
+     * {@code setValue} operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Set.remove}, {@code removeAll}, {@code retainAll} and
+     * {@code clear} operations.  It does not support the
+     * {@code add} or {@code addAll} operations.
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySet es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet());
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableMap<K, V> descendingMap() {
+        NavigableMap<K, V> km = descendingMap;
+        return (km != null) ? km :
+            (descendingMap = new DescendingSubMap<>(this,
+                                                    true, null, true,
+                                                    true, null, true));
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is
+     *         null and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                    K toKey,   boolean toInclusive) {
+        return new AscendingSubMap<>(this,
+                                     false, fromKey, fromInclusive,
+                                     false, toKey,   toInclusive);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+        return new AscendingSubMap<>(this,
+                                     true,  null,  true,
+                                     false, toKey, inclusive);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+        return new AscendingSubMap<>(this,
+                                     false, fromKey, inclusive,
+                                     true,  null,    true);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is
+     *         null and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> subMap(K fromKey, K toKey) {
+        return subMap(fromKey, true, toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> headMap(K toKey) {
+        return headMap(toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     *         and this map uses natural ordering, or its comparator
+     *         does not permit null keys
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedMap<K,V> tailMap(K fromKey) {
+        return tailMap(fromKey, true);
+    }
+
+    @Override
+    public boolean replace(K key, V oldValue, V newValue) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p!=null && Objects.equals(oldValue, p.value)) {
+            p.value = newValue;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public V replace(K key, V value) {
+        TreeMapEntry<K,V> p = getEntry(key);
+        if (p!=null) {
+            V oldValue = p.value;
+            p.value = value;
+            return oldValue;
+        }
+        return null;
+    }
+
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            action.accept(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+            e.value = function.apply(e.key, e.value);
+
+            if (expectedModCount != modCount) {
+                throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // View class support
+
+    class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator(getFirstEntry());
+        }
+
+        public int size() {
+            return TreeMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return TreeMap.this.containsValue(o);
+        }
+
+        public boolean remove(Object o) {
+            for (TreeMapEntry<K,V> e = getFirstEntry(); e != null; e = successor(e)) {
+                if (valEquals(e.getValue(), o)) {
+                    deleteEntry(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public void clear() {
+            TreeMap.this.clear();
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<K,V>(TreeMap.this, null, null, 0, -1, 0);
+        }
+    }
+
+    class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator(getFirstEntry());
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+            Object value = entry.getValue();
+            TreeMapEntry<K,V> p = getEntry(entry.getKey());
+            return p != null && valEquals(p.getValue(), value);
+        }
+
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+            Object value = entry.getValue();
+            TreeMapEntry<K,V> p = getEntry(entry.getKey());
+            if (p != null && valEquals(p.getValue(), value)) {
+                deleteEntry(p);
+                return true;
+            }
+            return false;
+        }
+
+        public int size() {
+            return TreeMap.this.size();
+        }
+
+        public void clear() {
+            TreeMap.this.clear();
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<K,V>(TreeMap.this, null, null, 0, -1, 0);
+        }
+    }
+
+    /*
+     * Unlike Values and EntrySet, the KeySet class is static,
+     * delegating to a NavigableMap to allow use by SubMaps, which
+     * outweighs the ugliness of needing type-tests for the following
+     * Iterator methods that are defined appropriately in main versus
+     * submap classes.
+     */
+
+    Iterator<K> keyIterator() {
+        return new KeyIterator(getFirstEntry());
+    }
+
+    Iterator<K> descendingKeyIterator() {
+        return new DescendingKeyIterator(getLastEntry());
+    }
+
+    static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> {
+        private final NavigableMap<E, ?> m;
+        KeySet(NavigableMap<E,?> map) { m = map; }
+
+        public Iterator<E> iterator() {
+            if (m instanceof TreeMap)
+                return ((TreeMap<E,?>)m).keyIterator();
+            else
+                return ((TreeMap.NavigableSubMap<E,?>)m).keyIterator();
+        }
+
+        public Iterator<E> descendingIterator() {
+            if (m instanceof TreeMap)
+                return ((TreeMap<E,?>)m).descendingKeyIterator();
+            else
+                return ((TreeMap.NavigableSubMap<E,?>)m).descendingKeyIterator();
+        }
+
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public void clear() { m.clear(); }
+        public E lower(E e) { return m.lowerKey(e); }
+        public E floor(E e) { return m.floorKey(e); }
+        public E ceiling(E e) { return m.ceilingKey(e); }
+        public E higher(E e) { return m.higherKey(e); }
+        public E first() { return m.firstKey(); }
+        public E last() { return m.lastKey(); }
+        public Comparator<? super E> comparator() { return m.comparator(); }
+        public E pollFirst() {
+            Map.Entry<E,?> e = m.pollFirstEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public E pollLast() {
+            Map.Entry<E,?> e = m.pollLastEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public boolean remove(Object o) {
+            int oldSize = size();
+            m.remove(o);
+            return size() != oldSize;
+        }
+        public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                                      E toElement,   boolean toInclusive) {
+            return new KeySet<>(m.subMap(fromElement, fromInclusive,
+                                          toElement,   toInclusive));
+        }
+        public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+            return new KeySet<>(m.headMap(toElement, inclusive));
+        }
+        public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+            return new KeySet<>(m.tailMap(fromElement, inclusive));
+        }
+        public SortedSet<E> subSet(E fromElement, E toElement) {
+            return subSet(fromElement, true, toElement, false);
+        }
+        public SortedSet<E> headSet(E toElement) {
+            return headSet(toElement, false);
+        }
+        public SortedSet<E> tailSet(E fromElement) {
+            return tailSet(fromElement, true);
+        }
+        public NavigableSet<E> descendingSet() {
+            return new KeySet<>(m.descendingMap());
+        }
+
+        public Spliterator<E> spliterator() {
+            return keySpliteratorFor(m);
+        }
+    }
+
+    /**
+     * Base class for TreeMap Iterators
+     */
+    abstract class PrivateEntryIterator<T> implements Iterator<T> {
+        TreeMapEntry<K,V> next;
+        TreeMapEntry<K,V> lastReturned;
+        int expectedModCount;
+
+        PrivateEntryIterator(TreeMapEntry<K,V> first) {
+            expectedModCount = modCount;
+            lastReturned = null;
+            next = first;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final TreeMapEntry<K,V> nextEntry() {
+            TreeMapEntry<K,V> e = next;
+            if (e == null)
+                throw new NoSuchElementException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            next = successor(e);
+            lastReturned = e;
+            return e;
+        }
+
+        final TreeMapEntry<K,V> prevEntry() {
+            TreeMapEntry<K,V> e = next;
+            if (e == null)
+                throw new NoSuchElementException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            next = predecessor(e);
+            lastReturned = e;
+            return e;
+        }
+
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            // deleted entries are replaced by their successors
+            if (lastReturned.left != null && lastReturned.right != null)
+                next = lastReturned;
+            deleteEntry(lastReturned);
+            expectedModCount = modCount;
+            lastReturned = null;
+        }
+    }
+
+    final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> {
+        EntryIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public Map.Entry<K,V> next() {
+            return nextEntry();
+        }
+    }
+
+    final class ValueIterator extends PrivateEntryIterator<V> {
+        ValueIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public V next() {
+            return nextEntry().value;
+        }
+    }
+
+    final class KeyIterator extends PrivateEntryIterator<K> {
+        KeyIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public K next() {
+            return nextEntry().key;
+        }
+    }
+
+    final class DescendingKeyIterator extends PrivateEntryIterator<K> {
+        DescendingKeyIterator(TreeMapEntry<K,V> first) {
+            super(first);
+        }
+        public K next() {
+            return prevEntry().key;
+        }
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            deleteEntry(lastReturned);
+            lastReturned = null;
+            expectedModCount = modCount;
+        }
+    }
+
+    // Little utilities
+
+    /**
+     * Compares two keys using the correct comparison method for this TreeMap.
+     */
+    @SuppressWarnings("unchecked")
+    final int compare(Object k1, Object k2) {
+        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
+            : comparator.compare((K)k1, (K)k2);
+    }
+
+    /**
+     * Test two values for equality.  Differs from o1.equals(o2) only in
+     * that it copes with {@code null} o1 properly.
+     */
+    static final boolean valEquals(Object o1, Object o2) {
+        return (o1==null ? o2==null : o1.equals(o2));
+    }
+
+    /**
+     * Return SimpleImmutableEntry for entry, or null if null
+     */
+    static <K,V> Map.Entry<K,V> exportEntry(TreeMapEntry<K,V> e) {
+        return (e == null) ? null :
+            new AbstractMap.SimpleImmutableEntry<>(e);
+    }
+
+    /**
+     * Return key for entry, or null if null
+     */
+    static <K,V> K keyOrNull(TreeMapEntry<K,V> e) {
+        return (e == null) ? null : e.key;
+    }
+
+    /**
+     * Returns the key corresponding to the specified Entry.
+     * @throws NoSuchElementException if the Entry is null
+     */
+    static <K> K key(TreeMapEntry<K,?> e) {
+        if (e==null)
+            throw new NoSuchElementException();
+        return e.key;
+    }
+
+
+    // SubMaps
+
+    /**
+     * Dummy value serving as unmatchable fence key for unbounded
+     * SubMapIterators
+     */
+    private static final Object UNBOUNDED = new Object();
+
+    /**
+     * @serial include
+     */
+    abstract static class NavigableSubMap<K,V> extends AbstractMap<K,V>
+        implements NavigableMap<K,V>, java.io.Serializable {
+        // Android-changed: Explicitly add a serialVersionUID so that we're serialization
+        // compatible with the Java-7 version of this class. Several new methods were added
+        // in Java-8 but none of them have any bearing on the serialized format of the class
+        // or require any additional state to be preserved.
+        private static final long serialVersionUID = 2765629423043303731L;
+
+        /**
+         * The backing map.
+         */
+        final TreeMap<K,V> m;
+
+        /**
+         * Endpoints are represented as triples (fromStart, lo,
+         * loInclusive) and (toEnd, hi, hiInclusive). If fromStart is
+         * true, then the low (absolute) bound is the start of the
+         * backing map, and the other values are ignored. Otherwise,
+         * if loInclusive is true, lo is the inclusive bound, else lo
+         * is the exclusive bound. Similarly for the upper bound.
+         */
+        final K lo, hi;
+        final boolean fromStart, toEnd;
+        final boolean loInclusive, hiInclusive;
+
+        NavigableSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            if (!fromStart && !toEnd) {
+                if (m.compare(lo, hi) > 0)
+                    throw new IllegalArgumentException("fromKey > toKey");
+            } else {
+                if (!fromStart) // type check
+                    m.compare(lo, lo);
+                if (!toEnd)
+                    m.compare(hi, hi);
+            }
+
+            this.m = m;
+            this.fromStart = fromStart;
+            this.lo = lo;
+            this.loInclusive = loInclusive;
+            this.toEnd = toEnd;
+            this.hi = hi;
+            this.hiInclusive = hiInclusive;
+        }
+
+        // internal utilities
+
+        final boolean tooLow(Object key) {
+            if (!fromStart) {
+                int c = m.compare(key, lo);
+                if (c < 0 || (c == 0 && !loInclusive))
+                    return true;
+            }
+            return false;
+        }
+
+        final boolean tooHigh(Object key) {
+            if (!toEnd) {
+                int c = m.compare(key, hi);
+                if (c > 0 || (c == 0 && !hiInclusive))
+                    return true;
+            }
+            return false;
+        }
+
+        final boolean inRange(Object key) {
+            return !tooLow(key) && !tooHigh(key);
+        }
+
+        final boolean inClosedRange(Object key) {
+            return (fromStart || m.compare(key, lo) >= 0)
+                && (toEnd || m.compare(hi, key) >= 0);
+        }
+
+        final boolean inRange(Object key, boolean inclusive) {
+            return inclusive ? inRange(key) : inClosedRange(key);
+        }
+
+        /*
+         * Absolute versions of relation operations.
+         * Subclasses map to these using like-named "sub"
+         * versions that invert senses for descending maps
+         */
+
+        final TreeMapEntry<K,V> absLowest() {
+            TreeMapEntry<K,V> e =
+                (fromStart ?  m.getFirstEntry() :
+                 (loInclusive ? m.getCeilingEntry(lo) :
+                                m.getHigherEntry(lo)));
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absHighest() {
+            TreeMapEntry<K,V> e =
+                (toEnd ?  m.getLastEntry() :
+                 (hiInclusive ?  m.getFloorEntry(hi) :
+                                 m.getLowerEntry(hi)));
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absCeiling(K key) {
+            if (tooLow(key))
+                return absLowest();
+            TreeMapEntry<K,V> e = m.getCeilingEntry(key);
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absHigher(K key) {
+            if (tooLow(key))
+                return absLowest();
+            TreeMapEntry<K,V> e = m.getHigherEntry(key);
+            return (e == null || tooHigh(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absFloor(K key) {
+            if (tooHigh(key))
+                return absHighest();
+            TreeMapEntry<K,V> e = m.getFloorEntry(key);
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        final TreeMapEntry<K,V> absLower(K key) {
+            if (tooHigh(key))
+                return absHighest();
+            TreeMapEntry<K,V> e = m.getLowerEntry(key);
+            return (e == null || tooLow(e.key)) ? null : e;
+        }
+
+        /** Returns the absolute high fence for ascending traversal */
+        final TreeMapEntry<K,V> absHighFence() {
+            return (toEnd ? null : (hiInclusive ?
+                                    m.getHigherEntry(hi) :
+                                    m.getCeilingEntry(hi)));
+        }
+
+        /** Return the absolute low fence for descending traversal  */
+        final TreeMapEntry<K,V> absLowFence() {
+            return (fromStart ? null : (loInclusive ?
+                                        m.getLowerEntry(lo) :
+                                        m.getFloorEntry(lo)));
+        }
+
+        // Abstract methods defined in ascending vs descending classes
+        // These relay to the appropriate absolute versions
+
+        abstract TreeMapEntry<K,V> subLowest();
+        abstract TreeMapEntry<K,V> subHighest();
+        abstract TreeMapEntry<K,V> subCeiling(K key);
+        abstract TreeMapEntry<K,V> subHigher(K key);
+        abstract TreeMapEntry<K,V> subFloor(K key);
+        abstract TreeMapEntry<K,V> subLower(K key);
+
+        /** Returns ascending iterator from the perspective of this submap */
+        abstract Iterator<K> keyIterator();
+
+        abstract Spliterator<K> keySpliterator();
+
+        /** Returns descending iterator from the perspective of this submap */
+        abstract Iterator<K> descendingKeyIterator();
+
+        // public methods
+
+        public boolean isEmpty() {
+            return (fromStart && toEnd) ? m.isEmpty() : entrySet().isEmpty();
+        }
+
+        public int size() {
+            return (fromStart && toEnd) ? m.size() : entrySet().size();
+        }
+
+        public final boolean containsKey(Object key) {
+            return inRange(key) && m.containsKey(key);
+        }
+
+        public final V put(K key, V value) {
+            if (!inRange(key))
+                throw new IllegalArgumentException("key out of range");
+            return m.put(key, value);
+        }
+
+        public final V get(Object key) {
+            return !inRange(key) ? null :  m.get(key);
+        }
+
+        public final V remove(Object key) {
+            return !inRange(key) ? null : m.remove(key);
+        }
+
+        public final Map.Entry<K,V> ceilingEntry(K key) {
+            return exportEntry(subCeiling(key));
+        }
+
+        public final K ceilingKey(K key) {
+            return keyOrNull(subCeiling(key));
+        }
+
+        public final Map.Entry<K,V> higherEntry(K key) {
+            return exportEntry(subHigher(key));
+        }
+
+        public final K higherKey(K key) {
+            return keyOrNull(subHigher(key));
+        }
+
+        public final Map.Entry<K,V> floorEntry(K key) {
+            return exportEntry(subFloor(key));
+        }
+
+        public final K floorKey(K key) {
+            return keyOrNull(subFloor(key));
+        }
+
+        public final Map.Entry<K,V> lowerEntry(K key) {
+            return exportEntry(subLower(key));
+        }
+
+        public final K lowerKey(K key) {
+            return keyOrNull(subLower(key));
+        }
+
+        public final K firstKey() {
+            return key(subLowest());
+        }
+
+        public final K lastKey() {
+            return key(subHighest());
+        }
+
+        public final Map.Entry<K,V> firstEntry() {
+            return exportEntry(subLowest());
+        }
+
+        public final Map.Entry<K,V> lastEntry() {
+            return exportEntry(subHighest());
+        }
+
+        public final Map.Entry<K,V> pollFirstEntry() {
+            TreeMapEntry<K,V> e = subLowest();
+            Map.Entry<K,V> result = exportEntry(e);
+            if (e != null)
+                m.deleteEntry(e);
+            return result;
+        }
+
+        public final Map.Entry<K,V> pollLastEntry() {
+            TreeMapEntry<K,V> e = subHighest();
+            Map.Entry<K,V> result = exportEntry(e);
+            if (e != null)
+                m.deleteEntry(e);
+            return result;
+        }
+
+        // Views
+        transient NavigableMap<K,V> descendingMapView;
+        transient EntrySetView entrySetView;
+        transient KeySet<K> navigableKeySetView;
+
+        public final NavigableSet<K> navigableKeySet() {
+            KeySet<K> nksv = navigableKeySetView;
+            return (nksv != null) ? nksv :
+                (navigableKeySetView = new TreeMap.KeySet<>(this));
+        }
+
+        public final Set<K> keySet() {
+            return navigableKeySet();
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return descendingMap().navigableKeySet();
+        }
+
+        public final SortedMap<K,V> subMap(K fromKey, K toKey) {
+            return subMap(fromKey, true, toKey, false);
+        }
+
+        public final SortedMap<K,V> headMap(K toKey) {
+            return headMap(toKey, false);
+        }
+
+        public final SortedMap<K,V> tailMap(K fromKey) {
+            return tailMap(fromKey, true);
+        }
+
+        // View classes
+
+        abstract class EntrySetView extends AbstractSet<Map.Entry<K,V>> {
+            private transient int size = -1, sizeModCount;
+
+            public int size() {
+                if (fromStart && toEnd)
+                    return m.size();
+                if (size == -1 || sizeModCount != m.modCount) {
+                    sizeModCount = m.modCount;
+                    size = 0;
+                    Iterator<?> i = iterator();
+                    while (i.hasNext()) {
+                        size++;
+                        i.next();
+                    }
+                }
+                return size;
+            }
+
+            public boolean isEmpty() {
+                TreeMapEntry<K,V> n = absLowest();
+                return n == null || tooHigh(n.key);
+            }
+
+            public boolean contains(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+                Object key = entry.getKey();
+                if (!inRange(key))
+                    return false;
+                TreeMapEntry<?, ?> node = m.getEntry(key);
+                return node != null &&
+                    valEquals(node.getValue(), entry.getValue());
+            }
+
+            public boolean remove(Object o) {
+                if (!(o instanceof Map.Entry))
+                    return false;
+                Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
+                Object key = entry.getKey();
+                if (!inRange(key))
+                    return false;
+                TreeMapEntry<K,V> node = m.getEntry(key);
+                if (node!=null && valEquals(node.getValue(),
+                                            entry.getValue())) {
+                    m.deleteEntry(node);
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        /**
+         * Iterators for SubMaps
+         */
+        abstract class SubMapIterator<T> implements Iterator<T> {
+            TreeMapEntry<K,V> lastReturned;
+            TreeMapEntry<K,V> next;
+            final Object fenceKey;
+            int expectedModCount;
+
+            SubMapIterator(TreeMapEntry<K,V> first,
+                           TreeMapEntry<K,V> fence) {
+                expectedModCount = m.modCount;
+                lastReturned = null;
+                next = first;
+                fenceKey = fence == null ? UNBOUNDED : fence.key;
+            }
+
+            public final boolean hasNext() {
+                return next != null && next.key != fenceKey;
+            }
+
+            final TreeMapEntry<K,V> nextEntry() {
+                TreeMapEntry<K,V> e = next;
+                if (e == null || e.key == fenceKey)
+                    throw new NoSuchElementException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                next = successor(e);
+                lastReturned = e;
+                return e;
+            }
+
+            final TreeMapEntry<K,V> prevEntry() {
+                TreeMapEntry<K,V> e = next;
+                if (e == null || e.key == fenceKey)
+                    throw new NoSuchElementException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                next = predecessor(e);
+                lastReturned = e;
+                return e;
+            }
+
+            final void removeAscending() {
+                if (lastReturned == null)
+                    throw new IllegalStateException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                // deleted entries are replaced by their successors
+                if (lastReturned.left != null && lastReturned.right != null)
+                    next = lastReturned;
+                m.deleteEntry(lastReturned);
+                lastReturned = null;
+                expectedModCount = m.modCount;
+            }
+
+            final void removeDescending() {
+                if (lastReturned == null)
+                    throw new IllegalStateException();
+                if (m.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                m.deleteEntry(lastReturned);
+                lastReturned = null;
+                expectedModCount = m.modCount;
+            }
+
+        }
+
+        final class SubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
+            SubMapEntryIterator(TreeMapEntry<K,V> first,
+                                TreeMapEntry<K,V> fence) {
+                super(first, fence);
+            }
+            public Map.Entry<K,V> next() {
+                return nextEntry();
+            }
+            public void remove() {
+                removeAscending();
+            }
+        }
+
+        final class DescendingSubMapEntryIterator extends SubMapIterator<Map.Entry<K,V>> {
+            DescendingSubMapEntryIterator(TreeMapEntry<K,V> last,
+                                          TreeMapEntry<K,V> fence) {
+                super(last, fence);
+            }
+
+            public Map.Entry<K,V> next() {
+                return prevEntry();
+            }
+            public void remove() {
+                removeDescending();
+            }
+        }
+
+        // Implement minimal Spliterator as KeySpliterator backup
+        final class SubMapKeyIterator extends SubMapIterator<K>
+            implements Spliterator<K> {
+            SubMapKeyIterator(TreeMapEntry<K,V> first,
+                              TreeMapEntry<K,V> fence) {
+                super(first, fence);
+            }
+            public K next() {
+                return nextEntry().key;
+            }
+            public void remove() {
+                removeAscending();
+            }
+            public Spliterator<K> trySplit() {
+                return null;
+            }
+            public void forEachRemaining(Consumer<? super K> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+            public boolean tryAdvance(Consumer<? super K> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED |
+                    Spliterator.SORTED;
+            }
+            public final Comparator<? super K>  getComparator() {
+                return NavigableSubMap.this.comparator();
+            }
+        }
+
+        final class DescendingSubMapKeyIterator extends SubMapIterator<K>
+            implements Spliterator<K> {
+            DescendingSubMapKeyIterator(TreeMapEntry<K,V> last,
+                                        TreeMapEntry<K,V> fence) {
+                super(last, fence);
+            }
+            public K next() {
+                return prevEntry().key;
+            }
+            public void remove() {
+                removeDescending();
+            }
+            public Spliterator<K> trySplit() {
+                return null;
+            }
+            public void forEachRemaining(Consumer<? super K> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+            public boolean tryAdvance(Consumer<? super K> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED;
+            }
+        }
+    }
+
+    /**
+     * @serial include
+     */
+    static final class AscendingSubMap<K,V> extends NavigableSubMap<K,V> {
+        private static final long serialVersionUID = 912986545866124060L;
+
+        AscendingSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
+        }
+
+        public Comparator<? super K> comparator() {
+            return m.comparator();
+        }
+
+        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                        K toKey,   boolean toInclusive) {
+            if (!inRange(fromKey, fromInclusive))
+                throw new IllegalArgumentException("fromKey out of range");
+            if (!inRange(toKey, toInclusive))
+                throw new IllegalArgumentException("toKey out of range");
+            return new AscendingSubMap<>(m,
+                                         false, fromKey, fromInclusive,
+                                         false, toKey,   toInclusive);
+        }
+
+        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(toKey, inclusive))
+            if (!inRange(toKey) && !(!toEnd && m.compare(toKey, hi) == 0 &&
+                !hiInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("toKey out of range");
+            return new AscendingSubMap<>(m,
+                                         fromStart, lo,    loInclusive,
+                                         false,     toKey, inclusive);
+        }
+
+        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(fromKey, inclusive))
+            if (!inRange(fromKey) && !(!fromStart && m.compare(fromKey, lo) == 0 &&
+                !loInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("fromKey out of range");
+            return new AscendingSubMap<>(m,
+                                         false, fromKey, inclusive,
+                                         toEnd, hi,      hiInclusive);
+        }
+
+        public NavigableMap<K,V> descendingMap() {
+            NavigableMap<K,V> mv = descendingMapView;
+            return (mv != null) ? mv :
+                (descendingMapView =
+                 new DescendingSubMap<>(m,
+                                        fromStart, lo, loInclusive,
+                                        toEnd,     hi, hiInclusive));
+        }
+
+        Iterator<K> keyIterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        Spliterator<K> keySpliterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        Iterator<K> descendingKeyIterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        final class AscendingEntrySetView extends EntrySetView {
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new SubMapEntryIterator(absLowest(), absHighFence());
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySetView es = entrySetView;
+            return (es != null) ? es : (entrySetView = new AscendingEntrySetView());
+        }
+
+        TreeMapEntry<K,V> subLowest()       { return absLowest(); }
+        TreeMapEntry<K,V> subHighest()      { return absHighest(); }
+        TreeMapEntry<K,V> subCeiling(K key) { return absCeiling(key); }
+        TreeMapEntry<K,V> subHigher(K key)  { return absHigher(key); }
+        TreeMapEntry<K,V> subFloor(K key)   { return absFloor(key); }
+        TreeMapEntry<K,V> subLower(K key)   { return absLower(key); }
+    }
+
+    /**
+     * @serial include
+     */
+    static final class DescendingSubMap<K,V>  extends NavigableSubMap<K,V> {
+        private static final long serialVersionUID = 912986545866120460L;
+        DescendingSubMap(TreeMap<K,V> m,
+                        boolean fromStart, K lo, boolean loInclusive,
+                        boolean toEnd,     K hi, boolean hiInclusive) {
+            super(m, fromStart, lo, loInclusive, toEnd, hi, hiInclusive);
+        }
+
+        private final Comparator<? super K> reverseComparator =
+            Collections.reverseOrder(m.comparator);
+
+        public Comparator<? super K> comparator() {
+            return reverseComparator;
+        }
+
+        public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                        K toKey,   boolean toInclusive) {
+            if (!inRange(fromKey, fromInclusive))
+                throw new IllegalArgumentException("fromKey out of range");
+            if (!inRange(toKey, toInclusive))
+                throw new IllegalArgumentException("toKey out of range");
+            return new DescendingSubMap<>(m,
+                                          false, toKey,   toInclusive,
+                                          false, fromKey, fromInclusive);
+        }
+
+        public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(toKey, inclusive))
+            if (!inRange(toKey) && !(!fromStart && m.compare(toKey, lo) == 0 &&
+                !loInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("toKey out of range");
+            return new DescendingSubMap<>(m,
+                                          false, toKey, inclusive,
+                                          toEnd, hi,    hiInclusive);
+        }
+
+        public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            // BEGIN Android-changed: Fix for edge cases
+            // if (!inRange(fromKey, inclusive))
+            if (!inRange(fromKey) && !(!toEnd && m.compare(fromKey, hi) == 0 &&
+                !hiInclusive && !inclusive))
+            // END Android-changed: Fix for edge cases
+                throw new IllegalArgumentException("fromKey out of range");
+            return new DescendingSubMap<>(m,
+                                          fromStart, lo, loInclusive,
+                                          false, fromKey, inclusive);
+        }
+
+        public NavigableMap<K,V> descendingMap() {
+            NavigableMap<K,V> mv = descendingMapView;
+            return (mv != null) ? mv :
+                (descendingMapView =
+                 new AscendingSubMap<>(m,
+                                       fromStart, lo, loInclusive,
+                                       toEnd,     hi, hiInclusive));
+        }
+
+        Iterator<K> keyIterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        Spliterator<K> keySpliterator() {
+            return new DescendingSubMapKeyIterator(absHighest(), absLowFence());
+        }
+
+        Iterator<K> descendingKeyIterator() {
+            return new SubMapKeyIterator(absLowest(), absHighFence());
+        }
+
+        final class DescendingEntrySetView extends EntrySetView {
+            public Iterator<Map.Entry<K,V>> iterator() {
+                return new DescendingSubMapEntryIterator(absHighest(), absLowFence());
+            }
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            EntrySetView es = entrySetView;
+            return (es != null) ? es : (entrySetView = new DescendingEntrySetView());
+        }
+
+        TreeMapEntry<K,V> subLowest()       { return absHighest(); }
+        TreeMapEntry<K,V> subHighest()      { return absLowest(); }
+        TreeMapEntry<K,V> subCeiling(K key) { return absFloor(key); }
+        TreeMapEntry<K,V> subHigher(K key)  { return absLower(key); }
+        TreeMapEntry<K,V> subFloor(K key)   { return absCeiling(key); }
+        TreeMapEntry<K,V> subLower(K key)   { return absHigher(key); }
+    }
+
+    /**
+     * This class exists solely for the sake of serialization
+     * compatibility with previous releases of TreeMap that did not
+     * support NavigableMap.  It translates an old-version SubMap into
+     * a new-version AscendingSubMap. This class is never otherwise
+     * used.
+     *
+     * @serial include
+     */
+    private class SubMap extends AbstractMap<K,V>
+        implements SortedMap<K,V>, java.io.Serializable {
+        private static final long serialVersionUID = -6520786458950516097L;
+        private boolean fromStart = false, toEnd = false;
+        private K fromKey, toKey;
+        private Object readResolve() {
+            return new AscendingSubMap<>(TreeMap.this,
+                                         fromStart, fromKey, true,
+                                         toEnd, toKey, false);
+        }
+        public Set<Map.Entry<K,V>> entrySet() { throw new InternalError(); }
+        public K lastKey() { throw new InternalError(); }
+        public K firstKey() { throw new InternalError(); }
+        public SortedMap<K,V> subMap(K fromKey, K toKey) { throw new InternalError(); }
+        public SortedMap<K,V> headMap(K toKey) { throw new InternalError(); }
+        public SortedMap<K,V> tailMap(K fromKey) { throw new InternalError(); }
+        public Comparator<? super K> comparator() { throw new InternalError(); }
+    }
+
+
+    // Red-black mechanics
+
+    private static final boolean RED   = false;
+    private static final boolean BLACK = true;
+
+    /**
+     * Node in the Tree.  Doubles as a means to pass key-value pairs back to
+     * user (see Map.Entry).
+     */
+    // BEGIN Android-changed: Renamed Entry -> TreeMapEntry.
+    // Code references to "TreeMap.Entry" must mean Map.Entry
+    //
+    // This mirrors the corresponding rename of LinkedHashMap's
+    // Entry->LinkedHashMapEntry.
+    //
+    // This is for source compatibility with earlier versions of Android.
+    // Otherwise, it would hide Map.Entry.
+    // END Android-changed: Renamed Entry -> TreeMapEntry.
+    static final class TreeMapEntry<K,V> implements Map.Entry<K,V> {
+        K key;
+        V value;
+        TreeMapEntry<K,V> left;
+        TreeMapEntry<K,V> right;
+        TreeMapEntry<K,V> parent;
+        boolean color = BLACK;
+
+        /**
+         * Make a new cell with given key, value, and parent, and with
+         * {@code null} child links, and BLACK color.
+         */
+        TreeMapEntry(K key, V value, TreeMapEntry<K,V> parent) {
+            this.key = key;
+            this.value = value;
+            this.parent = parent;
+        }
+
+        /**
+         * Returns the key.
+         *
+         * @return the key
+         */
+        public K getKey() {
+            return key;
+        }
+
+        /**
+         * Returns the value associated with the key.
+         *
+         * @return the value associated with the key
+         */
+        public V getValue() {
+            return value;
+        }
+
+        /**
+         * Replaces the value currently associated with the key with the given
+         * value.
+         *
+         * @return the value associated with the key before this method was
+         *         called
+         */
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+
+            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
+        }
+
+        public int hashCode() {
+            int keyHash = (key==null ? 0 : key.hashCode());
+            int valueHash = (value==null ? 0 : value.hashCode());
+            return keyHash ^ valueHash;
+        }
+
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+    /**
+     * Returns the first Entry in the TreeMap (according to the TreeMap's
+     * key-sort function).  Returns null if the TreeMap is empty.
+     */
+    final TreeMapEntry<K,V> getFirstEntry() {
+        TreeMapEntry<K,V> p = root;
+        if (p != null)
+            while (p.left != null)
+                p = p.left;
+        return p;
+    }
+
+    /**
+     * Returns the last Entry in the TreeMap (according to the TreeMap's
+     * key-sort function).  Returns null if the TreeMap is empty.
+     */
+    final TreeMapEntry<K,V> getLastEntry() {
+        TreeMapEntry<K,V> p = root;
+        if (p != null)
+            while (p.right != null)
+                p = p.right;
+        return p;
+    }
+
+    /**
+     * Returns the successor of the specified Entry, or null if no such.
+     */
+    static <K,V> TreeMapEntry<K,V> successor(TreeMapEntry<K,V> t) {
+        if (t == null)
+            return null;
+        else if (t.right != null) {
+            TreeMapEntry<K,V> p = t.right;
+            while (p.left != null)
+                p = p.left;
+            return p;
+        } else {
+            TreeMapEntry<K,V> p = t.parent;
+            TreeMapEntry<K,V> ch = t;
+            while (p != null && ch == p.right) {
+                ch = p;
+                p = p.parent;
+            }
+            return p;
+        }
+    }
+
+    /**
+     * Returns the predecessor of the specified Entry, or null if no such.
+     */
+    static <K,V> TreeMapEntry<K,V> predecessor(TreeMapEntry<K,V> t) {
+        if (t == null)
+            return null;
+        else if (t.left != null) {
+            TreeMapEntry<K,V> p = t.left;
+            while (p.right != null)
+                p = p.right;
+            return p;
+        } else {
+            TreeMapEntry<K,V> p = t.parent;
+            TreeMapEntry<K,V> ch = t;
+            while (p != null && ch == p.left) {
+                ch = p;
+                p = p.parent;
+            }
+            return p;
+        }
+    }
+
+    /**
+     * Balancing operations.
+     *
+     * Implementations of rebalancings during insertion and deletion are
+     * slightly different than the CLR version.  Rather than using dummy
+     * nilnodes, we use a set of accessors that deal properly with null.  They
+     * are used to avoid messiness surrounding nullness checks in the main
+     * algorithms.
+     */
+
+    private static <K,V> boolean colorOf(TreeMapEntry<K,V> p) {
+        return (p == null ? BLACK : p.color);
+    }
+
+    private static <K,V> TreeMapEntry<K,V> parentOf(TreeMapEntry<K,V> p) {
+        return (p == null ? null: p.parent);
+    }
+
+    private static <K,V> void setColor(TreeMapEntry<K,V> p, boolean c) {
+        if (p != null)
+            p.color = c;
+    }
+
+    private static <K,V> TreeMapEntry<K,V> leftOf(TreeMapEntry<K,V> p) {
+        return (p == null) ? null: p.left;
+    }
+
+    private static <K,V> TreeMapEntry<K,V> rightOf(TreeMapEntry<K,V> p) {
+        return (p == null) ? null: p.right;
+    }
+
+    /** From CLR */
+    private void rotateLeft(TreeMapEntry<K,V> p) {
+        if (p != null) {
+            TreeMapEntry<K,V> r = p.right;
+            p.right = r.left;
+            if (r.left != null)
+                r.left.parent = p;
+            r.parent = p.parent;
+            if (p.parent == null)
+                root = r;
+            else if (p.parent.left == p)
+                p.parent.left = r;
+            else
+                p.parent.right = r;
+            r.left = p;
+            p.parent = r;
+        }
+    }
+
+    /** From CLR */
+    private void rotateRight(TreeMapEntry<K,V> p) {
+        if (p != null) {
+            TreeMapEntry<K,V> l = p.left;
+            p.left = l.right;
+            if (l.right != null) l.right.parent = p;
+            l.parent = p.parent;
+            if (p.parent == null)
+                root = l;
+            else if (p.parent.right == p)
+                p.parent.right = l;
+            else p.parent.left = l;
+            l.right = p;
+            p.parent = l;
+        }
+    }
+
+    /** From CLR */
+    private void fixAfterInsertion(TreeMapEntry<K,V> x) {
+        x.color = RED;
+
+        while (x != null && x != root && x.parent.color == RED) {
+            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
+                TreeMapEntry<K,V> y = rightOf(parentOf(parentOf(x)));
+                if (colorOf(y) == RED) {
+                    setColor(parentOf(x), BLACK);
+                    setColor(y, BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    x = parentOf(parentOf(x));
+                } else {
+                    if (x == rightOf(parentOf(x))) {
+                        x = parentOf(x);
+                        rotateLeft(x);
+                    }
+                    setColor(parentOf(x), BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    rotateRight(parentOf(parentOf(x)));
+                }
+            } else {
+                TreeMapEntry<K,V> y = leftOf(parentOf(parentOf(x)));
+                if (colorOf(y) == RED) {
+                    setColor(parentOf(x), BLACK);
+                    setColor(y, BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    x = parentOf(parentOf(x));
+                } else {
+                    if (x == leftOf(parentOf(x))) {
+                        x = parentOf(x);
+                        rotateRight(x);
+                    }
+                    setColor(parentOf(x), BLACK);
+                    setColor(parentOf(parentOf(x)), RED);
+                    rotateLeft(parentOf(parentOf(x)));
+                }
+            }
+        }
+        root.color = BLACK;
+    }
+
+    /**
+     * Delete node p, and then rebalance the tree.
+     */
+    private void deleteEntry(TreeMapEntry<K,V> p) {
+        modCount++;
+        size--;
+
+        // If strictly internal, copy successor's element to p and then make p
+        // point to successor.
+        if (p.left != null && p.right != null) {
+            TreeMapEntry<K,V> s = successor(p);
+            p.key = s.key;
+            p.value = s.value;
+            p = s;
+        } // p has 2 children
+
+        // Start fixup at replacement node, if it exists.
+        TreeMapEntry<K,V> replacement = (p.left != null ? p.left : p.right);
+
+        if (replacement != null) {
+            // Link replacement to parent
+            replacement.parent = p.parent;
+            if (p.parent == null)
+                root = replacement;
+            else if (p == p.parent.left)
+                p.parent.left  = replacement;
+            else
+                p.parent.right = replacement;
+
+            // Null out links so they are OK to use by fixAfterDeletion.
+            p.left = p.right = p.parent = null;
+
+            // Fix replacement
+            if (p.color == BLACK)
+                fixAfterDeletion(replacement);
+        } else if (p.parent == null) { // return if we are the only node.
+            root = null;
+        } else { //  No children. Use self as phantom replacement and unlink.
+            if (p.color == BLACK)
+                fixAfterDeletion(p);
+
+            if (p.parent != null) {
+                if (p == p.parent.left)
+                    p.parent.left = null;
+                else if (p == p.parent.right)
+                    p.parent.right = null;
+                p.parent = null;
+            }
+        }
+    }
+
+    /** From CLR */
+    private void fixAfterDeletion(TreeMapEntry<K,V> x) {
+        while (x != root && colorOf(x) == BLACK) {
+            if (x == leftOf(parentOf(x))) {
+                TreeMapEntry<K,V> sib = rightOf(parentOf(x));
+
+                if (colorOf(sib) == RED) {
+                    setColor(sib, BLACK);
+                    setColor(parentOf(x), RED);
+                    rotateLeft(parentOf(x));
+                    sib = rightOf(parentOf(x));
+                }
+
+                if (colorOf(leftOf(sib))  == BLACK &&
+                    colorOf(rightOf(sib)) == BLACK) {
+                    setColor(sib, RED);
+                    x = parentOf(x);
+                } else {
+                    if (colorOf(rightOf(sib)) == BLACK) {
+                        setColor(leftOf(sib), BLACK);
+                        setColor(sib, RED);
+                        rotateRight(sib);
+                        sib = rightOf(parentOf(x));
+                    }
+                    setColor(sib, colorOf(parentOf(x)));
+                    setColor(parentOf(x), BLACK);
+                    setColor(rightOf(sib), BLACK);
+                    rotateLeft(parentOf(x));
+                    x = root;
+                }
+            } else { // symmetric
+                TreeMapEntry<K,V> sib = leftOf(parentOf(x));
+
+                if (colorOf(sib) == RED) {
+                    setColor(sib, BLACK);
+                    setColor(parentOf(x), RED);
+                    rotateRight(parentOf(x));
+                    sib = leftOf(parentOf(x));
+                }
+
+                if (colorOf(rightOf(sib)) == BLACK &&
+                    colorOf(leftOf(sib)) == BLACK) {
+                    setColor(sib, RED);
+                    x = parentOf(x);
+                } else {
+                    if (colorOf(leftOf(sib)) == BLACK) {
+                        setColor(rightOf(sib), BLACK);
+                        setColor(sib, RED);
+                        rotateLeft(sib);
+                        sib = leftOf(parentOf(x));
+                    }
+                    setColor(sib, colorOf(parentOf(x)));
+                    setColor(parentOf(x), BLACK);
+                    setColor(leftOf(sib), BLACK);
+                    rotateRight(parentOf(x));
+                    x = root;
+                }
+            }
+        }
+
+        setColor(x, BLACK);
+    }
+
+    private static final long serialVersionUID = 919286545866124006L;
+
+    /**
+     * Save the state of the {@code TreeMap} instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <em>size</em> of the TreeMap (the number of key-value
+     *             mappings) is emitted (int), followed by the key (Object)
+     *             and value (Object) for each key-value mapping represented
+     *             by the TreeMap. The key-value mappings are emitted in
+     *             key-order (as determined by the TreeMap's Comparator,
+     *             or by the keys' natural ordering if the TreeMap has no
+     *             Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out the Comparator and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) {
+            Map.Entry<K,V> e = i.next();
+            s.writeObject(e.getKey());
+            s.writeObject(e.getValue());
+        }
+    }
+
+    /**
+     * Reconstitute the {@code TreeMap} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(final java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in the Comparator and any hidden stuff
+        s.defaultReadObject();
+
+        // Read in size
+        int size = s.readInt();
+
+        buildFromSorted(size, null, s, null);
+    }
+
+    /** Intended to be called only from TreeSet.readObject */
+    void readTreeSet(int size, java.io.ObjectInputStream s, V defaultVal)
+        throws java.io.IOException, ClassNotFoundException {
+        buildFromSorted(size, null, s, defaultVal);
+    }
+
+    /** Intended to be called only from TreeSet.addAll */
+    void addAllForTreeSet(SortedSet<? extends K> set, V defaultVal) {
+        try {
+            buildFromSorted(set.size(), set.iterator(), null, defaultVal);
+        } catch (java.io.IOException cannotHappen) {
+        } catch (ClassNotFoundException cannotHappen) {
+        }
+    }
+
+
+    /**
+     * Linear time tree building algorithm from sorted data.  Can accept keys
+     * and/or values from iterator or stream. This leads to too many
+     * parameters, but seems better than alternatives.  The four formats
+     * that this method accepts are:
+     *
+     *    1) An iterator of Map.Entries.  (it != null, defaultVal == null).
+     *    2) An iterator of keys.         (it != null, defaultVal != null).
+     *    3) A stream of alternating serialized keys and values.
+     *                                   (it == null, defaultVal == null).
+     *    4) A stream of serialized keys. (it == null, defaultVal != null).
+     *
+     * It is assumed that the comparator of the TreeMap is already set prior
+     * to calling this method.
+     *
+     * @param size the number of keys (or key-value pairs) to be read from
+     *        the iterator or stream
+     * @param it If non-null, new entries are created from entries
+     *        or keys read from this iterator.
+     * @param str If non-null, new entries are created from keys and
+     *        possibly values read from this stream in serialized form.
+     *        Exactly one of it and str should be non-null.
+     * @param defaultVal if non-null, this default value is used for
+     *        each value in the map.  If null, each value is read from
+     *        iterator or stream, as described above.
+     * @throws java.io.IOException propagated from stream reads. This cannot
+     *         occur if str is null.
+     * @throws ClassNotFoundException propagated from readObject.
+     *         This cannot occur if str is null.
+     */
+    private void buildFromSorted(int size, Iterator<?> it,
+                                 java.io.ObjectInputStream str,
+                                 V defaultVal)
+        throws  java.io.IOException, ClassNotFoundException {
+        this.size = size;
+        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
+                               it, str, defaultVal);
+    }
+
+    /**
+     * Recursive "helper method" that does the real work of the
+     * previous method.  Identically named parameters have
+     * identical definitions.  Additional parameters are documented below.
+     * It is assumed that the comparator and size fields of the TreeMap are
+     * already set prior to calling this method.  (It ignores both fields.)
+     *
+     * @param level the current level of tree. Initial call should be 0.
+     * @param lo the first element index of this subtree. Initial should be 0.
+     * @param hi the last element index of this subtree.  Initial should be
+     *        size-1.
+     * @param redLevel the level at which nodes should be red.
+     *        Must be equal to computeRedLevel for tree of this size.
+     */
+    @SuppressWarnings("unchecked")
+    private final TreeMapEntry<K,V> buildFromSorted(int level, int lo, int hi,
+                                             int redLevel,
+                                             Iterator<?> it,
+                                             java.io.ObjectInputStream str,
+                                             V defaultVal)
+        throws  java.io.IOException, ClassNotFoundException {
+        /*
+         * Strategy: The root is the middlemost element. To get to it, we
+         * have to first recursively construct the entire left subtree,
+         * so as to grab all of its elements. We can then proceed with right
+         * subtree.
+         *
+         * The lo and hi arguments are the minimum and maximum
+         * indices to pull out of the iterator or stream for current subtree.
+         * They are not actually indexed, we just proceed sequentially,
+         * ensuring that items are extracted in corresponding order.
+         */
+
+        if (hi < lo) return null;
+
+        int mid = (lo + hi) >>> 1;
+
+        TreeMapEntry<K,V> left  = null;
+        if (lo < mid)
+            left = buildFromSorted(level+1, lo, mid - 1, redLevel,
+                                   it, str, defaultVal);
+
+        // extract key and/or value from iterator or stream
+        K key;
+        V value;
+        if (it != null) {
+            if (defaultVal==null) {
+                Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next();
+                key = (K)entry.getKey();
+                value = (V)entry.getValue();
+            } else {
+                key = (K)it.next();
+                value = defaultVal;
+            }
+        } else { // use stream
+            key = (K) str.readObject();
+            value = (defaultVal != null ? defaultVal : (V) str.readObject());
+        }
+
+        TreeMapEntry<K,V> middle =  new TreeMapEntry<>(key, value, null);
+
+        // color nodes in non-full bottommost level red
+        if (level == redLevel)
+            middle.color = RED;
+
+        if (left != null) {
+            middle.left = left;
+            left.parent = middle;
+        }
+
+        if (mid < hi) {
+            TreeMapEntry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
+                                               it, str, defaultVal);
+            middle.right = right;
+            right.parent = middle;
+        }
+
+        return middle;
+    }
+
+    /**
+     * Find the level down to which to assign all nodes BLACK.  This is the
+     * last `full' level of the complete binary tree produced by
+     * buildTree. The remaining nodes are colored RED. (This makes a `nice'
+     * set of color assignments wrt future insertions.) This level number is
+     * computed by finding the number of splits needed to reach the zeroeth
+     * node.  (The answer is ~lg(N), but in any case must be computed by same
+     * quick O(lg(N)) loop.)
+     */
+    private static int computeRedLevel(int sz) {
+        int level = 0;
+        for (int m = sz - 1; m >= 0; m = m / 2 - 1)
+            level++;
+        return level;
+    }
+
+    /**
+     * Currently, we support Spliterator-based versions only for the
+     * full map, in either plain of descending form, otherwise relying
+     * on defaults because size estimation for submaps would dominate
+     * costs. The type tests needed to check these for key views are
+     * not very nice but avoid disrupting existing class
+     * structures. Callers must use plain default spliterators if this
+     * returns null.
+     */
+    static <K> Spliterator<K> keySpliteratorFor(NavigableMap<K,?> m) {
+        if (m instanceof TreeMap) {
+            @SuppressWarnings("unchecked") TreeMap<K,Object> t =
+                (TreeMap<K,Object>) m;
+            return t.keySpliterator();
+        }
+        if (m instanceof DescendingSubMap) {
+            @SuppressWarnings("unchecked") DescendingSubMap<K,?> dm =
+                (DescendingSubMap<K,?>) m;
+            TreeMap<K,?> tm = dm.m;
+            if (dm == tm.descendingMap) {
+                @SuppressWarnings("unchecked") TreeMap<K,Object> t =
+                    (TreeMap<K,Object>) tm;
+                return t.descendingKeySpliterator();
+            }
+        }
+        @SuppressWarnings("unchecked") NavigableSubMap<K,?> sm =
+            (NavigableSubMap<K,?>) m;
+        return sm.keySpliterator();
+    }
+
+    final Spliterator<K> keySpliterator() {
+        return new KeySpliterator<K,V>(this, null, null, 0, -1, 0);
+    }
+
+    final Spliterator<K> descendingKeySpliterator() {
+        return new DescendingKeySpliterator<K,V>(this, null, null, 0, -2, 0);
+    }
+
+    /**
+     * Base class for spliterators.  Iteration starts at a given
+     * origin and continues up to but not including a given fence (or
+     * null for end).  At top-level, for ascending cases, the first
+     * split uses the root as left-fence/right-origin. From there,
+     * right-hand splits replace the current fence with its left
+     * child, also serving as origin for the split-off spliterator.
+     * Left-hands are symmetric. Descending versions place the origin
+     * at the end and invert ascending split rules.  This base class
+     * is non-commital about directionality, or whether the top-level
+     * spliterator covers the whole tree. This means that the actual
+     * split mechanics are located in subclasses. Some of the subclass
+     * trySplit methods are identical (except for return types), but
+     * not nicely factorable.
+     *
+     * Currently, subclass versions exist only for the full map
+     * (including descending keys via its descendingMap).  Others are
+     * possible but currently not worthwhile because submaps require
+     * O(n) computations to determine size, which substantially limits
+     * potential speed-ups of using custom Spliterators versus default
+     * mechanics.
+     *
+     * To boostrap initialization, external constructors use
+     * negative size estimates: -1 for ascend, -2 for descend.
+     */
+    static class TreeMapSpliterator<K,V> {
+        final TreeMap<K,V> tree;
+        TreeMapEntry<K,V> current; // traverser; initially first node in range
+        TreeMapEntry<K,V> fence;   // one past last, or null
+        int side;                   // 0: top, -1: is a left split, +1: right
+        int est;                    // size estimate (exact only for top-level)
+        int expectedModCount;       // for CME checks
+
+        TreeMapSpliterator(TreeMap<K,V> tree,
+                           TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                           int side, int est, int expectedModCount) {
+            this.tree = tree;
+            this.current = origin;
+            this.fence = fence;
+            this.side = side;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getEstimate() { // force initialization
+            int s; TreeMap<K,V> t;
+            if ((s = est) < 0) {
+                if ((t = tree) != null) {
+                    current = (s == -1) ? t.getFirstEntry() : t.getLastEntry();
+                    s = est = t.size;
+                    expectedModCount = t.modCount;
+                }
+                else
+                    s = est = 0;
+            }
+            return s;
+        }
+
+        public final long estimateSize() {
+            return (long)getEstimate();
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(TreeMap<K,V> tree,
+                       TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                       int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                s = ((e == null || e == f) ? null :      // empty
+                     (d == 0)              ? tree.root : // was top
+                     (d >  0)              ? e.right :   // was right
+                     (d <  0 && f != null) ? f.left :    // was left
+                     null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new KeySpliterator<>
+                    (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.key);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e.key);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
+        }
+
+        public final Comparator<? super K>  getComparator() {
+            return tree.comparator;
+        }
+
+    }
+
+    static final class DescendingKeySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<K> {
+        DescendingKeySpliterator(TreeMap<K,V> tree,
+                                 TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                                 int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public DescendingKeySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d <  0)              ? e.left :    // was left
+                         (d >  0 && f != null) ? f.right :   // was right
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) > 0) {       // e not already past s
+                side = 1;
+                return new DescendingKeySpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pr;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.key);
+                    if ((p = e.left) != null) {
+                        while ((pr = p.right) != null)
+                            p = pr;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.left)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = predecessor(e);
+            action.accept(e.key);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                Spliterator.DISTINCT | Spliterator.ORDERED;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+            extends TreeMapSpliterator<K,V>
+            implements Spliterator<V> {
+        ValueSpliterator(TreeMap<K,V> tree,
+                         TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                         int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d >  0)              ? e.right :   // was right
+                         (d <  0 && f != null) ? f.left :    // was left
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new ValueSpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e.value);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e.value);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) | Spliterator.ORDERED;
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends TreeMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(TreeMap<K,V> tree,
+                         TreeMapEntry<K,V> origin, TreeMapEntry<K,V> fence,
+                         int side, int est, int expectedModCount) {
+            super(tree, origin, fence, side, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            if (est < 0)
+                getEstimate(); // force initialization
+            int d = side;
+            TreeMapEntry<K,V> e = current, f = fence,
+                    s = ((e == null || e == f) ? null :      // empty
+                         (d == 0)              ? tree.root : // was top
+                         (d >  0)              ? e.right :   // was right
+                         (d <  0 && f != null) ? f.left :    // was left
+                         null);
+            if (s != null && s != e && s != f &&
+                tree.compare(e.key, s.key) < 0) {        // e not already past s
+                side = 1;
+                return new EntrySpliterator<>
+                        (tree, e, current = s, -1, est >>>= 1, expectedModCount);
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            TreeMapEntry<K,V> f = fence, e, p, pl;
+            if ((e = current) != null && e != f) {
+                current = f; // exhaust
+                do {
+                    action.accept(e);
+                    if ((p = e.right) != null) {
+                        while ((pl = p.left) != null)
+                            p = pl;
+                    }
+                    else {
+                        while ((p = e.parent) != null && e == p.right)
+                            e = p;
+                    }
+                } while ((e = p) != null && e != f);
+                if (tree.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            TreeMapEntry<K,V> e;
+            if (action == null)
+                throw new NullPointerException();
+            if (est < 0)
+                getEstimate(); // force initialization
+            if ((e = current) == null || e == fence)
+                return false;
+            current = successor(e);
+            action.accept(e);
+            if (tree.modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            return true;
+        }
+
+        public int characteristics() {
+            return (side == 0 ? Spliterator.SIZED : 0) |
+                    Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
+        }
+
+        @Override
+        public Comparator<Map.Entry<K, V>> getComparator() {
+            // Adapt or create a key-based comparator
+            if (tree.comparator != null) {
+                return Map.Entry.comparingByKey(tree.comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K, V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
+        }
+    }
+}
diff --git a/java/util/TreeSet.java b/java/util/TreeSet.java
new file mode 100644
index 0000000..54eeeda
--- /dev/null
+++ b/java/util/TreeSet.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * A {@link NavigableSet} implementation based on a {@link TreeMap}.
+ * The elements are ordered using their {@linkplain Comparable natural
+ * ordering}, or by a {@link Comparator} provided at set creation
+ * time, depending on which constructor is used.
+ *
+ * <p>This implementation provides guaranteed log(n) time cost for the basic
+ * operations ({@code add}, {@code remove} and {@code contains}).
+ *
+ * <p>Note that the ordering maintained by a set (whether or not an explicit
+ * comparator is provided) must be <i>consistent with equals</i> if it is to
+ * correctly implement the {@code Set} interface.  (See {@code Comparable}
+ * or {@code Comparator} for a precise definition of <i>consistent with
+ * equals</i>.)  This is so because the {@code Set} interface is defined in
+ * terms of the {@code equals} operation, but a {@code TreeSet} instance
+ * performs all element comparisons using its {@code compareTo} (or
+ * {@code compare}) method, so two elements that are deemed equal by this method
+ * are, from the standpoint of the set, equal.  The behavior of a set
+ * <i>is</i> well-defined even if its ordering is inconsistent with equals; it
+ * just fails to obey the general contract of the {@code Set} interface.
+ *
+ * <p><strong>Note that this implementation is not synchronized.</strong>
+ * If multiple threads access a tree set concurrently, and at least one
+ * of the threads modifies the set, it <i>must</i> be synchronized
+ * externally.  This is typically accomplished by synchronizing on some
+ * object that naturally encapsulates the set.
+ * If no such object exists, the set should be "wrapped" using the
+ * {@link Collections#synchronizedSortedSet Collections.synchronizedSortedSet}
+ * method.  This is best done at creation time, to prevent accidental
+ * unsynchronized access to the set: <pre>
+ *   SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));</pre>
+ *
+ * <p>The iterators returned by this class's {@code iterator} method are
+ * <i>fail-fast</i>: if the set is modified at any time after the iterator is
+ * created, in any way except through the iterator's own {@code remove}
+ * method, the iterator will throw a {@link ConcurrentModificationException}.
+ * Thus, in the face of concurrent modification, the iterator fails quickly
+ * and cleanly, rather than risking arbitrary, non-deterministic behavior at
+ * an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:   <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <E> the type of elements maintained by this set
+ *
+ * @author  Josh Bloch
+ * @see     Collection
+ * @see     Set
+ * @see     HashSet
+ * @see     Comparable
+ * @see     Comparator
+ * @see     TreeMap
+ * @since   1.2
+ */
+
+public class TreeSet<E> extends AbstractSet<E>
+    implements NavigableSet<E>, Cloneable, java.io.Serializable
+{
+    /**
+     * The backing map.
+     */
+    private transient NavigableMap<E,Object> m;
+
+    // Dummy value to associate with an Object in the backing Map
+    private static final Object PRESENT = new Object();
+
+    /**
+     * Constructs a set backed by the specified navigable map.
+     */
+    TreeSet(NavigableMap<E,Object> m) {
+        this.m = m;
+    }
+
+    /**
+     * Constructs a new, empty tree set, sorted according to the
+     * natural ordering of its elements.  All elements inserted into
+     * the set must implement the {@link Comparable} interface.
+     * Furthermore, all such elements must be <i>mutually
+     * comparable</i>: {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the set.  If the user attempts to add an element
+     * to the set that violates this constraint (for example, the user
+     * attempts to add a string element to a set whose elements are
+     * integers), the {@code add} call will throw a
+     * {@code ClassCastException}.
+     */
+    public TreeSet() {
+        this(new TreeMap<E,Object>());
+    }
+
+    /**
+     * Constructs a new, empty tree set, sorted according to the specified
+     * comparator.  All elements inserted into the set must be <i>mutually
+     * comparable</i> by the specified comparator: {@code comparator.compare(e1,
+     * e2)} must not throw a {@code ClassCastException} for any elements
+     * {@code e1} and {@code e2} in the set.  If the user attempts to add
+     * an element to the set that violates this constraint, the
+     * {@code add} call will throw a {@code ClassCastException}.
+     *
+     * @param comparator the comparator that will be used to order this set.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the elements will be used.
+     */
+    public TreeSet(Comparator<? super E> comparator) {
+        this(new TreeMap<>(comparator));
+    }
+
+    /**
+     * Constructs a new tree set containing the elements in the specified
+     * collection, sorted according to the <i>natural ordering</i> of its
+     * elements.  All elements inserted into the set must implement the
+     * {@link Comparable} interface.  Furthermore, all such elements must be
+     * <i>mutually comparable</i>: {@code e1.compareTo(e2)} must not throw a
+     * {@code ClassCastException} for any elements {@code e1} and
+     * {@code e2} in the set.
+     *
+     * @param c collection whose elements will comprise the new set
+     * @throws ClassCastException if the elements in {@code c} are
+     *         not {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified collection is null
+     */
+    public TreeSet(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new tree set containing the same elements and
+     * using the same ordering as the specified sorted set.
+     *
+     * @param s sorted set whose elements will comprise the new set
+     * @throws NullPointerException if the specified sorted set is null
+     */
+    public TreeSet(SortedSet<E> s) {
+        this(s.comparator());
+        addAll(s);
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in ascending order.
+     *
+     * @return an iterator over the elements in this set in ascending order
+     */
+    public Iterator<E> iterator() {
+        return m.navigableKeySet().iterator();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in descending order.
+     *
+     * @return an iterator over the elements in this set in descending order
+     * @since 1.6
+     */
+    public Iterator<E> descendingIterator() {
+        return m.descendingKeySet().iterator();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public NavigableSet<E> descendingSet() {
+        return new TreeSet<>(m.descendingMap());
+    }
+
+    /**
+     * Returns the number of elements in this set (its cardinality).
+     *
+     * @return the number of elements in this set (its cardinality)
+     */
+    public int size() {
+        return m.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return m.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o object to be checked for containment in this set
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in the set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean contains(Object o) {
+        return m.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that
+     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean add(E e) {
+        return m.put(e, PRESENT)==null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>,
+     * if this set contains such an element.  Returns {@code true} if
+     * this set contained the element (or equivalently, if this set
+     * changed as a result of the call).  (This set will not contain the
+     * element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if the specified object cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     */
+    public boolean remove(Object o) {
+        return m.remove(o)==PRESENT;
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        m.clear();
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set.
+     *
+     * @param c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the elements provided cannot be compared
+     *         with the elements currently in the set
+     * @throws NullPointerException if the specified collection is null or
+     *         if any element is null and this set uses natural ordering, or
+     *         its comparator does not permit null elements
+     */
+    public  boolean addAll(Collection<? extends E> c) {
+        // Use linear-time version if applicable
+        if (m.size()==0 && c.size() > 0 &&
+            c instanceof SortedSet &&
+            m instanceof TreeMap) {
+            SortedSet<? extends E> set = (SortedSet<? extends E>) c;
+            TreeMap<E,Object> map = (TreeMap<E, Object>) m;
+            Comparator<?> cc = set.comparator();
+            Comparator<? super E> mc = map.comparator();
+            if (cc==mc || (cc != null && cc.equals(mc))) {
+                map.addAllForTreeSet(set, PRESENT);
+                return true;
+            }
+        }
+        return super.addAll(c);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or {@code toElement}
+     *         is null and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
+                                  E toElement,   boolean toInclusive) {
+        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
+                                       toElement,   toInclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null and
+     *         this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return new TreeSet<>(m.headMap(toElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null and
+     *         this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.6
+     */
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return new TreeSet<>(m.tailMap(fromElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null and this set uses natural ordering,
+     *         or its comparator does not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> subSet(E fromElement, E toElement) {
+        return subSet(fromElement, true, toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     *         and this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> headSet(E toElement) {
+        return headSet(toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     *         and this set uses natural ordering, or its comparator does
+     *         not permit null elements
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public SortedSet<E> tailSet(E fromElement) {
+        return tailSet(fromElement, true);
+    }
+
+    public Comparator<? super E> comparator() {
+        return m.comparator();
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E first() {
+        return m.firstKey();
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E last() {
+        return m.lastKey();
+    }
+
+    // NavigableSet API methods
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E lower(E e) {
+        return m.lowerKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E floor(E e) {
+        return m.floorKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E ceiling(E e) {
+        return m.ceilingKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     *         and this set uses natural ordering, or its comparator
+     *         does not permit null elements
+     * @since 1.6
+     */
+    public E higher(E e) {
+        return m.higherKey(e);
+    }
+
+    /**
+     * @since 1.6
+     */
+    public E pollFirst() {
+        Map.Entry<E,?> e = m.pollFirstEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    /**
+     * @since 1.6
+     */
+    public E pollLast() {
+        Map.Entry<E,?> e = m.pollLastEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    /**
+     * Returns a shallow copy of this {@code TreeSet} instance. (The elements
+     * themselves are not cloned.)
+     *
+     * @return a shallow copy of this set
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        TreeSet<E> clone;
+        try {
+            clone = (TreeSet<E>) super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError(e);
+        }
+
+        clone.m = new TreeMap<>(m);
+        return clone;
+    }
+
+    /**
+     * Save the state of the {@code TreeSet} instance to a stream (that is,
+     * serialize it).
+     *
+     * @serialData Emits the comparator used to order this set, or
+     *             {@code null} if it obeys its elements' natural ordering
+     *             (Object), followed by the size of the set (the number of
+     *             elements it contains) (int), followed by all of its
+     *             elements (each an Object) in order (as determined by the
+     *             set's Comparator, or by the elements' natural ordering if
+     *             the set has no Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out Comparator
+        s.writeObject(m.comparator());
+
+        // Write out size
+        s.writeInt(m.size());
+
+        // Write out all elements in the proper order.
+        for (E e : m.keySet())
+            s.writeObject(e);
+    }
+
+    /**
+     * Reconstitute the {@code TreeSet} instance from a stream (that is,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in any hidden stuff
+        s.defaultReadObject();
+
+        // Read in Comparator
+        @SuppressWarnings("unchecked")
+            Comparator<? super E> c = (Comparator<? super E>) s.readObject();
+
+        // Create backing TreeMap
+        TreeMap<E,Object> tm = new TreeMap<>(c);
+        m = tm;
+
+        // Read in size
+        int size = s.readInt();
+
+        tm.readTreeSet(size, s, PRESENT);
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return TreeMap.keySpliteratorFor(m);
+    }
+
+    private static final long serialVersionUID = -2479143000061671589L;
+}
diff --git a/java/util/Tripwire.java b/java/util/Tripwire.java
new file mode 100644
index 0000000..d1bd39e
--- /dev/null
+++ b/java/util/Tripwire.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util;
+
+import sun.util.logging.PlatformLogger;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Utility class for detecting inadvertent uses of boxing in
+ * {@code java.util} classes.  The detection is turned on or off based on
+ * whether the system property {@code org.openjdk.java.util.stream.tripwire} is
+ * considered {@code true} according to {@link Boolean#getBoolean(String)}.
+ * This should normally be turned off for production use.
+ *
+ * @apiNote
+ * Typical usage would be for boxing code to do:
+ * <pre>{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling PrimitiveIterator.OfInt.nextInt()");
+ * }</pre>
+ *
+ * @since 1.8
+ */
+final class Tripwire {
+    private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
+
+    /** Should debugging checks be enabled? */
+    static final boolean ENABLED = AccessController.doPrivileged(
+            (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
+
+    private Tripwire() { }
+
+    /**
+     * Produces a log warning, using {@code PlatformLogger.getLogger(className)},
+     * using the supplied message.  The class name of {@code trippingClass} will
+     * be used as the first parameter to the message.
+     *
+     * @param trippingClass Name of the class generating the message
+     * @param msg A message format string of the type expected by
+     * {@link PlatformLogger}
+     */
+    static void trip(Class<?> trippingClass, String msg) {
+        PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
+    }
+}
diff --git a/java/util/UUID.java b/java/util/UUID.java
new file mode 100644
index 0000000..b4ea41f
--- /dev/null
+++ b/java/util/UUID.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.security.*;
+
+/**
+ * A class that represents an immutable universally unique identifier (UUID).
+ * A UUID represents a 128-bit value.
+ *
+ * <p> There exist different variants of these global identifiers.  The methods
+ * of this class are for manipulating the Leach-Salz variant, although the
+ * constructors allow the creation of any variant of UUID (described below).
+ *
+ * <p> The layout of a variant 2 (Leach-Salz) UUID is as follows:
+ *
+ * The most significant long consists of the following unsigned fields:
+ * <pre>
+ * 0xFFFFFFFF00000000 time_low
+ * 0x00000000FFFF0000 time_mid
+ * 0x000000000000F000 version
+ * 0x0000000000000FFF time_hi
+ * </pre>
+ * The least significant long consists of the following unsigned fields:
+ * <pre>
+ * 0xC000000000000000 variant
+ * 0x3FFF000000000000 clock_seq
+ * 0x0000FFFFFFFFFFFF node
+ * </pre>
+ *
+ * <p> The variant field contains a value which identifies the layout of the
+ * {@code UUID}.  The bit layout described above is valid only for a {@code
+ * UUID} with a variant value of 2, which indicates the Leach-Salz variant.
+ *
+ * <p> The version field holds a value that describes the type of this {@code
+ * UUID}.  There are four different basic types of UUIDs: time-based, DCE
+ * security, name-based, and randomly generated UUIDs.  These types have a
+ * version value of 1, 2, 3 and 4, respectively.
+ *
+ * <p> For more information including algorithms used to create {@code UUID}s,
+ * see <a href="http://www.ietf.org/rfc/rfc4122.txt"> <i>RFC&nbsp;4122: A
+ * Universally Unique IDentifier (UUID) URN Namespace</i></a>, section 4.2
+ * &quot;Algorithms for Creating a Time-Based UUID&quot;.
+ *
+ * @since   1.5
+ */
+public final class UUID implements java.io.Serializable, Comparable<UUID> {
+
+    /**
+     * Explicit serialVersionUID for interoperability.
+     */
+    private static final long serialVersionUID = -4856846361193249489L;
+
+    /*
+     * The most significant 64 bits of this UUID.
+     *
+     * @serial
+     */
+    private final long mostSigBits;
+
+    /*
+     * The least significant 64 bits of this UUID.
+     *
+     * @serial
+     */
+    private final long leastSigBits;
+
+    /*
+     * The random number generator used by this class to create random
+     * based UUIDs. In a holder class to defer initialization until needed.
+     */
+    private static class Holder {
+        static final SecureRandom numberGenerator = new SecureRandom();
+    }
+
+    // Constructors and Factories
+
+    /*
+     * Private constructor which uses a byte array to construct the new UUID.
+     */
+    private UUID(byte[] data) {
+        long msb = 0;
+        long lsb = 0;
+        assert data.length == 16 : "data must be 16 bytes in length";
+        for (int i=0; i<8; i++)
+            msb = (msb << 8) | (data[i] & 0xff);
+        for (int i=8; i<16; i++)
+            lsb = (lsb << 8) | (data[i] & 0xff);
+        this.mostSigBits = msb;
+        this.leastSigBits = lsb;
+    }
+
+    /**
+     * Constructs a new {@code UUID} using the specified data.  {@code
+     * mostSigBits} is used for the most significant 64 bits of the {@code
+     * UUID} and {@code leastSigBits} becomes the least significant 64 bits of
+     * the {@code UUID}.
+     *
+     * @param  mostSigBits
+     *         The most significant bits of the {@code UUID}
+     *
+     * @param  leastSigBits
+     *         The least significant bits of the {@code UUID}
+     */
+    public UUID(long mostSigBits, long leastSigBits) {
+        this.mostSigBits = mostSigBits;
+        this.leastSigBits = leastSigBits;
+    }
+
+    /**
+     * Static factory to retrieve a type 4 (pseudo randomly generated) UUID.
+     *
+     * The {@code UUID} is generated using a cryptographically strong pseudo
+     * random number generator.
+     *
+     * @return  A randomly generated {@code UUID}
+     */
+    public static UUID randomUUID() {
+        SecureRandom ng = Holder.numberGenerator;
+
+        byte[] randomBytes = new byte[16];
+        ng.nextBytes(randomBytes);
+        randomBytes[6]  &= 0x0f;  /* clear version        */
+        randomBytes[6]  |= 0x40;  /* set to version 4     */
+        randomBytes[8]  &= 0x3f;  /* clear variant        */
+        randomBytes[8]  |= 0x80;  /* set to IETF variant  */
+        return new UUID(randomBytes);
+    }
+
+    /**
+     * Static factory to retrieve a type 3 (name based) {@code UUID} based on
+     * the specified byte array.
+     *
+     * @param  name
+     *         A byte array to be used to construct a {@code UUID}
+     *
+     * @return  A {@code UUID} generated from the specified array
+     */
+    public static UUID nameUUIDFromBytes(byte[] name) {
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5");
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new InternalError("MD5 not supported", nsae);
+        }
+        byte[] md5Bytes = md.digest(name);
+        md5Bytes[6]  &= 0x0f;  /* clear version        */
+        md5Bytes[6]  |= 0x30;  /* set to version 3     */
+        md5Bytes[8]  &= 0x3f;  /* clear variant        */
+        md5Bytes[8]  |= 0x80;  /* set to IETF variant  */
+        return new UUID(md5Bytes);
+    }
+
+    /**
+     * Creates a {@code UUID} from the string standard representation as
+     * described in the {@link #toString} method.
+     *
+     * @param  name
+     *         A string that specifies a {@code UUID}
+     *
+     * @return  A {@code UUID} with the specified value
+     *
+     * @throws  IllegalArgumentException
+     *          If name does not conform to the string representation as
+     *          described in {@link #toString}
+     *
+     */
+    public static UUID fromString(String name) {
+        String[] components = name.split("-");
+        if (components.length != 5)
+            throw new IllegalArgumentException("Invalid UUID string: "+name);
+        for (int i=0; i<5; i++)
+            components[i] = "0x"+components[i];
+
+        long mostSigBits = Long.decode(components[0]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[1]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[2]).longValue();
+
+        long leastSigBits = Long.decode(components[3]).longValue();
+        leastSigBits <<= 48;
+        leastSigBits |= Long.decode(components[4]).longValue();
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    // Field Accessor Methods
+
+    /**
+     * Returns the least significant 64 bits of this UUID's 128 bit value.
+     *
+     * @return  The least significant 64 bits of this UUID's 128 bit value
+     */
+    public long getLeastSignificantBits() {
+        return leastSigBits;
+    }
+
+    /**
+     * Returns the most significant 64 bits of this UUID's 128 bit value.
+     *
+     * @return  The most significant 64 bits of this UUID's 128 bit value
+     */
+    public long getMostSignificantBits() {
+        return mostSigBits;
+    }
+
+    /**
+     * The version number associated with this {@code UUID}.  The version
+     * number describes how this {@code UUID} was generated.
+     *
+     * The version number has the following meaning:
+     * <ul>
+     * <li>1    Time-based UUID
+     * <li>2    DCE security UUID
+     * <li>3    Name-based UUID
+     * <li>4    Randomly generated UUID
+     * </ul>
+     *
+     * @return  The version number of this {@code UUID}
+     */
+    public int version() {
+        // Version is bits masked by 0x000000000000F000 in MS long
+        return (int)((mostSigBits >> 12) & 0x0f);
+    }
+
+    /**
+     * The variant number associated with this {@code UUID}.  The variant
+     * number describes the layout of the {@code UUID}.
+     *
+     * The variant number has the following meaning:
+     * <ul>
+     * <li>0    Reserved for NCS backward compatibility
+     * <li>2    <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>
+     * (Leach-Salz), used by this class
+     * <li>6    Reserved, Microsoft Corporation backward compatibility
+     * <li>7    Reserved for future definition
+     * </ul>
+     *
+     * @return  The variant number of this {@code UUID}
+     */
+    public int variant() {
+        // This field is composed of a varying number of bits.
+        // 0    -    -    Reserved for NCS backward compatibility
+        // 1    0    -    The IETF aka Leach-Salz variant (used by this class)
+        // 1    1    0    Reserved, Microsoft backward compatibility
+        // 1    1    1    Reserved for future definition.
+        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62)))
+                      & (leastSigBits >> 63));
+    }
+
+    /**
+     * The timestamp value associated with this UUID.
+     *
+     * <p> The 60 bit timestamp value is constructed from the time_low,
+     * time_mid, and time_hi fields of this {@code UUID}.  The resulting
+     * timestamp is measured in 100-nanosecond units since midnight,
+     * October 15, 1582 UTC.
+     *
+     * <p> The timestamp value is only meaningful in a time-based UUID, which
+     * has version type 1.  If this {@code UUID} is not a time-based UUID then
+     * this method throws UnsupportedOperationException.
+     *
+     * @throws UnsupportedOperationException
+     *         If this UUID is not a version 1 UUID
+     * @return The timestamp of this {@code UUID}.
+     */
+    public long timestamp() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return (mostSigBits & 0x0FFFL) << 48
+             | ((mostSigBits >> 16) & 0x0FFFFL) << 32
+             | mostSigBits >>> 32;
+    }
+
+    /**
+     * The clock sequence value associated with this UUID.
+     *
+     * <p> The 14 bit clock sequence value is constructed from the clock
+     * sequence field of this UUID.  The clock sequence field is used to
+     * guarantee temporal uniqueness in a time-based UUID.
+     *
+     * <p> The {@code clockSequence} value is only meaningful in a time-based
+     * UUID, which has version type 1.  If this UUID is not a time-based UUID
+     * then this method throws UnsupportedOperationException.
+     *
+     * @return  The clock sequence of this {@code UUID}
+     *
+     * @throws  UnsupportedOperationException
+     *          If this UUID is not a version 1 UUID
+     */
+    public int clockSequence() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return (int)((leastSigBits & 0x3FFF000000000000L) >>> 48);
+    }
+
+    /**
+     * The node value associated with this UUID.
+     *
+     * <p> The 48 bit node value is constructed from the node field of this
+     * UUID.  This field is intended to hold the IEEE 802 address of the machine
+     * that generated this UUID to guarantee spatial uniqueness.
+     *
+     * <p> The node value is only meaningful in a time-based UUID, which has
+     * version type 1.  If this UUID is not a time-based UUID then this method
+     * throws UnsupportedOperationException.
+     *
+     * @return  The node value of this {@code UUID}
+     *
+     * @throws  UnsupportedOperationException
+     *          If this UUID is not a version 1 UUID
+     */
+    public long node() {
+        if (version() != 1) {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+
+        return leastSigBits & 0x0000FFFFFFFFFFFFL;
+    }
+
+    // Object Inherited Methods
+
+    /**
+     * Returns a {@code String} object representing this {@code UUID}.
+     *
+     * <p> The UUID string representation is as described by this BNF:
+     * <blockquote><pre>
+     * {@code
+     * UUID                   = <time_low> "-" <time_mid> "-"
+     *                          <time_high_and_version> "-"
+     *                          <variant_and_sequence> "-"
+     *                          <node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               =
+     *       "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+     *       | "a" | "b" | "c" | "d" | "e" | "f"
+     *       | "A" | "B" | "C" | "D" | "E" | "F"
+     * }</pre></blockquote>
+     *
+     * @return  A string representation of this {@code UUID}
+     */
+    public String toString() {
+        return (digits(mostSigBits >> 32, 8) + "-" +
+                digits(mostSigBits >> 16, 4) + "-" +
+                digits(mostSigBits, 4) + "-" +
+                digits(leastSigBits >> 48, 4) + "-" +
+                digits(leastSigBits, 12));
+    }
+
+    /** Returns val represented by the specified number of hex digits. */
+    private static String digits(long val, int digits) {
+        long hi = 1L << (digits * 4);
+        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
+    }
+
+    /**
+     * Returns a hash code for this {@code UUID}.
+     *
+     * @return  A hash code value for this {@code UUID}
+     */
+    public int hashCode() {
+        long hilo = mostSigBits ^ leastSigBits;
+        return ((int)(hilo >> 32)) ^ (int) hilo;
+    }
+
+    /**
+     * Compares this object to the specified object.  The result is {@code
+     * true} if and only if the argument is not {@code null}, is a {@code UUID}
+     * object, has the same variant, and contains the same value, bit for bit,
+     * as this {@code UUID}.
+     *
+     * @param  obj
+     *         The object to be compared
+     *
+     * @return  {@code true} if the objects are the same; {@code false}
+     *          otherwise
+     */
+    public boolean equals(Object obj) {
+        if ((null == obj) || (obj.getClass() != UUID.class))
+            return false;
+        UUID id = (UUID)obj;
+        return (mostSigBits == id.mostSigBits &&
+                leastSigBits == id.leastSigBits);
+    }
+
+    // Comparison Operations
+
+    /**
+     * Compares this UUID with the specified UUID.
+     *
+     * <p> The first of two UUIDs is greater than the second if the most
+     * significant field in which the UUIDs differ is greater for the first
+     * UUID.
+     *
+     * @param  val
+     *         {@code UUID} to which this {@code UUID} is to be compared
+     *
+     * @return  -1, 0 or 1 as this {@code UUID} is less than, equal to, or
+     *          greater than {@code val}
+     *
+     */
+    public int compareTo(UUID val) {
+        // The ordering is intentionally set up so that the UUIDs
+        // can simply be numerically compared as two numbers
+        return (this.mostSigBits < val.mostSigBits ? -1 :
+                (this.mostSigBits > val.mostSigBits ? 1 :
+                 (this.leastSigBits < val.leastSigBits ? -1 :
+                  (this.leastSigBits > val.leastSigBits ? 1 :
+                   0))));
+    }
+}
diff --git a/java/util/UnknownFormatConversionException.java b/java/util/UnknownFormatConversionException.java
new file mode 100644
index 0000000..9ef964d
--- /dev/null
+++ b/java/util/UnknownFormatConversionException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an unknown conversion is given.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to
+ * any method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class UnknownFormatConversionException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19060418L;
+
+    private String s;
+
+    /**
+     * Constructs an instance of this class with the unknown conversion.
+     *
+     * @param  s
+     *         Unknown conversion
+     */
+    public UnknownFormatConversionException(String s) {
+        if (s == null)
+            throw new NullPointerException();
+        this.s = s;
+    }
+
+    /**
+     * Returns the unknown conversion.
+     *
+     * @return  The unknown conversion.
+     */
+    public String getConversion() {
+        return s;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return String.format("Conversion = '%s'", s);
+    }
+}
diff --git a/java/util/UnknownFormatFlagsException.java b/java/util/UnknownFormatFlagsException.java
new file mode 100644
index 0000000..764fe6d
--- /dev/null
+++ b/java/util/UnknownFormatFlagsException.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+/**
+ * Unchecked exception thrown when an unknown flag is given.
+ *
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
+ * method or constructor in this class will cause a {@link
+ * NullPointerException} to be thrown.
+ *
+ * @since 1.5
+ */
+public class UnknownFormatFlagsException extends IllegalFormatException {
+
+    private static final long serialVersionUID = 19370506L;
+
+    private String flags;
+
+    /**
+     * Constructs an instance of this class with the specified flags.
+     *
+     * @param  f
+     *         The set of format flags which contain an unknown flag
+     */
+    public UnknownFormatFlagsException(String f) {
+        if (f == null)
+            throw new NullPointerException();
+        this.flags = f;
+    }
+
+    /**
+     * Returns the set of flags which contains an unknown flag.
+     *
+     * @return  The flags
+     */
+    public String getFlags() {
+        return flags;
+    }
+
+    // javadoc inherited from Throwable.java
+    public String getMessage() {
+        return "Flags = " + flags;
+    }
+}
diff --git a/java/util/Vector.annotated.java b/java/util/Vector.annotated.java
new file mode 100644
index 0000000..09bb48c
--- /dev/null
+++ b/java/util/Vector.annotated.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Vector<E> extends java.util.AbstractList<E> implements java.util.List<E>, java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
+
+public Vector(int initialCapacity, int capacityIncrement) { throw new RuntimeException("Stub!"); }
+
+public Vector(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public Vector() { throw new RuntimeException("Stub!"); }
+
+public Vector(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized void copyInto([email protected] Object @libcore.util.NonNull [] anArray) { throw new RuntimeException("Stub!"); }
+
+public synchronized void trimToSize() { throw new RuntimeException("Stub!"); }
+
+public synchronized void ensureCapacity(int minCapacity) { throw new RuntimeException("Stub!"); }
+
+public synchronized void setSize(int newSize) { throw new RuntimeException("Stub!"); }
+
+public synchronized int capacity() { throw new RuntimeException("Stub!"); }
+
+public synchronized int size() { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Enumeration<@libcore.util.NullFromTypeParam E> elements() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public synchronized int indexOf(@libcore.util.Nullable java.lang.Object o, int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public synchronized int lastIndexOf(@libcore.util.Nullable java.lang.Object o, int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E elementAt(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E firstElement() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E lastElement() { throw new RuntimeException("Stub!"); }
+
+public synchronized void setElementAt(@libcore.util.NullFromTypeParam E obj, int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized void removeElementAt(int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized void insertElementAt(@libcore.util.NullFromTypeParam E obj, int index) { throw new RuntimeException("Stub!"); }
+
+public synchronized void addElement(@libcore.util.NullFromTypeParam E obj) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean removeElement(@libcore.util.Nullable java.lang.Object obj) { throw new RuntimeException("Stub!"); }
+
+public synchronized void removeAllElements() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public synchronized [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public synchronized <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public synchronized int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
+protected synchronized void removeRange(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public synchronized java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
+public synchronized void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+
+public synchronized boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public synchronized void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public synchronized void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
+protected int capacityIncrement;
+
+protected int elementCount;
+
+protected [email protected] Object @libcore.util.NonNull [] elementData;
+}
diff --git a/java/util/Vector.java b/java/util/Vector.java
new file mode 100644
index 0000000..f184437
--- /dev/null
+++ b/java/util/Vector.java
@@ -0,0 +1,1448 @@
+/*
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+/**
+ * The {@code Vector} class implements a growable array of
+ * objects. Like an array, it contains components that can be
+ * accessed using an integer index. However, the size of a
+ * {@code Vector} can grow or shrink as needed to accommodate
+ * adding and removing items after the {@code Vector} has been created.
+ *
+ * <p>Each vector tries to optimize storage management by maintaining a
+ * {@code capacity} and a {@code capacityIncrement}. The
+ * {@code capacity} is always at least as large as the vector
+ * size; it is usually larger because as components are added to the
+ * vector, the vector's storage increases in chunks the size of
+ * {@code capacityIncrement}. An application can increase the
+ * capacity of a vector before inserting a large number of
+ * components; this reduces the amount of incremental reallocation.
+ *
+ * <p><a name="fail-fast">
+ * The iterators returned by this class's {@link #iterator() iterator} and
+ * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em></a>:
+ * if the vector is structurally modified at any time after the iterator is
+ * created, in any way except through the iterator's own
+ * {@link ListIterator#remove() remove} or
+ * {@link ListIterator#add(Object) add} methods, the iterator will throw a
+ * {@link ConcurrentModificationException}.  Thus, in the face of
+ * concurrent modification, the iterator fails quickly and cleanly, rather
+ * than risking arbitrary, non-deterministic behavior at an undetermined
+ * time in the future.  The {@link Enumeration Enumerations} returned by
+ * the {@link #elements() elements} method are <em>not</em> fail-fast.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw {@code ConcurrentModificationException} on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:  <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>As of the Java 2 platform v1.2, this class was retrofitted to
+ * implement the {@link List} interface, making it a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.  Unlike the new collection
+ * implementations, {@code Vector} is synchronized.  If a thread-safe
+ * implementation is not needed, it is recommended to use {@link
+ * ArrayList} in place of {@code Vector}.
+ *
+ * @author  Lee Boynton
+ * @author  Jonathan Payne
+ * @see Collection
+ * @see LinkedList
+ * @since   JDK1.0
+ */
+public class Vector<E>
+    extends AbstractList<E>
+    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
+{
+    /**
+     * The array buffer into which the components of the vector are
+     * stored. The capacity of the vector is the length of this array buffer,
+     * and is at least large enough to contain all the vector's elements.
+     *
+     * <p>Any array elements following the last element in the Vector are null.
+     *
+     * @serial
+     */
+    protected Object[] elementData;
+
+    /**
+     * The number of valid components in this {@code Vector} object.
+     * Components {@code elementData[0]} through
+     * {@code elementData[elementCount-1]} are the actual items.
+     *
+     * @serial
+     */
+    protected int elementCount;
+
+    /**
+     * The amount by which the capacity of the vector is automatically
+     * incremented when its size becomes greater than its capacity.  If
+     * the capacity increment is less than or equal to zero, the capacity
+     * of the vector is doubled each time it needs to grow.
+     *
+     * @serial
+     */
+    protected int capacityIncrement;
+
+    /** use serialVersionUID from JDK 1.0.2 for interoperability */
+    private static final long serialVersionUID = -2767605614048989439L;
+
+    /**
+     * Constructs an empty vector with the specified initial capacity and
+     * capacity increment.
+     *
+     * @param   initialCapacity     the initial capacity of the vector
+     * @param   capacityIncrement   the amount by which the capacity is
+     *                              increased when the vector overflows
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public Vector(int initialCapacity, int capacityIncrement) {
+        super();
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+
+                                               initialCapacity);
+        this.elementData = new Object[initialCapacity];
+        this.capacityIncrement = capacityIncrement;
+    }
+
+    /**
+     * Constructs an empty vector with the specified initial capacity and
+     * with its capacity increment equal to zero.
+     *
+     * @param   initialCapacity   the initial capacity of the vector
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public Vector(int initialCapacity) {
+        this(initialCapacity, 0);
+    }
+
+    /**
+     * Constructs an empty vector so that its internal data array
+     * has size {@code 10} and its standard capacity increment is
+     * zero.
+     */
+    public Vector() {
+        this(10);
+    }
+
+    /**
+     * Constructs a vector containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection whose elements are to be placed into this
+     *       vector
+     * @throws NullPointerException if the specified collection is null
+     * @since   1.2
+     */
+    public Vector(Collection<? extends E> c) {
+        elementData = c.toArray();
+        elementCount = elementData.length;
+        // c.toArray might (incorrectly) not return Object[] (see 6260652)
+        if (elementData.getClass() != Object[].class)
+            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
+    }
+
+    /**
+     * Copies the components of this vector into the specified array.
+     * The item at index {@code k} in this vector is copied into
+     * component {@code k} of {@code anArray}.
+     *
+     * @param  anArray the array into which the components get copied
+     * @throws NullPointerException if the given array is null
+     * @throws IndexOutOfBoundsException if the specified array is not
+     *         large enough to hold all the components of this vector
+     * @throws ArrayStoreException if a component of this vector is not of
+     *         a runtime type that can be stored in the specified array
+     * @see #toArray(Object[])
+     */
+    public synchronized void copyInto(Object[] anArray) {
+        System.arraycopy(elementData, 0, anArray, 0, elementCount);
+    }
+
+    /**
+     * Trims the capacity of this vector to be the vector's current
+     * size. If the capacity of this vector is larger than its current
+     * size, then the capacity is changed to equal the size by replacing
+     * its internal data array, kept in the field {@code elementData},
+     * with a smaller one. An application can use this operation to
+     * minimize the storage of a vector.
+     */
+    public synchronized void trimToSize() {
+        modCount++;
+        int oldCapacity = elementData.length;
+        if (elementCount < oldCapacity) {
+            elementData = Arrays.copyOf(elementData, elementCount);
+        }
+    }
+
+    /**
+     * Increases the capacity of this vector, if necessary, to ensure
+     * that it can hold at least the number of components specified by
+     * the minimum capacity argument.
+     *
+     * <p>If the current capacity of this vector is less than
+     * {@code minCapacity}, then its capacity is increased by replacing its
+     * internal data array, kept in the field {@code elementData}, with a
+     * larger one.  The size of the new data array will be the old size plus
+     * {@code capacityIncrement}, unless the value of
+     * {@code capacityIncrement} is less than or equal to zero, in which case
+     * the new capacity will be twice the old capacity; but if this new size
+     * is still smaller than {@code minCapacity}, then the new capacity will
+     * be {@code minCapacity}.
+     *
+     * @param minCapacity the desired minimum capacity
+     */
+    public synchronized void ensureCapacity(int minCapacity) {
+        if (minCapacity > 0) {
+            modCount++;
+            ensureCapacityHelper(minCapacity);
+        }
+    }
+
+    /**
+     * This implements the unsynchronized semantics of ensureCapacity.
+     * Synchronized methods in this class can internally call this
+     * method for ensuring capacity without incurring the cost of an
+     * extra synchronization.
+     *
+     * @see #ensureCapacity(int)
+     */
+    private void ensureCapacityHelper(int minCapacity) {
+        // overflow-conscious code
+        if (minCapacity - elementData.length > 0)
+            grow(minCapacity);
+    }
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    private void grow(int minCapacity) {
+        // overflow-conscious code
+        int oldCapacity = elementData.length;
+        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
+                                         capacityIncrement : oldCapacity);
+        if (newCapacity - minCapacity < 0)
+            newCapacity = minCapacity;
+        if (newCapacity - MAX_ARRAY_SIZE > 0)
+            newCapacity = hugeCapacity(minCapacity);
+        elementData = Arrays.copyOf(elementData, newCapacity);
+    }
+
+    private static int hugeCapacity(int minCapacity) {
+        if (minCapacity < 0) // overflow
+            throw new OutOfMemoryError();
+        return (minCapacity > MAX_ARRAY_SIZE) ?
+            Integer.MAX_VALUE :
+            MAX_ARRAY_SIZE;
+    }
+
+    /**
+     * Sets the size of this vector. If the new size is greater than the
+     * current size, new {@code null} items are added to the end of
+     * the vector. If the new size is less than the current size, all
+     * components at index {@code newSize} and greater are discarded.
+     *
+     * @param  newSize   the new size of this vector
+     * @throws ArrayIndexOutOfBoundsException if the new size is negative
+     */
+    public synchronized void setSize(int newSize) {
+        modCount++;
+        if (newSize > elementCount) {
+            ensureCapacityHelper(newSize);
+        } else {
+            for (int i = newSize ; i < elementCount ; i++) {
+                elementData[i] = null;
+            }
+        }
+        elementCount = newSize;
+    }
+
+    /**
+     * Returns the current capacity of this vector.
+     *
+     * @return  the current capacity (the length of its internal
+     *          data array, kept in the field {@code elementData}
+     *          of this vector)
+     */
+    public synchronized int capacity() {
+        return elementData.length;
+    }
+
+    /**
+     * Returns the number of components in this vector.
+     *
+     * @return  the number of components in this vector
+     */
+    public synchronized int size() {
+        return elementCount;
+    }
+
+    /**
+     * Tests if this vector has no components.
+     *
+     * @return  {@code true} if and only if this vector has
+     *          no components, that is, its size is zero;
+     *          {@code false} otherwise.
+     */
+    public synchronized boolean isEmpty() {
+        return elementCount == 0;
+    }
+
+    /**
+     * Returns an enumeration of the components of this vector. The
+     * returned {@code Enumeration} object will generate all items in
+     * this vector. The first item generated is the item at index {@code 0},
+     * then the item at index {@code 1}, and so on.
+     *
+     * @return  an enumeration of the components of this vector
+     * @see     Iterator
+     */
+    public Enumeration<E> elements() {
+        return new Enumeration<E>() {
+            int count = 0;
+
+            public boolean hasMoreElements() {
+                return count < elementCount;
+            }
+
+            public E nextElement() {
+                synchronized (Vector.this) {
+                    if (count < elementCount) {
+                        return elementData(count++);
+                    }
+                }
+                throw new NoSuchElementException("Vector Enumeration");
+            }
+        };
+    }
+
+    /**
+     * Returns {@code true} if this vector contains the specified element.
+     * More formally, returns {@code true} if and only if this vector
+     * contains at least one element {@code e} such that
+     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
+     *
+     * @param o element whose presence in this vector is to be tested
+     * @return {@code true} if this vector contains the specified element
+     */
+    public boolean contains(Object o) {
+        return indexOf(o, 0) >= 0;
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element
+     * in this vector, or -1 if this vector does not contain the element.
+     * More formally, returns the lowest index {@code i} such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the first occurrence of the specified element in
+     *         this vector, or -1 if this vector does not contain the element
+     */
+    public int indexOf(Object o) {
+        return indexOf(o, 0);
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in
+     * this vector, searching forwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the lowest index {@code i} such that
+     * <tt>(i&nbsp;&gt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i))))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @param index index to start searching from
+     * @return the index of the first occurrence of the element in
+     *         this vector at position {@code index} or later in the vector;
+     *         {@code -1} if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     * @see     Object#equals(Object)
+     */
+    public synchronized int indexOf(Object o, int index) {
+        if (o == null) {
+            for (int i = index ; i < elementCount ; i++)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = index ; i < elementCount ; i++)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element
+     * in this vector, or -1 if this vector does not contain the element.
+     * More formally, returns the highest index {@code i} such that
+     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @return the index of the last occurrence of the specified element in
+     *         this vector, or -1 if this vector does not contain the element
+     */
+    public synchronized int lastIndexOf(Object o) {
+        return lastIndexOf(o, elementCount-1);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in
+     * this vector, searching backwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the highest index {@code i} such that
+     * <tt>(i&nbsp;&lt;=&nbsp;index&nbsp;&amp;&amp;&nbsp;(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i))))</tt>,
+     * or -1 if there is no such index.
+     *
+     * @param o element to search for
+     * @param index index to start searching backwards from
+     * @return the index of the last occurrence of the element at position
+     *         less than or equal to {@code index} in this vector;
+     *         -1 if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is greater
+     *         than or equal to the current size of this vector
+     */
+    public synchronized int lastIndexOf(Object o, int index) {
+        if (index >= elementCount)
+            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
+
+        if (o == null) {
+            for (int i = index; i >= 0; i--)
+                if (elementData[i]==null)
+                    return i;
+        } else {
+            for (int i = index; i >= 0; i--)
+                if (o.equals(elementData[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the component at the specified index.
+     *
+     * <p>This method is identical in functionality to the {@link #get(int)}
+     * method (which is part of the {@link List} interface).
+     *
+     * @param      index   an index into this vector
+     * @return     the component at the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized E elementAt(int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
+        }
+
+        return elementData(index);
+    }
+
+    /**
+     * Returns the first component (the item at index {@code 0}) of
+     * this vector.
+     *
+     * @return     the first component of this vector
+     * @throws NoSuchElementException if this vector has no components
+     */
+    public synchronized E firstElement() {
+        if (elementCount == 0) {
+            throw new NoSuchElementException();
+        }
+        return elementData(0);
+    }
+
+    /**
+     * Returns the last component of the vector.
+     *
+     * @return  the last component of the vector, i.e., the component at index
+     *          <code>size()&nbsp;-&nbsp;1</code>.
+     * @throws NoSuchElementException if this vector is empty
+     */
+    public synchronized E lastElement() {
+        if (elementCount == 0) {
+            throw new NoSuchElementException();
+        }
+        return elementData(elementCount - 1);
+    }
+
+    /**
+     * Sets the component at the specified {@code index} of this
+     * vector to be the specified object. The previous component at that
+     * position is discarded.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than the current size of the vector.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #set(int, Object) set(int, E)}
+     * method (which is part of the {@link List} interface). Note that the
+     * {@code set} method reverses the order of the parameters, to more closely
+     * match array usage.  Note also that the {@code set} method returns the
+     * old value that was stored at the specified position.
+     *
+     * @param      obj     what the component is to be set to
+     * @param      index   the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized void setElementAt(E obj, int index) {
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " +
+                                                     elementCount);
+        }
+        elementData[index] = obj;
+    }
+
+    /**
+     * Deletes the component at the specified index. Each component in
+     * this vector with an index greater or equal to the specified
+     * {@code index} is shifted downward to have an index one
+     * smaller than the value it had previously. The size of this vector
+     * is decreased by {@code 1}.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than the current size of the vector.
+     *
+     * <p>This method is identical in functionality to the {@link #remove(int)}
+     * method (which is part of the {@link List} interface).  Note that the
+     * {@code remove} method returns the old value that was stored at the
+     * specified position.
+     *
+     * @param      index   the index of the object to remove
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     */
+    public synchronized void removeElementAt(int index) {
+        modCount++;
+        if (index >= elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index + " >= " +
+                                                     elementCount);
+        }
+        else if (index < 0) {
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+        int j = elementCount - index - 1;
+        if (j > 0) {
+            System.arraycopy(elementData, index + 1, elementData, index, j);
+        }
+        elementCount--;
+        elementData[elementCount] = null; /* to let gc do its work */
+    }
+
+    /**
+     * Inserts the specified object as a component in this vector at the
+     * specified {@code index}. Each component in this vector with
+     * an index greater or equal to the specified {@code index} is
+     * shifted upward to have an index one greater than the value it had
+     * previously.
+     *
+     * <p>The index must be a value greater than or equal to {@code 0}
+     * and less than or equal to the current size of the vector. (If the
+     * index is equal to the current size of the vector, the new element
+     * is appended to the Vector.)
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #add(int, Object) add(int, E)}
+     * method (which is part of the {@link List} interface).  Note that the
+     * {@code add} method reverses the order of the parameters, to more closely
+     * match array usage.
+     *
+     * @param      obj     the component to insert
+     * @param      index   where to insert the new component
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     */
+    public synchronized void insertElementAt(E obj, int index) {
+        modCount++;
+        if (index > elementCount) {
+            throw new ArrayIndexOutOfBoundsException(index
+                                                     + " > " + elementCount);
+        }
+        ensureCapacityHelper(elementCount + 1);
+        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
+        elementData[index] = obj;
+        elementCount++;
+    }
+
+    /**
+     * Adds the specified component to the end of this vector,
+     * increasing its size by one. The capacity of this vector is
+     * increased if its size becomes greater than its capacity.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #add(Object) add(E)}
+     * method (which is part of the {@link List} interface).
+     *
+     * @param   obj   the component to be added
+     */
+    public synchronized void addElement(E obj) {
+        modCount++;
+        ensureCapacityHelper(elementCount + 1);
+        elementData[elementCount++] = obj;
+    }
+
+    /**
+     * Removes the first (lowest-indexed) occurrence of the argument
+     * from this vector. If the object is found in this vector, each
+     * component in the vector with an index greater or equal to the
+     * object's index is shifted downward to have an index one smaller
+     * than the value it had previously.
+     *
+     * <p>This method is identical in functionality to the
+     * {@link #remove(Object)} method (which is part of the
+     * {@link List} interface).
+     *
+     * @param   obj   the component to be removed
+     * @return  {@code true} if the argument was a component of this
+     *          vector; {@code false} otherwise.
+     */
+    public synchronized boolean removeElement(Object obj) {
+        modCount++;
+        int i = indexOf(obj);
+        if (i >= 0) {
+            removeElementAt(i);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Removes all components from this vector and sets its size to zero.
+     *
+     * <p>This method is identical in functionality to the {@link #clear}
+     * method (which is part of the {@link List} interface).
+     */
+    public synchronized void removeAllElements() {
+        modCount++;
+        // Let gc do its work
+        for (int i = 0; i < elementCount; i++)
+            elementData[i] = null;
+
+        elementCount = 0;
+    }
+
+    /**
+     * Returns a clone of this vector. The copy will contain a
+     * reference to a clone of the internal data array, not a reference
+     * to the original internal data array of this {@code Vector} object.
+     *
+     * @return  a clone of this vector
+     */
+    public synchronized Object clone() {
+        try {
+            @SuppressWarnings("unchecked")
+                Vector<E> v = (Vector<E>) super.clone();
+            v.elementData = Arrays.copyOf(elementData, elementCount);
+            v.modCount = 0;
+            return v;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this Vector
+     * in the correct order.
+     *
+     * @since 1.2
+     */
+    public synchronized Object[] toArray() {
+        return Arrays.copyOf(elementData, elementCount);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this Vector in the
+     * correct order; the runtime type of the returned array is that of the
+     * specified array.  If the Vector fits in the specified array, it is
+     * returned therein.  Otherwise, a new array is allocated with the runtime
+     * type of the specified array and the size of this Vector.
+     *
+     * <p>If the Vector fits in the specified array with room to spare
+     * (i.e., the array has more elements than the Vector),
+     * the element in the array immediately following the end of the
+     * Vector is set to null.  (This is useful in determining the length
+     * of the Vector <em>only</em> if the caller knows that the Vector
+     * does not contain any null elements.)
+     *
+     * @param a the array into which the elements of the Vector are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing the elements of the Vector
+     * @throws ArrayStoreException if the runtime type of a is not a supertype
+     * of the runtime type of every element in this Vector
+     * @throws NullPointerException if the given array is null
+     * @since 1.2
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized <T> T[] toArray(T[] a) {
+        if (a.length < elementCount)
+            return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
+
+        System.arraycopy(elementData, 0, a, 0, elementCount);
+
+        if (a.length > elementCount)
+            a[elementCount] = null;
+
+        return a;
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    E elementData(int index) {
+        return (E) elementData[index];
+    }
+
+    /**
+     * Returns the element at the specified position in this Vector.
+     *
+     * @param index index of the element to return
+     * @return object at the specified index
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *            ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E get(int index) {
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        return elementData(index);
+    }
+
+    /**
+     * Replaces the element at the specified position in this Vector with the
+     * specified element.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     * @since 1.2
+     */
+    public synchronized E set(int index, E element) {
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        E oldValue = elementData(index);
+        elementData[index] = element;
+        return oldValue;
+    }
+
+    /**
+     * Appends the specified element to the end of this Vector.
+     *
+     * @param e element to be appended to this Vector
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @since 1.2
+     */
+    public synchronized boolean add(E e) {
+        modCount++;
+        ensureCapacityHelper(elementCount + 1);
+        elementData[elementCount++] = e;
+        return true;
+    }
+
+    /**
+     * Removes the first occurrence of the specified element in this Vector
+     * If the Vector does not contain the element, it is unchanged.  More
+     * formally, removes the element with the lowest index i such that
+     * {@code (o==null ? get(i)==null : o.equals(get(i)))} (if such
+     * an element exists).
+     *
+     * @param o element to be removed from this Vector, if present
+     * @return true if the Vector contained the specified element
+     * @since 1.2
+     */
+    public boolean remove(Object o) {
+        return removeElement(o);
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this Vector.
+     * Shifts the element currently at that position (if any) and any
+     * subsequent elements to the right (adds one to their indices).
+     *
+     * @param index index at which the specified element is to be inserted
+     * @param element element to be inserted
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     * @since 1.2
+     */
+    public void add(int index, E element) {
+        insertElementAt(element, index);
+    }
+
+    /**
+     * Removes the element at the specified position in this Vector.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).  Returns the element that was removed from the Vector.
+     *
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index >= size()})
+     * @param index the index of the element to be removed
+     * @return element that was removed
+     * @since 1.2
+     */
+    public synchronized E remove(int index) {
+        modCount++;
+        if (index >= elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+        E oldValue = elementData(index);
+
+        int numMoved = elementCount - index - 1;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index+1, elementData, index,
+                             numMoved);
+        elementData[--elementCount] = null; // Let gc do its work
+
+        return oldValue;
+    }
+
+    /**
+     * Removes all of the elements from this Vector.  The Vector will
+     * be empty after this call returns (unless it throws an exception).
+     *
+     * @since 1.2
+     */
+    public void clear() {
+        removeAllElements();
+    }
+
+    // Bulk Operations
+
+    /**
+     * Returns true if this Vector contains all of the elements in the
+     * specified Collection.
+     *
+     * @param   c a collection whose elements will be tested for containment
+     *          in this Vector
+     * @return true if this Vector contains all of the elements in the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     */
+    public synchronized boolean containsAll(Collection<?> c) {
+        return super.containsAll(c);
+    }
+
+    /**
+     * Appends all of the elements in the specified Collection to the end of
+     * this Vector, in the order that they are returned by the specified
+     * Collection's Iterator.  The behavior of this operation is undefined if
+     * the specified Collection is modified while the operation is in progress.
+     * (This implies that the behavior of this call is undefined if the
+     * specified Collection is this Vector, and this Vector is nonempty.)
+     *
+     * @param c elements to be inserted into this Vector
+     * @return {@code true} if this Vector changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean addAll(Collection<? extends E> c) {
+        modCount++;
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityHelper(elementCount + numNew);
+        System.arraycopy(a, 0, elementData, elementCount, numNew);
+        elementCount += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Removes from this Vector all of its elements that are contained in the
+     * specified Collection.
+     *
+     * @param c a collection of elements to be removed from the Vector
+     * @return true if this Vector changed as a result of the call
+     * @throws ClassCastException if the types of one or more elements
+     *         in this vector are incompatible with the specified
+     *         collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this vector contains one or more null
+     *         elements and the specified collection does not support null
+     *         elements
+     * (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean removeAll(Collection<?> c) {
+        return super.removeAll(c);
+    }
+
+    /**
+     * Retains only the elements in this Vector that are contained in the
+     * specified Collection.  In other words, removes from this Vector all
+     * of its elements that are not contained in the specified Collection.
+     *
+     * @param c a collection of elements to be retained in this Vector
+     *          (all other elements are removed)
+     * @return true if this Vector changed as a result of the call
+     * @throws ClassCastException if the types of one or more elements
+     *         in this vector are incompatible with the specified
+     *         collection
+     * (<a href="Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this vector contains one or more null
+     *         elements and the specified collection does not support null
+     *         elements
+     *         (<a href="Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean retainAll(Collection<?> c) {
+        return super.retainAll(c);
+    }
+
+    /**
+     * Inserts all of the elements in the specified Collection into this
+     * Vector at the specified position.  Shifts the element currently at
+     * that position (if any) and any subsequent elements to the right
+     * (increases their indices).  The new elements will appear in the Vector
+     * in the order that they are returned by the specified Collection's
+     * iterator.
+     *
+     * @param index index at which to insert the first element from the
+     *              specified collection
+     * @param c elements to be inserted into this Vector
+     * @return {@code true} if this Vector changed as a result of the call
+     * @throws ArrayIndexOutOfBoundsException if the index is out of range
+     *         ({@code index < 0 || index > size()})
+     * @throws NullPointerException if the specified collection is null
+     * @since 1.2
+     */
+    public synchronized boolean addAll(int index, Collection<? extends E> c) {
+        modCount++;
+        if (index < 0 || index > elementCount)
+            throw new ArrayIndexOutOfBoundsException(index);
+
+        Object[] a = c.toArray();
+        int numNew = a.length;
+        ensureCapacityHelper(elementCount + numNew);
+
+        int numMoved = elementCount - index;
+        if (numMoved > 0)
+            System.arraycopy(elementData, index, elementData, index + numNew,
+                             numMoved);
+
+        System.arraycopy(a, 0, elementData, index, numNew);
+        elementCount += numNew;
+        return numNew != 0;
+    }
+
+    /**
+     * Compares the specified Object with this Vector for equality.  Returns
+     * true if and only if the specified Object is also a List, both Lists
+     * have the same size, and all corresponding pairs of elements in the two
+     * Lists are <em>equal</em>.  (Two elements {@code e1} and
+     * {@code e2} are <em>equal</em> if {@code (e1==null ? e2==null :
+     * e1.equals(e2))}.)  In other words, two Lists are defined to be
+     * equal if they contain the same elements in the same order.
+     *
+     * @param o the Object to be compared for equality with this Vector
+     * @return true if the specified Object is equal to this Vector
+     */
+    public synchronized boolean equals(Object o) {
+        return super.equals(o);
+    }
+
+    /**
+     * Returns the hash code value for this Vector.
+     */
+    public synchronized int hashCode() {
+        return super.hashCode();
+    }
+
+    /**
+     * Returns a string representation of this Vector, containing
+     * the String representation of each element.
+     */
+    public synchronized String toString() {
+        return super.toString();
+    }
+
+    /**
+     * Returns a view of the portion of this List between fromIndex,
+     * inclusive, and toIndex, exclusive.  (If fromIndex and toIndex are
+     * equal, the returned List is empty.)  The returned List is backed by this
+     * List, so changes in the returned List are reflected in this List, and
+     * vice-versa.  The returned List supports all of the optional List
+     * operations supported by this List.
+     *
+     * <p>This method eliminates the need for explicit range operations (of
+     * the sort that commonly exist for arrays).  Any operation that expects
+     * a List can be used as a range operation by operating on a subList view
+     * instead of a whole List.  For example, the following idiom
+     * removes a range of elements from a List:
+     * <pre>
+     *      list.subList(from, to).clear();
+     * </pre>
+     * Similar idioms may be constructed for indexOf and lastIndexOf,
+     * and all of the algorithms in the Collections class can be applied to
+     * a subList.
+     *
+     * <p>The semantics of the List returned by this method become undefined if
+     * the backing list (i.e., this List) is <i>structurally modified</i> in
+     * any way other than via the returned List.  (Structural modifications are
+     * those that change the size of the List, or otherwise perturb it in such
+     * a fashion that iterations in progress may yield incorrect results.)
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this List
+     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
+     *         {@code (fromIndex < 0 || toIndex > size)}
+     * @throws IllegalArgumentException if the endpoint indices are out of order
+     *         {@code (fromIndex > toIndex)}
+     */
+    public synchronized List<E> subList(int fromIndex, int toIndex) {
+        return Collections.synchronizedList(super.subList(fromIndex, toIndex),
+                                            this);
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     */
+    protected synchronized void removeRange(int fromIndex, int toIndex) {
+        modCount++;
+        int numMoved = elementCount - toIndex;
+        System.arraycopy(elementData, toIndex, elementData, fromIndex,
+                         numMoved);
+
+        // Let gc do its work
+        int newElementCount = elementCount - (toIndex-fromIndex);
+        while (elementCount != newElementCount)
+            elementData[--elementCount] = null;
+    }
+
+    /**
+     * Save the state of the {@code Vector} instance to a stream (that
+     * is, serialize it).
+     * This method performs synchronization to ensure the consistency
+     * of the serialized data.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+            throws java.io.IOException {
+        final java.io.ObjectOutputStream.PutField fields = s.putFields();
+        final Object[] data;
+        synchronized (this) {
+            fields.put("capacityIncrement", capacityIncrement);
+            fields.put("elementCount", elementCount);
+            data = elementData.clone();
+        }
+        fields.put("elementData", data);
+        s.writeFields();
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence), starting at the specified position in the list.
+     * The specified index indicates the first element that would be
+     * returned by an initial call to {@link ListIterator#next next}.
+     * An initial call to {@link ListIterator#previous previous} would
+     * return the element with the specified index minus one.
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public synchronized ListIterator<E> listIterator(int index) {
+        if (index < 0 || index > elementCount)
+            throw new IndexOutOfBoundsException("Index: "+index);
+        return new ListItr(index);
+    }
+
+    /**
+     * Returns a list iterator over the elements in this list (in proper
+     * sequence).
+     *
+     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @see #listIterator(int)
+     */
+    public synchronized ListIterator<E> listIterator() {
+        return new ListItr(0);
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public synchronized Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * An optimized version of AbstractList.Itr
+     */
+    private class Itr implements Iterator<E> {
+        // Android-added: Change CME behavior: Use added limit field, not elementCount.
+        // http://b/27430229 AOSP commit 6e5b758a4438d2c154dd11a5c04d14a5d2fc907c
+        //
+        // The "limit" of this iterator. This is the size of the list at the time the
+        // iterator was created. Adding & removing elements will invalidate the iteration
+        // anyway (and cause next() to throw) so saving this value will guarantee that the
+        // value of hasNext() remains stable and won't flap between true and false when elements
+        // are added and removed from the list.
+        protected int limit = Vector.this.elementCount;
+
+        int cursor;       // index of next element to return
+        int lastRet = -1; // index of last element returned; -1 if no such
+        int expectedModCount = modCount;
+
+        public boolean hasNext() {
+            // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+            // return cursor != elementCount;
+            return cursor < limit;
+        }
+
+        public E next() {
+            synchronized (Vector.this) {
+                checkForComodification();
+                int i = cursor;
+                // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+                // if (i >= elementCount)
+                if (i >= limit)
+                    throw new NoSuchElementException();
+                cursor = i + 1;
+                return elementData(lastRet = i);
+            }
+        }
+
+        public void remove() {
+            if (lastRet == -1)
+                throw new IllegalStateException();
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.remove(lastRet);
+                expectedModCount = modCount;
+                // Android-added: Change CME behavior: Use added limit field, not elementCount.
+                limit--;
+            }
+            cursor = lastRet;
+            lastRet = -1;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            synchronized (Vector.this) {
+                // Android-changed: Change CME behavior: Use added limit field, not elementCount.
+                // final int size = elementCount;
+                final int size = limit;
+                int i = cursor;
+                if (i >= size) {
+                    return;
+                }
+        @SuppressWarnings("unchecked")
+                final E[] elementData = (E[]) Vector.this.elementData;
+                if (i >= elementData.length) {
+                    throw new ConcurrentModificationException();
+                }
+                while (i != size && modCount == expectedModCount) {
+                    action.accept(elementData[i++]);
+                }
+                // update once at end of iteration to reduce heap write traffic
+                cursor = i;
+                lastRet = i - 1;
+                checkForComodification();
+            }
+        }
+
+        final void checkForComodification() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * An optimized version of AbstractList.ListItr
+     */
+    final class ListItr extends Itr implements ListIterator<E> {
+        ListItr(int index) {
+            super();
+            cursor = index;
+        }
+
+        public boolean hasPrevious() {
+            return cursor != 0;
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor - 1;
+        }
+
+        public E previous() {
+            synchronized (Vector.this) {
+                checkForComodification();
+                int i = cursor - 1;
+                if (i < 0)
+                    throw new NoSuchElementException();
+                cursor = i;
+                return elementData(lastRet = i);
+            }
+        }
+
+        public void set(E e) {
+            if (lastRet == -1)
+                throw new IllegalStateException();
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.set(lastRet, e);
+            }
+        }
+
+        public void add(E e) {
+            int i = cursor;
+            synchronized (Vector.this) {
+                checkForComodification();
+                Vector.this.add(i, e);
+                expectedModCount = modCount;
+                // Android-added: Change CME behavior: Use added limit field, not elementCount.
+                limit++;
+            }
+            cursor = i + 1;
+            lastRet = -1;
+        }
+    }
+
+    @Override
+    public synchronized void forEach(Consumer<? super E> action) {
+        Objects.requireNonNull(action);
+        final int expectedModCount = modCount;
+        @SuppressWarnings("unchecked")
+        final E[] elementData = (E[]) this.elementData;
+        final int elementCount = this.elementCount;
+        for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
+            action.accept(elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public synchronized boolean removeIf(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        // figure out which elements are to be removed
+        // any exception thrown from the filter predicate at this stage
+        // will leave the collection unmodified
+        int removeCount = 0;
+        final int size = elementCount;
+        final BitSet removeSet = new BitSet(size);
+        final int expectedModCount = modCount;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            @SuppressWarnings("unchecked")
+            final E element = (E) elementData[i];
+            if (filter.test(element)) {
+                removeSet.set(i);
+                removeCount++;
+            }
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+
+        // shift surviving elements left over the spaces left by removed elements
+        final boolean anyToRemove = removeCount > 0;
+        if (anyToRemove) {
+            final int newSize = size - removeCount;
+            for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
+                i = removeSet.nextClearBit(i);
+                elementData[j] = elementData[i];
+            }
+            for (int k=newSize; k < size; k++) {
+                elementData[k] = null;  // Let gc do its work
+            }
+            elementCount = newSize;
+            if (modCount != expectedModCount) {
+                throw new ConcurrentModificationException();
+            }
+            modCount++;
+        }
+
+        return anyToRemove;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public synchronized void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final int expectedModCount = modCount;
+        final int size = elementCount;
+        for (int i=0; modCount == expectedModCount && i < size; i++) {
+            elementData[i] = operator.apply((E) elementData[i]);
+        }
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized void sort(Comparator<? super E> c) {
+        final int expectedModCount = modCount;
+        Arrays.sort((E[]) elementData, 0, elementCount, c);
+        if (modCount != expectedModCount) {
+            throw new ConcurrentModificationException();
+        }
+        modCount++;
+    }
+
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new VectorSpliterator<>(this, null, 0, -1, 0);
+    }
+
+    /** Similar to ArrayList Spliterator */
+    static final class VectorSpliterator<E> implements Spliterator<E> {
+        private final Vector<E> list;
+        private Object[] array;
+        private int index; // current index, modified on advance/split
+        private int fence; // -1 until used; then one past last index
+        private int expectedModCount; // initialized when fence set
+
+        /** Create new spliterator covering the given  range */
+        VectorSpliterator(Vector<E> list, Object[] array, int origin, int fence,
+                          int expectedModCount) {
+            this.list = list;
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.expectedModCount = expectedModCount;
+        }
+
+        private int getFence() { // initialize on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                synchronized(list) {
+                    array = list.elementData;
+                    expectedModCount = list.modCount;
+                    hi = fence = list.elementCount;
+                }
+            }
+            return hi;
+        }
+
+        public Spliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new VectorSpliterator<E>(list, array, lo, index = mid,
+                                         expectedModCount);
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super E> action) {
+            int i;
+            if (action == null)
+                throw new NullPointerException();
+            if (getFence() > (i = index)) {
+                index = i + 1;
+                action.accept((E)array[i]);
+                if (list.modCount != expectedModCount)
+                    throw new ConcurrentModificationException();
+                return true;
+            }
+            return false;
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            int i, hi; // hoist accesses and checks from loop
+            Vector<E> lst; Object[] a;
+            if (action == null)
+                throw new NullPointerException();
+            if ((lst = list) != null) {
+                if ((hi = fence) < 0) {
+                    synchronized(lst) {
+                        expectedModCount = lst.modCount;
+                        a = array = lst.elementData;
+                        hi = fence = lst.elementCount;
+                    }
+                }
+                else
+                    a = array;
+                if (a != null && (i = index) >= 0 && (index = hi) <= a.length) {
+                    while (i < hi)
+                        action.accept((E) a[i++]);
+                    if (lst.modCount == expectedModCount)
+                        return;
+                }
+            }
+            throw new ConcurrentModificationException();
+        }
+
+        public long estimateSize() {
+            return (long) (getFence() - index);
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+}
diff --git a/java/util/WeakHashMap.annotated.java b/java/util/WeakHashMap.annotated.java
new file mode 100644
index 0000000..83ae1cb
--- /dev/null
+++ b/java/util/WeakHashMap.annotated.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util;
+
+import java.lang.ref.WeakReference;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class WeakHashMap<K, V> extends java.util.AbstractMap<K,V> implements java.util.Map<K,V> {
+
+public WeakHashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+public WeakHashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+public WeakHashMap() { throw new RuntimeException("Stub!"); }
+
+public WeakHashMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
[email protected] public V get(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public boolean containsKey(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
[email protected] public V put(@libcore.util.NullFromTypeParam K key, @libcore.util.NullFromTypeParam V value) { throw new RuntimeException("Stub!"); }
+
+public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NullFromTypeParam K,? extends @libcore.util.NullFromTypeParam V> m) { throw new RuntimeException("Stub!"); }
+
[email protected] public V remove(@libcore.util.Nullable java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean containsValue(@libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<@libcore.util.NullFromTypeParam K> keySet() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Collection<@libcore.util.NullFromTypeParam V> values() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Set<[email protected] Entry<@libcore.util.NullFromTypeParam K, @libcore.util.NullFromTypeParam V>> entrySet() { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V> action) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NullFromTypeParam K,? super @libcore.util.NullFromTypeParam V,? extends @libcore.util.NullFromTypeParam V> function) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/WeakHashMap.java b/java/util/WeakHashMap.java
new file mode 100644
index 0000000..7352391
--- /dev/null
+++ b/java/util/WeakHashMap.java
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.lang.ref.WeakReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+
+
+/**
+ * Hash table based implementation of the <tt>Map</tt> interface, with
+ * <em>weak keys</em>.
+ * An entry in a <tt>WeakHashMap</tt> will automatically be removed when
+ * its key is no longer in ordinary use.  More precisely, the presence of a
+ * mapping for a given key will not prevent the key from being discarded by the
+ * garbage collector, that is, made finalizable, finalized, and then reclaimed.
+ * When a key has been discarded its entry is effectively removed from the map,
+ * so this class behaves somewhat differently from other <tt>Map</tt>
+ * implementations.
+ *
+ * <p> Both null values and the null key are supported. This class has
+ * performance characteristics similar to those of the <tt>HashMap</tt>
+ * class, and has the same efficiency parameters of <em>initial capacity</em>
+ * and <em>load factor</em>.
+ *
+ * <p> Like most collection classes, this class is not synchronized.
+ * A synchronized <tt>WeakHashMap</tt> may be constructed using the
+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
+ * method.
+ *
+ * <p> This class is intended primarily for use with key objects whose
+ * <tt>equals</tt> methods test for object identity using the
+ * <tt>==</tt> operator.  Once such a key is discarded it can never be
+ * recreated, so it is impossible to do a lookup of that key in a
+ * <tt>WeakHashMap</tt> at some later time and be surprised that its entry
+ * has been removed.  This class will work perfectly well with key objects
+ * whose <tt>equals</tt> methods are not based upon object identity, such
+ * as <tt>String</tt> instances.  With such recreatable key objects,
+ * however, the automatic removal of <tt>WeakHashMap</tt> entries whose
+ * keys have been discarded may prove to be confusing.
+ *
+ * <p> The behavior of the <tt>WeakHashMap</tt> class depends in part upon
+ * the actions of the garbage collector, so several familiar (though not
+ * required) <tt>Map</tt> invariants do not hold for this class.  Because
+ * the garbage collector may discard keys at any time, a
+ * <tt>WeakHashMap</tt> may behave as though an unknown thread is silently
+ * removing entries.  In particular, even if you synchronize on a
+ * <tt>WeakHashMap</tt> instance and invoke none of its mutator methods, it
+ * is possible for the <tt>size</tt> method to return smaller values over
+ * time, for the <tt>isEmpty</tt> method to return <tt>false</tt> and
+ * then <tt>true</tt>, for the <tt>containsKey</tt> method to return
+ * <tt>true</tt> and later <tt>false</tt> for a given key, for the
+ * <tt>get</tt> method to return a value for a given key but later return
+ * <tt>null</tt>, for the <tt>put</tt> method to return
+ * <tt>null</tt> and the <tt>remove</tt> method to return
+ * <tt>false</tt> for a key that previously appeared to be in the map, and
+ * for successive examinations of the key set, the value collection, and
+ * the entry set to yield successively smaller numbers of elements.
+ *
+ * <p> Each key object in a <tt>WeakHashMap</tt> is stored indirectly as
+ * the referent of a weak reference.  Therefore a key will automatically be
+ * removed only after the weak references to it, both inside and outside of the
+ * map, have been cleared by the garbage collector.
+ *
+ * <p> <strong>Implementation note:</strong> The value objects in a
+ * <tt>WeakHashMap</tt> are held by ordinary strong references.  Thus care
+ * should be taken to ensure that value objects do not strongly refer to their
+ * own keys, either directly or indirectly, since that will prevent the keys
+ * from being discarded.  Note that a value object may refer indirectly to its
+ * key via the <tt>WeakHashMap</tt> itself; that is, a value object may
+ * strongly refer to some other key object whose associated value object, in
+ * turn, strongly refers to the key of the first value object.  If the values
+ * in the map do not rely on the map holding strong references to them, one way
+ * to deal with this is to wrap values themselves within
+ * <tt>WeakReferences</tt> before
+ * inserting, as in: <tt>m.put(key, new WeakReference(value))</tt>,
+ * and then unwrapping upon each <tt>get</tt>.
+ *
+ * <p>The iterators returned by the <tt>iterator</tt> method of the collections
+ * returned by all of this class's "collection view methods" are
+ * <i>fail-fast</i>: if the map is structurally modified at any time after the
+ * iterator is created, in any way except through the iterator's own
+ * <tt>remove</tt> method, the iterator will throw a {@link
+ * ConcurrentModificationException}.  Thus, in the face of concurrent
+ * modification, the iterator fails quickly and cleanly, rather than risking
+ * arbitrary, non-deterministic behavior at an undetermined time in the future.
+ *
+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
+ * as it is, generally speaking, impossible to make any hard guarantees in the
+ * presence of unsynchronized concurrent modification.  Fail-fast iterators
+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
+ * Therefore, it would be wrong to write a program that depended on this
+ * exception for its correctness:  <i>the fail-fast behavior of iterators
+ * should be used only to detect bugs.</i>
+ *
+ * <p>This class is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ *
+ * @author      Doug Lea
+ * @author      Josh Bloch
+ * @author      Mark Reinhold
+ * @since       1.2
+ * @see         java.util.HashMap
+ * @see         java.lang.ref.WeakReference
+ */
+public class WeakHashMap<K,V>
+    extends AbstractMap<K,V>
+    implements Map<K,V> {
+
+    /**
+     * The default initial capacity -- MUST be a power of two.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * The maximum capacity, used if a higher value is implicitly specified
+     * by either of the constructors with arguments.
+     * MUST be a power of two <= 1<<30.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The load factor used when none specified in constructor.
+     */
+    private static final float DEFAULT_LOAD_FACTOR = 0.75f;
+
+    /**
+     * The table, resized as necessary. Length MUST Always be a power of two.
+     */
+    Entry<K,V>[] table;
+
+    /**
+     * The number of key-value mappings contained in this weak hash map.
+     */
+    private int size;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     */
+    private int threshold;
+
+    /**
+     * The load factor for the hash table.
+     */
+    private final float loadFactor;
+
+    /**
+     * Reference queue for cleared WeakEntries
+     */
+    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
+
+    /**
+     * The number of times this WeakHashMap has been structurally modified.
+     * Structural modifications are those that change the number of
+     * mappings in the map or otherwise modify its internal structure
+     * (e.g., rehash).  This field is used to make iterators on
+     * Collection-views of the map fail-fast.
+     *
+     * @see ConcurrentModificationException
+     */
+    int modCount;
+
+    @SuppressWarnings("unchecked")
+    private Entry<K,V>[] newTable(int n) {
+        return (Entry<K,V>[]) new Entry<?,?>[n];
+    }
+
+    /**
+     * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
+     * capacity and the given load factor.
+     *
+     * @param  initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
+     * @param  loadFactor      The load factor of the <tt>WeakHashMap</tt>
+     * @throws IllegalArgumentException if the initial capacity is negative,
+     *         or if the load factor is nonpositive.
+     */
+    public WeakHashMap(int initialCapacity, float loadFactor) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Initial Capacity: "+
+                                               initialCapacity);
+        if (initialCapacity > MAXIMUM_CAPACITY)
+            initialCapacity = MAXIMUM_CAPACITY;
+
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
+            throw new IllegalArgumentException("Illegal Load factor: "+
+                                               loadFactor);
+        int capacity = 1;
+        while (capacity < initialCapacity)
+            capacity <<= 1;
+        table = newTable(capacity);
+        this.loadFactor = loadFactor;
+        threshold = (int)(capacity * loadFactor);
+    }
+
+    /**
+     * Constructs a new, empty <tt>WeakHashMap</tt> with the given initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity The initial capacity of the <tt>WeakHashMap</tt>
+     * @throws IllegalArgumentException if the initial capacity is negative
+     */
+    public WeakHashMap(int initialCapacity) {
+        this(initialCapacity, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new, empty <tt>WeakHashMap</tt> with the default initial
+     * capacity (16) and load factor (0.75).
+     */
+    public WeakHashMap() {
+        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+    }
+
+    /**
+     * Constructs a new <tt>WeakHashMap</tt> with the same mappings as the
+     * specified map.  The <tt>WeakHashMap</tt> is created with the default
+     * load factor (0.75) and an initial capacity sufficient to hold the
+     * mappings in the specified map.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     * @since   1.3
+     */
+    public WeakHashMap(Map<? extends K, ? extends V> m) {
+        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
+                DEFAULT_INITIAL_CAPACITY),
+             DEFAULT_LOAD_FACTOR);
+        putAll(m);
+    }
+
+    // internal utilities
+
+    /**
+     * Value representing null keys inside tables.
+     */
+    private static final Object NULL_KEY = new Object();
+
+    /**
+     * Use NULL_KEY for key if it is null.
+     */
+    private static Object maskNull(Object key) {
+        return (key == null) ? NULL_KEY : key;
+    }
+
+    /**
+     * Returns internal representation of null key back to caller as null.
+     */
+    static Object unmaskNull(Object key) {
+        return (key == NULL_KEY) ? null : key;
+    }
+
+    /**
+     * Checks for equality of non-null reference x and possibly-null y.  By
+     * default uses Object.equals.
+     */
+    private static boolean eq(Object x, Object y) {
+        return x == y || x.equals(y);
+    }
+
+    /**
+     * Retrieve object hash code and applies a supplemental hash function to the
+     * result hash, which defends against poor quality hash functions.  This is
+     * critical because HashMap uses power-of-two length hash tables, that
+     * otherwise encounter collisions for hashCodes that do not differ
+     * in lower bits.
+     */
+    final int hash(Object k) {
+        int h = k.hashCode();
+
+        // This function ensures that hashCodes that differ only by
+        // constant multiples at each bit position have a bounded
+        // number of collisions (approximately 8 at default load factor).
+        h ^= (h >>> 20) ^ (h >>> 12);
+        return h ^ (h >>> 7) ^ (h >>> 4);
+    }
+
+    /**
+     * Returns index for hash code h.
+     */
+    private static int indexFor(int h, int length) {
+        return h & (length-1);
+    }
+
+    /**
+     * Expunges stale entries from the table.
+     */
+    private void expungeStaleEntries() {
+        for (Object x; (x = queue.poll()) != null; ) {
+            synchronized (queue) {
+                @SuppressWarnings("unchecked")
+                    Entry<K,V> e = (Entry<K,V>) x;
+                int i = indexFor(e.hash, table.length);
+
+                Entry<K,V> prev = table[i];
+                Entry<K,V> p = prev;
+                while (p != null) {
+                    Entry<K,V> next = p.next;
+                    if (p == e) {
+                        if (prev == e)
+                            table[i] = next;
+                        else
+                            prev.next = next;
+                        // Must not null out e.next;
+                        // stale entries may be in use by a HashIterator
+                        e.value = null; // Help GC
+                        size--;
+                        break;
+                    }
+                    prev = p;
+                    p = next;
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the table after first expunging stale entries.
+     */
+    private Entry<K,V>[] getTable() {
+        expungeStaleEntries();
+        return table;
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     * This result is a snapshot, and may not reflect unprocessed
+     * entries that will be removed before next attempted access
+     * because they are no longer referenced.
+     */
+    public int size() {
+        if (size == 0)
+            return 0;
+        expungeStaleEntries();
+        return size;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains no key-value mappings.
+     * This result is a snapshot, and may not reflect unprocessed
+     * entries that will be removed before next attempted access
+     * because they are no longer referenced.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code (key==null ? k==null :
+     * key.equals(k))}, then this method returns {@code v}; otherwise
+     * it returns {@code null}.  (There can be at most one such mapping.)
+     *
+     * <p>A return value of {@code null} does not <i>necessarily</i>
+     * indicate that the map contains no mapping for the key; it's also
+     * possible that the map explicitly maps the key to {@code null}.
+     * The {@link #containsKey containsKey} operation may be used to
+     * distinguish these two cases.
+     *
+     * @see #put(Object, Object)
+     */
+    public V get(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int index = indexFor(h, tab.length);
+        Entry<K,V> e = tab[index];
+        while (e != null) {
+            if (e.hash == h && eq(k, e.get()))
+                return e.value;
+            e = e.next;
+        }
+        return null;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map contains a mapping for the
+     * specified key.
+     *
+     * @param  key   The key whose presence in this map is to be tested
+     * @return <tt>true</tt> if there is a mapping for <tt>key</tt>;
+     *         <tt>false</tt> otherwise
+     */
+    public boolean containsKey(Object key) {
+        return getEntry(key) != null;
+    }
+
+    /**
+     * Returns the entry associated with the specified key in this map.
+     * Returns null if the map contains no mapping for this key.
+     */
+    Entry<K,V> getEntry(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int index = indexFor(h, tab.length);
+        Entry<K,V> e = tab[index];
+        while (e != null && !(e.hash == h && eq(k, e.get())))
+            e = e.next;
+        return e;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for this key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
+     *         (A <tt>null</tt> return can also indicate that the map
+     *         previously associated <tt>null</tt> with <tt>key</tt>.)
+     */
+    public V put(K key, V value) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int i = indexFor(h, tab.length);
+
+        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
+            if (h == e.hash && eq(k, e.get())) {
+                V oldValue = e.value;
+                if (value != oldValue)
+                    e.value = value;
+                return oldValue;
+            }
+        }
+
+        modCount++;
+        Entry<K,V> e = tab[i];
+        tab[i] = new Entry<>(k, value, queue, h, e);
+        if (++size >= threshold)
+            resize(tab.length * 2);
+        return null;
+    }
+
+    /**
+     * Rehashes the contents of this map into a new array with a
+     * larger capacity.  This method is called automatically when the
+     * number of keys in this map reaches its threshold.
+     *
+     * If current capacity is MAXIMUM_CAPACITY, this method does not
+     * resize the map, but sets threshold to Integer.MAX_VALUE.
+     * This has the effect of preventing future calls.
+     *
+     * @param newCapacity the new capacity, MUST be a power of two;
+     *        must be greater than current capacity unless current
+     *        capacity is MAXIMUM_CAPACITY (in which case value
+     *        is irrelevant).
+     */
+    void resize(int newCapacity) {
+        Entry<K,V>[] oldTable = getTable();
+        int oldCapacity = oldTable.length;
+        if (oldCapacity == MAXIMUM_CAPACITY) {
+            threshold = Integer.MAX_VALUE;
+            return;
+        }
+
+        Entry<K,V>[] newTable = newTable(newCapacity);
+        transfer(oldTable, newTable);
+        table = newTable;
+
+        /*
+         * If ignoring null elements and processing ref queue caused massive
+         * shrinkage, then restore old table.  This should be rare, but avoids
+         * unbounded expansion of garbage-filled tables.
+         */
+        if (size >= threshold / 2) {
+            threshold = (int)(newCapacity * loadFactor);
+        } else {
+            expungeStaleEntries();
+            transfer(newTable, oldTable);
+            table = oldTable;
+        }
+    }
+
+    /** Transfers all entries from src to dest tables */
+    private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
+        for (int j = 0; j < src.length; ++j) {
+            Entry<K,V> e = src[j];
+            src[j] = null;
+            while (e != null) {
+                Entry<K,V> next = e.next;
+                Object key = e.get();
+                if (key == null) {
+                    e.next = null;  // Help GC
+                    e.value = null; //  "   "
+                    size--;
+                } else {
+                    int i = indexFor(e.hash, dest.length);
+                    e.next = dest[i];
+                    dest[i] = e;
+                }
+                e = next;
+            }
+        }
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this map.
+     * These mappings will replace any mappings that this map had for any
+     * of the keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map.
+     * @throws  NullPointerException if the specified map is null.
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        int numKeysToBeAdded = m.size();
+        if (numKeysToBeAdded == 0)
+            return;
+
+        /*
+         * Expand the map if the map if the number of mappings to be added
+         * is greater than or equal to threshold.  This is conservative; the
+         * obvious condition is (m.size() + size) >= threshold, but this
+         * condition could result in a map with twice the appropriate capacity,
+         * if the keys to be added overlap with the keys already in this map.
+         * By using the conservative calculation, we subject ourself
+         * to at most one extra resize.
+         */
+        if (numKeysToBeAdded > threshold) {
+            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
+            if (targetCapacity > MAXIMUM_CAPACITY)
+                targetCapacity = MAXIMUM_CAPACITY;
+            int newCapacity = table.length;
+            while (newCapacity < targetCapacity)
+                newCapacity <<= 1;
+            if (newCapacity > table.length)
+                resize(newCapacity);
+        }
+
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            put(e.getKey(), e.getValue());
+    }
+
+    /**
+     * Removes the mapping for a key from this weak hash map if it is present.
+     * More formally, if this map contains a mapping from key <tt>k</tt> to
+     * value <tt>v</tt> such that <code>(key==null ?  k==null :
+     * key.equals(k))</code>, that mapping is removed.  (The map can contain
+     * at most one such mapping.)
+     *
+     * <p>Returns the value to which this map previously associated the key,
+     * or <tt>null</tt> if the map contained no mapping for the key.  A
+     * return value of <tt>null</tt> does not <i>necessarily</i> indicate
+     * that the map contained no mapping for the key; it's also possible
+     * that the map explicitly mapped the key to <tt>null</tt>.
+     *
+     * <p>The map will not contain a mapping for the specified key once the
+     * call returns.
+     *
+     * @param key key whose mapping is to be removed from the map
+     * @return the previous value associated with <tt>key</tt>, or
+     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
+     */
+    public V remove(Object key) {
+        Object k = maskNull(key);
+        int h = hash(k);
+        Entry<K,V>[] tab = getTable();
+        int i = indexFor(h, tab.length);
+        Entry<K,V> prev = tab[i];
+        Entry<K,V> e = prev;
+
+        while (e != null) {
+            Entry<K,V> next = e.next;
+            if (h == e.hash && eq(k, e.get())) {
+                modCount++;
+                size--;
+                if (prev == e)
+                    tab[i] = next;
+                else
+                    prev.next = next;
+                return e.value;
+            }
+            prev = e;
+            e = next;
+        }
+
+        return null;
+    }
+
+    /** Special version of remove needed by Entry set */
+    boolean removeMapping(Object o) {
+        if (!(o instanceof Map.Entry))
+            return false;
+        Entry<K,V>[] tab = getTable();
+        Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
+        Object k = maskNull(entry.getKey());
+        int h = hash(k);
+        int i = indexFor(h, tab.length);
+        Entry<K,V> prev = tab[i];
+        Entry<K,V> e = prev;
+
+        while (e != null) {
+            Entry<K,V> next = e.next;
+            if (h == e.hash && e.equals(entry)) {
+                modCount++;
+                size--;
+                if (prev == e)
+                    tab[i] = next;
+                else
+                    prev.next = next;
+                return true;
+            }
+            prev = e;
+            e = next;
+        }
+
+        return false;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     * The map will be empty after this call returns.
+     */
+    public void clear() {
+        // clear out ref queue. We don't need to expunge entries
+        // since table is getting cleared.
+        while (queue.poll() != null)
+            ;
+
+        modCount++;
+        Arrays.fill(table, null);
+        size = 0;
+
+        // Allocation of array may have caused GC, which may have caused
+        // additional entries to go stale.  Removing these entries from the
+        // reference queue will make them eligible for reclamation.
+        while (queue.poll() != null)
+            ;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this map maps one or more keys to the
+     * specified value.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return <tt>true</tt> if this map maps one or more keys to the
+     *         specified value
+     */
+    public boolean containsValue(Object value) {
+        if (value==null)
+            return containsNullValue();
+
+        Entry<K,V>[] tab = getTable();
+        for (int i = tab.length; i-- > 0;)
+            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
+                if (value.equals(e.value))
+                    return true;
+        return false;
+    }
+
+    /**
+     * Special-case code for containsValue with null argument
+     */
+    private boolean containsNullValue() {
+        Entry<K,V>[] tab = getTable();
+        for (int i = tab.length; i-- > 0;)
+            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
+                if (e.value==null)
+                    return true;
+        return false;
+    }
+
+    /**
+     * The entries in this hash table extend WeakReference, using its main ref
+     * field as the key.
+     */
+    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
+        V value;
+        final int hash;
+        Entry<K,V> next;
+
+        /**
+         * Creates new entry.
+         */
+        Entry(Object key, V value,
+              ReferenceQueue<Object> queue,
+              int hash, Entry<K,V> next) {
+            super(key, queue);
+            this.value = value;
+            this.hash  = hash;
+            this.next  = next;
+        }
+
+        @SuppressWarnings("unchecked")
+        public K getKey() {
+            return (K) WeakHashMap.unmaskNull(get());
+        }
+
+        public V getValue() {
+            return value;
+        }
+
+        public V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public boolean equals(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            K k1 = getKey();
+            Object k2 = e.getKey();
+            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
+                V v1 = getValue();
+                Object v2 = e.getValue();
+                if (v1 == v2 || (v1 != null && v1.equals(v2)))
+                    return true;
+            }
+            return false;
+        }
+
+        public int hashCode() {
+            K k = getKey();
+            V v = getValue();
+            return Objects.hashCode(k) ^ Objects.hashCode(v);
+        }
+
+        public String toString() {
+            return getKey() + "=" + getValue();
+        }
+    }
+
+    private abstract class HashIterator<T> implements Iterator<T> {
+        private int index;
+        private Entry<K,V> entry;
+        private Entry<K,V> lastReturned;
+        private int expectedModCount = modCount;
+
+        /**
+         * Strong reference needed to avoid disappearance of key
+         * between hasNext and next
+         */
+        private Object nextKey;
+
+        /**
+         * Strong reference needed to avoid disappearance of key
+         * between nextEntry() and any use of the entry
+         */
+        private Object currentKey;
+
+        HashIterator() {
+            index = isEmpty() ? 0 : table.length;
+        }
+
+        public boolean hasNext() {
+            Entry<K,V>[] t = table;
+
+            while (nextKey == null) {
+                Entry<K,V> e = entry;
+                int i = index;
+                while (e == null && i > 0)
+                    e = t[--i];
+                entry = e;
+                index = i;
+                if (e == null) {
+                    currentKey = null;
+                    return false;
+                }
+                nextKey = e.get(); // hold on to key in strong ref
+                if (nextKey == null)
+                    entry = entry.next;
+            }
+            return true;
+        }
+
+        /** The common parts of next() across different types of iterators */
+        protected Entry<K,V> nextEntry() {
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (nextKey == null && !hasNext())
+                throw new NoSuchElementException();
+
+            lastReturned = entry;
+            entry = entry.next;
+            currentKey = nextKey;
+            nextKey = null;
+            return lastReturned;
+        }
+
+        public void remove() {
+            if (lastReturned == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+
+            WeakHashMap.this.remove(currentKey);
+            expectedModCount = modCount;
+            lastReturned = null;
+            currentKey = null;
+        }
+
+    }
+
+    private class ValueIterator extends HashIterator<V> {
+        public V next() {
+            return nextEntry().value;
+        }
+    }
+
+    private class KeyIterator extends HashIterator<K> {
+        public K next() {
+            return nextEntry().getKey();
+        }
+    }
+
+    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
+        public Map.Entry<K,V> next() {
+            return nextEntry();
+        }
+    }
+
+    // Views
+
+    private transient Set<Map.Entry<K,V>> entrySet;
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     */
+    public Set<K> keySet() {
+        Set<K> ks = keySet;
+        if (ks == null) {
+            ks = new KeySet();
+            keySet = ks;
+        }
+        return ks;
+    }
+
+    private class KeySet extends AbstractSet<K> {
+        public Iterator<K> iterator() {
+            return new KeyIterator();
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+
+        public boolean remove(Object o) {
+            if (containsKey(o)) {
+                WeakHashMap.this.remove(o);
+                return true;
+            }
+            else
+                return false;
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        public Spliterator<K> spliterator() {
+            return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     */
+    public Collection<V> values() {
+        Collection<V> vs = values;
+        if (vs == null) {
+            vs = new Values();
+            values = vs;
+        }
+        return vs;
+    }
+
+    private class Values extends AbstractCollection<V> {
+        public Iterator<V> iterator() {
+            return new ValueIterator();
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public boolean contains(Object o) {
+            return containsValue(o);
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        public Spliterator<V> spliterator() {
+            return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es = entrySet;
+        return es != null ? es : (entrySet = new EntrySet());
+    }
+
+    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            Entry<K,V> candidate = getEntry(e.getKey());
+            return candidate != null && candidate.equals(e);
+        }
+
+        public boolean remove(Object o) {
+            return removeMapping(o);
+        }
+
+        public int size() {
+            return WeakHashMap.this.size();
+        }
+
+        public void clear() {
+            WeakHashMap.this.clear();
+        }
+
+        private List<Map.Entry<K,V>> deepCopy() {
+            List<Map.Entry<K,V>> list = new ArrayList<>(size());
+            for (Map.Entry<K,V> e : this)
+                list.add(new AbstractMap.SimpleEntry<>(e));
+            return list;
+        }
+
+        public Object[] toArray() {
+            return deepCopy().toArray();
+        }
+
+        public <T> T[] toArray(T[] a) {
+            return deepCopy().toArray(a);
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    action.accept((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        int expectedModCount = modCount;
+
+        Entry<K, V>[] tab = getTable();;
+        for (Entry<K, V> entry : tab) {
+            while (entry != null) {
+                Object key = entry.get();
+                if (key != null) {
+                    entry.value = function.apply((K)WeakHashMap.unmaskNull(key), entry.value);
+                }
+                entry = entry.next;
+
+                if (expectedModCount != modCount) {
+                    throw new ConcurrentModificationException();
+                }
+            }
+        }
+    }
+
+    /**
+     * Similar form as other hash Spliterators, but skips dead
+     * elements.
+     */
+    static class WeakHashMapSpliterator<K,V> {
+        final WeakHashMap<K,V> map;
+        WeakHashMap.Entry<K,V> current; // current node
+        int index;             // current index, modified on advance/split
+        int fence;             // -1 until first use; then one past last index
+        int est;               // size estimate
+        int expectedModCount;  // for comodification checks
+
+        WeakHashMapSpliterator(WeakHashMap<K,V> m, int origin,
+                               int fence, int est,
+                               int expectedModCount) {
+            this.map = m;
+            this.index = origin;
+            this.fence = fence;
+            this.est = est;
+            this.expectedModCount = expectedModCount;
+        }
+
+        final int getFence() { // initialize fence and size on first use
+            int hi;
+            if ((hi = fence) < 0) {
+                WeakHashMap<K,V> m = map;
+                est = m.size();
+                expectedModCount = m.modCount;
+                hi = fence = m.table.length;
+            }
+            return hi;
+        }
+
+        public final long estimateSize() {
+            getFence(); // force init
+            return (long) est;
+        }
+    }
+
+    static final class KeySpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        p = p.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept(k);
+                        }
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        current = current.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept(k);
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT;
+        }
+    }
+
+    static final class ValueSpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                         int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        V v = p.value;
+                        p = p.next;
+                        if (x != null)
+                            action.accept(v);
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        V v = current.value;
+                        current = current.next;
+                        if (x != null) {
+                            action.accept(v);
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return 0;
+        }
+    }
+
+    static final class EntrySpliterator<K,V>
+        extends WeakHashMapSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(WeakHashMap<K,V> m, int origin, int fence, int est,
+                       int expectedModCount) {
+            super(m, origin, fence, est, expectedModCount);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
+        }
+
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
+            int i, hi, mc;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap<K,V> m = map;
+            WeakHashMap.Entry<K,V>[] tab = m.table;
+            if ((hi = fence) < 0) {
+                mc = expectedModCount = m.modCount;
+                hi = fence = tab.length;
+            }
+            else
+                mc = expectedModCount;
+            if (tab.length >= hi && (i = index) >= 0 &&
+                (i < (index = hi) || current != null)) {
+                WeakHashMap.Entry<K,V> p = current;
+                current = null; // exhaust
+                do {
+                    if (p == null)
+                        p = tab[i++];
+                    else {
+                        Object x = p.get();
+                        V v = p.value;
+                        p = p.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept
+                                (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                        }
+                    }
+                } while (p != null || i < hi);
+            }
+            if (m.modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            int hi;
+            if (action == null)
+                throw new NullPointerException();
+            WeakHashMap.Entry<K,V>[] tab = map.table;
+            if (tab.length >= (hi = getFence()) && index >= 0) {
+                while (current != null || index < hi) {
+                    if (current == null)
+                        current = tab[index++];
+                    else {
+                        Object x = current.get();
+                        V v = current.value;
+                        current = current.next;
+                        if (x != null) {
+                            @SuppressWarnings("unchecked") K k =
+                                (K) WeakHashMap.unmaskNull(x);
+                            action.accept
+                                (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
+                            if (map.modCount != expectedModCount)
+                                throw new ConcurrentModificationException();
+                            return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT;
+        }
+    }
+
+}
diff --git a/java/util/XMLUtils.java b/java/util/XMLUtils.java
new file mode 100644
index 0000000..8f061e5
--- /dev/null
+++ b/java/util/XMLUtils.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util;
+
+import java.io.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+import org.w3c.dom.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+
+/**
+ * A class used to aid in Properties load and save in XML. Keeping this
+ * code outside of Properties helps reduce the number of classes loaded
+ * when Properties is loaded.
+ *
+ * @author  Michael McCloskey
+ * @since   1.3
+ */
+class XMLUtils {
+
+    // XML loading and saving methods for Properties
+
+    // The required DTD URI for exported properties
+    private static final String PROPS_DTD_URI =
+    "http://java.sun.com/dtd/properties.dtd";
+
+    private static final String PROPS_DTD =
+    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+    "<!-- DTD for properties -->"                +
+    "<!ELEMENT properties ( comment?, entry* ) >"+
+    "<!ATTLIST properties"                       +
+        " version CDATA #FIXED \"1.0\">"         +
+    "<!ELEMENT comment (#PCDATA) >"              +
+    "<!ELEMENT entry (#PCDATA) >"                +
+    "<!ATTLIST entry "                           +
+        " key CDATA #REQUIRED>";
+
+    /**
+     * Version number for the format of exported properties files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+
+    static void load(Properties props, InputStream in)
+        throws IOException, InvalidPropertiesFormatException
+    {
+        Document doc = null;
+        try {
+            doc = getLoadingDoc(in);
+        } catch (SAXException saxe) {
+            throw new InvalidPropertiesFormatException(saxe);
+        }
+        Element propertiesElement = doc.getDocumentElement();
+        String xmlVersion = propertiesElement.getAttribute("version");
+        if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
+            throw new InvalidPropertiesFormatException(
+                "Exported Properties file format version " + xmlVersion +
+                " is not supported. This java installation can read" +
+                " versions " + EXTERNAL_XML_VERSION + " or older. You" +
+                " may need to install a newer version of JDK.");
+        importProperties(props, propertiesElement);
+    }
+
+    static Document getLoadingDoc(InputStream in)
+        throws SAXException, IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setIgnoringElementContentWhitespace(true);
+        // Android-changed: We don't currently have a validating document builder.
+        // Revert this if the situation changes.
+        //
+        // dbf.setValidating(true);
+        dbf.setCoalescing(true);
+        dbf.setIgnoringComments(true);
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            db.setEntityResolver(new Resolver());
+            db.setErrorHandler(new EH());
+            InputSource is = new InputSource(in);
+            return db.parse(is);
+        } catch (ParserConfigurationException x) {
+            throw new Error(x);
+        }
+    }
+
+    static void importProperties(Properties props, Element propertiesElement) {
+        NodeList entries = propertiesElement.getChildNodes();
+        int numEntries = entries.getLength();
+        int start = numEntries > 0 &&
+            entries.item(0).getNodeName().equals("comment") ? 1 : 0;
+        for (int i=start; i<numEntries; i++) {
+            // Android-changed: Exclude CDATA nodes and the like.
+            if (!(entries.item(i) instanceof Element)) {
+                continue;
+            }
+            Element entry = (Element)entries.item(i);
+            if (entry.hasAttribute("key")) {
+                Node n = entry.getFirstChild();
+                String val = (n == null) ? "" : n.getNodeValue();
+                props.setProperty(entry.getAttribute("key"), val);
+            }
+        }
+    }
+
+    static void save(Properties props, OutputStream os, String comment,
+                     String encoding)
+        throws IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        DocumentBuilder db = null;
+        try {
+            db = dbf.newDocumentBuilder();
+        } catch (ParserConfigurationException pce) {
+            assert(false);
+        }
+        Document doc = db.newDocument();
+        Element properties =  (Element)
+            doc.appendChild(doc.createElement("properties"));
+
+        if (comment != null) {
+            Element comments = (Element)properties.appendChild(
+                doc.createElement("comment"));
+            comments.appendChild(doc.createTextNode(comment));
+        }
+
+        synchronized (props) {
+            for (String key : props.stringPropertyNames()) {
+                Element entry = (Element)properties.appendChild(
+                    doc.createElement("entry"));
+                entry.setAttribute("key", key);
+                entry.appendChild(doc.createTextNode(props.getProperty(key)));
+            }
+        }
+        emitDocument(doc, os, encoding);
+    }
+
+    static void emitDocument(Document doc, OutputStream os, String encoding)
+        throws IOException
+    {
+        TransformerFactory tf = TransformerFactory.newInstance();
+        Transformer t = null;
+        try {
+            t = tf.newTransformer();
+            t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, PROPS_DTD_URI);
+            t.setOutputProperty(OutputKeys.INDENT, "yes");
+            t.setOutputProperty(OutputKeys.METHOD, "xml");
+            t.setOutputProperty(OutputKeys.ENCODING, encoding);
+        } catch (TransformerConfigurationException tce) {
+            assert(false);
+        }
+        DOMSource doms = new DOMSource(doc);
+        StreamResult sr = new StreamResult(os);
+        try {
+            t.transform(doms, sr);
+        } catch (TransformerException te) {
+            IOException ioe = new IOException();
+            ioe.initCause(te);
+            throw ioe;
+        }
+    }
+
+    private static class Resolver implements EntityResolver {
+        public InputSource resolveEntity(String pid, String sid)
+            throws SAXException
+        {
+            if (sid.equals(PROPS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PROPS_DTD));
+                is.setSystemId(PROPS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sid);
+        }
+    }
+
+    private static class EH implements ErrorHandler {
+        public void error(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void fatalError(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void warning(SAXParseException x) throws SAXException {
+            throw x;
+        }
+    }
+
+}
diff --git a/java/util/concurrent/AbstractExecutorService.java b/java/util/concurrent/AbstractExecutorService.java
new file mode 100644
index 0000000..e4d2235
--- /dev/null
+++ b/java/util/concurrent/AbstractExecutorService.java
@@ -0,0 +1,312 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Provides default implementations of {@link ExecutorService}
+ * execution methods. This class implements the {@code submit},
+ * {@code invokeAny} and {@code invokeAll} methods using a
+ * {@link RunnableFuture} returned by {@code newTaskFor}, which defaults
+ * to the {@link FutureTask} class provided in this package.  For example,
+ * the implementation of {@code submit(Runnable)} creates an
+ * associated {@code RunnableFuture} that is executed and
+ * returned. Subclasses may override the {@code newTaskFor} methods
+ * to return {@code RunnableFuture} implementations other than
+ * {@code FutureTask}.
+ *
+ * <p><b>Extension example</b>. Here is a sketch of a class
+ * that customizes {@link ThreadPoolExecutor} to use
+ * a {@code CustomTask} class instead of the default {@code FutureTask}:
+ * <pre> {@code
+ * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
+ *
+ *   static class CustomTask<V> implements RunnableFuture<V> {...}
+ *
+ *   protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
+ *       return new CustomTask<V>(c);
+ *   }
+ *   protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
+ *       return new CustomTask<V>(r, v);
+ *   }
+ *   // ... add constructors, etc.
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractExecutorService implements ExecutorService {
+
+    /**
+     * Returns a {@code RunnableFuture} for the given runnable and default
+     * value.
+     *
+     * @param runnable the runnable task being wrapped
+     * @param value the default value for the returned future
+     * @param <T> the type of the given value
+     * @return a {@code RunnableFuture} which, when run, will run the
+     * underlying runnable and which, as a {@code Future}, will yield
+     * the given value as its result and provide for cancellation of
+     * the underlying task
+     * @since 1.6
+     */
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return new FutureTask<T>(runnable, value);
+    }
+
+    /**
+     * Returns a {@code RunnableFuture} for the given callable task.
+     *
+     * @param callable the callable task being wrapped
+     * @param <T> the type of the callable's result
+     * @return a {@code RunnableFuture} which, when run, will call the
+     * underlying callable and which, as a {@code Future}, will yield
+     * the callable's result as its result and provide for
+     * cancellation of the underlying task
+     * @since 1.6
+     */
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return new FutureTask<T>(callable);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<?> submit(Runnable task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<Void> ftask = newTaskFor(task, null);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Runnable task, T result) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<T> ftask = newTaskFor(task, result);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Callable<T> task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<T> ftask = newTaskFor(task);
+        execute(ftask);
+        return ftask;
+    }
+
+    /**
+     * the main mechanics of invokeAny.
+     */
+    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
+                              boolean timed, long nanos)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        if (tasks == null)
+            throw new NullPointerException();
+        int ntasks = tasks.size();
+        if (ntasks == 0)
+            throw new IllegalArgumentException();
+        ArrayList<Future<T>> futures = new ArrayList<>(ntasks);
+        ExecutorCompletionService<T> ecs =
+            new ExecutorCompletionService<T>(this);
+
+        // For efficiency, especially in executors with limited
+        // parallelism, check to see if previously submitted tasks are
+        // done before submitting more of them. This interleaving
+        // plus the exception mechanics account for messiness of main
+        // loop.
+
+        try {
+            // Record exceptions so that if we fail to obtain any
+            // result, we can throw the last exception we got.
+            ExecutionException ee = null;
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Iterator<? extends Callable<T>> it = tasks.iterator();
+
+            // Start one task for sure; the rest incrementally
+            futures.add(ecs.submit(it.next()));
+            --ntasks;
+            int active = 1;
+
+            for (;;) {
+                Future<T> f = ecs.poll();
+                if (f == null) {
+                    if (ntasks > 0) {
+                        --ntasks;
+                        futures.add(ecs.submit(it.next()));
+                        ++active;
+                    }
+                    else if (active == 0)
+                        break;
+                    else if (timed) {
+                        f = ecs.poll(nanos, NANOSECONDS);
+                        if (f == null)
+                            throw new TimeoutException();
+                        nanos = deadline - System.nanoTime();
+                    }
+                    else
+                        f = ecs.take();
+                }
+                if (f != null) {
+                    --active;
+                    try {
+                        return f.get();
+                    } catch (ExecutionException eex) {
+                        ee = eex;
+                    } catch (RuntimeException rex) {
+                        ee = new ExecutionException(rex);
+                    }
+                }
+            }
+
+            if (ee == null)
+                ee = new ExecutionException();
+            throw ee;
+
+        } finally {
+            cancelAll(futures);
+        }
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException {
+        try {
+            return doInvokeAny(tasks, false, 0);
+        } catch (TimeoutException cannotHappen) {
+            assert false;
+            return null;
+        }
+    }
+
+    public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                           long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        return doInvokeAny(tasks, true, unit.toNanos(timeout));
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException {
+        if (tasks == null)
+            throw new NullPointerException();
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        try {
+            for (Callable<T> t : tasks) {
+                RunnableFuture<T> f = newTaskFor(t);
+                futures.add(f);
+                execute(f);
+            }
+            for (int i = 0, size = futures.size(); i < size; i++) {
+                Future<T> f = futures.get(i);
+                if (!f.isDone()) {
+                    try { f.get(); }
+                    catch (CancellationException ignore) {}
+                    catch (ExecutionException ignore) {}
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            cancelAll(futures);
+            throw t;
+        }
+    }
+
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (tasks == null)
+            throw new NullPointerException();
+        final long nanos = unit.toNanos(timeout);
+        final long deadline = System.nanoTime() + nanos;
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+        int j = 0;
+        timedOut: try {
+            for (Callable<T> t : tasks)
+                futures.add(newTaskFor(t));
+
+            final int size = futures.size();
+
+            // Interleave time checks and calls to execute in case
+            // executor doesn't have any/much parallelism.
+            for (int i = 0; i < size; i++) {
+                if (((i == 0) ? nanos : deadline - System.nanoTime()) <= 0L)
+                    break timedOut;
+                execute((Runnable)futures.get(i));
+            }
+
+            for (; j < size; j++) {
+                Future<T> f = futures.get(j);
+                if (!f.isDone()) {
+                    try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
+                    catch (CancellationException ignore) {}
+                    catch (ExecutionException ignore) {}
+                    catch (TimeoutException timedOut) {
+                        break timedOut;
+                    }
+                }
+            }
+            return futures;
+        } catch (Throwable t) {
+            cancelAll(futures);
+            throw t;
+        }
+        // Timed out before all the tasks could be completed; cancel remaining
+        cancelAll(futures, j);
+        return futures;
+    }
+
+    private static <T> void cancelAll(ArrayList<Future<T>> futures) {
+        cancelAll(futures, 0);
+    }
+
+    /** Cancels all futures with index at least j. */
+    private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {
+        for (int size = futures.size(); j < size; j++)
+            futures.get(j).cancel(true);
+    }
+}
diff --git a/java/util/concurrent/ArrayBlockingQueue.java b/java/util/concurrent/ArrayBlockingQueue.java
new file mode 100644
index 0000000..96a60b3
--- /dev/null
+++ b/java/util/concurrent/ArrayBlockingQueue.java
@@ -0,0 +1,1369 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.ref.WeakReference;
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A bounded {@linkplain BlockingQueue blocking queue} backed by an
+ * array.  This queue orders elements FIFO (first-in-first-out).  The
+ * <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.  The <em>tail</em> of the queue is that
+ * element that has been on the queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ *
+ * <p>This is a classic &quot;bounded buffer&quot;, in which a
+ * fixed-sized array holds elements inserted by producers and
+ * extracted by consumers.  Once created, the capacity cannot be
+ * changed.  Attempts to {@code put} an element into a full queue
+ * will result in the operation blocking; attempts to {@code take} an
+ * element from an empty queue will similarly block.
+ *
+ * <p>This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads.  By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to {@code true} grants threads access in FIFO order. Fairness
+ * generally decreases throughput but reduces variability and avoids
+ * starvation.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class ArrayBlockingQueue<E> extends AbstractQueue<E>
+        implements BlockingQueue<E>, java.io.Serializable {
+
+    /**
+     * Serialization ID. This class relies on default serialization
+     * even for the items array, which is default-serialized, even if
+     * it is empty. Otherwise it could not be declared final, which is
+     * necessary here.
+     */
+    private static final long serialVersionUID = -817911632652898426L;
+
+    /** The queued items */
+    final Object[] items;
+
+    /** items index for next take, poll, peek or remove */
+    int takeIndex;
+
+    /** items index for next put, offer, or add */
+    int putIndex;
+
+    /** Number of elements in the queue */
+    int count;
+
+    /*
+     * Concurrency control uses the classic two-condition algorithm
+     * found in any textbook.
+     */
+
+    /** Main lock guarding all access */
+    final ReentrantLock lock;
+
+    /** Condition for waiting takes */
+    private final Condition notEmpty;
+
+    /** Condition for waiting puts */
+    private final Condition notFull;
+
+    /**
+     * Shared state for currently active iterators, or null if there
+     * are known not to be any.  Allows queue operations to update
+     * iterator state.
+     */
+    transient Itrs itrs;
+
+    // Internal helper methods
+
+    /**
+     * Circularly decrements array index i.
+     */
+    final int dec(int i) {
+        return ((i == 0) ? items.length : i) - 1;
+    }
+
+    /**
+     * Returns item at index i.
+     */
+    @SuppressWarnings("unchecked")
+    final E itemAt(int i) {
+        return (E) items[i];
+    }
+
+    /**
+     * Inserts element at current put position, advances, and signals.
+     * Call only when holding lock.
+     */
+    private void enqueue(E x) {
+        // assert lock.getHoldCount() == 1;
+        // assert items[putIndex] == null;
+        final Object[] items = this.items;
+        items[putIndex] = x;
+        if (++putIndex == items.length) putIndex = 0;
+        count++;
+        notEmpty.signal();
+    }
+
+    /**
+     * Extracts element at current take position, advances, and signals.
+     * Call only when holding lock.
+     */
+    private E dequeue() {
+        // assert lock.getHoldCount() == 1;
+        // assert items[takeIndex] != null;
+        final Object[] items = this.items;
+        @SuppressWarnings("unchecked")
+        E x = (E) items[takeIndex];
+        items[takeIndex] = null;
+        if (++takeIndex == items.length) takeIndex = 0;
+        count--;
+        if (itrs != null)
+            itrs.elementDequeued();
+        notFull.signal();
+        return x;
+    }
+
+    /**
+     * Deletes item at array index removeIndex.
+     * Utility for remove(Object) and iterator.remove.
+     * Call only when holding lock.
+     */
+    void removeAt(final int removeIndex) {
+        // assert lock.getHoldCount() == 1;
+        // assert items[removeIndex] != null;
+        // assert removeIndex >= 0 && removeIndex < items.length;
+        final Object[] items = this.items;
+        if (removeIndex == takeIndex) {
+            // removing front item; just advance
+            items[takeIndex] = null;
+            if (++takeIndex == items.length) takeIndex = 0;
+            count--;
+            if (itrs != null)
+                itrs.elementDequeued();
+        } else {
+            // an "interior" remove
+
+            // slide over all others up through putIndex.
+            for (int i = removeIndex, putIndex = this.putIndex;;) {
+                int pred = i;
+                if (++i == items.length) i = 0;
+                if (i == putIndex) {
+                    items[pred] = null;
+                    this.putIndex = pred;
+                    break;
+                }
+                items[pred] = items[i];
+            }
+            count--;
+            if (itrs != null)
+                itrs.removedAt(removeIndex);
+        }
+        notFull.signal();
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity and default access policy.
+     *
+     * @param capacity the capacity of this queue
+     * @throws IllegalArgumentException if {@code capacity < 1}
+     */
+    public ArrayBlockingQueue(int capacity) {
+        this(capacity, false);
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity and the specified access policy.
+     *
+     * @param capacity the capacity of this queue
+     * @param fair if {@code true} then queue accesses for threads blocked
+     *        on insertion or removal, are processed in FIFO order;
+     *        if {@code false} the access order is unspecified.
+     * @throws IllegalArgumentException if {@code capacity < 1}
+     */
+    public ArrayBlockingQueue(int capacity, boolean fair) {
+        if (capacity <= 0)
+            throw new IllegalArgumentException();
+        this.items = new Object[capacity];
+        lock = new ReentrantLock(fair);
+        notEmpty = lock.newCondition();
+        notFull =  lock.newCondition();
+    }
+
+    /**
+     * Creates an {@code ArrayBlockingQueue} with the given (fixed)
+     * capacity, the specified access policy and initially containing the
+     * elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param capacity the capacity of this queue
+     * @param fair if {@code true} then queue accesses for threads blocked
+     *        on insertion or removal, are processed in FIFO order;
+     *        if {@code false} the access order is unspecified.
+     * @param c the collection of elements to initially contain
+     * @throws IllegalArgumentException if {@code capacity} is less than
+     *         {@code c.size()}, or less than 1.
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ArrayBlockingQueue(int capacity, boolean fair,
+                              Collection<? extends E> c) {
+        this(capacity, fair);
+
+        final ReentrantLock lock = this.lock;
+        lock.lock(); // Lock only for visibility, not mutual exclusion
+        try {
+            int i = 0;
+            try {
+                for (E e : c)
+                    items[i++] = Objects.requireNonNull(e);
+            } catch (ArrayIndexOutOfBoundsException ex) {
+                throw new IllegalArgumentException();
+            }
+            count = i;
+            putIndex = (i == capacity) ? 0 : i;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and throwing an
+     * {@code IllegalStateException} if this queue is full.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if this queue is full
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return super.add(e);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and {@code false} if this queue
+     * is full.  This method is generally preferable to method {@link #add},
+     * which can fail to insert an element only by throwing an exception.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        Objects.requireNonNull(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count == items.length)
+                return false;
+            else {
+                enqueue(e);
+                return true;
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting
+     * for space to become available if the queue is full.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        Objects.requireNonNull(e);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == items.length)
+                notFull.await();
+            enqueue(e);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting
+     * up to the specified wait time for space to become available if
+     * the queue is full.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+
+        Objects.requireNonNull(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == items.length) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            enqueue(e);
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (count == 0) ? null : dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == 0)
+                notEmpty.await();
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (count == 0) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return itemAt(takeIndex); // null when queue is empty
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // this doc comment is overridden to remove the reference to collections
+    // greater in size than Integer.MAX_VALUE
+    /**
+     * Returns the number of elements in this queue.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // this doc comment is a modified copy of the inherited doc comment,
+    // without the reference to unlimited queues.
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this queue
+     * less the current {@code size} of this queue.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return items.length - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * <p>Removal of interior elements in circular array based queues
+     * is an intrinsically slow and disruptive operation, so should
+     * be undertaken only in exceptional circumstances, ideally
+     * only when the queue is known not to be accessible by other
+     * threads.
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i])) {
+                        removeAt(i);
+                        return true;
+                    }
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (count > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    if (o.equals(items[i]))
+                        return true;
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] items = this.items;
+            final int end = takeIndex + count;
+            final Object[] a = Arrays.copyOfRange(items, takeIndex, end);
+            if (end != putIndex)
+                System.arraycopy(items, 0, a, items.length - takeIndex, putIndex);
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Object[] items = this.items;
+            final int count = this.count;
+            final int firstLeg = Math.min(items.length - takeIndex, count);
+            if (a.length < count) {
+                a = (T[]) Arrays.copyOfRange(items, takeIndex, takeIndex + count,
+                                             a.getClass());
+            } else {
+                System.arraycopy(items, takeIndex, a, 0, firstLeg);
+                if (a.length > count)
+                    a[count] = null;
+            }
+            if (firstLeg < count)
+                System.arraycopy(items, 0, a, firstLeg, putIndex);
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int k = count;
+            if (k > 0) {
+                final Object[] items = this.items;
+                final int putIndex = this.putIndex;
+                int i = takeIndex;
+                do {
+                    items[i] = null;
+                    if (++i == items.length) i = 0;
+                } while (i != putIndex);
+                takeIndex = putIndex;
+                count = 0;
+                if (itrs != null)
+                    itrs.queueIsEmpty();
+                for (; k > 0 && lock.hasWaiters(notFull); k--)
+                    notFull.signal();
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        Objects.requireNonNull(c);
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final Object[] items = this.items;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(maxElements, count);
+            int take = takeIndex;
+            int i = 0;
+            try {
+                while (i < n) {
+                    @SuppressWarnings("unchecked")
+                    E x = (E) items[take];
+                    c.add(x);
+                    items[take] = null;
+                    if (++take == items.length) take = 0;
+                    i++;
+                }
+                return n;
+            } finally {
+                // Restore invariants even if c.add() threw
+                if (i > 0) {
+                    count -= i;
+                    takeIndex = take;
+                    if (itrs != null) {
+                        if (count == 0)
+                            itrs.queueIsEmpty();
+                        else if (i > take)
+                            itrs.takeIndexWrapped();
+                    }
+                    for (; i > 0 && lock.hasWaiters(notFull); i--)
+                        notFull.signal();
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Shared data between iterators and their queue, allowing queue
+     * modifications to update iterators when elements are removed.
+     *
+     * This adds a lot of complexity for the sake of correctly
+     * handling some uncommon operations, but the combination of
+     * circular-arrays and supporting interior removes (i.e., those
+     * not at head) would cause iterators to sometimes lose their
+     * places and/or (re)report elements they shouldn't.  To avoid
+     * this, when a queue has one or more iterators, it keeps iterator
+     * state consistent by:
+     *
+     * (1) keeping track of the number of "cycles", that is, the
+     *     number of times takeIndex has wrapped around to 0.
+     * (2) notifying all iterators via the callback removedAt whenever
+     *     an interior element is removed (and thus other elements may
+     *     be shifted).
+     *
+     * These suffice to eliminate iterator inconsistencies, but
+     * unfortunately add the secondary responsibility of maintaining
+     * the list of iterators.  We track all active iterators in a
+     * simple linked list (accessed only when the queue's lock is
+     * held) of weak references to Itr.  The list is cleaned up using
+     * 3 different mechanisms:
+     *
+     * (1) Whenever a new iterator is created, do some O(1) checking for
+     *     stale list elements.
+     *
+     * (2) Whenever takeIndex wraps around to 0, check for iterators
+     *     that have been unused for more than one wrap-around cycle.
+     *
+     * (3) Whenever the queue becomes empty, all iterators are notified
+     *     and this entire data structure is discarded.
+     *
+     * So in addition to the removedAt callback that is necessary for
+     * correctness, iterators have the shutdown and takeIndexWrapped
+     * callbacks that help remove stale iterators from the list.
+     *
+     * Whenever a list element is examined, it is expunged if either
+     * the GC has determined that the iterator is discarded, or if the
+     * iterator reports that it is "detached" (does not need any
+     * further state updates).  Overhead is maximal when takeIndex
+     * never advances, iterators are discarded before they are
+     * exhausted, and all removals are interior removes, in which case
+     * all stale iterators are discovered by the GC.  But even in this
+     * case we don't increase the amortized complexity.
+     *
+     * Care must be taken to keep list sweeping methods from
+     * reentrantly invoking another such method, causing subtle
+     * corruption bugs.
+     */
+    class Itrs {
+
+        /**
+         * Node in a linked list of weak iterator references.
+         */
+        private class Node extends WeakReference<Itr> {
+            Node next;
+
+            Node(Itr iterator, Node next) {
+                super(iterator);
+                this.next = next;
+            }
+        }
+
+        /** Incremented whenever takeIndex wraps around to 0 */
+        int cycles;
+
+        /** Linked list of weak iterator references */
+        private Node head;
+
+        /** Used to expunge stale iterators */
+        private Node sweeper;
+
+        private static final int SHORT_SWEEP_PROBES = 4;
+        private static final int LONG_SWEEP_PROBES = 16;
+
+        Itrs(Itr initial) {
+            register(initial);
+        }
+
+        /**
+         * Sweeps itrs, looking for and expunging stale iterators.
+         * If at least one was found, tries harder to find more.
+         * Called only from iterating thread.
+         *
+         * @param tryHarder whether to start in try-harder mode, because
+         * there is known to be at least one iterator to collect
+         */
+        void doSomeSweeping(boolean tryHarder) {
+            // assert lock.getHoldCount() == 1;
+            // assert head != null;
+            int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
+            Node o, p;
+            final Node sweeper = this.sweeper;
+            boolean passedGo;   // to limit search to one full sweep
+
+            if (sweeper == null) {
+                o = null;
+                p = head;
+                passedGo = true;
+            } else {
+                o = sweeper;
+                p = o.next;
+                passedGo = false;
+            }
+
+            for (; probes > 0; probes--) {
+                if (p == null) {
+                    if (passedGo)
+                        break;
+                    o = null;
+                    p = head;
+                    passedGo = true;
+                }
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.isDetached()) {
+                    // found a discarded/exhausted iterator
+                    probes = LONG_SWEEP_PROBES; // "try harder"
+                    // unlink p
+                    p.clear();
+                    p.next = null;
+                    if (o == null) {
+                        head = next;
+                        if (next == null) {
+                            // We've run out of iterators to track; retire
+                            itrs = null;
+                            return;
+                        }
+                    }
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+
+            this.sweeper = (p == null) ? null : o;
+        }
+
+        /**
+         * Adds a new iterator to the linked list of tracked iterators.
+         */
+        void register(Itr itr) {
+            // assert lock.getHoldCount() == 1;
+            head = new Node(itr, head);
+        }
+
+        /**
+         * Called whenever takeIndex wraps around to 0.
+         *
+         * Notifies all iterators, and expunges any that are now stale.
+         */
+        void takeIndexWrapped() {
+            // assert lock.getHoldCount() == 1;
+            cycles++;
+            for (Node o = null, p = head; p != null;) {
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.takeIndexWrapped()) {
+                    // unlink p
+                    // assert it == null || it.isDetached();
+                    p.clear();
+                    p.next = null;
+                    if (o == null)
+                        head = next;
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occurred.
+         *
+         * Notifies all iterators, and expunges any that are now stale.
+         */
+        void removedAt(int removedIndex) {
+            for (Node o = null, p = head; p != null;) {
+                final Itr it = p.get();
+                final Node next = p.next;
+                if (it == null || it.removedAt(removedIndex)) {
+                    // unlink p
+                    // assert it == null || it.isDetached();
+                    p.clear();
+                    p.next = null;
+                    if (o == null)
+                        head = next;
+                    else
+                        o.next = next;
+                } else {
+                    o = p;
+                }
+                p = next;
+            }
+            if (head == null)   // no more iterators to track
+                itrs = null;
+        }
+
+        /**
+         * Called whenever the queue becomes empty.
+         *
+         * Notifies all active iterators that the queue is empty,
+         * clears all weak refs, and unlinks the itrs datastructure.
+         */
+        void queueIsEmpty() {
+            // assert lock.getHoldCount() == 1;
+            for (Node p = head; p != null; p = p.next) {
+                Itr it = p.get();
+                if (it != null) {
+                    p.clear();
+                    it.shutdown();
+                }
+            }
+            head = null;
+            itrs = null;
+        }
+
+        /**
+         * Called whenever an element has been dequeued (at takeIndex).
+         */
+        void elementDequeued() {
+            // assert lock.getHoldCount() == 1;
+            if (count == 0)
+                queueIsEmpty();
+            else if (takeIndex == 0)
+                takeIndexWrapped();
+        }
+    }
+
+    /**
+     * Iterator for ArrayBlockingQueue.
+     *
+     * To maintain weak consistency with respect to puts and takes, we
+     * read ahead one slot, so as to not report hasNext true but then
+     * not have an element to return.
+     *
+     * We switch into "detached" mode (allowing prompt unlinking from
+     * itrs without help from the GC) when all indices are negative, or
+     * when hasNext returns false for the first time.  This allows the
+     * iterator to track concurrent updates completely accurately,
+     * except for the corner case of the user calling Iterator.remove()
+     * after hasNext() returned false.  Even in this case, we ensure
+     * that we don't remove the wrong element by keeping track of the
+     * expected element to remove, in lastItem.  Yes, we may fail to
+     * remove lastItem from the queue if it moved due to an interleaved
+     * interior remove while in detached mode.
+     */
+    private class Itr implements Iterator<E> {
+        /** Index to look for new nextItem; NONE at end */
+        private int cursor;
+
+        /** Element to be returned by next call to next(); null if none */
+        private E nextItem;
+
+        /** Index of nextItem; NONE if none, REMOVED if removed elsewhere */
+        private int nextIndex;
+
+        /** Last element returned; null if none or not detached. */
+        private E lastItem;
+
+        /** Index of lastItem, NONE if none, REMOVED if removed elsewhere */
+        private int lastRet;
+
+        /** Previous value of takeIndex, or DETACHED when detached */
+        private int prevTakeIndex;
+
+        /** Previous value of iters.cycles */
+        private int prevCycles;
+
+        /** Special index value indicating "not available" or "undefined" */
+        private static final int NONE = -1;
+
+        /**
+         * Special index value indicating "removed elsewhere", that is,
+         * removed by some operation other than a call to this.remove().
+         */
+        private static final int REMOVED = -2;
+
+        /** Special value for prevTakeIndex indicating "detached mode" */
+        private static final int DETACHED = -3;
+
+        Itr() {
+            // assert lock.getHoldCount() == 0;
+            lastRet = NONE;
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (count == 0) {
+                    // assert itrs == null;
+                    cursor = NONE;
+                    nextIndex = NONE;
+                    prevTakeIndex = DETACHED;
+                } else {
+                    final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+                    prevTakeIndex = takeIndex;
+                    nextItem = itemAt(nextIndex = takeIndex);
+                    cursor = incCursor(takeIndex);
+                    if (itrs == null) {
+                        itrs = new Itrs(this);
+                    } else {
+                        itrs.register(this); // in this order
+                        itrs.doSomeSweeping(false);
+                    }
+                    prevCycles = itrs.cycles;
+                    // assert takeIndex >= 0;
+                    // assert prevTakeIndex == takeIndex;
+                    // assert nextIndex >= 0;
+                    // assert nextItem != null;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        boolean isDetached() {
+            // assert lock.getHoldCount() == 1;
+            return prevTakeIndex < 0;
+        }
+
+        private int incCursor(int index) {
+            // assert lock.getHoldCount() == 1;
+            if (++index == items.length) index = 0;
+            if (index == putIndex) index = NONE;
+            return index;
+        }
+
+        /**
+         * Returns true if index is invalidated by the given number of
+         * dequeues, starting from prevTakeIndex.
+         */
+        private boolean invalidated(int index, int prevTakeIndex,
+                                    long dequeues, int length) {
+            if (index < 0)
+                return false;
+            int distance = index - prevTakeIndex;
+            if (distance < 0)
+                distance += length;
+            return dequeues > distance;
+        }
+
+        /**
+         * Adjusts indices to incorporate all dequeues since the last
+         * operation on this iterator.  Call only from iterating thread.
+         */
+        private void incorporateDequeues() {
+            // assert lock.getHoldCount() == 1;
+            // assert itrs != null;
+            // assert !isDetached();
+            // assert count > 0;
+
+            final int cycles = itrs.cycles;
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevCycles = this.prevCycles;
+            final int prevTakeIndex = this.prevTakeIndex;
+
+            if (cycles != prevCycles || takeIndex != prevTakeIndex) {
+                final int len = items.length;
+                // how far takeIndex has advanced since the previous
+                // operation of this iterator
+                long dequeues = (cycles - prevCycles) * len
+                    + (takeIndex - prevTakeIndex);
+
+                // Check indices for invalidation
+                if (invalidated(lastRet, prevTakeIndex, dequeues, len))
+                    lastRet = REMOVED;
+                if (invalidated(nextIndex, prevTakeIndex, dequeues, len))
+                    nextIndex = REMOVED;
+                if (invalidated(cursor, prevTakeIndex, dequeues, len))
+                    cursor = takeIndex;
+
+                if (cursor < 0 && nextIndex < 0 && lastRet < 0)
+                    detach();
+                else {
+                    this.prevCycles = cycles;
+                    this.prevTakeIndex = takeIndex;
+                }
+            }
+        }
+
+        /**
+         * Called when itrs should stop tracking this iterator, either
+         * because there are no more indices to update (cursor < 0 &&
+         * nextIndex < 0 && lastRet < 0) or as a special exception, when
+         * lastRet >= 0, because hasNext() is about to return false for the
+         * first time.  Call only from iterating thread.
+         */
+        private void detach() {
+            // Switch to detached mode
+            // assert lock.getHoldCount() == 1;
+            // assert cursor == NONE;
+            // assert nextIndex < 0;
+            // assert lastRet < 0 || nextItem == null;
+            // assert lastRet < 0 ^ lastItem != null;
+            if (prevTakeIndex >= 0) {
+                // assert itrs != null;
+                prevTakeIndex = DETACHED;
+                // try to unlink from itrs (but not too hard)
+                itrs.doSomeSweeping(true);
+            }
+        }
+
+        /**
+         * For performance reasons, we would like not to acquire a lock in
+         * hasNext in the common case.  To allow for this, we only access
+         * fields (i.e. nextItem) that are not modified by update operations
+         * triggered by queue modifications.
+         */
+        public boolean hasNext() {
+            // assert lock.getHoldCount() == 0;
+            if (nextItem != null)
+                return true;
+            noNext();
+            return false;
+        }
+
+        private void noNext() {
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                // assert cursor == NONE;
+                // assert nextIndex == NONE;
+                if (!isDetached()) {
+                    // assert lastRet >= 0;
+                    incorporateDequeues(); // might update lastRet
+                    if (lastRet >= 0) {
+                        lastItem = itemAt(lastRet);
+                        // assert lastItem != null;
+                        detach();
+                    }
+                }
+                // assert isDetached();
+                // assert lastRet < 0 ^ lastItem != null;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public E next() {
+            // assert lock.getHoldCount() == 0;
+            final E x = nextItem;
+            if (x == null)
+                throw new NoSuchElementException();
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (!isDetached())
+                    incorporateDequeues();
+                // assert nextIndex != NONE;
+                // assert lastItem == null;
+                lastRet = nextIndex;
+                final int cursor = this.cursor;
+                if (cursor >= 0) {
+                    nextItem = itemAt(nextIndex = cursor);
+                    // assert nextItem != null;
+                    this.cursor = incCursor(cursor);
+                } else {
+                    nextIndex = NONE;
+                    nextItem = null;
+                }
+            } finally {
+                lock.unlock();
+            }
+            return x;
+        }
+
+        public void remove() {
+            // assert lock.getHoldCount() == 0;
+            final ReentrantLock lock = ArrayBlockingQueue.this.lock;
+            lock.lock();
+            try {
+                if (!isDetached())
+                    incorporateDequeues(); // might update lastRet or detach
+                final int lastRet = this.lastRet;
+                this.lastRet = NONE;
+                if (lastRet >= 0) {
+                    if (!isDetached())
+                        removeAt(lastRet);
+                    else {
+                        final E lastItem = this.lastItem;
+                        // assert lastItem != null;
+                        this.lastItem = null;
+                        if (itemAt(lastRet) == lastItem)
+                            removeAt(lastRet);
+                    }
+                } else if (lastRet == NONE)
+                    throw new IllegalStateException();
+                // else lastRet == REMOVED and the last returned element was
+                // previously asynchronously removed via an operation other
+                // than this.remove(), so nothing to do.
+
+                if (cursor < 0 && nextIndex < 0)
+                    detach();
+            } finally {
+                lock.unlock();
+                // assert lastRet == NONE;
+                // assert lastItem == null;
+            }
+        }
+
+        /**
+         * Called to notify the iterator that the queue is empty, or that it
+         * has fallen hopelessly behind, so that it should abandon any
+         * further iteration, except possibly to return one more element
+         * from next(), as promised by returning true from hasNext().
+         */
+        void shutdown() {
+            // assert lock.getHoldCount() == 1;
+            cursor = NONE;
+            if (nextIndex >= 0)
+                nextIndex = REMOVED;
+            if (lastRet >= 0) {
+                lastRet = REMOVED;
+                lastItem = null;
+            }
+            prevTakeIndex = DETACHED;
+            // Don't set nextItem to null because we must continue to be
+            // able to return it on next().
+            //
+            // Caller will unlink from itrs when convenient.
+        }
+
+        private int distance(int index, int prevTakeIndex, int length) {
+            int distance = index - prevTakeIndex;
+            if (distance < 0)
+                distance += length;
+            return distance;
+        }
+
+        /**
+         * Called whenever an interior remove (not at takeIndex) occurred.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean removedAt(int removedIndex) {
+            // assert lock.getHoldCount() == 1;
+            if (isDetached())
+                return true;
+
+            final int takeIndex = ArrayBlockingQueue.this.takeIndex;
+            final int prevTakeIndex = this.prevTakeIndex;
+            final int len = items.length;
+            // distance from prevTakeIndex to removedIndex
+            final int removedDistance =
+                len * (itrs.cycles - this.prevCycles
+                       + ((removedIndex < takeIndex) ? 1 : 0))
+                + (removedIndex - prevTakeIndex);
+            // assert itrs.cycles - this.prevCycles >= 0;
+            // assert itrs.cycles - this.prevCycles <= 1;
+            // assert removedDistance > 0;
+            // assert removedIndex != takeIndex;
+            int cursor = this.cursor;
+            if (cursor >= 0) {
+                int x = distance(cursor, prevTakeIndex, len);
+                if (x == removedDistance) {
+                    if (cursor == putIndex)
+                        this.cursor = cursor = NONE;
+                }
+                else if (x > removedDistance) {
+                    // assert cursor != prevTakeIndex;
+                    this.cursor = cursor = dec(cursor);
+                }
+            }
+            int lastRet = this.lastRet;
+            if (lastRet >= 0) {
+                int x = distance(lastRet, prevTakeIndex, len);
+                if (x == removedDistance)
+                    this.lastRet = lastRet = REMOVED;
+                else if (x > removedDistance)
+                    this.lastRet = lastRet = dec(lastRet);
+            }
+            int nextIndex = this.nextIndex;
+            if (nextIndex >= 0) {
+                int x = distance(nextIndex, prevTakeIndex, len);
+                if (x == removedDistance)
+                    this.nextIndex = nextIndex = REMOVED;
+                else if (x > removedDistance)
+                    this.nextIndex = nextIndex = dec(nextIndex);
+            }
+            if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
+                this.prevTakeIndex = DETACHED;
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Called whenever takeIndex wraps around to zero.
+         *
+         * @return true if this iterator should be unlinked from itrs
+         */
+        boolean takeIndexWrapped() {
+            // assert lock.getHoldCount() == 1;
+            if (isDetached())
+                return true;
+            if (itrs.cycles - prevCycles > 1) {
+                // All the elements that existed at the time of the last
+                // operation are gone, so abandon further iteration.
+                shutdown();
+                return true;
+            }
+            return false;
+        }
+
+//         /** Uncomment for debugging. */
+//         public String toString() {
+//             return ("cursor=" + cursor + " " +
+//                     "nextIndex=" + nextIndex + " " +
+//                     "lastRet=" + lastRet + " " +
+//                     "nextItem=" + nextItem + " " +
+//                     "lastItem=" + lastItem + " " +
+//                     "prevCycles=" + prevCycles + " " +
+//                     "prevTakeIndex=" + prevTakeIndex + " " +
+//                     "size()=" + size() + " " +
+//                     "remainingCapacity()=" + remainingCapacity());
+//         }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (this, (Spliterator.ORDERED |
+                    Spliterator.NONNULL |
+                    Spliterator.CONCURRENT));
+    }
+
+}
diff --git a/java/util/concurrent/BlockingDeque.java b/java/util/concurrent/BlockingDeque.java
new file mode 100644
index 0000000..290fee1
--- /dev/null
+++ b/java/util/concurrent/BlockingDeque.java
@@ -0,0 +1,658 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+// BEGIN android-note
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link Deque} that additionally supports blocking operations that wait
+ * for the deque to become non-empty when retrieving an element, and wait for
+ * space to become available in the deque when storing an element.
+ *
+ * <p>{@code BlockingDeque} methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * {@code null} or {@code false}, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up.  These methods are summarized in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of BlockingDeque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 5> <b>First Element (Head)</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #addFirst addFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object) offerFirst(e)}</td>
+ *    <td>{@link #putFirst putFirst(e)}</td>
+ *    <td>{@link #offerFirst(Object, long, TimeUnit) offerFirst(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #removeFirst removeFirst()}</td>
+ *    <td>{@link #pollFirst pollFirst()}</td>
+ *    <td>{@link #takeFirst takeFirst()}</td>
+ *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #getFirst getFirst()}</td>
+ *    <td>{@link #peekFirst peekFirst()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 5> <b>Last Element (Tail)</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #addLast addLast(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *    <td>{@link #putLast putLast(e)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #removeLast() removeLast()}</td>
+ *    <td>{@link #pollLast() pollLast()}</td>
+ *    <td>{@link #takeLast takeLast()}</td>
+ *    <td>{@link #pollLast(long, TimeUnit) pollLast(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #getLast getLast()}</td>
+ *    <td>{@link #peekLast peekLast()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Like any {@link BlockingQueue}, a {@code BlockingDeque} is thread safe,
+ * does not permit null elements, and may (or may not) be
+ * capacity-constrained.
+ *
+ * <p>A {@code BlockingDeque} implementation may be used directly as a FIFO
+ * {@code BlockingQueue}. The methods inherited from the
+ * {@code BlockingQueue} interface are precisely equivalent to
+ * {@code BlockingDeque} methods as indicated in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Comparison of BlockingQueue and BlockingDeque methods</caption>
+ *  <tr>
+ *    <td ALIGN=CENTER> <b>{@code BlockingQueue} Method</b></td>
+ *    <td ALIGN=CENTER> <b>Equivalent {@code BlockingDeque} Method</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Insert</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #add(Object) add(e)}</td>
+ *    <td>{@link #addLast(Object) addLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #offer(Object) offer(e)}</td>
+ *    <td>{@link #offerLast(Object) offerLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #put(Object) put(e)}</td>
+ *    <td>{@link #putLast(Object) putLast(e)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *    <td>{@link #offerLast(Object, long, TimeUnit) offerLast(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Remove</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #remove() remove()}</td>
+ *    <td>{@link #removeFirst() removeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #poll() poll()}</td>
+ *    <td>{@link #pollFirst() pollFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #take() take()}</td>
+ *    <td>{@link #takeFirst() takeFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ *    <td>{@link #pollFirst(long, TimeUnit) pollFirst(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td ALIGN=CENTER COLSPAN = 2> <b>Examine</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #element() element()}</td>
+ *    <td>{@link #getFirst() getFirst()}</td>
+ *  </tr>
+ *  <tr>
+ *    <td>{@link #peek() peek()}</td>
+ *    <td>{@link #peekFirst() peekFirst()}</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingDeque} in another thread.
+ *
+ * <p>This interface is a member of the
+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
+ * Java Collections Framework</a>.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ * @param <E> the type of elements held in this deque
+ */
+public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
+    /*
+     * We have "diamond" multiple interface inheritance here, and that
+     * introduces ambiguities.  Methods might end up with different
+     * specs depending on the branch chosen by javadoc.  Thus a lot of
+     * methods specs here are copied from superinterfaces.
+     */
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use {@link #offerFirst(Object) offerFirst}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void addFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * throwing an {@code IllegalStateException} if no space is currently
+     * available.  When using a capacity-restricted deque, it is generally
+     * preferable to use {@link #offerLast(Object) offerLast}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void addLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * returning {@code true} upon success and {@code false} if no space is
+     * currently available.
+     * When using a capacity-restricted deque, this method is generally
+     * preferable to the {@link #addFirst(Object) addFirst} method, which can
+     * fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    boolean offerFirst(E e);
+
+    /**
+     * Inserts the specified element at the end of this deque if it is
+     * possible to do so immediately without violating capacity restrictions,
+     * returning {@code true} upon success and {@code false} if no space is
+     * currently available.
+     * When using a capacity-restricted deque, this method is generally
+     * preferable to the {@link #addLast(Object) addLast} method, which can
+     * fail to insert an element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    boolean offerLast(E e);
+
+    /**
+     * Inserts the specified element at the front of this deque,
+     * waiting if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void putFirst(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the end of this deque,
+     * waiting if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void putLast(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the front of this deque,
+     * waiting up to the specified wait time if necessary for space to
+     * become available.
+     *
+     * @param e the element to add
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerFirst(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Inserts the specified element at the end of this deque,
+     * waiting up to the specified wait time if necessary for space to
+     * become available.
+     *
+     * @param e the element to add
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offerLast(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the first element of this deque, waiting
+     * if necessary until an element becomes available.
+     *
+     * @return the head of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E takeFirst() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the last element of this deque, waiting
+     * if necessary until an element becomes available.
+     *
+     * @return the tail of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E takeLast() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the first element of this deque, waiting
+     * up to the specified wait time if necessary for an element to
+     * become available.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the head of this deque, or {@code null} if the specified
+     *         waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E pollFirst(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the last element of this deque, waiting
+     * up to the specified wait time if necessary for an element to
+     * become available.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the tail of this deque, or {@code null} if the specified
+     *         waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E pollLast(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeFirstOccurrence(Object o);
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if an element was removed as a result of this call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean removeLastOccurrence(Object o);
+
+    // *** BlockingQueue methods ***
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted deque, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast(Object) addLast}.
+     *
+     * @param e the element to add
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted deque, this method is
+     * generally preferable to the {@link #add} method, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * <p>This method is equivalent to {@link #offerLast(Object) offerLast}.
+     *
+     * @param e the element to add
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e);
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque), waiting if necessary for
+     * space to become available.
+     *
+     * <p>This method is equivalent to {@link #putLast(Object) putLast}.
+     *
+     * @param e the element to add
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    void put(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element into the queue represented by this deque
+     * (in other words, at the tail of this deque), waiting up to the
+     * specified wait time if necessary for space to become available.
+     *
+     * <p>This method is equivalent to
+     * {@link #offerLast(Object,long,TimeUnit) offerLast}.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this deque, else
+     *         {@code false}
+     * @throws InterruptedException {@inheritDoc}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this deque
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this deque
+     */
+    boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque).
+     * This method differs from {@link #poll poll} only in that it
+     * throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E remove();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), or returns
+     * {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #pollFirst()}.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E poll();
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), waiting if
+     * necessary until an element becomes available.
+     *
+     * <p>This method is equivalent to {@link #takeFirst() takeFirst}.
+     *
+     * @return the head of this deque
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque
+     * (in other words, the first element of this deque), waiting up to the
+     * specified wait time if necessary for an element to become available.
+     *
+     * <p>This method is equivalent to
+     * {@link #pollFirst(long,TimeUnit) pollFirst}.
+     *
+     * @return the head of this deque, or {@code null} if the
+     *         specified waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque).
+     * This method differs from {@link #peek peek} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst() getFirst}.
+     *
+     * @return the head of this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    E element();
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque (in other words, the first element of this deque), or
+     * returns {@code null} if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #peekFirst() peekFirst}.
+     *
+     * @return the head of this deque, or {@code null} if this deque is empty
+     */
+    E peek();
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this deque
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    int size();
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    Iterator<E> iterator();
+
+    // *** Stack methods ***
+
+    /**
+     * Pushes an element onto the stack represented by this deque (in other
+     * words, at the head of this deque) if it is possible to do so
+     * immediately without violating capacity restrictions, throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     *
+     * <p>This method is equivalent to {@link #addFirst(Object) addFirst}.
+     *
+     * @throws IllegalStateException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    void push(E e);
+}
diff --git a/java/util/concurrent/BlockingQueue.java b/java/util/concurrent/BlockingQueue.java
new file mode 100644
index 0000000..6f01b77
--- /dev/null
+++ b/java/util/concurrent/BlockingQueue.java
@@ -0,0 +1,377 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.Queue;
+
+// BEGIN android-note
+// removed link to collections framework docs from header
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link java.util.Queue} that additionally supports operations
+ * that wait for the queue to become non-empty when retrieving an
+ * element, and wait for space to become available in the queue when
+ * storing an element.
+ *
+ * <p>{@code BlockingQueue} methods come in four forms, with different ways
+ * of handling operations that cannot be satisfied immediately, but may be
+ * satisfied at some point in the future:
+ * one throws an exception, the second returns a special value (either
+ * {@code null} or {@code false}, depending on the operation), the third
+ * blocks the current thread indefinitely until the operation can succeed,
+ * and the fourth blocks for only a given maximum time limit before giving
+ * up.  These methods are summarized in the following table:
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of BlockingQueue methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER><em>Throws exception</em></td>
+ *    <td ALIGN=CENTER><em>Special value</em></td>
+ *    <td ALIGN=CENTER><em>Blocks</em></td>
+ *    <td ALIGN=CENTER><em>Times out</em></td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Insert</b></td>
+ *    <td>{@link #add add(e)}</td>
+ *    <td>{@link #offer offer(e)}</td>
+ *    <td>{@link #put put(e)}</td>
+ *    <td>{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Remove</b></td>
+ *    <td>{@link #remove remove()}</td>
+ *    <td>{@link #poll poll()}</td>
+ *    <td>{@link #take take()}</td>
+ *    <td>{@link #poll(long, TimeUnit) poll(time, unit)}</td>
+ *  </tr>
+ *  <tr>
+ *    <td><b>Examine</b></td>
+ *    <td>{@link #element element()}</td>
+ *    <td>{@link #peek peek()}</td>
+ *    <td><em>not applicable</em></td>
+ *    <td><em>not applicable</em></td>
+ *  </tr>
+ * </table>
+ *
+ * <p>A {@code BlockingQueue} does not accept {@code null} elements.
+ * Implementations throw {@code NullPointerException} on attempts
+ * to {@code add}, {@code put} or {@code offer} a {@code null}.  A
+ * {@code null} is used as a sentinel value to indicate failure of
+ * {@code poll} operations.
+ *
+ * <p>A {@code BlockingQueue} may be capacity bounded. At any given
+ * time it may have a {@code remainingCapacity} beyond which no
+ * additional elements can be {@code put} without blocking.
+ * A {@code BlockingQueue} without any intrinsic capacity constraints always
+ * reports a remaining capacity of {@code Integer.MAX_VALUE}.
+ *
+ * <p>{@code BlockingQueue} implementations are designed to be used
+ * primarily for producer-consumer queues, but additionally support
+ * the {@link java.util.Collection} interface.  So, for example, it is
+ * possible to remove an arbitrary element from a queue using
+ * {@code remove(x)}. However, such operations are in general
+ * <em>not</em> performed very efficiently, and are intended for only
+ * occasional use, such as when a queued message is cancelled.
+ *
+ * <p>{@code BlockingQueue} implementations are thread-safe.  All
+ * queuing methods achieve their effects atomically using internal
+ * locks or other forms of concurrency control. However, the
+ * <em>bulk</em> Collection operations {@code addAll},
+ * {@code containsAll}, {@code retainAll} and {@code removeAll} are
+ * <em>not</em> necessarily performed atomically unless specified
+ * otherwise in an implementation. So it is possible, for example, for
+ * {@code addAll(c)} to fail (throwing an exception) after adding
+ * only some of the elements in {@code c}.
+ *
+ * <p>A {@code BlockingQueue} does <em>not</em> intrinsically support
+ * any kind of &quot;close&quot; or &quot;shutdown&quot; operation to
+ * indicate that no more items will be added.  The needs and usage of
+ * such features tend to be implementation-dependent. For example, a
+ * common tactic is for producers to insert special
+ * <em>end-of-stream</em> or <em>poison</em> objects, that are
+ * interpreted accordingly when taken by consumers.
+ *
+ * <p>
+ * Usage example, based on a typical producer-consumer scenario.
+ * Note that a {@code BlockingQueue} can safely be used with multiple
+ * producers and multiple consumers.
+ * <pre> {@code
+ * class Producer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Producer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { queue.put(produce()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   Object produce() { ... }
+ * }
+ *
+ * class Consumer implements Runnable {
+ *   private final BlockingQueue queue;
+ *   Consumer(BlockingQueue q) { queue = q; }
+ *   public void run() {
+ *     try {
+ *       while (true) { consume(queue.take()); }
+ *     } catch (InterruptedException ex) { ... handle ...}
+ *   }
+ *   void consume(Object x) { ... }
+ * }
+ *
+ * class Setup {
+ *   void main() {
+ *     BlockingQueue q = new SomeQueueImplementation();
+ *     Producer p = new Producer(q);
+ *     Consumer c1 = new Consumer(q);
+ *     Consumer c2 = new Consumer(q);
+ *     new Thread(p).start();
+ *     new Thread(c1).start();
+ *     new Thread(c2).start();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code BlockingQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code BlockingQueue} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface BlockingQueue<E> extends Queue<E> {
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions, returning
+     * {@code true} upon success and throwing an
+     * {@code IllegalStateException} if no space is currently available.
+     * When using a capacity-restricted queue, it is generally preferable to
+     * use {@link #offer(Object) offer}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws IllegalStateException if the element cannot be added at this
+     *         time due to capacity restrictions
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean add(E e);
+
+    /**
+     * Inserts the specified element into this queue if it is possible to do
+     * so immediately without violating capacity restrictions, returning
+     * {@code true} upon success and {@code false} if no space is currently
+     * available.  When using a capacity-restricted queue, this method is
+     * generally preferable to {@link #add}, which can fail to insert an
+     * element only by throwing an exception.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean offer(E e);
+
+    /**
+     * Inserts the specified element into this queue, waiting if necessary
+     * for space to become available.
+     *
+     * @param e the element to add
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    void put(E e) throws InterruptedException;
+
+    /**
+     * Inserts the specified element into this queue, waiting up to the
+     * specified wait time if necessary for space to become available.
+     *
+     * @param e the element to add
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException if interrupted while waiting
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element becomes available.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the head of this queue, waiting up to the
+     * specified wait time if necessary for an element to become available.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element is available
+     * @throws InterruptedException if interrupted while waiting
+     */
+    E poll(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking, or {@code Integer.MAX_VALUE} if there is no intrinsic
+     * limit.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     *
+     * @return the remaining capacity
+     */
+    int remainingCapacity();
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this queue
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object o);
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     * @throws ClassCastException if the class of the specified element
+     *         is incompatible with this queue
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified element is null
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean contains(Object o);
+
+    /**
+     * Removes all available elements from this queue and adds them
+     * to the given collection.  This operation may be more
+     * efficient than repeatedly polling this queue.  A failure
+     * encountered while attempting to add elements to
+     * collection {@code c} may result in elements being in neither,
+     * either or both collections when the associated exception is
+     * thrown.  Attempts to drain a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @return the number of elements transferred
+     * @throws UnsupportedOperationException if addition of elements
+     *         is not supported by the specified collection
+     * @throws ClassCastException if the class of an element of this queue
+     *         prevents it from being added to the specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @throws IllegalArgumentException if the specified collection is this
+     *         queue, or some property of an element of this queue prevents
+     *         it from being added to the specified collection
+     */
+    int drainTo(Collection<? super E> c);
+
+    /**
+     * Removes at most the given number of available elements from
+     * this queue and adds them to the given collection.  A failure
+     * encountered while attempting to add elements to
+     * collection {@code c} may result in elements being in neither,
+     * either or both collections when the associated exception is
+     * thrown.  Attempts to drain a queue to itself result in
+     * {@code IllegalArgumentException}. Further, the behavior of
+     * this operation is undefined if the specified collection is
+     * modified while the operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @param maxElements the maximum number of elements to transfer
+     * @return the number of elements transferred
+     * @throws UnsupportedOperationException if addition of elements
+     *         is not supported by the specified collection
+     * @throws ClassCastException if the class of an element of this queue
+     *         prevents it from being added to the specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @throws IllegalArgumentException if the specified collection is this
+     *         queue, or some property of an element of this queue prevents
+     *         it from being added to the specified collection
+     */
+    int drainTo(Collection<? super E> c, int maxElements);
+}
diff --git a/java/util/concurrent/BrokenBarrierException.java b/java/util/concurrent/BrokenBarrierException.java
new file mode 100644
index 0000000..11f126e
--- /dev/null
+++ b/java/util/concurrent/BrokenBarrierException.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when a thread tries to wait upon a barrier that is
+ * in a broken state, or which enters the broken state while the thread
+ * is waiting.
+ *
+ * @see CyclicBarrier
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class BrokenBarrierException extends Exception {
+    private static final long serialVersionUID = 7117394618823254244L;
+
+    /**
+     * Constructs a {@code BrokenBarrierException} with no specified detail
+     * message.
+     */
+    public BrokenBarrierException() {}
+
+    /**
+     * Constructs a {@code BrokenBarrierException} with the specified
+     * detail message.
+     *
+     * @param message the detail message
+     */
+    public BrokenBarrierException(String message) {
+        super(message);
+    }
+}
diff --git a/java/util/concurrent/Callable.java b/java/util/concurrent/Callable.java
new file mode 100644
index 0000000..04bc607
--- /dev/null
+++ b/java/util/concurrent/Callable.java
@@ -0,0 +1,66 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A task that returns a result and may throw an exception.
+ * Implementors define a single method with no arguments called
+ * {@code call}.
+ *
+ * <p>The {@code Callable} interface is similar to {@link
+ * java.lang.Runnable}, in that both are designed for classes whose
+ * instances are potentially executed by another thread.  A
+ * {@code Runnable}, however, does not return a result and cannot
+ * throw a checked exception.
+ *
+ * <p>The {@link Executors} class contains utility methods to
+ * convert from other common forms to {@code Callable} classes.
+ *
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> the result type of method {@code call}
+ */
+@FunctionalInterface
+public interface Callable<V> {
+    /**
+     * Computes a result, or throws an exception if unable to do so.
+     *
+     * @return computed result
+     * @throws Exception if unable to compute a result
+     */
+    V call() throws Exception;
+}
diff --git a/java/util/concurrent/CancellationException.java b/java/util/concurrent/CancellationException.java
new file mode 100644
index 0000000..bd35173
--- /dev/null
+++ b/java/util/concurrent/CancellationException.java
@@ -0,0 +1,63 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception indicating that the result of a value-producing task,
+ * such as a {@link FutureTask}, cannot be retrieved because the task
+ * was cancelled.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CancellationException extends IllegalStateException {
+    private static final long serialVersionUID = -9202173006928992231L;
+
+    /**
+     * Constructs a {@code CancellationException} with no detail message.
+     */
+    public CancellationException() {}
+
+    /**
+     * Constructs a {@code CancellationException} with the specified detail
+     * message.
+     *
+     * @param message the detail message
+     */
+    public CancellationException(String message) {
+        super(message);
+    }
+}
diff --git a/java/util/concurrent/CompletableFuture.annotated.java b/java/util/concurrent/CompletableFuture.annotated.java
new file mode 100644
index 0000000..5ac5a83
--- /dev/null
+++ b/java/util/concurrent/CompletableFuture.annotated.java
@@ -0,0 +1,195 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util.concurrent;
+
+import java.util.function.Supplier;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class CompletableFuture<T> implements java.util.concurrent.Future<T>, java.util.concurrent.CompletionStage<T> {
+
+public CompletableFuture() { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U> supplier) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletableFuture<U> supplyAsync(java.util.function.Supplier<U> supplier, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable runnable) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Void> runAsync(java.lang.Runnable runnable, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletableFuture<U> completedFuture(U value) { throw new RuntimeException("Stub!"); }
+
+public boolean isDone() { throw new RuntimeException("Stub!"); }
+
+public T get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException { throw new RuntimeException("Stub!"); }
+
+public T get(long timeout, java.util.concurrent.TimeUnit unit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException { throw new RuntimeException("Stub!"); }
+
+public T join() { throw new RuntimeException("Stub!"); }
+
+public T getNow(T valueIfAbsent) { throw new RuntimeException("Stub!"); }
+
+public boolean complete(T value) { throw new RuntimeException("Stub!"); }
+
+public boolean completeExceptionally(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenApply(java.util.function.Function<? super T,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenApplyAsync(java.util.function.Function<? super T,? extends U> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenAccept(java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptAsync(java.util.function.Consumer<? super T> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenRun(java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> thenRunAsync(java.lang.Runnable action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U, V> java.util.concurrent.CompletableFuture<V> thenCombine(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiFunction<? super T,? super U,? extends V> fn) { throw new RuntimeException("Stub!"); }
+
+public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiFunction<? super T,? super U,? extends V> fn) { throw new RuntimeException("Stub!"); }
+
+public <U, V> java.util.concurrent.CompletableFuture<V> thenCombineAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiFunction<? super T,? super U,? extends V> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBoth(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiConsumer<? super T,? super U> action) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiConsumer<? super T,? super U> action) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<java.lang.Void> thenAcceptBothAsync(java.util.concurrent.CompletionStage<? extends U> other, java.util.function.BiConsumer<? super T,? super U> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBoth(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterBothAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> applyToEither(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Function<? super T,U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Function<? super T,U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> applyToEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Function<? super T,U> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEither(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Consumer<? super T> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> acceptEitherAsync(java.util.concurrent.CompletionStage<? extends T> other, java.util.function.Consumer<? super T> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEither(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<java.lang.Void> runAfterEitherAsync(java.util.concurrent.CompletionStage<?> other, java.lang.Runnable action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenCompose(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> thenComposeAsync(java.util.function.Function<? super T,? extends java.util.concurrent.CompletionStage<U>> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> whenComplete(java.util.function.BiConsumer<? super T,? super java.lang.Throwable> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable> action) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> whenCompleteAsync(java.util.function.BiConsumer<? super T,? super java.lang.Throwable> action, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> handle(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U> fn) { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> handleAsync(java.util.function.BiFunction<? super T,java.lang.Throwable,? extends U> fn, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> toCompletableFuture() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> exceptionally(java.util.function.Function<java.lang.Throwable,? extends T> fn) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Void> allOf(java.util.concurrent.CompletableFuture<?>... cfs) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.CompletableFuture<java.lang.Object> anyOf(java.util.concurrent.CompletableFuture<?>... cfs) { throw new RuntimeException("Stub!"); }
+
+public boolean cancel(boolean mayInterruptIfRunning) { throw new RuntimeException("Stub!"); }
+
+public boolean isCancelled() { throw new RuntimeException("Stub!"); }
+
+public boolean isCompletedExceptionally() { throw new RuntimeException("Stub!"); }
+
+public void obtrudeValue(T value) { throw new RuntimeException("Stub!"); }
+
+public void obtrudeException(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+
+public int getNumberOfDependents() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public <U> java.util.concurrent.CompletableFuture<U> newIncompleteFuture() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.Executor defaultExecutor() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> copy() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletionStage<T> minimalCompletionStage() { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> completeAsync(java.util.function.Supplier<? extends T> supplier, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> completeAsync(java.util.function.Supplier<? extends T> supplier) { throw new RuntimeException("Stub!"); }
+
+public java.util.concurrent.CompletableFuture<T> orTimeout(long timeout, java.util.concurrent.TimeUnit unit) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public java.util.concurrent.CompletableFuture<T> completeOnTimeout(T value, long timeout, java.util.concurrent.TimeUnit unit) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.Executor delayedExecutor(long delay, java.util.concurrent.TimeUnit unit, java.util.concurrent.Executor executor) { throw new RuntimeException("Stub!"); }
+
+public static java.util.concurrent.Executor delayedExecutor(long delay, java.util.concurrent.TimeUnit unit) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletionStage<U> completedStage(U value) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public static <U> java.util.concurrent.CompletableFuture<U> failedFuture(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+
+public static <U> java.util.concurrent.CompletionStage<U> failedStage(java.lang.Throwable ex) { throw new RuntimeException("Stub!"); }
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public static interface AsynchronousCompletionTask {
+}
+
+}
diff --git a/java/util/concurrent/CompletableFuture.java b/java/util/concurrent/CompletableFuture.java
new file mode 100644
index 0000000..976bfe4
--- /dev/null
+++ b/java/util/concurrent/CompletableFuture.java
@@ -0,0 +1,2788 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+// Android-note: Class javadoc changed to remove references to hidden OpenJDK 9 methods.
+
+/**
+ * A {@link Future} that may be explicitly completed (setting its
+ * value and status), and may be used as a {@link CompletionStage},
+ * supporting dependent functions and actions that trigger upon its
+ * completion.
+ *
+ * <p>When two or more threads attempt to
+ * {@link #complete complete},
+ * {@link #completeExceptionally completeExceptionally}, or
+ * {@link #cancel cancel}
+ * a CompletableFuture, only one of them succeeds.
+ *
+ * <p>In addition to these and related methods for directly
+ * manipulating status and results, CompletableFuture implements
+ * interface {@link CompletionStage} with the following policies: <ul>
+ *
+ * <li>Actions supplied for dependent completions of
+ * <em>non-async</em> methods may be performed by the thread that
+ * completes the current CompletableFuture, or by any other caller of
+ * a completion method.
+ *
+ * <li>All <em>async</em> methods without an explicit Executor
+ * argument are performed using the {@link ForkJoinPool#commonPool()}
+ * (unless it does not support a parallelism level of at least two, in
+ * which case, a new Thread is created to run each task).
+ * To simplify monitoring, debugging,
+ * and tracking, all generated asynchronous tasks are instances of the
+ * marker interface {@link AsynchronousCompletionTask}.  Operations
+ * with time-delays can use adapter methods defined in this class, for
+ * example: {@code supplyAsync(supplier, delayedExecutor(timeout,
+ * timeUnit))}.  To support methods with delays and timeouts, this
+ * class maintains at most one daemon thread for triggering and
+ * cancelling actions, not for running them.
+ *
+ * <li>All CompletionStage methods are implemented independently of
+ * other public methods, so the behavior of one method is not impacted
+ * by overrides of others in subclasses.
+ *
+ * </ul>
+ *
+ * <p>CompletableFuture also implements {@link Future} with the following
+ * policies: <ul>
+ *
+ * <li>Since (unlike {@link FutureTask}) this class has no direct
+ * control over the computation that causes it to be completed,
+ * cancellation is treated as just another form of exceptional
+ * completion.  Method {@link #cancel cancel} has the same effect as
+ * {@code completeExceptionally(new CancellationException())}. Method
+ * {@link #isCompletedExceptionally} can be used to determine if a
+ * CompletableFuture completed in any exceptional fashion.
+ *
+ * <li>In case of exceptional completion with a CompletionException,
+ * methods {@link #get()} and {@link #get(long, TimeUnit)} throw an
+ * {@link ExecutionException} with the same cause as held in the
+ * corresponding CompletionException.  To simplify usage in most
+ * contexts, this class also defines methods {@link #join()} and
+ * {@link #getNow} that instead throw the CompletionException directly
+ * in these cases.
+ * </ul>
+ *
+ * <p>Arguments used to pass a completion result (that is, for
+ * parameters of type {@code T}) for methods accepting them may be
+ * null, but passing a null value for any other parameter will result
+ * in a {@link NullPointerException} being thrown.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ * @param <T> The result type returned by this future's {@code join}
+ * and {@code get} methods
+ */
+public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
+
+    /*
+     * Overview:
+     *
+     * A CompletableFuture may have dependent completion actions,
+     * collected in a linked stack. It atomically completes by CASing
+     * a result field, and then pops off and runs those actions. This
+     * applies across normal vs exceptional outcomes, sync vs async
+     * actions, binary triggers, and various forms of completions.
+     *
+     * Non-nullness of field result (set via CAS) indicates done.  An
+     * AltResult is used to box null as a result, as well as to hold
+     * exceptions.  Using a single field makes completion simple to
+     * detect and trigger.  Encoding and decoding is straightforward
+     * but adds to the sprawl of trapping and associating exceptions
+     * with targets.  Minor simplifications rely on (static) NIL (to
+     * box null results) being the only AltResult with a null
+     * exception field, so we don't usually need explicit comparisons.
+     * Even though some of the generics casts are unchecked (see
+     * SuppressWarnings annotations), they are placed to be
+     * appropriate even if checked.
+     *
+     * Dependent actions are represented by Completion objects linked
+     * as Treiber stacks headed by field "stack". There are Completion
+     * classes for each kind of action, grouped into single-input
+     * (UniCompletion), two-input (BiCompletion), projected
+     * (BiCompletions using either (not both) of two inputs), shared
+     * (CoCompletion, used by the second of two sources), zero-input
+     * source actions, and Signallers that unblock waiters. Class
+     * Completion extends ForkJoinTask to enable async execution
+     * (adding no space overhead because we exploit its "tag" methods
+     * to maintain claims). It is also declared as Runnable to allow
+     * usage with arbitrary executors.
+     *
+     * Support for each kind of CompletionStage relies on a separate
+     * class, along with two CompletableFuture methods:
+     *
+     * * A Completion class with name X corresponding to function,
+     *   prefaced with "Uni", "Bi", or "Or". Each class contains
+     *   fields for source(s), actions, and dependent. They are
+     *   boringly similar, differing from others only with respect to
+     *   underlying functional forms. We do this so that users don't
+     *   encounter layers of adapters in common usages.
+     *
+     * * Boolean CompletableFuture method x(...) (for example
+     *   uniApply) takes all of the arguments needed to check that an
+     *   action is triggerable, and then either runs the action or
+     *   arranges its async execution by executing its Completion
+     *   argument, if present. The method returns true if known to be
+     *   complete.
+     *
+     * * Completion method tryFire(int mode) invokes the associated x
+     *   method with its held arguments, and on success cleans up.
+     *   The mode argument allows tryFire to be called twice (SYNC,
+     *   then ASYNC); the first to screen and trap exceptions while
+     *   arranging to execute, and the second when called from a
+     *   task. (A few classes are not used async so take slightly
+     *   different forms.)  The claim() callback suppresses function
+     *   invocation if already claimed by another thread.
+     *
+     * * CompletableFuture method xStage(...) is called from a public
+     *   stage method of CompletableFuture x. It screens user
+     *   arguments and invokes and/or creates the stage object.  If
+     *   not async and x is already complete, the action is run
+     *   immediately.  Otherwise a Completion c is created, pushed to
+     *   x's stack (unless done), and started or triggered via
+     *   c.tryFire.  This also covers races possible if x completes
+     *   while pushing.  Classes with two inputs (for example BiApply)
+     *   deal with races across both while pushing actions.  The
+     *   second completion is a CoCompletion pointing to the first,
+     *   shared so that at most one performs the action.  The
+     *   multiple-arity methods allOf and anyOf do this pairwise to
+     *   form trees of completions.
+     *
+     * Note that the generic type parameters of methods vary according
+     * to whether "this" is a source, dependent, or completion.
+     *
+     * Method postComplete is called upon completion unless the target
+     * is guaranteed not to be observable (i.e., not yet returned or
+     * linked). Multiple threads can call postComplete, which
+     * atomically pops each dependent action, and tries to trigger it
+     * via method tryFire, in NESTED mode.  Triggering can propagate
+     * recursively, so NESTED mode returns its completed dependent (if
+     * one exists) for further processing by its caller (see method
+     * postFire).
+     *
+     * Blocking methods get() and join() rely on Signaller Completions
+     * that wake up waiting threads.  The mechanics are similar to
+     * Treiber stack wait-nodes used in FutureTask, Phaser, and
+     * SynchronousQueue. See their internal documentation for
+     * algorithmic details.
+     *
+     * Without precautions, CompletableFutures would be prone to
+     * garbage accumulation as chains of Completions build up, each
+     * pointing back to its sources. So we null out fields as soon as
+     * possible.  The screening checks needed anyway harmlessly ignore
+     * null arguments that may have been obtained during races with
+     * threads nulling out fields.  We also try to unlink fired
+     * Completions from stacks that might never be popped (see method
+     * postFire).  Completion fields need not be declared as final or
+     * volatile because they are only visible to other threads upon
+     * safe publication.
+     */
+
+    volatile Object result;       // Either the result or boxed AltResult
+    volatile Completion stack;    // Top of Treiber stack of dependent actions
+
+    final boolean internalComplete(Object r) { // CAS from null to r
+        return U.compareAndSwapObject(this, RESULT, null, r);
+    }
+
+    final boolean casStack(Completion cmp, Completion val) {
+        return U.compareAndSwapObject(this, STACK, cmp, val);
+    }
+
+    /** Returns true if successfully pushed c onto stack. */
+    final boolean tryPushStack(Completion c) {
+        Completion h = stack;
+        lazySetNext(c, h);
+        return U.compareAndSwapObject(this, STACK, h, c);
+    }
+
+    /** Unconditionally pushes c onto stack, retrying if necessary. */
+    final void pushStack(Completion c) {
+        do {} while (!tryPushStack(c));
+    }
+
+    /* ------------- Encoding and decoding outcomes -------------- */
+
+    static final class AltResult { // See above
+        final Throwable ex;        // null only for NIL
+        AltResult(Throwable x) { this.ex = x; }
+    }
+
+    /** The encoding of the null value. */
+    static final AltResult NIL = new AltResult(null);
+
+    /** Completes with the null value, unless already completed. */
+    final boolean completeNull() {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      NIL);
+    }
+
+    /** Returns the encoding of the given non-exceptional value. */
+    final Object encodeValue(T t) {
+        return (t == null) ? NIL : t;
+    }
+
+    /** Completes with a non-exceptional result, unless already completed. */
+    final boolean completeValue(T t) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      (t == null) ? NIL : t);
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.
+     */
+    static AltResult encodeThrowable(Throwable x) {
+        return new AltResult((x instanceof CompletionException) ? x :
+                             new CompletionException(x));
+    }
+
+    /** Completes with an exceptional result, unless already completed. */
+    final boolean completeThrowable(Throwable x) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeThrowable(x));
+    }
+
+    /**
+     * Returns the encoding of the given (non-null) exception as a
+     * wrapped CompletionException unless it is one already.  May
+     * return the given Object r (which must have been the result of a
+     * source future) if it is equivalent, i.e. if this is a simple
+     * relay of an existing CompletionException.
+     */
+    static Object encodeThrowable(Throwable x, Object r) {
+        if (!(x instanceof CompletionException))
+            x = new CompletionException(x);
+        else if (r instanceof AltResult && x == ((AltResult)r).ex)
+            return r;
+        return new AltResult(x);
+    }
+
+    /**
+     * Completes with the given (non-null) exceptional result as a
+     * wrapped CompletionException unless it is one already, unless
+     * already completed.  May complete with the given Object r
+     * (which must have been the result of a source future) if it is
+     * equivalent, i.e. if this is a simple propagation of an
+     * existing CompletionException.
+     */
+    final boolean completeThrowable(Throwable x, Object r) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeThrowable(x, r));
+    }
+
+    /**
+     * Returns the encoding of the given arguments: if the exception
+     * is non-null, encodes as AltResult.  Otherwise uses the given
+     * value, boxed as NIL if null.
+     */
+    Object encodeOutcome(T t, Throwable x) {
+        return (x == null) ? (t == null) ? NIL : t : encodeThrowable(x);
+    }
+
+    /**
+     * Returns the encoding of a copied outcome; if exceptional,
+     * rewraps as a CompletionException, else returns argument.
+     */
+    static Object encodeRelay(Object r) {
+        Throwable x;
+        return (((r instanceof AltResult) &&
+                 (x = ((AltResult)r).ex) != null &&
+                 !(x instanceof CompletionException)) ?
+                new AltResult(new CompletionException(x)) : r);
+    }
+
+    /**
+     * Completes with r or a copy of r, unless already completed.
+     * If exceptional, r is first coerced to a CompletionException.
+     */
+    final boolean completeRelay(Object r) {
+        return U.compareAndSwapObject(this, RESULT, null,
+                                      encodeRelay(r));
+    }
+
+    /**
+     * Reports result using Future.get conventions.
+     */
+    private static <T> T reportGet(Object r)
+        throws InterruptedException, ExecutionException {
+        if (r == null) // by convention below, null means interrupted
+            throw new InterruptedException();
+        if (r instanceof AltResult) {
+            Throwable x, cause;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if ((x instanceof CompletionException) &&
+                (cause = x.getCause()) != null)
+                x = cause;
+            throw new ExecutionException(x);
+        }
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
+    }
+
+    /**
+     * Decodes outcome to return result or throw unchecked exception.
+     */
+    private static <T> T reportJoin(Object r) {
+        if (r instanceof AltResult) {
+            Throwable x;
+            if ((x = ((AltResult)r).ex) == null)
+                return null;
+            if (x instanceof CancellationException)
+                throw (CancellationException)x;
+            if (x instanceof CompletionException)
+                throw (CompletionException)x;
+            throw new CompletionException(x);
+        }
+        @SuppressWarnings("unchecked") T t = (T) r;
+        return t;
+    }
+
+    /* ------------- Async task preliminaries -------------- */
+
+    /**
+     * A marker interface identifying asynchronous tasks produced by
+     * {@code async} methods. This may be useful for monitoring,
+     * debugging, and tracking asynchronous activities.
+     *
+     * @since 1.8
+     */
+    public static interface AsynchronousCompletionTask {
+    }
+
+    private static final boolean USE_COMMON_POOL =
+        (ForkJoinPool.getCommonPoolParallelism() > 1);
+
+    /**
+     * Default executor -- ForkJoinPool.commonPool() unless it cannot
+     * support parallelism.
+     */
+    private static final Executor ASYNC_POOL = USE_COMMON_POOL ?
+        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
+
+    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
+    static final class ThreadPerTaskExecutor implements Executor {
+        public void execute(Runnable r) { new Thread(r).start(); }
+    }
+
+    /**
+     * Null-checks user executor argument, and translates uses of
+     * commonPool to ASYNC_POOL in case parallelism disabled.
+     */
+    static Executor screenExecutor(Executor e) {
+        if (!USE_COMMON_POOL && e == ForkJoinPool.commonPool())
+            return ASYNC_POOL;
+        if (e == null) throw new NullPointerException();
+        return e;
+    }
+
+    // Modes for Completion.tryFire. Signedness matters.
+    static final int SYNC   =  0;
+    static final int ASYNC  =  1;
+    static final int NESTED = -1;
+
+    /**
+     * Spins before blocking in waitingGet
+     */
+    static final int SPINS = (Runtime.getRuntime().availableProcessors() > 1 ?
+                              1 << 8 : 0);
+
+    /* ------------- Base Completion classes and operations -------------- */
+
+    @SuppressWarnings("serial")
+    abstract static class Completion extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        volatile Completion next;      // Treiber stack link
+
+        /**
+         * Performs completion action if triggered, returning a
+         * dependent that may need propagation, if one exists.
+         *
+         * @param mode SYNC, ASYNC, or NESTED
+         */
+        abstract CompletableFuture<?> tryFire(int mode);
+
+        /** Returns true if possibly still triggerable. Used by cleanStack. */
+        abstract boolean isLive();
+
+        public final void run()                { tryFire(ASYNC); }
+        public final boolean exec()            { tryFire(ASYNC); return false; }
+        public final Void getRawResult()       { return null; }
+        public final void setRawResult(Void v) {}
+    }
+
+    static void lazySetNext(Completion c, Completion next) {
+        U.putOrderedObject(c, NEXT, next);
+    }
+
+    /**
+     * Pops and tries to trigger all reachable dependents.  Call only
+     * when known to be done.
+     */
+    final void postComplete() {
+        /*
+         * On each step, variable f holds current dependents to pop
+         * and run.  It is extended along only one path at a time,
+         * pushing others to avoid unbounded recursion.
+         */
+        CompletableFuture<?> f = this; Completion h;
+        while ((h = f.stack) != null ||
+               (f != this && (h = (f = this).stack) != null)) {
+            CompletableFuture<?> d; Completion t;
+            if (f.casStack(h, t = h.next)) {
+                if (t != null) {
+                    if (f != this) {
+                        pushStack(h);
+                        continue;
+                    }
+                    h.next = null;    // detach
+                }
+                f = (d = h.tryFire(NESTED)) == null ? this : d;
+            }
+        }
+    }
+
+    /** Traverses stack and unlinks dead Completions. */
+    final void cleanStack() {
+        for (Completion p = null, q = stack; q != null;) {
+            Completion s = q.next;
+            if (q.isLive()) {
+                p = q;
+                q = s;
+            }
+            else if (p == null) {
+                casStack(q, s);
+                q = stack;
+            }
+            else {
+                p.next = s;
+                if (p.isLive())
+                    q = s;
+                else {
+                    p = null;  // restart
+                    q = stack;
+                }
+            }
+        }
+    }
+
+    /* ------------- One-input Completions -------------- */
+
+    /** A Completion with a source, dependent, and executor. */
+    @SuppressWarnings("serial")
+    abstract static class UniCompletion<T,V> extends Completion {
+        Executor executor;                 // executor to use (null if none)
+        CompletableFuture<V> dep;          // the dependent to complete
+        CompletableFuture<T> src;          // source for action
+
+        UniCompletion(Executor executor, CompletableFuture<V> dep,
+                      CompletableFuture<T> src) {
+            this.executor = executor; this.dep = dep; this.src = src;
+        }
+
+        /**
+         * Returns true if action can be run. Call only when known to
+         * be triggerable. Uses FJ tag bit to ensure that only one
+         * thread claims ownership.  If async, starts as task -- a
+         * later call to tryFire will run action.
+         */
+        final boolean claim() {
+            Executor e = executor;
+            if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
+                if (e == null)
+                    return true;
+                executor = null; // disable
+                e.execute(this);
+            }
+            return false;
+        }
+
+        final boolean isLive() { return dep != null; }
+    }
+
+    /** Pushes the given completion (if it exists) unless done. */
+    final void push(UniCompletion<?,?> c) {
+        if (c != null) {
+            while (result == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
+        }
+    }
+
+    /**
+     * Post-processing by dependent after successful UniCompletion
+     * tryFire.  Tries to clean stack of source a, and then either runs
+     * postComplete or returns this to caller, depending on mode.
+     */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
+        if (a != null && a.stack != null) {
+            if (mode < 0 || a.result == null)
+                a.cleanStack();
+            else
+                a.postComplete();
+        }
+        if (result != null && stack != null) {
+            if (mode < 0)
+                return this;
+            else
+                postComplete();
+        }
+        return null;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniApply<T,V> extends UniCompletion<T,V> {
+        Function<? super T,? extends V> fn;
+        UniApply(Executor executor, CompletableFuture<V> dep,
+                 CompletableFuture<T> src,
+                 Function<? super T,? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniApply(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniApply(CompletableFuture<S> a,
+                               Function<? super S,? extends T> f,
+                               UniApply<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                completeValue(f.apply(s));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniApplyStage(
+        Executor e, Function<? super T,? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.uniApply(this, f, null)) {
+            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniAccept<T> extends UniCompletion<T,Void> {
+        Consumer<? super T> fn;
+        UniAccept(Executor executor, CompletableFuture<Void> dep,
+                  CompletableFuture<T> src, Consumer<? super T> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniAccept(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniAccept(CompletableFuture<S> a,
+                                Consumer<? super S> f, UniAccept<S> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                f.accept(s);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> uniAcceptStage(Executor e,
+                                                   Consumer<? super T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.uniAccept(this, f, null)) {
+            UniAccept<T> c = new UniAccept<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRun<T> extends UniCompletion<T,Void> {
+        Runnable fn;
+        UniRun(Executor executor, CompletableFuture<Void> dep,
+               CompletableFuture<T> src, Runnable fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniRun(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniRun(CompletableFuture<?> a, Runnable f, UniRun<?> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> uniRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.uniRun(this, f, null)) {
+            UniRun<T> c = new UniRun<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniWhenComplete<T> extends UniCompletion<T,T> {
+        BiConsumer<? super T, ? super Throwable> fn;
+        UniWhenComplete(Executor executor, CompletableFuture<T> dep,
+                        CompletableFuture<T> src,
+                        BiConsumer<? super T, ? super Throwable> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniWhenComplete(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniWhenComplete(CompletableFuture<T> a,
+                                  BiConsumer<? super T,? super Throwable> f,
+                                  UniWhenComplete<T> c) {
+        Object r; T t; Throwable x = null;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    t = null;
+                } else {
+                    @SuppressWarnings("unchecked") T tr = (T) r;
+                    t = tr;
+                }
+                f.accept(t, x);
+                if (x == null) {
+                    internalComplete(r);
+                    return true;
+                }
+            } catch (Throwable ex) {
+                if (x == null)
+                    x = ex;
+                else if (x != ex)
+                    x.addSuppressed(ex);
+            }
+            completeThrowable(x, r);
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniWhenCompleteStage(
+        Executor e, BiConsumer<? super T, ? super Throwable> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        if (e != null || !d.uniWhenComplete(this, f, null)) {
+            UniWhenComplete<T> c = new UniWhenComplete<T>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniHandle<T,V> extends UniCompletion<T,V> {
+        BiFunction<? super T, Throwable, ? extends V> fn;
+        UniHandle(Executor executor, CompletableFuture<V> dep,
+                  CompletableFuture<T> src,
+                  BiFunction<? super T, Throwable, ? extends V> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniHandle(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniHandle(CompletableFuture<S> a,
+                                BiFunction<? super S, Throwable, ? extends T> f,
+                                UniHandle<S,T> c) {
+        Object r; S s; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    x = ((AltResult)r).ex;
+                    s = null;
+                } else {
+                    x = null;
+                    @SuppressWarnings("unchecked") S ss = (S) r;
+                    s = ss;
+                }
+                completeValue(f.apply(s, x));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniHandleStage(
+        Executor e, BiFunction<? super T, Throwable, ? extends V> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.uniHandle(this, f, null)) {
+            UniHandle<T,V> c = new UniHandle<T,V>(e, d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniExceptionally<T> extends UniCompletion<T,T> {
+        Function<? super Throwable, ? extends T> fn;
+        UniExceptionally(CompletableFuture<T> dep, CompletableFuture<T> src,
+                         Function<? super Throwable, ? extends T> fn) {
+            super(null, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<T> tryFire(int mode) { // never ASYNC
+            // assert mode != ASYNC;
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniExceptionally(a = src, fn, this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniExceptionally(CompletableFuture<T> a,
+                                   Function<? super Throwable, ? extends T> f,
+                                   UniExceptionally<T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null) {
+                    if (c != null && !c.claim())
+                        return false;
+                    completeValue(f.apply(x));
+                } else
+                    internalComplete(r);
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<T> uniExceptionallyStage(
+        Function<Throwable, ? extends T> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<T> d = newIncompleteFuture();
+        if (!d.uniExceptionally(this, f, null)) {
+            UniExceptionally<T> c = new UniExceptionally<T>(d, this, f);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniRelay<T> extends UniCompletion<T,T> { // for Compose
+        UniRelay(CompletableFuture<T> dep, CompletableFuture<T> src) {
+            super(null, dep, src);
+        }
+        final CompletableFuture<T> tryFire(int mode) {
+            CompletableFuture<T> d; CompletableFuture<T> a;
+            if ((d = dep) == null || !d.uniRelay(a = src))
+                return null;
+            src = null; dep = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final boolean uniRelay(CompletableFuture<T> a) {
+        Object r;
+        if (a == null || (r = a.result) == null)
+            return false;
+        if (result == null) // no need to claim
+            completeRelay(r);
+        return true;
+    }
+
+    private CompletableFuture<T> uniCopyStage() {
+        Object r;
+        CompletableFuture<T> d = newIncompleteFuture();
+        if ((r = result) != null)
+            d.completeRelay(r);
+        else {
+            UniRelay<T> c = new UniRelay<T>(d, this);
+            push(c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    private MinimalStage<T> uniAsMinimalStage() {
+        Object r;
+        if ((r = result) != null)
+            return new MinimalStage<T>(encodeRelay(r));
+        MinimalStage<T> d = new MinimalStage<T>();
+        UniRelay<T> c = new UniRelay<T>(d, this);
+        push(c);
+        c.tryFire(SYNC);
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class UniCompose<T,V> extends UniCompletion<T,V> {
+        Function<? super T, ? extends CompletionStage<V>> fn;
+        UniCompose(Executor executor, CompletableFuture<V> dep,
+                   CompletableFuture<T> src,
+                   Function<? super T, ? extends CompletionStage<V>> fn) {
+            super(executor, dep, src); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d; CompletableFuture<T> a;
+            if ((d = dep) == null ||
+                !d.uniCompose(a = src, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; fn = null;
+            return d.postFire(a, mode);
+        }
+    }
+
+    final <S> boolean uniCompose(
+        CompletableFuture<S> a,
+        Function<? super S, ? extends CompletionStage<T>> f,
+        UniCompose<S,T> c) {
+        Object r; Throwable x;
+        if (a == null || (r = a.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") S s = (S) r;
+                CompletableFuture<T> g = f.apply(s).toCompletableFuture();
+                if (g.result == null || !uniRelay(g)) {
+                    UniRelay<T> copy = new UniRelay<T>(this, g);
+                    g.push(copy);
+                    copy.tryFire(SYNC);
+                    if (result == null)
+                        return false;
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <V> CompletableFuture<V> uniComposeStage(
+        Executor e, Function<? super T, ? extends CompletionStage<V>> f) {
+        if (f == null) throw new NullPointerException();
+        Object r, s; Throwable x;
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e == null && (r = result) != null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    d.result = encodeThrowable(x, r);
+                    return d;
+                }
+                r = null;
+            }
+            try {
+                @SuppressWarnings("unchecked") T t = (T) r;
+                CompletableFuture<V> g = f.apply(t).toCompletableFuture();
+                if ((s = g.result) != null)
+                    d.completeRelay(s);
+                else {
+                    UniRelay<V> c = new UniRelay<V>(d, g);
+                    g.push(c);
+                    c.tryFire(SYNC);
+                }
+                return d;
+            } catch (Throwable ex) {
+                d.result = encodeThrowable(ex);
+                return d;
+            }
+        }
+        UniCompose<T,V> c = new UniCompose<T,V>(e, d, this, f);
+        push(c);
+        c.tryFire(SYNC);
+        return d;
+    }
+
+    /* ------------- Two-input Completions -------------- */
+
+    /** A Completion for an action with two sources */
+    @SuppressWarnings("serial")
+    abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
+        CompletableFuture<U> snd; // second source for action
+        BiCompletion(Executor executor, CompletableFuture<V> dep,
+                     CompletableFuture<T> src, CompletableFuture<U> snd) {
+            super(executor, dep, src); this.snd = snd;
+        }
+    }
+
+    /** A Completion delegating to a BiCompletion */
+    @SuppressWarnings("serial")
+    static final class CoCompletion extends Completion {
+        BiCompletion<?,?,?> base;
+        CoCompletion(BiCompletion<?,?,?> base) { this.base = base; }
+        final CompletableFuture<?> tryFire(int mode) {
+            BiCompletion<?,?,?> c; CompletableFuture<?> d;
+            if ((c = base) == null || (d = c.tryFire(mode)) == null)
+                return null;
+            base = null; // detach
+            return d;
+        }
+        final boolean isLive() {
+            BiCompletion<?,?,?> c;
+            return (c = base) != null && c.dep != null;
+        }
+    }
+
+    /** Pushes completion to this and b unless both done. */
+    final void bipush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            Object r;
+            while ((r = result) == null && !tryPushStack(c))
+                lazySetNext(c, null); // clear on failure
+            if (b != null && b != this && b.result == null) {
+                Completion q = (r != null) ? c : new CoCompletion(c);
+                while (b.result == null && !b.tryPushStack(q))
+                    lazySetNext(q, null); // clear on failure
+            }
+        }
+    }
+
+    /** Post-processing after successful BiCompletion tryFire. */
+    final CompletableFuture<T> postFire(CompletableFuture<?> a,
+                                        CompletableFuture<?> b, int mode) {
+        if (b != null && b.stack != null) { // clean second source
+            if (mode < 0 || b.result == null)
+                b.cleanStack();
+            else
+                b.postComplete();
+        }
+        return postFire(a, mode);
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiApply<T,U,V> extends BiCompletion<T,U,V> {
+        BiFunction<? super T,? super U,? extends V> fn;
+        BiApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src, CompletableFuture<U> snd,
+                BiFunction<? super T,? super U,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biApply(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biApply(CompletableFuture<R> a,
+                                CompletableFuture<S> b,
+                                BiFunction<? super R,? super S,? extends T> f,
+                                BiApply<R,S,T> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                completeValue(f.apply(rr, ss));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U,V> CompletableFuture<V> biApplyStage(
+        Executor e, CompletionStage<U> o,
+        BiFunction<? super T,? super U,? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.biApply(this, b, f, null)) {
+            BiApply<T,U,V> c = new BiApply<T,U,V>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiAccept<T,U> extends BiCompletion<T,U,Void> {
+        BiConsumer<? super T,? super U> fn;
+        BiAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src, CompletableFuture<U> snd,
+                 BiConsumer<? super T,? super U> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S> boolean biAccept(CompletableFuture<R> a,
+                                 CompletableFuture<S> b,
+                                 BiConsumer<? super R,? super S> f,
+                                 BiAccept<R,S> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            if (r instanceof AltResult) {
+                if ((x = ((AltResult)r).ex) != null) {
+                    completeThrowable(x, r);
+                    break tryComplete;
+                }
+                r = null;
+            }
+            if (s instanceof AltResult) {
+                if ((x = ((AltResult)s).ex) != null) {
+                    completeThrowable(x, s);
+                    break tryComplete;
+                }
+                s = null;
+            }
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                @SuppressWarnings("unchecked") S ss = (S) s;
+                f.accept(rr, ss);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U> CompletableFuture<Void> biAcceptStage(
+        Executor e, CompletionStage<U> o,
+        BiConsumer<? super T,? super U> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.biAccept(this, b, f, null)) {
+            BiAccept<T,U> c = new BiAccept<T,U>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        BiRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.biRun(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean biRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, BiRun<?,?> c) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null || f == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                try {
+                    if (c != null && !c.claim())
+                        return false;
+                    f.run();
+                    completeNull();
+                } catch (Throwable ex) {
+                    completeThrowable(ex);
+                }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> biRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.biRun(this, b, f, null)) {
+            BiRun<T,?> c = new BiRun<>(e, d, this, b, f);
+            bipush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class BiRelay<T,U> extends BiCompletion<T,U,Void> { // for And
+        BiRelay(CompletableFuture<Void> dep,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.biRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    boolean biRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r, s; Throwable x;
+        if (a == null || (r = a.result) == null ||
+            b == null || (s = b.result) == null)
+            return false;
+        if (result == null) {
+            if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                completeThrowable(x, r);
+            else if (s instanceof AltResult && (x = ((AltResult)s).ex) != null)
+                completeThrowable(x, s);
+            else
+                completeNull();
+        }
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs,
+                                           int lo, int hi) {
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        if (lo > hi) // empty
+            d.result = NIL;
+        else {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      andTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      andTree(cfs, mid+1, hi))) == null)
+                throw new NullPointerException();
+            if (!d.biRelay(a, b)) {
+                BiRelay<?,?> c = new BiRelay<>(d, a, b);
+                a.bipush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Projected (Ored) BiCompletions -------------- */
+
+    /** Pushes completion to this and b unless either done. */
+    final void orpush(CompletableFuture<?> b, BiCompletion<?,?,?> c) {
+        if (c != null) {
+            while ((b == null || b.result == null) && result == null) {
+                if (tryPushStack(c)) {
+                    if (b != null && b != this && b.result == null) {
+                        Completion q = new CoCompletion(c);
+                        while (result == null && b.result == null &&
+                               !b.tryPushStack(q))
+                            lazySetNext(q, null); // clear on failure
+                    }
+                    break;
+                }
+                lazySetNext(c, null); // clear on failure
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrApply<T,U extends T,V> extends BiCompletion<T,U,V> {
+        Function<? super T,? extends V> fn;
+        OrApply(Executor executor, CompletableFuture<V> dep,
+                CompletableFuture<T> src,
+                CompletableFuture<U> snd,
+                Function<? super T,? extends V> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<V> tryFire(int mode) {
+            CompletableFuture<V> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orApply(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S extends R> boolean orApply(CompletableFuture<R> a,
+                                          CompletableFuture<S> b,
+                                          Function<? super R, ? extends T> f,
+                                          OrApply<R,S,T> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                completeValue(f.apply(rr));
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U extends T,V> CompletableFuture<V> orApplyStage(
+        Executor e, CompletionStage<U> o,
+        Function<? super T, ? extends V> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<V> d = newIncompleteFuture();
+        if (e != null || !d.orApply(this, b, f, null)) {
+            OrApply<T,U,V> c = new OrApply<T,U,V>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrAccept<T,U extends T> extends BiCompletion<T,U,Void> {
+        Consumer<? super T> fn;
+        OrAccept(Executor executor, CompletableFuture<Void> dep,
+                 CompletableFuture<T> src,
+                 CompletableFuture<U> snd,
+                 Consumer<? super T> fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orAccept(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final <R,S extends R> boolean orAccept(CompletableFuture<R> a,
+                                           CompletableFuture<S> b,
+                                           Consumer<? super R> f,
+                                           OrAccept<R,S> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        tryComplete: if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult) {
+                    if ((x = ((AltResult)r).ex) != null) {
+                        completeThrowable(x, r);
+                        break tryComplete;
+                    }
+                    r = null;
+                }
+                @SuppressWarnings("unchecked") R rr = (R) r;
+                f.accept(rr);
+                completeNull();
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private <U extends T> CompletableFuture<Void> orAcceptStage(
+        Executor e, CompletionStage<U> o, Consumer<? super T> f) {
+        CompletableFuture<U> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.orAccept(this, b, f, null)) {
+            OrAccept<T,U> c = new OrAccept<T,U>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRun<T,U> extends BiCompletion<T,U,Void> {
+        Runnable fn;
+        OrRun(Executor executor, CompletableFuture<Void> dep,
+              CompletableFuture<T> src,
+              CompletableFuture<U> snd,
+              Runnable fn) {
+            super(executor, dep, src, snd); this.fn = fn;
+        }
+        final CompletableFuture<Void> tryFire(int mode) {
+            CompletableFuture<Void> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null ||
+                !d.orRun(a = src, b = snd, fn, mode > 0 ? null : this))
+                return null;
+            dep = null; src = null; snd = null; fn = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean orRun(CompletableFuture<?> a, CompletableFuture<?> b,
+                        Runnable f, OrRun<?,?> c) {
+        Object r; Throwable x;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null) || f == null)
+            return false;
+        if (result == null) {
+            try {
+                if (c != null && !c.claim())
+                    return false;
+                if (r instanceof AltResult && (x = ((AltResult)r).ex) != null)
+                    completeThrowable(x, r);
+                else {
+                    f.run();
+                    completeNull();
+                }
+            } catch (Throwable ex) {
+                completeThrowable(ex);
+            }
+        }
+        return true;
+    }
+
+    private CompletableFuture<Void> orRunStage(Executor e, CompletionStage<?> o,
+                                               Runnable f) {
+        CompletableFuture<?> b;
+        if (f == null || (b = o.toCompletableFuture()) == null)
+            throw new NullPointerException();
+        CompletableFuture<Void> d = newIncompleteFuture();
+        if (e != null || !d.orRun(this, b, f, null)) {
+            OrRun<T,?> c = new OrRun<>(e, d, this, b, f);
+            orpush(b, c);
+            c.tryFire(SYNC);
+        }
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class OrRelay<T,U> extends BiCompletion<T,U,Object> { // for Or
+        OrRelay(CompletableFuture<Object> dep, CompletableFuture<T> src,
+                CompletableFuture<U> snd) {
+            super(null, dep, src, snd);
+        }
+        final CompletableFuture<Object> tryFire(int mode) {
+            CompletableFuture<Object> d;
+            CompletableFuture<T> a;
+            CompletableFuture<U> b;
+            if ((d = dep) == null || !d.orRelay(a = src, b = snd))
+                return null;
+            src = null; snd = null; dep = null;
+            return d.postFire(a, b, mode);
+        }
+    }
+
+    final boolean orRelay(CompletableFuture<?> a, CompletableFuture<?> b) {
+        Object r;
+        if (a == null || b == null ||
+            ((r = a.result) == null && (r = b.result) == null))
+            return false;
+        if (result == null)
+            completeRelay(r);
+        return true;
+    }
+
+    /** Recursively constructs a tree of completions. */
+    static CompletableFuture<Object> orTree(CompletableFuture<?>[] cfs,
+                                            int lo, int hi) {
+        CompletableFuture<Object> d = new CompletableFuture<Object>();
+        if (lo <= hi) {
+            CompletableFuture<?> a, b;
+            int mid = (lo + hi) >>> 1;
+            if ((a = (lo == mid ? cfs[lo] :
+                      orTree(cfs, lo, mid))) == null ||
+                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
+                      orTree(cfs, mid+1, hi))) == null)
+                throw new NullPointerException();
+            if (!d.orRelay(a, b)) {
+                OrRelay<?,?> c = new OrRelay<>(d, a, b);
+                a.orpush(b, c);
+                c.tryFire(SYNC);
+            }
+        }
+        return d;
+    }
+
+    /* ------------- Zero-input Async forms -------------- */
+
+    @SuppressWarnings("serial")
+    static final class AsyncSupply<T> extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<T> dep; Supplier<? extends T> fn;
+        AsyncSupply(CompletableFuture<T> dep, Supplier<? extends T> fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return true; }
+
+        public void run() {
+            CompletableFuture<T> d; Supplier<? extends T> f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        d.completeValue(f.get());
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
+                                                     Supplier<U> f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<U> d = new CompletableFuture<U>();
+        e.execute(new AsyncSupply<U>(d, f));
+        return d;
+    }
+
+    @SuppressWarnings("serial")
+    static final class AsyncRun extends ForkJoinTask<Void>
+        implements Runnable, AsynchronousCompletionTask {
+        CompletableFuture<Void> dep; Runnable fn;
+        AsyncRun(CompletableFuture<Void> dep, Runnable fn) {
+            this.dep = dep; this.fn = fn;
+        }
+
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) {}
+        public final boolean exec() { run(); return true; }
+
+        public void run() {
+            CompletableFuture<Void> d; Runnable f;
+            if ((d = dep) != null && (f = fn) != null) {
+                dep = null; fn = null;
+                if (d.result == null) {
+                    try {
+                        f.run();
+                        d.completeNull();
+                    } catch (Throwable ex) {
+                        d.completeThrowable(ex);
+                    }
+                }
+                d.postComplete();
+            }
+        }
+    }
+
+    static CompletableFuture<Void> asyncRunStage(Executor e, Runnable f) {
+        if (f == null) throw new NullPointerException();
+        CompletableFuture<Void> d = new CompletableFuture<Void>();
+        e.execute(new AsyncRun(d, f));
+        return d;
+    }
+
+    /* ------------- Signallers -------------- */
+
+    /**
+     * Completion for recording and releasing a waiting thread.  This
+     * class implements ManagedBlocker to avoid starvation when
+     * blocking actions pile up in ForkJoinPools.
+     */
+    @SuppressWarnings("serial")
+    static final class Signaller extends Completion
+        implements ForkJoinPool.ManagedBlocker {
+        long nanos;                    // remaining wait time if timed
+        final long deadline;           // non-zero if timed
+        final boolean interruptible;
+        boolean interrupted;
+        volatile Thread thread;
+
+        Signaller(boolean interruptible, long nanos, long deadline) {
+            this.thread = Thread.currentThread();
+            this.interruptible = interruptible;
+            this.nanos = nanos;
+            this.deadline = deadline;
+        }
+        final CompletableFuture<?> tryFire(int ignore) {
+            Thread w; // no need to atomically claim
+            if ((w = thread) != null) {
+                thread = null;
+                LockSupport.unpark(w);
+            }
+            return null;
+        }
+        public boolean isReleasable() {
+            if (Thread.interrupted())
+                interrupted = true;
+            return ((interrupted && interruptible) ||
+                    (deadline != 0L &&
+                     (nanos <= 0L ||
+                      (nanos = deadline - System.nanoTime()) <= 0L)) ||
+                    thread == null);
+        }
+        public boolean block() {
+            while (!isReleasable()) {
+                if (deadline == 0L)
+                    LockSupport.park(this);
+                else
+                    LockSupport.parkNanos(this, nanos);
+            }
+            return true;
+        }
+        final boolean isLive() { return thread != null; }
+    }
+
+    /**
+     * Returns raw result after waiting, or null if interruptible and
+     * interrupted.
+     */
+    private Object waitingGet(boolean interruptible) {
+        Signaller q = null;
+        boolean queued = false;
+        int spins = SPINS;
+        Object r;
+        while ((r = result) == null) {
+            if (spins > 0) {
+                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
+                    --spins;
+            }
+            else if (q == null)
+                q = new Signaller(interruptible, 0L, 0L);
+            else if (!queued)
+                queued = tryPushStack(q);
+            else {
+                try {
+                    ForkJoinPool.managedBlock(q);
+                } catch (InterruptedException ie) { // currently cannot happen
+                    q.interrupted = true;
+                }
+                if (q.interrupted && interruptible)
+                    break;
+            }
+        }
+        if (q != null) {
+            q.thread = null;
+            if (q.interrupted) {
+                if (interruptible)
+                    cleanStack();
+                else
+                    Thread.currentThread().interrupt();
+            }
+        }
+        if (r != null)
+            postComplete();
+        return r;
+    }
+
+    /**
+     * Returns raw result after waiting, or null if interrupted, or
+     * throws TimeoutException on timeout.
+     */
+    private Object timedGet(long nanos) throws TimeoutException {
+        if (Thread.interrupted())
+            return null;
+        if (nanos > 0L) {
+            long d = System.nanoTime() + nanos;
+            long deadline = (d == 0L) ? 1L : d; // avoid 0
+            Signaller q = null;
+            boolean queued = false;
+            Object r;
+            while ((r = result) == null) { // similar to untimed, without spins
+                if (q == null)
+                    q = new Signaller(true, nanos, deadline);
+                else if (!queued)
+                    queued = tryPushStack(q);
+                else if (q.nanos <= 0L)
+                    break;
+                else {
+                    try {
+                        ForkJoinPool.managedBlock(q);
+                    } catch (InterruptedException ie) {
+                        q.interrupted = true;
+                    }
+                    if (q.interrupted)
+                        break;
+                }
+            }
+            if (q != null)
+                q.thread = null;
+            if (r != null)
+                postComplete();
+            else
+                cleanStack();
+            if (r != null || (q != null && q.interrupted))
+                return r;
+        }
+        throw new TimeoutException();
+    }
+
+    /* ------------- public methods -------------- */
+
+    /**
+     * Creates a new incomplete CompletableFuture.
+     */
+    public CompletableFuture() {
+    }
+
+    /**
+     * Creates a new complete CompletableFuture with given encoded result.
+     */
+    CompletableFuture(Object r) {
+        this.result = r;
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the {@link ForkJoinPool#commonPool()} with
+     * the value obtained by calling the given Supplier.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete the returned CompletableFuture
+     * @param <U> the function's return type
+     * @return the new CompletableFuture
+     */
+    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
+        return asyncSupplyStage(ASYNC_POOL, supplier);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the given executor with the value obtained
+     * by calling the given Supplier.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete the returned CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletableFuture
+     */
+    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
+                                                       Executor executor) {
+        return asyncSupplyStage(screenExecutor(executor), supplier);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the {@link ForkJoinPool#commonPool()} after
+     * it runs the given action.
+     *
+     * @param runnable the action to run before completing the
+     * returned CompletableFuture
+     * @return the new CompletableFuture
+     */
+    public static CompletableFuture<Void> runAsync(Runnable runnable) {
+        return asyncRunStage(ASYNC_POOL, runnable);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is asynchronously completed
+     * by a task running in the given executor after it runs the given
+     * action.
+     *
+     * @param runnable the action to run before completing the
+     * returned CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletableFuture
+     */
+    public static CompletableFuture<Void> runAsync(Runnable runnable,
+                                                   Executor executor) {
+        return asyncRunStage(screenExecutor(executor), runnable);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is already completed with
+     * the given value.
+     *
+     * @param value the value
+     * @param <U> the type of the value
+     * @return the completed CompletableFuture
+     */
+    public static <U> CompletableFuture<U> completedFuture(U value) {
+        return new CompletableFuture<U>((value == null) ? NIL : value);
+    }
+
+    /**
+     * Returns {@code true} if completed in any fashion: normally,
+     * exceptionally, or via cancellation.
+     *
+     * @return {@code true} if completed
+     */
+    public boolean isDone() {
+        return result != null;
+    }
+
+    /**
+     * Waits if necessary for this future to complete, and then
+     * returns its result.
+     *
+     * @return the result value
+     * @throws CancellationException if this future was cancelled
+     * @throws ExecutionException if this future completed exceptionally
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     */
+    public T get() throws InterruptedException, ExecutionException {
+        Object r;
+        return reportGet((r = result) == null ? waitingGet(true) : r);
+    }
+
+    /**
+     * Waits if necessary for at most the given time for this future
+     * to complete, and then returns its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the result value
+     * @throws CancellationException if this future was cancelled
+     * @throws ExecutionException if this future completed exceptionally
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    public T get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        Object r;
+        long nanos = unit.toNanos(timeout);
+        return reportGet((r = result) == null ? timedGet(nanos) : r);
+    }
+
+    /**
+     * Returns the result value when complete, or throws an
+     * (unchecked) exception if completed exceptionally. To better
+     * conform with the use of common functional forms, if a
+     * computation involved in the completion of this
+     * CompletableFuture threw an exception, this method throws an
+     * (unchecked) {@link CompletionException} with the underlying
+     * exception as its cause.
+     *
+     * @return the result value
+     * @throws CancellationException if the computation was cancelled
+     * @throws CompletionException if this future completed
+     * exceptionally or a completion computation threw an exception
+     */
+    public T join() {
+        Object r;
+        return reportJoin((r = result) == null ? waitingGet(false) : r);
+    }
+
+    /**
+     * Returns the result value (or throws any encountered exception)
+     * if completed, else returns the given valueIfAbsent.
+     *
+     * @param valueIfAbsent the value to return if not completed
+     * @return the result value, if completed, else the given valueIfAbsent
+     * @throws CancellationException if the computation was cancelled
+     * @throws CompletionException if this future completed
+     * exceptionally or a completion computation threw an exception
+     */
+    public T getNow(T valueIfAbsent) {
+        Object r;
+        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
+    }
+
+    /**
+     * If not already completed, sets the value returned by {@link
+     * #get()} and related methods to the given value.
+     *
+     * @param value the result value
+     * @return {@code true} if this invocation caused this CompletableFuture
+     * to transition to a completed state, else {@code false}
+     */
+    public boolean complete(T value) {
+        boolean triggered = completeValue(value);
+        postComplete();
+        return triggered;
+    }
+
+    /**
+     * If not already completed, causes invocations of {@link #get()}
+     * and related methods to throw the given exception.
+     *
+     * @param ex the exception
+     * @return {@code true} if this invocation caused this CompletableFuture
+     * to transition to a completed state, else {@code false}
+     */
+    public boolean completeExceptionally(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        boolean triggered = internalComplete(new AltResult(ex));
+        postComplete();
+        return triggered;
+    }
+
+    public <U> CompletableFuture<U> thenApply(
+        Function<? super T,? extends U> fn) {
+        return uniApplyStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> thenApplyAsync(
+        Function<? super T,? extends U> fn) {
+        return uniApplyStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> thenApplyAsync(
+        Function<? super T,? extends U> fn, Executor executor) {
+        return uniApplyStage(screenExecutor(executor), fn);
+    }
+
+    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
+        return uniAcceptStage(null, action);
+    }
+
+    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action) {
+        return uniAcceptStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action,
+                                                   Executor executor) {
+        return uniAcceptStage(screenExecutor(executor), action);
+    }
+
+    public CompletableFuture<Void> thenRun(Runnable action) {
+        return uniRunStage(null, action);
+    }
+
+    public CompletableFuture<Void> thenRunAsync(Runnable action) {
+        return uniRunStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<Void> thenRunAsync(Runnable action,
+                                                Executor executor) {
+        return uniRunStage(screenExecutor(executor), action);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombine(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn) {
+        return biApplyStage(null, other, fn);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombineAsync(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn) {
+        return biApplyStage(defaultExecutor(), other, fn);
+    }
+
+    public <U,V> CompletableFuture<V> thenCombineAsync(
+        CompletionStage<? extends U> other,
+        BiFunction<? super T,? super U,? extends V> fn, Executor executor) {
+        return biApplyStage(screenExecutor(executor), other, fn);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBoth(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action) {
+        return biAcceptStage(null, other, action);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBothAsync(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action) {
+        return biAcceptStage(defaultExecutor(), other, action);
+    }
+
+    public <U> CompletableFuture<Void> thenAcceptBothAsync(
+        CompletionStage<? extends U> other,
+        BiConsumer<? super T, ? super U> action, Executor executor) {
+        return biAcceptStage(screenExecutor(executor), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
+                                                Runnable action) {
+        return biRunStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                     Runnable action) {
+        return biRunStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                     Runnable action,
+                                                     Executor executor) {
+        return biRunStage(screenExecutor(executor), other, action);
+    }
+
+    public <U> CompletableFuture<U> applyToEither(
+        CompletionStage<? extends T> other, Function<? super T, U> fn) {
+        return orApplyStage(null, other, fn);
+    }
+
+    public <U> CompletableFuture<U> applyToEitherAsync(
+        CompletionStage<? extends T> other, Function<? super T, U> fn) {
+        return orApplyStage(defaultExecutor(), other, fn);
+    }
+
+    public <U> CompletableFuture<U> applyToEitherAsync(
+        CompletionStage<? extends T> other, Function<? super T, U> fn,
+        Executor executor) {
+        return orApplyStage(screenExecutor(executor), other, fn);
+    }
+
+    public CompletableFuture<Void> acceptEither(
+        CompletionStage<? extends T> other, Consumer<? super T> action) {
+        return orAcceptStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> acceptEitherAsync(
+        CompletionStage<? extends T> other, Consumer<? super T> action) {
+        return orAcceptStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> acceptEitherAsync(
+        CompletionStage<? extends T> other, Consumer<? super T> action,
+        Executor executor) {
+        return orAcceptStage(screenExecutor(executor), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
+                                                  Runnable action) {
+        return orRunStage(null, other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+                                                       Runnable action) {
+        return orRunStage(defaultExecutor(), other, action);
+    }
+
+    public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,
+                                                       Runnable action,
+                                                       Executor executor) {
+        return orRunStage(screenExecutor(executor), other, action);
+    }
+
+    public <U> CompletableFuture<U> thenCompose(
+        Function<? super T, ? extends CompletionStage<U>> fn) {
+        return uniComposeStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> thenComposeAsync(
+        Function<? super T, ? extends CompletionStage<U>> fn) {
+        return uniComposeStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> thenComposeAsync(
+        Function<? super T, ? extends CompletionStage<U>> fn,
+        Executor executor) {
+        return uniComposeStage(screenExecutor(executor), fn);
+    }
+
+    public CompletableFuture<T> whenComplete(
+        BiConsumer<? super T, ? super Throwable> action) {
+        return uniWhenCompleteStage(null, action);
+    }
+
+    public CompletableFuture<T> whenCompleteAsync(
+        BiConsumer<? super T, ? super Throwable> action) {
+        return uniWhenCompleteStage(defaultExecutor(), action);
+    }
+
+    public CompletableFuture<T> whenCompleteAsync(
+        BiConsumer<? super T, ? super Throwable> action, Executor executor) {
+        return uniWhenCompleteStage(screenExecutor(executor), action);
+    }
+
+    public <U> CompletableFuture<U> handle(
+        BiFunction<? super T, Throwable, ? extends U> fn) {
+        return uniHandleStage(null, fn);
+    }
+
+    public <U> CompletableFuture<U> handleAsync(
+        BiFunction<? super T, Throwable, ? extends U> fn) {
+        return uniHandleStage(defaultExecutor(), fn);
+    }
+
+    public <U> CompletableFuture<U> handleAsync(
+        BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
+        return uniHandleStage(screenExecutor(executor), fn);
+    }
+
+    /**
+     * Returns this CompletableFuture.
+     *
+     * @return this CompletableFuture
+     */
+    public CompletableFuture<T> toCompletableFuture() {
+        return this;
+    }
+
+    // not in interface CompletionStage
+
+    /**
+     * Returns a new CompletableFuture that is completed when this
+     * CompletableFuture completes, with the result of the given
+     * function of the exception triggering this CompletableFuture's
+     * completion when it completes exceptionally; otherwise, if this
+     * CompletableFuture completes normally, then the returned
+     * CompletableFuture also completes normally with the same value.
+     * Note: More flexible versions of this functionality are
+     * available using methods {@code whenComplete} and {@code handle}.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletableFuture if this CompletableFuture completed
+     * exceptionally
+     * @return the new CompletableFuture
+     */
+    public CompletableFuture<T> exceptionally(
+        Function<Throwable, ? extends T> fn) {
+        return uniExceptionallyStage(fn);
+    }
+
+
+    /* ------------- Arbitrary-arity constructions -------------- */
+
+    /**
+     * Returns a new CompletableFuture that is completed when all of
+     * the given CompletableFutures complete.  If any of the given
+     * CompletableFutures complete exceptionally, then the returned
+     * CompletableFuture also does so, with a CompletionException
+     * holding this exception as its cause.  Otherwise, the results,
+     * if any, of the given CompletableFutures are not reflected in
+     * the returned CompletableFuture, but may be obtained by
+     * inspecting them individually. If no CompletableFutures are
+     * provided, returns a CompletableFuture completed with the value
+     * {@code null}.
+     *
+     * <p>Among the applications of this method is to await completion
+     * of a set of independent CompletableFutures before continuing a
+     * program, as in: {@code CompletableFuture.allOf(c1, c2,
+     * c3).join();}.
+     *
+     * @param cfs the CompletableFutures
+     * @return a new CompletableFuture that is completed when all of the
+     * given CompletableFutures complete
+     * @throws NullPointerException if the array or any of its elements are
+     * {@code null}
+     */
+    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
+        return andTree(cfs, 0, cfs.length - 1);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is completed when any of
+     * the given CompletableFutures complete, with the same result.
+     * Otherwise, if it completed exceptionally, the returned
+     * CompletableFuture also does so, with a CompletionException
+     * holding this exception as its cause.  If no CompletableFutures
+     * are provided, returns an incomplete CompletableFuture.
+     *
+     * @param cfs the CompletableFutures
+     * @return a new CompletableFuture that is completed with the
+     * result or exception of any of the given CompletableFutures when
+     * one completes
+     * @throws NullPointerException if the array or any of its elements are
+     * {@code null}
+     */
+    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
+        return orTree(cfs, 0, cfs.length - 1);
+    }
+
+    /* ------------- Control and status methods -------------- */
+
+    /**
+     * If not already completed, completes this CompletableFuture with
+     * a {@link CancellationException}. Dependent CompletableFutures
+     * that have not already completed will also complete
+     * exceptionally, with a {@link CompletionException} caused by
+     * this {@code CancellationException}.
+     *
+     * @param mayInterruptIfRunning this value has no effect in this
+     * implementation because interrupts are not used to control
+     * processing.
+     *
+     * @return {@code true} if this task is now cancelled
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        boolean cancelled = (result == null) &&
+            internalComplete(new AltResult(new CancellationException()));
+        postComplete();
+        return cancelled || isCancelled();
+    }
+
+    /**
+     * Returns {@code true} if this CompletableFuture was cancelled
+     * before it completed normally.
+     *
+     * @return {@code true} if this CompletableFuture was cancelled
+     * before it completed normally
+     */
+    public boolean isCancelled() {
+        Object r;
+        return ((r = result) instanceof AltResult) &&
+            (((AltResult)r).ex instanceof CancellationException);
+    }
+
+    /**
+     * Returns {@code true} if this CompletableFuture completed
+     * exceptionally, in any way. Possible causes include
+     * cancellation, explicit invocation of {@code
+     * completeExceptionally}, and abrupt termination of a
+     * CompletionStage action.
+     *
+     * @return {@code true} if this CompletableFuture completed
+     * exceptionally
+     */
+    public boolean isCompletedExceptionally() {
+        Object r;
+        return ((r = result) instanceof AltResult) && r != NIL;
+    }
+
+    /**
+     * Forcibly sets or resets the value subsequently returned by
+     * method {@link #get()} and related methods, whether or not
+     * already completed. This method is designed for use only in
+     * error recovery actions, and even in such situations may result
+     * in ongoing dependent completions using established versus
+     * overwritten outcomes.
+     *
+     * @param value the completion value
+     */
+    public void obtrudeValue(T value) {
+        result = (value == null) ? NIL : value;
+        postComplete();
+    }
+
+    /**
+     * Forcibly causes subsequent invocations of method {@link #get()}
+     * and related methods to throw the given exception, whether or
+     * not already completed. This method is designed for use only in
+     * error recovery actions, and even in such situations may result
+     * in ongoing dependent completions using established versus
+     * overwritten outcomes.
+     *
+     * @param ex the exception
+     * @throws NullPointerException if the exception is null
+     */
+    public void obtrudeException(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        result = new AltResult(ex);
+        postComplete();
+    }
+
+    /**
+     * Returns the estimated number of CompletableFutures whose
+     * completions are awaiting completion of this CompletableFuture.
+     * This method is designed for use in monitoring system state, not
+     * for synchronization control.
+     *
+     * @return the number of dependent CompletableFutures
+     */
+    public int getNumberOfDependents() {
+        int count = 0;
+        for (Completion p = stack; p != null; p = p.next)
+            ++count;
+        return count;
+    }
+
+    /**
+     * Returns a string identifying this CompletableFuture, as well as
+     * its completion state.  The state, in brackets, contains the
+     * String {@code "Completed Normally"} or the String {@code
+     * "Completed Exceptionally"}, or the String {@code "Not
+     * completed"} followed by the number of CompletableFutures
+     * dependent upon its completion, if any.
+     *
+     * @return a string identifying this CompletableFuture, as well as its state
+     */
+    public String toString() {
+        Object r = result;
+        int count = 0; // avoid call to getNumberOfDependents in case disabled
+        for (Completion p = stack; p != null; p = p.next)
+            ++count;
+        return super.toString() +
+            ((r == null) ?
+             ((count == 0) ?
+              "[Not completed]" :
+              "[Not completed, " + count + " dependents]") :
+             (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
+              "[Completed exceptionally]" :
+              "[Completed normally]"));
+    }
+
+    // jdk9 additions
+
+    /**
+     * Returns a new incomplete CompletableFuture of the type to be
+     * returned by a CompletionStage method. Subclasses should
+     * normally override this method to return an instance of the same
+     * class as this CompletableFuture. The default implementation
+     * returns an instance of class CompletableFuture.
+     *
+     * @param <U> the type of the value
+     * @return a new CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public <U> CompletableFuture<U> newIncompleteFuture() {
+        return new CompletableFuture<U>();
+    }
+
+    /**
+     * Returns the default Executor used for async methods that do not
+     * specify an Executor. This class uses the {@link
+     * ForkJoinPool#commonPool()} if it supports more than one
+     * parallel thread, or else an Executor using one thread per async
+     * task.  This method may be overridden in subclasses to return
+     * an Executor that provides at least one independent thread.
+     *
+     * @return the executor
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public Executor defaultExecutor() {
+        return ASYNC_POOL;
+    }
+
+    /**
+     * Returns a new CompletableFuture that is completed normally with
+     * the same value as this CompletableFuture when it completes
+     * normally. If this CompletableFuture completes exceptionally,
+     * then the returned CompletableFuture completes exceptionally
+     * with a CompletionException with this exception as cause. The
+     * behavior is equivalent to {@code thenApply(x -> x)}. This
+     * method may be useful as a form of "defensive copying", to
+     * prevent clients from completing, while still being able to
+     * arrange dependent actions.
+     *
+     * @return the new CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> copy() {
+        return uniCopyStage();
+    }
+
+    /**
+     * Returns a new CompletionStage that is completed normally with
+     * the same value as this CompletableFuture when it completes
+     * normally, and cannot be independently completed or otherwise
+     * used in ways not defined by the methods of interface {@link
+     * CompletionStage}.  If this CompletableFuture completes
+     * exceptionally, then the returned CompletionStage completes
+     * exceptionally with a CompletionException with this exception as
+     * cause.
+     *
+     * @return the new CompletionStage
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletionStage<T> minimalCompletionStage() {
+        return uniAsMinimalStage();
+    }
+
+    /**
+     * Completes this CompletableFuture with the result of
+     * the given Supplier function invoked from an asynchronous
+     * task using the given executor.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete this CompletableFuture
+     * @param executor the executor to use for asynchronous execution
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier,
+                                              Executor executor) {
+        if (supplier == null || executor == null)
+            throw new NullPointerException();
+        executor.execute(new AsyncSupply<T>(this, supplier));
+        return this;
+    }
+
+    /**
+     * Completes this CompletableFuture with the result of the given
+     * Supplier function invoked from an asynchronous task using the
+     * default executor.
+     *
+     * @param supplier a function returning the value to be used
+     * to complete this CompletableFuture
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier) {
+        return completeAsync(supplier, defaultExecutor());
+    }
+
+    /**
+     * Exceptionally completes this CompletableFuture with
+     * a {@link TimeoutException} if not otherwise completed
+     * before the given timeout.
+     *
+     * @param timeout how long to wait before completing exceptionally
+     *        with a TimeoutException, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        if (result == null)
+            whenComplete(new Canceller(Delayer.delay(new Timeout(this),
+                                                     timeout, unit)));
+        return this;
+    }
+
+    /**
+     * Completes this CompletableFuture with the given value if not
+     * otherwise completed before the given timeout.
+     *
+     * @param value the value to use upon timeout
+     * @param timeout how long to wait before completing normally
+     *        with the given value, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return this CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public CompletableFuture<T> completeOnTimeout(T value, long timeout,
+                                                  TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        if (result == null)
+            whenComplete(new Canceller(Delayer.delay(
+                                           new DelayedCompleter<T>(this, value),
+                                           timeout, unit)));
+        return this;
+    }
+
+    /**
+     * Returns a new Executor that submits a task to the given base
+     * executor after the given delay (or no delay if non-positive).
+     * Each delay commences upon invocation of the returned executor's
+     * {@code execute} method.
+     *
+     * @param delay how long to delay, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code delay} parameter
+     * @param executor the base executor
+     * @return the new delayed executor
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static Executor delayedExecutor(long delay, TimeUnit unit,
+                                           Executor executor) {
+        if (unit == null || executor == null)
+            throw new NullPointerException();
+        return new DelayedExecutor(delay, unit, executor);
+    }
+
+    /**
+     * Returns a new Executor that submits a task to the default
+     * executor after the given delay (or no delay if non-positive).
+     * Each delay commences upon invocation of the returned executor's
+     * {@code execute} method.
+     *
+     * @param delay how long to delay, in units of {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code delay} parameter
+     * @return the new delayed executor
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static Executor delayedExecutor(long delay, TimeUnit unit) {
+        if (unit == null)
+            throw new NullPointerException();
+        return new DelayedExecutor(delay, unit, ASYNC_POOL);
+    }
+
+    /**
+     * Returns a new CompletionStage that is already completed with
+     * the given value and supports only those methods in
+     * interface {@link CompletionStage}.
+     *
+     * @param value the value
+     * @param <U> the type of the value
+     * @return the completed CompletionStage
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static <U> CompletionStage<U> completedStage(U value) {
+        return new MinimalStage<U>((value == null) ? NIL : value);
+    }
+
+    /**
+     * Returns a new CompletableFuture that is already completed
+     * exceptionally with the given exception.
+     *
+     * @param ex the exception
+     * @param <U> the type of the value
+     * @return the exceptionally completed CompletableFuture
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static <U> CompletableFuture<U> failedFuture(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        return new CompletableFuture<U>(new AltResult(ex));
+    }
+
+    /**
+     * Returns a new CompletionStage that is already completed
+     * exceptionally with the given exception and supports only those
+     * methods in interface {@link CompletionStage}.
+     *
+     * @param ex the exception
+     * @param <U> the type of the value
+     * @return the exceptionally completed CompletionStage
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    public static <U> CompletionStage<U> failedStage(Throwable ex) {
+        if (ex == null) throw new NullPointerException();
+        return new MinimalStage<U>(new AltResult(ex));
+    }
+
+    /**
+     * Singleton delay scheduler, used only for starting and
+     * cancelling tasks.
+     */
+    static final class Delayer {
+        static ScheduledFuture<?> delay(Runnable command, long delay,
+                                        TimeUnit unit) {
+            return delayer.schedule(command, delay, unit);
+        }
+
+        static final class DaemonThreadFactory implements ThreadFactory {
+            public Thread newThread(Runnable r) {
+                Thread t = new Thread(r);
+                t.setDaemon(true);
+                t.setName("CompletableFutureDelayScheduler");
+                return t;
+            }
+        }
+
+        static final ScheduledThreadPoolExecutor delayer;
+        static {
+            (delayer = new ScheduledThreadPoolExecutor(
+                1, new DaemonThreadFactory())).
+                setRemoveOnCancelPolicy(true);
+        }
+    }
+
+    // Little class-ified lambdas to better support monitoring
+
+    static final class DelayedExecutor implements Executor {
+        final long delay;
+        final TimeUnit unit;
+        final Executor executor;
+        DelayedExecutor(long delay, TimeUnit unit, Executor executor) {
+            this.delay = delay; this.unit = unit; this.executor = executor;
+        }
+        public void execute(Runnable r) {
+            Delayer.delay(new TaskSubmitter(executor, r), delay, unit);
+        }
+    }
+
+    /** Action to submit user task */
+    static final class TaskSubmitter implements Runnable {
+        final Executor executor;
+        final Runnable action;
+        TaskSubmitter(Executor executor, Runnable action) {
+            this.executor = executor;
+            this.action = action;
+        }
+        public void run() { executor.execute(action); }
+    }
+
+    /** Action to completeExceptionally on timeout */
+    static final class Timeout implements Runnable {
+        final CompletableFuture<?> f;
+        Timeout(CompletableFuture<?> f) { this.f = f; }
+        public void run() {
+            if (f != null && !f.isDone())
+                f.completeExceptionally(new TimeoutException());
+        }
+    }
+
+    /** Action to complete on timeout */
+    static final class DelayedCompleter<U> implements Runnable {
+        final CompletableFuture<U> f;
+        final U u;
+        DelayedCompleter(CompletableFuture<U> f, U u) { this.f = f; this.u = u; }
+        public void run() {
+            if (f != null)
+                f.complete(u);
+        }
+    }
+
+    /** Action to cancel unneeded timeouts */
+    static final class Canceller implements BiConsumer<Object, Throwable> {
+        final Future<?> f;
+        Canceller(Future<?> f) { this.f = f; }
+        public void accept(Object ignore, Throwable ex) {
+            if (ex == null && f != null && !f.isDone())
+                f.cancel(false);
+        }
+    }
+
+    /**
+     * A subclass that just throws UOE for most non-CompletionStage methods.
+     */
+    static final class MinimalStage<T> extends CompletableFuture<T> {
+        MinimalStage() { }
+        MinimalStage(Object r) { super(r); }
+        @Override public <U> CompletableFuture<U> newIncompleteFuture() {
+            return new MinimalStage<U>(); }
+        @Override public T get() {
+            throw new UnsupportedOperationException(); }
+        @Override public T get(long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public T getNow(T valueIfAbsent) {
+            throw new UnsupportedOperationException(); }
+        @Override public T join() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean complete(T value) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean completeExceptionally(Throwable ex) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean cancel(boolean mayInterruptIfRunning) {
+            throw new UnsupportedOperationException(); }
+        @Override public void obtrudeValue(T value) {
+            throw new UnsupportedOperationException(); }
+        @Override public void obtrudeException(Throwable ex) {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isDone() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isCancelled() {
+            throw new UnsupportedOperationException(); }
+        @Override public boolean isCompletedExceptionally() {
+            throw new UnsupportedOperationException(); }
+        @Override public int getNumberOfDependents() {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeAsync
+            (Supplier<? extends T> supplier, Executor executor) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeAsync
+            (Supplier<? extends T> supplier) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> orTimeout
+            (long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+        @Override public CompletableFuture<T> completeOnTimeout
+            (T value, long timeout, TimeUnit unit) {
+            throw new UnsupportedOperationException(); }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long RESULT;
+    private static final long STACK;
+    private static final long NEXT;
+    static {
+        try {
+            RESULT = U.objectFieldOffset
+                (CompletableFuture.class.getDeclaredField("result"));
+            STACK = U.objectFieldOffset
+                (CompletableFuture.class.getDeclaredField("stack"));
+            NEXT = U.objectFieldOffset
+                (Completion.class.getDeclaredField("next"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/CompletionException.java b/java/util/concurrent/CompletionException.java
new file mode 100644
index 0000000..2a3cfc5
--- /dev/null
+++ b/java/util/concurrent/CompletionException.java
@@ -0,0 +1,90 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when an error or other exception is encountered
+ * in the course of completing a result or task.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class CompletionException extends RuntimeException {
+    private static final long serialVersionUID = 7830266012832686185L;
+
+    /**
+     * Constructs a {@code CompletionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    protected CompletionException() { }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified detail
+     * message. The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    protected CompletionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified detail
+     * message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public CompletionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code CompletionException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public CompletionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/util/concurrent/CompletionService.java b/java/util/concurrent/CompletionService.java
new file mode 100644
index 0000000..f647e21
--- /dev/null
+++ b/java/util/concurrent/CompletionService.java
@@ -0,0 +1,124 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A service that decouples the production of new asynchronous tasks
+ * from the consumption of the results of completed tasks.  Producers
+ * {@code submit} tasks for execution. Consumers {@code take}
+ * completed tasks and process their results in the order they
+ * complete.  A {@code CompletionService} can for example be used to
+ * manage asynchronous I/O, in which tasks that perform reads are
+ * submitted in one part of a program or system, and then acted upon
+ * in a different part of the program when the reads complete,
+ * possibly in a different order than they were requested.
+ *
+ * <p>Typically, a {@code CompletionService} relies on a separate
+ * {@link Executor} to actually execute the tasks, in which case the
+ * {@code CompletionService} only manages an internal completion
+ * queue. The {@link ExecutorCompletionService} class provides an
+ * implementation of this approach.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a task to a {@code CompletionService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions taken by that task, which in turn <i>happen-before</i>
+ * actions following a successful return from the corresponding {@code take()}.
+ */
+public interface CompletionService<V> {
+    /**
+     * Submits a value-returning task for execution and returns a Future
+     * representing the pending results of the task.  Upon completion,
+     * this task may be taken or polled.
+     *
+     * @param task the task to submit
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<V> submit(Callable<V> task);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task.  Upon completion, this task may be
+     * taken or polled.
+     *
+     * @param task the task to submit
+     * @param result the result to return upon successful completion
+     * @return a Future representing pending completion of the task,
+     *         and whose {@code get()} method will return the given
+     *         result value upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<V> submit(Runnable task, V result);
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, waiting if none are yet present.
+     *
+     * @return the Future representing the next completed task
+     * @throws InterruptedException if interrupted while waiting
+     */
+    Future<V> take() throws InterruptedException;
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, or {@code null} if none are present.
+     *
+     * @return the Future representing the next completed task, or
+     *         {@code null} if none are present
+     */
+    Future<V> poll();
+
+    /**
+     * Retrieves and removes the Future representing the next
+     * completed task, waiting if necessary up to the specified wait
+     * time if none are yet present.
+     *
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the Future representing the next completed task or
+     *         {@code null} if the specified waiting time elapses
+     *         before one is present
+     * @throws InterruptedException if interrupted while waiting
+     */
+    Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException;
+}
diff --git a/java/util/concurrent/CompletionStage.java b/java/util/concurrent/CompletionStage.java
new file mode 100644
index 0000000..d855945
--- /dev/null
+++ b/java/util/concurrent/CompletionStage.java
@@ -0,0 +1,869 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * A stage of a possibly asynchronous computation, that performs an
+ * action or computes a value when another CompletionStage completes.
+ * A stage completes upon termination of its computation, but this may
+ * in turn trigger other dependent stages.  The functionality defined
+ * in this interface takes only a few basic forms, which expand out to
+ * a larger set of methods to capture a range of usage styles:
+ *
+ * <ul>
+ *
+ * <li>The computation performed by a stage may be expressed as a
+ * Function, Consumer, or Runnable (using methods with names including
+ * <em>apply</em>, <em>accept</em>, or <em>run</em>, respectively)
+ * depending on whether it requires arguments and/or produces results.
+ * For example:
+ * <pre> {@code
+ * stage.thenApply(x -> square(x))
+ *      .thenAccept(x -> System.out.print(x))
+ *      .thenRun(() -> System.out.println());}</pre>
+ *
+ * An additional form (<em>compose</em>) allows the construction of
+ * computation pipelines from functions returning completion stages.
+ *
+ * <p>Any argument to a stage's computation is the outcome of a
+ * triggering stage's computation.
+ *
+ * <li>One stage's execution may be triggered by completion of a
+ * single stage, or both of two stages, or either of two stages.
+ * Dependencies on a single stage are arranged using methods with
+ * prefix <em>then</em>. Those triggered by completion of
+ * <em>both</em> of two stages may <em>combine</em> their results or
+ * effects, using correspondingly named methods. Those triggered by
+ * <em>either</em> of two stages make no guarantees about which of the
+ * results or effects are used for the dependent stage's computation.
+ *
+ * <li>Dependencies among stages control the triggering of
+ * computations, but do not otherwise guarantee any particular
+ * ordering. Additionally, execution of a new stage's computations may
+ * be arranged in any of three ways: default execution, default
+ * asynchronous execution (using methods with suffix <em>async</em>
+ * that employ the stage's default asynchronous execution facility),
+ * or custom (via a supplied {@link Executor}).  The execution
+ * properties of default and async modes are specified by
+ * CompletionStage implementations, not this interface. Methods with
+ * explicit Executor arguments may have arbitrary execution
+ * properties, and might not even support concurrent execution, but
+ * are arranged for processing in a way that accommodates asynchrony.
+ *
+ * <li>Two method forms ({@link #handle handle} and {@link
+ * #whenComplete whenComplete}) support unconditional computation
+ * whether the triggering stage completed normally or exceptionally.
+ * Method {@link #exceptionally exceptionally} supports computation
+ * only when the triggering stage completes exceptionally, computing a
+ * replacement result, similarly to the java {@code catch} keyword.
+ * In all other cases, if a stage's computation terminates abruptly
+ * with an (unchecked) exception or error, then all dependent stages
+ * requiring its completion complete exceptionally as well, with a
+ * {@link CompletionException} holding the exception as its cause.  If
+ * a stage is dependent on <em>both</em> of two stages, and both
+ * complete exceptionally, then the CompletionException may correspond
+ * to either one of these exceptions.  If a stage is dependent on
+ * <em>either</em> of two others, and only one of them completes
+ * exceptionally, no guarantees are made about whether the dependent
+ * stage completes normally or exceptionally. In the case of method
+ * {@code whenComplete}, when the supplied action itself encounters an
+ * exception, then the stage completes exceptionally with this
+ * exception unless the source stage also completed exceptionally, in
+ * which case the exceptional completion from the source stage is
+ * given preference and propagated to the dependent stage.
+ *
+ * </ul>
+ *
+ * <p>All methods adhere to the above triggering, execution, and
+ * exceptional completion specifications (which are not repeated in
+ * individual method specifications). Additionally, while arguments
+ * used to pass a completion result (that is, for parameters of type
+ * {@code T}) for methods accepting them may be null, passing a null
+ * value for any other parameter will result in a {@link
+ * NullPointerException} being thrown.
+ *
+ * <p>Method form {@link #handle handle} is the most general way of
+ * creating a continuation stage, unconditionally performing a
+ * computation that is given both the result and exception (if any) of
+ * the triggering CompletionStage, and computing an arbitrary result.
+ * Method {@link #whenComplete whenComplete} is similar, but preserves
+ * the result of the triggering stage instead of computing a new one.
+ * Because a stage's normal result may be {@code null}, both methods
+ * should have a computation structured thus:
+ *
+ * <pre>{@code (result, exception) -> {
+ *   if (exception == null) {
+ *     // triggering stage completed normally
+ *   } else {
+ *     // triggering stage completed exceptionally
+ *   }
+ * }}</pre>
+ *
+ * <p>This interface does not define methods for initially creating,
+ * forcibly completing normally or exceptionally, probing completion
+ * status or results, or awaiting completion of a stage.
+ * Implementations of CompletionStage may provide means of achieving
+ * such effects, as appropriate.  Method {@link #toCompletableFuture}
+ * enables interoperability among different implementations of this
+ * interface by providing a common conversion type.
+ *
+ * @author Doug Lea
+ * @since 1.8
+ */
+public interface CompletionStage<T> {
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed with this stage's result as the argument
+     * to the supplied function.
+     *
+     * <p>This method is analogous to
+     * {@link java.util.Optional#map Optional.map} and
+     * {@link java.util.stream.Stream#map Stream.map}.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApply(Function<? super T,? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using this stage's default asynchronous
+     * execution facility, with this stage's result as the argument to
+     * the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApplyAsync
+        (Function<? super T,? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using the supplied Executor, with this
+     * stage's result as the argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenApplyAsync
+        (Function<? super T,? extends U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed with this stage's result as the argument
+     * to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAccept(Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using this stage's default asynchronous
+     * execution facility, with this stage's result as the argument to
+     * the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, is executed using the supplied Executor, with this
+     * stage's result as the argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenAcceptAsync(Consumer<? super T> action,
+                                                 Executor executor);
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRun(Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action using this stage's default
+     * asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRunAsync(Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * normally, executes the given action using the supplied Executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> thenRunAsync(Runnable action,
+                                              Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed with the two
+     * results as arguments to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombine
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the two
+     * results as arguments to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombineAsync
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using the
+     * supplied executor, with the two results as arguments to the
+     * supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the other CompletionStage's result
+     * @param <V> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U,V> CompletionStage<V> thenCombineAsync
+        (CompletionStage<? extends U> other,
+         BiFunction<? super T,? super U,? extends V> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed with the two
+     * results as arguments to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBoth
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the two
+     * results as arguments to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBothAsync
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, is executed using the
+     * supplied executor, with the two results as arguments to the
+     * supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the other CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<Void> thenAcceptBothAsync
+        (CompletionStage<? extends U> other,
+         BiConsumer<? super T, ? super U> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBoth(CompletionStage<?> other,
+                                              Runnable action);
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action
+     * using this stage's default asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                   Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when this and the other
+     * given stage both complete normally, executes the given action
+     * using the supplied executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterBothAsync(CompletionStage<?> other,
+                                                   Runnable action,
+                                                   Executor executor);
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed with the
+     * corresponding result as argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEither
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the
+     * corresponding result as argument to the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEitherAsync
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using the
+     * supplied executor, with the corresponding result as argument to
+     * the supplied function.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> applyToEitherAsync
+        (CompletionStage<? extends T> other,
+         Function<? super T, U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed with the
+     * corresponding result as argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEither
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using this
+     * stage's default asynchronous execution facility, with the
+     * corresponding result as argument to the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEitherAsync
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, is executed using the
+     * supplied executor, with the corresponding result as argument to
+     * the supplied action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> acceptEitherAsync
+        (CompletionStage<? extends T> other,
+         Consumer<? super T> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEither(CompletionStage<?> other,
+                                                Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action
+     * using this stage's default asynchronous execution facility.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEitherAsync
+        (CompletionStage<?> other,
+         Runnable action);
+
+    /**
+     * Returns a new CompletionStage that, when either this or the
+     * other given stage complete normally, executes the given action
+     * using the supplied executor.
+     *
+     * See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param other the other CompletionStage
+     * @param action the action to perform before completing the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<Void> runAfterEitherAsync
+        (CompletionStage<?> other,
+         Runnable action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>This method is analogous to
+     * {@link java.util.Optional#flatMap Optional.flatMap} and
+     * {@link java.util.stream.Stream#flatMap Stream.flatMap}.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenCompose
+        (Function<? super T, ? extends CompletionStage<U>> fn);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function,
+     * executed using this stage's default asynchronous execution
+     * facility.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenComposeAsync
+        (Function<? super T, ? extends CompletionStage<U>> fn);
+
+    /**
+     * Returns a new CompletionStage that is completed with the same
+     * value as the CompletionStage returned by the given function,
+     * executed using the supplied Executor.
+     *
+     * <p>When this stage completes normally, the given function is
+     * invoked with this stage's result as the argument, returning
+     * another CompletionStage.  When that stage completes normally,
+     * the CompletionStage returned by this method is completed with
+     * the same value.
+     *
+     * <p>To ensure progress, the supplied function must arrange
+     * eventual completion of its result.
+     *
+     * <p>See the {@link CompletionStage} documentation for rules
+     * covering exceptional completion.
+     *
+     * @param fn the function to use to compute another CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the type of the returned CompletionStage's result
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> thenComposeAsync
+        (Function<? super T, ? extends CompletionStage<U>> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed with this stage's
+     * result and exception as arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handle
+        (BiFunction<? super T, Throwable, ? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed using this stage's
+     * default asynchronous execution facility, with this stage's
+     * result and exception as arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handleAsync
+        (BiFunction<? super T, Throwable, ? extends U> fn);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * either normally or exceptionally, is executed using the
+     * supplied executor, with this stage's result and exception as
+     * arguments to the supplied function.
+     *
+     * <p>When this stage is complete, the given function is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments, and the
+     * function's result is used to complete the returned stage.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage
+     * @param executor the executor to use for asynchronous execution
+     * @param <U> the function's return type
+     * @return the new CompletionStage
+     */
+    public <U> CompletionStage<U> handleAsync
+        (BiFunction<? super T, Throwable, ? extends U> fn,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked
+     * with the result (or {@code null} if none) and the exception (or
+     * {@code null} if none) of this stage as arguments.  The returned
+     * stage is completed when the action returns.
+     *
+     * <p>Unlike method {@link #handle handle},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: if this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenComplete
+        (BiConsumer<? super T, ? super Throwable> action);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action using this stage's
+     * default asynchronous execution facility when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked with the
+     * result (or {@code null} if none) and the exception (or {@code null}
+     * if none) of this stage as arguments.  The returned stage is completed
+     * when the action returns.
+     *
+     * <p>Unlike method {@link #handleAsync(BiFunction) handleAsync},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: If this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenCompleteAsync
+        (BiConsumer<? super T, ? super Throwable> action);
+
+    /**
+     * Returns a new CompletionStage with the same result or exception as
+     * this stage, that executes the given action using the supplied
+     * Executor when this stage completes.
+     *
+     * <p>When this stage is complete, the given action is invoked with the
+     * result (or {@code null} if none) and the exception (or {@code null}
+     * if none) of this stage as arguments.  The returned stage is completed
+     * when the action returns.
+     *
+     * <p>Unlike method {@link #handleAsync(BiFunction,Executor) handleAsync},
+     * this method is not designed to translate completion outcomes,
+     * so the supplied action should not throw an exception. However,
+     * if it does, the following rules apply: If this stage completed
+     * normally but the supplied action throws an exception, then the
+     * returned stage completes exceptionally with the supplied
+     * action's exception. Or, if this stage completed exceptionally
+     * and the supplied action throws an exception, then the returned
+     * stage completes exceptionally with this stage's exception.
+     *
+     * @param action the action to perform
+     * @param executor the executor to use for asynchronous execution
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> whenCompleteAsync
+        (BiConsumer<? super T, ? super Throwable> action,
+         Executor executor);
+
+    /**
+     * Returns a new CompletionStage that, when this stage completes
+     * exceptionally, is executed with this stage's exception as the
+     * argument to the supplied function.  Otherwise, if this stage
+     * completes normally, then the returned stage also completes
+     * normally with the same value.
+     *
+     * @param fn the function to use to compute the value of the
+     * returned CompletionStage if this CompletionStage completed
+     * exceptionally
+     * @return the new CompletionStage
+     */
+    public CompletionStage<T> exceptionally
+        (Function<Throwable, ? extends T> fn);
+
+    /**
+     * Returns a {@link CompletableFuture} maintaining the same
+     * completion properties as this stage. If this stage is already a
+     * CompletableFuture, this method may return this stage itself.
+     * Otherwise, invocation of this method may be equivalent in
+     * effect to {@code thenApply(x -> x)}, but returning an instance
+     * of type {@code CompletableFuture}. A CompletionStage
+     * implementation that does not choose to interoperate with others
+     * may throw {@code UnsupportedOperationException}.
+     *
+     * @return the CompletableFuture
+     * @throws UnsupportedOperationException if this implementation
+     * does not interoperate with CompletableFuture
+     */
+    public CompletableFuture<T> toCompletableFuture();
+
+}
diff --git a/java/util/concurrent/ConcurrentHashMap.annotated.java b/java/util/concurrent/ConcurrentHashMap.annotated.java
new file mode 100644
index 0000000..bf53e84
--- /dev/null
+++ b/java/util/concurrent/ConcurrentHashMap.annotated.java
@@ -0,0 +1,238 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+
+package java.util.concurrent;
+
+import java.util.Set;
+import java.util.HashMap;
+import java.util.AbstractMap;
+import java.util.Iterator;
+import java.util.stream.Stream;
+import java.util.Spliterator;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Collection;
+import java.util.function.Function;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ConcurrentHashMap<K, V> extends java.util.AbstractMap<@libcore.util.NonNull K, @libcore.util.NonNull V> implements java.util.concurrent.ConcurrentMap<@libcore.util.NonNull K, @libcore.util.NonNull V>, java.io.Serializable {
+
+  public ConcurrentHashMap() { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V> m) { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(int initialCapacity, float loadFactor) { throw new RuntimeException("Stub!"); }
+
+  public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { throw new RuntimeException("Stub!"); }
+
+  public int size() { throw new RuntimeException("Stub!"); }
+
+  public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V get(@libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+  public boolean containsKey(@libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+  public boolean containsValue(@libcore.util.NonNull java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V put(@libcore.util.NonNull K key, @libcore.util.NonNull V value) { throw new RuntimeException("Stub!"); }
+
+  public void putAll(@libcore.util.NonNull java.util.Map<? extends @libcore.util.NonNull K,? extends @libcore.util.NonNull V> m) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V remove(@libcore.util.NonNull java.lang.Object key) { throw new RuntimeException("Stub!"); }
+
+  public void clear() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Set<@libcore.util.NonNull K> keySet() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Collection<@libcore.util.NonNull V> values() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Set<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> entrySet() { throw new RuntimeException("Stub!"); }
+
+  public int hashCode() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+  public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V putIfAbsent(@libcore.util.NonNull K key, @libcore.util.NonNull V value) { throw new RuntimeException("Stub!"); }
+
+  public boolean remove(@libcore.util.NonNull java.lang.Object key, @libcore.util.Nullable java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+  public boolean replace(@libcore.util.NonNull K key, @libcore.util.NonNull V oldValue, @libcore.util.NonNull V newValue) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V replace(@libcore.util.NonNull K key, @libcore.util.NonNull V value) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V getOrDefault(@libcore.util.NonNull java.lang.Object key, @libcore.util.Nullable V defaultValue) { throw new RuntimeException("Stub!"); }
+
+  public void forEach(@libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> action) { throw new RuntimeException("Stub!"); }
+
+  public void replaceAll(@libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.NonNull V> function) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V computeIfAbsent(@libcore.util.NonNull K key, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable V> mappingFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V computeIfPresent(@libcore.util.NonNull K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V compute(@libcore.util.NonNull K key, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.Nullable V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V merge(@libcore.util.NonNull K key, @libcore.util.NonNull V value, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> remappingFunction) { throw new RuntimeException("Stub!"); }
+
+  public boolean contains(@libcore.util.NonNull java.lang.Object value) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Enumeration<@libcore.util.NonNull K> keys() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.Enumeration<@libcore.util.NonNull V> elements() { throw new RuntimeException("Stub!"); }
+
+  public long mappingCount() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public static <@libcore.util.NonNull K> java.util.concurrent.ConcurrentHashMap.KeySetView<@libcore.util.NonNull K, @libcore.util.NonNull java.lang.Boolean> newKeySet() { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public static <@libcore.util.NonNull K> java.util.concurrent.ConcurrentHashMap.KeySetView<@libcore.util.NonNull K, @libcore.util.NonNull java.lang.Boolean> newKeySet(int initialCapacity) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.NonNull public java.util.concurrent.ConcurrentHashMap.KeySetView<@libcore.util.NonNull K, @libcore.util.NonNull V> keySet(@libcore.util.NonNull V mappedValue) { throw new RuntimeException("Stub!"); }
+
+  public void forEach(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiConsumer<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEach(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U search(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduce(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleBiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongBiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntBiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull V> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public void forEachKey(long parallelismThreshold, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull K> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEachKey(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U searchKeys(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public K reduceKeys(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull K,? super @libcore.util.NonNull K,? extends @libcore.util.Nullable K> reducer) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduceKeys(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull K,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceKeysToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleFunction<? super @libcore.util.NonNull K> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceKeysToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongFunction<? super @libcore.util.NonNull K> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceKeysToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntFunction<? super @libcore.util.NonNull K> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public void forEachValue(long parallelismThreshold, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull V> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEachValue(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U searchValues(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public V reduceValues(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull V,? super @libcore.util.NonNull V,? extends @libcore.util.Nullable V> reducer) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduceValues(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<? super @libcore.util.NonNull V,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceValuesToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleFunction<? super @libcore.util.NonNull V> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceValuesToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongFunction<? super @libcore.util.NonNull V> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceValuesToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntFunction<? super @libcore.util.NonNull V> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public void forEachEntry(long parallelismThreshold, @libcore.util.NonNull java.util.function.Consumer<? super [email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> action) { throw new RuntimeException("Stub!"); }
+
+  public <U> void forEachEntry(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull U> action) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U searchEntries(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends @libcore.util.Nullable U> searchFunction) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public java.util.Map.Entry<@libcore.util.NonNull K, @libcore.util.NonNull V> reduceEntries(long parallelismThreshold, @libcore.util.NonNull java.util.function.BiFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>, [email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends [email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> reducer) { throw new RuntimeException("Stub!"); }
+
+  @libcore.util.Nullable public <U> U reduceEntries(long parallelismThreshold, @libcore.util.NonNull java.util.function.Function<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>,? extends @libcore.util.Nullable U> transformer, @libcore.util.NonNull java.util.function.BiFunction<? super @libcore.util.NonNull U,? super @libcore.util.NonNull U,? extends @libcore.util.Nullable U> reducer) { throw new RuntimeException("Stub!"); }
+
+  public double reduceEntriesToDouble(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToDoubleFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> transformer, double basis, @libcore.util.NonNull java.util.function.DoubleBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public long reduceEntriesToLong(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToLongFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> transformer, long basis, @libcore.util.NonNull java.util.function.LongBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  public int reduceEntriesToInt(long parallelismThreshold, @libcore.util.NonNull java.util.function.ToIntFunction<[email protected] Entry<@libcore.util.NonNull K, @libcore.util.NonNull V>> transformer, int basis, @libcore.util.NonNull java.util.function.IntBinaryOperator reducer) { throw new RuntimeException("Stub!"); }
+
+  @SuppressWarnings({"unchecked", "deprecation", "all"})
+  public static class KeySetView<K, V> implements java.util.Collection<K>, java.io.Serializable, java.util.Set<K> {
+
+    KeySetView(@libcore.util.NonNull java.util.concurrent.ConcurrentHashMap<K,V> map, @libcore.util.Nullable V value) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.Nullable public V getMappedValue() { throw new RuntimeException("Stub!"); }
+
+    public boolean contains(@libcore.util.NonNull java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+    public boolean remove(@libcore.util.NonNull java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public java.util.Iterator<@libcore.util.NonNull K> iterator() { throw new RuntimeException("Stub!"); }
+
+    public boolean add(@libcore.util.NonNull K e) { throw new RuntimeException("Stub!"); }
+
+    public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NonNull K> c) { throw new RuntimeException("Stub!"); }
+
+    public int hashCode() { throw new RuntimeException("Stub!"); }
+
+    public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public java.util.Spliterator<@libcore.util.NonNull K> spliterator() { throw new RuntimeException("Stub!"); }
+
+    public void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NonNull K> action) { throw new RuntimeException("Stub!"); }
+
+    public final boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+    public final int size() { throw new RuntimeException("Stub!"); }
+
+    public final boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+    public final void clear() { throw new RuntimeException("Stub!"); }
+
+    public final boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+    public final [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+    public final <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public final java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+    @libcore.util.NonNull public java.util.concurrent.ConcurrentHashMap<@libcore.util.NonNull K, @libcore.util.NonNull V> getMap() { throw new RuntimeException("Stub!"); }
+
+    public final boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+  }
+
+}
diff --git a/java/util/concurrent/ConcurrentHashMap.java b/java/util/concurrent/ConcurrentHashMap.java
new file mode 100644
index 0000000..5407963
--- /dev/null
+++ b/java/util/concurrent/ConcurrentHashMap.java
@@ -0,0 +1,6383 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.ObjectStreamField;
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.Predicate;
+import java.util.function.ToDoubleBiFunction;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntBiFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongBiFunction;
+import java.util.function.ToLongFunction;
+import java.util.stream.Stream;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A hash table supporting full concurrency of retrievals and
+ * high expected concurrency for updates. This class obeys the
+ * same functional specification as {@link java.util.Hashtable}, and
+ * includes versions of methods corresponding to each method of
+ * {@code Hashtable}. However, even though all operations are
+ * thread-safe, retrieval operations do <em>not</em> entail locking,
+ * and there is <em>not</em> any support for locking the entire table
+ * in a way that prevents all access.  This class is fully
+ * interoperable with {@code Hashtable} in programs that rely on its
+ * thread safety but not on its synchronization details.
+ *
+ * <p>Retrieval operations (including {@code get}) generally do not
+ * block, so may overlap with update operations (including {@code put}
+ * and {@code remove}). Retrievals reflect the results of the most
+ * recently <em>completed</em> update operations holding upon their
+ * onset. (More formally, an update operation for a given key bears a
+ * <em>happens-before</em> relation with any (non-null) retrieval for
+ * that key reporting the updated value.)  For aggregate operations
+ * such as {@code putAll} and {@code clear}, concurrent retrievals may
+ * reflect insertion or removal of only some entries.  Similarly,
+ * Iterators, Spliterators and Enumerations return elements reflecting the
+ * state of the hash table at some point at or since the creation of the
+ * iterator/enumeration.  They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException ConcurrentModificationException}.
+ * However, iterators are designed to be used by only one thread at a time.
+ * Bear in mind that the results of aggregate status methods including
+ * {@code size}, {@code isEmpty}, and {@code containsValue} are typically
+ * useful only when a map is not undergoing concurrent updates in other threads.
+ * Otherwise the results of these methods reflect transient states
+ * that may be adequate for monitoring or estimation purposes, but not
+ * for program control.
+ *
+ * <p>The table is dynamically expanded when there are too many
+ * collisions (i.e., keys that have distinct hash codes but fall into
+ * the same slot modulo the table size), with the expected average
+ * effect of maintaining roughly two bins per mapping (corresponding
+ * to a 0.75 load factor threshold for resizing). There may be much
+ * variance around this average as mappings are added and removed, but
+ * overall, this maintains a commonly accepted time/space tradeoff for
+ * hash tables.  However, resizing this or any other kind of hash
+ * table may be a relatively slow operation. When possible, it is a
+ * good idea to provide a size estimate as an optional {@code
+ * initialCapacity} constructor argument. An additional optional
+ * {@code loadFactor} constructor argument provides a further means of
+ * customizing initial table capacity by specifying the table density
+ * to be used in calculating the amount of space to allocate for the
+ * given number of elements.  Also, for compatibility with previous
+ * versions of this class, constructors may optionally specify an
+ * expected {@code concurrencyLevel} as an additional hint for
+ * internal sizing.  Note that using many keys with exactly the same
+ * {@code hashCode()} is a sure way to slow down performance of any
+ * hash table. To ameliorate impact, when keys are {@link Comparable},
+ * this class may use comparison order among keys to help break ties.
+ *
+ * <p>A {@link Set} projection of a ConcurrentHashMap may be created
+ * (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
+ * (using {@link #keySet(Object)} when only keys are of interest, and the
+ * mapped values are (perhaps transiently) not used or all take the
+ * same mapping value.
+ *
+ * <p>A ConcurrentHashMap can be used as a scalable frequency map (a
+ * form of histogram or multiset) by using {@link
+ * java.util.concurrent.atomic.LongAdder} values and initializing via
+ * {@link #computeIfAbsent computeIfAbsent}. For example, to add a count
+ * to a {@code ConcurrentHashMap<String,LongAdder> freqs}, you can use
+ * {@code freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces.
+ *
+ * <p>Like {@link Hashtable} but unlike {@link HashMap}, this class
+ * does <em>not</em> allow {@code null} to be used as a key or value.
+ *
+ * <p>ConcurrentHashMaps support a set of sequential and parallel bulk
+ * operations that, unlike most {@link Stream} methods, are designed
+ * to be safely, and often sensibly, applied even with maps that are
+ * being concurrently updated by other threads; for example, when
+ * computing a snapshot summary of the values in a shared registry.
+ * There are three kinds of operation, each with four forms, accepting
+ * functions with keys, values, entries, and (key, value) pairs as
+ * arguments and/or return values. Because the elements of a
+ * ConcurrentHashMap are not ordered in any particular way, and may be
+ * processed in different orders in different parallel executions, the
+ * correctness of supplied functions should not depend on any
+ * ordering, or on any other objects or values that may transiently
+ * change while computation is in progress; and except for forEach
+ * actions, should ideally be side-effect-free. Bulk operations on
+ * {@link java.util.Map.Entry} objects do not support method {@code
+ * setValue}.
+ *
+ * <ul>
+ * <li>forEach: Performs a given action on each element.
+ * A variant form applies a given transformation on each element
+ * before performing the action.
+ *
+ * <li>search: Returns the first available non-null result of
+ * applying a given function on each element; skipping further
+ * search when a result is found.
+ *
+ * <li>reduce: Accumulates each element.  The supplied reduction
+ * function cannot rely on ordering (more formally, it should be
+ * both associative and commutative).  There are five variants:
+ *
+ * <ul>
+ *
+ * <li>Plain reductions. (There is not a form of this method for
+ * (key, value) function arguments since there is no corresponding
+ * return type.)
+ *
+ * <li>Mapped reductions that accumulate the results of a given
+ * function applied to each element.
+ *
+ * <li>Reductions to scalar doubles, longs, and ints, using a
+ * given basis value.
+ *
+ * </ul>
+ * </ul>
+ *
+ * <p>These bulk operations accept a {@code parallelismThreshold}
+ * argument. Methods proceed sequentially if the current map size is
+ * estimated to be less than the given threshold. Using a value of
+ * {@code Long.MAX_VALUE} suppresses all parallelism.  Using a value
+ * of {@code 1} results in maximal parallelism by partitioning into
+ * enough subtasks to fully utilize the {@link
+ * ForkJoinPool#commonPool()} that is used for all parallel
+ * computations. Normally, you would initially choose one of these
+ * extreme values, and then measure performance of using in-between
+ * values that trade off overhead versus throughput.
+ *
+ * <p>The concurrency properties of bulk operations follow
+ * from those of ConcurrentHashMap: Any non-null result returned
+ * from {@code get(key)} and related access methods bears a
+ * happens-before relation with the associated insertion or
+ * update.  The result of any bulk operation reflects the
+ * composition of these per-element relations (but is not
+ * necessarily atomic with respect to the map as a whole unless it
+ * is somehow known to be quiescent).  Conversely, because keys
+ * and values in the map are never null, null serves as a reliable
+ * atomic indicator of the current lack of any result.  To
+ * maintain this property, null serves as an implicit basis for
+ * all non-scalar reduction operations. For the double, long, and
+ * int versions, the basis should be one that, when combined with
+ * any other value, returns that other value (more formally, it
+ * should be the identity element for the reduction). Most common
+ * reductions have these properties; for example, computing a sum
+ * with basis 0 or a minimum with basis MAX_VALUE.
+ *
+ * <p>Search and transformation functions provided as arguments
+ * should similarly return null to indicate the lack of any result
+ * (in which case it is not used). In the case of mapped
+ * reductions, this also enables transformations to serve as
+ * filters, returning null (or, in the case of primitive
+ * specializations, the identity basis) if the element should not
+ * be combined. You can create compound transformations and
+ * filterings by composing them yourself under this "null means
+ * there is nothing there now" rule before using them in search or
+ * reduce operations.
+ *
+ * <p>Methods accepting and/or returning Entry arguments maintain
+ * key-value associations. They may be useful for example when
+ * finding the key for the greatest value. Note that "plain" Entry
+ * arguments can be supplied using {@code new
+ * AbstractMap.SimpleEntry(k,v)}.
+ *
+ * <p>Bulk operations may complete abruptly, throwing an
+ * exception encountered in the application of a supplied
+ * function. Bear in mind when handling such exceptions that other
+ * concurrently executing functions could also have thrown
+ * exceptions, or would have done so if the first exception had
+ * not occurred.
+ *
+ * <p>Speedups for parallel compared to sequential forms are common
+ * but not guaranteed.  Parallel operations involving brief functions
+ * on small maps may execute more slowly than sequential forms if the
+ * underlying work to parallelize the computation is more expensive
+ * than the computation itself.  Similarly, parallelization may not
+ * lead to much actual parallelism if all processors are busy
+ * performing unrelated tasks.
+ *
+ * <p>All arguments to all task methods must be non-null.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentMap<K,V>, Serializable {
+    private static final long serialVersionUID = 7249069246763182397L;
+
+    /*
+     * Overview:
+     *
+     * The primary design goal of this hash table is to maintain
+     * concurrent readability (typically method get(), but also
+     * iterators and related methods) while minimizing update
+     * contention. Secondary goals are to keep space consumption about
+     * the same or better than java.util.HashMap, and to support high
+     * initial insertion rates on an empty table by many threads.
+     *
+     * This map usually acts as a binned (bucketed) hash table.  Each
+     * key-value mapping is held in a Node.  Most nodes are instances
+     * of the basic Node class with hash, key, value, and next
+     * fields. However, various subclasses exist: TreeNodes are
+     * arranged in balanced trees, not lists.  TreeBins hold the roots
+     * of sets of TreeNodes. ForwardingNodes are placed at the heads
+     * of bins during resizing. ReservationNodes are used as
+     * placeholders while establishing values in computeIfAbsent and
+     * related methods.  The types TreeBin, ForwardingNode, and
+     * ReservationNode do not hold normal user keys, values, or
+     * hashes, and are readily distinguishable during search etc
+     * because they have negative hash fields and null key and value
+     * fields. (These special nodes are either uncommon or transient,
+     * so the impact of carrying around some unused fields is
+     * insignificant.)
+     *
+     * The table is lazily initialized to a power-of-two size upon the
+     * first insertion.  Each bin in the table normally contains a
+     * list of Nodes (most often, the list has only zero or one Node).
+     * Table accesses require volatile/atomic reads, writes, and
+     * CASes.  Because there is no other way to arrange this without
+     * adding further indirections, we use intrinsics
+     * (sun.misc.Unsafe) operations.
+     *
+     * We use the top (sign) bit of Node hash fields for control
+     * purposes -- it is available anyway because of addressing
+     * constraints.  Nodes with negative hash fields are specially
+     * handled or ignored in map methods.
+     *
+     * Insertion (via put or its variants) of the first node in an
+     * empty bin is performed by just CASing it to the bin.  This is
+     * by far the most common case for put operations under most
+     * key/hash distributions.  Other update operations (insert,
+     * delete, and replace) require locks.  We do not want to waste
+     * the space required to associate a distinct lock object with
+     * each bin, so instead use the first node of a bin list itself as
+     * a lock. Locking support for these locks relies on builtin
+     * "synchronized" monitors.
+     *
+     * Using the first node of a list as a lock does not by itself
+     * suffice though: When a node is locked, any update must first
+     * validate that it is still the first node after locking it, and
+     * retry if not. Because new nodes are always appended to lists,
+     * once a node is first in a bin, it remains first until deleted
+     * or the bin becomes invalidated (upon resizing).
+     *
+     * The main disadvantage of per-bin locks is that other update
+     * operations on other nodes in a bin list protected by the same
+     * lock can stall, for example when user equals() or mapping
+     * functions take a long time.  However, statistically, under
+     * random hash codes, this is not a common problem.  Ideally, the
+     * frequency of nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average, given the resizing threshold
+     * of 0.75, although with a large variance because of resizing
+     * granularity. Ignoring variance, the expected occurrences of
+     * list size k are (exp(-0.5) * pow(0.5, k) / factorial(k)). The
+     * first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * Lock contention probability for two threads accessing distinct
+     * elements is roughly 1 / (8 * #elements) under random hashes.
+     *
+     * Actual hash code distributions encountered in practice
+     * sometimes deviate significantly from uniform randomness.  This
+     * includes the case when N > (1<<30), so some keys MUST collide.
+     * Similarly for dumb or hostile usages in which multiple keys are
+     * designed to have identical hash codes or ones that differs only
+     * in masked-out high bits. So we use a secondary strategy that
+     * applies when the number of nodes in a bin exceeds a
+     * threshold. These TreeBins use a balanced tree to hold nodes (a
+     * specialized form of red-black trees), bounding search time to
+     * O(log N).  Each search step in a TreeBin is at least twice as
+     * slow as in a regular list, but given that N cannot exceed
+     * (1<<64) (before running out of addresses) this bounds search
+     * steps, lock hold times, etc, to reasonable constants (roughly
+     * 100 nodes inspected per operation worst case) so long as keys
+     * are Comparable (which is very common -- String, Long, etc).
+     * TreeBin nodes (TreeNodes) also maintain the same "next"
+     * traversal pointers as regular nodes, so can be traversed in
+     * iterators in the same way.
+     *
+     * The table is resized when occupancy exceeds a percentage
+     * threshold (nominally, 0.75, but see below).  Any thread
+     * noticing an overfull bin may assist in resizing after the
+     * initiating thread allocates and sets up the replacement array.
+     * However, rather than stalling, these other threads may proceed
+     * with insertions etc.  The use of TreeBins shields us from the
+     * worst case effects of overfilling while resizes are in
+     * progress.  Resizing proceeds by transferring bins, one by one,
+     * from the table to the next table. However, threads claim small
+     * blocks of indices to transfer (via field transferIndex) before
+     * doing so, reducing contention.  A generation stamp in field
+     * sizeCtl ensures that resizings do not overlap. Because we are
+     * using power-of-two expansion, the elements from each bin must
+     * either stay at same index, or move with a power of two
+     * offset. We eliminate unnecessary node creation by catching
+     * cases where old nodes can be reused because their next fields
+     * won't change.  On average, only about one-sixth of them need
+     * cloning when a table doubles. The nodes they replace will be
+     * garbage collectable as soon as they are no longer referenced by
+     * any reader thread that may be in the midst of concurrently
+     * traversing table.  Upon transfer, the old table bin contains
+     * only a special forwarding node (with hash field "MOVED") that
+     * contains the next table as its key. On encountering a
+     * forwarding node, access and update operations restart, using
+     * the new table.
+     *
+     * Each bin transfer requires its bin lock, which can stall
+     * waiting for locks while resizing. However, because other
+     * threads can join in and help resize rather than contend for
+     * locks, average aggregate waits become shorter as resizing
+     * progresses.  The transfer operation must also ensure that all
+     * accessible bins in both the old and new table are usable by any
+     * traversal.  This is arranged in part by proceeding from the
+     * last bin (table.length - 1) up towards the first.  Upon seeing
+     * a forwarding node, traversals (see class Traverser) arrange to
+     * move to the new table without revisiting nodes.  To ensure that
+     * no intervening nodes are skipped even when moved out of order,
+     * a stack (see class TableStack) is created on first encounter of
+     * a forwarding node during a traversal, to maintain its place if
+     * later processing the current table. The need for these
+     * save/restore mechanics is relatively rare, but when one
+     * forwarding node is encountered, typically many more will be.
+     * So Traversers use a simple caching scheme to avoid creating so
+     * many new TableStack nodes. (Thanks to Peter Levart for
+     * suggesting use of a stack here.)
+     *
+     * The traversal scheme also applies to partial traversals of
+     * ranges of bins (via an alternate Traverser constructor)
+     * to support partitioned aggregate operations.  Also, read-only
+     * operations give up if ever forwarded to a null table, which
+     * provides support for shutdown-style clearing, which is also not
+     * currently implemented.
+     *
+     * Lazy table initialization minimizes footprint until first use,
+     * and also avoids resizings when the first operation is from a
+     * putAll, constructor with map argument, or deserialization.
+     * These cases attempt to override the initial capacity settings,
+     * but harmlessly fail to take effect in cases of races.
+     *
+     * The element count is maintained using a specialization of
+     * LongAdder. We need to incorporate a specialization rather than
+     * just use a LongAdder in order to access implicit
+     * contention-sensing that leads to creation of multiple
+     * CounterCells.  The counter mechanics avoid contention on
+     * updates but can encounter cache thrashing if read too
+     * frequently during concurrent access. To avoid reading so often,
+     * resizing under contention is attempted only upon adding to a
+     * bin already holding two or more nodes. Under uniform hash
+     * distributions, the probability of this occurring at threshold
+     * is around 13%, meaning that only about 1 in 8 puts check
+     * threshold (and after resizing, many fewer do so).
+     *
+     * TreeBins use a special form of comparison for search and
+     * related operations (which is the main reason we cannot use
+     * existing collections such as TreeMaps). TreeBins contain
+     * Comparable elements, but may contain others, as well as
+     * elements that are Comparable but not necessarily Comparable for
+     * the same T, so we cannot invoke compareTo among them. To handle
+     * this, the tree is ordered primarily by hash value, then by
+     * Comparable.compareTo order if applicable.  On lookup at a node,
+     * if elements are not comparable or compare as 0 then both left
+     * and right children may need to be searched in the case of tied
+     * hash values. (This corresponds to the full list search that
+     * would be necessary if all elements were non-Comparable and had
+     * tied hashes.) On insertion, to keep a total ordering (or as
+     * close as is required here) across rebalancings, we compare
+     * classes and identityHashCodes as tie-breakers. The red-black
+     * balancing code is updated from pre-jdk-collections
+     * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
+     * based in turn on Cormen, Leiserson, and Rivest "Introduction to
+     * Algorithms" (CLR).
+     *
+     * TreeBins also require an additional locking mechanism.  While
+     * list traversal is always possible by readers even during
+     * updates, tree traversal is not, mainly because of tree-rotations
+     * that may change the root node and/or its linkages.  TreeBins
+     * include a simple read-write lock mechanism parasitic on the
+     * main bin-synchronization strategy: Structural adjustments
+     * associated with an insertion or removal are already bin-locked
+     * (and so cannot conflict with other writers) but must wait for
+     * ongoing readers to finish. Since there can be only one such
+     * waiter, we use a simple scheme using a single "waiter" field to
+     * block writers.  However, readers need never block.  If the root
+     * lock is held, they proceed along the slow traversal path (via
+     * next-pointers) until the lock becomes available or the list is
+     * exhausted, whichever comes first. These cases are not fast, but
+     * maximize aggregate expected throughput.
+     *
+     * Maintaining API and serialization compatibility with previous
+     * versions of this class introduces several oddities. Mainly: We
+     * leave untouched but unused constructor arguments referring to
+     * concurrencyLevel. We accept a loadFactor constructor argument,
+     * but apply it only to initial table capacity (which is the only
+     * time that we can guarantee to honor it.) We also declare an
+     * unused "Segment" class that is instantiated in minimal form
+     * only when serializing.
+     *
+     * Also, solely for compatibility with previous versions of this
+     * class, it extends AbstractMap, even though all of its methods
+     * are overridden, so it is just useless baggage.
+     *
+     * This file is organized to make things a little easier to follow
+     * while reading than they might otherwise: First the main static
+     * declarations and utilities, then fields, then main public
+     * methods (with a few factorings of multiple public methods into
+     * internal ones), then sizing methods, trees, traversers, and
+     * bulk operations.
+     */
+
+    /* ---------------- Constants -------------- */
+
+    /**
+     * The largest possible table capacity.  This value must be
+     * exactly 1<<30 to stay within Java array allocation and indexing
+     * bounds for power of two table sizes, and is further required
+     * because the top two bits of 32bit hash fields are used for
+     * control purposes.
+     */
+    private static final int MAXIMUM_CAPACITY = 1 << 30;
+
+    /**
+     * The default initial table capacity.  Must be a power of 2
+     * (i.e., at least 1) and at most MAXIMUM_CAPACITY.
+     */
+    private static final int DEFAULT_CAPACITY = 16;
+
+    /**
+     * The largest possible (non-power of two) array size.
+     * Needed by toArray and related methods.
+     */
+    static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * The default concurrency level for this table. Unused but
+     * defined for compatibility with previous versions of this class.
+     */
+    private static final int DEFAULT_CONCURRENCY_LEVEL = 16;
+
+    /**
+     * The load factor for this table. Overrides of this value in
+     * constructors affect only the initial table capacity.  The
+     * actual floating point value isn't normally used -- it is
+     * simpler to use expressions such as {@code n - (n >>> 2)} for
+     * the associated resizing threshold.
+     */
+    private static final float LOAD_FACTOR = 0.75f;
+
+    /**
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2, and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * The value should be at least 4 * TREEIFY_THRESHOLD to avoid
+     * conflicts between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Minimum number of rebinnings per transfer step. Ranges are
+     * subdivided to allow multiple resizer threads.  This value
+     * serves as a lower bound to avoid resizers encountering
+     * excessive memory contention.  The value should be at least
+     * DEFAULT_CAPACITY.
+     */
+    private static final int MIN_TRANSFER_STRIDE = 16;
+
+    /**
+     * The number of bits used for generation stamp in sizeCtl.
+     * Must be at least 6 for 32bit arrays.
+     */
+    private static final int RESIZE_STAMP_BITS = 16;
+
+    /**
+     * The maximum number of threads that can help resize.
+     * Must fit in 32 - RESIZE_STAMP_BITS bits.
+     */
+    private static final int MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
+
+    /**
+     * The bit shift for recording size stamp in sizeCtl.
+     */
+    private static final int RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
+
+    /*
+     * Encodings for Node hash fields. See above for explanation.
+     */
+    static final int MOVED     = -1; // hash for forwarding nodes
+    static final int TREEBIN   = -2; // hash for roots of trees
+    static final int RESERVED  = -3; // hash for transient reservations
+    static final int HASH_BITS = 0x7fffffff; // usable bits of normal node hash
+
+    /** Number of CPUS, to place bounds on some sizings */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * Serialized pseudo-fields, provided only for jdk7 compatibility.
+     * @serialField segments Segment[]
+     *   The segments, each of which is a specialized hash table.
+     * @serialField segmentMask int
+     *   Mask value for indexing into segments. The upper bits of a
+     *   key's hash code are used to choose the segment.
+     * @serialField segmentShift int
+     *   Shift value for indexing within segments.
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("segments", Segment[].class),
+        new ObjectStreamField("segmentMask", Integer.TYPE),
+        new ObjectStreamField("segmentShift", Integer.TYPE),
+    };
+
+    /* ---------------- Nodes -------------- */
+
+    /**
+     * Key-value entry.  This class is never exported out as a
+     * user-mutable Map.Entry (i.e., one supporting setValue; see
+     * MapEntry below), but can be used for read-only traversals used
+     * in bulk tasks.  Subclasses of Node with a negative hash field
+     * are special, and contain null keys and values (but are never
+     * exported).  Otherwise, keys and vals are never null.
+     */
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        volatile V val;
+        volatile Node<K,V> next;
+
+        Node(int hash, K key, V val, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.val = val;
+            this.next = next;
+        }
+
+        public final K getKey()     { return key; }
+        public final V getValue()   { return val; }
+        public final int hashCode() { return key.hashCode() ^ val.hashCode(); }
+        public final String toString() {
+            return Helpers.mapEntryToString(key, val);
+        }
+        public final V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+
+        public final boolean equals(Object o) {
+            Object k, v, u; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == (u = val) || v.equals(u)));
+        }
+
+        /**
+         * Virtualized support for map.get(); overridden in subclasses.
+         */
+        Node<K,V> find(int h, Object k) {
+            Node<K,V> e = this;
+            if (k != null) {
+                do {
+                    K ek;
+                    if (e.hash == h &&
+                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+            return null;
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
+
+    /**
+     * Spreads (XORs) higher bits of hash to lower and also forces top
+     * bit to 0. Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int spread(int h) {
+        return (h ^ (h >>> 16)) & HASH_BITS;
+    }
+
+    /**
+     * Returns a power of two table size for the given desired capacity.
+     * See Hackers Delight, sec 3.2
+     */
+    private static final int tableSizeFor(int c) {
+        int n = c - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
+     */
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /* ---------------- Table element access -------------- */
+
+    /*
+     * Volatile access methods are used for table elements as well as
+     * elements of in-progress next table while resizing.  All uses of
+     * the tab arguments must be null checked by callers.  All callers
+     * also paranoically precheck that tab's length is not zero (or an
+     * equivalent check), thus ensuring that any index argument taking
+     * the form of a hash value anded with (length - 1) is a valid
+     * index.  Note that, to be correct wrt arbitrary concurrency
+     * errors by users, these checks must operate on local variables,
+     * which accounts for some odd-looking inline assignments below.
+     * Note that calls to setTabAt always occur within locked regions,
+     * and so in principle require only release ordering, not
+     * full volatile semantics, but are currently coded as volatile
+     * writes to be conservative.
+     */
+
+    @SuppressWarnings("unchecked")
+    static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
+        return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+    }
+
+    static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
+                                        Node<K,V> c, Node<K,V> v) {
+        return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
+    }
+
+    static final <K,V> void setTabAt(Node<K,V>[] tab, int i, Node<K,V> v) {
+        U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The array of bins. Lazily initialized upon first insertion.
+     * Size is always a power of two. Accessed directly by iterators.
+     */
+    transient volatile Node<K,V>[] table;
+
+    /**
+     * The next table to use; non-null only while resizing.
+     */
+    private transient volatile Node<K,V>[] nextTable;
+
+    /**
+     * Base counter value, used mainly when there is no contention,
+     * but also as a fallback during table initialization
+     * races. Updated via CAS.
+     */
+    private transient volatile long baseCount;
+
+    /**
+     * Table initialization and resizing control.  When negative, the
+     * table is being initialized or resized: -1 for initialization,
+     * else -(1 + the number of active resizing threads).  Otherwise,
+     * when table is null, holds the initial table size to use upon
+     * creation, or 0 for default. After initialization, holds the
+     * next element count value upon which to resize the table.
+     */
+    private transient volatile int sizeCtl;
+
+    /**
+     * The next table index (plus one) to split while resizing.
+     */
+    private transient volatile int transferIndex;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
+     */
+    private transient volatile int cellsBusy;
+
+    /**
+     * Table of counter cells. When non-null, size is a power of 2.
+     */
+    private transient volatile CounterCell[] counterCells;
+
+    // views
+    private transient KeySetView<K,V> keySet;
+    private transient ValuesView<K,V> values;
+    private transient EntrySetView<K,V> entrySet;
+
+
+    /* ---------------- Public operations -------------- */
+
+    /**
+     * Creates a new, empty map with the default initial table size (16).
+     */
+    public ConcurrentHashMap() {
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size
+     * accommodating the specified number of elements without the need
+     * to dynamically resize.
+     *
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     */
+    public ConcurrentHashMap(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException();
+        int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
+                   MAXIMUM_CAPACITY :
+                   tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
+        this.sizeCtl = cap;
+    }
+
+    /**
+     * Creates a new map with the same mappings as the given map.
+     *
+     * @param m the map
+     */
+    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
+        this.sizeCtl = DEFAULT_CAPACITY;
+        putAll(m);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}) and
+     * initial table density ({@code loadFactor}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative or the load factor is nonpositive
+     *
+     * @since 1.6
+     */
+    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
+        this(initialCapacity, loadFactor, 1);
+    }
+
+    /**
+     * Creates a new, empty map with an initial table size based on
+     * the given number of elements ({@code initialCapacity}), table
+     * density ({@code loadFactor}), and number of concurrently
+     * updating threads ({@code concurrencyLevel}).
+     *
+     * @param initialCapacity the initial capacity. The implementation
+     * performs internal sizing to accommodate this many elements,
+     * given the specified load factor.
+     * @param loadFactor the load factor (table density) for
+     * establishing the initial table size
+     * @param concurrencyLevel the estimated number of concurrently
+     * updating threads. The implementation may use this value as
+     * a sizing hint.
+     * @throws IllegalArgumentException if the initial capacity is
+     * negative or the load factor or concurrencyLevel are
+     * nonpositive
+     */
+    public ConcurrentHashMap(int initialCapacity,
+                             float loadFactor, int concurrencyLevel) {
+        if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
+            throw new IllegalArgumentException();
+        if (initialCapacity < concurrencyLevel)   // Use at least as many bins
+            initialCapacity = concurrencyLevel;   // as estimated threads
+        long size = (long)(1.0 + (long)initialCapacity / loadFactor);
+        int cap = (size >= (long)MAXIMUM_CAPACITY) ?
+            MAXIMUM_CAPACITY : tableSizeFor((int)size);
+        this.sizeCtl = cap;
+    }
+
+    // Original (since JDK1.2) Map methods
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size() {
+        long n = sumCount();
+        return ((n < 0L) ? 0 :
+                (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
+                (int)n);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        return sumCount() <= 0L; // ignore transient negative values
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key.equals(k)},
+     * then this method returns {@code v}; otherwise it returns
+     * {@code null}.  (There can be at most one such mapping.)
+     *
+     * @throws NullPointerException if the specified key is null
+     */
+    public V get(Object key) {
+        Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
+        int h = spread(key.hashCode());
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (e = tabAt(tab, (n - 1) & h)) != null) {
+            if ((eh = e.hash) == h) {
+                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
+                    return e.val;
+            }
+            else if (eh < 0)
+                return (p = e.find(h, key)) != null ? p.val : null;
+            while ((e = e.next) != null) {
+                if (e.hash == h &&
+                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
+                    return e.val;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Tests if the specified object is a key in this table.
+     *
+     * @param  key possible key
+     * @return {@code true} if and only if the specified object
+     *         is a key in this table, as determined by the
+     *         {@code equals} method; {@code false} otherwise
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean containsKey(Object key) {
+        return get(key) != null;
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value. Note: This method may require a full traversal
+     * of the map, and is much slower than method {@code containsKey}.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if this map maps one or more keys to the
+     *         specified value
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V v;
+                if ((v = p.val) == value || (v != null && value.equals(v)))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Maps the specified key to the specified value in this table.
+     * Neither the key nor the value can be null.
+     *
+     * <p>The value can be retrieved by calling the {@code get} method
+     * with a key that is equal to the original key.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V put(K key, V value) {
+        return putVal(key, value, false);
+    }
+
+    /** Implementation for put and putIfAbsent */
+    final V putVal(K key, V value, boolean onlyIfAbsent) {
+        if (key == null || value == null) throw new NullPointerException();
+        int hash = spread(key.hashCode());
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
+                if (casTabAt(tab, i, null,
+                             new Node<K,V>(hash, key, value, null)))
+                    break;                   // no lock when adding to empty bin
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                V oldVal = null;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f;; ++binCount) {
+                                K ek;
+                                if (e.hash == hash &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    oldVal = e.val;
+                                    if (!onlyIfAbsent)
+                                        e.val = value;
+                                    break;
+                                }
+                                Node<K,V> pred = e;
+                                if ((e = e.next) == null) {
+                                    pred.next = new Node<K,V>(hash, key,
+                                                              value, null);
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            Node<K,V> p;
+                            binCount = 2;
+                            if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
+                                                           value)) != null) {
+                                oldVal = p.val;
+                                if (!onlyIfAbsent)
+                                    p.val = value;
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    if (oldVal != null)
+                        return oldVal;
+                    break;
+                }
+            }
+        }
+        addCount(1L, binCount);
+        return null;
+    }
+
+    /**
+     * Copies all of the mappings from the specified map to this one.
+     * These mappings replace any mappings that this map had for any of the
+     * keys currently in the specified map.
+     *
+     * @param m mappings to be stored in this map
+     */
+    public void putAll(Map<? extends K, ? extends V> m) {
+        tryPresize(m.size());
+        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
+            putVal(e.getKey(), e.getValue(), false);
+    }
+
+    /**
+     * Removes the key (and its corresponding value) from this map.
+     * This method does nothing if the key is not in the map.
+     *
+     * @param  key the key that needs to be removed
+     * @return the previous value associated with {@code key}, or
+     *         {@code null} if there was no mapping for {@code key}
+     * @throws NullPointerException if the specified key is null
+     */
+    public V remove(Object key) {
+        return replaceNode(key, null, null);
+    }
+
+    /**
+     * Implementation for the four public remove/replace methods:
+     * Replaces node value with v, conditional upon match of cv if
+     * non-null.  If resulting value is null, delete.
+     */
+    final V replaceNode(Object key, V value, Object cv) {
+        int hash = spread(key.hashCode());
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0 ||
+                (f = tabAt(tab, i = (n - 1) & hash)) == null)
+                break;
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                V oldVal = null;
+                boolean validated = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            validated = true;
+                            for (Node<K,V> e = f, pred = null;;) {
+                                K ek;
+                                if (e.hash == hash &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    V ev = e.val;
+                                    if (cv == null || cv == ev ||
+                                        (ev != null && cv.equals(ev))) {
+                                        oldVal = ev;
+                                        if (value != null)
+                                            e.val = value;
+                                        else if (pred != null)
+                                            pred.next = e.next;
+                                        else
+                                            setTabAt(tab, i, e.next);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null)
+                                    break;
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            validated = true;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(hash, key, null)) != null) {
+                                V pv = p.val;
+                                if (cv == null || cv == pv ||
+                                    (pv != null && cv.equals(pv))) {
+                                    oldVal = pv;
+                                    if (value != null)
+                                        p.val = value;
+                                    else if (t.removeTreeNode(p))
+                                        setTabAt(tab, i, untreeify(t.first));
+                                }
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (validated) {
+                    if (oldVal != null) {
+                        if (value == null)
+                            addCount(-1L, -1);
+                        return oldVal;
+                    }
+                    break;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     */
+    public void clear() {
+        long delta = 0L; // negative number of deletions
+        int i = 0;
+        Node<K,V>[] tab = table;
+        while (tab != null && i < tab.length) {
+            int fh;
+            Node<K,V> f = tabAt(tab, i);
+            if (f == null)
+                ++i;
+            else if ((fh = f.hash) == MOVED) {
+                tab = helpTransfer(tab, f);
+                i = 0; // restart
+            }
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        Node<K,V> p = (fh >= 0 ? f :
+                                       (f instanceof TreeBin) ?
+                                       ((TreeBin<K,V>)f).first : null);
+                        while (p != null) {
+                            --delta;
+                            p = p.next;
+                        }
+                        setTabAt(tab, i++, null);
+                    }
+                }
+            }
+        }
+        if (delta != 0L)
+            addCount(delta, -1);
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa. The set supports element
+     * removal, which removes the corresponding mapping from this map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
+     *
+     * <p> The set returned by this method is guaranteed to an instance of
+     * {@link KeySetView}.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+     *
+     * @return the set view
+     */
+    // Android-changed: Return type for backwards compat. Was KeySetView<K,V>. http://b/28099367
+    @dalvik.annotation.codegen.CovariantReturnType(returnType = KeySetView.class, presentAfter = 28)
+    public Set<K> keySet() {
+        KeySetView<K,V> ks;
+        return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from this map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll}, and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}
+     * and {@link Spliterator#NONNULL}.
+     *
+     * @return the collection view
+     */
+    public Collection<V> values() {
+        ValuesView<K,V> vs;
+        return (vs = values) != null ? vs : (values = new ValuesView<K,V>(this));
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
+     *
+     * @return the set view
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySetView<K,V> es;
+        return (es = entrySet) != null ? es : (entrySet = new EntrySetView<K,V>(this));
+    }
+
+    /**
+     * Returns the hash code value for this {@link Map}, i.e.,
+     * the sum of, for each key-value pair in the map,
+     * {@code key.hashCode() ^ value.hashCode()}.
+     *
+     * @return the hash code value for this map
+     */
+    public int hashCode() {
+        int h = 0;
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; )
+                h += p.key.hashCode() ^ p.val.hashCode();
+        }
+        return h;
+    }
+
+    /**
+     * Returns a string representation of this map.  The string
+     * representation consists of a list of key-value mappings (in no
+     * particular order) enclosed in braces ("{@code {}}").  Adjacent
+     * mappings are separated by the characters {@code ", "} (comma
+     * and space).  Each key-value mapping is rendered as the key
+     * followed by an equals sign ("{@code =}") followed by the
+     * associated value.
+     *
+     * @return a string representation of this map
+     */
+    public String toString() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+        StringBuilder sb = new StringBuilder();
+        sb.append('{');
+        Node<K,V> p;
+        if ((p = it.advance()) != null) {
+            for (;;) {
+                K k = p.key;
+                V v = p.val;
+                sb.append(k == this ? "(this Map)" : k);
+                sb.append('=');
+                sb.append(v == this ? "(this Map)" : v);
+                if ((p = it.advance()) == null)
+                    break;
+                sb.append(',').append(' ');
+            }
+        }
+        return sb.append('}').toString();
+    }
+
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is a map with the same
+     * mappings as this map.  This operation may return misleading
+     * results if either map is concurrently modified during execution
+     * of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o != this) {
+            if (!(o instanceof Map))
+                return false;
+            Map<?,?> m = (Map<?,?>) o;
+            Node<K,V>[] t;
+            int f = (t = table) == null ? 0 : t.length;
+            Traverser<K,V> it = new Traverser<K,V>(t, f, 0, f);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V val = p.val;
+                Object v = m.get(p.key);
+                if (v == null || (v != val && !v.equals(val)))
+                    return false;
+            }
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object mk, mv, v;
+                if ((mk = e.getKey()) == null ||
+                    (mv = e.getValue()) == null ||
+                    (v = get(mk)) == null ||
+                    (mv != v && !mv.equals(v)))
+                    return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Stripped-down version of helper class used in previous version,
+     * declared for the sake of serialization compatibility.
+     */
+    static class Segment<K,V> extends ReentrantLock implements Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        final float loadFactor;
+        Segment(float lf) { this.loadFactor = lf; }
+    }
+
+    /**
+     * Saves the state of the {@code ConcurrentHashMap} instance to a
+     * stream (i.e., serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData
+     * the serialized fields, followed by the key (Object) and value
+     * (Object) for each key-value mapping, followed by a null pair.
+     * The key-value mappings are emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // For serialization compatibility
+        // Emulate segment calculation from previous version of this class
+        int sshift = 0;
+        int ssize = 1;
+        while (ssize < DEFAULT_CONCURRENCY_LEVEL) {
+            ++sshift;
+            ssize <<= 1;
+        }
+        int segmentShift = 32 - sshift;
+        int segmentMask = ssize - 1;
+        @SuppressWarnings("unchecked")
+        Segment<K,V>[] segments = (Segment<K,V>[])
+            new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
+        for (int i = 0; i < segments.length; ++i)
+            segments[i] = new Segment<K,V>(LOAD_FACTOR);
+        java.io.ObjectOutputStream.PutField streamFields = s.putFields();
+        streamFields.put("segments", segments);
+        streamFields.put("segmentShift", segmentShift);
+        streamFields.put("segmentMask", segmentMask);
+        s.writeFields();
+
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                s.writeObject(p.key);
+                s.writeObject(p.val);
+            }
+        }
+        s.writeObject(null);
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        /*
+         * To improve performance in typical cases, we create nodes
+         * while reading, then place in table once size is known.
+         * However, we must also validate uniqueness and deal with
+         * overpopulated bins while doing so, which requires
+         * specialized versions of putVal mechanics.
+         */
+        sizeCtl = -1; // force exclusion for table construction
+        s.defaultReadObject();
+        long size = 0L;
+        Node<K,V> p = null;
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            K k = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+            V v = (V) s.readObject();
+            if (k != null && v != null) {
+                p = new Node<K,V>(spread(k.hashCode()), k, v, p);
+                ++size;
+            }
+            else
+                break;
+        }
+        if (size == 0L)
+            sizeCtl = 0;
+        else {
+            int n;
+            if (size >= (long)(MAXIMUM_CAPACITY >>> 1))
+                n = MAXIMUM_CAPACITY;
+            else {
+                int sz = (int)size;
+                n = tableSizeFor(sz + (sz >>> 1) + 1);
+            }
+            @SuppressWarnings("unchecked")
+            Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
+            int mask = n - 1;
+            long added = 0L;
+            while (p != null) {
+                boolean insertAtFront;
+                Node<K,V> next = p.next, first;
+                int h = p.hash, j = h & mask;
+                if ((first = tabAt(tab, j)) == null)
+                    insertAtFront = true;
+                else {
+                    K k = p.key;
+                    if (first.hash < 0) {
+                        TreeBin<K,V> t = (TreeBin<K,V>)first;
+                        if (t.putTreeVal(h, k, p.val) == null)
+                            ++added;
+                        insertAtFront = false;
+                    }
+                    else {
+                        int binCount = 0;
+                        insertAtFront = true;
+                        Node<K,V> q; K qk;
+                        for (q = first; q != null; q = q.next) {
+                            if (q.hash == h &&
+                                ((qk = q.key) == k ||
+                                 (qk != null && k.equals(qk)))) {
+                                insertAtFront = false;
+                                break;
+                            }
+                            ++binCount;
+                        }
+                        if (insertAtFront && binCount >= TREEIFY_THRESHOLD) {
+                            insertAtFront = false;
+                            ++added;
+                            p.next = first;
+                            TreeNode<K,V> hd = null, tl = null;
+                            for (q = p; q != null; q = q.next) {
+                                TreeNode<K,V> t = new TreeNode<K,V>
+                                    (q.hash, q.key, q.val, null, null);
+                                if ((t.prev = tl) == null)
+                                    hd = t;
+                                else
+                                    tl.next = t;
+                                tl = t;
+                            }
+                            setTabAt(tab, j, new TreeBin<K,V>(hd));
+                        }
+                    }
+                }
+                if (insertAtFront) {
+                    ++added;
+                    p.next = first;
+                    setTabAt(tab, j, p);
+                }
+                p = next;
+            }
+            table = tab;
+            sizeCtl = n - (n >>> 2);
+            baseCount = added;
+        }
+    }
+
+    // ConcurrentMap methods
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V putIfAbsent(K key, V value) {
+        return putVal(key, value, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean remove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && replaceNode(key, null, value) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public boolean replace(K key, V oldValue, V newValue) {
+        if (key == null || oldValue == null || newValue == null)
+            throw new NullPointerException();
+        return replaceNode(key, newValue, oldValue) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V replace(K key, V value) {
+        if (key == null || value == null)
+            throw new NullPointerException();
+        return replaceNode(key, value, null);
+    }
+
+    // Overrides of JDK8+ Map extension method defaults
+
+    /**
+     * Returns the value to which the specified key is mapped, or the
+     * given default value if this map contains no mapping for the
+     * key.
+     *
+     * @param key the key whose associated value is to be returned
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the default value
+     * @throws NullPointerException if the specified key is null
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = get(key)) == null ? defaultValue : v;
+    }
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                action.accept(p.key, p.val);
+            }
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                V oldValue = p.val;
+                for (K key = p.key;;) {
+                    V newValue = function.apply(key, oldValue);
+                    if (newValue == null)
+                        throw new NullPointerException();
+                    if (replaceNode(key, newValue, oldValue) != null ||
+                        (oldValue = get(key)) == null)
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method for EntrySetView.removeIf.
+     */
+    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        boolean removed = false;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = p.key;
+                V v = p.val;
+                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                if (function.test(e) && replaceNode(k, null, v) != null)
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Helper method for ValuesView.removeIf.
+     */
+    boolean removeValueIf(Predicate<? super V> function) {
+        if (function == null) throw new NullPointerException();
+        Node<K,V>[] t;
+        boolean removed = false;
+        if ((t = table) != null) {
+            Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+            for (Node<K,V> p; (p = it.advance()) != null; ) {
+                K k = p.key;
+                V v = p.val;
+                if (function.test(v) && replaceNode(k, null, v) != null)
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The entire
+     * method invocation is performed atomically, so the function is
+     * applied at most once per key.  Some attempted update operations
+     * on this map by other threads may be blocked while computation
+     * is in progress, so the computation should be short and simple,
+     * and must not attempt to update any other mappings of this map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key or mappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the mappingFunction does so,
+     *         in which case the mapping is left unestablished
+     */
+    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+        if (key == null || mappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                Node<K,V> r = new ReservationNode<K,V>();
+                synchronized (r) {
+                    if (casTabAt(tab, i, null, r)) {
+                        binCount = 1;
+                        Node<K,V> node = null;
+                        try {
+                            if ((val = mappingFunction.apply(key)) != null)
+                                node = new Node<K,V>(h, key, val, null);
+                        } finally {
+                            setTabAt(tab, i, node);
+                        }
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                boolean added = false;
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = e.val;
+                                    break;
+                                }
+                                Node<K,V> pred = e;
+                                if ((e = e.next) == null) {
+                                    if ((val = mappingFunction.apply(key)) != null) {
+                                        if (pred.next != null)
+                                            throw new IllegalStateException("Recursive update");
+                                        added = true;
+                                        pred.next = new Node<K,V>(h, key, val, null);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(h, key, null)) != null)
+                                val = p.val;
+                            else if ((val = mappingFunction.apply(key)) != null) {
+                                added = true;
+                                t.putTreeVal(h, key, val);
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    if (!added)
+                        return val;
+                    break;
+                }
+            }
+        }
+        if (val != null)
+            addCount(1L, binCount);
+        return val;
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value.  The entire method invocation is performed atomically.
+     * Some attempted update operations on this map by other threads
+     * may be blocked while computation is in progress, so the
+     * computation should be short and simple, and must not attempt to
+     * update any other mappings of this map.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null)
+                break;
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(key, e.val);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null)
+                                    break;
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null &&
+                                (p = r.findTreeNode(h, key, null)) != null) {
+                                val = remappingFunction.apply(key, p.val);
+                                if (val != null)
+                                    p.val = val;
+                                else {
+                                    delta = -1;
+                                    if (t.removeTreeNode(p))
+                                        setTabAt(tab, i, untreeify(t.first));
+                                }
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The entire method invocation is performed atomically.
+     * Some attempted update operations on this map by other threads
+     * may be blocked while computation is in progress, so the
+     * computation should be short and simple, and must not attempt to
+     * update any other mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or remappingFunction
+     *         is null
+     * @throws IllegalStateException if the computation detectably
+     *         attempts a recursive update to this map that would
+     *         otherwise never complete
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                Node<K,V> r = new ReservationNode<K,V>();
+                synchronized (r) {
+                    if (casTabAt(tab, i, null, r)) {
+                        binCount = 1;
+                        Node<K,V> node = null;
+                        try {
+                            if ((val = remappingFunction.apply(key, null)) != null) {
+                                delta = 1;
+                                node = new Node<K,V>(h, key, val, null);
+                            }
+                        } finally {
+                            setTabAt(tab, i, node);
+                        }
+                    }
+                }
+                if (binCount != 0)
+                    break;
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(key, e.val);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null) {
+                                    val = remappingFunction.apply(key, null);
+                                    if (val != null) {
+                                        if (pred.next != null)
+                                            throw new IllegalStateException("Recursive update");
+                                        delta = 1;
+                                        pred.next =
+                                            new Node<K,V>(h, key, val, null);
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 1;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r, p;
+                            if ((r = t.root) != null)
+                                p = r.findTreeNode(h, key, null);
+                            else
+                                p = null;
+                            V pv = (p == null) ? null : p.val;
+                            val = remappingFunction.apply(key, pv);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeVal(h, key, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                if (t.removeTreeNode(p))
+                                    setTabAt(tab, i, untreeify(t.first));
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    break;
+                }
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    /**
+     * If the specified key is not already associated with a
+     * (non-null) value, associates it with the given value.
+     * Otherwise, replaces the value with the results of the given
+     * remapping function, or removes if {@code null}. The entire
+     * method invocation is performed atomically.  Some attempted
+     * update operations on this map by other threads may be blocked
+     * while computation is in progress, so the computation should be
+     * short and simple, and must not attempt to update any other
+     * mappings of this Map.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or the
+     *         remappingFunction is null
+     * @throws RuntimeException or Error if the remappingFunction does so,
+     *         in which case the mapping is unchanged
+     */
+    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (key == null || value == null || remappingFunction == null)
+            throw new NullPointerException();
+        int h = spread(key.hashCode());
+        V val = null;
+        int delta = 0;
+        int binCount = 0;
+        for (Node<K,V>[] tab = table;;) {
+            Node<K,V> f; int n, i, fh;
+            if (tab == null || (n = tab.length) == 0)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (n - 1) & h)) == null) {
+                if (casTabAt(tab, i, null, new Node<K,V>(h, key, value, null))) {
+                    delta = 1;
+                    val = value;
+                    break;
+                }
+            }
+            else if ((fh = f.hash) == MOVED)
+                tab = helpTransfer(tab, f);
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        if (fh >= 0) {
+                            binCount = 1;
+                            for (Node<K,V> e = f, pred = null;; ++binCount) {
+                                K ek;
+                                if (e.hash == h &&
+                                    ((ek = e.key) == key ||
+                                     (ek != null && key.equals(ek)))) {
+                                    val = remappingFunction.apply(e.val, value);
+                                    if (val != null)
+                                        e.val = val;
+                                    else {
+                                        delta = -1;
+                                        Node<K,V> en = e.next;
+                                        if (pred != null)
+                                            pred.next = en;
+                                        else
+                                            setTabAt(tab, i, en);
+                                    }
+                                    break;
+                                }
+                                pred = e;
+                                if ((e = e.next) == null) {
+                                    delta = 1;
+                                    val = value;
+                                    pred.next =
+                                        new Node<K,V>(h, key, val, null);
+                                    break;
+                                }
+                            }
+                        }
+                        else if (f instanceof TreeBin) {
+                            binCount = 2;
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> r = t.root;
+                            TreeNode<K,V> p = (r == null) ? null :
+                                r.findTreeNode(h, key, null);
+                            val = (p == null) ? value :
+                                remappingFunction.apply(p.val, value);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    delta = 1;
+                                    t.putTreeVal(h, key, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                if (t.removeTreeNode(p))
+                                    setTabAt(tab, i, untreeify(t.first));
+                            }
+                        }
+                        else if (f instanceof ReservationNode)
+                            throw new IllegalStateException("Recursive update");
+                    }
+                }
+                if (binCount != 0) {
+                    if (binCount >= TREEIFY_THRESHOLD)
+                        treeifyBin(tab, i);
+                    break;
+                }
+            }
+        }
+        if (delta != 0)
+            addCount((long)delta, binCount);
+        return val;
+    }
+
+    // Hashtable legacy methods
+
+    /**
+     * Tests if some key maps into the specified value in this table.
+     *
+     * <p>Note that this method is identical in functionality to
+     * {@link #containsValue(Object)}, and exists solely to ensure
+     * full compatibility with class {@link java.util.Hashtable},
+     * which supported this method prior to introduction of the
+     * Java Collections Framework.
+     *
+     * @param  value a value to search for
+     * @return {@code true} if and only if some key maps to the
+     *         {@code value} argument in this table as
+     *         determined by the {@code equals} method;
+     *         {@code false} otherwise
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean contains(Object value) {
+        return containsValue(value);
+    }
+
+    /**
+     * Returns an enumeration of the keys in this table.
+     *
+     * @return an enumeration of the keys in this table
+     * @see #keySet()
+     */
+    public Enumeration<K> keys() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new KeyIterator<K,V>(t, f, 0, f, this);
+    }
+
+    /**
+     * Returns an enumeration of the values in this table.
+     *
+     * @return an enumeration of the values in this table
+     * @see #values()
+     */
+    public Enumeration<V> elements() {
+        Node<K,V>[] t;
+        int f = (t = table) == null ? 0 : t.length;
+        return new ValueIterator<K,V>(t, f, 0, f, this);
+    }
+
+    // ConcurrentHashMap-only methods
+
+    /**
+     * Returns the number of mappings. This method should be used
+     * instead of {@link #size} because a ConcurrentHashMap may
+     * contain more mappings than can be represented as an int. The
+     * value returned is an estimate; the actual count may differ if
+     * there are concurrent insertions or removals.
+     *
+     * @return the number of mappings
+     * @since 1.8
+     */
+    public long mappingCount() {
+        long n = sumCount();
+        return (n < 0L) ? 0L : n; // ignore transient negative values
+    }
+
+    /**
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
+     *
+     * @param <K> the element type of the returned set
+     * @return the new set
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet() {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(), Boolean.TRUE);
+    }
+
+    /**
+     * Creates a new {@link Set} backed by a ConcurrentHashMap
+     * from the given type to {@code Boolean.TRUE}.
+     *
+     * @param initialCapacity The implementation performs internal
+     * sizing to accommodate this many elements.
+     * @param <K> the element type of the returned set
+     * @return the new set
+     * @throws IllegalArgumentException if the initial capacity of
+     * elements is negative
+     * @since 1.8
+     */
+    public static <K> KeySetView<K,Boolean> newKeySet(int initialCapacity) {
+        return new KeySetView<K,Boolean>
+            (new ConcurrentHashMap<K,Boolean>(initialCapacity), Boolean.TRUE);
+    }
+
+    /**
+     * Returns a {@link Set} view of the keys in this map, using the
+     * given common mapped value for any additions (i.e., {@link
+     * Collection#add} and {@link Collection#addAll(Collection)}).
+     * This is of course only appropriate if it is acceptable to use
+     * the same value for all additions from this view.
+     *
+     * @param mappedValue the mapped value to use for any additions
+     * @return the set view
+     * @throws NullPointerException if the mappedValue is null
+     */
+    public KeySetView<K,V> keySet(V mappedValue) {
+        if (mappedValue == null)
+            throw new NullPointerException();
+        return new KeySetView<K,V>(this, mappedValue);
+    }
+
+    /* ---------------- Special Nodes -------------- */
+
+    /**
+     * A node inserted at head of bins during transfer operations.
+     */
+    static final class ForwardingNode<K,V> extends Node<K,V> {
+        final Node<K,V>[] nextTable;
+        ForwardingNode(Node<K,V>[] tab) {
+            super(MOVED, null, null, null);
+            this.nextTable = tab;
+        }
+
+        Node<K,V> find(int h, Object k) {
+            // loop to avoid arbitrarily deep recursion on forwarding nodes
+            outer: for (Node<K,V>[] tab = nextTable;;) {
+                Node<K,V> e; int n;
+                if (k == null || tab == null || (n = tab.length) == 0 ||
+                    (e = tabAt(tab, (n - 1) & h)) == null)
+                    return null;
+                for (;;) {
+                    int eh; K ek;
+                    if ((eh = e.hash) == h &&
+                        ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                        return e;
+                    if (eh < 0) {
+                        if (e instanceof ForwardingNode) {
+                            tab = ((ForwardingNode<K,V>)e).nextTable;
+                            continue outer;
+                        }
+                        else
+                            return e.find(h, k);
+                    }
+                    if ((e = e.next) == null)
+                        return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * A place-holder node used in computeIfAbsent and compute.
+     */
+    static final class ReservationNode<K,V> extends Node<K,V> {
+        ReservationNode() {
+            super(RESERVED, null, null, null);
+        }
+
+        Node<K,V> find(int h, Object k) {
+            return null;
+        }
+    }
+
+    /* ---------------- Table Initialization and Resizing -------------- */
+
+    /**
+     * Returns the stamp bits for resizing a table of size n.
+     * Must be negative when shifted left by RESIZE_STAMP_SHIFT.
+     */
+    static final int resizeStamp(int n) {
+        return Integer.numberOfLeadingZeros(n) | (1 << (RESIZE_STAMP_BITS - 1));
+    }
+
+    /**
+     * Initializes table, using the size recorded in sizeCtl.
+     */
+    private final Node<K,V>[] initTable() {
+        Node<K,V>[] tab; int sc;
+        while ((tab = table) == null || tab.length == 0) {
+            if ((sc = sizeCtl) < 0)
+                Thread.yield(); // lost initialization race; just spin
+            else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                try {
+                    if ((tab = table) == null || tab.length == 0) {
+                        int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
+                        @SuppressWarnings("unchecked")
+                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
+                        table = tab = nt;
+                        sc = n - (n >>> 2);
+                    }
+                } finally {
+                    sizeCtl = sc;
+                }
+                break;
+            }
+        }
+        return tab;
+    }
+
+    /**
+     * Adds to count, and if table is too small and not already
+     * resizing, initiates transfer. If already resizing, helps
+     * perform transfer if work is available.  Rechecks occupancy
+     * after a transfer to see if another resize is already needed
+     * because resizings are lagging additions.
+     *
+     * @param x the count to add
+     * @param check if <0, don't check resize, if <= 1 only check if uncontended
+     */
+    private final void addCount(long x, int check) {
+        CounterCell[] as; long b, s;
+        if ((as = counterCells) != null ||
+            !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
+            CounterCell a; long v; int m;
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
+                !(uncontended =
+                  U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
+                fullAddCount(x, uncontended);
+                return;
+            }
+            if (check <= 1)
+                return;
+            s = sumCount();
+        }
+        if (check >= 0) {
+            Node<K,V>[] tab, nt; int n, sc;
+            while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
+                   (n = tab.length) < MAXIMUM_CAPACITY) {
+                int rs = resizeStamp(n);
+                if (sc < 0) {
+                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+                        sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
+                        transferIndex <= 0)
+                        break;
+                    if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
+                        transfer(tab, nt);
+                }
+                else if (U.compareAndSwapInt(this, SIZECTL, sc,
+                                             (rs << RESIZE_STAMP_SHIFT) + 2))
+                    transfer(tab, null);
+                s = sumCount();
+            }
+        }
+    }
+
+    /**
+     * Helps transfer if a resize is in progress.
+     */
+    final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
+        Node<K,V>[] nextTab; int sc;
+        if (tab != null && (f instanceof ForwardingNode) &&
+            (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
+            int rs = resizeStamp(tab.length);
+            while (nextTab == nextTable && table == tab &&
+                   (sc = sizeCtl) < 0) {
+                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
+                    sc == rs + MAX_RESIZERS || transferIndex <= 0)
+                    break;
+                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
+                    transfer(tab, nextTab);
+                    break;
+                }
+            }
+            return nextTab;
+        }
+        return table;
+    }
+
+    /**
+     * Tries to presize table to accommodate the given number of elements.
+     *
+     * @param size number of elements (doesn't need to be perfectly accurate)
+     */
+    private final void tryPresize(int size) {
+        int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
+            tableSizeFor(size + (size >>> 1) + 1);
+        int sc;
+        while ((sc = sizeCtl) >= 0) {
+            Node<K,V>[] tab = table; int n;
+            if (tab == null || (n = tab.length) == 0) {
+                n = (sc > c) ? sc : c;
+                if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
+                    try {
+                        if (table == tab) {
+                            @SuppressWarnings("unchecked")
+                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
+                            table = nt;
+                            sc = n - (n >>> 2);
+                        }
+                    } finally {
+                        sizeCtl = sc;
+                    }
+                }
+            }
+            else if (c <= sc || n >= MAXIMUM_CAPACITY)
+                break;
+            else if (tab == table) {
+                int rs = resizeStamp(n);
+                if (U.compareAndSwapInt(this, SIZECTL, sc,
+                                        (rs << RESIZE_STAMP_SHIFT) + 2))
+                    transfer(tab, null);
+            }
+        }
+    }
+
+    /**
+     * Moves and/or copies the nodes in each bin to new table. See
+     * above for explanation.
+     */
+    private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
+        int n = tab.length, stride;
+        if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
+            stride = MIN_TRANSFER_STRIDE; // subdivide range
+        if (nextTab == null) {            // initiating
+            try {
+                @SuppressWarnings("unchecked")
+                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
+                nextTab = nt;
+            } catch (Throwable ex) {      // try to cope with OOME
+                sizeCtl = Integer.MAX_VALUE;
+                return;
+            }
+            nextTable = nextTab;
+            transferIndex = n;
+        }
+        int nextn = nextTab.length;
+        ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
+        boolean advance = true;
+        boolean finishing = false; // to ensure sweep before committing nextTab
+        for (int i = 0, bound = 0;;) {
+            Node<K,V> f; int fh;
+            while (advance) {
+                int nextIndex, nextBound;
+                if (--i >= bound || finishing)
+                    advance = false;
+                else if ((nextIndex = transferIndex) <= 0) {
+                    i = -1;
+                    advance = false;
+                }
+                else if (U.compareAndSwapInt
+                         (this, TRANSFERINDEX, nextIndex,
+                          nextBound = (nextIndex > stride ?
+                                       nextIndex - stride : 0))) {
+                    bound = nextBound;
+                    i = nextIndex - 1;
+                    advance = false;
+                }
+            }
+            if (i < 0 || i >= n || i + n >= nextn) {
+                int sc;
+                if (finishing) {
+                    nextTable = null;
+                    table = nextTab;
+                    sizeCtl = (n << 1) - (n >>> 1);
+                    return;
+                }
+                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
+                    if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
+                        return;
+                    finishing = advance = true;
+                    i = n; // recheck before commit
+                }
+            }
+            else if ((f = tabAt(tab, i)) == null)
+                advance = casTabAt(tab, i, null, fwd);
+            else if ((fh = f.hash) == MOVED)
+                advance = true; // already processed
+            else {
+                synchronized (f) {
+                    if (tabAt(tab, i) == f) {
+                        Node<K,V> ln, hn;
+                        if (fh >= 0) {
+                            int runBit = fh & n;
+                            Node<K,V> lastRun = f;
+                            for (Node<K,V> p = f.next; p != null; p = p.next) {
+                                int b = p.hash & n;
+                                if (b != runBit) {
+                                    runBit = b;
+                                    lastRun = p;
+                                }
+                            }
+                            if (runBit == 0) {
+                                ln = lastRun;
+                                hn = null;
+                            }
+                            else {
+                                hn = lastRun;
+                                ln = null;
+                            }
+                            for (Node<K,V> p = f; p != lastRun; p = p.next) {
+                                int ph = p.hash; K pk = p.key; V pv = p.val;
+                                if ((ph & n) == 0)
+                                    ln = new Node<K,V>(ph, pk, pv, ln);
+                                else
+                                    hn = new Node<K,V>(ph, pk, pv, hn);
+                            }
+                            setTabAt(nextTab, i, ln);
+                            setTabAt(nextTab, i + n, hn);
+                            setTabAt(tab, i, fwd);
+                            advance = true;
+                        }
+                        else if (f instanceof TreeBin) {
+                            TreeBin<K,V> t = (TreeBin<K,V>)f;
+                            TreeNode<K,V> lo = null, loTail = null;
+                            TreeNode<K,V> hi = null, hiTail = null;
+                            int lc = 0, hc = 0;
+                            for (Node<K,V> e = t.first; e != null; e = e.next) {
+                                int h = e.hash;
+                                TreeNode<K,V> p = new TreeNode<K,V>
+                                    (h, e.key, e.val, null, null);
+                                if ((h & n) == 0) {
+                                    if ((p.prev = loTail) == null)
+                                        lo = p;
+                                    else
+                                        loTail.next = p;
+                                    loTail = p;
+                                    ++lc;
+                                }
+                                else {
+                                    if ((p.prev = hiTail) == null)
+                                        hi = p;
+                                    else
+                                        hiTail.next = p;
+                                    hiTail = p;
+                                    ++hc;
+                                }
+                            }
+                            ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
+                                (hc != 0) ? new TreeBin<K,V>(lo) : t;
+                            hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
+                                (lc != 0) ? new TreeBin<K,V>(hi) : t;
+                            setTabAt(nextTab, i, ln);
+                            setTabAt(nextTab, i + n, hn);
+                            setTabAt(tab, i, fwd);
+                            advance = true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /* ---------------- Counter support -------------- */
+
+    /**
+     * A padded cell for distributing counts.  Adapted from LongAdder
+     * and Striped64.  See their internal docs for explanation.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    //@jdk.internal.vm.annotation.Contended
+    static final class CounterCell {
+        volatile long value;
+        CounterCell(long x) { value = x; }
+    }
+
+    final long sumCount() {
+        CounterCell[] as = counterCells; CounterCell a;
+        long sum = baseCount;
+        if (as != null) {
+            for (int i = 0; i < as.length; ++i) {
+                if ((a = as[i]) != null)
+                    sum += a.value;
+            }
+        }
+        return sum;
+    }
+
+    // See LongAdder version for explanation
+    private final void fullAddCount(long x, boolean wasUncontended) {
+        int h;
+        if ((h = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();      // force initialization
+            h = ThreadLocalRandom.getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        for (;;) {
+            CounterCell[] as; CounterCell a; int n; long v;
+            if ((as = counterCells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {            // Try to attach new Cell
+                        CounterCell r = new CounterCell(x); // Optimistic create
+                        if (cellsBusy == 0 &&
+                            U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                            boolean created = false;
+                            try {               // Recheck under lock
+                                CounterCell[] rs; int m, j;
+                                if ((rs = counterCells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    created = true;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            if (created)
+                                break;
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
+                    break;
+                else if (counterCells != as || n >= NCPU)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 &&
+                         U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                    try {
+                        if (counterCells == as) {// Expand table unless stale
+                            CounterCell[] rs = new CounterCell[n << 1];
+                            for (int i = 0; i < n; ++i)
+                                rs[i] = as[i];
+                            counterCells = rs;
+                        }
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = ThreadLocalRandom.advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && counterCells == as &&
+                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
+                boolean init = false;
+                try {                           // Initialize table
+                    if (counterCells == as) {
+                        CounterCell[] rs = new CounterCell[2];
+                        rs[h & 1] = new CounterCell(x);
+                        counterCells = rs;
+                        init = true;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+                if (init)
+                    break;
+            }
+            else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
+                break;                          // Fall back on using base
+        }
+    }
+
+    /* ---------------- Conversion from/to TreeBins -------------- */
+
+    /**
+     * Replaces all linked nodes in bin at given index unless table is
+     * too small, in which case resizes instead.
+     */
+    private final void treeifyBin(Node<K,V>[] tab, int index) {
+        Node<K,V> b; int n;
+        if (tab != null) {
+            if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
+                tryPresize(n << 1);
+            else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
+                synchronized (b) {
+                    if (tabAt(tab, index) == b) {
+                        TreeNode<K,V> hd = null, tl = null;
+                        for (Node<K,V> e = b; e != null; e = e.next) {
+                            TreeNode<K,V> p =
+                                new TreeNode<K,V>(e.hash, e.key, e.val,
+                                                  null, null);
+                            if ((p.prev = tl) == null)
+                                hd = p;
+                            else
+                                tl.next = p;
+                            tl = p;
+                        }
+                        setTabAt(tab, index, new TreeBin<K,V>(hd));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a list on non-TreeNodes replacing those in given list.
+     */
+    static <K,V> Node<K,V> untreeify(Node<K,V> b) {
+        Node<K,V> hd = null, tl = null;
+        for (Node<K,V> q = b; q != null; q = q.next) {
+            Node<K,V> p = new Node<K,V>(q.hash, q.key, q.val, null);
+            if (tl == null)
+                hd = p;
+            else
+                tl.next = p;
+            tl = p;
+        }
+        return hd;
+    }
+
+    /* ---------------- TreeNodes -------------- */
+
+    /**
+     * Nodes for use in TreeBins.
+     */
+    static final class TreeNode<K,V> extends Node<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+
+        TreeNode(int hash, K key, V val, Node<K,V> next,
+                 TreeNode<K,V> parent) {
+            super(hash, key, val, next);
+            this.parent = parent;
+        }
+
+        Node<K,V> find(int h, Object k) {
+            return findTreeNode(h, k, null);
+        }
+
+        /**
+         * Returns the TreeNode (or null if not found) for the given key
+         * starting at given root.
+         */
+        final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
+            if (k != null) {
+                TreeNode<K,V> p = this;
+                do {
+                    int ph, dir; K pk; TreeNode<K,V> q;
+                    TreeNode<K,V> pl = p.left, pr = p.right;
+                    if ((ph = p.hash) > h)
+                        p = pl;
+                    else if (ph < h)
+                        p = pr;
+                    else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                        return p;
+                    else if (pl == null)
+                        p = pr;
+                    else if (pr == null)
+                        p = pl;
+                    else if ((kc != null ||
+                              (kc = comparableClassFor(k)) != null) &&
+                             (dir = compareComparables(kc, k, pk)) != 0)
+                        p = (dir < 0) ? pl : pr;
+                    else if ((q = pr.findTreeNode(h, k, kc)) != null)
+                        return q;
+                    else
+                        p = pl;
+                } while (p != null);
+            }
+            return null;
+        }
+    }
+
+    /* ---------------- TreeBins -------------- */
+
+    /**
+     * TreeNodes used at the heads of bins. TreeBins do not hold user
+     * keys or values, but instead point to list of TreeNodes and
+     * their root. They also maintain a parasitic read-write lock
+     * forcing writers (who hold bin lock) to wait for readers (who do
+     * not) to complete before tree restructuring operations.
+     */
+    static final class TreeBin<K,V> extends Node<K,V> {
+        TreeNode<K,V> root;
+        volatile TreeNode<K,V> first;
+        volatile Thread waiter;
+        volatile int lockState;
+        // values for lockState
+        static final int WRITER = 1; // set while holding write lock
+        static final int WAITER = 2; // set when waiting for write lock
+        static final int READER = 4; // increment value for setting read lock
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Creates bin with initial set of nodes headed by b.
+         */
+        TreeBin(TreeNode<K,V> b) {
+            super(TREEBIN, null, null, null);
+            this.first = b;
+            TreeNode<K,V> r = null;
+            for (TreeNode<K,V> x = b, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (r == null) {
+                    x.parent = null;
+                    x.red = false;
+                    r = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = r;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            r = balanceInsertion(r, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            this.root = r;
+            assert checkInvariants(root);
+        }
+
+        /**
+         * Acquires write lock for tree restructuring.
+         */
+        private final void lockRoot() {
+            if (!U.compareAndSwapInt(this, LOCKSTATE, 0, WRITER))
+                contendedLock(); // offload to separate method
+        }
+
+        /**
+         * Releases write lock for tree restructuring.
+         */
+        private final void unlockRoot() {
+            lockState = 0;
+        }
+
+        /**
+         * Possibly blocks awaiting root lock.
+         */
+        private final void contendedLock() {
+            boolean waiting = false;
+            for (int s;;) {
+                if (((s = lockState) & ~WAITER) == 0) {
+                    if (U.compareAndSwapInt(this, LOCKSTATE, s, WRITER)) {
+                        if (waiting)
+                            waiter = null;
+                        return;
+                    }
+                }
+                else if ((s & WAITER) == 0) {
+                    if (U.compareAndSwapInt(this, LOCKSTATE, s, s | WAITER)) {
+                        waiting = true;
+                        waiter = Thread.currentThread();
+                    }
+                }
+                else if (waiting)
+                    LockSupport.park(this);
+            }
+        }
+
+        /**
+         * Returns matching node or null if none. Tries to search
+         * using tree comparisons from root, but continues linear
+         * search when lock not available.
+         */
+        final Node<K,V> find(int h, Object k) {
+            if (k != null) {
+                for (Node<K,V> e = first; e != null; ) {
+                    int s; K ek;
+                    if (((s = lockState) & (WAITER|WRITER)) != 0) {
+                        if (e.hash == h &&
+                            ((ek = e.key) == k || (ek != null && k.equals(ek))))
+                            return e;
+                        e = e.next;
+                    }
+                    else if (U.compareAndSwapInt(this, LOCKSTATE, s,
+                                                 s + READER)) {
+                        TreeNode<K,V> r, p;
+                        try {
+                            p = ((r = root) == null ? null :
+                                 r.findTreeNode(h, k, null));
+                        } finally {
+                            Thread w;
+                            if (U.getAndAddInt(this, LOCKSTATE, -READER) ==
+                                (READER|WAITER) && (w = waiter) != null)
+                                LockSupport.unpark(w);
+                        }
+                        return p;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Finds or adds a node.
+         * @return null if added
+         */
+        final TreeNode<K,V> putTreeVal(int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if (p == null) {
+                    first = root = new TreeNode<K,V>(h, k, v, null, null);
+                    break;
+                }
+                else if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.findTreeNode(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.findTreeNode(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    TreeNode<K,V> x, f = first;
+                    first = x = new TreeNode<K,V>(h, k, v, f, xp);
+                    if (f != null)
+                        f.prev = x;
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    if (!xp.red)
+                        x.red = true;
+                    else {
+                        lockRoot();
+                        try {
+                            root = balanceInsertion(root, x);
+                        } finally {
+                            unlockRoot();
+                        }
+                    }
+                    break;
+                }
+            }
+            assert checkInvariants(root);
+            return null;
+        }
+
+        /**
+         * Removes the given node, that must be present before this
+         * call.  This is messier than typical red-black deletion code
+         * because we cannot swap the contents of an interior node
+         * with a leaf successor that is pinned by "next" pointers
+         * that are accessible independently of lock. So instead we
+         * swap the tree linkages.
+         *
+         * @return true if now too small, so should be untreeified
+         */
+        final boolean removeTreeNode(TreeNode<K,V> p) {
+            TreeNode<K,V> next = (TreeNode<K,V>)p.next;
+            TreeNode<K,V> pred = p.prev;  // unlink traversal pointers
+            TreeNode<K,V> r, rl;
+            if (pred == null)
+                first = next;
+            else
+                pred.next = next;
+            if (next != null)
+                next.prev = pred;
+            if (first == null) {
+                root = null;
+                return true;
+            }
+            if ((r = root) == null || r.right == null || // too small
+                (rl = r.left) == null || rl.left == null)
+                return true;
+            lockRoot();
+            try {
+                TreeNode<K,V> replacement;
+                TreeNode<K,V> pl = p.left;
+                TreeNode<K,V> pr = p.right;
+                if (pl != null && pr != null) {
+                    TreeNode<K,V> s = pr, sl;
+                    while ((sl = s.left) != null) // find successor
+                        s = sl;
+                    boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                    TreeNode<K,V> sr = s.right;
+                    TreeNode<K,V> pp = p.parent;
+                    if (s == pr) { // p was s's direct parent
+                        p.parent = s;
+                        s.right = p;
+                    }
+                    else {
+                        TreeNode<K,V> sp = s.parent;
+                        if ((p.parent = sp) != null) {
+                            if (s == sp.left)
+                                sp.left = p;
+                            else
+                                sp.right = p;
+                        }
+                        if ((s.right = pr) != null)
+                            pr.parent = s;
+                    }
+                    p.left = null;
+                    if ((p.right = sr) != null)
+                        sr.parent = p;
+                    if ((s.left = pl) != null)
+                        pl.parent = s;
+                    if ((s.parent = pp) == null)
+                        r = s;
+                    else if (p == pp.left)
+                        pp.left = s;
+                    else
+                        pp.right = s;
+                    if (sr != null)
+                        replacement = sr;
+                    else
+                        replacement = p;
+                }
+                else if (pl != null)
+                    replacement = pl;
+                else if (pr != null)
+                    replacement = pr;
+                else
+                    replacement = p;
+                if (replacement != p) {
+                    TreeNode<K,V> pp = replacement.parent = p.parent;
+                    if (pp == null)
+                        r = replacement;
+                    else if (p == pp.left)
+                        pp.left = replacement;
+                    else
+                        pp.right = replacement;
+                    p.left = p.right = p.parent = null;
+                }
+
+                root = (p.red) ? r : balanceDeletion(r, replacement);
+
+                if (p == replacement) {  // detach pointers
+                    TreeNode<K,V> pp;
+                    if ((pp = p.parent) != null) {
+                        if (p == pp.left)
+                            pp.left = null;
+                        else if (p == pp.right)
+                            pp.right = null;
+                        p.parent = null;
+                    }
+                }
+            } finally {
+                unlockRoot();
+            }
+            assert checkInvariants(root);
+            return false;
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;) {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Checks invariants recursively for the tree of Nodes rooted at t.
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long LOCKSTATE;
+        static {
+            try {
+                LOCKSTATE = U.objectFieldOffset
+                    (TreeBin.class.getDeclaredField("lockState"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /* ----------------Table Traversal -------------- */
+
+    /**
+     * Records the table, its length, and current traversal index for a
+     * traverser that must process a region of a forwarded table before
+     * proceeding with current table.
+     */
+    static final class TableStack<K,V> {
+        int length;
+        int index;
+        Node<K,V>[] tab;
+        TableStack<K,V> next;
+    }
+
+    /**
+     * Encapsulates traversal for methods such as containsValue; also
+     * serves as a base class for other iterators and spliterators.
+     *
+     * Method advance visits once each still-valid node that was
+     * reachable upon iterator construction. It might miss some that
+     * were added to a bin after the bin was visited, which is OK wrt
+     * consistency guarantees. Maintaining this property in the face
+     * of possible ongoing resizes requires a fair amount of
+     * bookkeeping state that is difficult to optimize away amidst
+     * volatile accesses.  Even so, traversal maintains reasonable
+     * throughput.
+     *
+     * Normally, iteration proceeds bin-by-bin traversing lists.
+     * However, if the table has been resized, then all future steps
+     * must traverse both the bin at the current index as well as at
+     * (index + baseSize); and so on for further resizings. To
+     * paranoically cope with potential sharing by users of iterators
+     * across threads, iteration terminates if a bounds checks fails
+     * for a table read.
+     */
+    static class Traverser<K,V> {
+        Node<K,V>[] tab;        // current table; updated if resized
+        Node<K,V> next;         // the next entry to use
+        TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes
+        int index;              // index of bin to use next
+        int baseIndex;          // current index of initial table
+        int baseLimit;          // index bound for initial table
+        final int baseSize;     // initial table size
+
+        Traverser(Node<K,V>[] tab, int size, int index, int limit) {
+            this.tab = tab;
+            this.baseSize = size;
+            this.baseIndex = this.index = index;
+            this.baseLimit = limit;
+            this.next = null;
+        }
+
+        /**
+         * Advances if possible, returning next valid node, or null if none.
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n;  // must use locals in checks
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
+                    if (e instanceof ForwardingNode) {
+                        tab = ((ForwardingNode<K,V>)e).nextTable;
+                        e = null;
+                        pushState(t, i, n);
+                        continue;
+                    }
+                    else if (e instanceof TreeBin)
+                        e = ((TreeBin<K,V>)e).first;
+                    else
+                        e = null;
+                }
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex; // visit upper slots if present
+            }
+        }
+
+        /**
+         * Saves traversal state upon encountering a forwarding node.
+         */
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;  // reuse if possible
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        /**
+         * Possibly pops traversal state.
+         *
+         * @param n length of current table
+         */
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
+    }
+
+    /**
+     * Base of key, value, and entry Iterators. Adds fields to
+     * Traverser to support iterator.remove.
+     */
+    static class BaseIterator<K,V> extends Traverser<K,V> {
+        final ConcurrentHashMap<K,V> map;
+        Node<K,V> lastReturned;
+        BaseIterator(Node<K,V>[] tab, int size, int index, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            advance();
+        }
+
+        public final boolean hasNext() { return next != null; }
+        public final boolean hasMoreElements() { return next != null; }
+
+        public final void remove() {
+            Node<K,V> p;
+            if ((p = lastReturned) == null)
+                throw new IllegalStateException();
+            lastReturned = null;
+            map.replaceNode(p.key, null, null);
+        }
+    }
+
+    static final class KeyIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<K>, Enumeration<K> {
+        KeyIterator(Node<K,V>[] tab, int index, int size, int limit,
+                    ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final K next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = p.key;
+            lastReturned = p;
+            advance();
+            return k;
+        }
+
+        public final K nextElement() { return next(); }
+    }
+
+    static final class ValueIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<V>, Enumeration<V> {
+        ValueIterator(Node<K,V>[] tab, int index, int size, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final V next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return v;
+        }
+
+        public final V nextElement() { return next(); }
+    }
+
+    static final class EntryIterator<K,V> extends BaseIterator<K,V>
+        implements Iterator<Map.Entry<K,V>> {
+        EntryIterator(Node<K,V>[] tab, int index, int size, int limit,
+                      ConcurrentHashMap<K,V> map) {
+            super(tab, index, size, limit, map);
+        }
+
+        public final Map.Entry<K,V> next() {
+            Node<K,V> p;
+            if ((p = next) == null)
+                throw new NoSuchElementException();
+            K k = p.key;
+            V v = p.val;
+            lastReturned = p;
+            advance();
+            return new MapEntry<K,V>(k, v, map);
+        }
+    }
+
+    /**
+     * Exported Entry for EntryIterator.
+     */
+    static final class MapEntry<K,V> implements Map.Entry<K,V> {
+        final K key; // non-null
+        V val;       // non-null
+        final ConcurrentHashMap<K,V> map;
+        MapEntry(K key, V val, ConcurrentHashMap<K,V> map) {
+            this.key = key;
+            this.val = val;
+            this.map = map;
+        }
+        public K getKey()        { return key; }
+        public V getValue()      { return val; }
+        public int hashCode()    { return key.hashCode() ^ val.hashCode(); }
+        public String toString() {
+            return Helpers.mapEntryToString(key, val);
+        }
+
+        public boolean equals(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    (k == key || k.equals(key)) &&
+                    (v == val || v.equals(val)));
+        }
+
+        /**
+         * Sets our entry's value and writes through to the map. The
+         * value to return is somewhat arbitrary here. Since we do not
+         * necessarily track asynchronous changes, the most recent
+         * "previous" value could be different from what we return (or
+         * could even have been removed, in which case the put will
+         * re-establish). We do not and cannot guarantee more.
+         */
+        public V setValue(V value) {
+            if (value == null) throw new NullPointerException();
+            V v = val;
+            val = value;
+            map.put(key, value);
+            return v;
+        }
+    }
+
+    static final class KeySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<K> {
+        long est;               // size estimate
+        KeySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                       long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new KeySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                        f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.key);
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.key);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+    static final class ValueSpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<V> {
+        long est;               // size estimate
+        ValueSpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est) {
+            super(tab, size, index, limit);
+            this.est = est;
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new ValueSpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1);
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null;)
+                action.accept(p.val);
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(p.val);
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.NONNULL;
+        }
+    }
+
+    static final class EntrySpliterator<K,V> extends Traverser<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        final ConcurrentHashMap<K,V> map; // To export MapEntry
+        long est;               // size estimate
+        EntrySpliterator(Node<K,V>[] tab, int size, int index, int limit,
+                         long est, ConcurrentHashMap<K,V> map) {
+            super(tab, size, index, limit);
+            this.map = map;
+            this.est = est;
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            int i, f, h;
+            return (h = ((i = baseIndex) + (f = baseLimit)) >>> 1) <= i ? null :
+                new EntrySpliterator<K,V>(tab, baseSize, baseLimit = h,
+                                          f, est >>>= 1, map);
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            for (Node<K,V> p; (p = advance()) != null; )
+                action.accept(new MapEntry<K,V>(p.key, p.val, map));
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V> p;
+            if ((p = advance()) == null)
+                return false;
+            action.accept(new MapEntry<K,V>(p.key, p.val, map));
+            return true;
+        }
+
+        public long estimateSize() { return est; }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+    }
+
+    // Parallel bulk operations
+
+    /**
+     * Computes initial batch value for bulk tasks. The returned value
+     * is approximately exp2 of the number of times (minus one) to
+     * split task by two before executing leaf action. This value is
+     * faster to compute and more convenient to use as a guide to
+     * splitting than is the depth, since it is used while dividing by
+     * two anyway.
+     */
+    final int batchFor(long b) {
+        long n;
+        if (b == Long.MAX_VALUE || (n = sumCount()) <= 1L || n < b)
+            return 0;
+        int sp = ForkJoinPool.getCommonPoolParallelism() << 2; // slack of 4
+        return (b <= 0L || (n /= b) >= sp) ? sp : (int)n;
+    }
+
+    /**
+     * Performs the given action for each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEach(long parallelismThreshold,
+                        BiConsumer<? super K,? super V> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachMappingTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each (key, value).
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEach(long parallelismThreshold,
+                            BiFunction<? super K, ? super V, ? extends U> transformer,
+                            Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedMappingTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each (key, value), or null if none.  Upon
+     * success, further element processing is suppressed and the
+     * results of any other parallel invocations of the search
+     * function are ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each (key, value), or null if none
+     * @since 1.8
+     */
+    public <U> U search(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public <U> U reduce(long parallelismThreshold,
+                        BiFunction<? super K, ? super V, ? extends U> transformer,
+                        BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public double reduceToDouble(long parallelismThreshold,
+                                 ToDoubleBiFunction<? super K, ? super V> transformer,
+                                 double basis,
+                                 DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public long reduceToLong(long parallelismThreshold,
+                             ToLongBiFunction<? super K, ? super V> transformer,
+                             long basis,
+                             LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all (key, value) pairs using the given reducer to
+     * combine values, and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all (key, value) pairs
+     * @since 1.8
+     */
+    public int reduceToInt(long parallelismThreshold,
+                           ToIntBiFunction<? super K, ? super V> transformer,
+                           int basis,
+                           IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceMappingsToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachKey(long parallelismThreshold,
+                           Consumer<? super K> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachKeyTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each key.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachKey(long parallelismThreshold,
+                               Function<? super K, ? extends U> transformer,
+                               Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedKeyTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each key, or null if none. Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each key, or null if none
+     * @since 1.8
+     */
+    public <U> U searchKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all keys using the given
+     * reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all keys using the given
+     * reducer to combine values, or null if none
+     * @since 1.8
+     */
+    public K reduceKeys(long parallelismThreshold,
+                        BiFunction<? super K, ? super K, ? extends K> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceKeysTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public <U> U reduceKeys(long parallelismThreshold,
+                            Function<? super K, ? extends U> transformer,
+         BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public double reduceKeysToDouble(long parallelismThreshold,
+                                     ToDoubleFunction<? super K> transformer,
+                                     double basis,
+                                     DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public long reduceKeysToLong(long parallelismThreshold,
+                                 ToLongFunction<? super K> transformer,
+                                 long basis,
+                                 LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all keys using the given reducer to combine values, and
+     * the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all keys
+     * @since 1.8
+     */
+    public int reduceKeysToInt(long parallelismThreshold,
+                               ToIntFunction<? super K> transformer,
+                               int basis,
+                               IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceKeysToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachValue(long parallelismThreshold,
+                             Consumer<? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        new ForEachValueTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachValue(long parallelismThreshold,
+                                 Function<? super V, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedValueTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each value, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each value, or null if none
+     * @since 1.8
+     */
+    public <U> U searchValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all values using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all values
+     * @since 1.8
+     */
+    public V reduceValues(long parallelismThreshold,
+                          BiFunction<? super V, ? super V, ? extends V> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceValuesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values, or
+     * null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public <U> U reduceValues(long parallelismThreshold,
+                              Function<? super V, ? extends U> transformer,
+                              BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public double reduceValuesToDouble(long parallelismThreshold,
+                                       ToDoubleFunction<? super V> transformer,
+                                       double basis,
+                                       DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public long reduceValuesToLong(long parallelismThreshold,
+                                   ToLongFunction<? super V> transformer,
+                                   long basis,
+                                   LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all values using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all values
+     * @since 1.8
+     */
+    public int reduceValuesToInt(long parallelismThreshold,
+                                 ToIntFunction<? super V> transformer,
+                                 int basis,
+                                 IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceValuesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Performs the given action for each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param action the action
+     * @since 1.8
+     */
+    public void forEachEntry(long parallelismThreshold,
+                             Consumer<? super Map.Entry<K,V>> action) {
+        if (action == null) throw new NullPointerException();
+        new ForEachEntryTask<K,V>(null, batchFor(parallelismThreshold), 0, 0, table,
+                                  action).invoke();
+    }
+
+    /**
+     * Performs the given action for each non-null transformation
+     * of each entry.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case the action is not applied)
+     * @param action the action
+     * @param <U> the return type of the transformer
+     * @since 1.8
+     */
+    public <U> void forEachEntry(long parallelismThreshold,
+                                 Function<Map.Entry<K,V>, ? extends U> transformer,
+                                 Consumer<? super U> action) {
+        if (transformer == null || action == null)
+            throw new NullPointerException();
+        new ForEachTransformedEntryTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             transformer, action).invoke();
+    }
+
+    /**
+     * Returns a non-null result from applying the given search
+     * function on each entry, or null if none.  Upon success,
+     * further element processing is suppressed and the results of
+     * any other parallel invocations of the search function are
+     * ignored.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param searchFunction a function returning a non-null
+     * result on success, else null
+     * @param <U> the return type of the search function
+     * @return a non-null result from applying the given search
+     * function on each entry, or null if none
+     * @since 1.8
+     */
+    public <U> U searchEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> searchFunction) {
+        if (searchFunction == null) throw new NullPointerException();
+        return new SearchEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             searchFunction, new AtomicReference<U>()).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating all entries using the
+     * given reducer to combine values, or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating all entries
+     * @since 1.8
+     */
+    public Map.Entry<K,V> reduceEntries(long parallelismThreshold,
+                                        BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+        if (reducer == null) throw new NullPointerException();
+        return new ReduceEntriesTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * or null if none.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element, or null if there is no transformation (in
+     * which case it is not combined)
+     * @param reducer a commutative associative combining function
+     * @param <U> the return type of the transformer
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public <U> U reduceEntries(long parallelismThreshold,
+                               Function<Map.Entry<K,V>, ? extends U> transformer,
+                               BiFunction<? super U, ? super U, ? extends U> reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesTask<K,V,U>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public double reduceEntriesToDouble(long parallelismThreshold,
+                                        ToDoubleFunction<Map.Entry<K,V>> transformer,
+                                        double basis,
+                                        DoubleBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToDoubleTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public long reduceEntriesToLong(long parallelismThreshold,
+                                    ToLongFunction<Map.Entry<K,V>> transformer,
+                                    long basis,
+                                    LongBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToLongTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+    /**
+     * Returns the result of accumulating the given transformation
+     * of all entries using the given reducer to combine values,
+     * and the given basis as an identity value.
+     *
+     * @param parallelismThreshold the (estimated) number of elements
+     * needed for this operation to be executed in parallel
+     * @param transformer a function returning the transformation
+     * for an element
+     * @param basis the identity (initial default value) for the reduction
+     * @param reducer a commutative associative combining function
+     * @return the result of accumulating the given transformation
+     * of all entries
+     * @since 1.8
+     */
+    public int reduceEntriesToInt(long parallelismThreshold,
+                                  ToIntFunction<Map.Entry<K,V>> transformer,
+                                  int basis,
+                                  IntBinaryOperator reducer) {
+        if (transformer == null || reducer == null)
+            throw new NullPointerException();
+        return new MapReduceEntriesToIntTask<K,V>
+            (null, batchFor(parallelismThreshold), 0, 0, table,
+             null, transformer, basis, reducer).invoke();
+    }
+
+
+    /* ----------------Views -------------- */
+
+    /**
+     * Base class for views.
+     */
+    abstract static class CollectionView<K,V,E>
+        implements Collection<E>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        final ConcurrentHashMap<K,V> map;
+        CollectionView(ConcurrentHashMap<K,V> map)  { this.map = map; }
+
+        /**
+         * Returns the map backing this view.
+         *
+         * @return the map backing this view
+         */
+        public ConcurrentHashMap<K,V> getMap() { return map; }
+
+        /**
+         * Removes all of the elements from this view, by removing all
+         * the mappings from the map backing this view.
+         */
+        public final void clear()      { map.clear(); }
+        public final int size()        { return map.size(); }
+        public final boolean isEmpty() { return map.isEmpty(); }
+
+        // implementations below rely on concrete classes supplying these
+        // abstract methods
+        /**
+         * Returns an iterator over the elements in this collection.
+         *
+         * <p>The returned iterator is
+         * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+         *
+         * @return an iterator over the elements in this collection
+         */
+        public abstract Iterator<E> iterator();
+        public abstract boolean contains(Object o);
+        public abstract boolean remove(Object o);
+
+        private static final String OOME_MSG = "Required array size too large";
+
+        public final Object[] toArray() {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(OOME_MSG);
+            int n = (int)sz;
+            Object[] r = new Object[n];
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(OOME_MSG);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = e;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final <T> T[] toArray(T[] a) {
+            long sz = map.mappingCount();
+            if (sz > MAX_ARRAY_SIZE)
+                throw new OutOfMemoryError(OOME_MSG);
+            int m = (int)sz;
+            T[] r = (a.length >= m) ? a :
+                (T[])java.lang.reflect.Array
+                .newInstance(a.getClass().getComponentType(), m);
+            int n = r.length;
+            int i = 0;
+            for (E e : this) {
+                if (i == n) {
+                    if (n >= MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError(OOME_MSG);
+                    if (n >= MAX_ARRAY_SIZE - (MAX_ARRAY_SIZE >>> 1) - 1)
+                        n = MAX_ARRAY_SIZE;
+                    else
+                        n += (n >>> 1) + 1;
+                    r = Arrays.copyOf(r, n);
+                }
+                r[i++] = (T)e;
+            }
+            if (a == r && i < n) {
+                r[i] = null; // null-terminate
+                return r;
+            }
+            return (i == n) ? r : Arrays.copyOf(r, i);
+        }
+
+        /**
+         * Returns a string representation of this collection.
+         * The string representation consists of the string representations
+         * of the collection's elements in the order they are returned by
+         * its iterator, enclosed in square brackets ({@code "[]"}).
+         * Adjacent elements are separated by the characters {@code ", "}
+         * (comma and space).  Elements are converted to strings as by
+         * {@link String#valueOf(Object)}.
+         *
+         * @return a string representation of this collection
+         */
+        public final String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append('[');
+            Iterator<E> it = iterator();
+            if (it.hasNext()) {
+                for (;;) {
+                    Object e = it.next();
+                    sb.append(e == this ? "(this Collection)" : e);
+                    if (!it.hasNext())
+                        break;
+                    sb.append(',').append(' ');
+                }
+            }
+            return sb.append(']').toString();
+        }
+
+        public final boolean containsAll(Collection<?> c) {
+            if (c != this) {
+                for (Object e : c) {
+                    if (e == null || !contains(e))
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        public final boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+        public final boolean retainAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean modified = false;
+            for (Iterator<E> it = iterator(); it.hasNext();) {
+                if (!c.contains(it.next())) {
+                    it.remove();
+                    modified = true;
+                }
+            }
+            return modified;
+        }
+
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of keys, in
+     * which additions may optionally be enabled by mapping to a
+     * common value.  This class cannot be directly instantiated.
+     * See {@link #keySet(Object) keySet(V)},
+     * {@link #newKeySet() newKeySet()},
+     * {@link #newKeySet(int) newKeySet(int)}.
+     *
+     * @since 1.8
+     */
+    public static class KeySetView<K,V> extends CollectionView<K,V,K>
+        implements Set<K>, java.io.Serializable {
+        private static final long serialVersionUID = 7249069246763182397L;
+        private final V value;
+        KeySetView(ConcurrentHashMap<K,V> map, V value) {  // non-public
+            super(map);
+            this.value = value;
+        }
+
+        /**
+         * Returns the default mapped value for additions,
+         * or {@code null} if additions are not supported.
+         *
+         * @return the default mapped value for additions, or {@code null}
+         * if not supported
+         */
+        public V getMappedValue() { return value; }
+
+        /**
+         * {@inheritDoc}
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean contains(Object o) { return map.containsKey(o); }
+
+        /**
+         * Removes the key from this map view, by removing the key (and its
+         * corresponding value) from the backing map.  This method does
+         * nothing if the key is not in the map.
+         *
+         * @param  o the key to be removed from the backing map
+         * @return {@code true} if the backing map contained the specified key
+         * @throws NullPointerException if the specified key is null
+         */
+        public boolean remove(Object o) { return map.remove(o) != null; }
+
+        /**
+         * @return an iterator over the keys of the backing map
+         */
+        public Iterator<K> iterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeyIterator<K,V>(t, f, 0, f, m);
+        }
+
+        /**
+         * Adds the specified key to this set view by mapping the key to
+         * the default mapped value in the backing map, if defined.
+         *
+         * @param e key to be added
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the specified key is null
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean add(K e) {
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            return map.putVal(e, v, true) == null;
+        }
+
+        /**
+         * Adds all of the elements in the specified collection to this set,
+         * as if by calling {@link #add} on each one.
+         *
+         * @param c the elements to be inserted into this set
+         * @return {@code true} if this set changed as a result of the call
+         * @throws NullPointerException if the collection or any of its
+         * elements are {@code null}
+         * @throws UnsupportedOperationException if no default mapped value
+         * for additions was provided
+         */
+        public boolean addAll(Collection<? extends K> c) {
+            boolean added = false;
+            V v;
+            if ((v = value) == null)
+                throw new UnsupportedOperationException();
+            for (K e : c) {
+                if (map.putVal(e, v, true) == null)
+                    added = true;
+            }
+            return added;
+        }
+
+        public int hashCode() {
+            int h = 0;
+            for (K e : this)
+                h += e.hashCode();
+            return h;
+        }
+
+        public boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<K> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new KeySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.key);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Collection} of
+     * values, in which additions are disabled. This class cannot be
+     * directly instantiated. See {@link #values()}.
+     */
+    static final class ValuesView<K,V> extends CollectionView<K,V,V>
+        implements Collection<V>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        ValuesView(ConcurrentHashMap<K,V> map) { super(map); }
+        public final boolean contains(Object o) {
+            return map.containsValue(o);
+        }
+
+        public final boolean remove(Object o) {
+            if (o != null) {
+                for (Iterator<V> it = iterator(); it.hasNext();) {
+                    if (o.equals(it.next())) {
+                        it.remove();
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        public final Iterator<V> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public final boolean add(V e) {
+            throw new UnsupportedOperationException();
+        }
+        public final boolean addAll(Collection<? extends V> c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean removeIf(Predicate<? super V> filter) {
+            return map.removeValueIf(filter);
+        }
+
+        public Spliterator<V> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new ValueSpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n);
+        }
+
+        public void forEach(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(p.val);
+            }
+        }
+    }
+
+    /**
+     * A view of a ConcurrentHashMap as a {@link Set} of (key, value)
+     * entries.  This class cannot be directly instantiated. See
+     * {@link #entrySet()}.
+     */
+    static final class EntrySetView<K,V> extends CollectionView<K,V,Map.Entry<K,V>>
+        implements Set<Map.Entry<K,V>>, java.io.Serializable {
+        private static final long serialVersionUID = 2249069246763182397L;
+        EntrySetView(ConcurrentHashMap<K,V> map) { super(map); }
+
+        public boolean contains(Object o) {
+            Object k, v, r; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (r = map.get(k)) != null &&
+                    (v = e.getValue()) != null &&
+                    (v == r || v.equals(r)));
+        }
+
+        public boolean remove(Object o) {
+            Object k, v; Map.Entry<?,?> e;
+            return ((o instanceof Map.Entry) &&
+                    (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
+                    (v = e.getValue()) != null &&
+                    map.remove(k, v));
+        }
+
+        /**
+         * @return an iterator over the entries of the backing map
+         */
+        public Iterator<Map.Entry<K,V>> iterator() {
+            ConcurrentHashMap<K,V> m = map;
+            Node<K,V>[] t;
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntryIterator<K,V>(t, f, 0, f, m);
+        }
+
+        public boolean add(Entry<K,V> e) {
+            return map.putVal(e.getKey(), e.getValue(), false) == null;
+        }
+
+        public boolean addAll(Collection<? extends Entry<K,V>> c) {
+            boolean added = false;
+            for (Entry<K,V> e : c) {
+                if (add(e))
+                    added = true;
+            }
+            return added;
+        }
+
+        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
+            return map.removeEntryIf(filter);
+        }
+
+        public final int hashCode() {
+            int h = 0;
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; ) {
+                    h += p.hashCode();
+                }
+            }
+            return h;
+        }
+
+        public final boolean equals(Object o) {
+            Set<?> c;
+            return ((o instanceof Set) &&
+                    ((c = (Set<?>)o) == this ||
+                     (containsAll(c) && c.containsAll(this))));
+        }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            Node<K,V>[] t;
+            ConcurrentHashMap<K,V> m = map;
+            long n = m.sumCount();
+            int f = (t = m.table) == null ? 0 : t.length;
+            return new EntrySpliterator<K,V>(t, f, 0, f, n < 0L ? 0L : n, m);
+        }
+
+        public void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Node<K,V>[] t;
+            if ((t = map.table) != null) {
+                Traverser<K,V> it = new Traverser<K,V>(t, t.length, 0, t.length);
+                for (Node<K,V> p; (p = it.advance()) != null; )
+                    action.accept(new MapEntry<K,V>(p.key, p.val, map));
+            }
+        }
+
+    }
+
+    // -------------------------------------------------------
+
+    /**
+     * Base class for bulk tasks. Repeats some fields and code from
+     * class Traverser, because we need to subclass CountedCompleter.
+     */
+    @SuppressWarnings("serial")
+    abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
+        Node<K,V>[] tab;        // same as Traverser
+        Node<K,V> next;
+        TableStack<K,V> stack, spare;
+        int index;
+        int baseIndex;
+        int baseLimit;
+        final int baseSize;
+        int batch;              // split control
+
+        BulkTask(BulkTask<K,V,?> par, int b, int i, int f, Node<K,V>[] t) {
+            super(par);
+            this.batch = b;
+            this.index = this.baseIndex = i;
+            if ((this.tab = t) == null)
+                this.baseSize = this.baseLimit = 0;
+            else if (par == null)
+                this.baseSize = this.baseLimit = t.length;
+            else {
+                this.baseLimit = f;
+                this.baseSize = par.baseSize;
+            }
+        }
+
+        /**
+         * Same as Traverser version.
+         */
+        final Node<K,V> advance() {
+            Node<K,V> e;
+            if ((e = next) != null)
+                e = e.next;
+            for (;;) {
+                Node<K,V>[] t; int i, n;
+                if (e != null)
+                    return next = e;
+                if (baseIndex >= baseLimit || (t = tab) == null ||
+                    (n = t.length) <= (i = index) || i < 0)
+                    return next = null;
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
+                    if (e instanceof ForwardingNode) {
+                        tab = ((ForwardingNode<K,V>)e).nextTable;
+                        e = null;
+                        pushState(t, i, n);
+                        continue;
+                    }
+                    else if (e instanceof TreeBin)
+                        e = ((TreeBin<K,V>)e).first;
+                    else
+                        e = null;
+                }
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex;
+            }
+        }
+
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
+    }
+
+    /*
+     * Task classes. Coded in a regular but ugly format/style to
+     * simplify checks that each variant differs in the right way from
+     * others. The null screenings exist because compilers cannot tell
+     * that we've already null-checked task arguments, so we force
+     * simplest hoisted bypass to help avoid convoluted traps.
+     */
+    @SuppressWarnings("serial")
+    static final class ForEachKeyTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super K> action;
+        ForEachKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super K> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super K> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachKeyTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.key);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachValueTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super V> action;
+        ForEachValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachValueTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null;)
+                    action.accept(p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachEntryTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final Consumer<? super Entry<K,V>> action;
+        ForEachEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Consumer<? super Entry<K,V>> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final Consumer<? super Entry<K,V>> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachEntryTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachMappingTask<K,V>
+        extends BulkTask<K,V,Void> {
+        final BiConsumer<? super K, ? super V> action;
+        ForEachMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiConsumer<? super K,? super V> action) {
+            super(p, b, i, f, t);
+            this.action = action;
+        }
+        public final void compute() {
+            final BiConsumer<? super K, ? super V> action;
+            if ((action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachMappingTask<K,V>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    action.accept(p.key, p.val);
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedKeyTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super K, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedKeyTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedKeyTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedValueTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedValueTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedValueTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedEntryTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedEntryTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Map.Entry<K,V>, ? extends U> transformer, Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedEntryTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ForEachTransformedMappingTask<K,V,U>
+        extends BulkTask<K,V,Void> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final Consumer<? super U> action;
+        ForEachTransformedMappingTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             Consumer<? super U> action) {
+            super(p, b, i, f, t);
+            this.transformer = transformer; this.action = action;
+        }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final Consumer<? super U> action;
+            if ((transformer = this.transformer) != null &&
+                (action = this.action) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    new ForEachTransformedMappingTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         transformer, action).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key, p.val)) != null)
+                        action.accept(u);
+                }
+                propagateCompletion();
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super K, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super K, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchKeysTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.key)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchValuesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Entry<K,V>, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             Function<Entry<K,V>, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final Function<Entry<K,V>, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchEntriesTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        return;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class SearchMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+        final AtomicReference<U> result;
+        SearchMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             BiFunction<? super K, ? super V, ? extends U> searchFunction,
+             AtomicReference<U> result) {
+            super(p, b, i, f, t);
+            this.searchFunction = searchFunction; this.result = result;
+        }
+        public final U getRawResult() { return result.get(); }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> searchFunction;
+            final AtomicReference<U> result;
+            if ((searchFunction = this.searchFunction) != null &&
+                (result = this.result) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    if (result.get() != null)
+                        return;
+                    addToPendingCount(1);
+                    new SearchMappingsTask<K,V,U>
+                        (this, batch >>>= 1, baseLimit = h, f, tab,
+                         searchFunction, result).fork();
+                }
+                while (result.get() == null) {
+                    U u;
+                    Node<K,V> p;
+                    if ((p = advance()) == null) {
+                        propagateCompletion();
+                        break;
+                    }
+                    if ((u = searchFunction.apply(p.key, p.val)) != null) {
+                        if (result.compareAndSet(null, u))
+                            quietlyCompleteRoot();
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceKeysTask<K,V>
+        extends BulkTask<K,V,K> {
+        final BiFunction<? super K, ? super K, ? extends K> reducer;
+        K result;
+        ReduceKeysTask<K,V> rights, nextRight;
+        ReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceKeysTask<K,V> nextRight,
+             BiFunction<? super K, ? super K, ? extends K> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final K getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super K, ? extends K> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceKeysTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                K r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    K u = p.key;
+                    r = (r == null) ? u : u == null ? r : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceKeysTask<K,V>
+                        t = (ReduceKeysTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        K tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceValuesTask<K,V>
+        extends BulkTask<K,V,V> {
+        final BiFunction<? super V, ? super V, ? extends V> reducer;
+        V result;
+        ReduceValuesTask<K,V> rights, nextRight;
+        ReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceValuesTask<K,V> nextRight,
+             BiFunction<? super V, ? super V, ? extends V> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final V getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super V, ? super V, ? extends V> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceValuesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                V r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    V v = p.val;
+                    r = (r == null) ? v : reducer.apply(r, v);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceValuesTask<K,V>
+                        t = (ReduceValuesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        V tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class ReduceEntriesTask<K,V>
+        extends BulkTask<K,V,Map.Entry<K,V>> {
+        final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+        Map.Entry<K,V> result;
+        ReduceEntriesTask<K,V> rights, nextRight;
+        ReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             ReduceEntriesTask<K,V> nextRight,
+             BiFunction<Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.reducer = reducer;
+        }
+        public final Map.Entry<K,V> getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<Map.Entry<K,V>, Map.Entry<K,V>, ? extends Map.Entry<K,V>> reducer;
+            if ((reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new ReduceEntriesTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, reducer)).fork();
+                }
+                Map.Entry<K,V> r = null;
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = (r == null) ? p : reducer.apply(r, p);
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    ReduceEntriesTask<K,V>
+                        t = (ReduceEntriesTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        Map.Entry<K,V> tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super K, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceKeysTask<K,V,U> rights, nextRight;
+        MapReduceKeysTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysTask<K,V,U> nextRight,
+             Function<? super K, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super K, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysTask<K,V,U>
+                        t = (MapReduceKeysTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceValuesTask<K,V,U> rights, nextRight;
+        MapReduceValuesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesTask<K,V,U> nextRight,
+             Function<? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesTask<K,V,U>
+                        t = (MapReduceValuesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final Function<Map.Entry<K,V>, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceEntriesTask<K,V,U> rights, nextRight;
+        MapReduceEntriesTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesTask<K,V,U> nextRight,
+             Function<Map.Entry<K,V>, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final Function<Map.Entry<K,V>, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesTask<K,V,U>
+                        t = (MapReduceEntriesTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsTask<K,V,U>
+        extends BulkTask<K,V,U> {
+        final BiFunction<? super K, ? super V, ? extends U> transformer;
+        final BiFunction<? super U, ? super U, ? extends U> reducer;
+        U result;
+        MapReduceMappingsTask<K,V,U> rights, nextRight;
+        MapReduceMappingsTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsTask<K,V,U> nextRight,
+             BiFunction<? super K, ? super V, ? extends U> transformer,
+             BiFunction<? super U, ? super U, ? extends U> reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.reducer = reducer;
+        }
+        public final U getRawResult() { return result; }
+        public final void compute() {
+            final BiFunction<? super K, ? super V, ? extends U> transformer;
+            final BiFunction<? super U, ? super U, ? extends U> reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsTask<K,V,U>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, reducer)).fork();
+                }
+                U r = null;
+                for (Node<K,V> p; (p = advance()) != null; ) {
+                    U u;
+                    if ((u = transformer.apply(p.key, p.val)) != null)
+                        r = (r == null) ? u : reducer.apply(r, u);
+                }
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsTask<K,V,U>
+                        t = (MapReduceMappingsTask<K,V,U>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        U tr, sr;
+                        if ((sr = s.result) != null)
+                            t.result = (((tr = t.result) == null) ? sr :
+                                        reducer.apply(tr, sr));
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super K> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceKeysToDoubleTask<K,V> rights, nextRight;
+        MapReduceKeysToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super K> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super K> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToDoubleTask<K,V>
+                        t = (MapReduceKeysToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceValuesToDoubleTask<K,V> rights, nextRight;
+        MapReduceValuesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToDoubleTask<K,V>
+                        t = (MapReduceValuesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleFunction<Map.Entry<K,V>> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceEntriesToDoubleTask<K,V> rights, nextRight;
+        MapReduceEntriesToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToDoubleTask<K,V> nextRight,
+             ToDoubleFunction<Map.Entry<K,V>> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleFunction<Map.Entry<K,V>> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToDoubleTask<K,V>
+                        t = (MapReduceEntriesToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToDoubleTask<K,V>
+        extends BulkTask<K,V,Double> {
+        final ToDoubleBiFunction<? super K, ? super V> transformer;
+        final DoubleBinaryOperator reducer;
+        final double basis;
+        double result;
+        MapReduceMappingsToDoubleTask<K,V> rights, nextRight;
+        MapReduceMappingsToDoubleTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToDoubleTask<K,V> nextRight,
+             ToDoubleBiFunction<? super K, ? super V> transformer,
+             double basis,
+             DoubleBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Double getRawResult() { return result; }
+        public final void compute() {
+            final ToDoubleBiFunction<? super K, ? super V> transformer;
+            final DoubleBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                double r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToDoubleTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsDouble(r, transformer.applyAsDouble(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToDoubleTask<K,V>
+                        t = (MapReduceMappingsToDoubleTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsDouble(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super K> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceKeysToLongTask<K,V> rights, nextRight;
+        MapReduceKeysToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToLongTask<K,V> nextRight,
+             ToLongFunction<? super K> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super K> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToLongTask<K,V>
+                        t = (MapReduceKeysToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceValuesToLongTask<K,V> rights, nextRight;
+        MapReduceValuesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToLongTask<K,V> nextRight,
+             ToLongFunction<? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToLongTask<K,V>
+                        t = (MapReduceValuesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongFunction<Map.Entry<K,V>> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceEntriesToLongTask<K,V> rights, nextRight;
+        MapReduceEntriesToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToLongTask<K,V> nextRight,
+             ToLongFunction<Map.Entry<K,V>> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongFunction<Map.Entry<K,V>> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToLongTask<K,V>
+                        t = (MapReduceEntriesToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToLongTask<K,V>
+        extends BulkTask<K,V,Long> {
+        final ToLongBiFunction<? super K, ? super V> transformer;
+        final LongBinaryOperator reducer;
+        final long basis;
+        long result;
+        MapReduceMappingsToLongTask<K,V> rights, nextRight;
+        MapReduceMappingsToLongTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToLongTask<K,V> nextRight,
+             ToLongBiFunction<? super K, ? super V> transformer,
+             long basis,
+             LongBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Long getRawResult() { return result; }
+        public final void compute() {
+            final ToLongBiFunction<? super K, ? super V> transformer;
+            final LongBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                long r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToLongTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsLong(r, transformer.applyAsLong(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToLongTask<K,V>
+                        t = (MapReduceMappingsToLongTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsLong(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceKeysToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super K> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceKeysToIntTask<K,V> rights, nextRight;
+        MapReduceKeysToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceKeysToIntTask<K,V> nextRight,
+             ToIntFunction<? super K> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super K> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceKeysToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.key));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToIntTask<K,V>
+                        t = (MapReduceKeysToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceValuesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceValuesToIntTask<K,V> rights, nextRight;
+        MapReduceValuesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceValuesToIntTask<K,V> nextRight,
+             ToIntFunction<? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceValuesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToIntTask<K,V>
+                        t = (MapReduceValuesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceEntriesToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntFunction<Map.Entry<K,V>> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceEntriesToIntTask<K,V> rights, nextRight;
+        MapReduceEntriesToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceEntriesToIntTask<K,V> nextRight,
+             ToIntFunction<Map.Entry<K,V>> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntFunction<Map.Entry<K,V>> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceEntriesToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToIntTask<K,V>
+                        t = (MapReduceEntriesToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    static final class MapReduceMappingsToIntTask<K,V>
+        extends BulkTask<K,V,Integer> {
+        final ToIntBiFunction<? super K, ? super V> transformer;
+        final IntBinaryOperator reducer;
+        final int basis;
+        int result;
+        MapReduceMappingsToIntTask<K,V> rights, nextRight;
+        MapReduceMappingsToIntTask
+            (BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
+             MapReduceMappingsToIntTask<K,V> nextRight,
+             ToIntBiFunction<? super K, ? super V> transformer,
+             int basis,
+             IntBinaryOperator reducer) {
+            super(p, b, i, f, t); this.nextRight = nextRight;
+            this.transformer = transformer;
+            this.basis = basis; this.reducer = reducer;
+        }
+        public final Integer getRawResult() { return result; }
+        public final void compute() {
+            final ToIntBiFunction<? super K, ? super V> transformer;
+            final IntBinaryOperator reducer;
+            if ((transformer = this.transformer) != null &&
+                (reducer = this.reducer) != null) {
+                int r = this.basis;
+                for (int i = baseIndex, f, h; batch > 0 &&
+                         (h = ((f = baseLimit) + i) >>> 1) > i;) {
+                    addToPendingCount(1);
+                    (rights = new MapReduceMappingsToIntTask<K,V>
+                     (this, batch >>>= 1, baseLimit = h, f, tab,
+                      rights, transformer, r, reducer)).fork();
+                }
+                for (Node<K,V> p; (p = advance()) != null; )
+                    r = reducer.applyAsInt(r, transformer.applyAsInt(p.key, p.val));
+                result = r;
+                CountedCompleter<?> c;
+                for (c = firstComplete(); c != null; c = c.nextComplete()) {
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToIntTask<K,V>
+                        t = (MapReduceMappingsToIntTask<K,V>)c,
+                        s = t.rights;
+                    while (s != null) {
+                        t.result = reducer.applyAsInt(t.result, s.result);
+                        s = t.rights = s.nextRight;
+                    }
+                }
+            }
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long SIZECTL;
+    private static final long TRANSFERINDEX;
+    private static final long BASECOUNT;
+    private static final long CELLSBUSY;
+    private static final long CELLVALUE;
+    private static final int ABASE;
+    private static final int ASHIFT;
+
+    static {
+        try {
+            SIZECTL = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("sizeCtl"));
+            TRANSFERINDEX = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("transferIndex"));
+            BASECOUNT = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("baseCount"));
+            CELLSBUSY = U.objectFieldOffset
+                (ConcurrentHashMap.class.getDeclaredField("cellsBusy"));
+
+            CELLVALUE = U.objectFieldOffset
+                (CounterCell.class.getDeclaredField("value"));
+
+            ABASE = U.arrayBaseOffset(Node[].class);
+            int scale = U.arrayIndexScale(Node[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/ConcurrentLinkedDeque.java b/java/util/concurrent/ConcurrentLinkedDeque.java
new file mode 100644
index 0000000..3edde54
--- /dev/null
+++ b/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -0,0 +1,1628 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractCollection;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded concurrent {@linkplain Deque deque} based on linked nodes.
+ * Concurrent insertion, removal, and access operations execute safely
+ * across multiple threads.
+ * A {@code ConcurrentLinkedDeque} is an appropriate choice when
+ * many threads will share access to a common collection.
+ * Like most other concurrent collection implementations, this class
+ * does not permit the use of {@code null} elements.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these deques, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Deque} and {@link Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent collections,
+ * actions in a thread prior to placing an object into a
+ * {@code ConcurrentLinkedDeque}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code ConcurrentLinkedDeque} in another thread.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @author Martin Buchholz
+ * @param <E> the type of elements held in this deque
+ */
+public class ConcurrentLinkedDeque<E>
+    extends AbstractCollection<E>
+    implements Deque<E>, java.io.Serializable {
+
+    /*
+     * This is an implementation of a concurrent lock-free deque
+     * supporting interior removes but not interior insertions, as
+     * required to support the entire Deque interface.
+     *
+     * We extend the techniques developed for ConcurrentLinkedQueue and
+     * LinkedTransferQueue (see the internal docs for those classes).
+     * Understanding the ConcurrentLinkedQueue implementation is a
+     * prerequisite for understanding the implementation of this class.
+     *
+     * The data structure is a symmetrical doubly-linked "GC-robust"
+     * linked list of nodes.  We minimize the number of volatile writes
+     * using two techniques: advancing multiple hops with a single CAS
+     * and mixing volatile and non-volatile writes of the same memory
+     * locations.
+     *
+     * A node contains the expected E ("item") and links to predecessor
+     * ("prev") and successor ("next") nodes:
+     *
+     * class Node<E> { volatile Node<E> prev, next; volatile E item; }
+     *
+     * A node p is considered "live" if it contains a non-null item
+     * (p.item != null).  When an item is CASed to null, the item is
+     * atomically logically deleted from the collection.
+     *
+     * At any time, there is precisely one "first" node with a null
+     * prev reference that terminates any chain of prev references
+     * starting at a live node.  Similarly there is precisely one
+     * "last" node terminating any chain of next references starting at
+     * a live node.  The "first" and "last" nodes may or may not be live.
+     * The "first" and "last" nodes are always mutually reachable.
+     *
+     * A new element is added atomically by CASing the null prev or
+     * next reference in the first or last node to a fresh node
+     * containing the element.  The element's node atomically becomes
+     * "live" at that point.
+     *
+     * A node is considered "active" if it is a live node, or the
+     * first or last node.  Active nodes cannot be unlinked.
+     *
+     * A "self-link" is a next or prev reference that is the same node:
+     *   p.prev == p  or  p.next == p
+     * Self-links are used in the node unlinking process.  Active nodes
+     * never have self-links.
+     *
+     * A node p is active if and only if:
+     *
+     * p.item != null ||
+     * (p.prev == null && p.next != p) ||
+     * (p.next == null && p.prev != p)
+     *
+     * The deque object has two node references, "head" and "tail".
+     * The head and tail are only approximations to the first and last
+     * nodes of the deque.  The first node can always be found by
+     * following prev pointers from head; likewise for tail.  However,
+     * it is permissible for head and tail to be referring to deleted
+     * nodes that have been unlinked and so may not be reachable from
+     * any live node.
+     *
+     * There are 3 stages of node deletion;
+     * "logical deletion", "unlinking", and "gc-unlinking".
+     *
+     * 1. "logical deletion" by CASing item to null atomically removes
+     * the element from the collection, and makes the containing node
+     * eligible for unlinking.
+     *
+     * 2. "unlinking" makes a deleted node unreachable from active
+     * nodes, and thus eventually reclaimable by GC.  Unlinked nodes
+     * may remain reachable indefinitely from an iterator.
+     *
+     * Physical node unlinking is merely an optimization (albeit a
+     * critical one), and so can be performed at our convenience.  At
+     * any time, the set of live nodes maintained by prev and next
+     * links are identical, that is, the live nodes found via next
+     * links from the first node is equal to the elements found via
+     * prev links from the last node.  However, this is not true for
+     * nodes that have already been logically deleted - such nodes may
+     * be reachable in one direction only.
+     *
+     * 3. "gc-unlinking" takes unlinking further by making active
+     * nodes unreachable from deleted nodes, making it easier for the
+     * GC to reclaim future deleted nodes.  This step makes the data
+     * structure "gc-robust", as first described in detail by Boehm
+     * (http://portal.acm.org/citation.cfm?doid=503272.503282).
+     *
+     * GC-unlinked nodes may remain reachable indefinitely from an
+     * iterator, but unlike unlinked nodes, are never reachable from
+     * head or tail.
+     *
+     * Making the data structure GC-robust will eliminate the risk of
+     * unbounded memory retention with conservative GCs and is likely
+     * to improve performance with generational GCs.
+     *
+     * When a node is dequeued at either end, e.g. via poll(), we would
+     * like to break any references from the node to active nodes.  We
+     * develop further the use of self-links that was very effective in
+     * other concurrent collection classes.  The idea is to replace
+     * prev and next pointers with special values that are interpreted
+     * to mean off-the-list-at-one-end.  These are approximations, but
+     * good enough to preserve the properties we want in our
+     * traversals, e.g. we guarantee that a traversal will never visit
+     * the same element twice, but we don't guarantee whether a
+     * traversal that runs out of elements will be able to see more
+     * elements later after enqueues at that end.  Doing gc-unlinking
+     * safely is particularly tricky, since any node can be in use
+     * indefinitely (for example by an iterator).  We must ensure that
+     * the nodes pointed at by head/tail never get gc-unlinked, since
+     * head/tail are needed to get "back on track" by other nodes that
+     * are gc-unlinked.  gc-unlinking accounts for much of the
+     * implementation complexity.
+     *
+     * Since neither unlinking nor gc-unlinking are necessary for
+     * correctness, there are many implementation choices regarding
+     * frequency (eagerness) of these operations.  Since volatile
+     * reads are likely to be much cheaper than CASes, saving CASes by
+     * unlinking multiple adjacent nodes at a time may be a win.
+     * gc-unlinking can be performed rarely and still be effective,
+     * since it is most important that long chains of deleted nodes
+     * are occasionally broken.
+     *
+     * The actual representation we use is that p.next == p means to
+     * goto the first node (which in turn is reached by following prev
+     * pointers from head), and p.next == null && p.prev == p means
+     * that the iteration is at an end and that p is a (static final)
+     * dummy node, NEXT_TERMINATOR, and not the last active node.
+     * Finishing the iteration when encountering such a TERMINATOR is
+     * good enough for read-only traversals, so such traversals can use
+     * p.next == null as the termination condition.  When we need to
+     * find the last (active) node, for enqueueing a new node, we need
+     * to check whether we have reached a TERMINATOR node; if so,
+     * restart traversal from tail.
+     *
+     * The implementation is completely directionally symmetrical,
+     * except that most public methods that iterate through the list
+     * follow next pointers ("forward" direction).
+     *
+     * We believe (without full proof) that all single-element deque
+     * operations (e.g., addFirst, peekLast, pollLast) are linearizable
+     * (see Herlihy and Shavit's book).  However, some combinations of
+     * operations are known not to be linearizable.  In particular,
+     * when an addFirst(A) is racing with pollFirst() removing B, it is
+     * possible for an observer iterating over the elements to observe
+     * A B C and subsequently observe A C, even though no interior
+     * removes are ever performed.  Nevertheless, iterators behave
+     * reasonably, providing the "weakly consistent" guarantees.
+     *
+     * Empirically, microbenchmarks suggest that this class adds about
+     * 40% overhead relative to ConcurrentLinkedQueue, which feels as
+     * good as we can hope for.
+     */
+
+    private static final long serialVersionUID = 876323262645176354L;
+
+    /**
+     * A node from which the first node on list (that is, the unique node p
+     * with p.prev == null && p.next != p) can be reached in O(1) time.
+     * Invariants:
+     * - the first node is always O(1) reachable from head via prev links
+     * - all live nodes are reachable from the first node via succ()
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * - head is never gc-unlinked (but may be unlinked)
+     * Non-invariants:
+     * - head.item may or may not be null
+     * - head may not be reachable from the first or last node, or from tail
+     */
+    private transient volatile Node<E> head;
+
+    /**
+     * A node from which the last node on list (that is, the unique node p
+     * with p.next == null && p.prev != p) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always O(1) reachable from tail via next links
+     * - all live nodes are reachable from the last node via pred()
+     * - tail != null
+     * - tail is never gc-unlinked (but may be unlinked)
+     * Non-invariants:
+     * - tail.item may or may not be null
+     * - tail may not be reachable from the first or last node, or from head
+     */
+    private transient volatile Node<E> tail;
+
+    private static final Node<Object> PREV_TERMINATOR, NEXT_TERMINATOR;
+
+    @SuppressWarnings("unchecked")
+    Node<E> prevTerminator() {
+        return (Node<E>) PREV_TERMINATOR;
+    }
+
+    @SuppressWarnings("unchecked")
+    Node<E> nextTerminator() {
+        return (Node<E>) NEXT_TERMINATOR;
+    }
+
+    static final class Node<E> {
+        volatile Node<E> prev;
+        volatile E item;
+        volatile Node<E> next;
+
+        Node() {  // default constructor for NEXT_TERMINATOR, PREV_TERMINATOR
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext or casPrev.
+         */
+        Node(E item) {
+            U.putObject(this, ITEM, item);
+        }
+
+        boolean casItem(E cmp, E val) {
+            return U.compareAndSwapObject(this, ITEM, cmp, val);
+        }
+
+        void lazySetNext(Node<E> val) {
+            U.putOrderedObject(this, NEXT, val);
+        }
+
+        boolean casNext(Node<E> cmp, Node<E> val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        void lazySetPrev(Node<E> val) {
+            U.putOrderedObject(this, PREV, val);
+        }
+
+        boolean casPrev(Node<E> cmp, Node<E> val) {
+            return U.compareAndSwapObject(this, PREV, cmp, val);
+        }
+
+        // Unsafe mechanics
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long PREV;
+        private static final long ITEM;
+        private static final long NEXT;
+
+        static {
+            try {
+                PREV = U.objectFieldOffset
+                    (Node.class.getDeclaredField("prev"));
+                ITEM = U.objectFieldOffset
+                    (Node.class.getDeclaredField("item"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * Links e as first element.
+     */
+    private void linkFirst(E e) {
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+
+        restartFromHead:
+        for (;;)
+            for (Node<E> h = head, p = h, q;;) {
+                if ((q = p.prev) != null &&
+                    (q = (p = q).prev) != null)
+                    // Check for head updates every other hop.
+                    // If p == q, we are sure to follow head instead.
+                    p = (h != (h = head)) ? h : q;
+                else if (p.next == p) // PREV_TERMINATOR
+                    continue restartFromHead;
+                else {
+                    // p is first node
+                    newNode.lazySetNext(p); // CAS piggyback
+                    if (p.casPrev(null, newNode)) {
+                        // Successful CAS is the linearization point
+                        // for e to become an element of this deque,
+                        // and for newNode to become "live".
+                        if (p != h) // hop two nodes at a time
+                            casHead(h, newNode);  // Failure is OK.
+                        return;
+                    }
+                    // Lost CAS race to another thread; re-read prev
+                }
+            }
+    }
+
+    /**
+     * Links e as last element.
+     */
+    private void linkLast(E e) {
+        final Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p.prev == p) // NEXT_TERMINATOR
+                    continue restartFromTail;
+                else {
+                    // p is last node
+                    newNode.lazySetPrev(p); // CAS piggyback
+                    if (p.casNext(null, newNode)) {
+                        // Successful CAS is the linearization point
+                        // for e to become an element of this deque,
+                        // and for newNode to become "live".
+                        if (p != t) // hop two nodes at a time
+                            casTail(t, newNode);  // Failure is OK.
+                        return;
+                    }
+                    // Lost CAS race to another thread; re-read next
+                }
+            }
+    }
+
+    private static final int HOPS = 2;
+
+    /**
+     * Unlinks non-null node x.
+     */
+    void unlink(Node<E> x) {
+        // assert x != null;
+        // assert x.item == null;
+        // assert x != PREV_TERMINATOR;
+        // assert x != NEXT_TERMINATOR;
+
+        final Node<E> prev = x.prev;
+        final Node<E> next = x.next;
+        if (prev == null) {
+            unlinkFirst(x, next);
+        } else if (next == null) {
+            unlinkLast(x, prev);
+        } else {
+            // Unlink interior node.
+            //
+            // This is the common case, since a series of polls at the
+            // same end will be "interior" removes, except perhaps for
+            // the first one, since end nodes cannot be unlinked.
+            //
+            // At any time, all active nodes are mutually reachable by
+            // following a sequence of either next or prev pointers.
+            //
+            // Our strategy is to find the unique active predecessor
+            // and successor of x.  Try to fix up their links so that
+            // they point to each other, leaving x unreachable from
+            // active nodes.  If successful, and if x has no live
+            // predecessor/successor, we additionally try to gc-unlink,
+            // leaving active nodes unreachable from x, by rechecking
+            // that the status of predecessor and successor are
+            // unchanged and ensuring that x is not reachable from
+            // tail/head, before setting x's prev/next links to their
+            // logical approximate replacements, self/TERMINATOR.
+            Node<E> activePred, activeSucc;
+            boolean isFirst, isLast;
+            int hops = 1;
+
+            // Find active predecessor
+            for (Node<E> p = prev; ; ++hops) {
+                if (p.item != null) {
+                    activePred = p;
+                    isFirst = false;
+                    break;
+                }
+                Node<E> q = p.prev;
+                if (q == null) {
+                    if (p.next == p)
+                        return;
+                    activePred = p;
+                    isFirst = true;
+                    break;
+                }
+                else if (p == q)
+                    return;
+                else
+                    p = q;
+            }
+
+            // Find active successor
+            for (Node<E> p = next; ; ++hops) {
+                if (p.item != null) {
+                    activeSucc = p;
+                    isLast = false;
+                    break;
+                }
+                Node<E> q = p.next;
+                if (q == null) {
+                    if (p.prev == p)
+                        return;
+                    activeSucc = p;
+                    isLast = true;
+                    break;
+                }
+                else if (p == q)
+                    return;
+                else
+                    p = q;
+            }
+
+            // TODO: better HOP heuristics
+            if (hops < HOPS
+                // always squeeze out interior deleted nodes
+                && (isFirst | isLast))
+                return;
+
+            // Squeeze out deleted nodes between activePred and
+            // activeSucc, including x.
+            skipDeletedSuccessors(activePred);
+            skipDeletedPredecessors(activeSucc);
+
+            // Try to gc-unlink, if possible
+            if ((isFirst | isLast) &&
+
+                // Recheck expected state of predecessor and successor
+                (activePred.next == activeSucc) &&
+                (activeSucc.prev == activePred) &&
+                (isFirst ? activePred.prev == null : activePred.item != null) &&
+                (isLast  ? activeSucc.next == null : activeSucc.item != null)) {
+
+                updateHead(); // Ensure x is not reachable from head
+                updateTail(); // Ensure x is not reachable from tail
+
+                // Finally, actually gc-unlink
+                x.lazySetPrev(isFirst ? prevTerminator() : x);
+                x.lazySetNext(isLast  ? nextTerminator() : x);
+            }
+        }
+    }
+
+    /**
+     * Unlinks non-null first node.
+     */
+    private void unlinkFirst(Node<E> first, Node<E> next) {
+        // assert first != null;
+        // assert next != null;
+        // assert first.item == null;
+        for (Node<E> o = null, p = next, q;;) {
+            if (p.item != null || (q = p.next) == null) {
+                if (o != null && p.prev != p && first.casNext(next, p)) {
+                    skipDeletedPredecessors(p);
+                    if (first.prev == null &&
+                        (p.next == null || p.item != null) &&
+                        p.prev == first) {
+
+                        updateHead(); // Ensure o is not reachable from head
+                        updateTail(); // Ensure o is not reachable from tail
+
+                        // Finally, actually gc-unlink
+                        o.lazySetNext(o);
+                        o.lazySetPrev(prevTerminator());
+                    }
+                }
+                return;
+            }
+            else if (p == q)
+                return;
+            else {
+                o = p;
+                p = q;
+            }
+        }
+    }
+
+    /**
+     * Unlinks non-null last node.
+     */
+    private void unlinkLast(Node<E> last, Node<E> prev) {
+        // assert last != null;
+        // assert prev != null;
+        // assert last.item == null;
+        for (Node<E> o = null, p = prev, q;;) {
+            if (p.item != null || (q = p.prev) == null) {
+                if (o != null && p.next != p && last.casPrev(prev, p)) {
+                    skipDeletedSuccessors(p);
+                    if (last.next == null &&
+                        (p.prev == null || p.item != null) &&
+                        p.next == last) {
+
+                        updateHead(); // Ensure o is not reachable from head
+                        updateTail(); // Ensure o is not reachable from tail
+
+                        // Finally, actually gc-unlink
+                        o.lazySetPrev(o);
+                        o.lazySetNext(nextTerminator());
+                    }
+                }
+                return;
+            }
+            else if (p == q)
+                return;
+            else {
+                o = p;
+                p = q;
+            }
+        }
+    }
+
+    /**
+     * Guarantees that any node which was unlinked before a call to
+     * this method will be unreachable from head after it returns.
+     * Does not guarantee to eliminate slack, only that head will
+     * point to a node that was active while this method was running.
+     */
+    private final void updateHead() {
+        // Either head already points to an active node, or we keep
+        // trying to cas it to the first node until it does.
+        Node<E> h, p, q;
+        restartFromHead:
+        while ((h = head).item == null && (p = h.prev) != null) {
+            for (;;) {
+                if ((q = p.prev) == null ||
+                    (q = (p = q).prev) == null) {
+                    // It is possible that p is PREV_TERMINATOR,
+                    // but if so, the CAS is guaranteed to fail.
+                    if (casHead(h, p))
+                        return;
+                    else
+                        continue restartFromHead;
+                }
+                else if (h != head)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Guarantees that any node which was unlinked before a call to
+     * this method will be unreachable from tail after it returns.
+     * Does not guarantee to eliminate slack, only that tail will
+     * point to a node that was active while this method was running.
+     */
+    private final void updateTail() {
+        // Either tail already points to an active node, or we keep
+        // trying to cas it to the last node until it does.
+        Node<E> t, p, q;
+        restartFromTail:
+        while ((t = tail).item == null && (p = t.next) != null) {
+            for (;;) {
+                if ((q = p.next) == null ||
+                    (q = (p = q).next) == null) {
+                    // It is possible that p is NEXT_TERMINATOR,
+                    // but if so, the CAS is guaranteed to fail.
+                    if (casTail(t, p))
+                        return;
+                    else
+                        continue restartFromTail;
+                }
+                else if (t != tail)
+                    continue restartFromTail;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    private void skipDeletedPredecessors(Node<E> x) {
+        whileActive:
+        do {
+            Node<E> prev = x.prev;
+            // assert prev != null;
+            // assert x != NEXT_TERMINATOR;
+            // assert x != PREV_TERMINATOR;
+            Node<E> p = prev;
+            findActive:
+            for (;;) {
+                if (p.item != null)
+                    break findActive;
+                Node<E> q = p.prev;
+                if (q == null) {
+                    if (p.next == p)
+                        continue whileActive;
+                    break findActive;
+                }
+                else if (p == q)
+                    continue whileActive;
+                else
+                    p = q;
+            }
+
+            // found active CAS target
+            if (prev == p || x.casPrev(prev, p))
+                return;
+
+        } while (x.item != null || x.next == null);
+    }
+
+    private void skipDeletedSuccessors(Node<E> x) {
+        whileActive:
+        do {
+            Node<E> next = x.next;
+            // assert next != null;
+            // assert x != NEXT_TERMINATOR;
+            // assert x != PREV_TERMINATOR;
+            Node<E> p = next;
+            findActive:
+            for (;;) {
+                if (p.item != null)
+                    break findActive;
+                Node<E> q = p.next;
+                if (q == null) {
+                    if (p.prev == p)
+                        continue whileActive;
+                    break findActive;
+                }
+                else if (p == q)
+                    continue whileActive;
+                else
+                    p = q;
+            }
+
+            // found active CAS target
+            if (next == p || x.casNext(next, p))
+                return;
+
+        } while (x.item != null || x.prev == null);
+    }
+
+    /**
+     * Returns the successor of p, or the first node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> succ(Node<E> p) {
+        // TODO: should we skip deleted nodes here?
+        Node<E> q = p.next;
+        return (p == q) ? first() : q;
+    }
+
+    /**
+     * Returns the predecessor of p, or the last node if p.prev has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> pred(Node<E> p) {
+        Node<E> q = p.prev;
+        return (p == q) ? last() : q;
+    }
+
+    /**
+     * Returns the first node, the unique node p for which:
+     *     p.prev == null && p.next != p
+     * The returned node may or may not be logically deleted.
+     * Guarantees that head is set to the returned node.
+     */
+    Node<E> first() {
+        restartFromHead:
+        for (;;)
+            for (Node<E> h = head, p = h, q;;) {
+                if ((q = p.prev) != null &&
+                    (q = (p = q).prev) != null)
+                    // Check for head updates every other hop.
+                    // If p == q, we are sure to follow head instead.
+                    p = (h != (h = head)) ? h : q;
+                else if (p == h
+                         // It is possible that p is PREV_TERMINATOR,
+                         // but if so, the CAS is guaranteed to fail.
+                         || casHead(h, p))
+                    return p;
+                else
+                    continue restartFromHead;
+            }
+    }
+
+    /**
+     * Returns the last node, the unique node p for which:
+     *     p.next == null && p.prev != p
+     * The returned node may or may not be logically deleted.
+     * Guarantees that tail is set to the returned node.
+     */
+    Node<E> last() {
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p == t
+                         // It is possible that p is NEXT_TERMINATOR,
+                         // but if so, the CAS is guaranteed to fail.
+                         || casTail(t, p))
+                    return p;
+                else
+                    continue restartFromTail;
+            }
+    }
+
+    // Minor convenience utilities
+
+    /**
+     * Returns element unless it is null, in which case throws
+     * NoSuchElementException.
+     *
+     * @param v the element
+     * @return the element
+     */
+    private E screenNullResult(E v) {
+        if (v == null)
+            throw new NoSuchElementException();
+        return v;
+    }
+
+    /**
+     * Constructs an empty deque.
+     */
+    public ConcurrentLinkedDeque() {
+        head = tail = new Node<E>(null);
+    }
+
+    /**
+     * Constructs a deque initially containing the elements of
+     * the given collection, added in traversal order of the
+     * collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentLinkedDeque(Collection<? extends E> c) {
+        // Copy c into a private chain of Nodes
+        Node<E> h = null, t = null;
+        for (E e : c) {
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else {
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
+                t = newNode;
+            }
+        }
+        initHeadTail(h, t);
+    }
+
+    /**
+     * Initializes head and tail, ensuring invariants hold.
+     */
+    private void initHeadTail(Node<E> h, Node<E> t) {
+        if (h == t) {
+            if (h == null)
+                h = t = new Node<E>(null);
+            else {
+                // Avoid edge case of a single Node with non-null item.
+                Node<E> newNode = new Node<E>(null);
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
+                t = newNode;
+            }
+        }
+        head = h;
+        tail = t;
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException}.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addFirst(E e) {
+        linkFirst(e);
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void addLast(E e) {
+        linkLast(e);
+    }
+
+    /**
+     * Inserts the specified element at the front of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Deque#offerFirst})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerFirst(E e) {
+        linkFirst(e);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the end of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * <p>This method is equivalent to {@link #add}.
+     *
+     * @return {@code true} (as specified by {@link Deque#offerLast})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offerLast(E e) {
+        linkLast(e);
+        return true;
+    }
+
+    public E peekFirst() {
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null)
+                return item;
+        }
+        return null;
+    }
+
+    public E peekLast() {
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null)
+                return item;
+        }
+        return null;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        return screenNullResult(peekFirst());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        return screenNullResult(peekLast());
+    }
+
+    public E pollFirst() {
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null && p.casItem(item, null)) {
+                unlink(p);
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public E pollLast() {
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null && p.casItem(item, null)) {
+                unlink(p);
+                return item;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        return screenNullResult(pollFirst());
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        return screenNullResult(pollLast());
+    }
+
+    // *** Queue and stack methods ***
+
+    /**
+     * Inserts the specified element at the tail of this deque.
+     * As the deque is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this deque.
+     * As the deque is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offerLast(e);
+    }
+
+    public E poll()           { return pollFirst(); }
+    public E peek()           { return peekFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E remove()         { return removeFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop()            { return removeFirst(); }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E element()        { return getFirst(); }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void push(E e)     { addFirst(e); }
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean removeFirstOccurrence(Object o) {
+        Objects.requireNonNull(o);
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null && o.equals(item) && p.casItem(item, null)) {
+                unlink(p);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes the last occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the last element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean removeLastOccurrence(Object o) {
+        Objects.requireNonNull(o);
+        for (Node<E> p = last(); p != null; p = pred(p)) {
+            E item = p.item;
+            if (item != null && o.equals(item) && p.casItem(item, null)) {
+                unlink(p);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o element whose presence in this deque is to be tested
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node<E> p = first(); p != null; p = succ(p)) {
+                E item = p.item;
+                if (item != null && o.equals(item))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if this collection contains no elements.
+     *
+     * @return {@code true} if this collection contains no elements
+     */
+    public boolean isEmpty() {
+        return peekFirst() == null;
+    }
+
+    /**
+     * Returns the number of elements in this deque.  If this deque
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these deques, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node<E> p = first(); p != null;) {
+                if (p.item != null)
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to {@link #removeFirstOccurrence(Object)}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if the deque contained the specified element
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this deque, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a deque to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this deque
+     * @return {@code true} if this deque changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this deque
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beginningOfTheEnd = null, last = null;
+        for (E e : c) {
+            Node<E> newNode = new Node<E>(Objects.requireNonNull(e));
+            if (beginningOfTheEnd == null)
+                beginningOfTheEnd = last = newNode;
+            else {
+                last.lazySetNext(newNode);
+                newNode.lazySetPrev(last);
+                last = newNode;
+            }
+        }
+        if (beginningOfTheEnd == null)
+            return false;
+
+        // Atomically append the chain at the tail of this collection
+        restartFromTail:
+        for (;;)
+            for (Node<E> t = tail, p = t, q;;) {
+                if ((q = p.next) != null &&
+                    (q = (p = q).next) != null)
+                    // Check for tail updates every other hop.
+                    // If p == q, we are sure to follow tail instead.
+                    p = (t != (t = tail)) ? t : q;
+                else if (p.prev == p) // NEXT_TERMINATOR
+                    continue restartFromTail;
+                else {
+                    // p is last node
+                    beginningOfTheEnd.lazySetPrev(p); // CAS piggyback
+                    if (p.casNext(null, beginningOfTheEnd)) {
+                        // Successful CAS is the linearization point
+                        // for all elements to be added to this deque.
+                        if (!casTail(t, last)) {
+                            // Try a little harder to update tail,
+                            // since we may be adding many elements.
+                            t = tail;
+                            if (last.next == null)
+                                casTail(t, last);
+                        }
+                        return true;
+                    }
+                    // Lost CAS race to another thread; re-read next
+                }
+            }
+    }
+
+    /**
+     * Removes all of the elements from this deque.
+     */
+    public void clear() {
+        while (pollFirst() != null)
+            ;
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (a == null)
+                        a = new String[4];
+                    else if (size == a.length)
+                        a = Arrays.copyOf(a, 2 * size);
+                    String s = item.toString();
+                    a[size++] = s;
+                    charLength += s.length();
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (x == null)
+                        x = new Object[4];
+                    else if (size == x.length)
+                        x = Arrays.copyOf(x, 2 * (size + 4));
+                    x[size++] = item;
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque,
+     * in proper sequence (from first to last element); the runtime
+     * type of the returned array is that of the specified array.  If
+     * the deque fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of
+     * the specified array and the size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as
+     * bridge between array-based and collection-based APIs.  Further,
+     * this method allows precise control over the runtime type of the
+     * output array, and may, under certain circumstances, be used to
+     * save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in reverse order
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingItr();
+    }
+
+    private abstract class AbstractItr implements Iterator<E> {
+        /**
+         * Next node to return item for.
+         */
+        private Node<E> nextNode;
+
+        /**
+         * nextItem holds on to item fields because once we claim
+         * that an element exists in hasNext(), we must return it in
+         * the following next() call even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        private E nextItem;
+
+        /**
+         * Node returned by most recent call to next. Needed by remove.
+         * Reset to null if this element is deleted by a call to remove.
+         */
+        private Node<E> lastRet;
+
+        abstract Node<E> startNode();
+        abstract Node<E> nextNode(Node<E> p);
+
+        AbstractItr() {
+            advance();
+        }
+
+        /**
+         * Sets nextNode and nextItem to next valid node, or to null
+         * if no such.
+         */
+        private void advance() {
+            lastRet = nextNode;
+
+            Node<E> p = (nextNode == null) ? startNode() : nextNode(nextNode);
+            for (;; p = nextNode(p)) {
+                if (p == null) {
+                    // might be at active end or TERMINATOR node; both are OK
+                    nextNode = null;
+                    nextItem = null;
+                    break;
+                }
+                E item = p.item;
+                if (item != null) {
+                    nextNode = p;
+                    nextItem = item;
+                    break;
+                }
+            }
+        }
+
+        public boolean hasNext() {
+            return nextItem != null;
+        }
+
+        public E next() {
+            E item = nextItem;
+            if (item == null) throw new NoSuchElementException();
+            advance();
+            return item;
+        }
+
+        public void remove() {
+            Node<E> l = lastRet;
+            if (l == null) throw new IllegalStateException();
+            l.item = null;
+            unlink(l);
+            lastRet = null;
+        }
+    }
+
+    /** Forward iterator */
+    private class Itr extends AbstractItr {
+        Node<E> startNode() { return first(); }
+        Node<E> nextNode(Node<E> p) { return succ(p); }
+    }
+
+    /** Descending iterator */
+    private class DescendingItr extends AbstractItr {
+        Node<E> startNode() { return last(); }
+        Node<E> nextNode(Node<E> p) { return pred(p); }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class CLDSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final ConcurrentLinkedDeque<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        CLDSpliterator(ConcurrentLinkedDeque<E> queue) {
+            this.queue = queue;
+        }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                if (p.item == null && p == (p = p.next))
+                    current = p = q.first();
+                if (p != null && p.next != null) {
+                    Object[] a = new Object[n];
+                    int i = 0;
+                    do {
+                        if ((a[i] = p.item) != null)
+                            ++i;
+                        if (p == (p = p.next))
+                            p = q.first();
+                    } while (p != null && i < n);
+                    if ((current = p) == null)
+                        exhausted = true;
+                    if (i > 0) {
+                        batch = i;
+                        return Spliterators.spliterator
+                            (a, 0, i, (Spliterator.ORDERED |
+                                       Spliterator.NONNULL |
+                                       Spliterator.CONCURRENT));
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                exhausted = true;
+                do {
+                    E e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedDeque<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                E e;
+                do {
+                    e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (e == null && p != null);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new CLDSpliterator<E>(this);
+    }
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out all elements in the proper order.
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            E item = p.item;
+            if (item != null)
+                s.writeObject(item);
+        }
+
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in elements until trailing null sentinel found
+        Node<E> h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            @SuppressWarnings("unchecked")
+            Node<E> newNode = new Node<E>((E) item);
+            if (h == null)
+                h = t = newNode;
+            else {
+                t.lazySetNext(newNode);
+                newNode.lazySetPrev(t);
+                t = newNode;
+            }
+        }
+        initHeadTail(h, t);
+    }
+
+    private boolean casHead(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    private boolean casTail(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    static {
+        PREV_TERMINATOR = new Node<Object>();
+        PREV_TERMINATOR.next = PREV_TERMINATOR;
+        NEXT_TERMINATOR = new Node<Object>();
+        NEXT_TERMINATOR.prev = NEXT_TERMINATOR;
+        try {
+            HEAD = U.objectFieldOffset
+                (ConcurrentLinkedDeque.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (ConcurrentLinkedDeque.class.getDeclaredField("tail"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentLinkedQueue.java b/java/util/concurrent/ConcurrentLinkedQueue.java
new file mode 100644
index 0000000..7997c60
--- /dev/null
+++ b/java/util/concurrent/ConcurrentLinkedQueue.java
@@ -0,0 +1,951 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea and Martin Buchholz with assistance from members of
+ * JCP JSR-166 Expert Group and released to the public domain, as explained
+ * at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded thread-safe {@linkplain Queue queue} based on linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * A {@code ConcurrentLinkedQueue} is an appropriate choice when
+ * many threads will share access to a common collection.
+ * Like most other concurrent collection implementations, this class
+ * does not permit the use of {@code null} elements.
+ *
+ * <p>This implementation employs an efficient <em>non-blocking</em>
+ * algorithm based on one described in
+ * <a href="http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf">
+ * Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue
+ * Algorithms</a> by Maged M. Michael and Michael L. Scott.
+ *
+ * <p>Iterators are <i>weakly consistent</i>, returning elements
+ * reflecting the state of the queue at some point at or since the
+ * creation of the iterator.  They do <em>not</em> throw {@link
+ * java.util.ConcurrentModificationException}, and may proceed concurrently
+ * with other operations.  Elements contained in the queue since the creation
+ * of the iterator will be returned exactly once.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these queues, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the <em>optional</em>
+ * methods of the {@link Queue} and {@link Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code ConcurrentLinkedQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code ConcurrentLinkedQueue} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
+        implements Queue<E>, java.io.Serializable {
+    private static final long serialVersionUID = 196745693267521676L;
+
+    /*
+     * This is a modification of the Michael & Scott algorithm,
+     * adapted for a garbage-collected environment, with support for
+     * interior node deletion (to support remove(Object)).  For
+     * explanation, read the paper.
+     *
+     * Note that like most non-blocking algorithms in this package,
+     * this implementation relies on the fact that in garbage
+     * collected systems, there is no possibility of ABA problems due
+     * to recycled nodes, so there is no need to use "counted
+     * pointers" or related techniques seen in versions used in
+     * non-GC'ed settings.
+     *
+     * The fundamental invariants are:
+     * - There is exactly one (last) Node with a null next reference,
+     *   which is CASed when enqueueing.  This last Node can be
+     *   reached in O(1) time from tail, but tail is merely an
+     *   optimization - it can always be reached in O(N) time from
+     *   head as well.
+     * - The elements contained in the queue are the non-null items in
+     *   Nodes that are reachable from head.  CASing the item
+     *   reference of a Node to null atomically removes it from the
+     *   queue.  Reachability of all elements from head must remain
+     *   true even in the case of concurrent modifications that cause
+     *   head to advance.  A dequeued Node may remain in use
+     *   indefinitely due to creation of an Iterator or simply a
+     *   poll() that has lost its time slice.
+     *
+     * The above might appear to imply that all Nodes are GC-reachable
+     * from a predecessor dequeued Node.  That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to advance to head.
+     *
+     * Both head and tail are permitted to lag.  In fact, failing to
+     * update them every time one could is a significant optimization
+     * (fewer CASes). As with LinkedTransferQueue (see the internal
+     * documentation for that class), we use a slack threshold of two;
+     * that is, we update head/tail when the current pointer appears
+     * to be two or more steps away from the first/last node.
+     *
+     * Since head and tail are updated concurrently and independently,
+     * it is possible for tail to lag behind head (why not)?
+     *
+     * CASing a Node's item reference to null atomically removes the
+     * element from the queue.  Iterators skip over Nodes with null
+     * items.  Prior implementations of this class had a race between
+     * poll() and remove(Object) where the same element would appear
+     * to be successfully removed by two concurrent operations.  The
+     * method remove(Object) also lazily unlinks deleted Nodes, but
+     * this is merely an optimization.
+     *
+     * When constructing a Node (before enqueuing it) we avoid paying
+     * for a volatile write to item by using Unsafe.putObject instead
+     * of a normal write.  This allows the cost of enqueue to be
+     * "one-and-a-half" CASes.
+     *
+     * Both head and tail may or may not point to a Node with a
+     * non-null item.  If the queue is empty, all items must of course
+     * be null.  Upon creation, both head and tail refer to a dummy
+     * Node with null item.  Both head and tail are only updated using
+     * CAS, so they never regress, although again this is merely an
+     * optimization.
+     */
+
+    private static class Node<E> {
+        volatile E item;
+        volatile Node<E> next;
+    }
+
+    /**
+     * Returns a new node holding item.  Uses relaxed write because item
+     * can only be seen after piggy-backing publication via casNext.
+     */
+    static <E> Node<E> newNode(E item) {
+        Node<E> node = new Node<E>();
+        U.putObject(node, ITEM, item);
+        return node;
+    }
+
+    static <E> boolean casItem(Node<E> node, E cmp, E val) {
+        return U.compareAndSwapObject(node, ITEM, cmp, val);
+    }
+
+    static <E> void lazySetNext(Node<E> node, Node<E> val) {
+        U.putOrderedObject(node, NEXT, val);
+    }
+
+    static <E> boolean casNext(Node<E> node, Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(node, NEXT, cmp, val);
+    }
+
+    /**
+     * A node from which the first live (non-deleted) node (if any)
+     * can be reached in O(1) time.
+     * Invariants:
+     * - all live nodes are reachable from head via succ()
+     * - head != null
+     * - (tmp = head).next != tmp || tmp != head
+     * Non-invariants:
+     * - head.item may or may not be null.
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     */
+    transient volatile Node<E> head;
+
+    /**
+     * A node from which the last node on list (that is, the unique
+     * node with node.next == null) can be reached in O(1) time.
+     * Invariants:
+     * - the last node is always reachable from tail via succ()
+     * - tail != null
+     * Non-invariants:
+     * - tail.item may or may not be null.
+     * - it is permitted for tail to lag behind head, that is, for tail
+     *   to not be reachable from head!
+     * - tail.next may or may not be self-pointing to tail.
+     */
+    private transient volatile Node<E> tail;
+
+    /**
+     * Creates a {@code ConcurrentLinkedQueue} that is initially empty.
+     */
+    public ConcurrentLinkedQueue() {
+        head = tail = newNode(null);
+    }
+
+    /**
+     * Creates a {@code ConcurrentLinkedQueue}
+     * initially containing the elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentLinkedQueue(Collection<? extends E> c) {
+        Node<E> h = null, t = null;
+        for (E e : c) {
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            if (h == null)
+                h = t = newNode;
+            else {
+                lazySetNext(t, newNode);
+                t = newNode;
+            }
+        }
+        if (h == null)
+            h = t = newNode(null);
+        head = h;
+        tail = t;
+    }
+
+    // Have to override just to update the javadoc
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Tries to CAS head to p. If successful, repoint old head to itself
+     * as sentinel for succ(), below.
+     */
+    final void updateHead(Node<E> h, Node<E> p) {
+        // assert h != null && p != null && (h == p || h.item == null);
+        if (h != p && casHead(h, p))
+            lazySetNext(h, h);
+    }
+
+    /**
+     * Returns the successor of p, or the head node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node<E> succ(Node<E> p) {
+        Node<E> next = p.next;
+        return (p == next) ? head : next;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        final Node<E> newNode = newNode(Objects.requireNonNull(e));
+
+        for (Node<E> t = tail, p = t;;) {
+            Node<E> q = p.next;
+            if (q == null) {
+                // p is last node
+                if (casNext(p, null, newNode)) {
+                    // Successful CAS is the linearization point
+                    // for e to become an element of this queue,
+                    // and for newNode to become "live".
+                    if (p != t) // hop two nodes at a time
+                        casTail(t, newNode);  // Failure is OK.
+                    return true;
+                }
+                // Lost CAS race to another thread; re-read next
+            }
+            else if (p == q)
+                // We have fallen off list.  If tail is unchanged, it
+                // will also be off-list, in which case we need to
+                // jump to head, from which all live nodes are always
+                // reachable.  Else the new tail is a better bet.
+                p = (t != (t = tail)) ? t : head;
+            else
+                // Check for tail updates after two hops.
+                p = (p != t && t != (t = tail)) ? t : q;
+        }
+    }
+
+    public E poll() {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                E item = p.item;
+
+                if (item != null && casItem(p, item, null)) {
+                    // Successful CAS is the linearization point
+                    // for item to be removed from this queue.
+                    if (p != h) // hop two nodes at a time
+                        updateHead(h, ((q = p.next) != null) ? q : p);
+                    return item;
+                }
+                else if ((q = p.next) == null) {
+                    updateHead(h, p);
+                    return null;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    public E peek() {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                E item = p.item;
+                if (item != null || (q = p.next) == null) {
+                    updateHead(h, p);
+                    return item;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Returns the first live (non-deleted) node on list, or null if none.
+     * This is yet another variant of poll/peek; here returning the
+     * first node, not element.  We could make peek() a wrapper around
+     * first(), but that would cost an extra volatile read of item,
+     * and the need to add a retry loop to deal with the possibility
+     * of losing a race to a concurrent poll().
+     */
+    Node<E> first() {
+        restartFromHead:
+        for (;;) {
+            for (Node<E> h = head, p = h, q;;) {
+                boolean hasItem = (p.item != null);
+                if (hasItem || (q = p.next) == null) {
+                    updateHead(h, p);
+                    return hasItem ? p : null;
+                }
+                else if (p == q)
+                    continue restartFromHead;
+                else
+                    p = q;
+            }
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        return first() == null;
+    }
+
+    /**
+     * Returns the number of elements in this queue.  If this queue
+     * contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these queues, determining the current
+     * number of elements requires an O(n) traversal.
+     * Additionally, if elements are added or removed during execution
+     * of this method, the returned result may be inaccurate.  Thus,
+     * this method is typically not very useful in concurrent
+     * applications.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node<E> p = first(); p != null;) {
+                if (p.item != null)
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node<E> p = first(); p != null; p = succ(p)) {
+                E item = p.item;
+                if (item != null && o.equals(item))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        if (o != null) {
+            Node<E> next, pred = null;
+            for (Node<E> p = first(); p != null; pred = p, p = next) {
+                boolean removed = false;
+                E item = p.item;
+                if (item != null) {
+                    if (!o.equals(item)) {
+                        next = succ(p);
+                        continue;
+                    }
+                    removed = casItem(p, item, null);
+                }
+
+                next = succ(p);
+                if (pred != null && next != null) // unlink
+                    casNext(pred, p, next);
+                if (removed)
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end of
+     * this queue, in the order that they are returned by the specified
+     * collection's iterator.  Attempts to {@code addAll} of a queue to
+     * itself result in {@code IllegalArgumentException}.
+     *
+     * @param c the elements to be inserted into this queue
+     * @return {@code true} if this queue changed as a result of the call
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     * @throws IllegalArgumentException if the collection is this queue
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        if (c == this)
+            // As historically specified in AbstractQueue#addAll
+            throw new IllegalArgumentException();
+
+        // Copy c into a private chain of Nodes
+        Node<E> beginningOfTheEnd = null, last = null;
+        for (E e : c) {
+            Node<E> newNode = newNode(Objects.requireNonNull(e));
+            if (beginningOfTheEnd == null)
+                beginningOfTheEnd = last = newNode;
+            else {
+                lazySetNext(last, newNode);
+                last = newNode;
+            }
+        }
+        if (beginningOfTheEnd == null)
+            return false;
+
+        // Atomically append the chain at the tail of this collection
+        for (Node<E> t = tail, p = t;;) {
+            Node<E> q = p.next;
+            if (q == null) {
+                // p is last node
+                if (casNext(p, null, beginningOfTheEnd)) {
+                    // Successful CAS is the linearization point
+                    // for all elements to be added to this queue.
+                    if (!casTail(t, last)) {
+                        // Try a little harder to update tail,
+                        // since we may be adding many elements.
+                        t = tail;
+                        if (last.next == null)
+                            casTail(t, last);
+                    }
+                    return true;
+                }
+                // Lost CAS race to another thread; re-read next
+            }
+            else if (p == q)
+                // We have fallen off list.  If tail is unchanged, it
+                // will also be off-list, in which case we need to
+                // jump to head, from which all live nodes are always
+                // reachable.  Else the new tail is a better bet.
+                p = (t != (t = tail)) ? t : head;
+            else
+                // Check for tail updates after two hops.
+                p = (p != t && t != (t = tail)) ? t : q;
+        }
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (a == null)
+                        a = new String[4];
+                    else if (size == a.length)
+                        a = Arrays.copyOf(a, 2 * size);
+                    String s = item.toString();
+                    a[size++] = s;
+                    charLength += s.length();
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node<E> p = first(); p != null;) {
+                E item = p.item;
+                if (item != null) {
+                    if (x == null)
+                        x = new Object[4];
+                    else if (size == x.length)
+                        x = Arrays.copyOf(x, 2 * (size + 4));
+                    x[size++] = item;
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private class Itr implements Iterator<E> {
+        /**
+         * Next node to return item for.
+         */
+        private Node<E> nextNode;
+
+        /**
+         * nextItem holds on to item fields because once we claim
+         * that an element exists in hasNext(), we must return it in
+         * the following next() call even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        private E nextItem;
+
+        /**
+         * Node of the last returned item, to support remove.
+         */
+        private Node<E> lastRet;
+
+        Itr() {
+            restartFromHead: for (;;) {
+                Node<E> h, p, q;
+                for (p = h = head;; p = q) {
+                    E item;
+                    if ((item = p.item) != null) {
+                        nextNode = p;
+                        nextItem = item;
+                        break;
+                    }
+                    else if ((q = p.next) == null)
+                        break;
+                    else if (p == q)
+                        continue restartFromHead;
+                }
+                updateHead(h, p);
+                return;
+            }
+        }
+
+        public boolean hasNext() {
+            return nextItem != null;
+        }
+
+        public E next() {
+            final Node<E> pred = nextNode;
+            if (pred == null) throw new NoSuchElementException();
+            // assert nextItem != null;
+            lastRet = pred;
+            E item = null;
+
+            for (Node<E> p = succ(pred), q;; p = q) {
+                if (p == null || (item = p.item) != null) {
+                    nextNode = p;
+                    E x = nextItem;
+                    nextItem = item;
+                    return x;
+                }
+                // unlink deleted nodes
+                if ((q = succ(p)) != null)
+                    casNext(pred, p, q);
+            }
+        }
+
+        public void remove() {
+            Node<E> l = lastRet;
+            if (l == null) throw new IllegalStateException();
+            // rely on a future traversal to relink.
+            l.item = null;
+            lastRet = null;
+        }
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        // Write out any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out all elements in the proper order.
+        for (Node<E> p = first(); p != null; p = succ(p)) {
+            Object item = p.item;
+            if (item != null)
+                s.writeObject(item);
+        }
+
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+
+        // Read in elements until trailing null sentinel found
+        Node<E> h = null, t = null;
+        for (Object item; (item = s.readObject()) != null; ) {
+            @SuppressWarnings("unchecked")
+            Node<E> newNode = newNode((E) item);
+            if (h == null)
+                h = t = newNode;
+            else {
+                lazySetNext(t, newNode);
+                t = newNode;
+            }
+        }
+        if (h == null)
+            h = t = newNode(null);
+        head = h;
+        tail = t;
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class CLQSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final ConcurrentLinkedQueue<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        CLQSpliterator(ConcurrentLinkedQueue<E> queue) {
+            this.queue = queue;
+        }
+
+        public Spliterator<E> trySplit() {
+            Node<E> p;
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null) &&
+                p.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                do {
+                    if ((a[i] = p.item) != null)
+                        ++i;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (p != null && i < n);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                exhausted = true;
+                do {
+                    E e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node<E> p;
+            if (action == null) throw new NullPointerException();
+            final ConcurrentLinkedQueue<E> q = this.queue;
+            if (!exhausted &&
+                ((p = current) != null || (p = q.first()) != null)) {
+                E e;
+                do {
+                    e = p.item;
+                    if (p == (p = p.next))
+                        p = q.first();
+                } while (e == null && p != null);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    @Override
+    public Spliterator<E> spliterator() {
+        return new CLQSpliterator<E>(this);
+    }
+
+    private boolean casTail(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    }
+
+    private boolean casHead(Node<E> cmp, Node<E> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    private static final long ITEM;
+    private static final long NEXT;
+    static {
+        try {
+            HEAD = U.objectFieldOffset
+                (ConcurrentLinkedQueue.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (ConcurrentLinkedQueue.class.getDeclaredField("tail"));
+            ITEM = U.objectFieldOffset
+                (Node.class.getDeclaredField("item"));
+            NEXT = U.objectFieldOffset
+                (Node.class.getDeclaredField("next"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentMap.java b/java/util/concurrent/ConcurrentMap.java
new file mode 100644
index 0000000..69dae6f
--- /dev/null
+++ b/java/util/concurrent/ConcurrentMap.java
@@ -0,0 +1,502 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link java.util.Map} providing thread safety and atomicity
+ * guarantees.
+ *
+ * <p>To maintain the specified guarantees, default implementations of
+ * methods including {@link #putIfAbsent} inherited from {@link Map}
+ * must be overridden by implementations of this interface. Similarly,
+ * implementations of the collections returned by methods {@link
+ * #keySet}, {@link #values}, and {@link #entrySet} must override
+ * methods such as {@code removeIf} when necessary to
+ * preserve atomicity guarantees.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code ConcurrentMap} as a key or value
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that object from
+ * the {@code ConcurrentMap} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ */
+public interface ConcurrentMap<K,V> extends Map<K,V> {
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote This implementation assumes that the ConcurrentMap cannot
+     * contain null values and {@code get()} returning null unambiguously means
+     * the key is absent. Implementations which support null values
+     * <strong>must</strong> override this default implementation.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return ((v = get(key)) != null) ? v : defaultValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec The default implementation is equivalent to, for this
+     * {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K,V> entry : map.entrySet()) {
+     *   action.accept(entry.getKey(), entry.getValue());
+     * }}</pre>
+     *
+     * @implNote The default implementation assumes that
+     * {@code IllegalStateException} thrown by {@code getKey()} or
+     * {@code getValue()} indicates that the entry has been removed and cannot
+     * be processed. Operation continues for subsequent entries.
+     *
+     * @throws NullPointerException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default void forEach(BiConsumer<? super K, ? super V> action) {
+        Objects.requireNonNull(action);
+        for (Map.Entry<K,V> entry : entrySet()) {
+            K k;
+            V v;
+            try {
+                k = entry.getKey();
+                v = entry.getValue();
+            } catch (IllegalStateException ise) {
+                // this usually means the entry is no longer in the map.
+                continue;
+            }
+            action.accept(k, v);
+        }
+    }
+
+    /**
+     * If the specified key is not already associated
+     * with a value, associates it with the given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (!map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return map.get(key);}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V putIfAbsent(K key, V value);
+
+    /**
+     * Removes the entry for a key only if currently mapped to a given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key)
+     *     && Objects.equals(map.get(key), value)) {
+     *   map.remove(key);
+     *   return true;
+     * } else {
+     *   return false;
+     * }}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value expected to be associated with the specified key
+     * @return {@code true} if the value was removed
+     * @throws UnsupportedOperationException if the {@code remove} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the key or value is of an inappropriate
+     *         type for this map
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     */
+    boolean remove(Object key, Object value);
+
+    /**
+     * Replaces the entry for a key only if currently mapped to a given value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key)
+     *     && Objects.equals(map.get(key), oldValue)) {
+     *   map.put(key, newValue);
+     *   return true;
+     * } else {
+     *   return false;
+     * }}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param oldValue value expected to be associated with the specified key
+     * @param newValue value to be associated with the specified key
+     * @return {@code true} if the value was replaced
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of a specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if a specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of a specified key
+     *         or value prevents it from being stored in this map
+     */
+    boolean replace(K key, V oldValue, V newValue);
+
+    /**
+     * Replaces the entry for a key only if currently mapped to some value.
+     * This is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * if (map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return null;}</pre>
+     *
+     * except that the action is performed atomically.
+     *
+     * @implNote This implementation intentionally re-abstracts the
+     * inappropriate default provided in {@code Map}.
+     *
+     * @param key key with which the specified value is associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key.
+     *         (A {@code null} return can also indicate that the map
+     *         previously associated {@code null} with the key,
+     *         if the implementation supports null values.)
+     * @throws UnsupportedOperationException if the {@code put} operation
+     *         is not supported by this map
+     * @throws ClassCastException if the class of the specified key or value
+     *         prevents it from being stored in this map
+     * @throws NullPointerException if the specified key or value is null,
+     *         and this map does not permit null keys or values
+     * @throws IllegalArgumentException if some property of the specified key
+     *         or value prevents it from being stored in this map
+     */
+    V replace(K key, V value);
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * <p>The default implementation is equivalent to, for this {@code map}:
+     * <pre> {@code
+     * for (Map.Entry<K,V> entry : map.entrySet()) {
+     *   K k;
+     *   V v;
+     *   do {
+     *     k = entry.getKey();
+     *     v = entry.getValue();
+     *   } while (!map.replace(k, v, function.apply(k, v)));
+     * }}</pre>
+     *
+     * The default implementation may retry these steps when multiple
+     * threads attempt updates including potentially calling the function
+     * repeatedly for a given key.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Objects.requireNonNull(function);
+        forEach((k,v) -> {
+            while (!replace(k, v, function.apply(k, v))) {
+                // v changed or k is gone
+                if ( (v = get(k)) == null) {
+                    // k is no longer in the map.
+                    break;
+                }
+            }
+        });
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to the following steps for this
+     * {@code map}:
+     *
+     * <pre> {@code
+     * V oldValue, newValue;
+     * return ((oldValue = map.get(key)) == null
+     *         && (newValue = mappingFunction.apply(key)) != null
+     *         && (oldValue = map.putIfAbsent(key, newValue)) == null)
+     *   ? newValue
+     *   : oldValue;}</pre>
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V computeIfAbsent(K key,
+            Function<? super K, ? extends V> mappingFunction) {
+        Objects.requireNonNull(mappingFunction);
+        V oldValue, newValue;
+        return ((oldValue = get(key)) == null
+                && (newValue = mappingFunction.apply(key)) != null
+                && (oldValue = putIfAbsent(key, newValue)) == null)
+            ? newValue
+            : oldValue;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (V oldValue; (oldValue = map.get(key)) != null; ) {
+     *   V newValue = remappingFunction.apply(key, oldValue);
+     *   if ((newValue == null)
+     *       ? map.remove(key, oldValue)
+     *       : map.replace(key, oldValue, newValue))
+     *     return newValue;
+     * }
+     * return null;}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V computeIfPresent(K key,
+            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        for (V oldValue; (oldValue = get(key)) != null; ) {
+            V newValue = remappingFunction.apply(key, oldValue);
+            if ((newValue == null)
+                ? remove(key, oldValue)
+                : replace(key, oldValue, newValue))
+                return newValue;
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (;;) {
+     *   V oldValue = map.get(key);
+     *   V newValue = remappingFunction.apply(key, oldValue);
+     *   if (newValue != null) {
+     *     if ((oldValue != null)
+     *       ? map.replace(key, oldValue, newValue)
+     *       : map.putIfAbsent(key, newValue) == null)
+     *       return newValue;
+     *   } else if (oldValue == null || map.remove(key, oldValue)) {
+     *     return null;
+     *   }
+     * }}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V compute(K key,
+                      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        retry: for (;;) {
+            V oldValue = get(key);
+            // if putIfAbsent fails, opportunistically use its return value
+            haveOldValue: for (;;) {
+                V newValue = remappingFunction.apply(key, oldValue);
+                if (newValue != null) {
+                    if (oldValue != null) {
+                        if (replace(key, oldValue, newValue))
+                            return newValue;
+                    }
+                    else if ((oldValue = putIfAbsent(key, newValue)) == null)
+                        return newValue;
+                    else continue haveOldValue;
+                } else if (oldValue == null || remove(key, oldValue)) {
+                    return null;
+                }
+                continue retry;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implSpec
+     * The default implementation is equivalent to performing the following
+     * steps for this {@code map}:
+     *
+     * <pre> {@code
+     * for (;;) {
+     *   V oldValue = map.get(key);
+     *   if (oldValue != null) {
+     *     V newValue = remappingFunction.apply(oldValue, value);
+     *     if (newValue != null) {
+     *       if (map.replace(key, oldValue, newValue))
+     *         return newValue;
+     *     } else if (map.remove(key, oldValue)) {
+     *       return null;
+     *     }
+     *   } else if (map.putIfAbsent(key, value) == null) {
+     *     return value;
+     *   }
+     * }}</pre>
+     * When multiple threads attempt updates, map operations and the
+     * remapping function may be called multiple times.
+     *
+     * <p>This implementation assumes that the ConcurrentMap cannot contain null
+     * values and {@code get()} returning null unambiguously means the key is
+     * absent. Implementations which support null values <strong>must</strong>
+     * override this default implementation.
+     *
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     * @since 1.8
+     */
+    @Override
+    default V merge(K key, V value,
+            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        Objects.requireNonNull(remappingFunction);
+        Objects.requireNonNull(value);
+        retry: for (;;) {
+            V oldValue = get(key);
+            // if putIfAbsent fails, opportunistically use its return value
+            haveOldValue: for (;;) {
+                if (oldValue != null) {
+                    V newValue = remappingFunction.apply(oldValue, value);
+                    if (newValue != null) {
+                        if (replace(key, oldValue, newValue))
+                            return newValue;
+                    } else if (remove(key, oldValue)) {
+                        return null;
+                    }
+                    continue retry;
+                } else {
+                    if ((oldValue = putIfAbsent(key, value)) == null)
+                        return value;
+                    continue haveOldValue;
+                }
+            }
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentNavigableMap.java b/java/util/concurrent/ConcurrentNavigableMap.java
new file mode 100644
index 0000000..94a90cd
--- /dev/null
+++ b/java/util/concurrent/ConcurrentNavigableMap.java
@@ -0,0 +1,169 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link ConcurrentMap} supporting {@link NavigableMap} operations,
+ * and recursively so for its navigable sub-maps.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public interface ConcurrentNavigableMap<K,V>
+    extends ConcurrentMap<K,V>, NavigableMap<K,V>
+{
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                       K toKey,   boolean toInclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> headMap(K toKey);
+
+    /**
+     * @throws ClassCastException       {@inheritDoc}
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    ConcurrentNavigableMap<K,V> tailMap(K fromKey);
+
+    /**
+     * Returns a reverse order view of the mappings contained in this map.
+     * The descending map is backed by this map, so changes to the map are
+     * reflected in the descending map, and vice-versa.
+     *
+     * <p>The returned map has an ordering equivalent to
+     * {@link java.util.Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code m.descendingMap().descendingMap()} returns a
+     * view of {@code m} essentially equivalent to {@code m}.
+     *
+     * @return a reverse order view of this map
+     */
+    ConcurrentNavigableMap<K,V> descendingMap();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> navigableKeySet();
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in ascending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>This method is equivalent to method {@code navigableKeySet}.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    NavigableSet<K> keySet();
+
+    /**
+     * Returns a reverse order {@link NavigableSet} view of the keys contained in this map.
+     * The set's iterator returns the keys in descending order.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return a reverse order navigable set view of the keys in this map
+     */
+    NavigableSet<K> descendingKeySet();
+}
diff --git a/java/util/concurrent/ConcurrentSkipListMap.java b/java/util/concurrent/ConcurrentSkipListMap.java
new file mode 100644
index 0000000..583244b
--- /dev/null
+++ b/java/util/concurrent/ConcurrentSkipListMap.java
@@ -0,0 +1,3609 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.Serializable;
+import java.util.AbstractCollection;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
+ * The map is sorted according to the {@linkplain Comparable natural
+ * ordering} of its keys, or by a {@link Comparator} provided at map
+ * creation time, depending on which constructor is used.
+ *
+ * <p>This class implements a concurrent variant of <a
+ * href="http://en.wikipedia.org/wiki/Skip_list" target="_top">SkipLists</a>
+ * providing expected average <i>log(n)</i> time cost for the
+ * {@code containsKey}, {@code get}, {@code put} and
+ * {@code remove} operations and their variants.  Insertion, removal,
+ * update, and access operations safely execute concurrently by
+ * multiple threads.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Ascending key ordered views and their iterators are faster than
+ * descending ones.
+ *
+ * <p>All {@code Map.Entry} pairs returned by methods in this class
+ * and its views represent snapshots of mappings at the time they were
+ * produced. They do <em>not</em> support the {@code Entry.setValue}
+ * method. (Note however that it is possible to change mappings in the
+ * associated map using {@code put}, {@code putIfAbsent}, or
+ * {@code replace}, depending on exactly which effect you need.)
+ *
+ * <p>Beware that, unlike in most collections, the {@code size}
+ * method is <em>not</em> a constant-time operation. Because of the
+ * asynchronous nature of these maps, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code putAll}, {@code equals},
+ * {@code toArray}, {@code containsValue}, and {@code clear} are
+ * <em>not</em> guaranteed to be performed atomically. For example, an
+ * iterator operating concurrently with a {@code putAll} operation
+ * might view only some of the added elements.
+ *
+ * <p>This class and its views and iterators implement all of the
+ * <em>optional</em> methods of the {@link Map} and {@link Iterator}
+ * interfaces. Like most other concurrent collections, this class does
+ * <em>not</em> permit the use of {@code null} keys or values because some
+ * null return values cannot be reliably distinguished from the absence of
+ * elements.
+ *
+ * @author Doug Lea
+ * @param <K> the type of keys maintained by this map
+ * @param <V> the type of mapped values
+ * @since 1.6
+ */
+public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
+    implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+    /*
+     * This class implements a tree-like two-dimensionally linked skip
+     * list in which the index levels are represented in separate
+     * nodes from the base nodes holding data.  There are two reasons
+     * for taking this approach instead of the usual array-based
+     * structure: 1) Array based implementations seem to encounter
+     * more complexity and overhead 2) We can use cheaper algorithms
+     * for the heavily-traversed index lists than can be used for the
+     * base lists.  Here's a picture of some of the basics for a
+     * possible list with 2 levels of index:
+     *
+     * Head nodes          Index nodes
+     * +-+    right        +-+                      +-+
+     * |2|---------------->| |--------------------->| |->null
+     * +-+                 +-+                      +-+
+     *  | down              |                        |
+     *  v                   v                        v
+     * +-+            +-+  +-+       +-+            +-+       +-+
+     * |1|----------->| |->| |------>| |----------->| |------>| |->null
+     * +-+            +-+  +-+       +-+            +-+       +-+
+     *  v              |    |         |              |         |
+     * Nodes  next     v    v         v              v         v
+     * +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+
+     * | |->|A|->|B|->|C|->|D|->|E|->|F|->|G|->|H|->|I|->|J|->|K|->null
+     * +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+  +-+
+     *
+     * The base lists use a variant of the HM linked ordered set
+     * algorithm. See Tim Harris, "A pragmatic implementation of
+     * non-blocking linked lists"
+     * http://www.cl.cam.ac.uk/~tlh20/publications.html and Maged
+     * Michael "High Performance Dynamic Lock-Free Hash Tables and
+     * List-Based Sets"
+     * http://www.research.ibm.com/people/m/michael/pubs.htm.  The
+     * basic idea in these lists is to mark the "next" pointers of
+     * deleted nodes when deleting to avoid conflicts with concurrent
+     * insertions, and when traversing to keep track of triples
+     * (predecessor, node, successor) in order to detect when and how
+     * to unlink these deleted nodes.
+     *
+     * Rather than using mark-bits to mark list deletions (which can
+     * be slow and space-intensive using AtomicMarkedReference), nodes
+     * use direct CAS'able next pointers.  On deletion, instead of
+     * marking a pointer, they splice in another node that can be
+     * thought of as standing for a marked pointer (indicating this by
+     * using otherwise impossible field values).  Using plain nodes
+     * acts roughly like "boxed" implementations of marked pointers,
+     * but uses new nodes only when nodes are deleted, not for every
+     * link.  This requires less space and supports faster
+     * traversal. Even if marked references were better supported by
+     * JVMs, traversal using this technique might still be faster
+     * because any search need only read ahead one more node than
+     * otherwise required (to check for trailing marker) rather than
+     * unmasking mark bits or whatever on each read.
+     *
+     * This approach maintains the essential property needed in the HM
+     * algorithm of changing the next-pointer of a deleted node so
+     * that any other CAS of it will fail, but implements the idea by
+     * changing the pointer to point to a different node, not by
+     * marking it.  While it would be possible to further squeeze
+     * space by defining marker nodes not to have key/value fields, it
+     * isn't worth the extra type-testing overhead.  The deletion
+     * markers are rarely encountered during traversal and are
+     * normally quickly garbage collected. (Note that this technique
+     * would not work well in systems without garbage collection.)
+     *
+     * In addition to using deletion markers, the lists also use
+     * nullness of value fields to indicate deletion, in a style
+     * similar to typical lazy-deletion schemes.  If a node's value is
+     * null, then it is considered logically deleted and ignored even
+     * though it is still reachable. This maintains proper control of
+     * concurrent replace vs delete operations -- an attempted replace
+     * must fail if a delete beat it by nulling field, and a delete
+     * must return the last non-null value held in the field. (Note:
+     * Null, rather than some special marker, is used for value fields
+     * here because it just so happens to mesh with the Map API
+     * requirement that method get returns null if there is no
+     * mapping, which allows nodes to remain concurrently readable
+     * even when deleted. Using any other marker value here would be
+     * messy at best.)
+     *
+     * Here's the sequence of events for a deletion of node n with
+     * predecessor b and successor f, initially:
+     *
+     *        +------+       +------+      +------+
+     *   ...  |   b  |------>|   n  |----->|   f  | ...
+     *        +------+       +------+      +------+
+     *
+     * 1. CAS n's value field from non-null to null.
+     *    From this point on, no public operations encountering
+     *    the node consider this mapping to exist. However, other
+     *    ongoing insertions and deletions might still modify
+     *    n's next pointer.
+     *
+     * 2. CAS n's next pointer to point to a new marker node.
+     *    From this point on, no other nodes can be appended to n.
+     *    which avoids deletion errors in CAS-based linked lists.
+     *
+     *        +------+       +------+      +------+       +------+
+     *   ...  |   b  |------>|   n  |----->|marker|------>|   f  | ...
+     *        +------+       +------+      +------+       +------+
+     *
+     * 3. CAS b's next pointer over both n and its marker.
+     *    From this point on, no new traversals will encounter n,
+     *    and it can eventually be GCed.
+     *        +------+                                    +------+
+     *   ...  |   b  |----------------------------------->|   f  | ...
+     *        +------+                                    +------+
+     *
+     * A failure at step 1 leads to simple retry due to a lost race
+     * with another operation. Steps 2-3 can fail because some other
+     * thread noticed during a traversal a node with null value and
+     * helped out by marking and/or unlinking.  This helping-out
+     * ensures that no thread can become stuck waiting for progress of
+     * the deleting thread.  The use of marker nodes slightly
+     * complicates helping-out code because traversals must track
+     * consistent reads of up to four nodes (b, n, marker, f), not
+     * just (b, n, f), although the next field of a marker is
+     * immutable, and once a next field is CAS'ed to point to a
+     * marker, it never again changes, so this requires less care.
+     *
+     * Skip lists add indexing to this scheme, so that the base-level
+     * traversals start close to the locations being found, inserted
+     * or deleted -- usually base level traversals only traverse a few
+     * nodes. This doesn't change the basic algorithm except for the
+     * need to make sure base traversals start at predecessors (here,
+     * b) that are not (structurally) deleted, otherwise retrying
+     * after processing the deletion.
+     *
+     * Index levels are maintained as lists with volatile next fields,
+     * using CAS to link and unlink.  Races are allowed in index-list
+     * operations that can (rarely) fail to link in a new index node
+     * or delete one. (We can't do this of course for data nodes.)
+     * However, even when this happens, the index lists remain sorted,
+     * so correctly serve as indices.  This can impact performance,
+     * but since skip lists are probabilistic anyway, the net result
+     * is that under contention, the effective "p" value may be lower
+     * than its nominal value. And race windows are kept small enough
+     * that in practice these failures are rare, even under a lot of
+     * contention.
+     *
+     * The fact that retries (for both base and index lists) are
+     * relatively cheap due to indexing allows some minor
+     * simplifications of retry logic. Traversal restarts are
+     * performed after most "helping-out" CASes. This isn't always
+     * strictly necessary, but the implicit backoffs tend to help
+     * reduce other downstream failed CAS's enough to outweigh restart
+     * cost.  This worsens the worst case, but seems to improve even
+     * highly contended cases.
+     *
+     * Unlike most skip-list implementations, index insertion and
+     * deletion here require a separate traversal pass occurring after
+     * the base-level action, to add or remove index nodes.  This adds
+     * to single-threaded overhead, but improves contended
+     * multithreaded performance by narrowing interference windows,
+     * and allows deletion to ensure that all index nodes will be made
+     * unreachable upon return from a public remove operation, thus
+     * avoiding unwanted garbage retention. This is more important
+     * here than in some other data structures because we cannot null
+     * out node fields referencing user keys since they might still be
+     * read by other ongoing traversals.
+     *
+     * Indexing uses skip list parameters that maintain good search
+     * performance while using sparser-than-usual indices: The
+     * hardwired parameters k=1, p=0.5 (see method doPut) mean
+     * that about one-quarter of the nodes have indices. Of those that
+     * do, half have one level, a quarter have two, and so on (see
+     * Pugh's Skip List Cookbook, sec 3.4).  The expected total space
+     * requirement for a map is slightly less than for the current
+     * implementation of java.util.TreeMap.
+     *
+     * Changing the level of the index (i.e, the height of the
+     * tree-like structure) also uses CAS. The head index has initial
+     * level/height of one. Creation of an index with height greater
+     * than the current level adds a level to the head index by
+     * CAS'ing on a new top-most head. To maintain good performance
+     * after a lot of removals, deletion methods heuristically try to
+     * reduce the height if the topmost levels appear to be empty.
+     * This may encounter races in which it possible (but rare) to
+     * reduce and "lose" a level just as it is about to contain an
+     * index (that will then never be encountered). This does no
+     * structural harm, and in practice appears to be a better option
+     * than allowing unrestrained growth of levels.
+     *
+     * The code for all this is more verbose than you'd like. Most
+     * operations entail locating an element (or position to insert an
+     * element). The code to do this can't be nicely factored out
+     * because subsequent uses require a snapshot of predecessor
+     * and/or successor and/or value fields which can't be returned
+     * all at once, at least not without creating yet another object
+     * to hold them -- creating such little objects is an especially
+     * bad idea for basic internal search operations because it adds
+     * to GC overhead.  (This is one of the few times I've wished Java
+     * had macros.) Instead, some traversal code is interleaved within
+     * insertion and removal operations.  The control logic to handle
+     * all the retry conditions is sometimes twisty. Most search is
+     * broken into 2 parts. findPredecessor() searches index nodes
+     * only, returning a base-level predecessor of the key. findNode()
+     * finishes out the base-level search. Even with this factoring,
+     * there is a fair amount of near-duplication of code to handle
+     * variants.
+     *
+     * To produce random values without interference across threads,
+     * we use within-JDK thread local random support (via the
+     * "secondary seed", to avoid interference with user-level
+     * ThreadLocalRandom.)
+     *
+     * A previous version of this class wrapped non-comparable keys
+     * with their comparators to emulate Comparables when using
+     * comparators vs Comparables.  However, JVMs now appear to better
+     * handle infusing comparator-vs-comparable choice into search
+     * loops. Static method cpr(comparator, x, y) is used for all
+     * comparisons, which works well as long as the comparator
+     * argument is set up outside of loops (thus sometimes passed as
+     * an argument to internal methods) to avoid field re-reads.
+     *
+     * For explanation of algorithms sharing at least a couple of
+     * features with this one, see Mikhail Fomitchev's thesis
+     * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
+     * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
+     * thesis (http://www.cs.chalmers.se/~phs/).
+     *
+     * Given the use of tree-like index nodes, you might wonder why
+     * this doesn't use some kind of search tree instead, which would
+     * support somewhat faster search operations. The reason is that
+     * there are no known efficient lock-free insertion and deletion
+     * algorithms for search trees. The immutability of the "down"
+     * links of index nodes (as opposed to mutable "left" fields in
+     * true trees) makes this tractable using only CAS operations.
+     *
+     * Notation guide for local variables
+     * Node:         b, n, f    for  predecessor, node, successor
+     * Index:        q, r, d    for index node, right, down.
+     *               t          for another index node
+     * Head:         h
+     * Levels:       j
+     * Keys:         k, key
+     * Values:       v, value
+     * Comparisons:  c
+     */
+
+    private static final long serialVersionUID = -8627078645895051609L;
+
+    /**
+     * Special value used to identify base-level header.
+     */
+    static final Object BASE_HEADER = new Object();
+
+    /**
+     * The topmost head index of the skiplist.
+     */
+    private transient volatile HeadIndex<K,V> head;
+
+    /**
+     * The comparator used to maintain order in this map, or null if
+     * using natural ordering.  (Non-private to simplify access in
+     * nested classes.)
+     * @serial
+     */
+    final Comparator<? super K> comparator;
+
+    /** Lazily initialized key set */
+    private transient KeySet<K,V> keySet;
+    /** Lazily initialized entry set */
+    private transient EntrySet<K,V> entrySet;
+    /** Lazily initialized values collection */
+    private transient Values<K,V> values;
+    /** Lazily initialized descending key set */
+    private transient ConcurrentNavigableMap<K,V> descendingMap;
+
+    /**
+     * Initializes or resets state. Needed by constructors, clone,
+     * clear, readObject. and ConcurrentSkipListSet.clone.
+     * (Note that comparator must be separately initialized.)
+     */
+    private void initialize() {
+        keySet = null;
+        entrySet = null;
+        values = null;
+        descendingMap = null;
+        head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
+                                  null, null, 1);
+    }
+
+    /**
+     * compareAndSet head node.
+     */
+    private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    /* ---------------- Nodes -------------- */
+
+    /**
+     * Nodes hold keys and values, and are singly linked in sorted
+     * order, possibly with some intervening marker nodes. The list is
+     * headed by a dummy node accessible as head.node. The value field
+     * is declared only as Object because it takes special non-V
+     * values for marker and header nodes.
+     */
+    static final class Node<K,V> {
+        final K key;
+        volatile Object value;
+        volatile Node<K,V> next;
+
+        /**
+         * Creates a new regular node.
+         */
+        Node(K key, Object value, Node<K,V> next) {
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        /**
+         * Creates a new marker node. A marker is distinguished by
+         * having its value field point to itself.  Marker nodes also
+         * have null keys, a fact that is exploited in a few places,
+         * but this doesn't distinguish markers from the base-level
+         * header node (head.node), which also has a null key.
+         */
+        Node(Node<K,V> next) {
+            this.key = null;
+            this.value = this;
+            this.next = next;
+        }
+
+        /**
+         * compareAndSet value field.
+         */
+        boolean casValue(Object cmp, Object val) {
+            return U.compareAndSwapObject(this, VALUE, cmp, val);
+        }
+
+        /**
+         * compareAndSet next field.
+         */
+        boolean casNext(Node<K,V> cmp, Node<K,V> val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        /**
+         * Returns true if this node is a marker. This method isn't
+         * actually called in any current code checking for markers
+         * because callers will have already read value field and need
+         * to use that read (not another done here) and so directly
+         * test if value points to node.
+         *
+         * @return true if this node is a marker node
+         */
+        boolean isMarker() {
+            return value == this;
+        }
+
+        /**
+         * Returns true if this node is the header of base-level list.
+         * @return true if this node is header node
+         */
+        boolean isBaseHeader() {
+            return value == BASE_HEADER;
+        }
+
+        /**
+         * Tries to append a deletion marker to this node.
+         * @param f the assumed current successor of this node
+         * @return true if successful
+         */
+        boolean appendMarker(Node<K,V> f) {
+            return casNext(f, new Node<K,V>(f));
+        }
+
+        /**
+         * Helps out a deletion by appending marker or unlinking from
+         * predecessor. This is called during traversals when value
+         * field seen to be null.
+         * @param b predecessor
+         * @param f successor
+         */
+        void helpDelete(Node<K,V> b, Node<K,V> f) {
+            /*
+             * Rechecking links and then doing only one of the
+             * help-out stages per call tends to minimize CAS
+             * interference among helping threads.
+             */
+            if (f == next && this == b.next) {
+                if (f == null || f.value != f) // not already marked
+                    casNext(f, new Node<K,V>(f));
+                else
+                    b.casNext(this, f.next);
+            }
+        }
+
+        /**
+         * Returns value if this node contains a valid key-value pair,
+         * else null.
+         * @return this node's value if it isn't a marker or header or
+         * is deleted, else null
+         */
+        V getValidValue() {
+            Object v = value;
+            if (v == this || v == BASE_HEADER)
+                return null;
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return vv;
+        }
+
+        /**
+         * Creates and returns a new SimpleImmutableEntry holding current
+         * mapping if this node holds a valid value, else null.
+         * @return new entry or null
+         */
+        AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
+            Object v = value;
+            if (v == null || v == this || v == BASE_HEADER)
+                return null;
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+        }
+
+        // Unsafe mechanics
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long VALUE;
+        private static final long NEXT;
+
+        static {
+            try {
+                VALUE = U.objectFieldOffset
+                    (Node.class.getDeclaredField("value"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /* ---------------- Indexing -------------- */
+
+    /**
+     * Index nodes represent the levels of the skip list.  Note that
+     * even though both Nodes and Indexes have forward-pointing
+     * fields, they have different types and are handled in different
+     * ways, that can't nicely be captured by placing field in a
+     * shared abstract class.
+     */
+    static class Index<K,V> {
+        final Node<K,V> node;
+        final Index<K,V> down;
+        volatile Index<K,V> right;
+
+        /**
+         * Creates index node with given values.
+         */
+        Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
+            this.node = node;
+            this.down = down;
+            this.right = right;
+        }
+
+        /**
+         * compareAndSet right field.
+         */
+        final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
+            return U.compareAndSwapObject(this, RIGHT, cmp, val);
+        }
+
+        /**
+         * Returns true if the node this indexes has been deleted.
+         * @return true if indexed node is known to be deleted
+         */
+        final boolean indexesDeletedNode() {
+            return node.value == null;
+        }
+
+        /**
+         * Tries to CAS newSucc as successor.  To minimize races with
+         * unlink that may lose this index node, if the node being
+         * indexed is known to be deleted, it doesn't try to link in.
+         * @param succ the expected current successor
+         * @param newSucc the new successor
+         * @return true if successful
+         */
+        final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
+            Node<K,V> n = node;
+            newSucc.right = succ;
+            return n.value != null && casRight(succ, newSucc);
+        }
+
+        /**
+         * Tries to CAS right field to skip over apparent successor
+         * succ.  Fails (forcing a retraversal by caller) if this node
+         * is known to be deleted.
+         * @param succ the expected current successor
+         * @return true if successful
+         */
+        final boolean unlink(Index<K,V> succ) {
+            return node.value != null && casRight(succ, succ.right);
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long RIGHT;
+        static {
+            try {
+                RIGHT = U.objectFieldOffset
+                    (Index.class.getDeclaredField("right"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /* ---------------- Head nodes -------------- */
+
+    /**
+     * Nodes heading each level keep track of their level.
+     */
+    static final class HeadIndex<K,V> extends Index<K,V> {
+        final int level;
+        HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
+            super(node, down, right);
+            this.level = level;
+        }
+    }
+
+    /* ---------------- Comparison utilities -------------- */
+
+    /**
+     * Compares using comparator or natural ordering if null.
+     * Called only by methods that have performed required type checks.
+     */
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    static final int cpr(Comparator c, Object x, Object y) {
+        return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
+    }
+
+    /* ---------------- Traversal -------------- */
+
+    /**
+     * Returns a base-level node with key strictly less than given key,
+     * or the base-level header if there is no such node.  Also
+     * unlinks indexes to deleted nodes found along the way.  Callers
+     * rely on this side-effect of clearing indices to deleted nodes.
+     * @param key the key
+     * @return a predecessor of key
+     */
+    private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
+        if (key == null)
+            throw new NullPointerException(); // don't postpone errors
+        for (;;) {
+            for (Index<K,V> q = head, r = q.right, d;;) {
+                if (r != null) {
+                    Node<K,V> n = r.node;
+                    K k = n.key;
+                    if (n.value == null) {
+                        if (!q.unlink(r))
+                            break;           // restart
+                        r = q.right;         // reread r
+                        continue;
+                    }
+                    if (cpr(cmp, key, k) > 0) {
+                        q = r;
+                        r = r.right;
+                        continue;
+                    }
+                }
+                if ((d = q.down) == null)
+                    return q.node;
+                q = d;
+                r = d.right;
+            }
+        }
+    }
+
+    /**
+     * Returns node holding key or null if no such, clearing out any
+     * deleted nodes seen along the way.  Repeatedly traverses at
+     * base-level looking for key starting at predecessor returned
+     * from findPredecessor, processing base-level deletions as
+     * encountered. Some callers rely on this side-effect of clearing
+     * deleted nodes.
+     *
+     * Restarts occur, at traversal step centered on node n, if:
+     *
+     *   (1) After reading n's next field, n is no longer assumed
+     *       predecessor b's current successor, which means that
+     *       we don't have a consistent 3-node snapshot and so cannot
+     *       unlink any subsequent deleted nodes encountered.
+     *
+     *   (2) n's value field is null, indicating n is deleted, in
+     *       which case we help out an ongoing structural deletion
+     *       before retrying.  Even though there are cases where such
+     *       unlinking doesn't require restart, they aren't sorted out
+     *       here because doing so would not usually outweigh cost of
+     *       restarting.
+     *
+     *   (3) n is a marker or n's predecessor's value field is null,
+     *       indicating (among other possibilities) that
+     *       findPredecessor returned a deleted node. We can't unlink
+     *       the node because we don't know its predecessor, so rely
+     *       on another call to findPredecessor to notice and return
+     *       some earlier predecessor, which it will do. This check is
+     *       only strictly needed at beginning of loop, (and the
+     *       b.value check isn't strictly needed at all) but is done
+     *       each iteration to help avoid contention with other
+     *       threads by callers that will fail to be able to change
+     *       links, and so will retry anyway.
+     *
+     * The traversal loops in doPut, doRemove, and findNear all
+     * include the same three kinds of checks. And specialized
+     * versions appear in findFirst, and findLast and their variants.
+     * They can't easily share code because each uses the reads of
+     * fields held in locals occurring in the orders they were
+     * performed.
+     *
+     * @param key the key
+     * @return node holding key, or null if no such
+     */
+    private Node<K,V> findNode(Object key) {
+        if (key == null)
+            throw new NullPointerException(); // don't postpone errors
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                // inconsistent read
+                    break;
+                if ((v = n.value) == null) {    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)  // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) == 0)
+                    return n;
+                if (c < 0)
+                    break outer;
+                b = n;
+                n = f;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Gets value for key. Almost the same as findNode, but returns
+     * the found value (to avoid retries during re-reads)
+     *
+     * @param key the key
+     * @return the value, or null if absent
+     */
+    private V doGet(Object key) {
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                // inconsistent read
+                    break;
+                if ((v = n.value) == null) {    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)  // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) == 0) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    return vv;
+                }
+                if (c < 0)
+                    break outer;
+                b = n;
+                n = f;
+            }
+        }
+        return null;
+    }
+
+    /* ---------------- Insertion -------------- */
+
+    /**
+     * Main insertion method.  Adds element if not present, or
+     * replaces value if present and onlyIfAbsent is false.
+     * @param key the key
+     * @param value the value that must be associated with key
+     * @param onlyIfAbsent if should not insert if already present
+     * @return the old value, or null if newly inserted
+     */
+    private V doPut(K key, V value, boolean onlyIfAbsent) {
+        Node<K,V> z;             // added node
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                if (n != null) {
+                    Object v; int c;
+                    Node<K,V> f = n.next;
+                    if (n != b.next)               // inconsistent read
+                        break;
+                    if ((v = n.value) == null) {   // n is deleted
+                        n.helpDelete(b, f);
+                        break;
+                    }
+                    if (b.value == null || v == n) // b is deleted
+                        break;
+                    if ((c = cpr(cmp, key, n.key)) > 0) {
+                        b = n;
+                        n = f;
+                        continue;
+                    }
+                    if (c == 0) {
+                        if (onlyIfAbsent || n.casValue(v, value)) {
+                            @SuppressWarnings("unchecked") V vv = (V)v;
+                            return vv;
+                        }
+                        break; // restart if lost race to replace value
+                    }
+                    // else c < 0; fall through
+                }
+
+                z = new Node<K,V>(key, value, n);
+                if (!b.casNext(n, z))
+                    break;         // restart if lost race to append to b
+                break outer;
+            }
+        }
+
+        int rnd = ThreadLocalRandom.nextSecondarySeed();
+        if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
+            int level = 1, max;
+            while (((rnd >>>= 1) & 1) != 0)
+                ++level;
+            Index<K,V> idx = null;
+            HeadIndex<K,V> h = head;
+            if (level <= (max = h.level)) {
+                for (int i = 1; i <= level; ++i)
+                    idx = new Index<K,V>(z, idx, null);
+            }
+            else { // try to grow by one level
+                level = max + 1; // hold in array and later pick the one to use
+                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
+                    (Index<K,V>[])new Index<?,?>[level+1];
+                for (int i = 1; i <= level; ++i)
+                    idxs[i] = idx = new Index<K,V>(z, idx, null);
+                for (;;) {
+                    h = head;
+                    int oldLevel = h.level;
+                    if (level <= oldLevel) // lost race to add level
+                        break;
+                    HeadIndex<K,V> newh = h;
+                    Node<K,V> oldbase = h.node;
+                    for (int j = oldLevel+1; j <= level; ++j)
+                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
+                    if (casHead(h, newh)) {
+                        h = newh;
+                        idx = idxs[level = oldLevel];
+                        break;
+                    }
+                }
+            }
+            // find insertion points and splice in
+            splice: for (int insertionLevel = level;;) {
+                int j = h.level;
+                for (Index<K,V> q = h, r = q.right, t = idx;;) {
+                    if (q == null || t == null)
+                        break splice;
+                    if (r != null) {
+                        Node<K,V> n = r.node;
+                        // compare before deletion check avoids needing recheck
+                        int c = cpr(cmp, key, n.key);
+                        if (n.value == null) {
+                            if (!q.unlink(r))
+                                break;
+                            r = q.right;
+                            continue;
+                        }
+                        if (c > 0) {
+                            q = r;
+                            r = r.right;
+                            continue;
+                        }
+                    }
+
+                    if (j == insertionLevel) {
+                        if (!q.link(r, t))
+                            break; // restart
+                        if (t.node.value == null) {
+                            findNode(key);
+                            break splice;
+                        }
+                        if (--insertionLevel == 0)
+                            break splice;
+                    }
+
+                    if (--j >= insertionLevel && j < level)
+                        t = t.down;
+                    q = q.down;
+                    r = q.right;
+                }
+            }
+        }
+        return null;
+    }
+
+    /* ---------------- Deletion -------------- */
+
+    /**
+     * Main deletion method. Locates node, nulls value, appends a
+     * deletion marker, unlinks predecessor, removes associated index
+     * nodes, and possibly reduces head index level.
+     *
+     * Index nodes are cleared out simply by calling findPredecessor.
+     * which unlinks indexes to deleted nodes found along path to key,
+     * which will include the indexes to this node.  This is done
+     * unconditionally. We can't check beforehand whether there are
+     * index nodes because it might be the case that some or all
+     * indexes hadn't been inserted yet for this node during initial
+     * search for it, and we'd like to ensure lack of garbage
+     * retention, so must call to be sure.
+     *
+     * @param key the key
+     * @param value if non-null, the value that must be
+     * associated with key
+     * @return the node, or null if not found
+     */
+    final V doRemove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        Comparator<? super K> cmp = comparator;
+        outer: for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v; int c;
+                if (n == null)
+                    break outer;
+                Node<K,V> f = n.next;
+                if (n != b.next)                    // inconsistent read
+                    break;
+                if ((v = n.value) == null) {        // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                if ((c = cpr(cmp, key, n.key)) < 0)
+                    break outer;
+                if (c > 0) {
+                    b = n;
+                    n = f;
+                    continue;
+                }
+                if (value != null && !value.equals(v))
+                    break outer;
+                if (!n.casValue(v, null))
+                    break;
+                if (!n.appendMarker(f) || !b.casNext(n, f))
+                    findNode(key);                  // retry via findNode
+                else {
+                    findPredecessor(key, cmp);      // clean index
+                    if (head.right == null)
+                        tryReduceLevel();
+                }
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return vv;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Possibly reduce head level if it has no nodes.  This method can
+     * (rarely) make mistakes, in which case levels can disappear even
+     * though they are about to contain index nodes. This impacts
+     * performance, not correctness.  To minimize mistakes as well as
+     * to reduce hysteresis, the level is reduced by one only if the
+     * topmost three levels look empty. Also, if the removed level
+     * looks non-empty after CAS, we try to change it back quick
+     * before anyone notices our mistake! (This trick works pretty
+     * well because this method will practically never make mistakes
+     * unless current thread stalls immediately before first CAS, in
+     * which case it is very unlikely to stall again immediately
+     * afterwards, so will recover.)
+     *
+     * We put up with all this rather than just let levels grow
+     * because otherwise, even a small map that has undergone a large
+     * number of insertions and removals will have a lot of levels,
+     * slowing down access more than would an occasional unwanted
+     * reduction.
+     */
+    private void tryReduceLevel() {
+        HeadIndex<K,V> h = head;
+        HeadIndex<K,V> d;
+        HeadIndex<K,V> e;
+        if (h.level > 3 &&
+            (d = (HeadIndex<K,V>)h.down) != null &&
+            (e = (HeadIndex<K,V>)d.down) != null &&
+            e.right == null &&
+            d.right == null &&
+            h.right == null &&
+            casHead(h, d) && // try to set
+            h.right != null) // recheck
+            casHead(d, h);   // try to backout
+    }
+
+    /* ---------------- Finding and removing first element -------------- */
+
+    /**
+     * Specialized variant of findNode to get first valid node.
+     * @return first node or null if empty
+     */
+    final Node<K,V> findFirst() {
+        for (Node<K,V> b, n;;) {
+            if ((n = (b = head.node).next) == null)
+                return null;
+            if (n.value != null)
+                return n;
+            n.helpDelete(b, n.next);
+        }
+    }
+
+    /**
+     * Removes first entry; returns its snapshot.
+     * @return null if empty, else snapshot of first entry
+     */
+    private Map.Entry<K,V> doRemoveFirstEntry() {
+        for (Node<K,V> b, n;;) {
+            if ((n = (b = head.node).next) == null)
+                return null;
+            Node<K,V> f = n.next;
+            if (n != b.next)
+                continue;
+            Object v = n.value;
+            if (v == null) {
+                n.helpDelete(b, f);
+                continue;
+            }
+            if (!n.casValue(v, null))
+                continue;
+            if (!n.appendMarker(f) || !b.casNext(n, f))
+                findFirst(); // retry
+            clearIndexToFirst();
+            @SuppressWarnings("unchecked") V vv = (V)v;
+            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
+        }
+    }
+
+    /**
+     * Clears out index nodes associated with deleted first entry.
+     */
+    private void clearIndexToFirst() {
+        for (;;) {
+            for (Index<K,V> q = head;;) {
+                Index<K,V> r = q.right;
+                if (r != null && r.indexesDeletedNode() && !q.unlink(r))
+                    break;
+                if ((q = q.down) == null) {
+                    if (head.right == null)
+                        tryReduceLevel();
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes last entry; returns its snapshot.
+     * Specialized variant of doRemove.
+     * @return null if empty, else snapshot of last entry
+     */
+    private Map.Entry<K,V> doRemoveLastEntry() {
+        for (;;) {
+            Node<K,V> b = findPredecessorOfLast();
+            Node<K,V> n = b.next;
+            if (n == null) {
+                if (b.isBaseHeader())               // empty
+                    return null;
+                else
+                    continue; // all b's successors are deleted; retry
+            }
+            for (;;) {
+                Node<K,V> f = n.next;
+                if (n != b.next)                    // inconsistent read
+                    break;
+                Object v = n.value;
+                if (v == null) {                    // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                if (f != null) {
+                    b = n;
+                    n = f;
+                    continue;
+                }
+                if (!n.casValue(v, null))
+                    break;
+                K key = n.key;
+                if (!n.appendMarker(f) || !b.casNext(n, f))
+                    findNode(key);                  // retry via findNode
+                else {                              // clean index
+                    findPredecessor(key, comparator);
+                    if (head.right == null)
+                        tryReduceLevel();
+                }
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
+            }
+        }
+    }
+
+    /* ---------------- Finding and removing last element -------------- */
+
+    /**
+     * Specialized version of find to get last valid node.
+     * @return last node or null if empty
+     */
+    final Node<K,V> findLast() {
+        /*
+         * findPredecessor can't be used to traverse index level
+         * because this doesn't use comparisons.  So traversals of
+         * both levels are folded together.
+         */
+        Index<K,V> q = head;
+        for (;;) {
+            Index<K,V> d, r;
+            if ((r = q.right) != null) {
+                if (r.indexesDeletedNode()) {
+                    q.unlink(r);
+                    q = head; // restart
+                }
+                else
+                    q = r;
+            } else if ((d = q.down) != null) {
+                q = d;
+            } else {
+                for (Node<K,V> b = q.node, n = b.next;;) {
+                    if (n == null)
+                        return b.isBaseHeader() ? null : b;
+                    Node<K,V> f = n.next;            // inconsistent read
+                    if (n != b.next)
+                        break;
+                    Object v = n.value;
+                    if (v == null) {                 // n is deleted
+                        n.helpDelete(b, f);
+                        break;
+                    }
+                    if (b.value == null || v == n)      // b is deleted
+                        break;
+                    b = n;
+                    n = f;
+                }
+                q = head; // restart
+            }
+        }
+    }
+
+    /**
+     * Specialized variant of findPredecessor to get predecessor of last
+     * valid node.  Needed when removing the last entry.  It is possible
+     * that all successors of returned node will have been deleted upon
+     * return, in which case this method can be retried.
+     * @return likely predecessor of last node
+     */
+    private Node<K,V> findPredecessorOfLast() {
+        for (;;) {
+            for (Index<K,V> q = head;;) {
+                Index<K,V> d, r;
+                if ((r = q.right) != null) {
+                    if (r.indexesDeletedNode()) {
+                        q.unlink(r);
+                        break;    // must restart
+                    }
+                    // proceed as far across as possible without overshooting
+                    if (r.node.next != null) {
+                        q = r;
+                        continue;
+                    }
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else
+                    return q.node;
+            }
+        }
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    // Control values OR'ed as arguments to findNear
+
+    private static final int EQ = 1;
+    private static final int LT = 2;
+    private static final int GT = 0; // Actually checked as !LT
+
+    /**
+     * Utility for ceiling, floor, lower, higher methods.
+     * @param key the key
+     * @param rel the relation -- OR'ed combination of EQ, LT, GT
+     * @return nearest node fitting relation, or null if no such
+     */
+    final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
+        if (key == null)
+            throw new NullPointerException();
+        for (;;) {
+            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
+                Object v;
+                if (n == null)
+                    return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
+                Node<K,V> f = n.next;
+                if (n != b.next)                  // inconsistent read
+                    break;
+                if ((v = n.value) == null) {      // n is deleted
+                    n.helpDelete(b, f);
+                    break;
+                }
+                if (b.value == null || v == n)      // b is deleted
+                    break;
+                int c = cpr(cmp, key, n.key);
+                if ((c == 0 && (rel & EQ) != 0) ||
+                    (c <  0 && (rel & LT) == 0))
+                    return n;
+                if ( c <= 0 && (rel & LT) != 0)
+                    return b.isBaseHeader() ? null : b;
+                b = n;
+                n = f;
+            }
+        }
+    }
+
+    /**
+     * Returns SimpleImmutableEntry for results of findNear.
+     * @param key the key
+     * @param rel the relation -- OR'ed combination of EQ, LT, GT
+     * @return Entry fitting relation, or null if no such
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
+        Comparator<? super K> cmp = comparator;
+        for (;;) {
+            Node<K,V> n = findNear(key, rel, cmp);
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
+    }
+
+    /* ---------------- Constructors -------------- */
+
+    /**
+     * Constructs a new, empty map, sorted according to the
+     * {@linkplain Comparable natural ordering} of the keys.
+     */
+    public ConcurrentSkipListMap() {
+        this.comparator = null;
+        initialize();
+    }
+
+    /**
+     * Constructs a new, empty map, sorted according to the specified
+     * comparator.
+     *
+     * @param comparator the comparator that will be used to order this map.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the keys will be used.
+     */
+    public ConcurrentSkipListMap(Comparator<? super K> comparator) {
+        this.comparator = comparator;
+        initialize();
+    }
+
+    /**
+     * Constructs a new map containing the same mappings as the given map,
+     * sorted according to the {@linkplain Comparable natural ordering} of
+     * the keys.
+     *
+     * @param  m the map whose mappings are to be placed in this map
+     * @throws ClassCastException if the keys in {@code m} are not
+     *         {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified map or any of its keys
+     *         or values are null
+     */
+    public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
+        this.comparator = null;
+        initialize();
+        putAll(m);
+    }
+
+    /**
+     * Constructs a new map containing the same mappings and using the
+     * same ordering as the specified sorted map.
+     *
+     * @param m the sorted map whose mappings are to be placed in this
+     *        map, and whose comparator is to be used to sort this map
+     * @throws NullPointerException if the specified sorted map or any of
+     *         its keys or values are null
+     */
+    public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
+        this.comparator = m.comparator();
+        initialize();
+        buildFromSorted(m);
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ConcurrentSkipListMap}
+     * instance. (The keys and values themselves are not cloned.)
+     *
+     * @return a shallow copy of this map
+     */
+    public ConcurrentSkipListMap<K,V> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListMap<K,V> clone =
+                (ConcurrentSkipListMap<K,V>) super.clone();
+            clone.initialize();
+            clone.buildFromSorted(this);
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Streamlined bulk insertion to initialize from elements of
+     * given sorted map.  Call only from constructor or clone
+     * method.
+     */
+    private void buildFromSorted(SortedMap<K, ? extends V> map) {
+        if (map == null)
+            throw new NullPointerException();
+
+        HeadIndex<K,V> h = head;
+        Node<K,V> basepred = h.node;
+
+        // Track the current rightmost node at each level. Uses an
+        // ArrayList to avoid committing to initial or maximum level.
+        ArrayList<Index<K,V>> preds = new ArrayList<>();
+
+        // initialize
+        for (int i = 0; i <= h.level; ++i)
+            preds.add(null);
+        Index<K,V> q = h;
+        for (int i = h.level; i > 0; --i) {
+            preds.set(i, q);
+            q = q.down;
+        }
+
+        Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
+            map.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<? extends K, ? extends V> e = it.next();
+            int rnd = ThreadLocalRandom.current().nextInt();
+            int j = 0;
+            if ((rnd & 0x80000001) == 0) {
+                do {
+                    ++j;
+                } while (((rnd >>>= 1) & 1) != 0);
+                if (j > h.level) j = h.level + 1;
+            }
+            K k = e.getKey();
+            V v = e.getValue();
+            if (k == null || v == null)
+                throw new NullPointerException();
+            Node<K,V> z = new Node<K,V>(k, v, null);
+            basepred.next = z;
+            basepred = z;
+            if (j > 0) {
+                Index<K,V> idx = null;
+                for (int i = 1; i <= j; ++i) {
+                    idx = new Index<K,V>(z, idx, null);
+                    if (i > h.level)
+                        h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+                    if (i < preds.size()) {
+                        preds.get(i).right = idx;
+                        preds.set(i, idx);
+                    } else
+                        preds.add(idx);
+                }
+            }
+        }
+        head = h;
+    }
+
+    /* ---------------- Serialization -------------- */
+
+    /**
+     * Saves this map to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The key (Object) and value (Object) for each
+     * key-value mapping represented by the map, followed by
+     * {@code null}. The key-value mappings are emitted in key-order
+     * (as determined by the Comparator, or by the keys' natural
+     * ordering if no Comparator).
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        // Write out the Comparator and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out keys and values (alternating)
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v = n.getValidValue();
+            if (v != null) {
+                s.writeObject(n.key);
+                s.writeObject(v);
+            }
+        }
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this map from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    @SuppressWarnings("unchecked")
+    private void readObject(final java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in the Comparator and any hidden stuff
+        s.defaultReadObject();
+        // Reset transients
+        initialize();
+
+        /*
+         * This is nearly identical to buildFromSorted, but is
+         * distinct because readObject calls can't be nicely adapted
+         * as the kind of iterator needed by buildFromSorted. (They
+         * can be, but doing so requires type cheats and/or creation
+         * of adapter classes.) It is simpler to just adapt the code.
+         */
+
+        HeadIndex<K,V> h = head;
+        Node<K,V> basepred = h.node;
+        ArrayList<Index<K,V>> preds = new ArrayList<>();
+        for (int i = 0; i <= h.level; ++i)
+            preds.add(null);
+        Index<K,V> q = h;
+        for (int i = h.level; i > 0; --i) {
+            preds.set(i, q);
+            q = q.down;
+        }
+
+        for (;;) {
+            Object k = s.readObject();
+            if (k == null)
+                break;
+            Object v = s.readObject();
+            if (v == null)
+                throw new NullPointerException();
+            K key = (K) k;
+            V val = (V) v;
+            int rnd = ThreadLocalRandom.current().nextInt();
+            int j = 0;
+            if ((rnd & 0x80000001) == 0) {
+                do {
+                    ++j;
+                } while (((rnd >>>= 1) & 1) != 0);
+                if (j > h.level) j = h.level + 1;
+            }
+            Node<K,V> z = new Node<K,V>(key, val, null);
+            basepred.next = z;
+            basepred = z;
+            if (j > 0) {
+                Index<K,V> idx = null;
+                for (int i = 1; i <= j; ++i) {
+                    idx = new Index<K,V>(z, idx, null);
+                    if (i > h.level)
+                        h = new HeadIndex<K,V>(h.node, h, idx, i);
+
+                    if (i < preds.size()) {
+                        preds.get(i).right = idx;
+                        preds.set(i, idx);
+                    } else
+                        preds.add(idx);
+                }
+            }
+        }
+        head = h;
+    }
+
+    /* ------ Map API methods ------ */
+
+    /**
+     * Returns {@code true} if this map contains a mapping for the specified
+     * key.
+     *
+     * @param key key whose presence in this map is to be tested
+     * @return {@code true} if this map contains a mapping for the specified key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean containsKey(Object key) {
+        return doGet(key) != null;
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or {@code null} if this map contains no mapping for the key.
+     *
+     * <p>More formally, if this map contains a mapping from a key
+     * {@code k} to a value {@code v} such that {@code key} compares
+     * equal to {@code k} according to the map's ordering, then this
+     * method returns {@code v}; otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public V get(Object key) {
+        return doGet(key);
+    }
+
+    /**
+     * Returns the value to which the specified key is mapped,
+     * or the given defaultValue if this map contains no mapping for the key.
+     *
+     * @param key the key
+     * @param defaultValue the value to return if this map contains
+     * no mapping for the given key
+     * @return the mapping for the key, if present; else the defaultValue
+     * @throws NullPointerException if the specified key is null
+     * @since 1.8
+     */
+    public V getOrDefault(Object key, V defaultValue) {
+        V v;
+        return (v = doGet(key)) == null ? defaultValue : v;
+    }
+
+    /**
+     * Associates the specified value with the specified key in this map.
+     * If the map previously contained a mapping for the key, the old
+     * value is replaced.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value value to be associated with the specified key
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V put(K key, V value) {
+        if (value == null)
+            throw new NullPointerException();
+        return doPut(key, value, false);
+    }
+
+    /**
+     * Removes the mapping for the specified key from this map if present.
+     *
+     * @param  key key for which mapping should be removed
+     * @return the previous value associated with the specified key, or
+     *         {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public V remove(Object key) {
+        return doRemove(key, null);
+    }
+
+    /**
+     * Returns {@code true} if this map maps one or more keys to the
+     * specified value.  This operation requires time linear in the
+     * map size. Additionally, it is possible for the map to change
+     * during execution of this method, in which case the returned
+     * result may be inaccurate.
+     *
+     * @param value value whose presence in this map is to be tested
+     * @return {@code true} if a mapping to {@code value} exists;
+     *         {@code false} otherwise
+     * @throws NullPointerException if the specified value is null
+     */
+    public boolean containsValue(Object value) {
+        if (value == null)
+            throw new NullPointerException();
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v = n.getValidValue();
+            if (v != null && value.equals(v))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns the number of key-value mappings in this map.  If this map
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these maps, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this map
+     */
+    public int size() {
+        long count = 0;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            if (n.getValidValue() != null)
+                ++count;
+        }
+        return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+    }
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     * @return {@code true} if this map contains no key-value mappings
+     */
+    public boolean isEmpty() {
+        return findFirst() == null;
+    }
+
+    /**
+     * Removes all of the mappings from this map.
+     */
+    public void clear() {
+        initialize();
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this map unless {@code null}.  The function
+     * is <em>NOT</em> guaranteed to be applied once atomically only
+     * if the value is not present.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     *         the specified key, or null if the computed value is null
+     * @throws NullPointerException if the specified key is null
+     *         or the mappingFunction is null
+     * @since 1.8
+     */
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (key == null || mappingFunction == null)
+            throw new NullPointerException();
+        V v, p, r;
+        if ((v = doGet(key)) == null &&
+            (r = mappingFunction.apply(key)) != null)
+            v = (p = doPut(key, r, true)) == null ? r : p;
+        return v;
+    }
+
+    /**
+     * If the value for the specified key is present, attempts to
+     * compute a new mapping given the key and its current mapped
+     * value. The function is <em>NOT</em> guaranteed to be applied
+     * once atomically.
+     *
+     * @param key key with which a value may be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        Node<K,V> n; Object v;
+        while ((n = findNode(key)) != null) {
+            if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                V r = remappingFunction.apply(key, vv);
+                if (r != null) {
+                    if (n.casValue(vv, r))
+                        return r;
+                }
+                else if (doRemove(key, vv) != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Attempts to compute a mapping for the specified key and its
+     * current mapped value (or {@code null} if there is no current
+     * mapping). The function is <em>NOT</em> guaranteed to be applied
+     * once atomically.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param remappingFunction the function to compute a value
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (key == null || remappingFunction == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v; V r;
+            if ((n = findNode(key)) == null) {
+                if ((r = remappingFunction.apply(key, null)) == null)
+                    break;
+                if (doPut(key, r, true) == null)
+                    return r;
+            }
+            else if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                if ((r = remappingFunction.apply(key, vv)) != null) {
+                    if (n.casValue(vv, r))
+                        return r;
+                }
+                else if (doRemove(key, vv) != null)
+                    break;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * If the specified key is not already associated with a value,
+     * associates it with the given value.  Otherwise, replaces the
+     * value with the results of the given remapping function, or
+     * removes if {@code null}. The function is <em>NOT</em>
+     * guaranteed to be applied once atomically.
+     *
+     * @param key key with which the specified value is to be associated
+     * @param value the value to use if absent
+     * @param remappingFunction the function to recompute a value if present
+     * @return the new value associated with the specified key, or null if none
+     * @throws NullPointerException if the specified key or value is null
+     *         or the remappingFunction is null
+     * @since 1.8
+     */
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (key == null || value == null || remappingFunction == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v; V r;
+            if ((n = findNode(key)) == null) {
+                if (doPut(key, value, true) == null)
+                    return value;
+            }
+            else if ((v = n.value) != null) {
+                @SuppressWarnings("unchecked") V vv = (V) v;
+                if ((r = remappingFunction.apply(vv, value)) != null) {
+                    if (n.casValue(vv, r))
+                        return r;
+                }
+                else if (doRemove(key, vv) != null)
+                    return null;
+            }
+        }
+    }
+
+    /* ---------------- View methods -------------- */
+
+    /*
+     * Note: Lazy initialization works for views because view classes
+     * are stateless/immutable so it doesn't matter wrt correctness if
+     * more than one is created (which will only rarely happen).  Even
+     * so, the following idiom conservatively ensures that the method
+     * returns the one it created if it does so, not one created by
+     * another racing thread.
+     */
+
+    /**
+     * Returns a {@link NavigableSet} view of the keys contained in this map.
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll}, and {@code clear}
+     * operations.  It does not support the {@code add} or {@code addAll}
+     * operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>This method is equivalent to method {@code navigableKeySet}.
+     *
+     * @return a navigable set view of the keys in this map
+     */
+    public NavigableSet<K> keySet() {
+        KeySet<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<>(this));
+    }
+
+    public NavigableSet<K> navigableKeySet() {
+        KeySet<K,V> ks = keySet;
+        return (ks != null) ? ks : (keySet = new KeySet<>(this));
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collections's spliterator additionally
+     * reports {@link Spliterator#CONCURRENT}, {@link Spliterator#NONNULL} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * order of the corresponding keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll} and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     */
+    public Collection<V> values() {
+        Values<K,V> vs = values;
+        return (vs != null) ? vs : (values = new Values<>(this));
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     *
+     * <p>The set's iterator returns the entries in ascending key order.  The
+     * set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED}, with an encounter order that is ascending
+     * key order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  The set supports element
+     * removal, which removes the corresponding mapping from the map,
+     * via the {@code Iterator.remove}, {@code Set.remove},
+     * {@code removeAll}, {@code retainAll} and {@code clear}
+     * operations.  It does not support the {@code add} or
+     * {@code addAll} operations.
+     *
+     * <p>The view's iterators and spliterators are
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Map.Entry} elements traversed by the {@code iterator}
+     * or {@code spliterator} do <em>not</em> support the {@code setValue}
+     * operation.
+     *
+     * @return a set view of the mappings contained in this map,
+     *         sorted in ascending key order
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        EntrySet<K,V> es = entrySet;
+        return (es != null) ? es : (entrySet = new EntrySet<K,V>(this));
+    }
+
+    public ConcurrentNavigableMap<K,V> descendingMap() {
+        ConcurrentNavigableMap<K,V> dm = descendingMap;
+        return (dm != null) ? dm : (descendingMap = new SubMap<K,V>
+                                    (this, null, false, null, false, true));
+    }
+
+    public NavigableSet<K> descendingKeySet() {
+        return descendingMap().navigableKeySet();
+    }
+
+    /* ---------------- AbstractMap Overrides -------------- */
+
+    /**
+     * Compares the specified object with this map for equality.
+     * Returns {@code true} if the given object is also a map and the
+     * two maps represent the same mappings.  More formally, two maps
+     * {@code m1} and {@code m2} represent the same mappings if
+     * {@code m1.entrySet().equals(m2.entrySet())}.  This
+     * operation may return misleading results if either map is
+     * concurrently modified during execution of this method.
+     *
+     * @param o object to be compared for equality with this map
+     * @return {@code true} if the specified object is equal to this map
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof Map))
+            return false;
+        Map<?,?> m = (Map<?,?>) o;
+        try {
+            for (Map.Entry<K,V> e : this.entrySet())
+                if (! e.getValue().equals(m.get(e.getKey())))
+                    return false;
+            for (Map.Entry<?,?> e : m.entrySet()) {
+                Object k = e.getKey();
+                Object v = e.getValue();
+                if (k == null || v == null || !v.equals(get(k)))
+                    return false;
+            }
+            return true;
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /* ------ ConcurrentMap API methods ------ */
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V putIfAbsent(K key, V value) {
+        if (value == null)
+            throw new NullPointerException();
+        return doPut(key, value, true);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key is null
+     */
+    public boolean remove(Object key, Object value) {
+        if (key == null)
+            throw new NullPointerException();
+        return value != null && doRemove(key, value) != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if any of the arguments are null
+     */
+    public boolean replace(K key, V oldValue, V newValue) {
+        if (key == null || oldValue == null || newValue == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v;
+            if ((n = findNode(key)) == null)
+                return false;
+            if ((v = n.value) != null) {
+                if (!oldValue.equals(v))
+                    return false;
+                if (n.casValue(v, newValue))
+                    return true;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return the previous value associated with the specified key,
+     *         or {@code null} if there was no mapping for the key
+     * @throws ClassCastException if the specified key cannot be compared
+     *         with the keys currently in the map
+     * @throws NullPointerException if the specified key or value is null
+     */
+    public V replace(K key, V value) {
+        if (key == null || value == null)
+            throw new NullPointerException();
+        for (;;) {
+            Node<K,V> n; Object v;
+            if ((n = findNode(key)) == null)
+                return null;
+            if ((v = n.value) != null && n.casValue(v, value)) {
+                @SuppressWarnings("unchecked") V vv = (V)v;
+                return vv;
+            }
+        }
+    }
+
+    /* ------ SortedMap API methods ------ */
+
+    public Comparator<? super K> comparator() {
+        return comparator;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K firstKey() {
+        Node<K,V> n = findFirst();
+        if (n == null)
+            throw new NoSuchElementException();
+        return n.key;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public K lastKey() {
+        Node<K,V> n = findLast();
+        if (n == null)
+            throw new NoSuchElementException();
+        return n.key;
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> subMap(K fromKey,
+                                              boolean fromInclusive,
+                                              K toKey,
+                                              boolean toInclusive) {
+        if (fromKey == null || toKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, fromKey, fromInclusive, toKey, toInclusive, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> headMap(K toKey,
+                                               boolean inclusive) {
+        if (toKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, null, false, toKey, inclusive, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> tailMap(K fromKey,
+                                               boolean inclusive) {
+        if (fromKey == null)
+            throw new NullPointerException();
+        return new SubMap<K,V>
+            (this, fromKey, inclusive, null, false, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} or {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey) {
+        return subMap(fromKey, true, toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> headMap(K toKey) {
+        return headMap(toKey, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromKey} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public ConcurrentNavigableMap<K,V> tailMap(K fromKey) {
+        return tailMap(fromKey, true);
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * strictly less than the given key, or {@code null} if there is
+     * no such key. The returned entry does <em>not</em> support the
+     * {@code Entry.setValue} method.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> lowerEntry(K key) {
+        return getNear(key, LT);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K lowerKey(K key) {
+        Node<K,V> n = findNear(key, LT, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the greatest key
+     * less than or equal to the given key, or {@code null} if there
+     * is no such key. The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     *
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> floorEntry(K key) {
+        return getNear(key, LT|EQ);
+    }
+
+    /**
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K floorKey(K key) {
+        Node<K,V> n = findNear(key, LT|EQ, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * greater than or equal to the given key, or {@code null} if
+     * there is no such entry. The returned entry does <em>not</em>
+     * support the {@code Entry.setValue} method.
+     *
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> ceilingEntry(K key) {
+        return getNear(key, GT|EQ);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K ceilingKey(K key) {
+        Node<K,V> n = findNear(key, GT|EQ, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least key
+     * strictly greater than the given key, or {@code null} if there
+     * is no such key. The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     *
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public Map.Entry<K,V> higherEntry(K key) {
+        return getNear(key, GT);
+    }
+
+    /**
+     * @param key the key
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified key is null
+     */
+    public K higherKey(K key) {
+        Node<K,V> n = findNear(key, GT, comparator);
+        return (n == null) ? null : n.key;
+    }
+
+    /**
+     * Returns a key-value mapping associated with the least
+     * key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> firstEntry() {
+        for (;;) {
+            Node<K,V> n = findFirst();
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
+    }
+
+    /**
+     * Returns a key-value mapping associated with the greatest
+     * key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> lastEntry() {
+        for (;;) {
+            Node<K,V> n = findLast();
+            if (n == null)
+                return null;
+            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
+            if (e != null)
+                return e;
+        }
+    }
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the least key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> pollFirstEntry() {
+        return doRemoveFirstEntry();
+    }
+
+    /**
+     * Removes and returns a key-value mapping associated with
+     * the greatest key in this map, or {@code null} if the map is empty.
+     * The returned entry does <em>not</em> support
+     * the {@code Entry.setValue} method.
+     */
+    public Map.Entry<K,V> pollLastEntry() {
+        return doRemoveLastEntry();
+    }
+
+
+    /* ---------------- Iterators -------------- */
+
+    /**
+     * Base of iterator classes:
+     */
+    abstract class Iter<T> implements Iterator<T> {
+        /** the last node returned by next() */
+        Node<K,V> lastReturned;
+        /** the next node to return from next(); */
+        Node<K,V> next;
+        /** Cache of next value field to maintain weak consistency */
+        V nextValue;
+
+        /** Initializes ascending iterator for entire range. */
+        Iter() {
+            while ((next = findFirst()) != null) {
+                Object x = next.value;
+                if (x != null && x != next) {
+                    @SuppressWarnings("unchecked") V vv = (V)x;
+                    nextValue = vv;
+                    break;
+                }
+            }
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        /** Advances next to higher entry. */
+        final void advance() {
+            if (next == null)
+                throw new NoSuchElementException();
+            lastReturned = next;
+            while ((next = next.next) != null) {
+                Object x = next.value;
+                if (x != null && x != next) {
+                    @SuppressWarnings("unchecked") V vv = (V)x;
+                    nextValue = vv;
+                    break;
+                }
+            }
+        }
+
+        public void remove() {
+            Node<K,V> l = lastReturned;
+            if (l == null)
+                throw new IllegalStateException();
+            // It would not be worth all of the overhead to directly
+            // unlink from here. Using remove is fast enough.
+            ConcurrentSkipListMap.this.remove(l.key);
+            lastReturned = null;
+        }
+
+    }
+
+    final class ValueIterator extends Iter<V> {
+        public V next() {
+            V v = nextValue;
+            advance();
+            return v;
+        }
+    }
+
+    final class KeyIterator extends Iter<K> {
+        public K next() {
+            Node<K,V> n = next;
+            advance();
+            return n.key;
+        }
+    }
+
+    final class EntryIterator extends Iter<Map.Entry<K,V>> {
+        public Map.Entry<K,V> next() {
+            Node<K,V> n = next;
+            V v = nextValue;
+            advance();
+            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+        }
+    }
+
+    /* ---------------- View Classes -------------- */
+
+    /*
+     * View classes are static, delegating to a ConcurrentNavigableMap
+     * to allow use by SubMaps, which outweighs the ugliness of
+     * needing type-tests for Iterator methods.
+     */
+
+    static final <E> List<E> toList(Collection<E> c) {
+        // Using size() here would be a pessimization.
+        ArrayList<E> list = new ArrayList<E>();
+        for (E e : c)
+            list.add(e);
+        return list;
+    }
+
+    static final class KeySet<K,V>
+            extends AbstractSet<K> implements NavigableSet<K> {
+        final ConcurrentNavigableMap<K,V> m;
+        KeySet(ConcurrentNavigableMap<K,V> map) { m = map; }
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsKey(o); }
+        public boolean remove(Object o) { return m.remove(o) != null; }
+        public void clear() { m.clear(); }
+        public K lower(K e) { return m.lowerKey(e); }
+        public K floor(K e) { return m.floorKey(e); }
+        public K ceiling(K e) { return m.ceilingKey(e); }
+        public K higher(K e) { return m.higherKey(e); }
+        public Comparator<? super K> comparator() { return m.comparator(); }
+        public K first() { return m.firstKey(); }
+        public K last() { return m.lastKey(); }
+        public K pollFirst() {
+            Map.Entry<K,V> e = m.pollFirstEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public K pollLast() {
+            Map.Entry<K,V> e = m.pollLastEntry();
+            return (e == null) ? null : e.getKey();
+        }
+        public Iterator<K> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new KeyIterator()
+                : ((SubMap<K,V>)m).new SubMapKeyIterator();
+        }
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof Set))
+                return false;
+            Collection<?> c = (Collection<?>) o;
+            try {
+                return containsAll(c) && c.containsAll(this);
+            } catch (ClassCastException unused) {
+                return false;
+            } catch (NullPointerException unused) {
+                return false;
+            }
+        }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+        public Iterator<K> descendingIterator() {
+            return descendingSet().iterator();
+        }
+        public NavigableSet<K> subSet(K fromElement,
+                                      boolean fromInclusive,
+                                      K toElement,
+                                      boolean toInclusive) {
+            return new KeySet<>(m.subMap(fromElement, fromInclusive,
+                                         toElement,   toInclusive));
+        }
+        public NavigableSet<K> headSet(K toElement, boolean inclusive) {
+            return new KeySet<>(m.headMap(toElement, inclusive));
+        }
+        public NavigableSet<K> tailSet(K fromElement, boolean inclusive) {
+            return new KeySet<>(m.tailMap(fromElement, inclusive));
+        }
+        public NavigableSet<K> subSet(K fromElement, K toElement) {
+            return subSet(fromElement, true, toElement, false);
+        }
+        public NavigableSet<K> headSet(K toElement) {
+            return headSet(toElement, false);
+        }
+        public NavigableSet<K> tailSet(K fromElement) {
+            return tailSet(fromElement, true);
+        }
+        public NavigableSet<K> descendingSet() {
+            return new KeySet<>(m.descendingMap());
+        }
+
+        public Spliterator<K> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).keySpliterator()
+                : ((SubMap<K,V>)m).new SubMapKeyIterator();
+        }
+    }
+
+    static final class Values<K,V> extends AbstractCollection<V> {
+        final ConcurrentNavigableMap<K,V> m;
+        Values(ConcurrentNavigableMap<K,V> map) {
+            m = map;
+        }
+        public Iterator<V> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new ValueIterator()
+                : ((SubMap<K,V>)m).new SubMapValueIterator();
+        }
+        public int size() { return m.size(); }
+        public boolean isEmpty() { return m.isEmpty(); }
+        public boolean contains(Object o) { return m.containsValue(o); }
+        public void clear() { m.clear(); }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+
+        public Spliterator<V> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).valueSpliterator()
+                : ((SubMap<K,V>)m).new SubMapValueIterator();
+        }
+
+        public boolean removeIf(Predicate<? super V> filter) {
+            if (filter == null) throw new NullPointerException();
+            if (m instanceof ConcurrentSkipListMap)
+                return ((ConcurrentSkipListMap<K,V>)m).removeValueIf(filter);
+            // else use iterator
+            Iterator<Map.Entry<K,V>> it =
+                ((SubMap<K,V>)m).new SubMapEntryIterator();
+            boolean removed = false;
+            while (it.hasNext()) {
+                Map.Entry<K,V> e = it.next();
+                V v = e.getValue();
+                if (filter.test(v) && m.remove(e.getKey(), v))
+                    removed = true;
+            }
+            return removed;
+        }
+    }
+
+    static final class EntrySet<K,V> extends AbstractSet<Map.Entry<K,V>> {
+        final ConcurrentNavigableMap<K,V> m;
+        EntrySet(ConcurrentNavigableMap<K,V> map) {
+            m = map;
+        }
+        public Iterator<Map.Entry<K,V>> iterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).new EntryIterator()
+                : ((SubMap<K,V>)m).new SubMapEntryIterator();
+        }
+
+        public boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            V v = m.get(e.getKey());
+            return v != null && v.equals(e.getValue());
+        }
+        public boolean remove(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+            return m.remove(e.getKey(),
+                            e.getValue());
+        }
+        public boolean isEmpty() {
+            return m.isEmpty();
+        }
+        public int size() {
+            return m.size();
+        }
+        public void clear() {
+            m.clear();
+        }
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof Set))
+                return false;
+            Collection<?> c = (Collection<?>) o;
+            try {
+                return containsAll(c) && c.containsAll(this);
+            } catch (ClassCastException unused) {
+                return false;
+            } catch (NullPointerException unused) {
+                return false;
+            }
+        }
+        public Object[] toArray()     { return toList(this).toArray();  }
+        public <T> T[] toArray(T[] a) { return toList(this).toArray(a); }
+
+        public Spliterator<Map.Entry<K,V>> spliterator() {
+            return (m instanceof ConcurrentSkipListMap)
+                ? ((ConcurrentSkipListMap<K,V>)m).entrySpliterator()
+                : ((SubMap<K,V>)m).new SubMapEntryIterator();
+        }
+        public boolean removeIf(Predicate<? super Entry<K,V>> filter) {
+            if (filter == null) throw new NullPointerException();
+            if (m instanceof ConcurrentSkipListMap)
+                return ((ConcurrentSkipListMap<K,V>)m).removeEntryIf(filter);
+            // else use iterator
+            Iterator<Map.Entry<K,V>> it =
+                ((SubMap<K,V>)m).new SubMapEntryIterator();
+            boolean removed = false;
+            while (it.hasNext()) {
+                Map.Entry<K,V> e = it.next();
+                if (filter.test(e) && m.remove(e.getKey(), e.getValue()))
+                    removed = true;
+            }
+            return removed;
+        }
+    }
+
+    /**
+     * Submaps returned by {@link ConcurrentSkipListMap} submap operations
+     * represent a subrange of mappings of their underlying maps.
+     * Instances of this class support all methods of their underlying
+     * maps, differing in that mappings outside their range are ignored,
+     * and attempts to add mappings outside their ranges result in {@link
+     * IllegalArgumentException}.  Instances of this class are constructed
+     * only using the {@code subMap}, {@code headMap}, and {@code tailMap}
+     * methods of their underlying maps.
+     *
+     * @serial include
+     */
+    static final class SubMap<K,V> extends AbstractMap<K,V>
+        implements ConcurrentNavigableMap<K,V>, Cloneable, Serializable {
+        private static final long serialVersionUID = -7647078645895051609L;
+
+        /** Underlying map */
+        final ConcurrentSkipListMap<K,V> m;
+        /** lower bound key, or null if from start */
+        private final K lo;
+        /** upper bound key, or null if to end */
+        private final K hi;
+        /** inclusion flag for lo */
+        private final boolean loInclusive;
+        /** inclusion flag for hi */
+        private final boolean hiInclusive;
+        /** direction */
+        final boolean isDescending;
+
+        // Lazily initialized view holders
+        private transient KeySet<K,V> keySetView;
+        private transient Set<Map.Entry<K,V>> entrySetView;
+        private transient Collection<V> valuesView;
+
+        /**
+         * Creates a new submap, initializing all fields.
+         */
+        SubMap(ConcurrentSkipListMap<K,V> map,
+               K fromKey, boolean fromInclusive,
+               K toKey, boolean toInclusive,
+               boolean isDescending) {
+            Comparator<? super K> cmp = map.comparator;
+            if (fromKey != null && toKey != null &&
+                cpr(cmp, fromKey, toKey) > 0)
+                throw new IllegalArgumentException("inconsistent range");
+            this.m = map;
+            this.lo = fromKey;
+            this.hi = toKey;
+            this.loInclusive = fromInclusive;
+            this.hiInclusive = toInclusive;
+            this.isDescending = isDescending;
+        }
+
+        /* ----------------  Utilities -------------- */
+
+        boolean tooLow(Object key, Comparator<? super K> cmp) {
+            int c;
+            return (lo != null && ((c = cpr(cmp, key, lo)) < 0 ||
+                                   (c == 0 && !loInclusive)));
+        }
+
+        boolean tooHigh(Object key, Comparator<? super K> cmp) {
+            int c;
+            return (hi != null && ((c = cpr(cmp, key, hi)) > 0 ||
+                                   (c == 0 && !hiInclusive)));
+        }
+
+        boolean inBounds(Object key, Comparator<? super K> cmp) {
+            return !tooLow(key, cmp) && !tooHigh(key, cmp);
+        }
+
+        void checkKeyBounds(K key, Comparator<? super K> cmp) {
+            if (key == null)
+                throw new NullPointerException();
+            if (!inBounds(key, cmp))
+                throw new IllegalArgumentException("key out of range");
+        }
+
+        /**
+         * Returns true if node key is less than upper bound of range.
+         */
+        boolean isBeforeEnd(ConcurrentSkipListMap.Node<K,V> n,
+                            Comparator<? super K> cmp) {
+            if (n == null)
+                return false;
+            if (hi == null)
+                return true;
+            K k = n.key;
+            if (k == null) // pass by markers and headers
+                return true;
+            int c = cpr(cmp, k, hi);
+            if (c > 0 || (c == 0 && !hiInclusive))
+                return false;
+            return true;
+        }
+
+        /**
+         * Returns lowest node. This node might not be in range, so
+         * most usages need to check bounds.
+         */
+        ConcurrentSkipListMap.Node<K,V> loNode(Comparator<? super K> cmp) {
+            if (lo == null)
+                return m.findFirst();
+            else if (loInclusive)
+                return m.findNear(lo, GT|EQ, cmp);
+            else
+                return m.findNear(lo, GT, cmp);
+        }
+
+        /**
+         * Returns highest node. This node might not be in range, so
+         * most usages need to check bounds.
+         */
+        ConcurrentSkipListMap.Node<K,V> hiNode(Comparator<? super K> cmp) {
+            if (hi == null)
+                return m.findLast();
+            else if (hiInclusive)
+                return m.findNear(hi, LT|EQ, cmp);
+            else
+                return m.findNear(hi, LT, cmp);
+        }
+
+        /**
+         * Returns lowest absolute key (ignoring directionality).
+         */
+        K lowestKey() {
+            Comparator<? super K> cmp = m.comparator;
+            ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+            if (isBeforeEnd(n, cmp))
+                return n.key;
+            else
+                throw new NoSuchElementException();
+        }
+
+        /**
+         * Returns highest absolute key (ignoring directionality).
+         */
+        K highestKey() {
+            Comparator<? super K> cmp = m.comparator;
+            ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+            if (n != null) {
+                K last = n.key;
+                if (inBounds(last, cmp))
+                    return last;
+            }
+            throw new NoSuchElementException();
+        }
+
+        Map.Entry<K,V> lowestEntry() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                if (!isBeforeEnd(n, cmp))
+                    return null;
+                Map.Entry<K,V> e = n.createSnapshot();
+                if (e != null)
+                    return e;
+            }
+        }
+
+        Map.Entry<K,V> highestEntry() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                Map.Entry<K,V> e = n.createSnapshot();
+                if (e != null)
+                    return e;
+            }
+        }
+
+        Map.Entry<K,V> removeLowest() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                Node<K,V> n = loNode(cmp);
+                if (n == null)
+                    return null;
+                K k = n.key;
+                if (!inBounds(k, cmp))
+                    return null;
+                V v = m.doRemove(k, null);
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        Map.Entry<K,V> removeHighest() {
+            Comparator<? super K> cmp = m.comparator;
+            for (;;) {
+                Node<K,V> n = hiNode(cmp);
+                if (n == null)
+                    return null;
+                K k = n.key;
+                if (!inBounds(k, cmp))
+                    return null;
+                V v = m.doRemove(k, null);
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        /**
+         * Submap version of ConcurrentSkipListMap.getNearEntry.
+         */
+        Map.Entry<K,V> getNearEntry(K key, int rel) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // adjust relation for direction
+                if ((rel & LT) == 0)
+                    rel |= LT;
+                else
+                    rel &= ~LT;
+            }
+            if (tooLow(key, cmp))
+                return ((rel & LT) != 0) ? null : lowestEntry();
+            if (tooHigh(key, cmp))
+                return ((rel & LT) != 0) ? highestEntry() : null;
+            for (;;) {
+                Node<K,V> n = m.findNear(key, rel, cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                K k = n.key;
+                V v = n.getValidValue();
+                if (v != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+            }
+        }
+
+        // Almost the same as getNearEntry, except for keys
+        K getNearKey(K key, int rel) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // adjust relation for direction
+                if ((rel & LT) == 0)
+                    rel |= LT;
+                else
+                    rel &= ~LT;
+            }
+            if (tooLow(key, cmp)) {
+                if ((rel & LT) == 0) {
+                    ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                    if (isBeforeEnd(n, cmp))
+                        return n.key;
+                }
+                return null;
+            }
+            if (tooHigh(key, cmp)) {
+                if ((rel & LT) != 0) {
+                    ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
+                    if (n != null) {
+                        K last = n.key;
+                        if (inBounds(last, cmp))
+                            return last;
+                    }
+                }
+                return null;
+            }
+            for (;;) {
+                Node<K,V> n = m.findNear(key, rel, cmp);
+                if (n == null || !inBounds(n.key, cmp))
+                    return null;
+                K k = n.key;
+                V v = n.getValidValue();
+                if (v != null)
+                    return k;
+            }
+        }
+
+        /* ----------------  Map API methods -------------- */
+
+        public boolean containsKey(Object key) {
+            if (key == null) throw new NullPointerException();
+            return inBounds(key, m.comparator) && m.containsKey(key);
+        }
+
+        public V get(Object key) {
+            if (key == null) throw new NullPointerException();
+            return (!inBounds(key, m.comparator)) ? null : m.get(key);
+        }
+
+        public V put(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.put(key, value);
+        }
+
+        public V remove(Object key) {
+            return (!inBounds(key, m.comparator)) ? null : m.remove(key);
+        }
+
+        public int size() {
+            Comparator<? super K> cmp = m.comparator;
+            long count = 0;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                if (n.getValidValue() != null)
+                    ++count;
+            }
+            return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
+        }
+
+        public boolean isEmpty() {
+            Comparator<? super K> cmp = m.comparator;
+            return !isBeforeEnd(loNode(cmp), cmp);
+        }
+
+        public boolean containsValue(Object value) {
+            if (value == null)
+                throw new NullPointerException();
+            Comparator<? super K> cmp = m.comparator;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                V v = n.getValidValue();
+                if (v != null && value.equals(v))
+                    return true;
+            }
+            return false;
+        }
+
+        public void clear() {
+            Comparator<? super K> cmp = m.comparator;
+            for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
+                 isBeforeEnd(n, cmp);
+                 n = n.next) {
+                if (n.getValidValue() != null)
+                    m.remove(n.key);
+            }
+        }
+
+        /* ----------------  ConcurrentMap API methods -------------- */
+
+        public V putIfAbsent(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.putIfAbsent(key, value);
+        }
+
+        public boolean remove(Object key, Object value) {
+            return inBounds(key, m.comparator) && m.remove(key, value);
+        }
+
+        public boolean replace(K key, V oldValue, V newValue) {
+            checkKeyBounds(key, m.comparator);
+            return m.replace(key, oldValue, newValue);
+        }
+
+        public V replace(K key, V value) {
+            checkKeyBounds(key, m.comparator);
+            return m.replace(key, value);
+        }
+
+        /* ----------------  SortedMap API methods -------------- */
+
+        public Comparator<? super K> comparator() {
+            Comparator<? super K> cmp = m.comparator();
+            if (isDescending)
+                return Collections.reverseOrder(cmp);
+            else
+                return cmp;
+        }
+
+        /**
+         * Utility to create submaps, where given bounds override
+         * unbounded(null) ones and/or are checked against bounded ones.
+         */
+        SubMap<K,V> newSubMap(K fromKey, boolean fromInclusive,
+                              K toKey, boolean toInclusive) {
+            Comparator<? super K> cmp = m.comparator;
+            if (isDescending) { // flip senses
+                K tk = fromKey;
+                fromKey = toKey;
+                toKey = tk;
+                boolean ti = fromInclusive;
+                fromInclusive = toInclusive;
+                toInclusive = ti;
+            }
+            if (lo != null) {
+                if (fromKey == null) {
+                    fromKey = lo;
+                    fromInclusive = loInclusive;
+                }
+                else {
+                    int c = cpr(cmp, fromKey, lo);
+                    if (c < 0 || (c == 0 && !loInclusive && fromInclusive))
+                        throw new IllegalArgumentException("key out of range");
+                }
+            }
+            if (hi != null) {
+                if (toKey == null) {
+                    toKey = hi;
+                    toInclusive = hiInclusive;
+                }
+                else {
+                    int c = cpr(cmp, toKey, hi);
+                    if (c > 0 || (c == 0 && !hiInclusive && toInclusive))
+                        throw new IllegalArgumentException("key out of range");
+                }
+            }
+            return new SubMap<K,V>(m, fromKey, fromInclusive,
+                                   toKey, toInclusive, isDescending);
+        }
+
+        public SubMap<K,V> subMap(K fromKey, boolean fromInclusive,
+                                  K toKey, boolean toInclusive) {
+            if (fromKey == null || toKey == null)
+                throw new NullPointerException();
+            return newSubMap(fromKey, fromInclusive, toKey, toInclusive);
+        }
+
+        public SubMap<K,V> headMap(K toKey, boolean inclusive) {
+            if (toKey == null)
+                throw new NullPointerException();
+            return newSubMap(null, false, toKey, inclusive);
+        }
+
+        public SubMap<K,V> tailMap(K fromKey, boolean inclusive) {
+            if (fromKey == null)
+                throw new NullPointerException();
+            return newSubMap(fromKey, inclusive, null, false);
+        }
+
+        public SubMap<K,V> subMap(K fromKey, K toKey) {
+            return subMap(fromKey, true, toKey, false);
+        }
+
+        public SubMap<K,V> headMap(K toKey) {
+            return headMap(toKey, false);
+        }
+
+        public SubMap<K,V> tailMap(K fromKey) {
+            return tailMap(fromKey, true);
+        }
+
+        public SubMap<K,V> descendingMap() {
+            return new SubMap<K,V>(m, lo, loInclusive,
+                                   hi, hiInclusive, !isDescending);
+        }
+
+        /* ----------------  Relational methods -------------- */
+
+        public Map.Entry<K,V> ceilingEntry(K key) {
+            return getNearEntry(key, GT|EQ);
+        }
+
+        public K ceilingKey(K key) {
+            return getNearKey(key, GT|EQ);
+        }
+
+        public Map.Entry<K,V> lowerEntry(K key) {
+            return getNearEntry(key, LT);
+        }
+
+        public K lowerKey(K key) {
+            return getNearKey(key, LT);
+        }
+
+        public Map.Entry<K,V> floorEntry(K key) {
+            return getNearEntry(key, LT|EQ);
+        }
+
+        public K floorKey(K key) {
+            return getNearKey(key, LT|EQ);
+        }
+
+        public Map.Entry<K,V> higherEntry(K key) {
+            return getNearEntry(key, GT);
+        }
+
+        public K higherKey(K key) {
+            return getNearKey(key, GT);
+        }
+
+        public K firstKey() {
+            return isDescending ? highestKey() : lowestKey();
+        }
+
+        public K lastKey() {
+            return isDescending ? lowestKey() : highestKey();
+        }
+
+        public Map.Entry<K,V> firstEntry() {
+            return isDescending ? highestEntry() : lowestEntry();
+        }
+
+        public Map.Entry<K,V> lastEntry() {
+            return isDescending ? lowestEntry() : highestEntry();
+        }
+
+        public Map.Entry<K,V> pollFirstEntry() {
+            return isDescending ? removeHighest() : removeLowest();
+        }
+
+        public Map.Entry<K,V> pollLastEntry() {
+            return isDescending ? removeLowest() : removeHighest();
+        }
+
+        /* ---------------- Submap Views -------------- */
+
+        public NavigableSet<K> keySet() {
+            KeySet<K,V> ks = keySetView;
+            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+        }
+
+        public NavigableSet<K> navigableKeySet() {
+            KeySet<K,V> ks = keySetView;
+            return (ks != null) ? ks : (keySetView = new KeySet<>(this));
+        }
+
+        public Collection<V> values() {
+            Collection<V> vs = valuesView;
+            return (vs != null) ? vs : (valuesView = new Values<>(this));
+        }
+
+        public Set<Map.Entry<K,V>> entrySet() {
+            Set<Map.Entry<K,V>> es = entrySetView;
+            return (es != null) ? es : (entrySetView = new EntrySet<K,V>(this));
+        }
+
+        public NavigableSet<K> descendingKeySet() {
+            return descendingMap().navigableKeySet();
+        }
+
+        /**
+         * Variant of main Iter class to traverse through submaps.
+         * Also serves as back-up Spliterator for views.
+         */
+        abstract class SubMapIter<T> implements Iterator<T>, Spliterator<T> {
+            /** the last node returned by next() */
+            Node<K,V> lastReturned;
+            /** the next node to return from next(); */
+            Node<K,V> next;
+            /** Cache of next value field to maintain weak consistency */
+            V nextValue;
+
+            SubMapIter() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = isDescending ? hiNode(cmp) : loNode(cmp);
+                    if (next == null)
+                        break;
+                    Object x = next.value;
+                    if (x != null && x != next) {
+                        if (! inBounds(next.key, cmp))
+                            next = null;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            public final boolean hasNext() {
+                return next != null;
+            }
+
+            final void advance() {
+                if (next == null)
+                    throw new NoSuchElementException();
+                lastReturned = next;
+                if (isDescending)
+                    descend();
+                else
+                    ascend();
+            }
+
+            private void ascend() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = next.next;
+                    if (next == null)
+                        break;
+                    Object x = next.value;
+                    if (x != null && x != next) {
+                        if (tooHigh(next.key, cmp))
+                            next = null;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            private void descend() {
+                Comparator<? super K> cmp = m.comparator;
+                for (;;) {
+                    next = m.findNear(lastReturned.key, LT, cmp);
+                    if (next == null)
+                        break;
+                    Object x = next.value;
+                    if (x != null && x != next) {
+                        if (tooLow(next.key, cmp))
+                            next = null;
+                        else {
+                            @SuppressWarnings("unchecked") V vv = (V)x;
+                            nextValue = vv;
+                        }
+                        break;
+                    }
+                }
+            }
+
+            public void remove() {
+                Node<K,V> l = lastReturned;
+                if (l == null)
+                    throw new IllegalStateException();
+                m.remove(l.key);
+                lastReturned = null;
+            }
+
+            public Spliterator<T> trySplit() {
+                return null;
+            }
+
+            public boolean tryAdvance(Consumer<? super T> action) {
+                if (hasNext()) {
+                    action.accept(next());
+                    return true;
+                }
+                return false;
+            }
+
+            public void forEachRemaining(Consumer<? super T> action) {
+                while (hasNext())
+                    action.accept(next());
+            }
+
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+
+        }
+
+        final class SubMapValueIterator extends SubMapIter<V> {
+            public V next() {
+                V v = nextValue;
+                advance();
+                return v;
+            }
+            public int characteristics() {
+                return 0;
+            }
+        }
+
+        final class SubMapKeyIterator extends SubMapIter<K> {
+            public K next() {
+                Node<K,V> n = next;
+                advance();
+                return n.key;
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT | Spliterator.ORDERED |
+                    Spliterator.SORTED;
+            }
+            public final Comparator<? super K> getComparator() {
+                return SubMap.this.comparator();
+            }
+        }
+
+        final class SubMapEntryIterator extends SubMapIter<Map.Entry<K,V>> {
+            public Map.Entry<K,V> next() {
+                Node<K,V> n = next;
+                V v = nextValue;
+                advance();
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+            public int characteristics() {
+                return Spliterator.DISTINCT;
+            }
+        }
+    }
+
+    // default Map method overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null) throw new NullPointerException();
+        V v;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            if ((v = n.getValidValue()) != null)
+                action.accept(n.key, v);
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null) throw new NullPointerException();
+        V v;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            while ((v = n.getValidValue()) != null) {
+                V r = function.apply(n.key, v);
+                if (r == null) throw new NullPointerException();
+                if (n.casValue(v, r))
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Helper method for EntrySet.removeIf.
+     */
+    boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
+        if (function == null) throw new NullPointerException();
+        boolean removed = false;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v;
+            if ((v = n.getValidValue()) != null) {
+                K k = n.key;
+                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                if (function.test(e) && remove(k, v))
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Helper method for Values.removeIf.
+     */
+    boolean removeValueIf(Predicate<? super V> function) {
+        if (function == null) throw new NullPointerException();
+        boolean removed = false;
+        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
+            V v;
+            if ((v = n.getValidValue()) != null) {
+                K k = n.key;
+                if (function.test(v) && remove(k, v))
+                    removed = true;
+            }
+        }
+        return removed;
+    }
+
+    /**
+     * Base class providing common structure for Spliterators.
+     * (Although not all that much common functionality; as usual for
+     * view classes, details annoyingly vary in key, value, and entry
+     * subclasses in ways that are not worth abstracting out for
+     * internal classes.)
+     *
+     * The basic split strategy is to recursively descend from top
+     * level, row by row, descending to next row when either split
+     * off, or the end of row is encountered. Control of the number of
+     * splits relies on some statistical estimation: The expected
+     * remaining number of elements of a skip list when advancing
+     * either across or down decreases by about 25%. To make this
+     * observation useful, we need to know initial size, which we
+     * don't. But we can just use Integer.MAX_VALUE so that we
+     * don't prematurely zero out while splitting.
+     */
+    abstract static class CSLMSpliterator<K,V> {
+        final Comparator<? super K> comparator;
+        final K fence;     // exclusive upper bound for keys, or null if to end
+        Index<K,V> row;    // the level to split out
+        Node<K,V> current; // current traversal node; initialize at origin
+        int est;           // pseudo-size estimate
+        CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                        Node<K,V> origin, K fence, int est) {
+            this.comparator = comparator; this.row = row;
+            this.current = origin; this.fence = fence; this.est = est;
+        }
+
+        public final long estimateSize() { return (long)est; }
+    }
+
+    static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<K> {
+        KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                       Node<K,V> origin, K fence, int est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public KeySpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.value != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new KeySpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.value) != null && v != e)
+                    action.accept(k);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super K> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.value) != null && v != e) {
+                    current = e.next;
+                    action.accept(k);
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.SORTED |
+                Spliterator.ORDERED | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+
+        public final Comparator<? super K> getComparator() {
+            return comparator;
+        }
+    }
+    // factory method for KeySpliterator
+    final KeySpliterator<K,V> keySpliterator() {
+        Comparator<? super K> cmp = comparator;
+        for (;;) { // ensure h corresponds to origin p
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                               0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
+        }
+    }
+
+    static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<V> {
+        ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                       Node<K,V> origin, K fence, int est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public ValueSpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.value != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new ValueSpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.value) != null && v != e) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept(vv);
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super V> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.value) != null && v != e) {
+                    current = e.next;
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept(vv);
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.CONCURRENT | Spliterator.ORDERED |
+                Spliterator.NONNULL;
+        }
+    }
+
+    // Almost the same as keySpliterator()
+    final ValueSpliterator<K,V> valueSpliterator() {
+        Comparator<? super K> cmp = comparator;
+        for (;;) {
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                                 0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
+        }
+    }
+
+    static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
+        implements Spliterator<Map.Entry<K,V>> {
+        EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
+                         Node<K,V> origin, K fence, int est) {
+            super(comparator, row, origin, fence, est);
+        }
+
+        public EntrySpliterator<K,V> trySplit() {
+            Node<K,V> e; K ek;
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            if ((e = current) != null && (ek = e.key) != null) {
+                for (Index<K,V> q = row; q != null; q = row = q.down) {
+                    Index<K,V> s; Node<K,V> b, n; K sk;
+                    if ((s = q.right) != null && (b = s.node) != null &&
+                        (n = b.next) != null && n.value != null &&
+                        (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
+                        (f == null || cpr(cmp, sk, f) < 0)) {
+                        current = n;
+                        Index<K,V> r = q.down;
+                        row = (s.right != null) ? s : s.down;
+                        est -= est >>> 2;
+                        return new EntrySpliterator<K,V>(cmp, r, e, sk, est);
+                    }
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            current = null;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
+                    break;
+                if ((v = e.value) != null && v != e) {
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                }
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null) throw new NullPointerException();
+            Comparator<? super K> cmp = comparator;
+            K f = fence;
+            Node<K,V> e = current;
+            for (; e != null; e = e.next) {
+                K k; Object v;
+                if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
+                    e = null;
+                    break;
+                }
+                if ((v = e.value) != null && v != e) {
+                    current = e.next;
+                    @SuppressWarnings("unchecked") V vv = (V)v;
+                    action.accept
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                    return true;
+                }
+            }
+            current = e;
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.DISTINCT | Spliterator.SORTED |
+                Spliterator.ORDERED | Spliterator.CONCURRENT |
+                Spliterator.NONNULL;
+        }
+
+        public final Comparator<Map.Entry<K,V>> getComparator() {
+            // Adapt or create a key-based comparator
+            if (comparator != null) {
+                return Map.Entry.comparingByKey(comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K,V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
+        }
+    }
+
+    // Almost the same as keySpliterator()
+    final EntrySpliterator<K,V> entrySpliterator() {
+        Comparator<? super K> cmp = comparator;
+        for (;;) { // almost same as key version
+            HeadIndex<K,V> h; Node<K,V> p;
+            Node<K,V> b = (h = head).node;
+            if ((p = b.next) == null || p.value != null)
+                return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
+                                                 0 : Integer.MAX_VALUE);
+            p.helpDelete(b, p.next);
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    static {
+        try {
+            HEAD = U.objectFieldOffset
+                (ConcurrentSkipListMap.class.getDeclaredField("head"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/ConcurrentSkipListSet.java b/java/util/concurrent/ConcurrentSkipListSet.java
new file mode 100644
index 0000000..2e11b17
--- /dev/null
+++ b/java/util/concurrent/ConcurrentSkipListSet.java
@@ -0,0 +1,524 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NavigableMap;
+import java.util.NavigableSet;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.Spliterator;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A scalable concurrent {@link NavigableSet} implementation based on
+ * a {@link ConcurrentSkipListMap}.  The elements of the set are kept
+ * sorted according to their {@linkplain Comparable natural ordering},
+ * or by a {@link Comparator} provided at set creation time, depending
+ * on which constructor is used.
+ *
+ * <p>This implementation provides expected average <i>log(n)</i> time
+ * cost for the {@code contains}, {@code add}, and {@code remove}
+ * operations and their variants.  Insertion, removal, and access
+ * operations safely execute concurrently by multiple threads.
+ *
+ * <p>Iterators and spliterators are
+ * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+ *
+ * <p>Ascending ordered views and their iterators are faster than
+ * descending ones.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size}
+ * method is <em>not</em> a constant-time operation. Because of the
+ * asynchronous nature of these sets, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterators implement all of the
+ * <em>optional</em> methods of the {@link Set} and {@link Iterator}
+ * interfaces. Like most other concurrent collection implementations,
+ * this class does not permit the use of {@code null} elements,
+ * because {@code null} arguments and return values cannot be reliably
+ * distinguished from the absence of elements.
+ *
+ * @author Doug Lea
+ * @param <E> the type of elements maintained by this set
+ * @since 1.6
+ */
+public class ConcurrentSkipListSet<E>
+    extends AbstractSet<E>
+    implements NavigableSet<E>, Cloneable, java.io.Serializable {
+
+    private static final long serialVersionUID = -2479143111061671589L;
+
+    /**
+     * The underlying map. Uses Boolean.TRUE as value for each
+     * element.  This field is declared final for the sake of thread
+     * safety, which entails some ugliness in clone().
+     */
+    private final ConcurrentNavigableMap<E,Object> m;
+
+    /**
+     * Constructs a new, empty set that orders its elements according to
+     * their {@linkplain Comparable natural ordering}.
+     */
+    public ConcurrentSkipListSet() {
+        m = new ConcurrentSkipListMap<E,Object>();
+    }
+
+    /**
+     * Constructs a new, empty set that orders its elements according to
+     * the specified comparator.
+     *
+     * @param comparator the comparator that will be used to order this set.
+     *        If {@code null}, the {@linkplain Comparable natural
+     *        ordering} of the elements will be used.
+     */
+    public ConcurrentSkipListSet(Comparator<? super E> comparator) {
+        m = new ConcurrentSkipListMap<E,Object>(comparator);
+    }
+
+    /**
+     * Constructs a new set containing the elements in the specified
+     * collection, that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param c The elements that will comprise the new set
+     * @throws ClassCastException if the elements in {@code c} are
+     *         not {@link Comparable}, or are not mutually comparable
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public ConcurrentSkipListSet(Collection<? extends E> c) {
+        m = new ConcurrentSkipListMap<E,Object>();
+        addAll(c);
+    }
+
+    /**
+     * Constructs a new set containing the same elements and using the
+     * same ordering as the specified sorted set.
+     *
+     * @param s sorted set whose elements will comprise the new set
+     * @throws NullPointerException if the specified sorted set or any
+     *         of its elements are null
+     */
+    public ConcurrentSkipListSet(SortedSet<E> s) {
+        m = new ConcurrentSkipListMap<E,Object>(s.comparator());
+        addAll(s);
+    }
+
+    /**
+     * For use by submaps
+     */
+    ConcurrentSkipListSet(ConcurrentNavigableMap<E,Object> m) {
+        this.m = m;
+    }
+
+    /**
+     * Returns a shallow copy of this {@code ConcurrentSkipListSet}
+     * instance. (The elements themselves are not cloned.)
+     *
+     * @return a shallow copy of this set
+     */
+    public ConcurrentSkipListSet<E> clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            ConcurrentSkipListSet<E> clone =
+                (ConcurrentSkipListSet<E>) super.clone();
+            clone.setMap(new ConcurrentSkipListMap<E,Object>(m));
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /* ---------------- Set operations -------------- */
+
+    /**
+     * Returns the number of elements in this set.  If this set
+     * contains more than {@code Integer.MAX_VALUE} elements, it
+     * returns {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these sets, determining the current
+     * number of elements requires traversing them all to count them.
+     * Additionally, it is possible for the size to change during
+     * execution of this method, in which case the returned result
+     * will be inaccurate. Thus, this method is typically not very
+     * useful in concurrent applications.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return m.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return m.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this set
+     * @return {@code true} if this set contains the specified element
+     * @throws ClassCastException if the specified element cannot be
+     *         compared with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean contains(Object o) {
+        return m.containsKey(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that {@code e.equals(e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the
+     *         specified element
+     * @throws ClassCastException if {@code e} cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return m.putIfAbsent(e, Boolean.TRUE) == null;
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code o.equals(e)}, if this set contains such an element.
+     * Returns {@code true} if this set contained the element (or
+     * equivalently, if this set changed as a result of the call).
+     * (This set will not contain the element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     * @throws ClassCastException if {@code o} cannot be compared
+     *         with the elements currently in this set
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean remove(Object o) {
+        return m.remove(o, Boolean.TRUE);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     */
+    public void clear() {
+        m.clear();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in ascending order.
+     *
+     * @return an iterator over the elements in this set in ascending order
+     */
+    public Iterator<E> iterator() {
+        return m.navigableKeySet().iterator();
+    }
+
+    /**
+     * Returns an iterator over the elements in this set in descending order.
+     *
+     * @return an iterator over the elements in this set in descending order
+     */
+    public Iterator<E> descendingIterator() {
+        return m.descendingKeySet().iterator();
+    }
+
+
+    /* ---------------- AbstractSet Overrides -------------- */
+
+    /**
+     * Compares the specified object with this set for equality.  Returns
+     * {@code true} if the specified object is also a set, the two sets
+     * have the same size, and every member of the specified set is
+     * contained in this set (or equivalently, every member of this set is
+     * contained in the specified set).  This definition ensures that the
+     * equals method works properly across different implementations of the
+     * set interface.
+     *
+     * @param o the object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        // Override AbstractSet version to avoid calling size()
+        if (o == this)
+            return true;
+        if (!(o instanceof Set))
+            return false;
+        Collection<?> c = (Collection<?>) o;
+        try {
+            return containsAll(c) && c.containsAll(this);
+        } catch (ClassCastException unused) {
+            return false;
+        } catch (NullPointerException unused) {
+            return false;
+        }
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in
+     * the specified collection.  If the specified collection is also
+     * a set, this operation effectively modifies this set so that its
+     * value is the <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public boolean removeAll(Collection<?> c) {
+        // Override AbstractSet version to avoid unnecessary call to size()
+        boolean modified = false;
+        for (Object e : c)
+            if (remove(e))
+                modified = true;
+        return modified;
+    }
+
+    /* ---------------- Relational operations -------------- */
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E lower(E e) {
+        return m.lowerKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E floor(E e) {
+        return m.floorKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E ceiling(E e) {
+        return m.ceilingKey(e);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if the specified element is null
+     */
+    public E higher(E e) {
+        return m.higherKey(e);
+    }
+
+    public E pollFirst() {
+        Map.Entry<E,Object> e = m.pollFirstEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+    public E pollLast() {
+        Map.Entry<E,Object> e = m.pollLastEntry();
+        return (e == null) ? null : e.getKey();
+    }
+
+
+    /* ---------------- SortedSet operations -------------- */
+
+    public Comparator<? super E> comparator() {
+        return m.comparator();
+    }
+
+    /**
+     * @throws java.util.NoSuchElementException {@inheritDoc}
+     */
+    public E first() {
+        return m.firstKey();
+    }
+
+    /**
+     * @throws java.util.NoSuchElementException {@inheritDoc}
+     */
+    public E last() {
+        return m.lastKey();
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> subSet(E fromElement,
+                                  boolean fromInclusive,
+                                  E toElement,
+                                  boolean toInclusive) {
+        return new ConcurrentSkipListSet<E>
+            (m.subMap(fromElement, fromInclusive,
+                      toElement,   toInclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
+        return new ConcurrentSkipListSet<E>(m.headMap(toElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
+        return new ConcurrentSkipListSet<E>(m.tailMap(fromElement, inclusive));
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} or
+     *         {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> subSet(E fromElement, E toElement) {
+        return subSet(fromElement, true, toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code toElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> headSet(E toElement) {
+        return headSet(toElement, false);
+    }
+
+    /**
+     * @throws ClassCastException {@inheritDoc}
+     * @throws NullPointerException if {@code fromElement} is null
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public NavigableSet<E> tailSet(E fromElement) {
+        return tailSet(fromElement, true);
+    }
+
+    /**
+     * Returns a reverse order view of the elements contained in this set.
+     * The descending set is backed by this set, so changes to the set are
+     * reflected in the descending set, and vice-versa.
+     *
+     * <p>The returned set has an ordering equivalent to
+     * {@link Collections#reverseOrder(Comparator) Collections.reverseOrder}{@code (comparator())}.
+     * The expression {@code s.descendingSet().descendingSet()} returns a
+     * view of {@code s} essentially equivalent to {@code s}.
+     *
+     * @return a reverse order view of this set
+     */
+    public NavigableSet<E> descendingSet() {
+        return new ConcurrentSkipListSet<E>(m.descendingMap());
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED} and {@link Spliterator#ORDERED}, with an
+     * encounter order that is ascending order.  Overriding implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return (m instanceof ConcurrentSkipListMap)
+            ? ((ConcurrentSkipListMap<E,?>)m).keySpliterator()
+            : ((ConcurrentSkipListMap.SubMap<E,?>)m).new SubMapKeyIterator();
+    }
+
+    // Support for resetting map in clone
+    private void setMap(ConcurrentNavigableMap<E,Object> map) {
+        U.putObjectVolatile(this, MAP, map);
+    }
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long MAP;
+    static {
+        try {
+            MAP = U.objectFieldOffset
+                (ConcurrentSkipListSet.class.getDeclaredField("m"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/CopyOnWriteArrayList.annotated.java b/java/util/concurrent/CopyOnWriteArrayList.annotated.java
new file mode 100644
index 0000000..57ab75c
--- /dev/null
+++ b/java/util/concurrent/CopyOnWriteArrayList.annotated.java
@@ -0,0 +1,125 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group.  Adapted and released, under explicit permission,
+ * from JDK ArrayList.java which carries the following copyright:
+ *
+ * Copyright 1997 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ */
+
+
+package java.util.concurrent;
+
+import java.util.ConcurrentModificationException;
+import java.util.List;
+import java.util.Objects;
+import java.util.Collection;
+import java.util.Spliterator;
+import java.util.AbstractList;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class CopyOnWriteArrayList<E> implements java.util.List<E>, java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
+
+public CopyOnWriteArrayList() { throw new RuntimeException("Stub!"); }
+
+public CopyOnWriteArrayList(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public CopyOnWriteArrayList(E @libcore.util.NonNull [] toCopyIn) { throw new RuntimeException("Stub!"); }
+
+public int size() { throw new RuntimeException("Stub!"); }
+
+public boolean isEmpty() { throw new RuntimeException("Stub!"); }
+
+public boolean contains(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int indexOf(@libcore.util.Nullable E e, int index) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int lastIndexOf(@libcore.util.Nullable E e, int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public [email protected] Object @libcore.util.NonNull [] toArray() { throw new RuntimeException("Stub!"); }
+
+public <T> T @libcore.util.NonNull [] toArray(T @libcore.util.NonNull [] a) { throw new RuntimeException("Stub!"); }
+
[email protected] public E get(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public E set(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
+public boolean add(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public void add(int index, @libcore.util.NullFromTypeParam E element) { throw new RuntimeException("Stub!"); }
+
[email protected] public E remove(int index) { throw new RuntimeException("Stub!"); }
+
+public boolean remove(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public boolean addIfAbsent(@libcore.util.NullFromTypeParam E e) { throw new RuntimeException("Stub!"); }
+
+public boolean containsAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean removeAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public boolean retainAll(@libcore.util.NonNull java.util.Collection<?> c) { throw new RuntimeException("Stub!"); }
+
+public int addAllAbsent(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void clear() { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(@libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public boolean addAll(int index, @libcore.util.NonNull java.util.Collection<? extends @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
+public void forEach(@libcore.util.NonNull java.util.function.Consumer<? super @libcore.util.NullFromTypeParam E> action) { throw new RuntimeException("Stub!"); }
+
+public boolean removeIf(@libcore.util.NonNull java.util.function.Predicate<? super @libcore.util.NullFromTypeParam E> filter) { throw new RuntimeException("Stub!"); }
+
+public void replaceAll(@libcore.util.NonNull java.util.function.UnaryOperator<@libcore.util.NullFromTypeParam E> operator) { throw new RuntimeException("Stub!"); }
+
+public void sort(@libcore.util.Nullable java.util.Comparator<? super @libcore.util.NullFromTypeParam E> c) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object o) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Iterator<@libcore.util.NullFromTypeParam E> iterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ListIterator<@libcore.util.NullFromTypeParam E> listIterator(int index) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.Spliterator<@libcore.util.NullFromTypeParam E> spliterator() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.List<@libcore.util.NullFromTypeParam E> subList(int fromIndex, int toIndex) { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/concurrent/CopyOnWriteArrayList.java b/java/util/concurrent/CopyOnWriteArrayList.java
new file mode 100644
index 0000000..ebcbbef
--- /dev/null
+++ b/java/util/concurrent/CopyOnWriteArrayList.java
@@ -0,0 +1,1555 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group.  Adapted and released, under explicit permission,
+ * from JDK ArrayList.java which carries the following copyright:
+ *
+ * Copyright 1997 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+// Android-changed: Removed javadoc link to collections framework docs
+/**
+ * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
+ * operations ({@code add}, {@code set}, and so on) are implemented by
+ * making a fresh copy of the underlying array.
+ *
+ * <p>This is ordinarily too costly, but may be <em>more</em> efficient
+ * than alternatives when traversal operations vastly outnumber
+ * mutations, and is useful when you cannot or don't want to
+ * synchronize traversals, yet need to preclude interference among
+ * concurrent threads.  The "snapshot" style iterator method uses a
+ * reference to the state of the array at the point that the iterator
+ * was created. This array never changes during the lifetime of the
+ * iterator, so interference is impossible and the iterator is
+ * guaranteed not to throw {@code ConcurrentModificationException}.
+ * The iterator will not reflect additions, removals, or changes to
+ * the list since the iterator was created.  Element-changing
+ * operations on iterators themselves ({@code remove}, {@code set}, and
+ * {@code add}) are not supported. These methods throw
+ * {@code UnsupportedOperationException}.
+ *
+ * <p>All elements are permitted, including {@code null}.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code CopyOnWriteArrayList}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code CopyOnWriteArrayList} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this list
+ */
+public class CopyOnWriteArrayList<E>
+    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
+    private static final long serialVersionUID = 8673264195747942595L;
+
+    /**
+     * The lock protecting all mutators.  (We have a mild preference
+     * for builtin monitors over ReentrantLock when either will do.)
+     */
+    final transient Object lock = new Object();
+
+    /** The array, accessed only via getArray/setArray. */
+    private transient volatile Object[] array;
+
+    /**
+     * Gets the array.  Non-private so as to also be accessible
+     * from CopyOnWriteArraySet class.
+     */
+    final Object[] getArray() {
+        return array;
+    }
+
+    /**
+     * Sets the array.
+     */
+    final void setArray(Object[] a) {
+        array = a;
+    }
+
+    /**
+     * Creates an empty list.
+     */
+    public CopyOnWriteArrayList() {
+        setArray(new Object[0]);
+    }
+
+    /**
+     * Creates a list containing the elements of the specified
+     * collection, in the order they are returned by the collection's
+     * iterator.
+     *
+     * @param c the collection of initially held elements
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArrayList(Collection<? extends E> c) {
+        Object[] elements;
+        if (c.getClass() == CopyOnWriteArrayList.class)
+            elements = ((CopyOnWriteArrayList<?>)c).getArray();
+        else {
+            elements = c.toArray();
+            // defend against c.toArray (incorrectly) not returning Object[]
+            // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
+            if (elements.getClass() != Object[].class)
+                elements = Arrays.copyOf(elements, elements.length, Object[].class);
+        }
+        setArray(elements);
+    }
+
+    /**
+     * Creates a list holding a copy of the given array.
+     *
+     * @param toCopyIn the array (a copy of this array is used as the
+     *        internal array)
+     * @throws NullPointerException if the specified array is null
+     */
+    public CopyOnWriteArrayList(E[] toCopyIn) {
+        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
+    }
+
+    /**
+     * Returns the number of elements in this list.
+     *
+     * @return the number of elements in this list
+     */
+    public int size() {
+        return getArray().length;
+    }
+
+    /**
+     * Returns {@code true} if this list contains no elements.
+     *
+     * @return {@code true} if this list contains no elements
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * static version of indexOf, to allow repeated calls without
+     * needing to re-acquire array each time.
+     * @param o element to search for
+     * @param elements the array
+     * @param index first index to search
+     * @param fence one past last index to search
+     * @return index of element, or -1 if absent
+     */
+    private static int indexOf(Object o, Object[] elements,
+                               int index, int fence) {
+        if (o == null) {
+            for (int i = index; i < fence; i++)
+                if (elements[i] == null)
+                    return i;
+        } else {
+            for (int i = index; i < fence; i++)
+                if (o.equals(elements[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * static version of lastIndexOf.
+     * @param o element to search for
+     * @param elements the array
+     * @param index first index to search
+     * @return index of element, or -1 if absent
+     */
+    private static int lastIndexOf(Object o, Object[] elements, int index) {
+        if (o == null) {
+            for (int i = index; i >= 0; i--)
+                if (elements[i] == null)
+                    return i;
+        } else {
+            for (int i = index; i >= 0; i--)
+                if (o.equals(elements[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns {@code true} if this list contains the specified element.
+     * More formally, returns {@code true} if and only if this list contains
+     * at least one element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this list is to be tested
+     * @return {@code true} if this list contains the specified element
+     */
+    public boolean contains(Object o) {
+        Object[] elements = getArray();
+        return indexOf(o, elements, 0, elements.length) >= 0;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int indexOf(Object o) {
+        Object[] elements = getArray();
+        return indexOf(o, elements, 0, elements.length);
+    }
+
+    /**
+     * Returns the index of the first occurrence of the specified element in
+     * this list, searching forwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the lowest index {@code i} such that
+     * {@code i >= index && Objects.equals(get(i), e)},
+     * or -1 if there is no such index.
+     *
+     * @param e element to search for
+     * @param index index to start searching from
+     * @return the index of the first occurrence of the element in
+     *         this list at position {@code index} or later in the list;
+     *         {@code -1} if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is negative
+     */
+    public int indexOf(E e, int index) {
+        Object[] elements = getArray();
+        return indexOf(e, elements, index, elements.length);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public int lastIndexOf(Object o) {
+        Object[] elements = getArray();
+        return lastIndexOf(o, elements, elements.length - 1);
+    }
+
+    /**
+     * Returns the index of the last occurrence of the specified element in
+     * this list, searching backwards from {@code index}, or returns -1 if
+     * the element is not found.
+     * More formally, returns the highest index {@code i} such that
+     * {@code i <= index && Objects.equals(get(i), e)},
+     * or -1 if there is no such index.
+     *
+     * @param e element to search for
+     * @param index index to start searching backwards from
+     * @return the index of the last occurrence of the element at position
+     *         less than or equal to {@code index} in this list;
+     *         -1 if the element is not found.
+     * @throws IndexOutOfBoundsException if the specified index is greater
+     *         than or equal to the current size of this list
+     */
+    public int lastIndexOf(E e, int index) {
+        Object[] elements = getArray();
+        return lastIndexOf(e, elements, index);
+    }
+
+    /**
+     * Returns a shallow copy of this list.  (The elements themselves
+     * are not copied.)
+     *
+     * @return a clone of this list
+     */
+    public Object clone() {
+        try {
+            @SuppressWarnings("unchecked")
+            CopyOnWriteArrayList<E> clone =
+                (CopyOnWriteArrayList<E>) super.clone();
+            clone.resetLock();
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list
+     * in proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this list.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this list
+     */
+    public Object[] toArray() {
+        Object[] elements = getArray();
+        return Arrays.copyOf(elements, elements.length);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this list in
+     * proper sequence (from first to last element); the runtime type of
+     * the returned array is that of the specified array.  If the list fits
+     * in the specified array, it is returned therein.  Otherwise, a new
+     * array is allocated with the runtime type of the specified array and
+     * the size of this list.
+     *
+     * <p>If this list fits in the specified array with room to spare
+     * (i.e., the array has more elements than this list), the element in
+     * the array immediately following the end of the list is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * list <i>only</i> if the caller knows that this list does not contain
+     * any null elements.)
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a list known to contain only strings.
+     * The following code can be used to dump the list into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the list are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this list
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this list
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        Object[] elements = getArray();
+        int len = elements.length;
+        if (a.length < len)
+            return (T[]) Arrays.copyOf(elements, len, a.getClass());
+        else {
+            System.arraycopy(elements, 0, a, 0, len);
+            if (a.length > len)
+                a[len] = null;
+            return a;
+        }
+    }
+
+    // Positional Access Operations
+
+    @SuppressWarnings("unchecked")
+    private E get(Object[] a, int index) {
+        return (E) a[index];
+    }
+
+    static String outOfBounds(int index, int size) {
+        return "Index: " + index + ", Size: " + size;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E get(int index) {
+        return get(getArray(), index);
+    }
+
+    /**
+     * Replaces the element at the specified position in this list with the
+     * specified element.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E set(int index, E element) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            E oldValue = get(elements, index);
+
+            if (oldValue != element) {
+                int len = elements.length;
+                Object[] newElements = Arrays.copyOf(elements, len);
+                newElements[index] = element;
+                setArray(newElements);
+            } else {
+                // Not quite a no-op; ensures volatile write semantics
+                setArray(elements);
+            }
+            return oldValue;
+        }
+    }
+
+    /**
+     * Appends the specified element to the end of this list.
+     *
+     * @param e element to be appended to this list
+     * @return {@code true} (as specified by {@link Collection#add})
+     */
+    public boolean add(E e) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            Object[] newElements = Arrays.copyOf(elements, len + 1);
+            newElements[len] = e;
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Inserts the specified element at the specified position in this
+     * list. Shifts the element currently at that position (if any) and
+     * any subsequent elements to the right (adds one to their indices).
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public void add(int index, E element) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (index > len || index < 0)
+                throw new IndexOutOfBoundsException(outOfBounds(index, len));
+            Object[] newElements;
+            int numMoved = len - index;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(elements, len + 1);
+            else {
+                newElements = new Object[len + 1];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index, newElements, index + 1,
+                                 numMoved);
+            }
+            newElements[index] = element;
+            setArray(newElements);
+        }
+    }
+
+    /**
+     * Removes the element at the specified position in this list.
+     * Shifts any subsequent elements to the left (subtracts one from their
+     * indices).  Returns the element that was removed from the list.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public E remove(int index) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            E oldValue = get(elements, index);
+            int numMoved = len - index - 1;
+            if (numMoved == 0)
+                setArray(Arrays.copyOf(elements, len - 1));
+            else {
+                Object[] newElements = new Object[len - 1];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index + 1, newElements, index,
+                                 numMoved);
+                setArray(newElements);
+            }
+            return oldValue;
+        }
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this list,
+     * if it is present.  If this list does not contain the element, it is
+     * unchanged.  More formally, removes the element with the lowest index
+     * {@code i} such that {@code Objects.equals(o, get(i))}
+     * (if such an element exists).  Returns {@code true} if this list
+     * contained the specified element (or equivalently, if this list
+     * changed as a result of the call).
+     *
+     * @param o element to be removed from this list, if present
+     * @return {@code true} if this list contained the specified element
+     */
+    public boolean remove(Object o) {
+        Object[] snapshot = getArray();
+        int index = indexOf(o, snapshot, 0, snapshot.length);
+        return (index < 0) ? false : remove(o, snapshot, index);
+    }
+
+    /**
+     * A version of remove(Object) using the strong hint that given
+     * recent snapshot contains o at the given index.
+     */
+    private boolean remove(Object o, Object[] snapshot, int index) {
+        synchronized (lock) {
+            Object[] current = getArray();
+            int len = current.length;
+            if (snapshot != current) findIndex: {
+                int prefix = Math.min(index, len);
+                for (int i = 0; i < prefix; i++) {
+                    if (current[i] != snapshot[i]
+                        && Objects.equals(o, current[i])) {
+                        index = i;
+                        break findIndex;
+                    }
+                }
+                if (index >= len)
+                    return false;
+                if (current[index] == o)
+                    break findIndex;
+                index = indexOf(o, current, index, len);
+                if (index < 0)
+                    return false;
+            }
+            Object[] newElements = new Object[len - 1];
+            System.arraycopy(current, 0, newElements, 0, index);
+            System.arraycopy(current, index + 1,
+                             newElements, index,
+                             len - index - 1);
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Removes from this list all of the elements whose index is between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * Shifts any succeeding elements to the left (reduces their index).
+     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
+     * (If {@code toIndex==fromIndex}, this operation has no effect.)
+     *
+     * @param fromIndex index of first element to be removed
+     * @param toIndex index after last element to be removed
+     * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range
+     *         ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex})
+     */
+    void removeRange(int fromIndex, int toIndex) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+
+            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
+                throw new IndexOutOfBoundsException();
+            int newlen = len - (toIndex - fromIndex);
+            int numMoved = len - toIndex;
+            if (numMoved == 0)
+                setArray(Arrays.copyOf(elements, newlen));
+            else {
+                Object[] newElements = new Object[newlen];
+                System.arraycopy(elements, 0, newElements, 0, fromIndex);
+                System.arraycopy(elements, toIndex, newElements,
+                                 fromIndex, numMoved);
+                setArray(newElements);
+            }
+        }
+    }
+
+    /**
+     * Appends the element, if not present.
+     *
+     * @param e element to be added to this list, if absent
+     * @return {@code true} if the element was added
+     */
+    public boolean addIfAbsent(E e) {
+        Object[] snapshot = getArray();
+        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
+            addIfAbsent(e, snapshot);
+    }
+
+    /**
+     * A version of addIfAbsent using the strong hint that given
+     * recent snapshot does not contain e.
+     */
+    private boolean addIfAbsent(E e, Object[] snapshot) {
+        synchronized (lock) {
+            Object[] current = getArray();
+            int len = current.length;
+            if (snapshot != current) {
+                // Optimize for lost race to another addXXX operation
+                int common = Math.min(snapshot.length, len);
+                for (int i = 0; i < common; i++)
+                    if (current[i] != snapshot[i]
+                        && Objects.equals(e, current[i]))
+                        return false;
+                if (indexOf(e, current, common, len) >= 0)
+                        return false;
+            }
+            Object[] newElements = Arrays.copyOf(current, len + 1);
+            newElements[len] = e;
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this list contains all of the elements of the
+     * specified collection.
+     *
+     * @param c collection to be checked for containment in this list
+     * @return {@code true} if this list contains all of the elements of the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        Object[] elements = getArray();
+        int len = elements.length;
+        for (Object e : c) {
+            if (indexOf(e, elements, 0, len) < 0)
+                return false;
+        }
+        return true;
+    }
+
+    /**
+     * Removes from this list all of its elements that are contained in
+     * the specified collection. This is a particularly expensive operation
+     * in this class because of the need for an internal temporary array.
+     *
+     * @param c collection containing elements to be removed from this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        if (c == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len != 0) {
+                // temp array holds those elements we know we want to keep
+                int newlen = 0;
+                Object[] temp = new Object[len];
+                for (int i = 0; i < len; ++i) {
+                    Object element = elements[i];
+                    if (!c.contains(element))
+                        temp[newlen++] = element;
+                }
+                if (newlen != len) {
+                    setArray(Arrays.copyOf(temp, newlen));
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Retains only the elements in this list that are contained in the
+     * specified collection.  In other words, removes from this list all of
+     * its elements that are not contained in the specified collection.
+     *
+     * @param c collection containing elements to be retained in this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws ClassCastException if the class of an element of this list
+     *         is incompatible with the specified collection
+     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this list contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="{@docRoot}/../api/java/util/Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        if (c == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len != 0) {
+                // temp array holds those elements we know we want to keep
+                int newlen = 0;
+                Object[] temp = new Object[len];
+                for (int i = 0; i < len; ++i) {
+                    Object element = elements[i];
+                    if (c.contains(element))
+                        temp[newlen++] = element;
+                }
+                if (newlen != len) {
+                    setArray(Arrays.copyOf(temp, newlen));
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection that
+     * are not already contained in this list, to the end of
+     * this list, in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param c collection containing elements to be added to this list
+     * @return the number of elements added
+     * @throws NullPointerException if the specified collection is null
+     * @see #addIfAbsent(Object)
+     */
+    public int addAllAbsent(Collection<? extends E> c) {
+        Object[] cs = c.toArray();
+        if (cs.length == 0)
+            return 0;
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            int added = 0;
+            // uniquify and compact elements in cs
+            for (int i = 0; i < cs.length; ++i) {
+                Object e = cs[i];
+                if (indexOf(e, elements, 0, len) < 0 &&
+                    indexOf(e, cs, 0, added) < 0)
+                    cs[added++] = e;
+            }
+            if (added > 0) {
+                Object[] newElements = Arrays.copyOf(elements, len + added);
+                System.arraycopy(cs, 0, newElements, len, added);
+                setArray(newElements);
+            }
+            return added;
+        }
+    }
+
+    /**
+     * Removes all of the elements from this list.
+     * The list will be empty after this call returns.
+     */
+    public void clear() {
+        synchronized (lock) {
+            setArray(new Object[0]);
+        }
+    }
+
+    /**
+     * Appends all of the elements in the specified collection to the end
+     * of this list, in the order that they are returned by the specified
+     * collection's iterator.
+     *
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
+            ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
+        if (cs.length == 0)
+            return false;
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (len == 0 && cs.getClass() == Object[].class)
+                setArray(cs);
+            else {
+                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
+                System.arraycopy(cs, 0, newElements, len, cs.length);
+                setArray(newElements);
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Inserts all of the elements in the specified collection into this
+     * list, starting at the specified position.  Shifts the element
+     * currently at that position (if any) and any subsequent elements to
+     * the right (increases their indices).  The new elements will appear
+     * in this list in the order that they are returned by the
+     * specified collection's iterator.
+     *
+     * @param index index at which to insert the first element
+     *        from the specified collection
+     * @param c collection containing elements to be added to this list
+     * @return {@code true} if this list changed as a result of the call
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(int,Object)
+     */
+    public boolean addAll(int index, Collection<? extends E> c) {
+        Object[] cs = c.toArray();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (index > len || index < 0)
+                throw new IndexOutOfBoundsException(outOfBounds(index, len));
+            if (cs.length == 0)
+                return false;
+            int numMoved = len - index;
+            Object[] newElements;
+            if (numMoved == 0)
+                newElements = Arrays.copyOf(elements, len + cs.length);
+            else {
+                newElements = new Object[len + cs.length];
+                System.arraycopy(elements, 0, newElements, 0, index);
+                System.arraycopy(elements, index,
+                                 newElements, index + cs.length,
+                                 numMoved);
+            }
+            System.arraycopy(cs, 0, newElements, index, cs.length);
+            setArray(newElements);
+            return true;
+        }
+    }
+
+    public void forEach(Consumer<? super E> action) {
+        if (action == null) throw new NullPointerException();
+        for (Object x : getArray()) {
+            @SuppressWarnings("unchecked") E e = (E) x;
+            action.accept(e);
+        }
+    }
+
+    public boolean removeIf(Predicate<? super E> filter) {
+        if (filter == null) throw new NullPointerException();
+        synchronized (lock) {
+            final Object[] elements = getArray();
+            final int len = elements.length;
+            int i;
+            for (i = 0; i < len; i++) {
+                @SuppressWarnings("unchecked") E e = (E) elements[i];
+                if (filter.test(e)) {
+                    int newlen = i;
+                    final Object[] newElements = new Object[len - 1];
+                    System.arraycopy(elements, 0, newElements, 0, newlen);
+                    for (i++; i < len; i++) {
+                        @SuppressWarnings("unchecked") E x = (E) elements[i];
+                        if (!filter.test(x))
+                            newElements[newlen++] = x;
+                    }
+                    setArray((newlen == len - 1)
+                             ? newElements // one match => one copy
+                             : Arrays.copyOf(newElements, newlen));
+                    return true;
+                }
+            }
+            return false;       // zero matches => zero copies
+        }
+    }
+
+    public void replaceAll(UnaryOperator<E> operator) {
+        if (operator == null) throw new NullPointerException();
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            Object[] newElements = Arrays.copyOf(elements, len);
+            for (int i = 0; i < len; ++i) {
+                @SuppressWarnings("unchecked") E e = (E) elements[i];
+                newElements[i] = operator.apply(e);
+            }
+            setArray(newElements);
+        }
+    }
+
+    public void sort(Comparator<? super E> c) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            Object[] newElements = Arrays.copyOf(elements, elements.length);
+            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
+            Arrays.sort(es, c);
+            setArray(newElements);
+        }
+    }
+
+    /**
+     * Saves this list to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The length of the array backing the list is emitted
+     *               (int), followed by all of its elements (each an Object)
+     *               in the proper order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        s.defaultWriteObject();
+
+        Object[] elements = getArray();
+        // Write out array length
+        s.writeInt(elements.length);
+
+        // Write out all elements in the proper order.
+        for (Object element : elements)
+            s.writeObject(element);
+    }
+
+    /**
+     * Reconstitutes this list from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        s.defaultReadObject();
+
+        // bind to new lock
+        resetLock();
+
+        // Read in array length and allocate array
+        int len = s.readInt();
+        Object[] elements = new Object[len];
+
+        // Read in all elements in the proper order.
+        for (int i = 0; i < len; i++)
+            elements[i] = s.readObject();
+        setArray(elements);
+    }
+
+    /**
+     * Returns a string representation of this list.  The string
+     * representation consists of the string representations of the list's
+     * elements in the order they are returned by its iterator, enclosed in
+     * square brackets ({@code "[]"}).  Adjacent elements are separated by
+     * the characters {@code ", "} (comma and space).  Elements are
+     * converted to strings as by {@link String#valueOf(Object)}.
+     *
+     * @return a string representation of this list
+     */
+    public String toString() {
+        return Arrays.toString(getArray());
+    }
+
+    /**
+     * Compares the specified object with this list for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link List} and the sequence
+     * of elements returned by an {@linkplain List#iterator() iterator}
+     * over the specified list is the same as the sequence returned by
+     * an iterator over this list.  The two sequences are considered to
+     * be the same if they have the same length and corresponding
+     * elements at the same position in the sequence are <em>equal</em>.
+     * Two elements {@code e1} and {@code e2} are considered
+     * <em>equal</em> if {@code Objects.equals(e1, e2)}.
+     *
+     * @param o the object to be compared for equality with this list
+     * @return {@code true} if the specified object is equal to this list
+     */
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (!(o instanceof List))
+            return false;
+
+        List<?> list = (List<?>)o;
+        Iterator<?> it = list.iterator();
+        Object[] elements = getArray();
+        for (int i = 0, len = elements.length; i < len; i++)
+            if (!it.hasNext() || !Objects.equals(elements[i], it.next()))
+                return false;
+        if (it.hasNext())
+            return false;
+        return true;
+    }
+
+    /**
+     * Returns the hash code value for this list.
+     *
+     * <p>This implementation uses the definition in {@link List#hashCode}.
+     *
+     * @return the hash code value for this list
+     */
+    public int hashCode() {
+        int hashCode = 1;
+        for (Object x : getArray())
+            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+        return hashCode;
+    }
+
+    /**
+     * Returns an iterator over the elements in this list in proper sequence.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove} method.
+     *
+     * @return an iterator over the elements in this list in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new COWIterator<E>(getArray(), 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove}, {@code set} or {@code add} methods.
+     */
+    public ListIterator<E> listIterator() {
+        return new COWIterator<E>(getArray(), 0);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The returned iterator provides a snapshot of the state of the list
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove}, {@code set} or {@code add} methods.
+     *
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public ListIterator<E> listIterator(int index) {
+        Object[] elements = getArray();
+        int len = elements.length;
+        if (index < 0 || index > len)
+            throw new IndexOutOfBoundsException(outOfBounds(index, len));
+
+        return new COWIterator<E>(elements, index);
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#ORDERED}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the list
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (getArray(), Spliterator.IMMUTABLE | Spliterator.ORDERED);
+    }
+
+    static final class COWIterator<E> implements ListIterator<E> {
+        /** Snapshot of the array */
+        private final Object[] snapshot;
+        /** Index of element to be returned by subsequent call to next.  */
+        private int cursor;
+
+        COWIterator(Object[] elements, int initialCursor) {
+            cursor = initialCursor;
+            snapshot = elements;
+        }
+
+        public boolean hasNext() {
+            return cursor < snapshot.length;
+        }
+
+        public boolean hasPrevious() {
+            return cursor > 0;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (! hasNext())
+                throw new NoSuchElementException();
+            return (E) snapshot[cursor++];
+        }
+
+        @SuppressWarnings("unchecked")
+        public E previous() {
+            if (! hasPrevious())
+                throw new NoSuchElementException();
+            return (E) snapshot[--cursor];
+        }
+
+        public int nextIndex() {
+            return cursor;
+        }
+
+        public int previousIndex() {
+            return cursor-1;
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code remove}
+         *         is not supported by this iterator.
+         */
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code set}
+         *         is not supported by this iterator.
+         */
+        public void set(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Not supported. Always throws UnsupportedOperationException.
+         * @throws UnsupportedOperationException always; {@code add}
+         *         is not supported by this iterator.
+         */
+        public void add(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            final int size = snapshot.length;
+            for (int i = cursor; i < size; i++) {
+                action.accept((E) snapshot[i]);
+            }
+            cursor = size;
+        }
+    }
+
+    /**
+     * Returns a view of the portion of this list between
+     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
+     * The returned list is backed by this list, so changes in the
+     * returned list are reflected in this list.
+     *
+     * <p>The semantics of the list returned by this method become
+     * undefined if the backing list (i.e., this list) is modified in
+     * any way other than via the returned list.
+     *
+     * @param fromIndex low endpoint (inclusive) of the subList
+     * @param toIndex high endpoint (exclusive) of the subList
+     * @return a view of the specified range within this list
+     * @throws IndexOutOfBoundsException {@inheritDoc}
+     */
+    public List<E> subList(int fromIndex, int toIndex) {
+        synchronized (lock) {
+            Object[] elements = getArray();
+            int len = elements.length;
+            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
+                throw new IndexOutOfBoundsException();
+            return new COWSubList<E>(this, fromIndex, toIndex);
+        }
+    }
+
+    /**
+     * Sublist for CopyOnWriteArrayList.
+     * This class extends AbstractList merely for convenience, to
+     * avoid having to define addAll, etc. This doesn't hurt, but
+     * is wasteful.  This class does not need or use modCount
+     * mechanics in AbstractList, but does need to check for
+     * concurrent modification using similar mechanics.  On each
+     * operation, the array that we expect the backing list to use
+     * is checked and updated.  Since we do this for all of the
+     * base operations invoked by those defined in AbstractList,
+     * all is well.  While inefficient, this is not worth
+     * improving.  The kinds of list operations inherited from
+     * AbstractList are already so slow on COW sublists that
+     * adding a bit more space/time doesn't seem even noticeable.
+     */
+    private static class COWSubList<E>
+        extends AbstractList<E>
+        implements RandomAccess
+    {
+        private final CopyOnWriteArrayList<E> l;
+        private final int offset;
+        private int size;
+        private Object[] expectedArray;
+
+        // only call this holding l's lock
+        COWSubList(CopyOnWriteArrayList<E> list,
+                   int fromIndex, int toIndex) {
+            // assert Thread.holdsLock(list.lock);
+            l = list;
+            expectedArray = l.getArray();
+            offset = fromIndex;
+            size = toIndex - fromIndex;
+        }
+
+        // only call this holding l's lock
+        private void checkForComodification() {
+            // assert Thread.holdsLock(l.lock);
+            if (l.getArray() != expectedArray)
+                throw new ConcurrentModificationException();
+        }
+
+        // only call this holding l's lock
+        private void rangeCheck(int index) {
+            // assert Thread.holdsLock(l.lock);
+            if (index < 0 || index >= size)
+                throw new IndexOutOfBoundsException(outOfBounds(index, size));
+        }
+
+        public E set(int index, E element) {
+            synchronized (l.lock) {
+                rangeCheck(index);
+                checkForComodification();
+                E x = l.set(index+offset, element);
+                expectedArray = l.getArray();
+                return x;
+            }
+        }
+
+        public E get(int index) {
+            synchronized (l.lock) {
+                rangeCheck(index);
+                checkForComodification();
+                return l.get(index+offset);
+            }
+        }
+
+        public int size() {
+            synchronized (l.lock) {
+                checkForComodification();
+                return size;
+            }
+        }
+
+        public void add(int index, E element) {
+            synchronized (l.lock) {
+                checkForComodification();
+                if (index < 0 || index > size)
+                    throw new IndexOutOfBoundsException
+                        (outOfBounds(index, size));
+                l.add(index+offset, element);
+                expectedArray = l.getArray();
+                size++;
+            }
+        }
+
+        public void clear() {
+            synchronized (l.lock) {
+                checkForComodification();
+                l.removeRange(offset, offset+size);
+                expectedArray = l.getArray();
+                size = 0;
+            }
+        }
+
+        public E remove(int index) {
+            synchronized (l.lock) {
+                rangeCheck(index);
+                checkForComodification();
+                E result = l.remove(index+offset);
+                expectedArray = l.getArray();
+                size--;
+                return result;
+            }
+        }
+
+        public boolean remove(Object o) {
+            int index = indexOf(o);
+            if (index == -1)
+                return false;
+            remove(index);
+            return true;
+        }
+
+        public Iterator<E> iterator() {
+            synchronized (l.lock) {
+                checkForComodification();
+                return new COWSubListIterator<E>(l, 0, offset, size);
+            }
+        }
+
+        public ListIterator<E> listIterator(int index) {
+            synchronized (l.lock) {
+                checkForComodification();
+                if (index < 0 || index > size)
+                    throw new IndexOutOfBoundsException
+                        (outOfBounds(index, size));
+                return new COWSubListIterator<E>(l, index, offset, size);
+            }
+        }
+
+        public List<E> subList(int fromIndex, int toIndex) {
+            synchronized (l.lock) {
+                checkForComodification();
+                if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
+                    throw new IndexOutOfBoundsException();
+                return new COWSubList<E>(l, fromIndex + offset,
+                                         toIndex + offset);
+            }
+        }
+
+        public void forEach(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            int lo = offset;
+            int hi = offset + size;
+            Object[] a = expectedArray;
+            if (l.getArray() != a)
+                throw new ConcurrentModificationException();
+            if (lo < 0 || hi > a.length)
+                throw new IndexOutOfBoundsException();
+            for (int i = lo; i < hi; ++i) {
+                @SuppressWarnings("unchecked") E e = (E) a[i];
+                action.accept(e);
+            }
+        }
+
+        public void replaceAll(UnaryOperator<E> operator) {
+            if (operator == null) throw new NullPointerException();
+            synchronized (l.lock) {
+                int lo = offset;
+                int hi = offset + size;
+                Object[] elements = expectedArray;
+                if (l.getArray() != elements)
+                    throw new ConcurrentModificationException();
+                int len = elements.length;
+                if (lo < 0 || hi > len)
+                    throw new IndexOutOfBoundsException();
+                Object[] newElements = Arrays.copyOf(elements, len);
+                for (int i = lo; i < hi; ++i) {
+                    @SuppressWarnings("unchecked") E e = (E) elements[i];
+                    newElements[i] = operator.apply(e);
+                }
+                l.setArray(expectedArray = newElements);
+            }
+        }
+
+        public void sort(Comparator<? super E> c) {
+            synchronized (l.lock) {
+                int lo = offset;
+                int hi = offset + size;
+                Object[] elements = expectedArray;
+                if (l.getArray() != elements)
+                    throw new ConcurrentModificationException();
+                int len = elements.length;
+                if (lo < 0 || hi > len)
+                    throw new IndexOutOfBoundsException();
+                Object[] newElements = Arrays.copyOf(elements, len);
+                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
+                Arrays.sort(es, lo, hi, c);
+                l.setArray(expectedArray = newElements);
+            }
+        }
+
+        public boolean removeAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        Object element = elements[i];
+                        if (!c.contains(element))
+                            temp[newSize++] = element;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[len - n + newSize];
+                        System.arraycopy(elements, 0, newElements, 0, lo);
+                        System.arraycopy(temp, 0, newElements, lo, newSize);
+                        System.arraycopy(elements, hi, newElements,
+                                         lo + newSize, len - hi);
+                        size = newSize;
+                        removed = true;
+                        l.setArray(expectedArray = newElements);
+                    }
+                }
+            }
+            return removed;
+        }
+
+        public boolean retainAll(Collection<?> c) {
+            if (c == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        Object element = elements[i];
+                        if (c.contains(element))
+                            temp[newSize++] = element;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[len - n + newSize];
+                        System.arraycopy(elements, 0, newElements, 0, lo);
+                        System.arraycopy(temp, 0, newElements, lo, newSize);
+                        System.arraycopy(elements, hi, newElements,
+                                         lo + newSize, len - hi);
+                        size = newSize;
+                        removed = true;
+                        l.setArray(expectedArray = newElements);
+                    }
+                }
+            }
+            return removed;
+        }
+
+        public boolean removeIf(Predicate<? super E> filter) {
+            if (filter == null) throw new NullPointerException();
+            boolean removed = false;
+            synchronized (l.lock) {
+                int n = size;
+                if (n > 0) {
+                    int lo = offset;
+                    int hi = offset + n;
+                    Object[] elements = expectedArray;
+                    if (l.getArray() != elements)
+                        throw new ConcurrentModificationException();
+                    int len = elements.length;
+                    if (lo < 0 || hi > len)
+                        throw new IndexOutOfBoundsException();
+                    int newSize = 0;
+                    Object[] temp = new Object[n];
+                    for (int i = lo; i < hi; ++i) {
+                        @SuppressWarnings("unchecked") E e = (E) elements[i];
+                        if (!filter.test(e))
+                            temp[newSize++] = e;
+                    }
+                    if (newSize != n) {
+                        Object[] newElements = new Object[len - n + newSize];
+                        System.arraycopy(elements, 0, newElements, 0, lo);
+                        System.arraycopy(temp, 0, newElements, lo, newSize);
+                        System.arraycopy(elements, hi, newElements,
+                                         lo + newSize, len - hi);
+                        size = newSize;
+                        removed = true;
+                        l.setArray(expectedArray = newElements);
+                    }
+                }
+            }
+            return removed;
+        }
+
+        public Spliterator<E> spliterator() {
+            int lo = offset;
+            int hi = offset + size;
+            Object[] a = expectedArray;
+            if (l.getArray() != a)
+                throw new ConcurrentModificationException();
+            if (lo < 0 || hi > a.length)
+                throw new IndexOutOfBoundsException();
+            return Spliterators.spliterator
+                (a, lo, hi, Spliterator.IMMUTABLE | Spliterator.ORDERED);
+        }
+
+    }
+
+    private static class COWSubListIterator<E> implements ListIterator<E> {
+        private final ListIterator<E> it;
+        private final int offset;
+        private final int size;
+
+        COWSubListIterator(List<E> l, int index, int offset, int size) {
+            this.offset = offset;
+            this.size = size;
+            it = l.listIterator(index+offset);
+        }
+
+        public boolean hasNext() {
+            return nextIndex() < size;
+        }
+
+        public E next() {
+            if (hasNext())
+                return it.next();
+            else
+                throw new NoSuchElementException();
+        }
+
+        public boolean hasPrevious() {
+            return previousIndex() >= 0;
+        }
+
+        public E previous() {
+            if (hasPrevious())
+                return it.previous();
+            else
+                throw new NoSuchElementException();
+        }
+
+        public int nextIndex() {
+            return it.nextIndex() - offset;
+        }
+
+        public int previousIndex() {
+            return it.previousIndex() - offset;
+        }
+
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void set(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void add(E e) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Objects.requireNonNull(action);
+            while (nextIndex() < size) {
+                action.accept(it.next());
+            }
+        }
+    }
+
+    // Support for resetting lock while deserializing
+    private void resetLock() {
+        U.putObjectVolatile(this, LOCK, new Object());
+    }
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long LOCK;
+    static {
+        try {
+            LOCK = U.objectFieldOffset
+                (CopyOnWriteArrayList.class.getDeclaredField("lock"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/CopyOnWriteArraySet.java b/java/util/concurrent/CopyOnWriteArraySet.java
new file mode 100644
index 0000000..fb707dd
--- /dev/null
+++ b/java/util/concurrent/CopyOnWriteArraySet.java
@@ -0,0 +1,442 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// fixed framework docs link to "Collection#optional"
+// END android-note
+
+/**
+ * A {@link java.util.Set} that uses an internal {@link CopyOnWriteArrayList}
+ * for all of its operations.  Thus, it shares the same basic properties:
+ * <ul>
+ *  <li>It is best suited for applications in which set sizes generally
+ *       stay small, read-only operations
+ *       vastly outnumber mutative operations, and you need
+ *       to prevent interference among threads during traversal.
+ *  <li>It is thread-safe.
+ *  <li>Mutative operations ({@code add}, {@code set}, {@code remove}, etc.)
+ *      are expensive since they usually entail copying the entire underlying
+ *      array.
+ *  <li>Iterators do not support the mutative {@code remove} operation.
+ *  <li>Traversal via iterators is fast and cannot encounter
+ *      interference from other threads. Iterators rely on
+ *      unchanging snapshots of the array at the time the iterators were
+ *      constructed.
+ * </ul>
+ *
+ * <p><b>Sample Usage.</b> The following code sketch uses a
+ * copy-on-write set to maintain a set of Handler objects that
+ * perform some action upon state updates.
+ *
+ * <pre> {@code
+ * class Handler { void handle(); ... }
+ *
+ * class X {
+ *   private final CopyOnWriteArraySet<Handler> handlers
+ *     = new CopyOnWriteArraySet<>();
+ *   public void addHandler(Handler h) { handlers.add(h); }
+ *
+ *   private long internalState;
+ *   private synchronized void changeState() { internalState = ...; }
+ *
+ *   public void update() {
+ *     changeState();
+ *     for (Handler handler : handlers)
+ *       handler.handle();
+ *   }
+ * }}</pre>
+ *
+ * @see CopyOnWriteArrayList
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this set
+ */
+public class CopyOnWriteArraySet<E> extends AbstractSet<E>
+        implements java.io.Serializable {
+    private static final long serialVersionUID = 5457747651344034263L;
+
+    private final CopyOnWriteArrayList<E> al;
+
+    /**
+     * Creates an empty set.
+     */
+    public CopyOnWriteArraySet() {
+        al = new CopyOnWriteArrayList<E>();
+    }
+
+    /**
+     * Creates a set containing all of the elements of the specified
+     * collection.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection is null
+     */
+    public CopyOnWriteArraySet(Collection<? extends E> c) {
+        if (c.getClass() == CopyOnWriteArraySet.class) {
+            @SuppressWarnings("unchecked") CopyOnWriteArraySet<E> cc =
+                (CopyOnWriteArraySet<E>)c;
+            al = new CopyOnWriteArrayList<E>(cc.al);
+        }
+        else {
+            al = new CopyOnWriteArrayList<E>();
+            al.addAllAbsent(c);
+        }
+    }
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @return the number of elements in this set
+     */
+    public int size() {
+        return al.size();
+    }
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @return {@code true} if this set contains no elements
+     */
+    public boolean isEmpty() {
+        return al.isEmpty();
+    }
+
+    /**
+     * Returns {@code true} if this set contains the specified element.
+     * More formally, returns {@code true} if and only if this set
+     * contains an element {@code e} such that {@code Objects.equals(o, e)}.
+     *
+     * @param o element whose presence in this set is to be tested
+     * @return {@code true} if this set contains the specified element
+     */
+    public boolean contains(Object o) {
+        return al.contains(o);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set.
+     * If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the
+     * elements in the same order.
+     *
+     * <p>The returned array will be "safe" in that no references to it
+     * are maintained by this set.  (In other words, this method must
+     * allocate a new array even if this set is backed by an array).
+     * The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all the elements in this set
+     */
+    public Object[] toArray() {
+        return al.toArray();
+    }
+
+    /**
+     * Returns an array containing all of the elements in this set; the
+     * runtime type of the returned array is that of the specified array.
+     * If the set fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this set.
+     *
+     * <p>If this set fits in the specified array with room to spare
+     * (i.e., the array has more elements than this set), the element in
+     * the array immediately following the end of the set is set to
+     * {@code null}.  (This is useful in determining the length of this
+     * set <i>only</i> if the caller knows that this set does not contain
+     * any null elements.)
+     *
+     * <p>If this set makes any guarantees as to what order its elements
+     * are returned by its iterator, this method must return the elements
+     * in the same order.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a set known to contain only strings.
+     * The following code can be used to dump the set into a newly allocated
+     * array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of this set are to be
+     *        stored, if it is big enough; otherwise, a new array of the same
+     *        runtime type is allocated for this purpose.
+     * @return an array containing all the elements in this set
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in this
+     *         set
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        return al.toArray(a);
+    }
+
+    /**
+     * Removes all of the elements from this set.
+     * The set will be empty after this call returns.
+     */
+    public void clear() {
+        al.clear();
+    }
+
+    /**
+     * Removes the specified element from this set if it is present.
+     * More formally, removes an element {@code e} such that
+     * {@code Objects.equals(o, e)}, if this set contains such an element.
+     * Returns {@code true} if this set contained the element (or
+     * equivalently, if this set changed as a result of the call).
+     * (This set will not contain the element once the call returns.)
+     *
+     * @param o object to be removed from this set, if present
+     * @return {@code true} if this set contained the specified element
+     */
+    public boolean remove(Object o) {
+        return al.remove(o);
+    }
+
+    /**
+     * Adds the specified element to this set if it is not already present.
+     * More formally, adds the specified element {@code e} to this set if
+     * the set contains no element {@code e2} such that
+     * {@code Objects.equals(e, e2)}.
+     * If this set already contains the element, the call leaves the set
+     * unchanged and returns {@code false}.
+     *
+     * @param e element to be added to this set
+     * @return {@code true} if this set did not already contain the specified
+     *         element
+     */
+    public boolean add(E e) {
+        return al.addIfAbsent(e);
+    }
+
+    /**
+     * Returns {@code true} if this set contains all of the elements of the
+     * specified collection.  If the specified collection is also a set, this
+     * method returns {@code true} if it is a <i>subset</i> of this set.
+     *
+     * @param  c collection to be checked for containment in this set
+     * @return {@code true} if this set contains all of the elements of the
+     *         specified collection
+     * @throws NullPointerException if the specified collection is null
+     * @see #contains(Object)
+     */
+    public boolean containsAll(Collection<?> c) {
+        return (c instanceof Set)
+            ? compareSets(al.getArray(), (Set<?>) c) >= 0
+            : al.containsAll(c);
+    }
+
+    /**
+     * Tells whether the objects in snapshot (regarded as a set) are a
+     * superset of the given set.
+     *
+     * @return -1 if snapshot is not a superset, 0 if the two sets
+     * contain precisely the same elements, and 1 if snapshot is a
+     * proper superset of the given set
+     */
+    private static int compareSets(Object[] snapshot, Set<?> set) {
+        // Uses O(n^2) algorithm, that is only appropriate for small
+        // sets, which CopyOnWriteArraySets should be.
+        //
+        // Optimize up to O(n) if the two sets share a long common prefix,
+        // as might happen if one set was created as a copy of the other set.
+
+        final int len = snapshot.length;
+        // Mark matched elements to avoid re-checking
+        final boolean[] matched = new boolean[len];
+
+        // j is the largest int with matched[i] true for { i | 0 <= i < j }
+        int j = 0;
+        outer: for (Object x : set) {
+            for (int i = j; i < len; i++) {
+                if (!matched[i] && Objects.equals(x, snapshot[i])) {
+                    matched[i] = true;
+                    if (i == j)
+                        do { j++; } while (j < len && matched[j]);
+                    continue outer;
+                }
+            }
+            return -1;
+        }
+        return (j == len) ? 0 : 1;
+    }
+
+    /**
+     * Adds all of the elements in the specified collection to this set if
+     * they're not already present.  If the specified collection is also a
+     * set, the {@code addAll} operation effectively modifies this set so
+     * that its value is the <i>union</i> of the two sets.  The behavior of
+     * this operation is undefined if the specified collection is modified
+     * while the operation is in progress.
+     *
+     * @param  c collection containing elements to be added to this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws NullPointerException if the specified collection is null
+     * @see #add(Object)
+     */
+    public boolean addAll(Collection<? extends E> c) {
+        return al.addAllAbsent(c) > 0;
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in the
+     * specified collection.  If the specified collection is also a set,
+     * this operation effectively modifies this set so that its value is the
+     * <i>asymmetric set difference</i> of the two sets.
+     *
+     * @param  c collection containing elements to be removed from this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean removeAll(Collection<?> c) {
+        return al.removeAll(c);
+    }
+
+    /**
+     * Retains only the elements in this set that are contained in the
+     * specified collection.  In other words, removes from this set all of
+     * its elements that are not contained in the specified collection.  If
+     * the specified collection is also a set, this operation effectively
+     * modifies this set so that its value is the <i>intersection</i> of the
+     * two sets.
+     *
+     * @param  c collection containing elements to be retained in this set
+     * @return {@code true} if this set changed as a result of the call
+     * @throws ClassCastException if the class of an element of this set
+     *         is incompatible with the specified collection
+     * (<a href="../Collection.html#optional-restrictions">optional</a>)
+     * @throws NullPointerException if this set contains a null element and the
+     *         specified collection does not permit null elements
+     * (<a href="../Collection.html#optional-restrictions">optional</a>),
+     *         or if the specified collection is null
+     * @see #remove(Object)
+     */
+    public boolean retainAll(Collection<?> c) {
+        return al.retainAll(c);
+    }
+
+    /**
+     * Returns an iterator over the elements contained in this set
+     * in the order in which these elements were added.
+     *
+     * <p>The returned iterator provides a snapshot of the state of the set
+     * when the iterator was constructed. No synchronization is needed while
+     * traversing the iterator. The iterator does <em>NOT</em> support the
+     * {@code remove} method.
+     *
+     * @return an iterator over the elements in this set
+     */
+    public Iterator<E> iterator() {
+        return al.iterator();
+    }
+
+    /**
+     * Compares the specified object with this set for equality.
+     * Returns {@code true} if the specified object is the same object
+     * as this object, or if it is also a {@link Set} and the elements
+     * returned by an {@linkplain Set#iterator() iterator} over the
+     * specified set are the same as the elements returned by an
+     * iterator over this set.  More formally, the two iterators are
+     * considered to return the same elements if they return the same
+     * number of elements and for every element {@code e1} returned by
+     * the iterator over the specified set, there is an element
+     * {@code e2} returned by the iterator over this set such that
+     * {@code Objects.equals(e1, e2)}.
+     *
+     * @param o object to be compared for equality with this set
+     * @return {@code true} if the specified object is equal to this set
+     */
+    public boolean equals(Object o) {
+        return (o == this)
+            || ((o instanceof Set)
+                && compareSets(al.getArray(), (Set<?>) o) == 0);
+    }
+
+    public boolean removeIf(Predicate<? super E> filter) {
+        return al.removeIf(filter);
+    }
+
+    public void forEach(Consumer<? super E> action) {
+        al.forEach(action);
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this set in the order
+     * in which these elements were added.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the set
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.spliterator
+            (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
+    }
+}
diff --git a/java/util/concurrent/CountDownLatch.java b/java/util/concurrent/CountDownLatch.java
new file mode 100644
index 0000000..8d85418
--- /dev/null
+++ b/java/util/concurrent/CountDownLatch.java
@@ -0,0 +1,316 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * A synchronization aid that allows one or more threads to wait until
+ * a set of operations being performed in other threads completes.
+ *
+ * <p>A {@code CountDownLatch} is initialized with a given <em>count</em>.
+ * The {@link #await await} methods block until the current count reaches
+ * zero due to invocations of the {@link #countDown} method, after which
+ * all waiting threads are released and any subsequent invocations of
+ * {@link #await await} return immediately.  This is a one-shot phenomenon
+ * -- the count cannot be reset.  If you need a version that resets the
+ * count, consider using a {@link CyclicBarrier}.
+ *
+ * <p>A {@code CountDownLatch} is a versatile synchronization tool
+ * and can be used for a number of purposes.  A
+ * {@code CountDownLatch} initialized with a count of one serves as a
+ * simple on/off latch, or gate: all threads invoking {@link #await await}
+ * wait at the gate until it is opened by a thread invoking {@link
+ * #countDown}.  A {@code CountDownLatch} initialized to <em>N</em>
+ * can be used to make one thread wait until <em>N</em> threads have
+ * completed some action, or some action has been completed N times.
+ *
+ * <p>A useful property of a {@code CountDownLatch} is that it
+ * doesn't require that threads calling {@code countDown} wait for
+ * the count to reach zero before proceeding, it simply prevents any
+ * thread from proceeding past an {@link #await await} until all
+ * threads could pass.
+ *
+ * <p><b>Sample usage:</b> Here is a pair of classes in which a group
+ * of worker threads use two countdown latches:
+ * <ul>
+ * <li>The first is a start signal that prevents any worker from proceeding
+ * until the driver is ready for them to proceed;
+ * <li>The second is a completion signal that allows the driver to wait
+ * until all workers have completed.
+ * </ul>
+ *
+ * <pre> {@code
+ * class Driver { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch startSignal = new CountDownLatch(1);
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       new Thread(new Worker(startSignal, doneSignal)).start();
+ *
+ *     doSomethingElse();            // don't let run yet
+ *     startSignal.countDown();      // let all threads proceed
+ *     doSomethingElse();
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class Worker implements Runnable {
+ *   private final CountDownLatch startSignal;
+ *   private final CountDownLatch doneSignal;
+ *   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
+ *     this.startSignal = startSignal;
+ *     this.doneSignal = doneSignal;
+ *   }
+ *   public void run() {
+ *     try {
+ *       startSignal.await();
+ *       doWork();
+ *       doneSignal.countDown();
+ *     } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }}</pre>
+ *
+ * <p>Another typical usage would be to divide a problem into N parts,
+ * describe each part with a Runnable that executes that portion and
+ * counts down on the latch, and queue all the Runnables to an
+ * Executor.  When all sub-parts are complete, the coordinating thread
+ * will be able to pass through await. (When threads must repeatedly
+ * count down in this way, instead use a {@link CyclicBarrier}.)
+ *
+ * <pre> {@code
+ * class Driver2 { // ...
+ *   void main() throws InterruptedException {
+ *     CountDownLatch doneSignal = new CountDownLatch(N);
+ *     Executor e = ...
+ *
+ *     for (int i = 0; i < N; ++i) // create and start threads
+ *       e.execute(new WorkerRunnable(doneSignal, i));
+ *
+ *     doneSignal.await();           // wait for all to finish
+ *   }
+ * }
+ *
+ * class WorkerRunnable implements Runnable {
+ *   private final CountDownLatch doneSignal;
+ *   private final int i;
+ *   WorkerRunnable(CountDownLatch doneSignal, int i) {
+ *     this.doneSignal = doneSignal;
+ *     this.i = i;
+ *   }
+ *   public void run() {
+ *     try {
+ *       doWork(i);
+ *       doneSignal.countDown();
+ *     } catch (InterruptedException ex) {} // return;
+ *   }
+ *
+ *   void doWork() { ... }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: Until the count reaches
+ * zero, actions in a thread prior to calling
+ * {@code countDown()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions following a successful return from a corresponding
+ * {@code await()} in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class CountDownLatch {
+    /**
+     * Synchronization control For CountDownLatch.
+     * Uses AQS state to represent count.
+     */
+    private static final class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 4982264981922014374L;
+
+        Sync(int count) {
+            setState(count);
+        }
+
+        int getCount() {
+            return getState();
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            return (getState() == 0) ? 1 : -1;
+        }
+
+        protected boolean tryReleaseShared(int releases) {
+            // Decrement count; signal when transition to zero
+            for (;;) {
+                int c = getState();
+                if (c == 0)
+                    return false;
+                int nextc = c - 1;
+                if (compareAndSetState(c, nextc))
+                    return nextc == 0;
+            }
+        }
+    }
+
+    private final Sync sync;
+
+    /**
+     * Constructs a {@code CountDownLatch} initialized with the given count.
+     *
+     * @param count the number of times {@link #countDown} must be invoked
+     *        before threads can pass through {@link #await}
+     * @throws IllegalArgumentException if {@code count} is negative
+     */
+    public CountDownLatch(int count) {
+        if (count < 0) throw new IllegalArgumentException("count < 0");
+        this.sync = new Sync(count);
+    }
+
+    /**
+     * Causes the current thread to wait until the latch has counted down to
+     * zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>If the current count is zero then this method returns immediately.
+     *
+     * <p>If the current count is greater than zero then the current
+     * thread becomes disabled for thread scheduling purposes and lies
+     * dormant until one of two things happen:
+     * <ul>
+     * <li>The count reaches zero due to invocations of the
+     * {@link #countDown} method; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting
+     */
+    public void await() throws InterruptedException {
+        sync.acquireSharedInterruptibly(1);
+    }
+
+    /**
+     * Causes the current thread to wait until the latch has counted down to
+     * zero, unless the thread is {@linkplain Thread#interrupt interrupted},
+     * or the specified waiting time elapses.
+     *
+     * <p>If the current count is zero then this method returns immediately
+     * with the value {@code true}.
+     *
+     * <p>If the current count is greater than zero then the current
+     * thread becomes disabled for thread scheduling purposes and lies
+     * dormant until one of three things happen:
+     * <ul>
+     * <li>The count reaches zero due to invocations of the
+     * {@link #countDown} method; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If the count reaches zero then the method returns with the
+     * value {@code true}.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if the count reached zero and {@code false}
+     *         if the waiting time elapsed before the count reached zero
+     * @throws InterruptedException if the current thread is interrupted
+     *         while waiting
+     */
+    public boolean await(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Decrements the count of the latch, releasing all waiting threads if
+     * the count reaches zero.
+     *
+     * <p>If the current count is greater than zero then it is decremented.
+     * If the new count is zero then all waiting threads are re-enabled for
+     * thread scheduling purposes.
+     *
+     * <p>If the current count equals zero then nothing happens.
+     */
+    public void countDown() {
+        sync.releaseShared(1);
+    }
+
+    /**
+     * Returns the current count.
+     *
+     * <p>This method is typically used for debugging and testing purposes.
+     *
+     * @return the current count
+     */
+    public long getCount() {
+        return sync.getCount();
+    }
+
+    /**
+     * Returns a string identifying this latch, as well as its state.
+     * The state, in brackets, includes the String {@code "Count ="}
+     * followed by the current count.
+     *
+     * @return a string identifying this latch, as well as its state
+     */
+    public String toString() {
+        return super.toString() + "[Count = " + sync.getCount() + "]";
+    }
+}
diff --git a/java/util/concurrent/CountedCompleter.java b/java/util/concurrent/CountedCompleter.java
new file mode 100644
index 0000000..a29208e
--- /dev/null
+++ b/java/util/concurrent/CountedCompleter.java
@@ -0,0 +1,767 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link ForkJoinTask} with a completion action performed when
+ * triggered and there are no remaining pending actions.
+ * CountedCompleters are in general more robust in the
+ * presence of subtask stalls and blockage than are other forms of
+ * ForkJoinTasks, but are less intuitive to program.  Uses of
+ * CountedCompleter are similar to those of other completion based
+ * components (such as {@link java.nio.channels.CompletionHandler})
+ * except that multiple <em>pending</em> completions may be necessary
+ * to trigger the completion action {@link #onCompletion(CountedCompleter)},
+ * not just one.
+ * Unless initialized otherwise, the {@linkplain #getPendingCount pending
+ * count} starts at zero, but may be (atomically) changed using
+ * methods {@link #setPendingCount}, {@link #addToPendingCount}, and
+ * {@link #compareAndSetPendingCount}. Upon invocation of {@link
+ * #tryComplete}, if the pending action count is nonzero, it is
+ * decremented; otherwise, the completion action is performed, and if
+ * this completer itself has a completer, the process is continued
+ * with its completer.  As is the case with related synchronization
+ * components such as {@link java.util.concurrent.Phaser Phaser} and
+ * {@link java.util.concurrent.Semaphore Semaphore}, these methods
+ * affect only internal counts; they do not establish any further
+ * internal bookkeeping. In particular, the identities of pending
+ * tasks are not maintained. As illustrated below, you can create
+ * subclasses that do record some or all pending tasks or their
+ * results when needed.  As illustrated below, utility methods
+ * supporting customization of completion traversals are also
+ * provided. However, because CountedCompleters provide only basic
+ * synchronization mechanisms, it may be useful to create further
+ * abstract subclasses that maintain linkages, fields, and additional
+ * support methods appropriate for a set of related usages.
+ *
+ * <p>A concrete CountedCompleter class must define method {@link
+ * #compute}, that should in most cases (as illustrated below), invoke
+ * {@code tryComplete()} once before returning. The class may also
+ * optionally override method {@link #onCompletion(CountedCompleter)}
+ * to perform an action upon normal completion, and method
+ * {@link #onExceptionalCompletion(Throwable, CountedCompleter)} to
+ * perform an action upon any exception.
+ *
+ * <p>CountedCompleters most often do not bear results, in which case
+ * they are normally declared as {@code CountedCompleter<Void>}, and
+ * will always return {@code null} as a result value.  In other cases,
+ * you should override method {@link #getRawResult} to provide a
+ * result from {@code join(), invoke()}, and related methods.  In
+ * general, this method should return the value of a field (or a
+ * function of one or more fields) of the CountedCompleter object that
+ * holds the result upon completion. Method {@link #setRawResult} by
+ * default plays no role in CountedCompleters.  It is possible, but
+ * rarely applicable, to override this method to maintain other
+ * objects or fields holding result data.
+ *
+ * <p>A CountedCompleter that does not itself have a completer (i.e.,
+ * one for which {@link #getCompleter} returns {@code null}) can be
+ * used as a regular ForkJoinTask with this added functionality.
+ * However, any completer that in turn has another completer serves
+ * only as an internal helper for other computations, so its own task
+ * status (as reported in methods such as {@link ForkJoinTask#isDone})
+ * is arbitrary; this status changes only upon explicit invocations of
+ * {@link #complete}, {@link ForkJoinTask#cancel},
+ * {@link ForkJoinTask#completeExceptionally(Throwable)} or upon
+ * exceptional completion of method {@code compute}. Upon any
+ * exceptional completion, the exception may be relayed to a task's
+ * completer (and its completer, and so on), if one exists and it has
+ * not otherwise already completed. Similarly, cancelling an internal
+ * CountedCompleter has only a local effect on that completer, so is
+ * not often useful.
+ *
+ * <p><b>Sample Usages.</b>
+ *
+ * <p><b>Parallel recursive decomposition.</b> CountedCompleters may
+ * be arranged in trees similar to those often used with {@link
+ * RecursiveAction}s, although the constructions involved in setting
+ * them up typically vary. Here, the completer of each task is its
+ * parent in the computation tree. Even though they entail a bit more
+ * bookkeeping, CountedCompleters may be better choices when applying
+ * a possibly time-consuming operation (that cannot be further
+ * subdivided) to each element of an array or collection; especially
+ * when the operation takes a significantly different amount of time
+ * to complete for some elements than others, either because of
+ * intrinsic variation (for example I/O) or auxiliary effects such as
+ * garbage collection.  Because CountedCompleters provide their own
+ * continuations, other threads need not block waiting to perform
+ * them.
+ *
+ * <p>For example, here is an initial version of a class that uses
+ * divide-by-two recursive decomposition to divide work into single
+ * pieces (leaf tasks). Even when work is split into individual calls,
+ * tree-based techniques are usually preferable to directly forking
+ * leaf tasks, because they reduce inter-thread communication and
+ * improve load balancing. In the recursive case, the second of each
+ * pair of subtasks to finish triggers completion of its parent
+ * (because no result combination is performed, the default no-op
+ * implementation of method {@code onCompletion} is not overridden).
+ * A static utility method sets up the base task and invokes it
+ * (here, implicitly using the {@link ForkJoinPool#commonPool()}).
+ *
+ * <pre> {@code
+ * class MyOperation<E> { void apply(E e) { ... }  }
+ *
+ * class ForEach<E> extends CountedCompleter<Void> {
+ *
+ *   public static <E> void forEach(E[] array, MyOperation<E> op) {
+ *     new ForEach<E>(null, array, op, 0, array.length).invoke();
+ *   }
+ *
+ *   final E[] array; final MyOperation<E> op; final int lo, hi;
+ *   ForEach(CountedCompleter<?> p, E[] array, MyOperation<E> op, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.op = op; this.lo = lo; this.hi = hi;
+ *   }
+ *
+ *   public void compute() { // version 1
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(2); // must set pending count before fork
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).fork(); // left child
+ *     }
+ *     else if (hi > lo)
+ *       op.apply(array[lo]);
+ *     tryComplete();
+ *   }
+ * }}</pre>
+ *
+ * This design can be improved by noticing that in the recursive case,
+ * the task has nothing to do after forking its right task, so can
+ * directly invoke its left task before returning. (This is an analog
+ * of tail recursion removal.)  Also, because the task returns upon
+ * executing its left task (rather than falling through to invoke
+ * {@code tryComplete}) the pending count is set to one:
+ *
+ * <pre> {@code
+ * class ForEach<E> ... {
+ *   ...
+ *   public void compute() { // version 2
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       setPendingCount(1); // only one pending
+ *       new ForEach(this, array, op, mid, hi).fork(); // right child
+ *       new ForEach(this, array, op, lo, mid).compute(); // direct invoke
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *         op.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * As a further optimization, notice that the left task need not even exist.
+ * Instead of creating a new one, we can iterate using the original task,
+ * and add a pending count for each fork.  Additionally, because no task
+ * in this tree implements an {@link #onCompletion(CountedCompleter)} method,
+ * {@code tryComplete()} can be replaced with {@link #propagateCompletion}.
+ *
+ * <pre> {@code
+ * class ForEach<E> ... {
+ *   ...
+ *   public void compute() { // version 3
+ *     int l = lo, h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       new ForEach(this, array, op, mid, h).fork(); // right child
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       op.apply(array[l]);
+ *     propagateCompletion();
+ *   }
+ * }}</pre>
+ *
+ * Additional optimizations of such classes might entail precomputing
+ * pending counts so that they can be established in constructors,
+ * specializing classes for leaf steps, subdividing by say, four,
+ * instead of two per iteration, and using an adaptive threshold
+ * instead of always subdividing down to single elements.
+ *
+ * <p><b>Searching.</b> A tree of CountedCompleters can search for a
+ * value or property in different parts of a data structure, and
+ * report a result in an {@link
+ * java.util.concurrent.atomic.AtomicReference AtomicReference} as
+ * soon as one is found. The others can poll the result to avoid
+ * unnecessary work. (You could additionally {@linkplain #cancel
+ * cancel} other tasks, but it is usually simpler and more efficient
+ * to just let them notice that the result is set and if so skip
+ * further processing.)  Illustrating again with an array using full
+ * partitioning (again, in practice, leaf tasks will almost always
+ * process more than one element):
+ *
+ * <pre> {@code
+ * class Searcher<E> extends CountedCompleter<E> {
+ *   final E[] array; final AtomicReference<E> result; final int lo, hi;
+ *   Searcher(CountedCompleter<?> p, E[] array, AtomicReference<E> result, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.result = result; this.lo = lo; this.hi = hi;
+ *   }
+ *   public E getRawResult() { return result.get(); }
+ *   public void compute() { // similar to ForEach version 3
+ *     int l = lo, h = hi;
+ *     while (result.get() == null && h >= l) {
+ *       if (h - l >= 2) {
+ *         int mid = (l + h) >>> 1;
+ *         addToPendingCount(1);
+ *         new Searcher(this, array, result, mid, h).fork();
+ *         h = mid;
+ *       }
+ *       else {
+ *         E x = array[l];
+ *         if (matches(x) && result.compareAndSet(null, x))
+ *           quietlyCompleteRoot(); // root task is now joinable
+ *         break;
+ *       }
+ *     }
+ *     tryComplete(); // normally complete whether or not found
+ *   }
+ *   boolean matches(E e) { ... } // return true if found
+ *
+ *   public static <E> E search(E[] array) {
+ *       return new Searcher<E>(null, array, new AtomicReference<E>(), 0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * In this example, as well as others in which tasks have no other
+ * effects except to {@code compareAndSet} a common result, the
+ * trailing unconditional invocation of {@code tryComplete} could be
+ * made conditional ({@code if (result.get() == null) tryComplete();})
+ * because no further bookkeeping is required to manage completions
+ * once the root task completes.
+ *
+ * <p><b>Recording subtasks.</b> CountedCompleter tasks that combine
+ * results of multiple subtasks usually need to access these results
+ * in method {@link #onCompletion(CountedCompleter)}. As illustrated in the following
+ * class (that performs a simplified form of map-reduce where mappings
+ * and reductions are all of type {@code E}), one way to do this in
+ * divide and conquer designs is to have each subtask record its
+ * sibling, so that it can be accessed in method {@code onCompletion}.
+ * This technique applies to reductions in which the order of
+ * combining left and right results does not matter; ordered
+ * reductions require explicit left/right designations.  Variants of
+ * other streamlinings seen in the above examples may also apply.
+ *
+ * <pre> {@code
+ * class MyMapper<E> { E apply(E v) {  ...  } }
+ * class MyReducer<E> { E apply(E x, E y) {  ...  } }
+ * class MapReducer<E> extends CountedCompleter<E> {
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> sibling;
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *   }
+ *   public void compute() {
+ *     if (hi - lo >= 2) {
+ *       int mid = (lo + hi) >>> 1;
+ *       MapReducer<E> left = new MapReducer(this, array, mapper, reducer, lo, mid);
+ *       MapReducer<E> right = new MapReducer(this, array, mapper, reducer, mid, hi);
+ *       left.sibling = right;
+ *       right.sibling = left;
+ *       setPendingCount(1); // only right is pending
+ *       right.fork();
+ *       left.compute();     // directly execute left
+ *     }
+ *     else {
+ *       if (hi > lo)
+ *           result = mapper.apply(array[lo]);
+ *       tryComplete();
+ *     }
+ *   }
+ *   public void onCompletion(CountedCompleter<?> caller) {
+ *     if (caller != this) {
+ *       MapReducer<E> child = (MapReducer<E>)caller;
+ *       MapReducer<E> sib = child.sibling;
+ *       if (sib == null || sib.result == null)
+ *         result = child.result;
+ *       else
+ *         result = reducer.apply(child.result, sib.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length).invoke();
+ *   }
+ * }}</pre>
+ *
+ * Here, method {@code onCompletion} takes a form common to many
+ * completion designs that combine results. This callback-style method
+ * is triggered once per task, in either of the two different contexts
+ * in which the pending count is, or becomes, zero: (1) by a task
+ * itself, if its pending count is zero upon invocation of {@code
+ * tryComplete}, or (2) by any of its subtasks when they complete and
+ * decrement the pending count to zero. The {@code caller} argument
+ * distinguishes cases.  Most often, when the caller is {@code this},
+ * no action is necessary. Otherwise the caller argument can be used
+ * (usually via a cast) to supply a value (and/or links to other
+ * values) to be combined.  Assuming proper use of pending counts, the
+ * actions inside {@code onCompletion} occur (once) upon completion of
+ * a task and its subtasks. No additional synchronization is required
+ * within this method to ensure thread safety of accesses to fields of
+ * this task or other completed tasks.
+ *
+ * <p><b>Completion Traversals</b>. If using {@code onCompletion} to
+ * process completions is inapplicable or inconvenient, you can use
+ * methods {@link #firstComplete} and {@link #nextComplete} to create
+ * custom traversals.  For example, to define a MapReducer that only
+ * splits out right-hand tasks in the form of the third ForEach
+ * example, the completions must cooperatively reduce along
+ * unexhausted subtask links, which can be done as follows:
+ *
+ * <pre> {@code
+ * class MapReducer<E> extends CountedCompleter<E> { // version 2
+ *   final E[] array; final MyMapper<E> mapper;
+ *   final MyReducer<E> reducer; final int lo, hi;
+ *   MapReducer<E> forks, next; // record subtask forks in list
+ *   E result;
+ *   MapReducer(CountedCompleter<?> p, E[] array, MyMapper<E> mapper,
+ *              MyReducer<E> reducer, int lo, int hi, MapReducer<E> next) {
+ *     super(p);
+ *     this.array = array; this.mapper = mapper;
+ *     this.reducer = reducer; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *   public void compute() {
+ *     int l = lo, h = hi;
+ *     while (h - l >= 2) {
+ *       int mid = (l + h) >>> 1;
+ *       addToPendingCount(1);
+ *       (forks = new MapReducer(this, array, mapper, reducer, mid, h, forks)).fork();
+ *       h = mid;
+ *     }
+ *     if (h > l)
+ *       result = mapper.apply(array[l]);
+ *     // process completions by reducing along and advancing subtask links
+ *     for (CountedCompleter<?> c = firstComplete(); c != null; c = c.nextComplete()) {
+ *       for (MapReducer t = (MapReducer)c, s = t.forks; s != null; s = t.forks = s.next)
+ *         t.result = reducer.apply(t.result, s.result);
+ *     }
+ *   }
+ *   public E getRawResult() { return result; }
+ *
+ *   public static <E> E mapReduce(E[] array, MyMapper<E> mapper, MyReducer<E> reducer) {
+ *     return new MapReducer<E>(null, array, mapper, reducer,
+ *                              0, array.length, null).invoke();
+ *   }
+ * }}</pre>
+ *
+ * <p><b>Triggers.</b> Some CountedCompleters are themselves never
+ * forked, but instead serve as bits of plumbing in other designs;
+ * including those in which the completion of one or more async tasks
+ * triggers another async task. For example:
+ *
+ * <pre> {@code
+ * class HeaderBuilder extends CountedCompleter<...> { ... }
+ * class BodyBuilder extends CountedCompleter<...> { ... }
+ * class PacketSender extends CountedCompleter<...> {
+ *   PacketSender(...) { super(null, 1); ... } // trigger on second completion
+ *   public void compute() { } // never called
+ *   public void onCompletion(CountedCompleter<?> caller) { sendPacket(); }
+ * }
+ * // sample use:
+ * PacketSender p = new PacketSender();
+ * new HeaderBuilder(p, ...).fork();
+ * new BodyBuilder(p, ...).fork();}</pre>
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public abstract class CountedCompleter<T> extends ForkJoinTask<T> {
+    private static final long serialVersionUID = 5232453752276485070L;
+
+    /** This task's completer, or null if none */
+    final CountedCompleter<?> completer;
+    /** The number of pending tasks until completion */
+    volatile int pending;
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and initial pending count.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     * @param initialPendingCount the initial pending count
+     */
+    protected CountedCompleter(CountedCompleter<?> completer,
+                               int initialPendingCount) {
+        this.completer = completer;
+        this.pending = initialPendingCount;
+    }
+
+    /**
+     * Creates a new CountedCompleter with the given completer
+     * and an initial pending count of zero.
+     *
+     * @param completer this task's completer, or {@code null} if none
+     */
+    protected CountedCompleter(CountedCompleter<?> completer) {
+        this.completer = completer;
+    }
+
+    /**
+     * Creates a new CountedCompleter with no completer
+     * and an initial pending count of zero.
+     */
+    protected CountedCompleter() {
+        this.completer = null;
+    }
+
+    /**
+     * The main computation performed by this task.
+     */
+    public abstract void compute();
+
+    /**
+     * Performs an action when method {@link #tryComplete} is invoked
+     * and the pending count is zero, or when the unconditional
+     * method {@link #complete} is invoked.  By default, this method
+     * does nothing. You can distinguish cases by checking the
+     * identity of the given caller argument. If not equal to {@code
+     * this}, then it is typically a subtask that may contain results
+     * (and/or links to other results) to combine.
+     *
+     * @param caller the task invoking this method (which may
+     * be this task itself)
+     */
+    public void onCompletion(CountedCompleter<?> caller) {
+    }
+
+    /**
+     * Performs an action when method {@link
+     * #completeExceptionally(Throwable)} is invoked or method {@link
+     * #compute} throws an exception, and this task has not already
+     * otherwise completed normally. On entry to this method, this task
+     * {@link ForkJoinTask#isCompletedAbnormally}.  The return value
+     * of this method controls further propagation: If {@code true}
+     * and this task has a completer that has not completed, then that
+     * completer is also completed exceptionally, with the same
+     * exception as this completer.  The default implementation of
+     * this method does nothing except return {@code true}.
+     *
+     * @param ex the exception
+     * @param caller the task invoking this method (which may
+     * be this task itself)
+     * @return {@code true} if this exception should be propagated to this
+     * task's completer, if one exists
+     */
+    public boolean onExceptionalCompletion(Throwable ex, CountedCompleter<?> caller) {
+        return true;
+    }
+
+    /**
+     * Returns the completer established in this task's constructor,
+     * or {@code null} if none.
+     *
+     * @return the completer
+     */
+    public final CountedCompleter<?> getCompleter() {
+        return completer;
+    }
+
+    /**
+     * Returns the current pending count.
+     *
+     * @return the current pending count
+     */
+    public final int getPendingCount() {
+        return pending;
+    }
+
+    /**
+     * Sets the pending count to the given value.
+     *
+     * @param count the count
+     */
+    public final void setPendingCount(int count) {
+        pending = count;
+    }
+
+    /**
+     * Adds (atomically) the given value to the pending count.
+     *
+     * @param delta the value to add
+     */
+    public final void addToPendingCount(int delta) {
+        U.getAndAddInt(this, PENDING, delta);
+    }
+
+    /**
+     * Sets (atomically) the pending count to the given count only if
+     * it currently holds the given expected value.
+     *
+     * @param expected the expected value
+     * @param count the new value
+     * @return {@code true} if successful
+     */
+    public final boolean compareAndSetPendingCount(int expected, int count) {
+        return U.compareAndSwapInt(this, PENDING, expected, count);
+    }
+
+    /**
+     * If the pending count is nonzero, (atomically) decrements it.
+     *
+     * @return the initial (undecremented) pending count holding on entry
+     * to this method
+     */
+    public final int decrementPendingCountUnlessZero() {
+        int c;
+        do {} while ((c = pending) != 0 &&
+                     !U.compareAndSwapInt(this, PENDING, c, c - 1));
+        return c;
+    }
+
+    /**
+     * Returns the root of the current computation; i.e., this
+     * task if it has no completer, else its completer's root.
+     *
+     * @return the root of the current computation
+     */
+    public final CountedCompleter<?> getRoot() {
+        CountedCompleter<?> a = this, p;
+        while ((p = a.completer) != null)
+            a = p;
+        return a;
+    }
+
+    /**
+     * If the pending count is nonzero, decrements the count;
+     * otherwise invokes {@link #onCompletion(CountedCompleter)}
+     * and then similarly tries to complete this task's completer,
+     * if one exists, else marks this task as complete.
+     */
+    public final void tryComplete() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                a.onCompletion(s);
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Equivalent to {@link #tryComplete} but does not invoke {@link
+     * #onCompletion(CountedCompleter)} along the completion path:
+     * If the pending count is nonzero, decrements the count;
+     * otherwise, similarly tries to complete this task's completer, if
+     * one exists, else marks this task as complete. This method may be
+     * useful in cases where {@code onCompletion} should not, or need
+     * not, be invoked for each completer in a computation.
+     */
+    public final void propagateCompletion() {
+        CountedCompleter<?> a = this, s = a;
+        for (int c;;) {
+            if ((c = a.pending) == 0) {
+                if ((a = (s = a).completer) == null) {
+                    s.quietlyComplete();
+                    return;
+                }
+            }
+            else if (U.compareAndSwapInt(a, PENDING, c, c - 1))
+                return;
+        }
+    }
+
+    /**
+     * Regardless of pending count, invokes
+     * {@link #onCompletion(CountedCompleter)}, marks this task as
+     * complete and further triggers {@link #tryComplete} on this
+     * task's completer, if one exists.  The given rawResult is
+     * used as an argument to {@link #setRawResult} before invoking
+     * {@link #onCompletion(CountedCompleter)} or marking this task
+     * as complete; its value is meaningful only for classes
+     * overriding {@code setRawResult}.  This method does not modify
+     * the pending count.
+     *
+     * <p>This method may be useful when forcing completion as soon as
+     * any one (versus all) of several subtask results are obtained.
+     * However, in the common (and recommended) case in which {@code
+     * setRawResult} is not overridden, this effect can be obtained
+     * more simply using {@link #quietlyCompleteRoot()}.
+     *
+     * @param rawResult the raw result
+     */
+    public void complete(T rawResult) {
+        CountedCompleter<?> p;
+        setRawResult(rawResult);
+        onCompletion(this);
+        quietlyComplete();
+        if ((p = completer) != null)
+            p.tryComplete();
+    }
+
+    /**
+     * If this task's pending count is zero, returns this task;
+     * otherwise decrements its pending count and returns {@code null}.
+     * This method is designed to be used with {@link #nextComplete} in
+     * completion traversal loops.
+     *
+     * @return this task, if pending count was zero, else {@code null}
+     */
+    public final CountedCompleter<?> firstComplete() {
+        for (int c;;) {
+            if ((c = pending) == 0)
+                return this;
+            else if (U.compareAndSwapInt(this, PENDING, c, c - 1))
+                return null;
+        }
+    }
+
+    /**
+     * If this task does not have a completer, invokes {@link
+     * ForkJoinTask#quietlyComplete} and returns {@code null}.  Or, if
+     * the completer's pending count is non-zero, decrements that
+     * pending count and returns {@code null}.  Otherwise, returns the
+     * completer.  This method can be used as part of a completion
+     * traversal loop for homogeneous task hierarchies:
+     *
+     * <pre> {@code
+     * for (CountedCompleter<?> c = firstComplete();
+     *      c != null;
+     *      c = c.nextComplete()) {
+     *   // ... process c ...
+     * }}</pre>
+     *
+     * @return the completer, or {@code null} if none
+     */
+    public final CountedCompleter<?> nextComplete() {
+        CountedCompleter<?> p;
+        if ((p = completer) != null)
+            return p.firstComplete();
+        else {
+            quietlyComplete();
+            return null;
+        }
+    }
+
+    /**
+     * Equivalent to {@code getRoot().quietlyComplete()}.
+     */
+    public final void quietlyCompleteRoot() {
+        for (CountedCompleter<?> a = this, p;;) {
+            if ((p = a.completer) == null) {
+                a.quietlyComplete();
+                return;
+            }
+            a = p;
+        }
+    }
+
+    /**
+     * If this task has not completed, attempts to process at most the
+     * given number of other unprocessed tasks for which this task is
+     * on the completion path, if any are known to exist.
+     *
+     * @param maxTasks the maximum number of tasks to process.  If
+     *                 less than or equal to zero, then no tasks are
+     *                 processed.
+     */
+    public final void helpComplete(int maxTasks) {
+        Thread t; ForkJoinWorkerThread wt;
+        if (maxTasks > 0 && status >= 0) {
+            if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+                (wt = (ForkJoinWorkerThread)t).pool.
+                    helpComplete(wt.workQueue, this, maxTasks);
+            else
+                ForkJoinPool.common.externalHelpComplete(this, maxTasks);
+        }
+    }
+
+    /**
+     * Supports ForkJoinTask exception propagation.
+     */
+    void internalPropagateException(Throwable ex) {
+        CountedCompleter<?> a = this, s = a;
+        while (a.onExceptionalCompletion(ex, s) &&
+               (a = (s = a).completer) != null && a.status >= 0 &&
+               a.recordExceptionalCompletion(ex) == EXCEPTIONAL)
+            ;
+    }
+
+    /**
+     * Implements execution conventions for CountedCompleters.
+     */
+    protected final boolean exec() {
+        compute();
+        return false;
+    }
+
+    /**
+     * Returns the result of the computation.  By default,
+     * returns {@code null}, which is appropriate for {@code Void}
+     * actions, but in other cases should be overridden, almost
+     * always to return a field or function of a field that
+     * holds the result upon completion.
+     *
+     * @return the result of the computation
+     */
+    public T getRawResult() { return null; }
+
+    /**
+     * A method that result-bearing CountedCompleters may optionally
+     * use to help maintain result data.  By default, does nothing.
+     * Overrides are not recommended. However, if this method is
+     * overridden to update existing objects or fields, then it must
+     * in general be defined to be thread-safe.
+     */
+    protected void setRawResult(T t) { }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PENDING;
+    static {
+        try {
+            PENDING = U.objectFieldOffset
+                (CountedCompleter.class.getDeclaredField("pending"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/CyclicBarrier.java b/java/util/concurrent/CyclicBarrier.java
new file mode 100644
index 0000000..5e018f1
--- /dev/null
+++ b/java/util/concurrent/CyclicBarrier.java
@@ -0,0 +1,492 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A synchronization aid that allows a set of threads to all wait for
+ * each other to reach a common barrier point.  CyclicBarriers are
+ * useful in programs involving a fixed sized party of threads that
+ * must occasionally wait for each other. The barrier is called
+ * <em>cyclic</em> because it can be re-used after the waiting threads
+ * are released.
+ *
+ * <p>A {@code CyclicBarrier} supports an optional {@link Runnable} command
+ * that is run once per barrier point, after the last thread in the party
+ * arrives, but before any threads are released.
+ * This <em>barrier action</em> is useful
+ * for updating shared-state before any of the parties continue.
+ *
+ * <p><b>Sample usage:</b> Here is an example of using a barrier in a
+ * parallel decomposition design:
+ *
+ * <pre> {@code
+ * class Solver {
+ *   final int N;
+ *   final float[][] data;
+ *   final CyclicBarrier barrier;
+ *
+ *   class Worker implements Runnable {
+ *     int myRow;
+ *     Worker(int row) { myRow = row; }
+ *     public void run() {
+ *       while (!done()) {
+ *         processRow(myRow);
+ *
+ *         try {
+ *           barrier.await();
+ *         } catch (InterruptedException ex) {
+ *           return;
+ *         } catch (BrokenBarrierException ex) {
+ *           return;
+ *         }
+ *       }
+ *     }
+ *   }
+ *
+ *   public Solver(float[][] matrix) {
+ *     data = matrix;
+ *     N = matrix.length;
+ *     Runnable barrierAction =
+ *       new Runnable() { public void run() { mergeRows(...); }};
+ *     barrier = new CyclicBarrier(N, barrierAction);
+ *
+ *     List<Thread> threads = new ArrayList<>(N);
+ *     for (int i = 0; i < N; i++) {
+ *       Thread thread = new Thread(new Worker(i));
+ *       threads.add(thread);
+ *       thread.start();
+ *     }
+ *
+ *     // wait until done
+ *     for (Thread thread : threads)
+ *       thread.join();
+ *   }
+ * }}</pre>
+ *
+ * Here, each worker thread processes a row of the matrix then waits at the
+ * barrier until all rows have been processed. When all rows are processed
+ * the supplied {@link Runnable} barrier action is executed and merges the
+ * rows. If the merger
+ * determines that a solution has been found then {@code done()} will return
+ * {@code true} and each worker will terminate.
+ *
+ * <p>If the barrier action does not rely on the parties being suspended when
+ * it is executed, then any of the threads in the party could execute that
+ * action when it is released. To facilitate this, each invocation of
+ * {@link #await} returns the arrival index of that thread at the barrier.
+ * You can then choose which thread should execute the barrier action, for
+ * example:
+ * <pre> {@code
+ * if (barrier.await() == 0) {
+ *   // log the completion of this iteration
+ * }}</pre>
+ *
+ * <p>The {@code CyclicBarrier} uses an all-or-none breakage model
+ * for failed synchronization attempts: If a thread leaves a barrier
+ * point prematurely because of interruption, failure, or timeout, all
+ * other threads waiting at that barrier point will also leave
+ * abnormally via {@link BrokenBarrierException} (or
+ * {@link InterruptedException} if they too were interrupted at about
+ * the same time).
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to calling
+ * {@code await()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions that are part of the barrier action, which in turn
+ * <i>happen-before</i> actions following a successful return from the
+ * corresponding {@code await()} in other threads.
+ *
+ * @since 1.5
+ * @see CountDownLatch
+ *
+ * @author Doug Lea
+ */
+public class CyclicBarrier {
+    /**
+     * Each use of the barrier is represented as a generation instance.
+     * The generation changes whenever the barrier is tripped, or
+     * is reset. There can be many generations associated with threads
+     * using the barrier - due to the non-deterministic way the lock
+     * may be allocated to waiting threads - but only one of these
+     * can be active at a time (the one to which {@code count} applies)
+     * and all the rest are either broken or tripped.
+     * There need not be an active generation if there has been a break
+     * but no subsequent reset.
+     */
+    private static class Generation {
+        boolean broken;         // initially false
+    }
+
+    /** The lock for guarding barrier entry */
+    private final ReentrantLock lock = new ReentrantLock();
+    /** Condition to wait on until tripped */
+    private final Condition trip = lock.newCondition();
+    /** The number of parties */
+    private final int parties;
+    /** The command to run when tripped */
+    private final Runnable barrierCommand;
+    /** The current generation */
+    private Generation generation = new Generation();
+
+    /**
+     * Number of parties still waiting. Counts down from parties to 0
+     * on each generation.  It is reset to parties on each new
+     * generation or when broken.
+     */
+    private int count;
+
+    /**
+     * Updates state on barrier trip and wakes up everyone.
+     * Called only while holding lock.
+     */
+    private void nextGeneration() {
+        // signal completion of last generation
+        trip.signalAll();
+        // set up next generation
+        count = parties;
+        generation = new Generation();
+    }
+
+    /**
+     * Sets current barrier generation as broken and wakes up everyone.
+     * Called only while holding lock.
+     */
+    private void breakBarrier() {
+        generation.broken = true;
+        count = parties;
+        trip.signalAll();
+    }
+
+    /**
+     * Main barrier code, covering the various policies.
+     */
+    private int dowait(boolean timed, long nanos)
+        throws InterruptedException, BrokenBarrierException,
+               TimeoutException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            final Generation g = generation;
+
+            if (g.broken)
+                throw new BrokenBarrierException();
+
+            if (Thread.interrupted()) {
+                breakBarrier();
+                throw new InterruptedException();
+            }
+
+            int index = --count;
+            if (index == 0) {  // tripped
+                boolean ranAction = false;
+                try {
+                    final Runnable command = barrierCommand;
+                    if (command != null)
+                        command.run();
+                    ranAction = true;
+                    nextGeneration();
+                    return 0;
+                } finally {
+                    if (!ranAction)
+                        breakBarrier();
+                }
+            }
+
+            // loop until tripped, broken, interrupted, or timed out
+            for (;;) {
+                try {
+                    if (!timed)
+                        trip.await();
+                    else if (nanos > 0L)
+                        nanos = trip.awaitNanos(nanos);
+                } catch (InterruptedException ie) {
+                    if (g == generation && ! g.broken) {
+                        breakBarrier();
+                        throw ie;
+                    } else {
+                        // We're about to finish waiting even if we had not
+                        // been interrupted, so this interrupt is deemed to
+                        // "belong" to subsequent execution.
+                        Thread.currentThread().interrupt();
+                    }
+                }
+
+                if (g.broken)
+                    throw new BrokenBarrierException();
+
+                if (g != generation)
+                    return index;
+
+                if (timed && nanos <= 0L) {
+                    breakBarrier();
+                    throw new TimeoutException();
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Creates a new {@code CyclicBarrier} that will trip when the
+     * given number of parties (threads) are waiting upon it, and which
+     * will execute the given barrier action when the barrier is tripped,
+     * performed by the last thread entering the barrier.
+     *
+     * @param parties the number of threads that must invoke {@link #await}
+     *        before the barrier is tripped
+     * @param barrierAction the command to execute when the barrier is
+     *        tripped, or {@code null} if there is no action
+     * @throws IllegalArgumentException if {@code parties} is less than 1
+     */
+    public CyclicBarrier(int parties, Runnable barrierAction) {
+        if (parties <= 0) throw new IllegalArgumentException();
+        this.parties = parties;
+        this.count = parties;
+        this.barrierCommand = barrierAction;
+    }
+
+    /**
+     * Creates a new {@code CyclicBarrier} that will trip when the
+     * given number of parties (threads) are waiting upon it, and
+     * does not perform a predefined action when the barrier is tripped.
+     *
+     * @param parties the number of threads that must invoke {@link #await}
+     *        before the barrier is tripped
+     * @throws IllegalArgumentException if {@code parties} is less than 1
+     */
+    public CyclicBarrier(int parties) {
+        this(parties, null);
+    }
+
+    /**
+     * Returns the number of parties required to trip this barrier.
+     *
+     * @return the number of parties required to trip this barrier
+     */
+    public int getParties() {
+        return parties;
+    }
+
+    /**
+     * Waits until all {@linkplain #getParties parties} have invoked
+     * {@code await} on this barrier.
+     *
+     * <p>If the current thread is not the last to arrive then it is
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of the following things happens:
+     * <ul>
+     * <li>The last thread arrives; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * one of the other waiting threads; or
+     * <li>Some other thread times out while waiting for barrier; or
+     * <li>Some other thread invokes {@link #reset} on this barrier.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the barrier is {@link #reset} while any thread is waiting,
+     * or if the barrier {@linkplain #isBroken is broken} when
+     * {@code await} is invoked, or while any thread is waiting, then
+     * {@link BrokenBarrierException} is thrown.
+     *
+     * <p>If any thread is {@linkplain Thread#interrupt interrupted} while waiting,
+     * then all other waiting threads will throw
+     * {@link BrokenBarrierException} and the barrier is placed in the broken
+     * state.
+     *
+     * <p>If the current thread is the last thread to arrive, and a
+     * non-null barrier action was supplied in the constructor, then the
+     * current thread runs the action before allowing the other threads to
+     * continue.
+     * If an exception occurs during the barrier action then that exception
+     * will be propagated in the current thread and the barrier is placed in
+     * the broken state.
+     *
+     * @return the arrival index of the current thread, where index
+     *         {@code getParties() - 1} indicates the first
+     *         to arrive and zero indicates the last to arrive
+     * @throws InterruptedException if the current thread was interrupted
+     *         while waiting
+     * @throws BrokenBarrierException if <em>another</em> thread was
+     *         interrupted or timed out while the current thread was
+     *         waiting, or the barrier was reset, or the barrier was
+     *         broken when {@code await} was called, or the barrier
+     *         action (if present) failed due to an exception
+     */
+    public int await() throws InterruptedException, BrokenBarrierException {
+        try {
+            return dowait(false, 0L);
+        } catch (TimeoutException toe) {
+            throw new Error(toe); // cannot happen
+        }
+    }
+
+    /**
+     * Waits until all {@linkplain #getParties parties} have invoked
+     * {@code await} on this barrier, or the specified waiting time elapses.
+     *
+     * <p>If the current thread is not the last to arrive then it is
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of the following things happens:
+     * <ul>
+     * <li>The last thread arrives; or
+     * <li>The specified timeout elapses; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * one of the other waiting threads; or
+     * <li>Some other thread times out while waiting for barrier; or
+     * <li>Some other thread invokes {@link #reset} on this barrier.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then {@link TimeoutException}
+     * is thrown. If the time is less than or equal to zero, the
+     * method will not wait at all.
+     *
+     * <p>If the barrier is {@link #reset} while any thread is waiting,
+     * or if the barrier {@linkplain #isBroken is broken} when
+     * {@code await} is invoked, or while any thread is waiting, then
+     * {@link BrokenBarrierException} is thrown.
+     *
+     * <p>If any thread is {@linkplain Thread#interrupt interrupted} while
+     * waiting, then all other waiting threads will throw {@link
+     * BrokenBarrierException} and the barrier is placed in the broken
+     * state.
+     *
+     * <p>If the current thread is the last thread to arrive, and a
+     * non-null barrier action was supplied in the constructor, then the
+     * current thread runs the action before allowing the other threads to
+     * continue.
+     * If an exception occurs during the barrier action then that exception
+     * will be propagated in the current thread and the barrier is placed in
+     * the broken state.
+     *
+     * @param timeout the time to wait for the barrier
+     * @param unit the time unit of the timeout parameter
+     * @return the arrival index of the current thread, where index
+     *         {@code getParties() - 1} indicates the first
+     *         to arrive and zero indicates the last to arrive
+     * @throws InterruptedException if the current thread was interrupted
+     *         while waiting
+     * @throws TimeoutException if the specified timeout elapses.
+     *         In this case the barrier will be broken.
+     * @throws BrokenBarrierException if <em>another</em> thread was
+     *         interrupted or timed out while the current thread was
+     *         waiting, or the barrier was reset, or the barrier was broken
+     *         when {@code await} was called, or the barrier action (if
+     *         present) failed due to an exception
+     */
+    public int await(long timeout, TimeUnit unit)
+        throws InterruptedException,
+               BrokenBarrierException,
+               TimeoutException {
+        return dowait(true, unit.toNanos(timeout));
+    }
+
+    /**
+     * Queries if this barrier is in a broken state.
+     *
+     * @return {@code true} if one or more parties broke out of this
+     *         barrier due to interruption or timeout since
+     *         construction or the last reset, or a barrier action
+     *         failed due to an exception; {@code false} otherwise.
+     */
+    public boolean isBroken() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return generation.broken;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Resets the barrier to its initial state.  If any parties are
+     * currently waiting at the barrier, they will return with a
+     * {@link BrokenBarrierException}. Note that resets <em>after</em>
+     * a breakage has occurred for other reasons can be complicated to
+     * carry out; threads need to re-synchronize in some other way,
+     * and choose one to perform the reset.  It may be preferable to
+     * instead create a new barrier for subsequent use.
+     */
+    public void reset() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            breakBarrier();   // break the current generation
+            nextGeneration(); // start a new generation
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the number of parties currently waiting at the barrier.
+     * This method is primarily useful for debugging and assertions.
+     *
+     * @return the number of parties currently blocked in {@link #await}
+     */
+    public int getNumberWaiting() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return parties - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+}
diff --git a/java/util/concurrent/DelayQueue.java b/java/util/concurrent/DelayQueue.java
new file mode 100644
index 0000000..04a83d9
--- /dev/null
+++ b/java/util/concurrent/DelayQueue.java
@@ -0,0 +1,562 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@linkplain BlockingQueue blocking queue} of
+ * {@code Delayed} elements, in which an element can only be taken
+ * when its delay has expired.  The <em>head</em> of the queue is that
+ * {@code Delayed} element whose delay expired furthest in the
+ * past.  If no delay has expired there is no head and {@code poll}
+ * will return {@code null}. Expiration occurs when an element's
+ * {@code getDelay(TimeUnit.NANOSECONDS)} method returns a value less
+ * than or equal to zero.  Even though unexpired elements cannot be
+ * removed using {@code take} or {@code poll}, they are otherwise
+ * treated as normal elements. For example, the {@code size} method
+ * returns the count of both expired and unexpired elements.
+ * This queue does not permit null elements.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the DelayQueue in any particular order.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
+    implements BlockingQueue<E> {
+
+    private final transient ReentrantLock lock = new ReentrantLock();
+    private final PriorityQueue<E> q = new PriorityQueue<E>();
+
+    /**
+     * Thread designated to wait for the element at the head of
+     * the queue.  This variant of the Leader-Follower pattern
+     * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
+     * minimize unnecessary timed waiting.  When a thread becomes
+     * the leader, it waits only for the next delay to elapse, but
+     * other threads await indefinitely.  The leader thread must
+     * signal some other thread before returning from take() or
+     * poll(...), unless some other thread becomes leader in the
+     * interim.  Whenever the head of the queue is replaced with
+     * an element with an earlier expiration time, the leader
+     * field is invalidated by being reset to null, and some
+     * waiting thread, but not necessarily the current leader, is
+     * signalled.  So waiting threads must be prepared to acquire
+     * and lose leadership while waiting.
+     */
+    private Thread leader;
+
+    /**
+     * Condition signalled when a newer element becomes available
+     * at the head of the queue or a new thread may need to
+     * become leader.
+     */
+    private final Condition available = lock.newCondition();
+
+    /**
+     * Creates a new {@code DelayQueue} that is initially empty.
+     */
+    public DelayQueue() {}
+
+    /**
+     * Creates a {@code DelayQueue} initially containing the elements of the
+     * given collection of {@link Delayed} instances.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public DelayQueue(Collection<? extends E> c) {
+        this.addAll(c);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue.
+     *
+     * @param e the element to add
+     * @return {@code true}
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            q.offer(e);
+            if (q.peek() == e) {
+                leader = null;
+                available.signal();
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Inserts the specified element into this delay queue. As the queue is
+     * unbounded this method will never block.
+     *
+     * @param e the element to add
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) {
+        offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this delay queue. As the queue is
+     * unbounded this method will never block.
+     *
+     * @param e the element to add
+     * @param timeout This parameter is ignored as the method never blocks
+     * @param unit This parameter is ignored as the method never blocks
+     * @return {@code true}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        return offer(e);
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, or returns {@code null}
+     * if this queue has no elements with an expired delay.
+     *
+     * @return the head of this queue, or {@code null} if this
+     *         queue has no elements with an expired delay
+     */
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E first = q.peek();
+            return (first == null || first.getDelay(NANOSECONDS) > 0)
+                ? null
+                : q.poll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element with an expired delay is available on this queue.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            for (;;) {
+                E first = q.peek();
+                if (first == null)
+                    available.await();
+                else {
+                    long delay = first.getDelay(NANOSECONDS);
+                    if (delay <= 0L)
+                        return q.poll();
+                    first = null; // don't retain ref while waiting
+                    if (leader != null)
+                        available.await();
+                    else {
+                        Thread thisThread = Thread.currentThread();
+                        leader = thisThread;
+                        try {
+                            available.awaitNanos(delay);
+                        } finally {
+                            if (leader == thisThread)
+                                leader = null;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (leader == null && q.peek() != null)
+                available.signal();
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * until an element with an expired delay is available on this queue,
+     * or the specified wait time expires.
+     *
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element with
+     *         an expired delay becomes available
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            for (;;) {
+                E first = q.peek();
+                if (first == null) {
+                    if (nanos <= 0L)
+                        return null;
+                    else
+                        nanos = available.awaitNanos(nanos);
+                } else {
+                    long delay = first.getDelay(NANOSECONDS);
+                    if (delay <= 0L)
+                        return q.poll();
+                    if (nanos <= 0L)
+                        return null;
+                    first = null; // don't retain ref while waiting
+                    if (nanos < delay || leader != null)
+                        nanos = available.awaitNanos(nanos);
+                    else {
+                        Thread thisThread = Thread.currentThread();
+                        leader = thisThread;
+                        try {
+                            long timeLeft = available.awaitNanos(delay);
+                            nanos -= delay - timeLeft;
+                        } finally {
+                            if (leader == thisThread)
+                                leader = null;
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (leader == null && q.peek() != null)
+                available.signal();
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of this queue, or
+     * returns {@code null} if this queue is empty.  Unlike
+     * {@code poll}, if no expired elements are available in the queue,
+     * this method returns the element that will expire next,
+     * if one exists.
+     *
+     * @return the head of this queue, or {@code null} if this
+     *         queue is empty
+     */
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.peek();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.size();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns first element only if it is expired.
+     * Used only by drainTo.  Call only when holding lock.
+     */
+    private E peekExpired() {
+        // assert lock.isHeldByCurrentThread();
+        E first = q.peek();
+        return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+            null : first;
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = 0;
+            for (E e; (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
+                ++n;
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = 0;
+            for (E e; n < maxElements && (e = peekExpired()) != null;) {
+                c.add(e);       // In this order, in case add() throws.
+                q.poll();
+                ++n;
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Atomically removes all of the elements from this delay queue.
+     * The queue will be empty after this call returns.
+     * Elements with an unexpired delay are not waited for; they are
+     * simply discarded from the queue.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            q.clear();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because
+     * a {@code DelayQueue} is not capacity constrained.
+     *
+     * @return {@code Integer.MAX_VALUE}
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The returned array elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.toArray();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>The following code can be used to dump a delay queue into a newly
+     * allocated array of {@code Delayed}:
+     *
+     * <pre> {@code Delayed[] a = q.toArray(new Delayed[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.toArray(a);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Removes a single instance of the specified element from this
+     * queue, if it is present, whether or not it has expired.
+     */
+    public boolean remove(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return q.remove(o);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Identity-based version for use in Itr.remove.
+     */
+    void removeEQ(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Iterator<E> it = q.iterator(); it.hasNext(); ) {
+                if (o == it.next()) {
+                    it.remove();
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over all the elements (both expired and
+     * unexpired) in this queue. The iterator does not return the
+     * elements in any particular order.
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr(toArray());
+    }
+
+    /**
+     * Snapshot iterator that works off copy of underlying q array.
+     */
+    private class Itr implements Iterator<E> {
+        final Object[] array; // Array of all elements
+        int cursor;           // index of next element to return
+        int lastRet;          // index of last element, or -1 if no such
+
+        Itr(Object[] array) {
+            lastRet = -1;
+            this.array = array;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        @SuppressWarnings("unchecked")
+        public E next() {
+            if (cursor >= array.length)
+                throw new NoSuchElementException();
+            lastRet = cursor;
+            return (E)array[cursor++];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            removeEQ(array[lastRet]);
+            lastRet = -1;
+        }
+    }
+
+}
diff --git a/java/util/concurrent/Delayed.java b/java/util/concurrent/Delayed.java
new file mode 100644
index 0000000..5da1ec8
--- /dev/null
+++ b/java/util/concurrent/Delayed.java
@@ -0,0 +1,60 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A mix-in style interface for marking objects that should be
+ * acted upon after a given delay.
+ *
+ * <p>An implementation of this interface must define a
+ * {@code compareTo} method that provides an ordering consistent with
+ * its {@code getDelay} method.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Delayed extends Comparable<Delayed> {
+
+    /**
+     * Returns the remaining delay associated with this object, in the
+     * given time unit.
+     *
+     * @param unit the time unit
+     * @return the remaining delay; zero or negative values indicate
+     * that the delay has already elapsed
+     */
+    long getDelay(TimeUnit unit);
+}
diff --git a/java/util/concurrent/Exchanger.java b/java/util/concurrent/Exchanger.java
new file mode 100644
index 0000000..f01a705
--- /dev/null
+++ b/java/util/concurrent/Exchanger.java
@@ -0,0 +1,658 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea, Bill Scherer, and Michael Scott with
+ * assistance from members of JCP JSR-166 Expert Group and released to
+ * the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A synchronization point at which threads can pair and swap elements
+ * within pairs.  Each thread presents some object on entry to the
+ * {@link #exchange exchange} method, matches with a partner thread,
+ * and receives its partner's object on return.  An Exchanger may be
+ * viewed as a bidirectional form of a {@link SynchronousQueue}.
+ * Exchangers may be useful in applications such as genetic algorithms
+ * and pipeline designs.
+ *
+ * <p><b>Sample Usage:</b>
+ * Here are the highlights of a class that uses an {@code Exchanger}
+ * to swap buffers between threads so that the thread filling the
+ * buffer gets a freshly emptied one when it needs it, handing off the
+ * filled one to the thread emptying the buffer.
+ * <pre> {@code
+ * class FillAndEmpty {
+ *   Exchanger<DataBuffer> exchanger = new Exchanger<>();
+ *   DataBuffer initialEmptyBuffer = ... a made-up type
+ *   DataBuffer initialFullBuffer = ...
+ *
+ *   class FillingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialEmptyBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           addToBuffer(currentBuffer);
+ *           if (currentBuffer.isFull())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ... }
+ *     }
+ *   }
+ *
+ *   class EmptyingLoop implements Runnable {
+ *     public void run() {
+ *       DataBuffer currentBuffer = initialFullBuffer;
+ *       try {
+ *         while (currentBuffer != null) {
+ *           takeFromBuffer(currentBuffer);
+ *           if (currentBuffer.isEmpty())
+ *             currentBuffer = exchanger.exchange(currentBuffer);
+ *         }
+ *       } catch (InterruptedException ex) { ... handle ...}
+ *     }
+ *   }
+ *
+ *   void start() {
+ *     new Thread(new FillingLoop()).start();
+ *     new Thread(new EmptyingLoop()).start();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: For each pair of threads that
+ * successfully exchange objects via an {@code Exchanger}, actions
+ * prior to the {@code exchange()} in each thread
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * those subsequent to a return from the corresponding {@code exchange()}
+ * in the other thread.
+ *
+ * @since 1.5
+ * @author Doug Lea and Bill Scherer and Michael Scott
+ * @param <V> The type of objects that may be exchanged
+ */
+public class Exchanger<V> {
+
+    /*
+     * Overview: The core algorithm is, for an exchange "slot",
+     * and a participant (caller) with an item:
+     *
+     * for (;;) {
+     *   if (slot is empty) {                       // offer
+     *     place item in a Node;
+     *     if (can CAS slot from empty to node) {
+     *       wait for release;
+     *       return matching item in node;
+     *     }
+     *   }
+     *   else if (can CAS slot from node to empty) { // release
+     *     get the item in node;
+     *     set matching item in node;
+     *     release waiting thread;
+     *   }
+     *   // else retry on CAS failure
+     * }
+     *
+     * This is among the simplest forms of a "dual data structure" --
+     * see Scott and Scherer's DISC 04 paper and
+     * http://www.cs.rochester.edu/research/synchronization/pseudocode/duals.html
+     *
+     * This works great in principle. But in practice, like many
+     * algorithms centered on atomic updates to a single location, it
+     * scales horribly when there are more than a few participants
+     * using the same Exchanger. So the implementation instead uses a
+     * form of elimination arena, that spreads out this contention by
+     * arranging that some threads typically use different slots,
+     * while still ensuring that eventually, any two parties will be
+     * able to exchange items. That is, we cannot completely partition
+     * across threads, but instead give threads arena indices that
+     * will on average grow under contention and shrink under lack of
+     * contention. We approach this by defining the Nodes that we need
+     * anyway as ThreadLocals, and include in them per-thread index
+     * and related bookkeeping state. (We can safely reuse per-thread
+     * nodes rather than creating them fresh each time because slots
+     * alternate between pointing to a node vs null, so cannot
+     * encounter ABA problems. However, we do need some care in
+     * resetting them between uses.)
+     *
+     * Implementing an effective arena requires allocating a bunch of
+     * space, so we only do so upon detecting contention (except on
+     * uniprocessors, where they wouldn't help, so aren't used).
+     * Otherwise, exchanges use the single-slot slotExchange method.
+     * On contention, not only must the slots be in different
+     * locations, but the locations must not encounter memory
+     * contention due to being on the same cache line (or more
+     * generally, the same coherence unit).  Because, as of this
+     * writing, there is no way to determine cacheline size, we define
+     * a value that is enough for common platforms.  Additionally,
+     * extra care elsewhere is taken to avoid other false/unintended
+     * sharing and to enhance locality, including adding padding (via
+     * @Contended) to Nodes, embedding "bound" as an Exchanger field,
+     * and reworking some park/unpark mechanics compared to
+     * LockSupport versions.
+     *
+     * The arena starts out with only one used slot. We expand the
+     * effective arena size by tracking collisions; i.e., failed CASes
+     * while trying to exchange. By nature of the above algorithm, the
+     * only kinds of collision that reliably indicate contention are
+     * when two attempted releases collide -- one of two attempted
+     * offers can legitimately fail to CAS without indicating
+     * contention by more than one other thread. (Note: it is possible
+     * but not worthwhile to more precisely detect contention by
+     * reading slot values after CAS failures.)  When a thread has
+     * collided at each slot within the current arena bound, it tries
+     * to expand the arena size by one. We track collisions within
+     * bounds by using a version (sequence) number on the "bound"
+     * field, and conservatively reset collision counts when a
+     * participant notices that bound has been updated (in either
+     * direction).
+     *
+     * The effective arena size is reduced (when there is more than
+     * one slot) by giving up on waiting after a while and trying to
+     * decrement the arena size on expiration. The value of "a while"
+     * is an empirical matter.  We implement by piggybacking on the
+     * use of spin->yield->block that is essential for reasonable
+     * waiting performance anyway -- in a busy exchanger, offers are
+     * usually almost immediately released, in which case context
+     * switching on multiprocessors is extremely slow/wasteful.  Arena
+     * waits just omit the blocking part, and instead cancel. The spin
+     * count is empirically chosen to be a value that avoids blocking
+     * 99% of the time under maximum sustained exchange rates on a
+     * range of test machines. Spins and yields entail some limited
+     * randomness (using a cheap xorshift) to avoid regular patterns
+     * that can induce unproductive grow/shrink cycles. (Using a
+     * pseudorandom also helps regularize spin cycle duration by
+     * making branches unpredictable.)  Also, during an offer, a
+     * waiter can "know" that it will be released when its slot has
+     * changed, but cannot yet proceed until match is set.  In the
+     * mean time it cannot cancel the offer, so instead spins/yields.
+     * Note: It is possible to avoid this secondary check by changing
+     * the linearization point to be a CAS of the match field (as done
+     * in one case in the Scott & Scherer DISC paper), which also
+     * increases asynchrony a bit, at the expense of poorer collision
+     * detection and inability to always reuse per-thread nodes. So
+     * the current scheme is typically a better tradeoff.
+     *
+     * On collisions, indices traverse the arena cyclically in reverse
+     * order, restarting at the maximum index (which will tend to be
+     * sparsest) when bounds change. (On expirations, indices instead
+     * are halved until reaching 0.) It is possible (and has been
+     * tried) to use randomized, prime-value-stepped, or double-hash
+     * style traversal instead of simple cyclic traversal to reduce
+     * bunching.  But empirically, whatever benefits these may have
+     * don't overcome their added overhead: We are managing operations
+     * that occur very quickly unless there is sustained contention,
+     * so simpler/faster control policies work better than more
+     * accurate but slower ones.
+     *
+     * Because we use expiration for arena size control, we cannot
+     * throw TimeoutExceptions in the timed version of the public
+     * exchange method until the arena size has shrunken to zero (or
+     * the arena isn't enabled). This may delay response to timeout
+     * but is still within spec.
+     *
+     * Essentially all of the implementation is in methods
+     * slotExchange and arenaExchange. These have similar overall
+     * structure, but differ in too many details to combine. The
+     * slotExchange method uses the single Exchanger field "slot"
+     * rather than arena array elements. However, it still needs
+     * minimal collision detection to trigger arena construction.
+     * (The messiest part is making sure interrupt status and
+     * InterruptedExceptions come out right during transitions when
+     * both methods may be called. This is done by using null return
+     * as a sentinel to recheck interrupt status.)
+     *
+     * As is too common in this sort of code, methods are monolithic
+     * because most of the logic relies on reads of fields that are
+     * maintained as local variables so can't be nicely factored --
+     * mainly, here, bulky spin->yield->block/cancel code), and
+     * heavily dependent on intrinsics (Unsafe) to use inlined
+     * embedded CAS and related memory access operations (that tend
+     * not to be as readily inlined by dynamic compilers when they are
+     * hidden behind other methods that would more nicely name and
+     * encapsulate the intended effects). This includes the use of
+     * putOrderedX to clear fields of the per-thread Nodes between
+     * uses. Note that field Node.item is not declared as volatile
+     * even though it is read by releasing threads, because they only
+     * do so after CAS operations that must precede access, and all
+     * uses by the owning thread are otherwise acceptably ordered by
+     * other operations. (Because the actual points of atomicity are
+     * slot CASes, it would also be legal for the write to Node.match
+     * in a release to be weaker than a full volatile write. However,
+     * this is not done because it could allow further postponement of
+     * the write, delaying progress.)
+     */
+
+    /**
+     * The byte distance (as a shift value) between any two used slots
+     * in the arena.  1 << ASHIFT should be at least cacheline size.
+     */
+    private static final int ASHIFT = 7;
+
+    /**
+     * The maximum supported arena index. The maximum allocatable
+     * arena size is MMASK + 1. Must be a power of two minus one, less
+     * than (1<<(31-ASHIFT)). The cap of 255 (0xff) more than suffices
+     * for the expected scaling limits of the main algorithms.
+     */
+    private static final int MMASK = 0xff;
+
+    /**
+     * Unit for sequence/version bits of bound field. Each successful
+     * change to the bound also adds SEQ.
+     */
+    private static final int SEQ = MMASK + 1;
+
+    /** The number of CPUs, for sizing and spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * The maximum slot index of the arena: The number of slots that
+     * can in principle hold all threads without contention, or at
+     * most the maximum indexable value.
+     */
+    static final int FULL = (NCPU >= (MMASK << 1)) ? MMASK : NCPU >>> 1;
+
+    /**
+     * The bound for spins while waiting for a match. The actual
+     * number of iterations will on average be about twice this value
+     * due to randomization. Note: Spinning is disabled when NCPU==1.
+     */
+    private static final int SPINS = 1 << 10;
+
+    /**
+     * Value representing null arguments/returns from public
+     * methods. Needed because the API originally didn't disallow null
+     * arguments, which it should have.
+     */
+    private static final Object NULL_ITEM = new Object();
+
+    /**
+     * Sentinel value returned by internal exchange methods upon
+     * timeout, to avoid need for separate timed versions of these
+     * methods.
+     */
+    private static final Object TIMED_OUT = new Object();
+
+    /**
+     * Nodes hold partially exchanged data, plus other per-thread
+     * bookkeeping. Padded via @Contended to reduce memory contention.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    //@jdk.internal.vm.annotation.Contended
+    static final class Node {
+        int index;              // Arena index
+        int bound;              // Last recorded value of Exchanger.bound
+        int collides;           // Number of CAS failures at current bound
+        int hash;               // Pseudo-random for spins
+        Object item;            // This thread's current item
+        volatile Object match;  // Item provided by releasing thread
+        volatile Thread parked; // Set to this thread when parked, else null
+    }
+
+    /** The corresponding thread local class */
+    static final class Participant extends ThreadLocal<Node> {
+        public Node initialValue() { return new Node(); }
+    }
+
+    /**
+     * Per-thread state.
+     */
+    private final Participant participant;
+
+    /**
+     * Elimination array; null until enabled (within slotExchange).
+     * Element accesses use emulation of volatile gets and CAS.
+     */
+    private volatile Node[] arena;
+
+    /**
+     * Slot used until contention detected.
+     */
+    private volatile Node slot;
+
+    /**
+     * The index of the largest valid arena position, OR'ed with SEQ
+     * number in high bits, incremented on each update.  The initial
+     * update from 0 to SEQ is used to ensure that the arena array is
+     * constructed only once.
+     */
+    private volatile int bound;
+
+    /**
+     * Exchange function when arenas enabled. See above for explanation.
+     *
+     * @param item the (non-null) item to exchange
+     * @param timed true if the wait is timed
+     * @param ns if timed, the maximum wait time, else 0L
+     * @return the other thread's item; or null if interrupted; or
+     * TIMED_OUT if timed and timed out
+     */
+    private final Object arenaExchange(Object item, boolean timed, long ns) {
+        Node[] a = arena;
+        Node p = participant.get();
+        for (int i = p.index;;) {                      // access slot at i
+            int b, m, c; long j;                       // j is raw array offset
+            Node q = (Node)U.getObjectVolatile(a, j = (i << ASHIFT) + ABASE);
+            if (q != null && U.compareAndSwapObject(a, j, q, null)) {
+                Object v = q.item;                     // release
+                q.match = item;
+                Thread w = q.parked;
+                if (w != null)
+                    U.unpark(w);
+                return v;
+            }
+            else if (i <= (m = (b = bound) & MMASK) && q == null) {
+                p.item = item;                         // offer
+                if (U.compareAndSwapObject(a, j, null, p)) {
+                    long end = (timed && m == 0) ? System.nanoTime() + ns : 0L;
+                    Thread t = Thread.currentThread(); // wait
+                    for (int h = p.hash, spins = SPINS;;) {
+                        Object v = p.match;
+                        if (v != null) {
+                            U.putOrderedObject(p, MATCH, null);
+                            p.item = null;             // clear for next use
+                            p.hash = h;
+                            return v;
+                        }
+                        else if (spins > 0) {
+                            h ^= h << 1; h ^= h >>> 3; h ^= h << 10; // xorshift
+                            if (h == 0)                // initialize hash
+                                h = SPINS | (int)t.getId();
+                            else if (h < 0 &&          // approx 50% true
+                                     (--spins & ((SPINS >>> 1) - 1)) == 0)
+                                Thread.yield();        // two yields per wait
+                        }
+                        else if (U.getObjectVolatile(a, j) != p)
+                            spins = SPINS;       // releaser hasn't set match yet
+                        else if (!t.isInterrupted() && m == 0 &&
+                                 (!timed ||
+                                  (ns = end - System.nanoTime()) > 0L)) {
+                            U.putObject(t, BLOCKER, this); // emulate LockSupport
+                            p.parked = t;              // minimize window
+                            if (U.getObjectVolatile(a, j) == p)
+                                U.park(false, ns);
+                            p.parked = null;
+                            U.putObject(t, BLOCKER, null);
+                        }
+                        else if (U.getObjectVolatile(a, j) == p &&
+                                 U.compareAndSwapObject(a, j, p, null)) {
+                            if (m != 0)                // try to shrink
+                                U.compareAndSwapInt(this, BOUND, b, b + SEQ - 1);
+                            p.item = null;
+                            p.hash = h;
+                            i = p.index >>>= 1;        // descend
+                            if (Thread.interrupted())
+                                return null;
+                            if (timed && m == 0 && ns <= 0L)
+                                return TIMED_OUT;
+                            break;                     // expired; restart
+                        }
+                    }
+                }
+                else
+                    p.item = null;                     // clear offer
+            }
+            else {
+                if (p.bound != b) {                    // stale; reset
+                    p.bound = b;
+                    p.collides = 0;
+                    i = (i != m || m == 0) ? m : m - 1;
+                }
+                else if ((c = p.collides) < m || m == FULL ||
+                         !U.compareAndSwapInt(this, BOUND, b, b + SEQ + 1)) {
+                    p.collides = c + 1;
+                    i = (i == 0) ? m : i - 1;          // cyclically traverse
+                }
+                else
+                    i = m + 1;                         // grow
+                p.index = i;
+            }
+        }
+    }
+
+    /**
+     * Exchange function used until arenas enabled. See above for explanation.
+     *
+     * @param item the item to exchange
+     * @param timed true if the wait is timed
+     * @param ns if timed, the maximum wait time, else 0L
+     * @return the other thread's item; or null if either the arena
+     * was enabled or the thread was interrupted before completion; or
+     * TIMED_OUT if timed and timed out
+     */
+    private final Object slotExchange(Object item, boolean timed, long ns) {
+        Node p = participant.get();
+        Thread t = Thread.currentThread();
+        if (t.isInterrupted()) // preserve interrupt status so caller can recheck
+            return null;
+
+        for (Node q;;) {
+            if ((q = slot) != null) {
+                if (U.compareAndSwapObject(this, SLOT, q, null)) {
+                    Object v = q.item;
+                    q.match = item;
+                    Thread w = q.parked;
+                    if (w != null)
+                        U.unpark(w);
+                    return v;
+                }
+                // create arena on contention, but continue until slot null
+                if (NCPU > 1 && bound == 0 &&
+                    U.compareAndSwapInt(this, BOUND, 0, SEQ))
+                    arena = new Node[(FULL + 2) << ASHIFT];
+            }
+            else if (arena != null)
+                return null; // caller must reroute to arenaExchange
+            else {
+                p.item = item;
+                if (U.compareAndSwapObject(this, SLOT, null, p))
+                    break;
+                p.item = null;
+            }
+        }
+
+        // await release
+        int h = p.hash;
+        long end = timed ? System.nanoTime() + ns : 0L;
+        int spins = (NCPU > 1) ? SPINS : 1;
+        Object v;
+        while ((v = p.match) == null) {
+            if (spins > 0) {
+                h ^= h << 1; h ^= h >>> 3; h ^= h << 10;
+                if (h == 0)
+                    h = SPINS | (int)t.getId();
+                else if (h < 0 && (--spins & ((SPINS >>> 1) - 1)) == 0)
+                    Thread.yield();
+            }
+            else if (slot != p)
+                spins = SPINS;
+            else if (!t.isInterrupted() && arena == null &&
+                     (!timed || (ns = end - System.nanoTime()) > 0L)) {
+                U.putObject(t, BLOCKER, this);
+                p.parked = t;
+                if (slot == p)
+                    U.park(false, ns);
+                p.parked = null;
+                U.putObject(t, BLOCKER, null);
+            }
+            else if (U.compareAndSwapObject(this, SLOT, p, null)) {
+                v = timed && ns <= 0L && !t.isInterrupted() ? TIMED_OUT : null;
+                break;
+            }
+        }
+        U.putOrderedObject(p, MATCH, null);
+        p.item = null;
+        p.hash = h;
+        return v;
+    }
+
+    /**
+     * Creates a new Exchanger.
+     */
+    public Exchanger() {
+        participant = new Participant();
+    }
+
+    /**
+     * Waits for another thread to arrive at this exchange point (unless
+     * the current thread is {@linkplain Thread#interrupt interrupted}),
+     * and then transfers the given object to it, receiving its object
+     * in return.
+     *
+     * <p>If another thread is already waiting at the exchange point then
+     * it is resumed for thread scheduling purposes and receives the object
+     * passed in by the current thread.  The current thread returns immediately,
+     * receiving the object passed to the exchange by that other thread.
+     *
+     * <p>If no other thread is already waiting at the exchange then the
+     * current thread is disabled for thread scheduling purposes and lies
+     * dormant until one of two things happens:
+     * <ul>
+     * <li>Some other thread enters the exchange; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for the exchange,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @param x the object to exchange
+     * @return the object provided by the other thread
+     * @throws InterruptedException if the current thread was
+     *         interrupted while waiting
+     */
+    @SuppressWarnings("unchecked")
+    public V exchange(V x) throws InterruptedException {
+        Object v;
+        Object item = (x == null) ? NULL_ITEM : x; // translate null args
+        if ((arena != null ||
+             (v = slotExchange(item, false, 0L)) == null) &&
+            ((Thread.interrupted() || // disambiguates null return
+              (v = arenaExchange(item, false, 0L)) == null)))
+            throw new InterruptedException();
+        return (v == NULL_ITEM) ? null : (V)v;
+    }
+
+    /**
+     * Waits for another thread to arrive at this exchange point (unless
+     * the current thread is {@linkplain Thread#interrupt interrupted} or
+     * the specified waiting time elapses), and then transfers the given
+     * object to it, receiving its object in return.
+     *
+     * <p>If another thread is already waiting at the exchange point then
+     * it is resumed for thread scheduling purposes and receives the object
+     * passed in by the current thread.  The current thread returns immediately,
+     * receiving the object passed to the exchange by that other thread.
+     *
+     * <p>If no other thread is already waiting at the exchange then the
+     * current thread is disabled for thread scheduling purposes and lies
+     * dormant until one of three things happens:
+     * <ul>
+     * <li>Some other thread enters the exchange; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for the exchange,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then {@link
+     * TimeoutException} is thrown.  If the time is less than or equal
+     * to zero, the method will not wait at all.
+     *
+     * @param x the object to exchange
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the {@code timeout} argument
+     * @return the object provided by the other thread
+     * @throws InterruptedException if the current thread was
+     *         interrupted while waiting
+     * @throws TimeoutException if the specified waiting time elapses
+     *         before another thread enters the exchange
+     */
+    @SuppressWarnings("unchecked")
+    public V exchange(V x, long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException {
+        Object v;
+        Object item = (x == null) ? NULL_ITEM : x;
+        long ns = unit.toNanos(timeout);
+        if ((arena != null ||
+             (v = slotExchange(item, true, ns)) == null) &&
+            ((Thread.interrupted() ||
+              (v = arenaExchange(item, true, ns)) == null)))
+            throw new InterruptedException();
+        if (v == TIMED_OUT)
+            throw new TimeoutException();
+        return (v == NULL_ITEM) ? null : (V)v;
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long BOUND;
+    private static final long SLOT;
+    private static final long MATCH;
+    private static final long BLOCKER;
+    private static final int ABASE;
+    static {
+        try {
+            BOUND = U.objectFieldOffset
+                (Exchanger.class.getDeclaredField("bound"));
+            SLOT = U.objectFieldOffset
+                (Exchanger.class.getDeclaredField("slot"));
+
+            MATCH = U.objectFieldOffset
+                (Node.class.getDeclaredField("match"));
+
+            BLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+
+            int scale = U.arrayIndexScale(Node[].class);
+            if ((scale & (scale - 1)) != 0 || scale > (1 << ASHIFT))
+                throw new Error("Unsupported array scale");
+            // ABASE absorbs padding in front of element 0
+            ABASE = U.arrayBaseOffset(Node[].class) + (1 << ASHIFT);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/ExecutionException.java b/java/util/concurrent/ExecutionException.java
new file mode 100644
index 0000000..71e7a71
--- /dev/null
+++ b/java/util/concurrent/ExecutionException.java
@@ -0,0 +1,92 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when attempting to retrieve the result of a task
+ * that aborted by throwing an exception. This exception can be
+ * inspected using the {@link #getCause()} method.
+ *
+ * @see Future
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ExecutionException extends Exception {
+    private static final long serialVersionUID = 7830266012832686185L;
+
+    /**
+     * Constructs an {@code ExecutionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    protected ExecutionException() { }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified detail
+     * message. The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    protected ExecutionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified detail
+     * message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public ExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs an {@code ExecutionException} with the specified cause.
+     * The detail message is set to {@code (cause == null ? null :
+     * cause.toString())} (which typically contains the class and
+     * detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public ExecutionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/util/concurrent/Executor.java b/java/util/concurrent/Executor.java
new file mode 100644
index 0000000..a615705
--- /dev/null
+++ b/java/util/concurrent/Executor.java
@@ -0,0 +1,139 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An object that executes submitted {@link Runnable} tasks. This
+ * interface provides a way of decoupling task submission from the
+ * mechanics of how each task will be run, including details of thread
+ * use, scheduling, etc.  An {@code Executor} is normally used
+ * instead of explicitly creating threads. For example, rather than
+ * invoking {@code new Thread(new RunnableTask()).start()} for each
+ * of a set of tasks, you might use:
+ *
+ * <pre> {@code
+ * Executor executor = anExecutor();
+ * executor.execute(new RunnableTask1());
+ * executor.execute(new RunnableTask2());
+ * ...}</pre>
+ *
+ * However, the {@code Executor} interface does not strictly require
+ * that execution be asynchronous. In the simplest case, an executor
+ * can run the submitted task immediately in the caller's thread:
+ *
+ * <pre> {@code
+ * class DirectExecutor implements Executor {
+ *   public void execute(Runnable r) {
+ *     r.run();
+ *   }
+ * }}</pre>
+ *
+ * More typically, tasks are executed in some thread other than the
+ * caller's thread.  The executor below spawns a new thread for each
+ * task.
+ *
+ * <pre> {@code
+ * class ThreadPerTaskExecutor implements Executor {
+ *   public void execute(Runnable r) {
+ *     new Thread(r).start();
+ *   }
+ * }}</pre>
+ *
+ * Many {@code Executor} implementations impose some sort of
+ * limitation on how and when tasks are scheduled.  The executor below
+ * serializes the submission of tasks to a second executor,
+ * illustrating a composite executor.
+ *
+ * <pre> {@code
+ * class SerialExecutor implements Executor {
+ *   final Queue<Runnable> tasks = new ArrayDeque<>();
+ *   final Executor executor;
+ *   Runnable active;
+ *
+ *   SerialExecutor(Executor executor) {
+ *     this.executor = executor;
+ *   }
+ *
+ *   public synchronized void execute(final Runnable r) {
+ *     tasks.add(new Runnable() {
+ *       public void run() {
+ *         try {
+ *           r.run();
+ *         } finally {
+ *           scheduleNext();
+ *         }
+ *       }
+ *     });
+ *     if (active == null) {
+ *       scheduleNext();
+ *     }
+ *   }
+ *
+ *   protected synchronized void scheduleNext() {
+ *     if ((active = tasks.poll()) != null) {
+ *       executor.execute(active);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * The {@code Executor} implementations provided in this package
+ * implement {@link ExecutorService}, which is a more extensive
+ * interface.  The {@link ThreadPoolExecutor} class provides an
+ * extensible thread pool implementation. The {@link Executors} class
+ * provides convenient factory methods for these Executors.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to
+ * submitting a {@code Runnable} object to an {@code Executor}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * its execution begins, perhaps in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Executor {
+
+    /**
+     * Executes the given command at some time in the future.  The command
+     * may execute in a new thread, in a pooled thread, or in the calling
+     * thread, at the discretion of the {@code Executor} implementation.
+     *
+     * @param command the runnable task
+     * @throws RejectedExecutionException if this task cannot be
+     * accepted for execution
+     * @throws NullPointerException if command is null
+     */
+    void execute(Runnable command);
+}
diff --git a/java/util/concurrent/ExecutorCompletionService.java b/java/util/concurrent/ExecutorCompletionService.java
new file mode 100644
index 0000000..a093844
--- /dev/null
+++ b/java/util/concurrent/ExecutorCompletionService.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link CompletionService} that uses a supplied {@link Executor}
+ * to execute tasks.  This class arranges that submitted tasks are,
+ * upon completion, placed on a queue accessible using {@code take}.
+ * The class is lightweight enough to be suitable for transient use
+ * when processing groups of tasks.
+ *
+ * <p>
+ *
+ * <b>Usage Examples.</b>
+ *
+ * Suppose you have a set of solvers for a certain problem, each
+ * returning a value of some type {@code Result}, and would like to
+ * run them concurrently, processing the results of each of them that
+ * return a non-null value, in some method {@code use(Result r)}. You
+ * could write this as:
+ *
+ * <pre> {@code
+ * void solve(Executor e,
+ *            Collection<Callable<Result>> solvers)
+ *     throws InterruptedException, ExecutionException {
+ *   CompletionService<Result> ecs
+ *       = new ExecutorCompletionService<Result>(e);
+ *   for (Callable<Result> s : solvers)
+ *     ecs.submit(s);
+ *   int n = solvers.size();
+ *   for (int i = 0; i < n; ++i) {
+ *     Result r = ecs.take().get();
+ *     if (r != null)
+ *       use(r);
+ *   }
+ * }}</pre>
+ *
+ * Suppose instead that you would like to use the first non-null result
+ * of the set of tasks, ignoring any that encounter exceptions,
+ * and cancelling all other tasks when the first one is ready:
+ *
+ * <pre> {@code
+ * void solve(Executor e,
+ *            Collection<Callable<Result>> solvers)
+ *     throws InterruptedException {
+ *   CompletionService<Result> ecs
+ *       = new ExecutorCompletionService<Result>(e);
+ *   int n = solvers.size();
+ *   List<Future<Result>> futures = new ArrayList<>(n);
+ *   Result result = null;
+ *   try {
+ *     for (Callable<Result> s : solvers)
+ *       futures.add(ecs.submit(s));
+ *     for (int i = 0; i < n; ++i) {
+ *       try {
+ *         Result r = ecs.take().get();
+ *         if (r != null) {
+ *           result = r;
+ *           break;
+ *         }
+ *       } catch (ExecutionException ignore) {}
+ *     }
+ *   }
+ *   finally {
+ *     for (Future<Result> f : futures)
+ *       f.cancel(true);
+ *   }
+ *
+ *   if (result != null)
+ *     use(result);
+ * }}</pre>
+ */
+public class ExecutorCompletionService<V> implements CompletionService<V> {
+    private final Executor executor;
+    private final AbstractExecutorService aes;
+    private final BlockingQueue<Future<V>> completionQueue;
+
+    /**
+     * FutureTask extension to enqueue upon completion.
+     */
+    private static class QueueingFuture<V> extends FutureTask<Void> {
+        QueueingFuture(RunnableFuture<V> task,
+                       BlockingQueue<Future<V>> completionQueue) {
+            super(task, null);
+            this.task = task;
+            this.completionQueue = completionQueue;
+        }
+        private final Future<V> task;
+        private final BlockingQueue<Future<V>> completionQueue;
+        protected void done() { completionQueue.add(task); }
+    }
+
+    private RunnableFuture<V> newTaskFor(Callable<V> task) {
+        if (aes == null)
+            return new FutureTask<V>(task);
+        else
+            return aes.newTaskFor(task);
+    }
+
+    private RunnableFuture<V> newTaskFor(Runnable task, V result) {
+        if (aes == null)
+            return new FutureTask<V>(task, result);
+        else
+            return aes.newTaskFor(task, result);
+    }
+
+    /**
+     * Creates an ExecutorCompletionService using the supplied
+     * executor for base task execution and a
+     * {@link LinkedBlockingQueue} as a completion queue.
+     *
+     * @param executor the executor to use
+     * @throws NullPointerException if executor is {@code null}
+     */
+    public ExecutorCompletionService(Executor executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        this.executor = executor;
+        this.aes = (executor instanceof AbstractExecutorService) ?
+            (AbstractExecutorService) executor : null;
+        this.completionQueue = new LinkedBlockingQueue<Future<V>>();
+    }
+
+    /**
+     * Creates an ExecutorCompletionService using the supplied
+     * executor for base task execution and the supplied queue as its
+     * completion queue.
+     *
+     * @param executor the executor to use
+     * @param completionQueue the queue to use as the completion queue
+     *        normally one dedicated for use by this service. This
+     *        queue is treated as unbounded -- failed attempted
+     *        {@code Queue.add} operations for completed tasks cause
+     *        them not to be retrievable.
+     * @throws NullPointerException if executor or completionQueue are {@code null}
+     */
+    public ExecutorCompletionService(Executor executor,
+                                     BlockingQueue<Future<V>> completionQueue) {
+        if (executor == null || completionQueue == null)
+            throw new NullPointerException();
+        this.executor = executor;
+        this.aes = (executor instanceof AbstractExecutorService) ?
+            (AbstractExecutorService) executor : null;
+        this.completionQueue = completionQueue;
+    }
+
+    public Future<V> submit(Callable<V> task) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<V> f = newTaskFor(task);
+        executor.execute(new QueueingFuture<V>(f, completionQueue));
+        return f;
+    }
+
+    public Future<V> submit(Runnable task, V result) {
+        if (task == null) throw new NullPointerException();
+        RunnableFuture<V> f = newTaskFor(task, result);
+        executor.execute(new QueueingFuture<V>(f, completionQueue));
+        return f;
+    }
+
+    public Future<V> take() throws InterruptedException {
+        return completionQueue.take();
+    }
+
+    public Future<V> poll() {
+        return completionQueue.poll();
+    }
+
+    public Future<V> poll(long timeout, TimeUnit unit)
+            throws InterruptedException {
+        return completionQueue.poll(timeout, unit);
+    }
+
+}
diff --git a/java/util/concurrent/ExecutorService.java b/java/util/concurrent/ExecutorService.java
new file mode 100644
index 0000000..83be00b
--- /dev/null
+++ b/java/util/concurrent/ExecutorService.java
@@ -0,0 +1,360 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.List;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * An {@link Executor} that provides methods to manage termination and
+ * methods that can produce a {@link Future} for tracking progress of
+ * one or more asynchronous tasks.
+ *
+ * <p>An {@code ExecutorService} can be shut down, which will cause
+ * it to reject new tasks.  Two different methods are provided for
+ * shutting down an {@code ExecutorService}. The {@link #shutdown}
+ * method will allow previously submitted tasks to execute before
+ * terminating, while the {@link #shutdownNow} method prevents waiting
+ * tasks from starting and attempts to stop currently executing tasks.
+ * Upon termination, an executor has no tasks actively executing, no
+ * tasks awaiting execution, and no new tasks can be submitted.  An
+ * unused {@code ExecutorService} should be shut down to allow
+ * reclamation of its resources.
+ *
+ * <p>Method {@code submit} extends base method {@link
+ * Executor#execute(Runnable)} by creating and returning a {@link Future}
+ * that can be used to cancel execution and/or wait for completion.
+ * Methods {@code invokeAny} and {@code invokeAll} perform the most
+ * commonly useful forms of bulk execution, executing a collection of
+ * tasks and then waiting for at least one, or all, to
+ * complete. (Class {@link ExecutorCompletionService} can be used to
+ * write customized variants of these methods.)
+ *
+ * <p>The {@link Executors} class provides factory methods for the
+ * executor services provided in this package.
+ *
+ * <h3>Usage Examples</h3>
+ *
+ * Here is a sketch of a network service in which threads in a thread
+ * pool service incoming requests. It uses the preconfigured {@link
+ * Executors#newFixedThreadPool} factory method:
+ *
+ * <pre> {@code
+ * class NetworkService implements Runnable {
+ *   private final ServerSocket serverSocket;
+ *   private final ExecutorService pool;
+ *
+ *   public NetworkService(int port, int poolSize)
+ *       throws IOException {
+ *     serverSocket = new ServerSocket(port);
+ *     pool = Executors.newFixedThreadPool(poolSize);
+ *   }
+ *
+ *   public void run() { // run the service
+ *     try {
+ *       for (;;) {
+ *         pool.execute(new Handler(serverSocket.accept()));
+ *       }
+ *     } catch (IOException ex) {
+ *       pool.shutdown();
+ *     }
+ *   }
+ * }
+ *
+ * class Handler implements Runnable {
+ *   private final Socket socket;
+ *   Handler(Socket socket) { this.socket = socket; }
+ *   public void run() {
+ *     // read and service request on socket
+ *   }
+ * }}</pre>
+ *
+ * The following method shuts down an {@code ExecutorService} in two phases,
+ * first by calling {@code shutdown} to reject incoming tasks, and then
+ * calling {@code shutdownNow}, if necessary, to cancel any lingering tasks:
+ *
+ * <pre> {@code
+ * void shutdownAndAwaitTermination(ExecutorService pool) {
+ *   pool.shutdown(); // Disable new tasks from being submitted
+ *   try {
+ *     // Wait a while for existing tasks to terminate
+ *     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
+ *       pool.shutdownNow(); // Cancel currently executing tasks
+ *       // Wait a while for tasks to respond to being cancelled
+ *       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
+ *           System.err.println("Pool did not terminate");
+ *     }
+ *   } catch (InterruptedException ie) {
+ *     // (Re-)Cancel if current thread also interrupted
+ *     pool.shutdownNow();
+ *     // Preserve interrupt status
+ *     Thread.currentThread().interrupt();
+ *   }
+ * }}</pre>
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to the
+ * submission of a {@code Runnable} or {@code Callable} task to an
+ * {@code ExecutorService}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * any actions taken by that task, which in turn <i>happen-before</i> the
+ * result is retrieved via {@code Future.get()}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ExecutorService extends Executor {
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     */
+    void shutdown();
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  For example, typical
+     * implementations will cancel via {@link Thread#interrupt}, so any
+     * task that fails to respond to interrupts may never terminate.
+     *
+     * @return list of tasks that never commenced execution
+     */
+    List<Runnable> shutdownNow();
+
+    /**
+     * Returns {@code true} if this executor has been shut down.
+     *
+     * @return {@code true} if this executor has been shut down
+     */
+    boolean isShutdown();
+
+    /**
+     * Returns {@code true} if all tasks have completed following shut down.
+     * Note that {@code isTerminated} is never {@code true} unless
+     * either {@code shutdown} or {@code shutdownNow} was called first.
+     *
+     * @return {@code true} if all tasks have completed following shut down
+     */
+    boolean isTerminated();
+
+    /**
+     * Blocks until all tasks have completed execution after a shutdown
+     * request, or the timeout occurs, or the current thread is
+     * interrupted, whichever happens first.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if this executor terminated and
+     *         {@code false} if the timeout elapsed before termination
+     * @throws InterruptedException if interrupted while waiting
+     */
+    boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Submits a value-returning task for execution and returns a
+     * Future representing the pending results of the task. The
+     * Future's {@code get} method will return the task's result upon
+     * successful completion.
+     *
+     * <p>
+     * If you would like to immediately block waiting
+     * for a task, you can use constructions of the form
+     * {@code result = exec.submit(aCallable).get();}
+     *
+     * <p>Note: The {@link Executors} class includes a set of methods
+     * that can convert some other common closure-like objects,
+     * for example, {@link java.security.PrivilegedAction} to
+     * {@link Callable} form so they can be submitted.
+     *
+     * @param task the task to submit
+     * @param <T> the type of the task's result
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    <T> Future<T> submit(Callable<T> task);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task. The Future's {@code get} method will
+     * return the given result upon successful completion.
+     *
+     * @param task the task to submit
+     * @param result the result to return
+     * @param <T> the type of the result
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    <T> Future<T> submit(Runnable task, T result);
+
+    /**
+     * Submits a Runnable task for execution and returns a Future
+     * representing that task. The Future's {@code get} method will
+     * return {@code null} upon <em>successful</em> completion.
+     *
+     * @param task the task to submit
+     * @return a Future representing pending completion of the task
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if the task is null
+     */
+    Future<?> submit(Runnable task);
+
+    /**
+     * Executes the given tasks, returning a list of Futures holding
+     * their status and results when all complete.
+     * {@link Future#isDone} is {@code true} for each
+     * element of the returned list.
+     * Note that a <em>completed</em> task could have
+     * terminated either normally or by throwing an exception.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return a list of Futures representing the tasks, in the same
+     *         sequential order as produced by the iterator for the
+     *         given task list, each of which has completed
+     * @throws InterruptedException if interrupted while waiting, in
+     *         which case unfinished tasks are cancelled
+     * @throws NullPointerException if tasks or any of its elements are {@code null}
+     * @throws RejectedExecutionException if any task cannot be
+     *         scheduled for execution
+     */
+    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException;
+
+    /**
+     * Executes the given tasks, returning a list of Futures holding
+     * their status and results
+     * when all complete or the timeout expires, whichever happens first.
+     * {@link Future#isDone} is {@code true} for each
+     * element of the returned list.
+     * Upon return, tasks that have not completed are cancelled.
+     * Note that a <em>completed</em> task could have
+     * terminated either normally or by throwing an exception.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @param <T> the type of the values returned from the tasks
+     * @return a list of Futures representing the tasks, in the same
+     *         sequential order as produced by the iterator for the
+     *         given task list. If the operation did not time out,
+     *         each task will have completed. If it did time out, some
+     *         of these tasks will not have completed.
+     * @throws InterruptedException if interrupted while waiting, in
+     *         which case unfinished tasks are cancelled
+     * @throws NullPointerException if tasks, any of its elements, or
+     *         unit are {@code null}
+     * @throws RejectedExecutionException if any task cannot be scheduled
+     *         for execution
+     */
+    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                  long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Executes the given tasks, returning the result
+     * of one that has completed successfully (i.e., without throwing
+     * an exception), if any do. Upon normal or exceptional return,
+     * tasks that have not completed are cancelled.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return the result returned by one of the tasks
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if tasks or any element task
+     *         subject to execution is {@code null}
+     * @throws IllegalArgumentException if tasks is empty
+     * @throws ExecutionException if no task successfully completes
+     * @throws RejectedExecutionException if tasks cannot be scheduled
+     *         for execution
+     */
+    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+        throws InterruptedException, ExecutionException;
+
+    /**
+     * Executes the given tasks, returning the result
+     * of one that has completed successfully (i.e., without throwing
+     * an exception), if any do before the given timeout elapses.
+     * Upon normal or exceptional return, tasks that have not
+     * completed are cancelled.
+     * The results of this method are undefined if the given
+     * collection is modified while this operation is in progress.
+     *
+     * @param tasks the collection of tasks
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @param <T> the type of the values returned from the tasks
+     * @return the result returned by one of the tasks
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if tasks, or unit, or any element
+     *         task subject to execution is {@code null}
+     * @throws TimeoutException if the given timeout elapses before
+     *         any task successfully completes
+     * @throws ExecutionException if no task successfully completes
+     * @throws RejectedExecutionException if tasks cannot be scheduled
+     *         for execution
+     */
+    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                    long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/java/util/concurrent/Executors.java b/java/util/concurrent/Executors.java
new file mode 100644
index 0000000..565fdeb
--- /dev/null
+++ b/java/util/concurrent/Executors.java
@@ -0,0 +1,706 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import sun.security.util.SecurityConstants;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * Factory and utility methods for {@link Executor}, {@link
+ * ExecutorService}, {@link ScheduledExecutorService}, {@link
+ * ThreadFactory}, and {@link Callable} classes defined in this
+ * package. This class supports the following kinds of methods:
+ *
+ * <ul>
+ *   <li>Methods that create and return an {@link ExecutorService}
+ *       set up with commonly useful configuration settings.
+ *   <li>Methods that create and return a {@link ScheduledExecutorService}
+ *       set up with commonly useful configuration settings.
+ *   <li>Methods that create and return a "wrapped" ExecutorService, that
+ *       disables reconfiguration by making implementation-specific methods
+ *       inaccessible.
+ *   <li>Methods that create and return a {@link ThreadFactory}
+ *       that sets newly created threads to a known state.
+ *   <li>Methods that create and return a {@link Callable}
+ *       out of other closure-like forms, so they can be used
+ *       in execution methods requiring {@code Callable}.
+ * </ul>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Executors {
+
+    /**
+     * Creates a thread pool that reuses a fixed number of threads
+     * operating off a shared unbounded queue.  At any point, at most
+     * {@code nThreads} threads will be active processing tasks.
+     * If additional tasks are submitted when all threads are active,
+     * they will wait in the queue until a thread is available.
+     * If any thread terminates due to a failure during execution
+     * prior to shutdown, a new one will take its place if needed to
+     * execute subsequent tasks.  The threads in the pool will exist
+     * until it is explicitly {@link ExecutorService#shutdown shutdown}.
+     *
+     * @param nThreads the number of threads in the pool
+     * @return the newly created thread pool
+     * @throws IllegalArgumentException if {@code nThreads <= 0}
+     */
+    public static ExecutorService newFixedThreadPool(int nThreads) {
+        return new ThreadPoolExecutor(nThreads, nThreads,
+                                      0L, TimeUnit.MILLISECONDS,
+                                      new LinkedBlockingQueue<Runnable>());
+    }
+
+    /**
+     * Creates a thread pool that maintains enough threads to support
+     * the given parallelism level, and may use multiple queues to
+     * reduce contention. The parallelism level corresponds to the
+     * maximum number of threads actively engaged in, or available to
+     * engage in, task processing. The actual number of threads may
+     * grow and shrink dynamically. A work-stealing pool makes no
+     * guarantees about the order in which submitted tasks are
+     * executed.
+     *
+     * @param parallelism the targeted parallelism level
+     * @return the newly created thread pool
+     * @throws IllegalArgumentException if {@code parallelism <= 0}
+     * @since 1.8
+     */
+    public static ExecutorService newWorkStealingPool(int parallelism) {
+        return new ForkJoinPool
+            (parallelism,
+             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+             null, true);
+    }
+
+    /**
+     * Creates a work-stealing thread pool using the number of
+     * {@linkplain Runtime#availableProcessors available processors}
+     * as its target parallelism level.
+     *
+     * @return the newly created thread pool
+     * @see #newWorkStealingPool(int)
+     * @since 1.8
+     */
+    public static ExecutorService newWorkStealingPool() {
+        return new ForkJoinPool
+            (Runtime.getRuntime().availableProcessors(),
+             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
+             null, true);
+    }
+
+    /**
+     * Creates a thread pool that reuses a fixed number of threads
+     * operating off a shared unbounded queue, using the provided
+     * ThreadFactory to create new threads when needed.  At any point,
+     * at most {@code nThreads} threads will be active processing
+     * tasks.  If additional tasks are submitted when all threads are
+     * active, they will wait in the queue until a thread is
+     * available.  If any thread terminates due to a failure during
+     * execution prior to shutdown, a new one will take its place if
+     * needed to execute subsequent tasks.  The threads in the pool will
+     * exist until it is explicitly {@link ExecutorService#shutdown
+     * shutdown}.
+     *
+     * @param nThreads the number of threads in the pool
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created thread pool
+     * @throws NullPointerException if threadFactory is null
+     * @throws IllegalArgumentException if {@code nThreads <= 0}
+     */
+    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
+        return new ThreadPoolExecutor(nThreads, nThreads,
+                                      0L, TimeUnit.MILLISECONDS,
+                                      new LinkedBlockingQueue<Runnable>(),
+                                      threadFactory);
+    }
+
+    /**
+     * Creates an Executor that uses a single worker thread operating
+     * off an unbounded queue. (Note however that if this single
+     * thread terminates due to a failure during execution prior to
+     * shutdown, a new one will take its place if needed to execute
+     * subsequent tasks.)  Tasks are guaranteed to execute
+     * sequentially, and no more than one task will be active at any
+     * given time. Unlike the otherwise equivalent
+     * {@code newFixedThreadPool(1)} the returned executor is
+     * guaranteed not to be reconfigurable to use additional threads.
+     *
+     * @return the newly created single-threaded Executor
+     */
+    public static ExecutorService newSingleThreadExecutor() {
+        return new FinalizableDelegatedExecutorService
+            (new ThreadPoolExecutor(1, 1,
+                                    0L, TimeUnit.MILLISECONDS,
+                                    new LinkedBlockingQueue<Runnable>()));
+    }
+
+    /**
+     * Creates an Executor that uses a single worker thread operating
+     * off an unbounded queue, and uses the provided ThreadFactory to
+     * create a new thread when needed. Unlike the otherwise
+     * equivalent {@code newFixedThreadPool(1, threadFactory)} the
+     * returned executor is guaranteed not to be reconfigurable to use
+     * additional threads.
+     *
+     * @param threadFactory the factory to use when creating new
+     * threads
+     *
+     * @return the newly created single-threaded Executor
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
+        return new FinalizableDelegatedExecutorService
+            (new ThreadPoolExecutor(1, 1,
+                                    0L, TimeUnit.MILLISECONDS,
+                                    new LinkedBlockingQueue<Runnable>(),
+                                    threadFactory));
+    }
+
+    /**
+     * Creates a thread pool that creates new threads as needed, but
+     * will reuse previously constructed threads when they are
+     * available.  These pools will typically improve the performance
+     * of programs that execute many short-lived asynchronous tasks.
+     * Calls to {@code execute} will reuse previously constructed
+     * threads if available. If no existing thread is available, a new
+     * thread will be created and added to the pool. Threads that have
+     * not been used for sixty seconds are terminated and removed from
+     * the cache. Thus, a pool that remains idle for long enough will
+     * not consume any resources. Note that pools with similar
+     * properties but different details (for example, timeout parameters)
+     * may be created using {@link ThreadPoolExecutor} constructors.
+     *
+     * @return the newly created thread pool
+     */
+    public static ExecutorService newCachedThreadPool() {
+        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                      60L, TimeUnit.SECONDS,
+                                      new SynchronousQueue<Runnable>());
+    }
+
+    /**
+     * Creates a thread pool that creates new threads as needed, but
+     * will reuse previously constructed threads when they are
+     * available, and uses the provided
+     * ThreadFactory to create new threads when needed.
+     * @param threadFactory the factory to use when creating new threads
+     * @return the newly created thread pool
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
+        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
+                                      60L, TimeUnit.SECONDS,
+                                      new SynchronousQueue<Runnable>(),
+                                      threadFactory);
+    }
+
+    /**
+     * Creates a single-threaded executor that can schedule commands
+     * to run after a given delay, or to execute periodically.
+     * (Note however that if this single
+     * thread terminates due to a failure during execution prior to
+     * shutdown, a new one will take its place if needed to execute
+     * subsequent tasks.)  Tasks are guaranteed to execute
+     * sequentially, and no more than one task will be active at any
+     * given time. Unlike the otherwise equivalent
+     * {@code newScheduledThreadPool(1)} the returned executor is
+     * guaranteed not to be reconfigurable to use additional threads.
+     * @return the newly created scheduled executor
+     */
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
+        return new DelegatedScheduledExecutorService
+            (new ScheduledThreadPoolExecutor(1));
+    }
+
+    /**
+     * Creates a single-threaded executor that can schedule commands
+     * to run after a given delay, or to execute periodically.  (Note
+     * however that if this single thread terminates due to a failure
+     * during execution prior to shutdown, a new one will take its
+     * place if needed to execute subsequent tasks.)  Tasks are
+     * guaranteed to execute sequentially, and no more than one task
+     * will be active at any given time. Unlike the otherwise
+     * equivalent {@code newScheduledThreadPool(1, threadFactory)}
+     * the returned executor is guaranteed not to be reconfigurable to
+     * use additional threads.
+     * @param threadFactory the factory to use when creating new
+     * threads
+     * @return a newly created scheduled executor
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
+        return new DelegatedScheduledExecutorService
+            (new ScheduledThreadPoolExecutor(1, threadFactory));
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a
+     * given delay, or to execute periodically.
+     * @param corePoolSize the number of threads to keep in the pool,
+     * even if they are idle
+     * @return a newly created scheduled thread pool
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
+        return new ScheduledThreadPoolExecutor(corePoolSize);
+    }
+
+    /**
+     * Creates a thread pool that can schedule commands to run after a
+     * given delay, or to execute periodically.
+     * @param corePoolSize the number of threads to keep in the pool,
+     * even if they are idle
+     * @param threadFactory the factory to use when the executor
+     * creates a new thread
+     * @return a newly created scheduled thread pool
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if threadFactory is null
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(
+            int corePoolSize, ThreadFactory threadFactory) {
+        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
+    }
+
+    /**
+     * Returns an object that delegates all defined {@link
+     * ExecutorService} methods to the given executor, but not any
+     * other methods that might otherwise be accessible using
+     * casts. This provides a way to safely "freeze" configuration and
+     * disallow tuning of a given concrete implementation.
+     * @param executor the underlying implementation
+     * @return an {@code ExecutorService} instance
+     * @throws NullPointerException if executor null
+     */
+    public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        return new DelegatedExecutorService(executor);
+    }
+
+    /**
+     * Returns an object that delegates all defined {@link
+     * ScheduledExecutorService} methods to the given executor, but
+     * not any other methods that might otherwise be accessible using
+     * casts. This provides a way to safely "freeze" configuration and
+     * disallow tuning of a given concrete implementation.
+     * @param executor the underlying implementation
+     * @return a {@code ScheduledExecutorService} instance
+     * @throws NullPointerException if executor null
+     */
+    public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
+        if (executor == null)
+            throw new NullPointerException();
+        return new DelegatedScheduledExecutorService(executor);
+    }
+
+    // Android-changed: Removed references to SecurityManager from javadoc.
+    /**
+     * Returns a default thread factory used to create new threads.
+     * This factory creates all new threads used by an Executor in the
+     * same {@link ThreadGroup}. Each new
+     * thread is created as a non-daemon thread with priority set to
+     * the smaller of {@code Thread.NORM_PRIORITY} and the maximum
+     * priority permitted in the thread group.  New threads have names
+     * accessible via {@link Thread#getName} of
+     * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
+     * number of this factory, and <em>M</em> is the sequence number
+     * of the thread created by this factory.
+     * @return a thread factory
+     */
+    public static ThreadFactory defaultThreadFactory() {
+        return new DefaultThreadFactory();
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     */
+    public static ThreadFactory privilegedThreadFactory() {
+        return new PrivilegedThreadFactory();
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given task and returns the given result.  This
+     * can be useful when applying methods requiring a
+     * {@code Callable} to an otherwise resultless action.
+     * @param task the task to run
+     * @param result the result to return
+     * @param <T> the type of the result
+     * @return a callable object
+     * @throws NullPointerException if task null
+     */
+    public static <T> Callable<T> callable(Runnable task, T result) {
+        if (task == null)
+            throw new NullPointerException();
+        return new RunnableAdapter<T>(task, result);
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given task and returns {@code null}.
+     * @param task the task to run
+     * @return a callable object
+     * @throws NullPointerException if task null
+     */
+    public static Callable<Object> callable(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        return new RunnableAdapter<Object>(task, null);
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given privileged action and returns its result.
+     * @param action the privileged action to run
+     * @return a callable object
+     * @throws NullPointerException if action null
+     */
+    public static Callable<Object> callable(final PrivilegedAction<?> action) {
+        if (action == null)
+            throw new NullPointerException();
+        return new Callable<Object>() {
+            public Object call() { return action.run(); }};
+    }
+
+    /**
+     * Returns a {@link Callable} object that, when
+     * called, runs the given privileged exception action and returns
+     * its result.
+     * @param action the privileged exception action to run
+     * @return a callable object
+     * @throws NullPointerException if action null
+     */
+    public static Callable<Object> callable(final PrivilegedExceptionAction<?> action) {
+        if (action == null)
+            throw new NullPointerException();
+        return new Callable<Object>() {
+            public Object call() throws Exception { return action.run(); }};
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     */
+    public static <T> Callable<T> privilegedCallable(Callable<T> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        return new PrivilegedCallable<T>(callable);
+    }
+
+    // Android-changed: Dropped documentation for legacy security code.
+    /**
+     * Legacy security code; do not use.
+     */
+    public static <T> Callable<T> privilegedCallableUsingCurrentClassLoader(Callable<T> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        return new PrivilegedCallableUsingCurrentClassLoader<T>(callable);
+    }
+
+    // Non-public classes supporting the public methods
+
+    /**
+     * A callable that runs given task and returns given result.
+     */
+    private static final class RunnableAdapter<T> implements Callable<T> {
+        private final Runnable task;
+        private final T result;
+        RunnableAdapter(Runnable task, T result) {
+            this.task = task;
+            this.result = result;
+        }
+        public T call() {
+            task.run();
+            return result;
+        }
+    }
+
+    /**
+     * A callable that runs under established access control settings.
+     */
+    private static final class PrivilegedCallable<T> implements Callable<T> {
+        final Callable<T> task;
+        final AccessControlContext acc;
+
+        PrivilegedCallable(Callable<T> task) {
+            this.task = task;
+            this.acc = AccessController.getContext();
+        }
+
+        public T call() throws Exception {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<T>() {
+                        public T run() throws Exception {
+                            return task.call();
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException e) {
+                throw e.getException();
+            }
+        }
+    }
+
+    /**
+     * A callable that runs under established access control settings and
+     * current ClassLoader.
+     */
+    private static final class PrivilegedCallableUsingCurrentClassLoader<T>
+            implements Callable<T> {
+        final Callable<T> task;
+        final AccessControlContext acc;
+        final ClassLoader ccl;
+
+        PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {
+            // Android-removed: System.getSecurityManager always returns null.
+            /*
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                // Calls to getContextClassLoader from this class
+                // never trigger a security check, but we check
+                // whether our callers have this permission anyways.
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+
+                // Whether setContextClassLoader turns out to be necessary
+                // or not, we fail fast if permission is not available.
+                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+            }
+            */
+            this.task = task;
+            this.acc = AccessController.getContext();
+            this.ccl = Thread.currentThread().getContextClassLoader();
+        }
+
+        public T call() throws Exception {
+            try {
+                return AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<T>() {
+                        public T run() throws Exception {
+                            Thread t = Thread.currentThread();
+                            ClassLoader cl = t.getContextClassLoader();
+                            if (ccl == cl) {
+                                return task.call();
+                            } else {
+                                t.setContextClassLoader(ccl);
+                                try {
+                                    return task.call();
+                                } finally {
+                                    t.setContextClassLoader(cl);
+                                }
+                            }
+                        }
+                    }, acc);
+            } catch (PrivilegedActionException e) {
+                throw e.getException();
+            }
+        }
+    }
+
+    /**
+     * The default thread factory.
+     */
+    private static class DefaultThreadFactory implements ThreadFactory {
+        private static final AtomicInteger poolNumber = new AtomicInteger(1);
+        private final ThreadGroup group;
+        private final AtomicInteger threadNumber = new AtomicInteger(1);
+        private final String namePrefix;
+
+        DefaultThreadFactory() {
+            SecurityManager s = System.getSecurityManager();
+            group = (s != null) ? s.getThreadGroup() :
+                                  Thread.currentThread().getThreadGroup();
+            namePrefix = "pool-" +
+                          poolNumber.getAndIncrement() +
+                         "-thread-";
+        }
+
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(group, r,
+                                  namePrefix + threadNumber.getAndIncrement(),
+                                  0);
+            if (t.isDaemon())
+                t.setDaemon(false);
+            if (t.getPriority() != Thread.NORM_PRIORITY)
+                t.setPriority(Thread.NORM_PRIORITY);
+            return t;
+        }
+    }
+
+    /**
+     * Thread factory capturing access control context and class loader.
+     */
+    private static class PrivilegedThreadFactory extends DefaultThreadFactory {
+        final AccessControlContext acc;
+        final ClassLoader ccl;
+
+        PrivilegedThreadFactory() {
+            super();
+            // Android-removed: System.getSecurityManager always returns null.
+            /*
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                // Calls to getContextClassLoader from this class
+                // never trigger a security check, but we check
+                // whether our callers have this permission anyways.
+                sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+
+                // Fail fast
+                sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+            }
+            */
+            this.acc = AccessController.getContext();
+            this.ccl = Thread.currentThread().getContextClassLoader();
+        }
+
+        public Thread newThread(final Runnable r) {
+            return super.newThread(new Runnable() {
+                public void run() {
+                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                        public Void run() {
+                            Thread.currentThread().setContextClassLoader(ccl);
+                            r.run();
+                            return null;
+                        }
+                    }, acc);
+                }
+            });
+        }
+    }
+
+    /**
+     * A wrapper class that exposes only the ExecutorService methods
+     * of an ExecutorService implementation.
+     */
+    private static class DelegatedExecutorService
+            extends AbstractExecutorService {
+        // Android-added: @ReachabilitySensitive
+        // Needed for FinalizableDelegatedExecutorService below.
+        @ReachabilitySensitive
+        private final ExecutorService e;
+        DelegatedExecutorService(ExecutorService executor) { e = executor; }
+        public void execute(Runnable command) { e.execute(command); }
+        public void shutdown() { e.shutdown(); }
+        public List<Runnable> shutdownNow() { return e.shutdownNow(); }
+        public boolean isShutdown() { return e.isShutdown(); }
+        public boolean isTerminated() { return e.isTerminated(); }
+        public boolean awaitTermination(long timeout, TimeUnit unit)
+            throws InterruptedException {
+            return e.awaitTermination(timeout, unit);
+        }
+        public Future<?> submit(Runnable task) {
+            return e.submit(task);
+        }
+        public <T> Future<T> submit(Callable<T> task) {
+            return e.submit(task);
+        }
+        public <T> Future<T> submit(Runnable task, T result) {
+            return e.submit(task, result);
+        }
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException {
+            return e.invokeAll(tasks);
+        }
+        public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
+                                             long timeout, TimeUnit unit)
+            throws InterruptedException {
+            return e.invokeAll(tasks, timeout, unit);
+        }
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
+            throws InterruptedException, ExecutionException {
+            return e.invokeAny(tasks);
+        }
+        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
+                               long timeout, TimeUnit unit)
+            throws InterruptedException, ExecutionException, TimeoutException {
+            return e.invokeAny(tasks, timeout, unit);
+        }
+    }
+
+    private static class FinalizableDelegatedExecutorService
+            extends DelegatedExecutorService {
+        FinalizableDelegatedExecutorService(ExecutorService executor) {
+            super(executor);
+        }
+        protected void finalize() {
+            super.shutdown();
+        }
+    }
+
+    /**
+     * A wrapper class that exposes only the ScheduledExecutorService
+     * methods of a ScheduledExecutorService implementation.
+     */
+    private static class DelegatedScheduledExecutorService
+            extends DelegatedExecutorService
+            implements ScheduledExecutorService {
+        private final ScheduledExecutorService e;
+        DelegatedScheduledExecutorService(ScheduledExecutorService executor) {
+            super(executor);
+            e = executor;
+        }
+        public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+            return e.schedule(command, delay, unit);
+        }
+        public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+            return e.schedule(callable, delay, unit);
+        }
+        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+            return e.scheduleAtFixedRate(command, initialDelay, period, unit);
+        }
+        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+            return e.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+        }
+    }
+
+    /** Cannot instantiate. */
+    private Executors() {}
+}
diff --git a/java/util/concurrent/Flow.java b/java/util/concurrent/Flow.java
new file mode 100644
index 0000000..0231790
--- /dev/null
+++ b/java/util/concurrent/Flow.java
@@ -0,0 +1,319 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// Android-changed: Remove reference to SubmissionPublisher class (not present on Android).
+/**
+ * Interrelated interfaces and static methods for establishing
+ * flow-controlled components in which {@link Publisher Publishers}
+ * produce items consumed by one or more {@link Subscriber
+ * Subscribers}, each managed by a {@link Subscription
+ * Subscription}.
+ *
+ * <p>These interfaces correspond to the <a
+ * href="http://www.reactive-streams.org/"> reactive-streams</a>
+ * specification.  They apply in both concurrent and distributed
+ * asynchronous settings: All (seven) methods are defined in {@code
+ * void} "one-way" message style. Communication relies on a simple form
+ * of flow control (method {@link Subscription#request}) that can be
+ * used to avoid resource management problems that may otherwise occur
+ * in "push" based systems.
+ *
+ * <p><b>Examples.</b> A {@link Publisher} usually defines its own
+ * {@link Subscription} implementation; constructing one in method
+ * {@code subscribe} and issuing it to the calling {@link
+ * Subscriber}. It publishes items to the subscriber asynchronously,
+ * normally using an {@link Executor}.  For example, here is a very
+ * simple publisher that only issues (when requested) a single {@code
+ * TRUE} item to a single subscriber.  Because the subscriber receives
+ * only a single item, this class does not use buffering and ordering
+ * control required in most implementations.
+ *
+ * <pre> {@code
+ * class OneShotPublisher implements Publisher<Boolean> {
+ *   private final ExecutorService executor = ForkJoinPool.commonPool(); // daemon-based
+ *   private boolean subscribed; // true after first subscribe
+ *   public synchronized void subscribe(Subscriber<? super Boolean> subscriber) {
+ *     if (subscribed)
+ *       subscriber.onError(new IllegalStateException()); // only one allowed
+ *     else {
+ *       subscribed = true;
+ *       subscriber.onSubscribe(new OneShotSubscription(subscriber, executor));
+ *     }
+ *   }
+ *   static class OneShotSubscription implements Subscription {
+ *     private final Subscriber<? super Boolean> subscriber;
+ *     private final ExecutorService executor;
+ *     private Future<?> future; // to allow cancellation
+ *     private boolean completed;
+ *     OneShotSubscription(Subscriber<? super Boolean> subscriber,
+ *                         ExecutorService executor) {
+ *       this.subscriber = subscriber;
+ *       this.executor = executor;
+ *     }
+ *     public synchronized void request(long n) {
+ *       if (n != 0 && !completed) {
+ *         completed = true;
+ *         if (n < 0) {
+ *           IllegalArgumentException ex = new IllegalArgumentException();
+ *           executor.execute(() -> subscriber.onError(ex));
+ *         } else {
+ *           future = executor.submit(() -> {
+ *             subscriber.onNext(Boolean.TRUE);
+ *             subscriber.onComplete();
+ *           });
+ *         }
+ *       }
+ *     }
+ *     public synchronized void cancel() {
+ *       completed = true;
+ *       if (future != null) future.cancel(false);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>A {@link Subscriber} arranges that items be requested and
+ * processed.  Items (invocations of {@link Subscriber#onNext}) are
+ * not issued unless requested, but multiple items may be requested.
+ * Many Subscriber implementations can arrange this in the style of
+ * the following example, where a buffer size of 1 single-steps, and
+ * larger sizes usually allow for more efficient overlapped processing
+ * with less communication; for example with a value of 64, this keeps
+ * total outstanding requests between 32 and 64.
+ * Because Subscriber method invocations for a given {@link
+ * Subscription} are strictly ordered, there is no need for these
+ * methods to use locks or volatiles unless a Subscriber maintains
+ * multiple Subscriptions (in which case it is better to instead
+ * define multiple Subscribers, each with its own Subscription).
+ *
+ * <pre> {@code
+ * class SampleSubscriber<T> implements Subscriber<T> {
+ *   final Consumer<? super T> consumer;
+ *   Subscription subscription;
+ *   final long bufferSize;
+ *   long count;
+ *   SampleSubscriber(long bufferSize, Consumer<? super T> consumer) {
+ *     this.bufferSize = bufferSize;
+ *     this.consumer = consumer;
+ *   }
+ *   public void onSubscribe(Subscription subscription) {
+ *     long initialRequestSize = bufferSize;
+ *     count = bufferSize - bufferSize / 2; // re-request when half consumed
+ *     (this.subscription = subscription).request(initialRequestSize);
+ *   }
+ *   public void onNext(T item) {
+ *     if (--count <= 0)
+ *       subscription.request(count = bufferSize - bufferSize / 2);
+ *     consumer.accept(item);
+ *   }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ * }}</pre>
+ *
+ * <p>The default value of {@link #defaultBufferSize} may provide a
+ * useful starting point for choosing request sizes and capacities in
+ * Flow components based on expected rates, resources, and usages.
+ * Or, when flow control is never needed, a subscriber may initially
+ * request an effectively unbounded number of items, as in:
+ *
+ * <pre> {@code
+ * class UnboundedSubscriber<T> implements Subscriber<T> {
+ *   public void onSubscribe(Subscription subscription) {
+ *     subscription.request(Long.MAX_VALUE); // effectively unbounded
+ *   }
+ *   public void onNext(T item) { use(item); }
+ *   public void onError(Throwable ex) { ex.printStackTrace(); }
+ *   public void onComplete() {}
+ *   void use(T item) { ... }
+ * }}</pre>
+ *
+ * @author Doug Lea
+ * @since 9
+ */
+public final class Flow {
+
+    private Flow() {} // uninstantiable
+
+    /**
+     * A producer of items (and related control messages) received by
+     * Subscribers.  Each current {@link Subscriber} receives the same
+     * items (via method {@code onNext}) in the same order, unless
+     * drops or errors are encountered. If a Publisher encounters an
+     * error that does not allow items to be issued to a Subscriber,
+     * that Subscriber receives {@code onError}, and then receives no
+     * further messages.  Otherwise, when it is known that no further
+     * messages will be issued to it, a subscriber receives {@code
+     * onComplete}.  Publishers ensure that Subscriber method
+     * invocations for each subscription are strictly ordered in <a
+     * href="package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * order.
+     *
+     * <p>Publishers may vary in policy about whether drops (failures
+     * to issue an item because of resource limitations) are treated
+     * as unrecoverable errors.  Publishers may also vary about
+     * whether Subscribers receive items that were produced or
+     * available before they subscribed.
+     *
+     * @param <T> the published item type
+     */
+    @FunctionalInterface
+    public static interface Publisher<T> {
+        /**
+         * Adds the given Subscriber if possible.  If already
+         * subscribed, or the attempt to subscribe fails due to policy
+         * violations or errors, the Subscriber's {@code onError}
+         * method is invoked with an {@link IllegalStateException}.
+         * Otherwise, the Subscriber's {@code onSubscribe} method is
+         * invoked with a new {@link Subscription}.  Subscribers may
+         * enable receiving items by invoking the {@code request}
+         * method of this Subscription, and may unsubscribe by
+         * invoking its {@code cancel} method.
+         *
+         * @param subscriber the subscriber
+         * @throws NullPointerException if subscriber is null
+         */
+        public void subscribe(Subscriber<? super T> subscriber);
+    }
+
+    /**
+     * A receiver of messages.  The methods in this interface are
+     * invoked in strict sequential order for each {@link
+     * Subscription}.
+     *
+     * @param <T> the subscribed item type
+     */
+    public static interface Subscriber<T> {
+        /**
+         * Method invoked prior to invoking any other Subscriber
+         * methods for the given Subscription. If this method throws
+         * an exception, resulting behavior is not guaranteed, but may
+         * cause the Subscription not to be established or to be cancelled.
+         *
+         * <p>Typically, implementations of this method invoke {@code
+         * subscription.request} to enable receiving items.
+         *
+         * @param subscription a new subscription
+         */
+        public void onSubscribe(Subscription subscription);
+
+        /**
+         * Method invoked with a Subscription's next item.  If this
+         * method throws an exception, resulting behavior is not
+         * guaranteed, but may cause the Subscription to be cancelled.
+         *
+         * @param item the item
+         */
+        public void onNext(T item);
+
+        /**
+         * Method invoked upon an unrecoverable error encountered by a
+         * Publisher or Subscription, after which no other Subscriber
+         * methods are invoked by the Subscription.  If this method
+         * itself throws an exception, resulting behavior is
+         * undefined.
+         *
+         * @param throwable the exception
+         */
+        public void onError(Throwable throwable);
+
+        /**
+         * Method invoked when it is known that no additional
+         * Subscriber method invocations will occur for a Subscription
+         * that is not already terminated by error, after which no
+         * other Subscriber methods are invoked by the Subscription.
+         * If this method throws an exception, resulting behavior is
+         * undefined.
+         */
+        public void onComplete();
+    }
+
+    /**
+     * Message control linking a {@link Publisher} and {@link
+     * Subscriber}.  Subscribers receive items only when requested,
+     * and may cancel at any time. The methods in this interface are
+     * intended to be invoked only by their Subscribers; usages in
+     * other contexts have undefined effects.
+     */
+    public static interface Subscription {
+        /**
+         * Adds the given number {@code n} of items to the current
+         * unfulfilled demand for this subscription.  If {@code n} is
+         * less than or equal to zero, the Subscriber will receive an
+         * {@code onError} signal with an {@link
+         * IllegalArgumentException} argument.  Otherwise, the
+         * Subscriber will receive up to {@code n} additional {@code
+         * onNext} invocations (or fewer if terminated).
+         *
+         * @param n the increment of demand; a value of {@code
+         * Long.MAX_VALUE} may be considered as effectively unbounded
+         */
+        public void request(long n);
+
+        /**
+         * Causes the Subscriber to (eventually) stop receiving
+         * messages.  Implementation is best-effort -- additional
+         * messages may be received after invoking this method.
+         * A cancelled subscription need not ever receive an
+         * {@code onComplete} or {@code onError} signal.
+         */
+        public void cancel();
+    }
+
+    /**
+     * A component that acts as both a Subscriber and Publisher.
+     *
+     * @param <T> the subscribed item type
+     * @param <R> the published item type
+     */
+    public static interface Processor<T,R> extends Subscriber<T>, Publisher<R> {
+    }
+
+    static final int DEFAULT_BUFFER_SIZE = 256;
+
+    /**
+     * Returns a default value for Publisher or Subscriber buffering,
+     * that may be used in the absence of other constraints.
+     *
+     * @implNote
+     * The current value returned is 256.
+     *
+     * @return the buffer size value
+     */
+    public static int defaultBufferSize() {
+        return DEFAULT_BUFFER_SIZE;
+    }
+
+}
diff --git a/java/util/concurrent/ForkJoinPool.java b/java/util/concurrent/ForkJoinPool.java
new file mode 100644
index 0000000..04ad7d7
--- /dev/null
+++ b/java/util/concurrent/ForkJoinPool.java
@@ -0,0 +1,3582 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.lang.Thread.UncaughtExceptionHandler;
+import java.security.AccessControlContext;
+import java.security.Permissions;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * An {@link ExecutorService} for running {@link ForkJoinTask}s.
+ * A {@code ForkJoinPool} provides the entry point for submissions
+ * from non-{@code ForkJoinTask} clients, as well as management and
+ * monitoring operations.
+ *
+ * <p>A {@code ForkJoinPool} differs from other kinds of {@link
+ * ExecutorService} mainly by virtue of employing
+ * <em>work-stealing</em>: all threads in the pool attempt to find and
+ * execute tasks submitted to the pool and/or created by other active
+ * tasks (eventually blocking waiting for work if none exist). This
+ * enables efficient processing when most tasks spawn other subtasks
+ * (as do most {@code ForkJoinTask}s), as well as when many small
+ * tasks are submitted to the pool from external clients.  Especially
+ * when setting <em>asyncMode</em> to true in constructors, {@code
+ * ForkJoinPool}s may also be appropriate for use with event-style
+ * tasks that are never joined.
+ *
+ * <p>A static {@link #commonPool()} is available and appropriate for
+ * most applications. The common pool is used by any ForkJoinTask that
+ * is not explicitly submitted to a specified pool. Using the common
+ * pool normally reduces resource usage (its threads are slowly
+ * reclaimed during periods of non-use, and reinstated upon subsequent
+ * use).
+ *
+ * <p>For applications that require separate or custom pools, a {@code
+ * ForkJoinPool} may be constructed with a given target parallelism
+ * level; by default, equal to the number of available processors.
+ * The pool attempts to maintain enough active (or available) threads
+ * by dynamically adding, suspending, or resuming internal worker
+ * threads, even if some tasks are stalled waiting to join others.
+ * However, no such adjustments are guaranteed in the face of blocked
+ * I/O or other unmanaged synchronization. The nested {@link
+ * ManagedBlocker} interface enables extension of the kinds of
+ * synchronization accommodated.
+ *
+ * <p>In addition to execution and lifecycle control methods, this
+ * class provides status check methods (for example
+ * {@link #getStealCount}) that are intended to aid in developing,
+ * tuning, and monitoring fork/join applications. Also, method
+ * {@link #toString} returns indications of pool state in a
+ * convenient form for informal monitoring.
+ *
+ * <p>As is the case with other ExecutorServices, there are three
+ * main task execution methods summarized in the following table.
+ * These are designed to be used primarily by clients not already
+ * engaged in fork/join computations in the current pool.  The main
+ * forms of these methods accept instances of {@code ForkJoinTask},
+ * but overloaded forms also allow mixed execution of plain {@code
+ * Runnable}- or {@code Callable}- based activities as well.  However,
+ * tasks that are already executing in a pool should normally instead
+ * use the within-computation forms listed in the table unless using
+ * async event-style tasks that are not usually joined, in which case
+ * there is little difference among choice of methods.
+ *
+ * <table BORDER CELLPADDING=3 CELLSPACING=1>
+ * <caption>Summary of task execution methods</caption>
+ *  <tr>
+ *    <td></td>
+ *    <td ALIGN=CENTER> <b>Call from non-fork/join clients</b></td>
+ *    <td ALIGN=CENTER> <b>Call from within fork/join computations</b></td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Arrange async execution</b></td>
+ *    <td> {@link #execute(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork}</td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Await and obtain result</b></td>
+ *    <td> {@link #invoke(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#invoke}</td>
+ *  </tr>
+ *  <tr>
+ *    <td> <b>Arrange exec and obtain Future</b></td>
+ *    <td> {@link #submit(ForkJoinTask)}</td>
+ *    <td> {@link ForkJoinTask#fork} (ForkJoinTasks <em>are</em> Futures)</td>
+ *  </tr>
+ * </table>
+ *
+ * <p>The common pool is by default constructed with default
+ * parameters, but these may be controlled by setting three
+ * {@linkplain System#getProperty system properties}:
+ * <ul>
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.parallelism}
+ * - the parallelism level, a non-negative integer
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.threadFactory}
+ * - the class name of a {@link ForkJoinWorkerThreadFactory}
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.exceptionHandler}
+ * - the class name of a {@link UncaughtExceptionHandler}
+ * <li>{@code java.util.concurrent.ForkJoinPool.common.maximumSpares}
+ * - the maximum number of allowed extra threads to maintain target
+ * parallelism (default 256).
+ * </ul>
+ * If a {@link SecurityManager} is present and no factory is
+ * specified, then the default pool uses a factory supplying
+ * threads that have no {@link Permissions} enabled.
+ * The system class loader is used to load these classes.
+ * Upon any error in establishing these settings, default parameters
+ * are used. It is possible to disable or limit the use of threads in
+ * the common pool by setting the parallelism property to zero, and/or
+ * using a factory that may return {@code null}. However doing so may
+ * cause unjoined tasks to never be executed.
+ *
+ * <p><b>Implementation notes</b>: This implementation restricts the
+ * maximum number of running threads to 32767. Attempts to create
+ * pools with greater than the maximum number result in
+ * {@code IllegalArgumentException}.
+ *
+ * <p>This implementation rejects submitted tasks (that is, by throwing
+ * {@link RejectedExecutionException}) only when the pool is shut down
+ * or internal resources have been exhausted.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+// Android-removed: @Contended, this hint is not used by the Android runtime.
+//@jdk.internal.vm.annotation.Contended
+public class ForkJoinPool extends AbstractExecutorService {
+
+    /*
+     * Implementation Overview
+     *
+     * This class and its nested classes provide the main
+     * functionality and control for a set of worker threads:
+     * Submissions from non-FJ threads enter into submission queues.
+     * Workers take these tasks and typically split them into subtasks
+     * that may be stolen by other workers.  Preference rules give
+     * first priority to processing tasks from their own queues (LIFO
+     * or FIFO, depending on mode), then to randomized FIFO steals of
+     * tasks in other queues.  This framework began as vehicle for
+     * supporting tree-structured parallelism using work-stealing.
+     * Over time, its scalability advantages led to extensions and
+     * changes to better support more diverse usage contexts.  Because
+     * most internal methods and nested classes are interrelated,
+     * their main rationale and descriptions are presented here;
+     * individual methods and nested classes contain only brief
+     * comments about details.
+     *
+     * WorkQueues
+     * ==========
+     *
+     * Most operations occur within work-stealing queues (in nested
+     * class WorkQueue).  These are special forms of Deques that
+     * support only three of the four possible end-operations -- push,
+     * pop, and poll (aka steal), under the further constraints that
+     * push and pop are called only from the owning thread (or, as
+     * extended here, under a lock), while poll may be called from
+     * other threads.  (If you are unfamiliar with them, you probably
+     * want to read Herlihy and Shavit's book "The Art of
+     * Multiprocessor programming", chapter 16 describing these in
+     * more detail before proceeding.)  The main work-stealing queue
+     * design is roughly similar to those in the papers "Dynamic
+     * Circular Work-Stealing Deque" by Chase and Lev, SPAA 2005
+     * (http://research.sun.com/scalable/pubs/index.html) and
+     * "Idempotent work stealing" by Michael, Saraswat, and Vechev,
+     * PPoPP 2009 (http://portal.acm.org/citation.cfm?id=1504186).
+     * The main differences ultimately stem from GC requirements that
+     * we null out taken slots as soon as we can, to maintain as small
+     * a footprint as possible even in programs generating huge
+     * numbers of tasks. To accomplish this, we shift the CAS
+     * arbitrating pop vs poll (steal) from being on the indices
+     * ("base" and "top") to the slots themselves.
+     *
+     * Adding tasks then takes the form of a classic array push(task)
+     * in a circular buffer:
+     *    q.array[q.top++ % length] = task;
+     *
+     * (The actual code needs to null-check and size-check the array,
+     * uses masking, not mod, for indexing a power-of-two-sized array,
+     * properly fences accesses, and possibly signals waiting workers
+     * to start scanning -- see below.)  Both a successful pop and
+     * poll mainly entail a CAS of a slot from non-null to null.
+     *
+     * The pop operation (always performed by owner) is:
+     *   if ((the task at top slot is not null) and
+     *        (CAS slot to null))
+     *           decrement top and return task;
+     *
+     * And the poll operation (usually by a stealer) is
+     *    if ((the task at base slot is not null) and
+     *        (CAS slot to null))
+     *           increment base and return task;
+     *
+     * There are several variants of each of these; for example most
+     * versions of poll pre-screen the CAS by rechecking that the base
+     * has not changed since reading the slot, and most methods only
+     * attempt the CAS if base appears not to be equal to top.
+     *
+     * Memory ordering.  See "Correct and Efficient Work-Stealing for
+     * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
+     * (http://www.di.ens.fr/~zappa/readings/ppopp13.pdf) for an
+     * analysis of memory ordering requirements in work-stealing
+     * algorithms similar to (but different than) the one used here.
+     * Extracting tasks in array slots via (fully fenced) CAS provides
+     * primary synchronization. The base and top indices imprecisely
+     * guide where to extract from. We do not always require strict
+     * orderings of array and index updates, so sometimes let them be
+     * subject to compiler and processor reorderings. However, the
+     * volatile "base" index also serves as a basis for memory
+     * ordering: Slot accesses are preceded by a read of base,
+     * ensuring happens-before ordering with respect to stealers (so
+     * the slots themselves can be read via plain array reads.)  The
+     * only other memory orderings relied on are maintained in the
+     * course of signalling and activation (see below).  A check that
+     * base == top indicates (momentary) emptiness, but otherwise may
+     * err on the side of possibly making the queue appear nonempty
+     * when a push, pop, or poll have not fully committed, or making
+     * it appear empty when an update of top has not yet been visibly
+     * written.  (Method isEmpty() checks the case of a partially
+     * completed removal of the last element.)  Because of this, the
+     * poll operation, considered individually, is not wait-free. One
+     * thief cannot successfully continue until another in-progress
+     * one (or, if previously empty, a push) visibly completes.
+     * However, in the aggregate, we ensure at least probabilistic
+     * non-blockingness.  If an attempted steal fails, a scanning
+     * thief chooses a different random victim target to try next. So,
+     * in order for one thief to progress, it suffices for any
+     * in-progress poll or new push on any empty queue to
+     * complete. (This is why we normally use method pollAt and its
+     * variants that try once at the apparent base index, else
+     * consider alternative actions, rather than method poll, which
+     * retries.)
+     *
+     * This approach also enables support of a user mode in which
+     * local task processing is in FIFO, not LIFO order, simply by
+     * using poll rather than pop.  This can be useful in
+     * message-passing frameworks in which tasks are never joined.
+     *
+     * WorkQueues are also used in a similar way for tasks submitted
+     * to the pool. We cannot mix these tasks in the same queues used
+     * by workers. Instead, we randomly associate submission queues
+     * with submitting threads, using a form of hashing.  The
+     * ThreadLocalRandom probe value serves as a hash code for
+     * choosing existing queues, and may be randomly repositioned upon
+     * contention with other submitters.  In essence, submitters act
+     * like workers except that they are restricted to executing local
+     * tasks that they submitted (or in the case of CountedCompleters,
+     * others with the same root task).  Insertion of tasks in shared
+     * mode requires a lock but we use only a simple spinlock (using
+     * field qlock), because submitters encountering a busy queue move
+     * on to try or create other queues -- they block only when
+     * creating and registering new queues. Because it is used only as
+     * a spinlock, unlocking requires only a "releasing" store (using
+     * putOrderedInt).  The qlock is also used during termination
+     * detection, in which case it is forced to a negative
+     * non-lockable value.
+     *
+     * Management
+     * ==========
+     *
+     * The main throughput advantages of work-stealing stem from
+     * decentralized control -- workers mostly take tasks from
+     * themselves or each other, at rates that can exceed a billion
+     * per second.  The pool itself creates, activates (enables
+     * scanning for and running tasks), deactivates, blocks, and
+     * terminates threads, all with minimal central information.
+     * There are only a few properties that we can globally track or
+     * maintain, so we pack them into a small number of variables,
+     * often maintaining atomicity without blocking or locking.
+     * Nearly all essentially atomic control state is held in two
+     * volatile variables that are by far most often read (not
+     * written) as status and consistency checks. (Also, field
+     * "config" holds unchanging configuration state.)
+     *
+     * Field "ctl" contains 64 bits holding information needed to
+     * atomically decide to add, inactivate, enqueue (on an event
+     * queue), dequeue, and/or re-activate workers.  To enable this
+     * packing, we restrict maximum parallelism to (1<<15)-1 (which is
+     * far in excess of normal operating range) to allow ids, counts,
+     * and their negations (used for thresholding) to fit into 16bit
+     * subfields.
+     *
+     * Field "runState" holds lifetime status, atomically and
+     * monotonically setting STARTED, SHUTDOWN, STOP, and finally
+     * TERMINATED bits.
+     *
+     * Field "auxState" is a ReentrantLock subclass that also
+     * opportunistically holds some other bookkeeping fields accessed
+     * only when locked.  It is mainly used to lock (infrequent)
+     * updates to workQueues.  The auxState instance is itself lazily
+     * constructed (see tryInitialize), requiring a double-check-style
+     * bootstrapping use of field runState, and locking a private
+     * static.
+     *
+     * Field "workQueues" holds references to WorkQueues.  It is
+     * updated (only during worker creation and termination) under the
+     * lock, but is otherwise concurrently readable, and accessed
+     * directly. We also ensure that reads of the array reference
+     * itself never become too stale (for example, re-reading before
+     * each scan). To simplify index-based operations, the array size
+     * is always a power of two, and all readers must tolerate null
+     * slots. Worker queues are at odd indices. Shared (submission)
+     * queues are at even indices, up to a maximum of 64 slots, to
+     * limit growth even if array needs to expand to add more
+     * workers. Grouping them together in this way simplifies and
+     * speeds up task scanning.
+     *
+     * All worker thread creation is on-demand, triggered by task
+     * submissions, replacement of terminated workers, and/or
+     * compensation for blocked workers. However, all other support
+     * code is set up to work with other policies.  To ensure that we
+     * do not hold on to worker references that would prevent GC, all
+     * accesses to workQueues are via indices into the workQueues
+     * array (which is one source of some of the messy code
+     * constructions here). In essence, the workQueues array serves as
+     * a weak reference mechanism. Thus for example the stack top
+     * subfield of ctl stores indices, not references.
+     *
+     * Queuing Idle Workers. Unlike HPC work-stealing frameworks, we
+     * cannot let workers spin indefinitely scanning for tasks when
+     * none can be found immediately, and we cannot start/resume
+     * workers unless there appear to be tasks available.  On the
+     * other hand, we must quickly prod them into action when new
+     * tasks are submitted or generated. In many usages, ramp-up time
+     * to activate workers is the main limiting factor in overall
+     * performance, which is compounded at program start-up by JIT
+     * compilation and allocation. So we streamline this as much as
+     * possible.
+     *
+     * The "ctl" field atomically maintains active and total worker
+     * counts as well as a queue to place waiting threads so they can
+     * be located for signalling. Active counts also play the role of
+     * quiescence indicators, so are decremented when workers believe
+     * that there are no more tasks to execute. The "queue" is
+     * actually a form of Treiber stack.  A stack is ideal for
+     * activating threads in most-recently used order. This improves
+     * performance and locality, outweighing the disadvantages of
+     * being prone to contention and inability to release a worker
+     * unless it is topmost on stack.  We block/unblock workers after
+     * pushing on the idle worker stack (represented by the lower
+     * 32bit subfield of ctl) when they cannot find work.  The top
+     * stack state holds the value of the "scanState" field of the
+     * worker: its index and status, plus a version counter that, in
+     * addition to the count subfields (also serving as version
+     * stamps) provide protection against Treiber stack ABA effects.
+     *
+     * Creating workers. To create a worker, we pre-increment total
+     * count (serving as a reservation), and attempt to construct a
+     * ForkJoinWorkerThread via its factory. Upon construction, the
+     * new thread invokes registerWorker, where it constructs a
+     * WorkQueue and is assigned an index in the workQueues array
+     * (expanding the array if necessary). The thread is then started.
+     * Upon any exception across these steps, or null return from
+     * factory, deregisterWorker adjusts counts and records
+     * accordingly.  If a null return, the pool continues running with
+     * fewer than the target number workers. If exceptional, the
+     * exception is propagated, generally to some external caller.
+     * Worker index assignment avoids the bias in scanning that would
+     * occur if entries were sequentially packed starting at the front
+     * of the workQueues array. We treat the array as a simple
+     * power-of-two hash table, expanding as needed. The seedIndex
+     * increment ensures no collisions until a resize is needed or a
+     * worker is deregistered and replaced, and thereafter keeps
+     * probability of collision low. We cannot use
+     * ThreadLocalRandom.getProbe() for similar purposes here because
+     * the thread has not started yet, but do so for creating
+     * submission queues for existing external threads (see
+     * externalPush).
+     *
+     * WorkQueue field scanState is used by both workers and the pool
+     * to manage and track whether a worker is UNSIGNALLED (possibly
+     * blocked waiting for a signal).  When a worker is inactivated,
+     * its scanState field is set, and is prevented from executing
+     * tasks, even though it must scan once for them to avoid queuing
+     * races. Note that scanState updates lag queue CAS releases so
+     * usage requires care. When queued, the lower 16 bits of
+     * scanState must hold its pool index. So we place the index there
+     * upon initialization (see registerWorker) and otherwise keep it
+     * there or restore it when necessary.
+     *
+     * The ctl field also serves as the basis for memory
+     * synchronization surrounding activation. This uses a more
+     * efficient version of a Dekker-like rule that task producers and
+     * consumers sync with each other by both writing/CASing ctl (even
+     * if to its current value).  This would be extremely costly. So
+     * we relax it in several ways: (1) Producers only signal when
+     * their queue is empty. Other workers propagate this signal (in
+     * method scan) when they find tasks. (2) Workers only enqueue
+     * after scanning (see below) and not finding any tasks.  (3)
+     * Rather than CASing ctl to its current value in the common case
+     * where no action is required, we reduce write contention by
+     * equivalently prefacing signalWork when called by an external
+     * task producer using a memory access with full-volatile
+     * semantics or a "fullFence". (4) For internal task producers we
+     * rely on the fact that even if no other workers awaken, the
+     * producer itself will eventually see the task and execute it.
+     *
+     * Almost always, too many signals are issued. A task producer
+     * cannot in general tell if some existing worker is in the midst
+     * of finishing one task (or already scanning) and ready to take
+     * another without being signalled. So the producer might instead
+     * activate a different worker that does not find any work, and
+     * then inactivates. This scarcely matters in steady-state
+     * computations involving all workers, but can create contention
+     * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
+     * computations involving only a few workers.
+     *
+     * Scanning. Method scan() performs top-level scanning for tasks.
+     * Each scan traverses (and tries to poll from) each queue in
+     * pseudorandom permutation order by randomly selecting an origin
+     * index and a step value.  (The pseudorandom generator need not
+     * have high-quality statistical properties in the long term, but
+     * just within computations; We use 64bit and 32bit Marsaglia
+     * XorShifts, which are cheap and suffice here.)  Scanning also
+     * employs contention reduction: When scanning workers fail a CAS
+     * polling for work, they soon restart with a different
+     * pseudorandom scan order (thus likely retrying at different
+     * intervals). This improves throughput when many threads are
+     * trying to take tasks from few queues.  Scans do not otherwise
+     * explicitly take into account core affinities, loads, cache
+     * localities, etc, However, they do exploit temporal locality
+     * (which usually approximates these) by preferring to re-poll (up
+     * to POLL_LIMIT times) from the same queue after a successful
+     * poll before trying others.  Restricted forms of scanning occur
+     * in methods helpComplete and findNonEmptyStealQueue, and take
+     * similar but simpler forms.
+     *
+     * Deactivation and waiting. Queuing encounters several intrinsic
+     * races; most notably that an inactivating scanning worker can
+     * miss seeing a task produced during a scan.  So when a worker
+     * cannot find a task to steal, it inactivates and enqueues, and
+     * then rescans to ensure that it didn't miss one, reactivating
+     * upon seeing one with probability approximately proportional to
+     * probability of a miss.  (In most cases, the worker will be
+     * signalled before self-signalling, avoiding cascades of multiple
+     * signals for the same task).
+     *
+     * Workers block (in method awaitWork) using park/unpark;
+     * advertising the need for signallers to unpark by setting their
+     * "parker" fields.
+     *
+     * Trimming workers. To release resources after periods of lack of
+     * use, a worker starting to wait when the pool is quiescent will
+     * time out and terminate (see awaitWork) if the pool has remained
+     * quiescent for period given by IDLE_TIMEOUT_MS, increasing the
+     * period as the number of threads decreases, eventually removing
+     * all workers.
+     *
+     * Shutdown and Termination. A call to shutdownNow invokes
+     * tryTerminate to atomically set a runState bit. The calling
+     * thread, as well as every other worker thereafter terminating,
+     * helps terminate others by setting their (qlock) status,
+     * cancelling their unprocessed tasks, and waking them up, doing
+     * so repeatedly until stable. Calls to non-abrupt shutdown()
+     * preface this by checking whether termination should commence.
+     * This relies primarily on the active count bits of "ctl"
+     * maintaining consensus -- tryTerminate is called from awaitWork
+     * whenever quiescent. However, external submitters do not take
+     * part in this consensus.  So, tryTerminate sweeps through queues
+     * (until stable) to ensure lack of in-flight submissions and
+     * workers about to process them before triggering the "STOP"
+     * phase of termination. (Note: there is an intrinsic conflict if
+     * helpQuiescePool is called when shutdown is enabled. Both wait
+     * for quiescence, but tryTerminate is biased to not trigger until
+     * helpQuiescePool completes.)
+     *
+     * Joining Tasks
+     * =============
+     *
+     * Any of several actions may be taken when one worker is waiting
+     * to join a task stolen (or always held) by another.  Because we
+     * are multiplexing many tasks on to a pool of workers, we can't
+     * just let them block (as in Thread.join).  We also cannot just
+     * reassign the joiner's run-time stack with another and replace
+     * it later, which would be a form of "continuation", that even if
+     * possible is not necessarily a good idea since we may need both
+     * an unblocked task and its continuation to progress.  Instead we
+     * combine two tactics:
+     *
+     *   Helping: Arranging for the joiner to execute some task that it
+     *      would be running if the steal had not occurred.
+     *
+     *   Compensating: Unless there are already enough live threads,
+     *      method tryCompensate() may create or re-activate a spare
+     *      thread to compensate for blocked joiners until they unblock.
+     *
+     * A third form (implemented in tryRemoveAndExec) amounts to
+     * helping a hypothetical compensator: If we can readily tell that
+     * a possible action of a compensator is to steal and execute the
+     * task being joined, the joining thread can do so directly,
+     * without the need for a compensation thread (although at the
+     * expense of larger run-time stacks, but the tradeoff is
+     * typically worthwhile).
+     *
+     * The ManagedBlocker extension API can't use helping so relies
+     * only on compensation in method awaitBlocker.
+     *
+     * The algorithm in helpStealer entails a form of "linear
+     * helping".  Each worker records (in field currentSteal) the most
+     * recent task it stole from some other worker (or a submission).
+     * It also records (in field currentJoin) the task it is currently
+     * actively joining. Method helpStealer uses these markers to try
+     * to find a worker to help (i.e., steal back a task from and
+     * execute it) that could hasten completion of the actively joined
+     * task.  Thus, the joiner executes a task that would be on its
+     * own local deque had the to-be-joined task not been stolen. This
+     * is a conservative variant of the approach described in Wagner &
+     * Calder "Leapfrogging: a portable technique for implementing
+     * efficient futures" SIGPLAN Notices, 1993
+     * (http://portal.acm.org/citation.cfm?id=155354). It differs in
+     * that: (1) We only maintain dependency links across workers upon
+     * steals, rather than use per-task bookkeeping.  This sometimes
+     * requires a linear scan of workQueues array to locate stealers,
+     * but often doesn't because stealers leave hints (that may become
+     * stale/wrong) of where to locate them.  It is only a hint
+     * because a worker might have had multiple steals and the hint
+     * records only one of them (usually the most current).  Hinting
+     * isolates cost to when it is needed, rather than adding to
+     * per-task overhead.  (2) It is "shallow", ignoring nesting and
+     * potentially cyclic mutual steals.  (3) It is intentionally
+     * racy: field currentJoin is updated only while actively joining,
+     * which means that we miss links in the chain during long-lived
+     * tasks, GC stalls etc (which is OK since blocking in such cases
+     * is usually a good idea).  (4) We bound the number of attempts
+     * to find work using checksums and fall back to suspending the
+     * worker and if necessary replacing it with another.
+     *
+     * Helping actions for CountedCompleters do not require tracking
+     * currentJoins: Method helpComplete takes and executes any task
+     * with the same root as the task being waited on (preferring
+     * local pops to non-local polls). However, this still entails
+     * some traversal of completer chains, so is less efficient than
+     * using CountedCompleters without explicit joins.
+     *
+     * Compensation does not aim to keep exactly the target
+     * parallelism number of unblocked threads running at any given
+     * time. Some previous versions of this class employed immediate
+     * compensations for any blocked join. However, in practice, the
+     * vast majority of blockages are transient byproducts of GC and
+     * other JVM or OS activities that are made worse by replacement.
+     * Currently, compensation is attempted only after validating that
+     * all purportedly active threads are processing tasks by checking
+     * field WorkQueue.scanState, which eliminates most false
+     * positives.  Also, compensation is bypassed (tolerating fewer
+     * threads) in the most common case in which it is rarely
+     * beneficial: when a worker with an empty queue (thus no
+     * continuation tasks) blocks on a join and there still remain
+     * enough threads to ensure liveness.
+     *
+     * Spare threads are removed as soon as they notice that the
+     * target parallelism level has been exceeded, in method
+     * tryDropSpare. (Method scan arranges returns for rechecks upon
+     * each probe via the "bound" parameter.)
+     *
+     * The compensation mechanism may be bounded.  Bounds for the
+     * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
+     * with programming errors and abuse before running out of
+     * resources to do so. In other cases, users may supply factories
+     * that limit thread construction. The effects of bounding in this
+     * pool (like all others) is imprecise.  Total worker counts are
+     * decremented when threads deregister, not when they exit and
+     * resources are reclaimed by the JVM and OS. So the number of
+     * simultaneously live threads may transiently exceed bounds.
+     *
+     * Common Pool
+     * ===========
+     *
+     * The static common pool always exists after static
+     * initialization.  Since it (or any other created pool) need
+     * never be used, we minimize initial construction overhead and
+     * footprint to the setup of about a dozen fields, with no nested
+     * allocation. Most bootstrapping occurs within method
+     * externalSubmit during the first submission to the pool.
+     *
+     * When external threads submit to the common pool, they can
+     * perform subtask processing (see externalHelpComplete and
+     * related methods) upon joins.  This caller-helps policy makes it
+     * sensible to set common pool parallelism level to one (or more)
+     * less than the total number of available cores, or even zero for
+     * pure caller-runs.  We do not need to record whether external
+     * submissions are to the common pool -- if not, external help
+     * methods return quickly. These submitters would otherwise be
+     * blocked waiting for completion, so the extra effort (with
+     * liberally sprinkled task status checks) in inapplicable cases
+     * amounts to an odd form of limited spin-wait before blocking in
+     * ForkJoinTask.join.
+     *
+     * As a more appropriate default in managed environments, unless
+     * overridden by system properties, we use workers of subclass
+     * InnocuousForkJoinWorkerThread when there is a SecurityManager
+     * present. These workers have no permissions set, do not belong
+     * to any user-defined ThreadGroup, and erase all ThreadLocals
+     * after executing any top-level task (see WorkQueue.runTask).
+     * The associated mechanics (mainly in ForkJoinWorkerThread) may
+     * be JVM-dependent and must access particular Thread class fields
+     * to achieve this effect.
+     *
+     * Style notes
+     * ===========
+     *
+     * Memory ordering relies mainly on Unsafe intrinsics that carry
+     * the further responsibility of explicitly performing null- and
+     * bounds- checks otherwise carried out implicitly by JVMs.  This
+     * can be awkward and ugly, but also reflects the need to control
+     * outcomes across the unusual cases that arise in very racy code
+     * with very few invariants. So these explicit checks would exist
+     * in some form anyway.  All fields are read into locals before
+     * use, and null-checked if they are references.  This is usually
+     * done in a "C"-like style of listing declarations at the heads
+     * of methods or blocks, and using inline assignments on first
+     * encounter.  Array bounds-checks are usually performed by
+     * masking with array.length-1, which relies on the invariant that
+     * these arrays are created with positive lengths, which is itself
+     * paranoically checked. Nearly all explicit checks lead to
+     * bypass/return, not exception throws, because they may
+     * legitimately arise due to cancellation/revocation during
+     * shutdown.
+     *
+     * There is a lot of representation-level coupling among classes
+     * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
+     * fields of WorkQueue maintain data structures managed by
+     * ForkJoinPool, so are directly accessed.  There is little point
+     * trying to reduce this, since any associated future changes in
+     * representations will need to be accompanied by algorithmic
+     * changes anyway. Several methods intrinsically sprawl because
+     * they must accumulate sets of consistent reads of fields held in
+     * local variables.  There are also other coding oddities
+     * (including several unnecessary-looking hoisted null checks)
+     * that help some methods perform reasonably even when interpreted
+     * (not compiled).
+     *
+     * The order of declarations in this file is (with a few exceptions):
+     * (1) Static utility functions
+     * (2) Nested (static) classes
+     * (3) Static fields
+     * (4) Fields, along with constants used when unpacking some of them
+     * (5) Internal control methods
+     * (6) Callbacks and other support for ForkJoinTask methods
+     * (7) Exported methods
+     * (8) Static block initializing statics in minimally dependent order
+     */
+
+    // Static utilities
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to modify threads.
+     */
+    private static void checkPermission() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(modifyThreadPermission);
+    }
+
+    // Nested classes
+
+    /**
+     * Factory for creating new {@link ForkJoinWorkerThread}s.
+     * A {@code ForkJoinWorkerThreadFactory} must be defined and used
+     * for {@code ForkJoinWorkerThread} subclasses that extend base
+     * functionality or initialize threads with different contexts.
+     */
+    public static interface ForkJoinWorkerThreadFactory {
+        /**
+         * Returns a new worker thread operating in the given pool.
+         *
+         * @param pool the pool this thread works in
+         * @return the new worker thread, or {@code null} if the request
+         *         to create a thread is rejected
+         * @throws NullPointerException if the pool is null
+         */
+        public ForkJoinWorkerThread newThread(ForkJoinPool pool);
+    }
+
+    /**
+     * Default ForkJoinWorkerThreadFactory implementation; creates a
+     * new ForkJoinWorkerThread.
+     */
+    private static final class DefaultForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return new ForkJoinWorkerThread(pool);
+        }
+    }
+
+    /**
+     * Class for artificial tasks that are used to replace the target
+     * of local joins if they are removed from an interior queue slot
+     * in WorkQueue.tryRemoveAndExec. We don't need the proxy to
+     * actually do anything beyond having a unique identity.
+     */
+    private static final class EmptyTask extends ForkJoinTask<Void> {
+        private static final long serialVersionUID = -7721805057305804111L;
+        EmptyTask() { status = ForkJoinTask.NORMAL; } // force done
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void x) {}
+        public final boolean exec() { return true; }
+    }
+
+    /**
+     * Additional fields and lock created upon initialization.
+     */
+    private static final class AuxState extends ReentrantLock {
+        private static final long serialVersionUID = -6001602636862214147L;
+        volatile long stealCount;     // cumulative steal count
+        long indexSeed;               // index bits for registerWorker
+        AuxState() {}
+    }
+
+    // Constants shared across ForkJoinPool and WorkQueue
+
+    // Bounds
+    static final int SMASK        = 0xffff;        // short bits == max index
+    static final int MAX_CAP      = 0x7fff;        // max #workers - 1
+    static final int EVENMASK     = 0xfffe;        // even short bits
+    static final int SQMASK       = 0x007e;        // max 64 (even) slots
+
+    // Masks and units for WorkQueue.scanState and ctl sp subfield
+    static final int UNSIGNALLED  = 1 << 31;       // must be negative
+    static final int SS_SEQ       = 1 << 16;       // version count
+
+    // Mode bits for ForkJoinPool.config and WorkQueue.config
+    static final int MODE_MASK    = 0xffff << 16;  // top half of int
+    static final int SPARE_WORKER = 1 << 17;       // set if tc > 0 on creation
+    static final int UNREGISTERED = 1 << 18;       // to skip some of deregister
+    static final int FIFO_QUEUE   = 1 << 31;       // must be negative
+    static final int LIFO_QUEUE   = 0;             // for clarity
+    static final int IS_OWNED     = 1;             // low bit 0 if shared
+
+    /**
+     * The maximum number of task executions from the same queue
+     * before checking other queues, bounding unfairness and impact of
+     * infinite user task recursion.  Must be a power of two minus 1.
+     */
+    static final int POLL_LIMIT = (1 << 10) - 1;
+
+    /**
+     * Queues supporting work-stealing as well as external task
+     * submission. See above for descriptions and algorithms.
+     * Performance on most platforms is very sensitive to placement of
+     * instances of both WorkQueues and their arrays -- we absolutely
+     * do not want multiple WorkQueue instances or multiple queue
+     * arrays sharing cache lines. The @Contended annotation alerts
+     * JVMs to try to keep instances apart.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    //@jdk.internal.vm.annotation.Contended
+    static final class WorkQueue {
+
+        /**
+         * Capacity of work-stealing queue array upon initialization.
+         * Must be a power of two; at least 4, but should be larger to
+         * reduce or eliminate cacheline sharing among queues.
+         * Currently, it is much larger, as a partial workaround for
+         * the fact that JVMs often place arrays in locations that
+         * share GC bookkeeping (especially cardmarks) such that
+         * per-write accesses encounter serious memory contention.
+         */
+        static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+        /**
+         * Maximum size for queue arrays. Must be a power of two less
+         * than or equal to 1 << (31 - width of array entry) to ensure
+         * lack of wraparound of index calculations, but defined to a
+         * value a bit less than this to help users trap runaway
+         * programs before saturating systems.
+         */
+        static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+        // Instance fields
+
+        volatile int scanState;    // versioned, negative if inactive
+        int stackPred;             // pool stack (ctl) predecessor
+        int nsteals;               // number of steals
+        int hint;                  // randomization and stealer index hint
+        int config;                // pool index and mode
+        volatile int qlock;        // 1: locked, < 0: terminate; else 0
+        volatile int base;         // index of next slot for poll
+        int top;                   // index of next slot for push
+        ForkJoinTask<?>[] array;   // the elements (initially unallocated)
+        final ForkJoinPool pool;   // the containing pool (may be null)
+        final ForkJoinWorkerThread owner; // owning thread or null if shared
+        volatile Thread parker;    // == owner during call to park; else null
+        volatile ForkJoinTask<?> currentJoin; // task being joined in awaitJoin
+
+      // Android-removed: @Contended, this hint is not used by the Android runtime.
+      // @jdk.internal.vm.annotation.Contended("group2") // segregate
+        volatile ForkJoinTask<?> currentSteal; // nonnull when running some task
+
+        WorkQueue(ForkJoinPool pool, ForkJoinWorkerThread owner) {
+            this.pool = pool;
+            this.owner = owner;
+            // Place indices in the center of array (that is not yet allocated)
+            base = top = INITIAL_QUEUE_CAPACITY >>> 1;
+        }
+
+        /**
+         * Returns an exportable index (used by ForkJoinWorkerThread).
+         */
+        final int getPoolIndex() {
+            return (config & 0xffff) >>> 1; // ignore odd/even tag bit
+        }
+
+        /**
+         * Returns the approximate number of tasks in the queue.
+         */
+        final int queueSize() {
+            int n = base - top;       // read base first
+            return (n >= 0) ? 0 : -n; // ignore transient negative
+        }
+
+        /**
+         * Provides a more accurate estimate of whether this queue has
+         * any tasks than does queueSize, by checking whether a
+         * near-empty queue has at least one unclaimed task.
+         */
+        final boolean isEmpty() {
+            ForkJoinTask<?>[] a; int n, al, s;
+            return ((n = base - (s = top)) >= 0 || // possibly one task
+                    (n == -1 && ((a = array) == null ||
+                                 (al = a.length) == 0 ||
+                                 a[(al - 1) & (s - 1)] == null)));
+        }
+
+        /**
+         * Pushes a task. Call only by owner in unshared queues.
+         *
+         * @param task the task. Caller must ensure non-null.
+         * @throws RejectedExecutionException if array cannot be resized
+         */
+        final void push(ForkJoinTask<?> task) {
+            U.storeFence();              // ensure safe publication
+            int s = top, al, d; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                a[(al - 1) & s] = task;  // relaxed writes OK
+                top = s + 1;
+                ForkJoinPool p = pool;
+                if ((d = base - s) == 0 && p != null) {
+                    U.fullFence();
+                    p.signalWork();
+                }
+                else if (al + d == 1)
+                    growArray();
+            }
+        }
+
+        /**
+         * Initializes or doubles the capacity of array. Call either
+         * by owner or with lock held -- it is OK for base, but not
+         * top, to move while resizings are in progress.
+         */
+        final ForkJoinTask<?>[] growArray() {
+            ForkJoinTask<?>[] oldA = array;
+            int size = oldA != null ? oldA.length << 1 : INITIAL_QUEUE_CAPACITY;
+            if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
+                throw new RejectedExecutionException("Queue capacity exceeded");
+            int oldMask, t, b;
+            ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
+            if (oldA != null && (oldMask = oldA.length - 1) > 0 &&
+                (t = top) - (b = base) > 0) {
+                int mask = size - 1;
+                do { // emulate poll from old array, push to new array
+                    int index = b & oldMask;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> x = (ForkJoinTask<?>)
+                        U.getObjectVolatile(oldA, offset);
+                    if (x != null &&
+                        U.compareAndSwapObject(oldA, offset, x, null))
+                        a[b & mask] = x;
+                } while (++b != t);
+                U.storeFence();
+            }
+            return a;
+        }
+
+        /**
+         * Takes next task, if one exists, in LIFO order.  Call only
+         * by owner in unshared queues.
+         */
+        final ForkJoinTask<?> pop() {
+            int b = base, s = top, al, i; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & --s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    U.getObject(a, offset);
+                if (t != null &&
+                    U.compareAndSwapObject(a, offset, t, null)) {
+                    top = s;
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes a task in FIFO order if b is base of queue and a task
+         * can be claimed without contention. Specialized versions
+         * appear in ForkJoinPool methods scan and helpStealer.
+         */
+        final ForkJoinTask<?> pollAt(int b) {
+            ForkJoinTask<?>[] a; int al;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & b;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (t != null && b++ == base &&
+                    U.compareAndSwapObject(a, offset, t, null)) {
+                    base = b;
+                    return t;
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in FIFO order.
+         */
+        final ForkJoinTask<?> poll() {
+            for (;;) {
+                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (d = b - s) < 0 &&
+                    (al = a.length) > 0) {
+                    int index = (al - 1) & b;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, offset);
+                    if (b++ == base) {
+                        if (t != null) {
+                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                                base = b;
+                                return t;
+                            }
+                        }
+                        else if (d == -1)
+                            break; // now empty
+                    }
+                }
+                else
+                    break;
+            }
+            return null;
+        }
+
+        /**
+         * Takes next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> nextLocalTask() {
+            return (config < 0) ? poll() : pop();
+        }
+
+        /**
+         * Returns next task, if one exists, in order specified by mode.
+         */
+        final ForkJoinTask<?> peek() {
+            int al; ForkJoinTask<?>[] a;
+            return ((a = array) != null && (al = a.length) > 0) ?
+                a[(al - 1) & (config < 0 ? base : top - 1)] : null;
+        }
+
+        /**
+         * Pops the given task only if it is at the current top.
+         */
+        final boolean tryUnpush(ForkJoinTask<?> task) {
+            int b = base, s = top, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & --s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                if (U.compareAndSwapObject(a, offset, task, null)) {
+                    top = s;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        /**
+         * Shared version of push. Fails if already locked.
+         *
+         * @return status: > 0 locked, 0 possibly was empty, < 0 was nonempty
+         */
+        final int sharedPush(ForkJoinTask<?> task) {
+            int stat;
+            if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                int b = base, s = top, al, d; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (al = a.length) > 0 &&
+                    al - 1 + (d = b - s) > 0) {
+                    a[(al - 1) & s] = task;
+                    top = s + 1;                 // relaxed writes OK here
+                    qlock = 0;
+                    stat = (d < 0 && b == base) ? d : 0;
+                }
+                else {
+                    growAndSharedPush(task);
+                    stat = 0;
+                }
+            }
+            else
+                stat = 1;
+            return stat;
+        }
+
+        /**
+         * Helper for sharedPush; called only when locked and resize
+         * needed.
+         */
+        private void growAndSharedPush(ForkJoinTask<?> task) {
+            try {
+                growArray();
+                int s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && (al = a.length) > 0) {
+                    a[(al - 1) & s] = task;
+                    top = s + 1;
+                }
+            } finally {
+                qlock = 0;
+            }
+        }
+
+        /**
+         * Shared version of tryUnpush.
+         */
+        final boolean trySharedUnpush(ForkJoinTask<?> task) {
+            boolean popped = false;
+            int s = top - 1, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (al = a.length) > 0) {
+                int index = (al - 1) & s;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> t = (ForkJoinTask<?>) U.getObject(a, offset);
+                if (t == task &&
+                    U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                    if (top == s + 1 && array == a &&
+                        U.compareAndSwapObject(a, offset, task, null)) {
+                        popped = true;
+                        top = s;
+                    }
+                    U.putOrderedInt(this, QLOCK, 0);
+                }
+            }
+            return popped;
+        }
+
+        /**
+         * Removes and cancels all known tasks, ignoring any exceptions.
+         */
+        final void cancelAll() {
+            ForkJoinTask<?> t;
+            if ((t = currentJoin) != null) {
+                currentJoin = null;
+                ForkJoinTask.cancelIgnoringExceptions(t);
+            }
+            if ((t = currentSteal) != null) {
+                currentSteal = null;
+                ForkJoinTask.cancelIgnoringExceptions(t);
+            }
+            while ((t = poll()) != null)
+                ForkJoinTask.cancelIgnoringExceptions(t);
+        }
+
+        // Specialized execution methods
+
+        /**
+         * Pops and executes up to POLL_LIMIT tasks or until empty.
+         */
+        final void localPopAndExec() {
+            for (int nexec = 0;;) {
+                int b = base, s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && b != s && (al = a.length) > 0) {
+                    int index = (al - 1) & --s;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getAndSetObject(a, offset, null);
+                    if (t != null) {
+                        top = s;
+                        (currentSteal = t).doExec();
+                        if (++nexec > POLL_LIMIT)
+                            break;
+                    }
+                    else
+                        break;
+                }
+                else
+                    break;
+            }
+        }
+
+        /**
+         * Polls and executes up to POLL_LIMIT tasks or until empty.
+         */
+        final void localPollAndExec() {
+            for (int nexec = 0;;) {
+                int b = base, s = top, al; ForkJoinTask<?>[] a;
+                if ((a = array) != null && b != s && (al = a.length) > 0) {
+                    int index = (al - 1) & b++;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getAndSetObject(a, offset, null);
+                    if (t != null) {
+                        base = b;
+                        t.doExec();
+                        if (++nexec > POLL_LIMIT)
+                            break;
+                    }
+                }
+                else
+                    break;
+            }
+        }
+
+        /**
+         * Executes the given task and (some) remaining local tasks.
+         */
+        final void runTask(ForkJoinTask<?> task) {
+            if (task != null) {
+                task.doExec();
+                if (config < 0)
+                    localPollAndExec();
+                else
+                    localPopAndExec();
+                int ns = ++nsteals;
+                ForkJoinWorkerThread thread = owner;
+                currentSteal = null;
+                if (ns < 0)           // collect on overflow
+                    transferStealCount(pool);
+                if (thread != null)
+                    thread.afterTopLevelExec();
+            }
+        }
+
+        /**
+         * Adds steal count to pool steal count if it exists, and resets.
+         */
+        final void transferStealCount(ForkJoinPool p) {
+            AuxState aux;
+            if (p != null && (aux = p.auxState) != null) {
+                long s = nsteals;
+                nsteals = 0;            // if negative, correct for overflow
+                if (s < 0) s = Integer.MAX_VALUE;
+                aux.lock();
+                try {
+                    aux.stealCount += s;
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+
+        /**
+         * If present, removes from queue and executes the given task,
+         * or any other cancelled task. Used only by awaitJoin.
+         *
+         * @return true if queue empty and task not known to be done
+         */
+        final boolean tryRemoveAndExec(ForkJoinTask<?> task) {
+            if (task != null && task.status >= 0) {
+                int b, s, d, al; ForkJoinTask<?>[] a;
+                while ((d = (b = base) - (s = top)) < 0 &&
+                       (a = array) != null && (al = a.length) > 0) {
+                    for (;;) {      // traverse from s to b
+                        int index = --s & (al - 1);
+                        long offset = (index << ASHIFT) + ABASE;
+                        ForkJoinTask<?> t = (ForkJoinTask<?>)
+                            U.getObjectVolatile(a, offset);
+                        if (t == null)
+                            break;                   // restart
+                        else if (t == task) {
+                            boolean removed = false;
+                            if (s + 1 == top) {      // pop
+                                if (U.compareAndSwapObject(a, offset, t, null)) {
+                                    top = s;
+                                    removed = true;
+                                }
+                            }
+                            else if (base == b)      // replace with proxy
+                                removed = U.compareAndSwapObject(a, offset, t,
+                                                                 new EmptyTask());
+                            if (removed) {
+                                ForkJoinTask<?> ps = currentSteal;
+                                (currentSteal = task).doExec();
+                                currentSteal = ps;
+                            }
+                            break;
+                        }
+                        else if (t.status < 0 && s + 1 == top) {
+                            if (U.compareAndSwapObject(a, offset, t, null)) {
+                                top = s;
+                            }
+                            break;                  // was cancelled
+                        }
+                        else if (++d == 0) {
+                            if (base != b)          // rescan
+                                break;
+                            return false;
+                        }
+                    }
+                    if (task.status < 0)
+                        return false;
+                }
+            }
+            return true;
+        }
+
+        /**
+         * Pops task if in the same CC computation as the given task,
+         * in either shared or owned mode. Used only by helpComplete.
+         */
+        final CountedCompleter<?> popCC(CountedCompleter<?> task, int mode) {
+            int b = base, s = top, al; ForkJoinTask<?>[] a;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & (s - 1);
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> o = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (o instanceof CountedCompleter) {
+                    CountedCompleter<?> t = (CountedCompleter<?>)o;
+                    for (CountedCompleter<?> r = t;;) {
+                        if (r == task) {
+                            if ((mode & IS_OWNED) == 0) {
+                                boolean popped = false;
+                                if (U.compareAndSwapInt(this, QLOCK, 0, 1)) {
+                                    if (top == s && array == a &&
+                                        U.compareAndSwapObject(a, offset,
+                                                               t, null)) {
+                                        popped = true;
+                                        top = s - 1;
+                                    }
+                                    U.putOrderedInt(this, QLOCK, 0);
+                                    if (popped)
+                                        return t;
+                                }
+                            }
+                            else if (U.compareAndSwapObject(a, offset,
+                                                            t, null)) {
+                                top = s - 1;
+                                return t;
+                            }
+                            break;
+                        }
+                        else if ((r = r.completer) == null) // try parent
+                            break;
+                    }
+                }
+            }
+            return null;
+        }
+
+        /**
+         * Steals and runs a task in the same CC computation as the
+         * given task if one exists and can be taken without
+         * contention. Otherwise returns a checksum/control value for
+         * use by method helpComplete.
+         *
+         * @return 1 if successful, 2 if retryable (lost to another
+         * stealer), -1 if non-empty but no matching task found, else
+         * the base index, forced negative.
+         */
+        final int pollAndExecCC(CountedCompleter<?> task) {
+            ForkJoinTask<?>[] a;
+            int b = base, s = top, al, h;
+            if ((a = array) != null && b != s && (al = a.length) > 0) {
+                int index = (al - 1) & b;
+                long offset = ((long)index << ASHIFT) + ABASE;
+                ForkJoinTask<?> o = (ForkJoinTask<?>)
+                    U.getObjectVolatile(a, offset);
+                if (o == null)
+                    h = 2;                      // retryable
+                else if (!(o instanceof CountedCompleter))
+                    h = -1;                     // unmatchable
+                else {
+                    CountedCompleter<?> t = (CountedCompleter<?>)o;
+                    for (CountedCompleter<?> r = t;;) {
+                        if (r == task) {
+                            if (b++ == base &&
+                                U.compareAndSwapObject(a, offset, t, null)) {
+                                base = b;
+                                t.doExec();
+                                h = 1;          // success
+                            }
+                            else
+                                h = 2;          // lost CAS
+                            break;
+                        }
+                        else if ((r = r.completer) == null) {
+                            h = -1;             // unmatched
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+                h = b | Integer.MIN_VALUE;      // to sense movement on re-poll
+            return h;
+        }
+
+        /**
+         * Returns true if owned and not known to be blocked.
+         */
+        final boolean isApparentlyUnblocked() {
+            Thread wt; Thread.State s;
+            return (scanState >= 0 &&
+                    (wt = owner) != null &&
+                    (s = wt.getState()) != Thread.State.BLOCKED &&
+                    s != Thread.State.WAITING &&
+                    s != Thread.State.TIMED_WAITING);
+        }
+
+        // Unsafe mechanics. Note that some are (and must be) the same as in FJP
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long QLOCK;
+        private static final int ABASE;
+        private static final int ASHIFT;
+        static {
+            try {
+                QLOCK = U.objectFieldOffset
+                    (WorkQueue.class.getDeclaredField("qlock"));
+                ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
+                int scale = U.arrayIndexScale(ForkJoinTask[].class);
+                if ((scale & (scale - 1)) != 0)
+                    throw new Error("array index scale not a power of two");
+                ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    // static fields (initialized in static initializer below)
+
+    /**
+     * Creates a new ForkJoinWorkerThread. This factory is used unless
+     * overridden in ForkJoinPool constructors.
+     */
+    public static final ForkJoinWorkerThreadFactory
+        defaultForkJoinWorkerThreadFactory;
+
+    /**
+     * Permission required for callers of methods that may start or
+     * kill threads.  Also used as a static lock in tryInitialize.
+     */
+    static final RuntimePermission modifyThreadPermission;
+
+    /**
+     * Common (static) pool. Non-null for public use unless a static
+     * construction exception, but internal usages null-check on use
+     * to paranoically avoid potential initialization circularities
+     * as well as to simplify generated code.
+     */
+    static final ForkJoinPool common;
+
+    /**
+     * Common pool parallelism. To allow simpler use and management
+     * when common pool threads are disabled, we allow the underlying
+     * common.parallelism field to be zero, but in that case still report
+     * parallelism as 1 to reflect resulting caller-runs mechanics.
+     */
+    static final int COMMON_PARALLELISM;
+
+    /**
+     * Limit on spare thread construction in tryCompensate.
+     */
+    private static final int COMMON_MAX_SPARES;
+
+    /**
+     * Sequence number for creating workerNamePrefix.
+     */
+    private static int poolNumberSequence;
+
+    /**
+     * Returns the next sequence number. We don't expect this to
+     * ever contend, so use simple builtin sync.
+     */
+    private static final synchronized int nextPoolId() {
+        return ++poolNumberSequence;
+    }
+
+    // static configuration constants
+
+    /**
+     * Initial timeout value (in milliseconds) for the thread
+     * triggering quiescence to park waiting for new work. On timeout,
+     * the thread will instead try to shrink the number of workers.
+     * The value should be large enough to avoid overly aggressive
+     * shrinkage during most transient stalls (long GCs etc).
+     */
+    private static final long IDLE_TIMEOUT_MS = 2000L; // 2sec
+
+    /**
+     * Tolerance for idle timeouts, to cope with timer undershoots.
+     */
+    private static final long TIMEOUT_SLOP_MS =   20L; // 20ms
+
+    /**
+     * The default value for COMMON_MAX_SPARES.  Overridable using the
+     * "java.util.concurrent.ForkJoinPool.common.maximumSpares" system
+     * property.  The default value is far in excess of normal
+     * requirements, but also far short of MAX_CAP and typical OS
+     * thread limits, so allows JVMs to catch misuse/abuse before
+     * running out of resources needed to do so.
+     */
+    private static final int DEFAULT_COMMON_MAX_SPARES = 256;
+
+    /**
+     * Increment for seed generators. See class ThreadLocal for
+     * explanation.
+     */
+    private static final int SEED_INCREMENT = 0x9e3779b9;
+
+    /*
+     * Bits and masks for field ctl, packed with 4 16 bit subfields:
+     * AC: Number of active running workers minus target parallelism
+     * TC: Number of total workers minus target parallelism
+     * SS: version count and status of top waiting thread
+     * ID: poolIndex of top of Treiber stack of waiters
+     *
+     * When convenient, we can extract the lower 32 stack top bits
+     * (including version bits) as sp=(int)ctl.  The offsets of counts
+     * by the target parallelism and the positionings of fields makes
+     * it possible to perform the most common checks via sign tests of
+     * fields: When ac is negative, there are not enough active
+     * workers, when tc is negative, there are not enough total
+     * workers.  When sp is non-zero, there are waiting workers.  To
+     * deal with possibly negative fields, we use casts in and out of
+     * "short" and/or signed shifts to maintain signedness.
+     *
+     * Because it occupies uppermost bits, we can add one active count
+     * using getAndAddLong of AC_UNIT, rather than CAS, when returning
+     * from a blocked join.  Other updates entail multiple subfields
+     * and masking, requiring CAS.
+     */
+
+    // Lower and upper word masks
+    private static final long SP_MASK    = 0xffffffffL;
+    private static final long UC_MASK    = ~SP_MASK;
+
+    // Active counts
+    private static final int  AC_SHIFT   = 48;
+    private static final long AC_UNIT    = 0x0001L << AC_SHIFT;
+    private static final long AC_MASK    = 0xffffL << AC_SHIFT;
+
+    // Total counts
+    private static final int  TC_SHIFT   = 32;
+    private static final long TC_UNIT    = 0x0001L << TC_SHIFT;
+    private static final long TC_MASK    = 0xffffL << TC_SHIFT;
+    private static final long ADD_WORKER = 0x0001L << (TC_SHIFT + 15); // sign
+
+    // runState bits: SHUTDOWN must be negative, others arbitrary powers of two
+    private static final int  STARTED    = 1;
+    private static final int  STOP       = 1 << 1;
+    private static final int  TERMINATED = 1 << 2;
+    private static final int  SHUTDOWN   = 1 << 31;
+
+    // Instance fields
+    volatile long ctl;                   // main pool control
+    volatile int runState;
+    final int config;                    // parallelism, mode
+    AuxState auxState;                   // lock, steal counts
+    volatile WorkQueue[] workQueues;     // main registry
+    final String workerNamePrefix;       // to create worker name string
+    final ForkJoinWorkerThreadFactory factory;
+    final UncaughtExceptionHandler ueh;  // per-worker UEH
+
+    /**
+     * Instantiates fields upon first submission, or upon shutdown if
+     * no submissions. If checkTermination true, also responds to
+     * termination by external calls submitting tasks.
+     */
+    private void tryInitialize(boolean checkTermination) {
+        if (runState == 0) { // bootstrap by locking static field
+            int p = config & SMASK;
+            int n = (p > 1) ? p - 1 : 1; // ensure at least 2 slots
+            n |= n >>> 1;    // create workQueues array with size a power of two
+            n |= n >>> 2;
+            n |= n >>> 4;
+            n |= n >>> 8;
+            n |= n >>> 16;
+            n = ((n + 1) << 1) & SMASK;
+            AuxState aux = new AuxState();
+            WorkQueue[] ws = new WorkQueue[n];
+            synchronized (modifyThreadPermission) { // double-check
+                if (runState == 0) {
+                    workQueues = ws;
+                    auxState = aux;
+                    runState = STARTED;
+                }
+            }
+        }
+        if (checkTermination && runState < 0) {
+            tryTerminate(false, false); // help terminate
+            throw new RejectedExecutionException();
+        }
+    }
+
+    // Creating, registering and deregistering workers
+
+    /**
+     * Tries to construct and start one worker. Assumes that total
+     * count has already been incremented as a reservation.  Invokes
+     * deregisterWorker on any failure.
+     *
+     * @param isSpare true if this is a spare thread
+     * @return true if successful
+     */
+    private boolean createWorker(boolean isSpare) {
+        ForkJoinWorkerThreadFactory fac = factory;
+        Throwable ex = null;
+        ForkJoinWorkerThread wt = null;
+        WorkQueue q;
+        try {
+            if (fac != null && (wt = fac.newThread(this)) != null) {
+                if (isSpare && (q = wt.workQueue) != null)
+                    q.config |= SPARE_WORKER;
+                wt.start();
+                return true;
+            }
+        } catch (Throwable rex) {
+            ex = rex;
+        }
+        deregisterWorker(wt, ex);
+        return false;
+    }
+
+    /**
+     * Tries to add one worker, incrementing ctl counts before doing
+     * so, relying on createWorker to back out on failure.
+     *
+     * @param c incoming ctl value, with total count negative and no
+     * idle workers.  On CAS failure, c is refreshed and retried if
+     * this holds (otherwise, a new worker is not needed).
+     */
+    private void tryAddWorker(long c) {
+        do {
+            long nc = ((AC_MASK & (c + AC_UNIT)) |
+                       (TC_MASK & (c + TC_UNIT)));
+            if (ctl == c && U.compareAndSwapLong(this, CTL, c, nc)) {
+                createWorker(false);
+                break;
+            }
+        } while (((c = ctl) & ADD_WORKER) != 0L && (int)c == 0);
+    }
+
+    /**
+     * Callback from ForkJoinWorkerThread constructor to establish and
+     * record its WorkQueue.
+     *
+     * @param wt the worker thread
+     * @return the worker's queue
+     */
+    final WorkQueue registerWorker(ForkJoinWorkerThread wt) {
+        UncaughtExceptionHandler handler;
+        AuxState aux;
+        wt.setDaemon(true);                           // configure thread
+        if ((handler = ueh) != null)
+            wt.setUncaughtExceptionHandler(handler);
+        WorkQueue w = new WorkQueue(this, wt);
+        int i = 0;                                    // assign a pool index
+        int mode = config & MODE_MASK;
+        if ((aux = auxState) != null) {
+            aux.lock();
+            try {
+                int s = (int)(aux.indexSeed += SEED_INCREMENT), n, m;
+                WorkQueue[] ws = workQueues;
+                if (ws != null && (n = ws.length) > 0) {
+                    i = (m = n - 1) & ((s << 1) | 1); // odd-numbered indices
+                    if (ws[i] != null) {              // collision
+                        int probes = 0;               // step by approx half n
+                        int step = (n <= 4) ? 2 : ((n >>> 1) & EVENMASK) + 2;
+                        while (ws[i = (i + step) & m] != null) {
+                            if (++probes >= n) {
+                                workQueues = ws = Arrays.copyOf(ws, n <<= 1);
+                                m = n - 1;
+                                probes = 0;
+                            }
+                        }
+                    }
+                    w.hint = s;                       // use as random seed
+                    w.config = i | mode;
+                    w.scanState = i | (s & 0x7fff0000); // random seq bits
+                    ws[i] = w;
+                }
+            } finally {
+                aux.unlock();
+            }
+        }
+        wt.setName(workerNamePrefix.concat(Integer.toString(i >>> 1)));
+        return w;
+    }
+
+    /**
+     * Final callback from terminating worker, as well as upon failure
+     * to construct or start a worker.  Removes record of worker from
+     * array, and adjusts counts. If pool is shutting down, tries to
+     * complete termination.
+     *
+     * @param wt the worker thread, or null if construction failed
+     * @param ex the exception causing failure, or null if none
+     */
+    final void deregisterWorker(ForkJoinWorkerThread wt, Throwable ex) {
+        WorkQueue w = null;
+        if (wt != null && (w = wt.workQueue) != null) {
+            AuxState aux; WorkQueue[] ws;          // remove index from array
+            int idx = w.config & SMASK;
+            int ns = w.nsteals;
+            if ((aux = auxState) != null) {
+                aux.lock();
+                try {
+                    if ((ws = workQueues) != null && ws.length > idx &&
+                        ws[idx] == w)
+                        ws[idx] = null;
+                    aux.stealCount += ns;
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+        if (w == null || (w.config & UNREGISTERED) == 0) { // else pre-adjusted
+            long c;                                   // decrement counts
+            do {} while (!U.compareAndSwapLong
+                         (this, CTL, c = ctl, ((AC_MASK & (c - AC_UNIT)) |
+                                               (TC_MASK & (c - TC_UNIT)) |
+                                               (SP_MASK & c))));
+        }
+        if (w != null) {
+            w.currentSteal = null;
+            w.qlock = -1;                             // ensure set
+            w.cancelAll();                            // cancel remaining tasks
+        }
+        while (tryTerminate(false, false) >= 0) {     // possibly replace
+            WorkQueue[] ws; int wl, sp; long c;
+            if (w == null || w.array == null ||
+                (ws = workQueues) == null || (wl = ws.length) <= 0)
+                break;
+            else if ((sp = (int)(c = ctl)) != 0) {    // wake up replacement
+                if (tryRelease(c, ws[(wl - 1) & sp], AC_UNIT))
+                    break;
+            }
+            else if (ex != null && (c & ADD_WORKER) != 0L) {
+                tryAddWorker(c);                      // create replacement
+                break;
+            }
+            else                                      // don't need replacement
+                break;
+        }
+        if (ex == null)                               // help clean on way out
+            ForkJoinTask.helpExpungeStaleExceptions();
+        else                                          // rethrow
+            ForkJoinTask.rethrow(ex);
+    }
+
+    // Signalling
+
+    /**
+     * Tries to create or activate a worker if too few are active.
+     */
+    final void signalWork() {
+        for (;;) {
+            long c; int sp, i; WorkQueue v; WorkQueue[] ws;
+            if ((c = ctl) >= 0L)                      // enough workers
+                break;
+            else if ((sp = (int)c) == 0) {            // no idle workers
+                if ((c & ADD_WORKER) != 0L)           // too few workers
+                    tryAddWorker(c);
+                break;
+            }
+            else if ((ws = workQueues) == null)
+                break;                                // unstarted/terminated
+            else if (ws.length <= (i = sp & SMASK))
+                break;                                // terminated
+            else if ((v = ws[i]) == null)
+                break;                                // terminating
+            else {
+                int ns = sp & ~UNSIGNALLED;
+                int vs = v.scanState;
+                long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
+                if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
+                    v.scanState = ns;
+                    LockSupport.unpark(v.parker);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Signals and releases worker v if it is top of idle worker
+     * stack.  This performs a one-shot version of signalWork only if
+     * there is (apparently) at least one idle worker.
+     *
+     * @param c incoming ctl value
+     * @param v if non-null, a worker
+     * @param inc the increment to active count (zero when compensating)
+     * @return true if successful
+     */
+    private boolean tryRelease(long c, WorkQueue v, long inc) {
+        int sp = (int)c, ns = sp & ~UNSIGNALLED;
+        if (v != null) {
+            int vs = v.scanState;
+            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + inc));
+            if (sp == vs && U.compareAndSwapLong(this, CTL, c, nc)) {
+                v.scanState = ns;
+                LockSupport.unpark(v.parker);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * With approx probability of a missed signal, tries (once) to
+     * reactivate worker w (or some other worker), failing if stale or
+     * known to be already active.
+     *
+     * @param w the worker
+     * @param ws the workQueue array to use
+     * @param r random seed
+     */
+    private void tryReactivate(WorkQueue w, WorkQueue[] ws, int r) {
+        long c; int sp, wl; WorkQueue v;
+        if ((sp = (int)(c = ctl)) != 0 && w != null &&
+            ws != null && (wl = ws.length) > 0 &&
+            ((sp ^ r) & SS_SEQ) == 0 &&
+            (v = ws[(wl - 1) & sp]) != null) {
+            long nc = (v.stackPred & SP_MASK) | (UC_MASK & (c + AC_UNIT));
+            int ns = sp & ~UNSIGNALLED;
+            if (w.scanState < 0 &&
+                v.scanState == sp &&
+                U.compareAndSwapLong(this, CTL, c, nc)) {
+                v.scanState = ns;
+                LockSupport.unpark(v.parker);
+            }
+        }
+    }
+
+    /**
+     * If worker w exists and is active, enqueues and sets status to inactive.
+     *
+     * @param w the worker
+     * @param ss current (non-negative) scanState
+     */
+    private void inactivate(WorkQueue w, int ss) {
+        int ns = (ss + SS_SEQ) | UNSIGNALLED;
+        long lc = ns & SP_MASK, nc, c;
+        if (w != null) {
+            w.scanState = ns;
+            do {
+                nc = lc | (UC_MASK & ((c = ctl) - AC_UNIT));
+                w.stackPred = (int)c;
+            } while (!U.compareAndSwapLong(this, CTL, c, nc));
+        }
+    }
+
+    /**
+     * Possibly blocks worker w waiting for signal, or returns
+     * negative status if the worker should terminate. May return
+     * without status change if multiple stale unparks and/or
+     * interrupts occur.
+     *
+     * @param w the calling worker
+     * @return negative if w should terminate
+     */
+    private int awaitWork(WorkQueue w) {
+        int stat = 0;
+        if (w != null && w.scanState < 0) {
+            long c = ctl;
+            if ((int)(c >> AC_SHIFT) + (config & SMASK) <= 0)
+                stat = timedAwaitWork(w, c);     // possibly quiescent
+            else if ((runState & STOP) != 0)
+                stat = w.qlock = -1;             // pool terminating
+            else if (w.scanState < 0) {
+                w.parker = Thread.currentThread();
+                if (w.scanState < 0)             // recheck after write
+                    LockSupport.park(this);
+                w.parker = null;
+                if ((runState & STOP) != 0)
+                    stat = w.qlock = -1;         // recheck
+                else if (w.scanState < 0)
+                    Thread.interrupted();        // clear status
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * Possibly triggers shutdown and tries (once) to block worker
+     * when pool is (or may be) quiescent. Waits up to a duration
+     * determined by number of workers.  On timeout, if ctl has not
+     * changed, terminates the worker, which will in turn wake up
+     * another worker to possibly repeat this process.
+     *
+     * @param w the calling worker
+     * @return negative if w should terminate
+     */
+    private int timedAwaitWork(WorkQueue w, long c) {
+        int stat = 0;
+        int scale = 1 - (short)(c >>> TC_SHIFT);
+        long deadline = (((scale <= 0) ? 1 : scale) * IDLE_TIMEOUT_MS +
+                         System.currentTimeMillis());
+        if ((runState >= 0 || (stat = tryTerminate(false, false)) > 0) &&
+            w != null && w.scanState < 0) {
+            int ss; AuxState aux;
+            w.parker = Thread.currentThread();
+            if (w.scanState < 0)
+                LockSupport.parkUntil(this, deadline);
+            w.parker = null;
+            if ((runState & STOP) != 0)
+                stat = w.qlock = -1;         // pool terminating
+            else if ((ss = w.scanState) < 0 && !Thread.interrupted() &&
+                     (int)c == ss && (aux = auxState) != null && ctl == c &&
+                     deadline - System.currentTimeMillis() <= TIMEOUT_SLOP_MS) {
+                aux.lock();
+                try {                        // pre-deregister
+                    WorkQueue[] ws;
+                    int cfg = w.config, idx = cfg & SMASK;
+                    long nc = ((UC_MASK & (c - TC_UNIT)) |
+                               (SP_MASK & w.stackPred));
+                    if ((runState & STOP) == 0 &&
+                        (ws = workQueues) != null &&
+                        idx < ws.length && idx >= 0 && ws[idx] == w &&
+                        U.compareAndSwapLong(this, CTL, c, nc)) {
+                        ws[idx] = null;
+                        w.config = cfg | UNREGISTERED;
+                        stat = w.qlock = -1;
+                    }
+                } finally {
+                    aux.unlock();
+                }
+            }
+        }
+        return stat;
+    }
+
+    /**
+     * If the given worker is a spare with no queued tasks, and there
+     * are enough existing workers, drops it from ctl counts and sets
+     * its state to terminated.
+     *
+     * @param w the calling worker -- must be a spare
+     * @return true if dropped (in which case it must not process more tasks)
+     */
+    private boolean tryDropSpare(WorkQueue w) {
+        if (w != null && w.isEmpty()) {           // no local tasks
+            long c; int sp, wl; WorkQueue[] ws; WorkQueue v;
+            while ((short)((c = ctl) >> TC_SHIFT) > 0 &&
+                   ((sp = (int)c) != 0 || (int)(c >> AC_SHIFT) > 0) &&
+                   (ws = workQueues) != null && (wl = ws.length) > 0) {
+                boolean dropped, canDrop;
+                if (sp == 0) {                    // no queued workers
+                    long nc = ((AC_MASK & (c - AC_UNIT)) |
+                               (TC_MASK & (c - TC_UNIT)) | (SP_MASK & c));
+                    dropped = U.compareAndSwapLong(this, CTL, c, nc);
+                }
+                else if (
+                    (v = ws[(wl - 1) & sp]) == null || v.scanState != sp)
+                    dropped = false;              // stale; retry
+                else {
+                    long nc = v.stackPred & SP_MASK;
+                    if (w == v || w.scanState >= 0) {
+                        canDrop = true;           // w unqueued or topmost
+                        nc |= ((AC_MASK & c) |    // ensure replacement
+                               (TC_MASK & (c - TC_UNIT)));
+                    }
+                    else {                        // w may be queued
+                        canDrop = false;          // help uncover
+                        nc |= ((AC_MASK & (c + AC_UNIT)) |
+                               (TC_MASK & c));
+                    }
+                    if (U.compareAndSwapLong(this, CTL, c, nc)) {
+                        v.scanState = sp & ~UNSIGNALLED;
+                        LockSupport.unpark(v.parker);
+                        dropped = canDrop;
+                    }
+                    else
+                        dropped = false;
+                }
+                if (dropped) {                    // pre-deregister
+                    int cfg = w.config, idx = cfg & SMASK;
+                    if (idx >= 0 && idx < ws.length && ws[idx] == w)
+                        ws[idx] = null;
+                    w.config = cfg | UNREGISTERED;
+                    w.qlock = -1;
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.
+     */
+    final void runWorker(WorkQueue w) {
+        w.growArray();                                  // allocate queue
+        int bound = (w.config & SPARE_WORKER) != 0 ? 0 : POLL_LIMIT;
+        long seed = w.hint * 0xdaba0b6eb09322e3L;       // initial random seed
+        if ((runState & STOP) == 0) {
+            for (long r = (seed == 0L) ? 1L : seed;;) { // ensure nonzero
+                if (bound == 0 && tryDropSpare(w))
+                    break;
+                // high bits of prev seed for step; current low bits for idx
+                int step = (int)(r >>> 48) | 1;
+                r ^= r >>> 12; r ^= r << 25; r ^= r >>> 27; // xorshift
+                if (scan(w, bound, step, (int)r) < 0 && awaitWork(w) < 0)
+                    break;
+            }
+        }
+    }
+
+    // Scanning for tasks
+
+    /**
+     * Repeatedly scans for and tries to steal and execute (via
+     * workQueue.runTask) a queued task. Each scan traverses queues in
+     * pseudorandom permutation. Upon finding a non-empty queue, makes
+     * at most the given bound attempts to re-poll (fewer if
+     * contended) on the same queue before returning (impossible
+     * scanState value) 0 to restart scan. Else returns after at least
+     * 1 and at most 32 full scans.
+     *
+     * @param w the worker (via its WorkQueue)
+     * @param bound repoll bound as bitmask (0 if spare)
+     * @param step (circular) index increment per iteration (must be odd)
+     * @param r a random seed for origin index
+     * @return negative if should await signal
+     */
+    private int scan(WorkQueue w, int bound, int step, int r) {
+        int stat = 0, wl; WorkQueue[] ws;
+        if ((ws = workQueues) != null && w != null && (wl = ws.length) > 0) {
+            for (int m = wl - 1,
+                     origin = m & r, idx = origin,
+                     npolls = 0,
+                     ss = w.scanState;;) {         // negative if inactive
+                WorkQueue q; ForkJoinTask<?>[] a; int b, al;
+                if ((q = ws[idx]) != null && (b = q.base) - q.top < 0 &&
+                    (a = q.array) != null && (al = a.length) > 0) {
+                    int index = (al - 1) & b;
+                    long offset = ((long)index << ASHIFT) + ABASE;
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)
+                        U.getObjectVolatile(a, offset);
+                    if (t == null)
+                        break;                     // empty or busy
+                    else if (b++ != q.base)
+                        break;                     // busy
+                    else if (ss < 0) {
+                        tryReactivate(w, ws, r);
+                        break;                     // retry upon rescan
+                    }
+                    else if (!U.compareAndSwapObject(a, offset, t, null))
+                        break;                     // contended
+                    else {
+                        q.base = b;
+                        w.currentSteal = t;
+                        if (b != q.top)            // propagate signal
+                            signalWork();
+                        w.runTask(t);
+                        if (++npolls > bound)
+                            break;
+                    }
+                }
+                else if (npolls != 0)              // rescan
+                    break;
+                else if ((idx = (idx + step) & m) == origin) {
+                    if (ss < 0) {                  // await signal
+                        stat = ss;
+                        break;
+                    }
+                    else if (r >= 0) {
+                        inactivate(w, ss);
+                        break;
+                    }
+                    else
+                        r <<= 1;                   // at most 31 rescans
+                }
+            }
+        }
+        return stat;
+    }
+
+    // Joining tasks
+
+    /**
+     * Tries to steal and run tasks within the target's computation.
+     * Uses a variant of the top-level algorithm, restricted to tasks
+     * with the given task as ancestor: It prefers taking and running
+     * eligible tasks popped from the worker's own queue (via
+     * popCC). Otherwise it scans others, randomly moving on
+     * contention or execution, deciding to give up based on a
+     * checksum (via return codes from pollAndExecCC). The maxTasks
+     * argument supports external usages; internal calls use zero,
+     * allowing unbounded steps (external calls trap non-positive
+     * values).
+     *
+     * @param w caller
+     * @param maxTasks if non-zero, the maximum number of other tasks to run
+     * @return task status on exit
+     */
+    final int helpComplete(WorkQueue w, CountedCompleter<?> task,
+                           int maxTasks) {
+        WorkQueue[] ws; int s = 0, wl;
+        if ((ws = workQueues) != null && (wl = ws.length) > 1 &&
+            task != null && w != null) {
+            for (int m = wl - 1,
+                     mode = w.config,
+                     r = ~mode,                  // scanning seed
+                     origin = r & m, k = origin, // first queue to scan
+                     step = 3,                   // first scan step
+                     h = 1,                      // 1:ran, >1:contended, <0:hash
+                     oldSum = 0, checkSum = 0;;) {
+                CountedCompleter<?> p; WorkQueue q; int i;
+                if ((s = task.status) < 0)
+                    break;
+                if (h == 1 && (p = w.popCC(task, mode)) != null) {
+                    p.doExec();                  // run local task
+                    if (maxTasks != 0 && --maxTasks == 0)
+                        break;
+                    origin = k;                  // reset
+                    oldSum = checkSum = 0;
+                }
+                else {                           // poll other worker queues
+                    if ((i = k | 1) < 0 || i > m || (q = ws[i]) == null)
+                        h = 0;
+                    else if ((h = q.pollAndExecCC(task)) < 0)
+                        checkSum += h;
+                    if (h > 0) {
+                        if (h == 1 && maxTasks != 0 && --maxTasks == 0)
+                            break;
+                        step = (r >>> 16) | 3;
+                        r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift
+                        k = origin = r & m;      // move and restart
+                        oldSum = checkSum = 0;
+                    }
+                    else if ((k = (k + step) & m) == origin) {
+                        if (oldSum == (oldSum = checkSum))
+                            break;
+                        checkSum = 0;
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Tries to locate and execute tasks for a stealer of the given
+     * task, or in turn one of its stealers. Traces currentSteal ->
+     * currentJoin links looking for a thread working on a descendant
+     * of the given task and with a non-empty queue to steal back and
+     * execute tasks from. The first call to this method upon a
+     * waiting join will often entail scanning/search, (which is OK
+     * because the joiner has nothing better to do), but this method
+     * leaves hints in workers to speed up subsequent calls.
+     *
+     * @param w caller
+     * @param task the task to join
+     */
+    private void helpStealer(WorkQueue w, ForkJoinTask<?> task) {
+        if (task != null && w != null) {
+            ForkJoinTask<?> ps = w.currentSteal;
+            WorkQueue[] ws; int wl, oldSum = 0;
+            outer: while (w.tryRemoveAndExec(task) && task.status >= 0 &&
+                          (ws = workQueues) != null && (wl = ws.length) > 0) {
+                ForkJoinTask<?> subtask;
+                int m = wl - 1, checkSum = 0;          // for stability check
+                WorkQueue j = w, v;                    // v is subtask stealer
+                descent: for (subtask = task; subtask.status >= 0; ) {
+                    for (int h = j.hint | 1, k = 0, i;;) {
+                        if ((v = ws[i = (h + (k << 1)) & m]) != null) {
+                            if (v.currentSteal == subtask) {
+                                j.hint = i;
+                                break;
+                            }
+                            checkSum += v.base;
+                        }
+                        if (++k > m)                   // can't find stealer
+                            break outer;
+                    }
+
+                    for (;;) {                         // help v or descend
+                        ForkJoinTask<?>[] a; int b, al;
+                        if (subtask.status < 0)        // too late to help
+                            break descent;
+                        checkSum += (b = v.base);
+                        ForkJoinTask<?> next = v.currentJoin;
+                        ForkJoinTask<?> t = null;
+                        if ((a = v.array) != null && (al = a.length) > 0) {
+                            int index = (al - 1) & b;
+                            long offset = ((long)index << ASHIFT) + ABASE;
+                            t = (ForkJoinTask<?>)
+                                U.getObjectVolatile(a, offset);
+                            if (t != null && b++ == v.base) {
+                                if (j.currentJoin != subtask ||
+                                    v.currentSteal != subtask ||
+                                    subtask.status < 0)
+                                    break descent;     // stale
+                                if (U.compareAndSwapObject(a, offset, t, null)) {
+                                    v.base = b;
+                                    w.currentSteal = t;
+                                    for (int top = w.top;;) {
+                                        t.doExec();    // help
+                                        w.currentSteal = ps;
+                                        if (task.status < 0)
+                                            break outer;
+                                        if (w.top == top)
+                                            break;     // run local tasks
+                                        if ((t = w.pop()) == null)
+                                            break descent;
+                                        w.currentSteal = t;
+                                    }
+                                }
+                            }
+                        }
+                        if (t == null && b == v.base && b - v.top >= 0) {
+                            if ((subtask = next) == null) {  // try to descend
+                                if (next == v.currentJoin &&
+                                    oldSum == (oldSum = checkSum))
+                                    break outer;
+                                break descent;
+                            }
+                            j = v;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Tries to decrement active count (sometimes implicitly) and
+     * possibly release or create a compensating worker in preparation
+     * for blocking. Returns false (retryable by caller), on
+     * contention, detected staleness, instability, or termination.
+     *
+     * @param w caller
+     */
+    private boolean tryCompensate(WorkQueue w) {
+        boolean canBlock; int wl;
+        long c = ctl;
+        WorkQueue[] ws = workQueues;
+        int pc = config & SMASK;
+        int ac = pc + (int)(c >> AC_SHIFT);
+        int tc = pc + (short)(c >> TC_SHIFT);
+        if (w == null || w.qlock < 0 || pc == 0 ||  // terminating or disabled
+            ws == null || (wl = ws.length) <= 0)
+            canBlock = false;
+        else {
+            int m = wl - 1, sp;
+            boolean busy = true;                    // validate ac
+            for (int i = 0; i <= m; ++i) {
+                int k; WorkQueue v;
+                if ((k = (i << 1) | 1) <= m && k >= 0 && (v = ws[k]) != null &&
+                    v.scanState >= 0 && v.currentSteal == null) {
+                    busy = false;
+                    break;
+                }
+            }
+            if (!busy || ctl != c)
+                canBlock = false;                   // unstable or stale
+            else if ((sp = (int)c) != 0)            // release idle worker
+                canBlock = tryRelease(c, ws[m & sp], 0L);
+            else if (tc >= pc && ac > 1 && w.isEmpty()) {
+                long nc = ((AC_MASK & (c - AC_UNIT)) |
+                           (~AC_MASK & c));         // uncompensated
+                canBlock = U.compareAndSwapLong(this, CTL, c, nc);
+            }
+            else if (tc >= MAX_CAP ||
+                     (this == common && tc >= pc + COMMON_MAX_SPARES))
+                throw new RejectedExecutionException(
+                    "Thread limit exceeded replacing blocked worker");
+            else {                                  // similar to tryAddWorker
+                boolean isSpare = (tc >= pc);
+                long nc = (AC_MASK & c) | (TC_MASK & (c + TC_UNIT));
+                canBlock = (U.compareAndSwapLong(this, CTL, c, nc) &&
+                            createWorker(isSpare)); // throws on exception
+            }
+        }
+        return canBlock;
+    }
+
+    /**
+     * Helps and/or blocks until the given task is done or timeout.
+     *
+     * @param w caller
+     * @param task the task
+     * @param deadline for timed waits, if nonzero
+     * @return task status on exit
+     */
+    final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
+        int s = 0;
+        if (w != null) {
+            ForkJoinTask<?> prevJoin = w.currentJoin;
+            if (task != null && (s = task.status) >= 0) {
+                w.currentJoin = task;
+                CountedCompleter<?> cc = (task instanceof CountedCompleter) ?
+                    (CountedCompleter<?>)task : null;
+                for (;;) {
+                    if (cc != null)
+                        helpComplete(w, cc, 0);
+                    else
+                        helpStealer(w, task);
+                    if ((s = task.status) < 0)
+                        break;
+                    long ms, ns;
+                    if (deadline == 0L)
+                        ms = 0L;
+                    else if ((ns = deadline - System.nanoTime()) <= 0L)
+                        break;
+                    else if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) <= 0L)
+                        ms = 1L;
+                    if (tryCompensate(w)) {
+                        task.internalWait(ms);
+                        U.getAndAddLong(this, CTL, AC_UNIT);
+                    }
+                    if ((s = task.status) < 0)
+                        break;
+                }
+                w.currentJoin = prevJoin;
+            }
+        }
+        return s;
+    }
+
+    // Specialized scanning
+
+    /**
+     * Returns a (probably) non-empty steal queue, if one is found
+     * during a scan, else null.  This method must be retried by
+     * caller if, by the time it tries to use the queue, it is empty.
+     */
+    private WorkQueue findNonEmptyStealQueue() {
+        WorkQueue[] ws; int wl;  // one-shot version of scan loop
+        int r = ThreadLocalRandom.nextSecondarySeed();
+        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
+            int m = wl - 1, origin = r & m;
+            for (int k = origin, oldSum = 0, checkSum = 0;;) {
+                WorkQueue q; int b;
+                if ((q = ws[k]) != null) {
+                    if ((b = q.base) - q.top < 0)
+                        return q;
+                    checkSum += b;
+                }
+                if ((k = (k + 1) & m) == origin) {
+                    if (oldSum == (oldSum = checkSum))
+                        break;
+                    checkSum = 0;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Runs tasks until {@code isQuiescent()}. We piggyback on
+     * active count ctl maintenance, but rather than blocking
+     * when tasks cannot be found, we rescan until all others cannot
+     * find tasks either.
+     */
+    final void helpQuiescePool(WorkQueue w) {
+        ForkJoinTask<?> ps = w.currentSteal; // save context
+        int wc = w.config;
+        for (boolean active = true;;) {
+            long c; WorkQueue q; ForkJoinTask<?> t;
+            if (wc >= 0 && (t = w.pop()) != null) { // run locals if LIFO
+                (w.currentSteal = t).doExec();
+                w.currentSteal = ps;
+            }
+            else if ((q = findNonEmptyStealQueue()) != null) {
+                if (!active) {      // re-establish active count
+                    active = true;
+                    U.getAndAddLong(this, CTL, AC_UNIT);
+                }
+                if ((t = q.pollAt(q.base)) != null) {
+                    (w.currentSteal = t).doExec();
+                    w.currentSteal = ps;
+                    if (++w.nsteals < 0)
+                        w.transferStealCount(this);
+                }
+            }
+            else if (active) {      // decrement active count without queuing
+                long nc = (AC_MASK & ((c = ctl) - AC_UNIT)) | (~AC_MASK & c);
+                if (U.compareAndSwapLong(this, CTL, c, nc))
+                    active = false;
+            }
+            else if ((int)((c = ctl) >> AC_SHIFT) + (config & SMASK) <= 0 &&
+                     U.compareAndSwapLong(this, CTL, c, c + AC_UNIT))
+                break;
+        }
+    }
+
+    /**
+     * Gets and removes a local or stolen task for the given worker.
+     *
+     * @return a task, if available
+     */
+    final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
+        for (ForkJoinTask<?> t;;) {
+            WorkQueue q;
+            if ((t = w.nextLocalTask()) != null)
+                return t;
+            if ((q = findNonEmptyStealQueue()) == null)
+                return null;
+            if ((t = q.pollAt(q.base)) != null)
+                return t;
+        }
+    }
+
+    /**
+     * Returns a cheap heuristic guide for task partitioning when
+     * programmers, frameworks, tools, or languages have little or no
+     * idea about task granularity.  In essence, by offering this
+     * method, we ask users only about tradeoffs in overhead vs
+     * expected throughput and its variance, rather than how finely to
+     * partition tasks.
+     *
+     * In a steady state strict (tree-structured) computation, each
+     * thread makes available for stealing enough tasks for other
+     * threads to remain active. Inductively, if all threads play by
+     * the same rules, each thread should make available only a
+     * constant number of tasks.
+     *
+     * The minimum useful constant is just 1. But using a value of 1
+     * would require immediate replenishment upon each steal to
+     * maintain enough tasks, which is infeasible.  Further,
+     * partitionings/granularities of offered tasks should minimize
+     * steal rates, which in general means that threads nearer the top
+     * of computation tree should generate more than those nearer the
+     * bottom. In perfect steady state, each thread is at
+     * approximately the same level of computation tree. However,
+     * producing extra tasks amortizes the uncertainty of progress and
+     * diffusion assumptions.
+     *
+     * So, users will want to use values larger (but not much larger)
+     * than 1 to both smooth over transient shortages and hedge
+     * against uneven progress; as traded off against the cost of
+     * extra task overhead. We leave the user to pick a threshold
+     * value to compare with the results of this call to guide
+     * decisions, but recommend values such as 3.
+     *
+     * When all threads are active, it is on average OK to estimate
+     * surplus strictly locally. In steady-state, if one thread is
+     * maintaining say 2 surplus tasks, then so are others. So we can
+     * just use estimated queue length.  However, this strategy alone
+     * leads to serious mis-estimates in some non-steady-state
+     * conditions (ramp-up, ramp-down, other stalls). We can detect
+     * many of these by further considering the number of "idle"
+     * threads, that are known to have zero queued tasks, so
+     * compensate by a factor of (#idle/#active) threads.
+     */
+    static int getSurplusQueuedTaskCount() {
+        Thread t; ForkJoinWorkerThread wt; ForkJoinPool pool; WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            int p = (pool = (wt = (ForkJoinWorkerThread)t).pool).config & SMASK;
+            int n = (q = wt.workQueue).top - q.base;
+            int a = (int)(pool.ctl >> AC_SHIFT) + p;
+            return n - (a > (p >>>= 1) ? 0 :
+                        a > (p >>>= 1) ? 1 :
+                        a > (p >>>= 1) ? 2 :
+                        a > (p >>>= 1) ? 4 :
+                        8);
+        }
+        return 0;
+    }
+
+    //  Termination
+
+    /**
+     * Possibly initiates and/or completes termination.
+     *
+     * @param now if true, unconditionally terminate, else only
+     * if no work and no active workers
+     * @param enable if true, terminate when next possible
+     * @return -1: terminating/terminated, 0: retry if internal caller, else 1
+     */
+    private int tryTerminate(boolean now, boolean enable) {
+        int rs; // 3 phases: try to set SHUTDOWN, then STOP, then TERMINATED
+
+        while ((rs = runState) >= 0) {
+            if (!enable || this == common)        // cannot shutdown
+                return 1;
+            else if (rs == 0)
+                tryInitialize(false);             // ensure initialized
+            else
+                U.compareAndSwapInt(this, RUNSTATE, rs, rs | SHUTDOWN);
+        }
+
+        if ((rs & STOP) == 0) {                   // try to initiate termination
+            if (!now) {                           // check quiescence
+                for (long oldSum = 0L;;) {        // repeat until stable
+                    WorkQueue[] ws; WorkQueue w; int b;
+                    long checkSum = ctl;
+                    if ((int)(checkSum >> AC_SHIFT) + (config & SMASK) > 0)
+                        return 0;                 // still active workers
+                    if ((ws = workQueues) != null) {
+                        for (int i = 0; i < ws.length; ++i) {
+                            if ((w = ws[i]) != null) {
+                                checkSum += (b = w.base);
+                                if (w.currentSteal != null || b != w.top)
+                                    return 0;     // retry if internal caller
+                            }
+                        }
+                    }
+                    if (oldSum == (oldSum = checkSum))
+                        break;
+                }
+            }
+            do {} while (!U.compareAndSwapInt(this, RUNSTATE,
+                                              rs = runState, rs | STOP));
+        }
+
+        for (long oldSum = 0L;;) {                // repeat until stable
+            WorkQueue[] ws; WorkQueue w; ForkJoinWorkerThread wt;
+            long checkSum = ctl;
+            if ((ws = workQueues) != null) {      // help terminate others
+                for (int i = 0; i < ws.length; ++i) {
+                    if ((w = ws[i]) != null) {
+                        w.cancelAll();            // clear queues
+                        checkSum += w.base;
+                        if (w.qlock >= 0) {
+                            w.qlock = -1;         // racy set OK
+                            if ((wt = w.owner) != null) {
+                                try {             // unblock join or park
+                                    wt.interrupt();
+                                } catch (Throwable ignore) {
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if (oldSum == (oldSum = checkSum))
+                break;
+        }
+
+        if ((short)(ctl >>> TC_SHIFT) + (config & SMASK) <= 0) {
+            runState = (STARTED | SHUTDOWN | STOP | TERMINATED); // final write
+            synchronized (this) {
+                notifyAll();                      // for awaitTermination
+            }
+        }
+
+        return -1;
+    }
+
+    // External operations
+
+    /**
+     * Constructs and tries to install a new external queue,
+     * failing if the workQueues array already has a queue at
+     * the given index.
+     *
+     * @param index the index of the new queue
+     */
+    private void tryCreateExternalQueue(int index) {
+        AuxState aux;
+        if ((aux = auxState) != null && index >= 0) {
+            WorkQueue q = new WorkQueue(this, null);
+            q.config = index;
+            q.scanState = ~UNSIGNALLED;
+            q.qlock = 1;                   // lock queue
+            boolean installed = false;
+            aux.lock();
+            try {                          // lock pool to install
+                WorkQueue[] ws;
+                if ((ws = workQueues) != null && index < ws.length &&
+                    ws[index] == null) {
+                    ws[index] = q;         // else throw away
+                    installed = true;
+                }
+            } finally {
+                aux.unlock();
+            }
+            if (installed) {
+                try {
+                    q.growArray();
+                } finally {
+                    q.qlock = 0;
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds the given task to a submission queue at submitter's
+     * current queue. Also performs secondary initialization upon the
+     * first submission of the first task to the pool, and detects
+     * first submission by an external thread and creates a new shared
+     * queue if the one at index if empty or contended.
+     *
+     * @param task the task. Caller must ensure non-null.
+     */
+    final void externalPush(ForkJoinTask<?> task) {
+        int r;                            // initialize caller's probe
+        if ((r = ThreadLocalRandom.getProbe()) == 0) {
+            ThreadLocalRandom.localInit();
+            r = ThreadLocalRandom.getProbe();
+        }
+        for (;;) {
+            WorkQueue q; int wl, k, stat;
+            int rs = runState;
+            WorkQueue[] ws = workQueues;
+            if (rs <= 0 || ws == null || (wl = ws.length) <= 0)
+                tryInitialize(true);
+            else if ((q = ws[k = (wl - 1) & r & SQMASK]) == null)
+                tryCreateExternalQueue(k);
+            else if ((stat = q.sharedPush(task)) < 0)
+                break;
+            else if (stat == 0) {
+                signalWork();
+                break;
+            }
+            else                          // move if busy
+                r = ThreadLocalRandom.advanceProbe(r);
+        }
+    }
+
+    /**
+     * Pushes a possibly-external submission.
+     */
+    private <T> ForkJoinTask<T> externalSubmit(ForkJoinTask<T> task) {
+        Thread t; ForkJoinWorkerThread w; WorkQueue q;
+        if (task == null)
+            throw new NullPointerException();
+        if (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) &&
+            (w = (ForkJoinWorkerThread)t).pool == this &&
+            (q = w.workQueue) != null)
+            q.push(task);
+        else
+            externalPush(task);
+        return task;
+    }
+
+    /**
+     * Returns common pool queue for an external thread.
+     */
+    static WorkQueue commonSubmitterQueue() {
+        ForkJoinPool p = common;
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; int wl;
+        return (p != null && (ws = p.workQueues) != null &&
+                (wl = ws.length) > 0) ?
+            ws[(wl - 1) & r & SQMASK] : null;
+    }
+
+    /**
+     * Performs tryUnpush for an external submitter.
+     */
+    final boolean tryExternalUnpush(ForkJoinTask<?> task) {
+        int r = ThreadLocalRandom.getProbe();
+        WorkQueue[] ws; WorkQueue w; int wl;
+        return ((ws = workQueues) != null &&
+                (wl = ws.length) > 0 &&
+                (w = ws[(wl - 1) & r & SQMASK]) != null &&
+                w.trySharedUnpush(task));
+    }
+
+    /**
+     * Performs helpComplete for an external submitter.
+     */
+    final int externalHelpComplete(CountedCompleter<?> task, int maxTasks) {
+        WorkQueue[] ws; int wl;
+        int r = ThreadLocalRandom.getProbe();
+        return ((ws = workQueues) != null && (wl = ws.length) > 0) ?
+            helpComplete(ws[(wl - 1) & r & SQMASK], task, maxTasks) : 0;
+    }
+
+    // Exported methods
+
+    // Constructors
+
+    /**
+     * Creates a {@code ForkJoinPool} with parallelism equal to {@link
+     * java.lang.Runtime#availableProcessors}, using the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     *
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool() {
+        this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
+             defaultForkJoinWorkerThreadFactory, null, false);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the indicated parallelism
+     * level, the {@linkplain
+     * #defaultForkJoinWorkerThreadFactory default thread factory},
+     * no UncaughtExceptionHandler, and non-async LIFO processing mode.
+     *
+     * @param parallelism the parallelism level
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool(int parallelism) {
+        this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters.
+     *
+     * @param parallelism the parallelism level. For default value,
+     * use {@link java.lang.Runtime#availableProcessors}.
+     * @param factory the factory for creating new threads. For default value,
+     * use {@link #defaultForkJoinWorkerThreadFactory}.
+     * @param handler the handler for internal worker threads that
+     * terminate due to unrecoverable errors encountered while executing
+     * tasks. For default value, use {@code null}.
+     * @param asyncMode if true,
+     * establishes local first-in-first-out scheduling mode for forked
+     * tasks that are never joined. This mode may be more appropriate
+     * than default locally stack-based mode in applications in which
+     * worker threads only process event-style asynchronous tasks.
+     * For default value, use {@code false}.
+     * @throws IllegalArgumentException if parallelism less than or
+     *         equal to zero, or greater than implementation limit
+     * @throws NullPointerException if the factory is null
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public ForkJoinPool(int parallelism,
+                        ForkJoinWorkerThreadFactory factory,
+                        UncaughtExceptionHandler handler,
+                        boolean asyncMode) {
+        this(checkParallelism(parallelism),
+             checkFactory(factory),
+             handler,
+             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
+             "ForkJoinPool-" + nextPoolId() + "-worker-");
+        checkPermission();
+    }
+
+    private static int checkParallelism(int parallelism) {
+        if (parallelism <= 0 || parallelism > MAX_CAP)
+            throw new IllegalArgumentException();
+        return parallelism;
+    }
+
+    private static ForkJoinWorkerThreadFactory checkFactory
+        (ForkJoinWorkerThreadFactory factory) {
+        if (factory == null)
+            throw new NullPointerException();
+        return factory;
+    }
+
+    /**
+     * Creates a {@code ForkJoinPool} with the given parameters, without
+     * any security checks or parameter validation.  Invoked directly by
+     * makeCommonPool.
+     */
+    private ForkJoinPool(int parallelism,
+                         ForkJoinWorkerThreadFactory factory,
+                         UncaughtExceptionHandler handler,
+                         int mode,
+                         String workerNamePrefix) {
+        this.workerNamePrefix = workerNamePrefix;
+        this.factory = factory;
+        this.ueh = handler;
+        this.config = (parallelism & SMASK) | mode;
+        long np = (long)(-parallelism); // offset ctl counts
+        this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
+    }
+
+    /**
+     * Returns the common pool instance. This pool is statically
+     * constructed; its run state is unaffected by attempts to {@link
+     * #shutdown} or {@link #shutdownNow}. However this pool and any
+     * ongoing processing are automatically terminated upon program
+     * {@link System#exit}.  Any program that relies on asynchronous
+     * task processing to complete before program termination should
+     * invoke {@code commonPool().}{@link #awaitQuiescence awaitQuiescence},
+     * before exit.
+     *
+     * @return the common pool instance
+     * @since 1.8
+     */
+    public static ForkJoinPool commonPool() {
+        // assert common != null : "static init error";
+        return common;
+    }
+
+    // Execution methods
+
+    /**
+     * Performs the given task, returning its result upon completion.
+     * If the computation encounters an unchecked Exception or Error,
+     * it is rethrown as the outcome of this invocation.  Rethrown
+     * exceptions behave in the same way as regular exceptions, but,
+     * when possible, contain stack traces (as displayed for example
+     * using {@code ex.printStackTrace()}) of both the current thread
+     * as well as the thread actually encountering the exception;
+     * minimally only the latter.
+     *
+     * @param task the task
+     * @param <T> the type of the task's result
+     * @return the task's result
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> T invoke(ForkJoinTask<T> task) {
+        if (task == null)
+            throw new NullPointerException();
+        externalSubmit(task);
+        return task.join();
+    }
+
+    /**
+     * Arranges for (asynchronous) execution of the given task.
+     *
+     * @param task the task
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public void execute(ForkJoinTask<?> task) {
+        externalSubmit(task);
+    }
+
+    // AbstractExecutorService methods
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public void execute(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = new ForkJoinTask.RunnableExecuteAction(task);
+        externalSubmit(job);
+    }
+
+    /**
+     * Submits a ForkJoinTask for execution.
+     *
+     * @param task the task to submit
+     * @param <T> the type of the task's result
+     * @return the task
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
+        return externalSubmit(task);
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(Callable<T> task) {
+        return externalSubmit(new ForkJoinTask.AdaptedCallable<T>(task));
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public <T> ForkJoinTask<T> submit(Runnable task, T result) {
+        return externalSubmit(new ForkJoinTask.AdaptedRunnable<T>(task, result));
+    }
+
+    /**
+     * @throws NullPointerException if the task is null
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     */
+    public ForkJoinTask<?> submit(Runnable task) {
+        if (task == null)
+            throw new NullPointerException();
+        ForkJoinTask<?> job;
+        if (task instanceof ForkJoinTask<?>) // avoid re-wrap
+            job = (ForkJoinTask<?>) task;
+        else
+            job = new ForkJoinTask.AdaptedRunnableAction(task);
+        return externalSubmit(job);
+    }
+
+    /**
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws RejectedExecutionException {@inheritDoc}
+     */
+    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
+        // In previous versions of this class, this method constructed
+        // a task to run ForkJoinTask.invokeAll, but now external
+        // invocation of multiple tasks is at least as efficient.
+        ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
+
+        try {
+            for (Callable<T> t : tasks) {
+                ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
+                futures.add(f);
+                externalSubmit(f);
+            }
+            for (int i = 0, size = futures.size(); i < size; i++)
+                ((ForkJoinTask<?>)futures.get(i)).quietlyJoin();
+            return futures;
+        } catch (Throwable t) {
+            for (int i = 0, size = futures.size(); i < size; i++)
+                futures.get(i).cancel(false);
+            throw t;
+        }
+    }
+
+    /**
+     * Returns the factory used for constructing new workers.
+     *
+     * @return the factory used for constructing new workers
+     */
+    public ForkJoinWorkerThreadFactory getFactory() {
+        return factory;
+    }
+
+    /**
+     * Returns the handler for internal worker threads that terminate
+     * due to unrecoverable errors encountered while executing tasks.
+     *
+     * @return the handler, or {@code null} if none
+     */
+    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+        return ueh;
+    }
+
+    /**
+     * Returns the targeted parallelism level of this pool.
+     *
+     * @return the targeted parallelism level of this pool
+     */
+    public int getParallelism() {
+        int par;
+        return ((par = config & SMASK) > 0) ? par : 1;
+    }
+
+    /**
+     * Returns the targeted parallelism level of the common pool.
+     *
+     * @return the targeted parallelism level of the common pool
+     * @since 1.8
+     */
+    public static int getCommonPoolParallelism() {
+        return COMMON_PARALLELISM;
+    }
+
+    /**
+     * Returns the number of worker threads that have started but not
+     * yet terminated.  The result returned by this method may differ
+     * from {@link #getParallelism} when threads are created to
+     * maintain parallelism when others are cooperatively blocked.
+     *
+     * @return the number of worker threads
+     */
+    public int getPoolSize() {
+        return (config & SMASK) + (short)(ctl >>> TC_SHIFT);
+    }
+
+    /**
+     * Returns {@code true} if this pool uses local first-in-first-out
+     * scheduling mode for forked tasks that are never joined.
+     *
+     * @return {@code true} if this pool uses async mode
+     */
+    public boolean getAsyncMode() {
+        return (config & FIFO_QUEUE) != 0;
+    }
+
+    /**
+     * Returns an estimate of the number of worker threads that are
+     * not blocked waiting to join tasks or for other managed
+     * synchronization. This method may overestimate the
+     * number of running threads.
+     *
+     * @return the number of worker threads
+     */
+    public int getRunningThreadCount() {
+        int rc = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && w.isApparentlyUnblocked())
+                    ++rc;
+            }
+        }
+        return rc;
+    }
+
+    /**
+     * Returns an estimate of the number of threads that are currently
+     * stealing or executing tasks. This method may overestimate the
+     * number of active threads.
+     *
+     * @return the number of active threads
+     */
+    public int getActiveThreadCount() {
+        int r = (config & SMASK) + (int)(ctl >> AC_SHIFT);
+        return (r <= 0) ? 0 : r; // suppress momentarily negative values
+    }
+
+    /**
+     * Returns {@code true} if all worker threads are currently idle.
+     * An idle worker is one that cannot obtain a task to execute
+     * because none are available to steal from other threads, and
+     * there are no pending submissions to the pool. This method is
+     * conservative; it might not return {@code true} immediately upon
+     * idleness of all threads, but will eventually become true if
+     * threads remain inactive.
+     *
+     * @return {@code true} if all threads are currently idle
+     */
+    public boolean isQuiescent() {
+        return (config & SMASK) + (int)(ctl >> AC_SHIFT) <= 0;
+    }
+
+    /**
+     * Returns an estimate of the total number of tasks stolen from
+     * one thread's work queue by another. The reported value
+     * underestimates the actual total number of steals when the pool
+     * is not quiescent. This value may be useful for monitoring and
+     * tuning fork/join programs: in general, steal counts should be
+     * high enough to keep threads busy, but low enough to avoid
+     * overhead and contention across threads.
+     *
+     * @return the number of steals
+     */
+    public long getStealCount() {
+        AuxState sc = auxState;
+        long count = (sc == null) ? 0L : sc.stealCount;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.nsteals;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns an estimate of the total number of tasks currently held
+     * in queues by worker threads (but not including tasks submitted
+     * to the pool that have not begun executing). This value is only
+     * an approximation, obtained by iterating across all threads in
+     * the pool. This method may be useful for tuning task
+     * granularities.
+     *
+     * @return the number of queued tasks
+     */
+    public long getQueuedTaskCount() {
+        long count = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 1; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.queueSize();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns an estimate of the number of tasks submitted to this
+     * pool that have not yet begun executing.  This method may take
+     * time proportional to the number of submissions.
+     *
+     * @return the number of queued submissions
+     */
+    public int getQueuedSubmissionCount() {
+        int count = 0;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null)
+                    count += w.queueSize();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns {@code true} if there are any tasks submitted to this
+     * pool that have not yet begun executing.
+     *
+     * @return {@code true} if there are any queued submissions
+     */
+    public boolean hasQueuedSubmissions() {
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; i += 2) {
+                if ((w = ws[i]) != null && !w.isEmpty())
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Removes and returns the next unexecuted submission if one is
+     * available.  This method may be useful in extensions to this
+     * class that re-assign work in systems with multiple pools.
+     *
+     * @return the next submission, or {@code null} if none
+     */
+    protected ForkJoinTask<?> pollSubmission() {
+        WorkQueue[] ws; int wl; WorkQueue w; ForkJoinTask<?> t;
+        int r = ThreadLocalRandom.nextSecondarySeed();
+        if ((ws = workQueues) != null && (wl = ws.length) > 0) {
+            for (int m = wl - 1, i = 0; i < wl; ++i) {
+                if ((w = ws[(i << 1) & m]) != null && (t = w.poll()) != null)
+                    return t;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Removes all available unexecuted submitted and forked tasks
+     * from scheduling queues and adds them to the given collection,
+     * without altering their execution status. These may include
+     * artificially generated or wrapped tasks. This method is
+     * designed to be invoked only when the pool is known to be
+     * quiescent. Invocations at other times may not remove all
+     * tasks. A failure encountered while attempting to add elements
+     * to collection {@code c} may result in elements being in
+     * neither, either or both collections when the associated
+     * exception is thrown.  The behavior of this operation is
+     * undefined if the specified collection is modified while the
+     * operation is in progress.
+     *
+     * @param c the collection to transfer elements into
+     * @return the number of elements transferred
+     */
+    protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+        int count = 0;
+        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; ++i) {
+                if ((w = ws[i]) != null) {
+                    while ((t = w.poll()) != null) {
+                        c.add(t);
+                        ++count;
+                    }
+                }
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns a string identifying this pool, as well as its state,
+     * including indications of run state, parallelism level, and
+     * worker and task counts.
+     *
+     * @return a string identifying this pool, as well as its state
+     */
+    public String toString() {
+        // Use a single pass through workQueues to collect counts
+        long qt = 0L, qs = 0L; int rc = 0;
+        AuxState sc = auxState;
+        long st = (sc == null) ? 0L : sc.stealCount;
+        long c = ctl;
+        WorkQueue[] ws; WorkQueue w;
+        if ((ws = workQueues) != null) {
+            for (int i = 0; i < ws.length; ++i) {
+                if ((w = ws[i]) != null) {
+                    int size = w.queueSize();
+                    if ((i & 1) == 0)
+                        qs += size;
+                    else {
+                        qt += size;
+                        st += w.nsteals;
+                        if (w.isApparentlyUnblocked())
+                            ++rc;
+                    }
+                }
+            }
+        }
+        int pc = (config & SMASK);
+        int tc = pc + (short)(c >>> TC_SHIFT);
+        int ac = pc + (int)(c >> AC_SHIFT);
+        if (ac < 0) // ignore transient negative
+            ac = 0;
+        int rs = runState;
+        String level = ((rs & TERMINATED) != 0 ? "Terminated" :
+                        (rs & STOP)       != 0 ? "Terminating" :
+                        (rs & SHUTDOWN)   != 0 ? "Shutting down" :
+                        "Running");
+        return super.toString() +
+            "[" + level +
+            ", parallelism = " + pc +
+            ", size = " + tc +
+            ", active = " + ac +
+            ", running = " + rc +
+            ", steals = " + st +
+            ", tasks = " + qt +
+            ", submissions = " + qs +
+            "]";
+    }
+
+    /**
+     * Possibly initiates an orderly shutdown in which previously
+     * submitted tasks are executed, but no new tasks will be
+     * accepted. Invocation has no effect on execution state if this
+     * is the {@link #commonPool()}, and no additional effect if
+     * already shut down.  Tasks that are in the process of being
+     * submitted concurrently during the course of this method may or
+     * may not be rejected.
+     *
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public void shutdown() {
+        checkPermission();
+        tryTerminate(false, true);
+    }
+
+    /**
+     * Possibly attempts to cancel and/or stop all tasks, and reject
+     * all subsequently submitted tasks.  Invocation has no effect on
+     * execution state if this is the {@link #commonPool()}, and no
+     * additional effect if already shut down. Otherwise, tasks that
+     * are in the process of being submitted or executed concurrently
+     * during the course of this method may or may not be
+     * rejected. This method cancels both existing and unexecuted
+     * tasks, in order to permit termination in the presence of task
+     * dependencies. So the method always returns an empty list
+     * (unlike the case for some other Executors).
+     *
+     * @return an empty list
+     * @throws SecurityException if a security manager exists and
+     *         the caller is not permitted to modify threads
+     *         because it does not hold {@link
+     *         java.lang.RuntimePermission}{@code ("modifyThread")}
+     */
+    public List<Runnable> shutdownNow() {
+        checkPermission();
+        tryTerminate(true, true);
+        return Collections.emptyList();
+    }
+
+    /**
+     * Returns {@code true} if all tasks have completed following shut down.
+     *
+     * @return {@code true} if all tasks have completed following shut down
+     */
+    public boolean isTerminated() {
+        return (runState & TERMINATED) != 0;
+    }
+
+    /**
+     * Returns {@code true} if the process of termination has
+     * commenced but not yet completed.  This method may be useful for
+     * debugging. A return of {@code true} reported a sufficient
+     * period after shutdown may indicate that submitted tasks have
+     * ignored or suppressed interruption, or are waiting for I/O,
+     * causing this executor not to properly terminate. (See the
+     * advisory notes for class {@link ForkJoinTask} stating that
+     * tasks should not normally entail blocking operations.  But if
+     * they do, they must abort them on interrupt.)
+     *
+     * @return {@code true} if terminating but not yet terminated
+     */
+    public boolean isTerminating() {
+        int rs = runState;
+        return (rs & STOP) != 0 && (rs & TERMINATED) == 0;
+    }
+
+    /**
+     * Returns {@code true} if this pool has been shut down.
+     *
+     * @return {@code true} if this pool has been shut down
+     */
+    public boolean isShutdown() {
+        return (runState & SHUTDOWN) != 0;
+    }
+
+    /**
+     * Blocks until all tasks have completed execution after a
+     * shutdown request, or the timeout occurs, or the current thread
+     * is interrupted, whichever happens first. Because the {@link
+     * #commonPool()} never terminates until program shutdown, when
+     * applied to the common pool, this method is equivalent to {@link
+     * #awaitQuiescence(long, TimeUnit)} but always returns {@code false}.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if this executor terminated and
+     *         {@code false} if the timeout elapsed before termination
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (this == common) {
+            awaitQuiescence(timeout, unit);
+            return false;
+        }
+        long nanos = unit.toNanos(timeout);
+        if (isTerminated())
+            return true;
+        if (nanos <= 0L)
+            return false;
+        long deadline = System.nanoTime() + nanos;
+        synchronized (this) {
+            for (;;) {
+                if (isTerminated())
+                    return true;
+                if (nanos <= 0L)
+                    return false;
+                long millis = TimeUnit.NANOSECONDS.toMillis(nanos);
+                wait(millis > 0L ? millis : 1L);
+                nanos = deadline - System.nanoTime();
+            }
+        }
+    }
+
+    /**
+     * If called by a ForkJoinTask operating in this pool, equivalent
+     * in effect to {@link ForkJoinTask#helpQuiesce}. Otherwise,
+     * waits and/or attempts to assist performing tasks until this
+     * pool {@link #isQuiescent} or the indicated timeout elapses.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if quiescent; {@code false} if the
+     * timeout elapsed.
+     */
+    public boolean awaitQuiescence(long timeout, TimeUnit unit) {
+        long nanos = unit.toNanos(timeout);
+        ForkJoinWorkerThread wt;
+        Thread thread = Thread.currentThread();
+        if ((thread instanceof ForkJoinWorkerThread) &&
+            (wt = (ForkJoinWorkerThread)thread).pool == this) {
+            helpQuiescePool(wt.workQueue);
+            return true;
+        }
+        long startTime = System.nanoTime();
+        WorkQueue[] ws;
+        int r = 0, wl;
+        boolean found = true;
+        while (!isQuiescent() && (ws = workQueues) != null &&
+               (wl = ws.length) > 0) {
+            if (!found) {
+                if ((System.nanoTime() - startTime) > nanos)
+                    return false;
+                Thread.yield(); // cannot block
+            }
+            found = false;
+            for (int m = wl - 1, j = (m + 1) << 2; j >= 0; --j) {
+                ForkJoinTask<?> t; WorkQueue q; int b, k;
+                if ((k = r++ & m) <= m && k >= 0 && (q = ws[k]) != null &&
+                    (b = q.base) - q.top < 0) {
+                    found = true;
+                    if ((t = q.pollAt(b)) != null)
+                        t.doExec();
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Waits and/or attempts to assist performing tasks indefinitely
+     * until the {@link #commonPool()} {@link #isQuiescent}.
+     */
+    static void quiesceCommonPool() {
+        common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+    }
+
+    /**
+     * Interface for extending managed parallelism for tasks running
+     * in {@link ForkJoinPool}s.
+     *
+     * <p>A {@code ManagedBlocker} provides two methods.  Method
+     * {@link #isReleasable} must return {@code true} if blocking is
+     * not necessary. Method {@link #block} blocks the current thread
+     * if necessary (perhaps internally invoking {@code isReleasable}
+     * before actually blocking). These actions are performed by any
+     * thread invoking {@link ForkJoinPool#managedBlock(ManagedBlocker)}.
+     * The unusual methods in this API accommodate synchronizers that
+     * may, but don't usually, block for long periods. Similarly, they
+     * allow more efficient internal handling of cases in which
+     * additional workers may be, but usually are not, needed to
+     * ensure sufficient parallelism.  Toward this end,
+     * implementations of method {@code isReleasable} must be amenable
+     * to repeated invocation.
+     *
+     * <p>For example, here is a ManagedBlocker based on a
+     * ReentrantLock:
+     * <pre> {@code
+     * class ManagedLocker implements ManagedBlocker {
+     *   final ReentrantLock lock;
+     *   boolean hasLock = false;
+     *   ManagedLocker(ReentrantLock lock) { this.lock = lock; }
+     *   public boolean block() {
+     *     if (!hasLock)
+     *       lock.lock();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return hasLock || (hasLock = lock.tryLock());
+     *   }
+     * }}</pre>
+     *
+     * <p>Here is a class that possibly blocks waiting for an
+     * item on a given queue:
+     * <pre> {@code
+     * class QueueTaker<E> implements ManagedBlocker {
+     *   final BlockingQueue<E> queue;
+     *   volatile E item = null;
+     *   QueueTaker(BlockingQueue<E> q) { this.queue = q; }
+     *   public boolean block() throws InterruptedException {
+     *     if (item == null)
+     *       item = queue.take();
+     *     return true;
+     *   }
+     *   public boolean isReleasable() {
+     *     return item != null || (item = queue.poll()) != null;
+     *   }
+     *   public E getItem() { // call after pool.managedBlock completes
+     *     return item;
+     *   }
+     * }}</pre>
+     */
+    public static interface ManagedBlocker {
+        /**
+         * Possibly blocks the current thread, for example waiting for
+         * a lock or condition.
+         *
+         * @return {@code true} if no additional blocking is necessary
+         * (i.e., if isReleasable would return true)
+         * @throws InterruptedException if interrupted while waiting
+         * (the method is not required to do so, but is allowed to)
+         */
+        boolean block() throws InterruptedException;
+
+        /**
+         * Returns {@code true} if blocking is unnecessary.
+         * @return {@code true} if blocking is unnecessary
+         */
+        boolean isReleasable();
+    }
+
+    /**
+     * Runs the given possibly blocking task.  When {@linkplain
+     * ForkJoinTask#inForkJoinPool() running in a ForkJoinPool}, this
+     * method possibly arranges for a spare thread to be activated if
+     * necessary to ensure sufficient parallelism while the current
+     * thread is blocked in {@link ManagedBlocker#block blocker.block()}.
+     *
+     * <p>This method repeatedly calls {@code blocker.isReleasable()} and
+     * {@code blocker.block()} until either method returns {@code true}.
+     * Every call to {@code blocker.block()} is preceded by a call to
+     * {@code blocker.isReleasable()} that returned {@code false}.
+     *
+     * <p>If not running in a ForkJoinPool, this method is
+     * behaviorally equivalent to
+     * <pre> {@code
+     * while (!blocker.isReleasable())
+     *   if (blocker.block())
+     *     break;}</pre>
+     *
+     * If running in a ForkJoinPool, the pool may first be expanded to
+     * ensure sufficient parallelism available during the call to
+     * {@code blocker.block()}.
+     *
+     * @param blocker the blocker task
+     * @throws InterruptedException if {@code blocker.block()} did so
+     */
+    public static void managedBlock(ManagedBlocker blocker)
+        throws InterruptedException {
+        ForkJoinPool p;
+        ForkJoinWorkerThread wt;
+        Thread t = Thread.currentThread();
+        if ((t instanceof ForkJoinWorkerThread) &&
+            (p = (wt = (ForkJoinWorkerThread)t).pool) != null) {
+            WorkQueue w = wt.workQueue;
+            while (!blocker.isReleasable()) {
+                if (p.tryCompensate(w)) {
+                    try {
+                        do {} while (!blocker.isReleasable() &&
+                                     !blocker.block());
+                    } finally {
+                        U.getAndAddLong(p, CTL, AC_UNIT);
+                    }
+                    break;
+                }
+            }
+        }
+        else {
+            do {} while (!blocker.isReleasable() &&
+                         !blocker.block());
+        }
+    }
+
+    // AbstractExecutorService overrides.  These rely on undocumented
+    // fact that ForkJoinTask.adapt returns ForkJoinTasks that also
+    // implement RunnableFuture.
+
+    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
+        return new ForkJoinTask.AdaptedRunnable<T>(runnable, value);
+    }
+
+    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
+        return new ForkJoinTask.AdaptedCallable<T>(callable);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long CTL;
+    private static final long RUNSTATE;
+    private static final int ABASE;
+    private static final int ASHIFT;
+
+    static {
+        try {
+            CTL = U.objectFieldOffset
+                (ForkJoinPool.class.getDeclaredField("ctl"));
+            RUNSTATE = U.objectFieldOffset
+                (ForkJoinPool.class.getDeclaredField("runState"));
+            ABASE = U.arrayBaseOffset(ForkJoinTask[].class);
+            int scale = U.arrayIndexScale(ForkJoinTask[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+
+        int commonMaxSpares = DEFAULT_COMMON_MAX_SPARES;
+        try {
+            String p = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.maximumSpares");
+            if (p != null)
+                commonMaxSpares = Integer.parseInt(p);
+        } catch (Exception ignore) {}
+        COMMON_MAX_SPARES = commonMaxSpares;
+
+        defaultForkJoinWorkerThreadFactory =
+            new DefaultForkJoinWorkerThreadFactory();
+        modifyThreadPermission = new RuntimePermission("modifyThread");
+
+        common = java.security.AccessController.doPrivileged
+            (new java.security.PrivilegedAction<ForkJoinPool>() {
+                public ForkJoinPool run() { return makeCommonPool(); }});
+
+        // report 1 even if threads disabled
+        COMMON_PARALLELISM = Math.max(common.config & SMASK, 1);
+    }
+
+    /**
+     * Creates and returns the common pool, respecting user settings
+     * specified via system properties.
+     */
+    static ForkJoinPool makeCommonPool() {
+        int parallelism = -1;
+        ForkJoinWorkerThreadFactory factory = null;
+        UncaughtExceptionHandler handler = null;
+        try {  // ignore exceptions in accessing/parsing properties
+            String pp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.parallelism");
+            String fp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.threadFactory");
+            String hp = System.getProperty
+                ("java.util.concurrent.ForkJoinPool.common.exceptionHandler");
+            if (pp != null)
+                parallelism = Integer.parseInt(pp);
+            if (fp != null)
+                factory = ((ForkJoinWorkerThreadFactory)ClassLoader.
+                           getSystemClassLoader().loadClass(fp).newInstance());
+            if (hp != null)
+                handler = ((UncaughtExceptionHandler)ClassLoader.
+                           getSystemClassLoader().loadClass(hp).newInstance());
+        } catch (Exception ignore) {
+        }
+        if (factory == null) {
+            if (System.getSecurityManager() == null)
+                factory = defaultForkJoinWorkerThreadFactory;
+            else // use security-managed default
+                factory = new InnocuousForkJoinWorkerThreadFactory();
+        }
+        if (parallelism < 0 && // default 1 less than #cores
+            (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)
+            parallelism = 1;
+        if (parallelism > MAX_CAP)
+            parallelism = MAX_CAP;
+        return new ForkJoinPool(parallelism, factory, handler, LIFO_QUEUE,
+                                "ForkJoinPool.commonPool-worker-");
+    }
+
+    /**
+     * Factory for innocuous worker threads.
+     */
+    private static final class InnocuousForkJoinWorkerThreadFactory
+        implements ForkJoinWorkerThreadFactory {
+
+        /**
+         * An ACC to restrict permissions for the factory itself.
+         * The constructed workers have no permissions set.
+         */
+        private static final AccessControlContext innocuousAcc;
+        static {
+            Permissions innocuousPerms = new Permissions();
+            innocuousPerms.add(modifyThreadPermission);
+            innocuousPerms.add(new RuntimePermission(
+                                   "enableContextClassLoaderOverride"));
+            innocuousPerms.add(new RuntimePermission(
+                                   "modifyThreadGroup"));
+            innocuousAcc = new AccessControlContext(new ProtectionDomain[] {
+                    new ProtectionDomain(null, innocuousPerms)
+                });
+        }
+
+        public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+            return java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<ForkJoinWorkerThread>() {
+                    public ForkJoinWorkerThread run() {
+                        return new ForkJoinWorkerThread.
+                            InnocuousForkJoinWorkerThread(pool);
+                    }}, innocuousAcc);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/ForkJoinTask.java b/java/util/concurrent/ForkJoinTask.java
new file mode 100644
index 0000000..efccfa5
--- /dev/null
+++ b/java/util/concurrent/ForkJoinTask.java
@@ -0,0 +1,1534 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.Serializable;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.util.Collection;
+import java.util.List;
+import java.util.RandomAccess;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed java 9 code
+// END android-note
+
+/**
+ * Abstract base class for tasks that run within a {@link ForkJoinPool}.
+ * A {@code ForkJoinTask} is a thread-like entity that is much
+ * lighter weight than a normal thread.  Huge numbers of tasks and
+ * subtasks may be hosted by a small number of actual threads in a
+ * ForkJoinPool, at the price of some usage limitations.
+ *
+ * <p>A "main" {@code ForkJoinTask} begins execution when it is
+ * explicitly submitted to a {@link ForkJoinPool}, or, if not already
+ * engaged in a ForkJoin computation, commenced in the {@link
+ * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * related methods.  Once started, it will usually in turn start other
+ * subtasks.  As indicated by the name of this class, many programs
+ * using {@code ForkJoinTask} employ only methods {@link #fork} and
+ * {@link #join}, or derivatives such as {@link
+ * #invokeAll(ForkJoinTask...) invokeAll}.  However, this class also
+ * provides a number of other methods that can come into play in
+ * advanced usages, as well as extension mechanics that allow support
+ * of new forms of fork/join processing.
+ *
+ * <p>A {@code ForkJoinTask} is a lightweight form of {@link Future}.
+ * The efficiency of {@code ForkJoinTask}s stems from a set of
+ * restrictions (that are only partially statically enforceable)
+ * reflecting their main use as computational tasks calculating pure
+ * functions or operating on purely isolated objects.  The primary
+ * coordination mechanisms are {@link #fork}, that arranges
+ * asynchronous execution, and {@link #join}, that doesn't proceed
+ * until the task's result has been computed.  Computations should
+ * ideally avoid {@code synchronized} methods or blocks, and should
+ * minimize other blocking synchronization apart from joining other
+ * tasks or using synchronizers such as Phasers that are advertised to
+ * cooperate with fork/join scheduling. Subdividable tasks should also
+ * not perform blocking I/O, and should ideally access variables that
+ * are completely independent of those accessed by other running
+ * tasks. These guidelines are loosely enforced by not permitting
+ * checked exceptions such as {@code IOExceptions} to be
+ * thrown. However, computations may still encounter unchecked
+ * exceptions, that are rethrown to callers attempting to join
+ * them. These exceptions may additionally include {@link
+ * RejectedExecutionException} stemming from internal resource
+ * exhaustion, such as failure to allocate internal task
+ * queues. Rethrown exceptions behave in the same way as regular
+ * exceptions, but, when possible, contain stack traces (as displayed
+ * for example using {@code ex.printStackTrace()}) of both the thread
+ * that initiated the computation as well as the thread actually
+ * encountering the exception; minimally only the latter.
+ *
+ * <p>It is possible to define and use ForkJoinTasks that may block,
+ * but doing do requires three further considerations: (1) Completion
+ * of few if any <em>other</em> tasks should be dependent on a task
+ * that blocks on external synchronization or I/O. Event-style async
+ * tasks that are never joined (for example, those subclassing {@link
+ * CountedCompleter}) often fall into this category.  (2) To minimize
+ * resource impact, tasks should be small; ideally performing only the
+ * (possibly) blocking action. (3) Unless the {@link
+ * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
+ * blocked tasks is known to be less than the pool's {@link
+ * ForkJoinPool#getParallelism} level, the pool cannot guarantee that
+ * enough threads will be available to ensure progress or good
+ * performance.
+ *
+ * <p>The primary method for awaiting completion and extracting
+ * results of a task is {@link #join}, but there are several variants:
+ * The {@link Future#get} methods support interruptible and/or timed
+ * waits for completion and report results using {@code Future}
+ * conventions. Method {@link #invoke} is semantically
+ * equivalent to {@code fork(); join()} but always attempts to begin
+ * execution in the current thread. The "<em>quiet</em>" forms of
+ * these methods do not extract results or report exceptions. These
+ * may be useful when a set of tasks are being executed, and you need
+ * to delay processing of results or exceptions until all complete.
+ * Method {@code invokeAll} (available in multiple versions)
+ * performs the most common form of parallel invocation: forking a set
+ * of tasks and joining them all.
+ *
+ * <p>In the most typical usages, a fork-join pair act like a call
+ * (fork) and return (join) from a parallel recursive function. As is
+ * the case with other forms of recursive calls, returns (joins)
+ * should be performed innermost-first. For example, {@code a.fork();
+ * b.fork(); b.join(); a.join();} is likely to be substantially more
+ * efficient than joining {@code a} before {@code b}.
+ *
+ * <p>The execution status of tasks may be queried at several levels
+ * of detail: {@link #isDone} is true if a task completed in any way
+ * (including the case where a task was cancelled without executing);
+ * {@link #isCompletedNormally} is true if a task completed without
+ * cancellation or encountering an exception; {@link #isCancelled} is
+ * true if the task was cancelled (in which case {@link #getException}
+ * returns a {@link java.util.concurrent.CancellationException}); and
+ * {@link #isCompletedAbnormally} is true if a task was either
+ * cancelled or encountered an exception, in which case {@link
+ * #getException} will return either the encountered exception or
+ * {@link java.util.concurrent.CancellationException}.
+ *
+ * <p>The ForkJoinTask class is not usually directly subclassed.
+ * Instead, you subclass one of the abstract classes that support a
+ * particular style of fork/join processing, typically {@link
+ * RecursiveAction} for most computations that do not return results,
+ * {@link RecursiveTask} for those that do, and {@link
+ * CountedCompleter} for those in which completed actions trigger
+ * other actions.  Normally, a concrete ForkJoinTask subclass declares
+ * fields comprising its parameters, established in a constructor, and
+ * then defines a {@code compute} method that somehow uses the control
+ * methods supplied by this base class.
+ *
+ * <p>Method {@link #join} and its variants are appropriate for use
+ * only when completion dependencies are acyclic; that is, the
+ * parallel computation can be described as a directed acyclic graph
+ * (DAG). Otherwise, executions may encounter a form of deadlock as
+ * tasks cyclically wait for each other.  However, this framework
+ * supports other methods and techniques (for example the use of
+ * {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
+ * may be of use in constructing custom subclasses for problems that
+ * are not statically structured as DAGs. To support such usages, a
+ * ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
+ * value using {@link #setForkJoinTaskTag} or {@link
+ * #compareAndSetForkJoinTaskTag} and checked using {@link
+ * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * these {@code protected} methods or tags for any purpose, but they
+ * may be of use in the construction of specialized subclasses.  For
+ * example, parallel graph traversals can use the supplied methods to
+ * avoid revisiting nodes/tasks that have already been processed.
+ * (Method names for tagging are bulky in part to encourage definition
+ * of methods that reflect their usage patterns.)
+ *
+ * <p>Most base support methods are {@code final}, to prevent
+ * overriding of implementations that are intrinsically tied to the
+ * underlying lightweight task scheduling framework.  Developers
+ * creating new basic styles of fork/join processing should minimally
+ * implement {@code protected} methods {@link #exec}, {@link
+ * #setRawResult}, and {@link #getRawResult}, while also introducing
+ * an abstract computational method that can be implemented in its
+ * subclasses, possibly relying on other {@code protected} methods
+ * provided by this class.
+ *
+ * <p>ForkJoinTasks should perform relatively small amounts of
+ * computation. Large tasks should be split into smaller subtasks,
+ * usually via recursive decomposition. As a very rough rule of thumb,
+ * a task should perform more than 100 and less than 10000 basic
+ * computational steps, and should avoid indefinite looping. If tasks
+ * are too big, then parallelism cannot improve throughput. If too
+ * small, then memory and internal task maintenance overhead may
+ * overwhelm processing.
+ *
+ * <p>This class provides {@code adapt} methods for {@link Runnable}
+ * and {@link Callable}, that may be of use when mixing execution of
+ * {@code ForkJoinTasks} with other kinds of tasks. When all tasks are
+ * of this form, consider using a pool constructed in <em>asyncMode</em>.
+ *
+ * <p>ForkJoinTasks are {@code Serializable}, which enables them to be
+ * used in extensions such as remote execution frameworks. It is
+ * sensible to serialize tasks only before or after, but not during,
+ * execution. Serialization is not relied on during execution itself.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
+
+    /*
+     * See the internal documentation of class ForkJoinPool for a
+     * general implementation overview.  ForkJoinTasks are mainly
+     * responsible for maintaining their "status" field amidst relays
+     * to methods in ForkJoinWorkerThread and ForkJoinPool.
+     *
+     * The methods of this class are more-or-less layered into
+     * (1) basic status maintenance
+     * (2) execution and awaiting completion
+     * (3) user-level methods that additionally report results.
+     * This is sometimes hard to see because this file orders exported
+     * methods in a way that flows well in javadocs.
+     */
+
+    /*
+     * The status field holds run control status bits packed into a
+     * single int to minimize footprint and to ensure atomicity (via
+     * CAS).  Status is initially zero, and takes on nonnegative
+     * values until completed, upon which status (anded with
+     * DONE_MASK) holds value NORMAL, CANCELLED, or EXCEPTIONAL. Tasks
+     * undergoing blocking waits by other threads have the SIGNAL bit
+     * set.  Completion of a stolen task with SIGNAL set awakens any
+     * waiters via notifyAll. Even though suboptimal for some
+     * purposes, we use basic builtin wait/notify to take advantage of
+     * "monitor inflation" in JVMs that we would otherwise need to
+     * emulate to avoid adding further per-task bookkeeping overhead.
+     * We want these monitors to be "fat", i.e., not use biasing or
+     * thin-lock techniques, so use some odd coding idioms that tend
+     * to avoid them, mainly by arranging that every synchronized
+     * block performs a wait, notifyAll or both.
+     *
+     * These control bits occupy only (some of) the upper half (16
+     * bits) of status field. The lower bits are used for user-defined
+     * tags.
+     */
+
+    /** The run status of this task */
+    volatile int status; // accessed directly by pool and workers
+    static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits
+    static final int NORMAL      = 0xf0000000;  // must be negative
+    static final int CANCELLED   = 0xc0000000;  // must be < NORMAL
+    static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED
+    static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16
+    static final int SMASK       = 0x0000ffff;  // short bits for tags
+
+    /**
+     * Marks completion and wakes up threads waiting to join this
+     * task.
+     *
+     * @param completion one of NORMAL, CANCELLED, EXCEPTIONAL
+     * @return completion status on exit
+     */
+    private int setCompletion(int completion) {
+        for (int s;;) {
+            if ((s = status) < 0)
+                return s;
+            if (U.compareAndSwapInt(this, STATUS, s, s | completion)) {
+                if ((s >>> 16) != 0)
+                    synchronized (this) { notifyAll(); }
+                return completion;
+            }
+        }
+    }
+
+    /**
+     * Primary execution method for stolen tasks. Unless done, calls
+     * exec and records status if completed, but doesn't wait for
+     * completion otherwise.
+     *
+     * @return status on exit from this method
+     */
+    final int doExec() {
+        int s; boolean completed;
+        if ((s = status) >= 0) {
+            try {
+                completed = exec();
+            } catch (Throwable rex) {
+                return setExceptionalCompletion(rex);
+            }
+            if (completed)
+                s = setCompletion(NORMAL);
+        }
+        return s;
+    }
+
+    /**
+     * If not done, sets SIGNAL status and performs Object.wait(timeout).
+     * This task may or may not be done on exit. Ignores interrupts.
+     *
+     * @param timeout using Object.wait conventions.
+     */
+    final void internalWait(long timeout) {
+        int s;
+        if ((s = status) >= 0 && // force completer to issue notify
+            U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+            synchronized (this) {
+                if (status >= 0)
+                    try { wait(timeout); } catch (InterruptedException ie) { }
+                else
+                    notifyAll();
+            }
+        }
+    }
+
+    /**
+     * Blocks a non-worker-thread until completion.
+     * @return status upon completion
+     */
+    private int externalAwaitDone() {
+        int s = ((this instanceof CountedCompleter) ? // try helping
+                 ForkJoinPool.common.externalHelpComplete(
+                     (CountedCompleter<?>)this, 0) :
+                 ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);
+        if (s >= 0 && (s = status) >= 0) {
+            boolean interrupted = false;
+            do {
+                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                    synchronized (this) {
+                        if (status >= 0) {
+                            try {
+                                wait(0L);
+                            } catch (InterruptedException ie) {
+                                interrupted = true;
+                            }
+                        }
+                        else
+                            notifyAll();
+                    }
+                }
+            } while ((s = status) >= 0);
+            if (interrupted)
+                Thread.currentThread().interrupt();
+        }
+        return s;
+    }
+
+    /**
+     * Blocks a non-worker-thread until completion or interruption.
+     */
+    private int externalInterruptibleAwaitDone() throws InterruptedException {
+        int s;
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if ((s = status) >= 0 &&
+            (s = ((this instanceof CountedCompleter) ?
+                  ForkJoinPool.common.externalHelpComplete(
+                      (CountedCompleter<?>)this, 0) :
+                  ForkJoinPool.common.tryExternalUnpush(this) ? doExec() :
+                  0)) >= 0) {
+            while ((s = status) >= 0) {
+                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                    synchronized (this) {
+                        if (status >= 0)
+                            wait(0L);
+                        else
+                            notifyAll();
+                    }
+                }
+            }
+        }
+        return s;
+    }
+
+    /**
+     * Implementation for join, get, quietlyJoin. Directly handles
+     * only cases of already-completed, external wait, and
+     * unfork+exec.  Others are relayed to ForkJoinPool.awaitJoin.
+     *
+     * @return status upon completion
+     */
+    private int doJoin() {
+        int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;
+        return (s = status) < 0 ? s :
+            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (w = (wt = (ForkJoinWorkerThread)t).workQueue).
+            tryUnpush(this) && (s = doExec()) < 0 ? s :
+            wt.pool.awaitJoin(w, this, 0L) :
+            externalAwaitDone();
+    }
+
+    /**
+     * Implementation for invoke, quietlyInvoke.
+     *
+     * @return status upon completion
+     */
+    private int doInvoke() {
+        int s; Thread t; ForkJoinWorkerThread wt;
+        return (s = doExec()) < 0 ? s :
+            ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (wt = (ForkJoinWorkerThread)t).pool.
+            awaitJoin(wt.workQueue, this, 0L) :
+            externalAwaitDone();
+    }
+
+    // Exception table support
+
+    /**
+     * Table of exceptions thrown by tasks, to enable reporting by
+     * callers. Because exceptions are rare, we don't directly keep
+     * them with task objects, but instead use a weak ref table.  Note
+     * that cancellation exceptions don't appear in the table, but are
+     * instead recorded as status values.
+     *
+     * Note: These statics are initialized below in static block.
+     */
+    private static final ExceptionNode[] exceptionTable;
+    private static final ReentrantLock exceptionTableLock;
+    private static final ReferenceQueue<Object> exceptionTableRefQueue;
+
+    /**
+     * Fixed capacity for exceptionTable.
+     */
+    private static final int EXCEPTION_MAP_CAPACITY = 32;
+
+    /**
+     * Key-value nodes for exception table.  The chained hash table
+     * uses identity comparisons, full locking, and weak references
+     * for keys. The table has a fixed capacity because it only
+     * maintains task exceptions long enough for joiners to access
+     * them, so should never become very large for sustained
+     * periods. However, since we do not know when the last joiner
+     * completes, we must use weak references and expunge them. We do
+     * so on each operation (hence full locking). Also, some thread in
+     * any ForkJoinPool will call helpExpungeStaleExceptions when its
+     * pool becomes isQuiescent.
+     */
+    static final class ExceptionNode extends WeakReference<ForkJoinTask<?>> {
+        final Throwable ex;
+        ExceptionNode next;
+        final long thrower;  // use id not ref to avoid weak cycles
+        final int hashCode;  // store task hashCode before weak ref disappears
+        ExceptionNode(ForkJoinTask<?> task, Throwable ex, ExceptionNode next,
+                      ReferenceQueue<Object> exceptionTableRefQueue) {
+            super(task, exceptionTableRefQueue);
+            this.ex = ex;
+            this.next = next;
+            this.thrower = Thread.currentThread().getId();
+            this.hashCode = System.identityHashCode(task);
+        }
+    }
+
+    /**
+     * Records exception and sets status.
+     *
+     * @return status on exit
+     */
+    final int recordExceptionalCompletion(Throwable ex) {
+        int s;
+        if ((s = status) >= 0) {
+            int h = System.identityHashCode(this);
+            final ReentrantLock lock = exceptionTableLock;
+            lock.lock();
+            try {
+                expungeStaleExceptions();
+                ExceptionNode[] t = exceptionTable;
+                int i = h & (t.length - 1);
+                for (ExceptionNode e = t[i]; ; e = e.next) {
+                    if (e == null) {
+                        t[i] = new ExceptionNode(this, ex, t[i],
+                                                 exceptionTableRefQueue);
+                        break;
+                    }
+                    if (e.get() == this) // already present
+                        break;
+                }
+            } finally {
+                lock.unlock();
+            }
+            s = setCompletion(EXCEPTIONAL);
+        }
+        return s;
+    }
+
+    /**
+     * Records exception and possibly propagates.
+     *
+     * @return status on exit
+     */
+    private int setExceptionalCompletion(Throwable ex) {
+        int s = recordExceptionalCompletion(ex);
+        if ((s & DONE_MASK) == EXCEPTIONAL)
+            internalPropagateException(ex);
+        return s;
+    }
+
+    /**
+     * Hook for exception propagation support for tasks with completers.
+     */
+    void internalPropagateException(Throwable ex) {
+    }
+
+    /**
+     * Cancels, ignoring any exceptions thrown by cancel. Used during
+     * worker and pool shutdown. Cancel is spec'ed not to throw any
+     * exceptions, but if it does anyway, we have no recourse during
+     * shutdown, so guard against this case.
+     */
+    static final void cancelIgnoringExceptions(ForkJoinTask<?> t) {
+        if (t != null && t.status >= 0) {
+            try {
+                t.cancel(false);
+            } catch (Throwable ignore) {
+            }
+        }
+    }
+
+    /**
+     * Removes exception node and clears status.
+     */
+    private void clearExceptionalCompletion() {
+        int h = System.identityHashCode(this);
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            ExceptionNode[] t = exceptionTable;
+            int i = h & (t.length - 1);
+            ExceptionNode e = t[i];
+            ExceptionNode pred = null;
+            while (e != null) {
+                ExceptionNode next = e.next;
+                if (e.get() == this) {
+                    if (pred == null)
+                        t[i] = next;
+                    else
+                        pred.next = next;
+                    break;
+                }
+                pred = e;
+                e = next;
+            }
+            expungeStaleExceptions();
+            status = 0;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns a rethrowable exception for this task, if available.
+     * To provide accurate stack traces, if the exception was not
+     * thrown by the current thread, we try to create a new exception
+     * of the same type as the one thrown, but with the recorded
+     * exception as its cause. If there is no such constructor, we
+     * instead try to use a no-arg constructor, followed by initCause,
+     * to the same effect. If none of these apply, or any fail due to
+     * other exceptions, we return the recorded exception, which is
+     * still correct, although it may contain a misleading stack
+     * trace.
+     *
+     * @return the exception, or null if none
+     */
+    private Throwable getThrowableException() {
+        int h = System.identityHashCode(this);
+        ExceptionNode e;
+        final ReentrantLock lock = exceptionTableLock;
+        lock.lock();
+        try {
+            expungeStaleExceptions();
+            ExceptionNode[] t = exceptionTable;
+            e = t[h & (t.length - 1)];
+            while (e != null && e.get() != this)
+                e = e.next;
+        } finally {
+            lock.unlock();
+        }
+        Throwable ex;
+        if (e == null || (ex = e.ex) == null)
+            return null;
+        if (e.thrower != Thread.currentThread().getId()) {
+            try {
+                Constructor<?> noArgCtor = null;
+                // public ctors only
+                for (Constructor<?> c : ex.getClass().getConstructors()) {
+                    Class<?>[] ps = c.getParameterTypes();
+                    if (ps.length == 0)
+                        noArgCtor = c;
+                    else if (ps.length == 1 && ps[0] == Throwable.class)
+                        return (Throwable)c.newInstance(ex);
+                }
+                if (noArgCtor != null) {
+                    Throwable wx = (Throwable)noArgCtor.newInstance();
+                    wx.initCause(ex);
+                    return wx;
+                }
+            } catch (Exception ignore) {
+            }
+        }
+        return ex;
+    }
+
+    /**
+     * Polls stale refs and removes them. Call only while holding lock.
+     */
+    private static void expungeStaleExceptions() {
+        for (Object x; (x = exceptionTableRefQueue.poll()) != null;) {
+            if (x instanceof ExceptionNode) {
+                int hashCode = ((ExceptionNode)x).hashCode;
+                ExceptionNode[] t = exceptionTable;
+                int i = hashCode & (t.length - 1);
+                ExceptionNode e = t[i];
+                ExceptionNode pred = null;
+                while (e != null) {
+                    ExceptionNode next = e.next;
+                    if (e == x) {
+                        if (pred == null)
+                            t[i] = next;
+                        else
+                            pred.next = next;
+                        break;
+                    }
+                    pred = e;
+                    e = next;
+                }
+            }
+        }
+    }
+
+    /**
+     * If lock is available, polls stale refs and removes them.
+     * Called from ForkJoinPool when pools become quiescent.
+     */
+    static final void helpExpungeStaleExceptions() {
+        final ReentrantLock lock = exceptionTableLock;
+        if (lock.tryLock()) {
+            try {
+                expungeStaleExceptions();
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /**
+     * A version of "sneaky throw" to relay exceptions.
+     */
+    static void rethrow(Throwable ex) {
+        ForkJoinTask.<RuntimeException>uncheckedThrow(ex);
+    }
+
+    /**
+     * The sneaky part of sneaky throw, relying on generics
+     * limitations to evade compiler complaints about rethrowing
+     * unchecked exceptions.
+     */
+    @SuppressWarnings("unchecked") static <T extends Throwable>
+    void uncheckedThrow(Throwable t) throws T {
+        if (t != null)
+            throw (T)t; // rely on vacuous cast
+        else
+            throw new Error("Unknown Exception");
+    }
+
+    /**
+     * Throws exception, if any, associated with the given status.
+     */
+    private void reportException(int s) {
+        if (s == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL)
+            rethrow(getThrowableException());
+    }
+
+    // public methods
+
+    /**
+     * Arranges to asynchronously execute this task in the pool the
+     * current task is running in, if applicable, or using the {@link
+     * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}.  While
+     * it is not necessarily enforced, it is a usage error to fork a
+     * task more than once unless it has completed and been
+     * reinitialized.  Subsequent modifications to the state of this
+     * task or any data it operates on are not necessarily
+     * consistently observable by any thread other than the one
+     * executing it unless preceded by a call to {@link #join} or
+     * related methods, or a call to {@link #isDone} returning {@code
+     * true}.
+     *
+     * @return {@code this}, to simplify usage
+     */
+    public final ForkJoinTask<V> fork() {
+        Thread t;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            ((ForkJoinWorkerThread)t).workQueue.push(this);
+        else
+            ForkJoinPool.common.externalPush(this);
+        return this;
+    }
+
+    /**
+     * Returns the result of the computation when it {@link #isDone is
+     * done}.  This method differs from {@link #get()} in that
+     * abnormal completion results in {@code RuntimeException} or
+     * {@code Error}, not {@code ExecutionException}, and that
+     * interrupts of the calling thread do <em>not</em> cause the
+     * method to abruptly return by throwing {@code
+     * InterruptedException}.
+     *
+     * @return the computed result
+     */
+    public final V join() {
+        int s;
+        if ((s = doJoin() & DONE_MASK) != NORMAL)
+            reportException(s);
+        return getRawResult();
+    }
+
+    /**
+     * Commences performing this task, awaits its completion if
+     * necessary, and returns its result, or throws an (unchecked)
+     * {@code RuntimeException} or {@code Error} if the underlying
+     * computation did so.
+     *
+     * @return the computed result
+     */
+    public final V invoke() {
+        int s;
+        if ((s = doInvoke() & DONE_MASK) != NORMAL)
+            reportException(s);
+        return getRawResult();
+    }
+
+    /**
+     * Forks the given tasks, returning when {@code isDone} holds for
+     * each task or an (unchecked) exception is encountered, in which
+     * case the exception is rethrown. If more than one task
+     * encounters an exception, then this method throws any one of
+     * these exceptions. If any task encounters an exception, the
+     * other may be cancelled. However, the execution status of
+     * individual tasks is not guaranteed upon exceptional return. The
+     * status of each task may be obtained using {@link
+     * #getException()} and related methods to check if they have been
+     * cancelled, completed normally or exceptionally, or left
+     * unprocessed.
+     *
+     * @param t1 the first task
+     * @param t2 the second task
+     * @throws NullPointerException if any task is null
+     */
+    public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) {
+        int s1, s2;
+        t2.fork();
+        if ((s1 = t1.doInvoke() & DONE_MASK) != NORMAL)
+            t1.reportException(s1);
+        if ((s2 = t2.doJoin() & DONE_MASK) != NORMAL)
+            t2.reportException(s2);
+    }
+
+    /**
+     * Forks the given tasks, returning when {@code isDone} holds for
+     * each task or an (unchecked) exception is encountered, in which
+     * case the exception is rethrown. If more than one task
+     * encounters an exception, then this method throws any one of
+     * these exceptions. If any task encounters an exception, others
+     * may be cancelled. However, the execution status of individual
+     * tasks is not guaranteed upon exceptional return. The status of
+     * each task may be obtained using {@link #getException()} and
+     * related methods to check if they have been cancelled, completed
+     * normally or exceptionally, or left unprocessed.
+     *
+     * @param tasks the tasks
+     * @throws NullPointerException if any task is null
+     */
+    public static void invokeAll(ForkJoinTask<?>... tasks) {
+        Throwable ex = null;
+        int last = tasks.length - 1;
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t = tasks[i];
+            if (t == null) {
+                if (ex == null)
+                    ex = new NullPointerException();
+            }
+            else if (i != 0)
+                t.fork();
+            else if (t.doInvoke() < NORMAL && ex == null)
+                ex = t.getException();
+        }
+        for (int i = 1; i <= last; ++i) {
+            ForkJoinTask<?> t = tasks[i];
+            if (t != null) {
+                if (ex != null)
+                    t.cancel(false);
+                else if (t.doJoin() < NORMAL)
+                    ex = t.getException();
+            }
+        }
+        if (ex != null)
+            rethrow(ex);
+    }
+
+    /**
+     * Forks all tasks in the specified collection, returning when
+     * {@code isDone} holds for each task or an (unchecked) exception
+     * is encountered, in which case the exception is rethrown. If
+     * more than one task encounters an exception, then this method
+     * throws any one of these exceptions. If any task encounters an
+     * exception, others may be cancelled. However, the execution
+     * status of individual tasks is not guaranteed upon exceptional
+     * return. The status of each task may be obtained using {@link
+     * #getException()} and related methods to check if they have been
+     * cancelled, completed normally or exceptionally, or left
+     * unprocessed.
+     *
+     * @param tasks the collection of tasks
+     * @param <T> the type of the values returned from the tasks
+     * @return the tasks argument, to simplify usage
+     * @throws NullPointerException if tasks or any element are null
+     */
+    public static <T extends ForkJoinTask<?>> Collection<T> invokeAll(Collection<T> tasks) {
+        if (!(tasks instanceof RandomAccess) || !(tasks instanceof List<?>)) {
+            invokeAll(tasks.toArray(new ForkJoinTask<?>[tasks.size()]));
+            return tasks;
+        }
+        @SuppressWarnings("unchecked")
+        List<? extends ForkJoinTask<?>> ts =
+            (List<? extends ForkJoinTask<?>>) tasks;
+        Throwable ex = null;
+        int last = ts.size() - 1;
+        for (int i = last; i >= 0; --i) {
+            ForkJoinTask<?> t = ts.get(i);
+            if (t == null) {
+                if (ex == null)
+                    ex = new NullPointerException();
+            }
+            else if (i != 0)
+                t.fork();
+            else if (t.doInvoke() < NORMAL && ex == null)
+                ex = t.getException();
+        }
+        for (int i = 1; i <= last; ++i) {
+            ForkJoinTask<?> t = ts.get(i);
+            if (t != null) {
+                if (ex != null)
+                    t.cancel(false);
+                else if (t.doJoin() < NORMAL)
+                    ex = t.getException();
+            }
+        }
+        if (ex != null)
+            rethrow(ex);
+        return tasks;
+    }
+
+    /**
+     * Attempts to cancel execution of this task. This attempt will
+     * fail if the task has already completed or could not be
+     * cancelled for some other reason. If successful, and this task
+     * has not started when {@code cancel} is called, execution of
+     * this task is suppressed. After this method returns
+     * successfully, unless there is an intervening call to {@link
+     * #reinitialize}, subsequent calls to {@link #isCancelled},
+     * {@link #isDone}, and {@code cancel} will return {@code true}
+     * and calls to {@link #join} and related methods will result in
+     * {@code CancellationException}.
+     *
+     * <p>This method may be overridden in subclasses, but if so, must
+     * still ensure that these properties hold. In particular, the
+     * {@code cancel} method itself must not throw exceptions.
+     *
+     * <p>This method is designed to be invoked by <em>other</em>
+     * tasks. To terminate the current task, you can just return or
+     * throw an unchecked exception from its computation method, or
+     * invoke {@link #completeExceptionally(Throwable)}.
+     *
+     * @param mayInterruptIfRunning this value has no effect in the
+     * default implementation because interrupts are not used to
+     * control cancellation.
+     *
+     * @return {@code true} if this task is now cancelled
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return (setCompletion(CANCELLED) & DONE_MASK) == CANCELLED;
+    }
+
+    public final boolean isDone() {
+        return status < 0;
+    }
+
+    public final boolean isCancelled() {
+        return (status & DONE_MASK) == CANCELLED;
+    }
+
+    /**
+     * Returns {@code true} if this task threw an exception or was cancelled.
+     *
+     * @return {@code true} if this task threw an exception or was cancelled
+     */
+    public final boolean isCompletedAbnormally() {
+        return status < NORMAL;
+    }
+
+    /**
+     * Returns {@code true} if this task completed without throwing an
+     * exception and was not cancelled.
+     *
+     * @return {@code true} if this task completed without throwing an
+     * exception and was not cancelled
+     */
+    public final boolean isCompletedNormally() {
+        return (status & DONE_MASK) == NORMAL;
+    }
+
+    /**
+     * Returns the exception thrown by the base computation, or a
+     * {@code CancellationException} if cancelled, or {@code null} if
+     * none or if the method has not yet completed.
+     *
+     * @return the exception, or {@code null} if none
+     */
+    public final Throwable getException() {
+        int s = status & DONE_MASK;
+        return ((s >= NORMAL)    ? null :
+                (s == CANCELLED) ? new CancellationException() :
+                getThrowableException());
+    }
+
+    /**
+     * Completes this task abnormally, and if not already aborted or
+     * cancelled, causes it to throw the given exception upon
+     * {@code join} and related operations. This method may be used
+     * to induce exceptions in asynchronous tasks, or to force
+     * completion of tasks that would not otherwise complete.  Its use
+     * in other situations is discouraged.  This method is
+     * overridable, but overridden versions must invoke {@code super}
+     * implementation to maintain guarantees.
+     *
+     * @param ex the exception to throw. If this exception is not a
+     * {@code RuntimeException} or {@code Error}, the actual exception
+     * thrown will be a {@code RuntimeException} with cause {@code ex}.
+     */
+    public void completeExceptionally(Throwable ex) {
+        setExceptionalCompletion((ex instanceof RuntimeException) ||
+                                 (ex instanceof Error) ? ex :
+                                 new RuntimeException(ex));
+    }
+
+    /**
+     * Completes this task, and if not already aborted or cancelled,
+     * returning the given value as the result of subsequent
+     * invocations of {@code join} and related operations. This method
+     * may be used to provide results for asynchronous tasks, or to
+     * provide alternative handling for tasks that would not otherwise
+     * complete normally. Its use in other situations is
+     * discouraged. This method is overridable, but overridden
+     * versions must invoke {@code super} implementation to maintain
+     * guarantees.
+     *
+     * @param value the result value for this task
+     */
+    public void complete(V value) {
+        try {
+            setRawResult(value);
+        } catch (Throwable rex) {
+            setExceptionalCompletion(rex);
+            return;
+        }
+        setCompletion(NORMAL);
+    }
+
+    /**
+     * Completes this task normally without setting a value. The most
+     * recent value established by {@link #setRawResult} (or {@code
+     * null} by default) will be returned as the result of subsequent
+     * invocations of {@code join} and related operations.
+     *
+     * @since 1.8
+     */
+    public final void quietlyComplete() {
+        setCompletion(NORMAL);
+    }
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread is not a
+     * member of a ForkJoinPool and was interrupted while waiting
+     */
+    public final V get() throws InterruptedException, ExecutionException {
+        int s = (Thread.currentThread() instanceof ForkJoinWorkerThread) ?
+            doJoin() : externalInterruptibleAwaitDone();
+        if ((s &= DONE_MASK) == CANCELLED)
+            throw new CancellationException();
+        if (s == EXCEPTIONAL)
+            throw new ExecutionException(getThrowableException());
+        return getRawResult();
+    }
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread is not a
+     * member of a ForkJoinPool and was interrupted while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    public final V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        int s;
+        long nanos = unit.toNanos(timeout);
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if ((s = status) >= 0 && nanos > 0L) {
+            long d = System.nanoTime() + nanos;
+            long deadline = (d == 0L) ? 1L : d; // avoid 0
+            Thread t = Thread.currentThread();
+            if (t instanceof ForkJoinWorkerThread) {
+                ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+                s = wt.pool.awaitJoin(wt.workQueue, this, deadline);
+            }
+            else if ((s = ((this instanceof CountedCompleter) ?
+                           ForkJoinPool.common.externalHelpComplete(
+                               (CountedCompleter<?>)this, 0) :
+                           ForkJoinPool.common.tryExternalUnpush(this) ?
+                           doExec() : 0)) >= 0) {
+                long ns, ms; // measure in nanosecs, but wait in millisecs
+                while ((s = status) >= 0 &&
+                       (ns = deadline - System.nanoTime()) > 0L) {
+                    if ((ms = TimeUnit.NANOSECONDS.toMillis(ns)) > 0L &&
+                        U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {
+                        synchronized (this) {
+                            if (status >= 0)
+                                wait(ms); // OK to throw InterruptedException
+                            else
+                                notifyAll();
+                        }
+                    }
+                }
+            }
+        }
+        if (s >= 0)
+            s = status;
+        if ((s &= DONE_MASK) != NORMAL) {
+            if (s == CANCELLED)
+                throw new CancellationException();
+            if (s != EXCEPTIONAL)
+                throw new TimeoutException();
+            throw new ExecutionException(getThrowableException());
+        }
+        return getRawResult();
+    }
+
+    /**
+     * Joins this task, without returning its result or throwing its
+     * exception. This method may be useful when processing
+     * collections of tasks when some have been cancelled or otherwise
+     * known to have aborted.
+     */
+    public final void quietlyJoin() {
+        doJoin();
+    }
+
+    /**
+     * Commences performing this task and awaits its completion if
+     * necessary, without returning its result or throwing its
+     * exception.
+     */
+    public final void quietlyInvoke() {
+        doInvoke();
+    }
+
+    /**
+     * Possibly executes tasks until the pool hosting the current task
+     * {@linkplain ForkJoinPool#isQuiescent is quiescent}.  This
+     * method may be of use in designs in which many tasks are forked,
+     * but none are explicitly joined, instead executing them until
+     * all are processed.
+     */
+    public static void helpQuiesce() {
+        Thread t;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
+            ForkJoinWorkerThread wt = (ForkJoinWorkerThread)t;
+            wt.pool.helpQuiescePool(wt.workQueue);
+        }
+        else
+            ForkJoinPool.quiesceCommonPool();
+    }
+
+    /**
+     * Resets the internal bookkeeping state of this task, allowing a
+     * subsequent {@code fork}. This method allows repeated reuse of
+     * this task, but only if reuse occurs when this task has either
+     * never been forked, or has been forked, then completed and all
+     * outstanding joins of this task have also completed. Effects
+     * under any other usage conditions are not guaranteed.
+     * This method may be useful when executing
+     * pre-constructed trees of subtasks in loops.
+     *
+     * <p>Upon completion of this method, {@code isDone()} reports
+     * {@code false}, and {@code getException()} reports {@code
+     * null}. However, the value returned by {@code getRawResult} is
+     * unaffected. To clear this value, you can invoke {@code
+     * setRawResult(null)}.
+     */
+    public void reinitialize() {
+        if ((status & DONE_MASK) == EXCEPTIONAL)
+            clearExceptionalCompletion();
+        else
+            status = 0;
+    }
+
+    /**
+     * Returns the pool hosting the current thread, or {@code null}
+     * if the current thread is executing outside of any ForkJoinPool.
+     *
+     * <p>This method returns {@code null} if and only if {@link
+     * #inForkJoinPool} returns {@code false}.
+     *
+     * @return the pool, or {@code null} if none
+     */
+    public static ForkJoinPool getPool() {
+        Thread t = Thread.currentThread();
+        return (t instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread) t).pool : null;
+    }
+
+    /**
+     * Returns {@code true} if the current thread is a {@link
+     * ForkJoinWorkerThread} executing as a ForkJoinPool computation.
+     *
+     * @return {@code true} if the current thread is a {@link
+     * ForkJoinWorkerThread} executing as a ForkJoinPool computation,
+     * or {@code false} otherwise
+     */
+    public static boolean inForkJoinPool() {
+        return Thread.currentThread() instanceof ForkJoinWorkerThread;
+    }
+
+    /**
+     * Tries to unschedule this task for execution. This method will
+     * typically (but is not guaranteed to) succeed if this task is
+     * the most recently forked task by the current thread, and has
+     * not commenced executing in another thread.  This method may be
+     * useful when arranging alternative local processing of tasks
+     * that could have been, but were not, stolen.
+     *
+     * @return {@code true} if unforked
+     */
+    public boolean tryUnfork() {
+        Thread t;
+        return (((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+                ((ForkJoinWorkerThread)t).workQueue.tryUnpush(this) :
+                ForkJoinPool.common.tryExternalUnpush(this));
+    }
+
+    /**
+     * Returns an estimate of the number of tasks that have been
+     * forked by the current worker thread but not yet executed. This
+     * value may be useful for heuristic decisions about whether to
+     * fork other tasks.
+     *
+     * @return the number of tasks
+     */
+    public static int getQueuedTaskCount() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonSubmitterQueue();
+        return (q == null) ? 0 : q.queueSize();
+    }
+
+    /**
+     * Returns an estimate of how many more locally queued tasks are
+     * held by the current worker thread than there are other worker
+     * threads that might steal them, or zero if this thread is not
+     * operating in a ForkJoinPool. This value may be useful for
+     * heuristic decisions about whether to fork other tasks. In many
+     * usages of ForkJoinTasks, at steady state, each worker should
+     * aim to maintain a small constant surplus (for example, 3) of
+     * tasks, and to process computations locally if this threshold is
+     * exceeded.
+     *
+     * @return the surplus number of tasks, which may be negative
+     */
+    public static int getSurplusQueuedTaskCount() {
+        return ForkJoinPool.getSurplusQueuedTaskCount();
+    }
+
+    // Extension methods
+
+    /**
+     * Returns the result that would be returned by {@link #join}, even
+     * if this task completed abnormally, or {@code null} if this task
+     * is not known to have been completed.  This method is designed
+     * to aid debugging, as well as to support extensions. Its use in
+     * any other context is discouraged.
+     *
+     * @return the result, or {@code null} if not completed
+     */
+    public abstract V getRawResult();
+
+    /**
+     * Forces the given value to be returned as a result.  This method
+     * is designed to support extensions, and should not in general be
+     * called otherwise.
+     *
+     * @param value the value
+     */
+    protected abstract void setRawResult(V value);
+
+    /**
+     * Immediately performs the base action of this task and returns
+     * true if, upon return from this method, this task is guaranteed
+     * to have completed normally. This method may return false
+     * otherwise, to indicate that this task is not necessarily
+     * complete (or is not known to be complete), for example in
+     * asynchronous actions that require explicit invocations of
+     * completion methods. This method may also throw an (unchecked)
+     * exception to indicate abnormal exit. This method is designed to
+     * support extensions, and should not in general be called
+     * otherwise.
+     *
+     * @return {@code true} if this task is known to have completed normally
+     */
+    protected abstract boolean exec();
+
+    /**
+     * Returns, but does not unschedule or execute, a task queued by
+     * the current thread but not yet executed, if one is immediately
+     * available. There is no guarantee that this task will actually
+     * be polled or executed next. Conversely, this method may return
+     * null even if a task exists but cannot be accessed without
+     * contention with other threads.  This method is designed
+     * primarily to support extensions, and is unlikely to be useful
+     * otherwise.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> peekNextLocalTask() {
+        Thread t; ForkJoinPool.WorkQueue q;
+        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread)
+            q = ((ForkJoinWorkerThread)t).workQueue;
+        else
+            q = ForkJoinPool.commonSubmitterQueue();
+        return (q == null) ? null : q.peek();
+    }
+
+    /**
+     * Unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed, if the
+     * current thread is operating in a ForkJoinPool.  This method is
+     * designed primarily to support extensions, and is unlikely to be
+     * useful otherwise.
+     *
+     * @return the next task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollNextLocalTask() {
+        Thread t;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread)t).workQueue.nextLocalTask() :
+            null;
+    }
+
+    /**
+     * If the current thread is operating in a ForkJoinPool,
+     * unschedules and returns, without executing, the next task
+     * queued by the current thread but not yet executed, if one is
+     * available, or if not available, a task that was forked by some
+     * other thread, if available. Availability may be transient, so a
+     * {@code null} result does not necessarily imply quiescence of
+     * the pool this task is operating in.  This method is designed
+     * primarily to support extensions, and is unlikely to be useful
+     * otherwise.
+     *
+     * @return a task, or {@code null} if none are available
+     */
+    protected static ForkJoinTask<?> pollTask() {
+        Thread t; ForkJoinWorkerThread wt;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            (wt = (ForkJoinWorkerThread)t).pool.nextTaskFor(wt.workQueue) :
+            null;
+    }
+
+    /**
+     * If the current thread is operating in a ForkJoinPool,
+     * unschedules and returns, without executing, a task externally
+     * submitted to the pool, if one is available. Availability may be
+     * transient, so a {@code null} result does not necessarily imply
+     * quiescence of the pool.  This method is designed primarily to
+     * support extensions, and is unlikely to be useful otherwise.
+     *
+     * @return a task, or {@code null} if none are available
+     * @since 9
+     * @hide API from OpenJDK 9, not yet exposed on Android.
+     */
+    protected static ForkJoinTask<?> pollSubmission() {
+        Thread t;
+        return ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?
+            ((ForkJoinWorkerThread)t).pool.pollSubmission() : null;
+    }
+
+    // tag operations
+
+    /**
+     * Returns the tag for this task.
+     *
+     * @return the tag for this task
+     * @since 1.8
+     */
+    public final short getForkJoinTaskTag() {
+        return (short)status;
+    }
+
+    /**
+     * Atomically sets the tag value for this task and returns the old value.
+     *
+     * @param newValue the new tag value
+     * @return the previous value of the tag
+     * @since 1.8
+     */
+    public final short setForkJoinTaskTag(short newValue) {
+        for (int s;;) {
+            if (U.compareAndSwapInt(this, STATUS, s = status,
+                                    (s & ~SMASK) | (newValue & SMASK)))
+                return (short)s;
+        }
+    }
+
+    /**
+     * Atomically conditionally sets the tag value for this task.
+     * Among other applications, tags can be used as visit markers
+     * in tasks operating on graphs, as in methods that check: {@code
+     * if (task.compareAndSetForkJoinTaskTag((short)0, (short)1))}
+     * before processing, otherwise exiting because the node has
+     * already been visited.
+     *
+     * @param expect the expected tag value
+     * @param update the new tag value
+     * @return {@code true} if successful; i.e., the current value was
+     * equal to {@code expect} and was changed to {@code update}.
+     * @since 1.8
+     */
+    public final boolean compareAndSetForkJoinTaskTag(short expect, short update) {
+        for (int s;;) {
+            if ((short)(s = status) != expect)
+                return false;
+            if (U.compareAndSwapInt(this, STATUS, s,
+                                    (s & ~SMASK) | (update & SMASK)))
+                return true;
+        }
+    }
+
+    /**
+     * Adapter for Runnables. This implements RunnableFuture
+     * to be compliant with AbstractExecutorService constraints
+     * when used in ForkJoinPool.
+     */
+    static final class AdaptedRunnable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        final Runnable runnable;
+        T result;
+        AdaptedRunnable(Runnable runnable, T result) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+            this.result = result; // OK to set this even before completion
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Runnables without results.
+     */
+    static final class AdaptedRunnableAction extends ForkJoinTask<Void>
+        implements RunnableFuture<Void> {
+        final Runnable runnable;
+        AdaptedRunnableAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Runnables in which failure forces worker exception.
+     */
+    static final class RunnableExecuteAction extends ForkJoinTask<Void> {
+        final Runnable runnable;
+        RunnableExecuteAction(Runnable runnable) {
+            if (runnable == null) throw new NullPointerException();
+            this.runnable = runnable;
+        }
+        public final Void getRawResult() { return null; }
+        public final void setRawResult(Void v) { }
+        public final boolean exec() { runnable.run(); return true; }
+        void internalPropagateException(Throwable ex) {
+            rethrow(ex); // rethrow outside exec() catches.
+        }
+        private static final long serialVersionUID = 5232453952276885070L;
+    }
+
+    /**
+     * Adapter for Callables.
+     */
+    static final class AdaptedCallable<T> extends ForkJoinTask<T>
+        implements RunnableFuture<T> {
+        final Callable<? extends T> callable;
+        T result;
+        AdaptedCallable(Callable<? extends T> callable) {
+            if (callable == null) throw new NullPointerException();
+            this.callable = callable;
+        }
+        public final T getRawResult() { return result; }
+        public final void setRawResult(T v) { result = v; }
+        public final boolean exec() {
+            try {
+                result = callable.call();
+                return true;
+            } catch (RuntimeException rex) {
+                throw rex;
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        public final void run() { invoke(); }
+        private static final long serialVersionUID = 2838392045355241008L;
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code run}
+     * method of the given {@code Runnable} as its action, and returns
+     * a null result upon {@link #join}.
+     *
+     * @param runnable the runnable action
+     * @return the task
+     */
+    public static ForkJoinTask<?> adapt(Runnable runnable) {
+        return new AdaptedRunnableAction(runnable);
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code run}
+     * method of the given {@code Runnable} as its action, and returns
+     * the given result upon {@link #join}.
+     *
+     * @param runnable the runnable action
+     * @param result the result upon completion
+     * @param <T> the type of the result
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Runnable runnable, T result) {
+        return new AdaptedRunnable<T>(runnable, result);
+    }
+
+    /**
+     * Returns a new {@code ForkJoinTask} that performs the {@code call}
+     * method of the given {@code Callable} as its action, and returns
+     * its result upon {@link #join}, translating any checked exceptions
+     * encountered into {@code RuntimeException}.
+     *
+     * @param callable the callable action
+     * @param <T> the type of the callable's result
+     * @return the task
+     */
+    public static <T> ForkJoinTask<T> adapt(Callable<? extends T> callable) {
+        return new AdaptedCallable<T>(callable);
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -7721805057305804111L;
+
+    /**
+     * Saves this task to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData the current run status and the exception thrown
+     * during execution, or {@code null} if none
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        s.writeObject(getException());
+    }
+
+    /**
+     * Reconstitutes this task from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        Object ex = s.readObject();
+        if (ex != null)
+            setExceptionalCompletion((Throwable)ex);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATUS;
+
+    static {
+        exceptionTableLock = new ReentrantLock();
+        exceptionTableRefQueue = new ReferenceQueue<Object>();
+        exceptionTable = new ExceptionNode[EXCEPTION_MAP_CAPACITY];
+        try {
+            STATUS = U.objectFieldOffset
+                (ForkJoinTask.class.getDeclaredField("status"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/ForkJoinWorkerThread.java b/java/util/concurrent/ForkJoinWorkerThread.java
new file mode 100644
index 0000000..e98ba99
--- /dev/null
+++ b/java/util/concurrent/ForkJoinWorkerThread.java
@@ -0,0 +1,273 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+/**
+ * A thread managed by a {@link ForkJoinPool}, which executes
+ * {@link ForkJoinTask}s.
+ * This class is subclassable solely for the sake of adding
+ * functionality -- there are no overridable methods dealing with
+ * scheduling or execution.  However, you can override initialization
+ * and termination methods surrounding the main task processing loop.
+ * If you do create such a subclass, you will also need to supply a
+ * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
+ * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class ForkJoinWorkerThread extends Thread {
+    /*
+     * ForkJoinWorkerThreads are managed by ForkJoinPools and perform
+     * ForkJoinTasks. For explanation, see the internal documentation
+     * of class ForkJoinPool.
+     *
+     * This class just maintains links to its pool and WorkQueue.  The
+     * pool field is set immediately upon construction, but the
+     * workQueue field is not set until a call to registerWorker
+     * completes. This leads to a visibility race, that is tolerated
+     * by requiring that the workQueue field is only accessed by the
+     * owning thread.
+     *
+     * Support for (non-public) subclass InnocuousForkJoinWorkerThread
+     * requires that we break quite a lot of encapsulation (via Unsafe)
+     * both here and in the subclass to access and set Thread fields.
+     */
+
+    final ForkJoinPool pool;                // the pool this thread works in
+    final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics
+
+    /**
+     * Creates a ForkJoinWorkerThread operating in the given pool.
+     *
+     * @param pool the pool this thread works in
+     * @throws NullPointerException if pool is null
+     */
+    protected ForkJoinWorkerThread(ForkJoinPool pool) {
+        // Use a placeholder until a useful name can be set in registerWorker
+        super("aForkJoinWorkerThread");
+        this.pool = pool;
+        this.workQueue = pool.registerWorker(this);
+    }
+
+    /**
+     * Version for InnocuousForkJoinWorkerThread.
+     */
+    ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
+                         AccessControlContext acc) {
+        super(threadGroup, null, "aForkJoinWorkerThread");
+        U.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, acc);
+        eraseThreadLocals(); // clear before registering
+        this.pool = pool;
+        this.workQueue = pool.registerWorker(this);
+    }
+
+    /**
+     * Returns the pool hosting this thread.
+     *
+     * @return the pool
+     */
+    public ForkJoinPool getPool() {
+        return pool;
+    }
+
+    /**
+     * Returns the unique index number of this thread in its pool.
+     * The returned value ranges from zero to the maximum number of
+     * threads (minus one) that may exist in the pool, and does not
+     * change during the lifetime of the thread.  This method may be
+     * useful for applications that track status or collect results
+     * per-worker-thread rather than per-task.
+     *
+     * @return the index number
+     */
+    public int getPoolIndex() {
+        return workQueue.getPoolIndex();
+    }
+
+    /**
+     * Initializes internal state after construction but before
+     * processing any tasks. If you override this method, you must
+     * invoke {@code super.onStart()} at the beginning of the method.
+     * Initialization requires care: Most fields must have legal
+     * default values, to ensure that attempted accesses from other
+     * threads work correctly even before this thread starts
+     * processing tasks.
+     */
+    protected void onStart() {
+    }
+
+    /**
+     * Performs cleanup associated with termination of this worker
+     * thread.  If you override this method, you must invoke
+     * {@code super.onTermination} at the end of the overridden method.
+     *
+     * @param exception the exception causing this thread to abort due
+     * to an unrecoverable error, or {@code null} if completed normally
+     */
+    protected void onTermination(Throwable exception) {
+    }
+
+    /**
+     * This method is required to be public, but should never be
+     * called explicitly. It performs the main run loop to execute
+     * {@link ForkJoinTask}s.
+     */
+    public void run() {
+        if (workQueue.array == null) { // only run once
+            Throwable exception = null;
+            try {
+                onStart();
+                pool.runWorker(workQueue);
+            } catch (Throwable ex) {
+                exception = ex;
+            } finally {
+                try {
+                    onTermination(exception);
+                } catch (Throwable ex) {
+                    if (exception == null)
+                        exception = ex;
+                } finally {
+                    pool.deregisterWorker(this, exception);
+                }
+            }
+        }
+    }
+
+    /**
+     * Erases ThreadLocals by nulling out Thread maps.
+     */
+    final void eraseThreadLocals() {
+        U.putObject(this, THREADLOCALS, null);
+        U.putObject(this, INHERITABLETHREADLOCALS, null);
+    }
+
+    /**
+     * Non-public hook method for InnocuousForkJoinWorkerThread.
+     */
+    void afterTopLevelExec() {
+    }
+
+    // Set up to allow setting thread fields in constructor
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long THREADLOCALS;
+    private static final long INHERITABLETHREADLOCALS;
+    private static final long INHERITEDACCESSCONTROLCONTEXT;
+    static {
+        try {
+            THREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocals"));
+            INHERITABLETHREADLOCALS = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritableThreadLocals"));
+            INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
+                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /**
+     * A worker thread that has no permissions, is not a member of any
+     * user-defined ThreadGroup, and erases all ThreadLocals after
+     * running each top-level task.
+     */
+    static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
+        /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
+        private static final ThreadGroup innocuousThreadGroup =
+            createThreadGroup();
+
+        /** An AccessControlContext supporting no privileges */
+        private static final AccessControlContext INNOCUOUS_ACC =
+            new AccessControlContext(
+                new ProtectionDomain[] {
+                    new ProtectionDomain(null, null)
+                });
+
+        InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
+            super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
+        }
+
+        @Override // to erase ThreadLocals
+        void afterTopLevelExec() {
+            eraseThreadLocals();
+        }
+
+        @Override // to always report system loader
+        public ClassLoader getContextClassLoader() {
+            return ClassLoader.getSystemClassLoader();
+        }
+
+        @Override // to silently fail
+        public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }
+
+        @Override // paranoically
+        public void setContextClassLoader(ClassLoader cl) {
+            throw new SecurityException("setContextClassLoader");
+        }
+
+        /**
+         * Returns a new group with the system ThreadGroup (the
+         * topmost, parent-less group) as parent.  Uses Unsafe to
+         * traverse Thread.group and ThreadGroup.parent fields.
+         */
+        private static ThreadGroup createThreadGroup() {
+            try {
+                sun.misc.Unsafe u = sun.misc.Unsafe.getUnsafe();
+                long tg = u.objectFieldOffset
+                    (Thread.class.getDeclaredField("group"));
+                long gp = u.objectFieldOffset
+                    (ThreadGroup.class.getDeclaredField("parent"));
+                ThreadGroup group = (ThreadGroup)
+                    u.getObject(Thread.currentThread(), tg);
+                while (group != null) {
+                    ThreadGroup parent = (ThreadGroup)u.getObject(group, gp);
+                    if (parent == null)
+                        return new ThreadGroup(group,
+                                               "InnocuousForkJoinWorkerThreadGroup");
+                    group = parent;
+                }
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+            // fall through if null as cannot-happen safeguard
+            throw new Error("Cannot create ThreadGroup");
+        }
+    }
+
+}
diff --git a/java/util/concurrent/Future.java b/java/util/concurrent/Future.java
new file mode 100644
index 0000000..9bd05d6
--- /dev/null
+++ b/java/util/concurrent/Future.java
@@ -0,0 +1,170 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@code Future} represents the result of an asynchronous
+ * computation.  Methods are provided to check if the computation is
+ * complete, to wait for its completion, and to retrieve the result of
+ * the computation.  The result can only be retrieved using method
+ * {@code get} when the computation has completed, blocking if
+ * necessary until it is ready.  Cancellation is performed by the
+ * {@code cancel} method.  Additional methods are provided to
+ * determine if the task completed normally or was cancelled. Once a
+ * computation has completed, the computation cannot be cancelled.
+ * If you would like to use a {@code Future} for the sake
+ * of cancellability but not provide a usable result, you can
+ * declare types of the form {@code Future<?>} and
+ * return {@code null} as a result of the underlying task.
+ *
+ * <p>
+ * <b>Sample Usage</b> (Note that the following classes are all
+ * made-up.)
+ *
+ * <pre> {@code
+ * interface ArchiveSearcher { String search(String target); }
+ * class App {
+ *   ExecutorService executor = ...
+ *   ArchiveSearcher searcher = ...
+ *   void showSearch(final String target)
+ *       throws InterruptedException {
+ *     Future<String> future
+ *       = executor.submit(new Callable<String>() {
+ *         public String call() {
+ *             return searcher.search(target);
+ *         }});
+ *     displayOtherThings(); // do other things while searching
+ *     try {
+ *       displayText(future.get()); // use future
+ *     } catch (ExecutionException ex) { cleanup(); return; }
+ *   }
+ * }}</pre>
+ *
+ * The {@link FutureTask} class is an implementation of {@code Future} that
+ * implements {@code Runnable}, and so may be executed by an {@code Executor}.
+ * For example, the above construction with {@code submit} could be replaced by:
+ * <pre> {@code
+ * FutureTask<String> future =
+ *   new FutureTask<>(new Callable<String>() {
+ *     public String call() {
+ *       return searcher.search(target);
+ *   }});
+ * executor.execute(future);}</pre>
+ *
+ * <p>Memory consistency effects: Actions taken by the asynchronous computation
+ * <a href="package-summary.html#MemoryVisibility"> <i>happen-before</i></a>
+ * actions following the corresponding {@code Future.get()} in another thread.
+ *
+ * @see FutureTask
+ * @see Executor
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface Future<V> {
+
+    /**
+     * Attempts to cancel execution of this task.  This attempt will
+     * fail if the task has already completed, has already been cancelled,
+     * or could not be cancelled for some other reason. If successful,
+     * and this task has not started when {@code cancel} is called,
+     * this task should never run.  If the task has already started,
+     * then the {@code mayInterruptIfRunning} parameter determines
+     * whether the thread executing this task should be interrupted in
+     * an attempt to stop the task.
+     *
+     * <p>After this method returns, subsequent calls to {@link #isDone} will
+     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
+     * will always return {@code true} if this method returned {@code true}.
+     *
+     * @param mayInterruptIfRunning {@code true} if the thread executing this
+     * task should be interrupted; otherwise, in-progress tasks are allowed
+     * to complete
+     * @return {@code false} if the task could not be cancelled,
+     * typically because it has already completed normally;
+     * {@code true} otherwise
+     */
+    boolean cancel(boolean mayInterruptIfRunning);
+
+    /**
+     * Returns {@code true} if this task was cancelled before it completed
+     * normally.
+     *
+     * @return {@code true} if this task was cancelled before it completed
+     */
+    boolean isCancelled();
+
+    /**
+     * Returns {@code true} if this task completed.
+     *
+     * Completion may be due to normal termination, an exception, or
+     * cancellation -- in all of these cases, this method will return
+     * {@code true}.
+     *
+     * @return {@code true} if this task completed
+     */
+    boolean isDone();
+
+    /**
+     * Waits if necessary for the computation to complete, and then
+     * retrieves its result.
+     *
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     */
+    V get() throws InterruptedException, ExecutionException;
+
+    /**
+     * Waits if necessary for at most the given time for the computation
+     * to complete, and then retrieves its result, if available.
+     *
+     * @param timeout the maximum time to wait
+     * @param unit the time unit of the timeout argument
+     * @return the computed result
+     * @throws CancellationException if the computation was cancelled
+     * @throws ExecutionException if the computation threw an
+     * exception
+     * @throws InterruptedException if the current thread was interrupted
+     * while waiting
+     * @throws TimeoutException if the wait timed out
+     */
+    V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException;
+}
diff --git a/java/util/concurrent/FutureTask.java b/java/util/concurrent/FutureTask.java
new file mode 100644
index 0000000..62c2bfc
--- /dev/null
+++ b/java/util/concurrent/FutureTask.java
@@ -0,0 +1,508 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A cancellable asynchronous computation.  This class provides a base
+ * implementation of {@link Future}, with methods to start and cancel
+ * a computation, query to see if the computation is complete, and
+ * retrieve the result of the computation.  The result can only be
+ * retrieved when the computation has completed; the {@code get}
+ * methods will block if the computation has not yet completed.  Once
+ * the computation has completed, the computation cannot be restarted
+ * or cancelled (unless the computation is invoked using
+ * {@link #runAndReset}).
+ *
+ * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or
+ * {@link Runnable} object.  Because {@code FutureTask} implements
+ * {@code Runnable}, a {@code FutureTask} can be submitted to an
+ * {@link Executor} for execution.
+ *
+ * <p>In addition to serving as a standalone class, this class provides
+ * {@code protected} functionality that may be useful when creating
+ * customized task classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this FutureTask's {@code get} methods
+ */
+public class FutureTask<V> implements RunnableFuture<V> {
+    /*
+     * Revision notes: This differs from previous versions of this
+     * class that relied on AbstractQueuedSynchronizer, mainly to
+     * avoid surprising users about retaining interrupt status during
+     * cancellation races. Sync control in the current design relies
+     * on a "state" field updated via CAS to track completion, along
+     * with a simple Treiber stack to hold waiting threads.
+     *
+     * Style note: As usual, we bypass overhead of using
+     * AtomicXFieldUpdaters and instead directly use Unsafe intrinsics.
+     */
+
+    /**
+     * The run state of this task, initially NEW.  The run state
+     * transitions to a terminal state only in methods set,
+     * setException, and cancel.  During completion, state may take on
+     * transient values of COMPLETING (while outcome is being set) or
+     * INTERRUPTING (only while interrupting the runner to satisfy a
+     * cancel(true)). Transitions from these intermediate to final
+     * states use cheaper ordered/lazy writes because values are unique
+     * and cannot be further modified.
+     *
+     * Possible state transitions:
+     * NEW -> COMPLETING -> NORMAL
+     * NEW -> COMPLETING -> EXCEPTIONAL
+     * NEW -> CANCELLED
+     * NEW -> INTERRUPTING -> INTERRUPTED
+     */
+    private volatile int state;
+    private static final int NEW          = 0;
+    private static final int COMPLETING   = 1;
+    private static final int NORMAL       = 2;
+    private static final int EXCEPTIONAL  = 3;
+    private static final int CANCELLED    = 4;
+    private static final int INTERRUPTING = 5;
+    private static final int INTERRUPTED  = 6;
+
+    /** The underlying callable; nulled out after running */
+    private Callable<V> callable;
+    /** The result to return or exception to throw from get() */
+    private Object outcome; // non-volatile, protected by state reads/writes
+    /** The thread running the callable; CASed during run() */
+    private volatile Thread runner;
+    /** Treiber stack of waiting threads */
+    private volatile WaitNode waiters;
+
+    /**
+     * Returns result or throws exception for completed task.
+     *
+     * @param s completed state value
+     */
+    @SuppressWarnings("unchecked")
+    private V report(int s) throws ExecutionException {
+        Object x = outcome;
+        if (s == NORMAL)
+            return (V)x;
+        if (s >= CANCELLED)
+            throw new CancellationException();
+        throw new ExecutionException((Throwable)x);
+    }
+
+    /**
+     * Creates a {@code FutureTask} that will, upon running, execute the
+     * given {@code Callable}.
+     *
+     * @param  callable the callable task
+     * @throws NullPointerException if the callable is null
+     */
+    public FutureTask(Callable<V> callable) {
+        if (callable == null)
+            throw new NullPointerException();
+        this.callable = callable;
+        this.state = NEW;       // ensure visibility of callable
+    }
+
+    /**
+     * Creates a {@code FutureTask} that will, upon running, execute the
+     * given {@code Runnable}, and arrange that {@code get} will return the
+     * given result on successful completion.
+     *
+     * @param runnable the runnable task
+     * @param result the result to return on successful completion. If
+     * you don't need a particular result, consider using
+     * constructions of the form:
+     * {@code Future<?> f = new FutureTask<Void>(runnable, null)}
+     * @throws NullPointerException if the runnable is null
+     */
+    public FutureTask(Runnable runnable, V result) {
+        this.callable = Executors.callable(runnable, result);
+        this.state = NEW;       // ensure visibility of callable
+    }
+
+    public boolean isCancelled() {
+        return state >= CANCELLED;
+    }
+
+    public boolean isDone() {
+        return state != NEW;
+    }
+
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        if (!(state == NEW &&
+              U.compareAndSwapInt(this, STATE, NEW,
+                  mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
+            return false;
+        try {    // in case call to interrupt throws exception
+            if (mayInterruptIfRunning) {
+                try {
+                    Thread t = runner;
+                    if (t != null)
+                        t.interrupt();
+                } finally { // final state
+                    U.putOrderedInt(this, STATE, INTERRUPTED);
+                }
+            }
+        } finally {
+            finishCompletion();
+        }
+        return true;
+    }
+
+    /**
+     * @throws CancellationException {@inheritDoc}
+     */
+    public V get() throws InterruptedException, ExecutionException {
+        int s = state;
+        if (s <= COMPLETING)
+            s = awaitDone(false, 0L);
+        return report(s);
+    }
+
+    /**
+     * @throws CancellationException {@inheritDoc}
+     */
+    public V get(long timeout, TimeUnit unit)
+        throws InterruptedException, ExecutionException, TimeoutException {
+        if (unit == null)
+            throw new NullPointerException();
+        int s = state;
+        if (s <= COMPLETING &&
+            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
+            throw new TimeoutException();
+        return report(s);
+    }
+
+    /**
+     * Protected method invoked when this task transitions to state
+     * {@code isDone} (whether normally or via cancellation). The
+     * default implementation does nothing.  Subclasses may override
+     * this method to invoke completion callbacks or perform
+     * bookkeeping. Note that you can query status inside the
+     * implementation of this method to determine whether this task
+     * has been cancelled.
+     */
+    protected void done() { }
+
+    /**
+     * Sets the result of this future to the given value unless
+     * this future has already been set or has been cancelled.
+     *
+     * <p>This method is invoked internally by the {@link #run} method
+     * upon successful completion of the computation.
+     *
+     * @param v the value
+     */
+    protected void set(V v) {
+        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+            outcome = v;
+            U.putOrderedInt(this, STATE, NORMAL); // final state
+            finishCompletion();
+        }
+    }
+
+    /**
+     * Causes this future to report an {@link ExecutionException}
+     * with the given throwable as its cause, unless this future has
+     * already been set or has been cancelled.
+     *
+     * <p>This method is invoked internally by the {@link #run} method
+     * upon failure of the computation.
+     *
+     * @param t the cause of failure
+     */
+    protected void setException(Throwable t) {
+        if (U.compareAndSwapInt(this, STATE, NEW, COMPLETING)) {
+            outcome = t;
+            U.putOrderedInt(this, STATE, EXCEPTIONAL); // final state
+            finishCompletion();
+        }
+    }
+
+    public void run() {
+        if (state != NEW ||
+            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            return;
+        try {
+            Callable<V> c = callable;
+            if (c != null && state == NEW) {
+                V result;
+                boolean ran;
+                try {
+                    result = c.call();
+                    ran = true;
+                } catch (Throwable ex) {
+                    result = null;
+                    ran = false;
+                    setException(ex);
+                }
+                if (ran)
+                    set(result);
+            }
+        } finally {
+            // runner must be non-null until state is settled to
+            // prevent concurrent calls to run()
+            runner = null;
+            // state must be re-read after nulling runner to prevent
+            // leaked interrupts
+            int s = state;
+            if (s >= INTERRUPTING)
+                handlePossibleCancellationInterrupt(s);
+        }
+    }
+
+    /**
+     * Executes the computation without setting its result, and then
+     * resets this future to initial state, failing to do so if the
+     * computation encounters an exception or is cancelled.  This is
+     * designed for use with tasks that intrinsically execute more
+     * than once.
+     *
+     * @return {@code true} if successfully run and reset
+     */
+    protected boolean runAndReset() {
+        if (state != NEW ||
+            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
+            return false;
+        boolean ran = false;
+        int s = state;
+        try {
+            Callable<V> c = callable;
+            if (c != null && s == NEW) {
+                try {
+                    c.call(); // don't set result
+                    ran = true;
+                } catch (Throwable ex) {
+                    setException(ex);
+                }
+            }
+        } finally {
+            // runner must be non-null until state is settled to
+            // prevent concurrent calls to run()
+            runner = null;
+            // state must be re-read after nulling runner to prevent
+            // leaked interrupts
+            s = state;
+            if (s >= INTERRUPTING)
+                handlePossibleCancellationInterrupt(s);
+        }
+        return ran && s == NEW;
+    }
+
+    /**
+     * Ensures that any interrupt from a possible cancel(true) is only
+     * delivered to a task while in run or runAndReset.
+     */
+    private void handlePossibleCancellationInterrupt(int s) {
+        // It is possible for our interrupter to stall before getting a
+        // chance to interrupt us.  Let's spin-wait patiently.
+        if (s == INTERRUPTING)
+            while (state == INTERRUPTING)
+                Thread.yield(); // wait out pending interrupt
+
+        // assert state == INTERRUPTED;
+
+        // We want to clear any interrupt we may have received from
+        // cancel(true).  However, it is permissible to use interrupts
+        // as an independent mechanism for a task to communicate with
+        // its caller, and there is no way to clear only the
+        // cancellation interrupt.
+        //
+        // Thread.interrupted();
+    }
+
+    /**
+     * Simple linked list nodes to record waiting threads in a Treiber
+     * stack.  See other classes such as Phaser and SynchronousQueue
+     * for more detailed explanation.
+     */
+    static final class WaitNode {
+        volatile Thread thread;
+        volatile WaitNode next;
+        WaitNode() { thread = Thread.currentThread(); }
+    }
+
+    /**
+     * Removes and signals all waiting threads, invokes done(), and
+     * nulls out callable.
+     */
+    private void finishCompletion() {
+        // assert state > COMPLETING;
+        for (WaitNode q; (q = waiters) != null;) {
+            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
+                for (;;) {
+                    Thread t = q.thread;
+                    if (t != null) {
+                        q.thread = null;
+                        LockSupport.unpark(t);
+                    }
+                    WaitNode next = q.next;
+                    if (next == null)
+                        break;
+                    q.next = null; // unlink to help gc
+                    q = next;
+                }
+                break;
+            }
+        }
+
+        done();
+
+        callable = null;        // to reduce footprint
+    }
+
+    /**
+     * Awaits completion or aborts on interrupt or timeout.
+     *
+     * @param timed true if use timed waits
+     * @param nanos time to wait, if timed
+     * @return state upon completion or at timeout
+     */
+    private int awaitDone(boolean timed, long nanos)
+        throws InterruptedException {
+        // The code below is very delicate, to achieve these goals:
+        // - call nanoTime exactly once for each call to park
+        // - if nanos <= 0L, return promptly without allocation or nanoTime
+        // - if nanos == Long.MIN_VALUE, don't underflow
+        // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
+        //   and we suffer a spurious wakeup, we will do no worse than
+        //   to park-spin for a while
+        long startTime = 0L;    // Special value 0L means not yet parked
+        WaitNode q = null;
+        boolean queued = false;
+        for (;;) {
+            int s = state;
+            if (s > COMPLETING) {
+                if (q != null)
+                    q.thread = null;
+                return s;
+            }
+            else if (s == COMPLETING)
+                // We may have already promised (via isDone) that we are done
+                // so never return empty-handed or throw InterruptedException
+                Thread.yield();
+            else if (Thread.interrupted()) {
+                removeWaiter(q);
+                throw new InterruptedException();
+            }
+            else if (q == null) {
+                if (timed && nanos <= 0L)
+                    return s;
+                q = new WaitNode();
+            }
+            else if (!queued)
+                queued = U.compareAndSwapObject(this, WAITERS,
+                                                q.next = waiters, q);
+            else if (timed) {
+                final long parkNanos;
+                if (startTime == 0L) { // first time
+                    startTime = System.nanoTime();
+                    if (startTime == 0L)
+                        startTime = 1L;
+                    parkNanos = nanos;
+                } else {
+                    long elapsed = System.nanoTime() - startTime;
+                    if (elapsed >= nanos) {
+                        removeWaiter(q);
+                        return state;
+                    }
+                    parkNanos = nanos - elapsed;
+                }
+                // nanoTime may be slow; recheck before parking
+                if (state < COMPLETING)
+                    LockSupport.parkNanos(this, parkNanos);
+            }
+            else
+                LockSupport.park(this);
+        }
+    }
+
+    /**
+     * Tries to unlink a timed-out or interrupted wait node to avoid
+     * accumulating garbage.  Internal nodes are simply unspliced
+     * without CAS since it is harmless if they are traversed anyway
+     * by releasers.  To avoid effects of unsplicing from already
+     * removed nodes, the list is retraversed in case of an apparent
+     * race.  This is slow when there are a lot of nodes, but we don't
+     * expect lists to be long enough to outweigh higher-overhead
+     * schemes.
+     */
+    private void removeWaiter(WaitNode node) {
+        if (node != null) {
+            node.thread = null;
+            retry:
+            for (;;) {          // restart on removeWaiter race
+                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
+                    s = q.next;
+                    if (q.thread != null)
+                        pred = q;
+                    else if (pred != null) {
+                        pred.next = s;
+                        if (pred.thread == null) // check for race
+                            continue retry;
+                    }
+                    else if (!U.compareAndSwapObject(this, WAITERS, q, s))
+                        continue retry;
+                }
+                break;
+            }
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long RUNNER;
+    private static final long WAITERS;
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("state"));
+            RUNNER = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("runner"));
+            WAITERS = U.objectFieldOffset
+                (FutureTask.class.getDeclaredField("waiters"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+}
diff --git a/java/util/concurrent/Helpers.java b/java/util/concurrent/Helpers.java
new file mode 100644
index 0000000..369da0e
--- /dev/null
+++ b/java/util/concurrent/Helpers.java
@@ -0,0 +1,118 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+
+/** Shared implementation code for java.util.concurrent. */
+class Helpers {
+    private Helpers() {}                // non-instantiable
+
+    /**
+     * An implementation of Collection.toString() suitable for classes
+     * with locks.  Instead of holding a lock for the entire duration of
+     * toString(), or acquiring a lock for each call to Iterator.next(),
+     * we hold the lock only during the call to toArray() (less
+     * disruptive to other threads accessing the collection) and follows
+     * the maxim "Never call foreign code while holding a lock".
+     */
+    static String collectionToString(Collection<?> c) {
+        final Object[] a = c.toArray();
+        final int size = a.length;
+        if (size == 0)
+            return "[]";
+        int charLength = 0;
+
+        // Replace every array element with its string representation
+        for (int i = 0; i < size; i++) {
+            Object e = a[i];
+            // Extreme compatibility with AbstractCollection.toString()
+            String s = (e == c) ? "(this Collection)" : objectToString(e);
+            a[i] = s;
+            charLength += s.length();
+        }
+
+        return toString(a, size, charLength);
+    }
+
+    /**
+     * Like Arrays.toString(), but caller guarantees that size > 0,
+     * each element with index 0 <= i < size is a non-null String,
+     * and charLength is the sum of the lengths of the input Strings.
+     */
+    static String toString(Object[] a, int size, int charLength) {
+        // assert a != null;
+        // assert size > 0;
+
+        // Copy each string into a perfectly sized char[]
+        // Length of [ , , , ] == 2 * size
+        final char[] chars = new char[charLength + 2 * size];
+        chars[0] = '[';
+        int j = 1;
+        for (int i = 0; i < size; i++) {
+            if (i > 0) {
+                chars[j++] = ',';
+                chars[j++] = ' ';
+            }
+            String s = (String) a[i];
+            int len = s.length();
+            s.getChars(0, len, chars, j);
+            j += len;
+        }
+        chars[j] = ']';
+        // assert j == chars.length - 1;
+        return new String(chars);
+    }
+
+    /** Optimized form of: key + "=" + val */
+    static String mapEntryToString(Object key, Object val) {
+        final String k, v;
+        final int klen, vlen;
+        final char[] chars =
+            new char[(klen = (k = objectToString(key)).length()) +
+                     (vlen = (v = objectToString(val)).length()) + 1];
+        k.getChars(0, klen, chars, 0);
+        chars[klen] = '=';
+        v.getChars(0, vlen, chars, klen + 1);
+        return new String(chars);
+    }
+
+    private static String objectToString(Object x) {
+        // Extreme compatibility with StringBuilder.append(null)
+        String s;
+        return (x == null || (s = x.toString()) == null) ? "null" : s;
+    }
+}
diff --git a/java/util/concurrent/LinkedBlockingDeque.java b/java/util/concurrent/LinkedBlockingDeque.java
new file mode 100644
index 0000000..9829c9c
--- /dev/null
+++ b/java/util/concurrent/LinkedBlockingDeque.java
@@ -0,0 +1,1315 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An optionally-bounded {@linkplain BlockingDeque blocking deque} based on
+ * linked nodes.
+ *
+ * <p>The optional capacity bound constructor argument serves as a
+ * way to prevent excessive expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * deque above capacity.
+ *
+ * <p>Most operations run in constant time (ignoring time spent
+ * blocking).  Exceptions include {@link #remove(Object) remove},
+ * {@link #removeFirstOccurrence removeFirstOccurrence}, {@link
+ * #removeLastOccurrence removeLastOccurrence}, {@link #contains
+ * contains}, {@link #iterator iterator.remove()}, and the bulk
+ * operations, all of which run in linear time.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.6
+ * @author  Doug Lea
+ * @param <E> the type of elements held in this deque
+ */
+public class LinkedBlockingDeque<E>
+    extends AbstractQueue<E>
+    implements BlockingDeque<E>, java.io.Serializable {
+
+    /*
+     * Implemented as a simple doubly-linked list protected by a
+     * single lock and using conditions to manage blocking.
+     *
+     * To implement weakly consistent iterators, it appears we need to
+     * keep all Nodes GC-reachable from a predecessor dequeued Node.
+     * That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to jump to "first" (for next links)
+     * or "last" (for prev links).
+     */
+
+    /*
+     * We have "diamond" multiple interface/abstract class inheritance
+     * here, and that introduces ambiguities. Often we want the
+     * BlockingDeque javadoc combined with the AbstractQueue
+     * implementation, so a lot of method specs are duplicated here.
+     */
+
+    private static final long serialVersionUID = -387911632671998426L;
+
+    /** Doubly-linked list node class */
+    static final class Node<E> {
+        /**
+         * The item, or null if this node has been removed.
+         */
+        E item;
+
+        /**
+         * One of:
+         * - the real predecessor Node
+         * - this Node, meaning the predecessor is tail
+         * - null, meaning there is no predecessor
+         */
+        Node<E> prev;
+
+        /**
+         * One of:
+         * - the real successor Node
+         * - this Node, meaning the successor is head
+         * - null, meaning there is no successor
+         */
+        Node<E> next;
+
+        Node(E x) {
+            item = x;
+        }
+    }
+
+    /**
+     * Pointer to first node.
+     * Invariant: (first == null && last == null) ||
+     *            (first.prev == null && first.item != null)
+     */
+    transient Node<E> first;
+
+    /**
+     * Pointer to last node.
+     * Invariant: (first == null && last == null) ||
+     *            (last.next == null && last.item != null)
+     */
+    transient Node<E> last;
+
+    /** Number of items in the deque */
+    private transient int count;
+
+    /** Maximum number of items in the deque */
+    private final int capacity;
+
+    /** Main lock guarding all access */
+    final ReentrantLock lock = new ReentrantLock();
+
+    /** Condition for waiting takes */
+    private final Condition notEmpty = lock.newCondition();
+
+    /** Condition for waiting puts */
+    private final Condition notFull = lock.newCondition();
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with a capacity of
+     * {@link Integer#MAX_VALUE}.
+     */
+    public LinkedBlockingDeque() {
+        this(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with the given (fixed) capacity.
+     *
+     * @param capacity the capacity of this deque
+     * @throws IllegalArgumentException if {@code capacity} is less than 1
+     */
+    public LinkedBlockingDeque(int capacity) {
+        if (capacity <= 0) throw new IllegalArgumentException();
+        this.capacity = capacity;
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingDeque} with a capacity of
+     * {@link Integer#MAX_VALUE}, initially containing the elements of
+     * the given collection, added in traversal order of the
+     * collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedBlockingDeque(Collection<? extends E> c) {
+        this(Integer.MAX_VALUE);
+        final ReentrantLock lock = this.lock;
+        lock.lock(); // Never contended, but necessary for visibility
+        try {
+            for (E e : c) {
+                if (e == null)
+                    throw new NullPointerException();
+                if (!linkLast(new Node<E>(e)))
+                    throw new IllegalStateException("Deque full");
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+
+    // Basic linking and unlinking operations, called only while holding lock
+
+    /**
+     * Links node as first element, or returns false if full.
+     */
+    private boolean linkFirst(Node<E> node) {
+        // assert lock.isHeldByCurrentThread();
+        if (count >= capacity)
+            return false;
+        Node<E> f = first;
+        node.next = f;
+        first = node;
+        if (last == null)
+            last = node;
+        else
+            f.prev = node;
+        ++count;
+        notEmpty.signal();
+        return true;
+    }
+
+    /**
+     * Links node as last element, or returns false if full.
+     */
+    private boolean linkLast(Node<E> node) {
+        // assert lock.isHeldByCurrentThread();
+        if (count >= capacity)
+            return false;
+        Node<E> l = last;
+        node.prev = l;
+        last = node;
+        if (first == null)
+            first = node;
+        else
+            l.next = node;
+        ++count;
+        notEmpty.signal();
+        return true;
+    }
+
+    /**
+     * Removes and returns first element, or null if empty.
+     */
+    private E unlinkFirst() {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> f = first;
+        if (f == null)
+            return null;
+        Node<E> n = f.next;
+        E item = f.item;
+        f.item = null;
+        f.next = f; // help GC
+        first = n;
+        if (n == null)
+            last = null;
+        else
+            n.prev = null;
+        --count;
+        notFull.signal();
+        return item;
+    }
+
+    /**
+     * Removes and returns last element, or null if empty.
+     */
+    private E unlinkLast() {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> l = last;
+        if (l == null)
+            return null;
+        Node<E> p = l.prev;
+        E item = l.item;
+        l.item = null;
+        l.prev = l; // help GC
+        last = p;
+        if (p == null)
+            first = null;
+        else
+            p.next = null;
+        --count;
+        notFull.signal();
+        return item;
+    }
+
+    /**
+     * Unlinks x.
+     */
+    void unlink(Node<E> x) {
+        // assert lock.isHeldByCurrentThread();
+        Node<E> p = x.prev;
+        Node<E> n = x.next;
+        if (p == null) {
+            unlinkFirst();
+        } else if (n == null) {
+            unlinkLast();
+        } else {
+            p.next = n;
+            n.prev = p;
+            x.item = null;
+            // Don't mess with x's links.  They may still be in use by
+            // an iterator.
+            --count;
+            notFull.signal();
+        }
+    }
+
+    // BlockingDeque methods
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void addFirst(E e) {
+        if (!offerFirst(e))
+            throw new IllegalStateException("Deque full");
+    }
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException  {@inheritDoc}
+     */
+    public void addLast(E e) {
+        if (!offerLast(e))
+            throw new IllegalStateException("Deque full");
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offerFirst(E e) {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return linkFirst(node);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offerLast(E e) {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return linkLast(node);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void putFirst(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            while (!linkFirst(node))
+                notFull.await();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void putLast(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            while (!linkLast(node))
+                notFull.await();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offerFirst(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (!linkFirst(node)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offerLast(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        Node<E> node = new Node<E>(e);
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            while (!linkLast(node)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeFirst() {
+        E x = pollFirst();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E removeLast() {
+        E x = pollLast();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    public E pollFirst() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return unlinkFirst();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollLast() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return unlinkLast();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E takeFirst() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E x;
+            while ( (x = unlinkFirst()) == null)
+                notEmpty.await();
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E takeLast() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            E x;
+            while ( (x = unlinkLast()) == null)
+                notEmpty.await();
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollFirst(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            E x;
+            while ( (x = unlinkFirst()) == null) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E pollLast(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        try {
+            E x;
+            while ( (x = unlinkLast()) == null) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            return x;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getFirst() {
+        E x = peekFirst();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E getLast() {
+        E x = peekLast();
+        if (x == null) throw new NoSuchElementException();
+        return x;
+    }
+
+    public E peekFirst() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (first == null) ? null : first.item;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E peekLast() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (last == null) ? null : last.item;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean removeFirstOccurrence(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = first; p != null; p = p.next) {
+                if (o.equals(p.item)) {
+                    unlink(p);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public boolean removeLastOccurrence(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = last; p != null; p = p.prev) {
+                if (o.equals(p.item)) {
+                    unlink(p);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // BlockingQueue methods
+
+    /**
+     * Inserts the specified element at the end of this deque unless it would
+     * violate capacity restrictions.  When using a capacity-restricted deque,
+     * it is generally preferable to use method {@link #offer(Object) offer}.
+     *
+     * <p>This method is equivalent to {@link #addLast}.
+     *
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        addLast(e);
+        return true;
+    }
+
+    /**
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        return offerLast(e);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        putLast(e);
+    }
+
+    /**
+     * @throws NullPointerException {@inheritDoc}
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return offerLast(e, timeout, unit);
+    }
+
+    /**
+     * Retrieves and removes the head of the queue represented by this deque.
+     * This method differs from {@link #poll poll} only in that it throws an
+     * exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #removeFirst() removeFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    public E remove() {
+        return removeFirst();
+    }
+
+    public E poll() {
+        return pollFirst();
+    }
+
+    public E take() throws InterruptedException {
+        return takeFirst();
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        return pollFirst(timeout, unit);
+    }
+
+    /**
+     * Retrieves, but does not remove, the head of the queue represented by
+     * this deque.  This method differs from {@link #peek peek} only in that
+     * it throws an exception if this deque is empty.
+     *
+     * <p>This method is equivalent to {@link #getFirst() getFirst}.
+     *
+     * @return the head of the queue represented by this deque
+     * @throws NoSuchElementException if this deque is empty
+     */
+    public E element() {
+        return getFirst();
+    }
+
+    public E peek() {
+        return peekFirst();
+    }
+
+    /**
+     * Returns the number of additional elements that this deque can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this deque
+     * less the current {@code size} of this deque.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return capacity - count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(maxElements, count);
+            for (int i = 0; i < n; i++) {
+                c.add(first.item);   // In this order, in case add() throws.
+                unlinkFirst();
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    // Stack methods
+
+    /**
+     * @throws IllegalStateException if this deque is full
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void push(E e) {
+        addFirst(e);
+    }
+
+    /**
+     * @throws NoSuchElementException {@inheritDoc}
+     */
+    public E pop() {
+        return removeFirst();
+    }
+
+    // Collection methods
+
+    /**
+     * Removes the first occurrence of the specified element from this deque.
+     * If the deque does not contain the element, it is unchanged.
+     * More formally, removes the first element {@code e} such that
+     * {@code o.equals(e)} (if such an element exists).
+     * Returns {@code true} if this deque contained the specified element
+     * (or equivalently, if this deque changed as a result of the call).
+     *
+     * <p>This method is equivalent to
+     * {@link #removeFirstOccurrence(Object) removeFirstOccurrence}.
+     *
+     * @param o element to be removed from this deque, if present
+     * @return {@code true} if this deque changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        return removeFirstOccurrence(o);
+    }
+
+    /**
+     * Returns the number of elements in this deque.
+     *
+     * @return the number of elements in this deque
+     */
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return count;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this deque contains the specified element.
+     * More formally, returns {@code true} if and only if this deque contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this deque
+     * @return {@code true} if this deque contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> p = first; p != null; p = p.next)
+                if (o.equals(p.item))
+                    return true;
+            return false;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /*
+     * TODO: Add support for more efficient bulk operations.
+     *
+     * We don't want to acquire the lock for every iteration, but we
+     * also want other threads a chance to interact with the
+     * collection, especially when count is close to capacity.
+     */
+
+//     /**
+//      * Adds all of the elements in the specified collection to this
+//      * queue.  Attempts to addAll of a queue to itself result in
+//      * {@code IllegalArgumentException}. Further, the behavior of
+//      * this operation is undefined if the specified collection is
+//      * modified while the operation is in progress.
+//      *
+//      * @param c collection containing elements to be added to this queue
+//      * @return {@code true} if this queue changed as a result of the call
+//      * @throws ClassCastException            {@inheritDoc}
+//      * @throws NullPointerException          {@inheritDoc}
+//      * @throws IllegalArgumentException      {@inheritDoc}
+//      * @throws IllegalStateException if this deque is full
+//      * @see #add(Object)
+//      */
+//     public boolean addAll(Collection<? extends E> c) {
+//         if (c == null)
+//             throw new NullPointerException();
+//         if (c == this)
+//             throw new IllegalArgumentException();
+//         final ReentrantLock lock = this.lock;
+//         lock.lock();
+//         try {
+//             boolean modified = false;
+//             for (E e : c)
+//                 if (linkLast(e))
+//                     modified = true;
+//             return modified;
+//         } finally {
+//             lock.unlock();
+//         }
+//     }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence (from first to last element).
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this deque.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this deque
+     */
+    @SuppressWarnings("unchecked")
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] a = new Object[count];
+            int k = 0;
+            for (Node<E> p = first; p != null; p = p.next)
+                a[k++] = p.item;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this deque, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the deque fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this deque.
+     *
+     * <p>If this deque fits in the specified array with room to spare
+     * (i.e., the array has more elements than this deque), the element in
+     * the array immediately following the end of the deque is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a deque known to contain only strings.
+     * The following code can be used to dump the deque into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the deque are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this deque
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this deque
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            if (a.length < count)
+                a = (T[])java.lang.reflect.Array.newInstance
+                    (a.getClass().getComponentType(), count);
+
+            int k = 0;
+            for (Node<E> p = first; p != null; p = p.next)
+                a[k++] = (T)p.item;
+            if (a.length > k)
+                a[k] = null;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this deque.
+     * The deque will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            for (Node<E> f = first; f != null; ) {
+                f.item = null;
+                Node<E> n = f.next;
+                f.prev = null;
+                f.next = null;
+                f = n;
+            }
+            first = last = null;
+            count = 0;
+            notFull.signalAll();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    /**
+     * Returns an iterator over the elements in this deque in reverse
+     * sequential order.  The elements will be returned in order from
+     * last (tail) to first (head).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this deque in reverse order
+     */
+    public Iterator<E> descendingIterator() {
+        return new DescendingItr();
+    }
+
+    /**
+     * Base class for LinkedBlockingDeque iterators.
+     */
+    private abstract class AbstractItr implements Iterator<E> {
+        /**
+         * The next node to return in next().
+         */
+        Node<E> next;
+
+        /**
+         * nextItem holds on to item fields because once we claim that
+         * an element exists in hasNext(), we must return item read
+         * under lock (in advance()) even if it was in the process of
+         * being removed when hasNext() was called.
+         */
+        E nextItem;
+
+        /**
+         * Node returned by most recent call to next. Needed by remove.
+         * Reset to null if this element is deleted by a call to remove.
+         */
+        private Node<E> lastRet;
+
+        abstract Node<E> firstNode();
+        abstract Node<E> nextNode(Node<E> n);
+
+        AbstractItr() {
+            // set to initial position
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                next = firstNode();
+                nextItem = (next == null) ? null : next.item;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        /**
+         * Returns the successor node of the given non-null, but
+         * possibly previously deleted, node.
+         */
+        private Node<E> succ(Node<E> n) {
+            // Chains of deleted nodes ending in null or self-links
+            // are possible if multiple interior nodes are removed.
+            for (;;) {
+                Node<E> s = nextNode(n);
+                if (s == null)
+                    return null;
+                else if (s.item != null)
+                    return s;
+                else if (s == n)
+                    return firstNode();
+                else
+                    n = s;
+            }
+        }
+
+        /**
+         * Advances next.
+         */
+        void advance() {
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                // assert next != null;
+                next = succ(next);
+                nextItem = (next == null) ? null : next.item;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean hasNext() {
+            return next != null;
+        }
+
+        public E next() {
+            if (next == null)
+                throw new NoSuchElementException();
+            lastRet = next;
+            E x = nextItem;
+            advance();
+            return x;
+        }
+
+        public void remove() {
+            Node<E> n = lastRet;
+            if (n == null)
+                throw new IllegalStateException();
+            lastRet = null;
+            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
+            lock.lock();
+            try {
+                if (n.item != null)
+                    unlink(n);
+            } finally {
+                lock.unlock();
+            }
+        }
+    }
+
+    /** Forward iterator */
+    private class Itr extends AbstractItr {
+        Node<E> firstNode() { return first; }
+        Node<E> nextNode(Node<E> n) { return n.next; }
+    }
+
+    /** Descending iterator */
+    private class DescendingItr extends AbstractItr {
+        Node<E> firstNode() { return last; }
+        Node<E> nextNode(Node<E> n) { return n.prev; }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LBDSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedBlockingDeque<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        long est;           // size estimate
+        LBDSpliterator(LinkedBlockingDeque<E> queue) {
+            this.queue = queue;
+            this.est = queue.size();
+        }
+
+        public long estimateSize() { return est; }
+
+        public Spliterator<E> trySplit() {
+            Node<E> h;
+            final LinkedBlockingDeque<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((h = current) != null || (h = q.first) != null) &&
+                h.next != null) {
+                Object[] a = new Object[n];
+                final ReentrantLock lock = q.lock;
+                int i = 0;
+                Node<E> p = current;
+                lock.lock();
+                try {
+                    if (p != null || (p = q.first) != null) {
+                        do {
+                            if ((a[i] = p.item) != null)
+                                ++i;
+                        } while ((p = p.next) != null && i < n);
+                    }
+                } finally {
+                    lock.unlock();
+                }
+                if ((current = p) == null) {
+                    est = 0L;
+                    exhausted = true;
+                }
+                else if ((est -= i) < 0L)
+                    est = 0L;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingDeque<E> q = this.queue;
+            final ReentrantLock lock = q.lock;
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                do {
+                    E e = null;
+                    lock.lock();
+                    try {
+                        if (p == null)
+                            p = q.first;
+                        while (p != null) {
+                            e = p.item;
+                            p = p.next;
+                            if (e != null)
+                                break;
+                        }
+                    } finally {
+                        lock.unlock();
+                    }
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingDeque<E> q = this.queue;
+            final ReentrantLock lock = q.lock;
+            if (!exhausted) {
+                E e = null;
+                lock.lock();
+                try {
+                    if (current == null)
+                        current = q.first;
+                    while (current != null) {
+                        e = current.item;
+                        current = current.next;
+                        if (e != null)
+                            break;
+                    }
+                } finally {
+                    lock.unlock();
+                }
+                if (current == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LBDSpliterator<E>(this);
+    }
+
+    /**
+     * Saves this deque to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The capacity (int), followed by elements (each an
+     * {@code Object}) in the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            // Write out capacity and any hidden stuff
+            s.defaultWriteObject();
+            // Write out all elements in the proper order.
+            for (Node<E> p = first; p != null; p = p.next)
+                s.writeObject(p.item);
+            // Use trailing null as sentinel
+            s.writeObject(null);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this deque from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        count = 0;
+        first = null;
+        last = null;
+        // Read in all elements and place in queue
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E)s.readObject();
+            if (item == null)
+                break;
+            add(item);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/LinkedBlockingQueue.java b/java/util/concurrent/LinkedBlockingQueue.java
new file mode 100644
index 0000000..cf2d447
--- /dev/null
+++ b/java/util/concurrent/LinkedBlockingQueue.java
@@ -0,0 +1,1015 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An optionally-bounded {@linkplain BlockingQueue blocking queue} based on
+ * linked nodes.
+ * This queue orders elements FIFO (first-in-first-out).
+ * The <em>head</em> of the queue is that element that has been on the
+ * queue the longest time.
+ * The <em>tail</em> of the queue is that element that has been on the
+ * queue the shortest time. New elements
+ * are inserted at the tail of the queue, and the queue retrieval
+ * operations obtain elements at the head of the queue.
+ * Linked queues typically have higher throughput than array-based queues but
+ * less predictable performance in most concurrent applications.
+ *
+ * <p>The optional capacity bound constructor argument serves as a
+ * way to prevent excessive queue expansion. The capacity, if unspecified,
+ * is equal to {@link Integer#MAX_VALUE}.  Linked nodes are
+ * dynamically created upon each insertion unless this would bring the
+ * queue above capacity.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class LinkedBlockingQueue<E> extends AbstractQueue<E>
+        implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -6903933977591709194L;
+
+    /*
+     * A variant of the "two lock queue" algorithm.  The putLock gates
+     * entry to put (and offer), and has an associated condition for
+     * waiting puts.  Similarly for the takeLock.  The "count" field
+     * that they both rely on is maintained as an atomic to avoid
+     * needing to get both locks in most cases. Also, to minimize need
+     * for puts to get takeLock and vice-versa, cascading notifies are
+     * used. When a put notices that it has enabled at least one take,
+     * it signals taker. That taker in turn signals others if more
+     * items have been entered since the signal. And symmetrically for
+     * takes signalling puts. Operations such as remove(Object) and
+     * iterators acquire both locks.
+     *
+     * Visibility between writers and readers is provided as follows:
+     *
+     * Whenever an element is enqueued, the putLock is acquired and
+     * count updated.  A subsequent reader guarantees visibility to the
+     * enqueued Node by either acquiring the putLock (via fullyLock)
+     * or by acquiring the takeLock, and then reading n = count.get();
+     * this gives visibility to the first n items.
+     *
+     * To implement weakly consistent iterators, it appears we need to
+     * keep all Nodes GC-reachable from a predecessor dequeued Node.
+     * That would cause two problems:
+     * - allow a rogue Iterator to cause unbounded memory retention
+     * - cause cross-generational linking of old Nodes to new Nodes if
+     *   a Node was tenured while live, which generational GCs have a
+     *   hard time dealing with, causing repeated major collections.
+     * However, only non-deleted Nodes need to be reachable from
+     * dequeued Nodes, and reachability does not necessarily have to
+     * be of the kind understood by the GC.  We use the trick of
+     * linking a Node that has just been dequeued to itself.  Such a
+     * self-link implicitly means to advance to head.next.
+     */
+
+    /**
+     * Linked list node class.
+     */
+    static class Node<E> {
+        E item;
+
+        /**
+         * One of:
+         * - the real successor Node
+         * - this Node, meaning the successor is head.next
+         * - null, meaning there is no successor (this is the last node)
+         */
+        Node<E> next;
+
+        Node(E x) { item = x; }
+    }
+
+    /** The capacity bound, or Integer.MAX_VALUE if none */
+    private final int capacity;
+
+    /** Current number of elements */
+    private final AtomicInteger count = new AtomicInteger();
+
+    /**
+     * Head of linked list.
+     * Invariant: head.item == null
+     */
+    transient Node<E> head;
+
+    /**
+     * Tail of linked list.
+     * Invariant: last.next == null
+     */
+    private transient Node<E> last;
+
+    /** Lock held by take, poll, etc */
+    private final ReentrantLock takeLock = new ReentrantLock();
+
+    /** Wait queue for waiting takes */
+    private final Condition notEmpty = takeLock.newCondition();
+
+    /** Lock held by put, offer, etc */
+    private final ReentrantLock putLock = new ReentrantLock();
+
+    /** Wait queue for waiting puts */
+    private final Condition notFull = putLock.newCondition();
+
+    /**
+     * Signals a waiting take. Called only from put/offer (which do not
+     * otherwise ordinarily lock takeLock.)
+     */
+    private void signalNotEmpty() {
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Signals a waiting put. Called only from take/poll.
+     */
+    private void signalNotFull() {
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    /**
+     * Links node at end of queue.
+     *
+     * @param node the node
+     */
+    private void enqueue(Node<E> node) {
+        // assert putLock.isHeldByCurrentThread();
+        // assert last.next == null;
+        last = last.next = node;
+    }
+
+    /**
+     * Removes a node from head of queue.
+     *
+     * @return the node
+     */
+    private E dequeue() {
+        // assert takeLock.isHeldByCurrentThread();
+        // assert head.item == null;
+        Node<E> h = head;
+        Node<E> first = h.next;
+        h.next = h; // help GC
+        head = first;
+        E x = first.item;
+        first.item = null;
+        return x;
+    }
+
+    /**
+     * Locks to prevent both puts and takes.
+     */
+    void fullyLock() {
+        putLock.lock();
+        takeLock.lock();
+    }
+
+    /**
+     * Unlocks to allow both puts and takes.
+     */
+    void fullyUnlock() {
+        takeLock.unlock();
+        putLock.unlock();
+    }
+
+//     /**
+//      * Tells whether both locks are held by current thread.
+//      */
+//     boolean isFullyLocked() {
+//         return (putLock.isHeldByCurrentThread() &&
+//                 takeLock.isHeldByCurrentThread());
+//     }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with a capacity of
+     * {@link Integer#MAX_VALUE}.
+     */
+    public LinkedBlockingQueue() {
+        this(Integer.MAX_VALUE);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
+     *
+     * @param capacity the capacity of this queue
+     * @throws IllegalArgumentException if {@code capacity} is not greater
+     *         than zero
+     */
+    public LinkedBlockingQueue(int capacity) {
+        if (capacity <= 0) throw new IllegalArgumentException();
+        this.capacity = capacity;
+        last = head = new Node<E>(null);
+    }
+
+    /**
+     * Creates a {@code LinkedBlockingQueue} with a capacity of
+     * {@link Integer#MAX_VALUE}, initially containing the elements of the
+     * given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedBlockingQueue(Collection<? extends E> c) {
+        this(Integer.MAX_VALUE);
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock(); // Never contended, but necessary for visibility
+        try {
+            int n = 0;
+            for (E e : c) {
+                if (e == null)
+                    throw new NullPointerException();
+                if (n == capacity)
+                    throw new IllegalStateException("Queue full");
+                enqueue(new Node<E>(e));
+                ++n;
+            }
+            count.set(n);
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    // this doc comment is overridden to remove the reference to collections
+    // greater in size than Integer.MAX_VALUE
+    /**
+     * Returns the number of elements in this queue.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        return count.get();
+    }
+
+    // this doc comment is a modified copy of the inherited doc comment,
+    // without the reference to unlimited queues.
+    /**
+     * Returns the number of additional elements that this queue can ideally
+     * (in the absence of memory or resource constraints) accept without
+     * blocking. This is always equal to the initial capacity of this queue
+     * less the current {@code size} of this queue.
+     *
+     * <p>Note that you <em>cannot</em> always tell if an attempt to insert
+     * an element will succeed by inspecting {@code remainingCapacity}
+     * because it may be the case that another thread is about to
+     * insert or remove an element.
+     */
+    public int remainingCapacity() {
+        return capacity - count.get();
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting if
+     * necessary for space to become available.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        // Note: convention in all put/take/etc is to preset local var
+        // holding count negative to indicate failure unless set.
+        int c = -1;
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            /*
+             * Note that count is used in wait guard even though it is
+             * not protected by lock. This works because count can
+             * only decrease at this point (all other puts are shut
+             * out by lock), and we (or some other waiting put) are
+             * signalled if it ever changes from capacity. Similarly
+             * for all other uses of count in other wait guards.
+             */
+            while (count.get() == capacity) {
+                notFull.await();
+            }
+            enqueue(node);
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue, waiting if
+     * necessary up to the specified wait time for space to become available.
+     *
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before space is available
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+
+        if (e == null) throw new NullPointerException();
+        long nanos = unit.toNanos(timeout);
+        int c = -1;
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            while (count.get() == capacity) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            enqueue(new Node<E>(e));
+            c = count.getAndIncrement();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue if it is
+     * possible to do so immediately without exceeding the queue's capacity,
+     * returning {@code true} upon success and {@code false} if this queue
+     * is full.
+     * When using a capacity-restricted queue, this method is generally
+     * preferable to method {@link BlockingQueue#add add}, which can fail to
+     * insert an element only by throwing an exception.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        final AtomicInteger count = this.count;
+        if (count.get() == capacity)
+            return false;
+        int c = -1;
+        Node<E> node = new Node<E>(e);
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            if (count.get() < capacity) {
+                enqueue(node);
+                c = count.getAndIncrement();
+                if (c + 1 < capacity)
+                    notFull.signal();
+            }
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return c >= 0;
+    }
+
+    public E take() throws InterruptedException {
+        E x;
+        int c = -1;
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                notEmpty.await();
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E x = null;
+        int c = -1;
+        long nanos = unit.toNanos(timeout);
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                if (nanos <= 0L)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E poll() {
+        final AtomicInteger count = this.count;
+        if (count.get() == 0)
+            return null;
+        E x = null;
+        int c = -1;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            if (count.get() > 0) {
+                x = dequeue();
+                c = count.getAndDecrement();
+                if (c > 1)
+                    notEmpty.signal();
+            }
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    public E peek() {
+        if (count.get() == 0)
+            return null;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            return (count.get() > 0) ? head.next.item : null;
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Unlinks interior Node p with predecessor trail.
+     */
+    void unlink(Node<E> p, Node<E> trail) {
+        // assert isFullyLocked();
+        // p.next is not changed, to allow iterators that are
+        // traversing p to maintain their weak-consistency guarantee.
+        p.item = null;
+        trail.next = p.next;
+        if (last == p)
+            last = trail;
+        if (count.getAndDecrement() == capacity)
+            notFull.signal();
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        if (o == null) return false;
+        fullyLock();
+        try {
+            for (Node<E> trail = head, p = trail.next;
+                 p != null;
+                 trail = p, p = p.next) {
+                if (o.equals(p.item)) {
+                    unlink(p, trail);
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o == null) return false;
+        fullyLock();
+        try {
+            for (Node<E> p = head.next; p != null; p = p.next)
+                if (o.equals(p.item))
+                    return true;
+            return false;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        fullyLock();
+        try {
+            int size = count.get();
+            Object[] a = new Object[size];
+            int k = 0;
+            for (Node<E> p = head.next; p != null; p = p.next)
+                a[k++] = p.item;
+            return a;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        fullyLock();
+        try {
+            int size = count.get();
+            if (a.length < size)
+                a = (T[])java.lang.reflect.Array.newInstance
+                    (a.getClass().getComponentType(), size);
+
+            int k = 0;
+            for (Node<E> p = head.next; p != null; p = p.next)
+                a[k++] = (T)p.item;
+            if (a.length > k)
+                a[k] = null;
+            return a;
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        fullyLock();
+        try {
+            for (Node<E> p, h = head; (p = h.next) != null; h = p) {
+                h.next = h;
+                p.item = null;
+            }
+            head = last;
+            // assert head.item == null && head.next == null;
+            if (count.getAndSet(0) == capacity)
+                notFull.signal();
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        boolean signalNotFull = false;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            int n = Math.min(maxElements, count.get());
+            // count.get provides visibility to first n Nodes
+            Node<E> h = head;
+            int i = 0;
+            try {
+                while (i < n) {
+                    Node<E> p = h.next;
+                    c.add(p.item);
+                    p.item = null;
+                    h.next = h;
+                    h = p;
+                    ++i;
+                }
+                return n;
+            } finally {
+                // Restore invariants even if c.add() threw
+                if (i > 0) {
+                    // assert h.item == null;
+                    head = h;
+                    signalNotFull = (count.getAndAdd(-i) == capacity);
+                }
+            }
+        } finally {
+            takeLock.unlock();
+            if (signalNotFull)
+                signalNotFull();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    private class Itr implements Iterator<E> {
+        /*
+         * Basic weakly-consistent iterator.  At all times hold the next
+         * item to hand out so that if hasNext() reports true, we will
+         * still have it to return even if lost race with a take etc.
+         */
+
+        private Node<E> current;
+        private Node<E> lastRet;
+        private E currentElement;
+
+        Itr() {
+            fullyLock();
+            try {
+                current = head.next;
+                if (current != null)
+                    currentElement = current.item;
+            } finally {
+                fullyUnlock();
+            }
+        }
+
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        public E next() {
+            fullyLock();
+            try {
+                if (current == null)
+                    throw new NoSuchElementException();
+                lastRet = current;
+                E item = null;
+                // Unlike other traversal methods, iterators must handle both:
+                // - dequeued nodes (p.next == p)
+                // - (possibly multiple) interior removed nodes (p.item == null)
+                for (Node<E> p = current, q;; p = q) {
+                    if ((q = p.next) == p)
+                        q = head.next;
+                    if (q == null || (item = q.item) != null) {
+                        current = q;
+                        E x = currentElement;
+                        currentElement = item;
+                        return x;
+                    }
+                }
+            } finally {
+                fullyUnlock();
+            }
+        }
+
+        public void remove() {
+            if (lastRet == null)
+                throw new IllegalStateException();
+            fullyLock();
+            try {
+                Node<E> node = lastRet;
+                lastRet = null;
+                for (Node<E> trail = head, p = trail.next;
+                     p != null;
+                     trail = p, p = p.next) {
+                    if (p == node) {
+                        unlink(p, trail);
+                        break;
+                    }
+                }
+            } finally {
+                fullyUnlock();
+            }
+        }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    static final class LBQSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        final LinkedBlockingQueue<E> queue;
+        Node<E> current;    // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        long est;           // size estimate
+        LBQSpliterator(LinkedBlockingQueue<E> queue) {
+            this.queue = queue;
+            this.est = queue.size();
+        }
+
+        public long estimateSize() { return est; }
+
+        public Spliterator<E> trySplit() {
+            Node<E> h;
+            final LinkedBlockingQueue<E> q = this.queue;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((h = current) != null || (h = q.head.next) != null) &&
+                h.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                Node<E> p = current;
+                q.fullyLock();
+                try {
+                    if (p != null || (p = q.head.next) != null) {
+                        do {
+                            if ((a[i] = p.item) != null)
+                                ++i;
+                        } while ((p = p.next) != null && i < n);
+                    }
+                } finally {
+                    q.fullyUnlock();
+                }
+                if ((current = p) == null) {
+                    est = 0L;
+                    exhausted = true;
+                }
+                else if ((est -= i) < 0L)
+                    est = 0L;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        public void forEachRemaining(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingQueue<E> q = this.queue;
+            if (!exhausted) {
+                exhausted = true;
+                Node<E> p = current;
+                do {
+                    E e = null;
+                    q.fullyLock();
+                    try {
+                        if (p == null)
+                            p = q.head.next;
+                        while (p != null) {
+                            e = p.item;
+                            p = p.next;
+                            if (e != null)
+                                break;
+                        }
+                    } finally {
+                        q.fullyUnlock();
+                    }
+                    if (e != null)
+                        action.accept(e);
+                } while (p != null);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null) throw new NullPointerException();
+            final LinkedBlockingQueue<E> q = this.queue;
+            if (!exhausted) {
+                E e = null;
+                q.fullyLock();
+                try {
+                    if (current == null)
+                        current = q.head.next;
+                    while (current != null) {
+                        e = current.item;
+                        current = current.next;
+                        if (e != null)
+                            break;
+                    }
+                } finally {
+                    q.fullyUnlock();
+                }
+                if (current == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept(e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LBQSpliterator<E>(this);
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData The capacity is emitted (int), followed by all of
+     * its elements (each an {@code Object}) in the proper order,
+     * followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        fullyLock();
+        try {
+            // Write out any hidden stuff, plus capacity
+            s.defaultWriteObject();
+
+            // Write out all elements in the proper order.
+            for (Node<E> p = head.next; p != null; p = p.next)
+                s.writeObject(p.item);
+
+            // Use trailing null as sentinel
+            s.writeObject(null);
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Read in capacity, and any hidden stuff
+        s.defaultReadObject();
+
+        count.set(0);
+        last = head = new Node<E>(null);
+
+        // Read in all elements and place in queue
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E)s.readObject();
+            if (item == null)
+                break;
+            add(item);
+        }
+    }
+}
diff --git a/java/util/concurrent/LinkedTransferQueue.java b/java/util/concurrent/LinkedTransferQueue.java
new file mode 100644
index 0000000..e282b42
--- /dev/null
+++ b/java/util/concurrent/LinkedTransferQueue.java
@@ -0,0 +1,1587 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@link TransferQueue} based on linked nodes.
+ * This queue orders elements FIFO (first-in-first-out) with respect
+ * to any given producer.  The <em>head</em> of the queue is that
+ * element that has been on the queue the longest time for some
+ * producer.  The <em>tail</em> of the queue is that element that has
+ * been on the queue the shortest time for some producer.
+ *
+ * <p>Beware that, unlike in most collections, the {@code size} method
+ * is <em>NOT</em> a constant-time operation. Because of the
+ * asynchronous nature of these queues, determining the current number
+ * of elements requires a traversal of the elements, and so may report
+ * inaccurate results if this collection is modified during traversal.
+ * Additionally, the bulk operations {@code addAll},
+ * {@code removeAll}, {@code retainAll}, {@code containsAll},
+ * {@code equals}, and {@code toArray} are <em>not</em> guaranteed
+ * to be performed atomically. For example, an iterator operating
+ * concurrently with an {@code addAll} operation might view only some
+ * of the added elements.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * <p>Memory consistency effects: As with other concurrent
+ * collections, actions in a thread prior to placing an object into a
+ * {@code LinkedTransferQueue}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions subsequent to the access or removal of that element from
+ * the {@code LinkedTransferQueue} in another thread.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public class LinkedTransferQueue<E> extends AbstractQueue<E>
+    implements TransferQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -3223113410248163686L;
+
+    /*
+     * *** Overview of Dual Queues with Slack ***
+     *
+     * Dual Queues, introduced by Scherer and Scott
+     * (http://www.cs.rice.edu/~wns1/papers/2004-DISC-DDS.pdf) are
+     * (linked) queues in which nodes may represent either data or
+     * requests.  When a thread tries to enqueue a data node, but
+     * encounters a request node, it instead "matches" and removes it;
+     * and vice versa for enqueuing requests. Blocking Dual Queues
+     * arrange that threads enqueuing unmatched requests block until
+     * other threads provide the match. Dual Synchronous Queues (see
+     * Scherer, Lea, & Scott
+     * http://www.cs.rochester.edu/u/scott/papers/2009_Scherer_CACM_SSQ.pdf)
+     * additionally arrange that threads enqueuing unmatched data also
+     * block.  Dual Transfer Queues support all of these modes, as
+     * dictated by callers.
+     *
+     * A FIFO dual queue may be implemented using a variation of the
+     * Michael & Scott (M&S) lock-free queue algorithm
+     * (http://www.cs.rochester.edu/~scott/papers/1996_PODC_queues.pdf).
+     * It maintains two pointer fields, "head", pointing to a
+     * (matched) node that in turn points to the first actual
+     * (unmatched) queue node (or null if empty); and "tail" that
+     * points to the last node on the queue (or again null if
+     * empty). For example, here is a possible queue with four data
+     * elements:
+     *
+     *  head                tail
+     *    |                   |
+     *    v                   v
+     *    M -> U -> U -> U -> U
+     *
+     * The M&S queue algorithm is known to be prone to scalability and
+     * overhead limitations when maintaining (via CAS) these head and
+     * tail pointers. This has led to the development of
+     * contention-reducing variants such as elimination arrays (see
+     * Moir et al http://portal.acm.org/citation.cfm?id=1074013) and
+     * optimistic back pointers (see Ladan-Mozes & Shavit
+     * http://people.csail.mit.edu/edya/publications/OptimisticFIFOQueue-journal.pdf).
+     * However, the nature of dual queues enables a simpler tactic for
+     * improving M&S-style implementations when dual-ness is needed.
+     *
+     * In a dual queue, each node must atomically maintain its match
+     * status. While there are other possible variants, we implement
+     * this here as: for a data-mode node, matching entails CASing an
+     * "item" field from a non-null data value to null upon match, and
+     * vice-versa for request nodes, CASing from null to a data
+     * value. (Note that the linearization properties of this style of
+     * queue are easy to verify -- elements are made available by
+     * linking, and unavailable by matching.) Compared to plain M&S
+     * queues, this property of dual queues requires one additional
+     * successful atomic operation per enq/deq pair. But it also
+     * enables lower cost variants of queue maintenance mechanics. (A
+     * variation of this idea applies even for non-dual queues that
+     * support deletion of interior elements, such as
+     * j.u.c.ConcurrentLinkedQueue.)
+     *
+     * Once a node is matched, its match status can never again
+     * change.  We may thus arrange that the linked list of them
+     * contain a prefix of zero or more matched nodes, followed by a
+     * suffix of zero or more unmatched nodes. (Note that we allow
+     * both the prefix and suffix to be zero length, which in turn
+     * means that we do not use a dummy header.)  If we were not
+     * concerned with either time or space efficiency, we could
+     * correctly perform enqueue and dequeue operations by traversing
+     * from a pointer to the initial node; CASing the item of the
+     * first unmatched node on match and CASing the next field of the
+     * trailing node on appends. (Plus some special-casing when
+     * initially empty).  While this would be a terrible idea in
+     * itself, it does have the benefit of not requiring ANY atomic
+     * updates on head/tail fields.
+     *
+     * We introduce here an approach that lies between the extremes of
+     * never versus always updating queue (head and tail) pointers.
+     * This offers a tradeoff between sometimes requiring extra
+     * traversal steps to locate the first and/or last unmatched
+     * nodes, versus the reduced overhead and contention of fewer
+     * updates to queue pointers. For example, a possible snapshot of
+     * a queue is:
+     *
+     *  head           tail
+     *    |              |
+     *    v              v
+     *    M -> M -> U -> U -> U -> U
+     *
+     * The best value for this "slack" (the targeted maximum distance
+     * between the value of "head" and the first unmatched node, and
+     * similarly for "tail") is an empirical matter. We have found
+     * that using very small constants in the range of 1-3 work best
+     * over a range of platforms. Larger values introduce increasing
+     * costs of cache misses and risks of long traversal chains, while
+     * smaller values increase CAS contention and overhead.
+     *
+     * Dual queues with slack differ from plain M&S dual queues by
+     * virtue of only sometimes updating head or tail pointers when
+     * matching, appending, or even traversing nodes; in order to
+     * maintain a targeted slack.  The idea of "sometimes" may be
+     * operationalized in several ways. The simplest is to use a
+     * per-operation counter incremented on each traversal step, and
+     * to try (via CAS) to update the associated queue pointer
+     * whenever the count exceeds a threshold. Another, that requires
+     * more overhead, is to use random number generators to update
+     * with a given probability per traversal step.
+     *
+     * In any strategy along these lines, because CASes updating
+     * fields may fail, the actual slack may exceed targeted
+     * slack. However, they may be retried at any time to maintain
+     * targets.  Even when using very small slack values, this
+     * approach works well for dual queues because it allows all
+     * operations up to the point of matching or appending an item
+     * (hence potentially allowing progress by another thread) to be
+     * read-only, thus not introducing any further contention. As
+     * described below, we implement this by performing slack
+     * maintenance retries only after these points.
+     *
+     * As an accompaniment to such techniques, traversal overhead can
+     * be further reduced without increasing contention of head
+     * pointer updates: Threads may sometimes shortcut the "next" link
+     * path from the current "head" node to be closer to the currently
+     * known first unmatched node, and similarly for tail. Again, this
+     * may be triggered with using thresholds or randomization.
+     *
+     * These ideas must be further extended to avoid unbounded amounts
+     * of costly-to-reclaim garbage caused by the sequential "next"
+     * links of nodes starting at old forgotten head nodes: As first
+     * described in detail by Boehm
+     * (http://portal.acm.org/citation.cfm?doid=503272.503282), if a GC
+     * delays noticing that any arbitrarily old node has become
+     * garbage, all newer dead nodes will also be unreclaimed.
+     * (Similar issues arise in non-GC environments.)  To cope with
+     * this in our implementation, upon CASing to advance the head
+     * pointer, we set the "next" link of the previous head to point
+     * only to itself; thus limiting the length of connected dead lists.
+     * (We also take similar care to wipe out possibly garbage
+     * retaining values held in other Node fields.)  However, doing so
+     * adds some further complexity to traversal: If any "next"
+     * pointer links to itself, it indicates that the current thread
+     * has lagged behind a head-update, and so the traversal must
+     * continue from the "head".  Traversals trying to find the
+     * current tail starting from "tail" may also encounter
+     * self-links, in which case they also continue at "head".
+     *
+     * It is tempting in slack-based scheme to not even use CAS for
+     * updates (similarly to Ladan-Mozes & Shavit). However, this
+     * cannot be done for head updates under the above link-forgetting
+     * mechanics because an update may leave head at a detached node.
+     * And while direct writes are possible for tail updates, they
+     * increase the risk of long retraversals, and hence long garbage
+     * chains, which can be much more costly than is worthwhile
+     * considering that the cost difference of performing a CAS vs
+     * write is smaller when they are not triggered on each operation
+     * (especially considering that writes and CASes equally require
+     * additional GC bookkeeping ("write barriers") that are sometimes
+     * more costly than the writes themselves because of contention).
+     *
+     * *** Overview of implementation ***
+     *
+     * We use a threshold-based approach to updates, with a slack
+     * threshold of two -- that is, we update head/tail when the
+     * current pointer appears to be two or more steps away from the
+     * first/last node. The slack value is hard-wired: a path greater
+     * than one is naturally implemented by checking equality of
+     * traversal pointers except when the list has only one element,
+     * in which case we keep slack threshold at one. Avoiding tracking
+     * explicit counts across method calls slightly simplifies an
+     * already-messy implementation. Using randomization would
+     * probably work better if there were a low-quality dirt-cheap
+     * per-thread one available, but even ThreadLocalRandom is too
+     * heavy for these purposes.
+     *
+     * With such a small slack threshold value, it is not worthwhile
+     * to augment this with path short-circuiting (i.e., unsplicing
+     * interior nodes) except in the case of cancellation/removal (see
+     * below).
+     *
+     * We allow both the head and tail fields to be null before any
+     * nodes are enqueued; initializing upon first append.  This
+     * simplifies some other logic, as well as providing more
+     * efficient explicit control paths instead of letting JVMs insert
+     * implicit NullPointerExceptions when they are null.  While not
+     * currently fully implemented, we also leave open the possibility
+     * of re-nulling these fields when empty (which is complicated to
+     * arrange, for little benefit.)
+     *
+     * All enqueue/dequeue operations are handled by the single method
+     * "xfer" with parameters indicating whether to act as some form
+     * of offer, put, poll, take, or transfer (each possibly with
+     * timeout). The relative complexity of using one monolithic
+     * method outweighs the code bulk and maintenance problems of
+     * using separate methods for each case.
+     *
+     * Operation consists of up to three phases. The first is
+     * implemented within method xfer, the second in tryAppend, and
+     * the third in method awaitMatch.
+     *
+     * 1. Try to match an existing node
+     *
+     *    Starting at head, skip already-matched nodes until finding
+     *    an unmatched node of opposite mode, if one exists, in which
+     *    case matching it and returning, also if necessary updating
+     *    head to one past the matched node (or the node itself if the
+     *    list has no other unmatched nodes). If the CAS misses, then
+     *    a loop retries advancing head by two steps until either
+     *    success or the slack is at most two. By requiring that each
+     *    attempt advances head by two (if applicable), we ensure that
+     *    the slack does not grow without bound. Traversals also check
+     *    if the initial head is now off-list, in which case they
+     *    start at the new head.
+     *
+     *    If no candidates are found and the call was untimed
+     *    poll/offer, (argument "how" is NOW) return.
+     *
+     * 2. Try to append a new node (method tryAppend)
+     *
+     *    Starting at current tail pointer, find the actual last node
+     *    and try to append a new node (or if head was null, establish
+     *    the first node). Nodes can be appended only if their
+     *    predecessors are either already matched or are of the same
+     *    mode. If we detect otherwise, then a new node with opposite
+     *    mode must have been appended during traversal, so we must
+     *    restart at phase 1. The traversal and update steps are
+     *    otherwise similar to phase 1: Retrying upon CAS misses and
+     *    checking for staleness.  In particular, if a self-link is
+     *    encountered, then we can safely jump to a node on the list
+     *    by continuing the traversal at current head.
+     *
+     *    On successful append, if the call was ASYNC, return.
+     *
+     * 3. Await match or cancellation (method awaitMatch)
+     *
+     *    Wait for another thread to match node; instead cancelling if
+     *    the current thread was interrupted or the wait timed out. On
+     *    multiprocessors, we use front-of-queue spinning: If a node
+     *    appears to be the first unmatched node in the queue, it
+     *    spins a bit before blocking. In either case, before blocking
+     *    it tries to unsplice any nodes between the current "head"
+     *    and the first unmatched node.
+     *
+     *    Front-of-queue spinning vastly improves performance of
+     *    heavily contended queues. And so long as it is relatively
+     *    brief and "quiet", spinning does not much impact performance
+     *    of less-contended queues.  During spins threads check their
+     *    interrupt status and generate a thread-local random number
+     *    to decide to occasionally perform a Thread.yield. While
+     *    yield has underdefined specs, we assume that it might help,
+     *    and will not hurt, in limiting impact of spinning on busy
+     *    systems.  We also use smaller (1/2) spins for nodes that are
+     *    not known to be front but whose predecessors have not
+     *    blocked -- these "chained" spins avoid artifacts of
+     *    front-of-queue rules which otherwise lead to alternating
+     *    nodes spinning vs blocking. Further, front threads that
+     *    represent phase changes (from data to request node or vice
+     *    versa) compared to their predecessors receive additional
+     *    chained spins, reflecting longer paths typically required to
+     *    unblock threads during phase changes.
+     *
+     *
+     * ** Unlinking removed interior nodes **
+     *
+     * In addition to minimizing garbage retention via self-linking
+     * described above, we also unlink removed interior nodes. These
+     * may arise due to timed out or interrupted waits, or calls to
+     * remove(x) or Iterator.remove.  Normally, given a node that was
+     * at one time known to be the predecessor of some node s that is
+     * to be removed, we can unsplice s by CASing the next field of
+     * its predecessor if it still points to s (otherwise s must
+     * already have been removed or is now offlist). But there are two
+     * situations in which we cannot guarantee to make node s
+     * unreachable in this way: (1) If s is the trailing node of list
+     * (i.e., with null next), then it is pinned as the target node
+     * for appends, so can only be removed later after other nodes are
+     * appended. (2) We cannot necessarily unlink s given a
+     * predecessor node that is matched (including the case of being
+     * cancelled): the predecessor may already be unspliced, in which
+     * case some previous reachable node may still point to s.
+     * (For further explanation see Herlihy & Shavit "The Art of
+     * Multiprocessor Programming" chapter 9).  Although, in both
+     * cases, we can rule out the need for further action if either s
+     * or its predecessor are (or can be made to be) at, or fall off
+     * from, the head of list.
+     *
+     * Without taking these into account, it would be possible for an
+     * unbounded number of supposedly removed nodes to remain
+     * reachable.  Situations leading to such buildup are uncommon but
+     * can occur in practice; for example when a series of short timed
+     * calls to poll repeatedly time out but never otherwise fall off
+     * the list because of an untimed call to take at the front of the
+     * queue.
+     *
+     * When these cases arise, rather than always retraversing the
+     * entire list to find an actual predecessor to unlink (which
+     * won't help for case (1) anyway), we record a conservative
+     * estimate of possible unsplice failures (in "sweepVotes").
+     * We trigger a full sweep when the estimate exceeds a threshold
+     * ("SWEEP_THRESHOLD") indicating the maximum number of estimated
+     * removal failures to tolerate before sweeping through, unlinking
+     * cancelled nodes that were not unlinked upon initial removal.
+     * We perform sweeps by the thread hitting threshold (rather than
+     * background threads or by spreading work to other threads)
+     * because in the main contexts in which removal occurs, the
+     * caller is already timed-out, cancelled, or performing a
+     * potentially O(n) operation (e.g. remove(x)), none of which are
+     * time-critical enough to warrant the overhead that alternatives
+     * would impose on other threads.
+     *
+     * Because the sweepVotes estimate is conservative, and because
+     * nodes become unlinked "naturally" as they fall off the head of
+     * the queue, and because we allow votes to accumulate even while
+     * sweeps are in progress, there are typically significantly fewer
+     * such nodes than estimated.  Choice of a threshold value
+     * balances the likelihood of wasted effort and contention, versus
+     * providing a worst-case bound on retention of interior nodes in
+     * quiescent queues. The value defined below was chosen
+     * empirically to balance these under various timeout scenarios.
+     *
+     * Note that we cannot self-link unlinked interior nodes during
+     * sweeps. However, the associated garbage chains terminate when
+     * some successor ultimately falls off the head of the list and is
+     * self-linked.
+     */
+
+    /** True if on multiprocessor */
+    private static final boolean MP =
+        Runtime.getRuntime().availableProcessors() > 1;
+
+    /**
+     * The number of times to spin (with randomly interspersed calls
+     * to Thread.yield) on multiprocessor before blocking when a node
+     * is apparently the first waiter in the queue.  See above for
+     * explanation. Must be a power of two. The value is empirically
+     * derived -- it works pretty well across a variety of processors,
+     * numbers of CPUs, and OSes.
+     */
+    private static final int FRONT_SPINS   = 1 << 7;
+
+    /**
+     * The number of times to spin before blocking when a node is
+     * preceded by another node that is apparently spinning.  Also
+     * serves as an increment to FRONT_SPINS on phase changes, and as
+     * base average frequency for yielding during spins. Must be a
+     * power of two.
+     */
+    private static final int CHAINED_SPINS = FRONT_SPINS >>> 1;
+
+    /**
+     * The maximum number of estimated removal failures (sweepVotes)
+     * to tolerate before sweeping through the queue unlinking
+     * cancelled nodes that were not unlinked upon initial
+     * removal. See above for explanation. The value must be at least
+     * two to avoid useless sweeps when removing trailing nodes.
+     */
+    static final int SWEEP_THRESHOLD = 32;
+
+    /**
+     * Queue nodes. Uses Object, not E, for items to allow forgetting
+     * them after use.  Relies heavily on Unsafe mechanics to minimize
+     * unnecessary ordering constraints: Writes that are intrinsically
+     * ordered wrt other accesses or CASes use simple relaxed forms.
+     */
+    static final class Node {
+        final boolean isData;   // false if this is a request node
+        volatile Object item;   // initially non-null if isData; CASed to match
+        volatile Node next;
+        volatile Thread waiter; // null until waiting
+
+        // CAS methods for fields
+        final boolean casNext(Node cmp, Node val) {
+            return U.compareAndSwapObject(this, NEXT, cmp, val);
+        }
+
+        final boolean casItem(Object cmp, Object val) {
+            // assert cmp == null || cmp.getClass() != Node.class;
+            return U.compareAndSwapObject(this, ITEM, cmp, val);
+        }
+
+        /**
+         * Constructs a new node.  Uses relaxed write because item can
+         * only be seen after publication via casNext.
+         */
+        Node(Object item, boolean isData) {
+            U.putObject(this, ITEM, item); // relaxed write
+            this.isData = isData;
+        }
+
+        /**
+         * Links node to itself to avoid garbage retention.  Called
+         * only after CASing head field, so uses relaxed write.
+         */
+        final void forgetNext() {
+            U.putObject(this, NEXT, this);
+        }
+
+        /**
+         * Sets item to self and waiter to null, to avoid garbage
+         * retention after matching or cancelling. Uses relaxed writes
+         * because order is already constrained in the only calling
+         * contexts: item is forgotten only after volatile/atomic
+         * mechanics that extract items.  Similarly, clearing waiter
+         * follows either CAS or return from park (if ever parked;
+         * else we don't care).
+         */
+        final void forgetContents() {
+            U.putObject(this, ITEM, this);
+            U.putObject(this, WAITER, null);
+        }
+
+        /**
+         * Returns true if this node has been matched, including the
+         * case of artificial matches due to cancellation.
+         */
+        final boolean isMatched() {
+            Object x = item;
+            return (x == this) || ((x == null) == isData);
+        }
+
+        /**
+         * Returns true if this is an unmatched request node.
+         */
+        final boolean isUnmatchedRequest() {
+            return !isData && item == null;
+        }
+
+        /**
+         * Returns true if a node with the given mode cannot be
+         * appended to this node because this node is unmatched and
+         * has opposite data mode.
+         */
+        final boolean cannotPrecede(boolean haveData) {
+            boolean d = isData;
+            Object x;
+            return d != haveData && (x = item) != this && (x != null) == d;
+        }
+
+        /**
+         * Tries to artificially match a data node -- used by remove.
+         */
+        final boolean tryMatchData() {
+            // assert isData;
+            Object x = item;
+            if (x != null && x != this && casItem(x, null)) {
+                LockSupport.unpark(waiter);
+                return true;
+            }
+            return false;
+        }
+
+        private static final long serialVersionUID = -3375979862319811754L;
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long ITEM;
+        private static final long NEXT;
+        private static final long WAITER;
+        static {
+            try {
+                ITEM = U.objectFieldOffset
+                    (Node.class.getDeclaredField("item"));
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+                WAITER = U.objectFieldOffset
+                    (Node.class.getDeclaredField("waiter"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** head of the queue; null until first enqueue */
+    transient volatile Node head;
+
+    /** tail of the queue; null until first append */
+    private transient volatile Node tail;
+
+    /** The number of apparent failures to unsplice removed nodes */
+    private transient volatile int sweepVotes;
+
+    // CAS methods for fields
+    private boolean casTail(Node cmp, Node val) {
+        return U.compareAndSwapObject(this, TAIL, cmp, val);
+    }
+
+    private boolean casHead(Node cmp, Node val) {
+        return U.compareAndSwapObject(this, HEAD, cmp, val);
+    }
+
+    private boolean casSweepVotes(int cmp, int val) {
+        return U.compareAndSwapInt(this, SWEEPVOTES, cmp, val);
+    }
+
+    /*
+     * Possible values for "how" argument in xfer method.
+     */
+    private static final int NOW   = 0; // for untimed poll, tryTransfer
+    private static final int ASYNC = 1; // for offer, put, add
+    private static final int SYNC  = 2; // for transfer, take
+    private static final int TIMED = 3; // for timed poll, tryTransfer
+
+    /**
+     * Implements all queuing methods. See above for explanation.
+     *
+     * @param e the item or null for take
+     * @param haveData true if this is a put, else a take
+     * @param how NOW, ASYNC, SYNC, or TIMED
+     * @param nanos timeout in nanosecs, used only if mode is TIMED
+     * @return an item if matched, else e
+     * @throws NullPointerException if haveData mode but e is null
+     */
+    private E xfer(E e, boolean haveData, int how, long nanos) {
+        if (haveData && (e == null))
+            throw new NullPointerException();
+        Node s = null;                        // the node to append, if needed
+
+        retry:
+        for (;;) {                            // restart on append race
+
+            for (Node h = head, p = h; p != null;) { // find & match first node
+                boolean isData = p.isData;
+                Object item = p.item;
+                if (item != p && (item != null) == isData) { // unmatched
+                    if (isData == haveData)   // can't match
+                        break;
+                    if (p.casItem(item, e)) { // match
+                        for (Node q = p; q != h;) {
+                            Node n = q.next;  // update by 2 unless singleton
+                            if (head == h && casHead(h, n == null ? q : n)) {
+                                h.forgetNext();
+                                break;
+                            }                 // advance and retry
+                            if ((h = head)   == null ||
+                                (q = h.next) == null || !q.isMatched())
+                                break;        // unless slack < 2
+                        }
+                        LockSupport.unpark(p.waiter);
+                        @SuppressWarnings("unchecked") E itemE = (E) item;
+                        return itemE;
+                    }
+                }
+                Node n = p.next;
+                p = (p != n) ? n : (h = head); // Use head if p offlist
+            }
+
+            if (how != NOW) {                 // No matches available
+                if (s == null)
+                    s = new Node(e, haveData);
+                Node pred = tryAppend(s, haveData);
+                if (pred == null)
+                    continue retry;           // lost race vs opposite mode
+                if (how != ASYNC)
+                    return awaitMatch(s, pred, e, (how == TIMED), nanos);
+            }
+            return e; // not waiting
+        }
+    }
+
+    /**
+     * Tries to append node s as tail.
+     *
+     * @param s the node to append
+     * @param haveData true if appending in data mode
+     * @return null on failure due to losing race with append in
+     * different mode, else s's predecessor, or s itself if no
+     * predecessor
+     */
+    private Node tryAppend(Node s, boolean haveData) {
+        for (Node t = tail, p = t;;) {        // move p to last node and append
+            Node n, u;                        // temps for reads of next & tail
+            if (p == null && (p = head) == null) {
+                if (casHead(null, s))
+                    return s;                 // initialize
+            }
+            else if (p.cannotPrecede(haveData))
+                return null;                  // lost race vs opposite mode
+            else if ((n = p.next) != null)    // not last; keep traversing
+                p = p != t && t != (u = tail) ? (t = u) : // stale tail
+                    (p != n) ? n : null;      // restart if off list
+            else if (!p.casNext(null, s))
+                p = p.next;                   // re-read on CAS failure
+            else {
+                if (p != t) {                 // update if slack now >= 2
+                    while ((tail != t || !casTail(t, s)) &&
+                           (t = tail)   != null &&
+                           (s = t.next) != null && // advance and retry
+                           (s = s.next) != null && s != t);
+                }
+                return p;
+            }
+        }
+    }
+
+    /**
+     * Spins/yields/blocks until node s is matched or caller gives up.
+     *
+     * @param s the waiting node
+     * @param pred the predecessor of s, or s itself if it has no
+     * predecessor, or null if unknown (the null case does not occur
+     * in any current calls but may in possible future extensions)
+     * @param e the comparison value for checking match
+     * @param timed if true, wait only until timeout elapses
+     * @param nanos timeout in nanosecs, used only if timed is true
+     * @return matched item, or e if unmatched on interrupt or timeout
+     */
+    private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) {
+        final long deadline = timed ? System.nanoTime() + nanos : 0L;
+        Thread w = Thread.currentThread();
+        int spins = -1; // initialized after first item and cancel checks
+        ThreadLocalRandom randomYields = null; // bound if needed
+
+        for (;;) {
+            Object item = s.item;
+            if (item != e) {                  // matched
+                // assert item != s;
+                s.forgetContents();           // avoid garbage
+                @SuppressWarnings("unchecked") E itemE = (E) item;
+                return itemE;
+            }
+            else if (w.isInterrupted() || (timed && nanos <= 0L)) {
+                unsplice(pred, s);           // try to unlink and cancel
+                if (s.casItem(e, s))         // return normally if lost CAS
+                    return e;
+            }
+            else if (spins < 0) {            // establish spins at/near front
+                if ((spins = spinsFor(pred, s.isData)) > 0)
+                    randomYields = ThreadLocalRandom.current();
+            }
+            else if (spins > 0) {             // spin
+                --spins;
+                if (randomYields.nextInt(CHAINED_SPINS) == 0)
+                    Thread.yield();           // occasionally yield
+            }
+            else if (s.waiter == null) {
+                s.waiter = w;                 // request unpark then recheck
+            }
+            else if (timed) {
+                nanos = deadline - System.nanoTime();
+                if (nanos > 0L)
+                    LockSupport.parkNanos(this, nanos);
+            }
+            else {
+                LockSupport.park(this);
+            }
+        }
+    }
+
+    /**
+     * Returns spin/yield value for a node with given predecessor and
+     * data mode. See above for explanation.
+     */
+    private static int spinsFor(Node pred, boolean haveData) {
+        if (MP && pred != null) {
+            if (pred.isData != haveData)      // phase change
+                return FRONT_SPINS + CHAINED_SPINS;
+            if (pred.isMatched())             // probably at front
+                return FRONT_SPINS;
+            if (pred.waiter == null)          // pred apparently spinning
+                return CHAINED_SPINS;
+        }
+        return 0;
+    }
+
+    /* -------------- Traversal methods -------------- */
+
+    /**
+     * Returns the successor of p, or the head node if p.next has been
+     * linked to self, which will only be true if traversing with a
+     * stale pointer that is now off the list.
+     */
+    final Node succ(Node p) {
+        Node next = p.next;
+        return (p == next) ? head : next;
+    }
+
+    /**
+     * Returns the first unmatched data node, or null if none.
+     * Callers must recheck if the returned node's item field is null
+     * or self-linked before using.
+     */
+    final Node firstDataNode() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p)
+                        return p;
+                }
+                else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Traverses and counts unmatched nodes of the given mode.
+     * Used by methods size and getWaitingConsumerCount.
+     */
+    private int countOfMode(boolean data) {
+        restartFromHead: for (;;) {
+            int count = 0;
+            for (Node p = head; p != null;) {
+                if (!p.isMatched()) {
+                    if (p.isData != data)
+                        return 0;
+                    if (++count == Integer.MAX_VALUE)
+                        break;  // @see Collection.size()
+                }
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return count;
+        }
+    }
+
+    public String toString() {
+        String[] a = null;
+        restartFromHead: for (;;) {
+            int charLength = 0;
+            int size = 0;
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p) {
+                        if (a == null)
+                            a = new String[4];
+                        else if (size == a.length)
+                            a = Arrays.copyOf(a, 2 * size);
+                        String s = item.toString();
+                        a[size++] = s;
+                        charLength += s.length();
+                    }
+                } else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+
+            if (size == 0)
+                return "[]";
+
+            return Helpers.toString(a, size, charLength);
+        }
+    }
+
+    private Object[] toArrayInternal(Object[] a) {
+        Object[] x = a;
+        restartFromHead: for (;;) {
+            int size = 0;
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p) {
+                        if (x == null)
+                            x = new Object[4];
+                        else if (size == x.length)
+                            x = Arrays.copyOf(x, 2 * (size + 4));
+                        x[size++] = item;
+                    }
+                } else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            if (x == null)
+                return new Object[0];
+            else if (a != null && size <= a.length) {
+                if (a != x)
+                    System.arraycopy(x, 0, a, 0, size);
+                if (size < a.length)
+                    a[size] = null;
+                return a;
+            }
+            return (size == x.length) ? x : Arrays.copyOf(x, size);
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        return toArrayInternal(null);
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue, in
+     * proper sequence; the runtime type of the returned array is that of
+     * the specified array.  If the queue fits in the specified array, it
+     * is returned therein.  Otherwise, a new array is allocated with the
+     * runtime type of the specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    @SuppressWarnings("unchecked")
+    public <T> T[] toArray(T[] a) {
+        if (a == null) throw new NullPointerException();
+        return (T[]) toArrayInternal(a);
+    }
+
+    final class Itr implements Iterator<E> {
+        private Node nextNode;   // next node to return item for
+        private E nextItem;      // the corresponding item
+        private Node lastRet;    // last returned node, to support remove
+        private Node lastPred;   // predecessor to unlink lastRet
+
+        /**
+         * Moves to next node after prev, or first node if prev null.
+         */
+        private void advance(Node prev) {
+            /*
+             * To track and avoid buildup of deleted nodes in the face
+             * of calls to both Queue.remove and Itr.remove, we must
+             * include variants of unsplice and sweep upon each
+             * advance: Upon Itr.remove, we may need to catch up links
+             * from lastPred, and upon other removes, we might need to
+             * skip ahead from stale nodes and unsplice deleted ones
+             * found while advancing.
+             */
+
+            Node r, b; // reset lastPred upon possible deletion of lastRet
+            if ((r = lastRet) != null && !r.isMatched())
+                lastPred = r;    // next lastPred is old lastRet
+            else if ((b = lastPred) == null || b.isMatched())
+                lastPred = null; // at start of list
+            else {
+                Node s, n;       // help with removal of lastPred.next
+                while ((s = b.next) != null &&
+                       s != b && s.isMatched() &&
+                       (n = s.next) != null && n != s)
+                    b.casNext(s, n);
+            }
+
+            this.lastRet = prev;
+
+            for (Node p = prev, s, n;;) {
+                s = (p == null) ? head : p.next;
+                if (s == null)
+                    break;
+                else if (s == p) {
+                    p = null;
+                    continue;
+                }
+                Object item = s.item;
+                if (s.isData) {
+                    if (item != null && item != s) {
+                        @SuppressWarnings("unchecked") E itemE = (E) item;
+                        nextItem = itemE;
+                        nextNode = s;
+                        return;
+                    }
+                }
+                else if (item == null)
+                    break;
+                // assert s.isMatched();
+                if (p == null)
+                    p = s;
+                else if ((n = s.next) == null)
+                    break;
+                else if (s == n)
+                    p = null;
+                else
+                    p.casNext(s, n);
+            }
+            nextNode = null;
+            nextItem = null;
+        }
+
+        Itr() {
+            advance(null);
+        }
+
+        public final boolean hasNext() {
+            return nextNode != null;
+        }
+
+        public final E next() {
+            Node p = nextNode;
+            if (p == null) throw new NoSuchElementException();
+            E e = nextItem;
+            advance(p);
+            return e;
+        }
+
+        public final void remove() {
+            final Node lastRet = this.lastRet;
+            if (lastRet == null)
+                throw new IllegalStateException();
+            this.lastRet = null;
+            if (lastRet.tryMatchData())
+                unsplice(lastPred, lastRet);
+        }
+    }
+
+    /** A customized variant of Spliterators.IteratorSpliterator */
+    final class LTQSpliterator<E> implements Spliterator<E> {
+        static final int MAX_BATCH = 1 << 25;  // max batch array size;
+        Node current;       // current node; null until initialized
+        int batch;          // batch size for splits
+        boolean exhausted;  // true when no more nodes
+        LTQSpliterator() {}
+
+        public Spliterator<E> trySplit() {
+            Node p;
+            int b = batch;
+            int n = (b <= 0) ? 1 : (b >= MAX_BATCH) ? MAX_BATCH : b + 1;
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null) &&
+                p.next != null) {
+                Object[] a = new Object[n];
+                int i = 0;
+                do {
+                    Object e = p.item;
+                    if (e != p && (a[i] = e) != null)
+                        ++i;
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (p != null && i < n && p.isData);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (i > 0) {
+                    batch = i;
+                    return Spliterators.spliterator
+                        (a, 0, i, (Spliterator.ORDERED |
+                                   Spliterator.NONNULL |
+                                   Spliterator.CONCURRENT));
+                }
+            }
+            return null;
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Node p;
+            if (action == null) throw new NullPointerException();
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null)) {
+                exhausted = true;
+                do {
+                    Object e = p.item;
+                    if (e != null && e != p)
+                        action.accept((E)e);
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (p != null && p.isData);
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public boolean tryAdvance(Consumer<? super E> action) {
+            Node p;
+            if (action == null) throw new NullPointerException();
+            if (!exhausted &&
+                ((p = current) != null || (p = firstDataNode()) != null)) {
+                Object e;
+                do {
+                    if ((e = p.item) == p)
+                        e = null;
+                    if (p == (p = p.next))
+                        p = firstDataNode();
+                } while (e == null && p != null && p.isData);
+                if ((current = p) == null)
+                    exhausted = true;
+                if (e != null) {
+                    action.accept((E)e);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public long estimateSize() { return Long.MAX_VALUE; }
+
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.NONNULL |
+                Spliterator.CONCURRENT;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new LTQSpliterator<E>();
+    }
+
+    /* -------------- Removal methods -------------- */
+
+    /**
+     * Unsplices (now or later) the given deleted/cancelled node with
+     * the given predecessor.
+     *
+     * @param pred a node that was at one time known to be the
+     * predecessor of s, or null or s itself if s is/was at head
+     * @param s the node to be unspliced
+     */
+    final void unsplice(Node pred, Node s) {
+        s.waiter = null; // disable signals
+        /*
+         * See above for rationale. Briefly: if pred still points to
+         * s, try to unlink s.  If s cannot be unlinked, because it is
+         * trailing node or pred might be unlinked, and neither pred
+         * nor s are head or offlist, add to sweepVotes, and if enough
+         * votes have accumulated, sweep.
+         */
+        if (pred != null && pred != s && pred.next == s) {
+            Node n = s.next;
+            if (n == null ||
+                (n != s && pred.casNext(s, n) && pred.isMatched())) {
+                for (;;) {               // check if at, or could be, head
+                    Node h = head;
+                    if (h == pred || h == s || h == null)
+                        return;          // at head or list empty
+                    if (!h.isMatched())
+                        break;
+                    Node hn = h.next;
+                    if (hn == null)
+                        return;          // now empty
+                    if (hn != h && casHead(h, hn))
+                        h.forgetNext();  // advance head
+                }
+                if (pred.next != pred && s.next != s) { // recheck if offlist
+                    for (;;) {           // sweep now if enough votes
+                        int v = sweepVotes;
+                        if (v < SWEEP_THRESHOLD) {
+                            if (casSweepVotes(v, v + 1))
+                                break;
+                        }
+                        else if (casSweepVotes(v, 0)) {
+                            sweep();
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Unlinks matched (typically cancelled) nodes encountered in a
+     * traversal from head.
+     */
+    private void sweep() {
+        for (Node p = head, s, n; p != null && (s = p.next) != null; ) {
+            if (!s.isMatched())
+                // Unmatched nodes are never self-linked
+                p = s;
+            else if ((n = s.next) == null) // trailing node is pinned
+                break;
+            else if (s == n)    // stale
+                // No need to also check for p == s, since that implies s == n
+                p = head;
+            else
+                p.casNext(s, n);
+        }
+    }
+
+    /**
+     * Main implementation of remove(Object)
+     */
+    private boolean findAndRemove(Object e) {
+        if (e != null) {
+            for (Node pred = null, p = head; p != null; ) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && e.equals(item) &&
+                        p.tryMatchData()) {
+                        unsplice(pred, p);
+                        return true;
+                    }
+                }
+                else if (item == null)
+                    break;
+                pred = p;
+                if ((p = p.next) == pred) { // stale
+                    pred = null;
+                    p = head;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Creates an initially empty {@code LinkedTransferQueue}.
+     */
+    public LinkedTransferQueue() {
+    }
+
+    /**
+     * Creates a {@code LinkedTransferQueue}
+     * initially containing the elements of the given collection,
+     * added in traversal order of the collection's iterator.
+     *
+     * @param c the collection of elements to initially contain
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public LinkedTransferQueue(Collection<? extends E> c) {
+        this();
+        addAll(c);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never block.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void put(E e) {
+        xfer(e, true, ASYNC, 0);
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never block or
+     * return {@code false}.
+     *
+     * @return {@code true} (as specified by
+     *  {@link java.util.concurrent.BlockingQueue#offer(Object,long,TimeUnit)
+     *  BlockingQueue.offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Inserts the specified element at the tail of this queue.
+     * As the queue is unbounded, this method will never throw
+     * {@link IllegalStateException} or return {@code false}.
+     *
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        xfer(e, true, ASYNC, 0);
+        return true;
+    }
+
+    /**
+     * Transfers the element to a waiting consumer immediately, if possible.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * otherwise returning {@code false} without enqueuing the element.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean tryTransfer(E e) {
+        return xfer(e, true, NOW, 0) == null;
+    }
+
+    /**
+     * Transfers the element to a consumer, waiting if necessary to do so.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else inserts the specified element at the tail of this queue
+     * and waits until the element is received by a consumer.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public void transfer(E e) throws InterruptedException {
+        if (xfer(e, true, SYNC, 0) != null) {
+            Thread.interrupted(); // failure possible only due to interrupt
+            throw new InterruptedException();
+        }
+    }
+
+    /**
+     * Transfers the element to a consumer if it is possible to do so
+     * before the timeout elapses.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else inserts the specified element at the tail of this queue
+     * and waits until the element is received by a consumer,
+     * returning {@code false} if the specified wait time elapses
+     * before the element can be transferred.
+     *
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean tryTransfer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (xfer(e, true, TIMED, unit.toNanos(timeout)) == null)
+            return true;
+        if (!Thread.interrupted())
+            return false;
+        throw new InterruptedException();
+    }
+
+    public E take() throws InterruptedException {
+        E e = xfer(null, false, SYNC, 0);
+        if (e != null)
+            return e;
+        Thread.interrupted();
+        throw new InterruptedException();
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E e = xfer(null, false, TIMED, unit.toNanos(timeout));
+        if (e != null || !Thread.interrupted())
+            return e;
+        throw new InterruptedException();
+    }
+
+    public E poll() {
+        return xfer(null, false, NOW, 0);
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * @throws NullPointerException     {@inheritDoc}
+     * @throws IllegalArgumentException {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue in proper sequence.
+     * The elements will be returned in order from first (head) to last (tail).
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue in proper sequence
+     */
+    public Iterator<E> iterator() {
+        return new Itr();
+    }
+
+    public E peek() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p) {
+                        @SuppressWarnings("unchecked") E e = (E) item;
+                        return e;
+                    }
+                }
+                else if (item == null)
+                    break;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains no elements.
+     *
+     * @return {@code true} if this queue contains no elements
+     */
+    public boolean isEmpty() {
+        return firstDataNode() == null;
+    }
+
+    public boolean hasWaitingConsumer() {
+        restartFromHead: for (;;) {
+            for (Node p = head; p != null;) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p)
+                        break;
+                }
+                else if (item == null)
+                    return true;
+                if (p == (p = p.next))
+                    continue restartFromHead;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Returns the number of elements in this queue.  If this queue
+     * contains more than {@code Integer.MAX_VALUE} elements, returns
+     * {@code Integer.MAX_VALUE}.
+     *
+     * <p>Beware that, unlike in most collections, this method is
+     * <em>NOT</em> a constant-time operation. Because of the
+     * asynchronous nature of these queues, determining the current
+     * number of elements requires an O(n) traversal.
+     *
+     * @return the number of elements in this queue
+     */
+    public int size() {
+        return countOfMode(true);
+    }
+
+    public int getWaitingConsumerCount() {
+        return countOfMode(false);
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.
+     * Returns {@code true} if this queue contained the specified element
+     * (or equivalently, if this queue changed as a result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        return findAndRemove(o);
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        if (o != null) {
+            for (Node p = head; p != null; p = succ(p)) {
+                Object item = p.item;
+                if (p.isData) {
+                    if (item != null && item != p && o.equals(item))
+                        return true;
+                }
+                else if (item == null)
+                    break;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because a
+     * {@code LinkedTransferQueue} is not capacity constrained.
+     *
+     * @return {@code Integer.MAX_VALUE} (as specified by
+     *         {@link java.util.concurrent.BlockingQueue#remainingCapacity()
+     *         BlockingQueue.remainingCapacity})
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     * @serialData All of the elements (each an {@code E}) in
+     * the proper order, followed by a null
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        s.defaultWriteObject();
+        for (E e : this)
+            s.writeObject(e);
+        // Use trailing null as sentinel
+        s.writeObject(null);
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        for (;;) {
+            @SuppressWarnings("unchecked")
+            E item = (E) s.readObject();
+            if (item == null)
+                break;
+            else
+                offer(item);
+        }
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long HEAD;
+    private static final long TAIL;
+    private static final long SWEEPVOTES;
+    static {
+        try {
+            HEAD = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("tail"));
+            SWEEPVOTES = U.objectFieldOffset
+                (LinkedTransferQueue.class.getDeclaredField("sweepVotes"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/Phaser.java b/java/util/concurrent/Phaser.java
new file mode 100644
index 0000000..9ef9936
--- /dev/null
+++ b/java/util/concurrent/Phaser.java
@@ -0,0 +1,1154 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.LockSupport;
+
+/**
+ * A reusable synchronization barrier, similar in functionality to
+ * {@link java.util.concurrent.CyclicBarrier CyclicBarrier} and
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * but supporting more flexible usage.
+ *
+ * <p><b>Registration.</b> Unlike the case for other barriers, the
+ * number of parties <em>registered</em> to synchronize on a phaser
+ * may vary over time.  Tasks may be registered at any time (using
+ * methods {@link #register}, {@link #bulkRegister}, or forms of
+ * constructors establishing initial numbers of parties), and
+ * optionally deregistered upon any arrival (using {@link
+ * #arriveAndDeregister}).  As is the case with most basic
+ * synchronization constructs, registration and deregistration affect
+ * only internal counts; they do not establish any further internal
+ * bookkeeping, so tasks cannot query whether they are registered.
+ * (However, you can introduce such bookkeeping by subclassing this
+ * class.)
+ *
+ * <p><b>Synchronization.</b> Like a {@code CyclicBarrier}, a {@code
+ * Phaser} may be repeatedly awaited.  Method {@link
+ * #arriveAndAwaitAdvance} has effect analogous to {@link
+ * java.util.concurrent.CyclicBarrier#await CyclicBarrier.await}. Each
+ * generation of a phaser has an associated phase number. The phase
+ * number starts at zero, and advances when all parties arrive at the
+ * phaser, wrapping around to zero after reaching {@code
+ * Integer.MAX_VALUE}. The use of phase numbers enables independent
+ * control of actions upon arrival at a phaser and upon awaiting
+ * others, via two kinds of methods that may be invoked by any
+ * registered party:
+ *
+ * <ul>
+ *
+ *   <li><b>Arrival.</b> Methods {@link #arrive} and
+ *       {@link #arriveAndDeregister} record arrival.  These methods
+ *       do not block, but return an associated <em>arrival phase
+ *       number</em>; that is, the phase number of the phaser to which
+ *       the arrival applied. When the final party for a given phase
+ *       arrives, an optional action is performed and the phase
+ *       advances.  These actions are performed by the party
+ *       triggering a phase advance, and are arranged by overriding
+ *       method {@link #onAdvance(int, int)}, which also controls
+ *       termination. Overriding this method is similar to, but more
+ *       flexible than, providing a barrier action to a {@code
+ *       CyclicBarrier}.
+ *
+ *   <li><b>Waiting.</b> Method {@link #awaitAdvance} requires an
+ *       argument indicating an arrival phase number, and returns when
+ *       the phaser advances to (or is already at) a different phase.
+ *       Unlike similar constructions using {@code CyclicBarrier},
+ *       method {@code awaitAdvance} continues to wait even if the
+ *       waiting thread is interrupted. Interruptible and timeout
+ *       versions are also available, but exceptions encountered while
+ *       tasks wait interruptibly or with timeout do not change the
+ *       state of the phaser. If necessary, you can perform any
+ *       associated recovery within handlers of those exceptions,
+ *       often after invoking {@code forceTermination}.  Phasers may
+ *       also be used by tasks executing in a {@link ForkJoinPool}.
+ *       Progress is ensured if the pool's parallelismLevel can
+ *       accommodate the maximum number of simultaneously blocked
+ *       parties.
+ *
+ * </ul>
+ *
+ * <p><b>Termination.</b> A phaser may enter a <em>termination</em>
+ * state, that may be checked using method {@link #isTerminated}. Upon
+ * termination, all synchronization methods immediately return without
+ * waiting for advance, as indicated by a negative return value.
+ * Similarly, attempts to register upon termination have no effect.
+ * Termination is triggered when an invocation of {@code onAdvance}
+ * returns {@code true}. The default implementation returns {@code
+ * true} if a deregistration has caused the number of registered
+ * parties to become zero.  As illustrated below, when phasers control
+ * actions with a fixed number of iterations, it is often convenient
+ * to override this method to cause termination when the current phase
+ * number reaches a threshold. Method {@link #forceTermination} is
+ * also available to abruptly release waiting threads and allow them
+ * to terminate.
+ *
+ * <p><b>Tiering.</b> Phasers may be <em>tiered</em> (i.e.,
+ * constructed in tree structures) to reduce contention. Phasers with
+ * large numbers of parties that would otherwise experience heavy
+ * synchronization contention costs may instead be set up so that
+ * groups of sub-phasers share a common parent.  This may greatly
+ * increase throughput even though it incurs greater per-operation
+ * overhead.
+ *
+ * <p>In a tree of tiered phasers, registration and deregistration of
+ * child phasers with their parent are managed automatically.
+ * Whenever the number of registered parties of a child phaser becomes
+ * non-zero (as established in the {@link #Phaser(Phaser,int)}
+ * constructor, {@link #register}, or {@link #bulkRegister}), the
+ * child phaser is registered with its parent.  Whenever the number of
+ * registered parties becomes zero as the result of an invocation of
+ * {@link #arriveAndDeregister}, the child phaser is deregistered
+ * from its parent.
+ *
+ * <p><b>Monitoring.</b> While synchronization methods may be invoked
+ * only by registered parties, the current state of a phaser may be
+ * monitored by any caller.  At any given moment there are {@link
+ * #getRegisteredParties} parties in total, of which {@link
+ * #getArrivedParties} have arrived at the current phase ({@link
+ * #getPhase}).  When the remaining ({@link #getUnarrivedParties})
+ * parties arrive, the phase advances.  The values returned by these
+ * methods may reflect transient states and so are not in general
+ * useful for synchronization control.  Method {@link #toString}
+ * returns snapshots of these state queries in a form convenient for
+ * informal monitoring.
+ *
+ * <p><b>Sample usages:</b>
+ *
+ * <p>A {@code Phaser} may be used instead of a {@code CountDownLatch}
+ * to control a one-shot action serving a variable number of parties.
+ * The typical idiom is for the method setting this up to first
+ * register, then start the actions, then deregister, as in:
+ *
+ * <pre> {@code
+ * void runTasks(List<Runnable> tasks) {
+ *   final Phaser phaser = new Phaser(1); // "1" to register self
+ *   // create and start threads
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         phaser.arriveAndAwaitAdvance(); // await all creation
+ *         task.run();
+ *       }
+ *     }.start();
+ *   }
+ *
+ *   // allow threads to start and deregister self
+ *   phaser.arriveAndDeregister();
+ * }}</pre>
+ *
+ * <p>One way to cause a set of threads to repeatedly perform actions
+ * for a given number of iterations is to override {@code onAdvance}:
+ *
+ * <pre> {@code
+ * void startTasks(List<Runnable> tasks, final int iterations) {
+ *   final Phaser phaser = new Phaser() {
+ *     protected boolean onAdvance(int phase, int registeredParties) {
+ *       return phase >= iterations || registeredParties == 0;
+ *     }
+ *   };
+ *   phaser.register();
+ *   for (final Runnable task : tasks) {
+ *     phaser.register();
+ *     new Thread() {
+ *       public void run() {
+ *         do {
+ *           task.run();
+ *           phaser.arriveAndAwaitAdvance();
+ *         } while (!phaser.isTerminated());
+ *       }
+ *     }.start();
+ *   }
+ *   phaser.arriveAndDeregister(); // deregister self, don't wait
+ * }}</pre>
+ *
+ * If the main task must later await termination, it
+ * may re-register and then execute a similar loop:
+ * <pre> {@code
+ *   // ...
+ *   phaser.register();
+ *   while (!phaser.isTerminated())
+ *     phaser.arriveAndAwaitAdvance();}</pre>
+ *
+ * <p>Related constructions may be used to await particular phase numbers
+ * in contexts where you are sure that the phase will never wrap around
+ * {@code Integer.MAX_VALUE}. For example:
+ *
+ * <pre> {@code
+ * void awaitPhase(Phaser phaser, int phase) {
+ *   int p = phaser.register(); // assumes caller not already registered
+ *   while (p < phase) {
+ *     if (phaser.isTerminated())
+ *       // ... deal with unexpected termination
+ *     else
+ *       p = phaser.arriveAndAwaitAdvance();
+ *   }
+ *   phaser.arriveAndDeregister();
+ * }}</pre>
+ *
+ *
+ * <p>To create a set of {@code n} tasks using a tree of phasers, you
+ * could use code of the following form, assuming a Task class with a
+ * constructor accepting a {@code Phaser} that it registers with upon
+ * construction. After invocation of {@code build(new Task[n], 0, n,
+ * new Phaser())}, these tasks could then be started, for example by
+ * submitting to a pool:
+ *
+ * <pre> {@code
+ * void build(Task[] tasks, int lo, int hi, Phaser ph) {
+ *   if (hi - lo > TASKS_PER_PHASER) {
+ *     for (int i = lo; i < hi; i += TASKS_PER_PHASER) {
+ *       int j = Math.min(i + TASKS_PER_PHASER, hi);
+ *       build(tasks, i, j, new Phaser(ph));
+ *     }
+ *   } else {
+ *     for (int i = lo; i < hi; ++i)
+ *       tasks[i] = new Task(ph);
+ *       // assumes new Task(ph) performs ph.register()
+ *   }
+ * }}</pre>
+ *
+ * The best value of {@code TASKS_PER_PHASER} depends mainly on
+ * expected synchronization rates. A value as low as four may
+ * be appropriate for extremely small per-phase task bodies (thus
+ * high rates), or up to hundreds for extremely large ones.
+ *
+ * <p><b>Implementation notes</b>: This implementation restricts the
+ * maximum number of parties to 65535. Attempts to register additional
+ * parties result in {@code IllegalStateException}. However, you can and
+ * should create tiered phasers to accommodate arbitrarily large sets
+ * of participants.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class Phaser {
+    /*
+     * This class implements an extension of X10 "clocks".  Thanks to
+     * Vijay Saraswat for the idea, and to Vivek Sarkar for
+     * enhancements to extend functionality.
+     */
+
+    /**
+     * Primary state representation, holding four bit-fields:
+     *
+     * unarrived  -- the number of parties yet to hit barrier (bits  0-15)
+     * parties    -- the number of parties to wait            (bits 16-31)
+     * phase      -- the generation of the barrier            (bits 32-62)
+     * terminated -- set if barrier is terminated             (bit  63 / sign)
+     *
+     * Except that a phaser with no registered parties is
+     * distinguished by the otherwise illegal state of having zero
+     * parties and one unarrived parties (encoded as EMPTY below).
+     *
+     * To efficiently maintain atomicity, these values are packed into
+     * a single (atomic) long. Good performance relies on keeping
+     * state decoding and encoding simple, and keeping race windows
+     * short.
+     *
+     * All state updates are performed via CAS except initial
+     * registration of a sub-phaser (i.e., one with a non-null
+     * parent).  In this (relatively rare) case, we use built-in
+     * synchronization to lock while first registering with its
+     * parent.
+     *
+     * The phase of a subphaser is allowed to lag that of its
+     * ancestors until it is actually accessed -- see method
+     * reconcileState.
+     */
+    private volatile long state;
+
+    private static final int  MAX_PARTIES     = 0xffff;
+    private static final int  MAX_PHASE       = Integer.MAX_VALUE;
+    private static final int  PARTIES_SHIFT   = 16;
+    private static final int  PHASE_SHIFT     = 32;
+    private static final int  UNARRIVED_MASK  = 0xffff;      // to mask ints
+    private static final long PARTIES_MASK    = 0xffff0000L; // to mask longs
+    private static final long COUNTS_MASK     = 0xffffffffL;
+    private static final long TERMINATION_BIT = 1L << 63;
+
+    // some special values
+    private static final int  ONE_ARRIVAL     = 1;
+    private static final int  ONE_PARTY       = 1 << PARTIES_SHIFT;
+    private static final int  ONE_DEREGISTER  = ONE_ARRIVAL|ONE_PARTY;
+    private static final int  EMPTY           = 1;
+
+    // The following unpacking methods are usually manually inlined
+
+    private static int unarrivedOf(long s) {
+        int counts = (int)s;
+        return (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+    }
+
+    private static int partiesOf(long s) {
+        return (int)s >>> PARTIES_SHIFT;
+    }
+
+    private static int phaseOf(long s) {
+        return (int)(s >>> PHASE_SHIFT);
+    }
+
+    private static int arrivedOf(long s) {
+        int counts = (int)s;
+        return (counts == EMPTY) ? 0 :
+            (counts >>> PARTIES_SHIFT) - (counts & UNARRIVED_MASK);
+    }
+
+    /**
+     * The parent of this phaser, or null if none.
+     */
+    private final Phaser parent;
+
+    /**
+     * The root of phaser tree. Equals this if not in a tree.
+     */
+    private final Phaser root;
+
+    /**
+     * Heads of Treiber stacks for waiting threads. To eliminate
+     * contention when releasing some threads while adding others, we
+     * use two of them, alternating across even and odd phases.
+     * Subphasers share queues with root to speed up releases.
+     */
+    private final AtomicReference<QNode> evenQ;
+    private final AtomicReference<QNode> oddQ;
+
+    private AtomicReference<QNode> queueFor(int phase) {
+        return ((phase & 1) == 0) ? evenQ : oddQ;
+    }
+
+    /**
+     * Returns message string for bounds exceptions on arrival.
+     */
+    private String badArrive(long s) {
+        return "Attempted arrival of unregistered party for " +
+            stateToString(s);
+    }
+
+    /**
+     * Returns message string for bounds exceptions on registration.
+     */
+    private String badRegister(long s) {
+        return "Attempt to register more than " +
+            MAX_PARTIES + " parties for " + stateToString(s);
+    }
+
+    /**
+     * Main implementation for methods arrive and arriveAndDeregister.
+     * Manually tuned to speed up and minimize race windows for the
+     * common case of just decrementing unarrived field.
+     *
+     * @param adjust value to subtract from state;
+     *               ONE_ARRIVAL for arrive,
+     *               ONE_DEREGISTER for arriveAndDeregister
+     */
+    private int doArrive(int adjust) {
+        final Phaser root = this.root;
+        for (;;) {
+            long s = (root == this) ? state : reconcileState();
+            int phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                return phase;
+            int counts = (int)s;
+            int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+            if (unarrived <= 0)
+                throw new IllegalStateException(badArrive(s));
+            if (U.compareAndSwapLong(this, STATE, s, s-=adjust)) {
+                if (unarrived == 1) {
+                    long n = s & PARTIES_MASK;  // base of next state
+                    int nextUnarrived = (int)n >>> PARTIES_SHIFT;
+                    if (root == this) {
+                        if (onAdvance(phase, nextUnarrived))
+                            n |= TERMINATION_BIT;
+                        else if (nextUnarrived == 0)
+                            n |= EMPTY;
+                        else
+                            n |= nextUnarrived;
+                        int nextPhase = (phase + 1) & MAX_PHASE;
+                        n |= (long)nextPhase << PHASE_SHIFT;
+                        U.compareAndSwapLong(this, STATE, s, n);
+                        releaseWaiters(phase);
+                    }
+                    else if (nextUnarrived == 0) { // propagate deregistration
+                        phase = parent.doArrive(ONE_DEREGISTER);
+                        U.compareAndSwapLong(this, STATE, s, s | EMPTY);
+                    }
+                    else
+                        phase = parent.doArrive(ONE_ARRIVAL);
+                }
+                return phase;
+            }
+        }
+    }
+
+    /**
+     * Implementation of register, bulkRegister.
+     *
+     * @param registrations number to add to both parties and
+     * unarrived fields. Must be greater than zero.
+     */
+    private int doRegister(int registrations) {
+        // adjustment to state
+        long adjust = ((long)registrations << PARTIES_SHIFT) | registrations;
+        final Phaser parent = this.parent;
+        int phase;
+        for (;;) {
+            long s = (parent == null) ? state : reconcileState();
+            int counts = (int)s;
+            int parties = counts >>> PARTIES_SHIFT;
+            int unarrived = counts & UNARRIVED_MASK;
+            if (registrations > MAX_PARTIES - parties)
+                throw new IllegalStateException(badRegister(s));
+            phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                break;
+            if (counts != EMPTY) {                  // not 1st registration
+                if (parent == null || reconcileState() == s) {
+                    if (unarrived == 0)             // wait out advance
+                        root.internalAwaitAdvance(phase, null);
+                    else if (U.compareAndSwapLong(this, STATE, s, s + adjust))
+                        break;
+                }
+            }
+            else if (parent == null) {              // 1st root registration
+                long next = ((long)phase << PHASE_SHIFT) | adjust;
+                if (U.compareAndSwapLong(this, STATE, s, next))
+                    break;
+            }
+            else {
+                synchronized (this) {               // 1st sub registration
+                    if (state == s) {               // recheck under lock
+                        phase = parent.doRegister(1);
+                        if (phase < 0)
+                            break;
+                        // finish registration whenever parent registration
+                        // succeeded, even when racing with termination,
+                        // since these are part of the same "transaction".
+                        while (!U.compareAndSwapLong
+                               (this, STATE, s,
+                                ((long)phase << PHASE_SHIFT) | adjust)) {
+                            s = state;
+                            phase = (int)(root.state >>> PHASE_SHIFT);
+                            // assert (int)s == EMPTY;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        return phase;
+    }
+
+    /**
+     * Resolves lagged phase propagation from root if necessary.
+     * Reconciliation normally occurs when root has advanced but
+     * subphasers have not yet done so, in which case they must finish
+     * their own advance by setting unarrived to parties (or if
+     * parties is zero, resetting to unregistered EMPTY state).
+     *
+     * @return reconciled state
+     */
+    private long reconcileState() {
+        final Phaser root = this.root;
+        long s = state;
+        if (root != this) {
+            int phase, p;
+            // CAS to root phase with current parties, tripping unarrived
+            while ((phase = (int)(root.state >>> PHASE_SHIFT)) !=
+                   (int)(s >>> PHASE_SHIFT) &&
+                   !U.compareAndSwapLong
+                   (this, STATE, s,
+                    s = (((long)phase << PHASE_SHIFT) |
+                         ((phase < 0) ? (s & COUNTS_MASK) :
+                          (((p = (int)s >>> PARTIES_SHIFT) == 0) ? EMPTY :
+                           ((s & PARTIES_MASK) | p))))))
+                s = state;
+        }
+        return s;
+    }
+
+    /**
+     * Creates a new phaser with no initially registered parties, no
+     * parent, and initial phase number 0. Any thread using this
+     * phaser will need to first register for it.
+     */
+    public Phaser() {
+        this(null, 0);
+    }
+
+    /**
+     * Creates a new phaser with the given number of registered
+     * unarrived parties, no parent, and initial phase number 0.
+     *
+     * @param parties the number of parties required to advance to the
+     * next phase
+     * @throws IllegalArgumentException if parties less than zero
+     * or greater than the maximum number of parties supported
+     */
+    public Phaser(int parties) {
+        this(null, parties);
+    }
+
+    /**
+     * Equivalent to {@link #Phaser(Phaser, int) Phaser(parent, 0)}.
+     *
+     * @param parent the parent phaser
+     */
+    public Phaser(Phaser parent) {
+        this(parent, 0);
+    }
+
+    /**
+     * Creates a new phaser with the given parent and number of
+     * registered unarrived parties.  When the given parent is non-null
+     * and the given number of parties is greater than zero, this
+     * child phaser is registered with its parent.
+     *
+     * @param parent the parent phaser
+     * @param parties the number of parties required to advance to the
+     * next phase
+     * @throws IllegalArgumentException if parties less than zero
+     * or greater than the maximum number of parties supported
+     */
+    public Phaser(Phaser parent, int parties) {
+        if (parties >>> PARTIES_SHIFT != 0)
+            throw new IllegalArgumentException("Illegal number of parties");
+        int phase = 0;
+        this.parent = parent;
+        if (parent != null) {
+            final Phaser root = parent.root;
+            this.root = root;
+            this.evenQ = root.evenQ;
+            this.oddQ = root.oddQ;
+            if (parties != 0)
+                phase = parent.doRegister(1);
+        }
+        else {
+            this.root = this;
+            this.evenQ = new AtomicReference<QNode>();
+            this.oddQ = new AtomicReference<QNode>();
+        }
+        this.state = (parties == 0) ? (long)EMPTY :
+            ((long)phase << PHASE_SHIFT) |
+            ((long)parties << PARTIES_SHIFT) |
+            ((long)parties);
+    }
+
+    /**
+     * Adds a new unarrived party to this phaser.  If an ongoing
+     * invocation of {@link #onAdvance} is in progress, this method
+     * may await its completion before returning.  If this phaser has
+     * a parent, and this phaser previously had no registered parties,
+     * this child phaser is also registered with its parent. If
+     * this phaser is terminated, the attempt to register has
+     * no effect, and a negative value is returned.
+     *
+     * @return the arrival phase number to which this registration
+     * applied.  If this value is negative, then this phaser has
+     * terminated, in which case registration has no effect.
+     * @throws IllegalStateException if attempting to register more
+     * than the maximum supported number of parties
+     */
+    public int register() {
+        return doRegister(1);
+    }
+
+    /**
+     * Adds the given number of new unarrived parties to this phaser.
+     * If an ongoing invocation of {@link #onAdvance} is in progress,
+     * this method may await its completion before returning.  If this
+     * phaser has a parent, and the given number of parties is greater
+     * than zero, and this phaser previously had no registered
+     * parties, this child phaser is also registered with its parent.
+     * If this phaser is terminated, the attempt to register has no
+     * effect, and a negative value is returned.
+     *
+     * @param parties the number of additional parties required to
+     * advance to the next phase
+     * @return the arrival phase number to which this registration
+     * applied.  If this value is negative, then this phaser has
+     * terminated, in which case registration has no effect.
+     * @throws IllegalStateException if attempting to register more
+     * than the maximum supported number of parties
+     * @throws IllegalArgumentException if {@code parties < 0}
+     */
+    public int bulkRegister(int parties) {
+        if (parties < 0)
+            throw new IllegalArgumentException();
+        if (parties == 0)
+            return getPhase();
+        return doRegister(parties);
+    }
+
+    /**
+     * Arrives at this phaser, without waiting for others to arrive.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or a negative value if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of unarrived parties would become negative
+     */
+    public int arrive() {
+        return doArrive(ONE_ARRIVAL);
+    }
+
+    /**
+     * Arrives at this phaser and deregisters from it without waiting
+     * for others to arrive. Deregistration reduces the number of
+     * parties required to advance in future phases.  If this phaser
+     * has a parent, and deregistration causes this phaser to have
+     * zero parties, this phaser is also deregistered from its parent.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or a negative value if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of registered or unarrived parties would become negative
+     */
+    public int arriveAndDeregister() {
+        return doArrive(ONE_DEREGISTER);
+    }
+
+    /**
+     * Arrives at this phaser and awaits others. Equivalent in effect
+     * to {@code awaitAdvance(arrive())}.  If you need to await with
+     * interruption or timeout, you can arrange this with an analogous
+     * construction using one of the other forms of the {@code
+     * awaitAdvance} method.  If instead you need to deregister upon
+     * arrival, use {@code awaitAdvance(arriveAndDeregister())}.
+     *
+     * <p>It is a usage error for an unregistered party to invoke this
+     * method.  However, this error may result in an {@code
+     * IllegalStateException} only upon some subsequent operation on
+     * this phaser, if ever.
+     *
+     * @return the arrival phase number, or the (negative)
+     * {@linkplain #getPhase() current phase} if terminated
+     * @throws IllegalStateException if not terminated and the number
+     * of unarrived parties would become negative
+     */
+    public int arriveAndAwaitAdvance() {
+        // Specialization of doArrive+awaitAdvance eliminating some reads/paths
+        final Phaser root = this.root;
+        for (;;) {
+            long s = (root == this) ? state : reconcileState();
+            int phase = (int)(s >>> PHASE_SHIFT);
+            if (phase < 0)
+                return phase;
+            int counts = (int)s;
+            int unarrived = (counts == EMPTY) ? 0 : (counts & UNARRIVED_MASK);
+            if (unarrived <= 0)
+                throw new IllegalStateException(badArrive(s));
+            if (U.compareAndSwapLong(this, STATE, s, s -= ONE_ARRIVAL)) {
+                if (unarrived > 1)
+                    return root.internalAwaitAdvance(phase, null);
+                if (root != this)
+                    return parent.arriveAndAwaitAdvance();
+                long n = s & PARTIES_MASK;  // base of next state
+                int nextUnarrived = (int)n >>> PARTIES_SHIFT;
+                if (onAdvance(phase, nextUnarrived))
+                    n |= TERMINATION_BIT;
+                else if (nextUnarrived == 0)
+                    n |= EMPTY;
+                else
+                    n |= nextUnarrived;
+                int nextPhase = (phase + 1) & MAX_PHASE;
+                n |= (long)nextPhase << PHASE_SHIFT;
+                if (!U.compareAndSwapLong(this, STATE, s, n))
+                    return (int)(state >>> PHASE_SHIFT); // terminated
+                releaseWaiters(phase);
+                return nextPhase;
+            }
+        }
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value, returning immediately if the current phase is not equal
+     * to the given phase value or this phaser is terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     */
+    public int awaitAdvance(int phase) {
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase)
+            return root.internalAwaitAdvance(phase, null);
+        return p;
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value, throwing {@code InterruptedException} if interrupted
+     * while waiting, or returning immediately if the current phase is
+     * not equal to the given phase value or this phaser is
+     * terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     * @throws InterruptedException if thread interrupted while waiting
+     */
+    public int awaitAdvanceInterruptibly(int phase)
+        throws InterruptedException {
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase) {
+            QNode node = new QNode(this, phase, true, false, 0L);
+            p = root.internalAwaitAdvance(phase, node);
+            if (node.wasInterrupted)
+                throw new InterruptedException();
+        }
+        return p;
+    }
+
+    /**
+     * Awaits the phase of this phaser to advance from the given phase
+     * value or the given timeout to elapse, throwing {@code
+     * InterruptedException} if interrupted while waiting, or
+     * returning immediately if the current phase is not equal to the
+     * given phase value or this phaser is terminated.
+     *
+     * @param phase an arrival phase number, or negative value if
+     * terminated; this argument is normally the value returned by a
+     * previous call to {@code arrive} or {@code arriveAndDeregister}.
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return the next arrival phase number, or the argument if it is
+     * negative, or the (negative) {@linkplain #getPhase() current phase}
+     * if terminated
+     * @throws InterruptedException if thread interrupted while waiting
+     * @throws TimeoutException if timed out while waiting
+     */
+    public int awaitAdvanceInterruptibly(int phase,
+                                         long timeout, TimeUnit unit)
+        throws InterruptedException, TimeoutException {
+        long nanos = unit.toNanos(timeout);
+        final Phaser root = this.root;
+        long s = (root == this) ? state : reconcileState();
+        int p = (int)(s >>> PHASE_SHIFT);
+        if (phase < 0)
+            return phase;
+        if (p == phase) {
+            QNode node = new QNode(this, phase, true, true, nanos);
+            p = root.internalAwaitAdvance(phase, node);
+            if (node.wasInterrupted)
+                throw new InterruptedException();
+            else if (p == phase)
+                throw new TimeoutException();
+        }
+        return p;
+    }
+
+    /**
+     * Forces this phaser to enter termination state.  Counts of
+     * registered parties are unaffected.  If this phaser is a member
+     * of a tiered set of phasers, then all of the phasers in the set
+     * are terminated.  If this phaser is already terminated, this
+     * method has no effect.  This method may be useful for
+     * coordinating recovery after one or more tasks encounter
+     * unexpected exceptions.
+     */
+    public void forceTermination() {
+        // Only need to change root state
+        final Phaser root = this.root;
+        long s;
+        while ((s = root.state) >= 0) {
+            if (U.compareAndSwapLong(root, STATE, s, s | TERMINATION_BIT)) {
+                // signal all threads
+                releaseWaiters(0); // Waiters on evenQ
+                releaseWaiters(1); // Waiters on oddQ
+                return;
+            }
+        }
+    }
+
+    /**
+     * Returns the current phase number. The maximum phase number is
+     * {@code Integer.MAX_VALUE}, after which it restarts at
+     * zero. Upon termination, the phase number is negative,
+     * in which case the prevailing phase prior to termination
+     * may be obtained via {@code getPhase() + Integer.MIN_VALUE}.
+     *
+     * @return the phase number, or a negative value if terminated
+     */
+    public final int getPhase() {
+        return (int)(root.state >>> PHASE_SHIFT);
+    }
+
+    /**
+     * Returns the number of parties registered at this phaser.
+     *
+     * @return the number of parties
+     */
+    public int getRegisteredParties() {
+        return partiesOf(state);
+    }
+
+    /**
+     * Returns the number of registered parties that have arrived at
+     * the current phase of this phaser. If this phaser has terminated,
+     * the returned value is meaningless and arbitrary.
+     *
+     * @return the number of arrived parties
+     */
+    public int getArrivedParties() {
+        return arrivedOf(reconcileState());
+    }
+
+    /**
+     * Returns the number of registered parties that have not yet
+     * arrived at the current phase of this phaser. If this phaser has
+     * terminated, the returned value is meaningless and arbitrary.
+     *
+     * @return the number of unarrived parties
+     */
+    public int getUnarrivedParties() {
+        return unarrivedOf(reconcileState());
+    }
+
+    /**
+     * Returns the parent of this phaser, or {@code null} if none.
+     *
+     * @return the parent of this phaser, or {@code null} if none
+     */
+    public Phaser getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the root ancestor of this phaser, which is the same as
+     * this phaser if it has no parent.
+     *
+     * @return the root ancestor of this phaser
+     */
+    public Phaser getRoot() {
+        return root;
+    }
+
+    /**
+     * Returns {@code true} if this phaser has been terminated.
+     *
+     * @return {@code true} if this phaser has been terminated
+     */
+    public boolean isTerminated() {
+        return root.state < 0L;
+    }
+
+    /**
+     * Overridable method to perform an action upon impending phase
+     * advance, and to control termination. This method is invoked
+     * upon arrival of the party advancing this phaser (when all other
+     * waiting parties are dormant).  If this method returns {@code
+     * true}, this phaser will be set to a final termination state
+     * upon advance, and subsequent calls to {@link #isTerminated}
+     * will return true. Any (unchecked) Exception or Error thrown by
+     * an invocation of this method is propagated to the party
+     * attempting to advance this phaser, in which case no advance
+     * occurs.
+     *
+     * <p>The arguments to this method provide the state of the phaser
+     * prevailing for the current transition.  The effects of invoking
+     * arrival, registration, and waiting methods on this phaser from
+     * within {@code onAdvance} are unspecified and should not be
+     * relied on.
+     *
+     * <p>If this phaser is a member of a tiered set of phasers, then
+     * {@code onAdvance} is invoked only for its root phaser on each
+     * advance.
+     *
+     * <p>To support the most common use cases, the default
+     * implementation of this method returns {@code true} when the
+     * number of registered parties has become zero as the result of a
+     * party invoking {@code arriveAndDeregister}.  You can disable
+     * this behavior, thus enabling continuation upon future
+     * registrations, by overriding this method to always return
+     * {@code false}:
+     *
+     * <pre> {@code
+     * Phaser phaser = new Phaser() {
+     *   protected boolean onAdvance(int phase, int parties) { return false; }
+     * }}</pre>
+     *
+     * @param phase the current phase number on entry to this method,
+     * before this phaser is advanced
+     * @param registeredParties the current number of registered parties
+     * @return {@code true} if this phaser should terminate
+     */
+    protected boolean onAdvance(int phase, int registeredParties) {
+        return registeredParties == 0;
+    }
+
+    /**
+     * Returns a string identifying this phaser, as well as its
+     * state.  The state, in brackets, includes the String {@code
+     * "phase = "} followed by the phase number, {@code "parties = "}
+     * followed by the number of registered parties, and {@code
+     * "arrived = "} followed by the number of arrived parties.
+     *
+     * @return a string identifying this phaser, as well as its state
+     */
+    public String toString() {
+        return stateToString(reconcileState());
+    }
+
+    /**
+     * Implementation of toString and string-based error messages.
+     */
+    private String stateToString(long s) {
+        return super.toString() +
+            "[phase = " + phaseOf(s) +
+            " parties = " + partiesOf(s) +
+            " arrived = " + arrivedOf(s) + "]";
+    }
+
+    // Waiting mechanics
+
+    /**
+     * Removes and signals threads from queue for phase.
+     */
+    private void releaseWaiters(int phase) {
+        QNode q;   // first element of queue
+        Thread t;  // its thread
+        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+        while ((q = head.get()) != null &&
+               q.phase != (int)(root.state >>> PHASE_SHIFT)) {
+            if (head.compareAndSet(q, q.next) &&
+                (t = q.thread) != null) {
+                q.thread = null;
+                LockSupport.unpark(t);
+            }
+        }
+    }
+
+    /**
+     * Variant of releaseWaiters that additionally tries to remove any
+     * nodes no longer waiting for advance due to timeout or
+     * interrupt. Currently, nodes are removed only if they are at
+     * head of queue, which suffices to reduce memory footprint in
+     * most usages.
+     *
+     * @return current phase on exit
+     */
+    private int abortWait(int phase) {
+        AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+        for (;;) {
+            Thread t;
+            QNode q = head.get();
+            int p = (int)(root.state >>> PHASE_SHIFT);
+            if (q == null || ((t = q.thread) != null && q.phase == p))
+                return p;
+            if (head.compareAndSet(q, q.next) && t != null) {
+                q.thread = null;
+                LockSupport.unpark(t);
+            }
+        }
+    }
+
+    /** The number of CPUs, for spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * The number of times to spin before blocking while waiting for
+     * advance, per arrival while waiting. On multiprocessors, fully
+     * blocking and waking up a large number of threads all at once is
+     * usually a very slow process, so we use rechargeable spins to
+     * avoid it when threads regularly arrive: When a thread in
+     * internalAwaitAdvance notices another arrival before blocking,
+     * and there appear to be enough CPUs available, it spins
+     * SPINS_PER_ARRIVAL more times before blocking. The value trades
+     * off good-citizenship vs big unnecessary slowdowns.
+     */
+    static final int SPINS_PER_ARRIVAL = (NCPU < 2) ? 1 : 1 << 8;
+
+    /**
+     * Possibly blocks and waits for phase to advance unless aborted.
+     * Call only on root phaser.
+     *
+     * @param phase current phase
+     * @param node if non-null, the wait node to track interrupt and timeout;
+     * if null, denotes noninterruptible wait
+     * @return current phase
+     */
+    private int internalAwaitAdvance(int phase, QNode node) {
+        // assert root == this;
+        releaseWaiters(phase-1);          // ensure old queue clean
+        boolean queued = false;           // true when node is enqueued
+        int lastUnarrived = 0;            // to increase spins upon change
+        int spins = SPINS_PER_ARRIVAL;
+        long s;
+        int p;
+        while ((p = (int)((s = state) >>> PHASE_SHIFT)) == phase) {
+            if (node == null) {           // spinning in noninterruptible mode
+                int unarrived = (int)s & UNARRIVED_MASK;
+                if (unarrived != lastUnarrived &&
+                    (lastUnarrived = unarrived) < NCPU)
+                    spins += SPINS_PER_ARRIVAL;
+                boolean interrupted = Thread.interrupted();
+                if (interrupted || --spins < 0) { // need node to record intr
+                    node = new QNode(this, phase, false, false, 0L);
+                    node.wasInterrupted = interrupted;
+                }
+            }
+            else if (node.isReleasable()) // done or aborted
+                break;
+            else if (!queued) {           // push onto queue
+                AtomicReference<QNode> head = (phase & 1) == 0 ? evenQ : oddQ;
+                QNode q = node.next = head.get();
+                if ((q == null || q.phase == phase) &&
+                    (int)(state >>> PHASE_SHIFT) == phase) // avoid stale enq
+                    queued = head.compareAndSet(q, node);
+            }
+            else {
+                try {
+                    ForkJoinPool.managedBlock(node);
+                } catch (InterruptedException cantHappen) {
+                    node.wasInterrupted = true;
+                }
+            }
+        }
+
+        if (node != null) {
+            if (node.thread != null)
+                node.thread = null;       // avoid need for unpark()
+            if (node.wasInterrupted && !node.interruptible)
+                Thread.currentThread().interrupt();
+            if (p == phase && (p = (int)(state >>> PHASE_SHIFT)) == phase)
+                return abortWait(phase); // possibly clean up on abort
+        }
+        releaseWaiters(phase);
+        return p;
+    }
+
+    /**
+     * Wait nodes for Treiber stack representing wait queue.
+     */
+    static final class QNode implements ForkJoinPool.ManagedBlocker {
+        final Phaser phaser;
+        final int phase;
+        final boolean interruptible;
+        final boolean timed;
+        boolean wasInterrupted;
+        long nanos;
+        final long deadline;
+        volatile Thread thread; // nulled to cancel wait
+        QNode next;
+
+        QNode(Phaser phaser, int phase, boolean interruptible,
+              boolean timed, long nanos) {
+            this.phaser = phaser;
+            this.phase = phase;
+            this.interruptible = interruptible;
+            this.nanos = nanos;
+            this.timed = timed;
+            this.deadline = timed ? System.nanoTime() + nanos : 0L;
+            thread = Thread.currentThread();
+        }
+
+        public boolean isReleasable() {
+            if (thread == null)
+                return true;
+            if (phaser.getPhase() != phase) {
+                thread = null;
+                return true;
+            }
+            if (Thread.interrupted())
+                wasInterrupted = true;
+            if (wasInterrupted && interruptible) {
+                thread = null;
+                return true;
+            }
+            if (timed &&
+                (nanos <= 0L || (nanos = deadline - System.nanoTime()) <= 0L)) {
+                thread = null;
+                return true;
+            }
+            return false;
+        }
+
+        public boolean block() {
+            while (!isReleasable()) {
+                if (timed)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    LockSupport.park(this);
+            }
+            return true;
+        }
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (Phaser.class.getDeclaredField("state"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/PriorityBlockingQueue.java b/java/util/concurrent/PriorityBlockingQueue.java
new file mode 100644
index 0000000..644de86
--- /dev/null
+++ b/java/util/concurrent/PriorityBlockingQueue.java
@@ -0,0 +1,1023 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.PriorityQueue;
+import java.util.Queue;
+import java.util.SortedSet;
+import java.util.Spliterator;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Consumer;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * An unbounded {@linkplain BlockingQueue blocking queue} that uses
+ * the same ordering rules as class {@link PriorityQueue} and supplies
+ * blocking retrieval operations.  While this queue is logically
+ * unbounded, attempted additions may fail due to resource exhaustion
+ * (causing {@code OutOfMemoryError}). This class does not permit
+ * {@code null} elements.  A priority queue relying on {@linkplain
+ * Comparable natural ordering} also does not permit insertion of
+ * non-comparable objects (doing so results in
+ * {@code ClassCastException}).
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.  The Iterator provided in method {@link
+ * #iterator()} is <em>not</em> guaranteed to traverse the elements of
+ * the PriorityBlockingQueue in any particular order. If you need
+ * ordered traversal, consider using
+ * {@code Arrays.sort(pq.toArray())}.  Also, method {@code drainTo}
+ * can be used to <em>remove</em> some or all elements in priority
+ * order and place them in another collection.
+ *
+ * <p>Operations on this class make no guarantees about the ordering
+ * of elements with equal priority. If you need to enforce an
+ * ordering, you can define custom classes or comparators that use a
+ * secondary key to break ties in primary priority values.  For
+ * example, here is a class that applies first-in-first-out
+ * tie-breaking to comparable elements. To use it, you would insert a
+ * {@code new FIFOEntry(anEntry)} instead of a plain entry object.
+ *
+ * <pre> {@code
+ * class FIFOEntry<E extends Comparable<? super E>>
+ *     implements Comparable<FIFOEntry<E>> {
+ *   static final AtomicLong seq = new AtomicLong(0);
+ *   final long seqNum;
+ *   final E entry;
+ *   public FIFOEntry(E entry) {
+ *     seqNum = seq.getAndIncrement();
+ *     this.entry = entry;
+ *   }
+ *   public E getEntry() { return entry; }
+ *   public int compareTo(FIFOEntry<E> other) {
+ *     int res = entry.compareTo(other.entry);
+ *     if (res == 0 && other.entry != this.entry)
+ *       res = (seqNum < other.seqNum ? -1 : 1);
+ *     return res;
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+@SuppressWarnings("unchecked")
+public class PriorityBlockingQueue<E> extends AbstractQueue<E>
+    implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = 5595510919245408276L;
+
+    /*
+     * The implementation uses an array-based binary heap, with public
+     * operations protected with a single lock. However, allocation
+     * during resizing uses a simple spinlock (used only while not
+     * holding main lock) in order to allow takes to operate
+     * concurrently with allocation.  This avoids repeated
+     * postponement of waiting consumers and consequent element
+     * build-up. The need to back away from lock during allocation
+     * makes it impossible to simply wrap delegated
+     * java.util.PriorityQueue operations within a lock, as was done
+     * in a previous version of this class. To maintain
+     * interoperability, a plain PriorityQueue is still used during
+     * serialization, which maintains compatibility at the expense of
+     * transiently doubling overhead.
+     */
+
+    /**
+     * Default array capacity.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 11;
+
+    /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Priority queue represented as a balanced binary heap: the two
+     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
+     * priority queue is ordered by comparator, or by the elements'
+     * natural ordering, if comparator is null: For each node n in the
+     * heap and each descendant d of n, n <= d.  The element with the
+     * lowest value is in queue[0], assuming the queue is nonempty.
+     */
+    private transient Object[] queue;
+
+    /**
+     * The number of elements in the priority queue.
+     */
+    private transient int size;
+
+    /**
+     * The comparator, or null if priority queue uses elements'
+     * natural ordering.
+     */
+    private transient Comparator<? super E> comparator;
+
+    /**
+     * Lock used for all public operations.
+     */
+    private final ReentrantLock lock;
+
+    /**
+     * Condition for blocking when empty.
+     */
+    private final Condition notEmpty;
+
+    /**
+     * Spinlock for allocation, acquired via CAS.
+     */
+    private transient volatile int allocationSpinLock;
+
+    /**
+     * A plain PriorityQueue used only for serialization,
+     * to maintain compatibility with previous versions
+     * of this class. Non-null only during serialization/deserialization.
+     */
+    private PriorityQueue<E> q;
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the default
+     * initial capacity (11) that orders its elements according to
+     * their {@linkplain Comparable natural ordering}.
+     */
+    public PriorityBlockingQueue() {
+        this(DEFAULT_INITIAL_CAPACITY, null);
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the specified
+     * initial capacity that orders its elements according to their
+     * {@linkplain Comparable natural ordering}.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityBlockingQueue(int initialCapacity) {
+        this(initialCapacity, null);
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} with the specified initial
+     * capacity that orders its elements according to the specified
+     * comparator.
+     *
+     * @param initialCapacity the initial capacity for this priority queue
+     * @param  comparator the comparator that will be used to order this
+     *         priority queue.  If {@code null}, the {@linkplain Comparable
+     *         natural ordering} of the elements will be used.
+     * @throws IllegalArgumentException if {@code initialCapacity} is less
+     *         than 1
+     */
+    public PriorityBlockingQueue(int initialCapacity,
+                                 Comparator<? super E> comparator) {
+        if (initialCapacity < 1)
+            throw new IllegalArgumentException();
+        this.lock = new ReentrantLock();
+        this.notEmpty = lock.newCondition();
+        this.comparator = comparator;
+        this.queue = new Object[initialCapacity];
+    }
+
+    /**
+     * Creates a {@code PriorityBlockingQueue} containing the elements
+     * in the specified collection.  If the specified collection is a
+     * {@link SortedSet} or a {@link PriorityQueue}, this
+     * priority queue will be ordered according to the same ordering.
+     * Otherwise, this priority queue will be ordered according to the
+     * {@linkplain Comparable natural ordering} of its elements.
+     *
+     * @param  c the collection whose elements are to be placed
+     *         into this priority queue
+     * @throws ClassCastException if elements of the specified collection
+     *         cannot be compared to one another according to the priority
+     *         queue's ordering
+     * @throws NullPointerException if the specified collection or any
+     *         of its elements are null
+     */
+    public PriorityBlockingQueue(Collection<? extends E> c) {
+        this.lock = new ReentrantLock();
+        this.notEmpty = lock.newCondition();
+        boolean heapify = true; // true if not known to be in heap order
+        boolean screen = true;  // true if must screen for nulls
+        if (c instanceof SortedSet<?>) {
+            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
+            this.comparator = (Comparator<? super E>) ss.comparator();
+            heapify = false;
+        }
+        else if (c instanceof PriorityBlockingQueue<?>) {
+            PriorityBlockingQueue<? extends E> pq =
+                (PriorityBlockingQueue<? extends E>) c;
+            this.comparator = (Comparator<? super E>) pq.comparator();
+            screen = false;
+            if (pq.getClass() == PriorityBlockingQueue.class) // exact match
+                heapify = false;
+        }
+        Object[] a = c.toArray();
+        int n = a.length;
+        // If c.toArray incorrectly doesn't return Object[], copy it.
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf(a, n, Object[].class);
+        if (screen && (n == 1 || this.comparator != null)) {
+            for (int i = 0; i < n; ++i)
+                if (a[i] == null)
+                    throw new NullPointerException();
+        }
+        this.queue = a;
+        this.size = n;
+        if (heapify)
+            heapify();
+    }
+
+    /**
+     * Tries to grow array to accommodate at least one more element
+     * (but normally expand by about 50%), giving up (allowing retry)
+     * on contention (which we expect to be rare). Call only while
+     * holding lock.
+     *
+     * @param array the heap array
+     * @param oldCap the length of the array
+     */
+    private void tryGrow(Object[] array, int oldCap) {
+        lock.unlock(); // must release and then re-acquire main lock
+        Object[] newArray = null;
+        if (allocationSpinLock == 0 &&
+            U.compareAndSwapInt(this, ALLOCATIONSPINLOCK, 0, 1)) {
+            try {
+                int newCap = oldCap + ((oldCap < 64) ?
+                                       (oldCap + 2) : // grow faster if small
+                                       (oldCap >> 1));
+                if (newCap - MAX_ARRAY_SIZE > 0) {    // possible overflow
+                    int minCap = oldCap + 1;
+                    if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
+                        throw new OutOfMemoryError();
+                    newCap = MAX_ARRAY_SIZE;
+                }
+                if (newCap > oldCap && queue == array)
+                    newArray = new Object[newCap];
+            } finally {
+                allocationSpinLock = 0;
+            }
+        }
+        if (newArray == null) // back off if another thread is allocating
+            Thread.yield();
+        lock.lock();
+        if (newArray != null && queue == array) {
+            queue = newArray;
+            System.arraycopy(array, 0, newArray, 0, oldCap);
+        }
+    }
+
+    /**
+     * Mechanics for poll().  Call only while holding lock.
+     */
+    private E dequeue() {
+        int n = size - 1;
+        if (n < 0)
+            return null;
+        else {
+            Object[] array = queue;
+            E result = (E) array[0];
+            E x = (E) array[n];
+            array[n] = null;
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftDownComparable(0, x, array, n);
+            else
+                siftDownUsingComparator(0, x, array, n, cmp);
+            size = n;
+            return result;
+        }
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * promoting x up the tree until it is greater than or equal to
+     * its parent, or is the root.
+     *
+     * To simplify and speed up coercions and comparisons. the
+     * Comparable and Comparator versions are separated into different
+     * methods that are otherwise identical. (Similarly for siftDown.)
+     * These methods are static, with heap state as arguments, to
+     * simplify use in light of possible comparator exceptions.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     * @param array the heap array
+     */
+    private static <T> void siftUpComparable(int k, T x, Object[] array) {
+        Comparable<? super T> key = (Comparable<? super T>) x;
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = array[parent];
+            if (key.compareTo((T) e) >= 0)
+                break;
+            array[k] = e;
+            k = parent;
+        }
+        array[k] = key;
+    }
+
+    private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
+                                       Comparator<? super T> cmp) {
+        while (k > 0) {
+            int parent = (k - 1) >>> 1;
+            Object e = array[parent];
+            if (cmp.compare(x, (T) e) >= 0)
+                break;
+            array[k] = e;
+            k = parent;
+        }
+        array[k] = x;
+    }
+
+    /**
+     * Inserts item x at position k, maintaining heap invariant by
+     * demoting x down the tree repeatedly until it is less than or
+     * equal to its children or is a leaf.
+     *
+     * @param k the position to fill
+     * @param x the item to insert
+     * @param array the heap array
+     * @param n heap size
+     */
+    private static <T> void siftDownComparable(int k, T x, Object[] array,
+                                               int n) {
+        if (n > 0) {
+            Comparable<? super T> key = (Comparable<? super T>)x;
+            int half = n >>> 1;           // loop while a non-leaf
+            while (k < half) {
+                int child = (k << 1) + 1; // assume left child is least
+                Object c = array[child];
+                int right = child + 1;
+                if (right < n &&
+                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
+                    c = array[child = right];
+                if (key.compareTo((T) c) <= 0)
+                    break;
+                array[k] = c;
+                k = child;
+            }
+            array[k] = key;
+        }
+    }
+
+    private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
+                                                    int n,
+                                                    Comparator<? super T> cmp) {
+        if (n > 0) {
+            int half = n >>> 1;
+            while (k < half) {
+                int child = (k << 1) + 1;
+                Object c = array[child];
+                int right = child + 1;
+                if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
+                    c = array[child = right];
+                if (cmp.compare(x, (T) c) <= 0)
+                    break;
+                array[k] = c;
+                k = child;
+            }
+            array[k] = x;
+        }
+    }
+
+    /**
+     * Establishes the heap invariant (described above) in the entire tree,
+     * assuming nothing about the order of the elements prior to the call.
+     */
+    private void heapify() {
+        Object[] array = queue;
+        int n = size;
+        int half = (n >>> 1) - 1;
+        Comparator<? super E> cmp = comparator;
+        if (cmp == null) {
+            for (int i = half; i >= 0; i--)
+                siftDownComparable(i, (E) array[i], array, n);
+        }
+        else {
+            for (int i = half; i >= 0; i--)
+                siftDownUsingComparator(i, (E) array[i], array, n, cmp);
+        }
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Collection#add})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean add(E e) {
+        return offer(e);
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never return {@code false}.
+     *
+     * @param e the element to add
+     * @return {@code true} (as specified by {@link Queue#offer})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null)
+            throw new NullPointerException();
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        int n, cap;
+        Object[] array;
+        while ((n = size) >= (cap = (array = queue).length))
+            tryGrow(array, cap);
+        try {
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftUpComparable(n, e, array);
+            else
+                siftUpUsingComparator(n, e, array, cmp);
+            size = n + 1;
+            notEmpty.signal();
+        } finally {
+            lock.unlock();
+        }
+        return true;
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never block.
+     *
+     * @param e the element to add
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public void put(E e) {
+        offer(e); // never need to block
+    }
+
+    /**
+     * Inserts the specified element into this priority queue.
+     * As the queue is unbounded, this method will never block or
+     * return {@code false}.
+     *
+     * @param e the element to add
+     * @param timeout This parameter is ignored as the method never blocks
+     * @param unit This parameter is ignored as the method never blocks
+     * @return {@code true} (as specified by
+     *  {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
+     * @throws ClassCastException if the specified element cannot be compared
+     *         with elements currently in the priority queue according to the
+     *         priority queue's ordering
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit) {
+        return offer(e); // never need to block
+    }
+
+    public E poll() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return dequeue();
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public E take() throws InterruptedException {
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        E result;
+        try {
+            while ( (result = dequeue()) == null)
+                notEmpty.await();
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock lock = this.lock;
+        lock.lockInterruptibly();
+        E result;
+        try {
+            while ( (result = dequeue()) == null && nanos > 0)
+                nanos = notEmpty.awaitNanos(nanos);
+        } finally {
+            lock.unlock();
+        }
+        return result;
+    }
+
+    public E peek() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return (size == 0) ? null : (E) queue[0];
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns the comparator used to order the elements in this queue,
+     * or {@code null} if this queue uses the {@linkplain Comparable
+     * natural ordering} of its elements.
+     *
+     * @return the comparator used to order the elements in this queue,
+     *         or {@code null} if this queue uses the natural
+     *         ordering of its elements
+     */
+    public Comparator<? super E> comparator() {
+        return comparator;
+    }
+
+    public int size() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return size;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Always returns {@code Integer.MAX_VALUE} because
+     * a {@code PriorityBlockingQueue} is not capacity constrained.
+     * @return {@code Integer.MAX_VALUE} always
+     */
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE;
+    }
+
+    private int indexOf(Object o) {
+        if (o != null) {
+            Object[] array = queue;
+            int n = size;
+            for (int i = 0; i < n; i++)
+                if (o.equals(array[i]))
+                    return i;
+        }
+        return -1;
+    }
+
+    /**
+     * Removes the ith element from queue.
+     */
+    private void removeAt(int i) {
+        Object[] array = queue;
+        int n = size - 1;
+        if (n == i) // removed last element
+            array[i] = null;
+        else {
+            E moved = (E) array[n];
+            array[n] = null;
+            Comparator<? super E> cmp = comparator;
+            if (cmp == null)
+                siftDownComparable(i, moved, array, n);
+            else
+                siftDownUsingComparator(i, moved, array, n, cmp);
+            if (array[i] == moved) {
+                if (cmp == null)
+                    siftUpComparable(i, moved, array);
+                else
+                    siftUpUsingComparator(i, moved, array, cmp);
+            }
+        }
+        size = n;
+    }
+
+    /**
+     * Removes a single instance of the specified element from this queue,
+     * if it is present.  More formally, removes an element {@code e} such
+     * that {@code o.equals(e)}, if this queue contains one or more such
+     * elements.  Returns {@code true} if and only if this queue contained
+     * the specified element (or equivalently, if this queue changed as a
+     * result of the call).
+     *
+     * @param o element to be removed from this queue, if present
+     * @return {@code true} if this queue changed as a result of the call
+     */
+    public boolean remove(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int i = indexOf(o);
+            if (i == -1)
+                return false;
+            removeAt(i);
+            return true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Identity-based version for use in Itr.remove.
+     */
+    void removeEQ(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] array = queue;
+            for (int i = 0, n = size; i < n; i++) {
+                if (o == array[i]) {
+                    removeAt(i);
+                    break;
+                }
+            }
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns {@code true} if this queue contains the specified element.
+     * More formally, returns {@code true} if and only if this queue contains
+     * at least one element {@code e} such that {@code o.equals(e)}.
+     *
+     * @param o object to be checked for containment in this queue
+     * @return {@code true} if this queue contains the specified element
+     */
+    public boolean contains(Object o) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return indexOf(o) != -1;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public String toString() {
+        return Helpers.collectionToString(this);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c, Integer.MAX_VALUE);
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        if (maxElements <= 0)
+            return 0;
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = Math.min(size, maxElements);
+            for (int i = 0; i < n; i++) {
+                c.add((E) queue[0]); // In this order, in case add() throws.
+                dequeue();
+            }
+            return n;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Atomically removes all of the elements from this queue.
+     * The queue will be empty after this call returns.
+     */
+    public void clear() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            Object[] array = queue;
+            int n = size;
+            size = 0;
+            for (int i = 0; i < n; i++)
+                array[i] = null;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue.
+     * The returned array elements are in no particular order.
+     *
+     * <p>The returned array will be "safe" in that no references to it are
+     * maintained by this queue.  (In other words, this method must allocate
+     * a new array).  The caller is thus free to modify the returned array.
+     *
+     * <p>This method acts as bridge between array-based and collection-based
+     * APIs.
+     *
+     * @return an array containing all of the elements in this queue
+     */
+    public Object[] toArray() {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            return Arrays.copyOf(queue, size);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an array containing all of the elements in this queue; the
+     * runtime type of the returned array is that of the specified array.
+     * The returned array elements are in no particular order.
+     * If the queue fits in the specified array, it is returned therein.
+     * Otherwise, a new array is allocated with the runtime type of the
+     * specified array and the size of this queue.
+     *
+     * <p>If this queue fits in the specified array with room to spare
+     * (i.e., the array has more elements than this queue), the element in
+     * the array immediately following the end of the queue is set to
+     * {@code null}.
+     *
+     * <p>Like the {@link #toArray()} method, this method acts as bridge between
+     * array-based and collection-based APIs.  Further, this method allows
+     * precise control over the runtime type of the output array, and may,
+     * under certain circumstances, be used to save allocation costs.
+     *
+     * <p>Suppose {@code x} is a queue known to contain only strings.
+     * The following code can be used to dump the queue into a newly
+     * allocated array of {@code String}:
+     *
+     * <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
+     *
+     * Note that {@code toArray(new Object[0])} is identical in function to
+     * {@code toArray()}.
+     *
+     * @param a the array into which the elements of the queue are to
+     *          be stored, if it is big enough; otherwise, a new array of the
+     *          same runtime type is allocated for this purpose
+     * @return an array containing all of the elements in this queue
+     * @throws ArrayStoreException if the runtime type of the specified array
+     *         is not a supertype of the runtime type of every element in
+     *         this queue
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            int n = size;
+            if (a.length < n)
+                // Make a new array of a's runtime type, but my contents:
+                return (T[]) Arrays.copyOf(queue, size, a.getClass());
+            System.arraycopy(queue, 0, a, 0, n);
+            if (a.length > n)
+                a[n] = null;
+            return a;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Returns an iterator over the elements in this queue. The
+     * iterator does not return the elements in any particular order.
+     *
+     * <p>The returned iterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * @return an iterator over the elements in this queue
+     */
+    public Iterator<E> iterator() {
+        return new Itr(toArray());
+    }
+
+    /**
+     * Snapshot iterator that works off copy of underlying q array.
+     */
+    final class Itr implements Iterator<E> {
+        final Object[] array; // Array of all elements
+        int cursor;           // index of next element to return
+        int lastRet;          // index of last element, or -1 if no such
+
+        Itr(Object[] array) {
+            lastRet = -1;
+            this.array = array;
+        }
+
+        public boolean hasNext() {
+            return cursor < array.length;
+        }
+
+        public E next() {
+            if (cursor >= array.length)
+                throw new NoSuchElementException();
+            lastRet = cursor;
+            return (E)array[cursor++];
+        }
+
+        public void remove() {
+            if (lastRet < 0)
+                throw new IllegalStateException();
+            removeEQ(array[lastRet]);
+            lastRet = -1;
+        }
+    }
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     *
+     * For compatibility with previous version of this class, elements
+     * are first copied to a java.util.PriorityQueue, which is then
+     * serialized.
+     *
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        lock.lock();
+        try {
+            // avoid zero capacity argument
+            q = new PriorityQueue<E>(Math.max(size, 1), comparator);
+            q.addAll(this);
+            s.defaultWriteObject();
+        } finally {
+            q = null;
+            lock.unlock();
+        }
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        try {
+            s.defaultReadObject();
+            this.queue = new Object[q.size()];
+            comparator = q.comparator();
+            addAll(q);
+        } finally {
+            q = null;
+        }
+    }
+
+    // Similar to Collections.ArraySnapshotSpliterator but avoids
+    // commitment to toArray until needed
+    static final class PBQSpliterator<E> implements Spliterator<E> {
+        final PriorityBlockingQueue<E> queue;
+        Object[] array;
+        int index;
+        int fence;
+
+        PBQSpliterator(PriorityBlockingQueue<E> queue, Object[] array,
+                       int index, int fence) {
+            this.queue = queue;
+            this.array = array;
+            this.index = index;
+            this.fence = fence;
+        }
+
+        final int getFence() {
+            int hi;
+            if ((hi = fence) < 0)
+                hi = fence = (array = queue.toArray()).length;
+            return hi;
+        }
+
+        public PBQSpliterator<E> trySplit() {
+            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
+            return (lo >= mid) ? null :
+                new PBQSpliterator<E>(queue, array, lo, index = mid);
+        }
+
+        @SuppressWarnings("unchecked")
+        public void forEachRemaining(Consumer<? super E> action) {
+            Object[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array) == null)
+                fence = (a = queue.toArray()).length;
+            if ((hi = fence) <= a.length &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept((E)a[i]); } while (++i < hi);
+            }
+        }
+
+        public boolean tryAdvance(Consumer<? super E> action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (getFence() > index && index >= 0) {
+                @SuppressWarnings("unchecked") E e = (E) array[index++];
+                action.accept(e);
+                return true;
+            }
+            return false;
+        }
+
+        public long estimateSize() { return (long)(getFence() - index); }
+
+        public int characteristics() {
+            return Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED;
+        }
+    }
+
+    /**
+     * Returns a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The returned spliterator is
+     * <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return new PBQSpliterator<E>(this, null, 0, -1);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long ALLOCATIONSPINLOCK;
+    static {
+        try {
+            ALLOCATIONSPINLOCK = U.objectFieldOffset
+                (PriorityBlockingQueue.class.getDeclaredField("allocationSpinLock"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/RecursiveAction.java b/java/util/concurrent/RecursiveAction.java
new file mode 100644
index 0000000..8ac71d2
--- /dev/null
+++ b/java/util/concurrent/RecursiveAction.java
@@ -0,0 +1,193 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A recursive resultless {@link ForkJoinTask}.  This class
+ * establishes conventions to parameterize resultless actions as
+ * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the
+ * only valid value of type {@code Void}, methods such as {@code join}
+ * always return {@code null} upon completion.
+ *
+ * <p><b>Sample Usages.</b> Here is a simple but complete ForkJoin
+ * sort that sorts a given {@code long[]} array:
+ *
+ * <pre> {@code
+ * static class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   SortTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   SortTask(long[] array) { this(array, 0, array.length); }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD)
+ *       sortSequentially(lo, hi);
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new SortTask(array, lo, mid),
+ *                 new SortTask(array, mid, hi));
+ *       merge(lo, mid, hi);
+ *     }
+ *   }
+ *   // implementation details follow:
+ *   static final int THRESHOLD = 1000;
+ *   void sortSequentially(int lo, int hi) {
+ *     Arrays.sort(array, lo, hi);
+ *   }
+ *   void merge(int lo, int mid, int hi) {
+ *     long[] buf = Arrays.copyOfRange(array, lo, mid);
+ *     for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ *       array[j] = (k == hi || buf[i] < array[k]) ?
+ *         buf[i++] : array[k++];
+ *   }
+ * }}</pre>
+ *
+ * You could then sort {@code anArray} by creating {@code new
+ * SortTask(anArray)} and invoking it in a ForkJoinPool.  As a more
+ * concrete simple example, the following task increments each element
+ * of an array:
+ * <pre> {@code
+ * class IncrementTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
+ *   IncrementTask(long[] array, int lo, int hi) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *   }
+ *   protected void compute() {
+ *     if (hi - lo < THRESHOLD) {
+ *       for (int i = lo; i < hi; ++i)
+ *         array[i]++;
+ *     }
+ *     else {
+ *       int mid = (lo + hi) >>> 1;
+ *       invokeAll(new IncrementTask(array, lo, mid),
+ *                 new IncrementTask(array, mid, hi));
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>The following example illustrates some refinements and idioms
+ * that may lead to better performance: RecursiveActions need not be
+ * fully recursive, so long as they maintain the basic
+ * divide-and-conquer approach. Here is a class that sums the squares
+ * of each element of a double array, by subdividing out only the
+ * right-hand-sides of repeated divisions by two, and keeping track of
+ * them with a chain of {@code next} references. It uses a dynamic
+ * threshold based on method {@code getSurplusQueuedTaskCount}, but
+ * counterbalances potential excess partitioning by directly
+ * performing leaf actions on unstolen tasks rather than further
+ * subdividing.
+ *
+ * <pre> {@code
+ * double sumOfSquares(ForkJoinPool pool, double[] array) {
+ *   int n = array.length;
+ *   Applyer a = new Applyer(array, 0, n, null);
+ *   pool.invoke(a);
+ *   return a.result;
+ * }
+ *
+ * class Applyer extends RecursiveAction {
+ *   final double[] array;
+ *   final int lo, hi;
+ *   double result;
+ *   Applyer next; // keeps track of right-hand-side tasks
+ *   Applyer(double[] array, int lo, int hi, Applyer next) {
+ *     this.array = array; this.lo = lo; this.hi = hi;
+ *     this.next = next;
+ *   }
+ *
+ *   double atLeaf(int l, int h) {
+ *     double sum = 0;
+ *     for (int i = l; i < h; ++i) // perform leftmost base step
+ *       sum += array[i] * array[i];
+ *     return sum;
+ *   }
+ *
+ *   protected void compute() {
+ *     int l = lo;
+ *     int h = hi;
+ *     Applyer right = null;
+ *     while (h - l > 1 && getSurplusQueuedTaskCount() <= 3) {
+ *       int mid = (l + h) >>> 1;
+ *       right = new Applyer(array, mid, h, right);
+ *       right.fork();
+ *       h = mid;
+ *     }
+ *     double sum = atLeaf(l, h);
+ *     while (right != null) {
+ *       if (right.tryUnfork()) // directly calculate if not stolen
+ *         sum += right.atLeaf(right.lo, right.hi);
+ *       else {
+ *         right.join();
+ *         sum += right.result;
+ *       }
+ *       right = right.next;
+ *     }
+ *     result = sum;
+ *   }
+ * }}</pre>
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public abstract class RecursiveAction extends ForkJoinTask<Void> {
+    private static final long serialVersionUID = 5232453952276485070L;
+
+    /**
+     * The main computation performed by this task.
+     */
+    protected abstract void compute();
+
+    /**
+     * Always returns {@code null}.
+     *
+     * @return {@code null} always
+     */
+    public final Void getRawResult() { return null; }
+
+    /**
+     * Requires null completion value.
+     */
+    protected final void setRawResult(Void mustBeNull) { }
+
+    /**
+     * Implements execution conventions for RecursiveActions.
+     */
+    protected final boolean exec() {
+        compute();
+        return true;
+    }
+
+}
diff --git a/java/util/concurrent/RecursiveTask.java b/java/util/concurrent/RecursiveTask.java
new file mode 100644
index 0000000..9c5ad91
--- /dev/null
+++ b/java/util/concurrent/RecursiveTask.java
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A recursive result-bearing {@link ForkJoinTask}.
+ *
+ * <p>For a classic example, here is a task computing Fibonacci numbers:
+ *
+ * <pre> {@code
+ * class Fibonacci extends RecursiveTask<Integer> {
+ *   final int n;
+ *   Fibonacci(int n) { this.n = n; }
+ *   protected Integer compute() {
+ *     if (n <= 1)
+ *       return n;
+ *     Fibonacci f1 = new Fibonacci(n - 1);
+ *     f1.fork();
+ *     Fibonacci f2 = new Fibonacci(n - 2);
+ *     return f2.compute() + f1.join();
+ *   }
+ * }}</pre>
+ *
+ * However, besides being a dumb way to compute Fibonacci functions
+ * (there is a simple fast linear algorithm that you'd use in
+ * practice), this is likely to perform poorly because the smallest
+ * subtasks are too small to be worthwhile splitting up. Instead, as
+ * is the case for nearly all fork/join applications, you'd pick some
+ * minimum granularity size (for example 10 here) for which you always
+ * sequentially solve rather than subdividing.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
+    private static final long serialVersionUID = 5232453952276485270L;
+
+    /**
+     * The result of the computation.
+     */
+    V result;
+
+    /**
+     * The main computation performed by this task.
+     * @return the result of the computation
+     */
+    protected abstract V compute();
+
+    public final V getRawResult() {
+        return result;
+    }
+
+    protected final void setRawResult(V value) {
+        result = value;
+    }
+
+    /**
+     * Implements execution conventions for RecursiveTask.
+     */
+    protected final boolean exec() {
+        result = compute();
+        return true;
+    }
+
+}
diff --git a/java/util/concurrent/RejectedExecutionException.java b/java/util/concurrent/RejectedExecutionException.java
new file mode 100644
index 0000000..87feef4
--- /dev/null
+++ b/java/util/concurrent/RejectedExecutionException.java
@@ -0,0 +1,91 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown by an {@link Executor} when a task cannot be
+ * accepted for execution.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class RejectedExecutionException extends RuntimeException {
+    private static final long serialVersionUID = -375805702767069545L;
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with no detail message.
+     * The cause is not initialized, and may subsequently be
+     * initialized by a call to {@link #initCause(Throwable) initCause}.
+     */
+    public RejectedExecutionException() { }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified detail message. The cause is not initialized, and may
+     * subsequently be initialized by a call to {@link
+     * #initCause(Throwable) initCause}.
+     *
+     * @param message the detail message
+     */
+    public RejectedExecutionException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified detail message and cause.
+     *
+     * @param  message the detail message
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public RejectedExecutionException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a {@code RejectedExecutionException} with the
+     * specified cause.  The detail message is set to {@code (cause ==
+     * null ? null : cause.toString())} (which typically contains
+     * the class and detail message of {@code cause}).
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link #getCause()} method)
+     */
+    public RejectedExecutionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/java/util/concurrent/RejectedExecutionHandler.java b/java/util/concurrent/RejectedExecutionHandler.java
new file mode 100644
index 0000000..c1e314c
--- /dev/null
+++ b/java/util/concurrent/RejectedExecutionHandler.java
@@ -0,0 +1,62 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A handler for tasks that cannot be executed by a {@link ThreadPoolExecutor}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface RejectedExecutionHandler {
+
+    /**
+     * Method that may be invoked by a {@link ThreadPoolExecutor} when
+     * {@link ThreadPoolExecutor#execute execute} cannot accept a
+     * task.  This may occur when no more threads or queue slots are
+     * available because their bounds would be exceeded, or upon
+     * shutdown of the Executor.
+     *
+     * <p>In the absence of other alternatives, the method may throw
+     * an unchecked {@link RejectedExecutionException}, which will be
+     * propagated to the caller of {@code execute}.
+     *
+     * @param r the runnable task requested to be executed
+     * @param executor the executor attempting to execute this task
+     * @throws RejectedExecutionException if there is no remedy
+     */
+    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
+}
diff --git a/java/util/concurrent/RunnableFuture.java b/java/util/concurrent/RunnableFuture.java
new file mode 100644
index 0000000..b6b088a
--- /dev/null
+++ b/java/util/concurrent/RunnableFuture.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link Future} that is {@link Runnable}. Successful execution of
+ * the {@code run} method causes completion of the {@code Future}
+ * and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface RunnableFuture<V> extends Runnable, Future<V> {
+    /**
+     * Sets this Future to the result of its computation
+     * unless it has been cancelled.
+     */
+    void run();
+}
diff --git a/java/util/concurrent/RunnableScheduledFuture.java b/java/util/concurrent/RunnableScheduledFuture.java
new file mode 100644
index 0000000..4f5ce1b
--- /dev/null
+++ b/java/util/concurrent/RunnableScheduledFuture.java
@@ -0,0 +1,58 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A {@link ScheduledFuture} that is {@link Runnable}. Successful
+ * execution of the {@code run} method causes completion of the
+ * {@code Future} and allows access to its results.
+ * @see FutureTask
+ * @see Executor
+ * @since 1.6
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future's {@code get} method
+ */
+public interface RunnableScheduledFuture<V> extends RunnableFuture<V>, ScheduledFuture<V> {
+
+    /**
+     * Returns {@code true} if this task is periodic. A periodic task may
+     * re-run according to some schedule. A non-periodic task can be
+     * run only once.
+     *
+     * @return {@code true} if this task is periodic
+     */
+    boolean isPeriodic();
+}
diff --git a/java/util/concurrent/ScheduledExecutorService.java b/java/util/concurrent/ScheduledExecutorService.java
new file mode 100644
index 0000000..c32e2d1
--- /dev/null
+++ b/java/util/concurrent/ScheduledExecutorService.java
@@ -0,0 +1,213 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An {@link ExecutorService} that can schedule commands to run after a given
+ * delay, or to execute periodically.
+ *
+ * <p>The {@code schedule} methods create tasks with various delays
+ * and return a task object that can be used to cancel or check
+ * execution. The {@code scheduleAtFixedRate} and
+ * {@code scheduleWithFixedDelay} methods create and execute tasks
+ * that run periodically until cancelled.
+ *
+ * <p>Commands submitted using the {@link Executor#execute(Runnable)}
+ * and {@link ExecutorService} {@code submit} methods are scheduled
+ * with a requested delay of zero. Zero and negative delays (but not
+ * periods) are also allowed in {@code schedule} methods, and are
+ * treated as requests for immediate execution.
+ *
+ * <p>All {@code schedule} methods accept <em>relative</em> delays and
+ * periods as arguments, not absolute times or dates. It is a simple
+ * matter to transform an absolute time represented as a {@link
+ * java.util.Date} to the required form. For example, to schedule at
+ * a certain future {@code date}, you can use: {@code schedule(task,
+ * date.getTime() - System.currentTimeMillis(),
+ * TimeUnit.MILLISECONDS)}. Beware however that expiration of a
+ * relative delay need not coincide with the current {@code Date} at
+ * which the task is enabled due to network time synchronization
+ * protocols, clock drift, or other factors.
+ *
+ * <p>The {@link Executors} class provides convenient factory methods for
+ * the ScheduledExecutorService implementations provided in this package.
+ *
+ * <h3>Usage Example</h3>
+ *
+ * Here is a class with a method that sets up a ScheduledExecutorService
+ * to beep every ten seconds for an hour:
+ *
+ * <pre> {@code
+ * import static java.util.concurrent.TimeUnit.*;
+ * class BeeperControl {
+ *   private final ScheduledExecutorService scheduler =
+ *     Executors.newScheduledThreadPool(1);
+ *
+ *   public void beepForAnHour() {
+ *     final Runnable beeper = new Runnable() {
+ *       public void run() { System.out.println("beep"); }
+ *     };
+ *     final ScheduledFuture<?> beeperHandle =
+ *       scheduler.scheduleAtFixedRate(beeper, 10, 10, SECONDS);
+ *     scheduler.schedule(new Runnable() {
+ *       public void run() { beeperHandle.cancel(true); }
+ *     }, 60 * 60, SECONDS);
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ScheduledExecutorService extends ExecutorService {
+
+    /**
+     * Creates and executes a one-shot action that becomes enabled
+     * after the given delay.
+     *
+     * @param command the task to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @return a ScheduledFuture representing pending completion of
+     *         the task and whose {@code get()} method will return
+     *         {@code null} upon completion
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command is null
+     */
+    public ScheduledFuture<?> schedule(Runnable command,
+                                       long delay, TimeUnit unit);
+
+    /**
+     * Creates and executes a ScheduledFuture that becomes enabled after the
+     * given delay.
+     *
+     * @param callable the function to execute
+     * @param delay the time from now to delay execution
+     * @param unit the time unit of the delay parameter
+     * @param <V> the type of the callable's result
+     * @return a ScheduledFuture that can be used to extract result or cancel
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if callable is null
+     */
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
+                                           long delay, TimeUnit unit);
+
+    /**
+     * Creates and executes a periodic action that becomes enabled first
+     * after the given initial delay, and subsequently with the given
+     * period; that is, executions will commence after
+     * {@code initialDelay}, then {@code initialDelay + period}, then
+     * {@code initialDelay + 2 * period}, and so on.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will
+     * throw {@link ExecutionException}.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * <p>If any execution of this task takes longer than its period, then
+     * subsequent executions may start late, but will not concurrently
+     * execute.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param period the period between successive executions
+     * @param unit the time unit of the initialDelay and period parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command is null
+     * @throws IllegalArgumentException if period less than or equal to zero
+     */
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+                                                  long initialDelay,
+                                                  long period,
+                                                  TimeUnit unit);
+
+    /**
+     * Creates and executes a periodic action that becomes enabled first
+     * after the given initial delay, and subsequently with the
+     * given delay between the termination of one execution and the
+     * commencement of the next.
+     *
+     * <p>The sequence of task executions continues indefinitely until
+     * one of the following exceptional completions occur:
+     * <ul>
+     * <li>The task is {@linkplain Future#cancel explicitly cancelled}
+     * via the returned future.
+     * <li>The executor terminates, also resulting in task cancellation.
+     * <li>An execution of the task throws an exception.  In this case
+     * calling {@link Future#get() get} on the returned future will
+     * throw {@link ExecutionException}.
+     * </ul>
+     * Subsequent executions are suppressed.  Subsequent calls to
+     * {@link Future#isDone isDone()} on the returned future will
+     * return {@code true}.
+     *
+     * @param command the task to execute
+     * @param initialDelay the time to delay first execution
+     * @param delay the delay between the termination of one
+     * execution and the commencement of the next
+     * @param unit the time unit of the initialDelay and delay parameters
+     * @return a ScheduledFuture representing pending completion of
+     *         the series of repeated tasks.  The future's {@link
+     *         Future#get() get()} method will never return normally,
+     *         and will throw an exception upon task cancellation or
+     *         abnormal termination of a task execution.
+     * @throws RejectedExecutionException if the task cannot be
+     *         scheduled for execution
+     * @throws NullPointerException if command is null
+     * @throws IllegalArgumentException if delay less than or equal to zero
+     */
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+                                                     long initialDelay,
+                                                     long delay,
+                                                     TimeUnit unit);
+
+}
diff --git a/java/util/concurrent/ScheduledFuture.java b/java/util/concurrent/ScheduledFuture.java
new file mode 100644
index 0000000..1c1efa4
--- /dev/null
+++ b/java/util/concurrent/ScheduledFuture.java
@@ -0,0 +1,48 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * A delayed result-bearing action that can be cancelled.
+ * Usually a scheduled future is the result of scheduling
+ * a task with a {@link ScheduledExecutorService}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The result type returned by this Future
+ */
+public interface ScheduledFuture<V> extends Delayed, Future<V> {
+}
diff --git a/java/util/concurrent/ScheduledThreadPoolExecutor.java b/java/util/concurrent/ScheduledThreadPoolExecutor.java
new file mode 100644
index 0000000..4249872
--- /dev/null
+++ b/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -0,0 +1,1322 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import java.util.AbstractQueue;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// omit class-level docs on setRemoveOnCancelPolicy()
+// END android-note
+
+/**
+ * A {@link ThreadPoolExecutor} that can additionally schedule
+ * commands to run after a given delay, or to execute periodically.
+ * This class is preferable to {@link java.util.Timer} when multiple
+ * worker threads are needed, or when the additional flexibility or
+ * capabilities of {@link ThreadPoolExecutor} (which this class
+ * extends) are required.
+ *
+ * <p>Delayed tasks execute no sooner than they are enabled, but
+ * without any real-time guarantees about when, after they are
+ * enabled, they will commence. Tasks scheduled for exactly the same
+ * execution time are enabled in first-in-first-out (FIFO) order of
+ * submission.
+ *
+ * <p>When a submitted task is cancelled before it is run, execution
+ * is suppressed.  By default, such a cancelled task is not
+ * automatically removed from the work queue until its delay elapses.
+ * While this enables further inspection and monitoring, it may also
+ * cause unbounded retention of cancelled tasks.
+ *
+ * <p>Successive executions of a periodic task scheduled via
+ * {@link #scheduleAtFixedRate scheduleAtFixedRate} or
+ * {@link #scheduleWithFixedDelay scheduleWithFixedDelay}
+ * do not overlap. While different executions may be performed by
+ * different threads, the effects of prior executions
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * those of subsequent ones.
+ *
+ * <p>While this class inherits from {@link ThreadPoolExecutor}, a few
+ * of the inherited tuning methods are not useful for it. In
+ * particular, because it acts as a fixed-sized pool using
+ * {@code corePoolSize} threads and an unbounded queue, adjustments
+ * to {@code maximumPoolSize} have no useful effect. Additionally, it
+ * is almost never a good idea to set {@code corePoolSize} to zero or
+ * use {@code allowCoreThreadTimeOut} because this may leave the pool
+ * without threads to handle tasks once they become eligible to run.
+ *
+ * <p><b>Extension notes:</b> This class overrides the
+ * {@link ThreadPoolExecutor#execute(Runnable) execute} and
+ * {@link AbstractExecutorService#submit(Runnable) submit}
+ * methods to generate internal {@link ScheduledFuture} objects to
+ * control per-task delays and scheduling.  To preserve
+ * functionality, any further overrides of these methods in
+ * subclasses must invoke superclass versions, which effectively
+ * disables additional task customization.  However, this class
+ * provides alternative protected extension method
+ * {@code decorateTask} (one version each for {@code Runnable} and
+ * {@code Callable}) that can be used to customize the concrete task
+ * types used to execute commands entered via {@code execute},
+ * {@code submit}, {@code schedule}, {@code scheduleAtFixedRate},
+ * and {@code scheduleWithFixedDelay}.  By default, a
+ * {@code ScheduledThreadPoolExecutor} uses a task type extending
+ * {@link FutureTask}. However, this may be modified or replaced using
+ * subclasses of the form:
+ *
+ * <pre> {@code
+ * public class CustomScheduledExecutor extends ScheduledThreadPoolExecutor {
+ *
+ *   static class CustomTask<V> implements RunnableScheduledFuture<V> { ... }
+ *
+ *   protected <V> RunnableScheduledFuture<V> decorateTask(
+ *                Runnable r, RunnableScheduledFuture<V> task) {
+ *       return new CustomTask<V>(r, task);
+ *   }
+ *
+ *   protected <V> RunnableScheduledFuture<V> decorateTask(
+ *                Callable<V> c, RunnableScheduledFuture<V> task) {
+ *       return new CustomTask<V>(c, task);
+ *   }
+ *   // ... add constructors, etc.
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ScheduledThreadPoolExecutor
+        extends ThreadPoolExecutor
+        implements ScheduledExecutorService {
+
+    /*
+     * This class specializes ThreadPoolExecutor implementation by
+     *
+     * 1. Using a custom task type ScheduledFutureTask, even for tasks
+     *    that don't require scheduling because they are submitted
+     *    using ExecutorService rather than ScheduledExecutorService
+     *    methods, which are treated as tasks with a delay of zero.
+     *
+     * 2. Using a custom queue (DelayedWorkQueue), a variant of
+     *    unbounded DelayQueue. The lack of capacity constraint and
+     *    the fact that corePoolSize and maximumPoolSize are
+     *    effectively identical simplifies some execution mechanics
+     *    (see delayedExecute) compared to ThreadPoolExecutor.
+     *
+     * 3. Supporting optional run-after-shutdown parameters, which
+     *    leads to overrides of shutdown methods to remove and cancel
+     *    tasks that should NOT be run after shutdown, as well as
+     *    different recheck logic when task (re)submission overlaps
+     *    with a shutdown.
+     *
+     * 4. Task decoration methods to allow interception and
+     *    instrumentation, which are needed because subclasses cannot
+     *    otherwise override submit methods to get this effect. These
+     *    don't have any impact on pool control logic though.
+     */
+
+    /**
+     * False if should cancel/suppress periodic tasks on shutdown.
+     */
+    private volatile boolean continueExistingPeriodicTasksAfterShutdown;
+
+    /**
+     * False if should cancel non-periodic tasks on shutdown.
+     */
+    private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
+
+    /**
+     * True if ScheduledFutureTask.cancel should remove from queue.
+     */
+    volatile boolean removeOnCancel;
+
+    /**
+     * Sequence number to break scheduling ties, and in turn to
+     * guarantee FIFO order among tied entries.
+     */
+    private static final AtomicLong sequencer = new AtomicLong();
+
+    private class ScheduledFutureTask<V>
+            extends FutureTask<V> implements RunnableScheduledFuture<V> {
+
+        /** Sequence number to break ties FIFO */
+        private final long sequenceNumber;
+
+        /** The nanoTime-based time when the task is enabled to execute. */
+        private volatile long time;
+
+        /**
+         * Period for repeating tasks, in nanoseconds.
+         * A positive value indicates fixed-rate execution.
+         * A negative value indicates fixed-delay execution.
+         * A value of 0 indicates a non-repeating (one-shot) task.
+         */
+        private final long period;
+
+        /** The actual task to be re-enqueued by reExecutePeriodic */
+        RunnableScheduledFuture<V> outerTask = this;
+
+        /**
+         * Index into delay queue, to support faster cancellation.
+         */
+        int heapIndex;
+
+        /**
+         * Creates a one-shot action with given nanoTime-based trigger time.
+         */
+        ScheduledFutureTask(Runnable r, V result, long triggerTime,
+                            long sequenceNumber) {
+            super(r, result);
+            this.time = triggerTime;
+            this.period = 0;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        /**
+         * Creates a periodic action with given nanoTime-based initial
+         * trigger time and period.
+         */
+        ScheduledFutureTask(Runnable r, V result, long triggerTime,
+                            long period, long sequenceNumber) {
+            super(r, result);
+            this.time = triggerTime;
+            this.period = period;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        /**
+         * Creates a one-shot action with given nanoTime-based trigger time.
+         */
+        ScheduledFutureTask(Callable<V> callable, long triggerTime,
+                            long sequenceNumber) {
+            super(callable);
+            this.time = triggerTime;
+            this.period = 0;
+            this.sequenceNumber = sequenceNumber;
+        }
+
+        public long getDelay(TimeUnit unit) {
+            return unit.convert(time - System.nanoTime(), NANOSECONDS);
+        }
+
+        public int compareTo(Delayed other) {
+            if (other == this) // compare zero if same object
+                return 0;
+            if (other instanceof ScheduledFutureTask) {
+                ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
+                long diff = time - x.time;
+                if (diff < 0)
+                    return -1;
+                else if (diff > 0)
+                    return 1;
+                else if (sequenceNumber < x.sequenceNumber)
+                    return -1;
+                else
+                    return 1;
+            }
+            long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
+            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+        }
+
+        /**
+         * Returns {@code true} if this is a periodic (not a one-shot) action.
+         *
+         * @return {@code true} if periodic
+         */
+        public boolean isPeriodic() {
+            return period != 0;
+        }
+
+        /**
+         * Sets the next time to run for a periodic task.
+         */
+        private void setNextRunTime() {
+            long p = period;
+            if (p > 0)
+                time += p;
+            else
+                time = triggerTime(-p);
+        }
+
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            // The racy read of heapIndex below is benign:
+            // if heapIndex < 0, then OOTA guarantees that we have surely
+            // been removed; else we recheck under lock in remove()
+            boolean cancelled = super.cancel(mayInterruptIfRunning);
+            if (cancelled && removeOnCancel && heapIndex >= 0)
+                remove(this);
+            return cancelled;
+        }
+
+        /**
+         * Overrides FutureTask version so as to reset/requeue if periodic.
+         */
+        public void run() {
+            boolean periodic = isPeriodic();
+            if (!canRunInCurrentRunState(periodic))
+                cancel(false);
+            else if (!periodic)
+                super.run();
+            else if (super.runAndReset()) {
+                setNextRunTime();
+                reExecutePeriodic(outerTask);
+            }
+        }
+    }
+
+    /**
+     * Returns true if can run a task given current run state
+     * and run-after-shutdown parameters.
+     *
+     * @param periodic true if this task periodic, false if delayed
+     */
+    boolean canRunInCurrentRunState(boolean periodic) {
+        return isRunningOrShutdown(periodic ?
+                                   continueExistingPeriodicTasksAfterShutdown :
+                                   executeExistingDelayedTasksAfterShutdown);
+    }
+
+    /**
+     * Main execution method for delayed or periodic tasks.  If pool
+     * is shut down, rejects the task. Otherwise adds task to queue
+     * and starts a thread, if necessary, to run it.  (We cannot
+     * prestart the thread to run the task because the task (probably)
+     * shouldn't be run yet.)  If the pool is shut down while the task
+     * is being added, cancel and remove it if required by state and
+     * run-after-shutdown parameters.
+     *
+     * @param task the task
+     */
+    private void delayedExecute(RunnableScheduledFuture<?> task) {
+        if (isShutdown())
+            reject(task);
+        else {
+            super.getQueue().add(task);
+            if (isShutdown() &&
+                !canRunInCurrentRunState(task.isPeriodic()) &&
+                remove(task))
+                task.cancel(false);
+            else
+                ensurePrestart();
+        }
+    }
+
+    /**
+     * Requeues a periodic task unless current run state precludes it.
+     * Same idea as delayedExecute except drops task rather than rejecting.
+     *
+     * @param task the task
+     */
+    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
+        if (canRunInCurrentRunState(true)) {
+            super.getQueue().add(task);
+            if (!canRunInCurrentRunState(true) && remove(task))
+                task.cancel(false);
+            else
+                ensurePrestart();
+        }
+    }
+
+    /**
+     * Cancels and clears the queue of all tasks that should not be run
+     * due to shutdown policy.  Invoked within super.shutdown.
+     */
+    @Override void onShutdown() {
+        BlockingQueue<Runnable> q = super.getQueue();
+        boolean keepDelayed =
+            getExecuteExistingDelayedTasksAfterShutdownPolicy();
+        boolean keepPeriodic =
+            getContinueExistingPeriodicTasksAfterShutdownPolicy();
+        if (!keepDelayed && !keepPeriodic) {
+            for (Object e : q.toArray())
+                if (e instanceof RunnableScheduledFuture<?>)
+                    ((RunnableScheduledFuture<?>) e).cancel(false);
+            q.clear();
+        }
+        else {
+            // Traverse snapshot to avoid iterator exceptions
+            for (Object e : q.toArray()) {
+                if (e instanceof RunnableScheduledFuture) {
+                    RunnableScheduledFuture<?> t =
+                        (RunnableScheduledFuture<?>)e;
+                    if ((t.isPeriodic() ? !keepPeriodic : !keepDelayed) ||
+                        t.isCancelled()) { // also remove if already cancelled
+                        if (q.remove(t))
+                            t.cancel(false);
+                    }
+                }
+            }
+        }
+        tryTerminate();
+    }
+
+    /**
+     * Modifies or replaces the task used to execute a runnable.
+     * This method can be used to override the concrete
+     * class used for managing internal tasks.
+     * The default implementation simply returns the given task.
+     *
+     * @param runnable the submitted Runnable
+     * @param task the task created to execute the runnable
+     * @param <V> the type of the task's result
+     * @return a task that can execute the runnable
+     * @since 1.6
+     */
+    protected <V> RunnableScheduledFuture<V> decorateTask(
+        Runnable runnable, RunnableScheduledFuture<V> task) {
+        return task;
+    }
+
+    /**
+     * Modifies or replaces the task used to execute a callable.
+     * This method can be used to override the concrete
+     * class used for managing internal tasks.
+     * The default implementation simply returns the given task.
+     *
+     * @param callable the submitted Callable
+     * @param task the task created to execute the callable
+     * @param <V> the type of the task's result
+     * @return a task that can execute the callable
+     * @since 1.6
+     */
+    protected <V> RunnableScheduledFuture<V> decorateTask(
+        Callable<V> callable, RunnableScheduledFuture<V> task) {
+        return task;
+    }
+
+    /**
+     * The default keep-alive time for pool threads.
+     *
+     * Normally, this value is unused because all pool threads will be
+     * core threads, but if a user creates a pool with a corePoolSize
+     * of zero (against our advice), we keep a thread alive as long as
+     * there are queued tasks.  If the keep alive time is zero (the
+     * historic value), we end up hot-spinning in getTask, wasting a
+     * CPU.  But on the other hand, if we set the value too high, and
+     * users create a one-shot pool which they don't cleanly shutdown,
+     * the pool's non-daemon threads will prevent JVM termination.  A
+     * small but non-zero value (relative to a JVM's lifetime) seems
+     * best.
+     */
+    private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given core pool size.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue());
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code threadFactory} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       ThreadFactory threadFactory) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), threadFactory);
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code handler} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       RejectedExecutionHandler handler) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), handler);
+    }
+
+    /**
+     * Creates a new {@code ScheduledThreadPoolExecutor} with the
+     * given initial parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @throws NullPointerException if {@code threadFactory} or
+     *         {@code handler} is null
+     */
+    public ScheduledThreadPoolExecutor(int corePoolSize,
+                                       ThreadFactory threadFactory,
+                                       RejectedExecutionHandler handler) {
+        super(corePoolSize, Integer.MAX_VALUE,
+              DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
+              new DelayedWorkQueue(), threadFactory, handler);
+    }
+
+    /**
+     * Returns the nanoTime-based trigger time of a delayed action.
+     */
+    private long triggerTime(long delay, TimeUnit unit) {
+        return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
+    }
+
+    /**
+     * Returns the nanoTime-based trigger time of a delayed action.
+     */
+    long triggerTime(long delay) {
+        return System.nanoTime() +
+            ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
+    }
+
+    /**
+     * Constrains the values of all delays in the queue to be within
+     * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
+     * This may occur if a task is eligible to be dequeued, but has
+     * not yet been, while some other task is added with a delay of
+     * Long.MAX_VALUE.
+     */
+    private long overflowFree(long delay) {
+        Delayed head = (Delayed) super.getQueue().peek();
+        if (head != null) {
+            long headDelay = head.getDelay(NANOSECONDS);
+            if (headDelay < 0 && (delay - headDelay < 0))
+                delay = Long.MAX_VALUE + headDelay;
+        }
+        return delay;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public ScheduledFuture<?> schedule(Runnable command,
+                                       long delay,
+                                       TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        RunnableScheduledFuture<Void> t = decorateTask(command,
+            new ScheduledFutureTask<Void>(command, null,
+                                          triggerTime(delay, unit),
+                                          sequencer.getAndIncrement()));
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
+                                           long delay,
+                                           TimeUnit unit) {
+        if (callable == null || unit == null)
+            throw new NullPointerException();
+        RunnableScheduledFuture<V> t = decorateTask(callable,
+            new ScheduledFutureTask<V>(callable,
+                                       triggerTime(delay, unit),
+                                       sequencer.getAndIncrement()));
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws IllegalArgumentException   {@inheritDoc}
+     */
+    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+                                                  long initialDelay,
+                                                  long period,
+                                                  TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        if (period <= 0L)
+            throw new IllegalArgumentException();
+        ScheduledFutureTask<Void> sft =
+            new ScheduledFutureTask<Void>(command,
+                                          null,
+                                          triggerTime(initialDelay, unit),
+                                          unit.toNanos(period),
+                                          sequencer.getAndIncrement());
+        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+        sft.outerTask = t;
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     * @throws IllegalArgumentException   {@inheritDoc}
+     */
+    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+                                                     long initialDelay,
+                                                     long delay,
+                                                     TimeUnit unit) {
+        if (command == null || unit == null)
+            throw new NullPointerException();
+        if (delay <= 0L)
+            throw new IllegalArgumentException();
+        ScheduledFutureTask<Void> sft =
+            new ScheduledFutureTask<Void>(command,
+                                          null,
+                                          triggerTime(initialDelay, unit),
+                                          -unit.toNanos(delay),
+                                          sequencer.getAndIncrement());
+        RunnableScheduledFuture<Void> t = decorateTask(command, sft);
+        sft.outerTask = t;
+        delayedExecute(t);
+        return t;
+    }
+
+    /**
+     * Executes {@code command} with zero required delay.
+     * This has effect equivalent to
+     * {@link #schedule(Runnable,long,TimeUnit) schedule(command, 0, anyUnit)}.
+     * Note that inspections of the queue and of the list returned by
+     * {@code shutdownNow} will access the zero-delayed
+     * {@link ScheduledFuture}, not the {@code command} itself.
+     *
+     * <p>A consequence of the use of {@code ScheduledFuture} objects is
+     * that {@link ThreadPoolExecutor#afterExecute afterExecute} is always
+     * called with a null second {@code Throwable} argument, even if the
+     * {@code command} terminated abruptly.  Instead, the {@code Throwable}
+     * thrown by such a task can be obtained via {@link Future#get}.
+     *
+     * @throws RejectedExecutionException at discretion of
+     *         {@code RejectedExecutionHandler}, if the task
+     *         cannot be accepted for execution because the
+     *         executor has been shut down
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void execute(Runnable command) {
+        schedule(command, 0, NANOSECONDS);
+    }
+
+    // Override AbstractExecutorService methods
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public Future<?> submit(Runnable task) {
+        return schedule(task, 0, NANOSECONDS);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Runnable task, T result) {
+        return schedule(Executors.callable(task, result), 0, NANOSECONDS);
+    }
+
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
+    public <T> Future<T> submit(Callable<T> task) {
+        return schedule(task, 0, NANOSECONDS);
+    }
+
+    /**
+     * Sets the policy on whether to continue executing existing
+     * periodic tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow} or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code false}.
+     *
+     * @param value if {@code true}, continue after shutdown, else don't
+     * @see #getContinueExistingPeriodicTasksAfterShutdownPolicy
+     */
+    public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean value) {
+        continueExistingPeriodicTasksAfterShutdown = value;
+        if (!value && isShutdown())
+            onShutdown();
+    }
+
+    /**
+     * Gets the policy on whether to continue executing existing
+     * periodic tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow} or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code false}.
+     *
+     * @return {@code true} if will continue after shutdown
+     * @see #setContinueExistingPeriodicTasksAfterShutdownPolicy
+     */
+    public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy() {
+        return continueExistingPeriodicTasksAfterShutdown;
+    }
+
+    /**
+     * Sets the policy on whether to execute existing delayed
+     * tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow}, or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code true}.
+     *
+     * @param value if {@code true}, execute after shutdown, else don't
+     * @see #getExecuteExistingDelayedTasksAfterShutdownPolicy
+     */
+    public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean value) {
+        executeExistingDelayedTasksAfterShutdown = value;
+        if (!value && isShutdown())
+            onShutdown();
+    }
+
+    /**
+     * Gets the policy on whether to execute existing delayed
+     * tasks even when this executor has been {@code shutdown}.
+     * In this case, these tasks will only terminate upon
+     * {@code shutdownNow}, or after setting the policy to
+     * {@code false} when already shutdown.
+     * This value is by default {@code true}.
+     *
+     * @return {@code true} if will execute after shutdown
+     * @see #setExecuteExistingDelayedTasksAfterShutdownPolicy
+     */
+    public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy() {
+        return executeExistingDelayedTasksAfterShutdown;
+    }
+
+    /**
+     * Sets the policy on whether cancelled tasks should be immediately
+     * removed from the work queue at time of cancellation.  This value is
+     * by default {@code false}.
+     *
+     * @param value if {@code true}, remove on cancellation, else don't
+     * @see #getRemoveOnCancelPolicy
+     * @since 1.7
+     */
+    public void setRemoveOnCancelPolicy(boolean value) {
+        removeOnCancel = value;
+    }
+
+    /**
+     * Gets the policy on whether cancelled tasks should be immediately
+     * removed from the work queue at time of cancellation.  This value is
+     * by default {@code false}.
+     *
+     * @return {@code true} if cancelled tasks are immediately removed
+     *         from the queue
+     * @see #setRemoveOnCancelPolicy
+     * @since 1.7
+     */
+    public boolean getRemoveOnCancelPolicy() {
+        return removeOnCancel;
+    }
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     *
+     * <p>If the {@code ExecuteExistingDelayedTasksAfterShutdownPolicy}
+     * has been set {@code false}, existing delayed tasks whose delays
+     * have not yet elapsed are cancelled.  And unless the {@code
+     * ContinueExistingPeriodicTasksAfterShutdownPolicy} has been set
+     * {@code true}, future executions of existing periodic tasks will
+     * be cancelled.
+     */
+    // android-note: Removed "throws SecurityException" doc.
+    public void shutdown() {
+        super.shutdown();
+    }
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution. These tasks are drained (removed)
+     * from the task queue upon return from this method.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  This implementation
+     * interrupts tasks via {@link Thread#interrupt}; any task that
+     * fails to respond to interrupts may never terminate.
+     *
+     * @return list of tasks that never commenced execution.
+     *         Each element of this list is a {@link ScheduledFuture}.
+     *         For tasks submitted via one of the {@code schedule}
+     *         methods, the element will be identical to the returned
+     *         {@code ScheduledFuture}.  For tasks submitted using
+     *         {@link #execute execute}, the element will be a
+     *         zero-delay {@code ScheduledFuture}.
+     */
+    // android-note: Removed "throws SecurityException" doc.
+    public List<Runnable> shutdownNow() {
+        return super.shutdownNow();
+    }
+
+    /**
+     * Returns the task queue used by this executor.  Access to the
+     * task queue is intended primarily for debugging and monitoring.
+     * This queue may be in active use.  Retrieving the task queue
+     * does not prevent queued tasks from executing.
+     *
+     * <p>Each element of this queue is a {@link ScheduledFuture}.
+     * For tasks submitted via one of the {@code schedule} methods, the
+     * element will be identical to the returned {@code ScheduledFuture}.
+     * For tasks submitted using {@link #execute execute}, the element
+     * will be a zero-delay {@code ScheduledFuture}.
+     *
+     * <p>Iteration over this queue is <em>not</em> guaranteed to traverse
+     * tasks in the order in which they will execute.
+     *
+     * @return the task queue
+     */
+    public BlockingQueue<Runnable> getQueue() {
+        return super.getQueue();
+    }
+
+    /**
+     * Specialized delay queue. To mesh with TPE declarations, this
+     * class must be declared as a BlockingQueue<Runnable> even though
+     * it can only hold RunnableScheduledFutures.
+     */
+    static class DelayedWorkQueue extends AbstractQueue<Runnable>
+        implements BlockingQueue<Runnable> {
+
+        /*
+         * A DelayedWorkQueue is based on a heap-based data structure
+         * like those in DelayQueue and PriorityQueue, except that
+         * every ScheduledFutureTask also records its index into the
+         * heap array. This eliminates the need to find a task upon
+         * cancellation, greatly speeding up removal (down from O(n)
+         * to O(log n)), and reducing garbage retention that would
+         * otherwise occur by waiting for the element to rise to top
+         * before clearing. But because the queue may also hold
+         * RunnableScheduledFutures that are not ScheduledFutureTasks,
+         * we are not guaranteed to have such indices available, in
+         * which case we fall back to linear search. (We expect that
+         * most tasks will not be decorated, and that the faster cases
+         * will be much more common.)
+         *
+         * All heap operations must record index changes -- mainly
+         * within siftUp and siftDown. Upon removal, a task's
+         * heapIndex is set to -1. Note that ScheduledFutureTasks can
+         * appear at most once in the queue (this need not be true for
+         * other kinds of tasks or work queues), so are uniquely
+         * identified by heapIndex.
+         */
+
+        private static final int INITIAL_CAPACITY = 16;
+        private RunnableScheduledFuture<?>[] queue =
+            new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
+        private final ReentrantLock lock = new ReentrantLock();
+        private int size;
+
+        /**
+         * Thread designated to wait for the task at the head of the
+         * queue.  This variant of the Leader-Follower pattern
+         * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to
+         * minimize unnecessary timed waiting.  When a thread becomes
+         * the leader, it waits only for the next delay to elapse, but
+         * other threads await indefinitely.  The leader thread must
+         * signal some other thread before returning from take() or
+         * poll(...), unless some other thread becomes leader in the
+         * interim.  Whenever the head of the queue is replaced with a
+         * task with an earlier expiration time, the leader field is
+         * invalidated by being reset to null, and some waiting
+         * thread, but not necessarily the current leader, is
+         * signalled.  So waiting threads must be prepared to acquire
+         * and lose leadership while waiting.
+         */
+        private Thread leader;
+
+        /**
+         * Condition signalled when a newer task becomes available at the
+         * head of the queue or a new thread may need to become leader.
+         */
+        private final Condition available = lock.newCondition();
+
+        /**
+         * Sets f's heapIndex if it is a ScheduledFutureTask.
+         */
+        private void setIndex(RunnableScheduledFuture<?> f, int idx) {
+            if (f instanceof ScheduledFutureTask)
+                ((ScheduledFutureTask)f).heapIndex = idx;
+        }
+
+        /**
+         * Sifts element added at bottom up to its heap-ordered spot.
+         * Call only when holding lock.
+         */
+        private void siftUp(int k, RunnableScheduledFuture<?> key) {
+            while (k > 0) {
+                int parent = (k - 1) >>> 1;
+                RunnableScheduledFuture<?> e = queue[parent];
+                if (key.compareTo(e) >= 0)
+                    break;
+                queue[k] = e;
+                setIndex(e, k);
+                k = parent;
+            }
+            queue[k] = key;
+            setIndex(key, k);
+        }
+
+        /**
+         * Sifts element added at top down to its heap-ordered spot.
+         * Call only when holding lock.
+         */
+        private void siftDown(int k, RunnableScheduledFuture<?> key) {
+            int half = size >>> 1;
+            while (k < half) {
+                int child = (k << 1) + 1;
+                RunnableScheduledFuture<?> c = queue[child];
+                int right = child + 1;
+                if (right < size && c.compareTo(queue[right]) > 0)
+                    c = queue[child = right];
+                if (key.compareTo(c) <= 0)
+                    break;
+                queue[k] = c;
+                setIndex(c, k);
+                k = child;
+            }
+            queue[k] = key;
+            setIndex(key, k);
+        }
+
+        /**
+         * Resizes the heap array.  Call only when holding lock.
+         */
+        private void grow() {
+            int oldCapacity = queue.length;
+            int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
+            if (newCapacity < 0) // overflow
+                newCapacity = Integer.MAX_VALUE;
+            queue = Arrays.copyOf(queue, newCapacity);
+        }
+
+        /**
+         * Finds index of given object, or -1 if absent.
+         */
+        private int indexOf(Object x) {
+            if (x != null) {
+                if (x instanceof ScheduledFutureTask) {
+                    int i = ((ScheduledFutureTask) x).heapIndex;
+                    // Sanity check; x could conceivably be a
+                    // ScheduledFutureTask from some other pool.
+                    if (i >= 0 && i < size && queue[i] == x)
+                        return i;
+                } else {
+                    for (int i = 0; i < size; i++)
+                        if (x.equals(queue[i]))
+                            return i;
+                }
+            }
+            return -1;
+        }
+
+        public boolean contains(Object x) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return indexOf(x) != -1;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean remove(Object x) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int i = indexOf(x);
+                if (i < 0)
+                    return false;
+
+                setIndex(queue[i], -1);
+                int s = --size;
+                RunnableScheduledFuture<?> replacement = queue[s];
+                queue[s] = null;
+                if (s != i) {
+                    siftDown(i, replacement);
+                    if (queue[i] == replacement)
+                        siftUp(i, replacement);
+                }
+                return true;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public int size() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return size;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean isEmpty() {
+            return size() == 0;
+        }
+
+        public int remainingCapacity() {
+            return Integer.MAX_VALUE;
+        }
+
+        public RunnableScheduledFuture<?> peek() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return queue[0];
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public boolean offer(Runnable x) {
+            if (x == null)
+                throw new NullPointerException();
+            RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                int i = size;
+                if (i >= queue.length)
+                    grow();
+                size = i + 1;
+                if (i == 0) {
+                    queue[0] = e;
+                    setIndex(e, 0);
+                } else {
+                    siftUp(i, e);
+                }
+                if (queue[0] == e) {
+                    leader = null;
+                    available.signal();
+                }
+            } finally {
+                lock.unlock();
+            }
+            return true;
+        }
+
+        public void put(Runnable e) {
+            offer(e);
+        }
+
+        public boolean add(Runnable e) {
+            return offer(e);
+        }
+
+        public boolean offer(Runnable e, long timeout, TimeUnit unit) {
+            return offer(e);
+        }
+
+        /**
+         * Performs common bookkeeping for poll and take: Replaces
+         * first element with last and sifts it down.  Call only when
+         * holding lock.
+         * @param f the task to remove and return
+         */
+        private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
+            int s = --size;
+            RunnableScheduledFuture<?> x = queue[s];
+            queue[s] = null;
+            if (s != 0)
+                siftDown(0, x);
+            setIndex(f, -1);
+            return f;
+        }
+
+        public RunnableScheduledFuture<?> poll() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first = queue[0];
+                return (first == null || first.getDelay(NANOSECONDS) > 0)
+                    ? null
+                    : finishPoll(first);
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public RunnableScheduledFuture<?> take() throws InterruptedException {
+            final ReentrantLock lock = this.lock;
+            lock.lockInterruptibly();
+            try {
+                for (;;) {
+                    RunnableScheduledFuture<?> first = queue[0];
+                    if (first == null)
+                        available.await();
+                    else {
+                        long delay = first.getDelay(NANOSECONDS);
+                        if (delay <= 0L)
+                            return finishPoll(first);
+                        first = null; // don't retain ref while waiting
+                        if (leader != null)
+                            available.await();
+                        else {
+                            Thread thisThread = Thread.currentThread();
+                            leader = thisThread;
+                            try {
+                                available.awaitNanos(delay);
+                            } finally {
+                                if (leader == thisThread)
+                                    leader = null;
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (leader == null && queue[0] != null)
+                    available.signal();
+                lock.unlock();
+            }
+        }
+
+        public RunnableScheduledFuture<?> poll(long timeout, TimeUnit unit)
+            throws InterruptedException {
+            long nanos = unit.toNanos(timeout);
+            final ReentrantLock lock = this.lock;
+            lock.lockInterruptibly();
+            try {
+                for (;;) {
+                    RunnableScheduledFuture<?> first = queue[0];
+                    if (first == null) {
+                        if (nanos <= 0L)
+                            return null;
+                        else
+                            nanos = available.awaitNanos(nanos);
+                    } else {
+                        long delay = first.getDelay(NANOSECONDS);
+                        if (delay <= 0L)
+                            return finishPoll(first);
+                        if (nanos <= 0L)
+                            return null;
+                        first = null; // don't retain ref while waiting
+                        if (nanos < delay || leader != null)
+                            nanos = available.awaitNanos(nanos);
+                        else {
+                            Thread thisThread = Thread.currentThread();
+                            leader = thisThread;
+                            try {
+                                long timeLeft = available.awaitNanos(delay);
+                                nanos -= delay - timeLeft;
+                            } finally {
+                                if (leader == thisThread)
+                                    leader = null;
+                            }
+                        }
+                    }
+                }
+            } finally {
+                if (leader == null && queue[0] != null)
+                    available.signal();
+                lock.unlock();
+            }
+        }
+
+        public void clear() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                for (int i = 0; i < size; i++) {
+                    RunnableScheduledFuture<?> t = queue[i];
+                    if (t != null) {
+                        queue[i] = null;
+                        setIndex(t, -1);
+                    }
+                }
+                size = 0;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        /**
+         * Returns first element only if it is expired.
+         * Used only by drainTo.  Call only when holding lock.
+         */
+        private RunnableScheduledFuture<?> peekExpired() {
+            // assert lock.isHeldByCurrentThread();
+            RunnableScheduledFuture<?> first = queue[0];
+            return (first == null || first.getDelay(NANOSECONDS) > 0) ?
+                null : first;
+        }
+
+        public int drainTo(Collection<? super Runnable> c) {
+            if (c == null)
+                throw new NullPointerException();
+            if (c == this)
+                throw new IllegalArgumentException();
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first;
+                int n = 0;
+                while ((first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
+                    ++n;
+                }
+                return n;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public int drainTo(Collection<? super Runnable> c, int maxElements) {
+            if (c == null)
+                throw new NullPointerException();
+            if (c == this)
+                throw new IllegalArgumentException();
+            if (maxElements <= 0)
+                return 0;
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                RunnableScheduledFuture<?> first;
+                int n = 0;
+                while (n < maxElements && (first = peekExpired()) != null) {
+                    c.add(first);   // In this order, in case add() throws.
+                    finishPoll(first);
+                    ++n;
+                }
+                return n;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public Object[] toArray() {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                return Arrays.copyOf(queue, size, Object[].class);
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final ReentrantLock lock = this.lock;
+            lock.lock();
+            try {
+                if (a.length < size)
+                    return (T[]) Arrays.copyOf(queue, size, a.getClass());
+                System.arraycopy(queue, 0, a, 0, size);
+                if (a.length > size)
+                    a[size] = null;
+                return a;
+            } finally {
+                lock.unlock();
+            }
+        }
+
+        public Iterator<Runnable> iterator() {
+            return new Itr(Arrays.copyOf(queue, size));
+        }
+
+        /**
+         * Snapshot iterator that works off copy of underlying q array.
+         */
+        private class Itr implements Iterator<Runnable> {
+            final RunnableScheduledFuture<?>[] array;
+            int cursor;        // index of next element to return; initially 0
+            int lastRet = -1;  // index of last element returned; -1 if no such
+
+            Itr(RunnableScheduledFuture<?>[] array) {
+                this.array = array;
+            }
+
+            public boolean hasNext() {
+                return cursor < array.length;
+            }
+
+            public Runnable next() {
+                if (cursor >= array.length)
+                    throw new NoSuchElementException();
+                lastRet = cursor;
+                return array[cursor++];
+            }
+
+            public void remove() {
+                if (lastRet < 0)
+                    throw new IllegalStateException();
+                DelayedWorkQueue.this.remove(array[lastRet]);
+                lastRet = -1;
+            }
+        }
+    }
+}
diff --git a/java/util/concurrent/Semaphore.java b/java/util/concurrent/Semaphore.java
new file mode 100644
index 0000000..1298a6e
--- /dev/null
+++ b/java/util/concurrent/Semaphore.java
@@ -0,0 +1,717 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Collection;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+/**
+ * A counting semaphore.  Conceptually, a semaphore maintains a set of
+ * permits.  Each {@link #acquire} blocks if necessary until a permit is
+ * available, and then takes it.  Each {@link #release} adds a permit,
+ * potentially releasing a blocking acquirer.
+ * However, no actual permit objects are used; the {@code Semaphore} just
+ * keeps a count of the number available and acts accordingly.
+ *
+ * <p>Semaphores are often used to restrict the number of threads than can
+ * access some (physical or logical) resource. For example, here is
+ * a class that uses a semaphore to control access to a pool of items:
+ * <pre> {@code
+ * class Pool {
+ *   private static final int MAX_AVAILABLE = 100;
+ *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
+ *
+ *   public Object getItem() throws InterruptedException {
+ *     available.acquire();
+ *     return getNextAvailableItem();
+ *   }
+ *
+ *   public void putItem(Object x) {
+ *     if (markAsUnused(x))
+ *       available.release();
+ *   }
+ *
+ *   // Not a particularly efficient data structure; just for demo
+ *
+ *   protected Object[] items = ... whatever kinds of items being managed
+ *   protected boolean[] used = new boolean[MAX_AVAILABLE];
+ *
+ *   protected synchronized Object getNextAvailableItem() {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (!used[i]) {
+ *          used[i] = true;
+ *          return items[i];
+ *       }
+ *     }
+ *     return null; // not reached
+ *   }
+ *
+ *   protected synchronized boolean markAsUnused(Object item) {
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (item == items[i]) {
+ *          if (used[i]) {
+ *            used[i] = false;
+ *            return true;
+ *          } else
+ *            return false;
+ *       }
+ *     }
+ *     return false;
+ *   }
+ * }}</pre>
+ *
+ * <p>Before obtaining an item each thread must acquire a permit from
+ * the semaphore, guaranteeing that an item is available for use. When
+ * the thread has finished with the item it is returned back to the
+ * pool and a permit is returned to the semaphore, allowing another
+ * thread to acquire that item.  Note that no synchronization lock is
+ * held when {@link #acquire} is called as that would prevent an item
+ * from being returned to the pool.  The semaphore encapsulates the
+ * synchronization needed to restrict access to the pool, separately
+ * from any synchronization needed to maintain the consistency of the
+ * pool itself.
+ *
+ * <p>A semaphore initialized to one, and which is used such that it
+ * only has at most one permit available, can serve as a mutual
+ * exclusion lock.  This is more commonly known as a <em>binary
+ * semaphore</em>, because it only has two states: one permit
+ * available, or zero permits available.  When used in this way, the
+ * binary semaphore has the property (unlike many {@link java.util.concurrent.locks.Lock}
+ * implementations), that the &quot;lock&quot; can be released by a
+ * thread other than the owner (as semaphores have no notion of
+ * ownership).  This can be useful in some specialized contexts, such
+ * as deadlock recovery.
+ *
+ * <p>The constructor for this class optionally accepts a
+ * <em>fairness</em> parameter. When set false, this class makes no
+ * guarantees about the order in which threads acquire permits. In
+ * particular, <em>barging</em> is permitted, that is, a thread
+ * invoking {@link #acquire} can be allocated a permit ahead of a
+ * thread that has been waiting - logically the new thread places itself at
+ * the head of the queue of waiting threads. When fairness is set true, the
+ * semaphore guarantees that threads invoking any of the {@link
+ * #acquire() acquire} methods are selected to obtain permits in the order in
+ * which their invocation of those methods was processed
+ * (first-in-first-out; FIFO). Note that FIFO ordering necessarily
+ * applies to specific internal points of execution within these
+ * methods.  So, it is possible for one thread to invoke
+ * {@code acquire} before another, but reach the ordering point after
+ * the other, and similarly upon return from the method.
+ * Also note that the untimed {@link #tryAcquire() tryAcquire} methods do not
+ * honor the fairness setting, but will take any permits that are
+ * available.
+ *
+ * <p>Generally, semaphores used to control resource access should be
+ * initialized as fair, to ensure that no thread is starved out from
+ * accessing a resource. When using semaphores for other kinds of
+ * synchronization control, the throughput advantages of non-fair
+ * ordering often outweigh fairness considerations.
+ *
+ * <p>This class also provides convenience methods to {@link
+ * #acquire(int) acquire} and {@link #release(int) release} multiple
+ * permits at a time. These methods are generally more efficient and
+ * effective than loops. However, they do not establish any preference
+ * order. For example, if thread A invokes {@code s.acquire(3}) and
+ * thread B invokes {@code s.acquire(2)}, and two permits become
+ * available, then there is no guarantee that thread B will obtain
+ * them unless its acquire came first and Semaphore {@code s} is in
+ * fair mode.
+ *
+ * <p>Memory consistency effects: Actions in a thread prior to calling
+ * a "release" method such as {@code release()}
+ * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
+ * actions following a successful "acquire" method such as {@code acquire()}
+ * in another thread.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class Semaphore implements java.io.Serializable {
+    private static final long serialVersionUID = -3222578661600680210L;
+    /** All mechanics via AbstractQueuedSynchronizer subclass */
+    private final Sync sync;
+
+    /**
+     * Synchronization implementation for semaphore.  Uses AQS state
+     * to represent permits. Subclassed into fair and nonfair
+     * versions.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 1192457210091910933L;
+
+        Sync(int permits) {
+            setState(permits);
+        }
+
+        final int getPermits() {
+            return getState();
+        }
+
+        final int nonfairTryAcquireShared(int acquires) {
+            for (;;) {
+                int available = getState();
+                int remaining = available - acquires;
+                if (remaining < 0 ||
+                    compareAndSetState(available, remaining))
+                    return remaining;
+            }
+        }
+
+        protected final boolean tryReleaseShared(int releases) {
+            for (;;) {
+                int current = getState();
+                int next = current + releases;
+                if (next < current) // overflow
+                    throw new Error("Maximum permit count exceeded");
+                if (compareAndSetState(current, next))
+                    return true;
+            }
+        }
+
+        final void reducePermits(int reductions) {
+            for (;;) {
+                int current = getState();
+                int next = current - reductions;
+                if (next > current) // underflow
+                    throw new Error("Permit count underflow");
+                if (compareAndSetState(current, next))
+                    return;
+            }
+        }
+
+        final int drainPermits() {
+            for (;;) {
+                int current = getState();
+                if (current == 0 || compareAndSetState(current, 0))
+                    return current;
+            }
+        }
+    }
+
+    /**
+     * NonFair version
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = -2694183684443567898L;
+
+        NonfairSync(int permits) {
+            super(permits);
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            return nonfairTryAcquireShared(acquires);
+        }
+    }
+
+    /**
+     * Fair version
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = 2014338818796000944L;
+
+        FairSync(int permits) {
+            super(permits);
+        }
+
+        protected int tryAcquireShared(int acquires) {
+            for (;;) {
+                if (hasQueuedPredecessors())
+                    return -1;
+                int available = getState();
+                int remaining = available - acquires;
+                if (remaining < 0 ||
+                    compareAndSetState(available, remaining))
+                    return remaining;
+            }
+        }
+    }
+
+    /**
+     * Creates a {@code Semaphore} with the given number of
+     * permits and nonfair fairness setting.
+     *
+     * @param permits the initial number of permits available.
+     *        This value may be negative, in which case releases
+     *        must occur before any acquires will be granted.
+     */
+    public Semaphore(int permits) {
+        sync = new NonfairSync(permits);
+    }
+
+    /**
+     * Creates a {@code Semaphore} with the given number of
+     * permits and the given fairness setting.
+     *
+     * @param permits the initial number of permits available.
+     *        This value may be negative, in which case releases
+     *        must occur before any acquires will be granted.
+     * @param fair {@code true} if this semaphore will guarantee
+     *        first-in first-out granting of permits under contention,
+     *        else {@code false}
+     */
+    public Semaphore(int permits, boolean fair) {
+        sync = fair ? new FairSync(permits) : new NonfairSync(permits);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, blocking until one is
+     * available, or the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public void acquire() throws InterruptedException {
+        sync.acquireSharedInterruptibly(1);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, blocking until one is
+     * available.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit.
+     *
+     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting for a permit then it will continue to wait, but the
+     * time at which the thread is assigned a permit may change compared to
+     * the time it would have received the permit had no interruption
+     * occurred.  When the thread does return from this method its interrupt
+     * status will be set.
+     */
+    public void acquireUninterruptibly() {
+        sync.acquireShared(1);
+    }
+
+    /**
+     * Acquires a permit from this semaphore, only if one is available at the
+     * time of invocation.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * with the value {@code true},
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then this method will return
+     * immediately with the value {@code false}.
+     *
+     * <p>Even when this semaphore has been set to use a
+     * fair ordering policy, a call to {@code tryAcquire()} <em>will</em>
+     * immediately acquire a permit if one is available, whether or not
+     * other threads are currently waiting.
+     * This &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to honor
+     * the fairness setting, then use
+     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) }
+     * which is almost equivalent (it also detects interruption).
+     *
+     * @return {@code true} if a permit was acquired and {@code false}
+     *         otherwise
+     */
+    public boolean tryAcquire() {
+        return sync.nonfairTryAcquireShared(1) >= 0;
+    }
+
+    /**
+     * Acquires a permit from this semaphore, if one becomes available
+     * within the given waiting time and the current thread has not
+     * been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires a permit, if one is available and returns immediately,
+     * with the value {@code true},
+     * reducing the number of available permits by one.
+     *
+     * <p>If no permit is available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of three things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #release} method for this
+     * semaphore and the current thread is next to be assigned a permit; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If a permit is acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * to acquire a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * @param timeout the maximum time to wait for a permit
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if a permit was acquired and {@code false}
+     *         if the waiting time elapsed before a permit was acquired
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public boolean tryAcquire(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Releases a permit, returning it to the semaphore.
+     *
+     * <p>Releases a permit, increasing the number of available permits by
+     * one.  If any threads are trying to acquire a permit, then one is
+     * selected and given the permit that was just released.  That thread
+     * is (re)enabled for thread scheduling purposes.
+     *
+     * <p>There is no requirement that a thread that releases a permit must
+     * have acquired that permit by calling {@link #acquire}.
+     * Correct usage of a semaphore is established by programming convention
+     * in the application.
+     */
+    public void release() {
+        sync.releaseShared(1);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore,
+     * blocking until all are available,
+     * or the thread is {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the given number of permits, if they are available,
+     * and returns immediately, reducing the number of available permits
+     * by the given amount. This method has the same effect as the
+     * loop {@code for (int i = 0; i < permits; ++i) acquire();} except
+     * that it atomically acquires the permits all at once:
+     *
+     * <p>If insufficient permits are available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     * <ul>
+     * <li>Some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * for a permit,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * Any permits that were to be assigned to this thread are instead
+     * assigned to other threads trying to acquire permits, as if
+     * permits had been made available by a call to {@link #release()}.
+     *
+     * @param permits the number of permits to acquire
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void acquire(int permits) throws InterruptedException {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.acquireSharedInterruptibly(permits);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore,
+     * blocking until all are available.
+     *
+     * <p>Acquires the given number of permits, if they are available,
+     * and returns immediately, reducing the number of available permits
+     * by the given amount. This method has the same effect as the
+     * loop {@code for (int i = 0; i < permits; ++i) acquireUninterruptibly();}
+     * except that it atomically acquires the permits all at once:
+     *
+     * <p>If insufficient permits are available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request.
+     *
+     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting for permits then it will continue to wait and its
+     * position in the queue is not affected.  When the thread does return
+     * from this method its interrupt status will be set.
+     *
+     * @param permits the number of permits to acquire
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void acquireUninterruptibly(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.acquireShared(permits);
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore, only
+     * if all are available at the time of invocation.
+     *
+     * <p>Acquires the given number of permits, if they are available, and
+     * returns immediately, with the value {@code true},
+     * reducing the number of available permits by the given amount.
+     *
+     * <p>If insufficient permits are available then this method will return
+     * immediately with the value {@code false} and the number of available
+     * permits is unchanged.
+     *
+     * <p>Even when this semaphore has been set to use a fair ordering
+     * policy, a call to {@code tryAcquire} <em>will</em>
+     * immediately acquire a permit if one is available, whether or
+     * not other threads are currently waiting.  This
+     * &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to
+     * honor the fairness setting, then use {@link #tryAcquire(int,
+     * long, TimeUnit) tryAcquire(permits, 0, TimeUnit.SECONDS) }
+     * which is almost equivalent (it also detects interruption).
+     *
+     * @param permits the number of permits to acquire
+     * @return {@code true} if the permits were acquired and
+     *         {@code false} otherwise
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public boolean tryAcquire(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        return sync.nonfairTryAcquireShared(permits) >= 0;
+    }
+
+    /**
+     * Acquires the given number of permits from this semaphore, if all
+     * become available within the given waiting time and the current
+     * thread has not been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the given number of permits, if they are available and
+     * returns immediately, with the value {@code true},
+     * reducing the number of available permits by the given amount.
+     *
+     * <p>If insufficient permits are available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>Some other thread invokes one of the {@link #release() release}
+     * methods for this semaphore and the current thread is next to be assigned
+     * permits and the number of available permits satisfies this request; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     * <li>The specified waiting time elapses.
+     * </ul>
+     *
+     * <p>If the permits are acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * to acquire the permits,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     * Any permits that were to be assigned to this thread, are instead
+     * assigned to other threads trying to acquire permits, as if
+     * the permits had been made available by a call to {@link #release()}.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.  Any permits that were to be assigned to this
+     * thread, are instead assigned to other threads trying to acquire
+     * permits, as if the permits had been made available by a call to
+     * {@link #release()}.
+     *
+     * @param permits the number of permits to acquire
+     * @param timeout the maximum time to wait for the permits
+     * @param unit the time unit of the {@code timeout} argument
+     * @return {@code true} if all permits were acquired and {@code false}
+     *         if the waiting time elapsed before all permits were acquired
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (permits < 0) throw new IllegalArgumentException();
+        return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
+    }
+
+    /**
+     * Releases the given number of permits, returning them to the semaphore.
+     *
+     * <p>Releases the given number of permits, increasing the number of
+     * available permits by that amount.
+     * If any threads are trying to acquire permits, then one thread
+     * is selected and given the permits that were just released.
+     * If the number of available permits satisfies that thread's request
+     * then that thread is (re)enabled for thread scheduling purposes;
+     * otherwise the thread will wait until sufficient permits are available.
+     * If there are still permits available
+     * after this thread's request has been satisfied, then those permits
+     * are assigned in turn to other threads trying to acquire permits.
+     *
+     * <p>There is no requirement that a thread that releases a permit must
+     * have acquired that permit by calling {@link Semaphore#acquire acquire}.
+     * Correct usage of a semaphore is established by programming convention
+     * in the application.
+     *
+     * @param permits the number of permits to release
+     * @throws IllegalArgumentException if {@code permits} is negative
+     */
+    public void release(int permits) {
+        if (permits < 0) throw new IllegalArgumentException();
+        sync.releaseShared(permits);
+    }
+
+    /**
+     * Returns the current number of permits available in this semaphore.
+     *
+     * <p>This method is typically used for debugging and testing purposes.
+     *
+     * @return the number of permits available in this semaphore
+     */
+    public int availablePermits() {
+        return sync.getPermits();
+    }
+
+    /**
+     * Acquires and returns all permits that are immediately available.
+     *
+     * @return the number of permits acquired
+     */
+    public int drainPermits() {
+        return sync.drainPermits();
+    }
+
+    /**
+     * Shrinks the number of available permits by the indicated
+     * reduction. This method can be useful in subclasses that use
+     * semaphores to track resources that become unavailable. This
+     * method differs from {@code acquire} in that it does not block
+     * waiting for permits to become available.
+     *
+     * @param reduction the number of permits to remove
+     * @throws IllegalArgumentException if {@code reduction} is negative
+     */
+    protected void reducePermits(int reduction) {
+        if (reduction < 0) throw new IllegalArgumentException();
+        sync.reducePermits(reduction);
+    }
+
+    /**
+     * Returns {@code true} if this semaphore has fairness set true.
+     *
+     * @return {@code true} if this semaphore has fairness set true
+     */
+    public boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations may occur at any time, a {@code true}
+     * return does not guarantee that any other thread will ever
+     * acquire.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire.
+     * The value is only an estimate because the number of threads may
+     * change dynamically while this method traverses internal data
+     * structures.  This method is designed for use in monitoring
+     * system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to acquire.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a best-effort
+     * estimate.  The elements of the returned collection are in no particular
+     * order.  This method is designed to facilitate construction of
+     * subclasses that provide more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Returns a string identifying this semaphore, as well as its state.
+     * The state, in brackets, includes the String {@code "Permits ="}
+     * followed by the number of permits.
+     *
+     * @return a string identifying this semaphore, as well as its state
+     */
+    public String toString() {
+        return super.toString() + "[Permits = " + sync.getPermits() + "]";
+    }
+}
diff --git a/java/util/concurrent/SynchronousQueue.java b/java/util/concurrent/SynchronousQueue.java
new file mode 100644
index 0000000..9655205
--- /dev/null
+++ b/java/util/concurrent/SynchronousQueue.java
@@ -0,0 +1,1208 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea, Bill Scherer, and Michael Scott with
+ * assistance from members of JCP JSR-166 Expert Group and released to
+ * the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.locks.LockSupport;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@linkplain BlockingQueue blocking queue} in which each insert
+ * operation must wait for a corresponding remove operation by another
+ * thread, and vice versa.  A synchronous queue does not have any
+ * internal capacity, not even a capacity of one.  You cannot
+ * {@code peek} at a synchronous queue because an element is only
+ * present when you try to remove it; you cannot insert an element
+ * (using any method) unless another thread is trying to remove it;
+ * you cannot iterate as there is nothing to iterate.  The
+ * <em>head</em> of the queue is the element that the first queued
+ * inserting thread is trying to add to the queue; if there is no such
+ * queued thread then no element is available for removal and
+ * {@code poll()} will return {@code null}.  For purposes of other
+ * {@code Collection} methods (for example {@code contains}), a
+ * {@code SynchronousQueue} acts as an empty collection.  This queue
+ * does not permit {@code null} elements.
+ *
+ * <p>Synchronous queues are similar to rendezvous channels used in
+ * CSP and Ada. They are well suited for handoff designs, in which an
+ * object running in one thread must sync up with an object running
+ * in another thread in order to hand it some information, event, or
+ * task.
+ *
+ * <p>This class supports an optional fairness policy for ordering
+ * waiting producer and consumer threads.  By default, this ordering
+ * is not guaranteed. However, a queue constructed with fairness set
+ * to {@code true} grants threads access in FIFO order.
+ *
+ * <p>This class and its iterator implement all of the
+ * <em>optional</em> methods of the {@link Collection} and {@link
+ * Iterator} interfaces.
+ *
+ * @since 1.5
+ * @author Doug Lea and Bill Scherer and Michael Scott
+ * @param <E> the type of elements held in this queue
+ */
+public class SynchronousQueue<E> extends AbstractQueue<E>
+    implements BlockingQueue<E>, java.io.Serializable {
+    private static final long serialVersionUID = -3223113410248163686L;
+
+    /*
+     * This class implements extensions of the dual stack and dual
+     * queue algorithms described in "Nonblocking Concurrent Objects
+     * with Condition Synchronization", by W. N. Scherer III and
+     * M. L. Scott.  18th Annual Conf. on Distributed Computing,
+     * Oct. 2004 (see also
+     * http://www.cs.rochester.edu/u/scott/synchronization/pseudocode/duals.html).
+     * The (Lifo) stack is used for non-fair mode, and the (Fifo)
+     * queue for fair mode. The performance of the two is generally
+     * similar. Fifo usually supports higher throughput under
+     * contention but Lifo maintains higher thread locality in common
+     * applications.
+     *
+     * A dual queue (and similarly stack) is one that at any given
+     * time either holds "data" -- items provided by put operations,
+     * or "requests" -- slots representing take operations, or is
+     * empty. A call to "fulfill" (i.e., a call requesting an item
+     * from a queue holding data or vice versa) dequeues a
+     * complementary node.  The most interesting feature of these
+     * queues is that any operation can figure out which mode the
+     * queue is in, and act accordingly without needing locks.
+     *
+     * Both the queue and stack extend abstract class Transferer
+     * defining the single method transfer that does a put or a
+     * take. These are unified into a single method because in dual
+     * data structures, the put and take operations are symmetrical,
+     * so nearly all code can be combined. The resulting transfer
+     * methods are on the long side, but are easier to follow than
+     * they would be if broken up into nearly-duplicated parts.
+     *
+     * The queue and stack data structures share many conceptual
+     * similarities but very few concrete details. For simplicity,
+     * they are kept distinct so that they can later evolve
+     * separately.
+     *
+     * The algorithms here differ from the versions in the above paper
+     * in extending them for use in synchronous queues, as well as
+     * dealing with cancellation. The main differences include:
+     *
+     *  1. The original algorithms used bit-marked pointers, but
+     *     the ones here use mode bits in nodes, leading to a number
+     *     of further adaptations.
+     *  2. SynchronousQueues must block threads waiting to become
+     *     fulfilled.
+     *  3. Support for cancellation via timeout and interrupts,
+     *     including cleaning out cancelled nodes/threads
+     *     from lists to avoid garbage retention and memory depletion.
+     *
+     * Blocking is mainly accomplished using LockSupport park/unpark,
+     * except that nodes that appear to be the next ones to become
+     * fulfilled first spin a bit (on multiprocessors only). On very
+     * busy synchronous queues, spinning can dramatically improve
+     * throughput. And on less busy ones, the amount of spinning is
+     * small enough not to be noticeable.
+     *
+     * Cleaning is done in different ways in queues vs stacks.  For
+     * queues, we can almost always remove a node immediately in O(1)
+     * time (modulo retries for consistency checks) when it is
+     * cancelled. But if it may be pinned as the current tail, it must
+     * wait until some subsequent cancellation. For stacks, we need a
+     * potentially O(n) traversal to be sure that we can remove the
+     * node, but this can run concurrently with other threads
+     * accessing the stack.
+     *
+     * While garbage collection takes care of most node reclamation
+     * issues that otherwise complicate nonblocking algorithms, care
+     * is taken to "forget" references to data, other nodes, and
+     * threads that might be held on to long-term by blocked
+     * threads. In cases where setting to null would otherwise
+     * conflict with main algorithms, this is done by changing a
+     * node's link to now point to the node itself. This doesn't arise
+     * much for Stack nodes (because blocked threads do not hang on to
+     * old head pointers), but references in Queue nodes must be
+     * aggressively forgotten to avoid reachability of everything any
+     * node has ever referred to since arrival.
+     */
+
+    /**
+     * Shared internal API for dual stacks and queues.
+     */
+    abstract static class Transferer<E> {
+        /**
+         * Performs a put or take.
+         *
+         * @param e if non-null, the item to be handed to a consumer;
+         *          if null, requests that transfer return an item
+         *          offered by producer.
+         * @param timed if this operation should timeout
+         * @param nanos the timeout, in nanoseconds
+         * @return if non-null, the item provided or received; if null,
+         *         the operation failed due to timeout or interrupt --
+         *         the caller can distinguish which of these occurred
+         *         by checking Thread.interrupted.
+         */
+        abstract E transfer(E e, boolean timed, long nanos);
+    }
+
+    /**
+     * The number of times to spin before blocking in timed waits.
+     * The value is empirically derived -- it works well across a
+     * variety of processors and OSes. Empirically, the best value
+     * seems not to vary with number of CPUs (beyond 2) so is just
+     * a constant.
+     */
+    static final int MAX_TIMED_SPINS =
+        (Runtime.getRuntime().availableProcessors() < 2) ? 0 : 32;
+
+    /**
+     * The number of times to spin before blocking in untimed waits.
+     * This is greater than timed value because untimed waits spin
+     * faster since they don't need to check times on each spin.
+     */
+    static final int MAX_UNTIMED_SPINS = MAX_TIMED_SPINS * 16;
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+
+    /** Dual stack */
+    static final class TransferStack<E> extends Transferer<E> {
+        /*
+         * This extends Scherer-Scott dual stack algorithm, differing,
+         * among other ways, by using "covering" nodes rather than
+         * bit-marked pointers: Fulfilling operations push on marker
+         * nodes (with FULFILLING bit set in mode) to reserve a spot
+         * to match a waiting node.
+         */
+
+        /* Modes for SNodes, ORed together in node fields */
+        /** Node represents an unfulfilled consumer */
+        static final int REQUEST    = 0;
+        /** Node represents an unfulfilled producer */
+        static final int DATA       = 1;
+        /** Node is fulfilling another unfulfilled DATA or REQUEST */
+        static final int FULFILLING = 2;
+
+        /** Returns true if m has fulfilling bit set. */
+        static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
+
+        /** Node class for TransferStacks. */
+        static final class SNode {
+            volatile SNode next;        // next node in stack
+            volatile SNode match;       // the node matched to this
+            volatile Thread waiter;     // to control park/unpark
+            Object item;                // data; or null for REQUESTs
+            int mode;
+            // Note: item and mode fields don't need to be volatile
+            // since they are always written before, and read after,
+            // other volatile/atomic operations.
+
+            SNode(Object item) {
+                this.item = item;
+            }
+
+            boolean casNext(SNode cmp, SNode val) {
+                return cmp == next &&
+                    U.compareAndSwapObject(this, NEXT, cmp, val);
+            }
+
+            /**
+             * Tries to match node s to this node, if so, waking up thread.
+             * Fulfillers call tryMatch to identify their waiters.
+             * Waiters block until they have been matched.
+             *
+             * @param s the node to match
+             * @return true if successfully matched to s
+             */
+            boolean tryMatch(SNode s) {
+                if (match == null &&
+                    U.compareAndSwapObject(this, MATCH, null, s)) {
+                    Thread w = waiter;
+                    if (w != null) {    // waiters need at most one unpark
+                        waiter = null;
+                        LockSupport.unpark(w);
+                    }
+                    return true;
+                }
+                return match == s;
+            }
+
+            /**
+             * Tries to cancel a wait by matching node to itself.
+             */
+            void tryCancel() {
+                U.compareAndSwapObject(this, MATCH, null, this);
+            }
+
+            boolean isCancelled() {
+                return match == this;
+            }
+
+            // Unsafe mechanics
+            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+            private static final long MATCH;
+            private static final long NEXT;
+
+            static {
+                try {
+                    MATCH = U.objectFieldOffset
+                        (SNode.class.getDeclaredField("match"));
+                    NEXT = U.objectFieldOffset
+                        (SNode.class.getDeclaredField("next"));
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }
+            }
+        }
+
+        /** The head (top) of the stack */
+        volatile SNode head;
+
+        boolean casHead(SNode h, SNode nh) {
+            return h == head &&
+                U.compareAndSwapObject(this, HEAD, h, nh);
+        }
+
+        /**
+         * Creates or resets fields of a node. Called only from transfer
+         * where the node to push on stack is lazily created and
+         * reused when possible to help reduce intervals between reads
+         * and CASes of head and to avoid surges of garbage when CASes
+         * to push nodes fail due to contention.
+         */
+        static SNode snode(SNode s, Object e, SNode next, int mode) {
+            if (s == null) s = new SNode(e);
+            s.mode = mode;
+            s.next = next;
+            return s;
+        }
+
+        /**
+         * Puts or takes an item.
+         */
+        @SuppressWarnings("unchecked")
+        E transfer(E e, boolean timed, long nanos) {
+            /*
+             * Basic algorithm is to loop trying one of three actions:
+             *
+             * 1. If apparently empty or already containing nodes of same
+             *    mode, try to push node on stack and wait for a match,
+             *    returning it, or null if cancelled.
+             *
+             * 2. If apparently containing node of complementary mode,
+             *    try to push a fulfilling node on to stack, match
+             *    with corresponding waiting node, pop both from
+             *    stack, and return matched item. The matching or
+             *    unlinking might not actually be necessary because of
+             *    other threads performing action 3:
+             *
+             * 3. If top of stack already holds another fulfilling node,
+             *    help it out by doing its match and/or pop
+             *    operations, and then continue. The code for helping
+             *    is essentially the same as for fulfilling, except
+             *    that it doesn't return the item.
+             */
+
+            SNode s = null; // constructed/reused as needed
+            int mode = (e == null) ? REQUEST : DATA;
+
+            for (;;) {
+                SNode h = head;
+                if (h == null || h.mode == mode) {  // empty or same-mode
+                    if (timed && nanos <= 0L) {     // can't wait
+                        if (h != null && h.isCancelled())
+                            casHead(h, h.next);     // pop cancelled node
+                        else
+                            return null;
+                    } else if (casHead(h, s = snode(s, e, h, mode))) {
+                        SNode m = awaitFulfill(s, timed, nanos);
+                        if (m == s) {               // wait was cancelled
+                            clean(s);
+                            return null;
+                        }
+                        if ((h = head) != null && h.next == s)
+                            casHead(h, s.next);     // help s's fulfiller
+                        return (E) ((mode == REQUEST) ? m.item : s.item);
+                    }
+                } else if (!isFulfilling(h.mode)) { // try to fulfill
+                    if (h.isCancelled())            // already cancelled
+                        casHead(h, h.next);         // pop and retry
+                    else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
+                        for (;;) { // loop until matched or waiters disappear
+                            SNode m = s.next;       // m is s's match
+                            if (m == null) {        // all waiters are gone
+                                casHead(s, null);   // pop fulfill node
+                                s = null;           // use new node next time
+                                break;              // restart main loop
+                            }
+                            SNode mn = m.next;
+                            if (m.tryMatch(s)) {
+                                casHead(s, mn);     // pop both s and m
+                                return (E) ((mode == REQUEST) ? m.item : s.item);
+                            } else                  // lost match
+                                s.casNext(m, mn);   // help unlink
+                        }
+                    }
+                } else {                            // help a fulfiller
+                    SNode m = h.next;               // m is h's match
+                    if (m == null)                  // waiter is gone
+                        casHead(h, null);           // pop fulfilling node
+                    else {
+                        SNode mn = m.next;
+                        if (m.tryMatch(h))          // help match
+                            casHead(h, mn);         // pop both h and m
+                        else                        // lost match
+                            h.casNext(m, mn);       // help unlink
+                    }
+                }
+            }
+        }
+
+        /**
+         * Spins/blocks until node s is matched by a fulfill operation.
+         *
+         * @param s the waiting node
+         * @param timed true if timed wait
+         * @param nanos timeout value
+         * @return matched node, or s if cancelled
+         */
+        SNode awaitFulfill(SNode s, boolean timed, long nanos) {
+            /*
+             * When a node/thread is about to block, it sets its waiter
+             * field and then rechecks state at least one more time
+             * before actually parking, thus covering race vs
+             * fulfiller noticing that waiter is non-null so should be
+             * woken.
+             *
+             * When invoked by nodes that appear at the point of call
+             * to be at the head of the stack, calls to park are
+             * preceded by spins to avoid blocking when producers and
+             * consumers are arriving very close in time.  This can
+             * happen enough to bother only on multiprocessors.
+             *
+             * The order of checks for returning out of main loop
+             * reflects fact that interrupts have precedence over
+             * normal returns, which have precedence over
+             * timeouts. (So, on timeout, one last check for match is
+             * done before giving up.) Except that calls from untimed
+             * SynchronousQueue.{poll/offer} don't check interrupts
+             * and don't wait at all, so are trapped in transfer
+             * method rather than calling awaitFulfill.
+             */
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Thread w = Thread.currentThread();
+            int spins = shouldSpin(s)
+                ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
+                : 0;
+            for (;;) {
+                if (w.isInterrupted())
+                    s.tryCancel();
+                SNode m = s.match;
+                if (m != null)
+                    return m;
+                if (timed) {
+                    nanos = deadline - System.nanoTime();
+                    if (nanos <= 0L) {
+                        s.tryCancel();
+                        continue;
+                    }
+                }
+                if (spins > 0)
+                    spins = shouldSpin(s) ? (spins - 1) : 0;
+                else if (s.waiter == null)
+                    s.waiter = w; // establish waiter so can park next iter
+                else if (!timed)
+                    LockSupport.park(this);
+                else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanos);
+            }
+        }
+
+        /**
+         * Returns true if node s is at head or there is an active
+         * fulfiller.
+         */
+        boolean shouldSpin(SNode s) {
+            SNode h = head;
+            return (h == s || h == null || isFulfilling(h.mode));
+        }
+
+        /**
+         * Unlinks s from the stack.
+         */
+        void clean(SNode s) {
+            s.item = null;   // forget item
+            s.waiter = null; // forget thread
+
+            /*
+             * At worst we may need to traverse entire stack to unlink
+             * s. If there are multiple concurrent calls to clean, we
+             * might not see s if another thread has already removed
+             * it. But we can stop when we see any node known to
+             * follow s. We use s.next unless it too is cancelled, in
+             * which case we try the node one past. We don't check any
+             * further because we don't want to doubly traverse just to
+             * find sentinel.
+             */
+
+            SNode past = s.next;
+            if (past != null && past.isCancelled())
+                past = past.next;
+
+            // Absorb cancelled nodes at head
+            SNode p;
+            while ((p = head) != null && p != past && p.isCancelled())
+                casHead(p, p.next);
+
+            // Unsplice embedded nodes
+            while (p != null && p != past) {
+                SNode n = p.next;
+                if (n != null && n.isCancelled())
+                    p.casNext(n, n.next);
+                else
+                    p = n;
+            }
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long HEAD;
+        static {
+            try {
+                HEAD = U.objectFieldOffset
+                    (TransferStack.class.getDeclaredField("head"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** Dual Queue */
+    static final class TransferQueue<E> extends Transferer<E> {
+        /*
+         * This extends Scherer-Scott dual queue algorithm, differing,
+         * among other ways, by using modes within nodes rather than
+         * marked pointers. The algorithm is a little simpler than
+         * that for stacks because fulfillers do not need explicit
+         * nodes, and matching is done by CAS'ing QNode.item field
+         * from non-null to null (for put) or vice versa (for take).
+         */
+
+        /** Node class for TransferQueue. */
+        static final class QNode {
+            volatile QNode next;          // next node in queue
+            volatile Object item;         // CAS'ed to or from null
+            volatile Thread waiter;       // to control park/unpark
+            final boolean isData;
+
+            QNode(Object item, boolean isData) {
+                this.item = item;
+                this.isData = isData;
+            }
+
+            boolean casNext(QNode cmp, QNode val) {
+                return next == cmp &&
+                    U.compareAndSwapObject(this, NEXT, cmp, val);
+            }
+
+            boolean casItem(Object cmp, Object val) {
+                return item == cmp &&
+                    U.compareAndSwapObject(this, ITEM, cmp, val);
+            }
+
+            /**
+             * Tries to cancel by CAS'ing ref to this as item.
+             */
+            void tryCancel(Object cmp) {
+                U.compareAndSwapObject(this, ITEM, cmp, this);
+            }
+
+            boolean isCancelled() {
+                return item == this;
+            }
+
+            /**
+             * Returns true if this node is known to be off the queue
+             * because its next pointer has been forgotten due to
+             * an advanceHead operation.
+             */
+            boolean isOffList() {
+                return next == this;
+            }
+
+            // Unsafe mechanics
+            private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+            private static final long ITEM;
+            private static final long NEXT;
+
+            static {
+                try {
+                    ITEM = U.objectFieldOffset
+                        (QNode.class.getDeclaredField("item"));
+                    NEXT = U.objectFieldOffset
+                        (QNode.class.getDeclaredField("next"));
+                } catch (ReflectiveOperationException e) {
+                    throw new Error(e);
+                }
+            }
+        }
+
+        /** Head of queue */
+        transient volatile QNode head;
+        /** Tail of queue */
+        transient volatile QNode tail;
+        /**
+         * Reference to a cancelled node that might not yet have been
+         * unlinked from queue because it was the last inserted node
+         * when it was cancelled.
+         */
+        transient volatile QNode cleanMe;
+
+        TransferQueue() {
+            QNode h = new QNode(null, false); // initialize to dummy node.
+            head = h;
+            tail = h;
+        }
+
+        /**
+         * Tries to cas nh as new head; if successful, unlink
+         * old head's next node to avoid garbage retention.
+         */
+        void advanceHead(QNode h, QNode nh) {
+            if (h == head &&
+                U.compareAndSwapObject(this, HEAD, h, nh))
+                h.next = h; // forget old next
+        }
+
+        /**
+         * Tries to cas nt as new tail.
+         */
+        void advanceTail(QNode t, QNode nt) {
+            if (tail == t)
+                U.compareAndSwapObject(this, TAIL, t, nt);
+        }
+
+        /**
+         * Tries to CAS cleanMe slot.
+         */
+        boolean casCleanMe(QNode cmp, QNode val) {
+            return cleanMe == cmp &&
+                U.compareAndSwapObject(this, CLEANME, cmp, val);
+        }
+
+        /**
+         * Puts or takes an item.
+         */
+        @SuppressWarnings("unchecked")
+        E transfer(E e, boolean timed, long nanos) {
+            /* Basic algorithm is to loop trying to take either of
+             * two actions:
+             *
+             * 1. If queue apparently empty or holding same-mode nodes,
+             *    try to add node to queue of waiters, wait to be
+             *    fulfilled (or cancelled) and return matching item.
+             *
+             * 2. If queue apparently contains waiting items, and this
+             *    call is of complementary mode, try to fulfill by CAS'ing
+             *    item field of waiting node and dequeuing it, and then
+             *    returning matching item.
+             *
+             * In each case, along the way, check for and try to help
+             * advance head and tail on behalf of other stalled/slow
+             * threads.
+             *
+             * The loop starts off with a null check guarding against
+             * seeing uninitialized head or tail values. This never
+             * happens in current SynchronousQueue, but could if
+             * callers held non-volatile/final ref to the
+             * transferer. The check is here anyway because it places
+             * null checks at top of loop, which is usually faster
+             * than having them implicitly interspersed.
+             */
+
+            QNode s = null; // constructed/reused as needed
+            boolean isData = (e != null);
+
+            for (;;) {
+                QNode t = tail;
+                QNode h = head;
+                if (t == null || h == null)         // saw uninitialized value
+                    continue;                       // spin
+
+                if (h == t || t.isData == isData) { // empty or same-mode
+                    QNode tn = t.next;
+                    if (t != tail)                  // inconsistent read
+                        continue;
+                    if (tn != null) {               // lagging tail
+                        advanceTail(t, tn);
+                        continue;
+                    }
+                    if (timed && nanos <= 0L)       // can't wait
+                        return null;
+                    if (s == null)
+                        s = new QNode(e, isData);
+                    if (!t.casNext(null, s))        // failed to link in
+                        continue;
+
+                    advanceTail(t, s);              // swing tail and wait
+                    Object x = awaitFulfill(s, e, timed, nanos);
+                    if (x == s) {                   // wait was cancelled
+                        clean(t, s);
+                        return null;
+                    }
+
+                    if (!s.isOffList()) {           // not already unlinked
+                        advanceHead(t, s);          // unlink if head
+                        if (x != null)              // and forget fields
+                            s.item = s;
+                        s.waiter = null;
+                    }
+                    return (x != null) ? (E)x : e;
+
+                } else {                            // complementary-mode
+                    QNode m = h.next;               // node to fulfill
+                    if (t != tail || m == null || h != head)
+                        continue;                   // inconsistent read
+
+                    Object x = m.item;
+                    if (isData == (x != null) ||    // m already fulfilled
+                        x == m ||                   // m cancelled
+                        !m.casItem(x, e)) {         // lost CAS
+                        advanceHead(h, m);          // dequeue and retry
+                        continue;
+                    }
+
+                    advanceHead(h, m);              // successfully fulfilled
+                    LockSupport.unpark(m.waiter);
+                    return (x != null) ? (E)x : e;
+                }
+            }
+        }
+
+        /**
+         * Spins/blocks until node s is fulfilled.
+         *
+         * @param s the waiting node
+         * @param e the comparison value for checking match
+         * @param timed true if timed wait
+         * @param nanos timeout value
+         * @return matched item, or s if cancelled
+         */
+        Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {
+            /* Same idea as TransferStack.awaitFulfill */
+            final long deadline = timed ? System.nanoTime() + nanos : 0L;
+            Thread w = Thread.currentThread();
+            int spins = (head.next == s)
+                ? (timed ? MAX_TIMED_SPINS : MAX_UNTIMED_SPINS)
+                : 0;
+            for (;;) {
+                if (w.isInterrupted())
+                    s.tryCancel(e);
+                Object x = s.item;
+                if (x != e)
+                    return x;
+                if (timed) {
+                    nanos = deadline - System.nanoTime();
+                    if (nanos <= 0L) {
+                        s.tryCancel(e);
+                        continue;
+                    }
+                }
+                if (spins > 0)
+                    --spins;
+                else if (s.waiter == null)
+                    s.waiter = w;
+                else if (!timed)
+                    LockSupport.park(this);
+                else if (nanos > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanos);
+            }
+        }
+
+        /**
+         * Gets rid of cancelled node s with original predecessor pred.
+         */
+        void clean(QNode pred, QNode s) {
+            s.waiter = null; // forget thread
+            /*
+             * At any given time, exactly one node on list cannot be
+             * deleted -- the last inserted node. To accommodate this,
+             * if we cannot delete s, we save its predecessor as
+             * "cleanMe", deleting the previously saved version
+             * first. At least one of node s or the node previously
+             * saved can always be deleted, so this always terminates.
+             */
+            while (pred.next == s) { // Return early if already unlinked
+                QNode h = head;
+                QNode hn = h.next;   // Absorb cancelled first node as head
+                if (hn != null && hn.isCancelled()) {
+                    advanceHead(h, hn);
+                    continue;
+                }
+                QNode t = tail;      // Ensure consistent read for tail
+                if (t == h)
+                    return;
+                QNode tn = t.next;
+                if (t != tail)
+                    continue;
+                if (tn != null) {
+                    advanceTail(t, tn);
+                    continue;
+                }
+                if (s != t) {        // If not tail, try to unsplice
+                    QNode sn = s.next;
+                    if (sn == s || pred.casNext(s, sn))
+                        return;
+                }
+                QNode dp = cleanMe;
+                if (dp != null) {    // Try unlinking previous cancelled node
+                    QNode d = dp.next;
+                    QNode dn;
+                    if (d == null ||               // d is gone or
+                        d == dp ||                 // d is off list or
+                        !d.isCancelled() ||        // d not cancelled or
+                        (d != t &&                 // d not tail and
+                         (dn = d.next) != null &&  //   has successor
+                         dn != d &&                //   that is on list
+                         dp.casNext(d, dn)))       // d unspliced
+                        casCleanMe(dp, null);
+                    if (dp == pred)
+                        return;      // s is already saved node
+                } else if (casCleanMe(null, pred))
+                    return;          // Postpone cleaning s
+            }
+        }
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long HEAD;
+        private static final long TAIL;
+        private static final long CLEANME;
+        static {
+            try {
+                HEAD = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("head"));
+                TAIL = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("tail"));
+                CLEANME = U.objectFieldOffset
+                    (TransferQueue.class.getDeclaredField("cleanMe"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * The transferer. Set only in constructor, but cannot be declared
+     * as final without further complicating serialization.  Since
+     * this is accessed only at most once per public method, there
+     * isn't a noticeable performance penalty for using volatile
+     * instead of final here.
+     */
+    private transient volatile Transferer<E> transferer;
+
+    /**
+     * Creates a {@code SynchronousQueue} with nonfair access policy.
+     */
+    public SynchronousQueue() {
+        this(false);
+    }
+
+    /**
+     * Creates a {@code SynchronousQueue} with the specified fairness policy.
+     *
+     * @param fair if true, waiting threads contend in FIFO order for
+     *        access; otherwise the order is unspecified.
+     */
+    public SynchronousQueue(boolean fair) {
+        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
+    }
+
+    /**
+     * Adds the specified element to this queue, waiting if necessary for
+     * another thread to receive it.
+     *
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        if (transferer.transfer(e, false, 0) == null) {
+            Thread.interrupted();
+            throw new InterruptedException();
+        }
+    }
+
+    /**
+     * Inserts the specified element into this queue, waiting if necessary
+     * up to the specified wait time for another thread to receive it.
+     *
+     * @return {@code true} if successful, or {@code false} if the
+     *         specified waiting time elapses before a consumer appears
+     * @throws InterruptedException {@inheritDoc}
+     * @throws NullPointerException {@inheritDoc}
+     */
+    public boolean offer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
+            return true;
+        if (!Thread.interrupted())
+            return false;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Inserts the specified element into this queue, if another thread is
+     * waiting to receive it.
+     *
+     * @param e the element to add
+     * @return {@code true} if the element was added to this queue, else
+     *         {@code false}
+     * @throws NullPointerException if the specified element is null
+     */
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        return transferer.transfer(e, true, 0) != null;
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting if necessary
+     * for another thread to insert it.
+     *
+     * @return the head of this queue
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E take() throws InterruptedException {
+        E e = transferer.transfer(null, false, 0);
+        if (e != null)
+            return e;
+        Thread.interrupted();
+        throw new InterruptedException();
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, waiting
+     * if necessary up to the specified wait time, for another thread
+     * to insert it.
+     *
+     * @return the head of this queue, or {@code null} if the
+     *         specified waiting time elapses before an element is present
+     * @throws InterruptedException {@inheritDoc}
+     */
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E e = transferer.transfer(null, true, unit.toNanos(timeout));
+        if (e != null || !Thread.interrupted())
+            return e;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Retrieves and removes the head of this queue, if another thread
+     * is currently making an element available.
+     *
+     * @return the head of this queue, or {@code null} if no
+     *         element is available
+     */
+    public E poll() {
+        return transferer.transfer(null, true, 0);
+    }
+
+    /**
+     * Always returns {@code true}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return {@code true}
+     */
+    public boolean isEmpty() {
+        return true;
+    }
+
+    /**
+     * Always returns zero.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return zero
+     */
+    public int size() {
+        return 0;
+    }
+
+    /**
+     * Always returns zero.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @return zero
+     */
+    public int remainingCapacity() {
+        return 0;
+    }
+
+    /**
+     * Does nothing.
+     * A {@code SynchronousQueue} has no internal capacity.
+     */
+    public void clear() {
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param o the element
+     * @return {@code false}
+     */
+    public boolean contains(Object o) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param o the element to remove
+     * @return {@code false}
+     */
+    public boolean remove(Object o) {
+        return false;
+    }
+
+    /**
+     * Returns {@code false} unless the given collection is empty.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false} unless given collection is empty
+     */
+    public boolean containsAll(Collection<?> c) {
+        return c.isEmpty();
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false}
+     */
+    public boolean removeAll(Collection<?> c) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code false}.
+     * A {@code SynchronousQueue} has no internal capacity.
+     *
+     * @param c the collection
+     * @return {@code false}
+     */
+    public boolean retainAll(Collection<?> c) {
+        return false;
+    }
+
+    /**
+     * Always returns {@code null}.
+     * A {@code SynchronousQueue} does not return elements
+     * unless actively waited on.
+     *
+     * @return {@code null}
+     */
+    public E peek() {
+        return null;
+    }
+
+    /**
+     * Returns an empty iterator in which {@code hasNext} always returns
+     * {@code false}.
+     *
+     * @return an empty iterator
+     */
+    public Iterator<E> iterator() {
+        return Collections.emptyIterator();
+    }
+
+    /**
+     * Returns an empty spliterator in which calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return an empty spliterator
+     * @since 1.8
+     */
+    public Spliterator<E> spliterator() {
+        return Spliterators.emptySpliterator();
+    }
+
+    /**
+     * Returns a zero-length array.
+     * @return a zero-length array
+     */
+    public Object[] toArray() {
+        return new Object[0];
+    }
+
+    /**
+     * Sets the zeroth element of the specified array to {@code null}
+     * (if the array has non-zero length) and returns it.
+     *
+     * @param a the array
+     * @return the specified array
+     * @throws NullPointerException if the specified array is null
+     */
+    public <T> T[] toArray(T[] a) {
+        if (a.length > 0)
+            a[0] = null;
+        return a;
+    }
+
+    /**
+     * Always returns {@code "[]"}.
+     * @return {@code "[]"}
+     */
+    public String toString() {
+        return "[]";
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /**
+     * @throws UnsupportedOperationException {@inheritDoc}
+     * @throws ClassCastException            {@inheritDoc}
+     * @throws NullPointerException          {@inheritDoc}
+     * @throws IllegalArgumentException      {@inheritDoc}
+     */
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        int n = 0;
+        for (E e; n < maxElements && (e = poll()) != null;) {
+            c.add(e);
+            ++n;
+        }
+        return n;
+    }
+
+    /*
+     * To cope with serialization strategy in the 1.5 version of
+     * SynchronousQueue, we declare some unused classes and fields
+     * that exist solely to enable serializability across versions.
+     * These fields are never used, so are initialized only if this
+     * object is ever serialized or deserialized.
+     */
+
+    @SuppressWarnings("serial")
+    static class WaitQueue implements java.io.Serializable { }
+    static class LifoWaitQueue extends WaitQueue {
+        private static final long serialVersionUID = -3633113410248163686L;
+    }
+    static class FifoWaitQueue extends WaitQueue {
+        private static final long serialVersionUID = -3623113410248163686L;
+    }
+    private ReentrantLock qlock;
+    private WaitQueue waitingProducers;
+    private WaitQueue waitingConsumers;
+
+    /**
+     * Saves this queue to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+        boolean fair = transferer instanceof TransferQueue;
+        if (fair) {
+            qlock = new ReentrantLock(true);
+            waitingProducers = new FifoWaitQueue();
+            waitingConsumers = new FifoWaitQueue();
+        }
+        else {
+            qlock = new ReentrantLock();
+            waitingProducers = new LifoWaitQueue();
+            waitingConsumers = new LifoWaitQueue();
+        }
+        s.defaultWriteObject();
+    }
+
+    /**
+     * Reconstitutes this queue from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        if (waitingProducers instanceof FifoWaitQueue)
+            transferer = new TransferQueue<E>();
+        else
+            transferer = new TransferStack<E>();
+    }
+
+    static {
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+}
diff --git a/java/util/concurrent/ThreadFactory.java b/java/util/concurrent/ThreadFactory.java
new file mode 100644
index 0000000..ac7afa0
--- /dev/null
+++ b/java/util/concurrent/ThreadFactory.java
@@ -0,0 +1,69 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * An object that creates new threads on demand.  Using thread factories
+ * removes hardwiring of calls to {@link Thread#Thread(Runnable) new Thread},
+ * enabling applications to use special thread subclasses, priorities, etc.
+ *
+ * <p>
+ * The simplest implementation of this interface is just:
+ * <pre> {@code
+ * class SimpleThreadFactory implements ThreadFactory {
+ *   public Thread newThread(Runnable r) {
+ *     return new Thread(r);
+ *   }
+ * }}</pre>
+ *
+ * The {@link Executors#defaultThreadFactory} method provides a more
+ * useful simple implementation, that sets the created thread context
+ * to known values before returning it.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ThreadFactory {
+
+    /**
+     * Constructs a new {@code Thread}.  Implementations may also initialize
+     * priority, name, daemon status, {@code ThreadGroup}, etc.
+     *
+     * @param r a runnable to be executed by new thread instance
+     * @return constructed thread, or {@code null} if the request to
+     *         create a thread is rejected
+     */
+    Thread newThread(Runnable r);
+}
diff --git a/java/util/concurrent/ThreadLocalRandom.java b/java/util/concurrent/ThreadLocalRandom.java
new file mode 100644
index 0000000..195f8ac
--- /dev/null
+++ b/java/util/concurrent/ThreadLocalRandom.java
@@ -0,0 +1,1073 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.io.ObjectStreamField;
+import java.util.Random;
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
+/**
+ * A random number generator isolated to the current thread.  Like the
+ * global {@link java.util.Random} generator used by the {@link
+ * java.lang.Math} class, a {@code ThreadLocalRandom} is initialized
+ * with an internally generated seed that may not otherwise be
+ * modified. When applicable, use of {@code ThreadLocalRandom} rather
+ * than shared {@code Random} objects in concurrent programs will
+ * typically encounter much less overhead and contention.  Use of
+ * {@code ThreadLocalRandom} is particularly appropriate when multiple
+ * tasks (for example, each a {@link ForkJoinTask}) use random numbers
+ * in parallel in thread pools.
+ *
+ * <p>Usages of this class should typically be of the form:
+ * {@code ThreadLocalRandom.current().nextX(...)} (where
+ * {@code X} is {@code Int}, {@code Long}, etc).
+ * When all usages are of this form, it is never possible to
+ * accidently share a {@code ThreadLocalRandom} across multiple threads.
+ *
+ * <p>This class also provides additional commonly used bounded random
+ * generation methods.
+ *
+ * <p>Instances of {@code ThreadLocalRandom} are not cryptographically
+ * secure.  Consider instead using {@link java.security.SecureRandom}
+ * in security-sensitive applications. Additionally,
+ * default-constructed instances do not use a cryptographically random
+ * seed unless the {@linkplain System#getProperty system property}
+ * {@code java.util.secureRandomSeed} is set to {@code true}.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ */
+public class ThreadLocalRandom extends Random {
+    /*
+     * This class implements the java.util.Random API (and subclasses
+     * Random) using a single static instance that accesses random
+     * number state held in class Thread (primarily, field
+     * threadLocalRandomSeed). In doing so, it also provides a home
+     * for managing package-private utilities that rely on exactly the
+     * same state as needed to maintain the ThreadLocalRandom
+     * instances. We leverage the need for an initialization flag
+     * field to also use it as a "probe" -- a self-adjusting thread
+     * hash used for contention avoidance, as well as a secondary
+     * simpler (xorShift) random seed that is conservatively used to
+     * avoid otherwise surprising users by hijacking the
+     * ThreadLocalRandom sequence.  The dual use is a marriage of
+     * convenience, but is a simple and efficient way of reducing
+     * application-level overhead and footprint of most concurrent
+     * programs.
+     *
+     * Even though this class subclasses java.util.Random, it uses the
+     * same basic algorithm as java.util.SplittableRandom.  (See its
+     * internal documentation for explanations, which are not repeated
+     * here.)  Because ThreadLocalRandoms are not splittable
+     * though, we use only a single 64bit gamma.
+     *
+     * Because this class is in a different package than class Thread,
+     * field access methods use Unsafe to bypass access control rules.
+     * To conform to the requirements of the Random superclass
+     * constructor, the common static ThreadLocalRandom maintains an
+     * "initialized" field for the sake of rejecting user calls to
+     * setSeed while still allowing a call from constructor.  Note
+     * that serialization is completely unnecessary because there is
+     * only a static singleton.  But we generate a serial form
+     * containing "rnd" and "initialized" fields to ensure
+     * compatibility across versions.
+     *
+     * Implementations of non-core methods are mostly the same as in
+     * SplittableRandom, that were in part derived from a previous
+     * version of this class.
+     *
+     * The nextLocalGaussian ThreadLocal supports the very rarely used
+     * nextGaussian method by providing a holder for the second of a
+     * pair of them. As is true for the base class version of this
+     * method, this time/space tradeoff is probably never worthwhile,
+     * but we provide identical statistical properties.
+     */
+
+    private static long mix64(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+        return z ^ (z >>> 33);
+    }
+
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
+    }
+
+    /**
+     * Field used only during singleton initialization.
+     * True when constructor completes.
+     */
+    boolean initialized;
+
+    /** Constructor used only for static singleton */
+    private ThreadLocalRandom() {
+        initialized = true; // false during super() call
+    }
+
+    /**
+     * Initialize Thread fields for the current thread.  Called only
+     * when Thread.threadLocalRandomProbe is zero, indicating that a
+     * thread local seed value needs to be generated. Note that even
+     * though the initialization is purely thread-local, we need to
+     * rely on (static) atomic generators to initialize the values.
+     */
+    static final void localInit() {
+        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
+        int probe = (p == 0) ? 1 : p; // skip 0
+        long seed = mix64(seeder.getAndAdd(SEEDER_INCREMENT));
+        Thread t = Thread.currentThread();
+        U.putLong(t, SEED, seed);
+        U.putInt(t, PROBE, probe);
+    }
+
+    /**
+     * Returns the current thread's {@code ThreadLocalRandom}.
+     *
+     * @return the current thread's {@code ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom current() {
+        if (U.getInt(Thread.currentThread(), PROBE) == 0)
+            localInit();
+        return instance;
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.  Setting seeds in
+     * this generator is not supported.
+     *
+     * @throws UnsupportedOperationException always
+     */
+    public void setSeed(long seed) {
+        // only allow call from super() constructor
+        if (initialized)
+            throw new UnsupportedOperationException();
+    }
+
+    final long nextSeed() {
+        Thread t; long r; // read and update per-thread seed
+        U.putLong(t = Thread.currentThread(), SEED,
+                  r = U.getLong(t, SEED) + GAMMA);
+        return r;
+    }
+
+    // We must define this, but never use it.
+    protected int next(int bits) {
+        return (int)(mix64(nextSeed()) >>> (64 - bits));
+    }
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        long r = mix64(nextSeed());
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = mix64(nextSeed()) >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = mix64(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * Exactly the same as long version, except for types.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final int internalNextInt(int origin, int bound) {
+        int r = mix32(nextSeed());
+        if (origin < bound) {
+            int n = bound - origin, m = n - 1;
+            if ((n & m) == 0)
+                r = (r & m) + origin;
+            else if (n > 0) {
+                for (int u = r >>> 1;
+                     u + m - (r = u % n) < 0;
+                     u = mix32(nextSeed()) >>> 1)
+                    ;
+                r += origin;
+            }
+            else {
+                while (r < origin || r >= bound)
+                    r = mix32(nextSeed());
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = (nextLong() >>> 11) * DOUBLE_UNIT;
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value.
+     *
+     * @return a pseudorandom {@code int} value
+     */
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code int} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        int r = mix32(nextSeed());
+        int m = bound - 1;
+        if ((bound & m) == 0) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (int u = r >>> 1;
+                 u + m - (r = u % bound) < 0;
+                 u = mix32(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code int} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public int nextInt(int origin, int bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextInt(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value.
+     *
+     * @return a pseudorandom {@code long} value
+     */
+    public long nextLong() {
+        return mix64(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code long} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public long nextLong(long bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BAD_BOUND);
+        long r = mix64(nextSeed());
+        long m = bound - 1;
+        if ((bound & m) == 0L) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (long u = r >>> 1;
+                 u + m - (r = u % bound) < 0L;
+                 u = mix64(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code long} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code long} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public long nextLong(long origin, long bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextLong(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and one (exclusive)
+     */
+    public double nextDouble() {
+        return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between 0.0
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the upper bound (exclusive).  Must be positive.
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public double nextDouble(double bound) {
+        if (!(bound > 0.0))
+            throw new IllegalArgumentException(BAD_BOUND);
+        double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
+        return (result < bound) ? result : // correct for rounding
+            Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between the specified
+     * origin (inclusive) and bound (exclusive).
+     *
+     * @param origin the least value returned
+     * @param bound the upper bound (exclusive)
+     * @return a pseudorandom {@code double} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
+     */
+    public double nextDouble(double origin, double bound) {
+        if (!(origin < bound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return internalNextDouble(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code boolean} value.
+     *
+     * @return a pseudorandom {@code boolean} value
+     */
+    public boolean nextBoolean() {
+        return mix32(nextSeed()) < 0;
+    }
+
+    /**
+     * Returns a pseudorandom {@code float} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code float} value between zero
+     *         (inclusive) and one (exclusive)
+     */
+    public float nextFloat() {
+        return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT;
+    }
+
+    public double nextGaussian() {
+        // Use nextLocalGaussian instead of nextGaussian field
+        Double d = nextLocalGaussian.get();
+        if (d != null) {
+            nextLocalGaussian.set(null);
+            return d.doubleValue();
+        }
+        double v1, v2, s;
+        do {
+            v1 = 2 * nextDouble() - 1; // between -1 and 1
+            v2 = 2 * nextDouble() - 1; // between -1 and 1
+            s = v1 * v1 + v2 * v2;
+        } while (s >= 1 || s == 0);
+        double multiplier = StrictMath.sqrt(-2 * StrictMath.log(s)/s);
+        nextLocalGaussian.set(new Double(v2 * multiplier));
+        return v1 * multiplier;
+    }
+
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, streamSize, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     * @since 1.8
+     */
+    public IntStream ints() {
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number
+     * of pseudorandom {@code int} values, each conforming to the given
+     * origin (inclusive) and bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, streamSize, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code long}
+     * values.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     * @since 1.8
+     */
+    public LongStream longs() {
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long}, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, streamSize, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     * @since 1.8
+     */
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the given origin
+     * (inclusive) and bound (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BAD_SIZE);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin (inclusive) and bound
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin (inclusive) of each random value
+     * @param randomNumberBound the bound (exclusive) of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     *         each with the given origin (inclusive) and bound (exclusive)
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     * @since 1.8
+     */
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BAD_RANGE);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    private static final class RandomIntsSpliterator
+            implements Spliterator.OfInt {
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(long index, long fence,
+                              int origin, int bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomIntsSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                int o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    private static final class RandomLongsSpliterator
+            implements Spliterator.OfLong {
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(long index, long fence,
+                               long origin, long bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomLongsSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                long o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    private static final class RandomDoublesSpliterator
+            implements Spliterator.OfDouble {
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(long index, long fence,
+                                 double origin, double bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomDoublesSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                double o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+
+    // Within-package utilities
+
+    /*
+     * Descriptions of the usages of the methods below can be found in
+     * the classes that use them. Briefly, a thread's "probe" value is
+     * a non-zero hash code that (probably) does not collide with
+     * other existing threads with respect to any power of two
+     * collision space. When it does collide, it is pseudo-randomly
+     * adjusted (using a Marsaglia XorShift). The nextSecondarySeed
+     * method is used in the same contexts as ThreadLocalRandom, but
+     * only for transient usages such as random adaptive spin/block
+     * sequences for which a cheap RNG suffices and for which it could
+     * in principle disrupt user-visible statistical properties of the
+     * main ThreadLocalRandom if we were to use it.
+     *
+     * Note: Because of package-protection issues, versions of some
+     * these methods also appear in some subpackage classes.
+     */
+
+    /**
+     * Returns the probe value for the current thread without forcing
+     * initialization. Note that invoking ThreadLocalRandom.current()
+     * can be used to force initialization on zero return.
+     */
+    static final int getProbe() {
+        return U.getInt(Thread.currentThread(), PROBE);
+    }
+
+    /**
+     * Pseudo-randomly advances and records the given probe value for the
+     * given thread.
+     */
+    static final int advanceProbe(int probe) {
+        probe ^= probe << 13;   // xorshift
+        probe ^= probe >>> 17;
+        probe ^= probe << 5;
+        U.putInt(Thread.currentThread(), PROBE, probe);
+        return probe;
+    }
+
+    /**
+     * Returns the pseudo-randomly initialized or updated secondary seed.
+     */
+    static final int nextSecondarySeed() {
+        int r;
+        Thread t = Thread.currentThread();
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
+            r ^= r << 13;   // xorshift
+            r ^= r >>> 17;
+            r ^= r << 5;
+        }
+        else if ((r = mix32(seeder.getAndAdd(SEEDER_INCREMENT))) == 0)
+            r = 1; // avoid zero
+        U.putInt(t, SECONDARY, r);
+        return r;
+    }
+
+    // Serialization support
+
+    private static final long serialVersionUID = -5851777807851030925L;
+
+    /**
+     * @serialField rnd long
+     *              seed for random computations
+     * @serialField initialized boolean
+     *              always true
+     */
+    private static final ObjectStreamField[] serialPersistentFields = {
+        new ObjectStreamField("rnd", long.class),
+        new ObjectStreamField("initialized", boolean.class),
+    };
+
+    /**
+     * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void writeObject(java.io.ObjectOutputStream s)
+        throws java.io.IOException {
+
+        java.io.ObjectOutputStream.PutField fields = s.putFields();
+        fields.put("rnd", U.getLong(Thread.currentThread(), SEED));
+        fields.put("initialized", true);
+        s.writeFields();
+    }
+
+    /**
+     * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
+     * @return the {@link #current() current} thread's {@code ThreadLocalRandom}
+     */
+    private Object readResolve() {
+        return current();
+    }
+
+    // Static initialization
+
+    /**
+     * The seed increment.
+     */
+    private static final long GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The increment for generating probe values.
+     */
+    private static final int PROBE_INCREMENT = 0x9e3779b9;
+
+    /**
+     * The increment of seeder per new instance.
+     */
+    private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
+
+    // Constants from SplittableRandom
+    private static final double DOUBLE_UNIT = 0x1.0p-53;  // 1.0  / (1L << 53)
+    private static final float  FLOAT_UNIT  = 0x1.0p-24f; // 1.0f / (1 << 24)
+
+    // IllegalArgumentException messages
+    static final String BAD_BOUND = "bound must be positive";
+    static final String BAD_RANGE = "bound must be greater than origin";
+    static final String BAD_SIZE  = "size must be non-negative";
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long SEED;
+    private static final long PROBE;
+    private static final long SECONDARY;
+    static {
+        try {
+            SEED = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSeed"));
+            PROBE = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+            SECONDARY = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    /** Rarely-used holder for the second of a pair of Gaussians */
+    private static final ThreadLocal<Double> nextLocalGaussian =
+        new ThreadLocal<>();
+
+    /** Generates per-thread initialization/probe field */
+    private static final AtomicInteger probeGenerator = new AtomicInteger();
+
+    /** The common ThreadLocalRandom */
+    static final ThreadLocalRandom instance = new ThreadLocalRandom();
+
+    /**
+     * The next seed for default constructors.
+     */
+    private static final AtomicLong seeder
+        = new AtomicLong(mix64(System.currentTimeMillis()) ^
+                         mix64(System.nanoTime()));
+
+    // at end of <clinit> to survive static initialization circularity
+    static {
+        if (java.security.AccessController.doPrivileged(
+            new java.security.PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return Boolean.getBoolean("java.util.secureRandomSeed");
+                }})) {
+            byte[] seedBytes = java.security.SecureRandom.getSeed(8);
+            long s = (long)seedBytes[0] & 0xffL;
+            for (int i = 1; i < 8; ++i)
+                s = (s << 8) | ((long)seedBytes[i] & 0xffL);
+            seeder.set(s);
+        }
+    }
+}
diff --git a/java/util/concurrent/ThreadPoolExecutor.java b/java/util/concurrent/ThreadPoolExecutor.java
new file mode 100644
index 0000000..b0096a4
--- /dev/null
+++ b/java/util/concurrent/ThreadPoolExecutor.java
@@ -0,0 +1,2137 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+// BEGIN android-note
+// removed security manager docs
+// END android-note
+
+/**
+ * An {@link ExecutorService} that executes each submitted task using
+ * one of possibly several pooled threads, normally configured
+ * using {@link Executors} factory methods.
+ *
+ * <p>Thread pools address two different problems: they usually
+ * provide improved performance when executing large numbers of
+ * asynchronous tasks, due to reduced per-task invocation overhead,
+ * and they provide a means of bounding and managing the resources,
+ * including threads, consumed when executing a collection of tasks.
+ * Each {@code ThreadPoolExecutor} also maintains some basic
+ * statistics, such as the number of completed tasks.
+ *
+ * <p>To be useful across a wide range of contexts, this class
+ * provides many adjustable parameters and extensibility
+ * hooks. However, programmers are urged to use the more convenient
+ * {@link Executors} factory methods {@link
+ * Executors#newCachedThreadPool} (unbounded thread pool, with
+ * automatic thread reclamation), {@link Executors#newFixedThreadPool}
+ * (fixed size thread pool) and {@link
+ * Executors#newSingleThreadExecutor} (single background thread), that
+ * preconfigure settings for the most common usage
+ * scenarios. Otherwise, use the following guide when manually
+ * configuring and tuning this class:
+ *
+ * <dl>
+ *
+ * <dt>Core and maximum pool sizes</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A {@code ThreadPoolExecutor} will automatically adjust the
+ * pool size (see {@link #getPoolSize})
+ * according to the bounds set by
+ * corePoolSize (see {@link #getCorePoolSize}) and
+ * maximumPoolSize (see {@link #getMaximumPoolSize}).
+ *
+ * When a new task is submitted in method {@link #execute(Runnable)},
+ * and fewer than corePoolSize threads are running, a new thread is
+ * created to handle the request, even if other worker threads are
+ * idle.  If there are more than corePoolSize but less than
+ * maximumPoolSize threads running, a new thread will be created only
+ * if the queue is full.  By setting corePoolSize and maximumPoolSize
+ * the same, you create a fixed-size thread pool. By setting
+ * maximumPoolSize to an essentially unbounded value such as {@code
+ * Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
+ * number of concurrent tasks. Most typically, core and maximum pool
+ * sizes are set only upon construction, but they may also be changed
+ * dynamically using {@link #setCorePoolSize} and {@link
+ * #setMaximumPoolSize}. </dd>
+ *
+ * <dt>On-demand construction</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * By default, even core threads are initially created and
+ * started only when new tasks arrive, but this can be overridden
+ * dynamically using method {@link #prestartCoreThread} or {@link
+ * #prestartAllCoreThreads}.  You probably want to prestart threads if
+ * you construct the pool with a non-empty queue. </dd>
+ *
+ * <dt>Creating new threads</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New threads are created using a {@link ThreadFactory}.  If not
+ * otherwise specified, a {@link Executors#defaultThreadFactory} is
+ * used, that creates threads to all be in the same {@link
+ * ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
+ * non-daemon status. By supplying a different ThreadFactory, you can
+ * alter the thread's name, thread group, priority, daemon status,
+ * etc. If a {@code ThreadFactory} fails to create a thread when asked
+ * by returning null from {@code newThread}, the executor will
+ * continue, but might not be able to execute any tasks. Threads
+ * should possess the "modifyThread" {@code RuntimePermission}. If
+ * worker threads or other threads using the pool do not possess this
+ * permission, service may be degraded: configuration changes may not
+ * take effect in a timely manner, and a shutdown pool may remain in a
+ * state in which termination is possible but not completed.</dd>
+ *
+ * <dt>Keep-alive times</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * If the pool currently has more than corePoolSize threads,
+ * excess threads will be terminated if they have been idle for more
+ * than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
+ * This provides a means of reducing resource consumption when the
+ * pool is not being actively used. If the pool becomes more active
+ * later, new threads will be constructed. This parameter can also be
+ * changed dynamically using method {@link #setKeepAliveTime(long,
+ * TimeUnit)}.  Using a value of {@code Long.MAX_VALUE} {@link
+ * TimeUnit#NANOSECONDS} effectively disables idle threads from ever
+ * terminating prior to shut down. By default, the keep-alive policy
+ * applies only when there are more than corePoolSize threads, but
+ * method {@link #allowCoreThreadTimeOut(boolean)} can be used to
+ * apply this time-out policy to core threads as well, so long as the
+ * keepAliveTime value is non-zero. </dd>
+ *
+ * <dt>Queuing</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Any {@link BlockingQueue} may be used to transfer and hold
+ * submitted tasks.  The use of this queue interacts with pool sizing:
+ *
+ * <ul>
+ *
+ * <li>If fewer than corePoolSize threads are running, the Executor
+ * always prefers adding a new thread
+ * rather than queuing.
+ *
+ * <li>If corePoolSize or more threads are running, the Executor
+ * always prefers queuing a request rather than adding a new
+ * thread.
+ *
+ * <li>If a request cannot be queued, a new thread is created unless
+ * this would exceed maximumPoolSize, in which case, the task will be
+ * rejected.
+ *
+ * </ul>
+ *
+ * There are three general strategies for queuing:
+ * <ol>
+ *
+ * <li><em> Direct handoffs.</em> A good default choice for a work
+ * queue is a {@link SynchronousQueue} that hands off tasks to threads
+ * without otherwise holding them. Here, an attempt to queue a task
+ * will fail if no threads are immediately available to run it, so a
+ * new thread will be constructed. This policy avoids lockups when
+ * handling sets of requests that might have internal dependencies.
+ * Direct handoffs generally require unbounded maximumPoolSizes to
+ * avoid rejection of new submitted tasks. This in turn admits the
+ * possibility of unbounded thread growth when commands continue to
+ * arrive on average faster than they can be processed.
+ *
+ * <li><em> Unbounded queues.</em> Using an unbounded queue (for
+ * example a {@link LinkedBlockingQueue} without a predefined
+ * capacity) will cause new tasks to wait in the queue when all
+ * corePoolSize threads are busy. Thus, no more than corePoolSize
+ * threads will ever be created. (And the value of the maximumPoolSize
+ * therefore doesn't have any effect.)  This may be appropriate when
+ * each task is completely independent of others, so tasks cannot
+ * affect each others execution; for example, in a web page server.
+ * While this style of queuing can be useful in smoothing out
+ * transient bursts of requests, it admits the possibility of
+ * unbounded work queue growth when commands continue to arrive on
+ * average faster than they can be processed.
+ *
+ * <li><em>Bounded queues.</em> A bounded queue (for example, an
+ * {@link ArrayBlockingQueue}) helps prevent resource exhaustion when
+ * used with finite maximumPoolSizes, but can be more difficult to
+ * tune and control.  Queue sizes and maximum pool sizes may be traded
+ * off for each other: Using large queues and small pools minimizes
+ * CPU usage, OS resources, and context-switching overhead, but can
+ * lead to artificially low throughput.  If tasks frequently block (for
+ * example if they are I/O bound), a system may be able to schedule
+ * time for more threads than you otherwise allow. Use of small queues
+ * generally requires larger pool sizes, which keeps CPUs busier but
+ * may encounter unacceptable scheduling overhead, which also
+ * decreases throughput.
+ *
+ * </ol>
+ *
+ * </dd>
+ *
+ * <dt>Rejected tasks</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * New tasks submitted in method {@link #execute(Runnable)} will be
+ * <em>rejected</em> when the Executor has been shut down, and also when
+ * the Executor uses finite bounds for both maximum threads and work queue
+ * capacity, and is saturated.  In either case, the {@code execute} method
+ * invokes the {@link
+ * RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)}
+ * method of its {@link RejectedExecutionHandler}.  Four predefined handler
+ * policies are provided:
+ *
+ * <ol>
+ *
+ * <li>In the default {@link ThreadPoolExecutor.AbortPolicy}, the
+ * handler throws a runtime {@link RejectedExecutionException} upon
+ * rejection.
+ *
+ * <li>In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
+ * that invokes {@code execute} itself runs the task. This provides a
+ * simple feedback control mechanism that will slow down the rate that
+ * new tasks are submitted.
+ *
+ * <li>In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
+ * cannot be executed is simply dropped.
+ *
+ * <li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
+ * executor is not shut down, the task at the head of the work queue
+ * is dropped, and then execution is retried (which can fail again,
+ * causing this to be repeated.)
+ *
+ * </ol>
+ *
+ * It is possible to define and use other kinds of {@link
+ * RejectedExecutionHandler} classes. Doing so requires some care
+ * especially when policies are designed to work only under particular
+ * capacity or queuing policies. </dd>
+ *
+ * <dt>Hook methods</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * This class provides {@code protected} overridable
+ * {@link #beforeExecute(Thread, Runnable)} and
+ * {@link #afterExecute(Runnable, Throwable)} methods that are called
+ * before and after execution of each task.  These can be used to
+ * manipulate the execution environment; for example, reinitializing
+ * ThreadLocals, gathering statistics, or adding log entries.
+ * Additionally, method {@link #terminated} can be overridden to perform
+ * any special processing that needs to be done once the Executor has
+ * fully terminated.
+ *
+ * <p>If hook, callback, or BlockingQueue methods throw exceptions,
+ * internal worker threads may in turn fail, abruptly terminate, and
+ * possibly be replaced.</dd>
+ *
+ * <dt>Queue maintenance</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * Method {@link #getQueue()} allows access to the work queue
+ * for purposes of monitoring and debugging.  Use of this method for
+ * any other purpose is strongly discouraged.  Two supplied methods,
+ * {@link #remove(Runnable)} and {@link #purge} are available to
+ * assist in storage reclamation when large numbers of queued tasks
+ * become cancelled.</dd>
+ *
+ * <dt>Finalization</dt>
+ *
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * A pool that is no longer referenced in a program <em>AND</em>
+ * has no remaining threads will be {@code shutdown} automatically. If
+ * you would like to ensure that unreferenced pools are reclaimed even
+ * if users forget to call {@link #shutdown}, then you must arrange
+ * that unused threads eventually die, by setting appropriate
+ * keep-alive times, using a lower bound of zero core threads and/or
+ * setting {@link #allowCoreThreadTimeOut(boolean)}.  </dd>
+ *
+ * </dl>
+ *
+ * <p><b>Extension example</b>. Most extensions of this class
+ * override one or more of the protected hook methods. For example,
+ * here is a subclass that adds a simple pause/resume feature:
+ *
+ * <pre> {@code
+ * class PausableThreadPoolExecutor extends ThreadPoolExecutor {
+ *   private boolean isPaused;
+ *   private ReentrantLock pauseLock = new ReentrantLock();
+ *   private Condition unpaused = pauseLock.newCondition();
+ *
+ *   public PausableThreadPoolExecutor(...) { super(...); }
+ *
+ *   protected void beforeExecute(Thread t, Runnable r) {
+ *     super.beforeExecute(t, r);
+ *     pauseLock.lock();
+ *     try {
+ *       while (isPaused) unpaused.await();
+ *     } catch (InterruptedException ie) {
+ *       t.interrupt();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void pause() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = true;
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ *
+ *   public void resume() {
+ *     pauseLock.lock();
+ *     try {
+ *       isPaused = false;
+ *       unpaused.signalAll();
+ *     } finally {
+ *       pauseLock.unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ThreadPoolExecutor extends AbstractExecutorService {
+    /**
+     * The main pool control state, ctl, is an atomic integer packing
+     * two conceptual fields
+     *   workerCount, indicating the effective number of threads
+     *   runState,    indicating whether running, shutting down etc
+     *
+     * In order to pack them into one int, we limit workerCount to
+     * (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
+     * billion) otherwise representable. If this is ever an issue in
+     * the future, the variable can be changed to be an AtomicLong,
+     * and the shift/mask constants below adjusted. But until the need
+     * arises, this code is a bit faster and simpler using an int.
+     *
+     * The workerCount is the number of workers that have been
+     * permitted to start and not permitted to stop.  The value may be
+     * transiently different from the actual number of live threads,
+     * for example when a ThreadFactory fails to create a thread when
+     * asked, and when exiting threads are still performing
+     * bookkeeping before terminating. The user-visible pool size is
+     * reported as the current size of the workers set.
+     *
+     * The runState provides the main lifecycle control, taking on values:
+     *
+     *   RUNNING:  Accept new tasks and process queued tasks
+     *   SHUTDOWN: Don't accept new tasks, but process queued tasks
+     *   STOP:     Don't accept new tasks, don't process queued tasks,
+     *             and interrupt in-progress tasks
+     *   TIDYING:  All tasks have terminated, workerCount is zero,
+     *             the thread transitioning to state TIDYING
+     *             will run the terminated() hook method
+     *   TERMINATED: terminated() has completed
+     *
+     * The numerical order among these values matters, to allow
+     * ordered comparisons. The runState monotonically increases over
+     * time, but need not hit each state. The transitions are:
+     *
+     * RUNNING -> SHUTDOWN
+     *    On invocation of shutdown(), perhaps implicitly in finalize()
+     * (RUNNING or SHUTDOWN) -> STOP
+     *    On invocation of shutdownNow()
+     * SHUTDOWN -> TIDYING
+     *    When both queue and pool are empty
+     * STOP -> TIDYING
+     *    When pool is empty
+     * TIDYING -> TERMINATED
+     *    When the terminated() hook method has completed
+     *
+     * Threads waiting in awaitTermination() will return when the
+     * state reaches TERMINATED.
+     *
+     * Detecting the transition from SHUTDOWN to TIDYING is less
+     * straightforward than you'd like because the queue may become
+     * empty after non-empty and vice versa during SHUTDOWN state, but
+     * we can only terminate if, after seeing that it is empty, we see
+     * that workerCount is 0 (which sometimes entails a recheck -- see
+     * below).
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
+    private static final int COUNT_BITS = Integer.SIZE - 3;
+    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
+
+    // runState is stored in the high-order bits
+    private static final int RUNNING    = -1 << COUNT_BITS;
+    private static final int SHUTDOWN   =  0 << COUNT_BITS;
+    private static final int STOP       =  1 << COUNT_BITS;
+    private static final int TIDYING    =  2 << COUNT_BITS;
+    private static final int TERMINATED =  3 << COUNT_BITS;
+
+    // Packing and unpacking ctl
+    private static int runStateOf(int c)     { return c & ~CAPACITY; }
+    private static int workerCountOf(int c)  { return c & CAPACITY; }
+    private static int ctlOf(int rs, int wc) { return rs | wc; }
+
+    /*
+     * Bit field accessors that don't require unpacking ctl.
+     * These depend on the bit layout and on workerCount being never negative.
+     */
+
+    private static boolean runStateLessThan(int c, int s) {
+        return c < s;
+    }
+
+    private static boolean runStateAtLeast(int c, int s) {
+        return c >= s;
+    }
+
+    private static boolean isRunning(int c) {
+        return c < SHUTDOWN;
+    }
+
+    /**
+     * Attempts to CAS-increment the workerCount field of ctl.
+     */
+    private boolean compareAndIncrementWorkerCount(int expect) {
+        return ctl.compareAndSet(expect, expect + 1);
+    }
+
+    /**
+     * Attempts to CAS-decrement the workerCount field of ctl.
+     */
+    private boolean compareAndDecrementWorkerCount(int expect) {
+        return ctl.compareAndSet(expect, expect - 1);
+    }
+
+    /**
+     * Decrements the workerCount field of ctl. This is called only on
+     * abrupt termination of a thread (see processWorkerExit). Other
+     * decrements are performed within getTask.
+     */
+    private void decrementWorkerCount() {
+        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+    }
+
+    /**
+     * The queue used for holding tasks and handing off to worker
+     * threads.  We do not require that workQueue.poll() returning
+     * null necessarily means that workQueue.isEmpty(), so rely
+     * solely on isEmpty to see if the queue is empty (which we must
+     * do for example when deciding whether to transition from
+     * SHUTDOWN to TIDYING).  This accommodates special-purpose
+     * queues such as DelayQueues for which poll() is allowed to
+     * return null even if it may later return non-null when delays
+     * expire.
+     */
+    private final BlockingQueue<Runnable> workQueue;
+
+    /**
+     * Lock held on access to workers set and related bookkeeping.
+     * While we could use a concurrent set of some sort, it turns out
+     * to be generally preferable to use a lock. Among the reasons is
+     * that this serializes interruptIdleWorkers, which avoids
+     * unnecessary interrupt storms, especially during shutdown.
+     * Otherwise exiting threads would concurrently interrupt those
+     * that have not yet interrupted. It also simplifies some of the
+     * associated statistics bookkeeping of largestPoolSize etc. We
+     * also hold mainLock on shutdown and shutdownNow, for the sake of
+     * ensuring workers set is stable while separately checking
+     * permission to interrupt and actually interrupting.
+     */
+    private final ReentrantLock mainLock = new ReentrantLock();
+
+    /**
+     * Set containing all worker threads in pool. Accessed only when
+     * holding mainLock.
+     */
+    // Android-added: @ReachabilitySensitive
+    @ReachabilitySensitive
+    private final HashSet<Worker> workers = new HashSet<>();
+
+    /**
+     * Wait condition to support awaitTermination.
+     */
+    private final Condition termination = mainLock.newCondition();
+
+    /**
+     * Tracks largest attained pool size. Accessed only under
+     * mainLock.
+     */
+    private int largestPoolSize;
+
+    /**
+     * Counter for completed tasks. Updated only on termination of
+     * worker threads. Accessed only under mainLock.
+     */
+    private long completedTaskCount;
+
+    /*
+     * All user control parameters are declared as volatiles so that
+     * ongoing actions are based on freshest values, but without need
+     * for locking, since no internal invariants depend on them
+     * changing synchronously with respect to other actions.
+     */
+
+    /**
+     * Factory for new threads. All threads are created using this
+     * factory (via method addWorker).  All callers must be prepared
+     * for addWorker to fail, which may reflect a system or user's
+     * policy limiting the number of threads.  Even though it is not
+     * treated as an error, failure to create threads may result in
+     * new tasks being rejected or existing ones remaining stuck in
+     * the queue.
+     *
+     * We go further and preserve pool invariants even in the face of
+     * errors such as OutOfMemoryError, that might be thrown while
+     * trying to create threads.  Such errors are rather common due to
+     * the need to allocate a native stack in Thread.start, and users
+     * will want to perform clean pool shutdown to clean up.  There
+     * will likely be enough memory available for the cleanup code to
+     * complete without encountering yet another OutOfMemoryError.
+     */
+    private volatile ThreadFactory threadFactory;
+
+    /**
+     * Handler called when saturated or shutdown in execute.
+     */
+    private volatile RejectedExecutionHandler handler;
+
+    /**
+     * Timeout in nanoseconds for idle threads waiting for work.
+     * Threads use this timeout when there are more than corePoolSize
+     * present or if allowCoreThreadTimeOut. Otherwise they wait
+     * forever for new work.
+     */
+    private volatile long keepAliveTime;
+
+    /**
+     * If false (default), core threads stay alive even when idle.
+     * If true, core threads use keepAliveTime to time out waiting
+     * for work.
+     */
+    private volatile boolean allowCoreThreadTimeOut;
+
+    /**
+     * Core pool size is the minimum number of workers to keep alive
+     * (and not allow to time out etc) unless allowCoreThreadTimeOut
+     * is set, in which case the minimum is zero.
+     */
+    private volatile int corePoolSize;
+
+    /**
+     * Maximum pool size. Note that the actual maximum is internally
+     * bounded by CAPACITY.
+     */
+    private volatile int maximumPoolSize;
+
+    /**
+     * The default rejected execution handler.
+     */
+    private static final RejectedExecutionHandler defaultHandler =
+        new AbortPolicy();
+
+    /**
+     * Permission required for callers of shutdown and shutdownNow.
+     * We additionally require (see checkShutdownAccess) that callers
+     * have permission to actually interrupt threads in the worker set
+     * (as governed by Thread.interrupt, which relies on
+     * ThreadGroup.checkAccess, which in turn relies on
+     * SecurityManager.checkAccess). Shutdowns are attempted only if
+     * these checks pass.
+     *
+     * All actual invocations of Thread.interrupt (see
+     * interruptIdleWorkers and interruptWorkers) ignore
+     * SecurityExceptions, meaning that the attempted interrupts
+     * silently fail. In the case of shutdown, they should not fail
+     * unless the SecurityManager has inconsistent policies, sometimes
+     * allowing access to a thread and sometimes not. In such cases,
+     * failure to actually interrupt threads may disable or delay full
+     * termination. Other uses of interruptIdleWorkers are advisory,
+     * and failure to actually interrupt will merely delay response to
+     * configuration changes so is not handled exceptionally.
+     */
+    private static final RuntimePermission shutdownPerm =
+        new RuntimePermission("modifyThread");
+
+    /**
+     * Class Worker mainly maintains interrupt control state for
+     * threads running tasks, along with other minor bookkeeping.
+     * This class opportunistically extends AbstractQueuedSynchronizer
+     * to simplify acquiring and releasing a lock surrounding each
+     * task execution.  This protects against interrupts that are
+     * intended to wake up a worker thread waiting for a task from
+     * instead interrupting a task being run.  We implement a simple
+     * non-reentrant mutual exclusion lock rather than use
+     * ReentrantLock because we do not want worker tasks to be able to
+     * reacquire the lock when they invoke pool control methods like
+     * setCorePoolSize.  Additionally, to suppress interrupts until
+     * the thread actually starts running tasks, we initialize lock
+     * state to a negative value, and clear it upon start (in
+     * runWorker).
+     */
+    private final class Worker
+        extends AbstractQueuedSynchronizer
+        implements Runnable
+    {
+        /**
+         * This class will never be serialized, but we provide a
+         * serialVersionUID to suppress a javac warning.
+         */
+        private static final long serialVersionUID = 6138294804551838833L;
+
+        /** Thread this worker is running in.  Null if factory fails. */
+        final Thread thread;
+        /** Initial task to run.  Possibly null. */
+        Runnable firstTask;
+        /** Per-thread task counter */
+        volatile long completedTasks;
+
+        /**
+         * Creates with given first task and thread from ThreadFactory.
+         * @param firstTask the first task (null if none)
+         */
+        Worker(Runnable firstTask) {
+            setState(-1); // inhibit interrupts until runWorker
+            this.firstTask = firstTask;
+            this.thread = getThreadFactory().newThread(this);
+        }
+
+        /** Delegates main run loop to outer runWorker. */
+        public void run() {
+            runWorker(this);
+        }
+
+        // Lock methods
+        //
+        // The value 0 represents the unlocked state.
+        // The value 1 represents the locked state.
+
+        protected boolean isHeldExclusively() {
+            return getState() != 0;
+        }
+
+        protected boolean tryAcquire(int unused) {
+            if (compareAndSetState(0, 1)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
+        }
+
+        protected boolean tryRelease(int unused) {
+            setExclusiveOwnerThread(null);
+            setState(0);
+            return true;
+        }
+
+        public void lock()        { acquire(1); }
+        public boolean tryLock()  { return tryAcquire(1); }
+        public void unlock()      { release(1); }
+        public boolean isLocked() { return isHeldExclusively(); }
+
+        void interruptIfStarted() {
+            Thread t;
+            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
+                try {
+                    t.interrupt();
+                } catch (SecurityException ignore) {
+                }
+            }
+        }
+    }
+
+    /*
+     * Methods for setting control state
+     */
+
+    /**
+     * Transitions runState to given target, or leaves it alone if
+     * already at least the given target.
+     *
+     * @param targetState the desired state, either SHUTDOWN or STOP
+     *        (but not TIDYING or TERMINATED -- use tryTerminate for that)
+     */
+    private void advanceRunState(int targetState) {
+        // assert targetState == SHUTDOWN || targetState == STOP;
+        for (;;) {
+            int c = ctl.get();
+            if (runStateAtLeast(c, targetState) ||
+                ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
+                break;
+        }
+    }
+
+    /**
+     * Transitions to TERMINATED state if either (SHUTDOWN and pool
+     * and queue empty) or (STOP and pool empty).  If otherwise
+     * eligible to terminate but workerCount is nonzero, interrupts an
+     * idle worker to ensure that shutdown signals propagate. This
+     * method must be called following any action that might make
+     * termination possible -- reducing worker count or removing tasks
+     * from the queue during shutdown. The method is non-private to
+     * allow access from ScheduledThreadPoolExecutor.
+     */
+    final void tryTerminate() {
+        for (;;) {
+            int c = ctl.get();
+            if (isRunning(c) ||
+                runStateAtLeast(c, TIDYING) ||
+                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+                return;
+            if (workerCountOf(c) != 0) { // Eligible to terminate
+                interruptIdleWorkers(ONLY_ONE);
+                return;
+            }
+
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
+                    try {
+                        terminated();
+                    } finally {
+                        ctl.set(ctlOf(TERMINATED, 0));
+                        termination.signalAll();
+                    }
+                    return;
+                }
+            } finally {
+                mainLock.unlock();
+            }
+            // else retry on failed CAS
+        }
+    }
+
+    /*
+     * Methods for controlling interrupts to worker threads.
+     */
+
+    /**
+     * If there is a security manager, makes sure caller has
+     * permission to shut down threads in general (see shutdownPerm).
+     * If this passes, additionally makes sure the caller is allowed
+     * to interrupt each worker thread. This might not be true even if
+     * first check passed, if the SecurityManager treats some threads
+     * specially.
+     */
+    private void checkShutdownAccess() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null) {
+            security.checkPermission(shutdownPerm);
+            final ReentrantLock mainLock = this.mainLock;
+            mainLock.lock();
+            try {
+                for (Worker w : workers)
+                    security.checkAccess(w.thread);
+            } finally {
+                mainLock.unlock();
+            }
+        }
+    }
+
+    /**
+     * Interrupts all threads, even if active. Ignores SecurityExceptions
+     * (in which case some threads may remain uninterrupted).
+     */
+    private void interruptWorkers() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers)
+                w.interruptIfStarted();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Interrupts threads that might be waiting for tasks (as
+     * indicated by not being locked) so they can check for
+     * termination or configuration changes. Ignores
+     * SecurityExceptions (in which case some threads may remain
+     * uninterrupted).
+     *
+     * @param onlyOne If true, interrupt at most one worker. This is
+     * called only from tryTerminate when termination is otherwise
+     * enabled but there are still other workers.  In this case, at
+     * most one waiting worker is interrupted to propagate shutdown
+     * signals in case all threads are currently waiting.
+     * Interrupting any arbitrary thread ensures that newly arriving
+     * workers since shutdown began will also eventually exit.
+     * To guarantee eventual termination, it suffices to always
+     * interrupt only one idle worker, but shutdown() interrupts all
+     * idle workers so that redundant workers exit promptly, not
+     * waiting for a straggler task to finish.
+     */
+    private void interruptIdleWorkers(boolean onlyOne) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            for (Worker w : workers) {
+                Thread t = w.thread;
+                if (!t.isInterrupted() && w.tryLock()) {
+                    try {
+                        t.interrupt();
+                    } catch (SecurityException ignore) {
+                    } finally {
+                        w.unlock();
+                    }
+                }
+                if (onlyOne)
+                    break;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Common form of interruptIdleWorkers, to avoid having to
+     * remember what the boolean argument means.
+     */
+    private void interruptIdleWorkers() {
+        interruptIdleWorkers(false);
+    }
+
+    private static final boolean ONLY_ONE = true;
+
+    /*
+     * Misc utilities, most of which are also exported to
+     * ScheduledThreadPoolExecutor
+     */
+
+    /**
+     * Invokes the rejected execution handler for the given command.
+     * Package-protected for use by ScheduledThreadPoolExecutor.
+     */
+    final void reject(Runnable command) {
+        handler.rejectedExecution(command, this);
+    }
+
+    /**
+     * Performs any further cleanup following run state transition on
+     * invocation of shutdown.  A no-op here, but used by
+     * ScheduledThreadPoolExecutor to cancel delayed tasks.
+     */
+    void onShutdown() {
+    }
+
+    /**
+     * State check needed by ScheduledThreadPoolExecutor to
+     * enable running tasks during shutdown.
+     *
+     * @param shutdownOK true if should return true if SHUTDOWN
+     */
+    final boolean isRunningOrShutdown(boolean shutdownOK) {
+        int rs = runStateOf(ctl.get());
+        return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
+    }
+
+    /**
+     * Drains the task queue into a new list, normally using
+     * drainTo. But if the queue is a DelayQueue or any other kind of
+     * queue for which poll or drainTo may fail to remove some
+     * elements, it deletes them one by one.
+     */
+    private List<Runnable> drainQueue() {
+        BlockingQueue<Runnable> q = workQueue;
+        ArrayList<Runnable> taskList = new ArrayList<>();
+        q.drainTo(taskList);
+        if (!q.isEmpty()) {
+            for (Runnable r : q.toArray(new Runnable[0])) {
+                if (q.remove(r))
+                    taskList.add(r);
+            }
+        }
+        return taskList;
+    }
+
+    /*
+     * Methods for creating, running and cleaning up after workers
+     */
+
+    /**
+     * Checks if a new worker can be added with respect to current
+     * pool state and the given bound (either core or maximum). If so,
+     * the worker count is adjusted accordingly, and, if possible, a
+     * new worker is created and started, running firstTask as its
+     * first task. This method returns false if the pool is stopped or
+     * eligible to shut down. It also returns false if the thread
+     * factory fails to create a thread when asked.  If the thread
+     * creation fails, either due to the thread factory returning
+     * null, or due to an exception (typically OutOfMemoryError in
+     * Thread.start()), we roll back cleanly.
+     *
+     * @param firstTask the task the new thread should run first (or
+     * null if none). Workers are created with an initial first task
+     * (in method execute()) to bypass queuing when there are fewer
+     * than corePoolSize threads (in which case we always start one),
+     * or when the queue is full (in which case we must bypass queue).
+     * Initially idle threads are usually created via
+     * prestartCoreThread or to replace other dying workers.
+     *
+     * @param core if true use corePoolSize as bound, else
+     * maximumPoolSize. (A boolean indicator is used here rather than a
+     * value to ensure reads of fresh values after checking other pool
+     * state).
+     * @return true if successful
+     */
+    private boolean addWorker(Runnable firstTask, boolean core) {
+        retry:
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN &&
+                ! (rs == SHUTDOWN &&
+                   firstTask == null &&
+                   ! workQueue.isEmpty()))
+                return false;
+
+            for (;;) {
+                int wc = workerCountOf(c);
+                if (wc >= CAPACITY ||
+                    wc >= (core ? corePoolSize : maximumPoolSize))
+                    return false;
+                if (compareAndIncrementWorkerCount(c))
+                    break retry;
+                c = ctl.get();  // Re-read ctl
+                if (runStateOf(c) != rs)
+                    continue retry;
+                // else CAS failed due to workerCount change; retry inner loop
+            }
+        }
+
+        boolean workerStarted = false;
+        boolean workerAdded = false;
+        Worker w = null;
+        try {
+            w = new Worker(firstTask);
+            final Thread t = w.thread;
+            if (t != null) {
+                final ReentrantLock mainLock = this.mainLock;
+                mainLock.lock();
+                try {
+                    // Recheck while holding lock.
+                    // Back out on ThreadFactory failure or if
+                    // shut down before lock acquired.
+                    int rs = runStateOf(ctl.get());
+
+                    if (rs < SHUTDOWN ||
+                        (rs == SHUTDOWN && firstTask == null)) {
+                        if (t.isAlive()) // precheck that t is startable
+                            throw new IllegalThreadStateException();
+                        workers.add(w);
+                        int s = workers.size();
+                        if (s > largestPoolSize)
+                            largestPoolSize = s;
+                        workerAdded = true;
+                    }
+                } finally {
+                    mainLock.unlock();
+                }
+                if (workerAdded) {
+                    t.start();
+                    workerStarted = true;
+                }
+            }
+        } finally {
+            if (! workerStarted)
+                addWorkerFailed(w);
+        }
+        return workerStarted;
+    }
+
+    /**
+     * Rolls back the worker thread creation.
+     * - removes worker from workers, if present
+     * - decrements worker count
+     * - rechecks for termination, in case the existence of this
+     *   worker was holding up termination
+     */
+    private void addWorkerFailed(Worker w) {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            if (w != null)
+                workers.remove(w);
+            decrementWorkerCount();
+            tryTerminate();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Performs cleanup and bookkeeping for a dying worker. Called
+     * only from worker threads. Unless completedAbruptly is set,
+     * assumes that workerCount has already been adjusted to account
+     * for exit.  This method removes thread from worker set, and
+     * possibly terminates the pool or replaces the worker if either
+     * it exited due to user task exception or if fewer than
+     * corePoolSize workers are running or queue is non-empty but
+     * there are no workers.
+     *
+     * @param w the worker
+     * @param completedAbruptly if the worker died due to user exception
+     */
+    private void processWorkerExit(Worker w, boolean completedAbruptly) {
+        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
+            decrementWorkerCount();
+
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            completedTaskCount += w.completedTasks;
+            workers.remove(w);
+        } finally {
+            mainLock.unlock();
+        }
+
+        tryTerminate();
+
+        int c = ctl.get();
+        if (runStateLessThan(c, STOP)) {
+            if (!completedAbruptly) {
+                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
+                if (min == 0 && ! workQueue.isEmpty())
+                    min = 1;
+                if (workerCountOf(c) >= min)
+                    return; // replacement not needed
+            }
+            addWorker(null, false);
+        }
+    }
+
+    /**
+     * Performs blocking or timed wait for a task, depending on
+     * current configuration settings, or returns null if this worker
+     * must exit because of any of:
+     * 1. There are more than maximumPoolSize workers (due to
+     *    a call to setMaximumPoolSize).
+     * 2. The pool is stopped.
+     * 3. The pool is shutdown and the queue is empty.
+     * 4. This worker timed out waiting for a task, and timed-out
+     *    workers are subject to termination (that is,
+     *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
+     *    both before and after the timed wait, and if the queue is
+     *    non-empty, this worker is not the last thread in the pool.
+     *
+     * @return task, or null if the worker must exit, in which case
+     *         workerCount is decremented
+     */
+    private Runnable getTask() {
+        boolean timedOut = false; // Did the last poll() time out?
+
+        for (;;) {
+            int c = ctl.get();
+            int rs = runStateOf(c);
+
+            // Check if queue empty only if necessary.
+            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+                decrementWorkerCount();
+                return null;
+            }
+
+            int wc = workerCountOf(c);
+
+            // Are workers subject to culling?
+            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
+
+            if ((wc > maximumPoolSize || (timed && timedOut))
+                && (wc > 1 || workQueue.isEmpty())) {
+                if (compareAndDecrementWorkerCount(c))
+                    return null;
+                continue;
+            }
+
+            try {
+                Runnable r = timed ?
+                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
+                    workQueue.take();
+                if (r != null)
+                    return r;
+                timedOut = true;
+            } catch (InterruptedException retry) {
+                timedOut = false;
+            }
+        }
+    }
+
+    /**
+     * Main worker run loop.  Repeatedly gets tasks from queue and
+     * executes them, while coping with a number of issues:
+     *
+     * 1. We may start out with an initial task, in which case we
+     * don't need to get the first one. Otherwise, as long as pool is
+     * running, we get tasks from getTask. If it returns null then the
+     * worker exits due to changed pool state or configuration
+     * parameters.  Other exits result from exception throws in
+     * external code, in which case completedAbruptly holds, which
+     * usually leads processWorkerExit to replace this thread.
+     *
+     * 2. Before running any task, the lock is acquired to prevent
+     * other pool interrupts while the task is executing, and then we
+     * ensure that unless pool is stopping, this thread does not have
+     * its interrupt set.
+     *
+     * 3. Each task run is preceded by a call to beforeExecute, which
+     * might throw an exception, in which case we cause thread to die
+     * (breaking loop with completedAbruptly true) without processing
+     * the task.
+     *
+     * 4. Assuming beforeExecute completes normally, we run the task,
+     * gathering any of its thrown exceptions to send to afterExecute.
+     * We separately handle RuntimeException, Error (both of which the
+     * specs guarantee that we trap) and arbitrary Throwables.
+     * Because we cannot rethrow Throwables within Runnable.run, we
+     * wrap them within Errors on the way out (to the thread's
+     * UncaughtExceptionHandler).  Any thrown exception also
+     * conservatively causes thread to die.
+     *
+     * 5. After task.run completes, we call afterExecute, which may
+     * also throw an exception, which will also cause thread to
+     * die. According to JLS Sec 14.20, this exception is the one that
+     * will be in effect even if task.run throws.
+     *
+     * The net effect of the exception mechanics is that afterExecute
+     * and the thread's UncaughtExceptionHandler have as accurate
+     * information as we can provide about any problems encountered by
+     * user code.
+     *
+     * @param w the worker
+     */
+    final void runWorker(Worker w) {
+        Thread wt = Thread.currentThread();
+        Runnable task = w.firstTask;
+        w.firstTask = null;
+        w.unlock(); // allow interrupts
+        boolean completedAbruptly = true;
+        try {
+            while (task != null || (task = getTask()) != null) {
+                w.lock();
+                // If pool is stopping, ensure thread is interrupted;
+                // if not, ensure thread is not interrupted.  This
+                // requires a recheck in second case to deal with
+                // shutdownNow race while clearing interrupt
+                if ((runStateAtLeast(ctl.get(), STOP) ||
+                     (Thread.interrupted() &&
+                      runStateAtLeast(ctl.get(), STOP))) &&
+                    !wt.isInterrupted())
+                    wt.interrupt();
+                try {
+                    beforeExecute(wt, task);
+                    Throwable thrown = null;
+                    try {
+                        task.run();
+                    } catch (RuntimeException x) {
+                        thrown = x; throw x;
+                    } catch (Error x) {
+                        thrown = x; throw x;
+                    } catch (Throwable x) {
+                        thrown = x; throw new Error(x);
+                    } finally {
+                        afterExecute(task, thrown);
+                    }
+                } finally {
+                    task = null;
+                    w.completedTasks++;
+                    w.unlock();
+                }
+            }
+            completedAbruptly = false;
+        } finally {
+            processWorkerExit(w, completedAbruptly);
+        }
+    }
+
+    // Public constructors and methods
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and default thread factory and rejected execution handler.
+     * It may be more convenient to use one of the {@link Executors} factory
+     * methods instead of this general purpose constructor.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             Executors.defaultThreadFactory(), defaultHandler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and default rejected execution handler.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code threadFactory} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              ThreadFactory threadFactory) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             threadFactory, defaultHandler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters and default thread factory.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code handler} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              RejectedExecutionHandler handler) {
+        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
+             Executors.defaultThreadFactory(), handler);
+    }
+
+    /**
+     * Creates a new {@code ThreadPoolExecutor} with the given initial
+     * parameters.
+     *
+     * @param corePoolSize the number of threads to keep in the pool, even
+     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
+     * @param maximumPoolSize the maximum number of threads to allow in the
+     *        pool
+     * @param keepAliveTime when the number of threads is greater than
+     *        the core, this is the maximum time that excess idle threads
+     *        will wait for new tasks before terminating.
+     * @param unit the time unit for the {@code keepAliveTime} argument
+     * @param workQueue the queue to use for holding tasks before they are
+     *        executed.  This queue will hold only the {@code Runnable}
+     *        tasks submitted by the {@code execute} method.
+     * @param threadFactory the factory to use when the executor
+     *        creates a new thread
+     * @param handler the handler to use when execution is blocked
+     *        because the thread bounds and queue capacities are reached
+     * @throws IllegalArgumentException if one of the following holds:<br>
+     *         {@code corePoolSize < 0}<br>
+     *         {@code keepAliveTime < 0}<br>
+     *         {@code maximumPoolSize <= 0}<br>
+     *         {@code maximumPoolSize < corePoolSize}
+     * @throws NullPointerException if {@code workQueue}
+     *         or {@code threadFactory} or {@code handler} is null
+     */
+    public ThreadPoolExecutor(int corePoolSize,
+                              int maximumPoolSize,
+                              long keepAliveTime,
+                              TimeUnit unit,
+                              BlockingQueue<Runnable> workQueue,
+                              ThreadFactory threadFactory,
+                              RejectedExecutionHandler handler) {
+        if (corePoolSize < 0 ||
+            maximumPoolSize <= 0 ||
+            maximumPoolSize < corePoolSize ||
+            keepAliveTime < 0)
+            throw new IllegalArgumentException();
+        if (workQueue == null || threadFactory == null || handler == null)
+            throw new NullPointerException();
+        this.corePoolSize = corePoolSize;
+        this.maximumPoolSize = maximumPoolSize;
+        this.workQueue = workQueue;
+        this.keepAliveTime = unit.toNanos(keepAliveTime);
+        this.threadFactory = threadFactory;
+        this.handler = handler;
+    }
+
+    /**
+     * Executes the given task sometime in the future.  The task
+     * may execute in a new thread or in an existing pooled thread.
+     *
+     * If the task cannot be submitted for execution, either because this
+     * executor has been shutdown or because its capacity has been reached,
+     * the task is handled by the current {@code RejectedExecutionHandler}.
+     *
+     * @param command the task to execute
+     * @throws RejectedExecutionException at discretion of
+     *         {@code RejectedExecutionHandler}, if the task
+     *         cannot be accepted for execution
+     * @throws NullPointerException if {@code command} is null
+     */
+    public void execute(Runnable command) {
+        if (command == null)
+            throw new NullPointerException();
+        /*
+         * Proceed in 3 steps:
+         *
+         * 1. If fewer than corePoolSize threads are running, try to
+         * start a new thread with the given command as its first
+         * task.  The call to addWorker atomically checks runState and
+         * workerCount, and so prevents false alarms that would add
+         * threads when it shouldn't, by returning false.
+         *
+         * 2. If a task can be successfully queued, then we still need
+         * to double-check whether we should have added a thread
+         * (because existing ones died since last checking) or that
+         * the pool shut down since entry into this method. So we
+         * recheck state and if necessary roll back the enqueuing if
+         * stopped, or start a new thread if there are none.
+         *
+         * 3. If we cannot queue task, then we try to add a new
+         * thread.  If it fails, we know we are shut down or saturated
+         * and so reject the task.
+         */
+        int c = ctl.get();
+        if (workerCountOf(c) < corePoolSize) {
+            if (addWorker(command, true))
+                return;
+            c = ctl.get();
+        }
+        if (isRunning(c) && workQueue.offer(command)) {
+            int recheck = ctl.get();
+            if (! isRunning(recheck) && remove(command))
+                reject(command);
+            else if (workerCountOf(recheck) == 0)
+                addWorker(null, false);
+        }
+        else if (!addWorker(command, false))
+            reject(command);
+    }
+
+    /**
+     * Initiates an orderly shutdown in which previously submitted
+     * tasks are executed, but no new tasks will be accepted.
+     * Invocation has no additional effect if already shut down.
+     *
+     * <p>This method does not wait for previously submitted tasks to
+     * complete execution.  Use {@link #awaitTermination awaitTermination}
+     * to do that.
+     */
+    // android-note: Removed @throws SecurityException
+    public void shutdown() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            checkShutdownAccess();
+            advanceRunState(SHUTDOWN);
+            interruptIdleWorkers();
+            onShutdown(); // hook for ScheduledThreadPoolExecutor
+        } finally {
+            mainLock.unlock();
+        }
+        tryTerminate();
+    }
+
+    /**
+     * Attempts to stop all actively executing tasks, halts the
+     * processing of waiting tasks, and returns a list of the tasks
+     * that were awaiting execution. These tasks are drained (removed)
+     * from the task queue upon return from this method.
+     *
+     * <p>This method does not wait for actively executing tasks to
+     * terminate.  Use {@link #awaitTermination awaitTermination} to
+     * do that.
+     *
+     * <p>There are no guarantees beyond best-effort attempts to stop
+     * processing actively executing tasks.  This implementation
+     * interrupts tasks via {@link Thread#interrupt}; any task that
+     * fails to respond to interrupts may never terminate.
+     */
+    // android-note: Removed @throws SecurityException
+    public List<Runnable> shutdownNow() {
+        List<Runnable> tasks;
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            checkShutdownAccess();
+            advanceRunState(STOP);
+            interruptWorkers();
+            tasks = drainQueue();
+        } finally {
+            mainLock.unlock();
+        }
+        tryTerminate();
+        return tasks;
+    }
+
+    public boolean isShutdown() {
+        return ! isRunning(ctl.get());
+    }
+
+    /**
+     * Returns true if this executor is in the process of terminating
+     * after {@link #shutdown} or {@link #shutdownNow} but has not
+     * completely terminated.  This method may be useful for
+     * debugging. A return of {@code true} reported a sufficient
+     * period after shutdown may indicate that submitted tasks have
+     * ignored or suppressed interruption, causing this executor not
+     * to properly terminate.
+     *
+     * @return {@code true} if terminating but not yet terminated
+     */
+    public boolean isTerminating() {
+        int c = ctl.get();
+        return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+    }
+
+    public boolean isTerminated() {
+        return runStateAtLeast(ctl.get(), TERMINATED);
+    }
+
+    public boolean awaitTermination(long timeout, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(timeout);
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+                if (nanos <= 0L)
+                    return false;
+                nanos = termination.awaitNanos(nanos);
+            }
+            return true;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Invokes {@code shutdown} when this executor is no longer
+     * referenced and it has no threads.
+     */
+    protected void finalize() {
+        shutdown();
+    }
+
+    /**
+     * Sets the thread factory used to create new threads.
+     *
+     * @param threadFactory the new thread factory
+     * @throws NullPointerException if threadFactory is null
+     * @see #getThreadFactory
+     */
+    public void setThreadFactory(ThreadFactory threadFactory) {
+        if (threadFactory == null)
+            throw new NullPointerException();
+        this.threadFactory = threadFactory;
+    }
+
+    /**
+     * Returns the thread factory used to create new threads.
+     *
+     * @return the current thread factory
+     * @see #setThreadFactory(ThreadFactory)
+     */
+    public ThreadFactory getThreadFactory() {
+        return threadFactory;
+    }
+
+    /**
+     * Sets a new handler for unexecutable tasks.
+     *
+     * @param handler the new handler
+     * @throws NullPointerException if handler is null
+     * @see #getRejectedExecutionHandler
+     */
+    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
+        if (handler == null)
+            throw new NullPointerException();
+        this.handler = handler;
+    }
+
+    /**
+     * Returns the current handler for unexecutable tasks.
+     *
+     * @return the current handler
+     * @see #setRejectedExecutionHandler(RejectedExecutionHandler)
+     */
+    public RejectedExecutionHandler getRejectedExecutionHandler() {
+        return handler;
+    }
+
+    // Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+    /**
+     * Sets the core number of threads.  This overrides any value set
+     * in the constructor.  If the new value is smaller than the
+     * current value, excess existing threads will be terminated when
+     * they next become idle.  If larger, new threads will, if needed,
+     * be started to execute any queued tasks.
+     *
+     * @param corePoolSize the new core size
+     * @throws IllegalArgumentException if {@code corePoolSize < 0}
+     * @see #getCorePoolSize
+     */
+    public void setCorePoolSize(int corePoolSize) {
+        // BEGIN Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+        // This reverts a change that threw an IAE on that condition. This is due to defective code
+        // in a commonly used third party library that does something like exec.setCorePoolSize(N)
+        // before doing exec.setMaxPoolSize(N).
+        //
+        // if (corePoolSize < 0 || maximumPoolSize < corePoolSize)
+        if (corePoolSize < 0)
+        // END Android-changed: Tolerate maximumPoolSize >= corePoolSize during setCorePoolSize().
+            throw new IllegalArgumentException();
+        int delta = corePoolSize - this.corePoolSize;
+        this.corePoolSize = corePoolSize;
+        if (workerCountOf(ctl.get()) > corePoolSize)
+            interruptIdleWorkers();
+        else if (delta > 0) {
+            // We don't really know how many new threads are "needed".
+            // As a heuristic, prestart enough new workers (up to new
+            // core size) to handle the current number of tasks in
+            // queue, but stop if queue becomes empty while doing so.
+            int k = Math.min(delta, workQueue.size());
+            while (k-- > 0 && addWorker(null, true)) {
+                if (workQueue.isEmpty())
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Returns the core number of threads.
+     *
+     * @return the core number of threads
+     * @see #setCorePoolSize
+     */
+    public int getCorePoolSize() {
+        return corePoolSize;
+    }
+
+    /**
+     * Starts a core thread, causing it to idly wait for work. This
+     * overrides the default policy of starting core threads only when
+     * new tasks are executed. This method will return {@code false}
+     * if all core threads have already been started.
+     *
+     * @return {@code true} if a thread was started
+     */
+    public boolean prestartCoreThread() {
+        return workerCountOf(ctl.get()) < corePoolSize &&
+            addWorker(null, true);
+    }
+
+    /**
+     * Same as prestartCoreThread except arranges that at least one
+     * thread is started even if corePoolSize is 0.
+     */
+    void ensurePrestart() {
+        int wc = workerCountOf(ctl.get());
+        if (wc < corePoolSize)
+            addWorker(null, true);
+        else if (wc == 0)
+            addWorker(null, false);
+    }
+
+    /**
+     * Starts all core threads, causing them to idly wait for work. This
+     * overrides the default policy of starting core threads only when
+     * new tasks are executed.
+     *
+     * @return the number of threads started
+     */
+    public int prestartAllCoreThreads() {
+        int n = 0;
+        while (addWorker(null, true))
+            ++n;
+        return n;
+    }
+
+    /**
+     * Returns true if this pool allows core threads to time out and
+     * terminate if no tasks arrive within the keepAlive time, being
+     * replaced if needed when new tasks arrive. When true, the same
+     * keep-alive policy applying to non-core threads applies also to
+     * core threads. When false (the default), core threads are never
+     * terminated due to lack of incoming tasks.
+     *
+     * @return {@code true} if core threads are allowed to time out,
+     *         else {@code false}
+     *
+     * @since 1.6
+     */
+    public boolean allowsCoreThreadTimeOut() {
+        return allowCoreThreadTimeOut;
+    }
+
+    /**
+     * Sets the policy governing whether core threads may time out and
+     * terminate if no tasks arrive within the keep-alive time, being
+     * replaced if needed when new tasks arrive. When false, core
+     * threads are never terminated due to lack of incoming
+     * tasks. When true, the same keep-alive policy applying to
+     * non-core threads applies also to core threads. To avoid
+     * continual thread replacement, the keep-alive time must be
+     * greater than zero when setting {@code true}. This method
+     * should in general be called before the pool is actively used.
+     *
+     * @param value {@code true} if should time out, else {@code false}
+     * @throws IllegalArgumentException if value is {@code true}
+     *         and the current keep-alive time is not greater than zero
+     *
+     * @since 1.6
+     */
+    public void allowCoreThreadTimeOut(boolean value) {
+        if (value && keepAliveTime <= 0)
+            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+        if (value != allowCoreThreadTimeOut) {
+            allowCoreThreadTimeOut = value;
+            if (value)
+                interruptIdleWorkers();
+        }
+    }
+
+    /**
+     * Sets the maximum allowed number of threads. This overrides any
+     * value set in the constructor. If the new value is smaller than
+     * the current value, excess existing threads will be
+     * terminated when they next become idle.
+     *
+     * @param maximumPoolSize the new maximum
+     * @throws IllegalArgumentException if the new maximum is
+     *         less than or equal to zero, or
+     *         less than the {@linkplain #getCorePoolSize core pool size}
+     * @see #getMaximumPoolSize
+     */
+    public void setMaximumPoolSize(int maximumPoolSize) {
+        if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
+            throw new IllegalArgumentException();
+        this.maximumPoolSize = maximumPoolSize;
+        if (workerCountOf(ctl.get()) > maximumPoolSize)
+            interruptIdleWorkers();
+    }
+
+    /**
+     * Returns the maximum allowed number of threads.
+     *
+     * @return the maximum allowed number of threads
+     * @see #setMaximumPoolSize
+     */
+    public int getMaximumPoolSize() {
+        return maximumPoolSize;
+    }
+
+    /**
+     * Sets the thread keep-alive time, which is the amount of time
+     * that threads may remain idle before being terminated.
+     * Threads that wait this amount of time without processing a
+     * task will be terminated if there are more than the core
+     * number of threads currently in the pool, or if this pool
+     * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+     * This overrides any value set in the constructor.
+     *
+     * @param time the time to wait.  A time value of zero will cause
+     *        excess threads to terminate immediately after executing tasks.
+     * @param unit the time unit of the {@code time} argument
+     * @throws IllegalArgumentException if {@code time} less than zero or
+     *         if {@code time} is zero and {@code allowsCoreThreadTimeOut}
+     * @see #getKeepAliveTime(TimeUnit)
+     */
+    public void setKeepAliveTime(long time, TimeUnit unit) {
+        if (time < 0)
+            throw new IllegalArgumentException();
+        if (time == 0 && allowsCoreThreadTimeOut())
+            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
+        long keepAliveTime = unit.toNanos(time);
+        long delta = keepAliveTime - this.keepAliveTime;
+        this.keepAliveTime = keepAliveTime;
+        if (delta < 0)
+            interruptIdleWorkers();
+    }
+
+    /**
+     * Returns the thread keep-alive time, which is the amount of time
+     * that threads may remain idle before being terminated.
+     * Threads that wait this amount of time without processing a
+     * task will be terminated if there are more than the core
+     * number of threads currently in the pool, or if this pool
+     * {@linkplain #allowsCoreThreadTimeOut() allows core thread timeout}.
+     *
+     * @param unit the desired time unit of the result
+     * @return the time limit
+     * @see #setKeepAliveTime(long, TimeUnit)
+     */
+    public long getKeepAliveTime(TimeUnit unit) {
+        return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
+    }
+
+    /* User-level queue utilities */
+
+    /**
+     * Returns the task queue used by this executor. Access to the
+     * task queue is intended primarily for debugging and monitoring.
+     * This queue may be in active use.  Retrieving the task queue
+     * does not prevent queued tasks from executing.
+     *
+     * @return the task queue
+     */
+    public BlockingQueue<Runnable> getQueue() {
+        return workQueue;
+    }
+
+    /**
+     * Removes this task from the executor's internal queue if it is
+     * present, thus causing it not to be run if it has not already
+     * started.
+     *
+     * <p>This method may be useful as one part of a cancellation
+     * scheme.  It may fail to remove tasks that have been converted
+     * into other forms before being placed on the internal queue.
+     * For example, a task entered using {@code submit} might be
+     * converted into a form that maintains {@code Future} status.
+     * However, in such cases, method {@link #purge} may be used to
+     * remove those Futures that have been cancelled.
+     *
+     * @param task the task to remove
+     * @return {@code true} if the task was removed
+     */
+    public boolean remove(Runnable task) {
+        boolean removed = workQueue.remove(task);
+        tryTerminate(); // In case SHUTDOWN and now empty
+        return removed;
+    }
+
+    /**
+     * Tries to remove from the work queue all {@link Future}
+     * tasks that have been cancelled. This method can be useful as a
+     * storage reclamation operation, that has no other impact on
+     * functionality. Cancelled tasks are never executed, but may
+     * accumulate in work queues until worker threads can actively
+     * remove them. Invoking this method instead tries to remove them now.
+     * However, this method may fail to remove tasks in
+     * the presence of interference by other threads.
+     */
+    public void purge() {
+        final BlockingQueue<Runnable> q = workQueue;
+        try {
+            Iterator<Runnable> it = q.iterator();
+            while (it.hasNext()) {
+                Runnable r = it.next();
+                if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
+                    it.remove();
+            }
+        } catch (ConcurrentModificationException fallThrough) {
+            // Take slow path if we encounter interference during traversal.
+            // Make copy for traversal and call remove for cancelled entries.
+            // The slow path is more likely to be O(N*N).
+            for (Object r : q.toArray())
+                if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
+                    q.remove(r);
+        }
+
+        tryTerminate(); // In case SHUTDOWN and now empty
+    }
+
+    /* Statistics */
+
+    /**
+     * Returns the current number of threads in the pool.
+     *
+     * @return the number of threads
+     */
+    public int getPoolSize() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            // Remove rare and surprising possibility of
+            // isTerminated() && getPoolSize() > 0
+            return runStateAtLeast(ctl.get(), TIDYING) ? 0
+                : workers.size();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate number of threads that are actively
+     * executing tasks.
+     *
+     * @return the number of threads
+     */
+    public int getActiveCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            int n = 0;
+            for (Worker w : workers)
+                if (w.isLocked())
+                    ++n;
+            return n;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the largest number of threads that have ever
+     * simultaneously been in the pool.
+     *
+     * @return the number of threads
+     */
+    public int getLargestPoolSize() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            return largestPoolSize;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate total number of tasks that have ever been
+     * scheduled for execution. Because the states of tasks and
+     * threads may change dynamically during computation, the returned
+     * value is only an approximation.
+     *
+     * @return the number of tasks
+     */
+    public long getTaskCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            long n = completedTaskCount;
+            for (Worker w : workers) {
+                n += w.completedTasks;
+                if (w.isLocked())
+                    ++n;
+            }
+            return n + workQueue.size();
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns the approximate total number of tasks that have
+     * completed execution. Because the states of tasks and threads
+     * may change dynamically during computation, the returned value
+     * is only an approximation, but one that does not ever decrease
+     * across successive calls.
+     *
+     * @return the number of tasks
+     */
+    public long getCompletedTaskCount() {
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            long n = completedTaskCount;
+            for (Worker w : workers)
+                n += w.completedTasks;
+            return n;
+        } finally {
+            mainLock.unlock();
+        }
+    }
+
+    /**
+     * Returns a string identifying this pool, as well as its state,
+     * including indications of run state and estimated worker and
+     * task counts.
+     *
+     * @return a string identifying this pool, as well as its state
+     */
+    public String toString() {
+        long ncompleted;
+        int nworkers, nactive;
+        final ReentrantLock mainLock = this.mainLock;
+        mainLock.lock();
+        try {
+            ncompleted = completedTaskCount;
+            nactive = 0;
+            nworkers = workers.size();
+            for (Worker w : workers) {
+                ncompleted += w.completedTasks;
+                if (w.isLocked())
+                    ++nactive;
+            }
+        } finally {
+            mainLock.unlock();
+        }
+        int c = ctl.get();
+        String runState =
+            runStateLessThan(c, SHUTDOWN) ? "Running" :
+            runStateAtLeast(c, TERMINATED) ? "Terminated" :
+            "Shutting down";
+        return super.toString() +
+            "[" + runState +
+            ", pool size = " + nworkers +
+            ", active threads = " + nactive +
+            ", queued tasks = " + workQueue.size() +
+            ", completed tasks = " + ncompleted +
+            "]";
+    }
+
+    /* Extension hooks */
+
+    /**
+     * Method invoked prior to executing the given Runnable in the
+     * given thread.  This method is invoked by thread {@code t} that
+     * will execute task {@code r}, and may be used to re-initialize
+     * ThreadLocals, or to perform logging.
+     *
+     * <p>This implementation does nothing, but may be customized in
+     * subclasses. Note: To properly nest multiple overridings, subclasses
+     * should generally invoke {@code super.beforeExecute} at the end of
+     * this method.
+     *
+     * @param t the thread that will run task {@code r}
+     * @param r the task that will be executed
+     */
+    protected void beforeExecute(Thread t, Runnable r) { }
+
+    /**
+     * Method invoked upon completion of execution of the given Runnable.
+     * This method is invoked by the thread that executed the task. If
+     * non-null, the Throwable is the uncaught {@code RuntimeException}
+     * or {@code Error} that caused execution to terminate abruptly.
+     *
+     * <p>This implementation does nothing, but may be customized in
+     * subclasses. Note: To properly nest multiple overridings, subclasses
+     * should generally invoke {@code super.afterExecute} at the
+     * beginning of this method.
+     *
+     * <p><b>Note:</b> When actions are enclosed in tasks (such as
+     * {@link FutureTask}) either explicitly or via methods such as
+     * {@code submit}, these task objects catch and maintain
+     * computational exceptions, and so they do not cause abrupt
+     * termination, and the internal exceptions are <em>not</em>
+     * passed to this method. If you would like to trap both kinds of
+     * failures in this method, you can further probe for such cases,
+     * as in this sample subclass that prints either the direct cause
+     * or the underlying exception if a task has been aborted:
+     *
+     * <pre> {@code
+     * class ExtendedExecutor extends ThreadPoolExecutor {
+     *   // ...
+     *   protected void afterExecute(Runnable r, Throwable t) {
+     *     super.afterExecute(r, t);
+     *     if (t == null
+     *         && r instanceof Future<?>
+     *         && ((Future<?>)r).isDone()) {
+     *       try {
+     *         Object result = ((Future<?>) r).get();
+     *       } catch (CancellationException ce) {
+     *         t = ce;
+     *       } catch (ExecutionException ee) {
+     *         t = ee.getCause();
+     *       } catch (InterruptedException ie) {
+     *         // ignore/reset
+     *         Thread.currentThread().interrupt();
+     *       }
+     *     }
+     *     if (t != null)
+     *       System.out.println(t);
+     *   }
+     * }}</pre>
+     *
+     * @param r the runnable that has completed
+     * @param t the exception that caused termination, or null if
+     * execution completed normally
+     */
+    protected void afterExecute(Runnable r, Throwable t) { }
+
+    /**
+     * Method invoked when the Executor has terminated.  Default
+     * implementation does nothing. Note: To properly nest multiple
+     * overridings, subclasses should generally invoke
+     * {@code super.terminated} within this method.
+     */
+    protected void terminated() { }
+
+    /* Predefined RejectedExecutionHandlers */
+
+    /**
+     * A handler for rejected tasks that runs the rejected task
+     * directly in the calling thread of the {@code execute} method,
+     * unless the executor has been shut down, in which case the task
+     * is discarded.
+     */
+    public static class CallerRunsPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code CallerRunsPolicy}.
+         */
+        public CallerRunsPolicy() { }
+
+        /**
+         * Executes task r in the caller's thread, unless the executor
+         * has been shut down, in which case the task is discarded.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                r.run();
+            }
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that throws a
+     * {@code RejectedExecutionException}.
+     */
+    public static class AbortPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates an {@code AbortPolicy}.
+         */
+        public AbortPolicy() { }
+
+        /**
+         * Always throws RejectedExecutionException.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         * @throws RejectedExecutionException always
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            throw new RejectedExecutionException("Task " + r.toString() +
+                                                 " rejected from " +
+                                                 e.toString());
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that silently discards the
+     * rejected task.
+     */
+    public static class DiscardPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code DiscardPolicy}.
+         */
+        public DiscardPolicy() { }
+
+        /**
+         * Does nothing, which has the effect of discarding task r.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+        }
+    }
+
+    /**
+     * A handler for rejected tasks that discards the oldest unhandled
+     * request and then retries {@code execute}, unless the executor
+     * is shut down, in which case the task is discarded.
+     */
+    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
+        /**
+         * Creates a {@code DiscardOldestPolicy} for the given executor.
+         */
+        public DiscardOldestPolicy() { }
+
+        /**
+         * Obtains and ignores the next task that the executor
+         * would otherwise execute, if one is immediately available,
+         * and then retries execution of task r, unless the executor
+         * is shut down, in which case task r is instead discarded.
+         *
+         * @param r the runnable task requested to be executed
+         * @param e the executor attempting to execute this task
+         */
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                e.getQueue().poll();
+                e.execute(r);
+            }
+        }
+    }
+}
diff --git a/java/util/concurrent/TimeUnit.java b/java/util/concurrent/TimeUnit.java
new file mode 100644
index 0000000..44d7964
--- /dev/null
+++ b/java/util/concurrent/TimeUnit.java
@@ -0,0 +1,443 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+import java.util.Objects;
+
+/**
+ * A {@code TimeUnit} represents time durations at a given unit of
+ * granularity and provides utility methods to convert across units,
+ * and to perform timing and delay operations in these units.  A
+ * {@code TimeUnit} does not maintain time information, but only
+ * helps organize and use time representations that may be maintained
+ * separately across various contexts.  A nanosecond is defined as one
+ * thousandth of a microsecond, a microsecond as one thousandth of a
+ * millisecond, a millisecond as one thousandth of a second, a minute
+ * as sixty seconds, an hour as sixty minutes, and a day as twenty four
+ * hours.
+ *
+ * <p>A {@code TimeUnit} is mainly used to inform time-based methods
+ * how a given timing parameter should be interpreted. For example,
+ * the following code will timeout in 50 milliseconds if the {@link
+ * java.util.concurrent.locks.Lock lock} is not available:
+ *
+ * <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}</pre>
+ *
+ * while this code will timeout in 50 seconds:
+ * <pre> {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}</pre>
+ *
+ * Note however, that there is no guarantee that a particular timeout
+ * implementation will be able to notice the passage of time at the
+ * same granularity as the given {@code TimeUnit}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public enum TimeUnit {
+    /**
+     * Time unit representing one thousandth of a microsecond.
+     */
+    NANOSECONDS {
+        public long toNanos(long d)   { return d; }
+        public long toMicros(long d)  { return d/(C1/C0); }
+        public long toMillis(long d)  { return d/(C2/C0); }
+        public long toSeconds(long d) { return d/(C3/C0); }
+        public long toMinutes(long d) { return d/(C4/C0); }
+        public long toHours(long d)   { return d/(C5/C0); }
+        public long toDays(long d)    { return d/(C6/C0); }
+        public long convert(long d, TimeUnit u) { return u.toNanos(d); }
+        int excessNanos(long d, long m) { return (int)(d - (m*C2)); }
+    },
+
+    /**
+     * Time unit representing one thousandth of a millisecond.
+     */
+    MICROSECONDS {
+        public long toNanos(long d)   { return x(d, C1/C0, MAX/(C1/C0)); }
+        public long toMicros(long d)  { return d; }
+        public long toMillis(long d)  { return d/(C2/C1); }
+        public long toSeconds(long d) { return d/(C3/C1); }
+        public long toMinutes(long d) { return d/(C4/C1); }
+        public long toHours(long d)   { return d/(C5/C1); }
+        public long toDays(long d)    { return d/(C6/C1); }
+        public long convert(long d, TimeUnit u) { return u.toMicros(d); }
+        int excessNanos(long d, long m) { return (int)((d*C1) - (m*C2)); }
+    },
+
+    /**
+     * Time unit representing one thousandth of a second.
+     */
+    MILLISECONDS {
+        public long toNanos(long d)   { return x(d, C2/C0, MAX/(C2/C0)); }
+        public long toMicros(long d)  { return x(d, C2/C1, MAX/(C2/C1)); }
+        public long toMillis(long d)  { return d; }
+        public long toSeconds(long d) { return d/(C3/C2); }
+        public long toMinutes(long d) { return d/(C4/C2); }
+        public long toHours(long d)   { return d/(C5/C2); }
+        public long toDays(long d)    { return d/(C6/C2); }
+        public long convert(long d, TimeUnit u) { return u.toMillis(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing one second.
+     */
+    SECONDS {
+        public long toNanos(long d)   { return x(d, C3/C0, MAX/(C3/C0)); }
+        public long toMicros(long d)  { return x(d, C3/C1, MAX/(C3/C1)); }
+        public long toMillis(long d)  { return x(d, C3/C2, MAX/(C3/C2)); }
+        public long toSeconds(long d) { return d; }
+        public long toMinutes(long d) { return d/(C4/C3); }
+        public long toHours(long d)   { return d/(C5/C3); }
+        public long toDays(long d)    { return d/(C6/C3); }
+        public long convert(long d, TimeUnit u) { return u.toSeconds(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing sixty seconds.
+     * @since 1.6
+     */
+    MINUTES {
+        public long toNanos(long d)   { return x(d, C4/C0, MAX/(C4/C0)); }
+        public long toMicros(long d)  { return x(d, C4/C1, MAX/(C4/C1)); }
+        public long toMillis(long d)  { return x(d, C4/C2, MAX/(C4/C2)); }
+        public long toSeconds(long d) { return x(d, C4/C3, MAX/(C4/C3)); }
+        public long toMinutes(long d) { return d; }
+        public long toHours(long d)   { return d/(C5/C4); }
+        public long toDays(long d)    { return d/(C6/C4); }
+        public long convert(long d, TimeUnit u) { return u.toMinutes(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing sixty minutes.
+     * @since 1.6
+     */
+    HOURS {
+        public long toNanos(long d)   { return x(d, C5/C0, MAX/(C5/C0)); }
+        public long toMicros(long d)  { return x(d, C5/C1, MAX/(C5/C1)); }
+        public long toMillis(long d)  { return x(d, C5/C2, MAX/(C5/C2)); }
+        public long toSeconds(long d) { return x(d, C5/C3, MAX/(C5/C3)); }
+        public long toMinutes(long d) { return x(d, C5/C4, MAX/(C5/C4)); }
+        public long toHours(long d)   { return d; }
+        public long toDays(long d)    { return d/(C6/C5); }
+        public long convert(long d, TimeUnit u) { return u.toHours(d); }
+        int excessNanos(long d, long m) { return 0; }
+    },
+
+    /**
+     * Time unit representing twenty four hours.
+     * @since 1.6
+     */
+    DAYS {
+        public long toNanos(long d)   { return x(d, C6/C0, MAX/(C6/C0)); }
+        public long toMicros(long d)  { return x(d, C6/C1, MAX/(C6/C1)); }
+        public long toMillis(long d)  { return x(d, C6/C2, MAX/(C6/C2)); }
+        public long toSeconds(long d) { return x(d, C6/C3, MAX/(C6/C3)); }
+        public long toMinutes(long d) { return x(d, C6/C4, MAX/(C6/C4)); }
+        public long toHours(long d)   { return x(d, C6/C5, MAX/(C6/C5)); }
+        public long toDays(long d)    { return d; }
+        public long convert(long d, TimeUnit u) { return u.toDays(d); }
+        int excessNanos(long d, long m) { return 0; }
+    };
+
+    // Handy constants for conversion methods
+    static final long C0 = 1L;
+    static final long C1 = C0 * 1000L;
+    static final long C2 = C1 * 1000L;
+    static final long C3 = C2 * 1000L;
+    static final long C4 = C3 * 60L;
+    static final long C5 = C4 * 60L;
+    static final long C6 = C5 * 24L;
+
+    static final long MAX = Long.MAX_VALUE;
+
+    /**
+     * Scale d by m, checking for overflow.
+     * This has a short name to make above code more readable.
+     */
+    static long x(long d, long m, long over) {
+        if (d > +over) return Long.MAX_VALUE;
+        if (d < -over) return Long.MIN_VALUE;
+        return d * m;
+    }
+
+    // To maintain full signature compatibility with 1.5, and to improve the
+    // clarity of the generated javadoc (see 6287639: Abstract methods in
+    // enum classes should not be listed as abstract), method convert
+    // etc. are not declared abstract but otherwise act as abstract methods.
+
+    /**
+     * Converts the given time duration in the given unit to this unit.
+     * Conversions from finer to coarser granularities truncate, so
+     * lose precision. For example, converting {@code 999} milliseconds
+     * to seconds results in {@code 0}. Conversions from coarser to
+     * finer granularities with arguments that would numerically
+     * overflow saturate to {@code Long.MIN_VALUE} if negative or
+     * {@code Long.MAX_VALUE} if positive.
+     *
+     * <p>For example, to convert 10 minutes to milliseconds, use:
+     * {@code TimeUnit.MILLISECONDS.convert(10L, TimeUnit.MINUTES)}
+     *
+     * @param sourceDuration the time duration in the given {@code sourceUnit}
+     * @param sourceUnit the unit of the {@code sourceDuration} argument
+     * @return the converted duration in this unit,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long convert(long sourceDuration, TimeUnit sourceUnit) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) NANOSECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toNanos(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MICROSECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toMicros(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MILLISECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toMillis(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) SECONDS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     */
+    public long toSeconds(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) MINUTES.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @since 1.6
+     */
+    public long toMinutes(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) HOURS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration,
+     * or {@code Long.MIN_VALUE} if conversion would negatively
+     * overflow, or {@code Long.MAX_VALUE} if it would positively overflow.
+     * @since 1.6
+     */
+    public long toHours(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Equivalent to
+     * {@link #convert(long, TimeUnit) DAYS.convert(duration, this)}.
+     * @param duration the duration
+     * @return the converted duration
+     * @since 1.6
+     */
+    public long toDays(long duration) {
+        throw new AbstractMethodError();
+    }
+
+    /**
+     * Utility to compute the excess-nanosecond argument to wait,
+     * sleep, join.
+     * @param d the duration
+     * @param m the number of milliseconds
+     * @return the number of nanoseconds
+     */
+    abstract int excessNanos(long d, long m);
+
+    /**
+     * Performs a timed {@link Object#wait(long, int) Object.wait}
+     * using this time unit.
+     * This is a convenience method that converts timeout arguments
+     * into the form required by the {@code Object.wait} method.
+     *
+     * <p>For example, you could implement a blocking {@code poll}
+     * method (see {@link BlockingQueue#poll BlockingQueue.poll})
+     * using:
+     *
+     * <pre> {@code
+     * public synchronized Object poll(long timeout, TimeUnit unit)
+     *     throws InterruptedException {
+     *   while (empty) {
+     *     unit.timedWait(this, timeout);
+     *     ...
+     *   }
+     * }}</pre>
+     *
+     * @param obj the object to wait on
+     * @param timeout the maximum time to wait. If less than
+     * or equal to zero, do not wait at all.
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public void timedWait(Object obj, long timeout)
+            throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            obj.wait(ms, ns);
+        }
+    }
+
+    /**
+     * Performs a timed {@link Thread#join(long, int) Thread.join}
+     * using this time unit.
+     * This is a convenience method that converts time arguments into the
+     * form required by the {@code Thread.join} method.
+     *
+     * @param thread the thread to wait for
+     * @param timeout the maximum time to wait. If less than
+     * or equal to zero, do not wait at all.
+     * @throws InterruptedException if interrupted while waiting
+     */
+    public void timedJoin(Thread thread, long timeout)
+            throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            thread.join(ms, ns);
+        }
+    }
+
+    /**
+     * Performs a {@link Thread#sleep(long, int) Thread.sleep} using
+     * this time unit.
+     * This is a convenience method that converts time arguments into the
+     * form required by the {@code Thread.sleep} method.
+     *
+     * @param timeout the minimum time to sleep. If less than
+     * or equal to zero, do not sleep at all.
+     * @throws InterruptedException if interrupted while sleeping
+     */
+    public void sleep(long timeout) throws InterruptedException {
+        if (timeout > 0) {
+            long ms = toMillis(timeout);
+            int ns = excessNanos(timeout, ms);
+            Thread.sleep(ms, ns);
+        }
+    }
+
+    // BEGIN Android-removed: OpenJDK 9 ChronoUnit related code.
+    /*
+    /**
+     * Converts this {@code TimeUnit} to the equivalent {@code ChronoUnit}.
+     *
+     * @return the converted equivalent ChronoUnit
+     * @since 9
+     *
+    public ChronoUnit toChronoUnit() {
+        switch (this) {
+        case NANOSECONDS:  return ChronoUnit.NANOS;
+        case MICROSECONDS: return ChronoUnit.MICROS;
+        case MILLISECONDS: return ChronoUnit.MILLIS;
+        case SECONDS:      return ChronoUnit.SECONDS;
+        case MINUTES:      return ChronoUnit.MINUTES;
+        case HOURS:        return ChronoUnit.HOURS;
+        case DAYS:         return ChronoUnit.DAYS;
+        default: throw new AssertionError();
+        }
+    }
+
+    /**
+     * Converts a {@code ChronoUnit} to the equivalent {@code TimeUnit}.
+     *
+     * @param chronoUnit the ChronoUnit to convert
+     * @return the converted equivalent TimeUnit
+     * @throws IllegalArgumentException if {@code chronoUnit} has no
+     *         equivalent TimeUnit
+     * @throws NullPointerException if {@code chronoUnit} is null
+     * @since 9
+     *
+    public static TimeUnit of(ChronoUnit chronoUnit) {
+        switch (Objects.requireNonNull(chronoUnit, "chronoUnit")) {
+        case NANOS:   return TimeUnit.NANOSECONDS;
+        case MICROS:  return TimeUnit.MICROSECONDS;
+        case MILLIS:  return TimeUnit.MILLISECONDS;
+        case SECONDS: return TimeUnit.SECONDS;
+        case MINUTES: return TimeUnit.MINUTES;
+        case HOURS:   return TimeUnit.HOURS;
+        case DAYS:    return TimeUnit.DAYS;
+        default:
+            throw new IllegalArgumentException(
+                "No TimeUnit equivalent for " + chronoUnit);
+        }
+    }
+    */
+    // END Android-removed: OpenJDK 9 ChronoUnit related code.
+
+}
diff --git a/java/util/concurrent/TimeoutException.java b/java/util/concurrent/TimeoutException.java
new file mode 100644
index 0000000..b54c52b
--- /dev/null
+++ b/java/util/concurrent/TimeoutException.java
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+/**
+ * Exception thrown when a blocking operation times out.  Blocking
+ * operations for which a timeout is specified need a means to
+ * indicate that the timeout has occurred. For many such operations it
+ * is possible to return a value that indicates timeout; when that is
+ * not possible or desirable then {@code TimeoutException} should be
+ * declared and thrown.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class TimeoutException extends Exception {
+    private static final long serialVersionUID = 1900926677490660714L;
+
+    /**
+     * Constructs a {@code TimeoutException} with no specified detail
+     * message.
+     */
+    public TimeoutException() {}
+
+    /**
+     * Constructs a {@code TimeoutException} with the specified detail
+     * message.
+     *
+     * @param message the detail message
+     */
+    public TimeoutException(String message) {
+        super(message);
+    }
+}
diff --git a/java/util/concurrent/TransferQueue.java b/java/util/concurrent/TransferQueue.java
new file mode 100644
index 0000000..53da597
--- /dev/null
+++ b/java/util/concurrent/TransferQueue.java
@@ -0,0 +1,161 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent;
+
+// BEGIN android-note
+// removed link to collections framework docs
+// END android-note
+
+/**
+ * A {@link BlockingQueue} in which producers may wait for consumers
+ * to receive elements.  A {@code TransferQueue} may be useful for
+ * example in message passing applications in which producers
+ * sometimes (using method {@link #transfer}) await receipt of
+ * elements by consumers invoking {@code take} or {@code poll}, while
+ * at other times enqueue elements (via method {@code put}) without
+ * waiting for receipt.
+ * {@linkplain #tryTransfer(Object) Non-blocking} and
+ * {@linkplain #tryTransfer(Object,long,TimeUnit) time-out} versions of
+ * {@code tryTransfer} are also available.
+ * A {@code TransferQueue} may also be queried, via {@link
+ * #hasWaitingConsumer}, whether there are any threads waiting for
+ * items, which is a converse analogy to a {@code peek} operation.
+ *
+ * <p>Like other blocking queues, a {@code TransferQueue} may be
+ * capacity bounded.  If so, an attempted transfer operation may
+ * initially block waiting for available space, and/or subsequently
+ * block waiting for reception by a consumer.  Note that in a queue
+ * with zero capacity, such as {@link SynchronousQueue}, {@code put}
+ * and {@code transfer} are effectively synonymous.
+ *
+ * @since 1.7
+ * @author Doug Lea
+ * @param <E> the type of elements held in this queue
+ */
+public interface TransferQueue<E> extends BlockingQueue<E> {
+    /**
+     * Transfers the element to a waiting consumer immediately, if possible.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * otherwise returning {@code false} without enqueuing the element.
+     *
+     * @param e the element to transfer
+     * @return {@code true} if the element was transferred, else
+     *         {@code false}
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean tryTransfer(E e);
+
+    /**
+     * Transfers the element to a consumer, waiting if necessary to do so.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else waits until the element is received by a consumer.
+     *
+     * @param e the element to transfer
+     * @throws InterruptedException if interrupted while waiting,
+     *         in which case the element is not left enqueued
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    void transfer(E e) throws InterruptedException;
+
+    /**
+     * Transfers the element to a consumer if it is possible to do so
+     * before the timeout elapses.
+     *
+     * <p>More precisely, transfers the specified element immediately
+     * if there exists a consumer already waiting to receive it (in
+     * {@link #take} or timed {@link #poll(long,TimeUnit) poll}),
+     * else waits until the element is received by a consumer,
+     * returning {@code false} if the specified wait time elapses
+     * before the element can be transferred.
+     *
+     * @param e the element to transfer
+     * @param timeout how long to wait before giving up, in units of
+     *        {@code unit}
+     * @param unit a {@code TimeUnit} determining how to interpret the
+     *        {@code timeout} parameter
+     * @return {@code true} if successful, or {@code false} if
+     *         the specified waiting time elapses before completion,
+     *         in which case the element is not left enqueued
+     * @throws InterruptedException if interrupted while waiting,
+     *         in which case the element is not left enqueued
+     * @throws ClassCastException if the class of the specified element
+     *         prevents it from being added to this queue
+     * @throws NullPointerException if the specified element is null
+     * @throws IllegalArgumentException if some property of the specified
+     *         element prevents it from being added to this queue
+     */
+    boolean tryTransfer(E e, long timeout, TimeUnit unit)
+        throws InterruptedException;
+
+    /**
+     * Returns {@code true} if there is at least one consumer waiting
+     * to receive an element via {@link #take} or
+     * timed {@link #poll(long,TimeUnit) poll}.
+     * The return value represents a momentary state of affairs.
+     *
+     * @return {@code true} if there is at least one waiting consumer
+     */
+    boolean hasWaitingConsumer();
+
+    /**
+     * Returns an estimate of the number of consumers waiting to
+     * receive elements via {@link #take} or timed
+     * {@link #poll(long,TimeUnit) poll}.  The return value is an
+     * approximation of a momentary state of affairs, that may be
+     * inaccurate if consumers have completed or given up waiting.
+     * The value may be useful for monitoring and heuristics, but
+     * not for synchronization control.  Implementations of this
+     * method are likely to be noticeably slower than those for
+     * {@link #hasWaitingConsumer}.
+     *
+     * @return the number of consumers waiting to receive elements
+     */
+    int getWaitingConsumerCount();
+}
diff --git a/java/util/concurrent/atomic/AtomicBoolean.java b/java/util/concurrent/atomic/AtomicBoolean.java
new file mode 100644
index 0000000..b2a2390
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicBoolean.java
@@ -0,0 +1,164 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * A {@code boolean} value that may be updated atomically. See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicBoolean} is used in applications such as atomically
+ * updated flags, and cannot be used as a replacement for a
+ * {@link java.lang.Boolean}.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicBoolean implements java.io.Serializable {
+    private static final long serialVersionUID = 4654671469794556979L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicBoolean.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile int value;
+
+    /**
+     * Creates a new {@code AtomicBoolean} with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicBoolean(boolean initialValue) {
+        value = initialValue ? 1 : 0;
+    }
+
+    /**
+     * Creates a new {@code AtomicBoolean} with initial value {@code false}.
+     */
+    public AtomicBoolean() {
+    }
+
+    /**
+     * Returns the current value.
+     *
+     * @return the current value
+     */
+    public final boolean get() {
+        return value != 0;
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(boolean expect, boolean update) {
+        return U.compareAndSwapInt(this, VALUE,
+                                   (expect ? 1 : 0),
+                                   (update ? 1 : 0));
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(boolean expect, boolean update) {
+        return U.compareAndSwapInt(this, VALUE,
+                                   (expect ? 1 : 0),
+                                   (update ? 1 : 0));
+    }
+
+    /**
+     * Unconditionally sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(boolean newValue) {
+        value = newValue ? 1 : 0;
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(boolean newValue) {
+        U.putOrderedInt(this, VALUE, (newValue ? 1 : 0));
+    }
+
+    /**
+     * Atomically sets to the given value and returns the previous value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final boolean getAndSet(boolean newValue) {
+        boolean prev;
+        do {
+            prev = get();
+        } while (!compareAndSet(prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Boolean.toString(get());
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicInteger.java b/java/util/concurrent/atomic/AtomicInteger.java
new file mode 100644
index 0000000..19b3418
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicInteger.java
@@ -0,0 +1,338 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * An {@code int} value that may be updated atomically.  See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicInteger} is used in applications such as atomically
+ * incremented counters, and cannot be used as a replacement for an
+ * {@link java.lang.Integer}. However, this class does extend
+ * {@code Number} to allow uniform access by tools and utilities that
+ * deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicInteger extends Number implements java.io.Serializable {
+    private static final long serialVersionUID = 6214790243416807050L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicInteger.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile int value;
+
+    /**
+     * Creates a new AtomicInteger with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicInteger(int initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicInteger with initial value {@code 0}.
+     */
+    public AtomicInteger() {
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final int get() {
+        return value;
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(int newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int newValue) {
+        U.putOrderedInt(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final int getAndSet(int newValue) {
+        return U.getAndSetInt(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int expect, int update) {
+        return U.compareAndSwapInt(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int expect, int update) {
+        return U.compareAndSwapInt(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the previous value
+     */
+    public final int getAndIncrement() {
+        return U.getAndAddInt(this, VALUE, 1);
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the previous value
+     */
+    public final int getAndDecrement() {
+        return U.getAndAddInt(this, VALUE, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final int getAndAdd(int delta) {
+        return U.getAndAddInt(this, VALUE, delta);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the updated value
+     */
+    public final int incrementAndGet() {
+        return U.getAndAddInt(this, VALUE, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the updated value
+     */
+    public final int decrementAndGet() {
+        return U.getAndAddInt(this, VALUE, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final int addAndGet(int delta) {
+        return U.getAndAddInt(this, VALUE, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Integer.toString(get());
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as an {@code int}.
+     * Equivalent to {@link #get()}.
+     */
+    public int intValue() {
+        return get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code long}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public long longValue() {
+        return (long)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code float}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicInteger} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicIntegerArray.java b/java/util/concurrent/atomic/AtomicIntegerArray.java
new file mode 100644
index 0000000..2ea9a27
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicIntegerArray.java
@@ -0,0 +1,364 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+
+/**
+ * An {@code int} array in which elements may be updated atomically.
+ * See the {@link java.util.concurrent.atomic} package
+ * specification for description of the properties of atomic
+ * variables.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicIntegerArray implements java.io.Serializable {
+    private static final long serialVersionUID = 2862133569453604235L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final int ABASE;
+    private static final int ASHIFT;
+    private final int[] array;
+
+    static {
+        ABASE = U.arrayBaseOffset(int[].class);
+        int scale = U.arrayIndexScale(int[].class);
+        if ((scale & (scale - 1)) != 0)
+            throw new Error("array index scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+    }
+
+    private long checkedByteOffset(int i) {
+        if (i < 0 || i >= array.length)
+            throw new IndexOutOfBoundsException("index " + i);
+
+        return byteOffset(i);
+    }
+
+    private static long byteOffset(int i) {
+        return ((long) i << ASHIFT) + ABASE;
+    }
+
+    /**
+     * Creates a new AtomicIntegerArray of the given length, with all
+     * elements initially zero.
+     *
+     * @param length the length of the array
+     */
+    public AtomicIntegerArray(int length) {
+        array = new int[length];
+    }
+
+    /**
+     * Creates a new AtomicIntegerArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicIntegerArray(int[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = array.clone();
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Gets the current value at position {@code i}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final int get(int i) {
+        return getRaw(checkedByteOffset(i));
+    }
+
+    private int getRaw(long offset) {
+        return U.getIntVolatile(array, offset);
+    }
+
+    /**
+     * Sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, int newValue) {
+        U.putIntVolatile(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Eventually sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, int newValue) {
+        U.putOrderedInt(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * value and returns the old value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final int getAndSet(int i, int newValue) {
+        return U.getAndSetInt(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, int expect, int update) {
+        return compareAndSetRaw(checkedByteOffset(i), expect, update);
+    }
+
+    private boolean compareAndSetRaw(long offset, int expect, int update) {
+        return U.compareAndSwapInt(array, offset, expect, update);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int i, int expect, int update) {
+        return compareAndSet(i, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final int getAndIncrement(int i) {
+        return getAndAdd(i, 1);
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final int getAndDecrement(int i) {
+        return getAndAdd(i, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final int getAndAdd(int i, int delta) {
+        return U.getAndAddInt(array, checkedByteOffset(i), delta);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final int incrementAndGet(int i) {
+        return getAndAdd(i, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final int decrementAndGet(int i) {
+        return getAndAdd(i, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final int addAndGet(int i, int delta) {
+        return getAndAdd(i, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(int i, IntUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(int i, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(int i, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        int prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(getRaw(byteOffset(i)));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
new file mode 100644
index 0000000..589d5da
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -0,0 +1,534 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntUnaryOperator;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile int} fields of designated classes.
+ * This class is designed for use in atomic data structures in which
+ * several fields of the same node are independently subject to atomic
+ * updates.
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ */
+public abstract class AtomicIntegerFieldUpdater<T> {
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class argument is needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @return the updater
+     * @throws IllegalArgumentException if the field is not a
+     * volatile integer type
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
+                                                              String fieldName) {
+        return new AtomicIntegerFieldUpdaterImpl<U>
+            (tclass, fieldName, Reflection.getCallerClass());
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicIntegerFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean compareAndSet(T obj, int expect, int update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean weakCompareAndSet(T obj, int expect, int update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, int newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, int newValue);
+
+    /**
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract int get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public int getAndSet(T obj, int newValue) {
+        int prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public int getAndIncrement(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public int getAndDecrement(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public int getAndAdd(T obj, int delta) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public int incrementAndGet(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public int decrementAndGet(T obj) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public int addAndGet(T obj, int delta) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsInt(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final int getAndAccumulate(T obj, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final int accumulateAndGet(T obj, int x,
+                                      IntBinaryOperator accumulatorFunction) {
+        int prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsInt(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Standard hotspot implementation using intrinsics.
+     */
+    private static final class AtomicIntegerFieldUpdaterImpl<T>
+        extends AtomicIntegerFieldUpdater<T> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        AtomicIntegerFieldUpdaterImpl(final Class<T> tclass,
+                                      final String fieldName,
+                                      final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // BEGIN Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                // END Android-changed: Skip privilege escalation which is a noop on Android.
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // BEGIN Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+                // END Android-removed: Skip checkPackageAccess which is a noop on Android.
+            // BEGIN Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            // END Android-removed: Skip privilege escalation which is a noop on Android.
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != int.class)
+                throw new IllegalArgumentException("Must be integer type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        // BEGIN Android-removed: isAncestor()'s only usage was removed above.
+        /*
+        /**
+         * Returns true if the second classloader can be found in the first
+         * classloader's delegation chain.
+         * Equivalent to the inaccessible: first.isAncestor(second).
+         *
+        private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+            ClassLoader acl = first;
+            do {
+                acl = acl.getParent();
+                if (second == acl) {
+                    return true;
+                }
+            } while (acl != null);
+            return false;
+        }
+        */
+        // END Android-removed: isAncestor()'s only usage was removed above.
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, int expect, int update) {
+            accessCheck(obj);
+            return U.compareAndSwapInt(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, int expect, int update) {
+            accessCheck(obj);
+            return U.compareAndSwapInt(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, int newValue) {
+            accessCheck(obj);
+            U.putIntVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, int newValue) {
+            accessCheck(obj);
+            U.putOrderedInt(obj, offset, newValue);
+        }
+
+        public final int get(T obj) {
+            accessCheck(obj);
+            return U.getIntVolatile(obj, offset);
+        }
+
+        public final int getAndSet(T obj, int newValue) {
+            accessCheck(obj);
+            return U.getAndSetInt(obj, offset, newValue);
+        }
+
+        public final int getAndAdd(T obj, int delta) {
+            accessCheck(obj);
+            return U.getAndAddInt(obj, offset, delta);
+        }
+
+        public final int getAndIncrement(T obj) {
+            return getAndAdd(obj, 1);
+        }
+
+        public final int getAndDecrement(T obj) {
+            return getAndAdd(obj, -1);
+        }
+
+        public final int incrementAndGet(T obj) {
+            return getAndAdd(obj, 1) + 1;
+        }
+
+        public final int decrementAndGet(T obj) {
+            return getAndAdd(obj, -1) - 1;
+        }
+
+        public final int addAndGet(T obj, int delta) {
+            return getAndAdd(obj, delta) + delta;
+        }
+
+    }
+}
diff --git a/java/util/concurrent/atomic/AtomicLong.java b/java/util/concurrent/atomic/AtomicLong.java
new file mode 100644
index 0000000..b919f1e
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicLong.java
@@ -0,0 +1,354 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+
+/**
+ * A {@code long} value that may be updated atomically.  See the
+ * {@link java.util.concurrent.atomic} package specification for
+ * description of the properties of atomic variables. An
+ * {@code AtomicLong} is used in applications such as atomically
+ * incremented sequence numbers, and cannot be used as a replacement
+ * for a {@link java.lang.Long}. However, this class does extend
+ * {@code Number} to allow uniform access by tools and utilities that
+ * deal with numerically-based classes.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicLong extends Number implements java.io.Serializable {
+    private static final long serialVersionUID = 1927816293512124184L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    /**
+     * Records whether the underlying JVM supports lockless
+     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
+     * method works in either case, some constructions should be
+     * handled at Java level to avoid locking user-visible locks.
+     */
+    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
+
+    /**
+     * Returns whether underlying JVM supports lockless CompareAndSet
+     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
+     */
+    private static native boolean VMSupportsCS8();
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicLong.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile long value;
+
+    /**
+     * Creates a new AtomicLong with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicLong(long initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicLong with initial value {@code 0}.
+     */
+    public AtomicLong() {
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final long get() {
+        return value;
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(long newValue) {
+        // Use putLongVolatile instead of ordinary volatile store when
+        // using compareAndSwapLong, for sake of some 32bit systems.
+        U.putLongVolatile(this, VALUE, newValue);
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(long newValue) {
+        U.putOrderedLong(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final long getAndSet(long newValue) {
+        return U.getAndSetLong(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(long expect, long update) {
+        return U.compareAndSwapLong(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(long expect, long update) {
+        return U.compareAndSwapLong(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the previous value
+     */
+    public final long getAndIncrement() {
+        return U.getAndAddLong(this, VALUE, 1L);
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the previous value
+     */
+    public final long getAndDecrement() {
+        return U.getAndAddLong(this, VALUE, -1L);
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final long getAndAdd(long delta) {
+        return U.getAndAddLong(this, VALUE, delta);
+    }
+
+    /**
+     * Atomically increments by one the current value.
+     *
+     * @return the updated value
+     */
+    public final long incrementAndGet() {
+        return U.getAndAddLong(this, VALUE, 1L) + 1L;
+    }
+
+    /**
+     * Atomically decrements by one the current value.
+     *
+     * @return the updated value
+     */
+    public final long decrementAndGet() {
+        return U.getAndAddLong(this, VALUE, -1L) - 1L;
+    }
+
+    /**
+     * Atomically adds the given value to the current value.
+     *
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public final long addAndGet(long delta) {
+        return U.getAndAddLong(this, VALUE, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Long.toString(get());
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as an {@code int}
+     * after a narrowing primitive conversion.
+     * @jls 5.1.3 Narrowing Primitive Conversions
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code long}.
+     * Equivalent to {@link #get()}.
+     */
+    public long longValue() {
+        return get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code float}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the value of this {@code AtomicLong} as a {@code double}
+     * after a widening primitive conversion.
+     * @jls 5.1.2 Widening Primitive Conversions
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicLongArray.java b/java/util/concurrent/atomic/AtomicLongArray.java
new file mode 100644
index 0000000..d1af039
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicLongArray.java
@@ -0,0 +1,363 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+
+/**
+ * A {@code long} array in which elements may be updated atomically.
+ * See the {@link java.util.concurrent.atomic} package specification
+ * for description of the properties of atomic variables.
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class AtomicLongArray implements java.io.Serializable {
+    private static final long serialVersionUID = -2308431214976778248L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final int ABASE;
+    private static final int ASHIFT;
+    private final long[] array;
+
+    static {
+        ABASE = U.arrayBaseOffset(long[].class);
+        int scale = U.arrayIndexScale(long[].class);
+        if ((scale & (scale - 1)) != 0)
+            throw new Error("array index scale not a power of two");
+        ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+    }
+
+    private long checkedByteOffset(int i) {
+        if (i < 0 || i >= array.length)
+            throw new IndexOutOfBoundsException("index " + i);
+
+        return byteOffset(i);
+    }
+
+    private static long byteOffset(int i) {
+        return ((long) i << ASHIFT) + ABASE;
+    }
+
+    /**
+     * Creates a new AtomicLongArray of the given length, with all
+     * elements initially zero.
+     *
+     * @param length the length of the array
+     */
+    public AtomicLongArray(int length) {
+        array = new long[length];
+    }
+
+    /**
+     * Creates a new AtomicLongArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicLongArray(long[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = array.clone();
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Gets the current value at position {@code i}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final long get(int i) {
+        return getRaw(checkedByteOffset(i));
+    }
+
+    private long getRaw(long offset) {
+        return U.getLongVolatile(array, offset);
+    }
+
+    /**
+     * Sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, long newValue) {
+        U.putLongVolatile(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Eventually sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, long newValue) {
+        U.putOrderedLong(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given value
+     * and returns the old value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public final long getAndSet(int i, long newValue) {
+        return U.getAndSetLong(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, long expect, long update) {
+        return compareAndSetRaw(checkedByteOffset(i), expect, update);
+    }
+
+    private boolean compareAndSetRaw(long offset, long expect, long update) {
+        return U.compareAndSwapLong(array, offset, expect, update);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int i, long expect, long update) {
+        return compareAndSet(i, expect, update);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final long getAndIncrement(int i) {
+        return getAndAdd(i, 1);
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the previous value
+     */
+    public final long getAndDecrement(int i) {
+        return getAndAdd(i, -1);
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public final long getAndAdd(int i, long delta) {
+        return U.getAndAddLong(array, checkedByteOffset(i), delta);
+    }
+
+    /**
+     * Atomically increments by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final long incrementAndGet(int i) {
+        return getAndAdd(i, 1) + 1;
+    }
+
+    /**
+     * Atomically decrements by one the element at index {@code i}.
+     *
+     * @param i the index
+     * @return the updated value
+     */
+    public final long decrementAndGet(int i) {
+        return getAndAdd(i, -1) - 1;
+    }
+
+    /**
+     * Atomically adds the given value to the element at index {@code i}.
+     *
+     * @param i the index
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public long addAndGet(int i, long delta) {
+        return getAndAdd(i, delta) + delta;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(int i, LongUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(int i, LongUnaryOperator updateFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(int i, long x,
+                                      LongBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(int i, long x,
+                                      LongBinaryOperator accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        long prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(getRaw(byteOffset(i)));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
new file mode 100644
index 0000000..447a642
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -0,0 +1,646 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongUnaryOperator;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile long} fields of designated classes.
+ * This class is designed for use in atomic data structures in which
+ * several fields of the same node are independently subject to atomic
+ * updates.
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ */
+public abstract class AtomicLongFieldUpdater<T> {
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class argument is needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @return the updater
+     * @throws IllegalArgumentException if the field is not a
+     * volatile long type
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass,
+                                                           String fieldName) {
+        Class<?> caller = Reflection.getCallerClass();
+        if (AtomicLong.VM_SUPPORTS_LONG_CAS)
+            return new CASUpdater<U>(tclass, fieldName, caller);
+        else
+            return new LockedUpdater<U>(tclass, fieldName, caller);
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicLongFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean compareAndSet(T obj, long expect, long update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     * @throws ClassCastException if {@code obj} is not an instance
+     * of the class possessing the field established in the constructor
+     */
+    public abstract boolean weakCompareAndSet(T obj, long expect, long update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, long newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, long newValue);
+
+    /**
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract long get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public long getAndSet(T obj, long newValue) {
+        long prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public long getAndIncrement(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the previous value
+     */
+    public long getAndDecrement(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the previous value
+     */
+    public long getAndAdd(T obj, long delta) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically increments by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public long incrementAndGet(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically decrements by one the current value of the field of the
+     * given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @return the updated value
+     */
+    public long decrementAndGet(T obj) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev - 1;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically adds the given value to the current value of the field of
+     * the given object managed by this updater.
+     *
+     * @param obj An object whose field to get and set
+     * @param delta the value to add
+     * @return the updated value
+     */
+    public long addAndGet(T obj, long delta) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = prev + delta;
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndUpdate(T obj, LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long updateAndGet(T obj, LongUnaryOperator updateFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.applyAsLong(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final long getAndAccumulate(T obj, long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final long accumulateAndGet(T obj, long x,
+                                       LongBinaryOperator accumulatorFunction) {
+        long prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.applyAsLong(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        CASUpdater(final Class<T> tclass, final String fieldName,
+                   final Class<?> caller) {
+            final Field field;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != long.class)
+                throw new IllegalArgumentException("Must be long type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            return U.compareAndSwapLong(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            return U.compareAndSwapLong(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, long newValue) {
+            accessCheck(obj);
+            U.putLongVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, long newValue) {
+            accessCheck(obj);
+            U.putOrderedLong(obj, offset, newValue);
+        }
+
+        public final long get(T obj) {
+            accessCheck(obj);
+            return U.getLongVolatile(obj, offset);
+        }
+
+        public final long getAndSet(T obj, long newValue) {
+            accessCheck(obj);
+            return U.getAndSetLong(obj, offset, newValue);
+        }
+
+        public final long getAndAdd(T obj, long delta) {
+            accessCheck(obj);
+            return U.getAndAddLong(obj, offset, delta);
+        }
+
+        public final long getAndIncrement(T obj) {
+            return getAndAdd(obj, 1);
+        }
+
+        public final long getAndDecrement(T obj) {
+            return getAndAdd(obj, -1);
+        }
+
+        public final long incrementAndGet(T obj) {
+            return getAndAdd(obj, 1) + 1;
+        }
+
+        public final long decrementAndGet(T obj) {
+            return getAndAdd(obj, -1) - 1;
+        }
+
+        public final long addAndGet(T obj, long delta) {
+            return getAndAdd(obj, delta) + delta;
+        }
+    }
+
+    private static final class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+
+        LockedUpdater(final Class<T> tclass, final String fieldName,
+                      final Class<?> caller) {
+            Field field = null;
+            int modifiers = 0;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (field.getType() != long.class)
+                throw new IllegalArgumentException("Must be long type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throw accessCheckException(obj);
+        }
+
+        /**
+         * Returns access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final RuntimeException accessCheckException(T obj) {
+            if (cclass == tclass)
+                return new ClassCastException();
+            else
+                return new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        public final boolean compareAndSet(T obj, long expect, long update) {
+            accessCheck(obj);
+            synchronized (this) {
+                long v = U.getLong(obj, offset);
+                if (v != expect)
+                    return false;
+                U.putLong(obj, offset, update);
+                return true;
+            }
+        }
+
+        public final boolean weakCompareAndSet(T obj, long expect, long update) {
+            return compareAndSet(obj, expect, update);
+        }
+
+        public final void set(T obj, long newValue) {
+            accessCheck(obj);
+            synchronized (this) {
+                U.putLong(obj, offset, newValue);
+            }
+        }
+
+        public final void lazySet(T obj, long newValue) {
+            set(obj, newValue);
+        }
+
+        public final long get(T obj) {
+            accessCheck(obj);
+            synchronized (this) {
+                return U.getLong(obj, offset);
+            }
+        }
+    }
+
+    // Android-removed: isAncestor's only usage was removed above.
+    /*
+    /**
+     * Returns true if the second classloader can be found in the first
+     * classloader's delegation chain.
+     * Equivalent to the inaccessible: first.isAncestor(second).
+     *
+    static boolean isAncestor(ClassLoader first, ClassLoader second) {
+        ClassLoader acl = first;
+        do {
+            acl = acl.getParent();
+            if (second == acl) {
+                return true;
+            }
+        } while (acl != null);
+        return false;
+    }
+    */
+}
diff --git a/java/util/concurrent/atomic/AtomicMarkableReference.java b/java/util/concurrent/atomic/AtomicMarkableReference.java
new file mode 100644
index 0000000..b49118b
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicMarkableReference.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * An {@code AtomicMarkableReference} maintains an object reference
+ * along with a mark bit, that can be updated atomically.
+ *
+ * <p>Implementation note: This implementation maintains markable
+ * references by creating internal objects representing "boxed"
+ * [reference, boolean] pairs.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicMarkableReference<V> {
+
+    private static class Pair<T> {
+        final T reference;
+        final boolean mark;
+        private Pair(T reference, boolean mark) {
+            this.reference = reference;
+            this.mark = mark;
+        }
+        static <T> Pair<T> of(T reference, boolean mark) {
+            return new Pair<T>(reference, mark);
+        }
+    }
+
+    private volatile Pair<V> pair;
+
+    /**
+     * Creates a new {@code AtomicMarkableReference} with the given
+     * initial values.
+     *
+     * @param initialRef the initial reference
+     * @param initialMark the initial mark
+     */
+    public AtomicMarkableReference(V initialRef, boolean initialMark) {
+        pair = Pair.of(initialRef, initialMark);
+    }
+
+    /**
+     * Returns the current value of the reference.
+     *
+     * @return the current value of the reference
+     */
+    public V getReference() {
+        return pair.reference;
+    }
+
+    /**
+     * Returns the current value of the mark.
+     *
+     * @return the current value of the mark
+     */
+    public boolean isMarked() {
+        return pair.mark;
+    }
+
+    /**
+     * Returns the current values of both the reference and the mark.
+     * Typical usage is {@code boolean[1] holder; ref = v.get(holder); }.
+     *
+     * @param markHolder an array of size of at least one. On return,
+     * {@code markHolder[0]} will hold the value of the mark.
+     * @return the current value of the reference
+     */
+    public V get(boolean[] markHolder) {
+        Pair<V> pair = this.pair;
+        markHolder[0] = pair.mark;
+        return pair.reference;
+    }
+
+    /**
+     * Atomically sets the value of both the reference and mark
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current mark is equal to the expected mark.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedMark the expected value of the mark
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(V       expectedReference,
+                                     V       newReference,
+                                     boolean expectedMark,
+                                     boolean newMark) {
+        return compareAndSet(expectedReference, newReference,
+                             expectedMark, newMark);
+    }
+
+    /**
+     * Atomically sets the value of both the reference and mark
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current mark is equal to the expected mark.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedMark the expected value of the mark
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean compareAndSet(V       expectedReference,
+                                 V       newReference,
+                                 boolean expectedMark,
+                                 boolean newMark) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            expectedMark == current.mark &&
+            ((newReference == current.reference &&
+              newMark == current.mark) ||
+             casPair(current, Pair.of(newReference, newMark)));
+    }
+
+    /**
+     * Unconditionally sets the value of both the reference and mark.
+     *
+     * @param newReference the new value for the reference
+     * @param newMark the new value for the mark
+     */
+    public void set(V newReference, boolean newMark) {
+        Pair<V> current = pair;
+        if (newReference != current.reference || newMark != current.mark)
+            this.pair = Pair.of(newReference, newMark);
+    }
+
+    /**
+     * Atomically sets the value of the mark to the given update value
+     * if the current reference is {@code ==} to the expected
+     * reference.  Any given invocation of this operation may fail
+     * (return {@code false}) spuriously, but repeated invocation
+     * when the current value holds the expected value and no other
+     * thread is also attempting to set the value will eventually
+     * succeed.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newMark the new value for the mark
+     * @return {@code true} if successful
+     */
+    public boolean attemptMark(V expectedReference, boolean newMark) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            (newMark == current.mark ||
+             casPair(current, Pair.of(expectedReference, newMark)));
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PAIR;
+    static {
+        try {
+            PAIR = U.objectFieldOffset
+                (AtomicMarkableReference.class.getDeclaredField("pair"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private boolean casPair(Pair<V> cmp, Pair<V> val) {
+        return U.compareAndSwapObject(this, PAIR, cmp, val);
+    }
+}
diff --git a/java/util/concurrent/atomic/AtomicReference.java b/java/util/concurrent/atomic/AtomicReference.java
new file mode 100644
index 0000000..dbc6685
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicReference.java
@@ -0,0 +1,242 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * An object reference that may be updated atomically. See the {@link
+ * java.util.concurrent.atomic} package specification for description
+ * of the properties of atomic variables.
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicReference<V> implements java.io.Serializable {
+    private static final long serialVersionUID = -1848883965231344442L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long VALUE;
+
+    static {
+        try {
+            VALUE = U.objectFieldOffset
+                (AtomicReference.class.getDeclaredField("value"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private volatile V value;
+
+    /**
+     * Creates a new AtomicReference with the given initial value.
+     *
+     * @param initialValue the initial value
+     */
+    public AtomicReference(V initialValue) {
+        value = initialValue;
+    }
+
+    /**
+     * Creates a new AtomicReference with null initial value.
+     */
+    public AtomicReference() {
+    }
+
+    /**
+     * Gets the current value.
+     *
+     * @return the current value
+     */
+    public final V get() {
+        return value;
+    }
+
+    /**
+     * Sets to the given value.
+     *
+     * @param newValue the new value
+     */
+    public final void set(V newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Eventually sets to the given value.
+     *
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(V newValue) {
+        U.putOrderedObject(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(V expect, V update) {
+        return U.compareAndSwapObject(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets the value to the given updated value
+     * if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(V expect, V update) {
+        return U.compareAndSwapObject(this, VALUE, expect, update);
+    }
+
+    /**
+     * Atomically sets to the given value and returns the old value.
+     *
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final V getAndSet(V newValue) {
+        return (V)U.getAndSetObject(this, VALUE, newValue);
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndUpdate(UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V updateAndGet(UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the previous value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndAccumulate(V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the current value with the results of
+     * applying the given function to the current and given values,
+     * returning the updated value. The function should be
+     * side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function
+     * is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V accumulateAndGet(V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get();
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return String.valueOf(get());
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicReferenceArray.java b/java/util/concurrent/atomic/AtomicReferenceArray.java
new file mode 100644
index 0000000..cce148e
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicReferenceArray.java
@@ -0,0 +1,332 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+
+/**
+ * An array of object references in which elements may be updated
+ * atomically.  See the {@link java.util.concurrent.atomic} package
+ * specification for description of the properties of atomic
+ * variables.
+ * @since 1.5
+ * @author Doug Lea
+ * @param <E> The base class of elements held in this array
+ */
+public class AtomicReferenceArray<E> implements java.io.Serializable {
+    private static final long serialVersionUID = -6209656149925076980L;
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long ARRAY;
+    private static final int ABASE;
+    private static final int ASHIFT;
+    private final Object[] array; // must have exact type Object[]
+
+    static {
+        try {
+            ARRAY = U.objectFieldOffset
+                (AtomicReferenceArray.class.getDeclaredField("array"));
+            ABASE = U.arrayBaseOffset(Object[].class);
+            int scale = U.arrayIndexScale(Object[].class);
+            if ((scale & (scale - 1)) != 0)
+                throw new Error("array index scale not a power of two");
+            ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private long checkedByteOffset(int i) {
+        if (i < 0 || i >= array.length)
+            throw new IndexOutOfBoundsException("index " + i);
+
+        return byteOffset(i);
+    }
+
+    private static long byteOffset(int i) {
+        return ((long) i << ASHIFT) + ABASE;
+    }
+
+    /**
+     * Creates a new AtomicReferenceArray of the given length, with all
+     * elements initially null.
+     *
+     * @param length the length of the array
+     */
+    public AtomicReferenceArray(int length) {
+        array = new Object[length];
+    }
+
+    /**
+     * Creates a new AtomicReferenceArray with the same length as, and
+     * all elements copied from, the given array.
+     *
+     * @param array the array to copy elements from
+     * @throws NullPointerException if array is null
+     */
+    public AtomicReferenceArray(E[] array) {
+        // Visibility guaranteed by final field guarantees
+        this.array = Arrays.copyOf(array, array.length, Object[].class);
+    }
+
+    /**
+     * Returns the length of the array.
+     *
+     * @return the length of the array
+     */
+    public final int length() {
+        return array.length;
+    }
+
+    /**
+     * Gets the current value at position {@code i}.
+     *
+     * @param i the index
+     * @return the current value
+     */
+    public final E get(int i) {
+        return getRaw(checkedByteOffset(i));
+    }
+
+    @SuppressWarnings("unchecked")
+    private E getRaw(long offset) {
+        return (E) U.getObjectVolatile(array, offset);
+    }
+
+    /**
+     * Sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     */
+    public final void set(int i, E newValue) {
+        U.putObjectVolatile(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Eventually sets the element at position {@code i} to the given value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public final void lazySet(int i, E newValue) {
+        U.putOrderedObject(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * value and returns the old value.
+     *
+     * @param i the index
+     * @param newValue the new value
+     * @return the previous value
+     */
+    @SuppressWarnings("unchecked")
+    public final E getAndSet(int i, E newValue) {
+        return (E)U.getAndSetObject(array, checkedByteOffset(i), newValue);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that
+     * the actual value was not equal to the expected value.
+     */
+    public final boolean compareAndSet(int i, E expect, E update) {
+        return compareAndSetRaw(checkedByteOffset(i), expect, update);
+    }
+
+    private boolean compareAndSetRaw(long offset, E expect, E update) {
+        return U.compareAndSwapObject(array, offset, expect, update);
+    }
+
+    /**
+     * Atomically sets the element at position {@code i} to the given
+     * updated value if the current value {@code ==} the expected value.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param i the index
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public final boolean weakCompareAndSet(int i, E expect, E update) {
+        return compareAndSet(i, expect, update);
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the results
+     * of applying the given function, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.
+     *
+     * @param i the index
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the previous value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final E getAndAccumulate(int i, E x,
+                                    BinaryOperator<E> accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the element at index {@code i} with the
+     * results of applying the given function to the current and
+     * given values, returning the updated value. The function should
+     * be side-effect-free, since it may be re-applied when attempted
+     * updates fail due to contention among threads.  The function is
+     * applied with the current value at index {@code i} as its first
+     * argument, and the given update as the second argument.
+     *
+     * @param i the index
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final E accumulateAndGet(int i, E x,
+                                    BinaryOperator<E> accumulatorFunction) {
+        long offset = checkedByteOffset(i);
+        E prev, next;
+        do {
+            prev = getRaw(offset);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSetRaw(offset, prev, next));
+        return next;
+    }
+
+    /**
+     * Returns the String representation of the current values of array.
+     * @return the String representation of the current values of array
+     */
+    public String toString() {
+        int iMax = array.length - 1;
+        if (iMax == -1)
+            return "[]";
+
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0; ; i++) {
+            b.append(getRaw(byteOffset(i)));
+            if (i == iMax)
+                return b.append(']').toString();
+            b.append(',').append(' ');
+        }
+    }
+
+    /**
+     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws java.io.IOException if an I/O error occurs
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        // Note: This must be changed if any additional fields are defined
+        Object a = s.readFields().get("array", null);
+        if (a == null || !a.getClass().isArray())
+            throw new java.io.InvalidObjectException("Not array type");
+        if (a.getClass() != Object[].class)
+            a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class);
+        U.putObjectVolatile(this, ARRAY, a);
+    }
+
+}
diff --git a/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
new file mode 100644
index 0000000..17423ad
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -0,0 +1,458 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A reflection-based utility that enables atomic updates to
+ * designated {@code volatile} reference fields of designated
+ * classes.  This class is designed for use in atomic data structures
+ * in which several reference fields of the same node are
+ * independently subject to atomic updates. For example, a tree node
+ * might be declared as
+ *
+ * <pre> {@code
+ * class Node {
+ *   private volatile Node left, right;
+ *
+ *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
+ *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
+ *   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
+ *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
+ *
+ *   Node getLeft() { return left; }
+ *   boolean compareAndSetLeft(Node expect, Node update) {
+ *     return leftUpdater.compareAndSet(this, expect, update);
+ *   }
+ *   // ... and so on
+ * }}</pre>
+ *
+ * <p>Note that the guarantees of the {@code compareAndSet}
+ * method in this class are weaker than in other atomic classes.
+ * Because this class cannot ensure that all uses of the field
+ * are appropriate for purposes of atomic access, it can
+ * guarantee atomicity only with respect to other invocations of
+ * {@code compareAndSet} and {@code set} on the same updater.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <T> The type of the object holding the updatable field
+ * @param <V> The type of the field
+ */
+public abstract class AtomicReferenceFieldUpdater<T,V> {
+
+    /**
+     * Creates and returns an updater for objects with the given field.
+     * The Class arguments are needed to check that reflective types and
+     * generic types match.
+     *
+     * @param tclass the class of the objects holding the field
+     * @param vclass the class of the field
+     * @param fieldName the name of the field to be updated
+     * @param <U> the type of instances of tclass
+     * @param <W> the type of instances of vclass
+     * @return the updater
+     * @throws ClassCastException if the field is of the wrong type
+     * @throws IllegalArgumentException if the field is not volatile
+     * @throws RuntimeException with a nested reflection-based
+     * exception if the class does not hold field or is the wrong type,
+     * or the field is inaccessible to the caller according to Java language
+     * access control
+     */
+    @CallerSensitive
+    public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
+                                                                    Class<W> vclass,
+                                                                    String fieldName) {
+        return new AtomicReferenceFieldUpdaterImpl<U,W>
+            (tclass, vclass, fieldName, Reflection.getCallerClass());
+    }
+
+    /**
+     * Protected do-nothing constructor for use by subclasses.
+     */
+    protected AtomicReferenceFieldUpdater() {
+    }
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean compareAndSet(T obj, V expect, V update);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given updated value if the current value {@code ==} the
+     * expected value. This method is guaranteed to be atomic with respect to
+     * other calls to {@code compareAndSet} and {@code set}, but not
+     * necessarily with respect to other changes in the field.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param obj An object whose field to conditionally set
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful
+     */
+    public abstract boolean weakCompareAndSet(T obj, V expect, V update);
+
+    /**
+     * Sets the field of the given object managed by this updater to the
+     * given updated value. This operation is guaranteed to act as a volatile
+     * store with respect to subsequent invocations of {@code compareAndSet}.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     */
+    public abstract void set(T obj, V newValue);
+
+    /**
+     * Eventually sets the field of the given object managed by this
+     * updater to the given updated value.
+     *
+     * @param obj An object whose field to set
+     * @param newValue the new value
+     * @since 1.6
+     */
+    public abstract void lazySet(T obj, V newValue);
+
+    /**
+     * Gets the current value held in the field of the given object managed
+     * by this updater.
+     *
+     * @param obj An object whose field to get
+     * @return the current value
+     */
+    public abstract V get(T obj);
+
+    /**
+     * Atomically sets the field of the given object managed by this updater
+     * to the given value and returns the old value.
+     *
+     * @param obj An object whose field to get and set
+     * @param newValue the new value
+     * @return the previous value
+     */
+    public V getAndSet(T obj, V newValue) {
+        V prev;
+        do {
+            prev = get(obj);
+        } while (!compareAndSet(obj, prev, newValue));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the previous
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndUpdate(T obj, UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this updater
+     * with the results of applying the given function, returning the updated
+     * value. The function should be side-effect-free, since it may be
+     * re-applied when attempted updates fail due to contention among threads.
+     *
+     * @param obj An object whose field to get and set
+     * @param updateFunction a side-effect-free function
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V updateAndGet(T obj, UnaryOperator<V> updateFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = updateFunction.apply(prev);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the previous value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the previous value
+     * @since 1.8
+     */
+    public final V getAndAccumulate(T obj, V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return prev;
+    }
+
+    /**
+     * Atomically updates the field of the given object managed by this
+     * updater with the results of applying the given function to the
+     * current and given values, returning the updated value. The
+     * function should be side-effect-free, since it may be re-applied
+     * when attempted updates fail due to contention among threads.  The
+     * function is applied with the current value as its first argument,
+     * and the given update as the second argument.
+     *
+     * @param obj An object whose field to get and set
+     * @param x the update value
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @return the updated value
+     * @since 1.8
+     */
+    public final V accumulateAndGet(T obj, V x,
+                                    BinaryOperator<V> accumulatorFunction) {
+        V prev, next;
+        do {
+            prev = get(obj);
+            next = accumulatorFunction.apply(prev, x);
+        } while (!compareAndSet(obj, prev, next));
+        return next;
+    }
+
+    private static final class AtomicReferenceFieldUpdaterImpl<T,V>
+        extends AtomicReferenceFieldUpdater<T,V> {
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private final long offset;
+        /**
+         * if field is protected, the subclass constructing updater, else
+         * the same as tclass
+         */
+        private final Class<?> cclass;
+        /** class holding the field */
+        private final Class<T> tclass;
+        /** field value type */
+        private final Class<V> vclass;
+
+        /*
+         * Internal type checks within all update methods contain
+         * internal inlined optimizations checking for the common
+         * cases where the class is final (in which case a simple
+         * getClass comparison suffices) or is of type Object (in
+         * which case no check is needed because all objects are
+         * instances of Object). The Object case is handled simply by
+         * setting vclass to null in constructor.  The targetCheck and
+         * updateCheck methods are invoked when these faster
+         * screenings fail.
+         */
+
+        AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
+                                        final Class<V> vclass,
+                                        final String fieldName,
+                                        final Class<?> caller) {
+            final Field field;
+            final Class<?> fieldClass;
+            final int modifiers;
+            try {
+                // Android-changed: Skip privilege escalation which is a noop on Android.
+                /*
+                field = AccessController.doPrivileged(
+                    new PrivilegedExceptionAction<Field>() {
+                        public Field run() throws NoSuchFieldException {
+                            return tclass.getDeclaredField(fieldName);
+                        }
+                    });
+                */
+                field = tclass.getDeclaredField(fieldName);
+                modifiers = field.getModifiers();
+                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
+                    caller, tclass, null, modifiers);
+                // Android-removed: Skip checkPackageAccess which is a noop on Android.
+                /*
+                ClassLoader cl = tclass.getClassLoader();
+                ClassLoader ccl = caller.getClassLoader();
+                if ((ccl != null) && (ccl != cl) &&
+                    ((cl == null) || !isAncestor(cl, ccl))) {
+                    sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
+                }
+                */
+                fieldClass = field.getType();
+            // Android-removed: Skip privilege escalation which is a noop on Android.
+            /*
+            } catch (PrivilegedActionException pae) {
+                throw new RuntimeException(pae.getException());
+            */
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+
+            if (vclass != fieldClass)
+                throw new ClassCastException();
+            if (vclass.isPrimitive())
+                throw new IllegalArgumentException("Must be reference type");
+
+            if (!Modifier.isVolatile(modifiers))
+                throw new IllegalArgumentException("Must be volatile type");
+
+            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            this.tclass = tclass;
+            this.vclass = vclass;
+            this.offset = U.objectFieldOffset(field);
+        }
+
+        // Android-removed: isAncestor's only usage was removed above.
+        /*
+        /**
+         * Returns true if the second classloader can be found in the first
+         * classloader's delegation chain.
+         * Equivalent to the inaccessible: first.isAncestor(second).
+         *
+        private static boolean isAncestor(ClassLoader first, ClassLoader second) {
+            ClassLoader acl = first;
+            do {
+                acl = acl.getParent();
+                if (second == acl) {
+                    return true;
+                }
+            } while (acl != null);
+            return false;
+        }
+        */
+
+        /**
+         * Checks that target argument is instance of cclass.  On
+         * failure, throws cause.
+         */
+        private final void accessCheck(T obj) {
+            if (!cclass.isInstance(obj))
+                throwAccessCheckException(obj);
+        }
+
+        /**
+         * Throws access exception if accessCheck failed due to
+         * protected access, else ClassCastException.
+         */
+        private final void throwAccessCheckException(T obj) {
+            if (cclass == tclass)
+                throw new ClassCastException();
+            else
+                throw new RuntimeException(
+                    new IllegalAccessException(
+                        "Class " +
+                        cclass.getName() +
+                        " can not access a protected member of class " +
+                        tclass.getName() +
+                        " using an instance of " +
+                        obj.getClass().getName()));
+        }
+
+        private final void valueCheck(V v) {
+            if (v != null && !(vclass.isInstance(v)))
+                throwCCE();
+        }
+
+        static void throwCCE() {
+            throw new ClassCastException();
+        }
+
+        public final boolean compareAndSet(T obj, V expect, V update) {
+            accessCheck(obj);
+            valueCheck(update);
+            return U.compareAndSwapObject(obj, offset, expect, update);
+        }
+
+        public final boolean weakCompareAndSet(T obj, V expect, V update) {
+            // same implementation as strong form for now
+            accessCheck(obj);
+            valueCheck(update);
+            return U.compareAndSwapObject(obj, offset, expect, update);
+        }
+
+        public final void set(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            U.putObjectVolatile(obj, offset, newValue);
+        }
+
+        public final void lazySet(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            U.putOrderedObject(obj, offset, newValue);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final V get(T obj) {
+            accessCheck(obj);
+            return (V)U.getObjectVolatile(obj, offset);
+        }
+
+        @SuppressWarnings("unchecked")
+        public final V getAndSet(T obj, V newValue) {
+            accessCheck(obj);
+            valueCheck(newValue);
+            return (V)U.getAndSetObject(obj, offset, newValue);
+        }
+    }
+}
diff --git a/java/util/concurrent/atomic/AtomicStampedReference.java b/java/util/concurrent/atomic/AtomicStampedReference.java
new file mode 100644
index 0000000..40ceeb2
--- /dev/null
+++ b/java/util/concurrent/atomic/AtomicStampedReference.java
@@ -0,0 +1,207 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+/**
+ * An {@code AtomicStampedReference} maintains an object reference
+ * along with an integer "stamp", that can be updated atomically.
+ *
+ * <p>Implementation note: This implementation maintains stamped
+ * references by creating internal objects representing "boxed"
+ * [reference, integer] pairs.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ * @param <V> The type of object referred to by this reference
+ */
+public class AtomicStampedReference<V> {
+
+    private static class Pair<T> {
+        final T reference;
+        final int stamp;
+        private Pair(T reference, int stamp) {
+            this.reference = reference;
+            this.stamp = stamp;
+        }
+        static <T> Pair<T> of(T reference, int stamp) {
+            return new Pair<T>(reference, stamp);
+        }
+    }
+
+    private volatile Pair<V> pair;
+
+    /**
+     * Creates a new {@code AtomicStampedReference} with the given
+     * initial values.
+     *
+     * @param initialRef the initial reference
+     * @param initialStamp the initial stamp
+     */
+    public AtomicStampedReference(V initialRef, int initialStamp) {
+        pair = Pair.of(initialRef, initialStamp);
+    }
+
+    /**
+     * Returns the current value of the reference.
+     *
+     * @return the current value of the reference
+     */
+    public V getReference() {
+        return pair.reference;
+    }
+
+    /**
+     * Returns the current value of the stamp.
+     *
+     * @return the current value of the stamp
+     */
+    public int getStamp() {
+        return pair.stamp;
+    }
+
+    /**
+     * Returns the current values of both the reference and the stamp.
+     * Typical usage is {@code int[1] holder; ref = v.get(holder); }.
+     *
+     * @param stampHolder an array of size of at least one.  On return,
+     * {@code stampHolder[0]} will hold the value of the stamp.
+     * @return the current value of the reference
+     */
+    public V get(int[] stampHolder) {
+        Pair<V> pair = this.pair;
+        stampHolder[0] = pair.stamp;
+        return pair.reference;
+    }
+
+    /**
+     * Atomically sets the value of both the reference and stamp
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current stamp is equal to the expected stamp.
+     *
+     * <p><a href="package-summary.html#weakCompareAndSet">May fail
+     * spuriously and does not provide ordering guarantees</a>, so is
+     * only rarely an appropriate alternative to {@code compareAndSet}.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedStamp the expected value of the stamp
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean weakCompareAndSet(V   expectedReference,
+                                     V   newReference,
+                                     int expectedStamp,
+                                     int newStamp) {
+        return compareAndSet(expectedReference, newReference,
+                             expectedStamp, newStamp);
+    }
+
+    /**
+     * Atomically sets the value of both the reference and stamp
+     * to the given update values if the
+     * current reference is {@code ==} to the expected reference
+     * and the current stamp is equal to the expected stamp.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newReference the new value for the reference
+     * @param expectedStamp the expected value of the stamp
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean compareAndSet(V   expectedReference,
+                                 V   newReference,
+                                 int expectedStamp,
+                                 int newStamp) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            expectedStamp == current.stamp &&
+            ((newReference == current.reference &&
+              newStamp == current.stamp) ||
+             casPair(current, Pair.of(newReference, newStamp)));
+    }
+
+    /**
+     * Unconditionally sets the value of both the reference and stamp.
+     *
+     * @param newReference the new value for the reference
+     * @param newStamp the new value for the stamp
+     */
+    public void set(V newReference, int newStamp) {
+        Pair<V> current = pair;
+        if (newReference != current.reference || newStamp != current.stamp)
+            this.pair = Pair.of(newReference, newStamp);
+    }
+
+    /**
+     * Atomically sets the value of the stamp to the given update value
+     * if the current reference is {@code ==} to the expected
+     * reference.  Any given invocation of this operation may fail
+     * (return {@code false}) spuriously, but repeated invocation
+     * when the current value holds the expected value and no other
+     * thread is also attempting to set the value will eventually
+     * succeed.
+     *
+     * @param expectedReference the expected value of the reference
+     * @param newStamp the new value for the stamp
+     * @return {@code true} if successful
+     */
+    public boolean attemptStamp(V expectedReference, int newStamp) {
+        Pair<V> current = pair;
+        return
+            expectedReference == current.reference &&
+            (newStamp == current.stamp ||
+             casPair(current, Pair.of(expectedReference, newStamp)));
+    }
+
+    // Unsafe mechanics
+
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PAIR;
+    static {
+        try {
+            PAIR = U.objectFieldOffset
+                (AtomicStampedReference.class.getDeclaredField("pair"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+    private boolean casPair(Pair<V> cmp, Pair<V> val) {
+        return U.compareAndSwapObject(this, PAIR, cmp, val);
+    }
+}
diff --git a/java/util/concurrent/atomic/DoubleAccumulator.java b/java/util/concurrent/atomic/DoubleAccumulator.java
new file mode 100644
index 0000000..f3e3531
--- /dev/null
+++ b/java/util/concurrent/atomic/DoubleAccumulator.java
@@ -0,0 +1,299 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+import java.util.function.DoubleBinaryOperator;
+
+/**
+ * One or more variables that together maintain a running {@code double}
+ * value updated using a supplied function.  When updates (method
+ * {@link #accumulate}) are contended across threads, the set of variables
+ * may grow dynamically to reduce contention.  Method {@link #get}
+ * (or, equivalently, {@link #doubleValue}) returns the current value
+ * across the variables maintaining updates.
+ *
+ * <p>This class is usually preferable to alternatives when multiple
+ * threads update a common value that is used for purposes such as
+ * summary statistics that are frequently updated but less frequently
+ * read.
+ *
+ * <p>The supplied accumulator function should be side-effect-free,
+ * since it may be re-applied when attempted updates fail due to
+ * contention among threads. The function is applied with the current
+ * value as its first argument, and the given update as the second
+ * argument.  For example, to maintain a running maximum value, you
+ * could supply {@code Double::max} along with {@code
+ * Double.NEGATIVE_INFINITY} as the identity. The order of
+ * accumulation within or across threads is not guaranteed. Thus, this
+ * class may not be applicable if numerical stability is required,
+ * especially when combining values of substantially different orders
+ * of magnitude.
+ *
+ * <p>Class {@link DoubleAdder} provides analogs of the functionality
+ * of this class for the common special case of maintaining sums.  The
+ * call {@code new DoubleAdder()} is equivalent to {@code new
+ * DoubleAccumulator((x, y) -> x + y, 0.0)}.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class DoubleAccumulator extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    private final DoubleBinaryOperator function;
+    private final long identity; // use long representation
+
+    /**
+     * Creates a new instance using the given accumulator function
+     * and identity element.
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @param identity identity (initial value) for the accumulator function
+     */
+    public DoubleAccumulator(DoubleBinaryOperator accumulatorFunction,
+                             double identity) {
+        this.function = accumulatorFunction;
+        base = this.identity = Double.doubleToRawLongBits(identity);
+    }
+
+    /**
+     * Updates with the given value.
+     *
+     * @param x the value
+     */
+    public void accumulate(double x) {
+        Cell[] as; long b, v, r; int m; Cell a;
+        if ((as = cells) != null ||
+            (r = Double.doubleToRawLongBits
+             (function.applyAsDouble
+              (Double.longBitsToDouble(b = base), x))) != b  && !casBase(b, r)) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended =
+                  (r = Double.doubleToRawLongBits
+                   (function.applyAsDouble
+                    (Double.longBitsToDouble(v = a.value), x))) == v ||
+                  a.cas(v, r)))
+                doubleAccumulate(x, function, uncontended);
+        }
+    }
+
+    /**
+     * Returns the current value.  The returned value is <em>NOT</em>
+     * an atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the value is being calculated might not be
+     * incorporated.
+     *
+     * @return the current value
+     */
+    public double get() {
+        Cell[] as = cells;
+        double result = Double.longBitsToDouble(base);
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    result = function.applyAsDouble
+                        (result, Double.longBitsToDouble(a.value));
+        }
+        return result;
+    }
+
+    /**
+     * Resets variables maintaining updates to the identity value.
+     * This method may be a useful alternative to creating a new
+     * updater, but is only effective if there are no concurrent
+     * updates.  Because this method is intrinsically racy, it should
+     * only be used when it is known that no threads are concurrently
+     * updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = identity;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset(identity);
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #get} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the value before reset
+     */
+    public double getThenReset() {
+        Cell[] as = cells;
+        double result = Double.longBitsToDouble(base);
+        base = identity;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    double v = Double.longBitsToDouble(a.value);
+                    a.reset(identity);
+                    result = function.applyAsDouble(result, v);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Double.toString(get());
+    }
+
+    /**
+     * Equivalent to {@link #get}.
+     *
+     * @return the current value
+     */
+    public double doubleValue() {
+        return get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code long}
+     * after a narrowing primitive conversion.
+     */
+    public long longValue() {
+        return (long)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code float}
+     * after a narrowing primitive conversion.
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by get().
+         * @serial
+         */
+        private final double value;
+
+        /**
+         * The function used for updates.
+         * @serial
+         */
+        private final DoubleBinaryOperator function;
+
+        /**
+         * The identity value, represented as a long, as converted by
+         * {@link Double#doubleToRawLongBits}.  The original identity
+         * can be recovered using {@link Double#longBitsToDouble}.
+         * @serial
+         */
+        private final long identity;
+
+        SerializationProxy(double value,
+                           DoubleBinaryOperator function,
+                           long identity) {
+            this.value = value;
+            this.function = function;
+            this.identity = identity;
+        }
+
+        /**
+         * Returns a {@code DoubleAccumulator} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code DoubleAccumulator} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            double d = Double.longBitsToDouble(identity);
+            DoubleAccumulator a = new DoubleAccumulator(function, d);
+            a.base = Double.doubleToRawLongBits(value);
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAccumulator.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(get(), function, identity);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/DoubleAdder.java b/java/util/concurrent/atomic/DoubleAdder.java
new file mode 100644
index 0000000..57bd8c5
--- /dev/null
+++ b/java/util/concurrent/atomic/DoubleAdder.java
@@ -0,0 +1,266 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code double} sum.  When updates (method {@link #add}) are
+ * contended across threads, the set of variables may grow dynamically
+ * to reduce contention.  Method {@link #sum} (or, equivalently {@link
+ * #doubleValue}) returns the current total combined across the
+ * variables maintaining the sum. The order of accumulation within or
+ * across threads is not guaranteed. Thus, this class may not be
+ * applicable if numerical stability is required, especially when
+ * combining values of substantially different orders of magnitude.
+ *
+ * <p>This class is usually preferable to alternatives when multiple
+ * threads update a common value that is used for purposes such as
+ * summary statistics that are frequently updated but less frequently
+ * read.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class DoubleAdder extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    /*
+     * Note that we must use "long" for underlying representations,
+     * because there is no compareAndSet for double, due to the fact
+     * that the bitwise equals used in any CAS implementation is not
+     * the same as double-precision equals.  However, we use CAS only
+     * to detect and alleviate contention, for which bitwise equals
+     * works best anyway. In principle, the long/double conversions
+     * used here should be essentially free on most platforms since
+     * they just re-interpret bits.
+     */
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public DoubleAdder() {
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(double x) {
+        Cell[] as; long b, v; int m; Cell a;
+        if ((as = cells) != null ||
+            !casBase(b = base,
+                     Double.doubleToRawLongBits
+                     (Double.longBitsToDouble(b) + x))) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended = a.cas(v = a.value,
+                                      Double.doubleToRawLongBits
+                                      (Double.longBitsToDouble(v) + x))))
+                doubleAccumulate(x, null, uncontended);
+        }
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.  Also, because floating-point arithmetic is not
+     * strictly associative, the returned result need not be identical
+     * to the value that would be obtained in a sequential series of
+     * updates to a single variable.
+     *
+     * @return the sum
+     */
+    public double sum() {
+        Cell[] as = cells;
+        double sum = Double.longBitsToDouble(base);
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    sum += Double.longBitsToDouble(a.value);
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = 0L; // relies on fact that double 0 must have same rep as long
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset();
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public double sumThenReset() {
+        Cell[] as = cells;
+        double sum = Double.longBitsToDouble(base);
+        base = 0L;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    long v = a.value;
+                    a.reset();
+                    sum += Double.longBitsToDouble(v);
+                }
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Returns the String representation of the {@link #sum}.
+     * @return the String representation of the {@link #sum}
+     */
+    public String toString() {
+        return Double.toString(sum());
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public double doubleValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code long} after a
+     * narrowing primitive conversion.
+     */
+    public long longValue() {
+        return (long)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a
+     * narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a narrowing primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by sum().
+         * @serial
+         */
+        private final double value;
+
+        SerializationProxy(DoubleAdder a) {
+            value = a.sum();
+        }
+
+        /**
+         * Returns a {@code DoubleAdder} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code DoubleAdder} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            DoubleAdder a = new DoubleAdder();
+            a.base = Double.doubleToRawLongBits(value);
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.DoubleAdder.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(this);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/LongAccumulator.java b/java/util/concurrent/atomic/LongAccumulator.java
new file mode 100644
index 0000000..0e9a8f5
--- /dev/null
+++ b/java/util/concurrent/atomic/LongAccumulator.java
@@ -0,0 +1,293 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * One or more variables that together maintain a running {@code long}
+ * value updated using a supplied function.  When updates (method
+ * {@link #accumulate}) are contended across threads, the set of variables
+ * may grow dynamically to reduce contention.  Method {@link #get}
+ * (or, equivalently, {@link #longValue}) returns the current value
+ * across the variables maintaining updates.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common value that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>The order of accumulation within or across threads is not
+ * guaranteed and cannot be depended upon, so this class is only
+ * applicable to functions for which the order of accumulation does
+ * not matter. The supplied accumulator function should be
+ * side-effect-free, since it may be re-applied when attempted updates
+ * fail due to contention among threads. The function is applied with
+ * the current value as its first argument, and the given update as
+ * the second argument.  For example, to maintain a running maximum
+ * value, you could supply {@code Long::max} along with {@code
+ * Long.MIN_VALUE} as the identity.
+ *
+ * <p>Class {@link LongAdder} provides analogs of the functionality of
+ * this class for the common special case of maintaining counts and
+ * sums.  The call {@code new LongAdder()} is equivalent to {@code new
+ * LongAccumulator((x, y) -> x + y, 0L}.
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAccumulator extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    private final LongBinaryOperator function;
+    private final long identity;
+
+    /**
+     * Creates a new instance using the given accumulator function
+     * and identity element.
+     * @param accumulatorFunction a side-effect-free function of two arguments
+     * @param identity identity (initial value) for the accumulator function
+     */
+    public LongAccumulator(LongBinaryOperator accumulatorFunction,
+                           long identity) {
+        this.function = accumulatorFunction;
+        base = this.identity = identity;
+    }
+
+    /**
+     * Updates with the given value.
+     *
+     * @param x the value
+     */
+    public void accumulate(long x) {
+        Cell[] as; long b, v, r; int m; Cell a;
+        if ((as = cells) != null ||
+            (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended =
+                  (r = function.applyAsLong(v = a.value, x)) == v ||
+                  a.cas(v, r)))
+                longAccumulate(x, function, uncontended);
+        }
+    }
+
+    /**
+     * Returns the current value.  The returned value is <em>NOT</em>
+     * an atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the value is being calculated might not be
+     * incorporated.
+     *
+     * @return the current value
+     */
+    public long get() {
+        Cell[] as = cells;
+        long result = base;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    result = function.applyAsLong(result, a.value);
+        }
+        return result;
+    }
+
+    /**
+     * Resets variables maintaining updates to the identity value.
+     * This method may be a useful alternative to creating a new
+     * updater, but is only effective if there are no concurrent
+     * updates.  Because this method is intrinsically racy, it should
+     * only be used when it is known that no threads are concurrently
+     * updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = identity;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset(identity);
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #get} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the value before reset
+     */
+    public long getThenReset() {
+        Cell[] as = cells;
+        long result = base;
+        base = identity;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    long v = a.value;
+                    a.reset(identity);
+                    result = function.applyAsLong(result, v);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the String representation of the current value.
+     * @return the String representation of the current value
+     */
+    public String toString() {
+        return Long.toString(get());
+    }
+
+    /**
+     * Equivalent to {@link #get}.
+     *
+     * @return the current value
+     */
+    public long longValue() {
+        return get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as an {@code int}
+     * after a narrowing primitive conversion.
+     */
+    public int intValue() {
+        return (int)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)get();
+    }
+
+    /**
+     * Returns the {@linkplain #get current value} as a {@code double}
+     * after a widening primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)get();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by get().
+         * @serial
+         */
+        private final long value;
+
+        /**
+         * The function used for updates.
+         * @serial
+         */
+        private final LongBinaryOperator function;
+
+        /**
+         * The identity value.
+         * @serial
+         */
+        private final long identity;
+
+        SerializationProxy(long value,
+                           LongBinaryOperator function,
+                           long identity) {
+            this.value = value;
+            this.function = function;
+            this.identity = identity;
+        }
+
+        /**
+         * Returns a {@code LongAccumulator} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code LongAccumulator} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            LongAccumulator a = new LongAccumulator(function, identity);
+            a.base = value;
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAccumulator.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(get(), function, identity);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/LongAdder.java b/java/util/concurrent/atomic/LongAdder.java
new file mode 100644
index 0000000..0248fad
--- /dev/null
+++ b/java/util/concurrent/atomic/LongAdder.java
@@ -0,0 +1,267 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code long} sum.  When updates (method {@link #add}) are contended
+ * across threads, the set of variables may grow dynamically to reduce
+ * contention. Method {@link #sum} (or, equivalently, {@link
+ * #longValue}) returns the current total combined across the
+ * variables maintaining the sum.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common sum that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>LongAdders can be used with a {@link
+ * java.util.concurrent.ConcurrentHashMap} to maintain a scalable
+ * frequency map (a form of histogram or multiset). For example, to
+ * add a count to a {@code ConcurrentHashMap<String,LongAdder> freqs},
+ * initializing if not already present, you can use {@code
+ * freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAdder extends Striped64 implements Serializable {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public LongAdder() {
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(long x) {
+        Cell[] as; long b, v; int m; Cell a;
+        if ((as = cells) != null || !casBase(b = base, b + x)) {
+            boolean uncontended = true;
+            if (as == null || (m = as.length - 1) < 0 ||
+                (a = as[getProbe() & m]) == null ||
+                !(uncontended = a.cas(v = a.value, v + x)))
+                longAccumulate(x, null, uncontended);
+        }
+    }
+
+    /**
+     * Equivalent to {@code add(1)}.
+     */
+    public void increment() {
+        add(1L);
+    }
+
+    /**
+     * Equivalent to {@code add(-1)}.
+     */
+    public void decrement() {
+        add(-1L);
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.
+     *
+     * @return the sum
+     */
+    public long sum() {
+        Cell[] as = cells;
+        long sum = base;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    sum += a.value;
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] as = cells;
+        base = 0L;
+        if (as != null) {
+            for (Cell a : as)
+                if (a != null)
+                    a.reset();
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public long sumThenReset() {
+        Cell[] as = cells;
+        long sum = base;
+        base = 0L;
+        if (as != null) {
+            for (Cell a : as) {
+                if (a != null) {
+                    sum += a.value;
+                    a.reset();
+                }
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Returns the String representation of the {@link #sum}.
+     * @return the String representation of the {@link #sum}
+     */
+    public String toString() {
+        return Long.toString(sum());
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public long longValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a narrowing
+     * primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code double} after a widening
+     * primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)sum();
+    }
+
+    /**
+     * Serialization proxy, used to avoid reference to the non-public
+     * Striped64 superclass in serialized forms.
+     * @serial include
+     */
+    private static class SerializationProxy implements Serializable {
+        private static final long serialVersionUID = 7249069246863182397L;
+
+        /**
+         * The current value returned by sum().
+         * @serial
+         */
+        private final long value;
+
+        SerializationProxy(LongAdder a) {
+            value = a.sum();
+        }
+
+        /**
+         * Returns a {@code LongAdder} object with initial state
+         * held by this proxy.
+         *
+         * @return a {@code LongAdder} object with initial state
+         * held by this proxy
+         */
+        private Object readResolve() {
+            LongAdder a = new LongAdder();
+            a.base = value;
+            return a;
+        }
+    }
+
+    /**
+     * Returns a
+     * <a href="../../../../serialized-form.html#java.util.concurrent.atomic.LongAdder.SerializationProxy">
+     * SerializationProxy</a>
+     * representing the state of this instance.
+     *
+     * @return a {@link SerializationProxy}
+     * representing the state of this instance
+     */
+    private Object writeReplace() {
+        return new SerializationProxy(this);
+    }
+
+    /**
+     * @param s the stream
+     * @throws java.io.InvalidObjectException always
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.InvalidObjectException {
+        throw new java.io.InvalidObjectException("Proxy required");
+    }
+
+}
diff --git a/java/util/concurrent/atomic/Striped64.java b/java/util/concurrent/atomic/Striped64.java
new file mode 100644
index 0000000..2a8f327
--- /dev/null
+++ b/java/util/concurrent/atomic/Striped64.java
@@ -0,0 +1,395 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.util.Arrays;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.LongBinaryOperator;
+
+/**
+ * A package-local class holding common representation and mechanics
+ * for classes supporting dynamic striping on 64bit values. The class
+ * extends Number so that concrete subclasses must publicly do so.
+ */
+@SuppressWarnings("serial")
+abstract class Striped64 extends Number {
+    /*
+     * This class maintains a lazily-initialized table of atomically
+     * updated variables, plus an extra "base" field. The table size
+     * is a power of two. Indexing uses masked per-thread hash codes.
+     * Nearly all declarations in this class are package-private,
+     * accessed directly by subclasses.
+     *
+     * Table entries are of class Cell; a variant of AtomicLong padded
+     * (via @Contended) to reduce cache contention. Padding is
+     * overkill for most Atomics because they are usually irregularly
+     * scattered in memory and thus don't interfere much with each
+     * other. But Atomic objects residing in arrays will tend to be
+     * placed adjacent to each other, and so will most often share
+     * cache lines (with a huge negative performance impact) without
+     * this precaution.
+     *
+     * In part because Cells are relatively large, we avoid creating
+     * them until they are needed.  When there is no contention, all
+     * updates are made to the base field.  Upon first contention (a
+     * failed CAS on base update), the table is initialized to size 2.
+     * The table size is doubled upon further contention until
+     * reaching the nearest power of two greater than or equal to the
+     * number of CPUS. Table slots remain empty (null) until they are
+     * needed.
+     *
+     * A single spinlock ("cellsBusy") is used for initializing and
+     * resizing the table, as well as populating slots with new Cells.
+     * There is no need for a blocking lock; when the lock is not
+     * available, threads try other slots (or the base).  During these
+     * retries, there is increased contention and reduced locality,
+     * which is still better than alternatives.
+     *
+     * The Thread probe fields maintained via ThreadLocalRandom serve
+     * as per-thread hash codes. We let them remain uninitialized as
+     * zero (if they come in this way) until they contend at slot
+     * 0. They are then initialized to values that typically do not
+     * often conflict with others.  Contention and/or table collisions
+     * are indicated by failed CASes when performing an update
+     * operation. Upon a collision, if the table size is less than
+     * the capacity, it is doubled in size unless some other thread
+     * holds the lock. If a hashed slot is empty, and lock is
+     * available, a new Cell is created. Otherwise, if the slot
+     * exists, a CAS is tried.  Retries proceed by "double hashing",
+     * using a secondary hash (Marsaglia XorShift) to try to find a
+     * free slot.
+     *
+     * The table size is capped because, when there are more threads
+     * than CPUs, supposing that each thread were bound to a CPU,
+     * there would exist a perfect hash function mapping threads to
+     * slots that eliminates collisions. When we reach capacity, we
+     * search for this mapping by randomly varying the hash codes of
+     * colliding threads.  Because search is random, and collisions
+     * only become known via CAS failures, convergence can be slow,
+     * and because threads are typically not bound to CPUS forever,
+     * may not occur at all. However, despite these limitations,
+     * observed contention rates are typically low in these cases.
+     *
+     * It is possible for a Cell to become unused when threads that
+     * once hashed to it terminate, as well as in the case where
+     * doubling the table causes no thread to hash to it under
+     * expanded mask.  We do not try to detect or remove such cells,
+     * under the assumption that for long-running instances, observed
+     * contention levels will recur, so the cells will eventually be
+     * needed again; and for short-lived ones, it does not matter.
+     */
+
+    /**
+     * Padded variant of AtomicLong supporting only raw accesses plus CAS.
+     *
+     * JVM intrinsics note: It would be possible to use a release-only
+     * form of CAS here, if it were provided.
+     */
+    // Android-removed: @Contended, this hint is not used by the Android runtime.
+    // @jdk.internal.vm.annotation.Contended
+    static final class Cell {
+        volatile long value;
+        Cell(long x) { value = x; }
+        final boolean cas(long cmp, long val) {
+            return U.compareAndSwapLong(this, VALUE, cmp, val);
+        }
+        final void reset() {
+            U.putLongVolatile(this, VALUE, 0L);
+        }
+        final void reset(long identity) {
+            U.putLongVolatile(this, VALUE, identity);
+        }
+
+        // Unsafe mechanics
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long VALUE;
+        static {
+            try {
+                VALUE = U.objectFieldOffset
+                    (Cell.class.getDeclaredField("value"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /** Number of CPUS, to place bound on table size */
+    static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /**
+     * Table of cells. When non-null, size is a power of 2.
+     */
+    transient volatile Cell[] cells;
+
+    /**
+     * Base value, used mainly when there is no contention, but also as
+     * a fallback during table initialization races. Updated via CAS.
+     */
+    transient volatile long base;
+
+    /**
+     * Spinlock (locked via CAS) used when resizing and/or creating Cells.
+     */
+    transient volatile int cellsBusy;
+
+    /**
+     * Package-private default constructor.
+     */
+    Striped64() {
+    }
+
+    /**
+     * CASes the base field.
+     */
+    final boolean casBase(long cmp, long val) {
+        return U.compareAndSwapLong(this, BASE, cmp, val);
+    }
+
+    /**
+     * CASes the cellsBusy field from 0 to 1 to acquire lock.
+     */
+    final boolean casCellsBusy() {
+        return U.compareAndSwapInt(this, CELLSBUSY, 0, 1);
+    }
+
+    /**
+     * Returns the probe value for the current thread.
+     * Duplicated from ThreadLocalRandom because of packaging restrictions.
+     */
+    static final int getProbe() {
+        return U.getInt(Thread.currentThread(), PROBE);
+    }
+
+    /**
+     * Pseudo-randomly advances and records the given probe value for the
+     * given thread.
+     * Duplicated from ThreadLocalRandom because of packaging restrictions.
+     */
+    static final int advanceProbe(int probe) {
+        probe ^= probe << 13;   // xorshift
+        probe ^= probe >>> 17;
+        probe ^= probe << 5;
+        U.putInt(Thread.currentThread(), PROBE, probe);
+        return probe;
+    }
+
+    /**
+     * Handles cases of updates involving initialization, resizing,
+     * creating new Cells, and/or contention. See above for
+     * explanation. This method suffers the usual non-modularity
+     * problems of optimistic retry code, relying on rechecked sets of
+     * reads.
+     *
+     * @param x the value
+     * @param fn the update function, or null for add (this convention
+     * avoids the need for an extra field or function in LongAdder).
+     * @param wasUncontended false if CAS failed before call
+     */
+    final void longAccumulate(long x, LongBinaryOperator fn,
+                              boolean wasUncontended) {
+        int h;
+        if ((h = getProbe()) == 0) {
+            ThreadLocalRandom.current(); // force initialization
+            h = getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        done: for (;;) {
+            Cell[] as; Cell a; int n; long v;
+            if ((as = cells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {       // Try to attach new Cell
+                        Cell r = new Cell(x);   // Optimistically create
+                        if (cellsBusy == 0 && casCellsBusy()) {
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = cells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    break done;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (a.cas(v = a.value,
+                               (fn == null) ? v + x : fn.applyAsLong(v, x)))
+                    break;
+                else if (n >= NCPU || cells != as)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 && casCellsBusy()) {
+                    try {
+                        if (cells == as)        // Expand table unless stale
+                            cells = Arrays.copyOf(as, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
+                try {                           // Initialize table
+                    if (cells == as) {
+                        Cell[] rs = new Cell[2];
+                        rs[h & 1] = new Cell(x);
+                        cells = rs;
+                        break done;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+            }
+            // Fall back on using base
+            else if (casBase(v = base,
+                             (fn == null) ? v + x : fn.applyAsLong(v, x)))
+                break done;
+        }
+    }
+
+    private static long apply(DoubleBinaryOperator fn, long v, double x) {
+        double d = Double.longBitsToDouble(v);
+        d = (fn == null) ? d + x : fn.applyAsDouble(d, x);
+        return Double.doubleToRawLongBits(d);
+    }
+
+    /**
+     * Same as longAccumulate, but injecting long/double conversions
+     * in too many places to sensibly merge with long version, given
+     * the low-overhead requirements of this class. So must instead be
+     * maintained by copy/paste/adapt.
+     */
+    final void doubleAccumulate(double x, DoubleBinaryOperator fn,
+                                boolean wasUncontended) {
+        int h;
+        if ((h = getProbe()) == 0) {
+            ThreadLocalRandom.current(); // force initialization
+            h = getProbe();
+            wasUncontended = true;
+        }
+        boolean collide = false;                // True if last slot nonempty
+        done: for (;;) {
+            Cell[] as; Cell a; int n; long v;
+            if ((as = cells) != null && (n = as.length) > 0) {
+                if ((a = as[(n - 1) & h]) == null) {
+                    if (cellsBusy == 0) {       // Try to attach new Cell
+                        Cell r = new Cell(Double.doubleToRawLongBits(x));
+                        if (cellsBusy == 0 && casCellsBusy()) {
+                            try {               // Recheck under lock
+                                Cell[] rs; int m, j;
+                                if ((rs = cells) != null &&
+                                    (m = rs.length) > 0 &&
+                                    rs[j = (m - 1) & h] == null) {
+                                    rs[j] = r;
+                                    break done;
+                                }
+                            } finally {
+                                cellsBusy = 0;
+                            }
+                            continue;           // Slot is now non-empty
+                        }
+                    }
+                    collide = false;
+                }
+                else if (!wasUncontended)       // CAS already known to fail
+                    wasUncontended = true;      // Continue after rehash
+                else if (a.cas(v = a.value, apply(fn, v, x)))
+                    break;
+                else if (n >= NCPU || cells != as)
+                    collide = false;            // At max size or stale
+                else if (!collide)
+                    collide = true;
+                else if (cellsBusy == 0 && casCellsBusy()) {
+                    try {
+                        if (cells == as)        // Expand table unless stale
+                            cells = Arrays.copyOf(as, n << 1);
+                    } finally {
+                        cellsBusy = 0;
+                    }
+                    collide = false;
+                    continue;                   // Retry with expanded table
+                }
+                h = advanceProbe(h);
+            }
+            else if (cellsBusy == 0 && cells == as && casCellsBusy()) {
+                try {                           // Initialize table
+                    if (cells == as) {
+                        Cell[] rs = new Cell[2];
+                        rs[h & 1] = new Cell(Double.doubleToRawLongBits(x));
+                        cells = rs;
+                        break done;
+                    }
+                } finally {
+                    cellsBusy = 0;
+                }
+            }
+            // Fall back on using base
+            else if (casBase(v = base, apply(fn, v, x)))
+                break done;
+        }
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long BASE;
+    private static final long CELLSBUSY;
+    private static final long PROBE;
+    static {
+        try {
+            BASE = U.objectFieldOffset
+                (Striped64.class.getDeclaredField("base"));
+            CELLSBUSY = U.objectFieldOffset
+                (Striped64.class.getDeclaredField("cellsBusy"));
+
+            PROBE = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/atomic/package-info.java b/java/util/concurrent/atomic/package-info.java
new file mode 100644
index 0000000..a8e1ff3
--- /dev/null
+++ b/java/util/concurrent/atomic/package-info.java
@@ -0,0 +1,213 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * A small toolkit of classes that support lock-free thread-safe
+ * programming on single variables.  In essence, the classes in this
+ * package extend the notion of {@code volatile} values, fields, and
+ * array elements to those that also provide an atomic conditional update
+ * operation of the form:
+ *
+ * <pre> {@code boolean compareAndSet(expectedValue, updateValue);}</pre>
+ *
+ * <p>This method (which varies in argument types across different
+ * classes) atomically sets a variable to the {@code updateValue} if it
+ * currently holds the {@code expectedValue}, reporting {@code true} on
+ * success.  The classes in this package also contain methods to get and
+ * unconditionally set values, as well as a weaker conditional atomic
+ * update operation {@code weakCompareAndSet} described below.
+ *
+ * <p>The specifications of these methods enable implementations to
+ * employ efficient machine-level atomic instructions that are available
+ * on contemporary processors.  However on some platforms, support may
+ * entail some form of internal locking.  Thus the methods are not
+ * strictly guaranteed to be non-blocking --
+ * a thread may block transiently before performing the operation.
+ *
+ * <p>Instances of classes
+ * {@link java.util.concurrent.atomic.AtomicBoolean},
+ * {@link java.util.concurrent.atomic.AtomicInteger},
+ * {@link java.util.concurrent.atomic.AtomicLong}, and
+ * {@link java.util.concurrent.atomic.AtomicReference}
+ * each provide access and updates to a single variable of the
+ * corresponding type.  Each class also provides appropriate utility
+ * methods for that type.  For example, classes {@code AtomicLong} and
+ * {@code AtomicInteger} provide atomic increment methods.  One
+ * application is to generate sequence numbers, as in:
+ *
+ * <pre> {@code
+ * class Sequencer {
+ *   private final AtomicLong sequenceNumber
+ *     = new AtomicLong(0);
+ *   public long next() {
+ *     return sequenceNumber.getAndIncrement();
+ *   }
+ * }}</pre>
+ *
+ * <p>It is straightforward to define new utility functions that, like
+ * {@code getAndIncrement}, apply a function to a value atomically.
+ * For example, given some transformation
+ * <pre> {@code long transform(long input)}</pre>
+ *
+ * write your utility method as follows:
+ * <pre> {@code
+ * long getAndTransform(AtomicLong var) {
+ *   long prev, next;
+ *   do {
+ *     prev = var.get();
+ *     next = transform(prev);
+ *   } while (!var.compareAndSet(prev, next));
+ *   return prev; // return next; for transformAndGet
+ * }}</pre>
+ *
+ * <p>The memory effects for accesses and updates of atomics generally
+ * follow the rules for volatiles, as stated in
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
+ * Chapter 17 of
+ * <cite>The Java&trade; Language Specification</cite></a>:
+ *
+ * <ul>
+ *
+ *   <li>{@code get} has the memory effects of reading a
+ * {@code volatile} variable.
+ *
+ *   <li>{@code set} has the memory effects of writing (assigning) a
+ * {@code volatile} variable.
+ *
+ *   <li>{@code lazySet} has the memory effects of writing (assigning)
+ *   a {@code volatile} variable except that it permits reorderings with
+ *   subsequent (but not previous) memory actions that do not themselves
+ *   impose reordering constraints with ordinary non-{@code volatile}
+ *   writes.  Among other usage contexts, {@code lazySet} may apply when
+ *   nulling out, for the sake of garbage collection, a reference that is
+ *   never accessed again.
+ *
+ *   <li>{@code weakCompareAndSet} atomically reads and conditionally
+ *   writes a variable but does <em>not</em>
+ *   create any happens-before orderings, so provides no guarantees
+ *   with respect to previous or subsequent reads and writes of any
+ *   variables other than the target of the {@code weakCompareAndSet}.
+ *
+ *   <li>{@code compareAndSet}
+ *   and all other read-and-update operations such as {@code getAndIncrement}
+ *   have the memory effects of both reading and
+ *   writing {@code volatile} variables.
+ * </ul>
+ *
+ * <p>In addition to classes representing single values, this package
+ * contains <em>Updater</em> classes that can be used to obtain
+ * {@code compareAndSet} operations on any selected {@code volatile}
+ * field of any selected class.
+ *
+ * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
+ * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
+ * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
+ * reflection-based utilities that provide access to the associated
+ * field types.  These are mainly of use in atomic data structures in
+ * which several {@code volatile} fields of the same node (for
+ * example, the links of a tree node) are independently subject to
+ * atomic updates.  These classes enable greater flexibility in how
+ * and when to use atomic updates, at the expense of more awkward
+ * reflection-based setup, less convenient usage, and weaker
+ * guarantees.
+ *
+ * <p>The
+ * {@link java.util.concurrent.atomic.AtomicIntegerArray},
+ * {@link java.util.concurrent.atomic.AtomicLongArray}, and
+ * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
+ * further extend atomic operation support to arrays of these types.
+ * These classes are also notable in providing {@code volatile} access
+ * semantics for their array elements, which is not supported for
+ * ordinary arrays.
+ *
+ * <p id="weakCompareAndSet">The atomic classes also support method
+ * {@code weakCompareAndSet}, which has limited applicability.  On some
+ * platforms, the weak version may be more efficient than {@code
+ * compareAndSet} in the normal case, but differs in that any given
+ * invocation of the {@code weakCompareAndSet} method may return {@code
+ * false} <em>spuriously</em> (that is, for no apparent reason).  A
+ * {@code false} return means only that the operation may be retried if
+ * desired, relying on the guarantee that repeated invocation when the
+ * variable holds {@code expectedValue} and no other thread is also
+ * attempting to set the variable will eventually succeed.  (Such
+ * spurious failures may for example be due to memory contention effects
+ * that are unrelated to whether the expected and current values are
+ * equal.)  Additionally {@code weakCompareAndSet} does not provide
+ * ordering guarantees that are usually needed for synchronization
+ * control.  However, the method may be useful for updating counters and
+ * statistics when such updates are unrelated to the other
+ * happens-before orderings of a program.  When a thread sees an update
+ * to an atomic variable caused by a {@code weakCompareAndSet}, it does
+ * not necessarily see updates to any <em>other</em> variables that
+ * occurred before the {@code weakCompareAndSet}.  This may be
+ * acceptable when, for example, updating performance statistics, but
+ * rarely otherwise.
+ *
+ * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
+ * class associates a single boolean with a reference.  For example, this
+ * bit might be used inside a data structure to mean that the object
+ * being referenced has logically been deleted.
+ *
+ * The {@link java.util.concurrent.atomic.AtomicStampedReference}
+ * class associates an integer value with a reference.  This may be
+ * used for example, to represent version numbers corresponding to
+ * series of updates.
+ *
+ * <p>Atomic classes are designed primarily as building blocks for
+ * implementing non-blocking data structures and related infrastructure
+ * classes.  The {@code compareAndSet} method is not a general
+ * replacement for locking.  It applies only when critical updates for an
+ * object are confined to a <em>single</em> variable.
+ *
+ * <p>Atomic classes are not general purpose replacements for
+ * {@code java.lang.Integer} and related classes.  They do <em>not</em>
+ * define methods such as {@code equals}, {@code hashCode} and
+ * {@code compareTo}.  (Because atomic variables are expected to be
+ * mutated, they are poor choices for hash table keys.)  Additionally,
+ * classes are provided only for those types that are commonly useful in
+ * intended applications.  For example, there is no atomic class for
+ * representing {@code byte}.  In those infrequent cases where you would
+ * like to do so, you can use an {@code AtomicInteger} to hold
+ * {@code byte} values, and cast appropriately.
+ *
+ * You can also hold floats using
+ * {@link java.lang.Float#floatToRawIntBits} and
+ * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
+ * {@link java.lang.Double#doubleToRawLongBits} and
+ * {@link java.lang.Double#longBitsToDouble} conversions.
+ *
+ * @since 1.5
+ */
+package java.util.concurrent.atomic;
diff --git a/java/util/concurrent/locks/AbstractOwnableSynchronizer.java b/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
new file mode 100644
index 0000000..30dec97
--- /dev/null
+++ b/java/util/concurrent/locks/AbstractOwnableSynchronizer.java
@@ -0,0 +1,86 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * A synchronizer that may be exclusively owned by a thread.  This
+ * class provides a basis for creating locks and related synchronizers
+ * that may entail a notion of ownership.  The
+ * {@code AbstractOwnableSynchronizer} class itself does not manage or
+ * use this information. However, subclasses and tools may use
+ * appropriately maintained values to help control and monitor access
+ * and provide diagnostics.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    /** Use serial ID even though all fields transient. */
+    private static final long serialVersionUID = 3737899427754241961L;
+
+    /**
+     * Empty constructor for use by subclasses.
+     */
+    protected AbstractOwnableSynchronizer() { }
+
+    /**
+     * The current owner of exclusive mode synchronization.
+     */
+    private transient Thread exclusiveOwnerThread;
+
+    /**
+     * Sets the thread that currently owns exclusive access.
+     * A {@code null} argument indicates that no thread owns access.
+     * This method does not otherwise impose any synchronization or
+     * {@code volatile} field accesses.
+     * @param thread the owner thread
+     */
+    protected final void setExclusiveOwnerThread(Thread thread) {
+        exclusiveOwnerThread = thread;
+    }
+
+    /**
+     * Returns the thread last set by {@code setExclusiveOwnerThread},
+     * or {@code null} if never set.  This method does not otherwise
+     * impose any synchronization or {@code volatile} field accesses.
+     * @return the owner thread
+     */
+    protected final Thread getExclusiveOwnerThread() {
+        return exclusiveOwnerThread;
+    }
+}
diff --git a/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
new file mode 100644
index 0000000..fb610fb
--- /dev/null
+++ b/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -0,0 +1,1859 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
+
+/**
+ * A version of {@link AbstractQueuedSynchronizer} in
+ * which synchronization state is maintained as a {@code long}.
+ * This class has exactly the same structure, properties, and methods
+ * as {@code AbstractQueuedSynchronizer} with the exception
+ * that all state-related parameters and results are defined
+ * as {@code long} rather than {@code int}. This class
+ * may be useful when creating synchronizers such as
+ * multilevel locks and barriers that require
+ * 64 bits of state.
+ *
+ * <p>See {@link AbstractQueuedSynchronizer} for usage
+ * notes and examples.
+ *
+ * @since 1.6
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedLongSynchronizer
+    extends AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7373984972572414692L;
+
+    /*
+      To keep sources in sync, the remainder of this source file is
+      exactly cloned from AbstractQueuedSynchronizer, replacing class
+      name and changing ints related with sync state to longs. Please
+      keep it that way.
+    */
+
+    /**
+     * Creates a new {@code AbstractQueuedLongSynchronizer} instance
+     * with initial synchronization state of zero.
+     */
+    protected AbstractQueuedLongSynchronizer() { }
+
+    /**
+     * Head of the wait queue, lazily initialized.  Except for
+     * initialization, it is modified only via method setHead.  Note:
+     * If head exists, its waitStatus is guaranteed not to be
+     * CANCELLED.
+     */
+    private transient volatile Node head;
+
+    /**
+     * Tail of the wait queue, lazily initialized.  Modified only via
+     * method enq to add new wait node.
+     */
+    private transient volatile Node tail;
+
+    /**
+     * The synchronization state.
+     */
+    private volatile long state;
+
+    /**
+     * Returns the current value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} read.
+     * @return current state value
+     */
+    protected final long getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} write.
+     * @param newState the new state value
+     */
+    protected final void setState(long newState) {
+        // Use putLongVolatile instead of ordinary volatile store when
+        // using compareAndSwapLong, for sake of some 32bit systems.
+        U.putLongVolatile(this, STATE, newState);
+    }
+
+    /**
+     * Atomically sets synchronization state to the given updated
+     * value if the current state value equals the expected value.
+     * This operation has memory semantics of a {@code volatile} read
+     * and write.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual
+     *         value was not equal to the expected value.
+     */
+    protected final boolean compareAndSetState(long expect, long update) {
+        return U.compareAndSwapLong(this, STATE, expect, update);
+    }
+
+    // Queuing utilities
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices
+     * to improve responsiveness with very short timeouts.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+
+    /**
+     * Inserts node into queue, initializing if necessary. See picture above.
+     * @param node the node to insert
+     * @return node's predecessor
+     */
+    private Node enq(Node node) {
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return oldTail;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Creates and enqueues node for current thread and given mode.
+     *
+     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
+     * @return the new node
+     */
+    private Node addWaiter(Node mode) {
+        Node node = new Node(mode);
+
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return node;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Sets head of queue to be node, thus dequeuing. Called only by
+     * acquire methods.  Also nulls out unused fields for sake of GC
+     * and to suppress unnecessary signals and traversals.
+     *
+     * @param node the node
+     */
+    private void setHead(Node node) {
+        head = node;
+        node.thread = null;
+        node.prev = null;
+    }
+
+    /**
+     * Wakes up node's successor, if one exists.
+     *
+     * @param node the node
+     */
+    private void unparkSuccessor(Node node) {
+        /*
+         * If status is negative (i.e., possibly needing signal) try
+         * to clear in anticipation of signalling.  It is OK if this
+         * fails or if status is changed by waiting thread.
+         */
+        int ws = node.waitStatus;
+        if (ws < 0)
+            node.compareAndSetWaitStatus(ws, 0);
+
+        /*
+         * Thread to unpark is held in successor, which is normally
+         * just the next node.  But if cancelled or apparently null,
+         * traverse backwards from tail to find the actual
+         * non-cancelled successor.
+         */
+        Node s = node.next;
+        if (s == null || s.waitStatus > 0) {
+            s = null;
+            for (Node p = tail; p != node && p != null; p = p.prev)
+                if (p.waitStatus <= 0)
+                    s = p;
+        }
+        if (s != null)
+            LockSupport.unpark(s.thread);
+    }
+
+    /**
+     * Release action for shared mode -- signals successor and ensures
+     * propagation. (Note: For exclusive mode, release just amounts
+     * to calling unparkSuccessor of head if it needs signal.)
+     */
+    private void doReleaseShared() {
+        /*
+         * Ensure that a release propagates, even if there are other
+         * in-progress acquires/releases.  This proceeds in the usual
+         * way of trying to unparkSuccessor of head if it needs
+         * signal. But if it does not, status is set to PROPAGATE to
+         * ensure that upon release, propagation continues.
+         * Additionally, we must loop in case a new node is added
+         * while we are doing this. Also, unlike other uses of
+         * unparkSuccessor, we need to know if CAS to reset status
+         * fails, if so rechecking.
+         */
+        for (;;) {
+            Node h = head;
+            if (h != null && h != tail) {
+                int ws = h.waitStatus;
+                if (ws == Node.SIGNAL) {
+                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
+                        continue;            // loop to recheck cases
+                    unparkSuccessor(h);
+                }
+                else if (ws == 0 &&
+                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
+                    continue;                // loop on failed CAS
+            }
+            if (h == head)                   // loop if head changed
+                break;
+        }
+    }
+
+    /**
+     * Sets head of queue, and checks if successor may be waiting
+     * in shared mode, if so propagating if either propagate > 0 or
+     * PROPAGATE status was set.
+     *
+     * @param node the node
+     * @param propagate the return value from a tryAcquireShared
+     */
+    private void setHeadAndPropagate(Node node, long propagate) {
+        Node h = head; // Record old head for check below
+        setHead(node);
+        /*
+         * Try to signal next queued node if:
+         *   Propagation was indicated by caller,
+         *     or was recorded (as h.waitStatus either before
+         *     or after setHead) by a previous operation
+         *     (note: this uses sign-check of waitStatus because
+         *      PROPAGATE status may transition to SIGNAL.)
+         * and
+         *   The next node is waiting in shared mode,
+         *     or we don't know, because it appears null
+         *
+         * The conservatism in both of these checks may cause
+         * unnecessary wake-ups, but only when there are multiple
+         * racing acquires/releases, so most need signals now or soon
+         * anyway.
+         */
+        if (propagate > 0 || h == null || h.waitStatus < 0 ||
+            (h = head) == null || h.waitStatus < 0) {
+            Node s = node.next;
+            if (s == null || s.isShared())
+                doReleaseShared();
+        }
+    }
+
+    // Utilities for various versions of acquire
+
+    /**
+     * Cancels an ongoing attempt to acquire.
+     *
+     * @param node the node
+     */
+    private void cancelAcquire(Node node) {
+        // Ignore if node doesn't exist
+        if (node == null)
+            return;
+
+        node.thread = null;
+
+        // Skip cancelled predecessors
+        Node pred = node.prev;
+        while (pred.waitStatus > 0)
+            node.prev = pred = pred.prev;
+
+        // predNext is the apparent node to unsplice. CASes below will
+        // fail if not, in which case, we lost race vs another cancel
+        // or signal, so no further action is necessary.
+        Node predNext = pred.next;
+
+        // Can use unconditional write instead of CAS here.
+        // After this atomic step, other Nodes can skip past us.
+        // Before, we are free of interference from other threads.
+        node.waitStatus = Node.CANCELLED;
+
+        // If we are the tail, remove ourselves.
+        if (node == tail && compareAndSetTail(node, pred)) {
+            pred.compareAndSetNext(predNext, null);
+        } else {
+            // If successor needs signal, try to set pred's next-link
+            // so it will get one. Otherwise wake it up to propagate.
+            int ws;
+            if (pred != head &&
+                ((ws = pred.waitStatus) == Node.SIGNAL ||
+                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
+                pred.thread != null) {
+                Node next = node.next;
+                if (next != null && next.waitStatus <= 0)
+                    pred.compareAndSetNext(predNext, next);
+            } else {
+                unparkSuccessor(node);
+            }
+
+            node.next = node; // help GC
+        }
+    }
+
+    /**
+     * Checks and updates status for a node that failed to acquire.
+     * Returns true if thread should block. This is the main signal
+     * control in all acquire loops.  Requires that pred == node.prev.
+     *
+     * @param pred node's predecessor holding status
+     * @param node the node
+     * @return {@code true} if thread should block
+     */
+    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
+        int ws = pred.waitStatus;
+        if (ws == Node.SIGNAL)
+            /*
+             * This node has already set status asking a release
+             * to signal it, so it can safely park.
+             */
+            return true;
+        if (ws > 0) {
+            /*
+             * Predecessor was cancelled. Skip over predecessors and
+             * indicate retry.
+             */
+            do {
+                node.prev = pred = pred.prev;
+            } while (pred.waitStatus > 0);
+            pred.next = node;
+        } else {
+            /*
+             * waitStatus must be 0 or PROPAGATE.  Indicate that we
+             * need a signal, but don't park yet.  Caller will need to
+             * retry to make sure it cannot acquire before parking.
+             */
+            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
+        }
+        return false;
+    }
+
+    /**
+     * Convenience method to interrupt current thread.
+     */
+    static void selfInterrupt() {
+        Thread.currentThread().interrupt();
+    }
+
+    /**
+     * Convenience method to park and then check if interrupted.
+     *
+     * @return {@code true} if interrupted
+     */
+    private final boolean parkAndCheckInterrupt() {
+        LockSupport.park(this);
+        return Thread.interrupted();
+    }
+
+    /*
+     * Various flavors of acquire, varying in exclusive/shared and
+     * control modes.  Each is mostly the same, but annoyingly
+     * different.  Only a little bit of factoring is possible due to
+     * interactions of exception mechanics (including ensuring that we
+     * cancel if tryAcquire throws exception) and other control, at
+     * least not without hurting performance too much.
+     */
+
+    /**
+     * Acquires in exclusive uninterruptible mode for thread already in
+     * queue. Used by condition wait methods as well as acquire.
+     *
+     * @param node the node
+     * @param arg the acquire argument
+     * @return {@code true} if interrupted while waiting
+     */
+    final boolean acquireQueued(final Node node, long arg) {
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return interrupted;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireInterruptibly(long arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return true;
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared uninterruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireShared(long arg) {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    long r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        if (interrupted)
+                            selfInterrupt();
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireSharedInterruptibly(long arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    long r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireSharedNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    long r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return true;
+                    }
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    // Main exported methods
+
+    /**
+     * Attempts to acquire in exclusive mode. This method should query
+     * if the state of the object permits it to be acquired in the
+     * exclusive mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread. This can be used
+     * to implement method {@link Lock#tryLock()}.
+     *
+     * <p>The default
+     * implementation throws {@link UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return {@code true} if successful. Upon success, this object has
+     *         been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryAcquire(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in exclusive
+     * mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this object is now in a fully released
+     *         state, so that any waiting threads may attempt to acquire;
+     *         and {@code false} otherwise.
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryRelease(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode. This method should query if
+     * the state of the object permits it to be acquired in the shared
+     * mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return a negative value on failure; zero if acquisition in shared
+     *         mode succeeded but no subsequent shared-mode acquire can
+     *         succeed; and a positive value if acquisition in shared
+     *         mode succeeded and subsequent shared-mode acquires might
+     *         also succeed, in which case a subsequent waiting thread
+     *         must check availability. (Support for three different
+     *         return values enables this method to be used in contexts
+     *         where acquires only sometimes act exclusively.)  Upon
+     *         success, this object has been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected long tryAcquireShared(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in shared mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this release of shared mode may permit a
+     *         waiting acquire (shared or exclusive) to succeed; and
+     *         {@code false} otherwise
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected boolean tryReleaseShared(long arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns {@code true} if synchronization is held exclusively with
+     * respect to the current (calling) thread.  This method is invoked
+     * upon each call to a non-waiting {@link ConditionObject} method.
+     * (Waiting methods instead invoke {@link #release}.)
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}. This method is invoked
+     * internally only within {@link ConditionObject} methods, so need
+     * not be defined if conditions are not used.
+     *
+     * @return {@code true} if synchronization is held exclusively;
+     *         {@code false} otherwise
+     * @throws UnsupportedOperationException if conditions are not supported
+     */
+    protected boolean isHeldExclusively() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Acquires in exclusive mode, ignoring interrupts.  Implemented
+     * by invoking at least once {@link #tryAcquire},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquire} until success.  This method can be used
+     * to implement method {@link Lock#lock}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     */
+    public final void acquire(long arg) {
+        if (!tryAcquire(arg) &&
+            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+            selfInterrupt();
+    }
+
+    /**
+     * Acquires in exclusive mode, aborting if interrupted.
+     * Implemented by first checking interrupt status, then invoking
+     * at least once {@link #tryAcquire}, returning on
+     * success.  Otherwise the thread is queued, possibly repeatedly
+     * blocking and unblocking, invoking {@link #tryAcquire}
+     * until success or the thread is interrupted.  This method can be
+     * used to implement method {@link Lock#lockInterruptibly}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireInterruptibly(long arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (!tryAcquire(arg))
+            doAcquireInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in exclusive mode, aborting if interrupted,
+     * and failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquire}, returning on success.  Otherwise, the thread is
+     * queued, possibly repeatedly blocking and unblocking, invoking
+     * {@link #tryAcquire} until success or the thread is interrupted
+     * or the timeout elapses.  This method can be used to implement
+     * method {@link Lock#tryLock(long, TimeUnit)}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquire(arg) ||
+            doAcquireNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in exclusive mode.  Implemented by unblocking one or
+     * more threads if {@link #tryRelease} returns true.
+     * This method can be used to implement method {@link Lock#unlock}.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryRelease} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @return the value returned from {@link #tryRelease}
+     */
+    public final boolean release(long arg) {
+        if (tryRelease(arg)) {
+            Node h = head;
+            if (h != null && h.waitStatus != 0)
+                unparkSuccessor(h);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires in shared mode, ignoring interrupts.  Implemented by
+     * first invoking at least once {@link #tryAcquireShared},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquireShared} until success.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     */
+    public final void acquireShared(long arg) {
+        if (tryAcquireShared(arg) < 0)
+            doAcquireShared(arg);
+    }
+
+    /**
+     * Acquires in shared mode, aborting if interrupted.  Implemented
+     * by first checking interrupt status, then invoking at least once
+     * {@link #tryAcquireShared}, returning on success.  Otherwise the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted.
+     * @param arg the acquire argument.
+     * This value is conveyed to {@link #tryAcquireShared} but is
+     * otherwise uninterpreted and can represent anything
+     * you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireSharedInterruptibly(long arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (tryAcquireShared(arg) < 0)
+            doAcquireSharedInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in shared mode, aborting if interrupted, and
+     * failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquireShared}, returning on success.  Otherwise, the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted or the timeout elapses.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquireShared(arg) >= 0 ||
+            doAcquireSharedNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in shared mode.  Implemented by unblocking one or more
+     * threads if {@link #tryReleaseShared} returns true.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryReleaseShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return the value returned from {@link #tryReleaseShared}
+     */
+    public final boolean releaseShared(long arg) {
+        if (tryReleaseShared(arg)) {
+            doReleaseShared();
+            return true;
+        }
+        return false;
+    }
+
+    // Queue inspection methods
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations due to interrupts and timeouts may occur
+     * at any time, a {@code true} return does not guarantee that any
+     * other thread will ever acquire.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there may be other threads waiting to acquire
+     */
+    public final boolean hasQueuedThreads() {
+        return head != tail;
+    }
+
+    /**
+     * Queries whether any threads have ever contended to acquire this
+     * synchronizer; that is, if an acquire method has ever blocked.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there has ever been contention
+     */
+    public final boolean hasContended() {
+        return head != null;
+    }
+
+    /**
+     * Returns the first (longest-waiting) thread in the queue, or
+     * {@code null} if no threads are currently queued.
+     *
+     * <p>In this implementation, this operation normally returns in
+     * constant time, but may iterate upon contention if other threads are
+     * concurrently modifying the queue.
+     *
+     * @return the first (longest-waiting) thread in the queue, or
+     *         {@code null} if no threads are currently queued
+     */
+    public final Thread getFirstQueuedThread() {
+        // handle only fast path, else relay
+        return (head == tail) ? null : fullGetFirstQueuedThread();
+    }
+
+    /**
+     * Version of getFirstQueuedThread called when fastpath fails.
+     */
+    private Thread fullGetFirstQueuedThread() {
+        /*
+         * The first node is normally head.next. Try to get its
+         * thread field, ensuring consistent reads: If thread
+         * field is nulled out or s.prev is no longer head, then
+         * some other thread(s) concurrently performed setHead in
+         * between some of our reads. We try this twice before
+         * resorting to traversal.
+         */
+        Node h, s;
+        Thread st;
+        if (((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null) ||
+            ((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null))
+            return st;
+
+        /*
+         * Head's next field might not have been set yet, or may have
+         * been unset after setHead. So we must check to see if tail
+         * is actually first node. If not, we continue on, safely
+         * traversing from tail back to head to find first,
+         * guaranteeing termination.
+         */
+
+        Thread firstThread = null;
+        for (Node p = tail; p != null && p != head; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                firstThread = t;
+        }
+        return firstThread;
+    }
+
+    /**
+     * Returns true if the given thread is currently queued.
+     *
+     * <p>This implementation traverses the queue to determine
+     * presence of the given thread.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is on the queue
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean isQueued(Thread thread) {
+        if (thread == null)
+            throw new NullPointerException();
+        for (Node p = tail; p != null; p = p.prev)
+            if (p.thread == thread)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the apparent first queued thread, if one
+     * exists, is waiting in exclusive mode.  If this method returns
+     * {@code true}, and the current thread is attempting to acquire in
+     * shared mode (that is, this method is invoked from {@link
+     * #tryAcquireShared}) then it is guaranteed that the current thread
+     * is not the first queued thread.  Used only as a heuristic in
+     * ReentrantReadWriteLock.
+     */
+    final boolean apparentlyFirstQueuedIsExclusive() {
+        Node h, s;
+        return (h = head) != null &&
+            (s = h.next)  != null &&
+            !s.isShared()         &&
+            s.thread != null;
+    }
+
+    /**
+     * Queries whether any threads have been waiting to acquire longer
+     * than the current thread.
+     *
+     * <p>An invocation of this method is equivalent to (but may be
+     * more efficient than):
+     * <pre> {@code
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
+     *
+     * <p>Note that because cancellations due to interrupts and
+     * timeouts may occur at any time, a {@code true} return does not
+     * guarantee that some other thread will acquire before the current
+     * thread.  Likewise, it is possible for another thread to win a
+     * race to enqueue after this method has returned {@code false},
+     * due to the queue being empty.
+     *
+     * <p>This method is designed to be used by a fair synchronizer to
+     * avoid <a href="AbstractQueuedSynchronizer.html#barging">barging</a>.
+     * Such a synchronizer's {@link #tryAcquire} method should return
+     * {@code false}, and its {@link #tryAcquireShared} method should
+     * return a negative value, if this method returns {@code true}
+     * (unless this is a reentrant acquire).  For example, the {@code
+     * tryAcquire} method for a fair, reentrant, exclusive mode
+     * synchronizer might look like this:
+     *
+     * <pre> {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if there is a queued thread preceding the
+     *         current thread, and {@code false} if the current thread
+     *         is at the head of the queue or the queue is empty
+     * @since 1.7
+     */
+    public final boolean hasQueuedPredecessors() {
+        // The correctness of this depends on head being initialized
+        // before tail and on head.next being accurate if the current
+        // thread is first in queue.
+        Node t = tail; // Read fields in reverse initialization order
+        Node h = head;
+        Node s;
+        return h != t &&
+            ((s = h.next) == null || s.thread != Thread.currentThread());
+    }
+
+
+    // Instrumentation and monitoring methods
+
+    /**
+     * Returns an estimate of the number of threads waiting to
+     * acquire.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting to acquire
+     */
+    public final int getQueueLength() {
+        int n = 0;
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.thread != null)
+                ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                list.add(t);
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in exclusive mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to an exclusive acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getExclusiveQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (!p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in shared mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to a shared acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getSharedQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a string identifying this synchronizer, as well as its state.
+     * The state, in brackets, includes the String {@code "State ="}
+     * followed by the current value of {@link #getState}, and either
+     * {@code "nonempty"} or {@code "empty"} depending on whether the
+     * queue is empty.
+     *
+     * @return a string identifying this synchronizer, as well as its state
+     */
+    public String toString() {
+        return super.toString()
+            + "[State = " + getState() + ", "
+            + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+    }
+
+
+    // Internal support methods for Conditions
+
+    /**
+     * Returns true if a node, always one that was initially placed on
+     * a condition queue, is now waiting to reacquire on sync queue.
+     * @param node the node
+     * @return true if is reacquiring
+     */
+    final boolean isOnSyncQueue(Node node) {
+        if (node.waitStatus == Node.CONDITION || node.prev == null)
+            return false;
+        if (node.next != null) // If has successor, it must be on queue
+            return true;
+        /*
+         * node.prev can be non-null, but not yet on queue because
+         * the CAS to place it on queue can fail. So we have to
+         * traverse from tail to make sure it actually made it.  It
+         * will always be near the tail in calls to this method, and
+         * unless the CAS failed (which is unlikely), it will be
+         * there, so we hardly ever traverse much.
+         */
+        return findNodeFromTail(node);
+    }
+
+    /**
+     * Returns true if node is on sync queue by searching backwards from tail.
+     * Called only when needed by isOnSyncQueue.
+     * @return true if present
+     */
+    private boolean findNodeFromTail(Node node) {
+        // We check for node first, since it's likely to be at or near tail.
+        // tail is known to be non-null, so we could re-order to "save"
+        // one null check, but we leave it this way to help the VM.
+        for (Node p = tail;;) {
+            if (p == node)
+                return true;
+            if (p == null)
+                return false;
+            p = p.prev;
+        }
+    }
+
+    /**
+     * Transfers a node from a condition queue onto sync queue.
+     * Returns true if successful.
+     * @param node the node
+     * @return true if successfully transferred (else the node was
+     * cancelled before signal)
+     */
+    final boolean transferForSignal(Node node) {
+        /*
+         * If cannot change waitStatus, the node has been cancelled.
+         */
+        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
+            return false;
+
+        /*
+         * Splice onto queue and try to set waitStatus of predecessor to
+         * indicate that thread is (probably) waiting. If cancelled or
+         * attempt to set waitStatus fails, wake up to resync (in which
+         * case the waitStatus can be transiently and harmlessly wrong).
+         */
+        Node p = enq(node);
+        int ws = p.waitStatus;
+        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
+            LockSupport.unpark(node.thread);
+        return true;
+    }
+
+    /**
+     * Transfers node, if necessary, to sync queue after a cancelled wait.
+     * Returns true if thread was cancelled before being signalled.
+     *
+     * @param node the node
+     * @return true if cancelled before the node was signalled
+     */
+    final boolean transferAfterCancelledWait(Node node) {
+        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
+            enq(node);
+            return true;
+        }
+        /*
+         * If we lost out to a signal(), then we can't proceed
+         * until it finishes its enq().  Cancelling during an
+         * incomplete transfer is both rare and transient, so just
+         * spin.
+         */
+        while (!isOnSyncQueue(node))
+            Thread.yield();
+        return false;
+    }
+
+    /**
+     * Invokes release with current state value; returns saved state.
+     * Cancels node and throws exception on failure.
+     * @param node the condition node for this wait
+     * @return previous sync state
+     */
+    final long fullyRelease(Node node) {
+        try {
+            long savedState = getState();
+            if (release(savedState))
+                return savedState;
+            throw new IllegalMonitorStateException();
+        } catch (Throwable t) {
+            node.waitStatus = Node.CANCELLED;
+            throw t;
+        }
+    }
+
+    // Instrumentation methods for conditions
+
+    /**
+     * Queries whether the given ConditionObject
+     * uses this synchronizer as its lock.
+     *
+     * @param condition the condition
+     * @return {@code true} if owned
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean owns(ConditionObject condition) {
+        return condition.isOwnedBy(this);
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this synchronizer. Note that because timeouts
+     * and interrupts may occur at any time, a {@code true} return
+     * does not guarantee that a future {@code signal} will awaken
+     * any threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean hasWaiters(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.hasWaiters();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this synchronizer. Note that
+     * because timeouts and interrupts may occur at any time, the
+     * estimate serves only as an upper bound on the actual number of
+     * waiters.  This method is designed for use in monitoring system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final int getWaitQueueLength(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitQueueLength();
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this
+     * synchronizer.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate. The elements of the
+     * returned collection are in no particular order.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitingThreads();
+    }
+
+    /**
+     * Condition implementation for a {@link
+     * AbstractQueuedLongSynchronizer} serving as the basis of a {@link
+     * Lock} implementation.
+     *
+     * <p>Method documentation for this class describes mechanics,
+     * not behavioral specifications from the point of view of Lock
+     * and Condition users. Exported versions of this class will in
+     * general need to be accompanied by documentation describing
+     * condition semantics that rely on those of the associated
+     * {@code AbstractQueuedLongSynchronizer}.
+     *
+     * <p>This class is Serializable, but all fields are transient,
+     * so deserialized conditions have no waiters.
+     *
+     * @since 1.6
+     */
+    public class ConditionObject implements Condition, java.io.Serializable {
+        private static final long serialVersionUID = 1173984872572414699L;
+        /** First node of condition queue. */
+        private transient Node firstWaiter;
+        /** Last node of condition queue. */
+        private transient Node lastWaiter;
+
+        /**
+         * Creates a new {@code ConditionObject} instance.
+         */
+        public ConditionObject() { }
+
+        // Internal methods
+
+        /**
+         * Adds a new waiter to wait queue.
+         * @return its new wait node
+         */
+        private Node addConditionWaiter() {
+            Node t = lastWaiter;
+            // If lastWaiter is cancelled, clean out.
+            if (t != null && t.waitStatus != Node.CONDITION) {
+                unlinkCancelledWaiters();
+                t = lastWaiter;
+            }
+
+            Node node = new Node(Node.CONDITION);
+
+            if (t == null)
+                firstWaiter = node;
+            else
+                t.nextWaiter = node;
+            lastWaiter = node;
+            return node;
+        }
+
+        /**
+         * Removes and transfers nodes until hit non-cancelled one or
+         * null. Split out from signal in part to encourage compilers
+         * to inline the case of no waiters.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignal(Node first) {
+            do {
+                if ( (firstWaiter = first.nextWaiter) == null)
+                    lastWaiter = null;
+                first.nextWaiter = null;
+            } while (!transferForSignal(first) &&
+                     (first = firstWaiter) != null);
+        }
+
+        /**
+         * Removes and transfers all nodes.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignalAll(Node first) {
+            lastWaiter = firstWaiter = null;
+            do {
+                Node next = first.nextWaiter;
+                first.nextWaiter = null;
+                transferForSignal(first);
+                first = next;
+            } while (first != null);
+        }
+
+        /**
+         * Unlinks cancelled waiter nodes from condition queue.
+         * Called only while holding lock. This is called when
+         * cancellation occurred during condition wait, and upon
+         * insertion of a new waiter when lastWaiter is seen to have
+         * been cancelled. This method is needed to avoid garbage
+         * retention in the absence of signals. So even though it may
+         * require a full traversal, it comes into play only when
+         * timeouts or cancellations occur in the absence of
+         * signals. It traverses all nodes rather than stopping at a
+         * particular target to unlink all pointers to garbage nodes
+         * without requiring many re-traversals during cancellation
+         * storms.
+         */
+        private void unlinkCancelledWaiters() {
+            Node t = firstWaiter;
+            Node trail = null;
+            while (t != null) {
+                Node next = t.nextWaiter;
+                if (t.waitStatus != Node.CONDITION) {
+                    t.nextWaiter = null;
+                    if (trail == null)
+                        firstWaiter = next;
+                    else
+                        trail.nextWaiter = next;
+                    if (next == null)
+                        lastWaiter = trail;
+                }
+                else
+                    trail = t;
+                t = next;
+            }
+        }
+
+        // public methods
+
+        /**
+         * Moves the longest-waiting thread, if one exists, from the
+         * wait queue for this condition to the wait queue for the
+         * owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signal() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignal(first);
+        }
+
+        /**
+         * Moves all threads from the wait queue for this condition to
+         * the wait queue for the owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signalAll() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignalAll(first);
+        }
+
+        /**
+         * Implements uninterruptible condition wait.
+         * <ol>
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * </ol>
+         */
+        public final void awaitUninterruptibly() {
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            boolean interrupted = false;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if (Thread.interrupted())
+                    interrupted = true;
+            }
+            if (acquireQueued(node, savedState) || interrupted)
+                selfInterrupt();
+        }
+
+        /*
+         * For interruptible waits, we need to track whether to throw
+         * InterruptedException, if interrupted while blocked on
+         * condition, versus reinterrupt current thread, if
+         * interrupted while blocked waiting to re-acquire.
+         */
+
+        /** Mode meaning to reinterrupt on exit from wait */
+        private static final int REINTERRUPT =  1;
+        /** Mode meaning to throw InterruptedException on exit from wait */
+        private static final int THROW_IE    = -1;
+
+        /**
+         * Checks for interrupt, returning THROW_IE if interrupted
+         * before signalled, REINTERRUPT if after signalled, or
+         * 0 if not interrupted.
+         */
+        private int checkInterruptWhileWaiting(Node node) {
+            return Thread.interrupted() ?
+                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
+                0;
+        }
+
+        /**
+         * Throws InterruptedException, reinterrupts current thread, or
+         * does nothing, depending on mode.
+         */
+        private void reportInterruptAfterWait(int interruptMode)
+            throws InterruptedException {
+            if (interruptMode == THROW_IE)
+                throw new InterruptedException();
+            else if (interruptMode == REINTERRUPT)
+                selfInterrupt();
+        }
+
+        /**
+         * Implements interruptible condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled or interrupted.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final void await() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null) // clean up if cancelled
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final long awaitNanos(long nanosTimeout)
+                throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // awaitNanos(0) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            long initialNanos = nanosTimeout;
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            long remaining = deadline - System.nanoTime(); // avoid overflow
+            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+        }
+
+        /**
+         * Implements absolute timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean awaitUntil(Date deadline)
+                throws InterruptedException {
+            long abstime = deadline.getTime();
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (System.currentTimeMillis() >= abstime) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                LockSupport.parkUntil(this, abstime);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean await(long time, TimeUnit unit)
+                throws InterruptedException {
+            long nanosTimeout = unit.toNanos(time);
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // await(0, unit) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            Node node = addConditionWaiter();
+            long savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        //  support for instrumentation
+
+        /**
+         * Returns true if this condition was created by the given
+         * synchronization object.
+         *
+         * @return {@code true} if owned
+         */
+        final boolean isOwnedBy(AbstractQueuedLongSynchronizer sync) {
+            return sync == AbstractQueuedLongSynchronizer.this;
+        }
+
+        /**
+         * Queries whether any threads are waiting on this condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#hasWaiters(ConditionObject)}.
+         *
+         * @return {@code true} if there are any waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final boolean hasWaiters() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an estimate of the number of threads waiting on
+         * this condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#getWaitQueueLength(ConditionObject)}.
+         *
+         * @return the estimated number of waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final int getWaitQueueLength() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int n = 0;
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    ++n;
+            }
+            return n;
+        }
+
+        /**
+         * Returns a collection containing those threads that may be
+         * waiting on this Condition.
+         * Implements {@link AbstractQueuedLongSynchronizer#getWaitingThreads(ConditionObject)}.
+         *
+         * @return the collection of threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final Collection<Thread> getWaitingThreads() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            ArrayList<Thread> list = new ArrayList<>();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION) {
+                    Thread t = w.thread;
+                    if (t != null)
+                        list.add(t);
+                }
+            }
+            return list;
+        }
+    }
+
+    /**
+     * Setup to support compareAndSet. We need to natively implement
+     * this here: For the sake of permitting future enhancements, we
+     * cannot explicitly subclass AtomicLong, which would be
+     * efficient and useful otherwise. So, as the lesser of evils, we
+     * natively implement using hotspot intrinsics API. And while we
+     * are at it, we do the same for other CASable fields (which could
+     * otherwise be done with atomic field updaters).
+     */
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long HEAD;
+    private static final long TAIL;
+
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (AbstractQueuedLongSynchronizer.class.getDeclaredField("state"));
+            HEAD = U.objectFieldOffset
+                (AbstractQueuedLongSynchronizer.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (AbstractQueuedLongSynchronizer.class.getDeclaredField("tail"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+    /**
+     * Initializes head and tail fields on first contention.
+     */
+    private final void initializeSyncQueue() {
+        Node h;
+        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+            tail = h;
+    }
+
+    /**
+     * CASes tail field.
+     */
+    private final boolean compareAndSetTail(Node expect, Node update) {
+        return U.compareAndSwapObject(this, TAIL, expect, update);
+    }
+}
diff --git a/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
new file mode 100644
index 0000000..602b5ce
--- /dev/null
+++ b/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -0,0 +1,2331 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Provides a framework for implementing blocking locks and related
+ * synchronizers (semaphores, events, etc) that rely on
+ * first-in-first-out (FIFO) wait queues.  This class is designed to
+ * be a useful basis for most kinds of synchronizers that rely on a
+ * single atomic {@code int} value to represent state. Subclasses
+ * must define the protected methods that change this state, and which
+ * define what that state means in terms of this object being acquired
+ * or released.  Given these, the other methods in this class carry
+ * out all queuing and blocking mechanics. Subclasses can maintain
+ * other state fields, but only the atomically updated {@code int}
+ * value manipulated using methods {@link #getState}, {@link
+ * #setState} and {@link #compareAndSetState} is tracked with respect
+ * to synchronization.
+ *
+ * <p>Subclasses should be defined as non-public internal helper
+ * classes that are used to implement the synchronization properties
+ * of their enclosing class.  Class
+ * {@code AbstractQueuedSynchronizer} does not implement any
+ * synchronization interface.  Instead it defines methods such as
+ * {@link #acquireInterruptibly} that can be invoked as
+ * appropriate by concrete locks and related synchronizers to
+ * implement their public methods.
+ *
+ * <p>This class supports either or both a default <em>exclusive</em>
+ * mode and a <em>shared</em> mode. When acquired in exclusive mode,
+ * attempted acquires by other threads cannot succeed. Shared mode
+ * acquires by multiple threads may (but need not) succeed. This class
+ * does not &quot;understand&quot; these differences except in the
+ * mechanical sense that when a shared mode acquire succeeds, the next
+ * waiting thread (if one exists) must also determine whether it can
+ * acquire as well. Threads waiting in the different modes share the
+ * same FIFO queue. Usually, implementation subclasses support only
+ * one of these modes, but both can come into play for example in a
+ * {@link ReadWriteLock}. Subclasses that support only exclusive or
+ * only shared modes need not define the methods supporting the unused mode.
+ *
+ * <p>This class defines a nested {@link ConditionObject} class that
+ * can be used as a {@link Condition} implementation by subclasses
+ * supporting exclusive mode for which method {@link
+ * #isHeldExclusively} reports whether synchronization is exclusively
+ * held with respect to the current thread, method {@link #release}
+ * invoked with the current {@link #getState} value fully releases
+ * this object, and {@link #acquire}, given this saved state value,
+ * eventually restores this object to its previous acquired state.  No
+ * {@code AbstractQueuedSynchronizer} method otherwise creates such a
+ * condition, so if this constraint cannot be met, do not use it.  The
+ * behavior of {@link ConditionObject} depends of course on the
+ * semantics of its synchronizer implementation.
+ *
+ * <p>This class provides inspection, instrumentation, and monitoring
+ * methods for the internal queue, as well as similar methods for
+ * condition objects. These can be exported as desired into classes
+ * using an {@code AbstractQueuedSynchronizer} for their
+ * synchronization mechanics.
+ *
+ * <p>Serialization of this class stores only the underlying atomic
+ * integer maintaining state, so deserialized objects have empty
+ * thread queues. Typical subclasses requiring serializability will
+ * define a {@code readObject} method that restores this to a known
+ * initial state upon deserialization.
+ *
+ * <h3>Usage</h3>
+ *
+ * <p>To use this class as the basis of a synchronizer, redefine the
+ * following methods, as applicable, by inspecting and/or modifying
+ * the synchronization state using {@link #getState}, {@link
+ * #setState} and/or {@link #compareAndSetState}:
+ *
+ * <ul>
+ * <li>{@link #tryAcquire}
+ * <li>{@link #tryRelease}
+ * <li>{@link #tryAcquireShared}
+ * <li>{@link #tryReleaseShared}
+ * <li>{@link #isHeldExclusively}
+ * </ul>
+ *
+ * Each of these methods by default throws {@link
+ * UnsupportedOperationException}.  Implementations of these methods
+ * must be internally thread-safe, and should in general be short and
+ * not block. Defining these methods is the <em>only</em> supported
+ * means of using this class. All other methods are declared
+ * {@code final} because they cannot be independently varied.
+ *
+ * <p>You may also find the inherited methods from {@link
+ * AbstractOwnableSynchronizer} useful to keep track of the thread
+ * owning an exclusive synchronizer.  You are encouraged to use them
+ * -- this enables monitoring and diagnostic tools to assist users in
+ * determining which threads hold locks.
+ *
+ * <p>Even though this class is based on an internal FIFO queue, it
+ * does not automatically enforce FIFO acquisition policies.  The core
+ * of exclusive synchronization takes the form:
+ *
+ * <pre>
+ * Acquire:
+ *     while (!tryAcquire(arg)) {
+ *        <em>enqueue thread if it is not already queued</em>;
+ *        <em>possibly block current thread</em>;
+ *     }
+ *
+ * Release:
+ *     if (tryRelease(arg))
+ *        <em>unblock the first queued thread</em>;
+ * </pre>
+ *
+ * (Shared mode is similar but may involve cascading signals.)
+ *
+ * <p id="barging">Because checks in acquire are invoked before
+ * enqueuing, a newly acquiring thread may <em>barge</em> ahead of
+ * others that are blocked and queued.  However, you can, if desired,
+ * define {@code tryAcquire} and/or {@code tryAcquireShared} to
+ * disable barging by internally invoking one or more of the inspection
+ * methods, thereby providing a <em>fair</em> FIFO acquisition order.
+ * In particular, most fair synchronizers can define {@code tryAcquire}
+ * to return {@code false} if {@link #hasQueuedPredecessors} (a method
+ * specifically designed to be used by fair synchronizers) returns
+ * {@code true}.  Other variations are possible.
+ *
+ * <p>Throughput and scalability are generally highest for the
+ * default barging (also known as <em>greedy</em>,
+ * <em>renouncement</em>, and <em>convoy-avoidance</em>) strategy.
+ * While this is not guaranteed to be fair or starvation-free, earlier
+ * queued threads are allowed to recontend before later queued
+ * threads, and each recontention has an unbiased chance to succeed
+ * against incoming threads.  Also, while acquires do not
+ * &quot;spin&quot; in the usual sense, they may perform multiple
+ * invocations of {@code tryAcquire} interspersed with other
+ * computations before blocking.  This gives most of the benefits of
+ * spins when exclusive synchronization is only briefly held, without
+ * most of the liabilities when it isn't. If so desired, you can
+ * augment this by preceding calls to acquire methods with
+ * "fast-path" checks, possibly prechecking {@link #hasContended}
+ * and/or {@link #hasQueuedThreads} to only do so if the synchronizer
+ * is likely not to be contended.
+ *
+ * <p>This class provides an efficient and scalable basis for
+ * synchronization in part by specializing its range of use to
+ * synchronizers that can rely on {@code int} state, acquire, and
+ * release parameters, and an internal FIFO wait queue. When this does
+ * not suffice, you can build synchronizers from a lower level using
+ * {@link java.util.concurrent.atomic atomic} classes, your own custom
+ * {@link java.util.Queue} classes, and {@link LockSupport} blocking
+ * support.
+ *
+ * <h3>Usage Examples</h3>
+ *
+ * <p>Here is a non-reentrant mutual exclusion lock class that uses
+ * the value zero to represent the unlocked state, and one to
+ * represent the locked state. While a non-reentrant lock
+ * does not strictly require recording of the current owner
+ * thread, this class does so anyway to make usage easier to monitor.
+ * It also supports conditions and exposes
+ * one of the instrumentation methods:
+ *
+ * <pre> {@code
+ * class Mutex implements Lock, java.io.Serializable {
+ *
+ *   // Our internal helper class
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     // Reports whether in locked state
+ *     protected boolean isHeldExclusively() {
+ *       return getState() == 1;
+ *     }
+ *
+ *     // Acquires the lock if state is zero
+ *     public boolean tryAcquire(int acquires) {
+ *       assert acquires == 1; // Otherwise unused
+ *       if (compareAndSetState(0, 1)) {
+ *         setExclusiveOwnerThread(Thread.currentThread());
+ *         return true;
+ *       }
+ *       return false;
+ *     }
+ *
+ *     // Releases the lock by setting state to zero
+ *     protected boolean tryRelease(int releases) {
+ *       assert releases == 1; // Otherwise unused
+ *       if (getState() == 0) throw new IllegalMonitorStateException();
+ *       setExclusiveOwnerThread(null);
+ *       setState(0);
+ *       return true;
+ *     }
+ *
+ *     // Provides a Condition
+ *     Condition newCondition() { return new ConditionObject(); }
+ *
+ *     // Deserializes properly
+ *     private void readObject(ObjectInputStream s)
+ *         throws IOException, ClassNotFoundException {
+ *       s.defaultReadObject();
+ *       setState(0); // reset to unlocked state
+ *     }
+ *   }
+ *
+ *   // The sync object does all the hard work. We just forward to it.
+ *   private final Sync sync = new Sync();
+ *
+ *   public void lock()                { sync.acquire(1); }
+ *   public boolean tryLock()          { return sync.tryAcquire(1); }
+ *   public void unlock()              { sync.release(1); }
+ *   public Condition newCondition()   { return sync.newCondition(); }
+ *   public boolean isLocked()         { return sync.isHeldExclusively(); }
+ *   public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
+ *   public void lockInterruptibly() throws InterruptedException {
+ *     sync.acquireInterruptibly(1);
+ *   }
+ *   public boolean tryLock(long timeout, TimeUnit unit)
+ *       throws InterruptedException {
+ *     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+ *   }
+ * }}</pre>
+ *
+ * <p>Here is a latch class that is like a
+ * {@link java.util.concurrent.CountDownLatch CountDownLatch}
+ * except that it only requires a single {@code signal} to
+ * fire. Because a latch is non-exclusive, it uses the {@code shared}
+ * acquire and release methods.
+ *
+ * <pre> {@code
+ * class BooleanLatch {
+ *
+ *   private static class Sync extends AbstractQueuedSynchronizer {
+ *     boolean isSignalled() { return getState() != 0; }
+ *
+ *     protected int tryAcquireShared(int ignore) {
+ *       return isSignalled() ? 1 : -1;
+ *     }
+ *
+ *     protected boolean tryReleaseShared(int ignore) {
+ *       setState(1);
+ *       return true;
+ *     }
+ *   }
+ *
+ *   private final Sync sync = new Sync();
+ *   public boolean isSignalled() { return sync.isSignalled(); }
+ *   public void signal()         { sync.releaseShared(1); }
+ *   public void await() throws InterruptedException {
+ *     sync.acquireSharedInterruptibly(1);
+ *   }
+ * }}</pre>
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public abstract class AbstractQueuedSynchronizer
+    extends AbstractOwnableSynchronizer
+    implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7373984972572414691L;
+
+    /**
+     * Creates a new {@code AbstractQueuedSynchronizer} instance
+     * with initial synchronization state of zero.
+     */
+    protected AbstractQueuedSynchronizer() { }
+
+    /**
+     * Wait queue node class.
+     *
+     * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
+     * Hagersten) lock queue. CLH locks are normally used for
+     * spinlocks.  We instead use them for blocking synchronizers, but
+     * use the same basic tactic of holding some of the control
+     * information about a thread in the predecessor of its node.  A
+     * "status" field in each node keeps track of whether a thread
+     * should block.  A node is signalled when its predecessor
+     * releases.  Each node of the queue otherwise serves as a
+     * specific-notification-style monitor holding a single waiting
+     * thread. The status field does NOT control whether threads are
+     * granted locks etc though.  A thread may try to acquire if it is
+     * first in the queue. But being first does not guarantee success;
+     * it only gives the right to contend.  So the currently released
+     * contender thread may need to rewait.
+     *
+     * <p>To enqueue into a CLH lock, you atomically splice it in as new
+     * tail. To dequeue, you just set the head field.
+     * <pre>
+     *      +------+  prev +-----+       +-----+
+     * head |      | <---- |     | <---- |     |  tail
+     *      +------+       +-----+       +-----+
+     * </pre>
+     *
+     * <p>Insertion into a CLH queue requires only a single atomic
+     * operation on "tail", so there is a simple atomic point of
+     * demarcation from unqueued to queued. Similarly, dequeuing
+     * involves only updating the "head". However, it takes a bit
+     * more work for nodes to determine who their successors are,
+     * in part to deal with possible cancellation due to timeouts
+     * and interrupts.
+     *
+     * <p>The "prev" links (not used in original CLH locks), are mainly
+     * needed to handle cancellation. If a node is cancelled, its
+     * successor is (normally) relinked to a non-cancelled
+     * predecessor. For explanation of similar mechanics in the case
+     * of spin locks, see the papers by Scott and Scherer at
+     * http://www.cs.rochester.edu/u/scott/synchronization/
+     *
+     * <p>We also use "next" links to implement blocking mechanics.
+     * The thread id for each node is kept in its own node, so a
+     * predecessor signals the next node to wake up by traversing
+     * next link to determine which thread it is.  Determination of
+     * successor must avoid races with newly queued nodes to set
+     * the "next" fields of their predecessors.  This is solved
+     * when necessary by checking backwards from the atomically
+     * updated "tail" when a node's successor appears to be null.
+     * (Or, said differently, the next-links are an optimization
+     * so that we don't usually need a backward scan.)
+     *
+     * <p>Cancellation introduces some conservatism to the basic
+     * algorithms.  Since we must poll for cancellation of other
+     * nodes, we can miss noticing whether a cancelled node is
+     * ahead or behind us. This is dealt with by always unparking
+     * successors upon cancellation, allowing them to stabilize on
+     * a new predecessor, unless we can identify an uncancelled
+     * predecessor who will carry this responsibility.
+     *
+     * <p>CLH queues need a dummy header node to get started. But
+     * we don't create them on construction, because it would be wasted
+     * effort if there is never contention. Instead, the node
+     * is constructed and head and tail pointers are set upon first
+     * contention.
+     *
+     * <p>Threads waiting on Conditions use the same nodes, but
+     * use an additional link. Conditions only need to link nodes
+     * in simple (non-concurrent) linked queues because they are
+     * only accessed when exclusively held.  Upon await, a node is
+     * inserted into a condition queue.  Upon signal, the node is
+     * transferred to the main queue.  A special value of status
+     * field is used to mark which queue a node is on.
+     *
+     * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+     * Scherer and Michael Scott, along with members of JSR-166
+     * expert group, for helpful ideas, discussions, and critiques
+     * on the design of this class.
+     */
+    static final class Node {
+        /** Marker to indicate a node is waiting in shared mode */
+        static final Node SHARED = new Node();
+        /** Marker to indicate a node is waiting in exclusive mode */
+        static final Node EXCLUSIVE = null;
+
+        /** waitStatus value to indicate thread has cancelled. */
+        static final int CANCELLED =  1;
+        /** waitStatus value to indicate successor's thread needs unparking. */
+        static final int SIGNAL    = -1;
+        /** waitStatus value to indicate thread is waiting on condition. */
+        static final int CONDITION = -2;
+        /**
+         * waitStatus value to indicate the next acquireShared should
+         * unconditionally propagate.
+         */
+        static final int PROPAGATE = -3;
+
+        /**
+         * Status field, taking on only the values:
+         *   SIGNAL:     The successor of this node is (or will soon be)
+         *               blocked (via park), so the current node must
+         *               unpark its successor when it releases or
+         *               cancels. To avoid races, acquire methods must
+         *               first indicate they need a signal,
+         *               then retry the atomic acquire, and then,
+         *               on failure, block.
+         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
+         *               Nodes never leave this state. In particular,
+         *               a thread with cancelled node never again blocks.
+         *   CONDITION:  This node is currently on a condition queue.
+         *               It will not be used as a sync queue node
+         *               until transferred, at which time the status
+         *               will be set to 0. (Use of this value here has
+         *               nothing to do with the other uses of the
+         *               field, but simplifies mechanics.)
+         *   PROPAGATE:  A releaseShared should be propagated to other
+         *               nodes. This is set (for head node only) in
+         *               doReleaseShared to ensure propagation
+         *               continues, even if other operations have
+         *               since intervened.
+         *   0:          None of the above
+         *
+         * The values are arranged numerically to simplify use.
+         * Non-negative values mean that a node doesn't need to
+         * signal. So, most code doesn't need to check for particular
+         * values, just for sign.
+         *
+         * The field is initialized to 0 for normal sync nodes, and
+         * CONDITION for condition nodes.  It is modified using CAS
+         * (or when possible, unconditional volatile writes).
+         */
+        volatile int waitStatus;
+
+        /**
+         * Link to predecessor node that current node/thread relies on
+         * for checking waitStatus. Assigned during enqueuing, and nulled
+         * out (for sake of GC) only upon dequeuing.  Also, upon
+         * cancellation of a predecessor, we short-circuit while
+         * finding a non-cancelled one, which will always exist
+         * because the head node is never cancelled: A node becomes
+         * head only as a result of successful acquire. A
+         * cancelled thread never succeeds in acquiring, and a thread only
+         * cancels itself, not any other node.
+         */
+        volatile Node prev;
+
+        /**
+         * Link to the successor node that the current node/thread
+         * unparks upon release. Assigned during enqueuing, adjusted
+         * when bypassing cancelled predecessors, and nulled out (for
+         * sake of GC) when dequeued.  The enq operation does not
+         * assign next field of a predecessor until after attachment,
+         * so seeing a null next field does not necessarily mean that
+         * node is at end of queue. However, if a next field appears
+         * to be null, we can scan prev's from the tail to
+         * double-check.  The next field of cancelled nodes is set to
+         * point to the node itself instead of null, to make life
+         * easier for isOnSyncQueue.
+         */
+        volatile Node next;
+
+        /**
+         * The thread that enqueued this node.  Initialized on
+         * construction and nulled out after use.
+         */
+        volatile Thread thread;
+
+        /**
+         * Link to next node waiting on condition, or the special
+         * value SHARED.  Because condition queues are accessed only
+         * when holding in exclusive mode, we just need a simple
+         * linked queue to hold nodes while they are waiting on
+         * conditions. They are then transferred to the queue to
+         * re-acquire. And because conditions can only be exclusive,
+         * we save a field by using special value to indicate shared
+         * mode.
+         */
+        Node nextWaiter;
+
+        /**
+         * Returns true if node is waiting in shared mode.
+         */
+        final boolean isShared() {
+            return nextWaiter == SHARED;
+        }
+
+        /**
+         * Returns previous node, or throws NullPointerException if null.
+         * Use when predecessor cannot be null.  The null check could
+         * be elided, but is present to help the VM.
+         *
+         * @return the predecessor of this node
+         */
+        final Node predecessor() throws NullPointerException {
+            Node p = prev;
+            if (p == null)
+                throw new NullPointerException();
+            else
+                return p;
+        }
+
+        /** Establishes initial head or SHARED marker. */
+        Node() {}
+
+        /** Constructor used by addWaiter. */
+        Node(Node nextWaiter) {
+            this.nextWaiter = nextWaiter;
+            U.putObject(this, THREAD, Thread.currentThread());
+        }
+
+        /** Constructor used by addConditionWaiter. */
+        Node(int waitStatus) {
+            U.putInt(this, WAITSTATUS, waitStatus);
+            U.putObject(this, THREAD, Thread.currentThread());
+        }
+
+        /** CASes waitStatus field. */
+        final boolean compareAndSetWaitStatus(int expect, int update) {
+            return U.compareAndSwapInt(this, WAITSTATUS, expect, update);
+        }
+
+        /** CASes next field. */
+        final boolean compareAndSetNext(Node expect, Node update) {
+            return U.compareAndSwapObject(this, NEXT, expect, update);
+        }
+
+        private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+        private static final long NEXT;
+        static final long PREV;
+        private static final long THREAD;
+        private static final long WAITSTATUS;
+        static {
+            try {
+                NEXT = U.objectFieldOffset
+                    (Node.class.getDeclaredField("next"));
+                PREV = U.objectFieldOffset
+                    (Node.class.getDeclaredField("prev"));
+                THREAD = U.objectFieldOffset
+                    (Node.class.getDeclaredField("thread"));
+                WAITSTATUS = U.objectFieldOffset
+                    (Node.class.getDeclaredField("waitStatus"));
+            } catch (ReflectiveOperationException e) {
+                throw new Error(e);
+            }
+        }
+    }
+
+    /**
+     * Head of the wait queue, lazily initialized.  Except for
+     * initialization, it is modified only via method setHead.  Note:
+     * If head exists, its waitStatus is guaranteed not to be
+     * CANCELLED.
+     */
+    private transient volatile Node head;
+
+    /**
+     * Tail of the wait queue, lazily initialized.  Modified only via
+     * method enq to add new wait node.
+     */
+    private transient volatile Node tail;
+
+    /**
+     * The synchronization state.
+     */
+    private volatile int state;
+
+    /**
+     * Returns the current value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} read.
+     * @return current state value
+     */
+    protected final int getState() {
+        return state;
+    }
+
+    /**
+     * Sets the value of synchronization state.
+     * This operation has memory semantics of a {@code volatile} write.
+     * @param newState the new state value
+     */
+    protected final void setState(int newState) {
+        state = newState;
+    }
+
+    /**
+     * Atomically sets synchronization state to the given updated
+     * value if the current state value equals the expected value.
+     * This operation has memory semantics of a {@code volatile} read
+     * and write.
+     *
+     * @param expect the expected value
+     * @param update the new value
+     * @return {@code true} if successful. False return indicates that the actual
+     *         value was not equal to the expected value.
+     */
+    protected final boolean compareAndSetState(int expect, int update) {
+        return U.compareAndSwapInt(this, STATE, expect, update);
+    }
+
+    // Queuing utilities
+
+    /**
+     * The number of nanoseconds for which it is faster to spin
+     * rather than to use timed park. A rough estimate suffices
+     * to improve responsiveness with very short timeouts.
+     */
+    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+
+    /**
+     * Inserts node into queue, initializing if necessary. See picture above.
+     * @param node the node to insert
+     * @return node's predecessor
+     */
+    private Node enq(Node node) {
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return oldTail;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Creates and enqueues node for current thread and given mode.
+     *
+     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
+     * @return the new node
+     */
+    private Node addWaiter(Node mode) {
+        Node node = new Node(mode);
+
+        for (;;) {
+            Node oldTail = tail;
+            if (oldTail != null) {
+                U.putObject(node, Node.PREV, oldTail);
+                if (compareAndSetTail(oldTail, node)) {
+                    oldTail.next = node;
+                    return node;
+                }
+            } else {
+                initializeSyncQueue();
+            }
+        }
+    }
+
+    /**
+     * Sets head of queue to be node, thus dequeuing. Called only by
+     * acquire methods.  Also nulls out unused fields for sake of GC
+     * and to suppress unnecessary signals and traversals.
+     *
+     * @param node the node
+     */
+    private void setHead(Node node) {
+        head = node;
+        node.thread = null;
+        node.prev = null;
+    }
+
+    /**
+     * Wakes up node's successor, if one exists.
+     *
+     * @param node the node
+     */
+    private void unparkSuccessor(Node node) {
+        /*
+         * If status is negative (i.e., possibly needing signal) try
+         * to clear in anticipation of signalling.  It is OK if this
+         * fails or if status is changed by waiting thread.
+         */
+        int ws = node.waitStatus;
+        if (ws < 0)
+            node.compareAndSetWaitStatus(ws, 0);
+
+        /*
+         * Thread to unpark is held in successor, which is normally
+         * just the next node.  But if cancelled or apparently null,
+         * traverse backwards from tail to find the actual
+         * non-cancelled successor.
+         */
+        Node s = node.next;
+        if (s == null || s.waitStatus > 0) {
+            s = null;
+            for (Node p = tail; p != node && p != null; p = p.prev)
+                if (p.waitStatus <= 0)
+                    s = p;
+        }
+        if (s != null)
+            LockSupport.unpark(s.thread);
+    }
+
+    /**
+     * Release action for shared mode -- signals successor and ensures
+     * propagation. (Note: For exclusive mode, release just amounts
+     * to calling unparkSuccessor of head if it needs signal.)
+     */
+    private void doReleaseShared() {
+        /*
+         * Ensure that a release propagates, even if there are other
+         * in-progress acquires/releases.  This proceeds in the usual
+         * way of trying to unparkSuccessor of head if it needs
+         * signal. But if it does not, status is set to PROPAGATE to
+         * ensure that upon release, propagation continues.
+         * Additionally, we must loop in case a new node is added
+         * while we are doing this. Also, unlike other uses of
+         * unparkSuccessor, we need to know if CAS to reset status
+         * fails, if so rechecking.
+         */
+        for (;;) {
+            Node h = head;
+            if (h != null && h != tail) {
+                int ws = h.waitStatus;
+                if (ws == Node.SIGNAL) {
+                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
+                        continue;            // loop to recheck cases
+                    unparkSuccessor(h);
+                }
+                else if (ws == 0 &&
+                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
+                    continue;                // loop on failed CAS
+            }
+            if (h == head)                   // loop if head changed
+                break;
+        }
+    }
+
+    /**
+     * Sets head of queue, and checks if successor may be waiting
+     * in shared mode, if so propagating if either propagate > 0 or
+     * PROPAGATE status was set.
+     *
+     * @param node the node
+     * @param propagate the return value from a tryAcquireShared
+     */
+    private void setHeadAndPropagate(Node node, int propagate) {
+        Node h = head; // Record old head for check below
+        setHead(node);
+        /*
+         * Try to signal next queued node if:
+         *   Propagation was indicated by caller,
+         *     or was recorded (as h.waitStatus either before
+         *     or after setHead) by a previous operation
+         *     (note: this uses sign-check of waitStatus because
+         *      PROPAGATE status may transition to SIGNAL.)
+         * and
+         *   The next node is waiting in shared mode,
+         *     or we don't know, because it appears null
+         *
+         * The conservatism in both of these checks may cause
+         * unnecessary wake-ups, but only when there are multiple
+         * racing acquires/releases, so most need signals now or soon
+         * anyway.
+         */
+        if (propagate > 0 || h == null || h.waitStatus < 0 ||
+            (h = head) == null || h.waitStatus < 0) {
+            Node s = node.next;
+            if (s == null || s.isShared())
+                doReleaseShared();
+        }
+    }
+
+    // Utilities for various versions of acquire
+
+    /**
+     * Cancels an ongoing attempt to acquire.
+     *
+     * @param node the node
+     */
+    private void cancelAcquire(Node node) {
+        // Ignore if node doesn't exist
+        if (node == null)
+            return;
+
+        node.thread = null;
+
+        // Skip cancelled predecessors
+        Node pred = node.prev;
+        while (pred.waitStatus > 0)
+            node.prev = pred = pred.prev;
+
+        // predNext is the apparent node to unsplice. CASes below will
+        // fail if not, in which case, we lost race vs another cancel
+        // or signal, so no further action is necessary.
+        Node predNext = pred.next;
+
+        // Can use unconditional write instead of CAS here.
+        // After this atomic step, other Nodes can skip past us.
+        // Before, we are free of interference from other threads.
+        node.waitStatus = Node.CANCELLED;
+
+        // If we are the tail, remove ourselves.
+        if (node == tail && compareAndSetTail(node, pred)) {
+            pred.compareAndSetNext(predNext, null);
+        } else {
+            // If successor needs signal, try to set pred's next-link
+            // so it will get one. Otherwise wake it up to propagate.
+            int ws;
+            if (pred != head &&
+                ((ws = pred.waitStatus) == Node.SIGNAL ||
+                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
+                pred.thread != null) {
+                Node next = node.next;
+                if (next != null && next.waitStatus <= 0)
+                    pred.compareAndSetNext(predNext, next);
+            } else {
+                unparkSuccessor(node);
+            }
+
+            node.next = node; // help GC
+        }
+    }
+
+    /**
+     * Checks and updates status for a node that failed to acquire.
+     * Returns true if thread should block. This is the main signal
+     * control in all acquire loops.  Requires that pred == node.prev.
+     *
+     * @param pred node's predecessor holding status
+     * @param node the node
+     * @return {@code true} if thread should block
+     */
+    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
+        int ws = pred.waitStatus;
+        if (ws == Node.SIGNAL)
+            /*
+             * This node has already set status asking a release
+             * to signal it, so it can safely park.
+             */
+            return true;
+        if (ws > 0) {
+            /*
+             * Predecessor was cancelled. Skip over predecessors and
+             * indicate retry.
+             */
+            do {
+                node.prev = pred = pred.prev;
+            } while (pred.waitStatus > 0);
+            pred.next = node;
+        } else {
+            /*
+             * waitStatus must be 0 or PROPAGATE.  Indicate that we
+             * need a signal, but don't park yet.  Caller will need to
+             * retry to make sure it cannot acquire before parking.
+             */
+            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
+        }
+        return false;
+    }
+
+    /**
+     * Convenience method to interrupt current thread.
+     */
+    static void selfInterrupt() {
+        Thread.currentThread().interrupt();
+    }
+
+    /**
+     * Convenience method to park and then check if interrupted.
+     *
+     * @return {@code true} if interrupted
+     */
+    private final boolean parkAndCheckInterrupt() {
+        LockSupport.park(this);
+        return Thread.interrupted();
+    }
+
+    /*
+     * Various flavors of acquire, varying in exclusive/shared and
+     * control modes.  Each is mostly the same, but annoyingly
+     * different.  Only a little bit of factoring is possible due to
+     * interactions of exception mechanics (including ensuring that we
+     * cancel if tryAcquire throws exception) and other control, at
+     * least not without hurting performance too much.
+     */
+
+    /**
+     * Acquires in exclusive uninterruptible mode for thread already in
+     * queue. Used by condition wait methods as well as acquire.
+     *
+     * @param node the node
+     * @param arg the acquire argument
+     * @return {@code true} if interrupted while waiting
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    final boolean acquireQueued(final Node node, int arg) {
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return interrupted;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireInterruptibly(int arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in exclusive timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.EXCLUSIVE);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head && tryAcquire(arg)) {
+                    setHead(node);
+                    p.next = null; // help GC
+                    return true;
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared uninterruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireShared(int arg) {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            boolean interrupted = false;
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    int r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        if (interrupted)
+                            selfInterrupt();
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    interrupted = true;
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared interruptible mode.
+     * @param arg the acquire argument
+     */
+    private void doAcquireSharedInterruptibly(int arg)
+        throws InterruptedException {
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    int r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return;
+                    }
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    parkAndCheckInterrupt())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    /**
+     * Acquires in shared timed mode.
+     *
+     * @param arg the acquire argument
+     * @param nanosTimeout max wait time
+     * @return {@code true} if acquired
+     */
+    private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (nanosTimeout <= 0L)
+            return false;
+        final long deadline = System.nanoTime() + nanosTimeout;
+        final Node node = addWaiter(Node.SHARED);
+        try {
+            for (;;) {
+                final Node p = node.predecessor();
+                if (p == head) {
+                    int r = tryAcquireShared(arg);
+                    if (r >= 0) {
+                        setHeadAndPropagate(node, r);
+                        p.next = null; // help GC
+                        return true;
+                    }
+                }
+                nanosTimeout = deadline - System.nanoTime();
+                if (nanosTimeout <= 0L) {
+                    cancelAcquire(node);
+                    return false;
+                }
+                if (shouldParkAfterFailedAcquire(p, node) &&
+                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if (Thread.interrupted())
+                    throw new InterruptedException();
+            }
+        } catch (Throwable t) {
+            cancelAcquire(node);
+            throw t;
+        }
+    }
+
+    // Main exported methods
+
+    /**
+     * Attempts to acquire in exclusive mode. This method should query
+     * if the state of the object permits it to be acquired in the
+     * exclusive mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread. This can be used
+     * to implement method {@link Lock#tryLock()}.
+     *
+     * <p>The default
+     * implementation throws {@link UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return {@code true} if successful. Upon success, this object has
+     *         been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryAcquire(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in exclusive
+     * mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this object is now in a fully released
+     *         state, so that any waiting threads may attempt to acquire;
+     *         and {@code false} otherwise.
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if exclusive mode is not supported
+     */
+    protected boolean tryRelease(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to acquire in shared mode. This method should query if
+     * the state of the object permits it to be acquired in the shared
+     * mode, and if so to acquire it.
+     *
+     * <p>This method is always invoked by the thread performing
+     * acquire.  If this method reports failure, the acquire method
+     * may queue the thread, if it is not already queued, until it is
+     * signalled by a release from some other thread.
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}.
+     *
+     * @param arg the acquire argument. This value is always the one
+     *        passed to an acquire method, or is the value saved on entry
+     *        to a condition wait.  The value is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return a negative value on failure; zero if acquisition in shared
+     *         mode succeeded but no subsequent shared-mode acquire can
+     *         succeed; and a positive value if acquisition in shared
+     *         mode succeeded and subsequent shared-mode acquires might
+     *         also succeed, in which case a subsequent waiting thread
+     *         must check availability. (Support for three different
+     *         return values enables this method to be used in contexts
+     *         where acquires only sometimes act exclusively.)  Upon
+     *         success, this object has been acquired.
+     * @throws IllegalMonitorStateException if acquiring would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected int tryAcquireShared(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Attempts to set the state to reflect a release in shared mode.
+     *
+     * <p>This method is always invoked by the thread performing release.
+     *
+     * <p>The default implementation throws
+     * {@link UnsupportedOperationException}.
+     *
+     * @param arg the release argument. This value is always the one
+     *        passed to a release method, or the current state value upon
+     *        entry to a condition wait.  The value is otherwise
+     *        uninterpreted and can represent anything you like.
+     * @return {@code true} if this release of shared mode may permit a
+     *         waiting acquire (shared or exclusive) to succeed; and
+     *         {@code false} otherwise
+     * @throws IllegalMonitorStateException if releasing would place this
+     *         synchronizer in an illegal state. This exception must be
+     *         thrown in a consistent fashion for synchronization to work
+     *         correctly.
+     * @throws UnsupportedOperationException if shared mode is not supported
+     */
+    protected boolean tryReleaseShared(int arg) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns {@code true} if synchronization is held exclusively with
+     * respect to the current (calling) thread.  This method is invoked
+     * upon each call to a non-waiting {@link ConditionObject} method.
+     * (Waiting methods instead invoke {@link #release}.)
+     *
+     * <p>The default implementation throws {@link
+     * UnsupportedOperationException}. This method is invoked
+     * internally only within {@link ConditionObject} methods, so need
+     * not be defined if conditions are not used.
+     *
+     * @return {@code true} if synchronization is held exclusively;
+     *         {@code false} otherwise
+     * @throws UnsupportedOperationException if conditions are not supported
+     */
+    protected boolean isHeldExclusively() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Acquires in exclusive mode, ignoring interrupts.  Implemented
+     * by invoking at least once {@link #tryAcquire},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquire} until success.  This method can be used
+     * to implement method {@link Lock#lock}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    public final void acquire(int arg) {
+        if (!tryAcquire(arg) &&
+            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+            selfInterrupt();
+    }
+
+    /**
+     * Acquires in exclusive mode, aborting if interrupted.
+     * Implemented by first checking interrupt status, then invoking
+     * at least once {@link #tryAcquire}, returning on
+     * success.  Otherwise the thread is queued, possibly repeatedly
+     * blocking and unblocking, invoking {@link #tryAcquire}
+     * until success or the thread is interrupted.  This method can be
+     * used to implement method {@link Lock#lockInterruptibly}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireInterruptibly(int arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (!tryAcquire(arg))
+            doAcquireInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in exclusive mode, aborting if interrupted,
+     * and failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquire}, returning on success.  Otherwise, the thread is
+     * queued, possibly repeatedly blocking and unblocking, invoking
+     * {@link #tryAcquire} until success or the thread is interrupted
+     * or the timeout elapses.  This method can be used to implement
+     * method {@link Lock#tryLock(long, TimeUnit)}.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquire} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquire(arg) ||
+            doAcquireNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in exclusive mode.  Implemented by unblocking one or
+     * more threads if {@link #tryRelease} returns true.
+     * This method can be used to implement method {@link Lock#unlock}.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryRelease} but is otherwise uninterpreted and
+     *        can represent anything you like.
+     * @return the value returned from {@link #tryRelease}
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    public final boolean release(int arg) {
+        if (tryRelease(arg)) {
+            Node h = head;
+            if (h != null && h.waitStatus != 0)
+                unparkSuccessor(h);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Acquires in shared mode, ignoring interrupts.  Implemented by
+     * first invoking at least once {@link #tryAcquireShared},
+     * returning on success.  Otherwise the thread is queued, possibly
+     * repeatedly blocking and unblocking, invoking {@link
+     * #tryAcquireShared} until success.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     */
+    public final void acquireShared(int arg) {
+        if (tryAcquireShared(arg) < 0)
+            doAcquireShared(arg);
+    }
+
+    /**
+     * Acquires in shared mode, aborting if interrupted.  Implemented
+     * by first checking interrupt status, then invoking at least once
+     * {@link #tryAcquireShared}, returning on success.  Otherwise the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted.
+     * @param arg the acquire argument.
+     * This value is conveyed to {@link #tryAcquireShared} but is
+     * otherwise uninterpreted and can represent anything
+     * you like.
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final void acquireSharedInterruptibly(int arg)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        if (tryAcquireShared(arg) < 0)
+            doAcquireSharedInterruptibly(arg);
+    }
+
+    /**
+     * Attempts to acquire in shared mode, aborting if interrupted, and
+     * failing if the given timeout elapses.  Implemented by first
+     * checking interrupt status, then invoking at least once {@link
+     * #tryAcquireShared}, returning on success.  Otherwise, the
+     * thread is queued, possibly repeatedly blocking and unblocking,
+     * invoking {@link #tryAcquireShared} until success or the thread
+     * is interrupted or the timeout elapses.
+     *
+     * @param arg the acquire argument.  This value is conveyed to
+     *        {@link #tryAcquireShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @param nanosTimeout the maximum number of nanoseconds to wait
+     * @return {@code true} if acquired; {@code false} if timed out
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
+            throws InterruptedException {
+        if (Thread.interrupted())
+            throw new InterruptedException();
+        return tryAcquireShared(arg) >= 0 ||
+            doAcquireSharedNanos(arg, nanosTimeout);
+    }
+
+    /**
+     * Releases in shared mode.  Implemented by unblocking one or more
+     * threads if {@link #tryReleaseShared} returns true.
+     *
+     * @param arg the release argument.  This value is conveyed to
+     *        {@link #tryReleaseShared} but is otherwise uninterpreted
+     *        and can represent anything you like.
+     * @return the value returned from {@link #tryReleaseShared}
+     */
+    // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+    // @ReservedStackAccess
+    public final boolean releaseShared(int arg) {
+        if (tryReleaseShared(arg)) {
+            doReleaseShared();
+            return true;
+        }
+        return false;
+    }
+
+    // Queue inspection methods
+
+    /**
+     * Queries whether any threads are waiting to acquire. Note that
+     * because cancellations due to interrupts and timeouts may occur
+     * at any time, a {@code true} return does not guarantee that any
+     * other thread will ever acquire.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there may be other threads waiting to acquire
+     */
+    public final boolean hasQueuedThreads() {
+        return head != tail;
+    }
+
+    /**
+     * Queries whether any threads have ever contended to acquire this
+     * synchronizer; that is, if an acquire method has ever blocked.
+     *
+     * <p>In this implementation, this operation returns in
+     * constant time.
+     *
+     * @return {@code true} if there has ever been contention
+     */
+    public final boolean hasContended() {
+        return head != null;
+    }
+
+    /**
+     * Returns the first (longest-waiting) thread in the queue, or
+     * {@code null} if no threads are currently queued.
+     *
+     * <p>In this implementation, this operation normally returns in
+     * constant time, but may iterate upon contention if other threads are
+     * concurrently modifying the queue.
+     *
+     * @return the first (longest-waiting) thread in the queue, or
+     *         {@code null} if no threads are currently queued
+     */
+    public final Thread getFirstQueuedThread() {
+        // handle only fast path, else relay
+        return (head == tail) ? null : fullGetFirstQueuedThread();
+    }
+
+    /**
+     * Version of getFirstQueuedThread called when fastpath fails.
+     */
+    private Thread fullGetFirstQueuedThread() {
+        /*
+         * The first node is normally head.next. Try to get its
+         * thread field, ensuring consistent reads: If thread
+         * field is nulled out or s.prev is no longer head, then
+         * some other thread(s) concurrently performed setHead in
+         * between some of our reads. We try this twice before
+         * resorting to traversal.
+         */
+        Node h, s;
+        Thread st;
+        if (((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null) ||
+            ((h = head) != null && (s = h.next) != null &&
+             s.prev == head && (st = s.thread) != null))
+            return st;
+
+        /*
+         * Head's next field might not have been set yet, or may have
+         * been unset after setHead. So we must check to see if tail
+         * is actually first node. If not, we continue on, safely
+         * traversing from tail back to head to find first,
+         * guaranteeing termination.
+         */
+
+        Thread firstThread = null;
+        for (Node p = tail; p != null && p != head; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                firstThread = t;
+        }
+        return firstThread;
+    }
+
+    /**
+     * Returns true if the given thread is currently queued.
+     *
+     * <p>This implementation traverses the queue to determine
+     * presence of the given thread.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is on the queue
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean isQueued(Thread thread) {
+        if (thread == null)
+            throw new NullPointerException();
+        for (Node p = tail; p != null; p = p.prev)
+            if (p.thread == thread)
+                return true;
+        return false;
+    }
+
+    /**
+     * Returns {@code true} if the apparent first queued thread, if one
+     * exists, is waiting in exclusive mode.  If this method returns
+     * {@code true}, and the current thread is attempting to acquire in
+     * shared mode (that is, this method is invoked from {@link
+     * #tryAcquireShared}) then it is guaranteed that the current thread
+     * is not the first queued thread.  Used only as a heuristic in
+     * ReentrantReadWriteLock.
+     */
+    final boolean apparentlyFirstQueuedIsExclusive() {
+        Node h, s;
+        return (h = head) != null &&
+            (s = h.next)  != null &&
+            !s.isShared()         &&
+            s.thread != null;
+    }
+
+    /**
+     * Queries whether any threads have been waiting to acquire longer
+     * than the current thread.
+     *
+     * <p>An invocation of this method is equivalent to (but may be
+     * more efficient than):
+     * <pre> {@code
+     * getFirstQueuedThread() != Thread.currentThread()
+     *   && hasQueuedThreads()}</pre>
+     *
+     * <p>Note that because cancellations due to interrupts and
+     * timeouts may occur at any time, a {@code true} return does not
+     * guarantee that some other thread will acquire before the current
+     * thread.  Likewise, it is possible for another thread to win a
+     * race to enqueue after this method has returned {@code false},
+     * due to the queue being empty.
+     *
+     * <p>This method is designed to be used by a fair synchronizer to
+     * avoid <a href="AbstractQueuedSynchronizer.html#barging">barging</a>.
+     * Such a synchronizer's {@link #tryAcquire} method should return
+     * {@code false}, and its {@link #tryAcquireShared} method should
+     * return a negative value, if this method returns {@code true}
+     * (unless this is a reentrant acquire).  For example, the {@code
+     * tryAcquire} method for a fair, reentrant, exclusive mode
+     * synchronizer might look like this:
+     *
+     * <pre> {@code
+     * protected boolean tryAcquire(int arg) {
+     *   if (isHeldExclusively()) {
+     *     // A reentrant acquire; increment hold count
+     *     return true;
+     *   } else if (hasQueuedPredecessors()) {
+     *     return false;
+     *   } else {
+     *     // try to acquire normally
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if there is a queued thread preceding the
+     *         current thread, and {@code false} if the current thread
+     *         is at the head of the queue or the queue is empty
+     * @since 1.7
+     */
+    public final boolean hasQueuedPredecessors() {
+        // The correctness of this depends on head being initialized
+        // before tail and on head.next being accurate if the current
+        // thread is first in queue.
+        Node t = tail; // Read fields in reverse initialization order
+        Node h = head;
+        Node s;
+        return h != t &&
+            ((s = h.next) == null || s.thread != Thread.currentThread());
+    }
+
+
+    // Instrumentation and monitoring methods
+
+    /**
+     * Returns an estimate of the number of threads waiting to
+     * acquire.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting to acquire
+     */
+    public final int getQueueLength() {
+        int n = 0;
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.thread != null)
+                ++n;
+        }
+        return n;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            Thread t = p.thread;
+            if (t != null)
+                list.add(t);
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in exclusive mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to an exclusive acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getExclusiveQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (!p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire in shared mode. This has the same properties
+     * as {@link #getQueuedThreads} except that it only returns
+     * those threads waiting due to a shared acquire.
+     *
+     * @return the collection of threads
+     */
+    public final Collection<Thread> getSharedQueuedThreads() {
+        ArrayList<Thread> list = new ArrayList<>();
+        for (Node p = tail; p != null; p = p.prev) {
+            if (p.isShared()) {
+                Thread t = p.thread;
+                if (t != null)
+                    list.add(t);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns a string identifying this synchronizer, as well as its state.
+     * The state, in brackets, includes the String {@code "State ="}
+     * followed by the current value of {@link #getState}, and either
+     * {@code "nonempty"} or {@code "empty"} depending on whether the
+     * queue is empty.
+     *
+     * @return a string identifying this synchronizer, as well as its state
+     */
+    public String toString() {
+        return super.toString()
+            + "[State = " + getState() + ", "
+            + (hasQueuedThreads() ? "non" : "") + "empty queue]";
+    }
+
+
+    // Internal support methods for Conditions
+
+    /**
+     * Returns true if a node, always one that was initially placed on
+     * a condition queue, is now waiting to reacquire on sync queue.
+     * @param node the node
+     * @return true if is reacquiring
+     */
+    final boolean isOnSyncQueue(Node node) {
+        if (node.waitStatus == Node.CONDITION || node.prev == null)
+            return false;
+        if (node.next != null) // If has successor, it must be on queue
+            return true;
+        /*
+         * node.prev can be non-null, but not yet on queue because
+         * the CAS to place it on queue can fail. So we have to
+         * traverse from tail to make sure it actually made it.  It
+         * will always be near the tail in calls to this method, and
+         * unless the CAS failed (which is unlikely), it will be
+         * there, so we hardly ever traverse much.
+         */
+        return findNodeFromTail(node);
+    }
+
+    /**
+     * Returns true if node is on sync queue by searching backwards from tail.
+     * Called only when needed by isOnSyncQueue.
+     * @return true if present
+     */
+    private boolean findNodeFromTail(Node node) {
+        // We check for node first, since it's likely to be at or near tail.
+        // tail is known to be non-null, so we could re-order to "save"
+        // one null check, but we leave it this way to help the VM.
+        for (Node p = tail;;) {
+            if (p == node)
+                return true;
+            if (p == null)
+                return false;
+            p = p.prev;
+        }
+    }
+
+    /**
+     * Transfers a node from a condition queue onto sync queue.
+     * Returns true if successful.
+     * @param node the node
+     * @return true if successfully transferred (else the node was
+     * cancelled before signal)
+     */
+    final boolean transferForSignal(Node node) {
+        /*
+         * If cannot change waitStatus, the node has been cancelled.
+         */
+        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
+            return false;
+
+        /*
+         * Splice onto queue and try to set waitStatus of predecessor to
+         * indicate that thread is (probably) waiting. If cancelled or
+         * attempt to set waitStatus fails, wake up to resync (in which
+         * case the waitStatus can be transiently and harmlessly wrong).
+         */
+        Node p = enq(node);
+        int ws = p.waitStatus;
+        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
+            LockSupport.unpark(node.thread);
+        return true;
+    }
+
+    /**
+     * Transfers node, if necessary, to sync queue after a cancelled wait.
+     * Returns true if thread was cancelled before being signalled.
+     *
+     * @param node the node
+     * @return true if cancelled before the node was signalled
+     */
+    final boolean transferAfterCancelledWait(Node node) {
+        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
+            enq(node);
+            return true;
+        }
+        /*
+         * If we lost out to a signal(), then we can't proceed
+         * until it finishes its enq().  Cancelling during an
+         * incomplete transfer is both rare and transient, so just
+         * spin.
+         */
+        while (!isOnSyncQueue(node))
+            Thread.yield();
+        return false;
+    }
+
+    /**
+     * Invokes release with current state value; returns saved state.
+     * Cancels node and throws exception on failure.
+     * @param node the condition node for this wait
+     * @return previous sync state
+     */
+    final int fullyRelease(Node node) {
+        try {
+            int savedState = getState();
+            if (release(savedState))
+                return savedState;
+            throw new IllegalMonitorStateException();
+        } catch (Throwable t) {
+            node.waitStatus = Node.CANCELLED;
+            throw t;
+        }
+    }
+
+    // Instrumentation methods for conditions
+
+    /**
+     * Queries whether the given ConditionObject
+     * uses this synchronizer as its lock.
+     *
+     * @param condition the condition
+     * @return {@code true} if owned
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean owns(ConditionObject condition) {
+        return condition.isOwnedBy(this);
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this synchronizer. Note that because timeouts
+     * and interrupts may occur at any time, a {@code true} return
+     * does not guarantee that a future {@code signal} will awaken
+     * any threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final boolean hasWaiters(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.hasWaiters();
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this synchronizer. Note that
+     * because timeouts and interrupts may occur at any time, the
+     * estimate serves only as an upper bound on the actual number of
+     * waiters.  This method is designed for use in monitoring system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final int getWaitQueueLength(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitQueueLength();
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this
+     * synchronizer.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate. The elements of the
+     * returned collection are in no particular order.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if exclusive synchronization
+     *         is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this synchronizer
+     * @throws NullPointerException if the condition is null
+     */
+    public final Collection<Thread> getWaitingThreads(ConditionObject condition) {
+        if (!owns(condition))
+            throw new IllegalArgumentException("Not owner");
+        return condition.getWaitingThreads();
+    }
+
+    /**
+     * Condition implementation for a {@link
+     * AbstractQueuedSynchronizer} serving as the basis of a {@link
+     * Lock} implementation.
+     *
+     * <p>Method documentation for this class describes mechanics,
+     * not behavioral specifications from the point of view of Lock
+     * and Condition users. Exported versions of this class will in
+     * general need to be accompanied by documentation describing
+     * condition semantics that rely on those of the associated
+     * {@code AbstractQueuedSynchronizer}.
+     *
+     * <p>This class is Serializable, but all fields are transient,
+     * so deserialized conditions have no waiters.
+     */
+    public class ConditionObject implements Condition, java.io.Serializable {
+        private static final long serialVersionUID = 1173984872572414699L;
+        /** First node of condition queue. */
+        private transient Node firstWaiter;
+        /** Last node of condition queue. */
+        private transient Node lastWaiter;
+
+        /**
+         * Creates a new {@code ConditionObject} instance.
+         */
+        public ConditionObject() { }
+
+        // Internal methods
+
+        /**
+         * Adds a new waiter to wait queue.
+         * @return its new wait node
+         */
+        private Node addConditionWaiter() {
+            Node t = lastWaiter;
+            // If lastWaiter is cancelled, clean out.
+            if (t != null && t.waitStatus != Node.CONDITION) {
+                unlinkCancelledWaiters();
+                t = lastWaiter;
+            }
+
+            Node node = new Node(Node.CONDITION);
+
+            if (t == null)
+                firstWaiter = node;
+            else
+                t.nextWaiter = node;
+            lastWaiter = node;
+            return node;
+        }
+
+        /**
+         * Removes and transfers nodes until hit non-cancelled one or
+         * null. Split out from signal in part to encourage compilers
+         * to inline the case of no waiters.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignal(Node first) {
+            do {
+                if ( (firstWaiter = first.nextWaiter) == null)
+                    lastWaiter = null;
+                first.nextWaiter = null;
+            } while (!transferForSignal(first) &&
+                     (first = firstWaiter) != null);
+        }
+
+        /**
+         * Removes and transfers all nodes.
+         * @param first (non-null) the first node on condition queue
+         */
+        private void doSignalAll(Node first) {
+            lastWaiter = firstWaiter = null;
+            do {
+                Node next = first.nextWaiter;
+                first.nextWaiter = null;
+                transferForSignal(first);
+                first = next;
+            } while (first != null);
+        }
+
+        /**
+         * Unlinks cancelled waiter nodes from condition queue.
+         * Called only while holding lock. This is called when
+         * cancellation occurred during condition wait, and upon
+         * insertion of a new waiter when lastWaiter is seen to have
+         * been cancelled. This method is needed to avoid garbage
+         * retention in the absence of signals. So even though it may
+         * require a full traversal, it comes into play only when
+         * timeouts or cancellations occur in the absence of
+         * signals. It traverses all nodes rather than stopping at a
+         * particular target to unlink all pointers to garbage nodes
+         * without requiring many re-traversals during cancellation
+         * storms.
+         */
+        private void unlinkCancelledWaiters() {
+            Node t = firstWaiter;
+            Node trail = null;
+            while (t != null) {
+                Node next = t.nextWaiter;
+                if (t.waitStatus != Node.CONDITION) {
+                    t.nextWaiter = null;
+                    if (trail == null)
+                        firstWaiter = next;
+                    else
+                        trail.nextWaiter = next;
+                    if (next == null)
+                        lastWaiter = trail;
+                }
+                else
+                    trail = t;
+                t = next;
+            }
+        }
+
+        // public methods
+
+        /**
+         * Moves the longest-waiting thread, if one exists, from the
+         * wait queue for this condition to the wait queue for the
+         * owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signal() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignal(first);
+        }
+
+        /**
+         * Moves all threads from the wait queue for this condition to
+         * the wait queue for the owning lock.
+         *
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        public final void signalAll() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            Node first = firstWaiter;
+            if (first != null)
+                doSignalAll(first);
+        }
+
+        /**
+         * Implements uninterruptible condition wait.
+         * <ol>
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * </ol>
+         */
+        public final void awaitUninterruptibly() {
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            boolean interrupted = false;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if (Thread.interrupted())
+                    interrupted = true;
+            }
+            if (acquireQueued(node, savedState) || interrupted)
+                selfInterrupt();
+        }
+
+        /*
+         * For interruptible waits, we need to track whether to throw
+         * InterruptedException, if interrupted while blocked on
+         * condition, versus reinterrupt current thread, if
+         * interrupted while blocked waiting to re-acquire.
+         */
+
+        /** Mode meaning to reinterrupt on exit from wait */
+        private static final int REINTERRUPT =  1;
+        /** Mode meaning to throw InterruptedException on exit from wait */
+        private static final int THROW_IE    = -1;
+
+        /**
+         * Checks for interrupt, returning THROW_IE if interrupted
+         * before signalled, REINTERRUPT if after signalled, or
+         * 0 if not interrupted.
+         */
+        private int checkInterruptWhileWaiting(Node node) {
+            return Thread.interrupted() ?
+                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
+                0;
+        }
+
+        /**
+         * Throws InterruptedException, reinterrupts current thread, or
+         * does nothing, depending on mode.
+         */
+        private void reportInterruptAfterWait(int interruptMode)
+            throws InterruptedException {
+            if (interruptMode == THROW_IE)
+                throw new InterruptedException();
+            else if (interruptMode == REINTERRUPT)
+                selfInterrupt();
+        }
+
+        /**
+         * Implements interruptible condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled or interrupted.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final void await() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                LockSupport.park(this);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null) // clean up if cancelled
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * </ol>
+         */
+        public final long awaitNanos(long nanosTimeout)
+                throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // awaitNanos(0) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            long initialNanos = nanosTimeout;
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            long remaining = deadline - System.nanoTime(); // avoid overflow
+            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+        }
+
+        /**
+         * Implements absolute timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean awaitUntil(Date deadline)
+                throws InterruptedException {
+            long abstime = deadline.getTime();
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (System.currentTimeMillis() >= abstime) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                LockSupport.parkUntil(this, abstime);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        /**
+         * Implements timed condition wait.
+         * <ol>
+         * <li>If current thread is interrupted, throw InterruptedException.
+         * <li>Save lock state returned by {@link #getState}.
+         * <li>Invoke {@link #release} with saved state as argument,
+         *     throwing IllegalMonitorStateException if it fails.
+         * <li>Block until signalled, interrupted, or timed out.
+         * <li>Reacquire by invoking specialized version of
+         *     {@link #acquire} with saved state as argument.
+         * <li>If interrupted while blocked in step 4, throw InterruptedException.
+         * <li>If timed out while blocked in step 4, return false, else true.
+         * </ol>
+         */
+        public final boolean await(long time, TimeUnit unit)
+                throws InterruptedException {
+            long nanosTimeout = unit.toNanos(time);
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            // We don't check for nanosTimeout <= 0L here, to allow
+            // await(0, unit) as a way to "yield the lock".
+            final long deadline = System.nanoTime() + nanosTimeout;
+            Node node = addConditionWaiter();
+            int savedState = fullyRelease(node);
+            boolean timedout = false;
+            int interruptMode = 0;
+            while (!isOnSyncQueue(node)) {
+                if (nanosTimeout <= 0L) {
+                    timedout = transferAfterCancelledWait(node);
+                    break;
+                }
+                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
+                    LockSupport.parkNanos(this, nanosTimeout);
+                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
+                    break;
+                nanosTimeout = deadline - System.nanoTime();
+            }
+            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
+                interruptMode = REINTERRUPT;
+            if (node.nextWaiter != null)
+                unlinkCancelledWaiters();
+            if (interruptMode != 0)
+                reportInterruptAfterWait(interruptMode);
+            return !timedout;
+        }
+
+        //  support for instrumentation
+
+        /**
+         * Returns true if this condition was created by the given
+         * synchronization object.
+         *
+         * @return {@code true} if owned
+         */
+        final boolean isOwnedBy(AbstractQueuedSynchronizer sync) {
+            return sync == AbstractQueuedSynchronizer.this;
+        }
+
+        /**
+         * Queries whether any threads are waiting on this condition.
+         * Implements {@link AbstractQueuedSynchronizer#hasWaiters(ConditionObject)}.
+         *
+         * @return {@code true} if there are any waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final boolean hasWaiters() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns an estimate of the number of threads waiting on
+         * this condition.
+         * Implements {@link AbstractQueuedSynchronizer#getWaitQueueLength(ConditionObject)}.
+         *
+         * @return the estimated number of waiting threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final int getWaitQueueLength() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int n = 0;
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION)
+                    ++n;
+            }
+            return n;
+        }
+
+        /**
+         * Returns a collection containing those threads that may be
+         * waiting on this Condition.
+         * Implements {@link AbstractQueuedSynchronizer#getWaitingThreads(ConditionObject)}.
+         *
+         * @return the collection of threads
+         * @throws IllegalMonitorStateException if {@link #isHeldExclusively}
+         *         returns {@code false}
+         */
+        protected final Collection<Thread> getWaitingThreads() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            ArrayList<Thread> list = new ArrayList<>();
+            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
+                if (w.waitStatus == Node.CONDITION) {
+                    Thread t = w.thread;
+                    if (t != null)
+                        list.add(t);
+                }
+            }
+            return list;
+        }
+    }
+
+    /**
+     * Setup to support compareAndSet. We need to natively implement
+     * this here: For the sake of permitting future enhancements, we
+     * cannot explicitly subclass AtomicInteger, which would be
+     * efficient and useful otherwise. So, as the lesser of evils, we
+     * natively implement using hotspot intrinsics API. And while we
+     * are at it, we do the same for other CASable fields (which could
+     * otherwise be done with atomic field updaters).
+     */
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long HEAD;
+    private static final long TAIL;
+
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
+            HEAD = U.objectFieldOffset
+                (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
+            TAIL = U.objectFieldOffset
+                (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+
+        // Reduce the risk of rare disastrous classloading in first call to
+        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
+        Class<?> ensureLoaded = LockSupport.class;
+    }
+
+    /**
+     * Initializes head and tail fields on first contention.
+     */
+    private final void initializeSyncQueue() {
+        Node h;
+        if (U.compareAndSwapObject(this, HEAD, null, (h = new Node())))
+            tail = h;
+    }
+
+    /**
+     * CASes tail field.
+     */
+    private final boolean compareAndSetTail(Node expect, Node update) {
+        return U.compareAndSwapObject(this, TAIL, expect, update);
+    }
+}
diff --git a/java/util/concurrent/locks/Condition.java b/java/util/concurrent/locks/Condition.java
new file mode 100644
index 0000000..79181fd
--- /dev/null
+++ b/java/util/concurrent/locks/Condition.java
@@ -0,0 +1,488 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Condition} factors out the {@code Object} monitor
+ * methods ({@link Object#wait() wait}, {@link Object#notify notify}
+ * and {@link Object#notifyAll notifyAll}) into distinct objects to
+ * give the effect of having multiple wait-sets per object, by
+ * combining them with the use of arbitrary {@link Lock} implementations.
+ * Where a {@code Lock} replaces the use of {@code synchronized} methods
+ * and statements, a {@code Condition} replaces the use of the Object
+ * monitor methods.
+ *
+ * <p>Conditions (also known as <em>condition queues</em> or
+ * <em>condition variables</em>) provide a means for one thread to
+ * suspend execution (to &quot;wait&quot;) until notified by another
+ * thread that some state condition may now be true.  Because access
+ * to this shared state information occurs in different threads, it
+ * must be protected, so a lock of some form is associated with the
+ * condition. The key property that waiting for a condition provides
+ * is that it <em>atomically</em> releases the associated lock and
+ * suspends the current thread, just like {@code Object.wait}.
+ *
+ * <p>A {@code Condition} instance is intrinsically bound to a lock.
+ * To obtain a {@code Condition} instance for a particular {@link Lock}
+ * instance use its {@link Lock#newCondition newCondition()} method.
+ *
+ * <p>As an example, suppose we have a bounded buffer which supports
+ * {@code put} and {@code take} methods.  If a
+ * {@code take} is attempted on an empty buffer, then the thread will block
+ * until an item becomes available; if a {@code put} is attempted on a
+ * full buffer, then the thread will block until a space becomes available.
+ * We would like to keep waiting {@code put} threads and {@code take}
+ * threads in separate wait-sets so that we can use the optimization of
+ * only notifying a single thread at a time when items or spaces become
+ * available in the buffer. This can be achieved using two
+ * {@link Condition} instances.
+ * <pre>
+ * class BoundedBuffer {
+ *   <b>final Lock lock = new ReentrantLock();</b>
+ *   final Condition notFull  = <b>lock.newCondition(); </b>
+ *   final Condition notEmpty = <b>lock.newCondition(); </b>
+ *
+ *   final Object[] items = new Object[100];
+ *   int putptr, takeptr, count;
+ *
+ *   public void put(Object x) throws InterruptedException {
+ *     <b>lock.lock();
+ *     try {</b>
+ *       while (count == items.length)
+ *         <b>notFull.await();</b>
+ *       items[putptr] = x;
+ *       if (++putptr == items.length) putptr = 0;
+ *       ++count;
+ *       <b>notEmpty.signal();</b>
+ *     <b>} finally {
+ *       lock.unlock();
+ *     }</b>
+ *   }
+ *
+ *   public Object take() throws InterruptedException {
+ *     <b>lock.lock();
+ *     try {</b>
+ *       while (count == 0)
+ *         <b>notEmpty.await();</b>
+ *       Object x = items[takeptr];
+ *       if (++takeptr == items.length) takeptr = 0;
+ *       --count;
+ *       <b>notFull.signal();</b>
+ *       return x;
+ *     <b>} finally {
+ *       lock.unlock();
+ *     }</b>
+ *   }
+ * }
+ * </pre>
+ *
+ * (The {@link java.util.concurrent.ArrayBlockingQueue} class provides
+ * this functionality, so there is no reason to implement this
+ * sample usage class.)
+ *
+ * <p>A {@code Condition} implementation can provide behavior and semantics
+ * that is
+ * different from that of the {@code Object} monitor methods, such as
+ * guaranteed ordering for notifications, or not requiring a lock to be held
+ * when performing notifications.
+ * If an implementation provides such specialized semantics then the
+ * implementation must document those semantics.
+ *
+ * <p>Note that {@code Condition} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement,
+ * and can have their own monitor {@link Object#wait wait} and
+ * {@link Object#notify notify} methods invoked.
+ * Acquiring the monitor lock of a {@code Condition} instance, or using its
+ * monitor methods, has no specified relationship with acquiring the
+ * {@link Lock} associated with that {@code Condition} or the use of its
+ * {@linkplain #await waiting} and {@linkplain #signal signalling} methods.
+ * It is recommended that to avoid confusion you never use {@code Condition}
+ * instances in this way, except perhaps within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any parameter
+ * will result in a {@link NullPointerException} being thrown.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p>When waiting upon a {@code Condition}, a &quot;<em>spurious
+ * wakeup</em>&quot; is permitted to occur, in
+ * general, as a concession to the underlying platform semantics.
+ * This has little practical impact on most application programs as a
+ * {@code Condition} should always be waited upon in a loop, testing
+ * the state predicate that is being waited for.  An implementation is
+ * free to remove the possibility of spurious wakeups but it is
+ * recommended that applications programmers always assume that they can
+ * occur and so always wait in a loop.
+ *
+ * <p>The three forms of condition waiting
+ * (interruptible, non-interruptible, and timed) may differ in their ease of
+ * implementation on some platforms and in their performance characteristics.
+ * In particular, it may be difficult to provide these features and maintain
+ * specific semantics such as ordering guarantees.
+ * Further, the ability to interrupt the actual suspension of the thread may
+ * not always be feasible to implement on all platforms.
+ *
+ * <p>Consequently, an implementation is not required to define exactly the
+ * same guarantees or semantics for all three forms of waiting, nor is it
+ * required to support interruption of the actual suspension of the thread.
+ *
+ * <p>An implementation is required to
+ * clearly document the semantics and guarantees provided by each of the
+ * waiting methods, and when an implementation does support interruption of
+ * thread suspension then it must obey the interruption semantics as defined
+ * in this interface.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action that may have
+ * unblocked the thread. An implementation should document this behavior.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Condition {
+
+    /**
+     * Causes the current thread to wait until it is signalled or
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>The lock associated with this {@code Condition} is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of four things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal. In that case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    void await() throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of three things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread's interrupted status is set when it enters
+     * this method, or it is {@linkplain Thread#interrupt interrupted}
+     * while waiting, it will continue to wait until signalled. When it finally
+     * returns from this method its interrupted status will still
+     * be set.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     */
+    void awaitUninterruptibly();
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified waiting time elapses.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of five things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>The specified waiting time elapses; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     * <p>The method returns an estimate of the number of nanoseconds
+     * remaining to wait given the supplied {@code nanosTimeout}
+     * value upon return, or a value less than or equal to zero if it
+     * timed out. This value can be used to determine whether and how
+     * long to re-wait in cases where the wait returns but an awaited
+     * condition still does not hold. Typical uses of this method take
+     * the following form:
+     *
+     * <pre> {@code
+     * boolean aMethod(long timeout, TimeUnit unit) {
+     *   long nanos = unit.toNanos(timeout);
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (nanos <= 0L)
+     *         return false;
+     *       nanos = theCondition.awaitNanos(nanos);
+     *     }
+     *     // ...
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}</pre>
+     *
+     * <p>Design note: This method requires a nanosecond argument so
+     * as to avoid truncation errors in reporting remaining times.
+     * Such precision loss would make it difficult for programmers to
+     * ensure that total waiting times are not systematically shorter
+     * than specified when re-waits occur.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal, or over indicating the elapse
+     * of the specified waiting time. In either case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @param nanosTimeout the maximum time to wait, in nanoseconds
+     * @return an estimate of the {@code nanosTimeout} value minus
+     *         the time spent waiting upon return from this method.
+     *         A positive value may be used as the argument to a
+     *         subsequent call to this method to finish waiting out
+     *         the desired time.  A value less than or equal to zero
+     *         indicates that no time remains.
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    long awaitNanos(long nanosTimeout) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified waiting time elapses. This method is behaviorally
+     * equivalent to:
+     * <pre> {@code awaitNanos(unit.toNanos(time)) > 0}</pre>
+     *
+     * @param time the maximum time to wait
+     * @param unit the time unit of the {@code time} argument
+     * @return {@code false} if the waiting time detectably elapsed
+     *         before return from the method, else {@code true}
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    boolean await(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Causes the current thread to wait until it is signalled or interrupted,
+     * or the specified deadline elapses.
+     *
+     * <p>The lock associated with this condition is atomically
+     * released and the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until <em>one</em> of five things happens:
+     * <ul>
+     * <li>Some other thread invokes the {@link #signal} method for this
+     * {@code Condition} and the current thread happens to be chosen as the
+     * thread to be awakened; or
+     * <li>Some other thread invokes the {@link #signalAll} method for this
+     * {@code Condition}; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of thread suspension is supported; or
+     * <li>The specified deadline elapses; or
+     * <li>A &quot;<em>spurious wakeup</em>&quot; occurs.
+     * </ul>
+     *
+     * <p>In all cases, before this method can return the current thread must
+     * re-acquire the lock associated with this condition. When the
+     * thread returns it is <em>guaranteed</em> to hold this lock.
+     *
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
+     * and interruption of thread suspension is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared. It is not specified, in the first
+     * case, whether or not the test for interruption occurs before the lock
+     * is released.
+     *
+     *
+     * <p>The return value indicates whether the deadline has elapsed,
+     * which can be used as follows:
+     * <pre> {@code
+     * boolean aMethod(Date deadline) {
+     *   boolean stillWaiting = true;
+     *   lock.lock();
+     *   try {
+     *     while (!conditionBeingWaitedFor()) {
+     *       if (!stillWaiting)
+     *         return false;
+     *       stillWaiting = theCondition.awaitUntil(deadline);
+     *     }
+     *     // ...
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * }}</pre>
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The current thread is assumed to hold the lock associated with this
+     * {@code Condition} when this method is called.
+     * It is up to the implementation to determine if this is
+     * the case and if not, how to respond. Typically, an exception will be
+     * thrown (such as {@link IllegalMonitorStateException}) and the
+     * implementation must document that fact.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return in response to a signal, or over indicating the passing
+     * of the specified deadline. In either case the implementation
+     * must ensure that the signal is redirected to another waiting thread, if
+     * there is one.
+     *
+     * @param deadline the absolute time to wait until
+     * @return {@code false} if the deadline has elapsed upon return, else
+     *         {@code true}
+     * @throws InterruptedException if the current thread is interrupted
+     *         (and interruption of thread suspension is supported)
+     */
+    boolean awaitUntil(Date deadline) throws InterruptedException;
+
+    /**
+     * Wakes up one waiting thread.
+     *
+     * <p>If any threads are waiting on this condition then one
+     * is selected for waking up. That thread must then re-acquire the
+     * lock before returning from {@code await}.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>An implementation may (and typically does) require that the
+     * current thread hold the lock associated with this {@code
+     * Condition} when this method is called. Implementations must
+     * document this precondition and any actions taken if the lock is
+     * not held. Typically, an exception such as {@link
+     * IllegalMonitorStateException} will be thrown.
+     */
+    void signal();
+
+    /**
+     * Wakes up all waiting threads.
+     *
+     * <p>If any threads are waiting on this condition then they are
+     * all woken up. Each thread must re-acquire the lock before it can
+     * return from {@code await}.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>An implementation may (and typically does) require that the
+     * current thread hold the lock associated with this {@code
+     * Condition} when this method is called. Implementations must
+     * document this precondition and any actions taken if the lock is
+     * not held. Typically, an exception such as {@link
+     * IllegalMonitorStateException} will be thrown.
+     */
+    void signalAll();
+}
diff --git a/java/util/concurrent/locks/Lock.java b/java/util/concurrent/locks/Lock.java
new file mode 100644
index 0000000..33ac44b
--- /dev/null
+++ b/java/util/concurrent/locks/Lock.java
@@ -0,0 +1,359 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@code Lock} implementations provide more extensive locking
+ * operations than can be obtained using {@code synchronized} methods
+ * and statements.  They allow more flexible structuring, may have
+ * quite different properties, and may support multiple associated
+ * {@link Condition} objects.
+ *
+ * <p>A lock is a tool for controlling access to a shared resource by
+ * multiple threads. Commonly, a lock provides exclusive access to a
+ * shared resource: only one thread at a time can acquire the lock and
+ * all access to the shared resource requires that the lock be
+ * acquired first. However, some locks may allow concurrent access to
+ * a shared resource, such as the read lock of a {@link ReadWriteLock}.
+ *
+ * <p>The use of {@code synchronized} methods or statements provides
+ * access to the implicit monitor lock associated with every object, but
+ * forces all lock acquisition and release to occur in a block-structured way:
+ * when multiple locks are acquired they must be released in the opposite
+ * order, and all locks must be released in the same lexical scope in which
+ * they were acquired.
+ *
+ * <p>While the scoping mechanism for {@code synchronized} methods
+ * and statements makes it much easier to program with monitor locks,
+ * and helps avoid many common programming errors involving locks,
+ * there are occasions where you need to work with locks in a more
+ * flexible way. For example, some algorithms for traversing
+ * concurrently accessed data structures require the use of
+ * &quot;hand-over-hand&quot; or &quot;chain locking&quot;: you
+ * acquire the lock of node A, then node B, then release A and acquire
+ * C, then release B and acquire D and so on.  Implementations of the
+ * {@code Lock} interface enable the use of such techniques by
+ * allowing a lock to be acquired and released in different scopes,
+ * and allowing multiple locks to be acquired and released in any
+ * order.
+ *
+ * <p>With this increased flexibility comes additional
+ * responsibility. The absence of block-structured locking removes the
+ * automatic release of locks that occurs with {@code synchronized}
+ * methods and statements. In most cases, the following idiom
+ * should be used:
+ *
+ * <pre> {@code
+ * Lock l = ...;
+ * l.lock();
+ * try {
+ *   // access the resource protected by this lock
+ * } finally {
+ *   l.unlock();
+ * }}</pre>
+ *
+ * When locking and unlocking occur in different scopes, care must be
+ * taken to ensure that all code that is executed while the lock is
+ * held is protected by try-finally or try-catch to ensure that the
+ * lock is released when necessary.
+ *
+ * <p>{@code Lock} implementations provide additional functionality
+ * over the use of {@code synchronized} methods and statements by
+ * providing a non-blocking attempt to acquire a lock ({@link
+ * #tryLock()}), an attempt to acquire the lock that can be
+ * interrupted ({@link #lockInterruptibly}, and an attempt to acquire
+ * the lock that can timeout ({@link #tryLock(long, TimeUnit)}).
+ *
+ * <p>A {@code Lock} class can also provide behavior and semantics
+ * that is quite different from that of the implicit monitor lock,
+ * such as guaranteed ordering, non-reentrant usage, or deadlock
+ * detection. If an implementation provides such specialized semantics
+ * then the implementation must document those semantics.
+ *
+ * <p>Note that {@code Lock} instances are just normal objects and can
+ * themselves be used as the target in a {@code synchronized} statement.
+ * Acquiring the
+ * monitor lock of a {@code Lock} instance has no specified relationship
+ * with invoking any of the {@link #lock} methods of that instance.
+ * It is recommended that to avoid confusion you never use {@code Lock}
+ * instances in this way, except within their own implementation.
+ *
+ * <p>Except where noted, passing a {@code null} value for any
+ * parameter will result in a {@link NullPointerException} being
+ * thrown.
+ *
+ * <h3>Memory Synchronization</h3>
+ *
+ * <p>All {@code Lock} implementations <em>must</em> enforce the same
+ * memory synchronization semantics as provided by the built-in monitor
+ * lock, as described in
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">
+ * Chapter 17 of
+ * <cite>The Java&trade; Language Specification</cite></a>:
+ * <ul>
+ * <li>A successful {@code lock} operation has the same memory
+ * synchronization effects as a successful <em>Lock</em> action.
+ * <li>A successful {@code unlock} operation has the same
+ * memory synchronization effects as a successful <em>Unlock</em> action.
+ * </ul>
+ *
+ * Unsuccessful locking and unlocking operations, and reentrant
+ * locking/unlocking operations, do not require any memory
+ * synchronization effects.
+ *
+ * <h3>Implementation Considerations</h3>
+ *
+ * <p>The three forms of lock acquisition (interruptible,
+ * non-interruptible, and timed) may differ in their performance
+ * characteristics, ordering guarantees, or other implementation
+ * qualities.  Further, the ability to interrupt the <em>ongoing</em>
+ * acquisition of a lock may not be available in a given {@code Lock}
+ * class.  Consequently, an implementation is not required to define
+ * exactly the same guarantees or semantics for all three forms of
+ * lock acquisition, nor is it required to support interruption of an
+ * ongoing lock acquisition.  An implementation is required to clearly
+ * document the semantics and guarantees provided by each of the
+ * locking methods. It must also obey the interruption semantics as
+ * defined in this interface, to the extent that interruption of lock
+ * acquisition is supported: which is either totally, or only on
+ * method entry.
+ *
+ * <p>As interruption generally implies cancellation, and checks for
+ * interruption are often infrequent, an implementation can favor responding
+ * to an interrupt over normal method return. This is true even if it can be
+ * shown that the interrupt occurred after another action may have unblocked
+ * the thread. An implementation should document this behavior.
+ *
+ * @see ReentrantLock
+ * @see Condition
+ * @see ReadWriteLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface Lock {
+
+    /**
+     * Acquires the lock.
+     *
+     * <p>If the lock is not available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until the
+     * lock has been acquired.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>A {@code Lock} implementation may be able to detect erroneous use
+     * of the lock, such as an invocation that would cause deadlock, and
+     * may throw an (unchecked) exception in such circumstances.  The
+     * circumstances and the exception type must be documented by that
+     * {@code Lock} implementation.
+     */
+    void lock();
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is available and returns immediately.
+     *
+     * <p>If the lock is not available then the current thread becomes
+     * disabled for thread scheduling purposes and lies dormant until
+     * one of two things happens:
+     *
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of lock acquisition is supported.
+     * </ul>
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring the
+     * lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some
+     * implementations may not be possible, and if possible may be an
+     * expensive operation.  The programmer should be aware that this
+     * may be the case. An implementation should document when this is
+     * the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over
+     * normal method return.
+     *
+     * <p>A {@code Lock} implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would
+     * cause deadlock, and may throw an (unchecked) exception in such
+     * circumstances.  The circumstances and the exception type must
+     * be documented by that {@code Lock} implementation.
+     *
+     * @throws InterruptedException if the current thread is
+     *         interrupted while acquiring the lock (and interruption
+     *         of lock acquisition is supported)
+     */
+    void lockInterruptibly() throws InterruptedException;
+
+    /**
+     * Acquires the lock only if it is free at the time of invocation.
+     *
+     * <p>Acquires the lock if it is available and returns immediately
+     * with the value {@code true}.
+     * If the lock is not available then this method will return
+     * immediately with the value {@code false}.
+     *
+     * <p>A typical usage idiom for this method would be:
+     * <pre> {@code
+     * Lock lock = ...;
+     * if (lock.tryLock()) {
+     *   try {
+     *     // manipulate protected state
+     *   } finally {
+     *     lock.unlock();
+     *   }
+     * } else {
+     *   // perform alternative actions
+     * }}</pre>
+     *
+     * This usage ensures that the lock is unlocked if it was acquired, and
+     * doesn't try to unlock if the lock was not acquired.
+     *
+     * @return {@code true} if the lock was acquired and
+     *         {@code false} otherwise
+     */
+    boolean tryLock();
+
+    /**
+     * Acquires the lock if it is free within the given waiting time and the
+     * current thread has not been {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>If the lock is available this method returns immediately
+     * with the value {@code true}.
+     * If the lock is not available then
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     * <ul>
+     * <li>The lock is acquired by the current thread; or
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread, and interruption of lock acquisition is supported; or
+     * <li>The specified waiting time elapses
+     * </ul>
+     *
+     * <p>If the lock is acquired then the value {@code true} is returned.
+     *
+     * <p>If the current thread:
+     * <ul>
+     * <li>has its interrupted status set on entry to this method; or
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+     * the lock, and interruption of lock acquisition is supported,
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.
+     * If the time is
+     * less than or equal to zero, the method will not wait at all.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The ability to interrupt a lock acquisition in some implementations
+     * may not be possible, and if possible may
+     * be an expensive operation.
+     * The programmer should be aware that this may be the case. An
+     * implementation should document when this is the case.
+     *
+     * <p>An implementation can favor responding to an interrupt over normal
+     * method return, or reporting a timeout.
+     *
+     * <p>A {@code Lock} implementation may be able to detect
+     * erroneous use of the lock, such as an invocation that would cause
+     * deadlock, and may throw an (unchecked) exception in such circumstances.
+     * The circumstances and the exception type must be documented by that
+     * {@code Lock} implementation.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return {@code true} if the lock was acquired and {@code false}
+     *         if the waiting time elapsed before the lock was acquired
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     *         while acquiring the lock (and interruption of lock
+     *         acquisition is supported)
+     */
+    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
+
+    /**
+     * Releases the lock.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>A {@code Lock} implementation will usually impose
+     * restrictions on which thread can release a lock (typically only the
+     * holder of the lock can release it) and may throw
+     * an (unchecked) exception if the restriction is violated.
+     * Any restrictions and the exception
+     * type must be documented by that {@code Lock} implementation.
+     */
+    void unlock();
+
+    /**
+     * Returns a new {@link Condition} instance that is bound to this
+     * {@code Lock} instance.
+     *
+     * <p>Before waiting on the condition the lock must be held by the
+     * current thread.
+     * A call to {@link Condition#await()} will atomically release the lock
+     * before waiting and re-acquire the lock before the wait returns.
+     *
+     * <p><b>Implementation Considerations</b>
+     *
+     * <p>The exact operation of the {@link Condition} instance depends on
+     * the {@code Lock} implementation and must be documented by that
+     * implementation.
+     *
+     * @return A new {@link Condition} instance for this {@code Lock} instance
+     * @throws UnsupportedOperationException if this {@code Lock}
+     *         implementation does not support conditions
+     */
+    Condition newCondition();
+}
diff --git a/java/util/concurrent/locks/LockSupport.java b/java/util/concurrent/locks/LockSupport.java
new file mode 100644
index 0000000..4c57596
--- /dev/null
+++ b/java/util/concurrent/locks/LockSupport.java
@@ -0,0 +1,423 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * Basic thread blocking primitives for creating locks and other
+ * synchronization classes.
+ *
+ * <p>This class associates, with each thread that uses it, a permit
+ * (in the sense of the {@link java.util.concurrent.Semaphore
+ * Semaphore} class). A call to {@code park} will return immediately
+ * if the permit is available, consuming it in the process; otherwise
+ * it <em>may</em> block.  A call to {@code unpark} makes the permit
+ * available, if it was not already available. (Unlike with Semaphores
+ * though, permits do not accumulate. There is at most one.)
+ * Reliable usage requires the use of volatile (or atomic) variables
+ * to control when to park or unpark.  Orderings of calls to these
+ * methods are maintained with respect to volatile variable accesses,
+ * but not necessarily non-volatile variable accesses.
+ *
+ * <p>Methods {@code park} and {@code unpark} provide efficient
+ * means of blocking and unblocking threads that do not encounter the
+ * problems that cause the deprecated methods {@code Thread.suspend}
+ * and {@code Thread.resume} to be unusable for such purposes: Races
+ * between one thread invoking {@code park} and another thread trying
+ * to {@code unpark} it will preserve liveness, due to the
+ * permit. Additionally, {@code park} will return if the caller's
+ * thread was interrupted, and timeout versions are supported. The
+ * {@code park} method may also return at any other time, for "no
+ * reason", so in general must be invoked within a loop that rechecks
+ * conditions upon return. In this sense {@code park} serves as an
+ * optimization of a "busy wait" that does not waste as much time
+ * spinning, but must be paired with an {@code unpark} to be
+ * effective.
+ *
+ * <p>The three forms of {@code park} each also support a
+ * {@code blocker} object parameter. This object is recorded while
+ * the thread is blocked to permit monitoring and diagnostic tools to
+ * identify the reasons that threads are blocked. (Such tools may
+ * access blockers using method {@link #getBlocker(Thread)}.)
+ * The use of these forms rather than the original forms without this
+ * parameter is strongly encouraged. The normal argument to supply as
+ * a {@code blocker} within a lock implementation is {@code this}.
+ *
+ * <p>These methods are designed to be used as tools for creating
+ * higher-level synchronization utilities, and are not in themselves
+ * useful for most concurrency control applications.  The {@code park}
+ * method is designed for use only in constructions of the form:
+ *
+ * <pre> {@code
+ * while (!canProceed()) {
+ *   // ensure request to unpark is visible to other threads
+ *   ...
+ *   LockSupport.park(this);
+ * }}</pre>
+ *
+ * where no actions by the thread publishing a request to unpark,
+ * prior to the call to {@code park}, entail locking or blocking.
+ * Because only one permit is associated with each thread, any
+ * intermediary uses of {@code park}, including implicitly via class
+ * loading, could lead to an unresponsive thread (a "lost unpark").
+ *
+ * <p><b>Sample Usage.</b> Here is a sketch of a first-in-first-out
+ * non-reentrant lock class:
+ * <pre> {@code
+ * class FIFOMutex {
+ *   private final AtomicBoolean locked = new AtomicBoolean(false);
+ *   private final Queue<Thread> waiters
+ *     = new ConcurrentLinkedQueue<>();
+ *
+ *   public void lock() {
+ *     boolean wasInterrupted = false;
+ *     // publish current thread for unparkers
+ *     waiters.add(Thread.currentThread());
+ *
+ *     // Block while not first in queue or cannot acquire lock
+ *     while (waiters.peek() != Thread.currentThread() ||
+ *            !locked.compareAndSet(false, true)) {
+ *       LockSupport.park(this);
+ *       // ignore interrupts while waiting
+ *       if (Thread.interrupted())
+ *         wasInterrupted = true;
+ *     }
+ *
+ *     waiters.remove();
+ *     // ensure correct interrupt status on return
+ *     if (wasInterrupted)
+ *       Thread.currentThread().interrupt();
+ *   }
+ *
+ *   public void unlock() {
+ *     locked.set(false);
+ *     LockSupport.unpark(waiters.peek());
+ *   }
+ *
+ *   static {
+ *     // Reduce the risk of "lost unpark" due to classloading
+ *     Class<?> ensureLoaded = LockSupport.class;
+ *   }
+ * }}</pre>
+ */
+public class LockSupport {
+    private LockSupport() {} // Cannot be instantiated.
+
+    private static void setBlocker(Thread t, Object arg) {
+        // Even though volatile, hotspot doesn't need a write barrier here.
+        U.putObject(t, PARKBLOCKER, arg);
+    }
+
+    /**
+     * Makes available the permit for the given thread, if it
+     * was not already available.  If the thread was blocked on
+     * {@code park} then it will unblock.  Otherwise, its next call
+     * to {@code park} is guaranteed not to block. This operation
+     * is not guaranteed to have any effect at all if the given
+     * thread has not been started.
+     *
+     * @param thread the thread to unpark, or {@code null}, in which case
+     *        this operation has no effect
+     */
+    public static void unpark(Thread thread) {
+        if (thread != null)
+            U.unpark(thread);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes unless the
+     * permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call returns
+     * immediately; otherwise
+     * the current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @since 1.6
+     */
+    public static void park(Object blocker) {
+        Thread t = Thread.currentThread();
+        setBlocker(t, blocker);
+        U.park(false, 0L);
+        setBlocker(t, null);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, for up to
+     * the specified waiting time, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the elapsed time
+     * upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @param nanos the maximum number of nanoseconds to wait
+     * @since 1.6
+     */
+    public static void parkNanos(Object blocker, long nanos) {
+        if (nanos > 0) {
+            Thread t = Thread.currentThread();
+            setBlocker(t, blocker);
+            U.park(false, nanos);
+            setBlocker(t, null);
+        }
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, until
+     * the specified deadline, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread; or
+     *
+     * <li>The specified deadline passes; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the current time
+     * upon return.
+     *
+     * @param blocker the synchronization object responsible for this
+     *        thread parking
+     * @param deadline the absolute time, in milliseconds from the Epoch,
+     *        to wait until
+     * @since 1.6
+     */
+    public static void parkUntil(Object blocker, long deadline) {
+        Thread t = Thread.currentThread();
+        setBlocker(t, blocker);
+        U.park(true, deadline);
+        setBlocker(t, null);
+    }
+
+    /**
+     * Returns the blocker object supplied to the most recent
+     * invocation of a park method that has not yet unblocked, or null
+     * if not blocked.  The value returned is just a momentary
+     * snapshot -- the thread may have since unblocked or blocked on a
+     * different blocker object.
+     *
+     * @param t the thread
+     * @return the blocker
+     * @throws NullPointerException if argument is null
+     * @since 1.6
+     */
+    public static Object getBlocker(Thread t) {
+        if (t == null)
+            throw new NullPointerException();
+        return U.getObjectVolatile(t, PARKBLOCKER);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes unless the
+     * permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of three
+     * things happens:
+     *
+     * <ul>
+     *
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread upon return.
+     */
+    public static void park() {
+        U.park(false, 0L);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, for up to
+     * the specified waiting time, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the elapsed time
+     * upon return.
+     *
+     * @param nanos the maximum number of nanoseconds to wait
+     */
+    public static void parkNanos(long nanos) {
+        if (nanos > 0)
+            U.park(false, nanos);
+    }
+
+    /**
+     * Disables the current thread for thread scheduling purposes, until
+     * the specified deadline, unless the permit is available.
+     *
+     * <p>If the permit is available then it is consumed and the call
+     * returns immediately; otherwise the current thread becomes disabled
+     * for thread scheduling purposes and lies dormant until one of four
+     * things happens:
+     *
+     * <ul>
+     * <li>Some other thread invokes {@link #unpark unpark} with the
+     * current thread as the target; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified deadline passes; or
+     *
+     * <li>The call spuriously (that is, for no reason) returns.
+     * </ul>
+     *
+     * <p>This method does <em>not</em> report which of these caused the
+     * method to return. Callers should re-check the conditions which caused
+     * the thread to park in the first place. Callers may also determine,
+     * for example, the interrupt status of the thread, or the current time
+     * upon return.
+     *
+     * @param deadline the absolute time, in milliseconds from the Epoch,
+     *        to wait until
+     */
+    public static void parkUntil(long deadline) {
+        U.park(true, deadline);
+    }
+
+    /**
+     * Returns the pseudo-randomly initialized or updated secondary seed.
+     * Copied from ThreadLocalRandom due to package access restrictions.
+     */
+    static final int nextSecondarySeed() {
+        int r;
+        Thread t = Thread.currentThread();
+        if ((r = U.getInt(t, SECONDARY)) != 0) {
+            r ^= r << 13;   // xorshift
+            r ^= r >>> 17;
+            r ^= r << 5;
+        }
+        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
+            r = 1; // avoid zero
+        U.putInt(t, SECONDARY, r);
+        return r;
+    }
+
+    // Hotspot implementation via intrinsics API
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long PARKBLOCKER;
+    private static final long SECONDARY;
+    static {
+        try {
+            PARKBLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+            SECONDARY = U.objectFieldOffset
+                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/locks/ReadWriteLock.java b/java/util/concurrent/locks/ReadWriteLock.java
new file mode 100644
index 0000000..00fb845
--- /dev/null
+++ b/java/util/concurrent/locks/ReadWriteLock.java
@@ -0,0 +1,133 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+/**
+ * A {@code ReadWriteLock} maintains a pair of associated {@link
+ * Lock locks}, one for read-only operations and one for writing.
+ * The {@linkplain #readLock read lock} may be held simultaneously
+ * by multiple reader threads, so long as there are no writers.
+ * The {@linkplain #writeLock write lock} is exclusive.
+ *
+ * <p>All {@code ReadWriteLock} implementations must guarantee that
+ * the memory synchronization effects of {@code writeLock} operations
+ * (as specified in the {@link Lock} interface) also hold with respect
+ * to the associated {@code readLock}. That is, a thread successfully
+ * acquiring the read lock will see all updates made upon previous
+ * release of the write lock.
+ *
+ * <p>A read-write lock allows for a greater level of concurrency in
+ * accessing shared data than that permitted by a mutual exclusion lock.
+ * It exploits the fact that while only a single thread at a time (a
+ * <em>writer</em> thread) can modify the shared data, in many cases any
+ * number of threads can concurrently read the data (hence <em>reader</em>
+ * threads).
+ * In theory, the increase in concurrency permitted by the use of a read-write
+ * lock will lead to performance improvements over the use of a mutual
+ * exclusion lock. In practice this increase in concurrency will only be fully
+ * realized on a multi-processor, and then only if the access patterns for
+ * the shared data are suitable.
+ *
+ * <p>Whether or not a read-write lock will improve performance over the use
+ * of a mutual exclusion lock depends on the frequency that the data is
+ * read compared to being modified, the duration of the read and write
+ * operations, and the contention for the data - that is, the number of
+ * threads that will try to read or write the data at the same time.
+ * For example, a collection that is initially populated with data and
+ * thereafter infrequently modified, while being frequently searched
+ * (such as a directory of some kind) is an ideal candidate for the use of
+ * a read-write lock. However, if updates become frequent then the data
+ * spends most of its time being exclusively locked and there is little, if any
+ * increase in concurrency. Further, if the read operations are too short
+ * the overhead of the read-write lock implementation (which is inherently
+ * more complex than a mutual exclusion lock) can dominate the execution
+ * cost, particularly as many read-write lock implementations still serialize
+ * all threads through a small section of code. Ultimately, only profiling
+ * and measurement will establish whether the use of a read-write lock is
+ * suitable for your application.
+ *
+ *
+ * <p>Although the basic operation of a read-write lock is straight-forward,
+ * there are many policy decisions that an implementation must make, which
+ * may affect the effectiveness of the read-write lock in a given application.
+ * Examples of these policies include:
+ * <ul>
+ * <li>Determining whether to grant the read lock or the write lock, when
+ * both readers and writers are waiting, at the time that a writer releases
+ * the write lock. Writer preference is common, as writes are expected to be
+ * short and infrequent. Reader preference is less common as it can lead to
+ * lengthy delays for a write if the readers are frequent and long-lived as
+ * expected. Fair, or &quot;in-order&quot; implementations are also possible.
+ *
+ * <li>Determining whether readers that request the read lock while a
+ * reader is active and a writer is waiting, are granted the read lock.
+ * Preference to the reader can delay the writer indefinitely, while
+ * preference to the writer can reduce the potential for concurrency.
+ *
+ * <li>Determining whether the locks are reentrant: can a thread with the
+ * write lock reacquire it? Can it acquire a read lock while holding the
+ * write lock? Is the read lock itself reentrant?
+ *
+ * <li>Can the write lock be downgraded to a read lock without allowing
+ * an intervening writer? Can a read lock be upgraded to a write lock,
+ * in preference to other waiting readers or writers?
+ *
+ * </ul>
+ * You should consider all of these things when evaluating the suitability
+ * of a given implementation for your application.
+ *
+ * @see ReentrantReadWriteLock
+ * @see Lock
+ * @see ReentrantLock
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public interface ReadWriteLock {
+    /**
+     * Returns the lock used for reading.
+     *
+     * @return the lock used for reading
+     */
+    Lock readLock();
+
+    /**
+     * Returns the lock used for writing.
+     *
+     * @return the lock used for writing
+     */
+    Lock writeLock();
+}
diff --git a/java/util/concurrent/locks/ReentrantLock.java b/java/util/concurrent/locks/ReentrantLock.java
new file mode 100644
index 0000000..3c1c492
--- /dev/null
+++ b/java/util/concurrent/locks/ReentrantLock.java
@@ -0,0 +1,770 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A reentrant mutual exclusion {@link Lock} with the same basic
+ * behavior and semantics as the implicit monitor lock accessed using
+ * {@code synchronized} methods and statements, but with extended
+ * capabilities.
+ *
+ * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last
+ * successfully locking, but not yet unlocking it. A thread invoking
+ * {@code lock} will return, successfully acquiring the lock, when
+ * the lock is not owned by another thread. The method will return
+ * immediately if the current thread already owns the lock. This can
+ * be checked using methods {@link #isHeldByCurrentThread}, and {@link
+ * #getHoldCount}.
+ *
+ * <p>The constructor for this class accepts an optional
+ * <em>fairness</em> parameter.  When set {@code true}, under
+ * contention, locks favor granting access to the longest-waiting
+ * thread.  Otherwise this lock does not guarantee any particular
+ * access order.  Programs using fair locks accessed by many threads
+ * may display lower overall throughput (i.e., are slower; often much
+ * slower) than those using the default setting, but have smaller
+ * variances in times to obtain locks and guarantee lack of
+ * starvation. Note however, that fairness of locks does not guarantee
+ * fairness of thread scheduling. Thus, one of many threads using a
+ * fair lock may obtain it multiple times in succession while other
+ * active threads are not progressing and not currently holding the
+ * lock.
+ * Also note that the untimed {@link #tryLock()} method does not
+ * honor the fairness setting. It will succeed if the lock
+ * is available even if other threads are waiting.
+ *
+ * <p>It is recommended practice to <em>always</em> immediately
+ * follow a call to {@code lock} with a {@code try} block, most
+ * typically in a before/after construction such as:
+ *
+ * <pre> {@code
+ * class X {
+ *   private final ReentrantLock lock = new ReentrantLock();
+ *   // ...
+ *
+ *   public void m() {
+ *     lock.lock();  // block until condition holds
+ *     try {
+ *       // ... method body
+ *     } finally {
+ *       lock.unlock()
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * <p>In addition to implementing the {@link Lock} interface, this
+ * class defines a number of {@code public} and {@code protected}
+ * methods for inspecting the state of the lock.  Some of these
+ * methods are only useful for instrumentation and monitoring.
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p>This lock supports a maximum of 2147483647 recursive locks by
+ * the same thread. Attempts to exceed this limit result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ReentrantLock implements Lock, java.io.Serializable {
+    private static final long serialVersionUID = 7373984872572414699L;
+    /** Synchronizer providing all implementation mechanics */
+    private final Sync sync;
+
+    /**
+     * Base of synchronization control for this lock. Subclassed
+     * into fair and nonfair versions below. Uses AQS state to
+     * represent the number of holds on the lock.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = -5179523762034025860L;
+
+        /**
+         * Performs {@link Lock#lock}. The main reason for subclassing
+         * is to allow fast path for nonfair version.
+         */
+        abstract void lock();
+
+        /**
+         * Performs non-fair tryLock.  tryAcquire is implemented in
+         * subclasses, but both need nonfair try for trylock method.
+         */
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        final boolean nonfairTryAcquire(int acquires) {
+            final Thread current = Thread.currentThread();
+            int c = getState();
+            if (c == 0) {
+                if (compareAndSetState(0, acquires)) {
+                    setExclusiveOwnerThread(current);
+                    return true;
+                }
+            }
+            else if (current == getExclusiveOwnerThread()) {
+                int nextc = c + acquires;
+                if (nextc < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(nextc);
+                return true;
+            }
+            return false;
+        }
+
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        protected final boolean tryRelease(int releases) {
+            int c = getState() - releases;
+            if (Thread.currentThread() != getExclusiveOwnerThread())
+                throw new IllegalMonitorStateException();
+            boolean free = false;
+            if (c == 0) {
+                free = true;
+                setExclusiveOwnerThread(null);
+            }
+            setState(c);
+            return free;
+        }
+
+        protected final boolean isHeldExclusively() {
+            // While we must in general read state before owner,
+            // we don't need to do so to check if current thread is owner
+            return getExclusiveOwnerThread() == Thread.currentThread();
+        }
+
+        final ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        // Methods relayed from outer class
+
+        final Thread getOwner() {
+            return getState() == 0 ? null : getExclusiveOwnerThread();
+        }
+
+        final int getHoldCount() {
+            return isHeldExclusively() ? getState() : 0;
+        }
+
+        final boolean isLocked() {
+            return getState() != 0;
+        }
+
+        /**
+         * Reconstitutes the instance from a stream (that is, deserializes it).
+         */
+        private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+            s.defaultReadObject();
+            setState(0); // reset to unlocked state
+        }
+    }
+
+    /**
+     * Sync object for non-fair locks
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = 7316153563782823691L;
+
+        /**
+         * Performs lock.  Try immediate barge, backing up to normal
+         * acquire on failure.
+         */
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        final void lock() {
+            if (compareAndSetState(0, 1))
+                setExclusiveOwnerThread(Thread.currentThread());
+            else
+                acquire(1);
+        }
+
+        protected final boolean tryAcquire(int acquires) {
+            return nonfairTryAcquire(acquires);
+        }
+    }
+
+    /**
+     * Sync object for fair locks
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = -3000897897090466540L;
+
+        final void lock() {
+            acquire(1);
+        }
+
+        /**
+         * Fair version of tryAcquire.  Don't grant access unless
+         * recursive call or no waiters or is first.
+         */
+        // Android-removed: @ReservedStackAccess from OpenJDK 9, not available on Android.
+        // @ReservedStackAccess
+        protected final boolean tryAcquire(int acquires) {
+            final Thread current = Thread.currentThread();
+            int c = getState();
+            if (c == 0) {
+                if (!hasQueuedPredecessors() &&
+                    compareAndSetState(0, acquires)) {
+                    setExclusiveOwnerThread(current);
+                    return true;
+                }
+            }
+            else if (current == getExclusiveOwnerThread()) {
+                int nextc = c + acquires;
+                if (nextc < 0)
+                    throw new Error("Maximum lock count exceeded");
+                setState(nextc);
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Creates an instance of {@code ReentrantLock}.
+     * This is equivalent to using {@code ReentrantLock(false)}.
+     */
+    public ReentrantLock() {
+        sync = new NonfairSync();
+    }
+
+    /**
+     * Creates an instance of {@code ReentrantLock} with the
+     * given fairness policy.
+     *
+     * @param fair {@code true} if this lock should use a fair ordering policy
+     */
+    public ReentrantLock(boolean fair) {
+        sync = fair ? new FairSync() : new NonfairSync();
+    }
+
+    /**
+     * Acquires the lock.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately, setting the lock hold count to one.
+     *
+     * <p>If the current thread already holds the lock then the hold
+     * count is incremented by one and the method returns immediately.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until the lock has been acquired,
+     * at which time the lock hold count is set to one.
+     */
+    public void lock() {
+        sync.lock();
+    }
+
+    /**
+     * Acquires the lock unless the current thread is
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately, setting the lock hold count to one.
+     *
+     * <p>If the current thread already holds this lock then the hold count
+     * is incremented by one and the method returns immediately.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of two things happens:
+     *
+     * <ul>
+     *
+     * <li>The lock is acquired by the current thread; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts} the
+     * current thread.
+     *
+     * </ul>
+     *
+     * <p>If the lock is acquired by the current thread then the lock hold
+     * count is set to one.
+     *
+     * <p>If the current thread:
+     *
+     * <ul>
+     *
+     * <li>has its interrupted status set on entry to this method; or
+     *
+     * <li>is {@linkplain Thread#interrupt interrupted} while acquiring
+     * the lock,
+     *
+     * </ul>
+     *
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>In this implementation, as this method is an explicit
+     * interruption point, preference is given to responding to the
+     * interrupt over normal or reentrant acquisition of the lock.
+     *
+     * @throws InterruptedException if the current thread is interrupted
+     */
+    public void lockInterruptibly() throws InterruptedException {
+        sync.acquireInterruptibly(1);
+    }
+
+    /**
+     * Acquires the lock only if it is not held by another thread at the time
+     * of invocation.
+     *
+     * <p>Acquires the lock if it is not held by another thread and
+     * returns immediately with the value {@code true}, setting the
+     * lock hold count to one. Even when this lock has been set to use a
+     * fair ordering policy, a call to {@code tryLock()} <em>will</em>
+     * immediately acquire the lock if it is available, whether or not
+     * other threads are currently waiting for the lock.
+     * This &quot;barging&quot; behavior can be useful in certain
+     * circumstances, even though it breaks fairness. If you want to honor
+     * the fairness setting for this lock, then use
+     * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
+     * which is almost equivalent (it also detects interruption).
+     *
+     * <p>If the current thread already holds this lock then the hold
+     * count is incremented by one and the method returns {@code true}.
+     *
+     * <p>If the lock is held by another thread then this method will return
+     * immediately with the value {@code false}.
+     *
+     * @return {@code true} if the lock was free and was acquired by the
+     *         current thread, or the lock was already held by the current
+     *         thread; and {@code false} otherwise
+     */
+    public boolean tryLock() {
+        return sync.nonfairTryAcquire(1);
+    }
+
+    /**
+     * Acquires the lock if it is not held by another thread within the given
+     * waiting time and the current thread has not been
+     * {@linkplain Thread#interrupt interrupted}.
+     *
+     * <p>Acquires the lock if it is not held by another thread and returns
+     * immediately with the value {@code true}, setting the lock hold count
+     * to one. If this lock has been set to use a fair ordering policy then
+     * an available lock <em>will not</em> be acquired if any other threads
+     * are waiting for the lock. This is in contrast to the {@link #tryLock()}
+     * method. If you want a timed {@code tryLock} that does permit barging on
+     * a fair lock then combine the timed and un-timed forms together:
+     *
+     * <pre> {@code
+     * if (lock.tryLock() ||
+     *     lock.tryLock(timeout, unit)) {
+     *   ...
+     * }}</pre>
+     *
+     * <p>If the current thread
+     * already holds this lock then the hold count is incremented by one and
+     * the method returns {@code true}.
+     *
+     * <p>If the lock is held by another thread then the
+     * current thread becomes disabled for thread scheduling
+     * purposes and lies dormant until one of three things happens:
+     *
+     * <ul>
+     *
+     * <li>The lock is acquired by the current thread; or
+     *
+     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+     * the current thread; or
+     *
+     * <li>The specified waiting time elapses
+     *
+     * </ul>
+     *
+     * <p>If the lock is acquired then the value {@code true} is returned and
+     * the lock hold count is set to one.
+     *
+     * <p>If the current thread:
+     *
+     * <ul>
+     *
+     * <li>has its interrupted status set on entry to this method; or
+     *
+     * <li>is {@linkplain Thread#interrupt interrupted} while
+     * acquiring the lock,
+     *
+     * </ul>
+     * then {@link InterruptedException} is thrown and the current thread's
+     * interrupted status is cleared.
+     *
+     * <p>If the specified waiting time elapses then the value {@code false}
+     * is returned.  If the time is less than or equal to zero, the method
+     * will not wait at all.
+     *
+     * <p>In this implementation, as this method is an explicit
+     * interruption point, preference is given to responding to the
+     * interrupt over normal or reentrant acquisition of the lock, and
+     * over reporting the elapse of the waiting time.
+     *
+     * @param timeout the time to wait for the lock
+     * @param unit the time unit of the timeout argument
+     * @return {@code true} if the lock was free and was acquired by the
+     *         current thread, or the lock was already held by the current
+     *         thread; and {@code false} if the waiting time elapsed before
+     *         the lock could be acquired
+     * @throws InterruptedException if the current thread is interrupted
+     * @throws NullPointerException if the time unit is null
+     */
+    public boolean tryLock(long timeout, TimeUnit unit)
+            throws InterruptedException {
+        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+    }
+
+    /**
+     * Attempts to release this lock.
+     *
+     * <p>If the current thread is the holder of this lock then the hold
+     * count is decremented.  If the hold count is now zero then the lock
+     * is released.  If the current thread is not the holder of this
+     * lock then {@link IllegalMonitorStateException} is thrown.
+     *
+     * @throws IllegalMonitorStateException if the current thread does not
+     *         hold this lock
+     */
+    public void unlock() {
+        sync.release(1);
+    }
+
+    /**
+     * Returns a {@link Condition} instance for use with this
+     * {@link Lock} instance.
+     *
+     * <p>The returned {@link Condition} instance supports the same
+     * usages as do the {@link Object} monitor methods ({@link
+     * Object#wait() wait}, {@link Object#notify notify}, and {@link
+     * Object#notifyAll notifyAll}) when used with the built-in
+     * monitor lock.
+     *
+     * <ul>
+     *
+     * <li>If this lock is not held when any of the {@link Condition}
+     * {@linkplain Condition#await() waiting} or {@linkplain
+     * Condition#signal signalling} methods are called, then an {@link
+     * IllegalMonitorStateException} is thrown.
+     *
+     * <li>When the condition {@linkplain Condition#await() waiting}
+     * methods are called the lock is released and, before they
+     * return, the lock is reacquired and the lock hold count restored
+     * to what it was when the method was called.
+     *
+     * <li>If a thread is {@linkplain Thread#interrupt interrupted}
+     * while waiting then the wait will terminate, an {@link
+     * InterruptedException} will be thrown, and the thread's
+     * interrupted status will be cleared.
+     *
+     * <li>Waiting threads are signalled in FIFO order.
+     *
+     * <li>The ordering of lock reacquisition for threads returning
+     * from waiting methods is the same as for threads initially
+     * acquiring the lock, which is in the default case not specified,
+     * but for <em>fair</em> locks favors those threads that have been
+     * waiting the longest.
+     *
+     * </ul>
+     *
+     * @return the Condition object
+     */
+    public Condition newCondition() {
+        return sync.newCondition();
+    }
+
+    /**
+     * Queries the number of holds on this lock by the current thread.
+     *
+     * <p>A thread has a hold on a lock for each lock action that is not
+     * matched by an unlock action.
+     *
+     * <p>The hold count information is typically only used for testing and
+     * debugging purposes. For example, if a certain section of code should
+     * not be entered with the lock already held then we can assert that
+     * fact:
+     *
+     * <pre> {@code
+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *   public void m() {
+     *     assert lock.getHoldCount() == 0;
+     *     lock.lock();
+     *     try {
+     *       // ... method body
+     *     } finally {
+     *       lock.unlock();
+     *     }
+     *   }
+     * }}</pre>
+     *
+     * @return the number of holds on this lock by the current thread,
+     *         or zero if this lock is not held by the current thread
+     */
+    public int getHoldCount() {
+        return sync.getHoldCount();
+    }
+
+    /**
+     * Queries if this lock is held by the current thread.
+     *
+     * <p>Analogous to the {@link Thread#holdsLock(Object)} method for
+     * built-in monitor locks, this method is typically used for
+     * debugging and testing. For example, a method that should only be
+     * called while a lock is held can assert that this is the case:
+     *
+     * <pre> {@code
+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert lock.isHeldByCurrentThread();
+     *       // ... method body
+     *   }
+     * }}</pre>
+     *
+     * <p>It can also be used to ensure that a reentrant lock is used
+     * in a non-reentrant manner, for example:
+     *
+     * <pre> {@code
+     * class X {
+     *   ReentrantLock lock = new ReentrantLock();
+     *   // ...
+     *
+     *   public void m() {
+     *       assert !lock.isHeldByCurrentThread();
+     *       lock.lock();
+     *       try {
+     *           // ... method body
+     *       } finally {
+     *           lock.unlock();
+     *       }
+     *   }
+     * }}</pre>
+     *
+     * @return {@code true} if current thread holds this lock and
+     *         {@code false} otherwise
+     */
+    public boolean isHeldByCurrentThread() {
+        return sync.isHeldExclusively();
+    }
+
+    /**
+     * Queries if this lock is held by any thread. This method is
+     * designed for use in monitoring of the system state,
+     * not for synchronization control.
+     *
+     * @return {@code true} if any thread holds this lock and
+     *         {@code false} otherwise
+     */
+    public boolean isLocked() {
+        return sync.isLocked();
+    }
+
+    /**
+     * Returns {@code true} if this lock has fairness set true.
+     *
+     * @return {@code true} if this lock has fairness set true
+     */
+    public final boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Returns the thread that currently owns this lock, or
+     * {@code null} if not owned. When this method is called by a
+     * thread that is not the owner, the return value reflects a
+     * best-effort approximation of current lock status. For example,
+     * the owner may be momentarily {@code null} even if there are
+     * threads trying to acquire the lock but have not yet done so.
+     * This method is designed to facilitate construction of
+     * subclasses that provide more extensive lock monitoring
+     * facilities.
+     *
+     * @return the owner, or {@code null} if not owned
+     */
+    protected Thread getOwner() {
+        return sync.getOwner();
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire this lock. Note that
+     * because cancellations may occur at any time, a {@code true}
+     * return does not guarantee that any other thread will ever
+     * acquire this lock.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Queries whether the given thread is waiting to acquire this
+     * lock. Note that because cancellations may occur at any time, a
+     * {@code true} return does not guarantee that this thread
+     * will ever acquire this lock.  This method is designed primarily for use
+     * in monitoring of the system state.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is queued waiting for this lock
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean hasQueuedThread(Thread thread) {
+        return sync.isQueued(thread);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire
+     * this lock.  The value is only an estimate because the number of
+     * threads may change dynamically while this method traverses
+     * internal data structures.  This method is designed for use in
+     * monitoring system state, not for synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire this lock.  Because the actual set of threads may change
+     * dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with this lock. Note that because timeouts and
+     * interrupts may occur at any time, a {@code true} return does
+     * not guarantee that a future {@code signal} will awaken any
+     * threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public boolean hasWaiters(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with this lock. Note that because
+     * timeouts and interrupts may occur at any time, the estimate
+     * serves only as an upper bound on the actual number of waiters.
+     * This method is designed for use in monitoring of the system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public int getWaitQueueLength(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with this lock.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a
+     * best-effort estimate. The elements of the returned collection
+     * are in no particular order.  This method is designed to
+     * facilitate construction of subclasses that provide more
+     * extensive condition monitoring facilities.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    protected Collection<Thread> getWaitingThreads(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock state.
+     * The state, in brackets, includes either the String {@code "Unlocked"}
+     * or the String {@code "Locked by"} followed by the
+     * {@linkplain Thread#getName name} of the owning thread.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        Thread o = sync.getOwner();
+        return super.toString() + ((o == null) ?
+                                   "[Unlocked]" :
+                                   "[Locked by thread " + o.getName() + "]");
+    }
+}
diff --git a/java/util/concurrent/locks/ReentrantReadWriteLock.java b/java/util/concurrent/locks/ReentrantReadWriteLock.java
new file mode 100644
index 0000000..9d98f37
--- /dev/null
+++ b/java/util/concurrent/locks/ReentrantReadWriteLock.java
@@ -0,0 +1,1515 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An implementation of {@link ReadWriteLock} supporting similar
+ * semantics to {@link ReentrantLock}.
+ * <p>This class has the following properties:
+ *
+ * <ul>
+ * <li><b>Acquisition order</b>
+ *
+ * <p>This class does not impose a reader or writer preference
+ * ordering for lock access.  However, it does support an optional
+ * <em>fairness</em> policy.
+ *
+ * <dl>
+ * <dt><b><i>Non-fair mode (default)</i></b>
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * When constructed as non-fair (the default), the order of entry
+ * to the read and write lock is unspecified, subject to reentrancy
+ * constraints.  A nonfair lock that is continuously contended may
+ * indefinitely postpone one or more reader or writer threads, but
+ * will normally have higher throughput than a fair lock.
+ *
+ * <dt><b><i>Fair mode</i></b>
+ * <dd style="font-family:'DejaVu Sans', Arial, Helvetica, sans-serif">
+ * When constructed as fair, threads contend for entry using an
+ * approximately arrival-order policy. When the currently held lock
+ * is released, either the longest-waiting single writer thread will
+ * be assigned the write lock, or if there is a group of reader threads
+ * waiting longer than all waiting writer threads, that group will be
+ * assigned the read lock.
+ *
+ * <p>A thread that tries to acquire a fair read lock (non-reentrantly)
+ * will block if either the write lock is held, or there is a waiting
+ * writer thread. The thread will not acquire the read lock until
+ * after the oldest currently waiting writer thread has acquired and
+ * released the write lock. Of course, if a waiting writer abandons
+ * its wait, leaving one or more reader threads as the longest waiters
+ * in the queue with the write lock free, then those readers will be
+ * assigned the read lock.
+ *
+ * <p>A thread that tries to acquire a fair write lock (non-reentrantly)
+ * will block unless both the read lock and write lock are free (which
+ * implies there are no waiting threads).  (Note that the non-blocking
+ * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods
+ * do not honor this fair setting and will immediately acquire the lock
+ * if it is possible, regardless of waiting threads.)
+ * </dl>
+ *
+ * <li><b>Reentrancy</b>
+ *
+ * <p>This lock allows both readers and writers to reacquire read or
+ * write locks in the style of a {@link ReentrantLock}. Non-reentrant
+ * readers are not allowed until all write locks held by the writing
+ * thread have been released.
+ *
+ * <p>Additionally, a writer can acquire the read lock, but not
+ * vice-versa.  Among other applications, reentrancy can be useful
+ * when write locks are held during calls or callbacks to methods that
+ * perform reads under read locks.  If a reader tries to acquire the
+ * write lock it will never succeed.
+ *
+ * <li><b>Lock downgrading</b>
+ * <p>Reentrancy also allows downgrading from the write lock to a read lock,
+ * by acquiring the write lock, then the read lock and then releasing the
+ * write lock. However, upgrading from a read lock to the write lock is
+ * <b>not</b> possible.
+ *
+ * <li><b>Interruption of lock acquisition</b>
+ * <p>The read lock and write lock both support interruption during lock
+ * acquisition.
+ *
+ * <li><b>{@link Condition} support</b>
+ * <p>The write lock provides a {@link Condition} implementation that
+ * behaves in the same way, with respect to the write lock, as the
+ * {@link Condition} implementation provided by
+ * {@link ReentrantLock#newCondition} does for {@link ReentrantLock}.
+ * This {@link Condition} can, of course, only be used with the write lock.
+ *
+ * <p>The read lock does not support a {@link Condition} and
+ * {@code readLock().newCondition()} throws
+ * {@code UnsupportedOperationException}.
+ *
+ * <li><b>Instrumentation</b>
+ * <p>This class supports methods to determine whether locks
+ * are held or contended. These methods are designed for monitoring
+ * system state, not for synchronization control.
+ * </ul>
+ *
+ * <p>Serialization of this class behaves in the same way as built-in
+ * locks: a deserialized lock is in the unlocked state, regardless of
+ * its state when serialized.
+ *
+ * <p><b>Sample usages</b>. Here is a code sketch showing how to perform
+ * lock downgrading after updating a cache (exception handling is
+ * particularly tricky when handling multiple locks in a non-nested
+ * fashion):
+ *
+ * <pre> {@code
+ * class CachedData {
+ *   Object data;
+ *   volatile boolean cacheValid;
+ *   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *
+ *   void processCachedData() {
+ *     rwl.readLock().lock();
+ *     if (!cacheValid) {
+ *       // Must release read lock before acquiring write lock
+ *       rwl.readLock().unlock();
+ *       rwl.writeLock().lock();
+ *       try {
+ *         // Recheck state because another thread might have
+ *         // acquired write lock and changed state before we did.
+ *         if (!cacheValid) {
+ *           data = ...
+ *           cacheValid = true;
+ *         }
+ *         // Downgrade by acquiring read lock before releasing write lock
+ *         rwl.readLock().lock();
+ *       } finally {
+ *         rwl.writeLock().unlock(); // Unlock write, still hold read
+ *       }
+ *     }
+ *
+ *     try {
+ *       use(data);
+ *     } finally {
+ *       rwl.readLock().unlock();
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * ReentrantReadWriteLocks can be used to improve concurrency in some
+ * uses of some kinds of Collections. This is typically worthwhile
+ * only when the collections are expected to be large, accessed by
+ * more reader threads than writer threads, and entail operations with
+ * overhead that outweighs synchronization overhead. For example, here
+ * is a class using a TreeMap that is expected to be large and
+ * concurrently accessed.
+ *
+ * <pre> {@code
+ * class RWDictionary {
+ *   private final Map<String, Data> m = new TreeMap<>();
+ *   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
+ *   private final Lock r = rwl.readLock();
+ *   private final Lock w = rwl.writeLock();
+ *
+ *   public Data get(String key) {
+ *     r.lock();
+ *     try { return m.get(key); }
+ *     finally { r.unlock(); }
+ *   }
+ *   public List<String> allKeys() {
+ *     r.lock();
+ *     try { return new ArrayList<>(m.keySet()); }
+ *     finally { r.unlock(); }
+ *   }
+ *   public Data put(String key, Data value) {
+ *     w.lock();
+ *     try { return m.put(key, value); }
+ *     finally { w.unlock(); }
+ *   }
+ *   public void clear() {
+ *     w.lock();
+ *     try { m.clear(); }
+ *     finally { w.unlock(); }
+ *   }
+ * }}</pre>
+ *
+ * <h3>Implementation Notes</h3>
+ *
+ * <p>This lock supports a maximum of 65535 recursive write locks
+ * and 65535 read locks. Attempts to exceed these limits result in
+ * {@link Error} throws from locking methods.
+ *
+ * @since 1.5
+ * @author Doug Lea
+ */
+public class ReentrantReadWriteLock
+        implements ReadWriteLock, java.io.Serializable {
+    private static final long serialVersionUID = -6992448646407690164L;
+    /** Inner class providing readlock */
+    private final ReentrantReadWriteLock.ReadLock readerLock;
+    /** Inner class providing writelock */
+    private final ReentrantReadWriteLock.WriteLock writerLock;
+    /** Performs all synchronization mechanics */
+    final Sync sync;
+
+    /**
+     * Creates a new {@code ReentrantReadWriteLock} with
+     * default (nonfair) ordering properties.
+     */
+    public ReentrantReadWriteLock() {
+        this(false);
+    }
+
+    /**
+     * Creates a new {@code ReentrantReadWriteLock} with
+     * the given fairness policy.
+     *
+     * @param fair {@code true} if this lock should use a fair ordering policy
+     */
+    public ReentrantReadWriteLock(boolean fair) {
+        sync = fair ? new FairSync() : new NonfairSync();
+        readerLock = new ReadLock(this);
+        writerLock = new WriteLock(this);
+    }
+
+    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
+    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }
+
+    /**
+     * Synchronization implementation for ReentrantReadWriteLock.
+     * Subclassed into fair and nonfair versions.
+     */
+    abstract static class Sync extends AbstractQueuedSynchronizer {
+        private static final long serialVersionUID = 6317671515068378041L;
+
+        /*
+         * Read vs write count extraction constants and functions.
+         * Lock state is logically divided into two unsigned shorts:
+         * The lower one representing the exclusive (writer) lock hold count,
+         * and the upper the shared (reader) hold count.
+         */
+
+        static final int SHARED_SHIFT   = 16;
+        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
+        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
+        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
+
+        /** Returns the number of shared holds represented in count. */
+        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
+        /** Returns the number of exclusive holds represented in count. */
+        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
+
+        /**
+         * A counter for per-thread read hold counts.
+         * Maintained as a ThreadLocal; cached in cachedHoldCounter.
+         */
+        static final class HoldCounter {
+            int count;          // initially 0
+            // Use id, not reference, to avoid garbage retention
+            final long tid = getThreadId(Thread.currentThread());
+        }
+
+        /**
+         * ThreadLocal subclass. Easiest to explicitly define for sake
+         * of deserialization mechanics.
+         */
+        static final class ThreadLocalHoldCounter
+            extends ThreadLocal<HoldCounter> {
+            public HoldCounter initialValue() {
+                return new HoldCounter();
+            }
+        }
+
+        /**
+         * The number of reentrant read locks held by current thread.
+         * Initialized only in constructor and readObject.
+         * Removed whenever a thread's read hold count drops to 0.
+         */
+        private transient ThreadLocalHoldCounter readHolds;
+
+        /**
+         * The hold count of the last thread to successfully acquire
+         * readLock. This saves ThreadLocal lookup in the common case
+         * where the next thread to release is the last one to
+         * acquire. This is non-volatile since it is just used
+         * as a heuristic, and would be great for threads to cache.
+         *
+         * <p>Can outlive the Thread for which it is caching the read
+         * hold count, but avoids garbage retention by not retaining a
+         * reference to the Thread.
+         *
+         * <p>Accessed via a benign data race; relies on the memory
+         * model's final field and out-of-thin-air guarantees.
+         */
+        private transient HoldCounter cachedHoldCounter;
+
+        /**
+         * firstReader is the first thread to have acquired the read lock.
+         * firstReaderHoldCount is firstReader's hold count.
+         *
+         * <p>More precisely, firstReader is the unique thread that last
+         * changed the shared count from 0 to 1, and has not released the
+         * read lock since then; null if there is no such thread.
+         *
+         * <p>Cannot cause garbage retention unless the thread terminated
+         * without relinquishing its read locks, since tryReleaseShared
+         * sets it to null.
+         *
+         * <p>Accessed via a benign data race; relies on the memory
+         * model's out-of-thin-air guarantees for references.
+         *
+         * <p>This allows tracking of read holds for uncontended read
+         * locks to be very cheap.
+         */
+        private transient Thread firstReader;
+        private transient int firstReaderHoldCount;
+
+        Sync() {
+            readHolds = new ThreadLocalHoldCounter();
+            setState(getState()); // ensures visibility of readHolds
+        }
+
+        /*
+         * Acquires and releases use the same code for fair and
+         * nonfair locks, but differ in whether/how they allow barging
+         * when queues are non-empty.
+         */
+
+        /**
+         * Returns true if the current thread, when trying to acquire
+         * the read lock, and otherwise eligible to do so, should block
+         * because of policy for overtaking other waiting threads.
+         */
+        abstract boolean readerShouldBlock();
+
+        /**
+         * Returns true if the current thread, when trying to acquire
+         * the write lock, and otherwise eligible to do so, should block
+         * because of policy for overtaking other waiting threads.
+         */
+        abstract boolean writerShouldBlock();
+
+        /*
+         * Note that tryRelease and tryAcquire can be called by
+         * Conditions. So it is possible that their arguments contain
+         * both read and write holds that are all released during a
+         * condition wait and re-established in tryAcquire.
+         */
+
+        protected final boolean tryRelease(int releases) {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
+            int nextc = getState() - releases;
+            boolean free = exclusiveCount(nextc) == 0;
+            if (free)
+                setExclusiveOwnerThread(null);
+            setState(nextc);
+            return free;
+        }
+
+        protected final boolean tryAcquire(int acquires) {
+            /*
+             * Walkthrough:
+             * 1. If read count nonzero or write count nonzero
+             *    and owner is a different thread, fail.
+             * 2. If count would saturate, fail. (This can only
+             *    happen if count is already nonzero.)
+             * 3. Otherwise, this thread is eligible for lock if
+             *    it is either a reentrant acquire or
+             *    queue policy allows it. If so, update state
+             *    and set owner.
+             */
+            Thread current = Thread.currentThread();
+            int c = getState();
+            int w = exclusiveCount(c);
+            if (c != 0) {
+                // (Note: if c != 0 and w == 0 then shared count != 0)
+                if (w == 0 || current != getExclusiveOwnerThread())
+                    return false;
+                if (w + exclusiveCount(acquires) > MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                // Reentrant acquire
+                setState(c + acquires);
+                return true;
+            }
+            if (writerShouldBlock() ||
+                !compareAndSetState(c, c + acquires))
+                return false;
+            setExclusiveOwnerThread(current);
+            return true;
+        }
+
+        protected final boolean tryReleaseShared(int unused) {
+            Thread current = Thread.currentThread();
+            if (firstReader == current) {
+                // assert firstReaderHoldCount > 0;
+                if (firstReaderHoldCount == 1)
+                    firstReader = null;
+                else
+                    firstReaderHoldCount--;
+            } else {
+                HoldCounter rh = cachedHoldCounter;
+                if (rh == null || rh.tid != getThreadId(current))
+                    rh = readHolds.get();
+                int count = rh.count;
+                if (count <= 1) {
+                    readHolds.remove();
+                    if (count <= 0)
+                        throw unmatchedUnlockException();
+                }
+                --rh.count;
+            }
+            for (;;) {
+                int c = getState();
+                int nextc = c - SHARED_UNIT;
+                if (compareAndSetState(c, nextc))
+                    // Releasing the read lock has no effect on readers,
+                    // but it may allow waiting writers to proceed if
+                    // both read and write locks are now free.
+                    return nextc == 0;
+            }
+        }
+
+        private IllegalMonitorStateException unmatchedUnlockException() {
+            return new IllegalMonitorStateException(
+                "attempt to unlock read lock, not locked by current thread");
+        }
+
+        protected final int tryAcquireShared(int unused) {
+            /*
+             * Walkthrough:
+             * 1. If write lock held by another thread, fail.
+             * 2. Otherwise, this thread is eligible for
+             *    lock wrt state, so ask if it should block
+             *    because of queue policy. If not, try
+             *    to grant by CASing state and updating count.
+             *    Note that step does not check for reentrant
+             *    acquires, which is postponed to full version
+             *    to avoid having to check hold count in
+             *    the more typical non-reentrant case.
+             * 3. If step 2 fails either because thread
+             *    apparently not eligible or CAS fails or count
+             *    saturated, chain to version with full retry loop.
+             */
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (exclusiveCount(c) != 0 &&
+                getExclusiveOwnerThread() != current)
+                return -1;
+            int r = sharedCount(c);
+            if (!readerShouldBlock() &&
+                r < MAX_COUNT &&
+                compareAndSetState(c, c + SHARED_UNIT)) {
+                if (r == 0) {
+                    firstReader = current;
+                    firstReaderHoldCount = 1;
+                } else if (firstReader == current) {
+                    firstReaderHoldCount++;
+                } else {
+                    HoldCounter rh = cachedHoldCounter;
+                    if (rh == null || rh.tid != getThreadId(current))
+                        cachedHoldCounter = rh = readHolds.get();
+                    else if (rh.count == 0)
+                        readHolds.set(rh);
+                    rh.count++;
+                }
+                return 1;
+            }
+            return fullTryAcquireShared(current);
+        }
+
+        /**
+         * Full version of acquire for reads, that handles CAS misses
+         * and reentrant reads not dealt with in tryAcquireShared.
+         */
+        final int fullTryAcquireShared(Thread current) {
+            /*
+             * This code is in part redundant with that in
+             * tryAcquireShared but is simpler overall by not
+             * complicating tryAcquireShared with interactions between
+             * retries and lazily reading hold counts.
+             */
+            HoldCounter rh = null;
+            for (;;) {
+                int c = getState();
+                if (exclusiveCount(c) != 0) {
+                    if (getExclusiveOwnerThread() != current)
+                        return -1;
+                    // else we hold the exclusive lock; blocking here
+                    // would cause deadlock.
+                } else if (readerShouldBlock()) {
+                    // Make sure we're not acquiring read lock reentrantly
+                    if (firstReader == current) {
+                        // assert firstReaderHoldCount > 0;
+                    } else {
+                        if (rh == null) {
+                            rh = cachedHoldCounter;
+                            if (rh == null || rh.tid != getThreadId(current)) {
+                                rh = readHolds.get();
+                                if (rh.count == 0)
+                                    readHolds.remove();
+                            }
+                        }
+                        if (rh.count == 0)
+                            return -1;
+                    }
+                }
+                if (sharedCount(c) == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                if (compareAndSetState(c, c + SHARED_UNIT)) {
+                    if (sharedCount(c) == 0) {
+                        firstReader = current;
+                        firstReaderHoldCount = 1;
+                    } else if (firstReader == current) {
+                        firstReaderHoldCount++;
+                    } else {
+                        if (rh == null)
+                            rh = cachedHoldCounter;
+                        if (rh == null || rh.tid != getThreadId(current))
+                            rh = readHolds.get();
+                        else if (rh.count == 0)
+                            readHolds.set(rh);
+                        rh.count++;
+                        cachedHoldCounter = rh; // cache for release
+                    }
+                    return 1;
+                }
+            }
+        }
+
+        /**
+         * Performs tryLock for write, enabling barging in both modes.
+         * This is identical in effect to tryAcquire except for lack
+         * of calls to writerShouldBlock.
+         */
+        final boolean tryWriteLock() {
+            Thread current = Thread.currentThread();
+            int c = getState();
+            if (c != 0) {
+                int w = exclusiveCount(c);
+                if (w == 0 || current != getExclusiveOwnerThread())
+                    return false;
+                if (w == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+            }
+            if (!compareAndSetState(c, c + 1))
+                return false;
+            setExclusiveOwnerThread(current);
+            return true;
+        }
+
+        /**
+         * Performs tryLock for read, enabling barging in both modes.
+         * This is identical in effect to tryAcquireShared except for
+         * lack of calls to readerShouldBlock.
+         */
+        final boolean tryReadLock() {
+            Thread current = Thread.currentThread();
+            for (;;) {
+                int c = getState();
+                if (exclusiveCount(c) != 0 &&
+                    getExclusiveOwnerThread() != current)
+                    return false;
+                int r = sharedCount(c);
+                if (r == MAX_COUNT)
+                    throw new Error("Maximum lock count exceeded");
+                if (compareAndSetState(c, c + SHARED_UNIT)) {
+                    if (r == 0) {
+                        firstReader = current;
+                        firstReaderHoldCount = 1;
+                    } else if (firstReader == current) {
+                        firstReaderHoldCount++;
+                    } else {
+                        HoldCounter rh = cachedHoldCounter;
+                        if (rh == null || rh.tid != getThreadId(current))
+                            cachedHoldCounter = rh = readHolds.get();
+                        else if (rh.count == 0)
+                            readHolds.set(rh);
+                        rh.count++;
+                    }
+                    return true;
+                }
+            }
+        }
+
+        protected final boolean isHeldExclusively() {
+            // While we must in general read state before owner,
+            // we don't need to do so to check if current thread is owner
+            return getExclusiveOwnerThread() == Thread.currentThread();
+        }
+
+        // Methods relayed to outer class
+
+        final ConditionObject newCondition() {
+            return new ConditionObject();
+        }
+
+        final Thread getOwner() {
+            // Must read state before owner to ensure memory consistency
+            return ((exclusiveCount(getState()) == 0) ?
+                    null :
+                    getExclusiveOwnerThread());
+        }
+
+        final int getReadLockCount() {
+            return sharedCount(getState());
+        }
+
+        final boolean isWriteLocked() {
+            return exclusiveCount(getState()) != 0;
+        }
+
+        final int getWriteHoldCount() {
+            return isHeldExclusively() ? exclusiveCount(getState()) : 0;
+        }
+
+        final int getReadHoldCount() {
+            if (getReadLockCount() == 0)
+                return 0;
+
+            Thread current = Thread.currentThread();
+            if (firstReader == current)
+                return firstReaderHoldCount;
+
+            HoldCounter rh = cachedHoldCounter;
+            if (rh != null && rh.tid == getThreadId(current))
+                return rh.count;
+
+            int count = readHolds.get().count;
+            if (count == 0) readHolds.remove();
+            return count;
+        }
+
+        /**
+         * Reconstitutes the instance from a stream (that is, deserializes it).
+         */
+        private void readObject(java.io.ObjectInputStream s)
+            throws java.io.IOException, ClassNotFoundException {
+            s.defaultReadObject();
+            readHolds = new ThreadLocalHoldCounter();
+            setState(0); // reset to unlocked state
+        }
+
+        final int getCount() { return getState(); }
+    }
+
+    /**
+     * Nonfair version of Sync
+     */
+    static final class NonfairSync extends Sync {
+        private static final long serialVersionUID = -8159625535654395037L;
+        final boolean writerShouldBlock() {
+            return false; // writers can always barge
+        }
+        final boolean readerShouldBlock() {
+            /* As a heuristic to avoid indefinite writer starvation,
+             * block if the thread that momentarily appears to be head
+             * of queue, if one exists, is a waiting writer.  This is
+             * only a probabilistic effect since a new reader will not
+             * block if there is a waiting writer behind other enabled
+             * readers that have not yet drained from the queue.
+             */
+            return apparentlyFirstQueuedIsExclusive();
+        }
+    }
+
+    /**
+     * Fair version of Sync
+     */
+    static final class FairSync extends Sync {
+        private static final long serialVersionUID = -2274990926593161451L;
+        final boolean writerShouldBlock() {
+            return hasQueuedPredecessors();
+        }
+        final boolean readerShouldBlock() {
+            return hasQueuedPredecessors();
+        }
+    }
+
+    /**
+     * The lock returned by method {@link ReentrantReadWriteLock#readLock}.
+     */
+    public static class ReadLock implements Lock, java.io.Serializable {
+        private static final long serialVersionUID = -5992448646407690164L;
+        private final Sync sync;
+
+        /**
+         * Constructor for use by subclasses.
+         *
+         * @param lock the outer lock object
+         * @throws NullPointerException if the lock is null
+         */
+        protected ReadLock(ReentrantReadWriteLock lock) {
+            sync = lock.sync;
+        }
+
+        /**
+         * Acquires the read lock.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately.
+         *
+         * <p>If the write lock is held by another thread then
+         * the current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until the read lock has been acquired.
+         */
+        public void lock() {
+            sync.acquireShared(1);
+        }
+
+        /**
+         * Acquires the read lock unless the current thread is
+         * {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the read lock if the write lock is not held
+         * by another thread and returns immediately.
+         *
+         * <p>If the write lock is held by another thread then the
+         * current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until one of two things happens:
+         *
+         * <ul>
+         *
+         * <li>The read lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread.
+         *
+         * </ul>
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method; or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the read lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         */
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireSharedInterruptibly(1);
+        }
+
+        /**
+         * Acquires the read lock only if the write lock is not held by
+         * another thread at the time of invocation.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately with the value
+         * {@code true}. Even when this lock has been set to use a
+         * fair ordering policy, a call to {@code tryLock()}
+         * <em>will</em> immediately acquire the read lock if it is
+         * available, whether or not other threads are currently
+         * waiting for the read lock.  This &quot;barging&quot; behavior
+         * can be useful in certain circumstances, even though it
+         * breaks fairness. If you want to honor the fairness setting
+         * for this lock, then use {@link #tryLock(long, TimeUnit)
+         * tryLock(0, TimeUnit.SECONDS) } which is almost equivalent
+         * (it also detects interruption).
+         *
+         * <p>If the write lock is held by another thread then
+         * this method will return immediately with the value
+         * {@code false}.
+         *
+         * @return {@code true} if the read lock was acquired
+         */
+        public boolean tryLock() {
+            return sync.tryReadLock();
+        }
+
+        /**
+         * Acquires the read lock if the write lock is not held by
+         * another thread within the given waiting time and the
+         * current thread has not been {@linkplain Thread#interrupt
+         * interrupted}.
+         *
+         * <p>Acquires the read lock if the write lock is not held by
+         * another thread and returns immediately with the value
+         * {@code true}. If this lock has been set to use a fair
+         * ordering policy then an available lock <em>will not</em> be
+         * acquired if any other threads are waiting for the
+         * lock. This is in contrast to the {@link #tryLock()}
+         * method. If you want a timed {@code tryLock} that does
+         * permit barging on a fair lock then combine the timed and
+         * un-timed forms together:
+         *
+         * <pre> {@code
+         * if (lock.tryLock() ||
+         *     lock.tryLock(timeout, unit)) {
+         *   ...
+         * }}</pre>
+         *
+         * <p>If the write lock is held by another thread then the
+         * current thread becomes disabled for thread scheduling
+         * purposes and lies dormant until one of three things happens:
+         *
+         * <ul>
+         *
+         * <li>The read lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread; or
+         *
+         * <li>The specified waiting time elapses.
+         *
+         * </ul>
+         *
+         * <p>If the read lock is acquired then the value {@code true} is
+         * returned.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method; or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the read lock,
+         *
+         * </ul> then {@link InterruptedException} is thrown and the
+         * current thread's interrupted status is cleared.
+         *
+         * <p>If the specified waiting time elapses then the value
+         * {@code false} is returned.  If the time is less than or
+         * equal to zero, the method will not wait at all.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock, and over reporting the elapse of the waiting time.
+         *
+         * @param timeout the time to wait for the read lock
+         * @param unit the time unit of the timeout argument
+         * @return {@code true} if the read lock was acquired
+         * @throws InterruptedException if the current thread is interrupted
+         * @throws NullPointerException if the time unit is null
+         */
+        public boolean tryLock(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
+        }
+
+        /**
+         * Attempts to release this lock.
+         *
+         * <p>If the number of readers is now zero then the lock
+         * is made available for write lock attempts. If the current
+         * thread does not hold this lock then {@link
+         * IllegalMonitorStateException} is thrown.
+         *
+         * @throws IllegalMonitorStateException if the current thread
+         * does not hold this lock
+         */
+        public void unlock() {
+            sync.releaseShared(1);
+        }
+
+        /**
+         * Throws {@code UnsupportedOperationException} because
+         * {@code ReadLocks} do not support conditions.
+         *
+         * @throws UnsupportedOperationException always
+         */
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Returns a string identifying this lock, as well as its lock state.
+         * The state, in brackets, includes the String {@code "Read locks ="}
+         * followed by the number of held read locks.
+         *
+         * @return a string identifying this lock, as well as its lock state
+         */
+        public String toString() {
+            int r = sync.getReadLockCount();
+            return super.toString() +
+                "[Read locks = " + r + "]";
+        }
+    }
+
+    /**
+     * The lock returned by method {@link ReentrantReadWriteLock#writeLock}.
+     */
+    public static class WriteLock implements Lock, java.io.Serializable {
+        private static final long serialVersionUID = -4992448646407690164L;
+        private final Sync sync;
+
+        /**
+         * Constructor for use by subclasses.
+         *
+         * @param lock the outer lock object
+         * @throws NullPointerException if the lock is null
+         */
+        protected WriteLock(ReentrantReadWriteLock lock) {
+            sync = lock.sync;
+        }
+
+        /**
+         * Acquires the write lock.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately, setting the write lock hold count to
+         * one.
+         *
+         * <p>If the current thread already holds the write lock then the
+         * hold count is incremented by one and the method returns
+         * immediately.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until the write lock has been acquired, at which
+         * time the write lock hold count is set to one.
+         */
+        public void lock() {
+            sync.acquire(1);
+        }
+
+        /**
+         * Acquires the write lock unless the current thread is
+         * {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately, setting the write lock hold count to
+         * one.
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * immediately.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until one of two things happens:
+         *
+         * <ul>
+         *
+         * <li>The write lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread.
+         *
+         * </ul>
+         *
+         * <p>If the write lock is acquired by the current thread then the
+         * lock hold count is set to one.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method;
+         * or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the write lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         */
+        public void lockInterruptibly() throws InterruptedException {
+            sync.acquireInterruptibly(1);
+        }
+
+        /**
+         * Acquires the write lock only if it is not held by another thread
+         * at the time of invocation.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately with the value {@code true},
+         * setting the write lock hold count to one. Even when this lock has
+         * been set to use a fair ordering policy, a call to
+         * {@code tryLock()} <em>will</em> immediately acquire the
+         * lock if it is available, whether or not other threads are
+         * currently waiting for the write lock.  This &quot;barging&quot;
+         * behavior can be useful in certain circumstances, even
+         * though it breaks fairness. If you want to honor the
+         * fairness setting for this lock, then use {@link
+         * #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
+         * which is almost equivalent (it also detects interruption).
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * {@code true}.
+         *
+         * <p>If the lock is held by another thread then this method
+         * will return immediately with the value {@code false}.
+         *
+         * @return {@code true} if the lock was free and was acquired
+         * by the current thread, or the write lock was already held
+         * by the current thread; and {@code false} otherwise.
+         */
+        public boolean tryLock() {
+            return sync.tryWriteLock();
+        }
+
+        /**
+         * Acquires the write lock if it is not held by another thread
+         * within the given waiting time and the current thread has
+         * not been {@linkplain Thread#interrupt interrupted}.
+         *
+         * <p>Acquires the write lock if neither the read nor write lock
+         * are held by another thread
+         * and returns immediately with the value {@code true},
+         * setting the write lock hold count to one. If this lock has been
+         * set to use a fair ordering policy then an available lock
+         * <em>will not</em> be acquired if any other threads are
+         * waiting for the write lock. This is in contrast to the {@link
+         * #tryLock()} method. If you want a timed {@code tryLock}
+         * that does permit barging on a fair lock then combine the
+         * timed and un-timed forms together:
+         *
+         * <pre> {@code
+         * if (lock.tryLock() ||
+         *     lock.tryLock(timeout, unit)) {
+         *   ...
+         * }}</pre>
+         *
+         * <p>If the current thread already holds this lock then the
+         * hold count is incremented by one and the method returns
+         * {@code true}.
+         *
+         * <p>If the lock is held by another thread then the current
+         * thread becomes disabled for thread scheduling purposes and
+         * lies dormant until one of three things happens:
+         *
+         * <ul>
+         *
+         * <li>The write lock is acquired by the current thread; or
+         *
+         * <li>Some other thread {@linkplain Thread#interrupt interrupts}
+         * the current thread; or
+         *
+         * <li>The specified waiting time elapses
+         *
+         * </ul>
+         *
+         * <p>If the write lock is acquired then the value {@code true} is
+         * returned and the write lock hold count is set to one.
+         *
+         * <p>If the current thread:
+         *
+         * <ul>
+         *
+         * <li>has its interrupted status set on entry to this method;
+         * or
+         *
+         * <li>is {@linkplain Thread#interrupt interrupted} while
+         * acquiring the write lock,
+         *
+         * </ul>
+         *
+         * then {@link InterruptedException} is thrown and the current
+         * thread's interrupted status is cleared.
+         *
+         * <p>If the specified waiting time elapses then the value
+         * {@code false} is returned.  If the time is less than or
+         * equal to zero, the method will not wait at all.
+         *
+         * <p>In this implementation, as this method is an explicit
+         * interruption point, preference is given to responding to
+         * the interrupt over normal or reentrant acquisition of the
+         * lock, and over reporting the elapse of the waiting time.
+         *
+         * @param timeout the time to wait for the write lock
+         * @param unit the time unit of the timeout argument
+         *
+         * @return {@code true} if the lock was free and was acquired
+         * by the current thread, or the write lock was already held by the
+         * current thread; and {@code false} if the waiting time
+         * elapsed before the lock could be acquired.
+         *
+         * @throws InterruptedException if the current thread is interrupted
+         * @throws NullPointerException if the time unit is null
+         */
+        public boolean tryLock(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        }
+
+        /**
+         * Attempts to release this lock.
+         *
+         * <p>If the current thread is the holder of this lock then
+         * the hold count is decremented. If the hold count is now
+         * zero then the lock is released.  If the current thread is
+         * not the holder of this lock then {@link
+         * IllegalMonitorStateException} is thrown.
+         *
+         * @throws IllegalMonitorStateException if the current thread does not
+         * hold this lock
+         */
+        public void unlock() {
+            sync.release(1);
+        }
+
+        /**
+         * Returns a {@link Condition} instance for use with this
+         * {@link Lock} instance.
+         * <p>The returned {@link Condition} instance supports the same
+         * usages as do the {@link Object} monitor methods ({@link
+         * Object#wait() wait}, {@link Object#notify notify}, and {@link
+         * Object#notifyAll notifyAll}) when used with the built-in
+         * monitor lock.
+         *
+         * <ul>
+         *
+         * <li>If this write lock is not held when any {@link
+         * Condition} method is called then an {@link
+         * IllegalMonitorStateException} is thrown.  (Read locks are
+         * held independently of write locks, so are not checked or
+         * affected. However it is essentially always an error to
+         * invoke a condition waiting method when the current thread
+         * has also acquired read locks, since other threads that
+         * could unblock it will not be able to acquire the write
+         * lock.)
+         *
+         * <li>When the condition {@linkplain Condition#await() waiting}
+         * methods are called the write lock is released and, before
+         * they return, the write lock is reacquired and the lock hold
+         * count restored to what it was when the method was called.
+         *
+         * <li>If a thread is {@linkplain Thread#interrupt interrupted} while
+         * waiting then the wait will terminate, an {@link
+         * InterruptedException} will be thrown, and the thread's
+         * interrupted status will be cleared.
+         *
+         * <li>Waiting threads are signalled in FIFO order.
+         *
+         * <li>The ordering of lock reacquisition for threads returning
+         * from waiting methods is the same as for threads initially
+         * acquiring the lock, which is in the default case not specified,
+         * but for <em>fair</em> locks favors those threads that have been
+         * waiting the longest.
+         *
+         * </ul>
+         *
+         * @return the Condition object
+         */
+        public Condition newCondition() {
+            return sync.newCondition();
+        }
+
+        /**
+         * Returns a string identifying this lock, as well as its lock
+         * state.  The state, in brackets includes either the String
+         * {@code "Unlocked"} or the String {@code "Locked by"}
+         * followed by the {@linkplain Thread#getName name} of the owning thread.
+         *
+         * @return a string identifying this lock, as well as its lock state
+         */
+        public String toString() {
+            Thread o = sync.getOwner();
+            return super.toString() + ((o == null) ?
+                                       "[Unlocked]" :
+                                       "[Locked by thread " + o.getName() + "]");
+        }
+
+        /**
+         * Queries if this write lock is held by the current thread.
+         * Identical in effect to {@link
+         * ReentrantReadWriteLock#isWriteLockedByCurrentThread}.
+         *
+         * @return {@code true} if the current thread holds this lock and
+         *         {@code false} otherwise
+         * @since 1.6
+         */
+        public boolean isHeldByCurrentThread() {
+            return sync.isHeldExclusively();
+        }
+
+        /**
+         * Queries the number of holds on this write lock by the current
+         * thread.  A thread has a hold on a lock for each lock action
+         * that is not matched by an unlock action.  Identical in effect
+         * to {@link ReentrantReadWriteLock#getWriteHoldCount}.
+         *
+         * @return the number of holds on this lock by the current thread,
+         *         or zero if this lock is not held by the current thread
+         * @since 1.6
+         */
+        public int getHoldCount() {
+            return sync.getWriteHoldCount();
+        }
+    }
+
+    // Instrumentation and status
+
+    /**
+     * Returns {@code true} if this lock has fairness set true.
+     *
+     * @return {@code true} if this lock has fairness set true
+     */
+    public final boolean isFair() {
+        return sync instanceof FairSync;
+    }
+
+    /**
+     * Returns the thread that currently owns the write lock, or
+     * {@code null} if not owned. When this method is called by a
+     * thread that is not the owner, the return value reflects a
+     * best-effort approximation of current lock status. For example,
+     * the owner may be momentarily {@code null} even if there are
+     * threads trying to acquire the lock but have not yet done so.
+     * This method is designed to facilitate construction of
+     * subclasses that provide more extensive lock monitoring
+     * facilities.
+     *
+     * @return the owner, or {@code null} if not owned
+     */
+    protected Thread getOwner() {
+        return sync.getOwner();
+    }
+
+    /**
+     * Queries the number of read locks held for this lock. This
+     * method is designed for use in monitoring system state, not for
+     * synchronization control.
+     * @return the number of read locks held
+     */
+    public int getReadLockCount() {
+        return sync.getReadLockCount();
+    }
+
+    /**
+     * Queries if the write lock is held by any thread. This method is
+     * designed for use in monitoring system state, not for
+     * synchronization control.
+     *
+     * @return {@code true} if any thread holds the write lock and
+     *         {@code false} otherwise
+     */
+    public boolean isWriteLocked() {
+        return sync.isWriteLocked();
+    }
+
+    /**
+     * Queries if the write lock is held by the current thread.
+     *
+     * @return {@code true} if the current thread holds the write lock and
+     *         {@code false} otherwise
+     */
+    public boolean isWriteLockedByCurrentThread() {
+        return sync.isHeldExclusively();
+    }
+
+    /**
+     * Queries the number of reentrant write holds on this lock by the
+     * current thread.  A writer thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the write lock by the current thread,
+     *         or zero if the write lock is not held by the current thread
+     */
+    public int getWriteHoldCount() {
+        return sync.getWriteHoldCount();
+    }
+
+    /**
+     * Queries the number of reentrant read holds on this lock by the
+     * current thread.  A reader thread has a hold on a lock for
+     * each lock action that is not matched by an unlock action.
+     *
+     * @return the number of holds on the read lock by the current thread,
+     *         or zero if the read lock is not held by the current thread
+     * @since 1.6
+     */
+    public int getReadHoldCount() {
+        return sync.getReadHoldCount();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire the write lock.  Because the actual set of threads may
+     * change dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive lock monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedWriterThreads() {
+        return sync.getExclusiveQueuedThreads();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire the read lock.  Because the actual set of threads may
+     * change dynamically while constructing this result, the returned
+     * collection is only a best-effort estimate.  The elements of the
+     * returned collection are in no particular order.  This method is
+     * designed to facilitate construction of subclasses that provide
+     * more extensive lock monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedReaderThreads() {
+        return sync.getSharedQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting to acquire the read or
+     * write lock. Note that because cancellations may occur at any
+     * time, a {@code true} return does not guarantee that any other
+     * thread will ever acquire a lock.  This method is designed
+     * primarily for use in monitoring of the system state.
+     *
+     * @return {@code true} if there may be other threads waiting to
+     *         acquire the lock
+     */
+    public final boolean hasQueuedThreads() {
+        return sync.hasQueuedThreads();
+    }
+
+    /**
+     * Queries whether the given thread is waiting to acquire either
+     * the read or write lock. Note that because cancellations may
+     * occur at any time, a {@code true} return does not guarantee
+     * that this thread will ever acquire a lock.  This method is
+     * designed primarily for use in monitoring of the system state.
+     *
+     * @param thread the thread
+     * @return {@code true} if the given thread is queued waiting for this lock
+     * @throws NullPointerException if the thread is null
+     */
+    public final boolean hasQueuedThread(Thread thread) {
+        return sync.isQueued(thread);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting to acquire
+     * either the read or write lock.  The value is only an estimate
+     * because the number of threads may change dynamically while this
+     * method traverses internal data structures.  This method is
+     * designed for use in monitoring system state, not for
+     * synchronization control.
+     *
+     * @return the estimated number of threads waiting for this lock
+     */
+    public final int getQueueLength() {
+        return sync.getQueueLength();
+    }
+
+    /**
+     * Returns a collection containing threads that may be waiting to
+     * acquire either the read or write lock.  Because the actual set
+     * of threads may change dynamically while constructing this
+     * result, the returned collection is only a best-effort estimate.
+     * The elements of the returned collection are in no particular
+     * order.  This method is designed to facilitate construction of
+     * subclasses that provide more extensive monitoring facilities.
+     *
+     * @return the collection of threads
+     */
+    protected Collection<Thread> getQueuedThreads() {
+        return sync.getQueuedThreads();
+    }
+
+    /**
+     * Queries whether any threads are waiting on the given condition
+     * associated with the write lock. Note that because timeouts and
+     * interrupts may occur at any time, a {@code true} return does
+     * not guarantee that a future {@code signal} will awaken any
+     * threads.  This method is designed primarily for use in
+     * monitoring of the system state.
+     *
+     * @param condition the condition
+     * @return {@code true} if there are any waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public boolean hasWaiters(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns an estimate of the number of threads waiting on the
+     * given condition associated with the write lock. Note that because
+     * timeouts and interrupts may occur at any time, the estimate
+     * serves only as an upper bound on the actual number of waiters.
+     * This method is designed for use in monitoring of the system
+     * state, not for synchronization control.
+     *
+     * @param condition the condition
+     * @return the estimated number of waiting threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    public int getWaitQueueLength(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a collection containing those threads that may be
+     * waiting on the given condition associated with the write lock.
+     * Because the actual set of threads may change dynamically while
+     * constructing this result, the returned collection is only a
+     * best-effort estimate. The elements of the returned collection
+     * are in no particular order.  This method is designed to
+     * facilitate construction of subclasses that provide more
+     * extensive condition monitoring facilities.
+     *
+     * @param condition the condition
+     * @return the collection of threads
+     * @throws IllegalMonitorStateException if this lock is not held
+     * @throws IllegalArgumentException if the given condition is
+     *         not associated with this lock
+     * @throws NullPointerException if the condition is null
+     */
+    protected Collection<Thread> getWaitingThreads(Condition condition) {
+        if (condition == null)
+            throw new NullPointerException();
+        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
+            throw new IllegalArgumentException("not owner");
+        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock state.
+     * The state, in brackets, includes the String {@code "Write locks ="}
+     * followed by the number of reentrantly held write locks, and the
+     * String {@code "Read locks ="} followed by the number of held
+     * read locks.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        int c = sync.getCount();
+        int w = Sync.exclusiveCount(c);
+        int r = Sync.sharedCount(c);
+
+        return super.toString() +
+            "[Write locks = " + w + ", Read locks = " + r + "]";
+    }
+
+    /**
+     * Returns the thread id for the given thread.  We must access
+     * this directly rather than via method Thread.getId() because
+     * getId() is not final, and has been known to be overridden in
+     * ways that do not preserve unique mappings.
+     */
+    static final long getThreadId(Thread thread) {
+        return U.getLongVolatile(thread, TID);
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long TID;
+    static {
+        try {
+            TID = U.objectFieldOffset
+                (Thread.class.getDeclaredField("tid"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+
+}
diff --git a/java/util/concurrent/locks/StampedLock.java b/java/util/concurrent/locks/StampedLock.java
new file mode 100644
index 0000000..d689599
--- /dev/null
+++ b/java/util/concurrent/locks/StampedLock.java
@@ -0,0 +1,1432 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.locks;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A capability-based lock with three modes for controlling read/write
+ * access.  The state of a StampedLock consists of a version and mode.
+ * Lock acquisition methods return a stamp that represents and
+ * controls access with respect to a lock state; "try" versions of
+ * these methods may instead return the special value zero to
+ * represent failure to acquire access. Lock release and conversion
+ * methods require stamps as arguments, and fail if they do not match
+ * the state of the lock. The three modes are:
+ *
+ * <ul>
+ *
+ *  <li><b>Writing.</b> Method {@link #writeLock} possibly blocks
+ *   waiting for exclusive access, returning a stamp that can be used
+ *   in method {@link #unlockWrite} to release the lock. Untimed and
+ *   timed versions of {@code tryWriteLock} are also provided. When
+ *   the lock is held in write mode, no read locks may be obtained,
+ *   and all optimistic read validations will fail.
+ *
+ *  <li><b>Reading.</b> Method {@link #readLock} possibly blocks
+ *   waiting for non-exclusive access, returning a stamp that can be
+ *   used in method {@link #unlockRead} to release the lock. Untimed
+ *   and timed versions of {@code tryReadLock} are also provided.
+ *
+ *  <li><b>Optimistic Reading.</b> Method {@link #tryOptimisticRead}
+ *   returns a non-zero stamp only if the lock is not currently held
+ *   in write mode. Method {@link #validate} returns true if the lock
+ *   has not been acquired in write mode since obtaining a given
+ *   stamp.  This mode can be thought of as an extremely weak version
+ *   of a read-lock, that can be broken by a writer at any time.  The
+ *   use of optimistic mode for short read-only code segments often
+ *   reduces contention and improves throughput.  However, its use is
+ *   inherently fragile.  Optimistic read sections should only read
+ *   fields and hold them in local variables for later use after
+ *   validation. Fields read while in optimistic mode may be wildly
+ *   inconsistent, so usage applies only when you are familiar enough
+ *   with data representations to check consistency and/or repeatedly
+ *   invoke method {@code validate()}.  For example, such steps are
+ *   typically required when first reading an object or array
+ *   reference, and then accessing one of its fields, elements or
+ *   methods.
+ *
+ * </ul>
+ *
+ * <p>This class also supports methods that conditionally provide
+ * conversions across the three modes. For example, method {@link
+ * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning
+ * a valid write stamp if (1) already in writing mode (2) in reading
+ * mode and there are no other readers or (3) in optimistic mode and
+ * the lock is available. The forms of these methods are designed to
+ * help reduce some of the code bloat that otherwise occurs in
+ * retry-based designs.
+ *
+ * <p>StampedLocks are designed for use as internal utilities in the
+ * development of thread-safe components. Their use relies on
+ * knowledge of the internal properties of the data, objects, and
+ * methods they are protecting.  They are not reentrant, so locked
+ * bodies should not call other unknown methods that may try to
+ * re-acquire locks (although you may pass a stamp to other methods
+ * that can use or convert it).  The use of read lock modes relies on
+ * the associated code sections being side-effect-free.  Unvalidated
+ * optimistic read sections cannot call methods that are not known to
+ * tolerate potential inconsistencies.  Stamps use finite
+ * representations, and are not cryptographically secure (i.e., a
+ * valid stamp may be guessable). Stamp values may recycle after (no
+ * sooner than) one year of continuous operation. A stamp held without
+ * use or validation for longer than this period may fail to validate
+ * correctly.  StampedLocks are serializable, but always deserialize
+ * into initial unlocked state, so they are not useful for remote
+ * locking.
+ *
+ * <p>The scheduling policy of StampedLock does not consistently
+ * prefer readers over writers or vice versa.  All "try" methods are
+ * best-effort and do not necessarily conform to any scheduling or
+ * fairness policy. A zero return from any "try" method for acquiring
+ * or converting locks does not carry any information about the state
+ * of the lock; a subsequent invocation may succeed.
+ *
+ * <p>Because it supports coordinated usage across multiple lock
+ * modes, this class does not directly implement the {@link Lock} or
+ * {@link ReadWriteLock} interfaces. However, a StampedLock may be
+ * viewed {@link #asReadLock()}, {@link #asWriteLock()}, or {@link
+ * #asReadWriteLock()} in applications requiring only the associated
+ * set of functionality.
+ *
+ * <p><b>Sample Usage.</b> The following illustrates some usage idioms
+ * in a class that maintains simple two-dimensional points. The sample
+ * code illustrates some try/catch conventions even though they are
+ * not strictly needed here because no exceptions can occur in their
+ * bodies.<br>
+ *
+ * <pre> {@code
+ * class Point {
+ *   private double x, y;
+ *   private final StampedLock sl = new StampedLock();
+ *
+ *   void move(double deltaX, double deltaY) { // an exclusively locked method
+ *     long stamp = sl.writeLock();
+ *     try {
+ *       x += deltaX;
+ *       y += deltaY;
+ *     } finally {
+ *       sl.unlockWrite(stamp);
+ *     }
+ *   }
+ *
+ *   double distanceFromOrigin() { // A read-only method
+ *     long stamp = sl.tryOptimisticRead();
+ *     double currentX = x, currentY = y;
+ *     if (!sl.validate(stamp)) {
+ *        stamp = sl.readLock();
+ *        try {
+ *          currentX = x;
+ *          currentY = y;
+ *        } finally {
+ *           sl.unlockRead(stamp);
+ *        }
+ *     }
+ *     return Math.sqrt(currentX * currentX + currentY * currentY);
+ *   }
+ *
+ *   void moveIfAtOrigin(double newX, double newY) { // upgrade
+ *     // Could instead start with optimistic, not read mode
+ *     long stamp = sl.readLock();
+ *     try {
+ *       while (x == 0.0 && y == 0.0) {
+ *         long ws = sl.tryConvertToWriteLock(stamp);
+ *         if (ws != 0L) {
+ *           stamp = ws;
+ *           x = newX;
+ *           y = newY;
+ *           break;
+ *         }
+ *         else {
+ *           sl.unlockRead(stamp);
+ *           stamp = sl.writeLock();
+ *         }
+ *       }
+ *     } finally {
+ *       sl.unlock(stamp);
+ *     }
+ *   }
+ * }}</pre>
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class StampedLock implements java.io.Serializable {
+    /*
+     * Algorithmic notes:
+     *
+     * The design employs elements of Sequence locks
+     * (as used in linux kernels; see Lameter's
+     * http://www.lameter.com/gelato2005.pdf
+     * and elsewhere; see
+     * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html)
+     * and Ordered RW locks (see Shirako et al
+     * http://dl.acm.org/citation.cfm?id=2312015)
+     *
+     * Conceptually, the primary state of the lock includes a sequence
+     * number that is odd when write-locked and even otherwise.
+     * However, this is offset by a reader count that is non-zero when
+     * read-locked.  The read count is ignored when validating
+     * "optimistic" seqlock-reader-style stamps.  Because we must use
+     * a small finite number of bits (currently 7) for readers, a
+     * supplementary reader overflow word is used when the number of
+     * readers exceeds the count field. We do this by treating the max
+     * reader count value (RBITS) as a spinlock protecting overflow
+     * updates.
+     *
+     * Waiters use a modified form of CLH lock used in
+     * AbstractQueuedSynchronizer (see its internal documentation for
+     * a fuller account), where each node is tagged (field mode) as
+     * either a reader or writer. Sets of waiting readers are grouped
+     * (linked) under a common node (field cowait) so act as a single
+     * node with respect to most CLH mechanics.  By virtue of the
+     * queue structure, wait nodes need not actually carry sequence
+     * numbers; we know each is greater than its predecessor.  This
+     * simplifies the scheduling policy to a mainly-FIFO scheme that
+     * incorporates elements of Phase-Fair locks (see Brandenburg &
+     * Anderson, especially http://www.cs.unc.edu/~bbb/diss/).  In
+     * particular, we use the phase-fair anti-barging rule: If an
+     * incoming reader arrives while read lock is held but there is a
+     * queued writer, this incoming reader is queued.  (This rule is
+     * responsible for some of the complexity of method acquireRead,
+     * but without it, the lock becomes highly unfair.) Method release
+     * does not (and sometimes cannot) itself wake up cowaiters. This
+     * is done by the primary thread, but helped by any other threads
+     * with nothing better to do in methods acquireRead and
+     * acquireWrite.
+     *
+     * These rules apply to threads actually queued. All tryLock forms
+     * opportunistically try to acquire locks regardless of preference
+     * rules, and so may "barge" their way in.  Randomized spinning is
+     * used in the acquire methods to reduce (increasingly expensive)
+     * context switching while also avoiding sustained memory
+     * thrashing among many threads.  We limit spins to the head of
+     * queue. A thread spin-waits up to SPINS times (where each
+     * iteration decreases spin count with 50% probability) before
+     * blocking. If, upon wakening it fails to obtain lock, and is
+     * still (or becomes) the first waiting thread (which indicates
+     * that some other thread barged and obtained lock), it escalates
+     * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
+     * continually losing to barging threads.
+     *
+     * Nearly all of these mechanics are carried out in methods
+     * acquireWrite and acquireRead, that, as typical of such code,
+     * sprawl out because actions and retries rely on consistent sets
+     * of locally cached reads.
+     *
+     * As noted in Boehm's paper (above), sequence validation (mainly
+     * method validate()) requires stricter ordering rules than apply
+     * to normal volatile reads (of "state").  To force orderings of
+     * reads before a validation and the validation itself in those
+     * cases where this is not already forced, we use
+     * Unsafe.loadFence.
+     *
+     * The memory layout keeps lock state and queue pointers together
+     * (normally on the same cache line). This usually works well for
+     * read-mostly loads. In most other cases, the natural tendency of
+     * adaptive-spin CLH locks to reduce memory contention lessens
+     * motivation to further spread out contended locations, but might
+     * be subject to future improvements.
+     */
+
+    private static final long serialVersionUID = -6001602636862214147L;
+
+    /** Number of processors, for spin control */
+    private static final int NCPU = Runtime.getRuntime().availableProcessors();
+
+    /** Maximum number of retries before enqueuing on acquisition */
+    private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0;
+
+    /** Maximum number of retries before blocking at head on acquisition */
+    private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 0;
+
+    /** Maximum number of retries before re-blocking */
+    private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 0;
+
+    /** The period for yielding when waiting for overflow spinlock */
+    private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
+
+    /** The number of bits to use for reader count before overflowing */
+    private static final int LG_READERS = 7;
+
+    // Values for lock state and stamp operations
+    private static final long RUNIT = 1L;
+    private static final long WBIT  = 1L << LG_READERS;
+    private static final long RBITS = WBIT - 1L;
+    private static final long RFULL = RBITS - 1L;
+    private static final long ABITS = RBITS | WBIT;
+    private static final long SBITS = ~RBITS; // note overlap with ABITS
+
+    // Initial value for lock state; avoid failure value zero
+    private static final long ORIGIN = WBIT << 1;
+
+    // Special value from cancelled acquire methods so caller can throw IE
+    private static final long INTERRUPTED = 1L;
+
+    // Values for node status; order matters
+    private static final int WAITING   = -1;
+    private static final int CANCELLED =  1;
+
+    // Modes for nodes (int not boolean to allow arithmetic)
+    private static final int RMODE = 0;
+    private static final int WMODE = 1;
+
+    /** Wait nodes */
+    static final class WNode {
+        volatile WNode prev;
+        volatile WNode next;
+        volatile WNode cowait;    // list of linked readers
+        volatile Thread thread;   // non-null while possibly parked
+        volatile int status;      // 0, WAITING, or CANCELLED
+        final int mode;           // RMODE or WMODE
+        WNode(int m, WNode p) { mode = m; prev = p; }
+    }
+
+    /** Head of CLH queue */
+    private transient volatile WNode whead;
+    /** Tail (last) of CLH queue */
+    private transient volatile WNode wtail;
+
+    // views
+    transient ReadLockView readLockView;
+    transient WriteLockView writeLockView;
+    transient ReadWriteLockView readWriteLockView;
+
+    /** Lock sequence/state */
+    private transient volatile long state;
+    /** extra reader count when state read count saturated */
+    private transient int readerOverflow;
+
+    /**
+     * Creates a new lock, initially in unlocked state.
+     */
+    public StampedLock() {
+        state = ORIGIN;
+    }
+
+    /**
+     * Exclusively acquires the lock, blocking if necessary
+     * until available.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     */
+    public long writeLock() {
+        long s, next;  // bypass acquireWrite in fully unlocked case only
+        return ((((s = state) & ABITS) == 0L &&
+                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
+                next : acquireWrite(false, 0L));
+    }
+
+    /**
+     * Exclusively acquires the lock if it is immediately available.
+     *
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     */
+    public long tryWriteLock() {
+        long s, next;
+        return ((((s = state) & ABITS) == 0L &&
+                 U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ?
+                next : 0L);
+    }
+
+    /**
+     * Exclusively acquires the lock if it is available within the
+     * given time and the current thread has not been interrupted.
+     * Behavior under timeout and interruption matches that specified
+     * for method {@link Lock#tryLock(long,TimeUnit)}.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long tryWriteLock(long time, TimeUnit unit)
+        throws InterruptedException {
+        long nanos = unit.toNanos(time);
+        if (!Thread.interrupted()) {
+            long next, deadline;
+            if ((next = tryWriteLock()) != 0L)
+                return next;
+            if (nanos <= 0L)
+                return 0L;
+            if ((deadline = System.nanoTime() + nanos) == 0L)
+                deadline = 1L;
+            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
+                return next;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Exclusively acquires the lock, blocking if necessary
+     * until available or the current thread is interrupted.
+     * Behavior under interruption matches that specified
+     * for method {@link Lock#lockInterruptibly()}.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long writeLockInterruptibly() throws InterruptedException {
+        long next;
+        if (!Thread.interrupted() &&
+            (next = acquireWrite(true, 0L)) != INTERRUPTED)
+            return next;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Non-exclusively acquires the lock, blocking if necessary
+     * until available.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     */
+    public long readLock() {
+        long s = state, next;  // bypass acquireRead on common uncontended case
+        return ((whead == wtail && (s & ABITS) < RFULL &&
+                 U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ?
+                next : acquireRead(false, 0L));
+    }
+
+    /**
+     * Non-exclusively acquires the lock if it is immediately available.
+     *
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     */
+    public long tryReadLock() {
+        for (;;) {
+            long s, m, next;
+            if ((m = (s = state) & ABITS) == WBIT)
+                return 0L;
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                    return next;
+            }
+            else if ((next = tryIncReaderOverflow(s)) != 0L)
+                return next;
+        }
+    }
+
+    /**
+     * Non-exclusively acquires the lock if it is available within the
+     * given time and the current thread has not been interrupted.
+     * Behavior under timeout and interruption matches that specified
+     * for method {@link Lock#tryLock(long,TimeUnit)}.
+     *
+     * @param time the maximum time to wait for the lock
+     * @param unit the time unit of the {@code time} argument
+     * @return a stamp that can be used to unlock or convert mode,
+     * or zero if the lock is not available
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long tryReadLock(long time, TimeUnit unit)
+        throws InterruptedException {
+        long s, m, next, deadline;
+        long nanos = unit.toNanos(time);
+        if (!Thread.interrupted()) {
+            if ((m = (s = state) & ABITS) != WBIT) {
+                if (m < RFULL) {
+                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                        return next;
+                }
+                else if ((next = tryIncReaderOverflow(s)) != 0L)
+                    return next;
+            }
+            if (nanos <= 0L)
+                return 0L;
+            if ((deadline = System.nanoTime() + nanos) == 0L)
+                deadline = 1L;
+            if ((next = acquireRead(true, deadline)) != INTERRUPTED)
+                return next;
+        }
+        throw new InterruptedException();
+    }
+
+    /**
+     * Non-exclusively acquires the lock, blocking if necessary
+     * until available or the current thread is interrupted.
+     * Behavior under interruption matches that specified
+     * for method {@link Lock#lockInterruptibly()}.
+     *
+     * @return a stamp that can be used to unlock or convert mode
+     * @throws InterruptedException if the current thread is interrupted
+     * before acquiring the lock
+     */
+    public long readLockInterruptibly() throws InterruptedException {
+        long next;
+        if (!Thread.interrupted() &&
+            (next = acquireRead(true, 0L)) != INTERRUPTED)
+            return next;
+        throw new InterruptedException();
+    }
+
+    /**
+     * Returns a stamp that can later be validated, or zero
+     * if exclusively locked.
+     *
+     * @return a stamp, or zero if exclusively locked
+     */
+    public long tryOptimisticRead() {
+        long s;
+        return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L;
+    }
+
+    /**
+     * Returns true if the lock has not been exclusively acquired
+     * since issuance of the given stamp. Always returns false if the
+     * stamp is zero. Always returns true if the stamp represents a
+     * currently held lock. Invoking this method with a value not
+     * obtained from {@link #tryOptimisticRead} or a locking method
+     * for this lock has no defined effect or result.
+     *
+     * @param stamp a stamp
+     * @return {@code true} if the lock has not been exclusively acquired
+     * since issuance of the given stamp; else false
+     */
+    public boolean validate(long stamp) {
+        U.loadFence();
+        return (stamp & SBITS) == (state & SBITS);
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * exclusive lock.
+     *
+     * @param stamp a stamp returned by a write-lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlockWrite(long stamp) {
+        WNode h;
+        if (state != stamp || (stamp & WBIT) == 0L)
+            throw new IllegalMonitorStateException();
+        U.putLongVolatile(this, STATE, (stamp += WBIT) == 0L ? ORIGIN : stamp);
+        if ((h = whead) != null && h.status != 0)
+            release(h);
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * non-exclusive lock.
+     *
+     * @param stamp a stamp returned by a read-lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlockRead(long stamp) {
+        long s, m; WNode h;
+        for (;;) {
+            if (((s = state) & SBITS) != (stamp & SBITS) ||
+                (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT)
+                throw new IllegalMonitorStateException();
+            if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    break;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                break;
+        }
+    }
+
+    /**
+     * If the lock state matches the given stamp, releases the
+     * corresponding mode of the lock.
+     *
+     * @param stamp a stamp returned by a lock operation
+     * @throws IllegalMonitorStateException if the stamp does
+     * not match the current state of this lock
+     */
+    public void unlock(long stamp) {
+        long a = stamp & ABITS, m, s; WNode h;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L)
+                break;
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return;
+            }
+            else if (a == 0L || a >= WBIT)
+                break;
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    return;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                return;
+        }
+        throw new IllegalMonitorStateException();
+    }
+
+    /**
+     * If the lock state matches the given stamp, atomically performs one of
+     * the following actions. If the stamp represents holding a write
+     * lock, returns it.  Or, if a read lock, if the write lock is
+     * available, releases the read lock and returns a write stamp.
+     * Or, if an optimistic read, returns a write stamp only if
+     * immediately available. This method returns zero in all other
+     * cases.
+     *
+     * @param stamp a stamp
+     * @return a valid write stamp, or zero on failure
+     */
+    public long tryConvertToWriteLock(long stamp) {
+        long a = stamp & ABITS, m, s, next;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT))
+                    return next;
+            }
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                return stamp;
+            }
+            else if (m == RUNIT && a != 0L) {
+                if (U.compareAndSwapLong(this, STATE, s,
+                                         next = s - RUNIT + WBIT))
+                    return next;
+            }
+            else
+                break;
+        }
+        return 0L;
+    }
+
+    /**
+     * If the lock state matches the given stamp, atomically performs one of
+     * the following actions. If the stamp represents holding a write
+     * lock, releases it and obtains a read lock.  Or, if a read lock,
+     * returns it. Or, if an optimistic read, acquires a read lock and
+     * returns a read stamp only if immediately available. This method
+     * returns zero in all other cases.
+     *
+     * @param stamp a stamp
+     * @return a valid read stamp, or zero on failure
+     */
+    public long tryConvertToReadLock(long stamp) {
+        long a = stamp & ABITS, m, s, next; WNode h;
+        while (((s = state) & SBITS) == (stamp & SBITS)) {
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                else if (m < RFULL) {
+                    if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT))
+                        return next;
+                }
+                else if ((next = tryIncReaderOverflow(s)) != 0L)
+                    return next;
+            }
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                U.putLongVolatile(this, STATE, next = s + (WBIT + RUNIT));
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return next;
+            }
+            else if (a != 0L && a < WBIT)
+                return stamp;
+            else
+                break;
+        }
+        return 0L;
+    }
+
+    /**
+     * If the lock state matches the given stamp then, atomically, if the stamp
+     * represents holding a lock, releases it and returns an
+     * observation stamp.  Or, if an optimistic read, returns it if
+     * validated. This method returns zero in all other cases, and so
+     * may be useful as a form of "tryUnlock".
+     *
+     * @param stamp a stamp
+     * @return a valid optimistic read stamp, or zero on failure
+     */
+    public long tryConvertToOptimisticRead(long stamp) {
+        long a = stamp & ABITS, m, s, next; WNode h;
+        U.loadFence();
+        for (;;) {
+            if (((s = state) & SBITS) != (stamp & SBITS))
+                break;
+            if ((m = s & ABITS) == 0L) {
+                if (a != 0L)
+                    break;
+                return s;
+            }
+            else if (m == WBIT) {
+                if (a != m)
+                    break;
+                U.putLongVolatile(this, STATE,
+                                  next = (s += WBIT) == 0L ? ORIGIN : s);
+                if ((h = whead) != null && h.status != 0)
+                    release(h);
+                return next;
+            }
+            else if (a == 0L || a >= WBIT)
+                break;
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    return next & SBITS;
+                }
+            }
+            else if ((next = tryDecReaderOverflow(s)) != 0L)
+                return next & SBITS;
+        }
+        return 0L;
+    }
+
+    /**
+     * Releases the write lock if it is held, without requiring a
+     * stamp value. This method may be useful for recovery after
+     * errors.
+     *
+     * @return {@code true} if the lock was held, else false
+     */
+    public boolean tryUnlockWrite() {
+        long s; WNode h;
+        if (((s = state) & WBIT) != 0L) {
+            U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
+            if ((h = whead) != null && h.status != 0)
+                release(h);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Releases one hold of the read lock if it is held, without
+     * requiring a stamp value. This method may be useful for recovery
+     * after errors.
+     *
+     * @return {@code true} if the read lock was held, else false
+     */
+    public boolean tryUnlockRead() {
+        long s, m; WNode h;
+        while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
+            if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    return true;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                return true;
+        }
+        return false;
+    }
+
+    // status monitoring methods
+
+    /**
+     * Returns combined state-held and overflow read count for given
+     * state s.
+     */
+    private int getReadLockCount(long s) {
+        long readers;
+        if ((readers = s & RBITS) >= RFULL)
+            readers = RFULL + readerOverflow;
+        return (int) readers;
+    }
+
+    /**
+     * Returns {@code true} if the lock is currently held exclusively.
+     *
+     * @return {@code true} if the lock is currently held exclusively
+     */
+    public boolean isWriteLocked() {
+        return (state & WBIT) != 0L;
+    }
+
+    /**
+     * Returns {@code true} if the lock is currently held non-exclusively.
+     *
+     * @return {@code true} if the lock is currently held non-exclusively
+     */
+    public boolean isReadLocked() {
+        return (state & RBITS) != 0L;
+    }
+
+    /**
+     * Queries the number of read locks held for this lock. This
+     * method is designed for use in monitoring system state, not for
+     * synchronization control.
+     * @return the number of read locks held
+     */
+    public int getReadLockCount() {
+        return getReadLockCount(state);
+    }
+
+    /**
+     * Returns a string identifying this lock, as well as its lock
+     * state.  The state, in brackets, includes the String {@code
+     * "Unlocked"} or the String {@code "Write-locked"} or the String
+     * {@code "Read-locks:"} followed by the current number of
+     * read-locks held.
+     *
+     * @return a string identifying this lock, as well as its lock state
+     */
+    public String toString() {
+        long s = state;
+        return super.toString() +
+            ((s & ABITS) == 0L ? "[Unlocked]" :
+             (s & WBIT) != 0L ? "[Write-locked]" :
+             "[Read-locks:" + getReadLockCount(s) + "]");
+    }
+
+    // views
+
+    /**
+     * Returns a plain {@link Lock} view of this StampedLock in which
+     * the {@link Lock#lock} method is mapped to {@link #readLock},
+     * and similarly for other methods. The returned Lock does not
+     * support a {@link Condition}; method {@link
+     * Lock#newCondition()} throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @return the lock
+     */
+    public Lock asReadLock() {
+        ReadLockView v;
+        return ((v = readLockView) != null ? v :
+                (readLockView = new ReadLockView()));
+    }
+
+    /**
+     * Returns a plain {@link Lock} view of this StampedLock in which
+     * the {@link Lock#lock} method is mapped to {@link #writeLock},
+     * and similarly for other methods. The returned Lock does not
+     * support a {@link Condition}; method {@link
+     * Lock#newCondition()} throws {@code
+     * UnsupportedOperationException}.
+     *
+     * @return the lock
+     */
+    public Lock asWriteLock() {
+        WriteLockView v;
+        return ((v = writeLockView) != null ? v :
+                (writeLockView = new WriteLockView()));
+    }
+
+    /**
+     * Returns a {@link ReadWriteLock} view of this StampedLock in
+     * which the {@link ReadWriteLock#readLock()} method is mapped to
+     * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to
+     * {@link #asWriteLock()}.
+     *
+     * @return the lock
+     */
+    public ReadWriteLock asReadWriteLock() {
+        ReadWriteLockView v;
+        return ((v = readWriteLockView) != null ? v :
+                (readWriteLockView = new ReadWriteLockView()));
+    }
+
+    // view classes
+
+    final class ReadLockView implements Lock {
+        public void lock() { readLock(); }
+        public void lockInterruptibly() throws InterruptedException {
+            readLockInterruptibly();
+        }
+        public boolean tryLock() { return tryReadLock() != 0L; }
+        public boolean tryLock(long time, TimeUnit unit)
+            throws InterruptedException {
+            return tryReadLock(time, unit) != 0L;
+        }
+        public void unlock() { unstampedUnlockRead(); }
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    final class WriteLockView implements Lock {
+        public void lock() { writeLock(); }
+        public void lockInterruptibly() throws InterruptedException {
+            writeLockInterruptibly();
+        }
+        public boolean tryLock() { return tryWriteLock() != 0L; }
+        public boolean tryLock(long time, TimeUnit unit)
+            throws InterruptedException {
+            return tryWriteLock(time, unit) != 0L;
+        }
+        public void unlock() { unstampedUnlockWrite(); }
+        public Condition newCondition() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    final class ReadWriteLockView implements ReadWriteLock {
+        public Lock readLock() { return asReadLock(); }
+        public Lock writeLock() { return asWriteLock(); }
+    }
+
+    // Unlock methods without stamp argument checks for view classes.
+    // Needed because view-class lock methods throw away stamps.
+
+    final void unstampedUnlockWrite() {
+        WNode h; long s;
+        if (((s = state) & WBIT) == 0L)
+            throw new IllegalMonitorStateException();
+        U.putLongVolatile(this, STATE, (s += WBIT) == 0L ? ORIGIN : s);
+        if ((h = whead) != null && h.status != 0)
+            release(h);
+    }
+
+    final void unstampedUnlockRead() {
+        for (;;) {
+            long s, m; WNode h;
+            if ((m = (s = state) & ABITS) == 0L || m >= WBIT)
+                throw new IllegalMonitorStateException();
+            else if (m < RFULL) {
+                if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) {
+                    if (m == RUNIT && (h = whead) != null && h.status != 0)
+                        release(h);
+                    break;
+                }
+            }
+            else if (tryDecReaderOverflow(s) != 0L)
+                break;
+        }
+    }
+
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+        s.defaultReadObject();
+        U.putLongVolatile(this, STATE, ORIGIN); // reset to unlocked state
+    }
+
+    // internals
+
+    /**
+     * Tries to increment readerOverflow by first setting state
+     * access bits value to RBITS, indicating hold of spinlock,
+     * then updating, then releasing.
+     *
+     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
+     * @return new stamp on success, else zero
+     */
+    private long tryIncReaderOverflow(long s) {
+        // assert (s & ABITS) >= RFULL;
+        if ((s & ABITS) == RFULL) {
+            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
+                ++readerOverflow;
+                U.putLongVolatile(this, STATE, s);
+                return s;
+            }
+        }
+        else if ((LockSupport.nextSecondarySeed() &
+                  OVERFLOW_YIELD_RATE) == 0)
+            Thread.yield();
+        return 0L;
+    }
+
+    /**
+     * Tries to decrement readerOverflow.
+     *
+     * @param s a reader overflow stamp: (s & ABITS) >= RFULL
+     * @return new stamp on success, else zero
+     */
+    private long tryDecReaderOverflow(long s) {
+        // assert (s & ABITS) >= RFULL;
+        if ((s & ABITS) == RFULL) {
+            if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) {
+                int r; long next;
+                if ((r = readerOverflow) > 0) {
+                    readerOverflow = r - 1;
+                    next = s;
+                }
+                else
+                    next = s - RUNIT;
+                U.putLongVolatile(this, STATE, next);
+                return next;
+            }
+        }
+        else if ((LockSupport.nextSecondarySeed() &
+                  OVERFLOW_YIELD_RATE) == 0)
+            Thread.yield();
+        return 0L;
+    }
+
+    /**
+     * Wakes up the successor of h (normally whead). This is normally
+     * just h.next, but may require traversal from wtail if next
+     * pointers are lagging. This may fail to wake up an acquiring
+     * thread when one or more have been cancelled, but the cancel
+     * methods themselves provide extra safeguards to ensure liveness.
+     */
+    private void release(WNode h) {
+        if (h != null) {
+            WNode q; Thread w;
+            U.compareAndSwapInt(h, WSTATUS, WAITING, 0);
+            if ((q = h.next) == null || q.status == CANCELLED) {
+                for (WNode t = wtail; t != null && t != h; t = t.prev)
+                    if (t.status <= 0)
+                        q = t;
+            }
+            if (q != null && (w = q.thread) != null)
+                U.unpark(w);
+        }
+    }
+
+    /**
+     * See above for explanation.
+     *
+     * @param interruptible true if should check interrupts and if so
+     * return INTERRUPTED
+     * @param deadline if nonzero, the System.nanoTime value to timeout
+     * at (and return zero)
+     * @return next state, or INTERRUPTED
+     */
+    private long acquireWrite(boolean interruptible, long deadline) {
+        WNode node = null, p;
+        for (int spins = -1;;) { // spin while enqueuing
+            long m, s, ns;
+            if ((m = (s = state) & ABITS) == 0L) {
+                if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT))
+                    return ns;
+            }
+            else if (spins < 0)
+                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
+            else if (spins > 0) {
+                if (LockSupport.nextSecondarySeed() >= 0)
+                    --spins;
+            }
+            else if ((p = wtail) == null) { // initialize queue
+                WNode hd = new WNode(WMODE, null);
+                if (U.compareAndSwapObject(this, WHEAD, null, hd))
+                    wtail = hd;
+            }
+            else if (node == null)
+                node = new WNode(WMODE, p);
+            else if (node.prev != p)
+                node.prev = p;
+            else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+                p.next = node;
+                break;
+            }
+        }
+
+        boolean wasInterrupted = false;
+        for (int spins = -1;;) {
+            WNode h, np, pp; int ps;
+            if ((h = whead) == p) {
+                if (spins < 0)
+                    spins = HEAD_SPINS;
+                else if (spins < MAX_HEAD_SPINS)
+                    spins <<= 1;
+                for (int k = spins;;) { // spin at head
+                    long s, ns;
+                    if (((s = state) & ABITS) == 0L) {
+                        if (U.compareAndSwapLong(this, STATE, s,
+                                                 ns = s + WBIT)) {
+                            whead = node;
+                            node.prev = null;
+                            if (wasInterrupted)
+                                Thread.currentThread().interrupt();
+                            return ns;
+                        }
+                    }
+                    else if (LockSupport.nextSecondarySeed() >= 0 &&
+                             --k <= 0)
+                        break;
+                }
+            }
+            else if (h != null) { // help release stale waiters
+                WNode c; Thread w;
+                while ((c = h.cowait) != null) {
+                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        (w = c.thread) != null)
+                        U.unpark(w);
+                }
+            }
+            if (whead == h) {
+                if ((np = node.prev) != p) {
+                    if (np != null)
+                        (p = np).next = node;   // stale
+                }
+                else if ((ps = p.status) == 0)
+                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
+                else if (ps == CANCELLED) {
+                    if ((pp = p.prev) != null) {
+                        node.prev = pp;
+                        pp.next = node;
+                    }
+                }
+                else {
+                    long time; // 0 argument to park means no timeout
+                    if (deadline == 0L)
+                        time = 0L;
+                    else if ((time = deadline - System.nanoTime()) <= 0L)
+                        return cancelWaiter(node, node, false);
+                    Thread wt = Thread.currentThread();
+                    U.putObject(wt, PARKBLOCKER, this);
+                    node.thread = wt;
+                    if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
+                        whead == h && node.prev == p)
+                        U.park(false, time);  // emulate LockSupport.park
+                    node.thread = null;
+                    U.putObject(wt, PARKBLOCKER, null);
+                    if (Thread.interrupted()) {
+                        if (interruptible)
+                            return cancelWaiter(node, node, true);
+                        wasInterrupted = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * See above for explanation.
+     *
+     * @param interruptible true if should check interrupts and if so
+     * return INTERRUPTED
+     * @param deadline if nonzero, the System.nanoTime value to timeout
+     * at (and return zero)
+     * @return next state, or INTERRUPTED
+     */
+    private long acquireRead(boolean interruptible, long deadline) {
+        boolean wasInterrupted = false;
+        WNode node = null, p;
+        for (int spins = -1;;) {
+            WNode h;
+            if ((h = whead) == (p = wtail)) {
+                for (long m, s, ns;;) {
+                    if ((m = (s = state) & ABITS) < RFULL ?
+                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
+                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
+                        if (wasInterrupted)
+                            Thread.currentThread().interrupt();
+                        return ns;
+                    }
+                    else if (m >= WBIT) {
+                        if (spins > 0) {
+                            if (LockSupport.nextSecondarySeed() >= 0)
+                                --spins;
+                        }
+                        else {
+                            if (spins == 0) {
+                                WNode nh = whead, np = wtail;
+                                if ((nh == h && np == p) || (h = nh) != (p = np))
+                                    break;
+                            }
+                            spins = SPINS;
+                        }
+                    }
+                }
+            }
+            if (p == null) { // initialize queue
+                WNode hd = new WNode(WMODE, null);
+                if (U.compareAndSwapObject(this, WHEAD, null, hd))
+                    wtail = hd;
+            }
+            else if (node == null)
+                node = new WNode(RMODE, p);
+            else if (h == p || p.mode != RMODE) {
+                if (node.prev != p)
+                    node.prev = p;
+                else if (U.compareAndSwapObject(this, WTAIL, p, node)) {
+                    p.next = node;
+                    break;
+                }
+            }
+            else if (!U.compareAndSwapObject(p, WCOWAIT,
+                                             node.cowait = p.cowait, node))
+                node.cowait = null;
+            else {
+                for (;;) {
+                    WNode pp, c; Thread w;
+                    if ((h = whead) != null && (c = h.cowait) != null &&
+                        U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        (w = c.thread) != null) // help release
+                        U.unpark(w);
+                    if (h == (pp = p.prev) || h == p || pp == null) {
+                        long m, s, ns;
+                        do {
+                            if ((m = (s = state) & ABITS) < RFULL ?
+                                U.compareAndSwapLong(this, STATE, s,
+                                                     ns = s + RUNIT) :
+                                (m < WBIT &&
+                                 (ns = tryIncReaderOverflow(s)) != 0L)) {
+                                if (wasInterrupted)
+                                    Thread.currentThread().interrupt();
+                                return ns;
+                            }
+                        } while (m < WBIT);
+                    }
+                    if (whead == h && p.prev == pp) {
+                        long time;
+                        if (pp == null || h == p || p.status > 0) {
+                            node = null; // throw away
+                            break;
+                        }
+                        if (deadline == 0L)
+                            time = 0L;
+                        else if ((time = deadline - System.nanoTime()) <= 0L) {
+                            if (wasInterrupted)
+                                Thread.currentThread().interrupt();
+                            return cancelWaiter(node, p, false);
+                        }
+                        Thread wt = Thread.currentThread();
+                        U.putObject(wt, PARKBLOCKER, this);
+                        node.thread = wt;
+                        if ((h != pp || (state & ABITS) == WBIT) &&
+                            whead == h && p.prev == pp)
+                            U.park(false, time);
+                        node.thread = null;
+                        U.putObject(wt, PARKBLOCKER, null);
+                        if (Thread.interrupted()) {
+                            if (interruptible)
+                                return cancelWaiter(node, p, true);
+                            wasInterrupted = true;
+                        }
+                    }
+                }
+            }
+        }
+
+        for (int spins = -1;;) {
+            WNode h, np, pp; int ps;
+            if ((h = whead) == p) {
+                if (spins < 0)
+                    spins = HEAD_SPINS;
+                else if (spins < MAX_HEAD_SPINS)
+                    spins <<= 1;
+                for (int k = spins;;) { // spin at head
+                    long m, s, ns;
+                    if ((m = (s = state) & ABITS) < RFULL ?
+                        U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) :
+                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
+                        WNode c; Thread w;
+                        whead = node;
+                        node.prev = null;
+                        while ((c = node.cowait) != null) {
+                            if (U.compareAndSwapObject(node, WCOWAIT,
+                                                       c, c.cowait) &&
+                                (w = c.thread) != null)
+                                U.unpark(w);
+                        }
+                        if (wasInterrupted)
+                            Thread.currentThread().interrupt();
+                        return ns;
+                    }
+                    else if (m >= WBIT &&
+                             LockSupport.nextSecondarySeed() >= 0 && --k <= 0)
+                        break;
+                }
+            }
+            else if (h != null) {
+                WNode c; Thread w;
+                while ((c = h.cowait) != null) {
+                    if (U.compareAndSwapObject(h, WCOWAIT, c, c.cowait) &&
+                        (w = c.thread) != null)
+                        U.unpark(w);
+                }
+            }
+            if (whead == h) {
+                if ((np = node.prev) != p) {
+                    if (np != null)
+                        (p = np).next = node;   // stale
+                }
+                else if ((ps = p.status) == 0)
+                    U.compareAndSwapInt(p, WSTATUS, 0, WAITING);
+                else if (ps == CANCELLED) {
+                    if ((pp = p.prev) != null) {
+                        node.prev = pp;
+                        pp.next = node;
+                    }
+                }
+                else {
+                    long time;
+                    if (deadline == 0L)
+                        time = 0L;
+                    else if ((time = deadline - System.nanoTime()) <= 0L)
+                        return cancelWaiter(node, node, false);
+                    Thread wt = Thread.currentThread();
+                    U.putObject(wt, PARKBLOCKER, this);
+                    node.thread = wt;
+                    if (p.status < 0 &&
+                        (p != h || (state & ABITS) == WBIT) &&
+                        whead == h && node.prev == p)
+                        U.park(false, time);
+                    node.thread = null;
+                    U.putObject(wt, PARKBLOCKER, null);
+                    if (Thread.interrupted()) {
+                        if (interruptible)
+                            return cancelWaiter(node, node, true);
+                        wasInterrupted = true;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * If node non-null, forces cancel status and unsplices it from
+     * queue if possible and wakes up any cowaiters (of the node, or
+     * group, as applicable), and in any case helps release current
+     * first waiter if lock is free. (Calling with null arguments
+     * serves as a conditional form of release, which is not currently
+     * needed but may be needed under possible future cancellation
+     * policies). This is a variant of cancellation methods in
+     * AbstractQueuedSynchronizer (see its detailed explanation in AQS
+     * internal documentation).
+     *
+     * @param node if nonnull, the waiter
+     * @param group either node or the group node is cowaiting with
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
+        if (node != null && group != null) {
+            Thread w;
+            node.status = CANCELLED;
+            // unsplice cancelled nodes from group
+            for (WNode p = group, q; (q = p.cowait) != null;) {
+                if (q.status == CANCELLED) {
+                    U.compareAndSwapObject(p, WCOWAIT, q, q.cowait);
+                    p = group; // restart
+                }
+                else
+                    p = q;
+            }
+            if (group == node) {
+                for (WNode r = group.cowait; r != null; r = r.cowait) {
+                    if ((w = r.thread) != null)
+                        U.unpark(w);       // wake up uncancelled co-waiters
+                }
+                for (WNode pred = node.prev; pred != null; ) { // unsplice
+                    WNode succ, pp;        // find valid successor
+                    while ((succ = node.next) == null ||
+                           succ.status == CANCELLED) {
+                        WNode q = null;    // find successor the slow way
+                        for (WNode t = wtail; t != null && t != node; t = t.prev)
+                            if (t.status != CANCELLED)
+                                q = t;     // don't link if succ cancelled
+                        if (succ == q ||   // ensure accurate successor
+                            U.compareAndSwapObject(node, WNEXT,
+                                                   succ, succ = q)) {
+                            if (succ == null && node == wtail)
+                                U.compareAndSwapObject(this, WTAIL, node, pred);
+                            break;
+                        }
+                    }
+                    if (pred.next == node) // unsplice pred link
+                        U.compareAndSwapObject(pred, WNEXT, node, succ);
+                    if (succ != null && (w = succ.thread) != null) {
+                        succ.thread = null;
+                        U.unpark(w);       // wake up succ to observe new pred
+                    }
+                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
+                        break;
+                    node.prev = pp;        // repeat if new pred wrong/cancelled
+                    U.compareAndSwapObject(pp, WNEXT, pred, succ);
+                    pred = pp;
+                }
+            }
+        }
+        WNode h; // Possibly release first waiter
+        while ((h = whead) != null) {
+            long s; WNode q; // similar to release() but check eligibility
+            if ((q = h.next) == null || q.status == CANCELLED) {
+                for (WNode t = wtail; t != null && t != h; t = t.prev)
+                    if (t.status <= 0)
+                        q = t;
+            }
+            if (h == whead) {
+                if (q != null && h.status == 0 &&
+                    ((s = state) & ABITS) != WBIT && // waiter is eligible
+                    (s == 0L || q.mode == RMODE))
+                    release(h);
+                break;
+            }
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    // Unsafe mechanics
+    private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
+    private static final long STATE;
+    private static final long WHEAD;
+    private static final long WTAIL;
+    private static final long WNEXT;
+    private static final long WSTATUS;
+    private static final long WCOWAIT;
+    private static final long PARKBLOCKER;
+
+    static {
+        try {
+            STATE = U.objectFieldOffset
+                (StampedLock.class.getDeclaredField("state"));
+            WHEAD = U.objectFieldOffset
+                (StampedLock.class.getDeclaredField("whead"));
+            WTAIL = U.objectFieldOffset
+                (StampedLock.class.getDeclaredField("wtail"));
+
+            WSTATUS = U.objectFieldOffset
+                (WNode.class.getDeclaredField("status"));
+            WNEXT = U.objectFieldOffset
+                (WNode.class.getDeclaredField("next"));
+            WCOWAIT = U.objectFieldOffset
+                (WNode.class.getDeclaredField("cowait"));
+
+            PARKBLOCKER = U.objectFieldOffset
+                (Thread.class.getDeclaredField("parkBlocker"));
+        } catch (ReflectiveOperationException e) {
+            throw new Error(e);
+        }
+    }
+}
diff --git a/java/util/concurrent/locks/package-info.java b/java/util/concurrent/locks/package-info.java
new file mode 100644
index 0000000..97dfcc9
--- /dev/null
+++ b/java/util/concurrent/locks/package-info.java
@@ -0,0 +1,79 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Interfaces and classes providing a framework for locking and waiting
+ * for conditions that is distinct from built-in synchronization and
+ * monitors.  The framework permits much greater flexibility in the use of
+ * locks and conditions, at the expense of more awkward syntax.
+ *
+ * <p>The {@link java.util.concurrent.locks.Lock} interface supports
+ * locking disciplines that differ in semantics (reentrant, fair, etc),
+ * and that can be used in non-block-structured contexts including
+ * hand-over-hand and lock reordering algorithms.  The main implementation
+ * is {@link java.util.concurrent.locks.ReentrantLock}.
+ *
+ * <p>The {@link java.util.concurrent.locks.ReadWriteLock} interface
+ * similarly defines locks that may be shared among readers but are
+ * exclusive to writers.  Only a single implementation, {@link
+ * java.util.concurrent.locks.ReentrantReadWriteLock}, is provided, since
+ * it covers most standard usage contexts.  But programmers may create
+ * their own implementations to cover nonstandard requirements.
+ *
+ * <p>The {@link java.util.concurrent.locks.Condition} interface
+ * describes condition variables that may be associated with Locks.
+ * These are similar in usage to the implicit monitors accessed using
+ * {@code Object.wait}, but offer extended capabilities.
+ * In particular, multiple {@code Condition} objects may be associated
+ * with a single {@code Lock}.  To avoid compatibility issues, the
+ * names of {@code Condition} methods are different from the
+ * corresponding {@code Object} versions.
+ *
+ * <p>The {@link java.util.concurrent.locks.AbstractQueuedSynchronizer}
+ * class serves as a useful superclass for defining locks and other
+ * synchronizers that rely on queuing blocked threads.  The {@link
+ * java.util.concurrent.locks.AbstractQueuedLongSynchronizer} class
+ * provides the same functionality but extends support to 64 bits of
+ * synchronization state.  Both extend class {@link
+ * java.util.concurrent.locks.AbstractOwnableSynchronizer}, a simple
+ * class that helps record the thread currently holding exclusive
+ * synchronization.  The {@link java.util.concurrent.locks.LockSupport}
+ * class provides lower-level blocking and unblocking support that is
+ * useful for those developers implementing their own customized lock
+ * classes.
+ *
+ * @since 1.5
+ */
+package java.util.concurrent.locks;
diff --git a/java/util/concurrent/package-info.java b/java/util/concurrent/package-info.java
new file mode 100644
index 0000000..387068d
--- /dev/null
+++ b/java/util/concurrent/package-info.java
@@ -0,0 +1,308 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Utility classes commonly useful in concurrent programming.  This
+ * package includes a few small standardized extensible frameworks, as
+ * well as some classes that provide useful functionality and are
+ * otherwise tedious or difficult to implement.  Here are brief
+ * descriptions of the main components.  See also the
+ * {@link java.util.concurrent.locks} and
+ * {@link java.util.concurrent.atomic} packages.
+ *
+ * <h2>Executors</h2>
+ *
+ * <b>Interfaces.</b>
+ *
+ * {@link java.util.concurrent.Executor} is a simple standardized
+ * interface for defining custom thread-like subsystems, including
+ * thread pools, asynchronous I/O, and lightweight task frameworks.
+ * Depending on which concrete Executor class is being used, tasks may
+ * execute in a newly created thread, an existing task-execution thread,
+ * or the thread calling {@link java.util.concurrent.Executor#execute
+ * execute}, and may execute sequentially or concurrently.
+ *
+ * {@link java.util.concurrent.ExecutorService} provides a more
+ * complete asynchronous task execution framework.  An
+ * ExecutorService manages queuing and scheduling of tasks,
+ * and allows controlled shutdown.
+ *
+ * The {@link java.util.concurrent.ScheduledExecutorService}
+ * subinterface and associated interfaces add support for
+ * delayed and periodic task execution.  ExecutorServices
+ * provide methods arranging asynchronous execution of any
+ * function expressed as {@link java.util.concurrent.Callable},
+ * the result-bearing analog of {@link java.lang.Runnable}.
+ *
+ * A {@link java.util.concurrent.Future} returns the results of
+ * a function, allows determination of whether execution has
+ * completed, and provides a means to cancel execution.
+ *
+ * A {@link java.util.concurrent.RunnableFuture} is a {@code Future}
+ * that possesses a {@code run} method that upon execution,
+ * sets its results.
+ *
+ * <p>
+ *
+ * <b>Implementations.</b>
+ *
+ * Classes {@link java.util.concurrent.ThreadPoolExecutor} and
+ * {@link java.util.concurrent.ScheduledThreadPoolExecutor}
+ * provide tunable, flexible thread pools.
+ *
+ * The {@link java.util.concurrent.Executors} class provides
+ * factory methods for the most common kinds and configurations
+ * of Executors, as well as a few utility methods for using
+ * them.  Other utilities based on {@code Executors} include the
+ * concrete class {@link java.util.concurrent.FutureTask}
+ * providing a common extensible implementation of Futures, and
+ * {@link java.util.concurrent.ExecutorCompletionService}, that
+ * assists in coordinating the processing of groups of
+ * asynchronous tasks.
+ *
+ * <p>Class {@link java.util.concurrent.ForkJoinPool} provides an
+ * Executor primarily designed for processing instances of {@link
+ * java.util.concurrent.ForkJoinTask} and its subclasses.  These
+ * classes employ a work-stealing scheduler that attains high
+ * throughput for tasks conforming to restrictions that often hold in
+ * computation-intensive parallel processing.
+ *
+ * <h2>Queues</h2>
+ *
+ * The {@link java.util.concurrent.ConcurrentLinkedQueue} class
+ * supplies an efficient scalable thread-safe non-blocking FIFO queue.
+ * The {@link java.util.concurrent.ConcurrentLinkedDeque} class is
+ * similar, but additionally supports the {@link java.util.Deque}
+ * interface.
+ *
+ * <p>Five implementations in {@code java.util.concurrent} support
+ * the extended {@link java.util.concurrent.BlockingQueue}
+ * interface, that defines blocking versions of put and take:
+ * {@link java.util.concurrent.LinkedBlockingQueue},
+ * {@link java.util.concurrent.ArrayBlockingQueue},
+ * {@link java.util.concurrent.SynchronousQueue},
+ * {@link java.util.concurrent.PriorityBlockingQueue}, and
+ * {@link java.util.concurrent.DelayQueue}.
+ * The different classes cover the most common usage contexts
+ * for producer-consumer, messaging, parallel tasking, and
+ * related concurrent designs.
+ *
+ * <p>Extended interface {@link java.util.concurrent.TransferQueue},
+ * and implementation {@link java.util.concurrent.LinkedTransferQueue}
+ * introduce a synchronous {@code transfer} method (along with related
+ * features) in which a producer may optionally block awaiting its
+ * consumer.
+ *
+ * <p>The {@link java.util.concurrent.BlockingDeque} interface
+ * extends {@code BlockingQueue} to support both FIFO and LIFO
+ * (stack-based) operations.
+ * Class {@link java.util.concurrent.LinkedBlockingDeque}
+ * provides an implementation.
+ *
+ * <h2>Timing</h2>
+ *
+ * The {@link java.util.concurrent.TimeUnit} class provides
+ * multiple granularities (including nanoseconds) for
+ * specifying and controlling time-out based operations.  Most
+ * classes in the package contain operations based on time-outs
+ * in addition to indefinite waits.  In all cases that
+ * time-outs are used, the time-out specifies the minimum time
+ * that the method should wait before indicating that it
+ * timed-out.  Implementations make a &quot;best effort&quot;
+ * to detect time-outs as soon as possible after they occur.
+ * However, an indefinite amount of time may elapse between a
+ * time-out being detected and a thread actually executing
+ * again after that time-out.  All methods that accept timeout
+ * parameters treat values less than or equal to zero to mean
+ * not to wait at all.  To wait "forever", you can use a value
+ * of {@code Long.MAX_VALUE}.
+ *
+ * <h2>Synchronizers</h2>
+ *
+ * Five classes aid common special-purpose synchronization idioms.
+ * <ul>
+ *
+ * <li>{@link java.util.concurrent.Semaphore} is a classic concurrency tool.
+ *
+ * <li>{@link java.util.concurrent.CountDownLatch} is a very simple yet
+ * very common utility for blocking until a given number of signals,
+ * events, or conditions hold.
+ *
+ * <li>A {@link java.util.concurrent.CyclicBarrier} is a resettable
+ * multiway synchronization point useful in some styles of parallel
+ * programming.
+ *
+ * <li>A {@link java.util.concurrent.Phaser} provides
+ * a more flexible form of barrier that may be used to control phased
+ * computation among multiple threads.
+ *
+ * <li>An {@link java.util.concurrent.Exchanger} allows two threads to
+ * exchange objects at a rendezvous point, and is useful in several
+ * pipeline designs.
+ *
+ * </ul>
+ *
+ * <h2>Concurrent Collections</h2>
+ *
+ * Besides Queues, this package supplies Collection implementations
+ * designed for use in multithreaded contexts:
+ * {@link java.util.concurrent.ConcurrentHashMap},
+ * {@link java.util.concurrent.ConcurrentSkipListMap},
+ * {@link java.util.concurrent.ConcurrentSkipListSet},
+ * {@link java.util.concurrent.CopyOnWriteArrayList}, and
+ * {@link java.util.concurrent.CopyOnWriteArraySet}.
+ * When many threads are expected to access a given collection, a
+ * {@code ConcurrentHashMap} is normally preferable to a synchronized
+ * {@code HashMap}, and a {@code ConcurrentSkipListMap} is normally
+ * preferable to a synchronized {@code TreeMap}.
+ * A {@code CopyOnWriteArrayList} is preferable to a synchronized
+ * {@code ArrayList} when the expected number of reads and traversals
+ * greatly outnumber the number of updates to a list.
+ *
+ * <p>The "Concurrent" prefix used with some classes in this package
+ * is a shorthand indicating several differences from similar
+ * "synchronized" classes.  For example {@code java.util.Hashtable} and
+ * {@code Collections.synchronizedMap(new HashMap())} are
+ * synchronized.  But {@link
+ * java.util.concurrent.ConcurrentHashMap} is "concurrent".  A
+ * concurrent collection is thread-safe, but not governed by a
+ * single exclusion lock.  In the particular case of
+ * ConcurrentHashMap, it safely permits any number of
+ * concurrent reads as well as a tunable number of concurrent
+ * writes.  "Synchronized" classes can be useful when you need
+ * to prevent all access to a collection via a single lock, at
+ * the expense of poorer scalability.  In other cases in which
+ * multiple threads are expected to access a common collection,
+ * "concurrent" versions are normally preferable.  And
+ * unsynchronized collections are preferable when either
+ * collections are unshared, or are accessible only when
+ * holding other locks.
+ *
+ * <p id="Weakly">Most concurrent Collection implementations
+ * (including most Queues) also differ from the usual {@code java.util}
+ * conventions in that their {@linkplain java.util.Iterator Iterators}
+ * and {@linkplain java.util.Spliterator Spliterators} provide
+ * <em>weakly consistent</em> rather than fast-fail traversal:
+ * <ul>
+ * <li>they may proceed concurrently with other operations
+ * <li>they will never throw {@link java.util.ConcurrentModificationException
+ * ConcurrentModificationException}
+ * <li>they are guaranteed to traverse elements as they existed upon
+ * construction exactly once, and may (but are not guaranteed to)
+ * reflect any modifications subsequent to construction.
+ * </ul>
+ *
+ * <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
+ *
+ * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5">
+ * Chapter 17 of
+ * <cite>The Java&trade; Language Specification</cite></a> defines the
+ * <i>happens-before</i> relation on memory operations such as reads and
+ * writes of shared variables.  The results of a write by one thread are
+ * guaranteed to be visible to a read by another thread only if the write
+ * operation <i>happens-before</i> the read operation.  The
+ * {@code synchronized} and {@code volatile} constructs, as well as the
+ * {@code Thread.start()} and {@code Thread.join()} methods, can form
+ * <i>happens-before</i> relationships.  In particular:
+ *
+ * <ul>
+ *   <li>Each action in a thread <i>happens-before</i> every action in that
+ *   thread that comes later in the program's order.
+ *
+ *   <li>An unlock ({@code synchronized} block or method exit) of a
+ *   monitor <i>happens-before</i> every subsequent lock ({@code synchronized}
+ *   block or method entry) of that same monitor.  And because
+ *   the <i>happens-before</i> relation is transitive, all actions
+ *   of a thread prior to unlocking <i>happen-before</i> all actions
+ *   subsequent to any thread locking that monitor.
+ *
+ *   <li>A write to a {@code volatile} field <i>happens-before</i> every
+ *   subsequent read of that same field.  Writes and reads of
+ *   {@code volatile} fields have similar memory consistency effects
+ *   as entering and exiting monitors, but do <em>not</em> entail
+ *   mutual exclusion locking.
+ *
+ *   <li>A call to {@code start} on a thread <i>happens-before</i> any
+ *   action in the started thread.
+ *
+ *   <li>All actions in a thread <i>happen-before</i> any other thread
+ *   successfully returns from a {@code join} on that thread.
+ *
+ * </ul>
+ *
+ *
+ * The methods of all classes in {@code java.util.concurrent} and its
+ * subpackages extend these guarantees to higher-level
+ * synchronization.  In particular:
+ *
+ * <ul>
+ *
+ *   <li>Actions in a thread prior to placing an object into any concurrent
+ *   collection <i>happen-before</i> actions subsequent to the access or
+ *   removal of that element from the collection in another thread.
+ *
+ *   <li>Actions in a thread prior to the submission of a {@code Runnable}
+ *   to an {@code Executor} <i>happen-before</i> its execution begins.
+ *   Similarly for {@code Callables} submitted to an {@code ExecutorService}.
+ *
+ *   <li>Actions taken by the asynchronous computation represented by a
+ *   {@code Future} <i>happen-before</i> actions subsequent to the
+ *   retrieval of the result via {@code Future.get()} in another thread.
+ *
+ *   <li>Actions prior to "releasing" synchronizer methods such as
+ *   {@code Lock.unlock}, {@code Semaphore.release}, and
+ *   {@code CountDownLatch.countDown} <i>happen-before</i> actions
+ *   subsequent to a successful "acquiring" method such as
+ *   {@code Lock.lock}, {@code Semaphore.acquire},
+ *   {@code Condition.await}, and {@code CountDownLatch.await} on the
+ *   same synchronizer object in another thread.
+ *
+ *   <li>For each pair of threads that successfully exchange objects via
+ *   an {@code Exchanger}, actions prior to the {@code exchange()}
+ *   in each thread <i>happen-before</i> those subsequent to the
+ *   corresponding {@code exchange()} in another thread.
+ *
+ *   <li>Actions prior to calling {@code CyclicBarrier.await} and
+ *   {@code Phaser.awaitAdvance} (as well as its variants)
+ *   <i>happen-before</i> actions performed by the barrier action, and
+ *   actions performed by the barrier action <i>happen-before</i> actions
+ *   subsequent to a successful return from the corresponding {@code await}
+ *   in other threads.
+ *
+ * </ul>
+ *
+ * @since 1.5
+ */
+package java.util.concurrent;
diff --git a/java/util/function/BiConsumer.java b/java/util/function/BiConsumer.java
new file mode 100644
index 0000000..61690e6
--- /dev/null
+++ b/java/util/function/BiConsumer.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts two input arguments and returns no
+ * result.  This is the two-arity specialization of {@link Consumer}.
+ * Unlike most other functional interfaces, {@code BiConsumer} is expected
+ * to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the operation
+ * @param <U> the type of the second argument to the operation
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiConsumer<T, U> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param u the second input argument
+     */
+    void accept(T t, U u);
+
+    /**
+     * Returns a composed {@code BiConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code BiConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> after) {
+        Objects.requireNonNull(after);
+
+        return (l, r) -> {
+            accept(l, r);
+            after.accept(l, r);
+        };
+    }
+}
diff --git a/java/util/function/BiFunction.java b/java/util/function/BiFunction.java
new file mode 100644
index 0000000..ef75901
--- /dev/null
+++ b/java/util/function/BiFunction.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a function that accepts two arguments and produces a result.
+ * This is the two-arity specialization of {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiFunction<T, U, R> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    R apply(T t, U u);
+
+    /**
+     * Returns a composed function that first applies this function to
+     * its input, and then applies the {@code after} function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of output of the {@code after} function, and of the
+     *           composed function
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then
+     * applies the {@code after} function
+     * @throws NullPointerException if after is null
+     */
+    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t, U u) -> after.apply(apply(t, u));
+    }
+}
diff --git a/java/util/function/BiPredicate.java b/java/util/function/BiPredicate.java
new file mode 100644
index 0000000..a0f19b8
--- /dev/null
+++ b/java/util/function/BiPredicate.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of two arguments.  This is
+ * the two-arity specialization of {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the predicate
+ * @param <U> the type of the second argument the predicate
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BiPredicate<T, U> {
+
+    /**
+     * Evaluates this predicate on the given arguments.
+     *
+     * @param t the first input argument
+     * @param u the second input argument
+     * @return {@code true} if the input arguments match the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(T t, U u);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default BiPredicate<T, U> and(BiPredicate<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+        return (T t, U u) -> test(t, u) && other.test(t, u);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default BiPredicate<T, U> negate() {
+        return (T t, U u) -> !test(t, u);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default BiPredicate<T, U> or(BiPredicate<? super T, ? super U> other) {
+        Objects.requireNonNull(other);
+        return (T t, U u) -> test(t, u) || other.test(t, u);
+    }
+}
diff --git a/java/util/function/BinaryOperator.java b/java/util/function/BinaryOperator.java
new file mode 100644
index 0000000..a015058
--- /dev/null
+++ b/java/util/function/BinaryOperator.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+import java.util.Comparator;
+
+/**
+ * Represents an operation upon two operands of the same type, producing a result
+ * of the same type as the operands.  This is a specialization of
+ * {@link BiFunction} for the case where the operands and the result are all of
+ * the same type.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the operands and result of the operator
+ *
+ * @see BiFunction
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BinaryOperator<T> extends BiFunction<T,T,T> {
+    /**
+     * Returns a {@link BinaryOperator} which returns the lesser of two elements
+     * according to the specified {@code Comparator}.
+     *
+     * @param <T> the type of the input arguments of the comparator
+     * @param comparator a {@code Comparator} for comparing the two values
+     * @return a {@code BinaryOperator} which returns the lesser of its operands,
+     *         according to the supplied {@code Comparator}
+     * @throws NullPointerException if the argument is null
+     */
+    public static <T> BinaryOperator<T> minBy(Comparator<? super T> comparator) {
+        Objects.requireNonNull(comparator);
+        return (a, b) -> comparator.compare(a, b) <= 0 ? a : b;
+    }
+
+    /**
+     * Returns a {@link BinaryOperator} which returns the greater of two elements
+     * according to the specified {@code Comparator}.
+     *
+     * @param <T> the type of the input arguments of the comparator
+     * @param comparator a {@code Comparator} for comparing the two values
+     * @return a {@code BinaryOperator} which returns the greater of its operands,
+     *         according to the supplied {@code Comparator}
+     * @throws NullPointerException if the argument is null
+     */
+    public static <T> BinaryOperator<T> maxBy(Comparator<? super T> comparator) {
+        Objects.requireNonNull(comparator);
+        return (a, b) -> comparator.compare(a, b) >= 0 ? a : b;
+    }
+}
diff --git a/java/util/function/BooleanSupplier.java b/java/util/function/BooleanSupplier.java
new file mode 100644
index 0000000..2faff30
--- /dev/null
+++ b/java/util/function/BooleanSupplier.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+
+/**
+ * Represents a supplier of {@code boolean}-valued results.  This is the
+ * {@code boolean}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsBoolean()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface BooleanSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    boolean getAsBoolean();
+}
diff --git a/java/util/function/Consumer.java b/java/util/function/Consumer.java
new file mode 100644
index 0000000..a2481fe
--- /dev/null
+++ b/java/util/function/Consumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single input argument and returns no
+ * result. Unlike most other functional interfaces, {@code Consumer} is expected
+ * to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object)}.
+ *
+ * @param <T> the type of the input to the operation
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Consumer<T> {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param t the input argument
+     */
+    void accept(T t);
+
+    /**
+     * Returns a composed {@code Consumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code Consumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default Consumer<T> andThen(Consumer<? super T> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/DoubleBinaryOperator.java b/java/util/function/DoubleBinaryOperator.java
new file mode 100644
index 0000000..839433d
--- /dev/null
+++ b/java/util/function/DoubleBinaryOperator.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code double}-valued operands and producing a
+ * {@code double}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code double}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(double, double)}.
+ *
+ * @see BinaryOperator
+ * @see DoubleUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleBinaryOperator {
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    double applyAsDouble(double left, double right);
+}
diff --git a/java/util/function/DoubleConsumer.java b/java/util/function/DoubleConsumer.java
new file mode 100644
index 0000000..046360c
--- /dev/null
+++ b/java/util/function/DoubleConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code double}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code double}.  Unlike most other functional interfaces,
+ * {@code DoubleConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(double)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(double value);
+
+    /**
+     * Returns a composed {@code DoubleConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code DoubleConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default DoubleConsumer andThen(DoubleConsumer after) {
+        Objects.requireNonNull(after);
+        return (double t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/DoubleFunction.java b/java/util/function/DoubleFunction.java
new file mode 100644
index 0000000..a8bb57d
--- /dev/null
+++ b/java/util/function/DoubleFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces a
+ * result.  This is the {@code double}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(double)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(double value);
+}
diff --git a/java/util/function/DoublePredicate.java b/java/util/function/DoublePredicate.java
new file mode 100644
index 0000000..1df1762
--- /dev/null
+++ b/java/util/function/DoublePredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code double}-valued
+ * argument. This is the {@code double}-consuming primitive type specialization
+ * of {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(double)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoublePredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(double value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default DoublePredicate and(DoublePredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default DoublePredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default DoublePredicate or(DoublePredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/java/util/function/DoubleSupplier.java b/java/util/function/DoubleSupplier.java
new file mode 100644
index 0000000..5169011
--- /dev/null
+++ b/java/util/function/DoubleSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code double}-valued results.  This is the
+ * {@code double}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsDouble()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    double getAsDouble();
+}
diff --git a/java/util/function/DoubleToIntFunction.java b/java/util/function/DoubleToIntFunction.java
new file mode 100644
index 0000000..a23f033
--- /dev/null
+++ b/java/util/function/DoubleToIntFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces an
+ * int-valued result.  This is the {@code double}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(double)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleToIntFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(double value);
+}
diff --git a/java/util/function/DoubleToLongFunction.java b/java/util/function/DoubleToLongFunction.java
new file mode 100644
index 0000000..436369c
--- /dev/null
+++ b/java/util/function/DoubleToLongFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a double-valued argument and produces a
+ * long-valued result.  This is the {@code double}-to-{@code long} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(double)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleToLongFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(double value);
+}
diff --git a/java/util/function/DoubleUnaryOperator.java b/java/util/function/DoubleUnaryOperator.java
new file mode 100644
index 0000000..2f134c9
--- /dev/null
+++ b/java/util/function/DoubleUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code double}-valued operand that produces
+ * a {@code double}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code double}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(double)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface DoubleUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    double applyAsDouble(double operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(DoubleUnaryOperator)
+     */
+    default DoubleUnaryOperator compose(DoubleUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (double v) -> applyAsDouble(before.applyAsDouble(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(DoubleUnaryOperator)
+     */
+    default DoubleUnaryOperator andThen(DoubleUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (double t) -> after.applyAsDouble(applyAsDouble(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static DoubleUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/Function.java b/java/util/function/Function.java
new file mode 100644
index 0000000..7bcbfd0
--- /dev/null
+++ b/java/util/function/Function.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a function that accepts one argument and produces a result.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ * @param <R> the type of the result of the function
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Function<T, R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param t the function argument
+     * @return the function result
+     */
+    R apply(T t);
+
+    /**
+     * Returns a composed function that first applies the {@code before}
+     * function to its input, and then applies this function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of input to the {@code before} function, and to the
+     *           composed function
+     * @param before the function to apply before this function is applied
+     * @return a composed function that first applies the {@code before}
+     * function and then applies this function
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(Function)
+     */
+    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> apply(before.apply(v));
+    }
+
+    /**
+     * Returns a composed function that first applies this function to
+     * its input, and then applies the {@code after} function to the result.
+     * If evaluation of either function throws an exception, it is relayed to
+     * the caller of the composed function.
+     *
+     * @param <V> the type of output of the {@code after} function, and of the
+     *           composed function
+     * @param after the function to apply after this function is applied
+     * @return a composed function that first applies this function and then
+     * applies the {@code after} function
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(Function)
+     */
+    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
+        Objects.requireNonNull(after);
+        return (T t) -> after.apply(apply(t));
+    }
+
+    /**
+     * Returns a function that always returns its input argument.
+     *
+     * @param <T> the type of the input and output objects to the function
+     * @return a function that always returns its input argument
+     */
+    static <T> Function<T, T> identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/IntBinaryOperator.java b/java/util/function/IntBinaryOperator.java
new file mode 100644
index 0000000..21bb946
--- /dev/null
+++ b/java/util/function/IntBinaryOperator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code int}-valued operands and producing an
+ * {@code int}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code int}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(int, int)}.
+ *
+ * @see BinaryOperator
+ * @see IntUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntBinaryOperator {
+
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    int applyAsInt(int left, int right);
+}
diff --git a/java/util/function/IntConsumer.java b/java/util/function/IntConsumer.java
new file mode 100644
index 0000000..d8daf73
--- /dev/null
+++ b/java/util/function/IntConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code int}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code int}.  Unlike most other functional interfaces,
+ * {@code IntConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(int)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(int value);
+
+    /**
+     * Returns a composed {@code IntConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code IntConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default IntConsumer andThen(IntConsumer after) {
+        Objects.requireNonNull(after);
+        return (int t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/IntFunction.java b/java/util/function/IntFunction.java
new file mode 100644
index 0000000..de10df4
--- /dev/null
+++ b/java/util/function/IntFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * result.  This is the {@code int}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(int)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(int value);
+}
diff --git a/java/util/function/IntPredicate.java b/java/util/function/IntPredicate.java
new file mode 100644
index 0000000..5a9bd46
--- /dev/null
+++ b/java/util/function/IntPredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code int}-valued
+ * argument. This is the {@code int}-consuming primitive type specialization of
+ * {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(int)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntPredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(int value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default IntPredicate and(IntPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default IntPredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default IntPredicate or(IntPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/java/util/function/IntSupplier.java b/java/util/function/IntSupplier.java
new file mode 100644
index 0000000..89489c5
--- /dev/null
+++ b/java/util/function/IntSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code int}-valued results.  This is the
+ * {@code int}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsInt()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    int getAsInt();
+}
diff --git a/java/util/function/IntToDoubleFunction.java b/java/util/function/IntToDoubleFunction.java
new file mode 100644
index 0000000..5012154
--- /dev/null
+++ b/java/util/function/IntToDoubleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * double-valued result.  This is the {@code int}-to-{@code double} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(int)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntToDoubleFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(int value);
+}
diff --git a/java/util/function/IntToLongFunction.java b/java/util/function/IntToLongFunction.java
new file mode 100644
index 0000000..6c52faa
--- /dev/null
+++ b/java/util/function/IntToLongFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts an int-valued argument and produces a
+ * long-valued result.  This is the {@code int}-to-{@code long} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(int)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntToLongFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(int value);
+}
diff --git a/java/util/function/IntUnaryOperator.java b/java/util/function/IntUnaryOperator.java
new file mode 100644
index 0000000..300fc14
--- /dev/null
+++ b/java/util/function/IntUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code int}-valued operand that produces
+ * an {@code int}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code int}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(int)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface IntUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    int applyAsInt(int operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(IntUnaryOperator)
+     */
+    default IntUnaryOperator compose(IntUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (int v) -> applyAsInt(before.applyAsInt(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(IntUnaryOperator)
+     */
+    default IntUnaryOperator andThen(IntUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (int t) -> after.applyAsInt(applyAsInt(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static IntUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/LongBinaryOperator.java b/java/util/function/LongBinaryOperator.java
new file mode 100644
index 0000000..287481e
--- /dev/null
+++ b/java/util/function/LongBinaryOperator.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation upon two {@code long}-valued operands and producing a
+ * {@code long}-valued result.   This is the primitive type specialization of
+ * {@link BinaryOperator} for {@code long}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(long, long)}.
+ *
+ * @see BinaryOperator
+ * @see LongUnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongBinaryOperator {
+
+    /**
+     * Applies this operator to the given operands.
+     *
+     * @param left the first operand
+     * @param right the second operand
+     * @return the operator result
+     */
+    long applyAsLong(long left, long right);
+}
diff --git a/java/util/function/LongConsumer.java b/java/util/function/LongConsumer.java
new file mode 100644
index 0000000..b59d030
--- /dev/null
+++ b/java/util/function/LongConsumer.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation that accepts a single {@code long}-valued argument and
+ * returns no result.  This is the primitive type specialization of
+ * {@link Consumer} for {@code long}.  Unlike most other functional interfaces,
+ * {@code LongConsumer} is expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(long)}.
+ *
+ * @see Consumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongConsumer {
+
+    /**
+     * Performs this operation on the given argument.
+     *
+     * @param value the input argument
+     */
+    void accept(long value);
+
+    /**
+     * Returns a composed {@code LongConsumer} that performs, in sequence, this
+     * operation followed by the {@code after} operation. If performing either
+     * operation throws an exception, it is relayed to the caller of the
+     * composed operation.  If performing this operation throws an exception,
+     * the {@code after} operation will not be performed.
+     *
+     * @param after the operation to perform after this operation
+     * @return a composed {@code LongConsumer} that performs in sequence this
+     * operation followed by the {@code after} operation
+     * @throws NullPointerException if {@code after} is null
+     */
+    default LongConsumer andThen(LongConsumer after) {
+        Objects.requireNonNull(after);
+        return (long t) -> { accept(t); after.accept(t); };
+    }
+}
diff --git a/java/util/function/LongFunction.java b/java/util/function/LongFunction.java
new file mode 100644
index 0000000..2030c04
--- /dev/null
+++ b/java/util/function/LongFunction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces a
+ * result.  This is the {@code long}-consuming primitive specialization for
+ * {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(long)}.
+ *
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongFunction<R> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    R apply(long value);
+}
diff --git a/java/util/function/LongPredicate.java b/java/util/function/LongPredicate.java
new file mode 100644
index 0000000..5afdd41
--- /dev/null
+++ b/java/util/function/LongPredicate.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one {@code long}-valued
+ * argument. This is the {@code long}-consuming primitive type specialization of
+ * {@link Predicate}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(long)}.
+ *
+ * @see Predicate
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongPredicate {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param value the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(long value);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default LongPredicate and(LongPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) && other.test(value);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default LongPredicate negate() {
+        return (value) -> !test(value);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default LongPredicate or(LongPredicate other) {
+        Objects.requireNonNull(other);
+        return (value) -> test(value) || other.test(value);
+    }
+}
diff --git a/java/util/function/LongSupplier.java b/java/util/function/LongSupplier.java
new file mode 100644
index 0000000..513d906
--- /dev/null
+++ b/java/util/function/LongSupplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of {@code long}-valued results.  This is the
+ * {@code long}-producing primitive specialization of {@link Supplier}.
+ *
+ * <p>There is no requirement that a distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #getAsLong()}.
+ *
+ * @see Supplier
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongSupplier {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    long getAsLong();
+}
diff --git a/java/util/function/LongToDoubleFunction.java b/java/util/function/LongToDoubleFunction.java
new file mode 100644
index 0000000..9d0831f
--- /dev/null
+++ b/java/util/function/LongToDoubleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces a
+ * double-valued result.  This is the {@code long}-to-{@code double} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(long)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongToDoubleFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(long value);
+}
diff --git a/java/util/function/LongToIntFunction.java b/java/util/function/LongToIntFunction.java
new file mode 100644
index 0000000..d1d6c34
--- /dev/null
+++ b/java/util/function/LongToIntFunction.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts a long-valued argument and produces an
+ * int-valued result.  This is the {@code long}-to-{@code int} primitive
+ * specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(long)}.
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongToIntFunction {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(long value);
+}
diff --git a/java/util/function/LongUnaryOperator.java b/java/util/function/LongUnaryOperator.java
new file mode 100644
index 0000000..e2bbddd
--- /dev/null
+++ b/java/util/function/LongUnaryOperator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents an operation on a single {@code long}-valued operand that produces
+ * a {@code long}-valued result.  This is the primitive type specialization of
+ * {@link UnaryOperator} for {@code long}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(long)}.
+ *
+ * @see UnaryOperator
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface LongUnaryOperator {
+
+    /**
+     * Applies this operator to the given operand.
+     *
+     * @param operand the operand
+     * @return the operator result
+     */
+    long applyAsLong(long operand);
+
+    /**
+     * Returns a composed operator that first applies the {@code before}
+     * operator to its input, and then applies this operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param before the operator to apply before this operator is applied
+     * @return a composed operator that first applies the {@code before}
+     * operator and then applies this operator
+     * @throws NullPointerException if before is null
+     *
+     * @see #andThen(LongUnaryOperator)
+     */
+    default LongUnaryOperator compose(LongUnaryOperator before) {
+        Objects.requireNonNull(before);
+        return (long v) -> applyAsLong(before.applyAsLong(v));
+    }
+
+    /**
+     * Returns a composed operator that first applies this operator to
+     * its input, and then applies the {@code after} operator to the result.
+     * If evaluation of either operator throws an exception, it is relayed to
+     * the caller of the composed operator.
+     *
+     * @param after the operator to apply after this operator is applied
+     * @return a composed operator that first applies this operator and then
+     * applies the {@code after} operator
+     * @throws NullPointerException if after is null
+     *
+     * @see #compose(LongUnaryOperator)
+     */
+    default LongUnaryOperator andThen(LongUnaryOperator after) {
+        Objects.requireNonNull(after);
+        return (long t) -> after.applyAsLong(applyAsLong(t));
+    }
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @return a unary operator that always returns its input argument
+     */
+    static LongUnaryOperator identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/ObjDoubleConsumer.java b/java/util/function/ObjDoubleConsumer.java
new file mode 100644
index 0000000..d551fc7
--- /dev/null
+++ b/java/util/function/ObjDoubleConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code double}-valued argument, and returns no result.  This is the
+ * {@code (reference, double)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjDoubleConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, double)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjDoubleConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, double value);
+}
diff --git a/java/util/function/ObjIntConsumer.java b/java/util/function/ObjIntConsumer.java
new file mode 100644
index 0000000..2eb32d6
--- /dev/null
+++ b/java/util/function/ObjIntConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code int}-valued argument, and returns no result.  This is the
+ * {@code (reference, int)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjIntConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, int)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjIntConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, int value);
+}
diff --git a/java/util/function/ObjLongConsumer.java b/java/util/function/ObjLongConsumer.java
new file mode 100644
index 0000000..f40eea2
--- /dev/null
+++ b/java/util/function/ObjLongConsumer.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation that accepts an object-valued and a
+ * {@code long}-valued argument, and returns no result.  This is the
+ * {@code (reference, long)} specialization of {@link BiConsumer}.
+ * Unlike most other functional interfaces, {@code ObjLongConsumer} is
+ * expected to operate via side-effects.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #accept(Object, long)}.
+ *
+ * @param <T> the type of the object argument to the operation
+ *
+ * @see BiConsumer
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ObjLongConsumer<T> {
+
+    /**
+     * Performs this operation on the given arguments.
+     *
+     * @param t the first input argument
+     * @param value the second input argument
+     */
+    void accept(T t, long value);
+}
diff --git a/java/util/function/Predicate.java b/java/util/function/Predicate.java
new file mode 100644
index 0000000..e2f448b
--- /dev/null
+++ b/java/util/function/Predicate.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+import java.util.Objects;
+
+/**
+ * Represents a predicate (boolean-valued function) of one argument.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #test(Object)}.
+ *
+ * @param <T> the type of the input to the predicate
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Predicate<T> {
+
+    /**
+     * Evaluates this predicate on the given argument.
+     *
+     * @param t the input argument
+     * @return {@code true} if the input argument matches the predicate,
+     * otherwise {@code false}
+     */
+    boolean test(T t);
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * AND of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code false}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ANDed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * AND of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default Predicate<T> and(Predicate<? super T> other) {
+        Objects.requireNonNull(other);
+        return (t) -> test(t) && other.test(t);
+    }
+
+    /**
+     * Returns a predicate that represents the logical negation of this
+     * predicate.
+     *
+     * @return a predicate that represents the logical negation of this
+     * predicate
+     */
+    default Predicate<T> negate() {
+        return (t) -> !test(t);
+    }
+
+    /**
+     * Returns a composed predicate that represents a short-circuiting logical
+     * OR of this predicate and another.  When evaluating the composed
+     * predicate, if this predicate is {@code true}, then the {@code other}
+     * predicate is not evaluated.
+     *
+     * <p>Any exceptions thrown during evaluation of either predicate are relayed
+     * to the caller; if evaluation of this predicate throws an exception, the
+     * {@code other} predicate will not be evaluated.
+     *
+     * @param other a predicate that will be logically-ORed with this
+     *              predicate
+     * @return a composed predicate that represents the short-circuiting logical
+     * OR of this predicate and the {@code other} predicate
+     * @throws NullPointerException if other is null
+     */
+    default Predicate<T> or(Predicate<? super T> other) {
+        Objects.requireNonNull(other);
+        return (t) -> test(t) || other.test(t);
+    }
+
+    /**
+     * Returns a predicate that tests if two arguments are equal according
+     * to {@link Objects#equals(Object, Object)}.
+     *
+     * @param <T> the type of arguments to the predicate
+     * @param targetRef the object reference with which to compare for equality,
+     *               which may be {@code null}
+     * @return a predicate that tests if two arguments are equal according
+     * to {@link Objects#equals(Object, Object)}
+     */
+    static <T> Predicate<T> isEqual(Object targetRef) {
+        return (null == targetRef)
+                ? Objects::isNull
+                : object -> targetRef.equals(object);
+    }
+}
diff --git a/java/util/function/Supplier.java b/java/util/function/Supplier.java
new file mode 100644
index 0000000..b87777e
--- /dev/null
+++ b/java/util/function/Supplier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a supplier of results.
+ *
+ * <p>There is no requirement that a new or distinct result be returned each
+ * time the supplier is invoked.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #get()}.
+ *
+ * @param <T> the type of results supplied by this supplier
+ *
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface Supplier<T> {
+
+    /**
+     * Gets a result.
+     *
+     * @return a result
+     */
+    T get();
+}
diff --git a/java/util/function/ToDoubleBiFunction.java b/java/util/function/ToDoubleBiFunction.java
new file mode 100644
index 0000000..d0efcee
--- /dev/null
+++ b/java/util/function/ToDoubleBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces a double-valued
+ * result.  This is the {@code double}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToDoubleBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    double applyAsDouble(T t, U u);
+}
diff --git a/java/util/function/ToDoubleFunction.java b/java/util/function/ToDoubleFunction.java
new file mode 100644
index 0000000..29bf988
--- /dev/null
+++ b/java/util/function/ToDoubleFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces a double-valued result.  This is the
+ * {@code double}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsDouble(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToDoubleFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    double applyAsDouble(T value);
+}
diff --git a/java/util/function/ToIntBiFunction.java b/java/util/function/ToIntBiFunction.java
new file mode 100644
index 0000000..0e28d26
--- /dev/null
+++ b/java/util/function/ToIntBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces an int-valued
+ * result.  This is the {@code int}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToIntBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    int applyAsInt(T t, U u);
+}
diff --git a/java/util/function/ToIntFunction.java b/java/util/function/ToIntFunction.java
new file mode 100644
index 0000000..5768242
--- /dev/null
+++ b/java/util/function/ToIntFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces an int-valued result.  This is the
+ * {@code int}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsInt(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToIntFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    int applyAsInt(T value);
+}
diff --git a/java/util/function/ToLongBiFunction.java b/java/util/function/ToLongBiFunction.java
new file mode 100644
index 0000000..8b5ed7e
--- /dev/null
+++ b/java/util/function/ToLongBiFunction.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that accepts two arguments and produces a long-valued
+ * result.  This is the {@code long}-producing primitive specialization for
+ * {@link BiFunction}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ *
+ * @see BiFunction
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToLongBiFunction<T, U> {
+
+    /**
+     * Applies this function to the given arguments.
+     *
+     * @param t the first function argument
+     * @param u the second function argument
+     * @return the function result
+     */
+    long applyAsLong(T t, U u);
+}
diff --git a/java/util/function/ToLongFunction.java b/java/util/function/ToLongFunction.java
new file mode 100644
index 0000000..eefb617
--- /dev/null
+++ b/java/util/function/ToLongFunction.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents a function that produces a long-valued result.  This is the
+ * {@code long}-producing primitive specialization for {@link Function}.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #applyAsLong(Object)}.
+ *
+ * @param <T> the type of the input to the function
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface ToLongFunction<T> {
+
+    /**
+     * Applies this function to the given argument.
+     *
+     * @param value the function argument
+     * @return the function result
+     */
+    long applyAsLong(T value);
+}
diff --git a/java/util/function/UnaryOperator.java b/java/util/function/UnaryOperator.java
new file mode 100644
index 0000000..c4aa749
--- /dev/null
+++ b/java/util/function/UnaryOperator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.function;
+
+/**
+ * Represents an operation on a single operand that produces a result of the
+ * same type as its operand.  This is a specialization of {@code Function} for
+ * the case where the operand and result are of the same type.
+ *
+ * <p>This is a <a href="package-summary.html">functional interface</a>
+ * whose functional method is {@link #apply(Object)}.
+ *
+ * @param <T> the type of the operand and result of the operator
+ *
+ * @see Function
+ * @since 1.8
+ */
+@FunctionalInterface
+public interface UnaryOperator<T> extends Function<T, T> {
+
+    /**
+     * Returns a unary operator that always returns its input argument.
+     *
+     * @param <T> the type of the input and output of the operator
+     * @return a unary operator that always returns its input argument
+     */
+    static <T> UnaryOperator<T> identity() {
+        return t -> t;
+    }
+}
diff --git a/java/util/function/package-info.java b/java/util/function/package-info.java
new file mode 100644
index 0000000..31a1c46
--- /dev/null
+++ b/java/util/function/package-info.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * <em>Functional interfaces</em> provide target types for lambda expressions
+ * and method references.  Each functional interface has a single abstract
+ * method, called the <em>functional method</em> for that functional interface,
+ * to which the lambda expression's parameter and return types are matched or
+ * adapted.  Functional interfaces can provide a target type in multiple
+ * contexts, such as assignment context, method invocation, or cast context:
+ *
+ * <pre>{@code
+ *     // Assignment context
+ *     Predicate<String> p = String::isEmpty;
+ *
+ *     // Method invocation context
+ *     stream.filter(e -> e.getSize() > 10)...
+ *
+ *     // Cast context
+ *     stream.map((ToIntFunction) e -> e.getSize())...
+ * }</pre>
+ *
+ * <p>The interfaces in this package are general purpose functional interfaces
+ * used by the JDK, and are available to be used by user code as well.  While
+ * they do not identify a complete set of function shapes to which lambda
+ * expressions might be adapted, they provide enough to cover common
+ * requirements. Other functional interfaces provided for specific purposes,
+ * such as {@link java.io.FileFilter}, are defined in the packages where they
+ * are used.
+ *
+ * <p>The interfaces in this package are annotated with
+ * {@link java.lang.FunctionalInterface}. This annotation is not a requirement
+ * for the compiler to recognize an interface as a functional interface, but
+ * merely an aid to capture design intent and enlist the help of the compiler in
+ * identifying accidental violations of design intent.
+ *
+ * <p>Functional interfaces often represent abstract concepts like functions,
+ * actions, or predicates.  In documenting functional interfaces, or referring
+ * to variables typed as functional interfaces, it is common to refer directly
+ * to those abstract concepts, for example using "this function" instead of
+ * "the function represented by this object".  When an API method is said to
+ * accept or return a functional interface in this manner, such as "applies the
+ * provided function to...", this is understood to mean a <i>non-null</i>
+ * reference to an object implementing the appropriate functional interface,
+ * unless potential nullity is explicitly specified.
+ *
+ * <p>The functional interfaces in this package follow an extensible naming
+ * convention, as follows:
+ *
+ * <ul>
+ *     <li>There are several basic function shapes, including
+ *     {@link java.util.function.Function} (unary function from {@code T} to {@code R}),
+ *     {@link java.util.function.Consumer} (unary function from {@code T} to {@code void}),
+ *     {@link java.util.function.Predicate} (unary function from {@code T} to {@code boolean}),
+ *     and {@link java.util.function.Supplier} (nilary function to {@code R}).
+ *     </li>
+ *
+ *     <li>Function shapes have a natural arity based on how they are most
+ *     commonly used.  The basic shapes can be modified by an arity prefix to
+ *     indicate a different arity, such as
+ *     {@link java.util.function.BiFunction} (binary function from {@code T} and
+ *     {@code U} to {@code R}).
+ *     </li>
+ *
+ *     <li>There are additional derived function shapes which extend the basic
+ *     function shapes, including {@link java.util.function.UnaryOperator}
+ *     (extends {@code Function}) and {@link java.util.function.BinaryOperator}
+ *     (extends {@code BiFunction}).
+ *     </li>
+ *
+ *     <li>Type parameters of functional interfaces can be specialized to
+ *     primitives with additional type prefixes.  To specialize the return type
+ *     for a type that has both generic return type and generic arguments, we
+ *     prefix {@code ToXxx}, as in {@link java.util.function.ToIntFunction}.
+ *     Otherwise, type arguments are specialized left-to-right, as in
+ *     {@link java.util.function.DoubleConsumer}
+ *     or {@link java.util.function.ObjIntConsumer}.
+ *     (The type prefix {@code Obj} is used to indicate that we don't want to
+ *     specialize this parameter, but want to move on to the next parameter,
+ *     as in {@link java.util.function.ObjIntConsumer}.)
+ *     These schemes can be combined, as in {@code IntToDoubleFunction}.
+ *     </li>
+ *
+ *     <li>If there are specialization prefixes for all arguments, the arity
+ *     prefix may be left out (as in {@link java.util.function.ObjIntConsumer}).
+ *     </li>
+ * </ul>
+ *
+ * @see java.lang.FunctionalInterface
+ * @since 1.8
+ */
+package java.util.function;
diff --git a/java/util/jar/Attributes.java b/java/util/jar/Attributes.java
new file mode 100644
index 0000000..795b809
--- /dev/null
+++ b/java/util/jar/Attributes.java
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.AbstractSet;
+import java.util.Iterator;
+import sun.util.logging.PlatformLogger;
+import java.util.Comparator;
+import sun.misc.ASCIICaseInsensitiveComparator;
+
+/**
+ * The Attributes class maps Manifest attribute names to associated string
+ * values. Valid attribute names are case-insensitive, are restricted to
+ * the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70
+ * characters in length. Attribute values can contain any characters and
+ * will be UTF8-encoded when written to the output stream.  See the
+ * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
+ * for more information about valid attribute names and values.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @since   1.2
+ */
+public class Attributes implements Map<Object,Object>, Cloneable {
+    /**
+     * The attribute name-value mappings.
+     */
+    protected Map<Object,Object> map;
+
+    /**
+     * Constructs a new, empty Attributes object with default size.
+     */
+    public Attributes() {
+        this(11);
+    }
+
+    /**
+     * Constructs a new, empty Attributes object with the specified
+     * initial size.
+     *
+     * @param size the initial number of attributes
+     */
+    public Attributes(int size) {
+        map = new HashMap<>(size);
+    }
+
+    /**
+     * Constructs a new Attributes object with the same attribute name-value
+     * mappings as in the specified Attributes.
+     *
+     * @param attr the specified Attributes
+     */
+    public Attributes(Attributes attr) {
+        map = new HashMap<>(attr);
+    }
+
+
+    /**
+     * Returns the value of the specified attribute name, or null if the
+     * attribute name was not found.
+     *
+     * @param name the attribute name
+     * @return the value of the specified attribute name, or null if
+     *         not found.
+     */
+    public Object get(Object name) {
+        return map.get(name);
+    }
+
+    /**
+     * Returns the value of the specified attribute name, specified as
+     * a string, or null if the attribute was not found. The attribute
+     * name is case-insensitive.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *      return (String)get(new Attributes.Name((String)name));
+     * </pre>
+     *
+     * @param name the attribute name as a string
+     * @return the String value of the specified attribute name, or null if
+     *         not found.
+     * @throws IllegalArgumentException if the attribute name is invalid
+     */
+    public String getValue(String name) {
+        return (String)get(new Attributes.Name(name));
+    }
+
+    /**
+     * Returns the value of the specified Attributes.Name, or null if the
+     * attribute was not found.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *     return (String)get(name);
+     * </pre>
+     *
+     * @param name the Attributes.Name object
+     * @return the String value of the specified Attribute.Name, or null if
+     *         not found.
+     */
+    public String getValue(Name name) {
+        return (String)get(name);
+    }
+
+    /**
+     * Associates the specified value with the specified attribute name
+     * (key) in this Map. If the Map previously contained a mapping for
+     * the attribute name, the old value is replaced.
+     *
+     * @param name the attribute name
+     * @param value the attribute value
+     * @return the previous value of the attribute, or null if none
+     * @exception ClassCastException if the name is not a Attributes.Name
+     *            or the value is not a String
+     */
+    public Object put(Object name, Object value) {
+        return map.put((Attributes.Name)name, (String)value);
+    }
+
+    /**
+     * Associates the specified value with the specified attribute name,
+     * specified as a String. The attributes name is case-insensitive.
+     * If the Map previously contained a mapping for the attribute name,
+     * the old value is replaced.
+     * <p>
+     * This method is defined as:
+     * <pre>
+     *      return (String)put(new Attributes.Name(name), value);
+     * </pre>
+     *
+     * @param name the attribute name as a string
+     * @param value the attribute value
+     * @return the previous value of the attribute, or null if none
+     * @exception IllegalArgumentException if the attribute name is invalid
+     */
+    public String putValue(String name, String value) {
+        return (String)put(new Name(name), value);
+    }
+
+    /**
+     * Removes the attribute with the specified name (key) from this Map.
+     * Returns the previous attribute value, or null if none.
+     *
+     * @param name attribute name
+     * @return the previous value of the attribute, or null if none
+     */
+    public Object remove(Object name) {
+        return map.remove(name);
+    }
+
+    /**
+     * Returns true if this Map maps one or more attribute names (keys)
+     * to the specified value.
+     *
+     * @param value the attribute value
+     * @return true if this Map maps one or more attribute names to
+     *         the specified value
+     */
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    /**
+     * Returns true if this Map contains the specified attribute name (key).
+     *
+     * @param name the attribute name
+     * @return true if this Map contains the specified attribute name
+     */
+    public boolean containsKey(Object name) {
+        return map.containsKey(name);
+    }
+
+    /**
+     * Copies all of the attribute name-value mappings from the specified
+     * Attributes to this Map. Duplicate mappings will be replaced.
+     *
+     * @param attr the Attributes to be stored in this map
+     * @exception ClassCastException if attr is not an Attributes
+     */
+    public void putAll(Map<?,?> attr) {
+        // ## javac bug?
+        if (!Attributes.class.isInstance(attr))
+            throw new ClassCastException();
+        for (Map.Entry<?,?> me : (attr).entrySet())
+            put(me.getKey(), me.getValue());
+    }
+
+    /**
+     * Removes all attributes from this Map.
+     */
+    public void clear() {
+        map.clear();
+    }
+
+    /**
+     * Returns the number of attributes in this Map.
+     */
+    public int size() {
+        return map.size();
+    }
+
+    /**
+     * Returns true if this Map contains no attributes.
+     */
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    /**
+     * Returns a Set view of the attribute names (keys) contained in this Map.
+     */
+    public Set<Object> keySet() {
+        return map.keySet();
+    }
+
+    /**
+     * Returns a Collection view of the attribute values contained in this Map.
+     */
+    public Collection<Object> values() {
+        return map.values();
+    }
+
+    /**
+     * Returns a Collection view of the attribute name-value mappings
+     * contained in this Map.
+     */
+    public Set<Map.Entry<Object,Object>> entrySet() {
+        return map.entrySet();
+    }
+
+    /**
+     * Compares the specified Attributes object with this Map for equality.
+     * Returns true if the given object is also an instance of Attributes
+     * and the two Attributes objects represent the same mappings.
+     *
+     * @param o the Object to be compared
+     * @return true if the specified Object is equal to this Map
+     */
+    public boolean equals(Object o) {
+        return map.equals(o);
+    }
+
+    /**
+     * Returns the hash code value for this Map.
+     */
+    public int hashCode() {
+        return map.hashCode();
+    }
+
+    /**
+     * Returns a copy of the Attributes, implemented as follows:
+     * <pre>
+     *     public Object clone() { return new Attributes(this); }
+     * </pre>
+     * Since the attribute names and values are themselves immutable,
+     * the Attributes returned can be safely modified without affecting
+     * the original.
+     */
+    public Object clone() {
+        return new Attributes(this);
+    }
+
+    /*
+     * Writes the current attributes to the specified data output stream.
+     * XXX Need to handle UTF8 values and break up lines longer than 72 bytes
+     */
+     void write(DataOutputStream os) throws IOException {
+        Iterator<Map.Entry<Object, Object>> it = entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Object, Object> e = it.next();
+            StringBuffer buffer = new StringBuffer(
+                                        ((Name)e.getKey()).toString());
+            buffer.append(": ");
+
+            String value = (String)e.getValue();
+            if (value != null) {
+                byte[] vb = value.getBytes("UTF8");
+                value = new String(vb, 0, 0, vb.length);
+            }
+            buffer.append(value);
+
+            buffer.append("\r\n");
+            Manifest.make72Safe(buffer);
+            os.writeBytes(buffer.toString());
+        }
+        os.writeBytes("\r\n");
+    }
+
+    /*
+     * Writes the current attributes to the specified data output stream,
+     * make sure to write out the MANIFEST_VERSION or SIGNATURE_VERSION
+     * attributes first.
+     *
+     * XXX Need to handle UTF8 values and break up lines longer than 72 bytes
+     */
+    void writeMain(DataOutputStream out) throws IOException
+    {
+        // write out the *-Version header first, if it exists
+        String vername = Name.MANIFEST_VERSION.toString();
+        String version = getValue(vername);
+        if (version == null) {
+            vername = Name.SIGNATURE_VERSION.toString();
+            version = getValue(vername);
+        }
+
+        if (version != null) {
+            out.writeBytes(vername+": "+version+"\r\n");
+        }
+
+        // write out all attributes except for the version
+        // we wrote out earlier
+        Iterator<Map.Entry<Object, Object>> it = entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Object, Object> e = it.next();
+            String name = ((Name)e.getKey()).toString();
+            if ((version != null) && ! (name.equalsIgnoreCase(vername))) {
+
+                StringBuffer buffer = new StringBuffer(name);
+                buffer.append(": ");
+
+                String value = (String)e.getValue();
+                if (value != null) {
+                    byte[] vb = value.getBytes("UTF8");
+                    value = new String(vb, 0, 0, vb.length);
+                }
+                buffer.append(value);
+
+                buffer.append("\r\n");
+                Manifest.make72Safe(buffer);
+                out.writeBytes(buffer.toString());
+            }
+        }
+        out.writeBytes("\r\n");
+    }
+
+    /*
+     * Reads attributes from the specified input stream.
+     * XXX Need to handle UTF8 values.
+     */
+    void read(Manifest.FastInputStream is, byte[] lbuf) throws IOException {
+        String name = null, value = null;
+        byte[] lastline = null;
+
+        int len;
+        while ((len = is.readLine(lbuf)) != -1) {
+            boolean lineContinued = false;
+            if (lbuf[--len] != '\n') {
+                throw new IOException("line too long");
+            }
+            if (len > 0 && lbuf[len-1] == '\r') {
+                --len;
+            }
+            if (len == 0) {
+                break;
+            }
+            int i = 0;
+            if (lbuf[0] == ' ') {
+                // continuation of previous line
+                if (name == null) {
+                    throw new IOException("misplaced continuation line");
+                }
+                lineContinued = true;
+                byte[] buf = new byte[lastline.length + len - 1];
+                System.arraycopy(lastline, 0, buf, 0, lastline.length);
+                System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
+                if (is.peek() == ' ') {
+                    lastline = buf;
+                    continue;
+                }
+                value = new String(buf, 0, buf.length, "UTF8");
+                lastline = null;
+            } else {
+                while (lbuf[i++] != ':') {
+                    if (i >= len) {
+                        throw new IOException("invalid header field");
+                    }
+                }
+                if (lbuf[i++] != ' ') {
+                    throw new IOException("invalid header field");
+                }
+                name = new String(lbuf, 0, 0, i - 2);
+                if (is.peek() == ' ') {
+                    lastline = new byte[len - i];
+                    System.arraycopy(lbuf, i, lastline, 0, len - i);
+                    continue;
+                }
+                value = new String(lbuf, i, len - i, "UTF8");
+            }
+            try {
+                if ((putValue(name, value) != null) && (!lineContinued)) {
+                    PlatformLogger.getLogger("java.util.jar").warning(
+                                     "Duplicate name in Manifest: " + name
+                                     + ".\n"
+                                     + "Ensure that the manifest does not "
+                                     + "have duplicate entries, and\n"
+                                     + "that blank lines separate "
+                                     + "individual sections in both your\n"
+                                     + "manifest and in the META-INF/MANIFEST.MF "
+                                     + "entry in the jar file.");
+                }
+            } catch (IllegalArgumentException e) {
+                throw new IOException("invalid header field name: " + name);
+            }
+        }
+    }
+
+    /**
+     * The Attributes.Name class represents an attribute name stored in
+     * this Map. Valid attribute names are case-insensitive, are restricted
+     * to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed
+     * 70 characters in length. Attribute values can contain any characters
+     * and will be UTF8-encoded when written to the output stream.  See the
+     * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
+     * for more information about valid attribute names and values.
+     */
+    public static class Name {
+        private String name;
+        private int hashCode = -1;
+
+        /**
+         * Constructs a new attribute name using the given string name.
+         *
+         * @param name the attribute string name
+         * @exception IllegalArgumentException if the attribute name was
+         *            invalid
+         * @exception NullPointerException if the attribute name was null
+         */
+        public Name(String name) {
+            if (name == null) {
+                throw new NullPointerException("name");
+            }
+            if (!isValid(name)) {
+                throw new IllegalArgumentException(name);
+            }
+            this.name = name.intern();
+        }
+
+        private static boolean isValid(String name) {
+            int len = name.length();
+            if (len > 70 || len == 0) {
+                return false;
+            }
+            for (int i = 0; i < len; i++) {
+                if (!isValid(name.charAt(i))) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static boolean isValid(char c) {
+            return isAlpha(c) || isDigit(c) || c == '_' || c == '-';
+        }
+
+        private static boolean isAlpha(char c) {
+            return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+        }
+
+        private static boolean isDigit(char c) {
+            return c >= '0' && c <= '9';
+        }
+
+        /**
+         * Compares this attribute name to another for equality.
+         * @param o the object to compare
+         * @return true if this attribute name is equal to the
+         *         specified attribute object
+         */
+        public boolean equals(Object o) {
+            if (o instanceof Name) {
+                Comparator<String> c = ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER;
+                return c.compare(name, ((Name)o).name) == 0;
+            } else {
+                return false;
+            }
+        }
+
+        /**
+         * Computes the hash value for this attribute name.
+         */
+        public int hashCode() {
+            if (hashCode == -1) {
+                hashCode = ASCIICaseInsensitiveComparator.lowerCaseHashCode(name);
+            }
+            return hashCode;
+        }
+
+        /**
+         * Returns the attribute name as a String.
+         */
+        public String toString() {
+            return name;
+        }
+
+        /**
+         * <code>Name</code> object for <code>Manifest-Version</code>
+         * manifest attribute. This attribute indicates the version number
+         * of the manifest standard to which a JAR file's manifest conforms.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#JAR_Manifest">
+         *      Manifest and Signature Specification</a>
+         */
+        public static final Name MANIFEST_VERSION = new Name("Manifest-Version");
+
+        /**
+         * <code>Name</code> object for <code>Signature-Version</code>
+         * manifest attribute used when signing JAR files.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#JAR_Manifest">
+         *      Manifest and Signature Specification</a>
+         */
+        public static final Name SIGNATURE_VERSION = new Name("Signature-Version");
+
+        /**
+         * <code>Name</code> object for <code>Content-Type</code>
+         * manifest attribute.
+         */
+        public static final Name CONTENT_TYPE = new Name("Content-Type");
+
+        /**
+         * <code>Name</code> object for <code>Class-Path</code>
+         * manifest attribute. Bundled extensions can use this attribute
+         * to find other JAR files containing needed classes.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#classpath">
+         *      JAR file specification</a>
+         */
+        public static final Name CLASS_PATH = new Name("Class-Path");
+
+        /**
+         * <code>Name</code> object for <code>Main-Class</code> manifest
+         * attribute used for launching applications packaged in JAR files.
+         * The <code>Main-Class</code> attribute is used in conjunction
+         * with the <code>-jar</code> command-line option of the
+         * <tt>java</tt> application launcher.
+         */
+        public static final Name MAIN_CLASS = new Name("Main-Class");
+
+        /**
+         * <code>Name</code> object for <code>Sealed</code> manifest attribute
+         * used for sealing.
+         * @see <a href="../../../../technotes/guides/jar/jar.html#sealing">
+         *      Package Sealing</a>
+         */
+        public static final Name SEALED = new Name("Sealed");
+
+       /**
+         * <code>Name</code> object for <code>Extension-List</code> manifest attribute
+         * used for declaring dependencies on installed extensions.
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+         *      Installed extension dependency</a>
+         */
+        public static final Name EXTENSION_LIST = new Name("Extension-List");
+
+        /**
+         * <code>Name</code> object for <code>Extension-Name</code> manifest attribute
+         * used for declaring dependencies on installed extensions.
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+         *      Installed extension dependency</a>
+         */
+        public static final Name EXTENSION_NAME = new Name("Extension-Name");
+
+        /**
+         * <code>Name</code> object for <code>Extension-Name</code> manifest attribute
+         * used for declaring dependencies on installed extensions.
+         * @deprecated Extension mechanism will be removed in a future release.
+         *             Use class path instead.
+         * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+         *      Installed extension dependency</a>
+         */
+        @Deprecated
+        public static final Name EXTENSION_INSTALLATION = new Name("Extension-Installation");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Title</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name IMPLEMENTATION_TITLE = new Name("Implementation-Title");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Version</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name IMPLEMENTATION_VERSION = new Name("Implementation-Version");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Vendor</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor");
+
+        /**
+         * <code>Name</code> object for <code>Implementation-Vendor-Id</code>
+         * manifest attribute used for package versioning.
+         * @deprecated Extension mechanism will be removed in a future release.
+         *             Use class path instead.
+         * @see <a href="../../../../technotes/guides/extensions/versioning.html#applet">
+         *      Optional Package Versioning</a>
+         */
+        @Deprecated
+        public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id");
+
+       /**
+         * <code>Name</code> object for <code>Implementation-URL</code>
+         * manifest attribute used for package versioning.
+         * @deprecated Extension mechanism will be removed in a future release.
+         *             Use class path instead.
+         * @see <a href="../../../../technotes/guides/extensions/versioning.html#applet">
+         *      Optional Package Versioning</a>
+         */
+        @Deprecated
+        public static final Name IMPLEMENTATION_URL = new Name("Implementation-URL");
+
+        /**
+         * <code>Name</code> object for <code>Specification-Title</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name SPECIFICATION_TITLE = new Name("Specification-Title");
+
+        /**
+         * <code>Name</code> object for <code>Specification-Version</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name SPECIFICATION_VERSION = new Name("Specification-Version");
+
+        /**
+         * <code>Name</code> object for <code>Specification-Vendor</code>
+         * manifest attribute used for package versioning.
+         * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+         *      Java Product Versioning Specification</a>
+         */
+        public static final Name SPECIFICATION_VENDOR = new Name("Specification-Vendor");
+    }
+}
diff --git a/java/util/jar/JarEntry.java b/java/util/jar/JarEntry.java
new file mode 100644
index 0000000..b0e6841
--- /dev/null
+++ b/java/util/jar/JarEntry.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+
+/**
+ * This class is used to represent a JAR file entry.
+ */
+public
+class JarEntry extends ZipEntry {
+    Attributes attr;
+    Certificate[] certs;
+    CodeSigner[] signers;
+
+    /**
+     * Creates a new <code>JarEntry</code> for the specified JAR file
+     * entry name.
+     *
+     * @param name the JAR file entry name
+     * @exception NullPointerException if the entry name is <code>null</code>
+     * @exception IllegalArgumentException if the entry name is longer than
+     *            0xFFFF bytes.
+     */
+    public JarEntry(String name) {
+        super(name);
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> with fields taken from the
+     * specified <code>ZipEntry</code> object.
+     * @param ze the <code>ZipEntry</code> object to create the
+     *           <code>JarEntry</code> from
+     */
+    public JarEntry(ZipEntry ze) {
+        super(ze);
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> with fields taken from the
+     * specified <code>JarEntry</code> object.
+     *
+     * @param je the <code>JarEntry</code> to copy
+     */
+    public JarEntry(JarEntry je) {
+        this((ZipEntry)je);
+        this.attr = je.attr;
+        this.certs = je.certs;
+        this.signers = je.signers;
+    }
+
+    /**
+     * Returns the <code>Manifest</code> <code>Attributes</code> for this
+     * entry, or <code>null</code> if none.
+     *
+     * @return the <code>Manifest</code> <code>Attributes</code> for this
+     * entry, or <code>null</code> if none
+     * @throws IOException  if an I/O error has occurred
+     */
+    public Attributes getAttributes() throws IOException {
+        return attr;
+    }
+
+    /**
+     * Returns the <code>Certificate</code> objects for this entry, or
+     * <code>null</code> if none. This method can only be called once
+     * the <code>JarEntry</code> has been completely verified by reading
+     * from the entry input stream until the end of the stream has been
+     * reached. Otherwise, this method will return <code>null</code>.
+     *
+     * <p>The returned certificate array comprises all the signer certificates
+     * that were used to verify this entry. Each signer certificate is
+     * followed by its supporting certificate chain (which may be empty).
+     * Each signer certificate and its supporting certificate chain are ordered
+     * bottom-to-top (i.e., with the signer certificate first and the (root)
+     * certificate authority last).
+     *
+     * @return the <code>Certificate</code> objects for this entry, or
+     * <code>null</code> if none.
+     */
+    public Certificate[] getCertificates() {
+        return certs == null ? null : certs.clone();
+    }
+
+    /**
+     * Returns the <code>CodeSigner</code> objects for this entry, or
+     * <code>null</code> if none. This method can only be called once
+     * the <code>JarEntry</code> has been completely verified by reading
+     * from the entry input stream until the end of the stream has been
+     * reached. Otherwise, this method will return <code>null</code>.
+     *
+     * <p>The returned array comprises all the code signers that have signed
+     * this entry.
+     *
+     * @return the <code>CodeSigner</code> objects for this entry, or
+     * <code>null</code> if none.
+     *
+     * @since 1.5
+     */
+    public CodeSigner[] getCodeSigners() {
+        return signers == null ? null : signers.clone();
+    }
+}
diff --git a/java/util/jar/JarException.java b/java/util/jar/JarException.java
new file mode 100644
index 0000000..b6e1ca2
--- /dev/null
+++ b/java/util/jar/JarException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+/**
+ * Signals that an error of some sort has occurred while reading from
+ * or writing to a JAR file.
+ *
+ * @author  David Connelly
+ * @since   1.2
+ */
+public
+class JarException extends java.util.zip.ZipException {
+    private static final long serialVersionUID = 7159778400963954473L;
+
+    /**
+     * Constructs a JarException with no detail message.
+     */
+    public JarException() {
+    }
+
+    /**
+     * Constructs a JarException with the specified detail message.
+     * @param s the detail message
+     */
+    public JarException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/jar/JarFile.java b/java/util/jar/JarFile.java
new file mode 100644
index 0000000..342e341
--- /dev/null
+++ b/java/util/jar/JarFile.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.*;
+import java.lang.ref.SoftReference;
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import java.util.zip.*;
+import java.security.CodeSigner;
+import java.security.cert.Certificate;
+import java.security.AccessController;
+import sun.misc.IOUtils;
+import sun.security.action.GetPropertyAction;
+import sun.security.util.ManifestEntryVerifier;
+import sun.security.util.SignatureFileVerifier;
+
+/**
+ * The <code>JarFile</code> class is used to read the contents of a jar file
+ * from any file that can be opened with <code>java.io.RandomAccessFile</code>.
+ * It extends the class <code>java.util.zip.ZipFile</code> with support
+ * for reading an optional <code>Manifest</code> entry. The
+ * <code>Manifest</code> can be used to specify meta-information about the
+ * jar file and its entries.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * If the verify flag is on when opening a signed jar file, the content of the
+ * file is verified against its signature embedded inside the file. Please note
+ * that the verification process does not include validating the signer's
+ * certificate. A caller should inspect the return value of
+ * {@link JarEntry#getCodeSigners()} to further determine if the signature
+ * can be trusted.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipFile
+ * @see     java.util.jar.JarEntry
+ * @since   1.2
+ */
+public
+class JarFile extends ZipFile {
+    // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+    // private SoftReference<Manifest> manRef;
+    private Manifest manifest;
+    private JarEntry manEntry;
+    private JarVerifier jv;
+    private boolean jvInitialized;
+    private boolean verify;
+
+    // indicates if Class-Path attribute present (only valid if hasCheckedSpecialAttributes true)
+    private boolean hasClassPathAttribute;
+    // true if manifest checked for special attributes
+    private volatile boolean hasCheckedSpecialAttributes;
+
+    // Android-removed: SharedSecrets.setJavaUtilJarAccess
+    /*
+    // Set up JavaUtilJarAccess in SharedSecrets
+    static {
+        SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
+    }
+    */
+
+    /**
+     * The JAR manifest file name.
+     */
+    public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * file <code>name</code>. The <code>JarFile</code> will be verified if
+     * it is signed.
+     * @param name the name of the jar file to be opened for reading
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(String name) throws IOException {
+        this(new File(name), true, ZipFile.OPEN_READ);
+    }
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * file <code>name</code>.
+     * @param name the name of the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(String name, boolean verify) throws IOException {
+        this(new File(name), verify, ZipFile.OPEN_READ);
+    }
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object. The <code>JarFile</code> will be verified if
+     * it is signed.
+     * @param file the jar file to be opened for reading
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     */
+    public JarFile(File file) throws IOException {
+        this(file, true, ZipFile.OPEN_READ);
+    }
+
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object.
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager.
+     */
+    public JarFile(File file, boolean verify) throws IOException {
+        this(file, verify, ZipFile.OPEN_READ);
+    }
+
+
+    /**
+     * Creates a new <code>JarFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * @param file the jar file to be opened for reading
+     * @param verify whether or not to verify the jar file if
+     * it is signed.
+     * @param mode the mode in which the file is to be opened
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalArgumentException
+     *         if the <tt>mode</tt> argument is invalid
+     * @throws SecurityException if access to the file is denied
+     *         by the SecurityManager
+     * @since 1.3
+     */
+    public JarFile(File file, boolean verify, int mode) throws IOException {
+        super(file, mode);
+        this.verify = verify;
+    }
+
+    /**
+     * Returns the jar file manifest, or <code>null</code> if none.
+     *
+     * @return the jar file manifest, or <code>null</code> if none
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     * @throws IOException  if an I/O error has occurred
+     */
+    public Manifest getManifest() throws IOException {
+        return getManifestFromReference();
+    }
+
+    // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114
+    // A volatile field might also work instead of synchronized. http://b/81505612
+    // private Manifest getManifestFromReference() throws IOException {
+    private synchronized Manifest getManifestFromReference() throws IOException {
+    // END Android-changed: Fix JarFile to be thread safe. http://b/27826114
+        // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+        // Manifest man = manRef != null ? manRef.get() : null;
+        Manifest man = manifest;
+        if (man == null) {
+
+            JarEntry manEntry = getManEntry();
+
+            // If found then load the manifest
+            if (manEntry != null) {
+                if (verify) {
+                    byte[] b = getBytes(manEntry);
+                    man = new Manifest(new ByteArrayInputStream(b));
+                    if (!jvInitialized) {
+                        jv = new JarVerifier(b);
+                    }
+                } else {
+                    man = new Manifest(super.getInputStream(manEntry));
+                }
+                // Android-changed: Hold the Manifest via a hard reference. http://b/28692091
+                // manRef = new SoftReference<>(man);
+                manifest = man;
+            }
+        }
+        return man;
+    }
+
+    private native String[] getMetaInfEntryNames();
+
+    /**
+     * Returns the <code>JarEntry</code> for the given entry name or
+     * <code>null</code> if not found.
+     *
+     * @param name the jar file entry name
+     * @return the <code>JarEntry</code> for the given entry name or
+     *         <code>null</code> if not found.
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     *
+     * @see java.util.jar.JarEntry
+     */
+    public JarEntry getJarEntry(String name) {
+        return (JarEntry)getEntry(name);
+    }
+
+    /**
+     * Returns the <code>ZipEntry</code> for the given entry name or
+     * <code>null</code> if not found.
+     *
+     * @param name the jar file entry name
+     * @return the <code>ZipEntry</code> for the given entry name or
+     *         <code>null</code> if not found
+     *
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     *
+     * @see java.util.zip.ZipEntry
+     */
+    public ZipEntry getEntry(String name) {
+        ZipEntry ze = super.getEntry(name);
+        if (ze != null) {
+            return new JarFileEntry(ze);
+        }
+        return null;
+    }
+
+    private class JarEntryIterator implements Enumeration<JarEntry>,
+            Iterator<JarEntry>
+    {
+        final Enumeration<? extends ZipEntry> e = JarFile.super.entries();
+
+        public boolean hasNext() {
+            return e.hasMoreElements();
+        }
+
+        public JarEntry next() {
+            ZipEntry ze = e.nextElement();
+            return new JarFileEntry(ze);
+        }
+
+        public boolean hasMoreElements() {
+            return hasNext();
+        }
+
+        public JarEntry nextElement() {
+            return next();
+        }
+    }
+
+    /**
+     * Returns an enumeration of the zip file entries.
+     */
+    public Enumeration<JarEntry> entries() {
+        return new JarEntryIterator();
+    }
+
+    @Override
+    public Stream<JarEntry> stream() {
+        return StreamSupport.stream(Spliterators.spliterator(
+                new JarEntryIterator(), size(),
+                Spliterator.ORDERED | Spliterator.DISTINCT |
+                        Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    private class JarFileEntry extends JarEntry {
+        JarFileEntry(ZipEntry ze) {
+            super(ze);
+        }
+        public Attributes getAttributes() throws IOException {
+            Manifest man = JarFile.this.getManifest();
+            if (man != null) {
+                return man.getAttributes(getName());
+            } else {
+                return null;
+            }
+        }
+        public Certificate[] getCertificates() {
+            try {
+                maybeInstantiateVerifier();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            if (certs == null && jv != null) {
+                certs = jv.getCerts(JarFile.this, this);
+            }
+            return certs == null ? null : certs.clone();
+        }
+        public CodeSigner[] getCodeSigners() {
+            try {
+                maybeInstantiateVerifier();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            if (signers == null && jv != null) {
+                signers = jv.getCodeSigners(JarFile.this, this);
+            }
+            return signers == null ? null : signers.clone();
+        }
+    }
+
+    /*
+     * Ensures that the JarVerifier has been created if one is
+     * necessary (i.e., the jar appears to be signed.) This is done as
+     * a quick check to avoid processing of the manifest for unsigned
+     * jars.
+     */
+    private void maybeInstantiateVerifier() throws IOException {
+        if (jv != null) {
+            return;
+        }
+
+        if (verify) {
+            String[] names = getMetaInfEntryNames();
+            if (names != null) {
+                for (int i = 0; i < names.length; i++) {
+                    String name = names[i].toUpperCase(Locale.ENGLISH);
+                    if (name.endsWith(".DSA") ||
+                        name.endsWith(".RSA") ||
+                        name.endsWith(".EC") ||
+                        name.endsWith(".SF")) {
+                        // Assume since we found a signature-related file
+                        // that the jar is signed and that we therefore
+                        // need a JarVerifier and Manifest
+                        getManifest();
+                        return;
+                    }
+                }
+            }
+            // No signature-related files; don't instantiate a
+            // verifier
+            verify = false;
+        }
+    }
+
+
+    /*
+     * Initializes the verifier object by reading all the manifest
+     * entries and passing them to the verifier.
+     */
+    private void initializeVerifier() {
+        ManifestEntryVerifier mev = null;
+
+        // Verify "META-INF/" entries...
+        try {
+            String[] names = getMetaInfEntryNames();
+            if (names != null) {
+                for (int i = 0; i < names.length; i++) {
+                    String uname = names[i].toUpperCase(Locale.ENGLISH);
+                    if (MANIFEST_NAME.equals(uname)
+                            || SignatureFileVerifier.isBlockOrSF(uname)) {
+                        JarEntry e = getJarEntry(names[i]);
+                        if (e == null) {
+                            throw new JarException("corrupted jar file");
+                        }
+                        if (mev == null) {
+                            mev = new ManifestEntryVerifier
+                                (getManifestFromReference());
+                        }
+                        byte[] b = getBytes(e);
+                        if (b != null && b.length > 0) {
+                            jv.beginEntry(e, mev);
+                            jv.update(b.length, b, 0, b.length, mev);
+                            jv.update(-1, null, 0, 0, mev);
+                        }
+                    }
+                }
+            }
+        } catch (IOException ex) {
+            // if we had an error parsing any blocks, just
+            // treat the jar file as being unsigned
+            jv = null;
+            verify = false;
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("jarfile parsing error!");
+                ex.printStackTrace();
+            }
+        }
+
+        // if after initializing the verifier we have nothing
+        // signed, we null it out.
+
+        if (jv != null) {
+
+            jv.doneWithMeta();
+            if (JarVerifier.debug != null) {
+                JarVerifier.debug.println("done with meta!");
+            }
+
+            if (jv.nothingToVerify()) {
+                if (JarVerifier.debug != null) {
+                    JarVerifier.debug.println("nothing to verify!");
+                }
+                jv = null;
+                verify = false;
+            }
+        }
+    }
+
+    /*
+     * Reads all the bytes for a given entry. Used to process the
+     * META-INF files.
+     */
+    private byte[] getBytes(ZipEntry ze) throws IOException {
+        try (InputStream is = super.getInputStream(ze)) {
+            return IOUtils.readFully(is, (int)ze.getSize(), true);
+        }
+    }
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     * @param ze the zip file entry
+     * @return an input stream for reading the contents of the specified
+     *         zip file entry
+     * @throws ZipException if a zip file format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     * @throws IllegalStateException
+     *         may be thrown if the jar file has been closed
+     */
+    public synchronized InputStream getInputStream(ZipEntry ze)
+        throws IOException
+    {
+        maybeInstantiateVerifier();
+        if (jv == null) {
+            return super.getInputStream(ze);
+        }
+        if (!jvInitialized) {
+            initializeVerifier();
+            jvInitialized = true;
+            // could be set to null after a call to
+            // initializeVerifier if we have nothing to
+            // verify
+            if (jv == null)
+                return super.getInputStream(ze);
+        }
+
+        // wrap a verifier stream around the real stream
+        return new JarVerifier.VerifierStream(
+            getManifestFromReference(),
+            ze instanceof JarFileEntry ?
+            (JarEntry) ze : getJarEntry(ze.getName()),
+            super.getInputStream(ze),
+            jv);
+    }
+
+    // Statics for hand-coded Boyer-Moore search
+    private static final char[] CLASSPATH_CHARS = {'c','l','a','s','s','-','p','a','t','h'};
+    // The bad character shift for "class-path"
+    private static final int[] CLASSPATH_LASTOCC;
+    // The good suffix shift for "class-path"
+    private static final int[] CLASSPATH_OPTOSFT;
+
+    static {
+        CLASSPATH_LASTOCC = new int[128];
+        CLASSPATH_OPTOSFT = new int[10];
+        CLASSPATH_LASTOCC[(int)'c'] = 1;
+        CLASSPATH_LASTOCC[(int)'l'] = 2;
+        CLASSPATH_LASTOCC[(int)'s'] = 5;
+        CLASSPATH_LASTOCC[(int)'-'] = 6;
+        CLASSPATH_LASTOCC[(int)'p'] = 7;
+        CLASSPATH_LASTOCC[(int)'a'] = 8;
+        CLASSPATH_LASTOCC[(int)'t'] = 9;
+        CLASSPATH_LASTOCC[(int)'h'] = 10;
+        for (int i=0; i<9; i++)
+            CLASSPATH_OPTOSFT[i] = 10;
+        CLASSPATH_OPTOSFT[9]=1;
+    }
+
+    // BEGIN Android-changed: Fix JarFile to be thread safe. http://b/27826114
+    // A volatile field might also work instead of synchronized. http://b/81505612
+    // private JarEntry getManEntry() {
+    private synchronized JarEntry getManEntry() {
+    // END Android-changed: Fix JarFile to be thread safe. http://b/27826114
+        if (manEntry == null) {
+            // First look up manifest entry using standard name
+            manEntry = getJarEntry(MANIFEST_NAME);
+            if (manEntry == null) {
+                // If not found, then iterate through all the "META-INF/"
+                // entries to find a match.
+                String[] names = getMetaInfEntryNames();
+                if (names != null) {
+                    for (int i = 0; i < names.length; i++) {
+                        if (MANIFEST_NAME.equals(
+                                                 names[i].toUpperCase(Locale.ENGLISH))) {
+                            manEntry = getJarEntry(names[i]);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return manEntry;
+    }
+
+   /**
+    * Returns {@code true} iff this JAR file has a manifest with the
+    * Class-Path attribute
+    * @hide
+    */
+    // Android-changed: Make hasClassPathAttribute() @hide public, for internal use.
+    // Used by URLClassPath.JarLoader.
+    // boolean hasClassPathAttribute() throws IOException {
+    public boolean hasClassPathAttribute() throws IOException {
+        checkForSpecialAttributes();
+        return hasClassPathAttribute;
+    }
+
+    /**
+     * Returns true if the pattern {@code src} is found in {@code b}.
+     * The {@code lastOcc} and {@code optoSft} arrays are the precomputed
+     * bad character and good suffix shifts.
+     */
+    private boolean match(char[] src, byte[] b, int[] lastOcc, int[] optoSft) {
+        int len = src.length;
+        int last = b.length - len;
+        int i = 0;
+        next:
+        while (i<=last) {
+            for (int j=(len-1); j>=0; j--) {
+                char c = (char) b[i+j];
+                c = (((c-'A')|('Z'-c)) >= 0) ? (char)(c + 32) : c;
+                if (c != src[j]) {
+                    i += Math.max(j + 1 - lastOcc[c&0x7F], optoSft[j]);
+                    continue next;
+                 }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * On first invocation, check if the JAR file has the Class-Path
+     * attribute. A no-op on subsequent calls.
+     */
+    private void checkForSpecialAttributes() throws IOException {
+        if (hasCheckedSpecialAttributes) return;
+        // Android-changed: Special handling of well-known .jar files specific to OpenJDK.
+        // if (!isKnownNotToHaveSpecialAttributes()) {
+        {
+            JarEntry manEntry = getManEntry();
+            if (manEntry != null) {
+                byte[] b = getBytes(manEntry);
+                if (match(CLASSPATH_CHARS, b, CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT))
+                    hasClassPathAttribute = true;
+            }
+        }
+        hasCheckedSpecialAttributes = true;
+    }
+
+
+    // Android-removed: Special handling of well-known .jar files specific to OpenJDK.
+    /*
+    private static String javaHome;
+    private static volatile String[] jarNames;
+    private boolean isKnownNotToHaveSpecialAttributes() {
+        // Optimize away even scanning of manifest for jar files we
+        // deliver which don't have a class-path attribute. If one of
+        // these jars is changed to include such an attribute this code
+        // must be changed.
+        if (javaHome == null) {
+            javaHome = AccessController.doPrivileged(
+                new GetPropertyAction("java.home"));
+        }
+        if (jarNames == null) {
+            String[] names = new String[11];
+            String fileSep = File.separator;
+            int i = 0;
+            names[i++] = fileSep + "rt.jar";
+            names[i++] = fileSep + "jsse.jar";
+            names[i++] = fileSep + "jce.jar";
+            names[i++] = fileSep + "charsets.jar";
+            names[i++] = fileSep + "dnsns.jar";
+            names[i++] = fileSep + "zipfs.jar";
+            names[i++] = fileSep + "localedata.jar";
+            names[i++] = fileSep = "cldrdata.jar";
+            names[i++] = fileSep + "sunjce_provider.jar";
+            names[i++] = fileSep + "sunpkcs11.jar";
+            names[i++] = fileSep + "sunec.jar";
+            jarNames = names;
+        }
+
+        String name = getName();
+        String localJavaHome = javaHome;
+        if (name.startsWith(localJavaHome)) {
+            String[] names = jarNames;
+            for (int i = 0; i < names.length; i++) {
+                if (name.endsWith(names[i])) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+    */
+
+    // Android-removed: Unused method ensureInitialization().
+    /*
+    private synchronized void ensureInitialization() {
+        try {
+            maybeInstantiateVerifier();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (jv != null && !jvInitialized) {
+            initializeVerifier();
+            jvInitialized = true;
+        }
+    }
+    */
+
+    JarEntry newEntry(ZipEntry ze) {
+        return new JarFileEntry(ze);
+    }
+
+    // Android-removed: Unused methods entryNames(), entries2().
+    /*
+    Enumeration<String> entryNames(CodeSource[] cs) {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.entryNames(this, cs);
+        }
+
+        /*
+         * JAR file has no signed content. Is there a non-signing
+         * code source?
+         *
+        boolean includeUnsigned = false;
+        for (int i = 0; i < cs.length; i++) {
+            if (cs[i].getCodeSigners() == null) {
+                includeUnsigned = true;
+                break;
+            }
+        }
+        if (includeUnsigned) {
+            return unsignedEntryNames();
+        } else {
+            return new Enumeration<String>() {
+
+                public boolean hasMoreElements() {
+                    return false;
+                }
+
+                public String nextElement() {
+                    throw new NoSuchElementException();
+                }
+            };
+        }
+    }
+
+    /**
+     * Returns an enumeration of the zip file entries
+     * excluding internal JAR mechanism entries and including
+     * signed entries missing from the ZIP directory.
+     *
+    Enumeration<JarEntry> entries2() {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.entries2(this, super.entries());
+        }
+
+        // screen out entries which are never signed
+        final Enumeration<? extends ZipEntry> enum_ = super.entries();
+        return new Enumeration<JarEntry>() {
+
+            ZipEntry entry;
+
+            public boolean hasMoreElements() {
+                if (entry != null) {
+                    return true;
+                }
+                while (enum_.hasMoreElements()) {
+                    ZipEntry ze = enum_.nextElement();
+                    if (JarVerifier.isSigningRelated(ze.getName())) {
+                        continue;
+                    }
+                    entry = ze;
+                    return true;
+                }
+                return false;
+            }
+
+            public JarFileEntry nextElement() {
+                if (hasMoreElements()) {
+                    ZipEntry ze = entry;
+                    entry = null;
+                    return new JarFileEntry(ze);
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    CodeSource[] getCodeSources(URL url) {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.getCodeSources(this, url);
+        }
+
+        /*
+         * JAR file has no signed content. Is there a non-signing
+         * code source?
+         *
+        Enumeration<String> unsigned = unsignedEntryNames();
+        if (unsigned.hasMoreElements()) {
+            return new CodeSource[]{JarVerifier.getUnsignedCS(url)};
+        } else {
+            return null;
+        }
+    }
+
+    private Enumeration<String> unsignedEntryNames() {
+        final Enumeration<JarEntry> entries = entries();
+        return new Enumeration<String>() {
+
+            String name;
+
+            /*
+             * Grab entries from ZIP directory but screen out
+             * metadata.
+             *
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+                while (entries.hasMoreElements()) {
+                    String value;
+                    ZipEntry e = entries.nextElement();
+                    value = e.getName();
+                    if (e.isDirectory() || JarVerifier.isSigningRelated(value)) {
+                        continue;
+                    }
+                    name = value;
+                    return true;
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    CodeSource getCodeSource(URL url, String name) {
+        ensureInitialization();
+        if (jv != null) {
+            if (jv.eagerValidation) {
+                CodeSource cs = null;
+                JarEntry je = getJarEntry(name);
+                if (je != null) {
+                    cs = jv.getCodeSource(url, this, je);
+                } else {
+                    cs = jv.getCodeSource(url, name);
+                }
+                return cs;
+            } else {
+                return jv.getCodeSource(url, name);
+            }
+        }
+
+        return JarVerifier.getUnsignedCS(url);
+    }
+
+    void setEagerValidation(boolean eager) {
+        try {
+            maybeInstantiateVerifier();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        if (jv != null) {
+            jv.setEagerValidation(eager);
+        }
+    }
+
+    List<Object> getManifestDigests() {
+        ensureInitialization();
+        if (jv != null) {
+            return jv.getManifestDigests();
+        }
+        return new ArrayList<Object>();
+    }
+    */
+}
diff --git a/java/util/jar/JarInputStream.java b/java/util/jar/JarInputStream.java
new file mode 100644
index 0000000..67f27be
--- /dev/null
+++ b/java/util/jar/JarInputStream.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+import sun.security.util.ManifestEntryVerifier;
+import sun.misc.JarIndex;
+
+/**
+ * The <code>JarInputStream</code> class is used to read the contents of
+ * a JAR file from any input stream. It extends the class
+ * <code>java.util.zip.ZipInputStream</code> with support for reading
+ * an optional <code>Manifest</code> entry. The <code>Manifest</code>
+ * can be used to store meta-information about the JAR file and its entries.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipInputStream
+ * @since   1.2
+ */
+public
+class JarInputStream extends ZipInputStream {
+    private Manifest man;
+    private JarEntry first;
+    private JarVerifier jv;
+    private ManifestEntryVerifier mev;
+    private final boolean doVerify;
+    private boolean tryManifest;
+
+    /**
+     * Creates a new <code>JarInputStream</code> and reads the optional
+     * manifest. If a manifest is present, also attempts to verify
+     * the signatures if the JarInputStream is signed.
+     * @param in the actual input stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarInputStream(InputStream in) throws IOException {
+        this(in, true);
+    }
+
+    /**
+     * Creates a new <code>JarInputStream</code> and reads the optional
+     * manifest. If a manifest is present and verify is true, also attempts
+     * to verify the signatures if the JarInputStream is signed.
+     *
+     * @param in the actual input stream
+     * @param verify whether or not to verify the JarInputStream if
+     * it is signed.
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarInputStream(InputStream in, boolean verify) throws IOException {
+        super(in);
+        this.doVerify = verify;
+
+        // This implementation assumes the META-INF/MANIFEST.MF entry
+        // should be either the first or the second entry (when preceded
+        // by the dir META-INF/). It skips the META-INF/ and then
+        // "consumes" the MANIFEST.MF to initialize the Manifest object.
+        JarEntry e = (JarEntry)super.getNextEntry();
+        if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
+            e = (JarEntry)super.getNextEntry();
+        first = checkManifest(e);
+    }
+
+    private JarEntry checkManifest(JarEntry e)
+        throws IOException
+    {
+        if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
+            man = new Manifest();
+            byte bytes[] = getBytes(new BufferedInputStream(this));
+            man.read(new ByteArrayInputStream(bytes));
+            closeEntry();
+            if (doVerify) {
+                jv = new JarVerifier(bytes);
+                mev = new ManifestEntryVerifier(man);
+            }
+            return (JarEntry)super.getNextEntry();
+        }
+        return e;
+    }
+
+    private byte[] getBytes(InputStream is)
+        throws IOException
+    {
+        byte[] buffer = new byte[8192];
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
+        int n;
+        while ((n = is.read(buffer, 0, buffer.length)) != -1) {
+            baos.write(buffer, 0, n);
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Returns the <code>Manifest</code> for this JAR file, or
+     * <code>null</code> if none.
+     *
+     * @return the <code>Manifest</code> for this JAR file, or
+     *         <code>null</code> if none.
+     */
+    public Manifest getManifest() {
+        return man;
+    }
+
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data. If verification has been enabled,
+     * any invalid signature detected while positioning the stream for
+     * the next entry will result in an exception.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public ZipEntry getNextEntry() throws IOException {
+        JarEntry e;
+        if (first == null) {
+            e = (JarEntry)super.getNextEntry();
+            if (tryManifest) {
+                e = checkManifest(e);
+                tryManifest = false;
+            }
+        } else {
+            e = first;
+            if (first.getName().equalsIgnoreCase(JarIndex.INDEX_NAME))
+                tryManifest = true;
+            first = null;
+        }
+        if (jv != null && e != null) {
+            // At this point, we might have parsed all the meta-inf
+            // entries and have nothing to verify. If we have
+            // nothing to verify, get rid of the JarVerifier object.
+            if (jv.nothingToVerify() == true) {
+                jv = null;
+                mev = null;
+            } else {
+                jv.beginEntry(e, mev);
+            }
+        }
+        return e;
+    }
+
+    /**
+     * Reads the next JAR file entry and positions the stream at the
+     * beginning of the entry data. If verification has been enabled,
+     * any invalid signature detected while positioning the stream for
+     * the next entry will result in an exception.
+     * @return the next JAR file entry, or null if there are no more entries
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public JarEntry getNextJarEntry() throws IOException {
+        return (JarEntry)getNextEntry();
+    }
+
+    /**
+     * Reads from the current JAR file entry into an array of bytes.
+     * If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * If verification has been enabled, any invalid signature
+     * on the current entry will be reported at some point before the
+     * end of the entry is reached.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes to read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         entry is reached
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception SecurityException if any of the jar file entries
+     *         are incorrectly signed.
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        int n;
+        if (first == null) {
+            n = super.read(b, off, len);
+        } else {
+            n = -1;
+        }
+        if (jv != null) {
+            jv.update(n, b, off, len, mev);
+        }
+        return n;
+    }
+
+    /**
+     * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
+     * specified JAR file entry name. The manifest attributes of
+     * the specified JAR file entry name will be copied to the new
+     * <CODE>JarEntry</CODE>.
+     *
+     * @param name the name of the JAR/ZIP file entry
+     * @return the <code>JarEntry</code> object just created
+     */
+    protected ZipEntry createZipEntry(String name) {
+        JarEntry e = new JarEntry(name);
+        if (man != null) {
+            e.attr = man.getAttributes(name);
+        }
+        return e;
+    }
+}
diff --git a/java/util/jar/JarOutputStream.java b/java/util/jar/JarOutputStream.java
new file mode 100644
index 0000000..3694277
--- /dev/null
+++ b/java/util/jar/JarOutputStream.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+
+/**
+ * The <code>JarOutputStream</code> class is used to write the contents
+ * of a JAR file to any output stream. It extends the class
+ * <code>java.util.zip.ZipOutputStream</code> with support
+ * for writing an optional <code>Manifest</code> entry. The
+ * <code>Manifest</code> can be used to specify meta-information about
+ * the JAR file and its entries.
+ *
+ * @author  David Connelly
+ * @see     Manifest
+ * @see     java.util.zip.ZipOutputStream
+ * @since   1.2
+ */
+public
+class JarOutputStream extends ZipOutputStream {
+    private static final int JAR_MAGIC = 0xCAFE;
+
+    /**
+     * Creates a new <code>JarOutputStream</code> with the specified
+     * <code>Manifest</code>. The manifest is written as the first
+     * entry to the output stream.
+     *
+     * @param out the actual output stream
+     * @param man the optional <code>Manifest</code>
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarOutputStream(OutputStream out, Manifest man) throws IOException {
+        super(out);
+        if (man == null) {
+            throw new NullPointerException("man");
+        }
+        ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
+        putNextEntry(e);
+        man.write(new BufferedOutputStream(this));
+        closeEntry();
+    }
+
+    /**
+     * Creates a new <code>JarOutputStream</code> with no manifest.
+     * @param out the actual output stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public JarOutputStream(OutputStream out) throws IOException {
+        super(out);
+    }
+
+    /**
+     * Begins writing a new JAR file entry and positions the stream
+     * to the start of the entry data. This method will also close
+     * any previous entry. The default compression method will be
+     * used if no compression method was specified for the entry.
+     * The current time will be used if the entry has no set modification
+     * time.
+     *
+     * @param ze the ZIP/JAR entry to be written
+     * @exception ZipException if a ZIP error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void putNextEntry(ZipEntry ze) throws IOException {
+        if (firstEntry) {
+            // Make sure that extra field data for first JAR
+            // entry includes JAR magic number id.
+            byte[] edata = ze.getExtra();
+            if (edata == null || !hasMagic(edata)) {
+                if (edata == null) {
+                    edata = new byte[4];
+                } else {
+                    // Prepend magic to existing extra data
+                    byte[] tmp = new byte[edata.length + 4];
+                    System.arraycopy(edata, 0, tmp, 4, edata.length);
+                    edata = tmp;
+                }
+                set16(edata, 0, JAR_MAGIC); // extra field id
+                set16(edata, 2, 0);         // extra field size
+                ze.setExtra(edata);
+            }
+            firstEntry = false;
+        }
+        super.putNextEntry(ze);
+    }
+
+    private boolean firstEntry = true;
+
+    /*
+     * Returns true if specified byte array contains the
+     * jar magic extra field id.
+     */
+    private static boolean hasMagic(byte[] edata) {
+        try {
+            int i = 0;
+            while (i < edata.length) {
+                if (get16(edata, i) == JAR_MAGIC) {
+                    return true;
+                }
+                i += get16(edata, i + 2) + 4;
+            }
+        } catch (ArrayIndexOutOfBoundsException e) {
+            // Invalid extra field data
+        }
+        return false;
+    }
+
+    /*
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    private static int get16(byte[] b, int off) {
+        return Byte.toUnsignedInt(b[off]) | ( Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    /*
+     * Sets 16-bit value at specified offset. The bytes are assumed to
+     * be in Intel (little-endian) byte order.
+     */
+    private static void set16(byte[] b, int off, int value) {
+        b[off+0] = (byte)value;
+        b[off+1] = (byte)(value >> 8);
+    }
+}
diff --git a/java/util/jar/JarVerifier.java b/java/util/jar/JarVerifier.java
new file mode 100644
index 0000000..e0e7d55
--- /dev/null
+++ b/java/util/jar/JarVerifier.java
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.*;
+import java.net.URL;
+import java.util.*;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.util.zip.ZipEntry;
+
+import sun.misc.JarIndex;
+import sun.security.util.ManifestDigester;
+import sun.security.util.ManifestEntryVerifier;
+import sun.security.util.SignatureFileVerifier;
+import sun.security.util.Debug;
+
+/**
+ *
+ * @author      Roland Schemers
+ */
+class JarVerifier {
+
+    /* Are we debugging ? */
+    static final Debug debug = Debug.getInstance("jar");
+
+    /* a table mapping names to code signers, for jar entries that have
+       had their actual hashes verified */
+    private Hashtable<String, CodeSigner[]> verifiedSigners;
+
+    /* a table mapping names to code signers, for jar entries that have
+       passed the .SF/.DSA/.EC -> MANIFEST check */
+    private Hashtable<String, CodeSigner[]> sigFileSigners;
+
+    /* a hash table to hold .SF bytes */
+    private Hashtable<String, byte[]> sigFileData;
+
+    /** "queue" of pending PKCS7 blocks that we couldn't parse
+     *  until we parsed the .SF file */
+    private ArrayList<SignatureFileVerifier> pendingBlocks;
+
+    /* cache of CodeSigner objects */
+    private ArrayList<CodeSigner[]> signerCache;
+
+    /* Are we parsing a block? */
+    private boolean parsingBlockOrSF = false;
+
+    /* Are we done parsing META-INF entries? */
+    private boolean parsingMeta = true;
+
+    /* Are there are files to verify? */
+    private boolean anyToVerify = true;
+
+    /* The output stream to use when keeping track of files we are interested
+       in */
+    private ByteArrayOutputStream baos;
+
+    /** The ManifestDigester object */
+    private volatile ManifestDigester manDig;
+
+    /** the bytes for the manDig object */
+    byte manifestRawBytes[] = null;
+
+    /** controls eager signature validation */
+    boolean eagerValidation;
+
+    /** makes code source singleton instances unique to us */
+    private Object csdomain = new Object();
+
+    /** collect -DIGEST-MANIFEST values for blacklist */
+    private List<Object> manifestDigests;
+
+    public JarVerifier(byte rawBytes[]) {
+        manifestRawBytes = rawBytes;
+        sigFileSigners = new Hashtable<>();
+        verifiedSigners = new Hashtable<>();
+        sigFileData = new Hashtable<>(11);
+        pendingBlocks = new ArrayList<>();
+        baos = new ByteArrayOutputStream();
+        manifestDigests = new ArrayList<>();
+    }
+
+    /**
+     * This method scans to see which entry we're parsing and
+     * keeps various state information depending on what type of
+     * file is being parsed.
+     */
+    public void beginEntry(JarEntry je, ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (je == null)
+            return;
+
+        if (debug != null) {
+            debug.println("beginEntry "+je.getName());
+        }
+
+        String name = je.getName();
+
+        /*
+         * Assumptions:
+         * 1. The manifest should be the first entry in the META-INF directory.
+         * 2. The .SF/.DSA/.EC files follow the manifest, before any normal entries
+         * 3. Any of the following will throw a SecurityException:
+         *    a. digest mismatch between a manifest section and
+         *       the SF section.
+         *    b. digest mismatch between the actual jar entry and the manifest
+         */
+
+        if (parsingMeta) {
+            String uname = name.toUpperCase(Locale.ENGLISH);
+            if ((uname.startsWith("META-INF/") ||
+                 uname.startsWith("/META-INF/"))) {
+
+                if (je.isDirectory()) {
+                    mev.setEntry(null, je);
+                    return;
+                }
+
+                if (uname.equals(JarFile.MANIFEST_NAME) ||
+                        uname.equals(JarIndex.INDEX_NAME)) {
+                    return;
+                }
+
+                if (SignatureFileVerifier.isBlockOrSF(uname)) {
+                    /* We parse only DSA, RSA or EC PKCS7 blocks. */
+                    parsingBlockOrSF = true;
+                    baos.reset();
+                    mev.setEntry(null, je);
+                    return;
+                }
+
+                // If a META-INF entry is not MF or block or SF, they should
+                // be normal entries. According to 2 above, no more block or
+                // SF will appear. Let's doneWithMeta.
+            }
+        }
+
+        if (parsingMeta) {
+            doneWithMeta();
+        }
+
+        if (je.isDirectory()) {
+            mev.setEntry(null, je);
+            return;
+        }
+
+        // be liberal in what you accept. If the name starts with ./, remove
+        // it as we internally canonicalize it with out the ./.
+        if (name.startsWith("./"))
+            name = name.substring(2);
+
+        // be liberal in what you accept. If the name starts with /, remove
+        // it as we internally canonicalize it with out the /.
+        if (name.startsWith("/"))
+            name = name.substring(1);
+
+        // only set the jev object for entries that have a signature
+        // (either verified or not)
+        if (sigFileSigners.get(name) != null ||
+                verifiedSigners.get(name) != null) {
+            mev.setEntry(name, je);
+            return;
+        }
+
+        // don't compute the digest for this entry
+        mev.setEntry(null, je);
+
+        return;
+    }
+
+    /**
+     * update a single byte.
+     */
+
+    public void update(int b, ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (b != -1) {
+            if (parsingBlockOrSF) {
+                baos.write(b);
+            } else {
+                mev.update((byte)b);
+            }
+        } else {
+            processEntry(mev);
+        }
+    }
+
+    /**
+     * update an array of bytes.
+     */
+
+    public void update(int n, byte[] b, int off, int len,
+                       ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (n != -1) {
+            if (parsingBlockOrSF) {
+                baos.write(b, off, n);
+            } else {
+                mev.update(b, off, n);
+            }
+        } else {
+            processEntry(mev);
+        }
+    }
+
+    /**
+     * called when we reach the end of entry in one of the read() methods.
+     */
+    private void processEntry(ManifestEntryVerifier mev)
+        throws IOException
+    {
+        if (!parsingBlockOrSF) {
+            JarEntry je = mev.getEntry();
+            if ((je != null) && (je.signers == null)) {
+                je.signers = mev.verify(verifiedSigners, sigFileSigners);
+                je.certs = mapSignersToCertArray(je.signers);
+            }
+        } else {
+
+            try {
+                parsingBlockOrSF = false;
+
+                if (debug != null) {
+                    debug.println("processEntry: processing block");
+                }
+
+                String uname = mev.getEntry().getName()
+                                             .toUpperCase(Locale.ENGLISH);
+
+                if (uname.endsWith(".SF")) {
+                    String key = uname.substring(0, uname.length()-3);
+                    byte bytes[] = baos.toByteArray();
+                    // add to sigFileData in case future blocks need it
+                    sigFileData.put(key, bytes);
+                    // check pending blocks, we can now process
+                    // anyone waiting for this .SF file
+                    Iterator<SignatureFileVerifier> it = pendingBlocks.iterator();
+                    while (it.hasNext()) {
+                        SignatureFileVerifier sfv = it.next();
+                        if (sfv.needSignatureFile(key)) {
+                            if (debug != null) {
+                                debug.println(
+                                 "processEntry: processing pending block");
+                            }
+
+                            sfv.setSignatureFile(bytes);
+                            sfv.process(sigFileSigners, manifestDigests);
+                        }
+                    }
+                    return;
+                }
+
+                // now we are parsing a signature block file
+
+                String key = uname.substring(0, uname.lastIndexOf("."));
+
+                if (signerCache == null)
+                    signerCache = new ArrayList<>();
+
+                if (manDig == null) {
+                    synchronized(manifestRawBytes) {
+                        if (manDig == null) {
+                            manDig = new ManifestDigester(manifestRawBytes);
+                            manifestRawBytes = null;
+                        }
+                    }
+                }
+
+                SignatureFileVerifier sfv =
+                  new SignatureFileVerifier(signerCache,
+                                            manDig, uname, baos.toByteArray());
+
+                if (sfv.needSignatureFileBytes()) {
+                    // see if we have already parsed an external .SF file
+                    byte[] bytes = sigFileData.get(key);
+
+                    if (bytes == null) {
+                        // put this block on queue for later processing
+                        // since we don't have the .SF bytes yet
+                        // (uname, block);
+                        if (debug != null) {
+                            debug.println("adding pending block");
+                        }
+                        pendingBlocks.add(sfv);
+                        return;
+                    } else {
+                        sfv.setSignatureFile(bytes);
+                    }
+                }
+                sfv.process(sigFileSigners, manifestDigests);
+
+            } catch (IOException ioe) {
+                // e.g. sun.security.pkcs.ParsingException
+                if (debug != null) debug.println("processEntry caught: "+ioe);
+                // ignore and treat as unsigned
+            } catch (SignatureException se) {
+                if (debug != null) debug.println("processEntry caught: "+se);
+                // ignore and treat as unsigned
+            } catch (NoSuchAlgorithmException nsae) {
+                if (debug != null) debug.println("processEntry caught: "+nsae);
+                // ignore and treat as unsigned
+            } catch (CertificateException ce) {
+                if (debug != null) debug.println("processEntry caught: "+ce);
+                // ignore and treat as unsigned
+            }
+        }
+    }
+
+    // Android-changed: @deprecated tag needs a description. http://b/110781661
+    /**
+     * Return an array of java.security.cert.Certificate objects for
+     * the given file in the jar.
+     * @deprecated Deprecated.
+     */
+    @Deprecated
+    public java.security.cert.Certificate[] getCerts(String name)
+    {
+        return mapSignersToCertArray(getCodeSigners(name));
+    }
+
+    public java.security.cert.Certificate[] getCerts(JarFile jar, JarEntry entry)
+    {
+        return mapSignersToCertArray(getCodeSigners(jar, entry));
+    }
+
+    /**
+     * return an array of CodeSigner objects for
+     * the given file in the jar. this array is not cloned.
+     *
+     */
+    public CodeSigner[] getCodeSigners(String name)
+    {
+        return verifiedSigners.get(name);
+    }
+
+    public CodeSigner[] getCodeSigners(JarFile jar, JarEntry entry)
+    {
+        String name = entry.getName();
+        if (eagerValidation && sigFileSigners.get(name) != null) {
+            /*
+             * Force a read of the entry data to generate the
+             * verification hash.
+             */
+            try {
+                InputStream s = jar.getInputStream(entry);
+                byte[] buffer = new byte[1024];
+                int n = buffer.length;
+                while (n != -1) {
+                    n = s.read(buffer, 0, buffer.length);
+                }
+                s.close();
+            } catch (IOException e) {
+            }
+        }
+        return getCodeSigners(name);
+    }
+
+    /*
+     * Convert an array of signers into an array of concatenated certificate
+     * arrays.
+     */
+    private static java.security.cert.Certificate[] mapSignersToCertArray(
+        CodeSigner[] signers) {
+
+        if (signers != null) {
+            ArrayList<java.security.cert.Certificate> certChains = new ArrayList<>();
+            for (int i = 0; i < signers.length; i++) {
+                certChains.addAll(
+                    signers[i].getSignerCertPath().getCertificates());
+            }
+
+            // Convert into a Certificate[]
+            return certChains.toArray(
+                    new java.security.cert.Certificate[certChains.size()]);
+        }
+        return null;
+    }
+
+    /**
+     * returns true if there no files to verify.
+     * should only be called after all the META-INF entries
+     * have been processed.
+     */
+    boolean nothingToVerify()
+    {
+        return (anyToVerify == false);
+    }
+
+    /**
+     * called to let us know we have processed all the
+     * META-INF entries, and if we re-read one of them, don't
+     * re-process it. Also gets rid of any data structures
+     * we needed when parsing META-INF entries.
+     */
+    void doneWithMeta()
+    {
+        parsingMeta = false;
+        anyToVerify = !sigFileSigners.isEmpty();
+        baos = null;
+        sigFileData = null;
+        pendingBlocks = null;
+        signerCache = null;
+        manDig = null;
+        // MANIFEST.MF is always treated as signed and verified,
+        // move its signers from sigFileSigners to verifiedSigners.
+        if (sigFileSigners.containsKey(JarFile.MANIFEST_NAME)) {
+            CodeSigner[] codeSigners = sigFileSigners.remove(JarFile.MANIFEST_NAME);
+            verifiedSigners.put(JarFile.MANIFEST_NAME, codeSigners);
+        }
+    }
+
+    static class VerifierStream extends java.io.InputStream {
+
+        private InputStream is;
+        private JarVerifier jv;
+        private ManifestEntryVerifier mev;
+        private long numLeft;
+
+        VerifierStream(Manifest man,
+                       JarEntry je,
+                       InputStream is,
+                       JarVerifier jv) throws IOException
+        {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            // To know that null signals that the stream has been closed, we disallow
+            // it in the constructor. There's no need for anyone to pass null into this
+            // constructor, anyway.
+            if (is == null) {
+                throw new NullPointerException("is == null");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            this.is = is;
+            this.jv = jv;
+            this.mev = new ManifestEntryVerifier(man);
+            this.jv.beginEntry(je, mev);
+            this.numLeft = je.getSize();
+            if (this.numLeft == 0)
+                this.jv.update(-1, this.mev);
+        }
+
+        public int read() throws IOException
+        {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (numLeft > 0) {
+                int b = is.read();
+                jv.update(b, mev);
+                numLeft--;
+                if (numLeft == 0)
+                    jv.update(-1, mev);
+                return b;
+            } else {
+                return -1;
+            }
+        }
+
+        public int read(byte b[], int off, int len) throws IOException {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if ((numLeft > 0) && (numLeft < len)) {
+                len = (int)numLeft;
+            }
+
+            if (numLeft > 0) {
+                int n = is.read(b, off, len);
+                jv.update(n, b, off, len, mev);
+                numLeft -= n;
+                if (numLeft == 0)
+                    jv.update(-1, b, off, len, mev);
+                return n;
+            } else {
+                return -1;
+            }
+        }
+
+        public void close()
+            throws IOException
+        {
+            if (is != null)
+                is.close();
+            is = null;
+            mev = null;
+            jv = null;
+        }
+
+        public int available() throws IOException {
+            // BEGIN Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            if (is == null) {
+                throw new IOException("stream closed");
+            }
+            // END Android-added: Throw IOE, not NPE, if stream is closed. http://b/110695212
+            return is.available();
+        }
+
+    }
+
+    // Extended JavaUtilJarAccess CodeSource API Support
+
+    private Map<URL, Map<CodeSigner[], CodeSource>> urlToCodeSourceMap = new HashMap<>();
+    private Map<CodeSigner[], CodeSource> signerToCodeSource = new HashMap<>();
+    private URL lastURL;
+    private Map<CodeSigner[], CodeSource> lastURLMap;
+
+    /*
+     * Create a unique mapping from codeSigner cache entries to CodeSource.
+     * In theory, multiple URLs origins could map to a single locally cached
+     * and shared JAR file although in practice there will be a single URL in use.
+     */
+    private synchronized CodeSource mapSignersToCodeSource(URL url, CodeSigner[] signers) {
+        Map<CodeSigner[], CodeSource> map;
+        if (url == lastURL) {
+            map = lastURLMap;
+        } else {
+            map = urlToCodeSourceMap.get(url);
+            if (map == null) {
+                map = new HashMap<>();
+                urlToCodeSourceMap.put(url, map);
+            }
+            lastURLMap = map;
+            lastURL = url;
+        }
+        CodeSource cs = map.get(signers);
+        if (cs == null) {
+            cs = new VerifierCodeSource(csdomain, url, signers);
+            signerToCodeSource.put(signers, cs);
+        }
+        return cs;
+    }
+
+    private CodeSource[] mapSignersToCodeSources(URL url, List<CodeSigner[]> signers, boolean unsigned) {
+        List<CodeSource> sources = new ArrayList<>();
+
+        for (int i = 0; i < signers.size(); i++) {
+            sources.add(mapSignersToCodeSource(url, signers.get(i)));
+        }
+        if (unsigned) {
+            sources.add(mapSignersToCodeSource(url, null));
+        }
+        return sources.toArray(new CodeSource[sources.size()]);
+    }
+    private CodeSigner[] emptySigner = new CodeSigner[0];
+
+    /*
+     * Match CodeSource to a CodeSigner[] in the signer cache.
+     */
+    private CodeSigner[] findMatchingSigners(CodeSource cs) {
+        if (cs instanceof VerifierCodeSource) {
+            VerifierCodeSource vcs = (VerifierCodeSource) cs;
+            if (vcs.isSameDomain(csdomain)) {
+                return ((VerifierCodeSource) cs).getPrivateSigners();
+            }
+        }
+
+        /*
+         * In practice signers should always be optimized above
+         * but this handles a CodeSource of any type, just in case.
+         */
+        CodeSource[] sources = mapSignersToCodeSources(cs.getLocation(), getJarCodeSigners(), true);
+        List<CodeSource> sourceList = new ArrayList<>();
+        for (int i = 0; i < sources.length; i++) {
+            sourceList.add(sources[i]);
+        }
+        int j = sourceList.indexOf(cs);
+        if (j != -1) {
+            CodeSigner[] match;
+            match = ((VerifierCodeSource) sourceList.get(j)).getPrivateSigners();
+            if (match == null) {
+                match = emptySigner;
+            }
+            return match;
+        }
+        return null;
+    }
+
+    /*
+     * Instances of this class hold uncopied references to internal
+     * signing data that can be compared by object reference identity.
+     */
+    private static class VerifierCodeSource extends CodeSource {
+        private static final long serialVersionUID = -9047366145967768825L;
+
+        URL vlocation;
+        CodeSigner[] vsigners;
+        java.security.cert.Certificate[] vcerts;
+        Object csdomain;
+
+        VerifierCodeSource(Object csdomain, URL location, CodeSigner[] signers) {
+            super(location, signers);
+            this.csdomain = csdomain;
+            vlocation = location;
+            vsigners = signers; // from signerCache
+        }
+
+        VerifierCodeSource(Object csdomain, URL location, java.security.cert.Certificate[] certs) {
+            super(location, certs);
+            this.csdomain = csdomain;
+            vlocation = location;
+            vcerts = certs; // from signerCache
+        }
+
+        /*
+         * All VerifierCodeSource instances are constructed based on
+         * singleton signerCache or signerCacheCert entries for each unique signer.
+         * No CodeSigner<->Certificate[] conversion is required.
+         * We use these assumptions to optimize equality comparisons.
+         */
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof VerifierCodeSource) {
+                VerifierCodeSource that = (VerifierCodeSource) obj;
+
+                /*
+                 * Only compare against other per-signer singletons constructed
+                 * on behalf of the same JarFile instance. Otherwise, compare
+                 * things the slower way.
+                 */
+                if (isSameDomain(that.csdomain)) {
+                    if (that.vsigners != this.vsigners
+                            || that.vcerts != this.vcerts) {
+                        return false;
+                    }
+                    if (that.vlocation != null) {
+                        return that.vlocation.equals(this.vlocation);
+                    } else if (this.vlocation != null) {
+                        return this.vlocation.equals(that.vlocation);
+                    } else { // both null
+                        return true;
+                    }
+                }
+            }
+            return super.equals(obj);
+        }
+
+        boolean isSameDomain(Object csdomain) {
+            return this.csdomain == csdomain;
+        }
+
+        private CodeSigner[] getPrivateSigners() {
+            return vsigners;
+        }
+
+        private java.security.cert.Certificate[] getPrivateCertificates() {
+            return vcerts;
+        }
+    }
+    private Map<String, CodeSigner[]> signerMap;
+
+    private synchronized Map<String, CodeSigner[]> signerMap() {
+        if (signerMap == null) {
+            /*
+             * Snapshot signer state so it doesn't change on us. We care
+             * only about the asserted signatures. Verification of
+             * signature validity happens via the JarEntry apis.
+             */
+            signerMap = new HashMap<>(verifiedSigners.size() + sigFileSigners.size());
+            signerMap.putAll(verifiedSigners);
+            signerMap.putAll(sigFileSigners);
+        }
+        return signerMap;
+    }
+
+    public synchronized Enumeration<String> entryNames(JarFile jar, final CodeSource[] cs) {
+        final Map<String, CodeSigner[]> map = signerMap();
+        final Iterator<Map.Entry<String, CodeSigner[]>> itor = map.entrySet().iterator();
+        boolean matchUnsigned = false;
+
+        /*
+         * Grab a single copy of the CodeSigner arrays. Check
+         * to see if we can optimize CodeSigner equality test.
+         */
+        List<CodeSigner[]> req = new ArrayList<>(cs.length);
+        for (int i = 0; i < cs.length; i++) {
+            CodeSigner[] match = findMatchingSigners(cs[i]);
+            if (match != null) {
+                if (match.length > 0) {
+                    req.add(match);
+                } else {
+                    matchUnsigned = true;
+                }
+            } else {
+                matchUnsigned = true;
+            }
+        }
+
+        final List<CodeSigner[]> signersReq = req;
+        final Enumeration<String> enum2 = (matchUnsigned) ? unsignedEntryNames(jar) : emptyEnumeration;
+
+        return new Enumeration<String>() {
+
+            String name;
+
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+
+                while (itor.hasNext()) {
+                    Map.Entry<String, CodeSigner[]> e = itor.next();
+                    if (signersReq.contains(e.getValue())) {
+                        name = e.getKey();
+                        return true;
+                    }
+                }
+                while (enum2.hasMoreElements()) {
+                    name = enum2.nextElement();
+                    return true;
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+    /*
+     * Like entries() but screens out internal JAR mechanism entries
+     * and includes signed entries with no ZIP data.
+     */
+    public Enumeration<JarEntry> entries2(final JarFile jar, Enumeration<? extends ZipEntry> e) {
+        final Map<String, CodeSigner[]> map = new HashMap<>();
+        map.putAll(signerMap());
+        final Enumeration<? extends ZipEntry> enum_ = e;
+        return new Enumeration<JarEntry>() {
+
+            Enumeration<String> signers = null;
+            JarEntry entry;
+
+            public boolean hasMoreElements() {
+                if (entry != null) {
+                    return true;
+                }
+                while (enum_.hasMoreElements()) {
+                    ZipEntry ze = enum_.nextElement();
+                    if (JarVerifier.isSigningRelated(ze.getName())) {
+                        continue;
+                    }
+                    entry = jar.newEntry(ze);
+                    return true;
+                }
+                if (signers == null) {
+                    signers = Collections.enumeration(map.keySet());
+                }
+                while (signers.hasMoreElements()) {
+                    String name = signers.nextElement();
+                    entry = jar.newEntry(new ZipEntry(name));
+                    return true;
+                }
+
+                // Any map entries left?
+                return false;
+            }
+
+            public JarEntry nextElement() {
+                if (hasMoreElements()) {
+                    JarEntry je = entry;
+                    map.remove(je.getName());
+                    entry = null;
+                    return je;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+    private Enumeration<String> emptyEnumeration = new Enumeration<String>() {
+
+        public boolean hasMoreElements() {
+            return false;
+        }
+
+        public String nextElement() {
+            throw new NoSuchElementException();
+        }
+    };
+
+    // true if file is part of the signature mechanism itself
+    static boolean isSigningRelated(String name) {
+        return SignatureFileVerifier.isSigningRelated(name);
+    }
+
+    private Enumeration<String> unsignedEntryNames(JarFile jar) {
+        final Map<String, CodeSigner[]> map = signerMap();
+        final Enumeration<JarEntry> entries = jar.entries();
+        return new Enumeration<String>() {
+
+            String name;
+
+            /*
+             * Grab entries from ZIP directory but screen out
+             * metadata.
+             */
+            public boolean hasMoreElements() {
+                if (name != null) {
+                    return true;
+                }
+                while (entries.hasMoreElements()) {
+                    String value;
+                    ZipEntry e = entries.nextElement();
+                    value = e.getName();
+                    if (e.isDirectory() || isSigningRelated(value)) {
+                        continue;
+                    }
+                    if (map.get(value) == null) {
+                        name = value;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            public String nextElement() {
+                if (hasMoreElements()) {
+                    String value = name;
+                    name = null;
+                    return value;
+                }
+                throw new NoSuchElementException();
+            }
+        };
+    }
+    private List<CodeSigner[]> jarCodeSigners;
+
+    private synchronized List<CodeSigner[]> getJarCodeSigners() {
+        CodeSigner[] signers;
+        if (jarCodeSigners == null) {
+            HashSet<CodeSigner[]> set = new HashSet<>();
+            set.addAll(signerMap().values());
+            jarCodeSigners = new ArrayList<>();
+            jarCodeSigners.addAll(set);
+        }
+        return jarCodeSigners;
+    }
+
+    public synchronized CodeSource[] getCodeSources(JarFile jar, URL url) {
+        boolean hasUnsigned = unsignedEntryNames(jar).hasMoreElements();
+
+        return mapSignersToCodeSources(url, getJarCodeSigners(), hasUnsigned);
+    }
+
+    public CodeSource getCodeSource(URL url, String name) {
+        CodeSigner[] signers;
+
+        signers = signerMap().get(name);
+        return mapSignersToCodeSource(url, signers);
+    }
+
+    public CodeSource getCodeSource(URL url, JarFile jar, JarEntry je) {
+        CodeSigner[] signers;
+
+        return mapSignersToCodeSource(url, getCodeSigners(jar, je));
+    }
+
+    public void setEagerValidation(boolean eager) {
+        eagerValidation = eager;
+    }
+
+    public synchronized List<Object> getManifestDigests() {
+        return Collections.unmodifiableList(manifestDigests);
+    }
+
+    static CodeSource getUnsignedCS(URL url) {
+        return new VerifierCodeSource(null, url, (java.security.cert.Certificate[]) null);
+    }
+}
diff --git a/java/util/jar/Manifest.java b/java/util/jar/Manifest.java
new file mode 100644
index 0000000..976e44c
--- /dev/null
+++ b/java/util/jar/Manifest.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.jar;
+
+import java.io.FilterInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * The Manifest class is used to maintain Manifest entry names and their
+ * associated Attributes. There are main Manifest Attributes as well as
+ * per-entry Attributes. For information on the Manifest format, please
+ * see the
+ * <a href="../../../../technotes/guides/jar/jar.html">
+ * Manifest format specification</a>.
+ *
+ * @author  David Connelly
+ * @see     Attributes
+ * @since   1.2
+ */
+public class Manifest implements Cloneable {
+    // manifest main attributes
+    private Attributes attr = new Attributes();
+
+    // manifest entries
+    private Map<String, Attributes> entries = new HashMap<>();
+
+    /**
+     * Constructs a new, empty Manifest.
+     */
+    public Manifest() {
+    }
+
+    /**
+     * Constructs a new Manifest from the specified input stream.
+     *
+     * @param is the input stream containing manifest data
+     * @throws IOException if an I/O error has occurred
+     */
+    public Manifest(InputStream is) throws IOException {
+        read(is);
+    }
+
+    /**
+     * Constructs a new Manifest that is a copy of the specified Manifest.
+     *
+     * @param man the Manifest to copy
+     */
+    public Manifest(Manifest man) {
+        attr.putAll(man.getMainAttributes());
+        entries.putAll(man.getEntries());
+    }
+
+    /**
+     * Returns the main Attributes for the Manifest.
+     * @return the main Attributes for the Manifest
+     */
+    public Attributes getMainAttributes() {
+        return attr;
+    }
+
+    /**
+     * Returns a Map of the entries contained in this Manifest. Each entry
+     * is represented by a String name (key) and associated Attributes (value).
+     * The Map permits the {@code null} key, but no entry with a null key is
+     * created by {@link #read}, nor is such an entry written by using {@link
+     * #write}.
+     *
+     * @return a Map of the entries contained in this Manifest
+     */
+    public Map<String,Attributes> getEntries() {
+        return entries;
+    }
+
+    /**
+     * Returns the Attributes for the specified entry name.
+     * This method is defined as:
+     * <pre>
+     *      return (Attributes)getEntries().get(name)
+     * </pre>
+     * Though {@code null} is a valid {@code name}, when
+     * {@code getAttributes(null)} is invoked on a {@code Manifest}
+     * obtained from a jar file, {@code null} will be returned.  While jar
+     * files themselves do not allow {@code null}-named attributes, it is
+     * possible to invoke {@link #getEntries} on a {@code Manifest}, and
+     * on that result, invoke {@code put} with a null key and an
+     * arbitrary value.  Subsequent invocations of
+     * {@code getAttributes(null)} will return the just-{@code put}
+     * value.
+     * <p>
+     * Note that this method does not return the manifest's main attributes;
+     * see {@link #getMainAttributes}.
+     *
+     * @param name entry name
+     * @return the Attributes for the specified entry name
+     */
+    public Attributes getAttributes(String name) {
+        return getEntries().get(name);
+    }
+
+    /**
+     * Clears the main Attributes as well as the entries in this Manifest.
+     */
+    public void clear() {
+        attr.clear();
+        entries.clear();
+    }
+
+    /**
+     * Writes the Manifest to the specified OutputStream.
+     * Attributes.Name.MANIFEST_VERSION must be set in
+     * MainAttributes prior to invoking this method.
+     *
+     * @param out the output stream
+     * @exception IOException if an I/O error has occurred
+     * @see #getMainAttributes
+     */
+    public void write(OutputStream out) throws IOException {
+        DataOutputStream dos = new DataOutputStream(out);
+        // Write out the main attributes for the manifest
+        attr.writeMain(dos);
+        // Now write out the pre-entry attributes
+        Iterator<Map.Entry<String, Attributes>> it = entries.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<String, Attributes> e = it.next();
+            StringBuffer buffer = new StringBuffer("Name: ");
+            String value = e.getKey();
+            if (value != null) {
+                byte[] vb = value.getBytes("UTF8");
+                value = new String(vb, 0, 0, vb.length);
+            }
+            buffer.append(value);
+            buffer.append("\r\n");
+            make72Safe(buffer);
+            dos.writeBytes(buffer.toString());
+            e.getValue().write(dos);
+        }
+        dos.flush();
+    }
+
+    /**
+     * Adds line breaks to enforce a maximum 72 bytes per line.
+     */
+    static void make72Safe(StringBuffer line) {
+        int length = line.length();
+        if (length > 72) {
+            int index = 70;
+            while (index < length - 2) {
+                line.insert(index, "\r\n ");
+                index += 72;
+                length += 3;
+            }
+        }
+        return;
+    }
+
+    /**
+     * Reads the Manifest from the specified InputStream. The entry
+     * names and attributes read will be merged in with the current
+     * manifest entries.
+     *
+     * @param is the input stream
+     * @exception IOException if an I/O error has occurred
+     */
+    public void read(InputStream is) throws IOException {
+        // Buffered input stream for reading manifest data
+        FastInputStream fis = new FastInputStream(is);
+        // Line buffer
+        byte[] lbuf = new byte[512];
+        // Read the main attributes for the manifest
+        attr.read(fis, lbuf);
+        // Total number of entries, attributes read
+        int ecount = 0, acount = 0;
+        // Average size of entry attributes
+        int asize = 2;
+        // Now parse the manifest entries
+        int len;
+        String name = null;
+        boolean skipEmptyLines = true;
+        byte[] lastline = null;
+
+        while ((len = fis.readLine(lbuf)) != -1) {
+            if (lbuf[--len] != '\n') {
+                throw new IOException("manifest line too long");
+            }
+            if (len > 0 && lbuf[len-1] == '\r') {
+                --len;
+            }
+            if (len == 0 && skipEmptyLines) {
+                continue;
+            }
+            skipEmptyLines = false;
+
+            if (name == null) {
+                name = parseName(lbuf, len);
+                if (name == null) {
+                    throw new IOException("invalid manifest format");
+                }
+                if (fis.peek() == ' ') {
+                    // name is wrapped
+                    lastline = new byte[len - 6];
+                    System.arraycopy(lbuf, 6, lastline, 0, len - 6);
+                    continue;
+                }
+            } else {
+                // continuation line
+                byte[] buf = new byte[lastline.length + len - 1];
+                System.arraycopy(lastline, 0, buf, 0, lastline.length);
+                System.arraycopy(lbuf, 1, buf, lastline.length, len - 1);
+                if (fis.peek() == ' ') {
+                    // name is wrapped
+                    lastline = buf;
+                    continue;
+                }
+                name = new String(buf, 0, buf.length, "UTF8");
+                lastline = null;
+            }
+            Attributes attr = getAttributes(name);
+            if (attr == null) {
+                attr = new Attributes(asize);
+                entries.put(name, attr);
+            }
+            attr.read(fis, lbuf);
+            ecount++;
+            acount += attr.size();
+            //XXX: Fix for when the average is 0. When it is 0,
+            // you get an Attributes object with an initial
+            // capacity of 0, which tickles a bug in HashMap.
+            asize = Math.max(2, acount / ecount);
+
+            name = null;
+            skipEmptyLines = true;
+        }
+    }
+
+    private String parseName(byte[] lbuf, int len) {
+        if (toLower(lbuf[0]) == 'n' && toLower(lbuf[1]) == 'a' &&
+            toLower(lbuf[2]) == 'm' && toLower(lbuf[3]) == 'e' &&
+            lbuf[4] == ':' && lbuf[5] == ' ') {
+            try {
+                return new String(lbuf, 6, len - 6, "UTF8");
+            }
+            catch (Exception e) {
+            }
+        }
+        return null;
+    }
+
+    private int toLower(int c) {
+        return (c >= 'A' && c <= 'Z') ? 'a' + (c - 'A') : c;
+    }
+
+    /**
+     * Returns true if the specified Object is also a Manifest and has
+     * the same main Attributes and entries.
+     *
+     * @param o the object to be compared
+     * @return true if the specified Object is also a Manifest and has
+     * the same main Attributes and entries
+     */
+    public boolean equals(Object o) {
+        if (o instanceof Manifest) {
+            Manifest m = (Manifest)o;
+            return attr.equals(m.getMainAttributes()) &&
+                   entries.equals(m.getEntries());
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns the hash code for this Manifest.
+     */
+    public int hashCode() {
+        return attr.hashCode() + entries.hashCode();
+    }
+
+    /**
+     * Returns a shallow copy of this Manifest.  The shallow copy is
+     * implemented as follows:
+     * <pre>
+     *     public Object clone() { return new Manifest(this); }
+     * </pre>
+     * @return a shallow copy of this Manifest
+     */
+    public Object clone() {
+        return new Manifest(this);
+    }
+
+    /*
+     * A fast buffered input stream for parsing manifest files.
+     */
+    static class FastInputStream extends FilterInputStream {
+        private byte buf[];
+        private int count = 0;
+        private int pos = 0;
+
+        FastInputStream(InputStream in) {
+            this(in, 8192);
+        }
+
+        FastInputStream(InputStream in, int size) {
+            super(in);
+            buf = new byte[size];
+        }
+
+        public int read() throws IOException {
+            if (pos >= count) {
+                fill();
+                if (pos >= count) {
+                    return -1;
+                }
+            }
+            return Byte.toUnsignedInt(buf[pos++]);
+        }
+
+        public int read(byte[] b, int off, int len) throws IOException {
+            int avail = count - pos;
+            if (avail <= 0) {
+                if (len >= buf.length) {
+                    return in.read(b, off, len);
+                }
+                fill();
+                avail = count - pos;
+                if (avail <= 0) {
+                    return -1;
+                }
+            }
+            if (len > avail) {
+                len = avail;
+            }
+            System.arraycopy(buf, pos, b, off, len);
+            pos += len;
+            return len;
+        }
+
+        /*
+         * Reads 'len' bytes from the input stream, or until an end-of-line
+         * is reached. Returns the number of bytes read.
+         */
+        public int readLine(byte[] b, int off, int len) throws IOException {
+            byte[] tbuf = this.buf;
+            int total = 0;
+            while (total < len) {
+                int avail = count - pos;
+                if (avail <= 0) {
+                    fill();
+                    avail = count - pos;
+                    if (avail <= 0) {
+                        return -1;
+                    }
+                }
+                int n = len - total;
+                if (n > avail) {
+                    n = avail;
+                }
+                int tpos = pos;
+                int maxpos = tpos + n;
+                while (tpos < maxpos && tbuf[tpos++] != '\n') ;
+                n = tpos - pos;
+                System.arraycopy(tbuf, pos, b, off, n);
+                off += n;
+                total += n;
+                pos = tpos;
+                if (tbuf[tpos-1] == '\n') {
+                    break;
+                }
+            }
+            return total;
+        }
+
+        public byte peek() throws IOException {
+            if (pos == count)
+                fill();
+            if (pos == count)
+                return -1; // nothing left in buffer
+            return buf[pos];
+        }
+
+        public int readLine(byte[] b) throws IOException {
+            return readLine(b, 0, b.length);
+        }
+
+        public long skip(long n) throws IOException {
+            if (n <= 0) {
+                return 0;
+            }
+            long avail = count - pos;
+            if (avail <= 0) {
+                return in.skip(n);
+            }
+            if (n > avail) {
+                n = avail;
+            }
+            pos += n;
+            return n;
+        }
+
+        public int available() throws IOException {
+            return (count - pos) + in.available();
+        }
+
+        public void close() throws IOException {
+            if (in != null) {
+                in.close();
+                in = null;
+                buf = null;
+            }
+        }
+
+        private void fill() throws IOException {
+            count = pos = 0;
+            int n = in.read(buf, 0, buf.length);
+            if (n > 0) {
+                count = n;
+            }
+        }
+    }
+}
diff --git a/java/util/jar/Pack200.java b/java/util/jar/Pack200.java
new file mode 100644
index 0000000..9211f0a
--- /dev/null
+++ b/java/util/jar/Pack200.java
@@ -0,0 +1,825 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.jar;
+
+import java.util.SortedMap;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.beans.PropertyChangeListener;
+
+
+
+
+/**
+ * Transforms a JAR file to or from a packed stream in Pack200 format.
+ * Please refer to Network Transfer Format JSR 200 Specification at
+ * <a href=http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html>http://jcp.org/aboutJava/communityprocess/review/jsr200/index.html</a>
+ * <p>
+ * Typically the packer engine is used by application developers
+ * to deploy or host JAR files on a website.
+ * The unpacker  engine is used by deployment applications to
+ * transform the byte-stream back to JAR format.
+ * <p>
+ * Here is an example using  packer and unpacker:
+ * <pre>{@code
+ *    import java.util.jar.Pack200;
+ *    import java.util.jar.Pack200.*;
+ *    ...
+ *    // Create the Packer object
+ *    Packer packer = Pack200.newPacker();
+ *
+ *    // Initialize the state by setting the desired properties
+ *    Map p = packer.properties();
+ *    // take more time choosing codings for better compression
+ *    p.put(Packer.EFFORT, "7");  // default is "5"
+ *    // use largest-possible archive segments (>10% better compression).
+ *    p.put(Packer.SEGMENT_LIMIT, "-1");
+ *    // reorder files for better compression.
+ *    p.put(Packer.KEEP_FILE_ORDER, Packer.FALSE);
+ *    // smear modification times to a single value.
+ *    p.put(Packer.MODIFICATION_TIME, Packer.LATEST);
+ *    // ignore all JAR deflation requests,
+ *    // transmitting a single request to use "store" mode.
+ *    p.put(Packer.DEFLATE_HINT, Packer.FALSE);
+ *    // discard debug attributes
+ *    p.put(Packer.CODE_ATTRIBUTE_PFX+"LineNumberTable", Packer.STRIP);
+ *    // throw an error if an attribute is unrecognized
+ *    p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR);
+ *    // pass one class file uncompressed:
+ *    p.put(Packer.PASS_FILE_PFX+0, "mutants/Rogue.class");
+ *    try {
+ *        JarFile jarFile = new JarFile("/tmp/testref.jar");
+ *        FileOutputStream fos = new FileOutputStream("/tmp/test.pack");
+ *        // Call the packer
+ *        packer.pack(jarFile, fos);
+ *        jarFile.close();
+ *        fos.close();
+ *
+ *        File f = new File("/tmp/test.pack");
+ *        FileOutputStream fostream = new FileOutputStream("/tmp/test.jar");
+ *        JarOutputStream jostream = new JarOutputStream(fostream);
+ *        Unpacker unpacker = Pack200.newUnpacker();
+ *        // Call the unpacker
+ *        unpacker.unpack(f, jostream);
+ *        // Must explicitly close the output.
+ *        jostream.close();
+ *    } catch (IOException ioe) {
+ *        ioe.printStackTrace();
+ *    }
+ * }</pre>
+ * <p>
+ * A Pack200 file compressed with gzip can be hosted on HTTP/1.1 web servers.
+ * The deployment applications can use "Accept-Encoding=pack200-gzip". This
+ * indicates to the server that the client application desires a version of
+ * the file encoded with Pack200 and further compressed with gzip. Please
+ * refer to  <a href="{@docRoot}/../technotes/guides/deployment/deployment-guide/pack200.html">Java Deployment Guide</a> for more details and
+ * techniques.
+ * <p>
+ * Unless otherwise noted, passing a <tt>null</tt> argument to a constructor or
+ * method in this class will cause a {@link NullPointerException} to be thrown.
+ *
+ * @author John Rose
+ * @author Kumar Srinivasan
+ * @since 1.5
+ */
+public abstract class Pack200 {
+    private Pack200() {} //prevent instantiation
+
+    // Static methods of the Pack200 class.
+    /**
+     * Obtain new instance of a class that implements Packer.
+     * <ul>
+     * <li><p>If the system property <tt>java.util.jar.Pack200.Packer</tt>
+     * is defined, then the value is taken to be the fully-qualified name
+     * of a concrete implementation class, which must implement Packer.
+     * This class is loaded and instantiated.  If this process fails
+     * then an unspecified error is thrown.</p></li>
+     *
+     * <li><p>If an implementation has not been specified with the system
+     * property, then the system-default implementation class is instantiated,
+     * and the result is returned.</p></li>
+     * </ul>
+     *
+     * <p>Note:  The returned object is not guaranteed to operate
+     * correctly if multiple threads use it at the same time.
+     * A multi-threaded application should either allocate multiple
+     * packer engines, or else serialize use of one engine with a lock.
+     *
+     * @return  A newly allocated Packer engine.
+     */
+    public synchronized static Packer newPacker() {
+        return (Packer) newInstance(PACK_PROVIDER);
+    }
+
+
+    /**
+     * Obtain new instance of a class that implements Unpacker.
+     * <ul>
+     * <li><p>If the system property <tt>java.util.jar.Pack200.Unpacker</tt>
+     * is defined, then the value is taken to be the fully-qualified
+     * name of a concrete implementation class, which must implement Unpacker.
+     * The class is loaded and instantiated.  If this process fails
+     * then an unspecified error is thrown.</p></li>
+     *
+     * <li><p>If an implementation has not been specified with the
+     * system property, then the system-default implementation class
+     * is instantiated, and the result is returned.</p></li>
+     * </ul>
+     *
+     * <p>Note:  The returned object is not guaranteed to operate
+     * correctly if multiple threads use it at the same time.
+     * A multi-threaded application should either allocate multiple
+     * unpacker engines, or else serialize use of one engine with a lock.
+     *
+     * @return  A newly allocated Unpacker engine.
+     */
+
+    public static Unpacker newUnpacker() {
+        return (Unpacker) newInstance(UNPACK_PROVIDER);
+    }
+
+    // Interfaces
+    /**
+     * The packer engine applies various transformations to the input JAR file,
+     * making the pack stream highly compressible by a compressor such as
+     * gzip or zip. An instance of the engine can be obtained
+     * using {@link #newPacker}.
+
+     * The high degree of compression is achieved
+     * by using a number of techniques described in the JSR 200 specification.
+     * Some of the techniques are sorting, re-ordering and co-location of the
+     * constant pool.
+     * <p>
+     * The pack engine is initialized to an initial state as described
+     * by their properties below.
+     * The initial state can be manipulated by getting the
+     * engine properties (using {@link #properties}) and storing
+     * the modified properties on the map.
+     * The resource files will be passed through with no changes at all.
+     * The class files will not contain identical bytes, since the unpacker
+     * is free to change minor class file features such as constant pool order.
+     * However, the class files will be semantically identical,
+     * as specified in
+     * <cite>The Java&trade; Virtual Machine Specification</cite>.
+     * <p>
+     * By default, the packer does not change the order of JAR elements.
+     * Also, the modification time and deflation hint of each
+     * JAR element is passed unchanged.
+     * (Any other ZIP-archive information, such as extra attributes
+     * giving Unix file permissions, are lost.)
+     * <p>
+     * Note that packing and unpacking a JAR will in general alter the
+     * bytewise contents of classfiles in the JAR.  This means that packing
+     * and unpacking will in general invalidate any digital signatures
+     * which rely on bytewise images of JAR elements.  In order both to sign
+     * and to pack a JAR, you must first pack and unpack the JAR to
+     * "normalize" it, then compute signatures on the unpacked JAR elements,
+     * and finally repack the signed JAR.
+     * Both packing steps should
+     * use precisely the same options, and the segment limit may also
+     * need to be set to "-1", to prevent accidental variation of segment
+     * boundaries as class file sizes change slightly.
+     * <p>
+     * (Here's why this works:  Any reordering the packer does
+     * of any classfile structures is idempotent, so the second packing
+     * does not change the orderings produced by the first packing.
+     * Also, the unpacker is guaranteed by the JSR 200 specification
+     * to produce a specific bytewise image for any given transmission
+     * ordering of archive elements.)
+     * <p>
+     * In order to maintain backward compatibility, the pack file's version is
+     * set to accommodate the class files present in the input JAR file. In
+     * other words, the pack file version will be the latest, if the class files
+     * are the latest and conversely the pack file version will be the oldest
+     * if the class file versions are also the oldest. For intermediate class
+     * file versions the corresponding pack file version will be used.
+     * For example:
+     *    If the input JAR-files are solely comprised of 1.5  (or  lesser)
+     * class files, a 1.5 compatible pack file is  produced. This will also be
+     * the case for archives that have no class files.
+     *    If the input JAR-files contains a 1.6 class file, then the pack file
+     * version will be set to 1.6.
+     * <p>
+     * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
+     * constructor or method in this class will cause a {@link NullPointerException}
+     * to be thrown.
+     * <p>
+     * @since 1.5
+     */
+    public interface Packer {
+        /**
+         * This property is a numeral giving the estimated target size N
+         * (in bytes) of each archive segment.
+         * If a single input file requires more than N bytes,
+         * it will be given its own archive segment.
+         * <p>
+         * As a special case, a value of -1 will produce a single large
+         * segment with all input files, while a value of 0 will
+         * produce one segment for each class.
+         * Larger archive segments result in less fragmentation and
+         * better compression, but processing them requires more memory.
+         * <p>
+         * The size of each segment is estimated by counting the size of each
+         * input file to be transmitted in the segment, along with the size
+         * of its name and other transmitted properties.
+         * <p>
+         * The default is -1, which means the packer will always create a single
+         * segment output file. In cases where extremely large output files are
+         * generated, users are strongly encouraged to use segmenting or break
+         * up the input file into smaller JARs.
+         * <p>
+         * A 10Mb JAR packed without this limit will
+         * typically pack about 10% smaller, but the packer may require
+         * a larger Java heap (about ten times the segment limit).
+         */
+        String SEGMENT_LIMIT    = "pack.segment.limit";
+
+        /**
+         * If this property is set to {@link #TRUE}, the packer will transmit
+         * all elements in their original order within the source archive.
+         * <p>
+         * If it is set to {@link #FALSE}, the packer may reorder elements,
+         * and also remove JAR directory entries, which carry no useful
+         * information for Java applications.
+         * (Typically this enables better compression.)
+         * <p>
+         * The default is {@link #TRUE}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         */
+        String KEEP_FILE_ORDER = "pack.keep.file.order";
+
+
+        /**
+         * If this property is set to a single decimal digit, the packer will
+         * use the indicated amount of effort in compressing the archive.
+         * Level 1 may produce somewhat larger size and faster compression speed,
+         * while level 9 will take much longer but may produce better compression.
+         * <p>
+         * The special value 0 instructs the packer to copy through the
+         * original JAR file directly, with no compression.  The JSR 200
+         * standard requires any unpacker to understand this special case
+         * as a pass-through of the entire archive.
+         * <p>
+         * The default is 5, investing a modest amount of time to
+         * produce reasonable compression.
+         */
+        String EFFORT           = "pack.effort";
+
+        /**
+         * If this property is set to {@link #TRUE} or {@link #FALSE}, the packer
+         * will set the deflation hint accordingly in the output archive, and
+         * will not transmit the individual deflation hints of archive elements.
+         * <p>
+         * If this property is set to the special string {@link #KEEP}, the packer
+         * will attempt to determine an independent deflation hint for each
+         * available element of the input archive, and transmit this hint separately.
+         * <p>
+         * The default is {@link #KEEP}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         * <p>
+         * It is up to the unpacker implementation
+         * to take action upon the hint to suitably compress the elements of
+         * the resulting unpacked jar.
+         * <p>
+         * The deflation hint of a ZIP or JAR element indicates
+         * whether the element was deflated or stored directly.
+         */
+        String DEFLATE_HINT     = "pack.deflate.hint";
+
+        /**
+         * If this property is set to the special string {@link #LATEST},
+         * the packer will attempt to determine the latest modification time,
+         * among all the available entries in the original archive or the latest
+         * modification time of all the available entries in each segment.
+         * This single value will be transmitted as part of the segment and applied
+         * to all the entries in each segment, {@link #SEGMENT_LIMIT}.
+         * <p>
+         * This can marginally decrease the transmitted size of the
+         * archive, at the expense of setting all installed files to a single
+         * date.
+         * <p>
+         * If this property is set to the special string {@link #KEEP},
+         * the packer transmits a separate modification time for each input
+         * element.
+         * <p>
+         * The default is {@link #KEEP}, which preserves the input information,
+         * but may cause the transmitted archive to be larger than necessary.
+         * <p>
+         * It is up to the unpacker implementation to take action to suitably
+         * set the modification time of each element of its output file.
+         * @see #SEGMENT_LIMIT
+         */
+        String MODIFICATION_TIME        = "pack.modification.time";
+
+        /**
+         * Indicates that a file should be passed through bytewise, with no
+         * compression.  Multiple files may be specified by specifying
+         * additional properties with distinct strings appended, to
+         * make a family of properties with the common prefix.
+         * <p>
+         * There is no pathname transformation, except
+         * that the system file separator is replaced by the JAR file
+         * separator '/'.
+         * <p>
+         * The resulting file names must match exactly as strings with their
+         * occurrences in the JAR file.
+         * <p>
+         * If a property value is a directory name, all files under that
+         * directory will be passed also.
+         * <p>
+         * Examples:
+         * <pre>{@code
+         *     Map p = packer.properties();
+         *     p.put(PASS_FILE_PFX+0, "mutants/Rogue.class");
+         *     p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class");
+         *     p.put(PASS_FILE_PFX+2, "mutants/Storm.class");
+         *     # Pass all files in an entire directory hierarchy:
+         *     p.put(PASS_FILE_PFX+3, "police/");
+         * }</pre>
+         */
+        String PASS_FILE_PFX            = "pack.pass.file.";
+
+        /// Attribute control.
+
+        /**
+         * Indicates the action to take when a class-file containing an unknown
+         * attribute is encountered.  Possible values are the strings {@link #ERROR},
+         * {@link #STRIP}, and {@link #PASS}.
+         * <p>
+         * The string {@link #ERROR} means that the pack operation
+         * as a whole will fail, with an exception of type <code>IOException</code>.
+         * The string
+         * {@link #STRIP} means that the attribute will be dropped.
+         * The string
+         * {@link #PASS} means that the whole class-file will be passed through
+         * (as if it were a resource file) without compression, with  a suitable warning.
+         * This is the default value for this property.
+         * <p>
+         * Examples:
+         * <pre>{@code
+         *     Map p = pack200.getProperties();
+         *     p.put(UNKNOWN_ATTRIBUTE, ERROR);
+         *     p.put(UNKNOWN_ATTRIBUTE, STRIP);
+         *     p.put(UNKNOWN_ATTRIBUTE, PASS);
+         * }</pre>
+         */
+        String UNKNOWN_ATTRIBUTE        = "pack.unknown.attribute";
+
+        /**
+         * When concatenated with a class attribute name,
+         * indicates the format of that attribute,
+         * using the layout language specified in the JSR 200 specification.
+         * <p>
+         * For example, the effect of this option is built in:
+         * <code>pack.class.attribute.SourceFile=RUH</code>.
+         * <p>
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} are
+         * also allowed, with the same meaning as {@link #UNKNOWN_ATTRIBUTE}.
+         * This provides a way for users to request that specific attributes be
+         * refused, stripped, or passed bitwise (with no class compression).
+         * <p>
+         * Code like this might be used to support attributes for JCOV:
+         * <pre><code>
+         *     Map p = packer.properties();
+         *     p.put(CODE_ATTRIBUTE_PFX+"CoverageTable",       "NH[PHHII]");
+         *     p.put(CODE_ATTRIBUTE_PFX+"CharacterRangeTable", "NH[PHPOHIIH]");
+         *     p.put(CLASS_ATTRIBUTE_PFX+"SourceID",           "RUH");
+         *     p.put(CLASS_ATTRIBUTE_PFX+"CompilationID",      "RUH");
+         * </code></pre>
+         * <p>
+         * Code like this might be used to strip debugging attributes:
+         * <pre><code>
+         *     Map p = packer.properties();
+         *     p.put(CODE_ATTRIBUTE_PFX+"LineNumberTable",    STRIP);
+         *     p.put(CODE_ATTRIBUTE_PFX+"LocalVariableTable", STRIP);
+         *     p.put(CLASS_ATTRIBUTE_PFX+"SourceFile",        STRIP);
+         * </code></pre>
+         */
+        String CLASS_ATTRIBUTE_PFX      = "pack.class.attribute.";
+
+        /**
+         * When concatenated with a field attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.field.attribute.Deprecated=</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and
+         * {@link #PASS} are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String FIELD_ATTRIBUTE_PFX      = "pack.field.attribute.";
+
+        /**
+         * When concatenated with a method attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.method.attribute.Exceptions=NH[RCH]</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
+         * are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String METHOD_ATTRIBUTE_PFX     = "pack.method.attribute.";
+
+        /**
+         * When concatenated with a code attribute name,
+         * indicates the format of that attribute.
+         * For example, the effect of this option is built in:
+         * <code>pack.code.attribute.LocalVariableTable=NH[PHOHRUHRSHH]</code>.
+         * The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
+         * are also allowed.
+         * @see #CLASS_ATTRIBUTE_PFX
+         */
+        String CODE_ATTRIBUTE_PFX       = "pack.code.attribute.";
+
+        /**
+         * The unpacker's progress as a percentage, as periodically
+         * updated by the unpacker.
+         * Values of 0 - 100 are normal, and -1 indicates a stall.
+         * Progress can be monitored by polling the value of this
+         * property.
+         * <p>
+         * At a minimum, the unpacker must set progress to 0
+         * at the beginning of a packing operation, and to 100
+         * at the end.
+         */
+        String PROGRESS                 = "pack.progress";
+
+        /** The string "keep", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         * @see #MODIFICATION_TIME
+         */
+        String KEEP  = "keep";
+
+        /** The string "pass", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String PASS  = "pass";
+
+        /** The string "strip", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String STRIP = "strip";
+
+        /** The string "error", a possible value for certain properties.
+         * @see #UNKNOWN_ATTRIBUTE
+         * @see #CLASS_ATTRIBUTE_PFX
+         * @see #FIELD_ATTRIBUTE_PFX
+         * @see #METHOD_ATTRIBUTE_PFX
+         * @see #CODE_ATTRIBUTE_PFX
+         */
+        String ERROR = "error";
+
+        /** The string "true", a possible value for certain properties.
+         * @see #KEEP_FILE_ORDER
+         * @see #DEFLATE_HINT
+         */
+        String TRUE = "true";
+
+        /** The string "false", a possible value for certain properties.
+         * @see #KEEP_FILE_ORDER
+         * @see #DEFLATE_HINT
+         */
+        String FALSE = "false";
+
+        /** The string "latest", a possible value for certain properties.
+         * @see #MODIFICATION_TIME
+         */
+        String LATEST = "latest";
+
+        /**
+         * Get the set of this engine's properties.
+         * This set is a "live view", so that changing its
+         * contents immediately affects the Packer engine, and
+         * changes from the engine (such as progress indications)
+         * are immediately visible in the map.
+         *
+         * <p>The property map may contain pre-defined implementation
+         * specific and default properties.  Users are encouraged to
+         * read the information and fully understand the implications,
+         * before modifying pre-existing properties.
+         * <p>
+         * Implementation specific properties are prefixed with a
+         * package name associated with the implementor, beginning
+         * with <tt>com.</tt> or a similar prefix.
+         * All property names beginning with <tt>pack.</tt> and
+         * <tt>unpack.</tt> are reserved for use by this API.
+         * <p>
+         * Unknown properties may be ignored or rejected with an
+         * unspecified error, and invalid entries may cause an
+         * unspecified error to be thrown.
+         *
+         * <p>
+         * The returned map implements all optional {@link SortedMap} operations
+         * @return A sorted association of property key strings to property
+         * values.
+         */
+        SortedMap<String,String> properties();
+
+        /**
+         * Takes a JarFile and converts it into a Pack200 archive.
+         * <p>
+         * Closes its input but not its output.  (Pack200 archives are appendable.)
+         * @param in a JarFile
+         * @param out an OutputStream
+         * @exception IOException if an error is encountered.
+         */
+        void pack(JarFile in, OutputStream out) throws IOException ;
+
+        /**
+         * Takes a JarInputStream and converts it into a Pack200 archive.
+         * <p>
+         * Closes its input but not its output.  (Pack200 archives are appendable.)
+         * <p>
+         * The modification time and deflation hint attributes are not available,
+         * for the JAR manifest file and its containing directory.
+         *
+         * @see #MODIFICATION_TIME
+         * @see #DEFLATE_HINT
+         * @param in a JarInputStream
+         * @param out an OutputStream
+         * @exception IOException if an error is encountered.
+         */
+        void pack(JarInputStream in, OutputStream out) throws IOException ;
+
+        /**
+         * Registers a listener for PropertyChange events on the properties map.
+         * This is typically used by applications to update a progress bar.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+
+         * @see #properties
+         * @see #PROGRESS
+         * @param listener  An object to be invoked when a property is changed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         *             Applications that need to monitor progress of the packer
+         *             can poll the value of the {@link #PROGRESS PROGRESS}
+         *             property instead.
+         */
+        @Deprecated
+        default void addPropertyChangeListener(PropertyChangeListener listener) {
+        }
+
+        /**
+         * Remove a listener for PropertyChange events, added by
+         * the {@link #addPropertyChangeListener}.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #addPropertyChangeListener
+         * @param listener  The PropertyChange listener to be removed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         */
+        @Deprecated
+        default void removePropertyChangeListener(PropertyChangeListener listener) {
+        }
+    }
+
+    /**
+     * The unpacker engine converts the packed stream to a JAR file.
+     * An instance of the engine can be obtained
+     * using {@link #newUnpacker}.
+     * <p>
+     * Every JAR file produced by this engine will include the string
+     * "<tt>PACK200</tt>" as a zip file comment.
+     * This allows a deployer to detect if a JAR archive was packed and unpacked.
+     * <p>
+     * Note: Unless otherwise noted, passing a <tt>null</tt> argument to a
+     * constructor or method in this class will cause a {@link NullPointerException}
+     * to be thrown.
+     * <p>
+     * This version of the unpacker is compatible with all previous versions.
+     * @since 1.5
+     */
+    public interface Unpacker {
+
+        /** The string "keep", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String KEEP  = "keep";
+
+        /** The string "true", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String TRUE = "true";
+
+        /** The string "false", a possible value for certain properties.
+         * @see #DEFLATE_HINT
+         */
+        String FALSE = "false";
+
+        /**
+         * Property indicating that the unpacker should
+         * ignore all transmitted values for DEFLATE_HINT,
+         * replacing them by the given value, {@link #TRUE} or {@link #FALSE}.
+         * The default value is the special string {@link #KEEP},
+         * which asks the unpacker to preserve all transmitted
+         * deflation hints.
+         */
+        String DEFLATE_HINT      = "unpack.deflate.hint";
+
+
+
+        /**
+         * The unpacker's progress as a percentage, as periodically
+         * updated by the unpacker.
+         * Values of 0 - 100 are normal, and -1 indicates a stall.
+         * Progress can be monitored by polling the value of this
+         * property.
+         * <p>
+         * At a minimum, the unpacker must set progress to 0
+         * at the beginning of a packing operation, and to 100
+         * at the end.
+         */
+        String PROGRESS         = "unpack.progress";
+
+        /**
+         * Get the set of this engine's properties. This set is
+         * a "live view", so that changing its
+         * contents immediately affects the Packer engine, and
+         * changes from the engine (such as progress indications)
+         * are immediately visible in the map.
+         *
+         * <p>The property map may contain pre-defined implementation
+         * specific and default properties.  Users are encouraged to
+         * read the information and fully understand the implications,
+         * before modifying pre-existing properties.
+         * <p>
+         * Implementation specific properties are prefixed with a
+         * package name associated with the implementor, beginning
+         * with <tt>com.</tt> or a similar prefix.
+         * All property names beginning with <tt>pack.</tt> and
+         * <tt>unpack.</tt> are reserved for use by this API.
+         * <p>
+         * Unknown properties may be ignored or rejected with an
+         * unspecified error, and invalid entries may cause an
+         * unspecified error to be thrown.
+         *
+         * @return A sorted association of option key strings to option values.
+         */
+        SortedMap<String,String> properties();
+
+        /**
+         * Read a Pack200 archive, and write the encoded JAR to
+         * a JarOutputStream.
+         * The entire contents of the input stream will be read.
+         * It may be more efficient to read the Pack200 archive
+         * to a file and pass the File object, using the alternate
+         * method described below.
+         * <p>
+         * Closes its input but not its output.  (The output can accumulate more elements.)
+         * @param in an InputStream.
+         * @param out a JarOutputStream.
+         * @exception IOException if an error is encountered.
+         */
+        void unpack(InputStream in, JarOutputStream out) throws IOException;
+
+        /**
+         * Read a Pack200 archive, and write the encoded JAR to
+         * a JarOutputStream.
+         * <p>
+         * Does not close its output.  (The output can accumulate more elements.)
+         * @param in a File.
+         * @param out a JarOutputStream.
+         * @exception IOException if an error is encountered.
+         */
+        void unpack(File in, JarOutputStream out) throws IOException;
+
+        /**
+         * Registers a listener for PropertyChange events on the properties map.
+         * This is typically used by applications to update a progress bar.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #properties
+         * @see #PROGRESS
+         * @param listener  An object to be invoked when a property is changed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         *             Applications that need to monitor progress of the
+         *             unpacker can poll the value of the {@link #PROGRESS
+         *             PROGRESS} property instead.
+         */
+        @Deprecated
+        default void addPropertyChangeListener(PropertyChangeListener listener) {
+        }
+
+        /**
+         * Remove a listener for PropertyChange events, added by
+         * the {@link #addPropertyChangeListener}.
+         *
+         * <p> The default implementation of this method does nothing and has
+         * no side-effects.</p>
+         *
+         * <p><b>WARNING:</b> This method is omitted from the interface
+         * declaration in all subset Profiles of Java SE that do not include
+         * the {@code java.beans} package. </p>
+         *
+         * @see #addPropertyChangeListener
+         * @param listener  The PropertyChange listener to be removed.
+         * @deprecated The dependency on {@code PropertyChangeListener} creates
+         *             a significant impediment to future modularization of the
+         *             Java platform. This method will be removed in a future
+         *             release.
+         */
+        @Deprecated
+        default void removePropertyChangeListener(PropertyChangeListener listener) {
+        }
+    }
+
+    // Private stuff....
+
+    private static final String PACK_PROVIDER = "java.util.jar.Pack200.Packer";
+    private static final String UNPACK_PROVIDER = "java.util.jar.Pack200.Unpacker";
+
+    private static Class<?> packerImpl;
+    private static Class<?> unpackerImpl;
+
+    private synchronized static Object newInstance(String prop) {
+        String implName = "(unknown)";
+        try {
+            Class<?> impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
+            if (impl == null) {
+                // The first time, we must decide which class to use.
+                implName = java.security.AccessController.doPrivileged(
+                    new sun.security.action.GetPropertyAction(prop,""));
+                if (implName != null && !implName.equals(""))
+                    impl = Class.forName(implName);
+                // Android-changed: Remove default Packer Impl.
+                //
+                // else if (PACK_PROVIDER.equals(prop))
+                //     impl = com.sun.java.util.jar.pack.PackerImpl.class;
+                // else
+                //    impl = com.sun.java.util.jar.pack.UnpackerImpl.class;
+            }
+            // We have a class.  Now instantiate it.
+            return impl.newInstance();
+        } catch (ClassNotFoundException e) {
+            throw new Error("Class not found: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        } catch (InstantiationException e) {
+            throw new Error("Could not instantiate: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        } catch (IllegalAccessException e) {
+            throw new Error("Cannot access class: " + implName +
+                                ":\ncheck property " + prop +
+                                " in your properties file.", e);
+        }
+    }
+
+}
diff --git a/java/util/logging/ConsoleHandler.java b/java/util/logging/ConsoleHandler.java
new file mode 100644
index 0000000..b791547
--- /dev/null
+++ b/java/util/logging/ConsoleHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
+ * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>ConsoleHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where {@code <handler-name>}
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.INFO</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.SimpleFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code ConsoleHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.ConsoleHandler.level=INFO </li>
+ * <li>   java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+public class ConsoleHandler extends StreamHandler {
+    // Private method to configure a ConsoleHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+    /**
+     * Create a <tt>ConsoleHandler</tt> for <tt>System.err</tt>.
+     * <p>
+     * The <tt>ConsoleHandler</tt> is configured based on
+     * <tt>LogManager</tt> properties (or their default values).
+     *
+     */
+    public ConsoleHandler() {
+        sealed = false;
+        configure();
+        setOutputStream(System.err);
+        sealed = true;
+    }
+
+    /**
+     * Publish a <tt>LogRecord</tt>.
+     * <p>
+     * The logging request was made initially to a <tt>Logger</tt> object,
+     * which initialized the <tt>LogRecord</tt> and forwarded it here.
+     * <p>
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public void publish(LogRecord record) {
+        super.publish(record);
+        flush();
+    }
+
+    /**
+     * Override <tt>StreamHandler.close</tt> to do a flush but not
+     * to close the output stream.  That is, we do <b>not</b>
+     * close <tt>System.err</tt>.
+     */
+    @Override
+    public void close() {
+        flush();
+    }
+}
diff --git a/java/util/logging/ErrorManager.java b/java/util/logging/ErrorManager.java
new file mode 100644
index 0000000..1aaba4c
--- /dev/null
+++ b/java/util/logging/ErrorManager.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * ErrorManager objects can be attached to Handlers to process
+ * any error that occurs on a Handler during Logging.
+ * <p>
+ * When processing logging output, if a Handler encounters problems
+ * then rather than throwing an Exception back to the issuer of
+ * the logging call (who is unlikely to be interested) the Handler
+ * should call its associated ErrorManager.
+ */
+
+public class ErrorManager {
+   private boolean reported = false;
+
+    /*
+     * We declare standard error codes for important categories of errors.
+     */
+
+    /**
+     * GENERIC_FAILURE is used for failure that don't fit
+     * into one of the other categories.
+     */
+    public final static int GENERIC_FAILURE = 0;
+    /**
+     * WRITE_FAILURE is used when a write to an output stream fails.
+     */
+    public final static int WRITE_FAILURE = 1;
+    /**
+     * FLUSH_FAILURE is used when a flush to an output stream fails.
+     */
+    public final static int FLUSH_FAILURE = 2;
+    /**
+     * CLOSE_FAILURE is used when a close of an output stream fails.
+     */
+    public final static int CLOSE_FAILURE = 3;
+    /**
+     * OPEN_FAILURE is used when an open of an output stream fails.
+     */
+    public final static int OPEN_FAILURE = 4;
+    /**
+     * FORMAT_FAILURE is used when formatting fails for any reason.
+     */
+    public final static int FORMAT_FAILURE = 5;
+
+    /**
+     * The error method is called when a Handler failure occurs.
+     * <p>
+     * This method may be overridden in subclasses.  The default
+     * behavior in this base class is that the first call is
+     * reported to System.err, and subsequent calls are ignored.
+     *
+     * @param msg    a descriptive string (may be null)
+     * @param ex     an exception (may be null)
+     * @param code   an error code defined in ErrorManager
+     */
+    public synchronized void error(String msg, Exception ex, int code) {
+        if (reported) {
+            // We only report the first error, to avoid clogging
+            // the screen.
+            return;
+        }
+        reported = true;
+        String text = "java.util.logging.ErrorManager: " + code;
+        if (msg != null) {
+            text = text + ": " + msg;
+        }
+        System.err.println(text);
+        if (ex != null) {
+            ex.printStackTrace();
+        }
+    }
+}
diff --git a/java/util/logging/FileHandler.java b/java/util/logging/FileHandler.java
new file mode 100644
index 0000000..24a7c75
--- /dev/null
+++ b/java/util/logging/FileHandler.java
@@ -0,0 +1,746 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import static java.nio.file.StandardOpenOption.APPEND;
+import static java.nio.file.StandardOpenOption.CREATE_NEW;
+import static java.nio.file.StandardOpenOption.WRITE;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Simple file logging <tt>Handler</tt>.
+ * <p>
+ * The <tt>FileHandler</tt> can either write to a specified file,
+ * or it can write to a rotating set of files.
+ * <p>
+ * For a rotating set of files, as each file reaches a given size
+ * limit, it is closed, rotated out, and a new file opened.
+ * Successively older files are named by adding "0", "1", "2",
+ * etc. into the base filename.
+ * <p>
+ * By default buffering is enabled in the IO libraries but each log
+ * record is flushed out when it is complete.
+ * <p>
+ * By default the <tt>XMLFormatter</tt> class is used for formatting.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>FileHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.XMLFormatter</tt>) </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * <li>   &lt;handler-name&gt;.limit
+ *        specifies an approximate maximum amount to write (in bytes)
+ *        to any one file.  If this is zero, then there is no limit.
+ *        (Defaults to no limit). </li>
+ * <li>   &lt;handler-name&gt;.count
+ *        specifies how many output files to cycle through (defaults to 1). </li>
+ * <li>   &lt;handler-name&gt;.pattern
+ *        specifies a pattern for generating the output file name.  See
+ *        below for details. (Defaults to "%h/java%u.log"). </li>
+ * <li>   &lt;handler-name&gt;.append
+ *        specifies whether the FileHandler should append onto
+ *        any existing files (defaults to false). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code FileHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.FileHandler.level=INFO </li>
+ * <li>   java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * A pattern consists of a string that includes the following special
+ * components that will be replaced at runtime:
+ * <ul>
+ * <li>    "/"    the local pathname separator </li>
+ * <li>     "%t"   the system temporary directory </li>
+ * <li>     "%h"   the value of the "user.home" system property </li>
+ * <li>     "%g"   the generation number to distinguish rotated logs </li>
+ * <li>     "%u"   a unique number to resolve conflicts </li>
+ * <li>     "%%"   translates to a single percent sign "%" </li>
+ * </ul>
+ * If no "%g" field has been specified and the file count is greater
+ * than one, then the generation number will be added to the end of
+ * the generated filename, after a dot.
+ * <p>
+ * Thus for example a pattern of "%t/java%g.log" with a count of 2
+ * would typically cause log files to be written on Solaris to
+ * /var/tmp/java0.log and /var/tmp/java1.log whereas on Windows 95 they
+ * would be typically written to C:\TEMP\java0.log and C:\TEMP\java1.log
+ * <p>
+ * Generation numbers follow the sequence 0, 1, 2, etc.
+ * <p>
+ * Normally the "%u" unique field is set to 0.  However, if the <tt>FileHandler</tt>
+ * tries to open the filename and finds the file is currently in use by
+ * another process it will increment the unique number field and try
+ * again.  This will be repeated until <tt>FileHandler</tt> finds a file name that
+ * is  not currently in use. If there is a conflict and no "%u" field has
+ * been specified, it will be added at the end of the filename after a dot.
+ * (This will be after any automatically added generation number.)
+ * <p>
+ * Thus if three processes were all trying to log to fred%u.%g.txt then
+ * they  might end up using fred0.0.txt, fred1.0.txt, fred2.0.txt as
+ * the first file in their rotating sequences.
+ * <p>
+ * Note that the use of unique ids to avoid conflicts is only guaranteed
+ * to work reliably when using a local disk file system.
+ *
+ * @since 1.4
+ */
+
+public class FileHandler extends StreamHandler {
+    private MeteredStream meter;
+    private boolean append;
+    private int limit;       // zero => no limit.
+    private int count;
+    private String pattern;
+    private String lockFileName;
+    private FileChannel lockFileChannel;
+    private File files[];
+    private static final int MAX_LOCKS = 100;
+    private static final Set<String> locks = new HashSet<>();
+
+    /**
+     * A metered stream is a subclass of OutputStream that
+     * (a) forwards all its output to a target stream
+     * (b) keeps track of how many bytes have been written
+     */
+    private class MeteredStream extends OutputStream {
+        final OutputStream out;
+        int written;
+
+        MeteredStream(OutputStream out, int written) {
+            this.out = out;
+            this.written = written;
+        }
+
+        @Override
+        public void write(int b) throws IOException {
+            out.write(b);
+            written++;
+        }
+
+        @Override
+        public void write(byte buff[]) throws IOException {
+            out.write(buff);
+            written += buff.length;
+        }
+
+        @Override
+        public void write(byte buff[], int off, int len) throws IOException {
+            out.write(buff,off,len);
+            written += len;
+        }
+
+        @Override
+        public void flush() throws IOException {
+            out.flush();
+        }
+
+        @Override
+        public void close() throws IOException {
+            out.close();
+        }
+    }
+
+    private void open(File fname, boolean append) throws IOException {
+        int len = 0;
+        if (append) {
+            len = (int)fname.length();
+        }
+        FileOutputStream fout = new FileOutputStream(fname.toString(), append);
+        BufferedOutputStream bout = new BufferedOutputStream(fout);
+        meter = new MeteredStream(bout, len);
+        setOutputStream(meter);
+    }
+
+    /**
+     * Configure a FileHandler from LogManager properties and/or default values
+     * as specified in the class javadoc.
+     */
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+
+        String cname = getClass().getName();
+
+        pattern = manager.getStringProperty(cname + ".pattern", "%h/java%u.log");
+        limit = manager.getIntProperty(cname + ".limit", 0);
+        if (limit < 0) {
+            limit = 0;
+        }
+        count = manager.getIntProperty(cname + ".count", 1);
+        if (count <= 0) {
+            count = 1;
+        }
+        append = manager.getBooleanProperty(cname + ".append", false);
+        setLevel(manager.getLevelProperty(cname + ".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname + ".filter", null));
+        setFormatter(manager.getFormatterProperty(cname + ".formatter", new XMLFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+
+    /**
+     * Construct a default <tt>FileHandler</tt>.  This will be configured
+     * entirely from <tt>LogManager</tt> properties (or their default values).
+     * <p>
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control"))</tt>.
+     * @exception  NullPointerException if pattern property is an empty String.
+     */
+    public FileHandler() throws IOException, SecurityException {
+        checkPermission();
+        configure();
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to the given filename.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to no limit, and the file count is set to one.
+     * <p>
+     * There is no limit on the amount of data that may be written,
+     * so use this with care.
+     *
+     * @param pattern  the name of the output file
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern) throws IOException, SecurityException {
+        if (pattern.length() < 1 ) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = 0;
+        this.count = 1;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to the given filename,
+     * with optional append.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to no limit, the file count is set to one, and the append
+     * mode is set to the given <tt>append</tt> argument.
+     * <p>
+     * There is no limit on the amount of data that may be written,
+     * so use this with care.
+     *
+     * @param pattern  the name of the output file
+     * @param append  specifies append mode
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern, boolean append) throws IOException,
+            SecurityException {
+        if (pattern.length() < 1 ) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = 0;
+        this.count = 1;
+        this.append = append;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to a set of files.  When
+     * (approximately) the given limit has been written to one file,
+     * another file will be opened.  The output will cycle through a set
+     * of count files.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to the limit argument, and the file count is set to the
+     * given count argument.
+     * <p>
+     * The count must be at least 1.
+     *
+     * @param pattern  the pattern for naming the output file
+     * @param limit  the maximum number of bytes to write to any one file
+     * @param count  the number of files to use
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     */
+    public FileHandler(String pattern, int limit, int count)
+                                        throws IOException, SecurityException {
+        if (limit < 0 || count < 1 || pattern.length() < 1) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = limit;
+        this.count = count;
+        openFiles();
+    }
+
+    /**
+     * Initialize a <tt>FileHandler</tt> to write to a set of files
+     * with optional append.  When (approximately) the given limit has
+     * been written to one file, another file will be opened.  The
+     * output will cycle through a set of count files.
+     * <p>
+     * The <tt>FileHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given pattern
+     * argument is used as the filename pattern, the file limit is
+     * set to the limit argument, and the file count is set to the
+     * given count argument, and the append mode is set to the given
+     * <tt>append</tt> argument.
+     * <p>
+     * The count must be at least 1.
+     *
+     * @param pattern  the pattern for naming the output file
+     * @param limit  the maximum number of bytes to write to any one file
+     * @param count  the number of files to use
+     * @param append  specifies append mode
+     * @exception  IOException if there are IO problems opening the files.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  IllegalArgumentException if {@code limit < 0}, or {@code count < 1}.
+     * @exception  IllegalArgumentException if pattern is an empty string
+     *
+     */
+    public FileHandler(String pattern, int limit, int count, boolean append)
+                                        throws IOException, SecurityException {
+        if (limit < 0 || count < 1 || pattern.length() < 1) {
+            throw new IllegalArgumentException();
+        }
+        checkPermission();
+        configure();
+        this.pattern = pattern;
+        this.limit = limit;
+        this.count = count;
+        this.append = append;
+        openFiles();
+    }
+
+    private  boolean isParentWritable(Path path) {
+        Path parent = path.getParent();
+        if (parent == null) {
+            parent = path.toAbsolutePath().getParent();
+        }
+        return parent != null && Files.isWritable(parent);
+    }
+
+    /**
+     * Open the set of output files, based on the configured
+     * instance variables.
+     */
+    private void openFiles() throws IOException {
+        LogManager manager = LogManager.getLogManager();
+        manager.checkPermission();
+        if (count < 1) {
+           throw new IllegalArgumentException("file count = " + count);
+        }
+        if (limit < 0) {
+            limit = 0;
+        }
+
+        // We register our own ErrorManager during initialization
+        // so we can record exceptions.
+        InitializationErrorManager em = new InitializationErrorManager();
+        setErrorManager(em);
+
+        // Create a lock file.  This grants us exclusive access
+        // to our set of output files, as long as we are alive.
+        int unique = -1;
+        for (;;) {
+            unique++;
+            if (unique > MAX_LOCKS) {
+                throw new IOException("Couldn't get lock for " + pattern);
+            }
+            // Generate a lock file name from the "unique" int.
+            lockFileName = generate(pattern, 0, unique).toString() + ".lck";
+            // Now try to lock that filename.
+            // Because some systems (e.g., Solaris) can only do file locks
+            // between processes (and not within a process), we first check
+            // if we ourself already have the file locked.
+            synchronized(locks) {
+                if (locks.contains(lockFileName)) {
+                    // We already own this lock, for a different FileHandler
+                    // object.  Try again.
+                    continue;
+                }
+
+                final Path lockFilePath = Paths.get(lockFileName);
+                FileChannel channel = null;
+                int retries = -1;
+                boolean fileCreated = false;
+                while (channel == null && retries++ < 1) {
+                    try {
+                        channel = FileChannel.open(lockFilePath,
+                                CREATE_NEW, WRITE);
+                        fileCreated = true;
+                    } catch (FileAlreadyExistsException ix) {
+                        // This may be a zombie file left over by a previous
+                        // execution. Reuse it - but only if we can actually
+                        // write to its directory.
+                        // Note that this is a situation that may happen,
+                        // but not too frequently.
+                        if (Files.isRegularFile(lockFilePath, LinkOption.NOFOLLOW_LINKS)
+                            && isParentWritable(lockFilePath)) {
+                            try {
+                                channel = FileChannel.open(lockFilePath,
+                                    WRITE, APPEND);
+                            } catch (NoSuchFileException x) {
+                                // Race condition - retry once, and if that
+                                // fails again just try the next name in
+                                // the sequence.
+                                continue;
+                            } catch(IOException x) {
+                                // the file may not be writable for us.
+                                // try the next name in the sequence
+                                break;
+                            }
+                        } else {
+                            // at this point channel should still be null.
+                            // break and try the next name in the sequence.
+                            break;
+                        }
+                    }
+                }
+
+                if (channel == null) continue; // try the next name;
+                lockFileChannel = channel;
+
+                boolean available;
+                try {
+                    available = lockFileChannel.tryLock() != null;
+                    // We got the lock OK.
+                    // At this point we could call File.deleteOnExit().
+                    // However, this could have undesirable side effects
+                    // as indicated by JDK-4872014. So we will instead
+                    // rely on the fact that close() will remove the lock
+                    // file and that whoever is creating FileHandlers should
+                    // be responsible for closing them.
+                } catch (IOException ix) {
+                    // We got an IOException while trying to get the lock.
+                    // This normally indicates that locking is not supported
+                    // on the target directory.  We have to proceed without
+                    // getting a lock.   Drop through, but only if we did
+                    // create the file...
+                    available = fileCreated;
+                } catch (OverlappingFileLockException x) {
+                    // someone already locked this file in this VM, through
+                    // some other channel - that is - using something else
+                    // than new FileHandler(...);
+                    // continue searching for an available lock.
+                    available = false;
+                }
+                if (available) {
+                    // We got the lock.  Remember it.
+                    locks.add(lockFileName);
+                    break;
+                }
+
+                // We failed to get the lock.  Try next file.
+                lockFileChannel.close();
+            }
+        }
+
+        files = new File[count];
+        for (int i = 0; i < count; i++) {
+            files[i] = generate(pattern, i, unique);
+        }
+
+        // Create the initial log file.
+        if (append) {
+            open(files[0], true);
+        } else {
+            rotate();
+        }
+
+        // Did we detect any exceptions during initialization?
+        Exception ex = em.lastException;
+        if (ex != null) {
+            if (ex instanceof IOException) {
+                throw (IOException) ex;
+            } else if (ex instanceof SecurityException) {
+                throw (SecurityException) ex;
+            } else {
+                throw new IOException("Exception: " + ex);
+            }
+        }
+
+        // Install the normal default ErrorManager.
+        setErrorManager(new ErrorManager());
+    }
+
+    /**
+     * Generate a file based on a user-supplied pattern, generation number,
+     * and an integer uniqueness suffix
+     * @param pattern the pattern for naming the output file
+     * @param generation the generation number to distinguish rotated logs
+     * @param unique a unique number to resolve conflicts
+     * @return the generated File
+     * @throws IOException
+     */
+    private File generate(String pattern, int generation, int unique)
+            throws IOException {
+        File file = null;
+        String word = "";
+        int ix = 0;
+        boolean sawg = false;
+        boolean sawu = false;
+        while (ix < pattern.length()) {
+            char ch = pattern.charAt(ix);
+            ix++;
+            char ch2 = 0;
+            if (ix < pattern.length()) {
+                ch2 = Character.toLowerCase(pattern.charAt(ix));
+            }
+            if (ch == '/') {
+                if (file == null) {
+                    file = new File(word);
+                } else {
+                    file = new File(file, word);
+                }
+                word = "";
+                continue;
+            } else  if (ch == '%') {
+                if (ch2 == 't') {
+                    String tmpDir = System.getProperty("java.io.tmpdir");
+                    if (tmpDir == null) {
+                        tmpDir = System.getProperty("user.home");
+                    }
+                    file = new File(tmpDir);
+                    ix++;
+                    word = "";
+                    continue;
+                } else if (ch2 == 'h') {
+                    file = new File(System.getProperty("user.home"));
+                    // Android-removed: Don't prohibit using user.home property in setuid programs.
+                    /*
+                    if (isSetUID()) {
+                        // Ok, we are in a set UID program.  For safety's sake
+                        // we disallow attempts to open files relative to %h.
+                        throw new IOException("can't use %h in set UID program");
+                    }
+                    */
+                    ix++;
+                    word = "";
+                    continue;
+                } else if (ch2 == 'g') {
+                    word = word + generation;
+                    sawg = true;
+                    ix++;
+                    continue;
+                } else if (ch2 == 'u') {
+                    word = word + unique;
+                    sawu = true;
+                    ix++;
+                    continue;
+                } else if (ch2 == '%') {
+                    word = word + "%";
+                    ix++;
+                    continue;
+                }
+            }
+            word = word + ch;
+        }
+        if (count > 1 && !sawg) {
+            word = word + "." + generation;
+        }
+        if (unique > 0 && !sawu) {
+            word = word + "." + unique;
+        }
+        if (word.length() > 0) {
+            if (file == null) {
+                file = new File(word);
+            } else {
+                file = new File(file, word);
+            }
+        }
+        return file;
+    }
+
+    /**
+     * Rotate the set of output files
+     */
+    private synchronized void rotate() {
+        Level oldLevel = getLevel();
+        setLevel(Level.OFF);
+
+        super.close();
+        for (int i = count-2; i >= 0; i--) {
+            File f1 = files[i];
+            File f2 = files[i+1];
+            if (f1.exists()) {
+                if (f2.exists()) {
+                    f2.delete();
+                }
+                f1.renameTo(f2);
+            }
+        }
+        try {
+            open(files[0], false);
+        } catch (IOException ix) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ix, ErrorManager.OPEN_FAILURE);
+
+        }
+        setLevel(oldLevel);
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        super.publish(record);
+        flush();
+        if (limit > 0 && meter.written >= limit) {
+            // We performed access checks in the "init" method to make sure
+            // we are only initialized from trusted code.  So we assume
+            // it is OK to write the target files, even if we are
+            // currently being called from untrusted code.
+            // So it is safe to raise privilege here.
+            AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                @Override
+                public Object run() {
+                    rotate();
+                    return null;
+                }
+            });
+        }
+    }
+
+    /**
+     * Close all the files.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        super.close();
+        // Unlock any lock file.
+        if (lockFileName == null) {
+            return;
+        }
+        try {
+            // Close the lock file channel (which also will free any locks)
+            lockFileChannel.close();
+        } catch (Exception ex) {
+            // Problems closing the stream.  Punt.
+        }
+        synchronized(locks) {
+            locks.remove(lockFileName);
+        }
+        new File(lockFileName).delete();
+        lockFileName = null;
+        lockFileChannel = null;
+    }
+
+    private static class InitializationErrorManager extends ErrorManager {
+        Exception lastException;
+        @Override
+        public void error(String msg, Exception ex, int code) {
+            lastException = ex;
+        }
+    }
+
+    // Android-removed: isSetUID's only caller is removed.
+    /*
+    /**
+     * check if we are in a set UID program.
+     *
+    private static native boolean isSetUID();
+    */
+}
diff --git a/java/util/logging/Filter.java b/java/util/logging/Filter.java
new file mode 100644
index 0000000..4383707
--- /dev/null
+++ b/java/util/logging/Filter.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * A Filter can be used to provide fine grain control over
+ * what is logged, beyond the control provided by log levels.
+ * <p>
+ * Each Logger and each Handler can have a filter associated with it.
+ * The Logger or Handler will call the isLoggable method to check
+ * if a given LogRecord should be published.  If isLoggable returns
+ * false, the LogRecord will be discarded.
+ *
+ * @since 1.4
+ */
+@FunctionalInterface
+public interface Filter {
+
+    /**
+     * Check if a given log record should be published.
+     * @param record  a LogRecord
+     * @return true if the log record should be published.
+     */
+    public boolean isLoggable(LogRecord record);
+}
diff --git a/java/util/logging/Formatter.java b/java/util/logging/Formatter.java
new file mode 100644
index 0000000..19e079f
--- /dev/null
+++ b/java/util/logging/Formatter.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+/**
+ * A Formatter provides support for formatting LogRecords.
+ * <p>
+ * Typically each logging Handler will have a Formatter associated
+ * with it.  The Formatter takes a LogRecord and converts it to
+ * a string.
+ * <p>
+ * Some formatters (such as the XMLFormatter) need to wrap head
+ * and tail strings around a set of formatted records. The getHeader
+ * and getTail methods can be used to obtain these strings.
+ *
+ * @since 1.4
+ */
+
+public abstract class Formatter {
+
+    /**
+     * Construct a new formatter.
+     */
+    protected Formatter() {
+    }
+
+    /**
+     * Format the given log record and return the formatted string.
+     * <p>
+     * The resulting formatted String will normally include a
+     * localized and formatted version of the LogRecord's message field.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return the formatted log record
+     */
+    public abstract String format(LogRecord record);
+
+
+    /**
+     * Return the header string for a set of formatted records.
+     * <p>
+     * This base class returns an empty string, but this may be
+     * overridden by subclasses.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  header string
+     */
+    public String getHead(Handler h) {
+        return "";
+    }
+
+    /**
+     * Return the tail string for a set of formatted records.
+     * <p>
+     * This base class returns an empty string, but this may be
+     * overridden by subclasses.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  tail string
+     */
+    public String getTail(Handler h) {
+        return "";
+    }
+
+
+    /**
+     * Localize and format the message string from a log record.  This
+     * method is provided as a convenience for Formatter subclasses to
+     * use when they are performing formatting.
+     * <p>
+     * The message string is first localized to a format string using
+     * the record's ResourceBundle.  (If there is no ResourceBundle,
+     * or if the message key is not found, then the key is used as the
+     * format string.)  The format String uses java.text style
+     * formatting.
+     * <ul>
+     * <li>If there are no parameters, no formatter is used.
+     * <li>Otherwise, if the string contains "{0" then
+     *     java.text.MessageFormat  is used to format the string.
+     * <li>Otherwise no formatting is performed.
+     * </ul>
+     * <p>
+     *
+     * @param  record  the log record containing the raw message
+     * @return   a localized and formatted message
+     */
+    public synchronized String formatMessage(LogRecord record) {
+        String format = record.getMessage();
+        java.util.ResourceBundle catalog = record.getResourceBundle();
+        if (catalog != null) {
+            try {
+                format = catalog.getString(record.getMessage());
+            } catch (java.util.MissingResourceException ex) {
+                // Drop through.  Use record message as format
+                format = record.getMessage();
+            }
+        }
+        // Do the formatting.
+        try {
+            Object parameters[] = record.getParameters();
+            if (parameters == null || parameters.length == 0) {
+                // No parameters.  Just return format string.
+                return format;
+            }
+            // Is it a java.text style format?
+            // Ideally we could match with
+            // Pattern.compile("\\{\\d").matcher(format).find())
+            // However the cost is 14% higher, so we cheaply check for
+            // 1 of the first 4 parameters
+            if (format.indexOf("{0") >= 0 || format.indexOf("{1") >=0 ||
+                        format.indexOf("{2") >=0|| format.indexOf("{3") >=0) {
+                return java.text.MessageFormat.format(format, parameters);
+            }
+            return format;
+
+        } catch (Exception ex) {
+            // Formatting failed: use localized format string.
+            return format;
+        }
+    }
+}
diff --git a/java/util/logging/Handler.java b/java/util/logging/Handler.java
new file mode 100644
index 0000000..1cc7b43
--- /dev/null
+++ b/java/util/logging/Handler.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.UnsupportedEncodingException;
+/**
+ * A <tt>Handler</tt> object takes log messages from a <tt>Logger</tt> and
+ * exports them.  It might for example, write them to a console
+ * or write them to a file, or send them to a network logging service,
+ * or forward them to an OS log, or whatever.
+ * <p>
+ * A <tt>Handler</tt> can be disabled by doing a <tt>setLevel(Level.OFF)</tt>
+ * and can  be re-enabled by doing a <tt>setLevel</tt> with an appropriate level.
+ * <p>
+ * <tt>Handler</tt> classes typically use <tt>LogManager</tt> properties to set
+ * default values for the <tt>Handler</tt>'s <tt>Filter</tt>, <tt>Formatter</tt>,
+ * and <tt>Level</tt>.  See the specific documentation for each concrete
+ * <tt>Handler</tt> class.
+ *
+ *
+ * @since 1.4
+ */
+
+public abstract class Handler {
+    private static final int offValue = Level.OFF.intValue();
+    private final LogManager manager = LogManager.getLogManager();
+
+    // We're using volatile here to avoid synchronizing getters, which
+    // would prevent other threads from calling isLoggable()
+    // while publish() is executing.
+    // On the other hand, setters will be synchronized to exclude concurrent
+    // execution with more complex methods, such as StreamHandler.publish().
+    // We wouldn't want 'level' to be changed by another thread in the middle
+    // of the execution of a 'publish' call.
+    private volatile Filter filter;
+    private volatile Formatter formatter;
+    private volatile Level logLevel = Level.ALL;
+    private volatile ErrorManager errorManager = new ErrorManager();
+    private volatile String encoding;
+
+    // Package private support for security checking.  When sealed
+    // is true, we access check updates to the class.
+    boolean sealed = true;
+
+    /**
+     * Default constructor.  The resulting <tt>Handler</tt> has a log
+     * level of <tt>Level.ALL</tt>, no <tt>Formatter</tt>, and no
+     * <tt>Filter</tt>.  A default <tt>ErrorManager</tt> instance is installed
+     * as the <tt>ErrorManager</tt>.
+     */
+    protected Handler() {
+    }
+
+    /**
+     * Publish a <tt>LogRecord</tt>.
+     * <p>
+     * The logging request was made initially to a <tt>Logger</tt> object,
+     * which initialized the <tt>LogRecord</tt> and forwarded it here.
+     * <p>
+     * The <tt>Handler</tt>  is responsible for formatting the message, when and
+     * if necessary.  The formatting should include localization.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    public abstract void publish(LogRecord record);
+
+    /**
+     * Flush any buffered output.
+     */
+    public abstract void flush();
+
+    /**
+     * Close the <tt>Handler</tt> and free all associated resources.
+     * <p>
+     * The close method will perform a <tt>flush</tt> and then close the
+     * <tt>Handler</tt>.   After close has been called this <tt>Handler</tt>
+     * should no longer be used.  Method calls may either be silently
+     * ignored or may throw runtime exceptions.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public abstract void close() throws SecurityException;
+
+    /**
+     * Set a <tt>Formatter</tt>.  This <tt>Formatter</tt> will be used
+     * to format <tt>LogRecords</tt> for this <tt>Handler</tt>.
+     * <p>
+     * Some <tt>Handlers</tt> may not use <tt>Formatters</tt>, in
+     * which case the <tt>Formatter</tt> will be remembered, but not used.
+     * <p>
+     * @param newFormatter the <tt>Formatter</tt> to use (may not be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
+        checkPermission();
+        // Check for a null pointer:
+        newFormatter.getClass();
+        formatter = newFormatter;
+    }
+
+    /**
+     * Return the <tt>Formatter</tt> for this <tt>Handler</tt>.
+     * @return the <tt>Formatter</tt> (may be null).
+     */
+    public Formatter getFormatter() {
+        return formatter;
+    }
+
+    /**
+     * Set the character encoding used by this <tt>Handler</tt>.
+     * <p>
+     * The encoding should be set before any <tt>LogRecords</tt> are written
+     * to the <tt>Handler</tt>.
+     *
+     * @param encoding  The name of a supported character encoding.
+     *        May be null, to indicate the default platform encoding.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  UnsupportedEncodingException if the named encoding is
+     *          not supported.
+     */
+    public synchronized void setEncoding(String encoding)
+                        throws SecurityException, java.io.UnsupportedEncodingException {
+        checkPermission();
+        if (encoding != null) {
+            try {
+                if(!java.nio.charset.Charset.isSupported(encoding)) {
+                    throw new UnsupportedEncodingException(encoding);
+                }
+            } catch (java.nio.charset.IllegalCharsetNameException e) {
+                throw new UnsupportedEncodingException(encoding);
+            }
+        }
+        this.encoding = encoding;
+    }
+
+    /**
+     * Return the character encoding for this <tt>Handler</tt>.
+     *
+     * @return  The encoding name.  May be null, which indicates the
+     *          default encoding should be used.
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Set a <tt>Filter</tt> to control output on this <tt>Handler</tt>.
+     * <P>
+     * For each call of <tt>publish</tt> the <tt>Handler</tt> will call
+     * this <tt>Filter</tt> (if it is non-null) to check if the
+     * <tt>LogRecord</tt> should be published or discarded.
+     *
+     * @param   newFilter  a <tt>Filter</tt> object (may be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setFilter(Filter newFilter) throws SecurityException {
+        checkPermission();
+        filter = newFilter;
+    }
+
+    /**
+     * Get the current <tt>Filter</tt> for this <tt>Handler</tt>.
+     *
+     * @return  a <tt>Filter</tt> object (may be null)
+     */
+    public Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Define an ErrorManager for this Handler.
+     * <p>
+     * The ErrorManager's "error" method will be invoked if any
+     * errors occur while using this Handler.
+     *
+     * @param em  the new ErrorManager
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setErrorManager(ErrorManager em) {
+        checkPermission();
+        if (em == null) {
+           throw new NullPointerException();
+        }
+        errorManager = em;
+    }
+
+    /**
+     * Retrieves the ErrorManager for this Handler.
+     *
+     * @return the ErrorManager for this Handler
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public ErrorManager getErrorManager() {
+        checkPermission();
+        return errorManager;
+    }
+
+   /**
+     * Protected convenience method to report an error to this Handler's
+     * ErrorManager.  Note that this method retrieves and uses the ErrorManager
+     * without doing a security check.  It can therefore be used in
+     * environments where the caller may be non-privileged.
+     *
+     * @param msg    a descriptive string (may be null)
+     * @param ex     an exception (may be null)
+     * @param code   an error code defined in ErrorManager
+     */
+    protected void reportError(String msg, Exception ex, int code) {
+        try {
+            errorManager.error(msg, ex, code);
+        } catch (Exception ex2) {
+            System.err.println("Handler.reportError caught:");
+            ex2.printStackTrace();
+        }
+    }
+
+    /**
+     * Set the log level specifying which message levels will be
+     * logged by this <tt>Handler</tt>.  Message levels lower than this
+     * value will be discarded.
+     * <p>
+     * The intention is to allow developers to turn on voluminous
+     * logging, but to limit the messages that are sent to certain
+     * <tt>Handlers</tt>.
+     *
+     * @param newLevel   the new value for the log level
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setLevel(Level newLevel) throws SecurityException {
+        if (newLevel == null) {
+            throw new NullPointerException();
+        }
+        checkPermission();
+        logLevel = newLevel;
+    }
+
+    /**
+     * Get the log level specifying which messages will be
+     * logged by this <tt>Handler</tt>.  Message levels lower
+     * than this level will be discarded.
+     * @return  the level of messages being logged.
+     */
+    public Level getLevel() {
+        return logLevel;
+    }
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate
+     * <tt>Level</tt> and  whether it satisfies any <tt>Filter</tt>.  It also
+     * may make other <tt>Handler</tt> specific checks that might prevent a
+     * handler from logging the <tt>LogRecord</tt>. It will return false if
+     * the <tt>LogRecord</tt> is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    public boolean isLoggable(LogRecord record) {
+        final int levelValue = getLevel().intValue();
+        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
+            return false;
+        }
+        final Filter filter = getFilter();
+        if (filter == null) {
+            return true;
+        }
+        return filter.isLoggable(record);
+    }
+
+    // Package-private support method for security checks.
+    // If "sealed" is true, we check that the caller has
+    // appropriate security privileges to update Handler
+    // state and if not throw a SecurityException.
+    void checkPermission() throws SecurityException {
+        if (sealed) {
+            manager.checkPermission();
+        }
+    }
+}
diff --git a/java/util/logging/Level.annotated.java b/java/util/logging/Level.annotated.java
new file mode 100644
index 0000000..769e9fd
--- /dev/null
+++ b/java/util/logging/Level.annotated.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Level implements java.io.Serializable {
+
+protected Level(@libcore.util.NonNull java.lang.String name, int value) { throw new RuntimeException("Stub!"); }
+
+protected Level(@libcore.util.NonNull java.lang.String name, int value, @libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getResourceBundleName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getLocalizedName() { throw new RuntimeException("Stub!"); }
+
[email protected] public final java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public final int intValue() { throw new RuntimeException("Stub!"); }
+
[email protected] public static synchronized java.util.logging.Level parse(@libcore.util.NonNull java.lang.String name) throws java.lang.IllegalArgumentException { throw new RuntimeException("Stub!"); }
+
+public boolean equals(@libcore.util.Nullable java.lang.Object ox) { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.util.logging.Level ALL;
+static { ALL = null; }
+
[email protected] public static final java.util.logging.Level CONFIG;
+static { CONFIG = null; }
+
[email protected] public static final java.util.logging.Level FINE;
+static { FINE = null; }
+
[email protected] public static final java.util.logging.Level FINER;
+static { FINER = null; }
+
[email protected] public static final java.util.logging.Level FINEST;
+static { FINEST = null; }
+
[email protected] public static final java.util.logging.Level INFO;
+static { INFO = null; }
+
[email protected] public static final java.util.logging.Level OFF;
+static { OFF = null; }
+
[email protected] public static final java.util.logging.Level SEVERE;
+static { SEVERE = null; }
+
[email protected] public static final java.util.logging.Level WARNING;
+static { WARNING = null; }
+}
diff --git a/java/util/logging/Level.java b/java/util/logging/Level.java
new file mode 100644
index 0000000..17b585b
--- /dev/null
+++ b/java/util/logging/Level.java
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+
+/**
+ * The Level class defines a set of standard logging levels that
+ * can be used to control logging output.  The logging Level objects
+ * are ordered and are specified by ordered integers.  Enabling logging
+ * at a given level also enables logging at all higher levels.
+ * <p>
+ * Clients should normally use the predefined Level constants such
+ * as Level.SEVERE.
+ * <p>
+ * The levels in descending order are:
+ * <ul>
+ * <li>SEVERE (highest value)
+ * <li>WARNING
+ * <li>INFO
+ * <li>CONFIG
+ * <li>FINE
+ * <li>FINER
+ * <li>FINEST  (lowest value)
+ * </ul>
+ * In addition there is a level OFF that can be used to turn
+ * off logging, and a level ALL that can be used to enable
+ * logging of all messages.
+ * <p>
+ * It is possible for third parties to define additional logging
+ * levels by subclassing Level.  In such cases subclasses should
+ * take care to chose unique integer level values and to ensure that
+ * they maintain the Object uniqueness property across serialization
+ * by defining a suitable readResolve method.
+ *
+ * @since 1.4
+ */
+
+public class Level implements java.io.Serializable {
+    private static final String defaultBundle = "sun.util.logging.resources.logging";
+
+    /**
+     * @serial  The non-localized name of the level.
+     */
+    private final String name;
+
+    /**
+     * @serial  The integer value of the level.
+     */
+    private final int value;
+
+    /**
+     * @serial The resource bundle name to be used in localizing the level name.
+     */
+    private final String resourceBundleName;
+
+    // localized level name
+    private transient String localizedLevelName;
+    private transient Locale cachedLocale;
+
+    /**
+     * OFF is a special level that can be used to turn off logging.
+     * This level is initialized to <CODE>Integer.MAX_VALUE</CODE>.
+     */
+    public static final Level OFF = new Level("OFF",Integer.MAX_VALUE, defaultBundle);
+
+    /**
+     * SEVERE is a message level indicating a serious failure.
+     * <p>
+     * In general SEVERE messages should describe events that are
+     * of considerable importance and which will prevent normal
+     * program execution.   They should be reasonably intelligible
+     * to end users and to system administrators.
+     * This level is initialized to <CODE>1000</CODE>.
+     */
+    public static final Level SEVERE = new Level("SEVERE",1000, defaultBundle);
+
+    /**
+     * WARNING is a message level indicating a potential problem.
+     * <p>
+     * In general WARNING messages should describe events that will
+     * be of interest to end users or system managers, or which
+     * indicate potential problems.
+     * This level is initialized to <CODE>900</CODE>.
+     */
+    public static final Level WARNING = new Level("WARNING", 900, defaultBundle);
+
+    /**
+     * INFO is a message level for informational messages.
+     * <p>
+     * Typically INFO messages will be written to the console
+     * or its equivalent.  So the INFO level should only be
+     * used for reasonably significant messages that will
+     * make sense to end users and system administrators.
+     * This level is initialized to <CODE>800</CODE>.
+     */
+    public static final Level INFO = new Level("INFO", 800, defaultBundle);
+
+    /**
+     * CONFIG is a message level for static configuration messages.
+     * <p>
+     * CONFIG messages are intended to provide a variety of static
+     * configuration information, to assist in debugging problems
+     * that may be associated with particular configurations.
+     * For example, CONFIG message might include the CPU type,
+     * the graphics depth, the GUI look-and-feel, etc.
+     * This level is initialized to <CODE>700</CODE>.
+     */
+    public static final Level CONFIG = new Level("CONFIG", 700, defaultBundle);
+
+    /**
+     * FINE is a message level providing tracing information.
+     * <p>
+     * All of FINE, FINER, and FINEST are intended for relatively
+     * detailed tracing.  The exact meaning of the three levels will
+     * vary between subsystems, but in general, FINEST should be used
+     * for the most voluminous detailed output, FINER for somewhat
+     * less detailed output, and FINE for the  lowest volume (and
+     * most important) messages.
+     * <p>
+     * In general the FINE level should be used for information
+     * that will be broadly interesting to developers who do not have
+     * a specialized interest in the specific subsystem.
+     * <p>
+     * FINE messages might include things like minor (recoverable)
+     * failures.  Issues indicating potential performance problems
+     * are also worth logging as FINE.
+     * This level is initialized to <CODE>500</CODE>.
+     */
+    public static final Level FINE = new Level("FINE", 500, defaultBundle);
+
+    /**
+     * FINER indicates a fairly detailed tracing message.
+     * By default logging calls for entering, returning, or throwing
+     * an exception are traced at this level.
+     * This level is initialized to <CODE>400</CODE>.
+     */
+    public static final Level FINER = new Level("FINER", 400, defaultBundle);
+
+    /**
+     * FINEST indicates a highly detailed tracing message.
+     * This level is initialized to <CODE>300</CODE>.
+     */
+    public static final Level FINEST = new Level("FINEST", 300, defaultBundle);
+
+    /**
+     * ALL indicates that all messages should be logged.
+     * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>.
+     */
+    public static final Level ALL = new Level("ALL", Integer.MIN_VALUE, defaultBundle);
+
+    /**
+     * Create a named Level with a given integer value.
+     * <p>
+     * Note that this constructor is "protected" to allow subclassing.
+     * In general clients of logging should use one of the constant Level
+     * objects such as SEVERE or FINEST.  However, if clients need to
+     * add new logging levels, they may subclass Level and define new
+     * constants.
+     * @param name  the name of the Level, for example "SEVERE".
+     * @param value an integer value for the level.
+     * @throws NullPointerException if the name is null
+     */
+    protected Level(String name, int value) {
+        this(name, value, null);
+    }
+
+    /**
+     * Create a named Level with a given integer value and a
+     * given localization resource name.
+     * <p>
+     * @param name  the name of the Level, for example "SEVERE".
+     * @param value an integer value for the level.
+     * @param resourceBundleName name of a resource bundle to use in
+     *    localizing the given name. If the resourceBundleName is null
+     *    or an empty string, it is ignored.
+     * @throws NullPointerException if the name is null
+     */
+    protected Level(String name, int value, String resourceBundleName) {
+        this(name, value, resourceBundleName, true);
+    }
+
+    // private constructor to specify whether this instance should be added
+    // to the KnownLevel list from which Level.parse method does its look up
+    private Level(String name, int value, String resourceBundleName, boolean visible) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        this.name = name;
+        this.value = value;
+        this.resourceBundleName = resourceBundleName;
+        this.localizedLevelName = resourceBundleName == null ? name : null;
+        this.cachedLocale = null;
+        if (visible) {
+            KnownLevel.add(this);
+        }
+    }
+
+    /**
+     * Return the level's localization resource bundle name, or
+     * null if no localization bundle is defined.
+     *
+     * @return localization resource bundle name
+     */
+    public String getResourceBundleName() {
+        return resourceBundleName;
+    }
+
+    /**
+     * Return the non-localized string name of the Level.
+     *
+     * @return non-localized name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Return the localized string name of the Level, for
+     * the current default locale.
+     * <p>
+     * If no localization information is available, the
+     * non-localized name is returned.
+     *
+     * @return localized name
+     */
+    public String getLocalizedName() {
+        return getLocalizedLevelName();
+    }
+
+    // package-private getLevelName() is used by the implementation
+    // instead of getName() to avoid calling the subclass's version
+    final String getLevelName() {
+        return this.name;
+    }
+
+    private String computeLocalizedLevelName(Locale newLocale) {
+        // Android-changed: Use Thread.currentThread().getContextClassLoader().
+        // Otherwise, we might get a BootClassLoader.
+        // ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
+        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale,
+                                                     Thread.currentThread().getContextClassLoader());
+        final String localizedName = rb.getString(name);
+
+        final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
+        if (!isDefaultBundle) return localizedName;
+
+        // This is a trick to determine whether the name has been translated
+        // or not. If it has not been translated, we need to use Locale.ROOT
+        // when calling toUpperCase().
+        final Locale rbLocale = rb.getLocale();
+        final Locale locale =
+                Locale.ROOT.equals(rbLocale)
+                || name.equals(localizedName.toUpperCase(Locale.ROOT))
+                ? Locale.ROOT : rbLocale;
+
+        // ALL CAPS in a resource bundle's message indicates no translation
+        // needed per Oracle translation guideline.  To workaround this
+        // in Oracle JDK implementation, convert the localized level name
+        // to uppercase for compatibility reason.
+        return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
+    }
+
+    // Avoid looking up the localizedLevelName twice if we already
+    // have it.
+    final String getCachedLocalizedLevelName() {
+
+        if (localizedLevelName != null) {
+            if (cachedLocale != null) {
+                if (cachedLocale.equals(Locale.getDefault())) {
+                    // OK: our cached value was looked up with the same
+                    //     locale. We can use it.
+                    return localizedLevelName;
+                }
+            }
+        }
+
+        if (resourceBundleName == null) {
+            // No resource bundle: just use the name.
+            return name;
+        }
+
+        // We need to compute the localized name.
+        // Either because it's the first time, or because our cached
+        // value is for a different locale. Just return null.
+        return null;
+    }
+
+    final synchronized String getLocalizedLevelName() {
+
+        // See if we have a cached localized name
+        final String cachedLocalizedName = getCachedLocalizedLevelName();
+        if (cachedLocalizedName != null) {
+            return cachedLocalizedName;
+        }
+
+        // No cached localized name or cache invalid.
+        // Need to compute the localized name.
+        final Locale newLocale = Locale.getDefault();
+        try {
+            localizedLevelName = computeLocalizedLevelName(newLocale);
+        } catch (Exception ex) {
+            localizedLevelName = name;
+        }
+        cachedLocale = newLocale;
+        return localizedLevelName;
+    }
+
+    // Returns a mirrored Level object that matches the given name as
+    // specified in the Level.parse method.  Returns null if not found.
+    //
+    // It returns the same Level object as the one returned by Level.parse
+    // method if the given name is a non-localized name or integer.
+    //
+    // If the name is a localized name, findLevel and parse method may
+    // return a different level value if there is a custom Level subclass
+    // that overrides Level.getLocalizedName() to return a different string
+    // than what's returned by the default implementation.
+    //
+    static Level findLevel(String name) {
+        if (name == null) {
+            throw new NullPointerException();
+        }
+
+        KnownLevel level;
+
+        // Look for a known Level with the given non-localized name.
+        level = KnownLevel.findByName(name);
+        if (level != null) {
+            return level.mirroredLevel;
+        }
+
+        // Now, check if the given name is an integer.  If so,
+        // first look for a Level with the given value and then
+        // if necessary create one.
+        try {
+            int x = Integer.parseInt(name);
+            level = KnownLevel.findByValue(x);
+            if (level == null) {
+                // add new Level
+                Level levelObject = new Level(name, x);
+                level = KnownLevel.findByValue(x);
+            }
+            return level.mirroredLevel;
+        } catch (NumberFormatException ex) {
+            // Not an integer.
+            // Drop through.
+        }
+
+        level = KnownLevel.findByLocalizedLevelName(name);
+        if (level != null) {
+            return level.mirroredLevel;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns a string representation of this Level.
+     *
+     * @return the non-localized name of the Level, for example "INFO".
+     */
+    @Override
+    public final String toString() {
+        return name;
+    }
+
+    /**
+     * Get the integer value for this level.  This integer value
+     * can be used for efficient ordering comparisons between
+     * Level objects.
+     * @return the integer value for this level.
+     */
+    public final int intValue() {
+        return value;
+    }
+
+    private static final long serialVersionUID = -8176160795706313070L;
+
+    // Serialization magic to prevent "doppelgangers".
+    // This is a performance optimization.
+    private Object readResolve() {
+        KnownLevel o = KnownLevel.matches(this);
+        if (o != null) {
+            return o.levelObject;
+        }
+
+        // Woops.  Whoever sent us this object knows
+        // about a new log level.  Add it to our list.
+        Level level = new Level(this.name, this.value, this.resourceBundleName);
+        return level;
+    }
+
+    /**
+     * Parse a level name string into a Level.
+     * <p>
+     * The argument string may consist of either a level name
+     * or an integer value.
+     * <p>
+     * For example:
+     * <ul>
+     * <li>     "SEVERE"
+     * <li>     "1000"
+     * </ul>
+     *
+     * @param  name   string to be parsed
+     * @throws NullPointerException if the name is null
+     * @throws IllegalArgumentException if the value is not valid.
+     * Valid values are integers between <CODE>Integer.MIN_VALUE</CODE>
+     * and <CODE>Integer.MAX_VALUE</CODE>, and all known level names.
+     * Known names are the levels defined by this class (e.g., <CODE>FINE</CODE>,
+     * <CODE>FINER</CODE>, <CODE>FINEST</CODE>), or created by this class with
+     * appropriate package access, or new levels defined or created
+     * by subclasses.
+     *
+     * @return The parsed value. Passing an integer that corresponds to a known name
+     * (e.g., 700) will return the associated name (e.g., <CODE>CONFIG</CODE>).
+     * Passing an integer that does not (e.g., 1) will return a new level name
+     * initialized to that value.
+     */
+    public static synchronized Level parse(String name) throws IllegalArgumentException {
+        // Check that name is not null.
+        name.length();
+
+        KnownLevel level;
+
+        // Look for a known Level with the given non-localized name.
+        level = KnownLevel.findByName(name);
+        if (level != null) {
+            return level.levelObject;
+        }
+
+        // Now, check if the given name is an integer.  If so,
+        // first look for a Level with the given value and then
+        // if necessary create one.
+        try {
+            int x = Integer.parseInt(name);
+            level = KnownLevel.findByValue(x);
+            if (level == null) {
+                // add new Level
+                Level levelObject = new Level(name, x);
+                level = KnownLevel.findByValue(x);
+            }
+            return level.levelObject;
+        } catch (NumberFormatException ex) {
+            // Not an integer.
+            // Drop through.
+        }
+
+        // Finally, look for a known level with the given localized name,
+        // in the current default locale.
+        // This is relatively expensive, but not excessively so.
+        level = KnownLevel.findByLocalizedLevelName(name);
+        if (level != null) {
+            return level.levelObject;
+        }
+
+        // OK, we've tried everything and failed
+        throw new IllegalArgumentException("Bad level \"" + name + "\"");
+    }
+
+    /**
+     * Compare two objects for value equality.
+     * @return true if and only if the two objects have the same level value.
+     */
+    @Override
+    public boolean equals(Object ox) {
+        try {
+            Level lx = (Level)ox;
+            return (lx.value == this.value);
+        } catch (Exception ex) {
+            return false;
+        }
+    }
+
+    /**
+     * Generate a hashcode.
+     * @return a hashcode based on the level value
+     */
+    @Override
+    public int hashCode() {
+        return this.value;
+    }
+
+    // KnownLevel class maintains the global list of all known levels.
+    // The API allows multiple custom Level instances of the same name/value
+    // be created. This class provides convenient methods to find a level
+    // by a given name, by a given value, or by a given localized name.
+    //
+    // KnownLevel wraps the following Level objects:
+    // 1. levelObject:   standard Level object or custom Level object
+    // 2. mirroredLevel: Level object representing the level specified in the
+    //                   logging configuration.
+    //
+    // Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
+    // are non-final but the name and resource bundle name are parameters to
+    // the Level constructor.  Use the mirroredLevel object instead of the
+    // levelObject to prevent the logging framework to execute foreign code
+    // implemented by untrusted Level subclass.
+    //
+    // Implementation Notes:
+    // If Level.getName, Level.getLocalizedName, Level.getResourceBundleName methods
+    // were final, the following KnownLevel implementation can be removed.
+    // Future API change should take this into consideration.
+    static final class KnownLevel {
+        private static Map<String, List<KnownLevel>> nameToLevels = new HashMap<>();
+        private static Map<Integer, List<KnownLevel>> intToLevels = new HashMap<>();
+        final Level levelObject;     // instance of Level class or Level subclass
+        final Level mirroredLevel;   // mirror of the custom Level
+        KnownLevel(Level l) {
+            this.levelObject = l;
+            if (l.getClass() == Level.class) {
+                this.mirroredLevel = l;
+            } else {
+                // this mirrored level object is hidden
+                this.mirroredLevel = new Level(l.name, l.value, l.resourceBundleName, false);
+            }
+        }
+
+        static synchronized void add(Level l) {
+            // the mirroredLevel object is always added to the list
+            // before the custom Level instance
+            KnownLevel o = new KnownLevel(l);
+            List<KnownLevel> list = nameToLevels.get(l.name);
+            if (list == null) {
+                list = new ArrayList<>();
+                nameToLevels.put(l.name, list);
+            }
+            list.add(o);
+
+            list = intToLevels.get(l.value);
+            if (list == null) {
+                list = new ArrayList<>();
+                intToLevels.put(l.value, list);
+            }
+            list.add(o);
+        }
+
+        // Returns a KnownLevel with the given non-localized name.
+        static synchronized KnownLevel findByName(String name) {
+            List<KnownLevel> list = nameToLevels.get(name);
+            if (list != null) {
+                return list.get(0);
+            }
+            return null;
+        }
+
+        // Returns a KnownLevel with the given value.
+        static synchronized KnownLevel findByValue(int value) {
+            List<KnownLevel> list = intToLevels.get(value);
+            if (list != null) {
+                return list.get(0);
+            }
+            return null;
+        }
+
+        // Returns a KnownLevel with the given localized name matching
+        // by calling the Level.getLocalizedLevelName() method (i.e. found
+        // from the resourceBundle associated with the Level object).
+        // This method does not call Level.getLocalizedName() that may
+        // be overridden in a subclass implementation
+        static synchronized KnownLevel findByLocalizedLevelName(String name) {
+            for (List<KnownLevel> levels : nameToLevels.values()) {
+                for (KnownLevel l : levels) {
+                    String lname = l.levelObject.getLocalizedLevelName();
+                    if (name.equals(lname)) {
+                        return l;
+                    }
+                }
+            }
+            return null;
+        }
+
+        static synchronized KnownLevel matches(Level l) {
+            List<KnownLevel> list = nameToLevels.get(l.name);
+            if (list != null) {
+                for (KnownLevel level : list) {
+                    Level other = level.mirroredLevel;
+                    Class<? extends Level> type = level.levelObject.getClass();
+                    if (l.value == other.value &&
+                           (l.resourceBundleName == other.resourceBundleName ||
+                               (l.resourceBundleName != null &&
+                                l.resourceBundleName.equals(other.resourceBundleName)))) {
+                        if (type == l.getClass()) {
+                            return level;
+                        }
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+}
diff --git a/java/util/logging/LogManager.java b/java/util/logging/LogManager.java
new file mode 100644
index 0000000..0d51b0f
--- /dev/null
+++ b/java/util/logging/LogManager.java
@@ -0,0 +1,1830 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.beans.PropertyChangeListener;
+
+/**
+ * There is a single global LogManager object that is used to
+ * maintain a set of shared state about Loggers and log services.
+ * <p>
+ * This LogManager object:
+ * <ul>
+ * <li> Manages a hierarchical namespace of Logger objects.  All
+ *      named Loggers are stored in this namespace.
+ * <li> Manages a set of logging control properties.  These are
+ *      simple key-value pairs that can be used by Handlers and
+ *      other logging objects to configure themselves.
+ * </ul>
+ * <p>
+ * The global LogManager object can be retrieved using LogManager.getLogManager().
+ * The LogManager object is created during class initialization and
+ * cannot subsequently be changed.
+ * <p>
+ * At startup the LogManager class is located using the
+ * java.util.logging.manager system property.
+ * <p>
+ * The LogManager defines two optional system properties that allow control over
+ * the initial configuration:
+ * <ul>
+ * <li>"java.util.logging.config.class"
+ * <li>"java.util.logging.config.file"
+ * </ul>
+ * These two properties may be specified on the command line to the "java"
+ * command, or as system property definitions passed to JNI_CreateJavaVM.
+ * <p>
+ * If the "java.util.logging.config.class" property is set, then the
+ * property value is treated as a class name.  The given class will be
+ * loaded, an object will be instantiated, and that object's constructor
+ * is responsible for reading in the initial configuration.  (That object
+ * may use other system properties to control its configuration.)  The
+ * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
+ * to define properties in the LogManager.
+ * <p>
+ * If "java.util.logging.config.class" property is <b>not</b> set,
+ * then the "java.util.logging.config.file" system property can be used
+ * to specify a properties file (in java.util.Properties format). The
+ * initial logging configuration will be read from this file.
+ * <p>
+ * If neither of these properties is defined then the LogManager uses its
+ * default configuration. The default configuration is typically loaded from the
+ * properties file "{@code lib/logging.properties}" in the Java installation
+ * directory.
+ * <p>
+ * The properties for loggers and Handlers will have names starting
+ * with the dot-separated name for the handler or logger.
+ * <p>
+ * The global logging properties may include:
+ * <ul>
+ * <li>A property "handlers".  This defines a whitespace or comma separated
+ * list of class names for handler classes to load and register as
+ * handlers on the root Logger (the Logger named "").  Each class
+ * name must be for a Handler class which has a default constructor.
+ * Note that these Handlers may be created lazily, when they are
+ * first used.
+ *
+ * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
+ * comma separated list of class names for handlers classes to
+ * load and register as handlers to the specified logger. Each class
+ * name must be for a Handler class which has a default constructor.
+ * Note that these Handlers may be created lazily, when they are
+ * first used.
+ *
+ * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
+ * value. By default every logger calls its parent in addition to
+ * handling the logging message itself, this often result in messages
+ * being handled by the root logger as well. When setting this property
+ * to false a Handler needs to be configured for this logger otherwise
+ * no logging messages are delivered.
+ *
+ * <li>A property "config".  This property is intended to allow
+ * arbitrary configuration code to be run.  The property defines a
+ * whitespace or comma separated list of class names.  A new instance will be
+ * created for each named class.  The default constructor of each class
+ * may execute arbitrary code to update the logging configuration, such as
+ * setting logger levels, adding handlers, adding filters, etc.
+ * </ul>
+ * <p>
+ * Note that all classes loaded during LogManager configuration are
+ * first searched on the system class path before any user class path.
+ * That includes the LogManager class, any config classes, and any
+ * handler classes.
+ * <p>
+ * Loggers are organized into a naming hierarchy based on their
+ * dot separated names.  Thus "a.b.c" is a child of "a.b", but
+ * "a.b1" and a.b2" are peers.
+ * <p>
+ * All properties whose names end with ".level" are assumed to define
+ * log levels for Loggers.  Thus "foo.level" defines a log level for
+ * the logger called "foo" and (recursively) for any of its children
+ * in the naming hierarchy.  Log Levels are applied in the order they
+ * are defined in the properties file.  Thus level settings for child
+ * nodes in the tree should come after settings for their parents.
+ * The property name ".level" can be used to set the level for the
+ * root of the tree.
+ * <p>
+ * All methods on the LogManager object are multi-thread safe.
+ *
+ * @since 1.4
+*/
+
+public class LogManager {
+    // The global LogManager object
+    private static final LogManager manager;
+
+    // 'props' is assigned within a lock but accessed without it.
+    // Declaring it volatile makes sure that another thread will not
+    // be able to see a partially constructed 'props' object.
+    // (seeing a partially constructed 'props' object can result in
+    // NPE being thrown in Hashtable.get(), because it leaves the door
+    // open for props.getProperties() to be called before the construcor
+    // of Hashtable is actually completed).
+    private volatile Properties props = new Properties();
+    private final static Level defaultLevel = Level.INFO;
+
+    // The map of the registered listeners. The map value is the registration
+    // count to allow for cases where the same listener is registered many times.
+    private final Map<Object,Integer> listenerMap = new HashMap<>();
+
+    // LoggerContext for system loggers and user loggers
+    private final LoggerContext systemContext = new SystemLoggerContext();
+    private final LoggerContext userContext = new LoggerContext();
+    // non final field - make it volatile to make sure that other threads
+    // will see the new value once ensureLogManagerInitialized() has finished
+    // executing.
+    private volatile Logger rootLogger;
+    // Have we done the primordial reading of the configuration file?
+    // (Must be done after a suitable amount of java.lang.System
+    // initialization has been done)
+    private volatile boolean readPrimordialConfiguration;
+    // Have we initialized global (root) handlers yet?
+    // This gets set to false in readConfiguration
+    private boolean initializedGlobalHandlers = true;
+    // True if JVM death is imminent and the exit hook has been called.
+    private boolean deathImminent;
+
+    static {
+        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
+            @Override
+            public LogManager run() {
+                LogManager mgr = null;
+                String cname = null;
+                try {
+                    cname = System.getProperty("java.util.logging.manager");
+                    if (cname != null) {
+                        // Android-changed: Extract logic into the getClassInstance() helper.
+                        mgr = (LogManager) getClassInstance(cname).newInstance();
+                    }
+                } catch (Exception ex) {
+                    System.err.println("Could not load Logmanager \"" + cname + "\"");
+                    ex.printStackTrace();
+                }
+                if (mgr == null) {
+                    mgr = new LogManager();
+                }
+                return mgr;
+
+            }
+        });
+    }
+
+
+    // This private class is used as a shutdown hook.
+    // It does a "reset" to close all open handlers.
+    private class Cleaner extends Thread {
+
+        private Cleaner() {
+            /* Set context class loader to null in order to avoid
+             * keeping a strong reference to an application classloader.
+             */
+            this.setContextClassLoader(null);
+        }
+
+        @Override
+        public void run() {
+            // This is to ensure the LogManager.<clinit> is completed
+            // before synchronized block. Otherwise deadlocks are possible.
+            LogManager mgr = manager;
+
+            // If the global handlers haven't been initialized yet, we
+            // don't want to initialize them just so we can close them!
+            synchronized (LogManager.this) {
+                // Note that death is imminent.
+                deathImminent = true;
+                initializedGlobalHandlers = true;
+            }
+
+            // Do a reset to close all active handlers.
+            reset();
+        }
+    }
+
+
+    /**
+     * Protected constructor.  This is protected so that container applications
+     * (such as J2EE containers) can subclass the object.  It is non-public as
+     * it is intended that there only be one LogManager object, whose value is
+     * retrieved by calling LogManager.getLogManager.
+     */
+    protected LogManager() {
+        this(checkSubclassPermissions());
+    }
+
+    private LogManager(Void checked) {
+
+        // Add a shutdown hook to close the global handlers.
+        try {
+            Runtime.getRuntime().addShutdownHook(new Cleaner());
+        } catch (IllegalStateException e) {
+            // If the VM is already shutting down,
+            // We do not need to register shutdownHook.
+        }
+    }
+
+    private static Void checkSubclassPermissions() {
+        final SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            // These permission will be checked in the LogManager constructor,
+            // in order to register the Cleaner() thread as a shutdown hook.
+            // Check them here to avoid the penalty of constructing the object
+            // etc...
+            sm.checkPermission(new RuntimePermission("shutdownHooks"));
+            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
+        }
+        return null;
+    }
+
+    /**
+     * Lazy initialization: if this instance of manager is the global
+     * manager then this method will read the initial configuration and
+     * add the root logger and global logger by calling addLogger().
+     *
+     * Note that it is subtly different from what we do in LoggerContext.
+     * In LoggerContext we're patching up the logger context tree in order to add
+     * the root and global logger *to the context tree*.
+     *
+     * For this to work, addLogger() must have already have been called
+     * once on the LogManager instance for the default logger being
+     * added.
+     *
+     * This is why ensureLogManagerInitialized() needs to be called before
+     * any logger is added to any logger context.
+     *
+     */
+    private boolean initializedCalled = false;
+    private volatile boolean initializationDone = false;
+    final void ensureLogManagerInitialized() {
+        final LogManager owner = this;
+        if (initializationDone || owner != manager) {
+            // we don't want to do this twice, and we don't want to do
+            // this on private manager instances.
+            return;
+        }
+
+        // Maybe another thread has called ensureLogManagerInitialized()
+        // before us and is still executing it. If so we will block until
+        // the log manager has finished initialized, then acquire the monitor,
+        // notice that initializationDone is now true and return.
+        // Otherwise - we have come here first! We will acquire the monitor,
+        // see that initializationDone is still false, and perform the
+        // initialization.
+        //
+        synchronized(this) {
+            // If initializedCalled is true it means that we're already in
+            // the process of initializing the LogManager in this thread.
+            // There has been a recursive call to ensureLogManagerInitialized().
+            final boolean isRecursiveInitialization = (initializedCalled == true);
+
+            assert initializedCalled || !initializationDone
+                    : "Initialization can't be done if initialized has not been called!";
+
+            if (isRecursiveInitialization || initializationDone) {
+                // If isRecursiveInitialization is true it means that we're
+                // already in the process of initializing the LogManager in
+                // this thread. There has been a recursive call to
+                // ensureLogManagerInitialized(). We should not proceed as
+                // it would lead to infinite recursion.
+                //
+                // If initializationDone is true then it means the manager
+                // has finished initializing; just return: we're done.
+                return;
+            }
+            // Calling addLogger below will in turn call requiresDefaultLogger()
+            // which will call ensureLogManagerInitialized().
+            // We use initializedCalled to break the recursion.
+            initializedCalled = true;
+            try {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        assert rootLogger == null;
+                        assert initializedCalled && !initializationDone;
+
+                        // Read configuration.
+                        owner.readPrimordialConfiguration();
+
+                        // Create and retain Logger for the root of the namespace.
+                        owner.rootLogger = owner.new RootLogger();
+                        owner.addLogger(owner.rootLogger);
+                        if (!owner.rootLogger.isLevelInitialized()) {
+                            owner.rootLogger.setLevel(defaultLevel);
+                        }
+
+                        // Adding the global Logger.
+                        // Do not call Logger.getGlobal() here as this might trigger
+                        // subtle inter-dependency issues.
+                        @SuppressWarnings("deprecation")
+                        final Logger global = Logger.global;
+
+                        // Make sure the global logger will be registered in the
+                        // global manager
+                        owner.addLogger(global);
+                        return null;
+                    }
+                });
+            } finally {
+                initializationDone = true;
+            }
+        }
+    }
+
+    /**
+     * Returns the global LogManager object.
+     * @return the global LogManager object
+     */
+    public static LogManager getLogManager() {
+        if (manager != null) {
+            manager.ensureLogManagerInitialized();
+        }
+        return manager;
+    }
+
+    private void readPrimordialConfiguration() {
+        if (!readPrimordialConfiguration) {
+            synchronized (this) {
+                if (!readPrimordialConfiguration) {
+                    // If System.in/out/err are null, it's a good
+                    // indication that we're still in the
+                    // bootstrapping phase
+                    if (System.out == null) {
+                        return;
+                    }
+                    readPrimordialConfiguration = true;
+
+                    try {
+                        AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                                @Override
+                                public Void run() throws Exception {
+                                    readConfiguration();
+
+                                    // Platform loggers begin to delegate to java.util.logging.Logger
+                                    sun.util.logging.PlatformLogger.redirectPlatformLoggers();
+                                    return null;
+                                }
+                            });
+                    } catch (Exception ex) {
+                        assert false : "Exception raised while reading logging configuration: " + ex;
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Adds an event listener to be invoked when the logging
+     * properties are re-read. Adding multiple instances of
+     * the same event Listener results in multiple entries
+     * in the property event listener table.
+     *
+     * <p><b>WARNING:</b> This method is omitted from this class in all subset
+     * Profiles of Java SE that do not include the {@code java.beans} package.
+     * </p>
+     *
+     * @param l  event listener
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception NullPointerException if the PropertyChangeListener is null.
+     * @deprecated The dependency on {@code PropertyChangeListener} creates a
+     *             significant impediment to future modularization of the Java
+     *             platform. This method will be removed in a future release.
+     *             The global {@code LogManager} can detect changes to the
+     *             logging configuration by overridding the {@link
+     *             #readConfiguration readConfiguration} method.
+     */
+    @Deprecated
+    public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException {
+        PropertyChangeListener listener = Objects.requireNonNull(l);
+        checkPermission();
+        synchronized (listenerMap) {
+            // increment the registration count if already registered
+            Integer value = listenerMap.get(listener);
+            value = (value == null) ? 1 : (value + 1);
+            listenerMap.put(listener, value);
+        }
+    }
+
+    /**
+     * Removes an event listener for property change events.
+     * If the same listener instance has been added to the listener table
+     * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
+     * then an equivalent number of
+     * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
+     * all instances of that listener from the listener table.
+     * <P>
+     * Returns silently if the given listener is not found.
+     *
+     * <p><b>WARNING:</b> This method is omitted from this class in all subset
+     * Profiles of Java SE that do not include the {@code java.beans} package.
+     * </p>
+     *
+     * @param l  event listener (can be null)
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @deprecated The dependency on {@code PropertyChangeListener} creates a
+     *             significant impediment to future modularization of the Java
+     *             platform. This method will be removed in a future release.
+     *             The global {@code LogManager} can detect changes to the
+     *             logging configuration by overridding the {@link
+     *             #readConfiguration readConfiguration} method.
+     */
+    @Deprecated
+    public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException {
+        checkPermission();
+        if (l != null) {
+            PropertyChangeListener listener = l;
+            synchronized (listenerMap) {
+                Integer value = listenerMap.get(listener);
+                if (value != null) {
+                    // remove from map if registration count is 1, otherwise
+                    // just decrement its count
+                    int i = value.intValue();
+                    if (i == 1) {
+                        listenerMap.remove(listener);
+                    } else {
+                        assert i > 1;
+                        listenerMap.put(listener, i - 1);
+                    }
+                }
+            }
+        }
+    }
+
+    // LoggerContext maps from AppContext
+    private WeakHashMap<Object, LoggerContext> contextsMap = null;
+
+    // Returns the LoggerContext for the user code (i.e. application or AppContext).
+    // Loggers are isolated from each AppContext.
+    private LoggerContext getUserContext() {
+        // Android-changed: Remove AWT specific hooks.
+        return userContext;
+    }
+
+    // The system context.
+    final LoggerContext getSystemContext() {
+        return systemContext;
+    }
+
+    private List<LoggerContext> contexts() {
+        List<LoggerContext> cxs = new ArrayList<>();
+        cxs.add(getSystemContext());
+        cxs.add(getUserContext());
+        return cxs;
+    }
+
+    // Find or create a specified logger instance. If a logger has
+    // already been created with the given name it is returned.
+    // Otherwise a new logger instance is created and registered
+    // in the LogManager global namespace.
+    // This method will always return a non-null Logger object.
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by addLogger().
+    //
+    // This method must delegate to the LogManager implementation to
+    // add a new Logger or return the one that has been added previously
+    // as a LogManager subclass may override the addLogger, getLogger,
+    // readConfiguration, and other methods.
+    Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
+        Logger result = getLogger(name);
+        if (result == null) {
+            // only allocate the new logger once
+            Logger newLogger = new Logger(name, resourceBundleName, caller, this, false);
+            do {
+                if (addLogger(newLogger)) {
+                    // We successfully added the new Logger that we
+                    // created above so return it without refetching.
+                    return newLogger;
+                }
+
+                // We didn't add the new Logger that we created above
+                // because another thread added a Logger with the same
+                // name after our null check above and before our call
+                // to addLogger(). We have to refetch the Logger because
+                // addLogger() returns a boolean instead of the Logger
+                // reference itself. However, if the thread that created
+                // the other Logger is not holding a strong reference to
+                // the other Logger, then it is possible for the other
+                // Logger to be GC'ed after we saw it in addLogger() and
+                // before we can refetch it. If it has been GC'ed then
+                // we'll just loop around and try again.
+                result = getLogger(name);
+            } while (result == null);
+        }
+        return result;
+    }
+
+    Logger demandSystemLogger(String name, String resourceBundleName) {
+        // Add a system logger in the system context's namespace
+        final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
+
+        // Add the system logger to the LogManager's namespace if not exist
+        // so that there is only one single logger of the given name.
+        // System loggers are visible to applications unless a logger of
+        // the same name has been added.
+        Logger logger;
+        do {
+            // First attempt to call addLogger instead of getLogger
+            // This would avoid potential bug in custom LogManager.getLogger
+            // implementation that adds a logger if does not exist
+            if (addLogger(sysLogger)) {
+                // successfully added the new system logger
+                logger = sysLogger;
+            } else {
+                logger = getLogger(name);
+            }
+        } while (logger == null);
+
+        // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
+        if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) {
+            // if logger already exists but handlers not set
+            final Logger l = logger;
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    for (Handler hdl : l.accessCheckedHandlers()) {
+                        sysLogger.addHandler(hdl);
+                    }
+                    return null;
+                }
+            });
+        }
+        return sysLogger;
+    }
+
+    // Android-added: getClassInstance helper method, used in several places in this class.
+    private static Class getClassInstance(String cname) throws ClassNotFoundException {
+        try {
+            return ClassLoader.getSystemClassLoader().loadClass(cname);
+        } catch (ClassNotFoundException ex) {
+            return Thread.currentThread().getContextClassLoader().loadClass(cname);
+        }
+    }
+
+    // LoggerContext maintains the logger namespace per context.
+    // The default LogManager implementation has one system context and user
+    // context.  The system context is used to maintain the namespace for
+    // all system loggers and is queried by the system code.  If a system logger
+    // doesn't exist in the user context, it'll also be added to the user context.
+    // The user context is queried by the user code and all other loggers are
+    // added in the user context.
+    class LoggerContext {
+        // Table of named Loggers that maps names to Loggers.
+        private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
+        // Tree of named Loggers
+        private final LogNode root;
+        private LoggerContext() {
+            this.root = new LogNode(null, this);
+        }
+
+
+        // Tells whether default loggers are required in this context.
+        // If true, the default loggers will be lazily added.
+        final boolean requiresDefaultLoggers() {
+            final boolean requiresDefaultLoggers = (getOwner() == manager);
+            if (requiresDefaultLoggers) {
+                getOwner().ensureLogManagerInitialized();
+            }
+            return requiresDefaultLoggers;
+        }
+
+        // This context's LogManager.
+        final LogManager getOwner() {
+            return LogManager.this;
+        }
+
+        // This context owner's root logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getRootLogger() {
+            return getOwner().rootLogger;
+        }
+
+        // The global logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getGlobalLogger() {
+            // Android-changed: Fix SuppressWarnings from "deprecated" to "deprecation".
+            @SuppressWarnings("deprecation") // avoids initialization cycles.
+            final Logger global = Logger.global;
+            return global;
+        }
+
+        Logger demandLogger(String name, String resourceBundleName) {
+            // a LogManager subclass may have its own implementation to add and
+            // get a Logger.  So delegate to the LogManager to do the work.
+            final LogManager owner = getOwner();
+            return owner.demandLogger(name, resourceBundleName, null);
+        }
+
+
+        // Due to subtle deadlock issues getUserContext() no longer
+        // calls addLocalLogger(rootLogger);
+        // Therefore - we need to add the default loggers later on.
+        // Checks that the context is properly initialized
+        // This is necessary before calling e.g. find(name)
+        // or getLoggerNames()
+        //
+        private void ensureInitialized() {
+            if (requiresDefaultLoggers()) {
+                // Ensure that the root and global loggers are set.
+                ensureDefaultLogger(getRootLogger());
+                ensureDefaultLogger(getGlobalLogger());
+            }
+        }
+
+
+        synchronized Logger findLogger(String name) {
+            // ensure that this context is properly initialized before
+            // looking for loggers.
+            ensureInitialized();
+            LoggerWeakRef ref = namedLoggers.get(name);
+            if (ref == null) {
+                return null;
+            }
+            Logger logger = ref.get();
+            if (logger == null) {
+                // Hashtable holds stale weak reference
+                // to a logger which has been GC-ed.
+                ref.dispose();
+            }
+            return logger;
+        }
+
+        // This method is called before adding a logger to the
+        // context.
+        // 'logger' is the context that will be added.
+        // This method will ensure that the defaults loggers are added
+        // before adding 'logger'.
+        //
+        private void ensureAllDefaultLoggers(Logger logger) {
+            if (requiresDefaultLoggers()) {
+                final String name = logger.getName();
+                if (!name.isEmpty()) {
+                    ensureDefaultLogger(getRootLogger());
+                    if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
+                        ensureDefaultLogger(getGlobalLogger());
+                    }
+                }
+            }
+        }
+
+        private void ensureDefaultLogger(Logger logger) {
+            // Used for lazy addition of root logger and global logger
+            // to a LoggerContext.
+
+            // This check is simple sanity: we do not want that this
+            // method be called for anything else than Logger.global
+            // or owner.rootLogger.
+            if (!requiresDefaultLoggers() || logger == null
+                    || logger != Logger.global && logger != LogManager.this.rootLogger) {
+
+                // the case where we have a non null logger which is neither
+                // Logger.global nor manager.rootLogger indicates a serious
+                // issue - as ensureDefaultLogger should never be called
+                // with any other loggers than one of these two (or null - if
+                // e.g manager.rootLogger is not yet initialized)...
+                assert logger == null;
+
+                return;
+            }
+
+            // Adds the logger if it's not already there.
+            if (!namedLoggers.containsKey(logger.getName())) {
+                // It is important to prevent addLocalLogger to
+                // call ensureAllDefaultLoggers when we're in the process
+                // off adding one of those default loggers - as this would
+                // immediately cause a stack overflow.
+                // Therefore we must pass addDefaultLoggersIfNeeded=false,
+                // even if requiresDefaultLoggers is true.
+                addLocalLogger(logger, false);
+            }
+        }
+
+        boolean addLocalLogger(Logger logger) {
+            // no need to add default loggers if it's not required
+            return addLocalLogger(logger, requiresDefaultLoggers());
+        }
+
+        // Add a logger to this context.  This method will only set its level
+        // and process parent loggers.  It doesn't set its handlers.
+        synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
+            // addDefaultLoggersIfNeeded serves to break recursion when adding
+            // default loggers. If we're adding one of the default loggers
+            // (we're being called from ensureDefaultLogger()) then
+            // addDefaultLoggersIfNeeded will be false: we don't want to
+            // call ensureAllDefaultLoggers again.
+            //
+            // Note: addDefaultLoggersIfNeeded can also be false when
+            //       requiresDefaultLoggers is false - since calling
+            //       ensureAllDefaultLoggers would have no effect in this case.
+            if (addDefaultLoggersIfNeeded) {
+                ensureAllDefaultLoggers(logger);
+            }
+
+            final String name = logger.getName();
+            if (name == null) {
+                throw new NullPointerException();
+            }
+            LoggerWeakRef ref = namedLoggers.get(name);
+            if (ref != null) {
+                if (ref.get() == null) {
+                    // It's possible that the Logger was GC'ed after a
+                    // drainLoggerRefQueueBounded() call above so allow
+                    // a new one to be registered.
+                    ref.dispose();
+                } else {
+                    // We already have a registered logger with the given name.
+                    return false;
+                }
+            }
+
+            // We're adding a new logger.
+            // Note that we are creating a weak reference here.
+            final LogManager owner = getOwner();
+            logger.setLogManager(owner);
+            ref = owner.new LoggerWeakRef(logger);
+            namedLoggers.put(name, ref);
+
+            // Apply any initial level defined for the new logger, unless
+            // the logger's level is already initialized
+            Level level = owner.getLevelProperty(name + ".level", null);
+            if (level != null && !logger.isLevelInitialized()) {
+                doSetLevel(logger, level);
+            }
+
+            // instantiation of the handler is done in the LogManager.addLogger
+            // implementation as a handler class may be only visible to LogManager
+            // subclass for the custom log manager case
+            processParentHandlers(logger, name);
+
+            // Find the new node and its parent.
+            LogNode node = getNode(name);
+            node.loggerRef = ref;
+            Logger parent = null;
+            LogNode nodep = node.parent;
+            while (nodep != null) {
+                LoggerWeakRef nodeRef = nodep.loggerRef;
+                if (nodeRef != null) {
+                    parent = nodeRef.get();
+                    if (parent != null) {
+                        break;
+                    }
+                }
+                nodep = nodep.parent;
+            }
+
+            if (parent != null) {
+                doSetParent(logger, parent);
+            }
+            // Walk over the children and tell them we are their new parent.
+            node.walkAndSetParent(logger);
+            // new LogNode is ready so tell the LoggerWeakRef about it
+            ref.setNode(node);
+            return true;
+        }
+
+        synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
+            namedLoggers.remove(name, ref);
+        }
+
+        synchronized Enumeration<String> getLoggerNames() {
+            // ensure that this context is properly initialized before
+            // returning logger names.
+            ensureInitialized();
+            return namedLoggers.keys();
+        }
+
+        // If logger.getUseParentHandlers() returns 'true' and any of the logger's
+        // parents have levels or handlers defined, make sure they are instantiated.
+        private void processParentHandlers(final Logger logger, final String name) {
+            final LogManager owner = getOwner();
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
+                public Void run() {
+                    if (logger != owner.rootLogger) {
+                        boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
+                        if (!useParent) {
+                            logger.setUseParentHandlers(false);
+                        }
+                    }
+                    return null;
+                }
+            });
+
+            int ix = 1;
+            for (;;) {
+                int ix2 = name.indexOf(".", ix);
+                if (ix2 < 0) {
+                    break;
+                }
+                String pname = name.substring(0, ix2);
+                if (owner.getProperty(pname + ".level") != null ||
+                    owner.getProperty(pname + ".handlers") != null) {
+                    // This pname has a level/handlers definition.
+                    // Make sure it exists.
+                    demandLogger(pname, null);
+                }
+                ix = ix2+1;
+            }
+        }
+
+        // Gets a node in our tree of logger nodes.
+        // If necessary, create it.
+        LogNode getNode(String name) {
+            if (name == null || name.equals("")) {
+                return root;
+            }
+            LogNode node = root;
+            while (name.length() > 0) {
+                int ix = name.indexOf(".");
+                String head;
+                if (ix > 0) {
+                    head = name.substring(0, ix);
+                    name = name.substring(ix + 1);
+                } else {
+                    head = name;
+                    name = "";
+                }
+                if (node.children == null) {
+                    node.children = new HashMap<>();
+                }
+                LogNode child = node.children.get(head);
+                if (child == null) {
+                    child = new LogNode(node, this);
+                    node.children.put(head, child);
+                }
+                node = child;
+            }
+            return node;
+        }
+    }
+
+    final class SystemLoggerContext extends LoggerContext {
+        // Add a system logger in the system context's namespace as well as
+        // in the LogManager's namespace if not exist so that there is only
+        // one single logger of the given name.  System loggers are visible
+        // to applications unless a logger of the same name has been added.
+        @Override
+        Logger demandLogger(String name, String resourceBundleName) {
+            Logger result = findLogger(name);
+            if (result == null) {
+                // only allocate the new system logger once
+                Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true);
+                do {
+                    if (addLocalLogger(newLogger)) {
+                        // We successfully added the new Logger that we
+                        // created above so return it without refetching.
+                        result = newLogger;
+                    } else {
+                        // We didn't add the new Logger that we created above
+                        // because another thread added a Logger with the same
+                        // name after our null check above and before our call
+                        // to addLogger(). We have to refetch the Logger because
+                        // addLogger() returns a boolean instead of the Logger
+                        // reference itself. However, if the thread that created
+                        // the other Logger is not holding a strong reference to
+                        // the other Logger, then it is possible for the other
+                        // Logger to be GC'ed after we saw it in addLogger() and
+                        // before we can refetch it. If it has been GC'ed then
+                        // we'll just loop around and try again.
+                        result = findLogger(name);
+                    }
+                } while (result == null);
+            }
+            return result;
+        }
+    }
+
+    // Add new per logger handlers.
+    // We need to raise privilege here. All our decisions will
+    // be made based on the logging configuration, which can
+    // only be modified by trusted code.
+    private void loadLoggerHandlers(final Logger logger, final String name,
+                                    final String handlersPropertyName)
+    {
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                String names[] = parseClassNames(handlersPropertyName);
+                for (int i = 0; i < names.length; i++) {
+                    String word = names[i];
+                    try {
+                        // Android-changed: Fall back from the system to the context classloader.
+                        // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                        Class<?> clz = getClassInstance(word);
+                        Handler hdl = (Handler) clz.newInstance();
+                        // Check if there is a property defining the
+                        // this handler's level.
+                        String levs = getProperty(word + ".level");
+                        if (levs != null) {
+                            Level l = Level.findLevel(levs);
+                            if (l != null) {
+                                hdl.setLevel(l);
+                            } else {
+                                // Probably a bad level. Drop through.
+                                System.err.println("Can't set level for " + word);
+                            }
+                        }
+                        // Add this Handler to the logger
+                        logger.addHandler(hdl);
+                    } catch (Exception ex) {
+                        System.err.println("Can't load log handler \"" + word + "\"");
+                        System.err.println("" + ex);
+                        ex.printStackTrace();
+                    }
+                }
+                return null;
+            }
+        });
+    }
+
+
+    // loggerRefQueue holds LoggerWeakRef objects for Logger objects
+    // that have been GC'ed.
+    private final ReferenceQueue<Logger> loggerRefQueue
+        = new ReferenceQueue<>();
+
+    // Package-level inner class.
+    // Helper class for managing WeakReferences to Logger objects.
+    //
+    // LogManager.namedLoggers
+    //     - has weak references to all named Loggers
+    //     - namedLoggers keeps the LoggerWeakRef objects for the named
+    //       Loggers around until we can deal with the book keeping for
+    //       the named Logger that is being GC'ed.
+    // LogManager.LogNode.loggerRef
+    //     - has a weak reference to a named Logger
+    //     - the LogNode will also keep the LoggerWeakRef objects for
+    //       the named Loggers around; currently LogNodes never go away.
+    // Logger.kids
+    //     - has a weak reference to each direct child Logger; this
+    //       includes anonymous and named Loggers
+    //     - anonymous Loggers are always children of the rootLogger
+    //       which is a strong reference; rootLogger.kids keeps the
+    //       LoggerWeakRef objects for the anonymous Loggers around
+    //       until we can deal with the book keeping.
+    //
+    final class LoggerWeakRef extends WeakReference<Logger> {
+        private String                name;       // for namedLoggers cleanup
+        private LogNode               node;       // for loggerRef cleanup
+        private WeakReference<Logger> parentRef;  // for kids cleanup
+        private boolean disposed = false;         // avoid calling dispose twice
+
+        LoggerWeakRef(Logger logger) {
+            super(logger, loggerRefQueue);
+
+            name = logger.getName();  // save for namedLoggers cleanup
+        }
+
+        // dispose of this LoggerWeakRef object
+        void dispose() {
+            // Avoid calling dispose twice. When a Logger is gc'ed, its
+            // LoggerWeakRef will be enqueued.
+            // However, a new logger of the same name may be added (or looked
+            // up) before the queue is drained. When that happens, dispose()
+            // will be called by addLocalLogger() or findLogger().
+            // Later when the queue is drained, dispose() will be called again
+            // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed
+            // avoids processing the data twice (even though the code should
+            // now be reentrant).
+            synchronized(this) {
+                // Note to maintainers:
+                // Be careful not to call any method that tries to acquire
+                // another lock from within this block - as this would surely
+                // lead to deadlocks, given that dispose() can be called by
+                // multiple threads, and from within different synchronized
+                // methods/blocks.
+                if (disposed) return;
+                disposed = true;
+            }
+
+            final LogNode n = node;
+            if (n != null) {
+                // n.loggerRef can only be safely modified from within
+                // a lock on LoggerContext. removeLoggerRef is already
+                // synchronized on LoggerContext so calling
+                // n.context.removeLoggerRef from within this lock is safe.
+                synchronized (n.context) {
+                    // if we have a LogNode, then we were a named Logger
+                    // so clear namedLoggers weak ref to us
+                    n.context.removeLoggerRef(name, this);
+                    name = null;  // clear our ref to the Logger's name
+
+                    // LogNode may have been reused - so only clear
+                    // LogNode.loggerRef if LogNode.loggerRef == this
+                    if (n.loggerRef == this) {
+                        n.loggerRef = null;  // clear LogNode's weak ref to us
+                    }
+                    node = null;            // clear our ref to LogNode
+                }
+            }
+
+            if (parentRef != null) {
+                // this LoggerWeakRef has or had a parent Logger
+                Logger parent = parentRef.get();
+                if (parent != null) {
+                    // the parent Logger is still there so clear the
+                    // parent Logger's weak ref to us
+                    parent.removeChildLogger(this);
+                }
+                parentRef = null;  // clear our weak ref to the parent Logger
+            }
+        }
+
+        // set the node field to the specified value
+        void setNode(LogNode node) {
+            this.node = node;
+        }
+
+        // set the parentRef field to the specified value
+        void setParentRef(WeakReference<Logger> parentRef) {
+            this.parentRef = parentRef;
+        }
+    }
+
+    // Package-level method.
+    // Drain some Logger objects that have been GC'ed.
+    //
+    // drainLoggerRefQueueBounded() is called by addLogger() below
+    // and by Logger.getAnonymousLogger(String) so we'll drain up to
+    // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
+    //
+    // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
+    // us about a 50/50 mix in increased weak ref counts versus
+    // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
+    // Here are stats for cleaning up sets of 400 anonymous Loggers:
+    //   - test duration 1 minute
+    //   - sample size of 125 sets of 400
+    //   - average: 1.99 ms
+    //   - minimum: 0.57 ms
+    //   - maximum: 25.3 ms
+    //
+    // The same config gives us a better decreased weak ref count
+    // than increased weak ref count in the LoggerWeakRefLeak test.
+    // Here are stats for cleaning up sets of 400 named Loggers:
+    //   - test duration 2 minutes
+    //   - sample size of 506 sets of 400
+    //   - average: 0.57 ms
+    //   - minimum: 0.02 ms
+    //   - maximum: 10.9 ms
+    //
+    private final static int MAX_ITERATIONS = 400;
+    final void drainLoggerRefQueueBounded() {
+        for (int i = 0; i < MAX_ITERATIONS; i++) {
+            if (loggerRefQueue == null) {
+                // haven't finished loading LogManager yet
+                break;
+            }
+
+            LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
+            if (ref == null) {
+                break;
+            }
+            // a Logger object has been GC'ed so clean it up
+            ref.dispose();
+        }
+    }
+
+    /**
+     * Add a named logger.  This does nothing and returns false if a logger
+     * with the same name is already registered.
+     * <p>
+     * The Logger factory methods call this method to register each
+     * newly created Logger.
+     * <p>
+     * The application should retain its own reference to the Logger
+     * object to avoid it being garbage collected.  The LogManager
+     * may only retain a weak reference.
+     *
+     * @param   logger the new logger.
+     * @return  true if the argument logger was registered successfully,
+     *          false if a logger of that name already exists.
+     * @exception NullPointerException if the logger name is null.
+     */
+    public boolean addLogger(Logger logger) {
+        final String name = logger.getName();
+        if (name == null) {
+            throw new NullPointerException();
+        }
+        drainLoggerRefQueueBounded();
+        LoggerContext cx = getUserContext();
+        if (cx.addLocalLogger(logger)) {
+            // Do we have a per logger handler too?
+            // Note: this will add a 200ms penalty
+            loadLoggerHandlers(logger, name, name + ".handlers");
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    // Private method to set a level on a logger.
+    // If necessary, we raise privilege before doing the call.
+    private static void doSetLevel(final Logger logger, final Level level) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            // There is no security manager, so things are easy.
+            logger.setLevel(level);
+            return;
+        }
+        // There is a security manager.  Raise privilege before
+        // calling setLevel.
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                logger.setLevel(level);
+                return null;
+            }});
+    }
+
+    // Private method to set a parent on a logger.
+    // If necessary, we raise privilege before doing the setParent call.
+    private static void doSetParent(final Logger logger, final Logger parent) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm == null) {
+            // There is no security manager, so things are easy.
+            logger.setParent(parent);
+            return;
+        }
+        // There is a security manager.  Raise privilege before
+        // calling setParent.
+        AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
+            public Object run() {
+                logger.setParent(parent);
+                return null;
+            }});
+    }
+
+    /**
+     * Method to find a named logger.
+     * <p>
+     * Note that since untrusted code may create loggers with
+     * arbitrary names this method should not be relied on to
+     * find Loggers for security sensitive logging.
+     * It is also important to note that the Logger associated with the
+     * String {@code name} may be garbage collected at any time if there
+     * is no strong reference to the Logger. The caller of this method
+     * must check the return value for null in order to properly handle
+     * the case where the Logger has been garbage collected.
+     * <p>
+     * @param name name of the logger
+     * @return  matching logger or null if none is found
+     */
+    public Logger getLogger(String name) {
+        return getUserContext().findLogger(name);
+    }
+
+    /**
+     * Get an enumeration of known logger names.
+     * <p>
+     * Note:  Loggers may be added dynamically as new classes are loaded.
+     * This method only reports on the loggers that are currently registered.
+     * It is also important to note that this method only returns the name
+     * of a Logger, not a strong reference to the Logger itself.
+     * The returned String does nothing to prevent the Logger from being
+     * garbage collected. In particular, if the returned name is passed
+     * to {@code LogManager.getLogger()}, then the caller must check the
+     * return value from {@code LogManager.getLogger()} for null to properly
+     * handle the case where the Logger has been garbage collected in the
+     * time since its name was returned by this method.
+     * <p>
+     * @return  enumeration of logger name strings
+     */
+    public Enumeration<String> getLoggerNames() {
+        return getUserContext().getLoggerNames();
+    }
+
+    /**
+     * Reinitialize the logging properties and reread the logging configuration.
+     * <p>
+     * The same rules are used for locating the configuration properties
+     * as are used at startup.  So normally the logging properties will
+     * be re-read from the same file that was used at startup.
+     * <P>
+     * Any log level definitions in the new configuration file will be
+     * applied using Logger.setLevel(), if the target Logger exists.
+     * <p>
+     * A PropertyChangeEvent will be fired after the properties are read.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception  IOException if there are IO problems reading the configuration.
+     */
+    public void readConfiguration() throws IOException, SecurityException {
+        checkPermission();
+
+        // if a configuration class is specified, load it and use it.
+        String cname = System.getProperty("java.util.logging.config.class");
+        if (cname != null) {
+            try {
+                // Instantiate the named class.  It is its constructor's
+                // responsibility to initialize the logging configuration, by
+                // calling readConfiguration(InputStream) with a suitable stream.
+                // Android-changed: Extract logic into the getClassInstance() helper.
+                getClassInstance(cname).newInstance();
+                return;
+            } catch (Exception ex) {
+                System.err.println("Logging configuration class \"" + cname + "\" failed");
+                System.err.println("" + ex);
+                // keep going and useful config file.
+            }
+        }
+
+        String fname = System.getProperty("java.util.logging.config.file");
+        if (fname == null) {
+            fname = System.getProperty("java.home");
+            if (fname == null) {
+                throw new Error("Can't find java.home ??");
+            }
+            File f = new File(fname, "lib");
+            f = new File(f, "logging.properties");
+            fname = f.getCanonicalPath();
+        }
+
+        // BEGIN Android-changed: Look in the boot class-path jar files for the logging.properties.
+        // It may not be present in the file system.
+        /*
+        try (final InputStream in = new FileInputStream(fname)) {
+            final BufferedInputStream bin = new BufferedInputStream(in);
+            readConfiguration(bin);
+        }
+        */
+        InputStream in;
+        try {
+            in = new FileInputStream(fname);
+        } catch (Exception e) {
+            in = LogManager.class.getResourceAsStream("logging.properties");
+            if (in == null) {
+                throw e;
+            }
+        }
+
+        BufferedInputStream bin = new BufferedInputStream(in);
+        try {
+            readConfiguration(bin);
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+        // END Android-changed: Look in the boot class-path jar files for the logging.properties.
+    }
+
+    /**
+     * Reset the logging configuration.
+     * <p>
+     * For all named loggers, the reset operation removes and closes
+     * all Handlers and (except for the root logger) sets the level
+     * to null.  The root logger's level is set to Level.INFO.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+
+    public void reset() throws SecurityException {
+        checkPermission();
+        synchronized (this) {
+            props = new Properties();
+            // Since we are doing a reset we no longer want to initialize
+            // the global handlers, if they haven't been initialized yet.
+            initializedGlobalHandlers = true;
+        }
+        for (LoggerContext cx : contexts()) {
+            Enumeration<String> enum_ = cx.getLoggerNames();
+            while (enum_.hasMoreElements()) {
+                String name = enum_.nextElement();
+                Logger logger = cx.findLogger(name);
+                if (logger != null) {
+                    resetLogger(logger);
+                }
+            }
+        }
+    }
+
+    // Private method to reset an individual target logger.
+    private void resetLogger(Logger logger) {
+        // Close all the Logger's handlers.
+        Handler[] targets = logger.getHandlers();
+        for (int i = 0; i < targets.length; i++) {
+            Handler h = targets[i];
+            logger.removeHandler(h);
+            try {
+                h.close();
+            } catch (Exception ex) {
+                // Problems closing a handler?  Keep going...
+            }
+        }
+        String name = logger.getName();
+        if (name != null && name.equals("")) {
+            // This is the root logger.
+            logger.setLevel(defaultLevel);
+        } else {
+            logger.setLevel(null);
+        }
+    }
+
+    // get a list of whitespace separated classnames from a property.
+    private String[] parseClassNames(String propertyName) {
+        String hands = getProperty(propertyName);
+        if (hands == null) {
+            return new String[0];
+        }
+        hands = hands.trim();
+        int ix = 0;
+        final List<String> result = new ArrayList<>();
+        while (ix < hands.length()) {
+            int end = ix;
+            while (end < hands.length()) {
+                if (Character.isWhitespace(hands.charAt(end))) {
+                    break;
+                }
+                if (hands.charAt(end) == ',') {
+                    break;
+                }
+                end++;
+            }
+            String word = hands.substring(ix, end);
+            ix = end+1;
+            word = word.trim();
+            if (word.length() == 0) {
+                continue;
+            }
+            result.add(word);
+        }
+        return result.toArray(new String[result.size()]);
+    }
+
+    /**
+     * Reinitialize the logging properties and reread the logging configuration
+     * from the given stream, which should be in java.util.Properties format.
+     * A PropertyChangeEvent will be fired after the properties are read.
+     * <p>
+     * Any log level definitions in the new configuration file will be
+     * applied using Logger.setLevel(), if the target Logger exists.
+     *
+     * @param ins       stream to read properties from
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     * @exception  IOException if there are problems reading from the stream.
+     */
+    public void readConfiguration(InputStream ins) throws IOException, SecurityException {
+        checkPermission();
+        reset();
+
+        // Load the properties
+        props.load(ins);
+        // Instantiate new configuration objects.
+        String names[] = parseClassNames("config");
+
+        for (int i = 0; i < names.length; i++) {
+            String word = names[i];
+            try {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
+                // clz.newInstance();
+                getClassInstance(word).newInstance();
+            } catch (Exception ex) {
+                System.err.println("Can't load config class \"" + word + "\"");
+                System.err.println("" + ex);
+                // ex.printStackTrace();
+            }
+        }
+
+        // Set levels on any pre-existing loggers, based on the new properties.
+        setLevelsOnExistingLoggers();
+
+        // Notify any interested parties that our properties have changed.
+        // We first take a copy of the listener map so that we aren't holding any
+        // locks when calling the listeners.
+        Map<Object,Integer> listeners = null;
+        synchronized (listenerMap) {
+            if (!listenerMap.isEmpty())
+                listeners = new HashMap<>(listenerMap);
+        }
+        if (listeners != null) {
+            assert Beans.isBeansPresent();
+            Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null);
+            for (Map.Entry<Object,Integer> entry : listeners.entrySet()) {
+                Object listener = entry.getKey();
+                int count = entry.getValue().intValue();
+                for (int i = 0; i < count; i++) {
+                    Beans.invokePropertyChange(listener, ev);
+                }
+            }
+        }
+
+
+        // Note that we need to reinitialize global handles when
+        // they are first referenced.
+        synchronized (this) {
+            initializedGlobalHandlers = false;
+        }
+    }
+
+    /**
+     * Get the value of a logging property.
+     * The method returns null if the property is not found.
+     * @param name      property name
+     * @return          property value
+     */
+    public String getProperty(String name) {
+        return props.getProperty(name);
+    }
+
+    // Package private method to get a String property.
+    // If the property is not defined we return the given
+    // default value.
+    String getStringProperty(String name, String defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        return val.trim();
+    }
+
+    // Package private method to get an integer property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    int getIntProperty(String name, int defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(val.trim());
+        } catch (Exception ex) {
+            return defaultValue;
+        }
+    }
+
+    // Package private method to get a boolean property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    boolean getBooleanProperty(String name, boolean defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        val = val.toLowerCase();
+        if (val.equals("true") || val.equals("1")) {
+            return true;
+        } else if (val.equals("false") || val.equals("0")) {
+            return false;
+        }
+        return defaultValue;
+    }
+
+    // Package private method to get a Level property.
+    // If the property is not defined or cannot be parsed
+    // we return the given default value.
+    Level getLevelProperty(String name, Level defaultValue) {
+        String val = getProperty(name);
+        if (val == null) {
+            return defaultValue;
+        }
+        Level l = Level.findLevel(val.trim());
+        return l != null ? l : defaultValue;
+    }
+
+    // Package private method to get a filter property.
+    // We return an instance of the class named by the "name"
+    // property. If the property is not defined or has problems
+    // we return the defaultValue.
+    Filter getFilterProperty(String name, Filter defaultValue) {
+        String val = getProperty(name);
+        try {
+            if (val != null) {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
+                // return (Filter) clz.newInstance();
+                return (Filter) getClassInstance(val).newInstance();
+            }
+        } catch (Exception ex) {
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
+        }
+        // We got an exception.  Return the defaultValue.
+        return defaultValue;
+    }
+
+
+    // Package private method to get a formatter property.
+    // We return an instance of the class named by the "name"
+    // property. If the property is not defined or has problems
+    // we return the defaultValue.
+    Formatter getFormatterProperty(String name, Formatter defaultValue) {
+        String val = getProperty(name);
+        try {
+            if (val != null) {
+                // Android-changed: Fall back from the system to the context classloader.
+                // Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
+                // return (Formatter) clz.newInstance();
+                return (Formatter) getClassInstance(val).newInstance();
+            }
+        } catch (Exception ex) {
+            // We got one of a variety of exceptions in creating the
+            // class or creating an instance.
+            // Drop through.
+        }
+        // We got an exception.  Return the defaultValue.
+        return defaultValue;
+    }
+
+    // Private method to load the global handlers.
+    // We do the real work lazily, when the global handlers
+    // are first used.
+    private synchronized void initializeGlobalHandlers() {
+        if (initializedGlobalHandlers) {
+            return;
+        }
+
+        initializedGlobalHandlers = true;
+
+        if (deathImminent) {
+            // Aaargh...
+            // The VM is shutting down and our exit hook has been called.
+            // Avoid allocating global handlers.
+            return;
+        }
+        loadLoggerHandlers(rootLogger, null, "handlers");
+    }
+
+    private final Permission controlPermission = new LoggingPermission("control", null);
+
+    void checkPermission() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null)
+            sm.checkPermission(controlPermission);
+    }
+
+    /**
+     * Check that the current context is trusted to modify the logging
+     * configuration.  This requires LoggingPermission("control").
+     * <p>
+     * If the check fails we throw a SecurityException, otherwise
+     * we return normally.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+    public void checkAccess() throws SecurityException {
+        checkPermission();
+    }
+
+    // Nested class to represent a node in our tree of named loggers.
+    private static class LogNode {
+        HashMap<String,LogNode> children;
+        LoggerWeakRef loggerRef;
+        LogNode parent;
+        final LoggerContext context;
+
+        LogNode(LogNode parent, LoggerContext context) {
+            this.parent = parent;
+            this.context = context;
+        }
+
+        // Recursive method to walk the tree below a node and set
+        // a new parent logger.
+        void walkAndSetParent(Logger parent) {
+            if (children == null) {
+                return;
+            }
+            Iterator<LogNode> values = children.values().iterator();
+            while (values.hasNext()) {
+                LogNode node = values.next();
+                LoggerWeakRef ref = node.loggerRef;
+                Logger logger = (ref == null) ? null : ref.get();
+                if (logger == null) {
+                    node.walkAndSetParent(parent);
+                } else {
+                    doSetParent(logger, parent);
+                }
+            }
+        }
+    }
+
+    // We use a subclass of Logger for the root logger, so
+    // that we only instantiate the global handlers when they
+    // are first needed.
+    private final class RootLogger extends Logger {
+        private RootLogger() {
+            // We do not call the protected Logger two args constructor here,
+            // to avoid calling LogManager.getLogManager() from within the
+            // RootLogger constructor.
+            super("", null, null, LogManager.this, true);
+        }
+
+        @Override
+        public void log(LogRecord record) {
+            // Make sure that the global handlers have been instantiated.
+            initializeGlobalHandlers();
+            super.log(record);
+        }
+
+        @Override
+        public void addHandler(Handler h) {
+            initializeGlobalHandlers();
+            super.addHandler(h);
+        }
+
+        @Override
+        public void removeHandler(Handler h) {
+            initializeGlobalHandlers();
+            super.removeHandler(h);
+        }
+
+        @Override
+        Handler[] accessCheckedHandlers() {
+            initializeGlobalHandlers();
+            return super.accessCheckedHandlers();
+        }
+    }
+
+
+    // Private method to be called when the configuration has
+    // changed to apply any level settings to any pre-existing loggers.
+    synchronized private void setLevelsOnExistingLoggers() {
+        Enumeration<?> enum_ = props.propertyNames();
+        while (enum_.hasMoreElements()) {
+            String key = (String)enum_.nextElement();
+            if (!key.endsWith(".level")) {
+                // Not a level definition.
+                continue;
+            }
+            int ix = key.length() - 6;
+            String name = key.substring(0, ix);
+            Level level = getLevelProperty(key, null);
+            if (level == null) {
+                System.err.println("Bad level value for property: " + key);
+                continue;
+            }
+            for (LoggerContext cx : contexts()) {
+                Logger l = cx.findLogger(name);
+                if (l == null) {
+                    continue;
+                }
+                l.setLevel(level);
+            }
+        }
+    }
+
+    // Management Support
+    private static LoggingMXBean loggingMXBean = null;
+    // Android-removed: References to java.lang.management in javadoc.
+    /**
+     * String representation of the {@code ObjectName} for the management interface
+     * for the logging facility.
+     *
+     * @see java.util.logging.LoggingMXBean
+     *
+     * @since 1.5
+     */
+    public final static String LOGGING_MXBEAN_NAME
+        = "java.util.logging:type=Logging";
+
+    // Android-removed: References to java.lang.management in javadoc.
+    /**
+     * Returns <tt>LoggingMXBean</tt> for managing loggers.
+     *
+     * @return a {@link LoggingMXBean} object.
+     *
+     * @since 1.5
+     */
+    public static synchronized LoggingMXBean getLoggingMXBean() {
+        if (loggingMXBean == null) {
+            loggingMXBean =  new Logging();
+        }
+        return loggingMXBean;
+    }
+
+    /**
+     * A class that provides access to the java.beans.PropertyChangeListener
+     * and java.beans.PropertyChangeEvent without creating a static dependency
+     * on java.beans. This class can be removed once the addPropertyChangeListener
+     * and removePropertyChangeListener methods are removed.
+     */
+    private static class Beans {
+        private static final Class<?> propertyChangeListenerClass =
+            getClass("java.beans.PropertyChangeListener");
+
+        private static final Class<?> propertyChangeEventClass =
+            getClass("java.beans.PropertyChangeEvent");
+
+        private static final Method propertyChangeMethod =
+            getMethod(propertyChangeListenerClass,
+                      "propertyChange",
+                      propertyChangeEventClass);
+
+        private static final Constructor<?> propertyEventCtor =
+            getConstructor(propertyChangeEventClass,
+                           Object.class,
+                           String.class,
+                           Object.class,
+                           Object.class);
+
+        private static Class<?> getClass(String name) {
+            try {
+                return Class.forName(name, true, Beans.class.getClassLoader());
+            } catch (ClassNotFoundException e) {
+                return null;
+            }
+        }
+        private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getDeclaredConstructor(types);
+            } catch (NoSuchMethodException x) {
+                throw new AssertionError(x);
+            }
+        }
+
+        private static Method getMethod(Class<?> c, String name, Class<?>... types) {
+            try {
+                return (c == null) ? null : c.getMethod(name, types);
+            } catch (NoSuchMethodException e) {
+                throw new AssertionError(e);
+            }
+        }
+
+        /**
+         * Returns {@code true} if java.beans is present.
+         */
+        static boolean isBeansPresent() {
+            return propertyChangeListenerClass != null &&
+                   propertyChangeEventClass != null;
+        }
+
+        /**
+         * Returns a new PropertyChangeEvent with the given source, property
+         * name, old and new values.
+         */
+        static Object newPropertyChangeEvent(Object source, String prop,
+                                             Object oldValue, Object newValue)
+        {
+            try {
+                return propertyEventCtor.newInstance(source, prop, oldValue, newValue);
+            } catch (InstantiationException | IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof Error)
+                    throw (Error)cause;
+                if (cause instanceof RuntimeException)
+                    throw (RuntimeException)cause;
+                throw new AssertionError(x);
+            }
+        }
+
+        /**
+         * Invokes the given PropertyChangeListener's propertyChange method
+         * with the given event.
+         */
+        static void invokePropertyChange(Object listener, Object ev) {
+            try {
+                propertyChangeMethod.invoke(listener, ev);
+            } catch (IllegalAccessException x) {
+                throw new AssertionError(x);
+            } catch (InvocationTargetException x) {
+                Throwable cause = x.getCause();
+                if (cause instanceof Error)
+                    throw (Error)cause;
+                if (cause instanceof RuntimeException)
+                    throw (RuntimeException)cause;
+                throw new AssertionError(x);
+            }
+        }
+    }
+}
diff --git a/java/util/logging/LogRecord.java b/java/util/logging/LogRecord.java
new file mode 100644
index 0000000..3b0e518
--- /dev/null
+++ b/java/util/logging/LogRecord.java
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+import dalvik.system.VMStack;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.io.*;
+
+/**
+ * LogRecord objects are used to pass logging requests between
+ * the logging framework and individual log Handlers.
+ * <p>
+ * When a LogRecord is passed into the logging framework it
+ * logically belongs to the framework and should no longer be
+ * used or updated by the client application.
+ * <p>
+ * Note that if the client application has not specified an
+ * explicit source method name and source class name, then the
+ * LogRecord class will infer them automatically when they are
+ * first accessed (due to a call on getSourceMethodName or
+ * getSourceClassName) by analyzing the call stack.  Therefore,
+ * if a logging Handler wants to pass off a LogRecord to another
+ * thread, or to transmit it over RMI, and if it wishes to subsequently
+ * obtain method name or class name information it should call
+ * one of getSourceClassName or getSourceMethodName to force
+ * the values to be filled in.
+ * <p>
+ * <b> Serialization notes:</b>
+ * <ul>
+ * <li>The LogRecord class is serializable.
+ *
+ * <li> Because objects in the parameters array may not be serializable,
+ * during serialization all objects in the parameters array are
+ * written as the corresponding Strings (using Object.toString).
+ *
+ * <li> The ResourceBundle is not transmitted as part of the serialized
+ * form, but the resource bundle name is, and the recipient object's
+ * readObject method will attempt to locate a suitable resource bundle.
+ *
+ * </ul>
+ *
+ * @since 1.4
+ */
+
+public class LogRecord implements java.io.Serializable {
+    private static final AtomicLong globalSequenceNumber
+        = new AtomicLong(0);
+
+    /**
+     * The default value of threadID will be the current thread's
+     * thread id, for ease of correlation, unless it is greater than
+     * MIN_SEQUENTIAL_THREAD_ID, in which case we try harder to keep
+     * our promise to keep threadIDs unique by avoiding collisions due
+     * to 32-bit wraparound.  Unfortunately, LogRecord.getThreadID()
+     * returns int, while Thread.getId() returns long.
+     */
+    private static final int MIN_SEQUENTIAL_THREAD_ID = Integer.MAX_VALUE / 2;
+
+    private static final AtomicInteger nextThreadId
+        = new AtomicInteger(MIN_SEQUENTIAL_THREAD_ID);
+
+    private static final ThreadLocal<Integer> threadIds = new ThreadLocal<>();
+
+    /**
+     * @serial Logging message level
+     */
+    private Level level;
+
+    /**
+     * @serial Sequence number
+     */
+    private long sequenceNumber;
+
+    /**
+     * @serial Class that issued logging call
+     */
+    private String sourceClassName;
+
+    /**
+     * @serial Method that issued logging call
+     */
+    private String sourceMethodName;
+
+    /**
+     * @serial Non-localized raw message text
+     */
+    private String message;
+
+    /**
+     * @serial Thread ID for thread that issued logging call.
+     */
+    private int threadID;
+
+    /**
+     * @serial Event time in milliseconds since 1970
+     */
+    private long millis;
+
+    /**
+     * @serial The Throwable (if any) associated with log message
+     */
+    private Throwable thrown;
+
+    /**
+     * @serial Name of the source Logger.
+     */
+    private String loggerName;
+
+    /**
+     * @serial Resource bundle name to localized log message.
+     */
+    private String resourceBundleName;
+
+    private transient boolean needToInferCaller;
+    private transient Object parameters[];
+    private transient ResourceBundle resourceBundle;
+
+    /**
+     * Returns the default value for a new LogRecord's threadID.
+     */
+    private int defaultThreadID() {
+        long tid = Thread.currentThread().getId();
+        if (tid < MIN_SEQUENTIAL_THREAD_ID) {
+            return (int) tid;
+        } else {
+            Integer id = threadIds.get();
+            if (id == null) {
+                id = nextThreadId.getAndIncrement();
+                threadIds.set(id);
+            }
+            return id;
+        }
+    }
+
+    /**
+     * Construct a LogRecord with the given level and message values.
+     * <p>
+     * The sequence property will be initialized with a new unique value.
+     * These sequence values are allocated in increasing order within a VM.
+     * <p>
+     * The millis property will be initialized to the current time.
+     * <p>
+     * The thread ID property will be initialized with a unique ID for
+     * the current thread.
+     * <p>
+     * All other properties will be initialized to "null".
+     *
+     * @param level  a logging level value
+     * @param msg  the raw non-localized logging message (may be null)
+     */
+    public LogRecord(Level level, String msg) {
+        // Make sure level isn't null, by calling random method.
+        level.getClass();
+        this.level = level;
+        message = msg;
+        // Assign a thread ID and a unique sequence number.
+        sequenceNumber = globalSequenceNumber.getAndIncrement();
+        threadID = defaultThreadID();
+        millis = System.currentTimeMillis();
+        needToInferCaller = true;
+   }
+
+    /**
+     * Get the source Logger's name.
+     *
+     * @return source logger name (may be null)
+     */
+    public String getLoggerName() {
+        return loggerName;
+    }
+
+    /**
+     * Set the source Logger's name.
+     *
+     * @param name   the source logger name (may be null)
+     */
+    public void setLoggerName(String name) {
+        loggerName = name;
+    }
+
+    /**
+     * Get the localization resource bundle
+     * <p>
+     * This is the ResourceBundle that should be used to localize
+     * the message string before formatting it.  The result may
+     * be null if the message is not localizable, or if no suitable
+     * ResourceBundle is available.
+     * @return the localization resource bundle
+     */
+    public ResourceBundle getResourceBundle() {
+        return resourceBundle;
+    }
+
+    /**
+     * Set the localization resource bundle.
+     *
+     * @param bundle  localization bundle (may be null)
+     */
+    public void setResourceBundle(ResourceBundle bundle) {
+        resourceBundle = bundle;
+    }
+
+    /**
+     * Get the localization resource bundle name
+     * <p>
+     * This is the name for the ResourceBundle that should be
+     * used to localize the message string before formatting it.
+     * The result may be null if the message is not localizable.
+     * @return the localization resource bundle name
+     */
+    public String getResourceBundleName() {
+        return resourceBundleName;
+    }
+
+    /**
+     * Set the localization resource bundle name.
+     *
+     * @param name  localization bundle name (may be null)
+     */
+    public void setResourceBundleName(String name) {
+        resourceBundleName = name;
+    }
+
+    /**
+     * Get the logging message level, for example Level.SEVERE.
+     * @return the logging message level
+     */
+    public Level getLevel() {
+        return level;
+    }
+
+    /**
+     * Set the logging message level, for example Level.SEVERE.
+     * @param level the logging message level
+     */
+    public void setLevel(Level level) {
+        if (level == null) {
+            throw new NullPointerException();
+        }
+        this.level = level;
+    }
+
+    /**
+     * Get the sequence number.
+     * <p>
+     * Sequence numbers are normally assigned in the LogRecord
+     * constructor, which assigns unique sequence numbers to
+     * each new LogRecord in increasing order.
+     * @return the sequence number
+     */
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    /**
+     * Set the sequence number.
+     * <p>
+     * Sequence numbers are normally assigned in the LogRecord constructor,
+     * so it should not normally be necessary to use this method.
+     * @param seq the sequence number
+     */
+    public void setSequenceNumber(long seq) {
+        sequenceNumber = seq;
+    }
+
+    /**
+     * Get the  name of the class that (allegedly) issued the logging request.
+     * <p>
+     * Note that this sourceClassName is not verified and may be spoofed.
+     * This information may either have been provided as part of the
+     * logging call, or it may have been inferred automatically by the
+     * logging framework.  In the latter case, the information may only
+     * be approximate and may in fact describe an earlier call on the
+     * stack frame.
+     * <p>
+     * May be null if no information could be obtained.
+     *
+     * @return the source class name
+     */
+    public String getSourceClassName() {
+        if (needToInferCaller) {
+            inferCaller();
+        }
+        return sourceClassName;
+    }
+
+    /**
+     * Set the name of the class that (allegedly) issued the logging request.
+     *
+     * @param sourceClassName the source class name (may be null)
+     */
+    public void setSourceClassName(String sourceClassName) {
+        this.sourceClassName = sourceClassName;
+        needToInferCaller = false;
+    }
+
+    /**
+     * Get the  name of the method that (allegedly) issued the logging request.
+     * <p>
+     * Note that this sourceMethodName is not verified and may be spoofed.
+     * This information may either have been provided as part of the
+     * logging call, or it may have been inferred automatically by the
+     * logging framework.  In the latter case, the information may only
+     * be approximate and may in fact describe an earlier call on the
+     * stack frame.
+     * <p>
+     * May be null if no information could be obtained.
+     *
+     * @return the source method name
+     */
+    public String getSourceMethodName() {
+        if (needToInferCaller) {
+            inferCaller();
+        }
+        return sourceMethodName;
+    }
+
+    /**
+     * Set the name of the method that (allegedly) issued the logging request.
+     *
+     * @param sourceMethodName the source method name (may be null)
+     */
+    public void setSourceMethodName(String sourceMethodName) {
+        this.sourceMethodName = sourceMethodName;
+        needToInferCaller = false;
+    }
+
+    /**
+     * Get the "raw" log message, before localization or formatting.
+     * <p>
+     * May be null, which is equivalent to the empty string "".
+     * <p>
+     * This message may be either the final text or a localization key.
+     * <p>
+     * During formatting, if the source logger has a localization
+     * ResourceBundle and if that ResourceBundle has an entry for
+     * this message string, then the message string is replaced
+     * with the localized value.
+     *
+     * @return the raw message string
+     */
+    public String getMessage() {
+        return message;
+    }
+
+    /**
+     * Set the "raw" log message, before localization or formatting.
+     *
+     * @param message the raw message string (may be null)
+     */
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    /**
+     * Get the parameters to the log message.
+     *
+     * @return the log message parameters.  May be null if
+     *                  there are no parameters.
+     */
+    public Object[] getParameters() {
+        return parameters;
+    }
+
+    /**
+     * Set the parameters to the log message.
+     *
+     * @param parameters the log message parameters. (may be null)
+     */
+    public void setParameters(Object parameters[]) {
+        this.parameters = parameters;
+    }
+
+    /**
+     * Get an identifier for the thread where the message originated.
+     * <p>
+     * This is a thread identifier within the Java VM and may or
+     * may not map to any operating system ID.
+     *
+     * @return thread ID
+     */
+    public int getThreadID() {
+        return threadID;
+    }
+
+    /**
+     * Set an identifier for the thread where the message originated.
+     * @param threadID  the thread ID
+     */
+    public void setThreadID(int threadID) {
+        this.threadID = threadID;
+    }
+
+    /**
+     * Get event time in milliseconds since 1970.
+     *
+     * @return event time in millis since 1970
+     */
+    public long getMillis() {
+        return millis;
+    }
+
+    /**
+     * Set event time.
+     *
+     * @param millis event time in millis since 1970
+     */
+    public void setMillis(long millis) {
+        this.millis = millis;
+    }
+
+    /**
+     * Get any throwable associated with the log record.
+     * <p>
+     * If the event involved an exception, this will be the
+     * exception object. Otherwise null.
+     *
+     * @return a throwable
+     */
+    public Throwable getThrown() {
+        return thrown;
+    }
+
+    /**
+     * Set a throwable associated with the log event.
+     *
+     * @param thrown  a throwable (may be null)
+     */
+    public void setThrown(Throwable thrown) {
+        this.thrown = thrown;
+    }
+
+    private static final long serialVersionUID = 5372048053134512534L;
+
+    /**
+     * @serialData Default fields, followed by a two byte version number
+     * (major byte, followed by minor byte), followed by information on
+     * the log record parameter array.  If there is no parameter array,
+     * then -1 is written.  If there is a parameter array (possible of zero
+     * length) then the array length is written as an integer, followed
+     * by String values for each parameter.  If a parameter is null, then
+     * a null String is written.  Otherwise the output of Object.toString()
+     * is written.
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        // We have to call defaultWriteObject first.
+        out.defaultWriteObject();
+
+        // Write our version number.
+        out.writeByte(1);
+        out.writeByte(0);
+        if (parameters == null) {
+            out.writeInt(-1);
+            return;
+        }
+        out.writeInt(parameters.length);
+        // Write string values for the parameters.
+        for (int i = 0; i < parameters.length; i++) {
+            if (parameters[i] == null) {
+                out.writeObject(null);
+            } else {
+                out.writeObject(parameters[i].toString());
+            }
+        }
+    }
+
+    private void readObject(ObjectInputStream in)
+                        throws IOException, ClassNotFoundException {
+        // We have to call defaultReadObject first.
+        in.defaultReadObject();
+
+        // Read version number.
+        byte major = in.readByte();
+        byte minor = in.readByte();
+        if (major != 1) {
+            throw new IOException("LogRecord: bad version: " + major + "." + minor);
+        }
+        int len = in.readInt();
+        if (len < -1) {
+            throw new NegativeArraySizeException();
+        } else if (len == -1) {
+            parameters = null;
+        } else if (len < 255) {
+            parameters = new Object[len];
+            for (int i = 0; i < parameters.length; i++) {
+                parameters[i] = in.readObject();
+            }
+        } else {
+            List<Object> params = new ArrayList<>(Math.min(len, 1024));
+            for (int i = 0; i < len; i++) {
+                params.add(in.readObject());
+            }
+            parameters = params.toArray(new Object[params.size()]);
+        }
+        // If necessary, try to regenerate the resource bundle.
+        if (resourceBundleName != null) {
+            try {
+                // use system class loader to ensure the ResourceBundle
+                // instance is a different instance than null loader uses
+                final ResourceBundle bundle =
+                        ResourceBundle.getBundle(resourceBundleName,
+                                Locale.getDefault(),
+                                ClassLoader.getSystemClassLoader());
+                resourceBundle = bundle;
+            } catch (MissingResourceException ex) {
+                // Android-changed: Fall back to context classloader before giving up.
+                /*
+                // This is not a good place to throw an exception,
+                // so we simply leave the resourceBundle null.
+                resourceBundle = null;
+                */
+                try {
+                    resourceBundle = ResourceBundle.getBundle(resourceBundleName, Locale.getDefault(),
+                            Thread.currentThread().getContextClassLoader());
+                } catch (MissingResourceException innerE){
+                    // This is not a good place to throw an exception,
+                    // so we simply leave the resourceBundle null.
+                    resourceBundle = null;
+                }
+            }
+        }
+
+        needToInferCaller = false;
+    }
+
+    // Private method to infer the caller's class and method names
+    private void inferCaller() {
+        needToInferCaller = false;
+        // BEGIN Android-changed: Use VMStack.getThreadStackTrace.
+        /*
+        JavaLangAccess access = SharedSecrets.getJavaLangAccess();
+        Throwable throwable = new Throwable();
+        int depth = access.getStackTraceDepth(throwable);
+        */
+        StackTraceElement[] stack = VMStack.getThreadStackTrace(Thread.currentThread());
+        int depth = stack.length;
+        // END Android-changed: Use VMStack.getThreadStackTrace.
+
+        boolean lookingForLogger = true;
+        for (int ix = 0; ix < depth; ix++) {
+            // Calling getStackTraceElement directly prevents the VM
+            // from paying the cost of building the entire stack frame.
+            //
+            // Android-changed: Use value from previous getThreadStackTrace call.
+            // StackTraceElement frame =
+            //     access.getStackTraceElement(throwable, ix);
+            StackTraceElement frame = stack[ix];
+            String cname = frame.getClassName();
+            boolean isLoggerImpl = isLoggerImplFrame(cname);
+            if (lookingForLogger) {
+                // Skip all frames until we have found the first logger frame.
+                if (isLoggerImpl) {
+                    lookingForLogger = false;
+                }
+            } else {
+                if (!isLoggerImpl) {
+                    // skip reflection call
+                    if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
+                       // We've found the relevant frame.
+                       setSourceClassName(cname);
+                       setSourceMethodName(frame.getMethodName());
+                       return;
+                    }
+                }
+            }
+        }
+        // We haven't found a suitable frame, so just punt.  This is
+        // OK as we are only committed to making a "best effort" here.
+    }
+
+    private boolean isLoggerImplFrame(String cname) {
+        // the log record could be created for a platform logger
+        return (cname.equals("java.util.logging.Logger") ||
+                cname.startsWith("java.util.logging.LoggingProxyImpl") ||
+                cname.startsWith("sun.util.logging."));
+    }
+}
diff --git a/java/util/logging/Logger.annotated.java b/java/util/logging/Logger.annotated.java
new file mode 100644
index 0000000..f3a25cb
--- /dev/null
+++ b/java/util/logging/Logger.annotated.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+package java.util.logging;
+
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.function.Supplier;
+import java.util.MissingResourceException;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class Logger {
+
+protected Logger(@libcore.util.Nullable java.lang.String name, @libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.util.logging.Logger getGlobal() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getLogger(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getLogger(@libcore.util.NonNull java.lang.String name, @libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getAnonymousLogger() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.logging.Logger getAnonymousLogger(@libcore.util.Nullable java.lang.String resourceBundleName) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.ResourceBundle getResourceBundle() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getResourceBundleName() { throw new RuntimeException("Stub!"); }
+
+public void setFilter(@libcore.util.Nullable java.util.logging.Filter newFilter) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.logging.Filter getFilter() { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.LogRecord record) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void log(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.Throwable thrown, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void logp(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Throwable thrown, @libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.util.ResourceBundle bundle, @libcore.util.Nullable java.lang.String msg, [email protected] Object @libcore.util.Nullable ... params) { throw new RuntimeException("Stub!"); }
+
+@Deprecated
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.String bundleName, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void logrb(@libcore.util.NonNull java.util.logging.Level level, @libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.util.ResourceBundle bundle, @libcore.util.Nullable java.lang.String msg, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void entering(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod) { throw new RuntimeException("Stub!"); }
+
+public void entering(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Object param1) { throw new RuntimeException("Stub!"); }
+
+public void entering(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, [email protected] Object @libcore.util.Nullable [] params) { throw new RuntimeException("Stub!"); }
+
+public void exiting(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod) { throw new RuntimeException("Stub!"); }
+
+public void exiting(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Object result) { throw new RuntimeException("Stub!"); }
+
+public void throwing(@libcore.util.Nullable java.lang.String sourceClass, @libcore.util.Nullable java.lang.String sourceMethod, @libcore.util.Nullable java.lang.Throwable thrown) { throw new RuntimeException("Stub!"); }
+
+public void severe(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void warning(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void info(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void config(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void fine(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void finer(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void finest(@libcore.util.Nullable java.lang.String msg) { throw new RuntimeException("Stub!"); }
+
+public void severe(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void warning(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void info(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void config(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void fine(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void finer(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void finest(@libcore.util.NonNull java.util.function.Supplier<[email protected] String> msgSupplier) { throw new RuntimeException("Stub!"); }
+
+public void setLevel(@libcore.util.Nullable java.util.logging.Level newLevel) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.logging.Level getLevel() { throw new RuntimeException("Stub!"); }
+
+public boolean isLoggable(@libcore.util.NonNull java.util.logging.Level level) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public void addHandler(@libcore.util.NonNull java.util.logging.Handler handler) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public void removeHandler(@libcore.util.Nullable java.util.logging.Handler handler) throws java.lang.SecurityException { throw new RuntimeException("Stub!"); }
+
+public [email protected] Handler @libcore.util.NonNull [] getHandlers() { throw new RuntimeException("Stub!"); }
+
+public void setUseParentHandlers(boolean useParentHandlers) { throw new RuntimeException("Stub!"); }
+
+public boolean getUseParentHandlers() { throw new RuntimeException("Stub!"); }
+
+public void setResourceBundle(@libcore.util.NonNull java.util.ResourceBundle bundle) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.logging.Logger getParent() { throw new RuntimeException("Stub!"); }
+
+public void setParent(@libcore.util.NonNull java.util.logging.Logger parent) { throw new RuntimeException("Stub!"); }
+
[email protected] public static final java.lang.String GLOBAL_LOGGER_NAME = "global";
+
+@Deprecated @libcore.util.NonNull public static final java.util.logging.Logger global;
+static { global = null; }
+}
diff --git a/java/util/logging/Logger.java b/java/util/logging/Logger.java
new file mode 100644
index 0000000..61bbe4e
--- /dev/null
+++ b/java/util/logging/Logger.java
@@ -0,0 +1,2188 @@
+/*
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.lang.ref.WeakReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
+/**
+ * A Logger object is used to log messages for a specific
+ * system or application component.  Loggers are normally named,
+ * using a hierarchical dot-separated namespace.  Logger names
+ * can be arbitrary strings, but they should normally be based on
+ * the package name or class name of the logged component, such
+ * as java.net or javax.swing.  In addition it is possible to create
+ * "anonymous" Loggers that are not stored in the Logger namespace.
+ * <p>
+ * Logger objects may be obtained by calls on one of the getLogger
+ * factory methods.  These will either create a new Logger or
+ * return a suitable existing Logger. It is important to note that
+ * the Logger returned by one of the {@code getLogger} factory methods
+ * may be garbage collected at any time if a strong reference to the
+ * Logger is not kept.
+ * <p>
+ * Logging messages will be forwarded to registered Handler
+ * objects, which can forward the messages to a variety of
+ * destinations, including consoles, files, OS logs, etc.
+ * <p>
+ * Each Logger keeps track of a "parent" Logger, which is its
+ * nearest existing ancestor in the Logger namespace.
+ * <p>
+ * Each Logger has a "Level" associated with it.  This reflects
+ * a minimum Level that this logger cares about.  If a Logger's
+ * level is set to <tt>null</tt>, then its effective level is inherited
+ * from its parent, which may in turn obtain it recursively from its
+ * parent, and so on up the tree.
+ * <p>
+ * The log level can be configured based on the properties from the
+ * logging configuration file, as described in the description
+ * of the LogManager class.  However it may also be dynamically changed
+ * by calls on the Logger.setLevel method.  If a logger's level is
+ * changed the change may also affect child loggers, since any child
+ * logger that has <tt>null</tt> as its level will inherit its
+ * effective level from its parent.
+ * <p>
+ * On each logging call the Logger initially performs a cheap
+ * check of the request level (e.g., SEVERE or FINE) against the
+ * effective log level of the logger.  If the request level is
+ * lower than the log level, the logging call returns immediately.
+ * <p>
+ * After passing this initial (cheap) test, the Logger will allocate
+ * a LogRecord to describe the logging message.  It will then call a
+ * Filter (if present) to do a more detailed check on whether the
+ * record should be published.  If that passes it will then publish
+ * the LogRecord to its output Handlers.  By default, loggers also
+ * publish to their parent's Handlers, recursively up the tree.
+ * <p>
+ * Each Logger may have a {@code ResourceBundle} associated with it.
+ * The {@code ResourceBundle} may be specified by name, using the
+ * {@link #getLogger(java.lang.String, java.lang.String)} factory
+ * method, or by value - using the {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
+ * This bundle will be used for localizing logging messages.
+ * If a Logger does not have its own {@code ResourceBundle} or resource bundle
+ * name, then it will inherit the {@code ResourceBundle} or resource bundle name
+ * from its parent, recursively up the tree.
+ * <p>
+ * Most of the logger output methods take a "msg" argument.  This
+ * msg argument may be either a raw value or a localization key.
+ * During formatting, if the logger has (or inherits) a localization
+ * {@code ResourceBundle} and if the {@code ResourceBundle} has a mapping for
+ * the msg string, then the msg string is replaced by the localized value.
+ * Otherwise the original msg string is used.  Typically, formatters use
+ * java.text.MessageFormat style formatting to format parameters, so
+ * for example a format string "{0} {1}" would format two parameters
+ * as strings.
+ * <p>
+ * A set of methods alternatively take a "msgSupplier" instead of a "msg"
+ * argument.  These methods take a {@link Supplier}{@code <String>} function
+ * which is invoked to construct the desired log message only when the message
+ * actually is to be logged based on the effective log level thus eliminating
+ * unnecessary message construction. For example, if the developer wants to
+ * log system health status for diagnosis, with the String-accepting version,
+ * the code would look like:
+ <pre><code>
+
+   class DiagnosisMessages {
+     static String systemHealthStatus() {
+       // collect system health information
+       ...
+     }
+   }
+   ...
+   logger.log(Level.FINER, DiagnosisMessages.systemHealthStatus());
+</code></pre>
+ * With the above code, the health status is collected unnecessarily even when
+ * the log level FINER is disabled. With the Supplier-accepting version as
+ * below, the status will only be collected when the log level FINER is
+ * enabled.
+ <pre><code>
+
+   logger.log(Level.FINER, DiagnosisMessages::systemHealthStatus);
+</code></pre>
+ * <p>
+ * When looking for a {@code ResourceBundle}, the logger will first look at
+ * whether a bundle was specified using {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle}, and then
+ * only whether a resource bundle name was specified through the {@link
+ * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
+ * If no {@code ResourceBundle} or no resource bundle name is found,
+ * then it will use the nearest {@code ResourceBundle} or resource bundle
+ * name inherited from its parent tree.<br>
+ * When a {@code ResourceBundle} was inherited or specified through the
+ * {@link
+ * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method, then
+ * that {@code ResourceBundle} will be used. Otherwise if the logger only
+ * has or inherited a resource bundle name, then that resource bundle name
+ * will be mapped to a {@code ResourceBundle} object, using the default Locale
+ * at the time of logging.
+ * <br id="ResourceBundleMapping">When mapping resource bundle names to
+ * {@code ResourceBundle} objects, the logger will first try to use the
+ * Thread's {@linkplain java.lang.Thread#getContextClassLoader() context class
+ * loader} to map the given resource bundle name to a {@code ResourceBundle}.
+ * If the thread context class loader is {@code null}, it will try the
+ * {@linkplain java.lang.ClassLoader#getSystemClassLoader() system class loader}
+ * instead.  If the {@code ResourceBundle} is still not found, it will use the
+ * class loader of the first caller of the {@link
+ * #getLogger(java.lang.String, java.lang.String) getLogger} factory method.
+ * <p>
+ * Formatting (including localization) is the responsibility of
+ * the output Handler, which will typically call a Formatter.
+ * <p>
+ * Note that formatting need not occur synchronously.  It may be delayed
+ * until a LogRecord is actually written to an external sink.
+ * <p>
+ * The logging methods are grouped in five main categories:
+ * <ul>
+ * <li><p>
+ *     There are a set of "log" methods that take a log level, a message
+ *     string, and optionally some parameters to the message string.
+ * <li><p>
+ *     There are a set of "logp" methods (for "log precise") that are
+ *     like the "log" methods, but also take an explicit source class name
+ *     and method name.
+ * <li><p>
+ *     There are a set of "logrb" method (for "log with resource bundle")
+ *     that are like the "logp" method, but also take an explicit resource
+ *     bundle object for use in localizing the log message.
+ * <li><p>
+ *     There are convenience methods for tracing method entries (the
+ *     "entering" methods), method returns (the "exiting" methods) and
+ *     throwing exceptions (the "throwing" methods).
+ * <li><p>
+ *     Finally, there are a set of convenience methods for use in the
+ *     very simplest cases, when a developer simply wants to log a
+ *     simple string at a given log level.  These methods are named
+ *     after the standard Level names ("severe", "warning", "info", etc.)
+ *     and take a single argument, a message string.
+ * </ul>
+ * <p>
+ * For the methods that do not take an explicit source name and
+ * method name, the Logging framework will make a "best effort"
+ * to determine which class and method called into the logging method.
+ * However, it is important to realize that this automatically inferred
+ * information may only be approximate (or may even be quite wrong!).
+ * Virtual machines are allowed to do extensive optimizations when
+ * JITing and may entirely remove stack frames, making it impossible
+ * to reliably locate the calling class and method.
+ * <P>
+ * All methods on Logger are multi-thread safe.
+ * <p>
+ * <b>Subclassing Information:</b> Note that a LogManager class may
+ * provide its own implementation of named Loggers for any point in
+ * the namespace.  Therefore, any subclasses of Logger (unless they
+ * are implemented in conjunction with a new LogManager class) should
+ * take care to obtain a Logger instance from the LogManager class and
+ * should delegate operations such as "isLoggable" and "log(LogRecord)"
+ * to that instance.  Note that in order to intercept all logging
+ * output, subclasses need only override the log(LogRecord) method.
+ * All the other logging methods are implemented as calls on this
+ * log(LogRecord) method.
+ *
+ * @since 1.4
+ */
+public class Logger {
+    private static final Handler emptyHandlers[] = new Handler[0];
+    private static final int offValue = Level.OFF.intValue();
+
+    static final String SYSTEM_LOGGER_RB_NAME = "sun.util.logging.resources.logging";
+
+    // This class is immutable and it is important that it remains so.
+    private static final class LoggerBundle {
+        final String resourceBundleName; // Base name of the bundle.
+        final ResourceBundle userBundle; // Bundle set through setResourceBundle.
+        private LoggerBundle(String resourceBundleName, ResourceBundle bundle) {
+            this.resourceBundleName = resourceBundleName;
+            this.userBundle = bundle;
+        }
+        boolean isSystemBundle() {
+            return SYSTEM_LOGGER_RB_NAME.equals(resourceBundleName);
+        }
+        static LoggerBundle get(String name, ResourceBundle bundle) {
+            if (name == null && bundle == null) {
+                return NO_RESOURCE_BUNDLE;
+            } else if (SYSTEM_LOGGER_RB_NAME.equals(name) && bundle == null) {
+                return SYSTEM_BUNDLE;
+            } else {
+                return new LoggerBundle(name, bundle);
+            }
+        }
+    }
+
+    // This instance will be shared by all loggers created by the system
+    // code
+    private static final LoggerBundle SYSTEM_BUNDLE =
+            new LoggerBundle(SYSTEM_LOGGER_RB_NAME, null);
+
+    // This instance indicates that no resource bundle has been specified yet,
+    // and it will be shared by all loggers which have no resource bundle.
+    private static final LoggerBundle NO_RESOURCE_BUNDLE =
+            new LoggerBundle(null, null);
+
+    private volatile LogManager manager;
+    private String name;
+    private final CopyOnWriteArrayList<Handler> handlers =
+        new CopyOnWriteArrayList<>();
+    private volatile LoggerBundle loggerBundle = NO_RESOURCE_BUNDLE;
+    private volatile boolean useParentHandlers = true;
+    private volatile Filter filter;
+    private boolean anonymous;
+
+    // Cache to speed up behavior of findResourceBundle:
+    private ResourceBundle catalog;     // Cached resource bundle
+    private String catalogName;         // name associated with catalog
+    private Locale catalogLocale;       // locale associated with catalog
+
+    // The fields relating to parent-child relationships and levels
+    // are managed under a separate lock, the treeLock.
+    private static final Object treeLock = new Object();
+    // We keep weak references from parents to children, but strong
+    // references from children to parents.
+    private volatile Logger parent;    // our nearest parent.
+    private ArrayList<LogManager.LoggerWeakRef> kids;   // WeakReferences to loggers that have us as parent
+    private volatile Level levelObject;
+    private volatile int levelValue;  // current effective level value
+    private WeakReference<ClassLoader> callersClassLoaderRef;
+    private final boolean isSystemLogger;
+
+    /**
+     * GLOBAL_LOGGER_NAME is a name for the global logger.
+     *
+     * @since 1.6
+     */
+    public static final String GLOBAL_LOGGER_NAME = "global";
+
+    /**
+     * Return global logger object with the name Logger.GLOBAL_LOGGER_NAME.
+     *
+     * @return global logger object
+     * @since 1.7
+     */
+    public static final Logger getGlobal() {
+        // In order to break a cyclic dependence between the LogManager
+        // and Logger static initializers causing deadlocks, the global
+        // logger is created with a special constructor that does not
+        // initialize its log manager.
+        //
+        // If an application calls Logger.getGlobal() before any logger
+        // has been initialized, it is therefore possible that the
+        // LogManager class has not been initialized yet, and therefore
+        // Logger.global.manager will be null.
+        //
+        // In order to finish the initialization of the global logger, we
+        // will therefore call LogManager.getLogManager() here.
+        //
+        // To prevent race conditions we also need to call
+        // LogManager.getLogManager() unconditionally here.
+        // Indeed we cannot rely on the observed value of global.manager,
+        // because global.manager will become not null somewhere during
+        // the initialization of LogManager.
+        // If two threads are calling getGlobal() concurrently, one thread
+        // will see global.manager null and call LogManager.getLogManager(),
+        // but the other thread could come in at a time when global.manager
+        // is already set although ensureLogManagerInitialized is not finished
+        // yet...
+        // Calling LogManager.getLogManager() unconditionally will fix that.
+
+        LogManager.getLogManager();
+
+        // Now the global LogManager should be initialized,
+        // and the global logger should have been added to
+        // it, unless we were called within the constructor of a LogManager
+        // subclass installed as LogManager, in which case global.manager
+        // would still be null, and global will be lazily initialized later on.
+
+        return global;
+    }
+
+    /**
+     * The "global" Logger object is provided as a convenience to developers
+     * who are making casual use of the Logging package.  Developers
+     * who are making serious use of the logging package (for example
+     * in products) should create and use their own Logger objects,
+     * with appropriate names, so that logging can be controlled on a
+     * suitable per-Logger granularity. Developers also need to keep a
+     * strong reference to their Logger objects to prevent them from
+     * being garbage collected.
+     * <p>
+     * @deprecated Initialization of this field is prone to deadlocks.
+     * The field must be initialized by the Logger class initialization
+     * which may cause deadlocks with the LogManager class initialization.
+     * In such cases two class initialization wait for each other to complete.
+     * The preferred way to get the global logger object is via the call
+     * <code>Logger.getGlobal()</code>.
+     * For compatibility with old JDK versions where the
+     * <code>Logger.getGlobal()</code> is not available use the call
+     * <code>Logger.getLogger(Logger.GLOBAL_LOGGER_NAME)</code>
+     * or <code>Logger.getLogger("global")</code>.
+     */
+    @Deprecated
+    public static final Logger global = new Logger(GLOBAL_LOGGER_NAME);
+
+    /**
+     * Protected method to construct a logger for a named subsystem.
+     * <p>
+     * The logger will be initially configured with a null Level
+     * and with useParentHandlers set to true.
+     *
+     * @param   name    A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing.  It may be null for anonymous Loggers.
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger.  May be null if none
+     *                          of the messages require localization.
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     */
+    protected Logger(String name, String resourceBundleName) {
+        this(name, resourceBundleName, null, LogManager.getLogManager(), false);
+    }
+
+    Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager, boolean isSystemLogger) {
+        this.manager = manager;
+        this.isSystemLogger = isSystemLogger;
+        setupResourceInfo(resourceBundleName, caller);
+        this.name = name;
+        levelValue = Level.INFO.intValue();
+    }
+
+    private void setCallersClassLoaderRef(Class<?> caller) {
+        ClassLoader callersClassLoader = ((caller != null)
+                                         ? caller.getClassLoader()
+                                         : null);
+        if (callersClassLoader != null) {
+            this.callersClassLoaderRef = new WeakReference<>(callersClassLoader);
+        }
+    }
+
+    private ClassLoader getCallersClassLoader() {
+        return (callersClassLoaderRef != null)
+                ? callersClassLoaderRef.get()
+                : null;
+    }
+
+    // This constructor is used only to create the global Logger.
+    // It is needed to break a cyclic dependence between the LogManager
+    // and Logger static initializers causing deadlocks.
+    private Logger(String name) {
+        // The manager field is not initialized here.
+        this.name = name;
+        this.isSystemLogger = true;
+        levelValue = Level.INFO.intValue();
+    }
+
+    // It is called from LoggerContext.addLocalLogger() when the logger
+    // is actually added to a LogManager.
+    void setLogManager(LogManager manager) {
+        this.manager = manager;
+    }
+
+    private void checkPermission() throws SecurityException {
+        if (!anonymous) {
+            if (manager == null) {
+                // Complete initialization of the global Logger.
+                manager = LogManager.getLogManager();
+            }
+            manager.checkPermission();
+        }
+    }
+
+    // Until all JDK code converted to call sun.util.logging.PlatformLogger
+    // (see 7054233), we need to determine if Logger.getLogger is to add
+    // a system logger or user logger.
+    //
+    // As an interim solution, if the immediate caller whose caller loader is
+    // null, we assume it's a system logger and add it to the system context.
+    // These system loggers only set the resource bundle to the given
+    // resource bundle name (rather than the default system resource bundle).
+    private static class SystemLoggerHelper {
+        static boolean disableCallerCheck = getBooleanProperty("sun.util.logging.disableCallerCheck");
+        private static boolean getBooleanProperty(final String key) {
+            String s = AccessController.doPrivileged(new PrivilegedAction<String>() {
+                @Override
+                public String run() {
+                    return System.getProperty(key);
+                }
+            });
+            return Boolean.valueOf(s);
+        }
+    }
+
+    private static Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
+        LogManager manager = LogManager.getLogManager();
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
+            if (caller.getClassLoader() == null) {
+                return manager.demandSystemLogger(name, resourceBundleName);
+            }
+        }
+        return manager.demandLogger(name, resourceBundleName, caller);
+        // ends up calling new Logger(name, resourceBundleName, caller)
+        // iff the logger doesn't exist already
+    }
+
+    /**
+     * Find or create a logger for a named subsystem.  If a logger has
+     * already been created with the given name it is returned.  Otherwise
+     * a new logger is created.
+     * <p>
+     * If a new logger is created its log level will be configured
+     * based on the LogManager configuration and it will configured
+     * to also send logging output to its parent's Handlers.  It will
+     * be registered in the LogManager global namespace.
+     * <p>
+     * Note: The LogManager may only retain a weak reference to the newly
+     * created Logger. It is important to understand that a previously
+     * created Logger with the given name may be garbage collected at any
+     * time if there is no strong reference to the Logger. In particular,
+     * this means that two back-to-back calls like
+     * {@code getLogger("MyLogger").log(...)} may use different Logger
+     * objects named "MyLogger" if there is no strong reference to the
+     * Logger named "MyLogger" elsewhere in the program.
+     *
+     * @param   name            A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing
+     * @return a suitable Logger
+     * @throws NullPointerException if the name is null.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
+    public static Logger getLogger(String name) {
+        // This method is intentionally not a wrapper around a call
+        // to getLogger(name, resourceBundleName). If it were then
+        // this sequence:
+        //
+        //     getLogger("Foo", "resourceBundleForFoo");
+        //     getLogger("Foo");
+        //
+        // would throw an IllegalArgumentException in the second call
+        // because the wrapper would result in an attempt to replace
+        // the existing "resourceBundleForFoo" with null.
+        return demandLogger(name, null, Reflection.getCallerClass());
+    }
+
+    /**
+     * Find or create a logger for a named subsystem.  If a logger has
+     * already been created with the given name it is returned.  Otherwise
+     * a new logger is created.
+     * <p>
+     * If a new logger is created its log level will be configured
+     * based on the LogManager and it will configured to also send logging
+     * output to its parent's Handlers.  It will be registered in
+     * the LogManager global namespace.
+     * <p>
+     * Note: The LogManager may only retain a weak reference to the newly
+     * created Logger. It is important to understand that a previously
+     * created Logger with the given name may be garbage collected at any
+     * time if there is no strong reference to the Logger. In particular,
+     * this means that two back-to-back calls like
+     * {@code getLogger("MyLogger", ...).log(...)} may use different Logger
+     * objects named "MyLogger" if there is no strong reference to the
+     * Logger named "MyLogger" elsewhere in the program.
+     * <p>
+     * If the named Logger already exists and does not yet have a
+     * localization resource bundle then the given resource bundle
+     * name is used.  If the named Logger already exists and has
+     * a different resource bundle name then an IllegalArgumentException
+     * is thrown.
+     * <p>
+     * @param   name    A name for the logger.  This should
+     *                          be a dot-separated name and should normally
+     *                          be based on the package name or class name
+     *                          of the subsystem, such as java.net
+     *                          or javax.swing
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger. May be {@code null}
+     *                          if none of the messages require localization.
+     * @return a suitable Logger
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     * @throws IllegalArgumentException if the Logger already exists and uses
+     *             a different resource bundle name; or if
+     *             {@code resourceBundleName} is {@code null} but the named
+     *             logger has a resource bundle set.
+     * @throws NullPointerException if the name is null.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new Logger object is handled by LogManager.addLogger().
+    @CallerSensitive
+    public static Logger getLogger(String name, String resourceBundleName) {
+        Class<?> callerClass = Reflection.getCallerClass();
+        Logger result = demandLogger(name, resourceBundleName, callerClass);
+
+        // MissingResourceException or IllegalArgumentException can be
+        // thrown by setupResourceInfo().
+        // We have to set the callers ClassLoader here in case demandLogger
+        // above found a previously created Logger.  This can happen, for
+        // example, if Logger.getLogger(name) is called and subsequently
+        // Logger.getLogger(name, resourceBundleName) is called.  In this case
+        // we won't necessarily have the correct classloader saved away, so
+        // we need to set it here, too.
+
+        result.setupResourceInfo(resourceBundleName, callerClass);
+        return result;
+    }
+
+    // package-private
+    // Add a platform logger to the system context.
+    // i.e. caller of sun.util.logging.PlatformLogger.getLogger
+    static Logger getPlatformLogger(String name) {
+        LogManager manager = LogManager.getLogManager();
+
+        // all loggers in the system context will default to
+        // the system logger's resource bundle
+        Logger result = manager.demandSystemLogger(name, SYSTEM_LOGGER_RB_NAME);
+        return result;
+    }
+
+    /**
+     * Create an anonymous Logger.  The newly created Logger is not
+     * registered in the LogManager namespace.  There will be no
+     * access checks on updates to the logger.
+     * <p>
+     * This factory method is primarily intended for use from applets.
+     * Because the resulting Logger is anonymous it can be kept private
+     * by the creating class.  This removes the need for normal security
+     * checks, which in turn allows untrusted applet code to update
+     * the control state of the Logger.  For example an applet can do
+     * a setLevel or an addHandler on an anonymous Logger.
+     * <p>
+     * Even although the new logger is anonymous, it is configured
+     * to have the root logger ("") as its parent.  This means that
+     * by default it inherits its effective level and handlers
+     * from the root logger. Changing its parent via the
+     * {@link #setParent(java.util.logging.Logger) setParent} method
+     * will still require the security permission specified by that method.
+     * <p>
+     *
+     * @return a newly created private Logger
+     */
+    public static Logger getAnonymousLogger() {
+        return getAnonymousLogger(null);
+    }
+
+    /**
+     * Create an anonymous Logger.  The newly created Logger is not
+     * registered in the LogManager namespace.  There will be no
+     * access checks on updates to the logger.
+     * <p>
+     * This factory method is primarily intended for use from applets.
+     * Because the resulting Logger is anonymous it can be kept private
+     * by the creating class.  This removes the need for normal security
+     * checks, which in turn allows untrusted applet code to update
+     * the control state of the Logger.  For example an applet can do
+     * a setLevel or an addHandler on an anonymous Logger.
+     * <p>
+     * Even although the new logger is anonymous, it is configured
+     * to have the root logger ("") as its parent.  This means that
+     * by default it inherits its effective level and handlers
+     * from the root logger.  Changing its parent via the
+     * {@link #setParent(java.util.logging.Logger) setParent} method
+     * will still require the security permission specified by that method.
+     * <p>
+     * @param   resourceBundleName  name of ResourceBundle to be used for localizing
+     *                          messages for this logger.
+     *          May be null if none of the messages require localization.
+     * @return a newly created private Logger
+     * @throws MissingResourceException if the resourceBundleName is non-null and
+     *             no corresponding resource can be found.
+     */
+
+    // Synchronization is not required here. All synchronization for
+    // adding a new anonymous Logger object is handled by doSetParent().
+    @CallerSensitive
+    public static Logger getAnonymousLogger(String resourceBundleName) {
+        LogManager manager = LogManager.getLogManager();
+        // cleanup some Loggers that have been GC'ed
+        manager.drainLoggerRefQueueBounded();
+        Logger result = new Logger(null, resourceBundleName,
+                                   Reflection.getCallerClass(), manager, false);
+        result.anonymous = true;
+        Logger root = manager.getLogger("");
+        result.doSetParent(root);
+        return result;
+    }
+
+    /**
+     * Retrieve the localization resource bundle for this
+     * logger.
+     * This method will return a {@code ResourceBundle} that was either
+     * set by the {@link
+     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method or
+     * <a href="#ResourceBundleMapping">mapped from the
+     * the resource bundle name</a> set via the {@link
+     * Logger#getLogger(java.lang.String, java.lang.String) getLogger} factory
+     * method for the current default locale.
+     * <br>Note that if the result is {@code null}, then the Logger will use a resource
+     * bundle or resource bundle name inherited from its parent.
+     *
+     * @return localization bundle (may be {@code null})
+     */
+    public ResourceBundle getResourceBundle() {
+        return findResourceBundle(getResourceBundleName(), true);
+    }
+
+    /**
+     * Retrieve the localization resource bundle name for this
+     * logger.
+     * This is either the name specified through the {@link
+     * #getLogger(java.lang.String, java.lang.String) getLogger} factory method,
+     * or the {@linkplain ResourceBundle#getBaseBundleName() base name} of the
+     * ResourceBundle set through {@link
+     * #setResourceBundle(java.util.ResourceBundle) setResourceBundle} method.
+     * <br>Note that if the result is {@code null}, then the Logger will use a resource
+     * bundle or resource bundle name inherited from its parent.
+     *
+     * @return localization bundle name (may be {@code null})
+     */
+    public String getResourceBundleName() {
+        return loggerBundle.resourceBundleName;
+    }
+
+    /**
+     * Set a filter to control output on this Logger.
+     * <P>
+     * After passing the initial "level" check, the Logger will
+     * call this Filter to check if a log record should really
+     * be published.
+     *
+     * @param   newFilter  a filter object (may be null)
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setFilter(Filter newFilter) throws SecurityException {
+        checkPermission();
+        filter = newFilter;
+    }
+
+    /**
+     * Get the current filter for this Logger.
+     *
+     * @return  a filter object (may be null)
+     */
+    public Filter getFilter() {
+        return filter;
+    }
+
+    /**
+     * Log a LogRecord.
+     * <p>
+     * All the other logging methods in this class call through
+     * this method to actually perform any logging.  Subclasses can
+     * override this single method to capture all log activity.
+     *
+     * @param record the LogRecord to be published
+     */
+    public void log(LogRecord record) {
+        if (!isLoggable(record.getLevel())) {
+            return;
+        }
+        Filter theFilter = filter;
+        if (theFilter != null && !theFilter.isLoggable(record)) {
+            return;
+        }
+
+        // Post the LogRecord to all our Handlers, and then to
+        // our parents' handlers, all the way up the tree.
+
+        Logger logger = this;
+        while (logger != null) {
+            final Handler[] loggerHandlers = isSystemLogger
+                ? logger.accessCheckedHandlers()
+                : logger.getHandlers();
+
+            for (Handler handler : loggerHandlers) {
+                handler.publish(record);
+            }
+
+            final boolean useParentHdls = isSystemLogger
+                ? logger.useParentHandlers
+                : logger.getUseParentHandlers();
+
+            if (!useParentHdls) {
+                break;
+            }
+
+            logger = isSystemLogger ? logger.parent : logger.getParent();
+        }
+    }
+
+    // private support method for logging.
+    // We fill in the logger name, resource bundle name, and
+    // resource bundle and then call "void log(LogRecord)".
+    private void doLog(LogRecord lr) {
+        lr.setLoggerName(name);
+        final LoggerBundle lb = getEffectiveLoggerBundle();
+        final ResourceBundle  bundle = lb.userBundle;
+        final String ebname = lb.resourceBundleName;
+        if (ebname != null && bundle != null) {
+            lr.setResourceBundleName(ebname);
+            lr.setResourceBundle(bundle);
+        }
+        log(lr);
+    }
+
+
+    //================================================================
+    // Start of convenience methods WITHOUT className and methodName
+    //================================================================
+
+    /**
+     * Log a message, with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void log(Level level, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, which is only to be constructed if the logging level
+     * is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since 1.8
+     */
+    public void log(Level level, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with one object parameter.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   param1  parameter to the message
+     */
+    public void log(Level level, String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  array of parameters to the message
+     */
+    public void log(Level level, String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     */
+    public void log(Level level, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message level then the
+     * message is constructed by invoking the provided supplier function. The
+     * message and the given {@link Throwable} are then stored in a {@link
+     * LogRecord} which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   thrown  Throwable associated with log message.
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    //================================================================
+    // Start of convenience methods WITH className and methodName
+    //================================================================
+
+    /**
+     * Log a message, specifying source class and method,
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, specifying source class and method,
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with a single object parameter to the log message.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg      The string message (or a key in the message catalog)
+     * @param   param1    Parameter to the log message.
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                                                String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Array of parameters to the message
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                                                String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setParameters(params);
+        doLog(lr);
+    }
+
+    /**
+     * Log a message, specifying source class and method,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    /**
+     * Log a lazily constructed message, specifying source class and method,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message level then the
+     * message is constructed by invoking the provided supplier function. The
+     * message and the given {@link Throwable} are then stored in a {@link
+     * LogRecord} which is forwarded to all registered output handlers.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   thrown  Throwable associated with log message.
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void logp(Level level, String sourceClass, String sourceMethod,
+                     Throwable thrown, Supplier<String> msgSupplier) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msgSupplier.get());
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+
+    //=========================================================================
+    // Start of convenience methods WITH className, methodName and bundle name.
+    //=========================================================================
+
+    // Private support method for logging for "logrb" methods.
+    // We fill in the logger name, resource bundle name, and
+    // resource bundle and then call "void log(LogRecord)".
+    private void doLog(LogRecord lr, String rbname) {
+        lr.setLoggerName(name);
+        if (rbname != null) {
+            lr.setResourceBundleName(rbname);
+            lr.setResourceBundle(findResourceBundle(rbname, false));
+        }
+        log(lr);
+    }
+
+    // Private support method for logging for "logrb" methods.
+    private void doLog(LogRecord lr, ResourceBundle rb) {
+        lr.setLoggerName(name);
+        if (rb != null) {
+            lr.setResourceBundleName(rb.getBaseBundleName());
+            lr.setResourceBundle(rb);
+        }
+        log(lr);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name
+     * with no arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg     The string message (or a key in the message catalog)
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     * java.lang.String, java.util.ResourceBundle, java.lang.String,
+     * java.lang.Object...)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with a single object parameter to the log message.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg      The string message (or a key in the message catalog)
+     * @param   param1    Parameter to the log message.
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *   java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *   java.lang.Object...)} instead
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg, Object param1) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        Object params[] = { param1 };
+        lr.setParameters(params);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with an array of object arguments.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null.
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Array of parameters to the message
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *      java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *      java.lang.Object...)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                String bundleName, String msg, Object params[]) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setParameters(params);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle,
+     * with an optional list of message parameters.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then a corresponding LogRecord is created and forwarded
+     * to all the registered output Handler objects.
+     * <p>
+     * The {@code msg} string is localized using the given resource bundle.
+     * If the resource bundle is {@code null}, then the {@code msg} string is not
+     * localized.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    Name of the class that issued the logging request
+     * @param   sourceMethod   Name of the method that issued the logging request
+     * @param   bundle         Resource bundle to localize {@code msg},
+     *                         can be {@code null}.
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   params  Parameters to the message (optional, may be none).
+     * @since 1.8
+     */
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                      ResourceBundle bundle, String msg, Object... params) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        if (params != null && params.length != 0) {
+            lr.setParameters(params);
+        }
+        doLog(lr, bundle);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle name,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * The msg string is localized using the named resource bundle.  If the
+     * resource bundle name is null, or an empty String or invalid
+     * then the msg string is not localized.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that issued the logging request
+     * @param   bundleName     name of resource bundle to localize msg,
+     *                         can be null
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with log message.
+     * @deprecated Use {@link #logrb(java.util.logging.Level, java.lang.String,
+     *     java.lang.String, java.util.ResourceBundle, java.lang.String,
+     *     java.lang.Throwable)} instead.
+     */
+    @Deprecated
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                                        String bundleName, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr, bundleName);
+    }
+
+    /**
+     * Log a message, specifying source class, method, and resource bundle,
+     * with associated Throwable information.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.
+     * <p>
+     * The {@code msg} string is localized using the given resource bundle.
+     * If the resource bundle is {@code null}, then the {@code msg} string is not
+     * localized.
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   level   One of the message level identifiers, e.g., SEVERE
+     * @param   sourceClass    Name of the class that issued the logging request
+     * @param   sourceMethod   Name of the method that issued the logging request
+     * @param   bundle         Resource bundle to localize {@code msg},
+     *                         can be {@code null}
+     * @param   msg     The string message (or a key in the message catalog)
+     * @param   thrown  Throwable associated with the log message.
+     * @since 1.8
+     */
+    public void logrb(Level level, String sourceClass, String sourceMethod,
+                      ResourceBundle bundle, String msg, Throwable thrown) {
+        if (!isLoggable(level)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(level, msg);
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr, bundle);
+    }
+
+    //======================================================================
+    // Start of convenience methods for logging method entries and returns.
+    //======================================================================
+
+    /**
+     * Log a method entry.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY", log level
+     * FINER, and the given sourceMethod and sourceClass is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     */
+    public void entering(String sourceClass, String sourceMethod) {
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
+    }
+
+    /**
+     * Log a method entry, with one parameter.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY {0}", log level
+     * FINER, and the given sourceMethod, sourceClass, and parameter
+     * is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     * @param   param1         parameter to the method being entered
+     */
+    public void entering(String sourceClass, String sourceMethod, Object param1) {
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
+    }
+
+    /**
+     * Log a method entry, with an array of parameters.
+     * <p>
+     * This is a convenience method that can be used to log entry
+     * to a method.  A LogRecord with message "ENTRY" (followed by a
+     * format {N} indicator for each entry in the parameter array),
+     * log level FINER, and the given sourceMethod, sourceClass, and
+     * parameters is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of method that is being entered
+     * @param   params         array of parameters to the method being entered
+     */
+    public void entering(String sourceClass, String sourceMethod, Object params[]) {
+        String msg = "ENTRY";
+        if (params == null ) {
+           logp(Level.FINER, sourceClass, sourceMethod, msg);
+           return;
+        }
+        if (!isLoggable(Level.FINER)) return;
+        for (int i = 0; i < params.length; i++) {
+            msg = msg + " {" + i + "}";
+        }
+        logp(Level.FINER, sourceClass, sourceMethod, msg, params);
+    }
+
+    /**
+     * Log a method return.
+     * <p>
+     * This is a convenience method that can be used to log returning
+     * from a method.  A LogRecord with message "RETURN", log level
+     * FINER, and the given sourceMethod and sourceClass is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of the method
+     */
+    public void exiting(String sourceClass, String sourceMethod) {
+        logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
+    }
+
+
+    /**
+     * Log a method return, with result object.
+     * <p>
+     * This is a convenience method that can be used to log returning
+     * from a method.  A LogRecord with message "RETURN {0}", log level
+     * FINER, and the gives sourceMethod, sourceClass, and result
+     * object is logged.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod   name of the method
+     * @param   result  Object that is being returned
+     */
+    public void exiting(String sourceClass, String sourceMethod, Object result) {
+        logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
+    }
+
+    /**
+     * Log throwing an exception.
+     * <p>
+     * This is a convenience method to log that a method is
+     * terminating by throwing an exception.  The logging is done
+     * using the FINER level.
+     * <p>
+     * If the logger is currently enabled for the given message
+     * level then the given arguments are stored in a LogRecord
+     * which is forwarded to all registered output handlers.  The
+     * LogRecord's message is set to "THROW".
+     * <p>
+     * Note that the thrown argument is stored in the LogRecord thrown
+     * property, rather than the LogRecord parameters property.  Thus it is
+     * processed specially by output Formatters and is not treated
+     * as a formatting parameter to the LogRecord message property.
+     * <p>
+     * @param   sourceClass    name of class that issued the logging request
+     * @param   sourceMethod  name of the method.
+     * @param   thrown  The Throwable that is being thrown.
+     */
+    public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
+        if (!isLoggable(Level.FINER)) {
+            return;
+        }
+        LogRecord lr = new LogRecord(Level.FINER, "THROW");
+        lr.setSourceClassName(sourceClass);
+        lr.setSourceMethodName(sourceMethod);
+        lr.setThrown(thrown);
+        doLog(lr);
+    }
+
+    //=======================================================================
+    // Start of simple convenience methods using level names as method names
+    //=======================================================================
+
+    /**
+     * Log a SEVERE message.
+     * <p>
+     * If the logger is currently enabled for the SEVERE message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void severe(String msg) {
+        log(Level.SEVERE, msg);
+    }
+
+    /**
+     * Log a WARNING message.
+     * <p>
+     * If the logger is currently enabled for the WARNING message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void warning(String msg) {
+        log(Level.WARNING, msg);
+    }
+
+    /**
+     * Log an INFO message.
+     * <p>
+     * If the logger is currently enabled for the INFO message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void info(String msg) {
+        log(Level.INFO, msg);
+    }
+
+    /**
+     * Log a CONFIG message.
+     * <p>
+     * If the logger is currently enabled for the CONFIG message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void config(String msg) {
+        log(Level.CONFIG, msg);
+    }
+
+    /**
+     * Log a FINE message.
+     * <p>
+     * If the logger is currently enabled for the FINE message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void fine(String msg) {
+        log(Level.FINE, msg);
+    }
+
+    /**
+     * Log a FINER message.
+     * <p>
+     * If the logger is currently enabled for the FINER message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void finer(String msg) {
+        log(Level.FINER, msg);
+    }
+
+    /**
+     * Log a FINEST message.
+     * <p>
+     * If the logger is currently enabled for the FINEST message
+     * level then the given message is forwarded to all the
+     * registered output Handler objects.
+     * <p>
+     * @param   msg     The string message (or a key in the message catalog)
+     */
+    public void finest(String msg) {
+        log(Level.FINEST, msg);
+    }
+
+    //=======================================================================
+    // Start of simple convenience methods using level names as method names
+    // and use Supplier<String>
+    //=======================================================================
+
+    /**
+     * Log a SEVERE message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the SEVERE message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void severe(Supplier<String> msgSupplier) {
+        log(Level.SEVERE, msgSupplier);
+    }
+
+    /**
+     * Log a WARNING message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the WARNING message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void warning(Supplier<String> msgSupplier) {
+        log(Level.WARNING, msgSupplier);
+    }
+
+    /**
+     * Log a INFO message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the INFO message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void info(Supplier<String> msgSupplier) {
+        log(Level.INFO, msgSupplier);
+    }
+
+    /**
+     * Log a CONFIG message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the CONFIG message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void config(Supplier<String> msgSupplier) {
+        log(Level.CONFIG, msgSupplier);
+    }
+
+    /**
+     * Log a FINE message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINE message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void fine(Supplier<String> msgSupplier) {
+        log(Level.FINE, msgSupplier);
+    }
+
+    /**
+     * Log a FINER message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINER message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void finer(Supplier<String> msgSupplier) {
+        log(Level.FINER, msgSupplier);
+    }
+
+    /**
+     * Log a FINEST message, which is only to be constructed if the logging
+     * level is such that the message will actually be logged.
+     * <p>
+     * If the logger is currently enabled for the FINEST message
+     * level then the message is constructed by invoking the provided
+     * supplier function and forwarded to all the registered output
+     * Handler objects.
+     * <p>
+     * @param   msgSupplier   A function, which when called, produces the
+     *                        desired log message
+     * @since   1.8
+     */
+    public void finest(Supplier<String> msgSupplier) {
+        log(Level.FINEST, msgSupplier);
+    }
+
+    //================================================================
+    // End of convenience methods
+    //================================================================
+
+    /**
+     * Set the log level specifying which message levels will be
+     * logged by this logger.  Message levels lower than this
+     * value will be discarded.  The level value Level.OFF
+     * can be used to turn off logging.
+     * <p>
+     * If the new level is null, it means that this node should
+     * inherit its level from its nearest ancestor with a specific
+     * (non-null) level value.
+     *
+     * @param newLevel   the new value for the log level (may be null)
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setLevel(Level newLevel) throws SecurityException {
+        checkPermission();
+        synchronized (treeLock) {
+            levelObject = newLevel;
+            updateEffectiveLevel();
+        }
+    }
+
+    final boolean isLevelInitialized() {
+        return levelObject != null;
+    }
+
+    /**
+     * Get the log Level that has been specified for this Logger.
+     * The result may be null, which means that this logger's
+     * effective level will be inherited from its parent.
+     *
+     * @return  this Logger's level
+     */
+    public Level getLevel() {
+        return levelObject;
+    }
+
+    /**
+     * Check if a message of the given level would actually be logged
+     * by this logger.  This check is based on the Loggers effective level,
+     * which may be inherited from its parent.
+     *
+     * @param   level   a message logging level
+     * @return  true if the given message level is currently being logged.
+     */
+    public boolean isLoggable(Level level) {
+        if (level.intValue() < levelValue || levelValue == offValue) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get the name for this logger.
+     * @return logger name.  Will be null for anonymous Loggers.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Add a log Handler to receive logging messages.
+     * <p>
+     * By default, Loggers also send their output to their parent logger.
+     * Typically the root Logger is configured with a set of Handlers
+     * that essentially act as default handlers for all loggers.
+     *
+     * @param   handler a logging Handler
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void addHandler(Handler handler) throws SecurityException {
+        // Check for null handler
+        handler.getClass();
+        checkPermission();
+        handlers.add(handler);
+    }
+
+    /**
+     * Remove a log Handler.
+     * <P>
+     * Returns silently if the given Handler is not found or is null
+     *
+     * @param   handler a logging Handler
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void removeHandler(Handler handler) throws SecurityException {
+        checkPermission();
+        if (handler == null) {
+            return;
+        }
+        handlers.remove(handler);
+    }
+
+    /**
+     * Get the Handlers associated with this logger.
+     * <p>
+     * @return  an array of all registered Handlers
+     */
+    public Handler[] getHandlers() {
+        return accessCheckedHandlers();
+    }
+
+    // This method should ideally be marked final - but unfortunately
+    // it needs to be overridden by LogManager.RootLogger
+    Handler[] accessCheckedHandlers() {
+        return handlers.toArray(emptyHandlers);
+    }
+
+    /**
+     * Specify whether or not this logger should send its output
+     * to its parent Logger.  This means that any LogRecords will
+     * also be written to the parent's Handlers, and potentially
+     * to its parent, recursively up the namespace.
+     *
+     * @param useParentHandlers   true if output is to be sent to the
+     *          logger's parent.
+     * @throws  SecurityException if a security manager exists,
+     *          this logger is not anonymous, and the caller
+     *          does not have LoggingPermission("control").
+     */
+    public void setUseParentHandlers(boolean useParentHandlers) {
+        checkPermission();
+        this.useParentHandlers = useParentHandlers;
+    }
+
+    /**
+     * Discover whether or not this logger is sending its output
+     * to its parent logger.
+     *
+     * @return  true if output is to be sent to the logger's parent
+     */
+    public boolean getUseParentHandlers() {
+        return useParentHandlers;
+    }
+
+    private static ResourceBundle findSystemResourceBundle(final Locale locale) {
+        // the resource bundle is in a restricted package
+        return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
+            @Override
+            public ResourceBundle run() {
+                try {
+                    return ResourceBundle.getBundle(SYSTEM_LOGGER_RB_NAME,
+                                                    locale,
+                                                    ClassLoader.getSystemClassLoader());
+                } catch (MissingResourceException e) {
+                    throw new InternalError(e.toString());
+                }
+            }
+        });
+    }
+
+    /**
+     * Private utility method to map a resource bundle name to an
+     * actual resource bundle, using a simple one-entry cache.
+     * Returns null for a null name.
+     * May also return null if we can't find the resource bundle and
+     * there is no suitable previous cached value.
+     *
+     * @param name the ResourceBundle to locate
+     * @param userCallersClassLoader if true search using the caller's ClassLoader
+     * @return ResourceBundle specified by name or null if not found
+     */
+    private synchronized ResourceBundle findResourceBundle(String name,
+                                                           boolean useCallersClassLoader) {
+        // For all lookups, we first check the thread context class loader
+        // if it is set.  If not, we use the system classloader.  If we
+        // still haven't found it we use the callersClassLoaderRef if it
+        // is set and useCallersClassLoader is true.  We set
+        // callersClassLoaderRef initially upon creating the logger with a
+        // non-null resource bundle name.
+
+        // Return a null bundle for a null name.
+        if (name == null) {
+            return null;
+        }
+
+        Locale currentLocale = Locale.getDefault();
+        final LoggerBundle lb = loggerBundle;
+
+        // Normally we should hit on our simple one entry cache.
+        if (lb.userBundle != null &&
+                name.equals(lb.resourceBundleName)) {
+            return lb.userBundle;
+        } else if (catalog != null && currentLocale.equals(catalogLocale)
+                && name.equals(catalogName)) {
+            return catalog;
+        }
+
+        if (name.equals(SYSTEM_LOGGER_RB_NAME)) {
+            catalog = findSystemResourceBundle(currentLocale);
+            catalogName = name;
+            catalogLocale = currentLocale;
+            return catalog;
+        }
+
+        // Use the thread's context ClassLoader.  If there isn't one, use the
+        // {@linkplain java.lang.ClassLoader#getSystemClassLoader() system ClassLoader}.
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        if (cl == null) {
+            cl = ClassLoader.getSystemClassLoader();
+        }
+        try {
+            catalog = ResourceBundle.getBundle(name, currentLocale, cl);
+            catalogName = name;
+            catalogLocale = currentLocale;
+            return catalog;
+        } catch (MissingResourceException ex) {
+            // We can't find the ResourceBundle in the default
+            // ClassLoader.  Drop through.
+        }
+
+        if (useCallersClassLoader) {
+            // Try with the caller's ClassLoader
+            ClassLoader callersClassLoader = getCallersClassLoader();
+
+            if (callersClassLoader == null || callersClassLoader == cl) {
+                return null;
+            }
+
+            try {
+                catalog = ResourceBundle.getBundle(name, currentLocale,
+                                                   callersClassLoader);
+                catalogName = name;
+                catalogLocale = currentLocale;
+                return catalog;
+            } catch (MissingResourceException ex) {
+                return null; // no luck
+            }
+        } else {
+            return null;
+        }
+    }
+
+    // Private utility method to initialize our one entry
+    // resource bundle name cache and the callers ClassLoader
+    // Note: for consistency reasons, we are careful to check
+    // that a suitable ResourceBundle exists before setting the
+    // resourceBundleName field.
+    // Synchronized to prevent races in setting the fields.
+    private synchronized void setupResourceInfo(String name,
+                                                Class<?> callersClass) {
+        final LoggerBundle lb = loggerBundle;
+        if (lb.resourceBundleName != null) {
+            // this Logger already has a ResourceBundle
+
+            if (lb.resourceBundleName.equals(name)) {
+                // the names match so there is nothing more to do
+                return;
+            }
+
+            // cannot change ResourceBundles once they are set
+            throw new IllegalArgumentException(
+                lb.resourceBundleName + " != " + name);
+        }
+
+        if (name == null) {
+            return;
+        }
+
+        setCallersClassLoaderRef(callersClass);
+        if (isSystemLogger && getCallersClassLoader() != null) {
+            checkPermission();
+        }
+        if (findResourceBundle(name, true) == null) {
+            // We've failed to find an expected ResourceBundle.
+            // unset the caller's ClassLoader since we were unable to find the
+            // the bundle using it
+            this.callersClassLoaderRef = null;
+            throw new MissingResourceException("Can't find " + name + " bundle",
+                                                name, "");
+        }
+
+        // if lb.userBundle is not null we won't reach this line.
+        assert lb.userBundle == null;
+        loggerBundle = LoggerBundle.get(name, null);
+    }
+
+    /**
+     * Sets a resource bundle on this logger.
+     * All messages will be logged using the given resource bundle for its
+     * specific {@linkplain ResourceBundle#getLocale locale}.
+     * @param bundle The resource bundle that this logger shall use.
+     * @throws NullPointerException if the given bundle is {@code null}.
+     * @throws IllegalArgumentException if the given bundle doesn't have a
+     *         {@linkplain ResourceBundle#getBaseBundleName base name},
+     *         or if this logger already has a resource bundle set but
+     *         the given bundle has a different base name.
+     * @throws SecurityException if a security manager exists,
+     *         this logger is not anonymous, and the caller
+     *         does not have LoggingPermission("control").
+     * @since 1.8
+     */
+    public void setResourceBundle(ResourceBundle bundle) {
+        checkPermission();
+
+        // Will throw NPE if bundle is null.
+        final String baseName = bundle.getBaseBundleName();
+
+        // bundle must have a name
+        if (baseName == null || baseName.isEmpty()) {
+            throw new IllegalArgumentException("resource bundle must have a name");
+        }
+
+        synchronized (this) {
+            LoggerBundle lb = loggerBundle;
+            final boolean canReplaceResourceBundle = lb.resourceBundleName == null
+                    || lb.resourceBundleName.equals(baseName);
+
+            if (!canReplaceResourceBundle) {
+                throw new IllegalArgumentException("can't replace resource bundle");
+            }
+
+
+            loggerBundle = LoggerBundle.get(baseName, bundle);
+        }
+    }
+
+    /**
+     * Return the parent for this Logger.
+     * <p>
+     * This method returns the nearest extant parent in the namespace.
+     * Thus if a Logger is called "a.b.c.d", and a Logger called "a.b"
+     * has been created but no logger "a.b.c" exists, then a call of
+     * getParent on the Logger "a.b.c.d" will return the Logger "a.b".
+     * <p>
+     * The result will be null if it is called on the root Logger
+     * in the namespace.
+     *
+     * @return nearest existing parent Logger
+     */
+    public Logger getParent() {
+        // Note: this used to be synchronized on treeLock.  However, this only
+        // provided memory semantics, as there was no guarantee that the caller
+        // would synchronize on treeLock (in fact, there is no way for external
+        // callers to so synchronize).  Therefore, we have made parent volatile
+        // instead.
+        return parent;
+    }
+
+    /**
+     * Set the parent for this Logger.  This method is used by
+     * the LogManager to update a Logger when the namespace changes.
+     * <p>
+     * It should not be called from application code.
+     * <p>
+     * @param  parent   the new parent logger
+     * @throws  SecurityException  if a security manager exists and if
+     *          the caller does not have LoggingPermission("control").
+     */
+    public void setParent(Logger parent) {
+        if (parent == null) {
+            throw new NullPointerException();
+        }
+
+        // check permission for all loggers, including anonymous loggers
+        if (manager == null) {
+            manager = LogManager.getLogManager();
+        }
+        manager.checkPermission();
+
+        doSetParent(parent);
+    }
+
+    // Private method to do the work for parenting a child
+    // Logger onto a parent logger.
+    private void doSetParent(Logger newParent) {
+
+        // System.err.println("doSetParent \"" + getName() + "\" \""
+        //                              + newParent.getName() + "\"");
+
+        synchronized (treeLock) {
+
+            // Remove ourself from any previous parent.
+            LogManager.LoggerWeakRef ref = null;
+            if (parent != null) {
+                // assert parent.kids != null;
+                for (Iterator<LogManager.LoggerWeakRef> iter = parent.kids.iterator(); iter.hasNext(); ) {
+                    ref = iter.next();
+                    Logger kid =  ref.get();
+                    if (kid == this) {
+                        // ref is used down below to complete the reparenting
+                        iter.remove();
+                        break;
+                    } else {
+                        ref = null;
+                    }
+                }
+                // We have now removed ourself from our parents' kids.
+            }
+
+            // Set our new parent.
+            parent = newParent;
+            if (parent.kids == null) {
+                parent.kids = new ArrayList<>(2);
+            }
+            if (ref == null) {
+                // we didn't have a previous parent
+                ref = manager.new LoggerWeakRef(this);
+            }
+            ref.setParentRef(new WeakReference<>(parent));
+            parent.kids.add(ref);
+
+            // As a result of the reparenting, the effective level
+            // may have changed for us and our children.
+            updateEffectiveLevel();
+
+        }
+    }
+
+    // Package-level method.
+    // Remove the weak reference for the specified child Logger from the
+    // kid list. We should only be called from LoggerWeakRef.dispose().
+    final void removeChildLogger(LogManager.LoggerWeakRef child) {
+        synchronized (treeLock) {
+            for (Iterator<LogManager.LoggerWeakRef> iter = kids.iterator(); iter.hasNext(); ) {
+                LogManager.LoggerWeakRef ref = iter.next();
+                if (ref == child) {
+                    iter.remove();
+                    return;
+                }
+            }
+        }
+    }
+
+    // Recalculate the effective level for this node and
+    // recursively for our children.
+
+    private void updateEffectiveLevel() {
+        // assert Thread.holdsLock(treeLock);
+
+        // Figure out our current effective level.
+        int newLevelValue;
+        if (levelObject != null) {
+            newLevelValue = levelObject.intValue();
+        } else {
+            if (parent != null) {
+                newLevelValue = parent.levelValue;
+            } else {
+                // This may happen during initialization.
+                newLevelValue = Level.INFO.intValue();
+            }
+        }
+
+        // If our effective value hasn't changed, we're done.
+        if (levelValue == newLevelValue) {
+            return;
+        }
+
+        levelValue = newLevelValue;
+
+        // System.err.println("effective level: \"" + getName() + "\" := " + level);
+
+        // Recursively update the level on each of our kids.
+        if (kids != null) {
+            for (int i = 0; i < kids.size(); i++) {
+                LogManager.LoggerWeakRef ref = kids.get(i);
+                Logger kid =  ref.get();
+                if (kid != null) {
+                    kid.updateEffectiveLevel();
+                }
+            }
+        }
+    }
+
+
+    // Private method to get the potentially inherited
+    // resource bundle and resource bundle name for this Logger.
+    // This method never returns null.
+    private LoggerBundle getEffectiveLoggerBundle() {
+        final LoggerBundle lb = loggerBundle;
+        if (lb.isSystemBundle()) {
+            return SYSTEM_BUNDLE;
+        }
+
+        // first take care of this logger
+        final ResourceBundle b = getResourceBundle();
+        if (b != null && b == lb.userBundle) {
+            return lb;
+        } else if (b != null) {
+            // either lb.userBundle is null or getResourceBundle() is
+            // overriden
+            final String rbName = getResourceBundleName();
+            return LoggerBundle.get(rbName, b);
+        }
+
+        // no resource bundle was specified on this logger, look up the
+        // parent stack.
+        Logger target = this.parent;
+        while (target != null) {
+            final LoggerBundle trb = target.loggerBundle;
+            if (trb.isSystemBundle()) {
+                return SYSTEM_BUNDLE;
+            }
+            if (trb.userBundle != null) {
+                return trb;
+            }
+            final String rbName = isSystemLogger
+                // ancestor of a system logger is expected to be a system logger.
+                // ignore resource bundle name if it's not.
+                ? (target.isSystemLogger ? trb.resourceBundleName : null)
+                : target.getResourceBundleName();
+            if (rbName != null) {
+                return LoggerBundle.get(rbName,
+                        findResourceBundle(rbName, true));
+            }
+            target = isSystemLogger ? target.parent : target.getParent();
+        }
+        return NO_RESOURCE_BUNDLE;
+    }
+
+}
diff --git a/java/util/logging/Logging.java b/java/util/logging/Logging.java
new file mode 100644
index 0000000..740a533
--- /dev/null
+++ b/java/util/logging/Logging.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Logging is the implementation class of LoggingMXBean.
+ *
+ * The <tt>LoggingMXBean</tt> interface provides a standard
+ * method for management access to the individual
+ * {@code Logger} objects available at runtime.
+ *
+ * @author Ron Mann
+ * @author Mandy Chung
+ * @since 1.5
+ *
+ * @see javax.management
+ * @see Logger
+ * @see LogManager
+ */
+class Logging implements LoggingMXBean {
+
+    private static LogManager logManager = LogManager.getLogManager();
+
+    /** Constructor of Logging which is the implementation class
+     *  of LoggingMXBean.
+     */
+    Logging() {
+    }
+
+    public List<String> getLoggerNames() {
+        Enumeration<String> loggers = logManager.getLoggerNames();
+        ArrayList<String> array = new ArrayList<>();
+
+        for (; loggers.hasMoreElements();) {
+            array.add(loggers.nextElement());
+        }
+        return array;
+    }
+
+    private static String EMPTY_STRING = "";
+    public String getLoggerLevel(String loggerName) {
+        Logger l = logManager.getLogger(loggerName);
+        if (l == null) {
+            return null;
+        }
+
+        Level level = l.getLevel();
+        if (level == null) {
+            return EMPTY_STRING;
+        } else {
+            return level.getLevelName();
+        }
+    }
+
+    public void setLoggerLevel(String loggerName, String levelName) {
+        if (loggerName == null) {
+            throw new NullPointerException("loggerName is null");
+        }
+
+        Logger logger = logManager.getLogger(loggerName);
+        if (logger == null) {
+            throw new IllegalArgumentException("Logger " + loggerName +
+                "does not exist");
+        }
+
+        Level level = null;
+        if (levelName != null) {
+            // parse will throw IAE if logLevel is invalid
+            level = Level.findLevel(levelName);
+            if (level == null) {
+                throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
+            }
+        }
+
+        logger.setLevel(level);
+    }
+
+    public String getParentLoggerName( String loggerName ) {
+        Logger l = logManager.getLogger( loggerName );
+        if (l == null) {
+            return null;
+        }
+
+        Logger p = l.getParent();
+        if (p == null) {
+            // root logger
+            return EMPTY_STRING;
+        } else {
+            return p.getName();
+        }
+    }
+}
diff --git a/java/util/logging/LoggingMXBean.java b/java/util/logging/LoggingMXBean.java
new file mode 100644
index 0000000..14777c0
--- /dev/null
+++ b/java/util/logging/LoggingMXBean.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+// Android-removed: References to java.lang.management in javadoc.
+
+/**
+ * The management interface for the logging facility.
+ *
+ * <p>There is a single global instance of the <tt>LoggingMXBean</tt>.
+ *
+ * The {@code javax.management.ObjectName ObjectName} that uniquely identifies
+ * the management interface for logging within the {@code MBeanServer} is:
+ * <pre>
+ *    {@link LogManager#LOGGING_MXBEAN_NAME java.util.logging:type=Logging}
+ * </pre>
+ * <p>
+ *
+ * @author  Ron Mann
+ * @author  Mandy Chung
+ * @since   1.5
+ *
+ */
+public interface LoggingMXBean {
+
+    /**
+     * Returns the list of currently registered logger names. This method
+     * calls {@link LogManager#getLoggerNames} and returns a list
+     * of the logger names.
+     *
+     * @return A list of <tt>String</tt> each of which is a
+     *         currently registered <tt>Logger</tt> name.
+     */
+    public java.util.List<String> getLoggerNames();
+
+    /**
+     * Gets the name of the log level associated with the specified logger.
+     * If the specified logger does not exist, <tt>null</tt>
+     * is returned.
+     * This method first finds the logger of the given name and
+     * then returns the name of the log level by calling:
+     * <blockquote>
+     *   {@link Logger#getLevel Logger.getLevel()}.{@link Level#getName getName()};
+     * </blockquote>
+     *
+     * <p>
+     * If the <tt>Level</tt> of the specified logger is <tt>null</tt>,
+     * which means that this logger's effective level is inherited
+     * from its parent, an empty string will be returned.
+     *
+     * @param loggerName The name of the <tt>Logger</tt> to be retrieved.
+     *
+     * @return The name of the log level of the specified logger; or
+     *         an empty string if the log level of the specified logger
+     *         is <tt>null</tt>.  If the specified logger does not
+     *         exist, <tt>null</tt> is returned.
+     *
+     * @see Logger#getLevel
+     */
+    public String getLoggerLevel(String loggerName);
+
+    /**
+     * Sets the specified logger to the specified new level.
+     * If the <tt>levelName</tt> is not <tt>null</tt>, the level
+     * of the specified logger is set to the parsed <tt>Level</tt>
+     * matching the <tt>levelName</tt>.
+     * If the <tt>levelName</tt> is <tt>null</tt>, the level
+     * of the specified logger is set to <tt>null</tt> and
+     * the effective level of the logger is inherited from
+     * its nearest ancestor with a specific (non-null) level value.
+     *
+     * @param loggerName The name of the <tt>Logger</tt> to be set.
+     *                   Must be non-null.
+     * @param levelName The name of the level to set on the specified logger,
+     *                 or <tt>null</tt> if setting the level to inherit
+     *                 from its nearest ancestor.
+     *
+     * @throws IllegalArgumentException if the specified logger
+     * does not exist, or <tt>levelName</tt> is not a valid level name.
+     *
+     * @throws SecurityException if a security manager exists and if
+     * the caller does not have LoggingPermission("control").
+     *
+     * @see Logger#setLevel
+     */
+    public void setLoggerLevel(String loggerName, String levelName);
+
+    /**
+     * Returns the name of the parent for the specified logger.
+     * If the specified logger does not exist, <tt>null</tt> is returned.
+     * If the specified logger is the root <tt>Logger</tt> in the namespace,
+     * the result will be an empty string.
+     *
+     * @param loggerName The name of a <tt>Logger</tt>.
+     *
+     * @return the name of the nearest existing parent logger;
+     *         an empty string if the specified logger is the root logger.
+     *         If the specified logger does not exist, <tt>null</tt>
+     *         is returned.
+     */
+    public String getParentLoggerName(String loggerName);
+}
diff --git a/java/util/logging/LoggingPermission.java b/java/util/logging/LoggingPermission.java
new file mode 100644
index 0000000..5cea7a5
--- /dev/null
+++ b/java/util/logging/LoggingPermission.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+// Android-changed: Stubbed the implementation.  Android doesn't support SecurityManager.
+// See comments in java.lang.SecurityManager for details.
+/**
+ * Legacy security code; do not use.
+ */
+
+public final class LoggingPermission extends java.security.BasicPermission {
+
+    public LoggingPermission(String name, String actions) throws IllegalArgumentException {
+        super("", "");
+    }
+}
diff --git a/java/util/logging/LoggingProxyImpl.java b/java/util/logging/LoggingProxyImpl.java
new file mode 100644
index 0000000..61fcb7b
--- /dev/null
+++ b/java/util/logging/LoggingProxyImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+import sun.util.logging.LoggingProxy;
+
+/**
+ * Implementation of LoggingProxy when java.util.logging classes exist.
+ */
+class LoggingProxyImpl implements LoggingProxy {
+    static final LoggingProxy INSTANCE = new LoggingProxyImpl();
+
+    private LoggingProxyImpl() { }
+
+    @Override
+    public Object getLogger(String name) {
+        // always create a platform logger with the resource bundle name
+        return Logger.getPlatformLogger(name);
+    }
+
+    @Override
+    public Object getLevel(Object logger) {
+        return ((Logger) logger).getLevel();
+    }
+
+    @Override
+    public void setLevel(Object logger, Object newLevel) {
+        ((Logger) logger).setLevel((Level) newLevel);
+    }
+
+    @Override
+    public boolean isLoggable(Object logger, Object level) {
+        return ((Logger) logger).isLoggable((Level) level);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg) {
+        ((Logger) logger).log((Level) level, msg);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg, Throwable t) {
+        ((Logger) logger).log((Level) level, msg, t);
+    }
+
+    @Override
+    public void log(Object logger, Object level, String msg, Object... params) {
+        ((Logger) logger).log((Level) level, msg, params);
+    }
+
+    @Override
+    public java.util.List<String> getLoggerNames() {
+        return LogManager.getLoggingMXBean().getLoggerNames();
+    }
+
+    @Override
+    public String getLoggerLevel(String loggerName) {
+        return LogManager.getLoggingMXBean().getLoggerLevel(loggerName);
+    }
+
+    @Override
+    public void setLoggerLevel(String loggerName, String levelName) {
+        LogManager.getLoggingMXBean().setLoggerLevel(loggerName, levelName);
+    }
+
+    @Override
+    public String getParentLoggerName(String loggerName) {
+        return LogManager.getLoggingMXBean().getParentLoggerName(loggerName);
+    }
+
+    @Override
+    public Object parseLevel(String levelName) {
+        Level level = Level.findLevel(levelName);
+        if (level == null) {
+            throw new IllegalArgumentException("Unknown level \"" + levelName + "\"");
+        }
+        return level;
+    }
+
+    @Override
+    public String getLevelName(Object level) {
+        return ((Level) level).getLevelName();
+    }
+
+    @Override
+    public int getLevelValue(Object level) {
+        return ((Level) level).intValue();
+    }
+
+    @Override
+    public String getProperty(String key) {
+        return LogManager.getLogManager().getProperty(key);
+    }
+}
diff --git a/java/util/logging/MemoryHandler.java b/java/util/logging/MemoryHandler.java
new file mode 100644
index 0000000..704c155
--- /dev/null
+++ b/java/util/logging/MemoryHandler.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.logging;
+
+/**
+ * <tt>Handler</tt> that buffers requests in a circular buffer in memory.
+ * <p>
+ * Normally this <tt>Handler</tt> simply stores incoming <tt>LogRecords</tt>
+ * into its memory buffer and discards earlier records.  This buffering
+ * is very cheap and avoids formatting costs.  On certain trigger
+ * conditions, the <tt>MemoryHandler</tt> will push out its current buffer
+ * contents to a target <tt>Handler</tt>, which will typically publish
+ * them to the outside world.
+ * <p>
+ * There are three main models for triggering a push of the buffer:
+ * <ul>
+ * <li>
+ * An incoming <tt>LogRecord</tt> has a type that is greater than
+ * a pre-defined level, the <tt>pushLevel</tt>. </li>
+ * <li>
+ * An external class calls the <tt>push</tt> method explicitly. </li>
+ * <li>
+ * A subclass overrides the <tt>log</tt> method and scans each incoming
+ * <tt>LogRecord</tt> and calls <tt>push</tt> if a record matches some
+ * desired criteria. </li>
+ * </ul>
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>MemoryHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * If no default value is defined then a RuntimeException is thrown.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.size
+ *        defines the buffer size (defaults to 1000). </li>
+ * <li>   &lt;handler-name&gt;.push
+ *        defines the <tt>pushLevel</tt> (defaults to <tt>level.SEVERE</tt>). </li>
+ * <li>   &lt;handler-name&gt;.target
+ *        specifies the name of the target <tt>Handler </tt> class.
+ *        (no default). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code MemoryHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.MemoryHandler.level=INFO </li>
+ * <li>   java.util.logging.MemoryHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+
+public class MemoryHandler extends Handler {
+    private final static int DEFAULT_SIZE = 1000;
+    private volatile Level pushLevel;
+    private int size;
+    private Handler target;
+    private LogRecord buffer[];
+    int start, count;
+
+    // Private method to configure a MemoryHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        pushLevel = manager.getLevelProperty(cname +".push", Level.SEVERE);
+        size = manager.getIntProperty(cname + ".size", DEFAULT_SIZE);
+        if (size <= 0) {
+            size = DEFAULT_SIZE;
+        }
+        setLevel(manager.getLevelProperty(cname +".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+    }
+
+    /**
+     * Create a <tt>MemoryHandler</tt> and configure it based on
+     * <tt>LogManager</tt> configuration properties.
+     */
+    public MemoryHandler() {
+        sealed = false;
+        configure();
+        sealed = true;
+
+        LogManager manager = LogManager.getLogManager();
+        String handlerName = getClass().getName();
+        String targetName = manager.getProperty(handlerName+".target");
+        if (targetName == null) {
+            throw new RuntimeException("The handler " + handlerName
+                    + " does not specify a target");
+        }
+        Class<?> clz;
+        try {
+            clz = ClassLoader.getSystemClassLoader().loadClass(targetName);
+            target = (Handler) clz.newInstance();
+        // Android-changed: Fall back to the context classloader before giving up.
+        // } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+        //     throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e);
+        } catch (Exception e) {
+            try {
+                clz = Thread.currentThread().getContextClassLoader()
+                        .loadClass(targetName);
+                target = (Handler) clz.newInstance();
+            } catch (Exception innerE) {
+                throw new RuntimeException("MemoryHandler can't load handler target \"" +
+                        targetName + "\"" , innerE);
+            }
+        }
+        init();
+    }
+
+    // Initialize.  Size is a count of LogRecords.
+    private void init() {
+        buffer = new LogRecord[size];
+        start = 0;
+        count = 0;
+    }
+
+    /**
+     * Create a <tt>MemoryHandler</tt>.
+     * <p>
+     * The <tt>MemoryHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given <tt>pushLevel</tt>
+     * argument and buffer size argument are used.
+     *
+     * @param target  the Handler to which to publish output.
+     * @param size    the number of log records to buffer (must be greater than zero)
+     * @param pushLevel  message level to push on
+     *
+     * @throws IllegalArgumentException if {@code size is <= 0}
+     */
+    public MemoryHandler(Handler target, int size, Level pushLevel) {
+        if (target == null || pushLevel == null) {
+            throw new NullPointerException();
+        }
+        if (size <= 0) {
+            throw new IllegalArgumentException();
+        }
+        sealed = false;
+        configure();
+        sealed = true;
+        this.target = target;
+        this.pushLevel = pushLevel;
+        this.size = size;
+        init();
+    }
+
+    /**
+     * Store a <tt>LogRecord</tt> in an internal buffer.
+     * <p>
+     * If there is a <tt>Filter</tt>, its <tt>isLoggable</tt>
+     * method is called to check if the given log record is loggable.
+     * If not we return.  Otherwise the given record is copied into
+     * an internal circular buffer.  Then the record's level property is
+     * compared with the <tt>pushLevel</tt>. If the given level is
+     * greater than or equal to the <tt>pushLevel</tt> then <tt>push</tt>
+     * is called to write all buffered records to the target output
+     * <tt>Handler</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        int ix = (start+count)%buffer.length;
+        buffer[ix] = record;
+        if (count < buffer.length) {
+            count++;
+        } else {
+            start++;
+            start %= buffer.length;
+        }
+        if (record.getLevel().intValue() >= pushLevel.intValue()) {
+            push();
+        }
+    }
+
+    /**
+     * Push any buffered output to the target <tt>Handler</tt>.
+     * <p>
+     * The buffer is then cleared.
+     */
+    public synchronized void push() {
+        for (int i = 0; i < count; i++) {
+            int ix = (start+i)%buffer.length;
+            LogRecord record = buffer[ix];
+            target.publish(record);
+        }
+        // Empty the buffer.
+        start = 0;
+        count = 0;
+    }
+
+    /**
+     * Causes a flush on the target <tt>Handler</tt>.
+     * <p>
+     * Note that the current contents of the <tt>MemoryHandler</tt>
+     * buffer are <b>not</b> written out.  That requires a "push".
+     */
+    @Override
+    public void flush() {
+        target.flush();
+    }
+
+    /**
+     * Close the <tt>Handler</tt> and free all associated resources.
+     * This will also close the target <tt>Handler</tt>.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public void close() throws SecurityException {
+        target.close();
+        setLevel(Level.OFF);
+    }
+
+    /**
+     * Set the <tt>pushLevel</tt>.  After a <tt>LogRecord</tt> is copied
+     * into our internal buffer, if its level is greater than or equal to
+     * the <tt>pushLevel</tt>, then <tt>push</tt> will be called.
+     *
+     * @param newLevel the new value of the <tt>pushLevel</tt>
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    public synchronized void setPushLevel(Level newLevel) throws SecurityException {
+        if (newLevel == null) {
+            throw new NullPointerException();
+        }
+        checkPermission();
+        pushLevel = newLevel;
+    }
+
+    /**
+     * Get the <tt>pushLevel</tt>.
+     *
+     * @return the value of the <tt>pushLevel</tt>
+     */
+    public Level getPushLevel() {
+        return pushLevel;
+    }
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given
+     * <tt>LogRecord</tt> into its internal buffer.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate level and
+     * whether it satisfies any <tt>Filter</tt>.  However it does <b>not</b>
+     * check whether the <tt>LogRecord</tt> would result in a "push" of the
+     * buffer contents. It will return false if the <tt>LogRecord</tt> is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    @Override
+    public boolean isLoggable(LogRecord record) {
+        return super.isLoggable(record);
+    }
+}
diff --git a/java/util/logging/SimpleFormatter.java b/java/util/logging/SimpleFormatter.java
new file mode 100644
index 0000000..12412f1
--- /dev/null
+++ b/java/util/logging/SimpleFormatter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.text.*;
+import java.util.Date;
+import sun.util.logging.LoggingSupport;
+
+/**
+ * Print a brief summary of the {@code LogRecord} in a human readable
+ * format.  The summary will typically be 1 or 2 lines.
+ *
+ * <p>
+ * <a name="formatting">
+ * <b>Configuration:</b></a>
+ * The {@code SimpleFormatter} is initialized with the
+ * <a href="../Formatter.html#syntax">format string</a>
+ * specified in the {@code java.util.logging.SimpleFormatter.format}
+ * property to {@linkplain #format format} the log messages.
+ * This property can be defined
+ * in the {@linkplain LogManager#getProperty logging properties}
+ * configuration file
+ * or as a system property.  If this property is set in both
+ * the logging properties and system properties,
+ * the format string specified in the system property will be used.
+ * If this property is not defined or the given format string
+ * is {@linkplain java.util.IllegalFormatException illegal},
+ * the default format is implementation-specific.
+ *
+ * @since 1.4
+ * @see java.util.Formatter
+ */
+
+public class SimpleFormatter extends Formatter {
+
+    // format string for printing the log record
+    private static final String format = LoggingSupport.getSimpleFormat();
+    private final Date dat = new Date();
+
+    /**
+     * Format the given LogRecord.
+     * <p>
+     * The formatting can be customized by specifying the
+     * <a href="../Formatter.html#syntax">format string</a>
+     * in the <a href="#formatting">
+     * {@code java.util.logging.SimpleFormatter.format}</a> property.
+     * The given {@code LogRecord} will be formatted as if by calling:
+     * <pre>
+     *    {@link String#format String.format}(format, date, source, logger, level, message, thrown);
+     * </pre>
+     * where the arguments are:<br>
+     * <ol>
+     * <li>{@code format} - the {@link java.util.Formatter
+     *     java.util.Formatter} format string specified in the
+     *     {@code java.util.logging.SimpleFormatter.format} property
+     *     or the default format.</li>
+     * <li>{@code date} - a {@link Date} object representing
+     *     {@linkplain LogRecord#getMillis event time} of the log record.</li>
+     * <li>{@code source} - a string representing the caller, if available;
+     *     otherwise, the logger's name.</li>
+     * <li>{@code logger} - the logger's name.</li>
+     * <li>{@code level} - the {@linkplain Level#getLocalizedName
+     *     log level}.</li>
+     * <li>{@code message} - the formatted log message
+     *     returned from the {@link Formatter#formatMessage(LogRecord)}
+     *     method.  It uses {@link java.text.MessageFormat java.text}
+     *     formatting and does not use the {@code java.util.Formatter
+     *     format} argument.</li>
+     * <li>{@code thrown} - a string representing
+     *     the {@linkplain LogRecord#getThrown throwable}
+     *     associated with the log record and its backtrace
+     *     beginning with a newline character, if any;
+     *     otherwise, an empty string.</li>
+     * </ol>
+     *
+     * <p>Some example formats:<br>
+     * <ul>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"}
+     *     <p>This prints 1 line with the log level ({@code 4$}),
+     *     the log message ({@code 5$}) and the timestamp ({@code 1$}) in
+     *     a square bracket.
+     *     <pre>
+     *     WARNING: warning message [Tue Mar 22 13:11:31 PDT 2011]
+     *     </pre></li>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%1$tc %2$s%n%4$s: %5$s%6$s%n"}
+     *     <p>This prints 2 lines where the first line includes
+     *     the timestamp ({@code 1$}) and the source ({@code 2$});
+     *     the second line includes the log level ({@code 4$}) and
+     *     the log message ({@code 5$}) followed with the throwable
+     *     and its backtrace ({@code 6$}), if any:
+     *     <pre>
+     *     Tue Mar 22 13:11:31 PDT 2011 MyClass fatal
+     *     SEVERE: several message with an exception
+     *     java.lang.IllegalArgumentException: invalid argument
+     *             at MyClass.mash(MyClass.java:9)
+     *             at MyClass.crunch(MyClass.java:6)
+     *             at MyClass.main(MyClass.java:3)
+     *     </pre></li>
+     * <li> {@code java.util.logging.SimpleFormatter.format="%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%n"}
+     *      <p>This prints 2 lines similar to the example above
+     *         with a different date/time formatting and does not print
+     *         the throwable and its backtrace:
+     *     <pre>
+     *     Mar 22, 2011 1:11:31 PM MyClass fatal
+     *     SEVERE: several message with an exception
+     *     </pre></li>
+     * </ul>
+     * <p>This method can also be overridden in a subclass.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return a formatted log record
+     */
+    public synchronized String format(LogRecord record) {
+        dat.setTime(record.getMillis());
+        String source;
+        if (record.getSourceClassName() != null) {
+            source = record.getSourceClassName();
+            if (record.getSourceMethodName() != null) {
+               source += " " + record.getSourceMethodName();
+            }
+        } else {
+            source = record.getLoggerName();
+        }
+        String message = formatMessage(record);
+        String throwable = "";
+        if (record.getThrown() != null) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            pw.println();
+            record.getThrown().printStackTrace(pw);
+            pw.close();
+            throwable = sw.toString();
+        }
+        return String.format(format,
+                             dat,
+                             source,
+                             record.getLoggerName(),
+                             record.getLevel().getLocalizedLevelName(),
+                             message,
+                             throwable);
+    }
+}
diff --git a/java/util/logging/SocketHandler.java b/java/util/logging/SocketHandler.java
new file mode 100644
index 0000000..2561e90
--- /dev/null
+++ b/java/util/logging/SocketHandler.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.net.*;
+import libcore.net.NetworkSecurityPolicy;
+
+/**
+ * Simple network logging <tt>Handler</tt>.
+ * <p>
+ * <tt>LogRecords</tt> are published to a network stream connection.  By default
+ * the <tt>XMLFormatter</tt> class is used for formatting.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>SocketHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.ALL</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *        (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.XMLFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * <li>   &lt;handler-name&gt;.host
+ *        specifies the target host name to connect to (no default). </li>
+ * <li>   &lt;handler-name&gt;.port
+ *        specifies the target TCP port to use (no default). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code SocketHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.SocketHandler.level=INFO </li>
+ * <li>   java.util.logging.SocketHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * The output IO stream is buffered, but is flushed after each
+ * <tt>LogRecord</tt> is written.
+ *
+ * @since 1.4
+ */
+
+public class SocketHandler extends StreamHandler {
+    private Socket sock;
+    private String host;
+    private int port;
+
+    // Private method to configure a SocketHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.ALL));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new XMLFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+        port = manager.getIntProperty(cname + ".port", 0);
+        host = manager.getStringProperty(cname + ".host", null);
+    }
+
+
+    /**
+     * Create a <tt>SocketHandler</tt>, using only <tt>LogManager</tt> properties
+     * (or their defaults).
+     * @throws IllegalArgumentException if the host or port are invalid or
+     *          are not specified as LogManager properties.
+     * @throws IOException if we are unable to connect to the target
+     *         host and port.
+     */
+    public SocketHandler() throws IOException {
+        // We are going to use the logging defaults.
+        sealed = false;
+        configure();
+
+        try {
+            connect();
+        } catch (IOException ix) {
+            System.err.println("SocketHandler: connect failed to " + host + ":" + port);
+            throw ix;
+        }
+        sealed = true;
+    }
+
+    /**
+     * Construct a <tt>SocketHandler</tt> using a specified host and port.
+     *
+     * The <tt>SocketHandler</tt> is configured based on <tt>LogManager</tt>
+     * properties (or their default values) except that the given target host
+     * and port arguments are used. If the host argument is empty, but not
+     * null String then the localhost is used.
+     *
+     * @param host target host.
+     * @param port target port.
+     *
+     * @throws IllegalArgumentException if the host or port are invalid.
+     * @throws IOException if we are unable to connect to the target
+     *         host and port.
+     */
+    public SocketHandler(String host, int port) throws IOException {
+        sealed = false;
+        configure();
+        sealed = true;
+        this.port = port;
+        this.host = host;
+        connect();
+    }
+
+    private void connect() throws IOException {
+        // Check the arguments are valid.
+        if (port == 0) {
+            throw new IllegalArgumentException("Bad port: " + port);
+        }
+        if (host == null) {
+            throw new IllegalArgumentException("Null host name: " + host);
+        }
+
+        // Android-added: Enforce cleartext policy.
+        if (!NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted()) {
+            throw new IOException("Cleartext traffic not permitted");
+        }
+
+        // Try to open a new socket.
+        sock = new Socket(host, port);
+        OutputStream out = sock.getOutputStream();
+        BufferedOutputStream bout = new BufferedOutputStream(out);
+        setOutputStream(bout);
+    }
+
+    /**
+     * Close this output stream.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        super.close();
+        if (sock != null) {
+            try {
+                sock.close();
+            } catch (IOException ix) {
+                // drop through.
+            }
+        }
+        sock = null;
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        super.publish(record);
+        flush();
+    }
+}
diff --git a/java/util/logging/StreamHandler.java b/java/util/logging/StreamHandler.java
new file mode 100644
index 0000000..3b5a276
--- /dev/null
+++ b/java/util/logging/StreamHandler.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+
+/**
+ * Stream based logging <tt>Handler</tt>.
+ * <p>
+ * This is primarily intended as a base class or support class to
+ * be used in implementing other logging <tt>Handlers</tt>.
+ * <p>
+ * <tt>LogRecords</tt> are published to a given <tt>java.io.OutputStream</tt>.
+ * <p>
+ * <b>Configuration:</b>
+ * By default each <tt>StreamHandler</tt> is initialized using the following
+ * <tt>LogManager</tt> configuration properties where <tt>&lt;handler-name&gt;</tt>
+ * refers to the fully-qualified class name of the handler.
+ * If properties are not defined
+ * (or have invalid values) then the specified default values are used.
+ * <ul>
+ * <li>   &lt;handler-name&gt;.level
+ *        specifies the default level for the <tt>Handler</tt>
+ *        (defaults to <tt>Level.INFO</tt>). </li>
+ * <li>   &lt;handler-name&gt;.filter
+ *        specifies the name of a <tt>Filter</tt> class to use
+ *         (defaults to no <tt>Filter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.formatter
+ *        specifies the name of a <tt>Formatter</tt> class to use
+ *        (defaults to <tt>java.util.logging.SimpleFormatter</tt>). </li>
+ * <li>   &lt;handler-name&gt;.encoding
+ *        the name of the character set encoding to use (defaults to
+ *        the default platform encoding). </li>
+ * </ul>
+ * <p>
+ * For example, the properties for {@code StreamHandler} would be:
+ * <ul>
+ * <li>   java.util.logging.StreamHandler.level=INFO </li>
+ * <li>   java.util.logging.StreamHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be:
+ * <ul>
+ * <li>   com.foo.MyHandler.level=INFO </li>
+ * <li>   com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter </li>
+ * </ul>
+ * <p>
+ * @since 1.4
+ */
+
+public class StreamHandler extends Handler {
+    private OutputStream output;
+    private boolean doneHeader;
+    private volatile Writer writer;
+
+    // Private method to configure a StreamHandler from LogManager
+    // properties and/or default values as specified in the class
+    // javadoc.
+    private void configure() {
+        LogManager manager = LogManager.getLogManager();
+        String cname = getClass().getName();
+
+        setLevel(manager.getLevelProperty(cname +".level", Level.INFO));
+        setFilter(manager.getFilterProperty(cname +".filter", null));
+        setFormatter(manager.getFormatterProperty(cname +".formatter", new SimpleFormatter()));
+        try {
+            setEncoding(manager.getStringProperty(cname +".encoding", null));
+        } catch (Exception ex) {
+            try {
+                setEncoding(null);
+            } catch (Exception ex2) {
+                // doing a setEncoding with null should always work.
+                // assert false;
+            }
+        }
+    }
+
+    /**
+     * Create a <tt>StreamHandler</tt>, with no current output stream.
+     */
+    public StreamHandler() {
+        sealed = false;
+        configure();
+        sealed = true;
+    }
+
+    /**
+     * Create a <tt>StreamHandler</tt> with a given <tt>Formatter</tt>
+     * and output stream.
+     * <p>
+     * @param out         the target output stream
+     * @param formatter   Formatter to be used to format output
+     */
+    public StreamHandler(OutputStream out, Formatter formatter) {
+        sealed = false;
+        configure();
+        setFormatter(formatter);
+        setOutputStream(out);
+        sealed = true;
+    }
+
+    /**
+     * Change the output stream.
+     * <P>
+     * If there is a current output stream then the <tt>Formatter</tt>'s
+     * tail string is written and the stream is flushed and closed.
+     * Then the output stream is replaced with the new output stream.
+     *
+     * @param out   New output stream.  May not be null.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     */
+    protected synchronized void setOutputStream(OutputStream out) throws SecurityException {
+        if (out == null) {
+            throw new NullPointerException();
+        }
+        flushAndClose();
+        output = out;
+        doneHeader = false;
+        String encoding = getEncoding();
+        if (encoding == null) {
+            writer = new OutputStreamWriter(output);
+        } else {
+            try {
+                writer = new OutputStreamWriter(output, encoding);
+            } catch (UnsupportedEncodingException ex) {
+                // This shouldn't happen.  The setEncoding method
+                // should have validated that the encoding is OK.
+                throw new Error("Unexpected exception " + ex);
+            }
+        }
+    }
+
+    /**
+     * Set (or change) the character encoding used by this <tt>Handler</tt>.
+     * <p>
+     * The encoding should be set before any <tt>LogRecords</tt> are written
+     * to the <tt>Handler</tt>.
+     *
+     * @param encoding  The name of a supported character encoding.
+     *        May be null, to indicate the default platform encoding.
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have <tt>LoggingPermission("control")</tt>.
+     * @exception  UnsupportedEncodingException if the named encoding is
+     *          not supported.
+     */
+    @Override
+    public synchronized void setEncoding(String encoding)
+                        throws SecurityException, java.io.UnsupportedEncodingException {
+        super.setEncoding(encoding);
+        if (output == null) {
+            return;
+        }
+        // Replace the current writer with a writer for the new encoding.
+        flush();
+        if (encoding == null) {
+            writer = new OutputStreamWriter(output);
+        } else {
+            writer = new OutputStreamWriter(output, encoding);
+        }
+    }
+
+    /**
+     * Format and publish a <tt>LogRecord</tt>.
+     * <p>
+     * The <tt>StreamHandler</tt> first checks if there is an <tt>OutputStream</tt>
+     * and if the given <tt>LogRecord</tt> has at least the required log level.
+     * If not it silently returns.  If so, it calls any associated
+     * <tt>Filter</tt> to check if the record should be published.  If so,
+     * it calls its <tt>Formatter</tt> to format the record and then writes
+     * the result to the current output stream.
+     * <p>
+     * If this is the first <tt>LogRecord</tt> to be written to a given
+     * <tt>OutputStream</tt>, the <tt>Formatter</tt>'s "head" string is
+     * written to the stream before the <tt>LogRecord</tt> is written.
+     *
+     * @param  record  description of the log event. A null record is
+     *                 silently ignored and is not published
+     */
+    @Override
+    public synchronized void publish(LogRecord record) {
+        if (!isLoggable(record)) {
+            return;
+        }
+        String msg;
+        try {
+            msg = getFormatter().format(record);
+        } catch (Exception ex) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ex, ErrorManager.FORMAT_FAILURE);
+            return;
+        }
+
+        try {
+            if (!doneHeader) {
+                writer.write(getFormatter().getHead(this));
+                doneHeader = true;
+            }
+            writer.write(msg);
+        } catch (Exception ex) {
+            // We don't want to throw an exception here, but we
+            // report the exception to any registered ErrorManager.
+            reportError(null, ex, ErrorManager.WRITE_FAILURE);
+        }
+    }
+
+
+    /**
+     * Check if this <tt>Handler</tt> would actually log a given <tt>LogRecord</tt>.
+     * <p>
+     * This method checks if the <tt>LogRecord</tt> has an appropriate level and
+     * whether it satisfies any <tt>Filter</tt>.  It will also return false if
+     * no output stream has been assigned yet or the LogRecord is null.
+     * <p>
+     * @param record  a <tt>LogRecord</tt>
+     * @return true if the <tt>LogRecord</tt> would be logged.
+     *
+     */
+    @Override
+    public boolean isLoggable(LogRecord record) {
+        if (writer == null || record == null) {
+            return false;
+        }
+        return super.isLoggable(record);
+    }
+
+    /**
+     * Flush any buffered messages.
+     */
+    @Override
+    public synchronized void flush() {
+        if (writer != null) {
+            try {
+                writer.flush();
+            } catch (Exception ex) {
+                // We don't want to throw an exception here, but we
+                // report the exception to any registered ErrorManager.
+                reportError(null, ex, ErrorManager.FLUSH_FAILURE);
+            }
+        }
+    }
+
+    private synchronized void flushAndClose() throws SecurityException {
+        checkPermission();
+        if (writer != null) {
+            try {
+                if (!doneHeader) {
+                    writer.write(getFormatter().getHead(this));
+                    doneHeader = true;
+                }
+                writer.write(getFormatter().getTail(this));
+                writer.flush();
+                writer.close();
+            } catch (Exception ex) {
+                // We don't want to throw an exception here, but we
+                // report the exception to any registered ErrorManager.
+                reportError(null, ex, ErrorManager.CLOSE_FAILURE);
+            }
+            writer = null;
+            output = null;
+        }
+    }
+
+    /**
+     * Close the current output stream.
+     * <p>
+     * The <tt>Formatter</tt>'s "tail" string is written to the stream before it
+     * is closed.  In addition, if the <tt>Formatter</tt>'s "head" string has not
+     * yet been written to the stream, it will be written before the
+     * "tail" string.
+     *
+     * @exception  SecurityException  if a security manager exists and if
+     *             the caller does not have LoggingPermission("control").
+     */
+    @Override
+    public synchronized void close() throws SecurityException {
+        flushAndClose();
+    }
+}
diff --git a/java/util/logging/XMLFormatter.java b/java/util/logging/XMLFormatter.java
new file mode 100644
index 0000000..ab95f58
--- /dev/null
+++ b/java/util/logging/XMLFormatter.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.logging;
+
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * Format a LogRecord into a standard XML format.
+ * <p>
+ * The DTD specification is provided as Appendix A to the
+ * Java Logging APIs specification.
+ * <p>
+ * The XMLFormatter can be used with arbitrary character encodings,
+ * but it is recommended that it normally be used with UTF-8.  The
+ * character encoding can be set on the output Handler.
+ *
+ * @since 1.4
+ */
+
+public class XMLFormatter extends Formatter {
+    private LogManager manager = LogManager.getLogManager();
+
+    // Append a two digit number.
+    private void a2(StringBuilder sb, int x) {
+        if (x < 10) {
+            sb.append('0');
+        }
+        sb.append(x);
+    }
+
+    // Append the time and date in ISO 8601 format
+    private void appendISO8601(StringBuilder sb, long millis) {
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.setTimeInMillis(millis);
+        sb.append(cal.get(Calendar.YEAR));
+        sb.append('-');
+        a2(sb, cal.get(Calendar.MONTH) + 1);
+        sb.append('-');
+        a2(sb, cal.get(Calendar.DAY_OF_MONTH));
+        sb.append('T');
+        a2(sb, cal.get(Calendar.HOUR_OF_DAY));
+        sb.append(':');
+        a2(sb, cal.get(Calendar.MINUTE));
+        sb.append(':');
+        a2(sb, cal.get(Calendar.SECOND));
+    }
+
+    // Append to the given StringBuilder an escaped version of the
+    // given text string where XML special characters have been escaped.
+    // For a null string we append "<null>"
+    private void escape(StringBuilder sb, String text) {
+        if (text == null) {
+            text = "<null>";
+        }
+        for (int i = 0; i < text.length(); i++) {
+            char ch = text.charAt(i);
+            if (ch == '<') {
+                sb.append("&lt;");
+            } else if (ch == '>') {
+                sb.append("&gt;");
+            } else if (ch == '&') {
+                sb.append("&amp;");
+            } else {
+                sb.append(ch);
+            }
+        }
+    }
+
+    /**
+     * Format the given message to XML.
+     * <p>
+     * This method can be overridden in a subclass.
+     * It is recommended to use the {@link Formatter#formatMessage}
+     * convenience method to localize and format the message field.
+     *
+     * @param record the log record to be formatted.
+     * @return a formatted log record
+     */
+    public String format(LogRecord record) {
+        StringBuilder sb = new StringBuilder(500);
+        sb.append("<record>\n");
+
+        sb.append("  <date>");
+        appendISO8601(sb, record.getMillis());
+        sb.append("</date>\n");
+
+        sb.append("  <millis>");
+        sb.append(record.getMillis());
+        sb.append("</millis>\n");
+
+        sb.append("  <sequence>");
+        sb.append(record.getSequenceNumber());
+        sb.append("</sequence>\n");
+
+        String name = record.getLoggerName();
+        if (name != null) {
+            sb.append("  <logger>");
+            escape(sb, name);
+            sb.append("</logger>\n");
+        }
+
+        sb.append("  <level>");
+        escape(sb, record.getLevel().toString());
+        sb.append("</level>\n");
+
+        if (record.getSourceClassName() != null) {
+            sb.append("  <class>");
+            escape(sb, record.getSourceClassName());
+            sb.append("</class>\n");
+        }
+
+        if (record.getSourceMethodName() != null) {
+            sb.append("  <method>");
+            escape(sb, record.getSourceMethodName());
+            sb.append("</method>\n");
+        }
+
+        sb.append("  <thread>");
+        sb.append(record.getThreadID());
+        sb.append("</thread>\n");
+
+        if (record.getMessage() != null) {
+            // Format the message string and its accompanying parameters.
+            String message = formatMessage(record);
+            sb.append("  <message>");
+            escape(sb, message);
+            sb.append("</message>");
+            sb.append("\n");
+        // Android-added: Include empty <message/> tag. http://b/25861348#comment17
+        } else {
+            sb.append("<message/>");
+            sb.append("\n");
+        }
+
+        // If the message is being localized, output the key, resource
+        // bundle name, and params.
+        ResourceBundle bundle = record.getResourceBundle();
+        try {
+            if (bundle != null && bundle.getString(record.getMessage()) != null) {
+                sb.append("  <key>");
+                escape(sb, record.getMessage());
+                sb.append("</key>\n");
+                sb.append("  <catalog>");
+                escape(sb, record.getResourceBundleName());
+                sb.append("</catalog>\n");
+            }
+        } catch (Exception ex) {
+            // The message is not in the catalog.  Drop through.
+        }
+
+        Object parameters[] = record.getParameters();
+        //  Check to see if the parameter was not a messagetext format
+        //  or was not null or empty
+        if ( parameters != null && parameters.length != 0
+                && record.getMessage().indexOf("{") == -1 ) {
+            for (int i = 0; i < parameters.length; i++) {
+                sb.append("  <param>");
+                try {
+                    escape(sb, parameters[i].toString());
+                } catch (Exception ex) {
+                    sb.append("???");
+                }
+                sb.append("</param>\n");
+            }
+        }
+
+        if (record.getThrown() != null) {
+            // Report on the state of the throwable.
+            Throwable th = record.getThrown();
+            sb.append("  <exception>\n");
+            sb.append("    <message>");
+            escape(sb, th.toString());
+            sb.append("</message>\n");
+            StackTraceElement trace[] = th.getStackTrace();
+            for (int i = 0; i < trace.length; i++) {
+                StackTraceElement frame = trace[i];
+                sb.append("    <frame>\n");
+                sb.append("      <class>");
+                escape(sb, frame.getClassName());
+                sb.append("</class>\n");
+                sb.append("      <method>");
+                escape(sb, frame.getMethodName());
+                sb.append("</method>\n");
+                // Check for a line number.
+                if (frame.getLineNumber() >= 0) {
+                    sb.append("      <line>");
+                    sb.append(frame.getLineNumber());
+                    sb.append("</line>\n");
+                }
+                sb.append("    </frame>\n");
+            }
+            sb.append("  </exception>\n");
+        }
+
+        sb.append("</record>\n");
+        return sb.toString();
+    }
+
+    /**
+     * Return the header string for a set of XML formatted records.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  a valid XML string
+     */
+    public String getHead(Handler h) {
+        StringBuilder sb = new StringBuilder();
+        String encoding;
+        sb.append("<?xml version=\"1.0\"");
+
+        if (h != null) {
+            encoding = h.getEncoding();
+        } else {
+            encoding = null;
+        }
+
+        if (encoding == null) {
+            // Figure out the default encoding.
+            encoding = java.nio.charset.Charset.defaultCharset().name();
+        }
+        // Try to map the encoding name to a canonical name.
+        try {
+            Charset cs = Charset.forName(encoding);
+            encoding = cs.name();
+        } catch (Exception ex) {
+            // We hit problems finding a canonical name.
+            // Just use the raw encoding name.
+        }
+
+        sb.append(" encoding=\"");
+        sb.append(encoding);
+        sb.append("\"");
+        sb.append(" standalone=\"no\"?>\n");
+        sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">\n");
+        sb.append("<log>\n");
+        return sb.toString();
+    }
+
+    /**
+     * Return the tail string for a set of XML formatted records.
+     *
+     * @param   h  The target handler (can be null)
+     * @return  a valid XML string
+     */
+    public String getTail(Handler h) {
+        return "</log>\n";
+    }
+}
diff --git a/java/util/prefs/AbstractPreferences.java b/java/util/prefs/AbstractPreferences.java
new file mode 100644
index 0000000..71616ee
--- /dev/null
+++ b/java/util/prefs/AbstractPreferences.java
@@ -0,0 +1,1669 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.util.*;
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+// These imports needed only as a workaround for a JavaDoc bug
+import java.lang.Integer;
+import java.lang.Long;
+import java.lang.Float;
+import java.lang.Double;
+
+/**
+ * This class provides a skeletal implementation of the {@link Preferences}
+ * class, greatly easing the task of implementing it.
+ *
+ * <p><strong>This class is for <tt>Preferences</tt> implementers only.
+ * Normal users of the <tt>Preferences</tt> facility should have no need to
+ * consult this documentation.  The {@link Preferences} documentation
+ * should suffice.</strong>
+ *
+ * <p>Implementors must override the nine abstract service-provider interface
+ * (SPI) methods: {@link #getSpi(String)}, {@link #putSpi(String,String)},
+ * {@link #removeSpi(String)}, {@link #childSpi(String)}, {@link
+ * #removeNodeSpi()}, {@link #keysSpi()}, {@link #childrenNamesSpi()}, {@link
+ * #syncSpi()} and {@link #flushSpi()}.  All of the concrete methods specify
+ * precisely how they are implemented atop these SPI methods.  The implementor
+ * may, at his discretion, override one or more of the concrete methods if the
+ * default implementation is unsatisfactory for any reason, such as
+ * performance.
+ *
+ * <p>The SPI methods fall into three groups concerning exception
+ * behavior. The <tt>getSpi</tt> method should never throw exceptions, but it
+ * doesn't really matter, as any exception thrown by this method will be
+ * intercepted by {@link #get(String,String)}, which will return the specified
+ * default value to the caller.  The <tt>removeNodeSpi, keysSpi,
+ * childrenNamesSpi, syncSpi</tt> and <tt>flushSpi</tt> methods are specified
+ * to throw {@link BackingStoreException}, and the implementation is required
+ * to throw this checked exception if it is unable to perform the operation.
+ * The exception propagates outward, causing the corresponding API method
+ * to fail.
+ *
+ * <p>The remaining SPI methods {@link #putSpi(String,String)}, {@link
+ * #removeSpi(String)} and {@link #childSpi(String)} have more complicated
+ * exception behavior.  They are not specified to throw
+ * <tt>BackingStoreException</tt>, as they can generally obey their contracts
+ * even if the backing store is unavailable.  This is true because they return
+ * no information and their effects are not required to become permanent until
+ * a subsequent call to {@link Preferences#flush()} or
+ * {@link Preferences#sync()}. Generally speaking, these SPI methods should not
+ * throw exceptions.  In some implementations, there may be circumstances
+ * under which these calls cannot even enqueue the requested operation for
+ * later processing.  Even under these circumstances it is generally better to
+ * simply ignore the invocation and return, rather than throwing an
+ * exception.  Under these circumstances, however, all subsequent invocations
+ * of <tt>flush()</tt> and <tt>sync</tt> should return <tt>false</tt>, as
+ * returning <tt>true</tt> would imply that all previous operations had
+ * successfully been made permanent.
+ *
+ * <p>There is one circumstance under which <tt>putSpi, removeSpi and
+ * childSpi</tt> <i>should</i> throw an exception: if the caller lacks
+ * sufficient privileges on the underlying operating system to perform the
+ * requested operation.  This will, for instance, occur on most systems
+ * if a non-privileged user attempts to modify system preferences.
+ * (The required privileges will vary from implementation to
+ * implementation.  On some implementations, they are the right to modify the
+ * contents of some directory in the file system; on others they are the right
+ * to modify contents of some key in a registry.)  Under any of these
+ * circumstances, it would generally be undesirable to let the program
+ * continue executing as if these operations would become permanent at a later
+ * time.  While implementations are not required to throw an exception under
+ * these circumstances, they are encouraged to do so.  A {@link
+ * SecurityException} would be appropriate.
+ *
+ * <p>Most of the SPI methods require the implementation to read or write
+ * information at a preferences node.  The implementor should beware of the
+ * fact that another VM may have concurrently deleted this node from the
+ * backing store.  It is the implementation's responsibility to recreate the
+ * node if it has been deleted.
+ *
+ * <p>Implementation note: In Sun's default <tt>Preferences</tt>
+ * implementations, the user's identity is inherited from the underlying
+ * operating system and does not change for the lifetime of the virtual
+ * machine.  It is recognized that server-side <tt>Preferences</tt>
+ * implementations may have the user identity change from request to request,
+ * implicitly passed to <tt>Preferences</tt> methods via the use of a
+ * static {@link ThreadLocal} instance.  Authors of such implementations are
+ * <i>strongly</i> encouraged to determine the user at the time preferences
+ * are accessed (for example by the {@link #get(String,String)} or {@link
+ * #put(String,String)} method) rather than permanently associating a user
+ * with each <tt>Preferences</tt> instance.  The latter behavior conflicts
+ * with normal <tt>Preferences</tt> usage and would lead to great confusion.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public abstract class AbstractPreferences extends Preferences {
+    /**
+     * Our name relative to parent.
+     */
+    private final String name;
+
+    /**
+     * Our absolute path name.
+     */
+    private final String absolutePath;
+
+    /**
+     * Our parent node.
+     */
+    final AbstractPreferences parent;
+
+    /**
+     * Our root node.
+     */
+    private final AbstractPreferences root; // Relative to this node
+
+    /**
+     * This field should be <tt>true</tt> if this node did not exist in the
+     * backing store prior to the creation of this object.  The field
+     * is initialized to false, but may be set to true by a subclass
+     * constructor (and should not be modified thereafter).  This field
+     * indicates whether a node change event should be fired when
+     * creation is complete.
+     */
+    protected boolean newNode = false;
+
+    /**
+     * All known unremoved children of this node.  (This "cache" is consulted
+     * prior to calling childSpi() or getChild().
+     */
+    private Map<String, AbstractPreferences> kidCache = new HashMap<>();
+
+    /**
+     * This field is used to keep track of whether or not this node has
+     * been removed.  Once it's set to true, it will never be reset to false.
+     */
+    private boolean removed = false;
+
+    /**
+     * Registered preference change listeners.
+     */
+    // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // It's not clear if this change provides overall benefit; it might be
+    // reverted in future. Discussion: http://b/111195881
+    // private PreferenceChangeListener[] prefListeners =
+    //     new PreferenceChangeListener[0];
+    private final ArrayList<PreferenceChangeListener> prefListeners = new ArrayList<>();
+
+    /**
+     * Registered node change listeners.
+     */
+    // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // private NodeChangeListener[] nodeListeners = new NodeChangeListener[0];
+    private final ArrayList<NodeChangeListener> nodeListeners = new ArrayList<>();
+
+    /**
+     * An object whose monitor is used to lock this node.  This object
+     * is used in preference to the node itself to reduce the likelihood of
+     * intentional or unintentional denial of service due to a locked node.
+     * To avoid deadlock, a node is <i>never</i> locked by a thread that
+     * holds a lock on a descendant of that node.
+     */
+    protected final Object lock = new Object();
+
+    /**
+     * Creates a preference node with the specified parent and the specified
+     * name relative to its parent.
+     *
+     * @param parent the parent of this preference node, or null if this
+     *               is the root.
+     * @param name the name of this preference node, relative to its parent,
+     *             or <tt>""</tt> if this is the root.
+     * @throws IllegalArgumentException if <tt>name</tt> contains a slash
+     *          (<tt>'/'</tt>),  or <tt>parent</tt> is <tt>null</tt> and
+     *          name isn't <tt>""</tt>.
+     */
+    protected AbstractPreferences(AbstractPreferences parent, String name) {
+        if (parent==null) {
+            if (!name.equals(""))
+                throw new IllegalArgumentException("Root name '"+name+
+                                                   "' must be \"\"");
+            this.absolutePath = "/";
+            root = this;
+        } else {
+            if (name.indexOf('/') != -1)
+                throw new IllegalArgumentException("Name '" + name +
+                                                 "' contains '/'");
+            if (name.equals(""))
+              throw new IllegalArgumentException("Illegal name: empty string");
+
+            root = parent.root;
+            absolutePath = (parent==root ? "/" + name
+                                         : parent.absolutePath() + "/" + name);
+        }
+        this.name = name;
+        this.parent = parent;
+    }
+
+    /**
+     * Implements the <tt>put</tt> method as per the specification in
+     * {@link Preferences#put(String,String)}.
+     *
+     * <p>This implementation checks that the key and value are legal,
+     * obtains this preference node's lock, checks that the node
+     * has not been removed, invokes {@link #putSpi(String,String)}, and if
+     * there are any preference change listeners, enqueues a notification
+     * event for processing by the event dispatch thread.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *       <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
+     *       <tt>MAX_VALUE_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void put(String key, String value) {
+        if (key==null || value==null)
+            throw new NullPointerException();
+        if (key.length() > MAX_KEY_LENGTH)
+            throw new IllegalArgumentException("Key too long: "+key);
+        if (value.length() > MAX_VALUE_LENGTH)
+            throw new IllegalArgumentException("Value too long: "+value);
+
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            putSpi(key, value);
+            enqueuePreferenceChangeEvent(key, value);
+        }
+    }
+
+    /**
+     * Implements the <tt>get</tt> method as per the specification in
+     * {@link Preferences#get(String,String)}.
+     *
+     * <p>This implementation first checks to see if <tt>key</tt> is
+     * <tt>null</tt> throwing a <tt>NullPointerException</tt> if this is
+     * the case.  Then it obtains this preference node's lock,
+     * checks that the node has not been removed, invokes {@link
+     * #getSpi(String)}, and returns the result, unless the <tt>getSpi</tt>
+     * invocation returns <tt>null</tt> or throws an exception, in which case
+     * this invocation returns <tt>def</tt>.
+     *
+     * @param key key whose associated value is to be returned.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>.
+     * @return the value associated with <tt>key</tt>, or <tt>def</tt>
+     *         if no value is associated with <tt>key</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if key is <tt>null</tt>.  (A
+     *         <tt>null</tt> default <i>is</i> permitted.)
+     */
+    public String get(String key, String def) {
+        if (key==null)
+            throw new NullPointerException("Null key");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            String result = null;
+            try {
+                result = getSpi(key);
+            } catch (Exception e) {
+                // Ignoring exception causes default to be returned
+            }
+            return (result==null ? def : result);
+        }
+    }
+
+    /**
+     * Implements the <tt>remove(String)</tt> method as per the specification
+     * in {@link Preferences#remove(String)}.
+     *
+     * <p>This implementation obtains this preference node's lock,
+     * checks that the node has not been removed, invokes
+     * {@link #removeSpi(String)} and if there are any preference
+     * change listeners, enqueues a notification event for processing by the
+     * event dispatch thread.
+     *
+     * @param key key whose mapping is to be removed from the preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException {@inheritDoc}.
+     */
+    public void remove(String key) {
+        Objects.requireNonNull(key, "Specified key cannot be null");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            removeSpi(key);
+            enqueuePreferenceChangeEvent(key, null);
+        }
+    }
+
+    /**
+     * Implements the <tt>clear</tt> method as per the specification in
+     * {@link Preferences#clear()}.
+     *
+     * <p>This implementation obtains this preference node's lock,
+     * invokes {@link #keys()} to obtain an array of keys, and
+     * iterates over the array invoking {@link #remove(String)} on each key.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void clear() throws BackingStoreException {
+        synchronized(lock) {
+            String[] keys = keys();
+            for (int i=0; i<keys.length; i++)
+                remove(keys[i]);
+        }
+    }
+
+    /**
+     * Implements the <tt>putInt</tt> method as per the specification in
+     * {@link Preferences#putInt(String,int)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Integer#toString(int)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putInt(String key, int value) {
+        put(key, Integer.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getInt</tt> method as per the specification in
+     * {@link Preferences#getInt(String,int)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>int</tt> with
+     * {@link Integer#parseInt(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as an int.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as an int.
+     * @return the int value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         an int.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public int getInt(String key, int def) {
+        int result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Integer.parseInt(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putLong</tt> method as per the specification in
+     * {@link Preferences#putLong(String,long)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Long#toString(long)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putLong(String key, long value) {
+        put(key, Long.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getLong</tt> method as per the specification in
+     * {@link Preferences#getLong(String,long)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to a <tt>long</tt> with
+     * {@link Long#parseLong(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a long.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a long.
+     * @return the long value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a long.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public long getLong(String key, long def) {
+        long result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Long.parseLong(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putBoolean</tt> method as per the specification in
+     * {@link Preferences#putBoolean(String,boolean)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link String#valueOf(boolean)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putBoolean(String key, boolean value) {
+        put(key, String.valueOf(value));
+    }
+
+    /**
+     * Implements the <tt>getBoolean</tt> method as per the specification in
+     * {@link Preferences#getBoolean(String,boolean)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, it is compared with
+     * <tt>"true"</tt> using {@link String#equalsIgnoreCase(String)}.  If the
+     * comparison returns <tt>true</tt>, this invocation returns
+     * <tt>true</tt>.  Otherwise, the original return value is compared with
+     * <tt>"false"</tt>, again using {@link String#equalsIgnoreCase(String)}.
+     * If the comparison returns <tt>true</tt>, this invocation returns
+     * <tt>false</tt>.  Otherwise, this invocation returns <tt>def</tt>.
+     *
+     * @param key key whose associated value is to be returned as a boolean.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a boolean.
+     * @return the boolean value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a boolean.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public boolean getBoolean(String key, boolean def) {
+        boolean result = def;
+        String value = get(key, null);
+        if (value != null) {
+            if (value.equalsIgnoreCase("true"))
+                result = true;
+            else if (value.equalsIgnoreCase("false"))
+                result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putFloat</tt> method as per the specification in
+     * {@link Preferences#putFloat(String,float)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Float#toString(float)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putFloat(String key, float value) {
+        put(key, Float.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getFloat</tt> method as per the specification in
+     * {@link Preferences#getFloat(String,float)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>float</tt> with
+     * {@link Float#parseFloat(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a float.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a float.
+     * @return the float value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a float.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public float getFloat(String key, float def) {
+        float result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Float.parseFloat(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putDouble</tt> method as per the specification in
+     * {@link Preferences#putDouble(String,double)}.
+     *
+     * <p>This implementation translates <tt>value</tt> to a string with
+     * {@link Double#toString(double)} and invokes {@link #put(String,String)}
+     * on the result.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putDouble(String key, double value) {
+        put(key, Double.toString(value));
+    }
+
+    /**
+     * Implements the <tt>getDouble</tt> method as per the specification in
+     * {@link Preferences#getDouble(String,double)}.
+     *
+     * <p>This implementation invokes {@link #get(String,String) <tt>get(key,
+     * null)</tt>}.  If the return value is non-null, the implementation
+     * attempts to translate it to an <tt>double</tt> with
+     * {@link Double#parseDouble(String)}.  If the attempt succeeds, the return
+     * value is returned by this method.  Otherwise, <tt>def</tt> is returned.
+     *
+     * @param key key whose associated value is to be returned as a double.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a double.
+     * @return the double value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a double.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     */
+    public double getDouble(String key, double def) {
+        double result = def;
+        try {
+            String value = get(key, null);
+            if (value != null)
+                result = Double.parseDouble(value);
+        } catch (NumberFormatException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>putByteArray</tt> method as per the specification in
+     * {@link Preferences#putByteArray(String,byte[])}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
+     *         or if value.length exceeds MAX_VALUE_LENGTH*3/4.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public void putByteArray(String key, byte[] value) {
+        put(key, Base64.byteArrayToBase64(value));
+    }
+
+    /**
+     * Implements the <tt>getByteArray</tt> method as per the specification in
+     * {@link Preferences#getByteArray(String,byte[])}.
+     *
+     * @param key key whose associated value is to be returned as a byte array.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a byte array.
+     * @return the byte array value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a byte array.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     */
+    public byte[] getByteArray(String key, byte[] def) {
+        byte[] result = def;
+        String value = get(key, null);
+        try {
+            if (value != null)
+                result = Base64.base64ToByteArray(value);
+        }
+        catch (RuntimeException e) {
+            // Ignoring exception causes specified default to be returned
+        }
+
+        return result;
+    }
+
+    /**
+     * Implements the <tt>keys</tt> method as per the specification in
+     * {@link Preferences#keys()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed and invokes {@link #keysSpi()}.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public String[] keys() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            return keysSpi();
+        }
+    }
+
+    /**
+     * Implements the <tt>children</tt> method as per the specification in
+     * {@link Preferences#childrenNames()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed, constructs a <tt>TreeSet</tt> initialized
+     * to the names of children already cached (the children in this node's
+     * "child-cache"), invokes {@link #childrenNamesSpi()}, and adds all of the
+     * returned child-names into the set.  The elements of the tree set are
+     * dumped into a <tt>String</tt> array using the <tt>toArray</tt> method,
+     * and this array is returned.
+     *
+     * @return the names of the children of this preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #cachedChildren()
+     */
+    public String[] childrenNames() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            Set<String> s = new TreeSet<>(kidCache.keySet());
+            for (String kid : childrenNamesSpi())
+                s.add(kid);
+            return s.toArray(EMPTY_STRING_ARRAY);
+        }
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    /**
+     * Returns all known unremoved children of this node.
+     *
+     * @return all known unremoved children of this node.
+     */
+    protected final AbstractPreferences[] cachedChildren() {
+        return kidCache.values().toArray(EMPTY_ABSTRACT_PREFS_ARRAY);
+    }
+
+    private static final AbstractPreferences[] EMPTY_ABSTRACT_PREFS_ARRAY
+        = new AbstractPreferences[0];
+
+    /**
+     * Implements the <tt>parent</tt> method as per the specification in
+     * {@link Preferences#parent()}.
+     *
+     * <p>This implementation obtains this preference node's lock, checks that
+     * the node has not been removed and returns the parent value that was
+     * passed to this node's constructor.
+     *
+     * @return the parent of this preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public Preferences parent() {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            return parent;
+        }
+    }
+
+    /**
+     * Implements the <tt>node</tt> method as per the specification in
+     * {@link Preferences#node(String)}.
+     *
+     * <p>This implementation obtains this preference node's lock and checks
+     * that the node has not been removed.  If <tt>path</tt> is <tt>""</tt>,
+     * this node is returned; if <tt>path</tt> is <tt>"/"</tt>, this node's
+     * root is returned.  If the first character in <tt>path</tt> is
+     * not <tt>'/'</tt>, the implementation breaks <tt>path</tt> into
+     * tokens and recursively traverses the path from this node to the
+     * named node, "consuming" a name and a slash from <tt>path</tt> at
+     * each step of the traversal.  At each step, the current node is locked
+     * and the node's child-cache is checked for the named node.  If it is
+     * not found, the name is checked to make sure its length does not
+     * exceed <tt>MAX_NAME_LENGTH</tt>.  Then the {@link #childSpi(String)}
+     * method is invoked, and the result stored in this node's child-cache.
+     * If the newly created <tt>Preferences</tt> object's {@link #newNode}
+     * field is <tt>true</tt> and there are any node change listeners,
+     * a notification event is enqueued for processing by the event dispatch
+     * thread.
+     *
+     * <p>When there are no more tokens, the last value found in the
+     * child-cache or returned by <tt>childSpi</tt> is returned by this
+     * method.  If during the traversal, two <tt>"/"</tt> tokens occur
+     * consecutively, or the final token is <tt>"/"</tt> (rather than a name),
+     * an appropriate <tt>IllegalArgumentException</tt> is thrown.
+     *
+     * <p> If the first character of <tt>path</tt> is <tt>'/'</tt>
+     * (indicating an absolute path name) this preference node's
+     * lock is dropped prior to breaking <tt>path</tt> into tokens, and
+     * this method recursively traverses the path starting from the root
+     * (rather than starting from this node).  The traversal is otherwise
+     * identical to the one described for relative path names.  Dropping
+     * the lock on this node prior to commencing the traversal at the root
+     * node is essential to avoid the possibility of deadlock, as per the
+     * {@link #lock locking invariant}.
+     *
+     * @param path the path name of the preference node to return.
+     * @return the specified preference node.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public Preferences node(String path) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            if (path.equals(""))
+                return this;
+            if (path.equals("/"))
+                return root;
+            if (path.charAt(0) != '/')
+                return node(new StringTokenizer(path, "/", true));
+        }
+
+        // Absolute path.  Note that we've dropped our lock to avoid deadlock
+        return root.node(new StringTokenizer(path.substring(1), "/", true));
+    }
+
+    /**
+     * tokenizer contains <name> {'/' <name>}*
+     */
+    private Preferences node(StringTokenizer path) {
+        String token = path.nextToken();
+        if (token.equals("/"))  // Check for consecutive slashes
+            throw new IllegalArgumentException("Consecutive slashes in path");
+        synchronized(lock) {
+            AbstractPreferences child = kidCache.get(token);
+            if (child == null) {
+                if (token.length() > MAX_NAME_LENGTH)
+                    throw new IllegalArgumentException(
+                        "Node name " + token + " too long");
+                child = childSpi(token);
+                if (child.newNode)
+                    enqueueNodeAddedEvent(child);
+                kidCache.put(token, child);
+            }
+            if (!path.hasMoreTokens())
+                return child;
+            path.nextToken();  // Consume slash
+            if (!path.hasMoreTokens())
+                throw new IllegalArgumentException("Path ends with slash");
+            return child.node(path);
+        }
+    }
+
+    /**
+     * Implements the <tt>nodeExists</tt> method as per the specification in
+     * {@link Preferences#nodeExists(String)}.
+     *
+     * <p>This implementation is very similar to {@link #node(String)},
+     * except that {@link #getChild(String)} is used instead of {@link
+     * #childSpi(String)}.
+     *
+     * @param path the path name of the node whose existence is to be checked.
+     * @return true if the specified node exists.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method and
+     *         <tt>pathname</tt> is not the empty string (<tt>""</tt>).
+     */
+    public boolean nodeExists(String path)
+        throws BackingStoreException
+    {
+        synchronized(lock) {
+            if (path.equals(""))
+                return !removed;
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            if (path.equals("/"))
+                return true;
+            if (path.charAt(0) != '/')
+                return nodeExists(new StringTokenizer(path, "/", true));
+        }
+
+        // Absolute path.  Note that we've dropped our lock to avoid deadlock
+        return root.nodeExists(new StringTokenizer(path.substring(1), "/",
+                                                   true));
+    }
+
+    /**
+     * tokenizer contains <name> {'/' <name>}*
+     */
+    private boolean nodeExists(StringTokenizer path)
+        throws BackingStoreException
+    {
+        String token = path.nextToken();
+        if (token.equals("/"))  // Check for consecutive slashes
+            throw new IllegalArgumentException("Consecutive slashes in path");
+        synchronized(lock) {
+            AbstractPreferences child = kidCache.get(token);
+            if (child == null)
+                child = getChild(token);
+            if (child==null)
+                return false;
+            if (!path.hasMoreTokens())
+                return true;
+            path.nextToken();  // Consume slash
+            if (!path.hasMoreTokens())
+                throw new IllegalArgumentException("Path ends with slash");
+            return child.nodeExists(path);
+        }
+    }
+
+    /**
+
+     * Implements the <tt>removeNode()</tt> method as per the specification in
+     * {@link Preferences#removeNode()}.
+     *
+     * <p>This implementation checks to see that this node is the root; if so,
+     * it throws an appropriate exception.  Then, it locks this node's parent,
+     * and calls a recursive helper method that traverses the subtree rooted at
+     * this node.  The recursive method locks the node on which it was called,
+     * checks that it has not already been removed, and then ensures that all
+     * of its children are cached: The {@link #childrenNamesSpi()} method is
+     * invoked and each returned child name is checked for containment in the
+     * child-cache.  If a child is not already cached, the {@link
+     * #childSpi(String)} method is invoked to create a <tt>Preferences</tt>
+     * instance for it, and this instance is put into the child-cache.  Then
+     * the helper method calls itself recursively on each node contained in its
+     * child-cache.  Next, it invokes {@link #removeNodeSpi()}, marks itself
+     * as removed, and removes itself from its parent's child-cache.  Finally,
+     * if there are any node change listeners, it enqueues a notification
+     * event for processing by the event dispatch thread.
+     *
+     * <p>Note that the helper method is always invoked with all ancestors up
+     * to the "closest non-removed ancestor" locked.
+     *
+     * @throws IllegalStateException if this node (or an ancestor) has already
+     *         been removed with the {@link #removeNode()} method.
+     * @throws UnsupportedOperationException if this method is invoked on
+     *         the root node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    public void removeNode() throws BackingStoreException {
+        if (this==root)
+            throw new UnsupportedOperationException("Can't remove the root!");
+        synchronized(parent.lock) {
+            removeNode2();
+            parent.kidCache.remove(name);
+        }
+    }
+
+    /*
+     * Called with locks on all nodes on path from parent of "removal root"
+     * to this (including the former but excluding the latter).
+     */
+    private void removeNode2() throws BackingStoreException {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node already removed.");
+
+            // Ensure that all children are cached
+            String[] kidNames = childrenNamesSpi();
+            for (int i=0; i<kidNames.length; i++)
+                if (!kidCache.containsKey(kidNames[i]))
+                    kidCache.put(kidNames[i], childSpi(kidNames[i]));
+
+            // Recursively remove all cached children
+            for (Iterator<AbstractPreferences> i = kidCache.values().iterator();
+                 i.hasNext();) {
+                try {
+                    i.next().removeNode2();
+                    i.remove();
+                } catch (BackingStoreException x) { }
+            }
+
+            // Now we have no descendants - it's time to die!
+            removeNodeSpi();
+            removed = true;
+            parent.enqueueNodeRemovedEvent(this);
+        }
+    }
+
+    /**
+     * Implements the <tt>name</tt> method as per the specification in
+     * {@link Preferences#name()}.
+     *
+     * <p>This implementation merely returns the name that was
+     * passed to this node's constructor.
+     *
+     * @return this preference node's name, relative to its parent.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Implements the <tt>absolutePath</tt> method as per the specification in
+     * {@link Preferences#absolutePath()}.
+     *
+     * <p>This implementation merely returns the absolute path name that
+     * was computed at the time that this node was constructed (based on
+     * the name that was passed to this node's constructor, and the names
+     * that were passed to this node's ancestors' constructors).
+     *
+     * @return this preference node's absolute path name.
+     */
+    public String absolutePath() {
+        return absolutePath;
+    }
+
+    /**
+     * Implements the <tt>isUserNode</tt> method as per the specification in
+     * {@link Preferences#isUserNode()}.
+     *
+     * <p>This implementation compares this node's root node (which is stored
+     * in a private field) with the value returned by
+     * {@link Preferences#userRoot()}.  If the two object references are
+     * identical, this method returns true.
+     *
+     * @return <tt>true</tt> if this preference node is in the user
+     *         preference tree, <tt>false</tt> if it's in the system
+     *         preference tree.
+     */
+    public boolean isUserNode() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<Boolean>() {
+                public Boolean run() {
+                    return root == Preferences.userRoot();
+            }
+            }).booleanValue();
+    }
+
+    public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
+        if (pcl==null)
+            throw new NullPointerException("Change listener is null.");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            PreferenceChangeListener[] old = prefListeners;
+            prefListeners = new PreferenceChangeListener[old.length + 1];
+            System.arraycopy(old, 0, prefListeners, 0, old.length);
+            prefListeners[old.length] = pcl;
+            */
+            prefListeners.add(pcl);
+        }
+        startEventDispatchThreadIfNecessary();
+    }
+
+    public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // if ((prefListeners == null) || (prefListeners.length == 0))
+            if (!prefListeners.contains(pcl)) {
+                throw new IllegalArgumentException("Listener not registered.");
+            }
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            PreferenceChangeListener[] newPl =
+                new PreferenceChangeListener[prefListeners.length - 1];
+            int i = 0;
+            while (i < newPl.length && prefListeners[i] != pcl)
+                newPl[i] = prefListeners[i++];
+
+            if (i == newPl.length &&  prefListeners[i] != pcl)
+                throw new IllegalArgumentException("Listener not registered.");
+            while (i < newPl.length)
+                newPl[i] = prefListeners[++i];
+            prefListeners = newPl;
+            */
+            prefListeners.remove(pcl);
+        }
+    }
+
+    public void addNodeChangeListener(NodeChangeListener ncl) {
+        if (ncl==null)
+            throw new NullPointerException("Change listener is null.");
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            if (nodeListeners == null) {
+                nodeListeners = new NodeChangeListener[1];
+                nodeListeners[0] = ncl;
+            } else {
+                NodeChangeListener[] old = nodeListeners;
+                nodeListeners = new NodeChangeListener[old.length + 1];
+                System.arraycopy(old, 0, nodeListeners, 0, old.length);
+                nodeListeners[old.length] = ncl;
+            }
+            */
+            nodeListeners.add(ncl);
+        }
+        startEventDispatchThreadIfNecessary();
+    }
+
+    public void removeNodeChangeListener(NodeChangeListener ncl) {
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed.");
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // if ((nodeListeners == null) || (nodeListeners.length == 0))
+            if (!nodeListeners.contains(ncl)) {
+                throw new IllegalArgumentException("Listener not registered.");
+            }
+
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            /*
+            // Copy-on-write
+            int i = 0;
+            while (i < nodeListeners.length && nodeListeners[i] != ncl)
+                i++;
+            if (i == nodeListeners.length)
+                throw new IllegalArgumentException("Listener not registered.");
+            NodeChangeListener[] newNl =
+                new NodeChangeListener[nodeListeners.length - 1];
+            if (i != 0)
+                System.arraycopy(nodeListeners, 0, newNl, 0, i);
+            if (i != newNl.length)
+                System.arraycopy(nodeListeners, i + 1,
+                                 newNl, i, newNl.length - i);
+            nodeListeners = newNl;
+            */
+            nodeListeners.remove(ncl);
+        }
+    }
+
+    // "SPI" METHODS
+
+    /**
+     * Put the given key-value association into this preference node.  It is
+     * guaranteed that <tt>key</tt> and <tt>value</tt> are non-null and of
+     * legal length.  Also, it is guaranteed that this node has not been
+     * removed.  (The implementor needn't check for any of these things.)
+     *
+     * <p>This method is invoked with the lock on this node held.
+     * @param key the key
+     * @param value the value
+     */
+    protected abstract void putSpi(String key, String value);
+
+    /**
+     * Return the value associated with the specified key at this preference
+     * node, or <tt>null</tt> if there is no association for this key, or the
+     * association cannot be determined at this time.  It is guaranteed that
+     * <tt>key</tt> is non-null.  Also, it is guaranteed that this node has
+     * not been removed.  (The implementor needn't check for either of these
+     * things.)
+     *
+     * <p> Generally speaking, this method should not throw an exception
+     * under any circumstances.  If, however, if it does throw an exception,
+     * the exception will be intercepted and treated as a <tt>null</tt>
+     * return value.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * @param key the key
+     * @return the value associated with the specified key at this preference
+     *          node, or <tt>null</tt> if there is no association for this
+     *          key, or the association cannot be determined at this time.
+     */
+    protected abstract String getSpi(String key);
+
+    /**
+     * Remove the association (if any) for the specified key at this
+     * preference node.  It is guaranteed that <tt>key</tt> is non-null.
+     * Also, it is guaranteed that this node has not been removed.
+     * (The implementor needn't check for either of these things.)
+     *
+     * <p>This method is invoked with the lock on this node held.
+     * @param key the key
+     */
+    protected abstract void removeSpi(String key);
+
+    /**
+     * Removes this preference node, invalidating it and any preferences that
+     * it contains.  The named child will have no descendants at the time this
+     * invocation is made (i.e., the {@link Preferences#removeNode()} method
+     * invokes this method repeatedly in a bottom-up fashion, removing each of
+     * a node's descendants before removing the node itself).
+     *
+     * <p>This method is invoked with the lock held on this node and its
+     * parent (and all ancestors that are being removed as a
+     * result of a single invocation to {@link Preferences#removeNode()}).
+     *
+     * <p>The removal of a node needn't become persistent until the
+     * <tt>flush</tt> method is invoked on this node (or an ancestor).
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #removeNode()}
+     * invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void removeNodeSpi() throws BackingStoreException;
+
+    /**
+     * Returns all of the keys that have an associated value in this
+     * preference node.  (The returned array will be of size zero if
+     * this node has no preferences.)  It is guaranteed that this node has not
+     * been removed.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #keys()} invocation.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract String[] keysSpi() throws BackingStoreException;
+
+    /**
+     * Returns the names of the children of this preference node.  (The
+     * returned array will be of size zero if this node has no children.)
+     * This method need not return the names of any nodes already cached,
+     * but may do so without harm.
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #childrenNames()}
+     * invocation.
+     *
+     * @return an array containing the names of the children of this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract String[] childrenNamesSpi()
+        throws BackingStoreException;
+
+    /**
+     * Returns the named child if it exists, or <tt>null</tt> if it does not.
+     * It is guaranteed that <tt>nodeName</tt> is non-null, non-empty,
+     * does not contain the slash character ('/'), and is no longer than
+     * {@link #MAX_NAME_LENGTH} characters.  Also, it is guaranteed
+     * that this node has not been removed.  (The implementor needn't check
+     * for any of these things if he chooses to override this method.)
+     *
+     * <p>Finally, it is guaranteed that the named node has not been returned
+     * by a previous invocation of this method or {@link #childSpi} after the
+     * last time that it was removed.  In other words, a cached value will
+     * always be used in preference to invoking this method.  (The implementor
+     * needn't maintain his own cache of previously returned children if he
+     * chooses to override this method.)
+     *
+     * <p>This implementation obtains this preference node's lock, invokes
+     * {@link #childrenNames()} to get an array of the names of this node's
+     * children, and iterates over the array comparing the name of each child
+     * with the specified node name.  If a child node has the correct name,
+     * the {@link #childSpi(String)} method is invoked and the resulting
+     * node is returned.  If the iteration completes without finding the
+     * specified name, <tt>null</tt> is returned.
+     *
+     * @param nodeName name of the child to be searched for.
+     * @return the named child if it exists, or null if it does not.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected AbstractPreferences getChild(String nodeName)
+            throws BackingStoreException {
+        synchronized(lock) {
+            // assert kidCache.get(nodeName)==null;
+            String[] kidNames = childrenNames();
+            for (int i=0; i<kidNames.length; i++)
+                if (kidNames[i].equals(nodeName))
+                    return childSpi(kidNames[i]);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the named child of this preference node, creating it if it does
+     * not already exist.  It is guaranteed that <tt>name</tt> is non-null,
+     * non-empty, does not contain the slash character ('/'), and is no longer
+     * than {@link #MAX_NAME_LENGTH} characters.  Also, it is guaranteed that
+     * this node has not been removed.  (The implementor needn't check for any
+     * of these things.)
+     *
+     * <p>Finally, it is guaranteed that the named node has not been returned
+     * by a previous invocation of this method or {@link #getChild(String)}
+     * after the last time that it was removed.  In other words, a cached
+     * value will always be used in preference to invoking this method.
+     * Subclasses need not maintain their own cache of previously returned
+     * children.
+     *
+     * <p>The implementer must ensure that the returned node has not been
+     * removed.  If a like-named child of this node was previously removed, the
+     * implementer must return a newly constructed <tt>AbstractPreferences</tt>
+     * node; once removed, an <tt>AbstractPreferences</tt> node
+     * cannot be "resuscitated."
+     *
+     * <p>If this method causes a node to be created, this node is not
+     * guaranteed to be persistent until the <tt>flush</tt> method is
+     * invoked on this node or one of its ancestors (or descendants).
+     *
+     * <p>This method is invoked with the lock on this node held.
+     *
+     * @param name The name of the child node to return, relative to
+     *        this preference node.
+     * @return The named child node.
+     */
+    protected abstract AbstractPreferences childSpi(String name);
+
+    /**
+     * Returns the absolute path name of this preferences node.
+     */
+    public String toString() {
+        return (this.isUserNode() ? "User" : "System") +
+               " Preference Node: " + this.absolutePath();
+    }
+
+    /**
+     * Implements the <tt>sync</tt> method as per the specification in
+     * {@link Preferences#sync()}.
+     *
+     * <p>This implementation calls a recursive helper method that locks this
+     * node, invokes syncSpi() on it, unlocks this node, and recursively
+     * invokes this method on each "cached child."  A cached child is a child
+     * of this node that has been created in this VM and not subsequently
+     * removed.  In effect, this method does a depth first traversal of the
+     * "cached subtree" rooted at this node, calling syncSpi() on each node in
+     * the subTree while only that node is locked. Note that syncSpi() is
+     * invoked top-down.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #flush()
+     */
+    public void sync() throws BackingStoreException {
+        sync2();
+    }
+
+    private void sync2() throws BackingStoreException {
+        AbstractPreferences[] cachedKids;
+
+        synchronized(lock) {
+            if (removed)
+                throw new IllegalStateException("Node has been removed");
+            syncSpi();
+            cachedKids = cachedChildren();
+        }
+
+        for (int i=0; i<cachedKids.length; i++)
+            cachedKids[i].sync2();
+    }
+
+    /**
+     * This method is invoked with this node locked.  The contract of this
+     * method is to synchronize any cached preferences stored at this node
+     * with any stored in the backing store.  (It is perfectly possible that
+     * this node does not exist on the backing store, either because it has
+     * been deleted by another VM, or because it has not yet been created.)
+     * Note that this method should <i>not</i> synchronize the preferences in
+     * any subnodes of this node.  If the backing store naturally syncs an
+     * entire subtree at once, the implementer is encouraged to override
+     * sync(), rather than merely overriding this method.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #sync()} invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void syncSpi() throws BackingStoreException;
+
+    /**
+     * Implements the <tt>flush</tt> method as per the specification in
+     * {@link Preferences#flush()}.
+     *
+     * <p>This implementation calls a recursive helper method that locks this
+     * node, invokes flushSpi() on it, unlocks this node, and recursively
+     * invokes this method on each "cached child."  A cached child is a child
+     * of this node that has been created in this VM and not subsequently
+     * removed.  In effect, this method does a depth first traversal of the
+     * "cached subtree" rooted at this node, calling flushSpi() on each node in
+     * the subTree while only that node is locked. Note that flushSpi() is
+     * invoked top-down.
+     *
+     * <p> If this method is invoked on a node that has been removed with
+     * the {@link #removeNode()} method, flushSpi() is invoked on this node,
+     * but not on others.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @see #flush()
+     */
+    public void flush() throws BackingStoreException {
+        flush2();
+    }
+
+    private void flush2() throws BackingStoreException {
+        AbstractPreferences[] cachedKids;
+
+        synchronized(lock) {
+            flushSpi();
+            if(removed)
+                return;
+            cachedKids = cachedChildren();
+        }
+
+        for (int i = 0; i < cachedKids.length; i++)
+            cachedKids[i].flush2();
+    }
+
+    /**
+     * This method is invoked with this node locked.  The contract of this
+     * method is to force any cached changes in the contents of this
+     * preference node to the backing store, guaranteeing their persistence.
+     * (It is perfectly possible that this node does not exist on the backing
+     * store, either because it has been deleted by another VM, or because it
+     * has not yet been created.)  Note that this method should <i>not</i>
+     * flush the preferences in any subnodes of this node.  If the backing
+     * store naturally flushes an entire subtree at once, the implementer is
+     * encouraged to override flush(), rather than merely overriding this
+     * method.
+     *
+     * <p>If this node throws a <tt>BackingStoreException</tt>, the exception
+     * will propagate out beyond the enclosing {@link #flush()} invocation.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     */
+    protected abstract void flushSpi() throws BackingStoreException;
+
+    /**
+     * Returns <tt>true</tt> iff this node (or an ancestor) has been
+     * removed with the {@link #removeNode()} method.  This method
+     * locks this node prior to returning the contents of the private
+     * field used to track this state.
+     *
+     * @return <tt>true</tt> iff this node (or an ancestor) has been
+     *       removed with the {@link #removeNode()} method.
+     */
+    protected boolean isRemoved() {
+        synchronized(lock) {
+            return removed;
+        }
+    }
+
+    /**
+     * Queue of pending notification events.  When a preference or node
+     * change event for which there are one or more listeners occurs,
+     * it is placed on this queue and the queue is notified.  A background
+     * thread waits on this queue and delivers the events.  This decouples
+     * event delivery from preference activity, greatly simplifying
+     * locking and reducing opportunity for deadlock.
+     */
+    private static final List<EventObject> eventQueue = new LinkedList<>();
+
+    /**
+     * These two classes are used to distinguish NodeChangeEvents on
+     * eventQueue so the event dispatch thread knows whether to call
+     * childAdded or childRemoved.
+     */
+    private class NodeAddedEvent extends NodeChangeEvent {
+        private static final long serialVersionUID = -6743557530157328528L;
+        NodeAddedEvent(Preferences parent, Preferences child) {
+            super(parent, child);
+        }
+    }
+    private class NodeRemovedEvent extends NodeChangeEvent {
+        private static final long serialVersionUID = 8735497392918824837L;
+        NodeRemovedEvent(Preferences parent, Preferences child) {
+            super(parent, child);
+        }
+    }
+
+    /**
+     * A single background thread ("the event notification thread") monitors
+     * the event queue and delivers events that are placed on the queue.
+     */
+    private static class EventDispatchThread extends Thread {
+        public void run() {
+            while(true) {
+                // Wait on eventQueue till an event is present
+                EventObject event = null;
+                synchronized(eventQueue) {
+                    try {
+                        while (eventQueue.isEmpty())
+                            eventQueue.wait();
+                        event = eventQueue.remove(0);
+                    } catch (InterruptedException e) {
+                        // XXX Log "Event dispatch thread interrupted. Exiting"
+                        return;
+                    }
+                }
+
+                // Now we have event & hold no locks; deliver evt to listeners
+                AbstractPreferences src=(AbstractPreferences)event.getSource();
+                if (event instanceof PreferenceChangeEvent) {
+                    PreferenceChangeEvent pce = (PreferenceChangeEvent)event;
+                    PreferenceChangeListener[] listeners = src.prefListeners();
+                    for (int i=0; i<listeners.length; i++)
+                        listeners[i].preferenceChange(pce);
+                } else {
+                    NodeChangeEvent nce = (NodeChangeEvent)event;
+                    NodeChangeListener[] listeners = src.nodeListeners();
+                    if (nce instanceof NodeAddedEvent) {
+                        for (int i=0; i<listeners.length; i++)
+                            listeners[i].childAdded(nce);
+                    } else {
+                        // assert nce instanceof NodeRemovedEvent;
+                        for (int i=0; i<listeners.length; i++)
+                            listeners[i].childRemoved(nce);
+                    }
+                }
+            }
+        }
+    }
+
+    private static Thread eventDispatchThread = null;
+
+    /**
+     * This method starts the event dispatch thread the first time it
+     * is called.  The event dispatch thread will be started only
+     * if someone registers a listener.
+     */
+    private static synchronized void startEventDispatchThreadIfNecessary() {
+        if (eventDispatchThread == null) {
+            // XXX Log "Starting event dispatch thread"
+            eventDispatchThread = new EventDispatchThread();
+            eventDispatchThread.setDaemon(true);
+            eventDispatchThread.start();
+        }
+    }
+
+    // BEGIN Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    // Changed documentation.
+    /*
+    /**
+     * Return this node's preference/node change listeners.  Even though
+     * we're using a copy-on-write lists, we use synchronized accessors to
+     * ensure information transmission from the writing thread to the
+     * reading thread.
+     *
+    */
+    /**
+     * Return this node's preference/node change listeners. All accesses to prefListeners
+     * and nodeListeners are guarded by |lock|. We return a copy of the list so that the
+     * EventQueue thread will iterate over a fixed snapshot of the listeners at the time of
+     * this call.
+     */
+    // END Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+    PreferenceChangeListener[] prefListeners() {
+        synchronized(lock) {
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // return prefListeners;
+            return prefListeners.toArray(new PreferenceChangeListener[prefListeners.size()]);
+        }
+    }
+    NodeChangeListener[] nodeListeners() {
+        synchronized(lock) {
+            // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+            // return nodeListeners;
+            return nodeListeners.toArray(new NodeChangeListener[nodeListeners.size()]);
+        }
+    }
+
+    /**
+     * Enqueue a preference change event for delivery to registered
+     * preference change listeners unless there are no registered
+     * listeners.  Invoked with this.lock held.
+     */
+    private void enqueuePreferenceChangeEvent(String key, String newValue) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (prefListeners.length != 0) {
+        if (!prefListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new PreferenceChangeEvent(this, key, newValue));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Enqueue a "node added" event for delivery to registered node change
+     * listeners unless there are no registered listeners.  Invoked with
+     * this.lock held.
+     */
+    private void enqueueNodeAddedEvent(Preferences child) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (nodeListeners.length != 0) {
+        if (!nodeListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new NodeAddedEvent(this, child));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Enqueue a "node removed" event for delivery to registered node change
+     * listeners unless there are no registered listeners.  Invoked with
+     * this.lock held.
+     */
+    private void enqueueNodeRemovedEvent(Preferences child) {
+        // Android-changed: Copy-on-read List of listeners, not copy-on-write array.
+        // if (nodeListeners.length != 0) {
+        if (!nodeListeners.isEmpty()) {
+            synchronized(eventQueue) {
+                eventQueue.add(new NodeRemovedEvent(this, child));
+                eventQueue.notify();
+            }
+        }
+    }
+
+    /**
+     * Implements the <tt>exportNode</tt> method as per the specification in
+     * {@link Preferences#exportNode(OutputStream)}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     */
+    public void exportNode(OutputStream os)
+        throws IOException, BackingStoreException
+    {
+        XmlSupport.export(os, this, false);
+    }
+
+    /**
+     * Implements the <tt>exportSubtree</tt> method as per the specification in
+     * {@link Preferences#exportSubtree(OutputStream)}.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     */
+    public void exportSubtree(OutputStream os)
+        throws IOException, BackingStoreException
+    {
+        XmlSupport.export(os, this, true);
+    }
+}
diff --git a/java/util/prefs/BackingStoreException.java b/java/util/prefs/BackingStoreException.java
new file mode 100644
index 0000000..0bce9c6
--- /dev/null
+++ b/java/util/prefs/BackingStoreException.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * Thrown to indicate that a preferences operation could not complete because
+ * of a failure in the backing store, or a failure to contact the backing
+ * store.
+ *
+ * @author  Josh Bloch
+ * @since   1.4
+ */
+public class BackingStoreException extends Exception {
+    /**
+     * Constructs a BackingStoreException with the specified detail message.
+     *
+     * @param s the detail message.
+     */
+    public BackingStoreException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a BackingStoreException with the specified cause.
+     *
+     * @param cause the cause
+     */
+    public BackingStoreException(Throwable cause) {
+        super(cause);
+    }
+
+    private static final long serialVersionUID = 859796500401108469L;
+}
diff --git a/java/util/prefs/Base64.java b/java/util/prefs/Base64.java
new file mode 100644
index 0000000..c0d8d53
--- /dev/null
+++ b/java/util/prefs/Base64.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * Static methods for translating Base64 encoded strings to byte arrays
+ * and vice-versa.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+class Base64 {
+    /**
+     * Translates the specified byte array into a Base64 string as per
+     * Preferences.put(byte[]).
+     */
+    static String byteArrayToBase64(byte[] a) {
+        return byteArrayToBase64(a, false);
+    }
+
+    /**
+     * Translates the specified byte array into an "alternate representation"
+     * Base64 string.  This non-standard variant uses an alphabet that does
+     * not contain the uppercase alphabetic characters, which makes it
+     * suitable for use in situations where case-folding occurs.
+     */
+    static String byteArrayToAltBase64(byte[] a) {
+        return byteArrayToBase64(a, true);
+    }
+
+    private static String byteArrayToBase64(byte[] a, boolean alternate) {
+        int aLen = a.length;
+        int numFullGroups = aLen/3;
+        int numBytesInPartialGroup = aLen - 3*numFullGroups;
+        int resultLen = 4*((aLen + 2)/3);
+        StringBuffer result = new StringBuffer(resultLen);
+        char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64);
+
+        // Translate all full groups from byte array elements to Base64
+        int inCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int byte0 = a[inCursor++] & 0xff;
+            int byte1 = a[inCursor++] & 0xff;
+            int byte2 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+            result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]);
+            result.append(intToAlpha[byte2 & 0x3f]);
+        }
+
+        // Translate partial group if present
+        if (numBytesInPartialGroup != 0) {
+            int byte0 = a[inCursor++] & 0xff;
+            result.append(intToAlpha[byte0 >> 2]);
+            if (numBytesInPartialGroup == 1) {
+                result.append(intToAlpha[(byte0 << 4) & 0x3f]);
+                result.append("==");
+            } else {
+                // assert numBytesInPartialGroup == 2;
+                int byte1 = a[inCursor++] & 0xff;
+                result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]);
+                result.append(intToAlpha[(byte1 << 2)&0x3f]);
+                result.append('=');
+            }
+        }
+        // assert inCursor == a.length;
+        // assert result.length() == resultLen;
+        return result.toString();
+    }
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Base64 Alphabet" equivalents as specified
+     * in Table 1 of RFC 2045.
+     */
+    private static final char intToBase64[] = {
+        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+        'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+    };
+
+    /**
+     * This array is a lookup table that translates 6-bit positive integer
+     * index values into their "Alternate Base64 Alphabet" equivalents.
+     * This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045.
+     * This alternate alphabet does not use the capital letters.  It is
+     * designed for use in environments where "case folding" occurs.
+     */
+    private static final char intToAltBase64[] = {
+        '!', '"', '#', '$', '%', '&', '\'', '(', ')', ',', '-', '.', ':',
+        ';', '<', '>', '@', '[', ']', '^',  '`', '_', '{', '|', '}', '~',
+        'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm',
+        'n', 'o', 'p', 'q', 'r', 's', 't',  'u', 'v', 'w', 'x', 'y', 'z',
+        '0', '1', '2', '3', '4', '5', '6',  '7', '8', '9', '+', '?'
+    };
+
+    /**
+     * Translates the specified Base64 string (as per Preferences.get(byte[]))
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException if <tt>s</tt> is not a valid Base64
+     *        string.
+     */
+    static byte[] base64ToByteArray(String s) {
+        return base64ToByteArray(s, false);
+    }
+
+    /**
+     * Translates the specified "alternate representation" Base64 string
+     * into a byte array.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException
+     *        if <tt>s</tt> is not a valid alternate representation
+     *        Base64 string.
+     */
+    static byte[] altBase64ToByteArray(String s) {
+        return base64ToByteArray(s, true);
+    }
+
+    private static byte[] base64ToByteArray(String s, boolean alternate) {
+        byte[] alphaToInt = (alternate ?  altBase64ToInt : base64ToInt);
+        int sLen = s.length();
+        int numGroups = sLen/4;
+        if (4*numGroups != sLen)
+            throw new IllegalArgumentException(
+                "String length must be a multiple of four.");
+        int missingBytesInLastGroup = 0;
+        int numFullGroups = numGroups;
+        if (sLen != 0) {
+            if (s.charAt(sLen-1) == '=') {
+                missingBytesInLastGroup++;
+                numFullGroups--;
+            }
+            if (s.charAt(sLen-2) == '=')
+                missingBytesInLastGroup++;
+        }
+        byte[] result = new byte[3*numGroups - missingBytesInLastGroup];
+
+        // Translate all full groups from base64 to byte array elements
+        int inCursor = 0, outCursor = 0;
+        for (int i=0; i<numFullGroups; i++) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+            result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            result[outCursor++] = (byte) ((ch2 << 6) | ch3);
+        }
+
+        // Translate partial group, if present
+        if (missingBytesInLastGroup != 0) {
+            int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt);
+            result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4));
+
+            if (missingBytesInLastGroup == 1) {
+                int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt);
+                result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2));
+            }
+        }
+        // assert inCursor == s.length()-missingBytesInLastGroup;
+        // assert outCursor == result.length;
+        return result;
+    }
+
+    /**
+     * Translates the specified character, which is assumed to be in the
+     * "Base 64 Alphabet" into its equivalent 6-bit positive integer.
+     *
+     * @throw IllegalArgumentException or ArrayOutOfBoundsException if
+     *        c is not in the Base64 Alphabet.
+     */
+    private static int base64toInt(char c, byte[] alphaToInt) {
+        int result = alphaToInt[c];
+        if (result < 0)
+            throw new IllegalArgumentException("Illegal character " + c);
+        return result;
+    }
+
+    /**
+     * This array is a lookup table that translates unicode characters
+     * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
+     * into their 6-bit positive integer equivalents.  Characters that
+     * are not in the Base64 alphabet but fall within the bounds of the
+     * array are translated to -1.
+     */
+    private static final byte base64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
+        55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
+        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+        24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+    };
+
+    /**
+     * This array is the analogue of base64ToInt, but for the nonstandard
+     * variant that avoids the use of uppercase alphabetic characters.
+     */
+    private static final byte altBase64ToInt[] = {
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,
+        2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10, 11, -1 , 52, 53, 54, 55, 56, 57,
+        58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+        -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28, 29, 30, 31, 32, 33,
+        34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
+        51, 22, 23, 24, 25
+    };
+
+    public static void main(String args[]) {
+        int numRuns  = Integer.parseInt(args[0]);
+        int numBytes = Integer.parseInt(args[1]);
+        java.util.Random rnd = new java.util.Random();
+        for (int i=0; i<numRuns; i++) {
+            for (int j=0; j<numBytes; j++) {
+                byte[] arr = new byte[j];
+                for (int k=0; k<j; k++)
+                    arr[k] = (byte)rnd.nextInt();
+
+                String s = byteArrayToBase64(arr);
+                byte [] b = base64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Dismal failure!");
+
+                s = byteArrayToAltBase64(arr);
+                b = altBase64ToByteArray(s);
+                if (!java.util.Arrays.equals(arr, b))
+                    System.out.println("Alternate dismal failure!");
+            }
+        }
+    }
+}
diff --git a/java/util/prefs/FileSystemPreferences.java b/java/util/prefs/FileSystemPreferences.java
new file mode 100644
index 0000000..b888c4d
--- /dev/null
+++ b/java/util/prefs/FileSystemPreferences.java
@@ -0,0 +1,996 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+import java.util.*;
+import java.io.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+
+import sun.util.logging.PlatformLogger;
+
+// Android-changed: @hide.
+/**
+ * Preferences implementation for Unix.  Preferences are stored in the file
+ * system, with one directory per preferences node.  All of the preferences
+ * at each node are stored in a single file.  Atomic file system operations
+ * (e.g. File.renameTo) are used to ensure integrity.  An in-memory cache of
+ * the "explored" portion of the tree is maintained for performance, and
+ * written back to the disk periodically.  File-locking is used to ensure
+ * reasonable behavior when multiple VMs are running at the same time.
+ * (The file lock is obtained only for sync(), flush() and removeNode().)
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ *
+ * @hide
+ */
+public class FileSystemPreferences extends AbstractPreferences {
+    /**
+     * Returns logger for error messages. Backing store exceptions are logged at
+     * WARNING level.
+     */
+    private static PlatformLogger getLogger() {
+        return PlatformLogger.getLogger("java.util.prefs");
+    }
+
+    /**
+     * Directory for system preferences.
+     */
+    private static File systemRootDir;
+
+    /*
+     * Flag, indicating whether systemRoot  directory is writable
+     */
+    private static boolean isSystemRootWritable;
+
+    /**
+     * Directory for user preferences.
+     */
+    private static File userRootDir;
+
+    /*
+     * Flag, indicating whether userRoot  directory is writable
+     */
+    private static boolean isUserRootWritable;
+
+   /**
+     * The user root.
+     */
+    static Preferences userRoot = null;
+
+    static synchronized Preferences getUserRoot() {
+        if (userRoot == null) {
+            setupUserRoot();
+            userRoot = new FileSystemPreferences(true);
+        }
+        return userRoot;
+    }
+
+    private static void setupUserRoot() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                userRootDir =
+                      new File(System.getProperty("java.util.prefs.userRoot",
+                      System.getProperty("user.home")), ".java/.userPrefs");
+                // Attempt to create root dir if it does not yet exist.
+                if (!userRootDir.exists()) {
+                    if (userRootDir.mkdirs()) {
+                        try {
+                            chmod(userRootDir.getCanonicalPath(), USER_RWX);
+                        } catch (IOException e) {
+                            getLogger().warning("Could not change permissions" +
+                                " on userRoot directory. ");
+                        }
+                        getLogger().info("Created user preferences directory.");
+                    }
+                    else
+                        getLogger().warning("Couldn't create user preferences" +
+                        " directory. User preferences are unusable.");
+                }
+                isUserRootWritable = userRootDir.canWrite();
+                String USER_NAME = System.getProperty("user.name");
+                userLockFile = new File (userRootDir,".user.lock." + USER_NAME);
+                userRootModFile = new File (userRootDir,
+                                               ".userRootModFile." + USER_NAME);
+                if (!userRootModFile.exists())
+                try {
+                    // create if does not exist.
+                    userRootModFile.createNewFile();
+                    // Only user can read/write userRootModFile.
+                    int result = chmod(userRootModFile.getCanonicalPath(),
+                                                               USER_READ_WRITE);
+                    if (result !=0)
+                        getLogger().warning("Problem creating userRoot " +
+                            "mod file. Chmod failed on " +
+                             userRootModFile.getCanonicalPath() +
+                             " Unix error code " + result);
+                } catch (IOException e) {
+                    getLogger().warning(e.toString());
+                }
+                userRootModTime = userRootModFile.lastModified();
+                return null;
+            }
+        });
+    }
+
+
+    /**
+     * The system root.
+     */
+    static Preferences systemRoot;
+
+    static synchronized Preferences getSystemRoot() {
+        if (systemRoot == null) {
+            setupSystemRoot();
+            systemRoot = new FileSystemPreferences(false);
+        }
+        return systemRoot;
+    }
+
+    private static void setupSystemRoot() {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                String systemPrefsDirName =
+                  System.getProperty("java.util.prefs.systemRoot","/etc/.java");
+                systemRootDir =
+                     new File(systemPrefsDirName, ".systemPrefs");
+                // Attempt to create root dir if it does not yet exist.
+                if (!systemRootDir.exists()) {
+                    // system root does not exist in /etc/.java
+                    // Switching  to java.home
+                    systemRootDir =
+                                  new File(System.getProperty("java.home"),
+                                                            ".systemPrefs");
+                    if (!systemRootDir.exists()) {
+                        if (systemRootDir.mkdirs()) {
+                            getLogger().info(
+                                "Created system preferences directory "
+                                + "in java.home.");
+                            try {
+                                chmod(systemRootDir.getCanonicalPath(),
+                                                          USER_RWX_ALL_RX);
+                            } catch (IOException e) {
+                            }
+                        } else {
+                            getLogger().warning("Could not create "
+                                + "system preferences directory. System "
+                                + "preferences are unusable.");
+                        }
+                    }
+                }
+                isSystemRootWritable = systemRootDir.canWrite();
+                systemLockFile = new File(systemRootDir, ".system.lock");
+                systemRootModFile =
+                               new File (systemRootDir,".systemRootModFile");
+                if (!systemRootModFile.exists() && isSystemRootWritable)
+                try {
+                    // create if does not exist.
+                    systemRootModFile.createNewFile();
+                    int result = chmod(systemRootModFile.getCanonicalPath(),
+                                                          USER_RW_ALL_READ);
+                    if (result !=0)
+                        getLogger().warning("Chmod failed on " +
+                               systemRootModFile.getCanonicalPath() +
+                              " Unix error code " + result);
+                } catch (IOException e) { getLogger().warning(e.toString());
+                }
+                systemRootModTime = systemRootModFile.lastModified();
+                return null;
+            }
+        });
+    }
+
+
+    /**
+     * Unix user write/read permission
+     */
+    private static final int USER_READ_WRITE = 0600;
+
+    private static final int USER_RW_ALL_READ = 0644;
+
+
+    private static final int USER_RWX_ALL_RX = 0755;
+
+    private static final int USER_RWX = 0700;
+
+    /**
+     * The lock file for the user tree.
+     */
+    static File userLockFile;
+
+
+
+    /**
+     * The lock file for the system tree.
+     */
+    static File systemLockFile;
+
+    /**
+     * Unix lock handle for userRoot.
+     * Zero, if unlocked.
+     */
+
+    private static int userRootLockHandle = 0;
+
+    /**
+     * Unix lock handle for systemRoot.
+     * Zero, if unlocked.
+     */
+
+    private static int systemRootLockHandle = 0;
+
+    /**
+     * The directory representing this preference node.  There is no guarantee
+     * that this directory exits, as another VM can delete it at any time
+     * that it (the other VM) holds the file-lock.  While the root node cannot
+     * be deleted, it may not yet have been created, or the underlying
+     * directory could have been deleted accidentally.
+     */
+    private final File dir;
+
+    /**
+     * The file representing this preference node's preferences.
+     * The file format is undocumented, and subject to change
+     * from release to release, but I'm sure that you can figure
+     * it out if you try real hard.
+     */
+    private final File prefsFile;
+
+    /**
+     * A temporary file used for saving changes to preferences.  As part of
+     * the sync operation, changes are first saved into this file, and then
+     * atomically renamed to prefsFile.  This results in an atomic state
+     * change from one valid set of preferences to another.  The
+     * the file-lock is held for the duration of this transformation.
+     */
+    private final File tmpFile;
+
+    /**
+     * File, which keeps track of global modifications of userRoot.
+     */
+    private static  File userRootModFile;
+
+    /**
+     * Flag, which indicated whether userRoot was modified by another VM
+     */
+    private static boolean isUserRootModified = false;
+
+    /**
+     * Keeps track of userRoot modification time. This time is reset to
+     * zero after UNIX reboot, and is increased by 1 second each time
+     * userRoot is modified.
+     */
+    private static long userRootModTime;
+
+
+    /*
+     * File, which keeps track of global modifications of systemRoot
+     */
+    private static File systemRootModFile;
+    /*
+     * Flag, which indicates whether systemRoot was modified by another VM
+     */
+    private static boolean isSystemRootModified = false;
+
+    /**
+     * Keeps track of systemRoot modification time. This time is reset to
+     * zero after system reboot, and is increased by 1 second each time
+     * systemRoot is modified.
+     */
+    private static long systemRootModTime;
+
+    /**
+     * Locally cached preferences for this node (includes uncommitted
+     * changes).  This map is initialized with from disk when the first get or
+     * put operation occurs on this node.  It is synchronized with the
+     * corresponding disk file (prefsFile) by the sync operation.  The initial
+     * value is read *without* acquiring the file-lock.
+     */
+    private Map<String, String> prefsCache = null;
+
+    /**
+     * The last modification time of the file backing this node at the time
+     * that prefCache was last synchronized (or initially read).  This
+     * value is set *before* reading the file, so it's conservative; the
+     * actual timestamp could be (slightly) higher.  A value of zero indicates
+     * that we were unable to initialize prefsCache from the disk, or
+     * have not yet attempted to do so.  (If prefsCache is non-null, it
+     * indicates the former; if it's null, the latter.)
+     */
+    private long lastSyncTime = 0;
+
+   /**
+    * Unix error code for locked file.
+    */
+    private static final int EAGAIN = 11;
+
+   /**
+    * Unix error code for denied access.
+    */
+    private static final int EACCES = 13;
+
+    /* Used to interpret results of native functions */
+    private static final int LOCK_HANDLE = 0;
+    private static final int ERROR_CODE = 1;
+
+    /**
+     * A list of all uncommitted preference changes.  The elements in this
+     * list are of type PrefChange.  If this node is concurrently modified on
+     * disk by another VM, the two sets of changes are merged when this node
+     * is sync'ed by overwriting our prefsCache with the preference map last
+     * written out to disk (by the other VM), and then replaying this change
+     * log against that map.  The resulting map is then written back
+     * to the disk.
+     */
+    final List<Change> changeLog = new ArrayList<>();
+
+    /**
+     * Represents a change to a preference.
+     */
+    private abstract class Change {
+        /**
+         * Reapplies the change to prefsCache.
+         */
+        abstract void replay();
+    };
+
+    /**
+     * Represents a preference put.
+     */
+    private class Put extends Change {
+        String key, value;
+
+        Put(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        void replay() {
+            prefsCache.put(key, value);
+        }
+    }
+
+    /**
+     * Represents a preference remove.
+     */
+    private class Remove extends Change {
+        String key;
+
+        Remove(String key) {
+            this.key = key;
+        }
+
+        void replay() {
+            prefsCache.remove(key);
+        }
+    }
+
+    /**
+     * Represents the creation of this node.
+     */
+    private class NodeCreate extends Change {
+        /**
+         * Performs no action, but the presence of this object in changeLog
+         * will force the node and its ancestors to be made permanent at the
+         * next sync.
+         */
+        void replay() {
+        }
+    }
+
+    /**
+     * NodeCreate object for this node.
+     */
+    NodeCreate nodeCreate = null;
+
+    /**
+     * Replay changeLog against prefsCache.
+     */
+    private void replayChanges() {
+        for (int i = 0, n = changeLog.size(); i<n; i++)
+            changeLog.get(i).replay();
+    }
+
+    static {
+        // Add shutdown hook to flush cached prefs on normal termination
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            public void run() {
+                syncWorld();
+            }
+        });
+    }
+
+    private static void syncWorld() {
+        /*
+         * Synchronization necessary because userRoot and systemRoot are
+         * lazily initialized.
+         */
+        Preferences userRt;
+        Preferences systemRt;
+        synchronized(FileSystemPreferences.class) {
+            userRt   = userRoot;
+            systemRt = systemRoot;
+        }
+
+        try {
+            if (userRt != null)
+                userRt.flush();
+        } catch(BackingStoreException e) {
+            getLogger().warning("Couldn't flush user prefs: " + e);
+        }
+
+        try {
+            if (systemRt != null)
+                systemRt.flush();
+        } catch(BackingStoreException e) {
+            getLogger().warning("Couldn't flush system prefs: " + e);
+        }
+    }
+
+    private final boolean isUserNode;
+
+    /**
+     * Special constructor for roots (both user and system).  This constructor
+     * will only be called twice, by the static initializer.
+     */
+    private FileSystemPreferences(boolean user) {
+        super(null, "");
+        isUserNode = user;
+        dir = (user ? userRootDir: systemRootDir);
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile   = new File(dir, "prefs.tmp");
+    }
+
+    /** @hide for unit testing only */
+    // Android-added constructor for testing.
+    public FileSystemPreferences(String path, File lockFile, boolean isUserNode) {
+        super(null, "");
+        this.isUserNode = isUserNode;
+        this.dir = new File(path);
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile = new File(dir, "prefs.tmp");
+        newNode = !dir.exists();
+        if (newNode) {
+            // These 2 things guarantee node will get wrtten at next flush/sync
+            prefsCache = new TreeMap<>();
+            nodeCreate = new NodeCreate();
+            changeLog.add(nodeCreate);
+        }
+
+        if (isUserNode) {
+            userLockFile = lockFile;
+            userRootModFile = new File(lockFile.getParentFile(), lockFile.getName() + ".rootmod");
+        } else {
+            systemLockFile = lockFile;
+            systemRootModFile = new File(lockFile.getParentFile(), lockFile.getName() + ".rootmod");
+        }
+    }
+
+    /**
+     * Construct a new FileSystemPreferences instance with the specified
+     * parent node and name.  This constructor, called from childSpi,
+     * is used to make every node except for the two //roots.
+     */
+    private FileSystemPreferences(FileSystemPreferences parent, String name) {
+        super(parent, name);
+        isUserNode = parent.isUserNode;
+        dir  = new File(parent.dir, dirName(name));
+        prefsFile = new File(dir, "prefs.xml");
+        tmpFile  = new File(dir, "prefs.tmp");
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            public Void run() {
+                newNode = !dir.exists();
+                return null;
+            }
+        });
+        if (newNode) {
+            // These 2 things guarantee node will get wrtten at next flush/sync
+            prefsCache = new TreeMap<>();
+            nodeCreate = new NodeCreate();
+            changeLog.add(nodeCreate);
+        }
+    }
+
+    public boolean isUserNode() {
+        return isUserNode;
+    }
+
+    protected void putSpi(String key, String value) {
+        initCacheIfNecessary();
+        changeLog.add(new Put(key, value));
+        prefsCache.put(key, value);
+    }
+
+    protected String getSpi(String key) {
+        initCacheIfNecessary();
+        return prefsCache.get(key);
+    }
+
+    protected void removeSpi(String key) {
+        initCacheIfNecessary();
+        changeLog.add(new Remove(key));
+        prefsCache.remove(key);
+    }
+
+    /**
+     * Initialize prefsCache if it has yet to be initialized.  When this method
+     * returns, prefsCache will be non-null.  If the data was successfully
+     * read from the file, lastSyncTime will be updated.  If prefsCache was
+     * null, but it was impossible to read the file (because it didn't
+     * exist or for any other reason) prefsCache will be initialized to an
+     * empty, modifiable Map, and lastSyncTime remain zero.
+     */
+    private void initCacheIfNecessary() {
+        if (prefsCache != null)
+            return;
+
+        try {
+            loadCache();
+        } catch(Exception e) {
+            // assert lastSyncTime == 0;
+            prefsCache = new TreeMap<>();
+        }
+    }
+
+    /**
+     * Attempt to load prefsCache from the backing store.  If the attempt
+     * succeeds, lastSyncTime will be updated (the new value will typically
+     * correspond to the data loaded into the map, but it may be less,
+     * if another VM is updating this node concurrently).  If the attempt
+     * fails, a BackingStoreException is thrown and both prefsCache and
+     * lastSyncTime are unaffected by the call.
+     */
+    private void loadCache() throws BackingStoreException {
+        Map<String, String> m = new TreeMap<>();
+        long newLastSyncTime = 0;
+        try {
+            newLastSyncTime = prefsFile.lastModified();
+            try (FileInputStream fis = new FileInputStream(prefsFile)) {
+                XmlSupport.importMap(fis, m);
+            }
+        } catch(Exception e) {
+            if (e instanceof InvalidPreferencesFormatException) {
+                getLogger().warning("Invalid preferences format in "
+                                    +  prefsFile.getPath());
+                prefsFile.renameTo( new File(
+                                             prefsFile.getParentFile(),
+                                             "IncorrectFormatPrefs.xml"));
+                m = new TreeMap<>();
+            } else if (e instanceof FileNotFoundException) {
+                getLogger().warning("Prefs file removed in background "
+                                    + prefsFile.getPath());
+            } else {
+                // Android-added: This exception may be ignored by some callers,
+                // added a logger entry to prevent omitting it completely.
+                getLogger().warning("Exception while reading cache: "
+                                    + e.getMessage());
+                throw new BackingStoreException(e);
+            }
+        }
+        // Attempt succeeded; update state
+        prefsCache = m;
+        lastSyncTime = newLastSyncTime;
+    }
+
+    /**
+     * Attempt to write back prefsCache to the backing store.  If the attempt
+     * succeeds, lastSyncTime will be updated (the new value will correspond
+     * exactly to the data thust written back, as we hold the file lock, which
+     * prevents a concurrent write.  If the attempt fails, a
+     * BackingStoreException is thrown and both the backing store (prefsFile)
+     * and lastSyncTime will be unaffected by this call.  This call will
+     * NEVER leave prefsFile in a corrupt state.
+     */
+    private void writeBackCache() throws BackingStoreException {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws BackingStoreException {
+                    try {
+                        if (!dir.exists() && !dir.mkdirs())
+                            throw new BackingStoreException(dir +
+                                                             " create failed.");
+                        try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
+                            XmlSupport.exportMap(fos, prefsCache);
+                        }
+                        if (!tmpFile.renameTo(prefsFile))
+                            throw new BackingStoreException("Can't rename " +
+                            tmpFile + " to " + prefsFile);
+                    } catch(Exception e) {
+                        if (e instanceof BackingStoreException)
+                            throw (BackingStoreException)e;
+                        throw new BackingStoreException(e);
+                    }
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw (BackingStoreException) e.getException();
+        }
+    }
+
+    protected String[] keysSpi() {
+        initCacheIfNecessary();
+        return prefsCache.keySet().toArray(new String[prefsCache.size()]);
+    }
+
+    protected String[] childrenNamesSpi() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<String[]>() {
+                public String[] run() {
+                    List<String> result = new ArrayList<>();
+                    File[] dirContents = dir.listFiles();
+                    if (dirContents != null) {
+                        for (int i = 0; i < dirContents.length; i++)
+                            if (dirContents[i].isDirectory())
+                                result.add(nodeName(dirContents[i].getName()));
+                    }
+                    return result.toArray(EMPTY_STRING_ARRAY);
+               }
+            });
+    }
+
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+    protected AbstractPreferences childSpi(String name) {
+        return new FileSystemPreferences(this, name);
+    }
+
+    public void removeNode() throws BackingStoreException {
+        synchronized (isUserNode()? userLockFile: systemLockFile) {
+            // to remove a node we need an exclusive lock
+            if (!lockFile(false))
+                throw(new BackingStoreException("Couldn't get file lock."));
+           try {
+                super.removeNode();
+           } finally {
+                unlockFile();
+           }
+        }
+    }
+
+    /**
+     * Called with file lock held (in addition to node locks).
+     */
+    protected void removeNodeSpi() throws BackingStoreException {
+        try {
+            AccessController.doPrivileged(
+                new PrivilegedExceptionAction<Void>() {
+                public Void run() throws BackingStoreException {
+                    if (changeLog.contains(nodeCreate)) {
+                        changeLog.remove(nodeCreate);
+                        nodeCreate = null;
+                        return null;
+                    }
+                    if (!dir.exists())
+                        return null;
+                    prefsFile.delete();
+                    tmpFile.delete();
+                    // dir should be empty now.  If it's not, empty it
+                    File[] junk = dir.listFiles();
+                    if (junk.length != 0) {
+                        getLogger().warning(
+                           "Found extraneous files when removing node: "
+                            + Arrays.asList(junk));
+                        for (int i=0; i<junk.length; i++)
+                            junk[i].delete();
+                    }
+                    if (!dir.delete())
+                        throw new BackingStoreException("Couldn't delete dir: "
+                                                                         + dir);
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException e) {
+            throw (BackingStoreException) e.getException();
+        }
+    }
+
+    public synchronized void sync() throws BackingStoreException {
+        boolean userNode = isUserNode();
+        boolean shared;
+
+        if (userNode) {
+            shared = false; /* use exclusive lock for user prefs */
+        } else {
+            /* if can write to system root, use exclusive lock.
+               otherwise use shared lock. */
+            shared = !isSystemRootWritable;
+        }
+        synchronized (isUserNode()? userLockFile:systemLockFile) {
+           if (!lockFile(shared))
+               throw(new BackingStoreException("Couldn't get file lock."));
+           final Long newModTime =
+                AccessController.doPrivileged(
+                    new PrivilegedAction<Long>() {
+               public Long run() {
+                   long nmt;
+                   if (isUserNode()) {
+                       nmt = userRootModFile.lastModified();
+                       isUserRootModified = userRootModTime == nmt;
+                   } else {
+                       nmt = systemRootModFile.lastModified();
+                       isSystemRootModified = systemRootModTime == nmt;
+                   }
+                   return new Long(nmt);
+               }
+           });
+           try {
+               super.sync();
+               AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                   public Void run() {
+                   if (isUserNode()) {
+                       userRootModTime = newModTime.longValue() + 1000;
+                       userRootModFile.setLastModified(userRootModTime);
+                   } else {
+                       systemRootModTime = newModTime.longValue() + 1000;
+                       systemRootModFile.setLastModified(systemRootModTime);
+                   }
+                   return null;
+                   }
+               });
+           } finally {
+                unlockFile();
+           }
+        }
+    }
+
+    protected void syncSpi() throws BackingStoreException {
+        syncSpiPrivileged();
+    }
+
+    private void syncSpiPrivileged() throws BackingStoreException {
+        if (isRemoved())
+            throw new IllegalStateException("Node has been removed");
+        if (prefsCache == null)
+            return;  // We've never been used, don't bother syncing
+        long lastModifiedTime;
+        if ((isUserNode() ? isUserRootModified : isSystemRootModified)) {
+            lastModifiedTime = prefsFile.lastModified();
+            if (lastModifiedTime  != lastSyncTime) {
+                // Prefs at this node were externally modified; read in node and
+                // playback any local mods since last sync
+                loadCache();
+                replayChanges();
+                lastSyncTime = lastModifiedTime;
+            }
+        } else if (lastSyncTime != 0 && !dir.exists()) {
+            // This node was removed in the background.  Playback any changes
+            // against a virgin (empty) Map.
+            prefsCache = new TreeMap<>();
+            replayChanges();
+        }
+        if (!changeLog.isEmpty()) {
+            writeBackCache();  // Creates directory & file if necessary
+           /*
+            * Attempt succeeded; it's barely possible that the call to
+            * lastModified might fail (i.e., return 0), but this would not
+            * be a disaster, as lastSyncTime is allowed to lag.
+            */
+            lastModifiedTime = prefsFile.lastModified();
+            /* If lastSyncTime did not change, or went back
+             * increment by 1 second. Since we hold the lock
+             * lastSyncTime always monotonically encreases in the
+             * atomic sense.
+             */
+            if (lastSyncTime <= lastModifiedTime) {
+                lastSyncTime = lastModifiedTime + 1000;
+                prefsFile.setLastModified(lastSyncTime);
+            }
+            changeLog.clear();
+        }
+    }
+
+    public void flush() throws BackingStoreException {
+        if (isRemoved())
+            return;
+        sync();
+    }
+
+    protected void flushSpi() throws BackingStoreException {
+        // assert false;
+    }
+
+    /**
+     * Returns true if the specified character is appropriate for use in
+     * Unix directory names.  A character is appropriate if it's a printable
+     * ASCII character (> 0x1f && < 0x7f) and unequal to slash ('/', 0x2f),
+     * dot ('.', 0x2e), or underscore ('_', 0x5f).
+     */
+    private static boolean isDirChar(char ch) {
+        return ch > 0x1f && ch < 0x7f && ch != '/' && ch != '.' && ch != '_';
+    }
+
+    /**
+     * Returns the directory name corresponding to the specified node name.
+     * Generally, this is just the node name.  If the node name includes
+     * inappropriate characters (as per isDirChar) it is translated to Base64.
+     * with the underscore  character ('_', 0x5f) prepended.
+     */
+    private static String dirName(String nodeName) {
+        for (int i=0, n=nodeName.length(); i < n; i++)
+            if (!isDirChar(nodeName.charAt(i)))
+                return "_" + Base64.byteArrayToAltBase64(byteArray(nodeName));
+        return nodeName;
+    }
+
+    /**
+     * Translate a string into a byte array by translating each character
+     * into two bytes, high-byte first ("big-endian").
+     */
+    private static byte[] byteArray(String s) {
+        int len = s.length();
+        byte[] result = new byte[2*len];
+        for (int i=0, j=0; i<len; i++) {
+            char c = s.charAt(i);
+            result[j++] = (byte) (c>>8);
+            result[j++] = (byte) c;
+        }
+        return result;
+    }
+
+    /**
+     * Returns the node name corresponding to the specified directory name.
+ * (Inverts the transformation of dirName(String).
+     */
+    private static String nodeName(String dirName) {
+        if (dirName.charAt(0) != '_')
+            return dirName;
+        byte a[] = Base64.altBase64ToByteArray(dirName.substring(1));
+        StringBuffer result = new StringBuffer(a.length/2);
+        for (int i = 0; i < a.length; ) {
+            int highByte = a[i++] & 0xff;
+            int lowByte =  a[i++] & 0xff;
+            result.append((char) ((highByte << 8) | lowByte));
+        }
+        return result.toString();
+    }
+
+    /**
+     * Try to acquire the appropriate file lock (user or system).  If
+     * the initial attempt fails, several more attempts are made using
+     * an exponential backoff strategy.  If all attempts fail, this method
+     * returns false.
+     * @throws SecurityException if file access denied.
+     */
+    private boolean lockFile(boolean shared) throws SecurityException{
+        boolean usernode = isUserNode();
+        int[] result;
+        int errorCode = 0;
+        File lockFile = (usernode ? userLockFile : systemLockFile);
+        long sleepTime = INIT_SLEEP_TIME;
+        for (int i = 0; i < MAX_ATTEMPTS; i++) {
+            try {
+                  int perm = (usernode? USER_READ_WRITE: USER_RW_ALL_READ);
+                  result = lockFile0(lockFile.getCanonicalPath(), perm, shared);
+
+                  errorCode = result[ERROR_CODE];
+                  if (result[LOCK_HANDLE] != 0) {
+                     if (usernode) {
+                         userRootLockHandle = result[LOCK_HANDLE];
+                     } else {
+                         systemRootLockHandle = result[LOCK_HANDLE];
+                     }
+                     return true;
+                  }
+            } catch(IOException e) {
+//                // If at first, you don't succeed...
+            }
+
+            try {
+                Thread.sleep(sleepTime);
+            } catch(InterruptedException e) {
+                checkLockFile0ErrorCode(errorCode);
+                return false;
+            }
+            sleepTime *= 2;
+        }
+        checkLockFile0ErrorCode(errorCode);
+        return false;
+    }
+
+    /**
+     * Checks if unlockFile0() returned an error. Throws a SecurityException,
+     * if access denied. Logs a warning otherwise.
+     */
+    private void checkLockFile0ErrorCode (int errorCode)
+                                                      throws SecurityException {
+        if (errorCode == EACCES)
+            throw new SecurityException("Could not lock " +
+            (isUserNode()? "User prefs." : "System prefs.") +
+             " Lock file access denied.");
+        if (errorCode != EAGAIN)
+            getLogger().warning("Could not lock " +
+                             (isUserNode()? "User prefs. " : "System prefs.") +
+                             " Unix error code " + errorCode + ".");
+    }
+
+    /**
+     * Locks file using UNIX file locking.
+     * @param fileName Absolute file name of the lock file.
+     * @return Returns a lock handle, used to unlock the file.
+     */
+    private static native int[]
+            lockFile0(String fileName, int permission, boolean shared);
+
+    /**
+     * Unlocks file previously locked by lockFile0().
+     * @param lockHandle Handle to the file lock.
+     * @return Returns zero if OK, UNIX error code if failure.
+     */
+    private  static native int unlockFile0(int lockHandle);
+
+    /**
+     * Changes UNIX file permissions.
+     */
+    private static native int chmod(String fileName, int permission);
+
+    /**
+     * Initial time between lock attempts, in ms.  The time is doubled
+     * after each failing attempt (except the first).
+     */
+    private static int INIT_SLEEP_TIME = 50;
+
+    /**
+     * Maximum number of lock attempts.
+     */
+    private static int MAX_ATTEMPTS = 5;
+
+    /**
+     * Release the the appropriate file lock (user or system).
+     * @throws SecurityException if file access denied.
+     */
+    private void unlockFile() {
+        int result;
+        boolean usernode = isUserNode();
+        File lockFile = (usernode ? userLockFile : systemLockFile);
+        int lockHandle = ( usernode ? userRootLockHandle:systemRootLockHandle);
+        if (lockHandle == 0) {
+            getLogger().warning("Unlock: zero lockHandle for " +
+                           (usernode ? "user":"system") + " preferences.)");
+            return;
+        }
+        result = unlockFile0(lockHandle);
+        if (result != 0) {
+            getLogger().warning("Could not drop file-lock on " +
+            (isUserNode() ? "user" : "system") + " preferences." +
+            " Unix error code " + result + ".");
+            if (result == EACCES)
+                throw new SecurityException("Could not unlock" +
+                (isUserNode()? "User prefs." : "System prefs.") +
+                " Lock file access denied.");
+        }
+        if (isUserNode()) {
+            userRootLockHandle = 0;
+        } else {
+            systemRootLockHandle = 0;
+        }
+    }
+}
diff --git a/java/util/prefs/FileSystemPreferencesFactory.java b/java/util/prefs/FileSystemPreferencesFactory.java
new file mode 100644
index 0000000..bd1a723
--- /dev/null
+++ b/java/util/prefs/FileSystemPreferencesFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * Factory for FileSystemPreferences.  This class allows FileSystemPreferences
+ * to be installed as the Preferences implementations via the
+ * java.util.prefs.PreferencesFactory system property.
+ *
+ * @author  Josh Bloch
+ * @see     FileSystemPreferences
+ * @see     Preferences
+ * @since   1.4
+ */
+
+class FileSystemPreferencesFactory implements PreferencesFactory {
+    public Preferences userRoot() {
+        return FileSystemPreferences.getUserRoot();
+    }
+
+    public Preferences systemRoot() {
+        return FileSystemPreferences.getSystemRoot();
+    }
+}
diff --git a/java/util/prefs/InvalidPreferencesFormatException.java b/java/util/prefs/InvalidPreferencesFormatException.java
new file mode 100644
index 0000000..3a5e817
--- /dev/null
+++ b/java/util/prefs/InvalidPreferencesFormatException.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * Thrown to indicate that an operation could not complete because
+ * the input did not conform to the appropriate XML document type
+ * for a collection of preferences, as per the {@link Preferences}
+ * specification.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public class InvalidPreferencesFormatException extends Exception {
+    /**
+     * Constructs an InvalidPreferencesFormatException with the specified
+     * cause.
+     *
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPreferencesFormatException(Throwable cause) {
+        super(cause);
+    }
+
+   /**
+    * Constructs an InvalidPreferencesFormatException with the specified
+    * detail message.
+    *
+    * @param   message   the detail message. The detail message is saved for
+    *          later retrieval by the {@link Throwable#getMessage()} method.
+    */
+    public InvalidPreferencesFormatException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs an InvalidPreferencesFormatException with the specified
+     * detail message and cause.
+     *
+     * @param  message   the detail message. The detail message is saved for
+     *         later retrieval by the {@link Throwable#getMessage()} method.
+     * @param  cause the cause (which is saved for later retrieval by the
+     *         {@link Throwable#getCause()} method).
+     */
+    public InvalidPreferencesFormatException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    private static final long serialVersionUID = -791715184232119669L;
+}
diff --git a/java/util/prefs/NodeChangeEvent.java b/java/util/prefs/NodeChangeEvent.java
new file mode 100644
index 0000000..f108925
--- /dev/null
+++ b/java/util/prefs/NodeChangeEvent.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * An event emitted by a <tt>Preferences</tt> node to indicate that
+ * a child of that node has been added or removed.<p>
+ *
+ * Note, that although NodeChangeEvent inherits Serializable interface from
+ * java.util.EventObject, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @see     NodeChangeListener
+ * @see     PreferenceChangeEvent
+ * @since   1.4
+ * @serial  exclude
+ */
+
+public class NodeChangeEvent extends java.util.EventObject {
+    /**
+     * The node that was added or removed.
+     *
+     * @serial
+     */
+    private Preferences child;
+
+    /**
+     * Constructs a new <code>NodeChangeEvent</code> instance.
+     *
+     * @param parent  The parent of the node that was added or removed.
+     * @param child   The node that was added or removed.
+     */
+    public NodeChangeEvent(Preferences parent, Preferences child) {
+        super(parent);
+        this.child = child;
+    }
+
+    /**
+     * Returns the parent of the node that was added or removed.
+     *
+     * @return  The parent Preferences node whose child was added or removed
+     */
+    public Preferences getParent() {
+        return (Preferences) getSource();
+    }
+
+    /**
+     * Returns the node that was added or removed.
+     *
+     * @return  The node that was added or removed.
+     */
+    public Preferences getChild() {
+        return child;
+    }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects are not
+     * intended to be serializable.
+     */
+     private void writeObject(java.io.ObjectOutputStream out)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects are not
+     * intended to be serializable.
+     */
+     private void readObject(java.io.ObjectInputStream in)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    // Defined so that this class isn't flagged as a potential problem when
+    // searches for missing serialVersionUID fields are done.
+    private static final long serialVersionUID = 8068949086596572957L;
+}
diff --git a/java/util/prefs/NodeChangeListener.java b/java/util/prefs/NodeChangeListener.java
new file mode 100644
index 0000000..f343764
--- /dev/null
+++ b/java/util/prefs/NodeChangeListener.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * A listener for receiving preference node change events.
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @see     NodeChangeEvent
+ * @see     PreferenceChangeListener
+ * @since   1.4
+ */
+
+public interface NodeChangeListener extends java.util.EventListener {
+    /**
+     * This method gets called when a child node is added.
+     *
+     * @param evt A node change event object describing the parent
+     *            and child node.
+     */
+    void childAdded(NodeChangeEvent evt);
+
+    /**
+     * This method gets called when a child node is removed.
+     *
+     * @param evt A node change event object describing the parent
+     *            and child node.
+     */
+    void childRemoved(NodeChangeEvent evt);
+}
diff --git a/java/util/prefs/PreferenceChangeEvent.java b/java/util/prefs/PreferenceChangeEvent.java
new file mode 100644
index 0000000..f7cf7b5
--- /dev/null
+++ b/java/util/prefs/PreferenceChangeEvent.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.NotSerializableException;
+
+/**
+ * An event emitted by a <tt>Preferences</tt> node to indicate that
+ * a preference has been added, removed or has had its value changed.<p>
+ *
+ * Note, that although PreferenceChangeEvent inherits Serializable interface
+ * from EventObject, it is not intended to be Serializable. Appropriate
+ * serialization methods are implemented to throw NotSerializableException.
+ *
+ * @author  Josh Bloch
+ * @see Preferences
+ * @see PreferenceChangeListener
+ * @see NodeChangeEvent
+ * @since   1.4
+ * @serial exclude
+ */
+public class PreferenceChangeEvent extends java.util.EventObject {
+
+    /**
+     * Key of the preference that changed.
+     *
+     * @serial
+     */
+    private String key;
+
+    /**
+     * New value for preference, or <tt>null</tt> if it was removed.
+     *
+     * @serial
+     */
+    private String newValue;
+
+    /**
+     * Constructs a new <code>PreferenceChangeEvent</code> instance.
+     *
+     * @param node  The Preferences node that emitted the event.
+     * @param key  The key of the preference that was changed.
+     * @param newValue  The new value of the preference, or <tt>null</tt>
+     *                  if the preference is being removed.
+     */
+    public PreferenceChangeEvent(Preferences node, String key,
+                                 String newValue) {
+        super(node);
+        this.key = key;
+        this.newValue = newValue;
+    }
+
+    /**
+     * Returns the preference node that emitted the event.
+     *
+     * @return  The preference node that emitted the event.
+     */
+    public Preferences getNode() {
+        return (Preferences) getSource();
+    }
+
+    /**
+     * Returns the key of the preference that was changed.
+     *
+     * @return  The key of the preference that was changed.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Returns the new value for the preference.
+     *
+     * @return  The new value for the preference, or <tt>null</tt> if the
+     *          preference was removed.
+     */
+    public String getNewValue() {
+        return newValue;
+    }
+
+    /**
+     * Throws NotSerializableException, since NodeChangeEvent objects
+     * are not intended to be serializable.
+     */
+     private void writeObject(java.io.ObjectOutputStream out)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    /**
+     * Throws NotSerializableException, since PreferenceChangeEvent objects
+     * are not intended to be serializable.
+     */
+     private void readObject(java.io.ObjectInputStream in)
+                                               throws NotSerializableException {
+         throw new NotSerializableException("Not serializable.");
+     }
+
+    // Defined so that this class isn't flagged as a potential problem when
+    // searches for missing serialVersionUID fields are done.
+    private static final long serialVersionUID = 793724513368024975L;
+}
diff --git a/java/util/prefs/PreferenceChangeListener.java b/java/util/prefs/PreferenceChangeListener.java
new file mode 100644
index 0000000..0fb96c5
--- /dev/null
+++ b/java/util/prefs/PreferenceChangeListener.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+/**
+ * A listener for receiving preference change events.
+ *
+ * @author  Josh Bloch
+ * @see Preferences
+ * @see PreferenceChangeEvent
+ * @see NodeChangeListener
+ * @since   1.4
+ */
+@FunctionalInterface
+public interface PreferenceChangeListener extends java.util.EventListener {
+    /**
+     * This method gets called when a preference is added, removed or when
+     * its value is changed.
+     * <p>
+     * @param evt A PreferenceChangeEvent object describing the event source
+     *          and the preference that has changed.
+     */
+    void preferenceChange(PreferenceChangeEvent evt);
+}
diff --git a/java/util/prefs/Preferences.java b/java/util/prefs/Preferences.java
new file mode 100644
index 0000000..c643fc2
--- /dev/null
+++ b/java/util/prefs/Preferences.java
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+
+// These imports needed only as a workaround for a JavaDoc bug
+import java.lang.RuntimePermission;
+import java.lang.Integer;
+import java.lang.Long;
+import java.lang.Float;
+import java.lang.Double;
+
+/**
+ * A node in a hierarchical collection of preference data.  This class
+ * allows applications to store and retrieve user and system
+ * preference and configuration data.  This data is stored
+ * persistently in an implementation-dependent backing store.  Typical
+ * implementations include flat files, OS-specific registries,
+ * directory servers and SQL databases.  The user of this class needn't
+ * be concerned with details of the backing store.
+ *
+ * <p>There are two separate trees of preference nodes, one for user
+ * preferences and one for system preferences.  Each user has a separate user
+ * preference tree, and all users in a given system share the same system
+ * preference tree.  The precise description of "user" and "system" will vary
+ * from implementation to implementation.  Typical information stored in the
+ * user preference tree might include font choice, color choice, or preferred
+ * window location and size for a particular application.  Typical information
+ * stored in the system preference tree might include installation
+ * configuration data for an application.
+ *
+ * <p>Nodes in a preference tree are named in a similar fashion to
+ * directories in a hierarchical file system.   Every node in a preference
+ * tree has a <i>node name</i> (which is not necessarily unique),
+ * a unique <i>absolute path name</i>, and a path name <i>relative</i> to each
+ * ancestor including itself.
+ *
+ * <p>The root node has a node name of the empty string ("").  Every other
+ * node has an arbitrary node name, specified at the time it is created.  The
+ * only restrictions on this name are that it cannot be the empty string, and
+ * it cannot contain the slash character ('/').
+ *
+ * <p>The root node has an absolute path name of <tt>"/"</tt>.  Children of
+ * the root node have absolute path names of <tt>"/" + </tt><i>&lt;node
+ * name&gt;</i>.  All other nodes have absolute path names of <i>&lt;parent's
+ * absolute path name&gt;</i><tt> + "/" + </tt><i>&lt;node name&gt;</i>.
+ * Note that all absolute path names begin with the slash character.
+ *
+ * <p>A node <i>n</i>'s path name relative to its ancestor <i>a</i>
+ * is simply the string that must be appended to <i>a</i>'s absolute path name
+ * in order to form <i>n</i>'s absolute path name, with the initial slash
+ * character (if present) removed.  Note that:
+ * <ul>
+ * <li>No relative path names begin with the slash character.
+ * <li>Every node's path name relative to itself is the empty string.
+ * <li>Every node's path name relative to its parent is its node name (except
+ * for the root node, which does not have a parent).
+ * <li>Every node's path name relative to the root is its absolute path name
+ * with the initial slash character removed.
+ * </ul>
+ *
+ * <p>Note finally that:
+ * <ul>
+ * <li>No path name contains multiple consecutive slash characters.
+ * <li>No path name with the exception of the root's absolute path name
+ * ends in the slash character.
+ * <li>Any string that conforms to these two rules is a valid path name.
+ * </ul>
+ *
+ * <p>All of the methods that modify preferences data are permitted to operate
+ * asynchronously; they may return immediately, and changes will eventually
+ * propagate to the persistent backing store with an implementation-dependent
+ * delay.  The <tt>flush</tt> method may be used to synchronously force
+ * updates to the backing store.  Normal termination of the Java Virtual
+ * Machine will <i>not</i> result in the loss of pending updates -- an explicit
+ * <tt>flush</tt> invocation is <i>not</i> required upon termination to ensure
+ * that pending updates are made persistent.
+ *
+ * <p>All of the methods that read preferences from a <tt>Preferences</tt>
+ * object require the invoker to provide a default value.  The default value is
+ * returned if no value has been previously set <i>or if the backing store is
+ * unavailable</i>.  The intent is to allow applications to operate, albeit
+ * with slightly degraded functionality, even if the backing store becomes
+ * unavailable.  Several methods, like <tt>flush</tt>, have semantics that
+ * prevent them from operating if the backing store is unavailable.  Ordinary
+ * applications should have no need to invoke any of these methods, which can
+ * be identified by the fact that they are declared to throw {@link
+ * BackingStoreException}.
+ *
+ * <p>The methods in this class may be invoked concurrently by multiple threads
+ * in a single JVM without the need for external synchronization, and the
+ * results will be equivalent to some serial execution.  If this class is used
+ * concurrently <i>by multiple JVMs</i> that store their preference data in
+ * the same backing store, the data store will not be corrupted, but no
+ * other guarantees are made concerning the consistency of the preference
+ * data.
+ *
+ * <p>This class contains an export/import facility, allowing preferences
+ * to be "exported" to an XML document, and XML documents representing
+ * preferences to be "imported" back into the system.  This facility
+ * may be used to back up all or part of a preference tree, and
+ * subsequently restore from the backup.
+ *
+ * <p>The XML document has the following DOCTYPE declaration:
+ * <pre>{@code
+ * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+ * }</pre>
+ * Note that the system URI (http://java.sun.com/dtd/preferences.dtd) is
+ * <i>not</i> accessed when exporting or importing preferences; it merely
+ * serves as a string to uniquely identify the DTD, which is:
+ * <pre>{@code
+ *    <?xml version="1.0" encoding="UTF-8"?>
+ *
+ *    <!-- DTD for a Preferences tree. -->
+ *
+ *    <!-- The preferences element is at the root of an XML document
+ *         representing a Preferences tree. -->
+ *    <!ELEMENT preferences (root)>
+ *
+ *    <!-- The preferences element contains an optional version attribute,
+ *          which specifies version of DTD. -->
+ *    <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >
+ *
+ *    <!-- The root element has a map representing the root's preferences
+ *         (if any), and one node for each child of the root (if any). -->
+ *    <!ELEMENT root (map, node*) >
+ *
+ *    <!-- Additionally, the root contains a type attribute, which
+ *         specifies whether it's the system or user root. -->
+ *    <!ATTLIST root
+ *              type (system|user) #REQUIRED >
+ *
+ *    <!-- Each node has a map representing its preferences (if any),
+ *         and one node for each child (if any). -->
+ *    <!ELEMENT node (map, node*) >
+ *
+ *    <!-- Additionally, each node has a name attribute -->
+ *    <!ATTLIST node
+ *              name CDATA #REQUIRED >
+ *
+ *    <!-- A map represents the preferences stored at a node (if any). -->
+ *    <!ELEMENT map (entry*) >
+ *
+ *    <!-- An entry represents a single preference, which is simply
+ *          a key-value pair. -->
+ *    <!ELEMENT entry EMPTY >
+ *    <!ATTLIST entry
+ *              key   CDATA #REQUIRED
+ *              value CDATA #REQUIRED >
+ * }</pre>
+ *
+ * Every <tt>Preferences</tt> implementation must have an associated {@link
+ * PreferencesFactory} implementation.  Every Java(TM) SE implementation must provide
+ * some means of specifying which <tt>PreferencesFactory</tt> implementation
+ * is used to generate the root preferences nodes.  This allows the
+ * administrator to replace the default preferences implementation with an
+ * alternative implementation.
+ *
+ * <p>Implementation note: In Sun's JRE, the <tt>PreferencesFactory</tt>
+ * implementation is located as follows:
+ *
+ * <ol>
+ *
+ * <li><p>If the system property
+ * <tt>java.util.prefs.PreferencesFactory</tt> is defined, then it is
+ * taken to be the fully-qualified name of a class implementing the
+ * <tt>PreferencesFactory</tt> interface.  The class is loaded and
+ * instantiated; if this process fails then an unspecified error is
+ * thrown.</p></li>
+ *
+ * <li><p> If a <tt>PreferencesFactory</tt> implementation class file
+ * has been installed in a jar file that is visible to the
+ * {@link java.lang.ClassLoader#getSystemClassLoader system class loader},
+ * and that jar file contains a provider-configuration file named
+ * <tt>java.util.prefs.PreferencesFactory</tt> in the resource
+ * directory <tt>META-INF/services</tt>, then the first class name
+ * specified in that file is taken.  If more than one such jar file is
+ * provided, the first one found will be used.  The class is loaded
+ * and instantiated; if this process fails then an unspecified error
+ * is thrown.  </p></li>
+ *
+ * <li><p>Finally, if neither the above-mentioned system property nor
+ * an extension jar file is provided, then the system-wide default
+ * <tt>PreferencesFactory</tt> implementation for the underlying
+ * platform is loaded and instantiated.</p></li>
+ *
+ * </ol>
+ *
+ * @author  Josh Bloch
+ * @since   1.4
+ */
+public abstract class Preferences {
+
+    // Android-changed: Allow Preferences.factory to be set by tests.
+    // private static final PreferencesFactory factory = factory();
+    private static PreferencesFactory factory = factory();
+
+    // BEGIN Android-changed: Logic for constructing the default Preferences factory.
+    /*
+    private static PreferencesFactory factory() {
+        // 1. Try user-specified system property
+        String factoryName = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                public String run() {
+                    return System.getProperty(
+                        "java.util.prefs.PreferencesFactory");}});
+        if (factoryName != null) {
+            // FIXME: This code should be run in a doPrivileged and
+            // not use the context classloader, to avoid being
+            // dependent on the invoking thread.
+            // Checking AllPermission also seems wrong.
+            try {
+                return (PreferencesFactory)
+                    Class.forName(factoryName, false,
+                                  ClassLoader.getSystemClassLoader())
+                    .newInstance();
+            } catch (Exception ex) {
+                try {
+                    // workaround for javaws, plugin,
+                    // load factory class using non-system classloader
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null) {
+                        sm.checkPermission(new java.security.AllPermission());
+                    }
+                    return (PreferencesFactory)
+                        Class.forName(factoryName, false,
+                                      Thread.currentThread()
+                                      .getContextClassLoader())
+                        .newInstance();
+                } catch (Exception e) {
+                    throw new InternalError(
+                        "Can't instantiate Preferences factory "
+                        + factoryName, e);
+                }
+            }
+        }
+
+        return AccessController.doPrivileged(
+            new PrivilegedAction<PreferencesFactory>() {
+                public PreferencesFactory run() {
+                    return factory1();}});
+    }
+
+    private static PreferencesFactory factory1() {
+        // 2. Try service provider interface
+        Iterator<PreferencesFactory> itr = ServiceLoader
+            .load(PreferencesFactory.class, ClassLoader.getSystemClassLoader())
+            .iterator();
+
+        // choose first provider instance
+        while (itr.hasNext()) {
+            try {
+                return itr.next();
+            } catch (ServiceConfigurationError sce) {
+                if (sce.getCause() instanceof SecurityException) {
+                    // Ignore the security exception, try the next provider
+                    continue;
+                }
+                throw sce;
+            }
+        }
+
+        // 3. Use platform-specific system-wide default
+        String osName = System.getProperty("os.name");
+        String platformFactory;
+        if (osName.startsWith("Windows")) {
+            platformFactory = "java.util.prefs.WindowsPreferencesFactory";
+        } else if (osName.contains("OS X")) {
+            platformFactory = "java.util.prefs.MacOSXPreferencesFactory";
+        } else {
+            platformFactory = "java.util.prefs.FileSystemPreferencesFactory";
+        }
+        try {
+            return (PreferencesFactory)
+                Class.forName(platformFactory, false,
+                              Preferences.class.getClassLoader()).newInstance();
+        } catch (Exception e) {
+            throw new InternalError(
+                "Can't instantiate platform default Preferences factory "
+                + platformFactory, e);
+        }
+    }
+    */
+    private static PreferencesFactory factory() {
+        // Try the system property first...
+        PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class);
+        if (result != null) {
+            return result;
+        }
+        // Then use ServiceLoader for META-INF/services/...
+        for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class)) {
+            return impl;
+        }
+        // Finally return a default...
+        return new FileSystemPreferencesFactory();
+    }
+    // END Android-changed: Logic for constructing the default Preferences factory.
+
+    // BEGIN Android-added: Allow Preferences.factory to be set by tests.
+    /** @hide for testing only. */
+    public static PreferencesFactory setPreferencesFactory(PreferencesFactory pf) {
+        PreferencesFactory previous = factory;
+        factory = pf;
+        return previous;
+    }
+    // END Android-added: Allow Preferences.factory to be set by tests.
+
+    /**
+     * Maximum length of string allowed as a key (80 characters).
+     */
+    public static final int MAX_KEY_LENGTH = 80;
+
+    /**
+     * Maximum length of string allowed as a value (8192 characters).
+     */
+    public static final int MAX_VALUE_LENGTH = 8*1024;
+
+    /**
+     * Maximum length of a node name (80 characters).
+     */
+    public static final int MAX_NAME_LENGTH = 80;
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the preference node from the calling user's preference tree
+     * that is associated (by convention) with the specified class's package.
+     * The convention is as follows: the absolute path name of the node is the
+     * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
+     * with each period (<tt>'.'</tt>) replaced by a slash.  For example the
+     * absolute path name of the node associated with the class
+     * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
+     *
+     * <p>This convention does not apply to the unnamed package, whose
+     * associated preference node is <tt>&lt;unnamed&gt;</tt>.  This node
+     * is not intended for long term use, but for convenience in the early
+     * development of programs that do not yet belong to a package, and
+     * for "throwaway" programs.  <i>Valuable data should not be stored
+     * at this node as it is shared by all programs that use it.</i>
+     *
+     * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
+     * package can obtain a preference node as follows: <pre>
+     *    static Preferences prefs = Preferences.userNodeForPackage(Foo.class);
+     * </pre>
+     * This idiom obviates the need for using a string to describe the
+     * preferences node and decreases the likelihood of a run-time failure.
+     * (If the class name is misspelled, it will typically result in a
+     * compile-time error.)
+     *
+     * <p>Invoking this method will result in the creation of the returned
+     * node and its ancestors if they do not already exist.  If the returned
+     * node did not exist prior to this call, this node and any ancestors that
+     * were created by this call are not guaranteed to become permanent until
+     * the <tt>flush</tt> method is called on the returned node (or one of its
+     * ancestors or descendants).
+     *
+     * @param c the class for whose package a user preference node is desired.
+     * @return the user preference node associated with the package of which
+     *         <tt>c</tt> is a member.
+     * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
+     * @throws SecurityException if a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences userNodeForPackage(Class<?> c) {
+        return userRoot().node(nodeName(c));
+    }
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the preference node from the system preference tree that is
+     * associated (by convention) with the specified class's package.  The
+     * convention is as follows: the absolute path name of the node is the
+     * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
+     * with each period (<tt>'.'</tt>) replaced by a slash.  For example the
+     * absolute path name of the node associated with the class
+     * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
+     *
+     * <p>This convention does not apply to the unnamed package, whose
+     * associated preference node is <tt>&lt;unnamed&gt;</tt>.  This node
+     * is not intended for long term use, but for convenience in the early
+     * development of programs that do not yet belong to a package, and
+     * for "throwaway" programs.  <i>Valuable data should not be stored
+     * at this node as it is shared by all programs that use it.</i>
+     *
+     * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
+     * package can obtain a preference node as follows: <pre>
+     *  static Preferences prefs = Preferences.systemNodeForPackage(Foo.class);
+     * </pre>
+     * This idiom obviates the need for using a string to describe the
+     * preferences node and decreases the likelihood of a run-time failure.
+     * (If the class name is misspelled, it will typically result in a
+     * compile-time error.)
+     *
+     * <p>Invoking this method will result in the creation of the returned
+     * node and its ancestors if they do not already exist.  If the returned
+     * node did not exist prior to this call, this node and any ancestors that
+     * were created by this call are not guaranteed to become permanent until
+     * the <tt>flush</tt> method is called on the returned node (or one of its
+     * ancestors or descendants).
+     *
+     * @param c the class for whose package a system preference node is desired.
+     * @return the system preference node associated with the package of which
+     *         <tt>c</tt> is a member.
+     * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
+     * @throws SecurityException if a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences systemNodeForPackage(Class<?> c) {
+        return systemRoot().node(nodeName(c));
+    }
+
+    /**
+     * Returns the absolute path name of the node corresponding to the package
+     * of the specified object.
+     *
+     * @throws IllegalArgumentException if the package has node preferences
+     *         node associated with it.
+     */
+    private static String nodeName(Class<?> c) {
+        if (c.isArray())
+            throw new IllegalArgumentException(
+                "Arrays have no associated preferences node.");
+        String className = c.getName();
+        int pkgEndIndex = className.lastIndexOf('.');
+        if (pkgEndIndex < 0)
+            return "/<unnamed>";
+        String packageName = className.substring(0, pkgEndIndex);
+        return "/" + packageName.replace('.', '/');
+    }
+
+    /**
+     * This permission object represents the permission required to get
+     * access to the user or system root (which in turn allows for all
+     * other operations).
+     */
+    private static Permission prefsPerm = new RuntimePermission("preferences");
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the root preference node for the calling user.
+     *
+     * @return the root preference node for the calling user.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences userRoot() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(prefsPerm);
+
+        return factory.userRoot();
+    }
+
+    // Android-added: Document Android's security restrictions on system/user preferences.
+    /**
+     * <strong>WARNING:</strong> On Android, the Preference nodes
+     * corresponding to the "system" and "user" preferences are stored in sections
+     * of the file system that are inaccessible to apps. Further, allowing apps to set
+     * "system wide" preferences is contrary to android's security model.
+     *
+     * Returns the root preference node for the system.
+     *
+     * @return the root preference node for the system.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static Preferences systemRoot() {
+        SecurityManager security = System.getSecurityManager();
+        if (security != null)
+            security.checkPermission(prefsPerm);
+
+        return factory.systemRoot();
+    }
+
+    /**
+     * Sole constructor. (For invocation by subclass constructors, typically
+     * implicit.)
+     */
+    protected Preferences() {
+    }
+
+    /**
+     * Associates the specified value with the specified key in this
+     * preference node.
+     *
+     * @param key key with which the specified value is to be associated.
+     * @param value value to be associated with the specified key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *       <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
+     *       <tt>MAX_VALUE_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void put(String key, String value);
+
+    /**
+     * Returns the value associated with the specified key in this preference
+     * node.  Returns the specified default if there is no value associated
+     * with the key, or the backing store is inaccessible.
+     *
+     * <p>Some implementations may store default values in their backing
+     * stores.  If there is no value associated with the specified key
+     * but there is such a <i>stored default</i>, it is returned in
+     * preference to the specified default.
+     *
+     * @param key key whose associated value is to be returned.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>.
+     * @return the value associated with <tt>key</tt>, or <tt>def</tt>
+     *         if no value is associated with <tt>key</tt>, or the backing
+     *         store is inaccessible.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     */
+    public abstract String get(String key, String def);
+
+    /**
+     * Removes the value associated with the specified key in this preference
+     * node, if any.
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, and there is
+     * such a default for the specified preference, the stored default will be
+     * "exposed" by this call, in the sense that it will be returned
+     * by a succeeding call to <tt>get</tt>.
+     *
+     * @param key key whose mapping is to be removed from the preference node.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void remove(String key);
+
+    /**
+     * Removes all of the preferences (key-value associations) in this
+     * preference node.  This call has no effect on any descendants
+     * of this node.
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, and this
+     * node in the preferences hierarchy contains any such defaults,
+     * the stored defaults will be "exposed" by this call, in the sense that
+     * they will be returned by succeeding calls to <tt>get</tt>.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removeNode()
+     */
+    public abstract void clear() throws BackingStoreException;
+
+    /**
+     * Associates a string representing the specified int value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the int value were passed to
+     * {@link Integer#toString(int)}.  This method is intended for use in
+     * conjunction with {@link #getInt}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getInt(String,int)
+     */
+    public abstract void putInt(String key, int value);
+
+    /**
+     * Returns the int value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to
+     * an integer as by {@link Integer#parseInt(String)}.  Returns the
+     * specified default if there is no value associated with the key,
+     * the backing store is inaccessible, or if
+     * <tt>Integer.parseInt(String)</tt> would throw a {@link
+     * NumberFormatException} if the associated value were passed.  This
+     * method is intended for use in conjunction with {@link #putInt}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to an int
+     * with <tt>Integer.parseInt</tt>, this int is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as an int.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as an int,
+     *        or the backing store is inaccessible.
+     * @return the int value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         an int.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putInt(String,int)
+     * @see #get(String,String)
+     */
+    public abstract int getInt(String key, int def);
+
+    /**
+     * Associates a string representing the specified long value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the long value were passed to
+     * {@link Long#toString(long)}.  This method is intended for use in
+     * conjunction with {@link #getLong}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getLong(String,long)
+     */
+    public abstract void putLong(String key, long value);
+
+    /**
+     * Returns the long value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to
+     * a long as by {@link Long#parseLong(String)}.  Returns the
+     * specified default if there is no value associated with the key,
+     * the backing store is inaccessible, or if
+     * <tt>Long.parseLong(String)</tt> would throw a {@link
+     * NumberFormatException} if the associated value were passed.  This
+     * method is intended for use in conjunction with {@link #putLong}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a long
+     * with <tt>Long.parseLong</tt>, this long is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as a long.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a long,
+     *        or the backing store is inaccessible.
+     * @return the long value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a long.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putLong(String,long)
+     * @see #get(String,String)
+     */
+    public abstract long getLong(String key, long def);
+
+    /**
+     * Associates a string representing the specified boolean value with the
+     * specified key in this preference node.  The associated string is
+     * <tt>"true"</tt> if the value is true, and <tt>"false"</tt> if it is
+     * false.  This method is intended for use in conjunction with
+     * {@link #getBoolean}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getBoolean(String,boolean)
+     * @see #get(String,String)
+     */
+    public abstract void putBoolean(String key, boolean value);
+
+    /**
+     * Returns the boolean value represented by the string associated with the
+     * specified key in this preference node.  Valid strings
+     * are <tt>"true"</tt>, which represents true, and <tt>"false"</tt>, which
+     * represents false.  Case is ignored, so, for example, <tt>"TRUE"</tt>
+     * and <tt>"False"</tt> are also valid.  This method is intended for use in
+     * conjunction with {@link #putBoolean}.
+     *
+     * <p>Returns the specified default if there is no value
+     * associated with the key, the backing store is inaccessible, or if the
+     * associated value is something other than <tt>"true"</tt> or
+     * <tt>"false"</tt>, ignoring case.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists and is accessible, it is used in preference to the
+     * specified default, unless the stored default is something other than
+     * <tt>"true"</tt> or <tt>"false"</tt>, ignoring case, in which case the
+     * specified default is used.
+     *
+     * @param key key whose associated value is to be returned as a boolean.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a boolean,
+     *        or the backing store is inaccessible.
+     * @return the boolean value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a boolean.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #get(String,String)
+     * @see #putBoolean(String,boolean)
+     */
+    public abstract boolean getBoolean(String key, boolean def);
+
+    /**
+     * Associates a string representing the specified float value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the float value were passed to
+     * {@link Float#toString(float)}.  This method is intended for use in
+     * conjunction with {@link #getFloat}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getFloat(String,float)
+     */
+    public abstract void putFloat(String key, float value);
+
+    /**
+     * Returns the float value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to an
+     * integer as by {@link Float#parseFloat(String)}.  Returns the specified
+     * default if there is no value associated with the key, the backing store
+     * is inaccessible, or if <tt>Float.parseFloat(String)</tt> would throw a
+     * {@link NumberFormatException} if the associated value were passed.
+     * This method is intended for use in conjunction with {@link #putFloat}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a float
+     * with <tt>Float.parseFloat</tt>, this float is returned in preference to
+     * the specified default.
+     *
+     * @param key key whose associated value is to be returned as a float.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a float,
+     *        or the backing store is inaccessible.
+     * @return the float value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a float.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putFloat(String,float)
+     * @see #get(String,String)
+     */
+    public abstract float getFloat(String key, float def);
+
+    /**
+     * Associates a string representing the specified double value with the
+     * specified key in this preference node.  The associated string is the
+     * one that would be returned if the double value were passed to
+     * {@link Double#toString(double)}.  This method is intended for use in
+     * conjunction with {@link #getDouble}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
+     *         <tt>MAX_KEY_LENGTH</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getDouble(String,double)
+     */
+    public abstract void putDouble(String key, double value);
+
+    /**
+     * Returns the double value represented by the string associated with the
+     * specified key in this preference node.  The string is converted to an
+     * integer as by {@link Double#parseDouble(String)}.  Returns the specified
+     * default if there is no value associated with the key, the backing store
+     * is inaccessible, or if <tt>Double.parseDouble(String)</tt> would throw a
+     * {@link NumberFormatException} if the associated value were passed.
+     * This method is intended for use in conjunction with {@link #putDouble}.
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists, is accessible, and could be converted to a double
+     * with <tt>Double.parseDouble</tt>, this double is returned in preference
+     * to the specified default.
+     *
+     * @param key key whose associated value is to be returned as a double.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a double,
+     *        or the backing store is inaccessible.
+     * @return the double value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a double.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
+     * @see #putDouble(String,double)
+     * @see #get(String,String)
+     */
+    public abstract double getDouble(String key, double def);
+
+    /**
+     * Associates a string representing the specified byte array with the
+     * specified key in this preference node.  The associated string is
+     * the <i>Base64</i> encoding of the byte array, as defined in <a
+     * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
+     * with one minor change: the string will consist solely of characters
+     * from the <i>Base64 Alphabet</i>; it will not contain any newline
+     * characters.  Note that the maximum length of the byte array is limited
+     * to three quarters of <tt>MAX_VALUE_LENGTH</tt> so that the length
+     * of the Base64 encoded String does not exceed <tt>MAX_VALUE_LENGTH</tt>.
+     * This method is intended for use in conjunction with
+     * {@link #getByteArray}.
+     *
+     * @param key key with which the string form of value is to be associated.
+     * @param value value whose string form is to be associated with key.
+     * @throws NullPointerException if key or value is <tt>null</tt>.
+     * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
+     *         or if value.length exceeds MAX_VALUE_LENGTH*3/4.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #getByteArray(String,byte[])
+     * @see #get(String,String)
+     */
+    public abstract void putByteArray(String key, byte[] value);
+
+    /**
+     * Returns the byte array value represented by the string associated with
+     * the specified key in this preference node.  Valid strings are
+     * <i>Base64</i> encoded binary data, as defined in <a
+     * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
+     * with one minor change: the string must consist solely of characters
+     * from the <i>Base64 Alphabet</i>; no newline characters or
+     * extraneous characters are permitted.  This method is intended for use
+     * in conjunction with {@link #putByteArray}.
+     *
+     * <p>Returns the specified default if there is no value
+     * associated with the key, the backing store is inaccessible, or if the
+     * associated value is not a valid Base64 encoded byte array
+     * (as defined above).
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and such a
+     * default exists and is accessible, it is used in preference to the
+     * specified default, unless the stored default is not a valid Base64
+     * encoded byte array (as defined above), in which case the
+     * specified default is used.
+     *
+     * @param key key whose associated value is to be returned as a byte array.
+     * @param def the value to be returned in the event that this
+     *        preference node has no value associated with <tt>key</tt>
+     *        or the associated value cannot be interpreted as a byte array,
+     *        or the backing store is inaccessible.
+     * @return the byte array value represented by the string associated with
+     *         <tt>key</tt> in this preference node, or <tt>def</tt> if the
+     *         associated value does not exist or cannot be interpreted as
+     *         a byte array.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.  (A
+     *         <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
+     * @see #get(String,String)
+     * @see #putByteArray(String,byte[])
+     */
+    public abstract byte[] getByteArray(String key, byte[] def);
+
+    /**
+     * Returns all of the keys that have an associated value in this
+     * preference node.  (The returned array will be of size zero if
+     * this node has no preferences.)
+     *
+     * <p>If the implementation supports <i>stored defaults</i> and there
+     * are any such defaults at this node that have not been overridden,
+     * by explicit preferences, the defaults are returned in the array in
+     * addition to any explicit preferences.
+     *
+     * @return an array of the keys that have an associated value in this
+     *         preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract String[] keys() throws BackingStoreException;
+
+    /**
+     * Returns the names of the children of this preference node, relative to
+     * this node.  (The returned array will be of size zero if this node has
+     * no children.)
+     *
+     * @return the names of the children of this preference node.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract String[] childrenNames() throws BackingStoreException;
+
+    /**
+     * Returns the parent of this preference node, or <tt>null</tt> if this is
+     * the root.
+     *
+     * @return the parent of this preference node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract Preferences parent();
+
+    /**
+     * Returns the named preference node in the same tree as this node,
+     * creating it and any of its ancestors if they do not already exist.
+     * Accepts a relative or absolute path name.  Relative path names
+     * (which do not begin with the slash character <tt>('/')</tt>) are
+     * interpreted relative to this preference node.
+     *
+     * <p>If the returned node did not exist prior to this call, this node and
+     * any ancestors that were created by this call are not guaranteed
+     * to become permanent until the <tt>flush</tt> method is called on
+     * the returned node (or one of its ancestors or descendants).
+     *
+     * @param pathName the path name of the preference node to return.
+     * @return the specified preference node.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws NullPointerException if path name is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #flush()
+     */
+    public abstract Preferences node(String pathName);
+
+    /**
+     * Returns true if the named preference node exists in the same tree
+     * as this node.  Relative path names (which do not begin with the slash
+     * character <tt>('/')</tt>) are interpreted relative to this preference
+     * node.
+     *
+     * <p>If this node (or an ancestor) has already been removed with the
+     * {@link #removeNode()} method, it <i>is</i> legal to invoke this method,
+     * but only with the path name <tt>""</tt>; the invocation will return
+     * <tt>false</tt>.  Thus, the idiom <tt>p.nodeExists("")</tt> may be
+     * used to test whether <tt>p</tt> has been removed.
+     *
+     * @param pathName the path name of the node whose existence
+     *        is to be checked.
+     * @return true if the specified node exists.
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalArgumentException if the path name is invalid (i.e.,
+     *         it contains multiple consecutive slash characters, or ends
+     *         with a slash character and is more than one character long).
+     * @throws NullPointerException if path name is <tt>null</tt>.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method and
+     *         <tt>pathName</tt> is not the empty string (<tt>""</tt>).
+     */
+    public abstract boolean nodeExists(String pathName)
+        throws BackingStoreException;
+
+    /**
+     * Removes this preference node and all of its descendants, invalidating
+     * any preferences contained in the removed nodes.  Once a node has been
+     * removed, attempting any method other than {@link #name()},
+     * {@link #absolutePath()}, {@link #isUserNode()}, {@link #flush()} or
+     * {@link #node(String) nodeExists("")} on the corresponding
+     * <tt>Preferences</tt> instance will fail with an
+     * <tt>IllegalStateException</tt>.  (The methods defined on {@link Object}
+     * can still be invoked on a node after it has been removed; they will not
+     * throw <tt>IllegalStateException</tt>.)
+     *
+     * <p>The removal is not guaranteed to be persistent until the
+     * <tt>flush</tt> method is called on this node (or an ancestor).
+     *
+     * <p>If this implementation supports <i>stored defaults</i>, removing a
+     * node exposes any stored defaults at or below this node.  Thus, a
+     * subsequent call to <tt>nodeExists</tt> on this node's path name may
+     * return <tt>true</tt>, and a subsequent call to <tt>node</tt> on this
+     * path name may return a (different) <tt>Preferences</tt> instance
+     * representing a non-empty collection of preferences and/or children.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has already
+     *         been removed with the {@link #removeNode()} method.
+     * @throws UnsupportedOperationException if this method is invoked on
+     *         the root node.
+     * @see #flush()
+     */
+    public abstract void removeNode() throws BackingStoreException;
+
+    /**
+     * Returns this preference node's name, relative to its parent.
+     *
+     * @return this preference node's name, relative to its parent.
+     */
+    public abstract String name();
+
+    /**
+     * Returns this preference node's absolute path name.
+     *
+     * @return this preference node's absolute path name.
+     */
+    public abstract String absolutePath();
+
+    /**
+     * Returns <tt>true</tt> if this preference node is in the user
+     * preference tree, <tt>false</tt> if it's in the system preference tree.
+     *
+     * @return <tt>true</tt> if this preference node is in the user
+     *         preference tree, <tt>false</tt> if it's in the system
+     *         preference tree.
+     */
+    public abstract boolean isUserNode();
+
+    /**
+     * Returns a string representation of this preferences node,
+     * as if computed by the expression:<tt>(this.isUserNode() ? "User" :
+     * "System") + " Preference Node: " + this.absolutePath()</tt>.
+     */
+    public abstract String toString();
+
+    /**
+     * Forces any changes in the contents of this preference node and its
+     * descendants to the persistent store.  Once this method returns
+     * successfully, it is safe to assume that all changes made in the
+     * subtree rooted at this node prior to the method invocation have become
+     * permanent.
+     *
+     * <p>Implementations are free to flush changes into the persistent store
+     * at any time.  They do not need to wait for this method to be called.
+     *
+     * <p>When a flush occurs on a newly created node, it is made persistent,
+     * as are any ancestors (and descendants) that have yet to be made
+     * persistent.  Note however that any preference value changes in
+     * ancestors are <i>not</i> guaranteed to be made persistent.
+     *
+     * <p> If this method is invoked on a node that has been removed with
+     * the {@link #removeNode()} method, flushSpi() is invoked on this node,
+     * but not on others.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @see    #sync()
+     */
+    public abstract void flush() throws BackingStoreException;
+
+    /**
+     * Ensures that future reads from this preference node and its
+     * descendants reflect any changes that were committed to the persistent
+     * store (from any VM) prior to the <tt>sync</tt> invocation.  As a
+     * side-effect, forces any changes in the contents of this preference node
+     * and its descendants to the persistent store, as if the <tt>flush</tt>
+     * method had been invoked on this node.
+     *
+     * @throws BackingStoreException if this operation cannot be completed
+     *         due to a failure in the backing store, or inability to
+     *         communicate with it.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see    #flush()
+     */
+    public abstract void sync() throws BackingStoreException;
+
+    /**
+     * Registers the specified listener to receive <i>preference change
+     * events</i> for this preference node.  A preference change event is
+     * generated when a preference is added to this node, removed from this
+     * node, or when the value associated with a preference is changed.
+     * (Preference change events are <i>not</i> generated by the {@link
+     * #removeNode()} method, which generates a <i>node change event</i>.
+     * Preference change events <i>are</i> generated by the <tt>clear</tt>
+     * method.)
+     *
+     * <p>Events are only guaranteed for changes made within the same JVM
+     * as the registered listener, though some implementations may generate
+     * events for changes made outside this JVM.  Events may be generated
+     * before the changes have been made persistent.  Events are not generated
+     * when preferences are modified in descendants of this node; a caller
+     * desiring such events must register with each descendant.
+     *
+     * @param pcl The preference change listener to add.
+     * @throws NullPointerException if <tt>pcl</tt> is null.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removePreferenceChangeListener(PreferenceChangeListener)
+     * @see #addNodeChangeListener(NodeChangeListener)
+     */
+    public abstract void addPreferenceChangeListener(
+        PreferenceChangeListener pcl);
+
+    /**
+     * Removes the specified preference change listener, so it no longer
+     * receives preference change events.
+     *
+     * @param pcl The preference change listener to remove.
+     * @throws IllegalArgumentException if <tt>pcl</tt> was not a registered
+     *         preference change listener on this node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #addPreferenceChangeListener(PreferenceChangeListener)
+     */
+    public abstract void removePreferenceChangeListener(
+        PreferenceChangeListener pcl);
+
+    /**
+     * Registers the specified listener to receive <i>node change events</i>
+     * for this node.  A node change event is generated when a child node is
+     * added to or removed from this node.  (A single {@link #removeNode()}
+     * invocation results in multiple <i>node change events</i>, one for every
+     * node in the subtree rooted at the removed node.)
+     *
+     * <p>Events are only guaranteed for changes made within the same JVM
+     * as the registered listener, though some implementations may generate
+     * events for changes made outside this JVM.  Events may be generated
+     * before the changes have become permanent.  Events are not generated
+     * when indirect descendants of this node are added or removed; a
+     * caller desiring such events must register with each descendant.
+     *
+     * <p>Few guarantees can be made regarding node creation.  Because nodes
+     * are created implicitly upon access, it may not be feasible for an
+     * implementation to determine whether a child node existed in the backing
+     * store prior to access (for example, because the backing store is
+     * unreachable or cached information is out of date).  Under these
+     * circumstances, implementations are neither required to generate node
+     * change events nor prohibited from doing so.
+     *
+     * @param ncl The <tt>NodeChangeListener</tt> to add.
+     * @throws NullPointerException if <tt>ncl</tt> is null.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #removeNodeChangeListener(NodeChangeListener)
+     * @see #addPreferenceChangeListener(PreferenceChangeListener)
+     */
+    public abstract void addNodeChangeListener(NodeChangeListener ncl);
+
+    /**
+     * Removes the specified <tt>NodeChangeListener</tt>, so it no longer
+     * receives change events.
+     *
+     * @param ncl The <tt>NodeChangeListener</tt> to remove.
+     * @throws IllegalArgumentException if <tt>ncl</tt> was not a registered
+     *         <tt>NodeChangeListener</tt> on this node.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see #addNodeChangeListener(NodeChangeListener)
+     */
+    public abstract void removeNodeChangeListener(NodeChangeListener ncl);
+
+    /**
+     * Emits on the specified output stream an XML document representing all
+     * of the preferences contained in this node (but not its descendants).
+     * This XML document is, in effect, an offline backup of the node.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * The UTF-8 character encoding will be used.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  If the preferences
+     * at this node are modified concurrently with an invocation of this
+     * method, the exported preferences comprise a "fuzzy snapshot" of the
+     * preferences contained in the node; some of the concurrent modifications
+     * may be reflected in the exported data while others may not.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @see    #importPreferences(InputStream)
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     */
+    public abstract void exportNode(OutputStream os)
+        throws IOException, BackingStoreException;
+
+    /**
+     * Emits an XML document representing all of the preferences contained
+     * in this node and all of its descendants.  This XML document is, in
+     * effect, an offline backup of the subtree rooted at the node.
+     *
+     * <p>The XML document will have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * The UTF-8 character encoding will be used.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  If the preferences
+     * or nodes in the subtree rooted at this node are modified concurrently
+     * with an invocation of this method, the exported preferences comprise a
+     * "fuzzy snapshot" of the subtree; some of the concurrent modifications
+     * may be reflected in the exported data while others may not.
+     *
+     * @param os the output stream on which to emit the XML document.
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link #removeNode()} method.
+     * @see    #importPreferences(InputStream)
+     * @see    #exportNode(OutputStream)
+     */
+    public abstract void exportSubtree(OutputStream os)
+        throws IOException, BackingStoreException;
+
+    /**
+     * Imports all of the preferences represented by the XML document on the
+     * specified input stream.  The document may represent user preferences or
+     * system preferences.  If it represents user preferences, the preferences
+     * will be imported into the calling user's preference tree (even if they
+     * originally came from a different user's preference tree).  If any of
+     * the preferences described by the document inhabit preference nodes that
+     * do not exist, the nodes will be created.
+     *
+     * <p>The XML document must have the following DOCTYPE declaration:
+     * <pre>{@code
+     * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
+     * }</pre>
+     * (This method is designed for use in conjunction with
+     * {@link #exportNode(OutputStream)} and
+     * {@link #exportSubtree(OutputStream)}.
+     *
+     * <p>This method is an exception to the general rule that the results of
+     * concurrently executing multiple methods in this class yields
+     * results equivalent to some serial execution.  The method behaves
+     * as if implemented on top of the other public methods in this class,
+     * notably {@link #node(String)} and {@link #put(String, String)}.
+     *
+     * @param is the input stream from which to read the XML document.
+     * @throws IOException if reading from the specified input stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     * @throws SecurityException If a security manager is present and
+     *         it denies <tt>RuntimePermission("preferences")</tt>.
+     * @see    RuntimePermission
+     */
+    public static void importPreferences(InputStream is)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        XmlSupport.importPreferences(is);
+    }
+}
diff --git a/java/util/prefs/PreferencesFactory.java b/java/util/prefs/PreferencesFactory.java
new file mode 100644
index 0000000..d7341e6
--- /dev/null
+++ b/java/util/prefs/PreferencesFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+import java.util.*;
+
+/**
+ * A factory object that generates Preferences objects.  Providers of
+ * new {@link Preferences} implementations should provide corresponding
+ * <tt>PreferencesFactory</tt> implementations so that the new
+ * <tt>Preferences</tt> implementation can be installed in place of the
+ * platform-specific default implementation.
+ *
+ * <p><strong>This class is for <tt>Preferences</tt> implementers only.
+ * Normal users of the <tt>Preferences</tt> facility should have no need to
+ * consult this documentation.</strong>
+ *
+ * @author  Josh Bloch
+ * @see     Preferences
+ * @since   1.4
+ */
+public interface PreferencesFactory {
+    /**
+     * Returns the system root preference node.  (Multiple calls on this
+     * method will return the same object reference.)
+     * @return the system root preference node
+     */
+    Preferences systemRoot();
+
+    /**
+     * Returns the user root preference node corresponding to the calling
+     * user.  In a server, the returned value will typically depend on
+     * some implicit client-context.
+     * @return the user root preference node corresponding to the calling
+     * user
+     */
+    Preferences userRoot();
+}
diff --git a/java/util/prefs/XmlSupport.java b/java/util/prefs/XmlSupport.java
new file mode 100644
index 0000000..a90ff19
--- /dev/null
+++ b/java/util/prefs/XmlSupport.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.prefs;
+
+import java.util.*;
+import java.io.*;
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+import org.xml.sax.*;
+import org.w3c.dom.*;
+
+/**
+ * XML Support for java.util.prefs. Methods to import and export preference
+ * nodes and subtrees.
+ *
+ * @author  Josh Bloch and Mark Reinhold
+ * @see     Preferences
+ * @since   1.4
+ */
+class XmlSupport {
+    // The required DTD URI for exported preferences
+    private static final String PREFS_DTD_URI =
+        "http://java.sun.com/dtd/preferences.dtd";
+
+    // The actual DTD corresponding to the URI
+    private static final String PREFS_DTD =
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+
+        "<!-- DTD for preferences -->"               +
+
+        "<!ELEMENT preferences (root) >"             +
+        "<!ATTLIST preferences"                      +
+        " EXTERNAL_XML_VERSION CDATA \"0.0\"  >"     +
+
+        "<!ELEMENT root (map, node*) >"              +
+        "<!ATTLIST root"                             +
+        "          type (system|user) #REQUIRED >"   +
+
+        "<!ELEMENT node (map, node*) >"              +
+        "<!ATTLIST node"                             +
+        "          name CDATA #REQUIRED >"           +
+
+        "<!ELEMENT map (entry*) >"                   +
+        "<!ATTLIST map"                              +
+        "  MAP_XML_VERSION CDATA \"0.0\"  >"         +
+        "<!ELEMENT entry EMPTY >"                    +
+        "<!ATTLIST entry"                            +
+        "          key CDATA #REQUIRED"              +
+        "          value CDATA #REQUIRED >"          ;
+    /**
+     * Version number for the format exported preferences files.
+     */
+    private static final String EXTERNAL_XML_VERSION = "1.0";
+
+    /*
+     * Version number for the internal map files.
+     */
+    private static final String MAP_XML_VERSION = "1.0";
+
+    /**
+     * Export the specified preferences node and, if subTree is true, all
+     * subnodes, to the specified output stream.  Preferences are exported as
+     * an XML document conforming to the definition in the Preferences spec.
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws BackingStoreException if preference data cannot be read from
+     *         backing store.
+     * @throws IllegalStateException if this node (or an ancestor) has been
+     *         removed with the {@link Preferences#removeNode()} method.
+     */
+    static void export(OutputStream os, final Preferences p, boolean subTree)
+        throws IOException, BackingStoreException {
+        if (((AbstractPreferences)p).isRemoved())
+            throw new IllegalStateException("Node has been removed");
+        Document doc = createPrefsDoc("preferences");
+        Element preferences =  doc.getDocumentElement() ;
+        preferences.setAttribute("EXTERNAL_XML_VERSION", EXTERNAL_XML_VERSION);
+        Element xmlRoot =  (Element)
+        preferences.appendChild(doc.createElement("root"));
+        xmlRoot.setAttribute("type", (p.isUserNode() ? "user" : "system"));
+
+        // Get bottom-up list of nodes from p to root, excluding root
+        List<Preferences> ancestors = new ArrayList<>();
+
+        for (Preferences kid = p, dad = kid.parent(); dad != null;
+                                   kid = dad, dad = kid.parent()) {
+            ancestors.add(kid);
+        }
+        Element e = xmlRoot;
+        for (int i=ancestors.size()-1; i >= 0; i--) {
+            e.appendChild(doc.createElement("map"));
+            e = (Element) e.appendChild(doc.createElement("node"));
+            e.setAttribute("name", ancestors.get(i).name());
+        }
+        putPreferencesInXml(e, doc, p, subTree);
+
+        writeDoc(doc, os);
+    }
+
+    /**
+     * Put the preferences in the specified Preferences node into the
+     * specified XML element which is assumed to represent a node
+     * in the specified XML document which is assumed to conform to
+     * PREFS_DTD.  If subTree is true, create children of the specified
+     * XML node conforming to all of the children of the specified
+     * Preferences node and recurse.
+     *
+     * @throws BackingStoreException if it is not possible to read
+     *         the preferences or children out of the specified
+     *         preferences node.
+     */
+    private static void putPreferencesInXml(Element elt, Document doc,
+               Preferences prefs, boolean subTree) throws BackingStoreException
+    {
+        Preferences[] kidsCopy = null;
+        String[] kidNames = null;
+
+        // Node is locked to export its contents and get a
+        // copy of children, then lock is released,
+        // and, if subTree = true, recursive calls are made on children
+        synchronized (((AbstractPreferences)prefs).lock) {
+            // Check if this node was concurrently removed. If yes
+            // remove it from XML Document and return.
+            if (((AbstractPreferences)prefs).isRemoved()) {
+                elt.getParentNode().removeChild(elt);
+                return;
+            }
+            // Put map in xml element
+            String[] keys = prefs.keys();
+            Element map = (Element) elt.appendChild(doc.createElement("map"));
+            for (int i=0; i<keys.length; i++) {
+                Element entry = (Element)
+                    map.appendChild(doc.createElement("entry"));
+                entry.setAttribute("key", keys[i]);
+                // NEXT STATEMENT THROWS NULL PTR EXC INSTEAD OF ASSERT FAIL
+                entry.setAttribute("value", prefs.get(keys[i], null));
+            }
+            // Recurse if appropriate
+            if (subTree) {
+                /* Get a copy of kids while lock is held */
+                kidNames = prefs.childrenNames();
+                kidsCopy = new Preferences[kidNames.length];
+                for (int i = 0; i <  kidNames.length; i++)
+                    kidsCopy[i] = prefs.node(kidNames[i]);
+            }
+            // release lock
+        }
+
+        if (subTree) {
+            for (int i=0; i < kidNames.length; i++) {
+                Element xmlKid = (Element)
+                    elt.appendChild(doc.createElement("node"));
+                xmlKid.setAttribute("name", kidNames[i]);
+                putPreferencesInXml(xmlKid, doc, kidsCopy[i], subTree);
+            }
+        }
+    }
+
+    /**
+     * Import preferences from the specified input stream, which is assumed
+     * to contain an XML document in the format described in the Preferences
+     * spec.
+     *
+     * @throws IOException if reading from the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     */
+    static void importPreferences(InputStream is)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        try {
+            Document doc = loadPrefsDoc(is);
+            String xmlVersion =
+                doc.getDocumentElement().getAttribute("EXTERNAL_XML_VERSION");
+            if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0)
+                throw new InvalidPreferencesFormatException(
+                "Exported preferences file format version " + xmlVersion +
+                " is not supported. This java installation can read" +
+                " versions " + EXTERNAL_XML_VERSION + " or older. You may need" +
+                " to install a newer version of JDK.");
+
+            // BEGIN Android-changed: Filter out non-Element nodes.
+            // Use a selector to skip over CDATA / DATA elements.
+            // The selector is specific to children with tag name "root";
+            // export() always creates exactly one such child.
+            // Element xmlRoot = (Element) doc.getDocumentElement().
+            //                                    getChildNodes().item(0);
+            Element xmlRoot = (Element) doc.getDocumentElement();
+
+            NodeList elements = xmlRoot.getElementsByTagName("root");
+            if (elements == null || elements.getLength() != 1) {
+                throw new InvalidPreferencesFormatException("invalid root node");
+            }
+
+            xmlRoot = (Element) elements.item(0);
+            // END Android-changed: Filter out non-Element nodes.
+            Preferences prefsRoot =
+                (xmlRoot.getAttribute("type").equals("user") ?
+                            Preferences.userRoot() : Preferences.systemRoot());
+            ImportSubtree(prefsRoot, xmlRoot);
+        } catch(SAXException e) {
+            throw new InvalidPreferencesFormatException(e);
+        }
+    }
+
+    /**
+     * Create a new prefs XML document.
+     */
+    private static Document createPrefsDoc( String qname ) {
+        try {
+            DOMImplementation di = DocumentBuilderFactory.newInstance().
+                newDocumentBuilder().getDOMImplementation();
+            DocumentType dt = di.createDocumentType(qname, null, PREFS_DTD_URI);
+            return di.createDocument(null, qname, dt);
+        } catch(ParserConfigurationException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Load an XML document from specified input stream, which must
+     * have the requisite DTD URI.
+     */
+    private static Document loadPrefsDoc(InputStream in)
+        throws SAXException, IOException
+    {
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setIgnoringElementContentWhitespace(true);
+        // Android-changed: No validating builder implementation.
+        // dbf.setValidating(true);
+        dbf.setCoalescing(true);
+        dbf.setIgnoringComments(true);
+        try {
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            db.setEntityResolver(new Resolver());
+            db.setErrorHandler(new EH());
+            return db.parse(new InputSource(in));
+        } catch (ParserConfigurationException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    /**
+     * Write XML document to the specified output stream.
+     */
+    private static final void writeDoc(Document doc, OutputStream out)
+        throws IOException
+    {
+        try {
+            TransformerFactory tf = TransformerFactory.newInstance();
+            try {
+                tf.setAttribute("indent-number", new Integer(2));
+            } catch (IllegalArgumentException iae) {
+                //Ignore the IAE. Should not fail the writeout even the
+                //transformer provider does not support "indent-number".
+            }
+            Transformer t = tf.newTransformer();
+            t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId());
+            t.setOutputProperty(OutputKeys.INDENT, "yes");
+            //Transformer resets the "indent" info if the "result" is a StreamResult with
+            //an OutputStream object embedded, creating a Writer object on top of that
+            //OutputStream object however works.
+            t.transform(new DOMSource(doc),
+                        new StreamResult(new BufferedWriter(new OutputStreamWriter(out, "UTF-8"))));
+        } catch(TransformerException e) {
+            throw new AssertionError(e);
+        }
+    }
+
+    // BEGIN Android-added: Filter out non-Element nodes.
+    static class NodeListAdapter implements NodeList {
+        private final List<? extends Node> delegate;
+
+        public NodeListAdapter(List<? extends Node> delegate) {
+            this.delegate = Objects.requireNonNull(delegate);
+        }
+
+        @Override public Node item(int index) {
+            if (index < 0 || index >= delegate.size()) {
+                return null;
+            }
+            return delegate.get(index);
+        }
+        @Override public int getLength() { return delegate.size(); }
+    }
+
+    private static NodeList elementNodesOf(NodeList xmlKids) {
+        List<Element> elements = new ArrayList<>(xmlKids.getLength());
+        for (int i = 0; i < xmlKids.getLength(); ++i) {
+            Node node = xmlKids.item(i);
+            if (node instanceof Element) {
+                elements.add((Element) node);
+            }
+        }
+        return new NodeListAdapter(elements);
+    }
+    // END Android-added: Filter out non-Element nodes.
+
+    /**
+     * Recursively traverse the specified preferences node and store
+     * the described preferences into the system or current user
+     * preferences tree, as appropriate.
+     */
+    private static void ImportSubtree(Preferences prefsNode, Element xmlNode) {
+        NodeList xmlKids = xmlNode.getChildNodes();
+        // Android-added: Filter out non-Element nodes.
+        xmlKids = elementNodesOf(xmlKids);
+        int numXmlKids = xmlKids.getLength();
+        /*
+         * We first lock the node, import its contents and get
+         * child nodes. Then we unlock the node and go to children
+         * Since some of the children might have been concurrently
+         * deleted we check for this.
+         */
+        Preferences[] prefsKids;
+        /* Lock the node */
+        synchronized (((AbstractPreferences)prefsNode).lock) {
+            //If removed, return silently
+            if (((AbstractPreferences)prefsNode).isRemoved())
+                return;
+
+            // Import any preferences at this node
+            Element firstXmlKid = (Element) xmlKids.item(0);
+            ImportPrefs(prefsNode, firstXmlKid);
+            prefsKids = new Preferences[numXmlKids - 1];
+
+            // Get involved children
+            for (int i=1; i < numXmlKids; i++) {
+                Element xmlKid = (Element) xmlKids.item(i);
+                prefsKids[i-1] = prefsNode.node(xmlKid.getAttribute("name"));
+            }
+        } // unlocked the node
+        // import children
+        for (int i=1; i < numXmlKids; i++)
+            ImportSubtree(prefsKids[i-1], (Element)xmlKids.item(i));
+    }
+
+    /**
+     * Import the preferences described by the specified XML element
+     * (a map from a preferences document) into the specified
+     * preferences node.
+     */
+    private static void ImportPrefs(Preferences prefsNode, Element map) {
+        NodeList entries = map.getChildNodes();
+        // Android-added: Filter out non-Element nodes.
+        entries = elementNodesOf(entries);
+        for (int i=0, numEntries = entries.getLength(); i < numEntries; i++) {
+            Element entry = (Element) entries.item(i);
+            prefsNode.put(entry.getAttribute("key"),
+                          entry.getAttribute("value"));
+        }
+    }
+
+    /**
+     * Export the specified Map<String,String> to a map document on
+     * the specified OutputStream as per the prefs DTD.  This is used
+     * as the internal (undocumented) format for FileSystemPrefs.
+     *
+     * @throws IOException if writing to the specified output stream
+     *         results in an <tt>IOException</tt>.
+     */
+    static void exportMap(OutputStream os, Map<String, String> map) throws IOException {
+        Document doc = createPrefsDoc("map");
+        Element xmlMap = doc.getDocumentElement( ) ;
+        xmlMap.setAttribute("MAP_XML_VERSION", MAP_XML_VERSION);
+
+        for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext(); ) {
+            Map.Entry<String, String> e = i.next();
+            Element xe = (Element)
+                xmlMap.appendChild(doc.createElement("entry"));
+            xe.setAttribute("key",   e.getKey());
+            xe.setAttribute("value", e.getValue());
+        }
+
+        writeDoc(doc, os);
+    }
+
+    /**
+     * Import Map from the specified input stream, which is assumed
+     * to contain a map document as per the prefs DTD.  This is used
+     * as the internal (undocumented) format for FileSystemPrefs.  The
+     * key-value pairs specified in the XML document will be put into
+     * the specified Map.  (If this Map is empty, it will contain exactly
+     * the key-value pairs int the XML-document when this method returns.)
+     *
+     * @throws IOException if reading from the specified output stream
+     *         results in an <tt>IOException</tt>.
+     * @throws InvalidPreferencesFormatException Data on input stream does not
+     *         constitute a valid XML document with the mandated document type.
+     */
+    static void importMap(InputStream is, Map<String, String> m)
+        throws IOException, InvalidPreferencesFormatException
+    {
+        try {
+            Document doc = loadPrefsDoc(is);
+            Element xmlMap = doc.getDocumentElement();
+            // check version
+            String mapVersion = xmlMap.getAttribute("MAP_XML_VERSION");
+            if (mapVersion.compareTo(MAP_XML_VERSION) > 0)
+                throw new InvalidPreferencesFormatException(
+                "Preferences map file format version " + mapVersion +
+                " is not supported. This java installation can read" +
+                " versions " + MAP_XML_VERSION + " or older. You may need" +
+                " to install a newer version of JDK.");
+
+            NodeList entries = xmlMap.getChildNodes();
+            for (int i=0, numEntries=entries.getLength(); i<numEntries; i++) {
+                // BEGIN Android-added: Filter out non-Element nodes.
+                // Android xml serializer generates one-char Text nodes with a single
+                // new-line character between expected Element nodes. OpenJDK code wasn't
+                // expecting anything else than Element nodes.
+                if (!(entries.item(i) instanceof Element)) {
+                    continue;
+                }
+                // END Android-added: Filter out non-Element nodes.
+                Element entry = (Element) entries.item(i);
+                m.put(entry.getAttribute("key"), entry.getAttribute("value"));
+            }
+        } catch(SAXException e) {
+            throw new InvalidPreferencesFormatException(e);
+        }
+    }
+
+    private static class Resolver implements EntityResolver {
+        public InputSource resolveEntity(String pid, String sid)
+            throws SAXException
+        {
+            if (sid.equals(PREFS_DTD_URI)) {
+                InputSource is;
+                is = new InputSource(new StringReader(PREFS_DTD));
+                is.setSystemId(PREFS_DTD_URI);
+                return is;
+            }
+            throw new SAXException("Invalid system identifier: " + sid);
+        }
+    }
+
+    private static class EH implements ErrorHandler {
+        public void error(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void fatalError(SAXParseException x) throws SAXException {
+            throw x;
+        }
+        public void warning(SAXParseException x) throws SAXException {
+            throw x;
+        }
+    }
+}
diff --git a/java/util/regex/MatchResult.java b/java/util/regex/MatchResult.java
new file mode 100644
index 0000000..4f42eae
--- /dev/null
+++ b/java/util/regex/MatchResult.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+/**
+ * The result of a match operation.
+ *
+ * <p>This interface contains query methods used to determine the
+ * results of a match against a regular expression. The match boundaries,
+ * groups and group boundaries can be seen but not modified through
+ * a <code>MatchResult</code>.
+ *
+ * @author  Michael McCloskey
+ * @see Matcher
+ * @since 1.5
+ */
+public interface MatchResult {
+
+    /**
+     * Returns the start index of the match.
+     *
+     * @return  The index of the first character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int start();
+
+    /**
+     * Returns the start index of the subsequence captured by the given group
+     * during this match.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
+     * <i>m.</i><tt>start()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or <tt>-1</tt> if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int start(int group);
+
+    /**
+     * Returns the offset after the last character matched.
+     *
+     * @return  The offset after the last character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int end();
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given group during this match.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
+     * <i>m.</i><tt>end()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or <tt>-1</tt> if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int end(int group);
+
+    /**
+     * Returns the input subsequence matched by the previous match.
+     *
+     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
+     * the expressions <i>m.</i><tt>group()</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt>&nbsp;<i>m.</i><tt>end())</tt>
+     * are equivalent.  </p>
+     *
+     * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
+     * string.  This method will return the empty string when the pattern
+     * successfully matches the empty string in the input.  </p>
+     *
+     * @return The (possibly empty) subsequence matched by the previous match,
+     *         in string form
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public String group();
+
+    /**
+     * Returns the input subsequence captured by the given group during the
+     * previous match operation.
+     *
+     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
+     * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt>&nbsp;<i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
+     * are equivalent.  </p>
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
+     * </p>
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then <tt>null</tt> is returned. Note
+     * that some groups, for example <tt>(a*)</tt>, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the group
+     *          during the previous match, or <tt>null</tt> if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public String group(int group);
+
+    /**
+     * Returns the number of capturing groups in this match result's pattern.
+     *
+     * <p> Group zero denotes the entire pattern by convention. It is not
+     * included in this count.
+     *
+     * <p> Any non-negative integer smaller than or equal to the value
+     * returned by this method is guaranteed to be a valid group index for
+     * this matcher.  </p>
+     *
+     * @return The number of capturing groups in this matcher's pattern
+     */
+    public int groupCount();
+
+}
diff --git a/java/util/regex/Matcher.annotated.java b/java/util/regex/Matcher.annotated.java
new file mode 100644
index 0000000..1bc7c89
--- /dev/null
+++ b/java/util/regex/Matcher.annotated.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.regex;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Matcher implements java.util.regex.MatchResult {
+
+Matcher(@libcore.util.NonNull java.util.regex.Pattern parent, @libcore.util.NonNull java.lang.CharSequence text) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Pattern pattern() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.MatchResult toMatchResult() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher usePattern(@libcore.util.NonNull java.util.regex.Pattern newPattern) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher reset() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher reset(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public int start() { throw new RuntimeException("Stub!"); }
+
+public int start(int group) { throw new RuntimeException("Stub!"); }
+
+public int start(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public int end() { throw new RuntimeException("Stub!"); }
+
+public int end(int group) { throw new RuntimeException("Stub!"); }
+
+public int end(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String group() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String group(int group) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String group(@libcore.util.NonNull java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public int groupCount() { throw new RuntimeException("Stub!"); }
+
+public boolean matches() { throw new RuntimeException("Stub!"); }
+
+public boolean find() { throw new RuntimeException("Stub!"); }
+
+public boolean find(int start) { throw new RuntimeException("Stub!"); }
+
+public boolean lookingAt() { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String quoteReplacement(@libcore.util.NonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher appendReplacement(@libcore.util.NonNull java.lang.StringBuffer sb, @libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.StringBuffer appendTail(@libcore.util.NonNull java.lang.StringBuffer sb) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replaceAll(@libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String replaceFirst(@libcore.util.NonNull java.lang.String replacement) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher region(int start, int end) { throw new RuntimeException("Stub!"); }
+
+public int regionStart() { throw new RuntimeException("Stub!"); }
+
+public int regionEnd() { throw new RuntimeException("Stub!"); }
+
+public boolean hasTransparentBounds() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher useTransparentBounds(boolean b) { throw new RuntimeException("Stub!"); }
+
+public boolean hasAnchoringBounds() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher useAnchoringBounds(boolean b) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public boolean hitEnd() { throw new RuntimeException("Stub!"); }
+
+public boolean requireEnd() { throw new RuntimeException("Stub!"); }
+}
diff --git a/java/util/regex/Matcher.java b/java/util/regex/Matcher.java
new file mode 100644
index 0000000..d50ea32
--- /dev/null
+++ b/java/util/regex/Matcher.java
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import com.android.icu.util.regex.MatcherNative;
+
+/**
+ * An engine that performs match operations on a {@linkplain java.lang.CharSequence
+ * character sequence} by interpreting a {@link Pattern}.
+ *
+ * <p> A matcher is created from a pattern by invoking the pattern's {@link
+ * Pattern#matcher matcher} method.  Once created, a matcher can be used to
+ * perform three different kinds of match operations:
+ *
+ * <ul>
+ *
+ *   <li><p> The {@link #matches matches} method attempts to match the entire
+ *   input sequence against the pattern.  </p></li>
+ *
+ *   <li><p> The {@link #lookingAt lookingAt} method attempts to match the
+ *   input sequence, starting at the beginning, against the pattern.  </p></li>
+ *
+ *   <li><p> The {@link #find find} method scans the input sequence looking for
+ *   the next subsequence that matches the pattern.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Each of these methods returns a boolean indicating success or failure.
+ * More information about a successful match can be obtained by querying the
+ * state of the matcher.
+ *
+ * <p> A matcher finds matches in a subset of its input called the
+ * <i>region</i>. By default, the region contains all of the matcher's input.
+ * The region can be modified via the{@link #region region} method and queried
+ * via the {@link #regionStart regionStart} and {@link #regionEnd regionEnd}
+ * methods. The way that the region boundaries interact with some pattern
+ * constructs can be changed. See {@link #useAnchoringBounds
+ * useAnchoringBounds} and {@link #useTransparentBounds useTransparentBounds}
+ * for more details.
+ *
+ * <p> This class also defines methods for replacing matched subsequences with
+ * new strings whose contents can, if desired, be computed from the match
+ * result.  The {@link #appendReplacement appendReplacement} and {@link
+ * #appendTail appendTail} methods can be used in tandem in order to collect
+ * the result into an existing string buffer, or the more convenient {@link
+ * #replaceAll replaceAll} method can be used to create a string in which every
+ * matching subsequence in the input sequence is replaced.
+ *
+ * <p> The explicit state of a matcher includes the start and end indices of
+ * the most recent successful match.  It also includes the start and end
+ * indices of the input subsequence captured by each <a
+ * href="Pattern.html#cg">capturing group</a> in the pattern as well as a total
+ * count of such subsequences.  As a convenience, methods are also provided for
+ * returning these captured subsequences in string form.
+ *
+ * <p> The explicit state of a matcher is initially undefined; attempting to
+ * query any part of it before a successful match will cause an {@link
+ * IllegalStateException} to be thrown.  The explicit state of a matcher is
+ * recomputed by every match operation.
+ *
+ * <p> The implicit state of a matcher includes the input character sequence as
+ * well as the <i>append position</i>, which is initially zero and is updated
+ * by the {@link #appendReplacement appendReplacement} method.
+ *
+ * <p> A matcher may be reset explicitly by invoking its {@link #reset()}
+ * method or, if a new input sequence is desired, its {@link
+ * #reset(java.lang.CharSequence) reset(CharSequence)} method.  Resetting a
+ * matcher discards its explicit state information and sets the append position
+ * to zero.
+ *
+ * <p> Instances of this class are not safe for use by multiple concurrent
+ * threads. </p>
+ *
+ *
+ * @author      Mike McCloskey
+ * @author      Mark Reinhold
+ * @author      JSR-51 Expert Group
+ * @since       1.4
+ * @spec        JSR-51
+ */
+
+public final class Matcher implements MatchResult {
+
+    /**
+     * The Pattern object that created this Matcher.
+     */
+    private Pattern parentPattern;
+
+    /**
+     * Holds the offsets for the most recent match.
+     */
+    int[] groups;
+
+    /**
+     * The range within the sequence that is to be matched (between  0
+     * and text.length()).
+     */
+    int from, to;
+
+    /**
+     * Holds the input text.
+     */
+    String text;
+
+    /**
+     * Reflects whether a match has been found during the most recent find
+     * operation.
+     */
+    private boolean matchFound;
+
+    private MatcherNative nativeMatcher;
+
+    /**
+     * The index of the last position appended in a substitution.
+     */
+    int appendPos = 0;
+
+    /**
+     * Holds the original CharSequence for use in {@link #reset}. {@link #text} is used during
+     * matching. Note that CharSequence is mutable while String is not, so reset can cause the input
+     * to match to change.
+     */
+    private CharSequence originalInput;
+
+    /**
+     * If transparentBounds is true then the boundaries of this
+     * matcher's region are transparent to lookahead, lookbehind,
+     * and boundary matching constructs that try to see beyond them.
+     */
+    boolean transparentBounds = false;
+
+    /**
+     * If anchoringBounds is true then the boundaries of this
+     * matcher's region match anchors such as ^ and $.
+     */
+    boolean anchoringBounds = true;
+
+    /**
+     * All matchers have the state used by Pattern during a match.
+     */
+    Matcher(Pattern parent, CharSequence text) {
+        usePattern(parent);
+        reset(text);
+    }
+
+    /**
+     * Returns the pattern that is interpreted by this matcher.
+     *
+     * @return  The pattern for which this matcher was created
+     */
+    public Pattern pattern() {
+        return parentPattern;
+    }
+
+    /**
+     * Returns the match state of this matcher as a {@link MatchResult}.
+     * The result is unaffected by subsequent operations performed upon this
+     * matcher.
+     *
+     * @return  a <code>MatchResult</code> with the state of this matcher
+     * @since 1.5
+     */
+    public MatchResult toMatchResult() {
+        ensureMatch();
+        return new OffsetBasedMatchResult(text, groups);
+    }
+
+    /**
+      * Changes the <tt>Pattern</tt> that this <tt>Matcher</tt> uses to
+      * find matches with.
+      *
+      * <p> This method causes this matcher to lose information
+      * about the groups of the last match that occurred. The
+      * matcher's position in the input is maintained and its
+      * last append position is unaffected.</p>
+      *
+      * @param  newPattern
+      *         The new pattern used by this matcher
+      * @return  This matcher
+      * @throws  IllegalArgumentException
+      *          If newPattern is <tt>null</tt>
+      * @since 1.5
+      */
+    public Matcher usePattern(Pattern newPattern) {
+        if (newPattern == null)
+            throw new IllegalArgumentException("Pattern cannot be null");
+
+        synchronized (this) {
+            // may throw
+            nativeMatcher = MatcherNative.create(newPattern.nativePattern);
+        }
+        parentPattern = newPattern;
+
+        if (text != null) {
+            resetForInput();
+        }
+
+        groups = new int[(groupCount() + 1) * 2];
+        matchFound = false;
+        return this;
+    }
+
+    /**
+     * Resets this matcher.
+     *
+     * <p> Resetting a matcher discards all of its explicit state information
+     * and sets its append position to zero. The matcher's region is set to the
+     * default region, which is its entire character sequence. The anchoring
+     * and transparency of this matcher's region boundaries are unaffected.
+     *
+     * @return  This matcher
+     */
+    public Matcher reset() {
+        return reset(originalInput, 0, originalInput.length());
+    }
+
+    /**
+     * Resets this matcher with a new input sequence.
+     *
+     * <p> Resetting a matcher discards all of its explicit state information
+     * and sets its append position to zero.  The matcher's region is set to
+     * the default region, which is its entire character sequence.  The
+     * anchoring and transparency of this matcher's region boundaries are
+     * unaffected.
+     *
+     * @param  input
+     *         The new input character sequence
+     *
+     * @return  This matcher
+     */
+    public Matcher reset(CharSequence input) {
+        return reset(input, 0, input.length());
+    }
+
+    /**
+     * Returns the start index of the previous match.
+     *
+     * @return  The index of the first character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int start() {
+        return start(0);
+    }
+
+    /**
+     * Returns the start index of the subsequence captured by the given group
+     * during the previous match operation.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>start(0)</tt> is equivalent to
+     * <i>m.</i><tt>start()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or <tt>-1</tt> if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int start(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        return groups[group * 2];
+    }
+
+    /**
+     * Returns the start index of the subsequence captured by the given
+     * <a href="Pattern.html#groupname">named-capturing group</a> during the
+     * previous match operation.
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The index of the first character captured by the group,
+     *          or {@code -1} if the match was successful but the group
+     *          itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.8
+     */
+    public int start(String name) {
+        return groups[getMatchedGroupIndex(name) * 2];
+    }
+
+    /**
+     * Returns the offset after the last character matched.
+     *
+     * @return  The offset after the last character matched
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public int end() {
+        return end(0);
+    }
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given group during the previous match operation.
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <i>m.</i><tt>end(0)</tt> is equivalent to
+     * <i>m.</i><tt>end()</tt>.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or <tt>-1</tt> if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public int end(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        return groups[group * 2 + 1];
+    }
+
+    /**
+     * Returns the offset after the last character of the subsequence
+     * captured by the given <a href="Pattern.html#groupname">named-capturing
+     * group</a> during the previous match operation.
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The offset after the last character captured by the group,
+     *          or {@code -1} if the match was successful
+     *          but the group itself did not match anything
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.8
+     */
+    public int end(String name) {
+        return groups[getMatchedGroupIndex(name) * 2 + 1];
+    }
+
+    /**
+     * Returns the input subsequence matched by the previous match.
+     *
+     * <p> For a matcher <i>m</i> with input sequence <i>s</i>,
+     * the expressions <i>m.</i><tt>group()</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(),</tt>&nbsp;<i>m.</i><tt>end())</tt>
+     * are equivalent.  </p>
+     *
+     * <p> Note that some patterns, for example <tt>a*</tt>, match the empty
+     * string.  This method will return the empty string when the pattern
+     * successfully matches the empty string in the input.  </p>
+     *
+     * @return The (possibly empty) subsequence matched by the previous match,
+     *         in string form
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     */
+    public String group() {
+        return group(0);
+    }
+
+    /**
+     * Returns the input subsequence captured by the given group during the
+     * previous match operation.
+     *
+     * <p> For a matcher <i>m</i>, input sequence <i>s</i>, and group index
+     * <i>g</i>, the expressions <i>m.</i><tt>group(</tt><i>g</i><tt>)</tt> and
+     * <i>s.</i><tt>substring(</tt><i>m.</i><tt>start(</tt><i>g</i><tt>),</tt>&nbsp;<i>m.</i><tt>end(</tt><i>g</i><tt>))</tt>
+     * are equivalent.  </p>
+     *
+     * <p> <a href="Pattern.html#cg">Capturing groups</a> are indexed from left
+     * to right, starting at one.  Group zero denotes the entire pattern, so
+     * the expression <tt>m.group(0)</tt> is equivalent to <tt>m.group()</tt>.
+     * </p>
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then <tt>null</tt> is returned. Note
+     * that some groups, for example <tt>(a*)</tt>, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  group
+     *         The index of a capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the group
+     *          during the previous match, or <tt>null</tt> if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If there is no capturing group in the pattern
+     *          with the given index
+     */
+    public String group(int group) {
+        ensureMatch();
+        if (group < 0 || group > groupCount())
+            throw new IndexOutOfBoundsException("No group " + group);
+        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+            return null;
+        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+    }
+
+    /**
+     * Returns the input subsequence captured by the given
+     * <a href="Pattern.html#groupname">named-capturing group</a> during the previous
+     * match operation.
+     *
+     * <p> If the match was successful but the group specified failed to match
+     * any part of the input sequence, then <tt>null</tt> is returned. Note
+     * that some groups, for example <tt>(a*)</tt>, match the empty string.
+     * This method will return the empty string when such a group successfully
+     * matches the empty string in the input.  </p>
+     *
+     * @param  name
+     *         The name of a named-capturing group in this matcher's pattern
+     *
+     * @return  The (possibly empty) subsequence captured by the named group
+     *          during the previous match, or <tt>null</tt> if the group
+     *          failed to match part of the input
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If there is no capturing group in the pattern
+     *          with the given name
+     * @since 1.7
+     */
+    public String group(String name) {
+        int group = getMatchedGroupIndex(name);
+        if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
+            return null;
+        return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
+    }
+
+    /**
+     * Returns the number of capturing groups in this matcher's pattern.
+     *
+     * <p> Group zero denotes the entire pattern by convention. It is not
+     * included in this count.
+     *
+     * <p> Any non-negative integer smaller than or equal to the value
+     * returned by this method is guaranteed to be a valid group index for
+     * this matcher.  </p>
+     *
+     * @return The number of capturing groups in this matcher's pattern
+     */
+    public int groupCount() {
+        synchronized (this) {
+            return nativeMatcher.groupCount();
+        }
+    }
+
+    /**
+     * Attempts to match the entire region against the pattern.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, the entire region sequence
+     *          matches this matcher's pattern
+     */
+    public boolean matches() {
+        synchronized (this) {
+            matchFound = nativeMatcher.matches(groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Attempts to find the next subsequence of the input sequence that matches
+     * the pattern.
+     *
+     * <p> This method starts at the beginning of this matcher's region, or, if
+     * a previous invocation of the method was successful and the matcher has
+     * not since been reset, at the first character not matched by the previous
+     * match.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, a subsequence of the input
+     *          sequence matches this matcher's pattern
+     */
+    public boolean find() {
+        synchronized (this) {
+            matchFound = nativeMatcher.findNext(groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Resets this matcher and then attempts to find the next subsequence of
+     * the input sequence that matches the pattern, starting at the specified
+     * index.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods, and subsequent
+     * invocations of the {@link #find()} method will start at the first
+     * character not matched by this match.  </p>
+     *
+     * @param start the index to start searching for a match
+     * @throws  IndexOutOfBoundsException
+     *          If start is less than zero or if start is greater than the
+     *          length of the input sequence.
+     *
+     * @return  <tt>true</tt> if, and only if, a subsequence of the input
+     *          sequence starting at the given index matches this matcher's
+     *          pattern
+     */
+    public boolean find(int start) {
+        int limit = getTextLength();
+        if ((start < 0) || (start > limit))
+            throw new IndexOutOfBoundsException("Illegal start index");
+        reset();
+        synchronized (this) {
+            matchFound = nativeMatcher.find(start, groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Attempts to match the input sequence, starting at the beginning of the
+     * region, against the pattern.
+     *
+     * <p> Like the {@link #matches matches} method, this method always starts
+     * at the beginning of the region; unlike that method, it does not
+     * require that the entire region be matched.
+     *
+     * <p> If the match succeeds then more information can be obtained via the
+     * <tt>start</tt>, <tt>end</tt>, and <tt>group</tt> methods.  </p>
+     *
+     * @return  <tt>true</tt> if, and only if, a prefix of the input
+     *          sequence matches this matcher's pattern
+     */
+    public boolean lookingAt() {
+        synchronized (this) {
+            matchFound = nativeMatcher.lookingAt(groups);
+        }
+        return matchFound;
+    }
+
+    /**
+     * Returns a literal replacement <code>String</code> for the specified
+     * <code>String</code>.
+     *
+     * This method produces a <code>String</code> that will work
+     * as a literal replacement <code>s</code> in the
+     * <code>appendReplacement</code> method of the {@link Matcher} class.
+     * The <code>String</code> produced will match the sequence of characters
+     * in <code>s</code> treated as a literal sequence. Slashes ('\') and
+     * dollar signs ('$') will be given no special meaning.
+     *
+     * @param  s The string to be literalized
+     * @return  A literal string replacement
+     * @since 1.5
+     */
+    public static String quoteReplacement(String s) {
+        if ((s.indexOf('\\') == -1) && (s.indexOf('$') == -1))
+            return s;
+        StringBuilder sb = new StringBuilder();
+        for (int i=0; i<s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' || c == '$') {
+                sb.append('\\');
+            }
+            sb.append(c);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Implements a non-terminal append-and-replace step.
+     *
+     * <p> This method performs the following actions: </p>
+     *
+     * <ol>
+     *
+     *   <li><p> It reads characters from the input sequence, starting at the
+     *   append position, and appends them to the given string buffer.  It
+     *   stops after reading the last character preceding the previous match,
+     *   that is, the character at index {@link
+     *   #start()}&nbsp;<tt>-</tt>&nbsp;<tt>1</tt>.  </p></li>
+     *
+     *   <li><p> It appends the given replacement string to the string buffer.
+     *   </p></li>
+     *
+     *   <li><p> It sets the append position of this matcher to the index of
+     *   the last character matched, plus one, that is, to {@link #end()}.
+     *   </p></li>
+     *
+     * </ol>
+     *
+     * <p> The replacement string may contain references to subsequences
+     * captured during the previous match: Each occurrence of
+     * <tt>${</tt><i>name</i><tt>}</tt> or <tt>$</tt><i>g</i>
+     * will be replaced by the result of evaluating the corresponding
+     * {@link #group(String) group(name)} or {@link #group(int) group(g)}
+     * respectively. For  <tt>$</tt><i>g</i>,
+     * the first number after the <tt>$</tt> is always treated as part of
+     * the group reference. Subsequent numbers are incorporated into g if
+     * they would form a legal group reference. Only the numerals '0'
+     * through '9' are considered as potential components of the group
+     * reference. If the second group matched the string <tt>"foo"</tt>, for
+     * example, then passing the replacement string <tt>"$2bar"</tt> would
+     * cause <tt>"foobar"</tt> to be appended to the string buffer. A dollar
+     * sign (<tt>$</tt>) may be included as a literal in the replacement
+     * string by preceding it with a backslash (<tt>\$</tt>).
+     *
+     * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> This method is intended to be used in a loop together with the
+     * {@link #appendTail appendTail} and {@link #find find} methods.  The
+     * following code, for example, writes <tt>one dog two dogs in the
+     * yard</tt> to the standard-output stream: </p>
+     *
+     * <blockquote><pre>
+     * Pattern p = Pattern.compile("cat");
+     * Matcher m = p.matcher("one cat two cats in the yard");
+     * StringBuffer sb = new StringBuffer();
+     * while (m.find()) {
+     *     m.appendReplacement(sb, "dog");
+     * }
+     * m.appendTail(sb);
+     * System.out.println(sb.toString());</pre></blockquote>
+     *
+     * @param  sb
+     *         The target string buffer
+     *
+     * @param  replacement
+     *         The replacement string
+     *
+     * @return  This matcher
+     *
+     * @throws  IllegalStateException
+     *          If no match has yet been attempted,
+     *          or if the previous match operation failed
+     *
+     * @throws  IllegalArgumentException
+     *          If the replacement string refers to a named-capturing
+     *          group that does not exist in the pattern
+     *
+     * @throws  IndexOutOfBoundsException
+     *          If the replacement string refers to a capturing group
+     *          that does not exist in the pattern
+     */
+    public Matcher appendReplacement(StringBuffer sb, String replacement) {
+
+        sb.append(text.substring(appendPos, start()));
+        appendEvaluated(sb, replacement);
+        appendPos = end();
+
+        return this;
+    }
+
+    /**
+     * Internal helper method to append a given string to a given string buffer.
+     * If the string contains any references to groups, these are replaced by
+     * the corresponding group's contents.
+     *
+     * @param buffer the string buffer.
+     * @param s the string to append.
+     */
+    private void appendEvaluated(StringBuffer buffer, String s) {
+        boolean escape = false;
+        boolean dollar = false;
+        boolean escapeNamedGroup = false;
+        int escapeNamedGroupStart = -1;
+
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (c == '\\' && !escape) {
+                escape = true;
+            } else if (c == '$' && !escape) {
+                dollar = true;
+            } else if (c >= '0' && c <= '9' && dollar && !escapeNamedGroup) {
+                String groupValue = group(c - '0');
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
+                dollar = false;
+            } else if (c == '{' && dollar) {
+                escapeNamedGroup = true;
+                escapeNamedGroupStart = i;
+            } else if (c == '}' && dollar && escapeNamedGroup) {
+                String groupValue = group(s.substring(escapeNamedGroupStart + 1, i));
+                if (groupValue != null) {
+                    buffer.append(groupValue);
+                }
+                dollar = false;
+                escapeNamedGroup = false;
+            } else if (c != '}' && dollar && escapeNamedGroup) {
+                continue;
+            } else {
+                buffer.append(c);
+                dollar = false;
+                escape = false;
+                escapeNamedGroup = false;
+            }
+        }
+
+        if (escape) {
+            throw new IllegalArgumentException("character to be escaped is missing");
+        }
+
+        if (dollar) {
+            throw new IllegalArgumentException("Illegal group reference: group index is missing");
+        }
+
+        if (escapeNamedGroup) {
+            throw new IllegalArgumentException("Missing ending brace '}' from replacement string");
+        }
+    }
+
+    /**
+     * Implements a terminal append-and-replace step.
+     *
+     * <p> This method reads characters from the input sequence, starting at
+     * the append position, and appends them to the given string buffer.  It is
+     * intended to be invoked after one or more invocations of the {@link
+     * #appendReplacement appendReplacement} method in order to copy the
+     * remainder of the input sequence.  </p>
+     *
+     * @param  sb
+     *         The target string buffer
+     *
+     * @return  The target string buffer
+     */
+    public StringBuffer appendTail(StringBuffer sb) {
+        if (appendPos < to) {
+            sb.append(text.substring(appendPos, to));
+        }
+        return sb;
+    }
+
+    /**
+     * Replaces every subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for matches of the pattern.  Characters that are not
+     * part of any match are appended directly to the result string; each match
+     * is replaced in the result by the replacement string.  The replacement
+     * string may contain references to captured subsequences as in the {@link
+     * #appendReplacement appendReplacement} method.
+     *
+     * <p> Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression <tt>a*b</tt>, the input
+     * <tt>"aabfooaabfooabfoob"</tt>, and the replacement string
+     * <tt>"-"</tt>, an invocation of this method on a matcher for that
+     * expression would yield the string <tt>"-foo-foo-foo-"</tt>.
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * @param  replacement
+     *         The replacement string
+     *
+     * @return  The string constructed by replacing each matching subsequence
+     *          by the replacement string, substituting captured subsequences
+     *          as needed
+     */
+    public String replaceAll(String replacement) {
+        reset();
+        boolean result = find();
+        if (result) {
+            StringBuffer sb = new StringBuffer();
+            do {
+                appendReplacement(sb, replacement);
+                result = find();
+            } while (result);
+            appendTail(sb);
+            return sb.toString();
+        }
+        return text.toString();
+    }
+
+    /**
+     * Replaces the first subsequence of the input sequence that matches the
+     * pattern with the given replacement string.
+     *
+     * <p> This method first resets this matcher.  It then scans the input
+     * sequence looking for a match of the pattern.  Characters that are not
+     * part of the match are appended directly to the result string; the match
+     * is replaced in the result by the replacement string.  The replacement
+     * string may contain references to captured subsequences as in the {@link
+     * #appendReplacement appendReplacement} method.
+     *
+     * <p>Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in
+     * the replacement string may cause the results to be different than if it
+     * were being treated as a literal replacement string. Dollar signs may be
+     * treated as references to captured subsequences as described above, and
+     * backslashes are used to escape literal characters in the replacement
+     * string.
+     *
+     * <p> Given the regular expression <tt>dog</tt>, the input
+     * <tt>"zzzdogzzzdogzzz"</tt>, and the replacement string
+     * <tt>"cat"</tt>, an invocation of this method on a matcher for that
+     * expression would yield the string <tt>"zzzcatzzzdogzzz"</tt>.  </p>
+     *
+     * <p> Invoking this method changes this matcher's state.  If the matcher
+     * is to be used in further matching operations then it should first be
+     * reset.  </p>
+     *
+     * @param  replacement
+     *         The replacement string
+     * @return  The string constructed by replacing the first matching
+     *          subsequence by the replacement string, substituting captured
+     *          subsequences as needed
+     */
+    public String replaceFirst(String replacement) {
+        if (replacement == null)
+            throw new NullPointerException("replacement");
+        reset();
+        if (!find())
+            return text.toString();
+        StringBuffer sb = new StringBuffer();
+        appendReplacement(sb, replacement);
+        appendTail(sb);
+        return sb.toString();
+    }
+
+    /**
+     * Sets the limits of this matcher's region. The region is the part of the
+     * input sequence that will be searched to find a match. Invoking this
+     * method resets the matcher, and then sets the region to start at the
+     * index specified by the <code>start</code> parameter and end at the
+     * index specified by the <code>end</code> parameter.
+     *
+     * <p>Depending on the transparency and anchoring being used (see
+     * {@link #useTransparentBounds useTransparentBounds} and
+     * {@link #useAnchoringBounds useAnchoringBounds}), certain constructs such
+     * as anchors may behave differently at or around the boundaries of the
+     * region.
+     *
+     * @param  start
+     *         The index to start searching at (inclusive)
+     * @param  end
+     *         The index to end searching at (exclusive)
+     * @throws  IndexOutOfBoundsException
+     *          If start or end is less than zero, if
+     *          start is greater than the length of the input sequence, if
+     *          end is greater than the length of the input sequence, or if
+     *          start is greater than end.
+     * @return  this matcher
+     * @since 1.5
+     */
+    public Matcher region(int start, int end) {
+        return reset(originalInput, start, end);
+    }
+
+    /**
+     * Reports the start index of this matcher's region. The
+     * searches this matcher conducts are limited to finding matches
+     * within {@link #regionStart regionStart} (inclusive) and
+     * {@link #regionEnd regionEnd} (exclusive).
+     *
+     * @return  The starting point of this matcher's region
+     * @since 1.5
+     */
+    public int regionStart() {
+        return from;
+    }
+
+    /**
+     * Reports the end index (exclusive) of this matcher's region.
+     * The searches this matcher conducts are limited to finding matches
+     * within {@link #regionStart regionStart} (inclusive) and
+     * {@link #regionEnd regionEnd} (exclusive).
+     *
+     * @return  the ending point of this matcher's region
+     * @since 1.5
+     */
+    public int regionEnd() {
+        return to;
+    }
+
+    /**
+     * Queries the transparency of region bounds for this matcher.
+     *
+     * <p> This method returns <tt>true</tt> if this matcher uses
+     * <i>transparent</i> bounds, <tt>false</tt> if it uses <i>opaque</i>
+     * bounds.
+     *
+     * <p> See {@link #useTransparentBounds useTransparentBounds} for a
+     * description of transparent and opaque bounds.
+     *
+     * <p> By default, a matcher uses opaque region boundaries.
+     *
+     * @return <tt>true</tt> iff this matcher is using transparent bounds,
+     *         <tt>false</tt> otherwise.
+     * @see java.util.regex.Matcher#useTransparentBounds(boolean)
+     * @since 1.5
+     */
+    public boolean hasTransparentBounds() {
+        return transparentBounds;
+    }
+
+    /**
+     * Sets the transparency of region bounds for this matcher.
+     *
+     * <p> Invoking this method with an argument of <tt>true</tt> will set this
+     * matcher to use <i>transparent</i> bounds. If the boolean
+     * argument is <tt>false</tt>, then <i>opaque</i> bounds will be used.
+     *
+     * <p> Using transparent bounds, the boundaries of this
+     * matcher's region are transparent to lookahead, lookbehind,
+     * and boundary matching constructs. Those constructs can see beyond the
+     * boundaries of the region to see if a match is appropriate.
+     *
+     * <p> Using opaque bounds, the boundaries of this matcher's
+     * region are opaque to lookahead, lookbehind, and boundary matching
+     * constructs that may try to see beyond them. Those constructs cannot
+     * look past the boundaries so they will fail to match anything outside
+     * of the region.
+     *
+     * <p> By default, a matcher uses opaque bounds.
+     *
+     * @param  b a boolean indicating whether to use opaque or transparent
+     *         regions
+     * @return this matcher
+     * @see java.util.regex.Matcher#hasTransparentBounds
+     * @since 1.5
+     */
+    public Matcher useTransparentBounds(boolean b) {
+        synchronized (this) {
+            transparentBounds = b;
+            nativeMatcher.useTransparentBounds(b);
+        }
+        return this;
+    }
+
+    /**
+     * Queries the anchoring of region bounds for this matcher.
+     *
+     * <p> This method returns <tt>true</tt> if this matcher uses
+     * <i>anchoring</i> bounds, <tt>false</tt> otherwise.
+     *
+     * <p> See {@link #useAnchoringBounds useAnchoringBounds} for a
+     * description of anchoring bounds.
+     *
+     * <p> By default, a matcher uses anchoring region boundaries.
+     *
+     * @return <tt>true</tt> iff this matcher is using anchoring bounds,
+     *         <tt>false</tt> otherwise.
+     * @see java.util.regex.Matcher#useAnchoringBounds(boolean)
+     * @since 1.5
+     */
+    public boolean hasAnchoringBounds() {
+        return anchoringBounds;
+    }
+
+    /**
+     * Sets the anchoring of region bounds for this matcher.
+     *
+     * <p> Invoking this method with an argument of <tt>true</tt> will set this
+     * matcher to use <i>anchoring</i> bounds. If the boolean
+     * argument is <tt>false</tt>, then <i>non-anchoring</i> bounds will be
+     * used.
+     *
+     * <p> Using anchoring bounds, the boundaries of this
+     * matcher's region match anchors such as ^ and $.
+     *
+     * <p> Without anchoring bounds, the boundaries of this
+     * matcher's region will not match anchors such as ^ and $.
+     *
+     * <p> By default, a matcher uses anchoring region boundaries.
+     *
+     * @param  b a boolean indicating whether or not to use anchoring bounds.
+     * @return this matcher
+     * @see java.util.regex.Matcher#hasAnchoringBounds
+     * @since 1.5
+     */
+    public Matcher useAnchoringBounds(boolean b) {
+        synchronized (this) {
+            anchoringBounds = b;
+            nativeMatcher.useAnchoringBounds(b);
+        }
+        return this;
+    }
+
+    /**
+     * <p>Returns the string representation of this matcher. The
+     * string representation of a <code>Matcher</code> contains information
+     * that may be useful for debugging. The exact format is unspecified.
+     *
+     * @return  The string representation of this matcher
+     * @since 1.5
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("java.util.regex.Matcher");
+        sb.append("[pattern=" + pattern());
+        sb.append(" region=");
+        sb.append(regionStart() + "," + regionEnd());
+        sb.append(" lastmatch=");
+        if (matchFound && (group() != null)) {
+            sb.append(group());
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    /**
+     * <p>Returns true if the end of input was hit by the search engine in
+     * the last match operation performed by this matcher.
+     *
+     * <p>When this method returns true, then it is possible that more input
+     * would have changed the result of the last search.
+     *
+     * @return  true iff the end of input was hit in the last match; false
+     *          otherwise
+     * @since 1.5
+     */
+    public boolean hitEnd() {
+        synchronized (this) {
+            return nativeMatcher.hitEnd();
+        }
+    }
+
+    /**
+     * <p>Returns true if more input could change a positive match into a
+     * negative one.
+     *
+     * <p>If this method returns true, and a match was found, then more
+     * input could cause the match to be lost. If this method returns false
+     * and a match was found, then more input might change the match but the
+     * match won't be lost. If a match was not found, then requireEnd has no
+     * meaning.
+     *
+     * @return  true iff more input could change a positive match into a
+     *          negative one.
+     * @since 1.5
+     */
+    public boolean requireEnd() {
+        synchronized (this) {
+            return nativeMatcher.requireEnd();
+        }
+    }
+
+    /**
+     * Returns the end index of the text.
+     *
+     * @return the index after the last character in the text
+     */
+    int getTextLength() {
+        return text.length();
+    }
+
+    /**
+     * Generates a String from this Matcher's input in the specified range.
+     *
+     * @param  beginIndex   the beginning index, inclusive
+     * @param  endIndex     the ending index, exclusive
+     * @return A String generated from this Matcher's input
+     */
+    CharSequence getSubSequence(int beginIndex, int endIndex) {
+        return text.subSequence(beginIndex, endIndex);
+    }
+
+    /**
+     * Resets the Matcher. A new input sequence and a new region can be
+     * specified. Results of a previous find get lost. The next attempt to find
+     * an occurrence of the Pattern in the string will start at the beginning of
+     * the region. This is the internal version of reset() to which the several
+     * public versions delegate.
+     *
+     * @param input
+     *            the input sequence.
+     * @param start
+     *            the start of the region.
+     * @param end
+     *            the end of the region.
+     *
+     * @return the matcher itself.
+     */
+    private Matcher reset(CharSequence input, int start, int end) {
+        if (input == null) {
+            throw new IllegalArgumentException("input == null");
+        }
+
+        if (start < 0 || end < 0 || start > input.length() || end > input.length() || start > end) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        this.originalInput = input;
+        this.text = input.toString();
+        this.from = start;
+        this.to = end;
+        resetForInput();
+
+        matchFound = false;
+        appendPos = 0;
+
+        return this;
+    }
+
+    private void resetForInput() {
+        synchronized (this) {
+            nativeMatcher.setInput(text, from, to);
+            nativeMatcher.useAnchoringBounds(anchoringBounds);
+            nativeMatcher.useTransparentBounds(transparentBounds);
+        }
+    }
+
+    /**
+     * Makes sure that a successful match has been made. Is invoked internally
+     * from various places in the class.
+     *
+     * @throws IllegalStateException
+     *             if no successful match has been made.
+     */
+    private void ensureMatch() {
+        if (!matchFound) {
+            throw new IllegalStateException("No successful match so far");
+        }
+    }
+
+    private int getMatchedGroupIndex(String name) {
+        ensureMatch();
+        int result = nativeMatcher.getMatchedGroupIndex(name);
+        if (result < 0) {
+            throw new IllegalArgumentException("No capturing group in the pattern " +
+                                               "with the name " + name);
+        }
+        return result;
+    }
+
+    /**
+     * A trivial match result implementation that's based on an array of integers
+     * representing match offsets. The array is of the form
+     * {@code { start1, end1, start2, end2 ....}) where each consecutive pair of elements represents
+     * the start and end of a match respectively.
+     */
+    static final class OffsetBasedMatchResult implements MatchResult {
+        private final String input;
+        private final int[] offsets;
+
+        OffsetBasedMatchResult(String input, int[] offsets) {
+            this.input = input;
+            this.offsets = offsets.clone();
+        }
+
+        @Override
+        public int start() {
+            return start(0);
+        }
+
+        @Override
+        public int start(int group) {
+            return offsets[2 * group];
+        }
+
+        @Override
+        public int end() {
+            return end(0);
+        }
+
+        @Override
+        public int end(int group) {
+            return offsets[2 * group + 1];
+        }
+
+        @Override
+        public String group() {
+            return group(0);
+        }
+
+        @Override
+        public String group(int group) {
+            final int start = start(group);
+            final int end = end(group);
+            if (start == -1 || end == -1) {
+                return null;
+            }
+
+            return input.substring(start, end);
+        }
+
+        @Override
+        public int groupCount() {
+            return (offsets.length / 2) - 1;
+        }
+    }
+}
diff --git a/java/util/regex/Pattern.annotated.java b/java/util/regex/Pattern.annotated.java
new file mode 100644
index 0000000..66db450
--- /dev/null
+++ b/java/util/regex/Pattern.annotated.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.regex;
+
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public final class Pattern implements java.io.Serializable {
+
+Pattern(@libcore.util.NonNull java.lang.String p, int f) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.regex.Pattern compile(@libcore.util.NonNull java.lang.String regex) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.util.regex.Pattern compile(@libcore.util.NonNull java.lang.String regex, int flags) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String pattern() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.regex.Matcher matcher(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public int flags() { throw new RuntimeException("Stub!"); }
+
+public static boolean matches(@libcore.util.NonNull java.lang.String regex, @libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.NonNull [] split(@libcore.util.NonNull java.lang.CharSequence input, int limit) { throw new RuntimeException("Stub!"); }
+
+public [email protected] String @libcore.util.NonNull [] split(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
[email protected] public static java.lang.String quote(@libcore.util.NonNull java.lang.String s) { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.function.Predicate<[email protected] String> asPredicate() { throw new RuntimeException("Stub!"); }
+
[email protected] public java.util.stream.Stream<[email protected] String> splitAsStream(@libcore.util.NonNull java.lang.CharSequence input) { throw new RuntimeException("Stub!"); }
+
+public static final int CANON_EQ = 128; // 0x80
+
+public static final int CASE_INSENSITIVE = 2; // 0x2
+
+public static final int COMMENTS = 4; // 0x4
+
+public static final int DOTALL = 32; // 0x20
+
+public static final int LITERAL = 16; // 0x10
+
+public static final int MULTILINE = 8; // 0x8
+
+public static final int UNICODE_CASE = 64; // 0x40
+
+public static final int UNICODE_CHARACTER_CLASS = 256; // 0x100
+
+public static final int UNIX_LINES = 1; // 0x1
+}
diff --git a/java/util/regex/Pattern.java b/java/util/regex/Pattern.java
new file mode 100644
index 0000000..a4ead58
--- /dev/null
+++ b/java/util/regex/Pattern.java
@@ -0,0 +1,1537 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import com.android.icu.util.regex.PatternNative;
+import dalvik.system.VMRuntime;
+
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import libcore.util.EmptyArray;
+
+// Android-changed: Document that named capturing is only available from API 26.
+// Android-changed: Android always uses unicode character classes.
+// UNICODE_CHARACTER_CLASS has no effect on Android.
+/**
+ * A compiled representation of a regular expression.
+ *
+ * <p> A regular expression, specified as a string, must first be compiled into
+ * an instance of this class.  The resulting pattern can then be used to create
+ * a {@link Matcher} object that can match arbitrary {@linkplain
+ * java.lang.CharSequence character sequences} against the regular
+ * expression.  All of the state involved in performing a match resides in the
+ * matcher, so many matchers can share the same pattern.
+ *
+ * <p> A typical invocation sequence is thus
+ *
+ * <blockquote><pre>
+ * Pattern p = Pattern.{@link #compile compile}("a*b");
+ * Matcher m = p.{@link #matcher matcher}("aaaaab");
+ * boolean b = m.{@link Matcher#matches matches}();</pre></blockquote>
+ *
+ * <p> A {@link #matches matches} method is defined by this class as a
+ * convenience for when a regular expression is used just once.  This method
+ * compiles an expression and matches an input sequence against it in a single
+ * invocation.  The statement
+ *
+ * <blockquote><pre>
+ * boolean b = Pattern.matches("a*b", "aaaaab");</pre></blockquote>
+ *
+ * is equivalent to the three statements above, though for repeated matches it
+ * is less efficient since it does not allow the compiled pattern to be reused.
+ *
+ * <p> Instances of this class are immutable and are safe for use by multiple
+ * concurrent threads.  Instances of the {@link Matcher} class are not safe for
+ * such use.
+ *
+ *
+ * <h3><a name="sum">Summary of regular-expression constructs</a></h3>
+ *
+ * <table border="0" cellpadding="1" cellspacing="0"
+ *  summary="Regular expression constructs, and what they match">
+ *
+ * <tr align="left">
+ * <th align="left" id="construct">Construct</th>
+ * <th align="left" id="matches">Matches</th>
+ * </tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="characters">Characters</th></tr>
+ *
+ * <tr><td valign="top" headers="construct characters"><i>x</i></td>
+ *     <td headers="matches">The character <i>x</i></td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\\</tt></td>
+ *     <td headers="matches">The backslash character</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>n</i></td>
+ *     <td headers="matches">The character with octal value <tt>0</tt><i>n</i>
+ *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>nn</i></td>
+ *     <td headers="matches">The character with octal value <tt>0</tt><i>nn</i>
+ *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\0</tt><i>mnn</i></td>
+ *     <td headers="matches">The character with octal value <tt>0</tt><i>mnn</i>
+ *         (0&nbsp;<tt>&lt;=</tt>&nbsp;<i>m</i>&nbsp;<tt>&lt;=</tt>&nbsp;3,
+ *         0&nbsp;<tt>&lt;=</tt>&nbsp;<i>n</i>&nbsp;<tt>&lt;=</tt>&nbsp;7)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\x</tt><i>hh</i></td>
+ *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>hh</i></td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>&#92;u</tt><i>hhhh</i></td>
+ *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>hhhh</i></td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>&#92;x</tt><i>{h...h}</i></td>
+ *     <td headers="matches">The character with hexadecimal&nbsp;value&nbsp;<tt>0x</tt><i>h...h</i>
+ *         ({@link java.lang.Character#MIN_CODE_POINT Character.MIN_CODE_POINT}
+ *         &nbsp;&lt;=&nbsp;<tt>0x</tt><i>h...h</i>&nbsp;&lt;=&nbsp;
+ *          {@link java.lang.Character#MAX_CODE_POINT Character.MAX_CODE_POINT})</td></tr>
+ * <tr><td valign="top" headers="matches"><tt>\t</tt></td>
+ *     <td headers="matches">The tab character (<tt>'&#92;u0009'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\n</tt></td>
+ *     <td headers="matches">The newline (line feed) character (<tt>'&#92;u000A'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\r</tt></td>
+ *     <td headers="matches">The carriage-return character (<tt>'&#92;u000D'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\f</tt></td>
+ *     <td headers="matches">The form-feed character (<tt>'&#92;u000C'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\a</tt></td>
+ *     <td headers="matches">The alert (bell) character (<tt>'&#92;u0007'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\e</tt></td>
+ *     <td headers="matches">The escape character (<tt>'&#92;u001B'</tt>)</td></tr>
+ * <tr><td valign="top" headers="construct characters"><tt>\c</tt><i>x</i></td>
+ *     <td headers="matches">The control character corresponding to <i>x</i></td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="classes">Character classes</th></tr>
+ *
+ * <tr><td valign="top" headers="construct classes">{@code [abc]}</td>
+ *     <td headers="matches">{@code a}, {@code b}, or {@code c} (simple class)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [^abc]}</td>
+ *     <td headers="matches">Any character except {@code a}, {@code b}, or {@code c} (negation)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-zA-Z]}</td>
+ *     <td headers="matches">{@code a} through {@code z}
+ *         or {@code A} through {@code Z}, inclusive (range)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-d[m-p]]}</td>
+ *     <td headers="matches">{@code a} through {@code d},
+ *      or {@code m} through {@code p}: {@code [a-dm-p]} (union)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-z&&[def]]}</td>
+ *     <td headers="matches">{@code d}, {@code e}, or {@code f} (intersection)</tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-z&&[^bc]]}</td>
+ *     <td headers="matches">{@code a} through {@code z},
+ *         except for {@code b} and {@code c}: {@code [ad-z]} (subtraction)</td></tr>
+ * <tr><td valign="top" headers="construct classes">{@code [a-z&&[^m-p]]}</td>
+ *     <td headers="matches">{@code a} through {@code z},
+ *          and not {@code m} through {@code p}: {@code [a-lq-z]}(subtraction)</td></tr>
+ * <tr><th>&nbsp;</th></tr>
+ *
+ * <tr align="left"><th colspan="2" id="predef">Predefined character classes</th></tr>
+ *
+ * <tr><td valign="top" headers="construct predef"><tt>.</tt></td>
+ *     <td headers="matches">Any character (may or may not match <a href="#lt">line terminators</a>)</td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\d</tt></td>
+ *     <td headers="matches">A digit: <tt>[0-9]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\D</tt></td>
+ *     <td headers="matches">A non-digit: <tt>[^0-9]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\h</tt></td>
+ *     <td headers="matches">A horizontal whitespace character:
+ *     <tt>[ \t\xA0&#92;u1680&#92;u180e&#92;u2000-&#92;u200a&#92;u202f&#92;u205f&#92;u3000]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\H</tt></td>
+ *     <td headers="matches">A non-horizontal whitespace character: <tt>[^\h]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\s</tt></td>
+ *     <td headers="matches">A whitespace character: <tt>[ \t\n\x0B\f\r]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\S</tt></td>
+ *     <td headers="matches">A non-whitespace character: <tt>[^\s]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\v</tt></td>
+ *     <td headers="matches">A vertical whitespace character: <tt>[\n\x0B\f\r\x85&#92;u2028&#92;u2029]</tt>
+ *     </td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\V</tt></td>
+ *     <td headers="matches">A non-vertical whitespace character: <tt>[^\v]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\w</tt></td>
+ *     <td headers="matches">A word character: <tt>[a-zA-Z_0-9]</tt></td></tr>
+ * <tr><td valign="top" headers="construct predef"><tt>\W</tt></td>
+ *     <td headers="matches">A non-word character: <tt>[^\w]</tt></td></tr>
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="posix"><b>POSIX character classes (US-ASCII only)</b></th></tr>
+ *
+ * <tr><td valign="top" headers="construct posix">{@code \p{Lower}}</td>
+ *     <td headers="matches">A lower-case alphabetic character: {@code [a-z]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Upper}}</td>
+ *     <td headers="matches">An upper-case alphabetic character:{@code [A-Z]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{ASCII}}</td>
+ *     <td headers="matches">All ASCII:{@code [\x00-\x7F]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Alpha}}</td>
+ *     <td headers="matches">An alphabetic character:{@code [\p{Lower}\p{Upper}]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Digit}}</td>
+ *     <td headers="matches">A decimal digit: {@code [0-9]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Alnum}}</td>
+ *     <td headers="matches">An alphanumeric character:{@code [\p{Alpha}\p{Digit}]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Punct}}</td>
+ *     <td headers="matches">Punctuation: One of {@code !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~}</td></tr>
+ *     <!-- {@code [\!"#\$%&'\(\)\*\+,\-\./:;\<=\>\?@\[\\\]\^_`\{\|\}~]}
+ *          {@code [\X21-\X2F\X31-\X40\X5B-\X60\X7B-\X7E]} -->
+ * <tr><td valign="top" headers="construct posix">{@code \p{Graph}}</td>
+ *     <td headers="matches">A visible character: {@code [\p{Alnum}\p{Punct}]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Print}}</td>
+ *     <td headers="matches">A printable character: {@code [\p{Graph}\x20]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Blank}}</td>
+ *     <td headers="matches">A space or a tab: {@code [ \t]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Cntrl}}</td>
+ *     <td headers="matches">A control character: {@code [\x00-\x1F\x7F]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{XDigit}}</td>
+ *     <td headers="matches">A hexadecimal digit: {@code [0-9a-fA-F]}</td></tr>
+ * <tr><td valign="top" headers="construct posix">{@code \p{Space}}</td>
+ *     <td headers="matches">A whitespace character: {@code [ \t\n\x0B\f\r]}</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2">java.lang.Character classes (simple <a href="#jcc">java character type</a>)</th></tr>
+ *
+ * <tr><td valign="top"><tt>\p{javaLowerCase}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isLowerCase()</td></tr>
+ * <tr><td valign="top"><tt>\p{javaUpperCase}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isUpperCase()</td></tr>
+ * <tr><td valign="top"><tt>\p{javaWhitespace}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isWhitespace()</td></tr>
+ * <tr><td valign="top"><tt>\p{javaMirrored}</tt></td>
+ *     <td>Equivalent to java.lang.Character.isMirrored()</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="unicode">Classes for Unicode scripts, blocks, categories and binary properties</th></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{IsLatin}}</td>
+ *     <td headers="matches">A Latin&nbsp;script character (<a href="#usc">script</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{InGreek}}</td>
+ *     <td headers="matches">A character in the Greek&nbsp;block (<a href="#ubc">block</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{Lu}}</td>
+ *     <td headers="matches">An uppercase letter (<a href="#ucc">category</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{IsAlphabetic}}</td>
+ *     <td headers="matches">An alphabetic character (<a href="#ubpc">binary property</a>)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \p{Sc}}</td>
+ *     <td headers="matches">A currency symbol</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code \P{InGreek}}</td>
+ *     <td headers="matches">Any character except one in the Greek block (negation)</td></tr>
+ * <tr><td valign="top" headers="construct unicode">{@code [\p{L}&&[^\p{Lu}]]}</td>
+ *     <td headers="matches">Any letter except an uppercase letter (subtraction)</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="bounds">Boundary matchers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct bounds"><tt>^</tt></td>
+ *     <td headers="matches">The beginning of a line</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>$</tt></td>
+ *     <td headers="matches">The end of a line</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\b</tt></td>
+ *     <td headers="matches">A word boundary</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\B</tt></td>
+ *     <td headers="matches">A non-word boundary</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\A</tt></td>
+ *     <td headers="matches">The beginning of the input</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\G</tt></td>
+ *     <td headers="matches">The end of the previous match</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\Z</tt></td>
+ *     <td headers="matches">The end of the input but for the final
+ *         <a href="#lt">terminator</a>, if&nbsp;any</td></tr>
+ * <tr><td valign="top" headers="construct bounds"><tt>\z</tt></td>
+ *     <td headers="matches">The end of the input</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="lineending">Linebreak matcher</th></tr>
+ * <tr><td valign="top" headers="construct lineending"><tt>\R</tt></td>
+ *     <td headers="matches">Any Unicode linebreak sequence, is equivalent to
+ *     <tt>&#92;u000D&#92;u000A|[&#92;u000A&#92;u000B&#92;u000C&#92;u000D&#92;u0085&#92;u2028&#92;u2029]
+ *     </tt></td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="greedy">Greedy quantifiers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>?</tt></td>
+ *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>*</tt></td>
+ *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>+</tt></td>
+ *     <td headers="matches"><i>X</i>, one or more times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>}</tt></td>
+ *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,}</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct greedy"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="reluc">Reluctant quantifiers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>??</tt></td>
+ *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>*?</tt></td>
+ *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>+?</tt></td>
+ *     <td headers="matches"><i>X</i>, one or more times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>}?</tt></td>
+ *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,}?</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct reluc"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}?</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="poss">Possessive quantifiers</th></tr>
+ *
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>?+</tt></td>
+ *     <td headers="matches"><i>X</i>, once or not at all</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>*+</tt></td>
+ *     <td headers="matches"><i>X</i>, zero or more times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>++</tt></td>
+ *     <td headers="matches"><i>X</i>, one or more times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>}+</tt></td>
+ *     <td headers="matches"><i>X</i>, exactly <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,}+</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> times</td></tr>
+ * <tr><td valign="top" headers="construct poss"><i>X</i><tt>{</tt><i>n</i><tt>,</tt><i>m</i><tt>}+</tt></td>
+ *     <td headers="matches"><i>X</i>, at least <i>n</i> but not more than <i>m</i> times</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="logical">Logical operators</th></tr>
+ *
+ * <tr><td valign="top" headers="construct logical"><i>XY</i></td>
+ *     <td headers="matches"><i>X</i> followed by <i>Y</i></td></tr>
+ * <tr><td valign="top" headers="construct logical"><i>X</i><tt>|</tt><i>Y</i></td>
+ *     <td headers="matches">Either <i>X</i> or <i>Y</i></td></tr>
+ * <tr><td valign="top" headers="construct logical"><tt>(</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches">X, as a <a href="#cg">capturing group</a></td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="backref">Back references</th></tr>
+ *
+ * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>n</i></td>
+ *     <td valign="bottom" headers="matches">Whatever the <i>n</i><sup>th</sup>
+ *     <a href="#cg">capturing group</a> matched</td></tr>
+ *
+ * <tr><td valign="bottom" headers="construct backref"><tt>\</tt><i>k</i>&lt;<i>name</i>&gt;</td>
+ *     <td valign="bottom" headers="matches">Whatever the
+ *     <a href="#groupname">named-capturing group</a> "name" matched. Only available for API 26 or above</td></tr>
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="quot">Quotation</th></tr>
+ *
+ * <tr><td valign="top" headers="construct quot"><tt>\</tt></td>
+ *     <td headers="matches">Nothing, but quotes the following character</td></tr>
+ * <tr><td valign="top" headers="construct quot"><tt>\Q</tt></td>
+ *     <td headers="matches">Nothing, but quotes all characters until <tt>\E</tt></td></tr>
+ * <tr><td valign="top" headers="construct quot"><tt>\E</tt></td>
+ *     <td headers="matches">Nothing, but ends quoting started by <tt>\Q</tt></td></tr>
+ *     <!-- Metachars: !$()*+.<>?[\]^{|} -->
+ *
+ * <tr><th>&nbsp;</th></tr>
+ * <tr align="left"><th colspan="2" id="special">Special constructs (named-capturing and non-capturing)</th></tr>
+ *
+ * <tr><td valign="top" headers="construct special"><tt>(?&lt;<a href="#groupname">name</a>&gt;</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, as a named-capturing group. Only available for API 26 or above.</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?:</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, as a non-capturing group</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?idmsuxU-idmsuxU)&nbsp;</tt></td>
+ *     <td headers="matches">Nothing, but turns match flags <a href="#CASE_INSENSITIVE">i</a>
+ * <a href="#UNIX_LINES">d</a> <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a>
+ * <a href="#UNICODE_CASE">u</a> <a href="#COMMENTS">x</a> <a href="#UNICODE_CHARACTER_CLASS">U</a>
+ * on - off</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?idmsux-idmsux:</tt><i>X</i><tt>)</tt>&nbsp;&nbsp;</td>
+ *     <td headers="matches"><i>X</i>, as a <a href="#cg">non-capturing group</a> with the
+ *         given flags <a href="#CASE_INSENSITIVE">i</a> <a href="#UNIX_LINES">d</a>
+ * <a href="#MULTILINE">m</a> <a href="#DOTALL">s</a> <a href="#UNICODE_CASE">u</a >
+ * <a href="#COMMENTS">x</a> on - off</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?=</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width positive lookahead</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?!</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width negative lookahead</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?&lt;=</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width positive lookbehind</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?&lt;!</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, via zero-width negative lookbehind</td></tr>
+ * <tr><td valign="top" headers="construct special"><tt>(?&gt;</tt><i>X</i><tt>)</tt></td>
+ *     <td headers="matches"><i>X</i>, as an independent, non-capturing group</td></tr>
+ *
+ * </table>
+ *
+ * <hr>
+ *
+ *
+ * <h3><a name="bs">Backslashes, escapes, and quoting</a></h3>
+ *
+ * <p> The backslash character (<tt>'\'</tt>) serves to introduce escaped
+ * constructs, as defined in the table above, as well as to quote characters
+ * that otherwise would be interpreted as unescaped constructs.  Thus the
+ * expression <tt>\\</tt> matches a single backslash and <tt>\{</tt> matches a
+ * left brace.
+ *
+ * <p> It is an error to use a backslash prior to any alphabetic character that
+ * does not denote an escaped construct; these are reserved for future
+ * extensions to the regular-expression language.  A backslash may be used
+ * prior to a non-alphabetic character regardless of whether that character is
+ * part of an unescaped construct.
+ *
+ * <p> Backslashes within string literals in Java source code are interpreted
+ * as required by
+ * <cite>The Java&trade; Language Specification</cite>
+ * as either Unicode escapes (section 3.3) or other character escapes (section 3.10.6)
+ * It is therefore necessary to double backslashes in string
+ * literals that represent regular expressions to protect them from
+ * interpretation by the Java bytecode compiler.  The string literal
+ * <tt>"&#92;b"</tt>, for example, matches a single backspace character when
+ * interpreted as a regular expression, while <tt>"&#92;&#92;b"</tt> matches a
+ * word boundary.  The string literal <tt>"&#92;(hello&#92;)"</tt> is illegal
+ * and leads to a compile-time error; in order to match the string
+ * <tt>(hello)</tt> the string literal <tt>"&#92;&#92;(hello&#92;&#92;)"</tt>
+ * must be used.
+ *
+ * <h3><a name="cc">Character Classes</a></h3>
+ *
+ *    <p> Character classes may appear within other character classes, and
+ *    may be composed by the union operator (implicit) and the intersection
+ *    operator (<tt>&amp;&amp;</tt>).
+ *    The union operator denotes a class that contains every character that is
+ *    in at least one of its operand classes.  The intersection operator
+ *    denotes a class that contains every character that is in both of its
+ *    operand classes.
+ *
+ *    <p> The precedence of character-class operators is as follows, from
+ *    highest to lowest:
+ *
+ *    <blockquote><table border="0" cellpadding="1" cellspacing="0"
+ *                 summary="Precedence of character class operators.">
+ *      <tr><th>1&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Literal escape&nbsp;&nbsp;&nbsp;&nbsp;</td>
+ *        <td><tt>\x</tt></td></tr>
+ *     <tr><th>2&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Grouping</td>
+ *        <td><tt>[...]</tt></td></tr>
+ *     <tr><th>3&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Range</td>
+ *        <td><tt>a-z</tt></td></tr>
+ *      <tr><th>4&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Union</td>
+ *        <td><tt>[a-e][i-u]</tt></td></tr>
+ *      <tr><th>5&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *        <td>Intersection</td>
+ *        <td>{@code [a-z&&[aeiou]]}</td></tr>
+ *    </table></blockquote>
+ *
+ *    <p> Note that a different set of metacharacters are in effect inside
+ *    a character class than outside a character class. For instance, the
+ *    regular expression <tt>.</tt> loses its special meaning inside a
+ *    character class, while the expression <tt>-</tt> becomes a range
+ *    forming metacharacter.
+ *
+ * <h3><a name="lt">Line terminators</a></h3>
+ *
+ * <p> A <i>line terminator</i> is a one- or two-character sequence that marks
+ * the end of a line of the input character sequence.  The following are
+ * recognized as line terminators:
+ *
+ * <ul>
+ *
+ *   <li> A newline (line feed) character&nbsp;(<tt>'\n'</tt>),
+ *
+ *   <li> A carriage-return character followed immediately by a newline
+ *   character&nbsp;(<tt>"\r\n"</tt>),
+ *
+ *   <li> A standalone carriage-return character&nbsp;(<tt>'\r'</tt>),
+ *
+ *   <li> A next-line character&nbsp;(<tt>'&#92;u0085'</tt>),
+ *
+ *   <li> A line-separator character&nbsp;(<tt>'&#92;u2028'</tt>), or
+ *
+ *   <li> A paragraph-separator character&nbsp;(<tt>'&#92;u2029</tt>).
+ *
+ * </ul>
+ * <p>If {@link #UNIX_LINES} mode is activated, then the only line terminators
+ * recognized are newline characters.
+ *
+ * <p> The regular expression <tt>.</tt> matches any character except a line
+ * terminator unless the {@link #DOTALL} flag is specified.
+ *
+ * <p> By default, the regular expressions <tt>^</tt> and <tt>$</tt> ignore
+ * line terminators and only match at the beginning and the end, respectively,
+ * of the entire input sequence. If {@link #MULTILINE} mode is activated then
+ * <tt>^</tt> matches at the beginning of input and after any line terminator
+ * except at the end of input. When in {@link #MULTILINE} mode <tt>$</tt>
+ * matches just before a line terminator or the end of the input sequence.
+ *
+ * <h3><a name="cg">Groups and capturing</a></h3>
+ *
+ * <h4><a name="gnumber">Group number</a></h4>
+ * <p> Capturing groups are numbered by counting their opening parentheses from
+ * left to right.  In the expression <tt>((A)(B(C)))</tt>, for example, there
+ * are four such groups: </p>
+ *
+ * <blockquote><table cellpadding=1 cellspacing=0 summary="Capturing group numberings">
+ * <tr><th>1&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>((A)(B(C)))</tt></td></tr>
+ * <tr><th>2&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>(A)</tt></td></tr>
+ * <tr><th>3&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>(B(C))</tt></td></tr>
+ * <tr><th>4&nbsp;&nbsp;&nbsp;&nbsp;</th>
+ *     <td><tt>(C)</tt></td></tr>
+ * </table></blockquote>
+ *
+ * <p> Group zero always stands for the entire expression.
+ *
+ * <p> Capturing groups are so named because, during a match, each subsequence
+ * of the input sequence that matches such a group is saved.  The captured
+ * subsequence may be used later in the expression, via a back reference, and
+ * may also be retrieved from the matcher once the match operation is complete.
+ *
+ * <h4><a name="groupname">Group name</a></h4>
+ * <p>The constructs and APIs are available since API level 26. A capturing group
+ * can also be assigned a "name", a <tt>named-capturing group</tt>,
+ * and then be back-referenced later by the "name". Group names are composed of
+ * the following characters. The first character must be a <tt>letter</tt>.
+ *
+ * <ul>
+ *   <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
+ *        (<tt>'&#92;u0041'</tt>&nbsp;through&nbsp;<tt>'&#92;u005a'</tt>),
+ *   <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
+ *        (<tt>'&#92;u0061'</tt>&nbsp;through&nbsp;<tt>'&#92;u007a'</tt>),
+ *   <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
+ *        (<tt>'&#92;u0030'</tt>&nbsp;through&nbsp;<tt>'&#92;u0039'</tt>),
+ * </ul>
+ *
+ * <p> A <tt>named-capturing group</tt> is still numbered as described in
+ * <a href="#gnumber">Group number</a>.
+ *
+ * <p> The captured input associated with a group is always the subsequence
+ * that the group most recently matched.  If a group is evaluated a second time
+ * because of quantification then its previously-captured value, if any, will
+ * be retained if the second evaluation fails.  Matching the string
+ * <tt>"aba"</tt> against the expression <tt>(a(b)?)+</tt>, for example, leaves
+ * group two set to <tt>"b"</tt>.  All captured input is discarded at the
+ * beginning of each match.
+ *
+ * <p> Groups beginning with <tt>(?</tt> are either pure, <i>non-capturing</i> groups
+ * that do not capture text and do not count towards the group total, or
+ * <i>named-capturing</i> group.
+ *
+ * <h3> Unicode support </h3>
+ *
+ * <p> This class is in conformance with Level 1 of <a
+ * href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
+ * Standard #18: Unicode Regular Expression</i></a>, plus RL2.1
+ * Canonical Equivalents.
+ * <p>
+ * <b>Unicode escape sequences</b> such as <tt>&#92;u2014</tt> in Java source code
+ * are processed as described in section 3.3 of
+ * <cite>The Java&trade; Language Specification</cite>.
+ * Such escape sequences are also implemented directly by the regular-expression
+ * parser so that Unicode escapes can be used in expressions that are read from
+ * files or from the keyboard.  Thus the strings <tt>"&#92;u2014"</tt> and
+ * <tt>"\\u2014"</tt>, while not equal, compile into the same pattern, which
+ * matches the character with hexadecimal value <tt>0x2014</tt>.
+ * <p>
+ * A Unicode character can also be represented in a regular-expression by
+ * using its <b>Hex notation</b>(hexadecimal code point value) directly as described in construct
+ * <tt>&#92;x{...}</tt>, for example a supplementary character U+2011F
+ * can be specified as <tt>&#92;x{2011F}</tt>, instead of two consecutive
+ * Unicode escape sequences of the surrogate pair
+ * <tt>&#92;uD840</tt><tt>&#92;uDD1F</tt>.
+ * <p>
+ * Unicode scripts, blocks, categories and binary properties are written with
+ * the <tt>\p</tt> and <tt>\P</tt> constructs as in Perl.
+ * <tt>\p{</tt><i>prop</i><tt>}</tt> matches if
+ * the input has the property <i>prop</i>, while <tt>\P{</tt><i>prop</i><tt>}</tt>
+ * does not match if the input has that property.
+ * <p>
+ * Scripts, blocks, categories and binary properties can be used both inside
+ * and outside of a character class.
+ *
+ * <p>
+ * <b><a name="usc">Scripts</a></b> are specified either with the prefix {@code Is}, as in
+ * {@code IsHiragana}, or by using  the {@code script} keyword (or its short
+ * form {@code sc})as in {@code script=Hiragana} or {@code sc=Hiragana}.
+ * <p>
+ * The script names supported by <code>Pattern</code> are the valid script names
+ * accepted and defined by
+ * {@link java.lang.Character.UnicodeScript#forName(String) UnicodeScript.forName}.
+ *
+ * <p>
+ * <b><a name="ubc">Blocks</a></b> are specified with the prefix {@code In}, as in
+ * {@code InMongolian}, or by using the keyword {@code block} (or its short
+ * form {@code blk}) as in {@code block=Mongolian} or {@code blk=Mongolian}.
+ * <p>
+ * The block names supported by <code>Pattern</code> are the valid block names
+ * accepted and defined by
+ * {@link java.lang.Character.UnicodeBlock#forName(String) UnicodeBlock.forName}.
+ * <p>
+ *
+ * <b><a name="ucc">Categories</a></b> may be specified with the optional prefix {@code Is}:
+ * Both {@code \p{L}} and {@code \p{IsL}} denote the category of Unicode
+ * letters. Same as scripts and blocks, categories can also be specified
+ * by using the keyword {@code general_category} (or its short form
+ * {@code gc}) as in {@code general_category=Lu} or {@code gc=Lu}.
+ * <p>
+ * The supported categories are those of
+ * <a href="http://www.unicode.org/unicode/standard/standard.html">
+ * <i>The Unicode Standard</i></a> in the version specified by the
+ * {@link java.lang.Character Character} class. The category names are those
+ * defined in the Standard, both normative and informative.
+ * <p>
+ *
+ * <b><a name="ubpc">Binary properties</a></b> are specified with the prefix {@code Is}, as in
+ * {@code IsAlphabetic}. The supported binary properties by <code>Pattern</code>
+ * are
+ * <ul>
+ *   <li> Alphabetic
+ *   <li> Ideographic
+ *   <li> Letter
+ *   <li> Lowercase
+ *   <li> Uppercase
+ *   <li> Titlecase
+ *   <li> Punctuation
+ *   <Li> Control
+ *   <li> White_Space
+ *   <li> Digit
+ *   <li> Hex_Digit
+ *   <li> Join_Control
+ *   <li> Noncharacter_Code_Point
+ *   <li> Assigned
+ * </ul>
+ * <p>
+ * The following <b>Predefined Character classes</b> and <b>POSIX character classes</b>
+ * are in conformance with the recommendation of <i>Annex C: Compatibility Properties</i>
+ * of <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Regular Expression
+ * </i></a>.
+ *
+ * <table border="0" cellpadding="1" cellspacing="0"
+ *  summary="predefined and posix character classes in Unicode mode">
+ * <tr align="left">
+ * <th align="left" id="predef_classes">Classes</th>
+ * <th align="left" id="predef_matches">Matches</th>
+ *</tr>
+ * <tr><td><tt>\p{Lower}</tt></td>
+ *     <td>A lowercase character:<tt>\p{IsLowercase}</tt></td></tr>
+ * <tr><td><tt>\p{Upper}</tt></td>
+ *     <td>An uppercase character:<tt>\p{IsUppercase}</tt></td></tr>
+ * <tr><td><tt>\p{ASCII}</tt></td>
+ *     <td>All ASCII:<tt>[\x00-\x7F]</tt></td></tr>
+ * <tr><td><tt>\p{Alpha}</tt></td>
+ *     <td>An alphabetic character:<tt>\p{IsAlphabetic}</tt></td></tr>
+ * <tr><td><tt>\p{Digit}</tt></td>
+ *     <td>A decimal digit character:<tt>p{IsDigit}</tt></td></tr>
+ * <tr><td><tt>\p{Alnum}</tt></td>
+ *     <td>An alphanumeric character:<tt>[\p{IsAlphabetic}\p{IsDigit}]</tt></td></tr>
+ * <tr><td><tt>\p{Punct}</tt></td>
+ *     <td>A punctuation character:<tt>p{IsPunctuation}</tt></td></tr>
+ * <tr><td><tt>\p{Graph}</tt></td>
+ *     <td>A visible character: <tt>[^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]</tt></td></tr>
+ * <tr><td><tt>\p{Print}</tt></td>
+ *     <td>A printable character: {@code [\p{Graph}\p{Blank}&&[^\p{Cntrl}]]}</td></tr>
+ * <tr><td><tt>\p{Blank}</tt></td>
+ *     <td>A space or a tab: {@code [\p{IsWhite_Space}&&[^\p{gc=Zl}\p{gc=Zp}\x0a\x0b\x0c\x0d\x85]]}</td></tr>
+ * <tr><td><tt>\p{Cntrl}</tt></td>
+ *     <td>A control character: <tt>\p{gc=Cc}</tt></td></tr>
+ * <tr><td><tt>\p{XDigit}</tt></td>
+ *     <td>A hexadecimal digit: <tt>[\p{gc=Nd}\p{IsHex_Digit}]</tt></td></tr>
+ * <tr><td><tt>\p{Space}</tt></td>
+ *     <td>A whitespace character:<tt>\p{IsWhite_Space}</tt></td></tr>
+ * <tr><td><tt>\d</tt></td>
+ *     <td>A digit: <tt>\p{IsDigit}</tt></td></tr>
+ * <tr><td><tt>\D</tt></td>
+ *     <td>A non-digit: <tt>[^\d]</tt></td></tr>
+ * <tr><td><tt>\s</tt></td>
+ *     <td>A whitespace character: <tt>\p{IsWhite_Space}</tt></td></tr>
+ * <tr><td><tt>\S</tt></td>
+ *     <td>A non-whitespace character: <tt>[^\s]</tt></td></tr>
+ * <tr><td><tt>\w</tt></td>
+ *     <td>A word character: <tt>[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin_Control}]</tt></td></tr>
+ * <tr><td><tt>\W</tt></td>
+ *     <td>A non-word character: <tt>[^\w]</tt></td></tr>
+ * </table>
+ * <p>
+ * <a name="jcc">
+ * Categories that behave like the java.lang.Character
+ * boolean is<i>methodname</i> methods (except for the deprecated ones) are
+ * available through the same <tt>\p{</tt><i>prop</i><tt>}</tt> syntax where
+ * the specified property has the name <tt>java<i>methodname</i></tt></a>.
+ *
+ * <h3> Comparison to Perl 5 </h3>
+ *
+ * <p>The <code>Pattern</code> engine performs traditional NFA-based matching
+ * with ordered alternation as occurs in Perl 5.
+ *
+ * <p> Perl constructs not supported by this class: </p>
+ *
+ * <ul>
+ *    <li><p> Predefined character classes (Unicode character)
+ *    <p><tt>\X&nbsp;&nbsp;&nbsp;&nbsp;</tt>Match Unicode
+ *    <a href="http://www.unicode.org/reports/tr18/#Default_Grapheme_Clusters">
+ *    <i>extended grapheme cluster</i></a>
+ *    </p></li>
+ *
+ *    <li><p> The backreference constructs, <tt>\g{</tt><i>n</i><tt>}</tt> for
+ *    the <i>n</i><sup>th</sup><a href="#cg">capturing group</a> and
+ *    <tt>\g{</tt><i>name</i><tt>}</tt> for
+ *    <a href="#groupname">named-capturing group</a>.
+ *    </p></li>
+ *
+ *    <li><p> The named character construct, <tt>\N{</tt><i>name</i><tt>}</tt>
+ *    for a Unicode character by its name.
+ *    </p></li>
+ *
+ *    <li><p> The conditional constructs
+ *    <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>)</tt> and
+ *    <tt>(?(</tt><i>condition</i><tt>)</tt><i>X</i><tt>|</tt><i>Y</i><tt>)</tt>,
+ *    </p></li>
+ *
+ *    <li><p> The embedded code constructs <tt>(?{</tt><i>code</i><tt>})</tt>
+ *    and <tt>(??{</tt><i>code</i><tt>})</tt>,</p></li>
+ *
+ *    <li><p> The embedded comment syntax <tt>(?#comment)</tt>, and </p></li>
+ *
+ *    <li><p> The preprocessing operations <tt>\l</tt> <tt>&#92;u</tt>,
+ *    <tt>\L</tt>, and <tt>\U</tt>.  </p></li>
+ *
+ * </ul>
+ *
+ * <p> Constructs supported by this class but not by Perl: </p>
+ *
+ * <ul>
+ *
+ *    <li><p> Character-class union and intersection as described
+ *    <a href="#cc">above</a>.</p></li>
+ *
+ * </ul>
+ *
+ * <p> Notable differences from Perl: </p>
+ *
+ * <ul>
+ *
+ *    <li><p> In Perl, <tt>\1</tt> through <tt>\9</tt> are always interpreted
+ *    as back references; a backslash-escaped number greater than <tt>9</tt> is
+ *    treated as a back reference if at least that many subexpressions exist,
+ *    otherwise it is interpreted, if possible, as an octal escape.  In this
+ *    class octal escapes must always begin with a zero. In this class,
+ *    <tt>\1</tt> through <tt>\9</tt> are always interpreted as back
+ *    references, and a larger number is accepted as a back reference if at
+ *    least that many subexpressions exist at that point in the regular
+ *    expression, otherwise the parser will drop digits until the number is
+ *    smaller or equal to the existing number of groups or it is one digit.
+ *    </p></li>
+ *
+ *    <li><p> Perl uses the <tt>g</tt> flag to request a match that resumes
+ *    where the last match left off.  This functionality is provided implicitly
+ *    by the {@link Matcher} class: Repeated invocations of the {@link
+ *    Matcher#find find} method will resume where the last match left off,
+ *    unless the matcher is reset.  </p></li>
+ *
+ *    <li><p> In Perl, embedded flags at the top level of an expression affect
+ *    the whole expression.  In this class, embedded flags always take effect
+ *    at the point at which they appear, whether they are at the top level or
+ *    within a group; in the latter case, flags are restored at the end of the
+ *    group just as in Perl.  </p></li>
+ *
+ * </ul>
+ *
+ *
+ * <p> For a more precise description of the behavior of regular expression
+ * constructs, please see <a href="http://www.oreilly.com/catalog/regex3/">
+ * <i>Mastering Regular Expressions, 3nd Edition</i>, Jeffrey E. F. Friedl,
+ * O'Reilly and Associates, 2006.</a>
+ * </p>
+ *
+ * @see java.lang.String#split(String, int)
+ * @see java.lang.String#split(String)
+ *
+ * @author      Mike McCloskey
+ * @author      Mark Reinhold
+ * @author      JSR-51 Expert Group
+ * @since       1.4
+ * @spec        JSR-51
+ */
+
+public final class Pattern
+    implements java.io.Serializable
+{
+
+    /**
+     * Regular expression modifier values.  Instead of being passed as
+     * arguments, they can also be passed as inline modifiers.
+     * For example, the following statements have the same effect.
+     * <pre>
+     * RegExp r1 = RegExp.compile("abc", Pattern.I|Pattern.M);
+     * RegExp r2 = RegExp.compile("(?im)abc", 0);
+     * </pre>
+     *
+     * The flags are duplicated so that the familiar Perl match flag
+     * names are available.
+     */
+
+    /**
+     * Enables Unix lines mode.
+     *
+     * <p> In this mode, only the <tt>'\n'</tt> line terminator is recognized
+     * in the behavior of <tt>.</tt>, <tt>^</tt>, and <tt>$</tt>.
+     *
+     * <p> Unix lines mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?d)</tt>.
+     */
+    public static final int UNIX_LINES = 0x01;
+
+    /**
+     * Enables case-insensitive matching.
+     *
+     * <p> By default, case-insensitive matching assumes that only characters
+     * in the US-ASCII charset are being matched.  Unicode-aware
+     * case-insensitive matching can be enabled by specifying the {@link
+     * #UNICODE_CASE} flag in conjunction with this flag.
+     *
+     * <p> Case-insensitive matching can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?i)</tt>.
+     *
+     * <p> Specifying this flag may impose a slight performance penalty.  </p>
+     */
+    public static final int CASE_INSENSITIVE = 0x02;
+
+    /**
+     * Permits whitespace and comments in pattern.
+     *
+     * <p> In this mode, whitespace is ignored, and embedded comments starting
+     * with <tt>#</tt> are ignored until the end of a line.
+     *
+     * <p> Comments mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?x)</tt>.
+     */
+    public static final int COMMENTS = 0x04;
+
+    /**
+     * Enables multiline mode.
+     *
+     * <p> In multiline mode the expressions <tt>^</tt> and <tt>$</tt> match
+     * just after or just before, respectively, a line terminator or the end of
+     * the input sequence.  By default these expressions only match at the
+     * beginning and the end of the entire input sequence.
+     *
+     * <p> Multiline mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?m)</tt>.  </p>
+     */
+    public static final int MULTILINE = 0x08;
+
+    /**
+     * Enables literal parsing of the pattern.
+     *
+     * <p> When this flag is specified then the input string that specifies
+     * the pattern is treated as a sequence of literal characters.
+     * Metacharacters or escape sequences in the input sequence will be
+     * given no special meaning.
+     *
+     * <p>The flags CASE_INSENSITIVE and UNICODE_CASE retain their impact on
+     * matching when used in conjunction with this flag. The other flags
+     * become superfluous.
+     *
+     * <p> There is no embedded flag character for enabling literal parsing.
+     * @since 1.5
+     */
+    public static final int LITERAL = 0x10;
+
+    /**
+     * Enables dotall mode.
+     *
+     * <p> In dotall mode, the expression <tt>.</tt> matches any character,
+     * including a line terminator.  By default this expression does not match
+     * line terminators.
+     *
+     * <p> Dotall mode can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?s)</tt>.  (The <tt>s</tt> is a mnemonic for
+     * "single-line" mode, which is what this is called in Perl.)  </p>
+     */
+    public static final int DOTALL = 0x20;
+
+    /**
+     * Enables Unicode-aware case folding.
+     *
+     * <p> When this flag is specified then case-insensitive matching, when
+     * enabled by the {@link #CASE_INSENSITIVE} flag, is done in a manner
+     * consistent with the Unicode Standard.  By default, case-insensitive
+     * matching assumes that only characters in the US-ASCII charset are being
+     * matched.
+     *
+     * <p> Unicode-aware case folding can also be enabled via the embedded flag
+     * expression&nbsp;<tt>(?u)</tt>.
+     *
+     * <p> Specifying this flag may impose a performance penalty.  </p>
+     */
+    public static final int UNICODE_CASE = 0x40;
+
+    /**
+     * Enables canonical equivalence.
+     *
+     * <p> When this flag is specified then two characters will be considered
+     * to match if, and only if, their full canonical decompositions match.
+     * The expression <tt>"a&#92;u030A"</tt>, for example, will match the
+     * string <tt>"&#92;u00E5"</tt> when this flag is specified.  By default,
+     * matching does not take canonical equivalence into account.
+     *
+     * <p> There is no embedded flag character for enabling canonical
+     * equivalence.
+     *
+     * <p> Specifying this flag may impose a performance penalty.  </p>
+     */
+    public static final int CANON_EQ = 0x80;
+
+    // Android-changed: Android always uses unicode character classes.
+    /**
+     * Enables the Unicode version of <i>Predefined character classes</i> and
+     * <i>POSIX character classes</i> as defined by <a href="http://www.unicode.org/reports/tr18/"><i>Unicode Technical
+     * Standard #18: Unicode Regular Expression</i></a>
+     * <i>Annex C: Compatibility Properties</i>.
+     * <p>
+     *
+     * This flag has no effect on Android, unicode character classes are always
+     * used.
+     *
+     * @since 1.7
+     */
+    public static final int UNICODE_CHARACTER_CLASS = 0x100;
+
+    /* Pattern has only two serialized components: The pattern string
+     * and the flags, which are all that is needed to recompile the pattern
+     * when it is deserialized.
+     */
+
+    /** use serialVersionUID from Merlin b59 for interoperability */
+    private static final long serialVersionUID = 5073258162644648461L;
+
+    /**
+     * The original regular-expression pattern string.
+     *
+     * @serial
+     */
+    // Android-changed: reimplement matching logic natively via ICU.
+    // private String pattern;
+    private final String pattern;
+
+    /**
+     * The original pattern flags.
+     *
+     * @serial
+     */
+    // Android-changed: reimplement matching logic natively via ICU.
+    // private int flags;
+    private final int flags;
+
+    // BEGIN Android-changed: reimplement matching logic natively via ICU.
+    // We only need some tie-ins to native memory, instead of a large number
+    // of fields on the .java side.
+    /* package */ transient PatternNative nativePattern;
+    // END Android-changed: reimplement matching logic natively via ICU.
+
+    /**
+     * Compiles the given regular expression into a pattern.
+     *
+     * @param  regex
+     *         The expression to be compiled
+     * @return the given regular expression compiled into a pattern
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static Pattern compile(String regex) {
+        return new Pattern(regex, 0);
+    }
+
+    /**
+     * Compiles the given regular expression into a pattern with the given
+     * flags.
+     *
+     * @param  regex
+     *         The expression to be compiled
+     *
+     * @param  flags
+     *         Match flags, a bit mask that may include
+     *         {@link #CASE_INSENSITIVE}, {@link #MULTILINE}, {@link #DOTALL},
+     *         {@link #UNICODE_CASE}, {@link #CANON_EQ}, {@link #UNIX_LINES},
+     *         {@link #LITERAL}, {@link #UNICODE_CHARACTER_CLASS}
+     *         and {@link #COMMENTS}
+     *
+     * @return the given regular expression compiled into a pattern with the given flags
+     * @throws  IllegalArgumentException
+     *          If bit values other than those corresponding to the defined
+     *          match flags are set in <tt>flags</tt>
+     *
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static Pattern compile(String regex, int flags) {
+        return new Pattern(regex, flags);
+    }
+
+    /**
+     * Returns the regular expression from which this pattern was compiled.
+     *
+     * @return  The source of this pattern
+     */
+    public String pattern() {
+        return pattern;
+    }
+
+    /**
+     * <p>Returns the string representation of this pattern. This
+     * is the regular expression from which this pattern was
+     * compiled.</p>
+     *
+     * @return  The string representation of this pattern
+     * @since 1.5
+     */
+    public String toString() {
+        return pattern;
+    }
+
+    /**
+     * Creates a matcher that will match the given input against this pattern.
+     *
+     * @param  input
+     *         The character sequence to be matched
+     *
+     * @return  A new matcher for this pattern
+     */
+    public Matcher matcher(CharSequence input) {
+        // Android-removed: Pattern is eagerly compiled() upon construction.
+        /*
+        if (!compiled) {
+            synchronized(this) {
+                if (!compiled)
+                    compile();
+            }
+        }
+        */
+        Matcher m = new Matcher(this, input);
+        return m;
+    }
+
+    /**
+     * Returns this pattern's match flags.
+     *
+     * @return  The match flags specified when this pattern was compiled
+     */
+    public int flags() {
+        return flags;
+    }
+
+    /**
+     * Compiles the given regular expression and attempts to match the given
+     * input against it.
+     *
+     * <p> An invocation of this convenience method of the form
+     *
+     * <blockquote><pre>
+     * Pattern.matches(regex, input);</pre></blockquote>
+     *
+     * behaves in exactly the same way as the expression
+     *
+     * <blockquote><pre>
+     * Pattern.compile(regex).matcher(input).matches()</pre></blockquote>
+     *
+     * <p> If a pattern is to be used multiple times, compiling it once and reusing
+     * it will be more efficient than invoking this method each time.  </p>
+     *
+     * @param  regex
+     *         The expression to be compiled
+     *
+     * @param  input
+     *         The character sequence to be matched
+     * @return whether or not the regular expression matches on the input
+     * @throws  PatternSyntaxException
+     *          If the expression's syntax is invalid
+     */
+    public static boolean matches(String regex, CharSequence input) {
+        Pattern p = Pattern.compile(regex);
+        Matcher m = p.matcher(input);
+        return m.matches();
+    }
+
+    // Android-changed: Adopt split() behavior change only for apps targeting API > 28.
+    // http://b/109659282#comment7
+    /**
+     * Splits the given input sequence around matches of this pattern.
+     *
+     * <p> The array returned by this method contains each substring of the
+     * input sequence that is terminated by another subsequence that matches
+     * this pattern or is terminated by the end of the input sequence.  The
+     * substrings in the array are in the order in which they occur in the
+     * input. If this pattern does not match any subsequence of the input then
+     * the resulting array has just one element, namely the input sequence in
+     * string form.
+     *
+     * <p> When there is a positive-width match at the beginning of the input
+     * sequence then an empty leading substring is included at the beginning
+     * of the resulting array. A zero-width match at the beginning however
+     * can only produce such an empty leading substring for apps running on or
+     * targeting API versions <= 28.
+     *
+     * <p> The <tt>limit</tt> parameter controls the number of times the
+     * pattern is applied and therefore affects the length of the resulting
+     * array.  If the limit <i>n</i> is greater than zero then the pattern
+     * will be applied at most <i>n</i>&nbsp;-&nbsp;1 times, the array's
+     * length will be no greater than <i>n</i>, and the array's last entry
+     * will contain all input beyond the last matched delimiter.  If <i>n</i>
+     * is non-positive then the pattern will be applied as many times as
+     * possible and the array can have any length.  If <i>n</i> is zero then
+     * the pattern will be applied as many times as possible, the array can
+     * have any length, and trailing empty strings will be discarded.
+     *
+     * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
+     * results with these parameters:
+     *
+     * <blockquote><table cellpadding=1 cellspacing=0
+     *              summary="Split examples showing regex, limit, and result">
+     * <tr><th align="left"><i>Regex&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
+     *     <th align="left"><i>Limit&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
+     *     <th align="left"><i>Result&nbsp;&nbsp;&nbsp;&nbsp;</i></th></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>2</td>
+     *     <td><tt>{ "boo", "and:foo" }</tt></td></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>5</td>
+     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+     * <tr><td align=center>:</td>
+     *     <td align=center>-2</td>
+     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>5</td>
+     *     <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>-2</td>
+     *     <td><tt>{ "b", "", ":and:f", "", "" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td align=center>0</td>
+     *     <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
+     * </table></blockquote>
+     *
+     * @param  input
+     *         The character sequence to be split
+     *
+     * @param  limit
+     *         The result threshold, as described above
+     *
+     * @return  The array of strings computed by splitting the input
+     *          around matches of this pattern
+     */
+    public String[] split(CharSequence input, int limit) {
+        // BEGIN Android-added: fastSplit() to speed up simple cases.
+        String[] fast = fastSplit(pattern, input.toString(), limit);
+        if (fast != null) {
+            return fast;
+        }
+        // END Android-added: fastSplit() to speed up simple cases.
+        int index = 0;
+        boolean matchLimited = limit > 0;
+        ArrayList<String> matchList = new ArrayList<>();
+        Matcher m = matcher(input);
+
+        // Add segments before each match found
+        while(m.find()) {
+            if (!matchLimited || matchList.size() < limit - 1) {
+                if (index == 0 && index == m.start() && m.start() == m.end()) {
+                    // no empty leading substring included for zero-width match
+                    // at the beginning of the input char sequence.
+                    // BEGIN Android-changed: split() compat behavior for apps targeting <= 28.
+                    // continue;
+                    int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+                    if (targetSdkVersion > 28) {
+                        continue;
+                    }
+                    // END Android-changed: split() compat behavior for apps targeting <= 28.
+                }
+                String match = input.subSequence(index, m.start()).toString();
+                matchList.add(match);
+                index = m.end();
+            } else if (matchList.size() == limit - 1) { // last one
+                String match = input.subSequence(index,
+                                                 input.length()).toString();
+                matchList.add(match);
+                index = m.end();
+            }
+        }
+
+        // If no match was found, return this
+        if (index == 0)
+            return new String[] {input.toString()};
+
+        // Add remaining segment
+        if (!matchLimited || matchList.size() < limit)
+            matchList.add(input.subSequence(index, input.length()).toString());
+
+        // Construct result
+        int resultSize = matchList.size();
+        if (limit == 0)
+            while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
+                resultSize--;
+        String[] result = new String[resultSize];
+        return matchList.subList(0, resultSize).toArray(result);
+    }
+
+    // BEGIN Android-added: fastSplit() to speed up simple cases.
+    private static final String FASTSPLIT_METACHARACTERS = "\\?*+[](){}^$.|";
+
+    /**
+     * Returns a result equivalent to {@code s.split(separator, limit)} if it's able
+     * to compute it more cheaply than native impl, or null if the caller should fall back to
+     * using native impl.
+     *
+     *  fastpath will work  if the regex is a
+     *   (1)one-char String and this character is not one of the
+     *      RegEx's meta characters ".$|()[{^?*+\\", or
+     *   (2)two-char String and the first char is the backslash and
+     *      the second is one of regEx's meta characters ".$|()[{^?*+\\".
+     * @hide
+     */
+    public static String[] fastSplit(String re, String input, int limit) {
+        // Can we do it cheaply?
+        int len = re.length();
+        if (len == 0) {
+            return null;
+        }
+        char ch = re.charAt(0);
+        if (len == 1 && FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+            // We're looking for a single non-metacharacter. Easy.
+        } else if (len == 2 && ch == '\\') {
+            // We're looking for a quoted character.
+            // Quoted metacharacters are effectively single non-metacharacters.
+            ch = re.charAt(1);
+            if (FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+                return null;
+            }
+        } else {
+            return null;
+        }
+
+        // We can do this cheaply...
+
+        // Unlike Perl, which considers the result of splitting the empty string to be the empty
+        // array, Java returns an array containing the empty string.
+        if (input.isEmpty()) {
+            return new String[] { "" };
+        }
+
+        // Count separators
+        int separatorCount = 0;
+        int begin = 0;
+        int end;
+        while (separatorCount + 1 != limit && (end = input.indexOf(ch, begin)) != -1) {
+            ++separatorCount;
+            begin = end + 1;
+        }
+        int lastPartEnd = input.length();
+        if (limit == 0 && begin == lastPartEnd) {
+            // Last part is empty for limit == 0, remove all trailing empty matches.
+            if (separatorCount == lastPartEnd) {
+                // Input contains only separators.
+                return EmptyArray.STRING;
+            }
+            // Find the beginning of trailing separators.
+            do {
+                --begin;
+            } while (input.charAt(begin - 1) == ch);
+            // Reduce separatorCount and fix lastPartEnd.
+            separatorCount -= input.length() - begin;
+            lastPartEnd = begin;
+        }
+
+        // Collect the result parts.
+        String[] result = new String[separatorCount + 1];
+        begin = 0;
+        for (int i = 0; i != separatorCount; ++i) {
+            end = input.indexOf(ch, begin);
+            result[i] = input.substring(begin, end);
+            begin = end + 1;
+        }
+        // Add last part.
+        result[separatorCount] = input.substring(begin, lastPartEnd);
+        return result;
+    }
+    // END Android-added: fastSplit() to speed up simple cases.
+
+    /**
+     * Splits the given input sequence around matches of this pattern.
+     *
+     * <p> This method works as if by invoking the two-argument {@link
+     * #split(java.lang.CharSequence, int) split} method with the given input
+     * sequence and a limit argument of zero.  Trailing empty strings are
+     * therefore not included in the resulting array. </p>
+     *
+     * <p> The input <tt>"boo:and:foo"</tt>, for example, yields the following
+     * results with these expressions:
+     *
+     * <blockquote><table cellpadding=1 cellspacing=0
+     *              summary="Split examples showing regex and result">
+     * <tr><th align="left"><i>Regex&nbsp;&nbsp;&nbsp;&nbsp;</i></th>
+     *     <th align="left"><i>Result</i></th></tr>
+     * <tr><td align=center>:</td>
+     *     <td><tt>{ "boo", "and", "foo" }</tt></td></tr>
+     * <tr><td align=center>o</td>
+     *     <td><tt>{ "b", "", ":and:f" }</tt></td></tr>
+     * </table></blockquote>
+     *
+     *
+     * @param  input
+     *         The character sequence to be split
+     *
+     * @return  The array of strings computed by splitting the input
+     *          around matches of this pattern
+     */
+    public String[] split(CharSequence input) {
+        return split(input, 0);
+    }
+
+    /**
+     * Returns a literal pattern <code>String</code> for the specified
+     * <code>String</code>.
+     *
+     * <p>This method produces a <code>String</code> that can be used to
+     * create a <code>Pattern</code> that would match the string
+     * <code>s</code> as if it were a literal pattern.</p> Metacharacters
+     * or escape sequences in the input sequence will be given no special
+     * meaning.
+     *
+     * @param  s The string to be literalized
+     * @return  A literal string replacement
+     * @since 1.5
+     */
+    public static String quote(String s) {
+        int slashEIndex = s.indexOf("\\E");
+        if (slashEIndex == -1)
+            return "\\Q" + s + "\\E";
+
+        StringBuilder sb = new StringBuilder(s.length() * 2);
+        sb.append("\\Q");
+        slashEIndex = 0;
+        int current = 0;
+        while ((slashEIndex = s.indexOf("\\E", current)) != -1) {
+            sb.append(s.substring(current, slashEIndex));
+            current = slashEIndex + 2;
+            sb.append("\\E\\\\E\\Q");
+        }
+        sb.append(s.substring(current, s.length()));
+        sb.append("\\E");
+        return sb.toString();
+    }
+
+    /**
+     * Recompile the Pattern instance from a stream.  The original pattern
+     * string is read in and the object tree is recompiled from it.
+     */
+    private void readObject(java.io.ObjectInputStream s)
+        throws java.io.IOException, ClassNotFoundException {
+
+        // Read in all fields
+        s.defaultReadObject();
+
+        // Android-removed: reimplement matching logic natively via ICU.
+        // // Initialize counts
+        // capturingGroupCount = 1;
+        // localCount = 0;
+
+        // Android-changed: Pattern is eagerly compiled() upon construction.
+        /*
+        // if length > 0, the Pattern is lazily compiled
+        compiled = false;
+        if (pattern.length() == 0) {
+            root = new Start(lastAccept);
+            matchRoot = lastAccept;
+            compiled = true;
+        }
+        */
+        compile();
+    }
+
+    // Android-changed: reimplement matching logic natively via ICU.
+    // Dropped documentation reference to Start and LastNode implementation
+    // details which do not apply on Android.
+    /**
+     * This private constructor is used to create all Patterns. The pattern
+     * string and match flags are all that is needed to completely describe
+     * a Pattern.
+     */
+    private Pattern(String p, int f) {
+        pattern = p;
+        flags = f;
+
+        // BEGIN Android-changed: Only specific flags are supported.
+        /*
+        // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
+        if ((flags & UNICODE_CHARACTER_CLASS) != 0)
+            flags |= UNICODE_CASE;
+
+        // Reset group index count
+        capturingGroupCount = 1;
+        localCount = 0;
+        */
+        if ((f & CANON_EQ) != 0) {
+            throw new UnsupportedOperationException("CANON_EQ flag not supported");
+        }
+        int supportedFlags = CASE_INSENSITIVE | COMMENTS | DOTALL | LITERAL | MULTILINE | UNICODE_CASE | UNIX_LINES;
+        if ((f & ~supportedFlags) != 0) {
+            throw new IllegalArgumentException("Unsupported flags: " + (f & ~supportedFlags));
+        }
+        // END Android-changed: Only specific flags are supported.
+
+        // BEGIN Android-removed: Pattern is eagerly compiled() upon construction.
+        // if (pattern.length() > 0) {
+        // END Android-removed: Pattern is eagerly compiled() upon construction.
+            compile();
+        // Android-removed: reimplement matching logic natively via ICU.
+        /*
+        } else {
+            root = new Start(lastAccept);
+            matchRoot = lastAccept;
+        }
+        */
+    }
+
+    // BEGIN Android-changed: reimplement matching logic natively via ICU.
+    // Use native implementation instead of > 3000 lines of helper methods.
+    private void compile() throws PatternSyntaxException {
+        if (pattern == null) {
+            throw new NullPointerException("pattern == null");
+        }
+
+        String icuPattern = pattern;
+        if ((flags & LITERAL) != 0) {
+            icuPattern = quote(pattern);
+        }
+
+        // These are the flags natively supported by ICU.
+        // They even have the same value in native code.
+        int icuFlags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES);
+        nativePattern = PatternNative.create(icuPattern, icuFlags);
+    }
+    // END Android-changed: reimplement matching logic natively via ICU.
+
+    /**
+     * Creates a predicate which can be used to match a string.
+     *
+     * @return  The predicate which can be used for matching on a string
+     * @since   1.8
+     */
+    public Predicate<String> asPredicate() {
+        return s -> matcher(s).find();
+    }
+
+    /**
+     * Creates a stream from the given input sequence around matches of this
+     * pattern.
+     *
+     * <p> The stream returned by this method contains each substring of the
+     * input sequence that is terminated by another subsequence that matches
+     * this pattern or is terminated by the end of the input sequence.  The
+     * substrings in the stream are in the order in which they occur in the
+     * input. Trailing empty strings will be discarded and not encountered in
+     * the stream.
+     *
+     * <p> If this pattern does not match any subsequence of the input then
+     * the resulting stream has just one element, namely the input sequence in
+     * string form.
+     *
+     * <p> When there is a positive-width match at the beginning of the input
+     * sequence then an empty leading substring is included at the beginning
+     * of the stream. A zero-width match at the beginning however never produces
+     * such empty leading substring.
+     *
+     * <p> If the input sequence is mutable, it must remain constant during the
+     * execution of the terminal stream operation.  Otherwise, the result of the
+     * terminal stream operation is undefined.
+     *
+     * @param   input
+     *          The character sequence to be split
+     *
+     * @return  The stream of strings computed by splitting the input
+     *          around matches of this pattern
+     * @see     #split(CharSequence)
+     * @since   1.8
+     */
+    public Stream<String> splitAsStream(final CharSequence input) {
+        class MatcherIterator implements Iterator<String> {
+            private final Matcher matcher;
+            // The start position of the next sub-sequence of input
+            // when current == input.length there are no more elements
+            private int current;
+            // null if the next element, if any, needs to obtained
+            private String nextElement;
+            // > 0 if there are N next empty elements
+            private int emptyElementCount;
+
+            MatcherIterator() {
+                this.matcher = matcher(input);
+            }
+
+            public String next() {
+                if (!hasNext())
+                    throw new NoSuchElementException();
+
+                if (emptyElementCount == 0) {
+                    String n = nextElement;
+                    nextElement = null;
+                    return n;
+                } else {
+                    emptyElementCount--;
+                    return "";
+                }
+            }
+
+            public boolean hasNext() {
+                if (nextElement != null || emptyElementCount > 0)
+                    return true;
+
+                if (current == input.length())
+                    return false;
+
+                // Consume the next matching element
+                // Count sequence of matching empty elements
+                while (matcher.find()) {
+                    nextElement = input.subSequence(current, matcher.start()).toString();
+                    current = matcher.end();
+                    if (!nextElement.isEmpty()) {
+                        return true;
+                    } else if (current > 0) { // no empty leading substring for zero-width
+                                              // match at the beginning of the input
+                        emptyElementCount++;
+                    }
+                }
+
+                // Consume last matching element
+                nextElement = input.subSequence(current, input.length()).toString();
+                current = input.length();
+                if (!nextElement.isEmpty()) {
+                    return true;
+                } else {
+                    // Ignore a terminal sequence of matching empty elements
+                    emptyElementCount = 0;
+                    nextElement = null;
+                    return false;
+                }
+            }
+        }
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                new MatcherIterator(), Spliterator.ORDERED | Spliterator.NONNULL), false);
+    }
+}
diff --git a/java/util/regex/PatternSyntaxException.java b/java/util/regex/PatternSyntaxException.java
new file mode 100644
index 0000000..d6ac72a
--- /dev/null
+++ b/java/util/regex/PatternSyntaxException.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.regex;
+
+import sun.security.action.GetPropertyAction;
+
+
+/**
+ * Unchecked exception thrown to indicate a syntax error in a
+ * regular-expression pattern.
+ *
+ * @author  unascribed
+ * @since 1.4
+ * @spec JSR-51
+ */
+
+public class PatternSyntaxException
+    extends IllegalArgumentException
+{
+    private static final long serialVersionUID = -3864639126226059218L;
+
+    private final String desc;
+    private final String pattern;
+    private final int index;
+
+    /**
+     * Constructs a new instance of this class.
+     *
+     * @param  desc
+     *         A description of the error
+     *
+     * @param  regex
+     *         The erroneous pattern
+     *
+     * @param  index
+     *         The approximate index in the pattern of the error,
+     *         or <tt>-1</tt> if the index is not known
+     */
+    public PatternSyntaxException(String desc, String regex, int index) {
+        this.desc = desc;
+        this.pattern = regex;
+        this.index = index;
+    }
+
+    /**
+     * Retrieves the error index.
+     *
+     * @return  The approximate index in the pattern of the error,
+     *         or <tt>-1</tt> if the index is not known
+     */
+    public int getIndex() {
+        return index;
+    }
+
+    /**
+     * Retrieves the description of the error.
+     *
+     * @return  The description of the error
+     */
+    public String getDescription() {
+        return desc;
+    }
+
+    /**
+     * Retrieves the erroneous regular-expression pattern.
+     *
+     * @return  The erroneous pattern
+     */
+    public String getPattern() {
+        return pattern;
+    }
+
+    private static final String nl =
+        java.security.AccessController
+            .doPrivileged(new GetPropertyAction("line.separator"));
+
+    /**
+     * Returns a multi-line string containing the description of the syntax
+     * error and its index, the erroneous regular-expression pattern, and a
+     * visual indication of the error index within the pattern.
+     *
+     * @return  The full detail message
+     */
+    public String getMessage() {
+        StringBuffer sb = new StringBuffer();
+        sb.append(desc);
+        if (index >= 0) {
+            sb.append(" near index ");
+            sb.append(index);
+        }
+        sb.append(nl);
+        sb.append(pattern);
+        if (index >= 0) {
+            sb.append(nl);
+            for (int i = 0; i < index; i++) sb.append(' ');
+            sb.append('^');
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/java/util/stream/AbstractPipeline.java b/java/util/stream/AbstractPipeline.java
new file mode 100644
index 0000000..627bb32
--- /dev/null
+++ b/java/util/stream/AbstractPipeline.java
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for "pipeline" classes, which are the core
+ * implementations of the Stream interface and its primitive specializations.
+ * Manages construction and evaluation of stream pipelines.
+ *
+ * <p>An {@code AbstractPipeline} represents an initial portion of a stream
+ * pipeline, encapsulating a stream source and zero or more intermediate
+ * operations.  The individual {@code AbstractPipeline} objects are often
+ * referred to as <em>stages</em>, where each stage describes either the stream
+ * source or an intermediate operation.
+ *
+ * <p>A concrete intermediate stage is generally built from an
+ * {@code AbstractPipeline}, a shape-specific pipeline class which extends it
+ * (e.g., {@code IntPipeline}) which is also abstract, and an operation-specific
+ * concrete class which extends that.  {@code AbstractPipeline} contains most of
+ * the mechanics of evaluating the pipeline, and implements methods that will be
+ * used by the operation; the shape-specific classes add helper methods for
+ * dealing with collection of results into the appropriate shape-specific
+ * containers.
+ *
+ * <p>After chaining a new intermediate operation, or executing a terminal
+ * operation, the stream is considered to be consumed, and no more intermediate
+ * or terminal operations are permitted on this stream instance.
+ *
+ * @implNote
+ * <p>For sequential streams, and parallel streams without
+ * <a href="package-summary.html#StreamOps">stateful intermediate
+ * operations</a>, parallel streams, pipeline evaluation is done in a single
+ * pass that "jams" all the operations together.  For parallel streams with
+ * stateful operations, execution is divided into segments, where each
+ * stateful operations marks the end of a segment, and each segment is
+ * evaluated separately and the result used as the input to the next
+ * segment.  In all cases, the source data is not consumed until a terminal
+ * operation begins.
+ *
+ * @param <E_IN>  type of input elements
+ * @param <E_OUT> type of output elements
+ * @param <S> type of the subclass implementing {@code BaseStream}
+ * @since 1.8
+ * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
+        extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
+    private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed";
+    private static final String MSG_CONSUMED = "source already consumed or closed";
+
+    /**
+     * Backlink to the head of the pipeline chain (self if this is the source
+     * stage).
+     */
+    @SuppressWarnings("rawtypes")
+    private final AbstractPipeline sourceStage;
+
+    /**
+     * The "upstream" pipeline, or null if this is the source stage.
+     */
+    @SuppressWarnings("rawtypes")
+    private final AbstractPipeline previousStage;
+
+    /**
+     * The operation flags for the intermediate operation represented by this
+     * pipeline object.
+     */
+    protected final int sourceOrOpFlags;
+
+    /**
+     * The next stage in the pipeline, or null if this is the last stage.
+     * Effectively final at the point of linking to the next pipeline.
+     */
+    @SuppressWarnings("rawtypes")
+    private AbstractPipeline nextStage;
+
+    /**
+     * The number of intermediate operations between this pipeline object
+     * and the stream source if sequential, or the previous stateful if parallel.
+     * Valid at the point of pipeline preparation for evaluation.
+     */
+    private int depth;
+
+    /**
+     * The combined source and operation flags for the source and all operations
+     * up to and including the operation represented by this pipeline object.
+     * Valid at the point of pipeline preparation for evaluation.
+     */
+    private int combinedFlags;
+
+    /**
+     * The source spliterator. Only valid for the head pipeline.
+     * Before the pipeline is consumed if non-null then {@code sourceSupplier}
+     * must be null. After the pipeline is consumed if non-null then is set to
+     * null.
+     */
+    private Spliterator<?> sourceSpliterator;
+
+    /**
+     * The source supplier. Only valid for the head pipeline. Before the
+     * pipeline is consumed if non-null then {@code sourceSpliterator} must be
+     * null. After the pipeline is consumed if non-null then is set to null.
+     */
+    private Supplier<? extends Spliterator<?>> sourceSupplier;
+
+    /**
+     * True if this pipeline has been linked or consumed
+     */
+    private boolean linkedOrConsumed;
+
+    /**
+     * True if there are any stateful ops in the pipeline; only valid for the
+     * source stage.
+     */
+    private boolean sourceAnyStateful;
+
+    private Runnable sourceCloseAction;
+
+    /**
+     * True if pipeline is parallel, otherwise the pipeline is sequential; only
+     * valid for the source stage.
+     */
+    private boolean parallel;
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     * @param parallel True if the pipeline is parallel
+     */
+    AbstractPipeline(Supplier<? extends Spliterator<?>> source,
+                     int sourceFlags, boolean parallel) {
+        this.previousStage = null;
+        this.sourceSupplier = source;
+        this.sourceStage = this;
+        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
+        // The following is an optimization of:
+        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
+        this.depth = 0;
+        this.parallel = parallel;
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    AbstractPipeline(Spliterator<?> source,
+                     int sourceFlags, boolean parallel) {
+        this.previousStage = null;
+        this.sourceSpliterator = source;
+        this.sourceStage = this;
+        this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
+        // The following is an optimization of:
+        // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
+        this.depth = 0;
+        this.parallel = parallel;
+    }
+
+    /**
+     * Constructor for appending an intermediate operation stage onto an
+     * existing pipeline.
+     *
+     * @param previousStage the upstream pipeline stage
+     * @param opFlags the operation flags for the new stage, described in
+     * {@link StreamOpFlag}
+     */
+    AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
+        if (previousStage.linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        previousStage.linkedOrConsumed = true;
+        previousStage.nextStage = this;
+
+        this.previousStage = previousStage;
+        this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK;
+        this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags);
+        this.sourceStage = previousStage.sourceStage;
+        if (opIsStateful())
+            sourceStage.sourceAnyStateful = true;
+        this.depth = previousStage.depth + 1;
+    }
+
+
+    // Terminal evaluation methods
+
+    /**
+     * Evaluate the pipeline with a terminal operation to produce a result.
+     *
+     * @param <R> the type of result
+     * @param terminalOp the terminal operation to be applied to the pipeline.
+     * @return the result
+     */
+    final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
+        assert getOutputShape() == terminalOp.inputShape();
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        return isParallel()
+               ? terminalOp.evaluateParallel(this, sourceSpliterator(terminalOp.getOpFlags()))
+               : terminalOp.evaluateSequential(this, sourceSpliterator(terminalOp.getOpFlags()));
+    }
+
+    /**
+     * Collect the elements output from the pipeline stage.
+     *
+     * @param generator the array generator to be used to create array instances
+     * @return a flat array-backed Node that holds the collected output elements
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final Node<E_OUT> evaluateToArrayNode(IntFunction<E_OUT[]> generator) {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        // If the last intermediate operation is stateful then
+        // evaluate directly to avoid an extra collection step
+        if (isParallel() && previousStage != null && opIsStateful()) {
+            // Set the depth of this, last, pipeline stage to zero to slice the
+            // pipeline such that this operation will not be included in the
+            // upstream slice and upstream operations will not be included
+            // in this slice
+            depth = 0;
+            return opEvaluateParallel(previousStage, previousStage.sourceSpliterator(0), generator);
+        }
+        else {
+            return evaluate(sourceSpliterator(0), true, generator);
+        }
+    }
+
+    /**
+     * Gets the source stage spliterator if this pipeline stage is the source
+     * stage.  The pipeline is consumed after this method is called and
+     * returns successfully.
+     *
+     * @return the source stage spliterator
+     * @throws IllegalStateException if this pipeline stage is not the source
+     *         stage.
+     */
+    @SuppressWarnings("unchecked")
+    final Spliterator<E_OUT> sourceStageSpliterator() {
+        if (this != sourceStage)
+            throw new IllegalStateException();
+
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        if (sourceStage.sourceSpliterator != null) {
+            @SuppressWarnings("unchecked")
+            Spliterator<E_OUT> s = sourceStage.sourceSpliterator;
+            sourceStage.sourceSpliterator = null;
+            return s;
+        }
+        else if (sourceStage.sourceSupplier != null) {
+            @SuppressWarnings("unchecked")
+            Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSupplier.get();
+            sourceStage.sourceSupplier = null;
+            return s;
+        }
+        else {
+            throw new IllegalStateException(MSG_CONSUMED);
+        }
+    }
+
+    // BaseStream
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final S sequential() {
+        sourceStage.parallel = false;
+        return (S) this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final S parallel() {
+        sourceStage.parallel = true;
+        return (S) this;
+    }
+
+    @Override
+    public void close() {
+        linkedOrConsumed = true;
+        sourceSupplier = null;
+        sourceSpliterator = null;
+        if (sourceStage.sourceCloseAction != null) {
+            Runnable closeAction = sourceStage.sourceCloseAction;
+            sourceStage.sourceCloseAction = null;
+            closeAction.run();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public S onClose(Runnable closeHandler) {
+        Runnable existingHandler = sourceStage.sourceCloseAction;
+        sourceStage.sourceCloseAction =
+                (existingHandler == null)
+                ? closeHandler
+                : Streams.composeWithExceptions(existingHandler, closeHandler);
+        return (S) this;
+    }
+
+    // Primitive specialization use co-variant overrides, hence is not final
+    @Override
+    @SuppressWarnings("unchecked")
+    public Spliterator<E_OUT> spliterator() {
+        if (linkedOrConsumed)
+            throw new IllegalStateException(MSG_STREAM_LINKED);
+        linkedOrConsumed = true;
+
+        if (this == sourceStage) {
+            if (sourceStage.sourceSpliterator != null) {
+                @SuppressWarnings("unchecked")
+                Spliterator<E_OUT> s = (Spliterator<E_OUT>) sourceStage.sourceSpliterator;
+                sourceStage.sourceSpliterator = null;
+                return s;
+            }
+            else if (sourceStage.sourceSupplier != null) {
+                @SuppressWarnings("unchecked")
+                Supplier<Spliterator<E_OUT>> s = (Supplier<Spliterator<E_OUT>>) sourceStage.sourceSupplier;
+                sourceStage.sourceSupplier = null;
+                return lazySpliterator(s);
+            }
+            else {
+                throw new IllegalStateException(MSG_CONSUMED);
+            }
+        }
+        else {
+            return wrap(this, () -> sourceSpliterator(0), isParallel());
+        }
+    }
+
+    @Override
+    public final boolean isParallel() {
+        return sourceStage.parallel;
+    }
+
+
+    /**
+     * Returns the composition of stream flags of the stream source and all
+     * intermediate operations.
+     *
+     * @return the composition of stream flags of the stream source and all
+     *         intermediate operations
+     * @see StreamOpFlag
+     */
+    // Android-changed: Made public for CTS tests only.
+    public final int getStreamFlags() {
+        return StreamOpFlag.toStreamFlags(combinedFlags);
+    }
+
+    /**
+     * Get the source spliterator for this pipeline stage.  For a sequential or
+     * stateless parallel pipeline, this is the source spliterator.  For a
+     * stateful parallel pipeline, this is a spliterator describing the results
+     * of all computations up to and including the most recent stateful
+     * operation.
+     */
+    @SuppressWarnings("unchecked")
+    private Spliterator<?> sourceSpliterator(int terminalFlags) {
+        // Get the source spliterator of the pipeline
+        Spliterator<?> spliterator = null;
+        if (sourceStage.sourceSpliterator != null) {
+            spliterator = sourceStage.sourceSpliterator;
+            sourceStage.sourceSpliterator = null;
+        }
+        else if (sourceStage.sourceSupplier != null) {
+            spliterator = (Spliterator<?>) sourceStage.sourceSupplier.get();
+            sourceStage.sourceSupplier = null;
+        }
+        else {
+            throw new IllegalStateException(MSG_CONSUMED);
+        }
+
+        if (isParallel() && sourceStage.sourceAnyStateful) {
+            // Adapt the source spliterator, evaluating each stateful op
+            // in the pipeline up to and including this pipeline stage.
+            // The depth and flags of each pipeline stage are adjusted accordingly.
+            int depth = 1;
+            for (@SuppressWarnings("rawtypes") AbstractPipeline u = sourceStage, p = sourceStage.nextStage, e = this;
+                 u != e;
+                 u = p, p = p.nextStage) {
+
+                int thisOpFlags = p.sourceOrOpFlags;
+                if (p.opIsStateful()) {
+                    depth = 0;
+
+                    if (StreamOpFlag.SHORT_CIRCUIT.isKnown(thisOpFlags)) {
+                        // Clear the short circuit flag for next pipeline stage
+                        // This stage encapsulates short-circuiting, the next
+                        // stage may not have any short-circuit operations, and
+                        // if so spliterator.forEachRemaining should be used
+                        // for traversal
+                        thisOpFlags = thisOpFlags & ~StreamOpFlag.IS_SHORT_CIRCUIT;
+                    }
+
+                    spliterator = p.opEvaluateParallelLazy(u, spliterator);
+
+                    // Inject or clear SIZED on the source pipeline stage
+                    // based on the stage's spliterator
+                    thisOpFlags = spliterator.hasCharacteristics(Spliterator.SIZED)
+                            ? (thisOpFlags & ~StreamOpFlag.NOT_SIZED) | StreamOpFlag.IS_SIZED
+                            : (thisOpFlags & ~StreamOpFlag.IS_SIZED) | StreamOpFlag.NOT_SIZED;
+                }
+                p.depth = depth++;
+                p.combinedFlags = StreamOpFlag.combineOpFlags(thisOpFlags, u.combinedFlags);
+            }
+        }
+
+        if (terminalFlags != 0)  {
+            // Apply flags from the terminal operation to last pipeline stage
+            combinedFlags = StreamOpFlag.combineOpFlags(terminalFlags, combinedFlags);
+        }
+
+        return spliterator;
+    }
+
+    // PipelineHelper
+
+    @Override
+    final StreamShape getSourceShape() {
+        @SuppressWarnings("rawtypes")
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+        return p.getOutputShape();
+    }
+
+    @Override
+    final <P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator) {
+        return StreamOpFlag.SIZED.isKnown(getStreamAndOpFlags()) ? spliterator.getExactSizeIfKnown() : -1;
+    }
+
+    @Override
+    final <P_IN, S extends Sink<E_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator) {
+        copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
+        return sink;
+    }
+
+    @Override
+    final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
+        Objects.requireNonNull(wrappedSink);
+
+        if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
+            wrappedSink.begin(spliterator.getExactSizeIfKnown());
+            spliterator.forEachRemaining(wrappedSink);
+            wrappedSink.end();
+        }
+        else {
+            copyIntoWithCancel(wrappedSink, spliterator);
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    final <P_IN> void copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
+        @SuppressWarnings({"rawtypes","unchecked"})
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+        wrappedSink.begin(spliterator.getExactSizeIfKnown());
+        p.forEachWithCancel(spliterator, wrappedSink);
+        wrappedSink.end();
+    }
+
+    @Override
+    // Android-changed: Made public for CTS tests only.
+    public final int getStreamAndOpFlags() {
+        return combinedFlags;
+    }
+
+    final boolean isOrdered() {
+        return StreamOpFlag.ORDERED.isKnown(combinedFlags);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
+        Objects.requireNonNull(sink);
+
+        for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
+            sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
+        }
+        return (Sink<P_IN>) sink;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    final <P_IN> Spliterator<E_OUT> wrapSpliterator(Spliterator<P_IN> sourceSpliterator) {
+        if (depth == 0) {
+            return (Spliterator<E_OUT>) sourceSpliterator;
+        }
+        else {
+            return wrap(this, () -> sourceSpliterator, isParallel());
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public final <P_IN> Node<E_OUT> evaluate(Spliterator<P_IN> spliterator,
+                                      boolean flatten,
+                                      IntFunction<E_OUT[]> generator) {
+        if (isParallel()) {
+            // @@@ Optimize if op of this pipeline stage is a stateful op
+            return evaluateToNode(this, spliterator, flatten, generator);
+        }
+        else {
+            Node.Builder<E_OUT> nb = makeNodeBuilder(
+                    exactOutputSizeIfKnown(spliterator), generator);
+            return wrapAndCopyInto(nb, spliterator).build();
+        }
+    }
+
+
+    // Shape-specific abstract methods, implemented by XxxPipeline classes
+
+    /**
+     * Get the output shape of the pipeline.  If the pipeline is the head,
+     * then it's output shape corresponds to the shape of the source.
+     * Otherwise, it's output shape corresponds to the output shape of the
+     * associated operation.
+     *
+     * @return the output shape
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract StreamShape getOutputShape();
+
+    /**
+     * Collect elements output from a pipeline into a Node that holds elements
+     * of this shape.
+     *
+     * @param helper the pipeline helper describing the pipeline stages
+     * @param spliterator the source spliterator
+     * @param flattenTree true if the returned node should be flattened
+     * @param generator the array generator
+     * @return a Node holding the output of the pipeline
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract <P_IN> Node<E_OUT> evaluateToNode(PipelineHelper<E_OUT> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      boolean flattenTree,
+                                                      IntFunction<E_OUT[]> generator);
+
+    /**
+     * Create a spliterator that wraps a source spliterator, compatible with
+     * this stream shape, and operations associated with a {@link
+     * PipelineHelper}.
+     *
+     * @param ph the pipeline helper describing the pipeline stages
+     * @param supplier the supplier of a spliterator
+     * @return a wrapping spliterator compatible with this shape
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract <P_IN> Spliterator<E_OUT> wrap(PipelineHelper<E_OUT> ph,
+                                                   Supplier<Spliterator<P_IN>> supplier,
+                                                   boolean isParallel);
+
+    /**
+     * Create a lazy spliterator that wraps and obtains the supplied the
+     * spliterator when a method is invoked on the lazy spliterator.
+     * @param supplier the supplier of a spliterator
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract Spliterator<E_OUT> lazySpliterator(Supplier<? extends Spliterator<E_OUT>> supplier);
+
+    /**
+     * Traverse the elements of a spliterator compatible with this stream shape,
+     * pushing those elements into a sink.   If the sink requests cancellation,
+     * no further elements will be pulled or pushed.
+     *
+     * @param spliterator the spliterator to pull elements from
+     * @param sink the sink to push elements to
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract void forEachWithCancel(Spliterator<E_OUT> spliterator, Sink<E_OUT> sink);
+
+    /**
+     * Make a node builder compatible with this stream shape.
+     *
+     * @param exactSizeIfKnown if {@literal >=0}, then a node builder will be
+     * created that has a fixed capacity of at most sizeIfKnown elements. If
+     * {@literal < 0}, then the node builder has an unfixed capacity. A fixed
+     * capacity node builder will throw exceptions if an element is added after
+     * builder has reached capacity, or is built before the builder has reached
+     * capacity.
+     *
+     * @param generator the array generator to be used to create instances of a
+     * T[] array. For implementations supporting primitive nodes, this parameter
+     * may be ignored.
+     * @return a node builder
+     */
+    @Override
+    // Android-changed: Made public for CTS tests only.
+    public abstract Node.Builder<E_OUT> makeNodeBuilder(long exactSizeIfKnown,
+                                                        IntFunction<E_OUT[]> generator);
+
+
+    // Op-specific abstract methods, implemented by the operation class
+
+    /**
+     * Returns whether this operation is stateful or not.  If it is stateful,
+     * then the method
+     * {@link #opEvaluateParallel(PipelineHelper, java.util.Spliterator, java.util.function.IntFunction)}
+     * must be overridden.
+     *
+     * @return {@code true} if this operation is stateful
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract boolean opIsStateful();
+
+    /**
+     * Accepts a {@code Sink} which will receive the results of this operation,
+     * and return a {@code Sink} which accepts elements of the input type of
+     * this operation and which performs the operation, passing the results to
+     * the provided {@code Sink}.
+     *
+     * @apiNote
+     * The implementation may use the {@code flags} parameter to optimize the
+     * sink wrapping.  For example, if the input is already {@code DISTINCT},
+     * the implementation for the {@code Stream#distinct()} method could just
+     * return the sink it was passed.
+     *
+     * @param flags The combined stream and operation flags up to, but not
+     *        including, this operation
+     * @param sink sink to which elements should be sent after processing
+     * @return a sink which accepts elements, perform the operation upon
+     *         each element, and passes the results (if any) to the provided
+     *         {@code Sink}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink);
+
+    /**
+     * Performs a parallel evaluation of the operation using the specified
+     * {@code PipelineHelper} which describes the upstream intermediate
+     * operations.  Only called on stateful operations.  If {@link
+     * #opIsStateful()} returns true then implementations must override the
+     * default implementation.
+     *
+     * @implSpec The default implementation always throw
+     * {@code UnsupportedOperationException}.
+     *
+     * @param helper the pipeline helper describing the pipeline stages
+     * @param spliterator the source {@code Spliterator}
+     * @param generator the array generator
+     * @return a {@code Node} describing the result of the evaluation
+     */
+    // Android-changed: Made public for CTS tests only.
+    public <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
+                                          Spliterator<P_IN> spliterator,
+                                          IntFunction<E_OUT[]> generator) {
+        throw new UnsupportedOperationException("Parallel evaluation is not supported");
+    }
+
+    /**
+     * Returns a {@code Spliterator} describing a parallel evaluation of the
+     * operation, using the specified {@code PipelineHelper} which describes the
+     * upstream intermediate operations.  Only called on stateful operations.
+     * It is not necessary (though acceptable) to do a full computation of the
+     * result here; it is preferable, if possible, to describe the result via a
+     * lazily evaluated spliterator.
+     *
+     * @implSpec The default implementation behaves as if:
+     * <pre>{@code
+     *     return evaluateParallel(helper, i -> (E_OUT[]) new
+     * Object[i]).spliterator();
+     * }</pre>
+     * and is suitable for implementations that cannot do better than a full
+     * synchronous evaluation.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source {@code Spliterator}
+     * @return a {@code Spliterator} describing the result of the evaluation
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public <P_IN> Spliterator<E_OUT> opEvaluateParallelLazy(PipelineHelper<E_OUT> helper,
+                                                     Spliterator<P_IN> spliterator) {
+        return opEvaluateParallel(helper, spliterator, i -> (E_OUT[]) new Object[i]).spliterator();
+    }
+}
diff --git a/java/util/stream/AbstractShortCircuitTask.java b/java/util/stream/AbstractShortCircuitTask.java
new file mode 100644
index 0000000..bbf09f0
--- /dev/null
+++ b/java/util/stream/AbstractShortCircuitTask.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Abstract class for fork-join tasks used to implement short-circuiting
+ * stream ops, which can produce a result without processing all elements of the
+ * stream.
+ *
+ * @param <P_IN> type of input elements to the pipeline
+ * @param <P_OUT> type of output elements from the pipeline
+ * @param <R> type of intermediate result, may be different from operation
+ *        result type
+ * @param <K> type of child and sibling tasks
+ * @since 1.8
+ */
+@SuppressWarnings("serial")
+abstract class AbstractShortCircuitTask<P_IN, P_OUT, R,
+                                        K extends AbstractShortCircuitTask<P_IN, P_OUT, R, K>>
+        extends AbstractTask<P_IN, P_OUT, R, K> {
+    /**
+     * The result for this computation; this is shared among all tasks and set
+     * exactly once
+     */
+    protected final AtomicReference<R> sharedResult;
+
+    /**
+     * Indicates whether this task has been canceled.  Tasks may cancel other
+     * tasks in the computation under various conditions, such as in a
+     * find-first operation, a task that finds a value will cancel all tasks
+     * that are later in the encounter order.
+     */
+    protected volatile boolean canceled;
+
+    /**
+     * Constructor for root tasks.
+     *
+     * @param helper the {@code PipelineHelper} describing the stream pipeline
+     *               up to this operation
+     * @param spliterator the {@code Spliterator} describing the source for this
+     *                    pipeline
+     */
+    protected AbstractShortCircuitTask(PipelineHelper<P_OUT> helper,
+                                       Spliterator<P_IN> spliterator) {
+        super(helper, spliterator);
+        sharedResult = new AtomicReference<>(null);
+    }
+
+    /**
+     * Constructor for non-root nodes.
+     *
+     * @param parent parent task in the computation tree
+     * @param spliterator the {@code Spliterator} for the portion of the
+     *                    computation tree described by this task
+     */
+    protected AbstractShortCircuitTask(K parent,
+                                       Spliterator<P_IN> spliterator) {
+        super(parent, spliterator);
+        sharedResult = parent.sharedResult;
+    }
+
+    /**
+     * Returns the value indicating the computation completed with no task
+     * finding a short-circuitable result.  For example, for a "find" operation,
+     * this might be null or an empty {@code Optional}.
+     *
+     * @return the result to return when no task finds a result
+     */
+    protected abstract R getEmptyResult();
+
+    /**
+     * Overrides AbstractTask version to include checks for early
+     * exits while splitting or computing.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> rs = spliterator, ls;
+        long sizeEstimate = rs.estimateSize();
+        long sizeThreshold = getTargetSize(sizeEstimate);
+        boolean forkRight = false;
+        @SuppressWarnings("unchecked") K task = (K) this;
+        AtomicReference<R> sr = sharedResult;
+        R result;
+        while ((result = sr.get()) == null) {
+            if (task.taskCanceled()) {
+                result = task.getEmptyResult();
+                break;
+            }
+            if (sizeEstimate <= sizeThreshold || (ls = rs.trySplit()) == null) {
+                result = task.doLeaf();
+                break;
+            }
+            K leftChild, rightChild, taskToFork;
+            task.leftChild  = leftChild = task.makeChild(ls);
+            task.rightChild = rightChild = task.makeChild(rs);
+            task.setPendingCount(1);
+            if (forkRight) {
+                forkRight = false;
+                rs = ls;
+                task = leftChild;
+                taskToFork = rightChild;
+            }
+            else {
+                forkRight = true;
+                task = rightChild;
+                taskToFork = leftChild;
+            }
+            taskToFork.fork();
+            sizeEstimate = rs.estimateSize();
+        }
+        task.setLocalResult(result);
+        task.tryComplete();
+    }
+
+
+    /**
+     * Declares that a globally valid result has been found.  If another task has
+     * not already found the answer, the result is installed in
+     * {@code sharedResult}.  The {@code compute()} method will check
+     * {@code sharedResult} before proceeding with computation, so this causes
+     * the computation to terminate early.
+     *
+     * @param result the result found
+     */
+    protected void shortCircuit(R result) {
+        if (result != null)
+            sharedResult.compareAndSet(null, result);
+    }
+
+    /**
+     * Sets a local result for this task.  If this task is the root, set the
+     * shared result instead (if not already set).
+     *
+     * @param localResult The result to set for this task
+     */
+    @Override
+    protected void setLocalResult(R localResult) {
+        if (isRoot()) {
+            if (localResult != null)
+                sharedResult.compareAndSet(null, localResult);
+        }
+        else
+            super.setLocalResult(localResult);
+    }
+
+    /**
+     * Retrieves the local result for this task
+     */
+    @Override
+    public R getRawResult() {
+        return getLocalResult();
+    }
+
+    /**
+     * Retrieves the local result for this task.  If this task is the root,
+     * retrieves the shared result instead.
+     */
+    @Override
+    public R getLocalResult() {
+        if (isRoot()) {
+            R answer = sharedResult.get();
+            return (answer == null) ? getEmptyResult() : answer;
+        }
+        else
+            return super.getLocalResult();
+    }
+
+    /**
+     * Mark this task as canceled
+     */
+    protected void cancel() {
+        canceled = true;
+    }
+
+    /**
+     * Queries whether this task is canceled.  A task is considered canceled if
+     * it or any of its parents have been canceled.
+     *
+     * @return {@code true} if this task or any parent is canceled.
+     */
+    protected boolean taskCanceled() {
+        boolean cancel = canceled;
+        if (!cancel) {
+            for (K parent = getParent(); !cancel && parent != null; parent = parent.getParent())
+                cancel = parent.canceled;
+        }
+
+        return cancel;
+    }
+
+    /**
+     * Cancels all tasks which succeed this one in the encounter order.  This
+     * includes canceling all the current task's right sibling, as well as the
+     * later right siblings of all its parents.
+     */
+    protected void cancelLaterNodes() {
+        // Go up the tree, cancel right siblings of this node and all parents
+        for (@SuppressWarnings("unchecked") K parent = getParent(), node = (K) this;
+             parent != null;
+             node = parent, parent = parent.getParent()) {
+            // If node is a left child of parent, then has a right sibling
+            if (parent.leftChild == node) {
+                K rightSibling = parent.rightChild;
+                if (!rightSibling.canceled)
+                    rightSibling.cancel();
+            }
+        }
+    }
+}
diff --git a/java/util/stream/AbstractSpinedBuffer.java b/java/util/stream/AbstractSpinedBuffer.java
new file mode 100644
index 0000000..46fdf4d
--- /dev/null
+++ b/java/util/stream/AbstractSpinedBuffer.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Base class for a data structure for gathering elements into a buffer and then
+ * iterating them. Maintains an array of increasingly sized arrays, so there is
+ * no copying cost associated with growing the data structure.
+ * @since 1.8
+ */
+abstract class AbstractSpinedBuffer {
+    /**
+     * Minimum power-of-two for the first chunk.
+     */
+    public static final int MIN_CHUNK_POWER = 4;
+
+    /**
+     * Minimum size for the first chunk.
+     */
+    public static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_POWER;
+
+    /**
+     * Max power-of-two for chunks.
+     */
+    public static final int MAX_CHUNK_POWER = 30;
+
+    /**
+     * Minimum array size for array-of-chunks.
+     */
+    public static final int MIN_SPINE_SIZE = 8;
+
+
+    /**
+     * log2 of the size of the first chunk.
+     */
+    protected final int initialChunkPower;
+
+    /**
+     * Index of the *next* element to write; may point into, or just outside of,
+     * the current chunk.
+     */
+    protected int elementIndex;
+
+    /**
+     * Index of the *current* chunk in the spine array, if the spine array is
+     * non-null.
+     */
+    protected int spineIndex;
+
+    /**
+     * Count of elements in all prior chunks.
+     */
+    protected long[] priorElementCount;
+
+    /**
+     * Construct with an initial capacity of 16.
+     */
+    protected AbstractSpinedBuffer() {
+        this.initialChunkPower = MIN_CHUNK_POWER;
+    }
+
+    /**
+     * Construct with a specified initial capacity.
+     *
+     * @param initialCapacity The minimum expected number of elements
+     */
+    protected AbstractSpinedBuffer(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
+
+        this.initialChunkPower = Math.max(MIN_CHUNK_POWER,
+                                          Integer.SIZE - Integer.numberOfLeadingZeros(initialCapacity - 1));
+    }
+
+    /**
+     * Is the buffer currently empty?
+     */
+    public boolean isEmpty() {
+        return (spineIndex == 0) && (elementIndex == 0);
+    }
+
+    /**
+     * How many elements are currently in the buffer?
+     */
+    public long count() {
+        return (spineIndex == 0)
+               ? elementIndex
+               : priorElementCount[spineIndex] + elementIndex;
+    }
+
+    /**
+     * How big should the nth chunk be?
+     */
+    protected int chunkSize(int n) {
+        int power = (n == 0 || n == 1)
+                    ? initialChunkPower
+                    : Math.min(initialChunkPower + n - 1, AbstractSpinedBuffer.MAX_CHUNK_POWER);
+        return 1 << power;
+    }
+
+    /**
+     * Remove all data from the buffer
+     */
+    public abstract void clear();
+}
diff --git a/java/util/stream/AbstractTask.java b/java/util/stream/AbstractTask.java
new file mode 100644
index 0000000..33de7d5
--- /dev/null
+++ b/java/util/stream/AbstractTask.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+
+/**
+ * Abstract base class for most fork-join tasks used to implement stream ops.
+ * Manages splitting logic, tracking of child tasks, and intermediate results.
+ * Each task is associated with a {@link Spliterator} that describes the portion
+ * of the input associated with the subtree rooted at this task.
+ * Tasks may be leaf nodes (which will traverse the elements of
+ * the {@code Spliterator}) or internal nodes (which split the
+ * {@code Spliterator} into multiple child tasks).
+ *
+ * @implNote
+ * <p>This class is based on {@link CountedCompleter}, a form of fork-join task
+ * where each task has a semaphore-like count of uncompleted children, and the
+ * task is implicitly completed and notified when its last child completes.
+ * Internal node tasks will likely override the {@code onCompletion} method from
+ * {@code CountedCompleter} to merge the results from child tasks into the
+ * current task's result.
+ *
+ * <p>Splitting and setting up the child task links is done by {@code compute()}
+ * for internal nodes.  At {@code compute()} time for leaf nodes, it is
+ * guaranteed that the parent's child-related fields (including sibling links
+ * for the parent's children) will be set up for all children.
+ *
+ * <p>For example, a task that performs a reduce would override {@code doLeaf()}
+ * to perform a reduction on that leaf node's chunk using the
+ * {@code Spliterator}, and override {@code onCompletion()} to merge the results
+ * of the child tasks for internal nodes:
+ *
+ * <pre>{@code
+ *     protected S doLeaf() {
+ *         spliterator.forEach(...);
+ *         return localReductionResult;
+ *     }
+ *
+ *     public void onCompletion(CountedCompleter caller) {
+ *         if (!isLeaf()) {
+ *             ReduceTask<P_IN, P_OUT, T, R> child = children;
+ *             R result = child.getLocalResult();
+ *             child = child.nextSibling;
+ *             for (; child != null; child = child.nextSibling)
+ *                 result = combine(result, child.getLocalResult());
+ *             setLocalResult(result);
+ *         }
+ *     }
+ * }</pre>
+ *
+ * <p>Serialization is not supported as there is no intention to serialize
+ * tasks managed by stream ops.
+ *
+ * @param <P_IN> Type of elements input to the pipeline
+ * @param <P_OUT> Type of elements output from the pipeline
+ * @param <R> Type of intermediate result, which may be different from operation
+ *        result type
+ * @param <K> Type of parent, child and sibling tasks
+ * @since 1.8
+ */
+@SuppressWarnings("serial")
+abstract class AbstractTask<P_IN, P_OUT, R,
+                            K extends AbstractTask<P_IN, P_OUT, R, K>>
+        extends CountedCompleter<R> {
+
+    /**
+     * Default target factor of leaf tasks for parallel decomposition.
+     * To allow load balancing, we over-partition, currently to approximately
+     * four tasks per processor, which enables others to help out
+     * if leaf tasks are uneven or some processors are otherwise busy.
+     */
+    static final int LEAF_TARGET = ForkJoinPool.getCommonPoolParallelism() << 2;
+
+    /** The pipeline helper, common to all tasks in a computation */
+    protected final PipelineHelper<P_OUT> helper;
+
+    /**
+     * The spliterator for the portion of the input associated with the subtree
+     * rooted at this task
+     */
+    protected Spliterator<P_IN> spliterator;
+
+    /** Target leaf size, common to all tasks in a computation */
+    protected long targetSize; // may be laziliy initialized
+
+    /**
+     * The left child.
+     * null if no children
+     * if non-null rightChild is non-null
+     */
+    protected K leftChild;
+
+    /**
+     * The right child.
+     * null if no children
+     * if non-null leftChild is non-null
+     */
+    protected K rightChild;
+
+    /** The result of this node, if completed */
+    private R localResult;
+
+    /**
+     * Constructor for root nodes.
+     *
+     * @param helper The {@code PipelineHelper} describing the stream pipeline
+     *               up to this operation
+     * @param spliterator The {@code Spliterator} describing the source for this
+     *                    pipeline
+     */
+    protected AbstractTask(PipelineHelper<P_OUT> helper,
+                           Spliterator<P_IN> spliterator) {
+        super(null);
+        this.helper = helper;
+        this.spliterator = spliterator;
+        this.targetSize = 0L;
+    }
+
+    /**
+     * Constructor for non-root nodes.
+     *
+     * @param parent this node's parent task
+     * @param spliterator {@code Spliterator} describing the subtree rooted at
+     *        this node, obtained by splitting the parent {@code Spliterator}
+     */
+    protected AbstractTask(K parent,
+                           Spliterator<P_IN> spliterator) {
+        super(parent);
+        this.spliterator = spliterator;
+        this.helper = parent.helper;
+        this.targetSize = parent.targetSize;
+    }
+
+    /**
+     * Constructs a new node of type T whose parent is the receiver; must call
+     * the AbstractTask(T, Spliterator) constructor with the receiver and the
+     * provided Spliterator.
+     *
+     * @param spliterator {@code Spliterator} describing the subtree rooted at
+     *        this node, obtained by splitting the parent {@code Spliterator}
+     * @return newly constructed child node
+     */
+    protected abstract K makeChild(Spliterator<P_IN> spliterator);
+
+    /**
+     * Computes the result associated with a leaf node.  Will be called by
+     * {@code compute()} and the result passed to @{code setLocalResult()}
+     *
+     * @return the computed result of a leaf node
+     */
+    protected abstract R doLeaf();
+
+    /**
+     * Returns a suggested target leaf size based on the initial size estimate.
+     *
+     * @return suggested target leaf size
+     */
+    public static long suggestTargetSize(long sizeEstimate) {
+        long est = sizeEstimate / LEAF_TARGET;
+        return est > 0L ? est : 1L;
+    }
+
+    /**
+     * Returns the targetSize, initializing it via the supplied
+     * size estimate if not already initialized.
+     */
+    protected final long getTargetSize(long sizeEstimate) {
+        long s;
+        return ((s = targetSize) != 0 ? s :
+                (targetSize = suggestTargetSize(sizeEstimate)));
+    }
+
+    /**
+     * Returns the local result, if any. Subclasses should use
+     * {@link #setLocalResult(Object)} and {@link #getLocalResult()} to manage
+     * results.  This returns the local result so that calls from within the
+     * fork-join framework will return the correct result.
+     *
+     * @return local result for this node previously stored with
+     * {@link #setLocalResult}
+     */
+    @Override
+    public R getRawResult() {
+        return localResult;
+    }
+
+    /**
+     * Does nothing; instead, subclasses should use
+     * {@link #setLocalResult(Object)}} to manage results.
+     *
+     * @param result must be null, or an exception is thrown (this is a safety
+     *        tripwire to detect when {@code setRawResult()} is being used
+     *        instead of {@code setLocalResult()}
+     */
+    @Override
+    protected void setRawResult(R result) {
+        if (result != null)
+            throw new IllegalStateException();
+    }
+
+    /**
+     * Retrieves a result previously stored with {@link #setLocalResult}
+     *
+     * @return local result for this node previously stored with
+     * {@link #setLocalResult}
+     */
+    protected R getLocalResult() {
+        return localResult;
+    }
+
+    /**
+     * Associates the result with the task, can be retrieved with
+     * {@link #getLocalResult}
+     *
+     * @param localResult local result for this node
+     */
+    protected void setLocalResult(R localResult) {
+        this.localResult = localResult;
+    }
+
+    /**
+     * Indicates whether this task is a leaf node.  (Only valid after
+     * {@link #compute} has been called on this node).  If the node is not a
+     * leaf node, then children will be non-null and numChildren will be
+     * positive.
+     *
+     * @return {@code true} if this task is a leaf node
+     */
+    protected boolean isLeaf() {
+        return leftChild == null;
+    }
+
+    /**
+     * Indicates whether this task is the root node
+     *
+     * @return {@code true} if this task is the root node.
+     */
+    protected boolean isRoot() {
+        return getParent() == null;
+    }
+
+    /**
+     * Returns the parent of this task, or null if this task is the root
+     *
+     * @return the parent of this task, or null if this task is the root
+     */
+    @SuppressWarnings("unchecked")
+    protected K getParent() {
+        return (K) getCompleter();
+    }
+
+    /**
+     * Decides whether or not to split a task further or compute it
+     * directly. If computing directly, calls {@code doLeaf} and pass
+     * the result to {@code setRawResult}. Otherwise splits off
+     * subtasks, forking one and continuing as the other.
+     *
+     * <p> The method is structured to conserve resources across a
+     * range of uses.  The loop continues with one of the child tasks
+     * when split, to avoid deep recursion. To cope with spliterators
+     * that may be systematically biased toward left-heavy or
+     * right-heavy splits, we alternate which child is forked versus
+     * continued in the loop.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> rs = spliterator, ls; // right, left spliterators
+        long sizeEstimate = rs.estimateSize();
+        long sizeThreshold = getTargetSize(sizeEstimate);
+        boolean forkRight = false;
+        @SuppressWarnings("unchecked") K task = (K) this;
+        while (sizeEstimate > sizeThreshold && (ls = rs.trySplit()) != null) {
+            K leftChild, rightChild, taskToFork;
+            task.leftChild  = leftChild = task.makeChild(ls);
+            task.rightChild = rightChild = task.makeChild(rs);
+            task.setPendingCount(1);
+            if (forkRight) {
+                forkRight = false;
+                rs = ls;
+                task = leftChild;
+                taskToFork = rightChild;
+            }
+            else {
+                forkRight = true;
+                task = rightChild;
+                taskToFork = leftChild;
+            }
+            taskToFork.fork();
+            sizeEstimate = rs.estimateSize();
+        }
+        task.setLocalResult(task.doLeaf());
+        task.tryComplete();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote
+     * Clears spliterator and children fields.  Overriders MUST call
+     * {@code super.onCompletion} as the last thing they do if they want these
+     * cleared.
+     */
+    @Override
+    public void onCompletion(CountedCompleter<?> caller) {
+        spliterator = null;
+        leftChild = rightChild = null;
+    }
+
+    /**
+     * Returns whether this node is a "leftmost" node -- whether the path from
+     * the root to this node involves only traversing leftmost child links.  For
+     * a leaf node, this means it is the first leaf node in the encounter order.
+     *
+     * @return {@code true} if this node is a "leftmost" node
+     */
+    protected boolean isLeftmostNode() {
+        @SuppressWarnings("unchecked")
+        K node = (K) this;
+        while (node != null) {
+            K parent = node.getParent();
+            if (parent != null && parent.leftChild != node)
+                return false;
+            node = parent;
+        }
+        return true;
+    }
+}
diff --git a/java/util/stream/BaseStream.java b/java/util/stream/BaseStream.java
new file mode 100644
index 0000000..35d46e0
--- /dev/null
+++ b/java/util/stream/BaseStream.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
+
+/**
+ * Base interface for streams, which are sequences of elements supporting
+ * sequential and parallel aggregate operations.  The following example
+ * illustrates an aggregate operation using the stream types {@link Stream}
+ * and {@link IntStream}, computing the sum of the weights of the red widgets:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism, which governs the behavior of all stream types.
+ *
+ * @param <T> the type of the stream elements
+ * @param <S> the type of of the stream implementing {@code BaseStream}
+ * @since 1.8
+ * @see Stream
+ * @see IntStream
+ * @see LongStream
+ * @see DoubleStream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface BaseStream<T, S extends BaseStream<T, S>>
+        extends AutoCloseable {
+    /**
+     * Returns an iterator for the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the element iterator for this stream
+     */
+    Iterator<T> iterator();
+
+    /**
+     * Returns a spliterator for the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the element spliterator for this stream
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     * Returns whether this stream, if a terminal operation were to be executed,
+     * would execute in parallel.  Calling this method after invoking an
+     * terminal stream operation method may yield unpredictable results.
+     *
+     * @return {@code true} if this stream would execute in parallel if executed
+     */
+    boolean isParallel();
+
+    /**
+     * Returns an equivalent stream that is sequential.  May return
+     * itself, either because the stream was already sequential, or because
+     * the underlying stream state was modified to be sequential.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a sequential stream
+     */
+    S sequential();
+
+    /**
+     * Returns an equivalent stream that is parallel.  May return
+     * itself, either because the stream was already parallel, or because
+     * the underlying stream state was modified to be parallel.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a parallel stream
+     */
+    S parallel();
+
+    /**
+     * Returns an equivalent stream that is
+     * <a href="package-summary.html#Ordering">unordered</a>.  May return
+     * itself, either because the stream was already unordered, or because
+     * the underlying stream state was modified to be unordered.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return an unordered stream
+     */
+    S unordered();
+
+    /**
+     * Returns an equivalent stream with an additional close handler.  Close
+     * handlers are run when the {@link #close()} method
+     * is called on the stream, and are executed in the order they were
+     * added.  All close handlers are run, even if earlier close handlers throw
+     * exceptions.  If any close handler throws an exception, the first
+     * exception thrown will be relayed to the caller of {@code close()}, with
+     * any remaining exceptions added to that exception as suppressed exceptions
+     * (unless one of the remaining exceptions is the same exception as the
+     * first exception, since an exception cannot suppress itself.)  May
+     * return itself.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param closeHandler A task to execute when the stream is closed
+     * @return a stream with a handler that is run if the stream is closed
+     */
+    S onClose(Runnable closeHandler);
+
+    /**
+     * Closes this stream, causing all close handlers for this stream pipeline
+     * to be called.
+     *
+     * @see AutoCloseable#close()
+     */
+    @Override
+    void close();
+}
diff --git a/java/util/stream/Collector.java b/java/util/stream/Collector.java
new file mode 100644
index 0000000..e409d56
--- /dev/null
+++ b/java/util/stream/Collector.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
+ * accumulates input elements into a mutable result container, optionally transforming
+ * the accumulated result into a final representation after all input elements
+ * have been processed.  Reduction operations can be performed either sequentially
+ * or in parallel.
+ *
+ * <p>Examples of mutable reduction operations include:
+ * accumulating elements into a {@code Collection}; concatenating
+ * strings using a {@code StringBuilder}; computing summary information about
+ * elements such as sum, min, max, or average; computing "pivot table" summaries
+ * such as "maximum valued transaction by seller", etc.  The class {@link Collectors}
+ * provides implementations of many common mutable reductions.
+ *
+ * <p>A {@code Collector} is specified by four functions that work together to
+ * accumulate entries into a mutable result container, and optionally perform
+ * a final transform on the result.  They are: <ul>
+ *     <li>creation of a new result container ({@link #supplier()})</li>
+ *     <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
+ *     <li>combining two result containers into one ({@link #combiner()})</li>
+ *     <li>performing an optional final transform on the container ({@link #finisher()})</li>
+ * </ul>
+ *
+ * <p>Collectors also have a set of characteristics, such as
+ * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
+ * reduction implementation to provide better performance.
+ *
+ * <p>A sequential implementation of a reduction using a collector would
+ * create a single result container using the supplier function, and invoke the
+ * accumulator function once for each input element.  A parallel implementation
+ * would partition the input, create a result container for each partition,
+ * accumulate the contents of each partition into a subresult for that partition,
+ * and then use the combiner function to merge the subresults into a combined
+ * result.
+ *
+ * <p>To ensure that sequential and parallel executions produce equivalent
+ * results, the collector functions must satisfy an <em>identity</em> and an
+ * <a href="package-summary.html#Associativity">associativity</a> constraints.
+ *
+ * <p>The identity constraint says that for any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result.  That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>The associativity constraint says that splitting the computation must
+ * produce an equivalent result.  That is, for any input elements {@code t1}
+ * and {@code t2}, the results {@code r1} and {@code r2} in the computation
+ * below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * } </pre>
+ *
+ * <p>For collectors that do not have the {@code UNORDERED} characteristic,
+ * two accumulated results {@code a1} and {@code a2} are equivalent if
+ * {@code finisher.apply(a1).equals(finisher.apply(a2))}.  For unordered
+ * collectors, equivalence is relaxed to allow for non-equality related to
+ * differences in order.  (For example, an unordered collector that accumulated
+ * elements to a {@code List} would consider two lists equivalent if they
+ * contained the same elements, ignoring order.)
+ *
+ * <p>Libraries that implement reduction based on {@code Collector}, such as
+ * {@link Stream#collect(Collector)}, must adhere to the following constraints:
+ * <ul>
+ *     <li>The first argument passed to the accumulator function, both
+ *     arguments passed to the combiner function, and the argument passed to the
+ *     finisher function must be the result of a previous invocation of the
+ *     result supplier, accumulator, or combiner functions.</li>
+ *     <li>The implementation should not do anything with the result of any of
+ *     the result supplier, accumulator, or combiner functions other than to
+ *     pass them again to the accumulator, combiner, or finisher functions,
+ *     or return them to the caller of the reduction operation.</li>
+ *     <li>If a result is passed to the combiner or finisher
+ *     function, and the same object is not returned from that function, it is
+ *     never used again.</li>
+ *     <li>Once a result is passed to the combiner or finisher function, it
+ *     is never passed to the accumulator function again.</li>
+ *     <li>For non-concurrent collectors, any result returned from the result
+ *     supplier, accumulator, or combiner functions must be serially
+ *     thread-confined.  This enables collection to occur in parallel without
+ *     the {@code Collector} needing to implement any additional synchronization.
+ *     The reduction implementation must manage that the input is properly
+ *     partitioned, that partitions are processed in isolation, and combining
+ *     happens only after accumulation is complete.</li>
+ *     <li>For concurrent collectors, an implementation is free to (but not
+ *     required to) implement reduction concurrently.  A concurrent reduction
+ *     is one where the accumulator function is called concurrently from
+ *     multiple threads, using the same concurrently-modifiable result container,
+ *     rather than keeping the result isolated during accumulation.
+ *     A concurrent reduction should only be applied if the collector has the
+ *     {@link Characteristics#UNORDERED} characteristics or if the
+ *     originating data is unordered.</li>
+ * </ul>
+ *
+ * <p>In addition to the predefined implementations in {@link Collectors}, the
+ * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
+ * can be used to construct collectors.  For example, you could create a collector
+ * that accumulates widgets into a {@code TreeSet} with:
+ *
+ * <pre>{@code
+ *     Collector<Widget, ?, TreeSet<Widget>> intoSet =
+ *         Collector.of(TreeSet::new, TreeSet::add,
+ *                      (left, right) -> { left.addAll(right); return left; });
+ * }</pre>
+ *
+ * (This behavior is also implemented by the predefined collector
+ * {@link Collectors#toCollection(Supplier)}).
+ *
+ * @apiNote
+ * Performing a reduction operation with a {@code Collector} should produce a
+ * result equivalent to:
+ * <pre>{@code
+ *     R container = collector.supplier().get();
+ *     for (T t : data)
+ *         collector.accumulator().accept(container, t);
+ *     return collector.finisher().apply(container);
+ * }</pre>
+ *
+ * <p>However, the library is free to partition the input, perform the reduction
+ * on the partitions, and then use the combiner function to combine the partial
+ * results to achieve a parallel reduction.  (Depending on the specific reduction
+ * operation, this may perform better or worse, depending on the relative cost
+ * of the accumulator and combiner functions.)
+ *
+ * <p>Collectors are designed to be <em>composed</em>; many of the methods
+ * in {@link Collectors} are functions that take a collector and produce
+ * a new collector.  For example, given the following collector that computes
+ * the sum of the salaries of a stream of employees:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary))
+ * }</pre>
+ *
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse the "sum of salaries" logic using
+ * {@link Collectors#groupingBy(Function, Collector)}:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
+ *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
+ * }</pre>
+ *
+ * @see Stream#collect(Collector)
+ * @see Collectors
+ *
+ * @param <T> the type of input elements to the reduction operation
+ * @param <A> the mutable accumulation type of the reduction operation (often
+ *            hidden as an implementation detail)
+ * @param <R> the result type of the reduction operation
+ * @since 1.8
+ */
+public interface Collector<T, A, R> {
+    /**
+     * A function that creates and returns a new mutable result container.
+     *
+     * @return a function which returns a new, mutable result container
+     */
+    Supplier<A> supplier();
+
+    /**
+     * A function that folds a value into a mutable result container.
+     *
+     * @return a function which folds a value into a mutable result container
+     */
+    BiConsumer<A, T> accumulator();
+
+    /**
+     * A function that accepts two partial results and merges them.  The
+     * combiner function may fold state from one argument into the other and
+     * return that, or may return a new result container.
+     *
+     * @return a function which combines two partial results into a combined
+     * result
+     */
+    BinaryOperator<A> combiner();
+
+    /**
+     * Perform the final transformation from the intermediate accumulation type
+     * {@code A} to the final result type {@code R}.
+     *
+     * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
+     * set, this function may be presumed to be an identity transform with an
+     * unchecked cast from {@code A} to {@code R}.
+     *
+     * @return a function which transforms the intermediate result to the final
+     * result
+     */
+    Function<A, R> finisher();
+
+    /**
+     * Returns a {@code Set} of {@code Collector.Characteristics} indicating
+     * the characteristics of this Collector.  This set should be immutable.
+     *
+     * @return an immutable set of collector characteristics
+     */
+    Set<Characteristics> characteristics();
+
+    /**
+     * Returns a new {@code Collector} described by the given {@code supplier},
+     * {@code accumulator}, and {@code combiner} functions.  The resulting
+     * {@code Collector} has the {@code Collector.Characteristics.IDENTITY_FINISH}
+     * characteristic.
+     *
+     * @param supplier The supplier function for the new collector
+     * @param accumulator The accumulator function for the new collector
+     * @param combiner The combiner function for the new collector
+     * @param characteristics The collector characteristics for the new
+     *                        collector
+     * @param <T> The type of input elements for the new collector
+     * @param <R> The type of intermediate accumulation result, and final result,
+     *           for the new collector
+     * @throws NullPointerException if any argument is null
+     * @return the new {@code Collector}
+     */
+    public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
+                                              BiConsumer<R, T> accumulator,
+                                              BinaryOperator<R> combiner,
+                                              Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(characteristics);
+        Set<Characteristics> cs = (characteristics.length == 0)
+                                  ? Collectors.CH_ID
+                                  : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
+                                                                           characteristics));
+        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, cs);
+    }
+
+    /**
+     * Returns a new {@code Collector} described by the given {@code supplier},
+     * {@code accumulator}, {@code combiner}, and {@code finisher} functions.
+     *
+     * @param supplier The supplier function for the new collector
+     * @param accumulator The accumulator function for the new collector
+     * @param combiner The combiner function for the new collector
+     * @param finisher The finisher function for the new collector
+     * @param characteristics The collector characteristics for the new
+     *                        collector
+     * @param <T> The type of input elements for the new collector
+     * @param <A> The intermediate accumulation type of the new collector
+     * @param <R> The final result type of the new collector
+     * @throws NullPointerException if any argument is null
+     * @return the new {@code Collector}
+     */
+    public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
+                                                 BiConsumer<A, T> accumulator,
+                                                 BinaryOperator<A> combiner,
+                                                 Function<A, R> finisher,
+                                                 Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(finisher);
+        Objects.requireNonNull(characteristics);
+        Set<Characteristics> cs = Collectors.CH_NOID;
+        if (characteristics.length > 0) {
+            cs = EnumSet.noneOf(Characteristics.class);
+            Collections.addAll(cs, characteristics);
+            cs = Collections.unmodifiableSet(cs);
+        }
+        return new Collectors.CollectorImpl<>(supplier, accumulator, combiner, finisher, cs);
+    }
+
+    /**
+     * Characteristics indicating properties of a {@code Collector}, which can
+     * be used to optimize reduction implementations.
+     */
+    enum Characteristics {
+        /**
+         * Indicates that this collector is <em>concurrent</em>, meaning that
+         * the result container can support the accumulator function being
+         * called concurrently with the same result container from multiple
+         * threads.
+         *
+         * <p>If a {@code CONCURRENT} collector is not also {@code UNORDERED},
+         * then it should only be evaluated concurrently if applied to an
+         * unordered data source.
+         */
+        CONCURRENT,
+
+        /**
+         * Indicates that the collection operation does not commit to preserving
+         * the encounter order of input elements.  (This might be true if the
+         * result container has no intrinsic order, such as a {@link Set}.)
+         */
+        UNORDERED,
+
+        /**
+         * Indicates that the finisher function is the identity function and
+         * can be elided.  If set, it must be the case that an unchecked cast
+         * from A to R will succeed.
+         */
+        IDENTITY_FINISH
+    }
+}
diff --git a/java/util/stream/CollectorOps.java b/java/util/stream/CollectorOps.java
new file mode 100644
index 0000000..c849415
--- /dev/null
+++ b/java/util/stream/CollectorOps.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/** Test helper class for java.util.stream test framework */
+public final class CollectorOps {
+    private CollectorOps() { }
+
+    public static <E_IN> StatefulTestOp<E_IN> collector() {
+        return new StatefulCollector<>(0, StreamShape.REFERENCE);
+    }
+
+    /* Utility classes for collecting output of intermediate pipeline stages */
+    public static class StatefulCollector<E_IN> implements StatefulTestOp<E_IN> {
+        private final int opFlags;
+        private final StreamShape inputShape;
+
+        public StatefulCollector(int opFlags, StreamShape inputShape) {
+            this.opFlags = opFlags;
+            this.inputShape = inputShape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public int opGetFlags() {
+            return opFlags;
+        }
+
+        @Override
+        public Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_IN> sink) {
+            return sink;
+        }
+
+        @Override
+        public <P_IN> Node<E_IN> opEvaluateParallel(PipelineHelper<E_IN> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<E_IN[]> generator) {
+            return helper.evaluate(spliterator, false, generator);
+        }
+    }
+
+    public static class TestParallelSizedOp<T> extends StatefulCollector<T> {
+        public TestParallelSizedOp() {
+            this(StreamShape.REFERENCE);
+        }
+
+        protected TestParallelSizedOp(StreamShape shape) {
+            super(0, shape);
+        }
+
+        @Override
+        public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<T[]> generator) {
+            int flags = helper.getStreamAndOpFlags();
+
+            Assert.assertTrue(StreamOpFlag.SIZED.isKnown(flags));
+            return super.opEvaluateParallel(helper, spliterator, generator);
+        }
+
+        public static class OfInt extends TestParallelSizedOp<Integer> {
+            public OfInt() {
+                super(StreamShape.INT_VALUE);
+            }
+        }
+
+        public static class OfLong extends TestParallelSizedOp<Long> {
+            public OfLong() {
+                super(StreamShape.LONG_VALUE);
+            }
+        }
+
+        public static class OfDouble extends TestParallelSizedOp<Double> {
+            public OfDouble() {
+                super(StreamShape.DOUBLE_VALUE);
+            }
+        }
+    }
+}
diff --git a/java/util/stream/Collectors.java b/java/util/stream/Collectors.java
new file mode 100644
index 0000000..a338ec2
--- /dev/null
+++ b/java/util/stream/Collectors.java
@@ -0,0 +1,1568 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.DoubleSummaryStatistics;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IntSummaryStatistics;
+import java.util.Iterator;
+import java.util.List;
+import java.util.LongSummaryStatistics;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Implementations of {@link Collector} that implement various useful reduction
+ * operations, such as accumulating elements into collections, summarizing
+ * elements according to various criteria, etc.
+ *
+ * <p>The following are examples of using the predefined collectors to perform
+ * common mutable reduction tasks:
+ *
+ * <pre>{@code
+ *     // Accumulate names into a List
+ *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
+ *
+ *     // Accumulate names into a TreeSet
+ *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
+ *
+ *     // Convert elements to strings and concatenate them, separated by commas
+ *     String joined = things.stream()
+ *                           .map(Object::toString)
+ *                           .collect(Collectors.joining(", "));
+ *
+ *     // Compute sum of salaries of employee
+ *     int total = employees.stream()
+ *                          .collect(Collectors.summingInt(Employee::getSalary)));
+ *
+ *     // Group employees by department
+ *     Map<Department, List<Employee>> byDept
+ *         = employees.stream()
+ *                    .collect(Collectors.groupingBy(Employee::getDepartment));
+ *
+ *     // Compute sum of salaries by department
+ *     Map<Department, Integer> totalByDept
+ *         = employees.stream()
+ *                    .collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                   Collectors.summingInt(Employee::getSalary)));
+ *
+ *     // Partition students into passing and failing
+ *     Map<Boolean, List<Student>> passingFailing =
+ *         students.stream()
+ *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
+ *
+ * }</pre>
+ *
+ * @since 1.8
+ */
+public final class Collectors {
+
+    static final Set<Collector.Characteristics> CH_CONCURRENT_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.UNORDERED,
+                                                     Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_CONCURRENT_NOID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.CONCURRENT,
+                                                     Collector.Characteristics.UNORDERED));
+    static final Set<Collector.Characteristics> CH_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_UNORDERED_ID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
+                                                     Collector.Characteristics.IDENTITY_FINISH));
+    static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
+
+    private Collectors() { }
+
+    /**
+     * Returns a merge function, suitable for use in
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()} or
+     * {@link #toMap(Function, Function, BinaryOperator) toMap()}, which always
+     * throws {@code IllegalStateException}.  This can be used to enforce the
+     * assumption that the elements being collected are distinct.
+     *
+     * @param <T> the type of input arguments to the merge function
+     * @return a merge function which always throw {@code IllegalStateException}
+     */
+    private static <T> BinaryOperator<T> throwingMerger() {
+        return (u,v) -> { throw new IllegalStateException(String.format("Duplicate key %s", u)); };
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <I, R> Function<I, R> castingIdentity() {
+        return i -> (R) i;
+    }
+
+    /**
+     * Simple implementation class for {@code Collector}.
+     *
+     * @param <T> the type of elements to be collected
+     * @param <R> the type of the result
+     */
+    static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
+        private final Supplier<A> supplier;
+        private final BiConsumer<A, T> accumulator;
+        private final BinaryOperator<A> combiner;
+        private final Function<A, R> finisher;
+        private final Set<Characteristics> characteristics;
+
+        CollectorImpl(Supplier<A> supplier,
+                      BiConsumer<A, T> accumulator,
+                      BinaryOperator<A> combiner,
+                      Function<A,R> finisher,
+                      Set<Characteristics> characteristics) {
+            this.supplier = supplier;
+            this.accumulator = accumulator;
+            this.combiner = combiner;
+            this.finisher = finisher;
+            this.characteristics = characteristics;
+        }
+
+        CollectorImpl(Supplier<A> supplier,
+                      BiConsumer<A, T> accumulator,
+                      BinaryOperator<A> combiner,
+                      Set<Characteristics> characteristics) {
+            this(supplier, accumulator, combiner, castingIdentity(), characteristics);
+        }
+
+        @Override
+        public BiConsumer<A, T> accumulator() {
+            return accumulator;
+        }
+
+        @Override
+        public Supplier<A> supplier() {
+            return supplier;
+        }
+
+        @Override
+        public BinaryOperator<A> combiner() {
+            return combiner;
+        }
+
+        @Override
+        public Function<A, R> finisher() {
+            return finisher;
+        }
+
+        @Override
+        public Set<Characteristics> characteristics() {
+            return characteristics;
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Collection}, in encounter order.  The {@code Collection} is
+     * created by the provided factory.
+     *
+     * @param <T> the type of the input elements
+     * @param <C> the type of the resulting {@code Collection}
+     * @param collectionFactory a {@code Supplier} which returns a new, empty
+     * {@code Collection} of the appropriate type
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Collection}, in encounter order
+     */
+    public static <T, C extends Collection<T>>
+    Collector<T, ?, C> toCollection(Supplier<C> collectionFactory) {
+        return new CollectorImpl<>(collectionFactory, Collection<T>::add,
+                                   (r1, r2) -> { r1.addAll(r2); return r1; },
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code List}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code List} returned; if more
+     * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code List}, in encounter order
+     */
+    public static <T>
+    Collector<T, ?, List<T>> toList() {
+        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into a
+     * new {@code Set}. There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Set} returned; if more
+     * control over the returned {@code Set} is required, use
+     * {@link #toCollection(Supplier)}.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} which collects all the input elements into a
+     * {@code Set}
+     */
+    public static <T>
+    Collector<T, ?, Set<T>> toSet() {
+        return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   CH_UNORDERED_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements into a
+     * {@code String}, in encounter order.
+     *
+     * @return a {@code Collector} that concatenates the input elements into a
+     * {@code String}, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining() {
+        return new CollectorImpl<CharSequence, StringBuilder, String>(
+                StringBuilder::new, StringBuilder::append,
+                (r1, r2) -> { r1.append(r2); return r1; },
+                StringBuilder::toString, CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements,
+     * separated by the specified delimiter, in encounter order.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @return A {@code Collector} which concatenates CharSequence elements,
+     * separated by the specified delimiter, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter) {
+        return joining(delimiter, "", "");
+    }
+
+    /**
+     * Returns a {@code Collector} that concatenates the input elements,
+     * separated by the specified delimiter, with the specified prefix and
+     * suffix, in encounter order.
+     *
+     * @param delimiter the delimiter to be used between each element
+     * @param  prefix the sequence of characters to be used at the beginning
+     *                of the joined result
+     * @param  suffix the sequence of characters to be used at the end
+     *                of the joined result
+     * @return A {@code Collector} which concatenates CharSequence elements,
+     * separated by the specified delimiter, in encounter order
+     */
+    public static Collector<CharSequence, ?, String> joining(CharSequence delimiter,
+                                                             CharSequence prefix,
+                                                             CharSequence suffix) {
+        return new CollectorImpl<>(
+                () -> new StringJoiner(delimiter, prefix, suffix),
+                StringJoiner::add, StringJoiner::merge,
+                StringJoiner::toString, CH_NOID);
+    }
+
+    /**
+     * {@code BinaryOperator<Map>} that merges the contents of its right
+     * argument into its left argument, using the provided merge function to
+     * handle duplicate keys.
+     *
+     * @param <K> type of the map keys
+     * @param <V> type of the map values
+     * @param <M> type of the map
+     * @param mergeFunction A merge function suitable for
+     * {@link Map#merge(Object, Object, BiFunction) Map.merge()}
+     * @return a merge function for two maps
+     */
+    private static <K, V, M extends Map<K,V>>
+    BinaryOperator<M> mapMerger(BinaryOperator<V> mergeFunction) {
+        return (m1, m2) -> {
+            for (Map.Entry<K,V> e : m2.entrySet())
+                m1.merge(e.getKey(), e.getValue(), mergeFunction);
+            return m1;
+        };
+    }
+
+    /**
+     * Adapts a {@code Collector} accepting elements of type {@code U} to one
+     * accepting elements of type {@code T} by applying a mapping function to
+     * each input element before accumulation.
+     *
+     * @apiNote
+     * The {@code mapping()} collectors are most useful when used in a
+     * multi-level reduction, such as downstream of a {@code groupingBy} or
+     * {@code partitioningBy}.  For example, given a stream of
+     * {@code Person}, to accumulate the set of last names in each city:
+     * <pre>{@code
+     *     Map<City, Set<String>> lastNamesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> type of elements accepted by downstream collector
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of collector
+     * @param mapper a function to be applied to the input elements
+     * @param downstream a collector which will accept mapped values
+     * @return a collector which applies the mapping function to the input
+     * elements and provides the mapped results to the downstream collector
+     */
+    public static <T, U, A, R>
+    Collector<T, ?, R> mapping(Function<? super T, ? extends U> mapper,
+                               Collector<? super U, A, R> downstream) {
+        BiConsumer<A, ? super U> downstreamAccumulator = downstream.accumulator();
+        return new CollectorImpl<>(downstream.supplier(),
+                                   (r, t) -> downstreamAccumulator.accept(r, mapper.apply(t)),
+                                   downstream.combiner(), downstream.finisher(),
+                                   downstream.characteristics());
+    }
+
+    /**
+     * Adapts a {@code Collector} to perform an additional finishing
+     * transformation.  For example, one could adapt the {@link #toList()}
+     * collector to always produce an immutable list with:
+     * <pre>{@code
+     *     List<String> people
+     *         = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of the downstream collector
+     * @param <RR> result type of the resulting collector
+     * @param downstream a collector
+     * @param finisher a function to be applied to the final result of the downstream collector
+     * @return a collector which performs the action of the downstream collector,
+     * followed by an additional finishing step
+     */
+    public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
+                                                                Function<R,RR> finisher) {
+        Set<Collector.Characteristics> characteristics = downstream.characteristics();
+        if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            if (characteristics.size() == 1)
+                characteristics = Collectors.CH_NOID;
+            else {
+                characteristics = EnumSet.copyOf(characteristics);
+                characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
+                characteristics = Collections.unmodifiableSet(characteristics);
+            }
+        }
+        return new CollectorImpl<>(downstream.supplier(),
+                                   downstream.accumulator(),
+                                   downstream.combiner(),
+                                   downstream.finisher().andThen(finisher),
+                                   characteristics);
+    }
+
+    /**
+     * Returns a {@code Collector} accepting elements of type {@code T} that
+     * counts the number of input elements.  If no elements are present, the
+     * result is 0.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(0L, e -> 1L, Long::sum)
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that counts the input elements
+     */
+    public static <T> Collector<T, ?, Long>
+    counting() {
+        return reducing(0L, e -> 1L, Long::sum);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the minimal element according
+     * to a given {@code Comparator}, described as an {@code Optional<T>}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(BinaryOperator.minBy(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the minimal value
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    minBy(Comparator<? super T> comparator) {
+        return reducing(BinaryOperator.minBy(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the maximal element according
+     * to a given {@code Comparator}, described as an {@code Optional<T>}.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     reducing(BinaryOperator.maxBy(comparator))
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param comparator a {@code Comparator} for comparing elements
+     * @return a {@code Collector} that produces the maximal value
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    maxBy(Comparator<? super T> comparator) {
+        return reducing(BinaryOperator.maxBy(comparator));
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a integer-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Integer>
+    summingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new int[1],
+                (a, t) -> { a[0] += mapper.applyAsInt(t); },
+                (a, b) -> { a[0] += b[0]; return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a long-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Long>
+    summingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[1],
+                (a, t) -> { a[0] += mapper.applyAsLong(t); },
+                (a, b) -> { a[0] += b[0]; return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the sum of a double-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * <p>The sum returned can vary depending upon the order in which
+     * values are recorded, due to accumulated rounding error in
+     * addition of values of differing magnitudes. Values sorted by increasing
+     * absolute magnitude tend to yield more accurate results.  If any recorded
+     * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+     * sum will be {@code NaN}.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    summingDouble(ToDoubleFunction<? super T> mapper) {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
+         */
+        return new CollectorImpl<>(
+                () -> new double[3],
+                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t));
+                            a[2] += mapper.applyAsDouble(t);},
+                (a, b) -> { sumWithCompensation(a, b[0]);
+                            a[2] += b[2];
+                            return sumWithCompensation(a, b[1]); },
+                a -> computeFinalSum(a),
+                CH_NOID);
+    }
+
+    /**
+     * Incorporate a new double value using Kahan summation /
+     * compensation summation.
+     *
+     * High-order bits of the sum are in intermediateSum[0], low-order
+     * bits of the sum are in intermediateSum[1], any additional
+     * elements are application-specific.
+     *
+     * @param intermediateSum the high-order and low-order words of the intermediate sum
+     * @param value the name value to be included in the running sum
+     */
+    static double[] sumWithCompensation(double[] intermediateSum, double value) {
+        double tmp = value - intermediateSum[1];
+        double sum = intermediateSum[0];
+        double velvel = sum + tmp; // Little wolf of rounding error
+        intermediateSum[1] = (velvel - sum) - tmp;
+        intermediateSum[0] = velvel;
+        return intermediateSum;
+    }
+
+    /**
+     * If the compensated sum is spuriously NaN from accumulating one
+     * or more same-signed infinite values, return the
+     * correctly-signed infinity stored in the simple sum.
+     */
+    static double computeFinalSum(double[] summands) {
+        // Better error bounds to add both terms as the final sum
+        double tmp = summands[0] + summands[1];
+        double simpleSum = summands[summands.length - 1];
+        if (Double.isNaN(tmp) && Double.isInfinite(simpleSum))
+            return simpleSum;
+        else
+            return tmp;
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of an integer-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[2],
+                (a, t) -> { a[0] += mapper.applyAsInt(t); a[1]++; },
+                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
+                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of a long-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<>(
+                () -> new long[2],
+                (a, t) -> { a[0] += mapper.applyAsLong(t); a[1]++; },
+                (a, b) -> { a[0] += b[0]; a[1] += b[1]; return a; },
+                a -> (a[1] == 0) ? 0.0d : (double) a[0] / a[1], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} that produces the arithmetic mean of a double-valued
+     * function applied to the input elements.  If no elements are present,
+     * the result is 0.
+     *
+     * <p>The average returned can vary depending upon the order in which
+     * values are recorded, due to accumulated rounding error in
+     * addition of values of differing magnitudes. Values sorted by increasing
+     * absolute magnitude tend to yield more accurate results.  If any recorded
+     * value is a {@code NaN} or the sum is at any point a {@code NaN} then the
+     * average will be {@code NaN}.
+     *
+     * @implNote The {@code double} format can represent all
+     * consecutive integers in the range -2<sup>53</sup> to
+     * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup>
+     * values, the divisor in the average computation will saturate at
+     * 2<sup>53</sup>, leading to additional numerical errors.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a function extracting the property to be summed
+     * @return a {@code Collector} that produces the sum of a derived property
+     */
+    public static <T> Collector<T, ?, Double>
+    averagingDouble(ToDoubleFunction<? super T> mapper) {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the number of values seen.
+         */
+        return new CollectorImpl<>(
+                () -> new double[4],
+                (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);},
+                (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; },
+                a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]),
+                CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator} using the
+     * provided identity.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(Object, BinaryOperator)}} instead.
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, ?, T>
+    reducing(T identity, BinaryOperator<T> op) {
+        return new CollectorImpl<>(
+                boxSupplier(identity),
+                (a, t) -> { a[0] = op.apply(a[0], t); },
+                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
+                a -> a[0],
+                CH_NOID);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> Supplier<T[]> boxSupplier(T identity) {
+        return () -> (T[]) new Object[] { identity };
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified {@code BinaryOperator}.  The result
+     * is described as an {@code Optional<T>}.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple reduction on a stream,
+     * use {@link Stream#reduce(BinaryOperator)} instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate tallest
+     * person in each city:
+     * <pre>{@code
+     *     Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
+     *     Map<City, Person> tallestByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, reducing(BinaryOperator.maxBy(byHeight))));
+     * }</pre>
+     *
+     * @param <T> element type for the input and output of the reduction
+     * @param op a {@code BinaryOperator<T>} used to reduce the input elements
+     * @return a {@code Collector} which implements the reduction operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(Object, Function, BinaryOperator)
+     */
+    public static <T> Collector<T, ?, Optional<T>>
+    reducing(BinaryOperator<T> op) {
+        class OptionalBox implements Consumer<T> {
+            T value = null;
+            boolean present = false;
+
+            @Override
+            public void accept(T t) {
+                if (present) {
+                    value = op.apply(value, t);
+                }
+                else {
+                    value = t;
+                    present = true;
+                }
+            }
+        }
+
+        return new CollectorImpl<T, OptionalBox, Optional<T>>(
+                OptionalBox::new, OptionalBox::accept,
+                (a, b) -> { if (b.present) a.accept(b.value); return a; },
+                a -> Optional.ofNullable(a.value), CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} which performs a reduction of its
+     * input elements under a specified mapping function and
+     * {@code BinaryOperator}. This is a generalization of
+     * {@link #reducing(Object, BinaryOperator)} which allows a transformation
+     * of the elements before reduction.
+     *
+     * @apiNote
+     * The {@code reducing()} collectors are most useful when used in a
+     * multi-level reduction, downstream of {@code groupingBy} or
+     * {@code partitioningBy}.  To perform a simple map-reduce on a stream,
+     * use {@link Stream#map(Function)} and {@link Stream#reduce(Object, BinaryOperator)}
+     * instead.
+     *
+     * <p>For example, given a stream of {@code Person}, to calculate the longest
+     * last name of residents in each city:
+     * <pre>{@code
+     *     Comparator<String> byLength = Comparator.comparing(String::length);
+     *     Map<City, String> longestLastNameByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              reducing(Person::getLastName, BinaryOperator.maxBy(byLength))));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the mapped values
+     * @param identity the identity value for the reduction (also, the value
+     *                 that is returned when there are no input elements)
+     * @param mapper a mapping function to apply to each input value
+     * @param op a {@code BinaryOperator<U>} used to reduce the mapped values
+     * @return a {@code Collector} implementing the map-reduce operation
+     *
+     * @see #reducing(Object, BinaryOperator)
+     * @see #reducing(BinaryOperator)
+     */
+    public static <T, U>
+    Collector<T, ?, U> reducing(U identity,
+                                Function<? super T, ? extends U> mapper,
+                                BinaryOperator<U> op) {
+        return new CollectorImpl<>(
+                boxSupplier(identity),
+                (a, t) -> { a[0] = op.apply(a[0], mapper.apply(t)); },
+                (a, b) -> { a[0] = op.apply(a[0], b[0]); return a; },
+                a -> a[0], CH_NOID);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a "group by" operation on
+     * input elements of type {@code T}, grouping elements according to a
+     * classification function, and returning the results in a {@code Map}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code Map<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, serializability, or
+     * thread-safety of the {@code Map} or {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingBy(classifier, toList());
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements appear in the resulting {@code Map}
+     * collector is not required, using {@link #groupingByConcurrent(Function)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier the classifier function mapping input elements to keys
+     * @return a {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function)
+     */
+    public static <T, K> Collector<T, ?, Map<K, List<T>>>
+    groupingBy(Function<? super T, ? extends K> classifier) {
+        return groupingBy(classifier, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * <p>For example, to compute the set of last names of people in each city:
+     * <pre>{@code
+     *     Map<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements are presented to the downstream
+     * collector is not required, using {@link #groupingByConcurrent(Function, Collector)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     * @see #groupingBy(Function)
+     *
+     * @see #groupingBy(Function, Supplier, Collector)
+     * @see #groupingByConcurrent(Function, Collector)
+     */
+    public static <T, K, A, D>
+    Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
+                                          Collector<? super T, A, D> downstream) {
+        return groupingBy(classifier, HashMap::new, downstream);
+    }
+
+    /**
+     * Returns a {@code Collector} implementing a cascaded "group by" operation
+     * on input elements of type {@code T}, grouping elements according to a
+     * classification function, and then performing a reduction operation on
+     * the values associated with a given key using the specified downstream
+     * {@code Collector}.  The {@code Map} produced by the Collector is created
+     * with the supplied factory function.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     Map<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, TreeMap::new,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If
+     * preservation of the order in which elements are presented to the downstream
+     * collector is not required, using {@link #groupingByConcurrent(Function, Supplier, Collector)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code Map}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a function which, when called, produces a new empty
+     *                   {@code Map} of the desired type
+     * @return a {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, D, A, M extends Map<K, D>>
+    Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
+                                  Supplier<M> mapFactory,
+                                  Collector<? super T, A, D> downstream) {
+        Supplier<A> downstreamSupplier = downstream.supplier();
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
+            K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+            A container = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+            downstreamAccumulator.accept(container, t);
+        };
+        BinaryOperator<Map<K, A>> merger = Collectors.<K, A, Map<K, A>>mapMerger(downstream.combiner());
+        @SuppressWarnings("unchecked")
+        Supplier<Map<K, A>> mangledFactory = (Supplier<Map<K, A>>) mapFactory;
+
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_ID);
+        }
+        else {
+            @SuppressWarnings("unchecked")
+            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
+            Function<Map<K, A>, M> finisher = intermediate -> {
+                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
+                @SuppressWarnings("unchecked")
+                M castResult = (M) intermediate;
+                return castResult;
+            };
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_NOID);
+        }
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The collector produces a {@code ConcurrentMap<K, List<T>>} whose keys are the
+     * values resulting from applying the classification function to the input
+     * elements, and whose corresponding values are {@code List}s containing the
+     * input elements which map to the associated key under the classification
+     * function.
+     *
+     * <p>There are no guarantees on the type, mutability, or serializability
+     * of the {@code Map} or {@code List} objects returned, or of the
+     * thread-safety of the {@code List} objects returned.
+     * @implSpec
+     * This produces a result similar to:
+     * <pre>{@code
+     *     groupingByConcurrent(classifier, toList());
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param classifier a classifier function mapping input elements to keys
+     * @return a concurrent, unordered {@code Collector} implementing the group-by operation
+     *
+     * @see #groupingBy(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K>
+    Collector<T, ?, ConcurrentMap<K, List<T>>>
+    groupingByConcurrent(Function<? super T, ? extends K> classifier) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, toList());
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     ConcurrentMap<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingByConcurrent(Person::getCity,
+     *                                                        mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingBy(Function, Collector)
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Supplier, Collector)
+     */
+    public static <T, K, A, D>
+    Collector<T, ?, ConcurrentMap<K, D>> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                                              Collector<? super T, A, D> downstream) {
+        return groupingByConcurrent(classifier, ConcurrentHashMap::new, downstream);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} implementing a cascaded "group by"
+     * operation on input elements of type {@code T}, grouping elements
+     * according to a classification function, and then performing a reduction
+     * operation on the values associated with a given key using the specified
+     * downstream {@code Collector}.  The {@code ConcurrentMap} produced by the
+     * Collector is created with the supplied factory function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * <p>The classification function maps elements to some key type {@code K}.
+     * The downstream collector operates on elements of type {@code T} and
+     * produces a result of type {@code D}. The resulting collector produces a
+     * {@code Map<K, D>}.
+     *
+     * <p>For example, to compute the set of last names of people in each city,
+     * where the city names are sorted:
+     * <pre>{@code
+     *     ConcurrentMap<City, Set<String>> namesByCity
+     *         = people.stream().collect(groupingBy(Person::getCity, ConcurrentSkipListMap::new,
+     *                                              mapping(Person::getLastName, toSet())));
+     * }</pre>
+     *
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the type of the keys
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param classifier a classifier function mapping input elements to keys
+     * @param downstream a {@code Collector} implementing the downstream reduction
+     * @param mapFactory a function which, when called, produces a new empty
+     *                   {@code ConcurrentMap} of the desired type
+     * @return a concurrent, unordered {@code Collector} implementing the cascaded group-by operation
+     *
+     * @see #groupingByConcurrent(Function)
+     * @see #groupingByConcurrent(Function, Collector)
+     * @see #groupingBy(Function, Supplier, Collector)
+     */
+    public static <T, K, A, D, M extends ConcurrentMap<K, D>>
+    Collector<T, ?, M> groupingByConcurrent(Function<? super T, ? extends K> classifier,
+                                            Supplier<M> mapFactory,
+                                            Collector<? super T, A, D> downstream) {
+        Supplier<A> downstreamSupplier = downstream.supplier();
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BinaryOperator<ConcurrentMap<K, A>> merger = Collectors.<K, A, ConcurrentMap<K, A>>mapMerger(downstream.combiner());
+        @SuppressWarnings("unchecked")
+        Supplier<ConcurrentMap<K, A>> mangledFactory = (Supplier<ConcurrentMap<K, A>>) mapFactory;
+        BiConsumer<ConcurrentMap<K, A>, T> accumulator;
+        if (downstream.characteristics().contains(Collector.Characteristics.CONCURRENT)) {
+            accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                downstreamAccumulator.accept(resultContainer, t);
+            };
+        }
+        else {
+            accumulator = (m, t) -> {
+                K key = Objects.requireNonNull(classifier.apply(t), "element cannot be mapped to a null key");
+                A resultContainer = m.computeIfAbsent(key, k -> downstreamSupplier.get());
+                synchronized (resultContainer) {
+                    downstreamAccumulator.accept(resultContainer, t);
+                }
+            };
+        }
+
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, CH_CONCURRENT_ID);
+        }
+        else {
+            @SuppressWarnings("unchecked")
+            Function<A, A> downstreamFinisher = (Function<A, A>) downstream.finisher();
+            Function<ConcurrentMap<K, A>, M> finisher = intermediate -> {
+                intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v));
+                @SuppressWarnings("unchecked")
+                M castResult = (M) intermediate;
+                return castResult;
+            };
+            return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, CH_CONCURRENT_NOID);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, and organizes them into a
+     * {@code Map<Boolean, List<T>>}.
+     *
+     * There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @param <T> the type of the input elements
+     * @param predicate a predicate used for classifying input elements
+     * @return a {@code Collector} implementing the partitioning operation
+     *
+     * @see #partitioningBy(Predicate, Collector)
+     */
+    public static <T>
+    Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
+        return partitioningBy(predicate, toList());
+    }
+
+    /**
+     * Returns a {@code Collector} which partitions the input elements according
+     * to a {@code Predicate}, reduces the values in each partition according to
+     * another {@code Collector}, and organizes them into a
+     * {@code Map<Boolean, D>} whose values are the result of the downstream
+     * reduction.
+     *
+     * <p>There are no guarantees on the type, mutability,
+     * serializability, or thread-safety of the {@code Map} returned.
+     *
+     * @param <T> the type of the input elements
+     * @param <A> the intermediate accumulation type of the downstream collector
+     * @param <D> the result type of the downstream reduction
+     * @param predicate a predicate used for classifying input elements
+     * @param downstream a {@code Collector} implementing the downstream
+     *                   reduction
+     * @return a {@code Collector} implementing the cascaded partitioning
+     *         operation
+     *
+     * @see #partitioningBy(Predicate)
+     */
+    public static <T, D, A>
+    Collector<T, ?, Map<Boolean, D>> partitioningBy(Predicate<? super T> predicate,
+                                                    Collector<? super T, A, D> downstream) {
+        BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
+        BiConsumer<Partition<A>, T> accumulator = (result, t) ->
+                downstreamAccumulator.accept(predicate.test(t) ? result.forTrue : result.forFalse, t);
+        BinaryOperator<A> op = downstream.combiner();
+        BinaryOperator<Partition<A>> merger = (left, right) ->
+                new Partition<>(op.apply(left.forTrue, right.forTrue),
+                                op.apply(left.forFalse, right.forFalse));
+        Supplier<Partition<A>> supplier = () ->
+                new Partition<>(downstream.supplier().get(),
+                                downstream.supplier().get());
+        if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            return new CollectorImpl<>(supplier, accumulator, merger, CH_ID);
+        }
+        else {
+            Function<Partition<A>, Map<Boolean, D>> finisher = par ->
+                    new Partition<>(downstream.finisher().apply(par.forTrue),
+                                    downstream.finisher().apply(par.forFalse));
+            return new CollectorImpl<>(supplier, accumulator, merger, finisher, CH_NOID);
+        }
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
+     * instead.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     *     Map<Student, Double> studentToGPA
+     *         students.stream().collect(toMap(Functions.identity(),
+     *                                         student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     *     Map<String, Student> studentIdToStudent
+     *         students.stream().collect(toMap(Student::getId,
+     *                                         Functions.identity());
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are inserted into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys and values are the result of applying mapping functions to
+     * the input elements
+     *
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function)
+     */
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper) {
+        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  The other forms of {@code toMap} simply use
+     * a merge function that throws unconditionally, but you can easily write
+     * more flexible merge policies.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deals with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     *     Map<String, String> phoneBook
+     *         people.stream().collect(toMap(Person::getName,
+     *                                       Person::getAddress,
+     *                                       (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are merged into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
+                                    Function<? super T, ? extends U> valueMapper,
+                                    BinaryOperator<U> mergeFunction) {
+        return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
+    }
+
+    /**
+     * Returns a {@code Collector} that accumulates elements into a
+     * {@code Map} whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The {@code Map}
+     * is created by a provided supplier function.
+     *
+     * @implNote
+     * The returned {@code Collector} is not concurrent.  For parallel stream
+     * pipelines, the {@code combiner} function operates by merging the keys
+     * from one map into another, which can be an expensive operation.  If it is
+     * not required that results are merged into the {@code Map} in encounter
+     * order, using {@link #toConcurrentMap(Function, Function, BinaryOperator, Supplier)}
+     * may offer better parallel performance.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code Map}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapSupplier a function which returns a new, empty {@code Map} into
+     *                    which the results will be inserted
+     * @return a {@code Collector} which collects elements into a {@code Map}
+     * whose keys are the result of applying a key mapping function to the input
+     * elements, and whose values are the result of applying a value mapping
+     * function to all input elements equal to the key and combining them
+     * using the merge function
+     *
+     * @see #toMap(Function, Function)
+     * @see #toMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends Map<K, U>>
+    Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
+                                Function<? super T, ? extends U> valueMapper,
+                                BinaryOperator<U> mergeFunction,
+                                Supplier<M> mapSupplier) {
+        BiConsumer<M, T> accumulator
+                = (map, element) -> map.merge(keyMapper.apply(element),
+                                              valueMapper.apply(element), mergeFunction);
+        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * may have duplicates, use
+     * {@link #toConcurrentMap(Function, Function, BinaryOperator)} instead.
+     *
+     * @apiNote
+     * It is common for either the key or the value to be the input elements.
+     * In this case, the utility method
+     * {@link java.util.function.Function#identity()} may be helpful.
+     * For example, the following produces a {@code Map} mapping
+     * students to their grade point average:
+     * <pre>{@code
+     *     Map<Student, Double> studentToGPA
+     *         students.stream().collect(toMap(Functions.identity(),
+     *                                         student -> computeGPA(student)));
+     * }</pre>
+     * And the following produces a {@code Map} mapping a unique identifier to
+     * students:
+     * <pre>{@code
+     *     Map<String, Student> studentIdToStudent
+     *         students.stream().collect(toConcurrentMap(Student::getId,
+     *                                                   Functions.identity());
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper the mapping function to produce keys
+     * @param valueMapper the mapping function to produce values
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to the input elements
+     *
+     * @see #toMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U>
+    Collector<T, ?, ConcurrentMap<K,U>> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                                        Function<? super T, ? extends U> valueMapper) {
+        return toConcurrentMap(keyMapper, valueMapper, throwingMerger(), ConcurrentHashMap::new);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * @apiNote
+     * There are multiple ways to deal with collisions between multiple elements
+     * mapping to the same key.  The other forms of {@code toConcurrentMap} simply use
+     * a merge function that throws unconditionally, but you can easily write
+     * more flexible merge policies.  For example, if you have a stream
+     * of {@code Person}, and you want to produce a "phone book" mapping name to
+     * address, but it is possible that two persons have the same name, you can
+     * do as follows to gracefully deals with these collisions, and produce a
+     * {@code Map} mapping names to a concatenated list of addresses:
+     * <pre>{@code
+     *     Map<String, String> phoneBook
+     *         people.stream().collect(toConcurrentMap(Person::getName,
+     *                                                 Person::getAddress,
+     *                                                 (s, a) -> s + ", " + a));
+     * }</pre>
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator, Supplier)
+     * @see #toMap(Function, Function, BinaryOperator)
+     */
+    public static <T, K, U>
+    Collector<T, ?, ConcurrentMap<K,U>>
+    toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                    Function<? super T, ? extends U> valueMapper,
+                    BinaryOperator<U> mergeFunction) {
+        return toConcurrentMap(keyMapper, valueMapper, mergeFunction, ConcurrentHashMap::new);
+    }
+
+    /**
+     * Returns a concurrent {@code Collector} that accumulates elements into a
+     * {@code ConcurrentMap} whose keys and values are the result of applying
+     * the provided mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contains duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.  The
+     * {@code ConcurrentMap} is created by a provided supplier function.
+     *
+     * <p>This is a {@link Collector.Characteristics#CONCURRENT concurrent} and
+     * {@link Collector.Characteristics#UNORDERED unordered} Collector.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param <M> the type of the resulting {@code ConcurrentMap}
+     * @param keyMapper a mapping function to produce keys
+     * @param valueMapper a mapping function to produce values
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)}
+     * @param mapSupplier a function which returns a new, empty {@code Map} into
+     *                    which the results will be inserted
+     * @return a concurrent, unordered {@code Collector} which collects elements into a
+     * {@code ConcurrentMap} whose keys are the result of applying a key mapping
+     * function to the input elements, and whose values are the result of
+     * applying a value mapping function to all input elements equal to the key
+     * and combining them using the merge function
+     *
+     * @see #toConcurrentMap(Function, Function)
+     * @see #toConcurrentMap(Function, Function, BinaryOperator)
+     * @see #toMap(Function, Function, BinaryOperator, Supplier)
+     */
+    public static <T, K, U, M extends ConcurrentMap<K, U>>
+    Collector<T, ?, M> toConcurrentMap(Function<? super T, ? extends K> keyMapper,
+                                       Function<? super T, ? extends U> valueMapper,
+                                       BinaryOperator<U> mergeFunction,
+                                       Supplier<M> mapSupplier) {
+        BiConsumer<M, T> accumulator
+                = (map, element) -> map.merge(keyMapper.apply(element),
+                                              valueMapper.apply(element), mergeFunction);
+        return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_CONCURRENT_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code int}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingDouble(ToDoubleFunction)
+     * @see #summarizingLong(ToLongFunction)
+     */
+    public static <T>
+    Collector<T, ?, IntSummaryStatistics> summarizingInt(ToIntFunction<? super T> mapper) {
+        return new CollectorImpl<T, IntSummaryStatistics, IntSummaryStatistics>(
+                IntSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsInt(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code long}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper the mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingDouble(ToDoubleFunction)
+     * @see #summarizingInt(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, ?, LongSummaryStatistics> summarizingLong(ToLongFunction<? super T> mapper) {
+        return new CollectorImpl<T, LongSummaryStatistics, LongSummaryStatistics>(
+                LongSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsLong(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Returns a {@code Collector} which applies an {@code double}-producing
+     * mapping function to each input element, and returns summary statistics
+     * for the resulting values.
+     *
+     * @param <T> the type of the input elements
+     * @param mapper a mapping function to apply to each element
+     * @return a {@code Collector} implementing the summary-statistics reduction
+     *
+     * @see #summarizingLong(ToLongFunction)
+     * @see #summarizingInt(ToIntFunction)
+     */
+    public static <T>
+    Collector<T, ?, DoubleSummaryStatistics> summarizingDouble(ToDoubleFunction<? super T> mapper) {
+        return new CollectorImpl<T, DoubleSummaryStatistics, DoubleSummaryStatistics>(
+                DoubleSummaryStatistics::new,
+                (r, t) -> r.accept(mapper.applyAsDouble(t)),
+                (l, r) -> { l.combine(r); return l; }, CH_ID);
+    }
+
+    /**
+     * Implementation class used by partitioningBy.
+     */
+    private static final class Partition<T>
+            extends AbstractMap<Boolean, T>
+            implements Map<Boolean, T> {
+        final T forTrue;
+        final T forFalse;
+
+        Partition(T forTrue, T forFalse) {
+            this.forTrue = forTrue;
+            this.forFalse = forFalse;
+        }
+
+        @Override
+        public Set<Map.Entry<Boolean, T>> entrySet() {
+            return new AbstractSet<Map.Entry<Boolean, T>>() {
+                @Override
+                public Iterator<Map.Entry<Boolean, T>> iterator() {
+                    Map.Entry<Boolean, T> falseEntry = new SimpleImmutableEntry<>(false, forFalse);
+                    Map.Entry<Boolean, T> trueEntry = new SimpleImmutableEntry<>(true, forTrue);
+                    return Arrays.asList(falseEntry, trueEntry).iterator();
+                }
+
+                @Override
+                public int size() {
+                    return 2;
+                }
+            };
+        }
+    }
+}
diff --git a/java/util/stream/DistinctOps.java b/java/util/stream/DistinctOps.java
new file mode 100644
index 0000000..22fbe05
--- /dev/null
+++ b/java/util/stream/DistinctOps.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.IntFunction;
+
+/**
+ * Factory methods for transforming streams into duplicate-free streams, using
+ * {@link Object#equals(Object)} to determine equality.
+ *
+ * @since 1.8
+ */
+final class DistinctOps {
+
+    private DistinctOps() { }
+
+    /**
+     * Appends a "distinct" operation to the provided stream, and returns the
+     * new stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @return the new stream
+     */
+    static <T> ReferencePipeline<T, T> makeRef(AbstractPipeline<?, T, ?> upstream) {
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
+                                                      StreamOpFlag.IS_DISTINCT | StreamOpFlag.NOT_SIZED) {
+
+            <P_IN> Node<T> reduce(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                // If the stream is SORTED then it should also be ORDERED so the following will also
+                // preserve the sort order
+                TerminalOp<T, LinkedHashSet<T>> reduceOp
+                        = ReduceOps.<T, LinkedHashSet<T>>makeRef(LinkedHashSet::new, LinkedHashSet::add,
+                                                                 LinkedHashSet::addAll);
+                return Nodes.node(reduceOp.evaluateParallel(helper, spliterator));
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+                    // No-op
+                    return helper.evaluate(spliterator, false, generator);
+                }
+                else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return reduce(helper, spliterator);
+                }
+                else {
+                    // Holder of null state since ConcurrentHashMap does not support null values
+                    AtomicBoolean seenNull = new AtomicBoolean(false);
+                    ConcurrentHashMap<T, Boolean> map = new ConcurrentHashMap<>();
+                    TerminalOp<T, Void> forEachOp = ForEachOps.makeRef(t -> {
+                        if (t == null)
+                            seenNull.set(true);
+                        else
+                            map.putIfAbsent(t, Boolean.TRUE);
+                    }, false);
+                    forEachOp.evaluateParallel(helper, spliterator);
+
+                    // If null has been seen then copy the key set into a HashSet that supports null values
+                    // and add null
+                    Set<T> keys = map.keySet();
+                    if (seenNull.get()) {
+                        // TODO Implement a more efficient set-union view, rather than copying
+                        keys = new HashSet<>(keys);
+                        keys.add(null);
+                    }
+                    return Nodes.node(keys);
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+                    // No-op
+                    return helper.wrapSpliterator(spliterator);
+                }
+                else if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    // Not lazy, barrier required to preserve order
+                    return reduce(helper, spliterator).spliterator();
+                }
+                else {
+                    // Lazy
+                    return new StreamSpliterators.DistinctSpliterator<>(helper.wrapSpliterator(spliterator));
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                Objects.requireNonNull(sink);
+
+                if (StreamOpFlag.DISTINCT.isKnown(flags)) {
+                    return sink;
+                } else if (StreamOpFlag.SORTED.isKnown(flags)) {
+                    return new Sink.ChainedReference<T, T>(sink) {
+                        boolean seenNull;
+                        T lastSeen;
+
+                        @Override
+                        public void begin(long size) {
+                            seenNull = false;
+                            lastSeen = null;
+                            downstream.begin(-1);
+                        }
+
+                        @Override
+                        public void end() {
+                            seenNull = false;
+                            lastSeen = null;
+                            downstream.end();
+                        }
+
+                        @Override
+                        public void accept(T t) {
+                            if (t == null) {
+                                if (!seenNull) {
+                                    seenNull = true;
+                                    downstream.accept(lastSeen = null);
+                                }
+                            } else if (lastSeen == null || !t.equals(lastSeen)) {
+                                downstream.accept(lastSeen = t);
+                            }
+                        }
+                    };
+                } else {
+                    return new Sink.ChainedReference<T, T>(sink) {
+                        Set<T> seen;
+
+                        @Override
+                        public void begin(long size) {
+                            seen = new HashSet<>();
+                            downstream.begin(-1);
+                        }
+
+                        @Override
+                        public void end() {
+                            seen = null;
+                            downstream.end();
+                        }
+
+                        @Override
+                        public void accept(T t) {
+                            if (!seen.contains(t)) {
+                                seen.add(t);
+                                downstream.accept(t);
+                            }
+                        }
+                    };
+                }
+            }
+        };
+    }
+}
diff --git a/java/util/stream/DoubleNodeTest.java b/java/util/stream/DoubleNodeTest.java
new file mode 100644
index 0000000..c1e8a30
--- /dev/null
+++ b/java/util/stream/DoubleNodeTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class DoubleNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            double[] array = new double[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Double>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toDoubleArray(l))));
+            nodes.add(fill(array, Nodes.doubleBuilder(array.length)));
+            nodes.add(fill(array, Nodes.doubleBuilder()));
+
+            for (Node<Double> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListDoubleArray(List<Double> list, double[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], list.get(i));
+    }
+
+    private List<Double> toList(double[] a) {
+        List<Double> l = new ArrayList<>();
+        for (double i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private double[] toDoubleArray(List<Double> l) {
+        double[] a = new double[l.size()];
+
+        int i = 0;
+        for (Double e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfDouble fill(double[] array, Node.Builder.OfDouble nb) {
+        nb.begin(array.length);
+        for (double i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfDouble degenerateTree(PrimitiveIterator.OfDouble it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new double[0]);
+        }
+
+        double i = it.nextDouble();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode.OfDouble(Nodes.node(new double[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new double[] {i});
+        }
+    }
+
+    private Node.OfDouble tree(List<Double> l, Function<List<Double>, Node.OfDouble> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode.OfDouble(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(double[] array, Node.OfDouble n) {
+        assertEquals(n.asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(double[] array, Node.OfDouble n) {
+        assertEquals(Nodes.flattenDouble(n).asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(double[] array, Node.OfDouble n) {
+        double[] copy = new double[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(double[] array, Node.OfDouble n) {
+        List<Double> l = new ArrayList<>((int) n.count());
+        n.forEach((double e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListDoubleArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(double[] array, Node.OfDouble n) {
+        TestData.OfDouble data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes", groups={ "serialization-hostile" })
+    // throws SOE on serialization of DoubleConcNode[size=1000]
+    public void testSpliterator(double[] array, Node.OfDouble n) {
+        SpliteratorTestHelper.testDoubleSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(double[] array, Node.OfDouble n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node.OfDouble slice = n.truncate(start, end, Double[]::new);
+                double[] asArray = slice.asPrimitiveArray();
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/DoublePipeline.java b/java/util/stream/DoublePipeline.java
new file mode 100644
index 0000000..e61e5de
--- /dev/null
+++ b/java/util/stream/DoublePipeline.java
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code double}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class DoublePipeline<E_IN>
+        extends AbstractPipeline<E_IN, Double, DoubleStream>
+        implements DoubleStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     */
+    DoublePipeline(Supplier<? extends Spliterator<Double>> source,
+                   int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     * {@link StreamOpFlag}
+     */
+    DoublePipeline(Spliterator<Double> source,
+                   int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source.
+     * @param opFlags the operation flags
+     */
+    DoublePipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Double> to a {@code DoubleConsumer}, ideally simply
+     * by casting.
+     */
+    private static DoubleConsumer adapt(Sink<Double> sink) {
+        if (sink instanceof DoubleConsumer) {
+            return (DoubleConsumer) sink;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using DoubleStream.adapt(Sink<Double> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Double>} to a {@code Spliterator.OfDouble}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfDouble, and throws
+     * an exception if this cast is not possible.
+     */
+    private static Spliterator.OfDouble adapt(Spliterator<Double> s) {
+        if (s instanceof Spliterator.OfDouble) {
+            return (Spliterator.OfDouble) s;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using DoubleStream.adapt(Spliterator<Double> s)");
+            throw new UnsupportedOperationException("DoubleStream.adapt(Spliterator<Double> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.DOUBLE_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Double> evaluateToNode(PipelineHelper<Double> helper,
+                                             Spliterator<P_IN> spliterator,
+                                             boolean flattenTree,
+                                             IntFunction<Double[]> generator) {
+        return Nodes.collectDouble(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Double> wrap(PipelineHelper<Double> ph,
+                                          Supplier<Spliterator<P_IN>> supplier,
+                                          boolean isParallel) {
+        return new StreamSpliterators.DoubleWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfDouble lazySpliterator(Supplier<? extends Spliterator<Double>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfDouble((Supplier<Spliterator.OfDouble>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<Double> spliterator, Sink<Double> sink) {
+        Spliterator.OfDouble spl = adapt(spliterator);
+        DoubleConsumer adaptedSink = adapt(sink);
+        do { } while (!sink.cancellationRequested() && spl.tryAdvance(adaptedSink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Double> makeNodeBuilder(long exactSizeIfKnown, IntFunction<Double[]> generator) {
+        return Nodes.doubleBuilder(exactSizeIfKnown);
+    }
+
+
+    // DoubleStream
+
+    @Override
+    public final PrimitiveIterator.OfDouble iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfDouble spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from DoubleStream
+
+    @Override
+    public final Stream<Double> boxed() {
+        return mapToObj(Double::valueOf);
+    }
+
+    @Override
+    public final DoubleStream map(DoubleUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE,
+                                                            StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedDouble<U>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(DoubleToIntFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                                   StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedDouble<Integer>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(DoubleToLongFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedDouble<Long>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper) {
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        try (DoubleStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public DoubleStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream filter(DoublePredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream peek(DoubleConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
+                                       0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from DoubleStream
+
+    @Override
+    public final DoubleStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeDouble(this, (long) 0, maxSize);
+    }
+
+    @Override
+    public final DoubleStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else {
+            long limit = -1;
+            return SliceOps.makeDouble(this, n, limit);
+        }
+    }
+
+    @Override
+    public final DoubleStream sorted() {
+        return SortedOps.makeDouble(this);
+    }
+
+    @Override
+    public final DoubleStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires a double-specific map/set implementation.
+        return boxed().distinct().mapToDouble(i -> (double) i);
+    }
+
+    // Terminal ops from DoubleStream
+
+    @Override
+    public void forEach(DoubleConsumer consumer) {
+        evaluate(ForEachOps.makeDouble(consumer, false));
+    }
+
+    @Override
+    public void forEachOrdered(DoubleConsumer consumer) {
+        evaluate(ForEachOps.makeDouble(consumer, true));
+    }
+
+    @Override
+    public final double sum() {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, and index 2 holds the simple sum used to compute
+         * the proper result if the stream contains infinite values of
+         * the same sign.
+         */
+        double[] summation = collect(() -> new double[3],
+                               (ll, d) -> {
+                                   Collectors.sumWithCompensation(ll, d);
+                                   ll[2] += d;
+                               },
+                               (ll, rr) -> {
+                                   Collectors.sumWithCompensation(ll, rr[0]);
+                                   Collectors.sumWithCompensation(ll, rr[1]);
+                                   ll[2] += rr[2];
+                               });
+
+        return Collectors.computeFinalSum(summation);
+    }
+
+    @Override
+    public final OptionalDouble min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalDouble max() {
+        return reduce(Math::max);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @implNote The {@code double} format can represent all
+     * consecutive integers in the range -2<sup>53</sup> to
+     * 2<sup>53</sup>. If the pipeline has more than 2<sup>53</sup>
+     * values, the divisor in the average computation will saturate at
+     * 2<sup>53</sup>, leading to additional numerical errors.
+     */
+    @Override
+    public final OptionalDouble average() {
+        /*
+         * In the arrays allocated for the collect operation, index 0
+         * holds the high-order bits of the running sum, index 1 holds
+         * the low-order bits of the sum computed via compensated
+         * summation, index 2 holds the number of values seen, index 3
+         * holds the simple sum.
+         */
+        double[] avg = collect(() -> new double[4],
+                               (ll, d) -> {
+                                   ll[2]++;
+                                   Collectors.sumWithCompensation(ll, d);
+                                   ll[3] += d;
+                               },
+                               (ll, rr) -> {
+                                   Collectors.sumWithCompensation(ll, rr[0]);
+                                   Collectors.sumWithCompensation(ll, rr[1]);
+                                   ll[2] += rr[2];
+                                   ll[3] += rr[3];
+                               });
+        return avg[2] > 0
+            ? OptionalDouble.of(Collectors.computeFinalSum(avg) / avg[2])
+            : OptionalDouble.empty();
+    }
+
+    @Override
+    public final long count() {
+        return mapToLong(e -> 1L).sum();
+    }
+
+    @Override
+    public final DoubleSummaryStatistics summaryStatistics() {
+        return collect(DoubleSummaryStatistics::new, DoubleSummaryStatistics::accept,
+                       DoubleSummaryStatistics::combine);
+    }
+
+    @Override
+    public final double reduce(double identity, DoubleBinaryOperator op) {
+        return evaluate(ReduceOps.makeDouble(identity, op));
+    }
+
+    @Override
+    public final OptionalDouble reduce(DoubleBinaryOperator op) {
+        return evaluate(ReduceOps.makeDouble(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjDoubleConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(DoublePredicate predicate) {
+        return evaluate(MatchOps.makeDouble(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalDouble findFirst() {
+        return evaluate(FindOps.makeDouble(true));
+    }
+
+    @Override
+    public final OptionalDouble findAny() {
+        return evaluate(FindOps.makeDouble(false));
+    }
+
+    @Override
+    public final double[] toArray() {
+        return Nodes.flattenDouble((Node.OfDouble) evaluateToArrayNode(Double[]::new))
+                        .asPrimitiveArray();
+    }
+
+    //
+
+    /**
+     * Source stage of a DoubleStream
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Constructor for the source stage of a DoubleStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Double>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a DoubleStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Double> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Made public for CTS tests only.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Made public for CTS tests only.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Double> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(consumer);
+            }
+            else {
+                super.forEach(consumer);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(DoubleConsumer consumer) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(consumer);
+            }
+            else {
+                super.forEachOrdered(consumer);
+            }
+        }
+
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of a DoubleStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Construct a new DoubleStream by appending a stateless intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream the upstream pipeline stage
+         * @param inputShape the stream shape for the upstream pipeline stage
+         * @param opFlags operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a DoubleStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends DoublePipeline<E_IN> {
+        /**
+         * Construct a new DoubleStream by appending a stateful intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream the upstream pipeline stage
+         * @param inputShape the stream shape for the upstream pipeline stage
+         * @param opFlags operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                        Spliterator<P_IN> spliterator,
+                                                        IntFunction<Double[]> generator);
+    }
+}
diff --git a/java/util/stream/DoubleStream.java b/java/util/stream/DoubleStream.java
new file mode 100644
index 0000000..4d5d23d
--- /dev/null
+++ b/java/util/stream/DoubleStream.java
@@ -0,0 +1,894 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.DoubleSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleFunction;
+import java.util.function.DoublePredicate;
+import java.util.function.DoubleSupplier;
+import java.util.function.DoubleToIntFunction;
+import java.util.function.DoubleToLongFunction;
+import java.util.function.DoubleUnaryOperator;
+import java.util.function.Function;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive double-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code double} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link DoubleStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     double sum = widgets.stream()
+ *                         .filter(w -> w.getColor() == RED)
+ *                         .mapToDouble(w -> w.getWeight())
+ *                         .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface DoubleStream extends BaseStream<Double, DoubleStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    DoubleStream filter(DoublePredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream map(DoubleUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(DoubleToIntFunction mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(DoubleToLongFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a
+     *               {@code DoubleStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    DoubleStream flatMap(DoubleFunction<? extends DoubleStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream. The
+     * elements are compared for equality according to
+     * {@link java.lang.Double#compare(double, double)}.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the result stream
+     */
+    DoubleStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order. The elements are compared for equality according to
+     * {@link java.lang.Double#compare(double, double)}.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the result stream
+     */
+    DoubleStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     DoubleStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    DoubleStream peek(DoubleConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(DoubleSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    DoubleStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(DoubleSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    DoubleStream skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(DoubleConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(DoubleConsumer)
+     */
+    void forEachOrdered(DoubleConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    double[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     double result = identity;
+     *     for (double element : this stream)
+     *         result = accumulator.applyAsDouble(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+
+     * <pre>{@code
+     *     double sum = numbers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     double sum = numbers.reduce(0, Double::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    double reduce(double identity, DoubleBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalDouble} describing the reduced
+     * value, if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     double result = null;
+     *     for (double element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsDouble(result, element);
+     *     }
+     *     return foundAny ? OptionalDouble.of(result) : OptionalDouble.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(double, DoubleBinaryOperator)
+     */
+    OptionalDouble reduce(DoubleBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (double element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(double, DoubleBinaryOperator)}, {@code collect}
+     * operations can be parallelized without requiring additional
+     * synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjDoubleConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.
+     *
+     * Summation is a special case of a <a
+     * href="package-summary.html#Reduction">reduction</a>. If
+     * floating-point summation were exact, this method would be
+     * equivalent to:
+     *
+     * <pre>{@code
+     *     return reduce(0, Double::sum);
+     * }</pre>
+     *
+     * However, since floating-point summation is not exact, the above
+     * code is not necessarily equivalent to the summation computation
+     * done by this method.
+     *
+     * <p>If any stream element is a NaN or the sum is at any point a NaN
+     * then the sum will be NaN.
+     *
+     * The value of a floating-point sum is a function both
+     * of the input values as well as the order of addition
+     * operations. The order of addition operations of this method is
+     * intentionally not defined to allow for implementation
+     * flexibility to improve the speed and accuracy of the computed
+     * result.
+     *
+     * In particular, this method may be implemented using compensated
+     * summation or other technique to reduce the error bound in the
+     * numerical sum compared to a simple summation of {@code double}
+     * values.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Elements sorted by increasing absolute magnitude tend
+     * to yield more accurate results.
+     *
+     * @return the sum of elements in this stream
+     */
+    double sum();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the minimum element of this
+     * stream, or an empty OptionalDouble if this stream is empty.  The minimum
+     * element will be {@code Double.NaN} if any stream element was NaN. Unlike
+     * the numerical comparison operators, this method considers negative zero
+     * to be strictly smaller than positive zero. This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return reduce(Double::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the minimum element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble min();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the maximum element of this
+     * stream, or an empty OptionalDouble if this stream is empty.  The maximum
+     * element will be {@code Double.NaN} if any stream element was NaN. Unlike
+     * the numerical comparison operators, this method considers negative zero
+     * to be strictly smaller than positive zero. This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return reduce(Double::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the maximum element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic
+     * mean of elements of this stream, or an empty optional if this
+     * stream is empty.
+     *
+     * If any recorded value is a NaN or the sum is at any point a NaN
+     * then the average will be NaN.
+     *
+     * <p>The average returned can vary depending upon the order in
+     * which values are recorded.
+     *
+     * This method may be implemented using compensated summation or
+     * other technique to reduce the error bound in the {@link #sum
+     * numerical sum} used to compute the average.
+     *
+     *  <p>The average is a special case of a <a
+     *  href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Elements sorted by increasing absolute magnitude tend
+     * to yield more accurate results.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns a {@code DoubleSummaryStatistics} describing various summary data
+     * about the elements of this stream.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return a {@code DoubleSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    DoubleSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(DoublePredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(DoublePredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(DoublePredicate predicate);
+
+    /**
+     * Returns an {@link OptionalDouble} describing the first element of this
+     * stream, or an empty {@code OptionalDouble} if the stream is empty.  If
+     * the stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalDouble} describing the first element of this
+     * stream, or an empty {@code OptionalDouble} if the stream is empty
+     */
+    OptionalDouble findFirst();
+
+    /**
+     * Returns an {@link OptionalDouble} describing some element of the stream,
+     * or an empty {@code OptionalDouble} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalDouble} describing some element of this stream,
+     * or an empty {@code OptionalDouble} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalDouble findAny();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * boxed to {@code Double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to a {@code Double}
+     */
+    Stream<Double> boxed();
+
+    @Override
+    DoubleStream sequential();
+
+    @Override
+    DoubleStream parallel();
+
+    @Override
+    PrimitiveIterator.OfDouble iterator();
+
+    @Override
+    Spliterator.OfDouble spliterator();
+
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code DoubleStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.DoubleStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code DoubleStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static DoubleStream empty() {
+        return StreamSupport.doubleStream(Spliterators.emptyDoubleSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code DoubleStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static DoubleStream of(double t) {
+        return StreamSupport.doubleStream(new Streams.DoubleStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static DoubleStream of(double... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code DoubleStream}
+     * will be the provided {@code seed}.  For {@code n > 0}, the element at
+     * position {@code n}, will be the result of applying the function {@code f}
+     *  to the element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code DoubleStream}
+     */
+    public static DoubleStream iterate(final double seed, final DoubleUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfDouble iterator = new PrimitiveIterator.OfDouble() {
+            double t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public double nextDouble() {
+                double v = t;
+                t = f.applyAsDouble(t);
+                return v;
+            }
+        };
+        return StreamSupport.doubleStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code DoubleSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code DoubleSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code DoubleStream}
+     */
+    public static DoubleStream generate(DoubleSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.doubleStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfDouble(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static DoubleStream concat(DoubleStream a, DoubleStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble(
+                a.spliterator(), b.spliterator());
+        DoubleStream stream = StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code DoubleStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see DoubleStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends DoubleConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(double t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(double t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        DoubleStream build();
+    }
+}
diff --git a/java/util/stream/DoubleStreamTestDataProvider.java b/java/util/stream/DoubleStreamTestDataProvider.java
new file mode 100644
index 0000000..0eb7c87
--- /dev/null
+++ b/java/util/stream/DoubleStreamTestDataProvider.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for double-valued streams */
+public class DoubleStreamTestDataProvider {
+    private static final double[] to0 = new double[0];
+    private static final double[] to1 = new double[1];
+    private static final double[] to10 = new double[10];
+    private static final double[] to100 = new double[100];
+    private static final double[] to1000 = new double[1000];
+    private static final double[] reversed = new double[100];
+    private static final double[] ones = new double[100];
+    private static final double[] twice = new double[200];
+    private static final double[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        double[][] arrays = {to0, to1, to10, to100, to1000};
+        for (double[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new double[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (double) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final double[] doubles = (double[]) data[1];
+
+                list.add(new Object[]{"array:" + name,
+                        TestData.Factory.ofArray("array:" + name, doubles)});
+
+                SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+                for (double i : doubles) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                        TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final double[] doubles = (double[]) data[1];
+
+                SpinedBuffer.OfDouble isl = new SpinedBuffer.OfDouble();
+                for (double i : doubles) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(doubles)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(doubles, 0, doubles.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), doubles.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfDouble> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, DoubleStreamTestData )
+    @DataProvider(name = "DoubleStreamTestData")
+    public static Object[][] makeDoubleStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Double>>)
+    @DataProvider(name = "DoubleSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/DoubleStreamTestScenario.java b/java/util/stream/DoubleStreamTestScenario.java
new file mode 100644
index 0000000..1811a4b
--- /dev/null
+++ b/java/util/stream/DoubleStreamTestScenario.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for double streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            DoubleStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (double t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (PrimitiveIterator.OfDouble seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextDouble());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (Spliterator.OfDouble spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (Spliterator.OfDouble spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            for (double t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            DoubleStream s = m.apply(data.parallelStream());
+            Spliterator.OfDouble sp = s.spliterator();
+            DoubleStream ss = StreamSupport.doubleStream(() -> sp,
+                                                         StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                         | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+            for (double t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            DoubleStream pipe2 = m.apply(pipe1);
+
+            for (double t : pipe2.toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<DoubleStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private boolean isParallel;
+
+    private final boolean isOrdered;
+
+    DoubleStreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    DoubleStreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.DOUBLE_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (DoubleConsumer) b, (Function<S_IN, DoubleStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m);
+
+}
diff --git a/java/util/stream/FindOps.java b/java/util/stream/FindOps.java
new file mode 100644
index 0000000..197d99c
--- /dev/null
+++ b/java/util/stream/FindOps.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Factory for instances of a short-circuiting {@code TerminalOp} that searches
+ * for an element in a stream pipeline, and terminates when it finds one.
+ * Supported variants include find-first (find the first element in the
+ * encounter order) and find-any (find any element, may not be the first in
+ * encounter order.)
+ *
+ * @since 1.8
+ */
+final class FindOps {
+
+    private FindOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of objects.
+     *
+     * @param <T> the type of elements of the stream
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static <T> TerminalOp<T, Optional<T>> makeRef(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.REFERENCE, Optional.empty(),
+                            Optional::isPresent, FindSink.OfRef::new);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of ints.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Integer, OptionalInt> makeInt(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.INT_VALUE, OptionalInt.empty(),
+                            OptionalInt::isPresent, FindSink.OfInt::new);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} for streams of longs.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Long, OptionalLong> makeLong(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.LONG_VALUE, OptionalLong.empty(),
+                            OptionalLong::isPresent, FindSink.OfLong::new);
+    }
+
+    /**
+     * Constructs a {@code FindOp} for streams of doubles.
+     *
+     * @param mustFindFirst whether the {@code TerminalOp} must produce the
+     *        first element in the encounter order
+     * @return a {@code TerminalOp} implementing the find operation
+     */
+    public static TerminalOp<Double, OptionalDouble> makeDouble(boolean mustFindFirst) {
+        return new FindOp<>(mustFindFirst, StreamShape.DOUBLE_VALUE, OptionalDouble.empty(),
+                            OptionalDouble::isPresent, FindSink.OfDouble::new);
+    }
+
+    /**
+     * A short-circuiting {@code TerminalOp} that searches for an element in a
+     * stream pipeline, and terminates when it finds one.  Implements both
+     * find-first (find the first element in the encounter order) and find-any
+     * (find any element, may not be the first in encounter order.)
+     *
+     * @param <T> the output type of the stream pipeline
+     * @param <O> the result type of the find operation, typically an optional
+     *        type
+     */
+    private static final class FindOp<T, O> implements TerminalOp<T, O> {
+        private final StreamShape shape;
+        final boolean mustFindFirst;
+        final O emptyValue;
+        final Predicate<O> presentPredicate;
+        final Supplier<TerminalSink<T, O>> sinkSupplier;
+
+        /**
+         * Constructs a {@code FindOp}.
+         *
+         * @param mustFindFirst if true, must find the first element in
+         *        encounter order, otherwise can find any element
+         * @param shape stream shape of elements to search
+         * @param emptyValue result value corresponding to "found nothing"
+         * @param presentPredicate {@code Predicate} on result value
+         *        corresponding to "found something"
+         * @param sinkSupplier supplier for a {@code TerminalSink} implementing
+         *        the matching functionality
+         */
+        FindOp(boolean mustFindFirst,
+                       StreamShape shape,
+                       O emptyValue,
+                       Predicate<O> presentPredicate,
+                       Supplier<TerminalSink<T, O>> sinkSupplier) {
+            this.mustFindFirst = mustFindFirst;
+            this.shape = shape;
+            this.emptyValue = emptyValue;
+            this.presentPredicate = presentPredicate;
+            this.sinkSupplier = sinkSupplier;
+        }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT | (mustFindFirst ? 0 : StreamOpFlag.NOT_ORDERED);
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+
+        @Override
+        public <S> O evaluateSequential(PipelineHelper<T> helper,
+                                        Spliterator<S> spliterator) {
+            O result = helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).get();
+            return result != null ? result : emptyValue;
+        }
+
+        @Override
+        public <P_IN> O evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<P_IN> spliterator) {
+            return new FindTask<>(this, helper, spliterator).invoke();
+        }
+    }
+
+    /**
+     * Implementation of @{code TerminalSink} that implements the find
+     * functionality, requesting cancellation when something has been found
+     *
+     * @param <T> The type of input element
+     * @param <O> The result type, typically an optional type
+     */
+    private static abstract class FindSink<T, O> implements TerminalSink<T, O> {
+        boolean hasValue;
+        T value;
+
+        FindSink() {} // Avoid creation of special accessor
+
+        @Override
+        public void accept(T value) {
+            if (!hasValue) {
+                hasValue = true;
+                this.value = value;
+            }
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return hasValue;
+        }
+
+        /** Specialization of {@code FindSink} for reference streams */
+        static final class OfRef<T> extends FindSink<T, Optional<T>> {
+            @Override
+            public Optional<T> get() {
+                return hasValue ? Optional.of(value) : null;
+            }
+        }
+
+        /** Specialization of {@code FindSink} for int streams */
+        static final class OfInt extends FindSink<Integer, OptionalInt>
+                implements Sink.OfInt {
+            @Override
+            public void accept(int value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Integer) value);
+            }
+
+            @Override
+            public OptionalInt get() {
+                return hasValue ? OptionalInt.of(value) : null;
+            }
+        }
+
+        /** Specialization of {@code FindSink} for long streams */
+        static final class OfLong extends FindSink<Long, OptionalLong>
+                implements Sink.OfLong {
+            @Override
+            public void accept(long value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Long) value);
+            }
+
+            @Override
+            public OptionalLong get() {
+                return hasValue ? OptionalLong.of(value) : null;
+            }
+        }
+
+        /** Specialization of {@code FindSink} for double streams */
+        static final class OfDouble extends FindSink<Double, OptionalDouble>
+                implements Sink.OfDouble {
+            @Override
+            public void accept(double value) {
+                // Boxing is OK here, since few values will actually flow into the sink
+                accept((Double) value);
+            }
+
+            @Override
+            public OptionalDouble get() {
+                return hasValue ? OptionalDouble.of(value) : null;
+            }
+        }
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing parallel short-circuiting search
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     * @param <O> Result type from the find operation
+     */
+    @SuppressWarnings("serial")
+    private static final class FindTask<P_IN, P_OUT, O>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, O, FindTask<P_IN, P_OUT, O>> {
+        private final FindOp<P_OUT, O> op;
+
+        FindTask(FindOp<P_OUT, O> op,
+                 PipelineHelper<P_OUT> helper,
+                 Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        FindTask(FindTask<P_IN, P_OUT, O> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected FindTask<P_IN, P_OUT, O> makeChild(Spliterator<P_IN> spliterator) {
+            return new FindTask<>(this, spliterator);
+        }
+
+        @Override
+        protected O getEmptyResult() {
+            return op.emptyValue;
+        }
+
+        private void foundResult(O answer) {
+            if (isLeftmostNode())
+                shortCircuit(answer);
+            else
+                cancelLaterNodes();
+        }
+
+        @Override
+        protected O doLeaf() {
+            O result = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).get();
+            if (!op.mustFindFirst) {
+                if (result != null)
+                    shortCircuit(result);
+                return null;
+            }
+            else {
+                if (result != null) {
+                    foundResult(result);
+                    return result;
+                }
+                else
+                    return null;
+            }
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (op.mustFindFirst) {
+                    for (FindTask<P_IN, P_OUT, O> child = leftChild, p = null; child != p;
+                         p = child, child = rightChild) {
+                    O result = child.getLocalResult();
+                    if (result != null && op.presentPredicate.test(result)) {
+                        setLocalResult(result);
+                        foundResult(result);
+                        break;
+                    }
+                }
+            }
+            super.onCompletion(caller);
+        }
+    }
+}
+
diff --git a/java/util/stream/FlagDeclaringOp.java b/java/util/stream/FlagDeclaringOp.java
new file mode 100644
index 0000000..a9882c8
--- /dev/null
+++ b/java/util/stream/FlagDeclaringOp.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An operation that injects or clears flags but otherwise performs no operation on elements.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class FlagDeclaringOp<T> implements StatelessTestOp<T, T> {
+    private final int flags;
+    private final StreamShape shape;
+
+    public FlagDeclaringOp(int flags) {
+        this(flags, StreamShape.REFERENCE);
+    }
+
+    public FlagDeclaringOp(int flags, StreamShape shape) {
+        this.flags = flags;
+        this.shape = shape;
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public int opGetFlags() {
+        return flags;
+    }
+
+    @Override
+    public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+        return sink;
+    }
+}
diff --git a/java/util/stream/FlagOpTest.java b/java/util/stream/FlagOpTest.java
new file mode 100644
index 0000000..1543108
--- /dev/null
+++ b/java/util/stream/FlagOpTest.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.function.Supplier;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+@Test
+public class FlagOpTest extends OpTestCase {
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testFlagsPassThrough(String name, TestData<Integer, Stream<Integer>> data) {
+
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        TestFlagPassThroughOp<Integer>[] ops = new TestFlagPassThroughOp[3];
+        ops[0] = new TestFlagPassThroughOp<>();
+        ops[1] = new TestFlagPassThroughOp<>();
+        ops[2] = new TestFlagPassThroughOp<>();
+
+        ops[0].set(null, ops[1]);
+        ops[1].set(ops[0], ops[2]);
+        ops[2].set(ops[1], null);
+
+        withData(data).ops(ops).exercise();
+    }
+
+    static class TestFlagPassThroughOp<T> extends FlagDeclaringOp<T> {
+        TestFlagPassThroughOp<T> upstream;
+        TestFlagPassThroughOp<T> downstream;
+
+        TestFlagPassThroughOp() {
+            super(0);
+        }
+
+        void set(TestFlagPassThroughOp<T> upstream, TestFlagPassThroughOp<T> downstream)  {
+            this.upstream = upstream;
+            this.downstream = downstream;
+        }
+
+        int wrapFlags;
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink sink) {
+            this.wrapFlags = flags;
+
+            if (downstream != null) {
+                assertTrue(flags == downstream.wrapFlags);
+            }
+
+            return sink;
+        }
+    }
+
+    public void testFlagsClearAllSet() {
+        int clearAllFlags = 0;
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+            if (f.isStreamFlag()) {
+                clearAllFlags |= f.clear();
+            }
+        }
+
+        EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> notKnown = StreamOpFlagTestHelper.allStreamFlags();
+
+        List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+        ops.add(new FlagDeclaringOp<>(clearAllFlags));
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            if (f.canSet(StreamOpFlag.Type.OP)) {
+                ops.add(new TestFlagExpectedOp<>(f.set(),
+                                             known.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class),
+                                             notKnown.clone()));
+                known.add(f);
+                notKnown.remove(f);
+            }
+        }
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+    public void testFlagsSetAllClear() {
+        EnumSet<StreamOpFlag> known = StreamOpFlagTestHelper.allStreamFlags();
+        int setAllFlags = 0;
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class)) {
+            if (f.isStreamFlag()) {
+                if (f.canSet(StreamOpFlag.Type.OP)) {
+                    setAllFlags |= f.set();
+                } else {
+                    known.remove(f);
+                }
+            }
+        }
+
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        List<FlagDeclaringOp<Integer>> ops = new ArrayList<>();
+        ops.add(new FlagDeclaringOp<>(setAllFlags));
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            ops.add(new TestFlagExpectedOp<>(f.clear(),
+                                             known.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class),
+                                             notKnown.clone()));
+            known.remove(f);
+            notKnown.add(f);
+        }
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        FlagDeclaringOp[] opsArray = ops.toArray(new FlagDeclaringOp[ops.size()]);
+
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+    public void testFlagsParallelCollect() {
+        testFlagsSetSequence(CollectorOps::collector);
+    }
+
+    private void testFlagsSetSequence(Supplier<StatefulTestOp<Integer>> cf) {
+        EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+            ops.add(cf.get());
+            ops.add(new TestFlagExpectedOp<>(f.set(),
+                                             known.clone(),
+                                             preserve.clone(),
+                                             EnumSet.noneOf(StreamOpFlag.class)));
+            known.add(f);
+            preserve.remove(f);
+        }
+        ops.add(cf.get());
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         preserve.clone(),
+                                         EnumSet.noneOf(StreamOpFlag.class)));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+
+    public void testFlagsClearParallelCollect() {
+        testFlagsClearSequence(CollectorOps::collector);
+    }
+
+    protected void testFlagsClearSequence(Supplier<StatefulTestOp<Integer>> cf) {
+        EnumSet<StreamOpFlag> known = EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> preserve = EnumSet.of(StreamOpFlag.DISTINCT, StreamOpFlag.SORTED);
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : EnumSet.of(StreamOpFlag.ORDERED, StreamOpFlag.DISTINCT, StreamOpFlag.SORTED)) {
+            ops.add(cf.get());
+            ops.add(new TestFlagExpectedOp<>(f.clear(),
+                                             known.clone(),
+                                             preserve.clone(),
+                                             notKnown.clone()));
+            known.remove(f);
+            preserve.remove(f);
+            notKnown.add(f);
+        }
+        ops.add(cf.get());
+        ops.add(new TestFlagExpectedOp<>(0,
+                                         known.clone(),
+                                         preserve.clone(),
+                                         notKnown.clone()));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).
+                without(StreamTestScenario.CLEAR_SIZED_SCENARIOS).
+                exercise();
+    }
+
+    public void testFlagsSizedOrderedParallelCollect() {
+        EnumSet<StreamOpFlag> parKnown = EnumSet.of(StreamOpFlag.SIZED);
+        EnumSet<StreamOpFlag> serKnown = parKnown.clone();
+
+        List<IntermediateTestOp<Integer, Integer>> ops = new ArrayList<>();
+        for (StreamOpFlag f : parKnown) {
+            ops.add(CollectorOps.collector());
+            ops.add(new ParSerTestFlagExpectedOp<>(f.clear(),
+                                             parKnown,
+                                             serKnown));
+            serKnown.remove(f);
+        }
+        ops.add(CollectorOps.collector());
+        ops.add(new ParSerTestFlagExpectedOp<>(0,
+                                         parKnown,
+                                         EnumSet.noneOf(StreamOpFlag.class)));
+
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofArray("Array", countTo(10).toArray(new Integer[0]));
+        @SuppressWarnings("rawtypes")
+        IntermediateTestOp[] opsArray = ops.toArray(new IntermediateTestOp[ops.size()]);
+
+        withData(data).ops(opsArray).exercise();
+    }
+
+    static class ParSerTestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+        final EnumSet<StreamOpFlag> parKnown;
+        final EnumSet<StreamOpFlag> serKnown;
+
+        ParSerTestFlagExpectedOp(int flags, EnumSet<StreamOpFlag> known, EnumSet<StreamOpFlag> serKnown) {
+            super(flags);
+            this.parKnown = known;
+            this.serKnown = serKnown;
+        }
+
+        @Override
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+            assertFlags(flags, parallel);
+            return upstream;
+        }
+
+        protected void assertFlags(int flags, boolean parallel) {
+            if (parallel) {
+                for (StreamOpFlag f : parKnown) {
+                    Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+                }
+
+            } else {
+                for (StreamOpFlag f : serKnown) {
+                    Assert.assertTrue(f.isKnown(flags), String.format("Flag %s is not known, but should be known.", f.toString()));
+                }
+
+            }
+        }
+    }
+}
diff --git a/java/util/stream/ForEachOps.java b/java/util/stream/ForEachOps.java
new file mode 100644
index 0000000..b527f05
--- /dev/null
+++ b/java/util/stream/ForEachOps.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinTask;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * Factory for creating instances of {@code TerminalOp} that perform an
+ * action for every element of a stream.  Supported variants include unordered
+ * traversal (elements are provided to the {@code Consumer} as soon as they are
+ * available), and ordered traversal (elements are provided to the
+ * {@code Consumer} in encounter order.)
+ *
+ * <p>Elements are provided to the {@code Consumer} on whatever thread and
+ * whatever order they become available.  For ordered traversals, it is
+ * guaranteed that processing an element <em>happens-before</em> processing
+ * subsequent elements in the encounter order.
+ *
+ * <p>Exceptions occurring as a result of sending an element to the
+ * {@code Consumer} will be relayed to the caller and traversal will be
+ * prematurely terminated.
+ *
+ * @since 1.8
+ */
+final class ForEachOps {
+
+    private ForEachOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a stream.
+     *
+     * @param action the {@code Consumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @param <T> the type of the stream elements
+     * @return the {@code TerminalOp} instance
+     */
+    public static <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action,
+                                                  boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfRef<>(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of an {@code IntStream}.
+     *
+     * @param action the {@code IntConsumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Integer, Void> makeInt(IntConsumer action,
+                                                    boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfInt(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a {@code LongStream}.
+     *
+     * @param action the {@code LongConsumer} that receives all elements of a
+     *        stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Long, Void> makeLong(LongConsumer action,
+                                                  boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfLong(action, ordered);
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that perform an action for every element
+     * of a {@code DoubleStream}.
+     *
+     * @param action the {@code DoubleConsumer} that receives all elements of
+     *        a stream
+     * @param ordered whether an ordered traversal is requested
+     * @return the {@code TerminalOp} instance
+     */
+    public static TerminalOp<Double, Void> makeDouble(DoubleConsumer action,
+                                                      boolean ordered) {
+        Objects.requireNonNull(action);
+        return new ForEachOp.OfDouble(action, ordered);
+    }
+
+    /**
+     * A {@code TerminalOp} that evaluates a stream pipeline and sends the
+     * output to itself as a {@code TerminalSink}.  Elements will be sent in
+     * whatever thread they become available.  If the traversal is unordered,
+     * they will be sent independent of the stream's encounter order.
+     *
+     * <p>This terminal operation is stateless.  For parallel evaluation, each
+     * leaf instance of a {@code ForEachTask} will send elements to the same
+     * {@code TerminalSink} reference that is an instance of this class.
+     *
+     * @param <T> the output type of the stream pipeline
+     */
+    static abstract class ForEachOp<T>
+            implements TerminalOp<T, Void>, TerminalSink<T, Void> {
+        private final boolean ordered;
+
+        protected ForEachOp(boolean ordered) {
+            this.ordered = ordered;
+        }
+
+        // TerminalOp
+
+        @Override
+        public int getOpFlags() {
+            return ordered ? 0 : StreamOpFlag.NOT_ORDERED;
+        }
+
+        @Override
+        public <S> Void evaluateSequential(PipelineHelper<T> helper,
+                                           Spliterator<S> spliterator) {
+            return helper.wrapAndCopyInto(this, spliterator).get();
+        }
+
+        @Override
+        public <S> Void evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<S> spliterator) {
+            if (ordered)
+                new ForEachOrderedTask<>(helper, spliterator, this).invoke();
+            else
+                new ForEachTask<>(helper, spliterator, helper.wrapSink(this)).invoke();
+            return null;
+        }
+
+        // TerminalSink
+
+        @Override
+        public Void get() {
+            return null;
+        }
+
+        // Implementations
+
+        /** Implementation class for reference streams */
+        static final class OfRef<T> extends ForEachOp<T> {
+            final Consumer<? super T> consumer;
+
+            OfRef(Consumer<? super T> consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public void accept(T t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code IntStream} */
+        static final class OfInt extends ForEachOp<Integer>
+                implements Sink.OfInt {
+            final IntConsumer consumer;
+
+            OfInt(IntConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.INT_VALUE;
+            }
+
+            @Override
+            public void accept(int t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code LongStream} */
+        static final class OfLong extends ForEachOp<Long>
+                implements Sink.OfLong {
+            final LongConsumer consumer;
+
+            OfLong(LongConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.LONG_VALUE;
+            }
+
+            @Override
+            public void accept(long t) {
+                consumer.accept(t);
+            }
+        }
+
+        /** Implementation class for {@code DoubleStream} */
+        static final class OfDouble extends ForEachOp<Double>
+                implements Sink.OfDouble {
+            final DoubleConsumer consumer;
+
+            OfDouble(DoubleConsumer consumer, boolean ordered) {
+                super(ordered);
+                this.consumer = consumer;
+            }
+
+            @Override
+            public StreamShape inputShape() {
+                return StreamShape.DOUBLE_VALUE;
+            }
+
+            @Override
+            public void accept(double t) {
+                consumer.accept(t);
+            }
+        }
+    }
+
+    /** A {@code ForkJoinTask} for performing a parallel for-each operation */
+    @SuppressWarnings("serial")
+    static final class ForEachTask<S, T> extends CountedCompleter<Void> {
+        private Spliterator<S> spliterator;
+        private final Sink<S> sink;
+        private final PipelineHelper<T> helper;
+        private long targetSize;
+
+        ForEachTask(PipelineHelper<T> helper,
+                    Spliterator<S> spliterator,
+                    Sink<S> sink) {
+            super(null);
+            this.sink = sink;
+            this.helper = helper;
+            this.spliterator = spliterator;
+            this.targetSize = 0L;
+        }
+
+        ForEachTask(ForEachTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent);
+            this.spliterator = spliterator;
+            this.sink = parent.sink;
+            this.targetSize = parent.targetSize;
+            this.helper = parent.helper;
+        }
+
+        // Similar to AbstractTask but doesn't need to track child tasks
+        public void compute() {
+            Spliterator<S> rightSplit = spliterator, leftSplit;
+            long sizeEstimate = rightSplit.estimateSize(), sizeThreshold;
+            if ((sizeThreshold = targetSize) == 0L)
+                targetSize = sizeThreshold = AbstractTask.suggestTargetSize(sizeEstimate);
+            boolean isShortCircuit = StreamOpFlag.SHORT_CIRCUIT.isKnown(helper.getStreamAndOpFlags());
+            boolean forkRight = false;
+            Sink<S> taskSink = sink;
+            ForEachTask<S, T> task = this;
+            while (!isShortCircuit || !taskSink.cancellationRequested()) {
+                if (sizeEstimate <= sizeThreshold ||
+                    (leftSplit = rightSplit.trySplit()) == null) {
+                    task.helper.copyInto(taskSink, rightSplit);
+                    break;
+                }
+                ForEachTask<S, T> leftTask = new ForEachTask<>(task, leftSplit);
+                task.addToPendingCount(1);
+                ForEachTask<S, T> taskToFork;
+                if (forkRight) {
+                    forkRight = false;
+                    rightSplit = leftSplit;
+                    taskToFork = task;
+                    task = leftTask;
+                }
+                else {
+                    forkRight = true;
+                    taskToFork = leftTask;
+                }
+                taskToFork.fork();
+                sizeEstimate = rightSplit.estimateSize();
+            }
+            task.spliterator = null;
+            task.propagateCompletion();
+        }
+    }
+
+    /**
+     * A {@code ForkJoinTask} for performing a parallel for-each operation
+     * which visits the elements in encounter order
+     */
+    @SuppressWarnings("serial")
+    static final class ForEachOrderedTask<S, T> extends CountedCompleter<Void> {
+        /*
+         * Our goal is to ensure that the elements associated with a task are
+         * processed according to an in-order traversal of the computation tree.
+         * We use completion counts for representing these dependencies, so that
+         * a task does not complete until all the tasks preceding it in this
+         * order complete.  We use the "completion map" to associate the next
+         * task in this order for any left child.  We increase the pending count
+         * of any node on the right side of such a mapping by one to indicate
+         * its dependency, and when a node on the left side of such a mapping
+         * completes, it decrements the pending count of its corresponding right
+         * side.  As the computation tree is expanded by splitting, we must
+         * atomically update the mappings to maintain the invariant that the
+         * completion map maps left children to the next node in the in-order
+         * traversal.
+         *
+         * Take, for example, the following computation tree of tasks:
+         *
+         *       a
+         *      / \
+         *     b   c
+         *    / \ / \
+         *   d  e f  g
+         *
+         * The complete map will contain (not necessarily all at the same time)
+         * the following associations:
+         *
+         *   d -> e
+         *   b -> f
+         *   f -> g
+         *
+         * Tasks e, f, g will have their pending counts increased by 1.
+         *
+         * The following relationships hold:
+         *
+         *   - completion of d "happens-before" e;
+         *   - completion of d and e "happens-before b;
+         *   - completion of b "happens-before" f; and
+         *   - completion of f "happens-before" g
+         *
+         * Thus overall the "happens-before" relationship holds for the
+         * reporting of elements, covered by tasks d, e, f and g, as specified
+         * by the forEachOrdered operation.
+         */
+
+        private final PipelineHelper<T> helper;
+        private Spliterator<S> spliterator;
+        private final long targetSize;
+        private final ConcurrentHashMap<ForEachOrderedTask<S, T>, ForEachOrderedTask<S, T>> completionMap;
+        private final Sink<T> action;
+        private final ForEachOrderedTask<S, T> leftPredecessor;
+        private Node<T> node;
+
+        protected ForEachOrderedTask(PipelineHelper<T> helper,
+                                     Spliterator<S> spliterator,
+                                     Sink<T> action) {
+            super(null);
+            this.helper = helper;
+            this.spliterator = spliterator;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            // Size map to avoid concurrent re-sizes
+            this.completionMap = new ConcurrentHashMap<>(Math.max(16, AbstractTask.LEAF_TARGET << 1));
+            this.action = action;
+            this.leftPredecessor = null;
+        }
+
+        ForEachOrderedTask(ForEachOrderedTask<S, T> parent,
+                           Spliterator<S> spliterator,
+                           ForEachOrderedTask<S, T> leftPredecessor) {
+            super(parent);
+            this.helper = parent.helper;
+            this.spliterator = spliterator;
+            this.targetSize = parent.targetSize;
+            this.completionMap = parent.completionMap;
+            this.action = parent.action;
+            this.leftPredecessor = leftPredecessor;
+        }
+
+        @Override
+        public final void compute() {
+            doCompute(this);
+        }
+
+        private static <S, T> void doCompute(ForEachOrderedTask<S, T> task) {
+            Spliterator<S> rightSplit = task.spliterator, leftSplit;
+            long sizeThreshold = task.targetSize;
+            boolean forkRight = false;
+            while (rightSplit.estimateSize() > sizeThreshold &&
+                   (leftSplit = rightSplit.trySplit()) != null) {
+                ForEachOrderedTask<S, T> leftChild =
+                    new ForEachOrderedTask<>(task, leftSplit, task.leftPredecessor);
+                ForEachOrderedTask<S, T> rightChild =
+                    new ForEachOrderedTask<>(task, rightSplit, leftChild);
+
+                // Fork the parent task
+                // Completion of the left and right children "happens-before"
+                // completion of the parent
+                task.addToPendingCount(1);
+                // Completion of the left child "happens-before" completion of
+                // the right child
+                rightChild.addToPendingCount(1);
+                task.completionMap.put(leftChild, rightChild);
+
+                // If task is not on the left spine
+                if (task.leftPredecessor != null) {
+                    /*
+                     * Completion of left-predecessor, or left subtree,
+                     * "happens-before" completion of left-most leaf node of
+                     * right subtree.
+                     * The left child's pending count needs to be updated before
+                     * it is associated in the completion map, otherwise the
+                     * left child can complete prematurely and violate the
+                     * "happens-before" constraint.
+                     */
+                    leftChild.addToPendingCount(1);
+                    // Update association of left-predecessor to left-most
+                    // leaf node of right subtree
+                    if (task.completionMap.replace(task.leftPredecessor, task, leftChild)) {
+                        // If replaced, adjust the pending count of the parent
+                        // to complete when its children complete
+                        task.addToPendingCount(-1);
+                    } else {
+                        // Left-predecessor has already completed, parent's
+                        // pending count is adjusted by left-predecessor;
+                        // left child is ready to complete
+                        leftChild.addToPendingCount(-1);
+                    }
+                }
+
+                ForEachOrderedTask<S, T> taskToFork;
+                if (forkRight) {
+                    forkRight = false;
+                    rightSplit = leftSplit;
+                    task = leftChild;
+                    taskToFork = rightChild;
+                }
+                else {
+                    forkRight = true;
+                    task = rightChild;
+                    taskToFork = leftChild;
+                }
+                taskToFork.fork();
+            }
+
+            /*
+             * Task's pending count is either 0 or 1.  If 1 then the completion
+             * map will contain a value that is task, and two calls to
+             * tryComplete are required for completion, one below and one
+             * triggered by the completion of task's left-predecessor in
+             * onCompletion.  Therefore there is no data race within the if
+             * block.
+             */
+            if (task.getPendingCount() > 0) {
+                // Cannot complete just yet so buffer elements into a Node
+                // for use when completion occurs
+                @SuppressWarnings("unchecked")
+                IntFunction<T[]> generator = size -> (T[]) new Object[size];
+                Node.Builder<T> nb = task.helper.makeNodeBuilder(
+                        task.helper.exactOutputSizeIfKnown(rightSplit),
+                        generator);
+                task.node = task.helper.wrapAndCopyInto(nb, rightSplit).build();
+                task.spliterator = null;
+            }
+            task.tryComplete();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (node != null) {
+                // Dump buffered elements from this leaf into the sink
+                node.forEach(action);
+                node = null;
+            }
+            else if (spliterator != null) {
+                // Dump elements output from this leaf's pipeline into the sink
+                helper.wrapAndCopyInto(action, spliterator);
+                spliterator = null;
+            }
+
+            // The completion of this task *and* the dumping of elements
+            // "happens-before" completion of the associated left-most leaf task
+            // of right subtree (if any, which can be this task's right sibling)
+            //
+            ForEachOrderedTask<S, T> leftDescendant = completionMap.remove(this);
+            if (leftDescendant != null)
+                leftDescendant.tryComplete();
+        }
+    }
+}
diff --git a/java/util/stream/IntNodeTest.java b/java/util/stream/IntNodeTest.java
new file mode 100644
index 0000000..e050e63
--- /dev/null
+++ b/java/util/stream/IntNodeTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class IntNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            int[] array = new int[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toIntArray(l))));
+            nodes.add(fill(array, Nodes.intBuilder(array.length)));
+            nodes.add(fill(array, Nodes.intBuilder()));
+
+            for (Node<Integer> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListIntArray(List<Integer> list, int[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], (int) list.get(i));
+    }
+
+    private List<Integer> toList(int[] a) {
+        List<Integer> l = new ArrayList<>();
+        for (int i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private int[] toIntArray(List<Integer> l) {
+        int[] a = new int[l.size()];
+
+        int i = 0;
+        for (Integer e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfInt fill(int[] array, Node.Builder.OfInt nb) {
+        nb.begin(array.length);
+        for (int i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfInt degenerateTree(PrimitiveIterator.OfInt it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new int[0]);
+        }
+
+        int i = it.nextInt();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode.OfInt(Nodes.node(new int[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new int[] {i});
+        }
+    }
+
+    private Node.OfInt tree(List<Integer> l, Function<List<Integer>, Node.OfInt> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode.OfInt(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(int[] array, Node.OfInt n) {
+        assertEquals(n.asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(int[] array, Node.OfInt n) {
+        assertEquals(Nodes.flattenInt(n).asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(int[] array, Node.OfInt n) {
+        int[] copy = new int[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(int[] array, Node.OfInt n) {
+        List<Integer> l = new ArrayList<>((int) n.count());
+        n.forEach((int e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListIntArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(int[] array, Node.OfInt n) {
+        TestData.OfInt data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(int[] array, Node.OfInt n) {
+        SpliteratorTestHelper.testIntSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(int[] array, Node.OfInt n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node.OfInt slice = n.truncate(start, end, Integer[]::new);
+                int[] asArray = slice.asPrimitiveArray();
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/IntPipeline.java b/java/util/stream/IntPipeline.java
new file mode 100644
index 0000000..11f0bb7
--- /dev/null
+++ b/java/util/stream/IntPipeline.java
@@ -0,0 +1,665 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.IntSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code int}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class IntPipeline<E_IN>
+        extends AbstractPipeline<E_IN, Integer, IntStream>
+        implements IntStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    IntPipeline(Supplier<? extends Spliterator<Integer>> source,
+                int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    IntPipeline(Spliterator<Integer> source,
+                int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source
+     * @param opFlags the operation flags for the new operation
+     */
+    IntPipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Integer> to an {@code IntConsumer}, ideally simply
+     * by casting.
+     */
+    private static IntConsumer adapt(Sink<Integer> sink) {
+        if (sink instanceof IntConsumer) {
+            return (IntConsumer) sink;
+        }
+        else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using IntStream.adapt(Sink<Integer> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Integer>} to a {@code Spliterator.OfInt}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfInt, and throws an
+     * exception if this cast is not possible.
+     */
+    private static Spliterator.OfInt adapt(Spliterator<Integer> s) {
+        if (s instanceof Spliterator.OfInt) {
+            return (Spliterator.OfInt) s;
+        }
+        else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using IntStream.adapt(Spliterator<Integer> s)");
+            throw new UnsupportedOperationException("IntStream.adapt(Spliterator<Integer> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.INT_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Integer> evaluateToNode(PipelineHelper<Integer> helper,
+                                                     Spliterator<P_IN> spliterator,
+                                                     boolean flattenTree,
+                                                     IntFunction<Integer[]> generator) {
+        return Nodes.collectInt(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Integer> wrap(PipelineHelper<Integer> ph,
+                                                  Supplier<Spliterator<P_IN>> supplier,
+                                                  boolean isParallel) {
+        return new StreamSpliterators.IntWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfInt lazySpliterator(Supplier<? extends Spliterator<Integer>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfInt((Supplier<Spliterator.OfInt>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<Integer> spliterator, Sink<Integer> sink) {
+        Spliterator.OfInt spl = adapt(spliterator);
+        IntConsumer adaptedSink = adapt(sink);
+        do { } while (!sink.cancellationRequested() && spl.tryAdvance(adaptedSink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Integer> makeNodeBuilder(long exactSizeIfKnown,
+                                                       IntFunction<Integer[]> generator) {
+        return Nodes.intBuilder(exactSizeIfKnown);
+    }
+
+
+    // IntStream
+
+    @Override
+    public final PrimitiveIterator.OfInt iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfInt spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from IntStream
+
+    @Override
+    public final LongStream asLongStream() {
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            public Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedInt<Long>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept((long) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream asDoubleStream() {
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedInt<Double>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept((double) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<Integer> boxed() {
+        return mapToObj(Integer::valueOf);
+    }
+
+    @Override
+    public final IntStream map(IntUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE,
+                                                             StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedInt<U>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(IntToLongFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedInt<Long>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(IntToDoubleFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedInt<Double>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream flatMap(IntFunction<? extends IntStream> mapper) {
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        try (IntStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public IntStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final IntStream filter(IntPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream peek(IntConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
+                                        0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from IntStream
+
+    @Override
+    public final IntStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeInt(this, 0, maxSize);
+    }
+
+    @Override
+    public final IntStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeInt(this, n, -1);
+    }
+
+    @Override
+    public final IntStream sorted() {
+        return SortedOps.makeInt(this);
+    }
+
+    @Override
+    public final IntStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires an int-specific map/set implementation.
+        return boxed().distinct().mapToInt(i -> i);
+    }
+
+    // Terminal ops from IntStream
+
+    @Override
+    public void forEach(IntConsumer action) {
+        evaluate(ForEachOps.makeInt(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(IntConsumer action) {
+        evaluate(ForEachOps.makeInt(action, true));
+    }
+
+    @Override
+    public final int sum() {
+        return reduce(0, Integer::sum);
+    }
+
+    @Override
+    public final OptionalInt min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalInt max() {
+        return reduce(Math::max);
+    }
+
+    @Override
+    public final long count() {
+        return mapToLong(e -> 1L).sum();
+    }
+
+    @Override
+    public final OptionalDouble average() {
+        long[] avg = collect(() -> new long[2],
+                             (ll, i) -> {
+                                 ll[0]++;
+                                 ll[1] += i;
+                             },
+                             (ll, rr) -> {
+                                 ll[0] += rr[0];
+                                 ll[1] += rr[1];
+                             });
+        return avg[0] > 0
+               ? OptionalDouble.of((double) avg[1] / avg[0])
+               : OptionalDouble.empty();
+    }
+
+    @Override
+    public final IntSummaryStatistics summaryStatistics() {
+        return collect(IntSummaryStatistics::new, IntSummaryStatistics::accept,
+                       IntSummaryStatistics::combine);
+    }
+
+    @Override
+    public final int reduce(int identity, IntBinaryOperator op) {
+        return evaluate(ReduceOps.makeInt(identity, op));
+    }
+
+    @Override
+    public final OptionalInt reduce(IntBinaryOperator op) {
+        return evaluate(ReduceOps.makeInt(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjIntConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeInt(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(IntPredicate predicate) {
+        return evaluate(MatchOps.makeInt(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalInt findFirst() {
+        return evaluate(FindOps.makeInt(true));
+    }
+
+    @Override
+    public final OptionalInt findAny() {
+        return evaluate(FindOps.makeInt(false));
+    }
+
+    @Override
+    public final int[] toArray() {
+        return Nodes.flattenInt((Node.OfInt) evaluateToArrayNode(Integer[]::new))
+                        .asPrimitiveArray();
+    }
+
+    //
+
+    /**
+     * Source stage of an IntStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Constructor for the source stage of an IntStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Integer>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of an IntStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Integer> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Integer> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(IntConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            }
+            else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(IntConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            }
+            else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of an IntStream
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Construct a new IntStream by appending a stateless intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of an IntStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends IntPipeline<E_IN> {
+        /**
+         * Construct a new IntStream by appending a stateful intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                         Spliterator<P_IN> spliterator,
+                                                         IntFunction<Integer[]> generator);
+    }
+}
diff --git a/java/util/stream/IntStream.java b/java/util/stream/IntStream.java
new file mode 100644
index 0000000..94c2924
--- /dev/null
+++ b/java/util/stream/IntStream.java
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.IntSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntSupplier;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.ObjIntConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive int-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code int} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface IntStream extends BaseStream<Integer, IntStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    IntStream filter(IntPredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream map(IntUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(IntFunction<? extends U> mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(IntToLongFunction mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(IntToDoubleFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces an
+     *               {@code IntStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    IntStream flatMap(IntFunction<? extends IntStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    IntStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    IntStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     IntStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    IntStream peek(IntConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(IntSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    IntStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(IntSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    IntStream skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(IntConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(IntConsumer)
+     */
+    void forEachOrdered(IntConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    int[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     int result = identity;
+     *     for (int element : this stream)
+     *         result = accumulator.applyAsInt(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     int sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     int sum = integers.reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    int reduce(int identity, IntBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalInt} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     int result = null;
+     *     for (int element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsInt(result, element);
+     *     }
+     *     return foundAny ? OptionalInt.of(result) : OptionalInt.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(int, IntBinaryOperator)
+     */
+    OptionalInt reduce(IntBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (int element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(int, IntBinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjIntConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.  This is a special case
+     * of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the sum of elements in this stream
+     */
+    int sum();
+
+    /**
+     * Returns an {@code OptionalInt} describing the minimum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Integer::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return an {@code OptionalInt} containing the minimum element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt min();
+
+    /**
+     * Returns an {@code OptionalInt} describing the maximum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Integer::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalInt} containing the maximum element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
+     * this stream, or an empty optional if this stream is empty.  This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns an {@code IntSummaryStatistics} describing various
+     * summary data about the elements of this stream.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code IntSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    IntSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(IntPredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(IntPredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(IntPredicate predicate);
+
+    /**
+     * Returns an {@link OptionalInt} describing the first element of this
+     * stream, or an empty {@code OptionalInt} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalInt} describing the first element of this stream,
+     * or an empty {@code OptionalInt} if the stream is empty
+     */
+    OptionalInt findFirst();
+
+    /**
+     * Returns an {@link OptionalInt} describing some element of the stream, or
+     * an empty {@code OptionalInt} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalInt} describing some element of this stream, or
+     * an empty {@code OptionalInt} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalInt findAny();
+
+    /**
+     * Returns a {@code LongStream} consisting of the elements of this stream,
+     * converted to {@code long}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code LongStream} consisting of the elements of this stream,
+     * converted to {@code long}
+     */
+    LongStream asLongStream();
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}
+     */
+    DoubleStream asDoubleStream();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * each boxed to an {@code Integer}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to an {@code Integer}
+     */
+    Stream<Integer> boxed();
+
+    @Override
+    IntStream sequential();
+
+    @Override
+    IntStream parallel();
+
+    @Override
+    PrimitiveIterator.OfInt iterator();
+
+    @Override
+    Spliterator.OfInt spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for an {@code IntStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.IntStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code IntStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static IntStream empty() {
+        return StreamSupport.intStream(Spliterators.emptyIntSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code IntStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static IntStream of(int t) {
+        return StreamSupport.intStream(new Streams.IntStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static IntStream of(int... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code IntStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code IntStream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return A new sequential {@code IntStream}
+     */
+    public static IntStream iterate(final int seed, final IntUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfInt iterator = new PrimitiveIterator.OfInt() {
+            int t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public int nextInt() {
+                int v = t;
+                t = f.applyAsInt(t);
+                return v;
+            }
+        };
+        return StreamSupport.intStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code IntSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code IntSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code IntStream}
+     */
+    public static IntStream generate(IntSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.intStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfInt(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i < endExclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream range(int startInclusive, int endExclusive) {
+        if (startInclusive >= endExclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(
+                    new Streams.RangeIntSpliterator(startInclusive, endExclusive, false), false);
+        }
+    }
+
+    /**
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
+     * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (int i = startInclusive; i <= endInclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endInclusive the inclusive upper bound
+     * @return a sequential {@code IntStream} for the range of {@code int}
+     *         elements
+     */
+    public static IntStream rangeClosed(int startInclusive, int endInclusive) {
+        if (startInclusive > endInclusive) {
+            return empty();
+        } else {
+            return StreamSupport.intStream(
+                    new Streams.RangeIntSpliterator(startInclusive, endInclusive, true), false);
+        }
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static IntStream concat(IntStream a, IntStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt(
+                a.spliterator(), b.spliterator());
+        IntStream stream = StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for an {@code IntStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see IntStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends IntConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(int t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(int t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        IntStream build();
+    }
+}
diff --git a/java/util/stream/IntStreamTestDataProvider.java b/java/util/stream/IntStreamTestDataProvider.java
new file mode 100644
index 0000000..dded670
--- /dev/null
+++ b/java/util/stream/IntStreamTestDataProvider.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for int-valued streams */
+public class IntStreamTestDataProvider {
+    private static final int[] to0 = new int[0];
+    private static final int[] to1 = new int[1];
+    private static final int[] to10 = new int[10];
+    private static final int[] to100 = new int[100];
+    private static final int[] to1000 = new int[1000];
+    private static final int[] reversed = new int[100];
+    private static final int[] ones = new int[100];
+    private static final int[] twice = new int[200];
+    private static final int[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        int[][] arrays = {to0, to1, to10, to100, to1000};
+        for (int[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new int[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final int[] ints = (int[]) data[1];
+
+                list.add(new Object[]{"array:" +
+                                      name, TestData.Factory.ofArray("array:" + name, ints)});
+
+                SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+                for (int i : ints) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                         TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("IntStream.intRange(0,l): " + ints.length,
+                                         () -> IntStream.range(0, ints.length)));
+                list.add(streamDataDescr("IntStream.rangeClosed(0,l): " + ints.length,
+                                         () -> IntStream.rangeClosed(0, ints.length)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final int[] ints = (int[]) data[1];
+
+                SpinedBuffer.OfInt isl = new SpinedBuffer.OfInt();
+                for (int i : ints) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(ints)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(ints, 0, ints.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), ints.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("IntStream.intRange(0,l):" + name,
+                                            () -> IntStream.range(0, ints.length).spliterator()));
+                spliterators.add(splitDescr("IntStream.intRangeClosed(0,l):" + name,
+                                            () -> IntStream.rangeClosed(0, ints.length).spliterator()));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<IntStream> s) {
+        return new Object[] { description, TestData.Factory.ofIntSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfInt> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, IntStreamTestData )
+    @DataProvider(name = "IntStreamTestData")
+    public static Object[][] makeIntStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Integer>>)
+    @DataProvider(name = "IntSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/IntStreamTestScenario.java b/java/util/stream/IntStreamTestScenario.java
new file mode 100644
index 0000000..9a3cc44
--- /dev/null
+++ b/java/util/stream/IntStreamTestScenario.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+
+/**
+ * Test scenarios for int streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            IntStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (int t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (PrimitiveIterator.OfInt seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextInt());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (Spliterator.OfInt spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (Spliterator.OfInt spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            for (int t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            IntStream s = m.apply(data.parallelStream());
+            Spliterator.OfInt sp = s.spliterator();
+            IntStream ss = StreamSupport.intStream(() -> sp,
+                                                   StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                   | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED),
+                                                   true);
+            for (int t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            IntStream pipe2 = m.apply(pipe1);
+
+            for (int t : pipe2.toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<IntStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private final boolean isParallel;
+
+    private final boolean isOrdered;
+
+    IntStreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    IntStreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.INT_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (IntConsumer) b, (Function<S_IN, IntStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m);
+
+}
diff --git a/java/util/stream/IntermediateTestOp.java b/java/util/stream/IntermediateTestOp.java
new file mode 100644
index 0000000..1ed04c7
--- /dev/null
+++ b/java/util/stream/IntermediateTestOp.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * A base type for test operations
+ */
+interface IntermediateTestOp<E_IN, E_OUT> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            IntermediateTestOp<?, T> op) {
+        if (op instanceof StatelessTestOp)
+            return StatelessTestOp.chain(upstream, (StatelessTestOp) op);
+
+        if (op instanceof StatefulTestOp)
+            return StatefulTestOp.chain(upstream, (StatefulTestOp) op);
+
+        throw new IllegalStateException("Unknown test op type: " + op.getClass().getName());
+    }
+}
diff --git a/java/util/stream/LambdaTestHelpers.java b/java/util/stream/LambdaTestHelpers.java
new file mode 100644
index 0000000..76a4d72
--- /dev/null
+++ b/java/util/stream/LambdaTestHelpers.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.*;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoublePredicate;
+import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * LambdaTestHelpers -- assertion methods and useful objects for lambda test cases
+ */
+public class LambdaTestHelpers {
+    public static final String LONG_STRING = "When in the Course of human events it becomes necessary for one people to dissolve the political bands which have connected them with another and to assume among the powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the separation.";
+
+    @SuppressWarnings("rawtypes")
+    public static final Consumer bEmpty = x -> {  };
+    @SuppressWarnings("rawtypes")
+    public static final IntConsumer bIntEmpty = x -> {  };
+    @SuppressWarnings("rawtypes")
+    public static final BiConsumer bBiEmpty = (x,y) -> { };
+    @SuppressWarnings("rawtypes")
+    public static final Consumer bHashCode = x -> { Objects.hashCode(x); };
+    @SuppressWarnings("rawtypes")
+    public static final BiConsumer bBiHashCode = (x,y) -> { Objects.hash(x, y); };
+    public static final Function<Integer, Integer> mZero = x -> 0;
+    public static final Function<Integer, Integer> mId = x -> x;
+    public static final Function<Integer, Integer> mDoubler = x -> x * 2;
+    public static final Function<Integer, Stream<Integer>> mfId = e -> Collections.singletonList(e).stream();
+    public static final Function<Integer, Stream<Integer>> mfNull = e -> Collections.<Integer>emptyList().stream();
+    public static final Function<Integer, Stream<Integer>> mfLt = e -> {
+        List<Integer> l = new ArrayList<>();
+        for (int i=0; i<e; i++)
+            l.add(i);
+        return l.stream();
+    };
+    public static final ToIntFunction<Integer> imDoubler = x -> x * 2;
+    public static final ToLongFunction<Long> lmDoubler = x -> x * 2;
+    public static final ToDoubleFunction<Double> dmDoubler = x -> x * 2;
+    public static final Predicate<Integer> pFalse = x -> false;
+    public static final Predicate<Integer> pTrue = x -> true;
+    public static final Predicate<Integer> pEven = x -> 0 == x % 2;
+    public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
+    public static final IntPredicate ipFalse = x -> false;
+    public static final IntPredicate ipTrue = x -> true;
+    public static final IntPredicate ipEven = x -> 0 == x % 2;
+    public static final IntPredicate ipOdd = x -> 1 == x % 2;
+    public static final LongPredicate lpFalse = x -> false;
+    public static final LongPredicate lpTrue = x -> true;
+    public static final LongPredicate lpEven = x -> 0 == x % 2;
+    public static final LongPredicate lpOdd = x -> 1 == x % 2;
+    public static final DoublePredicate dpFalse = x -> false;
+    public static final DoublePredicate dpTrue = x -> true;
+    public static final DoublePredicate dpEven = x -> 0 == ((long) x) % 2;
+    public static final DoublePredicate dpOdd = x -> 1 == ((long) x) % 2;
+    public static final BinaryOperator<Integer> rPlus = (x, y) -> x+y;
+    public static final BinaryOperator<Integer> rMax = (x, y) -> Math.max(x, y);
+    public static final BinaryOperator<Integer> rMin = (x, y) -> Math.min(x,y);
+    public static final IntBinaryOperator irPlus = (x, y) -> x+y;
+    public static final IntBinaryOperator irMax = (x, y) -> Math.max(x, y);
+    public static final IntBinaryOperator irMin = (x, y) -> Math.min(x,y);
+    public static final IntUnaryOperator irDoubler = x -> x * 2;
+    public static final LongBinaryOperator lrPlus = (x, y) -> x+y;
+    public static final DoubleBinaryOperator drPlus = (x, y) -> x+y;
+    public static final Comparator<Integer> cInteger = (a, b) -> Integer.compare(a, b);
+    public static final BiPredicate<?, ?> bipFalse = (x, y) -> false;
+    public static final BiPredicate<?, ?> bipTrue = (x, y) -> true;
+    public static final BiPredicate<Integer, Integer> bipBothEven = (x, y) -> 0 == (x % 2 + y % 2);
+    public static final BiPredicate<Integer, Integer> bipBothOdd = (x, y) -> 2 == (x % 2 + y % 2);
+    public static final BiPredicate<?, ?> bipSameString = (x, y) -> String.valueOf(x).equals(String.valueOf(y));
+
+    public static final IntFunction<Integer[]> integerArrayGenerator = s -> new Integer[s];
+
+    public static final IntFunction<Object[]> objectArrayGenerator = s -> new Object[s];
+
+    public static final Function<String, Stream<Character>> flattenChars = string -> {
+        List<Character> l = new ArrayList<>();
+        for (int i=0; i<string.length(); i++)
+            l.add(string.charAt(i));
+        return l.stream();
+    };
+
+    public static final Function<String, IntStream> flattenInt
+            = string -> IntStream.range(0, string.length()).map(string::charAt);
+
+    public static <T, R> Function<T, R> forPredicate(Predicate<? super T> predicate, R forTrue, R forFalse) {
+        Objects.requireNonNull(predicate);
+
+        return t -> predicate.test(t) ? forTrue : forFalse;
+    }
+
+    public static <T> Function<T, T> identity() {
+        return t -> t;
+    }
+
+    public static<V, T, R> Function<V, R> compose(Function<? super T, ? extends R> after, Function<? super V, ? extends T> before) {
+        Objects.requireNonNull(before);
+        return (V v) -> after.apply(before.apply(v));
+    }
+
+    public static List<Integer> empty() {
+        ArrayList<Integer> list = new ArrayList<>();
+        list.add(null);
+        return list;
+    }
+
+    public static List<Integer> countTo(int n) {
+        return range(1, n);
+    }
+
+    public static List<Integer> range(int l, int u) {
+        ArrayList<Integer> list = new ArrayList<>(u - l + 1);
+        for (int i=l; i<=u; i++) {
+            list.add(i);
+        }
+        return list;
+    }
+
+    public static List<Integer> repeat(int value, int n) {
+        ArrayList<Integer> list = new ArrayList<>(n);
+        for (int i=1; i<=n; i++) {
+            list.add(value);
+        }
+        return list;
+    }
+
+    public static List<Double> asDoubles(List<Integer> integers) {
+        ArrayList<Double> list = new ArrayList<>();
+        for (Integer i : integers) {
+            list.add((double) i);
+        }
+        return list;
+    }
+
+    public static List<Long> asLongs(List<Integer> integers) {
+        ArrayList<Long> list = new ArrayList<>();
+        for (Integer i : integers) {
+            list.add((long) i);
+        }
+        return list;
+    }
+
+    public static void assertCountSum(Stream<? super Integer> it, int count, int sum) {
+        assertCountSum(it.iterator(), count, sum);
+    }
+
+    public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
+        assertCountSum(it.iterator(), count, sum);
+    }
+
+    public static void assertCountSum(Iterator<? super Integer> it, int count, int sum) {
+        int c = 0;
+        int s = 0;
+        while (it.hasNext()) {
+            int i = (Integer) it.next();
+            c++;
+            s += i;
+        }
+
+        assertEquals(c, count);
+        assertEquals(s, sum);
+    }
+
+    public static void assertConcat(Iterator<Character> it, String result) {
+        StringBuilder sb = new StringBuilder();
+        while (it.hasNext()) {
+            sb.append(it.next());
+        }
+
+        assertEquals(result, sb.toString());
+    }
+
+    public static<T extends Comparable<? super T>> void assertSorted(Iterator<T> i) {
+        i = toBoxedList(i).iterator();
+
+        if (!i.hasNext())
+            return;
+        T last = i.next();
+        while (i.hasNext()) {
+            T t = i.next();
+            assertTrue(last.compareTo(t) <= 0);
+            assertTrue(t.compareTo(last) >= 0);
+            last = t;
+        }
+    }
+
+    public static<T> void assertSorted(Iterator<T> i, Comparator<? super T> comp) {
+        if (i instanceof PrimitiveIterator.OfInt
+                || i instanceof PrimitiveIterator.OfDouble
+                || i instanceof PrimitiveIterator.OfLong) {
+            i = toBoxedList(i).iterator();
+        }
+
+        if (!i.hasNext())
+            return;
+        T last = i.next();
+        while (i.hasNext()) {
+            T t = i.next();
+            assertTrue(comp.compare(last, t) <= 0);
+            assertTrue(comp.compare(t, last) >= 0);
+            last = t;
+        }
+    }
+
+    public static<T extends Comparable<? super T>> void assertSorted(Iterable<T> iter) {
+        assertSorted(iter.iterator());
+    }
+
+    public static<T> void assertSorted(Iterable<T> iter, Comparator<? super T> comp) {
+        assertSorted(iter.iterator(), comp);
+    }
+
+    public static <T> void assertUnique(Iterable<T> iter) {
+        assertUnique(iter.iterator());
+    }
+
+    public static<T> void assertUnique(Iterator<T> iter) {
+        if (!iter.hasNext()) {
+            return;
+        }
+
+        if (iter instanceof PrimitiveIterator.OfInt
+            || iter instanceof PrimitiveIterator.OfDouble
+            || iter instanceof PrimitiveIterator.OfLong) {
+            iter = toBoxedList(iter).iterator();
+        }
+
+        Set<T> uniq = new HashSet<>();
+        while(iter.hasNext()) {
+            T each = iter.next();
+            assertTrue(!uniq.contains(each), "Not unique");
+            uniq.add(each);
+        }
+    }
+
+    public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
+        if (actual instanceof Collection && expected instanceof Collection) {
+            assertEquals(actual, expected);
+        } else {
+            assertContents(actual.iterator(), expected.iterator());
+        }
+    }
+
+    public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
+        assertEquals(toBoxedList(actual), toBoxedList(expected));
+    }
+
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public static<T> void assertContents(Iterator<T> actual, T... expected) {
+        assertContents(actual, Arrays.asList(expected).iterator());
+    }
+
+    /**
+     * The all consuming consumer (rampant capitalist) that can accepting a reference or any primitive value.
+     */
+    private static interface OmnivorousConsumer<T>
+            extends Consumer<T>, IntConsumer, LongConsumer, DoubleConsumer { }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> Consumer<T> toBoxingConsumer(Consumer<? super T> c) {
+        return (Consumer<T>) new OmnivorousConsumer() {
+            @Override
+            public void accept(Object t) {
+                c.accept((T) t);
+            }
+
+            @Override
+            public void accept(int t) {
+                accept((Object) t);
+            }
+
+            @Override
+            public void accept(long t) {
+                accept((Object) t);
+            }
+
+            @Override
+            public void accept(double t) {
+                accept((Object) t);
+            }
+        };
+    }
+
+    /**
+     * Convert an iterator to a list using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    private static<T> List<T> toBoxedList(Iterator<T> it) {
+        List<T> l = new ArrayList<>();
+        it.forEachRemaining(toBoxingConsumer(l::add));
+        return l;
+    }
+
+    /**
+     * Convert a spliterator to a list using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    public static<T> List<T> toBoxedList(Spliterator<T> sp) {
+        List<T> l = new ArrayList<>();
+        sp.forEachRemaining(toBoxingConsumer(l::add));
+        return l;
+    }
+
+    /**
+     * Convert an iterator to a multi-set, represented as a Map, using forEach with an implementation of
+     * {@link java.util.stream.LambdaTestHelpers.OmnivorousConsumer}.
+     *
+     * This ensures equality comparisons for test results do not trip
+     * the boxing trip-wires.
+     */
+    @SuppressWarnings("unchecked")
+    private static<T> Map<T, Integer> toBoxedMultiset(Iterator<T> it) {
+        Map<Object, Integer> result = new HashMap<>();
+
+        it.forEachRemaining(toBoxingConsumer(o -> {
+                if (result.containsKey(o))
+                    result.put(o, result.get(o) + 1);
+                else
+                    result.put(o, 1);
+            }));
+
+        return (Map<T, Integer>) result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static<T> Map<T, Integer> toBoxedMultiset(Spliterator<T> it) {
+        Map<Object, Integer> result = new HashMap<>();
+
+        it.forEachRemaining(toBoxingConsumer(o -> {
+                if (result.containsKey(o))
+                    result.put(o, result.get(o) + 1);
+                else
+                    result.put(o, 1);
+            }));
+
+        return (Map<T, Integer>) result;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static void assertContentsEqual(Object a, Object b) {
+        if (a instanceof Iterable && b instanceof Iterable)
+            assertContents((Iterable) a, (Iterable) b);
+        else
+            assertEquals(a, b);
+    }
+
+    public static<T> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+        assertContentsUnordered(actual.iterator(), expected.iterator());
+    }
+
+    public static<T> void assertContentsUnordered(Iterator<T> actual, Iterator<T> expected) {
+        assertEquals(toBoxedMultiset(actual), toBoxedMultiset(expected));
+    }
+
+    public static void launderAssertion(Runnable r, Supplier<String> additionalInfo) {
+        try {
+            r.run();
+        }
+        catch (AssertionError ae) {
+            AssertionError cloned = new AssertionError(ae.getMessage() + String.format("%n%s", additionalInfo.get()));
+            cloned.setStackTrace(ae.getStackTrace());
+            if (ae.getCause() != null)
+                cloned.initCause(ae.getCause());
+            throw cloned;
+        }
+    }
+
+    public static <T, S extends BaseStream<T, S>>
+    List<Function<S, S>> permuteStreamFunctions(List<Function<S, S>> opFunctions) {
+        List<List<Function<S, S>>> opFunctionPermutations = perm(opFunctions);
+
+        List<Function<S, S>> appliedFunctions = new ArrayList<>();
+        for (List<Function<S, S>> fs : opFunctionPermutations) {
+            Function<S, S> applied = s -> {
+                for (Function<S, S> f : fs) {
+                    s = f.apply(s);
+                }
+                return s;
+            };
+            appliedFunctions.add(applied);
+        }
+
+        return appliedFunctions;
+    }
+
+    private static <T> List<T> sub(List<T> l, int index) {
+        List<T> subL = new ArrayList<>(l);
+        subL.remove(index);
+        return subL;
+    }
+
+    public static <T> List<List<T>> perm(List<T> l) {
+        List<List<T>> result = new ArrayList<>();
+        for (int i = 0; i < l.size(); i++) {
+            for (List<T> perm : perm(sub(l, i))) {
+                perm.add(0, l.get(i));
+                result.add(perm);
+            }
+        }
+        result.add(new ArrayList<T>());
+
+        return result;
+    }
+
+    public static String flagsToString(int flags) {
+        StringJoiner sj = new StringJoiner(", ", "StreamOpFlag[", "]");
+        if (StreamOpFlag.DISTINCT.isKnown(flags)) sj.add("IS_DISTINCT");
+        if (StreamOpFlag.ORDERED.isKnown(flags)) sj.add("IS_ORDERED");
+        if (StreamOpFlag.SIZED.isKnown(flags)) sj.add("IS_SIZED");
+        if (StreamOpFlag.SORTED.isKnown(flags)) sj.add("IS_SORTED");
+        if (StreamOpFlag.SHORT_CIRCUIT.isKnown(flags)) sj.add("IS_SHORT_CIRCUIT");
+        return sj.toString();
+    }
+}
diff --git a/java/util/stream/LambdaTestMode.java b/java/util/stream/LambdaTestMode.java
new file mode 100644
index 0000000..b598964
--- /dev/null
+++ b/java/util/stream/LambdaTestMode.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Runtime modes of test execution.
+ */
+public enum LambdaTestMode {
+    /**
+     * Execution mode with no particular runtime constraints.
+     */
+    NORMAL,
+
+    /**
+     * Execution mode where tests are executed for testing lambda serialization
+     * and deserialization.
+     *
+     * <p>This mode may be queried by tests or data supplied by data
+     * providers, which cannot otherwise be assigned to the test group
+     * <em>serialization-hostile</em>, to not execute or declare
+     * serialization-hostile code or data.
+     *
+     * <p>This mode is enabled if the boolean system property
+     * {@code org.openjdk.java.util.stream.sand.mode} is declared with a
+     * {@code true} value.
+     */
+    SERIALIZATION;
+
+    /**
+     * {@code true} if tests are executed in the mode for testing lambda
+     * Serialization ANd Deserialization (SAND).
+     */
+    private static final boolean IS_LAMBDA_SERIALIZATION_MODE =
+            Boolean.getBoolean("org.openjdk.java.util.stream.sand.mode");
+
+    /**
+     *
+     * @return the mode of test execution.
+     */
+    public static LambdaTestMode getMode() {
+        return IS_LAMBDA_SERIALIZATION_MODE ? SERIALIZATION : NORMAL;
+    }
+
+    /**
+     *
+     * @return {@code true} if normal test mode.
+     */
+    public static boolean isNormalMode() {
+        return getMode() == NORMAL;
+    }
+}
diff --git a/java/util/stream/LoggingTestCase.java b/java/util/stream/LoggingTestCase.java
new file mode 100644
index 0000000..a0f2219
--- /dev/null
+++ b/java/util/stream/LoggingTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.Assert;
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/**
+ * LoggingTestCase
+ *
+ */
+@Test
+public class LoggingTestCase extends Assert {
+    private Map<String, Object> context = new HashMap<>();
+
+    @BeforeMethod
+    public void before() {
+        context.clear();
+    }
+
+    @AfterMethod
+    public void after(ITestResult result) {
+        if (!result.isSuccess()) {
+            List<Object> list = new ArrayList<>();
+            Collections.addAll(list, result.getParameters());
+            list.add(context.toString());
+            result.setParameters(list.toArray(new Object[list.size()]));
+        }
+    }
+
+    protected void setContext(String key, Object value) {
+        context.put(key, value);
+    }
+
+    protected void clearContext(String key) {
+        context.remove(key);
+    }
+}
diff --git a/java/util/stream/LongNodeTest.java b/java/util/stream/LongNodeTest.java
new file mode 100644
index 0000000..d266fd7
--- /dev/null
+++ b/java/util/stream/LongNodeTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.PrimitiveIterator;
+import java.util.Spliterators;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class LongNodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            long[] array = new long[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Long>> nodes = new ArrayList<>();
+
+            nodes.add(Nodes.node(array));
+            nodes.add(degenerateTree(Spliterators.iterator(Arrays.spliterator(array))));
+            nodes.add(tree(toList(array), l -> Nodes.node(toLongArray(l))));
+            nodes.add(fill(array, Nodes.longBuilder(array.length)));
+            nodes.add(fill(array, Nodes.longBuilder()));
+
+            for (Node<Long> node : nodes) {
+                params.add(new Object[]{array, node});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    private static void assertEqualsListLongArray(List<Long> list, long[] array) {
+        assertEquals(list.size(), array.length);
+        for (int i = 0; i < array.length; i++)
+            assertEquals(array[i], (long) list.get(i));
+    }
+
+    private List<Long> toList(long[] a) {
+        List<Long> l = new ArrayList<>();
+        for (long i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    private long[] toLongArray(List<Long> l) {
+        long[] a = new long[l.size()];
+
+        int i = 0;
+        for (Long e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    private Node.OfLong fill(long[] array, Node.Builder.OfLong nb) {
+        nb.begin(array.length);
+        for (long i : array)
+            nb.accept(i);
+        nb.end();
+        return nb.build();
+    }
+
+    private Node.OfLong degenerateTree(PrimitiveIterator.OfLong it) {
+        if (!it.hasNext()) {
+            return Nodes.node(new long[0]);
+        }
+
+        long i = it.nextLong();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode.OfLong(Nodes.node(new long[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new long[] {i});
+        }
+    }
+
+    private Node.OfLong tree(List<Long> l, Function<List<Long>, Node.OfLong> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode.OfLong(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(long[] array, Node.OfLong n) {
+        assertEquals(n.asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(long[] array, Node.OfLong n) {
+        assertEquals(Nodes.flattenLong(n).asPrimitiveArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(long[] array, Node.OfLong n) {
+        long[] copy = new long[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(long[] array, Node.OfLong n) {
+        List<Long> l = new ArrayList<>((int) n.count());
+        n.forEach((long e) -> {
+            l.add(e);
+        });
+
+        assertEqualsListLongArray(l, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(long[] array, Node.OfLong n) {
+        TestData.OfLong data = TestData.Factory.ofNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(long[] array, Node.OfLong n) {
+        SpliteratorTestHelper.testLongSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(long[] array, Node.OfLong n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node.OfLong slice = n.truncate(start, end, Long[]::new);
+                long[] asArray = slice.asPrimitiveArray();
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/LongPipeline.java b/java/util/stream/LongPipeline.java
new file mode 100644
index 0000000..768a378
--- /dev/null
+++ b/java/util/stream/LongPipeline.java
@@ -0,0 +1,646 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.LongSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.IntFunction;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code long}.
+ *
+ * @param <E_IN> type of elements in the upstream source
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class LongPipeline<E_IN>
+        extends AbstractPipeline<E_IN, Long, LongStream>
+        implements LongStream {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    LongPipeline(Supplier<? extends Spliterator<Long>> source,
+                 int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    LongPipeline(Spliterator<Long> source,
+                 int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing pipeline.
+     *
+     * @param upstream the upstream element source.
+     * @param opFlags the operation flags
+     */
+    LongPipeline(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    /**
+     * Adapt a {@code Sink<Long> to an {@code LongConsumer}, ideally simply
+     * by casting.
+     */
+    private static LongConsumer adapt(Sink<Long> sink) {
+        if (sink instanceof LongConsumer) {
+            return (LongConsumer) sink;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using LongStream.adapt(Sink<Long> s)");
+            return sink::accept;
+        }
+    }
+
+    /**
+     * Adapt a {@code Spliterator<Long>} to a {@code Spliterator.OfLong}.
+     *
+     * @implNote
+     * The implementation attempts to cast to a Spliterator.OfLong, and throws
+     * an exception if this cast is not possible.
+     */
+    private static Spliterator.OfLong adapt(Spliterator<Long> s) {
+        if (s instanceof Spliterator.OfLong) {
+            return (Spliterator.OfLong) s;
+        } else {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(AbstractPipeline.class,
+                              "using LongStream.adapt(Spliterator<Long> s)");
+            throw new UnsupportedOperationException("LongStream.adapt(Spliterator<Long> s)");
+        }
+    }
+
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.LONG_VALUE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<Long> evaluateToNode(PipelineHelper<Long> helper,
+                                           Spliterator<P_IN> spliterator,
+                                           boolean flattenTree,
+                                           IntFunction<Long[]> generator) {
+        return Nodes.collectLong(helper, spliterator, flattenTree);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<Long> wrap(PipelineHelper<Long> ph,
+                                        Supplier<Spliterator<P_IN>> supplier,
+                                        boolean isParallel) {
+        return new StreamSpliterators.LongWrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator.OfLong lazySpliterator(Supplier<? extends Spliterator<Long>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator.OfLong((Supplier<Spliterator.OfLong>) supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<Long> spliterator, Sink<Long> sink) {
+        Spliterator.OfLong spl = adapt(spliterator);
+        LongConsumer adaptedSink =  adapt(sink);
+        do { } while (!sink.cancellationRequested() && spl.tryAdvance(adaptedSink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<Long> makeNodeBuilder(long exactSizeIfKnown, IntFunction<Long[]> generator) {
+        return Nodes.longBuilder(exactSizeIfKnown);
+    }
+
+
+    // LongStream
+
+    @Override
+    public final PrimitiveIterator.OfLong iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public final Spliterator.OfLong spliterator() {
+        return adapt(super.spliterator());
+    }
+
+    // Stateless intermediate ops from LongStream
+
+    @Override
+    public final DoubleStream asDoubleStream() {
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedLong<Double>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept((double) t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<Long> boxed() {
+        return mapToObj(Long::valueOf);
+    }
+
+    @Override
+    public final LongStream map(LongUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsLong(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
+        Objects.requireNonNull(mapper);
+        return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE,
+                                                          StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedLong<U>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(LongToIntFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                 StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedLong<Integer>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsInt(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(LongToDoubleFunction mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedLong<Double>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.applyAsDouble(t));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream flatMap(LongFunction<? extends LongStream> mapper) {
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        try (LongStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public LongStream unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final LongStream filter(LongPredicate predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (predicate.test(t))
+                            downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream peek(LongConsumer action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
+                                     0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        action.accept(t);
+                        downstream.accept(t);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate ops from LongStream
+
+    @Override
+    public final LongStream limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeLong(this, 0, maxSize);
+    }
+
+    @Override
+    public final LongStream skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeLong(this, n, -1);
+    }
+
+    @Override
+    public final LongStream sorted() {
+        return SortedOps.makeLong(this);
+    }
+
+    @Override
+    public final LongStream distinct() {
+        // While functional and quick to implement, this approach is not very efficient.
+        // An efficient version requires a long-specific map/set implementation.
+        return boxed().distinct().mapToLong(i -> (long) i);
+    }
+
+    // Terminal ops from LongStream
+
+    @Override
+    public void forEach(LongConsumer action) {
+        evaluate(ForEachOps.makeLong(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(LongConsumer action) {
+        evaluate(ForEachOps.makeLong(action, true));
+    }
+
+    @Override
+    public final long sum() {
+        // use better algorithm to compensate for intermediate overflow?
+        return reduce(0, Long::sum);
+    }
+
+    @Override
+    public final OptionalLong min() {
+        return reduce(Math::min);
+    }
+
+    @Override
+    public final OptionalLong max() {
+        return reduce(Math::max);
+    }
+
+    @Override
+    public final OptionalDouble average() {
+        long[] avg = collect(() -> new long[2],
+                             (ll, i) -> {
+                                 ll[0]++;
+                                 ll[1] += i;
+                             },
+                             (ll, rr) -> {
+                                 ll[0] += rr[0];
+                                 ll[1] += rr[1];
+                             });
+        return avg[0] > 0
+               ? OptionalDouble.of((double) avg[1] / avg[0])
+               : OptionalDouble.empty();
+    }
+
+    @Override
+    public final long count() {
+        return map(e -> 1L).sum();
+    }
+
+    @Override
+    public final LongSummaryStatistics summaryStatistics() {
+        return collect(LongSummaryStatistics::new, LongSummaryStatistics::accept,
+                       LongSummaryStatistics::combine);
+    }
+
+    @Override
+    public final long reduce(long identity, LongBinaryOperator op) {
+        return evaluate(ReduceOps.makeLong(identity, op));
+    }
+
+    @Override
+    public final OptionalLong reduce(LongBinaryOperator op) {
+        return evaluate(ReduceOps.makeLong(op));
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               ObjLongConsumer<R> accumulator,
+                               BiConsumer<R, R> combiner) {
+        BinaryOperator<R> operator = (left, right) -> {
+            combiner.accept(left, right);
+            return left;
+        };
+        return evaluate(ReduceOps.makeLong(supplier, accumulator, operator));
+    }
+
+    @Override
+    public final boolean anyMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(LongPredicate predicate) {
+        return evaluate(MatchOps.makeLong(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final OptionalLong findFirst() {
+        return evaluate(FindOps.makeLong(true));
+    }
+
+    @Override
+    public final OptionalLong findAny() {
+        return evaluate(FindOps.makeLong(false));
+    }
+
+    @Override
+    public final long[] toArray() {
+        return Nodes.flattenLong((Node.OfLong) evaluateToArrayNode(Long[]::new))
+                .asPrimitiveArray();
+    }
+
+
+    //
+
+    /**
+     * Source stage of a LongPipeline.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Made public for CTS tests only (OpenJDK 8 streams tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Constructor for the source stage of a LongStream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<Long>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a LongStream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         * @param parallel {@code true} if the pipeline is parallel
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<Long> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<Long> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(LongConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            } else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(LongConsumer action) {
+            if (!isParallel()) {
+                adapt(sourceStageSpliterator()).forEachRemaining(action);
+            } else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /** Base class for a stateless intermediate stage of a LongStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Construct a new LongStream by appending a stateless intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a LongStream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN> extends LongPipeline<E_IN> {
+        /**
+         * Construct a new LongStream by appending a stateful intermediate
+         * operation to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         * @hide Visible for CTS testing only (OpenJDK8 tests).
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<Long[]> generator);
+    }
+}
diff --git a/java/util/stream/LongStream.java b/java/util/stream/LongStream.java
new file mode 100644
index 0000000..a2d429e
--- /dev/null
+++ b/java/util/stream/LongStream.java
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LongSummaryStatistics;
+import java.util.Objects;
+import java.util.OptionalDouble;
+import java.util.OptionalLong;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.LongBinaryOperator;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+import java.util.function.LongPredicate;
+import java.util.function.LongSupplier;
+import java.util.function.LongToDoubleFunction;
+import java.util.function.LongToIntFunction;
+import java.util.function.LongUnaryOperator;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * A sequence of primitive long-valued elements supporting sequential and parallel
+ * aggregate operations.  This is the {@code long} primitive specialization of
+ * {@link Stream}.
+ *
+ * <p>The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link LongStream}, computing the sum of the weights of the
+ * red widgets:
+ *
+ * <pre>{@code
+ *     long sum = widgets.stream()
+ *                       .filter(w -> w.getColor() == RED)
+ *                       .mapToLong(w -> w.getWeight())
+ *                       .sum();
+ * }</pre>
+ *
+ * See the class documentation for {@link Stream} and the package documentation
+ * for <a href="package-summary.html">java.util.stream</a> for additional
+ * specification of streams, stream operations, stream pipelines, and
+ * parallelism.
+ *
+ * @since 1.8
+ * @see Stream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface LongStream extends BaseStream<Long, LongStream> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    LongStream filter(LongPredicate predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream map(LongUnaryOperator mapper);
+
+    /**
+     * Returns an object-valued {@code Stream} consisting of the results of
+     * applying the given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param <U> the element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <U> Stream<U> mapToObj(LongFunction<? extends U> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(LongToIntFunction mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(LongToDoubleFunction mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a
+     *               {@code LongStream} of new values
+     * @return the new stream
+     * @see Stream#flatMap(Function)
+     */
+    LongStream flatMap(LongFunction<? extends LongStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    LongStream distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream in sorted
+     * order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    LongStream sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     LongStream.of(1, 2, 3, 4)
+     *         .filter(e -> e > 2)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(e -> e * e)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .sum();
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
+     * @return the new stream
+     */
+    LongStream peek(LongConsumer action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(LongSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    LongStream limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(LongSupplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    LongStream skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(LongConsumer action);
+
+    /**
+     * Performs an action for each element of this stream, guaranteeing that
+     * each element is processed in encounter order for streams that have a
+     * defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(LongConsumer)
+     */
+    void forEachOrdered(LongConsumer action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    long[] toArray();
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     long result = identity;
+     *     for (long element : this stream)
+     *         result = accumulator.applyAsLong(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code x},
+     * {@code accumulator.apply(identity, x)} is equal to {@code x}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, and average are all special cases of reduction.
+     * Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     long sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or more compactly:
+     *
+     * <pre>{@code
+     *     long sum = integers.reduce(0, Long::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #sum()
+     * @see #min()
+     * @see #max()
+     * @see #average()
+     */
+    long reduce(long identity, LongBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code OptionalLong} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     long result = null;
+     *     for (long element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.applyAsLong(result, element);
+     *     }
+     *     return foundAny ? OptionalLong.of(result) : OptionalLong.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param op an <a href="package-summary.html#Associativity">associative</a>,
+     *           <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *           <a href="package-summary.html#Statelessness">stateless</a>
+     *           function for combining two values
+     * @return the result of the reduction
+     * @see #reduce(long, LongBinaryOperator)
+     */
+    OptionalLong reduce(LongBinaryOperator op);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (long element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(long, LongBinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
+     */
+    <R> R collect(Supplier<R> supplier,
+                  ObjLongConsumer<R> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Returns the sum of elements in this stream.  This is a special case
+     * of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(0, Long::sum);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return the sum of elements in this stream
+     */
+    long sum();
+
+    /**
+     * Returns an {@code OptionalLong} describing the minimum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Long::min);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return an {@code OptionalLong} containing the minimum element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong min();
+
+    /**
+     * Returns an {@code OptionalLong} describing the maximum element of this
+     * stream, or an empty optional if this stream is empty.  This is a special
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
+     * and is equivalent to:
+     * <pre>{@code
+     *     return reduce(Long::max);
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalLong} containing the maximum element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong max();
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return map(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
+     * this stream, or an empty optional if this stream is empty.  This is a
+     * special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an {@code OptionalDouble} containing the average element of this
+     * stream, or an empty optional if the stream is empty
+     */
+    OptionalDouble average();
+
+    /**
+     * Returns a {@code LongSummaryStatistics} describing various summary data
+     * about the elements of this stream.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return a {@code LongSummaryStatistics} describing various summary data
+     * about the elements of this stream
+     */
+    LongSummaryStatistics summaryStatistics();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(LongPredicate predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(LongPredicate predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(LongPredicate predicate);
+
+    /**
+     * Returns an {@link OptionalLong} describing the first element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code OptionalLong} describing the first element of this
+     * stream, or an empty {@code OptionalLong} if the stream is empty
+     */
+    OptionalLong findFirst();
+
+    /**
+     * Returns an {@link OptionalLong} describing some element of the stream, or
+     * an empty {@code OptionalLong} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code OptionalLong} describing some element of this stream,
+     * or an empty {@code OptionalLong} if the stream is empty
+     * @see #findFirst()
+     */
+    OptionalLong findAny();
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code DoubleStream} consisting of the elements of this stream,
+     * converted to {@code double}
+     */
+    DoubleStream asDoubleStream();
+
+    /**
+     * Returns a {@code Stream} consisting of the elements of this stream,
+     * each boxed to a {@code Long}.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @return a {@code Stream} consistent of the elements of this stream,
+     * each boxed to {@code Long}
+     */
+    Stream<Long> boxed();
+
+    @Override
+    LongStream sequential();
+
+    @Override
+    LongStream parallel();
+
+    @Override
+    PrimitiveIterator.OfLong iterator();
+
+    @Override
+    Spliterator.OfLong spliterator();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code LongStream}.
+     *
+     * @return a stream builder
+     */
+    public static Builder builder() {
+        return new Streams.LongStreamBuilderImpl();
+    }
+
+    /**
+     * Returns an empty sequential {@code LongStream}.
+     *
+     * @return an empty sequential stream
+     */
+    public static LongStream empty() {
+        return StreamSupport.longStream(Spliterators.emptyLongSpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code LongStream} containing a single element.
+     *
+     * @param t the single element
+     * @return a singleton sequential stream
+     */
+    public static LongStream of(long t) {
+        return StreamSupport.longStream(new Streams.LongStreamBuilderImpl(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    public static LongStream of(long... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code LongStream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code LongStream} will
+     * be the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code LongStream}
+     */
+    public static LongStream iterate(final long seed, final LongUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final PrimitiveIterator.OfLong iterator = new PrimitiveIterator.OfLong() {
+            long t = seed;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public long nextLong() {
+                long v = t;
+                t = f.applyAsLong(t);
+                return v;
+            }
+        };
+        return StreamSupport.longStream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code LongSupplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param s the {@code LongSupplier} for generated elements
+     * @return a new infinite sequential unordered {@code LongStream}
+     */
+    public static LongStream generate(LongSupplier s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.longStream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfLong(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i < endExclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endExclusive the exclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream range(long startInclusive, final long endExclusive) {
+        if (startInclusive >= endExclusive) {
+            return empty();
+        } else if (endExclusive - startInclusive < 0) {
+            // Size of range > Long.MAX_VALUE
+            // Split the range in two and concatenate
+            // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE) then
+            // the lower range, [Long.MIN_VALUE, 0) will be further split in two
+            long m = startInclusive + Long.divideUnsigned(endExclusive - startInclusive, 2) + 1;
+            return concat(range(startInclusive, m), range(m, endExclusive));
+        } else {
+            return StreamSupport.longStream(
+                    new Streams.RangeLongSpliterator(startInclusive, endExclusive, false), false);
+        }
+    }
+
+    /**
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
+     * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
+     * {@code 1}.
+     *
+     * @apiNote
+     * <p>An equivalent sequence of increasing values can be produced
+     * sequentially using a {@code for} loop as follows:
+     * <pre>{@code
+     *     for (long i = startInclusive; i <= endInclusive ; i++) { ... }
+     * }</pre>
+     *
+     * @param startInclusive the (inclusive) initial value
+     * @param endInclusive the inclusive upper bound
+     * @return a sequential {@code LongStream} for the range of {@code long}
+     *         elements
+     */
+    public static LongStream rangeClosed(long startInclusive, final long endInclusive) {
+        if (startInclusive > endInclusive) {
+            return empty();
+        } else if (endInclusive - startInclusive + 1 <= 0) {
+            // Size of range > Long.MAX_VALUE
+            // Split the range in two and concatenate
+            // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then
+            // the lower range, [Long.MIN_VALUE, 0), and upper range,
+            // [0, Long.MAX_VALUE], will both be further split in two
+            long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1;
+            return concat(range(startInclusive, m), rangeClosed(m, endInclusive));
+        } else {
+            return StreamSupport.longStream(
+                    new Streams.RangeLongSpliterator(startInclusive, endInclusive, true), false);
+        }
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static LongStream concat(LongStream a, LongStream b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong(
+                a.spliterator(), b.spliterator());
+        LongStream stream = StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code LongStream}.
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
+     * begins when the {@link #build()} method is called, which creates an
+     * ordered stream whose elements are the elements that were added to the
+     * stream builder, in the order they were added.
+     *
+     * @see LongStream#builder()
+     * @since 1.8
+     */
+    public interface Builder extends LongConsumer {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        @Override
+        void accept(long t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        default Builder add(long t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further
+         * attempts to operate on the builder after it has entered the built
+         * state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned
+         * to the built state
+         */
+        LongStream build();
+    }
+}
diff --git a/java/util/stream/LongStreamTestDataProvider.java b/java/util/stream/LongStreamTestDataProvider.java
new file mode 100644
index 0000000..4ce7ae6
--- /dev/null
+++ b/java/util/stream/LongStreamTestDataProvider.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/** TestNG DataProvider for long-valued streams */
+public class LongStreamTestDataProvider {
+    private static final long[] to0 = new long[0];
+    private static final long[] to1 = new long[1];
+    private static final long[] to10 = new long[10];
+    private static final long[] to100 = new long[100];
+    private static final long[] to1000 = new long[1000];
+    private static final long[] reversed = new long[100];
+    private static final long[] ones = new long[100];
+    private static final long[] twice = new long[200];
+    private static final long[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        long[][] arrays = {to0, to1, to10, to100, to1000};
+        for (long[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new long[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (long) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final long[] longs = (long[]) data[1];
+
+                list.add(new Object[]{"array:" + name,
+                        TestData.Factory.ofArray("array:" + name, longs)});
+
+                SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+                for (long i : longs) {
+                    isl.accept(i);
+                }
+                list.add(new Object[]{"SpinedList:" + name,
+                        TestData.Factory.ofSpinedBuffer("SpinedList:" + name, isl)});
+
+                list.add(streamDataDescr("LongStream.longRange(0,l): " + longs.length,
+                                         () -> LongStream.range(0, longs.length)));
+                list.add(streamDataDescr("LongStream.longRangeClosed(0,l): " + longs.length,
+                                         () -> LongStream.rangeClosed(0, longs.length)));
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final long[] longs = (long[]) data[1];
+
+                SpinedBuffer.OfLong isl = new SpinedBuffer.OfLong();
+                for (long i : longs) {
+                    isl.accept(i);
+                }
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(longs)));
+                spliterators.add(splitDescr("Arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(longs, 0, longs.length / 2)));
+
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> isl.spliterator()));
+
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(isl.iterator(), longs.length, 0)));
+                spliterators.add(splitDescr("Primitives.s(SpinedBuffer.iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(isl.iterator(), 0)));
+
+                spliterators.add(splitDescr("LongStream.longRange(0,l):" + name,
+                                            () -> LongStream.range(0, longs.length).spliterator()));
+                spliterators.add(splitDescr("LongStream.longRangeClosed(0,l):" + name,
+                                            () -> LongStream.rangeClosed(0, longs.length).spliterator()));
+                // Need more!
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<LongStream> s) {
+        return new Object[] { description, TestData.Factory.ofLongSupplier(description, s) };
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator.OfLong> s) {
+        return new Object[] { description, s };
+    }
+
+    // Return an array of ( String name, LongStreamTestData )
+    @DataProvider(name = "LongStreamTestData")
+    public static Object[][] makeLongStreamTestData() {
+        return testData;
+    }
+
+    // returns an array of (String name, Supplier<PrimitiveSpliterator<Long>>)
+    @DataProvider(name = "LongSpliterator")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/LongStreamTestScenario.java b/java/util/stream/LongStreamTestScenario.java
new file mode 100644
index 0000000..6d3e104
--- /dev/null
+++ b/java/util/stream/LongStreamTestScenario.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.LongConsumer;
+
+/**
+ * Test scenarios for long streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            LongStream s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (long t : m.apply(data.stream()).toArray()) {
+                b.accept(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (PrimitiveIterator.OfLong seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.nextLong());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (Spliterator.OfLong spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (Spliterator.OfLong spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) {
+            }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            for (long t : m.apply(data.parallelStream()).toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            LongStream s = m.apply(data.parallelStream());
+            Spliterator.OfLong sp = s.spliterator();
+            LongStream ss = StreamSupport.longStream(() -> sp,
+                                                     StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                     | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+            for (long t : ss.toArray())
+                b.accept(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            LongStream pipe2 = m.apply(pipe1);
+
+            for (long t : pipe2.toArray())
+                b.accept(t);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<LongStreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private boolean isParallel;
+
+    private final boolean isOrdered;
+
+    LongStreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    LongStreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.LONG_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, (LongConsumer) b, (Function<S_IN, LongStream>) m);
+    }
+
+    abstract <T, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m);
+
+}
diff --git a/java/util/stream/MatchOps.java b/java/util/stream/MatchOps.java
new file mode 100644
index 0000000..cc809e4
--- /dev/null
+++ b/java/util/stream/MatchOps.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.DoublePredicate;
+import java.util.function.IntPredicate;
+import java.util.function.LongPredicate;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * Factory for instances of a short-circuiting {@code TerminalOp} that implement
+ * quantified predicate matching on the elements of a stream. Supported variants
+ * include match-all, match-any, and match-none.
+ *
+ * @since 1.8
+ */
+final class MatchOps {
+
+    private MatchOps() { }
+
+    /**
+     * Enum describing quantified match options -- all match, any match, none
+     * match.
+     */
+    enum MatchKind {
+        /** Do all elements match the predicate? */
+        ANY(true, true),
+
+        /** Do any elements match the predicate? */
+        ALL(false, false),
+
+        /** Do no elements match the predicate? */
+        NONE(true, false);
+
+        private final boolean stopOnPredicateMatches;
+        private final boolean shortCircuitResult;
+
+        private MatchKind(boolean stopOnPredicateMatches,
+                          boolean shortCircuitResult) {
+            this.stopOnPredicateMatches = stopOnPredicateMatches;
+            this.shortCircuitResult = shortCircuitResult;
+        }
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a Stream.
+     *
+     * @param <T> the type of stream elements
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static <T> TerminalOp<T, Boolean> makeRef(Predicate<? super T> predicate,
+            MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<T> {
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(T t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.REFERENCE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for an {@code IntStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Integer, Boolean> makeInt(IntPredicate predicate,
+                                                       MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Integer> implements Sink.OfInt {
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(int t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.INT_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a {@code LongStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Long, Boolean> makeLong(LongPredicate predicate,
+                                                     MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Long> implements Sink.OfLong {
+
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(long t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.LONG_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * Constructs a quantified predicate matcher for a {@code DoubleStream}.
+     *
+     * @param predicate the {@code Predicate} to apply to stream elements
+     * @param matchKind the kind of quantified match (all, any, none)
+     * @return a {@code TerminalOp} implementing the desired quantified match
+     *         criteria
+     */
+    public static TerminalOp<Double, Boolean> makeDouble(DoublePredicate predicate,
+                                                         MatchKind matchKind) {
+        Objects.requireNonNull(predicate);
+        Objects.requireNonNull(matchKind);
+        class MatchSink extends BooleanTerminalSink<Double> implements Sink.OfDouble {
+
+            MatchSink() {
+                super(matchKind);
+            }
+
+            @Override
+            public void accept(double t) {
+                if (!stop && predicate.test(t) == matchKind.stopOnPredicateMatches) {
+                    stop = true;
+                    value = matchKind.shortCircuitResult;
+                }
+            }
+        }
+
+        return new MatchOp<>(StreamShape.DOUBLE_VALUE, matchKind, MatchSink::new);
+    }
+
+    /**
+     * A short-circuiting {@code TerminalOp} that evaluates a predicate on the
+     * elements of a stream and determines whether all, any or none of those
+     * elements match the predicate.
+     *
+     * @param <T> the output type of the stream pipeline
+     */
+    private static final class MatchOp<T> implements TerminalOp<T, Boolean> {
+        private final StreamShape inputShape;
+        final MatchKind matchKind;
+        final Supplier<BooleanTerminalSink<T>> sinkSupplier;
+
+        /**
+         * Constructs a {@code MatchOp}.
+         *
+         * @param shape the output shape of the stream pipeline
+         * @param matchKind the kind of quantified match (all, any, none)
+         * @param sinkSupplier {@code Supplier} for a {@code Sink} of the
+         *        appropriate shape which implements the matching operation
+         */
+        MatchOp(StreamShape shape,
+                MatchKind matchKind,
+                Supplier<BooleanTerminalSink<T>> sinkSupplier) {
+            this.inputShape = shape;
+            this.matchKind = matchKind;
+            this.sinkSupplier = sinkSupplier;
+        }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT | StreamOpFlag.NOT_ORDERED;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public <S> Boolean evaluateSequential(PipelineHelper<T> helper,
+                                              Spliterator<S> spliterator) {
+            return helper.wrapAndCopyInto(sinkSupplier.get(), spliterator).getAndClearState();
+        }
+
+        @Override
+        public <S> Boolean evaluateParallel(PipelineHelper<T> helper,
+                                            Spliterator<S> spliterator) {
+            // Approach for parallel implementation:
+            // - Decompose as per usual
+            // - run match on leaf chunks, call result "b"
+            // - if b == matchKind.shortCircuitOn, complete early and return b
+            // - else if we complete normally, return !shortCircuitOn
+
+            return new MatchTask<>(this, helper, spliterator).invoke();
+        }
+    }
+
+    /**
+     * Boolean specific terminal sink to avoid the boxing costs when returning
+     * results.  Subclasses implement the shape-specific functionality.
+     *
+     * @param <T> The output type of the stream pipeline
+     */
+    private static abstract class BooleanTerminalSink<T> implements Sink<T> {
+        boolean stop;
+        boolean value;
+
+        BooleanTerminalSink(MatchKind matchKind) {
+            value = !matchKind.shortCircuitResult;
+        }
+
+        public boolean getAndClearState() {
+            return value;
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return stop;
+        }
+    }
+
+    /**
+     * ForkJoinTask implementation to implement a parallel short-circuiting
+     * quantified match
+     *
+     * @param <P_IN> the type of source elements for the pipeline
+     * @param <P_OUT> the type of output elements for the pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class MatchTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Boolean, MatchTask<P_IN, P_OUT>> {
+        private final MatchOp<P_OUT> op;
+
+        /**
+         * Constructor for root node
+         */
+        MatchTask(MatchOp<P_OUT> op, PipelineHelper<P_OUT> helper,
+                  Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        /**
+         * Constructor for non-root node
+         */
+        MatchTask(MatchTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected MatchTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new MatchTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Boolean doLeaf() {
+            boolean b = helper.wrapAndCopyInto(op.sinkSupplier.get(), spliterator).getAndClearState();
+            if (b == op.matchKind.shortCircuitResult)
+                shortCircuit(b);
+            return null;
+        }
+
+        @Override
+        protected Boolean getEmptyResult() {
+            return !op.matchKind.shortCircuitResult;
+        }
+    }
+}
+
diff --git a/java/util/stream/Node.java b/java/util/stream/Node.java
new file mode 100644
index 0000000..e20de78
--- /dev/null
+++ b/java/util/stream/Node.java
@@ -0,0 +1,533 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * An immutable container for describing an ordered sequence of elements of some
+ * type {@code T}.
+ *
+ * <p>A {@code Node} contains a fixed number of elements, which can be accessed
+ * via the {@link #count}, {@link #spliterator}, {@link #forEach},
+ * {@link #asArray}, or {@link #copyInto} methods.  A {@code Node} may have zero
+ * or more child {@code Node}s; if it has no children (accessed via
+ * {@link #getChildCount} and {@link #getChild(int)}, it is considered <em>flat
+ * </em> or a <em>leaf</em>; if it has children, it is considered an
+ * <em>internal</em> node.  The size of an internal node is the sum of sizes of
+ * its children.
+ *
+ * @apiNote
+ * <p>A {@code Node} typically does not store the elements directly, but instead
+ * mediates access to one or more existing (effectively immutable) data
+ * structures such as a {@code Collection}, array, or a set of other
+ * {@code Node}s.  Commonly {@code Node}s are formed into a tree whose shape
+ * corresponds to the computation tree that produced the elements that are
+ * contained in the leaf nodes.  The use of {@code Node} within the stream
+ * framework is largely to avoid copying data unnecessarily during parallel
+ * operations.
+ *
+ * @param <T> the type of elements.
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public interface Node<T> {
+
+    /**
+     * Returns a {@link Spliterator} describing the elements contained in this
+     * {@code Node}.
+     *
+     * @return a {@code Spliterator} describing the elements contained in this
+     *         {@code Node}
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     * Traverses the elements of this node, and invoke the provided
+     * {@code Consumer} with each element.  Elements are provided in encounter
+     * order if the source for the {@code Node} has a defined encounter order.
+     *
+     * @param consumer a {@code Consumer} that is to be invoked with each
+     *        element in this {@code Node}
+     */
+    void forEach(Consumer<? super T> consumer);
+
+    /**
+     * Returns the number of child nodes of this node.
+     *
+     * @implSpec The default implementation returns zero.
+     *
+     * @return the number of child nodes
+     */
+    default int getChildCount() {
+        return 0;
+    }
+
+    /**
+     * Retrieves the child {@code Node} at a given index.
+     *
+     * @implSpec The default implementation always throws
+     * {@code IndexOutOfBoundsException}.
+     *
+     * @param i the index to the child node
+     * @return the child node
+     * @throws IndexOutOfBoundsException if the index is less than 0 or greater
+     *         than or equal to the number of child nodes
+     */
+    default Node<T> getChild(int i) {
+        throw new IndexOutOfBoundsException();
+    }
+
+    /**
+     * Return a node describing a subsequence of the elements of this node,
+     * starting at the given inclusive start offset and ending at the given
+     * exclusive end offset.
+     *
+     * @param from The (inclusive) starting offset of elements to include, must
+     *             be in range 0..count().
+     * @param to The (exclusive) end offset of elements to include, must be
+     *           in range 0..count().
+     * @param generator A function to be used to create a new array, if needed,
+     *                  for reference nodes.
+     * @return the truncated node
+     */
+    default Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+        if (from == 0 && to == count())
+            return this;
+        Spliterator<T> spliterator = spliterator();
+        long size = to - from;
+        Node.Builder<T> nodeBuilder = Nodes.builder(size, generator);
+        nodeBuilder.begin(size);
+        for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { }
+        for (int i = 0; (i < size) && spliterator.tryAdvance(nodeBuilder); i++) { }
+        nodeBuilder.end();
+        return nodeBuilder.build();
+    }
+
+    /**
+     * Provides an array view of the contents of this node.
+     *
+     * <p>Depending on the underlying implementation, this may return a
+     * reference to an internal array rather than a copy.  Since the returned
+     * array may be shared, the returned array should not be modified.  The
+     * {@code generator} function may be consulted to create the array if a new
+     * array needs to be created.
+     *
+     * @param generator a factory function which takes an integer parameter and
+     *        returns a new, empty array of that size and of the appropriate
+     *        array type
+     * @return an array containing the contents of this {@code Node}
+     */
+    T[] asArray(IntFunction<T[]> generator);
+
+    /**
+     * Copies the content of this {@code Node} into an array, starting at a
+     * given offset into the array.  It is the caller's responsibility to ensure
+     * there is sufficient room in the array, otherwise unspecified behaviour
+     * will occur if the array length is less than the number of elements
+     * contained in this node.
+     *
+     * @param array the array into which to copy the contents of this
+     *       {@code Node}
+     * @param offset the starting offset within the array
+     * @throws IndexOutOfBoundsException if copying would cause access of data
+     *         outside array bounds
+     * @throws NullPointerException if {@code array} is {@code null}
+     */
+    void copyInto(T[] array, int offset);
+
+    /**
+     * Gets the {@code StreamShape} associated with this {@code Node}.
+     *
+     * @implSpec The default in {@code Node} returns
+     * {@code StreamShape.REFERENCE}
+     *
+     * @return the stream shape associated with this node
+     */
+    default StreamShape getShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    /**
+     * Returns the number of elements contained in this node.
+     *
+     * @return the number of elements contained in this node
+     */
+    long count();
+
+    /**
+     * A mutable builder for a {@code Node} that implements {@link Sink}, which
+     * builds a flat node containing the elements that have been pushed to it.
+     */
+    interface Builder<T> extends Sink<T> {
+
+        /**
+         * Builds the node.  Should be called after all elements have been
+         * pushed and signalled with an invocation of {@link Sink#end()}.
+         *
+         * @return the resulting {@code Node}
+         */
+        Node<T> build();
+
+        /**
+         * Specialized @{code Node.Builder} for int elements
+         */
+        interface OfInt extends Node.Builder<Integer>, Sink.OfInt {
+            @Override
+            Node.OfInt build();
+        }
+
+        /**
+         * Specialized @{code Node.Builder} for long elements
+         */
+        interface OfLong extends Node.Builder<Long>, Sink.OfLong {
+            @Override
+            Node.OfLong build();
+        }
+
+        /**
+         * Specialized @{code Node.Builder} for double elements
+         */
+        interface OfDouble extends Node.Builder<Double>, Sink.OfDouble {
+            @Override
+            Node.OfDouble build();
+        }
+    }
+
+    public interface OfPrimitive<T, T_CONS, T_ARR,
+                                 T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                 T_NODE extends OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+            extends Node<T> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @return a {@link Spliterator.OfPrimitive} describing the elements of
+         *         this node
+         */
+        @Override
+        T_SPLITR spliterator();
+
+        /**
+         * Traverses the elements of this node, and invoke the provided
+         * {@code action} with each element.
+         *
+         * @param action a consumer that is to be invoked with each
+         *        element in this {@code Node.OfPrimitive}
+         */
+        @SuppressWarnings("overloads")
+        void forEach(T_CONS action);
+
+        @Override
+        default T_NODE getChild(int i) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        T_NODE truncate(long from, long to, IntFunction<T[]> generator);
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes the generator to create
+         * an instance of a boxed primitive array with a length of
+         * {@link #count()} and then invokes {@link #copyInto(T[], int)} with
+         * that array at an offset of 0.
+         */
+        @Override
+        default T[] asArray(IntFunction<T[]> generator) {
+            if (java.util.stream.Tripwire.ENABLED)
+                java.util.stream.Tripwire.trip(getClass(), "{0} calling Node.OfPrimitive.asArray");
+
+            long size = count();
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            T[] boxed = generator.apply((int) count());
+            copyInto(boxed, 0);
+            return boxed;
+        }
+
+        /**
+         * Views this node as a primitive array.
+         *
+         * <p>Depending on the underlying implementation this may return a
+         * reference to an internal array rather than a copy.  It is the callers
+         * responsibility to decide if either this node or the array is utilized
+         * as the primary reference for the data.</p>
+         *
+         * @return an array containing the contents of this {@code Node}
+         */
+        T_ARR asPrimitiveArray();
+
+        /**
+         * Creates a new primitive array.
+         *
+         * @param count the length of the primitive array.
+         * @return the new primitive array.
+         */
+        T_ARR newArray(int count);
+
+        /**
+         * Copies the content of this {@code Node} into a primitive array,
+         * starting at a given offset into the array.  It is the caller's
+         * responsibility to ensure there is sufficient room in the array.
+         *
+         * @param array the array into which to copy the contents of this
+         *              {@code Node}
+         * @param offset the starting offset within the array
+         * @throws IndexOutOfBoundsException if copying would cause access of
+         *         data outside array bounds
+         * @throws NullPointerException if {@code array} is {@code null}
+         */
+        void copyInto(T_ARR array, int offset);
+    }
+
+    /**
+     * Specialized {@code Node} for int elements
+     */
+    interface OfInt extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, OfInt> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer a {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code IntConsumer}, it is cast to {@code IntConsumer} so the
+         *        elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Integer> consumer) {
+            if (consumer instanceof IntConsumer) {
+                forEach((IntConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfInt.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()} to
+         * obtain an int[] array then and copies the elements from that int[]
+         * array into the boxed Integer[] array.  This is not efficient and it
+         * is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Integer[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Integer[], int)");
+
+            int[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfInt truncate(long from, long to, IntFunction<Integer[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfInt spliterator = spliterator();
+            Node.Builder.OfInt nodeBuilder = Nodes.intBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((IntConsumer) e -> { }); i++) { }
+            for (int i = 0; (i < size) && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default int[] newArray(int count) {
+            return new int[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec The default in {@code Node.OfInt} returns
+         * {@code StreamShape.INT_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.INT_VALUE;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for long elements
+     */
+    interface OfLong extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, OfLong> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer A {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code LongConsumer}, it is cast to {@code LongConsumer} so
+         *        the elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Long> consumer) {
+            if (consumer instanceof LongConsumer) {
+                forEach((LongConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()}
+         * to obtain a long[] array then and copies the elements from that
+         * long[] array into the boxed Long[] array.  This is not efficient and
+         * it is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Long[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Long[], int)");
+
+            long[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfLong truncate(long from, long to, IntFunction<Long[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfLong spliterator = spliterator();
+            Node.Builder.OfLong nodeBuilder = Nodes.longBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((LongConsumer) e -> { }); i++) { }
+            for (int i = 0; (i < size) && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default long[] newArray(int count) {
+            return new long[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         * @implSpec The default in {@code Node.OfLong} returns
+         * {@code StreamShape.LONG_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.LONG_VALUE;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for double elements
+     */
+    interface OfDouble extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, OfDouble> {
+
+        /**
+         * {@inheritDoc}
+         *
+         * @param consumer A {@code Consumer} that is to be invoked with each
+         *        element in this {@code Node}.  If this is an
+         *        {@code DoubleConsumer}, it is cast to {@code DoubleConsumer}
+         *        so the elements may be processed without boxing.
+         */
+        @Override
+        default void forEach(Consumer<? super Double> consumer) {
+            if (consumer instanceof DoubleConsumer) {
+                forEach((DoubleConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        //
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes {@link #asPrimitiveArray()}
+         * to obtain a double[] array then and copies the elements from that
+         * double[] array into the boxed Double[] array.  This is not efficient
+         * and it is recommended to invoke {@link #copyInto(Object, int)}.
+         */
+        @Override
+        default void copyInto(Double[] boxed, int offset) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Node.OfDouble.copyInto(Double[], int)");
+
+            double[] array = asPrimitiveArray();
+            for (int i = 0; i < array.length; i++) {
+                boxed[offset + i] = array[i];
+            }
+        }
+
+        @Override
+        default Node.OfDouble truncate(long from, long to, IntFunction<Double[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long size = to - from;
+            Spliterator.OfDouble spliterator = spliterator();
+            Node.Builder.OfDouble nodeBuilder = Nodes.doubleBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; i < from && spliterator.tryAdvance((DoubleConsumer) e -> { }); i++) { }
+            for (int i = 0; (i < size) && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { }
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        @Override
+        default double[] newArray(int count) {
+            return new double[count];
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec The default in {@code Node.OfDouble} returns
+         * {@code StreamShape.DOUBLE_VALUE}
+         */
+        default StreamShape getShape() {
+            return StreamShape.DOUBLE_VALUE;
+        }
+    }
+}
diff --git a/java/util/stream/NodeBuilderTest.java b/java/util/stream/NodeBuilderTest.java
new file mode 100644
index 0000000..11fe86f
--- /dev/null
+++ b/java/util/stream/NodeBuilderTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.assertContents;
+import static java.util.stream.LambdaTestHelpers.countTo;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class NodeBuilderTest {
+
+    List<Integer> sizes = Arrays.asList(0, 1, 4, 16, 256,
+                                        1023, 1024, 1025,
+                                        2047, 2048, 2049,
+                                        1024 * 32 - 1, 1024 * 32, 1024 * 32 + 1);
+
+    @DataProvider(name = "Node.Builder")
+    public Object[][] createNodeBuilders() {
+        List<List<Integer>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            ls.add(countTo(size));
+        }
+
+        List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+                s -> Nodes.builder(),
+                s -> Nodes.builder(s, LambdaTestHelpers.integerArrayGenerator)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Integer> l : ls) {
+            for (Function<Integer, Node.Builder<Integer>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder", groups = { "serialization-hostile" })
+    public void testIteration(List<Integer> l, Function<Integer, Node.Builder<Integer>> m) {
+        Node.Builder<Integer> nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Integer i : l) {
+            nb.accept(i);
+        }
+        nb.end();
+
+        Node<Integer> n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Integer> _l = new ArrayList<>();
+            n.forEach(_l::add);
+
+            assertContents(_l, l);
+        }
+    }
+
+    // Node.Builder.OfInt
+
+    @DataProvider(name = "Node.Builder<Integer>")
+    public Object[][] createIntNodeBuilders() {
+        List<List<Integer>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            ls.add(countTo(size));
+        }
+
+        List<Function<Integer, Node.Builder<Integer>>> ms = Arrays.asList(
+                s -> Nodes.intBuilder(),
+                s -> Nodes.intBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Integer> l : ls) {
+            for (Function<Integer, Node.Builder<Integer>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Integer>", groups = { "serialization-hostile" })
+    public void testIntIteration(List<Integer> l, Function<Integer, Node.Builder.OfInt> m) {
+        Node.Builder.OfInt nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Integer i : l) {
+            nb.accept((int) i);
+        }
+        nb.end();
+
+        Node.OfInt n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Integer> _l = new ArrayList<>();
+            n.forEach((IntConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+
+    // Node.Builder.OfLong
+
+    @DataProvider(name = "Node.Builder<Long>")
+    public Object[][] createLongNodeBuilders() {
+        List<List<Long>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            List<Long> l = new ArrayList<>();
+            for (long i = 0; i < size; i++) {
+                l.add(i);
+            }
+            ls.add(l);
+        }
+
+        List<Function<Integer, Node.Builder<Long>>> ms = Arrays.asList(
+                s -> Nodes.longBuilder(),
+                s -> Nodes.longBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Long> l : ls) {
+            for (Function<Integer, Node.Builder<Long>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Long>")
+    public void testLongIteration(List<Long> l, Function<Integer, Node.Builder.OfLong> m) {
+        Node.Builder.OfLong nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Long i : l) {
+            nb.accept((long) i);
+        }
+        nb.end();
+
+        Node.OfLong n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Long> _l = new ArrayList<>();
+            n.forEach((LongConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+
+    // Node.Builder.OfDouble
+
+    @DataProvider(name = "Node.Builder<Double>")
+    public Object[][] createDoubleNodeBuilders() {
+        List<List<Double>> ls = new ArrayList<>();
+        for (int size : sizes) {
+            List<Double> l = new ArrayList<>();
+            for (long i = 0; i < size; i++) {
+                l.add((double) i);
+            }
+            ls.add(l);
+        }
+
+        List<Function<Integer, Node.Builder<Double>>> ms = Arrays.asList(
+                s -> Nodes.doubleBuilder(),
+                s -> Nodes.doubleBuilder(s)
+        );
+
+        Object[][] params = new Object[ls.size() * ms.size()][];
+        int i = 0;
+        for (List<Double> l : ls) {
+            for (Function<Integer, Node.Builder<Double>> m : ms) {
+                params[i++] = new Object[]{l, m};
+            }
+        }
+
+        return params;
+    }
+
+    @Test(dataProvider = "Node.Builder<Double>")
+    public void testDoubleIteration(List<Double> l, Function<Integer, Node.Builder.OfDouble> m) {
+        Node.Builder.OfDouble nb = m.apply(l.size());
+        nb.begin(l.size());
+        for (Double i : l) {
+            nb.accept((double) i);
+        }
+        nb.end();
+
+        Node.OfDouble n = nb.build();
+        assertEquals(n.count(), l.size());
+
+        {
+            List<Double> _l = new ArrayList<>();
+            n.forEach((DoubleConsumer) _l::add);
+
+            assertContents(_l, l);
+        }
+
+    }
+}
diff --git a/java/util/stream/NodeTest.java b/java/util/stream/NodeTest.java
new file mode 100644
index 0000000..da71003
--- /dev/null
+++ b/java/util/stream/NodeTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Function;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+@Test
+public class NodeTest extends OpTestCase {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            Integer[] array = new Integer[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+            nodes.add(Nodes.node(array));
+            nodes.add(Nodes.node(Arrays.asList(array)));
+            nodes.add(degenerateTree(Arrays.asList(array).iterator()));
+            nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l.toArray(new Integer[l.size()]))));
+            nodes.add(tree(Arrays.asList(array), l -> Nodes.node(l)));
+            nodes.add(fill(array, Nodes.builder(array.length, LambdaTestHelpers.integerArrayGenerator)));
+            nodes.add(fill(array, Nodes.builder()));
+
+            for (int i = 0; i < nodes.size(); i++) {
+                params.add(new Object[]{array, nodes.get(i)});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    Node<Integer> fill(Integer[] array, Node.Builder<Integer> nb) {
+        nb.begin(array.length);
+        for (Integer i : array) {
+            nb.accept(i);
+        }
+        nb.end();
+        return nb.build();
+    }
+
+    Node<Integer> degenerateTree(Iterator<Integer> it) {
+        if (!it.hasNext()) {
+            return Nodes.node(Collections.emptyList());
+        }
+
+        Integer i = it.next();
+        if (it.hasNext()) {
+            return new Nodes.ConcNode<Integer>(Nodes.node(new Integer[] {i}), degenerateTree(it));
+        }
+        else {
+            return Nodes.node(new Integer[]{i});
+        }
+    }
+
+    Node<Integer> tree(List<Integer> l, Function<List<Integer>, Node<Integer>> m) {
+        if (l.size() < 3) {
+            return m.apply(l);
+        }
+        else {
+            return new Nodes.ConcNode<>(
+                    tree(l.subList(0, l.size() / 2), m),
+                    tree(l.subList(l.size() / 2, l.size()), m ));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(Integer[] array, Node<Integer> n) {
+        assertEquals(n.asArray(LambdaTestHelpers.integerArrayGenerator), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(Integer[] array, Node<Integer> n) {
+        assertEquals(Nodes.flatten(n, LambdaTestHelpers.integerArrayGenerator)
+                          .asArray(LambdaTestHelpers.integerArrayGenerator), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(Integer[] array, Node<Integer> n) {
+        Integer[] copy = new Integer[(int) n.count()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes", groups = { "serialization-hostile" })
+    public void testForEach(Integer[] array, Node<Integer> n) {
+        List<Integer> l = new ArrayList<>((int) n.count());
+        n.forEach(e -> l.add(e));
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testStreams(Integer[] array, Node<Integer> n) {
+        TestData<Integer, Stream<Integer>> data = TestData.Factory.ofRefNode("Node", n);
+
+        exerciseOps(data, s -> s);
+
+        exerciseTerminalOps(data, s -> s.toArray());
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(Integer[] array, Node<Integer> n) {
+        SpliteratorTestHelper.testSpliterator(n::spliterator);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTruncate(Integer[] array, Node<Integer> n) {
+        int[] nums = new int[] { 0, 1, array.length / 2, array.length - 1, array.length };
+        for (int start : nums)
+            for (int end : nums) {
+                if (start < 0 || end < 0 || end < start || end > array.length)
+                    continue;
+                Node<Integer> slice = n.truncate(start, end, Integer[]::new);
+                Integer[] asArray = slice.asArray(Integer[]::new);
+                for (int k = start; k < end; k++)
+                    assertEquals(array[k], asArray[k - start]);
+            }
+    }
+}
diff --git a/java/util/stream/Nodes.java b/java/util/stream/Nodes.java
new file mode 100644
index 0000000..c18540c
--- /dev/null
+++ b/java/util/stream/Nodes.java
@@ -0,0 +1,2227 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.List;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.LongFunction;
+
+/**
+ * Factory methods for constructing implementations of {@link Node} and
+ * {@link Node.Builder} and their primitive specializations.  Fork/Join tasks
+ * for collecting output from a {@link PipelineHelper} to a {@link Node} and
+ * flattening {@link Node}s.
+ *
+ * @since 1.8
+ */
+final class Nodes {
+
+    private Nodes() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * The maximum size of an array that can be allocated.
+     */
+    static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+    // IllegalArgumentException messages
+    static final String BAD_SIZE = "Stream size exceeds max array size";
+
+    @SuppressWarnings("rawtypes")
+    private static final Node EMPTY_NODE = new EmptyNode.OfRef();
+    private static final Node.OfInt EMPTY_INT_NODE = new EmptyNode.OfInt();
+    private static final Node.OfLong EMPTY_LONG_NODE = new EmptyNode.OfLong();
+    private static final Node.OfDouble EMPTY_DOUBLE_NODE = new EmptyNode.OfDouble();
+
+    // General shape-based node creation methods
+
+    /**
+     * Produces an empty node whose count is zero, has no children and no content.
+     *
+     * @param <T> the type of elements of the created node
+     * @param shape the shape of the node to be created
+     * @return an empty node.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Node<T> emptyNode(StreamShape shape) {
+        switch (shape) {
+            case REFERENCE:    return (Node<T>) EMPTY_NODE;
+            case INT_VALUE:    return (Node<T>) EMPTY_INT_NODE;
+            case LONG_VALUE:   return (Node<T>) EMPTY_LONG_NODE;
+            case DOUBLE_VALUE: return (Node<T>) EMPTY_DOUBLE_NODE;
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    /**
+     * Produces a concatenated {@link Node} that has two or more children.
+     * <p>The count of the concatenated node is equal to the sum of the count
+     * of each child. Traversal of the concatenated node traverses the content
+     * of each child in encounter order of the list of children. Splitting a
+     * spliterator obtained from the concatenated node preserves the encounter
+     * order of the list of children.
+     *
+     * <p>The result may be a concatenated node, the input sole node if the size
+     * of the list is 1, or an empty node.
+     *
+     * @param <T> the type of elements of the concatenated node
+     * @param shape the shape of the concatenated node to be created
+     * @param left the left input node
+     * @param right the right input node
+     * @return a {@code Node} covering the elements of the input nodes
+     * @throws IllegalStateException if all {@link Node} elements of the list
+     * are an not instance of type supported by this factory.
+     */
+    @SuppressWarnings("unchecked")
+    static <T> Node<T> conc(StreamShape shape, Node<T> left, Node<T> right) {
+        switch (shape) {
+            case REFERENCE:
+                return new ConcNode<>(left, right);
+            case INT_VALUE:
+                return (Node<T>) new ConcNode.OfInt((Node.OfInt) left, (Node.OfInt) right);
+            case LONG_VALUE:
+                return (Node<T>) new ConcNode.OfLong((Node.OfLong) left, (Node.OfLong) right);
+            case DOUBLE_VALUE:
+                return (Node<T>) new ConcNode.OfDouble((Node.OfDouble) left, (Node.OfDouble) right);
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    // Reference-based node methods
+
+    /**
+     * Produces a {@link Node} describing an array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param <T> the type of elements held by the node
+     * @param array the array
+     * @return a node holding an array
+     */
+    static <T> Node<T> node(T[] array) {
+        return new ArrayNode<>(array);
+    }
+
+    /**
+     * Produces a {@link Node} describing a {@link Collection}.
+     * <p>
+     * The node will hold a reference to the collection and will not make a copy.
+     *
+     * @param <T> the type of elements held by the node
+     * @param c the collection
+     * @return a node holding a collection
+     */
+    static <T> Node<T> node(Collection<T> c) {
+        return new CollectionNode<>(c);
+    }
+
+    /**
+     * Produces a {@link Node.Builder}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @param generator the array factory
+     * @param <T> the type of elements of the node builder
+     * @return a {@code Node.Builder}
+     */
+    static <T> Node.Builder<T> builder(long exactSizeIfKnown, IntFunction<T[]> generator) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new FixedNodeBuilder<>(exactSizeIfKnown, generator)
+               : builder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder}.
+     *
+     * @param <T> the type of elements of the node builder
+     * @return a {@code Node.Builder}
+     */
+    static <T> Node.Builder<T> builder() {
+        return new SpinedNodeBuilder<>();
+    }
+
+    // Int nodes
+
+    /**
+     * Produces a {@link Node.OfInt} describing an int[] array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfInt node(int[] array) {
+        return new IntArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfInt}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfInt}
+     */
+    static Node.Builder.OfInt intBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new IntFixedNodeBuilder(exactSizeIfKnown)
+               : intBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfInt}.
+     *
+     * @return a {@code Node.Builder.OfInt}
+     */
+    static Node.Builder.OfInt intBuilder() {
+        return new IntSpinedNodeBuilder();
+    }
+
+    // Long nodes
+
+    /**
+     * Produces a {@link Node.OfLong} describing a long[] array.
+     * <p>
+     * The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfLong node(final long[] array) {
+        return new LongArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfLong}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfLong}
+     */
+    static Node.Builder.OfLong longBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new LongFixedNodeBuilder(exactSizeIfKnown)
+               : longBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfLong}.
+     *
+     * @return a {@code Node.Builder.OfLong}
+     */
+    static Node.Builder.OfLong longBuilder() {
+        return new LongSpinedNodeBuilder();
+    }
+
+    // Double nodes
+
+    /**
+     * Produces a {@link Node.OfDouble} describing a double[] array.
+     *
+     * <p>The node will hold a reference to the array and will not make a copy.
+     *
+     * @param array the array
+     * @return a node holding an array
+     */
+    static Node.OfDouble node(final double[] array) {
+        return new DoubleArrayNode(array);
+    }
+
+    /**
+     * Produces a {@link Node.Builder.OfDouble}.
+     *
+     * @param exactSizeIfKnown -1 if a variable size builder is requested,
+     * otherwise the exact capacity desired.  A fixed capacity builder will
+     * fail if the wrong number of elements are added to the builder.
+     * @return a {@code Node.Builder.OfDouble}
+     */
+    static Node.Builder.OfDouble doubleBuilder(long exactSizeIfKnown) {
+        return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
+               ? new DoubleFixedNodeBuilder(exactSizeIfKnown)
+               : doubleBuilder();
+    }
+
+    /**
+     * Produces a variable size @{link Node.Builder.OfDouble}.
+     *
+     * @return a {@code Node.Builder.OfDouble}
+     */
+    static Node.Builder.OfDouble doubleBuilder() {
+        return new DoubleSpinedNodeBuilder();
+    }
+
+    // Parallel evaluation of pipelines to nodes
+
+    /**
+     * Collect, in parallel, elements output from a pipeline and describe those
+     * elements with a {@link Node}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node} if desired.
+     *
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @param generator the array generator
+     * @return a {@link Node} describing the output elements
+     */
+    public static <P_IN, P_OUT> Node<P_OUT> collect(PipelineHelper<P_OUT> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    boolean flattenTree,
+                                                    IntFunction<P_OUT[]> generator) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            P_OUT[] array = generator.apply((int) size);
+            new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke();
+            return node(array);
+        } else {
+            Node<P_OUT> node = new CollectorTask.OfRef<>(helper, generator, spliterator).invoke();
+            return flattenTree ? flatten(node, generator) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from an int-valued pipeline and
+     * describe those elements with a {@link Node.OfInt}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfInt} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfInt} describing the output elements
+     */
+    public static <P_IN> Node.OfInt collectInt(PipelineHelper<Integer> helper,
+                                               Spliterator<P_IN> spliterator,
+                                               boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            int[] array = new int[(int) size];
+            new SizedCollectorTask.OfInt<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfInt node = new CollectorTask.OfInt<>(helper, spliterator).invoke();
+            return flattenTree ? flattenInt(node) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from a long-valued pipeline and
+     * describe those elements with a {@link Node.OfLong}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfLong} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfLong} describing the output elements
+     */
+    public static <P_IN> Node.OfLong collectLong(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            long[] array = new long[(int) size];
+            new SizedCollectorTask.OfLong<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfLong node = new CollectorTask.OfLong<>(helper, spliterator).invoke();
+            return flattenTree ? flattenLong(node) : node;
+        }
+    }
+
+    /**
+     * Collect, in parallel, elements output from n double-valued pipeline and
+     * describe those elements with a {@link Node.OfDouble}.
+     *
+     * @implSpec
+     * If the exact size of the output from the pipeline is known and the source
+     * {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic,
+     * then a flat {@link Node} will be returned whose content is an array,
+     * since the size is known the array can be constructed in advance and
+     * output elements can be placed into the array concurrently by leaf
+     * tasks at the correct offsets.  If the exact size is not known, output
+     * elements are collected into a conc-node whose shape mirrors that
+     * of the computation. This conc-node can then be flattened in
+     * parallel to produce a flat {@code Node.OfDouble} if desired.
+     *
+     * @param <P_IN> the type of elements from the source Spliterator
+     * @param helper the pipeline helper describing the pipeline
+     * @param flattenTree whether a conc node should be flattened into a node
+     *                    describing an array before returning
+     * @return a {@link Node.OfDouble} describing the output elements
+     */
+    public static <P_IN> Node.OfDouble collectDouble(PipelineHelper<Double> helper,
+                                                     Spliterator<P_IN> spliterator,
+                                                     boolean flattenTree) {
+        long size = helper.exactOutputSizeIfKnown(spliterator);
+        if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            double[] array = new double[(int) size];
+            new SizedCollectorTask.OfDouble<>(spliterator, helper, array).invoke();
+            return node(array);
+        }
+        else {
+            Node.OfDouble node = new CollectorTask.OfDouble<>(helper, spliterator).invoke();
+            return flattenTree ? flattenDouble(node) : node;
+        }
+    }
+
+    // Parallel flattening of nodes
+
+    /**
+     * Flatten, in parallel, a {@link Node}.  A flattened node is one that has
+     * no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, the generator is used to create an array
+     * whose length is {@link Node#count()}.  Then the node tree is traversed
+     * and leaf node elements are placed in the array concurrently by leaf tasks
+     * at the correct offsets.
+     *
+     * @param <T> type of elements contained by the node
+     * @param node the node to flatten
+     * @param generator the array factory used to create array instances
+     * @return a flat {@code Node}
+     */
+    public static <T> Node<T> flatten(Node<T> node, IntFunction<T[]> generator) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            T[] array = generator.apply((int) size);
+            new ToArrayTask.OfRef<>(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfInt}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new int[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfInt}
+     */
+    public static Node.OfInt flattenInt(Node.OfInt node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            int[] array = new int[(int) size];
+            new ToArrayTask.OfInt(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfLong}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new long[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfLong}
+     */
+    public static Node.OfLong flattenLong(Node.OfLong node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            long[] array = new long[(int) size];
+            new ToArrayTask.OfLong(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    /**
+     * Flatten, in parallel, a {@link Node.OfDouble}.  A flattened node is one that
+     * has no children.  If the node is already flat, it is simply returned.
+     *
+     * @implSpec
+     * If a new node is to be created, a new double[] array is created whose length
+     * is {@link Node#count()}.  Then the node tree is traversed and leaf node
+     * elements are placed in the array concurrently by leaf tasks at the
+     * correct offsets.
+     *
+     * @param node the node to flatten
+     * @return a flat {@code Node.OfDouble}
+     */
+    public static Node.OfDouble flattenDouble(Node.OfDouble node) {
+        if (node.getChildCount() > 0) {
+            long size = node.count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            double[] array = new double[(int) size];
+            new ToArrayTask.OfDouble(node, array, 0).invoke();
+            return node(array);
+        } else {
+            return node;
+        }
+    }
+
+    // Implementations
+
+    private static abstract class EmptyNode<T, T_ARR, T_CONS> implements Node<T> {
+        EmptyNode() { }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            return generator.apply(0);
+        }
+
+        public void copyInto(T_ARR array, int offset) { }
+
+        @Override
+        public long count() {
+            return 0;
+        }
+
+        public void forEach(T_CONS consumer) { }
+
+        private static class OfRef<T> extends EmptyNode<T, T[], Consumer<? super T>> {
+            private OfRef() {
+                super();
+            }
+
+            @Override
+            public Spliterator<T> spliterator() {
+                return Spliterators.emptySpliterator();
+            }
+        }
+
+        private static final class OfInt
+                extends EmptyNode<Integer, int[], IntConsumer>
+                implements Node.OfInt {
+
+            OfInt() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfInt spliterator() {
+                return Spliterators.emptyIntSpliterator();
+            }
+
+            @Override
+            public int[] asPrimitiveArray() {
+                return EMPTY_INT_ARRAY;
+            }
+        }
+
+        private static final class OfLong
+                extends EmptyNode<Long, long[], LongConsumer>
+                implements Node.OfLong {
+
+            OfLong() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfLong spliterator() {
+                return Spliterators.emptyLongSpliterator();
+            }
+
+            @Override
+            public long[] asPrimitiveArray() {
+                return EMPTY_LONG_ARRAY;
+            }
+        }
+
+        private static final class OfDouble
+                extends EmptyNode<Double, double[], DoubleConsumer>
+                implements Node.OfDouble {
+
+            OfDouble() { } // Avoid creation of special accessor
+
+            @Override
+            public Spliterator.OfDouble spliterator() {
+                return Spliterators.emptyDoubleSpliterator();
+            }
+
+            @Override
+            public double[] asPrimitiveArray() {
+                return EMPTY_DOUBLE_ARRAY;
+            }
+        }
+    }
+
+    /** Node class for a reference array */
+    private static class ArrayNode<T> implements Node<T> {
+        final T[] array;
+        int curSize;
+
+        @SuppressWarnings("unchecked")
+        ArrayNode(long size, IntFunction<T[]> generator) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = generator.apply((int) size);
+            this.curSize = 0;
+        }
+
+        ArrayNode(T[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public void copyInto(T[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("ArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    /** Node class for a Collection */
+    private static final class CollectionNode<T> implements Node<T> {
+        private final Collection<T> c;
+
+        CollectionNode(Collection<T> c) {
+            this.c = c;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return c.stream().spliterator();
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            for (T t : c)
+                array[offset++] = t;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T[] asArray(IntFunction<T[]> generator) {
+            return c.toArray(generator.apply(c.size()));
+        }
+
+        @Override
+        public long count() {
+            return c.size();
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            c.forEach(consumer);
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("CollectionNode[%d][%s]", c.size(), c);
+        }
+    }
+
+    /**
+     * Node class for an internal node with two or more children
+     */
+    private static abstract class AbstractConcNode<T, T_NODE extends Node<T>> implements Node<T> {
+        protected final T_NODE left;
+        protected final T_NODE right;
+        private final long size;
+
+        AbstractConcNode(T_NODE left, T_NODE right) {
+            this.left = left;
+            this.right = right;
+            // The Node count will be required when the Node spliterator is
+            // obtained and it is cheaper to aggressively calculate bottom up
+            // as the tree is built rather than later on from the top down
+            // traversing the tree
+            this.size = left.count() + right.count();
+        }
+
+        @Override
+        public int getChildCount() {
+            return 2;
+        }
+
+        @Override
+        public T_NODE getChild(int i) {
+            if (i == 0) return left;
+            if (i == 1) return right;
+            throw new IndexOutOfBoundsException();
+        }
+
+        @Override
+        public long count() {
+            return size;
+        }
+    }
+
+    static final class ConcNode<T>
+            extends AbstractConcNode<T, Node<T>>
+            implements Node<T> {
+
+        ConcNode(Node<T> left, Node<T> right) {
+            super(left, right);
+        }
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return new Nodes.InternalNodeSpliterator.OfRef<>(this);
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            Objects.requireNonNull(array);
+            left.copyInto(array, offset);
+            // Cast to int is safe since it is the callers responsibility to
+            // ensure that there is sufficient room in the array
+            right.copyInto(array, offset + (int) left.count());
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> generator) {
+            long size = count();
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            T[] array = generator.apply((int) size);
+            copyInto(array, 0);
+            return array;
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            left.forEach(consumer);
+            right.forEach(consumer);
+        }
+
+        @Override
+        public Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+            if (from == 0 && to == count())
+                return this;
+            long leftCount = left.count();
+            if (from >= leftCount)
+                return right.truncate(from - leftCount, to - leftCount, generator);
+            else if (to <= leftCount)
+                return left.truncate(from, to, generator);
+            else {
+                return Nodes.conc(getShape(), left.truncate(from, leftCount, generator),
+                                  right.truncate(0, to - leftCount, generator));
+            }
+        }
+
+        @Override
+        public String toString() {
+            if (count() < 32) {
+                return String.format("ConcNode[%s.%s]", left, right);
+            } else {
+                return String.format("ConcNode[size=%d]", count());
+            }
+        }
+
+        private abstract static class OfPrimitive<E, T_CONS, T_ARR,
+                                                  T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>,
+                                                  T_NODE extends Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+                extends AbstractConcNode<E, T_NODE>
+                implements Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE> {
+
+            OfPrimitive(T_NODE left, T_NODE right) {
+                super(left, right);
+            }
+
+            @Override
+            public void forEach(T_CONS consumer) {
+                left.forEach(consumer);
+                right.forEach(consumer);
+            }
+
+            @Override
+            public void copyInto(T_ARR array, int offset) {
+                left.copyInto(array, offset);
+                // Cast to int is safe since it is the callers responsibility to
+                // ensure that there is sufficient room in the array
+                right.copyInto(array, offset + (int) left.count());
+            }
+
+            @Override
+            public T_ARR asPrimitiveArray() {
+                long size = count();
+                if (size >= MAX_ARRAY_SIZE)
+                    throw new IllegalArgumentException(BAD_SIZE);
+                T_ARR array = newArray((int) size);
+                copyInto(array, 0);
+                return array;
+            }
+
+            @Override
+            public String toString() {
+                if (count() < 32)
+                    return String.format("%s[%s.%s]", this.getClass().getName(), left, right);
+                else
+                    return String.format("%s[size=%d]", this.getClass().getName(), count());
+            }
+        }
+
+        static final class OfInt
+                extends ConcNode.OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
+                implements Node.OfInt {
+
+            OfInt(Node.OfInt left, Node.OfInt right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfInt spliterator() {
+                return new InternalNodeSpliterator.OfInt(this);
+            }
+        }
+
+        static final class OfLong
+                extends ConcNode.OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
+                implements Node.OfLong {
+
+            OfLong(Node.OfLong left, Node.OfLong right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfLong spliterator() {
+                return new InternalNodeSpliterator.OfLong(this);
+            }
+        }
+
+        static final class OfDouble
+                extends ConcNode.OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
+                implements Node.OfDouble {
+
+            OfDouble(Node.OfDouble left, Node.OfDouble right) {
+                super(left, right);
+            }
+
+            @Override
+            public Spliterator.OfDouble spliterator() {
+                return new InternalNodeSpliterator.OfDouble(this);
+            }
+        }
+    }
+
+    /** Abstract class for spliterator for all internal node classes */
+    private static abstract class InternalNodeSpliterator<T,
+                                                          S extends Spliterator<T>,
+                                                          N extends Node<T>>
+            implements Spliterator<T> {
+        // Node we are pointing to
+        // null if full traversal has occurred
+        N curNode;
+
+        // next child of curNode to consume
+        int curChildIndex;
+
+        // The spliterator of the curNode if that node is last and has no children.
+        // This spliterator will be delegated to for splitting and traversing.
+        // null if curNode has children
+        S lastNodeSpliterator;
+
+        // spliterator used while traversing with tryAdvance
+        // null if no partial traversal has occurred
+        S tryAdvanceSpliterator;
+
+        // node stack used when traversing to search and find leaf nodes
+        // null if no partial traversal has occurred
+        Deque<N> tryAdvanceStack;
+
+        InternalNodeSpliterator(N curNode) {
+            this.curNode = curNode;
+        }
+
+        /**
+         * Initiate a stack containing, in left-to-right order, the child nodes
+         * covered by this spliterator
+         */
+        @SuppressWarnings("unchecked")
+        protected final Deque<N> initStack() {
+            // Bias size to the case where leaf nodes are close to this node
+            // 8 is the minimum initial capacity for the ArrayDeque implementation
+            Deque<N> stack = new ArrayDeque<>(8);
+            for (int i = curNode.getChildCount() - 1; i >= curChildIndex; i--)
+                stack.addFirst((N) curNode.getChild(i));
+            return stack;
+        }
+
+        /**
+         * Depth first search, in left-to-right order, of the node tree, using
+         * an explicit stack, to find the next non-empty leaf node.
+         */
+        @SuppressWarnings("unchecked")
+        protected final N findNextLeafNode(Deque<N> stack) {
+            N n = null;
+            while ((n = stack.pollFirst()) != null) {
+                if (n.getChildCount() == 0) {
+                    if (n.count() > 0)
+                        return n;
+                } else {
+                    for (int i = n.getChildCount() - 1; i >= 0; i--)
+                        stack.addFirst((N) n.getChild(i));
+                }
+            }
+
+            return null;
+        }
+
+        @SuppressWarnings("unchecked")
+        protected final boolean initTryAdvance() {
+            if (curNode == null)
+                return false;
+
+            if (tryAdvanceSpliterator == null) {
+                if (lastNodeSpliterator == null) {
+                    // Initiate the node stack
+                    tryAdvanceStack = initStack();
+                    N leaf = findNextLeafNode(tryAdvanceStack);
+                    if (leaf != null)
+                        tryAdvanceSpliterator = (S) leaf.spliterator();
+                    else {
+                        // A non-empty leaf node was not found
+                        // No elements to traverse
+                        curNode = null;
+                        return false;
+                    }
+                }
+                else
+                    tryAdvanceSpliterator = lastNodeSpliterator;
+            }
+            return true;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public final S trySplit() {
+            if (curNode == null || tryAdvanceSpliterator != null)
+                return null; // Cannot split if fully or partially traversed
+            else if (lastNodeSpliterator != null)
+                return (S) lastNodeSpliterator.trySplit();
+            else if (curChildIndex < curNode.getChildCount() - 1)
+                return (S) curNode.getChild(curChildIndex++).spliterator();
+            else {
+                curNode = (N) curNode.getChild(curChildIndex);
+                if (curNode.getChildCount() == 0) {
+                    lastNodeSpliterator = (S) curNode.spliterator();
+                    return (S) lastNodeSpliterator.trySplit();
+                }
+                else {
+                    curChildIndex = 0;
+                    return (S) curNode.getChild(curChildIndex++).spliterator();
+                }
+            }
+        }
+
+        @Override
+        public final long estimateSize() {
+            if (curNode == null)
+                return 0;
+
+            // Will not reflect the effects of partial traversal.
+            // This is compliant with the specification
+            if (lastNodeSpliterator != null)
+                return lastNodeSpliterator.estimateSize();
+            else {
+                long size = 0;
+                for (int i = curChildIndex; i < curNode.getChildCount(); i++)
+                    size += curNode.getChild(i).count();
+                return size;
+            }
+        }
+
+        @Override
+        public final int characteristics() {
+            return Spliterator.SIZED;
+        }
+
+        private static final class OfRef<T>
+                extends InternalNodeSpliterator<T, Spliterator<T>, Node<T>> {
+
+            OfRef(Node<T> curNode) {
+                super(curNode);
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        Node<T> leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> consumer) {
+                if (curNode == null)
+                    return;
+
+                if (tryAdvanceSpliterator == null) {
+                    if (lastNodeSpliterator == null) {
+                        Deque<Node<T>> stack = initStack();
+                        Node<T> leaf;
+                        while ((leaf = findNextLeafNode(stack)) != null) {
+                            leaf.forEach(consumer);
+                        }
+                        curNode = null;
+                    }
+                    else
+                        lastNodeSpliterator.forEachRemaining(consumer);
+                }
+                else
+                    while(tryAdvance(consumer)) { }
+            }
+        }
+
+        private static abstract class OfPrimitive<T, T_CONS, T_ARR,
+                                                  T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                                  N extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, N>>
+                extends InternalNodeSpliterator<T, T_SPLITR, N>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+
+            OfPrimitive(N cur) {
+                super(cur);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        N leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                if (curNode == null)
+                    return;
+
+                if (tryAdvanceSpliterator == null) {
+                    if (lastNodeSpliterator == null) {
+                        Deque<N> stack = initStack();
+                        N leaf;
+                        while ((leaf = findNextLeafNode(stack)) != null) {
+                            leaf.forEach(consumer);
+                        }
+                        curNode = null;
+                    }
+                    else
+                        lastNodeSpliterator.forEachRemaining(consumer);
+                }
+                else
+                    while(tryAdvance(consumer)) { }
+            }
+        }
+
+        private static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
+                implements Spliterator.OfInt {
+
+            OfInt(Node.OfInt cur) {
+                super(cur);
+            }
+        }
+
+        private static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
+                implements Spliterator.OfLong {
+
+            OfLong(Node.OfLong cur) {
+                super(cur);
+            }
+        }
+
+        private static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
+                implements Spliterator.OfDouble {
+
+            OfDouble(Node.OfDouble cur) {
+                super(cur);
+            }
+        }
+    }
+
+    /**
+     * Fixed-sized builder class for reference nodes
+     */
+    private static final class FixedNodeBuilder<T>
+            extends ArrayNode<T>
+            implements Node.Builder<T> {
+
+        FixedNodeBuilder(long size, IntFunction<T[]> generator) {
+            super(size, generator);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node<T> build() {
+            if (curSize < array.length)
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length)
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(T t) {
+            if (curSize < array.length) {
+                array[curSize++] = t;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length)
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+        }
+
+        @Override
+        public String toString() {
+            return String.format("FixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    /**
+     * Variable-sized builder class for reference nodes
+     */
+    private static final class SpinedNodeBuilder<T>
+            extends SpinedBuffer<T>
+            implements Node<T>, Node.Builder<T> {
+        private boolean building = false;
+
+        SpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator<T> spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(Consumer<? super T> consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(T t) {
+            assert building : "not building";
+            super.accept(t);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public T[] asArray(IntFunction<T[]> arrayFactory) {
+            assert !building : "during building";
+            return super.asArray(arrayFactory);
+        }
+
+        @Override
+        public Node<T> build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    //
+
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+    private static final long[] EMPTY_LONG_ARRAY = new long[0];
+    private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
+
+    private static class IntArrayNode implements Node.OfInt {
+        final int[] array;
+        int curSize;
+
+        IntArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new int[(int) size];
+            this.curSize = 0;
+        }
+
+        IntArrayNode(int[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public int[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(int[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(IntConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class LongArrayNode implements Node.OfLong {
+        final long[] array;
+        int curSize;
+
+        LongArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new long[(int) size];
+            this.curSize = 0;
+        }
+
+        LongArrayNode(long[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        @Override
+        public Spliterator.OfLong spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public long[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(long[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(LongConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("LongArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class DoubleArrayNode implements Node.OfDouble {
+        final double[] array;
+        int curSize;
+
+        DoubleArrayNode(long size) {
+            if (size >= MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(BAD_SIZE);
+            this.array = new double[(int) size];
+            this.curSize = 0;
+        }
+
+        DoubleArrayNode(double[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        @Override
+        public Spliterator.OfDouble spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public double[] asPrimitiveArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(double[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            for (int i = 0; i < curSize; i++) {
+                consumer.accept(array[i]);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("DoubleArrayNode[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class IntFixedNodeBuilder
+            extends IntArrayNode
+            implements Node.Builder.OfInt {
+
+        IntFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfInt build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(int i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class LongFixedNodeBuilder
+            extends LongArrayNode
+            implements Node.Builder.OfLong {
+
+        LongFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfLong build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(long i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("LongFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class DoubleFixedNodeBuilder
+            extends DoubleArrayNode
+            implements Node.Builder.OfDouble {
+
+        DoubleFixedNodeBuilder(long size) {
+            super(size);
+            assert size < MAX_ARRAY_SIZE;
+        }
+
+        @Override
+        public Node.OfDouble build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+
+            return this;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d",
+                                                              size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(double i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d",
+                                                              array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d",
+                                                              curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("DoubleFixedNodeBuilder[%d][%s]",
+                                 array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static final class IntSpinedNodeBuilder
+            extends SpinedBuffer.OfInt
+            implements Node.OfInt, Node.Builder.OfInt {
+        private boolean building = false;
+
+        IntSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(IntConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(int i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public int[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfInt build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    private static final class LongSpinedNodeBuilder
+            extends SpinedBuffer.OfLong
+            implements Node.OfLong, Node.Builder.OfLong {
+        private boolean building = false;
+
+        LongSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfLong spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(LongConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(long i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(long[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public long[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfLong build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    private static final class DoubleSpinedNodeBuilder
+            extends SpinedBuffer.OfDouble
+            implements Node.OfDouble, Node.Builder.OfDouble {
+        private boolean building = false;
+
+        DoubleSpinedNodeBuilder() {} // Avoid creation of special accessor
+
+        @Override
+        public Spliterator.OfDouble spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(DoubleConsumer consumer) {
+            assert !building : "during building";
+            super.forEach(consumer);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(double i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(double[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public double[] asPrimitiveArray() {
+            assert !building : "during building";
+            return super.asPrimitiveArray();
+        }
+
+        @Override
+        public Node.OfDouble build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    /*
+     * This and subclasses are not intended to be serializable
+     */
+    @SuppressWarnings("serial")
+    private static abstract class SizedCollectorTask<P_IN, P_OUT, T_SINK extends Sink<P_OUT>,
+                                                     K extends SizedCollectorTask<P_IN, P_OUT, T_SINK, K>>
+            extends CountedCompleter<Void>
+            implements Sink<P_OUT> {
+        protected final Spliterator<P_IN> spliterator;
+        protected final PipelineHelper<P_OUT> helper;
+        protected final long targetSize;
+        protected long offset;
+        protected long length;
+        // For Sink implementation
+        protected int index, fence;
+
+        SizedCollectorTask(Spliterator<P_IN> spliterator,
+                           PipelineHelper<P_OUT> helper,
+                           int arrayLength) {
+            assert spliterator.hasCharacteristics(Spliterator.SUBSIZED);
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            this.offset = 0;
+            this.length = arrayLength;
+        }
+
+        SizedCollectorTask(K parent, Spliterator<P_IN> spliterator,
+                           long offset, long length, int arrayLength) {
+            super(parent);
+            assert spliterator.hasCharacteristics(Spliterator.SUBSIZED);
+            this.spliterator = spliterator;
+            this.helper = parent.helper;
+            this.targetSize = parent.targetSize;
+            this.offset = offset;
+            this.length = length;
+
+            if (offset < 0 || length < 0 || (offset + length - 1 >= arrayLength)) {
+                throw new IllegalArgumentException(
+                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
+                                      offset, offset, length, arrayLength));
+            }
+        }
+
+        @Override
+        public void compute() {
+            SizedCollectorTask<P_IN, P_OUT, T_SINK, K> task = this;
+            Spliterator<P_IN> rightSplit = spliterator, leftSplit;
+            while (rightSplit.estimateSize() > task.targetSize &&
+                   (leftSplit = rightSplit.trySplit()) != null) {
+                task.setPendingCount(1);
+                long leftSplitSize = leftSplit.estimateSize();
+                task.makeChild(leftSplit, task.offset, leftSplitSize).fork();
+                task = task.makeChild(rightSplit, task.offset + leftSplitSize,
+                                      task.length - leftSplitSize);
+            }
+
+            assert task.offset + task.length < MAX_ARRAY_SIZE;
+            @SuppressWarnings("unchecked")
+            T_SINK sink = (T_SINK) task;
+            task.helper.wrapAndCopyInto(sink, rightSplit);
+            task.propagateCompletion();
+        }
+
+        abstract K makeChild(Spliterator<P_IN> spliterator, long offset, long size);
+
+        @Override
+        public void begin(long size) {
+            if (size > length)
+                throw new IllegalStateException("size passed to Sink.begin exceeds array length");
+            // Casts to int are safe since absolute size is verified to be within
+            // bounds when the root concrete SizedCollectorTask is constructed
+            // with the shared array
+            index = (int) offset;
+            fence = index + (int) length;
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfRef<P_IN, P_OUT>
+                extends SizedCollectorTask<P_IN, P_OUT, Sink<P_OUT>, OfRef<P_IN, P_OUT>>
+                implements Sink<P_OUT> {
+            private final P_OUT[] array;
+
+            OfRef(Spliterator<P_IN> spliterator, PipelineHelper<P_OUT> helper, P_OUT[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfRef(OfRef<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator,
+                  long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfRef<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator,
+                                         long offset, long size) {
+                return new OfRef<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(P_OUT value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfInt<P_IN>
+                extends SizedCollectorTask<P_IN, Integer, Sink.OfInt, OfInt<P_IN>>
+                implements Sink.OfInt {
+            private final int[] array;
+
+            OfInt(Spliterator<P_IN> spliterator, PipelineHelper<Integer> helper, int[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfInt(SizedCollectorTask.OfInt<P_IN> parent, Spliterator<P_IN> spliterator,
+                  long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfInt<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                     long offset, long size) {
+                return new SizedCollectorTask.OfInt<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(int value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfLong<P_IN>
+                extends SizedCollectorTask<P_IN, Long, Sink.OfLong, OfLong<P_IN>>
+                implements Sink.OfLong {
+            private final long[] array;
+
+            OfLong(Spliterator<P_IN> spliterator, PipelineHelper<Long> helper, long[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfLong(SizedCollectorTask.OfLong<P_IN> parent, Spliterator<P_IN> spliterator,
+                   long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfLong<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                      long offset, long size) {
+                return new SizedCollectorTask.OfLong<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(long value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+
+        @SuppressWarnings("serial")
+        static final class OfDouble<P_IN>
+                extends SizedCollectorTask<P_IN, Double, Sink.OfDouble, OfDouble<P_IN>>
+                implements Sink.OfDouble {
+            private final double[] array;
+
+            OfDouble(Spliterator<P_IN> spliterator, PipelineHelper<Double> helper, double[] array) {
+                super(spliterator, helper, array.length);
+                this.array = array;
+            }
+
+            OfDouble(SizedCollectorTask.OfDouble<P_IN> parent, Spliterator<P_IN> spliterator,
+                     long offset, long length) {
+                super(parent, spliterator, offset, length, parent.array.length);
+                this.array = parent.array;
+            }
+
+            @Override
+            SizedCollectorTask.OfDouble<P_IN> makeChild(Spliterator<P_IN> spliterator,
+                                                        long offset, long size) {
+                return new SizedCollectorTask.OfDouble<>(this, spliterator, offset, size);
+            }
+
+            @Override
+            public void accept(double value) {
+                if (index >= fence) {
+                    throw new IndexOutOfBoundsException(Integer.toString(index));
+                }
+                array[index++] = value;
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static abstract class ToArrayTask<T, T_NODE extends Node<T>,
+                                              K extends ToArrayTask<T, T_NODE, K>>
+            extends CountedCompleter<Void> {
+        protected final T_NODE node;
+        protected final int offset;
+
+        ToArrayTask(T_NODE node, int offset) {
+            this.node = node;
+            this.offset = offset;
+        }
+
+        ToArrayTask(K parent, T_NODE node, int offset) {
+            super(parent);
+            this.node = node;
+            this.offset = offset;
+        }
+
+        abstract void copyNodeToArray();
+
+        abstract K makeChild(int childIndex, int offset);
+
+        @Override
+        public void compute() {
+            ToArrayTask<T, T_NODE, K> task = this;
+            while (true) {
+                if (task.node.getChildCount() == 0) {
+                    task.copyNodeToArray();
+                    task.propagateCompletion();
+                    return;
+                }
+                else {
+                    task.setPendingCount(task.node.getChildCount() - 1);
+
+                    int size = 0;
+                    int i = 0;
+                    for (;i < task.node.getChildCount() - 1; i++) {
+                        K leftTask = task.makeChild(i, task.offset + size);
+                        size += leftTask.node.count();
+                        leftTask.fork();
+                    }
+                    task = task.makeChild(i, task.offset + size);
+                }
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfRef<T>
+                extends ToArrayTask<T, Node<T>, OfRef<T>> {
+            private final T[] array;
+
+            private OfRef(Node<T> node, T[] array, int offset) {
+                super(node, offset);
+                this.array = array;
+            }
+
+            private OfRef(OfRef<T> parent, Node<T> node, int offset) {
+                super(parent, node, offset);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfRef<T> makeChild(int childIndex, int offset) {
+                return new OfRef<>(this, node.getChild(childIndex), offset);
+            }
+
+            @Override
+            void copyNodeToArray() {
+                node.copyInto(array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static class OfPrimitive<T, T_CONS, T_ARR,
+                                         T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                                         T_NODE extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
+                extends ToArrayTask<T, T_NODE, OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> {
+            private final T_ARR array;
+
+            private OfPrimitive(T_NODE node, T_ARR array, int offset) {
+                super(node, offset);
+                this.array = array;
+            }
+
+            private OfPrimitive(OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> parent, T_NODE node, int offset) {
+                super(parent, node, offset);
+                this.array = parent.array;
+            }
+
+            @Override
+            OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> makeChild(int childIndex, int offset) {
+                return new OfPrimitive<>(this, node.getChild(childIndex), offset);
+            }
+
+            @Override
+            void copyNodeToArray() {
+                node.copyInto(array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> {
+            private OfInt(Node.OfInt node, int[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> {
+            private OfLong(Node.OfLong node, long[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> {
+            private OfDouble(Node.OfDouble node, double[] array, int offset) {
+                super(node, array, offset);
+            }
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static class CollectorTask<P_IN, P_OUT, T_NODE extends Node<P_OUT>, T_BUILDER extends Node.Builder<P_OUT>>
+            extends AbstractTask<P_IN, P_OUT, T_NODE, CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER>> {
+        protected final PipelineHelper<P_OUT> helper;
+        protected final LongFunction<T_BUILDER> builderFactory;
+        protected final BinaryOperator<T_NODE> concFactory;
+
+        CollectorTask(PipelineHelper<P_OUT> helper,
+                      Spliterator<P_IN> spliterator,
+                      LongFunction<T_BUILDER> builderFactory,
+                      BinaryOperator<T_NODE> concFactory) {
+            super(helper, spliterator);
+            this.helper = helper;
+            this.builderFactory = builderFactory;
+            this.concFactory = concFactory;
+        }
+
+        CollectorTask(CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> parent,
+                      Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            helper = parent.helper;
+            builderFactory = parent.builderFactory;
+            concFactory = parent.concFactory;
+        }
+
+        @Override
+        protected CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> makeChild(Spliterator<P_IN> spliterator) {
+            return new CollectorTask<>(this, spliterator);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        protected T_NODE doLeaf() {
+            T_BUILDER builder = builderFactory.apply(helper.exactOutputSizeIfKnown(spliterator));
+            return (T_NODE) helper.wrapAndCopyInto(builder, spliterator).build();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf())
+                setLocalResult(concFactory.apply(leftChild.getLocalResult(), rightChild.getLocalResult()));
+            super.onCompletion(caller);
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfRef<P_IN, P_OUT>
+                extends CollectorTask<P_IN, P_OUT, Node<P_OUT>, Node.Builder<P_OUT>> {
+            OfRef(PipelineHelper<P_OUT> helper,
+                  IntFunction<P_OUT[]> generator,
+                  Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, s -> builder(s, generator), ConcNode::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfInt<P_IN>
+                extends CollectorTask<P_IN, Integer, Node.OfInt, Node.Builder.OfInt> {
+            OfInt(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::intBuilder, ConcNode.OfInt::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfLong<P_IN>
+                extends CollectorTask<P_IN, Long, Node.OfLong, Node.Builder.OfLong> {
+            OfLong(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::longBuilder, ConcNode.OfLong::new);
+            }
+        }
+
+        @SuppressWarnings("serial")
+        private static final class OfDouble<P_IN>
+                extends CollectorTask<P_IN, Double, Node.OfDouble, Node.Builder.OfDouble> {
+            OfDouble(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) {
+                super(helper, spliterator, Nodes::doubleBuilder, ConcNode.OfDouble::new);
+            }
+        }
+    }
+}
diff --git a/java/util/stream/OpTestCase.java b/java/util/stream/OpTestCase.java
new file mode 100644
index 0000000..331ac0e
--- /dev/null
+++ b/java/util/stream/OpTestCase.java
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.testng.annotations.Test;
+
+/**
+ * Base class for streams test cases.  Provides 'exercise' methods for taking
+ * lambdas that construct and modify streams, and evaluates them in different
+ * ways and asserts that they produce equivalent results.
+ */
+@Test
+public abstract class OpTestCase extends LoggingTestCase {
+
+    private final Map<StreamShape, Set<? extends BaseStreamTestScenario>> testScenarios;
+
+    protected OpTestCase() {
+        testScenarios = new EnumMap<>(StreamShape.class);
+        testScenarios.put(StreamShape.REFERENCE, Collections.unmodifiableSet(EnumSet.allOf(StreamTestScenario.class)));
+        testScenarios.put(StreamShape.INT_VALUE, Collections.unmodifiableSet(EnumSet.allOf(IntStreamTestScenario.class)));
+        testScenarios.put(StreamShape.LONG_VALUE, Collections.unmodifiableSet(EnumSet.allOf(LongStreamTestScenario.class)));
+        testScenarios.put(StreamShape.DOUBLE_VALUE, Collections.unmodifiableSet(EnumSet.allOf(DoubleStreamTestScenario.class)));
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static int getStreamFlags(BaseStream s) {
+        return ((AbstractPipeline) s).getStreamFlags();
+    }
+
+    /**
+     * An asserter for results produced when exercising of stream or terminal
+     * tests.
+     *
+     * @param <R> the type of result to assert on
+     */
+    public interface ResultAsserter<R> {
+        /**
+         * Assert a result produced when exercising of stream or terminal
+         * test.
+         *
+         * @param actual the actual result
+         * @param expected the expected result
+         * @param isOrdered true if the pipeline is ordered
+         * @param isParallel true if the pipeline is parallel
+         */
+        void assertResult(R actual, R expected, boolean isOrdered, boolean isParallel);
+    }
+
+    // Exercise stream operations
+
+    public interface BaseStreamTestScenario {
+        StreamShape getShape();
+
+        boolean isParallel();
+
+        boolean isOrdered();
+
+        <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+        void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m);
+    }
+
+    protected <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+        return withData(data).stream(m).exercise();
+    }
+
+    // Run multiple versions of exercise(), returning the result of the first, and asserting that others return the same result
+    // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+    @SafeVarargs
+    protected final<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOpsMulti(TestData<T, S_IN> data,
+                                   Function<S_IN, S_OUT>... ms) {
+        Collection<U> result = null;
+        for (Function<S_IN, S_OUT> m : ms) {
+            if (result == null)
+                result = withData(data).stream(m).exercise();
+            else {
+                Collection<U> r2 = withData(data).stream(m).exercise();
+                assertEquals(result, r2);
+            }
+        }
+        return result;
+    }
+
+    // Run multiple versions of exercise() for an Integer stream, returning the result of the first, and asserting that others return the same result
+    // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+    // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+    protected final
+    Collection<Integer> exerciseOpsInt(TestData.OfRef<Integer> data,
+                                       Function<Stream<Integer>, Stream<Integer>> mRef,
+                                       Function<IntStream, IntStream> mInt,
+                                       Function<LongStream, LongStream> mLong,
+                                       Function<DoubleStream, DoubleStream> mDouble) {
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        Function<Stream<Integer>, Stream<Integer>>[] ms = new Function[4];
+        ms[0] = mRef;
+        ms[1] = s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e);
+        ms[2] = s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e);
+        ms[3] = s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e);
+        return exerciseOpsMulti(data, ms);
+    }
+
+    // Run multiple versions of exercise() with multiple terminal operations for all kinds of stream, , and asserting against the expected result
+    // If the first version is s -> s.foo(), can be used with s -> s.mapToInt(i -> i).foo().mapToObj(i -> i) to test all shape variants
+    protected final<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void exerciseTerminalOpsMulti(TestData<T, S_IN> data,
+                                  R expected,
+                                  Map<String, Function<S_IN, S_OUT>> streams,
+                                  Map<String, Function<S_OUT, R>> terminals) {
+        for (Map.Entry<String, Function<S_IN, S_OUT>> se : streams.entrySet()) {
+            setContext("Intermediate stream", se.getKey());
+            for (Map.Entry<String, Function<S_OUT, R>> te : terminals.entrySet()) {
+                setContext("Terminal stream", te.getKey());
+                withData(data)
+                        .terminal(se.getValue(), te.getValue())
+                        .expectedResult(expected)
+                        .exercise();
+
+            }
+        }
+    }
+
+    // Run multiple versions of exercise() with multiple terminal operation for all kinds of stream, and asserting against the expected result
+    // Automates the conversion between Stream<Integer> and {Int,Long,Double}Stream and back, so client sites look like you are passing the same
+    // lambda four times, but in fact they are four different lambdas since they are transforming four different kinds of streams
+    protected final
+    void exerciseTerminalOpsInt(TestData<Integer, Stream<Integer>> data,
+                                Collection<Integer> expected,
+                                String desc,
+                                Function<Stream<Integer>, Stream<Integer>> mRef,
+                                Function<IntStream, IntStream> mInt,
+                                Function<LongStream, LongStream> mLong,
+                                Function<DoubleStream, DoubleStream> mDouble,
+                                Map<String, Function<Stream<Integer>, Collection<Integer>>> terminals) {
+
+        Map<String, Function<Stream<Integer>, Stream<Integer>>> m = new HashMap<>();
+        m.put("Ref " + desc, mRef);
+        m.put("Int " + desc, s -> mInt.apply(s.mapToInt(e -> e)).mapToObj(e -> e));
+        m.put("Long " + desc, s -> mLong.apply(s.mapToLong(e -> e)).mapToObj(e -> (int) e));
+        m.put("Double " + desc, s -> mDouble.apply(s.mapToDouble(e -> e)).mapToObj(e -> (int) e));
+
+        exerciseTerminalOpsMulti(data, expected, m, terminals);
+    }
+
+
+    protected <T, U, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m) {
+        TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).stream(m).exercise();
+    }
+
+    protected <T, U, S_OUT extends BaseStream<U, S_OUT>, I extends Iterable<U>>
+    Collection<U> exerciseOps(Collection<T> data, Function<Stream<T>, S_OUT> m, I expected) {
+        TestData.OfRef<T> data1 = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).stream(m).expectedResult(expected).exercise();
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <U, S_OUT extends BaseStream<U, S_OUT>>
+    Collection<U> exerciseOps(int[] data, Function<IntStream, S_OUT> m) {
+        return withData(TestData.Factory.ofArray("int array", data)).stream(m).exercise();
+    }
+
+    protected Collection<Integer> exerciseOps(int[] data, Function<IntStream, IntStream> m, int[] expected) {
+        TestData.OfInt data1 = TestData.Factory.ofArray("int array", data);
+        return withData(data1).stream(m).expectedResult(expected).exercise();
+    }
+
+    protected <T, S_IN extends BaseStream<T, S_IN>> DataStreamBuilder<T, S_IN> withData(TestData<T, S_IN> data) {
+        Objects.requireNonNull(data);
+        return new DataStreamBuilder<>(data);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class DataStreamBuilder<T, S_IN extends BaseStream<T, S_IN>> {
+        final TestData<T, S_IN> data;
+
+        private DataStreamBuilder(TestData<T, S_IN> data) {
+            this.data = Objects.requireNonNull(data);
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>>
+        ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> ops(IntermediateTestOp... ops) {
+            return new ExerciseDataStreamBuilder<>(data, (S_IN s) -> (S_OUT) chain(s, ops));
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+        stream(Function<S_IN, S_OUT> m) {
+            return new ExerciseDataStreamBuilder<>(data, m);
+        }
+
+        public <U, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT>
+        stream(Function<S_IN, S_OUT> m, IntermediateTestOp<U, U> additionalOp) {
+            return new ExerciseDataStreamBuilder<>(data, s -> (S_OUT) chain(m.apply(s), additionalOp));
+        }
+
+        public <R> ExerciseDataTerminalBuilder<T, T, R, S_IN, S_IN>
+        terminal(Function<S_IN, R> terminalF) {
+            return new ExerciseDataTerminalBuilder<>(data, s -> s, terminalF);
+        }
+
+        public <U, R, S_OUT extends BaseStream<U, S_OUT>> ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT>
+        terminal(Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+            return new ExerciseDataTerminalBuilder<>(data, streamF, terminalF);
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class ExerciseDataStreamBuilder<T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+        final TestData<T, S_IN> data;
+        final Function<S_IN, S_OUT> m;
+        final StreamShape shape;
+
+        Set<BaseStreamTestScenario> testSet = new HashSet<>();
+
+        Collection<U> refResult;
+
+        Consumer<TestData<T, S_IN>> before = LambdaTestHelpers.bEmpty;
+
+        Consumer<TestData<T, S_IN>> after = LambdaTestHelpers.bEmpty;
+
+        ResultAsserter<Iterable<U>> resultAsserter = (act, exp, ord, par) -> {
+            if (par & !ord) {
+                LambdaTestHelpers.assertContentsUnordered(act, exp);
+            }
+            else {
+                LambdaTestHelpers.assertContentsEqual(act, exp);
+            }
+        };
+
+        private ExerciseDataStreamBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> m) {
+            this.data = data;
+
+            this.m = Objects.requireNonNull(m);
+
+            this.shape = ((AbstractPipeline<?, U, ?>) m.apply(data.stream())).getOutputShape();
+
+            // Have to initiate from the output shape of the last stream
+            // This means the stream mapper is required first rather than last
+            testSet.addAll(testScenarios.get(shape));
+        }
+
+        //
+
+        public <I extends Iterable<U>> ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(I expectedResult) {
+            List<U> l = new ArrayList<>();
+            expectedResult.forEach(l::add);
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(int[] expectedResult) {
+            List l = new ArrayList();
+            for (int anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(long[] expectedResult) {
+            List l = new ArrayList();
+            for (long anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> expectedResult(double[] expectedResult) {
+            List l = new ArrayList();
+            for (double anExpectedResult : expectedResult) {
+                l.add(anExpectedResult);
+            }
+            refResult = l;
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> before(Consumer<TestData<T, S_IN>> before) {
+            this.before = Objects.requireNonNull(before);
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> after(Consumer<TestData<T, S_IN>> after) {
+            this.after = Objects.requireNonNull(after);
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(BaseStreamTestScenario... tests) {
+            return without(Arrays.asList(tests));
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> without(Collection<? extends BaseStreamTestScenario> tests) {
+            for (BaseStreamTestScenario ts : tests) {
+                if (ts.getShape() == shape) {
+                    testSet.remove(ts);
+                }
+            }
+
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Test scenario set is empty");
+            }
+
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(BaseStreamTestScenario... tests) {
+            return with(Arrays.asList(tests));
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> with(Collection<? extends BaseStreamTestScenario> tests) {
+            testSet = new HashSet<>();
+
+            for (BaseStreamTestScenario ts : tests) {
+                if (ts.getShape() == shape) {
+                    testSet.add(ts);
+                }
+            }
+
+            if (testSet.isEmpty()) {
+                throw new IllegalStateException("Test scenario set is empty");
+            }
+
+            return this;
+        }
+
+        public ExerciseDataStreamBuilder<T, U, S_IN, S_OUT> resultAsserter(ResultAsserter<Iterable<U>> resultAsserter) {
+            this.resultAsserter = resultAsserter;
+            return this;
+        }
+
+        // Build method
+
+        public Collection<U> exercise() {
+            final boolean isStreamOrdered;
+            if (refResult == null) {
+                // Induce the reference result
+                before.accept(data);
+                S_OUT sOut = m.apply(data.stream());
+                isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+                Node<U> refNodeResult = ((AbstractPipeline<?, U, ?>) sOut).evaluateToArrayNode(size -> (U[]) new Object[size]);
+                refResult = LambdaTestHelpers.toBoxedList(refNodeResult.spliterator());
+                after.accept(data);
+            }
+            else {
+                S_OUT sOut = m.apply(data.stream());
+                isStreamOrdered = StreamOpFlag.ORDERED.isKnown(((AbstractPipeline) sOut).getStreamFlags());
+            }
+
+            List<Error> errors = new ArrayList<>();
+            for (BaseStreamTestScenario test : testSet) {
+                try {
+                    before.accept(data);
+
+                    List<U> result = new ArrayList<>();
+                    test.run(data, LambdaTestHelpers.<U>toBoxingConsumer(result::add), m);
+
+                    Runnable asserter = () -> resultAsserter.assertResult(result, refResult, isStreamOrdered && test.isOrdered(), test.isParallel());
+
+                    if (refResult.size() > 1000) {
+                        LambdaTestHelpers.launderAssertion(
+                                asserter,
+                                () -> String.format("%n%s: [actual size=%d] != [expected size=%d]", test, result.size(), refResult.size()));
+                    }
+                    else {
+                        LambdaTestHelpers.launderAssertion(
+                                asserter,
+                                () -> String.format("%n%s: [actual] %s != [expected] %s", test, result, refResult));
+                    }
+
+                    after.accept(data);
+                } catch (Throwable t) {
+                    errors.add(new Error(String.format("%s: %s", test, t), t));
+                }
+            }
+
+            if (!errors.isEmpty()) {
+                StringBuilder sb = new StringBuilder();
+                int i = 1;
+                for (Error t : errors) {
+                    sb.append(i++).append(": ");
+                    if (t instanceof AssertionError) {
+                        sb.append(t).append("\n");
+                    }
+                    else {
+                        StringWriter sw = new StringWriter();
+                        PrintWriter pw = new PrintWriter(sw);
+
+                        t.getCause().printStackTrace(pw);
+                        pw.flush();
+                        sb.append(t).append("\n").append(sw);
+                    }
+                }
+                sb.append("--");
+
+                fail(String.format("%d failure(s) for test data: %s\n%s", i - 1, data.toString(), sb));
+            }
+
+            return refResult;
+        }
+    }
+
+    // Exercise terminal operations
+
+    interface BaseTerminalTestScenario<U, R, S_OUT extends BaseStream<U, S_OUT>> {
+        boolean requiresSingleStageSource();
+
+        boolean requiresParallelSource();
+
+        default R run(Function<S_OUT, R> terminalF, S_OUT source, StreamShape shape) {
+            return terminalF.apply(source);
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    enum TerminalTestScenario implements BaseTerminalTestScenario {
+        SINGLE_SEQUENTIAL(true, false),
+
+        SINGLE_SEQUENTIAL_SHORT_CIRCUIT(true, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+                return terminalF.apply(source);
+            }
+        },
+
+        SINGLE_PARALLEL(true, true),
+
+        ALL_SEQUENTIAL(false, false),
+
+        ALL_SEQUENTIAL_SHORT_CIRCUIT(false, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+                return terminalF.apply(source);
+            }
+        },
+
+        ALL_PARALLEL(false, true),
+
+        ALL_PARALLEL_SEQUENTIAL(false, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                return terminalF.apply(source.sequential());
+            }
+        },
+        ;
+
+        private final boolean requiresSingleStageSource;
+        private final boolean isParallel;
+
+        TerminalTestScenario(boolean requiresSingleStageSource, boolean isParallel) {
+            this.requiresSingleStageSource = requiresSingleStageSource;
+            this.isParallel = isParallel;
+        }
+
+        @Override
+        public boolean requiresSingleStageSource() {
+            return requiresSingleStageSource;
+        }
+
+        @Override
+        public boolean requiresParallelSource() {
+            return isParallel;
+        }
+
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public class ExerciseDataTerminalBuilder<T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> {
+        final TestData<T, S_IN> data;
+        final Function<S_IN, S_OUT> streamF;
+        final Function<S_OUT, R> terminalF;
+
+        R refResult;
+
+        ResultAsserter<R> resultAsserter = (act, exp, ord, par) -> LambdaTestHelpers.assertContentsEqual(act, exp);
+
+        private ExerciseDataTerminalBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
+            this.data = data;
+            this.streamF = Objects.requireNonNull(streamF);
+            this.terminalF = Objects.requireNonNull(terminalF);
+        }
+
+        //
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> expectedResult(R expectedResult) {
+            this.refResult = expectedResult;
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> equalator(BiConsumer<R, R> equalityAsserter) {
+            resultAsserter = (act, exp, ord, par) -> equalityAsserter.accept(act, exp);
+            return this;
+        }
+
+        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> resultAsserter(ResultAsserter<R> resultAsserter) {
+            this.resultAsserter = resultAsserter;
+            return this;
+        }
+
+        // Build method
+
+        public R exercise() {
+            S_OUT out = streamF.apply(data.stream()).sequential();
+            AbstractPipeline ap = (AbstractPipeline) out;
+            boolean isOrdered = StreamOpFlag.ORDERED.isKnown(ap.getStreamFlags());
+            StreamShape shape = ap.getOutputShape();
+
+            EnumSet<TerminalTestScenario> tests = EnumSet.allOf(TerminalTestScenario.class);
+            // Sequentially collect the output that will be input to the terminal op
+            Node<U> node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]);
+            if (refResult == null) {
+                // Induce the reference result
+                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                      false);
+
+                refResult = (R) TerminalTestScenario.SINGLE_SEQUENTIAL.run(terminalF, source, shape);
+                tests.remove(TerminalTestScenario.SINGLE_SEQUENTIAL);
+            }
+
+            for (BaseTerminalTestScenario test : tests) {
+                S_OUT source;
+                if (test.requiresSingleStageSource()) {
+                    source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                    StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                    test.requiresParallelSource());
+                }
+                else {
+                    source = streamF.apply(test.requiresParallelSource()
+                                           ? data.parallelStream() : data.stream());
+                }
+
+                R result = (R) test.run(terminalF, source, shape);
+
+                LambdaTestHelpers.launderAssertion(
+                        () -> resultAsserter.assertResult(result, refResult, isOrdered, test.requiresParallelSource()),
+                        () -> String.format("%s: %s != %s", test, refResult, result));
+            }
+
+            return refResult;
+        }
+
+        AbstractPipeline createPipeline(StreamShape shape, Spliterator s, int flags, boolean parallel) {
+            switch (shape) {
+                case REFERENCE:    return new ReferencePipeline.Head<>(s, flags, parallel);
+                case INT_VALUE:    return new IntPipeline.Head(s, flags, parallel);
+                case LONG_VALUE:   return new LongPipeline.Head(s, flags, parallel);
+                case DOUBLE_VALUE: return new DoublePipeline.Head(s, flags, parallel);
+                default: throw new IllegalStateException("Unknown shape: " + shape);
+            }
+        }
+    }
+
+    protected <T, R> R exerciseTerminalOps(Collection<T> data, Function<Stream<T>, R> m, R expected) {
+        TestData.OfRef<T> data1
+                = TestData.Factory.ofCollection("Collection of type " + data.getClass().getName(), data);
+        return withData(data1).terminal(m).expectedResult(expected).exercise();
+    }
+
+    protected <T, R, S_IN extends BaseStream<T, S_IN>> R
+    exerciseTerminalOps(TestData<T, S_IN> data,
+                        Function<S_IN, R> terminalF) {
+        return withData(data).terminal(terminalF).exercise();
+    }
+
+    protected <T, U, R, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>> R
+    exerciseTerminalOps(TestData<T, S_IN> data,
+                        Function<S_IN, S_OUT> streamF,
+                        Function<S_OUT, R> terminalF) {
+        return withData(data).terminal(streamF, terminalF).exercise();
+    }
+
+    //
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static <T> AbstractPipeline<?, T, ?> chain(AbstractPipeline upstream, IntermediateTestOp<?, T> op) {
+        return (AbstractPipeline<?, T, ?>) IntermediateTestOp.chain(upstream, op);
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static AbstractPipeline<?, ?, ?> chain(AbstractPipeline pipe, IntermediateTestOp... ops) {
+        for (IntermediateTestOp op : ops)
+            pipe = chain(pipe, op);
+        return pipe;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static <T> AbstractPipeline<?, T, ?> chain(BaseStream pipe, IntermediateTestOp<?, T> op) {
+        return chain((AbstractPipeline) pipe, op);
+    }
+
+    @SuppressWarnings("rawtypes")
+    public static AbstractPipeline<?, ?, ?> chain(BaseStream pipe, IntermediateTestOp... ops) {
+        return chain((AbstractPipeline) pipe, ops);
+    }
+
+    // Test data
+
+    static class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
+        private final StreamShape shape;
+
+        ShortCircuitOp(StreamShape shape) {
+            this.shape = shape;
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, boolean parallel, Sink<T> sink) {
+            return sink;
+        }
+
+        @Override
+        public int opGetFlags() {
+            return StreamOpFlag.IS_SHORT_CIRCUIT;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return shape;
+        }
+
+        @Override
+        public StreamShape inputShape() {
+            return shape;
+        }
+    }
+}
diff --git a/java/util/stream/PipelineHelper.java b/java/util/stream/PipelineHelper.java
new file mode 100644
index 0000000..832d68a
--- /dev/null
+++ b/java/util/stream/PipelineHelper.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * Helper class for executing <a href="package-summary.html#StreamOps">
+ * stream pipelines</a>, capturing all of the information about a stream
+ * pipeline (output shape, intermediate operations, stream flags, parallelism,
+ * etc) in one place.
+ *
+ * <p>
+ * A {@code PipelineHelper} describes the initial segment of a stream pipeline,
+ * including its source, intermediate operations, and may additionally
+ * incorporate information about the terminal (or stateful) operation which
+ * follows the last intermediate operation described by this
+ * {@code PipelineHelper}. The {@code PipelineHelper} is passed to the
+ * {@link TerminalOp#evaluateParallel(PipelineHelper, java.util.Spliterator)},
+ * {@link TerminalOp#evaluateSequential(PipelineHelper, java.util.Spliterator)},
+ * and {@link AbstractPipeline#opEvaluateParallel(PipelineHelper, java.util.Spliterator,
+ * java.util.function.IntFunction)}, methods, which can use the
+ * {@code PipelineHelper} to access information about the pipeline such as
+ * head shape, stream flags, and size, and use the helper methods
+ * such as {@link #wrapAndCopyInto(Sink, Spliterator)},
+ * {@link #copyInto(Sink, Spliterator)}, and {@link #wrapSink(Sink)} to execute
+ * pipeline operations.
+ *
+ * @param <P_OUT> type of output elements from the pipeline
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class PipelineHelper<P_OUT> {
+
+    /**
+     * Gets the stream shape for the source of the pipeline segment.
+     *
+     * @return the stream shape for the source of the pipeline segment.
+     */
+    abstract StreamShape getSourceShape();
+
+    /**
+     * Gets the combined stream and operation flags for the output of the described
+     * pipeline.  This will incorporate stream flags from the stream source, all
+     * the intermediate operations and the terminal operation.
+     *
+     * @return the combined stream and operation flags
+     * @see StreamOpFlag
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract int getStreamAndOpFlags();
+
+    /**
+     * Returns the exact output size of the portion of the output resulting from
+     * applying the pipeline stages described by this {@code PipelineHelper} to
+     * the the portion of the input described by the provided
+     * {@code Spliterator}, if known.  If not known or known infinite, will
+     * return {@code -1}.
+     *
+     * @apiNote
+     * The exact output size is known if the {@code Spliterator} has the
+     * {@code SIZED} characteristic, and the operation flags
+     * {@link StreamOpFlag#SIZED} is known on the combined stream and operation
+     * flags.
+     *
+     * @param spliterator the spliterator describing the relevant portion of the
+     *        source data
+     * @return the exact size if known, or -1 if infinite or unknown
+     */
+    abstract<P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator);
+
+    /**
+     * Applies the pipeline stages described by this {@code PipelineHelper} to
+     * the provided {@code Spliterator} and send the results to the provided
+     * {@code Sink}.
+     *
+     * @implSpec
+     * The implementation behaves as if:
+     * <pre>{@code
+     *     intoWrapped(wrapSink(sink), spliterator);
+     * }</pre>
+     *
+     * @param sink the {@code Sink} to receive the results
+     * @param spliterator the spliterator describing the source input to process
+     */
+    abstract<P_IN, S extends Sink<P_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Pushes elements obtained from the {@code Spliterator} into the provided
+     * {@code Sink}.  If the stream pipeline is known to have short-circuiting
+     * stages in it (see {@link StreamOpFlag#SHORT_CIRCUIT}), the
+     * {@link Sink#cancellationRequested()} is checked after each
+     * element, stopping if cancellation is requested.
+     *
+     * @implSpec
+     * This method conforms to the {@code Sink} protocol of calling
+     * {@code Sink.begin} before pushing elements, via {@code Sink.accept}, and
+     * calling {@code Sink.end} after all elements have been pushed.
+     *
+     * @param wrappedSink the destination {@code Sink}
+     * @param spliterator the source {@code Spliterator}
+     */
+    abstract<P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Pushes elements obtained from the {@code Spliterator} into the provided
+     * {@code Sink}, checking {@link Sink#cancellationRequested()} after each
+     * element, and stopping if cancellation is requested.
+     *
+     * @implSpec
+     * This method conforms to the {@code Sink} protocol of calling
+     * {@code Sink.begin} before pushing elements, via {@code Sink.accept}, and
+     * calling {@code Sink.end} after all elements have been pushed or if
+     * cancellation is requested.
+     *
+     * @param wrappedSink the destination {@code Sink}
+     * @param spliterator the source {@code Spliterator}
+     */
+    abstract <P_IN> void copyIntoWithCancel(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator);
+
+    /**
+     * Takes a {@code Sink} that accepts elements of the output type of the
+     * {@code PipelineHelper}, and wrap it with a {@code Sink} that accepts
+     * elements of the input type and implements all the intermediate operations
+     * described by this {@code PipelineHelper}, delivering the result into the
+     * provided {@code Sink}.
+     *
+     * @param sink the {@code Sink} to receive the results
+     * @return a {@code Sink} that implements the pipeline stages and sends
+     *         results to the provided {@code Sink}
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract<P_IN> Sink<P_IN> wrapSink(Sink<P_OUT> sink);
+
+    /**
+     *
+     * @param spliterator
+     * @param <P_IN>
+     * @return
+     */
+    abstract<P_IN> Spliterator<P_OUT> wrapSpliterator(Spliterator<P_IN> spliterator);
+
+    /**
+     * Constructs a @{link Node.Builder} compatible with the output shape of
+     * this {@code PipelineHelper}.
+     *
+     * @param exactSizeIfKnown if >=0 then a builder will be created that has a
+     *        fixed capacity of exactly sizeIfKnown elements; if < 0 then the
+     *        builder has variable capacity.  A fixed capacity builder will fail
+     *        if an element is added after the builder has reached capacity.
+     * @param generator a factory function for array instances
+     * @return a {@code Node.Builder} compatible with the output shape of this
+     *         {@code PipelineHelper}
+     */
+    abstract Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown,
+                                                 IntFunction<P_OUT[]> generator);
+
+    /**
+     * Collects all output elements resulting from applying the pipeline stages
+     * to the source {@code Spliterator} into a {@code Node}.
+     *
+     * @implNote
+     * If the pipeline has no intermediate operations and the source is backed
+     * by a {@code Node} then that {@code Node} will be returned (or flattened
+     * and then returned). This reduces copying for a pipeline consisting of a
+     * stateful operation followed by a terminal operation that returns an
+     * array, such as:
+     * <pre>{@code
+     *     stream.sorted().toArray();
+     * }</pre>
+     *
+     * @param spliterator the source {@code Spliterator}
+     * @param flatten if true and the pipeline is a parallel pipeline then the
+     *        {@code Node} returned will contain no children, otherwise the
+     *        {@code Node} may represent the root in a tree that reflects the
+     *        shape of the computation tree.
+     * @param generator a factory function for array instances
+     * @return the {@code Node} containing all output elements
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract<P_IN> Node<P_OUT> evaluate(Spliterator<P_IN> spliterator,
+                                        boolean flatten,
+                                        IntFunction<P_OUT[]> generator);
+}
diff --git a/java/util/stream/ReduceOps.java b/java/util/stream/ReduceOps.java
new file mode 100644
index 0000000..3a0f81a
--- /dev/null
+++ b/java/util/stream/ReduceOps.java
@@ -0,0 +1,761 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.OptionalLong;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.ObjDoubleConsumer;
+import java.util.function.ObjIntConsumer;
+import java.util.function.ObjLongConsumer;
+import java.util.function.Supplier;
+
+/**
+ * Factory for creating instances of {@code TerminalOp} that implement
+ * reductions.
+ *
+ * @since 1.8
+ */
+final class ReduceOps {
+
+    private ReduceOps() { }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <U> the type of the result
+     * @param seed the identity element for the reduction
+     * @param reducer the accumulating function that incorporates an additional
+     *        input element into the result
+     * @param combiner the combining function that combines two intermediate
+     *        results
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <T, U> TerminalOp<T, U>
+    makeRef(U seed, BiFunction<U, ? super T, U> reducer, BinaryOperator<U> combiner) {
+        Objects.requireNonNull(reducer);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<U> implements AccumulatingSink<T, U, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = seed;
+            }
+
+            @Override
+            public void accept(T t) {
+                state = reducer.apply(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<T, U, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * reference values producing an optional reference result.
+     *
+     * @param <T> The type of the input elements, and the type of the result
+     * @param operator The reducing function
+     * @return A {@code TerminalOp} implementing the reduction
+     */
+    public static <T> TerminalOp<T, Optional<T>>
+    makeRef(BinaryOperator<T> operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<T, Optional<T>, ReducingSink> {
+            private boolean empty;
+            private T state;
+
+            public void begin(long size) {
+                empty = true;
+                state = null;
+            }
+
+            @Override
+            public void accept(T t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                } else {
+                    state = operator.apply(state, t);
+                }
+            }
+
+            @Override
+            public Optional<T> get() {
+                return empty ? Optional.empty() : Optional.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<T, Optional<T>, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <I> the type of the intermediate reduction result
+     * @param collector a {@code Collector} defining the reduction
+     * @return a {@code ReduceOp} implementing the reduction
+     */
+    public static <T, I> TerminalOp<T, I>
+    makeRef(Collector<? super T, I, ?> collector) {
+        Supplier<I> supplier = Objects.requireNonNull(collector).supplier();
+        BiConsumer<I, ? super T> accumulator = collector.accumulator();
+        BinaryOperator<I> combiner = collector.combiner();
+        class ReducingSink extends Box<I>
+                implements AccumulatingSink<T, I, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<T, I, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+
+            @Override
+            public int getOpFlags() {
+                return collector.characteristics().contains(Collector.Characteristics.UNORDERED)
+                       ? StreamOpFlag.NOT_ORDERED
+                       : 0;
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * reference values.
+     *
+     * @param <T> the type of the input elements
+     * @param <R> the type of the result
+     * @param seedFactory a factory to produce a new base accumulator
+     * @param accumulator a function to incorporate an element into an
+     *        accumulator
+     * @param reducer a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <T, R> TerminalOp<T, R>
+    makeRef(Supplier<R> seedFactory,
+            BiConsumer<R, ? super T> accumulator,
+            BiConsumer<R,R> reducer) {
+        Objects.requireNonNull(seedFactory);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(reducer);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<T, R, ReducingSink> {
+            @Override
+            public void begin(long size) {
+                state = seedFactory.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                reducer.accept(state, other.state);
+            }
+        }
+        return new ReduceOp<T, R, ReducingSink>(StreamShape.REFERENCE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code int} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Integer, Integer>
+    makeInt(int identity, IntBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Integer, Integer, ReducingSink>, Sink.OfInt {
+            private int state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(int t) {
+                state = operator.applyAsInt(state, t);
+            }
+
+            @Override
+            public Integer get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Integer, Integer, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code int} values, producing an optional integer result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Integer, OptionalInt>
+    makeInt(IntBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Integer, OptionalInt, ReducingSink>, Sink.OfInt {
+            private boolean empty;
+            private int state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(int t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsInt(state, t);
+                }
+            }
+
+            @Override
+            public OptionalInt get() {
+                return empty ? OptionalInt.empty() : OptionalInt.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Integer, OptionalInt, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code int} values.
+     *
+     * @param <R> The type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return A {@code ReduceOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Integer, R>
+    makeInt(Supplier<R> supplier,
+            ObjIntConsumer<R> accumulator,
+            BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Integer, R, ReducingSink>, Sink.OfInt {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(int t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Integer, R, ReducingSink>(StreamShape.INT_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code long} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Long, Long>
+    makeLong(long identity, LongBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Long, Long, ReducingSink>, Sink.OfLong {
+            private long state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(long t) {
+                state = operator.applyAsLong(state, t);
+            }
+
+            @Override
+            public Long get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Long, Long, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code long} values, producing an optional long result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Long, OptionalLong>
+    makeLong(LongBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Long, OptionalLong, ReducingSink>, Sink.OfLong {
+            private boolean empty;
+            private long state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(long t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsLong(state, t);
+                }
+            }
+
+            @Override
+            public OptionalLong get() {
+                return empty ? OptionalLong.empty() : OptionalLong.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Long, OptionalLong, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code long} values.
+     *
+     * @param <R> the type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Long, R>
+    makeLong(Supplier<R> supplier,
+             ObjLongConsumer<R> accumulator,
+             BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Long, R, ReducingSink>, Sink.OfLong {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(long t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Long, R, ReducingSink>(StreamShape.LONG_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code double} values.
+     *
+     * @param identity the identity for the combining function
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Double, Double>
+    makeDouble(double identity, DoubleBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Double, Double, ReducingSink>, Sink.OfDouble {
+            private double state;
+
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(double t) {
+                state = operator.applyAsDouble(state, t);
+            }
+
+            @Override
+            public Double get() {
+                return state;
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                accept(other.state);
+            }
+        }
+        return new ReduceOp<Double, Double, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a functional reduce on
+     * {@code double} values, producing an optional double result.
+     *
+     * @param operator the combining function
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static TerminalOp<Double, OptionalDouble>
+    makeDouble(DoubleBinaryOperator operator) {
+        Objects.requireNonNull(operator);
+        class ReducingSink
+                implements AccumulatingSink<Double, OptionalDouble, ReducingSink>, Sink.OfDouble {
+            private boolean empty;
+            private double state;
+
+            public void begin(long size) {
+                empty = true;
+                state = 0;
+            }
+
+            @Override
+            public void accept(double t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsDouble(state, t);
+                }
+            }
+
+            @Override
+            public OptionalDouble get() {
+                return empty ? OptionalDouble.empty() : OptionalDouble.of(state);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new ReduceOp<Double, OptionalDouble, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * Constructs a {@code TerminalOp} that implements a mutable reduce on
+     * {@code double} values.
+     *
+     * @param <R> the type of the result
+     * @param supplier a factory to produce a new accumulator of the result type
+     * @param accumulator a function to incorporate an int into an
+     *        accumulator
+     * @param combiner a function to combine an accumulator into another
+     * @return a {@code TerminalOp} implementing the reduction
+     */
+    public static <R> TerminalOp<Double, R>
+    makeDouble(Supplier<R> supplier,
+               ObjDoubleConsumer<R> accumulator,
+               BinaryOperator<R> combiner) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        class ReducingSink extends Box<R>
+                implements AccumulatingSink<Double, R, ReducingSink>, Sink.OfDouble {
+            @Override
+            public void begin(long size) {
+                state = supplier.get();
+            }
+
+            @Override
+            public void accept(double t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(ReducingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        return new ReduceOp<Double, R, ReducingSink>(StreamShape.DOUBLE_VALUE) {
+            @Override
+            public ReducingSink makeSink() {
+                return new ReducingSink();
+            }
+        };
+    }
+
+    /**
+     * A type of {@code TerminalSink} that implements an associative reducing
+     * operation on elements of type {@code T} and producing a result of type
+     * {@code R}.
+     *
+     * @param <T> the type of input element to the combining operation
+     * @param <R> the result type
+     * @param <K> the type of the {@code AccumulatingSink}.
+     */
+    private interface AccumulatingSink<T, R, K extends AccumulatingSink<T, R, K>>
+            extends TerminalSink<T, R> {
+        public void combine(K other);
+    }
+
+    /**
+     * State box for a single state element, used as a base class for
+     * {@code AccumulatingSink} instances
+     *
+     * @param <U> The type of the state element
+     */
+    private static abstract class Box<U> {
+        U state;
+
+        Box() {} // Avoid creation of special accessor
+
+        public U get() {
+            return state;
+        }
+    }
+
+    /**
+     * A {@code TerminalOp} that evaluates a stream pipeline and sends the
+     * output into an {@code AccumulatingSink}, which performs a reduce
+     * operation. The {@code AccumulatingSink} must represent an associative
+     * reducing operation.
+     *
+     * @param <T> the output type of the stream pipeline
+     * @param <R> the result type of the reducing operation
+     * @param <S> the type of the {@code AccumulatingSink}
+     */
+    private static abstract class ReduceOp<T, R, S extends AccumulatingSink<T, R, S>>
+            implements TerminalOp<T, R> {
+        private final StreamShape inputShape;
+
+        /**
+         * Create a {@code ReduceOp} of the specified stream shape which uses
+         * the specified {@code Supplier} to create accumulating sinks.
+         *
+         * @param shape The shape of the stream pipeline
+         */
+        ReduceOp(StreamShape shape) {
+            inputShape = shape;
+        }
+
+        public abstract S makeSink();
+
+        @Override
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        @Override
+        public <P_IN> R evaluateSequential(PipelineHelper<T> helper,
+                                           Spliterator<P_IN> spliterator) {
+            return helper.wrapAndCopyInto(makeSink(), spliterator).get();
+        }
+
+        @Override
+        public <P_IN> R evaluateParallel(PipelineHelper<T> helper,
+                                         Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, helper, spliterator).invoke().get();
+        }
+    }
+
+    /**
+     * A {@code ForkJoinTask} for performing a parallel reduce operation.
+     */
+    @SuppressWarnings("serial")
+    private static final class ReduceTask<P_IN, P_OUT, R,
+                                          S extends AccumulatingSink<P_OUT, R, S>>
+            extends AbstractTask<P_IN, P_OUT, S, ReduceTask<P_IN, P_OUT, R, S>> {
+        private final ReduceOp<P_OUT, R, S> op;
+
+        ReduceTask(ReduceOp<P_OUT, R, S> op,
+                   PipelineHelper<P_OUT> helper,
+                   Spliterator<P_IN> spliterator) {
+            super(helper, spliterator);
+            this.op = op;
+        }
+
+        ReduceTask(ReduceTask<P_IN, P_OUT, R, S> parent,
+                   Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected ReduceTask<P_IN, P_OUT, R, S> makeChild(Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected S doLeaf() {
+            return helper.wrapAndCopyInto(op.makeSink(), spliterator);
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                S leftResult = leftChild.getLocalResult();
+                leftResult.combine(rightChild.getLocalResult());
+                setLocalResult(leftResult);
+            }
+            // GC spliterator, left and right child
+            super.onCompletion(caller);
+        }
+    }
+}
diff --git a/java/util/stream/ReferencePipeline.java b/java/util/stream/ReferencePipeline.java
new file mode 100644
index 0000000..84ec8c5
--- /dev/null
+++ b/java/util/stream/ReferencePipeline.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+/**
+ * Abstract base class for an intermediate pipeline stage or pipeline source
+ * stage implementing whose elements are of type {@code U}.
+ *
+ * @param <P_IN> type of elements in the upstream source
+ * @param <P_OUT> type of elements in produced by this stage
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public abstract class ReferencePipeline<P_IN, P_OUT>
+        extends AbstractPipeline<P_IN, P_OUT, Stream<P_OUT>>
+        implements Stream<P_OUT>  {
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Supplier<Spliterator>} describing the stream source
+     * @param sourceFlags the source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    ReferencePipeline(Supplier<? extends Spliterator<?>> source,
+                      int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for the head of a stream pipeline.
+     *
+     * @param source {@code Spliterator} describing the stream source
+     * @param sourceFlags The source flags for the stream source, described in
+     *        {@link StreamOpFlag}
+     * @param parallel {@code true} if the pipeline is parallel
+     */
+    ReferencePipeline(Spliterator<?> source,
+                      int sourceFlags, boolean parallel) {
+        super(source, sourceFlags, parallel);
+    }
+
+    /**
+     * Constructor for appending an intermediate operation onto an existing
+     * pipeline.
+     *
+     * @param upstream the upstream element source.
+     */
+    ReferencePipeline(AbstractPipeline<?, P_IN, ?> upstream, int opFlags) {
+        super(upstream, opFlags);
+    }
+
+    // Shape-specific methods
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final StreamShape getOutputShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Node<P_OUT> evaluateToNode(PipelineHelper<P_OUT> helper,
+                                        Spliterator<P_IN> spliterator,
+                                        boolean flattenTree,
+                                        IntFunction<P_OUT[]> generator) {
+        return Nodes.collect(helper, spliterator, flattenTree, generator);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final <P_IN> Spliterator<P_OUT> wrap(PipelineHelper<P_OUT> ph,
+                                     Supplier<Spliterator<P_IN>> supplier,
+                                     boolean isParallel) {
+        return new StreamSpliterators.WrappingSpliterator<>(ph, supplier, isParallel);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Spliterator<P_OUT> lazySpliterator(Supplier<? extends Spliterator<P_OUT>> supplier) {
+        return new StreamSpliterators.DelegatingSpliterator<>(supplier);
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final void forEachWithCancel(Spliterator<P_OUT> spliterator, Sink<P_OUT> sink) {
+        do { } while (!sink.cancellationRequested() && spliterator.tryAdvance(sink));
+    }
+
+    @Override
+    // Android-changed: Make public, to match the method it's overriding.
+    public final Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown, IntFunction<P_OUT[]> generator) {
+        return Nodes.builder(exactSizeIfKnown, generator);
+    }
+
+
+    // BaseStream
+
+    @Override
+    public final Iterator<P_OUT> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+
+    // Stream
+
+    // Stateless intermediate operations from Stream
+
+    @Override
+    public Stream<P_OUT> unordered() {
+        if (!isOrdered())
+            return this;
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE, StreamOpFlag.NOT_ORDERED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return sink;
+            }
+        };
+    }
+
+    @Override
+    public final Stream<P_OUT> filter(Predicate<? super P_OUT> predicate) {
+        Objects.requireNonNull(predicate);
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        if (predicate.test(u))
+                            downstream.accept(u);
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <R> Stream<R> map(Function<? super P_OUT, ? extends R> mapper) {
+        Objects.requireNonNull(mapper);
+        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.apply(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream mapToInt(ToIntFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new IntPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsInt(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream mapToLong(ToLongFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsLong(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream mapToDouble(ToDoubleFunction<? super P_OUT> mapper) {
+        Objects.requireNonNull(mapper);
+        return new DoublePipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        downstream.accept(mapper.applyAsDouble(u));
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final <R> Stream<R> flatMap(Function<? super P_OUT, ? extends Stream<? extends R>> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new StatelessOp<P_OUT, R>(this, StreamShape.REFERENCE,
+                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            public Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (Stream<? extends R> result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstream);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final IntStream flatMapToInt(Function<? super P_OUT, ? extends IntStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new IntPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
+                    IntConsumer downstreamAsInt = downstream::accept;
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (IntStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsInt);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final DoubleStream flatMapToDouble(Function<? super P_OUT, ? extends DoubleStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new DoublePipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
+                    DoubleConsumer downstreamAsDouble = downstream::accept;
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (DoubleStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsDouble);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final LongStream flatMapToLong(Function<? super P_OUT, ? extends LongStream> mapper) {
+        Objects.requireNonNull(mapper);
+        // We can do better than this, by polling cancellationRequested when stream is infinite
+        return new LongPipeline.StatelessOp<P_OUT>(this, StreamShape.REFERENCE,
+                                                   StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
+                    LongConsumer downstreamAsLong = downstream::accept;
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(-1);
+                    }
+
+                    @Override
+                    public void accept(P_OUT u) {
+                        try (LongStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsLong);
+                        }
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
+        Objects.requireNonNull(action);
+        return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
+                                     0) {
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
+                    @Override
+                    public void accept(P_OUT u) {
+                        action.accept(u);
+                        downstream.accept(u);
+                    }
+                };
+            }
+        };
+    }
+
+    // Stateful intermediate operations from Stream
+
+    @Override
+    public final Stream<P_OUT> distinct() {
+        return DistinctOps.makeRef(this);
+    }
+
+    @Override
+    public final Stream<P_OUT> sorted() {
+        return SortedOps.makeRef(this);
+    }
+
+    @Override
+    public final Stream<P_OUT> sorted(Comparator<? super P_OUT> comparator) {
+        return SortedOps.makeRef(this, comparator);
+    }
+
+    @Override
+    public final Stream<P_OUT> limit(long maxSize) {
+        if (maxSize < 0)
+            throw new IllegalArgumentException(Long.toString(maxSize));
+        return SliceOps.makeRef(this, 0, maxSize);
+    }
+
+    @Override
+    public final Stream<P_OUT> skip(long n) {
+        if (n < 0)
+            throw new IllegalArgumentException(Long.toString(n));
+        if (n == 0)
+            return this;
+        else
+            return SliceOps.makeRef(this, n, -1);
+    }
+
+    // Terminal operations from Stream
+
+    @Override
+    public void forEach(Consumer<? super P_OUT> action) {
+        evaluate(ForEachOps.makeRef(action, false));
+    }
+
+    @Override
+    public void forEachOrdered(Consumer<? super P_OUT> action) {
+        evaluate(ForEachOps.makeRef(action, true));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <A> A[] toArray(IntFunction<A[]> generator) {
+        // Since A has no relation to U (not possible to declare that A is an upper bound of U)
+        // there will be no static type checking.
+        // Therefore use a raw type and assume A == U rather than propagating the separation of A and U
+        // throughout the code-base.
+        // The runtime type of U is never checked for equality with the component type of the runtime type of A[].
+        // Runtime checking will be performed when an element is stored in A[], thus if A is not a
+        // super type of U an ArrayStoreException will be thrown.
+        @SuppressWarnings("rawtypes")
+        IntFunction rawGenerator = (IntFunction) generator;
+        // Android-changed: Eclipse compiler requires explicit (Node<A[]>) cast (b/29399275).
+        return (A[]) Nodes.flatten((Node<A[]>) evaluateToArrayNode(rawGenerator), rawGenerator)
+                .asArray(rawGenerator);
+    }
+
+    @Override
+    public final Object[] toArray() {
+        return toArray(Object[]::new);
+    }
+
+    @Override
+    public final boolean anyMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ANY));
+    }
+
+    @Override
+    public final boolean allMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.ALL));
+    }
+
+    @Override
+    public final boolean noneMatch(Predicate<? super P_OUT> predicate) {
+        return evaluate(MatchOps.makeRef(predicate, MatchOps.MatchKind.NONE));
+    }
+
+    @Override
+    public final Optional<P_OUT> findFirst() {
+        return evaluate(FindOps.makeRef(true));
+    }
+
+    @Override
+    public final Optional<P_OUT> findAny() {
+        return evaluate(FindOps.makeRef(false));
+    }
+
+    @Override
+    public final P_OUT reduce(final P_OUT identity, final BinaryOperator<P_OUT> accumulator) {
+        return evaluate(ReduceOps.makeRef(identity, accumulator, accumulator));
+    }
+
+    @Override
+    public final Optional<P_OUT> reduce(BinaryOperator<P_OUT> accumulator) {
+        return evaluate(ReduceOps.makeRef(accumulator));
+    }
+
+    @Override
+    public final <R> R reduce(R identity, BiFunction<R, ? super P_OUT, R> accumulator, BinaryOperator<R> combiner) {
+        return evaluate(ReduceOps.makeRef(identity, accumulator, combiner));
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
+        A container;
+        if (isParallel()
+                && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
+                && (!isOrdered() || collector.characteristics().contains(Collector.Characteristics.UNORDERED))) {
+            container = collector.supplier().get();
+            BiConsumer<A, ? super P_OUT> accumulator = collector.accumulator();
+            forEach(u -> accumulator.accept(container, u));
+        }
+        else {
+            container = evaluate(ReduceOps.makeRef(collector));
+        }
+        return collector.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)
+               ? (R) container
+               : collector.finisher().apply(container);
+    }
+
+    @Override
+    public final <R> R collect(Supplier<R> supplier,
+                               BiConsumer<R, ? super P_OUT> accumulator,
+                               BiConsumer<R, R> combiner) {
+        return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner));
+    }
+
+    @Override
+    public final Optional<P_OUT> max(Comparator<? super P_OUT> comparator) {
+        return reduce(BinaryOperator.maxBy(comparator));
+    }
+
+    @Override
+    public final Optional<P_OUT> min(Comparator<? super P_OUT> comparator) {
+        return reduce(BinaryOperator.minBy(comparator));
+
+    }
+
+    @Override
+    public final long count() {
+        return mapToLong(e -> 1L).sum();
+    }
+
+
+    //
+
+    /**
+     * Source stage of a ReferencePipeline.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class Head<E_IN, E_OUT> extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Constructor for the source stage of a Stream.
+         *
+         * @param source {@code Supplier<Spliterator>} describing the stream
+         *               source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Supplier<? extends Spliterator<?>> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        /**
+         * Constructor for the source stage of a Stream.
+         *
+         * @param source {@code Spliterator} describing the stream source
+         * @param sourceFlags the source flags for the stream source, described
+         *                    in {@link StreamOpFlag}
+         */
+        // Android-changed: Made public for CTS tests only.
+        public Head(Spliterator<?> source,
+             int sourceFlags, boolean parallel) {
+            super(source, sourceFlags, parallel);
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink) {
+            throw new UnsupportedOperationException();
+        }
+
+        // Optimized sequential terminal operations for the head of the pipeline
+
+        @Override
+        public void forEach(Consumer<? super E_OUT> action) {
+            if (!isParallel()) {
+                sourceStageSpliterator().forEachRemaining(action);
+            }
+            else {
+                super.forEach(action);
+            }
+        }
+
+        @Override
+        public void forEachOrdered(Consumer<? super E_OUT> action) {
+            if (!isParallel()) {
+                sourceStageSpliterator().forEachRemaining(action);
+            }
+            else {
+                super.forEachOrdered(action);
+            }
+        }
+    }
+
+    /**
+     * Base class for a stateless intermediate stage of a Stream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatelessOp<E_IN, E_OUT>
+            extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Construct a new Stream by appending a stateless intermediate
+         * operation to an existing stream.
+         *
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatelessOp(AbstractPipeline<?, E_IN, ?> upstream,
+                    StreamShape inputShape,
+                    int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return false;
+        }
+    }
+
+    /**
+     * Base class for a stateful intermediate stage of a Stream.
+     *
+     * @param <E_IN> type of elements in the upstream source
+     * @param <E_OUT> type of elements in produced by this stage
+     * @since 1.8
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public abstract static class StatefulOp<E_IN, E_OUT>
+            extends ReferencePipeline<E_IN, E_OUT> {
+        /**
+         * Construct a new Stream by appending a stateful intermediate operation
+         * to an existing stream.
+         * @param upstream The upstream pipeline stage
+         * @param inputShape The stream shape for the upstream pipeline stage
+         * @param opFlags Operation flags for the new stage
+         */
+        // Android-changed: Made public for CTS tests only.
+        public StatefulOp(AbstractPipeline<?, E_IN, ?> upstream,
+                   StreamShape inputShape,
+                   int opFlags) {
+            super(upstream, opFlags);
+            assert upstream.getOutputShape() == inputShape;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public final boolean opIsStateful() {
+            return true;
+        }
+
+        @Override
+        // Android-changed: Make public, to match the method it's overriding.
+        public abstract <P_IN> Node<E_OUT> opEvaluateParallel(PipelineHelper<E_OUT> helper,
+                                                       Spliterator<P_IN> spliterator,
+                                                       IntFunction<E_OUT[]> generator);
+    }
+}
diff --git a/java/util/stream/Sink.java b/java/util/stream/Sink.java
new file mode 100644
index 0000000..2c5609c
--- /dev/null
+++ b/java/util/stream/Sink.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * An extension of {@link Consumer} used to conduct values through the stages of
+ * a stream pipeline, with additional methods to manage size information,
+ * control flow, etc.  Before calling the {@code accept()} method on a
+ * {@code Sink} for the first time, you must first call the {@code begin()}
+ * method to inform it that data is coming (optionally informing the sink how
+ * much data is coming), and after all data has been sent, you must call the
+ * {@code end()} method.  After calling {@code end()}, you should not call
+ * {@code accept()} without again calling {@code begin()}.  {@code Sink} also
+ * offers a mechanism by which the sink can cooperatively signal that it does
+ * not wish to receive any more data (the {@code cancellationRequested()}
+ * method), which a source can poll before sending more data to the
+ * {@code Sink}.
+ *
+ * <p>A sink may be in one of two states: an initial state and an active state.
+ * It starts out in the initial state; the {@code begin()} method transitions
+ * it to the active state, and the {@code end()} method transitions it back into
+ * the initial state, where it can be re-used.  Data-accepting methods (such as
+ * {@code accept()} are only valid in the active state.
+ *
+ * @apiNote
+ * A stream pipeline consists of a source, zero or more intermediate stages
+ * (such as filtering or mapping), and a terminal stage, such as reduction or
+ * for-each.  For concreteness, consider the pipeline:
+ *
+ * <pre>{@code
+ *     int longestStringLengthStartingWithA
+ *         = strings.stream()
+ *                  .filter(s -> s.startsWith("A"))
+ *                  .mapToInt(String::length)
+ *                  .max();
+ * }</pre>
+ *
+ * <p>Here, we have three stages, filtering, mapping, and reducing.  The
+ * filtering stage consumes strings and emits a subset of those strings; the
+ * mapping stage consumes strings and emits ints; the reduction stage consumes
+ * those ints and computes the maximal value.
+ *
+ * <p>A {@code Sink} instance is used to represent each stage of this pipeline,
+ * whether the stage accepts objects, ints, longs, or doubles.  Sink has entry
+ * points for {@code accept(Object)}, {@code accept(int)}, etc, so that we do
+ * not need a specialized interface for each primitive specialization.  (It
+ * might be called a "kitchen sink" for this omnivorous tendency.)  The entry
+ * point to the pipeline is the {@code Sink} for the filtering stage, which
+ * sends some elements "downstream" -- into the {@code Sink} for the mapping
+ * stage, which in turn sends integral values downstream into the {@code Sink}
+ * for the reduction stage. The {@code Sink} implementations associated with a
+ * given stage is expected to know the data type for the next stage, and call
+ * the correct {@code accept} method on its downstream {@code Sink}.  Similarly,
+ * each stage must implement the correct {@code accept} method corresponding to
+ * the data type it accepts.
+ *
+ * <p>The specialized subtypes such as {@link Sink.OfInt} override
+ * {@code accept(Object)} to call the appropriate primitive specialization of
+ * {@code accept}, implement the appropriate primitive specialization of
+ * {@code Consumer}, and re-abstract the appropriate primitive specialization of
+ * {@code accept}.
+ *
+ * <p>The chaining subtypes such as {@link ChainedInt} not only implement
+ * {@code Sink.OfInt}, but also maintain a {@code downstream} field which
+ * represents the downstream {@code Sink}, and implement the methods
+ * {@code begin()}, {@code end()}, and {@code cancellationRequested()} to
+ * delegate to the downstream {@code Sink}.  Most implementations of
+ * intermediate operations will use these chaining wrappers.  For example, the
+ * mapping stage in the above example would look like:
+ *
+ * <pre>{@code
+ *     IntSink is = new Sink.ChainedReference<U>(sink) {
+ *         public void accept(U u) {
+ *             downstream.accept(mapper.applyAsInt(u));
+ *         }
+ *     };
+ * }</pre>
+ *
+ * <p>Here, we implement {@code Sink.ChainedReference<U>}, meaning that we expect
+ * to receive elements of type {@code U} as input, and pass the downstream sink
+ * to the constructor.  Because the next stage expects to receive integers, we
+ * must call the {@code accept(int)} method when emitting values to the downstream.
+ * The {@code accept()} method applies the mapping function from {@code U} to
+ * {@code int} and passes the resulting value to the downstream {@code Sink}.
+ *
+ * @param <T> type of elements for value streams
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public interface Sink<T> extends Consumer<T> {
+    /**
+     * Resets the sink state to receive a fresh data set.  This must be called
+     * before sending any data to the sink.  After calling {@link #end()},
+     * you may call this method to reset the sink for another calculation.
+     * @param size The exact size of the data to be pushed downstream, if
+     * known or {@code -1} if unknown or infinite.
+     *
+     * <p>Prior to this call, the sink must be in the initial state, and after
+     * this call it is in the active state.
+     */
+    default void begin(long size) {}
+
+    /**
+     * Indicates that all elements have been pushed.  If the {@code Sink} is
+     * stateful, it should send any stored state downstream at this time, and
+     * should clear any accumulated state (and associated resources).
+     *
+     * <p>Prior to this call, the sink must be in the active state, and after
+     * this call it is returned to the initial state.
+     */
+    default void end() {}
+
+    /**
+     * Indicates that this {@code Sink} does not wish to receive any more data.
+     *
+     * @implSpec The default implementation always returns false.
+     *
+     * @return true if cancellation is requested
+     */
+    default boolean cancellationRequested() {
+        return false;
+    }
+
+    /**
+     * Accepts an int value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept int values
+     */
+    default void accept(int value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * Accepts a long value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept long values
+     */
+    default void accept(long value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * Accepts a double value.
+     *
+     * @implSpec The default implementation throws IllegalStateException.
+     *
+     * @throws IllegalStateException if this sink does not accept double values
+     */
+    default void accept(double value) {
+        throw new IllegalStateException("called wrong accept method");
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Integer>}, re-abstracts
+     * {@code accept(int)}, and wires {@code accept(Integer)} to bridge to
+     * {@code accept(int)}.
+     */
+    interface OfInt extends Sink<Integer>, IntConsumer {
+        @Override
+        void accept(int value);
+
+        @Override
+        default void accept(Integer i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
+            accept(i.intValue());
+        }
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Long>}, re-abstracts
+     * {@code accept(long)}, and wires {@code accept(Long)} to bridge to
+     * {@code accept(long)}.
+     */
+    interface OfLong extends Sink<Long>, LongConsumer {
+        @Override
+        void accept(long value);
+
+        @Override
+        default void accept(Long i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfLong.accept(Long)");
+            accept(i.longValue());
+        }
+    }
+
+    /**
+     * {@code Sink} that implements {@code Sink<Double>}, re-abstracts
+     * {@code accept(double)}, and wires {@code accept(Double)} to bridge to
+     * {@code accept(double)}.
+     */
+    interface OfDouble extends Sink<Double>, DoubleConsumer {
+        @Override
+        void accept(double value);
+
+        @Override
+        default void accept(Double i) {
+            if (Tripwire.ENABLED)
+                Tripwire.trip(getClass(), "{0} calling Sink.OfDouble.accept(Double)");
+            accept(i.doubleValue());
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink<T>}.  The
+     * implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedReference(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfInt}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedInt<E_OUT> implements Sink.OfInt {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedInt(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfLong}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedLong<E_OUT> implements Sink.OfLong {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedLong(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+
+    /**
+     * Abstract {@code Sink} implementation designed for creating chains of
+     * sinks.  The {@code begin}, {@code end}, and
+     * {@code cancellationRequested} methods are wired to chain to the
+     * downstream {@code Sink}.  This implementation takes a downstream
+     * {@code Sink} of unknown input shape and produces a {@code Sink.OfDouble}.
+     * The implementation of the {@code accept()} method must call the correct
+     * {@code accept()} method on the downstream {@code Sink}.
+     */
+    static abstract class ChainedDouble<E_OUT> implements Sink.OfDouble {
+        protected final Sink<? super E_OUT> downstream;
+
+        public ChainedDouble(Sink<? super E_OUT> downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+
+        @Override
+        public boolean cancellationRequested() {
+            return downstream.cancellationRequested();
+        }
+    }
+}
diff --git a/java/util/stream/SliceOps.java b/java/util/stream/SliceOps.java
new file mode 100644
index 0000000..6a6f85e
--- /dev/null
+++ b/java/util/stream/SliceOps.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.IntFunction;
+
+/**
+ * Factory for instances of a short-circuiting stateful intermediate operations
+ * that produce subsequences of their input stream.
+ *
+ * @since 1.8
+ */
+final class SliceOps {
+
+    // No instances
+    private SliceOps() { }
+
+    /**
+     * Calculates the sliced size given the current size, number of elements
+     * skip, and the number of elements to limit.
+     *
+     * @param size the current size
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the sliced size
+     */
+    private static long calcSize(long size, long skip, long limit) {
+        return size >= 0 ? Math.max(-1, Math.min(size - skip, limit)) : -1;
+    }
+
+    /**
+     * Calculates the slice fence, which is one past the index of the slice
+     * range
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the slice fence.
+     */
+    private static long calcSliceFence(long skip, long limit) {
+        long sliceFence = limit >= 0 ? skip + limit : Long.MAX_VALUE;
+        // Check for overflow
+        return (sliceFence >= 0) ? sliceFence : Long.MAX_VALUE;
+    }
+
+    /**
+     * Creates a slice spliterator given a stream shape governing the
+     * spliterator type.  Requires that the underlying Spliterator
+     * be SUBSIZED.
+     */
+    @SuppressWarnings("unchecked")
+    private static <P_IN> Spliterator<P_IN> sliceSpliterator(StreamShape shape,
+                                                             Spliterator<P_IN> s,
+                                                             long skip, long limit) {
+        assert s.hasCharacteristics(Spliterator.SUBSIZED);
+        long sliceFence = calcSliceFence(skip, limit);
+        switch (shape) {
+            case REFERENCE:
+                return new StreamSpliterators
+                        .SliceSpliterator.OfRef<>(s, skip, sliceFence);
+            case INT_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfInt((Spliterator.OfInt) s, skip, sliceFence);
+            case LONG_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfLong((Spliterator.OfLong) s, skip, sliceFence);
+            case DOUBLE_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfDouble((Spliterator.OfDouble) s, skip, sliceFence);
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> IntFunction<T[]> castingArray() {
+        return size -> (T[]) new Object[size];
+    }
+
+    /**
+     * Appends a "slice" operation to the provided stream.  The slice operation
+     * may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param skip the number of elements to skip.  Must be >= 0.
+     * @param limit the maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
+                                        long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new ReferencePipeline.StatefulOp<T, T>(upstream, StreamShape.REFERENCE,
+                                                      flags(limit)) {
+            Spliterator<T> unorderedSkipLimitSpliterator(Spliterator<T> s,
+                                                         long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfRef<>(
+                            helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    // @@@ OOMEs will occur for LongStream.longs().filter(i -> true).limit(n)
+                    //     regardless of the value of n
+                    //     Need to adjust the target size of splitting for the
+                    //     SliceTask from say (size / k) to say min(size / k, 1 << 14)
+                    //     This will limit the size of the buffers created at the leaf nodes
+                    //     cancellation will be more aggressive cancelling later tasks
+                    //     if the target slice size has been reached from a given task,
+                    //     cancellation should also clear local results if any
+                    return new SliceTask<>(this, helper, spliterator, castingArray(), skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                              Spliterator<P_IN> spliterator,
+                                              IntFunction<T[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collect(helper, s, true, generator);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator<T> s =  unorderedSkipLimitSpliterator(
+                            helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collect(this, s, true, generator);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+                return new Sink.ChainedReference<T, T>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(T t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided IntStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream An IntStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static IntStream makeInt(AbstractPipeline<?, Integer, ?> upstream,
+                                    long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE,
+                                                   flags(limit)) {
+            Spliterator.OfInt unorderedSkipLimitSpliterator(
+                    Spliterator.OfInt s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                               Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfInt(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Integer[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Integer[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectInt(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfInt s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectInt(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(int t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided LongStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream A LongStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static LongStream makeLong(AbstractPipeline<?, Long, ?> upstream,
+                                      long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE,
+                                                 flags(limit)) {
+            Spliterator.OfLong unorderedSkipLimitSpliterator(
+                    Spliterator.OfLong s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                            Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfLong(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Long[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<Long[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectLong(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfLong s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectLong(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+                return new Sink.ChainedLong<Long>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(long t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    /**
+     * Appends a "slice" operation to the provided DoubleStream.  The slice
+     * operation may be may be skip-only, limit-only, or skip-and-limit.
+     *
+     * @param upstream A DoubleStream
+     * @param skip The number of elements to skip.  Must be >= 0.
+     * @param limit The maximum size of the resulting stream, or -1 if no limit
+     *        is to be imposed
+     */
+    public static DoubleStream makeDouble(AbstractPipeline<?, Double, ?> upstream,
+                                          long skip, long limit) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+
+        return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE,
+                                                     flags(limit)) {
+            Spliterator.OfDouble unorderedSkipLimitSpliterator(
+                    Spliterator.OfDouble s, long skip, long limit, long sizeIfKnown) {
+                if (skip <= sizeIfKnown) {
+                    // Use just the limit if the number of elements
+                    // to skip is <= the known pipeline size
+                    limit = limit >= 0 ? Math.min(limit, sizeIfKnown - skip) : sizeIfKnown - skip;
+                    skip = 0;
+                }
+                return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                              Spliterator<P_IN> spliterator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfDouble(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    return unorderedSkipLimitSpliterator(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, Double[]::new, skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                   Spliterator<P_IN> spliterator,
+                                                   IntFunction<Double[]> generator) {
+                long size = helper.exactOutputSizeIfKnown(spliterator);
+                if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // Because the pipeline is SIZED the slice spliterator
+                    // can be created from the source, this requires matching
+                    // to shape of the source, and is potentially more efficient
+                    // than creating the slice spliterator from the pipeline
+                    // wrapping spliterator
+                    Spliterator<P_IN> s = sliceSpliterator(helper.getSourceShape(), spliterator, skip, limit);
+                    return Nodes.collectDouble(helper, s, true);
+                } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    Spliterator.OfDouble s =  unorderedSkipLimitSpliterator(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip, limit, size);
+                    // Collect using this pipeline, which is empty and therefore
+                    // can be used with the pipeline wrapping spliterator
+                    // Note that we cannot create a slice spliterator from
+                    // the source spliterator if the pipeline is not SIZED
+                    return Nodes.collectDouble(this, s, true);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
+            }
+
+            @Override
+            // Android-changed: Make public, to match the method it's overriding.
+            public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
+                    long n = skip;
+                    long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+                    @Override
+                    public void begin(long size) {
+                        downstream.begin(calcSize(size, skip, m));
+                    }
+
+                    @Override
+                    public void accept(double t) {
+                        if (n == 0) {
+                            if (m > 0) {
+                                m--;
+                                downstream.accept(t);
+                            }
+                        }
+                        else {
+                            n--;
+                        }
+                    }
+
+                    @Override
+                    public boolean cancellationRequested() {
+                        return m == 0 || downstream.cancellationRequested();
+                    }
+                };
+            }
+        };
+    }
+
+    private static int flags(long limit) {
+        return StreamOpFlag.NOT_SIZED | ((limit != -1) ? StreamOpFlag.IS_SHORT_CIRCUIT : 0);
+    }
+
+    /**
+     * {@code ForkJoinTask} implementing slice computation.
+     *
+     * @param <P_IN> Input element type to the stream pipeline
+     * @param <P_OUT> Output element type from the stream pipeline
+     */
+    @SuppressWarnings("serial")
+    private static final class SliceTask<P_IN, P_OUT>
+            extends AbstractShortCircuitTask<P_IN, P_OUT, Node<P_OUT>, SliceTask<P_IN, P_OUT>> {
+        private final AbstractPipeline<P_OUT, P_OUT, ?> op;
+        private final IntFunction<P_OUT[]> generator;
+        private final long targetOffset, targetSize;
+        private long thisNodeSize;
+
+        private volatile boolean completed;
+
+        SliceTask(AbstractPipeline<P_OUT, P_OUT, ?> op,
+                  PipelineHelper<P_OUT> helper,
+                  Spliterator<P_IN> spliterator,
+                  IntFunction<P_OUT[]> generator,
+                  long offset, long size) {
+            super(helper, spliterator);
+            this.op = op;
+            this.generator = generator;
+            this.targetOffset = offset;
+            this.targetSize = size;
+        }
+
+        SliceTask(SliceTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+            this.generator = parent.generator;
+            this.targetOffset = parent.targetOffset;
+            this.targetSize = parent.targetSize;
+        }
+
+        @Override
+        protected SliceTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) {
+            return new SliceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected final Node<P_OUT> getEmptyResult() {
+            return Nodes.emptyNode(op.getOutputShape());
+        }
+
+        @Override
+        protected final Node<P_OUT> doLeaf() {
+            if (isRoot()) {
+                long sizeIfKnown = StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags)
+                                   ? op.exactOutputSizeIfKnown(spliterator)
+                                   : -1;
+                final Node.Builder<P_OUT> nb = op.makeNodeBuilder(sizeIfKnown, generator);
+                Sink<P_OUT> opSink = op.opWrapSink(helper.getStreamAndOpFlags(), nb);
+                helper.copyIntoWithCancel(helper.wrapSink(opSink), spliterator);
+                // There is no need to truncate since the op performs the
+                // skipping and limiting of elements
+                return nb.build();
+            }
+            else {
+                Node<P_OUT> node = helper.wrapAndCopyInto(helper.makeNodeBuilder(-1, generator),
+                                                          spliterator).build();
+                thisNodeSize = node.count();
+                completed = true;
+                spliterator = null;
+                return node;
+            }
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                Node<P_OUT> result;
+                thisNodeSize = leftChild.thisNodeSize + rightChild.thisNodeSize;
+                if (canceled) {
+                    thisNodeSize = 0;
+                    result = getEmptyResult();
+                }
+                else if (thisNodeSize == 0)
+                    result = getEmptyResult();
+                else if (leftChild.thisNodeSize == 0)
+                    result = rightChild.getLocalResult();
+                else {
+                    result = Nodes.conc(op.getOutputShape(),
+                                        leftChild.getLocalResult(), rightChild.getLocalResult());
+                }
+                setLocalResult(isRoot() ? doTruncate(result) : result);
+                completed = true;
+            }
+            if (targetSize >= 0
+                && !isRoot()
+                && isLeftCompleted(targetOffset + targetSize))
+                    cancelLaterNodes();
+
+            super.onCompletion(caller);
+        }
+
+        @Override
+        protected void cancel() {
+            super.cancel();
+            if (completed)
+                setLocalResult(getEmptyResult());
+        }
+
+        private Node<P_OUT> doTruncate(Node<P_OUT> input) {
+            long to = targetSize >= 0 ? Math.min(input.count(), targetOffset + targetSize) : thisNodeSize;
+            return input.truncate(targetOffset, to, generator);
+        }
+
+        /**
+         * Determine if the number of completed elements in this node and nodes
+         * to the left of this node is greater than or equal to the target size.
+         *
+         * @param target the target size
+         * @return true if the number of elements is greater than or equal to
+         *         the target size, otherwise false.
+         */
+        private boolean isLeftCompleted(long target) {
+            long size = completed ? thisNodeSize : completedSize(target);
+            if (size >= target)
+                return true;
+            for (SliceTask<P_IN, P_OUT> parent = getParent(), node = this;
+                 parent != null;
+                 node = parent, parent = parent.getParent()) {
+                if (node == parent.rightChild) {
+                    SliceTask<P_IN, P_OUT> left = parent.leftChild;
+                    if (left != null) {
+                        size += left.completedSize(target);
+                        if (size >= target)
+                            return true;
+                    }
+                }
+            }
+            return size >= target;
+        }
+
+        /**
+         * Compute the number of completed elements in this node.
+         * <p>
+         * Computation terminates if all nodes have been processed or the
+         * number of completed elements is greater than or equal to the target
+         * size.
+         *
+         * @param target the target size
+         * @return return the number of completed elements
+         */
+        private long completedSize(long target) {
+            if (completed)
+                return thisNodeSize;
+            else {
+                SliceTask<P_IN, P_OUT> left = leftChild;
+                SliceTask<P_IN, P_OUT> right = rightChild;
+                if (left == null || right == null) {
+                    // must be completed
+                    return thisNodeSize;
+                }
+                else {
+                    long leftSize = left.completedSize(target);
+                    return (leftSize >= target) ? leftSize : leftSize + right.completedSize(target);
+                }
+            }
+        }
+    }
+}
diff --git a/java/util/stream/SliceSpliteratorTest.java b/java/util/stream/SliceSpliteratorTest.java
new file mode 100644
index 0000000..7aa27bf
--- /dev/null
+++ b/java/util/stream/SliceSpliteratorTest.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Spliterator;
+
+import static java.util.stream.Collectors.toList;
+import static org.testng.Assert.assertEquals;
+
+/**
+ * @bug 8012987
+ */
+@Test
+public class SliceSpliteratorTest extends LoggingTestCase {
+
+    static class UnorderedContentAsserter<T> implements SpliteratorTestHelper.ContentAsserter<T> {
+        Collection<T> source;
+
+        UnorderedContentAsserter(Collection<T> source) {
+            this.source = source;
+        }
+
+        @Override
+        public void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+            if (isOrdered) {
+                assertEquals(actual, expected);
+            }
+            else {
+                assertEquals(actual.size(), expected.size());
+                assertTrue(source.containsAll(actual));
+            }
+        }
+    }
+
+    interface SliceTester {
+        void test(int size, int skip, int limit);
+    }
+
+    @DataProvider(name = "sliceSpliteratorDataProvider")
+    public static Object[][] sliceSpliteratorDataProvider() {
+        List<Object[]> data = new ArrayList<>();
+
+        // SIZED/SUBSIZED slice spliterator
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+
+                SpliteratorTestHelper.testSpliterator(() -> {
+                    Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
+
+                    return new StreamSpliterators.SliceSpliterator.OfRef<>(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfRef", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+
+                SpliteratorTestHelper.testIntSpliterator(() -> {
+                    Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
+
+                    return new StreamSpliterators.SliceSpliterator.OfInt(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfInt", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Long> source =  LongStream.range(0, size).boxed().collect(toList());
+
+                SpliteratorTestHelper.testLongSpliterator(() -> {
+                    Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
+
+                    return new StreamSpliterators.SliceSpliterator.OfLong(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Double> source =  LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
+
+                SpliteratorTestHelper.testDoubleSpliterator(() -> {
+                    Spliterator.OfDouble s = Arrays.spliterator(source.stream().mapToDouble(i->i).toArray());
+
+                    return new StreamSpliterators.SliceSpliterator.OfDouble(s, skip, limit);
+                });
+            };
+            data.add(new Object[]{"StreamSpliterators.SliceSpliterator.OfLong", r});
+        }
+
+
+        // Unordered slice spliterator
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+                final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testSpliterator(() -> {
+                    Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfRef", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Integer> source =  IntStream.range(0, size).boxed().collect(toList());
+                final UnorderedContentAsserter<Integer> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testIntSpliterator(() -> {
+                    Spliterator.OfInt s = Arrays.spliterator(source.stream().mapToInt(i->i).toArray());
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfInt(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfInt", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Long> source =  LongStream.range(0, size).boxed().collect(toList());
+                final UnorderedContentAsserter<Long> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testLongSpliterator(() -> {
+                    Spliterator.OfLong s = Arrays.spliterator(source.stream().mapToLong(i->i).toArray());
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfLong(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
+        }
+
+        {
+            SliceTester r = (size, skip, limit) -> {
+                final Collection<Double> source =  LongStream.range(0, size).asDoubleStream().boxed().collect(toList());
+                final UnorderedContentAsserter<Double> uca = new UnorderedContentAsserter<>(source);
+
+                SpliteratorTestHelper.testDoubleSpliterator(() -> {
+                    Spliterator.OfDouble s = Arrays.spliterator(LongStream.range(0, SIZE).asDoubleStream().toArray());
+
+                    return new StreamSpliterators.UnorderedSliceSpliterator.OfDouble(s, skip, limit);
+                }, uca);
+            };
+            data.add(new Object[]{"StreamSpliterators.UnorderedSliceSpliterator.OfLong", r});
+        }
+
+        return data.toArray(new Object[0][]);
+    }
+
+    static final int SIZE = 256;
+
+    static final int STEP = 32;
+
+    @Test(dataProvider = "sliceSpliteratorDataProvider")
+    public void testSliceSpliterator(String description, SliceTester r) {
+        setContext("size", SIZE);
+        for (int skip = 0; skip < SIZE; skip += STEP) {
+            setContext("skip", skip);
+            for (int limit = 0; limit < SIZE; limit += STEP) {
+                setContext("limit", skip);
+                r.test(SIZE, skip, limit);
+            }
+        }
+    }
+}
diff --git a/java/util/stream/SortedOps.java b/java/util/stream/SortedOps.java
new file mode 100644
index 0000000..592b609
--- /dev/null
+++ b/java/util/stream/SortedOps.java
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+
+/**
+ * Factory methods for transforming streams into sorted streams.
+ *
+ * @since 1.8
+ */
+final class SortedOps {
+
+    private SortedOps() { }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream) {
+        return new OfRef<>(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     * @param comparator the comparator to order elements by
+     */
+    static <T> Stream<T> makeRef(AbstractPipeline<?, T, ?> upstream,
+                                Comparator<? super T> comparator) {
+        return new OfRef<>(upstream, comparator);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> IntStream makeInt(AbstractPipeline<?, Integer, ?> upstream) {
+        return new OfInt(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> LongStream makeLong(AbstractPipeline<?, Long, ?> upstream) {
+        return new OfLong(upstream);
+    }
+
+    /**
+     * Appends a "sorted" operation to the provided stream.
+     *
+     * @param <T> the type of both input and output elements
+     * @param upstream a reference stream with element type T
+     */
+    static <T> DoubleStream makeDouble(AbstractPipeline<?, Double, ?> upstream) {
+        return new OfDouble(upstream);
+    }
+
+    /**
+     * Specialized subtype for sorting reference streams
+     */
+    private static final class OfRef<T> extends ReferencePipeline.StatefulOp<T, T> {
+        /**
+         * Comparator used for sorting
+         */
+        private final boolean isNaturalSort;
+        private final Comparator<? super T> comparator;
+
+        /**
+         * Sort using natural order of {@literal <T>} which must be
+         * {@code Comparable}.
+         */
+        OfRef(AbstractPipeline<?, T, ?> upstream) {
+            super(upstream, StreamShape.REFERENCE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+            this.isNaturalSort = true;
+            // Will throw CCE when we try to sort if T is not Comparable
+            @SuppressWarnings("unchecked")
+            Comparator<? super T> comp = (Comparator<? super T>) Comparator.naturalOrder();
+            this.comparator = comp;
+        }
+
+        /**
+         * Sort using the provided comparator.
+         *
+         * @param comparator The comparator to be used to evaluate ordering.
+         */
+        OfRef(AbstractPipeline<?, T, ?> upstream, Comparator<? super T> comparator) {
+            super(upstream, StreamShape.REFERENCE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.NOT_SORTED);
+            this.isNaturalSort = false;
+            this.comparator = Objects.requireNonNull(comparator);
+        }
+
+        @Override
+        public Sink<T> opWrapSink(int flags, Sink<T> sink) {
+            Objects.requireNonNull(sink);
+
+            // If the input is already naturally sorted and this operation
+            // also naturally sorted then this is a no-op
+            if (StreamOpFlag.SORTED.isKnown(flags) && isNaturalSort)
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedRefSortingSink<>(sink, comparator);
+            else
+                return new RefSortingSink<>(sink, comparator);
+        }
+
+        @Override
+        public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                 Spliterator<P_IN> spliterator,
+                                                 IntFunction<T[]> generator) {
+            // If the input is already naturally sorted and this operation
+            // naturally sorts then collect the output
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags()) && isNaturalSort) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                // @@@ Weak two-pass parallel implementation; parallel collect, parallel sort
+                T[] flattenedData = helper.evaluate(spliterator, true, generator).asArray(generator);
+                Arrays.parallelSort(flattenedData, comparator);
+                return Nodes.node(flattenedData);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting int streams.
+     */
+    private static final class OfInt extends IntPipeline.StatefulOp<Integer> {
+        OfInt(AbstractPipeline<?, Integer, ?> upstream) {
+            super(upstream, StreamShape.INT_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedIntSortingSink(sink);
+            else
+                return new IntSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                       Spliterator<P_IN> spliterator,
+                                                       IntFunction<Integer[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfInt n = (Node.OfInt) helper.evaluate(spliterator, true, generator);
+
+                int[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting long streams.
+     */
+    private static final class OfLong extends LongPipeline.StatefulOp<Long> {
+        OfLong(AbstractPipeline<?, Long, ?> upstream) {
+            super(upstream, StreamShape.LONG_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedLongSortingSink(sink);
+            else
+                return new LongSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                    Spliterator<P_IN> spliterator,
+                                                    IntFunction<Long[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfLong n = (Node.OfLong) helper.evaluate(spliterator, true, generator);
+
+                long[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Specialized subtype for sorting double streams.
+     */
+    private static final class OfDouble extends DoublePipeline.StatefulOp<Double> {
+        OfDouble(AbstractPipeline<?, Double, ?> upstream) {
+            super(upstream, StreamShape.DOUBLE_VALUE,
+                  StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+        }
+
+        @Override
+        public Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedDoubleSortingSink(sink);
+            else
+                return new DoubleSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<Double[]> generator) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.evaluate(spliterator, false, generator);
+            }
+            else {
+                Node.OfDouble n = (Node.OfDouble) helper.evaluate(spliterator, true, generator);
+
+                double[] content = n.asPrimitiveArray();
+                Arrays.parallelSort(content);
+
+                return Nodes.node(content);
+            }
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on reference streams.
+     *
+     * <p>
+     * Note: documentation below applies to reference and all primitive sinks.
+     * <p>
+     * Sorting sinks first accept all elements, buffering then into an array
+     * or a re-sizable data structure, if the size of the pipeline is known or
+     * unknown respectively.  At the end of the sink protocol those elements are
+     * sorted and then pushed downstream.
+     * This class records if {@link #cancellationRequested} is called.  If so it
+     * can be inferred that the source pushing source elements into the pipeline
+     * knows that the pipeline is short-circuiting.  In such cases sub-classes
+     * pushing elements downstream will preserve the short-circuiting protocol
+     * by calling {@code downstream.cancellationRequested()} and checking the
+     * result is {@code false} before an element is pushed.
+     * <p>
+     * Note that the above behaviour is an optimization for sorting with
+     * sequential streams.  It is not an error that more elements, than strictly
+     * required to produce a result, may flow through the pipeline.  This can
+     * occur, in general (not restricted to just sorting), for short-circuiting
+     * parallel pipelines.
+     */
+    private static abstract class AbstractRefSortingSink<T> extends Sink.ChainedReference<T, T> {
+        protected final Comparator<? super T> comparator;
+        // @@@ could be a lazy final value, if/when support is added
+        protected boolean cancellationWasRequested;
+
+        AbstractRefSortingSink(Sink<? super T> downstream, Comparator<? super T> comparator) {
+            super(downstream);
+            this.comparator = comparator;
+        }
+
+        /**
+         * Records is cancellation is requested so short-circuiting behaviour
+         * can be preserved when the sorted elements are pushed downstream.
+         *
+         * @return false, as this sink never short-circuits.
+         */
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED reference streams.
+     */
+    private static final class SizedRefSortingSink<T> extends AbstractRefSortingSink<T> {
+        private T[] array;
+        private int offset;
+
+        SizedRefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
+            super(sink, comparator);
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = (T[]) new Object[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset, comparator);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on reference streams.
+     */
+    private static final class RefSortingSink<T> extends AbstractRefSortingSink<T> {
+        private ArrayList<T> list;
+
+        RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
+            super(sink, comparator);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
+        }
+
+        @Override
+        public void end() {
+            list.sort(comparator);
+            downstream.begin(list.size());
+            if (!cancellationWasRequested) {
+                list.forEach(downstream::accept);
+            }
+            else {
+                for (T t : list) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(t);
+                }
+            }
+            downstream.end();
+            list = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            list.add(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on int streams.
+     */
+    private static abstract class AbstractIntSortingSink extends Sink.ChainedInt<Integer> {
+        protected boolean cancellationWasRequested;
+
+        AbstractIntSortingSink(Sink<? super Integer> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED int streams.
+     */
+    private static final class SizedIntSortingSink extends AbstractIntSortingSink {
+        private int[] array;
+        private int offset;
+
+        SizedIntSortingSink(Sink<? super Integer> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new int[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(int t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on int streams.
+     */
+    private static final class IntSortingSink extends AbstractIntSortingSink {
+        private SpinedBuffer.OfInt b;
+
+        IntSortingSink(Sink<? super Integer> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt();
+        }
+
+        @Override
+        public void end() {
+            int[] ints = b.asPrimitiveArray();
+            Arrays.sort(ints);
+            downstream.begin(ints.length);
+            if (!cancellationWasRequested) {
+                for (int anInt : ints)
+                    downstream.accept(anInt);
+            }
+            else {
+                for (int anInt : ints) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(anInt);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(int t) {
+            b.accept(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on long streams.
+     */
+    private static abstract class AbstractLongSortingSink extends Sink.ChainedLong<Long> {
+        protected boolean cancellationWasRequested;
+
+        AbstractLongSortingSink(Sink<? super Long> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED long streams.
+     */
+    private static final class SizedLongSortingSink extends AbstractLongSortingSink {
+        private long[] array;
+        private int offset;
+
+        SizedLongSortingSink(Sink<? super Long> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new long[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(long t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on long streams.
+     */
+    private static final class LongSortingSink extends AbstractLongSortingSink {
+        private SpinedBuffer.OfLong b;
+
+        LongSortingSink(Sink<? super Long> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfLong((int) size) : new SpinedBuffer.OfLong();
+        }
+
+        @Override
+        public void end() {
+            long[] longs = b.asPrimitiveArray();
+            Arrays.sort(longs);
+            downstream.begin(longs.length);
+            if (!cancellationWasRequested) {
+                for (long aLong : longs)
+                    downstream.accept(aLong);
+            }
+            else {
+                for (long aLong : longs) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(aLong);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(long t) {
+            b.accept(t);
+        }
+    }
+
+    /**
+     * Abstract {@link Sink} for implementing sort on long streams.
+     */
+    private static abstract class AbstractDoubleSortingSink extends Sink.ChainedDouble<Double> {
+        protected boolean cancellationWasRequested;
+
+        AbstractDoubleSortingSink(Sink<? super Double> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public final boolean cancellationRequested() {
+            cancellationWasRequested = true;
+            return false;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on SIZED double streams.
+     */
+    private static final class SizedDoubleSortingSink extends AbstractDoubleSortingSink {
+        private double[] array;
+        private int offset;
+
+        SizedDoubleSortingSink(Sink<? super Double> downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            array = new double[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, 0, offset);
+            downstream.begin(offset);
+            if (!cancellationWasRequested) {
+                for (int i = 0; i < offset; i++)
+                    downstream.accept(array[i]);
+            }
+            else {
+                for (int i = 0; i < offset && !downstream.cancellationRequested(); i++)
+                    downstream.accept(array[i]);
+            }
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(double t) {
+            array[offset++] = t;
+        }
+    }
+
+    /**
+     * {@link Sink} for implementing sort on double streams.
+     */
+    private static final class DoubleSortingSink extends AbstractDoubleSortingSink {
+        private SpinedBuffer.OfDouble b;
+
+        DoubleSortingSink(Sink<? super Double> sink) {
+            super(sink);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            b = (size > 0) ? new SpinedBuffer.OfDouble((int) size) : new SpinedBuffer.OfDouble();
+        }
+
+        @Override
+        public void end() {
+            double[] doubles = b.asPrimitiveArray();
+            Arrays.sort(doubles);
+            downstream.begin(doubles.length);
+            if (!cancellationWasRequested) {
+                for (double aDouble : doubles)
+                    downstream.accept(aDouble);
+            }
+            else {
+                for (double aDouble : doubles) {
+                    if (downstream.cancellationRequested()) break;
+                    downstream.accept(aDouble);
+                }
+            }
+            downstream.end();
+        }
+
+        @Override
+        public void accept(double t) {
+            b.accept(t);
+        }
+    }
+}
diff --git a/java/util/stream/SpinedBuffer.java b/java/util/stream/SpinedBuffer.java
new file mode 100644
index 0000000..d21518a
--- /dev/null
+++ b/java/util/stream/SpinedBuffer.java
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntFunction;
+import java.util.function.LongConsumer;
+
+/**
+ * An ordered collection of elements.  Elements can be added, but not removed.
+ * Goes through a building phase, during which elements can be added, and a
+ * traversal phase, during which elements can be traversed in order but no
+ * further modifications are possible.
+ *
+ * <p> One or more arrays are used to store elements. The use of a multiple
+ * arrays has better performance characteristics than a single array used by
+ * {@link ArrayList}, as when the capacity of the list needs to be increased
+ * no copying of elements is required.  This is usually beneficial in the case
+ * where the results will be traversed a small number of times.
+ *
+ * @param <E> the type of elements in this list
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public class SpinedBuffer<E>
+        extends AbstractSpinedBuffer
+        implements Consumer<E>, Iterable<E> {
+
+    /*
+     * We optimistically hope that all the data will fit into the first chunk,
+     * so we try to avoid inflating the spine[] and priorElementCount[] arrays
+     * prematurely.  So methods must be prepared to deal with these arrays being
+     * null.  If spine is non-null, then spineIndex points to the current chunk
+     * within the spine, otherwise it is zero.  The spine and priorElementCount
+     * arrays are always the same size, and for any i <= spineIndex,
+     * priorElementCount[i] is the sum of the sizes of all the prior chunks.
+     *
+     * The curChunk pointer is always valid.  The elementIndex is the index of
+     * the next element to be written in curChunk; this may be past the end of
+     * curChunk so we have to check before writing. When we inflate the spine
+     * array, curChunk becomes the first element in it.  When we clear the
+     * buffer, we discard all chunks except the first one, which we clear,
+     * restoring it to the initial single-chunk state.
+     */
+
+    /**
+     * Chunk that we're currently writing into; may or may not be aliased with
+     * the first element of the spine.
+     */
+    protected E[] curChunk;
+
+    /**
+     * All chunks, or null if there is only one chunk.
+     */
+    protected E[][] spine;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public SpinedBuffer(int initialCapacity) {
+        super(initialCapacity);
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of sixteen.
+     */
+    @SuppressWarnings("unchecked")
+    // Android-changed: Made public for CTS tests only.
+    public SpinedBuffer() {
+        super();
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Returns the current capacity of the buffer
+     */
+    protected long capacity() {
+        return (spineIndex == 0)
+               ? curChunk.length
+               : priorElementCount[spineIndex] + spine[spineIndex].length;
+    }
+
+    @SuppressWarnings("unchecked")
+    private void inflateSpine() {
+        if (spine == null) {
+            spine = (E[][]) new Object[MIN_SPINE_SIZE][];
+            priorElementCount = new long[MIN_SPINE_SIZE];
+            spine[0] = curChunk;
+        }
+    }
+
+    /**
+     * Ensure that the buffer has at least capacity to hold the target size
+     */
+    @SuppressWarnings("unchecked")
+    protected final void ensureCapacity(long targetSize) {
+        long capacity = capacity();
+        if (targetSize > capacity) {
+            inflateSpine();
+            for (int i=spineIndex+1; targetSize > capacity; i++) {
+                if (i >= spine.length) {
+                    int newSpineSize = spine.length * 2;
+                    spine = Arrays.copyOf(spine, newSpineSize);
+                    priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                }
+                int nextChunkSize = chunkSize(i);
+                spine[i] = (E[]) new Object[nextChunkSize];
+                priorElementCount[i] = priorElementCount[i-1] + spine[i-1].length;
+                capacity += nextChunkSize;
+            }
+        }
+    }
+
+    /**
+     * Force the buffer to increase its capacity.
+     */
+    protected void increaseCapacity() {
+        ensureCapacity(capacity() + 1);
+    }
+
+    /**
+     * Retrieve the element at the specified index.
+     */
+    public E get(long index) {
+        // @@@ can further optimize by caching last seen spineIndex,
+        // which is going to be right most of the time
+
+        // Casts to int are safe since the spine array index is the index minus
+        // the prior element count from the current spine
+        if (spineIndex == 0) {
+            if (index < elementIndex)
+                return curChunk[((int) index)];
+            else
+                throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        if (index >= count())
+            throw new IndexOutOfBoundsException(Long.toString(index));
+
+        for (int j=0; j <= spineIndex; j++)
+            if (index < priorElementCount[j] + spine[j].length)
+                return spine[j][((int) (index - priorElementCount[j]))];
+
+        throw new IndexOutOfBoundsException(Long.toString(index));
+    }
+
+    /**
+     * Copy the elements, starting at the specified offset, into the specified
+     * array.
+     */
+    public void copyInto(E[] array, int offset) {
+        long finalOffset = offset + count();
+        if (finalOffset > array.length || finalOffset < offset) {
+            throw new IndexOutOfBoundsException("does not fit");
+        }
+
+        if (spineIndex == 0)
+            System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        else {
+            // full chunks
+            for (int i=0; i < spineIndex; i++) {
+                System.arraycopy(spine[i], 0, array, offset, spine[i].length);
+                offset += spine[i].length;
+            }
+            if (elementIndex > 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        }
+    }
+
+    /**
+     * Create a new array using the specified array factory, and copy the
+     * elements into it.
+     */
+    public E[] asArray(IntFunction<E[]> arrayFactory) {
+        long size = count();
+        if (size >= Nodes.MAX_ARRAY_SIZE)
+            throw new IllegalArgumentException(Nodes.BAD_SIZE);
+        E[] result = arrayFactory.apply((int) size);
+        copyInto(result, 0);
+        return result;
+    }
+
+    @Override
+    public void clear() {
+        if (spine != null) {
+            curChunk = spine[0];
+            for (int i=0; i<curChunk.length; i++)
+                curChunk[i] = null;
+            spine = null;
+            priorElementCount = null;
+        }
+        else {
+            for (int i=0; i<elementIndex; i++)
+                curChunk[i] = null;
+        }
+        elementIndex = 0;
+        spineIndex = 0;
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    @Override
+    public void forEach(Consumer<? super E> consumer) {
+        // completed chunks, if any
+        for (int j = 0; j < spineIndex; j++)
+            for (E t : spine[j])
+                consumer.accept(t);
+
+        // current chunk
+        for (int i=0; i<elementIndex; i++)
+            consumer.accept(curChunk[i]);
+    }
+
+    @Override
+    public void accept(E e) {
+        if (elementIndex == curChunk.length) {
+            inflateSpine();
+            if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                increaseCapacity();
+            elementIndex = 0;
+            ++spineIndex;
+            curChunk = spine[spineIndex];
+        }
+        curChunk[elementIndex++] = e;
+    }
+
+    @Override
+    public String toString() {
+        List<E> list = new ArrayList<>();
+        forEach(list::add);
+        return "SpinedBuffer:" + list.toString();
+    }
+
+    private static final int SPLITERATOR_CHARACTERISTICS
+            = Spliterator.SIZED | Spliterator.ORDERED | Spliterator.SUBSIZED;
+
+    /**
+     * Return a {@link Spliterator} describing the contents of the buffer.
+     */
+    public Spliterator<E> spliterator() {
+        class Splitr implements Spliterator<E> {
+            // The current spine index
+            int splSpineIndex;
+
+            // Last spine index
+            final int lastSpineIndex;
+
+            // The current element index into the current spine
+            int splElementIndex;
+
+            // Last spine's last element index + 1
+            final int lastSpineElementFence;
+
+            // When splSpineIndex >= lastSpineIndex and
+            // splElementIndex >= lastSpineElementFence then
+            // this spliterator is fully traversed
+            // tryAdvance can set splSpineIndex > spineIndex if the last spine is full
+
+            // The current spine array
+            E[] splChunk;
+
+            Splitr(int firstSpineIndex, int lastSpineIndex,
+                   int firstSpineElementIndex, int lastSpineElementFence) {
+                this.splSpineIndex = firstSpineIndex;
+                this.lastSpineIndex = lastSpineIndex;
+                this.splElementIndex = firstSpineElementIndex;
+                this.lastSpineElementFence = lastSpineElementFence;
+                assert spine != null || firstSpineIndex == 0 && lastSpineIndex == 0;
+                splChunk = (spine == null) ? curChunk : spine[firstSpineIndex];
+            }
+
+            @Override
+            public long estimateSize() {
+                return (splSpineIndex == lastSpineIndex)
+                       ? (long) lastSpineElementFence - splElementIndex
+                       : // # of elements prior to end -
+                       priorElementCount[lastSpineIndex] + lastSpineElementFence -
+                       // # of elements prior to current
+                       priorElementCount[splSpineIndex] - splElementIndex;
+            }
+
+            @Override
+            public int characteristics() {
+                return SPLITERATOR_CHARACTERISTICS;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super E> consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    consumer.accept(splChunk[splElementIndex++]);
+
+                    if (splElementIndex == splChunk.length) {
+                        splElementIndex = 0;
+                        ++splSpineIndex;
+                        if (spine != null && splSpineIndex <= lastSpineIndex)
+                            splChunk = spine[splSpineIndex];
+                    }
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super E> consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    int i = splElementIndex;
+                    // completed chunks, if any
+                    for (int sp = splSpineIndex; sp < lastSpineIndex; sp++) {
+                        E[] chunk = spine[sp];
+                        for (; i < chunk.length; i++) {
+                            consumer.accept(chunk[i]);
+                        }
+                        i = 0;
+                    }
+                    // last (or current uncompleted) chunk
+                    E[] chunk = (splSpineIndex == lastSpineIndex) ? splChunk : spine[lastSpineIndex];
+                    int hElementIndex = lastSpineElementFence;
+                    for (; i < hElementIndex; i++) {
+                        consumer.accept(chunk[i]);
+                    }
+                    // mark consumed
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = lastSpineElementFence;
+                }
+            }
+
+            @Override
+            public Spliterator<E> trySplit() {
+                if (splSpineIndex < lastSpineIndex) {
+                    // split just before last chunk (if it is full this means 50:50 split)
+                    Spliterator<E> ret = new Splitr(splSpineIndex, lastSpineIndex - 1,
+                                                    splElementIndex, spine[lastSpineIndex-1].length);
+                    // position to start of last chunk
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = 0;
+                    splChunk = spine[splSpineIndex];
+                    return ret;
+                }
+                else if (splSpineIndex == lastSpineIndex) {
+                    int t = (lastSpineElementFence - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        Spliterator<E> ret = Arrays.spliterator(splChunk, splElementIndex, splElementIndex + t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        }
+        return new Splitr(0, spineIndex, 0, elementIndex);
+    }
+
+    /**
+     * An ordered collection of primitive values.  Elements can be added, but
+     * not removed. Goes through a building phase, during which elements can be
+     * added, and a traversal phase, during which elements can be traversed in
+     * order but no further modifications are possible.
+     *
+     * <p> One or more arrays are used to store elements. The use of a multiple
+     * arrays has better performance characteristics than a single array used by
+     * {@link ArrayList}, as when the capacity of the list needs to be increased
+     * no copying of elements is required.  This is usually beneficial in the case
+     * where the results will be traversed a small number of times.
+     *
+     * @param <E> the wrapper type for this primitive type
+     * @param <T_ARR> the array type for this primitive type
+     * @param <T_CONS> the Consumer type for this primitive type
+     */
+    abstract static class OfPrimitive<E, T_ARR, T_CONS>
+            extends AbstractSpinedBuffer implements Iterable<E> {
+
+        /*
+         * We optimistically hope that all the data will fit into the first chunk,
+         * so we try to avoid inflating the spine[] and priorElementCount[] arrays
+         * prematurely.  So methods must be prepared to deal with these arrays being
+         * null.  If spine is non-null, then spineIndex points to the current chunk
+         * within the spine, otherwise it is zero.  The spine and priorElementCount
+         * arrays are always the same size, and for any i <= spineIndex,
+         * priorElementCount[i] is the sum of the sizes of all the prior chunks.
+         *
+         * The curChunk pointer is always valid.  The elementIndex is the index of
+         * the next element to be written in curChunk; this may be past the end of
+         * curChunk so we have to check before writing. When we inflate the spine
+         * array, curChunk becomes the first element in it.  When we clear the
+         * buffer, we discard all chunks except the first one, which we clear,
+         * restoring it to the initial single-chunk state.
+         */
+
+        // The chunk we're currently writing into
+        T_ARR curChunk;
+
+        // All chunks, or null if there is only one chunk
+        T_ARR[] spine;
+
+        /**
+         * Constructs an empty list with the specified initial capacity.
+         *
+         * @param  initialCapacity  the initial capacity of the list
+         * @throws IllegalArgumentException if the specified initial capacity
+         *         is negative
+         */
+        OfPrimitive(int initialCapacity) {
+            super(initialCapacity);
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        /**
+         * Constructs an empty list with an initial capacity of sixteen.
+         */
+        OfPrimitive() {
+            super();
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        @Override
+        public abstract Iterator<E> iterator();
+
+        @Override
+        public abstract void forEach(Consumer<? super E> consumer);
+
+        /** Create a new array-of-array of the proper type and size */
+        protected abstract T_ARR[] newArrayArray(int size);
+
+        /** Create a new array of the proper type and size */
+        public abstract T_ARR newArray(int size);
+
+        /** Get the length of an array */
+        protected abstract int arrayLength(T_ARR array);
+
+        /** Iterate an array with the provided consumer */
+        protected abstract void arrayForEach(T_ARR array, int from, int to,
+                                             T_CONS consumer);
+
+        protected long capacity() {
+            return (spineIndex == 0)
+                   ? arrayLength(curChunk)
+                   : priorElementCount[spineIndex] + arrayLength(spine[spineIndex]);
+        }
+
+        private void inflateSpine() {
+            if (spine == null) {
+                spine = newArrayArray(MIN_SPINE_SIZE);
+                priorElementCount = new long[MIN_SPINE_SIZE];
+                spine[0] = curChunk;
+            }
+        }
+
+        protected final void ensureCapacity(long targetSize) {
+            long capacity = capacity();
+            if (targetSize > capacity) {
+                inflateSpine();
+                for (int i=spineIndex+1; targetSize > capacity; i++) {
+                    if (i >= spine.length) {
+                        int newSpineSize = spine.length * 2;
+                        spine = Arrays.copyOf(spine, newSpineSize);
+                        priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                    }
+                    int nextChunkSize = chunkSize(i);
+                    spine[i] = newArray(nextChunkSize);
+                    priorElementCount[i] = priorElementCount[i-1] + arrayLength(spine[i - 1]);
+                    capacity += nextChunkSize;
+                }
+            }
+        }
+
+        protected void increaseCapacity() {
+            ensureCapacity(capacity() + 1);
+        }
+
+        protected int chunkFor(long index) {
+            if (spineIndex == 0) {
+                if (index < elementIndex)
+                    return 0;
+                else
+                    throw new IndexOutOfBoundsException(Long.toString(index));
+            }
+
+            if (index >= count())
+                throw new IndexOutOfBoundsException(Long.toString(index));
+
+            for (int j=0; j <= spineIndex; j++)
+                if (index < priorElementCount[j] + arrayLength(spine[j]))
+                    return j;
+
+            throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        public void copyInto(T_ARR array, int offset) {
+            long finalOffset = offset + count();
+            if (finalOffset > arrayLength(array) || finalOffset < offset) {
+                throw new IndexOutOfBoundsException("does not fit");
+            }
+
+            if (spineIndex == 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            else {
+                // full chunks
+                for (int i=0; i < spineIndex; i++) {
+                    System.arraycopy(spine[i], 0, array, offset, arrayLength(spine[i]));
+                    offset += arrayLength(spine[i]);
+                }
+                if (elementIndex > 0)
+                    System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            }
+        }
+
+        public T_ARR asPrimitiveArray() {
+            long size = count();
+            if (size >= Nodes.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException(Nodes.BAD_SIZE);
+            T_ARR result = newArray((int) size);
+            copyInto(result, 0);
+            return result;
+        }
+
+        protected void preAccept() {
+            if (elementIndex == arrayLength(curChunk)) {
+                inflateSpine();
+                if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                    increaseCapacity();
+                elementIndex = 0;
+                ++spineIndex;
+                curChunk = spine[spineIndex];
+            }
+        }
+
+        public void clear() {
+            if (spine != null) {
+                curChunk = spine[0];
+                spine = null;
+                priorElementCount = null;
+            }
+            elementIndex = 0;
+            spineIndex = 0;
+        }
+
+        @SuppressWarnings("overloads")
+        public void forEach(T_CONS consumer) {
+            // completed chunks, if any
+            for (int j = 0; j < spineIndex; j++)
+                arrayForEach(spine[j], 0, arrayLength(spine[j]), consumer);
+
+            // current chunk
+            arrayForEach(curChunk, 0, elementIndex, consumer);
+        }
+
+        abstract class BaseSpliterator<T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>>
+                implements Spliterator.OfPrimitive<E, T_CONS, T_SPLITR> {
+            // The current spine index
+            int splSpineIndex;
+
+            // Last spine index
+            final int lastSpineIndex;
+
+            // The current element index into the current spine
+            int splElementIndex;
+
+            // Last spine's last element index + 1
+            final int lastSpineElementFence;
+
+            // When splSpineIndex >= lastSpineIndex and
+            // splElementIndex >= lastSpineElementFence then
+            // this spliterator is fully traversed
+            // tryAdvance can set splSpineIndex > spineIndex if the last spine is full
+
+            // The current spine array
+            T_ARR splChunk;
+
+            BaseSpliterator(int firstSpineIndex, int lastSpineIndex,
+                            int firstSpineElementIndex, int lastSpineElementFence) {
+                this.splSpineIndex = firstSpineIndex;
+                this.lastSpineIndex = lastSpineIndex;
+                this.splElementIndex = firstSpineElementIndex;
+                this.lastSpineElementFence = lastSpineElementFence;
+                assert spine != null || firstSpineIndex == 0 && lastSpineIndex == 0;
+                splChunk = (spine == null) ? curChunk : spine[firstSpineIndex];
+            }
+
+            abstract T_SPLITR newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                             int firstSpineElementIndex, int lastSpineElementFence);
+
+            abstract void arrayForOne(T_ARR array, int index, T_CONS consumer);
+
+            abstract T_SPLITR arraySpliterator(T_ARR array, int offset, int len);
+
+            @Override
+            public long estimateSize() {
+                return (splSpineIndex == lastSpineIndex)
+                       ? (long) lastSpineElementFence - splElementIndex
+                       : // # of elements prior to end -
+                       priorElementCount[lastSpineIndex] + lastSpineElementFence -
+                       // # of elements prior to current
+                       priorElementCount[splSpineIndex] - splElementIndex;
+            }
+
+            @Override
+            public int characteristics() {
+                return SPLITERATOR_CHARACTERISTICS;
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    arrayForOne(splChunk, splElementIndex++, consumer);
+
+                    if (splElementIndex == arrayLength(splChunk)) {
+                        splElementIndex = 0;
+                        ++splSpineIndex;
+                        if (spine != null && splSpineIndex <= lastSpineIndex)
+                            splChunk = spine[splSpineIndex];
+                    }
+                    return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                Objects.requireNonNull(consumer);
+
+                if (splSpineIndex < lastSpineIndex
+                    || (splSpineIndex == lastSpineIndex && splElementIndex < lastSpineElementFence)) {
+                    int i = splElementIndex;
+                    // completed chunks, if any
+                    for (int sp = splSpineIndex; sp < lastSpineIndex; sp++) {
+                        T_ARR chunk = spine[sp];
+                        arrayForEach(chunk, i, arrayLength(chunk), consumer);
+                        i = 0;
+                    }
+                    // last (or current uncompleted) chunk
+                    T_ARR chunk = (splSpineIndex == lastSpineIndex) ? splChunk : spine[lastSpineIndex];
+                    arrayForEach(chunk, i, lastSpineElementFence, consumer);
+                    // mark consumed
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = lastSpineElementFence;
+                }
+            }
+
+            @Override
+            public T_SPLITR trySplit() {
+                if (splSpineIndex < lastSpineIndex) {
+                    // split just before last chunk (if it is full this means 50:50 split)
+                    T_SPLITR ret = newSpliterator(splSpineIndex, lastSpineIndex - 1,
+                                                  splElementIndex, arrayLength(spine[lastSpineIndex - 1]));
+                    // position us to start of last chunk
+                    splSpineIndex = lastSpineIndex;
+                    splElementIndex = 0;
+                    splChunk = spine[splSpineIndex];
+                    return ret;
+                }
+                else if (splSpineIndex == lastSpineIndex) {
+                    int t = (lastSpineElementFence - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        T_SPLITR ret = arraySpliterator(splChunk, splElementIndex, t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    return null;
+                }
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code int} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfInt extends SpinedBuffer.OfPrimitive<Integer, int[], IntConsumer>
+            implements IntConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfInt() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfInt(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Integer> consumer) {
+            if (consumer instanceof IntConsumer) {
+                forEach((IntConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfInt.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected int[][] newArrayArray(int size) {
+            return new int[size][];
+        }
+
+        @Override
+        public int[] newArray(int size) {
+            return new int[size];
+        }
+
+        @Override
+        protected int arrayLength(int[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(int[] array,
+                                    int from, int to,
+                                    IntConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(int i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public int get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfInt iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+        public Spliterator.OfInt spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfInt>
+                    implements Spliterator.OfInt {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(int[] array, int index, IntConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfInt arraySpliterator(int[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            int[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                int[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code long} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfLong extends SpinedBuffer.OfPrimitive<Long, long[], LongConsumer>
+            implements LongConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfLong() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfLong(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Long> consumer) {
+            if (consumer instanceof LongConsumer) {
+                forEach((LongConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfLong.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected long[][] newArrayArray(int size) {
+            return new long[size][];
+        }
+
+        @Override
+        public long[] newArray(int size) {
+            return new long[size];
+        }
+
+        @Override
+        protected int arrayLength(long[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(long[] array,
+                                    int from, int to,
+                                    LongConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(long i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public long get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfLong iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+
+        public Spliterator.OfLong spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfLong>
+                    implements Spliterator.OfLong {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(long[] array, int index, LongConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfLong arraySpliterator(long[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            long[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                long[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+
+    /**
+     * An ordered collection of {@code double} values.
+     * @hide Visible for CTS testing only (OpenJDK8 tests).
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static class OfDouble
+            extends SpinedBuffer.OfPrimitive<Double, double[], DoubleConsumer>
+            implements DoubleConsumer {
+        // Android-changed: Made public for CTS tests only.
+        public OfDouble() { }
+
+        // Android-changed: Made public for CTS tests only.
+        public OfDouble(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        public void forEach(Consumer<? super Double> consumer) {
+            if (consumer instanceof DoubleConsumer) {
+                forEach((DoubleConsumer) consumer);
+            }
+            else {
+                if (Tripwire.ENABLED)
+                    Tripwire.trip(getClass(), "{0} calling SpinedBuffer.OfDouble.forEach(Consumer)");
+                spliterator().forEachRemaining(consumer);
+            }
+        }
+
+        @Override
+        protected double[][] newArrayArray(int size) {
+            return new double[size][];
+        }
+
+        @Override
+        public double[] newArray(int size) {
+            return new double[size];
+        }
+
+        @Override
+        protected int arrayLength(double[] array) {
+            return array.length;
+        }
+
+        @Override
+        protected void arrayForEach(double[] array,
+                                    int from, int to,
+                                    DoubleConsumer consumer) {
+            for (int i = from; i < to; i++)
+                consumer.accept(array[i]);
+        }
+
+        @Override
+        public void accept(double i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public double get(long index) {
+            // Casts to int are safe since the spine array index is the index minus
+            // the prior element count from the current spine
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index - priorElementCount[ch])];
+        }
+
+        @Override
+        public PrimitiveIterator.OfDouble iterator() {
+            return Spliterators.iterator(spliterator());
+        }
+
+        public Spliterator.OfDouble spliterator() {
+            class Splitr extends BaseSpliterator<Spliterator.OfDouble>
+                    implements Spliterator.OfDouble {
+                Splitr(int firstSpineIndex, int lastSpineIndex,
+                       int firstSpineElementIndex, int lastSpineElementFence) {
+                    super(firstSpineIndex, lastSpineIndex,
+                          firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                Splitr newSpliterator(int firstSpineIndex, int lastSpineIndex,
+                                      int firstSpineElementIndex, int lastSpineElementFence) {
+                    return new Splitr(firstSpineIndex, lastSpineIndex,
+                                      firstSpineElementIndex, lastSpineElementFence);
+                }
+
+                @Override
+                void arrayForOne(double[] array, int index, DoubleConsumer consumer) {
+                    consumer.accept(array[index]);
+                }
+
+                @Override
+                Spliterator.OfDouble arraySpliterator(double[] array, int offset, int len) {
+                    return Arrays.spliterator(array, offset, offset+len);
+                }
+            }
+            return new Splitr(0, spineIndex, 0, elementIndex);
+        }
+
+        @Override
+        public String toString() {
+            double[] array = asPrimitiveArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                double[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...",
+                                     getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+}
+
diff --git a/java/util/stream/SpinedBufferTest.java b/java/util/stream/SpinedBufferTest.java
new file mode 100644
index 0000000..26a62ca
--- /dev/null
+++ b/java/util/stream/SpinedBufferTest.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+@Test
+public class SpinedBufferTest {
+
+    // Create sizes around the boundary of spines
+    static List<Integer> sizes;
+    static {
+        try {
+            sizes = IntStream.range(0, 15)
+                             .map(i -> 1 << i)
+                             .flatMap(i -> Arrays.stream(new int[] { i-2, i-1, i, i+1, i+2 }))
+                             .filter(i -> i >= 0)
+                             .boxed()
+                             .distinct()
+                             .collect(Collectors.toList());
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static final int TEST_SIZE = 5000;
+
+    // SpinedBuffer
+
+    @DataProvider(name = "SpinedBuffer")
+    public Object[][] createSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            int[] array = IntStream.range(0, size).toArray();
+
+            SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size / 2);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+
+            sb = new SpinedBuffer<>(size * 2);
+            Arrays.stream(array).boxed().forEach(sb);
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "SpinedBuffer")
+    public void testSpliterator(int[] array, SpinedBuffer<Integer> sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "SpinedBuffer", groups = { "serialization-hostile" })
+    public void testLastSplit(int[] array, SpinedBuffer<Integer> sb) {
+        Spliterator<Integer> spliterator = sb.spliterator();
+        Spliterator<Integer> split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Integer> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining(contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Integer> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testSpinedBuffer() {
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+        for (int i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        Iterator<Integer> it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.next());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), (Integer) i, Integer.toString(i));
+
+        list2.clear();
+        sb.forEach(list2::add);
+        assertEquals(list1, list2);
+        Integer[] array = sb.asArray(LambdaTestHelpers.integerArrayGenerator);
+        list2.clear();
+        for (Integer i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // IntSpinedBuffer
+
+    @DataProvider(name = "IntSpinedBuffer")
+    public Object[][] createIntSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            int[] array = IntStream.range(0, size).toArray();
+            SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "IntSpinedBuffer")
+    public void testIntSpliterator(int[] array, SpinedBuffer.OfInt sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testIntSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "IntSpinedBuffer", groups = { "serialization-hostile" })
+    public void testIntLastSplit(int[] array, SpinedBuffer.OfInt sb) {
+        Spliterator.OfInt spliterator = sb.spliterator();
+        Spliterator.OfInt split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Integer> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((IntConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Integer> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testIntSpinedBuffer() {
+        List<Integer> list1 = new ArrayList<>();
+        List<Integer> list2 = new ArrayList<>();
+        SpinedBuffer.OfInt sb = new SpinedBuffer.OfInt();
+        for (int i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        PrimitiveIterator.OfInt it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextInt());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), i, Integer.toString(i));
+
+        list2.clear();
+        sb.forEach((int i) -> list2.add(i));
+        assertEquals(list1, list2);
+        int[] array = sb.asPrimitiveArray();
+        list2.clear();
+        for (int i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // LongSpinedBuffer
+
+    @DataProvider(name = "LongSpinedBuffer")
+    public Object[][] createLongSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            long[] array = LongStream.range(0, size).toArray();
+            SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "LongSpinedBuffer")
+    public void testLongSpliterator(long[] array, SpinedBuffer.OfLong sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testLongSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "LongSpinedBuffer", groups = { "serialization-hostile" })
+    public void testLongLastSplit(long[] array, SpinedBuffer.OfLong sb) {
+        Spliterator.OfLong spliterator = sb.spliterator();
+        Spliterator.OfLong split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Long> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((LongConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Long> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testLongSpinedBuffer() {
+        List<Long> list1 = new ArrayList<>();
+        List<Long> list2 = new ArrayList<>();
+        SpinedBuffer.OfLong sb = new SpinedBuffer.OfLong();
+        for (long i = 0; i < TEST_SIZE; i++) {
+            list1.add(i);
+            sb.accept(i);
+        }
+        PrimitiveIterator.OfLong it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextLong());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), i, Long.toString(i));
+
+        list2.clear();
+        sb.forEach((long i) -> list2.add(i));
+        assertEquals(list1, list2);
+        long[] array = sb.asPrimitiveArray();
+        list2.clear();
+        for (long i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+
+    // DoubleSpinedBuffer
+
+    @DataProvider(name = "DoubleSpinedBuffer")
+    public Object[][] createDoubleSpinedBuffer() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : sizes) {
+            // @@@ replace with double range when implemented
+            double[] array = LongStream.range(0, size).asDoubleStream().toArray();
+            SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+            Arrays.stream(array).forEach(sb);
+
+            params.add(new Object[]{array, sb});
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    @Test(dataProvider = "DoubleSpinedBuffer")
+    public void testDoubleSpliterator(double[] array, SpinedBuffer.OfDouble sb) {
+        assertEquals(sb.count(), array.length);
+        assertEquals(sb.count(), sb.spliterator().getExactSizeIfKnown());
+
+        SpliteratorTestHelper.testDoubleSpliterator(sb::spliterator);
+    }
+
+    @Test(dataProvider = "DoubleSpinedBuffer", groups = { "serialization-hostile" })
+    public void testLongLastSplit(double[] array, SpinedBuffer.OfDouble sb) {
+        Spliterator.OfDouble spliterator = sb.spliterator();
+        Spliterator.OfDouble split = spliterator.trySplit();
+        long splitSizes = (split == null) ? 0 : split.getExactSizeIfKnown();
+        long lastSplitSize = spliterator.getExactSizeIfKnown();
+        splitSizes += lastSplitSize;
+
+        assertEquals(splitSizes, array.length);
+
+        List<Double> contentOfLastSplit = new ArrayList<>();
+        spliterator.forEachRemaining((DoubleConsumer) contentOfLastSplit::add);
+
+        assertEquals(contentOfLastSplit.size(), lastSplitSize);
+
+        List<Double> end = Arrays.stream(array)
+                .boxed()
+                .skip(array.length - lastSplitSize)
+                .collect(Collectors.toList());
+        assertEquals(contentOfLastSplit, end);
+    }
+
+    @Test(groups = { "serialization-hostile" })
+    public void testDoubleSpinedBuffer() {
+        List<Double> list1 = new ArrayList<>();
+        List<Double> list2 = new ArrayList<>();
+        SpinedBuffer.OfDouble sb = new SpinedBuffer.OfDouble();
+        for (long i = 0; i < TEST_SIZE; i++) {
+            list1.add((double) i);
+            sb.accept((double) i);
+        }
+        PrimitiveIterator.OfDouble it = sb.iterator();
+        for (int i = 0; i < TEST_SIZE; i++)
+            list2.add(it.nextDouble());
+        assertFalse(it.hasNext());
+        assertEquals(list1, list2);
+
+        for (int i = 0; i < TEST_SIZE; i++)
+            assertEquals(sb.get(i), (double) i, Double.toString(i));
+
+        list2.clear();
+        sb.forEach((double i) -> list2.add(i));
+        assertEquals(list1, list2);
+        double[] array = sb.asPrimitiveArray();
+        list2.clear();
+        for (double i : array)
+            list2.add(i);
+        assertEquals(list1, list2);
+    }
+}
diff --git a/java/util/stream/SpliteratorTestHelper.java b/java/util/stream/SpliteratorTestHelper.java
new file mode 100644
index 0000000..cf9ce2a
--- /dev/null
+++ b/java/util/stream/SpliteratorTestHelper.java
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Spliterator;
+import java.util.function.*;
+
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+/**
+ * Assertion methods for spliterators, to be called from other tests
+ */
+public class SpliteratorTestHelper {
+
+    public interface ContentAsserter<T> {
+        void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered);
+    }
+
+    private static ContentAsserter<Object> DEFAULT_CONTENT_ASSERTER
+            = SpliteratorTestHelper::assertContents;
+
+    @SuppressWarnings("unchecked")
+    private static <T> ContentAsserter<T> defaultContentAsserter() {
+        return (ContentAsserter<T>) DEFAULT_CONTENT_ASSERTER;
+    }
+
+    public static void testSpliterator(Supplier<Spliterator<Integer>> supplier) {
+        testSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testSpliterator(Supplier<Spliterator<Integer>> supplier,
+                                       ContentAsserter<Integer> asserter) {
+        testSpliterator(supplier, (Consumer<Integer> b) -> b, asserter);
+    }
+
+    public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier) {
+        testIntSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testIntSpliterator(Supplier<Spliterator.OfInt> supplier,
+                                          ContentAsserter<Integer> asserter) {
+        class BoxingAdapter implements Consumer<Integer>, IntConsumer {
+            private final Consumer<Integer> b;
+
+            BoxingAdapter(Consumer<Integer> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Integer value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(int value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, BoxingAdapter::new, asserter);
+    }
+
+    public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier) {
+        testLongSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testLongSpliterator(Supplier<Spliterator.OfLong> supplier,
+                                           ContentAsserter<Long> asserter) {
+        class BoxingAdapter implements Consumer<Long>, LongConsumer {
+            private final Consumer<Long> b;
+
+            BoxingAdapter(Consumer<Long> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Long value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(long value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, BoxingAdapter::new, asserter);
+    }
+
+    public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier) {
+        testDoubleSpliterator(supplier, defaultContentAsserter());
+    }
+
+    public static void testDoubleSpliterator(Supplier<Spliterator.OfDouble> supplier,
+                                             ContentAsserter<Double> asserter) {
+        class BoxingAdapter implements Consumer<Double>, DoubleConsumer {
+            private final Consumer<Double> b;
+
+            BoxingAdapter(Consumer<Double> b) {
+                this.b = b;
+            }
+
+            @Override
+            public void accept(Double value) {
+                throw new IllegalStateException();
+            }
+
+            @Override
+            public void accept(double value) {
+                b.accept(value);
+            }
+        }
+
+        testSpliterator(supplier, BoxingAdapter::new, asserter);
+    }
+
+    static <T, S extends Spliterator<T>> void testSpliterator(Supplier<S> supplier,
+                                                              UnaryOperator<Consumer<T>> boxingAdapter,
+                                                              ContentAsserter<T> asserter) {
+        ArrayList<T> fromForEach = new ArrayList<>();
+        Spliterator<T> spliterator = supplier.get();
+        Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+        spliterator.forEachRemaining(addToFromForEach);
+
+        Collection<T> exp = Collections.unmodifiableList(fromForEach);
+
+        testNullPointerException(supplier);
+        testForEach(exp, supplier, boxingAdapter, asserter);
+        testTryAdvance(exp, supplier, boxingAdapter, asserter);
+        testMixedTryAdvanceForEach(exp, supplier, boxingAdapter, asserter);
+        testMixedTraverseAndSplit(exp, supplier, boxingAdapter, asserter);
+        testSplitAfterFullTraversal(supplier, boxingAdapter);
+        testSplitOnce(exp, supplier, boxingAdapter, asserter);
+        testSplitSixDeep(exp, supplier, boxingAdapter, asserter);
+        testSplitUntilNull(exp, supplier, boxingAdapter, asserter);
+    }
+
+    //
+
+    private static <T, S extends Spliterator<T>> void testNullPointerException(Supplier<S> s) {
+        S sp = s.get();
+        // Have to check instances and use casts to avoid tripwire messages and
+        // directly test the primitive methods
+        if (sp instanceof Spliterator.OfInt) {
+            Spliterator.OfInt psp = (Spliterator.OfInt) sp;
+            executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((IntConsumer) null));
+            executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((IntConsumer) null));
+        }
+        else if (sp instanceof Spliterator.OfLong) {
+            Spliterator.OfLong psp = (Spliterator.OfLong) sp;
+            executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((LongConsumer) null));
+            executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((LongConsumer) null));
+        }
+        else if (sp instanceof Spliterator.OfDouble) {
+            Spliterator.OfDouble psp = (Spliterator.OfDouble) sp;
+            executeAndCatch(NullPointerException.class, () -> psp.forEachRemaining((DoubleConsumer) null));
+            executeAndCatch(NullPointerException.class, () -> psp.tryAdvance((DoubleConsumer) null));
+        }
+        else {
+            executeAndCatch(NullPointerException.class, () -> sp.forEachRemaining(null));
+            executeAndCatch(NullPointerException.class, () -> sp.tryAdvance(null));
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testForEach(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> fromForEach = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> addToFromForEach = boxingAdapter.apply(fromForEach::add);
+        spliterator.forEachRemaining(addToFromForEach);
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(
+                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(
+                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        // assert that size, tryAdvance, and forEach are consistent
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, exp.size());
+        }
+        assertEquals(fromForEach.size(), exp.size());
+
+        asserter.assertContents(fromForEach, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testTryAdvance(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        spliterator = supplier.get();
+        ArrayList<T> fromTryAdvance = new ArrayList<>();
+        Consumer<T> addToFromTryAdvance = boxingAdapter.apply(fromTryAdvance::add);
+        while (spliterator.tryAdvance(addToFromTryAdvance)) { }
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(
+                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(
+                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        // assert that size, tryAdvance, and forEach are consistent
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, exp.size());
+        }
+        assertEquals(fromTryAdvance.size(), exp.size());
+
+        asserter.assertContents(fromTryAdvance, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testMixedTryAdvanceForEach(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        // tryAdvance first few elements, then forEach rest
+        ArrayList<T> dest = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+        for (int i = 0; i < 10 && spliterator.tryAdvance(addToDest); i++) { }
+        spliterator.forEachRemaining(addToDest);
+
+        // Assert that forEach now produces no elements
+        spliterator.forEachRemaining(boxingAdapter.apply(
+                e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+        // Assert that tryAdvance now produce no elements
+        spliterator.tryAdvance(boxingAdapter.apply(
+                e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        asserter.assertContents(dest, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        // tryAdvance first few elements, then forEach rest
+        ArrayList<T> dest = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> b = boxingAdapter.apply(dest::add);
+
+        Spliterator<T> spl1, spl2, spl3;
+        spliterator.tryAdvance(b);
+        spl2 = spliterator.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spl3 = spliterator.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spliterator.forEachRemaining(b);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        asserter.assertContents(dest, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        // Full traversal using tryAdvance
+        Spliterator<T> spliterator = supplier.get();
+        while (spliterator.tryAdvance(boxingAdapter.apply(e -> { }))) { }
+        Spliterator<T> split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using forEach
+        spliterator = supplier.get();
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
+        split = spliterator.trySplit();
+        assertNull(split);
+
+        // Full traversal using tryAdvance then forEach
+        spliterator = supplier.get();
+        spliterator.tryAdvance(boxingAdapter.apply(e -> { }));
+        spliterator.forEachRemaining(boxingAdapter.apply(e -> { }));
+        split = spliterator.trySplit();
+        assertNull(split);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitOnce(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> fromSplit = new ArrayList<>();
+        Spliterator<T> s1 = supplier.get();
+        Spliterator<T> s2 = s1.trySplit();
+        long s1Size = s1.getExactSizeIfKnown();
+        long s2Size = (s2 != null) ? s2.getExactSizeIfKnown() : 0;
+        Consumer<T> addToFromSplit = boxingAdapter.apply(fromSplit::add);
+        if (s2 != null)
+            s2.forEachRemaining(addToFromSplit);
+        s1.forEachRemaining(addToFromSplit);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, fromSplit.size());
+            if (s1Size >= 0 && s2Size >= 0)
+                assertEquals(sizeIfKnown, s1Size + s2Size);
+        }
+
+        asserter.assertContents(fromSplit, exp, isOrdered);
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitSixDeep(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        S spliterator = supplier.get();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        for (int depth=0; depth < 6; depth++) {
+            List<T> dest = new ArrayList<>();
+            spliterator = supplier.get();
+
+            assertSpliterator(spliterator);
+
+            // verify splitting with forEach
+            splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), false);
+            asserter.assertContents(dest, exp, isOrdered);
+
+            // verify splitting with tryAdvance
+            dest.clear();
+            spliterator = supplier.get();
+            splitSixDeepVisitor(depth, 0, dest, spliterator, boxingAdapter, spliterator.characteristics(), true);
+            asserter.assertContents(dest, exp, isOrdered);
+        }
+    }
+
+    static void splitSixDeepVisitorUnsafe(int depth, int curLevel, List dest,
+        Spliterator spliterator, UnaryOperator boxingAdapter,
+        int rootCharacteristics, boolean useTryAdvance) {
+      splitSixDeepVisitor(depth, curLevel, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+    }
+
+    // Android-changed: Workaround for jack type inference bug
+     private static <T>
+    // private static <T, S extends Spliterator<T>>
+    // Android-changed: Workaround for jack type inference bug
+    void splitSixDeepVisitor(int depth, int curLevel,
+                             List<T> dest, Spliterator<T> spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
+    //                         List<T> dest, S spliterator, UnaryOperator<Consumer<T>> boxingAdapter,
+                             int rootCharacteristics, boolean useTryAdvance) {
+        if (curLevel < depth) {
+            long beforeSize = spliterator.getExactSizeIfKnown();
+            Spliterator<T> split = spliterator.trySplit();
+            if (split != null) {
+                assertSpliterator(split, rootCharacteristics);
+                assertSpliterator(spliterator, rootCharacteristics);
+
+                if ((rootCharacteristics & Spliterator.SUBSIZED) != 0 &&
+                    (rootCharacteristics & Spliterator.SIZED) != 0) {
+                    assertEquals(beforeSize, split.estimateSize() + spliterator.estimateSize());
+                }
+                // Android-changed: Workaround for jack type inference bug
+                splitSixDeepVisitorUnsafe(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+                // splitSixDeepVisitor(depth, curLevel + 1, dest, split, boxingAdapter, rootCharacteristics, useTryAdvance);
+            }
+            splitSixDeepVisitor(depth, curLevel + 1, dest, spliterator, boxingAdapter, rootCharacteristics, useTryAdvance);
+        }
+        else {
+            long sizeIfKnown = spliterator.getExactSizeIfKnown();
+            if (useTryAdvance) {
+                Consumer<T> addToDest = boxingAdapter.apply(dest::add);
+                int count = 0;
+                while (spliterator.tryAdvance(addToDest)) {
+                    ++count;
+                }
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, count);
+
+                // Assert that forEach now produces no elements
+                spliterator.forEachRemaining(boxingAdapter.apply(
+                        e -> fail("Spliterator.forEach produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+            }
+            else {
+                List<T> leafDest = new ArrayList<>();
+                Consumer<T> addToLeafDest = boxingAdapter.apply(leafDest::add);
+                spliterator.forEachRemaining(addToLeafDest);
+
+                if (sizeIfKnown >= 0)
+                    assertEquals(sizeIfKnown, leafDest.size());
+
+                // Assert that forEach now produces no elements
+                spliterator.tryAdvance(boxingAdapter.apply(
+                        e -> fail("Spliterator.tryAdvance produced an element after spliterator exhausted: " + e)));
+
+                Spliterator<T> split = spliterator.trySplit();
+                assertNull(split);
+
+                dest.addAll(leafDest);
+            }
+        }
+    }
+
+    private static <T, S extends Spliterator<T>> void testSplitUntilNull(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter,
+            ContentAsserter<T> asserter) {
+        Spliterator<T> s = supplier.get();
+        boolean isOrdered = s.hasCharacteristics(Spliterator.ORDERED);
+        assertSpliterator(s);
+
+        List<T> splits = new ArrayList<>();
+        Consumer<T> c = boxingAdapter.apply(splits::add);
+
+        testSplitUntilNull(new SplitNode<T>(c, s));
+        asserter.assertContents(splits, exp, isOrdered);
+    }
+
+    private static class SplitNode<T> {
+        // Constant for every node
+        final Consumer<T> c;
+        final int rootCharacteristics;
+
+        final Spliterator<T> s;
+
+        SplitNode(Consumer<T> c, Spliterator<T> s) {
+            this(c, s.characteristics(), s);
+        }
+
+        private SplitNode(Consumer<T> c, int rootCharacteristics, Spliterator<T> s) {
+            this.c = c;
+            this.rootCharacteristics = rootCharacteristics;
+            this.s = s;
+        }
+
+        SplitNode<T> fromSplit(Spliterator<T> split) {
+            return new SplitNode<>(c, rootCharacteristics, split);
+        }
+    }
+
+    /**
+     * Set the maximum stack capacity to 0.25MB. This should be more than enough to detect a bad spliterator
+     * while not unduly disrupting test infrastructure given the test data sizes that are used are small.
+     * Note that j.u.c.ForkJoinPool sets the max queue size to 64M (1 << 26).
+     */
+    private static final int MAXIMUM_STACK_CAPACITY = 1 << 18; // 0.25MB
+
+    private static <T> void testSplitUntilNull(SplitNode<T> e) {
+        // Use an explicit stack to avoid a StackOverflowException when testing a Spliterator
+        // that when repeatedly split produces a right-balanced (and maybe degenerate) tree, or
+        // for a spliterator that is badly behaved.
+        Deque<SplitNode<T>> stack = new ArrayDeque<>();
+        stack.push(e);
+
+        int iteration = 0;
+        while (!stack.isEmpty()) {
+            assertTrue(iteration++ < MAXIMUM_STACK_CAPACITY, "Exceeded maximum stack modification count of 1 << 18");
+
+            e = stack.pop();
+            Spliterator<T> parentAndRightSplit = e.s;
+
+            long parentEstimateSize = parentAndRightSplit.estimateSize();
+            assertTrue(parentEstimateSize >= 0,
+                       String.format("Split size estimate %d < 0", parentEstimateSize));
+
+            long parentSize = parentAndRightSplit.getExactSizeIfKnown();
+            Spliterator<T> leftSplit = parentAndRightSplit.trySplit();
+            if (leftSplit == null) {
+                parentAndRightSplit.forEachRemaining(e.c);
+                continue;
+            }
+
+            assertSpliterator(leftSplit, e.rootCharacteristics);
+            assertSpliterator(parentAndRightSplit, e.rootCharacteristics);
+
+            if (parentEstimateSize != Long.MAX_VALUE && leftSplit.estimateSize() > 0
+                && parentAndRightSplit.estimateSize() > 0) {
+                assertTrue(leftSplit.estimateSize() < parentEstimateSize,
+                           String.format("Left split size estimate %d >= parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+                assertTrue(parentAndRightSplit.estimateSize() < parentEstimateSize,
+                           String.format("Right split size estimate %d >= parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+            }
+            else {
+                assertTrue(leftSplit.estimateSize() <= parentEstimateSize,
+                           String.format("Left split size estimate %d > parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+                assertTrue(parentAndRightSplit.estimateSize() <= parentEstimateSize,
+                           String.format("Right split size estimate %d > parent split size estimate %d",
+                                         leftSplit.estimateSize(), parentEstimateSize));
+            }
+
+            long leftSize = leftSplit.getExactSizeIfKnown();
+            long rightSize = parentAndRightSplit.getExactSizeIfKnown();
+            if (parentSize >= 0 && leftSize >= 0 && rightSize >= 0)
+                assertEquals(parentSize, leftSize + rightSize,
+                             String.format("exact left split size %d + exact right split size %d != parent exact split size %d",
+                                           leftSize, rightSize, parentSize));
+
+            // Add right side to stack first so left side is popped off first
+            stack.push(e.fromSplit(parentAndRightSplit));
+            stack.push(e.fromSplit(leftSplit));
+        }
+    }
+
+    private static void assertSpliterator(Spliterator<?> s, int rootCharacteristics) {
+        if ((rootCharacteristics & Spliterator.SUBSIZED) != 0) {
+            assertTrue(s.hasCharacteristics(Spliterator.SUBSIZED),
+                       "Child split is not SUBSIZED when root split is SUBSIZED");
+        }
+        assertSpliterator(s);
+    }
+
+    private static void assertSpliterator(Spliterator<?> s) {
+        if (s.hasCharacteristics(Spliterator.SUBSIZED)) {
+            assertTrue(s.hasCharacteristics(Spliterator.SIZED));
+        }
+        if (s.hasCharacteristics(Spliterator.SIZED)) {
+            assertTrue(s.estimateSize() != Long.MAX_VALUE);
+            assertTrue(s.getExactSizeIfKnown() >= 0);
+        }
+        try {
+            s.getComparator();
+            assertTrue(s.hasCharacteristics(Spliterator.SORTED));
+        } catch (IllegalStateException e) {
+            assertFalse(s.hasCharacteristics(Spliterator.SORTED));
+        }
+    }
+
+    private static<T> void assertContents(Collection<T> actual, Collection<T> expected, boolean isOrdered) {
+        if (isOrdered) {
+            assertEquals(actual, expected);
+        }
+        else {
+            LambdaTestHelpers.assertContentsUnordered(actual, expected);
+        }
+    }
+
+    private static void executeAndCatch(Class<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        assertTrue(expected.isInstance(caught),
+                   String.format("Exception thrown %s not an instance of %s",
+                                 caught.getClass().getName(), expected.getName()));
+    }
+
+    static<U> void mixedTraverseAndSplit(Consumer<U> b, Spliterator<U> splTop) {
+        Spliterator<U> spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+
+    static void mixedTraverseAndSplit(IntConsumer b, Spliterator.OfInt splTop) {
+        Spliterator.OfInt spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+    static void mixedTraverseAndSplit(LongConsumer b, Spliterator.OfLong splTop) {
+        Spliterator.OfLong spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+
+    static void mixedTraverseAndSplit(DoubleConsumer b, Spliterator.OfDouble splTop) {
+        Spliterator.OfDouble spl1, spl2, spl3;
+        splTop.tryAdvance(b);
+        spl2 = splTop.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        spl3 = splTop.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        splTop.tryAdvance(b);
+        splTop.forEachRemaining(b);
+    }
+}
diff --git a/java/util/stream/StatefulTestOp.java b/java/util/stream/StatefulTestOp.java
new file mode 100644
index 0000000..904b4e5
--- /dev/null
+++ b/java/util/stream/StatefulTestOp.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.IntFunction;
+
+/**
+ * The base type for a stateful test operation.
+ */
+interface StatefulTestOp<E> extends IntermediateTestOp<E, E> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            StatefulTestOp op) {
+        switch (op.outputShape()) {
+            case REFERENCE:
+                return new ReferencePipeline.StatefulOp<Object, T>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
+                                                      Spliterator<P_IN> spliterator,
+                                                      IntFunction<T[]> generator) {
+                        return op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case INT_VALUE:
+                return new IntPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
+                                                            Spliterator<P_IN> spliterator,
+                                                            IntFunction<Integer[]> generator) {
+                        return (Node<Integer>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case LONG_VALUE:
+                return new LongPipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                                 Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
+                                                         Spliterator<P_IN> spliterator,
+                                                         IntFunction<Long[]> generator) {
+                        return (Node<Long>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            case DOUBLE_VALUE:
+                return new DoublePipeline.StatefulOp<Object>(upstream, op.inputShape(), op.opGetFlags()) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+
+                    @Override
+                    public <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                                    Spliterator<P_IN> spliterator) {
+                        return op.opEvaluateParallelLazy(helper, spliterator);
+                    }
+
+                    @Override
+                    public <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
+                                                           Spliterator<P_IN> spliterator,
+                                                           IntFunction<Double[]> generator) {
+                        return (Node<Double>) op.opEvaluateParallel(helper, spliterator, generator);
+                    }
+                };
+            default: throw new IllegalStateException(op.outputShape().toString());
+        }
+    }
+
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    default int opGetFlags() { return 0; }
+
+    Sink<E> opWrapSink(int flags, boolean parallel, Sink<E> sink);
+
+    @SuppressWarnings("unchecked")
+    default <P_IN> Spliterator<E> opEvaluateParallelLazy(PipelineHelper<E> helper,
+                                                         Spliterator<P_IN> spliterator) {
+        return opEvaluateParallel(helper, spliterator, i -> (E[]) new Object[i]).spliterator();
+    }
+
+    <P_IN> Node<E> opEvaluateParallel(PipelineHelper<E> helper,
+                                      Spliterator<P_IN> spliterator,
+                                      IntFunction<E[]> generator);
+}
diff --git a/java/util/stream/StatelessTestOp.java b/java/util/stream/StatelessTestOp.java
new file mode 100644
index 0000000..3a6194b
--- /dev/null
+++ b/java/util/stream/StatelessTestOp.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * The base type of a stateless test operation
+ */
+interface StatelessTestOp<E_IN, E_OUT> extends IntermediateTestOp<E_IN, E_OUT> {
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static<T> AbstractPipeline chain(AbstractPipeline upstream,
+                                            StatelessTestOp<?, T> op) {
+        int flags = op.opGetFlags();
+        switch (op.outputShape()) {
+            case REFERENCE:
+                return new ReferencePipeline.StatelessOp<Object, T>(upstream, op.inputShape(), flags) {
+                    public Sink opWrapSink(int flags, Sink<T> sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case INT_VALUE:
+                return new IntPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case LONG_VALUE:
+                return new LongPipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            case DOUBLE_VALUE:
+                return new DoublePipeline.StatelessOp<Object>(upstream, op.inputShape(), flags) {
+                    @Override
+                    public Sink opWrapSink(int flags, Sink sink) {
+                        return op.opWrapSink(flags, isParallel(), sink);
+                    }
+                };
+            default: throw new IllegalStateException(op.outputShape().toString());
+        }
+    }
+
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    default int opGetFlags() { return 0; }
+
+    Sink<E_IN> opWrapSink(int flags, boolean parallel, Sink<E_OUT> sink);
+}
+
diff --git a/java/util/stream/Stream.java b/java/util/stream/Stream.java
new file mode 100644
index 0000000..c35fc05
--- /dev/null
+++ b/java/util/stream/Stream.java
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+import java.util.function.UnaryOperator;
+
+/**
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>In addition to {@code Stream}, which is a stream of object references,
+ * there are primitive specializations for {@link IntStream}, {@link LongStream},
+ * and {@link DoubleStream}, all of which are referred to as "streams" and
+ * conform to the characteristics and restrictions described here.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an I/O channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  To preserve correct behavior,
+ * these <em>behavioral parameters</em>:
+ * <ul>
+ * <li>must be <a href="package-summary.html#NonInterference">non-interfering</a>
+ * (they do not modify the stream source); and</li>
+ * <li>in most cases must be <a href="package-summary.html#Statelessness">stateless</a>
+ * (their result should not depend on any state that might change during execution
+ * of the stream pipeline).</li>
+ * </ul>
+ *
+ * <p>Such parameters are always instances of a
+ * <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  Unless otherwise specified these parameters must be
+ * <em>non-null</em>.
+ *
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
+ * @since 1.8
+ * @see IntStream
+ * @see LongStream
+ * @see DoubleStream
+ * @see <a href="package-summary.html">java.util.stream</a>
+ */
+public interface Stream<T> extends BaseStream<T, Stream<T>> {
+
+    /**
+     * Returns a stream consisting of the elements of this stream that match
+     * the given predicate.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to each element to determine if it
+     *                  should be included
+     * @return the new stream
+     */
+    Stream<T> filter(Predicate<? super T> predicate);
+
+    /**
+     * Returns a stream consisting of the results of applying the given
+     * function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    <R> Stream<R> map(Function<? super T, ? extends R> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">
+     *     intermediate operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    IntStream mapToInt(ToIntFunction<? super T> mapper);
+
+    /**
+     * Returns a {@code LongStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    LongStream mapToLong(ToLongFunction<? super T> mapper);
+
+    /**
+     * Returns a {@code DoubleStream} consisting of the results of applying the
+     * given function to the elements of this stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element
+     * @return the new stream
+     */
+    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
+
+    /**
+     * Returns a stream consisting of the results of replacing each element of
+     * this stream with the contents of a mapped stream produced by applying
+     * the provided mapping function to each element.  Each mapped stream is
+     * {@link java.util.stream.BaseStream#close() closed} after its contents
+     * have been placed into this stream.  (If a mapped stream is {@code null}
+     * an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @apiNote
+     * The {@code flatMap()} operation has the effect of applying a one-to-many
+     * transformation to the elements of the stream, and then flattening the
+     * resulting elements into a new stream.
+     *
+     * <p><b>Examples.</b>
+     *
+     * <p>If {@code orders} is a stream of purchase orders, and each purchase
+     * order contains a collection of line items, then the following produces a
+     * stream containing all the line items in all the orders:
+     * <pre>{@code
+     *     orders.flatMap(order -> order.getLineItems().stream())...
+     * }</pre>
+     *
+     * <p>If {@code path} is the path to a file, then the following produces a
+     * stream of the {@code words} contained in that file:
+     * <pre>{@code
+     *     Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8);
+     *     Stream<String> words = lines.flatMap(line -> Stream.of(line.split(" +")));
+     * }</pre>
+     * The {@code mapper} function passed to {@code flatMap} splits a line,
+     * using a simple regular expression, into an array of words, and then
+     * creates a stream of words from that array.
+     *
+     * @param <R> The element type of the new stream
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     */
+    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
+
+    /**
+     * Returns an {@code IntStream} consisting of the results of replacing each
+     * element of this stream with the contents of a mapped stream produced by
+     * applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have been placed into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
+
+    /**
+     * Returns an {@code LongStream} consisting of the results of replacing each
+     * element of this stream with the contents of a mapped stream produced by
+     * applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have been placed into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
+
+    /**
+     * Returns an {@code DoubleStream} consisting of the results of replacing
+     * each element of this stream with the contents of a mapped stream produced
+     * by applying the provided mapping function to each element.  Each mapped
+     * stream is {@link java.util.stream.BaseStream#close() closed} after its
+     * contents have placed been into this stream.  (If a mapped stream is
+     * {@code null} an empty stream is used, instead.)
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param mapper a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *               <a href="package-summary.html#Statelessness">stateless</a>
+     *               function to apply to each element which produces a stream
+     *               of new values
+     * @return the new stream
+     * @see #flatMap(Function)
+     */
+    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
+
+    /**
+     * Returns a stream consisting of the distinct elements (according to
+     * {@link Object#equals(Object)}) of this stream.
+     *
+     * <p>For ordered streams, the selection of distinct elements is stable
+     * (for duplicated elements, the element appearing first in the encounter
+     * order is preserved.)  For unordered streams, no stability guarantees
+     * are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * Preserving stability for {@code distinct()} in parallel pipelines is
+     * relatively expensive (requires that the operation act as a full barrier,
+     * with substantial buffering overhead), and stability is often not needed.
+     * Using an unordered stream source (such as {@link #generate(Supplier)})
+     * or removing the ordering constraint with {@link #unordered()} may result
+     * in significantly more efficient execution for {@code distinct()} in parallel
+     * pipelines, if the semantics of your situation permit.  If consistency
+     * with encounter order is required, and you are experiencing poor performance
+     * or memory utilization with {@code distinct()} in parallel pipelines,
+     * switching to sequential execution with {@link #sequential()} may improve
+     * performance.
+     *
+     * @return the new stream
+     */
+    Stream<T> distinct();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, sorted
+     * according to natural order.  If the elements of this stream are not
+     * {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown
+     * when the terminal operation is executed.
+     *
+     * <p>For ordered streams, the sort is stable.  For unordered streams, no
+     * stability guarantees are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @return the new stream
+     */
+    Stream<T> sorted();
+
+    /**
+     * Returns a stream consisting of the elements of this stream, sorted
+     * according to the provided {@code Comparator}.
+     *
+     * <p>For ordered streams, the sort is stable.  For unordered streams, no
+     * stability guarantees are made.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to be used to compare stream elements
+     * @return the new stream
+     */
+    Stream<T> sorted(Comparator<? super T> comparator);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, additionally
+     * performing the provided action on each element as elements are consumed
+     * from the resulting stream.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * <p>For parallel stream pipelines, the action may be called at
+     * whatever time and in whatever thread the element is made available by the
+     * upstream operation.  If the action modifies shared state,
+     * it is responsible for providing the required synchronization.
+     *
+     * @apiNote This method exists mainly to support debugging, where you want
+     * to see the elements as they flow past a certain point in a pipeline:
+     * <pre>{@code
+     *     Stream.of("one", "two", "three", "four")
+     *         .filter(e -> e.length() > 3)
+     *         .peek(e -> System.out.println("Filtered value: " + e))
+     *         .map(String::toUpperCase)
+     *         .peek(e -> System.out.println("Mapped value: " + e))
+     *         .collect(Collectors.toList());
+     * }</pre>
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *                 non-interfering</a> action to perform on the elements as
+     *                 they are consumed from the stream
+     * @return the new stream
+     */
+    Stream<T> peek(Consumer<? super T> action);
+
+    /**
+     * Returns a stream consisting of the elements of this stream, truncated
+     * to be no longer than {@code maxSize} in length.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * stateful intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code limit()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code maxSize}, since {@code limit(n)}
+     * is constrained to return not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(Supplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code limit()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code limit()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param maxSize the number of elements the stream should be limited to
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code maxSize} is negative
+     */
+    Stream<T> limit(long maxSize);
+
+    /**
+     * Returns a stream consisting of the remaining elements of this stream
+     * after discarding the first {@code n} elements of the stream.
+     * If this stream contains fewer than {@code n} elements then an
+     * empty stream will be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">stateful
+     * intermediate operation</a>.
+     *
+     * @apiNote
+     * While {@code skip()} is generally a cheap operation on sequential
+     * stream pipelines, it can be quite expensive on ordered parallel pipelines,
+     * especially for large values of {@code n}, since {@code skip(n)}
+     * is constrained to skip not just any <em>n</em> elements, but the
+     * <em>first n</em> elements in the encounter order.  Using an unordered
+     * stream source (such as {@link #generate(Supplier)}) or removing the
+     * ordering constraint with {@link #unordered()} may result in significant
+     * speedups of {@code skip()} in parallel pipelines, if the semantics of
+     * your situation permit.  If consistency with encounter order is required,
+     * and you are experiencing poor performance or memory utilization with
+     * {@code skip()} in parallel pipelines, switching to sequential execution
+     * with {@link #sequential()} may improve performance.
+     *
+     * @param n the number of leading elements to skip
+     * @return the new stream
+     * @throws IllegalArgumentException if {@code n} is negative
+     */
+    Stream<T> skip(long n);
+
+    /**
+     * Performs an action for each element of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic.
+     * For parallel stream pipelines, this operation does <em>not</em>
+     * guarantee to respect the encounter order of the stream, as doing so
+     * would sacrifice the benefit of parallelism.  For any given element, the
+     * action may be performed at whatever time and in whatever thread the
+     * library chooses.  If the action accesses shared state, it is
+     * responsible for providing the required synchronization.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     */
+    void forEach(Consumer<? super T> action);
+
+    /**
+     * Performs an action for each element of this stream, in the encounter
+     * order of the stream if the stream has a defined encounter order.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>This operation processes the elements one at a time, in encounter
+     * order if one exists.  Performing the action for one element
+     * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>happens-before</i></a>
+     * performing the action for subsequent elements, but for any given element,
+     * the action may be performed in whatever thread the library chooses.
+     *
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements
+     * @see #forEach(Consumer)
+     */
+    void forEachOrdered(Consumer<? super T> action);
+
+    /**
+     * Returns an array containing the elements of this stream.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @return an array containing the elements of this stream
+     */
+    Object[] toArray();
+
+    /**
+     * Returns an array containing the elements of this stream, using the
+     * provided {@code generator} function to allocate the returned array, as
+     * well as any additional arrays that might be required for a partitioned
+     * execution or for resizing.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote
+     * The generator function takes an integer, which is the size of the
+     * desired array, and produces an array of the desired size.  This can be
+     * concisely expressed with an array constructor reference:
+     * <pre>{@code
+     *     Person[] men = people.stream()
+     *                          .filter(p -> p.getGender() == MALE)
+     *                          .toArray(Person[]::new);
+     * }</pre>
+     *
+     * @param <A> the element type of the resulting array
+     * @param generator a function which produces a new array of the desired
+     *                  type and the provided length
+     * @return an array containing the elements in this stream
+     * @throws ArrayStoreException if the runtime type of the array returned
+     * from the array generator is not a supertype of the runtime type of every
+     * element in this stream
+     */
+    <A> A[] toArray(IntFunction<A[]> generator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity value and an
+     * <a href="package-summary.html#Associativity">associative</a>
+     * accumulation function, and returns the reduced value.  This is equivalent
+     * to:
+     * <pre>{@code
+     *     T result = identity;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the accumulator
+     * function. This means that for all {@code t},
+     * {@code accumulator.apply(identity, t)} is equal to {@code t}.
+     * The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Sum, min, max, average, and string concatenation are all special
+     * cases of reduction. Summing a stream of numbers can be expressed as:
+     *
+     * <pre>{@code
+     *     Integer sum = integers.reduce(0, (a, b) -> a+b);
+     * }</pre>
+     *
+     * or:
+     *
+     * <pre>{@code
+     *     Integer sum = integers.reduce(0, Integer::sum);
+     * }</pre>
+     *
+     * <p>While this may seem a more roundabout way to perform an aggregation
+     * compared to simply mutating a running total in a loop, reduction
+     * operations parallelize more gracefully, without needing additional
+     * synchronization and with greatly reduced risk of data races.
+     *
+     * @param identity the identity value for the accumulating function
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values
+     * @return the result of the reduction
+     */
+    T reduce(T identity, BinaryOperator<T> accumulator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using an
+     * <a href="package-summary.html#Associativity">associative</a> accumulation
+     * function, and returns an {@code Optional} describing the reduced value,
+     * if any. This is equivalent to:
+     * <pre>{@code
+     *     boolean foundAny = false;
+     *     T result = null;
+     *     for (T element : this stream) {
+     *         if (!foundAny) {
+     *             foundAny = true;
+     *             result = element;
+     *         }
+     *         else
+     *             result = accumulator.apply(result, element);
+     *     }
+     *     return foundAny ? Optional.of(result) : Optional.empty();
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code accumulator} function must be an
+     * <a href="package-summary.html#Associativity">associative</a> function.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values
+     * @return an {@link Optional} describing the result of the reduction
+     * @throws NullPointerException if the result of the reduction is null
+     * @see #reduce(Object, BinaryOperator)
+     * @see #min(Comparator)
+     * @see #max(Comparator)
+     */
+    Optional<T> reduce(BinaryOperator<T> accumulator);
+
+    /**
+     * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
+     * elements of this stream, using the provided identity, accumulation and
+     * combining functions.  This is equivalent to:
+     * <pre>{@code
+     *     U result = identity;
+     *     for (T element : this stream)
+     *         result = accumulator.apply(result, element)
+     *     return result;
+     * }</pre>
+     *
+     * but is not constrained to execute sequentially.
+     *
+     * <p>The {@code identity} value must be an identity for the combiner
+     * function.  This means that for all {@code u}, {@code combiner(identity, u)}
+     * is equal to {@code u}.  Additionally, the {@code combiner} function
+     * must be compatible with the {@code accumulator} function; for all
+     * {@code u} and {@code t}, the following must hold:
+     * <pre>{@code
+     *     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote Many reductions using this form can be represented more simply
+     * by an explicit combination of {@code map} and {@code reduce} operations.
+     * The {@code accumulator} function acts as a fused mapper and accumulator,
+     * which can sometimes be more efficient than separate mapping and reduction,
+     * such as when knowing the previously reduced value allows you to avoid
+     * some computation.
+     *
+     * @param <U> The type of the result
+     * @param identity the identity value for the combiner function
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     * @see #reduce(BinaryOperator)
+     * @see #reduce(Object, BinaryOperator)
+     */
+    <U> U reduce(U identity,
+                 BiFunction<U, ? super T, U> accumulator,
+                 BinaryOperator<U> combiner);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream.  A mutable
+     * reduction is one in which the reduced value is a mutable result container,
+     * such as an {@code ArrayList}, and elements are incorporated by updating
+     * the state of the result rather than by replacing the result.  This
+     * produces a result equivalent to:
+     * <pre>{@code
+     *     R result = supplier.get();
+     *     for (T element : this stream)
+     *         accumulator.accept(result, element);
+     *     return result;
+     * }</pre>
+     *
+     * <p>Like {@link #reduce(Object, BinaryOperator)}, {@code collect} operations
+     * can be parallelized without requiring additional synchronization.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @apiNote There are many existing classes in the JDK whose signatures are
+     * well-suited for use with method references as arguments to {@code collect()}.
+     * For example, the following will accumulate strings into an {@code ArrayList}:
+     * <pre>{@code
+     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
+     *                                                ArrayList::addAll);
+     * }</pre>
+     *
+     * <p>The following will take a stream of strings and concatenates them into a
+     * single string:
+     * <pre>{@code
+     *     String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
+     *                                          StringBuilder::append)
+     *                                 .toString();
+     * }</pre>
+     *
+     * @param <R> type of the result
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
+     * @param accumulator an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for incorporating an additional element into a result
+     * @param combiner an <a href="package-summary.html#Associativity">associative</a>,
+     *                    <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                    <a href="package-summary.html#Statelessness">stateless</a>
+     *                    function for combining two values, which must be
+     *                    compatible with the accumulator function
+     * @return the result of the reduction
+     */
+    <R> R collect(Supplier<R> supplier,
+                  BiConsumer<R, ? super T> accumulator,
+                  BiConsumer<R, R> combiner);
+
+    /**
+     * Performs a <a href="package-summary.html#MutableReduction">mutable
+     * reduction</a> operation on the elements of this stream using a
+     * {@code Collector}.  A {@code Collector}
+     * encapsulates the functions used as arguments to
+     * {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for reuse of
+     * collection strategies and composition of collect operations such as
+     * multiple-level grouping or partitioning.
+     *
+     * <p>If the stream is parallel, and the {@code Collector}
+     * is {@link Collector.Characteristics#CONCURRENT concurrent}, and
+     * either the stream is unordered or the collector is
+     * {@link Collector.Characteristics#UNORDERED unordered},
+     * then a concurrent reduction will be performed (see {@link Collector} for
+     * details on concurrent reduction.)
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * <p>When executed in parallel, multiple intermediate results may be
+     * instantiated, populated, and merged so as to maintain isolation of
+     * mutable data structures.  Therefore, even when executed in parallel
+     * with non-thread-safe data structures (such as {@code ArrayList}), no
+     * additional synchronization is needed for a parallel reduction.
+     *
+     * @apiNote
+     * The following will accumulate strings into an ArrayList:
+     * <pre>{@code
+     *     List<String> asList = stringStream.collect(Collectors.toList());
+     * }</pre>
+     *
+     * <p>The following will classify {@code Person} objects by city:
+     * <pre>{@code
+     *     Map<String, List<Person>> peopleByCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getCity));
+     * }</pre>
+     *
+     * <p>The following will classify {@code Person} objects by state and city,
+     * cascading two {@code Collector}s together:
+     * <pre>{@code
+     *     Map<String, Map<String, List<Person>>> peopleByStateAndCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getState,
+     *                                                      Collectors.groupingBy(Person::getCity)));
+     * }</pre>
+     *
+     * @param <R> the type of the result
+     * @param <A> the intermediate accumulation type of the {@code Collector}
+     * @param collector the {@code Collector} describing the reduction
+     * @return the result of the reduction
+     * @see #collect(Supplier, BiConsumer, BiConsumer)
+     * @see Collectors
+     */
+    <R, A> R collect(Collector<? super T, A, R> collector);
+
+    /**
+     * Returns the minimum element of this stream according to the provided
+     * {@code Comparator}.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to compare elements of this stream
+     * @return an {@code Optional} describing the minimum element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the minimum element is null
+     */
+    Optional<T> min(Comparator<? super T> comparator);
+
+    /**
+     * Returns the maximum element of this stream according to the provided
+     * {@code Comparator}.  This is a special case of a
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
+     * @param comparator a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                   <a href="package-summary.html#Statelessness">stateless</a>
+     *                   {@code Comparator} to compare elements of this stream
+     * @return an {@code Optional} describing the maximum element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the maximum element is null
+     */
+    Optional<T> max(Comparator<? super T> comparator);
+
+    /**
+     * Returns the count of elements in this stream.  This is a special case of
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
+     * equivalent to:
+     * <pre>{@code
+     *     return mapToLong(e -> 1L).sum();
+     * }</pre>
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
+     *
+     * @return the count of elements in this stream
+     */
+    long count();
+
+    /**
+     * Returns whether any elements of this stream match the provided
+     * predicate.  May not evaluate the predicate on all elements if not
+     * necessary for determining the result.  If the stream is empty then
+     * {@code false} is returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>existential quantification</em> of the
+     * predicate over the elements of the stream (for some x P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if any elements of the stream match the provided
+     * predicate, otherwise {@code false}
+     */
+    boolean anyMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns whether all elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * predicate over the elements of the stream (for all x P(x)).  If the
+     * stream is empty, the quantification is said to be <em>vacuously
+     * satisfied</em> and is always {@code true} (regardless of P(x)).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either all elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean allMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns whether no elements of this stream match the provided predicate.
+     * May not evaluate the predicate on all elements if not necessary for
+     * determining the result.  If the stream is empty then {@code true} is
+     * returned and the predicate is not evaluated.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @apiNote
+     * This method evaluates the <em>universal quantification</em> of the
+     * negated predicate over the elements of the stream (for all x ~P(x)).  If
+     * the stream is empty, the quantification is said to be vacuously satisfied
+     * and is always {@code true}, regardless of P(x).
+     *
+     * @param predicate a <a href="package-summary.html#NonInterference">non-interfering</a>,
+     *                  <a href="package-summary.html#Statelessness">stateless</a>
+     *                  predicate to apply to elements of this stream
+     * @return {@code true} if either no elements of the stream match the
+     * provided predicate or the stream is empty, otherwise {@code false}
+     */
+    boolean noneMatch(Predicate<? super T> predicate);
+
+    /**
+     * Returns an {@link Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty.  If the stream has
+     * no encounter order, then any element may be returned.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * @return an {@code Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the element selected is null
+     */
+    Optional<T> findFirst();
+
+    /**
+     * Returns an {@link Optional} describing some element of the stream, or an
+     * empty {@code Optional} if the stream is empty.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
+     * terminal operation</a>.
+     *
+     * <p>The behavior of this operation is explicitly nondeterministic; it is
+     * free to select any element in the stream.  This is to allow for maximal
+     * performance in parallel operations; the cost is that multiple invocations
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
+     *
+     * @return an {@code Optional} describing some element of this stream, or an
+     * empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the element selected is null
+     * @see #findFirst()
+     */
+    Optional<T> findAny();
+
+    // Static factories
+
+    /**
+     * Returns a builder for a {@code Stream}.
+     *
+     * @param <T> type of elements
+     * @return a stream builder
+     */
+    public static<T> Builder<T> builder() {
+        return new Streams.StreamBuilderImpl<>();
+    }
+
+    /**
+     * Returns an empty sequential {@code Stream}.
+     *
+     * @param <T> the type of stream elements
+     * @return an empty sequential stream
+     */
+    public static<T> Stream<T> empty() {
+        return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false);
+    }
+
+    /**
+     * Returns a sequential {@code Stream} containing a single element.
+     *
+     * @param t the single element
+     * @param <T> the type of stream elements
+     * @return a singleton sequential stream
+     */
+    public static<T> Stream<T> of(T t) {
+        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
+    }
+
+    /**
+     * Returns a sequential ordered stream whose elements are the specified values.
+     *
+     * @param <T> the type of stream elements
+     * @param values the elements of the new stream
+     * @return the new stream
+     */
+    @SafeVarargs
+    @SuppressWarnings("varargs") // Creating a stream from an array is safe
+    public static<T> Stream<T> of(T... values) {
+        return Arrays.stream(values);
+    }
+
+    /**
+     * Returns an infinite sequential ordered {@code Stream} produced by iterative
+     * application of a function {@code f} to an initial element {@code seed},
+     * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
+     * {@code f(f(seed))}, etc.
+     *
+     * <p>The first element (position {@code 0}) in the {@code Stream} will be
+     * the provided {@code seed}.  For {@code n > 0}, the element at position
+     * {@code n}, will be the result of applying the function {@code f} to the
+     * element at position {@code n - 1}.
+     *
+     * @param <T> the type of stream elements
+     * @param seed the initial element
+     * @param f a function to be applied to to the previous element to produce
+     *          a new element
+     * @return a new sequential {@code Stream}
+     */
+    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
+        Objects.requireNonNull(f);
+        final Iterator<T> iterator = new Iterator<T>() {
+            @SuppressWarnings("unchecked")
+            T t = (T) Streams.NONE;
+
+            @Override
+            public boolean hasNext() {
+                return true;
+            }
+
+            @Override
+            public T next() {
+                return t = (t == Streams.NONE) ? seed : f.apply(t);
+            }
+        };
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+                iterator,
+                Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
+    }
+
+    /**
+     * Returns an infinite sequential unordered stream where each element is
+     * generated by the provided {@code Supplier}.  This is suitable for
+     * generating constant streams, streams of random elements, etc.
+     *
+     * @param <T> the type of stream elements
+     * @param s the {@code Supplier} of generated elements
+     * @return a new infinite sequential unordered {@code Stream}
+     */
+    public static<T> Stream<T> generate(Supplier<T> s) {
+        Objects.requireNonNull(s);
+        return StreamSupport.stream(
+                new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
+    }
+
+    /**
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream.  The resulting stream is ordered if both
+     * of the input streams are ordered, and parallel if either of the input
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
+     *
+     * @implNote
+     * Use caution when constructing streams from repeated concatenation.
+     * Accessing an element of a deeply concatenated stream can result in deep
+     * call chains, or even {@code StackOverflowException}.
+     *
+     * @param <T> The type of stream elements
+     * @param a the first stream
+     * @param b the second stream
+     * @return the concatenation of the two input streams
+     */
+    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        @SuppressWarnings("unchecked")
+        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
+                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
+        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
+    }
+
+    /**
+     * A mutable builder for a {@code Stream}.  This allows the creation of a
+     * {@code Stream} by generating elements individually and adding them to the
+     * {@code Builder} (without the copying overhead that comes from using
+     * an {@code ArrayList} as a temporary buffer.)
+     *
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
+     * when the {@link #build()} method is called, which creates an ordered
+     * {@code Stream} whose elements are the elements that were added to the stream
+     * builder, in the order they were added.
+     *
+     * @param <T> the type of stream elements
+     * @see Stream#builder()
+     * @since 1.8
+     */
+    public interface Builder<T> extends Consumer<T> {
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        @Override
+        void accept(T t);
+
+        /**
+         * Adds an element to the stream being built.
+         *
+         * @implSpec
+         * The default implementation behaves as if:
+         * <pre>{@code
+         *     accept(t)
+         *     return this;
+         * }</pre>
+         *
+         * @param t the element to add
+         * @return {@code this} builder
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        default Builder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        /**
+         * Builds the stream, transitioning this builder to the built state.
+         * An {@code IllegalStateException} is thrown if there are further attempts
+         * to operate on the builder after it has entered the built state.
+         *
+         * @return the built stream
+         * @throws IllegalStateException if the builder has already transitioned to
+         * the built state
+         */
+        Stream<T> build();
+
+    }
+}
diff --git a/java/util/stream/StreamFlagsTest.java b/java/util/stream/StreamFlagsTest.java
new file mode 100644
index 0000000..29243cf
--- /dev/null
+++ b/java/util/stream/StreamFlagsTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.*;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlag;
+import java.util.stream.Streams;
+
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * StreamFlagsTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamFlagsTest {
+    Stream<String> arrayList = new ArrayList<String>().stream();
+    Stream<String> linkedList = new LinkedList<String>().stream();
+    Stream<String> hashSet = new HashSet<String>().stream();
+    Stream<String> treeSet = new TreeSet<String>().stream();
+    Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+    Stream<String> repeat = Stream.generate(() -> "");
+
+    Stream<?>[] streams = { arrayList, linkedList, hashSet, treeSet, linkedHashSet, repeat };
+
+    private void assertFlags(int value, EnumSet<StreamOpFlag> setFlags, EnumSet<StreamOpFlag> clearFlags) {
+        for (StreamOpFlag flag : setFlags)
+            assertTrue(flag.isKnown(value));
+        for (StreamOpFlag flag : clearFlags)
+            assertTrue(!flag.isKnown(value));
+    }
+
+    public void testBaseStreams() {
+        Stream<String> arrayList = new ArrayList<String>().stream();
+        Stream<String> linkedList = new LinkedList<String>().stream();
+        Stream<String> hashSet = new HashSet<String>().stream();
+        Stream<String> treeSet = new TreeSet<String>().stream();
+        Stream<String> linkedHashSet = new LinkedHashSet<String>().stream();
+        Stream<String> repeat = Stream.generate(() -> "");
+
+        assertFlags(OpTestCase.getStreamFlags(arrayList),
+                    EnumSet.of(ORDERED, SIZED),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(linkedList),
+                    EnumSet.of(ORDERED, SIZED),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(hashSet),
+                    EnumSet.of(SIZED, DISTINCT),
+                    EnumSet.of(ORDERED, SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(treeSet),
+                    EnumSet.of(ORDERED, SIZED, DISTINCT, SORTED),
+                    EnumSet.of(SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(linkedHashSet),
+                    EnumSet.of(ORDERED, DISTINCT, SIZED),
+                    EnumSet.of(SORTED, SHORT_CIRCUIT));
+        assertFlags(OpTestCase.getStreamFlags(repeat),
+                    EnumSet.noneOf(StreamOpFlag.class),
+                    EnumSet.of(DISTINCT, SORTED, SHORT_CIRCUIT));
+    }
+
+    public void testFilter() {
+        for (Stream<?> s : streams) {
+            int baseFlags = OpTestCase.getStreamFlags(s);
+            int filteredFlags = OpTestCase.getStreamFlags(s.filter((Object e) -> true));
+            int expectedFlags = baseFlags & ~SIZED.set();
+
+            assertEquals(filteredFlags, expectedFlags);
+        }
+    }
+}
diff --git a/java/util/stream/StreamOpFlag.java b/java/util/stream/StreamOpFlag.java
new file mode 100644
index 0000000..83a3660
--- /dev/null
+++ b/java/util/stream/StreamOpFlag.java
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Spliterator;
+
+/**
+ * Flags corresponding to characteristics of streams and operations. Flags are
+ * utilized by the stream framework to control, specialize or optimize
+ * computation.
+ *
+ * <p>
+ * Stream flags may be used to describe characteristics of several different
+ * entities associated with streams: stream sources, intermediate operations,
+ * and terminal operations.  Not all stream flags are meaningful for all
+ * entities; the following table summarizes which flags are meaningful in what
+ * contexts:
+ *
+ * <div>
+ * <table>
+ *   <caption>Type Characteristics</caption>
+ *   <thead class="tableSubHeadingColor">
+ *     <tr>
+ *       <th colspan="2">&nbsp;</th>
+ *       <th>{@code DISTINCT}</th>
+ *       <th>{@code SORTED}</th>
+ *       <th>{@code ORDERED}</th>
+ *       <th>{@code SIZED}</th>
+ *       <th>{@code SHORT_CIRCUIT}</th>
+ *     </tr>
+ *   </thead>
+ *   <tbody>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Stream source</th>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>Y</td>
+ *        <td>N</td>
+ *      </tr>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Intermediate operation</th>
+ *        <td>PCI</td>
+ *        <td>PCI</td>
+ *        <td>PCI</td>
+ *        <td>PC</td>
+ *        <td>PI</td>
+ *      </tr>
+ *      <tr>
+ *        <th colspan="2" class="tableSubHeadingColor">Terminal operation</th>
+ *        <td>N</td>
+ *        <td>N</td>
+ *        <td>PC</td>
+ *        <td>N</td>
+ *        <td>PI</td>
+ *      </tr>
+ *   </tbody>
+ *   <tfoot>
+ *       <tr>
+ *         <th class="tableSubHeadingColor" colspan="2">Legend</th>
+ *         <th colspan="6" rowspan="7">&nbsp;</th>
+ *       </tr>
+ *       <tr>
+ *         <th class="tableSubHeadingColor">Flag</th>
+ *         <th class="tableSubHeadingColor">Meaning</th>
+ *         <th colspan="6"></th>
+ *       </tr>
+ *       <tr><td>Y</td><td>Allowed</td></tr>
+ *       <tr><td>N</td><td>Invalid</td></tr>
+ *       <tr><td>P</td><td>Preserves</td></tr>
+ *       <tr><td>C</td><td>Clears</td></tr>
+ *       <tr><td>I</td><td>Injects</td></tr>
+ *   </tfoot>
+ * </table>
+ * </div>
+ *
+ * <p>In the above table, "PCI" means "may preserve, clear, or inject"; "PC"
+ * means "may preserve or clear", "PI" means "may preserve or inject", and "N"
+ * means "not valid".
+ *
+ * <p>Stream flags are represented by unioned bit sets, so that a single word
+ * may describe all the characteristics of a given stream entity, and that, for
+ * example, the flags for a stream source can be efficiently combined with the
+ * flags for later operations on that stream.
+ *
+ * <p>The bit masks {@link #STREAM_MASK}, {@link #OP_MASK}, and
+ * {@link #TERMINAL_OP_MASK} can be ANDed with a bit set of stream flags to
+ * produce a mask containing only the valid flags for that entity type.
+ *
+ * <p>When describing a stream source, one only need describe what
+ * characteristics that stream has; when describing a stream operation, one need
+ * describe whether the operation preserves, injects, or clears that
+ * characteristic.  Accordingly, two bits are used for each flag, so as to allow
+ * representing not only the presence of of a characteristic, but how an
+ * operation modifies that characteristic.  There are two common forms in which
+ * flag bits are combined into an {@code int} bit set.  <em>Stream flags</em>
+ * are a unioned bit set constructed by ORing the enum characteristic values of
+ * {@link #set()} (or, more commonly, ORing the corresponding static named
+ * constants prefixed with {@code IS_}).  <em>Operation flags</em> are a unioned
+ * bit set constructed by ORing the enum characteristic values of {@link #set()}
+ * or {@link #clear()} (to inject, or clear, respectively, the corresponding
+ * flag), or more commonly ORing the corresponding named constants prefixed with
+ * {@code IS_} or {@code NOT_}.  Flags that are not marked with {@code IS_} or
+ * {@code NOT_} are implicitly treated as preserved.  Care must be taken when
+ * combining bitsets that the correct combining operations are applied in the
+ * correct order.
+ *
+ * <p>
+ * With the exception of {@link #SHORT_CIRCUIT}, stream characteristics can be
+ * derived from the equivalent {@link java.util.Spliterator} characteristics:
+ * {@link java.util.Spliterator#DISTINCT}, {@link java.util.Spliterator#SORTED},
+ * {@link java.util.Spliterator#ORDERED}, and
+ * {@link java.util.Spliterator#SIZED}.  A spliterator characteristics bit set
+ * can be converted to stream flags using the method
+ * {@link #fromCharacteristics(java.util.Spliterator)} and converted back using
+ * {@link #toCharacteristics(int)}.  (The bit set
+ * {@link #SPLITERATOR_CHARACTERISTICS_MASK} is used to AND with a bit set to
+ * produce a valid spliterator characteristics bit set that can be converted to
+ * stream flags.)
+ *
+ * <p>
+ * The source of a stream encapsulates a spliterator. The characteristics of
+ * that source spliterator when transformed to stream flags will be a proper
+ * subset of stream flags of that stream.
+ * For example:
+ * <pre> {@code
+ *     Spliterator s = ...;
+ *     Stream stream = Streams.stream(s);
+ *     flagsFromSplitr = fromCharacteristics(s.characteristics());
+ *     assert(flagsFromSplitr & stream.getStreamFlags() == flagsFromSplitr);
+ * }</pre>
+ *
+ * <p>
+ * An intermediate operation, performed on an input stream to create a new
+ * output stream, may preserve, clear or inject stream or operation
+ * characteristics.  Similarly, a terminal operation, performed on an input
+ * stream to produce an output result may preserve, clear or inject stream or
+ * operation characteristics.  Preservation means that if that characteristic
+ * is present on the input, then it is also present on the output.  Clearing
+ * means that the characteristic is not present on the output regardless of the
+ * input.  Injection means that the characteristic is present on the output
+ * regardless of the input.  If a characteristic is not cleared or injected then
+ * it is implicitly preserved.
+ *
+ * <p>
+ * A pipeline consists of a stream source encapsulating a spliterator, one or
+ * more intermediate operations, and finally a terminal operation that produces
+ * a result.  At each stage of the pipeline, a combined stream and operation
+ * flags can be calculated, using {@link #combineOpFlags(int, int)}.  Such flags
+ * ensure that preservation, clearing and injecting information is retained at
+ * each stage.
+ *
+ * The combined stream and operation flags for the source stage of the pipeline
+ * is calculated as follows:
+ * <pre> {@code
+ *     int flagsForSourceStage = combineOpFlags(sourceFlags, INITIAL_OPS_VALUE);
+ * }</pre>
+ *
+ * The combined stream and operation flags of each subsequent intermediate
+ * operation stage in the pipeline is calculated as follows:
+ * <pre> {@code
+ *     int flagsForThisStage = combineOpFlags(flagsForPreviousStage, thisOpFlags);
+ * }</pre>
+ *
+ * Finally the flags output from the last intermediate operation of the pipeline
+ * are combined with the operation flags of the terminal operation to produce
+ * the flags output from the pipeline.
+ *
+ * <p>Those flags can then be used to apply optimizations. For example, if
+ * {@code SIZED.isKnown(flags)} returns true then the stream size remains
+ * constant throughout the pipeline, this information can be utilized to
+ * pre-allocate data structures and combined with
+ * {@link java.util.Spliterator#SUBSIZED} that information can be utilized to
+ * perform concurrent in-place updates into a shared array.
+ *
+ * For specific details see the {@link AbstractPipeline} constructors.
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public enum StreamOpFlag {
+
+    /*
+     * Each characteristic takes up 2 bits in a bit set to accommodate
+     * preserving, clearing and setting/injecting information.
+     *
+     * This applies to stream flags, intermediate/terminal operation flags, and
+     * combined stream and operation flags. Even though the former only requires
+     * 1 bit of information per characteristic, is it more efficient when
+     * combining flags to align set and inject bits.
+     *
+     * Characteristics belong to certain types, see the Type enum. Bit masks for
+     * the types are constructed as per the following table:
+     *
+     *                        DISTINCT  SORTED  ORDERED  SIZED  SHORT_CIRCUIT
+     *          SPLITERATOR      01       01       01      01        00
+     *               STREAM      01       01       01      01        00
+     *                   OP      11       11       11      10        01
+     *          TERMINAL_OP      00       00       10      00        01
+     * UPSTREAM_TERMINAL_OP      00       00       10      00        00
+     *
+     * 01 = set/inject
+     * 10 = clear
+     * 11 = preserve
+     *
+     * Construction of the columns is performed using a simple builder for
+     * non-zero values.
+     */
+
+
+    // The following flags correspond to characteristics on Spliterator
+    // and the values MUST be equal.
+    //
+
+    /**
+     * Characteristic value signifying that, for each pair of
+     * encountered elements in a stream {@code x, y}, {@code !x.equals(y)}.
+     * <p>
+     * A stream may have this value or an intermediate operation can preserve,
+     * clear or inject this value.
+     */
+    // 0, 0x00000001
+    // Matches Spliterator.DISTINCT
+    DISTINCT(0,
+             set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
+
+    /**
+     * Characteristic value signifying that encounter order follows a natural
+     * sort order of comparable elements.
+     * <p>
+     * A stream can have this value or an intermediate operation can preserve,
+     * clear or inject this value.
+     * <p>
+     * Note: The {@link java.util.Spliterator#SORTED} characteristic can define
+     * a sort order with an associated non-null comparator.  Augmenting flag
+     * state with addition properties such that those properties can be passed
+     * to operations requires some disruptive changes for a singular use-case.
+     * Furthermore, comparing comparators for equality beyond that of identity
+     * is likely to be unreliable.  Therefore the {@code SORTED} characteristic
+     * for a defined non-natural sort order is not mapped internally to the
+     * {@code SORTED} flag.
+     */
+    // 1, 0x00000004
+    // Matches Spliterator.SORTED
+    SORTED(1,
+           set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP)),
+
+    /**
+     * Characteristic value signifying that an encounter order is
+     * defined for stream elements.
+     * <p>
+     * A stream can have this value, an intermediate operation can preserve,
+     * clear or inject this value, or a terminal operation can preserve or clear
+     * this value.
+     */
+    // 2, 0x00000010
+    // Matches Spliterator.ORDERED
+    ORDERED(2,
+            set(Type.SPLITERATOR).set(Type.STREAM).setAndClear(Type.OP).clear(Type.TERMINAL_OP)
+                    .clear(Type.UPSTREAM_TERMINAL_OP)),
+
+    /**
+     * Characteristic value signifying that size of the stream
+     * is of a known finite size that is equal to the known finite
+     * size of the source spliterator input to the first stream
+     * in the pipeline.
+     * <p>
+     * A stream can have this value or an intermediate operation can preserve or
+     * clear this value.
+     */
+    // 3, 0x00000040
+    // Matches Spliterator.SIZED
+    SIZED(3,
+          set(Type.SPLITERATOR).set(Type.STREAM).clear(Type.OP)),
+
+    // The following Spliterator characteristics are not currently used but a
+    // gap in the bit set is deliberately retained to enable corresponding
+    // stream flags if//when required without modification to other flag values.
+    //
+    // 4, 0x00000100 NONNULL(4, ...
+    // 5, 0x00000400 IMMUTABLE(5, ...
+    // 6, 0x00001000 CONCURRENT(6, ...
+    // 7, 0x00004000 SUBSIZED(7, ...
+
+    // The following 4 flags are currently undefined and a free for any further
+    // spliterator characteristics.
+    //
+    //  8, 0x00010000
+    //  9, 0x00040000
+    // 10, 0x00100000
+    // 11, 0x00400000
+
+    // The following flags are specific to streams and operations
+    //
+
+    /**
+     * Characteristic value signifying that an operation may short-circuit the
+     * stream.
+     * <p>
+     * An intermediate operation can preserve or inject this value,
+     * or a terminal operation can preserve or inject this value.
+     */
+    // 12, 0x01000000
+    SHORT_CIRCUIT(12,
+                  set(Type.OP).set(Type.TERMINAL_OP));
+
+    // The following 2 flags are currently undefined and a free for any further
+    // stream flags if/when required
+    //
+    // 13, 0x04000000
+    // 14, 0x10000000
+    // 15, 0x40000000
+
+    /**
+     * Type of a flag
+     */
+    enum Type {
+        /**
+         * The flag is associated with spliterator characteristics.
+         */
+        SPLITERATOR,
+
+        /**
+         * The flag is associated with stream flags.
+         */
+        STREAM,
+
+        /**
+         * The flag is associated with intermediate operation flags.
+         */
+        OP,
+
+        /**
+         * The flag is associated with terminal operation flags.
+         */
+        TERMINAL_OP,
+
+        /**
+         * The flag is associated with terminal operation flags that are
+         * propagated upstream across the last stateful operation boundary
+         */
+        UPSTREAM_TERMINAL_OP
+    }
+
+    /**
+     * The bit pattern for setting/injecting a flag.
+     */
+    private static final int SET_BITS = 0b01;
+
+    /**
+     * The bit pattern for clearing a flag.
+     */
+    private static final int CLEAR_BITS = 0b10;
+
+    /**
+     * The bit pattern for preserving a flag.
+     */
+    private static final int PRESERVE_BITS = 0b11;
+
+    private static MaskBuilder set(Type t) {
+        return new MaskBuilder(new EnumMap<>(Type.class)).set(t);
+    }
+
+    private static class MaskBuilder {
+        final Map<Type, Integer> map;
+
+        MaskBuilder(Map<Type, Integer> map) {
+            this.map = map;
+        }
+
+        MaskBuilder mask(Type t, Integer i) {
+            map.put(t, i);
+            return this;
+        }
+
+        MaskBuilder set(Type t) {
+            return mask(t, SET_BITS);
+        }
+
+        MaskBuilder clear(Type t) {
+            return mask(t, CLEAR_BITS);
+        }
+
+        MaskBuilder setAndClear(Type t) {
+            return mask(t, PRESERVE_BITS);
+        }
+
+        Map<Type, Integer> build() {
+            for (Type t : Type.values()) {
+                map.putIfAbsent(t, 0b00);
+            }
+            return map;
+        }
+    }
+
+    /**
+     * The mask table for a flag, this is used to determine if a flag
+     * corresponds to a certain flag type and for creating mask constants.
+     */
+    private final Map<Type, Integer> maskTable;
+
+    /**
+     * The bit position in the bit mask.
+     */
+    private final int bitPosition;
+
+    /**
+     * The set 2 bit set offset at the bit position.
+     */
+    private final int set;
+
+    /**
+     * The clear 2 bit set offset at the bit position.
+     */
+    private final int clear;
+
+    /**
+     * The preserve 2 bit set offset at the bit position.
+     */
+    private final int preserve;
+
+    private StreamOpFlag(int position, MaskBuilder maskBuilder) {
+        this.maskTable = maskBuilder.build();
+        // Two bits per flag
+        position *= 2;
+        this.bitPosition = position;
+        this.set = SET_BITS << position;
+        this.clear = CLEAR_BITS << position;
+        this.preserve = PRESERVE_BITS << position;
+    }
+
+    /**
+     * Gets the bitmap associated with setting this characteristic.
+     *
+     * @return the bitmap for setting this characteristic
+     */
+    // Android-changed: Made public for CTS tests only.
+    public int set() {
+        return set;
+    }
+
+    /**
+     * Gets the bitmap associated with clearing this characteristic.
+     *
+     * @return the bitmap for clearing this characteristic
+     */
+    // Android-changed: Made public for CTS tests only.
+    public int clear() {
+        return clear;
+    }
+
+    /**
+     * Determines if this flag is a stream-based flag.
+     *
+     * @return true if a stream-based flag, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isStreamFlag() {
+        return maskTable.get(Type.STREAM) > 0;
+    }
+
+    /**
+     * Checks if this flag is set on stream flags, injected on operation flags,
+     * and injected on combined stream and operation flags.
+     *
+     * @param flags the stream flags, operation flags, or combined stream and
+     *        operation flags
+     * @return true if this flag is known, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isKnown(int flags) {
+        return (flags & preserve) == set;
+    }
+
+    /**
+     * Checks if this flag is cleared on operation flags or combined stream and
+     * operation flags.
+     *
+     * @param flags the operation flags or combined stream and operations flags.
+     * @return true if this flag is preserved, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isCleared(int flags) {
+        return (flags & preserve) == clear;
+    }
+
+    /**
+     * Checks if this flag is preserved on combined stream and operation flags.
+     *
+     * @param flags the combined stream and operations flags.
+     * @return true if this flag is preserved, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean isPreserved(int flags) {
+        return (flags & preserve) == preserve;
+    }
+
+    /**
+     * Determines if this flag can be set for a flag type.
+     *
+     * @param t the flag type.
+     * @return true if this flag can be set for the flag type, otherwise false.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public boolean canSet(Type t) {
+        return (maskTable.get(t) & SET_BITS) > 0;
+    }
+
+    /**
+     * The bit mask for spliterator characteristics
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int SPLITERATOR_CHARACTERISTICS_MASK = createMask(Type.SPLITERATOR);
+
+    /**
+     * The bit mask for source stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int STREAM_MASK = createMask(Type.STREAM);
+
+    /**
+     * The bit mask for intermediate operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int OP_MASK = createMask(Type.OP);
+
+    /**
+     * The bit mask for terminal operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int TERMINAL_OP_MASK = createMask(Type.TERMINAL_OP);
+
+    /**
+     * The bit mask for upstream terminal operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int UPSTREAM_TERMINAL_OP_MASK = createMask(Type.UPSTREAM_TERMINAL_OP);
+
+    private static int createMask(Type t) {
+        int mask = 0;
+        for (StreamOpFlag flag : StreamOpFlag.values()) {
+            mask |= flag.maskTable.get(t) << flag.bitPosition;
+        }
+        return mask;
+    }
+
+    /**
+     * Complete flag mask.
+     */
+    private static final int FLAG_MASK = createFlagMask();
+
+    private static int createFlagMask() {
+        int mask = 0;
+        for (StreamOpFlag flag : StreamOpFlag.values()) {
+            mask |= flag.preserve;
+        }
+        return mask;
+    }
+
+    /**
+     * Flag mask for stream flags that are set.
+     */
+    private static final int FLAG_MASK_IS = STREAM_MASK;
+
+    /**
+     * Flag mask for stream flags that are cleared.
+     */
+    private static final int FLAG_MASK_NOT = STREAM_MASK << 1;
+
+    /**
+     * The initial value to be combined with the stream flags of the first
+     * stream in the pipeline.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int INITIAL_OPS_VALUE = FLAG_MASK_IS | FLAG_MASK_NOT;
+
+    /**
+     * The bit value to set or inject {@link #DISTINCT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_DISTINCT = DISTINCT.set;
+
+    /**
+     * The bit value to clear {@link #DISTINCT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_DISTINCT = DISTINCT.clear;
+
+    /**
+     * The bit value to set or inject {@link #SORTED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SORTED = SORTED.set;
+
+    /**
+     * The bit value to clear {@link #SORTED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_SORTED = SORTED.clear;
+
+    /**
+     * The bit value to set or inject {@link #ORDERED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_ORDERED = ORDERED.set;
+
+    /**
+     * The bit value to clear {@link #ORDERED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_ORDERED = ORDERED.clear;
+
+    /**
+     * The bit value to set {@link #SIZED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SIZED = SIZED.set;
+
+    /**
+     * The bit value to clear {@link #SIZED}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int NOT_SIZED = SIZED.clear;
+
+    /**
+     * The bit value to inject {@link #SHORT_CIRCUIT}.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
+
+    private static int getMask(int flags) {
+        return (flags == 0)
+               ? FLAG_MASK
+               : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
+    }
+
+    /**
+     * Combines stream or operation flags with previously combined stream and
+     * operation flags to produce updated combined stream and operation flags.
+     * <p>
+     * A flag set on stream flags or injected on operation flags,
+     * and injected combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag set on stream flags or injected on operation flags,
+     * and cleared on the combined stream and operation flags,
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag set on the stream flags or injected on operation flags,
+     * and preserved on the combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags or cleared/preserved on operation
+     * flags, and injected on the combined stream and operation flags,
+     * will be injected on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags or cleared/preserved on operation
+     * flags, and cleared on the combined stream and operation flags,
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag not set on the stream flags,
+     * and preserved on the combined stream and operation flags
+     * will be preserved on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag cleared on operation flags,
+     * and preserved on the combined stream and operation flags
+     * will be cleared on the updated combined stream and operation flags.
+     *
+     * <p>
+     * A flag preserved on operation flags,
+     * and preserved on the combined stream and operation flags
+     * will be preserved on the updated combined stream and operation flags.
+     *
+     * @param newStreamOrOpFlags the stream or operation flags.
+     * @param prevCombOpFlags previously combined stream and operation flags.
+     *        The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
+     * @return the updated combined stream and operation flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int combineOpFlags(int newStreamOrOpFlags, int prevCombOpFlags) {
+        // 0x01 or 0x10 nibbles are transformed to 0x11
+        // 0x00 nibbles remain unchanged
+        // Then all the bits are flipped
+        // Then the result is logically or'ed with the operation flags.
+        return (prevCombOpFlags & StreamOpFlag.getMask(newStreamOrOpFlags)) | newStreamOrOpFlags;
+    }
+
+    /**
+     * Converts combined stream and operation flags to stream flags.
+     *
+     * <p>Each flag injected on the combined stream and operation flags will be
+     * set on the stream flags.
+     *
+     * @param combOpFlags the combined stream and operation flags.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int toStreamFlags(int combOpFlags) {
+        // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
+        // Shift left 1 to restore set flags and mask off anything other than the set flags
+        return ((~combOpFlags) >> 1) & FLAG_MASK_IS & combOpFlags;
+    }
+
+    /**
+     * Converts stream flags to a spliterator characteristic bit set.
+     *
+     * @param streamFlags the stream flags.
+     * @return the spliterator characteristic bit set.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int toCharacteristics(int streamFlags) {
+        return streamFlags & SPLITERATOR_CHARACTERISTICS_MASK;
+    }
+
+    /**
+     * Converts a spliterator characteristic bit set to stream flags.
+     *
+     * @implSpec
+     * If the spliterator is naturally {@code SORTED} (the associated
+     * {@code Comparator} is {@code null}) then the characteristic is converted
+     * to the {@link #SORTED} flag, otherwise the characteristic is not
+     * converted.
+     *
+     * @param spliterator the spliterator from which to obtain characteristic
+     *        bit set.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int fromCharacteristics(Spliterator<?> spliterator) {
+        int characteristics = spliterator.characteristics();
+        if ((characteristics & Spliterator.SORTED) != 0 && spliterator.getComparator() != null) {
+            // Do not propagate the SORTED characteristic if it does not correspond
+            // to a natural sort order
+            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK & ~Spliterator.SORTED;
+        }
+        else {
+            return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
+        }
+    }
+
+    /**
+     * Converts a spliterator characteristic bit set to stream flags.
+     *
+     * @param characteristics the spliterator characteristic bit set.
+     * @return the stream flags.
+     */
+    // Android-changed: Made public for CTS tests only.
+    public static int fromCharacteristics(int characteristics) {
+        return characteristics & SPLITERATOR_CHARACTERISTICS_MASK;
+    }
+}
diff --git a/java/util/stream/StreamOpFlagTestHelper.java b/java/util/stream/StreamOpFlagTestHelper.java
new file mode 100644
index 0000000..11ed0f1
--- /dev/null
+++ b/java/util/stream/StreamOpFlagTestHelper.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.EnumSet;
+
+public class StreamOpFlagTestHelper {
+
+    /** EnumSet containing stream flags */
+    private static final EnumSet<StreamOpFlag> allStreamFlags;
+
+    static {
+        allStreamFlags = EnumSet.allOf(StreamOpFlag.class);
+        for (StreamOpFlag f : EnumSet.allOf(StreamOpFlag.class))
+            if (!f.isStreamFlag())
+                allStreamFlags.remove(f);
+    }
+
+
+    static EnumSet<StreamOpFlag> allStreamFlags() {
+        // EnumSet is mutable
+        return allStreamFlags.clone();
+    }
+
+    public static boolean isStreamOrdered(Stream<?> s) {
+        return StreamOpFlag.ORDERED.isKnown(OpTestCase.getStreamFlags(s));
+    }
+}
diff --git a/java/util/stream/StreamOpFlagsTest.java b/java/util/stream/StreamOpFlagsTest.java
new file mode 100644
index 0000000..aa47aa2
--- /dev/null
+++ b/java/util/stream/StreamOpFlagsTest.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
+
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.StreamOpFlag.*;
+import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+
+@Test
+public class StreamOpFlagsTest {
+
+    public void testNullCombine() {
+        int sourceFlags = StreamOpFlag.IS_SIZED;
+
+        assertEquals(sourceFlags, toStreamFlags(combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE)));
+    }
+
+    public void testInitialOpFlagsFromSourceFlags() {
+        List<StreamOpFlag> flags = new ArrayList<>(StreamOpFlagTestHelper.allStreamFlags());
+        for (int i = 0; i < (1 << flags.size()); i++)  {
+            int sourceFlags = 0;
+            for (int f = 0; f < flags.size(); f++) {
+                if ((i & (1 << f)) != 0)  {
+                    sourceFlags |= flags.get(f).set();
+                }
+            }
+
+            int opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            assertEquals(opsFlags, (~(sourceFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE);
+        }
+    }
+
+    public void testSameCombine() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            int sourceFlags = f.set();
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testOpClear() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            // Clear when source not set
+            int sourceFlags = 0;
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.clear(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+
+            // Clear when source set
+            sourceFlags = f.set();
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.clear(), opsFlags);
+            assertEquals(0, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testOpInject() {
+        for (StreamOpFlag f : StreamOpFlagTestHelper.allStreamFlags()) {
+            // Set when source not set
+            int sourceFlags = 0;
+            int opsFlags;
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(f.set(), toStreamFlags(opsFlags));
+
+            // Set when source set
+            sourceFlags = f.set();
+
+            opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+            opsFlags = combineOpFlags(f.set(), opsFlags);
+            assertEquals(sourceFlags, toStreamFlags(opsFlags));
+        }
+    }
+
+    public void testPairSet() {
+        List<Integer> sourceFlagsList
+                = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+        sourceFlagsList.add(0, 0);
+
+        for (int sourceFlags : sourceFlagsList) {
+            for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags()) {
+                for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+                    int opsFlags;
+
+                    opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+                    opsFlags = combineOpFlags(f1.set(), opsFlags);
+                    opsFlags = combineOpFlags(f2.set(), opsFlags);
+                    assertEquals(sourceFlags | f1.set() | f2.set(), toStreamFlags(opsFlags));
+                }
+            }
+        }
+    }
+
+    public void testPairSetAndClear() {
+        List<Integer> sourceFlagsList
+                = StreamOpFlagTestHelper.allStreamFlags().stream().map(StreamOpFlag::set).collect(toList());
+        sourceFlagsList.add(0, 0);
+
+        for (int sourceFlags : sourceFlagsList) {
+            for (StreamOpFlag f1 : StreamOpFlagTestHelper.allStreamFlags())  {
+                for (StreamOpFlag f2 : StreamOpFlagTestHelper.allStreamFlags()) {
+                    int opsFlags;
+
+                    opsFlags = combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+                    opsFlags = combineOpFlags(f1.set(), opsFlags);
+                    opsFlags = combineOpFlags(f2.clear(), opsFlags);
+                    if (f1 == f2)
+                        assertEquals((f2.set() == sourceFlags) ? 0 : sourceFlags, toStreamFlags(opsFlags));
+                    else
+                        assertEquals((f2.set() == sourceFlags) ? f1.set() : sourceFlags | f1.set(), toStreamFlags(opsFlags));
+                }
+            }
+        }
+    }
+
+    public void testShortCircuit() {
+        int opsFlags = combineOpFlags(0, StreamOpFlag.INITIAL_OPS_VALUE);
+        assertFalse(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+        opsFlags = combineOpFlags(StreamOpFlag.IS_SHORT_CIRCUIT, opsFlags);
+        assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+
+        opsFlags = combineOpFlags(0, opsFlags);
+        assertTrue(StreamOpFlag.SHORT_CIRCUIT.isKnown(opsFlags));
+    }
+
+    public void testApplySourceFlags() {
+        int sourceFlags = StreamOpFlag.IS_SIZED | StreamOpFlag.IS_DISTINCT;
+
+        List<Integer> ops = Arrays.asList(StreamOpFlag.NOT_SIZED, StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SORTED);
+
+        int opsFlags = StreamOpFlag.combineOpFlags(sourceFlags, StreamOpFlag.INITIAL_OPS_VALUE);
+        for (int opFlags : ops) {
+            opsFlags = combineOpFlags(opFlags, opsFlags);
+        }
+        assertFalse(StreamOpFlag.SIZED.isKnown(opsFlags));
+        assertTrue(StreamOpFlag.SIZED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.SIZED.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.DISTINCT.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.DISTINCT.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.DISTINCT.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.SORTED.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.SORTED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.SORTED.isPreserved(opsFlags));
+        assertTrue(StreamOpFlag.ORDERED.isKnown(opsFlags));
+        assertFalse(StreamOpFlag.ORDERED.isCleared(opsFlags));
+        assertFalse(StreamOpFlag.ORDERED.isPreserved(opsFlags));
+
+        int streamFlags = toStreamFlags(opsFlags);
+        assertFalse(StreamOpFlag.SIZED.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.DISTINCT.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.SORTED.isKnown(streamFlags));
+        assertTrue(StreamOpFlag.ORDERED.isKnown(streamFlags));
+    }
+
+    public void testSpliteratorMask() {
+        assertSpliteratorMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertSpliteratorMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertSpliteratorMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertSpliteratorMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertSpliteratorMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertSpliteratorMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertSpliteratorMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.SPLITERATOR_CHARACTERISTICS_MASK, expected);
+    }
+
+    public void testStreamMask() {
+        assertStreamMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertStreamMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertStreamMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertStreamMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertStreamMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertStreamMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertStreamMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.STREAM_MASK, expected);
+    }
+
+    public void testOpMask() {
+        assertOpMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertOpMask(StreamOpFlag.DISTINCT.clear(), StreamOpFlag.NOT_DISTINCT);
+
+        assertOpMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertOpMask(StreamOpFlag.SORTED.clear(), StreamOpFlag.NOT_SORTED);
+
+        assertOpMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertOpMask(StreamOpFlag.SIZED.clear(), StreamOpFlag.NOT_SIZED);
+
+        assertOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+        assertOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.OP_MASK, expected);
+    }
+
+    public void testTerminalOpMask() {
+        assertTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), StreamOpFlag.IS_SHORT_CIRCUIT);
+        assertTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertTerminalOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.TERMINAL_OP_MASK, expected);
+    }
+
+    public void testUpstreamTerminalOpMask() {
+        assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.ORDERED.clear(), StreamOpFlag.NOT_ORDERED);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertUpstreamTerminalOpMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertUpstreamTerminalOpMask(int actual, int expected) {
+        assertEquals(actual & StreamOpFlag.UPSTREAM_TERMINAL_OP_MASK, expected);
+    }
+
+    public void testSpliteratorCharacteristics() {
+        assertEquals(Spliterator.DISTINCT, StreamOpFlag.IS_DISTINCT);
+        assertEquals(Spliterator.SORTED, StreamOpFlag.IS_SORTED);
+        assertEquals(Spliterator.ORDERED, StreamOpFlag.IS_ORDERED);
+        assertEquals(Spliterator.SIZED, StreamOpFlag.IS_SIZED);
+
+        List<Integer> others = Arrays.asList(Spliterator.NONNULL, Spliterator.IMMUTABLE,
+                                             Spliterator.CONCURRENT, Spliterator.SUBSIZED);
+        for (int c : others) {
+            assertNotEquals(c, StreamOpFlag.IS_SHORT_CIRCUIT);
+        }
+    }
+
+    public void testSpliteratorCharacteristicsMask() {
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.set(), StreamOpFlag.IS_DISTINCT);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.DISTINCT.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.set(), StreamOpFlag.IS_SORTED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SORTED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.set(), StreamOpFlag.IS_ORDERED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.ORDERED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.set(), StreamOpFlag.IS_SIZED);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SIZED.clear(), 0);
+
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.set(), 0);
+        assertSpliteratorCharacteristicsMask(StreamOpFlag.SHORT_CIRCUIT.clear(), 0);
+    }
+
+    private void assertSpliteratorCharacteristicsMask(int actual, int expected) {
+        assertEquals(StreamOpFlag.fromCharacteristics(actual), expected);
+    }
+
+    public void testSpliteratorSorted() {
+        class SortedEmptySpliterator implements Spliterator<Object> {
+            final Comparator<Object> c;
+
+            SortedEmptySpliterator(Comparator<Object> c) {
+                this.c = c;
+            }
+
+            @Override
+            public Spliterator<Object> trySplit() {
+                return null;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super Object> action) {
+                return false;
+            }
+
+            @Override
+            public long estimateSize() {
+                return Long.MAX_VALUE;
+            }
+
+            @Override
+            public int characteristics() {
+                return Spliterator.SORTED;
+            }
+
+            @Override
+            public Comparator<? super Object> getComparator() {
+                return c;
+            }
+        };
+
+        {
+            int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator(null));
+            assertEquals(flags, StreamOpFlag.IS_SORTED);
+        }
+
+        {
+            int flags = StreamOpFlag.fromCharacteristics(new SortedEmptySpliterator((a, b) -> 0));
+            assertEquals(flags, 0);
+        }
+    }
+}
diff --git a/java/util/stream/StreamReuseTest.java b/java/util/stream/StreamReuseTest.java
new file mode 100644
index 0000000..0ac9d68
--- /dev/null
+++ b/java/util/stream/StreamReuseTest.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.Test;
+
+import java.util.function.Function;
+
+import static org.testng.Assert.fail;
+
+/**
+ * StreamReuseTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class StreamReuseTest {
+
+    private <T, U, E, S extends BaseStream<E, S>, D extends TestData<E, S>> void assertSecondFails(
+            D data,
+            Function<S, T> first,
+            Function<S, U> second,
+            Class<? extends Throwable> exception,
+            String text) {
+        S stream = data.stream();
+        T fr = first.apply(stream);
+        try {
+            U sr = second.apply(stream);
+            fail(text + " (seq)");
+        }
+        catch (Throwable e) {
+            if (exception.isAssignableFrom(e.getClass())) {
+                // Expected
+            }
+            else if (e instanceof Error)
+                throw (Error) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new AssertionError("Unexpected exception " + e.getClass(), e);
+        }
+
+        stream = data.parallelStream();
+        fr = first.apply(stream);
+        try {
+            U sr = second.apply(stream);
+            fail(text + " (par)");
+        }
+        catch (Throwable e) {
+            if (exception.isAssignableFrom(e.getClass())) {
+                // Expected
+            }
+            else if (e instanceof Error)
+                throw (Error) e;
+            else if (e instanceof RuntimeException)
+                throw (RuntimeException) e;
+            else
+                throw new AssertionError("Unexpected exception " + e.getClass(), e);
+        }
+    }
+
+    // Stream
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream findFirst / findFirst succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::findFirst, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream findFirst / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream map / findFirst succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream findFirst / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream distinct / findFirst succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, Stream::findFirst,
+                          IllegalStateException.class,
+                          "Stream iterator / findFirst succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::findFirst, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream findFirst / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData<Integer, Stream<Integer>> data) {
+        assertSecondFails(data,
+                          Stream::iterator, (Stream<Integer> s) -> s.map(i -> i),
+                          IllegalStateException.class,
+                          "Stream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (Stream<Integer> s) -> s.map(i -> i), Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::iterator, Stream::distinct,
+                          IllegalStateException.class,
+                          "Stream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          Stream::distinct, Stream::iterator,
+                          IllegalStateException.class,
+                          "Stream distinct / iterator succeeded erroneously");
+    }
+
+    // IntStream
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::sum, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::sum,
+                          IllegalStateException.class,
+                          "IntStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::sum, IntStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfInt data) {
+        assertSecondFails(data,
+                          IntStream::iterator, (IntStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "IntStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (IntStream s) -> s.mapToObj(i -> i), IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::iterator, IntStream::distinct,
+                          IllegalStateException.class,
+                          "IntStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          IntStream::distinct, IntStream::iterator,
+                          IllegalStateException.class,
+                          "IntStream distinct / iterator succeeded erroneously");
+    }
+
+    // LongStream
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::sum, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::sum,
+                          IllegalStateException.class,
+                          "LongStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::sum, LongStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "LongStreamTestData", dataProviderClass = LongStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfLong data) {
+        assertSecondFails(data,
+                          LongStream::iterator, (LongStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "LongStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (LongStream s) -> s.mapToObj(i -> i), LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::iterator, LongStream::distinct,
+                          IllegalStateException.class,
+                          "LongStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          LongStream::distinct, LongStream::iterator,
+                          IllegalStateException.class,
+                          "LongStream distinct / iterator succeeded erroneously");
+    }
+
+    // DoubleStream
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoStreams(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream map / map succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream distinct / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream map / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / distinct succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoTerminals(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream sum / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTerminalStream(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::sum, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream sum / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream map / sum succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream sum / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / sum succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTwoIterators(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testTerminalIterator(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::sum,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / sum succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::sum, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "Stream sum / iterator succeeded erroneously");
+    }
+
+    @Test(dataProvider = "DoubleStreamTestData", dataProviderClass = DoubleStreamTestDataProvider.class)
+    public void testStreamIterator(String name, TestData.OfDouble data) {
+        assertSecondFails(data,
+                          DoubleStream::iterator, (DoubleStream s) -> s.mapToObj(i -> i),
+                          IllegalStateException.class,
+                          "DoubleStream iterator / map succeeded erroneously");
+        assertSecondFails(data,
+                          (DoubleStream s) -> s.mapToObj(i -> i), DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream map / iterator succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::iterator, DoubleStream::distinct,
+                          IllegalStateException.class,
+                          "DoubleStream iterator / distinct succeeded erroneously");
+        assertSecondFails(data,
+                          DoubleStream::distinct, DoubleStream::iterator,
+                          IllegalStateException.class,
+                          "DoubleStream distinct / iterator succeeded erroneously");
+    }
+}
diff --git a/java/util/stream/StreamShape.java b/java/util/stream/StreamShape.java
new file mode 100644
index 0000000..5bcae4a
--- /dev/null
+++ b/java/util/stream/StreamShape.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An enum describing the known shape specializations for stream abstractions.
+ * Each will correspond to a specific subinterface of {@link BaseStream}
+ * (e.g., {@code REFERENCE} corresponds to {@code Stream}, {@code INT_VALUE}
+ * corresponds to {@code IntStream}).  Each may also correspond to
+ * specializations of value-handling abstractions such as {@code Spliterator},
+ * {@code Consumer}, etc.
+ *
+ * @apiNote
+ * This enum is used by implementations to determine compatibility between
+ * streams and operations (i.e., if the output shape of a stream is compatible
+ * with the input shape of the next operation).
+ *
+ * <p>Some APIs require you to specify both a generic type and a stream shape
+ * for input or output elements, such as {@link TerminalOp} which has both
+ * generic type parameters for its input types, and a getter for the
+ * input shape.  When representing primitive streams in this way, the
+ * generic type parameter should correspond to the wrapper type for that
+ * primitive type.
+ *
+ * @since 1.8
+ * @hide Visible for CTS testing only (OpenJDK8 tests).
+ */
+// Android-changed: Made public for CTS tests only.
+public enum StreamShape {
+    /**
+     * The shape specialization corresponding to {@code Stream} and elements
+     * that are object references.
+     */
+    REFERENCE,
+    /**
+     * The shape specialization corresponding to {@code IntStream} and elements
+     * that are {@code int} values.
+     */
+    INT_VALUE,
+    /**
+     * The shape specialization corresponding to {@code LongStream} and elements
+     * that are {@code long} values.
+     */
+    LONG_VALUE,
+    /**
+     * The shape specialization corresponding to {@code DoubleStream} and
+     * elements that are {@code double} values.
+     */
+    DOUBLE_VALUE
+}
diff --git a/java/util/stream/StreamSpliterators.java b/java/util/stream/StreamSpliterators.java
new file mode 100644
index 0000000..6768342
--- /dev/null
+++ b/java/util/stream/StreamSpliterators.java
@@ -0,0 +1,1548 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BooleanSupplier;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.DoubleSupplier;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+/**
+ * Spliterator implementations for wrapping and delegating spliterators, used
+ * in the implementation of the {@link Stream#spliterator()} method.
+ *
+ * @since 1.8
+ */
+class StreamSpliterators {
+
+    /**
+     * Abstract wrapping spliterator that binds to the spliterator of a
+     * pipeline helper on first operation.
+     *
+     * <p>This spliterator is not late-binding and will bind to the source
+     * spliterator when first operated on.
+     *
+     * <p>A wrapping spliterator produced from a sequential stream
+     * cannot be split if there are stateful operations present.
+     */
+    private static abstract class AbstractWrappingSpliterator<P_IN, P_OUT,
+                                                              T_BUFFER extends AbstractSpinedBuffer>
+            implements Spliterator<P_OUT> {
+
+        // @@@ Detect if stateful operations are present or not
+        //     If not then can split otherwise cannot
+
+        /**
+         * True if this spliterator supports splitting
+         */
+        final boolean isParallel;
+
+        final PipelineHelper<P_OUT> ph;
+
+        /**
+         * Supplier for the source spliterator.  Client provides either a
+         * spliterator or a supplier.
+         */
+        private Supplier<Spliterator<P_IN>> spliteratorSupplier;
+
+        /**
+         * Source spliterator.  Either provided from client or obtained from
+         * supplier.
+         */
+        Spliterator<P_IN> spliterator;
+
+        /**
+         * Sink chain for the downstream stages of the pipeline, ultimately
+         * leading to the buffer. Used during partial traversal.
+         */
+        Sink<P_IN> bufferSink;
+
+        /**
+         * A function that advances one element of the spliterator, pushing
+         * it to bufferSink.  Returns whether any elements were processed.
+         * Used during partial traversal.
+         */
+        BooleanSupplier pusher;
+
+        /** Next element to consume from the buffer, used during partial traversal */
+        long nextToConsume;
+
+        /** Buffer into which elements are pushed.  Used during partial traversal. */
+        T_BUFFER buffer;
+
+        /**
+         * True if full traversal has occurred (with possible cancelation).
+         * If doing a partial traversal, there may be still elements in buffer.
+         */
+        boolean finished;
+
+        /**
+         * Construct an AbstractWrappingSpliterator from a
+         * {@code Supplier<Spliterator>}.
+         */
+        AbstractWrappingSpliterator(PipelineHelper<P_OUT> ph,
+                                    Supplier<Spliterator<P_IN>> spliteratorSupplier,
+                                    boolean parallel) {
+            this.ph = ph;
+            this.spliteratorSupplier = spliteratorSupplier;
+            this.spliterator = null;
+            this.isParallel = parallel;
+        }
+
+        /**
+         * Construct an AbstractWrappingSpliterator from a
+         * {@code Spliterator}.
+         */
+        AbstractWrappingSpliterator(PipelineHelper<P_OUT> ph,
+                                    Spliterator<P_IN> spliterator,
+                                    boolean parallel) {
+            this.ph = ph;
+            this.spliteratorSupplier = null;
+            this.spliterator = spliterator;
+            this.isParallel = parallel;
+        }
+
+        /**
+         * Called before advancing to set up spliterator, if needed.
+         */
+        final void init() {
+            if (spliterator == null) {
+                spliterator = spliteratorSupplier.get();
+                spliteratorSupplier = null;
+            }
+        }
+
+        /**
+         * Get an element from the source, pushing it into the sink chain,
+         * setting up the buffer if needed
+         * @return whether there are elements to consume from the buffer
+         */
+        final boolean doAdvance() {
+            if (buffer == null) {
+                if (finished)
+                    return false;
+
+                init();
+                initPartialTraversalState();
+                nextToConsume = 0;
+                bufferSink.begin(spliterator.getExactSizeIfKnown());
+                return fillBuffer();
+            }
+            else {
+                ++nextToConsume;
+                boolean hasNext = nextToConsume < buffer.count();
+                if (!hasNext) {
+                    nextToConsume = 0;
+                    buffer.clear();
+                    hasNext = fillBuffer();
+                }
+                return hasNext;
+            }
+        }
+
+        /**
+         * Invokes the shape-specific constructor with the provided arguments
+         * and returns the result.
+         */
+        abstract AbstractWrappingSpliterator<P_IN, P_OUT, ?> wrap(Spliterator<P_IN> s);
+
+        /**
+         * Initializes buffer, sink chain, and pusher for a shape-specific
+         * implementation.
+         */
+        abstract void initPartialTraversalState();
+
+        @Override
+        public Spliterator<P_OUT> trySplit() {
+            if (isParallel && !finished) {
+                init();
+
+                Spliterator<P_IN> split = spliterator.trySplit();
+                return (split == null) ? null : wrap(split);
+            }
+            else
+                return null;
+        }
+
+        /**
+         * If the buffer is empty, push elements into the sink chain until
+         * the source is empty or cancellation is requested.
+         * @return whether there are elements to consume from the buffer
+         */
+        private boolean fillBuffer() {
+            while (buffer.count() == 0) {
+                if (bufferSink.cancellationRequested() || !pusher.getAsBoolean()) {
+                    if (finished)
+                        return false;
+                    else {
+                        bufferSink.end(); // might trigger more elements
+                        finished = true;
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public final long estimateSize() {
+            init();
+            // Use the estimate of the wrapped spliterator
+            // Note this may not be accurate if there are filter/flatMap
+            // operations filtering or adding elements to the stream
+            return spliterator.estimateSize();
+        }
+
+        @Override
+        public final long getExactSizeIfKnown() {
+            init();
+            return StreamOpFlag.SIZED.isKnown(ph.getStreamAndOpFlags())
+                   ? spliterator.getExactSizeIfKnown()
+                   : -1;
+        }
+
+        @Override
+        public final int characteristics() {
+            init();
+
+            // Get the characteristics from the pipeline
+            int c = StreamOpFlag.toCharacteristics(StreamOpFlag.toStreamFlags(ph.getStreamAndOpFlags()));
+
+            // Mask off the size and uniform characteristics and replace with
+            // those of the spliterator
+            // Note that a non-uniform spliterator can change from something
+            // with an exact size to an estimate for a sub-split, for example
+            // with HashSet where the size is known at the top level spliterator
+            // but for sub-splits only an estimate is known
+            if ((c & Spliterator.SIZED) != 0) {
+                c &= ~(Spliterator.SIZED | Spliterator.SUBSIZED);
+                c |= (spliterator.characteristics() & (Spliterator.SIZED | Spliterator.SUBSIZED));
+            }
+
+            return c;
+        }
+
+        @Override
+        public Comparator<? super P_OUT> getComparator() {
+            if (!hasCharacteristics(SORTED))
+                throw new IllegalStateException();
+            return null;
+        }
+
+        @Override
+        public final String toString() {
+            return String.format("%s[%s]", getClass().getName(), spliterator);
+        }
+    }
+
+    static final class WrappingSpliterator<P_IN, P_OUT>
+            extends AbstractWrappingSpliterator<P_IN, P_OUT, SpinedBuffer<P_OUT>> {
+
+        WrappingSpliterator(PipelineHelper<P_OUT> ph,
+                            Supplier<Spliterator<P_IN>> supplier,
+                            boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        WrappingSpliterator(PipelineHelper<P_OUT> ph,
+                            Spliterator<P_IN> spliterator,
+                            boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        WrappingSpliterator<P_IN, P_OUT> wrap(Spliterator<P_IN> s) {
+            return new WrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer<P_OUT> b = new SpinedBuffer<>();
+            buffer = b;
+            bufferSink = ph.wrapSink(b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super P_OUT> consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super P_OUT> consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink<P_OUT>) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class IntWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Integer, SpinedBuffer.OfInt>
+            implements Spliterator.OfInt {
+
+        IntWrappingSpliterator(PipelineHelper<Integer> ph,
+                               Supplier<Spliterator<P_IN>> supplier,
+                               boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        IntWrappingSpliterator(PipelineHelper<Integer> ph,
+                               Spliterator<P_IN> spliterator,
+                               boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Integer, ?> wrap(Spliterator<P_IN> s) {
+            return new IntWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfInt b = new SpinedBuffer.OfInt();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfInt) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            return (Spliterator.OfInt) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfInt) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class LongWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Long, SpinedBuffer.OfLong>
+            implements Spliterator.OfLong {
+
+        LongWrappingSpliterator(PipelineHelper<Long> ph,
+                                Supplier<Spliterator<P_IN>> supplier,
+                                boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        LongWrappingSpliterator(PipelineHelper<Long> ph,
+                                Spliterator<P_IN> spliterator,
+                                boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Long, ?> wrap(Spliterator<P_IN> s) {
+            return new LongWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfLong b = new SpinedBuffer.OfLong();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfLong) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            return (Spliterator.OfLong) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfLong) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    static final class DoubleWrappingSpliterator<P_IN>
+            extends AbstractWrappingSpliterator<P_IN, Double, SpinedBuffer.OfDouble>
+            implements Spliterator.OfDouble {
+
+        DoubleWrappingSpliterator(PipelineHelper<Double> ph,
+                                  Supplier<Spliterator<P_IN>> supplier,
+                                  boolean parallel) {
+            super(ph, supplier, parallel);
+        }
+
+        DoubleWrappingSpliterator(PipelineHelper<Double> ph,
+                                  Spliterator<P_IN> spliterator,
+                                  boolean parallel) {
+            super(ph, spliterator, parallel);
+        }
+
+        @Override
+        AbstractWrappingSpliterator<P_IN, Double, ?> wrap(Spliterator<P_IN> s) {
+            return new DoubleWrappingSpliterator<>(ph, s, isParallel);
+        }
+
+        @Override
+        void initPartialTraversalState() {
+            SpinedBuffer.OfDouble b = new SpinedBuffer.OfDouble();
+            buffer = b;
+            bufferSink = ph.wrapSink((Sink.OfDouble) b::accept);
+            pusher = () -> spliterator.tryAdvance(bufferSink);
+        }
+
+        @Override
+        public Spliterator.OfDouble trySplit() {
+            return (Spliterator.OfDouble) super.trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            Objects.requireNonNull(consumer);
+            boolean hasNext = doAdvance();
+            if (hasNext)
+                consumer.accept(buffer.get(nextToConsume));
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (buffer == null && !finished) {
+                Objects.requireNonNull(consumer);
+                init();
+
+                ph.wrapAndCopyInto((Sink.OfDouble) consumer::accept, spliterator);
+                finished = true;
+            }
+            else {
+                do { } while (tryAdvance(consumer));
+            }
+        }
+    }
+
+    /**
+     * Spliterator implementation that delegates to an underlying spliterator,
+     * acquiring the spliterator from a {@code Supplier<Spliterator>} on the
+     * first call to any spliterator method.
+     * @param <T>
+     */
+    static class DelegatingSpliterator<T, T_SPLITR extends Spliterator<T>>
+            implements Spliterator<T> {
+        private final Supplier<? extends T_SPLITR> supplier;
+
+        private T_SPLITR s;
+
+        DelegatingSpliterator(Supplier<? extends T_SPLITR> supplier) {
+            this.supplier = supplier;
+        }
+
+        T_SPLITR get() {
+            if (s == null) {
+                s = supplier.get();
+            }
+            return s;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T_SPLITR trySplit() {
+            return (T_SPLITR) get().trySplit();
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> consumer) {
+            return get().tryAdvance(consumer);
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> consumer) {
+            get().forEachRemaining(consumer);
+        }
+
+        @Override
+        public long estimateSize() {
+            return get().estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            return get().characteristics();
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return get().getComparator();
+        }
+
+        @Override
+        public long getExactSizeIfKnown() {
+            return get().getExactSizeIfKnown();
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getName() + "[" + get() + "]";
+        }
+
+        static class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+            extends DelegatingSpliterator<T, T_SPLITR>
+            implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            OfPrimitive(Supplier<? extends T_SPLITR> supplier) {
+                super(supplier);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                return get().tryAdvance(consumer);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                get().forEachRemaining(consumer);
+            }
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
+
+            OfInt(Supplier<Spliterator.OfInt> supplier) {
+                super(supplier);
+            }
+        }
+
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
+
+            OfLong(Supplier<Spliterator.OfLong> supplier) {
+                super(supplier);
+            }
+        }
+
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
+
+            OfDouble(Supplier<Spliterator.OfDouble> supplier) {
+                super(supplier);
+            }
+        }
+    }
+
+    /**
+     * A slice Spliterator from a source Spliterator that reports
+     * {@code SUBSIZED}.
+     *
+     */
+    static abstract class SliceSpliterator<T, T_SPLITR extends Spliterator<T>> {
+        // The start index of the slice
+        final long sliceOrigin;
+        // One past the last index of the slice
+        final long sliceFence;
+
+        // The spliterator to slice
+        T_SPLITR s;
+        // current (absolute) index, modified on advance/split
+        long index;
+        // one past last (absolute) index or sliceFence, which ever is smaller
+        long fence;
+
+        SliceSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence) {
+            assert s.hasCharacteristics(Spliterator.SUBSIZED);
+            this.s = s;
+            this.sliceOrigin = sliceOrigin;
+            this.sliceFence = sliceFence;
+            this.index = origin;
+            this.fence = fence;
+        }
+
+        protected abstract T_SPLITR makeSpliterator(T_SPLITR s, long sliceOrigin, long sliceFence, long origin, long fence);
+
+        public T_SPLITR trySplit() {
+            if (sliceOrigin >= fence)
+                return null;
+
+            if (index >= fence)
+                return null;
+
+            // Keep splitting until the left and right splits intersect with the slice
+            // thereby ensuring the size estimate decreases.
+            // This also avoids creating empty spliterators which can result in
+            // existing and additionally created F/J tasks that perform
+            // redundant work on no elements.
+            while (true) {
+                @SuppressWarnings("unchecked")
+                T_SPLITR leftSplit = (T_SPLITR) s.trySplit();
+                if (leftSplit == null)
+                    return null;
+
+                long leftSplitFenceUnbounded = index + leftSplit.estimateSize();
+                long leftSplitFence = Math.min(leftSplitFenceUnbounded, sliceFence);
+                if (sliceOrigin >= leftSplitFence) {
+                    // The left split does not intersect with, and is to the left of, the slice
+                    // The right split does intersect
+                    // Discard the left split and split further with the right split
+                    index = leftSplitFence;
+                }
+                else if (leftSplitFence >= sliceFence) {
+                    // The right split does not intersect with, and is to the right of, the slice
+                    // The left split does intersect
+                    // Discard the right split and split further with the left split
+                    s = leftSplit;
+                    fence = leftSplitFence;
+                }
+                else if (index >= sliceOrigin && leftSplitFenceUnbounded <= sliceFence) {
+                    // The left split is contained within the slice, return the underlying left split
+                    // Right split is contained within or intersects with the slice
+                    index = leftSplitFence;
+                    return leftSplit;
+                } else {
+                    // The left split intersects with the slice
+                    // Right split is contained within or intersects with the slice
+                    return makeSpliterator(leftSplit, sliceOrigin, sliceFence, index, index = leftSplitFence);
+                }
+            }
+        }
+
+        public long estimateSize() {
+            return (sliceOrigin < fence)
+                   ? fence - Math.max(sliceOrigin, index) : 0;
+        }
+
+        public int characteristics() {
+            return s.characteristics();
+        }
+
+        static final class OfRef<T>
+                extends SliceSpliterator<T, Spliterator<T>>
+                implements Spliterator<T> {
+
+            OfRef(Spliterator<T> s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
+
+            private OfRef(Spliterator<T> s,
+                          long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator<T> makeSpliterator(Spliterator<T> s,
+                                                     long sliceOrigin, long sliceFence,
+                                                     long origin, long fence) {
+                return new OfRef<>(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(e -> {});
+                    index++;
+                }
+
+                if (index >= fence)
+                    return false;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(e -> {});
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
+                }
+            }
+        }
+
+        static abstract class OfPrimitive<T,
+                T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
+                T_CONS>
+                extends SliceSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+
+            OfPrimitive(T_SPLITR s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
+
+            private OfPrimitive(T_SPLITR s,
+                                long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(emptyConsumer());
+                    index++;
+                }
+
+                if (index >= fence)
+                    return false;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(emptyConsumer());
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
+                }
+            }
+
+            protected abstract T_CONS emptyConsumer();
+        }
+
+        static final class OfInt extends OfPrimitive<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfInt(Spliterator.OfInt s,
+                  long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s,
+                                                        long sliceOrigin, long sliceFence,
+                                                        long origin, long fence) {
+                return new SliceSpliterator.OfInt(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected IntConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+
+        static final class OfLong extends OfPrimitive<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfLong(Spliterator.OfLong s,
+                   long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s,
+                                                         long sliceOrigin, long sliceFence,
+                                                         long origin, long fence) {
+                return new SliceSpliterator.OfLong(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected LongConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+
+        static final class OfDouble extends OfPrimitive<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfDouble(Spliterator.OfDouble s,
+                     long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s,
+                                                           long sliceOrigin, long sliceFence,
+                                                           long origin, long fence) {
+                return new SliceSpliterator.OfDouble(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected DoubleConsumer emptyConsumer() {
+                return e -> {};
+            }
+        }
+    }
+
+    /**
+     * A slice Spliterator that does not preserve order, if any, of a source
+     * Spliterator.
+     *
+     * Note: The source spliterator may report {@code ORDERED} since that
+     * spliterator be the result of a previous pipeline stage that was
+     * collected to a {@code Node}. It is the order of the pipeline stage
+     * that governs whether the this slice spliterator is to be used or not.
+     */
+    static abstract class UnorderedSliceSpliterator<T, T_SPLITR extends Spliterator<T>> {
+        static final int CHUNK_SIZE = 1 << 7;
+
+        // The spliterator to slice
+        protected final T_SPLITR s;
+        protected final boolean unlimited;
+        private final long skipThreshold;
+        private final AtomicLong permits;
+
+        UnorderedSliceSpliterator(T_SPLITR s, long skip, long limit) {
+            this.s = s;
+            this.unlimited = limit < 0;
+            this.skipThreshold = limit >= 0 ? limit : 0;
+            this.permits = new AtomicLong(limit >= 0 ? skip + limit : skip);
+        }
+
+        UnorderedSliceSpliterator(T_SPLITR s,
+                                  UnorderedSliceSpliterator<T, T_SPLITR> parent) {
+            this.s = s;
+            this.unlimited = parent.unlimited;
+            this.permits = parent.permits;
+            this.skipThreshold = parent.skipThreshold;
+        }
+
+        /**
+         * Acquire permission to skip or process elements.  The caller must
+         * first acquire the elements, then consult this method for guidance
+         * as to what to do with the data.
+         *
+         * <p>We use an {@code AtomicLong} to atomically maintain a counter,
+         * which is initialized as skip+limit if we are limiting, or skip only
+         * if we are not limiting.  The user should consult the method
+         * {@code checkPermits()} before acquiring data elements.
+         *
+         * @param numElements the number of elements the caller has in hand
+         * @return the number of elements that should be processed; any
+         * remaining elements should be discarded.
+         */
+        protected final long acquirePermits(long numElements) {
+            long remainingPermits;
+            long grabbing;
+            // permits never increase, and don't decrease below zero
+            assert numElements > 0;
+            do {
+                remainingPermits = permits.get();
+                if (remainingPermits == 0)
+                    return unlimited ? numElements : 0;
+                grabbing = Math.min(remainingPermits, numElements);
+            } while (grabbing > 0 &&
+                     !permits.compareAndSet(remainingPermits, remainingPermits - grabbing));
+
+            if (unlimited)
+                return Math.max(numElements - grabbing, 0);
+            else if (remainingPermits > skipThreshold)
+                return Math.max(grabbing - (remainingPermits - skipThreshold), 0);
+            else
+                return grabbing;
+        }
+
+        enum PermitStatus { NO_MORE, MAYBE_MORE, UNLIMITED }
+
+        /** Call to check if permits might be available before acquiring data */
+        protected final PermitStatus permitStatus() {
+            if (permits.get() > 0)
+                return PermitStatus.MAYBE_MORE;
+            else
+                return unlimited ?  PermitStatus.UNLIMITED : PermitStatus.NO_MORE;
+        }
+
+        public final T_SPLITR trySplit() {
+            // Stop splitting when there are no more limit permits
+            if (permits.get() == 0)
+                return null;
+            @SuppressWarnings("unchecked")
+            T_SPLITR split = (T_SPLITR) s.trySplit();
+            return split == null ? null : makeSpliterator(split);
+        }
+
+        protected abstract T_SPLITR makeSpliterator(T_SPLITR s);
+
+        public final long estimateSize() {
+            return s.estimateSize();
+        }
+
+        public final int characteristics() {
+            return s.characteristics() &
+                   ~(Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED);
+        }
+
+        static final class OfRef<T> extends UnorderedSliceSpliterator<T, Spliterator<T>>
+                implements Spliterator<T>, Consumer<T> {
+            T tmpSlot;
+
+            OfRef(Spliterator<T> s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfRef(Spliterator<T> s, OfRef<T> parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public final void accept(T t) {
+                tmpSlot = t;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                while (permitStatus() != PermitStatus.NO_MORE) {
+                    if (!s.tryAdvance(this))
+                        return false;
+                    else if (acquirePermits(1) == 1) {
+                        action.accept(tmpSlot);
+                        tmpSlot = null;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            @Override
+            public void forEachRemaining(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                ArrayBuffer.OfRef<T> sb = null;
+                PermitStatus permitStatus;
+                while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
+                    if (permitStatus == PermitStatus.MAYBE_MORE) {
+                        // Optimistically traverse elements up to a threshold of CHUNK_SIZE
+                        if (sb == null)
+                            sb = new ArrayBuffer.OfRef<>(CHUNK_SIZE);
+                        else
+                            sb.reset();
+                        long permitsRequested = 0;
+                        do { } while (s.tryAdvance(sb) && ++permitsRequested < CHUNK_SIZE);
+                        if (permitsRequested == 0)
+                            return;
+                        sb.forEach(action, acquirePermits(permitsRequested));
+                    }
+                    else {
+                        // Must be UNLIMITED; let 'er rip
+                        s.forEachRemaining(action);
+                        return;
+                    }
+                }
+            }
+
+            @Override
+            protected Spliterator<T> makeSpliterator(Spliterator<T> s) {
+                return new UnorderedSliceSpliterator.OfRef<>(s, this);
+            }
+        }
+
+        /**
+         * Concrete sub-types must also be an instance of type {@code T_CONS}.
+         *
+         * @param <T_BUFF> the type of the spined buffer. Must also be a type of
+         *        {@code T_CONS}.
+         */
+        static abstract class OfPrimitive<
+                T,
+                T_CONS,
+                T_BUFF extends ArrayBuffer.OfPrimitive<T_CONS>,
+                T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+                extends UnorderedSliceSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            OfPrimitive(T_SPLITR s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfPrimitive(T_SPLITR s, UnorderedSliceSpliterator.OfPrimitive<T, T_CONS, T_BUFF, T_SPLITR> parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                Objects.requireNonNull(action);
+                @SuppressWarnings("unchecked")
+                T_CONS consumer = (T_CONS) this;
+
+                while (permitStatus() != PermitStatus.NO_MORE) {
+                    if (!s.tryAdvance(consumer))
+                        return false;
+                    else if (acquirePermits(1) == 1) {
+                        acceptConsumed(action);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            protected abstract void acceptConsumed(T_CONS action);
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                Objects.requireNonNull(action);
+
+                T_BUFF sb = null;
+                PermitStatus permitStatus;
+                while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
+                    if (permitStatus == PermitStatus.MAYBE_MORE) {
+                        // Optimistically traverse elements up to a threshold of CHUNK_SIZE
+                        if (sb == null)
+                            sb = bufferCreate(CHUNK_SIZE);
+                        else
+                            sb.reset();
+                        @SuppressWarnings("unchecked")
+                        T_CONS sbc = (T_CONS) sb;
+                        long permitsRequested = 0;
+                        do { } while (s.tryAdvance(sbc) && ++permitsRequested < CHUNK_SIZE);
+                        if (permitsRequested == 0)
+                            return;
+                        sb.forEach(action, acquirePermits(permitsRequested));
+                    }
+                    else {
+                        // Must be UNLIMITED; let 'er rip
+                        s.forEachRemaining(action);
+                        return;
+                    }
+                }
+            }
+
+            protected abstract T_BUFF bufferCreate(int initialCapacity);
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, ArrayBuffer.OfInt, Spliterator.OfInt>
+                implements Spliterator.OfInt, IntConsumer {
+
+            int tmpValue;
+
+            OfInt(Spliterator.OfInt s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfInt(Spliterator.OfInt s, UnorderedSliceSpliterator.OfInt parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(int value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(IntConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfInt bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfInt(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfInt makeSpliterator(Spliterator.OfInt s) {
+                return new UnorderedSliceSpliterator.OfInt(s, this);
+            }
+        }
+
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, ArrayBuffer.OfLong, Spliterator.OfLong>
+                implements Spliterator.OfLong, LongConsumer {
+
+            long tmpValue;
+
+            OfLong(Spliterator.OfLong s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfLong(Spliterator.OfLong s, UnorderedSliceSpliterator.OfLong parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(long value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(LongConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfLong bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfLong(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfLong makeSpliterator(Spliterator.OfLong s) {
+                return new UnorderedSliceSpliterator.OfLong(s, this);
+            }
+        }
+
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, ArrayBuffer.OfDouble, Spliterator.OfDouble>
+                implements Spliterator.OfDouble, DoubleConsumer {
+
+            double tmpValue;
+
+            OfDouble(Spliterator.OfDouble s, long skip, long limit) {
+                super(s, skip, limit);
+            }
+
+            OfDouble(Spliterator.OfDouble s, UnorderedSliceSpliterator.OfDouble parent) {
+                super(s, parent);
+            }
+
+            @Override
+            public void accept(double value) {
+                tmpValue = value;
+            }
+
+            @Override
+            protected void acceptConsumed(DoubleConsumer action) {
+                action.accept(tmpValue);
+            }
+
+            @Override
+            protected ArrayBuffer.OfDouble bufferCreate(int initialCapacity) {
+                return new ArrayBuffer.OfDouble(initialCapacity);
+            }
+
+            @Override
+            protected Spliterator.OfDouble makeSpliterator(Spliterator.OfDouble s) {
+                return new UnorderedSliceSpliterator.OfDouble(s, this);
+            }
+        }
+    }
+
+    /**
+     * A wrapping spliterator that only reports distinct elements of the
+     * underlying spliterator. Does not preserve size and encounter order.
+     */
+    static final class DistinctSpliterator<T> implements Spliterator<T>, Consumer<T> {
+
+        // The value to represent null in the ConcurrentHashMap
+        private static final Object NULL_VALUE = new Object();
+
+        // The underlying spliterator
+        private final Spliterator<T> s;
+
+        // ConcurrentHashMap holding distinct elements as keys
+        private final ConcurrentHashMap<T, Boolean> seen;
+
+        // Temporary element, only used with tryAdvance
+        private T tmpSlot;
+
+        DistinctSpliterator(Spliterator<T> s) {
+            this(s, new ConcurrentHashMap<>());
+        }
+
+        private DistinctSpliterator(Spliterator<T> s, ConcurrentHashMap<T, Boolean> seen) {
+            this.s = s;
+            this.seen = seen;
+        }
+
+        @Override
+        public void accept(T t) {
+            this.tmpSlot = t;
+        }
+
+        @SuppressWarnings("unchecked")
+        private T mapNull(T t) {
+            return t != null ? t : (T) NULL_VALUE;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            while (s.tryAdvance(this)) {
+                if (seen.putIfAbsent(mapNull(tmpSlot), Boolean.TRUE) == null) {
+                    action.accept(tmpSlot);
+                    tmpSlot = null;
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            s.forEachRemaining(t -> {
+                if (seen.putIfAbsent(mapNull(t), Boolean.TRUE) == null) {
+                    action.accept(t);
+                }
+            });
+        }
+
+        @Override
+        public Spliterator<T> trySplit() {
+            Spliterator<T> split = s.trySplit();
+            return (split != null) ? new DistinctSpliterator<>(split, seen) : null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return s.estimateSize();
+        }
+
+        @Override
+        public int characteristics() {
+            return (s.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED |
+                                            Spliterator.SORTED | Spliterator.ORDERED))
+                   | Spliterator.DISTINCT;
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            return s.getComparator();
+        }
+    }
+
+    /**
+     * A Spliterator that infinitely supplies elements in no particular order.
+     *
+     * <p>Splitting divides the estimated size in two and stops when the
+     * estimate size is 0.
+     *
+     * <p>The {@code forEachRemaining} method if invoked will never terminate.
+     * The {@code tryAdvance} method always returns true.
+     *
+     */
+    static abstract class InfiniteSupplyingSpliterator<T> implements Spliterator<T> {
+        long estimate;
+
+        protected InfiniteSupplyingSpliterator(long estimate) {
+            this.estimate = estimate;
+        }
+
+        @Override
+        public long estimateSize() {
+            return estimate;
+        }
+
+        @Override
+        public int characteristics() {
+            return IMMUTABLE;
+        }
+
+        static final class OfRef<T> extends InfiniteSupplyingSpliterator<T> {
+            final Supplier<T> s;
+
+            OfRef(long size, Supplier<T> s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(Consumer<? super T> action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.get());
+                return true;
+            }
+
+            @Override
+            public Spliterator<T> trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfRef<>(estimate >>>= 1, s);
+            }
+        }
+
+        static final class OfInt extends InfiniteSupplyingSpliterator<Integer>
+                implements Spliterator.OfInt {
+            final IntSupplier s;
+
+            OfInt(long size, IntSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(IntConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsInt());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfInt trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfInt(estimate = estimate >>> 1, s);
+            }
+        }
+
+        static final class OfLong extends InfiniteSupplyingSpliterator<Long>
+                implements Spliterator.OfLong {
+            final LongSupplier s;
+
+            OfLong(long size, LongSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(LongConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsLong());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfLong trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfLong(estimate = estimate >>> 1, s);
+            }
+        }
+
+        static final class OfDouble extends InfiniteSupplyingSpliterator<Double>
+                implements Spliterator.OfDouble {
+            final DoubleSupplier s;
+
+            OfDouble(long size, DoubleSupplier s) {
+                super(size);
+                this.s = s;
+            }
+
+            @Override
+            public boolean tryAdvance(DoubleConsumer action) {
+                Objects.requireNonNull(action);
+
+                action.accept(s.getAsDouble());
+                return true;
+            }
+
+            @Override
+            public Spliterator.OfDouble trySplit() {
+                if (estimate == 0)
+                    return null;
+                return new InfiniteSupplyingSpliterator.OfDouble(estimate = estimate >>> 1, s);
+            }
+        }
+    }
+
+    // @@@ Consolidate with Node.Builder
+    static abstract class ArrayBuffer {
+        int index;
+
+        void reset() {
+            index = 0;
+        }
+
+        static final class OfRef<T> extends ArrayBuffer implements Consumer<T> {
+            final Object[] array;
+
+            OfRef(int size) {
+                this.array = new Object[size];
+            }
+
+            @Override
+            public void accept(T t) {
+                array[index++] = t;
+            }
+
+            public void forEach(Consumer<? super T> action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    @SuppressWarnings("unchecked")
+                    T t = (T) array[i];
+                    action.accept(t);
+                }
+            }
+        }
+
+        static abstract class OfPrimitive<T_CONS> extends ArrayBuffer {
+            int index;
+
+            @Override
+            void reset() {
+                index = 0;
+            }
+
+            abstract void forEach(T_CONS action, long fence);
+        }
+
+        static final class OfInt extends OfPrimitive<IntConsumer>
+                implements IntConsumer {
+            final int[] array;
+
+            OfInt(int size) {
+                this.array = new int[size];
+            }
+
+            @Override
+            public void accept(int t) {
+                array[index++] = t;
+            }
+
+            @Override
+            public void forEach(IntConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+
+        static final class OfLong extends OfPrimitive<LongConsumer>
+                implements LongConsumer {
+            final long[] array;
+
+            OfLong(int size) {
+                this.array = new long[size];
+            }
+
+            @Override
+            public void accept(long t) {
+                array[index++] = t;
+            }
+
+            @Override
+            public void forEach(LongConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+
+        static final class OfDouble extends OfPrimitive<DoubleConsumer>
+                implements DoubleConsumer {
+            final double[] array;
+
+            OfDouble(int size) {
+                this.array = new double[size];
+            }
+
+            @Override
+            public void accept(double t) {
+                array[index++] = t;
+            }
+
+            @Override
+            void forEach(DoubleConsumer action, long fence) {
+                for (int i = 0; i < fence; i++) {
+                    action.accept(array[i]);
+                }
+            }
+        }
+    }
+}
+
diff --git a/java/util/stream/StreamSupport.java b/java/util/stream/StreamSupport.java
new file mode 100644
index 0000000..9a1820c
--- /dev/null
+++ b/java/util/stream/StreamSupport.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Supplier;
+
+/**
+ * Low-level utility methods for creating and manipulating streams.
+ *
+ * <p>This class is mostly for library writers presenting stream views
+ * of data structures; most static stream methods intended for end users are in
+ * the various {@code Stream} classes.
+ *
+ * @since 1.8
+ */
+public final class StreamSupport {
+
+    // Suppresses default constructor, ensuring non-instantiability.
+    private StreamSupport() {}
+
+    /**
+     * Creates a new sequential or parallel {@code Stream} from a
+     * {@code Spliterator}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated
+     * size after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #stream(java.util.function.Supplier, int, boolean)} should be used
+     * to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param <T> the type of stream elements
+     * @param spliterator a {@code Spliterator} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code Stream}
+     */
+    public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
+        Objects.requireNonNull(spliterator);
+        return new ReferencePipeline.Head<>(spliterator,
+                                            StreamOpFlag.fromCharacteristics(spliterator),
+                                            parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code Stream} from a
+     * {@code Supplier} of {@code Spliterator}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #stream(java.util.Spliterator, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param <T> the type of stream elements
+     * @param supplier a {@code Supplier} of a {@code Spliterator}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code Stream}
+     * @see #stream(java.util.Spliterator, boolean)
+     */
+    public static <T> Stream<T> stream(Supplier<? extends Spliterator<T>> supplier,
+                                       int characteristics,
+                                       boolean parallel) {
+        Objects.requireNonNull(supplier);
+        return new ReferencePipeline.Head<>(supplier,
+                                            StreamOpFlag.fromCharacteristics(characteristics),
+                                            parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code IntStream} from a
+     * {@code Spliterator.OfInt}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated size
+     * after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #intStream(java.util.function.Supplier, int, boolean)} should be
+     * used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator a {@code Spliterator.OfInt} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code IntStream}
+     */
+    public static IntStream intStream(Spliterator.OfInt spliterator, boolean parallel) {
+        return new IntPipeline.Head<>(spliterator,
+                                      StreamOpFlag.fromCharacteristics(spliterator),
+                                      parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code IntStream} from a
+     * {@code Supplier} of {@code Spliterator.OfInt}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #intStream(java.util.Spliterator.OfInt, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier a {@code Supplier} of a {@code Spliterator.OfInt}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfInt}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code IntStream}
+     * @see #intStream(java.util.Spliterator.OfInt, boolean)
+     */
+    public static IntStream intStream(Supplier<? extends Spliterator.OfInt> supplier,
+                                      int characteristics,
+                                      boolean parallel) {
+        return new IntPipeline.Head<>(supplier,
+                                      StreamOpFlag.fromCharacteristics(characteristics),
+                                      parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code LongStream} from a
+     * {@code Spliterator.OfLong}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated
+     * size after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #longStream(java.util.function.Supplier, int, boolean)} should be
+     * used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator a {@code Spliterator.OfLong} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code LongStream}
+     */
+    public static LongStream longStream(Spliterator.OfLong spliterator,
+                                        boolean parallel) {
+        return new LongPipeline.Head<>(spliterator,
+                                       StreamOpFlag.fromCharacteristics(spliterator),
+                                       parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code LongStream} from a
+     * {@code Supplier} of {@code Spliterator.OfLong}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #longStream(java.util.Spliterator.OfLong, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier a {@code Supplier} of a {@code Spliterator.OfLong}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfLong}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code LongStream}
+     * @see #longStream(java.util.Spliterator.OfLong, boolean)
+     */
+    public static LongStream longStream(Supplier<? extends Spliterator.OfLong> supplier,
+                                        int characteristics,
+                                        boolean parallel) {
+        return new LongPipeline.Head<>(supplier,
+                                       StreamOpFlag.fromCharacteristics(characteristics),
+                                       parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code DoubleStream} from a
+     * {@code Spliterator.OfDouble}.
+     *
+     * <p>The spliterator is only traversed, split, or queried for estimated size
+     * after the terminal operation of the stream pipeline commences.
+     *
+     * <p>It is strongly recommended the spliterator report a characteristic of
+     * {@code IMMUTABLE} or {@code CONCURRENT}, or be
+     * <a href="../Spliterator.html#binding">late-binding</a>.  Otherwise,
+     * {@link #doubleStream(java.util.function.Supplier, int, boolean)} should
+     * be used to reduce the scope of potential interference with the source.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param spliterator A {@code Spliterator.OfDouble} describing the stream elements
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code DoubleStream}
+     */
+    public static DoubleStream doubleStream(Spliterator.OfDouble spliterator,
+                                            boolean parallel) {
+        return new DoublePipeline.Head<>(spliterator,
+                                         StreamOpFlag.fromCharacteristics(spliterator),
+                                         parallel);
+    }
+
+    /**
+     * Creates a new sequential or parallel {@code DoubleStream} from a
+     * {@code Supplier} of {@code Spliterator.OfDouble}.
+     *
+     * <p>The {@link Supplier#get()} method will be invoked on the supplier no
+     * more than once, and only after the terminal operation of the stream pipeline
+     * commences.
+     *
+     * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
+     * or {@code CONCURRENT}, or that are
+     * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
+     * more efficient to use {@link #doubleStream(java.util.Spliterator.OfDouble, boolean)}
+     * instead.
+     * <p>The use of a {@code Supplier} in this form provides a level of
+     * indirection that reduces the scope of potential interference with the
+     * source.  Since the supplier is only invoked after the terminal operation
+     * commences, any modifications to the source up to the start of the
+     * terminal operation are reflected in the stream result.  See
+     * <a href="package-summary.html#NonInterference">Non-Interference</a> for
+     * more details.
+     *
+     * @param supplier A {@code Supplier} of a {@code Spliterator.OfDouble}
+     * @param characteristics Spliterator characteristics of the supplied
+     *        {@code Spliterator.OfDouble}.  The characteristics must be equal to
+     *        {@code supplier.get().characteristics()}, otherwise undefined
+     *        behavior may occur when terminal operation commences.
+     * @param parallel if {@code true} then the returned stream is a parallel
+     *        stream; if {@code false} the returned stream is a sequential
+     *        stream.
+     * @return a new sequential or parallel {@code DoubleStream}
+     * @see #doubleStream(java.util.Spliterator.OfDouble, boolean)
+     */
+    public static DoubleStream doubleStream(Supplier<? extends Spliterator.OfDouble> supplier,
+                                            int characteristics,
+                                            boolean parallel) {
+        return new DoublePipeline.Head<>(supplier,
+                                         StreamOpFlag.fromCharacteristics(characteristics),
+                                         parallel);
+    }
+}
diff --git a/java/util/stream/StreamTestDataProvider.java b/java/util/stream/StreamTestDataProvider.java
new file mode 100644
index 0000000..cc98529
--- /dev/null
+++ b/java/util/stream/StreamTestDataProvider.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.Spliterators;
+import java.util.function.Supplier;
+
+/**
+ * StreamTestDataProvider
+ *
+ * @author Brian Goetz
+ */
+/** TestNG DataProvider for ref-valued streams */
+public class StreamTestDataProvider {
+    private static final Integer[] to0 = new Integer[0];
+    private static final Integer[] to1 = new Integer[1];
+    private static final Integer[] to10 = new Integer[10];
+    private static final Integer[] to100 = new Integer[100];
+    private static final Integer[] to1000 = new Integer[1000];
+    private static final Integer[] reversed = new Integer[100];
+    private static final Integer[] ones = new Integer[100];
+    private static final Integer[] twice = new Integer[200];
+    private static final Integer[] pseudoRandom;
+
+    private static final Object[][] testData;
+    private static final Object[][] withNullTestData;
+    private static final Object[][] spliteratorTestData;
+
+    static {
+        Integer[][] arrays = {to0, to1, to10, to100, to1000};
+        for (Integer[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new Integer[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        {
+            List<Object[]> list = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final Integer[] ints = (Integer[])data[1];
+                final List<Integer> intsAsList = Arrays.asList(ints);
+
+                list.add(arrayDataDescr("array:" + name, ints));
+                list.add(collectionDataDescr("ArrayList.asList:" + name, intsAsList));
+                list.add(collectionDataDescr("ArrayList:" + name, new ArrayList<>(intsAsList)));
+                list.add(streamDataDescr("DelegatingStream(ArrayList):" + name,
+                                         () -> new ArrayList<>(intsAsList).stream()));
+                List<Integer> aList = new ArrayList<>(intsAsList);
+                if (LambdaTestMode.isNormalMode()) {
+                    // Only include sub-lists for normal test execution mode
+                    // This data is serialization-hostile since the state of the
+                    // deserialized sub-list will be out of sync with the
+                    // enclosing list.
+                    list.add(collectionDataDescr("ArrayList.Sublist:" + name,
+                                                 (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
+                }
+                list.add(collectionDataDescr("LinkedList:" + name, new LinkedList<>(intsAsList)));
+                list.add(collectionDataDescr("HashSet:" + name, new HashSet<>(intsAsList)));
+                list.add(collectionDataDescr("LinkedHashSet:" + name, new LinkedHashSet<>(intsAsList)));
+                list.add(collectionDataDescr("TreeSet:" + name, new TreeSet<>(intsAsList)));
+                SpinedBuffer<Integer> spinedBuffer = new SpinedBuffer<>();
+                intsAsList.forEach(spinedBuffer);
+                list.add(sbDataDescr("SpinedBuffer:" + name, spinedBuffer));
+
+                // @@@ Add more
+            }
+            testData = list.toArray(new Object[0][]);
+        }
+
+        // Simple combination of numbers and null values, probably excessive but may catch
+        // errors for initialization/termination/sequence
+        // @@@ This is separate from the other data for now until nulls are consitently supported by
+        // all operations
+        {
+            List<Object[]> list = new ArrayList<>();
+            int size = 5;
+            for (int i = 0; i < (1 << size) - 2; i++) {
+                Integer[] content = new Integer[size];
+                for (int e = 0; e < size; e++) {
+                    content[e] = (i & (1 << e)) > 0 ? e + 1 : null;
+                }
+
+                // ORDERED
+                list.add(arrayDataDescr("array:" + i, content));
+                // not ORDERED, DISTINCT
+                list.add(collectionDataDescr("HashSet:" + i, new HashSet<>(Arrays.asList(content))));
+            }
+
+            withNullTestData = list.toArray(new Object[0][]);
+        }
+
+        {
+            List<Object[]> spliterators = new ArrayList<>();
+            for (Object[] data : arrays) {
+                final Object name = data[0];
+                final Integer[] ints = (Integer[])data[1];
+
+                spliterators.add(splitDescr("Arrays.s(array):" + name,
+                                            () -> Arrays.spliterator(ints)));
+                spliterators.add(splitDescr("arrays.s(array,o,l):" + name,
+                                            () -> Arrays.spliterator(ints, 0, ints.length/2)));
+                spliterators.add(splitDescr("SpinedBuffer.s():" + name,
+                                            () -> {
+                                                SpinedBuffer<Integer> sb = new SpinedBuffer<>();
+                                                for (Integer i : ints)
+                                                    sb.accept(i);
+                                                return sb.spliterator();
+                                            }));
+                spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator(), size):" + name,
+                                            () -> Spliterators.spliterator(Arrays.asList(ints).iterator(), ints.length, 0)));
+                spliterators.add(splitDescr("Iterators.s(Arrays.s(array).iterator()):" + name,
+                                            () -> Spliterators.spliteratorUnknownSize(Arrays.asList(ints).iterator(), 0)));
+                // @@@ Add map and collection spliterators when spliterator() is exposed on Collection or Iterable
+            }
+            spliteratorTestData = spliterators.toArray(new Object[0][]);
+        }
+    }
+
+    static <T> Object[] arrayDataDescr(String description, T[] data) {
+        return new Object[] { description, TestData.Factory.ofArray(description, data)};
+    }
+
+    static <T> Object[] streamDataDescr(String description, Supplier<Stream<T>> supplier) {
+        return new Object[] { description, TestData.Factory.ofSupplier(description, supplier)};
+    }
+
+    static <T> Object[] collectionDataDescr(String description, Collection<T> data) {
+        return new Object[] { description, TestData.Factory.ofCollection(description, data)};
+    }
+
+    static <T> Object[] sbDataDescr(String description, SpinedBuffer<T> data) {
+        return new Object[] { description, TestData.Factory.ofSpinedBuffer(description, data)};
+    }
+
+    static <T> Object[] splitDescr(String description, Supplier<Spliterator<T>> ss) {
+        return new Object[] { description, ss };
+    }
+
+    // Return an array of ( String name, StreamTestData<Integer> )
+    @DataProvider(name = "StreamTestData<Integer>")
+    public static Object[][] makeStreamTestData() {
+        return testData;
+    }
+
+    @DataProvider(name = "withNull:StreamTestData<Integer>")
+    public static Object[][] makeStreamWithNullTestData() {
+        return withNullTestData;
+    }
+
+    // returns an array of (String name, Supplier<Spliterator<Integer>>)
+    @DataProvider(name = "Spliterator<Integer>")
+    public static Object[][] spliteratorProvider() {
+        return spliteratorTestData;
+    }
+}
diff --git a/java/util/stream/StreamTestScenario.java b/java/util/stream/StreamTestScenario.java
new file mode 100644
index 0000000..d19c416
--- /dev/null
+++ b/java/util/stream/StreamTestScenario.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+/**
+ * Test scenarios for reference streams.
+ *
+ * Each scenario is provided with a data source, a function that maps a fresh
+ * stream (as provided by the data source) to a new stream, and a sink to
+ * receive results.  Each scenario describes a different way of computing the
+ * stream contents.  The test driver will ensure that all scenarios produce
+ * the same output (modulo allowable differences in ordering).
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
+
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            Stream<U> s = m.apply(data.stream());
+            if (s.isParallel()) {
+                s = s.sequential();
+            }
+            s.forEach(b);
+            s.close();
+        }
+    },
+
+    // Collec to list
+    STREAM_COLLECT(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U t : m.apply(data.stream()).collect(Collectors.toList())) {
+                b.accept(t);
+            }
+        }
+    },
+
+    // To array
+    STREAM_TO_ARRAY(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Object t : m.apply(data.stream()).toArray()) {
+                b.accept((U) t);
+            }
+        }
+    },
+
+    // Wrap as stream, and iterate in pull mode
+    STREAM_ITERATOR(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Iterator<U> seqIter = m.apply(data.stream()).iterator(); seqIter.hasNext(); )
+                b.accept(seqIter.next());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Spliterator<U> spl = m.apply(data.stream()).spliterator(); spl.tryAdvance(b); ) { }
+        }
+    },
+
+    // Wrap as stream, spliterate, then split a few times mixing advances with forEach
+    STREAM_SPLITERATOR_WITH_MIXED_TRAVERSE_AND_SPLIT(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            SpliteratorTestHelper.mixedTraverseAndSplit(b, m.apply(data.stream()).spliterator());
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate in pull mode
+    STREAM_SPLITERATOR_FOREACH(false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.stream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    // Wrap as parallel stream + sequential
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).sequential().forEach(b);
+        }
+    },
+
+    // Wrap as parallel stream + forEachOrdered
+    PAR_STREAM_FOR_EACH_ORDERED(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            // @@@ Want to explicitly select ordered equalator
+            m.apply(data.parallelStream()).forEachOrdered(b);
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Spliterator<U> spl = m.apply(data.parallelStream()).spliterator(); spl.tryAdvance(b); ) { }
+        }
+    },
+
+    // Wrap as stream, and spliterate then iterate sequentially
+    PAR_STREAM_SPLITERATOR_FOREACH(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).spliterator().forEachRemaining(b);
+        }
+    },
+
+    // Wrap as parallel stream + toArray
+    PAR_STREAM_TO_ARRAY(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (Object t : m.apply(data.parallelStream()).toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel stream, get the spliterator, wrap as a stream + toArray
+    PAR_STREAM_SPLITERATOR_STREAM_TO_ARRAY(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            Stream<U> s = m.apply(data.parallelStream());
+            Spliterator<U> sp = s.spliterator();
+            Stream<U> ss = StreamSupport.stream(() -> sp,
+                                                StreamOpFlag.toCharacteristics(OpTestCase.getStreamFlags(s))
+                                                | (sp.getExactSizeIfKnown() < 0 ? 0 : Spliterator.SIZED), true);
+            for (Object t : ss.toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel stream + toArray and clear SIZED flag
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            Stream<U> pipe2 = m.apply(pipe1);
+
+            for (Object t : pipe2.toArray())
+                b.accept((U) t);
+        }
+    },
+
+    // Wrap as parallel + collect to list
+    PAR_STREAM_COLLECT_TO_LIST(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.parallelStream()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap sequential as parallel, + collect to list
+    STREAM_TO_PAR_STREAM_COLLECT_TO_LIST(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.stream().parallel()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap parallel as sequential,, + collect
+    PAR_STREAM_TO_STREAM_COLLECT_TO_LIST(true) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            for (U u : m.apply(data.parallelStream().sequential()).collect(Collectors.toList()))
+                b.accept(u);
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing
+    PAR_STREAM_FOR_EACH(true, false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            m.apply(data.parallelStream()).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+
+    // Wrap as parallel stream + forEach synchronizing and clear SIZED flag
+    PAR_STREAM_FOR_EACH_CLEAR_SIZED(true, false) {
+        <T, U, S_IN extends BaseStream<T, S_IN>>
+        void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
+            S_IN pipe1 = (S_IN) OpTestCase.chain(data.parallelStream(),
+                                                 new FlagDeclaringOp(StreamOpFlag.NOT_SIZED, data.getShape()));
+            m.apply(pipe1).forEach(e -> {
+                synchronized (data) {
+                    b.accept(e);
+                }
+            });
+        }
+    },
+    ;
+
+    // The set of scenarios that clean the SIZED flag
+    public static final Set<StreamTestScenario> CLEAR_SIZED_SCENARIOS = Collections.unmodifiableSet(
+            EnumSet.of(PAR_STREAM_TO_ARRAY_CLEAR_SIZED, PAR_STREAM_FOR_EACH_CLEAR_SIZED));
+
+    private final boolean isParallel;
+
+    private final boolean isOrdered;
+
+    StreamTestScenario(boolean isParallel) {
+        this(isParallel, true);
+    }
+
+    StreamTestScenario(boolean isParallel, boolean isOrdered) {
+        this.isParallel = isParallel;
+        this.isOrdered = isOrdered;
+    }
+
+    public StreamShape getShape() {
+        return StreamShape.REFERENCE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public boolean isOrdered() {
+        return isOrdered;
+    }
+
+    public <T, U, S_IN extends BaseStream<T, S_IN>, S_OUT extends BaseStream<U, S_OUT>>
+    void run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, S_OUT> m) {
+        _run(data, b, (Function<S_IN, Stream<U>>) m);
+    }
+
+    abstract <T, U, S_IN extends BaseStream<T, S_IN>>
+    void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m);
+
+}
diff --git a/java/util/stream/Streams.java b/java/util/stream/Streams.java
new file mode 100644
index 0000000..072691a
--- /dev/null
+++ b/java/util/stream/Streams.java
@@ -0,0 +1,896 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+
+/**
+ * Utility methods for operating on and creating streams.
+ *
+ * <p>Unless otherwise stated, streams are created as sequential streams.  A
+ * sequential stream can be transformed into a parallel stream by calling the
+ * {@code parallel()} method on the created stream.
+ *
+ * @since 1.8
+ */
+final class Streams {
+
+    private Streams() {
+        throw new Error("no instances");
+    }
+
+    /**
+     * An object instance representing no value, that cannot be an actual
+     * data element of a stream.  Used when processing streams that can contain
+     * {@code null} elements to distinguish between a {@code null} value and no
+     * value.
+     */
+    static final Object NONE = new Object();
+
+    /**
+     * An {@code int} range spliterator.
+     */
+    static final class RangeIntSpliterator implements Spliterator.OfInt {
+        // Can never be greater that upTo, this avoids overflow if upper bound
+        // is Integer.MAX_VALUE
+        // All elements are traversed if from == upTo & last == 0
+        private int from;
+        private final int upTo;
+        // 1 if the range is closed and the last element has not been traversed
+        // Otherwise, 0 if the range is open, or is a closed range and all
+        // elements have been traversed
+        private int last;
+
+        RangeIntSpliterator(int from, int upTo, boolean closed) {
+            this(from, upTo, closed ? 1 : 0);
+        }
+
+        private RangeIntSpliterator(int from, int upTo, int last) {
+            this.from = from;
+            this.upTo = upTo;
+            this.last = last;
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            final int i = from;
+            if (i < upTo) {
+                from++;
+                consumer.accept(i);
+                return true;
+            }
+            else if (last > 0) {
+                last = 0;
+                consumer.accept(i);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            int i = from;
+            final int hUpTo = upTo;
+            int hLast = last;
+            from = upTo;
+            last = 0;
+            while (i < hUpTo) {
+                consumer.accept(i++);
+            }
+            if (hLast > 0) {
+                // Last element of closed range
+                consumer.accept(i);
+            }
+        }
+
+        @Override
+        public long estimateSize() {
+            // Ensure ranges of size > Integer.MAX_VALUE report the correct size
+            return ((long) upTo) - from + last;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Integer> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfInt trySplit() {
+            long size = estimateSize();
+            return size <= 1
+                   ? null
+                   // Left split always has a half-open range
+                   : new RangeIntSpliterator(from, from = from + splitPoint(size), 0);
+        }
+
+        /**
+         * The spliterator size below which the spliterator will be split
+         * at the mid-point to produce balanced splits. Above this size the
+         * spliterator will be split at a ratio of
+         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
+         * to produce right-balanced splits.
+         *
+         * <p>Such splitting ensures that for very large ranges that the left
+         * side of the range will more likely be processed at a lower-depth
+         * than a balanced tree at the expense of a higher-depth for the right
+         * side of the range.
+         *
+         * <p>This is optimized for cases such as IntStream.ints() that is
+         * implemented as range of 0 to Integer.MAX_VALUE but is likely to be
+         * augmented with a limit operation that limits the number of elements
+         * to a count lower than this threshold.
+         */
+        private static final int BALANCED_SPLIT_THRESHOLD = 1 << 24;
+
+        /**
+         * The split ratio of the left and right split when the spliterator
+         * size is above BALANCED_SPLIT_THRESHOLD.
+         */
+        private static final int RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
+
+        private int splitPoint(long size) {
+            int d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
+            // Cast to int is safe since:
+            //   2 <= size < 2^32
+            //   2 <= d <= 8
+            return (int) (size / d);
+        }
+    }
+
+    /**
+     * A {@code long} range spliterator.
+     *
+     * This implementation cannot be used for ranges whose size is greater
+     * than Long.MAX_VALUE
+     */
+    static final class RangeLongSpliterator implements Spliterator.OfLong {
+        // Can never be greater that upTo, this avoids overflow if upper bound
+        // is Long.MAX_VALUE
+        // All elements are traversed if from == upTo & last == 0
+        private long from;
+        private final long upTo;
+        // 1 if the range is closed and the last element has not been traversed
+        // Otherwise, 0 if the range is open, or is a closed range and all
+        // elements have been traversed
+        private int last;
+
+        RangeLongSpliterator(long from, long upTo, boolean closed) {
+            this(from, upTo, closed ? 1 : 0);
+        }
+
+        private RangeLongSpliterator(long from, long upTo, int last) {
+            assert upTo - from + last > 0;
+            this.from = from;
+            this.upTo = upTo;
+            this.last = last;
+        }
+
+        @Override
+        public boolean tryAdvance(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            final long i = from;
+            if (i < upTo) {
+                from++;
+                consumer.accept(i);
+                return true;
+            }
+            else if (last > 0) {
+                last = 0;
+                consumer.accept(i);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer consumer) {
+            Objects.requireNonNull(consumer);
+
+            long i = from;
+            final long hUpTo = upTo;
+            int hLast = last;
+            from = upTo;
+            last = 0;
+            while (i < hUpTo) {
+                consumer.accept(i++);
+            }
+            if (hLast > 0) {
+                // Last element of closed range
+                consumer.accept(i);
+            }
+        }
+
+        @Override
+        public long estimateSize() {
+            return upTo - from + last;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.IMMUTABLE | Spliterator.NONNULL |
+                   Spliterator.DISTINCT | Spliterator.SORTED;
+        }
+
+        @Override
+        public Comparator<? super Long> getComparator() {
+            return null;
+        }
+
+        @Override
+        public Spliterator.OfLong trySplit() {
+            long size = estimateSize();
+            return size <= 1
+                   ? null
+                   // Left split always has a half-open range
+                   : new RangeLongSpliterator(from, from = from + splitPoint(size), 0);
+        }
+
+        /**
+         * The spliterator size below which the spliterator will be split
+         * at the mid-point to produce balanced splits. Above this size the
+         * spliterator will be split at a ratio of
+         * 1:(RIGHT_BALANCED_SPLIT_RATIO - 1)
+         * to produce right-balanced splits.
+         *
+         * <p>Such splitting ensures that for very large ranges that the left
+         * side of the range will more likely be processed at a lower-depth
+         * than a balanced tree at the expense of a higher-depth for the right
+         * side of the range.
+         *
+         * <p>This is optimized for cases such as LongStream.longs() that is
+         * implemented as range of 0 to Long.MAX_VALUE but is likely to be
+         * augmented with a limit operation that limits the number of elements
+         * to a count lower than this threshold.
+         */
+        private static final long BALANCED_SPLIT_THRESHOLD = 1 << 24;
+
+        /**
+         * The split ratio of the left and right split when the spliterator
+         * size is above BALANCED_SPLIT_THRESHOLD.
+         */
+        private static final long RIGHT_BALANCED_SPLIT_RATIO = 1 << 3;
+
+        private long splitPoint(long size) {
+            long d = (size < BALANCED_SPLIT_THRESHOLD) ? 2 : RIGHT_BALANCED_SPLIT_RATIO;
+            // 2 <= size <= Long.MAX_VALUE
+            return size / d;
+        }
+    }
+
+    private static abstract class AbstractStreamBuilderImpl<T, S extends Spliterator<T>> implements Spliterator<T> {
+        // >= 0 when building, < 0 when built
+        // -1 == no elements
+        // -2 == one element, held by first
+        // -3 == two or more elements, held by buffer
+        int count;
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public S trySplit() {
+            return null;
+        }
+
+        @Override
+        public long estimateSize() {
+            return -count - 1;
+        }
+
+        @Override
+        public int characteristics() {
+            return Spliterator.SIZED | Spliterator.SUBSIZED |
+                   Spliterator.ORDERED | Spliterator.IMMUTABLE;
+        }
+    }
+
+    static final class StreamBuilderImpl<T>
+            extends AbstractStreamBuilderImpl<T, Spliterator<T>>
+            implements Stream.Builder<T> {
+        // The first element in the stream
+        // valid if count == 1
+        T first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer<T> buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        StreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        StreamBuilderImpl(T t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(T t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer<>();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        public Stream.Builder<T> add(T t) {
+            accept(t);
+            return this;
+        }
+
+        @Override
+        public Stream<T> build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.stream(this, false) : StreamSupport.stream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class IntStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Integer, Spliterator.OfInt>
+            implements IntStream.Builder, Spliterator.OfInt {
+        // The first element in the stream
+        // valid if count == 1
+        int first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfInt buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        IntStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        IntStreamBuilderImpl(int t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(int t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfInt();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public IntStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.intStream(this, false) : StreamSupport.intStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class LongStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Long, Spliterator.OfLong>
+            implements LongStream.Builder, Spliterator.OfLong {
+        // The first element in the stream
+        // valid if count == 1
+        long first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfLong buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        LongStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        LongStreamBuilderImpl(long t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(long t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfLong();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public LongStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.longStream(this, false) : StreamSupport.longStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(LongConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(LongConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    static final class DoubleStreamBuilderImpl
+            extends AbstractStreamBuilderImpl<Double, Spliterator.OfDouble>
+            implements DoubleStream.Builder, Spliterator.OfDouble {
+        // The first element in the stream
+        // valid if count == 1
+        double first;
+
+        // The first and subsequent elements in the stream
+        // non-null if count == 2
+        SpinedBuffer.OfDouble buffer;
+
+        /**
+         * Constructor for building a stream of 0 or more elements.
+         */
+        DoubleStreamBuilderImpl() { }
+
+        /**
+         * Constructor for a singleton stream.
+         *
+         * @param t the single element
+         */
+        DoubleStreamBuilderImpl(double t) {
+            first = t;
+            count = -2;
+        }
+
+        // StreamBuilder implementation
+
+        @Override
+        public void accept(double t) {
+            if (count == 0) {
+                first = t;
+                count++;
+            }
+            else if (count > 0) {
+                if (buffer == null) {
+                    buffer = new SpinedBuffer.OfDouble();
+                    buffer.accept(first);
+                    count++;
+                }
+
+                buffer.accept(t);
+            }
+            else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public DoubleStream build() {
+            int c = count;
+            if (c >= 0) {
+                // Switch count to negative value signalling the builder is built
+                count = -count - 1;
+                // Use this spliterator if 0 or 1 elements, otherwise use
+                // the spliterator of the spined buffer
+                return (c < 2) ? StreamSupport.doubleStream(this, false) : StreamSupport.doubleStream(buffer.spliterator(), false);
+            }
+
+            throw new IllegalStateException();
+        }
+
+        // Spliterator implementation for 0 or 1 element
+        // count == -1 for no elements
+        // count == -2 for one element held by first
+
+        @Override
+        public boolean tryAdvance(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        @Override
+        public void forEachRemaining(DoubleConsumer action) {
+            Objects.requireNonNull(action);
+
+            if (count == -2) {
+                action.accept(first);
+                count = -1;
+            }
+        }
+    }
+
+    abstract static class ConcatSpliterator<T, T_SPLITR extends Spliterator<T>>
+            implements Spliterator<T> {
+        protected final T_SPLITR aSpliterator;
+        protected final T_SPLITR bSpliterator;
+        // True when no split has occurred, otherwise false
+        boolean beforeSplit;
+        // Never read after splitting
+        final boolean unsized;
+
+        public ConcatSpliterator(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
+            this.aSpliterator = aSpliterator;
+            this.bSpliterator = bSpliterator;
+            beforeSplit = true;
+            // The spliterator is known to be unsized before splitting if the
+            // sum of the estimates overflows.
+            unsized = aSpliterator.estimateSize() + bSpliterator.estimateSize() < 0;
+        }
+
+        @Override
+        public T_SPLITR trySplit() {
+            @SuppressWarnings("unchecked")
+            T_SPLITR ret = beforeSplit ? aSpliterator : (T_SPLITR) bSpliterator.trySplit();
+            beforeSplit = false;
+            return ret;
+        }
+
+        @Override
+        public boolean tryAdvance(Consumer<? super T> consumer) {
+            boolean hasNext;
+            if (beforeSplit) {
+                hasNext = aSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    beforeSplit = false;
+                    hasNext = bSpliterator.tryAdvance(consumer);
+                }
+            }
+            else
+                hasNext = bSpliterator.tryAdvance(consumer);
+            return hasNext;
+        }
+
+        @Override
+        public void forEachRemaining(Consumer<? super T> consumer) {
+            if (beforeSplit)
+                aSpliterator.forEachRemaining(consumer);
+            bSpliterator.forEachRemaining(consumer);
+        }
+
+        @Override
+        public long estimateSize() {
+            if (beforeSplit) {
+                // If one or both estimates are Long.MAX_VALUE then the sum
+                // will either be Long.MAX_VALUE or overflow to a negative value
+                long size = aSpliterator.estimateSize() + bSpliterator.estimateSize();
+                return (size >= 0) ? size : Long.MAX_VALUE;
+            }
+            else {
+                return bSpliterator.estimateSize();
+            }
+        }
+
+        @Override
+        public int characteristics() {
+            if (beforeSplit) {
+                // Concatenation loses DISTINCT and SORTED characteristics
+                return aSpliterator.characteristics() & bSpliterator.characteristics()
+                       & ~(Spliterator.DISTINCT | Spliterator.SORTED
+                           | (unsized ? Spliterator.SIZED | Spliterator.SUBSIZED : 0));
+            }
+            else {
+                return bSpliterator.characteristics();
+            }
+        }
+
+        @Override
+        public Comparator<? super T> getComparator() {
+            if (beforeSplit)
+                throw new IllegalStateException();
+            return bSpliterator.getComparator();
+        }
+
+        static class OfRef<T> extends ConcatSpliterator<T, Spliterator<T>> {
+            OfRef(Spliterator<T> aSpliterator, Spliterator<T> bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        private static abstract class OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>>
+                extends ConcatSpliterator<T, T_SPLITR>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
+            private OfPrimitive(T_SPLITR aSpliterator, T_SPLITR bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                boolean hasNext;
+                if (beforeSplit) {
+                    hasNext = aSpliterator.tryAdvance(action);
+                    if (!hasNext) {
+                        beforeSplit = false;
+                        hasNext = bSpliterator.tryAdvance(action);
+                    }
+                }
+                else
+                    hasNext = bSpliterator.tryAdvance(action);
+                return hasNext;
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                if (beforeSplit)
+                    aSpliterator.forEachRemaining(action);
+                bSpliterator.forEachRemaining(action);
+            }
+        }
+
+        static class OfInt
+                extends ConcatSpliterator.OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt aSpliterator, Spliterator.OfInt bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        static class OfLong
+                extends ConcatSpliterator.OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong aSpliterator, Spliterator.OfLong bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+
+        static class OfDouble
+                extends ConcatSpliterator.OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble aSpliterator, Spliterator.OfDouble bSpliterator) {
+                super(aSpliterator, bSpliterator);
+            }
+        }
+    }
+
+    /**
+     * Given two Runnables, return a Runnable that executes both in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composeWithExceptions(Runnable a, Runnable b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.run();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.run();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.run();
+            }
+        };
+    }
+
+    /**
+     * Given two streams, return a Runnable that
+     * executes both of their {@link BaseStream#close} methods in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.close();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.close();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.close();
+            }
+        };
+    }
+}
diff --git a/java/util/stream/TerminalOp.java b/java/util/stream/TerminalOp.java
new file mode 100644
index 0000000..a6e8ae1
--- /dev/null
+++ b/java/util/stream/TerminalOp.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+
+/**
+ * An operation in a stream pipeline that takes a stream as input and produces
+ * a result or side-effect.  A {@code TerminalOp} has an input type and stream
+ * shape, and a result type.  A {@code TerminalOp} also has a set of
+ * <em>operation flags</em> that describes how the operation processes elements
+ * of the stream (such as short-circuiting or respecting encounter order; see
+ * {@link StreamOpFlag}).
+ *
+ * <p>A {@code TerminalOp} must provide a sequential and parallel implementation
+ * of the operation relative to a given stream source and set of intermediate
+ * operations.
+ *
+ * @param <E_IN> the type of input elements
+ * @param <R>    the type of the result
+ * @since 1.8
+ */
+interface TerminalOp<E_IN, R> {
+    /**
+     * Gets the shape of the input type of this operation.
+     *
+     * @implSpec The default returns {@code StreamShape.REFERENCE}.
+     *
+     * @return StreamShape of the input type of this operation
+     */
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    /**
+     * Gets the stream flags of the operation.  Terminal operations may set a
+     * limited subset of the stream flags defined in {@link StreamOpFlag}, and
+     * these flags are combined with the previously combined stream and
+     * intermediate operation flags for the pipeline.
+     *
+     * @implSpec The default implementation returns zero.
+     *
+     * @return the stream flags for this operation
+     * @see StreamOpFlag
+     */
+    default int getOpFlags() { return 0; }
+
+    /**
+     * Performs a parallel evaluation of the operation using the specified
+     * {@code PipelineHelper}, which describes the upstream intermediate
+     * operations.
+     *
+     * @implSpec The default performs a sequential evaluation of the operation
+     * using the specified {@code PipelineHelper}.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source spliterator
+     * @return the result of the evaluation
+     */
+    default <P_IN> R evaluateParallel(PipelineHelper<E_IN> helper,
+                                      Spliterator<P_IN> spliterator) {
+        if (Tripwire.ENABLED)
+            Tripwire.trip(getClass(), "{0} triggering TerminalOp.evaluateParallel serial default");
+        return evaluateSequential(helper, spliterator);
+    }
+
+    /**
+     * Performs a sequential evaluation of the operation using the specified
+     * {@code PipelineHelper}, which describes the upstream intermediate
+     * operations.
+     *
+     * @param helper the pipeline helper
+     * @param spliterator the source spliterator
+     * @return the result of the evaluation
+     */
+    <P_IN> R evaluateSequential(PipelineHelper<E_IN> helper,
+                                Spliterator<P_IN> spliterator);
+}
diff --git a/java/util/stream/TerminalSink.java b/java/util/stream/TerminalSink.java
new file mode 100644
index 0000000..9808d54
--- /dev/null
+++ b/java/util/stream/TerminalSink.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.function.Supplier;
+
+/**
+ * A {@link Sink} which accumulates state as elements are accepted, and allows
+ * a result to be retrieved after the computation is finished.
+ *
+ * @param <T> the type of elements to be accepted
+ * @param <R> the type of the result
+ *
+ * @since 1.8
+ */
+interface TerminalSink<T, R> extends Sink<T>, Supplier<R> { }
diff --git a/java/util/stream/TestData.java b/java/util/stream/TestData.java
new file mode 100644
index 0000000..c763e84
--- /dev/null
+++ b/java/util/stream/TestData.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.DoubleConsumer;
+import java.util.function.Function;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.function.Supplier;
+import java.util.function.ToIntFunction;
+
+/** Describes a test data set for use in stream tests */
+public interface TestData<T, S extends BaseStream<T, S>>
+        extends Iterable<T> {
+
+    default int size() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    default Iterator<T> iterator() {
+        return Spliterators.iterator(spliterator());
+    }
+
+    Spliterator<T> spliterator();
+
+    default boolean isOrdered() {
+        return spliterator().hasCharacteristics(Spliterator.ORDERED);
+    }
+
+    StreamShape getShape();
+
+    default <A extends Collection<? super T>> A into(A target) {
+        spliterator().forEachRemaining(target::add);
+        return target;
+    }
+
+    S stream();
+
+    S parallelStream();
+
+    public interface OfRef<T> extends TestData<T, Stream<T>> { }
+
+    public interface OfInt extends TestData<Integer, IntStream> { }
+
+    public interface OfLong extends TestData<Long, LongStream> { }
+
+    public interface OfDouble extends TestData<Double, DoubleStream> { }
+
+    // @@@ Temporary garbage class to avoid triggering bugs with lambdas in static methods in interfaces
+    public static class Factory {
+        public static <T> OfRef<T> ofArray(String name, T[] array) {
+            return new AbstractTestData.RefTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                      Arrays::spliterator, a -> a.length);
+        }
+
+        public static <T> OfRef<T> ofCollection(String name, Collection<T> collection) {
+            return new AbstractTestData.RefTestData<>(name, collection, Collection::stream, Collection::parallelStream,
+                                                      Collection::spliterator, Collection::size);
+        }
+
+        public static <T> OfRef<T> ofSpinedBuffer(String name, SpinedBuffer<T> buffer) {
+            return new AbstractTestData.RefTestData<>(name, buffer,
+                                                      b -> StreamSupport.stream(b.spliterator(), false),
+                                                      b -> StreamSupport.stream(b.spliterator(), true),
+                                                      SpinedBuffer::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static <T> OfRef<T> ofSupplier(String name, Supplier<Stream<T>> supplier) {
+            return new AbstractTestData.RefTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static <T> OfRef<T> ofRefNode(String name, Node<T> node) {
+            return new AbstractTestData.RefTestData<>(name, node,
+                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, false),
+                                                      n -> StreamSupport.stream(n::spliterator, Spliterator.SIZED | Spliterator.ORDERED, true),
+                                                      Node::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // int factories
+        public static <T> OfInt ofArray(String name, int[] array) {
+            return new AbstractTestData.IntTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                      Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfInt ofSpinedBuffer(String name, SpinedBuffer.OfInt buffer) {
+            return new AbstractTestData.IntTestData<>(name, buffer,
+                                                      b -> StreamSupport.intStream(b.spliterator(), false),
+                                                      b -> StreamSupport.intStream(b.spliterator(), true),
+                                                      SpinedBuffer.OfInt::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static OfInt ofIntSupplier(String name, Supplier<IntStream> supplier) {
+            return new AbstractTestData.IntTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfInt ofNode(String name, Node.OfInt node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.IntTestData<>(name, node,
+                                                      n -> StreamSupport.intStream(n::spliterator, characteristics, false),
+                                                      n -> StreamSupport.intStream(n::spliterator, characteristics, true),
+                                                      Node.OfInt::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // long factories
+        public static <T> OfLong ofArray(String name, long[] array) {
+            return new AbstractTestData.LongTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                       Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfLong ofSpinedBuffer(String name, SpinedBuffer.OfLong buffer) {
+            return new AbstractTestData.LongTestData<>(name, buffer,
+                                                      b -> StreamSupport.longStream(b.spliterator(), false),
+                                                      b -> StreamSupport.longStream(b.spliterator(), true),
+                                                      SpinedBuffer.OfLong::spliterator,
+                                                      b -> (int) b.count());
+        }
+
+        public static OfLong ofLongSupplier(String name, Supplier<LongStream> supplier) {
+            return new AbstractTestData.LongTestData<>(name, supplier,
+                                                      Supplier::get,
+                                                      s -> s.get().parallel(),
+                                                      s -> s.get().spliterator(),
+                                                      s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfLong ofNode(String name, Node.OfLong node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.LongTestData<>(name, node,
+                                                      n -> StreamSupport.longStream(n::spliterator, characteristics, false),
+                                                      n -> StreamSupport.longStream(n::spliterator, characteristics, true),
+                                                      Node.OfLong::spliterator,
+                                                      n -> (int) n.count());
+        }
+
+        // double factories
+        public static <T> OfDouble ofArray(String name, double[] array) {
+            return new AbstractTestData.DoubleTestData<>(name, array, Arrays::stream, a -> Arrays.stream(a).parallel(),
+                                                         Arrays::spliterator, a -> a.length);
+        }
+
+        public static OfDouble ofSpinedBuffer(String name, SpinedBuffer.OfDouble buffer) {
+            return new AbstractTestData.DoubleTestData<>(name, buffer,
+                                                         b -> StreamSupport.doubleStream(b.spliterator(), false),
+                                                         b -> StreamSupport.doubleStream(b.spliterator(), true),
+                                                         SpinedBuffer.OfDouble::spliterator,
+                                                         b -> (int) b.count());
+        }
+
+        public static OfDouble ofDoubleSupplier(String name, Supplier<DoubleStream> supplier) {
+            return new AbstractTestData.DoubleTestData<>(name, supplier,
+                                                         Supplier::get,
+                                                         s -> s.get().parallel(),
+                                                         s -> s.get().spliterator(),
+                                                         s -> (int) s.get().spliterator().getExactSizeIfKnown());
+        }
+
+        public static OfDouble ofNode(String name, Node.OfDouble node) {
+            int characteristics = Spliterator.SIZED | Spliterator.ORDERED;
+            return new AbstractTestData.DoubleTestData<>(name, node,
+                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics, false),
+                                                         n -> StreamSupport.doubleStream(n::spliterator, characteristics, true),
+                                                         Node.OfDouble::spliterator,
+                                                         n -> (int) n.count());
+        }
+    }
+
+
+    abstract class AbstractTestData<T, S extends BaseStream<T, S>,
+            T_STATE,
+                                    T_SPLITR extends Spliterator<T>>
+            implements TestData<T, S> {
+        private final String name;
+        private final StreamShape shape;
+        protected final T_STATE state;
+        private final ToIntFunction<T_STATE> sizeFn;
+        private final Function<T_STATE, S> streamFn;
+        private final Function<T_STATE, S> parStreamFn;
+        private final Function<T_STATE, T_SPLITR> splitrFn;
+
+        AbstractTestData(String name,
+                         StreamShape shape,
+                         T_STATE state,
+                         Function<T_STATE, S> streamFn,
+                         Function<T_STATE, S> parStreamFn,
+                         Function<T_STATE, T_SPLITR> splitrFn,
+                         ToIntFunction<T_STATE> sizeFn) {
+            this.name = name;
+            this.shape = shape;
+            this.state = state;
+            this.streamFn = streamFn;
+            this.parStreamFn = parStreamFn;
+            this.splitrFn = splitrFn;
+            this.sizeFn = sizeFn;
+        }
+
+        @Override
+        public StreamShape getShape() {
+            return shape;
+        }
+
+        @Override
+        public String toString() {
+            return getClass().getSimpleName() + "[" + name + "]";
+        }
+
+        @Override
+        public int size() {
+            return sizeFn.applyAsInt(state);
+        }
+
+        @Override
+        public T_SPLITR spliterator() {
+            return splitrFn.apply(state);
+        }
+
+        @Override
+        public S stream() {
+            return streamFn.apply(state);
+        }
+
+        @Override
+        public S parallelStream() {
+            return parStreamFn.apply(state);
+        }
+
+        public static class RefTestData<T, I>
+                extends AbstractTestData<T, Stream<T>, I, Spliterator<T>>
+                implements TestData.OfRef<T> {
+
+            protected RefTestData(String name,
+                                  I state,
+                                  Function<I, Stream<T>> streamFn,
+                                  Function<I, Stream<T>> parStreamFn,
+                                  Function<I, Spliterator<T>> splitrFn,
+                                  ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.REFERENCE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+        }
+
+        static class IntTestData<I>
+                extends AbstractTestData<Integer, IntStream, I, Spliterator.OfInt>
+                implements TestData.OfInt {
+
+            protected IntTestData(String name,
+                                  I state,
+                                  Function<I, IntStream> streamFn,
+                                  Function<I, IntStream> parStreamFn,
+                                  Function<I, Spliterator.OfInt> splitrFn,
+                                  ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.INT_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfInt iterator() {
+                return Spliterators.iterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Integer>> A into(A target) {
+                spliterator().forEachRemaining((IntConsumer) target::add);
+                return target;
+            }
+        }
+
+        static class LongTestData<I>
+                extends AbstractTestData<Long, LongStream, I, Spliterator.OfLong>
+                implements TestData.OfLong {
+
+            protected LongTestData(String name,
+                                   I state,
+                                   Function<I, LongStream> streamFn,
+                                   Function<I, LongStream> parStreamFn,
+                                   Function<I, Spliterator.OfLong> splitrFn,
+                                   ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.LONG_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfLong iterator() {
+                return Spliterators.iterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Long>> A into(A target) {
+                spliterator().forEachRemaining((LongConsumer) target::add);
+                return target;
+            }
+        }
+
+        static class DoubleTestData<I>
+                extends AbstractTestData<Double, DoubleStream, I, Spliterator.OfDouble>
+                implements OfDouble {
+
+            protected DoubleTestData(String name,
+                                     I state,
+                                     Function<I, DoubleStream> streamFn,
+                                     Function<I, DoubleStream> parStreamFn,
+                                     Function<I, Spliterator.OfDouble> splitrFn,
+                                     ToIntFunction<I> sizeFn) {
+                super(name, StreamShape.DOUBLE_VALUE, state, streamFn, parStreamFn, splitrFn, sizeFn);
+            }
+
+            @Override
+            public PrimitiveIterator.OfDouble iterator() {
+                return Spliterators.iterator(spliterator());
+            }
+
+            @Override
+            public <A extends Collection<? super Double>> A into(A target) {
+                spliterator().forEachRemaining((DoubleConsumer) target::add);
+                return target;
+            }
+        }
+    }
+}
diff --git a/java/util/stream/TestFlagExpectedOp.java b/java/util/stream/TestFlagExpectedOp.java
new file mode 100644
index 0000000..c59a185
--- /dev/null
+++ b/java/util/stream/TestFlagExpectedOp.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import org.testng.Assert;
+
+import java.util.EnumSet;
+
+class TestFlagExpectedOp<T> extends FlagDeclaringOp<T> {
+
+    static class Builder<T> {
+        final int flags;
+        StreamShape shape = StreamShape.REFERENCE;
+
+        EnumSet<StreamOpFlag> known = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> preserve = EnumSet.noneOf(StreamOpFlag.class);
+        EnumSet<StreamOpFlag> notKnown = EnumSet.noneOf(StreamOpFlag.class);
+
+        Builder(int flags) {
+            this.flags = flags;
+        }
+
+        Builder<T> known(EnumSet<StreamOpFlag> known) {
+            this.known = known;
+            return this;
+        }
+
+        Builder<T> preserve(EnumSet<StreamOpFlag> preserve) {
+            this.preserve = preserve;
+            return this;
+        }
+
+        Builder<T> notKnown(EnumSet<StreamOpFlag> notKnown) {
+            this.notKnown = notKnown;
+            return this;
+        }
+
+        Builder<T> shape(StreamShape shape) {
+            this.shape = shape;
+            return this;
+        }
+
+        TestFlagExpectedOp<T> build() {
+            return new TestFlagExpectedOp<>(flags, known, preserve, notKnown, shape);
+        }
+    }
+
+    final EnumSet<StreamOpFlag> known;
+    final EnumSet<StreamOpFlag> preserve;
+    final EnumSet<StreamOpFlag> notKnown;
+    final StreamShape shape;
+
+    TestFlagExpectedOp(int flags,
+                       EnumSet<StreamOpFlag> known,
+                       EnumSet<StreamOpFlag> preserve,
+                       EnumSet<StreamOpFlag> notKnown) {
+        this(flags, known, preserve, notKnown, StreamShape.REFERENCE);
+    }
+
+    TestFlagExpectedOp(int flags,
+                       EnumSet<StreamOpFlag> known,
+                       EnumSet<StreamOpFlag> preserve,
+                       EnumSet<StreamOpFlag> notKnown,
+                       StreamShape shape) {
+        super(flags);
+        this.known = known;
+        this.preserve = preserve;
+        this.notKnown = notKnown;
+        this.shape = shape;
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public Sink<T> opWrapSink(int flags, boolean parallel, Sink upstream) {
+        assertFlags(flags);
+        return upstream;
+    }
+
+    private void assertFlags(int flags) {
+        for (StreamOpFlag f : known) {
+            Assert.assertTrue(f.isKnown(flags),
+                              String.format("Flag %s is not known, but should be known.", f.toString()));
+        }
+
+        for (StreamOpFlag f : preserve) {
+            Assert.assertTrue(f.isPreserved(flags),
+                              String.format("Flag %s is not preserved, but should be preserved.", f.toString()));
+        }
+
+        for (StreamOpFlag f : notKnown) {
+            Assert.assertFalse(f.isKnown(flags),
+                               String.format("Flag %s is known, but should be not known.", f.toString()));
+        }
+    }
+}
diff --git a/java/util/stream/Tripwire.java b/java/util/stream/Tripwire.java
new file mode 100644
index 0000000..c6558b9
--- /dev/null
+++ b/java/util/stream/Tripwire.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import sun.util.logging.PlatformLogger;
+
+/**
+ * Utility class for detecting inadvertent uses of boxing in
+ * {@code java.util.stream} classes.  The detection is turned on or off based on
+ * whether the system property {@code org.openjdk.java.util.stream.tripwire} is
+ * considered {@code true} according to {@link Boolean#getBoolean(String)}.
+ * This should normally be turned off for production use.
+ *
+ * @apiNote
+ * Typical usage would be for boxing code to do:
+ * <pre>{@code
+ *     if (Tripwire.ENABLED)
+ *         Tripwire.trip(getClass(), "{0} calling Sink.OfInt.accept(Integer)");
+ * }</pre>
+ *
+ * @since 1.8
+ */
+final class Tripwire {
+    private static final String TRIPWIRE_PROPERTY = "org.openjdk.java.util.stream.tripwire";
+
+    /** Should debugging checks be enabled? */
+    static final boolean ENABLED = AccessController.doPrivileged(
+            (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(TRIPWIRE_PROPERTY));
+
+    private Tripwire() { }
+
+    /**
+     * Produces a log warning, using {@code PlatformLogger.getLogger(className)},
+     * using the supplied message.  The class name of {@code trippingClass} will
+     * be used as the first parameter to the message.
+     *
+     * @param trippingClass Name of the class generating the message
+     * @param msg A message format string of the type expected by
+     * {@link PlatformLogger}
+     */
+    static void trip(Class<?> trippingClass, String msg) {
+        PlatformLogger.getLogger(trippingClass.getName()).warning(msg, trippingClass.getName());
+    }
+}
diff --git a/java/util/stream/package-info.java b/java/util/stream/package-info.java
new file mode 100644
index 0000000..016c86d
--- /dev/null
+++ b/java/util/stream/package-info.java
@@ -0,0 +1,740 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Classes to support functional-style operations on streams of elements, such
+ * as map-reduce transformations on collections.  For example:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(b -> b.getColor() == RED)
+ *                      .mapToInt(b -> b.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * <p>Here we use {@code widgets}, a {@code Collection<Widget>},
+ * as a source for a stream, and then perform a filter-map-reduce on the stream
+ * to obtain the sum of the weights of the red widgets.  (Summation is an
+ * example of a <a href="package-summary.html#Reduction">reduction</a>
+ * operation.)
+ *
+ * <p>The key abstraction introduced in this package is <em>stream</em>.  The
+ * classes {@link java.util.stream.Stream}, {@link java.util.stream.IntStream},
+ * {@link java.util.stream.LongStream}, and {@link java.util.stream.DoubleStream}
+ * are streams over objects and the primitive {@code int}, {@code long} and
+ * {@code double} types.  Streams differ from collections in several ways:
+ *
+ * <ul>
+ *     <li>No storage.  A stream is not a data structure that stores elements;
+ *     instead, it conveys elements from a source such as a data structure,
+ *     an array, a generator function, or an I/O channel, through a pipeline of
+ *     computational operations.</li>
+ *     <li>Functional in nature.  An operation on a stream produces a result,
+ *     but does not modify its source.  For example, filtering a {@code Stream}
+ *     obtained from a collection produces a new {@code Stream} without the
+ *     filtered elements, rather than removing elements from the source
+ *     collection.</li>
+ *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping,
+ *     or duplicate removal, can be implemented lazily, exposing opportunities
+ *     for optimization.  For example, "find the first {@code String} with
+ *     three consecutive vowels" need not examine all the input strings.
+ *     Stream operations are divided into intermediate ({@code Stream}-producing)
+ *     operations and terminal (value- or side-effect-producing) operations.
+ *     Intermediate operations are always lazy.</li>
+ *     <li>Possibly unbounded.  While collections have a finite size, streams
+ *     need not.  Short-circuiting operations such as {@code limit(n)} or
+ *     {@code findFirst()} can allow computations on infinite streams to
+ *     complete in finite time.</li>
+ *     <li>Consumable. The elements of a stream are only visited once during
+ *     the life of a stream. Like an {@link java.util.Iterator}, a new stream
+ *     must be generated to revisit the same elements of the source.
+ *     </li>
+ * </ul>
+ *
+ * Streams can be obtained in a number of ways. Some examples include:
+ * <ul>
+ *     <li>From a {@link java.util.Collection} via the {@code stream()} and
+ *     {@code parallelStream()} methods;</li>
+ *     <li>From an array via {@link java.util.Arrays#stream(Object[])};</li>
+ *     <li>From static factory methods on the stream classes, such as
+ *     {@link java.util.stream.Stream#of(Object[])},
+ *     {@link java.util.stream.IntStream#range(int, int)}
+ *     or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)};</li>
+ *     <li>The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};</li>
+ *     <li>Streams of file paths can be obtained from methods in {@link java.nio.file.Files};</li>
+ *     <li>Streams of random numbers can be obtained from {@link java.util.Random#ints()};</li>
+ *     <li>Numerous other stream-bearing methods in the JDK, including
+ *     {@link java.util.BitSet#stream()},
+ *     {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)},
+ *     and {@link java.util.jar.JarFile#stream()}.</li>
+ * </ul>
+ *
+ * <p>Additional stream sources can be provided by third-party libraries using
+ * <a href="package-summary.html#StreamSources">these techniques</a>.
+ *
+ * <h2><a name="StreamOps">Stream operations and pipelines</a></h2>
+ *
+ * <p>Stream operations are divided into <em>intermediate</em> and
+ * <em>terminal</em> operations, and are combined to form <em>stream
+ * pipelines</em>.  A stream pipeline consists of a source (such as a
+ * {@code Collection}, an array, a generator function, or an I/O channel);
+ * followed by zero or more intermediate operations such as
+ * {@code Stream.filter} or {@code Stream.map}; and a terminal operation such
+ * as {@code Stream.forEach} or {@code Stream.reduce}.
+ *
+ * <p>Intermediate operations return a new stream.  They are always
+ * <em>lazy</em>; executing an intermediate operation such as
+ * {@code filter()} does not actually perform any filtering, but instead
+ * creates a new stream that, when traversed, contains the elements of
+ * the initial stream that match the given predicate.  Traversal
+ * of the pipeline source does not begin until the terminal operation of the
+ * pipeline is executed.
+ *
+ * <p>Terminal operations, such as {@code Stream.forEach} or
+ * {@code IntStream.sum}, may traverse the stream to produce a result or a
+ * side-effect. After the terminal operation is performed, the stream pipeline
+ * is considered consumed, and can no longer be used; if you need to traverse
+ * the same data source again, you must return to the data source to get a new
+ * stream.  In almost all cases, terminal operations are <em>eager</em>,
+ * completing their traversal of the data source and processing of the pipeline
+ * before returning.  Only the terminal operations {@code iterator()} and
+ * {@code spliterator()} are not; these are provided as an "escape hatch" to enable
+ * arbitrary client-controlled pipeline traversals in the event that the
+ * existing operations are not sufficient to the task.
+ *
+ * <p> Processing streams lazily allows for significant efficiencies; in a
+ * pipeline such as the filter-map-sum example above, filtering, mapping, and
+ * summing can be fused into a single pass on the data, with minimal
+ * intermediate state. Laziness also allows avoiding examining all the data
+ * when it is not necessary; for operations such as "find the first string
+ * longer than 1000 characters", it is only necessary to examine just enough
+ * strings to find one that has the desired characteristics without examining
+ * all of the strings available from the source. (This behavior becomes even
+ * more important when the input stream is infinite and not merely large.)
+ *
+ * <p>Intermediate operations are further divided into <em>stateless</em>
+ * and <em>stateful</em> operations. Stateless operations, such as {@code filter}
+ * and {@code map}, retain no state from previously seen element when processing
+ * a new element -- each element can be processed
+ * independently of operations on other elements.  Stateful operations, such as
+ * {@code distinct} and {@code sorted}, may incorporate state from previously
+ * seen elements when processing new elements.
+ *
+ * <p>Stateful operations may need to process the entire input
+ * before producing a result.  For example, one cannot produce any results from
+ * sorting a stream until one has seen all elements of the stream.  As a result,
+ * under parallel computation, some pipelines containing stateful intermediate
+ * operations may require multiple passes on the data or may need to buffer
+ * significant data.  Pipelines containing exclusively stateless intermediate
+ * operations can be processed in a single pass, whether sequential or parallel,
+ * with minimal data buffering.
+ *
+ * <p>Further, some operations are deemed <em>short-circuiting</em> operations.
+ * An intermediate operation is short-circuiting if, when presented with
+ * infinite input, it may produce a finite stream as a result.  A terminal
+ * operation is short-circuiting if, when presented with infinite input, it may
+ * terminate in finite time.  Having a short-circuiting operation in the pipeline
+ * is a necessary, but not sufficient, condition for the processing of an infinite
+ * stream to terminate normally in finite time.
+ *
+ * <h3>Parallelism</h3>
+ *
+ * <p>Processing elements with an explicit {@code for-}loop is inherently serial.
+ * Streams facilitate parallel execution by reframing the computation as a pipeline of
+ * aggregate operations, rather than as imperative operations on each individual
+ * element.  All streams operations can execute either in serial or in parallel.
+ * The stream implementations in the JDK create serial streams unless parallelism is
+ * explicitly requested.  For example, {@code Collection} has methods
+ * {@link java.util.Collection#stream} and {@link java.util.Collection#parallelStream},
+ * which produce sequential and parallel streams respectively; other
+ * stream-bearing methods such as {@link java.util.stream.IntStream#range(int, int)}
+ * produce sequential streams but these streams can be efficiently parallelized by
+ * invoking their {@link java.util.stream.BaseStream#parallel()} method.
+ * To execute the prior "sum of weights of widgets" query in parallel, we would
+ * do:
+ *
+ * <pre>{@code
+ *     int sumOfWeights = widgets.}<code><b>parallelStream()</b></code>{@code
+ *                               .filter(b -> b.getColor() == RED)
+ *                               .mapToInt(b -> b.getWeight())
+ *                               .sum();
+ * }</pre>
+ *
+ * <p>The only difference between the serial and parallel versions of this
+ * example is the creation of the initial stream, using "{@code parallelStream()}"
+ * instead of "{@code stream()}".  When the terminal operation is initiated,
+ * the stream pipeline is executed sequentially or in parallel depending on the
+ * orientation of the stream on which it is invoked.  Whether a stream will execute in serial or
+ * parallel can be determined with the {@code isParallel()} method, and the
+ * orientation of a stream can be modified with the
+ * {@link java.util.stream.BaseStream#sequential()} and
+ * {@link java.util.stream.BaseStream#parallel()} operations.  When the terminal
+ * operation is initiated, the stream pipeline is executed sequentially or in
+ * parallel depending on the mode of the stream on which it is invoked.
+ *
+ * <p>Except for operations identified as explicitly nondeterministic, such
+ * as {@code findAny()}, whether a stream executes sequentially or in parallel
+ * should not change the result of the computation.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, which are often lambda expressions.  To preserve correct behavior,
+ * these <em>behavioral parameters</em> must be <em>non-interfering</em>, and in
+ * most cases must be <em>stateless</em>.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.
+ *
+ * <h3><a name="NonInterference">Non-interference</a></h3>
+ *
+ * Streams enable you to execute possibly-parallel aggregate operations over a
+ * variety of data sources, including even non-thread-safe collections such as
+ * {@code ArrayList}. This is possible only if we can prevent
+ * <em>interference</em> with the data source during the execution of a stream
+ * pipeline.  Except for the escape-hatch operations {@code iterator()} and
+ * {@code spliterator()}, execution begins when the terminal operation is
+ * invoked, and ends when the terminal operation completes.  For most data
+ * sources, preventing interference means ensuring that the data source is
+ * <em>not modified at all</em> during the execution of the stream pipeline.
+ * The notable exception to this are streams whose sources are concurrent
+ * collections, which are specifically designed to handle concurrent modification.
+ * Concurrent stream sources are those whose {@code Spliterator} reports the
+ * {@code CONCURRENT} characteristic.
+ *
+ * <p>Accordingly, behavioral parameters in stream pipelines whose source might
+ * not be concurrent should never modify the stream's data source.
+ * A behavioral parameter is said to <em>interfere</em> with a non-concurrent
+ * data source if it modifies, or causes to be
+ * modified, the stream's data source.  The need for non-interference applies
+ * to all pipelines, not just parallel ones.  Unless the stream source is
+ * concurrent, modifying a stream's data source during execution of a stream
+ * pipeline can cause exceptions, incorrect answers, or nonconformant behavior.
+ *
+ * For well-behaved stream sources, the source can be modified before the
+ * terminal operation commences and those modifications will be reflected in
+ * the covered elements.  For example, consider the following code:
+ *
+ * <pre>{@code
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     l.add("three");
+ *     String s = sl.collect(joining(" "));
+ * }</pre>
+ *
+ * First a list is created consisting of two strings: "one"; and "two". Then a
+ * stream is created from that list. Next the list is modified by adding a third
+ * string: "three". Finally the elements of the stream are collected and joined
+ * together. Since the list was modified before the terminal {@code collect}
+ * operation commenced the result will be a string of "one two three". All the
+ * streams returned from JDK collections, and most other JDK classes,
+ * are well-behaved in this manner; for streams generated by other libraries, see
+ * <a href="package-summary.html#StreamSources">Low-level stream
+ * construction</a> for requirements for building well-behaved streams.
+ *
+ * <h3><a name="Statelessness">Stateless behaviors</a></h3>
+ *
+ * Stream pipeline results may be nondeterministic or incorrect if the behavioral
+ * parameters to the stream operations are <em>stateful</em>.  A stateful lambda
+ * (or other object implementing the appropriate functional interface) is one
+ * whose result depends on any state which might change during the execution
+ * of the stream pipeline.  An example of a stateful lambda is the parameter
+ * to {@code map()} in:
+ *
+ * <pre>{@code
+ *     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
+ *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
+ * }</pre>
+ *
+ * Here, if the mapping operation is performed in parallel, the results for the
+ * same input could vary from run to run, due to thread scheduling differences,
+ * whereas, with a stateless lambda expression the results would always be the
+ * same.
+ *
+ * <p>Note also that attempting to access mutable state from behavioral parameters
+ * presents you with a bad choice with respect to safety and performance; if
+ * you do not synchronize access to that state, you have a data race and
+ * therefore your code is broken, but if you do synchronize access to that
+ * state, you risk having contention undermine the parallelism you are seeking
+ * to benefit from.  The best approach is to avoid stateful behavioral
+ * parameters to stream operations entirely; there is usually a way to
+ * restructure the stream pipeline to avoid statefulness.
+ *
+ * <h3>Side-effects</h3>
+ *
+ * Side-effects in behavioral parameters to stream operations are, in general,
+ * discouraged, as they can often lead to unwitting violations of the
+ * statelessness requirement, as well as other thread-safety hazards.
+ *
+ * <p>If the behavioral parameters do have side-effects, unless explicitly
+ * stated, there are no guarantees as to the
+ * <a href="../concurrent/package-summary.html#MemoryVisibility"><i>visibility</i></a>
+ * of those side-effects to other threads, nor are there any guarantees that
+ * different operations on the "same" element within the same stream pipeline
+ * are executed in the same thread.  Further, the ordering of those effects
+ * may be surprising.  Even when a pipeline is constrained to produce a
+ * <em>result</em> that is consistent with the encounter order of the stream
+ * source (for example, {@code IntStream.range(0,5).parallel().map(x -> x*2).toArray()}
+ * must produce {@code [0, 2, 4, 6, 8]}), no guarantees are made as to the order
+ * in which the mapper function is applied to individual elements, or in what
+ * thread any behavioral parameter is executed for a given element.
+ *
+ * <p>Many computations where one might be tempted to use side effects can be more
+ * safely and efficiently expressed without side-effects, such as using
+ * <a href="package-summary.html#Reduction">reduction</a> instead of mutable
+ * accumulators. However, side-effects such as using {@code println()} for debugging
+ * purposes are usually harmless.  A small number of stream operations, such as
+ * {@code forEach()} and {@code peek()}, can operate only via side-effects;
+ * these should be used with care.
+ *
+ * <p>As an example of how to transform a stream pipeline that inappropriately
+ * uses side-effects to one that does not, the following code searches a stream
+ * of strings for those matching a given regular expression, and puts the
+ * matches in a list.
+ *
+ * <pre>{@code
+ *     ArrayList<String> results = new ArrayList<>();
+ *     stream.filter(s -> pattern.matcher(s).matches())
+ *           .forEach(s -> results.add(s));  // Unnecessary use of side-effects!
+ * }</pre>
+ *
+ * This code unnecessarily uses side-effects.  If executed in parallel, the
+ * non-thread-safety of {@code ArrayList} would cause incorrect results, and
+ * adding needed synchronization would cause contention, undermining the
+ * benefit of parallelism.  Furthermore, using side-effects here is completely
+ * unnecessary; the {@code forEach()} can simply be replaced with a reduction
+ * operation that is safer, more efficient, and more amenable to
+ * parallelization:
+ *
+ * <pre>{@code
+ *     List<String>results =
+ *         stream.filter(s -> pattern.matcher(s).matches())
+ *               .collect(Collectors.toList());  // No side-effects!
+ * }</pre>
+ *
+ * <h3><a name="Ordering">Ordering</a></h3>
+ *
+ * <p>Streams may or may not have a defined <em>encounter order</em>.  Whether
+ * or not a stream has an encounter order depends on the source and the
+ * intermediate operations.  Certain stream sources (such as {@code List} or
+ * arrays) are intrinsically ordered, whereas others (such as {@code HashSet})
+ * are not.  Some intermediate operations, such as {@code sorted()}, may impose
+ * an encounter order on an otherwise unordered stream, and others may render an
+ * ordered stream unordered, such as {@link java.util.stream.BaseStream#unordered()}.
+ * Further, some terminal operations may ignore encounter order, such as
+ * {@code forEach()}.
+ *
+ * <p>If a stream is ordered, most operations are constrained to operate on the
+ * elements in their encounter order; if the source of a stream is a {@code List}
+ * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
+ * must be {@code [2, 4, 6]}.  However, if the source has no defined encounter
+ * order, then any permutation of the values {@code [2, 4, 6]} would be a valid
+ * result.
+ *
+ * <p>For sequential streams, the presence or absence of an encounter order does
+ * not affect performance, only determinism.  If a stream is ordered, repeated
+ * execution of identical stream pipelines on an identical source will produce
+ * an identical result; if it is not ordered, repeated execution might produce
+ * different results.
+ *
+ * <p>For parallel streams, relaxing the ordering constraint can sometimes enable
+ * more efficient execution.  Certain aggregate operations,
+ * such as filtering duplicates ({@code distinct()}) or grouped reductions
+ * ({@code Collectors.groupingBy()}) can be implemented more efficiently if ordering of elements
+ * is not relevant.  Similarly, operations that are intrinsically tied to encounter order,
+ * such as {@code limit()}, may require
+ * buffering to ensure proper ordering, undermining the benefit of parallelism.
+ * In cases where the stream has an encounter order, but the user does not
+ * particularly <em>care</em> about that encounter order, explicitly de-ordering
+ * the stream with {@link java.util.stream.BaseStream#unordered() unordered()} may
+ * improve parallel performance for some stateful or terminal operations.
+ * However, most stream pipelines, such as the "sum of weight of blocks" example
+ * above, still parallelize efficiently even under ordering constraints.
+ *
+ * <h2><a name="Reduction">Reduction operations</a></h2>
+ *
+ * A <em>reduction</em> operation (also called a <em>fold</em>) takes a sequence
+ * of input elements and combines them into a single summary result by repeated
+ * application of a combining operation, such as finding the sum or maximum of
+ * a set of numbers, or accumulating elements into a list.  The streams classes have
+ * multiple forms of general reduction operations, called
+ * {@link java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduce()}
+ * and {@link java.util.stream.Stream#collect(java.util.stream.Collector) collect()},
+ * as well as multiple specialized reduction forms such as
+ * {@link java.util.stream.IntStream#sum() sum()}, {@link java.util.stream.IntStream#max() max()},
+ * or {@link java.util.stream.IntStream#count() count()}.
+ *
+ * <p>Of course, such operations can be readily implemented as simple sequential
+ * loops, as in:
+ * <pre>{@code
+ *    int sum = 0;
+ *    for (int x : numbers) {
+ *       sum += x;
+ *    }
+ * }</pre>
+ * However, there are good reasons to prefer a reduce operation
+ * over a mutative accumulation such as the above.  Not only is a reduction
+ * "more abstract" -- it operates on the stream as a whole rather than individual
+ * elements -- but a properly constructed reduce operation is inherently
+ * parallelizable, so long as the function(s) used to process the elements
+ * are <a href="package-summary.html#Associativity">associative</a> and
+ * <a href="package-summary.html#NonInterfering">stateless</a>.
+ * For example, given a stream of numbers for which we want to find the sum, we
+ * can write:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, (x,y) -> x+y);
+ * }</pre>
+ * or:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, Integer::sum);
+ * }</pre>
+ *
+ * <p>These reduction operations can run safely in parallel with almost no
+ * modification:
+ * <pre>{@code
+ *    int sum = numbers.parallelStream().reduce(0, Integer::sum);
+ * }</pre>
+ *
+ * <p>Reduction parallellizes well because the implementation
+ * can operate on subsets of the data in parallel, and then combine the
+ * intermediate results to get the final correct answer.  (Even if the language
+ * had a "parallel for-each" construct, the mutative accumulation approach would
+ * still required the developer to provide
+ * thread-safe updates to the shared accumulating variable {@code sum}, and
+ * the required synchronization would then likely eliminate any performance gain from
+ * parallelism.)  Using {@code reduce()} instead removes all of the
+ * burden of parallelizing the reduction operation, and the library can provide
+ * an efficient parallel implementation with no additional synchronization
+ * required.
+ *
+ * <p>The "widgets" examples shown earlier shows how reduction combines with
+ * other operations to replace for loops with bulk operations.  If {@code widgets}
+ * is a collection of {@code Widget} objects, which have a {@code getWeight} method,
+ * we can find the heaviest widget with:
+ * <pre>{@code
+ *     OptionalInt heaviest = widgets.parallelStream()
+ *                                   .mapToInt(Widget::getWeight)
+ *                                   .max();
+ * }</pre>
+ *
+ * <p>In its more general form, a {@code reduce} operation on elements of type
+ * {@code <T>} yielding a result of type {@code <U>} requires three parameters:
+ * <pre>{@code
+ * <U> U reduce(U identity,
+ *              BiFunction<U, ? super T, U> accumulator,
+ *              BinaryOperator<U> combiner);
+ * }</pre>
+ * Here, the <em>identity</em> element is both an initial seed value for the reduction
+ * and a default result if there are no input elements. The <em>accumulator</em>
+ * function takes a partial result and the next element, and produces a new
+ * partial result. The <em>combiner</em> function combines two partial results
+ * to produce a new partial result.  (The combiner is necessary in parallel
+ * reductions, where the input is partitioned, a partial accumulation computed
+ * for each partition, and then the partial results are combined to produce a
+ * final result.)
+ *
+ * <p>More formally, the {@code identity} value must be an <em>identity</em> for
+ * the combiner function. This means that for all {@code u},
+ * {@code combiner.apply(identity, u)} is equal to {@code u}. Additionally, the
+ * {@code combiner} function must be <a href="package-summary.html#Associativity">associative</a> and
+ * must be compatible with the {@code accumulator} function: for all {@code u}
+ * and {@code t}, {@code combiner.apply(u, accumulator.apply(identity, t))} must
+ * be {@code equals()} to {@code accumulator.apply(u, t)}.
+ *
+ * <p>The three-argument form is a generalization of the two-argument form,
+ * incorporating a mapping step into the accumulation step.  We could
+ * re-cast the simple sum-of-weights example using the more general form as
+ * follows:
+ * <pre>{@code
+ *     int sumOfWeights = widgets.stream()
+ *                               .reduce(0,
+ *                                       (sum, b) -> sum + b.getWeight())
+ *                                       Integer::sum);
+ * }</pre>
+ * though the explicit map-reduce form is more readable and therefore should
+ * usually be preferred. The generalized form is provided for cases where
+ * significant work can be optimized away by combining mapping and reducing
+ * into a single function.
+ *
+ * <h3><a name="MutableReduction">Mutable reduction</a></h3>
+ *
+ * A <em>mutable reduction operation</em> accumulates input elements into a
+ * mutable result container, such as a {@code Collection} or {@code StringBuilder},
+ * as it processes the elements in the stream.
+ *
+ * <p>If we wanted to take a stream of strings and concatenate them into a
+ * single long string, we <em>could</em> achieve this with ordinary reduction:
+ * <pre>{@code
+ *     String concatenated = strings.reduce("", String::concat)
+ * }</pre>
+ *
+ * <p>We would get the desired result, and it would even work in parallel.  However,
+ * we might not be happy about the performance!  Such an implementation would do
+ * a great deal of string copying, and the run time would be <em>O(n^2)</em> in
+ * the number of characters.  A more performant approach would be to accumulate
+ * the results into a {@link java.lang.StringBuilder}, which is a mutable
+ * container for accumulating strings.  We can use the same technique to
+ * parallelize mutable reduction as we do with ordinary reduction.
+ *
+ * <p>The mutable reduction operation is called
+ * {@link java.util.stream.Stream#collect(Collector) collect()},
+ * as it collects together the desired results into a result container such
+ * as a {@code Collection}.
+ * A {@code collect} operation requires three functions:
+ * a supplier function to construct new instances of the result container, an
+ * accumulator function to incorporate an input element into a result
+ * container, and a combining function to merge the contents of one result
+ * container into another.  The form of this is very similar to the general
+ * form of ordinary reduction:
+ * <pre>{@code
+ * <R> R collect(Supplier<R> supplier,
+ *               BiConsumer<R, ? super T> accumulator,
+ *               BiConsumer<R, R> combiner);
+ * }</pre>
+ * <p>As with {@code reduce()}, a benefit of expressing {@code collect} in this
+ * abstract way is that it is directly amenable to parallelization: we can
+ * accumulate partial results in parallel and then combine them, so long as the
+ * accumulation and combining functions satisfy the appropriate requirements.
+ * For example, to collect the String representations of the elements in a
+ * stream into an {@code ArrayList}, we could write the obvious sequential
+ * for-each form:
+ * <pre>{@code
+ *     ArrayList<String> strings = new ArrayList<>();
+ *     for (T element : stream) {
+ *         strings.add(element.toString());
+ *     }
+ * }</pre>
+ * Or we could use a parallelizable collect form:
+ * <pre>{@code
+ *     ArrayList<String> strings = stream.collect(() -> new ArrayList<>(),
+ *                                                (c, e) -> c.add(e.toString()),
+ *                                                (c1, c2) -> c1.addAll(c2));
+ * }</pre>
+ * or, pulling the mapping operation out of the accumulator function, we could
+ * express it more succinctly as:
+ * <pre>{@code
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+ * }</pre>
+ * Here, our supplier is just the {@link java.util.ArrayList#ArrayList()
+ * ArrayList constructor}, the accumulator adds the stringified element to an
+ * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
+ * to copy the strings from one container into the other.
+ *
+ * <p>The three aspects of {@code collect} -- supplier, accumulator, and
+ * combiner -- are tightly coupled.  We can use the abstraction of a
+ * {@link java.util.stream.Collector} to capture all three aspects.  The
+ * above example for collecting strings into a {@code List} can be rewritten
+ * using a standard {@code Collector} as:
+ * <pre>{@code
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(Collectors.toList());
+ * }</pre>
+ *
+ * <p>Packaging mutable reductions into a Collector has another advantage:
+ * composability.  The class {@link java.util.stream.Collectors} contains a
+ * number of predefined factories for collectors, including combinators
+ * that transform one collector into another.  For example, suppose we have a
+ * collector that computes the sum of the salaries of a stream of
+ * employees, as follows:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary);
+ * }</pre>
+ *
+ * (The {@code ?} for the second type parameter merely indicates that we don't
+ * care about the intermediate representation used by this collector.)
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse {@code summingSalaries} using
+ * {@link java.util.stream.Collectors#groupingBy(java.util.function.Function, java.util.stream.Collector) groupingBy}:
+ *
+ * <pre>{@code
+ *     Map<Department, Integer> salariesByDept
+ *         = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                            summingSalaries));
+ * }</pre>
+ *
+ * <p>As with the regular reduction operation, {@code collect()} operations can
+ * only be parallelized if appropriate conditions are met.  For any partially
+ * accumulated result, combining it with an empty result container must
+ * produce an equivalent result.  That is, for a partially accumulated result
+ * {@code p} that is the result of any series of accumulator and combiner
+ * invocations, {@code p} must be equivalent to
+ * {@code combiner.apply(p, supplier.get())}.
+ *
+ * <p>Further, however the computation is split, it must produce an equivalent
+ * result.  For any input elements {@code t1} and {@code t2}, the results
+ * {@code r1} and {@code r2} in the computation below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * }</pre>
+ *
+ * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}.
+ * but in some cases equivalence may be relaxed to account for differences in
+ * order.
+ *
+ * <h3><a name="ConcurrentReduction">Reduction, concurrency, and ordering</a></h3>
+ *
+ * With some complex reduction operations, for example a {@code collect()} that
+ * produces a {@code Map}, such as:
+ * <pre>{@code
+ *     Map<Buyer, List<Transaction>> salesByBuyer
+ *         = txns.parallelStream()
+ *               .collect(Collectors.groupingBy(Transaction::getBuyer));
+ * }</pre>
+ * it may actually be counterproductive to perform the operation in parallel.
+ * This is because the combining step (merging one {@code Map} into another by
+ * key) can be expensive for some {@code Map} implementations.
+ *
+ * <p>Suppose, however, that the result container used in this reduction
+ * was a concurrently modifiable collection -- such as a
+ * {@link java.util.concurrent.ConcurrentHashMap}. In that case, the parallel
+ * invocations of the accumulator could actually deposit their results
+ * concurrently into the same shared result container, eliminating the need for
+ * the combiner to merge distinct result containers. This potentially provides
+ * a boost to the parallel execution performance. We call this a
+ * <em>concurrent</em> reduction.
+ *
+ * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
+ * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
+ * characteristic.  However, a concurrent collection also has a downside.  If
+ * multiple threads are depositing results concurrently into a shared container,
+ * the order in which results are deposited is non-deterministic. Consequently,
+ * a concurrent reduction is only possible if ordering is not important for the
+ * stream being processed. The {@link java.util.stream.Stream#collect(Collector)}
+ * implementation will only perform a concurrent reduction if
+ * <ul>
+ * <li>The stream is parallel;</li>
+ * <li>The collector has the
+ * {@link java.util.stream.Collector.Characteristics#CONCURRENT} characteristic,
+ * and;</li>
+ * <li>Either the stream is unordered, or the collector has the
+ * {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic.
+ * </ul>
+ * You can ensure the stream is unordered by using the
+ * {@link java.util.stream.BaseStream#unordered()} method.  For example:
+ * <pre>{@code
+ *     Map<Buyer, List<Transaction>> salesByBuyer
+ *         = txns.parallelStream()
+ *               .unordered()
+ *               .collect(groupingByConcurrent(Transaction::getBuyer));
+ * }</pre>
+ * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
+ * concurrent equivalent of {@code groupingBy}).
+ *
+ * <p>Note that if it is important that the elements for a given key appear in
+ * the order they appear in the source, then we cannot use a concurrent
+ * reduction, as ordering is one of the casualties of concurrent insertion.
+ * We would then be constrained to implement either a sequential reduction or
+ * a merge-based parallel reduction.
+ *
+ * <h3><a name="Associativity">Associativity</a></h3>
+ *
+ * An operator or function {@code op} is <em>associative</em> if the following
+ * holds:
+ * <pre>{@code
+ *     (a op b) op c == a op (b op c)
+ * }</pre>
+ * The importance of this to parallel evaluation can be seen if we expand this
+ * to four terms:
+ * <pre>{@code
+ *     a op b op c op d == (a op b) op (c op d)
+ * }</pre>
+ * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
+ * then invoke {@code op} on the results.
+ *
+ * <p>Examples of associative operations include numeric addition, min, and
+ * max, and string concatenation.
+ *
+ * <h2><a name="StreamSources">Low-level stream construction</a></h2>
+ *
+ * So far, all the stream examples have used methods like
+ * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
+ * to obtain a stream.  How are those stream-bearing methods implemented?
+ *
+ * <p>The class {@link java.util.stream.StreamSupport} has a number of
+ * low-level methods for creating a stream, all using some form of a
+ * {@link java.util.Spliterator}. A spliterator is the parallel analogue of an
+ * {@link java.util.Iterator}; it describes a (possibly infinite) collection of
+ * elements, with support for sequentially advancing, bulk traversal, and
+ * splitting off some portion of the input into another spliterator which can
+ * be processed in parallel.  At the lowest level, all streams are driven by a
+ * spliterator.
+ *
+ * <p>There are a number of implementation choices in implementing a
+ * spliterator, nearly all of which are tradeoffs between simplicity of
+ * implementation and runtime performance of streams using that spliterator.
+ * The simplest, but least performant, way to create a spliterator is to
+ * create one from an iterator using
+ * {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
+ * While such a spliterator will work, it will likely offer poor parallel
+ * performance, since we have lost sizing information (how big is the
+ * underlying data set), as well as being constrained to a simplistic
+ * splitting algorithm.
+ *
+ * <p>A higher-quality spliterator will provide balanced and known-size
+ * splits, accurate sizing information, and a number of other
+ * {@link java.util.Spliterator#characteristics() characteristics} of the
+ * spliterator or data that can be used by implementations to optimize
+ * execution.
+ *
+ * <p>Spliterators for mutable data sources have an additional challenge;
+ * timing of binding to the data, since the data could change between the time
+ * the spliterator is created and the time the stream pipeline is executed.
+ * Ideally, a spliterator for a stream would report a characteristic of
+
+ * {@code IMMUTABLE} or {@code CONCURRENT}; if not it should be
+ * <a href="../Spliterator.html#binding"><em>late-binding</em></a>. If a source
+ * cannot directly supply a recommended spliterator, it may indirectly supply
+ * a spliterator using a {@code Supplier}, and construct a stream via the
+ * {@code Supplier}-accepting versions of
+ * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
+ * The spliterator is obtained from the supplier only after the terminal
+ * operation of the stream pipeline commences.
+ *
+ * <p>These requirements significantly reduce the scope of potential
+ * interference between mutations of the stream source and execution of stream
+ * pipelines. Streams based on spliterators with the desired characteristics,
+ * or those using the Supplier-based factory forms, are immune to
+ * modifications of the data source prior to commencement of the terminal
+ * operation (provided the behavioral parameters to the stream operations meet
+ * the required criteria for non-interference and statelessness).  See
+ * <a href="package-summary.html#NonInterference">Non-Interference</a>
+ * for more details.
+ *
+ * @since 1.8
+ */
+package java.util.stream;
+
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
diff --git a/java/util/zip/Adler32.java b/java/util/zip/Adler32.java
new file mode 100644
index 0000000..de279f9
--- /dev/null
+++ b/java/util/zip/Adler32.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * A class that can be used to compute the Adler-32 checksum of a data
+ * stream. An Adler-32 checksum is almost as reliable as a CRC-32 but
+ * can be computed much faster.
+ *
+ * <p> Passing a {@code null} argument to a method in this class will cause
+ * a {@link NullPointerException} to be thrown.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class Adler32 implements Checksum {
+
+    private int adler = 1;
+
+    /**
+     * Creates a new Adler32 object.
+     */
+    public Adler32() {
+    }
+
+    /**
+     * Updates the checksum with the specified byte (the low eight
+     * bits of the argument b).
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b) {
+        adler = update(adler, b);
+    }
+
+    /**
+     * Updates the checksum with the specified array of bytes.
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *          if {@code off} is negative, or {@code len} is negative,
+     *          or {@code off+len} is greater than the length of the
+     *          array {@code b}
+     */
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        adler = updateBytes(adler, b, off, len);
+    }
+
+    /**
+     * Updates the checksum with the specified array of bytes.
+     *
+     * @param b the byte array to update the checksum with
+     */
+    public void update(byte[] b) {
+        adler = updateBytes(adler, b, 0, b.length);
+    }
+
+
+    /**
+     * Updates the checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated using
+     * buffer.{@link java.nio.Buffer#remaining() remaining()}
+     * bytes starting at
+     * buffer.{@link java.nio.Buffer#position() position()}
+     * Upon return, the buffer's position will be updated to its
+     * limit; its limit will not have been changed.
+     *
+     * @param buffer the ByteBuffer to update the checksum with
+     * @since 1.8
+     */
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0)
+            return;
+        if (buffer instanceof DirectBuffer) {
+            adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem);
+        } else if (buffer.hasArray()) {
+            adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[rem];
+            buffer.get(b);
+            adler = updateBytes(adler, b, 0, b.length);
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets the checksum to initial value.
+     */
+    public void reset() {
+        adler = 1;
+    }
+
+    /**
+     * Returns the checksum value.
+     */
+    public long getValue() {
+        return (long)adler & 0xffffffffL;
+    }
+
+    private native static int update(int adler, int b);
+    private native static int updateBytes(int adler, byte[] b, int off,
+                                          int len);
+    private native static int updateByteBuffer(int adler, long addr,
+                                               int off, int len);
+}
diff --git a/java/util/zip/CRC32.java b/java/util/zip/CRC32.java
new file mode 100644
index 0000000..0f55579
--- /dev/null
+++ b/java/util/zip/CRC32.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import sun.nio.ch.DirectBuffer;
+
+/**
+ * A class that can be used to compute the CRC-32 of a data stream.
+ *
+ * <p> Passing a {@code null} argument to a method in this class will cause
+ * a {@link NullPointerException} to be thrown.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class CRC32 implements Checksum {
+    private int crc;
+
+    /**
+     * Creates a new CRC32 object.
+     */
+    public CRC32() {
+    }
+
+
+    /**
+     * Updates the CRC-32 checksum with the specified byte (the low
+     * eight bits of the argument b).
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b) {
+        crc = update(crc, b);
+    }
+
+    /**
+     * Updates the CRC-32 checksum with the specified array of bytes.
+     *
+     * @throws  ArrayIndexOutOfBoundsException
+     *          if {@code off} is negative, or {@code len} is negative,
+     *          or {@code off+len} is greater than the length of the
+     *          array {@code b}
+     */
+    public void update(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        crc = updateBytes(crc, b, off, len);
+    }
+
+    /**
+     * Updates the CRC-32 checksum with the specified array of bytes.
+     *
+     * @param b the array of bytes to update the checksum with
+     */
+    public void update(byte[] b) {
+        crc = updateBytes(crc, b, 0, b.length);
+    }
+
+    /**
+     * Updates the checksum with the bytes from the specified buffer.
+     *
+     * The checksum is updated using
+     * buffer.{@link java.nio.Buffer#remaining() remaining()}
+     * bytes starting at
+     * buffer.{@link java.nio.Buffer#position() position()}
+     * Upon return, the buffer's position will
+     * be updated to its limit; its limit will not have been changed.
+     *
+     * @param buffer the ByteBuffer to update the checksum with
+     * @since 1.8
+     */
+    public void update(ByteBuffer buffer) {
+        int pos = buffer.position();
+        int limit = buffer.limit();
+        assert (pos <= limit);
+        int rem = limit - pos;
+        if (rem <= 0)
+            return;
+        if (buffer instanceof DirectBuffer) {
+            crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem);
+        } else if (buffer.hasArray()) {
+            crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), rem);
+        } else {
+            byte[] b = new byte[rem];
+            buffer.get(b);
+            crc = updateBytes(crc, b, 0, b.length);
+        }
+        buffer.position(limit);
+    }
+
+    /**
+     * Resets CRC-32 to initial value.
+     */
+    public void reset() {
+        crc = 0;
+    }
+
+    /**
+     * Returns CRC-32 value.
+     */
+    public long getValue() {
+        return (long)crc & 0xffffffffL;
+    }
+
+    private native static int update(int crc, int b);
+    private native static int updateBytes(int crc, byte[] b, int off, int len);
+
+    private native static int updateByteBuffer(int adler, long addr,
+                                               int off, int len);
+}
diff --git a/java/util/zip/CheckedInputStream.java b/java/util/zip/CheckedInputStream.java
new file mode 100644
index 0000000..e1e5249
--- /dev/null
+++ b/java/util/zip/CheckedInputStream.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * An input stream that also maintains a checksum of the data being read.
+ * The checksum can then be used to verify the integrity of the input data.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class CheckedInputStream extends FilterInputStream {
+    private Checksum cksum;
+
+    /**
+     * Creates an input stream using the specified Checksum.
+     * @param in the input stream
+     * @param cksum the Checksum
+     */
+    public CheckedInputStream(InputStream in, Checksum cksum) {
+        super(in);
+        this.cksum = cksum;
+    }
+
+    /**
+     * Reads a byte. Will block if no input is available.
+     * @return the byte read, or -1 if the end of the stream is reached.
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read() throws IOException {
+        int b = in.read();
+        if (b != -1) {
+            cksum.update(b);
+        }
+        return b;
+    }
+
+    /**
+     * Reads into an array of bytes. If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * @param buf the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return    the actual number of bytes read, or -1 if the end
+     *            of the stream is reached.
+     * @exception  NullPointerException If <code>buf</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>buf.length - off</code>
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        len = in.read(buf, off, len);
+        if (len != -1) {
+            cksum.update(buf, off, len);
+        }
+        return len;
+    }
+
+    /**
+     * Skips specified number of bytes of input.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped
+     * @exception IOException if an I/O error has occurred
+     */
+    public long skip(long n) throws IOException {
+        byte[] buf = new byte[512];
+        long total = 0;
+        while (total < n) {
+            long len = n - total;
+            len = read(buf, 0, len < buf.length ? (int)len : buf.length);
+            if (len == -1) {
+                return total;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Returns the Checksum for this input stream.
+     * @return the Checksum value
+     */
+    public Checksum getChecksum() {
+        return cksum;
+    }
+}
diff --git a/java/util/zip/CheckedOutputStream.java b/java/util/zip/CheckedOutputStream.java
new file mode 100644
index 0000000..698b941
--- /dev/null
+++ b/java/util/zip/CheckedOutputStream.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * An output stream that also maintains a checksum of the data being
+ * written. The checksum can then be used to verify the integrity of
+ * the output data.
+ *
+ * @see         Checksum
+ * @author      David Connelly
+ */
+public
+class CheckedOutputStream extends FilterOutputStream {
+    private Checksum cksum;
+
+    /**
+     * Creates an output stream with the specified Checksum.
+     * @param out the output stream
+     * @param cksum the checksum
+     */
+    public CheckedOutputStream(OutputStream out, Checksum cksum) {
+        super(out);
+        this.cksum = cksum;
+    }
+
+    /**
+     * Writes a byte. Will block until the byte is actually written.
+     * @param b the byte to be written
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(int b) throws IOException {
+        out.write(b);
+        cksum.update(b);
+    }
+
+    /**
+     * Writes an array of bytes. Will block until the bytes are
+     * actually written.
+     * @param b the data to be written
+     * @param off the start offset of the data
+     * @param len the number of bytes to be written
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        out.write(b, off, len);
+        cksum.update(b, off, len);
+    }
+
+    /**
+     * Returns the Checksum for this output stream.
+     * @return the Checksum
+     */
+    public Checksum getChecksum() {
+        return cksum;
+    }
+}
diff --git a/java/util/zip/Checksum.java b/java/util/zip/Checksum.java
new file mode 100644
index 0000000..0369c53
--- /dev/null
+++ b/java/util/zip/Checksum.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * An interface representing a data checksum.
+ *
+ * @author      David Connelly
+ */
+public
+interface Checksum {
+    /**
+     * Updates the current checksum with the specified byte.
+     *
+     * @param b the byte to update the checksum with
+     */
+    public void update(int b);
+
+    /**
+     * Updates the current checksum with the specified array of bytes.
+     * @param b the byte array to update the checksum with
+     * @param off the start offset of the data
+     * @param len the number of bytes to use for the update
+     */
+    public void update(byte[] b, int off, int len);
+
+    /**
+     * Returns the current checksum value.
+     * @return the current checksum value
+     */
+    public long getValue();
+
+    /**
+     * Resets the checksum to its initial value.
+     */
+    public void reset();
+}
diff --git a/java/util/zip/DataFormatException.java b/java/util/zip/DataFormatException.java
new file mode 100644
index 0000000..77adbe9
--- /dev/null
+++ b/java/util/zip/DataFormatException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * Signals that a data format error has occurred.
+ *
+ * @author      David Connelly
+ */
+public
+class DataFormatException extends Exception {
+    private static final long serialVersionUID = 2219632870893641452L;
+
+    /**
+     * Constructs a DataFormatException with no detail message.
+     */
+    public DataFormatException() {
+        super();
+    }
+
+    /**
+     * Constructs a DataFormatException with the specified detail message.
+     * A detail message is a String that describes this particular exception.
+     * @param s the String containing a detail message
+     */
+    public DataFormatException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/zip/Deflater.java b/java/util/zip/Deflater.java
new file mode 100644
index 0000000..5c7dffd
--- /dev/null
+++ b/java/util/zip/Deflater.java
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.CloseGuard;
+
+/**
+ * This class provides support for general purpose compression using the
+ * popular ZLIB compression library. The ZLIB compression library was
+ * initially developed as part of the PNG graphics standard and is not
+ * protected by patents. It is fully described in the specifications at
+ * the <a href="package-summary.html#package_description">java.util.zip
+ * package description</a>.
+ *
+ * <p>The following code fragment demonstrates a trivial compression
+ * and decompression of a string using <tt>Deflater</tt> and
+ * <tt>Inflater</tt>.
+ *
+ * <blockquote><pre>
+ * try {
+ *     // Encode a String into bytes
+ *     String inputString = "blahblahblah";
+ *     byte[] input = inputString.getBytes("UTF-8");
+ *
+ *     // Compress the bytes
+ *     byte[] output = new byte[100];
+ *     Deflater compresser = new Deflater();
+ *     compresser.setInput(input);
+ *     compresser.finish();
+ *     int compressedDataLength = compresser.deflate(output);
+ *     compresser.end();
+ *
+ *     // Decompress the bytes
+ *     Inflater decompresser = new Inflater();
+ *     decompresser.setInput(output, 0, compressedDataLength);
+ *     byte[] result = new byte[100];
+ *     int resultLength = decompresser.inflate(result);
+ *     decompresser.end();
+ *
+ *     // Decode the bytes into a String
+ *     String outputString = new String(result, 0, resultLength, "UTF-8");
+ * } catch(java.io.UnsupportedEncodingException ex) {
+ *     // handle
+ * } catch (java.util.zip.DataFormatException ex) {
+ *     // handle
+ * }
+ * </pre></blockquote>
+ *
+ * @see         Inflater
+ * @author      David Connelly
+ */
+public
+class Deflater {
+
+    // Android-added: @ReachabilitySensitive
+    // Finalization clears zsRef, and thus can't be allowed to occur early.
+    // Unlike some other CloseGuard uses, the spec allows clients to rely on finalization
+    // here.  Thus dropping a deflater without calling end() should work correctly.
+    // It thus does not suffice to just rely on the CloseGuard annotation.
+    @ReachabilitySensitive
+    private final ZStreamRef zsRef;
+    private byte[] buf = new byte[0];
+    private int off, len;
+    private int level, strategy;
+    private boolean setParams;
+    private boolean finish, finished;
+    private long bytesRead;
+    private long bytesWritten;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    /**
+     * Compression method for the deflate algorithm (the only one currently
+     * supported).
+     */
+    public static final int DEFLATED = 8;
+
+    /**
+     * Compression level for no compression.
+     */
+    public static final int NO_COMPRESSION = 0;
+
+    /**
+     * Compression level for fastest compression.
+     */
+    public static final int BEST_SPEED = 1;
+
+    /**
+     * Compression level for best compression.
+     */
+    public static final int BEST_COMPRESSION = 9;
+
+    /**
+     * Default compression level.
+     */
+    public static final int DEFAULT_COMPRESSION = -1;
+
+    /**
+     * Compression strategy best used for data consisting mostly of small
+     * values with a somewhat random distribution. Forces more Huffman coding
+     * and less string matching.
+     */
+    public static final int FILTERED = 1;
+
+    /**
+     * Compression strategy for Huffman coding only.
+     */
+    public static final int HUFFMAN_ONLY = 2;
+
+    /**
+     * Default compression strategy.
+     */
+    public static final int DEFAULT_STRATEGY = 0;
+
+    /**
+     * Compression flush mode used to achieve best compression result.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int NO_FLUSH = 0;
+
+    /**
+     * Compression flush mode used to flush out all pending output; may
+     * degrade compression for some compression algorithms.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int SYNC_FLUSH = 2;
+
+    /**
+     * Compression flush mode used to flush out all pending output and
+     * reset the deflater. Using this mode too often can seriously degrade
+     * compression.
+     *
+     * @see Deflater#deflate(byte[], int, int, int)
+     * @since 1.7
+     */
+    public static final int FULL_FLUSH = 3;
+
+    // Android-removed: initIDs handled in register method.
+    /*
+    static {
+        /* Zip library is loaded from System.initializeSystemClass *
+        initIDs();
+    }
+    */
+
+    /**
+     * Creates a new compressor using the specified compression level.
+     * If 'nowrap' is true then the ZLIB header and checksum fields will
+     * not be used in order to support the compression format used in
+     * both GZIP and PKZIP.
+     * @param level the compression level (0-9)
+     * @param nowrap if true then use GZIP compatible compression
+     */
+    public Deflater(int level, boolean nowrap) {
+        this.level = level;
+        this.strategy = DEFAULT_STRATEGY;
+        this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
+        // Android-added: CloseGuard support.
+        guard.open("end");
+    }
+
+    /**
+     * Creates a new compressor using the specified compression level.
+     * Compressed data will be generated in ZLIB format.
+     * @param level the compression level (0-9)
+     */
+    public Deflater(int level) {
+        this(level, false);
+    }
+
+    /**
+     * Creates a new compressor with the default compression level.
+     * Compressed data will be generated in ZLIB format.
+     */
+    public Deflater() {
+        this(DEFAULT_COMPRESSION, false);
+    }
+
+    /**
+     * Sets input data for compression. This should be called whenever
+     * needsInput() returns true indicating that more input data is required.
+     * @param b the input data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Deflater#needsInput
+     */
+    public void setInput(byte[] b, int off, int len) {
+        if (b== null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            this.buf = b;
+            this.off = off;
+            this.len = len;
+        }
+    }
+
+    /**
+     * Sets input data for compression. This should be called whenever
+     * needsInput() returns true indicating that more input data is required.
+     * @param b the input data bytes
+     * @see Deflater#needsInput
+     */
+    public void setInput(byte[] b) {
+        setInput(b, 0, b.length);
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * @param b the dictionary data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            setDictionary(zsRef.address(), b, off, len);
+        }
+    }
+
+    /**
+     * Sets preset dictionary for compression. A preset dictionary is used
+     * when the history buffer can be predetermined. When the data is later
+     * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
+     * in order to get the Adler-32 value of the dictionary required for
+     * decompression.
+     * @param b the dictionary data bytes
+     * @see Inflater#inflate
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b) {
+        setDictionary(b, 0, b.length);
+    }
+
+    /**
+     * Sets the compression strategy to the specified value.
+     *
+     * <p> If the compression strategy is changed, the next invocation
+     * of {@code deflate} will compress the input available so far with
+     * the old strategy (and may be flushed); the new strategy will take
+     * effect only after that invocation.
+     *
+     * @param strategy the new compression strategy
+     * @exception IllegalArgumentException if the compression strategy is
+     *                                     invalid
+     */
+    public void setStrategy(int strategy) {
+        switch (strategy) {
+          case DEFAULT_STRATEGY:
+          case FILTERED:
+          case HUFFMAN_ONLY:
+            break;
+          default:
+            throw new IllegalArgumentException();
+        }
+        synchronized (zsRef) {
+            if (this.strategy != strategy) {
+                this.strategy = strategy;
+                setParams = true;
+            }
+        }
+    }
+
+    /**
+     * Sets the compression level to the specified value.
+     *
+     * <p> If the compression level is changed, the next invocation
+     * of {@code deflate} will compress the input available so far
+     * with the old level (and may be flushed); the new level will
+     * take effect only after that invocation.
+     *
+     * @param level the new compression level (0-9)
+     * @exception IllegalArgumentException if the compression level is invalid
+     */
+    public void setLevel(int level) {
+        if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) {
+            throw new IllegalArgumentException("invalid compression level");
+        }
+        synchronized (zsRef) {
+            if (this.level != level) {
+                this.level = level;
+                setParams = true;
+            }
+        }
+    }
+
+    /**
+     * Returns true if the input data buffer is empty and setInput()
+     * should be called in order to provide more input.
+     * @return true if the input data buffer is empty and setInput()
+     * should be called in order to provide more input
+     */
+    public boolean needsInput() {
+        synchronized (zsRef) {
+            return len <= 0;
+        }
+    }
+
+    /**
+     * When called, indicates that compression should end with the current
+     * contents of the input buffer.
+     */
+    public void finish() {
+        synchronized (zsRef) {
+            finish = true;
+        }
+    }
+
+    /**
+     * Returns true if the end of the compressed data output stream has
+     * been reached.
+     * @return true if the end of the compressed data output stream has
+     * been reached
+     */
+    public boolean finished() {
+        synchronized (zsRef) {
+            return finished;
+        }
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(b, off, len)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
+     *
+     * @param b the buffer for the compressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes of compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     */
+    public int deflate(byte[] b, int off, int len) {
+        return deflate(b, off, len, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills specified buffer with compressed
+     * data. Returns actual number of bytes of compressed data. A return value
+     * of 0 indicates that {@link #needsInput() needsInput} should be called
+     * in order to determine if more input data is required.
+     *
+     * <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
+     * An invocation of this method of the form {@code deflater.deflate(b)}
+     * yields the same result as the invocation of
+     * {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
+     *
+     * @param b the buffer for the compressed data
+     * @return the actual number of bytes of compressed data written to the
+     *         output buffer
+     */
+    public int deflate(byte[] b) {
+        return deflate(b, 0, b.length, NO_FLUSH);
+    }
+
+    /**
+     * Compresses the input data and fills the specified buffer with compressed
+     * data. Returns actual number of bytes of data compressed.
+     *
+     * <p>Compression flush mode is one of the following three modes:
+     *
+     * <ul>
+     * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
+     * to accumulate, before producing output, in order to achieve the best
+     * compression (should be used in normal use scenario). A return value
+     * of 0 in this flush mode indicates that {@link #needsInput()} should
+     * be called in order to determine if more input data is required.
+     *
+     * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
+     * to the specified output buffer, so that an inflater that works on
+     * compressed data can get all input data available so far (In particular
+     * the {@link #needsInput()} returns {@code true} after this invocation
+     * if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
+     * may degrade compression for some compression algorithms and so it
+     * should be used only when necessary.
+     *
+     * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
+     * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
+     * that works on the compressed output data can restart from this point
+     * if previous compressed data has been damaged or if random access is
+     * desired. Using {@link #FULL_FLUSH} too often can seriously degrade
+     * compression.
+     * </ul>
+     *
+     * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
+     * the return value is {@code len}, the space available in output
+     * buffer {@code b}, this method should be invoked again with the same
+     * {@code flush} parameter and more output space.
+     *
+     * @param b the buffer for the compressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of bytes of compressed data
+     * @param flush the compression flush mode
+     * @return the actual number of bytes of compressed data written to
+     *         the output buffer
+     *
+     * @throws IllegalArgumentException if the flush mode is invalid
+     * @since 1.7
+     */
+    public int deflate(byte[] b, int off, int len, int flush) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
+                flush == FULL_FLUSH) {
+                int thisLen = this.len;
+                int n = deflateBytes(zsRef.address(), b, off, len, flush);
+                bytesWritten += n;
+                bytesRead += (thisLen - this.len);
+                return n;
+            }
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Returns the ADLER-32 value of the uncompressed data.
+     * @return the ADLER-32 value of the uncompressed data
+     */
+    public int getAdler() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return getAdler(zsRef.address());
+        }
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes input so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of uncompressed bytes input so far
+     */
+    public int getTotalIn() {
+        return (int) getBytesRead();
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes input so far.
+     *
+     * @return the total (non-negative) number of uncompressed bytes input so far
+     * @since 1.5
+     */
+    public long getBytesRead() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesRead;
+        }
+    }
+
+    /**
+     * Returns the total number of compressed bytes output so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of compressed bytes output so far
+     */
+    public int getTotalOut() {
+        return (int) getBytesWritten();
+    }
+
+    /**
+     * Returns the total number of compressed bytes output so far.
+     *
+     * @return the total (non-negative) number of compressed bytes output so far
+     * @since 1.5
+     */
+    public long getBytesWritten() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesWritten;
+        }
+    }
+
+    /**
+     * Resets deflater so that a new set of input data can be processed.
+     * Keeps current compression level and strategy settings.
+     */
+    public void reset() {
+        synchronized (zsRef) {
+            ensureOpen();
+            reset(zsRef.address());
+            finish = false;
+            finished = false;
+            off = len = 0;
+            bytesRead = bytesWritten = 0;
+        }
+    }
+
+    /**
+     * Closes the compressor and discards any unprocessed input.
+     * This method should be called when the compressor is no longer
+     * being used, but will also be called automatically by the
+     * finalize() method. Once this method is called, the behavior
+     * of the Deflater object is undefined.
+     */
+    public void end() {
+        synchronized (zsRef) {
+            // Android-added: CloseGuard support.
+            guard.close();
+            long addr = zsRef.address();
+            zsRef.clear();
+            if (addr != 0) {
+                end(addr);
+                buf = null;
+            }
+        }
+    }
+
+    /**
+     * Closes the compressor when garbage is collected.
+     */
+    protected void finalize() {
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+        end();
+    }
+
+    private void ensureOpen() {
+        assert Thread.holdsLock(zsRef);
+        if (zsRef.address() == 0)
+            throw new NullPointerException("Deflater has been closed");
+    }
+
+    // Android-changed: initIDs handled in register method.
+    // private native static void initIDs();
+    private native static long init(int level, int strategy, boolean nowrap);
+    private native static void setDictionary(long addr, byte[] b, int off, int len);
+    private native int deflateBytes(long addr, byte[] b, int off, int len,
+                                    int flush);
+    private native static int getAdler(long addr);
+    private native static void reset(long addr);
+    private native static void end(long addr);
+}
diff --git a/java/util/zip/DeflaterInputStream.java b/java/util/zip/DeflaterInputStream.java
new file mode 100644
index 0000000..c3f7802
--- /dev/null
+++ b/java/util/zip/DeflaterInputStream.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Implements an input stream filter for compressing data in the "deflate"
+ * compression format.
+ *
+ * @since       1.6
+ * @author      David R Tribble ([email protected])
+ *
+ * @see DeflaterOutputStream
+ * @see InflaterOutputStream
+ * @see InflaterInputStream
+ */
+
+public class DeflaterInputStream extends FilterInputStream {
+    /** Compressor for this stream. */
+    protected final Deflater def;
+
+    /** Input buffer for reading compressed data. */
+    protected final byte[] buf;
+
+    /** Temporary read buffer. */
+    private byte[] rbuf = new byte[1];
+
+    /** Default compressor is used. */
+    private boolean usesDefaultDeflater = false;
+
+    /** End of the underlying input stream has been reached. */
+    private boolean reachEOF = false;
+
+    /**
+     * Check to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (in == null) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new input stream with a default compressor and buffer
+     * size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @throws NullPointerException if {@code in} is null
+     */
+    public DeflaterInputStream(InputStream in) {
+        this(in, new Deflater());
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Creates a new input stream with the specified compressor and a
+     * default buffer size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @param defl compressor ("deflater") for this stream
+     * @throws NullPointerException if {@code in} or {@code defl} is null
+     */
+    public DeflaterInputStream(InputStream in, Deflater defl) {
+        this(in, defl, 512);
+    }
+
+    /**
+     * Creates a new input stream with the specified compressor and buffer
+     * size.
+     *
+     * @param in input stream to read the uncompressed data to
+     * @param defl compressor ("deflater") for this stream
+     * @param bufLen compression buffer size
+     * @throws IllegalArgumentException if {@code bufLen <= 0}
+     * @throws NullPointerException if {@code in} or {@code defl} is null
+     */
+    public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) {
+        super(in);
+
+        // Sanity checks
+        if (in == null)
+            throw new NullPointerException("Null input");
+        if (defl == null)
+            throw new NullPointerException("Null deflater");
+        if (bufLen < 1)
+            throw new IllegalArgumentException("Buffer size < 1");
+
+        // Initialize
+        def = defl;
+        buf = new byte[bufLen];
+    }
+
+    /**
+     * Closes this input stream and its underlying input stream, discarding
+     * any pending uncompressed data.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (in != null) {
+            try {
+                // Clean up
+                if (usesDefaultDeflater) {
+                    def.end();
+                }
+
+                in.close();
+            } finally {
+                in = null;
+            }
+        }
+    }
+
+    /**
+     * Reads a single byte of compressed data from the input stream.
+     * This method will block until some input can be read and compressed.
+     *
+     * @return a single byte of compressed data, or -1 if the end of the
+     * uncompressed input stream is reached
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public int read() throws IOException {
+        // Read a single byte of compressed data
+        int len = read(rbuf, 0, 1);
+        if (len <= 0)
+            return -1;
+        return (rbuf[0] & 0xFF);
+    }
+
+    /**
+     * Reads compressed data into a byte array.
+     * This method will block until some input can be read and compressed.
+     *
+     * @param b buffer into which the data is read
+     * @param off starting offset of the data within {@code b}
+     * @param len maximum number of compressed bytes to read into {@code b}
+     * @return the actual number of bytes read, or -1 if the end of the
+     * uncompressed input stream is reached
+     * @throws IndexOutOfBoundsException  if {@code len > b.length - off}
+     * @throws IOException if an I/O error occurs or if this input stream is
+     * already closed
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        // Sanity checks
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException("Null buffer for read");
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        // Read and compress (deflate) input data bytes
+        int cnt = 0;
+        while (len > 0 && !def.finished()) {
+            int n;
+
+            // Read data from the input stream
+            if (def.needsInput()) {
+                n = in.read(buf, 0, buf.length);
+                if (n < 0) {
+                    // End of the input stream reached
+                    def.finish();
+                } else if (n > 0) {
+                    def.setInput(buf, 0, n);
+                }
+            }
+
+            // Compress the input data, filling the read buffer
+            n = def.deflate(b, off, len);
+            cnt += n;
+            off += n;
+            len -= n;
+        }
+        // BEGIN Android-changed: Return more accurate value from available().
+        // Set reachEOF eagerly when the Deflater has finished, and not just when the number of
+        // bytes is zero so that available is more accurate.
+        // See http://b/111589691
+        /*
+        if (cnt == 0 && def.finished()) {
+            reachEOF = true;
+            cnt = -1;
+        }
+        */
+        if (def.finished()) {
+            reachEOF = true;
+            if (cnt == 0) {
+                cnt = -1;
+            }
+        }
+        // END Android-changed: Return more accurate value from available().
+
+        return cnt;
+    }
+
+    /**
+     * Skips over and discards data from the input stream.
+     * This method may block until the specified number of bytes are read and
+     * skipped. <em>Note:</em> While {@code n} is given as a {@code long},
+     * the maximum number of bytes which can be skipped is
+     * {@code Integer.MAX_VALUE}.
+     *
+     * @param n number of bytes to be skipped
+     * @return the actual number of bytes skipped
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+
+        // Skip bytes by repeatedly decompressing small blocks
+        if (rbuf.length < 512)
+            rbuf = new byte[512];
+
+        int total = (int)Math.min(n, Integer.MAX_VALUE);
+        long cnt = 0;
+        while (total > 0) {
+            // Read a small block of uncompressed bytes
+            int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length));
+
+            if (len < 0) {
+                break;
+            }
+            cnt += len;
+            total -= len;
+        }
+        return cnt;
+    }
+
+    /**
+     * Returns 0 after EOF has been reached, otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking
+     * @return zero after the end of the underlying input stream has been
+     * reached, otherwise always returns 1
+     * @throws IOException if an I/O error occurs or if this stream is
+     * already closed
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        if (reachEOF) {
+            return 0;
+        }
+        return 1;
+    }
+
+    /**
+     * Always returns {@code false} because this input stream does not support
+     * the {@link #mark mark()} and {@link #reset reset()} methods.
+     *
+     * @return false, always
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * <i>This operation is not supported</i>.
+     *
+     * @param limit maximum bytes that can be read before invalidating the position marker
+     */
+    public void mark(int limit) {
+        // Operation not supported
+    }
+
+    /**
+     * <i>This operation is not supported</i>.
+     *
+     * @throws IOException always thrown
+     */
+    public void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+}
diff --git a/java/util/zip/DeflaterOutputStream.java b/java/util/zip/DeflaterOutputStream.java
new file mode 100644
index 0000000..7821737
--- /dev/null
+++ b/java/util/zip/DeflaterOutputStream.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * This class implements an output stream filter for compressing data in
+ * the "deflate" compression format. It is also used as the basis for other
+ * types of compression filters, such as GZIPOutputStream.
+ *
+ * @see         Deflater
+ * @author      David Connelly
+ */
+public
+class DeflaterOutputStream extends FilterOutputStream {
+    /**
+     * Compressor for this stream.
+     */
+    protected Deflater def;
+
+    /**
+     * Output buffer for writing compressed data.
+     */
+    protected byte[] buf;
+
+    /**
+     * Indicates that the stream has been closed.
+     */
+
+    private boolean closed = false;
+
+    private final boolean syncFlush;
+
+    /**
+     * Creates a new output stream with the specified compressor,
+     * buffer size and flush mode.
+
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @throws IllegalArgumentException if {@code size <= 0}
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out,
+                                Deflater def,
+                                int size,
+                                boolean syncFlush) {
+        super(out);
+        if (out == null || def == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.def = def;
+        this.buf = new byte[size];
+        this.syncFlush = syncFlush;
+    }
+
+
+    /**
+     * Creates a new output stream with the specified compressor and
+     * buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 4-argument constructor DeflaterOutputStream(out, def, size, false).
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param size the output buffer size
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public DeflaterOutputStream(OutputStream out, Deflater def, int size) {
+        this(out, def, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified compressor, flush
+     * mode and a default buffer size.
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out,
+                                Deflater def,
+                                boolean syncFlush) {
+        this(out, def, 512, syncFlush);
+    }
+
+
+    /**
+     * Creates a new output stream with the specified compressor and
+     * a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor DeflaterOutputStream(out, def, false).
+     *
+     * @param out the output stream
+     * @param def the compressor ("deflater")
+     */
+    public DeflaterOutputStream(OutputStream out, Deflater def) {
+        this(out, def, 512, false);
+    }
+
+    boolean usesDefaultDeflater = false;
+
+
+    /**
+     * Creates a new output stream with a default compressor, a default
+     * buffer size and the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} the {@link #flush()} method of this
+     *        instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @since 1.7
+     */
+    public DeflaterOutputStream(OutputStream out, boolean syncFlush) {
+        this(out, new Deflater(), 512, syncFlush);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Creates a new output stream with a default compressor and buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor DeflaterOutputStream(out, false).
+     *
+     * @param out the output stream
+     */
+    public DeflaterOutputStream(OutputStream out) {
+        this(out, false);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Writes a byte to the compressed output stream. This method will
+     * block until the byte can be written.
+     * @param b the byte to be written
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(int b) throws IOException {
+        byte[] buf = new byte[1];
+        buf[0] = (byte)(b & 0xff);
+        write(buf, 0, 1);
+    }
+
+    /**
+     * Writes an array of bytes to the compressed output stream. This
+     * method will block until all the bytes are written.
+     * @param b the data to be written
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @exception IOException if an I/O error has occurred
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (def.finished()) {
+            throw new IOException("write beyond end of stream");
+        }
+        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+        if (!def.finished()) {
+            def.setInput(b, off, len);
+            while (!def.needsInput()) {
+                deflate();
+            }
+        }
+    }
+
+    /**
+     * Finishes writing compressed data to the output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void finish() throws IOException {
+        if (!def.finished()) {
+            def.finish();
+            while (!def.finished()) {
+                deflate();
+            }
+        }
+    }
+
+    /**
+     * Writes remaining compressed data to the output stream and closes the
+     * underlying stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            finish();
+            if (usesDefaultDeflater)
+                def.end();
+            out.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Writes next block of compressed data to the output stream.
+     * @throws IOException if an I/O error has occurred
+     */
+    protected void deflate() throws IOException {
+        // Android-changed: Output all available compressed data (b/4005091).
+        // See http://b/111496419 for more details.
+        // int len = def.deflate(buf, 0, buf.length);
+        // if (len > 0) {
+        //     out.write(buf, 0, len);
+        // }
+        int len = 0;
+        while ((len = def.deflate(buf, 0, buf.length)) > 0) {
+          out.write(buf, 0, len);
+        }
+    }
+
+    /**
+     * Flushes the compressed output stream.
+     *
+     * If {@link #DeflaterOutputStream(OutputStream, Deflater, int, boolean)
+     * syncFlush} is {@code true} when this compressed output stream is
+     * constructed, this method first flushes the underlying {@code compressor}
+     * with the flush mode {@link Deflater#SYNC_FLUSH} to force
+     * all pending data to be flushed out to the output stream and then
+     * flushes the output stream. Otherwise this method only flushes the
+     * output stream without flushing the {@code compressor}.
+     *
+     * @throws IOException if an I/O error has occurred
+     *
+     * @since 1.7
+     */
+    public void flush() throws IOException {
+        if (syncFlush && !def.finished()) {
+            int len = 0;
+            while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0)
+            {
+                out.write(buf, 0, len);
+                if (len < buf.length)
+                    break;
+            }
+        }
+        out.flush();
+    }
+}
diff --git a/java/util/zip/GZIPInputStream.java b/java/util/zip/GZIPInputStream.java
new file mode 100644
index 0000000..109454c
--- /dev/null
+++ b/java/util/zip/GZIPInputStream.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.SequenceInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+/**
+ * This class implements a stream filter for reading compressed data in
+ * the GZIP file format.
+ *
+ * @see         InflaterInputStream
+ * @author      David Connelly
+ *
+ */
+public
+class GZIPInputStream extends InflaterInputStream {
+    /**
+     * CRC-32 for uncompressed data.
+     */
+    protected CRC32 crc = new CRC32();
+
+    /**
+     * Indicates end of input stream.
+     */
+    protected boolean eos;
+
+    private boolean closed = false;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new input stream with the specified buffer size.
+     * @param in the input stream
+     * @param size the input buffer size
+     *
+     * @exception ZipException if a GZIP format error has occurred or the
+     *                         compression method used is unsupported
+     * @exception IOException if an I/O error has occurred
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public GZIPInputStream(InputStream in, int size) throws IOException {
+        super(in, new Inflater(true), size);
+        // Android-removed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+        // BEGIN Android-changed: Do not rely on finalization to inf.end().
+        // readHeader(in);
+        try {
+            readHeader(in);
+        } catch (Exception e) {
+            inf.end();
+            throw e;
+        }
+        // END Android-changed: Do not rely on finalization to inf.end().
+    }
+
+    /**
+     * Creates a new input stream with a default buffer size.
+     * @param in the input stream
+     *
+     * @exception ZipException if a GZIP format error has occurred or the
+     *                         compression method used is unsupported
+     * @exception IOException if an I/O error has occurred
+     */
+    public GZIPInputStream(InputStream in) throws IOException {
+        this(in, 512);
+    }
+
+    /**
+     * Reads uncompressed data into an array of bytes. If <code>len</code> is not
+     * zero, the method will block until some input can be decompressed; otherwise,
+     * no bytes are read and <code>0</code> is returned.
+     * @param buf the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return  the actual number of bytes read, or -1 if the end of the
+     *          compressed input stream is reached
+     *
+     * @exception  NullPointerException If <code>buf</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>buf.length - off</code>
+     * @exception ZipException if the compressed input data is corrupt.
+     * @exception IOException if an I/O error has occurred.
+     *
+     */
+    public int read(byte[] buf, int off, int len) throws IOException {
+        ensureOpen();
+        if (eos) {
+            return -1;
+        }
+        int n = super.read(buf, off, len);
+        if (n == -1) {
+            if (readTrailer())
+                eos = true;
+            else
+                return this.read(buf, off, len);
+        } else {
+            crc.update(buf, off, n);
+        }
+        return n;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            eos = true;
+            closed = true;
+        }
+    }
+
+    /**
+     * GZIP header magic number.
+     */
+    public final static int GZIP_MAGIC = 0x8b1f;
+
+    /*
+     * File header flags.
+     */
+    private final static int FTEXT      = 1;    // Extra text
+    private final static int FHCRC      = 2;    // Header CRC
+    private final static int FEXTRA     = 4;    // Extra field
+    private final static int FNAME      = 8;    // File name
+    private final static int FCOMMENT   = 16;   // File comment
+
+    /*
+     * Reads GZIP member header and returns the total byte number
+     * of this member header.
+     */
+    private int readHeader(InputStream this_in) throws IOException {
+        CheckedInputStream in = new CheckedInputStream(this_in, crc);
+        crc.reset();
+        // Check header magic
+        if (readUShort(in) != GZIP_MAGIC) {
+            throw new ZipException("Not in GZIP format");
+        }
+        // Check compression method
+        if (readUByte(in) != 8) {
+            throw new ZipException("Unsupported compression method");
+        }
+        // Read flags
+        int flg = readUByte(in);
+        // Skip MTIME, XFL, and OS fields
+        skipBytes(in, 6);
+        int n = 2 + 2 + 6;
+        // Skip optional extra field
+        if ((flg & FEXTRA) == FEXTRA) {
+            int m = readUShort(in);
+            skipBytes(in, m);
+            n += m + 2;
+        }
+        // Skip optional file name
+        if ((flg & FNAME) == FNAME) {
+            do {
+                n++;
+            } while (readUByte(in) != 0);
+        }
+        // Skip optional file comment
+        if ((flg & FCOMMENT) == FCOMMENT) {
+            do {
+                n++;
+            } while (readUByte(in) != 0);
+        }
+        // Check optional header CRC
+        if ((flg & FHCRC) == FHCRC) {
+            int v = (int)crc.getValue() & 0xffff;
+            if (readUShort(in) != v) {
+                throw new ZipException("Corrupt GZIP header");
+            }
+            n += 2;
+        }
+        crc.reset();
+        return n;
+    }
+
+    /*
+     * Reads GZIP member trailer and returns true if the eos
+     * reached, false if there are more (concatenated gzip
+     * data set)
+     */
+    private boolean readTrailer() throws IOException {
+        InputStream in = this.in;
+        int n = inf.getRemaining();
+        if (n > 0) {
+            in = new SequenceInputStream(
+                        new ByteArrayInputStream(buf, len - n, n),
+                        new FilterInputStream(in) {
+                            public void close() throws IOException {}
+                        });
+        }
+        // Uses left-to-right evaluation order
+        if ((readUInt(in) != crc.getValue()) ||
+            // rfc1952; ISIZE is the input size modulo 2^32
+            (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL)))
+            throw new ZipException("Corrupt GZIP trailer");
+
+        // If there are more bytes available in "in" or
+        // the leftover in the "inf" is > 26 bytes:
+        // this.trailer(8) + next.header.min(10) + next.trailer(8)
+        // try concatenated case
+        if (this.in.available() > 0 || n > 26) {
+            int m = 8;                  // this.trailer
+            try {
+                m += readHeader(in);    // next.header
+            } catch (IOException ze) {
+                return true;  // ignore any malformed, do nothing
+            }
+            inf.reset();
+            if (n > m)
+                inf.setInput(buf, len - n + m, n - m);
+            return false;
+        }
+        return true;
+    }
+
+    /*
+     * Reads unsigned integer in Intel byte order.
+     */
+    private long readUInt(InputStream in) throws IOException {
+        long s = readUShort(in);
+        return ((long)readUShort(in) << 16) | s;
+    }
+
+    /*
+     * Reads unsigned short in Intel byte order.
+     */
+    private int readUShort(InputStream in) throws IOException {
+        int b = readUByte(in);
+        return (readUByte(in) << 8) | b;
+    }
+
+    /*
+     * Reads unsigned byte.
+     */
+    private int readUByte(InputStream in) throws IOException {
+        int b = in.read();
+        if (b == -1) {
+            throw new EOFException();
+        }
+        if (b < -1 || b > 255) {
+            // Report on this.in, not argument in; see read{Header, Trailer}.
+            throw new IOException(this.in.getClass().getName()
+                + ".read() returned value out of range -1..255: " + b);
+        }
+        return b;
+    }
+
+    private byte[] tmpbuf = new byte[128];
+
+    /*
+     * Skips bytes of input data blocking until all bytes are skipped.
+     * Does not assume that the input stream is capable of seeking.
+     */
+    private void skipBytes(InputStream in, int n) throws IOException {
+        while (n > 0) {
+            int len = in.read(tmpbuf, 0, n < tmpbuf.length ? n : tmpbuf.length);
+            if (len == -1) {
+                throw new EOFException();
+            }
+            n -= len;
+        }
+    }
+}
diff --git a/java/util/zip/GZIPOutputStream.java b/java/util/zip/GZIPOutputStream.java
new file mode 100644
index 0000000..2c1cd40
--- /dev/null
+++ b/java/util/zip/GZIPOutputStream.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+
+/**
+ * This class implements a stream filter for writing compressed data in
+ * the GZIP file format.
+ * @author      David Connelly
+ *
+ */
+public
+class GZIPOutputStream extends DeflaterOutputStream {
+    /**
+     * CRC-32 of uncompressed data.
+     */
+    protected CRC32 crc = new CRC32();
+
+    /*
+     * GZIP header magic number.
+     */
+    private final static int GZIP_MAGIC = 0x8b1f;
+
+    /*
+     * Trailer size in bytes.
+     *
+     */
+    private final static int TRAILER_SIZE = 8;
+
+    /**
+     * Creates a new output stream with the specified buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 3-argument constructor GZIPOutputStream(out, size, false).
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @exception IOException If an I/O error has occurred.
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public GZIPOutputStream(OutputStream out, int size) throws IOException {
+        this(out, size, false);
+    }
+
+    /**
+     * Creates a new output stream with the specified buffer size and
+     * flush mode.
+     *
+     * @param out the output stream
+     * @param size the output buffer size
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     * @exception IOException If an I/O error has occurred.
+     * @exception IllegalArgumentException if {@code size <= 0}
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, int size, boolean syncFlush)
+        throws IOException
+    {
+        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true),
+              size,
+              syncFlush);
+        usesDefaultDeflater = true;
+        writeHeader();
+        crc.reset();
+    }
+
+
+    /**
+     * Creates a new output stream with a default buffer size.
+     *
+     * <p>The new output stream instance is created as if by invoking
+     * the 2-argument constructor GZIPOutputStream(out, false).
+     *
+     * @param out the output stream
+     * @exception IOException If an I/O error has occurred.
+     */
+    public GZIPOutputStream(OutputStream out) throws IOException {
+        this(out, 512, false);
+    }
+
+    /**
+     * Creates a new output stream with a default buffer size and
+     * the specified flush mode.
+     *
+     * @param out the output stream
+     * @param syncFlush
+     *        if {@code true} invocation of the inherited
+     *        {@link DeflaterOutputStream#flush() flush()} method of
+     *        this instance flushes the compressor with flush mode
+     *        {@link Deflater#SYNC_FLUSH} before flushing the output
+     *        stream, otherwise only flushes the output stream
+     *
+     * @exception IOException If an I/O error has occurred.
+     *
+     * @since 1.7
+     */
+    public GZIPOutputStream(OutputStream out, boolean syncFlush)
+        throws IOException
+    {
+        this(out, 512, syncFlush);
+    }
+
+    /**
+     * Writes array of bytes to the compressed output stream. This method
+     * will block until all the bytes are written.
+     * @param buf the data to be written
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @exception IOException If an I/O error has occurred.
+     */
+    public synchronized void write(byte[] buf, int off, int len)
+        throws IOException
+    {
+        super.write(buf, off, len);
+        crc.update(buf, off, len);
+    }
+
+    /**
+     * Finishes writing compressed data to the output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void finish() throws IOException {
+        if (!def.finished()) {
+            def.finish();
+            while (!def.finished()) {
+                int len = def.deflate(buf, 0, buf.length);
+                if (def.finished() && len <= buf.length - TRAILER_SIZE) {
+                    // last deflater buffer. Fit trailer at the end
+                    writeTrailer(buf, len);
+                    len = len + TRAILER_SIZE;
+                    out.write(buf, 0, len);
+                    return;
+                }
+                if (len > 0)
+                    out.write(buf, 0, len);
+            }
+            // if we can't fit the trailer at the end of the last
+            // deflater buffer, we write it separately
+            byte[] trailer = new byte[TRAILER_SIZE];
+            writeTrailer(trailer, 0);
+            out.write(trailer);
+        }
+    }
+
+    /*
+     * Writes GZIP member header.
+     */
+    private void writeHeader() throws IOException {
+        out.write(new byte[] {
+                      (byte) GZIP_MAGIC,        // Magic number (short)
+                      (byte)(GZIP_MAGIC >> 8),  // Magic number (short)
+                      Deflater.DEFLATED,        // Compression method (CM)
+                      0,                        // Flags (FLG)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Modification time MTIME (int)
+                      0,                        // Extra flags (XFLG)
+                      0                         // Operating system (OS)
+                  });
+    }
+
+    /*
+     * Writes GZIP member trailer to a byte array, starting at a given
+     * offset.
+     */
+    private void writeTrailer(byte[] buf, int offset) throws IOException {
+        writeInt((int)crc.getValue(), buf, offset); // CRC-32 of uncompr. data
+        writeInt(def.getTotalIn(), buf, offset + 4); // Number of uncompr. bytes
+    }
+
+    /*
+     * Writes integer in Intel byte order to a byte array, starting at a
+     * given offset.
+     */
+    private void writeInt(int i, byte[] buf, int offset) throws IOException {
+        writeShort(i & 0xffff, buf, offset);
+        writeShort((i >> 16) & 0xffff, buf, offset + 2);
+    }
+
+    /*
+     * Writes short integer in Intel byte order to a byte array, starting
+     * at a given offset
+     */
+    private void writeShort(int s, byte[] buf, int offset) throws IOException {
+        buf[offset] = (byte)(s & 0xff);
+        buf[offset + 1] = (byte)((s >> 8) & 0xff);
+    }
+}
diff --git a/java/util/zip/Inflater.java b/java/util/zip/Inflater.java
new file mode 100644
index 0000000..eb8754e
--- /dev/null
+++ b/java/util/zip/Inflater.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import dalvik.annotation.optimization.ReachabilitySensitive;
+import dalvik.system.CloseGuard;
+
+/**
+ * This class provides support for general purpose decompression using the
+ * popular ZLIB compression library. The ZLIB compression library was
+ * initially developed as part of the PNG graphics standard and is not
+ * protected by patents. It is fully described in the specifications at
+ * the <a href="package-summary.html#package_description">java.util.zip
+ * package description</a>.
+ *
+ * <p>The following code fragment demonstrates a trivial compression
+ * and decompression of a string using <tt>Deflater</tt> and
+ * <tt>Inflater</tt>.
+ *
+ * <blockquote><pre>
+ * try {
+ *     // Encode a String into bytes
+ *     String inputString = "blahblahblah\u20AC\u20AC";
+ *     byte[] input = inputString.getBytes("UTF-8");
+ *
+ *     // Compress the bytes
+ *     byte[] output = new byte[100];
+ *     Deflater compresser = new Deflater();
+ *     compresser.setInput(input);
+ *     compresser.finish();
+ *     int compressedDataLength = compresser.deflate(output);
+ *
+ *     // Decompress the bytes
+ *     Inflater decompresser = new Inflater();
+ *     decompresser.setInput(output, 0, compressedDataLength);
+ *     byte[] result = new byte[100];
+ *     int resultLength = decompresser.inflate(result);
+ *     decompresser.end();
+ *
+ *     // Decode the bytes into a String
+ *     String outputString = new String(result, 0, resultLength, "UTF-8");
+ * } catch(java.io.UnsupportedEncodingException ex) {
+ *     // handle
+ * } catch (java.util.zip.DataFormatException ex) {
+ *     // handle
+ * }
+ * </pre></blockquote>
+ *
+ * @see         Deflater
+ * @author      David Connelly
+ *
+ */
+public
+class Inflater {
+
+    // Android-added: @ReachabilitySensitive
+    // Finalization clears zsRef, and thus can't be allowed to occur early.
+    // Unlike some other CloseGuard uses, the spec allows clients to rely on finalization
+    // here.  Thus dropping a deflater without calling end() should work correctly.
+    // It thus does not suffice to just rely on the CloseGuard annotation.
+    @ReachabilitySensitive
+    private final ZStreamRef zsRef;
+    private byte[] buf = defaultBuf;
+    private int off, len;
+    private boolean finished;
+    private boolean needDict;
+    private long bytesRead;
+    private long bytesWritten;
+
+    // Android-added: CloseGuard support.
+    @ReachabilitySensitive
+    private final CloseGuard guard = CloseGuard.get();
+
+    private static final byte[] defaultBuf = new byte[0];
+
+    // Android-removed: initIDs handled in register method.
+    /*
+    static {
+        /* Zip library is loaded from System.initializeSystemClass *
+        initIDs();
+    }
+    */
+
+    /**
+     * Creates a new decompressor. If the parameter 'nowrap' is true then
+     * the ZLIB header and checksum fields will not be used. This provides
+     * compatibility with the compression format used by both GZIP and PKZIP.
+     * <p>
+     * Note: When using the 'nowrap' option it is also necessary to provide
+     * an extra "dummy" byte as input. This is required by the ZLIB native
+     * library in order to support certain optimizations.
+     *
+     * @param nowrap if true then support GZIP compatible compression
+     */
+    public Inflater(boolean nowrap) {
+        zsRef = new ZStreamRef(init(nowrap));
+        // Android-added: CloseGuard support.
+        guard.open("end");
+    }
+
+    /**
+     * Creates a new decompressor.
+     */
+    public Inflater() {
+        this(false);
+    }
+
+    /**
+     * Sets input data for decompression. Should be called whenever
+     * needsInput() returns true indicating that more input data is
+     * required.
+     * @param b the input data bytes
+     * @param off the start offset of the input data
+     * @param len the length of the input data
+     * @see Inflater#needsInput
+     */
+    public void setInput(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            this.buf = b;
+            this.off = off;
+            this.len = len;
+        }
+    }
+
+    /**
+     * Sets input data for decompression. Should be called whenever
+     * needsInput() returns true indicating that more input data is
+     * required.
+     * @param b the input data bytes
+     * @see Inflater#needsInput
+     */
+    public void setInput(byte[] b) {
+        setInput(b, 0, b.length);
+    }
+
+    /**
+     * Sets the preset dictionary to the given array of bytes. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * @param b the dictionary data bytes
+     * @param off the start offset of the data
+     * @param len the length of the data
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b, int off, int len) {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            setDictionary(zsRef.address(), b, off, len);
+            needDict = false;
+        }
+    }
+
+    /**
+     * Sets the preset dictionary to the given array of bytes. Should be
+     * called when inflate() returns 0 and needsDictionary() returns true
+     * indicating that a preset dictionary is required. The method getAdler()
+     * can be used to get the Adler-32 value of the dictionary needed.
+     * @param b the dictionary data bytes
+     * @see Inflater#needsDictionary
+     * @see Inflater#getAdler
+     */
+    public void setDictionary(byte[] b) {
+        setDictionary(b, 0, b.length);
+    }
+
+    /**
+     * Returns the total number of bytes remaining in the input buffer.
+     * This can be used to find out what bytes still remain in the input
+     * buffer after decompression has finished.
+     * @return the total number of bytes remaining in the input buffer
+     */
+    public int getRemaining() {
+        synchronized (zsRef) {
+            return len;
+        }
+    }
+
+    /**
+     * Returns true if no data remains in the input buffer. This can
+     * be used to determine if #setInput should be called in order
+     * to provide more input.
+     * @return true if no data remains in the input buffer
+     */
+    public boolean needsInput() {
+        synchronized (zsRef) {
+            return len <= 0;
+        }
+    }
+
+    /**
+     * Returns true if a preset dictionary is needed for decompression.
+     * @return true if a preset dictionary is needed for decompression
+     * @see Inflater#setDictionary
+     */
+    public boolean needsDictionary() {
+        synchronized (zsRef) {
+            return needDict;
+        }
+    }
+
+    /**
+     * Returns true if the end of the compressed data stream has been
+     * reached.
+     * @return true if the end of the compressed data stream has been
+     * reached
+     */
+    public boolean finished() {
+        synchronized (zsRef) {
+            return finished;
+        }
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * @param b the buffer for the uncompressed data
+     * @param off the start offset of the data
+     * @param len the maximum number of uncompressed bytes
+     * @return the actual number of uncompressed bytes
+     * @exception DataFormatException if the compressed data format is invalid
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     */
+    public int inflate(byte[] b, int off, int len)
+        throws DataFormatException
+    {
+        if (b == null) {
+            throw new NullPointerException();
+        }
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+        synchronized (zsRef) {
+            ensureOpen();
+            int thisLen = this.len;
+            int n = inflateBytes(zsRef.address(), b, off, len);
+            bytesWritten += n;
+            bytesRead += (thisLen - this.len);
+            return n;
+        }
+    }
+
+    /**
+     * Uncompresses bytes into specified buffer. Returns actual number
+     * of bytes uncompressed. A return value of 0 indicates that
+     * needsInput() or needsDictionary() should be called in order to
+     * determine if more input data or a preset dictionary is required.
+     * In the latter case, getAdler() can be used to get the Adler-32
+     * value of the dictionary required.
+     * @param b the buffer for the uncompressed data
+     * @return the actual number of uncompressed bytes
+     * @exception DataFormatException if the compressed data format is invalid
+     * @see Inflater#needsInput
+     * @see Inflater#needsDictionary
+     */
+    public int inflate(byte[] b) throws DataFormatException {
+        return inflate(b, 0, b.length);
+    }
+
+    /**
+     * Returns the ADLER-32 value of the uncompressed data.
+     * @return the ADLER-32 value of the uncompressed data
+     */
+    public int getAdler() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return getAdler(zsRef.address());
+        }
+    }
+
+    /**
+     * Returns the total number of compressed bytes input so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of compressed bytes input so far
+     */
+    public int getTotalIn() {
+        return (int) getBytesRead();
+    }
+
+    /**
+     * Returns the total number of compressed bytes input so far.
+     *
+     * @return the total (non-negative) number of compressed bytes input so far
+     * @since 1.5
+     */
+    public long getBytesRead() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesRead;
+        }
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes output so far.
+     *
+     * <p>Since the number of bytes may be greater than
+     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
+     * the preferred means of obtaining this information.</p>
+     *
+     * @return the total number of uncompressed bytes output so far
+     */
+    public int getTotalOut() {
+        return (int) getBytesWritten();
+    }
+
+    /**
+     * Returns the total number of uncompressed bytes output so far.
+     *
+     * @return the total (non-negative) number of uncompressed bytes output so far
+     * @since 1.5
+     */
+    public long getBytesWritten() {
+        synchronized (zsRef) {
+            ensureOpen();
+            return bytesWritten;
+        }
+    }
+
+    /**
+     * Resets inflater so that a new set of input data can be processed.
+     */
+    public void reset() {
+        synchronized (zsRef) {
+            ensureOpen();
+            reset(zsRef.address());
+            buf = defaultBuf;
+            finished = false;
+            needDict = false;
+            off = len = 0;
+            bytesRead = bytesWritten = 0;
+        }
+    }
+
+    /**
+     * Closes the decompressor and discards any unprocessed input.
+     * This method should be called when the decompressor is no longer
+     * being used, but will also be called automatically by the finalize()
+     * method. Once this method is called, the behavior of the Inflater
+     * object is undefined.
+     */
+    public void end() {
+        synchronized (zsRef) {
+            // Android-added: CloseGuard support.
+            guard.close();
+
+            long addr = zsRef.address();
+            zsRef.clear();
+            if (addr != 0) {
+                end(addr);
+                buf = null;
+            }
+        }
+    }
+
+    /**
+     * Closes the decompressor when garbage is collected.
+     */
+    protected void finalize() {
+        // Android-added: CloseGuard support.
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+
+        end();
+    }
+
+    private void ensureOpen () {
+        assert Thread.holdsLock(zsRef);
+        if (zsRef.address() == 0)
+            throw new NullPointerException("Inflater has been closed");
+    }
+
+    boolean ended() {
+        synchronized (zsRef) {
+            return zsRef.address() == 0;
+        }
+    }
+
+    // Android-changed: initIDs handled in register method.
+    // private native static void initIDs();
+    private native static long init(boolean nowrap);
+    private native static void setDictionary(long addr, byte[] b, int off,
+                                             int len);
+    private native int inflateBytes(long addr, byte[] b, int off, int len)
+            throws DataFormatException;
+    private native static int getAdler(long addr);
+    private native static void reset(long addr);
+    private native static void end(long addr);
+}
diff --git a/java/util/zip/InflaterInputStream.java b/java/util/zip/InflaterInputStream.java
new file mode 100644
index 0000000..b65adbe
--- /dev/null
+++ b/java/util/zip/InflaterInputStream.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+
+/**
+ * This class implements a stream filter for uncompressing data in the
+ * "deflate" compression format. It is also used as the basis for other
+ * decompression filters, such as GZIPInputStream.
+ *
+ * @see         Inflater
+ * @author      David Connelly
+ */
+public
+class InflaterInputStream extends FilterInputStream {
+    /**
+     * Decompressor for this stream.
+     */
+    protected Inflater inf;
+
+    /**
+     * Input buffer for decompression.
+     */
+    protected byte[] buf;
+
+    /**
+     * Length of input buffer.
+     */
+    protected int len;
+
+    // Android-changed: Make closed accessible to subclasses.
+    // This was made protected because it needed to be accessed by
+    // StrictJarFile.ZipInflaterInputStream. Unfortunately, it was not marked as @hide and so it
+    // inadvertently became part of the public API. It will be marked as @removed to remove it from
+    // the public API in a future release of Android. See http://b/111592689 for more information.
+    // private boolean closed = false;
+    /**
+     * Indicates whether the {@link #close()} method has been called, internal use only.
+     *
+     * @deprecated This field will be removed from a future version of Android and should not be
+     * used. Subclasses that access this field need to be modified to keep track of their own
+     * closed state by overriding close().
+     */
+    @Deprecated
+    protected boolean closed = false;
+
+    // this flag is set to true after EOF has reached
+    private boolean reachEOF = false;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+
+    /**
+     * Creates a new input stream with the specified decompressor and
+     * buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     * @param size the input buffer size
+     * @exception IllegalArgumentException if {@code size <= 0}
+     */
+    public InflaterInputStream(InputStream in, Inflater inf, int size) {
+        super(in);
+        if (in == null || inf == null) {
+            throw new NullPointerException();
+        } else if (size <= 0) {
+            throw new IllegalArgumentException("buffer size <= 0");
+        }
+        this.inf = inf;
+        buf = new byte[size];
+    }
+
+    /**
+     * Creates a new input stream with the specified decompressor and a
+     * default buffer size.
+     * @param in the input stream
+     * @param inf the decompressor ("inflater")
+     */
+    public InflaterInputStream(InputStream in, Inflater inf) {
+        this(in, inf, 512);
+    }
+
+    // Android-changed: Unconditionally close external inflaters (b/26462400)
+    // See http://b/111630946 for more details.
+    // boolean usesDefaultInflater = false;
+
+    /**
+     * Creates a new input stream with a default decompressor and buffer size.
+     * @param in the input stream
+     */
+    public InflaterInputStream(InputStream in) {
+        this(in, new Inflater());
+        // Android-changed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+    }
+
+    private byte[] singleByteBuf = new byte[1];
+
+    /**
+     * Reads a byte of uncompressed data. This method will block until
+     * enough input is available for decompression.
+     * @return the byte read, or -1 if end of compressed input is reached
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read() throws IOException {
+        ensureOpen();
+        return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]);
+    }
+
+    /**
+     * Reads uncompressed data into an array of bytes. If <code>len</code> is not
+     * zero, the method will block until some input can be decompressed; otherwise,
+     * no bytes are read and <code>0</code> is returned.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         compressed input is reached or a preset dictionary is needed
+     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP format error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException();
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+        try {
+            int n;
+            while ((n = inf.inflate(b, off, len)) == 0) {
+                if (inf.finished() || inf.needsDictionary()) {
+                    reachEOF = true;
+                    return -1;
+                }
+                if (inf.needsInput()) {
+                    fill();
+                }
+            }
+            return n;
+        } catch (DataFormatException e) {
+            String s = e.getMessage();
+            throw new ZipException(s != null ? s : "Invalid ZLIB data format");
+        }
+    }
+
+    /**
+     * Returns 0 after EOF has been reached, otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking.
+     *
+     * @return     1 before EOF and 0 after EOF.
+     * @exception  IOException  if an I/O error occurs.
+     *
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        if (reachEOF) {
+            return 0;
+        // BEGIN Android-added: Return more accurate value from available().
+        // Integrates change http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/dbcf47bfb044 made as part
+        // of https://bugs.openjdk.java.net/browse/JDK-7031075.
+        } else if (inf.finished()) {
+            // the end of the compressed data stream has been reached
+            reachEOF = true;
+            return 0;
+        // END Android-added: Return more accurate value from available().
+        } else {
+            return 1;
+        }
+    }
+
+    private byte[] b = new byte[512];
+
+    /**
+     * Skips specified number of bytes of uncompressed data.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped.
+     * @exception IOException if an I/O error has occurred
+     * @exception IllegalArgumentException if {@code n < 0}
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+        int max = (int)Math.min(n, Integer.MAX_VALUE);
+        int total = 0;
+        while (total < max) {
+            int len = max - total;
+            if (len > b.length) {
+                len = b.length;
+            }
+            len = read(b, 0, len);
+            if (len == -1) {
+                reachEOF = true;
+                break;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            // Android-changed: Unconditionally close external inflaters (b/26462400)
+            //if (usesDefaultInflater)
+            inf.end();
+            in.close();
+            closed = true;
+        }
+    }
+
+    /**
+     * Fills input buffer with more data to decompress.
+     * @exception IOException if an I/O error has occurred
+     */
+    protected void fill() throws IOException {
+        ensureOpen();
+        len = in.read(buf, 0, buf.length);
+        if (len == -1) {
+            throw new EOFException("Unexpected end of ZLIB input stream");
+        }
+        inf.setInput(buf, 0, len);
+    }
+
+    /**
+     * Tests if this input stream supports the <code>mark</code> and
+     * <code>reset</code> methods. The <code>markSupported</code>
+     * method of <code>InflaterInputStream</code> returns
+     * <code>false</code>.
+     *
+     * @return  a <code>boolean</code> indicating if this stream type supports
+     *          the <code>mark</code> and <code>reset</code> methods.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.InputStream#reset()
+     */
+    public boolean markSupported() {
+        return false;
+    }
+
+    /**
+     * Marks the current position in this input stream.
+     *
+     * <p> The <code>mark</code> method of <code>InflaterInputStream</code>
+     * does nothing.
+     *
+     * @param   readlimit   the maximum limit of bytes that can be read before
+     *                      the mark position becomes invalid.
+     * @see     java.io.InputStream#reset()
+     */
+    public synchronized void mark(int readlimit) {
+    }
+
+    /**
+     * Repositions this stream to the position at the time the
+     * <code>mark</code> method was last called on this input stream.
+     *
+     * <p> The method <code>reset</code> for class
+     * <code>InflaterInputStream</code> does nothing except throw an
+     * <code>IOException</code>.
+     *
+     * @exception  IOException  if this method is invoked.
+     * @see     java.io.InputStream#mark(int)
+     * @see     java.io.IOException
+     */
+    public synchronized void reset() throws IOException {
+        throw new IOException("mark/reset not supported");
+    }
+}
diff --git a/java/util/zip/InflaterOutputStream.java b/java/util/zip/InflaterOutputStream.java
new file mode 100644
index 0000000..02900c7
--- /dev/null
+++ b/java/util/zip/InflaterOutputStream.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Implements an output stream filter for uncompressing data stored in the
+ * "deflate" compression format.
+ *
+ * @since       1.6
+ * @author      David R Tribble ([email protected])
+ *
+ * @see InflaterInputStream
+ * @see DeflaterInputStream
+ * @see DeflaterOutputStream
+ */
+
+public class InflaterOutputStream extends FilterOutputStream {
+    /** Decompressor for this stream. */
+    protected final Inflater inf;
+
+    /** Output buffer for writing uncompressed data. */
+    protected final byte[] buf;
+
+    /** Temporary write buffer. */
+    private final byte[] wbuf = new byte[1];
+
+    /** Default decompressor is used. */
+    private boolean usesDefaultInflater = false;
+
+    /** true iff {@link #close()} has been called. */
+    private boolean closed = false;
+
+    /**
+     * Checks to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new output stream with a default decompressor and buffer
+     * size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @throws NullPointerException if {@code out} is null
+     */
+    public InflaterOutputStream(OutputStream out) {
+        this(out, new Inflater());
+        usesDefaultInflater = true;
+    }
+
+    /**
+     * Creates a new output stream with the specified decompressor and a
+     * default buffer size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @param infl decompressor ("inflater") for this stream
+     * @throws NullPointerException if {@code out} or {@code infl} is null
+     */
+    public InflaterOutputStream(OutputStream out, Inflater infl) {
+        this(out, infl, 512);
+    }
+
+    /**
+     * Creates a new output stream with the specified decompressor and
+     * buffer size.
+     *
+     * @param out output stream to write the uncompressed data to
+     * @param infl decompressor ("inflater") for this stream
+     * @param bufLen decompression buffer size
+     * @throws IllegalArgumentException if {@code bufLen <= 0}
+     * @throws NullPointerException if {@code out} or {@code infl} is null
+     */
+    public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) {
+        super(out);
+
+        // Sanity checks
+        if (out == null)
+            throw new NullPointerException("Null output");
+        if (infl == null)
+            throw new NullPointerException("Null inflater");
+        if (bufLen <= 0)
+            throw new IllegalArgumentException("Buffer size < 1");
+
+        // Initialize
+        inf = infl;
+        buf = new byte[bufLen];
+    }
+
+    /**
+     * Writes any remaining uncompressed data to the output stream and closes
+     * the underlying output stream.
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            // Complete the uncompressed output
+            try {
+                finish();
+            } finally {
+                out.close();
+                closed = true;
+            }
+        }
+    }
+
+    /**
+     * Flushes this output stream, forcing any pending buffered output bytes to be
+     * written.
+     *
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     */
+    public void flush() throws IOException {
+        ensureOpen();
+
+        // Finish decompressing and writing pending output data
+        if (!inf.finished()) {
+            try {
+                while (!inf.finished()  &&  !inf.needsInput()) {
+                    int n;
+
+                    // Decompress pending output data
+                    n = inf.inflate(buf, 0, buf.length);
+                    if (n < 1) {
+                        break;
+                    }
+
+                    // Write the uncompressed output data block
+                    out.write(buf, 0, n);
+                }
+                super.flush();
+            } catch (DataFormatException ex) {
+                // Improperly formatted compressed (ZIP) data
+                String msg = ex.getMessage();
+                if (msg == null) {
+                    msg = "Invalid ZLIB data format";
+                }
+                throw new ZipException(msg);
+            }
+        }
+    }
+
+    /**
+     * Finishes writing uncompressed data to the output stream without closing
+     * the underlying stream.  Use this method when applying multiple filters in
+     * succession to the same output stream.
+     *
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     */
+    public void finish() throws IOException {
+        ensureOpen();
+
+        // Finish decompressing and writing pending output data
+        flush();
+        if (usesDefaultInflater) {
+            inf.end();
+        }
+    }
+
+    /**
+     * Writes a byte to the uncompressed output stream.
+     *
+     * @param b a single byte of compressed data to decompress and write to
+     * the output stream
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     * @throws ZipException if a compression (ZIP) format error occurs
+     */
+    public void write(int b) throws IOException {
+        // Write a single byte of data
+        wbuf[0] = (byte) b;
+        write(wbuf, 0, 1);
+    }
+
+    /**
+     * Writes an array of bytes to the uncompressed output stream.
+     *
+     * @param b buffer containing compressed data to decompress and write to
+     * the output stream
+     * @param off starting offset of the compressed data within {@code b}
+     * @param len number of bytes to decompress from {@code b}
+     * @throws IndexOutOfBoundsException if {@code off < 0}, or if
+     * {@code len < 0}, or if {@code len > b.length - off}
+     * @throws IOException if an I/O error occurs or this stream is already
+     * closed
+     * @throws NullPointerException if {@code b} is null
+     * @throws ZipException if a compression (ZIP) format error occurs
+     */
+    public void write(byte[] b, int off, int len) throws IOException {
+        // Sanity checks
+        ensureOpen();
+        if (b == null) {
+            throw new NullPointerException("Null buffer for read");
+        } else if (off < 0 || len < 0 || len > b.length - off) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        // Write uncompressed data to the output stream
+        try {
+            for (;;) {
+                int n;
+
+                // Fill the decompressor buffer with output data
+                if (inf.needsInput()) {
+                    int part;
+
+                    if (len < 1) {
+                        break;
+                    }
+
+                    part = (len < 512 ? len : 512);
+                    inf.setInput(b, off, part);
+                    off += part;
+                    len -= part;
+                }
+
+                // Decompress and write blocks of output data
+                do {
+                    n = inf.inflate(buf, 0, buf.length);
+                    if (n > 0) {
+                        out.write(buf, 0, n);
+                    }
+                } while (n > 0);
+
+                // Check the decompressor
+                if (inf.finished()) {
+                    break;
+                }
+                if (inf.needsDictionary()) {
+                    throw new ZipException("ZLIB dictionary missing");
+                }
+            }
+        } catch (DataFormatException ex) {
+            // Improperly formatted compressed (ZIP) data
+            String msg = ex.getMessage();
+            if (msg == null) {
+                msg = "Invalid ZLIB data format";
+            }
+            throw new ZipException(msg);
+        }
+    }
+}
diff --git a/java/util/zip/ZStreamRef.java b/java/util/zip/ZStreamRef.java
new file mode 100644
index 0000000..09b2f30
--- /dev/null
+++ b/java/util/zip/ZStreamRef.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * A reference to the native zlib's z_stream structure.
+ */
+
+class ZStreamRef {
+
+    private volatile long address;
+    ZStreamRef (long address) {
+        this.address = address;
+    }
+
+    long address() {
+        return address;
+    }
+
+    void clear() {
+        address = 0;
+    }
+}
diff --git a/java/util/zip/ZipCoder.java b/java/util/zip/ZipCoder.java
new file mode 100644
index 0000000..b920b82
--- /dev/null
+++ b/java/util/zip/ZipCoder.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+import java.util.Arrays;
+import sun.nio.cs.ArrayDecoder;
+import sun.nio.cs.ArrayEncoder;
+
+/**
+ * Utility class for zipfile name and comment decoding and encoding
+ */
+
+final class ZipCoder {
+
+    String toString(byte[] ba, int length) {
+        CharsetDecoder cd = decoder().reset();
+        int len = (int)(length * cd.maxCharsPerByte());
+        char[] ca = new char[len];
+        if (len == 0)
+            return new String(ca);
+        // UTF-8 only for now. Other ArrayDeocder only handles
+        // CodingErrorAction.REPLACE mode. ZipCoder uses
+        // REPORT mode.
+        if (isUTF8 && cd instanceof ArrayDecoder) {
+            int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);
+            if (clen == -1)    // malformed
+                throw new IllegalArgumentException("MALFORMED");
+            return new String(ca, 0, clen);
+        }
+        ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
+        CharBuffer cb = CharBuffer.wrap(ca);
+        CoderResult cr = cd.decode(bb, cb, true);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        cr = cd.flush(cb);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        return new String(ca, 0, cb.position());
+    }
+
+    String toString(byte[] ba) {
+        return toString(ba, ba.length);
+    }
+
+    byte[] getBytes(String s) {
+        CharsetEncoder ce = encoder().reset();
+        char[] ca = s.toCharArray();
+        int len = (int)(ca.length * ce.maxBytesPerChar());
+        byte[] ba = new byte[len];
+        if (len == 0)
+            return ba;
+        // UTF-8 only for now. Other ArrayDeocder only handles
+        // CodingErrorAction.REPLACE mode.
+        if (isUTF8 && ce instanceof ArrayEncoder) {
+            int blen = ((ArrayEncoder)ce).encode(ca, 0, ca.length, ba);
+            if (blen == -1)    // malformed
+                throw new IllegalArgumentException("MALFORMED");
+            return Arrays.copyOf(ba, blen);
+        }
+        ByteBuffer bb = ByteBuffer.wrap(ba);
+        CharBuffer cb = CharBuffer.wrap(ca);
+        CoderResult cr = ce.encode(cb, bb, true);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        cr = ce.flush(bb);
+        if (!cr.isUnderflow())
+            throw new IllegalArgumentException(cr.toString());
+        if (bb.position() == ba.length)  // defensive copy?
+            return ba;
+        else
+            return Arrays.copyOf(ba, bb.position());
+    }
+
+    // assume invoked only if "this" is not utf8
+    byte[] getBytesUTF8(String s) {
+        if (isUTF8)
+            return getBytes(s);
+        if (utf8 == null)
+            utf8 = new ZipCoder(StandardCharsets.UTF_8);
+        return utf8.getBytes(s);
+    }
+
+
+    String toStringUTF8(byte[] ba, int len) {
+        if (isUTF8)
+            return toString(ba, len);
+        if (utf8 == null)
+            utf8 = new ZipCoder(StandardCharsets.UTF_8);
+        return utf8.toString(ba, len);
+    }
+
+    boolean isUTF8() {
+        return isUTF8;
+    }
+
+    private Charset cs;
+    private CharsetDecoder dec;
+    private CharsetEncoder enc;
+    private boolean isUTF8;
+    private ZipCoder utf8;
+
+    private ZipCoder(Charset cs) {
+        this.cs = cs;
+        this.isUTF8 = cs.name().equals(StandardCharsets.UTF_8.name());
+    }
+
+    static ZipCoder get(Charset charset) {
+        return new ZipCoder(charset);
+    }
+
+    private CharsetDecoder decoder() {
+        if (dec == null) {
+            dec = cs.newDecoder()
+              .onMalformedInput(CodingErrorAction.REPORT)
+              .onUnmappableCharacter(CodingErrorAction.REPORT);
+        }
+        return dec;
+    }
+
+    private CharsetEncoder encoder() {
+        if (enc == null) {
+            enc = cs.newEncoder()
+              .onMalformedInput(CodingErrorAction.REPORT)
+              .onUnmappableCharacter(CodingErrorAction.REPORT);
+        }
+        return enc;
+    }
+}
diff --git a/java/util/zip/ZipConstants.java b/java/util/zip/ZipConstants.java
new file mode 100644
index 0000000..db7f500
--- /dev/null
+++ b/java/util/zip/ZipConstants.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/*
+ * This interface defines the constants that are used by the classes
+ * which manipulate ZIP files.
+ *
+ * @author      David Connelly
+ */
+interface ZipConstants {
+    /*
+     * Header signatures
+     */
+    static long LOCSIG = 0x04034b50L;   // "PK\003\004"
+    static long EXTSIG = 0x08074b50L;   // "PK\007\008"
+    static long CENSIG = 0x02014b50L;   // "PK\001\002"
+    static long ENDSIG = 0x06054b50L;   // "PK\005\006"
+
+    /*
+     * Header sizes in bytes (including signatures)
+     */
+    static final int LOCHDR = 30;       // LOC header size
+    static final int EXTHDR = 16;       // EXT header size
+    static final int CENHDR = 46;       // CEN header size
+    static final int ENDHDR = 22;       // END header size
+
+    /*
+     * Local file (LOC) header field offsets
+     */
+    static final int LOCVER = 4;        // version needed to extract
+    static final int LOCFLG = 6;        // general purpose bit flag
+    static final int LOCHOW = 8;        // compression method
+    static final int LOCTIM = 10;       // modification time
+    static final int LOCCRC = 14;       // uncompressed file crc-32 value
+    static final int LOCSIZ = 18;       // compressed size
+    static final int LOCLEN = 22;       // uncompressed size
+    static final int LOCNAM = 26;       // filename length
+    static final int LOCEXT = 28;       // extra field length
+
+    /*
+     * Extra local (EXT) header field offsets
+     */
+    static final int EXTCRC = 4;        // uncompressed file crc-32 value
+    static final int EXTSIZ = 8;        // compressed size
+    static final int EXTLEN = 12;       // uncompressed size
+
+    /*
+     * Central directory (CEN) header field offsets
+     */
+    static final int CENVEM = 4;        // version made by
+    static final int CENVER = 6;        // version needed to extract
+    static final int CENFLG = 8;        // encrypt, decrypt flags
+    static final int CENHOW = 10;       // compression method
+    static final int CENTIM = 12;       // modification time
+    static final int CENCRC = 16;       // uncompressed file crc-32 value
+    static final int CENSIZ = 20;       // compressed size
+    static final int CENLEN = 24;       // uncompressed size
+    static final int CENNAM = 28;       // filename length
+    static final int CENEXT = 30;       // extra field length
+    static final int CENCOM = 32;       // comment length
+    static final int CENDSK = 34;       // disk number start
+    static final int CENATT = 36;       // internal file attributes
+    static final int CENATX = 38;       // external file attributes
+    static final int CENOFF = 42;       // LOC header offset
+
+    /*
+     * End of central directory (END) header field offsets
+     */
+    static final int ENDSUB = 8;        // number of entries on this disk
+    static final int ENDTOT = 10;       // total number of entries
+    static final int ENDSIZ = 12;       // central directory size in bytes
+    static final int ENDOFF = 16;       // offset of first CEN header
+    static final int ENDCOM = 20;       // zip file comment length
+}
diff --git a/java/util/zip/ZipConstants64.java b/java/util/zip/ZipConstants64.java
new file mode 100644
index 0000000..5d45f77
--- /dev/null
+++ b/java/util/zip/ZipConstants64.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/*
+ * This class defines the constants that are used by the classes
+ * which manipulate Zip64 files.
+ */
+
+class ZipConstants64 {
+
+    /*
+     * ZIP64 constants
+     */
+    static final long ZIP64_ENDSIG = 0x06064b50L;  // "PK\006\006"
+    static final long ZIP64_LOCSIG = 0x07064b50L;  // "PK\006\007"
+    static final int  ZIP64_ENDHDR = 56;           // ZIP64 end header size
+    static final int  ZIP64_LOCHDR = 20;           // ZIP64 end loc header size
+    static final int  ZIP64_EXTHDR = 24;           // EXT header size
+    static final int  ZIP64_EXTID  = 0x0001;       // Extra field Zip64 header ID
+
+    static final int  ZIP64_MAGICCOUNT = 0xFFFF;
+    static final long ZIP64_MAGICVAL = 0xFFFFFFFFL;
+
+    /*
+     * Zip64 End of central directory (END) header field offsets
+     */
+    static final int  ZIP64_ENDLEN = 4;       // size of zip64 end of central dir
+    static final int  ZIP64_ENDVEM = 12;      // version made by
+    static final int  ZIP64_ENDVER = 14;      // version needed to extract
+    static final int  ZIP64_ENDNMD = 16;      // number of this disk
+    static final int  ZIP64_ENDDSK = 20;      // disk number of start
+    static final int  ZIP64_ENDTOD = 24;      // total number of entries on this disk
+    static final int  ZIP64_ENDTOT = 32;      // total number of entries
+    static final int  ZIP64_ENDSIZ = 40;      // central directory size in bytes
+    static final int  ZIP64_ENDOFF = 48;      // offset of first CEN header
+    static final int  ZIP64_ENDEXT = 56;      // zip64 extensible data sector
+
+    /*
+     * Zip64 End of central directory locator field offsets
+     */
+    static final int  ZIP64_LOCDSK = 4;       // disk number start
+    static final int  ZIP64_LOCOFF = 8;       // offset of zip64 end
+    static final int  ZIP64_LOCTOT = 16;      // total number of disks
+
+    /*
+     * Zip64 Extra local (EXT) header field offsets
+     */
+    static final int  ZIP64_EXTCRC = 4;       // uncompressed file crc-32 value
+    static final int  ZIP64_EXTSIZ = 8;       // compressed size, 8-byte
+    static final int  ZIP64_EXTLEN = 16;      // uncompressed size, 8-byte
+
+    /*
+     * Language encoding flag EFS
+     */
+    static final int EFS = 0x800;       // If this bit is set the filename and
+                                        // comment fields for this file must be
+                                        // encoded using UTF-8.
+
+    /*
+     * Constants below are defined here (instead of in ZipConstants)
+     * to avoid being exposed as public fields of ZipFile, ZipEntry,
+     * ZipInputStream and ZipOutputstream.
+     */
+
+    /*
+     * Extra field header ID
+     */
+    static final int  EXTID_ZIP64 = 0x0001;    // Zip64
+    static final int  EXTID_NTFS  = 0x000a;    // NTFS
+    static final int  EXTID_UNIX  = 0x000d;    // UNIX
+    static final int  EXTID_EXTT  = 0x5455;    // Info-ZIP Extended Timestamp
+
+    /*
+     * EXTT timestamp flags
+     */
+    static final int  EXTT_FLAG_LMT = 0x1;       // LastModifiedTime
+    static final int  EXTT_FLAG_LAT = 0x2;       // LastAccessTime
+    static final int  EXTT_FLAT_CT  = 0x4;       // CreationTime
+
+    private ZipConstants64() {}
+}
diff --git a/java/util/zip/ZipEntry.annotated.java b/java/util/zip/ZipEntry.annotated.java
new file mode 100644
index 0000000..66b3616
--- /dev/null
+++ b/java/util/zip/ZipEntry.annotated.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package java.util.zip;
+
+import java.nio.file.attribute.FileTime;
+
+@SuppressWarnings({"unchecked", "deprecation", "all"})
+public class ZipEntry implements java.lang.Cloneable {
+
+public ZipEntry(java.lang.String name, java.lang.String comment, long crc, long compressedSize, long size, int compressionMethod, int xdostime, byte[] extra, long dataOffset) { throw new RuntimeException("Stub!"); }
+
+public ZipEntry(java.lang.String name) { throw new RuntimeException("Stub!"); }
+
+public ZipEntry(java.util.zip.ZipEntry e) { throw new RuntimeException("Stub!"); }
+
[email protected]
+public long getDataOffset() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getName() { throw new RuntimeException("Stub!"); }
+
+public void setTime(long time) { throw new RuntimeException("Stub!"); }
+
+public long getTime() { throw new RuntimeException("Stub!"); }
+
+public java.util.zip.ZipEntry setLastModifiedTime(java.nio.file.attribute.FileTime time) { throw new RuntimeException("Stub!"); }
+
+public java.nio.file.attribute.FileTime getLastModifiedTime() { throw new RuntimeException("Stub!"); }
+
+public java.util.zip.ZipEntry setLastAccessTime(java.nio.file.attribute.FileTime time) { throw new RuntimeException("Stub!"); }
+
+public java.nio.file.attribute.FileTime getLastAccessTime() { throw new RuntimeException("Stub!"); }
+
+public java.util.zip.ZipEntry setCreationTime(java.nio.file.attribute.FileTime time) { throw new RuntimeException("Stub!"); }
+
+public java.nio.file.attribute.FileTime getCreationTime() { throw new RuntimeException("Stub!"); }
+
+public void setSize(long size) { throw new RuntimeException("Stub!"); }
+
+public long getSize() { throw new RuntimeException("Stub!"); }
+
+public long getCompressedSize() { throw new RuntimeException("Stub!"); }
+
+public void setCompressedSize(long csize) { throw new RuntimeException("Stub!"); }
+
+public void setCrc(long crc) { throw new RuntimeException("Stub!"); }
+
+public long getCrc() { throw new RuntimeException("Stub!"); }
+
+public void setMethod(int method) { throw new RuntimeException("Stub!"); }
+
+public int getMethod() { throw new RuntimeException("Stub!"); }
+
+public void setExtra(byte[] extra) { throw new RuntimeException("Stub!"); }
+
+public byte[] getExtra() { throw new RuntimeException("Stub!"); }
+
+public void setComment(java.lang.String comment) { throw new RuntimeException("Stub!"); }
+
+public java.lang.String getComment() { throw new RuntimeException("Stub!"); }
+
+public boolean isDirectory() { throw new RuntimeException("Stub!"); }
+
+public java.lang.String toString() { throw new RuntimeException("Stub!"); }
+
+public int hashCode() { throw new RuntimeException("Stub!"); }
+
+public java.lang.Object clone() { throw new RuntimeException("Stub!"); }
+
+public static final int CENATT = 36; // 0x24
+
+public static final int CENATX = 38; // 0x26
+
+public static final int CENCOM = 32; // 0x20
+
+public static final int CENCRC = 16; // 0x10
+
+public static final int CENDSK = 34; // 0x22
+
+public static final int CENEXT = 30; // 0x1e
+
+public static final int CENFLG = 8; // 0x8
+
+public static final int CENHDR = 46; // 0x2e
+
+public static final int CENHOW = 10; // 0xa
+
+public static final int CENLEN = 24; // 0x18
+
+public static final int CENNAM = 28; // 0x1c
+
+public static final int CENOFF = 42; // 0x2a
+
+public static final long CENSIG = 33639248L; // 0x2014b50L
+
+public static final int CENSIZ = 20; // 0x14
+
+public static final int CENTIM = 12; // 0xc
+
+public static final int CENVEM = 4; // 0x4
+
+public static final int CENVER = 6; // 0x6
+
+public static final int DEFLATED = 8; // 0x8
+
+public static final int ENDCOM = 20; // 0x14
+
+public static final int ENDHDR = 22; // 0x16
+
+public static final int ENDOFF = 16; // 0x10
+
+public static final long ENDSIG = 101010256L; // 0x6054b50L
+
+public static final int ENDSIZ = 12; // 0xc
+
+public static final int ENDSUB = 8; // 0x8
+
+public static final int ENDTOT = 10; // 0xa
+
+public static final int EXTCRC = 4; // 0x4
+
+public static final int EXTHDR = 16; // 0x10
+
+public static final int EXTLEN = 12; // 0xc
+
+public static final long EXTSIG = 134695760L; // 0x8074b50L
+
+public static final int EXTSIZ = 8; // 0x8
+
+public static final int LOCCRC = 14; // 0xe
+
+public static final int LOCEXT = 28; // 0x1c
+
+public static final int LOCFLG = 6; // 0x6
+
+public static final int LOCHDR = 30; // 0x1e
+
+public static final int LOCHOW = 8; // 0x8
+
+public static final int LOCLEN = 22; // 0x16
+
+public static final int LOCNAM = 26; // 0x1a
+
+public static final long LOCSIG = 67324752L; // 0x4034b50L
+
+public static final int LOCSIZ = 18; // 0x12
+
+public static final int LOCTIM = 10; // 0xa
+
+public static final int LOCVER = 4; // 0x4
+
+public static final int STORED = 0; // 0x0
+
+public static final long UPPER_DOSTIME_BOUND = 4036608000000L; // 0x3abd8960000L
+}
+
diff --git a/java/util/zip/ZipEntry.java b/java/util/zip/ZipEntry.java
new file mode 100644
index 0000000..0de6756
--- /dev/null
+++ b/java/util/zip/ZipEntry.java
@@ -0,0 +1,636 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import static java.util.zip.ZipUtils.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.attribute.FileTime;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import static java.util.zip.ZipConstants64.*;
+
+/**
+ * This class is used to represent a ZIP file entry.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipEntry implements ZipConstants, Cloneable {
+    String name;        // entry name
+    long xdostime = -1; // last modification time (in extended DOS time,
+                        // where milliseconds lost in conversion might
+                        // be encoded into the upper half)
+    FileTime mtime;     // last modification time, from extra field data
+    FileTime atime;     // last access time, from extra field data
+    FileTime ctime;     // creation time, from extra field data
+    long crc = -1;      // crc-32 of entry data
+    long size = -1;     // uncompressed size of entry data
+    long csize = -1;    // compressed size of entry data
+    int method = -1;    // compression method
+    int flag = 0;       // general purpose flag
+    byte[] extra;       // optional extra field data for entry
+    String comment;     // optional comment string for entry
+    // Android-added: Add dataOffset for internal use.
+    // Used by android.util.jar.StrictJarFile from frameworks.
+    long dataOffset;
+
+    /**
+     * Compression method for uncompressed entries.
+     */
+    public static final int STORED = 0;
+
+    /**
+     * Compression method for compressed (deflated) entries.
+     */
+    public static final int DEFLATED = 8;
+
+    /**
+     * DOS time constant for representing timestamps before 1980.
+     */
+    static final long DOSTIME_BEFORE_1980 = (1 << 21) | (1 << 16);
+
+    /**
+     * Approximately 128 years, in milliseconds (ignoring leap years etc).
+     *
+     * This establish an approximate high-bound value for DOS times in
+     * milliseconds since epoch, used to enable an efficient but
+     * sufficient bounds check to avoid generating extended last modified
+     * time entries.
+     *
+     * Calculating the exact number is locale dependent, would require loading
+     * TimeZone data eagerly, and would make little practical sense. Since DOS
+     * times theoretically go to 2107 - with compatibility not guaranteed
+     * after 2099 - setting this to a time that is before but near 2099
+     * should be sufficient.
+     * @hide
+     */
+    // Android-changed: Make UPPER_DOSTIME_BOUND public hidden for testing purposes.
+    public static final long UPPER_DOSTIME_BOUND =
+            128L * 365 * 24 * 60 * 60 * 1000;
+
+    // Android-added: New constructor for use by StrictJarFile native code.
+    /** @hide */
+    public ZipEntry(String name, String comment, long crc, long compressedSize,
+            long size, int compressionMethod, int xdostime, byte[] extra,
+            long dataOffset) {
+        this.name = name;
+        this.comment = comment;
+        this.crc = crc;
+        this.csize = compressedSize;
+        this.size = size;
+        this.method = compressionMethod;
+        this.xdostime = xdostime;
+        this.dataOffset = dataOffset;
+        this.setExtra0(extra, false);
+    }
+
+    /**
+     * Creates a new zip entry with the specified name.
+     *
+     * @param  name
+     *         The entry name
+     *
+     * @throws NullPointerException if the entry name is null
+     * @throws IllegalArgumentException if the entry name is longer than
+     *         0xFFFF bytes
+     */
+    public ZipEntry(String name) {
+        Objects.requireNonNull(name, "name");
+        // Android-changed: Explicitly use UTF_8 instead of the default charset.
+        // if (name.length() > 0xFFFF) {
+        //     throw new IllegalArgumentException("entry name too long");
+        // }
+        if (name.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
+            throw new IllegalArgumentException(name + " too long: " +
+                    name.getBytes(StandardCharsets.UTF_8).length);
+        }
+        this.name = name;
+    }
+
+    /**
+     * Creates a new zip entry with fields taken from the specified
+     * zip entry.
+     *
+     * @param  e
+     *         A zip Entry object
+     *
+     * @throws NullPointerException if the entry object is null
+     */
+    public ZipEntry(ZipEntry e) {
+        Objects.requireNonNull(e, "entry");
+        name = e.name;
+        xdostime = e.xdostime;
+        mtime = e.mtime;
+        atime = e.atime;
+        ctime = e.ctime;
+        crc = e.crc;
+        size = e.size;
+        csize = e.csize;
+        method = e.method;
+        flag = e.flag;
+        extra = e.extra;
+        comment = e.comment;
+        // Android-added: Add dataOffset for internal use.
+        dataOffset = e.dataOffset;
+    }
+
+    /**
+     * Creates a new un-initialized zip entry
+     */
+    ZipEntry() {}
+
+    // Android-added: Add dataOffset for internal use.
+    /** @hide */
+    public long getDataOffset() {
+        return dataOffset;
+    }
+
+    /**
+     * Returns the name of the entry.
+     * @return the name of the entry
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the last modification time of the entry.
+     *
+     * <p> If the entry is output to a ZIP file or ZIP file formatted
+     * output stream the last modification time set by this method will
+     * be stored into the {@code date and time fields} of the zip file
+     * entry and encoded in standard {@code MS-DOS date and time format}.
+     * The {@link java.util.TimeZone#getDefault() default TimeZone} is
+     * used to convert the epoch time to the MS-DOS data and time.
+     *
+     * @param  time
+     *         The last modification time of the entry in milliseconds
+     *         since the epoch
+     *
+     * @see #getTime()
+     * @see #getLastModifiedTime()
+     */
+    public void setTime(long time) {
+        this.xdostime = javaToExtendedDosTime(time);
+        // Avoid setting the mtime field if time is in the valid
+        // range for a DOS time
+        if (xdostime != DOSTIME_BEFORE_1980 && time <= UPPER_DOSTIME_BOUND) {
+            this.mtime = null;
+        } else {
+            this.mtime = FileTime.from(time, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    /**
+     * Returns the last modification time of the entry.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the {@code
+     * date and time fields} of the zip file entry. The
+     * {@link java.util.TimeZone#getDefault() default TimeZone} is used
+     * to convert the standard MS-DOS formatted date and time to the
+     * epoch time.
+     *
+     * @return  The last modification time of the entry in milliseconds
+     *          since the epoch, or -1 if not specified
+     *
+     * @see #setTime(long)
+     * @see #setLastModifiedTime(FileTime)
+     */
+    public long getTime() {
+        if (mtime != null) {
+            return mtime.toMillis();
+        }
+        return (xdostime != -1) ? extendedDosToJavaTime(xdostime) : -1;
+    }
+
+    /**
+     * Sets the last modification time of the entry.
+     *
+     * <p> When output to a ZIP file or ZIP file formatted output stream
+     * the last modification time set by this method will be stored into
+     * zip file entry's {@code date and time fields} in {@code standard
+     * MS-DOS date and time format}), and the extended timestamp fields
+     * in {@code optional extra data} in UTC time.
+     *
+     * @param  time
+     *         The last modification time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getLastModifiedTime()
+     * @since 1.8
+     */
+    public ZipEntry setLastModifiedTime(FileTime time) {
+        this.mtime = Objects.requireNonNull(time, "lastModifiedTime");
+        this.xdostime = javaToExtendedDosTime(time.to(TimeUnit.MILLISECONDS));
+        return this;
+    }
+
+    /**
+     * Returns the last modification time of the entry.
+     *
+     * <p> If the entry is read from a ZIP file or ZIP file formatted
+     * input stream, this is the last modification time from the zip
+     * file entry's {@code optional extra data} if the extended timestamp
+     * fields are present. Otherwise the last modification time is read
+     * from the entry's {@code date and time fields}, the {@link
+     * java.util.TimeZone#getDefault() default TimeZone} is used to convert
+     * the standard MS-DOS formatted date and time to the epoch time.
+     *
+     * @return The last modification time of the entry, null if not specified
+     *
+     * @see #setLastModifiedTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getLastModifiedTime() {
+        if (mtime != null)
+            return mtime;
+        if (xdostime == -1)
+            return null;
+        return FileTime.from(getTime(), TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Sets the last access time of the entry.
+     *
+     * <p> If set, the last access time will be stored into the extended
+     * timestamp fields of entry's {@code optional extra data}, when output
+     * to a ZIP file or ZIP file formatted stream.
+     *
+     * @param  time
+     *         The last access time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getLastAccessTime()
+     * @since 1.8
+     */
+    public ZipEntry setLastAccessTime(FileTime time) {
+        this.atime = Objects.requireNonNull(time, "lastAccessTime");
+        return this;
+    }
+
+    /**
+     * Returns the last access time of the entry.
+     *
+     * <p> The last access time is from the extended timestamp fields
+     * of entry's {@code optional extra data} when read from a ZIP file
+     * or ZIP file formatted stream.
+     *
+     * @return The last access time of the entry, null if not specified
+
+     * @see #setLastAccessTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getLastAccessTime() {
+        return atime;
+    }
+
+    /**
+     * Sets the creation time of the entry.
+     *
+     * <p> If set, the creation time will be stored into the extended
+     * timestamp fields of entry's {@code optional extra data}, when
+     * output to a ZIP file or ZIP file formatted stream.
+     *
+     * @param  time
+     *         The creation time of the entry
+     * @return This zip entry
+     *
+     * @throws NullPointerException if the {@code time} is null
+     *
+     * @see #getCreationTime()
+     * @since 1.8
+     */
+    public ZipEntry setCreationTime(FileTime time) {
+        this.ctime = Objects.requireNonNull(time, "creationTime");
+        return this;
+    }
+
+    /**
+     * Returns the creation time of the entry.
+     *
+     * <p> The creation time is from the extended timestamp fields of
+     * entry's {@code optional extra data} when read from a ZIP file
+     * or ZIP file formatted stream.
+     *
+     * @return the creation time of the entry, null if not specified
+     * @see #setCreationTime(FileTime)
+     * @since 1.8
+     */
+    public FileTime getCreationTime() {
+        return ctime;
+    }
+
+    /**
+     * Sets the uncompressed size of the entry data.
+     *
+     * @param size the uncompressed size in bytes
+     *
+     * @throws IllegalArgumentException if the specified size is less
+     *         than 0, is greater than 0xFFFFFFFF when
+     *         <a href="package-summary.html#zip64">ZIP64 format</a> is not supported,
+     *         or is less than 0 when ZIP64 is supported
+     * @see #getSize()
+     */
+    public void setSize(long size) {
+        if (size < 0) {
+            throw new IllegalArgumentException("invalid entry size");
+        }
+        this.size = size;
+    }
+
+    /**
+     * Returns the uncompressed size of the entry data.
+     *
+     * @return the uncompressed size of the entry data, or -1 if not known
+     * @see #setSize(long)
+     */
+    public long getSize() {
+        return size;
+    }
+
+    /**
+     * Returns the size of the compressed entry data.
+     *
+     * <p> In the case of a stored entry, the compressed size will be the same
+     * as the uncompressed size of the entry.
+     *
+     * @return the size of the compressed entry data, or -1 if not known
+     * @see #setCompressedSize(long)
+     */
+    public long getCompressedSize() {
+        return csize;
+    }
+
+    /**
+     * Sets the size of the compressed entry data.
+     *
+     * @param csize the compressed size to set to
+     *
+     * @see #getCompressedSize()
+     */
+    public void setCompressedSize(long csize) {
+        this.csize = csize;
+    }
+
+    /**
+     * Sets the CRC-32 checksum of the uncompressed entry data.
+     *
+     * @param crc the CRC-32 value
+     *
+     * @throws IllegalArgumentException if the specified CRC-32 value is
+     *         less than 0 or greater than 0xFFFFFFFF
+     * @see #getCrc()
+     */
+    public void setCrc(long crc) {
+        if (crc < 0 || crc > 0xFFFFFFFFL) {
+            throw new IllegalArgumentException("invalid entry crc-32");
+        }
+        this.crc = crc;
+    }
+
+    /**
+     * Returns the CRC-32 checksum of the uncompressed entry data.
+     *
+     * @return the CRC-32 checksum of the uncompressed entry data, or -1 if
+     * not known
+     *
+     * @see #setCrc(long)
+     */
+    public long getCrc() {
+        return crc;
+    }
+
+    /**
+     * Sets the compression method for the entry.
+     *
+     * @param method the compression method, either STORED or DEFLATED
+     *
+     * @throws  IllegalArgumentException if the specified compression
+     *          method is invalid
+     * @see #getMethod()
+     */
+    public void setMethod(int method) {
+        if (method != STORED && method != DEFLATED) {
+            throw new IllegalArgumentException("invalid compression method");
+        }
+        this.method = method;
+    }
+
+    /**
+     * Returns the compression method of the entry.
+     *
+     * @return the compression method of the entry, or -1 if not specified
+     * @see #setMethod(int)
+     */
+    public int getMethod() {
+        return method;
+    }
+
+    /**
+     * Sets the optional extra field data for the entry.
+     *
+     * <p> Invoking this method may change this entry's last modification
+     * time, last access time and creation time, if the {@code extra} field
+     * data includes the extensible timestamp fields, such as {@code NTFS tag
+     * 0x0001} or {@code Info-ZIP Extended Timestamp}, as specified in
+     * <a href="http://www.info-zip.org/doc/appnote-19970311-iz.zip">Info-ZIP
+     * Application Note 970311</a>.
+     *
+     * @param  extra
+     *         The extra field data bytes
+     *
+     * @throws IllegalArgumentException if the length of the specified
+     *         extra field data is greater than 0xFFFF bytes
+     *
+     * @see #getExtra()
+     */
+    public void setExtra(byte[] extra) {
+        setExtra0(extra, false);
+    }
+
+    /**
+     * Sets the optional extra field data for the entry.
+     *
+     * @param extra
+     *        the extra field data bytes
+     * @param doZIP64
+     *        if true, set size and csize from ZIP64 fields if present
+     */
+    void setExtra0(byte[] extra, boolean doZIP64) {
+        if (extra != null) {
+            if (extra.length > 0xFFFF) {
+                throw new IllegalArgumentException("invalid extra field length");
+            }
+            // extra fields are in "HeaderID(2)DataSize(2)Data... format
+            int off = 0;
+            int len = extra.length;
+            while (off + 4 < len) {
+                int tag = get16(extra, off);
+                int sz = get16(extra, off + 2);
+                off += 4;
+                if (off + sz > len)         // invalid data
+                    break;
+                switch (tag) {
+                case EXTID_ZIP64:
+                    if (doZIP64) {
+                        // LOC extra zip64 entry MUST include BOTH original
+                        // and compressed file size fields.
+                        // If invalid zip64 extra fields, simply skip. Even
+                        // it's rare, it's possible the entry size happens to
+                        // be the magic value and it "accidently" has some
+                        // bytes in extra match the id.
+                        if (sz >= 16) {
+                            size = get64(extra, off);
+                            csize = get64(extra, off + 8);
+                        }
+                    }
+                    break;
+                case EXTID_NTFS:
+                    if (sz < 32) // reserved  4 bytes + tag 2 bytes + size 2 bytes
+                        break;   // m[a|c]time 24 bytes
+                    int pos = off + 4;               // reserved 4 bytes
+                    if (get16(extra, pos) !=  0x0001 || get16(extra, pos + 2) != 24)
+                        break;
+                    mtime = winTimeToFileTime(get64(extra, pos + 4));
+                    atime = winTimeToFileTime(get64(extra, pos + 12));
+                    ctime = winTimeToFileTime(get64(extra, pos + 20));
+                    break;
+                case EXTID_EXTT:
+                    int flag = Byte.toUnsignedInt(extra[off]);
+                    int sz0 = 1;
+                    // The CEN-header extra field contains the modification
+                    // time only, or no timestamp at all. 'sz' is used to
+                    // flag its presence or absence. But if mtime is present
+                    // in LOC it must be present in CEN as well.
+                    if ((flag & 0x1) != 0 && (sz0 + 4) <= sz) {
+                        mtime = unixTimeToFileTime(get32(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    if ((flag & 0x2) != 0 && (sz0 + 4) <= sz) {
+                        atime = unixTimeToFileTime(get32(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    if ((flag & 0x4) != 0 && (sz0 + 4) <= sz) {
+                        ctime = unixTimeToFileTime(get32(extra, off + sz0));
+                        sz0 += 4;
+                    }
+                    break;
+                 default:
+                }
+                off += sz;
+            }
+        }
+        this.extra = extra;
+    }
+
+    /**
+     * Returns the extra field data for the entry.
+     *
+     * @return the extra field data for the entry, or null if none
+     *
+     * @see #setExtra(byte[])
+     */
+    public byte[] getExtra() {
+        return extra;
+    }
+
+    /**
+     * Sets the optional comment string for the entry.
+     *
+     * <p>ZIP entry comments have maximum length of 0xffff. If the length of the
+     * specified comment string is greater than 0xFFFF bytes after encoding, only
+     * the first 0xFFFF bytes are output to the ZIP file entry.
+     *
+     * @param comment the comment string
+     *
+     * @see #getComment()
+     */
+    public void setComment(String comment) {
+        // BEGIN Android-added: Explicitly use UTF_8 instead of the default charset.
+        if (comment != null && comment.getBytes(StandardCharsets.UTF_8).length > 0xffff) {
+            throw new IllegalArgumentException(comment + " too long: " +
+                    comment.getBytes(StandardCharsets.UTF_8).length);
+        }
+        // END Android-added: Explicitly use UTF_8 instead of the default charset.
+
+        this.comment = comment;
+    }
+
+    /**
+     * Returns the comment string for the entry.
+     *
+     * @return the comment string for the entry, or null if none
+     *
+     * @see #setComment(String)
+     */
+    public String getComment() {
+        return comment;
+    }
+
+    /**
+     * Returns true if this is a directory entry. A directory entry is
+     * defined to be one whose name ends with a '/'.
+     * @return true if this is a directory entry
+     */
+    public boolean isDirectory() {
+        return name.endsWith("/");
+    }
+
+    /**
+     * Returns a string representation of the ZIP entry.
+     */
+    public String toString() {
+        return getName();
+    }
+
+    /**
+     * Returns the hash code value for this entry.
+     */
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * Returns a copy of this entry.
+     */
+    public Object clone() {
+        try {
+            ZipEntry e = (ZipEntry)super.clone();
+            e.extra = (extra == null) ? null : extra.clone();
+            return e;
+        } catch (CloneNotSupportedException e) {
+            // This should never happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+    }
+}
diff --git a/java/util/zip/ZipError.java b/java/util/zip/ZipError.java
new file mode 100644
index 0000000..2799c8e
--- /dev/null
+++ b/java/util/zip/ZipError.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+/**
+ * Signals that an unrecoverable error has occurred.
+ *
+ * @author  Dave Bristor
+ * @since   1.6
+ */
+public class ZipError extends InternalError {
+    private static final long serialVersionUID = 853973422266861979L;
+
+    /**
+     * Constructs a ZipError with the given detail message.
+     * @param s the {@code String} containing a detail message
+     */
+    public ZipError(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/zip/ZipException.java b/java/util/zip/ZipException.java
new file mode 100644
index 0000000..4bcfe03
--- /dev/null
+++ b/java/util/zip/ZipException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.IOException;
+
+/**
+ * Signals that a Zip exception of some sort has occurred.
+ *
+ * @author  unascribed
+ * @see     java.io.IOException
+ * @since   JDK1.0
+ */
+
+public
+class ZipException extends IOException {
+    private static final long serialVersionUID = 8000196834066748623L;
+
+    /**
+     * Constructs a <code>ZipException</code> with <code>null</code>
+     * as its error detail message.
+     */
+    public ZipException() {
+        super();
+    }
+
+    /**
+     * Constructs a <code>ZipException</code> with the specified detail
+     * message.
+     *
+     * @param   s   the detail message.
+     */
+
+    public ZipException(String s) {
+        super(s);
+    }
+}
diff --git a/java/util/zip/ZipFile.java b/java/util/zip/ZipFile.java
new file mode 100644
index 0000000..851aab1
--- /dev/null
+++ b/java/util/zip/ZipFile.java
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.WeakHashMap;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import dalvik.system.CloseGuard;
+
+import static java.util.zip.ZipConstants64.*;
+
+/**
+ * This class is used to read entries from a zip file.
+ *
+ * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
+ * or method in this class will cause a {@link NullPointerException} to be
+ * thrown.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipFile implements ZipConstants, Closeable {
+    // Android-note: jzfile does not require @ReachabilitySensitive annotation.
+    // The @ReachabilitySensitive annotation is usually added to instance fields that references
+    // native data that is cleaned up when the instance becomes unreachable. Its presence ensures
+    // that the instance object is not finalized until the field is no longer used. Without it an
+    // instance could be finalized during execution of an instance method iff that method's this
+    // variable holds the last reference to the instance and the method had copied all the fields
+    // it needs out of the instance. That would release the native data, invalidating its reference
+    // and would cause serious problems if the method had taken a copy of that field and
+    // then called a native method that would try to use it.
+    //
+    // This field does not require the annotation because all usages of this field are enclosed
+    // within a synchronized(this) block and finalizing of the object referenced in a synchronized
+    // block is not allowed as that would release its monitor that is currently in use.
+    private long jzfile;  // address of jzfile data
+    private final String name;     // zip file name
+    private final int total;       // total number of entries
+    private final boolean locsig;  // if zip file starts with LOCSIG (usually true)
+    private volatile boolean closeRequested = false;
+
+    // Android-added: CloseGuard support
+    private final CloseGuard guard = CloseGuard.get();
+
+    // Android-added: Do not use unlink() to implement OPEN_DELETE.
+    // Upstream uses unlink() to cause the file name to be removed from the filesystem after it is
+    // opened but that does not work on fuse fs as it causes problems with lseek. Android simply
+    // keeps a reference to the File so that it can explicitly delete it during close.
+    //
+    // OpenJDK 9+181 has a pure Java implementation of ZipFile that does not use unlink() and
+    // instead does something very similar to what Android does. If Android adopts it then this
+    // patch can be dropped.
+    // See http://b/28950284 and http://b/28901232 for more details.
+    private final File fileToRemoveOnClose;
+
+    private static final int STORED = ZipEntry.STORED;
+    private static final int DEFLATED = ZipEntry.DEFLATED;
+
+    /**
+     * Mode flag to open a zip file for reading.
+     */
+    public static final int OPEN_READ = 0x1;
+
+    /**
+     * Mode flag to open a zip file and mark it for deletion.  The file will be
+     * deleted some time between the moment that it is opened and the moment
+     * that it is closed, but its contents will remain accessible via the
+     * <tt>ZipFile</tt> object until either the close method is invoked or the
+     * virtual machine exits.
+     */
+    public static final int OPEN_DELETE = 0x4;
+
+    // Android-removed: initIDs() not used on Android.
+    /*
+    static {
+        /* Zip library is loaded from System.initializeSystemClass *
+        initIDs();
+    }
+
+    private static native void initIDs();
+    */
+
+    private static final boolean usemmap;
+
+    static {
+        // Android-changed: Always use mmap.
+        /*
+        // A system prpperty to disable mmap use to avoid vm crash when
+        // in-use zip file is accidently overwritten by others.
+        String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
+        usemmap = (prop == null ||
+                   !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
+        */
+        usemmap = true;
+    }
+
+    /**
+     * Opens a zip file for reading.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument
+     * to ensure the read is allowed.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments.
+     *
+     * @param name the name of the zip file
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if a security manager exists and its
+     *         <code>checkRead</code> method doesn't allow read access to the file.
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     */
+    public ZipFile(String name) throws IOException {
+        this(new File(name), OPEN_READ);
+    }
+
+    /**
+     * Opens a new <code>ZipFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument to
+     * ensure the read is allowed.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param mode the mode in which the file is to be opened
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException if a security manager exists and
+     *         its <code>checkRead</code> method
+     *         doesn't allow read access to the file,
+     *         or its <code>checkDelete</code> method doesn't allow deleting
+     *         the file when the <tt>OPEN_DELETE</tt> flag is set.
+     * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
+     * @see SecurityManager#checkRead(java.lang.String)
+     * @since 1.3
+     */
+    public ZipFile(File file, int mode) throws IOException {
+        this(file, mode, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Opens a ZIP file for reading given the specified File object.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names and comments.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     */
+    public ZipFile(File file) throws ZipException, IOException {
+        this(file, OPEN_READ);
+    }
+
+    private ZipCoder zc;
+
+    /**
+     * Opens a new <code>ZipFile</code> to read from the specified
+     * <code>File</code> object in the specified mode.  The mode argument
+     * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument to
+     * ensure the read is allowed.
+     *
+     * @param file the ZIP file to be opened for reading
+     * @param mode the mode in which the file is to be opened
+     * @param charset
+     *        the {@linkplain java.nio.charset.Charset charset} to
+     *        be used to decode the ZIP entry name and comment that are not
+     *        encoded by using UTF-8 encoding (indicated by entry's general
+     *        purpose flag).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     *
+     * @throws SecurityException
+     *         if a security manager exists and its <code>checkRead</code>
+     *         method doesn't allow read access to the file,or its
+     *         <code>checkDelete</code> method doesn't allow deleting the
+     *         file when the <tt>OPEN_DELETE</tt> flag is set
+     *
+     * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     *
+     * @since 1.7
+     */
+    public ZipFile(File file, int mode, Charset charset) throws IOException
+    {
+        if (((mode & OPEN_READ) == 0) ||
+            ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
+            throw new IllegalArgumentException("Illegal mode: 0x"+
+                                               Integer.toHexString(mode));
+        }
+        String name = file.getPath();
+        // Android-removed: SecurityManager is always null
+        /*
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkRead(name);
+            if ((mode & OPEN_DELETE) != 0) {
+                sm.checkDelete(name);
+            }
+        }
+        */
+
+        // Android-added: Do not use unlink() to implement OPEN_DELETE.
+        fileToRemoveOnClose = ((mode & OPEN_DELETE) != 0) ? file : null;
+
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+        // Android-removed: Skip perf counters
+        // long t0 = System.nanoTime();
+        jzfile = open(name, mode, file.lastModified(), usemmap);
+        // Android-removed: Skip perf counters
+        // sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
+        // sun.misc.PerfCounter.getZipFileCount().increment();
+        this.name = name;
+        this.total = getTotal(jzfile);
+        this.locsig = startsWithLOC(jzfile);
+        // Android-added: CloseGuard support
+        guard.open("close");
+    }
+
+    /**
+     * Opens a zip file for reading.
+     *
+     * <p>First, if there is a security manager, its <code>checkRead</code>
+     * method is called with the <code>name</code> argument as its argument
+     * to ensure the read is allowed.
+     *
+     * @param name the name of the zip file
+     * @param charset
+     *        the {@linkplain java.nio.charset.Charset charset} to
+     *        be used to decode the ZIP entry name and comment that are not
+     *        encoded by using UTF-8 encoding (indicated by entry's general
+     *        purpose flag).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws SecurityException
+     *         if a security manager exists and its <code>checkRead</code>
+     *         method doesn't allow read access to the file
+     *
+     * @see SecurityManager#checkRead(java.lang.String)
+     *
+     * @since 1.7
+     */
+    public ZipFile(String name, Charset charset) throws IOException
+    {
+        this(new File(name), OPEN_READ, charset);
+    }
+
+    /**
+     * Opens a ZIP file for reading given the specified File object.
+     * @param file the ZIP file to be opened for reading
+     * @param charset
+     *        The {@linkplain java.nio.charset.Charset charset} to be
+     *        used to decode the ZIP entry name and comment (ignored if
+     *        the <a href="package-summary.html#lang_encoding"> language
+     *        encoding bit</a> of the ZIP entry's general purpose bit
+     *        flag is set).
+     *
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     *
+     * @since 1.7
+     */
+    public ZipFile(File file, Charset charset) throws IOException
+    {
+        this(file, OPEN_READ, charset);
+    }
+
+    /**
+     * Returns the zip file comment, or null if none.
+     *
+     * @return the comment string for the zip file, or null if none
+     *
+     * @throws IllegalStateException if the zip file has been closed
+     *
+     * Since 1.7
+     */
+    public String getComment() {
+        synchronized (this) {
+            ensureOpen();
+            byte[] bcomm = getCommentBytes(jzfile);
+            if (bcomm == null)
+                return null;
+            return zc.toString(bcomm, bcomm.length);
+        }
+    }
+
+    /**
+     * Returns the zip file entry for the specified name, or null
+     * if not found.
+     *
+     * @param name the name of the entry
+     * @return the zip file entry, or null if not found
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public ZipEntry getEntry(String name) {
+        if (name == null) {
+            throw new NullPointerException("name");
+        }
+        long jzentry = 0;
+        synchronized (this) {
+            ensureOpen();
+            jzentry = getEntry(jzfile, zc.getBytes(name), true);
+            if (jzentry != 0) {
+                ZipEntry ze = getZipEntry(name, jzentry);
+                freeEntry(jzfile, jzentry);
+                return ze;
+            }
+        }
+        return null;
+    }
+
+    private static native long getEntry(long jzfile, byte[] name,
+                                        boolean addSlash);
+
+    // freeEntry releases the C jzentry struct.
+    private static native void freeEntry(long jzfile, long jzentry);
+
+    // the outstanding inputstreams that need to be closed,
+    // mapped to the inflater objects they use.
+    private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
+
+    /**
+     * Returns an input stream for reading the contents of the specified
+     * zip file entry.
+     *
+     * <p> Closing this ZIP file will, in turn, close all input
+     * streams that have been returned by invocations of this method.
+     *
+     * @param entry the zip file entry
+     * @return the input stream for reading the contents of the specified
+     * zip file entry.
+     * @throws ZipException if a ZIP format error has occurred
+     * @throws IOException if an I/O error has occurred
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public InputStream getInputStream(ZipEntry entry) throws IOException {
+        if (entry == null) {
+            throw new NullPointerException("entry");
+        }
+        long jzentry = 0;
+        ZipFileInputStream in = null;
+        synchronized (this) {
+            ensureOpen();
+            if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
+                // Android-changed: Find entry by name, falling back to name/ if cannot be found.
+                // Needed for ClassPathURLStreamHandler handling of URLs without trailing slashes.
+                // This was added as part of the work to move StrictJarFile from libcore to
+                // framework, see http://b/111293098 for more details.
+                // It should be possible to revert this after upgrading to OpenJDK 8u144 or above.
+                // jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
+                jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), true);
+            } else {
+                // Android-changed: Find entry by name, falling back to name/ if cannot be found.
+                // jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
+                jzentry = getEntry(jzfile, zc.getBytes(entry.name), true);
+            }
+            if (jzentry == 0) {
+                return null;
+            }
+            in = new ZipFileInputStream(jzentry);
+
+            switch (getEntryMethod(jzentry)) {
+            case STORED:
+                synchronized (streams) {
+                    streams.put(in, null);
+                }
+                return in;
+            case DEFLATED:
+                // MORE: Compute good size for inflater stream:
+                long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
+                // Android-changed: Use 64k buffer size, performs better than 8k.
+                // See http://b/65491407.
+                // if (size > 65536) size = 8192;
+                if (size > 65536) size = 65536;
+                if (size <= 0) size = 4096;
+                Inflater inf = getInflater();
+                InputStream is =
+                    new ZipFileInflaterInputStream(in, inf, (int)size);
+                synchronized (streams) {
+                    streams.put(is, inf);
+                }
+                return is;
+            default:
+                throw new ZipException("invalid compression method");
+            }
+        }
+    }
+
+    private class ZipFileInflaterInputStream extends InflaterInputStream {
+        private volatile boolean closeRequested = false;
+        private boolean eof = false;
+        private final ZipFileInputStream zfin;
+
+        ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
+                int size) {
+            super(zfin, inf, size);
+            this.zfin = zfin;
+        }
+
+        public void close() throws IOException {
+            if (closeRequested)
+                return;
+            closeRequested = true;
+
+            super.close();
+            Inflater inf;
+            synchronized (streams) {
+                inf = streams.remove(this);
+            }
+            if (inf != null) {
+                releaseInflater(inf);
+            }
+        }
+
+        // Override fill() method to provide an extra "dummy" byte
+        // at the end of the input stream. This is required when
+        // using the "nowrap" Inflater option.
+        protected void fill() throws IOException {
+            if (eof) {
+                throw new EOFException("Unexpected end of ZLIB input stream");
+            }
+            len = in.read(buf, 0, buf.length);
+            if (len == -1) {
+                buf[0] = 0;
+                len = 1;
+                eof = true;
+            }
+            inf.setInput(buf, 0, len);
+        }
+
+        public int available() throws IOException {
+            if (closeRequested)
+                return 0;
+            long avail = zfin.size() - inf.getBytesWritten();
+            return (avail > (long) Integer.MAX_VALUE ?
+                    Integer.MAX_VALUE : (int) avail);
+        }
+
+        protected void finalize() throws Throwable {
+            close();
+        }
+    }
+
+    /*
+     * Gets an inflater from the list of available inflaters or allocates
+     * a new one.
+     */
+    private Inflater getInflater() {
+        Inflater inf;
+        synchronized (inflaterCache) {
+            while (null != (inf = inflaterCache.poll())) {
+                if (false == inf.ended()) {
+                    return inf;
+                }
+            }
+        }
+        return new Inflater(true);
+    }
+
+    /*
+     * Releases the specified inflater to the list of available inflaters.
+     */
+    private void releaseInflater(Inflater inf) {
+        if (false == inf.ended()) {
+            inf.reset();
+            synchronized (inflaterCache) {
+                inflaterCache.add(inf);
+            }
+        }
+    }
+
+    // List of available Inflater objects for decompression
+    private Deque<Inflater> inflaterCache = new ArrayDeque<>();
+
+    /**
+     * Returns the path name of the ZIP file.
+     * @return the path name of the ZIP file
+     */
+    public String getName() {
+        return name;
+    }
+
+    private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> {
+        private int i = 0;
+
+        public ZipEntryIterator() {
+            ensureOpen();
+        }
+
+        public boolean hasMoreElements() {
+            return hasNext();
+        }
+
+        public boolean hasNext() {
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                return i < total;
+            }
+        }
+
+        public ZipEntry nextElement() {
+            return next();
+        }
+
+        public ZipEntry next() {
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                if (i >= total) {
+                    throw new NoSuchElementException();
+                }
+                long jzentry = getNextEntry(jzfile, i++);
+                if (jzentry == 0) {
+                    String message;
+                    if (closeRequested) {
+                        message = "ZipFile concurrently closed";
+                    } else {
+                        message = getZipMessage(ZipFile.this.jzfile);
+                    }
+                    throw new ZipError("jzentry == 0" +
+                                       ",\n jzfile = " + ZipFile.this.jzfile +
+                                       ",\n total = " + ZipFile.this.total +
+                                       ",\n name = " + ZipFile.this.name +
+                                       ",\n i = " + i +
+                                       ",\n message = " + message
+                        );
+                }
+                ZipEntry ze = getZipEntry(null, jzentry);
+                freeEntry(jzfile, jzentry);
+                return ze;
+            }
+        }
+    }
+
+    /**
+     * Returns an enumeration of the ZIP file entries.
+     * @return an enumeration of the ZIP file entries
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public Enumeration<? extends ZipEntry> entries() {
+        return new ZipEntryIterator();
+    }
+
+    /**
+     * Return an ordered {@code Stream} over the ZIP file entries.
+     * Entries appear in the {@code Stream} in the order they appear in
+     * the central directory of the ZIP file.
+     *
+     * @return an ordered {@code Stream} of entries in this ZIP file
+     * @throws IllegalStateException if the zip file has been closed
+     * @since 1.8
+     */
+    public Stream<? extends ZipEntry> stream() {
+        return StreamSupport.stream(Spliterators.spliterator(
+                new ZipEntryIterator(), size(),
+                Spliterator.ORDERED | Spliterator.DISTINCT |
+                        Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
+    }
+
+    private ZipEntry getZipEntry(String name, long jzentry) {
+        ZipEntry e = new ZipEntry();
+        e.flag = getEntryFlag(jzentry);  // get the flag first
+        if (name != null) {
+            e.name = name;
+        } else {
+            byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
+            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
+                e.name = zc.toStringUTF8(bname, bname.length);
+            } else {
+                e.name = zc.toString(bname, bname.length);
+            }
+        }
+        e.xdostime = getEntryTime(jzentry);
+        e.crc = getEntryCrc(jzentry);
+        e.size = getEntrySize(jzentry);
+        e.csize = getEntryCSize(jzentry);
+        e.method = getEntryMethod(jzentry);
+        e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
+        byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
+        if (bcomm == null) {
+            e.comment = null;
+        } else {
+            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
+                e.comment = zc.toStringUTF8(bcomm, bcomm.length);
+            } else {
+                e.comment = zc.toString(bcomm, bcomm.length);
+            }
+        }
+        return e;
+    }
+
+    private static native long getNextEntry(long jzfile, int i);
+
+    /**
+     * Returns the number of entries in the ZIP file.
+     * @return the number of entries in the ZIP file
+     * @throws IllegalStateException if the zip file has been closed
+     */
+    public int size() {
+        ensureOpen();
+        return total;
+    }
+
+    /**
+     * Closes the ZIP file.
+     * <p> Closing this ZIP file will close all of the input streams
+     * previously returned by invocations of the {@link #getInputStream
+     * getInputStream} method.
+     *
+     * @throws IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (closeRequested)
+            return;
+        // Android-added: CloseGuard support
+        if (guard != null) {
+            guard.close();
+        }
+        closeRequested = true;
+
+        synchronized (this) {
+            // Close streams, release their inflaters
+            // BEGIN Android-added: null field check to avoid NullPointerException during finalize.
+            // If the constructor threw an exception then the streams / inflaterCache fields can
+            // be null and close() can be called by the finalizer.
+            if (streams != null) {
+            // END Android-added: null field check to avoid NullPointerException during finalize.
+                synchronized (streams) {
+                    if (false == streams.isEmpty()) {
+                        Map<InputStream, Inflater> copy = new HashMap<>(streams);
+                        streams.clear();
+                        for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) {
+                            e.getKey().close();
+                            Inflater inf = e.getValue();
+                            if (inf != null) {
+                                inf.end();
+                            }
+                        }
+                    }
+                }
+            // BEGIN Android-added: null field check to avoid NullPointerException during finalize.
+            }
+
+            if (inflaterCache != null) {
+            // END Android-added: null field check to avoid NullPointerException during finalize.
+                // Release cached inflaters
+                Inflater inf;
+                synchronized (inflaterCache) {
+                    while (null != (inf = inflaterCache.poll())) {
+                        inf.end();
+                    }
+                }
+            // BEGIN Android-added: null field check to avoid NullPointerException during finalize.
+            }
+            // END Android-added: null field check to avoid NullPointerException during finalize.
+
+            if (jzfile != 0) {
+                // Close the zip file
+                long zf = this.jzfile;
+                jzfile = 0;
+
+                close(zf);
+            }
+            // Android-added: Do not use unlink() to implement OPEN_DELETE.
+            if (fileToRemoveOnClose != null) {
+                fileToRemoveOnClose.delete();
+            }
+        }
+    }
+
+    /**
+     * Ensures that the system resources held by this ZipFile object are
+     * released when there are no more references to it.
+     *
+     * <p>
+     * Since the time when GC would invoke this method is undetermined,
+     * it is strongly recommended that applications invoke the <code>close</code>
+     * method as soon they have finished accessing this <code>ZipFile</code>.
+     * This will prevent holding up system resources for an undetermined
+     * length of time.
+     *
+     * @throws IOException if an I/O error has occurred
+     * @see    java.util.zip.ZipFile#close()
+     */
+    protected void finalize() throws IOException {
+        // Android-added: CloseGuard support
+        if (guard != null) {
+            guard.warnIfOpen();
+        }
+        close();
+    }
+
+    private static native void close(long jzfile);
+
+    private void ensureOpen() {
+        if (closeRequested) {
+            throw new IllegalStateException("zip file closed");
+        }
+
+        if (jzfile == 0) {
+            throw new IllegalStateException("The object is not initialized.");
+        }
+    }
+
+    private void ensureOpenOrZipException() throws IOException {
+        if (closeRequested) {
+            throw new ZipException("ZipFile closed");
+        }
+    }
+
+    /*
+     * Inner class implementing the input stream used to read a
+     * (possibly compressed) zip file entry.
+     */
+   private class ZipFileInputStream extends InputStream {
+        private volatile boolean zfisCloseRequested = false;
+        protected long jzentry; // address of jzentry data
+        private   long pos;     // current position within entry data
+        protected long rem;     // number of remaining bytes within entry
+        protected long size;    // uncompressed size of this entry
+
+        ZipFileInputStream(long jzentry) {
+            pos = 0;
+            rem = getEntryCSize(jzentry);
+            size = getEntrySize(jzentry);
+            this.jzentry = jzentry;
+        }
+
+        public int read(byte b[], int off, int len) throws IOException {
+            // Android-added: Always throw an exception when reading from closed zipfile.
+            // Required by the JavaDoc for InputStream.read(byte[], int, int). Upstream version
+            // 8u121-b13 is not compliant but that bug has been fixed in upstream version 9+181
+            // as part of a major change to switch to a pure Java implementation.
+            // See https://bugs.openjdk.java.net/browse/JDK-8145260 and
+            // https://bugs.openjdk.java.net/browse/JDK-8142508.
+            ensureOpenOrZipException();
+
+            synchronized (ZipFile.this) {
+                long rem = this.rem;
+                long pos = this.pos;
+                if (rem == 0) {
+                    return -1;
+                }
+                if (len <= 0) {
+                    return 0;
+                }
+                if (len > rem) {
+                    len = (int) rem;
+                }
+
+                // Android-removed: Always throw an exception when reading from closed zipfile.
+                // Moved to the start of the method.
+                //ensureOpenOrZipException();
+                len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
+                                   off, len);
+                if (len > 0) {
+                    this.pos = (pos + len);
+                    this.rem = (rem - len);
+                }
+            }
+            if (rem == 0) {
+                close();
+            }
+            return len;
+        }
+
+        public int read() throws IOException {
+            byte[] b = new byte[1];
+            if (read(b, 0, 1) == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public long skip(long n) {
+            if (n > rem)
+                n = rem;
+            pos += n;
+            rem -= n;
+            if (rem == 0) {
+                close();
+            }
+            return n;
+        }
+
+        public int available() {
+            return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
+        }
+
+        public long size() {
+            return size;
+        }
+
+        public void close() {
+            if (zfisCloseRequested)
+                return;
+            zfisCloseRequested = true;
+
+            rem = 0;
+            synchronized (ZipFile.this) {
+                if (jzentry != 0 && ZipFile.this.jzfile != 0) {
+                    freeEntry(ZipFile.this.jzfile, jzentry);
+                    jzentry = 0;
+                }
+            }
+            synchronized (streams) {
+                streams.remove(this);
+            }
+        }
+
+        protected void finalize() {
+            close();
+        }
+    }
+
+    // Android-removed: Access startsWithLocHeader() directly.
+    /*
+    static {
+        sun.misc.SharedSecrets.setJavaUtilZipFileAccess(
+            new sun.misc.JavaUtilZipFileAccess() {
+                public boolean startsWithLocHeader(ZipFile zip) {
+                    return zip.startsWithLocHeader();
+                }
+             }
+        );
+    }
+    */
+
+    /**
+     * Returns {@code true} if, and only if, the zip file begins with {@code
+     * LOCSIG}.
+     * @hide
+     */
+    // Android-changed: Access startsWithLocHeader() directly.
+    // Make hidden public for use by sun.misc.URLClassPath
+    // private boolean startsWithLocHeader() {
+    public boolean startsWithLocHeader() {
+        return locsig;
+    }
+
+    // BEGIN Android-added: Provide access to underlying file descriptor for testing.
+    // See http://b/111148957 for background information.
+    /** @hide */
+    // @VisibleForTesting
+    public int getFileDescriptor() {
+        return getFileDescriptor(jzfile);
+    }
+
+    private static native int getFileDescriptor(long jzfile);
+    // END Android-added: Provide access to underlying file descriptor for testing.
+
+    private static native long open(String name, int mode, long lastModified,
+                                    boolean usemmap) throws IOException;
+    private static native int getTotal(long jzfile);
+    private static native boolean startsWithLOC(long jzfile);
+    private static native int read(long jzfile, long jzentry,
+                                   long pos, byte[] b, int off, int len);
+
+    // access to the native zentry object
+    private static native long getEntryTime(long jzentry);
+    private static native long getEntryCrc(long jzentry);
+    private static native long getEntryCSize(long jzentry);
+    private static native long getEntrySize(long jzentry);
+    private static native int getEntryMethod(long jzentry);
+    private static native int getEntryFlag(long jzentry);
+    private static native byte[] getCommentBytes(long jzfile);
+
+    private static final int JZENTRY_NAME = 0;
+    private static final int JZENTRY_EXTRA = 1;
+    private static final int JZENTRY_COMMENT = 2;
+    private static native byte[] getEntryBytes(long jzentry, int type);
+
+    private static native String getZipMessage(long jzfile);
+}
diff --git a/java/util/zip/ZipInputStream.java b/java/util/zip/ZipInputStream.java
new file mode 100644
index 0000000..aaebb49
--- /dev/null
+++ b/java/util/zip/ZipInputStream.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.PushbackInputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
+/**
+ * This class implements an input stream filter for reading files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipInputStream extends InflaterInputStream implements ZipConstants {
+    private ZipEntry entry;
+    private int flag;
+    private CRC32 crc = new CRC32();
+    private long remaining;
+    private byte[] tmpbuf = new byte[512];
+
+    private static final int STORED = ZipEntry.STORED;
+    private static final int DEFLATED = ZipEntry.DEFLATED;
+
+    private boolean closed = false;
+    // this flag is set to true after EOF has reached for
+    // one entry
+    private boolean entryEOF = false;
+
+    private ZipCoder zc;
+
+    /**
+     * Check to make sure that this stream has not been closed
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+
+    /**
+     * Creates a new ZIP input stream.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used to
+     * decode the entry names.
+     *
+     * @param in the actual input stream
+     */
+    public ZipInputStream(InputStream in) {
+        this(in, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a new ZIP input stream.
+     *
+     * @param in the actual input stream
+     *
+     * @param charset
+     *        The {@linkplain java.nio.charset.Charset charset} to be
+     *        used to decode the ZIP entry name (ignored if the
+     *        <a href="package-summary.html#lang_encoding"> language
+     *        encoding bit</a> of the ZIP entry's general purpose bit
+     *        flag is set).
+     *
+     * @since 1.7
+     */
+    public ZipInputStream(InputStream in, Charset charset) {
+        super(new PushbackInputStream(in, 512), new Inflater(true), 512);
+        // Android-changed: Unconditionally close external inflaters (b/26462400)
+        // usesDefaultInflater = true;
+        if(in == null) {
+            throw new NullPointerException("in is null");
+        }
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+    }
+
+    /**
+     * Reads the next ZIP file entry and positions the stream at the
+     * beginning of the entry data.
+     * @return the next ZIP file entry, or null if there are no more entries
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public ZipEntry getNextEntry() throws IOException {
+        ensureOpen();
+        if (entry != null) {
+            closeEntry();
+        }
+        crc.reset();
+        inf.reset();
+        if ((entry = readLOC()) == null) {
+            return null;
+        }
+        // Android-changed: Return more accurate value from available().
+        // Initialize the remaining field with the number of bytes that can be read from the entry
+        // for both uncompressed and compressed entries so that it can be used to provide a more
+        // accurate return value for available().
+        // if (entry.method == STORED) {
+        if (entry.method == STORED || entry.method == DEFLATED) {
+            remaining = entry.size;
+        }
+        entryEOF = false;
+        return entry;
+    }
+
+    /**
+     * Closes the current ZIP entry and positions the stream for reading the
+     * next entry.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void closeEntry() throws IOException {
+        ensureOpen();
+        while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
+        entryEOF = true;
+    }
+
+    /**
+     * Returns 0 after EOF has reached for the current entry data,
+     * otherwise always return 1.
+     * <p>
+     * Programs should not count on this method to return the actual number
+     * of bytes that could be read without blocking.
+     *
+     * @return     1 before EOF and 0 after EOF has reached for current entry.
+     * @exception  IOException  if an I/O error occurs.
+     *
+     */
+    public int available() throws IOException {
+        ensureOpen();
+        // Android-changed: Return more accurate value from available().
+        // Tracks the remaining bytes in order to return a more accurate value for the available
+        // bytes. Given an entry of size N both Android and upstream will return 1 until N bytes
+        // have been read at which point Android will return 0 and upstream will return 1.
+        // Upstream will only return 0 after an attempt to read a byte fails because the EOF has
+        // been reached. See http://b/111439440 for more details.
+        // if (entryEOF) {
+        if (entryEOF || (entry != null && remaining == 0)) {
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * Reads from the current ZIP entry into an array of bytes.
+     * If <code>len</code> is not zero, the method
+     * blocks until some input is available; otherwise, no
+     * bytes are read and <code>0</code> is returned.
+     * @param b the buffer into which the data is read
+     * @param off the start offset in the destination array <code>b</code>
+     * @param len the maximum number of bytes read
+     * @return the actual number of bytes read, or -1 if the end of the
+     *         entry is reached
+     * @exception  NullPointerException if <code>b</code> is <code>null</code>.
+     * @exception  IndexOutOfBoundsException if <code>off</code> is negative,
+     * <code>len</code> is negative, or <code>len</code> is greater than
+     * <code>b.length - off</code>
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public int read(byte[] b, int off, int len) throws IOException {
+        ensureOpen();
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return 0;
+        }
+
+        if (entry == null) {
+            return -1;
+        }
+        switch (entry.method) {
+        case DEFLATED:
+            len = super.read(b, off, len);
+            if (len == -1) {
+                readEnd(entry);
+                entryEOF = true;
+                entry = null;
+            } else {
+                crc.update(b, off, len);
+                // Android-added: Return more accurate value from available().
+                // Update the remaining field so it is an accurate count of the number of bytes
+                // remaining in this stream, after deflation.
+                remaining -= len;
+            }
+            return len;
+        case STORED:
+            if (remaining <= 0) {
+                entryEOF = true;
+                entry = null;
+                return -1;
+            }
+            if (len > remaining) {
+                len = (int)remaining;
+            }
+            len = in.read(b, off, len);
+            if (len == -1) {
+                throw new ZipException("unexpected EOF");
+            }
+            crc.update(b, off, len);
+            remaining -= len;
+            if (remaining == 0 && entry.crc != crc.getValue()) {
+                throw new ZipException(
+                    "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
+                    " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+            }
+            return len;
+        default:
+            throw new ZipException("invalid compression method");
+        }
+    }
+
+    /**
+     * Skips specified number of bytes in the current ZIP entry.
+     * @param n the number of bytes to skip
+     * @return the actual number of bytes skipped
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     * @exception IllegalArgumentException if {@code n < 0}
+     */
+    public long skip(long n) throws IOException {
+        if (n < 0) {
+            throw new IllegalArgumentException("negative skip length");
+        }
+        ensureOpen();
+        int max = (int)Math.min(n, Integer.MAX_VALUE);
+        int total = 0;
+        while (total < max) {
+            int len = max - total;
+            if (len > tmpbuf.length) {
+                len = tmpbuf.length;
+            }
+            len = read(tmpbuf, 0, len);
+            if (len == -1) {
+                entryEOF = true;
+                break;
+            }
+            total += len;
+        }
+        return total;
+    }
+
+    /**
+     * Closes this input stream and releases any system resources associated
+     * with the stream.
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            closed = true;
+        }
+    }
+
+    private byte[] b = new byte[256];
+
+    /*
+     * Reads local file (LOC) header for next entry.
+     */
+    private ZipEntry readLOC() throws IOException {
+        try {
+            readFully(tmpbuf, 0, LOCHDR);
+        } catch (EOFException e) {
+            return null;
+        }
+        if (get32(tmpbuf, 0) != LOCSIG) {
+            return null;
+        }
+        // get flag first, we need check EFS.
+        flag = get16(tmpbuf, LOCFLG);
+        // get the entry name and create the ZipEntry first
+        int len = get16(tmpbuf, LOCNAM);
+        int blen = b.length;
+        if (len > blen) {
+            do {
+                blen = blen * 2;
+            } while (len > blen);
+            b = new byte[blen];
+        }
+        readFully(b, 0, len);
+        // Force to use UTF-8 if the EFS bit is ON, even the cs is NOT UTF-8
+        ZipEntry e = createZipEntry(((flag & EFS) != 0)
+                                    ? zc.toStringUTF8(b, len)
+                                    : zc.toString(b, len));
+        // now get the remaining fields for the entry
+        if ((flag & 1) == 1) {
+            throw new ZipException("encrypted ZIP entry not supported");
+        }
+        e.method = get16(tmpbuf, LOCHOW);
+        e.xdostime = get32(tmpbuf, LOCTIM);
+        if ((flag & 8) == 8) {
+            // Android-Changed: Remove the requirement that only DEFLATED entries
+            // can have data descriptors. This is not required by the ZIP spec and
+            // is inconsistent with the behaviour of ZipFile and versions of Android
+            // prior to Android N.
+            //
+            // /* "Data Descriptor" present */
+            // if (e.method != DEFLATED) {
+            //     throw new ZipException(
+            //             "only DEFLATED entries can have EXT descriptor");
+            // }
+        } else {
+            e.crc = get32(tmpbuf, LOCCRC);
+            e.csize = get32(tmpbuf, LOCSIZ);
+            e.size = get32(tmpbuf, LOCLEN);
+        }
+        len = get16(tmpbuf, LOCEXT);
+        if (len > 0) {
+            byte[] extra = new byte[len];
+            readFully(extra, 0, len);
+            e.setExtra0(extra,
+                        e.csize == ZIP64_MAGICVAL || e.size == ZIP64_MAGICVAL);
+        }
+        return e;
+    }
+
+    /**
+     * Creates a new <code>ZipEntry</code> object for the specified
+     * entry name.
+     *
+     * @param name the ZIP file entry name
+     * @return the ZipEntry just created
+     */
+    protected ZipEntry createZipEntry(String name) {
+        return new ZipEntry(name);
+    }
+
+    /*
+     * Reads end of deflated entry as well as EXT descriptor if present.
+     */
+    private void readEnd(ZipEntry e) throws IOException {
+        int n = inf.getRemaining();
+        if (n > 0) {
+            ((PushbackInputStream)in).unread(buf, len - n, n);
+        }
+        if ((flag & 8) == 8) {
+            /* "Data Descriptor" present */
+            if (inf.getBytesWritten() > ZIP64_MAGICVAL ||
+                inf.getBytesRead() > ZIP64_MAGICVAL) {
+                // ZIP64 format
+                readFully(tmpbuf, 0, ZIP64_EXTHDR);
+                long sig = get32(tmpbuf, 0);
+                if (sig != EXTSIG) { // no EXTSIG present
+                    e.crc = sig;
+                    e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC);
+                    e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC);
+                    ((PushbackInputStream)in).unread(
+                        tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC - 1, ZIP64_EXTCRC);
+                } else {
+                    e.crc = get32(tmpbuf, ZIP64_EXTCRC);
+                    e.csize = get64(tmpbuf, ZIP64_EXTSIZ);
+                    e.size = get64(tmpbuf, ZIP64_EXTLEN);
+                }
+            } else {
+                readFully(tmpbuf, 0, EXTHDR);
+                long sig = get32(tmpbuf, 0);
+                if (sig != EXTSIG) { // no EXTSIG present
+                    e.crc = sig;
+                    e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
+                    e.size = get32(tmpbuf, EXTLEN - EXTCRC);
+                    ((PushbackInputStream)in).unread(
+                                               tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
+                } else {
+                    e.crc = get32(tmpbuf, EXTCRC);
+                    e.csize = get32(tmpbuf, EXTSIZ);
+                    e.size = get32(tmpbuf, EXTLEN);
+                }
+            }
+        }
+        if (e.size != inf.getBytesWritten()) {
+            throw new ZipException(
+                "invalid entry size (expected " + e.size +
+                " but got " + inf.getBytesWritten() + " bytes)");
+        }
+        if (e.csize != inf.getBytesRead()) {
+            throw new ZipException(
+                "invalid entry compressed size (expected " + e.csize +
+                " but got " + inf.getBytesRead() + " bytes)");
+        }
+        if (e.crc != crc.getValue()) {
+            throw new ZipException(
+                "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
+                " but got 0x" + Long.toHexString(crc.getValue()) + ")");
+        }
+    }
+
+    /*
+     * Reads bytes, blocking until all bytes are read.
+     */
+    private void readFully(byte[] b, int off, int len) throws IOException {
+        while (len > 0) {
+            int n = in.read(b, off, len);
+            if (n == -1) {
+                throw new EOFException();
+            }
+            off += n;
+            len -= n;
+        }
+    }
+
+}
diff --git a/java/util/zip/ZipOutputStream.java b/java/util/zip/ZipOutputStream.java
new file mode 100644
index 0000000..dd005ec
--- /dev/null
+++ b/java/util/zip/ZipOutputStream.java
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Vector;
+import java.util.HashSet;
+import static java.util.zip.ZipConstants64.*;
+import static java.util.zip.ZipUtils.*;
+
+/**
+ * This class implements an output stream filter for writing files in the
+ * ZIP file format. Includes support for both compressed and uncompressed
+ * entries.
+ *
+ * @author      David Connelly
+ */
+public
+class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
+
+    /**
+     * Whether to use ZIP64 for zip files with more than 64k entries.
+     * Until ZIP64 support in zip implementations is ubiquitous, this
+     * system property allows the creation of zip files which can be
+     * read by legacy zip implementations which tolerate "incorrect"
+     * total entry count fields, such as the ones in jdk6, and even
+     * some in jdk7.
+     */
+    // Android-changed: Always allow use of Zip64.
+    private static final boolean inhibitZip64 = false;
+    //  Boolean.parseBoolean(
+    //      java.security.AccessController.doPrivileged(
+    //          new sun.security.action.GetPropertyAction(
+    //              "jdk.util.zip.inhibitZip64", "false")));
+
+    private static class XEntry {
+        final ZipEntry entry;
+        final long offset;
+        public XEntry(ZipEntry entry, long offset) {
+            this.entry = entry;
+            this.offset = offset;
+        }
+    }
+
+    private XEntry current;
+    private Vector<XEntry> xentries = new Vector<>();
+    private HashSet<String> names = new HashSet<>();
+    private CRC32 crc = new CRC32();
+    private long written = 0;
+    private long locoff = 0;
+    private byte[] comment;
+    private int method = DEFLATED;
+    private boolean finished;
+
+    private boolean closed = false;
+
+    private final ZipCoder zc;
+
+    private static int version(ZipEntry e) throws ZipException {
+        switch (e.method) {
+        case DEFLATED: return 20;
+        case STORED:   return 10;
+        default: throw new ZipException("unsupported compression method");
+        }
+    }
+
+    /**
+     * Checks to make sure that this stream has not been closed.
+     */
+    private void ensureOpen() throws IOException {
+        if (closed) {
+            throw new IOException("Stream closed");
+        }
+    }
+    /**
+     * Compression method for uncompressed (STORED) entries.
+     */
+    public static final int STORED = ZipEntry.STORED;
+
+    /**
+     * Compression method for compressed (DEFLATED) entries.
+     */
+    public static final int DEFLATED = ZipEntry.DEFLATED;
+
+    /**
+     * Creates a new ZIP output stream.
+     *
+     * <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
+     * to encode the entry names and comments.
+     *
+     * @param out the actual output stream
+     */
+    public ZipOutputStream(OutputStream out) {
+        this(out, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * Creates a new ZIP output stream.
+     *
+     * @param out the actual output stream
+     *
+     * @param charset the {@linkplain java.nio.charset.Charset charset}
+     *                to be used to encode the entry names and comments
+     *
+     * @since 1.7
+     */
+    public ZipOutputStream(OutputStream out, Charset charset) {
+        super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+        if (charset == null)
+            throw new NullPointerException("charset is null");
+        this.zc = ZipCoder.get(charset);
+        usesDefaultDeflater = true;
+    }
+
+    /**
+     * Sets the ZIP file comment.
+     * @param comment the comment string
+     * @exception IllegalArgumentException if the length of the specified
+     *            ZIP file comment is greater than 0xFFFF bytes
+     */
+    public void setComment(String comment) {
+        if (comment != null) {
+            this.comment = zc.getBytes(comment);
+            if (this.comment.length > 0xffff)
+                throw new IllegalArgumentException("ZIP file comment too long.");
+        }
+    }
+
+    /**
+     * Sets the default compression method for subsequent entries. This
+     * default will be used whenever the compression method is not specified
+     * for an individual ZIP file entry, and is initially set to DEFLATED.
+     * @param method the default compression method
+     * @exception IllegalArgumentException if the specified compression method
+     *            is invalid
+     */
+    public void setMethod(int method) {
+        if (method != DEFLATED && method != STORED) {
+            throw new IllegalArgumentException("invalid compression method");
+        }
+        this.method = method;
+    }
+
+    /**
+     * Sets the compression level for subsequent entries which are DEFLATED.
+     * The default setting is DEFAULT_COMPRESSION.
+     * @param level the compression level (0-9)
+     * @exception IllegalArgumentException if the compression level is invalid
+     */
+    public void setLevel(int level) {
+        def.setLevel(level);
+    }
+
+    /**
+     * Begins writing a new ZIP file entry and positions the stream to the
+     * start of the entry data. Closes the current entry if still active.
+     * The default compression method will be used if no compression method
+     * was specified for the entry, and the current time will be used if
+     * the entry has no set modification time.
+     * @param e the ZIP entry to be written
+     * @exception ZipException if a ZIP format error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void putNextEntry(ZipEntry e) throws IOException {
+        ensureOpen();
+        if (current != null) {
+            closeEntry();       // close previous entry
+        }
+        if (e.xdostime == -1) {
+            // by default, do NOT use extended timestamps in extra
+            // data, for now.
+            e.setTime(System.currentTimeMillis());
+        }
+        if (e.method == -1) {
+            e.method = method;  // use default method
+        }
+        // store size, compressed size, and crc-32 in LOC header
+        e.flag = 0;
+        switch (e.method) {
+        case DEFLATED:
+            // store size, compressed size, and crc-32 in data descriptor
+            // immediately following the compressed entry data
+            if (e.size  == -1 || e.csize == -1 || e.crc   == -1)
+                e.flag = 8;
+
+            break;
+        case STORED:
+            // compressed size, uncompressed size, and crc-32 must all be
+            // set for entries using STORED compression method
+            if (e.size == -1) {
+                e.size = e.csize;
+            } else if (e.csize == -1) {
+                e.csize = e.size;
+            } else if (e.size != e.csize) {
+                throw new ZipException(
+                    "STORED entry where compressed != uncompressed size");
+            }
+            if (e.size == -1 || e.crc == -1) {
+                throw new ZipException(
+                    "STORED entry missing size, compressed size, or crc-32");
+            }
+            break;
+        default:
+            throw new ZipException("unsupported compression method");
+        }
+        if (! names.add(e.name)) {
+            throw new ZipException("duplicate entry: " + e.name);
+        }
+        if (zc.isUTF8())
+            e.flag |= EFS;
+        current = new XEntry(e, written);
+        xentries.add(current);
+        writeLOC(current);
+    }
+
+    /**
+     * Closes the current ZIP entry and positions the stream for writing
+     * the next entry.
+     * @exception ZipException if a ZIP format error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void closeEntry() throws IOException {
+        ensureOpen();
+        if (current != null) {
+            ZipEntry e = current.entry;
+            switch (e.method) {
+            case DEFLATED:
+                def.finish();
+                while (!def.finished()) {
+                    deflate();
+                }
+                if ((e.flag & 8) == 0) {
+                    // verify size, compressed size, and crc-32 settings
+                    if (e.size != def.getBytesRead()) {
+                        throw new ZipException(
+                            "invalid entry size (expected " + e.size +
+                            " but got " + def.getBytesRead() + " bytes)");
+                    }
+                    if (e.csize != def.getBytesWritten()) {
+                        throw new ZipException(
+                            "invalid entry compressed size (expected " +
+                            e.csize + " but got " + def.getBytesWritten() + " bytes)");
+                    }
+                    if (e.crc != crc.getValue()) {
+                        throw new ZipException(
+                            "invalid entry CRC-32 (expected 0x" +
+                            Long.toHexString(e.crc) + " but got 0x" +
+                            Long.toHexString(crc.getValue()) + ")");
+                    }
+                } else {
+                    e.size  = def.getBytesRead();
+                    e.csize = def.getBytesWritten();
+                    e.crc = crc.getValue();
+                    writeEXT(e);
+                }
+                def.reset();
+                written += e.csize;
+                break;
+            case STORED:
+                // we already know that both e.size and e.csize are the same
+                if (e.size != written - locoff) {
+                    throw new ZipException(
+                        "invalid entry size (expected " + e.size +
+                        " but got " + (written - locoff) + " bytes)");
+                }
+                if (e.crc != crc.getValue()) {
+                    throw new ZipException(
+                         "invalid entry crc-32 (expected 0x" +
+                         Long.toHexString(e.crc) + " but got 0x" +
+                         Long.toHexString(crc.getValue()) + ")");
+                }
+                break;
+            default:
+                throw new ZipException("invalid compression method");
+            }
+            crc.reset();
+            current = null;
+        }
+    }
+
+    /**
+     * Writes an array of bytes to the current ZIP entry data. This method
+     * will block until all the bytes are written.
+     * @param b the data to be written
+     * @param off the start offset in the data
+     * @param len the number of bytes that are written
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public synchronized void write(byte[] b, int off, int len)
+        throws IOException
+    {
+        ensureOpen();
+        if (off < 0 || len < 0 || off > b.length - len) {
+            throw new IndexOutOfBoundsException();
+        } else if (len == 0) {
+            return;
+        }
+
+        if (current == null) {
+            throw new ZipException("no current ZIP entry");
+        }
+        ZipEntry entry = current.entry;
+        switch (entry.method) {
+        case DEFLATED:
+            super.write(b, off, len);
+            break;
+        case STORED:
+            written += len;
+            if (written - locoff > entry.size) {
+                throw new ZipException(
+                    "attempt to write past end of STORED entry");
+            }
+            out.write(b, off, len);
+            break;
+        default:
+            throw new ZipException("invalid compression method");
+        }
+        crc.update(b, off, len);
+    }
+
+    /**
+     * Finishes writing the contents of the ZIP output stream without closing
+     * the underlying stream. Use this method when applying multiple filters
+     * in succession to the same output stream.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O exception has occurred
+     */
+    public void finish() throws IOException {
+        ensureOpen();
+        if (finished) {
+            return;
+        }
+        if (current != null) {
+            closeEntry();
+        }
+        // write central directory
+        long off = written;
+        for (XEntry xentry : xentries)
+            writeCEN(xentry);
+        writeEND(off, written - off);
+        finished = true;
+    }
+
+    /**
+     * Closes the ZIP output stream as well as the stream being filtered.
+     * @exception ZipException if a ZIP file error has occurred
+     * @exception IOException if an I/O error has occurred
+     */
+    public void close() throws IOException {
+        if (!closed) {
+            super.close();
+            closed = true;
+        }
+    }
+
+    /*
+     * Writes local file (LOC) header for specified entry.
+     */
+    private void writeLOC(XEntry xentry) throws IOException {
+        ZipEntry e = xentry.entry;
+        int flag = e.flag;
+        boolean hasZip64 = false;
+        int elen = getExtraLen(e.extra);
+
+        writeInt(LOCSIG);               // LOC header signature
+        if ((flag & 8) == 8) {
+            writeShort(version(e));     // version needed to extract
+            writeShort(flag);           // general purpose bit flag
+            writeShort(e.method);       // compression method
+            writeInt(e.xdostime);       // last modification time
+            // store size, uncompressed size, and crc-32 in data descriptor
+            // immediately following compressed entry data
+            writeInt(0);
+            writeInt(0);
+            writeInt(0);
+        } else {
+            if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
+                hasZip64 = true;
+                writeShort(45);         // ver 4.5 for zip64
+            } else {
+                writeShort(version(e)); // version needed to extract
+            }
+            writeShort(flag);           // general purpose bit flag
+            writeShort(e.method);       // compression method
+            writeInt(e.xdostime);       // last modification time
+            writeInt(e.crc);            // crc-32
+            if (hasZip64) {
+                writeInt(ZIP64_MAGICVAL);
+                writeInt(ZIP64_MAGICVAL);
+                elen += 20;        //headid(2) + size(2) + size(8) + csize(8)
+            } else {
+                writeInt(e.csize);  // compressed size
+                writeInt(e.size);   // uncompressed size
+            }
+        }
+        byte[] nameBytes = zc.getBytes(e.name);
+        writeShort(nameBytes.length);
+
+        int elenEXTT = 0;               // info-zip extended timestamp
+        int flagEXTT = 0;
+        if (e.mtime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAG_LMT;
+        }
+        if (e.atime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAG_LAT;
+        }
+        if (e.ctime != null) {
+            elenEXTT += 4;
+            flagEXTT |= EXTT_FLAT_CT;
+        }
+        if (flagEXTT != 0)
+            elen += (elenEXTT + 5);    // headid(2) + size(2) + flag(1) + data
+        writeShort(elen);
+        writeBytes(nameBytes, 0, nameBytes.length);
+        if (hasZip64) {
+            writeShort(ZIP64_EXTID);
+            writeShort(16);
+            writeLong(e.size);
+            writeLong(e.csize);
+        }
+        if (flagEXTT != 0) {
+            writeShort(EXTID_EXTT);
+            writeShort(elenEXTT + 1);      // flag + data
+            writeByte(flagEXTT);
+            if (e.mtime != null)
+                writeInt(fileTimeToUnixTime(e.mtime));
+            if (e.atime != null)
+                writeInt(fileTimeToUnixTime(e.atime));
+            if (e.ctime != null)
+                writeInt(fileTimeToUnixTime(e.ctime));
+        }
+        writeExtra(e.extra);
+        locoff = written;
+    }
+
+    /*
+     * Writes extra data descriptor (EXT) for specified entry.
+     */
+    private void writeEXT(ZipEntry e) throws IOException {
+        writeInt(EXTSIG);           // EXT header signature
+        writeInt(e.crc);            // crc-32
+        if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
+            writeLong(e.csize);
+            writeLong(e.size);
+        } else {
+            writeInt(e.csize);          // compressed size
+            writeInt(e.size);           // uncompressed size
+        }
+    }
+
+    /*
+     * Write central directory (CEN) header for specified entry.
+     * REMIND: add support for file attributes
+     */
+    private void writeCEN(XEntry xentry) throws IOException {
+        ZipEntry e  = xentry.entry;
+        int flag = e.flag;
+        int version = version(e);
+        long csize = e.csize;
+        long size = e.size;
+        long offset = xentry.offset;
+        int elenZIP64 = 0;
+        boolean hasZip64 = false;
+
+        if (e.csize >= ZIP64_MAGICVAL) {
+            csize = ZIP64_MAGICVAL;
+            elenZIP64 += 8;              // csize(8)
+            hasZip64 = true;
+        }
+        if (e.size >= ZIP64_MAGICVAL) {
+            size = ZIP64_MAGICVAL;    // size(8)
+            elenZIP64 += 8;
+            hasZip64 = true;
+        }
+        if (xentry.offset >= ZIP64_MAGICVAL) {
+            offset = ZIP64_MAGICVAL;
+            elenZIP64 += 8;              // offset(8)
+            hasZip64 = true;
+        }
+        writeInt(CENSIG);           // CEN header signature
+        if (hasZip64) {
+            writeShort(45);         // ver 4.5 for zip64
+            writeShort(45);
+        } else {
+            writeShort(version);    // version made by
+            writeShort(version);    // version needed to extract
+        }
+        writeShort(flag);           // general purpose bit flag
+        writeShort(e.method);       // compression method
+        writeInt(e.xdostime);       // last modification time
+        writeInt(e.crc);            // crc-32
+        writeInt(csize);            // compressed size
+        writeInt(size);             // uncompressed size
+        byte[] nameBytes = zc.getBytes(e.name);
+        writeShort(nameBytes.length);
+
+        int elen = getExtraLen(e.extra);
+        if (hasZip64) {
+            elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
+        }
+        // cen info-zip extended timestamp only outputs mtime
+        // but set the flag for a/ctime, if present in loc
+        int flagEXTT = 0;
+        if (e.mtime != null) {
+            elen += 4;              // + mtime(4)
+            flagEXTT |= EXTT_FLAG_LMT;
+        }
+        if (e.atime != null) {
+            flagEXTT |= EXTT_FLAG_LAT;
+        }
+        if (e.ctime != null) {
+            flagEXTT |= EXTT_FLAT_CT;
+        }
+        if (flagEXTT != 0) {
+            elen += 5;             // headid + sz + flag
+        }
+        writeShort(elen);
+        byte[] commentBytes;
+        if (e.comment != null) {
+            commentBytes = zc.getBytes(e.comment);
+            writeShort(Math.min(commentBytes.length, 0xffff));
+        } else {
+            commentBytes = null;
+            writeShort(0);
+        }
+        writeShort(0);              // starting disk number
+        writeShort(0);              // internal file attributes (unused)
+        writeInt(0);                // external file attributes (unused)
+        writeInt(offset);           // relative offset of local header
+        writeBytes(nameBytes, 0, nameBytes.length);
+
+        // take care of EXTID_ZIP64 and EXTID_EXTT
+        if (hasZip64) {
+            writeShort(ZIP64_EXTID);// Zip64 extra
+            writeShort(elenZIP64);
+            if (size == ZIP64_MAGICVAL)
+                writeLong(e.size);
+            if (csize == ZIP64_MAGICVAL)
+                writeLong(e.csize);
+            if (offset == ZIP64_MAGICVAL)
+                writeLong(xentry.offset);
+        }
+        if (flagEXTT != 0) {
+            writeShort(EXTID_EXTT);
+            if (e.mtime != null) {
+                writeShort(5);      // flag + mtime
+                writeByte(flagEXTT);
+                writeInt(fileTimeToUnixTime(e.mtime));
+            } else {
+                writeShort(1);      // flag only
+                writeByte(flagEXTT);
+            }
+        }
+        writeExtra(e.extra);
+        if (commentBytes != null) {
+            writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
+        }
+    }
+
+    /*
+     * Writes end of central directory (END) header.
+     */
+    private void writeEND(long off, long len) throws IOException {
+        boolean hasZip64 = false;
+        long xlen = len;
+        long xoff = off;
+        if (xlen >= ZIP64_MAGICVAL) {
+            xlen = ZIP64_MAGICVAL;
+            hasZip64 = true;
+        }
+        if (xoff >= ZIP64_MAGICVAL) {
+            xoff = ZIP64_MAGICVAL;
+            hasZip64 = true;
+        }
+        int count = xentries.size();
+        if (count >= ZIP64_MAGICCOUNT) {
+            hasZip64 |= !inhibitZip64;
+            if (hasZip64) {
+                count = ZIP64_MAGICCOUNT;
+            }
+        }
+        if (hasZip64) {
+            long off64 = written;
+            //zip64 end of central directory record
+            writeInt(ZIP64_ENDSIG);        // zip64 END record signature
+            writeLong(ZIP64_ENDHDR - 12);  // size of zip64 end
+            writeShort(45);                // version made by
+            writeShort(45);                // version needed to extract
+            writeInt(0);                   // number of this disk
+            writeInt(0);                   // central directory start disk
+            writeLong(xentries.size());    // number of directory entires on disk
+            writeLong(xentries.size());    // number of directory entires
+            writeLong(len);                // length of central directory
+            writeLong(off);                // offset of central directory
+
+            //zip64 end of central directory locator
+            writeInt(ZIP64_LOCSIG);        // zip64 END locator signature
+            writeInt(0);                   // zip64 END start disk
+            writeLong(off64);              // offset of zip64 END
+            writeInt(1);                   // total number of disks (?)
+        }
+        writeInt(ENDSIG);                 // END record signature
+        writeShort(0);                    // number of this disk
+        writeShort(0);                    // central directory start disk
+        writeShort(count);                // number of directory entries on disk
+        writeShort(count);                // total number of directory entries
+        writeInt(xlen);                   // length of central directory
+        writeInt(xoff);                   // offset of central directory
+        if (comment != null) {            // zip file comment
+            writeShort(comment.length);
+            writeBytes(comment, 0, comment.length);
+        } else {
+            writeShort(0);
+        }
+    }
+
+    /*
+     * Returns the length of extra data without EXTT and ZIP64.
+     */
+    private int getExtraLen(byte[] extra) {
+        if (extra == null)
+            return 0;
+        int skipped = 0;
+        int len = extra.length;
+        int off = 0;
+        while (off + 4 <= len) {
+            int tag = get16(extra, off);
+            int sz = get16(extra, off + 2);
+            if (sz < 0 || (off + 4 + sz) > len) {
+                break;
+            }
+            if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
+                skipped += (sz + 4);
+            }
+            off += (sz + 4);
+        }
+        return len - skipped;
+    }
+
+    /*
+     * Writes extra data without EXTT and ZIP64.
+     *
+     * Extra timestamp and ZIP64 data is handled/output separately
+     * in writeLOC and writeCEN.
+     */
+    private void writeExtra(byte[] extra) throws IOException {
+        if (extra != null) {
+            int len = extra.length;
+            int off = 0;
+            while (off + 4 <= len) {
+                int tag = get16(extra, off);
+                int sz = get16(extra, off + 2);
+                if (sz < 0 || (off + 4 + sz) > len) {
+                    writeBytes(extra, off, len - off);
+                    return;
+                }
+                if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
+                    writeBytes(extra, off, sz + 4);
+                }
+                off += (sz + 4);
+            }
+            if (off < len) {
+                writeBytes(extra, off, len - off);
+            }
+        }
+    }
+
+    /*
+     * Writes a 8-bit byte to the output stream.
+     */
+    private void writeByte(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write(v & 0xff);
+        written += 1;
+    }
+
+    /*
+     * Writes a 16-bit short to the output stream in little-endian byte order.
+     */
+    private void writeShort(int v) throws IOException {
+        OutputStream out = this.out;
+        out.write((v >>> 0) & 0xff);
+        out.write((v >>> 8) & 0xff);
+        written += 2;
+    }
+
+    /*
+     * Writes a 32-bit int to the output stream in little-endian byte order.
+     */
+    private void writeInt(long v) throws IOException {
+        OutputStream out = this.out;
+        out.write((int)((v >>>  0) & 0xff));
+        out.write((int)((v >>>  8) & 0xff));
+        out.write((int)((v >>> 16) & 0xff));
+        out.write((int)((v >>> 24) & 0xff));
+        written += 4;
+    }
+
+    /*
+     * Writes a 64-bit int to the output stream in little-endian byte order.
+     */
+    private void writeLong(long v) throws IOException {
+        OutputStream out = this.out;
+        out.write((int)((v >>>  0) & 0xff));
+        out.write((int)((v >>>  8) & 0xff));
+        out.write((int)((v >>> 16) & 0xff));
+        out.write((int)((v >>> 24) & 0xff));
+        out.write((int)((v >>> 32) & 0xff));
+        out.write((int)((v >>> 40) & 0xff));
+        out.write((int)((v >>> 48) & 0xff));
+        out.write((int)((v >>> 56) & 0xff));
+        written += 8;
+    }
+
+    /*
+     * Writes an array of bytes to the output stream.
+     */
+    private void writeBytes(byte[] b, int off, int len) throws IOException {
+        super.out.write(b, off, len);
+        written += len;
+    }
+}
diff --git a/java/util/zip/ZipUtils.java b/java/util/zip/ZipUtils.java
new file mode 100644
index 0000000..fce4d0e
--- /dev/null
+++ b/java/util/zip/ZipUtils.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.zip;
+
+import java.nio.file.attribute.FileTime;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+class ZipUtils {
+
+    // used to adjust values between Windows and java epoch
+    private static final long WINDOWS_EPOCH_IN_MICROSECONDS = -11644473600000000L;
+
+    /**
+     * Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
+     */
+    public static final FileTime winTimeToFileTime(long wtime) {
+        return FileTime.from(wtime / 10 + WINDOWS_EPOCH_IN_MICROSECONDS,
+                             TimeUnit.MICROSECONDS);
+    }
+
+    /**
+     * Converts FileTime to Windows time.
+     */
+    public static final long fileTimeToWinTime(FileTime ftime) {
+        return (ftime.to(TimeUnit.MICROSECONDS) - WINDOWS_EPOCH_IN_MICROSECONDS) * 10;
+    }
+
+    /**
+     * Converts "standard Unix time"(in seconds, UTC/GMT) to FileTime
+     */
+    public static final FileTime unixTimeToFileTime(long utime) {
+        return FileTime.from(utime, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts FileTime to "standard Unix time".
+     */
+    public static final long fileTimeToUnixTime(FileTime ftime) {
+        return ftime.to(TimeUnit.SECONDS);
+    }
+
+    /**
+     * Converts DOS time to Java time (number of milliseconds since epoch).
+     */
+    private static long dosToJavaTime(long dtime) {
+        @SuppressWarnings("deprecation") // Use of date constructor.
+        Date d = new Date((int)(((dtime >> 25) & 0x7f) + 80),
+                          (int)(((dtime >> 21) & 0x0f) - 1),
+                          (int)((dtime >> 16) & 0x1f),
+                          (int)((dtime >> 11) & 0x1f),
+                          (int)((dtime >> 5) & 0x3f),
+                          (int)((dtime << 1) & 0x3e));
+        return d.getTime();
+    }
+
+    /**
+     * Converts extended DOS time to Java time, where up to 1999 milliseconds
+     * might be encoded into the upper half of the returned long.
+     *
+     * @param xdostime the extended DOS time value
+     * @return milliseconds since epoch
+     */
+    public static long extendedDosToJavaTime(long xdostime) {
+        long time = dosToJavaTime(xdostime);
+        return time + (xdostime >> 32);
+    }
+
+    /**
+     * Converts Java time to DOS time.
+     */
+    @SuppressWarnings("deprecation") // Use of date methods
+    private static long javaToDosTime(long time) {
+        Date d = new Date(time);
+        int year = d.getYear() + 1900;
+        if (year < 1980) {
+            return ZipEntry.DOSTIME_BEFORE_1980;
+        }
+        // Android-changed: backport of JDK-8130914 fix
+        return ((year - 1980) << 25 | (d.getMonth() + 1) << 21 |
+                d.getDate() << 16 | d.getHours() << 11 | d.getMinutes() << 5 |
+                d.getSeconds() >> 1) & 0xffffffffL;
+    }
+
+    /**
+     * Converts Java time to DOS time, encoding any milliseconds lost
+     * in the conversion into the upper half of the returned long.
+     *
+     * @param time milliseconds since epoch
+     * @return DOS time with 2s remainder encoded into upper half
+     */
+    public static long javaToExtendedDosTime(long time) {
+        if (time < 0) {
+            return ZipEntry.DOSTIME_BEFORE_1980;
+        }
+        long dostime = javaToDosTime(time);
+        return (dostime != ZipEntry.DOSTIME_BEFORE_1980)
+                ? dostime + ((time % 2000) << 32)
+                : ZipEntry.DOSTIME_BEFORE_1980;
+    }
+
+    /**
+     * Fetches unsigned 16-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final int get16(byte b[], int off) {
+        return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
+    }
+
+    /**
+     * Fetches unsigned 32-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get32(byte b[], int off) {
+        return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL;
+    }
+
+    /**
+     * Fetches signed 64-bit value from byte array at specified offset.
+     * The bytes are assumed to be in Intel (little-endian) byte order.
+     */
+    public static final long get64(byte b[], int off) {
+        return get32(b, off) | (get32(b, off+4) << 32);
+    }
+}